diff --git a/.gitignore b/.gitignore
index 705e09913dc2..1be78fd8163b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,3 +127,7 @@ all.config
 
 # Kdevelop4
 *.kdev4
+
+#Automatically generated by ASN.1 compiler
+net/ipv4/netfilter/nf_nat_snmp_basic-asn1.c
+net/ipv4/netfilter/nf_nat_snmp_basic-asn1.h
diff --git a/Documentation/ABI/testing/sysfs-ata b/Documentation/ABI/testing/sysfs-ata
index aa4296498859..9ab0ef1dd1c7 100644
--- a/Documentation/ABI/testing/sysfs-ata
+++ b/Documentation/ABI/testing/sysfs-ata
@@ -1,110 +1,139 @@
 What:		/sys/class/ata_...
-Date:		August 2008
-Contact:	Gwendal Grignou<gwendal@google.com>
 Description:
-
-Provide a place in sysfs for storing the ATA topology of the system.  This allows
-retrieving various information about ATA objects.
+		Provide a place in sysfs for storing the ATA topology of the
+		system. This allows retrieving various information about ATA
+		objects.
 
 Files under /sys/class/ata_port
 -------------------------------
 
-	For each port, a directory ataX is created where X is the ata_port_id of
-	the port. The device parent is the ata host device.
+For each port, a directory ataX is created where X is the ata_port_id of the
+port. The device parent is the ata host device.
 
-idle_irq (read)
 
-	Number of IRQ received by the port while idle [some ata HBA only].
+What:		/sys/class/ata_port/ataX/nr_pmp_links
+What:		/sys/class/ata_port/ataX/idle_irq
+Date:		May, 2010
+KernelVersion:	v2.6.37
+Contact:	Gwendal Grignou <gwendal@chromium.org>
+Description:
+		nr_pmp_links:	(RO) If a SATA Port Multiplier (PM) is
+				connected, the number of links behind it.
 
-nr_pmp_links (read)
+		idle_irq:	(RO) Number of IRQ received by the port while
+				idle [some ata HBA only].
 
-	If a SATA Port Multiplier (PM) is connected, number of link behind it.
+
+What:		/sys/class/ata_port/ataX/port_no
+Date:		May, 2013
+KernelVersion:	v3.11
+Contact:	Gwendal Grignou <gwendal@chromium.org>
+Description:
+		(RO) Host local port number. While registering host controller,
+		port numbers are tracked based upon number of ports available on
+		the controller. This attribute is needed by udev for composing
+		persistent links in /dev/disk/by-path.
 
 Files under /sys/class/ata_link
 -------------------------------
 
-	Behind each port, there is a ata_link. If there is a SATA PM in the
-	topology, 15 ata_link objects are created.
-
-	If a link is behind a port, the directory name is linkX, where X is
-	ata_port_id of the port.
-	If a link is behind a PM, its name is linkX.Y where X is ata_port_id
-	of the parent port and Y the PM port.
+Behind each port, there is a ata_link. If there is a SATA PM in the topology, 15
+ata_link objects are created.
 
-hw_sata_spd_limit
+If a link is behind a port, the directory name is linkX, where X is ata_port_id
+of the port. If a link is behind a PM, its name is linkX.Y where X is
+ata_port_id of the parent port and Y the PM port.
 
-	Maximum speed supported by the connected SATA device.
 
-sata_spd_limit
+What:		/sys/class/ata_link/linkX[.Y]/hw_sata_spd_limit
+What:		/sys/class/ata_link/linkX[.Y]/sata_spd_limit
+What:		/sys/class/ata_link/linkX[.Y]/sata_spd
+Date:		May, 2010
+KernelVersion:	v2.6.37
+Contact:	Gwendal Grignou <gwendal@chromium.org>
+Description:
+		hw_sata_spd_limit:	(RO) Maximum speed supported by the
+					connected SATA device.
 
-	Maximum speed imposed by libata.
+		sata_spd_limit:		(RO) Maximum speed imposed by libata.
 
-sata_spd
+		sata_spd:		(RO) Current speed of the link
+					eg. 1.5, 3 Gbps etc.
 
-	Current speed of the link [1.5, 3Gps,...].
 
 Files under /sys/class/ata_device
 ---------------------------------
 
-	Behind each link, up to two ata device are created.
-	The name of the directory is devX[.Y].Z where:
-	- X is ata_port_id of the port where the device is connected,
-	- Y the port of the PM if any, and
-	- Z the device id: for PATA, there is usually 2 devices [0,1],
-	only 1 for SATA.
-
-class
-	Device class. Can be "ata" for disk, "atapi" for packet device,
-	"pmp" for PM, or "none" if no device was found behind the link.
-
-dma_mode
+Behind each link, up to two ata devices are created.
+The name of the directory is devX[.Y].Z where:
+- X is ata_port_id of the port where the device is connected,
+- Y the port of the PM if any, and
+- Z the device id: for PATA, there is usually 2 devices [0,1], only 1 for SATA.
+
+
+What:		/sys/class/ata_device/devX[.Y].Z/spdn_cnt
+What:		/sys/class/ata_device/devX[.Y].Z/gscr
+What:		/sys/class/ata_device/devX[.Y].Z/ering
+What:		/sys/class/ata_device/devX[.Y].Z/id
+What:		/sys/class/ata_device/devX[.Y].Z/pio_mode
+What:		/sys/class/ata_device/devX[.Y].Z/xfer_mode
+What:		/sys/class/ata_device/devX[.Y].Z/dma_mode
+What:		/sys/class/ata_device/devX[.Y].Z/class
+Date:		May, 2010
+KernelVersion:	v2.6.37
+Contact:	Gwendal Grignou <gwendal@chromium.org>
+Description:
+		spdn_cnt:	(RO) Number of times libata decided to lower the
+				speed of link due to errors.
 
-	Transfer modes supported by the device when in DMA mode.
-	Mostly used by PATA device.
+		gscr:		(RO) Cached result of the dump of PM GSCR
+				register. Valid registers are:
 
-pio_mode
+				0:      SATA_PMP_GSCR_PROD_ID,
+				1:	SATA_PMP_GSCR_REV,
+				2:      SATA_PMP_GSCR_PORT_INFO,
+				32:     SATA_PMP_GSCR_ERROR,
+				33:     SATA_PMP_GSCR_ERROR_EN,
+				64:     SATA_PMP_GSCR_FEAT,
+				96:     SATA_PMP_GSCR_FEAT_EN,
+				130:    SATA_PMP_GSCR_SII_GPIO
 
-	Transfer modes supported by the device when in PIO mode.
-	Mostly used by PATA device.
+				Only valid if the device is a PM.
 
-xfer_mode
+		ering:		(RO) Formatted output of the error ring of the
+				device.
 
-	Current transfer mode.
+		id:		(RO) Cached result of IDENTIFY command, as
+				described in ATA8 7.16 and 7.17. Only valid if
+				the device is not a PM.
 
-id
+		pio_mode:	(RO) Transfer modes supported by the device when
+				in PIO mode. Mostly used by PATA device.
 
-	Cached result of IDENTIFY command, as described in ATA8 7.16 and 7.17.
-	Only valid if the device is not a PM.
+		xfer_mode:	(RO) Current transfer mode
 
-gscr
+		dma_mode:	(RO) Transfer modes supported by the device when
+				in DMA mode. Mostly used by PATA device.
 
-	Cached result of the dump of PM GSCR register.
-	Valid registers are:
-	0: 	SATA_PMP_GSCR_PROD_ID,
-	1: 	SATA_PMP_GSCR_REV,
-	2: 	SATA_PMP_GSCR_PORT_INFO,
-	32:	SATA_PMP_GSCR_ERROR,
-	33:	SATA_PMP_GSCR_ERROR_EN,
-	64:	SATA_PMP_GSCR_FEAT,
-	96:	SATA_PMP_GSCR_FEAT_EN,
-	130:	SATA_PMP_GSCR_SII_GPIO
-	Only valid if the device is a PM.
+		class:		(RO) Device class. Can be "ata" for disk,
+				"atapi" for packet device, "pmp" for PM, or
+				"none" if no device was found behind the link.
 
-trim
 
-	Shows the DSM TRIM mode currently used by the device. Valid
-	values are:
-	unsupported:		Drive does not support DSM TRIM
-	unqueued:		Drive supports unqueued DSM TRIM only
-	queued:			Drive supports queued DSM TRIM
-	forced_unqueued:	Drive's queued DSM support is known to be
-				buggy and only unqueued TRIM commands
-				are sent
+What:		/sys/class/ata_device/devX[.Y].Z/trim
+Date:		May, 2015
+KernelVersion:	v4.10
+Contact:	Gwendal Grignou <gwendal@chromium.org>
+Description:
+		(RO) Shows the DSM TRIM mode currently used by the device. Valid
+		values are:
 
-spdn_cnt
+		unsupported:		Drive does not support DSM TRIM
 
-	Number of time libata decided to lower the speed of link due to errors.
+		unqueued:               Drive supports unqueued DSM TRIM only
 
-ering
+		queued:                 Drive supports queued DSM TRIM
 
-	Formatted output of the error ring of the device.
+		forced_unqueued:	Drive's queued DSM support is known to
+					be buggy and only unqueued TRIM commands
+					are sent
diff --git a/Documentation/ABI/testing/sysfs-block-device b/Documentation/ABI/testing/sysfs-block-device
new file mode 100644
index 000000000000..82ef6eab042d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-block-device
@@ -0,0 +1,58 @@
+What:		/sys/block/*/device/sw_activity
+Date:		Jun, 2008
+KernelVersion:	v2.6.27
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RW) Used by drivers which support software controlled activity
+		LEDs.
+
+		It has the following valid values:
+
+		0	OFF - the LED is not activated on activity
+		1	BLINK_ON - the LED blinks on every 10ms when activity is
+			detected.
+		2	BLINK_OFF - the LED is on when idle, and blinks off
+			every 10ms when activity is detected.
+
+		Note that the user must turn sw_activity OFF it they wish to
+		control the activity LED via the em_message file.
+
+
+What:		/sys/block/*/device/unload_heads
+Date:		Sep, 2008
+KernelVersion:	v2.6.28
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RW) Hard disk shock protection
+
+		Writing an integer value to this file will take the heads of the
+		respective drive off the platter and block all I/O operations
+		for the specified number of milliseconds.
+
+		- If the device does not support the unload heads feature,
+		  access is denied with -EOPNOTSUPP.
+		- The maximal value accepted for a timeout is 30000
+		  milliseconds.
+		- A previously set timeout can be cancelled and disk can resume
+		  normal operation immediately by specifying a timeout of 0.
+		- Some hard drives only comply with an earlier version of the
+		  ATA standard, but support the unload feature nonetheless.
+		  There is no safe way Linux can detect these devices, so this
+		  is not enabled by default. If it is known that your device
+		  does support the unload feature, then you can tell the kernel
+		  to enable it by writing -1. It can be disabled again by
+		  writing -2.
+		- Values below -2 are rejected with -EINVAL
+
+		For more information, see
+		Documentation/laptops/disk-shock-protection.txt
+
+
+What:		/sys/block/*/device/ncq_prio_enable
+Date:		Oct, 2016
+KernelVersion:	v4.10
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RW) Write to the file to turn on or off the SATA ncq (native
+		command queueing) support. By default this feature is turned
+		off.
diff --git a/Documentation/ABI/testing/sysfs-class-bdi b/Documentation/ABI/testing/sysfs-class-bdi
index d773d5697cf5..3187a18af6da 100644
--- a/Documentation/ABI/testing/sysfs-class-bdi
+++ b/Documentation/ABI/testing/sysfs-class-bdi
@@ -53,3 +53,11 @@ stable_pages_required (read-only)
 
 	If set, the backing device requires that all pages comprising a write
 	request must not be changed until writeout is complete.
+
+strictlimit (read-write)
+
+	Forces per-BDI checks for the share of given device in the write-back
+	cache even before the global background dirty limit is reached. This
+	is useful in situations where the global limit is much higher than
+	affordable for given relatively slow (or untrusted) device. Turning
+	strictlimit on has no visible effect if max_ratio is equal to 100%.
diff --git a/Documentation/ABI/testing/sysfs-class-rtc b/Documentation/ABI/testing/sysfs-class-rtc
index cf60412882f0..65270d95873c 100644
--- a/Documentation/ABI/testing/sysfs-class-rtc
+++ b/Documentation/ABI/testing/sysfs-class-rtc
@@ -58,8 +58,8 @@ Description:
 		(RO) RTC-provided time in 24-hour notation (hh:mm:ss)
 
 What:		/sys/class/rtc/rtcX/*/nvmem
-Date:		February 2016
-KernelVersion:	4.6
+Date:		July 2017
+KernelVersion:	4.13
 Contact:	linux-rtc@vger.kernel.org
 Description:
 		(RW) The non volatile storage exported as a raw file, as
diff --git a/Documentation/ABI/testing/sysfs-class-scsi_host b/Documentation/ABI/testing/sysfs-class-scsi_host
index 0eb255e7db12..bafc59fd7b69 100644
--- a/Documentation/ABI/testing/sysfs-class-scsi_host
+++ b/Documentation/ABI/testing/sysfs-class-scsi_host
@@ -27,3 +27,92 @@ Description:	This file contains the current status of the "SSD Smart Path"
 		the direct i/o path to physical devices.  This setting is
 		controller wide, affecting all configured logical drives on the
 		controller.  This file is readable and writable.
+
+What:		/sys/class/scsi_host/hostX/link_power_management_policy
+Date:		Oct, 2007
+KernelVersion:	v2.6.24
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RW) This parameter allows the user to read and set the link
+		(interface) power management.
+
+		There are four possible options:
+
+		min_power: Tell the controller to try to make the link use the
+		least possible power when possible. This may sacrifice some
+		performance due to increased latency when coming out of lower
+		power states.
+
+		max_performance: Generally, this means no power management.
+		Tell the controller to have performance be a priority over power
+		management.
+
+		medium_power: Tell the controller to enter a lower power state
+		when possible, but do not enter the lowest power state, thus
+		improving latency over min_power setting.
+
+		med_power_with_dipm: Identical to the existing medium_power
+		setting except that it enables dipm (device initiated power
+		management) on top, which makes it match the Windows IRST (Intel
+		Rapid Storage Technology) driver settings. This setting is also
+		close to min_power, except that:
+		a) It does not use host-initiated slumber mode, but it does
+		allow device-initiated slumber
+		b) It does not enable low power device sleep mode (DevSlp).
+
+What:		/sys/class/scsi_host/hostX/em_message
+What:		/sys/class/scsi_host/hostX/em_message_type
+Date:		Jun, 2008
+KernelVersion:	v2.6.27
+Contact:	linux-ide@vger.kernel.org
+Description:
+		em_message: (RW) Enclosure management support. For the LED
+		protocol, writes and reads correspond to the LED message format
+		as defined in the AHCI spec.
+
+		The user must turn sw_activity (under /sys/block/*/device/) OFF
+		it they wish to control the activity LED via the em_message
+		file.
+
+		em_message_type: (RO) Displays the current enclosure management
+		protocol that is being used by the driver (for eg. LED, SAF-TE,
+		SES-2, SGPIO etc).
+
+What:		/sys/class/scsi_host/hostX/ahci_port_cmd
+What:		/sys/class/scsi_host/hostX/ahci_host_caps
+What:		/sys/class/scsi_host/hostX/ahci_host_cap2
+Date:		Mar, 2010
+KernelVersion:	v2.6.35
+Contact:	linux-ide@vger.kernel.org
+Description:
+		[to be documented]
+
+What:		/sys/class/scsi_host/hostX/ahci_host_version
+Date:		Mar, 2010
+KernelVersion:	v2.6.35
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RO) Display the version of the AHCI spec implemented by the
+		host.
+
+What:		/sys/class/scsi_host/hostX/em_buffer
+Date:		Apr, 2010
+KernelVersion:	v2.6.35
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RW) Allows access to AHCI EM (enclosure management) buffer
+		directly if the host supports EM.
+
+		For eg. the AHCI driver supports SGPIO EM messages but the
+		SATA/AHCI specs do not define the SGPIO message format of the EM
+		buffer. Different hardware(HW) vendors may have different
+		definitions. With the em_buffer attribute, this issue can be
+		solved by allowing HW vendors to provide userland drivers and
+		tools for their SGPIO initiators.
+
+What:		/sys/class/scsi_host/hostX/em_message_supported
+Date:		Oct, 2009
+KernelVersion:	v2.6.39
+Contact:	linux-ide@vger.kernel.org
+Description:
+		(RO) Displays supported enclosure management message types.
diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs
new file mode 100644
index 000000000000..07f1c2f8dbfc
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-ufs
@@ -0,0 +1,804 @@
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device type. This is one of the UFS
+		device descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_class
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device class. This is one of the UFS
+		device descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_sub_class
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the UFS storage subclass. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/protocol
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the protocol supported by an UFS device.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/number_of_luns
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows number of logical units. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/number_of_wluns
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows number of well known logical units.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/boot_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows value that indicates whether the device is
+		enabled for boot. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/descriptor_access_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows value that indicates whether the device
+		descriptor could be read after partial initialization phase
+		of the boot sequence. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/initial_power_mode
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows value that defines the power mode after
+		device initialization or hardware reset. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/high_priority_lun
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the high priority lun. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/secure_removal_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the secure removal type. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/support_security_lun
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the security lun is supported.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/bkops_termination_latency
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the background operations termination
+		latency. This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/initial_active_icc_level
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the initial active ICC level. This is one
+		of the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/specification_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the specification version. This is one
+		of the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/manufacturing_date
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the manufacturing date in BCD format.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/manufacturer_id
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the manufacturee ID. This is one of the
+		UFS device descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/rtt_capability
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of outstanding RTTs
+		supported by the device. This is one of the UFS device
+		descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/rtc_update
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the frequency and method of the realtime
+		clock update. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/ufs_features
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows which features are supported by the device.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be
+		found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/ffu_timeout
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the FFU timeout. This is one of the
+		UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/queue_depth
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device queue depth. This is one of the
+		UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device version. This is one of the
+		UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/number_of_secure_wpa
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows number of secure write protect areas
+		supported by the device. This is one of the UFS device
+		descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/psa_max_data_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum amount of data that may be
+		written during the pre-soldering phase of the PSA flow.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/psa_state_timeout
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the command maximum timeout for a change
+		in PSA state. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/interconnect_descriptor/unipro_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the MIPI UniPro version number in BCD format.
+		This is one of the UFS interconnect descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/interconnect_descriptor/mphy_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the MIPI M-PHY version number in BCD format.
+		This is one of the UFS interconnect descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/raw_device_capacity
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the total memory quantity available to
+		the user to configure the device logical units. This is one
+		of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_number_of_luns
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of logical units
+		supported by the UFS device. This is one of the UFS
+		geometry descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/segment_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the segment size. This is one of the UFS
+		geometry descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/allocation_unit_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the allocation unit size. This is one of
+		the UFS geometry descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/min_addressable_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the minimum addressable block size. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/optimal_read_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the optimal read block size. This is one
+		of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/optimal_write_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the optimal write block size. This is one
+		of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_in_buffer_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum data-in buffer size. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_out_buffer_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum data-out buffer size. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/rpmb_rw_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of RPMB frames allowed
+		in Security Protocol In/Out. This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/dyn_capacity_resource_policy
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the dynamic capacity resource policy. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/data_ordering
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows support for out-of-order data transfer.
+		This is one of the UFS geometry descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_number_of_contexts
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows maximum available number of contexts which
+		are supported by the device. This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/sys_data_tag_unit_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows system data tag unit size. This is one of
+		the UFS geometry descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/sys_data_tag_resource_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows maximum storage area size allocated by
+		the device to handle system data by the tagging mechanism.
+		This is one of the UFS geometry descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/secure_removal_types
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows supported secure removal types. This is
+		one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/memory_types
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows supported memory types. This is one of
+		the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/*_memory_max_alloc_units
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of allocation units for
+		different memory types (system code, non persistent,
+		enhanced type 1-4). This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/*_memory_capacity_adjustment_factor
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the memory capacity adjustment factor for
+		different memory types (system code, non persistent,
+		enhanced type 1-4). This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/health_descriptor/eol_info
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows preend of life information. This is one
+		of the UFS health descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/health_descriptor/life_time_estimation_a
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows indication of the device life time
+		(method a). This is one of the UFS health descriptor
+		parameters. The full information about the descriptor
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/health_descriptor/life_time_estimation_b
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows indication of the device life time
+		(method b). This is one of the UFS health descriptor
+		parameters. The full information about the descriptor
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/power_descriptor/active_icc_levels_vcc*
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows maximum VCC, VCCQ and VCCQ2 value for
+		active ICC levels from 0 to 15. This is one of the UFS
+		power descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/manufacturer_name
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a device manufactureer name string.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/product_name
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a product name string. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/oem_id
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a OEM ID string. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/serial_number
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a device serial number string. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/product_revision
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a product revision string. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/boot_lun_id
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows boot LUN information. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/lun_write_protect
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows LUN write protection status. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/lun_queue_depth
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows LUN queue depth. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/psa_sensitive
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows PSA sensitivity. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/lun_memory_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows LUN memory type. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/data_reliability
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file defines the device behavior when a power failure
+		occurs during a write operation. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/logical_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the size of addressable logical blocks
+		(calculated as an exponent with base 2). This is one of
+		the UFS unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/logical_block_count
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows total number of addressable logical blocks.
+		This is one of the UFS unit descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/erase_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the erase block size. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/provisioning_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the thin provisioning type. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/physical_memory_resourse_count
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the total physical memory resources. This is
+		one of the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/context_capabilities
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the context capabilities. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/large_unit_granularity
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the granularity of the LUN. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/device_init
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device init status. The full information
+		about the flag could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/permanent_wpe
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether permanent write protection is enabled.
+		The full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/power_on_wpe
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether write protection is enabled on all
+		logical units configured as power on write protected. The
+		full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/bkops_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device background operations are
+		enabled. The full information about the flag could be
+		found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/life_span_mode_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device life span mode is enabled.
+		The full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/phy_resource_removal
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether physical resource removal is enable.
+		The full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/busy_rtc
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device is executing internal
+		operation related to real time clock. The full information
+		about the flag could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/disable_fw_update
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device FW update is permanently
+		disabled. The full information about the flag could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/boot_lun_enabled
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the boot lun enabled UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/current_power_mode
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the current power mode UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/active_icc_level
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the active icc level UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/ooo_data_enabled
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the out of order data transfer enabled UFS
+		device attribute. The full information about the attribute
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/bkops_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the background operations status UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/purge_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the purge operation status UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/max_data_in_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum data size in a DATA IN
+		UPIU. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/max_data_out_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of bytes that can be
+		requested with a READY TO TRANSFER UPIU. The full information
+		about the attribute could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/reference_clock_frequency
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the reference clock frequency UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/configuration_descriptor_lock
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the configuration descriptor is locked.
+		The full information about the attribute could be found at
+		UFS specifications 2.1. The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/max_number_of_rtt
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the maximum current number of
+		outstanding RTTs in device that is allowed. The full
+		information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/exception_event_control
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the exception event control UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/exception_event_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the exception event status UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/ffu_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the ffu status UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/psa_state
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file show the PSA feature status. The full information
+		about the attribute could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/psa_data_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the amount of data that the host plans to
+		load to all logical units in pre-soldering state.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/class/scsi_device/*/device/dyn_cap_needed
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the The amount of physical memory needed
+		to be removed from the physical memory resources pool of
+		the particular logical unit. The full information about
+		the attribute could be found at UFS specifications 2.1.
+		The file is read only.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 1d1d53f85ddd..5529fa82700b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2237,6 +2237,15 @@
 			The memory region may be marked as e820 type 12 (0xc)
 			and is NVDIMM or ADR memory.
 
+	memmap=<size>%<offset>-<oldtype>+<newtype>
+			[KNL,ACPI] Convert memory within the specified region
+			from <oldtype> to <newtype>. If "-<oldtype>" is left
+			out, the whole region will be marked as <newtype>,
+			even if previously unavailable. If "+<newtype>" is left
+			out, matching memory will be removed. Types are
+			specified as e820 types, e.g., 1 = RAM, 2 = reserved,
+			3 = ACPI, 12 = PRAM.
+
 	memory_corruption_check=0/1 [X86]
 			Some BIOSes seem to corrupt the first 64k of
 			memory when doing things like suspend/resume.
diff --git a/Documentation/admin-guide/tainted-kernels.rst b/Documentation/admin-guide/tainted-kernels.rst
index 1df03b5cb02f..28a869c509a0 100644
--- a/Documentation/admin-guide/tainted-kernels.rst
+++ b/Documentation/admin-guide/tainted-kernels.rst
@@ -6,34 +6,34 @@ counter. This indicates that the kernel has been tainted by some
 mechanism.  The string is followed by a series of position-sensitive
 characters, each representing a particular tainted value.
 
-  1) 'G' if all modules loaded have a GPL or compatible license, 'P' if
+ 1)  ``G`` if all modules loaded have a GPL or compatible license, ``P`` if
      any proprietary module has been loaded.  Modules without a
      MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by
      insmod as GPL compatible are assumed to be proprietary.
 
-  2) ``F`` if any module was force loaded by ``insmod -f``, ``' '`` if all
+ 2)  ``F`` if any module was force loaded by ``insmod -f``, ``' '`` if all
      modules were loaded normally.
 
-  3) ``S`` if the oops occurred on an SMP kernel running on hardware that
+ 3)  ``S`` if the oops occurred on an SMP kernel running on hardware that
      hasn't been certified as safe to run multiprocessor.
      Currently this occurs only on various Athlons that are not
      SMP capable.
 
-  4) ``R`` if a module was force unloaded by ``rmmod -f``, ``' '`` if all
+ 4)  ``R`` if a module was force unloaded by ``rmmod -f``, ``' '`` if all
      modules were unloaded normally.
 
-  5) ``M`` if any processor has reported a Machine Check Exception,
+ 5)  ``M`` if any processor has reported a Machine Check Exception,
      ``' '`` if no Machine Check Exceptions have occurred.
 
-  6) ``B`` if a page-release function has found a bad page reference or
+ 6)  ``B`` if a page-release function has found a bad page reference or
      some unexpected page flags.
 
-  7) ``U`` if a user or user application specifically requested that the
+ 7)  ``U`` if a user or user application specifically requested that the
      Tainted flag be set, ``' '`` otherwise.
 
-  8) ``D`` if the kernel has died recently, i.e. there was an OOPS or BUG.
+ 8)  ``D`` if the kernel has died recently, i.e. there was an OOPS or BUG.
 
-  9) ``A`` if the ACPI table has been overridden.
+ 9)  ``A`` if the ACPI table has been overridden.
 
  10) ``W`` if a warning has previously been issued by the kernel.
      (Though some warnings may set more specific taint flags.)
diff --git a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
index f057876b920b..dc1fd362d3c1 100644
--- a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
+++ b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
@@ -46,7 +46,7 @@ NAND
 ----
 
   The NAND hardware is similar to the S3C2440, and is supported by the
-  s3c2410 driver in the drivers/mtd/nand directory.
+  s3c2410 driver in the drivers/mtd/nand/raw directory.
 
 
 USB Host
diff --git a/Documentation/cgroup-v2.txt b/Documentation/cgroup-v2.txt
index 74cdeaed9f7a..f728e55602b2 100644
--- a/Documentation/cgroup-v2.txt
+++ b/Documentation/cgroup-v2.txt
@@ -48,6 +48,7 @@ v1 is available under Documentation/cgroup-v1/.
        5-2-1. Memory Interface Files
        5-2-2. Usage Guidelines
        5-2-3. Memory Ownership
+       5-2-4. OOM Killer
      5-3. IO
        5-3-1. IO Interface Files
        5-3-2. Writeback
@@ -1039,6 +1040,31 @@ PAGE_SIZE multiple when read back.
 	high limit is used and monitored properly, this limit's
 	utility is limited to providing the final safety net.
 
+  memory.oom_group
+
+	A read-write single value file which exists on non-root
+	cgroups.  The default is "0".
+
+	If set, OOM killer will consider the memory cgroup as an
+	indivisible memory consumers and compare it with other memory
+	consumers by it's memory footprint.
+	If such memory cgroup is selected as an OOM victim, all
+	processes belonging to it or it's descendants will be killed.
+
+	This applies to system-wide OOM conditions and reaching
+	the hard memory limit of the cgroup and their ancestor.
+	If OOM condition happens in a descendant cgroup with it's own
+	memory limit, the memory cgroup can't be considered
+	as an OOM victim, and OOM killer will not kill all belonging
+	tasks.
+
+	Also, OOM killer respects the /proc/pid/oom_score_adj value -1000,
+	and will never kill the unkillable task, even if memory.oom_group
+	is set.
+
+	If cgroup-aware OOM killer is not enabled, ENOTSUPP error
+	is returned on attempt to access the file.
+
   memory.events
 	A read-only flat-keyed file which exists on non-root cgroups.
 	The following entries are defined.  Unless specified
@@ -1242,6 +1268,54 @@ to be accessed repeatedly by other cgroups, it may make sense to use
 POSIX_FADV_DONTNEED to relinquish the ownership of memory areas
 belonging to the affected files to ensure correct memory ownership.
 
+OOM Killer
+~~~~~~~~~~
+
+Cgroup v2 memory controller implements a cgroup-aware OOM killer.
+It means that it treats cgroups as first class OOM entities.
+
+Cgroup-aware OOM logic is turned off by default and requires
+passing the "groupoom" option on mounting cgroupfs. It can also
+by remounting cgroupfs with the following command::
+
+  # mount -o remount,groupoom $MOUNT_POINT
+
+Under OOM conditions the memory controller tries to make the best
+choice of a victim, looking for a memory cgroup with the largest
+memory footprint, considering leaf cgroups and cgroups with the
+memory.oom_group option set, which are considered to be an indivisible
+memory consumers.
+
+By default, OOM killer will kill the biggest task in the selected
+memory cgroup. A user can change this behavior by enabling
+the per-cgroup memory.oom_group option. If set, it causes
+the OOM killer to kill all processes attached to the cgroup,
+except processes with oom_score_adj set to -1000.
+
+This affects both system- and cgroup-wide OOMs. For a cgroup-wide OOM
+the memory controller considers only cgroups belonging to the sub-tree
+of the OOM'ing cgroup.
+
+Leaf cgroups and cgroups with oom_group option set are compared based
+on their cumulative memory usage. The root cgroup is treated as a
+leaf memory cgroup as well, so it is compared with other leaf memory
+cgroups. Due to internal implementation restrictions the size of
+the root cgroup is the cumulative sum of oom_badness of all its tasks
+(in other words oom_score_adj of each task is obeyed). Relying on
+oom_score_adj (apart from OOM_SCORE_ADJ_MIN) can lead to over- or
+underestimation of the root cgroup consumption and it is therefore
+discouraged. This might change in the future, however.
+
+If there are no cgroups with the enabled memory controller,
+the OOM killer is using the "traditional" process-based approach.
+
+Please, note that memory charges are not migrating if tasks
+are moved between different memory cgroups. Moving tasks with
+significant memory footprint may affect OOM victim selection logic.
+If it's a case, please, consider creating a common ancestor for
+the source and destination memory cgroups and enabling oom_group
+on ancestor layer.
+
 
 IO
 --
diff --git a/Documentation/crypto/crypto_engine.rst b/Documentation/crypto/crypto_engine.rst
new file mode 100644
index 000000000000..8272ac92a14f
--- /dev/null
+++ b/Documentation/crypto/crypto_engine.rst
@@ -0,0 +1,48 @@
+=============
+CRYPTO ENGINE
+=============
+
+Overview
+--------
+The crypto engine API (CE), is a crypto queue manager.
+
+Requirement
+-----------
+You have to put at start of your tfm_ctx the struct crypto_engine_ctx
+struct your_tfm_ctx {
+        struct crypto_engine_ctx enginectx;
+        ...
+};
+Why: Since CE manage only crypto_async_request, it cannot know the underlying
+request_type and so have access only on the TFM.
+So using container_of for accessing __ctx is impossible.
+Furthermore, the crypto engine cannot know the "struct your_tfm_ctx",
+so it must assume that crypto_engine_ctx is at start of it.
+
+Order of operations
+-------------------
+You have to obtain a struct crypto_engine via crypto_engine_alloc_init().
+And start it via crypto_engine_start().
+
+Before transferring any request, you have to fill the enginectx.
+- prepare_request: (taking a function pointer) If you need to do some processing before doing the request
+- unprepare_request: (taking a function pointer) Undoing what's done in prepare_request
+- do_one_request: (taking a function pointer) Do encryption for current request
+
+Note: that those three functions get the crypto_async_request associated with the received request.
+So your need to get the original request via container_of(areq, struct yourrequesttype_request, base);
+
+When your driver receive a crypto_request, you have to transfer it to
+the cryptoengine via one of:
+- crypto_transfer_ablkcipher_request_to_engine()
+- crypto_transfer_aead_request_to_engine()
+- crypto_transfer_akcipher_request_to_engine()
+- crypto_transfer_hash_request_to_engine()
+- crypto_transfer_skcipher_request_to_engine()
+
+At the end of the request process, a call to one of the following function is needed:
+- crypto_finalize_ablkcipher_request
+- crypto_finalize_aead_request
+- crypto_finalize_akcipher_request
+- crypto_finalize_hash_request
+- crypto_finalize_skcipher_request
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index 326d24bca1a9..9a3e98356b1e 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -50,6 +50,10 @@ Rockchip platforms device tree bindings
     Required root node properties:
       - compatible = "firefly,firefly-rk3399", "rockchip,rk3399";
 
+- Firefly roc-rk3328-cc board:
+    Required root node properties:
+      - compatible = "firefly,roc-rk3328-cc", "rockchip,rk3328";
+
 - ChipSPARK PopMetal-RK3288 board:
     Required root node properties:
       - compatible = "chipspark,popmetal-rk3288", "rockchip,rk3288";
@@ -185,6 +189,10 @@ Rockchip platforms device tree bindings
     Required root node properties:
       - compatible = "rockchip,rk3399-sapphire-excavator", "rockchip,rk3399";
 
+- Theobroma Systems RK3368-uQ7 Haikou Baseboard:
+    Required root node properties:
+      - compatible = "tsd,rk3368-uq7-haikou", "rockchip,rk3368";
+
 - Theobroma Systems RK3399-Q7 Haikou Baseboard:
     Required root node properties:
       - compatible = "tsd,rk3399-q7-haikou", "rockchip,rk3399";
diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
index 779f5614bcee..16685787d2bd 100644
--- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
@@ -43,6 +43,12 @@ following properties:
 - interrupt-parent: a phandle indicating which interrupt controller
   this PMU signals interrupts to.
 
+
+Optional nodes:
+
+- nodes defining the restart and poweroff syscon children
+
+
 Example :
 pmu_system_controller: system-controller@10040000 {
 	compatible = "samsung,exynos5250-pmu", "syscon";
diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
index 469ac98ecf8f..14510b215480 100644
--- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
@@ -9,7 +9,11 @@ Required root node properties:
 	- "samsung,smdkv310"	- for Exynos4210-based Samsung SMDKV310 eval board.
 	- "samsung,trats"	- for Exynos4210-based Tizen Reference board.
 	- "samsung,universal_c210" - for Exynos4210-based Samsung board.
+	- "samsung,i9300"          - for Exynos4412-based Samsung GT-I9300 board.
+	- "samsung,i9305"          - for Exynos4412-based Samsung GT-I9305 board.
+	- "samsung,midas"       - for Exynos4412-based Samsung Midas board.
 	- "samsung,smdk4412",	- for Exynos4412-based Samsung SMDK4412 eval board.
+	- "samsung,n710x"          - for Exynos4412-based Samsung GT-N7100/GT-N7105 board.
 	- "samsung,trats2"	- for Exynos4412-based Tizen Reference board.
 	- "samsung,smdk5250"	- for Exynos5250-based Samsung SMDK5250 eval board.
 	- "samsung,xyref5260"	- for Exynos5260-based Samsung board.
diff --git a/Documentation/devicetree/bindings/arm/shmobile.txt b/Documentation/devicetree/bindings/arm/shmobile.txt
index 5c3af7ef0761..63edc11e83ef 100644
--- a/Documentation/devicetree/bindings/arm/shmobile.txt
+++ b/Documentation/devicetree/bindings/arm/shmobile.txt
@@ -39,8 +39,12 @@ SoCs:
     compatible = "renesas,r8a7795"
   - R-Car M3-W (R8A77960)
     compatible = "renesas,r8a7796"
+  - R-Car M3-N (R8A77965)
+    compatible = "renesas,r8a77965"
   - R-Car V3M (R8A77970)
     compatible = "renesas,r8a77970"
+  - R-Car V3H (R8A77980)
+    compatible = "renesas,r8a77980"
   - R-Car D3 (R8A77995)
     compatible = "renesas,r8a77995"
 
@@ -57,6 +61,8 @@ Boards:
     compatible = "renesas,blanche", "renesas,r8a7792"
   - BOCK-W
     compatible = "renesas,bockw", "renesas,r8a7778"
+  - Condor (RTP0RC77980SEB0010SS/RTP0RC77980SEB0010SA01)
+    compatible = "renesas,condor", "renesas,r8a77980"
   - Draak (RTP0RC77995SEB0010S)
     compatible = "renesas,draak", "renesas,r8a77995"
   - Eagle (RTP0RC77970SEB0010S)
@@ -112,6 +118,8 @@ Boards:
     compatible = "renesas,sk-rzg1e", "renesas,r8a7745"
   - SK-RZG1M (YR8A77430S000BE)
     compatible = "renesas,sk-rzg1m", "renesas,r8a7743"
+  - Stout (ADAS Starterkit, Y-R-CAR-ADAS-SKH2-BOARD)
+    compatible = "renesas,stout", "renesas,r8a7790"
   - V3MSK
     compatible = "renesas,v3msk", "renesas,r8a77970"
   - Wheat
diff --git a/Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt b/Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt
new file mode 100644
index 000000000000..082e6a9382d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt
@@ -0,0 +1,44 @@
+Allwinner SRAM for smp bringup:
+------------------------------------------------
+
+Allwinner's A80 SoC uses part of the secure sram for hotplugging of the
+primary core (cpu0). Once the core gets powered up it checks if a magic
+value is set at a specific location. If it is then the BROM will jump
+to the software entry address, instead of executing a standard boot.
+
+Therefore a reserved section sub-node has to be added to the mmio-sram
+declaration.
+
+Note that this is separate from the Allwinner SRAM controller found in
+../../sram/sunxi-sram.txt. This SRAM is secure only and not mappable to
+any device.
+
+Also there are no "secure-only" properties. The implementation should
+check if this SRAM is usable first.
+
+Required sub-node properties:
+- compatible : depending on the SoC this should be one of:
+		"allwinner,sun9i-a80-smp-sram"
+
+The rest of the properties should follow the generic mmio-sram discription
+found in ../../misc/sram.txt
+
+Example:
+
+	sram_b: sram@20000 {
+		/* 256 KiB secure SRAM at 0x20000 */
+		compatible = "mmio-sram";
+		reg = <0x00020000 0x40000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0x00020000 0x40000>;
+
+		smp-sram@1000 {
+			/*
+			 * This is checked by BROM to determine if
+			 * cpu0 should jump to SMP entry vector
+			 */
+			compatible = "allwinner,sun9i-a80-smp-sram";
+			reg = <0x1000 0x8>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt b/Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt
new file mode 100644
index 000000000000..e28e2aac47f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt
@@ -0,0 +1,18 @@
+ARM Versatile Character LCD
+-----------------------------------------------------
+This binding defines the character LCD interface found on ARM Versatile AB
+and PB reference platforms.
+
+Required properties:
+- compatible : "arm,versatile-clcd"
+- reg : Location and size of character LCD registers
+
+Optional properties:
+- interrupts - single interrupt for character LCD. The character LCD can
+  operate in polled mode without an interrupt.
+
+Example:
+	lcd@10008000 {
+		compatible = "arm,versatile-lcd";
+		reg = <0x10008000 0x1000>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
index e71c675ba5da..904ae682ea90 100644
--- a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt
@@ -32,6 +32,7 @@ clock-output-names:
  - "clkin_i2s" - external I2S clock - optional,
  - "gmac_clkin" - external GMAC clock - optional
  - "phy_50m_out" - output clock of the pll in the mac phy
+ - "hdmi_phy" - output clock of the hdmi phy pll - optional
 
 Example: Clock controller node:
 
diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
deleted file mode 100644
index 6ec1a880ac18..000000000000
--- a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-THS8135 Video DAC
------------------
-
-This is the binding for Texas Instruments THS8135 Video DAC bridge.
-
-Required properties:
-
-- compatible: Must be "ti,ths8135"
-
-Required nodes:
-
-This device has two video ports. Their connections are modelled using the OF
-graph bindings specified in Documentation/devicetree/bindings/graph.txt.
-
-- Video port 0 for RGB input
-- Video port 1 for VGA output
-
-Example
--------
-
-vga-bridge {
-	compatible = "ti,ths8135";
-	#address-cells = <1>;
-	#size-cells = <0>;
-
-	ports {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		port@0 {
-			reg = <0>;
-
-			vga_bridge_in: endpoint {
-				remote-endpoint = <&lcdc_out_vga>;
-			};
-		};
-
-		port@1 {
-			reg = <1>;
-
-			vga_bridge_out: endpoint {
-				remote-endpoint = <&vga_con_in>;
-			};
-		};
-	};
-};
diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt
new file mode 100644
index 000000000000..df3d7c1ac09e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt
@@ -0,0 +1,51 @@
+THS8134 and THS8135 Video DAC
+-----------------------------
+
+This is the binding for Texas Instruments THS8134, THS8134A, THS8134B and
+THS8135 Video DAC bridges.
+
+Required properties:
+
+- compatible: Must be one of
+  "ti,ths8134"
+  "ti,ths8134a," "ti,ths8134"
+  "ti,ths8134b", "ti,ths8134"
+  "ti,ths8135"
+
+Required nodes:
+
+This device has two video ports. Their connections are modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for RGB input
+- Video port 1 for VGA output
+
+Example
+-------
+
+vga-bridge {
+	compatible = "ti,ths8135";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+
+			vga_bridge_in: endpoint {
+				remote-endpoint = <&lcdc_out_vga>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+
+			vga_bridge_out: endpoint {
+				remote-endpoint = <&vga_con_in>;
+			};
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
index 05176f1ae108..8def11b16a24 100644
--- a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
+++ b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
@@ -1,23 +1,3 @@
-Etnaviv DRM master device
-=========================
-
-The Etnaviv DRM master device is a virtual device needed to list all
-Vivante GPU cores that comprise the GPU subsystem.
-
-Required properties:
-- compatible: Should be one of
-    "fsl,imx-gpu-subsystem"
-    "marvell,dove-gpu-subsystem"
-- cores: Should contain a list of phandles pointing to Vivante GPU devices
-
-example:
-
-gpu-subsystem {
-	compatible = "fsl,imx-gpu-subsystem";
-	cores = <&gpu_2d>, <&gpu_3d>;
-};
-
-
 Vivante GPU core devices
 ========================
 
@@ -32,7 +12,9 @@ Required properties:
 - clocks: should contain one clock for entry in clock-names
   see Documentation/devicetree/bindings/clock/clock-bindings.txt
 - clock-names:
-   - "bus":    AXI/register clock
+   - "bus":    AXI/master interface clock
+   - "reg":    AHB/slave interface clock
+               (only required if GPU can gate slave interface independently)
    - "core":   GPU core clock
    - "shader": Shader clock (only required if GPU has feature PIPE_3D)
 
diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt
index a6671bd2c85a..518e9cdf0d4b 100644
--- a/Documentation/devicetree/bindings/display/msm/dsi.txt
+++ b/Documentation/devicetree/bindings/display/msm/dsi.txt
@@ -7,8 +7,6 @@ Required properties:
 - reg: Physical base address and length of the registers of controller
 - reg-names: The names of register regions. The following regions are required:
   * "dsi_ctrl"
-- qcom,dsi-host-index: The ID of DSI controller hardware instance. This should
-  be 0 or 1, since we have 2 DSI controllers at most for now.
 - interrupts: The interrupt signal from the DSI block.
 - power-domains: Should be <&mmcc MDSS_GDSC>.
 - clocks: Phandles to device clocks.
@@ -22,6 +20,8 @@ Required properties:
   * "core"
   For DSIv2, we need an additional clock:
    * "src"
+  For DSI6G v2.0 onwards, we need also need the clock:
+   * "byte_intf"
 - assigned-clocks: Parents of "byte" and "pixel" for the given platform.
 - assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided
   by a DSI PHY block. See [1] for details on clock bindings.
@@ -88,21 +88,35 @@ Required properties:
   * "qcom,dsi-phy-28nm-lp"
   * "qcom,dsi-phy-20nm"
   * "qcom,dsi-phy-28nm-8960"
-- reg: Physical base address and length of the registers of PLL, PHY and PHY
-  regulator
+  * "qcom,dsi-phy-14nm"
+  * "qcom,dsi-phy-10nm"
+- reg: Physical base address and length of the registers of PLL, PHY. Some
+  revisions require the PHY regulator base address, whereas others require the
+  PHY lane base address. See below for each PHY revision.
 - reg-names: The names of register regions. The following regions are required:
+  For DSI 28nm HPM/LP/8960 PHYs and 20nm PHY:
   * "dsi_pll"
   * "dsi_phy"
   * "dsi_phy_regulator"
+  For DSI 14nm and 10nm PHYs:
+  * "dsi_pll"
+  * "dsi_phy"
+  * "dsi_phy_lane"
 - clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating
   2 clocks: A byte clock (index 0), and a pixel clock (index 1).
-- qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should
-  be 0 or 1, since we have 2 DSI PHYs at most for now.
 - power-domains: Should be <&mmcc MDSS_GDSC>.
 - clocks: Phandles to device clocks. See [1] for details on clock bindings.
 - clock-names: the following clocks are required:
   * "iface"
+  For 28nm HPM/LP, 28nm 8960 PHYs:
+- vddio-supply: phandle to vdd-io regulator device node
+  For 20nm PHY:
 - vddio-supply: phandle to vdd-io regulator device node
+- vcca-supply: phandle to vcca regulator device node
+  For 14nm PHY:
+- vcca-supply: phandle to vcca regulator device node
+  For 10nm PHY:
+- vdds-supply: phandle to vdds regulator device node
 
 Optional properties:
 - qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY
diff --git a/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt b/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt
new file mode 100644
index 000000000000..248141c3c7e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt
@@ -0,0 +1,31 @@
+ARM Versatile TFT Panels
+
+These panels are connected to the daughterboards found on the
+ARM Versatile reference designs.
+
+This device node must appear as a child to a "syscon"-compatible
+node.
+
+Required properties:
+- compatible: should be "arm,versatile-tft-panel"
+
+Required subnodes:
+- port: see display/panel/panel-common.txt, graph.txt
+
+
+Example:
+
+sysreg@0 {
+	compatible = "arm,versatile-sysreg", "syscon", "simple-mfd";
+	reg = <0x00000 0x1000>;
+
+	panel: display@0 {
+		compatible = "arm,versatile-tft-panel";
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&foo>;
+			};
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
index 029252253ad4..3eb1b48b47dd 100644
--- a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
+++ b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
@@ -98,7 +98,7 @@ Example 2: DSI panel
 			compatible = "st,stm32-dsi";
 			reg = <0x40016c00 0x800>;
 			clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>;
-			clock-names = "ref", "pclk";
+			clock-names = "pclk", "ref";
 			resets = <&rcc STM32F4_APB2_RESET(DSI)>;
 			reset-names = "apb";
 
diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
index 891db41e9420..2f5167da1afc 100644
--- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
+++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
@@ -26,6 +26,7 @@ Required Properties:
 		- "renesas,dmac-r8a7795" (R-Car H3)
 		- "renesas,dmac-r8a7796" (R-Car M3-W)
 		- "renesas,dmac-r8a77970" (R-Car V3M)
+		- "renesas,dmac-r8a77980" (R-Car V3H)
 
 - reg: base address and length of the registers block for the DMAC
 
diff --git a/Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt b/Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt
new file mode 100644
index 000000000000..20fc72d9e61e
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt
@@ -0,0 +1,27 @@
+Nintendo Wii (Hollywood) GPIO controller
+
+Required properties:
+- compatible: "nintendo,hollywood-gpio
+- reg: Physical base address and length of the controller's registers.
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells: Should be <2>. The first cell is the pin number and the
+  second cell is used to specify optional parameters:
+   - bit 0 specifies polarity (0 for normal, 1 for inverted).
+
+Optional properties:
+- ngpios: see Documentation/devicetree/bindings/gpio/gpio.txt
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Should be two.
+- interrupts: Interrupt specifier for the controller's Broadway (PowerPC)
+  interrupt.
+- interrupt-parent: phandle of the parent interrupt controller.
+
+Example:
+
+	GPIO: gpio@d8000c0 {
+		#gpio-cells = <2>;
+		compatible = "nintendo,hollywood-gpio";
+		reg = <0x0d8000c0 0x40>;
+		gpio-controller;
+		ngpios = <24>;
+	}
diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
new file mode 100644
index 000000000000..d98a9bf45d6c
--- /dev/null
+++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
@@ -0,0 +1,25 @@
+* Aspeed KCS (Keyboard Controller Style) IPMI interface
+
+The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
+(Baseboard Management Controllers) and the KCS interface can be
+used to perform in-band IPMI communication with their host.
+
+Required properties:
+- compatible : should be one of
+    "aspeed,ast2400-kcs-bmc"
+    "aspeed,ast2500-kcs-bmc"
+- interrupts : interrupt generated by the controller
+- kcs_chan : The LPC channel number in the controller
+- kcs_addr : The host CPU IO map address
+
+
+Example:
+
+    kcs3: kcs3@0 {
+        compatible = "aspeed,ast2500-kcs-bmc";
+        reg = <0x0 0x80>;
+        interrupts = <8>;
+        kcs_chan = <3>;
+        kcs_addr = <0xCA2>;
+        status = "okay";
+    };
diff --git a/Documentation/devicetree/bindings/misc/arm-charlcd.txt b/Documentation/devicetree/bindings/misc/arm-charlcd.txt
deleted file mode 100644
index e28e2aac47f1..000000000000
--- a/Documentation/devicetree/bindings/misc/arm-charlcd.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-ARM Versatile Character LCD
------------------------------------------------------
-This binding defines the character LCD interface found on ARM Versatile AB
-and PB reference platforms.
-
-Required properties:
-- compatible : "arm,versatile-clcd"
-- reg : Location and size of character LCD registers
-
-Optional properties:
-- interrupts - single interrupt for character LCD. The character LCD can
-  operate in polled mode without an interrupt.
-
-Example:
-	lcd@10008000 {
-		compatible = "arm,versatile-lcd";
-		reg = <0x10008000 0x1000>;
-	};
diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
index d8685cb83325..2d5287eeed95 100644
--- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
@@ -50,7 +50,6 @@ Required properties:
 	  2: R7S72100
 
 Optional properties:
-- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
 - pinctrl-names: should be "default", "state_uhs"
 - pinctrl-0: should contain default/high speed pin ctrl
 - pinctrl-1: should contain uhs mode pin ctrl
diff --git a/Documentation/devicetree/bindings/net/ti,dp83867.txt b/Documentation/devicetree/bindings/net/ti,dp83867.txt
index 02c4353b5cf2..9ef9338aaee1 100644
--- a/Documentation/devicetree/bindings/net/ti,dp83867.txt
+++ b/Documentation/devicetree/bindings/net/ti,dp83867.txt
@@ -25,6 +25,8 @@ Optional property:
 				    software needs to take when this pin is
 				    strapped in these modes. See data manual
 				    for details.
+	- ti,clk-output-sel - Muxing option for CLK_OUT pin - see dt-bindings/net/ti-dp83867.h
+				    for applicable values.
 
 Note: ti,min-output-impedance and ti,max-output-impedance are mutually
       exclusive. When both properties are present ti,max-output-impedance
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
new file mode 100644
index 000000000000..665aadb5ea28
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
@@ -0,0 +1,176 @@
+Qualcomm SDM845 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+SDM845 platform.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "qcom,sdm845-pinctrl"
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+	Usage: required
+	Value type: <string-array>
+	Definition: List of gpio pins affected by the properties specified in
+		    this subnode.
+
+		    Valid pins are:
+		      gpio0-gpio149
+		        Supports mux, bias and drive-strength
+
+		      sdc2_clk, sdc2_cmd, sdc2_data
+		        Supports bias and drive-strength
+
+- function:
+	Usage: required
+	Value type: <string>
+	Definition: Specify the alternative function to be configured for the
+		    specified pins. Functions are only valid for gpio pins.
+		    Valid values are:
+
+		    gpio, adsp_ext, agera_pll, atest_char, atest_tsens,
+		    atest_tsens2, atest_usb1, atest_usb10, atest_usb11,
+		    atest_usb12, atest_usb13, atest_usb2, atest_usb20,
+		    atest_usb21, atest_usb22, atest_usb23, audio_ref,
+		    btfm_slimbus, cam_mclk, cci_async, cci_i2c, cci_timer0,
+		    cci_timer1, cci_timer2, cci_timer3, cci_timer4, cri_trng,
+		    cri_trng0, cri_trng1, dbg_out, ddr_bist, ddr_pxi0,
+		    ddr_pxi1, ddr_pxi2, ddr_pxi3, edp_hot, edp_lcd, gcc_gp1,
+		    gcc_gp2, gcc_gp3, jitter_bist, ldo_en, ldo_update,
+		    lpass_slimbus, m_voc, mdp_vsync, mdp_vsync0, mdp_vsync1,
+		    mdp_vsync2, mdp_vsync3, mss_lte, nav_pps, pa_indicator,
+		    pci_e0, pci_e1, phase_flag, pll_bist, pll_bypassnl,
+		    pll_reset, pri_mi2s, pri_mi2s_ws, prng_rosc, qdss_cti,
+		    qdss, qlink_enable, qlink_request, qua_mi2s, qup0, qup1,
+		    qup10, qup11, qup12, qup13, qup14, qup15, qup2, qup3, qup4,
+		    qup5, qup6, qup7, qup8, qup9, qup_l4, qup_l5, qup_l6,
+		    qspi_clk, qspi_cs, qspi_data, sd_write, sdc4_clk, sdc4_cmd,
+		    sdc4_data, sec_mi2s, sp_cmu, spkr_i2s, ter_mi2s, tgu_ch0,
+		    tgu_ch1, tgu_ch2, tgu_ch3, tsense_pwm1, tsense_pwm2,
+		    tsif1_clk, tsif1_data, tsif1_en, tsif1_error, tsif1_sync,
+		    tsif2_clk, tsif2_data, tsif2_en, tsif2_error, tsif2_sync,
+		    uim1_clk, uim1_data, uim1_present, uim1_reset, uim2_clk,
+		    uim2_data, uim2_present, uim2_reset, uim_batt, usb_phy,
+		    vfr_1, vsense_trigger, wlan1_adc0, wlan1_adc1, wlan2_adc0,
+		    wlan2_adc1,
+
+- bias-disable:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull up.
+
+- output-high:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    high.
+		    Not valid for sdc pins.
+
+- output-low:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    low.
+		    Not valid for sdc pins.
+
+- drive-strength:
+	Usage: optional
+	Value type: <u32>
+	Definition: Selects the drive strength for the specified pins, in mA.
+		    Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+	tlmm: pinctrl@3400000 {
+		compatible = "qcom,sdm845-pinctrl";
+		reg = <0x03400000 0xc00000>;
+		interrupts = <GIC_SPI 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		qup9_active: qup9-active {
+			mux {
+				pins = "gpio4", "gpio5";
+				function = "qup9";
+			};
+
+			config {
+				pins = "gpio4", "gpio5";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt
index 8690f10426a3..6284a9550b3c 100644
--- a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt
+++ b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt
@@ -18,6 +18,7 @@ Required properties:
       - "renesas,r8a7795-sysc" (R-Car H3)
       - "renesas,r8a7796-sysc" (R-Car M3-W)
       - "renesas,r8a77970-sysc" (R-Car V3M)
+      - "renesas,r8a77980-sysc" (R-Car V3H)
       - "renesas,r8a77995-sysc" (R-Car D3)
   - reg: Address start and address range for the device.
   - #power-domain-cells: Must be 1.
diff --git a/Documentation/devicetree/bindings/power/reset/ocelot-reset.txt b/Documentation/devicetree/bindings/power/reset/ocelot-reset.txt
new file mode 100644
index 000000000000..1b4213eb3473
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/reset/ocelot-reset.txt
@@ -0,0 +1,14 @@
+Microsemi Ocelot reset controller
+
+The DEVCPU_GCB:CHIP_REGS have a SOFT_RST register that can be used to reset the
+SoC MIPS core.
+
+Required Properties:
+ - compatible: "mscc,ocelot-chip-reset"
+
+Example:
+	reset@1070008 {
+		compatible = "mscc,ocelot-chip-reset";
+		reg = <0x1070008 0x4>;
+	};
+
diff --git a/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt b/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
index 36afa322b04b..a3dc4b9fa11a 100644
--- a/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
+++ b/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
@@ -152,14 +152,7 @@ Nintendo Wii device tree
 
 1.l) The General Purpose I/O (GPIO) controller node
 
-  Represents the dual access 32 GPIO controller interface.
-
-  Required properties:
-
-  - #gpio-cells : <2>
-  - compatible : should be "nintendo,hollywood-gpio"
-  - reg : should contain the IPC registers location and length
-  - gpio-controller
+  see Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt
 
 1.m) The control node
 
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 4fae41d54798..0c2a6c8a1536 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -2,6 +2,7 @@ Fixed Voltage regulators
 
 Required properties:
 - compatible: Must be "regulator-fixed";
+- regulator-name: Defined in regulator.txt as optional, but required here.
 
 Optional properties:
 - gpio: gpio to use for enable control
diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
index dd1ed789728e..1f496159e2bb 100644
--- a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
@@ -2,6 +2,8 @@ GPIO controlled regulators
 
 Required properties:
 - compatible		: Must be "regulator-gpio".
+- regulator-name	: Defined in regulator.txt as optional, but required
+			  here.
 - states		: Selection of available voltages and GPIO configs.
                           if there are no states, then use a fixed regulator
 
diff --git a/Documentation/devicetree/bindings/reset/renesas,rst.txt b/Documentation/devicetree/bindings/reset/renesas,rst.txt
index a8014f3ab8ba..a55b88658446 100644
--- a/Documentation/devicetree/bindings/reset/renesas,rst.txt
+++ b/Documentation/devicetree/bindings/reset/renesas,rst.txt
@@ -27,6 +27,7 @@ Required properties:
 		  - "renesas,r8a7795-rst" (R-Car H3)
 		  - "renesas,r8a7796-rst" (R-Car M3-W)
 		  - "renesas,r8a77970-rst" (R-Car V3M)
+		  - "renesas,r8a77980-rst" (R-Car V3H)
 		  - "renesas,r8a77995-rst" (R-Car D3)
   - reg: Address start and address range for the device.
 
diff --git a/Documentation/devicetree/bindings/sound/ak4458.txt b/Documentation/devicetree/bindings/sound/ak4458.txt
new file mode 100644
index 000000000000..7839be78448d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ak4458.txt
@@ -0,0 +1,23 @@
+AK4458 audio DAC
+
+This device supports I2C mode.
+
+Required properties:
+
+- compatible : "asahi-kasei,ak4458"
+- reg : The I2C address of the device for I2C
+
+Optional properties:
+- reset-gpios: A GPIO specifier for the power down & reset pin
+- mute-gpios: A GPIO specifier for the soft mute pin
+
+Example:
+
+&i2c {
+	ak4458: dac@10 {
+		compatible = "asahi-kasei,ak4458";
+		reg = <0x10>;
+		reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>
+		mute-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/ak5558.txt b/Documentation/devicetree/bindings/sound/ak5558.txt
new file mode 100644
index 000000000000..7d67ca6ced80
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ak5558.txt
@@ -0,0 +1,22 @@
+AK5558 8 channel differential 32-bit delta-sigma ADC
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "asahi-kasei,ak5558"
+- reg : The I2C address of the device.
+
+Optional properties:
+
+- reset-gpios: A GPIO specifier for the power down & reset pin.
+
+Example:
+
+&i2c {
+	ak5558: adc@10 {
+		compatible = "asahi-kasei,ak5558";
+		reg = <0x10>;
+		reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt
index f7bf65611453..e957b4136716 100644
--- a/Documentation/devicetree/bindings/sound/dmic.txt
+++ b/Documentation/devicetree/bindings/sound/dmic.txt
@@ -8,6 +8,7 @@ Required properties:
 Optional properties:
 	- dmicen-gpios: GPIO specifier for dmic to control start and stop
 	- num-channels: Number of microphones on this DAI
+	- wakeup-delay-ms: Delay (in ms) after enabling the DMIC
 
 Example node:
 
@@ -15,4 +16,5 @@ Example node:
 		compatible = "dmic-codec";
 		dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
 		num-channels = <1>;
+		wakeup-delay-ms <50>;
 	};
diff --git a/Documentation/devicetree/bindings/sound/rt5665.txt b/Documentation/devicetree/bindings/sound/rt5665.txt
index 419c89219681..8df170506986 100644
--- a/Documentation/devicetree/bindings/sound/rt5665.txt
+++ b/Documentation/devicetree/bindings/sound/rt5665.txt
@@ -1,10 +1,10 @@
-RT5665/RT5666/RT5668 audio CODEC
+RT5665/RT5666 audio CODEC
 
 This device supports I2C only.
 
 Required properties:
 
-- compatible : One of "realtek,rt5665", "realtek,rt5666" or "realtek,rt5668".
+- compatible : One of "realtek,rt5665", "realtek,rt5666".
 
 - reg : The I2C address of the device.
 
diff --git a/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt b/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
index 94442e5673b3..f5ccc12ddc00 100644
--- a/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
+++ b/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
@@ -4,9 +4,13 @@ Required properties:
 
  - compatible		 : "samsung,tm2-audio"
  - model		 : the user-visible name of this sound complex
- - audio-codec		 : the phandle of the wm5110 audio codec node,
-			   as described in ../mfd/arizona.txt
- - i2s-controller	 : the phandle of the I2S controller
+ - audio-codec		 : the first entry should be phandle of the wm5110 audio
+			   codec node, as described in ../mfd/arizona.txt;
+			   the second entry should be phandle of the HDMI
+			   transmitter node
+ - i2s-controller	 : the list of phandle and argument tuples pointing to
+			   I2S controllers, the first entry should be I2S0 and
+			   the second one I2S1
  - audio-amplifier	 : the phandle of the MAX98504 amplifier
  - samsung,audio-routing : a list of the connections between audio components;
 			   each entry is a pair of strings, the first being the
@@ -22,8 +26,8 @@ Example:
 
 sound {
 	compatible = "samsung,tm2-audio";
-	audio-codec = <&wm5110>;
-	i2s-controller = <&i2s0>;
+	audio-codec = <&wm5110>, <&hdmi>;
+	i2s-controller = <&i2s0 0>, <&i2s1 0>;
 	audio-amplifier = <&max98504>;
 	mic-bias-gpios = <&gpr3 2 0>;
 	model = "wm5110";
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
index bf100cd0d0f7..a88cb00fa096 100644
--- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
@@ -7,7 +7,7 @@ Required SoC Specific Properties:
    - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
      secondary fifo, s/w reset control and internal mux for root clk src.
    - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
-     playback, sterio channel capture, secondary fifo using internal
+     playback, stereo channel capture, secondary fifo using internal
      or external dma, s/w reset control, internal mux for root clk src
      and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
      is to allow transfer of multiple channel audio data on single data line.
@@ -25,7 +25,7 @@ Required SoC Specific Properties:
   These strings correspond 1:1 with the ordered pairs in dmas.
 - clocks: Handle to iis clock and RCLK source clk.
 - clock-names:
-  i2s0 uses some base clks from CMU and some are from audio subsystem internal
+  i2s0 uses some base clocks from CMU and some are from audio subsystem internal
   clock controller. The clock names for i2s0 should be "iis", "i2s_opclk0" and
   "i2s_opclk1" as shown in the example below.
   i2s1 and i2s2 uses clocks from CMU. The clock names for i2s1 and i2s2 should
@@ -36,9 +36,9 @@ Required SoC Specific Properties:
 - #clock-cells: should be 1, this property must be present if the I2S device
   is a clock provider in terms of the common clock bindings, described in
   ../clock/clock-bindings.txt.
-- clock-output-names: from the common clock bindings, names of the CDCLK
-  I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
-  "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
+- clock-output-names (deprecated): from the common clock bindings, names of
+  the CDCLK I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
+  "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices respectively.
 
 There are following clocks available at the I2S device nodes:
  CLK_I2S_CDCLK    - the CDCLK (CODECLKO) gate clock,
@@ -49,9 +49,10 @@ There are following clocks available at the I2S device nodes:
 
 Refer to the SoC datasheet for availability of the above clocks.
 The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
-in the IIS Multi Audio Interface (I2S0).
-Note: Old DTs may not have the #clock-cells, clock-output-names properties
-and then not use the I2S node as a clock supplier.
+in the IIS Multi Audio Interface.
+
+Note: Old DTs may not have the #clock-cells property and then not use the I2S
+node as a clock supplier.
 
 Optional SoC Specific Properties:
 
@@ -59,6 +60,7 @@ Optional SoC Specific Properties:
   sub system(used in secondary sound source).
 - pinctrl-0: Should specify pin control groups used for this controller.
 - pinctrl-names: Should contain only one value - "default".
+- #sound-dai-cells: should be 1.
 
 
 Example:
@@ -74,9 +76,9 @@ i2s0: i2s@3830000 {
 		<&clock_audss EXYNOS_I2S_BUS>,
 		<&clock_audss EXYNOS_SCLK_I2S>;
 	clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
-	#clock-cells;
-	clock-output-names = "i2s_cdclk0";
+	#clock-cells = <1>;
 	samsung,idma-addr = <0x03000000>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2s0_bus>;
+	#sound-dai-cells = <1>;
 };
diff --git a/Documentation/devicetree/bindings/sound/uniphier,aio.txt b/Documentation/devicetree/bindings/sound/uniphier,aio.txt
new file mode 100644
index 000000000000..73f6c27ae4f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/uniphier,aio.txt
@@ -0,0 +1,36 @@
+Socionext UniPhier SoC audio driver
+
+The Socionext UniPhier audio subsystem consists of I2S and S/PDIF blocks in
+the same register space.
+
+Required properties:
+- compatible      : should be one of the following:
+		    "socionext,uniphier-ld11-aio"
+		    "socionext,uniphier-ld20-aio"
+- reg             : offset and length of the register set for the device.
+- interrupts      : should contain I2S or S/PDIF interrupt.
+- pinctrl-names   : should be "default".
+- pinctrl-0       : defined I2S signal pins for an external codec chip.
+- clock-names     : should include following entries:
+                    "aio"
+- clocks          : a list of phandle, should contain an entry for each
+                    entry in clock-names.
+- reset-names     : should include following entries:
+                    "aio"
+- resets          : a list of phandle, should contain an entry for each
+                    entry in reset-names.
+- #sound-dai-cells: should be 1.
+
+Example:
+	audio {
+		compatible = "socionext,uniphier-ld20-aio";
+		reg = <0x56000000 0x80000>;
+		interrupts = <0 144 4>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_aout>;
+		clock-names = "aio";
+		clocks = <&sys_clk 40>;
+		reset-names = "aio";
+		resets = <&sys_rst 40>;
+		#sound-dai-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt
index a95603bcf6ff..52db562f17a4 100644
--- a/Documentation/devicetree/bindings/spi/spi-gpio.txt
+++ b/Documentation/devicetree/bindings/spi/spi-gpio.txt
@@ -1,18 +1,30 @@
 SPI-GPIO devicetree bindings
 
+This represents a group of 3-n GPIO lines used for bit-banged SPI on dedicated
+GPIO lines.
+
 Required properties:
 
  - compatible: should be set to "spi-gpio"
  - #address-cells: should be set to <0x1>
  - ranges
- - gpio-sck: GPIO spec for the SCK line to use
- - gpio-miso: GPIO spec for the MISO line to use
- - gpio-mosi: GPIO spec for the MOSI line to use
+ - sck-gpios: GPIO spec for the SCK line to use
+ - miso-gpios: GPIO spec for the MISO line to use
+ - mosi-gpios: GPIO spec for the MOSI line to use
  - cs-gpios: GPIOs to use for chipselect lines.
              Not needed if num-chipselects = <0>.
  - num-chipselects: Number of chipselect lines. Should be <0> if a single device
                     with no chip select is connected.
 
+Deprecated bindings:
+
+These legacy GPIO line bindings can alternatively be used to define the
+GPIO lines used, they should not be used in new device trees.
+
+ - gpio-sck: GPIO spec for the SCK line to use
+ - gpio-miso: GPIO spec for the MISO line to use
+ - gpio-mosi: GPIO spec for the MOSI line to use
+
 Example:
 
 	spi {
@@ -20,9 +32,9 @@ Example:
 		#address-cells = <0x1>;
 		ranges;
 
-		gpio-sck = <&gpio 95 0>;
-		gpio-miso = <&gpio 98 0>;
-		gpio-mosi = <&gpio 97 0>;
+		sck-gpios = <&gpio 95 0>;
+		miso-gpios = <&gpio 98 0>;
+		mosi-gpios = <&gpio 97 0>;
 		cs-gpios = <&gpio 125 0>;
 		num-chipselects = <1>;
 
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
index 28be51afdb6a..379eb763073e 100644
--- a/Documentation/devicetree/bindings/thermal/imx-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
@@ -22,7 +22,32 @@ Optional properties:
 - clocks : thermal sensor's clock source.
 
 Example:
+ocotp: ocotp@21bc000 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "fsl,imx6sx-ocotp", "syscon";
+	reg = <0x021bc000 0x4000>;
+	clocks = <&clks IMX6SX_CLK_OCOTP>;
 
+	tempmon_calib: calib@38 {
+		reg = <0x38 4>;
+	};
+
+	tempmon_temp_grade: temp-grade@20 {
+		reg = <0x20 4>;
+	};
+};
+
+tempmon: tempmon {
+	compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon";
+	interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+	fsl,tempmon = <&anatop>;
+	nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+	nvmem-cell-names = "calib", "temp_grade";
+	clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>;
+};
+
+Legacy method (Deprecated):
 tempmon {
 	compatible = "fsl,imx6q-tempmon";
 	fsl,tempmon = <&anatop>;
diff --git a/Documentation/doc-guide/kernel-doc.rst b/Documentation/doc-guide/kernel-doc.rst
index 722d4525f7cf..c6c329708d8a 100644
--- a/Documentation/doc-guide/kernel-doc.rst
+++ b/Documentation/doc-guide/kernel-doc.rst
@@ -1,201 +1,48 @@
-Including kernel-doc comments
-=============================
-
-The Linux kernel source files may contain structured documentation comments, or
-kernel-doc comments to describe the functions and types and design of the
-code. The documentation comments may be included to any of the reStructuredText
-documents using a dedicated kernel-doc Sphinx directive extension.
-
-The kernel-doc directive is of the format::
-
-  .. kernel-doc:: source
-     :option:
-
-The *source* is the path to a source file, relative to the kernel source
-tree. The following directive options are supported:
-
-export: *[source-pattern ...]*
-  Include documentation for all functions in *source* that have been exported
-  using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` either in *source* or in any
-  of the files specified by *source-pattern*.
-
-  The *source-pattern* is useful when the kernel-doc comments have been placed
-  in header files, while ``EXPORT_SYMBOL`` and ``EXPORT_SYMBOL_GPL`` are next to
-  the function definitions.
-
-  Examples::
-
-    .. kernel-doc:: lib/bitmap.c
-       :export:
-
-    .. kernel-doc:: include/net/mac80211.h
-       :export: net/mac80211/*.c
-
-internal: *[source-pattern ...]*
-  Include documentation for all functions and types in *source* that have
-  **not** been exported using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` either
-  in *source* or in any of the files specified by *source-pattern*.
-
-  Example::
-
-    .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
-       :internal:
-
-doc: *title*
-  Include documentation for the ``DOC:`` paragraph identified by *title* in
-  *source*. Spaces are allowed in *title*; do not quote the *title*. The *title*
-  is only used as an identifier for the paragraph, and is not included in the
-  output. Please make sure to have an appropriate heading in the enclosing
-  reStructuredText document.
-
-  Example::
-
-    .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
-       :doc: High Definition Audio over HDMI and Display Port
-
-functions: *function* *[...]*
-  Include documentation for each *function* in *source*.
-
-  Example::
-
-    .. kernel-doc:: lib/bitmap.c
-       :functions: bitmap_parselist bitmap_parselist_user
-
-Without options, the kernel-doc directive includes all documentation comments
-from the source file.
-
-The kernel-doc extension is included in the kernel source tree, at
-``Documentation/sphinx/kerneldoc.py``. Internally, it uses the
-``scripts/kernel-doc`` script to extract the documentation comments from the
-source.
-
-.. _kernel_doc:
-
 Writing kernel-doc comments
 ===========================
 
-In order to provide embedded, "C" friendly, easy to maintain, but consistent and
-extractable overview, function and type documentation, the Linux kernel has
-adopted a consistent style for documentation comments. The format for this
-documentation is called the kernel-doc format, described below. This style
-embeds the documentation within the source files, using a few simple conventions
-for adding documentation paragraphs and documenting functions and their
-parameters, structures and unions and their members, enumerations, and typedefs.
-
-.. note:: The kernel-doc format is deceptively similar to gtk-doc or Doxygen,
-   yet distinctively different, for historical reasons. The kernel source
-   contains tens of thousands of kernel-doc comments. Please stick to the style
-   described here.
-
-The ``scripts/kernel-doc`` script is used by the Sphinx kernel-doc extension in
-the documentation build to extract this embedded documentation into the various
-HTML, PDF, and other format documents.
-
-In order to provide good documentation of kernel functions and data structures,
-please use the following conventions to format your kernel-doc comments in the
-Linux kernel source.
-
-How to format kernel-doc comments
----------------------------------
+The Linux kernel source files may contain structured documentation
+comments in the kernel-doc format to describe the functions, types
+and design of the code. It is easier to keep documentation up-to-date
+when it is embedded in source files.
 
-The opening comment mark ``/**`` is reserved for kernel-doc comments. Only
-comments so marked will be considered by the ``kernel-doc`` tool. Use it only
-for comment blocks that contain kernel-doc formatted comments. The usual ``*/``
-should be used as the closing comment marker. The lines in between should be
-prefixed by `` * `` (space star space).
+.. note:: The kernel-doc format is deceptively similar to javadoc,
+   gtk-doc or Doxygen, yet distinctively different, for historical
+   reasons. The kernel source contains tens of thousands of kernel-doc
+   comments. Please stick to the style described here.
 
-The function and type kernel-doc comments should be placed just before the
-function or type being described. The overview kernel-doc comments may be freely
-placed at the top indentation level.
-
-Example kernel-doc function comment::
-
-  /**
-   * foobar() - Brief description of foobar.
-   * @argument1: Description of parameter argument1 of foobar.
-   * @argument2: Description of parameter argument2 of foobar.
-   *
-   * Longer description of foobar.
-   *
-   * Return: Description of return value of foobar.
-   */
-  int foobar(int argument1, char *argument2)
-
-The format is similar for documentation for structures, enums, paragraphs,
-etc. See the sections below for specific details of each type.
-
-The kernel-doc structure is extracted from the comments, and proper `Sphinx C
-Domain`_ function and type descriptions with anchors are generated for them. The
-descriptions are filtered for special kernel-doc highlights and
-cross-references. See below for details.
+The kernel-doc structure is extracted from the comments, and proper
+`Sphinx C Domain`_ function and type descriptions with anchors are
+generated from them. The descriptions are filtered for special kernel-doc
+highlights and cross-references. See below for details.
 
 .. _Sphinx C Domain: http://www.sphinx-doc.org/en/stable/domains.html
 
+Every function that is exported to loadable modules using
+``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` should have a kernel-doc
+comment. Functions and data structures in header files which are intended
+to be used by modules should also have kernel-doc comments.
 
-Parameters and member arguments
--------------------------------
-
-The kernel-doc function comments describe each parameter to the function and
-function typedefs or each member of struct/union, in order, with the
-``@argument:`` descriptions. For each non-private member argument, one
-``@argument`` definition is needed.
-
-The ``@argument:`` descriptions begin on the very next line following
-the opening brief function description line, with no intervening blank
-comment lines.
-
-The ``@argument:`` descriptions may span multiple lines.
-
-.. note::
-
-   If the ``@argument`` description has multiple lines, the continuation
-   of the description should be starting exactly at the same column as
-   the previous line, e. g.::
-
-      * @argument: some long description
-      *       that continues on next lines
-
-   or::
-
-      * @argument:
-      *		some long description
-      *		that continues on next lines
-
-If a function or typedef parameter argument is ``...`` (e. g. a variable
-number of arguments), its description should be listed in kernel-doc
-notation as::
-
-      * @...: description
+It is good practice to also provide kernel-doc formatted documentation
+for functions externally visible to other kernel files (not marked
+``static``). We also recommend providing kernel-doc formatted
+documentation for private (file ``static``) routines, for consistency of
+kernel source code layout. This is lower priority and at the discretion
+of the maintainer of that kernel source file.
 
-Private members
-~~~~~~~~~~~~~~~
-
-Inside a struct or union description, you can use the ``private:`` and
-``public:`` comment tags. Structure fields that are inside a ``private:``
-area are not listed in the generated output documentation.
+How to format kernel-doc comments
+---------------------------------
 
-The ``private:`` and ``public:`` tags must begin immediately following a
-``/*`` comment marker.  They may optionally include comments between the
-``:`` and the ending ``*/`` marker.
+The opening comment mark ``/**`` is used for kernel-doc comments. The
+``kernel-doc`` tool will extract comments marked this way. The rest of
+the comment is formatted like a normal multi-line comment with a column
+of asterisks on the left side, closing with ``*/`` on a line by itself.
 
-Example::
-
-  /**
-   * struct my_struct - short description
-   * @a: first member
-   * @b: second member
-   * @d: fourth member
-   *
-   * Longer description
-   */
-  struct my_struct {
-      int a;
-      int b;
-  /* private: internal use only */
-      int c;
-  /* public: the next one is public */
-      int d;
-  };
+The function and type kernel-doc comments should be placed just before
+the function or type being described in order to maximise the chance
+that somebody changing the code will also change the documentation. The
+overview kernel-doc comments may be placed anywhere at the top indentation
+level.
 
 Function documentation
 ----------------------
@@ -216,6 +63,9 @@ The general format of a function and function-like macro kernel-doc comment is::
    *
    * The longer description may have multiple paragraphs.
    *
+   * Context: Describes whether the function can sleep, what locks it takes,
+   *          releases, or expects to be held. It can extend over multiple
+   *          lines.
    * Return: Describe the return value of foobar.
    *
    * The return value description can also have multiple paragraphs, and should
@@ -226,6 +76,52 @@ The brief description following the function name may span multiple lines, and
 ends with an argument description, a blank comment line, or the end of the
 comment block.
 
+Function parameters
+~~~~~~~~~~~~~~~~~~~
+
+Each function argument should be described in order, immediately following
+the short function description.  Do not leave a blank line between the
+function description and the arguments, nor between the arguments.
+
+Each ``@argument:`` description may span multiple lines.
+
+.. note::
+
+   If the ``@argument`` description has multiple lines, the continuation
+   of the description should start at the same column as the previous line::
+
+      * @argument: some long description
+      *            that continues on next lines
+
+   or::
+
+      * @argument:
+      *		some long description
+      *		that continues on next lines
+
+If a function has a variable number of arguments, its description should
+be written in kernel-doc notation as::
+
+      * @...: description
+
+Function context
+~~~~~~~~~~~~~~~~
+
+The context in which a function can be called should be described in a
+section named ``Context``. This should include whether the function
+sleeps or can be called from interrupt context, as well as what locks
+it takes, releases and expects to be held by its caller.
+
+Examples::
+
+  * Context: Any context.
+  * Context: Any context. Takes and releases the RCU lock.
+  * Context: Any context. Expects <lock> to be held by caller.
+  * Context: Process context. May sleep if @gfp flags permit.
+  * Context: Process context. Takes and releases <mutex>.
+  * Context: Softirq or process context. Takes and releases <lock>, BH-safe.
+  * Context: Interrupt context.
+
 Return values
 ~~~~~~~~~~~~~
 
@@ -255,7 +151,7 @@ named ``Return``.
 
   #) If the descriptive text you provide has lines that begin with
      some phrase followed by a colon, each of those phrases will be taken
-     as a new section heading, with probably won't produce the desired
+     as a new section heading, which probably won't produce the desired
      effect.
 
 Structure, union, and enumeration documentation
@@ -265,69 +161,144 @@ The general format of a struct, union, and enum kernel-doc comment is::
 
   /**
    * struct struct_name - Brief description.
-   * @argument: Description of member member_name.
+   * @member1: Description of member1.
+   * @member2: Description of member2.
+   *           One can provide multiple line descriptions
+   *           for members.
    *
    * Description of the structure.
    */
 
-On the above, ``struct`` is used to mean structs. You can also use ``union``
-and ``enum``  to describe unions and enums. ``argument`` is used
-to mean struct and union member names as well as enumerations in an enum.
+You can replace the ``struct`` in the above example with ``union`` or
+``enum``  to describe unions or enums. ``member`` is used to mean struct
+and union member names as well as enumerations in an enum.
 
-The brief description following the structure name may span multiple lines, and
-ends with a member description, a blank comment line, or the end of the
-comment block.
+The brief description following the structure name may span multiple
+lines, and ends with a member description, a blank comment line, or the
+end of the comment block.
+
+Members
+~~~~~~~
+
+Members of structs, unions and enums should be documented the same way
+as function parameters; they immediately succeed the short description
+and may be multi-line.
+
+Inside a struct or union description, you can use the ``private:`` and
+``public:`` comment tags. Structure fields that are inside a ``private:``
+area are not listed in the generated output documentation.
+
+The ``private:`` and ``public:`` tags must begin immediately following a
+``/*`` comment marker. They may optionally include comments between the
+``:`` and the ending ``*/`` marker.
 
-The kernel-doc data structure comments describe each member of the structure,
-in order, with the member descriptions.
+Example::
+
+  /**
+   * struct my_struct - short description
+   * @a: first member
+   * @b: second member
+   * @d: fourth member
+   *
+   * Longer description
+   */
+  struct my_struct {
+      int a;
+      int b;
+  /* private: internal use only */
+      int c;
+  /* public: the next one is public */
+      int d;
+  };
 
 Nested structs/unions
 ~~~~~~~~~~~~~~~~~~~~~
 
-It is possible to document nested structs unions, like::
+It is possible to document nested structs and unions, like::
 
       /**
        * struct nested_foobar - a struct with nested unions and structs
-       * @arg1: - first argument of anonymous union/anonymous struct
-       * @arg2: - second argument of anonymous union/anonymous struct
-       * @arg3: - third argument of anonymous union/anonymous struct
-       * @arg4: - fourth argument of anonymous union/anonymous struct
-       * @bar.st1.arg1 - first argument of struct st1 on union bar
-       * @bar.st1.arg2 - second argument of struct st1 on union bar
-       * @bar.st2.arg1 - first argument of struct st2 on union bar
-       * @bar.st2.arg2 - second argument of struct st2 on union bar
+       * @memb1: first member of anonymous union/anonymous struct
+       * @memb2: second member of anonymous union/anonymous struct
+       * @memb3: third member of anonymous union/anonymous struct
+       * @memb4: fourth member of anonymous union/anonymous struct
+       * @bar: non-anonymous union
+       * @bar.st1: struct st1 inside @bar
+       * @bar.st2: struct st2 inside @bar
+       * @bar.st1.memb1: first member of struct st1 on union bar
+       * @bar.st1.memb2: second member of struct st1 on union bar
+       * @bar.st2.memb1: first member of struct st2 on union bar
+       * @bar.st2.memb2: second member of struct st2 on union bar
+       */
       struct nested_foobar {
         /* Anonymous union/struct*/
         union {
           struct {
-            int arg1;
-            int arg2;
-	  }
+            int memb1;
+            int memb2;
+        }
           struct {
-            void *arg3;
-            int arg4;
-	  }
-	}
-	union {
+            void *memb3;
+            int memb4;
+          }
+        }
+        union {
           struct {
-            int arg1;
-            int arg2;
-	  } st1;
+            int memb1;
+            int memb2;
+          } st1;
           struct {
-            void *arg1;
-            int arg2;
-	  } st2;
-	} bar;
+            void *memb1;
+            int memb2;
+          } st2;
+        } bar;
       };
 
 .. note::
 
    #) When documenting nested structs or unions, if the struct/union ``foo``
-      is named, the argument ``bar`` inside it should be documented as
+      is named, the member ``bar`` inside it should be documented as
       ``@foo.bar:``
-   #) When the nested struct/union is anonymous, the argument ``bar`` on it
+   #) When the nested struct/union is anonymous, the member ``bar`` in it
       should be documented as ``@bar:``
 
+In-line member documentation comments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The structure members may also be documented in-line within the definition.
+There are two styles, single-line comments where both the opening ``/**`` and
+closing ``*/`` are on the same line, and multi-line comments where they are each
+on a line of their own, like all other kernel-doc comments::
+
+  /**
+   * struct foo - Brief description.
+   * @foo: The Foo member.
+   */
+  struct foo {
+        int foo;
+        /**
+         * @bar: The Bar member.
+         */
+        int bar;
+        /**
+         * @baz: The Baz member.
+         *
+         * Here, the member description may contain several paragraphs.
+         */
+        int baz;
+        union {
+                /** @foobar: Single line description. */
+                int foobar;
+        };
+        /** @bar2: Description for struct @bar2 inside @foo */
+        struct {
+                /**
+                 * @bar2.barbar: Description for @barbar inside @foo.bar2
+                 */
+                int barbar;
+        } bar2;
+  };
+
 Typedef documentation
 ---------------------
 
@@ -347,10 +318,12 @@ Typedefs with function prototypes can also be documented::
    * @arg2: description of arg2
    *
    * Description of the type.
+   *
+   * Context: Locking context.
+   * Return: Meaning of the return value.
    */
    typedef void (*type_name)(struct v4l2_ctrl *arg1, void *arg2);
 
-
 Highlights and cross-references
 -------------------------------
 
@@ -422,37 +395,6 @@ cross-references.
 
 For further details, please refer to the `Sphinx C Domain`_ documentation.
 
-
-
-In-line member documentation comments
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The structure members may also be documented in-line within the definition.
-There are two styles, single-line comments where both the opening ``/**`` and
-closing ``*/`` are on the same line, and multi-line comments where they are each
-on a line of their own, like all other kernel-doc comments::
-
-  /**
-   * struct foo - Brief description.
-   * @foo: The Foo member.
-   */
-  struct foo {
-        int foo;
-        /**
-         * @bar: The Bar member.
-         */
-        int bar;
-        /**
-         * @baz: The Baz member.
-         *
-         * Here, the member description may contain several paragraphs.
-         */
-        int baz;
-        /** @foobar: Single line description. */
-        int foobar;
-  }
-
-
 Overview documentation comments
 -------------------------------
 
@@ -482,53 +424,81 @@ The title following ``DOC:`` acts as a heading within the source file, but also
 as an identifier for extracting the documentation comment. Thus, the title must
 be unique within the file.
 
-Recommendations
----------------
+Including kernel-doc comments
+=============================
 
-We definitely need kernel-doc formatted documentation for functions that are
-exported to loadable modules using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL``.
+The documentation comments may be included in any of the reStructuredText
+documents using a dedicated kernel-doc Sphinx directive extension.
 
-We also look to provide kernel-doc formatted documentation for functions
-externally visible to other kernel files (not marked "static").
+The kernel-doc directive is of the format::
 
-We also recommend providing kernel-doc formatted documentation for private (file
-"static") routines, for consistency of kernel source code layout. But this is
-lower priority and at the discretion of the MAINTAINER of that kernel source
-file.
+  .. kernel-doc:: source
+     :option:
 
-Data structures visible in kernel include files should also be documented using
-kernel-doc formatted comments.
+The *source* is the path to a source file, relative to the kernel source
+tree. The following directive options are supported:
 
-How to use kernel-doc to generate man pages
--------------------------------------------
+export: *[source-pattern ...]*
+  Include documentation for all functions in *source* that have been exported
+  using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` either in *source* or in any
+  of the files specified by *source-pattern*.
 
-If you just want to use kernel-doc to generate man pages you can do this
-from the Kernel git tree::
+  The *source-pattern* is useful when the kernel-doc comments have been placed
+  in header files, while ``EXPORT_SYMBOL`` and ``EXPORT_SYMBOL_GPL`` are next to
+  the function definitions.
 
-  $ scripts/kernel-doc -man $(git grep -l '/\*\*' |grep -v Documentation/) | ./split-man.pl /tmp/man
+  Examples::
 
-Using the small ``split-man.pl`` script below::
+    .. kernel-doc:: lib/bitmap.c
+       :export:
 
+    .. kernel-doc:: include/net/mac80211.h
+       :export: net/mac80211/*.c
 
-  #!/usr/bin/perl
+internal: *[source-pattern ...]*
+  Include documentation for all functions and types in *source* that have
+  **not** been exported using ``EXPORT_SYMBOL`` or ``EXPORT_SYMBOL_GPL`` either
+  in *source* or in any of the files specified by *source-pattern*.
 
-  if ($#ARGV < 0) {
-     die "where do I put the results?\n";
-  }
+  Example::
 
-  mkdir $ARGV[0],0777;
-  $state = 0;
-  while (<STDIN>) {
-      if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) {
-	if ($state == 1) { close OUT }
-	$state = 1;
-	$fn = "$ARGV[0]/$1.9";
-	print STDERR "Creating $fn\n";
-	open OUT, ">$fn" or die "can't open $fn: $!\n";
-	print OUT $_;
-      } elsif ($state != 0) {
-	print OUT $_;
-      }
-  }
+    .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
+       :internal:
+
+doc: *title*
+  Include documentation for the ``DOC:`` paragraph identified by *title* in
+  *source*. Spaces are allowed in *title*; do not quote the *title*. The *title*
+  is only used as an identifier for the paragraph, and is not included in the
+  output. Please make sure to have an appropriate heading in the enclosing
+  reStructuredText document.
+
+  Example::
+
+    .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
+       :doc: High Definition Audio over HDMI and Display Port
+
+functions: *function* *[...]*
+  Include documentation for each *function* in *source*.
+
+  Example::
+
+    .. kernel-doc:: lib/bitmap.c
+       :functions: bitmap_parselist bitmap_parselist_user
+
+Without options, the kernel-doc directive includes all documentation comments
+from the source file.
+
+The kernel-doc extension is included in the kernel source tree, at
+``Documentation/sphinx/kerneldoc.py``. Internally, it uses the
+``scripts/kernel-doc`` script to extract the documentation comments from the
+source.
+
+.. _kernel_doc:
+
+How to use kernel-doc to generate man pages
+-------------------------------------------
+
+If you just want to use kernel-doc to generate man pages you can do this
+from the kernel git tree::
 
-  close OUT;
+  $ scripts/kernel-doc -man $(git grep -l '/\*\*' -- :^Documentation :^tools) | scripts/split-man.pl /tmp/man
diff --git a/Documentation/driver-api/mtdnand.rst b/Documentation/driver-api/mtdnand.rst
index 2a5191b6d445..dcd63599f700 100644
--- a/Documentation/driver-api/mtdnand.rst
+++ b/Documentation/driver-api/mtdnand.rst
@@ -967,10 +967,10 @@ API functions which are exported. Each function has a short description
 which is marked with an [XXX] identifier. See the chapter "Documentation
 hints" for an explanation.
 
-.. kernel-doc:: drivers/mtd/nand/nand_base.c
+.. kernel-doc:: drivers/mtd/nand/raw/nand_base.c
    :export:
 
-.. kernel-doc:: drivers/mtd/nand/nand_ecc.c
+.. kernel-doc:: drivers/mtd/nand/raw/nand_ecc.c
    :export:
 
 Internal Functions Provided
@@ -982,10 +982,10 @@ marked with an [XXX] identifier. See the chapter "Documentation hints"
 for an explanation. The functions marked with [DEFAULT] might be
 relevant for a board driver developer.
 
-.. kernel-doc:: drivers/mtd/nand/nand_base.c
+.. kernel-doc:: drivers/mtd/nand/raw/nand_base.c
    :internal:
 
-.. kernel-doc:: drivers/mtd/nand/nand_bbt.c
+.. kernel-doc:: drivers/mtd/nand/raw/nand_bbt.c
    :internal:
 
 Credits
diff --git a/Documentation/features/list-arch.sh b/Documentation/features/list-arch.sh
index c16b5b595688..1ec47c3bb5fa 100755
--- a/Documentation/features/list-arch.sh
+++ b/Documentation/features/list-arch.sh
@@ -17,7 +17,7 @@ for F in */*/arch-support.txt; do
   N=$(grep -h "^# Feature name:"        $F | cut -c25-)
   C=$(grep -h "^#         Kconfig:"     $F | cut -c25-)
   D=$(grep -h "^#         description:" $F | cut -c25-)
-  S=$(grep -hw $ARCH $F | cut -d\| -f3)
+  S=$(grep -hv "^#" $F | grep -w $ARCH | cut -d\| -f3)
 
   printf "%10s/%-22s:%s| %35s # %s\n" "$SUBSYS" "$N" "$S" "$C" "$D"
 done
diff --git a/Documentation/filesystems/cifs/README b/Documentation/filesystems/cifs/README
index a9da51553ba3..23bcfbd4d967 100644
--- a/Documentation/filesystems/cifs/README
+++ b/Documentation/filesystems/cifs/README
@@ -11,13 +11,14 @@ Information Foundation.  CIFS and now SMB3 has now become a defacto
 standard for interoperating between Macs and Windows and major NAS appliances.
 
 Please see
+  MS-SMB2 (for detailed SMB2/SMB3/SMB3.1.1 protocol specification)
   http://protocolfreedom.org/ and
   http://samba.org/samba/PFIF/
 for more details.
 
 
 For questions or bug reports please contact:
-    sfrench@samba.org (sfrench@us.ibm.com) 
+    smfrench@gmail.com 
 
 See the project page at: https://wiki.samba.org/index.php/LinuxCIFS_utils
 
@@ -37,15 +38,15 @@ Installation instructions:
 =========================
 If you have built the CIFS vfs as module (successfully) simply
 type "make modules_install" (or if you prefer, manually copy the file to
-the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
+the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.ko).
 
 If you have built the CIFS vfs into the kernel itself, follow the instructions
 for your distribution on how to install a new kernel (usually you
 would simply type "make install").
 
-If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on 
-the CIFS VFS web site) copy it to the same directory in which mount.smbfs and 
-similar files reside (usually /sbin).  Although the helper software is not  
+If you do not have the utility mount.cifs (in the Samba 4.x source tree and on 
+the CIFS VFS web site) copy it to the same directory in which mount helpers 
+reside (usually /sbin).  Although the helper software is not  
 required, mount.cifs is recommended.  Most distros include a "cifs-utils"
 package that includes this utility so it is recommended to install this.
 
@@ -118,10 +119,13 @@ this can become unwieldy when potential mount targets include many
 or  unpredictable UNC names.
 
 Samba Considerations 
-==================== 
-To get the maximum benefit from the CIFS VFS, we recommend using a server that 
-supports the SNIA CIFS Unix Extensions standard (e.g.  Samba 2.2.5 or later or 
-Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers.  
+====================
+Most current servers support SMB2.1 and SMB3 which are more secure,
+but there are useful protocol extensions for the older less secure CIFS
+dialect, so to get the maximum benefit if mounting using the older dialect
+(CIFS/SMB1), we recommend using a server that supports the SNIA CIFS
+Unix Extensions standard (e.g. almost any  version of Samba ie version
+2.2.5 or later) but the CIFS vfs works fine with a wide variety of CIFS servers.
 Note that uid, gid and file permissions will display default values if you do 
 not have a server that supports the Unix extensions for CIFS (such as Samba 
 2.2.5 or later).  To enable the Unix CIFS Extensions in the Samba server, add 
@@ -603,11 +607,6 @@ Stats			Lists summary resource usage information as well as per
 			in the kernel configuration.
 
 Configuration pseudo-files:
-PacketSigningEnabled	If set to one, cifs packet signing is enabled
-			and will be used if the server requires 
-			it.  If set to two, cifs packet signing is
-			required even if the server considers packet
-			signing optional. (default 1)
 SecurityFlags		Flags which control security negotiation and
 			also packet signing. Authentication (may/must)
 			flags (e.g. for NTLM and/or NTLMv2) may be combined with
@@ -666,8 +665,6 @@ traceSMB		If set to one, debug information is logged to the
 LookupCacheEnable	If set to one, inode information is kept cached
 			for one second improving performance of lookups
 			(default 1)
-OplockEnabled		If set to one, safe distributed caching enabled.
-			(default 1)
 LinuxExtensionsEnabled	If set to one then the client will attempt to
 			use the CIFS "UNIX" extensions which are optional
 			protocol enhancements that allow CIFS servers
diff --git a/Documentation/filesystems/cifs/TODO b/Documentation/filesystems/cifs/TODO
index 396ecfd6ff4a..c5adf149b57f 100644
--- a/Documentation/filesystems/cifs/TODO
+++ b/Documentation/filesystems/cifs/TODO
@@ -1,4 +1,4 @@
-Version 2.04 September 13, 2017
+Version 2.11 September 13, 2017
 
 A Partial List of Missing Features
 ==================================
@@ -8,10 +8,10 @@ for visible, important contributions to this module.  Here
 is a partial list of the known problems and missing features:
 
 a) SMB3 (and SMB3.02) missing optional features:
-   - RDMA (started)
-   - multichannel (started)
+   - multichannel (started), integration with RDMA
    - directory leases (improved metadata caching)
-   - T10 copy offload (copy chunk is only mechanism supported)
+   - T10 copy offload (copy chunk, and "Duplicate Extents" ioctl
+     currently the only two server side copy mechanisms supported)
 
 b) improved sparse file support
 
@@ -21,9 +21,8 @@ using Directory Leases
 d) quota support (needs minor kernel change since quota calls
 to make it to network filesystems or deviceless filesystems)
 
-e) Better optimize open to reduce redundant opens (using reference
-counts more) and to improve use of compounding in SMB3 to reduce
-number of roundtrips.
+e) Compounding (in progress) to reduce number of roundtrips, and also
+better optimize open to reduce redundant opens (using reference counts more).
 
 f) Finish inotify support so kde and gnome file list windows
 will autorefresh (partially complete by Asser). Needs minor kernel
@@ -35,7 +34,8 @@ the CIFS statistics (started)
 h) implement support for security and trusted categories of xattrs
 (requires minor protocol extension) to enable better support for SELINUX
 
-i) Implement O_DIRECT flag on open (already supported on mount)
+i) Add support for tree connect contexts (see MS-SMB2) a new SMB3.1.1 protocol
+   feature (may be especially useful for virtualization).
 
 j) Create UID mapping facility so server UIDs can be mapped on a per
 mount or a per server basis to client UIDs or nobody if no mapping
@@ -53,13 +53,16 @@ viewing them.
 
 o) mount helper GUI (to simplify the various configuration options on mount)
 
-p) autonegotiation of dialects (offering more than one dialect ie SMB3.02,
-SMB3, SMB2.1 not just SMB3).
+p) Add support for witness protocol (perhaps ioctl to cifs.ko from user space
+   tool listening on witness protocol RPC) to allow for notification of share
+   move, server failover, and server adapter changes.  And also improve other
+   failover scenarios, e.g. when client knows multiple DFS entries point to
+   different servers, and the server we are connected to has gone down.
 
 q) Allow mount.cifs to be more verbose in reporting errors with dialect
 or unsupported feature errors.
 
-r) updating cifs documentation, and user guid.
+r) updating cifs documentation, and user guide.
 
 s) Addressing bugs found by running a broader set of xfstests in standard
 file system xfstest suite.
diff --git a/Documentation/gpio/drivers-on-gpio.txt b/Documentation/gpio/drivers-on-gpio.txt
index a2ccbab12eb7..a3e612f55bc7 100644
--- a/Documentation/gpio/drivers-on-gpio.txt
+++ b/Documentation/gpio/drivers-on-gpio.txt
@@ -74,8 +74,8 @@ hardware descriptions such as device tree or ACPI:
   it from 1-to-0-to-1. If that hardware does not receive its "ping"
   periodically, it will reset the system.
 
-- gpio-nand: drivers/mtd/nand/gpio.c is used to connect a NAND flash chip to
-  a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the
+- gpio-nand: drivers/mtd/nand/raw/gpio.c is used to connect a NAND flash chip
+  to a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the
   NAND flash MTD subsystem and provides chip access and partition parsing like
   any other NAND driving hardware.
 
diff --git a/Documentation/hwmon/sht21 b/Documentation/hwmon/sht21
index 47f4765db256..8b3cdda541c1 100644
--- a/Documentation/hwmon/sht21
+++ b/Documentation/hwmon/sht21
@@ -6,13 +6,13 @@ Supported chips:
     Prefix: 'sht21'
     Addresses scanned: none
     Datasheet: Publicly available at the Sensirion website
-    http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
+    http://www.sensirion.com/file/datasheet_sht21
 
   * Sensirion SHT25
-    Prefix: 'sht21'
+    Prefix: 'sht25'
     Addresses scanned: none
     Datasheet: Publicly available at the Sensirion website
-    http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT25.pdf
+    http://www.sensirion.com/file/datasheet_sht25
 
 Author:
   Urs Fleisch <urs.fleisch@sensirion.com>
diff --git a/Documentation/hwmon/sht3x b/Documentation/hwmon/sht3x
index b0d88184f48e..d9daa6ab1e8e 100644
--- a/Documentation/hwmon/sht3x
+++ b/Documentation/hwmon/sht3x
@@ -5,7 +5,7 @@ Supported chips:
   * Sensirion SHT3x-DIS
     Prefix: 'sht3x'
     Addresses scanned: none
-    Datasheet: http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_Datasheet_SHT3x_DIS.pdf
+    Datasheet: https://www.sensirion.com/file/datasheet_sht3x_digital
 
 Author:
   David Frey <david.frey@sensirion.com>
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 71e9feefb63c..667cd899ada8 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -153,12 +153,18 @@ more details, with real examples.
 	configuration.
 
 	Kbuild compiles all the $(obj-y) files.  It then calls
-	"$(LD) -r" to merge these files into one built-in.o file.
-	built-in.o is later linked into vmlinux by the parent Makefile.
+	"$(AR) rcSTP" to merge these files into one built-in.a file.
+	This is a thin archive without a symbol table, which makes it
+	unsuitable as a linker input.
+
+	The scripts/link-vmlinux.sh script later makes an aggregate
+	built-in.a with "${AR} rcsTP", which creates the thin archive
+	with a symbol table and an index, making it a valid input for
+	the final vmlinux link passes.
 
 	The order of files in $(obj-y) is significant.  Duplicates in
 	the lists are allowed: the first instance will be linked into
-	built-in.o and succeeding instances will be ignored.
+	built-in.a and succeeding instances will be ignored.
 
 	Link order is significant, because certain functions
 	(module_init() / __initcall) will be called during boot in the
@@ -222,7 +228,7 @@ more details, with real examples.
 	Note: Of course, when you are building objects into the kernel,
 	the syntax above will also work. So, if you have CONFIG_EXT2_FS=y,
 	kbuild will build an ext2.o file for you out of the individual
-	parts and then link this into built-in.o, as you would expect.
+	parts and then link this into built-in.a, as you would expect.
 
 --- 3.4 Objects which export symbols
 
@@ -232,7 +238,7 @@ more details, with real examples.
 --- 3.5 Library file goals - lib-y
 
 	Objects listed with obj-* are used for modules, or
-	combined in a built-in.o for that specific directory.
+	combined in a built-in.a for that specific directory.
 	There is also the possibility to list objects that will
 	be included in a library, lib.a.
 	All objects listed with lib-y are combined in a single
@@ -244,7 +250,7 @@ more details, with real examples.
 
 	Note that the same kbuild makefile may list files to be built-in
 	and to be part of a library. Therefore the same directory
-	may contain both a built-in.o and a lib.a file.
+	may contain both a built-in.a and a lib.a file.
 
 	Example:
 		#arch/x86/lib/Makefile
@@ -986,7 +992,7 @@ When kbuild executes, the following steps are followed (roughly):
 
 	$(head-y) lists objects to be linked first in vmlinux.
 	$(libs-y) lists directories where a lib.a archive can be located.
-	The rest list directories where a built-in.o object file can be
+	The rest list directories where a built-in.a object file can be
 	located.
 
 	$(init-y) objects will be located after $(head-y).
@@ -1071,7 +1077,7 @@ When kbuild executes, the following steps are followed (roughly):
 		extra-y := head.o init_task.o
 
 	In this example, extra-y is used to list object files that
-	shall be built, but shall not be linked as part of built-in.o.
+	shall be built, but shall not be linked as part of built-in.a.
 
 
 --- 6.7 Commands useful for building a boot image
diff --git a/Documentation/locking/lockdep-design.txt b/Documentation/locking/lockdep-design.txt
index 9de1c158d44c..49f58a07ee7b 100644
--- a/Documentation/locking/lockdep-design.txt
+++ b/Documentation/locking/lockdep-design.txt
@@ -27,7 +27,8 @@ lock-class.
 State
 -----
 
-The validator tracks lock-class usage history into 4n + 1 separate state bits:
+The validator tracks lock-class usage history into 4 * nSTATEs + 1 separate
+state bits:
 
 - 'ever held in STATE context'
 - 'ever held as readlock in STATE context'
@@ -37,7 +38,6 @@ The validator tracks lock-class usage history into 4n + 1 separate state bits:
 Where STATE can be either one of (kernel/locking/lockdep_states.h)
  - hardirq
  - softirq
- - reclaim_fs
 
 - 'ever used'                                       [ == !unused        ]
 
@@ -169,6 +169,53 @@ Note: When changing code to use the _nested() primitives, be careful and
 check really thoroughly that the hierarchy is correctly mapped; otherwise
 you can get false positives or false negatives.
 
+Annotations
+-----------
+
+Two constructs can be used to annotate and check where and if certain locks
+must be held: lockdep_assert_held*(&lock) and lockdep_*pin_lock(&lock).
+
+As the name suggests, lockdep_assert_held* family of macros assert that a
+particular lock is held at a certain time (and generate a WARN() otherwise).
+This annotation is largely used all over the kernel, e.g. kernel/sched/
+core.c
+
+  void update_rq_clock(struct rq *rq)
+  {
+	s64 delta;
+
+	lockdep_assert_held(&rq->lock);
+	[...]
+  }
+
+where holding rq->lock is required to safely update a rq's clock.
+
+The other family of macros is lockdep_*pin_lock(), which is admittedly only
+used for rq->lock ATM. Despite their limited adoption these annotations
+generate a WARN() if the lock of interest is "accidentally" unlocked. This turns
+out to be especially helpful to debug code with callbacks, where an upper
+layer assumes a lock remains taken, but a lower layer thinks it can maybe drop
+and reacquire the lock ("unwittingly" introducing races). lockdep_pin_lock()
+returns a 'struct pin_cookie' that is then used by lockdep_unpin_lock() to check
+that nobody tampered with the lock, e.g. kernel/sched/sched.h
+
+  static inline void rq_pin_lock(struct rq *rq, struct rq_flags *rf)
+  {
+	rf->cookie = lockdep_pin_lock(&rq->lock);
+	[...]
+  }
+
+  static inline void rq_unpin_lock(struct rq *rq, struct rq_flags *rf)
+  {
+	[...]
+	lockdep_unpin_lock(&rq->lock, rf->cookie);
+  }
+
+While comments about locking requirements might provide useful information,
+the runtime checks performed by annotations are invaluable when debugging
+locking problems and they carry the same level of details when inspecting
+code.  Always prefer annotations when in doubt!
+
 Proof of 100% correctness:
 --------------------------
 
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index a863009849a3..23cf79b481df 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -48,7 +48,7 @@ CONTENTS
 
      - Varieties of memory barrier.
      - What may not be assumed about memory barriers?
-     - Data dependency barriers.
+     - Data dependency barriers (historical).
      - Control dependencies.
      - SMP barrier pairing.
      - Examples of memory barrier sequences.
@@ -550,8 +550,15 @@ There are certain things that the Linux kernel memory barriers do not guarantee:
 	    Documentation/DMA-API.txt
 
 
-DATA DEPENDENCY BARRIERS
-------------------------
+DATA DEPENDENCY BARRIERS (HISTORICAL)
+-------------------------------------
+
+As of v4.15 of the Linux kernel, an smp_read_barrier_depends() was
+added to READ_ONCE(), which means that about the only people who
+need to pay attention to this section are those working on DEC Alpha
+architecture-specific code and those working on READ_ONCE() itself.
+For those who need it, and for those who are interested in the history,
+here is the story of data-dependency barriers.
 
 The usage requirements of data dependency barriers are a little subtle, and
 it's not always obvious that they're needed.  To illustrate, consider the
@@ -2839,8 +2846,9 @@ as that committed on CPU 1.
 
 
 To intervene, we need to interpolate a data dependency barrier or a read
-barrier between the loads.  This will force the cache to commit its coherency
-queue before processing any further requests:
+barrier between the loads (which as of v4.15 is supplied unconditionally
+by the READ_ONCE() macro).  This will force the cache to commit its
+coherency queue before processing any further requests:
 
 	CPU 1		CPU 2		COMMENT
 	===============	===============	=======================================
@@ -2869,8 +2877,8 @@ Other CPUs may also have split caches, but must coordinate between the various
 cachelets for normal memory accesses.  The semantics of the Alpha removes the
 need for hardware coordination in the absence of memory barriers, which
 permitted Alpha to sport higher CPU clock rates back in the day.  However,
-please note that smp_read_barrier_depends() should not be used except in
-Alpha arch-specific code and within the READ_ONCE() macro.
+please note that (again, as of v4.15) smp_read_barrier_depends() should not
+be used except in Alpha arch-specific code and within the READ_ONCE() macro.
 
 
 CACHE COHERENCY VS DMA
@@ -3035,7 +3043,9 @@ the data dependency barrier really becomes necessary as this synchronises both
 caches with the memory coherence system, thus making it seem like pointer
 changes vs new data occur in the right order.
 
-The Alpha defines the Linux kernel's memory barrier model.
+The Alpha defines the Linux kernel's memory model, although as of v4.15
+the Linux kernel's addition of smp_read_barrier_depends() to READ_ONCE()
+greatly reduced Alpha's impact on the memory model.
 
 See the subsection on "Cache Coherency" above.
 
diff --git a/Documentation/networking/segmentation-offloads.txt b/Documentation/networking/segmentation-offloads.txt
index 2f09455a993a..d47480b61ac6 100644
--- a/Documentation/networking/segmentation-offloads.txt
+++ b/Documentation/networking/segmentation-offloads.txt
@@ -13,6 +13,7 @@ The following technologies are described:
  * Generic Segmentation Offload - GSO
  * Generic Receive Offload - GRO
  * Partial Generic Segmentation Offload - GSO_PARTIAL
+ * SCTP accelleration with GSO - GSO_BY_FRAGS
 
 TCP Segmentation Offload
 ========================
@@ -49,6 +50,10 @@ datagram into multiple IPv4 fragments.  Many of the requirements for UDP
 fragmentation offload are the same as TSO.  However the IPv4 ID for
 fragments should not increment as a single IPv4 datagram is fragmented.
 
+UFO is deprecated: modern kernels will no longer generate UFO skbs, but can
+still receive them from tuntap and similar devices. Offload of UDP-based
+tunnel protocols is still supported.
+
 IPIP, SIT, GRE, UDP Tunnel, and Remote Checksum Offloads
 ========================================================
 
@@ -83,10 +88,10 @@ SKB_GSO_UDP_TUNNEL_CSUM.  These two additional tunnel types reflect the
 fact that the outer header also requests to have a non-zero checksum
 included in the outer header.
 
-Finally there is SKB_GSO_REMCSUM which indicates that a given tunnel header
-has requested a remote checksum offload.  In this case the inner headers
-will be left with a partial checksum and only the outer header checksum
-will be computed.
+Finally there is SKB_GSO_TUNNEL_REMCSUM which indicates that a given tunnel
+header has requested a remote checksum offload.  In this case the inner
+headers will be left with a partial checksum and only the outer header
+checksum will be computed.
 
 Generic Segmentation Offload
 ============================
@@ -128,3 +133,28 @@ values for if the header was simply duplicated.  The one exception to this
 is the outer IPv4 ID field.  It is up to the device drivers to guarantee
 that the IPv4 ID field is incremented in the case that a given header does
 not have the DF bit set.
+
+SCTP accelleration with GSO
+===========================
+
+SCTP - despite the lack of hardware support - can still take advantage of
+GSO to pass one large packet through the network stack, rather than
+multiple small packets.
+
+This requires a different approach to other offloads, as SCTP packets
+cannot be just segmented to (P)MTU. Rather, the chunks must be contained in
+IP segments, padding respected. So unlike regular GSO, SCTP can't just
+generate a big skb, set gso_size to the fragmentation point and deliver it
+to IP layer.
+
+Instead, the SCTP protocol layer builds an skb with the segments correctly
+padded and stored as chained skbs, and skb_segment() splits based on those.
+To signal this, gso_size is set to the special value GSO_BY_FRAGS.
+
+Therefore, any code in the core networking stack must be aware of the
+possibility that gso_size will be GSO_BY_FRAGS and handle that case
+appropriately. (For size checks, the skb_gso_validate_*_len family of
+helpers do this automatically.)
+
+This also affects drivers with the NETIF_F_FRAGLIST & NETIF_F_GSO_SCTP bits
+set. Note also that NETIF_F_GSO_SCTP is included in NETIF_F_GSO_SOFTWARE.
diff --git a/Documentation/process/5.Posting.rst b/Documentation/process/5.Posting.rst
index 645fa9c7388a..c209d70da66f 100644
--- a/Documentation/process/5.Posting.rst
+++ b/Documentation/process/5.Posting.rst
@@ -213,7 +213,7 @@ The tags in common use are:
    which can be found in Documentation/process/submitting-patches.rst.  Code without a
    proper signoff cannot be merged into the mainline.
 
- - Co-Developed-by: states that the patch was also created by another developer
+ - Co-developed-by: states that the patch was also created by another developer
    along with the original author.  This is useful at times when multiple
    people work on a single patch.  Note, this person also needs to have a
    Signed-off-by: line in the patch as well.
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
index 81cdb528ad46..4f19a9725f76 100644
--- a/Documentation/process/changes.rst
+++ b/Documentation/process/changes.rst
@@ -78,7 +78,7 @@ Binutils
 --------
 
 The build system has, as of 4.13, switched to using thin archives (`ar T`)
-rather than incremental linking (`ld -r`) for built-in.o intermediate steps.
+rather than incremental linking (`ld -r`) for built-in.a intermediate steps.
 This requires binutils 2.20 or newer.
 
 Flex
diff --git a/Documentation/process/howto.rst b/Documentation/process/howto.rst
index c6875b1db56f..3df55811b916 100644
--- a/Documentation/process/howto.rst
+++ b/Documentation/process/howto.rst
@@ -213,13 +213,6 @@ will learn the basics of getting your patch into the Linux kernel tree,
 and possibly be pointed in the direction of what to go work on next, if
 you do not already have an idea.
 
-If you already have a chunk of code that you want to put into the kernel
-tree, but need some help getting it in the proper form, the
-kernel-mentors project was created to help you out with this.  It is a
-mailing list, and can be found at:
-
-	https://selenic.com/mailman/listinfo/kernel-mentors
-
 Before making any actual modifications to the Linux kernel code, it is
 imperative to understand how the code in question works.  For this
 purpose, nothing is better than reading through it directly (most tricky
@@ -381,14 +374,6 @@ bugs is one of the best ways to get merits among other developers, because
 not many people like wasting time fixing other people's bugs.
 
 To work in the already reported bug reports, go to https://bugzilla.kernel.org.
-If you want to be advised of the future bug reports, you can subscribe to the
-bugme-new mailing list (only new bug reports are mailed here) or to the
-bugme-janitor mailing list (every change in the bugzilla is mailed here)
-
-	https://lists.linux-foundation.org/mailman/listinfo/bugme-new
-
-	https://lists.linux-foundation.org/mailman/listinfo/bugme-janitors
-
 
 
 Mailing lists
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index ff234d229cbb..17256f2ad919 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -312,8 +312,6 @@ The lowmem_reserve_ratio is an array. You can see them by reading this file.
 % cat /proc/sys/vm/lowmem_reserve_ratio
 256     256     32
 -
-Note: # of this elements is one fewer than number of zones. Because the highest
-      zone's value is not necessary for following calculation.
 
 But, these values are not used directly. The kernel calculates # of protection
 pages for each zones from them. These are shown as array of protection pages
@@ -364,7 +362,8 @@ As above expression, they are reciprocal number of ratio.
 pages of higher zones on the node.
 
 If you would like to protect more pages, smaller values are effective.
-The minimum value is 1 (1/1 -> 100%).
+The minimum value is 1 (1/1 -> 100%). The value less than 1 completely
+disables protection of the pages.
 
 ==============================================================
 
diff --git a/Documentation/timers/NO_HZ.txt b/Documentation/timers/NO_HZ.txt
index 2dcaf9adb7a7..9591092da5e0 100644
--- a/Documentation/timers/NO_HZ.txt
+++ b/Documentation/timers/NO_HZ.txt
@@ -131,13 +131,6 @@ error message, and the boot CPU will be removed from the mask.  Note that
 this means that your system must have at least two CPUs in order for
 CONFIG_NO_HZ_FULL=y to do anything for you.
 
-Alternatively, the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter specifies
-that all CPUs other than the boot CPU are adaptive-ticks CPUs.  This
-Kconfig parameter will be overridden by the "nohz_full=" boot parameter,
-so that if both the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter and
-the "nohz_full=1" boot parameter is specified, the boot parameter will
-prevail so that only CPU 1 will be an adaptive-ticks CPU.
-
 Finally, adaptive-ticks CPUs must have their RCU callbacks offloaded.
 This is covered in the "RCU IMPLICATIONS" section below.
 
diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt
index a33c88cd5d1d..6f0120c3a4f1 100644
--- a/Documentation/trace/coresight.txt
+++ b/Documentation/trace/coresight.txt
@@ -330,3 +330,54 @@ Details on how to use the generic STM API can be found here [2].
 
 [1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
 [2]. Documentation/trace/stm.txt
+
+
+Using perf tools
+----------------
+
+perf can be used to record and analyze trace of programs.
+
+Execution can be recorded using 'perf record' with the cs_etm event,
+specifying the name of the sink to record to, e.g:
+
+    perf record -e cs_etm/@20070000.etr/u --per-thread
+
+The 'perf report' and 'perf script' commands can be used to analyze execution,
+synthesizing instruction and branch events from the instruction trace.
+'perf inject' can be used to replace the trace data with the synthesized events.
+The --itrace option controls the type and frequency of synthesized events
+(see perf documentation).
+
+Note that only 64-bit programs are currently supported - further work is
+required to support instruction decode of 32-bit Arm programs.
+
+
+Generating coverage files for Feedback Directed Optimization: AutoFDO
+---------------------------------------------------------------------
+
+'perf inject' accepts the --itrace option in which case tracing data is
+removed and replaced with the synthesized events. e.g.
+
+	perf inject --itrace --strip -i perf.data -o perf.data.new
+
+Below is an example of using ARM ETM for autoFDO.  It requires autofdo
+(https://github.com/google/autofdo) and gcc version 5.  The bubble
+sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial).
+
+	$ gcc-5 -O3 sort.c -o sort
+	$ taskset -c 2 ./sort
+	Bubble sorting array of 30000 elements
+	5910 ms
+
+	$ perf record -e cs_etm/@20070000.etr/u --per-thread taskset -c 2 ./sort
+	Bubble sorting array of 30000 elements
+	12543 ms
+	[ perf record: Woken up 35 times to write data ]
+	[ perf record: Captured and wrote 69.640 MB perf.data ]
+
+	$ perf inject -i perf.data -o inj.data --itrace=il64 --strip
+	$ create_gcov --binary=./sort --profile=inj.data --gcov=sort.gcov -gcov_version=1
+	$ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo
+	$ taskset -c 2 ./sort_autofdo
+	Bubble sorting array of 30000 elements
+	5806 ms
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt
index 2cc08d4a326e..1d486660b40f 100644
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -294,7 +294,7 @@ PID listed in the set_event_pid file.
 
 # cd /sys/kernel/debug/tracing
 # echo $$ > set_event_pid
-# echo 1 > events/enabled
+# echo 1 > events/enable
 
 Will only trace events for the current task.
 
diff --git a/Documentation/x86/x86_64/5level-paging.txt b/Documentation/x86/x86_64/5level-paging.txt
index 087251a0d99c..2432a5ef86d9 100644
--- a/Documentation/x86/x86_64/5level-paging.txt
+++ b/Documentation/x86/x86_64/5level-paging.txt
@@ -20,12 +20,9 @@ Documentation/x86/x86_64/mm.txt
 
 CONFIG_X86_5LEVEL=y enables the feature.
 
-So far, a kernel compiled with the option enabled will be able to boot
-only on machines that supports the feature -- see for 'la57' flag in
-/proc/cpuinfo.
-
-The plan is to implement boot-time switching between 4- and 5-level paging
-in the future.
+Kernel with CONFIG_X86_5LEVEL=y still able to boot on 4-level hardware.
+In this case additional page table level -- p4d -- will be folded at
+runtime.
 
 == User-space and large virtual address space ==
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 9a7f76eadae9..43b45a15106b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1152,7 +1152,7 @@ S:	Maintained
 F:	drivers/clk/sunxi/
 
 ARM/Allwinner sunXi SoC support
-M:	Maxime Ripard <maxime.ripard@free-electrons.com>
+M:	Maxime Ripard <maxime.ripard@bootlin.com>
 M:	Chen-Yu Tsai <wens@csie.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
@@ -1590,7 +1590,7 @@ ARM/Marvell Dove/MV78xx0/Orion SOC support
 M:	Jason Cooper <jason@lakedaemon.net>
 M:	Andrew Lunn <andrew@lunn.ch>
 M:	Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-M:	Gregory Clement <gregory.clement@free-electrons.com>
+M:	Gregory Clement <gregory.clement@bootlin.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	Documentation/devicetree/bindings/soc/dove/
@@ -1604,7 +1604,7 @@ F:	arch/arm/boot/dts/orion5x*
 ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support
 M:	Jason Cooper <jason@lakedaemon.net>
 M:	Andrew Lunn <andrew@lunn.ch>
-M:	Gregory Clement <gregory.clement@free-electrons.com>
+M:	Gregory Clement <gregory.clement@bootlin.com>
 M:	Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
@@ -1710,7 +1710,7 @@ F:	drivers/input/keyboard/w90p910_keypad.c
 F:	drivers/input/touchscreen/w90p910_ts.c
 F:	drivers/watchdog/nuc900_wdt.c
 F:	drivers/net/ethernet/nuvoton/w90p910_ether.c
-F:	drivers/mtd/nand/nuc900_nand.c
+F:	drivers/mtd/nand/raw/nuc900_nand.c
 F:	drivers/rtc/rtc-nuc900.c
 F:	drivers/spi/spi-nuc900.c
 F:	drivers/usb/host/ehci-w90x900.c
@@ -1863,7 +1863,6 @@ Q:	https://patchwork.kernel.org/project/linux-samsung-soc/list/
 S:	Maintained
 F:	arch/arm/boot/dts/s3c*
 F:	arch/arm/boot/dts/s5p*
-F:	arch/arm/boot/dts/samsung*
 F:	arch/arm/boot/dts/exynos*
 F:	arch/arm64/boot/dts/exynos/
 F:	arch/arm/plat-samsung/
@@ -2475,7 +2474,6 @@ M:	Paul Moore <paul@paul-moore.com>
 M:	Eric Paris <eparis@redhat.com>
 L:	linux-audit@redhat.com (moderated for non-subscribers)
 W:	https://github.com/linux-audit
-W:	https://people.redhat.com/sgrubb/audit
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
 S:	Supported
 F:	include/linux/audit.h
@@ -3014,7 +3012,7 @@ M:	Kamal Dasu <kdasu.kdev@gmail.com>
 L:	linux-mtd@lists.infradead.org
 L:	bcm-kernel-feedback-list@broadcom.com
 S:	Maintained
-F:	drivers/mtd/nand/brcmnand/
+F:	drivers/mtd/nand/raw/brcmnand/
 
 BROADCOM STB DPFE DRIVER
 M:	Markus Mayer <mmayer@broadcom.com>
@@ -3282,12 +3280,11 @@ F:	drivers/net/ieee802154/cc2520.c
 F:	include/linux/spi/cc2520.h
 F:	Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
 
-CCREE ARM TRUSTZONE CRYPTOCELL 700 REE DRIVER
+CCREE ARM TRUSTZONE CRYPTOCELL REE DRIVER
 M:	Gilad Ben-Yossef <gilad@benyossef.com>
 L:	linux-crypto@vger.kernel.org
-L:	driverdev-devel@linuxdriverproject.org
 S:	Supported
-F:	drivers/staging/ccree/
+F:	drivers/crypto/ccree/
 W:	https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
 
 CEC FRAMEWORK
@@ -4116,7 +4113,7 @@ DENALI NAND DRIVER
 M:	Masahiro Yamada <yamada.masahiro@socionext.com>
 L:	linux-mtd@lists.infradead.org
 S:	Supported
-F:	drivers/mtd/nand/denali*
+F:	drivers/mtd/nand/raw/denali*
 
 DESIGNWARE USB2 DRD IP DRIVER
 M:	John Youn <johnyoun@synopsys.com>
@@ -4456,6 +4453,13 @@ T:	git git://anongit.freedesktop.org/drm/drm-misc
 S:	Supported
 F:	drivers/gpu/drm/pl111/
 
+DRM DRIVER FOR ARM VERSATILE TFT PANELS
+M:	Linus Walleij <linus.walleij@linaro.org>
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+S:	Maintained
+F:	drivers/gpu/drm/panel/panel-arm-versatile.c
+F:	Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt
+
 DRM DRIVER FOR AST SERVER GRAPHICS CHIPS
 M:	Dave Airlie <airlied@redhat.com>
 S:	Odd Fixes
@@ -4610,8 +4614,8 @@ F:	include/uapi/drm/
 F:	include/linux/vga*
 
 DRM DRIVERS AND MISC GPU PATCHES
-M:	Daniel Vetter <daniel.vetter@intel.com>
 M:	Gustavo Padovan <gustavo@padovan.org>
+M:	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
 M:	Sean Paul <seanpaul@chromium.org>
 W:	https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
 S:	Maintained
@@ -4624,7 +4628,7 @@ F:	include/uapi/drm/drm*
 F:	include/linux/vga*
 
 DRM DRIVERS FOR ALLWINNER A10
-M:	Maxime Ripard  <maxime.ripard@free-electrons.com>
+M:	Maxime Ripard  <maxime.ripard@bootlin.com>
 L:	dri-devel@lists.freedesktop.org
 S:	Supported
 F:	drivers/gpu/drm/sun4i/
@@ -5646,7 +5650,7 @@ FREESCALE GPMI NAND DRIVER
 M:	Han Xu <han.xu@nxp.com>
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
-F:	drivers/mtd/nand/gpmi-nand/*
+F:	drivers/mtd/nand/raw/gpmi-nand/*
 
 FREESCALE I2C CPM DRIVER
 M:	Jochen Friedrich <jochen@scram.de>
@@ -6955,7 +6959,7 @@ INGENIC JZ4780 NAND DRIVER
 M:	Harvey Hunt <harveyhuntnexus@gmail.com>
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
-F:	drivers/mtd/nand/jz4780_*
+F:	drivers/mtd/nand/raw/jz4780_*
 
 INOTIFY
 M:	Jan Kara <jack@suse.cz>
@@ -7227,6 +7231,14 @@ L:	linux-rdma@vger.kernel.org
 S:	Supported
 F:	drivers/infiniband/hw/i40iw/
 
+INTEL SHA MULTIBUFFER DRIVER
+M:	Megha Dey <megha.dey@linux.intel.com>
+R:	Tim Chen <tim.c.chen@linux.intel.com>
+L:	linux-crypto@vger.kernel.org
+S:	Supported
+F:	arch/x86/crypto/sha*-mb
+F:	crypto/mcryptd.c
+
 INTEL TELEMETRY DRIVER
 M:	Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>
 L:	platform-driver-x86@vger.kernel.org
@@ -8474,7 +8486,7 @@ MARVELL NAND CONTROLLER DRIVER
 M:	Miquel Raynal <miquel.raynal@free-electrons.com>
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
-F:	drivers/mtd/nand/marvell_nand.c
+F:	drivers/mtd/nand/raw/marvell_nand.c
 F:	Documentation/devicetree/bindings/mtd/marvell-nand.txt
 
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
@@ -9003,6 +9015,7 @@ M:	Vadim Pasternak <vadimp@mellanox.com>
 L:	linux-leds@vger.kernel.org
 S:	Supported
 F:	drivers/leds/leds-mlxcpld.c
+F:	drivers/leds/leds-mlxreg.c
 F:	Documentation/leds/leds-mlxcpld.txt
 
 MELLANOX PLATFORM DRIVER
@@ -9136,7 +9149,7 @@ M:	Wenyou Yang <wenyou.yang@microchip.com>
 M:	Josh Wu <rainyfeeling@outlook.com>
 L:	linux-mtd@lists.infradead.org
 S:	Supported
-F:	drivers/mtd/nand/atmel/*
+F:	drivers/mtd/nand/raw/atmel/*
 F:	Documentation/devicetree/bindings/mtd/atmel-nand.txt
 
 MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
@@ -9922,6 +9935,13 @@ F:	Documentation/ABI/stable/sysfs-bus-nvmem
 F:	include/linux/nvmem-consumer.h
 F:	include/linux/nvmem-provider.h
 
+NXP SGTL5000 DRIVER
+M:	Fabio Estevam <fabio.estevam@nxp.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/sgtl5000.txt
+F:	sound/soc/codecs/sgtl5000*
+
 NXP TDA998X DRM DRIVER
 M:	Russell King <linux@armlinux.org.uk>
 S:	Supported
@@ -10834,6 +10854,7 @@ F:	drivers/platform/x86/peaq-wmi.c
 PER-CPU MEMORY ALLOCATOR
 M:	Tejun Heo <tj@kernel.org>
 M:	Christoph Lameter <cl@linux.com>
+M:	Dennis Zhou <dennisszhou@gmail.com>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git
 S:	Maintained
 F:	include/linux/percpu*.h
@@ -11333,7 +11354,7 @@ PXA3xx NAND FLASH DRIVER
 M:	Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
-F:	drivers/mtd/nand/pxa3xx_nand.c
+F:	drivers/mtd/nand/raw/pxa3xx_nand.c
 
 QAT DRIVER
 M:	Giovanni Cabiddu <giovanni.cabiddu@intel.com>
@@ -11695,7 +11716,7 @@ X:	kernel/torture.c
 
 REAL TIME CLOCK (RTC) SUBSYSTEM
 M:	Alessandro Zummo <a.zummo@towertech.it>
-M:	Alexandre Belloni <alexandre.belloni@free-electrons.com>
+M:	Alexandre Belloni <alexandre.belloni@bootlin.com>
 L:	linux-rtc@vger.kernel.org
 Q:	http://patchwork.ozlabs.org/project/rtc-linux/list/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
@@ -11817,8 +11838,8 @@ F:	drivers/memstick/host/r592.*
 RICOH SMARTMEDIA/XD DRIVER
 M:	Maxim Levitsky <maximlevitsky@gmail.com>
 S:	Maintained
-F:	drivers/mtd/nand/r852.c
-F:	drivers/mtd/nand/r852.h
+F:	drivers/mtd/nand/raw/r852.c
+F:	drivers/mtd/nand/raw/r852.h
 
 RISC-V ARCHITECTURE
 M:	Palmer Dabbelt <palmer@sifive.com>
@@ -12093,6 +12114,7 @@ M:	Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Supported
 F:	sound/soc/samsung/
+F:	Documentation/devicetree/bindings/sound/samsung*
 
 SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
 M:	Krzysztof Kozlowski <krzk@kernel.org>
@@ -12191,6 +12213,7 @@ M:	Tomasz Figa <tomasz.figa@gmail.com>
 M:	Chanwoo Choi <cw00.choi@samsung.com>
 S:	Supported
 L:	linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
 F:	drivers/clk/samsung/
 F:	include/dt-bindings/clock/exynos*.h
 F:	Documentation/devicetree/bindings/clock/exynos*.txt
@@ -14637,7 +14660,7 @@ VF610 NAND DRIVER
 M:	Stefan Agner <stefan@agner.ch>
 L:	linux-mtd@lists.infradead.org
 S:	Supported
-F:	drivers/mtd/nand/vf610_nfc.c
+F:	drivers/mtd/nand/raw/vf610_nfc.c
 
 VFAT/FAT/MSDOS FILESYSTEM
 M:	OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
diff --git a/Makefile b/Makefile
index d9cf3a40eda9..4f295a281e35 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ unexport GREP_OPTIONS
 # Most importantly: sub-Makefiles should only ever modify files in
 # their own directory. If in some directory we have a dependency on
 # a file in another dir (which doesn't happen often, but it's often
-# unavoidable when linking the built-in.o targets which finally
+# unavoidable when linking the built-in.a targets which finally
 # turn into vmlinux), we will call a sub make in that other dir, and
 # after that we are sure that everything which is in that other dir
 # is now up to date.
@@ -220,7 +220,8 @@ export srctree objtree VPATH
 version_h := include/generated/uapi/linux/version.h
 old_version_h := include/linux/version.h
 
-no-dot-config-targets := clean mrproper distclean \
+clean-targets := %clean mrproper cleandocs
+no-dot-config-targets := $(clean-targets) \
 			 cscope gtags TAGS tags help% %docs check% coccicheck \
 			 $(version_h) headers_% archheaders archscripts \
 			 kernelversion %src-pkg
@@ -243,6 +244,14 @@ ifeq ($(KBUILD_EXTMOD),)
                 endif
         endif
 endif
+
+# For "make -j clean all", "make -j mrproper defconfig all", etc.
+ifneq ($(filter $(clean-targets),$(MAKECMDGOALS)),)
+        ifneq ($(filter-out $(clean-targets),$(MAKECMDGOALS)),)
+                mixed-targets := 1
+        endif
+endif
+
 # install and modules_install need also be processed one by one
 ifneq ($(filter install,$(MAKECMDGOALS)),)
         ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
@@ -979,13 +988,13 @@ vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
 vmlinux-alldirs	:= $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \
 		     $(init-) $(core-) $(drivers-) $(net-) $(libs-) $(virt-))))
 
-init-y		:= $(patsubst %/, %/built-in.o, $(init-y))
-core-y		:= $(patsubst %/, %/built-in.o, $(core-y))
-drivers-y	:= $(patsubst %/, %/built-in.o, $(drivers-y))
-net-y		:= $(patsubst %/, %/built-in.o, $(net-y))
+init-y		:= $(patsubst %/, %/built-in.a, $(init-y))
+core-y		:= $(patsubst %/, %/built-in.a, $(core-y))
+drivers-y	:= $(patsubst %/, %/built-in.a, $(drivers-y))
+net-y		:= $(patsubst %/, %/built-in.a, $(net-y))
 libs-y1		:= $(patsubst %/, %/lib.a, $(libs-y))
-libs-y2		:= $(filter-out %.a, $(patsubst %/, %/built-in.o, $(libs-y)))
-virt-y		:= $(patsubst %/, %/built-in.o, $(virt-y))
+libs-y2		:= $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
+virt-y		:= $(patsubst %/, %/built-in.a, $(virt-y))
 
 # Externally visible symbols (used by link-vmlinux.sh)
 export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
diff --git a/Next/SHA1s b/Next/SHA1s
new file mode 100644
index 000000000000..d7d97f54649c
--- /dev/null
+++ b/Next/SHA1s
@@ -0,0 +1,258 @@
+Name		SHA1
+----		----
+origin		79c0ef3e85c015b0921a8fd5dd539d1480e9cd6c
+fixes		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+kbuild-current	36c1681678b507346e7397a235a7303dad665fc3
+arc-current	05382333595612204d6c91820bd77be20119cb9b
+arm-current	091f02483df7b56615b524491f404e574c5e0668
+m68k-current	2334b1ac1235934fc196f2d25bae7f348d3bf42e
+metag-fixes	b884a190afcecdbef34ca508ea5ee88bb7c77861
+powerpc-fixes	2c10636a0b9c689450e85f9945583920f50337c9
+sparc		aebb48f5e465772576359c1705c4a84abea92027
+fscrypt-current	ae64f9bd1d3621b5e60d7363bc20afb46aede215
+net		506b0a395f26e52b3f18827e0de1be051acb77ab
+bpf		9c2d63b843a5c8a8d0559cc067b5398aa5ec3ffc
+ipsec		510c321b557121861601f9d259aadd65aa274f35
+netfilter	cfc2c740533368b96e2be5e0a4e8c3cace7d9814
+ipvs		f7fb77fc12352d15180dc3c08ffba10573d5167d
+wireless-drivers	7ac8ff95f48cbfa609a060fd6a1e361dd62feeb3
+mac80211	3b07029729e347f288c70227cfe3c66b085d6b0b
+rdma-fixes	2f08ee363fe097bc6dc01aac53e1798b16c00986
+sound-current	fdcc968a3b290407bcba9d4c90e2fba6d8d928f1
+pci-current	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+driver-core.current	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+tty.current	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+usb.current	fc19b1d09414912a327cf0a4b5ba2050ac7ad59d
+usb-gadget-fixes	98112041bcca164676367e261c8c1073ef70cb51
+usb-serial-fixes	d14ac576d10f865970bb1324d337e5e24d79aaf4
+usb-chipidea-fixes	964728f9f407eca0b417fdf8e784b7a76979490c
+phy		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+staging.current	6d79bd5bb6c79a9dba4842040c9adf39e7806330
+char-misc.current	7ae079aca59f560d2a44b65d45dffdefed6bd17a
+input-current	ea4f7bd2aca9f68470e9aac0fc9432fd180b1fe7
+crypto-current	c927b080c67e3e97193c81fc1d27f4251bf4e036
+ide		8e44e6600caa7b96a5b71ae36c8829db753c2d70
+vfio-fixes	563b5cbe334e9503ab2b234e279d500fc4f76018
+kselftest-fixes	9eaa1fb2196156b31db1b2b4eb9182964efbeb17
+backlight-fixes	8ff5cbc6e3c5c2855245c014f3ba572ddfc5ab0f
+nand-fixes	ee02f73e04c0e690600f621a3a1d2245834af7fe
+spi-nor-fixes	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+mfd-fixes	107b7d9fa94c4692d9104243f0e793e2a4e1366e
+v4l-dvb-fixes	781b045baefdabf7e0bc9f33672ca830d3db9f27
+reset-fixes	f450f28e70a2378d9d6ded0932fe480055888cfa
+mips-fixes	5efad9eee33ee5fc4bf3059f74f3932a638534d1
+kvm-fixes	722c2cd7b7c99d5731689e61f674abeb8f2da537
+kvms390-fixes	baabee67f4135e3de87bc874929ac50637aacb0d
+drm-intel-fixes	ee622fe757f6de612dad0f01805eea815a5b3025
+drm-misc-fixes	06998a756a3865817b87a129a7e5d5bb66dc1ec3
+kbuild		b583b9f9c919dcb36ce2790f76daeb3ee04cbb5c
+uuid		c0020756315eebec58310aca42cf9fb73e1322eb
+dma-mapping	04f56534786c885f578c24461bcd782fe9a787cf
+asm-generic	a351e9b9fc24e982ec2f0e76379a49826036da12
+arc		4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
+arm		3a175cdf439275c3da347b6b42c4e9b652a12904
+arm-perf	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+arm-soc		2aa127e4d579def8ff77fbaadf53a4034e43158f
+actions		61862a89e6acb61e1193c3ad6d4eeab966c470ed
+alpine		a1144b2b1ec47f50951a83eb2bd847c74415b567
+amlogic		b1303f3fa73b71b0121990405a137c8c8d946735
+aspeed		91b55cc53a171a2330536a820cbbd6af9dd5307c
+at91		fa4cf68ab4b1972161d38bce2859850da4236994
+bcm2835		a6189bcc00123f47a256d5a6a46d93c9a2cab52e
+imx-mxs		914867289762b2776be4418099590d7e78e17f95
+keystone	a29b8b93e1582aaff0b13b84679b3dda935186d9
+mvebu		b4e369232fa8da87fead8fb04e19f7c15cc385c4
+omap		64dbb6ed7c33748bcfe1b628cdf9a53f6824eebe
+reset		70d2f16a6289a9ef13c56e408acd3aad6a6415c2
+qcom		f5788d2f292935cb841cb57a61868360fd726de6
+realtek		2b6286eb7ab8b9a22f7238bdaad403badd4a93e9
+renesas		aa0ce0bb0b6f3ff990251372e2f6bc8c1c12edf8
+rockchip	cc95e6771f11fa4cd611800b1436bcd7a624215e
+samsung		bebc6082da0a9f5d47a1ea2edc099bf671058bd4
+samsung-krzk	f9b2bb6c0ee0ae71f5e48346e18030d1613dc113
+sunxi		017b7e4e23ff35ed1714b9ae095420ea0e130ac8
+tegra		983371acdeda5fd76cab580f66438c02d633d512
+arm64		3a0a397ff5ff8b56ca9f7908b75dee6bf0b5fabb
+clk		c43a52cfd27b20292d19d924eddfa5ff8dce87e5
+clk-samsung	83942bdd992ff347442ec72d86c2d77fe51a0270
+c6x		9d440f7a282433338207c4ffb13cafaccaa27818
+cris		fd989db807a00d552ebf29d8ffb20c2ef04742da
+m68k		2334b1ac1235934fc196f2d25bae7f348d3bf42e
+m68knommu	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+metag		e3cd7f013bac3105d44b8bd5a90359989d45b5a5
+microblaze	f1517df8701c9f12dae9ce7f43a5d300a6917619
+mips		ea4d340cbea470247b19ee696e31f102bc64466a
+mips-james	35868f09594827299106a2b0411c276b307767aa
+nios2		e0691ebb33c12084ef11b6b59228c004e19f59c8
+openrisc	0fedb7653af7a8cac606c3eff213ac92693035b9
+parisc-hd	a156e659f2d211e50d220098e9238420faba0618
+powerpc		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+fsl		c095ff93f901c1620b28dce4d813dd548bc5236b
+risc-v		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+s390		c3ec23b8019292ab64761824ece835aea468449e
+sparc-next	8e44e6600caa7b96a5b71ae36c8829db753c2d70
+sh		6e2fbfdd585f46128ce8879738bca09719a65138
+uml		584bfe635481d9b2b7f181b05a84d6cfdce79ee7
+xtensa		ae6063c83634cbef7f73ec8a3ab7a6adf5294716
+fscrypt		0b1dfa4cc6c60052b2c30ead316fa84c46d3c43c
+befs		55d945e2e4aa148ef38bdfabb9569af78183a539
+btrfs		7c9a09f56a91c4ee5636703d3a95c72710917718
+btrfs-kdave	6537ffbd6382c25a2cbd26f5b5abf28ccf89bc87
+ceph		16515a6d54183349b858b9c05e483afc55fa7948
+cifs		1c6614d229e79061b82ad122aae652b2c0e2ae2c
+configfs	6ace4f6bbcfde70278a33c11443ecda3ed0ec1b6
+ecryptfs	4670269faba728683f7250319a65390946c028e3
+ext3		1d37d05f3c2c3c6bd329ccacb9f7415d389d85ce
+ext4		5dc397113d195a004899ee672c5a8a19809495ba
+f2fs		1c1d35df71104c76a4a2e25862926f22c334c9d6
+fuse		c6cdd51404b7ac12dd95173ddfc548c59ecf037f
+jfs		86313903430d08739e391ad51b4865dc3a2bf522
+nfs		91ab883eb21325ad80f3473633f794c78ac87f51
+nfs-anna	c54c14ba000d769b7f5e4a33f915f0171b378437
+nfsd		175e03101d36c3034f3c80038d4c28838351a7f2
+orangefs	74e938c22705c7b80d4422e84eea927fc78e60a8
+overlayfs	7168179fcf25f7812e8541decac686a91359e522
+ubifs		7f29ae9f977bcdc3654e68bc36d170223c52fd48
+xfs		76883f7988e6d06a97232e979bc7aaa7846a134b
+file-locks	1deab8ce2c91e3b16563b7a7ea150f82334262ec
+vfs		d85e2aa2e34dac793e70b900d865f48c69ecbc27
+vfs-miklos	0eb8af4916a540c362a2950e5ab54eca32eb7d58
+iversion	581e400ff935d34d95811258586128bf11baef15
+printk		02fffdcaed199d4bf13fc57ccedbd1e80463b717
+pci		c8989cd7ece73a807091d27e93a7c7825f0c922b
+pstore		a99f41a1b4412a0f27cc0b287ea34b168da750f1
+hid		ba6986149ce37a172040d56ca1b0bd2ed69923c0
+i2c		a2cdd4be7a2c9e5f6b1633ae49ca4e6db38574d1
+dmi		36a840c73dc6e70a440d05da3b6ee72f7187a5d3
+hwmon-staging	e464243586cbd061928f7fb6075f42bb34e50897
+jc_docs		b57c847ca6e6ebd6dc059978dfb0cd514c2f779a
+v4l-dvb		29422737017b866d4a51014cc7522fa3a99e8852
+v4l-dvb-next	a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a
+fbdev		5865889fe4319415e439095391dda52f23030d60
+pm		91ab883eb21325ad80f3473633f794c78ac87f51
+cpupower	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+idle		8a5776a5f49812d29fe4b2d0a2d71675c3facf3f
+opp		4a823c0be80fa996234ebb41c80d40458b1bec1e
+thermal		134f4010799a30acd969e603985c27b9f3e6f58d
+thermal-soc	d0ecbbbe518e1b256fcda1770ec06a5a1a058567
+ieee1394	188775181bc05f29372b305ef96485840e351fde
+dlm		9250e523592a8ced3ecd14abe29fbb1e036bd7eb
+swiotlb		69369f52d28a34c84acb6f2a8a585e743441566a
+net-next	26736a08ee0fb89a4f09bfb2c9f0805028ff63aa
+bpf-next	0b6b8a3dd86db78c3f38587d667d77065c75e4f8
+ipsec-next	60aa80460da115216070082b4ab686b9e37c86ef
+netfilter-next	c746fc0e8b2d144e2ee9122e4efd72326ff3cd1b
+nfc-next	4d63adfe12dd9cb61ed8badb4d798955399048c2
+ipvs-next	a910d20aa007b94cf1799df59341f5e27ca60e6f
+wireless-drivers-next	cf19e5e2054f5172c07a152f9e04eb3bae3d86dd
+bluetooth	1ec010e705934c8acbe7dbf31afc81e60e3d828b
+mac80211-next	b28971dfae9f716071cf5576fa33e4707f839ba6
+rdma		3a148896b24adf8688dc0c59af54531931677a40
+gfs2		6556677a80400ca5744340d8ff6fbed22621293e
+mtd		f23def8038611fa362de345c540107c78edaa085
+l2-mtd		0dbe4ea78d69756efeb0bba0764f6bd4a9ee9567
+nand		4da712e702941daa849ccd7fbcaa677dce7855b2
+spi-nor		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+crypto		a43a34845a156c9e1dae00e33595a508d53e0365
+drm		933519a5a269d8460450545adefcb5caec622cac
+drm-panel	e4bac408b08437d190785ab1250cc676304ed171
+drm-intel	be3fa66857051e2943960a06f8046e8445cdfe6e
+drm-tegra	8f62142e490d761ceb92b55a7c05bb79294d6c6c
+drm-misc	761e05a702f5d537ffcca1ba933f9f0a968aa022
+drm-msm		8fe2938c9bac4cb130093b85abdfdb99bba0c986
+hdlcd		f73e8b82531573a198a4d0e5bff0d3256cbbd1d8
+mali-dp		54243016ae35a0912a680f884835237fd6176820
+sunxi-drm	7dafb83edd3271917458de0ae70586ac63098e2f
+imx-drm		3addaba8141bc6a4f649a48f46e552af32922147
+etnaviv		246774d17fc05a9b33c769c937003cc73d258674
+kconfig		bebc6082da0a9f5d47a1ea2edc099bf671058bd4
+regmap		9e4e3b86e5ef16361629c1a0fd1c4d742400fd14
+sound		04f8773a3e980f60953e7aeb36ec6c2631e11f10
+sound-asoc	5a1dec3a8d43797db98afa937470bf0ee4d9be6e
+modules		0cad61d7a3d51e0237a7e421c75b04ebbb5062d0
+input		cdc2466df40f26af60f6b18123069bd52336a80c
+block		0ccfb3c0032b20a7f137976e9e783c896d55301e
+lightnvm	1c6286f26301ad154a1c10fb6e68925493dd28ba
+device-mapper	8dd601fa8317243be887458c49f6c29c2f3d719f
+mmc		80a7d93164966b8a55fe8e63cc6ce8cd7c0db168
+kgdb		2cf2f0d5b91fd1b06a6ae260462fc7945ea84add
+md		01a69cab01c184d3786af09e9339311123d63d22
+mfd		0f89ffefa4e122e7e9bc1c2d716c6052b4601b76
+backlight	2023b0524a6310e9ea80daf085f51c71bff9289f
+battery		416a1ae673db0918fbe6707c7d6f4459598e2c65
+regulator	775d434195db773857589950bf3a8a69885bd4f6
+security	400f428062af7e9200ff15dce2ef3c01ff007d96
+integrity	b79f5f38d87f66576deb49e18f2175a295db24de
+keys		1e684d3820d8f72d877c0adb521ae17c6fc9bc88
+selinux		213d7f94775322ba44e0bbb55ec6946e9de88cea
+tpmdd		c3211d722c614bfa0e2f728a1a0598f099f7adb0
+watchdog	a17f4f032b61abd998a1f81b206a4517e2e3db2f
+iommu		18b3c16e25fb85ad711c90cea1bdb258392f0cbd
+dwmw2-iommu	910170442944e1f8674fd5ddbeeb8ccd1877ea98
+vfio		46ed90f157f42d956ffed17c003f089a59b76e3e
+trivial		1972d6c0c86dd8620ff9f2811ce875135ffb5405
+audit		94d14e3e7b41d99f0d62a41fd856183057e1e474
+devicetree	7ea5c83472d39ec6065d98606f058c8fd9916616
+mailbox		0ae7d327a64b262443b7d3ebee5831e4dde47b89
+spi		a484784130356fcdfaa30bbe54eb588db9f5850a
+tip		cb85c73cf4617a3f7a732ecf2c9be7157b412052
+clockevents	322fd24f5e67c396f04bef01ed33ac6bfca46bcd
+edac		345fb0a9a6340ba0b3b714d62f877fde88c8a755
+edac-amd	68fa24f9121c04ef146b5158f538c8b32f285be5
+irqchip		c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201
+ftrace		841a915d20c7b22fc4f36f12368daf94d9f8cb10
+rcu		2faeeb29ab2bd42c0d4cc77d06023e7a17fa7531
+kvm		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+kvm-arm		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+kvm-mips	dc44abd6aad22411f7f9890e39fd4753dabf0d03
+kvm-ppc		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+kvms390		baabee67f4135e3de87bc874929ac50637aacb0d
+xen-tip		d1a75e0896f5e9f5cb6a979caaea39f1f4b9feb1
+percpu		554fef1c39ee148623a496e04569dabb11463406
+workqueues	a10eb37ccf1d47f9d97269ede326aa949816be87
+drivers-x86	c8ba9db2a790c0fcf2f6c4cafd45ff3a0751800e
+chrome-platform	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+hsi		b6dc80dbe6cdf4effd5a07bcd37f34cbf25eb07a
+leds		2dd1ea5b8a492121dc7cb3cb2bc17c22415260e6
+ipmi		09c0179286c76c2feeafd752c7aae961b9b11d35
+driver-core	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+usb		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+usb-gadget	8ada211d0383b72878582bd312b984a9eae62b30
+usb-serial	d1c48227d7c45fbb35c81f846a62ec92a74f4701
+usb-chipidea-next	ce4c1b820c5269437ce2e7831f638159b3b83269
+phy-next	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+tty		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+char-misc	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+extcon		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+staging		f782497c0991022c1a01d2cffe587eb7ea01a062
+mux		6cd361c99ef2bbe23edd554079c4187321a21219
+slave-dma	5ec91512231afbca3b98cd9e49c56bc345f4a4e0
+cgroup		c53593e5cb693d59d9e8b64fb3a79436bf99c3b3
+scsi		b00e1e5f242e05980e08018a41d470b2c2c83aab
+scsi-mkp	ec92b59cc03c3d5757449c1c9344524e088df2bd
+target-updates	1c130ae00b769a2e2df41bad3d6051ee8234b636
+target-bva	4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323
+libata		d058cdf3cc81aa457a95be9eb5b19906b68b3e12
+vhost		fa08a3b4eba59429cf7e241a7af089103e79160f
+rpmsg		ec6e6903695637d7446d140c3be3eb1f78c37015
+gpio		3c87d7c874b2119c1cff4eee5586b9a6bc0b7fe9
+pinctrl		cfc09838477f3d1606bba0f4b62f9c3def8ba173
+pinctrl-samsung	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+pwm		bccaa3f917c90917a758020dfbdd9027290a7c4e
+userns		9eba1cd4b565f66456e0705475f66bf32cd75ee1
+ktest		f7c6401ff84ab8ffffc281a29aa0a787f7eb346e
+random		9e66317d3c92ddaab330c125dfe9d06eee268aff
+aio		2a8a98673c13cb2a61a6476153acf8344adfa992
+kselftest	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+y2038		69973b830859bc6529a7a0468ba0d80ee5117826
+livepatching	d13f5d84ca2774e76f8461a383c222cbc75adad5
+coresight	7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+rtc		9fad33fc0bafa0322e32f0d3952f01b2dae93c4c
+nvdimm		ee95f4059a833839bf52972191b2d4c3d3cec552
+idr		f0f3f2d0a3e0f7c48163fd8b45f5909d46e7f371
+at24		7928b2cbe55b2a410a0f5c1f154610059c57b1b2
+ntb		53c3677c56c76f90cacd3a1063272fc6d6bc8f76
+kspp		2d00fcb32f71904a789d285c1ae335d5f42a38d2
+init_task	e1e871aff3ded26348c631b1370e257d401cd22d
+akpm-current	5682fa508060179aa2039afa6d7adb74147c7ca3
+akpm		5685a07f937fe8cf87db1563a94085532bac13e2
diff --git a/Next/Trees b/Next/Trees
new file mode 100644
index 000000000000..89cd025c56b4
--- /dev/null
+++ b/Next/Trees
@@ -0,0 +1,260 @@
+Trees included into this release:
+
+Name		Type	URL
+----		----	---
+origin		git	git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git#master
+fixes		git	git://git.kernel.org/pub/scm/linux/kernel/git/sfr/next-fixes.git#master
+kbuild-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git#fixes
+arc-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git#for-curr
+arm-current	git	git://git.armlinux.org.uk/~rmk/linux-arm.git#fixes
+m68k-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-linus
+metag-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag.git#fixes
+powerpc-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git#fixes
+sparc		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git#master
+fscrypt-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt.git#for-stable
+net		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git#master
+bpf		git	git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git#master
+ipsec		git	git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git#master
+netfilter	git	git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git#master
+ipvs		git	git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs.git#master
+wireless-drivers	git	git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git#master
+mac80211		git	git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git#master
+rdma-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git#for-rc
+sound-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-linus
+pci-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git#for-linus
+driver-core.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git#driver-core-linus
+tty.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-linus
+usb.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-linus
+usb-gadget-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git#fixes
+usb-serial-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git#usb-linus
+usb-chipidea-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git#ci-for-usb-stable
+phy		git	git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git#fixes
+staging.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-linus
+char-misc.current	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-linus
+input-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#for-linus
+crypto-current	git	git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git#master
+ide		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git#master
+vfio-fixes	git	git://github.com/awilliam/linux-vfio.git#for-linus
+kselftest-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#fixes
+backlight-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git#for-backlight-fixes
+nand-fixes	git	git://git.infradead.org/linux-mtd.git#nand/fixes
+spi-nor-fixes	git	git://git.infradead.org/linux-mtd.git#spi-nor/fixes
+mfd-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git#for-mfd-fixes
+v4l-dvb-fixes	git	git://linuxtv.org/mchehab/media-next.git#fixes
+reset-fixes	git	https://git.pengutronix.de/git/pza/linux#reset/fixes
+mips-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/mips.git#mips-fixes
+kvm-fixes	git	git://git.kernel.org/pub/scm/virt/kvm/kvm.git#master
+kvms390-fixes	git	git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git#master
+drm-intel-fixes	git	git://anongit.freedesktop.org/drm-intel#for-linux-next-fixes
+drm-misc-fixes	git	git://anongit.freedesktop.org/drm/drm-misc#for-linux-next-fixes
+kbuild		git	git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git#for-next
+uuid		git	git://git.infradead.org/users/hch/uuid.git#for-next
+dma-mapping	git	git://git.infradead.org/users/hch/dma-mapping.git#for-next
+asm-generic	git	git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git#master
+arc		git	git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git#for-next
+arm		git	git://git.armlinux.org.uk/~rmk/linux-arm.git#for-next
+arm-perf		git	git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git#for-next/perf
+arm-soc		git	git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git#for-next
+actions		git	git://git.kernel.org/pub/scm/linux/kernel/git/afaerber/linux-actions.git#for-next
+alpine		git	git://git.kernel.org/pub/scm/linux/kernel/git/atenart/linux.git#alpine/for-next
+amlogic		git	git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git#for-next
+aspeed		git	git://git.kernel.org/pub/scm/linux/kernel/git/joel/aspeed.git#for-next
+at91		git	git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git#at91-next
+bcm2835		git	git://github.com/anholt/linux.git#for-next
+imx-mxs		git	git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git#for-next
+keystone		git	git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git#next
+mvebu		git	git://git.infradead.org/linux-mvebu.git#for-next
+omap		git	git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git#for-next
+reset		git	https://git.pengutronix.de/git/pza/linux#reset/next
+qcom		git	git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git#for-next
+realtek		git	git://git.kernel.org/pub/scm/linux/kernel/git/afaerber/linux-realtek.git#for-next
+renesas		git	git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git#next
+rockchip		git	git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git#for-next
+samsung		git	git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git#for-next
+samsung-krzk	git	git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git#for-next
+sunxi		git	git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git#sunxi/for-next
+tegra		git	git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git#for-next
+arm64		git	git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux#for-next/core
+clk		git	git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git#clk-next
+clk-samsung	git	git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git#for-next
+c6x		git	git://linux-c6x.org/git/projects/linux-c6x-upstreaming.git#for-linux-next
+cris		git	git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris.git#for-next
+m68k		git	git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-next
+m68knommu	git	git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git#for-next
+metag		git	git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag.git#for-next
+microblaze	git	git://git.monstr.eu/linux-2.6-microblaze.git#next
+mips		git	git://git.linux-mips.org/pub/scm/ralf/upstream-sfr#mips-next
+mips-james	git	git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/mips.git#mips-next
+nios2		git	git://git.kernel.org/pub/scm/linux/kernel/git/lftan/nios2.git#for-next
+openrisc		git	git://github.com/openrisc/linux.git#for-next
+parisc-hd	git	git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git#for-next
+powerpc		git	git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git#next
+fsl		git	git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux.git#next
+risc-v		git	git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux.git#for-next
+s390		git	git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#features
+sparc-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git#master
+sh		git	git://git.libc.org/linux-sh#for-next
+uml		git	git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml.git#linux-next
+xtensa		git	git://github.com/jcmvbkbc/linux-xtensa.git#xtensa-for-next
+fscrypt		git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt.git#master
+befs		git	git://git.kernel.org/pub/scm/linux/kernel/git/luisbg/linux-befs.git#for-next
+btrfs		git	git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git#next
+btrfs-kdave	git	git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git#for-next
+ceph		git	git://github.com/ceph/ceph-client.git#master
+cifs		git	git://git.samba.org/sfrench/cifs-2.6.git#for-next
+configfs		git	git://git.infradead.org/users/hch/configfs.git#for-next
+ecryptfs		git	git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git#next
+ext3		git	git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git#for_next
+ext4		git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git#dev
+f2fs		git	git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git#dev
+fuse		git	git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git#for-next
+jfs		git	git://github.com/kleikamp/linux-shaggy.git#jfs-next
+nfs		git	git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git#linux-next
+nfs-anna		git	git://git.linux-nfs.org/projects/anna/linux-nfs.git#linux-next
+nfsd		git	git://git.linux-nfs.org/~bfields/linux.git#nfsd-next
+orangefs		git	git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux#for-next
+overlayfs	git	git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git#overlayfs-next
+ubifs		git	git://git.infradead.org/ubifs-2.6.git#linux-next
+xfs		git	git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git#for-next
+file-locks	git	git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux.git#locks-next
+vfs		git	git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6.git#for-next
+vfs-miklos	git	git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git#next
+iversion		git	git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux.git#iversion-next
+printk		git	git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git#for-next
+pci		git	git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git#next
+pstore		git	git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git#for-next/pstore
+hid		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git#for-next
+i2c		git	git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git#i2c/for-next
+dmi		quilt	http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/
+hwmon-staging	git	git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#hwmon-next
+jc_docs		git	git://git.lwn.net/linux.git#docs-next
+v4l-dvb		git	git://linuxtv.org/media_tree.git#master
+v4l-dvb-next	git	git://linuxtv.org/mchehab/media-next.git#master
+fbdev		git	git://github.com/bzolnier/linux.git#fbdev-for-next
+pm		git	git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git#linux-next
+cpupower		git	git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux.git#cpupower
+idle		git	git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git#next
+opp		git	git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git#opp/linux-next
+thermal		git	git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git#next
+thermal-soc	git	git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git#next
+ieee1394		git	git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git#for-next
+dlm		git	git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git#next
+swiotlb		git	git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git#linux-next
+net-next		git	git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git#master
+bpf-next		git	git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git#master
+ipsec-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git#master
+netfilter-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git#master
+nfc-next		git	git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next.git#master
+ipvs-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git#master
+wireless-drivers-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git#master
+bluetooth	git	git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git#master
+mac80211-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git#master
+rdma		git	git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git#for-next
+gfs2		git	git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git#for-next
+mtd		git	git://git.infradead.org/mtd-2.6.git#master
+l2-mtd		git	git://git.infradead.org/linux-mtd.git#mtd/next
+nand		git	git://git.infradead.org/linux-mtd.git#nand/next
+spi-nor		git	git://git.infradead.org/linux-mtd.git#spi-nor/next
+crypto		git	git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git#master
+drm		git	git://people.freedesktop.org/~airlied/linux.git#drm-next
+drm-panel	git	git://anongit.freedesktop.org/tegra/linux.git#drm/panel/for-next
+drm-intel	git	git://anongit.freedesktop.org/drm-intel#for-linux-next
+drm-tegra	git	git://anongit.freedesktop.org/tegra/linux.git#drm/tegra/for-next
+drm-misc		git	git://anongit.freedesktop.org/drm/drm-misc#for-linux-next
+drm-msm		git	git://people.freedesktop.org/~robclark/linux#msm-next
+hdlcd		git	git://linux-arm.org/linux-ld#for-upstream/hdlcd
+mali-dp		git	git://linux-arm.org/linux-ld#for-upstream/mali-dp
+sunxi-drm	git	git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git#sunxi-drm/for-next
+imx-drm		git	https://git.pengutronix.de/git/pza/linux#imx-drm/next
+etnaviv		git	https://git.pengutronix.de/git/lst/linux#etnaviv/next
+kconfig		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-kconfig.git#for-next
+regmap		git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git#for-next
+sound		git	git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-next
+sound-asoc	git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git#for-next
+modules		git	git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git#modules-next
+input		git	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#next
+block		git	git://git.kernel.dk/linux-block.git#for-next
+lightnvm		git	git://github.com/OpenChannelSSD/linux.git#for-next
+device-mapper	git	git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git#for-next
+mmc		git	git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git#next
+kgdb		git	git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb.git#kgdb-next
+md		git	git://git.kernel.org/pub/scm/linux/kernel/git/shli/md.git#for-next
+mfd		git	git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git#for-mfd-next
+backlight	git	git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git#for-backlight-next
+battery		git	git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git#for-next
+regulator	git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git#for-next
+security		git	git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git#next-testing
+integrity	git	git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity#next-integrity
+keys		git	git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git#keys-next
+selinux		git	git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git#next
+tpmdd		git	git://git.infradead.org/users/jjs/linux-tpmdd.git#next
+watchdog		git	git://www.linux-watchdog.org/linux-watchdog-next.git#master
+iommu		git	git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git#next
+dwmw2-iommu	git	git://git.infradead.org/iommu-2.6.git#master
+vfio		git	git://github.com/awilliam/linux-vfio.git#next
+trivial		git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git#for-next
+audit		git	git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git#next
+devicetree	git	git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git#for-next
+mailbox		git	git://git.linaro.org/landing-teams/working/fujitsu/integration.git#mailbox-for-next
+spi		git	git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git#for-next
+tip		git	git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git#auto-latest
+clockevents	git	git://git.linaro.org/people/daniel.lezcano/linux.git#clockevents/next
+edac		git	git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git#linux_next
+edac-amd		git	git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
+irqchip		git	git://git.infradead.org/users/jcooper/linux.git#irqchip/for-next
+ftrace		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git#for-next
+rcu		git	git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git#rcu/next
+kvm		git	git://git.kernel.org/pub/scm/virt/kvm/kvm.git#linux-next
+kvm-arm		git	git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git#next
+kvm-mips		git	git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/kvm-mips.git#next
+kvm-ppc		git	git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git#kvm-ppc-next
+kvms390		git	git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git#next
+xen-tip		git	git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git#linux-next
+percpu		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git#for-next
+workqueues	git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git#for-next
+drivers-x86	git	https://github.com/dvhart/linux-pdx86.git#for-next
+chrome-platform	git	git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git#for-next
+hsi		git	git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git#for-next
+leds		git	git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git#for-next
+ipmi		git	git://github.com/cminyard/linux-ipmi.git#for-next
+driver-core	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git#driver-core-next
+usb		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-next
+usb-gadget	git	git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git#next
+usb-serial	git	git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git#usb-next
+usb-chipidea-next	git	git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git#ci-for-usb-next
+phy-next		git	git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git#next
+tty		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-next
+char-misc	git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-next
+extcon		git	git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git#extcon-next
+staging		git	git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-next
+mux		git	https://gitlab.com/peda-linux/mux.git#for-next
+slave-dma	git	git://git.infradead.org/users/vkoul/slave-dma.git#next
+cgroup		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git#for-next
+scsi		git	git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git#for-next
+scsi-mkp		git	git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git#for-next
+target-updates	git	git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git#for-next
+target-bva	git	git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux.git#for-next
+libata		git	git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git#for-next
+vhost		git	git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git#linux-next
+rpmsg		git	git://github.com/andersson/remoteproc.git#for-next
+gpio		git	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git#for-next
+pinctrl		git	git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git#for-next
+pinctrl-samsung	git	git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git#for-next
+pwm		git	git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git#for-next
+userns		git	git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git#for-next
+ktest		git	git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-ktest.git#for-next
+random		git	git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random.git#dev
+aio		git	git://git.kvack.org/~bcrl/aio-next.git#master
+kselftest	git	git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#next
+y2038		git	git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git#y2038
+livepatching	git	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching#for-next
+coresight	git	git://git.linaro.org/kernel/coresight.git#next
+rtc		git	git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git#rtc-next
+nvdimm		git	git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git#libnvdimm-for-next
+idr		git	git://git.infradead.org/users/willy/linux-dax.git#idr-4.11
+at24		git	git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#at24/for-next
+ntb		git	https://github.com/jonmason/ntb.git#ntb-next
+kspp		git	git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git#for-next/kspp
+init_task	git	git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git#init_task
+akpm-current	mmotm	http://www.ozlabs.org/~akpm/mmotm/
+akpm		mmotm	http://www.ozlabs.org/~akpm/mmotm/
diff --git a/Next/merge.log b/Next/merge.log
new file mode 100644
index 000000000000..f58cba318692
--- /dev/null
+++ b/Next/merge.log
@@ -0,0 +1,4633 @@
+$ date -R
+Tue, 20 Feb 2018 07:59:03 +1100
+$ git checkout master
+Already on 'master'
+$ git reset --hard stable
+HEAD is now at c786427f57b6 Merge tag 'for-linus-20180217' of git://git.kernel.dk/linux-block
+Merging origin/master (79c0ef3e85c0 Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net)
+$ git merge origin/master
+Updating c786427f57b6..79c0ef3e85c0
+Fast-forward
+ Documentation/networking/segmentation-offloads.txt |  38 +-
+ Makefile                                           |   2 +-
+ arch/x86/Kconfig                                   |   2 +-
+ arch/x86/Kconfig.cpu                               |   4 +-
+ drivers/irqchip/irq-bcm7038-l1.c                   |   3 -
+ drivers/irqchip/irq-bcm7120-l2.c                   |   3 -
+ drivers/irqchip/irq-brcmstb-l2.c                   |   3 -
+ drivers/irqchip/irq-gic-v2m.c                      |  46 ++-
+ drivers/irqchip/irq-gic-v3-its-pci-msi.c           |   2 +
+ drivers/irqchip/irq-gic-v3-its-platform-msi.c      |   2 +
+ drivers/irqchip/irq-gic-v3-its.c                   |   2 +
+ drivers/irqchip/irq-gic-v3.c                       |   4 +-
+ drivers/irqchip/irq-mips-gic.c                     |   2 -
+ drivers/net/ethernet/broadcom/tg3.c                |  35 +-
+ drivers/net/ethernet/broadcom/tg3.h                |   5 +
+ drivers/net/ethernet/cavium/common/cavium_ptp.c    |   2 +
+ drivers/net/ethernet/cavium/thunder/nicvf_main.c   | 110 ++----
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.c |  11 +-
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.h |   4 -
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c     |   2 +-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c   |   2 +-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c    |  25 +-
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c         |  10 -
+ drivers/net/ethernet/ibm/ibmvnic.c                 |  54 ++-
+ drivers/net/ethernet/marvell/mvpp2.c               |  11 +-
+ .../net/ethernet/mellanox/mlxsw/spectrum_router.c  |  35 +-
+ drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c |  68 +---
+ .../ethernet/qualcomm/rmnet/rmnet_map_command.c    |   5 +
+ drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c    |   2 +-
+ drivers/net/ethernet/renesas/ravb_main.c           |   6 -
+ drivers/net/ethernet/renesas/sh_eth.c              |  18 +-
+ drivers/net/phy/phy_device.c                       |   2 +-
+ drivers/net/thunderbolt.c                          |  19 +-
+ drivers/net/tun.c                                  |  16 +-
+ drivers/pci/quirks.c                               |  39 +-
+ .../staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c |   2 +
+ include/linux/cpumask.h                            |   2 +
+ include/linux/ptr_ring.h                           |   2 +-
+ include/linux/skbuff.h                             |   2 +-
+ include/net/udplite.h                              |   1 +
+ include/uapi/linux/if_ether.h                      |   6 +-
+ include/uapi/linux/libc-compat.h                   |   6 -
+ kernel/irq/irqdomain.c                             |  18 +-
+ kernel/kprobes.c                                   | 178 ++++++---
+ net/bridge/br_sysfs_if.c                           |   3 +
+ net/core/dev.c                                     |  11 +-
+ net/decnet/af_decnet.c                             |  62 ++--
+ net/ipv4/fib_semantics.c                           |   5 +
+ net/ipv4/tcp_output.c                              |  25 ++
+ net/ipv4/udp.c                                     |   5 +
+ net/ipv6/ip6_checksum.c                            |   5 +
+ net/nfc/llcp_commands.c                            |   4 +
+ net/nfc/netlink.c                                  |   3 +-
+ net/rds/connection.c                               |   2 +-
+ net/rxrpc/recvmsg.c                                |   5 +-
+ net/sched/cls_api.c                                |  26 +-
+ net/sched/cls_u32.c                                |  24 +-
+ net/sctp/debug.c                                   |   6 +
+ net/sctp/input.c                                   |   5 +-
+ net/sctp/stream.c                                  |   2 +-
+ net/sctp/stream_interleave.c                       |  16 +-
+ net/tipc/bearer.c                                  |  82 ++--
+ net/tipc/bearer.h                                  |   4 +
+ net/tipc/net.c                                     |  15 +-
+ net/tipc/net.h                                     |   1 +
+ net/tipc/netlink_compat.c                          |  43 ++-
+ net/tls/tls_main.c                                 |   7 +-
+ net/unix/af_unix.c                                 |   2 +-
+ tools/arch/powerpc/include/uapi/asm/kvm.h          |   2 +
+ tools/arch/s390/include/uapi/asm/unistd.h          | 412 ---------------------
+ tools/arch/x86/include/asm/cpufeatures.h           |   1 +
+ tools/include/uapi/drm/i915_drm.h                  |  77 ++++
+ tools/include/uapi/linux/if_link.h                 |   1 +
+ tools/include/uapi/linux/kvm.h                     |  90 +++++
+ tools/perf/Documentation/perf-data.txt             |   4 +
+ tools/perf/arch/s390/Makefile                      |  10 +-
+ tools/perf/arch/s390/entry/syscalls/mksyscalltbl   |  18 +-
+ tools/perf/arch/s390/entry/syscalls/syscall.tbl    | 390 +++++++++++++++++++
+ tools/perf/builtin-c2c.c                           |   4 +-
+ tools/perf/builtin-report.c                        |   3 +-
+ tools/perf/builtin-top.c                           | 150 +++++++-
+ tools/perf/check-headers.sh                        |   1 -
+ .../pmu-events/arch/arm64/cortex-a53/branch.json   |  27 ++
+ .../perf/pmu-events/arch/arm64/cortex-a53/bus.json |  22 ++
+ .../pmu-events/arch/arm64/cortex-a53/cache.json    |  27 ++
+ .../pmu-events/arch/arm64/cortex-a53/memory.json   |  22 ++
+ .../pmu-events/arch/arm64/cortex-a53/other.json    |  32 ++
+ .../pmu-events/arch/arm64/cortex-a53/pipeline.json |  52 +++
+ tools/perf/pmu-events/arch/arm64/mapfile.csv       |   1 +
+ tools/perf/tests/backward-ring-buffer.c            |   7 +-
+ .../perf/tests/shell/trace+probe_libc_inet_pton.sh |  23 +-
+ tools/perf/ui/browsers/hists.c                     |  38 +-
+ tools/perf/ui/browsers/hists.h                     |   3 +-
+ tools/perf/util/evlist.c                           |  17 -
+ tools/perf/util/evlist.h                           |   4 -
+ tools/perf/util/evsel.c                            |  12 +-
+ tools/perf/util/evsel.h                            |  14 +
+ tools/perf/util/hist.h                             |   6 +-
+ tools/perf/util/mmap.c                             | 141 ++++---
+ tools/perf/util/mmap.h                             |  10 +-
+ tools/perf/util/util.c                             |  24 +-
+ 101 files changed, 1741 insertions(+), 1078 deletions(-)
+ delete mode 100644 tools/arch/s390/include/uapi/asm/unistd.h
+ create mode 100644 tools/perf/arch/s390/entry/syscalls/syscall.tbl
+ create mode 100644 tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json
+ create mode 100644 tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json
+ create mode 100644 tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json
+ create mode 100644 tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json
+ create mode 100644 tools/perf/pmu-events/arch/arm64/cortex-a53/other.json
+ create mode 100644 tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json
+Merging fixes/master (7928b2cbe55b Linux 4.16-rc1)
+$ git merge fixes/master
+Already up to date.
+Merging kbuild-current/fixes (36c1681678b5 genksyms: drop *.hash.c from .gitignore)
+$ git merge kbuild-current/fixes
+Already up to date.
+Merging arc-current/for-curr (053823335956 arc: dts: use 'atmel' as manufacturer for at24 in axs10x_mb)
+$ git merge arc-current/for-curr
+Auto-merging arch/arc/Kconfig
+Merge made by the 'recursive' strategy.
+ arch/arc/Kconfig                      | 1 -
+ arch/arc/boot/dts/axs101.dts          | 2 +-
+ arch/arc/boot/dts/axs10x_mb.dtsi      | 4 ++--
+ arch/arc/boot/dts/haps_hs_idu.dts     | 2 +-
+ arch/arc/boot/dts/nsim_700.dts        | 2 +-
+ arch/arc/boot/dts/nsim_hs.dts         | 2 +-
+ arch/arc/boot/dts/nsim_hs_idu.dts     | 2 +-
+ arch/arc/boot/dts/nsimosci.dts        | 2 +-
+ arch/arc/boot/dts/nsimosci_hs.dts     | 2 +-
+ arch/arc/boot/dts/nsimosci_hs_idu.dts | 2 +-
+ arch/arc/include/asm/entry-arcv2.h    | 2 +-
+ arch/arc/kernel/setup.c               | 2 +-
+ arch/arc/kernel/unwind.c              | 2 +-
+ arch/arc/mm/cache.c                   | 5 ++++-
+ 14 files changed, 17 insertions(+), 15 deletions(-)
+Merging arm-current/fixes (091f02483df7 ARM: net: bpf: clarify tail_call index)
+$ git merge arm-current/fixes
+Already up to date.
+Merging m68k-current/for-linus (2334b1ac1235 MAINTAINERS: Add NuBus subsystem entry)
+$ git merge m68k-current/for-linus
+Already up to date.
+Merging metag-fixes/fixes (b884a190afce metag/usercopy: Add missing fixups)
+$ git merge metag-fixes/fixes
+Already up to date.
+Merging powerpc-fixes/fixes (2c10636a0b9c powerpc/pseries: Check for zero filled ibm,dynamic-memory property)
+$ git merge powerpc-fixes/fixes
+Already up to date.
+Merging sparc/master (aebb48f5e465 sparc64: fix typo in CONFIG_CRYPTO_DES_SPARC64 => CONFIG_CRYPTO_CAMELLIA_SPARC64)
+$ git merge sparc/master
+Already up to date.
+Merging fscrypt-current/for-stable (ae64f9bd1d36 Linux 4.15-rc2)
+$ git merge fscrypt-current/for-stable
+Already up to date.
+Merging net/master (506b0a395f26 tg3: APE heartbeat changes)
+$ git merge net/master
+Already up to date.
+Merging bpf/master (9c2d63b843a5 bpf: fix mlock precharge on arraymaps)
+$ git merge bpf/master
+Merge made by the 'recursive' strategy.
+ kernel/bpf/arraymap.c    | 28 ++++++++++++++++------------
+ kernel/bpf/core.c        |  2 +-
+ kernel/bpf/cpumap.c      |  2 +-
+ kernel/bpf/lpm_trie.c    | 11 +++++++----
+ kernel/bpf/sockmap.c     |  3 ++-
+ kernel/trace/bpf_trace.c |  2 ++
+ tools/bpf/bpftool/main.c |  2 +-
+ tools/bpf/bpftool/prog.c |  3 +++
+ 8 files changed, 33 insertions(+), 20 deletions(-)
+Merging ipsec/master (510c321b5571 xfrm: reuse uncached_list to track xdsts)
+$ git merge ipsec/master
+Auto-merging net/ipv6/route.c
+Merge made by the 'recursive' strategy.
+ include/net/ip6_route.h |  3 +++
+ include/net/route.h     |  3 +++
+ net/ipv4/route.c        | 21 +++++++++++++--------
+ net/ipv4/xfrm4_policy.c |  4 +++-
+ net/ipv6/route.c        |  4 ++--
+ net/ipv6/xfrm6_policy.c |  5 +++++
+ net/xfrm/xfrm_policy.c  |  2 +-
+ net/xfrm/xfrm_state.c   |  5 +++++
+ net/xfrm/xfrm_user.c    | 21 ++++++++-------------
+ 9 files changed, 43 insertions(+), 25 deletions(-)
+Merging netfilter/master (cfc2c7405333 netfilter: IDLETIMER: be syzkaller friendly)
+$ git merge netfilter/master
+Merge made by the 'recursive' strategy.
+ .gitignore                          |  4 ++
+ net/bridge/netfilter/ebt_among.c    | 10 ++---
+ net/bridge/netfilter/ebt_limit.c    |  4 +-
+ net/ipv4/ip_sockglue.c              |  7 +---
+ net/ipv4/netfilter/arp_tables.c     |  4 ++
+ net/ipv4/netfilter/ip_tables.c      |  7 +++-
+ net/ipv4/netfilter/ipt_CLUSTERIP.c  | 20 ++++++----
+ net/ipv4/netfilter/ipt_ECN.c        | 12 +++---
+ net/ipv4/netfilter/ipt_REJECT.c     |  4 +-
+ net/ipv4/netfilter/ipt_rpfilter.c   |  6 +--
+ net/ipv6/ipv6_sockglue.c            | 10 +----
+ net/ipv6/netfilter/ip6_tables.c     |  4 ++
+ net/ipv6/netfilter/ip6t_REJECT.c    |  4 +-
+ net/ipv6/netfilter/ip6t_rpfilter.c  |  6 +--
+ net/ipv6/netfilter/ip6t_srh.c       |  6 ++-
+ net/netfilter/nf_nat_proto_common.c |  7 +++-
+ net/netfilter/x_tables.c            | 74 +++++++++++++++++--------------------
+ net/netfilter/xt_AUDIT.c            |  4 +-
+ net/netfilter/xt_CHECKSUM.c         |  8 ++--
+ net/netfilter/xt_CONNSECMARK.c      | 10 ++---
+ net/netfilter/xt_CT.c               | 25 +++++++------
+ net/netfilter/xt_DSCP.c             |  4 +-
+ net/netfilter/xt_HL.c               | 13 ++-----
+ net/netfilter/xt_HMARK.c            | 27 ++++++++------
+ net/netfilter/xt_IDLETIMER.c        |  9 +++--
+ net/netfilter/xt_LED.c              | 16 ++++----
+ net/netfilter/xt_NFQUEUE.c          |  8 ++--
+ net/netfilter/xt_SECMARK.c          | 18 +++++----
+ net/netfilter/xt_TCPMSS.c           | 10 ++---
+ net/netfilter/xt_TPROXY.c           |  6 +--
+ net/netfilter/xt_addrtype.c         | 33 ++++++++---------
+ net/netfilter/xt_bpf.c              |  4 +-
+ net/netfilter/xt_cgroup.c           |  8 ++--
+ net/netfilter/xt_cluster.c          |  8 ++--
+ net/netfilter/xt_connbytes.c        |  4 +-
+ net/netfilter/xt_connlabel.c        |  7 ++--
+ net/netfilter/xt_connmark.c         |  8 ++--
+ net/netfilter/xt_conntrack.c        |  4 +-
+ net/netfilter/xt_dscp.c             |  4 +-
+ net/netfilter/xt_ecn.c              |  4 +-
+ net/netfilter/xt_hashlimit.c        | 26 +++++++------
+ net/netfilter/xt_helper.c           |  4 +-
+ net/netfilter/xt_ipcomp.c           |  2 +-
+ net/netfilter/xt_ipvs.c             |  3 +-
+ net/netfilter/xt_l2tp.c             | 22 ++++++-----
+ net/netfilter/xt_limit.c            |  4 +-
+ net/netfilter/xt_nat.c              |  5 ++-
+ net/netfilter/xt_nfacct.c           |  6 ++-
+ net/netfilter/xt_physdev.c          |  4 +-
+ net/netfilter/xt_policy.c           | 23 +++++++-----
+ net/netfilter/xt_recent.c           | 14 +++----
+ net/netfilter/xt_set.c              | 50 ++++++++++++-------------
+ net/netfilter/xt_socket.c           | 10 +++--
+ net/netfilter/xt_state.c            |  4 +-
+ net/netfilter/xt_time.c             |  6 +--
+ 55 files changed, 314 insertions(+), 300 deletions(-)
+Merging ipvs/master (f7fb77fc1235 netfilter: nft_compat: check extension hook mask only if set)
+$ git merge ipvs/master
+Already up to date.
+Merging wireless-drivers/master (7ac8ff95f48c mvpp2: fix multicast address filter)
+$ git merge wireless-drivers/master
+Already up to date.
+Merging mac80211/master (3b07029729e3 mac80211: Fix sending ADDBA response for an ongoing session)
+$ git merge mac80211/master
+Auto-merging net/mac80211/mesh.c
+Auto-merging net/mac80211/ieee80211_i.h
+Auto-merging net/mac80211/cfg.c
+Auto-merging net/mac80211/agg-rx.c
+Auto-merging include/net/mac80211.h
+Auto-merging drivers/net/wireless/mac80211_hwsim.c
+Merge made by the 'recursive' strategy.
+ drivers/net/wireless/mac80211_hwsim.c |  2 +-
+ include/net/mac80211.h                |  2 +-
+ net/mac80211/agg-rx.c                 |  4 +---
+ net/mac80211/cfg.c                    |  2 +-
+ net/mac80211/ieee80211_i.h            |  2 +-
+ net/mac80211/mesh.c                   | 17 ++++++-----------
+ net/mac80211/spectmgmt.c              |  7 +++----
+ net/mac80211/sta_info.c               |  3 ++-
+ net/wireless/mesh.c                   | 25 ++++++++++++++++++++++---
+ net/wireless/sme.c                    |  2 ++
+ 10 files changed, 40 insertions(+), 26 deletions(-)
+Merging rdma-fixes/for-rc (2f08ee363fe0 RDMA/restrack: don't use uaccess_kernel())
+$ git merge rdma-fixes/for-rc
+Merge made by the 'recursive' strategy.
+ drivers/infiniband/core/core_priv.h             |  7 +++-
+ drivers/infiniband/core/rdma_core.c             | 38 ++++++++++++++------
+ drivers/infiniband/core/restrack.c              | 23 ++++++++----
+ drivers/infiniband/core/uverbs_cmd.c            | 47 +++++++++++++++++++------
+ drivers/infiniband/core/uverbs_ioctl.c          |  3 ++
+ drivers/infiniband/core/uverbs_ioctl_merge.c    | 18 +++++-----
+ drivers/infiniband/core/uverbs_main.c           | 29 +++++++++++----
+ drivers/infiniband/core/uverbs_std_types.c      | 12 ++++---
+ drivers/infiniband/core/verbs.c                 |  3 +-
+ drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c    |  4 ++-
+ drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c   |  4 ++-
+ drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c |  4 ++-
+ drivers/infiniband/ulp/ipoib/ipoib_fs.c         |  2 --
+ include/rdma/restrack.h                         |  4 ---
+ include/rdma/uverbs_ioctl.h                     | 43 +++++++++++++++-------
+ include/uapi/rdma/rdma_user_ioctl.h             |  4 +--
+ 16 files changed, 172 insertions(+), 73 deletions(-)
+Merging sound-current/for-linus (fdcc968a3b29 ALSA: hda/realtek: PCI quirk for Fujitsu U7x7)
+$ git merge sound-current/for-linus
+Already up to date.
+Merging pci-current/for-linus (7928b2cbe55b Linux 4.16-rc1)
+$ git merge pci-current/for-linus
+Already up to date.
+Merging driver-core.current/driver-core-linus (7928b2cbe55b Linux 4.16-rc1)
+$ git merge driver-core.current/driver-core-linus
+Already up to date.
+Merging tty.current/tty-linus (7928b2cbe55b Linux 4.16-rc1)
+$ git merge tty.current/tty-linus
+Already up to date.
+Merging usb.current/usb-linus (fc19b1d09414 Merge tag 'fixes-for-v4.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-linus)
+$ git merge usb.current/usb-linus
+Merge made by the 'recursive' strategy.
+ drivers/hid/hid-ids.h                 |   3 +
+ drivers/hid/hid-quirks.c              |   3 +
+ drivers/usb/class/cdc-acm.c           |   9 ++-
+ drivers/usb/core/quirks.c             |   3 +
+ drivers/usb/dwc2/gadget.c             |  26 ++++----
+ drivers/usb/dwc3/core.c               |  86 +++++++++++++++++++--------
+ drivers/usb/dwc3/core.h               |  21 ++++---
+ drivers/usb/dwc3/dwc3-of-simple.c     |   1 +
+ drivers/usb/dwc3/dwc3-omap.c          |  16 +++++
+ drivers/usb/dwc3/ep0.c                |   7 ++-
+ drivers/usb/dwc3/gadget.c             |   2 +
+ drivers/usb/gadget/function/f_fs.c    |  44 +++-----------
+ drivers/usb/gadget/function/f_uac2.c  |   2 +
+ drivers/usb/gadget/udc/Kconfig        |   1 -
+ drivers/usb/gadget/udc/bdc/bdc_pci.c  |   1 +
+ drivers/usb/gadget/udc/core.c         |   2 +-
+ drivers/usb/gadget/udc/fsl_udc_core.c |   4 +-
+ drivers/usb/gadget/udc/renesas_usb3.c |   2 +-
+ drivers/usb/host/ehci-hub.c           |   4 +-
+ drivers/usb/host/ehci-q.c             |  12 ++--
+ drivers/usb/host/ohci-hcd.c           |  10 +++-
+ drivers/usb/host/ohci-hub.c           |   4 +-
+ drivers/usb/host/ohci-q.c             |  17 +++---
+ drivers/usb/host/pci-quirks.c         | 109 ++++++++++++++++++++++++++++++++++
+ drivers/usb/host/pci-quirks.h         |   5 ++
+ drivers/usb/host/xhci-debugfs.c       |   4 +-
+ drivers/usb/host/xhci-hub.c           |  25 +++++---
+ drivers/usb/host/xhci-pci.c           |  11 ++++
+ drivers/usb/host/xhci.c               |  10 ++--
+ drivers/usb/host/xhci.h               |   2 +-
+ drivers/usb/misc/ldusb.c              |   6 ++
+ drivers/usb/phy/phy-mxs-usb.c         |   3 +
+ drivers/usb/renesas_usbhs/fifo.c      |   5 ++
+ drivers/usb/serial/option.c           |   7 +++
+ drivers/usb/usbip/stub_dev.c          |   3 +
+ drivers/usb/usbip/vhci_hcd.c          |   2 +
+ 36 files changed, 347 insertions(+), 125 deletions(-)
+Merging usb-gadget-fixes/fixes (98112041bcca usb: dwc3: core: Fix ULPI PHYs and prevent phy_get/ulpi_init during suspend/resume)
+$ git merge usb-gadget-fixes/fixes
+Already up to date.
+Merging usb-serial-fixes/usb-linus (d14ac576d10f USB: serial: cp210x: add new device ID ELV ALC 8xxx)
+$ git merge usb-serial-fixes/usb-linus
+Already up to date.
+Merging usb-chipidea-fixes/ci-for-usb-stable (964728f9f407 USB: chipidea: msm: fix ulpi-node lookup)
+$ git merge usb-chipidea-fixes/ci-for-usb-stable
+Already up to date.
+Merging phy/fixes (7928b2cbe55b Linux 4.16-rc1)
+$ git merge phy/fixes
+Already up to date.
+Merging staging.current/staging-linus (6d79bd5bb6c7 staging: android: ion: Zero CMA allocated memory)
+$ git merge staging.current/staging-linus
+Merge made by the 'recursive' strategy.
+ drivers/staging/android/ashmem.c           | 19 +++++++++++--------
+ drivers/staging/android/ion/ion_cma_heap.c | 17 +++++++++++++++++
+ drivers/staging/fsl-mc/bus/Kconfig         |  2 +-
+ 3 files changed, 29 insertions(+), 9 deletions(-)
+Merging char-misc.current/char-misc-linus (7ae079aca59f mei: set device client to the disconnected state upon suspend.)
+$ git merge char-misc.current/char-misc-linus
+Merge made by the 'recursive' strategy.
+ drivers/android/binder.c  | 29 +++++++++++++++++++++++------
+ drivers/misc/mei/bus.c    |  6 ------
+ drivers/misc/mei/client.c |  6 ++++++
+ 3 files changed, 29 insertions(+), 12 deletions(-)
+Merging input-current/for-linus (ea4f7bd2aca9 Input: matrix_keypad - fix race when disabling interrupts)
+$ git merge input-current/for-linus
+Merge made by the 'recursive' strategy.
+ drivers/input/keyboard/matrix_keypad.c |  4 +++-
+ drivers/input/touchscreen/mms114.c     | 15 ++++++---------
+ 2 files changed, 9 insertions(+), 10 deletions(-)
+Merging crypto-current/master (c927b080c67e crypto: s5p-sss - Fix kernel Oops in AES-ECB mode)
+$ git merge crypto-current/master
+Merge made by the 'recursive' strategy.
+ drivers/crypto/s5p-sss.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+Merging ide/master (8e44e6600caa Merge branch 'KASAN-read_word_at_a_time')
+$ git merge ide/master
+Already up to date.
+Merging vfio-fixes/for-linus (563b5cbe334e iommu/arm-smmu-v3: Cope with duplicated Stream IDs)
+$ git merge vfio-fixes/for-linus
+Already up to date.
+Merging kselftest-fixes/fixes (9eaa1fb21961 selftests: vm: update .gitignore with new test)
+$ git merge kselftest-fixes/fixes
+Resolved 'tools/testing/selftests/x86/Makefile' using previous resolution.
+Auto-merging tools/testing/selftests/x86/Makefile
+CONFLICT (content): Merge conflict in tools/testing/selftests/x86/Makefile
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master ef6ba01961f1] Merge remote-tracking branch 'kselftest-fixes/fixes'
+$ git diff -M --stat --summary HEAD^..
+ tools/testing/selftests/android/Makefile        |  8 ++++----
+ tools/testing/selftests/futex/Makefile          |  6 +++---
+ tools/testing/selftests/memfd/config            |  1 +
+ tools/testing/selftests/memory-hotplug/Makefile |  2 +-
+ tools/testing/selftests/pstore/config           |  1 +
+ tools/testing/selftests/sync/Makefile           |  2 +-
+ tools/testing/selftests/vDSO/Makefile           | 14 +++++++-------
+ tools/testing/selftests/vm/.gitignore           |  1 +
+ 8 files changed, 19 insertions(+), 16 deletions(-)
+ create mode 100644 tools/testing/selftests/memfd/config
+Merging backlight-fixes/for-backlight-fixes (8ff5cbc6e3c5 backlight: as3711_bl: fix device-tree node leaks)
+$ git merge backlight-fixes/for-backlight-fixes
+Merge made by the 'recursive' strategy.
+ drivers/video/backlight/as3711_bl.c   | 45 ++++++++++++++++++++++-------------
+ drivers/video/backlight/max8925_bl.c  |  4 +++-
+ drivers/video/backlight/tps65217_bl.c |  4 ++--
+ include/linux/mfd/as3711.h            |  4 ++--
+ 4 files changed, 36 insertions(+), 21 deletions(-)
+Merging nand-fixes/nand/fixes (ee02f73e04c0 mtd: nand: atmel: Fix EDO mode check)
+$ git merge nand-fixes/nand/fixes
+Already up to date.
+Merging spi-nor-fixes/spi-nor/fixes (7928b2cbe55b Linux 4.16-rc1)
+$ git merge spi-nor-fixes/spi-nor/fixes
+Already up to date.
+Merging mfd-fixes/for-mfd-fixes (107b7d9fa94c mfd: rtsx: Release IRQ during shutdown)
+$ git merge mfd-fixes/for-mfd-fixes
+Already up to date.
+Merging v4l-dvb-fixes/fixes (781b045baefd media: imx274: Fix error handling, add MAINTAINERS entry)
+$ git merge v4l-dvb-fixes/fixes
+Already up to date.
+Merging reset-fixes/reset/fixes (f450f28e70a2 reset: socfpga: fix for 64-bit compilation)
+$ git merge reset-fixes/reset/fixes
+Already up to date.
+Merging mips-fixes/mips-fixes (5efad9eee33e sparc,leon: Select USB_UHCI_BIG_ENDIAN_{MMIO,DESC})
+$ git merge mips-fixes/mips-fixes
+Already up to date.
+Merging kvm-fixes/master (722c2cd7b7c9 Merge tag 'kvm-s390-master-4.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD)
+$ git merge kvm-fixes/master
+Merge made by the 'recursive' strategy.
+ arch/s390/kvm/intercept.c |  51 +++++++------
+ arch/s390/kvm/interrupt.c |  98 +++++++++++++++----------
+ arch/s390/kvm/kvm-s390.h  |   2 -
+ arch/s390/kvm/priv.c      | 183 +++++++++++++++++++++++-----------------------
+ arch/s390/kvm/vsie.c      |  20 +++++
+ 5 files changed, 200 insertions(+), 154 deletions(-)
+Merging kvms390-fixes/master (baabee67f413 KVM: s390: use switch vs jump table in interrupt.c)
+$ git merge kvms390-fixes/master
+Already up to date.
+Merging drm-intel-fixes/for-linux-next-fixes (ee622fe757f6 drm/i915: Fix DSI panels with v1 MIPI sequences without a DEASSERT sequence v3)
+$ git merge drm-intel-fixes/for-linux-next-fixes
+Already up to date.
+Merging drm-misc-fixes/for-linux-next-fixes (06998a756a38 drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA)
+$ git merge drm-misc-fixes/for-linux-next-fixes
+Auto-merging kernel/workqueue.c
+Auto-merging include/drm/drm_atomic.h
+Auto-merging drivers/gpu/drm/radeon/radeon_connectors.c
+Auto-merging drivers/gpu/drm/drm_probe_helper.c
+Auto-merging drivers/gpu/drm/drm_edid.c
+Auto-merging drivers/gpu/drm/drm_atomic_helper.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+Merge made by the 'recursive' strategy.
+ drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 58 +++++++++++++-------
+ drivers/gpu/drm/cirrus/cirrus_mode.c           | 40 ++++++++------
+ drivers/gpu/drm/drm_atomic_helper.c            | 15 ++++++
+ drivers/gpu/drm/drm_edid.c                     |  3 ++
+ drivers/gpu/drm/drm_probe_helper.c             | 20 +++++++
+ drivers/gpu/drm/nouveau/nouveau_connector.c    | 18 +++++--
+ drivers/gpu/drm/radeon/radeon_connectors.c     | 74 +++++++++++++++++---------
+ include/drm/drm_atomic.h                       |  9 ++++
+ include/drm/drm_crtc_helper.h                  |  1 +
+ include/linux/workqueue.h                      |  1 +
+ kernel/workqueue.c                             | 16 ++++++
+ 11 files changed, 188 insertions(+), 67 deletions(-)
+Merging kbuild/for-next (b583b9f9c919 kbuild: process mixture of clean/build targets one by one)
+$ git merge kbuild/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/kbuild/makefiles.txt | 22 ++++++---
+ Documentation/process/changes.rst  |  2 +-
+ Makefile                           | 25 +++++++---
+ arch/Kconfig                       |  6 ---
+ arch/blackfin/kernel/bfin_ksyms.c  |  2 +-
+ arch/powerpc/kernel/Makefile       |  2 +-
+ arch/sh/boot/dts/Makefile          |  4 +-
+ drivers/s390/Makefile              |  2 +-
+ lib/Kconfig.debug                  |  4 +-
+ scripts/Kbuild.include             |  2 +-
+ scripts/Makefile.build             | 40 ++++++---------
+ scripts/Makefile.lib               |  6 +--
+ scripts/adjust_autoksyms.sh        |  4 +-
+ scripts/gen_initramfs_list.sh      |  2 +-
+ scripts/headers_install.sh         | 10 ++--
+ scripts/link-vmlinux.sh            | 99 ++++++++++++++------------------------
+ scripts/namespace.pl               |  2 +-
+ usr/initramfs_data.S               |  2 +-
+ 18 files changed, 106 insertions(+), 130 deletions(-)
+Merging uuid/for-next (c0020756315e efi: switch to use new generic UUID API)
+$ git merge uuid/for-next
+Already up to date.
+Merging dma-mapping/for-next (04f56534786c MAINTAINERS: add the iommu list for swiotlb and xen-swiotlb)
+$ git merge dma-mapping/for-next
+Already up to date.
+Merging asm-generic/master (a351e9b9fc24 Linux 4.11)
+$ git merge asm-generic/master
+Already up to date.
+Merging arc/for-next (4fbd8d194f06 Linux 4.15-rc1)
+$ git merge arc/for-next
+Already up to date.
+Merging arm/for-next (3a175cdf4392 Merge branches 'fixes', 'misc', 'sa1111' and 'sa1100-for-next' into for-next)
+$ git merge arm/for-next
+Already up to date.
+Merging arm-perf/for-next/perf (7928b2cbe55b Linux 4.16-rc1)
+$ git merge arm-perf/for-next/perf
+Already up to date.
+Merging arm-soc/for-next (2aa127e4d579 Merge branches 'next/dt' and 'next/drivers' into for-next)
+$ git merge arm-soc/for-next
+Merge made by the 'recursive' strategy.
+ arch/arm/arm-soc-for-next-contents.txt | 239 +++++++++++++++++++++++++++++++++
+ 1 file changed, 239 insertions(+)
+ create mode 100644 arch/arm/arm-soc-for-next-contents.txt
+Merging actions/for-next (61862a89e6ac Merge branch 'v4.16/drivers' into next)
+$ git merge actions/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging alpine/alpine/for-next (a1144b2b1ec4 ARM: dts: alpine: add valid clock-frequency values)
+$ git merge alpine/alpine/for-next
+Merge made by the 'recursive' strategy.
+Merging amlogic/for-next (b1303f3fa73b Merge branch 'v4.17/drivers' into tmp/aml-rebuild)
+$ git merge amlogic/for-next
+Merge made by the 'recursive' strategy.
+ arch/arm/boot/dts/meson8.dtsi                      |   9 +
+ arch/arm/boot/dts/meson8b-odroidc1.dts             |  30 +++
+ arch/arm/boot/dts/meson8b.dtsi                     |  37 ++-
+ arch/arm64/boot/dts/amlogic/meson-axg-s400.dts     |  15 ++
+ arch/arm64/boot/dts/amlogic/meson-axg.dtsi         | 268 ++++++++++++++++++++-
+ .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi |   1 +
+ arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |  10 +-
+ .../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts      |   1 +
+ .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    |   1 +
+ .../arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts |   1 +
+ arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   |   1 +
+ .../boot/dts/amlogic/meson-gxbb-vega-s95.dtsi      |   1 +
+ .../dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts |   1 +
+ .../dts/amlogic/meson-gxl-s905x-khadas-vim.dts     |   1 +
+ .../dts/amlogic/meson-gxl-s905x-libretech-cc.dts   |   1 +
+ .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts    |   1 +
+ .../boot/dts/amlogic/meson-gxl-s905x-p212.dtsi     |   1 +
+ arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   1 +
+ .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts |   1 +
+ arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts |   1 +
+ arch/arm64/configs/defconfig                       |   1 +
+ drivers/soc/amlogic/meson-gx-pwrc-vpu.c            |   9 +-
+ drivers/soc/amlogic/meson-gx-socinfo.c             |   2 +-
+ drivers/soc/amlogic/meson-mx-socinfo.c             |   2 +-
+ 24 files changed, 381 insertions(+), 16 deletions(-)
+Merging aspeed/for-next (91b55cc53a17 Merge branch 'dt-for-4.17' into for-next)
+$ git merge aspeed/for-next
+Merge made by the 'recursive' strategy.
+ arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts    | 188 +++++++++++++++++++++++
+ arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts     |   4 +
+ arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts |   4 +
+ arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts       |   4 +
+ arch/arm/boot/dts/aspeed-g4.dtsi                 |   8 +
+ arch/arm/boot/dts/aspeed-g5.dtsi                 |  15 +-
+ 6 files changed, 219 insertions(+), 4 deletions(-)
+Merging at91/at91-next (fa4cf68ab4b1 Merge tag 'at91-ab-4.16-dt' into at91-next)
+$ git merge at91/at91-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging bcm2835/for-next (a6189bcc0012 Merge branch anholt/bcm2835-drivers-next into for-next)
+$ git merge bcm2835/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging imx-mxs/for-next (914867289762 Merge branch 'imx/defconfig' into for-next)
+$ git merge imx-mxs/for-next
+Removing arch/arm/mach-imx/epit.c
+Merge made by the 'recursive' strategy.
+ arch/arm/boot/dts/Makefile                         |   8 +-
+ arch/arm/boot/dts/imx1-ads.dts                     |   2 +-
+ arch/arm/boot/dts/imx1-apf9328.dts                 |   2 +-
+ arch/arm/boot/dts/imx1.dtsi                        |   2 +-
+ arch/arm/boot/dts/imx23-evk.dts                    |   2 +-
+ arch/arm/boot/dts/imx23-olinuxino.dts              |   2 +-
+ arch/arm/boot/dts/imx23-sansa.dts                  |   2 +-
+ arch/arm/boot/dts/imx23-stmp378x_devb.dts          |   2 +-
+ arch/arm/boot/dts/imx23-xfi3.dts                   |   2 +-
+ arch/arm/boot/dts/imx23.dtsi                       |   8 +-
+ arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi       |   2 +-
+ .../boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts  |  12 +-
+ arch/arm/boot/dts/imx25-karo-tx25.dts              |   2 +-
+ arch/arm/boot/dts/imx25-pdk.dts                    |  14 +-
+ arch/arm/boot/dts/imx25-pinfunc.h                  |  72 ++-
+ arch/arm/boot/dts/imx25.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx27-apf27.dts                  |   2 +-
+ arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi       |  17 +-
+ .../boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts  |   2 +-
+ arch/arm/boot/dts/imx27-pdk.dts                    |   2 +-
+ arch/arm/boot/dts/imx27-phytec-phycard-s-som.dtsi  |   2 +-
+ arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi    |   2 +-
+ arch/arm/boot/dts/imx27.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx28-apf28.dts                  |   2 +-
+ arch/arm/boot/dts/imx28-apx4devkit.dts             |   5 +-
+ arch/arm/boot/dts/imx28-cfa10036.dts               |   2 +-
+ arch/arm/boot/dts/imx28-cfa10049.dts               | 130 ++---
+ arch/arm/boot/dts/imx28-duckbill-2-485.dts         |   2 +-
+ arch/arm/boot/dts/imx28-duckbill-2-enocean.dts     |   2 +-
+ arch/arm/boot/dts/imx28-duckbill-2-spi.dts         |   2 +-
+ arch/arm/boot/dts/imx28-duckbill-2.dts             |   2 +-
+ arch/arm/boot/dts/imx28-duckbill.dts               |   2 +-
+ arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts       |   2 +-
+ arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts       |   2 +-
+ arch/arm/boot/dts/imx28-evk.dts                    |   2 +-
+ arch/arm/boot/dts/imx28-m28.dtsi                   |   2 +-
+ arch/arm/boot/dts/imx28-m28cu3.dts                 |   2 +-
+ arch/arm/boot/dts/imx28-sps1.dts                   |   2 +-
+ arch/arm/boot/dts/imx28-ts4600.dts                 |   2 +-
+ arch/arm/boot/dts/imx28-tx28.dts                   |  30 +-
+ arch/arm/boot/dts/imx28.dtsi                       |  20 +-
+ arch/arm/boot/dts/imx31-bug.dts                    |   2 +-
+ arch/arm/boot/dts/imx31.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi       |   2 +-
+ arch/arm/boot/dts/imx35-pdk.dts                    |   2 +-
+ arch/arm/boot/dts/imx35.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx50-evk.dts                    |   2 +-
+ arch/arm/boot/dts/imx50.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx51-apf51.dts                  |   2 +-
+ arch/arm/boot/dts/imx51-babbage.dts                |   2 +-
+ arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi  |   2 +-
+ arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi       |   2 +-
+ arch/arm/boot/dts/imx51-ts4800.dts                 |   2 +-
+ arch/arm/boot/dts/imx51-zii-rdu1.dts               |   5 +
+ arch/arm/boot/dts/imx51.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx53-ard.dts                    |   2 +-
+ arch/arm/boot/dts/imx53-cx9020.dts                 |   2 +-
+ arch/arm/boot/dts/imx53-m53.dtsi                   |   2 +-
+ arch/arm/boot/dts/imx53-ppd.dts                    |  11 +
+ arch/arm/boot/dts/imx53-qsb-common.dtsi            |   2 +-
+ arch/arm/boot/dts/imx53-smd.dts                    |   2 +-
+ arch/arm/boot/dts/imx53-tqma53.dtsi                |   2 +-
+ arch/arm/boot/dts/imx53-tx53.dtsi                  |   5 +
+ arch/arm/boot/dts/imx53-usbarmory.dts              |   2 +-
+ arch/arm/boot/dts/imx53.dtsi                       |   2 +-
+ arch/arm/boot/dts/imx6dl-apf6dev.dts               |   2 +-
+ arch/arm/boot/dts/imx6dl-aristainetos2_4.dts       |   2 +-
+ arch/arm/boot/dts/imx6dl-aristainetos2_7.dts       |   2 +-
+ arch/arm/boot/dts/imx6dl-aristainetos_4.dts        |   2 +-
+ arch/arm/boot/dts/imx6dl-aristainetos_7.dts        |   2 +-
+ arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts       |   5 +
+ arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts         |   5 +
+ arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts  |  64 +++
+ arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi        |   2 +-
+ arch/arm/boot/dts/imx6dl-rex-basic.dts             |   2 +-
+ arch/arm/boot/dts/imx6dl-riotboard.dts             |   2 +-
+ arch/arm/boot/dts/imx6dl-ts4900.dts                |   5 +
+ arch/arm/boot/dts/imx6dl-ts7970.dts                |   5 +
+ arch/arm/boot/dts/imx6dl-wandboard-revb1.dts       |   2 +-
+ arch/arm/boot/dts/imx6dl-wandboard-revd1.dts       |   2 +-
+ arch/arm/boot/dts/imx6dl-wandboard.dts             |   2 +-
+ arch/arm/boot/dts/imx6q-apf6dev.dts                |   2 +-
+ arch/arm/boot/dts/imx6q-arm2.dts                   |   2 +-
+ arch/arm/boot/dts/imx6q-ba16.dtsi                  |   2 +-
+ arch/arm/boot/dts/imx6q-bx50v3.dtsi                |   8 +
+ arch/arm/boot/dts/imx6q-cm-fx6.dts                 |   2 +-
+ arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts          |   5 +
+ arch/arm/boot/dts/imx6q-display5.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts            |   2 +-
+ arch/arm/boot/dts/imx6q-evi.dts                    |   2 +-
+ arch/arm/boot/dts/imx6q-gk802.dts                  |   2 +-
+ arch/arm/boot/dts/imx6q-gw5400-a.dts               |   2 +-
+ arch/arm/boot/dts/imx6q-h100.dts                   |   7 +-
+ arch/arm/boot/dts/imx6q-marsboard.dts              |   2 +-
+ arch/arm/boot/dts/imx6q-mccmon6.dts                |   2 +-
+ arch/arm/boot/dts/imx6q-novena.dts                 |   5 +
+ arch/arm/boot/dts/imx6q-phytec-mira-rdk-emmc.dts   |  72 +++
+ arch/arm/boot/dts/imx6q-phytec-mira-rdk-nand.dts   |  72 +++
+ arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi         |   2 +-
+ arch/arm/boot/dts/imx6q-pistachio.dts              |   2 +-
+ arch/arm/boot/dts/imx6q-rex-pro.dts                |   2 +-
+ arch/arm/boot/dts/imx6q-sbc6x.dts                  |   2 +-
+ arch/arm/boot/dts/imx6q-tbs2910.dts                |   2 +-
+ arch/arm/boot/dts/imx6q-ts4900.dts                 |   5 +
+ arch/arm/boot/dts/imx6q-ts7970.dts                 |   5 +
+ arch/arm/boot/dts/imx6q-wandboard-revb1.dts        |   2 +-
+ arch/arm/boot/dts/imx6q-wandboard-revd1.dts        |   2 +-
+ arch/arm/boot/dts/imx6q-wandboard.dts              |   2 +-
+ arch/arm/boot/dts/imx6q-zii-rdu2.dts               |   5 +
+ arch/arm/boot/dts/imx6qdl-apalis.dtsi              |   5 +
+ arch/arm/boot/dts/imx6qdl-cubox-i.dtsi             |   5 +
+ arch/arm/boot/dts/imx6qdl-gw51xx.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw52xx.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw53xx.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw54xx.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw551x.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw552x.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw553x.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw5903.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-gw5904.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6qdl-hummingboard.dtsi        |   5 +
+ arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi       |   5 +
+ arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi           |   2 +-
+ arch/arm/boot/dts/imx6qdl-icore.dtsi               |   2 +-
+ arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi           |   2 +-
+ arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi       |   2 +-
+ arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi      |   2 +-
+ arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi          |   2 +-
+ arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi         | 390 +++++++++++++++
+ arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi       |   2 +-
+ arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi  | 279 +++++++++++
+ arch/arm/boot/dts/imx6qdl-rex.dtsi                 |   2 +-
+ arch/arm/boot/dts/imx6qdl-sabreauto.dtsi           |   2 +-
+ arch/arm/boot/dts/imx6qdl-sabrelite.dtsi           |   2 +-
+ arch/arm/boot/dts/imx6qdl-sabresd.dtsi             |   2 +-
+ arch/arm/boot/dts/imx6qdl-udoo.dtsi                |   2 +-
+ arch/arm/boot/dts/imx6qdl-var-dart.dtsi            |   2 +-
+ arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi            |   6 +-
+ arch/arm/boot/dts/imx6qdl.dtsi                     |   4 +-
+ arch/arm/boot/dts/imx6qp-phytec-mira-rdk-nand.dts  |  72 +++
+ arch/arm/boot/dts/imx6qp-wandboard-revd1.dts       |   2 +-
+ arch/arm/boot/dts/imx6qp-zii-rdu2.dts              |   5 +
+ arch/arm/boot/dts/imx6sl-evk.dts                   |   2 +-
+ arch/arm/boot/dts/imx6sl-warp.dts                  |   2 +-
+ arch/arm/boot/dts/imx6sl.dtsi                      |   2 +-
+ arch/arm/boot/dts/imx6sx-nitrogen6sx.dts           |   2 +-
+ arch/arm/boot/dts/imx6sx-sabreauto.dts             |   2 +-
+ arch/arm/boot/dts/imx6sx-sdb.dtsi                  |   2 +-
+ arch/arm/boot/dts/imx6sx-softing-vining-2000.dts   |   2 +-
+ arch/arm/boot/dts/imx6sx-udoo-neo-basic.dts        |   2 +-
+ arch/arm/boot/dts/imx6sx-udoo-neo-extended.dts     |   2 +-
+ arch/arm/boot/dts/imx6sx-udoo-neo-full.dts         |   2 +-
+ arch/arm/boot/dts/imx6sx.dtsi                      |  15 +-
+ arch/arm/boot/dts/imx6ul-14x14-evk.dts             | 480 +-----------------
+ arch/arm/boot/dts/imx6ul-14x14-evk.dtsi            | 499 +++++++++++++++++++
+ arch/arm/boot/dts/imx6ul-geam.dts                  |   2 +-
+ arch/arm/boot/dts/imx6ul-isiot.dtsi                |   2 +-
+ arch/arm/boot/dts/imx6ul-litesom.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6ul-opos6ul.dtsi              |   2 +-
+ arch/arm/boot/dts/imx6ul-pico-hobbit.dts           |   2 +-
+ arch/arm/boot/dts/imx6ul-pinfunc.h                 | 169 ++++---
+ arch/arm/boot/dts/imx6ul.dtsi                      |  23 +-
+ arch/arm/boot/dts/imx6ull-14x14-evk.dts            |   5 +-
+ arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts      |  14 +
+ arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi     | 157 ++++++
+ arch/arm/boot/dts/imx6ull-colibri-nonwifi.dtsi     |  23 +
+ arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts |  14 +
+ arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi        |  65 +++
+ arch/arm/boot/dts/imx6ull-colibri.dtsi             | 553 +++++++++++++++++++++
+ arch/arm/boot/dts/imx6ull-pinfunc-snvs.h           |  26 +
+ arch/arm/boot/dts/imx6ull.dtsi                     |  32 ++
+ arch/arm/boot/dts/imx7d-cl-som-imx7.dts            |  54 +-
+ arch/arm/boot/dts/imx7d-colibri-emmc.dtsi          |   2 +-
+ arch/arm/boot/dts/imx7d-colibri.dtsi               |   2 +-
+ arch/arm/boot/dts/imx7d-nitrogen7.dts              |   2 +-
+ arch/arm/boot/dts/imx7d-pico.dtsi                  |   2 +-
+ arch/arm/boot/dts/imx7d-sdb.dts                    |   7 +-
+ arch/arm/boot/dts/imx7s-colibri.dtsi               |   2 +-
+ arch/arm/boot/dts/imx7s-warp.dts                   |  18 +-
+ arch/arm/boot/dts/imx7s.dtsi                       |   2 +-
+ arch/arm/boot/dts/ls1021a.dtsi                     |  16 +
+ arch/arm/configs/imx_v6_v7_defconfig               |   9 +
+ arch/arm/mach-imx/Kconfig                          |  13 -
+ arch/arm/mach-imx/Makefile                         |   1 -
+ arch/arm/mach-imx/anatop.c                         |  56 +--
+ arch/arm/mach-imx/cpuidle-imx6sx.c                 |   1 +
+ arch/arm/mach-imx/epit.c                           | 228 ---------
+ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi     |  62 +--
+ arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi     |  62 +--
+ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi     |  62 +--
+ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi     | 132 +++--
+ arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi |   8 +-
+ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi     |  98 ++--
+ .../boot/dts/freescale/qoriq-bman-portals.dtsi     |   6 +
+ .../boot/dts/freescale/qoriq-qman-portals.dtsi     |   7 +
+ drivers/soc/imx/gpc.c                              |  10 +-
+ drivers/soc/imx/gpcv2.c                            |  13 +-
+ 197 files changed, 3250 insertions(+), 1321 deletions(-)
+ create mode 100644 arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts
+ create mode 100644 arch/arm/boot/dts/imx6q-phytec-mira-rdk-emmc.dts
+ create mode 100644 arch/arm/boot/dts/imx6q-phytec-mira-rdk-nand.dts
+ create mode 100644 arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6qp-phytec-mira-rdk-nand.dts
+ create mode 100644 arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts
+ create mode 100644 arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6ull-colibri-nonwifi.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts
+ create mode 100644 arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6ull-colibri.dtsi
+ create mode 100644 arch/arm/boot/dts/imx6ull-pinfunc-snvs.h
+ delete mode 100644 arch/arm/mach-imx/epit.c
+Merging keystone/next (a29b8b93e158 Merge branch 'for_4.16/keystone-config' into next)
+$ git merge keystone/next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging mvebu/for-next (b4e369232fa8 Merge branch 'mvebu/dt64' into mvebu/for-next)
+$ git merge mvebu/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                                        |  4 +-
+ arch/arm/boot/dts/armada-370-netgear-rn102.dts     |  2 +-
+ arch/arm/boot/dts/armada-370-netgear-rn104.dts     |  2 +-
+ arch/arm/boot/dts/armada-xp-netgear-rn2120.dts     |  2 +-
+ arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts   |  2 +-
+ arch/arm/mach-mvebu/Kconfig                        |  4 +-
+ arch/arm64/boot/dts/marvell/armada-371x.dtsi       | 38 +------------
+ arch/arm64/boot/dts/marvell/armada-3720-db.dts     | 39 +------------
+ .../boot/dts/marvell/armada-3720-espressobin.dts   | 38 +------------
+ arch/arm64/boot/dts/marvell/armada-372x.dtsi       | 38 +------------
+ arch/arm64/boot/dts/marvell/armada-37xx.dtsi       | 38 +------------
+ arch/arm64/boot/dts/marvell/armada-7020.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-7040-db.dts     | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-7040.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-70x0.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-8020.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-8040-db.dts     | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts  | 65 ++++++++--------------
+ arch/arm64/boot/dts/marvell/armada-8040.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-8080-db.dts     | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-8080.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-80x0.dtsi       | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-ap806.dtsi      | 41 +-------------
+ .../dts/marvell/armada-ap810-ap0-octa-core.dtsi    | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-ap810-ap0.dtsi  | 41 +-------------
+ arch/arm64/boot/dts/marvell/armada-common.dtsi     |  2 +-
+ arch/arm64/boot/dts/marvell/armada-cp110.dtsi      | 60 +++++++++++++++++---
+ 29 files changed, 106 insertions(+), 843 deletions(-)
+Merging omap/for-next (64dbb6ed7c33 Merge branch 'omap-for-v4.16/fixes' into for-next)
+$ git merge omap/for-next
+Auto-merging arch/arm/mach-omap1/i2c.h
+Auto-merging arch/arm/boot/dts/Makefile
+Merge made by the 'recursive' strategy.
+ arch/arm/boot/dts/Makefile                         |   1 +
+ arch/arm/boot/dts/am335x-boneblue.dts              |   2 +-
+ arch/arm/boot/dts/am335x-pdu001.dts                | 595 +++++++++++++++++++++
+ arch/arm/boot/dts/dra7.dtsi                        |   2 -
+ arch/arm/boot/dts/logicpd-som-lv.dtsi              |   9 +-
+ arch/arm/boot/dts/logicpd-torpedo-som.dtsi         |   8 +
+ arch/arm/boot/dts/omap3-n9.dts                     |   7 +
+ arch/arm/boot/dts/omap4-droid4-xt894.dts           |  22 +-
+ arch/arm/boot/dts/omap443x.dtsi                    |   2 -
+ arch/arm/boot/dts/omap4460.dtsi                    |   2 -
+ arch/arm/boot/dts/omap5-uevm.dts                   |   2 +-
+ arch/arm/boot/dts/omap5.dtsi                       |   2 -
+ arch/arm/mach-omap1/clock.c                        |   6 +-
+ arch/arm/mach-omap1/common.h                       |   3 +-
+ arch/arm/mach-omap1/i2c.c                          |   2 -
+ .../{plat-omap/include/plat => mach-omap1}/i2c.h   |   9 +-
+ arch/arm/mach-omap2/devices.c                      |   2 +-
+ arch/arm/mach-omap2/hsmmc.c                        |   2 -
+ arch/arm/mach-omap2/i2c.h                          |  15 +-
+ arch/arm/mach-omap2/msdi.c                         |   1 -
+ arch/arm/mach-omap2/omap-wakeupgen.c               |   4 +-
+ arch/arm/mach-omap2/omap_hwmod.c                   |   6 +-
+ arch/arm/mach-omap2/omap_hwmod_2420_data.c         |  11 -
+ arch/arm/mach-omap2/omap_hwmod_2430_data.c         |  18 -
+ arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |  61 +--
+ .../mach-omap2/omap_hwmod_33xx_43xx_common_data.h  |   3 -
+ .../mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c |  25 +-
+ arch/arm/mach-omap2/omap_hwmod_33xx_data.c         |   4 -
+ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         | 116 ----
+ arch/arm/mach-omap2/omap_hwmod_43xx_data.c         |   8 -
+ arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |  75 ---
+ arch/arm/mach-omap2/omap_hwmod_54xx_data.c         |  54 --
+ arch/arm/mach-omap2/omap_hwmod_7xx_data.c          |  53 --
+ arch/arm/mach-omap2/omap_hwmod_81xx_data.c         |  31 +-
+ arch/arm/mach-omap2/omap_hwmod_common_data.h       |   1 -
+ arch/arm/mach-omap2/pm.c                           |   4 +-
+ arch/arm/mach-omap2/timer.c                        |  19 +-
+ arch/arm/plat-omap/include/plat/dmtimer.h          |   4 -
+ drivers/bus/ti-sysc.c                              |   2 +-
+ include/linux/platform_data/asoc-ti-mcbsp.h        |  12 -
+ include/linux/platform_data/gpio-omap.h            |   5 -
+ include/linux/platform_data/spi-omap2-mcspi.h      |   8 -
+ 42 files changed, 660 insertions(+), 558 deletions(-)
+ create mode 100644 arch/arm/boot/dts/am335x-pdu001.dts
+ rename arch/arm/{plat-omap/include/plat => mach-omap1}/i2c.h (90%)
+Merging reset/reset/next (70d2f16a6289 reset: meson: enable level reset support on Meson8b)
+$ git merge reset/reset/next
+Merge made by the 'recursive' strategy.
+ drivers/reset/reset-meson.c | 22 +++++-----------------
+ 1 file changed, 5 insertions(+), 17 deletions(-)
+Merging qcom/for-next (f5788d2f2929 Merge tag 'qcom-arm64-defconfig-for-4.16' into tagged-for-4.16)
+$ git merge qcom/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging realtek/for-next (2b6286eb7ab8 Merge branch 'v4.15/dt64' into next)
+$ git merge realtek/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging renesas/next (aa0ce0bb0b6f Merge branches 'arm64-defconfig-for-v4.17', 'arm64-dt-for-v4.17', 'defconfig-for-v4.17', 'dt-bindings-for-v4.17', 'dt-for-v4.17' and 'soc-for-v4.17' into next)
+$ git merge renesas/next
+Auto-merging arch/arm64/configs/defconfig
+Auto-merging arch/arm/boot/dts/Makefile
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/arm/shmobile.txt |    8 +
+ .../bindings/power/renesas,rcar-sysc.txt           |    1 +
+ .../devicetree/bindings/reset/renesas,rst.txt      |    1 +
+ arch/arm/boot/dts/Makefile                         |    1 +
+ arch/arm/boot/dts/emev2-kzm9d.dts                  |    8 +-
+ arch/arm/boot/dts/r7s72100.dtsi                    | 1018 +++----
+ arch/arm/boot/dts/r8a7743-iwg20m.dtsi              |    9 +
+ arch/arm/boot/dts/r8a7743.dtsi                     | 1334 +++++----
+ arch/arm/boot/dts/r8a7745-iwg22m.dtsi              |    9 +
+ arch/arm/boot/dts/r8a7745.dtsi                     | 1786 ++++++------
+ arch/arm/boot/dts/r8a7790-lager.dts                |  292 +-
+ arch/arm/boot/dts/r8a7790-stout.dts                |  363 +++
+ arch/arm/boot/dts/r8a7790.dtsi                     | 2847 ++++++++++---------
+ arch/arm/boot/dts/r8a7791-koelsch.dts              |  237 +-
+ arch/arm/boot/dts/r8a7791-porter.dts               |  135 +-
+ arch/arm/boot/dts/r8a7791.dtsi                     | 2994 ++++++++++----------
+ arch/arm/boot/dts/r8a7792-blanche.dts              |    5 +
+ arch/arm/boot/dts/r8a7792-wheat.dts                |    5 +
+ arch/arm/boot/dts/r8a7792.dtsi                     |  502 ++--
+ arch/arm/boot/dts/r8a7793-gose.dts                 |  257 +-
+ arch/arm/boot/dts/r8a7793.dtsi                     | 2402 ++++++++--------
+ arch/arm/boot/dts/r8a7794-alt.dts                  |   58 +-
+ arch/arm/boot/dts/r8a7794-silk.dts                 |  133 +-
+ arch/arm/boot/dts/r8a7794.dtsi                     | 2429 ++++++++--------
+ arch/arm/configs/shmobile_defconfig                |    1 +
+ arch/arm64/Kconfig.platforms                       |    6 +
+ arch/arm64/boot/dts/renesas/Makefile               |    1 +
+ arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi       |    2 +-
+ arch/arm64/boot/dts/renesas/r8a7795.dtsi           |  133 +-
+ arch/arm64/boot/dts/renesas/r8a7796.dtsi           |  128 +-
+ arch/arm64/boot/dts/renesas/r8a77970-eagle.dts     |   12 +
+ arch/arm64/boot/dts/renesas/r8a77970.dtsi          |  117 +-
+ arch/arm64/boot/dts/renesas/r8a77980-condor.dts    |   58 +
+ arch/arm64/boot/dts/renesas/r8a77980.dtsi          |  385 +++
+ arch/arm64/boot/dts/renesas/r8a77995-draak.dts     |  123 +
+ arch/arm64/boot/dts/renesas/r8a77995.dtsi          |  191 +-
+ arch/arm64/boot/dts/renesas/salvator-common.dtsi   |    7 +
+ arch/arm64/configs/defconfig                       |    1 +
+ drivers/soc/renesas/Kconfig                        |    7 +-
+ drivers/soc/renesas/Makefile                       |    1 +
+ drivers/soc/renesas/r8a77970-sysc.c                |   12 +-
+ drivers/soc/renesas/r8a77980-sysc.c                |   52 +
+ drivers/soc/renesas/rcar-rst.c                     |   36 +-
+ drivers/soc/renesas/rcar-sysc.c                    |    5 +-
+ drivers/soc/renesas/rcar-sysc.h                    |    1 +
+ drivers/soc/renesas/renesas-soc.c                  |    8 +
+ include/dt-bindings/power/r8a77980-sysc.h          |   43 +
+ 47 files changed, 10273 insertions(+), 7891 deletions(-)
+ create mode 100644 arch/arm/boot/dts/r8a7790-stout.dts
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-condor.dts
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980.dtsi
+ create mode 100644 drivers/soc/renesas/r8a77980-sysc.c
+ create mode 100644 include/dt-bindings/power/r8a77980-sysc.h
+Merging rockchip/for-next (cc95e6771f11 Merge branch 'v4.17-armsoc/dts64' into for-next)
+$ git merge rockchip/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/arm/rockchip.txt |   8 +
+ .../bindings/clock/rockchip,rk3328-cru.txt         |   1 +
+ arch/arm/boot/dts/rk3036.dtsi                      |   4 +-
+ arch/arm/boot/dts/rk322x.dtsi                      |   8 +-
+ arch/arm/boot/dts/rk3288-phycore-rdk.dts           |   6 +-
+ arch/arm/boot/dts/rk3288-phycore-som.dtsi          |  25 +-
+ arch/arm/boot/dts/rk3288-rock2-som.dtsi            |   4 +
+ arch/arm/boot/dts/rk3288-rock2-square.dts          |  41 +++
+ arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi    |   1 -
+ arch/arm/boot/dts/rk3288-vyasa.dts                 |  11 +
+ arch/arm64/boot/dts/rockchip/Makefile              |   2 +
+ arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts     | 267 +++++++++++++++++
+ arch/arm64/boot/dts/rockchip/rk3328-rock64.dts     |   7 +-
+ arch/arm64/boot/dts/rockchip/rk3328.dtsi           |  12 +-
+ .../arm64/boot/dts/rockchip/rk3368-lion-haikou.dts | 146 ++++++++++
+ arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi      | 317 +++++++++++++++++++++
+ arch/arm64/boot/dts/rockchip/rk3368.dtsi           |   2 +-
+ arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       |   7 +-
+ .../arm64/boot/dts/rockchip/rk3399-puma-haikou.dts |  71 ++++-
+ arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi      |  28 ++
+ arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi  |  24 +-
+ arch/arm64/boot/dts/rockchip/rk3399.dtsi           |  77 ++++-
+ drivers/clk/rockchip/clk-rk3328.c                  |  67 +++--
+ drivers/soc/rockchip/grf.c                         |  14 +
+ include/dt-bindings/clock/rk3328-cru.h             |   1 -
+ 25 files changed, 1061 insertions(+), 90 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
+ create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
+ create mode 100644 arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
+Merging samsung/for-next (bebc6082da0a Linux 4.14)
+$ git merge samsung/for-next
+Already up to date.
+Merging samsung-krzk/for-next (f9b2bb6c0ee0 Merge branch 'next/dt' into for-next)
+$ git merge samsung-krzk/for-next
+Removing arch/arm/boot/dts/samsung_k3pe0e000b.dtsi
+Auto-merging arch/arm/boot/dts/Makefile
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/arm/samsung/pmu.txt        |    6 +
+ .../bindings/arm/samsung/samsung-boards.txt        |    4 +
+ MAINTAINERS                                        |    1 -
+ arch/arm/boot/dts/Makefile                         |    3 +
+ arch/arm/boot/dts/exynos-mfc-reserved-memory.dtsi  |    5 +-
+ arch/arm/boot/dts/exynos-syscon-restart.dtsi       |    5 +-
+ arch/arm/boot/dts/exynos3250-artik5.dtsi           |   36 +
+ arch/arm/boot/dts/exynos4.dtsi                     | 1723 +++++++++---------
+ arch/arm/boot/dts/exynos4210-pinctrl.dtsi          | 1680 +++++++++--------
+ arch/arm/boot/dts/exynos4210-trats.dts             |   73 +-
+ arch/arm/boot/dts/exynos4210-universal_c210.dts    |  115 +-
+ arch/arm/boot/dts/exynos4210.dtsi                  |  606 +++----
+ arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi        |  140 ++
+ arch/arm/boot/dts/exynos4412-i9300.dts             |   22 +
+ arch/arm/boot/dts/exynos4412-i9305.dts             |   20 +
+ arch/arm/boot/dts/exynos4412-itop-elite.dts        |   16 +-
+ arch/arm/boot/dts/exynos4412-midas.dtsi            | 1308 +++++++++++++
+ arch/arm/boot/dts/exynos4412-n710x.dts             |   57 +
+ arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |   12 +-
+ arch/arm/boot/dts/exynos4412-pinctrl.dtsi          | 1914 ++++++++++----------
+ arch/arm/boot/dts/exynos4412-tiny4412.dts          |    7 +-
+ arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi  |    6 +-
+ arch/arm/boot/dts/exynos4412-trats2.dts            | 1396 +-------------
+ arch/arm/boot/dts/exynos4412.dtsi                  |  868 ++++-----
+ arch/arm/boot/dts/exynos5250.dtsi                  |    2 -
+ arch/arm/boot/dts/exynos5410.dtsi                  |    1 -
+ arch/arm/boot/dts/exynos5420-cpus.dtsi             |   16 -
+ arch/arm/boot/dts/exynos5422-cpus.dtsi             |   16 -
+ arch/arm/boot/dts/exynos5440.dtsi                  |  514 +++---
+ arch/arm/boot/dts/exynos5800-peach-pi.dts          |    5 +-
+ arch/arm/boot/dts/exynos5800.dtsi                  |    5 +-
+ arch/arm/boot/dts/samsung_k3pe0e000b.dtsi          |   68 -
+ arch/arm/include/debug/exynos.S                    |    7 +-
+ arch/arm/include/debug/samsung.S                   |   10 +-
+ arch/arm/mach-exynos/exynos.c                      |    3 +-
+ .../boot/dts/exynos/exynos5433-tm2-common.dtsi     |   52 +-
+ arch/arm64/boot/dts/exynos/exynos5433.dtsi         |   24 +-
+ drivers/memory/samsung/Kconfig                     |    1 +
+ drivers/memory/samsung/Makefile                    |    1 +
+ drivers/memory/samsung/exynos-srom.c               |   18 +-
+ drivers/memory/samsung/exynos-srom.h               |    7 +-
+ drivers/soc/samsung/exynos-pmu.c                   |    7 +
+ include/linux/serial_s3c.h                         |   17 +-
+ include/linux/soc/samsung/exynos-pmu.h             |    5 +-
+ include/linux/soc/samsung/exynos-regs-pmu.h        |    6 +-
+ 45 files changed, 5483 insertions(+), 5325 deletions(-)
+ create mode 100644 arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
+ create mode 100644 arch/arm/boot/dts/exynos4412-i9300.dts
+ create mode 100644 arch/arm/boot/dts/exynos4412-i9305.dts
+ create mode 100644 arch/arm/boot/dts/exynos4412-midas.dtsi
+ create mode 100644 arch/arm/boot/dts/exynos4412-n710x.dts
+ delete mode 100644 arch/arm/boot/dts/samsung_k3pe0e000b.dtsi
+Merging sunxi/sunxi/for-next (017b7e4e23ff Merge branch 'sunxi/dt-for-4.17' into sunxi/for-next)
+$ git merge sunxi/sunxi/for-next
+Auto-merging arch/arm/boot/dts/Makefile
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/arm/sunxi/smp-sram.txt     |  44 ++
+ MAINTAINERS                                        |   4 +-
+ arch/arm/boot/dts/Makefile                         |   3 +
+ arch/arm/boot/dts/sun4i-a10-a1000.dts              |   3 +-
+ arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts         |   3 +-
+ arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts    |   3 +-
+ arch/arm/boot/dts/sun4i-a10-cubieboard.dts         |   3 +-
+ arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts   |   3 +-
+ arch/arm/boot/dts/sun4i-a10-gemei-g9.dts           |   3 +-
+ arch/arm/boot/dts/sun4i-a10-hackberry.dts          |   3 +-
+ arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts       |   3 +-
+ arch/arm/boot/dts/sun4i-a10-inet1.dts              |   3 +-
+ arch/arm/boot/dts/sun4i-a10-inet97fv2.dts          |   3 +-
+ arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts       |   3 +-
+ .../boot/dts/sun4i-a10-itead-iteaduino-plus.dts    |   3 +-
+ arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts         |   3 +-
+ arch/arm/boot/dts/sun4i-a10-marsboard.dts          |   3 +-
+ arch/arm/boot/dts/sun4i-a10-mini-xplus.dts         |   3 +-
+ arch/arm/boot/dts/sun4i-a10-mk802.dts              |  28 +-
+ arch/arm/boot/dts/sun4i-a10-mk802ii.dts            |   3 +-
+ arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts     |   4 +-
+ arch/arm/boot/dts/sun4i-a10-pcduino.dts            |   3 +-
+ arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts   |   3 +-
+ arch/arm/boot/dts/sun4i-a10.dtsi                   |   2 -
+ arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts       |   3 +-
+ arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts       |   3 +-
+ arch/arm/boot/dts/sun5i-a10s-mk802.dts             |   3 +-
+ arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts   |   6 +-
+ arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts      |   3 +-
+ arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts           |   3 +-
+ .../boot/dts/sun5i-a13-empire-electronix-d709.dts  |   3 +-
+ arch/arm/boot/dts/sun5i-a13-hsg-h702.dts           |   3 +-
+ arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts    |   3 +-
+ arch/arm/boot/dts/sun5i-a13-olinuxino.dts          |   3 +-
+ arch/arm/boot/dts/sun5i-a13.dtsi                   |   2 -
+ arch/arm/boot/dts/sun5i-gr8-evb.dts                |   3 +-
+ .../boot/dts/sun5i-reference-design-tablet.dtsi    |   3 +-
+ arch/arm/boot/dts/sun6i-a31-colombus.dts           |   3 +-
+ arch/arm/boot/dts/sun6i-a31-hummingbird.dts        |   3 +-
+ arch/arm/boot/dts/sun6i-a31-i7.dts                 |  32 +-
+ arch/arm/boot/dts/sun6i-a31-m9.dts                 |   3 +-
+ arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts   |   3 +-
+ arch/arm/boot/dts/sun6i-a31.dtsi                   |   2 -
+ arch/arm/boot/dts/sun6i-a31s-primo81.dts           |   3 +-
+ arch/arm/boot/dts/sun6i-a31s-sina31s.dts           |   3 +-
+ arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts   |  66 +-
+ .../dts/sun6i-a31s-yones-toptech-bs1078-v2.dts     |   3 +-
+ .../boot/dts/sun6i-reference-design-tablet.dtsi    |   3 +-
+ arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts   |   3 +-
+ arch/arm/boot/dts/sun7i-a20-bananapi.dts           |  28 +-
+ arch/arm/boot/dts/sun7i-a20-bananapro.dts          |   3 +-
+ arch/arm/boot/dts/sun7i-a20-cubieboard2.dts        |   3 +-
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts         |   3 +-
+ arch/arm/boot/dts/sun7i-a20-hummingbird.dts        |   3 +-
+ arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts          |   3 +-
+ arch/arm/boot/dts/sun7i-a20-icnova-swac.dts        |   3 +-
+ arch/arm/boot/dts/sun7i-a20-itead-ibox.dts         |   3 +-
+ arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts          |   3 +-
+ arch/arm/boot/dts/sun7i-a20-m3.dts                 |   3 +-
+ arch/arm/boot/dts/sun7i-a20-mk808c.dts             |  28 +-
+ arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts     |  31 +-
+ .../boot/dts/sun7i-a20-olimex-som204-evb-emmc.dts  |  36 +
+ arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts  | 335 +++++++++
+ arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts     |   3 +-
+ arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts    |   3 +-
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts    |   6 +-
+ arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts      |  31 +-
+ arch/arm/boot/dts/sun7i-a20-orangepi.dts           |   3 +-
+ arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts      |   3 +-
+ arch/arm/boot/dts/sun7i-a20-pcduino3.dts           |   3 +-
+ arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts     |   3 +-
+ arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts   |   3 +-
+ arch/arm/boot/dts/sun7i-a20.dtsi                   |  29 +-
+ arch/arm/boot/dts/sun8i-a23-evb.dts                |   3 +-
+ arch/arm/boot/dts/sun8i-a33-olinuxino.dts          |   3 +-
+ arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts     |   3 +-
+ arch/arm/boot/dts/sun8i-a33.dtsi                   |   1 -
+ .../boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts  |   3 +-
+ arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts       |  42 +-
+ arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts   |   3 +-
+ arch/arm/boot/dts/sun8i-a83t.dtsi                  | 108 ++-
+ .../boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts    | 121 ++++
+ arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts    |   8 +
+ arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts  |  11 +-
+ arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts    |   7 +-
+ arch/arm/boot/dts/sun8i-h3-beelink-x2.dts          |   7 +-
+ arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts |   5 +-
+ arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts      |   2 -
+ arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts      |  27 +-
+ arch/arm/boot/dts/sun8i-h3-nanopi.dtsi             |   5 +-
+ arch/arm/boot/dts/sun8i-h3-orangepi-2.dts          |   7 +-
+ arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts       |   7 +-
+ arch/arm/boot/dts/sun8i-h3-orangepi-one.dts        |   5 +-
+ arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts    |   2 -
+ arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts         |   5 +-
+ arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts       |   3 +-
+ arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts  |   3 +-
+ .../boot/dts/sun8i-reference-design-tablet.dtsi    |   3 +-
+ arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts  |   3 +-
+ arch/arm/boot/dts/sun9i-a80-cubieboard4.dts        |   3 +-
+ arch/arm/boot/dts/sun9i-a80-optimus.dts            |   3 +-
+ arch/arm/boot/dts/sun9i-a80.dtsi                   |  75 ++
+ arch/arm/boot/dts/sunxi-h3-h5.dtsi                 |  14 +-
+ arch/arm/mach-sunxi/Kconfig                        |   7 +
+ arch/arm/mach-sunxi/Makefile                       |   1 +
+ arch/arm/mach-sunxi/mc_smp.c                       | 791 +++++++++++++++++++++
+ .../boot/dts/allwinner/sun50i-a64-bananapi-m64.dts |   3 +-
+ .../boot/dts/allwinner/sun50i-a64-nanopi-a64.dts   |   3 +-
+ .../boot/dts/allwinner/sun50i-a64-olinuxino.dts    |   3 +-
+ .../boot/dts/allwinner/sun50i-a64-orangepi-win.dts |   3 +-
+ .../arm64/boot/dts/allwinner/sun50i-a64-pine64.dts |   8 +-
+ arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi      |  67 ++
+ .../dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts   |   4 -
+ .../boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts   |   2 -
+ .../boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts  |   2 -
+ .../dts/allwinner/sun50i-h5-orangepi-prime.dts     |   4 -
+ .../allwinner/sun50i-h5-orangepi-zero-plus2.dts    |   4 -
+ drivers/clk/sunxi-ng/Kconfig                       |   7 -
+ drivers/clk/sunxi-ng/ccu-sun6i-a31.c               |   6 +-
+ drivers/clk/sunxi-ng/ccu_nkmp.c                    |  42 +-
+ 120 files changed, 2037 insertions(+), 291 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt
+ create mode 100644 arch/arm/boot/dts/sun7i-a20-olimex-som204-evb-emmc.dts
+ create mode 100644 arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts
+ create mode 100644 arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
+ create mode 100644 arch/arm/mach-sunxi/mc_smp.c
+Merging tegra/for-next (983371acdeda Merge branch for-4.16/arm64/dt into for-next)
+$ git merge tegra/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging arm64/for-next/core (3a0a397ff5ff arm64: Kill PSCI_GET_VERSION as a variant-2 workaround)
+$ git merge arm64/for-next/core
+Already up to date.
+Merging clk/clk-next (c43a52cfd27b Merge branches 'clk-aspeed', 'clk-lock-UP', 'clk-mediatek' and 'clk-allwinner' into clk-next)
+$ git merge clk/clk-next
+Already up to date.
+Merging clk-samsung/for-next (83942bdd992f clk: exynos5433: Extend list of available AUD_PLL output frequencies)
+$ git merge clk-samsung/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                            |  1 +
+ drivers/clk/samsung/clk-exynos-audss.c |  4 +---
+ drivers/clk/samsung/clk-exynos5433.c   |  7 +++----
+ drivers/clk/samsung/clk-s3c2412.c      | 11 ++---------
+ drivers/clk/samsung/clk-s3c2443.c      | 17 ++++-------------
+ drivers/clk/samsung/clk-s3c64xx.c      | 17 ++++++-----------
+ 6 files changed, 17 insertions(+), 40 deletions(-)
+Merging c6x/for-linux-next (9d440f7a2824 c6x: fix platforms/plldata.c get_coreid build error)
+$ git merge c6x/for-linux-next
+Auto-merging arch/c6x/kernel/asm-offsets.c
+Merge made by the 'recursive' strategy.
+ arch/c6x/kernel/asm-offsets.c | 1 -
+ arch/c6x/platforms/plldata.c  | 1 +
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+Merging cris/for-next (fd989db807a0 cris: Fix conflicting types for _etext, _edata, _end)
+$ git merge cris/for-next
+Already up to date.
+Merging m68k/for-next (2334b1ac1235 MAINTAINERS: Add NuBus subsystem entry)
+$ git merge m68k/for-next
+Already up to date.
+Merging m68knommu/for-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge m68knommu/for-next
+Already up to date.
+Merging metag/for-next (e3cd7f013bac metag/mm: Drop pointless increment)
+$ git merge metag/for-next
+Already up to date.
+Merging microblaze/next (f1517df8701c Merge tag 'nfsd-4.16' of git://linux-nfs.org/~bfields/linux)
+$ git merge microblaze/next
+Already up to date.
+Merging mips/mips-next (ea4d340cbea4 Merge branches '4.15-fixes', '4.16-features' and 'octeon-3-net-mips-bits' into mips-next)
+$ git merge mips/mips-next
+Auto-merging drivers/staging/octeon/ethernet-tx.c
+Auto-merging drivers/staging/octeon/ethernet-rx.c
+Auto-merging drivers/staging/octeon/ethernet-defines.h
+Auto-merging arch/mips/include/asm/mipsregs.h
+Auto-merging arch/mips/cavium-octeon/Kconfig
+Merge made by the 'recursive' strategy.
+ arch/mips/cavium-octeon/Kconfig                    |  27 +-
+ arch/mips/cavium-octeon/Makefile                   |   1 +
+ arch/mips/cavium-octeon/resource-mgr.c             | 351 +++++++++++++++++++++
+ arch/mips/cavium-octeon/setup.c                    |  22 +-
+ arch/mips/include/asm/barrier.h                    |   2 +-
+ .../asm/mach-cavium-octeon/kernel-entry-init.h     |  20 +-
+ arch/mips/include/asm/mipsregs.h                   |   2 +
+ arch/mips/include/asm/octeon/octeon.h              |  32 +-
+ arch/mips/include/asm/processor.h                  |   2 +-
+ arch/mips/kernel/octeon_switch.S                   |   2 -
+ arch/mips/mm/tlbex.c                               |  29 +-
+ drivers/staging/octeon/ethernet-defines.h          |   6 -
+ drivers/staging/octeon/ethernet-rx.c               |  25 +-
+ drivers/staging/octeon/ethernet-tx.c               |  85 ++---
+ 14 files changed, 473 insertions(+), 133 deletions(-)
+ create mode 100644 arch/mips/cavium-octeon/resource-mgr.c
+Merging mips-james/mips-next (35868f095948 MIPS: generic: Enable crc32-mips on r6 configs)
+$ git merge mips-james/mips-next
+Auto-merging arch/mips/include/asm/mipsregs.h
+Merge made by the 'recursive' strategy.
+ arch/mips/Kconfig                     |   4 +
+ arch/mips/Makefile                    |   3 +
+ arch/mips/alchemy/board-gpr.c         |   2 +-
+ arch/mips/alchemy/board-mtx1.c        |   2 +-
+ arch/mips/ar7/platform.c              |  14 +-
+ arch/mips/boot/dts/img/boston.dts     |   2 +-
+ arch/mips/boot/dts/ingenic/ci20.dts   |   8 +-
+ arch/mips/cavium-octeon/octeon-irq.c  |  10 +-
+ arch/mips/configs/bmips_stb_defconfig |   1 +
+ arch/mips/configs/generic/32r6.config |   2 +
+ arch/mips/configs/generic/64r6.config |   2 +
+ arch/mips/crypto/Makefile             |   6 +
+ arch/mips/crypto/crc32-mips.c         | 348 ++++++++++++++++++++++++++++++++++
+ arch/mips/include/asm/mipsregs.h      |   1 +
+ arch/mips/include/uapi/asm/hwcap.h    |   1 +
+ arch/mips/kernel/cpu-probe.c          |   3 +
+ arch/mips/kernel/setup.c              |   5 +-
+ arch/mips/mm/init.c                   |   2 -
+ arch/mips/txx9/rbtx4927/setup.c       |   2 +-
+ crypto/Kconfig                        |   9 +
+ 20 files changed, 403 insertions(+), 24 deletions(-)
+ create mode 100644 arch/mips/crypto/Makefile
+ create mode 100644 arch/mips/crypto/crc32-mips.c
+Merging nios2/for-next (e0691ebb33c1 nios2: defconfig: Cleanup from old Kconfig options)
+$ git merge nios2/for-next
+Already up to date.
+Merging openrisc/for-next (0fedb7653af7 openrisc: remove unused __ARCH_HAVE_MMU define)
+$ git merge openrisc/for-next
+Merge made by the 'recursive' strategy.
+ arch/openrisc/include/uapi/asm/unistd.h | 2 --
+ 1 file changed, 2 deletions(-)
+Merging parisc-hd/for-next (a156e659f2d2 parisc: Reduce irq overhead when run in qemu)
+$ git merge parisc-hd/for-next
+Merge made by the 'recursive' strategy.
+ arch/parisc/include/asm/cacheflush.h |  1 +
+ arch/parisc/include/asm/processor.h  |  2 ++
+ arch/parisc/kernel/cache.c           | 51 ++++++++++++++++++++----------------
+ arch/parisc/kernel/head.S            | 18 ++++++++-----
+ arch/parisc/kernel/pacache.S         | 22 ++++++++++++++++
+ arch/parisc/kernel/smp.c             |  7 ++++-
+ arch/parisc/kernel/time.c            | 11 ++++----
+ arch/parisc/mm/init.c                |  7 ++++-
+ 8 files changed, 84 insertions(+), 35 deletions(-)
+Merging powerpc/next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge powerpc/next
+Already up to date.
+Merging fsl/next (c095ff93f901 powerpc/sysdev: change CPM GPIO to platform_device)
+$ git merge fsl/next
+Already up to date.
+Merging risc-v/for-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge risc-v/for-next
+Already up to date.
+Merging s390/features (c3ec23b80192 s390/sclp: Add support for Store Data SCLP interface)
+$ git merge s390/features
+Merge made by the 'recursive' strategy.
+ arch/s390/include/asm/pgalloc.h  |   3 +
+ arch/s390/kernel/nospec-branch.c |   4 +-
+ arch/s390/mm/pgalloc.c           | 293 +++++++++++++++++++-
+ drivers/s390/block/dasd.c        |  21 +-
+ drivers/s390/char/Makefile       |   2 +-
+ drivers/s390/char/sclp.h         |   2 +
+ drivers/s390/char/sclp_sd.c      | 569 +++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 876 insertions(+), 18 deletions(-)
+ create mode 100644 drivers/s390/char/sclp_sd.c
+Merging sparc-next/master (8e44e6600caa Merge branch 'KASAN-read_word_at_a_time')
+$ git merge sparc-next/master
+Already up to date.
+Merging sh/for-next (6e2fbfdd585f sh: fix futex FUTEX_OP_SET op on userspace addresses)
+$ git merge sh/for-next
+Auto-merging arch/sh/include/asm/futex.h
+Merge made by the 'recursive' strategy.
+ arch/sh/include/asm/futex.h | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+Merging uml/linux-next (584bfe635481 um: vector: Fix an error handling path in 'vector_parse()')
+$ git merge uml/linux-next
+Merge made by the 'recursive' strategy.
+ arch/um/Kconfig.net                  |   11 +
+ arch/um/drivers/Makefile             |    4 +-
+ arch/um/drivers/chan_kern.c          |   53 +-
+ arch/um/drivers/line.c               |    2 +-
+ arch/um/drivers/net_kern.c           |    4 +-
+ arch/um/drivers/random.c             |   11 +-
+ arch/um/drivers/ubd_kern.c           |    4 +-
+ arch/um/drivers/vector_kern.c        | 1632 ++++++++++++++++++++++++++++++++++
+ arch/um/drivers/vector_kern.h        |  129 +++
+ arch/um/drivers/vector_transports.c  |  458 ++++++++++
+ arch/um/drivers/vector_user.c        |  586 ++++++++++++
+ arch/um/drivers/vector_user.h        |   99 +++
+ arch/um/include/asm/asm-prototypes.h |    1 +
+ arch/um/include/asm/irq.h            |   12 +
+ arch/um/include/shared/irq_user.h    |   12 +-
+ arch/um/include/shared/net_kern.h    |    2 +
+ arch/um/include/shared/os.h          |   17 +-
+ arch/um/kernel/irq.c                 |  461 ++++++----
+ arch/um/kernel/time.c                |    6 +-
+ arch/um/os-Linux/irq.c               |  202 +++--
+ arch/um/os-Linux/signal.c            |    2 +-
+ arch/x86/um/stub_segv.c              |    2 +-
+ 22 files changed, 3385 insertions(+), 325 deletions(-)
+ create mode 100644 arch/um/drivers/vector_kern.c
+ create mode 100644 arch/um/drivers/vector_kern.h
+ create mode 100644 arch/um/drivers/vector_transports.c
+ create mode 100644 arch/um/drivers/vector_user.c
+ create mode 100644 arch/um/drivers/vector_user.h
+ create mode 100644 arch/um/include/asm/asm-prototypes.h
+Merging xtensa/xtensa-for-next (ae6063c83634 Merge branch 'xtensa-fixes' into xtensa-for-next)
+$ git merge xtensa/xtensa-for-next
+Merge made by the 'recursive' strategy.
+ arch/xtensa/kernel/pci-dma.c | 46 ++++++++++++++++++++++-------
+ arch/xtensa/mm/init.c        | 70 +++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 99 insertions(+), 17 deletions(-)
+Merging fscrypt/master (0b1dfa4cc6c6 fscrypt: fix build with pre-4.6 gcc versions)
+$ git merge fscrypt/master
+Already up to date.
+Merging befs/for-next (55d945e2e4aa fs: befs: btree: Fixed some coding standard issues)
+$ git merge befs/for-next
+Merge made by the 'recursive' strategy.
+ fs/befs/btree.c | 97 ++++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 51 insertions(+), 46 deletions(-)
+Merging btrfs/next (7c9a09f56a91 btrfs: don't use async helpers for crcs when under IO limits)
+$ git merge btrfs/next
+Auto-merging kernel/cgroup/cgroup.c
+Auto-merging include/linux/fs.h
+Auto-merging include/linux/buffer_head.h
+Auto-merging include/linux/backing-dev.h
+Auto-merging fs/ext4/super.c
+Auto-merging fs/ext4/inode.c
+Auto-merging fs/ext2/super.c
+Auto-merging fs/buffer.c
+Auto-merging fs/btrfs/super.c
+Auto-merging fs/btrfs/ioctl.c
+Auto-merging fs/btrfs/inode.c
+Auto-merging fs/btrfs/disk-io.c
+Merge made by the 'recursive' strategy.
+ block/blk-cgroup.c          |  1 +
+ fs/block_dev.c              |  3 +--
+ fs/btrfs/check-integrity.c  |  2 +-
+ fs/btrfs/disk-io.c          |  4 ++++
+ fs/btrfs/inode.c            | 15 ++++++++++++---
+ fs/btrfs/ioctl.c            |  8 +++++++-
+ fs/btrfs/super.c            |  1 -
+ fs/buffer.c                 | 42 ++++++++++++++++++++++++++++++++++--------
+ fs/ext2/inode.c             |  3 ++-
+ fs/ext2/super.c             |  1 -
+ fs/ext4/inode.c             |  4 +++-
+ fs/ext4/super.c             |  2 --
+ include/linux/backing-dev.h |  2 +-
+ include/linux/buffer_head.h |  3 +++
+ include/linux/fs.h          |  3 ++-
+ kernel/cgroup/cgroup.c      |  1 +
+ 16 files changed, 72 insertions(+), 23 deletions(-)
+$ git am -3 ../patches/0001-f2fs-fixup-for-cgroup-writeback-change.patch
+Applying: f2fs: fixup for cgroup/writeback change
+$ git reset HEAD^
+Unstaged changes after reset:
+M	fs/f2fs/inode.c
+M	fs/f2fs/super.c
+$ git add -A .
+$ git commit -v -a --amend
+[master b7cbe4c77997] Merge remote-tracking branch 'btrfs/next'
+ Date: Tue Feb 20 08:53:27 2018 +1100
+Merging btrfs-kdave/for-next (6537ffbd6382 Merge branch 'for-next-next-v4.16-20180213' into for-next-20180213)
+$ git merge btrfs-kdave/for-next
+Resolved 'fs/btrfs/disk-io.c' using previous resolution.
+Resolved 'fs/btrfs/tree-log.c' using previous resolution.
+Auto-merging fs/btrfs/tree-log.c
+CONFLICT (content): Merge conflict in fs/btrfs/tree-log.c
+Auto-merging fs/btrfs/super.c
+Auto-merging fs/btrfs/ioctl.c
+Auto-merging fs/btrfs/inode.c
+Removing fs/btrfs/hash.h
+Removing fs/btrfs/hash.c
+Auto-merging fs/btrfs/free-space-cache.c
+Auto-merging fs/btrfs/file.c
+Auto-merging fs/btrfs/extent_io.h
+Auto-merging fs/btrfs/extent_io.c
+Auto-merging fs/btrfs/disk-io.c
+CONFLICT (content): Merge conflict in fs/btrfs/disk-io.c
+Auto-merging fs/btrfs/delayed-inode.c
+Auto-merging fs/btrfs/compression.c
+Auto-merging fs/btrfs/check-integrity.c
+Auto-merging fs/btrfs/Kconfig
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 6b404579a2bcf07c5dd657f3c6aaf575d3e9c9ae] Merge remote-tracking branch 'btrfs-kdave/for-next'
+$ git diff -M --stat --summary HEAD^..
+ fs/btrfs/Kconfig                  |   3 +-
+ fs/btrfs/Makefile                 |   2 +-
+ fs/btrfs/btrfs_inode.h            |   1 -
+ fs/btrfs/check-integrity.c        |   4 +-
+ fs/btrfs/compression.c            |  21 ++-
+ fs/btrfs/ctree.h                  |  50 +++--
+ fs/btrfs/delayed-inode.c          |  64 ++++---
+ fs/btrfs/delayed-inode.h          |   6 +-
+ fs/btrfs/dev-replace.c            |  29 +--
+ fs/btrfs/dev-replace.h            |   3 +-
+ fs/btrfs/dir-item.c               |   1 -
+ fs/btrfs/disk-io.c                |  48 ++---
+ fs/btrfs/extent-tree.c            | 159 +++++++---------
+ fs/btrfs/extent_io.c              |   9 +-
+ fs/btrfs/extent_io.h              |   6 +-
+ fs/btrfs/extent_map.c             |   3 +
+ fs/btrfs/file.c                   |  23 +--
+ fs/btrfs/free-space-cache.c       |   2 +-
+ fs/btrfs/free-space-tree.c        |   4 +-
+ fs/btrfs/hash.c                   |  54 ------
+ fs/btrfs/hash.h                   |  43 -----
+ fs/btrfs/inode-item.c             |   1 -
+ fs/btrfs/inode-map.c              |   4 +-
+ fs/btrfs/inode.c                  | 142 +++++++++-----
+ fs/btrfs/ioctl.c                  | 128 +++----------
+ fs/btrfs/ordered-data.c           |   2 +-
+ fs/btrfs/ordered-data.h           |   4 +-
+ fs/btrfs/props.c                  |   4 +-
+ fs/btrfs/qgroup.c                 | 386 +++++++++++++++++++++++++++-----------
+ fs/btrfs/qgroup.h                 | 102 +++++++++-
+ fs/btrfs/relocation.c             |  27 ++-
+ fs/btrfs/scrub.c                  |  11 +-
+ fs/btrfs/send.c                   |  33 +++-
+ fs/btrfs/super.c                  | 102 ++++------
+ fs/btrfs/tests/btrfs-tests.c      |   3 +-
+ fs/btrfs/tests/extent-map-tests.c |   2 +-
+ fs/btrfs/transaction.c            | 184 +++++++++---------
+ fs/btrfs/transaction.h            |  25 ++-
+ fs/btrfs/tree-checker.c           | 148 ++++++++-------
+ fs/btrfs/tree-checker.h           |   7 +-
+ fs/btrfs/tree-log.c               |  14 +-
+ fs/btrfs/volumes.c                |  79 +++++---
+ fs/btrfs/volumes.h                |  27 ++-
+ fs/btrfs/zstd.c                   |  19 +-
+ include/linux/crc32c.h            |   1 +
+ include/trace/events/btrfs.h      | 108 ++++++++++-
+ lib/libcrc32c.c                   |   6 +
+ 47 files changed, 1189 insertions(+), 915 deletions(-)
+ delete mode 100644 fs/btrfs/hash.c
+ delete mode 100644 fs/btrfs/hash.h
+Merging ceph/master (16515a6d5418 ceph: improving efficiency of syncfs)
+$ git merge ceph/master
+Already up to date.
+Merging cifs/for-next (1c6614d229e7 CIFS: add sha512 secmech)
+$ git merge cifs/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/filesystems/cifs/README | 29 +++++------
+ Documentation/filesystems/cifs/TODO   | 25 +++++----
+ fs/cifs/Kconfig                       |  1 +
+ fs/cifs/cifsencrypt.c                 | 85 +++++-------------------------
+ fs/cifs/cifsfs.c                      |  1 +
+ fs/cifs/cifsglob.h                    |  2 +
+ fs/cifs/cifsproto.h                   |  5 ++
+ fs/cifs/link.c                        | 27 +++-------
+ fs/cifs/misc.c                        | 54 +++++++++++++++++++
+ fs/cifs/smb2pdu.c                     |  8 ++-
+ fs/cifs/smb2proto.h                   |  3 ++
+ fs/cifs/smb2transport.c               | 97 +++++++++++++++--------------------
+ fs/cifs/smbdirect.c                   |  4 +-
+ fs/cifs/smbencrypt.c                  | 27 +++-------
+ 14 files changed, 168 insertions(+), 200 deletions(-)
+Merging configfs/for-next (6ace4f6bbcfd RDMA/cma: make config_item_type const)
+$ git merge configfs/for-next
+Already up to date.
+Merging ecryptfs/next (4670269faba7 eCryptfs: constify attribute_group structures.)
+$ git merge ecryptfs/next
+Already up to date.
+Merging ext3/for_next (1d37d05f3c2c udf: Fix handling of Partition Descriptors)
+$ git merge ext3/for_next
+Merge made by the 'recursive' strategy.
+ fs/notify/inotify/inotify_user.c |  14 +++
+ fs/udf/super.c                   | 194 ++++++++++++++++++++++-----------------
+ include/uapi/linux/inotify.h     |   8 ++
+ 3 files changed, 132 insertions(+), 84 deletions(-)
+Merging ext4/dev (5dc397113d19 ext4: create ext4_kset dynamically)
+$ git merge ext4/dev
+Already up to date.
+Merging f2fs/dev (1c1d35df7110 f2fs: support inode creation time)
+$ git merge f2fs/dev
+Already up to date.
+Merging fuse/for-next (c6cdd51404b7 fuse: fix READDIRPLUS skipping an entry)
+$ git merge fuse/for-next
+Already up to date.
+Merging jfs/jfs-next (86313903430d MAINTAINERS: fix jfs tree location)
+$ git merge jfs/jfs-next
+Already up to date.
+Merging nfs/linux-next (91ab883eb213 Linux 4.16-rc2)
+$ git merge nfs/linux-next
+Already up to date.
+Merging nfs-anna/linux-next (c54c14ba000d xprtrdma: Spread reply processing over more CPUs)
+$ git merge nfs-anna/linux-next
+Resolved 'net/sunrpc/xprt.c' using previous resolution.
+Resolved 'net/sunrpc/xprtrdma/transport.c' using previous resolution.
+Auto-merging net/sunrpc/xprtrdma/transport.c
+CONFLICT (content): Merge conflict in net/sunrpc/xprtrdma/transport.c
+Auto-merging net/sunrpc/xprt.c
+CONFLICT (content): Merge conflict in net/sunrpc/xprt.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 938fc97c0060] Merge remote-tracking branch 'nfs-anna/linux-next'
+$ git diff -M --stat --summary HEAD^..
+Merging nfsd/nfsd-next (175e03101d36 svcrdma: Fix Read chunk round-up)
+$ git merge nfsd/nfsd-next
+Already up to date.
+Merging orangefs/for-next (74e938c22705 orangefs: reverse sense of is-inode-stale test in d_revalidate)
+$ git merge orangefs/for-next
+Already up to date.
+Merging overlayfs/overlayfs-next (7168179fcf25 ovl: check ERR_PTR() return value from ovl_lookup_real())
+$ git merge overlayfs/overlayfs-next
+Merge made by the 'recursive' strategy.
+ fs/overlayfs/export.c    | 214 +++++++++++++++++++++++++++++++++++++----------
+ fs/overlayfs/inode.c     |  58 +++++++++----
+ fs/overlayfs/overlayfs.h |   1 +
+ fs/overlayfs/super.c     |   1 +
+ 4 files changed, 210 insertions(+), 64 deletions(-)
+Merging ubifs/linux-next (7f29ae9f977b ubi: block: Fix locking for idr_alloc/idr_remove)
+$ git merge ubifs/linux-next
+Already up to date.
+Merging xfs/for-next (76883f7988e6 xfs: remove experimental tag for reverse mapping)
+$ git merge xfs/for-next
+Already up to date.
+Merging file-locks/locks-next (1deab8ce2c91 Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc)
+$ git merge file-locks/locks-next
+Already up to date.
+Merging vfs/for-next (d85e2aa2e34d annotate ep_scan_ready_list())
+$ git merge vfs/for-next
+Already up to date.
+Merging vfs-miklos/next (0eb8af4916a5 vfs: use helper for calling f_op->fsync())
+$ git merge vfs-miklos/next
+Already up to date.
+Merging iversion/iversion-next (581e400ff935 Merge tag 'modules-for-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux)
+$ git merge iversion/iversion-next
+Already up to date.
+Merging printk/for-next (02fffdcaed19 Merge branch 'for-4.17' into for-next)
+$ git merge printk/for-next
+Auto-merging kernel/printk/printk.c
+Merge made by the 'recursive' strategy.
+ kernel/printk/printk.c | 24 ++++++++++++++----------
+ lib/vsprintf.c         |  2 +-
+ 2 files changed, 15 insertions(+), 11 deletions(-)
+Merging pci/next (c8989cd7ece7 Merge branch 'pci/sparc' into next)
+$ git merge pci/next
+Auto-merging drivers/gpu/drm/i915/i915_drv.c
+Merge made by the 'recursive' strategy.
+ arch/sparc/kernel/pci.c          |  6 ++---
+ arch/sparc/kernel/pci_common.c   | 54 +++++++++++++++++++---------------------
+ arch/sparc/kernel/pci_impl.h     |  4 +++
+ arch/sparc/mm/init_64.c          | 17 +++++++++++++
+ drivers/gpu/drm/i915/i915_drv.c  |  5 +++-
+ drivers/rapidio/devices/tsi721.c |  5 ++--
+ include/linux/pci.h              |  8 ------
+ 7 files changed, 57 insertions(+), 42 deletions(-)
+Merging pstore/for-next/pstore (a99f41a1b441 fs: pstore: remove unused hardirq.h)
+$ git merge pstore/for-next/pstore
+Already up to date.
+Merging hid/for-next (ba6986149ce3 Merge branch 'for-4.16/upstream-fixes' into for-next)
+$ git merge hid/for-next
+Auto-merging drivers/hid/uhid.c
+Auto-merging drivers/hid/hid-quirks.c
+Auto-merging drivers/hid/hid-ids.h
+Merge made by the 'recursive' strategy.
+ drivers/hid/Kconfig           |   8 +
+ drivers/hid/Makefile          |   1 +
+ drivers/hid/hid-asus.c        |   4 +-
+ drivers/hid/hid-core.c        |  10 +-
+ drivers/hid/hid-corsair.c     |  24 ++-
+ drivers/hid/hid-elan.c        | 421 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/hid/hid-ids.h         |   2 +
+ drivers/hid/hid-input.c       |   3 +-
+ drivers/hid/hid-multitouch.c  |   5 +-
+ drivers/hid/hid-quirks.c      |   5 +
+ drivers/hid/hid-rmi.c         |   4 +-
+ drivers/hid/i2c-hid/i2c-hid.c |  17 +-
+ drivers/hid/uhid.c            |  12 +-
+ drivers/hid/wacom_sys.c       |   4 +-
+ include/linux/hid.h           |   6 +-
+ 15 files changed, 490 insertions(+), 36 deletions(-)
+ create mode 100644 drivers/hid/hid-elan.c
+Merging i2c/i2c/for-next (a2cdd4be7a2c Merge branch 'i2c/for-4.16' into i2c/for-next)
+$ git merge i2c/i2c/for-next
+Resolved 'drivers/i2c/i2c-core-smbus.c' using previous resolution.
+Auto-merging drivers/i2c/i2c-core-smbus.c
+CONFLICT (content): Merge conflict in drivers/i2c/i2c-core-smbus.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master d9e3eb5a9c11] Merge remote-tracking branch 'i2c/i2c/for-next'
+$ git diff -M --stat --summary HEAD^..
+Merging dmi/master (36a840c73dc6 firmware: dmi: handle missing DMI data gracefully)
+$ git merge dmi/master
+Merge made by the 'recursive' strategy.
+Merging hwmon-staging/hwmon-next (e464243586cb hwmon: (sht3x) Update data sheet URL)
+$ git merge hwmon-staging/hwmon-next
+Merge made by the 'recursive' strategy.
+ Documentation/hwmon/sht21 | 6 +++---
+ Documentation/hwmon/sht3x | 2 +-
+ drivers/hwmon/sht21.c     | 3 +--
+ 3 files changed, 5 insertions(+), 6 deletions(-)
+Merging jc_docs/docs-next (b57c847ca6e6 admin-guide: Fix list formatting in tained-kernels.html)
+$ git merge jc_docs/docs-next
+Merge made by the 'recursive' strategy.
+ Documentation/admin-guide/tainted-kernels.rst |  18 +-
+ Documentation/doc-guide/kernel-doc.rst        | 552 ++++++++++++--------------
+ Documentation/process/5.Posting.rst           |   2 +-
+ Documentation/process/howto.rst               |  15 -
+ Documentation/trace/events.txt                |   2 +-
+ scripts/kernel-doc                            |   4 +-
+ scripts/split-man.pl                          |  28 ++
+ 7 files changed, 302 insertions(+), 319 deletions(-)
+ create mode 100755 scripts/split-man.pl
+Merging v4l-dvb/master (29422737017b media: rc: get start time just before calling driver tx)
+$ git merge v4l-dvb/master
+Merge made by the 'recursive' strategy.
+ drivers/input/touchscreen/sur40.c                  | 178 ++++++++++++++++++++-
+ drivers/media/cec/cec-adap.c                       |  14 +-
+ drivers/media/cec/cec-api.c                        |  14 +-
+ drivers/media/cec/cec-core.c                       |  14 +-
+ drivers/media/cec/cec-edid.c                       |  14 +-
+ drivers/media/cec/cec-notifier.c                   |  14 +-
+ drivers/media/cec/cec-pin-priv.h                   |  14 +-
+ drivers/media/cec/cec-pin.c                        |  14 +-
+ drivers/media/cec/cec-priv.h                       |  14 +-
+ drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c    |  14 +-
+ drivers/media/common/v4l2-tpg/v4l2-tpg-core.c      |  14 +-
+ drivers/media/i2c/ad9389b.c                        |  14 +-
+ drivers/media/i2c/adv7511.c                        |  14 +-
+ drivers/media/i2c/adv7604.c                        |  14 +-
+ drivers/media/i2c/adv7842.c                        |  15 +-
+ drivers/media/i2c/tc358743.c                       |  15 +-
+ drivers/media/i2c/tc358743_regs.h                  |  15 +-
+ drivers/media/pci/cobalt/Makefile                  |   1 +
+ drivers/media/pci/cobalt/cobalt-alsa-main.c        |  14 +-
+ drivers/media/pci/cobalt/cobalt-alsa-pcm.c         |  14 +-
+ drivers/media/pci/cobalt/cobalt-alsa-pcm.h         |  14 +-
+ drivers/media/pci/cobalt/cobalt-alsa.h             |  14 +-
+ drivers/media/pci/cobalt/cobalt-cpld.c             |  14 +-
+ drivers/media/pci/cobalt/cobalt-cpld.h             |  14 +-
+ drivers/media/pci/cobalt/cobalt-driver.c           |  14 +-
+ drivers/media/pci/cobalt/cobalt-driver.h           |  14 +-
+ drivers/media/pci/cobalt/cobalt-flash.c            |  14 +-
+ drivers/media/pci/cobalt/cobalt-flash.h            |  14 +-
+ drivers/media/pci/cobalt/cobalt-i2c.c              |  14 +-
+ drivers/media/pci/cobalt/cobalt-i2c.h              |  14 +-
+ drivers/media/pci/cobalt/cobalt-irq.c              |  14 +-
+ drivers/media/pci/cobalt/cobalt-irq.h              |  14 +-
+ drivers/media/pci/cobalt/cobalt-omnitek.c          |  14 +-
+ drivers/media/pci/cobalt/cobalt-omnitek.h          |  14 +-
+ drivers/media/pci/cobalt/cobalt-v4l2.c             |  14 +-
+ drivers/media/pci/cobalt/cobalt-v4l2.h             |  14 +-
+ .../cobalt/m00233_video_measure_memmap_package.h   |  14 +-
+ .../pci/cobalt/m00235_fdma_packer_memmap_package.h |  14 +-
+ .../media/pci/cobalt/m00389_cvi_memmap_package.h   |  14 +-
+ .../media/pci/cobalt/m00460_evcnt_memmap_package.h |  14 +-
+ .../pci/cobalt/m00473_freewheel_memmap_package.h   |  14 +-
+ .../m00479_clk_loss_detector_memmap_package.h      |  14 +-
+ .../m00514_syncgen_flow_evcnt_memmap_package.h     |  14 +-
+ drivers/media/platform/cec-gpio/cec-gpio.c         |  14 +-
+ drivers/media/platform/vivid/vivid-cec.c           |  14 +-
+ drivers/media/platform/vivid/vivid-cec.h           |  14 +-
+ drivers/media/platform/vivid/vivid-core.c          |  14 +-
+ drivers/media/platform/vivid/vivid-core.h          |  14 +-
+ drivers/media/platform/vivid/vivid-ctrls.c         |  14 +-
+ drivers/media/platform/vivid/vivid-ctrls.h         |  14 +-
+ drivers/media/platform/vivid/vivid-kthread-cap.c   |  14 +-
+ drivers/media/platform/vivid/vivid-kthread-cap.h   |  14 +-
+ drivers/media/platform/vivid/vivid-kthread-out.c   |  14 +-
+ drivers/media/platform/vivid/vivid-kthread-out.h   |  14 +-
+ drivers/media/platform/vivid/vivid-osd.c           |  14 +-
+ drivers/media/platform/vivid/vivid-osd.h           |  14 +-
+ drivers/media/platform/vivid/vivid-radio-common.c  |  14 +-
+ drivers/media/platform/vivid/vivid-radio-common.h  |  14 +-
+ drivers/media/platform/vivid/vivid-radio-rx.c      |  14 +-
+ drivers/media/platform/vivid/vivid-radio-rx.h      |  14 +-
+ drivers/media/platform/vivid/vivid-radio-tx.c      |  14 +-
+ drivers/media/platform/vivid/vivid-radio-tx.h      |  14 +-
+ drivers/media/platform/vivid/vivid-rds-gen.c       |  14 +-
+ drivers/media/platform/vivid/vivid-rds-gen.h       |  14 +-
+ drivers/media/platform/vivid/vivid-sdr-cap.c       |  14 +-
+ drivers/media/platform/vivid/vivid-sdr-cap.h       |  14 +-
+ drivers/media/platform/vivid/vivid-vbi-cap.c       |  14 +-
+ drivers/media/platform/vivid/vivid-vbi-cap.h       |  14 +-
+ drivers/media/platform/vivid/vivid-vbi-gen.c       |  14 +-
+ drivers/media/platform/vivid/vivid-vbi-gen.h       |  14 +-
+ drivers/media/platform/vivid/vivid-vbi-out.c       |  14 +-
+ drivers/media/platform/vivid/vivid-vbi-out.h       |  14 +-
+ drivers/media/platform/vivid/vivid-vid-cap.c       |  14 +-
+ drivers/media/platform/vivid/vivid-vid-cap.h       |  14 +-
+ drivers/media/platform/vivid/vivid-vid-common.c    |  14 +-
+ drivers/media/platform/vivid/vivid-vid-common.h    |  14 +-
+ drivers/media/platform/vivid/vivid-vid-out.c       |  14 +-
+ drivers/media/platform/vivid/vivid-vid-out.h       |  14 +-
+ drivers/media/radio/radio-raremono.c               |  14 +-
+ drivers/media/radio/si4713/radio-usb-si4713.c      |  14 +-
+ drivers/media/rc/Kconfig                           |  11 --
+ drivers/media/rc/ir-hix5hd2.c                      |  35 +++-
+ drivers/media/rc/ir-jvc-decoder.c                  |  14 +-
+ drivers/media/rc/ir-mce_kbd-decoder.c              |  60 +++----
+ drivers/media/rc/ir-nec-decoder.c                  |  20 ++-
+ drivers/media/rc/ir-rc5-decoder.c                  |  12 +-
+ drivers/media/rc/ir-rc6-decoder.c                  |  26 +--
+ drivers/media/rc/ir-sanyo-decoder.c                |  18 +--
+ drivers/media/rc/ir-sharp-decoder.c                |  17 +-
+ drivers/media/rc/ir-sony-decoder.c                 |  14 +-
+ drivers/media/rc/ir-spi.c                          |  24 +--
+ drivers/media/rc/ir-xmp-decoder.c                  |  29 ++--
+ drivers/media/rc/lirc_dev.c                        |  16 +-
+ drivers/media/rc/rc-core-priv.h                    |   7 -
+ drivers/media/rc/rc-ir-raw.c                       |   6 +-
+ drivers/media/rc/rc-main.c                         |  91 ++++++-----
+ drivers/media/v4l2-core/v4l2-dv-timings.c          |  15 +-
+ include/media/cec-notifier.h                       |  14 +-
+ include/media/cec-pin.h                            |  14 +-
+ include/media/cec.h                                |  14 +-
+ include/media/i2c/ad9389b.h                        |  14 +-
+ include/media/i2c/adv7511.h                        |  14 +-
+ include/media/i2c/adv7604.h                        |  15 +-
+ include/media/i2c/adv7842.h                        |  15 +-
+ include/media/i2c/tc358743.h                       |  18 +--
+ include/media/i2c/ths7303.h                        |  10 +-
+ include/media/i2c/uda1342.h                        |  15 +-
+ include/media/rc-core.h                            |   7 -
+ include/media/tpg/v4l2-tpg.h                       |  14 +-
+ include/media/v4l2-dv-timings.h                    |  15 +-
+ include/media/v4l2-rect.h                          |  14 +-
+ include/uapi/linux/cec-funcs.h                     |  29 ----
+ include/uapi/linux/cec.h                           |  29 ----
+ 113 files changed, 463 insertions(+), 1477 deletions(-)
+Merging v4l-dvb-next/master (a1dfb4c48cc1 media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic)
+$ git merge v4l-dvb-next/master
+Already up to date.
+Merging fbdev/fbdev-for-next (5865889fe431 video: udlfb: Switch from the pr_*() to the dev_*() logging functions)
+$ git merge fbdev/fbdev-for-next
+Already up to date.
+Merging pm/linux-next (91ab883eb213 Linux 4.16-rc2)
+$ git merge pm/linux-next
+Already up to date.
+Merging cpupower/cpupower (7928b2cbe55b Linux 4.16-rc1)
+$ git merge cpupower/cpupower
+Already up to date.
+Merging idle/next (8a5776a5f498 Linux 4.14-rc4)
+$ git merge idle/next
+Already up to date.
+Merging opp/opp/linux-next (4a823c0be80f opp: cpu: Replace GFP_ATOMIC with GFP_KERNEL in dev_pm_opp_init_cpufreq_table)
+$ git merge opp/opp/linux-next
+Already up to date.
+Merging thermal/next (134f4010799a Merge branches 'thermal-core', 'thermal-intel' and 'thermal-soc' into next)
+$ git merge thermal/next
+Already up to date.
+Merging thermal-soc/next (d0ecbbbe518e thermal/drivers/hisi: Remove bogus const from function return type)
+$ git merge thermal-soc/next
+Already up to date.
+Merging ieee1394/for-next (188775181bc0 firewire-ohci: work around oversized DMA reads on JMicron controllers)
+$ git merge ieee1394/for-next
+Already up to date.
+Merging dlm/next (9250e523592a dlm: remove dlm_send_rcom_lookup_dump)
+$ git merge dlm/next
+Already up to date.
+Merging swiotlb/linux-next (69369f52d28a swiotlb-xen: implement xen_swiotlb_get_sgtable callback)
+$ git merge swiotlb/linux-next
+Already up to date.
+Merging net-next/master (26736a08ee0f tipc: don't call sock_release() in atomic context)
+$ git merge net-next/master
+Auto-merging net/xfrm/xfrm_policy.c
+Auto-merging net/unix/af_unix.c
+Auto-merging net/tipc/topsrv.h
+Removing net/tipc/server.c
+Auto-merging net/tipc/bearer.c
+Auto-merging net/sctp/diag.c
+Auto-merging net/sched/cls_api.c
+Auto-merging net/netfilter/x_tables.c
+Auto-merging net/ipv6/xfrm6_policy.c
+Auto-merging net/ipv6/route.c
+Auto-merging net/ipv4/xfrm4_policy.c
+Auto-merging net/ipv4/udp.c
+Auto-merging net/ipv4/route.c
+Auto-merging net/ipv4/netfilter/ip_tables.c
+Auto-merging net/ipv4/ip_sockglue.c
+Auto-merging net/ipv4/fib_semantics.c
+Auto-merging net/decnet/af_decnet.c
+Auto-merging net/core/dev.c
+Auto-merging include/net/route.h
+Auto-merging include/linux/skbuff.h
+Auto-merging include/linux/ptr_ring.h
+Auto-merging drivers/net/tun.c
+Auto-merging drivers/net/ethernet/renesas/sh_eth.c
+Auto-merging drivers/net/ethernet/renesas/ravb_main.c
+Auto-merging drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+Auto-merging drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+Auto-merging drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/net/ti,dp83867.txt         |    2 +
+ drivers/bluetooth/ath3k.c                          |   28 +-
+ drivers/bluetooth/btmrvl_main.c                    |    2 +-
+ drivers/bluetooth/btrtl.c                          |  119 ++-
+ drivers/bluetooth/btusb.c                          |   10 +
+ drivers/bluetooth/hci_ath.c                        |    4 +-
+ drivers/bluetooth/hci_ll.c                         |    2 +-
+ drivers/infiniband/hw/usnic/usnic_transport.c      |    5 +-
+ drivers/isdn/mISDN/socket.c                        |    5 +-
+ drivers/net/dsa/mv88e6xxx/Kconfig                  |   10 +
+ drivers/net/dsa/mv88e6xxx/Makefile                 |    4 +
+ drivers/net/dsa/mv88e6xxx/chip.c                   |   91 +-
+ drivers/net/dsa/mv88e6xxx/chip.h                   |  103 ++
+ drivers/net/dsa/mv88e6xxx/global2.c                |    9 +-
+ drivers/net/dsa/mv88e6xxx/global2.h                |   85 +-
+ drivers/net/dsa/mv88e6xxx/global2_avb.c            |  193 ++++
+ drivers/net/dsa/mv88e6xxx/global2_scratch.c        |  240 +++++
+ drivers/net/dsa/mv88e6xxx/hwtstamp.c               |  576 +++++++++++
+ drivers/net/dsa/mv88e6xxx/hwtstamp.h               |  172 ++++
+ drivers/net/dsa/mv88e6xxx/ptp.c                    |  381 ++++++++
+ drivers/net/dsa/mv88e6xxx/ptp.h                    |  108 +++
+ drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c     |   86 +-
+ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h         |    5 +
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c         |  193 ++--
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c     |    2 +-
+ drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c |    2 +-
+ drivers/net/ethernet/intel/i40e/i40e.h             |   10 +-
+ drivers/net/ethernet/intel/i40e/i40e_debugfs.c     |   52 +-
+ drivers/net/ethernet/intel/i40e/i40e_ethtool.c     |   89 +-
+ drivers/net/ethernet/intel/i40e/i40e_main.c        |  158 ++--
+ drivers/net/ethernet/intel/i40e/i40e_txrx.c        |  421 +++++---
+ drivers/net/ethernet/intel/i40e/i40e_txrx.h        |   68 +-
+ drivers/net/ethernet/intel/i40e/i40e_type.h        |    2 +-
+ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 1000 ++++++++++++++++++--
+ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h |   20 +
+ drivers/net/ethernet/intel/i40evf/i40e_txrx.c      |  425 ++++++---
+ drivers/net/ethernet/intel/i40evf/i40e_txrx.h      |   67 +-
+ drivers/net/ethernet/intel/i40evf/i40evf.h         |   75 +-
+ drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c |   52 +-
+ drivers/net/ethernet/intel/i40evf/i40evf_main.c    |  931 ++++++++++++++++--
+ .../net/ethernet/intel/i40evf/i40evf_virtchnl.c    |  334 ++++++-
+ drivers/net/ethernet/mellanox/mlxsw/Makefile       |    2 +-
+ drivers/net/ethernet/mellanox/mlxsw/spectrum.c     |  350 +------
+ drivers/net/ethernet/mellanox/mlxsw/spectrum.h     |   30 +-
+ .../mellanox/mlxsw/spectrum_acl_flex_actions.c     |    1 +
+ .../net/ethernet/mellanox/mlxsw/spectrum_ipip.c    |  141 ++-
+ .../net/ethernet/mellanox/mlxsw/spectrum_ipip.h    |    7 +-
+ .../net/ethernet/mellanox/mlxsw/spectrum_router.c  |   22 +-
+ .../net/ethernet/mellanox/mlxsw/spectrum_span.c    |  356 +++++++
+ .../net/ethernet/mellanox/mlxsw/spectrum_span.h    |   73 ++
+ .../ethernet/mellanox/mlxsw/spectrum_switchdev.c   |    6 +-
+ drivers/net/ethernet/netronome/nfp/flower/cmsg.h   |   11 +-
+ drivers/net/ethernet/netronome/nfp/flower/main.h   |    1 +
+ drivers/net/ethernet/netronome/nfp/flower/match.c  |   20 +
+ .../net/ethernet/netronome/nfp/flower/offload.c    |   34 +
+ drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h  |  280 +++---
+ drivers/net/ethernet/renesas/ravb.h                |    1 +
+ drivers/net/ethernet/renesas/ravb_main.c           |   34 +-
+ drivers/net/ethernet/renesas/sh_eth.c              |   16 +-
+ .../net/ethernet/stmicro/stmmac/dwmac-meson8b.c    |  208 ++--
+ drivers/net/loopback.c                             |    1 +
+ drivers/net/phy/dp83867.c                          |   19 +
+ drivers/net/ppp/pppoe.c                            |    6 +-
+ drivers/net/ppp/pptp.c                             |    6 +-
+ drivers/net/tun.c                                  |   72 +-
+ drivers/net/vrf.c                                  |    1 -
+ drivers/scsi/iscsi_tcp.c                           |   14 +-
+ drivers/soc/qcom/qmi_interface.c                   |    3 +-
+ drivers/staging/ipx/af_ipx.c                       |    6 +-
+ drivers/staging/irda/net/af_irda.c                 |    8 +-
+ drivers/staging/lustre/lnet/lnet/lib-socket.c      |    7 +-
+ drivers/target/iscsi/iscsi_target_login.c          |   18 +-
+ drivers/vhost/net.c                                |    7 +-
+ fs/dlm/lowcomms.c                                  |    7 +-
+ fs/nsfs.c                                          |    1 +
+ fs/ocfs2/cluster/tcp.c                             |    6 +-
+ fs/proc/proc_net.c                                 |    1 +
+ include/dt-bindings/net/ti-dp83867.h               |   14 +
+ include/linux/atalk.h                              |    2 +
+ include/linux/avf/virtchnl.h                       |  107 ++-
+ include/linux/net.h                                |    8 +-
+ include/linux/netdevice.h                          |    6 +
+ include/linux/ptp_classify.h                       |    4 +
+ include/linux/ptr_ring.h                           |    7 +-
+ include/linux/rtnetlink.h                          |    1 +
+ include/linux/skbuff.h                             |    3 +
+ include/linux/socket.h                             |    2 +
+ include/net/act_api.h                              |   17 +-
+ include/net/ax25.h                                 |    2 +
+ include/net/dsa.h                                  |   20 +
+ include/net/inet_common.h                          |    2 +-
+ include/net/ipv6.h                                 |    2 +-
+ include/net/lwtunnel.h                             |   15 +
+ include/net/net_namespace.h                        |    6 +
+ include/net/route.h                                |    2 -
+ include/net/sock.h                                 |    2 +-
+ include/net/tcp.h                                  |    3 +-
+ include/uapi/linux/errqueue.h                      |    2 +
+ include/uapi/linux/if_link.h                       |   18 +
+ include/uapi/linux/rds.h                           |    1 +
+ kernel/audit.c                                     |    1 +
+ lib/kobject_uevent.c                               |    1 +
+ net/appletalk/ddp.c                                |    5 +-
+ net/atm/pvc.c                                      |    5 +-
+ net/atm/svc.c                                      |    5 +-
+ net/ax25/af_ax25.c                                 |    4 +-
+ net/bluetooth/hci_request.c                        |    6 +-
+ net/bluetooth/hci_sock.c                           |    4 +-
+ net/bluetooth/l2cap_sock.c                         |    5 +-
+ net/bluetooth/rfcomm/sock.c                        |    5 +-
+ net/bluetooth/sco.c                                |    5 +-
+ net/can/raw.c                                      |    6 +-
+ net/core/dev.c                                     |    5 +-
+ net/core/fib_notifier.c                            |    1 +
+ net/core/fib_rules.c                               |    1 +
+ net/core/net-procfs.c                              |    2 +
+ net/core/net_namespace.c                           |   95 +-
+ net/core/rtnetlink.c                               |    5 +-
+ net/core/skbuff.c                                  |    6 +-
+ net/core/sock.c                                    |   32 +-
+ net/core/sock_diag.c                               |    1 +
+ net/core/sysctl_net_core.c                         |    1 +
+ net/decnet/af_decnet.c                             |    6 +-
+ net/dsa/dsa.c                                      |   36 +
+ net/dsa/slave.c                                    |   59 ++
+ net/ipv4/af_inet.c                                 |    7 +-
+ net/ipv4/arp.c                                     |    1 +
+ net/ipv4/devinet.c                                 |    1 +
+ net/ipv4/fib_frontend.c                            |    1 +
+ net/ipv4/fib_semantics.c                           |   12 +-
+ net/ipv4/icmp.c                                    |    1 +
+ net/ipv4/igmp.c                                    |    1 +
+ net/ipv4/ip_fragment.c                             |    1 +
+ net/ipv4/ip_sockglue.c                             |    6 +-
+ net/ipv4/ipmr.c                                    |    1 +
+ net/ipv4/netfilter/ip_tables.c                     |    1 +
+ net/ipv4/netfilter/iptable_filter.c                |    1 +
+ net/ipv4/ping.c                                    |    1 +
+ net/ipv4/proc.c                                    |    1 +
+ net/ipv4/raw.c                                     |    1 +
+ net/ipv4/route.c                                   |   31 +-
+ net/ipv4/sysctl_net_ipv4.c                         |    1 +
+ net/ipv4/tcp_input.c                               |    4 +-
+ net/ipv4/tcp_ipv4.c                                |   15 +-
+ net/ipv4/tcp_metrics.c                             |    1 +
+ net/ipv4/tcp_minisocks.c                           |    3 +-
+ net/ipv4/udp.c                                     |    1 +
+ net/ipv4/udplite.c                                 |    1 +
+ net/ipv4/xfrm4_policy.c                            |    2 +-
+ net/ipv6/addrconf.c                                |    2 +
+ net/ipv6/addrlabel.c                               |    1 +
+ net/ipv6/af_inet6.c                                |    6 +-
+ net/ipv6/fib6_rules.c                              |    1 +
+ net/ipv6/icmp.c                                    |    1 +
+ net/ipv6/ip6_fib.c                                 |    1 +
+ net/ipv6/ip6_flowlabel.c                           |    1 +
+ net/ipv6/ip6mr.c                                   |    1 +
+ net/ipv6/mcast.c                                   |    1 +
+ net/ipv6/ndisc.c                                   |    1 +
+ net/ipv6/ping.c                                    |    1 +
+ net/ipv6/proc.c                                    |    1 +
+ net/ipv6/raw.c                                     |    1 +
+ net/ipv6/reassembly.c                              |    1 +
+ net/ipv6/route.c                                   |   12 +-
+ net/ipv6/seg6.c                                    |    1 +
+ net/ipv6/sysctl_net_ipv6.c                         |    1 +
+ net/ipv6/tcp_ipv6.c                                |   14 +-
+ net/ipv6/udplite.c                                 |    1 +
+ net/ipv6/xfrm6_policy.c                            |    1 +
+ net/iucv/af_iucv.c                                 |    5 +-
+ net/kcm/kcmsock.c                                  |    1 +
+ net/l2tp/l2tp_ip.c                                 |    5 +-
+ net/l2tp/l2tp_ip6.c                                |    5 +-
+ net/l2tp/l2tp_ppp.c                                |    5 +-
+ net/llc/af_llc.c                                   |    5 +-
+ net/netfilter/core.c                               |    1 +
+ net/netfilter/nf_log.c                             |    1 +
+ net/netfilter/x_tables.c                           |    1 +
+ net/netlink/af_netlink.c                           |    7 +-
+ net/netlink/genetlink.c                            |    1 +
+ net/netrom/af_netrom.c                             |    9 +-
+ net/nfc/llcp_sock.c                                |    5 +-
+ net/packet/af_packet.c                             |   11 +-
+ net/phonet/socket.c                                |    5 +-
+ net/qrtr/qrtr.c                                    |    5 +-
+ net/rds/af_rds.c                                   |    7 +-
+ net/rds/message.c                                  |  132 ++-
+ net/rds/rds.h                                      |   17 +-
+ net/rds/recv.c                                     |    2 +
+ net/rds/send.c                                     |   51 +-
+ net/rds/tcp.c                                      |    7 +-
+ net/rose/af_rose.c                                 |    5 +-
+ net/sched/act_api.c                                |  140 ++-
+ net/sched/act_bpf.c                                |   10 +-
+ net/sched/act_connmark.c                           |   11 +-
+ net/sched/act_csum.c                               |   10 +-
+ net/sched/act_gact.c                               |   10 +-
+ net/sched/act_ife.c                                |   10 +-
+ net/sched/act_ipt.c                                |   20 +-
+ net/sched/act_mirred.c                             |   25 +-
+ net/sched/act_nat.c                                |   11 +-
+ net/sched/act_pedit.c                              |   10 +-
+ net/sched/act_police.c                             |   11 +-
+ net/sched/act_sample.c                             |   10 +-
+ net/sched/act_simple.c                             |   10 +-
+ net/sched/act_skbedit.c                            |   10 +-
+ net/sched/act_skbmod.c                             |   10 +-
+ net/sched/act_tunnel_key.c                         |   10 +-
+ net/sched/act_vlan.c                               |   10 +-
+ net/sched/cls_api.c                                |    4 +-
+ net/sched/sch_api.c                                |    1 +
+ net/sctp/Makefile                                  |    2 +
+ net/sctp/{sctp_diag.c => diag.c}                   |   31 +
+ net/sctp/ipv6.c                                    |    8 +-
+ net/smc/af_smc.c                                   |   11 +-
+ net/socket.c                                       |   39 +-
+ net/sunrpc/clnt.c                                  |    6 +-
+ net/sunrpc/svcsock.c                               |   13 +-
+ net/sunrpc/xprtsock.c                              |    3 +-
+ net/sysctl_net.c                                   |    1 +
+ net/tipc/Makefile                                  |    2 +-
+ net/tipc/bearer.c                                  |    8 +-
+ net/tipc/core.h                                    |    6 +-
+ net/tipc/group.c                                   |    2 +-
+ net/tipc/link.c                                    |    3 +-
+ net/tipc/name_table.c                              |   73 +-
+ net/tipc/name_table.h                              |    2 +-
+ net/tipc/node.c                                    |   24 +
+ net/tipc/node.h                                    |    1 +
+ net/tipc/server.c                                  |  710 --------------
+ net/tipc/socket.c                                  |    5 +-
+ net/tipc/subscr.c                                  |  361 ++-----
+ net/tipc/subscr.h                                  |   66 +-
+ net/tipc/topsrv.c                                  |  703 ++++++++++++++
+ net/tipc/{server.h => topsrv.h}                    |   57 +-
+ net/unix/af_unix.c                                 |   11 +-
+ net/vmw_vsock/af_vsock.c                           |    4 +-
+ net/wireless/core.c                                |    1 +
+ net/wireless/wext-core.c                           |    1 +
+ net/x25/af_x25.c                                   |    4 +-
+ net/xfrm/xfrm_policy.c                             |    1 +
+ security/tomoyo/network.c                          |    5 +-
+ tools/testing/selftests/net/fib-onlink-tests.sh    |  375 ++++++++
+ tools/testing/selftests/net/fib_tests.sh           |  483 +++++-----
+ tools/testing/selftests/net/msg_zerocopy.c         |  133 ++-
+ tools/testing/selftests/net/psock_fanout.c         |    3 +-
+ tools/testing/selftests/tc-testing/README          |  173 +++-
+ tools/testing/selftests/tc-testing/TODO.txt        |   25 +-
+ tools/testing/selftests/tc-testing/TdcPlugin.py    |   74 ++
+ .../tc-testing/creating-plugins/AddingPlugins.txt  |  104 ++
+ .../creating-testcases/AddingTestCases.txt         |   35 +-
+ .../selftests/tc-testing/plugin-lib/README-PLUGINS |   27 +
+ .../selftests/tc-testing/plugin-lib/nsPlugin.py    |  141 +++
+ .../selftests/tc-testing/plugin-lib/rootPlugin.py  |   19 +
+ .../tc-testing/plugin-lib/valgrindPlugin.py        |  142 +++
+ .../selftests/tc-testing/plugins/__init__.py       |    0
+ tools/testing/selftests/tc-testing/tdc.py          |  486 ++++++----
+ tools/testing/selftests/tc-testing/tdc_helper.py   |   15 +-
+ 258 files changed, 10015 insertions(+), 3621 deletions(-)
+ create mode 100644 drivers/net/dsa/mv88e6xxx/global2_avb.c
+ create mode 100644 drivers/net/dsa/mv88e6xxx/global2_scratch.c
+ create mode 100644 drivers/net/dsa/mv88e6xxx/hwtstamp.c
+ create mode 100644 drivers/net/dsa/mv88e6xxx/hwtstamp.h
+ create mode 100644 drivers/net/dsa/mv88e6xxx/ptp.c
+ create mode 100644 drivers/net/dsa/mv88e6xxx/ptp.h
+ create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+ create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
+ rename net/sctp/{sctp_diag.c => diag.c} (92%)
+ delete mode 100644 net/tipc/server.c
+ create mode 100644 net/tipc/topsrv.c
+ rename net/tipc/{server.h => topsrv.h} (55%)
+ create mode 100755 tools/testing/selftests/net/fib-onlink-tests.sh
+ create mode 100644 tools/testing/selftests/tc-testing/TdcPlugin.py
+ create mode 100644 tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt
+ create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS
+ create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py
+ create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py
+ create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py
+ create mode 100644 tools/testing/selftests/tc-testing/plugins/__init__.py
+Merging bpf-next/master (0b6b8a3dd86d Merge branch 'bpf-misc-selftest-improvements')
+$ git merge bpf-next/master
+Merge made by the 'recursive' strategy.
+ include/linux/filter.h                         |  2 +-
+ kernel/bpf/verifier.c                          |  4 ---
+ samples/bpf/xdp_redirect_user.c                |  7 +++++
+ samples/sockmap/Makefile                       |  2 +-
+ samples/sockmap/sockmap_user.c                 |  1 +
+ tools/testing/selftests/bpf/Makefile           |  4 ++-
+ tools/testing/selftests/bpf/test_tcpbpf_user.c |  6 ++++
+ tools/testing/selftests/bpf/test_verifier.c    | 39 ++++++++++++++++++++++----
+ 8 files changed, 53 insertions(+), 12 deletions(-)
+Merging ipsec-next/master (60aa80460da1 esp4: remove redundant initialization of pointer esph)
+$ git merge ipsec-next/master
+Merge made by the 'recursive' strategy.
+ net/ipv4/esp4.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Merging netfilter-next/master (c746fc0e8b2d cxgb4: add geneve offload support for T6)
+$ git merge netfilter-next/master
+Already up to date.
+Merging nfc-next/master (4d63adfe12dd NFC: Add NFC_CMD_DEACTIVATE_TARGET support)
+$ git merge nfc-next/master
+Already up to date.
+Merging ipvs-next/master (a910d20aa007 netfilter: ipvs: Fix space before '[' error.)
+$ git merge ipvs-next/master
+Auto-merging net/netfilter/ipvs/ip_vs_proto_tcp.c
+Merge made by the 'recursive' strategy.
+ net/netfilter/ipvs/ip_vs_proto_tcp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+Merging wireless-drivers-next/master (cf19e5e2054f Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue)
+$ git merge wireless-drivers-next/master
+Already up to date.
+Merging bluetooth/master (1ec010e70593 tun: export flags, uid, gid, queue information over netlink)
+$ git merge bluetooth/master
+Already up to date.
+Merging mac80211-next/master (b28971dfae9f mac80211: Adjust TSQ pacing shift)
+$ git merge mac80211-next/master
+Auto-merging net/wireless/nl80211.c
+Auto-merging net/mac80211/sta_info.c
+Auto-merging include/uapi/linux/if_ether.h
+Auto-merging include/net/mac80211.h
+Auto-merging drivers/net/wireless/mac80211_hwsim.c
+Merge made by the 'recursive' strategy.
+ drivers/net/wireless/ath/wil6210/cfg80211.c |   3 +-
+ drivers/net/wireless/mac80211_hwsim.c       |  81 ++++++++---
+ drivers/net/wireless/mac80211_hwsim.h       |   9 +-
+ include/linux/ieee80211.h                   |  14 +-
+ include/net/cfg80211.h                      | 104 +++++++++++++-
+ include/net/ieee80211_radiotap.h            |   2 +
+ include/net/mac80211.h                      |  19 +++
+ include/uapi/linux/if_ether.h               |   1 +
+ include/uapi/linux/nl80211.h                |  90 +++++++++++-
+ net/mac80211/debugfs.c                      |   1 +
+ net/mac80211/debugfs_sta.c                  |  10 +-
+ net/mac80211/iface.c                        |   3 +-
+ net/mac80211/michael.c                      |   2 +-
+ net/mac80211/mlme.c                         |  21 ++-
+ net/mac80211/rc80211_minstrel_ht.c          |   2 +-
+ net/mac80211/rx.c                           |  30 +++-
+ net/mac80211/scan.c                         |   4 +-
+ net/mac80211/sta_info.c                     |   6 +
+ net/mac80211/sta_info.h                     |   2 +
+ net/mac80211/status.c                       |  11 +-
+ net/mac80211/tx.c                           |  19 +--
+ net/mac80211/vht.c                          |   9 ++
+ net/mac80211/wpa.c                          |   8 +-
+ net/wireless/nl80211.c                      | 203 +++++++++++++++++++++++-----
+ net/wireless/rdev-ops.h                     |  15 ++
+ net/wireless/trace.h                        |  23 ++++
+ 26 files changed, 602 insertions(+), 90 deletions(-)
+Merging rdma/for-next (3a148896b24a IB/srp: Fix completion vector assignment algorithm)
+$ git merge rdma/for-next
+Removing drivers/infiniband/hw/cxgb3/cxio_dbg.c
+Merge made by the 'recursive' strategy.
+ drivers/infiniband/hw/cxgb3/Kconfig        |   9 --
+ drivers/infiniband/hw/cxgb3/Makefile       |   2 -
+ drivers/infiniband/hw/cxgb3/cxio_dbg.c     | 206 -----------------------------
+ drivers/infiniband/hw/cxgb3/cxio_hal.h     |   9 --
+ drivers/infiniband/hw/cxgb3/iwch_cq.c      |   6 -
+ drivers/infiniband/hw/hns/hns_roce_hw_v1.c |   8 +-
+ drivers/infiniband/hw/hns/hns_roce_hw_v2.c |  10 +-
+ drivers/infiniband/hw/hns/hns_roce_main.c  |   3 +-
+ drivers/infiniband/hw/hns/hns_roce_mr.c    |   2 +-
+ drivers/infiniband/sw/rxe/rxe_av.c         |   5 +-
+ drivers/infiniband/ulp/srp/ib_srp.c        |  10 +-
+ include/uapi/rdma/hfi/hfi1_user.h          |   6 +-
+ include/uapi/rdma/ocrdma-abi.h             |   2 +-
+ include/uapi/rdma/rdma_user_rxe.h          |   4 +-
+ 14 files changed, 26 insertions(+), 256 deletions(-)
+ delete mode 100644 drivers/infiniband/hw/cxgb3/cxio_dbg.c
+Merging gfs2/for-next (6556677a8040 Merge tag 'gfs2-4.16.rc1.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2)
+$ git merge gfs2/for-next
+Already up to date.
+Merging mtd/master (f23def803861 mtd: nand: MTD_NAND_MARVELL should depend on HAS_DMA)
+$ git merge mtd/master
+Already up to date.
+Merging l2-mtd/mtd/next (0dbe4ea78d69 mtd: get rid of the mtd_add_device_partitions())
+$ git merge l2-mtd/mtd/next
+Merge made by the 'recursive' strategy.
+ drivers/mtd/mtdcore.c | 62 ++++++++++++++++++++-------------------------------
+ 1 file changed, 24 insertions(+), 38 deletions(-)
+Merging nand/nand/next (4da712e70294 mtd: nand: fsmc: use ->exec_op())
+$ git merge nand/nand/next
+Resolved 'drivers/mtd/nand/Kconfig' using previous resolution.
+Auto-merging drivers/mtd/nand/raw/vf610_nfc.c
+Auto-merging drivers/mtd/nand/raw/socrates_nand.c
+Auto-merging drivers/mtd/nand/raw/sharpsl.c
+Auto-merging drivers/mtd/nand/raw/s3c2410.c
+Auto-merging drivers/mtd/nand/raw/pxa3xx_nand.c
+Auto-merging drivers/mtd/nand/raw/orion_nand.c
+Auto-merging drivers/mtd/nand/raw/nand_toshiba.c
+Auto-merging drivers/mtd/nand/raw/nand_ecc.c
+Auto-merging drivers/mtd/nand/raw/mxc_nand.c
+Auto-merging drivers/mtd/nand/raw/mpc5121_nfc.c
+Auto-merging drivers/mtd/nand/raw/marvell_nand.c
+Auto-merging drivers/mtd/nand/raw/gpio.c
+Auto-merging drivers/mtd/nand/raw/fsmc_nand.c
+Auto-merging drivers/mtd/nand/raw/diskonchip.c
+Auto-merging drivers/mtd/nand/raw/cs553x_nand.c
+Auto-merging drivers/mtd/nand/raw/cmx270_nand.c
+Auto-merging drivers/mtd/nand/raw/bf5xx_nand.c
+Auto-merging drivers/mtd/nand/raw/au1550nd.c
+Auto-merging drivers/mtd/nand/raw/atmel/pmecc.h
+Auto-merging drivers/mtd/nand/raw/atmel/pmecc.c
+Auto-merging drivers/mtd/nand/raw/atmel/nand-controller.c
+Auto-merging drivers/mtd/nand/raw/ams-delta.c
+Auto-merging drivers/mtd/nand/Kconfig
+CONFLICT (content): Merge conflict in drivers/mtd/nand/Kconfig
+Auto-merging MAINTAINERS
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master b5ca8b0f885c7e07a67348cdb8de23a6674d770b] Merge remote-tracking branch 'nand/nand/next'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/arm/Samsung-S3C24XX/S3C2412.txt      |   2 +-
+ Documentation/driver-api/mtdnand.rst               |   8 +-
+ Documentation/gpio/drivers-on-gpio.txt             |   4 +-
+ MAINTAINERS                                        |  22 +-
+ arch/cris/arch-v32/drivers/mach-a3/nandflash.c     |   2 +-
+ arch/cris/arch-v32/drivers/mach-fs/nandflash.c     |   2 +-
+ drivers/mtd/nand/Kconfig                           | 580 +---------------
+ drivers/mtd/nand/Makefile                          |  71 +-
+ drivers/mtd/nand/bbt.c                             | 130 ++++
+ drivers/mtd/nand/core.c                            | 244 +++++++
+ drivers/mtd/nand/raw/Kconfig                       | 580 ++++++++++++++++
+ drivers/mtd/nand/raw/Makefile                      |  68 ++
+ drivers/mtd/nand/{ => raw}/ams-delta.c             |   9 +-
+ drivers/mtd/nand/{ => raw}/atmel/Makefile          |   0
+ drivers/mtd/nand/{ => raw}/atmel/nand-controller.c |   4 +-
+ drivers/mtd/nand/{ => raw}/atmel/pmecc.c           |   4 +-
+ drivers/mtd/nand/{ => raw}/atmel/pmecc.h           |   4 +-
+ drivers/mtd/nand/{ => raw}/au1550nd.c              |   2 -
+ drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile  |   0
+ .../nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h   |   0
+ drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c    |   0
+ .../mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c |   0
+ drivers/mtd/nand/{ => raw}/bf5xx_nand.c            |   7 +-
+ drivers/mtd/nand/{ => raw}/brcmnand/Makefile       |   0
+ .../mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c    |   0
+ drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c |   0
+ drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c     |   0
+ drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h     |   0
+ drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c |   0
+ drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c   |   0
+ drivers/mtd/nand/{ => raw}/cafe_nand.c             |   0
+ drivers/mtd/nand/{ => raw}/cmx270_nand.c           |   4 +-
+ drivers/mtd/nand/{ => raw}/cs553x_nand.c           |   2 -
+ drivers/mtd/nand/{ => raw}/davinci_nand.c          |   0
+ drivers/mtd/nand/{ => raw}/denali.c                |   0
+ drivers/mtd/nand/{ => raw}/denali.h                |   0
+ drivers/mtd/nand/{ => raw}/denali_dt.c             |   0
+ drivers/mtd/nand/{ => raw}/denali_pci.c            |   0
+ drivers/mtd/nand/{ => raw}/diskonchip.c            |   2 -
+ drivers/mtd/nand/{ => raw}/docg4.c                 |   0
+ drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c         |   0
+ drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c          |   0
+ drivers/mtd/nand/{ => raw}/fsl_upm.c               |   0
+ drivers/mtd/nand/{ => raw}/fsmc_nand.c             | 252 +++----
+ drivers/mtd/nand/{ => raw}/gpio.c                  |   2 -
+ drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile      |   0
+ drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h    |   0
+ drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c    |   0
+ drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c   |   0
+ drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h   |   0
+ drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h   |   0
+ drivers/mtd/nand/{ => raw}/hisi504_nand.c          |   0
+ drivers/mtd/nand/{ => raw}/jz4740_nand.c           |   0
+ drivers/mtd/nand/{ => raw}/jz4780_bch.c            |   0
+ drivers/mtd/nand/{ => raw}/jz4780_bch.h            |   0
+ drivers/mtd/nand/{ => raw}/jz4780_nand.c           |   0
+ drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c           |   0
+ drivers/mtd/nand/{ => raw}/lpc32xx_slc.c           |   0
+ drivers/mtd/nand/{ => raw}/marvell_nand.c          |  39 +-
+ drivers/mtd/nand/{ => raw}/mpc5121_nfc.c           |   5 +-
+ drivers/mtd/nand/{ => raw}/mtk_ecc.c               |   0
+ drivers/mtd/nand/{ => raw}/mtk_ecc.h               |   0
+ drivers/mtd/nand/{ => raw}/mtk_nand.c              |   0
+ drivers/mtd/nand/{ => raw}/mxc_nand.c              | 509 ++++++++------
+ drivers/mtd/nand/{ => raw}/nand_amd.c              |   0
+ drivers/mtd/nand/{ => raw}/nand_base.c             |   0
+ drivers/mtd/nand/{ => raw}/nand_bbt.c              |   0
+ drivers/mtd/nand/{ => raw}/nand_bch.c              |   0
+ drivers/mtd/nand/{ => raw}/nand_ecc.c              |   2 -
+ drivers/mtd/nand/{ => raw}/nand_hynix.c            |   0
+ drivers/mtd/nand/{ => raw}/nand_ids.c              |   0
+ drivers/mtd/nand/{ => raw}/nand_macronix.c         |   0
+ drivers/mtd/nand/{ => raw}/nand_micron.c           |   0
+ drivers/mtd/nand/{ => raw}/nand_samsung.c          |   0
+ drivers/mtd/nand/{ => raw}/nand_timings.c          |   0
+ drivers/mtd/nand/{ => raw}/nand_toshiba.c          |  26 +
+ drivers/mtd/nand/{ => raw}/nandsim.c               |   0
+ drivers/mtd/nand/{ => raw}/ndfc.c                  |   0
+ drivers/mtd/nand/{ => raw}/nuc900_nand.c           |   0
+ drivers/mtd/nand/{ => raw}/omap2.c                 |   0
+ drivers/mtd/nand/{ => raw}/omap_elm.c              |   0
+ drivers/mtd/nand/{ => raw}/orion_nand.c            |   2 -
+ drivers/mtd/nand/{ => raw}/oxnas_nand.c            |   0
+ drivers/mtd/nand/{ => raw}/pasemi_nand.c           |   0
+ drivers/mtd/nand/{ => raw}/plat_nand.c             |   0
+ drivers/mtd/nand/{ => raw}/pxa3xx_nand.c           |   2 -
+ drivers/mtd/nand/{ => raw}/qcom_nandc.c            |   0
+ drivers/mtd/nand/{ => raw}/r852.c                  |   0
+ drivers/mtd/nand/{ => raw}/r852.h                  |   0
+ drivers/mtd/nand/{ => raw}/s3c2410.c               |   3 +-
+ drivers/mtd/nand/{ => raw}/sh_flctl.c              |   0
+ drivers/mtd/nand/{ => raw}/sharpsl.c               |   2 -
+ drivers/mtd/nand/{ => raw}/sm_common.c             |   0
+ drivers/mtd/nand/{ => raw}/sm_common.h             |   0
+ drivers/mtd/nand/{ => raw}/socrates_nand.c         |   2 -
+ drivers/mtd/nand/{ => raw}/sunxi_nand.c            |   0
+ drivers/mtd/nand/{ => raw}/tango_nand.c            |   0
+ drivers/mtd/nand/{ => raw}/tmio_nand.c             |   0
+ drivers/mtd/nand/{ => raw}/txx9ndfmc.c             |   0
+ drivers/mtd/nand/{ => raw}/vf610_nfc.c             |  44 +-
+ drivers/mtd/nand/{ => raw}/xway_nand.c             |   0
+ drivers/mtd/sm_ftl.c                               |   2 +-
+ include/linux/mtd/bbm.h                            |   2 -
+ include/linux/mtd/nand.h                           | 731 +++++++++++++++++++++
+ include/linux/mtd/nand_ecc.h                       |   2 -
+ include/linux/mtd/ndfc.h                           |   2 -
+ 106 files changed, 2321 insertions(+), 1059 deletions(-)
+ create mode 100644 drivers/mtd/nand/bbt.c
+ create mode 100644 drivers/mtd/nand/core.c
+ create mode 100644 drivers/mtd/nand/raw/Kconfig
+ create mode 100644 drivers/mtd/nand/raw/Makefile
+ rename drivers/mtd/nand/{ => raw}/ams-delta.c (97%)
+ rename drivers/mtd/nand/{ => raw}/atmel/Makefile (100%)
+ rename drivers/mtd/nand/{ => raw}/atmel/nand-controller.c (99%)
+ rename drivers/mtd/nand/{ => raw}/atmel/pmecc.c (99%)
+ rename drivers/mtd/nand/{ => raw}/atmel/pmecc.h (94%)
+ rename drivers/mtd/nand/{ => raw}/au1550nd.c (99%)
+ rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/Makefile (100%)
+ rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/bcm47xxnflash.h (100%)
+ rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/main.c (100%)
+ rename drivers/mtd/nand/{ => raw}/bcm47xxnflash/ops_bcm4706.c (100%)
+ rename drivers/mtd/nand/{ => raw}/bf5xx_nand.c (99%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/Makefile (100%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/bcm63138_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/bcm6368_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/brcmnand.h (100%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/brcmstb_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/brcmnand/iproc_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/cafe_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/cmx270_nand.c (98%)
+ rename drivers/mtd/nand/{ => raw}/cs553x_nand.c (99%)
+ rename drivers/mtd/nand/{ => raw}/davinci_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/denali.c (100%)
+ rename drivers/mtd/nand/{ => raw}/denali.h (100%)
+ rename drivers/mtd/nand/{ => raw}/denali_dt.c (100%)
+ rename drivers/mtd/nand/{ => raw}/denali_pci.c (100%)
+ rename drivers/mtd/nand/{ => raw}/diskonchip.c (99%)
+ rename drivers/mtd/nand/{ => raw}/docg4.c (100%)
+ rename drivers/mtd/nand/{ => raw}/fsl_elbc_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/fsl_ifc_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/fsl_upm.c (100%)
+ rename drivers/mtd/nand/{ => raw}/fsmc_nand.c (86%)
+ rename drivers/mtd/nand/{ => raw}/gpio.c (99%)
+ rename drivers/mtd/nand/{ => raw}/gpmi-nand/Makefile (100%)
+ rename drivers/mtd/nand/{ => raw}/gpmi-nand/bch-regs.h (100%)
+ rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-lib.c (100%)
+ rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-nand.h (100%)
+ rename drivers/mtd/nand/{ => raw}/gpmi-nand/gpmi-regs.h (100%)
+ rename drivers/mtd/nand/{ => raw}/hisi504_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/jz4740_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/jz4780_bch.c (100%)
+ rename drivers/mtd/nand/{ => raw}/jz4780_bch.h (100%)
+ rename drivers/mtd/nand/{ => raw}/jz4780_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/lpc32xx_mlc.c (100%)
+ rename drivers/mtd/nand/{ => raw}/lpc32xx_slc.c (100%)
+ rename drivers/mtd/nand/{ => raw}/marvell_nand.c (99%)
+ rename drivers/mtd/nand/{ => raw}/mpc5121_nfc.c (99%)
+ rename drivers/mtd/nand/{ => raw}/mtk_ecc.c (100%)
+ rename drivers/mtd/nand/{ => raw}/mtk_ecc.h (100%)
+ rename drivers/mtd/nand/{ => raw}/mtk_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/mxc_nand.c (88%)
+ rename drivers/mtd/nand/{ => raw}/nand_amd.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_base.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_bbt.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_bch.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_ecc.c (99%)
+ rename drivers/mtd/nand/{ => raw}/nand_hynix.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_ids.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_macronix.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_micron.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_samsung.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_timings.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nand_toshiba.c (71%)
+ rename drivers/mtd/nand/{ => raw}/nandsim.c (100%)
+ rename drivers/mtd/nand/{ => raw}/ndfc.c (100%)
+ rename drivers/mtd/nand/{ => raw}/nuc900_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/omap2.c (100%)
+ rename drivers/mtd/nand/{ => raw}/omap_elm.c (100%)
+ rename drivers/mtd/nand/{ => raw}/orion_nand.c (99%)
+ rename drivers/mtd/nand/{ => raw}/oxnas_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/pasemi_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/plat_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/pxa3xx_nand.c (99%)
+ rename drivers/mtd/nand/{ => raw}/qcom_nandc.c (100%)
+ rename drivers/mtd/nand/{ => raw}/r852.c (100%)
+ rename drivers/mtd/nand/{ => raw}/r852.h (100%)
+ rename drivers/mtd/nand/{ => raw}/s3c2410.c (99%)
+ rename drivers/mtd/nand/{ => raw}/sh_flctl.c (100%)
+ rename drivers/mtd/nand/{ => raw}/sharpsl.c (99%)
+ rename drivers/mtd/nand/{ => raw}/sm_common.c (100%)
+ rename drivers/mtd/nand/{ => raw}/sm_common.h (100%)
+ rename drivers/mtd/nand/{ => raw}/socrates_nand.c (99%)
+ rename drivers/mtd/nand/{ => raw}/sunxi_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/tango_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/tmio_nand.c (100%)
+ rename drivers/mtd/nand/{ => raw}/txx9ndfmc.c (100%)
+ rename drivers/mtd/nand/{ => raw}/vf610_nfc.c (97%)
+ rename drivers/mtd/nand/{ => raw}/xway_nand.c (100%)
+ create mode 100644 include/linux/mtd/nand.h
+Merging spi-nor/spi-nor/next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge spi-nor/spi-nor/next
+Already up to date.
+Merging crypto/master (a43a34845a15 crypto: stm32/cryp - add stm32mp1 support)
+$ git merge crypto/master
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/crypto/crypto_engine.rst        |   48 +
+ MAINTAINERS                                   |   13 +-
+ arch/x86/crypto/sha1-mb/sha1_mb.c             |   28 +-
+ arch/x86/crypto/sha1-mb/sha1_mb_ctx.h         |    8 +-
+ arch/x86/crypto/sha256-mb/sha256_mb.c         |   27 +-
+ arch/x86/crypto/sha256-mb/sha256_mb_ctx.h     |    8 +-
+ arch/x86/crypto/sha512-mb/sha512_mb.c         |   30 +-
+ arch/x86/crypto/sha512-mb/sha512_mb_ctx.h     |    8 +-
+ crypto/ahash.c                                |   18 +-
+ crypto/crypto_engine.c                        |  301 +--
+ crypto/crypto_user.c                          |    2 +-
+ crypto/mcryptd.c                              |   34 +-
+ crypto/rsa-pkcs1pad.c                         |    2 +-
+ drivers/char/hw_random/imx-rngc.c             |    2 +-
+ drivers/crypto/Kconfig                        |   27 +
+ drivers/crypto/Makefile                       |    1 +
+ drivers/crypto/bfin_crc.c                     |   12 +
+ drivers/crypto/caam/caamalg.c                 |   19 +-
+ drivers/crypto/caam/caamalg_desc.c            |  165 +-
+ drivers/crypto/caam/caamalg_desc.h            |   24 +-
+ drivers/crypto/caam/caamalg_qi.c              |  386 +++-
+ drivers/crypto/caam/qi.c                      |   11 +-
+ drivers/crypto/ccp/ccp-dmaengine.c            |    2 +-
+ drivers/crypto/ccree/Makefile                 |    7 +
+ drivers/crypto/ccree/cc_aead.c                | 2702 +++++++++++++++++++++++++
+ drivers/crypto/ccree/cc_aead.h                |  109 +
+ drivers/crypto/ccree/cc_buffer_mgr.c          | 1651 +++++++++++++++
+ drivers/crypto/ccree/cc_buffer_mgr.h          |   71 +
+ drivers/crypto/ccree/cc_cipher.c              | 1130 +++++++++++
+ drivers/crypto/ccree/cc_cipher.h              |   59 +
+ drivers/crypto/ccree/cc_crypto_ctx.h          |  169 ++
+ drivers/crypto/ccree/cc_debugfs.c             |  101 +
+ drivers/crypto/ccree/cc_debugfs.h             |   32 +
+ drivers/crypto/ccree/cc_driver.c              |  476 +++++
+ drivers/crypto/ccree/cc_driver.h              |  193 ++
+ drivers/crypto/ccree/cc_fips.c                |  111 +
+ drivers/crypto/ccree/cc_fips.h                |   36 +
+ drivers/crypto/ccree/cc_hash.c                | 2295 +++++++++++++++++++++
+ drivers/crypto/ccree/cc_hash.h                |  113 ++
+ drivers/crypto/ccree/cc_host_regs.h           |  142 ++
+ drivers/crypto/ccree/cc_hw_queue_defs.h       |  590 ++++++
+ drivers/crypto/ccree/cc_ivgen.c               |  279 +++
+ drivers/crypto/ccree/cc_ivgen.h               |   55 +
+ drivers/crypto/ccree/cc_kernel_regs.h         |  167 ++
+ drivers/crypto/ccree/cc_lli_defs.h            |   59 +
+ drivers/crypto/ccree/cc_pm.c                  |  122 ++
+ drivers/crypto/ccree/cc_pm.h                  |   56 +
+ drivers/crypto/ccree/cc_request_mgr.c         |  712 +++++++
+ drivers/crypto/ccree/cc_request_mgr.h         |   51 +
+ drivers/crypto/ccree/cc_sram_mgr.c            |  106 +
+ drivers/crypto/ccree/cc_sram_mgr.h            |   65 +
+ drivers/crypto/chelsio/chcr_algo.c            |    8 +-
+ drivers/crypto/mxs-dcp.c                      |   14 +
+ drivers/crypto/n2_core.c                      |   12 +
+ drivers/crypto/omap-aes.c                     |   21 +-
+ drivers/crypto/omap-aes.h                     |    3 +
+ drivers/crypto/omap-des.c                     |   24 +-
+ drivers/crypto/qat/qat_common/qat_asym_algs.c |    9 +-
+ drivers/crypto/stm32/stm32-cryp.c             |  964 ++++++++-
+ drivers/crypto/stm32/stm32-hash.c             |   41 +-
+ drivers/crypto/ux500/hash/hash_core.c         |   18 +
+ drivers/crypto/virtio/virtio_crypto_algs.c    |   16 +-
+ drivers/crypto/virtio/virtio_crypto_common.h  |    3 +-
+ drivers/crypto/virtio/virtio_crypto_core.c    |    3 -
+ drivers/staging/ccree/Kconfig                 |    4 +-
+ drivers/staging/ccree/Makefile                |    2 +-
+ include/crypto/engine.h                       |   68 +-
+ include/crypto/internal/hash.h                |    5 -
+ 68 files changed, 13623 insertions(+), 427 deletions(-)
+ create mode 100644 Documentation/crypto/crypto_engine.rst
+ create mode 100644 drivers/crypto/ccree/Makefile
+ create mode 100644 drivers/crypto/ccree/cc_aead.c
+ create mode 100644 drivers/crypto/ccree/cc_aead.h
+ create mode 100644 drivers/crypto/ccree/cc_buffer_mgr.c
+ create mode 100644 drivers/crypto/ccree/cc_buffer_mgr.h
+ create mode 100644 drivers/crypto/ccree/cc_cipher.c
+ create mode 100644 drivers/crypto/ccree/cc_cipher.h
+ create mode 100644 drivers/crypto/ccree/cc_crypto_ctx.h
+ create mode 100644 drivers/crypto/ccree/cc_debugfs.c
+ create mode 100644 drivers/crypto/ccree/cc_debugfs.h
+ create mode 100644 drivers/crypto/ccree/cc_driver.c
+ create mode 100644 drivers/crypto/ccree/cc_driver.h
+ create mode 100644 drivers/crypto/ccree/cc_fips.c
+ create mode 100644 drivers/crypto/ccree/cc_fips.h
+ create mode 100644 drivers/crypto/ccree/cc_hash.c
+ create mode 100644 drivers/crypto/ccree/cc_hash.h
+ create mode 100644 drivers/crypto/ccree/cc_host_regs.h
+ create mode 100644 drivers/crypto/ccree/cc_hw_queue_defs.h
+ create mode 100644 drivers/crypto/ccree/cc_ivgen.c
+ create mode 100644 drivers/crypto/ccree/cc_ivgen.h
+ create mode 100644 drivers/crypto/ccree/cc_kernel_regs.h
+ create mode 100644 drivers/crypto/ccree/cc_lli_defs.h
+ create mode 100644 drivers/crypto/ccree/cc_pm.c
+ create mode 100644 drivers/crypto/ccree/cc_pm.h
+ create mode 100644 drivers/crypto/ccree/cc_request_mgr.c
+ create mode 100644 drivers/crypto/ccree/cc_request_mgr.h
+ create mode 100644 drivers/crypto/ccree/cc_sram_mgr.c
+ create mode 100644 drivers/crypto/ccree/cc_sram_mgr.h
+Merging drm/drm-next (933519a5a269 Merge tag 'topic/hdcp-2018-02-13' of git://anongit.freedesktop.org/drm/drm-misc into drm-next)
+$ git merge drm/drm-next
+Resolved 'drivers/gpu/drm/i915/i915_pmu.c' using previous resolution.
+Resolved 'drivers/gpu/drm/i915/i915_pmu.h' using previous resolution.
+Resolved 'drivers/gpu/drm/i915/intel_breadcrumbs.c' using previous resolution.
+Removing include/drm/tinydrm/ili9341.h
+Auto-merging drivers/gpu/drm/i915/intel_engine_cs.c
+Auto-merging drivers/gpu/drm/i915/intel_cdclk.c
+Auto-merging drivers/gpu/drm/i915/intel_breadcrumbs.c
+CONFLICT (content): Merge conflict in drivers/gpu/drm/i915/intel_breadcrumbs.c
+Auto-merging drivers/gpu/drm/i915/intel_bios.c
+Auto-merging drivers/gpu/drm/i915/i915_pmu.h
+CONFLICT (content): Merge conflict in drivers/gpu/drm/i915/i915_pmu.h
+Auto-merging drivers/gpu/drm/i915/i915_pmu.c
+CONFLICT (content): Merge conflict in drivers/gpu/drm/i915/i915_pmu.c
+Auto-merging drivers/gpu/drm/i915/i915_drv.h
+Auto-merging drivers/gpu/drm/i915/i915_drv.c
+Auto-merging drivers/gpu/drm/drm_probe_helper.c
+Auto-merging drivers/gpu/drm/drm_edid.c
+Auto-merging MAINTAINERS
+Auto-merging Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 4c837d142a0776124eed65ae88f64415e56e342e] Merge remote-tracking branch 'drm/drm-next'
+$ git diff -M --stat --summary HEAD^..
+ .../bridge/{ti,ths8135.txt => ti,ths813x.txt}      |  13 +-
+ .../display/panel/arm,versatile-tft-panel.txt      |  31 +
+ .../devicetree/bindings/display/st,stm32-ltdc.txt  |   2 +-
+ MAINTAINERS                                        |   9 +-
+ drivers/dma-buf/reservation.c                      |  31 +-
+ drivers/dma-buf/sw_sync.c                          |   4 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h                |   1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c            |   6 +-
+ drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c              |   2 +
+ drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c              |   2 +
+ drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c              |   3 +
+ drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c              |   2 +
+ drivers/gpu/drm/arc/arcpgu_hdmi.c                  |   3 +-
+ drivers/gpu/drm/arc/arcpgu_sim.c                   |  16 +-
+ drivers/gpu/drm/arm/hdlcd_crtc.c                   |   5 +-
+ drivers/gpu/drm/arm/malidp_planes.c                |   6 +-
+ drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c    |  24 +-
+ drivers/gpu/drm/bridge/analogix-anx78xx.c          |   3 +-
+ drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |   6 +-
+ drivers/gpu/drm/bridge/dumb-vga-dac.c              |  59 +-
+ drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c      | 200 ++---
+ drivers/gpu/drm/drm_atomic.c                       |  14 +-
+ drivers/gpu/drm/drm_connector.c                    |  96 ++-
+ drivers/gpu/drm/drm_crtc.c                         |   6 +-
+ drivers/gpu/drm/drm_debugfs_crc.c                  |  19 +
+ drivers/gpu/drm/drm_dp_helper.c                    |   4 +
+ drivers/gpu/drm/drm_dp_mst_topology.c              |   3 +
+ drivers/gpu/drm/drm_edid.c                         |   4 +-
+ drivers/gpu/drm/drm_encoder.c                      |   4 +
+ drivers/gpu/drm/drm_fourcc.c                       |  50 +-
+ drivers/gpu/drm/drm_ioctl.c                        |   6 +-
+ drivers/gpu/drm/drm_memory.c                       |  13 +
+ drivers/gpu/drm/drm_mipi_dsi.c                     |   9 +-
+ drivers/gpu/drm/drm_modes.c                        |  62 +-
+ drivers/gpu/drm/drm_plane.c                        |   4 +
+ drivers/gpu/drm/drm_prime.c                        | 141 +++-
+ drivers/gpu/drm/drm_probe_helper.c                 |   2 +-
+ drivers/gpu/drm/drm_simple_kms_helper.c            |   5 +-
+ drivers/gpu/drm/exynos/exynos_mixer.c              |  14 +-
+ drivers/gpu/drm/i2c/sil164_drv.c                   |   3 +-
+ drivers/gpu/drm/i2c/tda998x_drv.c                  |   3 +-
+ drivers/gpu/drm/i915/Makefile                      |   2 +
+ drivers/gpu/drm/i915/i915_debugfs.c                |  85 ++-
+ drivers/gpu/drm/i915/i915_drv.c                    | 206 +++---
+ drivers/gpu/drm/i915/i915_drv.h                    |  57 +-
+ drivers/gpu/drm/i915/i915_gem.c                    | 145 +++-
+ drivers/gpu/drm/i915/i915_gem_fence_reg.c          |   8 +-
+ drivers/gpu/drm/i915/i915_gem_gtt.c                |  76 +-
+ drivers/gpu/drm/i915/i915_gem_request.c            |  30 +-
+ drivers/gpu/drm/i915/i915_gem_request.h            |  33 +-
+ drivers/gpu/drm/i915/i915_gpu_error.c              |  82 ++-
+ drivers/gpu/drm/i915/i915_irq.c                    |  82 +--
+ drivers/gpu/drm/i915/i915_params.c                 |   5 +-
+ drivers/gpu/drm/i915/i915_params.h                 |   2 +-
+ drivers/gpu/drm/i915/i915_pci.c                    |  18 +-
+ drivers/gpu/drm/i915/i915_pmu.c                    | 296 ++++++--
+ drivers/gpu/drm/i915/i915_pmu.h                    |   8 +
+ drivers/gpu/drm/i915/i915_reg.h                    | 240 +++++-
+ drivers/gpu/drm/i915/i915_sw_fence.c               |  56 +-
+ drivers/gpu/drm/i915/intel_atomic.c                |   2 +
+ drivers/gpu/drm/i915/intel_atomic_plane.c          |   9 -
+ drivers/gpu/drm/i915/intel_bios.c                  |  30 +
+ drivers/gpu/drm/i915/intel_breadcrumbs.c           | 143 ++--
+ drivers/gpu/drm/i915/intel_cdclk.c                 |  68 +-
+ drivers/gpu/drm/i915/intel_crt.c                   |   3 -
+ drivers/gpu/drm/i915/intel_csr.c                   |   5 +-
+ drivers/gpu/drm/i915/intel_ddi.c                   |  82 +++
+ drivers/gpu/drm/i915/intel_device_info.c           |   1 +
+ drivers/gpu/drm/i915/intel_device_info.h           |   2 +
+ drivers/gpu/drm/i915/intel_display.c               | 160 +++-
+ drivers/gpu/drm/i915/intel_display.h               |   4 +
+ drivers/gpu/drm/i915/intel_dp.c                    | 540 +++++++++++---
+ drivers/gpu/drm/i915/intel_drv.h                   | 119 ++-
+ drivers/gpu/drm/i915/intel_dsi.c                   |   5 -
+ drivers/gpu/drm/i915/intel_dvo.c                   |   3 -
+ drivers/gpu/drm/i915/intel_engine_cs.c             |   8 +-
+ drivers/gpu/drm/i915/intel_fbc.c                   |  30 +-
+ drivers/gpu/drm/i915/intel_guc.c                   |  47 +-
+ drivers/gpu/drm/i915/intel_guc_ads.c               | 151 ++++
+ drivers/gpu/drm/i915/intel_guc_ads.h               |  33 +
+ drivers/gpu/drm/i915/intel_guc_log.c               | 297 +++++---
+ drivers/gpu/drm/i915/intel_guc_log.h               |  14 +-
+ drivers/gpu/drm/i915/intel_guc_submission.c        | 134 ----
+ drivers/gpu/drm/i915/intel_hangcheck.c             |   2 +-
+ drivers/gpu/drm/i915/intel_hdcp.c                  | 807 +++++++++++++++++++++
+ drivers/gpu/drm/i915/intel_hdmi.c                  | 296 +++++++-
+ drivers/gpu/drm/i915/intel_hotplug.c               |  19 +-
+ drivers/gpu/drm/i915/intel_i2c.c                   |  98 ++-
+ drivers/gpu/drm/i915/intel_lrc.c                   | 245 ++++---
+ drivers/gpu/drm/i915/intel_lrc.h                   |   1 +
+ drivers/gpu/drm/i915/intel_lrc_reg.h               |  67 ++
+ drivers/gpu/drm/i915/intel_lspcon.c                |   3 +-
+ drivers/gpu/drm/i915/intel_modes.c                 |  17 -
+ drivers/gpu/drm/i915/intel_panel.c                 |   8 +-
+ drivers/gpu/drm/i915/intel_pm.c                    | 101 ++-
+ drivers/gpu/drm/i915/intel_psr.c                   |  54 +-
+ drivers/gpu/drm/i915/intel_runtime_pm.c            |  46 ++
+ drivers/gpu/drm/i915/intel_sdvo.c                  |   3 -
+ drivers/gpu/drm/i915/intel_sprite.c                | 120 ++-
+ drivers/gpu/drm/i915/intel_uc.c                    |  92 ++-
+ drivers/gpu/drm/i915/intel_uc.h                    |   4 +-
+ drivers/gpu/drm/i915/intel_uncore.c                |  28 +-
+ drivers/gpu/drm/i915/intel_uncore.h                |  14 +-
+ drivers/gpu/drm/i915/intel_vbt_defs.h              |  13 +-
+ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c      | 114 ++-
+ drivers/gpu/drm/i915/selftests/i915_random.c       |   3 +-
+ drivers/gpu/drm/i915/selftests/i915_sw_fence.c     | 134 ++++
+ drivers/gpu/drm/i915/selftests/intel_hangcheck.c   | 105 ++-
+ drivers/gpu/drm/i915/selftests/mock_context.c      |  11 +
+ drivers/gpu/drm/i915/selftests/mock_context.h      |   3 +
+ drivers/gpu/drm/imx/ipuv3-plane.c                  |  10 +-
+ drivers/gpu/drm/mediatek/mtk_drm_plane.c           |   5 +-
+ drivers/gpu/drm/meson/meson_plane.c                |   5 +-
+ drivers/gpu/drm/mgag200/mgag200_mode.c             |   4 +-
+ drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c          |  20 +-
+ drivers/gpu/drm/nouveau/nv50_display.c             |  20 +-
+ drivers/gpu/drm/panel/Kconfig                      |  10 +
+ drivers/gpu/drm/panel/Makefile                     |   1 +
+ drivers/gpu/drm/panel/panel-arm-versatile.c        | 377 ++++++++++
+ .../gpu/drm/panel/panel-panasonic-vvx10f034n00.c   |  16 +-
+ drivers/gpu/drm/pl111/Kconfig                      |   1 +
+ drivers/gpu/drm/pl111/pl111_display.c              |  64 +-
+ drivers/gpu/drm/pl111/pl111_drm.h                  |   8 +
+ drivers/gpu/drm/pl111/pl111_drv.c                  | 138 ++--
+ drivers/gpu/drm/pl111/pl111_versatile.c            |  86 ++-
+ drivers/gpu/drm/radeon/radeon.h                    |   1 +
+ drivers/gpu/drm/radeon/radeon_device.c             |   2 +
+ drivers/gpu/drm/radeon/radeon_ttm.c                |   6 +-
+ drivers/gpu/drm/rcar-du/rcar_du_plane.c            |   9 +-
+ drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |  22 +-
+ drivers/gpu/drm/stm/drv.c                          |  20 +-
+ drivers/gpu/drm/stm/dw_mipi_dsi-stm.c              |  53 +-
+ drivers/gpu/drm/stm/ltdc.c                         | 118 ++-
+ drivers/gpu/drm/stm/ltdc.h                         |   1 +
+ drivers/gpu/drm/sun4i/Makefile                     |   3 +-
+ drivers/gpu/drm/sun4i/sun4i_backend.c              | 248 ++++++-
+ drivers/gpu/drm/sun4i/sun4i_backend.h              |  18 +-
+ drivers/gpu/drm/sun4i/sun4i_crtc.c                 |  21 +-
+ drivers/gpu/drm/sun4i/sun4i_drv.c                  |  27 +-
+ drivers/gpu/drm/sun4i/sun4i_drv.h                  |   1 +
+ drivers/gpu/drm/sun4i/sun4i_framebuffer.c          |  24 +-
+ drivers/gpu/drm/sun4i/sun4i_frontend.c             | 389 ++++++++++
+ drivers/gpu/drm/sun4i/sun4i_frontend.h             |  99 +++
+ drivers/gpu/drm/sun4i/sun4i_layer.c                | 117 ++-
+ drivers/gpu/drm/sun4i/sun4i_layer.h                |  11 +
+ drivers/gpu/drm/sun4i/sun4i_tcon.c                 |   4 +
+ drivers/gpu/drm/sun4i/sun8i_ui_layer.c             |   9 +-
+ drivers/gpu/drm/sun4i/sun8i_vi_layer.c             |   9 +-
+ drivers/gpu/drm/sun4i/sunxi_engine.h               |  90 +++
+ drivers/gpu/drm/tegra/plane.c                      |   9 +-
+ drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c        |  34 +-
+ drivers/gpu/drm/tinydrm/ili9225.c                  |   6 +-
+ drivers/gpu/drm/tinydrm/mi0283qt.c                 | 106 ++-
+ drivers/gpu/drm/tinydrm/mipi-dbi.c                 | 101 ++-
+ drivers/gpu/drm/tinydrm/st7586.c                   |  15 +-
+ drivers/gpu/drm/tinydrm/st7735r.c                  |  11 +-
+ drivers/gpu/drm/vc4/Makefile                       |   1 +
+ drivers/gpu/drm/vc4/vc4_drv.c                      |  26 +
+ drivers/gpu/drm/vc4/vc4_drv.h                      |  68 ++
+ drivers/gpu/drm/vc4/vc4_gem.c                      |  48 +-
+ drivers/gpu/drm/vc4/vc4_irq.c                      |  40 +-
+ drivers/gpu/drm/vc4/vc4_perfmon.c                  | 188 +++++
+ drivers/gpu/drm/vc4/vc4_plane.c                    |  23 +-
+ drivers/gpu/drm/vc4/vc4_regs.h                     |  35 +-
+ drivers/gpu/drm/vc4/vc4_v3d.c                      |  64 +-
+ drivers/gpu/drm/virtio/virtgpu_ioctl.c             |   2 +
+ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c                |   7 +-
+ drivers/gpu/drm/zte/zx_plane.c                     |  18 +-
+ include/drm/bridge/dw_mipi_dsi.h                   |  17 +-
+ include/drm/drm_bridge.h                           |  35 +-
+ include/drm/drm_cache.h                            |   2 +
+ include/drm/drm_connector.h                        |  16 +
+ include/drm/drm_dp_helper.h                        |  35 +
+ include/drm/drm_fourcc.h                           |   2 +
+ include/drm/drm_hdcp.h                             |  41 ++
+ include/drm/drm_mode_config.h                      |  12 +
+ include/drm/drm_modes.h                            |  24 +-
+ include/drm/drm_prime.h                            |  22 +
+ include/drm/i915_component.h                       |   3 +-
+ include/drm/i915_pciids.h                          |  18 +-
+ include/drm/tinydrm/ili9341.h                      |  54 --
+ include/drm/tinydrm/mipi-dbi.h                     |   5 +-
+ include/uapi/drm/drm_mode.h                        |  34 +-
+ include/uapi/drm/i915_drm.h                        |   4 +-
+ include/uapi/drm/vc4_drm.h                         |  76 ++
+ 185 files changed, 7861 insertions(+), 2027 deletions(-)
+ rename Documentation/devicetree/bindings/display/bridge/{ti,ths8135.txt => ti,ths813x.txt} (69%)
+ create mode 100644 Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt
+ create mode 100644 drivers/gpu/drm/i915/intel_guc_ads.c
+ create mode 100644 drivers/gpu/drm/i915/intel_guc_ads.h
+ create mode 100644 drivers/gpu/drm/i915/intel_hdcp.c
+ create mode 100644 drivers/gpu/drm/i915/intel_lrc_reg.h
+ create mode 100644 drivers/gpu/drm/panel/panel-arm-versatile.c
+ create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
+ create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
+ create mode 100644 drivers/gpu/drm/vc4/vc4_perfmon.c
+ create mode 100644 include/drm/drm_hdcp.h
+ delete mode 100644 include/drm/tinydrm/ili9341.h
+Merging drm-panel/drm/panel/for-next (e4bac408b084 drm/panel: simple: Add support for Winstar WF35LTIACD)
+$ git merge drm-panel/drm/panel/for-next
+Already up to date.
+Merging drm-intel/for-linux-next (be3fa6685705 drm/i915/: Initialise trans_min for skl_compute_transition_wm())
+$ git merge drm-intel/for-linux-next
+Auto-merging include/drm/drm_atomic.h
+Auto-merging drivers/gpu/drm/i915/intel_uncore.h
+Auto-merging drivers/gpu/drm/i915/intel_uncore.c
+Auto-merging drivers/gpu/drm/i915/intel_sprite.c
+Auto-merging drivers/gpu/drm/i915/intel_sdvo.c
+Auto-merging drivers/gpu/drm/i915/intel_engine_cs.c
+Auto-merging drivers/gpu/drm/i915/intel_dvo.c
+Auto-merging drivers/gpu/drm/i915/intel_drv.h
+Auto-merging drivers/gpu/drm/i915/intel_dp.c
+Auto-merging drivers/gpu/drm/i915/intel_display.c
+Auto-merging drivers/gpu/drm/i915/intel_ddi.c
+Auto-merging drivers/gpu/drm/i915/intel_crt.c
+Auto-merging drivers/gpu/drm/i915/intel_bios.c
+Auto-merging drivers/gpu/drm/i915/intel_atomic.c
+Auto-merging drivers/gpu/drm/i915/i915_reg.h
+Auto-merging drivers/gpu/drm/i915/i915_gem_context.c
+Auto-merging drivers/gpu/drm/i915/i915_drv.h
+Auto-merging drivers/gpu/drm/i915/i915_drv.c
+Auto-merging drivers/gpu/drm/i915/gvt/dmabuf.c
+Auto-merging drivers/gpu/drm/i915/Makefile
+Auto-merging drivers/gpu/drm/drm_plane.c
+Merge made by the 'recursive' strategy.
+ drivers/gpu/drm/amd/amdgpu/amdgpu_display.c       |   2 +-
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   4 +-
+ drivers/gpu/drm/drm_plane.c                       |   2 +-
+ drivers/gpu/drm/drm_vblank.c                      |  85 ++++++-
+ drivers/gpu/drm/i915/Makefile                     |   1 +
+ drivers/gpu/drm/i915/dvo_ivch.c                   |  28 +--
+ drivers/gpu/drm/i915/gvt/dmabuf.c                 |   4 +-
+ drivers/gpu/drm/i915/i915_debugfs.c               |  52 ++---
+ drivers/gpu/drm/i915/i915_drv.c                   | 266 +++++++++++-----------
+ drivers/gpu/drm/i915/i915_drv.h                   |  31 +--
+ drivers/gpu/drm/i915/i915_gem.c                   |  91 ++++----
+ drivers/gpu/drm/i915/i915_gem_clflush.c           |   2 +-
+ drivers/gpu/drm/i915/i915_gem_context.c           |  38 ++--
+ drivers/gpu/drm/i915/i915_gem_context.h           |   3 +
+ drivers/gpu/drm/i915/i915_gem_dmabuf.c            |   4 +-
+ drivers/gpu/drm/i915/i915_gem_execbuffer.c        |  24 +-
+ drivers/gpu/drm/i915/i915_gem_fence_reg.c         |   2 +-
+ drivers/gpu/drm/i915/i915_gem_gtt.c               |  38 ++--
+ drivers/gpu/drm/i915/i915_gem_internal.c          |   8 +-
+ drivers/gpu/drm/i915/i915_gem_object.h            |  15 ++
+ drivers/gpu/drm/i915/i915_gem_request.c           |  42 +++-
+ drivers/gpu/drm/i915/i915_gem_stolen.c            |   4 +-
+ drivers/gpu/drm/i915/i915_gem_userptr.c           |  10 +-
+ drivers/gpu/drm/i915/i915_gpu_error.c             |  33 +--
+ drivers/gpu/drm/i915/i915_ioc32.c                 |  27 +--
+ drivers/gpu/drm/i915/i915_irq.c                   | 113 +++++----
+ drivers/gpu/drm/i915/i915_pci.c                   | 110 +++++----
+ drivers/gpu/drm/i915/i915_reg.h                   |  79 +++++--
+ drivers/gpu/drm/i915/i915_syncmap.c               |  16 +-
+ drivers/gpu/drm/i915/intel_atomic.c               |   5 +-
+ drivers/gpu/drm/i915/intel_audio.c                |   8 +-
+ drivers/gpu/drm/i915/intel_bios.c                 |   2 +-
+ drivers/gpu/drm/i915/intel_cdclk.c                | 239 ++++++++++++++++++-
+ drivers/gpu/drm/i915/intel_crt.c                  |  13 +-
+ drivers/gpu/drm/i915/intel_ddi.c                  |   2 +-
+ drivers/gpu/drm/i915/intel_device_info.c          |   6 +
+ drivers/gpu/drm/i915/intel_device_info.h          |   7 +
+ drivers/gpu/drm/i915/intel_display.c              |  52 +++--
+ drivers/gpu/drm/i915/intel_dp.c                   |   6 +-
+ drivers/gpu/drm/i915/intel_dpio_phy.c             |   2 +-
+ drivers/gpu/drm/i915/intel_drv.h                  |  10 +-
+ drivers/gpu/drm/i915/intel_dvo.c                  |  28 +--
+ drivers/gpu/drm/i915/intel_engine_cs.c            | 172 +++++++-------
+ drivers/gpu/drm/i915/intel_guc_submission.c       |  57 +++--
+ drivers/gpu/drm/i915/intel_huc.c                  |   3 +-
+ drivers/gpu/drm/i915/intel_lpe_audio.c            |  14 +-
+ drivers/gpu/drm/i915/intel_lrc.c                  |  28 ++-
+ drivers/gpu/drm/i915/intel_lvds.c                 |  44 ++--
+ drivers/gpu/drm/i915/intel_mocs.c                 |   2 +-
+ drivers/gpu/drm/i915/intel_panel.c                |  12 +-
+ drivers/gpu/drm/i915/intel_pm.c                   |  90 ++++++--
+ drivers/gpu/drm/i915/intel_psr.c                  |   4 +-
+ drivers/gpu/drm/i915/intel_ringbuffer.c           |  30 +--
+ drivers/gpu/drm/i915/intel_ringbuffer.h           |  11 +-
+ drivers/gpu/drm/i915/intel_runtime_pm.c           | 161 +++++++++++--
+ drivers/gpu/drm/i915/intel_sdvo.c                 |  82 ++++---
+ drivers/gpu/drm/i915/intel_sprite.c               |   7 +-
+ drivers/gpu/drm/i915/intel_tv.c                   |  28 +--
+ drivers/gpu/drm/i915/intel_uc_fw.c                |   5 +-
+ drivers/gpu/drm/i915/intel_uncore.c               |  23 +-
+ drivers/gpu/drm/i915/intel_uncore.h               |   5 +
+ drivers/gpu/drm/i915/selftests/huge_gem_object.c  |   4 +-
+ drivers/gpu/drm/i915/selftests/huge_pages.c       |   8 +-
+ drivers/gpu/drm/i915/selftests/i915_gem_context.c |   4 +-
+ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c     |   6 +-
+ drivers/gpu/drm/i915/selftests/i915_gem_object.c  |  18 +-
+ drivers/gpu/drm/i915/selftests/intel_guc.c        |  20 +-
+ drivers/gpu/drm/i915/selftests/mock_gem_device.c  |   6 -
+ drivers/gpu/drm/radeon/radeon_display.c           |   2 +-
+ drivers/gpu/drm/tegra/dc.c                        |   2 +-
+ include/drm/drm_atomic.h                          |   2 +-
+ include/drm/drm_gem.h                             |  15 --
+ include/drm/drm_vblank.h                          |   4 +-
+ include/drm/i915_pciids.h                         |  15 +-
+ 74 files changed, 1547 insertions(+), 851 deletions(-)
+Merging drm-tegra/drm/tegra/for-next (8f62142e490d drm/tegra: dc: Properly cleanup overlay planes)
+$ git merge drm-tegra/drm/tegra/for-next
+Already up to date.
+$ git am -3 ../patches/0001-mtd-nand-fix-up-for-raw-Kconfig-move.patch
+Applying: mtd: nand: fix up for raw Kconfig move
+$ git reset HEAD^
+Unstaged changes after reset:
+M	drivers/mtd/nand/raw/Kconfig
+$ git add -A .
+$ git commit -v -a --amend
+[master b556bcd658ea] Merge remote-tracking branch 'drm-intel/for-linux-next'
+ Date: Tue Feb 20 09:46:38 2018 +1100
+Merging drm-misc/for-linux-next (761e05a702f5 drm: Check for lessee in DROP_MASTER ioctl)
+$ git merge drm-misc/for-linux-next
+Already up to date.
+Merging drm-msm/msm-next (8fe2938c9bac drm/msm: Trigger fence completion from GPU)
+$ git merge drm-msm/msm-next
+Auto-merging drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
+Auto-merging drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+Auto-merging drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
+Auto-merging drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h
+Auto-merging drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+Auto-merging drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/display/msm/dsi.txt        |  26 +-
+ drivers/gpu/drm/msm/Kconfig                        |  20 +
+ drivers/gpu/drm/msm/Makefile                       |  50 +-
+ drivers/gpu/drm/msm/adreno/a3xx_gpu.c              |   9 +-
+ drivers/gpu/drm/msm/adreno/a4xx_gpu.c              |   9 +-
+ drivers/gpu/drm/msm/adreno/a5xx_debugfs.c          | 187 +++++
+ drivers/gpu/drm/msm/adreno/a5xx_gpu.c              |  99 ++-
+ drivers/gpu/drm/msm/adreno/a5xx_gpu.h              |   4 +
+ drivers/gpu/drm/msm/adreno/a5xx_power.c            |  26 +-
+ drivers/gpu/drm/msm/adreno/adreno_device.c         |  50 +-
+ drivers/gpu/drm/msm/adreno/adreno_gpu.c            |  70 +-
+ drivers/gpu/drm/msm/adreno/adreno_gpu.h            |  14 +-
+ drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4.xml.h  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_crtc.c |   6 +-
+ .../drm/msm/{mdp => disp}/mdp4/mdp4_dsi_encoder.c  |   0
+ .../drm/msm/{mdp => disp}/mdp4/mdp4_dtv_encoder.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_irq.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_kms.c  |   2 +-
+ drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_kms.h  |   2 +-
+ .../drm/msm/{mdp => disp}/mdp4/mdp4_lcdc_encoder.c |   0
+ .../msm/{mdp => disp}/mdp4/mdp4_lvds_connector.c   |   0
+ .../gpu/drm/msm/{mdp => disp}/mdp4/mdp4_lvds_pll.c |   0
+ .../gpu/drm/msm/{mdp => disp}/mdp4/mdp4_plane.c    |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5.xml.h  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_cfg.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_cfg.h  |   0
+ .../drm/msm/{mdp => disp}/mdp5/mdp5_cmd_encoder.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_crtc.c |   2 +-
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_ctl.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_ctl.h  |   0
+ .../gpu/drm/msm/{mdp => disp}/mdp5/mdp5_encoder.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_irq.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_kms.c  |   2 +-
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_kms.h  |   2 +-
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_mdss.c |   0
+ .../gpu/drm/msm/{mdp => disp}/mdp5/mdp5_mixer.c    |   0
+ .../gpu/drm/msm/{mdp => disp}/mdp5/mdp5_mixer.h    |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_pipe.c |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_pipe.h |   0
+ .../gpu/drm/msm/{mdp => disp}/mdp5/mdp5_plane.c    |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_smp.c  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_smp.h  |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp_common.xml.h |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp_format.c     |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp_kms.c        |   0
+ drivers/gpu/drm/msm/{mdp => disp}/mdp_kms.h        |   0
+ drivers/gpu/drm/msm/dsi/dsi.c                      |  25 +-
+ drivers/gpu/drm/msm/dsi/dsi.h                      |   1 +
+ drivers/gpu/drm/msm/dsi/dsi.xml.h                  | 187 ++++-
+ drivers/gpu/drm/msm/dsi/dsi_cfg.c                  |  19 +
+ drivers/gpu/drm/msm/dsi/dsi_cfg.h                  |   1 +
+ drivers/gpu/drm/msm/dsi/dsi_host.c                 |  47 +-
+ drivers/gpu/drm/msm/dsi/dsi_manager.c              |   6 +-
+ drivers/gpu/drm/msm/dsi/phy/dsi_phy.c              |  10 +-
+ drivers/gpu/drm/msm/dsi/phy/dsi_phy.h              |   1 +
+ drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c         | 251 +++++++
+ drivers/gpu/drm/msm/dsi/pll/dsi_pll.c              |   5 +-
+ drivers/gpu/drm/msm/dsi/pll/dsi_pll.h              |   9 +
+ drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c         | 822 +++++++++++++++++++++
+ drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c               |   2 +-
+ drivers/gpu/drm/msm/msm_debugfs.c                  |   5 +-
+ drivers/gpu/drm/msm/msm_drv.c                      |  20 +-
+ drivers/gpu/drm/msm/msm_drv.h                      |   1 -
+ drivers/gpu/drm/msm/msm_fb.c                       |   6 +-
+ drivers/gpu/drm/msm/msm_fence.h                    |   2 -
+ drivers/gpu/drm/msm/msm_gem.c                      |  13 +-
+ drivers/gpu/drm/msm/msm_gem.h                      |   1 +
+ drivers/gpu/drm/msm/msm_gem_submit.c               |   9 +
+ drivers/gpu/drm/msm/msm_gem_vma.c                  |   4 +-
+ drivers/gpu/drm/msm/msm_gpu.c                      |  12 +-
+ drivers/gpu/drm/msm/msm_gpu.h                      |   2 +
+ drivers/gpu/drm/msm/msm_ringbuffer.c               |   2 +-
+ include/uapi/drm/msm_drm.h                         |   2 +
+ 73 files changed, 1839 insertions(+), 206 deletions(-)
+ create mode 100644 drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4.xml.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_crtc.c (99%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_dsi_encoder.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_dtv_encoder.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_irq.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_kms.c (99%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_kms.h (99%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_lcdc_encoder.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_lvds_connector.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_lvds_pll.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp4/mdp4_plane.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5.xml.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_cfg.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_cfg.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_cmd_encoder.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_crtc.c (99%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_ctl.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_ctl.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_encoder.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_irq.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_kms.c (99%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_kms.h (99%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_mdss.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_mixer.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_mixer.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_pipe.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_pipe.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_plane.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_smp.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp5/mdp5_smp.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp_common.xml.h (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp_format.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp_kms.c (100%)
+ rename drivers/gpu/drm/msm/{mdp => disp}/mdp_kms.h (100%)
+ create mode 100644 drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+ create mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
+Merging hdlcd/for-upstream/hdlcd (f73e8b825315 drm/arm: Replace instances of drm_dev_unref with drm_dev_put.)
+$ git merge hdlcd/for-upstream/hdlcd
+Already up to date.
+Merging mali-dp/for-upstream/mali-dp (54243016ae35 drm: mali-dp: Disable planes when their CRTC gets disabled.)
+$ git merge mali-dp/for-upstream/mali-dp
+Already up to date.
+Merging sunxi-drm/sunxi-drm/for-next (7dafb83edd32 Merge branches 'sunxi/drm-fixes-for-4.13' and 'sunxi/drm-for-4.14' into sunxi-drm/for-next)
+$ git merge sunxi-drm/sunxi-drm/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging imx-drm/imx-drm/next (3addaba8141b gpu: ipu-v3: prg: fix device node leak in ipu_prg_lookup_by_phandle)
+$ git merge imx-drm/imx-drm/next
+Merge made by the 'recursive' strategy.
+ drivers/gpu/ipu-v3/ipu-common.c | 4 ++--
+ drivers/gpu/ipu-v3/ipu-cpmem.c  | 1 +
+ drivers/gpu/ipu-v3/ipu-pre.c    | 3 +++
+ drivers/gpu/ipu-v3/ipu-prg.c    | 3 +++
+ 4 files changed, 9 insertions(+), 2 deletions(-)
+Merging etnaviv/etnaviv/next (246774d17fc0 drm/etnaviv: remove the need for a gpu-subsystem DT node)
+$ git merge etnaviv/etnaviv/next
+Merge made by the 'recursive' strategy.
+ .../bindings/display/etnaviv/etnaviv-drm.txt       |  24 +-
+ drivers/gpu/drm/etnaviv/Kconfig                    |   1 +
+ drivers/gpu/drm/etnaviv/Makefile                   |   3 +-
+ drivers/gpu/drm/etnaviv/etnaviv_drv.c              |  52 ++--
+ drivers/gpu/drm/etnaviv/etnaviv_drv.h              |   7 +-
+ drivers/gpu/drm/etnaviv/etnaviv_dump.c             |  21 +-
+ drivers/gpu/drm/etnaviv/etnaviv_gem.h              |   5 +
+ drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c       |  68 ++---
+ drivers/gpu/drm/etnaviv/etnaviv_gpu.c              | 275 ++++++---------------
+ drivers/gpu/drm/etnaviv/etnaviv_gpu.h              |  29 +--
+ drivers/gpu/drm/etnaviv/etnaviv_iommu.c            |   2 +-
+ drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c         |   2 +-
+ drivers/gpu/drm/etnaviv/etnaviv_mmu.c              |   4 +-
+ drivers/gpu/drm/etnaviv/etnaviv_sched.c            | 169 +++++++++++++
+ drivers/gpu/drm/etnaviv/etnaviv_sched.h            |  35 +++
+ 15 files changed, 397 insertions(+), 300 deletions(-)
+ create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_sched.c
+ create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_sched.h
+Merging kconfig/for-next (bebc6082da0a Linux 4.14)
+$ git merge kconfig/for-next
+Already up to date.
+Merging regmap/for-next (9e4e3b86e5ef Merge remote-tracking branch 'regmap/topic/bulk' into regmap-next)
+$ git merge regmap/for-next
+Merge made by the 'recursive' strategy.
+ drivers/base/regmap/regmap-i2c.c |   4 -
+ drivers/base/regmap/regmap.c     | 165 ++++++++++++++++-----------------------
+ 2 files changed, 69 insertions(+), 100 deletions(-)
+Merging sound/for-next (04f8773a3e98 ALSA: emu10k1: add a IOMMU workaround)
+$ git merge sound/for-next
+Merge made by the 'recursive' strategy.
+ include/sound/emu10k1.h          |   4 +-
+ include/sound/hdaudio.h          |   2 +
+ sound/hda/hdac_device.c          |  35 ++++++++++++++
+ sound/pci/emu10k1/emu10k1_main.c |  71 ++++++++++++++++++++-------
+ sound/pci/emu10k1/emupcm.c       |  10 +++-
+ sound/pci/emu10k1/memory.c       | 101 ++++++++++++++++++++++++++++++---------
+ sound/pci/hda/hda_codec.c        |  28 +----------
+ sound/pci/hda/hda_local.h        |   6 ++-
+ 8 files changed, 186 insertions(+), 71 deletions(-)
+Merging sound-asoc/for-next (5a1dec3a8d43 Merge remote-tracking branches 'asoc/topic/wm9712', 'asoc/topic/wm9713', 'asoc/topic/wm9867', 'asoc/topic/wm_adsp' and 'asoc/topic/zx_aud96p22' into asoc-next)
+$ git merge sound-asoc/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/sound/ak4458.txt |   23 +
+ Documentation/devicetree/bindings/sound/ak5558.txt |   22 +
+ Documentation/devicetree/bindings/sound/dmic.txt   |    2 +
+ Documentation/devicetree/bindings/sound/rt5665.txt |    4 +-
+ .../bindings/sound/samsung,tm2-audio.txt           |   14 +-
+ .../devicetree/bindings/sound/samsung-i2s.txt      |   22 +-
+ .../devicetree/bindings/sound/uniphier,aio.txt     |   36 +
+ MAINTAINERS                                        |    8 +
+ drivers/gpu/drm/vc4/vc4_hdmi.c                     |   47 +-
+ include/sound/dmaengine_pcm.h                      |    2 +
+ include/sound/rt5659.h                             |    1 +
+ include/sound/soc.h                                |   13 +-
+ sound/soc/amd/Kconfig                              |    9 +
+ sound/soc/amd/Makefile                             |    2 +
+ sound/soc/amd/acp-da7219-max98357a.c               |  246 +++++
+ sound/soc/amd/acp-pcm-dma.c                        |  202 ++--
+ sound/soc/amd/acp-rt5645.c                         |    4 +-
+ sound/soc/amd/acp.h                                |    8 +-
+ sound/soc/atmel/atmel-classd.c                     |   58 +-
+ sound/soc/atmel/atmel-pcm-pdc.c                    |    6 +-
+ sound/soc/atmel/atmel-pdmic.c                      |   60 +-
+ sound/soc/au1x/dbdma2.c                            |   13 +-
+ sound/soc/au1x/dma.c                               |   12 +-
+ sound/soc/bcm/cygnus-pcm.c                         |    7 +-
+ sound/soc/blackfin/bf5xx-ac97-pcm.c                |    6 +-
+ sound/soc/blackfin/bf5xx-i2s-pcm.c                 |    6 +-
+ sound/soc/codecs/88pm860x-codec.c                  |  166 +--
+ sound/soc/codecs/88pm860x-codec.h                  |    4 +-
+ sound/soc/codecs/Kconfig                           |   12 +
+ sound/soc/codecs/Makefile                          |    5 +-
+ sound/soc/codecs/ab8500-codec.c                    |  295 +++---
+ sound/soc/codecs/ac97.c                            |   46 +-
+ sound/soc/codecs/ad1836.c                          |   68 +-
+ sound/soc/codecs/ad193x-i2c.c                      |    7 -
+ sound/soc/codecs/ad193x-spi.c                      |    7 -
+ sound/soc/codecs/ad193x.c                          |   46 +-
+ sound/soc/codecs/ad1980.c                          |   87 +-
+ sound/soc/codecs/ad73311.c                         |   27 +-
+ sound/soc/codecs/adau1373.c                        |   84 +-
+ sound/soc/codecs/adau1701.c                        |  101 +-
+ sound/soc/codecs/adau1761.c                        |   88 +-
+ sound/soc/codecs/adau1781.c                        |   51 +-
+ sound/soc/codecs/adau17x1.c                        |   69 +-
+ sound/soc/codecs/adau17x1.h                        |    8 +-
+ sound/soc/codecs/adau1977-i2c.c                    |    7 -
+ sound/soc/codecs/adau1977-spi.c                    |    7 -
+ sound/soc/codecs/adau1977.c                        |   59 +-
+ sound/soc/codecs/adau7002.c                        |   30 +-
+ sound/soc/codecs/adav801.c                         |    7 -
+ sound/soc/codecs/adav803.c                         |    7 -
+ sound/soc/codecs/adav80x.c                         |  130 +--
+ sound/soc/codecs/ads117x.c                         |   27 +-
+ sound/soc/codecs/ak4104.c                          |   68 +-
+ sound/soc/codecs/ak4458.c                          |  658 ++++++++++++
+ sound/soc/codecs/ak4458.h                          |   86 ++
+ sound/soc/codecs/ak4535.c                          |   78 +-
+ sound/soc/codecs/ak4554.c                          |   27 +-
+ sound/soc/codecs/ak4613.c                          |   72 +-
+ sound/soc/codecs/ak4641.c                          |   91 +-
+ sound/soc/codecs/ak4642.c                          |  104 +-
+ sound/soc/codecs/ak4671.c                          |   67 +-
+ sound/soc/codecs/ak5386.c                          |   62 +-
+ sound/soc/codecs/ak5558.c                          |  416 ++++++++
+ sound/soc/codecs/ak5558.h                          |   52 +
+ sound/soc/codecs/alc5623.c                         |  147 ++-
+ sound/soc/codecs/alc5632.c                         |  138 ++-
+ sound/soc/codecs/arizona.c                         |  208 ++--
+ sound/soc/codecs/arizona.h                         |   24 +-
+ sound/soc/codecs/bt-sco.c                          |   21 +-
+ sound/soc/codecs/cq93vc.c                          |   33 +-
+ sound/soc/codecs/cs35l32.c                         |   45 +-
+ sound/soc/codecs/cs35l33.c                         |  186 ++--
+ sound/soc/codecs/cs35l34.c                         |  127 ++-
+ sound/soc/codecs/cs35l35.c                         |  104 +-
+ sound/soc/codecs/cs4265.c                          |   98 +-
+ sound/soc/codecs/cs4270.c                          |  124 +--
+ sound/soc/codecs/cs4271-i2c.c                      |    7 -
+ sound/soc/codecs/cs4271-spi.c                      |    7 -
+ sound/soc/codecs/cs4271.c                          |  105 +-
+ sound/soc/codecs/cs42l42.c                         |  154 ++-
+ sound/soc/codecs/cs42l42.h                         |    2 +-
+ sound/soc/codecs/cs42l51-i2c.c                     |    8 -
+ sound/soc/codecs/cs42l51.c                         |   81 +-
+ sound/soc/codecs/cs42l52.c                         |  146 ++-
+ sound/soc/codecs/cs42l56.c                         |  158 ++-
+ sound/soc/codecs/cs42l73.c                         |  122 +--
+ sound/soc/codecs/cs42xx8-i2c.c                     |    1 -
+ sound/soc/codecs/cs42xx8.c                         |   57 +-
+ sound/soc/codecs/cs43130.c                         |  243 ++---
+ sound/soc/codecs/cs43130.h                         |    2 +-
+ sound/soc/codecs/cs4349.c                          |   39 +-
+ sound/soc/codecs/cs47l24.c                         |  120 +--
+ sound/soc/codecs/cs53l30.c                         |   57 +-
+ sound/soc/codecs/cx20442.c                         |   89 +-
+ sound/soc/codecs/da7210.c                          |  181 ++--
+ sound/soc/codecs/da7213.c                          |  328 +++---
+ sound/soc/codecs/da7218.c                          |  498 +++++----
+ sound/soc/codecs/da7218.h                          |    2 +-
+ sound/soc/codecs/da7219-aad.c                      |  236 ++---
+ sound/soc/codecs/da7219-aad.h                      |   12 +-
+ sound/soc/codecs/da7219.c                          |  307 +++---
+ sound/soc/codecs/da7219.h                          |    2 +-
+ sound/soc/codecs/da732x.c                          |  241 ++---
+ sound/soc/codecs/da9055.c                          |  186 ++--
+ sound/soc/codecs/dmic.c                            |   92 +-
+ sound/soc/codecs/es7134.c                          |   27 +-
+ sound/soc/codecs/es8316.c                          |   80 +-
+ sound/soc/codecs/es8328-i2c.c                      |    7 -
+ sound/soc/codecs/es8328-spi.c                      |    7 -
+ sound/soc/codecs/es8328.c                          |  147 ++-
+ sound/soc/codecs/gtm601.c                          |   28 +-
+ sound/soc/codecs/hdac_hdmi.c                       |   65 +-
+ sound/soc/codecs/hdac_hdmi.h                       |    2 +-
+ sound/soc/codecs/hdmi-codec.c                      |   23 +-
+ sound/soc/codecs/ics43432.c                        |   16 +-
+ sound/soc/codecs/inno_rk3036.c                     |   70 +-
+ sound/soc/codecs/isabelle.c                        |   57 +-
+ sound/soc/codecs/jz4740.c                          |   50 +-
+ sound/soc/codecs/lm49453.c                         |   65 +-
+ sound/soc/codecs/max98088.c                        |  314 +++---
+ sound/soc/codecs/max98090.c                        |  319 +++---
+ sound/soc/codecs/max98090.h                        |    4 +-
+ sound/soc/codecs/max98095.c                        |  448 ++++----
+ sound/soc/codecs/max98095.h                        |    2 +-
+ sound/soc/codecs/max98357a.c                       |   29 +-
+ sound/soc/codecs/max98371.c                        |   43 +-
+ sound/soc/codecs/max98371.h                        |    1 -
+ sound/soc/codecs/max98373.c                        |   75 +-
+ sound/soc/codecs/max9850.c                         |   80 +-
+ sound/soc/codecs/max9860.c                         |   70 +-
+ sound/soc/codecs/max9867.c                         |   65 +-
+ sound/soc/codecs/max9867.h                         |    2 +-
+ sound/soc/codecs/max98925.c                        |   72 +-
+ sound/soc/codecs/max98925.h                        |    2 +-
+ sound/soc/codecs/max98926.c                        |   56 +-
+ sound/soc/codecs/max98926.h                        |    2 +-
+ sound/soc/codecs/max98927.c                        |   82 +-
+ sound/soc/codecs/max98927.h                        |    2 +-
+ sound/soc/codecs/mc13783.c                         |   68 +-
+ sound/soc/codecs/ml26124.c                         |  103 +-
+ sound/soc/codecs/msm8916-wcd-analog.c              |  207 ++--
+ sound/soc/codecs/msm8916-wcd-digital.c             |  115 +-
+ sound/soc/codecs/nau8540.c                         |   79 +-
+ sound/soc/codecs/nau8810.c                         |   73 +-
+ sound/soc/codecs/nau8824.c                         |  113 +-
+ sound/soc/codecs/nau8824.h                         |    2 +-
+ sound/soc/codecs/nau8825.c                         |  107 +-
+ sound/soc/codecs/nau8825.h                         |    2 +-
+ sound/soc/codecs/pcm1681.c                         |   62 +-
+ sound/soc/codecs/pcm179x-i2c.c                     |    6 -
+ sound/soc/codecs/pcm179x-spi.c                     |    6 -
+ sound/soc/codecs/pcm179x.c                         |   45 +-
+ sound/soc/codecs/pcm179x.h                         |    1 -
+ sound/soc/codecs/pcm186x-i2c.c                     |    8 -
+ sound/soc/codecs/pcm186x-spi.c                     |    8 -
+ sound/soc/codecs/pcm186x.c                         |  143 ++-
+ sound/soc/codecs/pcm186x.h                         |    1 -
+ sound/soc/codecs/pcm3008.c                         |   36 +-
+ sound/soc/codecs/pcm3168a.c                        |   51 +-
+ sound/soc/codecs/pcm5102a.c                        |   16 +-
+ sound/soc/codecs/pcm512x.c                         |  162 ++-
+ sound/soc/codecs/rt274.c                           |  206 ++--
+ sound/soc/codecs/rt286.c                           |  198 ++--
+ sound/soc/codecs/rt286.h                           |    2 +-
+ sound/soc/codecs/rt298.c                           |  210 ++--
+ sound/soc/codecs/rt298.h                           |    2 +-
+ sound/soc/codecs/rt5514-spi.c                      |   36 +-
+ sound/soc/codecs/rt5514.c                          |  124 +--
+ sound/soc/codecs/rt5514.h                          |    2 +-
+ sound/soc/codecs/rt5616.c                          |  219 ++--
+ sound/soc/codecs/rt5631.c                          |  324 +++---
+ sound/soc/codecs/rt5640.c                          |  260 +++--
+ sound/soc/codecs/rt5640.h                          |    6 +-
+ sound/soc/codecs/rt5645.c                          |  370 ++++---
+ sound/soc/codecs/rt5645.h                          |    4 +-
+ sound/soc/codecs/rt5651.c                          |  221 ++--
+ sound/soc/codecs/rt5651.h                          |    4 +-
+ sound/soc/codecs/rt5659.c                          |  430 +++++---
+ sound/soc/codecs/rt5659.h                          |    7 +-
+ sound/soc/codecs/rt5660.c                          |  145 ++-
+ sound/soc/codecs/rt5660.h                          |    2 +-
+ sound/soc/codecs/rt5663.c                          |  600 ++++++-----
+ sound/soc/codecs/rt5663.h                          |    4 +-
+ sound/soc/codecs/rt5665.c                          |  350 +++----
+ sound/soc/codecs/rt5665.h                          |    3 +-
+ sound/soc/codecs/rt5670.c                          |  295 +++---
+ sound/soc/codecs/rt5670.h                          |   10 +-
+ sound/soc/codecs/rt5677.c                          |  205 ++--
+ sound/soc/codecs/rt5677.h                          |    4 +-
+ sound/soc/codecs/sgtl5000.c                        |  295 ++++--
+ sound/soc/codecs/sgtl5000.h                        |    7 +
+ sound/soc/codecs/si476x.c                          |   42 +-
+ sound/soc/codecs/sirf-audio-codec.c                |   58 +-
+ sound/soc/codecs/spdif_receiver.c                  |   26 +-
+ sound/soc/codecs/spdif_transmitter.c               |   26 +-
+ sound/soc/codecs/ssm2518.c                         |   57 +-
+ sound/soc/codecs/ssm2602-i2c.c                     |    7 -
+ sound/soc/codecs/ssm2602-spi.c                     |    7 -
+ sound/soc/codecs/ssm2602.c                         |   77 +-
+ sound/soc/codecs/ssm4567.c                         |   44 +-
+ sound/soc/codecs/sta32x.c                          |  134 ++-
+ sound/soc/codecs/sta350.c                          |  117 +--
+ sound/soc/codecs/sta529.c                          |   69 +-
+ sound/soc/codecs/stac9766.c                        |   77 +-
+ sound/soc/codecs/sti-sas.c                         |   84 +-
+ sound/soc/codecs/tas2552.c                         |  178 ++--
+ sound/soc/codecs/tas5086.c                         |   94 +-
+ sound/soc/codecs/tas571x.c                         |   55 +-
+ sound/soc/codecs/tas5720.c                         |  151 ++-
+ sound/soc/codecs/tas6424.c                         |   99 +-
+ sound/soc/codecs/tfa9879.c                         |   50 +-
+ sound/soc/codecs/tlv320aic23-i2c.c                 |    7 -
+ sound/soc/codecs/tlv320aic23-spi.c                 |    7 -
+ sound/soc/codecs/tlv320aic23.c                     |  120 +--
+ sound/soc/codecs/tlv320aic26.c                     |   83 +-
+ sound/soc/codecs/tlv320aic31xx.c                   |  339 +++---
+ sound/soc/codecs/tlv320aic31xx.h                   |    1 +
+ sound/soc/codecs/tlv320aic32x4.c                   |  207 ++--
+ sound/soc/codecs/tlv320aic3x.c                     |  295 +++---
+ sound/soc/codecs/tlv320dac33.c                     |  402 ++++---
+ sound/soc/codecs/tscs42xx.c                        |  234 ++---
+ sound/soc/codecs/twl4030.c                         |  383 ++++---
+ sound/soc/codecs/twl6040.c                         |  269 +++--
+ sound/soc/codecs/twl6040.h                         |   10 +-
+ sound/soc/codecs/uda134x.c                         |   78 +-
+ sound/soc/codecs/uda1380.c                         |  160 ++-
+ sound/soc/codecs/wl1273.c                          |   93 +-
+ sound/soc/codecs/wl1273.h                          |    2 +-
+ sound/soc/codecs/wm0010.c                          |  181 ++--
+ sound/soc/codecs/wm1250-ev1.c                      |   27 +-
+ sound/soc/codecs/wm2000.c                          |   78 +-
+ sound/soc/codecs/wm2200.c                          |  157 ++-
+ sound/soc/codecs/wm5100.c                          |  260 +++--
+ sound/soc/codecs/wm5100.h                          |    2 +-
+ sound/soc/codecs/wm5102.c                          |  140 ++-
+ sound/soc/codecs/wm5110.c                          |  174 ++-
+ sound/soc/codecs/wm8350.c                          |  183 ++--
+ sound/soc/codecs/wm8350.h                          |    4 +-
+ sound/soc/codecs/wm8400.c                          |  211 ++--
+ sound/soc/codecs/wm8510.c                          |  149 ++-
+ sound/soc/codecs/wm8523.c                          |   98 +-
+ sound/soc/codecs/wm8524.c                          |   56 +-
+ sound/soc/codecs/wm8580.c                          |  150 ++-
+ sound/soc/codecs/wm8711.c                          |  116 +-
+ sound/soc/codecs/wm8727.c                          |   29 +-
+ sound/soc/codecs/wm8728.c                          |   82 +-
+ sound/soc/codecs/wm8731.c                          |  101 +-
+ sound/soc/codecs/wm8737.c                          |  109 +-
+ sound/soc/codecs/wm8741.c                          |  133 ++-
+ sound/soc/codecs/wm8750.c                          |  115 +-
+ sound/soc/codecs/wm8753.c                          |  289 +++--
+ sound/soc/codecs/wm8770.c                          |  131 ++-
+ sound/soc/codecs/wm8776.c                          |  105 +-
+ sound/soc/codecs/wm8782.c                          |   27 +-
+ sound/soc/codecs/wm8804.c                          |  100 +-
+ sound/soc/codecs/wm8900.c                          |  251 +++--
+ sound/soc/codecs/wm8903.c                          |  211 ++--
+ sound/soc/codecs/wm8903.h                          |    2 +-
+ sound/soc/codecs/wm8904.c                          |  355 +++----
+ sound/soc/codecs/wm8940.c                          |  159 ++-
+ sound/soc/codecs/wm8955.c                          |  189 ++--
+ sound/soc/codecs/wm8958-dsp2.c                     |  278 ++---
+ sound/soc/codecs/wm8960.c                          |  249 ++---
+ sound/soc/codecs/wm8961.c                          |  241 +++--
+ sound/soc/codecs/wm8962.c                          |  397 ++++---
+ sound/soc/codecs/wm8962.h                          |    2 +-
+ sound/soc/codecs/wm8971.c                          |  108 +-
+ sound/soc/codecs/wm8974.c                          |  143 ++-
+ sound/soc/codecs/wm8978.c                          |  185 ++--
+ sound/soc/codecs/wm8983.c                          |  170 ++-
+ sound/soc/codecs/wm8985.c                          |  201 ++--
+ sound/soc/codecs/wm8988.c                          |  127 +--
+ sound/soc/codecs/wm8990.c                          |  179 ++--
+ sound/soc/codecs/wm8991.c                          |  167 ++-
+ sound/soc/codecs/wm8993.c                          |  237 ++---
+ sound/soc/codecs/wm8994.c                          |  810 +++++++-------
+ sound/soc/codecs/wm8994.h                          |    8 +-
+ sound/soc/codecs/wm8995.c                          |  286 +++--
+ sound/soc/codecs/wm8996.c                          |  401 ++++---
+ sound/soc/codecs/wm8996.h                          |    4 +-
+ sound/soc/codecs/wm8997.c                          |   62 +-
+ sound/soc/codecs/wm8998.c                          |   88 +-
+ sound/soc/codecs/wm9081.c                          |  228 ++--
+ sound/soc/codecs/wm9090.c                          |  109 +-
+ sound/soc/codecs/wm9705.c                          |   83 +-
+ sound/soc/codecs/wm9712.c                          |  111 +-
+ sound/soc/codecs/wm9713.c                          |  203 ++--
+ sound/soc/codecs/wm_adsp.c                         |   71 +-
+ sound/soc/codecs/wm_adsp.h                         |   14 +-
+ sound/soc/codecs/wm_hubs.c                         |  254 ++---
+ sound/soc/codecs/wm_hubs.h                         |   18 +-
+ sound/soc/codecs/zx_aud96p22.c                     |   35 +-
+ sound/soc/davinci/davinci-i2s.c                    |   13 +-
+ sound/soc/dwc/dwc-i2s.c                            |    4 +
+ sound/soc/dwc/dwc-pcm.c                            |    5 +-
+ sound/soc/fsl/fsl-asoc-card.c                      |    6 +-
+ sound/soc/fsl/fsl_asrc.c                           |   10 -
+ sound/soc/fsl/fsl_asrc.h                           |    3 +-
+ sound/soc/fsl/fsl_asrc_dma.c                       |   14 +-
+ sound/soc/fsl/fsl_dma.c                            |   27 +-
+ sound/soc/fsl/fsl_esai.c                           |    2 +-
+ sound/soc/fsl/fsl_ssi.c                            |    2 +-
+ sound/soc/fsl/fsl_utils.c                          |    2 +-
+ sound/soc/fsl/imx-pcm-fiq.c                        |    6 +-
+ sound/soc/fsl/mpc5200_dma.c                        |   16 +-
+ sound/soc/fsl/wm1133-ev1.c                         |    6 +-
+ sound/soc/img/pistachio-internal-dac.c             |   34 +-
+ sound/soc/intel/atom/sst-atom-controls.c           |   36 +-
+ sound/soc/intel/atom/sst-mfld-platform-compress.c  |    4 +-
+ sound/soc/intel/atom/sst-mfld-platform-pcm.c       |   32 +-
+ sound/soc/intel/atom/sst-mfld-platform.h           |    4 +-
+ sound/soc/intel/baytrail/sst-baytrail-pcm.c        |   66 +-
+ sound/soc/intel/boards/Kconfig                     |   14 +
+ sound/soc/intel/boards/Makefile                    |    2 +
+ sound/soc/intel/boards/bdw-rt5677.c                |   41 +-
+ sound/soc/intel/boards/broadwell.c                 |   17 +-
+ sound/soc/intel/boards/bxt_da7219_max98357a.c      |   12 +-
+ sound/soc/intel/boards/bxt_rt298.c                 |   12 +-
+ sound/soc/intel/boards/byt-rt5640.c                |    4 +-
+ sound/soc/intel/boards/bytcr_rt5640.c              |    8 +-
+ sound/soc/intel/boards/bytcr_rt5651.c              |    2 +-
+ sound/soc/intel/boards/cht_bsw_rt5645.c            |    8 +-
+ sound/soc/intel/boards/cht_bsw_rt5672.c            |   18 +-
+ sound/soc/intel/boards/haswell.c                   |    3 +-
+ sound/soc/intel/boards/kbl_da7219_max98357a.c      |  613 +++++++++++
+ sound/soc/intel/boards/kbl_rt5663_max98927.c       |   14 +-
+ .../soc/intel/boards/kbl_rt5663_rt5514_max98927.c  |   14 +-
+ sound/soc/intel/boards/skl_nau88l25_max98357a.c    |   12 +-
+ sound/soc/intel/boards/skl_nau88l25_ssm4567.c      |   12 +-
+ sound/soc/intel/boards/skl_rt286.c                 |   12 +-
+ sound/soc/intel/haswell/sst-haswell-ipc.h          |    2 +
+ sound/soc/intel/haswell/sst-haswell-pcm.c          |  118 +--
+ sound/soc/intel/skylake/skl-debug.c                |    2 +-
+ sound/soc/intel/skylake/skl-pcm.c                  |   52 +-
+ sound/soc/intel/skylake/skl-ssp-clk.c              |    4 +-
+ sound/soc/intel/skylake/skl-topology.c             |   26 +-
+ sound/soc/intel/skylake/skl-topology.h             |    2 +-
+ sound/soc/intel/skylake/skl.c                      |   13 +
+ sound/soc/intel/skylake/skl.h                      |    2 +-
+ sound/soc/kirkwood/kirkwood-dma.c                  |    3 +-
+ sound/soc/kirkwood/kirkwood-i2s.c                  |   20 +-
+ sound/soc/kirkwood/kirkwood.h                      |    4 +-
+ sound/soc/mediatek/common/mtk-afe-fe-dai.c         |   16 +-
+ .../soc/mediatek/common/mtk-afe-platform-driver.c  |    9 +-
+ .../soc/mediatek/common/mtk-afe-platform-driver.h  |    3 +-
+ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c         |   50 +-
+ sound/soc/mediatek/mt8173/mt8173-afe-pcm.c         |   42 +-
+ sound/soc/mediatek/mt8173/mt8173-max98090.c        |    4 +-
+ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c   |    6 +-
+ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c   |   12 +-
+ sound/soc/mediatek/mt8173/mt8173-rt5650.c          |   12 +-
+ sound/soc/nuc900/nuc900-pcm.c                      |    5 +-
+ sound/soc/omap/ams-delta.c                         |   20 +-
+ sound/soc/omap/omap-abe-twl6040.c                  |    8 +-
+ sound/soc/omap/omap-pcm.c                          |    5 +-
+ sound/soc/pxa/mioa701_wm9713.c                     |   30 +-
+ sound/soc/pxa/mmp-pcm.c                            |   11 +-
+ sound/soc/pxa/pxa2xx-pcm.c                         |    5 +-
+ sound/soc/pxa/ttc-dkb.c                            |    6 +-
+ sound/soc/qcom/lpass-platform.c                    |   42 +-
+ sound/soc/rockchip/rk3399_gru_sound.c              |    4 +-
+ sound/soc/rockchip/rockchip_rt5645.c               |    8 +-
+ sound/soc/samsung/Makefile                         |    3 -
+ sound/soc/samsung/i2s-regs.h                       |   11 +-
+ sound/soc/samsung/i2s.c                            |   52 +-
+ sound/soc/samsung/i2s.h                            |   11 +-
+ sound/soc/samsung/idma.c                           |    5 +-
+ sound/soc/samsung/littlemill.c                     |    8 +-
+ sound/soc/samsung/lowland.c                        |   12 +-
+ sound/soc/samsung/speyside.c                       |   12 +-
+ sound/soc/samsung/tm2_wm5110.c                     |  206 +++-
+ sound/soc/samsung/tobermory.c                      |    6 +-
+ sound/soc/sh/dma-sh7760.c                          |    5 +-
+ sound/soc/sh/fsi.c                                 |   24 +-
+ sound/soc/sh/rcar/core.c                           |   33 +-
+ sound/soc/sh/rcar/rsnd.h                           |   20 +
+ sound/soc/sh/rcar/src.c                            |   22 +-
+ sound/soc/sh/rcar/ssi.c                            |   16 +-
+ sound/soc/sh/siu.h                                 |    2 +-
+ sound/soc/sh/siu_dai.c                             |   10 +-
+ sound/soc/sh/siu_pcm.c                             |    9 +-
+ sound/soc/soc-ac97.c                               |   84 +-
+ sound/soc/soc-core.c                               |   77 +-
+ sound/soc/soc-dapm.c                               |    4 +-
+ sound/soc/soc-generic-dmaengine-pcm.c              |   55 +-
+ sound/soc/soc-utils.c                              |   28 +-
+ sound/soc/stm/stm32_adfsdm.c                       |    7 +-
+ sound/soc/stm/stm32_spdifrx.c                      |    7 +-
+ sound/soc/sunxi/sun4i-codec.c                      |   71 +-
+ sound/soc/sunxi/sun8i-codec.c                      |   23 +-
+ sound/soc/tegra/tegra_wm8903.c                     |    8 +-
+ sound/soc/txx9/txx9aclc.c                          |   26 +-
+ sound/soc/uniphier/Kconfig                         |   22 +
+ sound/soc/uniphier/Makefile                        |    6 +
+ sound/soc/uniphier/aio-compress.c                  |  439 ++++++++
+ sound/soc/uniphier/aio-core.c                      | 1104 ++++++++++++++++++++
+ sound/soc/uniphier/aio-cpu.c                       |  567 ++++++++++
+ sound/soc/uniphier/aio-dma.c                       |  319 ++++++
+ sound/soc/uniphier/aio-ld11.c                      |  431 ++++++++
+ sound/soc/uniphier/aio-reg.h                       |  462 ++++++++
+ sound/soc/uniphier/aio.h                           |  355 +++++++
+ sound/soc/uniphier/evea.c                          |   67 +-
+ sound/soc/xtensa/xtfpga-i2s.c                      |   17 +-
+ 403 files changed, 21342 insertions(+), 16013 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/sound/ak4458.txt
+ create mode 100644 Documentation/devicetree/bindings/sound/ak5558.txt
+ create mode 100644 Documentation/devicetree/bindings/sound/uniphier,aio.txt
+ create mode 100644 sound/soc/amd/acp-da7219-max98357a.c
+ create mode 100644 sound/soc/codecs/ak4458.c
+ create mode 100644 sound/soc/codecs/ak4458.h
+ create mode 100644 sound/soc/codecs/ak5558.c
+ create mode 100644 sound/soc/codecs/ak5558.h
+ create mode 100644 sound/soc/intel/boards/kbl_da7219_max98357a.c
+ create mode 100644 sound/soc/uniphier/aio-compress.c
+ create mode 100644 sound/soc/uniphier/aio-core.c
+ create mode 100644 sound/soc/uniphier/aio-cpu.c
+ create mode 100644 sound/soc/uniphier/aio-dma.c
+ create mode 100644 sound/soc/uniphier/aio-ld11.c
+ create mode 100644 sound/soc/uniphier/aio-reg.h
+ create mode 100644 sound/soc/uniphier/aio.h
+Merging modules/modules-next (0cad61d7a3d5 modpost: Remove trailing semicolon)
+$ git merge modules/modules-next
+Already up to date.
+Merging input/next (cdc2466df40f Input: synaptics - handle errors from input_mt_init_slots())
+$ git merge input/next
+Merge made by the 'recursive' strategy.
+ drivers/input/mouse/synaptics.c | 82 ++++++++++++++++++++++++-----------------
+ 1 file changed, 48 insertions(+), 34 deletions(-)
+Merging block/for-next (0ccfb3c0032b Merge branch 'for-4.16/block' into for-next)
+$ git merge block/for-next
+Merge made by the 'recursive' strategy.
+Merging lightnvm/for-next (1c6286f26301 lightnvm: fix some error code in pblk-init.c)
+$ git merge lightnvm/for-next
+Already up to date.
+Merging device-mapper/for-next (8dd601fa8317 dm: correctly handle chained bios in dec_pending())
+$ git merge device-mapper/for-next
+Already up to date.
+Merging mmc/next (80a7d9316496 Merge branch 'fixes' into next)
+$ git merge mmc/next
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/mmc/tmio_mmc.txt |   1 -
+ arch/sh/boards/mach-kfr2r09/setup.c                |   2 +-
+ drivers/mmc/core/core.c                            |   2 +-
+ drivers/mmc/host/renesas_sdhi_internal_dmac.c      |  12 +-
+ drivers/mmc/host/renesas_sdhi_sys_dmac.c           |  20 +-
+ drivers/mmc/host/sdhci-iproc.c                     |   1 +
+ drivers/mmc/host/sdhci-omap.c                      | 378 ++++++++++++++++++++-
+ drivers/mmc/host/sh_mmcif.c                        |   8 -
+ drivers/mmc/host/tmio_mmc_core.c                   |  61 ++--
+ include/linux/mfd/tmio.h                           |   1 -
+ 10 files changed, 428 insertions(+), 58 deletions(-)
+Merging kgdb/kgdb-next (2cf2f0d5b91f kdb: use memmove instead of overlapping memcpy)
+$ git merge kgdb/kgdb-next
+Auto-merging kernel/debug/kdb/kdb_main.c
+Merge made by the 'recursive' strategy.
+ drivers/misc/kgdbts.c              |  8 +++-
+ include/linux/timekeeping.h        |  1 +
+ kernel/debug/kdb/kdb_bp.c          |  4 +-
+ kernel/debug/kdb/kdb_main.c        | 89 +++++++++++++++++---------------------
+ kernel/debug/kdb/kdb_support.c     |  4 +-
+ kernel/time/timekeeping_internal.h |  2 -
+ 6 files changed, 51 insertions(+), 57 deletions(-)
+Merging md/for-next (01a69cab01c1 md raid10: fix NULL deference in handle_write_completed())
+$ git merge md/for-next
+Merge made by the 'recursive' strategy.
+ drivers/md/md-multipath.c |  2 +-
+ drivers/md/md.c           | 40 +++++++++++++++++++++++++++++++++++-----
+ drivers/md/md.h           |  2 ++
+ drivers/md/raid1.c        |  2 +-
+ drivers/md/raid1.h        | 12 ++++++++++++
+ drivers/md/raid10.c       |  8 +++++---
+ drivers/md/raid10.h       | 13 +++++++++++++
+ drivers/md/raid5.c        |  4 +---
+ drivers/md/raid5.h        | 12 ++++++++++++
+ 9 files changed, 82 insertions(+), 13 deletions(-)
+Merging mfd/for-mfd-next (0f89ffefa4e1 mfd: lpc_ich: Do not touch SPI-NOR write protection bit on Apollo Lake)
+$ git merge mfd/for-mfd-next
+Already up to date.
+Merging backlight/for-backlight-next (2023b0524a63 backlight: tdo24m: Fix the SPI CS between transfers)
+$ git merge backlight/for-backlight-next
+Already up to date.
+Merging battery/for-next (416a1ae673db power: supply: gpio-charger: use helper variable to access device info)
+$ git merge battery/for-next
+Merge made by the 'recursive' strategy.
+ .../bindings/power/reset/ocelot-reset.txt          | 14 ++++
+ drivers/power/reset/Kconfig                        |  7 ++
+ drivers/power/reset/Makefile                       |  1 +
+ drivers/power/reset/ocelot-reset.c                 | 88 ++++++++++++++++++++++
+ drivers/power/supply/gpio-charger.c                | 73 ++++++------------
+ drivers/power/supply/ltc2941-battery-gauge.c       | 59 ++++++++++++---
+ 6 files changed, 181 insertions(+), 61 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/power/reset/ocelot-reset.txt
+ create mode 100644 drivers/power/reset/ocelot-reset.c
+Merging regulator/for-next (775d434195db Merge remote-tracking branches 'regulator/topic/dt' and 'regulator/topic/gpio' into regulator-next)
+$ git merge regulator/for-next
+Merge made by the 'recursive' strategy.
+ .../bindings/regulator/fixed-regulator.txt         |  1 +
+ .../bindings/regulator/gpio-regulator.txt          |  2 ++
+ drivers/regulator/core.c                           | 25 ++++++++++++++--------
+ drivers/regulator/da9055-regulator.c               |  4 ++--
+ drivers/regulator/da9211-regulator.c               | 23 ++++++++++----------
+ drivers/regulator/of_regulator.c                   |  1 +
+ drivers/regulator/stm32-vrefbuf.c                  |  2 +-
+ include/linux/mfd/da9055/pdata.h                   |  5 +++--
+ include/linux/regulator/da9211.h                   |  4 +++-
+ include/linux/regulator/driver.h                   |  3 +++
+ 10 files changed, 43 insertions(+), 27 deletions(-)
+Merging security/next-testing (400f428062af Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next-testing)
+$ git merge security/next-testing
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging integrity/next-integrity (b79f5f38d87f fuse: introduce new fs_type flag FS_IMA_NO_CACHE)
+$ git merge integrity/next-integrity
+Resolved 'security/integrity/ima/ima_main.c' using previous resolution.
+Auto-merging security/integrity/ima/ima_main.c
+CONFLICT (content): Merge conflict in security/integrity/ima/ima_main.c
+Auto-merging include/linux/fs.h
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 4204accf3a08] Merge remote-tracking branch 'integrity/next-integrity'
+$ git diff -M --stat --summary HEAD^..
+ fs/fuse/inode.c                   |  2 +-
+ include/linux/fs.h                |  1 +
+ security/integrity/ima/ima_main.c | 15 +++++++++++++--
+ 3 files changed, 15 insertions(+), 3 deletions(-)
+Merging keys/keys-next (1e684d3820d8 pkcs7: Set the module licence to prevent tainting)
+$ git merge keys/keys-next
+Already up to date.
+Merging selinux/next (213d7f947753 netlabel: If PF_INET6, check sk_buff ip header version)
+$ git merge selinux/next
+Merge made by the 'recursive' strategy.
+ net/netlabel/netlabel_unlabeled.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+Merging tpmdd/next (c3211d722c61 tpm: fix potential buffer overruns caused by bit glitches on the bus)
+$ git merge tpmdd/next
+Merge made by the 'recursive' strategy.
+ drivers/char/tpm/tpm-interface.c | 4 ++++
+ drivers/char/tpm/tpm2-cmd.c      | 4 ++++
+ 2 files changed, 8 insertions(+)
+Merging watchdog/master (a17f4f032b61 watchdog: sp5100_tco.c: fix potential build failure)
+$ git merge watchdog/master
+Merge made by the 'recursive' strategy.
+ drivers/watchdog/Kconfig | 4 ++++
+ 1 file changed, 4 insertions(+)
+Merging iommu/next (18b3c16e25fb Merge branches 'x86/amd', 'x86/vt-d', 'arm/mediatek', 'arm/exynos' and 'core' into next)
+$ git merge iommu/next
+Auto-merging drivers/irqchip/irq-gic-v3-its.c
+Merge made by the 'recursive' strategy.
+ drivers/acpi/arm64/iort.c          | 111 ++++++++++++++++++++++++++++++++++++-
+ drivers/iommu/amd_iommu.c          |  65 +++++++++++++---------
+ drivers/iommu/amd_iommu_init.c     |   2 +-
+ drivers/iommu/amd_iommu_types.h    |   4 +-
+ drivers/iommu/dma-iommu.c          |   8 ++-
+ drivers/iommu/dmar.c               |   2 +-
+ drivers/iommu/exynos-iommu.c       |  13 +----
+ drivers/iommu/io-pgtable-arm-v7s.c |  21 +++----
+ drivers/iommu/io-pgtable-arm.c     |  24 ++++----
+ drivers/iommu/io-pgtable.h         |   4 +-
+ drivers/iommu/iommu.c              |   6 +-
+ drivers/iommu/mtk_iommu_v1.c       |  54 +++++++-----------
+ drivers/irqchip/irq-gic-v3-its.c   |   3 +-
+ include/linux/acpi_iort.h          |   7 ++-
+ include/linux/intel-iommu.h        |  12 ++--
+ include/linux/iommu.h              |  14 ++---
+ 16 files changed, 229 insertions(+), 121 deletions(-)
+Merging dwmw2-iommu/master (910170442944 iommu/vt-d: Fix PASID table allocation)
+$ git merge dwmw2-iommu/master
+Already up to date.
+Merging vfio/next (46ed90f157f4 vfio: mdev: make a couple of functions and structure vfio_mdev_driver static)
+$ git merge vfio/next
+Already up to date.
+Merging trivial/for-next (1972d6c0c86d MAINTAINERS: relinquish kconfig)
+$ git merge trivial/for-next
+Already up to date.
+Merging audit/next (94d14e3e7b41 audit: bail before bug check if audit disabled)
+$ git merge audit/next
+Auto-merging kernel/audit.c
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS          |  1 -
+ kernel/audit.c       |  3 ++-
+ kernel/auditfilter.c |  5 ++---
+ kernel/auditsc.c     | 22 ++++++++++------------
+ 4 files changed, 14 insertions(+), 17 deletions(-)
+Merging devicetree/for-next (7ea5c83472d3 Merge branches 'dt/next' and 'dt/linus' into for-next)
+$ git merge devicetree/for-next
+Merge made by the 'recursive' strategy.
+ .../bindings/{misc => auxdisplay}/arm-charlcd.txt  |   0
+ .../devicetree/bindings/thermal/imx-thermal.txt    |  25 +++
+ drivers/gpio/gpiolib-of.c                          |   4 +-
+ drivers/of/base.c                                  | 184 +++++++++++++++++++++
+ drivers/of/unittest-data/tests-phandle.dtsi        |  25 +++
+ drivers/of/unittest.c                              | 120 ++++++++++++++
+ include/linux/of.h                                 |  12 ++
+ 7 files changed, 368 insertions(+), 2 deletions(-)
+ rename Documentation/devicetree/bindings/{misc => auxdisplay}/arm-charlcd.txt (100%)
+Merging mailbox/mailbox-for-next (0ae7d327a64b dt-bindings: mailbox: qcom: Document the APCS clock binding)
+$ git merge mailbox/mailbox-for-next
+Already up to date.
+Merging spi/for-next (a48478413035 Merge remote-tracking branches 'spi/topic/orion' and 'spi/topic/pxa2xx' into spi-next)
+$ git merge spi/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/devicetree/bindings/spi/spi-gpio.txt |  24 +-
+ arch/arm/mach-pxa/cm-x300.c                        |  21 +-
+ arch/arm/mach-pxa/raumfeld.c                       |  26 +-
+ arch/arm/mach-s3c24xx/mach-jive.c                  |  55 +++--
+ arch/arm/mach-s3c24xx/mach-qt2410.c                |  26 +-
+ arch/arm/mach-s3c64xx/mach-smartq.c                |  22 +-
+ arch/mips/alchemy/devboards/db1000.c               |  24 +-
+ arch/mips/jz4740/board-qi_lb60.c                   |  26 +-
+ drivers/misc/eeprom/digsy_mtc_eeprom.c             |  29 ++-
+ drivers/spi/Kconfig                                |   4 +-
+ drivers/spi/spi-bcm2835aux.c                       |  18 +-
+ drivers/spi/spi-dw-mid.c                           |   6 +-
+ drivers/spi/spi-dw.c                               |  26 +-
+ drivers/spi/spi-dw.h                               |   4 +-
+ drivers/spi/spi-gpio.c                             | 270 +++++++--------------
+ drivers/spi/spi-orion.c                            |  65 ++++-
+ drivers/spi/spi-pxa2xx-dma.c                       |   4 +-
+ drivers/spi/spi-pxa2xx.c                           |  54 +++--
+ drivers/spi/spi-pxa2xx.h                           |   2 +-
+ include/linux/spi/spi_gpio.h                       |  49 +---
+ 20 files changed, 396 insertions(+), 359 deletions(-)
+Merging tip/auto-latest (cb85c73cf461 Merge branch 'x86/pti')
+$ git merge tip/auto-latest
+Merge made by the 'recursive' strategy.
+ Documentation/admin-guide/kernel-parameters.txt    |    9 +
+ Documentation/features/list-arch.sh                |    2 +-
+ Documentation/locking/lockdep-design.txt           |   51 +-
+ Documentation/trace/coresight.txt                  |   51 +
+ Documentation/x86/x86_64/5level-paging.txt         |    9 +-
+ arch/x86/Kconfig                                   |   13 +-
+ arch/x86/boot/compressed/Makefile                  |    2 +-
+ arch/x86/boot/compressed/head_64.S                 |  178 +-
+ arch/x86/boot/compressed/kaslr.c                   |   14 +
+ .../boot/compressed/{pagetable.c => kaslr_64.c}    |    0
+ arch/x86/boot/compressed/misc.c                    |   16 -
+ arch/x86/boot/compressed/pgtable.h                 |   18 +
+ arch/x86/boot/compressed/pgtable_64.c              |  100 +-
+ arch/x86/entry/calling.h                           |   27 +-
+ arch/x86/entry/entry_64.S                          |   30 +-
+ arch/x86/entry/entry_64_compat.S                   |   54 +-
+ arch/x86/include/asm/apic.h                        |    2 +-
+ arch/x86/include/asm/io_apic.h                     |   10 +-
+ arch/x86/include/asm/kaslr.h                       |    4 -
+ arch/x86/include/asm/mem_encrypt.h                 |    1 +
+ arch/x86/include/asm/microcode.h                   |    9 +-
+ arch/x86/include/asm/page_64.h                     |    6 +-
+ arch/x86/include/asm/page_64_types.h               |   20 +-
+ arch/x86/include/asm/paravirt.h                    |   10 +-
+ arch/x86/include/asm/pgalloc.h                     |    5 +-
+ arch/x86/include/asm/pgtable-3level_types.h        |    1 +
+ arch/x86/include/asm/pgtable.h                     |   11 +-
+ arch/x86/include/asm/pgtable_32.h                  |    2 +
+ arch/x86/include/asm/pgtable_32_types.h            |    2 +
+ arch/x86/include/asm/pgtable_64.h                  |   23 +-
+ arch/x86/include/asm/pgtable_64_types.h            |   67 +-
+ arch/x86/include/asm/processor.h                   |    1 +
+ arch/x86/include/asm/required-features.h           |    8 +-
+ arch/x86/include/asm/sparsemem.h                   |    9 +-
+ arch/x86/include/asm/x86_init.h                    |    8 +-
+ arch/x86/kernel/apic/apic.c                        |    4 +-
+ arch/x86/kernel/apic/io_apic.c                     |   16 +-
+ arch/x86/kernel/apic/x2apic_phys.c                 |    2 +-
+ arch/x86/kernel/cpu/common.c                       |   30 +
+ arch/x86/kernel/cpu/mcheck/mce.c                   |   18 +-
+ arch/x86/kernel/cpu/microcode/amd.c                |   10 +-
+ arch/x86/kernel/cpu/microcode/core.c               |   39 +-
+ arch/x86/kernel/cpu/microcode/intel.c              |   10 +-
+ arch/x86/kernel/crash.c                            |    3 +-
+ arch/x86/kernel/e820.c                             |   18 +
+ arch/x86/kernel/head64.c                           |   76 +-
+ arch/x86/kernel/head_64.S                          |   12 +-
+ arch/x86/kernel/irqinit.c                          |    9 +-
+ arch/x86/kernel/machine_kexec_32.c                 |    8 +-
+ arch/x86/kernel/machine_kexec_64.c                 |    8 +-
+ arch/x86/kernel/reboot.c                           |    3 +-
+ arch/x86/kernel/setup.c                            |    5 +-
+ arch/x86/kernel/vmlinux.lds.S                      |    7 +-
+ arch/x86/kernel/x86_init.c                         |    6 +-
+ arch/x86/lib/clear_page_64.S                       |    2 -
+ arch/x86/mm/Makefile                               |   14 +-
+ arch/x86/mm/debug_pagetables.c                     |   32 +
+ arch/x86/mm/dump_pagetables.c                      |   33 +-
+ arch/x86/mm/fault.c                                |    4 +-
+ arch/x86/mm/ident_map.c                            |    2 +-
+ arch/x86/mm/init_64.c                              |   32 +-
+ arch/x86/mm/kasan_init_64.c                        |   14 +-
+ arch/x86/mm/kaslr.c                                |   29 +-
+ arch/x86/mm/mem_encrypt.c                          |  578 +-----
+ arch/x86/mm/mem_encrypt_identity.c                 |  564 ++++++
+ arch/x86/mm/tlb.c                                  |    4 +-
+ arch/x86/platform/atom/punit_atom_debug.c          |   17 +-
+ arch/x86/platform/efi/efi_64.c                     |   10 +-
+ arch/x86/platform/intel-quark/imr.c                |   24 +-
+ arch/x86/power/hibernate_64.c                      |    6 +-
+ arch/x86/xen/apic.c                                |    2 +-
+ drivers/iommu/irq_remapping.c                      |    4 +-
+ include/asm-generic/5level-fixup.h                 |    1 +
+ include/asm-generic/pgtable-nop4d.h                |    9 +-
+ include/linux/interrupt.h                          |    2 -
+ include/linux/kasan.h                              |    2 +-
+ include/linux/nospec.h                             |   26 +-
+ include/linux/trace_events.h                       |    8 +
+ include/uapi/linux/perf_event.h                    |    4 +
+ kernel/events/core.c                               |  188 +-
+ kernel/irq/manage.c                                |   10 +-
+ kernel/sched/fair.c                                |    4 +-
+ kernel/trace/trace_event_perf.c                    |  102 ++
+ kernel/trace/trace_kprobe.c                        |   91 +-
+ kernel/trace/trace_probe.h                         |   11 +
+ kernel/trace/trace_uprobe.c                        |   86 +-
+ lib/debugobjects.c                                 |  140 +-
+ mm/kasan/kasan_init.c                              |    2 +-
+ mm/zsmalloc.c                                      |   13 +-
+ tools/arch/powerpc/include/uapi/asm/unistd.h       |  402 +++++
+ tools/include/uapi/linux/perf_event.h              |    4 +
+ tools/lib/api/fs/fs.c                              |   44 +-
+ tools/lib/api/fs/fs.h                              |    2 +
+ tools/lib/symbol/kallsyms.c                        |    4 +
+ tools/memory-model/Documentation/cheatsheet.txt    |   30 +
+ tools/memory-model/Documentation/explanation.txt   | 1840 ++++++++++++++++++++
+ tools/memory-model/Documentation/recipes.txt       |  570 ++++++
+ tools/memory-model/Documentation/references.txt    |  107 ++
+ tools/memory-model/MAINTAINERS                     |   15 +
+ tools/memory-model/README                          |  220 +++
+ tools/memory-model/linux-kernel.bell               |   53 +
+ tools/memory-model/linux-kernel.cat                |  124 ++
+ tools/memory-model/linux-kernel.cfg                |   21 +
+ tools/memory-model/linux-kernel.def                |  108 ++
+ .../litmus-tests/CoRR+poonceonce+Once.litmus       |   19 +
+ .../litmus-tests/CoRW+poonceonce+Once.litmus       |   18 +
+ .../litmus-tests/CoWR+poonceonce+Once.litmus       |   18 +
+ .../litmus-tests/CoWW+poonceonce.litmus            |   11 +
+ .../litmus-tests/IRIW+mbonceonces+OnceOnce.litmus  |   35 +
+ .../litmus-tests/IRIW+poonceonces+OnceOnce.litmus  |   33 +
+ .../litmus-tests/ISA2+poonceonces.litmus           |   28 +
+ ...cerelease+poacquirerelease+poacquireonce.litmus |   28 +
+ .../litmus-tests/LB+ctrlonceonce+mbonceonce.litmus |   23 +
+ .../LB+poacquireonce+pooncerelease.litmus          |   21 +
+ .../litmus-tests/LB+poonceonces.litmus             |   21 +
+ .../litmus-tests/MP+onceassign+derefonce.litmus    |   25 +
+ tools/memory-model/litmus-tests/MP+polocks.litmus  |   24 +
+ .../litmus-tests/MP+poonceonces.litmus             |   20 +
+ .../MP+pooncerelease+poacquireonce.litmus          |   20 +
+ .../memory-model/litmus-tests/MP+porevlocks.litmus |   24 +
+ .../litmus-tests/MP+wmbonceonce+rmbonceonce.litmus |   22 +
+ .../memory-model/litmus-tests/R+mbonceonces.litmus |   21 +
+ .../memory-model/litmus-tests/R+poonceonces.litmus |   19 +
+ tools/memory-model/litmus-tests/README             |  125 ++
+ .../memory-model/litmus-tests/S+poonceonces.litmus |   19 +
+ .../S+wmbonceonce+poacquireonce.litmus             |   20 +
+ .../litmus-tests/SB+mbonceonces.litmus             |   23 +
+ .../litmus-tests/SB+poonceonces.litmus             |   21 +
+ .../litmus-tests/WRC+poonceonces+Once.litmus       |   27 +
+ .../WRC+pooncerelease+rmbonceonce+Once.litmus      |   28 +
+ .../Z6.0+pooncelock+poonceLock+pombonce.litmus     |   33 +
+ .../Z6.0+pooncelock+pooncelock+pombonce.litmus     |   32 +
+ ...ooncerelease+poacquirerelease+mbonceonce.litmus |   28 +
+ tools/memory-model/lock.cat                        |   99 ++
+ tools/perf/Documentation/perf-annotate.txt         |    6 +-
+ tools/perf/Documentation/perf-kmem.txt             |    6 +-
+ tools/perf/Documentation/perf-mem.txt              |    4 +
+ tools/perf/Documentation/perf-report.txt           |    5 +-
+ tools/perf/Documentation/perf-script.txt           |    3 +
+ tools/perf/Documentation/perf-stat.txt             |   10 +
+ tools/perf/Makefile.config                         |    2 +
+ tools/perf/arch/arm/util/auxtrace.c                |    2 +-
+ tools/perf/arch/arm/util/cs-etm.c                  |   51 +-
+ tools/perf/arch/powerpc/Makefile                   |   25 +
+ .../perf/arch/powerpc/entry/syscalls/mksyscalltbl  |   37 +
+ tools/perf/arch/s390/annotate/instructions.c       |   27 +-
+ tools/perf/arch/s390/util/header.c                 |  148 +-
+ tools/perf/builtin-record.c                        |    2 +-
+ tools/perf/builtin-report.c                        |    7 +-
+ tools/perf/builtin-script.c                        |   17 +
+ tools/perf/builtin-stat.c                          |   53 +-
+ tools/perf/check-headers.sh                        |    1 +
+ tools/perf/tests/code-reading.c                    |   33 +-
+ tools/perf/tests/dwarf-unwind.c                    |   46 +-
+ tools/perf/tests/shell/lib/probe_vfs_getname.sh    |    2 +-
+ .../perf/tests/shell/trace+probe_libc_inet_pton.sh |    6 +-
+ tools/perf/tests/vmlinux-kallsyms.c                |    4 +-
+ tools/perf/ui/browsers/annotate.c                  |    9 +-
+ tools/perf/util/build-id.c                         |   10 +-
+ tools/perf/util/cs-etm-decoder/cs-etm-decoder.c    |   74 +-
+ tools/perf/util/cs-etm-decoder/cs-etm-decoder.h    |    2 +
+ tools/perf/util/cs-etm.c                           |  478 ++++-
+ tools/perf/util/event.c                            |   16 +-
+ tools/perf/util/evlist.c                           |   21 +-
+ tools/perf/util/header.h                           |    1 +
+ tools/perf/util/hist.c                             |    4 +-
+ tools/perf/util/hist.h                             |    1 -
+ tools/perf/util/machine.c                          |  145 +-
+ tools/perf/util/machine.h                          |    6 +-
+ tools/perf/util/pmu.c                              |   47 +-
+ tools/perf/util/sort.c                             |    7 +-
+ tools/perf/util/stat.h                             |    2 +
+ tools/perf/util/symbol.c                           |   13 +-
+ tools/perf/util/syscalltbl.c                       |    8 +
+ tools/perf/util/thread_map.c                       |    4 +-
+ tools/perf/util/thread_map.h                       |    2 +-
+ 176 files changed, 7488 insertions(+), 1415 deletions(-)
+ rename arch/x86/boot/compressed/{pagetable.c => kaslr_64.c} (100%)
+ create mode 100644 arch/x86/boot/compressed/pgtable.h
+ create mode 100644 arch/x86/mm/mem_encrypt_identity.c
+ create mode 100644 tools/arch/powerpc/include/uapi/asm/unistd.h
+ create mode 100644 tools/memory-model/Documentation/cheatsheet.txt
+ create mode 100644 tools/memory-model/Documentation/explanation.txt
+ create mode 100644 tools/memory-model/Documentation/recipes.txt
+ create mode 100644 tools/memory-model/Documentation/references.txt
+ create mode 100644 tools/memory-model/MAINTAINERS
+ create mode 100644 tools/memory-model/README
+ create mode 100644 tools/memory-model/linux-kernel.bell
+ create mode 100644 tools/memory-model/linux-kernel.cat
+ create mode 100644 tools/memory-model/linux-kernel.cfg
+ create mode 100644 tools/memory-model/linux-kernel.def
+ create mode 100644 tools/memory-model/litmus-tests/CoRR+poonceonce+Once.litmus
+ create mode 100644 tools/memory-model/litmus-tests/CoRW+poonceonce+Once.litmus
+ create mode 100644 tools/memory-model/litmus-tests/CoWR+poonceonce+Once.litmus
+ create mode 100644 tools/memory-model/litmus-tests/CoWW+poonceonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/IRIW+mbonceonces+OnceOnce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/IRIW+poonceonces+OnceOnce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/ISA2+poonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/LB+ctrlonceonce+mbonceonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/LB+poacquireonce+pooncerelease.litmus
+ create mode 100644 tools/memory-model/litmus-tests/LB+poonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/MP+onceassign+derefonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/MP+polocks.litmus
+ create mode 100644 tools/memory-model/litmus-tests/MP+poonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/MP+pooncerelease+poacquireonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/MP+porevlocks.litmus
+ create mode 100644 tools/memory-model/litmus-tests/MP+wmbonceonce+rmbonceonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/R+mbonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/R+poonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/README
+ create mode 100644 tools/memory-model/litmus-tests/S+poonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/S+wmbonceonce+poacquireonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/SB+mbonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/SB+poonceonces.litmus
+ create mode 100644 tools/memory-model/litmus-tests/WRC+poonceonces+Once.litmus
+ create mode 100644 tools/memory-model/litmus-tests/WRC+pooncerelease+rmbonceonce+Once.litmus
+ create mode 100644 tools/memory-model/litmus-tests/Z6.0+pooncelock+poonceLock+pombonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus
+ create mode 100644 tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus
+ create mode 100644 tools/memory-model/lock.cat
+ create mode 100755 tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl
+Merging clockevents/clockevents/next (322fd24f5e67 clocksource/drivers/stm32: Start the timer's counter sooner)
+$ git merge clockevents/clockevents/next
+Resolved 'drivers/clocksource/Kconfig' using previous resolution.
+Resolved 'drivers/clocksource/timer-of.c' using previous resolution.
+Resolved 'drivers/clocksource/timer-stm32.c' using previous resolution.
+Auto-merging drivers/clocksource/timer-stm32.c
+CONFLICT (content): Merge conflict in drivers/clocksource/timer-stm32.c
+Auto-merging drivers/clocksource/timer-of.c
+CONFLICT (content): Merge conflict in drivers/clocksource/timer-of.c
+Auto-merging drivers/clocksource/Kconfig
+CONFLICT (content): Merge conflict in drivers/clocksource/Kconfig
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master 3b3cfe431f6d] Merge remote-tracking branch 'clockevents/clockevents/next'
+$ git diff -M --stat --summary HEAD^..
+Merging edac/linux_next (345fb0a9a634 Merge tag 'edac_for_4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp)
+$ git merge edac/linux_next
+Already up to date.
+Merging edac-amd/for-next (68fa24f9121c EDAC, mv64x60: Fix an error handling path)
+$ git merge edac-amd/for-next
+Already up to date.
+Merging irqchip/irqchip/for-next (c1ae3cfa0e89 Linux 4.11-rc1)
+$ git merge irqchip/irqchip/for-next
+Already up to date.
+Merging ftrace/for-next (841a915d20c7 vsprintf: Do not have bprintf dereference pointers)
+$ git merge ftrace/for-next
+Already up to date.
+Merging rcu/rcu/next (2faeeb29ab2b EXP rcu: Add ->qsmask to assertion)
+$ git merge rcu/rcu/next
+Merge made by the 'recursive' strategy.
+ Documentation/memory-barriers.txt                  | 26 +++++---
+ Documentation/timers/NO_HZ.txt                     |  7 ---
+ include/linux/rcupdate.h                           | 10 +--
+ include/linux/types.h                              |  2 +-
+ include/trace/events/rcu.h                         |  4 ++
+ kernel/rcu/rcu.h                                   | 37 +++++++----
+ kernel/rcu/rcuperf.c                               | 21 ++++++-
+ kernel/rcu/rcutorture.c                            | 72 ++++++++++++----------
+ kernel/rcu/srcutree.c                              | 21 ++++---
+ kernel/rcu/tree.c                                  | 69 +++++++--------------
+ kernel/rcu/tree.h                                  | 37 ++---------
+ kernel/rcu/tree_exp.h                              | 34 +++++++---
+ kernel/rcu/tree_plugin.h                           | 66 ++++++++++++++++----
+ kernel/time/Kconfig                                | 10 ---
+ kernel/time/tick-sched.c                           | 22 +------
+ .../testing/selftests/rcutorture/bin/functions.sh  | 17 ++++-
+ .../rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh   | 11 ++--
+ .../selftests/rcutorture/bin/kvm-test-1-run.sh     |  4 +-
+ tools/testing/selftests/rcutorture/bin/kvm.sh      | 22 +++++--
+ .../selftests/rcutorture/configs/rcu/TASKS03       |  1 -
+ .../selftests/rcutorture/configs/rcu/TASKS03.boot  |  2 +-
+ .../selftests/rcutorture/configs/rcu/TREE04        |  1 -
+ .../selftests/rcutorture/configs/rcu/TREE04.boot   |  2 +-
+ .../selftests/rcutorture/configs/rcu/TREE07        |  1 -
+ .../rcutorture/configs/rcuperf/ver_functions.sh    | 24 +-------
+ .../selftests/rcutorture/doc/rcu-test-image.txt    |  2 +-
+ 26 files changed, 279 insertions(+), 246 deletions(-)
+Merging kvm/linux-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge kvm/linux-next
+Already up to date.
+Merging kvm-arm/next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge kvm-arm/next
+Already up to date.
+Merging kvm-mips/next (dc44abd6aad2 KVM: MIPS/Emulate: Properly implement TLBR for T&E)
+$ git merge kvm-mips/next
+Already up to date.
+Merging kvm-ppc/kvm-ppc-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge kvm-ppc/kvm-ppc-next
+Already up to date.
+Merging kvms390/next (baabee67f413 KVM: s390: use switch vs jump table in interrupt.c)
+$ git merge kvms390/next
+Already up to date.
+Merging xen-tip/linux-next (d1a75e0896f5 pvcalls-front: wait for other operations to return when release passive sockets)
+$ git merge xen-tip/linux-next
+Already up to date.
+Merging percpu/for-next (554fef1c39ee percpu: allow select gfp to be passed to underlying allocators)
+$ git merge percpu/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS    |  1 +
+ mm/percpu-km.c |  8 ++++----
+ mm/percpu-vm.c | 18 +++++++++++-------
+ mm/percpu.c    | 52 +++++++++++++++++++++++++++++++---------------------
+ 4 files changed, 47 insertions(+), 32 deletions(-)
+Merging workqueues/for-next (a10eb37ccf1d Merge branch 'for-4.15-fixes' into for-next)
+$ git merge workqueues/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging drivers-x86/for-next (c8ba9db2a790 platform/x86: dell-laptop: Removed duplicates in DMI whitelist)
+$ git merge drivers-x86/for-next
+Already up to date.
+Merging chrome-platform/for-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge chrome-platform/for-next
+Already up to date.
+Merging hsi/for-next (b6dc80dbe6cd HSI: cmt_speech: use timespec64 instead of timespec)
+$ git merge hsi/for-next
+Already up to date.
+Merging leds/for-next (2dd1ea5b8a49 leds: Add more product/board names for PC Engines APU2)
+$ git merge leds/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ MAINTAINERS                |   1 +
+ drivers/leds/Kconfig       |  29 +++--
+ drivers/leds/Makefile      |   1 +
+ drivers/leds/leds-apu.c    |  26 ++++-
+ drivers/leds/leds-mlxreg.c | 281 +++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 326 insertions(+), 12 deletions(-)
+ create mode 100644 drivers/leds/leds-mlxreg.c
+Merging ipmi/for-next (09c0179286c7 ipmi: kcs_bmc: mark expected switch fall-through in kcs_bmc_handle_data)
+$ git merge ipmi/for-next
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt    |  25 ++
+ drivers/char/ipmi/Kconfig                          |  15 +
+ drivers/char/ipmi/Makefile                         |   2 +
+ drivers/char/ipmi/kcs_bmc.c                        | 465 +++++++++++++++++++++
+ drivers/char/ipmi/kcs_bmc.h                        | 106 +++++
+ drivers/char/ipmi/kcs_bmc_aspeed.c                 | 319 ++++++++++++++
+ include/uapi/linux/ipmi_bmc.h                      |  14 +
+ 7 files changed, 946 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
+ create mode 100644 drivers/char/ipmi/kcs_bmc.c
+ create mode 100644 drivers/char/ipmi/kcs_bmc.h
+ create mode 100644 drivers/char/ipmi/kcs_bmc_aspeed.c
+ create mode 100644 include/uapi/linux/ipmi_bmc.h
+Merging driver-core/driver-core-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge driver-core/driver-core-next
+Already up to date.
+Merging usb/usb-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge usb/usb-next
+Already up to date.
+Merging usb-gadget/next (8ada211d0383 usb: renesas_usbhs: add extcon notifier to set mode for non-otg channel)
+$ git merge usb-gadget/next
+Already up to date.
+Merging usb-serial/usb-next (d1c48227d7c4 USB: serial: f81534: fix tx error on some baud rate)
+$ git merge usb-serial/usb-next
+Already up to date.
+Merging usb-chipidea-next/ci-for-usb-next (ce4c1b820c52 usb: chipidea: imx: Fix ULPI on imx53)
+$ git merge usb-chipidea-next/ci-for-usb-next
+Merge made by the 'recursive' strategy.
+ drivers/usb/chipidea/ci_hdrc_imx.c | 15 +++++++++++++--
+ drivers/usb/chipidea/usbmisc_imx.c | 26 ++++++++++++++++----------
+ 2 files changed, 29 insertions(+), 12 deletions(-)
+Merging phy-next/next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge phy-next/next
+Already up to date.
+Merging tty/tty-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge tty/tty-next
+Already up to date.
+Merging char-misc/char-misc-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge char-misc/char-misc-next
+Already up to date.
+Merging extcon/extcon-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge extcon/extcon-next
+Already up to date.
+Merging staging/staging-next (f782497c0991 staging: wilc1000: fix line over 80 chars in wilc_wlan_handle_txq())
+$ git merge staging/staging-next
+Removing drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c
+Removing drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
+Removing drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+Removing drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h
+Removing drivers/staging/unisys/visorinput/ultrainputreport.h
+Merge made by the 'recursive' strategy.
+ drivers/staging/android/ion/ion.c                  |  20 +-
+ drivers/staging/android/ion/ion.h                  |  22 +-
+ drivers/staging/android/ion/ion_page_pool.c        |  33 +-
+ drivers/staging/android/ion/ion_system_heap.c      |  76 +--
+ drivers/staging/ccree/cc_aead.c                    |  13 +-
+ drivers/staging/ccree/cc_buffer_mgr.c              |   2 +-
+ drivers/staging/ccree/cc_cipher.c                  |   3 +-
+ drivers/staging/ccree/cc_hash.c                    |  17 +-
+ drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c     |   1 -
+ drivers/staging/lustre/TODO                        | 310 ++++++++-
+ .../lustre/include/linux/libcfs/libcfs_debug.h     |   4 +-
+ .../lustre/include/linux/libcfs/libcfs_time.h      |   2 +-
+ .../lustre/include/linux/libcfs/linux/linux-time.h |   7 +-
+ .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c    |   8 +-
+ .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c |   4 +-
+ .../staging/lustre/lnet/klnds/socklnd/socklnd.c    |   6 +-
+ .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c |  22 +-
+ drivers/staging/lustre/lnet/libcfs/debug.c         |   2 +-
+ drivers/staging/lustre/lnet/libcfs/fail.c          |   2 +-
+ drivers/staging/lustre/lnet/libcfs/tracefile.c     |   4 +-
+ drivers/staging/lustre/lnet/lnet/acceptor.c        |   2 +-
+ drivers/staging/lustre/lnet/lnet/api-ni.c          |   4 +-
+ drivers/staging/lustre/lnet/lnet/lib-move.c        |   4 +-
+ drivers/staging/lustre/lnet/lnet/net_fault.c       |  14 +-
+ drivers/staging/lustre/lnet/lnet/peer.c            |   2 +-
+ drivers/staging/lustre/lnet/lnet/router.c          |   8 +-
+ drivers/staging/lustre/lnet/selftest/conrpc.c      |   4 +-
+ drivers/staging/lustre/lnet/selftest/framework.c   |   2 +-
+ drivers/staging/lustre/lnet/selftest/rpc.c         |   2 +-
+ drivers/staging/lustre/lnet/selftest/selftest.h    |   2 +-
+ drivers/staging/lustre/lnet/selftest/timer.c       |   2 +-
+ drivers/staging/lustre/lustre/include/lustre_dlm.h |   2 +-
+ drivers/staging/lustre/lustre/include/lustre_lib.h | 296 +--------
+ drivers/staging/lustre/lustre/include/lustre_lmv.h |   2 +-
+ drivers/staging/lustre/lustre/include/lustre_mdc.h |   2 +-
+ drivers/staging/lustre/lustre/include/lustre_net.h |   8 +-
+ drivers/staging/lustre/lustre/ldlm/ldlm_flock.c    |  30 +-
+ drivers/staging/lustre/lustre/ldlm/ldlm_lock.c     |  14 +-
+ drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c    |  12 +-
+ drivers/staging/lustre/lustre/ldlm/ldlm_pool.c     |  17 +-
+ drivers/staging/lustre/lustre/ldlm/ldlm_request.c  |  53 +-
+ drivers/staging/lustre/lustre/ldlm/ldlm_resource.c |  14 +-
+ drivers/staging/lustre/lustre/llite/dcache.c       |  10 +
+ drivers/staging/lustre/lustre/llite/llite_lib.c    |  25 +-
+ drivers/staging/lustre/lustre/llite/namei.c        |  60 +-
+ drivers/staging/lustre/lustre/llite/statahead.c    |  60 +-
+ drivers/staging/lustre/lustre/lov/lov_object.c     |   6 +-
+ drivers/staging/lustre/lustre/lov/lov_request.c    |  12 +-
+ drivers/staging/lustre/lustre/mdc/mdc_request.c    |   5 +-
+ drivers/staging/lustre/lustre/mgc/mgc_request.c    |  19 +-
+ drivers/staging/lustre/lustre/obdclass/cl_io.c     |  23 +-
+ drivers/staging/lustre/lustre/obdclass/genops.c    |  24 +-
+ drivers/staging/lustre/lustre/obdclass/llog_obd.c  |   5 +-
+ .../staging/lustre/lustre/obdecho/echo_client.c    |   2 +-
+ drivers/staging/lustre/lustre/osc/osc_cache.c      |  28 +-
+ drivers/staging/lustre/lustre/osc/osc_object.c     |   6 +-
+ drivers/staging/lustre/lustre/osc/osc_page.c       |   6 +-
+ drivers/staging/lustre/lustre/osc/osc_request.c    |   6 +-
+ drivers/staging/lustre/lustre/ptlrpc/client.c      | 101 ++-
+ drivers/staging/lustre/lustre/ptlrpc/events.c      |   7 +-
+ drivers/staging/lustre/lustre/ptlrpc/import.c      |  51 +-
+ drivers/staging/lustre/lustre/ptlrpc/niobuf.c      |  15 +-
+ .../staging/lustre/lustre/ptlrpc/pack_generic.c    |   9 +-
+ drivers/staging/lustre/lustre/ptlrpc/pinger.c      |  28 +-
+ .../staging/lustre/lustre/ptlrpc/ptlrpc_internal.h |   2 +-
+ drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c     |  18 +-
+ drivers/staging/lustre/lustre/ptlrpc/recover.c     |  12 +-
+ drivers/staging/lustre/lustre/ptlrpc/sec.c         |  34 +-
+ drivers/staging/lustre/lustre/ptlrpc/sec_gc.c      |  23 +-
+ drivers/staging/lustre/lustre/ptlrpc/service.c     |  84 +--
+ drivers/staging/pi433/Documentation/pi433.txt      |   6 +-
+ drivers/staging/pi433/pi433_if.c                   |   2 +-
+ drivers/staging/pi433/pi433_if.h                   |   2 +-
+ drivers/staging/pi433/rf69.c                       |  80 +--
+ drivers/staging/pi433/rf69.h                       |   6 +-
+ drivers/staging/pi433/rf69_enum.h                  |   6 +-
+ drivers/staging/rtl8188eu/core/rtw_xmit.c          |  55 +-
+ drivers/staging/rtl8188eu/hal/usb_halinit.c        |   2 +-
+ drivers/staging/rtl8188eu/include/xmit_osdep.h     |  13 -
+ drivers/staging/rtl8188eu/os_dep/xmit_linux.c      |  37 --
+ drivers/staging/rtl8723bs/include/drv_types.h      |   4 +-
+ drivers/staging/rtlwifi/wifi.h                     |  29 +-
+ drivers/staging/sm750fb/ddk750_chip.c              |   4 +-
+ drivers/staging/sm750fb/ddk750_chip.h              |  14 +-
+ drivers/staging/sm750fb/ddk750_mode.c              |   2 +-
+ drivers/staging/sm750fb/ddk750_mode.h              |   2 +-
+ drivers/staging/sm750fb/sm750_hw.c                 |   2 +-
+ drivers/staging/unisys/visorinput/Kconfig          |   2 +-
+ drivers/staging/unisys/visorinput/Makefile         |   1 -
+ .../staging/unisys/visorinput/ultrainputreport.h   |  57 --
+ drivers/staging/unisys/visorinput/visorinput.c     | 169 +++--
+ drivers/staging/vc04_services/Makefile             |   1 -
+ .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 369 +++++++++++
+ .../interface/vchiq_arm/vchiq_build_info.h         |  37 --
+ .../interface/vchiq_arm/vchiq_kern_lib.c           | 431 ------------
+ .../interface/vchiq_arm/vchiq_memdrv.h             |  59 --
+ .../interface/vchiq_arm/vchiq_version.c            |  59 --
+ drivers/staging/vt6656/usbpipe.c                   |   3 -
+ drivers/staging/wilc1000/coreconfigurator.c        |   4 +-
+ drivers/staging/wilc1000/host_interface.c          | 726 ++++++++++-----------
+ drivers/staging/wilc1000/wilc_sdio.c               | 145 ++--
+ drivers/staging/wilc1000/wilc_spi.c                | 551 ++++++++--------
+ drivers/staging/wilc1000/wilc_wlan.c               |  70 +-
+ drivers/staging/wilc1000/wilc_wlan_cfg.c           |  21 +-
+ drivers/staging/wlan-ng/prism2mgmt.c               |   2 +-
+ include/linux/wait.h                               | 114 ++++
+ 106 files changed, 2262 insertions(+), 2560 deletions(-)
+ delete mode 100644 drivers/staging/unisys/visorinput/ultrainputreport.h
+ delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h
+ delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+ delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
+ delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c
+Merging mux/for-next (6cd361c99ef2 mux: add SPDX identifiers to all mux source files)
+$ git merge mux/for-next
+Merge made by the 'recursive' strategy.
+Merging slave-dma/next (5ec91512231a Merge branch 'topic/renesas' into next)
+$ git merge slave-dma/next
+Merge made by the 'recursive' strategy.
+ .../devicetree/bindings/dma/renesas,rcar-dmac.txt        |  1 +
+ drivers/dma/dmatest.c                                    | 16 ++++++++++++----
+ include/linux/dmaengine.h                                |  4 ++++
+ 3 files changed, 17 insertions(+), 4 deletions(-)
+Merging cgroup/for-next (c53593e5cb69 sched, cgroup: Don't reject lower cpu.max on ancestors)
+$ git merge cgroup/for-next
+Auto-merging kernel/sched/core.c
+Merge made by the 'recursive' strategy.
+ kernel/sched/core.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+Merging scsi/for-next (b00e1e5f242e Merge branch 'misc' into for-next)
+$ git merge scsi/for-next
+Removing drivers/scsi/aic7xxx/aiclib.c
+Merge made by the 'recursive' strategy.
+ drivers/message/fusion/mptctl.c            |   2 +
+ drivers/scsi/Kconfig                       |   2 +
+ drivers/scsi/Makefile                      |   1 -
+ drivers/scsi/NCR53c406a.c                  |   2 +-
+ drivers/scsi/aacraid/aacraid.h             |   5 +
+ drivers/scsi/aacraid/linit.c               |   4 +-
+ drivers/scsi/aacraid/src.c                 | 205 +++++++++++++++++++++++++++--
+ drivers/scsi/aic7xxx/aiclib.c              |  34 -----
+ drivers/scsi/bnx2fc/bnx2fc_io.c            |   1 +
+ drivers/scsi/csiostor/csio_lnode.c         |   2 +-
+ drivers/scsi/device_handler/scsi_dh_alua.c |   5 +
+ drivers/scsi/hosts.c                       |  12 +-
+ drivers/scsi/ibmvscsi/ibmvfc.h             |   2 +-
+ drivers/scsi/ipr.c                         |  49 ++-----
+ drivers/scsi/ipr.h                         |   2 +-
+ drivers/scsi/isci/host.c                   |   2 +-
+ drivers/scsi/libfc/fc_disc.c               |   2 +-
+ drivers/scsi/lpfc/lpfc.h                   |   3 +-
+ drivers/scsi/lpfc/lpfc_attr.c              |  17 ++-
+ drivers/scsi/lpfc/lpfc_crtn.h              |   3 +-
+ drivers/scsi/lpfc/lpfc_els.c               |   5 +-
+ drivers/scsi/lpfc/lpfc_hbadisc.c           |   7 +-
+ drivers/scsi/lpfc/lpfc_hw4.h               |  14 +-
+ drivers/scsi/lpfc/lpfc_init.c              |  69 +++++++---
+ drivers/scsi/lpfc/lpfc_mbox.c              |   6 +-
+ drivers/scsi/lpfc/lpfc_mem.c               |  12 +-
+ drivers/scsi/lpfc/lpfc_nportdisc.c         |   7 +-
+ drivers/scsi/lpfc/lpfc_nvme.c              |  30 +++--
+ drivers/scsi/lpfc/lpfc_nvmet.c             | 162 ++++++++++++++++++++---
+ drivers/scsi/lpfc/lpfc_nvmet.h             |  10 +-
+ drivers/scsi/lpfc/lpfc_scsi.c              |  49 ++++---
+ drivers/scsi/lpfc/lpfc_sli.c               |  36 ++++-
+ drivers/scsi/lpfc/lpfc_sli4.h              |  12 +-
+ drivers/scsi/lpfc/lpfc_version.h           |   8 +-
+ drivers/scsi/mpt3sas/mpt3sas_base.c        |   5 +-
+ drivers/scsi/pmcraid.c                     |  51 ++-----
+ drivers/scsi/pmcraid.h                     |   3 +-
+ drivers/scsi/qedf/qedf_dbg.c               |   2 +-
+ drivers/scsi/qedf/qedf_dbg.h               |  17 ++-
+ drivers/scsi/qedf/qedf_debugfs.c           |   6 +-
+ drivers/scsi/qedf/qedf_io.c                |   2 +-
+ drivers/scsi/qedf/qedf_main.c              |   8 +-
+ drivers/scsi/qedi/qedi_dbg.h               |   2 +-
+ drivers/scsi/qedi/qedi_debugfs.c           |   4 +-
+ drivers/scsi/qedi/qedi_gbl.h               |   4 +-
+ drivers/scsi/qedi/qedi_main.c              |  59 ++++-----
+ drivers/scsi/qla2xxx/qla_dbg.c             |   4 +-
+ drivers/scsi/qla2xxx/qla_gs.c              |  78 ++++++-----
+ drivers/scsi/qla2xxx/qla_init.c            |  60 ++++-----
+ drivers/scsi/qla2xxx/qla_inline.h          |   1 +
+ drivers/scsi/qla2xxx/qla_iocb.c            |  22 ++--
+ drivers/scsi/qla2xxx/qla_isr.c             |  29 ++--
+ drivers/scsi/qla2xxx/qla_mbx.c             |   5 +-
+ drivers/scsi/qla2xxx/qla_mr.c              |  36 ++---
+ drivers/scsi/qla2xxx/qla_nx.c              |   7 +-
+ drivers/scsi/qla2xxx/qla_nx2.c             |  19 ++-
+ drivers/scsi/qla2xxx/qla_nx2.h             |   4 -
+ drivers/scsi/qla2xxx/qla_os.c              |   2 +
+ drivers/scsi/qla2xxx/qla_sup.c             |   1 +
+ drivers/scsi/qla2xxx/qla_target.c          |   9 +-
+ drivers/scsi/qla4xxx/ql4_def.h             |   2 +
+ drivers/scsi/qla4xxx/ql4_nx.c              |   2 +
+ drivers/scsi/qla4xxx/ql4_nx.h              |   7 -
+ drivers/scsi/qla4xxx/ql4_os.c              |  46 +++++++
+ drivers/scsi/raid_class.c                  |   1 +
+ drivers/scsi/scsi_debug.c                  | 202 +++++++++++++++++-----------
+ drivers/scsi/scsi_error.c                  |   6 +
+ drivers/scsi/scsi_lib.c                    |   2 +-
+ drivers/scsi/storvsc_drv.c                 |   2 +-
+ drivers/scsi/sym53c416.c                   |   2 +-
+ drivers/scsi/sym53c8xx_2/sym_hipd.c        |   2 +-
+ drivers/scsi/ufs/ufshcd.c                  |   2 +
+ include/linux/raid_class.h                 |   1 +
+ 73 files changed, 966 insertions(+), 533 deletions(-)
+ delete mode 100644 drivers/scsi/aic7xxx/aiclib.c
+Merging scsi-mkp/for-next (ec92b59cc03c scsi: ufs: sysfs: attributes)
+$ git merge scsi-mkp/for-next
+Auto-merging drivers/scsi/ufs/ufshcd.c
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-driver-ufs | 804 +++++++++++++++++++++++++++++
+ drivers/scsi/scsi_debug.c                  |  53 +-
+ drivers/scsi/scsi_sysfs.c                  |  11 +
+ drivers/scsi/scsi_transport_spi.c          |   4 +-
+ drivers/scsi/ufs/Makefile                  |   3 +-
+ drivers/scsi/ufs/ufs-sysfs.c               | 739 ++++++++++++++++++++++++++
+ drivers/scsi/ufs/ufs-sysfs.h               |  17 +
+ drivers/scsi/ufs/ufs.h                     | 115 ++++-
+ drivers/scsi/ufs/ufshcd.c                  | 218 ++------
+ drivers/scsi/ufs/ufshcd.h                  |  34 ++
+ include/scsi/scsi_host.h                   |   6 +
+ 11 files changed, 1791 insertions(+), 213 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-driver-ufs
+ create mode 100644 drivers/scsi/ufs/ufs-sysfs.c
+ create mode 100644 drivers/scsi/ufs/ufs-sysfs.h
+Merging target-updates/for-next (1c130ae00b76 iscsi-target: make sure to wake up sleeping login worker)
+$ git merge target-updates/for-next
+Already up to date.
+Merging target-bva/for-next (4fbd8d194f06 Linux 4.15-rc1)
+$ git merge target-bva/for-next
+Already up to date.
+Merging libata/for-next (d058cdf3cc81 Merge branches 'for-4.16-fixes' and 'for-4.17' into for-next)
+$ git merge libata/for-next
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-ata             | 171 ++++++++++++++----------
+ Documentation/ABI/testing/sysfs-block-device    |  58 ++++++++
+ Documentation/ABI/testing/sysfs-class-scsi_host |  89 ++++++++++++
+ drivers/ata/libahci.c                           |  10 ++
+ drivers/ata/libahci_platform.c                  |   2 +-
+ drivers/ata/libata-core.c                       |   8 +-
+ drivers/ata/libata-scsi.c                       |  12 +-
+ drivers/ata/pata_arasan_cf.c                    |   6 +-
+ drivers/ata/pata_it821x.c                       |   6 +-
+ drivers/ata/pata_macio.c                        |  12 +-
+ drivers/ata/pata_mpc52xx.c                      |   1 -
+ drivers/ata/pata_samsung_cf.c                   |   4 +-
+ drivers/ata/sata_dwc_460ex.c                    |   1 -
+ drivers/ata/sata_rcar.c                         |  62 +++++----
+ 14 files changed, 323 insertions(+), 119 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-block-device
+Merging vhost/linux-next (fa08a3b4eba5 virtio/s390: implement PM operations for virtio_ccw)
+$ git merge vhost/linux-next
+Already up to date.
+Merging rpmsg/for-next (ec6e69036956 Merge branches 'hwspinlock-next', 'rpmsg-next' and 'rproc-next' into for-next)
+$ git merge rpmsg/for-next
+Auto-merging drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+Merge made by the 'recursive' strategy.
+ drivers/gpu/drm/msm/adreno/a5xx_gpu.c        |   4 +-
+ drivers/media/platform/qcom/venus/firmware.c |   2 +-
+ drivers/remoteproc/Kconfig                   |  18 +
+ drivers/remoteproc/Makefile                  |   1 +
+ drivers/remoteproc/qcom_adsp_pil.c           |  20 +-
+ drivers/remoteproc/qcom_common.c             |  50 ++-
+ drivers/remoteproc/qcom_common.h             |  23 +
+ drivers/remoteproc/qcom_q6v5_pil.c           |   9 +-
+ drivers/remoteproc/qcom_sysmon.c             | 579 +++++++++++++++++++++++++
+ drivers/remoteproc/qcom_wcnss.c              |  11 +-
+ drivers/remoteproc/remoteproc_core.c         | 152 ++++++-
+ drivers/remoteproc/remoteproc_internal.h     |   7 +-
+ drivers/soc/qcom/mdt_loader.c                |   7 +-
+ include/linux/remoteproc.h                   |  27 +-
+ include/linux/soc/qcom/mdt_loader.h          |   3 +-
+ samples/Kconfig                              |   9 +
+ samples/Makefile                             |   2 +-
+ samples/qmi/Makefile                         |   1 +
+ samples/qmi/qmi_sample_client.c              | 622 +++++++++++++++++++++++++++
+ 19 files changed, 1504 insertions(+), 43 deletions(-)
+ create mode 100644 drivers/remoteproc/qcom_sysmon.c
+ create mode 100644 samples/qmi/Makefile
+ create mode 100644 samples/qmi/qmi_sample_client.c
+Merging gpio/for-next (3c87d7c874b2 gpio: davinci: add support for pinmux gpio ranges)
+$ git merge gpio/for-next
+Merge made by the 'recursive' strategy.
+ .../bindings/gpio/nintendo,hollywood-gpio.txt      | 27 ++++++++++++++++++++++
+ .../devicetree/bindings/powerpc/nintendo/wii.txt   |  9 +-------
+ drivers/gpio/gpio-davinci.c                        |  6 +++++
+ drivers/gpio/gpio-wm831x.c                         |  2 +-
+ 4 files changed, 35 insertions(+), 9 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt
+Merging pinctrl/for-next (cfc09838477f Merge branch 'devel' into for-next)
+$ git merge pinctrl/for-next
+Merge made by the 'recursive' strategy.
+ .../bindings/pinctrl/qcom,sdm845-pinctrl.txt       |  176 +++
+ drivers/pinctrl/core.c                             |   18 +-
+ drivers/pinctrl/meson/pinctrl-meson-axg.c          |    4 +-
+ drivers/pinctrl/pinctrl-mcp23s08.c                 |   49 +-
+ drivers/pinctrl/qcom/Kconfig                       |    9 +
+ drivers/pinctrl/qcom/Makefile                      |    1 +
+ drivers/pinctrl/qcom/pinctrl-msm.c                 |    2 +-
+ drivers/pinctrl/qcom/pinctrl-sdm845.c              | 1323 ++++++++++++++++++++
+ 8 files changed, 1565 insertions(+), 17 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt
+ create mode 100644 drivers/pinctrl/qcom/pinctrl-sdm845.c
+Merging pinctrl-samsung/for-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge pinctrl-samsung/for-next
+Already up to date.
+Merging pwm/for-next (bccaa3f917c9 pwm: meson: Add clock source configuration for Meson-AXG)
+$ git merge pwm/for-next
+Already up to date.
+Merging userns/for-next (9eba1cd4b565 24 Jan 2018 Merge of my siginfo and userns trees for testing in linux-next)
+$ git merge userns/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging ktest/for-next (f7c6401ff84a ktest: Make sure wait_for_input does honor the timeout)
+$ git merge ktest/for-next
+Already up to date.
+Merging random/dev (9e66317d3c92 Linux 4.14-rc3)
+$ git merge random/dev
+Already up to date.
+Merging aio/master (2a8a98673c13 fs: aio: fix the increment of aio-nr and counting against aio-max-nr)
+$ git merge aio/master
+Already up to date.
+Merging kselftest/next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge kselftest/next
+Already up to date.
+Merging y2038/y2038 (69973b830859 Linux 4.9)
+$ git merge y2038/y2038
+Already up to date.
+Merging livepatching/for-next (d13f5d84ca27 Merge branch 'for-4.16/signal-sysfs-force-v2' into for-next)
+$ git merge livepatching/for-next
+Already up to date!
+Merge made by the 'recursive' strategy.
+Merging coresight/next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge coresight/next
+Already up to date.
+Merging rtc/rtc-next (9fad33fc0baf rtc: tx4939: avoid unintended sign extension on a 24 bit shift)
+$ git merge rtc/rtc-next
+Auto-merging MAINTAINERS
+Merge made by the 'recursive' strategy.
+ Documentation/ABI/testing/sysfs-class-rtc |   4 +-
+ MAINTAINERS                               |   2 +-
+ drivers/char/rtc.c                        |  83 ------------
+ drivers/rtc/Kconfig                       |   2 +-
+ drivers/rtc/class.c                       |   2 -
+ drivers/rtc/interface.c                   |  30 +++++
+ drivers/rtc/nvmem.c                       |  29 +++--
+ drivers/rtc/rtc-cmos.c                    |  75 +++++------
+ drivers/rtc/rtc-core.h                    |   8 --
+ drivers/rtc/rtc-ds1302.c                  |   4 +-
+ drivers/rtc/rtc-ds1305.c                  |  21 ++-
+ drivers/rtc/rtc-ds1307.c                  |  29 +++--
+ drivers/rtc/rtc-ds1343.c                  | 183 +++++---------------------
+ drivers/rtc/rtc-ds1511.c                  |  22 ++--
+ drivers/rtc/rtc-ds1553.c                  |  74 +++++------
+ drivers/rtc/rtc-ds1742.c                  |  73 +++++------
+ drivers/rtc/rtc-goldfish.c                |   2 +
+ drivers/rtc/rtc-isl1208.c                 |   5 +
+ drivers/rtc/rtc-lib.c                     |   6 +-
+ drivers/rtc/rtc-m48t59.c                  |  57 ++++-----
+ drivers/rtc/rtc-m48t86.c                  |  23 ++--
+ drivers/rtc/rtc-mxc_v2.c                  |   2 +-
+ drivers/rtc/rtc-omap.c                    |   3 +-
+ drivers/rtc/rtc-pcf85363.c                |  25 ++--
+ drivers/rtc/rtc-rp5c01.c                  |  63 ++++-----
+ drivers/rtc/rtc-rv8803.c                  |  33 ++---
+ drivers/rtc/rtc-sirfsoc.c                 |  18 ---
+ drivers/rtc/rtc-stk17ta8.c                |  70 +++++-----
+ drivers/rtc/rtc-tx4939.c                  |  93 +++++++++-----
+ include/linux/rtc.h                       |  18 ++-
+ include/trace/events/rtc.h                | 206 ++++++++++++++++++++++++++++++
+ 31 files changed, 633 insertions(+), 632 deletions(-)
+ create mode 100644 include/trace/events/rtc.h
+Merging nvdimm/libnvdimm-for-next (ee95f4059a83 Merge branch 'for-4.16/nfit' into libnvdimm-for-next)
+$ git merge nvdimm/libnvdimm-for-next
+Already up to date.
+Merging idr/idr-4.11 (f0f3f2d0a3e0 radix tree test suite: Specify -m32 in LDFLAGS too)
+$ git merge idr/idr-4.11
+Already up to date.
+Merging at24/at24/for-next (7928b2cbe55b Linux 4.16-rc1)
+$ git merge at24/at24/for-next
+Already up to date.
+Merging ntb/ntb-next (53c3677c56c7 ntb: intel: change references of skx to gen3)
+$ git merge ntb/ntb-next
+Auto-merging drivers/ntb/hw/intel/ntb_hw_gen1.c
+Merge made by the 'recursive' strategy.
+ drivers/ntb/hw/intel/Makefile                      |   1 +
+ .../ntb/hw/intel/{ntb_hw_intel.c => ntb_hw_gen1.c} | 713 ++-------------------
+ drivers/ntb/hw/intel/ntb_hw_gen1.h                 | 182 ++++++
+ drivers/ntb/hw/intel/ntb_hw_gen3.c                 | 597 +++++++++++++++++
+ drivers/ntb/hw/intel/ntb_hw_gen3.h                 | 110 ++++
+ drivers/ntb/hw/intel/ntb_hw_intel.h                | 203 ++----
+ 6 files changed, 997 insertions(+), 809 deletions(-)
+ rename drivers/ntb/hw/intel/{ntb_hw_intel.c => ntb_hw_gen1.c} (74%)
+ create mode 100644 drivers/ntb/hw/intel/ntb_hw_gen1.h
+ create mode 100644 drivers/ntb/hw/intel/ntb_hw_gen3.c
+ create mode 100644 drivers/ntb/hw/intel/ntb_hw_gen3.h
+Merging kspp/for-next/kspp (2d00fcb32f71 Merge branch 'kspp/gcc-plugin/infrastructure' into for-next/kspp)
+$ git merge kspp/for-next/kspp
+Merge made by the 'recursive' strategy.
+Merging init_task/init_task (e1e871aff3de Expand INIT_STRUCT_PID and remove)
+$ git merge init_task/init_task
+Already up to date.
+Merging akpm-current/current (5682fa508060 elf: enforce MAP_FIXED on overlaying elf segments)
+$ git merge --no-ff akpm-current/current
+Resolved 'kernel/fork.c' using previous resolution.
+Auto-merging mm/swapfile.c
+Auto-merging mm/page_alloc.c
+Auto-merging mm/memory_hotplug.c
+Auto-merging mm/memory.c
+Auto-merging mm/memory-failure.c
+Auto-merging mm/memcontrol.c
+Auto-merging lib/radix-tree.c
+Auto-merging lib/idr.c
+Auto-merging kernel/relay.c
+Auto-merging kernel/fork.c
+CONFLICT (content): Merge conflict in kernel/fork.c
+Auto-merging kernel/cgroup/cgroup.c
+Auto-merging include/linux/seq_file.h
+Auto-merging include/linux/sched/mm.h
+Auto-merging include/linux/mm.h
+Auto-merging include/linux/memory_hotplug.h
+Auto-merging include/linux/compiler.h
+Auto-merging include/linux/compiler-gcc.h
+Auto-merging fs/seq_file.c
+Auto-merging arch/x86/kernel/machine_kexec_64.c
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit -v -a
+[master e66760a3b17e59e3db58c6bbbea1d9285e0bf805] Merge branch 'akpm-current/current'
+$ git diff -M --stat --summary HEAD^..
+ Documentation/ABI/testing/sysfs-class-bdi |   8 +
+ Documentation/cgroup-v2.txt               |  74 +++++++
+ Documentation/sysctl/vm.txt               |   5 +-
+ arch/alpha/include/uapi/asm/mman.h        |   1 +
+ arch/arc/include/asm/bug.h                |   3 +-
+ arch/arm/include/asm/page.h               |   2 +
+ arch/arm/mm/dma-mapping.c                 |  16 +-
+ arch/cris/include/arch-v10/arch/bug.h     |  11 +-
+ arch/ia64/include/asm/bug.h               |   6 +-
+ arch/m68k/include/asm/bug.h               |   3 +
+ arch/metag/kernel/process.c               |   6 +-
+ arch/mips/include/uapi/asm/mman.h         |   1 +
+ arch/parisc/include/uapi/asm/mman.h       |   1 +
+ arch/powerpc/mm/mmu_context_iommu.c       |   3 +-
+ arch/sparc/include/asm/bug.h              |   6 +-
+ arch/x86/kernel/machine_kexec_64.c        |   1 +
+ arch/xtensa/include/uapi/asm/mman.h       |   1 +
+ block/genhd.c                             |   2 +-
+ certs/blacklist_nohashes.c                |   2 +-
+ fs/binfmt_elf.c                           |  22 +-
+ fs/dcache.c                               |   3 +-
+ fs/exec.c                                 |   1 +
+ fs/ocfs2/dlmglue.c                        |   2 +-
+ fs/ocfs2/filecheck.c                      | 357 ++++++++++++------------------
+ fs/ocfs2/filecheck.h                      |  29 ++-
+ fs/ocfs2/ocfs2.h                          |   8 +
+ fs/ocfs2/stackglue.c                      |   6 -
+ fs/ocfs2/stackglue.h                      |   3 -
+ fs/ocfs2/super.c                          |  27 ++-
+ fs/proc/task_mmu.c                        |  21 +-
+ fs/seq_file.c                             |  65 +++++-
+ include/asm-generic/bug.h                 |   1 +
+ include/linux/cgroup-defs.h               |   5 +
+ include/linux/compiler-gcc.h              |  15 +-
+ include/linux/compiler.h                  |   5 +
+ include/linux/crash_core.h                |   2 +
+ include/linux/kconfig.h                   |   6 +
+ include/linux/list_lru.h                  |   3 +-
+ include/linux/memcontrol.h                |  58 ++++-
+ include/linux/memory_hotplug.h            |   3 -
+ include/linux/migrate.h                   |   7 +-
+ include/linux/mm.h                        |   2 +
+ include/linux/mmzone.h                    |   2 +-
+ include/linux/oom.h                       |  12 +-
+ include/linux/page-isolation.h            |   3 +-
+ include/linux/sched/mm.h                  |   8 +-
+ include/linux/sched/signal.h              |   3 +
+ include/linux/seq_file.h                  |   3 +
+ include/linux/shrinker.h                  |   2 +-
+ include/linux/swap.h                      |   2 -
+ include/uapi/asm-generic/mman-common.h    |   3 +
+ include/uapi/linux/prctl.h                |   4 +
+ include/uapi/linux/sysctl.h               |   4 +
+ kernel/cgroup/cgroup.c                    |  13 +-
+ kernel/cred.c                             |   1 +
+ kernel/exit.c                             |   4 +
+ kernel/fork.c                             |  17 +-
+ kernel/relay.c                            |   2 +-
+ kernel/sys.c                              |  11 +
+ lib/idr.c                                 |   2 -
+ lib/radix-tree.c                          |   2 +-
+ mm/backing-dev.c                          |  35 +++
+ mm/cma.c                                  |  83 ++++++-
+ mm/compaction.c                           |   7 +-
+ mm/huge_memory.c                          |   6 +
+ mm/internal.h                             |   5 +-
+ mm/kasan/kasan.c                          |  57 ++++-
+ mm/ksm.c                                  |   8 +-
+ mm/list_lru.c                             |  74 +++++--
+ mm/memcontrol.c                           | 264 +++++++++++++++++++++-
+ mm/memory-failure.c                       |  18 +-
+ mm/memory.c                               |   2 +-
+ mm/memory_hotplug.c                       |   9 +-
+ mm/mempolicy.c                            |  40 +---
+ mm/migrate.c                              | 357 +++++++++++++-----------------
+ mm/mlock.c                                |   6 +
+ mm/mmap.c                                 |  11 +
+ mm/oom_kill.c                             | 210 ++++++++++++------
+ mm/page_alloc.c                           | 108 +++++----
+ mm/page_io.c                              |   2 +-
+ mm/page_isolation.c                       |   3 +-
+ mm/page_owner.c                           |   4 +-
+ mm/swap.c                                 |  82 ++++---
+ mm/swapfile.c                             |   6 +-
+ mm/vmscan.c                               |  75 ++-----
+ security/apparmor/lsm.c                   |   1 +
+ security/selinux/hooks.c                  |   1 +
+ tools/cgroup/Makefile                     |   1 -
+ tools/gpio/Makefile                       |   2 -
+ tools/hv/Makefile                         |   1 -
+ tools/iio/Makefile                        |   2 -
+ tools/laptop/freefall/Makefile            |   1 -
+ tools/leds/Makefile                       |   1 -
+ tools/perf/Makefile.perf                  |   6 -
+ tools/power/acpi/Makefile.config          |   3 -
+ tools/scripts/Makefile.include            |  18 ++
+ tools/spi/Makefile                        |   2 -
+ tools/usb/Makefile                        |   1 -
+ tools/vm/Makefile                         |   1 -
+ tools/wmi/Makefile                        |   1 -
+ 100 files changed, 1575 insertions(+), 840 deletions(-)
+$ git clone -s -l -n -q . ../rebase-tmp
+$ cd ../rebase-tmp
+$ git checkout -b akpm remotes/origin/akpm/master
+Switched to a new branch 'akpm'
+$ git rebase --onto master remotes/origin/akpm/master-base
+First, rewinding head to replay your work on top of it...
+Applying: ipc/mqueue: add missing error code in init_mqueue_fs()
+Applying: drivers/media/platform/sti/delta/delta-ipc.c: fix read buffer overflow
+Applying: sparc64: NG4 memset 32 bits overflow
+$ cd ../next
+$ git fetch -f ../rebase-tmp akpm:akpm/master
+From ../rebase-tmp
+ + 696e646a8bc4...5685a07f937f akpm       -> akpm/master  (forced update)
+$ rm -rf ../rebase-tmp
+Merging akpm/master (5685a07f937f sparc64: NG4 memset 32 bits overflow)
+$ git merge --no-ff akpm/master
+Merge made by the 'recursive' strategy.
+ arch/sparc/lib/NG4memset.S                   | 26 +++++++++++++-------------
+ drivers/media/platform/sti/delta/delta-ipc.c |  4 ++--
+ ipc/mqueue.c                                 |  4 +++-
+ 3 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/Next/quilt-import.log b/Next/quilt-import.log
new file mode 100644
index 000000000000..293b1e8b2e1a
--- /dev/null
+++ b/Next/quilt-import.log
@@ -0,0 +1,2 @@
+Importing dmi based on 4.15
+Unchanged quilt series dmi
diff --git a/arch/Kconfig b/arch/Kconfig
index 76c0b54443b1..8e0d665c8d53 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -596,12 +596,6 @@ config CC_STACKPROTECTOR_AUTO
 
 endchoice
 
-config THIN_ARCHIVES
-	def_bool y
-	help
-	  Select this if the architecture wants to use thin archives
-	  instead of ld -r to create the built-in.o files.
-
 config LD_DEAD_CODE_DATA_ELIMINATION
 	bool
 	help
diff --git a/arch/alpha/include/uapi/asm/mman.h b/arch/alpha/include/uapi/asm/mman.h
index 2dbdf59258d9..f9d4e6b6d4bd 100644
--- a/arch/alpha/include/uapi/asm/mman.h
+++ b/arch/alpha/include/uapi/asm/mman.h
@@ -32,6 +32,7 @@
 #define MAP_NONBLOCK	0x40000		/* do not block on IO */
 #define MAP_STACK	0x80000		/* give out an address that is best suited for process/thread stacks */
 #define MAP_HUGETLB	0x100000	/* create a huge page mapping */
+#define MAP_FIXED_NOREPLACE	0x200000/* MAP_FIXED which doesn't unmap underlying mapping */
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_SYNC		2		/* synchronous memory sync */
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index f3a80cf164cc..d76bf4a83740 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -484,7 +484,6 @@ config ARC_CURR_IN_REG
 
 config ARC_EMUL_UNALIGNED
 	bool "Emulate unaligned memory access (userspace only)"
-	default N
 	select SYSCTL_ARCH_UNALIGN_NO_WARN
 	select SYSCTL_ARCH_UNALIGN_ALLOW
 	depends on ISA_ARCOMPACT
diff --git a/arch/arc/boot/dts/axs101.dts b/arch/arc/boot/dts/axs101.dts
index 70aec7d6ca60..626b694c7be7 100644
--- a/arch/arc/boot/dts/axs101.dts
+++ b/arch/arc/boot/dts/axs101.dts
@@ -17,6 +17,6 @@
 	compatible = "snps,axs101", "snps,arc-sdp";
 
 	chosen {
-		bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60";
+		bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60 print-fatal-signals=1";
 	};
 };
diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi
index 74d070cd3c13..47b74fbc403c 100644
--- a/arch/arc/boot/dts/axs10x_mb.dtsi
+++ b/arch/arc/boot/dts/axs10x_mb.dtsi
@@ -214,13 +214,13 @@
 			};
 
 			eeprom@0x54{
-				compatible = "24c01";
+				compatible = "atmel,24c01";
 				reg = <0x54>;
 				pagesize = <0x8>;
 			};
 
 			eeprom@0x57{
-				compatible = "24c04";
+				compatible = "atmel,24c04";
 				reg = <0x57>;
 				pagesize = <0x8>;
 			};
diff --git a/arch/arc/boot/dts/haps_hs_idu.dts b/arch/arc/boot/dts/haps_hs_idu.dts
index 215cddd0b63b..0c603308aeb3 100644
--- a/arch/arc/boot/dts/haps_hs_idu.dts
+++ b/arch/arc/boot/dts/haps_hs_idu.dts
@@ -22,7 +22,7 @@
 	};
 
 	chosen {
-		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 debug";
+		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 debug print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/boot/dts/nsim_700.dts b/arch/arc/boot/dts/nsim_700.dts
index 5ee96b067c08..ff2f2c70c545 100644
--- a/arch/arc/boot/dts/nsim_700.dts
+++ b/arch/arc/boot/dts/nsim_700.dts
@@ -17,7 +17,7 @@
 	interrupt-parent = <&core_intc>;
 
 	chosen {
-		bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
+		bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/boot/dts/nsim_hs.dts b/arch/arc/boot/dts/nsim_hs.dts
index 8d787b251f73..8e2489b16b0a 100644
--- a/arch/arc/boot/dts/nsim_hs.dts
+++ b/arch/arc/boot/dts/nsim_hs.dts
@@ -24,7 +24,7 @@
 	};
 
 	chosen {
-		bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
+		bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/boot/dts/nsim_hs_idu.dts b/arch/arc/boot/dts/nsim_hs_idu.dts
index 4f98ebf71fd8..ed12f494721d 100644
--- a/arch/arc/boot/dts/nsim_hs_idu.dts
+++ b/arch/arc/boot/dts/nsim_hs_idu.dts
@@ -15,7 +15,7 @@
 	interrupt-parent = <&core_intc>;
 
 	chosen {
-		bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
+		bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/boot/dts/nsimosci.dts b/arch/arc/boot/dts/nsimosci.dts
index 3c391ba565ed..7842e5eb4ab5 100644
--- a/arch/arc/boot/dts/nsimosci.dts
+++ b/arch/arc/boot/dts/nsimosci.dts
@@ -20,7 +20,7 @@
 		/* this is for console on PGU */
 		/* bootargs = "console=tty0 consoleblank=0"; */
 		/* this is for console on serial */
-		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24";
+		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24 print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/boot/dts/nsimosci_hs.dts b/arch/arc/boot/dts/nsimosci_hs.dts
index 14a727cbf4c9..b8838cf2b4ec 100644
--- a/arch/arc/boot/dts/nsimosci_hs.dts
+++ b/arch/arc/boot/dts/nsimosci_hs.dts
@@ -20,7 +20,7 @@
 		/* this is for console on PGU */
 		/* bootargs = "console=tty0 consoleblank=0"; */
 		/* this is for console on serial */
-		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24";
+		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24 print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/boot/dts/nsimosci_hs_idu.dts b/arch/arc/boot/dts/nsimosci_hs_idu.dts
index 5052917d4a99..72a2c723f1f7 100644
--- a/arch/arc/boot/dts/nsimosci_hs_idu.dts
+++ b/arch/arc/boot/dts/nsimosci_hs_idu.dts
@@ -18,7 +18,7 @@
 
 	chosen {
 		/* this is for console on serial */
-		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24";
+		bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24 print-fatal-signals=1";
 	};
 
 	aliases {
diff --git a/arch/arc/include/asm/bug.h b/arch/arc/include/asm/bug.h
index ea022d47896c..21ec82466d62 100644
--- a/arch/arc/include/asm/bug.h
+++ b/arch/arc/include/asm/bug.h
@@ -23,7 +23,8 @@ void die(const char *str, struct pt_regs *regs, unsigned long address);
 
 #define BUG()	do {								\
 	pr_warn("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-	dump_stack();								\
+	barrier_before_unreachable();						\
+	__builtin_trap();							\
 } while (0)
 
 #define HAVE_ARCH_BUG
diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h
index 257a68f3c2fe..309f4e6721b3 100644
--- a/arch/arc/include/asm/entry-arcv2.h
+++ b/arch/arc/include/asm/entry-arcv2.h
@@ -184,7 +184,7 @@
 .macro FAKE_RET_FROM_EXCPN
 	lr      r9, [status32]
 	bic     r9, r9, (STATUS_U_MASK|STATUS_DE_MASK|STATUS_AE_MASK)
-	or      r9, r9, (STATUS_L_MASK|STATUS_IE_MASK)
+	or      r9, r9, STATUS_IE_MASK
 	kflag   r9
 .endm
 
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index 9d27331fe69a..ec12fe1c2f07 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -373,7 +373,7 @@ static void arc_chk_core_config(void)
 {
 	struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
 	int saved = 0, present = 0;
-	char *opt_nm = NULL;;
+	char *opt_nm = NULL;
 
 	if (!cpu->extn.timer0)
 		panic("Timer0 is not present!\n");
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 333daab7def0..183391d4d33a 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -366,7 +366,7 @@ static void init_unwind_hdr(struct unwind_table *table,
 	return;
 
 ret_err:
-	panic("Attention !!! Dwarf FDE parsing errors\n");;
+	panic("Attention !!! Dwarf FDE parsing errors\n");
 }
 
 #ifdef CONFIG_MODULES
diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c
index eee924dfffa6..2072f3451e9c 100644
--- a/arch/arc/mm/cache.c
+++ b/arch/arc/mm/cache.c
@@ -780,7 +780,10 @@ noinline static void slc_entire_op(const int op)
 
 	write_aux_reg(r, ctrl);
 
-	write_aux_reg(ARC_REG_SLC_INVALIDATE, 1);
+	if (op & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
+		write_aux_reg(ARC_REG_SLC_INVALIDATE, 0x1);
+	else
+		write_aux_reg(ARC_REG_SLC_FLUSH, 0x1);
 
 	/* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
 	read_aux_reg(r);
diff --git a/arch/arm/arm-soc-for-next-contents.txt b/arch/arm/arm-soc-for-next-contents.txt
new file mode 100644
index 000000000000..ce0fa061861b
--- /dev/null
+++ b/arch/arm/arm-soc-for-next-contents.txt
@@ -0,0 +1,239 @@
+next/soc
+	patch
+		arm64: defconfig: enable new trigger modes for leds
+	renesas/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-soc-for-v4.16
+	patch
+		MAINTAINERS: Add self as extended maintainer for a slew of files
+		arm64: defconfig: enable CONFIG_UNIPHIER_EFUSE
+	ep93xx/soc
+		https://github.com/sverdlin/ep93xx tags/bk3
+	omap/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/soc-signed
+	omap/defconfig
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.15/defconfig-v2-signed
+	samsung/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-defconfig-4.16
+	tegra/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux tags/tegra-for-4.16-soc-2
+	mediatek/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/matthias.bgg/linux tags/v4.15-next-soc
+	patch
+		soc: Add SoC driver for Gemini
+	renesas/defconfig
+		https://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-defconfig-for-v4.16
+	renesas/soc2
+		https://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-soc2-for-v4.16
+	mvebu/arm64
+		git://git.infradead.org/linux-mvebu tags/mvebu-arm64-4.16-1
+	omap/soc-2
+		git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/soc-pt2-signed
+	omap/defconfig-2
+		git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/defconfig-signed
+	pxa/for-4.16
+		https://github.com/rjarzmik/linux tags/pxa-for-4.16
+	keystone/config
+		git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone tags/keystone_config_for_4.16
+	sunxi/config64
+		https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux tags/sunxi-config64-for-4.16
+	qcom/defconfig64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux tags/qcom-arm64-defconfig-for-4.16
+	qcom/defconfig
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux tags/qcom-defconfig-for-4.16
+	patch
+		Wind down ARM/TANGO port
+	imx/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux tags/imx-soc-4.16
+	davinci/soc
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci tags/davinci-for-v4.16/soc-v2
+	<no branch> (8bb65fc06c08f027980a917648e1cf6e4d51c5ad)
+		Merge commit '8bb65fc06c' into next/soc
+	imx/defconfig
+		git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux tags/imx-defconfig-4.16
+	samsung/soc-2
+		https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-soc-4.16-2
+	patch
+		arm64: defconfig: enable CONFIG_ACPI_APEI_MEMORY_FAILURE
+		arm64: defconfig: enable EDAC GHES option
+		arm64: defconfig: enable CONFIG_ACPI_APEI_EINJ
+		ARM: pxa/tosa-bt: add MODULE_LICENSE tag
+		ARM: omap: hwmod: fix section mismatch warnings
+
+next/dt
+	patch
+		ARM: dts: efm32: Add generic compatible string for I2C EEPROM
+		ARM: dts: lpc18xx: Add generic compatible string for I2C EEPROM
+		ARM: dts: socfpga: Add generic compatible string for I2C EEPROM
+		ARM: make ARCH_S3C24XX select USE_OF and clean-up boot/dts/Makefile
+		arm64: dts: qcom: apq8016-sbc: Allow USR4 LED to notify kernel panic
+		arm64: dts: hisilicon: hi3660-hikey960: Allow USR4 LED to notify kernel panic
+		arm64: dts: hisilicon: hi6220-hikey: Allow USR1 LED to notify kernel panic
+	renesas/dt-bindings
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-dt-bindings-for-v4.16
+	renesas/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-dt-for-v4.16
+	renesas/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-arm64-dt-for-v4.16
+	amlogic/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic tags/amlogic-dt
+	amlogic/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic tags/amlogic-dt64
+	omap/dt-clk
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/dt-clk-signed
+		contains omap/soc
+	omap/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/dt-signed
+	gemini/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik tags/gemni-dts-1
+	samsung/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-dt-4.16
+	samsung/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-dt64-4.16
+	tegra/dt-bindings
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux tags/tegra-for-4.16-dt-bindings
+	tegra/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux tags/tegra-for-4.16-arm-dt
+	tegra/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux tags/tegra-for-4.16-arm64-dt
+	mediatek/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/matthias.bgg/linux tags/v4.15-next-dts32
+	mediatek/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/matthias.bgg/linux tags/v4.15-next-dts64
+	rockchip/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip tags/v4.16-rockchip-dts32-1
+	rockchip/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip tags/v4.16-rockchip-dts64-1
+	patch
+		arm64: dts: add syscon for whale2 platform
+		arm64: dts: add clocks for SC9860
+	gemini/dt-2
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik tags/gemini-dts-update-2
+	patch
+		arm64: dts: sprd: remove broken header inclusion
+	broadcom/devicetree
+		http://github.com/Broadcom/stblinux tags/arm-soc/for-4.16/devicetree
+	hisi/dt64
+		git://github.com/hisilicon/linux-hisi tags/hisi-arm64-dt-for-4.16-v2
+	actions/dt
+		git://git.kernel.org/pub/scm/linux/kernel/git/afaerber/linux-actions tags/actions-arm-dt-for-4.16
+	actions/dt64
+		git://git.kernel.org/pub/scm/linux/kernel/git/afaerber/linux-actions tags/actions-arm64-dt-for-4.16
+	renesas/dt64-2
+		https://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-arm64-dt2-for-v4.16
+	reneases/dt2
+		https://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas tags/renesas-dt2-for-v4.16
+	mvebu/dt
+		git://git.infradead.org/linux-mvebu tags/mvebu-dt-4.16-1
+	mvebu/dt64
+		git://git.infradead.org/linux-mvebu tags/mvebu-dt64-4.16-1
+	omap/dt-2
+		git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/dt-pt2-v2-signed
+	keystone/dts
+		git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone tags/keystone_dts_for_4.16
+	sunxi/dt
+		https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux tags/sunxi-dt-for-4.16
+	sunxi/dt64
+		https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux tags/sunxi-dt64-for-4.16
+	uniphier/dt
+		git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier tags/uniphier-dt-v4.16
+	uniphier/dt64
+		git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier tags/uniphier-dt64-v4.16
+	at91/dt
+		git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux tags/at91-ab-4.16-dt
+	patch
+		ARM: dts: Delete bogus reference to the charlcd
+	qcom/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux tags/qcom-arm64-for-4.16
+	qcom/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux tags/qcom-dts-for-4.16
+	amlogic/dt64-2
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic tags/amlogic-dt64-2
+	aspeed/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/joel/aspeed tags/aspeed-4.16-devicetree
+	imx/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux tags/imx-dt-4.16
+	imx/dt64
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux tags/imx-dt64-4.16
+	mvebu/dt64-2
+		git://git.infradead.org/linux-mvebu tags/mvebu-dt64-4.16-2
+	amlogic/dt-3
+		git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic tags/amlogic-dt64-3
+	sunxi/dt-2
+		https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux tags/sunxi-dt-for-4.16-2
+	samsung/dt-2
+		https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-dt-4.16-2
+	samsung/dt64-2
+		https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-dt64-4.16-2
+	patch
+		arm64: dts: add #cooling-cells to CPU nodes
+		arm: spear600: Add missing interrupt-parent of rtc
+		arm: spear13xx: Fix dmas cells
+		arm: spear13xx: Fix spics gpio controller's warning
+		ARM: dts: STi: Add gpio polarity for "hdmi,hpd-gpio" property
+		ARM: lpc3250: fix uda1380 gpio numbers
+		ARM: dts: s5pv210: add interrupt-parent for ohci
+		ARM: dts: rename oxnas dts files
+	mvebu/dt-3
+		git://git.infradead.org/linux-mvebu tags/mvebu-dt64-4.16-3
+	gemini/dt-3
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik tags/gemini-dts-update-3
+	patch
+		ARM: dts: nomadik: add interrupt-parent for clcd
+	omap/clk-dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/dt-clk-dts-signed
+	omap/dt-pt3
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/dt-pt3-signed
+	socfpga/dt
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux tags/socfpga_dts_for_v4.16
+
+next/drivers
+	drivers/tee
+		https://git.linaro.org/people/jens.wiklander/linux-tee tags/tee-drv-async-supplicant-for-v4.16
+	drivers/gpmc-omap
+		https://github.com/rogerq/linux tags/gpmc-omap-for-v4.16-immutable
+	drivers/tee-2
+		https://git.linaro.org/people/jens.wiklander/linux-tee tags/tee-drv-dynamic-shm-for-v4.16
+	tegra/memory
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tegra/linux tags/tegra-for-4.16-memory
+		contains tegra/dt-bindings
+	patch
+		tee: optee: fix header dependencies
+	broadcom/drivers
+		http://github.com/Broadcom/stblinux tags/arm-soc/for-4.16/drivers
+	actions/drivers
+		git://git.kernel.org/pub/scm/linux/kernel/git/afaerber/linux-actions tags/actions-drivers-for-4.16
+	omap/ti-sysc
+		git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/ti-sysc-signed
+	keystone/driver
+		git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone tags/keystone_driver_soc_for_4.16
+	at91/drivers
+		git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux tags/at91-ab-4.16-drivers
+	qcom/drivers
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/agross/linux tags/qcom-drivers-for-4.16
+	drivers/reset
+		git://git.pengutronix.de/git/pza/linux tags/reset-for-4.16
+	imx/drivers
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux tags/imx-drivers-4.16
+	patch
+		soc: brcmstb: Only register SoC device on STB platforms
+	samsung/drivers-2
+		https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux tags/samsung-drivers-4.16-2
+	patch
+		bus: omap: add MODULE_LICENSE tags
+	drivers/tee-fixes
+		https://git.linaro.org/people/jens.wiklander/linux-tee tags/tee-drv-dynamic-shm+fixes-for-v4.16
+	xlnx/soc
+		https://github.com/Xilinx/linux-xlnx tags/zynqmp-soc-for-4.16
+	patch
+		Revert "soc: brcmstb: Only register SoC device on STB platforms"
+		soc: brcmstb: biuctrl: exit without warning on non brcmstb platforms
+		soc: bcm: brcmstb: Be multi-platform compatible
+		psci: add CPU_IDLE dependency
+		of: platform: fix OF node refcount leak
+	fsl/soc-driver
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/leo/linux tags/soc-fsl-for-4.16
+	zynq/soc-fixes
+		https://github.com/Xilinx/linux-xlnx tags/zynqmp-soc-fixes-for-4.16
+	omap/ti-sysc-fix
+		ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.16/ti-sysc-fix-signed
+
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index ade7a38543dc..26e2e290ec28 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -163,7 +163,10 @@ dtb-$(CONFIG_ARCH_EXYNOS4) += \
 	exynos4210-smdkv310.dtb \
 	exynos4210-trats.dtb \
 	exynos4210-universal_c210.dtb \
+	exynos4412-i9300.dtb \
+	exynos4412-i9305.dtb \
 	exynos4412-itop-elite.dtb \
+	exynos4412-n710x.dtb \
 	exynos4412-odroidu3.dtb \
 	exynos4412-odroidx.dtb \
 	exynos4412-odroidx2.dtb \
@@ -396,6 +399,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6dl-icore-rqs.dtb \
 	imx6dl-nit6xlite.dtb \
 	imx6dl-nitrogen6x.dtb \
+	imx6dl-phytec-mira-rdk-nand.dtb \
 	imx6dl-phytec-pbab01.dtb \
 	imx6dl-rex-basic.dtb \
 	imx6dl-riotboard.dtb \
@@ -465,6 +469,8 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6q-nitrogen6_max.dtb \
 	imx6q-nitrogen6_som2.dtb \
 	imx6q-novena.dtb \
+	imx6q-phytec-mira-rdk-emmc.dtb \
+	imx6q-phytec-mira-rdk-nand.dtb \
 	imx6q-phytec-pbab01.dtb \
 	imx6q-pistachio.dtb \
 	imx6q-rex-pro.dtb \
@@ -494,6 +500,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6q-zii-rdu2.dtb \
 	imx6qp-nitrogen6_max.dtb \
 	imx6qp-nitrogen6_som2.dtb \
+	imx6qp-phytec-mira-rdk-nand.dtb \
 	imx6qp-sabreauto.dtb \
 	imx6qp-sabresd.dtb \
 	imx6qp-tx6qp-8037.dtb \
@@ -526,7 +533,9 @@ dtb-$(CONFIG_SOC_IMX6UL) += \
 	imx6ul-tx6ul-0010.dtb \
 	imx6ul-tx6ul-0011.dtb \
 	imx6ul-tx6ul-mainboard.dtb \
-	imx6ull-14x14-evk.dtb
+	imx6ull-14x14-evk.dtb \
+	imx6ull-colibri-eval-v3.dtb \
+	imx6ull-colibri-wifi-eval-v3.dtb
 dtb-$(CONFIG_SOC_IMX7D) += \
 	imx7d-cl-som-imx7.dtb \
 	imx7d-colibri-emmc-eval-v3.dtb \
@@ -673,6 +682,7 @@ dtb-$(CONFIG_SOC_AM33XX) += \
 	am335x-lxm.dtb \
 	am335x-moxa-uc-8100-me-t.dtb \
 	am335x-nano.dtb \
+	am335x-pdu001.dtb \
 	am335x-pepper.dtb \
 	am335x-phycore-rdk.dtb \
 	am335x-shc.dtb \
@@ -784,6 +794,7 @@ dtb-$(CONFIG_ARCH_RENESAS) += \
 	r8a7778-bockw.dtb \
 	r8a7779-marzen.dtb \
 	r8a7790-lager.dtb \
+	r8a7790-stout.dtb \
 	r8a7791-koelsch.dtb \
 	r8a7791-porter.dtb \
 	r8a7792-blanche.dtb \
@@ -942,6 +953,8 @@ dtb-$(CONFIG_MACH_SUN7I) += \
 	sun7i-a20-m3.dtb \
 	sun7i-a20-mk808c.dtb \
 	sun7i-a20-olimex-som-evb.dtb \
+	sun7i-a20-olimex-som204-evb.dtb \
+	sun7i-a20-olimex-som204-evb-emmc.dtb \
 	sun7i-a20-olinuxino-lime.dtb \
 	sun7i-a20-olinuxino-lime2.dtb \
 	sun7i-a20-olinuxino-lime2-emmc.dtb \
@@ -974,6 +987,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-a83t-cubietruck-plus.dtb \
 	sun8i-a83t-tbs-a711.dtb \
 	sun8i-h2-plus-orangepi-r1.dtb \
+	sun8i-h2-plus-bananapi-m2-zero.dtb \
 	sun8i-h2-plus-orangepi-zero.dtb \
 	sun8i-h3-bananapi-m2-plus.dtb \
 	sun8i-h3-beelink-x2.dtb \
diff --git a/arch/arm/boot/dts/am335x-boneblue.dts b/arch/arm/boot/dts/am335x-boneblue.dts
index 3f2480d05a3b..58baee158e64 100644
--- a/arch/arm/boot/dts/am335x-boneblue.dts
+++ b/arch/arm/boot/dts/am335x-boneblue.dts
@@ -342,7 +342,7 @@
 	};
 
 	baseboard_eeprom: baseboard_eeprom@50 {
-		compatible = "at,24c256";
+		compatible = "atmel,24c256";
 		reg = <0x50>;
 
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/am335x-pdu001.dts b/arch/arm/boot/dts/am335x-pdu001.dts
new file mode 100644
index 000000000000..1ad530a39a95
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-pdu001.dts
@@ -0,0 +1,595 @@
+/*
+ * pdu001.dts
+ *
+ * EETS GmbH PDU001 board device tree file
+ *
+ * Copyright (C) 2018 EETS GmbH - http://www.eets.ch/
+ *
+ * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier:  GPL-2.0+
+ */
+
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/leds/leds-pca9532.h>
+
+/ {
+	model = "EETS,PDU001";
+	compatible = "ti,am33xx";
+
+	chosen {
+		stdout-path = &uart3;
+	};
+
+	cpus {
+		cpu@0 {
+			cpu0-supply = <&vdd1_reg>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>; /* 256 MB */
+	};
+
+	vbat: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vbat";
+		regulator-min-microvolt = <3600000>;
+		regulator-max-microvolt = <3600000>;
+		regulator-boot-on;
+	};
+
+	lis3_reg: fixedregulator@1 {
+		compatible = "regulator-fixed";
+		regulator-name = "lis3_reg";
+		regulator-boot-on;
+	};
+
+	panel {
+		compatible = "ti,tilcdc,panel";
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_pins_s0>;
+		panel-info {
+			ac-bias           = <255>;
+			ac-bias-intrpt    = <0>;
+			dma-burst-sz      = <16>;
+			bpp               = <16>;
+			fdd               = <0x80>;
+			sync-edge         = <0>;
+			sync-ctrl         = <1>;
+			raster-order      = <0>;
+			fifo-th           = <0>;
+		};
+
+		display-timings {
+			240x320p16 {
+				clock-frequency = <6500000>;
+				hactive = <240>;
+				vactive = <320>;
+				hfront-porch = <6>;
+				hback-porch = <6>;
+				hsync-len = <1>;
+				vback-porch = <6>;
+				vfront-porch = <6>;
+				vsync-len = <1>;
+				hsync-active = <0>;
+				vsync-active = <0>;
+				pixelclk-active = <1>;
+				de-active = <0>;
+			};
+		};
+	};
+};
+
+&am33xx_pinmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&clkout2_pin>;
+
+	i2c0_pins: pinmux_i2c0_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_sda.i2c0_sda */
+			AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_scl.i2c0_scl */
+		>;
+	};
+
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2)	/* spi0_d1.i2c1_sda */
+			AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2)	/* spi0_cs0.i2c1_scl */
+		>;
+	};
+
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE2)	/* spi0_clk.i2c2_sda */
+			AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE2)	/* spi0_d0.i2c2_scl */
+		>;
+	};
+
+	spi1_pins: pinmux_spi1_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x990, PIN_OUTPUT | MUX_MODE3)		/* mcasp0_aclkx.spi1_sclk */
+			AM33XX_IOPAD(0x994, PIN_OUTPUT | MUX_MODE3)		/* mcasp0_fsx.spi1_d0 */
+			AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE3)	/* mcasp0_axr0.spi1_d1 */
+			AM33XX_IOPAD(0x99C, PIN_OUTPUT | MUX_MODE3)		/* mcasp0_ahclkr.spi1_cs0 */
+		>;
+	};
+
+	uart0_pins: pinmux_uart0_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x96C, PIN_OUTPUT | MUX_MODE7)		/* uart0_rtsn.gpio1_9 */
+			AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
+			AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart0_txd.uart0_txd */
+		>;
+	};
+
+	uart1_pins: pinmux_uart1_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart1_rxd.uart1_rxd */
+			AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart1_txd.uart1_txd */
+		>;
+	};
+
+	uart3_pins: pinmux_uart3_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE1)	/* spi0_cs1.uart3_rxd */
+			AM33XX_IOPAD(0x964, PIN_OUTPUT_PULLDOWN | MUX_MODE1)	/* ecap0_in_pwm0_out.uart3_txd */
+		>;
+	};
+
+	clkout2_pin: pinmux_clkout2_pin {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr1.clkout2 */
+		>;
+	};
+
+	cpsw_default: cpsw_default {
+		pinctrl-single,pins = <
+			/* Port 1 (emac0) */
+			AM33XX_IOPAD(0x908, PIN_INPUT | MUX_MODE0)		/* mii1_col.mii1_col */
+			AM33XX_IOPAD(0x90C, PIN_INPUT | MUX_MODE0)		/* mii1_crs.mii1_crs */
+			AM33XX_IOPAD(0x910, PIN_INPUT | MUX_MODE0)		/* mii1_rxer.mii1_rxer */
+			AM33XX_IOPAD(0x914, PIN_OUTPUT | MUX_MODE0)		/* mii1_txen.mii1_txen */
+			AM33XX_IOPAD(0x918, PIN_INPUT | MUX_MODE0)		/* mii1_rxdv.mii1_rxdv */
+			AM33XX_IOPAD(0x91c, PIN_OUTPUT | MUX_MODE0)		/* mii1_txd3.mii1_txd3 */
+			AM33XX_IOPAD(0x920, PIN_OUTPUT | MUX_MODE0)		/* mii1_txd2.mii1_txd2 */
+			AM33XX_IOPAD(0x924, PIN_OUTPUT | MUX_MODE0)		/* mii1_txd1.mii1_txd1 */
+			AM33XX_IOPAD(0x928, PIN_OUTPUT | MUX_MODE0)		/* mii1_txd0.mii1_txd0 */
+			AM33XX_IOPAD(0x92c, PIN_INPUT | MUX_MODE0)		/* mii1_txclk.mii1_txclk */
+			AM33XX_IOPAD(0x930, PIN_INPUT | MUX_MODE0)		/* mii1_rxclk.mii1_rxclk */
+			AM33XX_IOPAD(0x934, PIN_INPUT | MUX_MODE0)		/* mii1_rxd3.mii1_rxd3 */
+			AM33XX_IOPAD(0x938, PIN_INPUT | MUX_MODE0)		/* mii1_rxd2.mii1_rxd2 */
+			AM33XX_IOPAD(0x93c, PIN_INPUT | MUX_MODE0)		/* mii1_rxd1.mii1_rxd1 */
+			AM33XX_IOPAD(0x940, PIN_INPUT | MUX_MODE0)		/* mii1_rxd0.mii1_rxd0 */
+
+			/* Port 2 (emac1) */
+			AM33XX_IOPAD(0x840, PIN_OUTPUT | MUX_MODE1)		/* mii2_txen.gpmc_a0 */
+			AM33XX_IOPAD(0x844, PIN_INPUT | MUX_MODE1)		/* mii2_rxdv.gpmc_a1 */
+			AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE1)		/* mii2_txd3.gpmc_a2 */
+			AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE1)		/* mii2_txd2.gpmc_a3 */
+			AM33XX_IOPAD(0x850, PIN_OUTPUT | MUX_MODE1)		/* mii2_txd1.gpmc_a4 */
+			AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE1)		/* mii2_txd0.gpmc_a5 */
+			AM33XX_IOPAD(0x858, PIN_INPUT | MUX_MODE1)		/* mii2_txclk.gpmc_a6 */
+			AM33XX_IOPAD(0x85c, PIN_INPUT | MUX_MODE1)		/* mii2_rxclk.gpmc_a7 */
+			AM33XX_IOPAD(0x860, PIN_INPUT | MUX_MODE1)		/* mii2_rxd3.gpmc_a8 */
+			AM33XX_IOPAD(0x864, PIN_INPUT | MUX_MODE1)		/* mii2_rxd2.gpmc_a9 */
+			AM33XX_IOPAD(0x868, PIN_INPUT | MUX_MODE1)		/* mii2_rxd1.gpmc_a10 */
+			AM33XX_IOPAD(0x86C, PIN_INPUT | MUX_MODE1)		/* mii2_rxd0.gpmc_a11 */
+			AM33XX_IOPAD(0x870, PIN_INPUT | MUX_MODE1)		/* mii2_crs.gpmc_wait0 */
+			AM33XX_IOPAD(0x874, PIN_INPUT | MUX_MODE1)		/* mii2_rxer.gpmc_wpn */
+			AM33XX_IOPAD(0x878, PIN_INPUT | MUX_MODE1)		/* mii2_col.gpmc_ben1 */
+		>;
+	};
+
+	davinci_mdio_default: davinci_mdio_default {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+			AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+		>;
+	};
+
+	mmc1_pins: pinmux_mmc1_pins {
+		/* eMMC */
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat3 */
+			AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat2 */
+			AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat1 */
+			AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat0 */
+			AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_clk */
+			AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_cmd */
+		>;
+	};
+
+	mmc2_pins: pinmux_mmc2_pins {
+		/* SD cardcage */
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1)	/* gpmc_ad3.mmc1_dat3 */
+			AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1)	/* gpmc_ad2.mmc1_dat2 */
+			AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1)	/* gpmc_ad1.mmc1_dat1 */
+			AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1)	/* gpmc_ad0.mmc1_dat0 */
+			AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2)	/* gpmc_csn1.mmc1_clk */
+			AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2)	/* gpmc_csn2.mmc1_cmd */
+			/* card change signal for frontpanel SD cardcage */
+			AM33XX_IOPAD(0x890, PIN_INPUT | MUX_MODE7)		/* gpmc_advn_ale.gpio2_2 */
+		>;
+	};
+
+	lcd_pins_s0: lcd_pins_s0 {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data0.lcd_data0 */
+			AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data1.lcd_data1 */
+			AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data2.lcd_data2 */
+			AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)		/* lcd_data3.lcd_data3 */
+			AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data4.lcd_data4 */
+			AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data5.lcd_data5 */
+			AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data6.lcd_data6 */
+			AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data7.lcd_data7 */
+			AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data8.lcd_data8 */
+			AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data9.lcd_data9 */
+			AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data10.lcd_data10 */
+			AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data11.lcd_data11 */
+			AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data12.lcd_data12 */
+			AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data13.lcd_data13 */
+			AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data14.lcd_data14 */
+			AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data15.lcd_data15 */
+			AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0)		/* lcd_vsync.lcd_vsync */
+			AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0)		/* lcd_hsync.lcd_hsync */
+			AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0)		/* lcd_pclk.lcd_pclk */
+			AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0)		/* lcd_ac_bias_en.lcd_ac_bias_en */
+		>;
+	};
+
+	dcan0_pins: pinmux_dcan0_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x978, PIN_OUTPUT | MUX_MODE2)		/* uart1_ctsn.d_can0_tx */
+			AM33XX_IOPAD(0x97c, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* uart1_rtsn.d_can0_rx */
+		>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+
+	rts-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+	rs485-rts-active-high;
+	rs485-rts-delay = <0 0>;
+	linux,rs485-enabled-at-boot-time;
+
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins>;
+
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+
+	status = "okay";
+	clock-frequency = <400000>;
+
+	tps: tps@2d {
+		reg = <0x2d>;
+	};
+
+	m2_eeprom: m2_eeprom@50 {
+		compatible = "atmel,24c256";
+		reg = <0x50>;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+
+	status = "okay";
+	clock-frequency = <100000>;
+
+	board_24aa025e48: board_24aa025e48@50 {
+		compatible = "atmel,24c02";
+		reg = <0x50>;
+	};
+
+	backplane_24aa025e48: backplane_24aa025e48@53 {
+		compatible = "atmel,24c02";
+		reg = <0x53>;
+	};
+
+	pca9532: pca9532@60 {
+		compatible = "nxp,pca9532";
+		reg = <0x60>;
+		psc0 = <0x97>;
+		pwm0 = <0x80>;
+		psc1 = <0x97>;
+		pwm1 = <0x10>;
+
+		run.red@0 {
+			type = <PCA9532_TYPE_LED>;
+		};
+		run.green@1 {
+			type = <PCA9532_TYPE_LED>;
+			default-state = "on";
+		};
+		s2.red@2 {
+			type = <PCA9532_TYPE_LED>;
+		};
+		s2.green@3 {
+			type = <PCA9532_TYPE_LED>;
+		};
+		s1.yellow@4 {
+			type = <PCA9532_TYPE_LED>;
+		};
+		s1.green@5 {
+			type = <PCA9532_TYPE_LED>;
+		};
+	};
+
+	pca9530: pca9530@61 {
+		compatible = "nxp,pca9530";
+		reg = <0x61>;
+
+		tft-panel@0 {
+			type = <PCA9532_TYPE_LED>;
+			linux,default-trigger = "backlight";
+			default-state = "on";
+		};
+	};
+
+	mcp79400: mcp79400@6f {
+		compatible = "microchip,mcp7940x";
+		reg = <0x6f>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+
+	status = "okay";
+	clock-frequency = <100000>;
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi1_pins>;
+	ti,pindir-d0-out-d1-in;
+	status = "okay";
+
+	cfaf240320a032t {
+		compatible = "orisetech,otm3225a";
+		reg = <0>;
+		spi-max-frequency = <1000000>;
+		// SPI mode 3
+		spi-cpol;
+		spi-cpha;
+		status = "okay";
+	};
+};
+
+&usb {
+	status = "okay";
+};
+
+&usb_ctrl_mod {
+	status = "okay";
+};
+
+&usb0_phy {
+	status = "okay";
+};
+
+&usb1_phy {
+	status = "okay";
+};
+
+&usb0 {
+	status = "okay";
+};
+
+&usb1 {
+	status = "okay";
+};
+
+&cppi41dma  {
+	status = "okay";
+};
+
+/*
+ * Disable soc's rtc as we have no VBAT for it. This makes the board
+ * rtc (Microchip MCP79400) the default rtc device 'rtc0'.
+ */
+&rtc {
+	status = "disabled";
+};
+
+&lcdc {
+	status = "okay";
+};
+
+&elm {
+	status = "okay";
+};
+
+#include "tps65910.dtsi"
+
+&tps {
+	vcc1-supply = <&vbat>;
+	vcc2-supply = <&vbat>;
+	vcc3-supply = <&vbat>;
+	vcc4-supply = <&vbat>;
+	vcc5-supply = <&vbat>;
+	vcc6-supply = <&vbat>;
+	vcc7-supply = <&vbat>;
+	vccio-supply = <&vbat>;
+
+	regulators {
+		vrtc_reg: regulator@0 {
+			regulator-name = "ldo_vrtc";
+			regulator-always-on;
+		};
+
+		vio_reg: regulator@1 {
+			regulator-name = "buck_vdd_ddr";
+			regulator-always-on;
+		};
+
+		vdd1_reg: regulator@2 {
+			/* VDD_MPU voltage limits */
+			regulator-name = "buck_vdd_mpu";
+			regulator-min-microvolt = <912500>;
+			regulator-max-microvolt = <1312500>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		vdd2_reg: regulator@3 {
+			/* VDD_CORE voltage limits */
+			regulator-name = "buck_vdd_core";
+			regulator-min-microvolt = <912500>;
+			regulator-max-microvolt = <1150000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		vdd3_reg: regulator@4 {
+			regulator-name = "boost_res";
+			regulator-always-on;
+		};
+
+		vdig1_reg: regulator@5 {
+			regulator-name = "ldo_vdig1";
+			regulator-always-on;
+		};
+
+		vdig2_reg: regulator@6 {
+			regulator-name = "ldo_vdig2";
+			regulator-always-on;
+		};
+
+		vpll_reg: regulator@7 {
+			regulator-name = "ldo_vpll";
+			regulator-always-on;
+		};
+
+		vdac_reg: regulator@8 {
+			regulator-name = "ldo_vdac";
+			regulator-always-on;
+		};
+
+		vaux1_reg: regulator@9 {
+			regulator-name = "ldo_vaux1";
+			regulator-always-on;
+		};
+
+		vaux2_reg: regulator@10 {
+			regulator-name = "ldo_vaux2";
+			regulator-always-on;
+		};
+
+		vaux33_reg: regulator@11 {
+			regulator-name = "ldo_vaux33";
+			regulator-always-on;
+		};
+
+		vmmc_reg: regulator@12 {
+			regulator-name = "ldo_vmmc";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		vbb_reg: regulator@13 {
+			regulator-name = "bat_vbb";
+		};
+	};
+};
+
+&mac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&cpsw_default>;
+	dual_emac;			/* no switch, two distinct MACs */
+	status = "okay";
+};
+
+&davinci_mdio {
+	pinctrl-names = "default";
+	pinctrl-0 = <&davinci_mdio_default>;
+	status = "okay";
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <0>;
+	phy-mode = "mii";
+	dual_emac_res_vlan = <1>;
+};
+
+&cpsw_emac1 {
+	phy_id = <&davinci_mdio>, <1>;
+	phy-mode = "mii";
+	dual_emac_res_vlan = <2>;
+};
+
+&tscadc {
+	status = "okay";
+	tsc {
+		ti,wires = <4>;
+		ti,x-plate-resistance = <200>;
+		ti,coordinate-readouts = <5>;
+		ti,wire-config = <0x01 0x10 0x22 0x33>;
+		ti,charge-delay = <0x400>;
+	};
+
+	adc {
+		ti,adc-channels = <4 5 6 7>;
+	};
+};
+
+&mmc1 {
+	status = "okay";
+	vmmc-supply = <&vmmc_reg>;
+	bus-width = <4>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	non-removable;
+};
+
+&mmc2 {
+	status = "okay";
+	vmmc-supply = <&vmmc_reg>;
+	bus-width = <4>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins>;
+	cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
+};
+
+&sham {
+	status = "okay";
+};
+
+&aes {
+	status = "okay";
+};
+
+&dcan0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&dcan0_pins>;
+};
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index b1a96e95e921..d2225bd4a76f 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -103,7 +103,7 @@
 
 				status = "okay";
 
-				isl12057: isl12057@68 {
+				isl12057: rtc@68 {
 					compatible = "isil,isl12057";
 					reg = <0x68>;
 					wakeup-source;
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index d67e7aa42b54..b73cae836bc1 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -105,7 +105,7 @@
 
 				status = "okay";
 
-				isl12057: isl12057@68 {
+				isl12057: rtc@68 {
 					compatible = "isil,isl12057";
 					reg = <0x68>;
 					wakeup-source;
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index 40c6fe21e720..e66fe80cf279 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -115,7 +115,7 @@
 					reg = <0x4c>;
 				};
 
-				isl12057: isl12057@68 {
+				isl12057: rtc@68 {
 					compatible = "isil,isl12057";
 					reg = <0x68>;
 					wakeup-source;
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
index 4379d09a261f..bbddfe1d1cc8 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
@@ -2,6 +2,7 @@
 /dts-v1/;
 
 #include "aspeed-g4.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
 
 / {
 	model = "Palmetto BMC";
@@ -26,6 +27,32 @@
 			reg = <0x5f000000 0x01000000>; /* 16M */
 		};
 	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		heartbeat {
+			gpios = <&gpio ASPEED_GPIO(R, 4) GPIO_ACTIVE_LOW>;
+		};
+
+		power {
+			gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_LOW>;
+		};
+
+		identify {
+			gpios = <&gpio ASPEED_GPIO(A, 2) GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		checkstop {
+			label = "checkstop";
+			gpios = <&gpio ASPEED_GPIO(P, 5) GPIO_ACTIVE_LOW>;
+			linux,code = <ASPEED_GPIO(P, 5)>;
+		};
+	};
 };
 
 &fmc {
@@ -47,6 +74,14 @@
 	};
 };
 
+&pinctrl {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flbusy_default &pinctrl_flwp_default
+
+			&pinctrl_vgahs_default &pinctrl_vgavs_default
+			&pinctrl_ddcclk_default &pinctrl_ddcdat_default>;
+};
+
 &uart5 {
 	status = "okay";
 };
@@ -111,3 +146,156 @@
 &vuart {
 	status = "okay";
 };
+
+&ibt {
+	status = "okay";
+};
+
+&gpio {
+	pin_func_mode0 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(C, 4) GPIO_ACTIVE_HIGH>;
+		output-low;
+		line-name = "func_mode0";
+	};
+
+	pin_func_mode1 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(C, 5)  GPIO_ACTIVE_HIGH>;
+		output-low;
+		line-name = "func_mode1";
+	};
+
+	pin_func_mode2 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(C, 6) GPIO_ACTIVE_HIGH>;
+		output-low;
+		line-name = "func_mode2";
+	};
+
+	pin_gpio_a0 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(A, 0) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "BMC_FAN_RESERVED_N";
+	};
+
+	pin_gpio_a1 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(A, 1) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "APSS_WDT_N";
+	};
+
+	pin_gpio_b1 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(B, 1) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "APSS_BOOT_MODE";
+	};
+
+	pin_gpio_b2 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(B, 2) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "APSS_RESET_N";
+	};
+
+	pin_gpio_b7 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(B, 7) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "SPIVID_STBY_RESET_N";
+	};
+
+	pin_gpio_d1 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(D, 1) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "BMC_POWER_UP";
+	};
+
+	pin_gpio_f1 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(F, 1) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "BMC_BATTERY_TEST";
+	};
+
+	pin_gpio_f4 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(F, 4) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "AST_HW_FAULT_N";
+	};
+
+	pin_gpio_f5 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(F, 5) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "AST_SYS_FAULT_N";
+	};
+
+	pin_gpio_f7 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(F, 7) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "BMC_FULL_SPEED_N";
+	};
+
+	pin_gpio_g3 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(G, 3) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "BMC_FAN_ERROR_N";
+	};
+
+	pin_gpio_g4 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(G, 4) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "BMC_WDT_RST1_P";
+	};
+
+	pin_gpio_g5 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(G, 5) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "BMC_WDT_RST2_P";
+	};
+
+	pin_gpio_h0 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "PE_SLOT_TEST_EN_N";
+	};
+
+	pin_gpio_h1 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(H, 1) GPIO_ACTIVE_HIGH>;
+		input;
+		line-name = "BMC_RTCRST_N";
+	};
+
+	pin_gpio_h2 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(H, 2) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "SYS_PWROK_BMC";
+	};
+
+	pin_gpio_h6 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(H, 6) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "SCM1_FSI0_DATA_EN";
+	};
+
+	pin_gpio_h7 {
+		gpio-hog;
+		gpios = <ASPEED_GPIO(H, 7) GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "BMC_TPM_INT_N";
+	};
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
index 623b6ab42021..d41be52c2393 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
@@ -257,3 +257,7 @@
 		aspeed,fan-tach-ch = /bits/ 8 <0x0e>;
 	};
 };
+
+&ibt {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
index 5f9049d2c4c3..7056231cbee6 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
@@ -546,3 +546,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_wdtrst1_default>;
 };
+
+&ibt {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
index c881484a85cf..ebe726a0d311 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
@@ -424,3 +424,7 @@
 		aspeed,fan-tach-ch = /bits/ 8 <0x03>;
 	};
 };
+
+&ibt {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index b0d8431a3700..48c28a71ae7e 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -233,6 +233,7 @@
 					lpc_ctrl: lpc-ctrl@0 {
 						compatible = "aspeed,ast2400-lpc-ctrl";
 						reg = <0x0 0x80>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 
@@ -247,6 +248,13 @@
 						compatible = "aspeed,ast2400-lhc";
 						reg = <0x20 0x24 0x48 0x8>;
 					};
+
+					ibt: ibt@c0  {
+						compatible = "aspeed,ast2400-ibt-bmc";
+						reg = <0xc0 0x18>;
+						interrupts = <8>;
+						status = "disabled";
+					};
 				};
 			};
 
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index 40de3b66c33f..8eac57c33880 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -264,7 +264,7 @@
 
 				#address-cells = <1>;
 				#size-cells = <1>;
-				ranges = <0 0x1e789000 0x1000>;
+				ranges = <0x0 0x1e789000 0x1000>;
 
 				lpc_bmc: lpc-bmc@0 {
 					compatible = "aspeed,ast2500-lpc-bmc";
@@ -274,16 +274,16 @@
 				lpc_host: lpc-host@80 {
 					compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon";
 					reg = <0x80 0x1e0>;
+					reg-io-width = <4>;
 
 					#address-cells = <1>;
 					#size-cells = <1>;
-					ranges = <0 0x80 0x1e0>;
-
-					reg-io-width = <4>;
+					ranges = <0x0 0x80 0x1e0>;
 
 					lpc_ctrl: lpc-ctrl@0 {
 						compatible = "aspeed,ast2500-lpc-ctrl";
 						reg = <0x0 0x80>;
+						clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
 						status = "disabled";
 					};
 
@@ -298,6 +298,13 @@
 						compatible = "aspeed,ast2500-lhc";
 						reg = <0x20 0x24 0x48 0x8>;
 					};
+
+					ibt: ibt@c0 {
+						compatible = "aspeed,ast2500-ibt-bmc";
+						reg = <0xc0 0x18>;
+						interrupts = <8>;
+						status = "disabled";
+					};
 				};
 			};
 
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index e4a420f16800..f4ddd86f2c77 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -92,8 +92,6 @@
 			clock-latency = <300000>; /* From omap-cpufreq driver */
 
 			/* cooling options */
-			cooling-min-level = <0>;
-			cooling-max-level = <2>;
 			#cooling-cells = <2>; /* min followed by max */
 
 			vbb-supply = <&abb_mpu>;
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
index 60d0a732833a..c238407133bf 100644
--- a/arch/arm/boot/dts/emev2-kzm9d.dts
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -38,28 +38,28 @@
 		#size-cells = <0>;
 
 		one {
-			debounce_interval = <50>;
+			debounce-interval = <50>;
 			wakeup-source;
 			label = "DSW2-1";
 			linux,code = <KEY_1>;
 			gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
 		};
 		two {
-			debounce_interval = <50>;
+			debounce-interval = <50>;
 			wakeup-source;
 			label = "DSW2-2";
 			linux,code = <KEY_2>;
 			gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
 		};
 		three {
-			debounce_interval = <50>;
+			debounce-interval = <50>;
 			wakeup-source;
 			label = "DSW2-3";
 			linux,code = <KEY_3>;
 			gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
 		};
 		four {
-			debounce_interval = <50>;
+			debounce-interval = <50>;
 			wakeup-source;
 			label = "DSW2-4";
 			linux,code = <KEY_4>;
diff --git a/arch/arm/boot/dts/exynos-mfc-reserved-memory.dtsi b/arch/arm/boot/dts/exynos-mfc-reserved-memory.dtsi
index 25186ac4188d..1dbf3bbff8d3 100644
--- a/arch/arm/boot/dts/exynos-mfc-reserved-memory.dtsi
+++ b/arch/arm/boot/dts/exynos-mfc-reserved-memory.dtsi
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Samsung's Exynos SoC MFC (Video Codec) reserved memory common definition.
  *
  * Copyright (c) 2016 Samsung Electronics Co., Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 / {
diff --git a/arch/arm/boot/dts/exynos-syscon-restart.dtsi b/arch/arm/boot/dts/exynos-syscon-restart.dtsi
index 09a2040054ed..4b3dd0549a54 100644
--- a/arch/arm/boot/dts/exynos-syscon-restart.dtsi
+++ b/arch/arm/boot/dts/exynos-syscon-restart.dtsi
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Samsung's Exynos SoC syscon reboot/poweroff nodes common definition.
- *
- * 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.
  */
 
 / {
diff --git a/arch/arm/boot/dts/exynos3250-artik5.dtsi b/arch/arm/boot/dts/exynos3250-artik5.dtsi
index 0aa577fe9f95..620b50c19ead 100644
--- a/arch/arm/boot/dts/exynos3250-artik5.dtsi
+++ b/arch/arm/boot/dts/exynos3250-artik5.dtsi
@@ -245,6 +245,7 @@
 				regulator-name = "VLDO23_1.8V";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
 			};
 
 			ldo24_reg: LDO24 {
@@ -316,6 +317,41 @@
 	status = "okay";
 };
 
+&mshc_1 {
+	cap-sd-highspeed;
+	cap-sdio-irq;
+	disable-wp;
+	non-removable;
+	keep-power-in-suspend;
+	fifo-depth = <0x40>;
+	vqmmc-supply = <&ldo11_reg>;
+	/*
+	 * Voltage negotiation is broken for the SDIO periph so we
+	 * can't actually set the voltage here.
+	 * vmmc-supply = <&ldo23_reg>;
+	 */
+	card-detect-delay = <500>;
+	clock-frequency = <100000000>;
+	max-frequency = <100000000>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <0 1>;
+	samsung,dw-mshc-ddr-timing = <1 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd1_cmd &sd1_clk &sd1_bus1 &sd1_bus4 &wlanen>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&pinctrl_1 {
+	wlanen: wlanen {
+		samsung,pins = "gpx2-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV3>;
+		samsung,pin-val = <1>;
+	};
+};
+
 &rtc {
 	clocks = <&cmu CLK_RTC>, <&s2mps14_osc S2MPS11_CLK_AP>;
 	clock-names = "rtc", "rtc_src";
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 6d59cc827649..967cd02401c5 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -52,961 +52,982 @@
 		serial3 = &serial_3;
 	};
 
-	clock_audss: clock-controller@3810000 {
-		compatible = "samsung,exynos4210-audss-clock";
-		reg = <0x03810000 0x0C>;
-		#clock-cells = <1>;
-		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_FOUT_EPLL>,
-			 <&clock CLK_SCLK_AUDIO0>, <&clock CLK_SCLK_AUDIO0>;
-		clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in";
-	};
-
-	i2s0: i2s@3830000 {
-		compatible = "samsung,s5pv210-i2s";
-		reg = <0x03830000 0x100>;
-		clocks = <&clock_audss EXYNOS_I2S_BUS>,
-			 <&clock_audss EXYNOS_DOUT_AUD_BUS>,
-			 <&clock_audss EXYNOS_SCLK_I2S>;
-		clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
-		#clock-cells = <1>;
-		clock-output-names = "i2s_cdclk0";
-		dmas = <&pdma0 12>, <&pdma0 11>, <&pdma0 10>;
-		dma-names = "tx", "rx", "tx-sec";
-		samsung,idma-addr = <0x03000000>;
-		#sound-dai-cells = <1>;
-		status = "disabled";
-	};
+	soc: soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 
-	chipid@10000000 {
-		compatible = "samsung,exynos4210-chipid";
-		reg = <0x10000000 0x100>;
-	};
+		clock_audss: clock-controller@3810000 {
+			compatible = "samsung,exynos4210-audss-clock";
+			reg = <0x03810000 0x0C>;
+			#clock-cells = <1>;
+			clocks = <&clock CLK_FIN_PLL>, <&clock CLK_FOUT_EPLL>,
+				 <&clock CLK_SCLK_AUDIO0>,
+				 <&clock CLK_SCLK_AUDIO0>;
+			clock-names = "pll_ref", "pll_in", "sclk_audio",
+				      "sclk_pcm_in";
+		};
 
-	scu: snoop-control-unit@10500000 {
-		compatible = "arm,cortex-a9-scu";
-		reg = <0x10500000 0x2000>;
-	};
+		i2s0: i2s@3830000 {
+			compatible = "samsung,s5pv210-i2s";
+			reg = <0x03830000 0x100>;
+			clocks = <&clock_audss EXYNOS_I2S_BUS>,
+				 <&clock_audss EXYNOS_DOUT_AUD_BUS>,
+				 <&clock_audss EXYNOS_SCLK_I2S>;
+			clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+			#clock-cells = <1>;
+			clock-output-names = "i2s_cdclk0";
+			dmas = <&pdma0 12>, <&pdma0 11>, <&pdma0 10>;
+			dma-names = "tx", "rx", "tx-sec";
+			samsung,idma-addr = <0x03000000>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+		};
 
-	memory-controller@12570000 {
-		compatible = "samsung,exynos4210-srom";
-		reg = <0x12570000 0x14>;
-	};
+		chipid@10000000 {
+			compatible = "samsung,exynos4210-chipid";
+			reg = <0x10000000 0x100>;
+		};
 
-	mipi_phy: video-phy {
-		compatible = "samsung,s5pv210-mipi-video-phy";
-		#phy-cells = <1>;
-		syscon = <&pmu_system_controller>;
-	};
+		scu: snoop-control-unit@10500000 {
+			compatible = "arm,cortex-a9-scu";
+			reg = <0x10500000 0x2000>;
+		};
 
-	pd_mfc: mfc-power-domain@10023c40 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023C40 0x20>;
-		#power-domain-cells = <0>;
-		label = "MFC";
-	};
+		memory-controller@12570000 {
+			compatible = "samsung,exynos4210-srom";
+			reg = <0x12570000 0x14>;
+		};
 
-	pd_g3d: g3d-power-domain@10023c60 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023C60 0x20>;
-		#power-domain-cells = <0>;
-		label = "G3D";
-	};
+		mipi_phy: video-phy {
+			compatible = "samsung,s5pv210-mipi-video-phy";
+			#phy-cells = <1>;
+			syscon = <&pmu_system_controller>;
+		};
 
-	pd_lcd0: lcd0-power-domain@10023c80 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023C80 0x20>;
-		#power-domain-cells = <0>;
-		label = "LCD0";
-	};
+		pd_mfc: mfc-power-domain@10023c40 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023C40 0x20>;
+			#power-domain-cells = <0>;
+			label = "MFC";
+		};
 
-	pd_tv: tv-power-domain@10023c20 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023C20 0x20>;
-		#power-domain-cells = <0>;
-		power-domains = <&pd_lcd0>;
-		label = "TV";
-	};
+		pd_g3d: g3d-power-domain@10023c60 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023C60 0x20>;
+			#power-domain-cells = <0>;
+			label = "G3D";
+		};
 
-	pd_cam: cam-power-domain@10023c00 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023C00 0x20>;
-		#power-domain-cells = <0>;
-		label = "CAM";
-	};
+		pd_lcd0: lcd0-power-domain@10023c80 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023C80 0x20>;
+			#power-domain-cells = <0>;
+			label = "LCD0";
+		};
 
-	pd_gps: gps-power-domain@10023ce0 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023CE0 0x20>;
-		#power-domain-cells = <0>;
-		label = "GPS";
-	};
+		pd_tv: tv-power-domain@10023c20 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023C20 0x20>;
+			#power-domain-cells = <0>;
+			power-domains = <&pd_lcd0>;
+			label = "TV";
+		};
 
-	pd_gps_alive: gps-alive-power-domain@10023d00 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023D00 0x20>;
-		#power-domain-cells = <0>;
-		label = "GPS alive";
-	};
+		pd_cam: cam-power-domain@10023c00 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023C00 0x20>;
+			#power-domain-cells = <0>;
+			label = "CAM";
+		};
 
-	gic: interrupt-controller@10490000 {
-		compatible = "arm,cortex-a9-gic";
-		#interrupt-cells = <3>;
-		interrupt-controller;
-		reg = <0x10490000 0x10000>, <0x10480000 0x10000>;
-	};
+		pd_gps: gps-power-domain@10023ce0 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023CE0 0x20>;
+			#power-domain-cells = <0>;
+			label = "GPS";
+		};
 
-	combiner: interrupt-controller@10440000 {
-		compatible = "samsung,exynos4210-combiner";
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0x10440000 0x1000>;
-	};
+		pd_gps_alive: gps-alive-power-domain@10023d00 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023D00 0x20>;
+			#power-domain-cells = <0>;
+			label = "GPS alive";
+		};
 
-	pmu {
-		compatible = "arm,cortex-a9-pmu";
-		interrupt-parent = <&combiner>;
-		interrupts = <2 2>, <3 2>;
-	};
+		gic: interrupt-controller@10490000 {
+			compatible = "arm,cortex-a9-gic";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg = <0x10490000 0x10000>, <0x10480000 0x10000>;
+		};
 
-	sys_reg: syscon@10010000 {
-		compatible = "samsung,exynos4-sysreg", "syscon";
-		reg = <0x10010000 0x400>;
-	};
+		combiner: interrupt-controller@10440000 {
+			compatible = "samsung,exynos4210-combiner";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0x10440000 0x1000>;
+		};
 
-	pmu_system_controller: system-controller@10020000 {
-		compatible = "samsung,exynos4210-pmu", "syscon";
-		reg = <0x10020000 0x4000>;
-		interrupt-controller;
-		#interrupt-cells = <3>;
-		interrupt-parent = <&gic>;
-	};
+		pmu: pmu {
+			compatible = "arm,cortex-a9-pmu";
+			interrupt-parent = <&combiner>;
+			interrupts = <2 2>, <3 2>;
+		};
 
-	dsi_0: dsi@11c80000 {
-		compatible = "samsung,exynos4210-mipi-dsi";
-		reg = <0x11C80000 0x10000>;
-		interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
-		power-domains = <&pd_lcd0>;
-		phys = <&mipi_phy 1>;
-		phy-names = "dsim";
-		clocks = <&clock CLK_DSIM0>, <&clock CLK_SCLK_MIPI0>;
-		clock-names = "bus_clk", "sclk_mipi";
-		status = "disabled";
-		#address-cells = <1>;
-		#size-cells = <0>;
-	};
+		sys_reg: syscon@10010000 {
+			compatible = "samsung,exynos4-sysreg", "syscon";
+			reg = <0x10010000 0x400>;
+		};
 
-	camera {
-		compatible = "samsung,fimc", "simple-bus";
-		status = "disabled";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		#clock-cells = <1>;
-		clock-output-names = "cam_a_clkout", "cam_b_clkout";
-		ranges;
+		pmu_system_controller: system-controller@10020000 {
+			compatible = "samsung,exynos4210-pmu", "syscon";
+			reg = <0x10020000 0x4000>;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
+		};
 
-		fimc_0: fimc@11800000 {
-			compatible = "samsung,exynos4210-fimc";
-			reg = <0x11800000 0x1000>;
-			interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_FIMC0>, <&clock CLK_SCLK_FIMC0>;
-			clock-names = "fimc", "sclk_fimc";
-			power-domains = <&pd_cam>;
-			samsung,sysreg = <&sys_reg>;
-			iommus = <&sysmmu_fimc0>;
+		dsi_0: dsi@11c80000 {
+			compatible = "samsung,exynos4210-mipi-dsi";
+			reg = <0x11C80000 0x10000>;
+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_lcd0>;
+			phys = <&mipi_phy 1>;
+			phy-names = "dsim";
+			clocks = <&clock CLK_DSIM0>, <&clock CLK_SCLK_MIPI0>;
+			clock-names = "bus_clk", "sclk_mipi";
 			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
 		};
 
-		fimc_1: fimc@11810000 {
-			compatible = "samsung,exynos4210-fimc";
-			reg = <0x11810000 0x1000>;
-			interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_FIMC1>, <&clock CLK_SCLK_FIMC1>;
-			clock-names = "fimc", "sclk_fimc";
-			power-domains = <&pd_cam>;
-			samsung,sysreg = <&sys_reg>;
-			iommus = <&sysmmu_fimc1>;
+		camera: camera {
+			compatible = "samsung,fimc", "simple-bus";
 			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#clock-cells = <1>;
+			clock-output-names = "cam_a_clkout", "cam_b_clkout";
+			ranges;
+
+			fimc_0: fimc@11800000 {
+				compatible = "samsung,exynos4210-fimc";
+				reg = <0x11800000 0x1000>;
+				interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_FIMC0>,
+					 <&clock CLK_SCLK_FIMC0>;
+				clock-names = "fimc", "sclk_fimc";
+				power-domains = <&pd_cam>;
+				samsung,sysreg = <&sys_reg>;
+				iommus = <&sysmmu_fimc0>;
+				status = "disabled";
+			};
+
+			fimc_1: fimc@11810000 {
+				compatible = "samsung,exynos4210-fimc";
+				reg = <0x11810000 0x1000>;
+				interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_FIMC1>,
+					 <&clock CLK_SCLK_FIMC1>;
+				clock-names = "fimc", "sclk_fimc";
+				power-domains = <&pd_cam>;
+				samsung,sysreg = <&sys_reg>;
+				iommus = <&sysmmu_fimc1>;
+				status = "disabled";
+			};
+
+			fimc_2: fimc@11820000 {
+				compatible = "samsung,exynos4210-fimc";
+				reg = <0x11820000 0x1000>;
+				interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_FIMC2>,
+					 <&clock CLK_SCLK_FIMC2>;
+				clock-names = "fimc", "sclk_fimc";
+				power-domains = <&pd_cam>;
+				samsung,sysreg = <&sys_reg>;
+				iommus = <&sysmmu_fimc2>;
+				status = "disabled";
+			};
+
+			fimc_3: fimc@11830000 {
+				compatible = "samsung,exynos4210-fimc";
+				reg = <0x11830000 0x1000>;
+				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_FIMC3>,
+					 <&clock CLK_SCLK_FIMC3>;
+				clock-names = "fimc", "sclk_fimc";
+				power-domains = <&pd_cam>;
+				samsung,sysreg = <&sys_reg>;
+				iommus = <&sysmmu_fimc3>;
+				status = "disabled";
+			};
+
+			csis_0: csis@11880000 {
+				compatible = "samsung,exynos4210-csis";
+				reg = <0x11880000 0x4000>;
+				interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_CSIS0>,
+					 <&clock CLK_SCLK_CSIS0>;
+				clock-names = "csis", "sclk_csis";
+				bus-width = <4>;
+				power-domains = <&pd_cam>;
+				phys = <&mipi_phy 0>;
+				phy-names = "csis";
+				status = "disabled";
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			csis_1: csis@11890000 {
+				compatible = "samsung,exynos4210-csis";
+				reg = <0x11890000 0x4000>;
+				interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_CSIS1>,
+					 <&clock CLK_SCLK_CSIS1>;
+				clock-names = "csis", "sclk_csis";
+				bus-width = <2>;
+				power-domains = <&pd_cam>;
+				phys = <&mipi_phy 2>;
+				phy-names = "csis";
+				status = "disabled";
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
 		};
 
-		fimc_2: fimc@11820000 {
-			compatible = "samsung,exynos4210-fimc";
-			reg = <0x11820000 0x1000>;
-			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_FIMC2>, <&clock CLK_SCLK_FIMC2>;
-			clock-names = "fimc", "sclk_fimc";
-			power-domains = <&pd_cam>;
-			samsung,sysreg = <&sys_reg>;
-			iommus = <&sysmmu_fimc2>;
+		rtc: rtc@10070000 {
+			compatible = "samsung,s3c6410-rtc";
+			reg = <0x10070000 0x100>;
+			interrupt-parent = <&pmu_system_controller>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_RTC>;
+			clock-names = "rtc";
 			status = "disabled";
 		};
 
-		fimc_3: fimc@11830000 {
-			compatible = "samsung,exynos4210-fimc";
-			reg = <0x11830000 0x1000>;
-			interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_FIMC3>, <&clock CLK_SCLK_FIMC3>;
-			clock-names = "fimc", "sclk_fimc";
-			power-domains = <&pd_cam>;
-			samsung,sysreg = <&sys_reg>;
-			iommus = <&sysmmu_fimc3>;
+		keypad: keypad@100a0000 {
+			compatible = "samsung,s5pv210-keypad";
+			reg = <0x100A0000 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_KEYIF>;
+			clock-names = "keypad";
 			status = "disabled";
 		};
 
-		csis_0: csis@11880000 {
-			compatible = "samsung,exynos4210-csis";
-			reg = <0x11880000 0x4000>;
-			interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_CSIS0>, <&clock CLK_SCLK_CSIS0>;
-			clock-names = "csis", "sclk_csis";
-			bus-width = <4>;
-			power-domains = <&pd_cam>;
-			phys = <&mipi_phy 0>;
-			phy-names = "csis";
+		sdhci_0: sdhci@12510000 {
+			compatible = "samsung,exynos4210-sdhci";
+			reg = <0x12510000 0x100>;
+			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SDMMC0>, <&clock CLK_SCLK_MMC0>;
+			clock-names = "hsmmc", "mmc_busclk.2";
 			status = "disabled";
-			#address-cells = <1>;
-			#size-cells = <0>;
 		};
 
-		csis_1: csis@11890000 {
-			compatible = "samsung,exynos4210-csis";
-			reg = <0x11890000 0x4000>;
-			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_CSIS1>, <&clock CLK_SCLK_CSIS1>;
-			clock-names = "csis", "sclk_csis";
-			bus-width = <2>;
-			power-domains = <&pd_cam>;
-			phys = <&mipi_phy 2>;
-			phy-names = "csis";
+		sdhci_1: sdhci@12520000 {
+			compatible = "samsung,exynos4210-sdhci";
+			reg = <0x12520000 0x100>;
+			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SDMMC1>, <&clock CLK_SCLK_MMC1>;
+			clock-names = "hsmmc", "mmc_busclk.2";
 			status = "disabled";
-			#address-cells = <1>;
-			#size-cells = <0>;
 		};
-	};
-
-	rtc: rtc@10070000 {
-		compatible = "samsung,s3c6410-rtc";
-		reg = <0x10070000 0x100>;
-		interrupt-parent = <&pmu_system_controller>;
-		interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_RTC>;
-		clock-names = "rtc";
-		status = "disabled";
-	};
-
-	keypad: keypad@100a0000 {
-		compatible = "samsung,s5pv210-keypad";
-		reg = <0x100A0000 0x100>;
-		interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_KEYIF>;
-		clock-names = "keypad";
-		status = "disabled";
-	};
-
-	sdhci_0: sdhci@12510000 {
-		compatible = "samsung,exynos4210-sdhci";
-		reg = <0x12510000 0x100>;
-		interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SDMMC0>, <&clock CLK_SCLK_MMC0>;
-		clock-names = "hsmmc", "mmc_busclk.2";
-		status = "disabled";
-	};
 
-	sdhci_1: sdhci@12520000 {
-		compatible = "samsung,exynos4210-sdhci";
-		reg = <0x12520000 0x100>;
-		interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SDMMC1>, <&clock CLK_SCLK_MMC1>;
-		clock-names = "hsmmc", "mmc_busclk.2";
-		status = "disabled";
-	};
-
-	sdhci_2: sdhci@12530000 {
-		compatible = "samsung,exynos4210-sdhci";
-		reg = <0x12530000 0x100>;
-		interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SDMMC2>, <&clock CLK_SCLK_MMC2>;
-		clock-names = "hsmmc", "mmc_busclk.2";
-		status = "disabled";
-	};
-
-	sdhci_3: sdhci@12540000 {
-		compatible = "samsung,exynos4210-sdhci";
-		reg = <0x12540000 0x100>;
-		interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SDMMC3>, <&clock CLK_SCLK_MMC3>;
-		clock-names = "hsmmc", "mmc_busclk.2";
-		status = "disabled";
-	};
+		sdhci_2: sdhci@12530000 {
+			compatible = "samsung,exynos4210-sdhci";
+			reg = <0x12530000 0x100>;
+			interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SDMMC2>, <&clock CLK_SCLK_MMC2>;
+			clock-names = "hsmmc", "mmc_busclk.2";
+			status = "disabled";
+		};
 
-	exynos_usbphy: exynos-usbphy@125b0000 {
-		compatible = "samsung,exynos4210-usb2-phy";
-		reg = <0x125B0000 0x100>;
-		samsung,pmureg-phandle = <&pmu_system_controller>;
-		clocks = <&clock CLK_USB_DEVICE>, <&clock CLK_XUSBXTI>;
-		clock-names = "phy", "ref";
-		#phy-cells = <1>;
-		status = "disabled";
-	};
+		sdhci_3: sdhci@12540000 {
+			compatible = "samsung,exynos4210-sdhci";
+			reg = <0x12540000 0x100>;
+			interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SDMMC3>, <&clock CLK_SCLK_MMC3>;
+			clock-names = "hsmmc", "mmc_busclk.2";
+			status = "disabled";
+		};
 
-	hsotg: hsotg@12480000 {
-		compatible = "samsung,s3c6400-hsotg";
-		reg = <0x12480000 0x20000>;
-		interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_USB_DEVICE>;
-		clock-names = "otg";
-		phys = <&exynos_usbphy 0>;
-		phy-names = "usb2-phy";
-		status = "disabled";
-	};
+		exynos_usbphy: exynos-usbphy@125b0000 {
+			compatible = "samsung,exynos4210-usb2-phy";
+			reg = <0x125B0000 0x100>;
+			samsung,pmureg-phandle = <&pmu_system_controller>;
+			clocks = <&clock CLK_USB_DEVICE>, <&clock CLK_XUSBXTI>;
+			clock-names = "phy", "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
 
-	ehci: ehci@12580000 {
-		compatible = "samsung,exynos4210-ehci";
-		reg = <0x12580000 0x100>;
-		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_USB_HOST>;
-		clock-names = "usbhost";
-		status = "disabled";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		port@0 {
-			reg = <0>;
-			phys = <&exynos_usbphy 1>;
+		hsotg: hsotg@12480000 {
+			compatible = "samsung,s3c6400-hsotg";
+			reg = <0x12480000 0x20000>;
+			interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_USB_DEVICE>;
+			clock-names = "otg";
+			phys = <&exynos_usbphy 0>;
+			phy-names = "usb2-phy";
 			status = "disabled";
 		};
-		port@1 {
-			reg = <1>;
-			phys = <&exynos_usbphy 2>;
+
+		ehci: ehci@12580000 {
+			compatible = "samsung,exynos4210-ehci";
+			reg = <0x12580000 0x100>;
+			interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_USB_HOST>;
+			clock-names = "usbhost";
 			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				phys = <&exynos_usbphy 1>;
+				status = "disabled";
+			};
+			port@1 {
+				reg = <1>;
+				phys = <&exynos_usbphy 2>;
+				status = "disabled";
+			};
+			port@2 {
+				reg = <2>;
+				phys = <&exynos_usbphy 3>;
+				status = "disabled";
+			};
 		};
-		port@2 {
-			reg = <2>;
-			phys = <&exynos_usbphy 3>;
+
+		ohci: ohci@12590000 {
+			compatible = "samsung,exynos4210-ohci";
+			reg = <0x12590000 0x100>;
+			interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_USB_HOST>;
+			clock-names = "usbhost";
 			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				phys = <&exynos_usbphy 1>;
+				status = "disabled";
+			};
 		};
-	};
 
-	ohci: ohci@12590000 {
-		compatible = "samsung,exynos4210-ohci";
-		reg = <0x12590000 0x100>;
-		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_USB_HOST>;
-		clock-names = "usbhost";
-		status = "disabled";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		port@0 {
-			reg = <0>;
-			phys = <&exynos_usbphy 1>;
+		i2s1: i2s@13960000 {
+			compatible = "samsung,s3c6410-i2s";
+			reg = <0x13960000 0x100>;
+			clocks = <&clock CLK_I2S1>;
+			clock-names = "iis";
+			#clock-cells = <1>;
+			clock-output-names = "i2s_cdclk1";
+			dmas = <&pdma1 12>, <&pdma1 11>;
+			dma-names = "tx", "rx";
+			#sound-dai-cells = <1>;
 			status = "disabled";
 		};
-	};
 
-	i2s1: i2s@13960000 {
-		compatible = "samsung,s3c6410-i2s";
-		reg = <0x13960000 0x100>;
-		clocks = <&clock CLK_I2S1>;
-		clock-names = "iis";
-		#clock-cells = <1>;
-		clock-output-names = "i2s_cdclk1";
-		dmas = <&pdma1 12>, <&pdma1 11>;
-		dma-names = "tx", "rx";
-		#sound-dai-cells = <1>;
-		status = "disabled";
-	};
+		i2s2: i2s@13970000 {
+			compatible = "samsung,s3c6410-i2s";
+			reg = <0x13970000 0x100>;
+			clocks = <&clock CLK_I2S2>;
+			clock-names = "iis";
+			#clock-cells = <1>;
+			clock-output-names = "i2s_cdclk2";
+			dmas = <&pdma0 14>, <&pdma0 13>;
+			dma-names = "tx", "rx";
+			#sound-dai-cells = <1>;
+			status = "disabled";
+		};
 
-	i2s2: i2s@13970000 {
-		compatible = "samsung,s3c6410-i2s";
-		reg = <0x13970000 0x100>;
-		clocks = <&clock CLK_I2S2>;
-		clock-names = "iis";
-		#clock-cells = <1>;
-		clock-output-names = "i2s_cdclk2";
-		dmas = <&pdma0 14>, <&pdma0 13>;
-		dma-names = "tx", "rx";
-		#sound-dai-cells = <1>;
-		status = "disabled";
-	};
+		mfc: codec@13400000 {
+			compatible = "samsung,mfc-v5";
+			reg = <0x13400000 0x10000>;
+			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&pd_mfc>;
+			clocks = <&clock CLK_MFC>, <&clock CLK_SCLK_MFC>;
+			clock-names = "mfc", "sclk_mfc";
+			iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>;
+			iommu-names = "left", "right";
+		};
 
-	mfc: codec@13400000 {
-		compatible = "samsung,mfc-v5";
-		reg = <0x13400000 0x10000>;
-		interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
-		power-domains = <&pd_mfc>;
-		clocks = <&clock CLK_MFC>, <&clock CLK_SCLK_MFC>;
-		clock-names = "mfc", "sclk_mfc";
-		iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>;
-		iommu-names = "left", "right";
-	};
+		serial_0: serial@13800000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x13800000 0x100>;
+			interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
+			clock-names = "uart", "clk_uart_baud0";
+			dmas = <&pdma0 15>, <&pdma0 16>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
 
-	serial_0: serial@13800000 {
-		compatible = "samsung,exynos4210-uart";
-		reg = <0x13800000 0x100>;
-		interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
-		clock-names = "uart", "clk_uart_baud0";
-		dmas = <&pdma0 15>, <&pdma0 16>;
-		dma-names = "rx", "tx";
-		status = "disabled";
-	};
+		serial_1: serial@13810000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x13810000 0x100>;
+			interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
+			clock-names = "uart", "clk_uart_baud0";
+			dmas = <&pdma1 15>, <&pdma1 16>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
 
-	serial_1: serial@13810000 {
-		compatible = "samsung,exynos4210-uart";
-		reg = <0x13810000 0x100>;
-		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
-		clock-names = "uart", "clk_uart_baud0";
-		dmas = <&pdma1 15>, <&pdma1 16>;
-		dma-names = "rx", "tx";
-		status = "disabled";
-	};
+		serial_2: serial@13820000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x13820000 0x100>;
+			interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
+			clock-names = "uart", "clk_uart_baud0";
+			dmas = <&pdma0 17>, <&pdma0 18>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
 
-	serial_2: serial@13820000 {
-		compatible = "samsung,exynos4210-uart";
-		reg = <0x13820000 0x100>;
-		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
-		clock-names = "uart", "clk_uart_baud0";
-		dmas = <&pdma0 17>, <&pdma0 18>;
-		dma-names = "rx", "tx";
-		status = "disabled";
-	};
+		serial_3: serial@13830000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x13830000 0x100>;
+			interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
+			clock-names = "uart", "clk_uart_baud0";
+			dmas = <&pdma1 17>, <&pdma1 18>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
 
-	serial_3: serial@13830000 {
-		compatible = "samsung,exynos4210-uart";
-		reg = <0x13830000 0x100>;
-		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
-		clock-names = "uart", "clk_uart_baud0";
-		dmas = <&pdma1 17>, <&pdma1 18>;
-		dma-names = "rx", "tx";
-		status = "disabled";
-	};
+		i2c_0: i2c@13860000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x13860000 0x100>;
+			interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C0>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_bus>;
+			status = "disabled";
+		};
 
-	i2c_0: i2c@13860000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x13860000 0x100>;
-		interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C0>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c0_bus>;
-		status = "disabled";
-	};
+		i2c_1: i2c@13870000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x13870000 0x100>;
+			interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C1>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_bus>;
+			status = "disabled";
+		};
 
-	i2c_1: i2c@13870000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x13870000 0x100>;
-		interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C1>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c1_bus>;
-		status = "disabled";
-	};
+		i2c_2: i2c@13880000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x13880000 0x100>;
+			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C2>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c2_bus>;
+			status = "disabled";
+		};
 
-	i2c_2: i2c@13880000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x13880000 0x100>;
-		interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C2>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c2_bus>;
-		status = "disabled";
-	};
+		i2c_3: i2c@13890000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x13890000 0x100>;
+			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C3>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c3_bus>;
+			status = "disabled";
+		};
 
-	i2c_3: i2c@13890000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x13890000 0x100>;
-		interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C3>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c3_bus>;
-		status = "disabled";
-	};
+		i2c_4: i2c@138a0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x138A0000 0x100>;
+			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C4>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c4_bus>;
+			status = "disabled";
+		};
 
-	i2c_4: i2c@138a0000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x138A0000 0x100>;
-		interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C4>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c4_bus>;
-		status = "disabled";
-	};
+		i2c_5: i2c@138b0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x138B0000 0x100>;
+			interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C5>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c5_bus>;
+			status = "disabled";
+		};
 
-	i2c_5: i2c@138b0000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x138B0000 0x100>;
-		interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C5>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c5_bus>;
-		status = "disabled";
-	};
+		i2c_6: i2c@138c0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x138C0000 0x100>;
+			interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C6>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c6_bus>;
+			status = "disabled";
+		};
 
-	i2c_6: i2c@138c0000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x138C0000 0x100>;
-		interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C6>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c6_bus>;
-		status = "disabled";
-	};
+		i2c_7: i2c@138d0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-i2c";
+			reg = <0x138D0000 0x100>;
+			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C7>;
+			clock-names = "i2c";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c7_bus>;
+			status = "disabled";
+		};
 
-	i2c_7: i2c@138d0000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-i2c";
-		reg = <0x138D0000 0x100>;
-		interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C7>;
-		clock-names = "i2c";
-		pinctrl-names = "default";
-		pinctrl-0 = <&i2c7_bus>;
-		status = "disabled";
-	};
+		i2c_8: i2c@138e0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "samsung,s3c2440-hdmiphy-i2c";
+			reg = <0x138E0000 0x100>;
+			interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_I2C_HDMI>;
+			clock-names = "i2c";
+			status = "disabled";
 
-	i2c_8: i2c@138e0000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "samsung,s3c2440-hdmiphy-i2c";
-		reg = <0x138E0000 0x100>;
-		interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_I2C_HDMI>;
-		clock-names = "i2c";
-		status = "disabled";
-
-		hdmi_i2c_phy: hdmiphy@38 {
-			compatible = "exynos4210-hdmiphy";
-			reg = <0x38>;
+			hdmi_i2c_phy: hdmiphy@38 {
+				compatible = "exynos4210-hdmiphy";
+				reg = <0x38>;
+			};
 		};
-	};
 
-	spi_0: spi@13920000 {
-		compatible = "samsung,exynos4210-spi";
-		reg = <0x13920000 0x100>;
-		interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
-		dmas = <&pdma0 7>, <&pdma0 6>;
-		dma-names = "tx", "rx";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&clock CLK_SPI0>, <&clock CLK_SCLK_SPI0>;
-		clock-names = "spi", "spi_busclk0";
-		pinctrl-names = "default";
-		pinctrl-0 = <&spi0_bus>;
-		status = "disabled";
-	};
-
-	spi_1: spi@13930000 {
-		compatible = "samsung,exynos4210-spi";
-		reg = <0x13930000 0x100>;
-		interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
-		dmas = <&pdma1 7>, <&pdma1 6>;
-		dma-names = "tx", "rx";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&clock CLK_SPI1>, <&clock CLK_SCLK_SPI1>;
-		clock-names = "spi", "spi_busclk0";
-		pinctrl-names = "default";
-		pinctrl-0 = <&spi1_bus>;
-		status = "disabled";
-	};
+		spi_0: spi@13920000 {
+			compatible = "samsung,exynos4210-spi";
+			reg = <0x13920000 0x100>;
+			interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&pdma0 7>, <&pdma0 6>;
+			dma-names = "tx", "rx";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&clock CLK_SPI0>, <&clock CLK_SCLK_SPI0>;
+			clock-names = "spi", "spi_busclk0";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi0_bus>;
+			status = "disabled";
+		};
 
-	spi_2: spi@13940000 {
-		compatible = "samsung,exynos4210-spi";
-		reg = <0x13940000 0x100>;
-		interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
-		dmas = <&pdma0 9>, <&pdma0 8>;
-		dma-names = "tx", "rx";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&clock CLK_SPI2>, <&clock CLK_SCLK_SPI2>;
-		clock-names = "spi", "spi_busclk0";
-		pinctrl-names = "default";
-		pinctrl-0 = <&spi2_bus>;
-		status = "disabled";
-	};
+		spi_1: spi@13930000 {
+			compatible = "samsung,exynos4210-spi";
+			reg = <0x13930000 0x100>;
+			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&pdma1 7>, <&pdma1 6>;
+			dma-names = "tx", "rx";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&clock CLK_SPI1>, <&clock CLK_SCLK_SPI1>;
+			clock-names = "spi", "spi_busclk0";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_bus>;
+			status = "disabled";
+		};
 
-	pwm: pwm@139d0000 {
-		compatible = "samsung,exynos4210-pwm";
-		reg = <0x139D0000 0x1000>;
-		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_PWM>;
-		clock-names = "timers";
-		#pwm-cells = <3>;
-		status = "disabled";
-	};
+		spi_2: spi@13940000 {
+			compatible = "samsung,exynos4210-spi";
+			reg = <0x13940000 0x100>;
+			interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&pdma0 9>, <&pdma0 8>;
+			dma-names = "tx", "rx";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&clock CLK_SPI2>, <&clock CLK_SCLK_SPI2>;
+			clock-names = "spi", "spi_busclk0";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi2_bus>;
+			status = "disabled";
+		};
 
-	amba {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		compatible = "simple-bus";
-		interrupt-parent = <&gic>;
-		ranges;
+		pwm: pwm@139d0000 {
+			compatible = "samsung,exynos4210-pwm";
+			reg = <0x139D0000 0x1000>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_PWM>;
+			clock-names = "timers";
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
 
-		pdma0: pdma@12680000 {
-			compatible = "arm,pl330", "arm,primecell";
-			reg = <0x12680000 0x1000>;
-			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_PDMA0>;
-			clock-names = "apb_pclk";
-			#dma-cells = <1>;
-			#dma-channels = <8>;
-			#dma-requests = <32>;
-		};
-
-		pdma1: pdma@12690000 {
-			compatible = "arm,pl330", "arm,primecell";
-			reg = <0x12690000 0x1000>;
-			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_PDMA1>;
-			clock-names = "apb_pclk";
-			#dma-cells = <1>;
-			#dma-channels = <8>;
-			#dma-requests = <32>;
-		};
-
-		mdma1: mdma@12850000 {
-			compatible = "arm,pl330", "arm,primecell";
-			reg = <0x12850000 0x1000>;
-			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clock CLK_MDMA>;
-			clock-names = "apb_pclk";
-			#dma-cells = <1>;
-			#dma-channels = <8>;
-			#dma-requests = <1>;
+		amba {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			interrupt-parent = <&gic>;
+			ranges;
+
+			pdma0: pdma@12680000 {
+				compatible = "arm,pl330", "arm,primecell";
+				reg = <0x12680000 0x1000>;
+				interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_PDMA0>;
+				clock-names = "apb_pclk";
+				#dma-cells = <1>;
+				#dma-channels = <8>;
+				#dma-requests = <32>;
+			};
+
+			pdma1: pdma@12690000 {
+				compatible = "arm,pl330", "arm,primecell";
+				reg = <0x12690000 0x1000>;
+				interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_PDMA1>;
+				clock-names = "apb_pclk";
+				#dma-cells = <1>;
+				#dma-channels = <8>;
+				#dma-requests = <32>;
+			};
+
+			mdma1: mdma@12850000 {
+				compatible = "arm,pl330", "arm,primecell";
+				reg = <0x12850000 0x1000>;
+				interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clock CLK_MDMA>;
+				clock-names = "apb_pclk";
+				#dma-cells = <1>;
+				#dma-channels = <8>;
+				#dma-requests = <1>;
+			};
 		};
-	};
 
-	fimd: fimd@11c00000 {
-		compatible = "samsung,exynos4210-fimd";
-		interrupt-parent = <&combiner>;
-		reg = <0x11c00000 0x20000>;
-		interrupt-names = "fifo", "vsync", "lcd_sys";
-		interrupts = <11 0>, <11 1>, <11 2>;
-		clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>;
-		clock-names = "sclk_fimd", "fimd";
-		power-domains = <&pd_lcd0>;
-		iommus = <&sysmmu_fimd0>;
-		samsung,sysreg = <&sys_reg>;
-		status = "disabled";
-	};
+		fimd: fimd@11c00000 {
+			compatible = "samsung,exynos4210-fimd";
+			interrupt-parent = <&combiner>;
+			reg = <0x11c00000 0x20000>;
+			interrupt-names = "fifo", "vsync", "lcd_sys";
+			interrupts = <11 0>, <11 1>, <11 2>;
+			clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>;
+			clock-names = "sclk_fimd", "fimd";
+			power-domains = <&pd_lcd0>;
+			iommus = <&sysmmu_fimd0>;
+			samsung,sysreg = <&sys_reg>;
+			status = "disabled";
+		};
 
-	tmu: tmu@100c0000 {
-		#include "exynos4412-tmu-sensor-conf.dtsi"
-	};
+		tmu: tmu@100c0000 {
+			interrupt-parent = <&combiner>;
+			reg = <0x100C0000 0x100>;
+			interrupts = <2 4>;
+			status = "disabled";
+			#include "exynos4412-tmu-sensor-conf.dtsi"
+		};
 
-	jpeg_codec: jpeg-codec@11840000 {
-		compatible = "samsung,exynos4210-jpeg";
-		reg = <0x11840000 0x1000>;
-		interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_JPEG>;
-		clock-names = "jpeg";
-		power-domains = <&pd_cam>;
-		iommus = <&sysmmu_jpeg>;
-	};
+		jpeg_codec: jpeg-codec@11840000 {
+			compatible = "samsung,exynos4210-jpeg";
+			reg = <0x11840000 0x1000>;
+			interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_JPEG>;
+			clock-names = "jpeg";
+			power-domains = <&pd_cam>;
+			iommus = <&sysmmu_jpeg>;
+		};
 
-	rotator: rotator@12810000 {
-		compatible = "samsung,exynos4210-rotator";
-		reg = <0x12810000 0x64>;
-		interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_ROTATOR>;
-		clock-names = "rotator";
-		iommus = <&sysmmu_rotator>;
-	};
+		rotator: rotator@12810000 {
+			compatible = "samsung,exynos4210-rotator";
+			reg = <0x12810000 0x64>;
+			interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_ROTATOR>;
+			clock-names = "rotator";
+			iommus = <&sysmmu_rotator>;
+		};
 
-	hdmi: hdmi@12d00000 {
-		compatible = "samsung,exynos4210-hdmi";
-		reg = <0x12D00000 0x70000>;
-		interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
-		clock-names = "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy",
-			"mout_hdmi";
-		clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
-			<&clock CLK_SCLK_PIXEL>, <&clock CLK_SCLK_HDMIPHY>,
-			<&clock CLK_MOUT_HDMI>;
-		phy = <&hdmi_i2c_phy>;
-		power-domains = <&pd_tv>;
-		samsung,syscon-phandle = <&pmu_system_controller>;
-		#sound-dai-cells = <0>;
-		status = "disabled";
-	};
+		hdmi: hdmi@12d00000 {
+			compatible = "samsung,exynos4210-hdmi";
+			reg = <0x12D00000 0x70000>;
+			interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+			clock-names = "hdmi", "sclk_hdmi", "sclk_pixel",
+				      "sclk_hdmiphy", "mout_hdmi";
+			clocks = <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>,
+				 <&clock CLK_SCLK_PIXEL>,
+				 <&clock CLK_SCLK_HDMIPHY>,
+				 <&clock CLK_MOUT_HDMI>;
+			phy = <&hdmi_i2c_phy>;
+			power-domains = <&pd_tv>;
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			#sound-dai-cells = <0>;
+			status = "disabled";
+		};
 
-	hdmicec: cec@100b0000 {
-		compatible = "samsung,s5p-cec";
-		reg = <0x100B0000 0x200>;
-		interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_HDMI_CEC>;
-		clock-names = "hdmicec";
-		samsung,syscon-phandle = <&pmu_system_controller>;
-		hdmi-phandle = <&hdmi>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&hdmi_cec>;
-		status = "disabled";
-	};
+		hdmicec: cec@100b0000 {
+			compatible = "samsung,s5p-cec";
+			reg = <0x100B0000 0x200>;
+			interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_HDMI_CEC>;
+			clock-names = "hdmicec";
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			hdmi-phandle = <&hdmi>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hdmi_cec>;
+			status = "disabled";
+		};
 
-	mixer: mixer@12c10000 {
-		compatible = "samsung,exynos4210-mixer";
-		interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
-		reg = <0x12C10000 0x2100>, <0x12c00000 0x300>;
-		power-domains = <&pd_tv>;
-		iommus = <&sysmmu_tv>;
-		status = "disabled";
-	};
+		mixer: mixer@12c10000 {
+			compatible = "samsung,exynos4210-mixer";
+			interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0x12C10000 0x2100>, <0x12c00000 0x300>;
+			power-domains = <&pd_tv>;
+			iommus = <&sysmmu_tv>;
+			status = "disabled";
+		};
 
-	ppmu_dmc0: ppmu_dmc0@106a0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x106a0000 0x2000>;
-		clocks = <&clock CLK_PPMUDMC0>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_dmc0: ppmu_dmc0@106a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106a0000 0x2000>;
+			clocks = <&clock CLK_PPMUDMC0>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_dmc1: ppmu_dmc1@106b0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x106b0000 0x2000>;
-		clocks = <&clock CLK_PPMUDMC1>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_dmc1: ppmu_dmc1@106b0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106b0000 0x2000>;
+			clocks = <&clock CLK_PPMUDMC1>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_cpu: ppmu_cpu@106c0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x106c0000 0x2000>;
-		clocks = <&clock CLK_PPMUCPU>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_cpu: ppmu_cpu@106c0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106c0000 0x2000>;
+			clocks = <&clock CLK_PPMUCPU>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_acp: ppmu_acp@10ae0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x106e0000 0x2000>;
-		status = "disabled";
-	};
+		ppmu_acp: ppmu_acp@10ae0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106e0000 0x2000>;
+			status = "disabled";
+		};
 
-	ppmu_rightbus: ppmu_rightbus@112a0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x112a0000 0x2000>;
-		clocks = <&clock CLK_PPMURIGHT>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_rightbus: ppmu_rightbus@112a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x112a0000 0x2000>;
+			clocks = <&clock CLK_PPMURIGHT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_leftbus: ppmu_leftbus0@116a0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x116a0000 0x2000>;
-		clocks = <&clock CLK_PPMULEFT>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_leftbus: ppmu_leftbus0@116a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x116a0000 0x2000>;
+			clocks = <&clock CLK_PPMULEFT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_camif: ppmu_camif@11ac0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x11ac0000 0x2000>;
-		clocks = <&clock CLK_PPMUCAMIF>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_camif: ppmu_camif@11ac0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11ac0000 0x2000>;
+			clocks = <&clock CLK_PPMUCAMIF>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_lcd0: ppmu_lcd0@11e40000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x11e40000 0x2000>;
-		clocks = <&clock CLK_PPMULCD0>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_lcd0: ppmu_lcd0@11e40000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11e40000 0x2000>;
+			clocks = <&clock CLK_PPMULCD0>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_fsys: ppmu_g3d@12630000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x12630000 0x2000>;
-		status = "disabled";
-	};
+		ppmu_fsys: ppmu_g3d@12630000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12630000 0x2000>;
+			status = "disabled";
+		};
 
-	ppmu_image: ppmu_image@12aa0000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x12aa0000 0x2000>;
-		clocks = <&clock CLK_PPMUIMAGE>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_image: ppmu_image@12aa0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12aa0000 0x2000>;
+			clocks = <&clock CLK_PPMUIMAGE>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_tv: ppmu_tv@12e40000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x12e40000 0x2000>;
-		clocks = <&clock CLK_PPMUTV>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_tv: ppmu_tv@12e40000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12e40000 0x2000>;
+			clocks = <&clock CLK_PPMUTV>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_g3d: ppmu_g3d@13220000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x13220000 0x2000>;
-		clocks = <&clock CLK_PPMUG3D>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_g3d: ppmu_g3d@13220000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13220000 0x2000>;
+			clocks = <&clock CLK_PPMUG3D>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_mfc_left: ppmu_mfc_left@13660000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x13660000 0x2000>;
-		clocks = <&clock CLK_PPMUMFC_L>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_mfc_left: ppmu_mfc_left@13660000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13660000 0x2000>;
+			clocks = <&clock CLK_PPMUMFC_L>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	ppmu_mfc_right: ppmu_mfc_right@13670000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x13670000 0x2000>;
-		clocks = <&clock CLK_PPMUMFC_R>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		ppmu_mfc_right: ppmu_mfc_right@13670000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13670000 0x2000>;
+			clocks = <&clock CLK_PPMUMFC_R>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 
-	sysmmu_mfc_l: sysmmu@13620000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x13620000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <5 5>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_MFCL>, <&clock CLK_MFC>;
-		power-domains = <&pd_mfc>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_mfc_l: sysmmu@13620000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x13620000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <5 5>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_MFCL>, <&clock CLK_MFC>;
+			power-domains = <&pd_mfc>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_mfc_r: sysmmu@13630000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x13630000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <5 6>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>;
-		power-domains = <&pd_mfc>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_mfc_r: sysmmu@13630000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x13630000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <5 6>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>;
+			power-domains = <&pd_mfc>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_tv: sysmmu@12e20000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x12E20000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <5 4>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_TV>, <&clock CLK_MIXER>;
-		power-domains = <&pd_tv>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_tv: sysmmu@12e20000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x12E20000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <5 4>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_TV>, <&clock CLK_MIXER>;
+			power-domains = <&pd_tv>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_fimc0: sysmmu@11a20000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x11A20000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 2>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_FIMC0>, <&clock CLK_FIMC0>;
-		power-domains = <&pd_cam>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_fimc0: sysmmu@11a20000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x11A20000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 2>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_FIMC0>, <&clock CLK_FIMC0>;
+			power-domains = <&pd_cam>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_fimc1: sysmmu@11a30000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x11A30000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 3>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_FIMC1>, <&clock CLK_FIMC1>;
-		power-domains = <&pd_cam>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_fimc1: sysmmu@11a30000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x11A30000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 3>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_FIMC1>, <&clock CLK_FIMC1>;
+			power-domains = <&pd_cam>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_fimc2: sysmmu@11a40000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x11A40000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 4>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_FIMC2>, <&clock CLK_FIMC2>;
-		power-domains = <&pd_cam>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_fimc2: sysmmu@11a40000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x11A40000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 4>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_FIMC2>, <&clock CLK_FIMC2>;
+			power-domains = <&pd_cam>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_fimc3: sysmmu@11a50000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x11A50000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 5>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_FIMC3>, <&clock CLK_FIMC3>;
-		power-domains = <&pd_cam>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_fimc3: sysmmu@11a50000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x11A50000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 5>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_FIMC3>, <&clock CLK_FIMC3>;
+			power-domains = <&pd_cam>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_jpeg: sysmmu@11a60000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x11A60000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 6>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_JPEG>, <&clock CLK_JPEG>;
-		power-domains = <&pd_cam>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_jpeg: sysmmu@11a60000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x11A60000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 6>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_JPEG>, <&clock CLK_JPEG>;
+			power-domains = <&pd_cam>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_rotator: sysmmu@12a30000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x12A30000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <5 0>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_ROTATOR>, <&clock CLK_ROTATOR>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_rotator: sysmmu@12a30000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x12A30000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <5 0>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_ROTATOR>,
+				 <&clock CLK_ROTATOR>;
+			#iommu-cells = <0>;
+		};
 
-	sysmmu_fimd0: sysmmu@11e20000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x11E20000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <5 2>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_FIMD0>, <&clock CLK_FIMD0>;
-		power-domains = <&pd_lcd0>;
-		#iommu-cells = <0>;
-	};
+		sysmmu_fimd0: sysmmu@11e20000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x11E20000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <5 2>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_FIMD0>, <&clock CLK_FIMD0>;
+			power-domains = <&pd_lcd0>;
+			#iommu-cells = <0>;
+		};
 
-	sss: sss@10830000 {
-		compatible = "samsung,exynos4210-secss";
-		reg = <0x10830000 0x300>;
-		interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SSS>;
-		clock-names = "secss";
-	};
+		sss: sss@10830000 {
+			compatible = "samsung,exynos4210-secss";
+			reg = <0x10830000 0x300>;
+			interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SSS>;
+			clock-names = "secss";
+		};
 
-	prng: rng@10830400 {
-		compatible = "samsung,exynos4-rng";
-		reg = <0x10830400 0x200>;
-		clocks = <&clock CLK_SSS>;
-		clock-names = "secss";
+		prng: rng@10830400 {
+			compatible = "samsung,exynos4-rng";
+			reg = <0x10830400 0x200>;
+			clocks = <&clock CLK_SSS>;
+			clock-names = "secss";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
index dbe6c052d8c1..520c5934a8d4 100644
--- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
@@ -13,853 +13,851 @@
 
 #include <dt-bindings/pinctrl/samsung.h>
 
-/ {
-	pinctrl@11400000 {
-		gpa0: gpa0 {
-			gpio-controller;
-			#gpio-cells = <2>;
+&pinctrl_0 {
+	gpa0: gpa0 {
+		gpio-controller;
+		#gpio-cells = <2>;
 
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpa1: gpa1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb: gpb {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpc0: gpc0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpc1: gpc1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd0: gpd0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd1: gpd1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpe0: gpe0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpe1: gpe1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpe2: gpe2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpe3: gpe3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpe4: gpe4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf0: gpf0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf1: gpf1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf2: gpf2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf3: gpf3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	uart0_data: uart0-data {
+		samsung,pins = "gpa0-0", "gpa0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart0_fctl: uart0-fctl {
+		samsung,pins = "gpa0-2", "gpa0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart1_data: uart1-data {
+		samsung,pins = "gpa0-4", "gpa0-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart1_fctl: uart1-fctl {
+		samsung,pins = "gpa0-6", "gpa0-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c2_bus: i2c2-bus {
+		samsung,pins = "gpa0-6", "gpa0-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart2_data: uart2-data {
+		samsung,pins = "gpa1-0", "gpa1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart2_fctl: uart2-fctl {
+		samsung,pins = "gpa1-2", "gpa1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart_audio_a: uart-audio-a {
+		samsung,pins = "gpa1-0", "gpa1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c3_bus: i2c3-bus {
+		samsung,pins = "gpa1-2", "gpa1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart3_data: uart3-data {
+		samsung,pins = "gpa1-4", "gpa1-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart_audio_b: uart-audio-b {
+		samsung,pins = "gpa1-4", "gpa1-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi0_bus: spi0-bus {
+		samsung,pins = "gpb-0", "gpb-2", "gpb-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c4_bus: i2c4-bus {
+		samsung,pins = "gpb-2", "gpb-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi1_bus: spi1-bus {
+		samsung,pins = "gpb-4", "gpb-6", "gpb-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c5_bus: i2c5-bus {
+		samsung,pins = "gpb-6", "gpb-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2s1_bus: i2s1-bus {
+		samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+				"gpc0-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pcm1_bus: pcm1-bus {
+		samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+				"gpc0-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	ac97_bus: ac97-bus {
+		samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+				"gpc0-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2s2_bus: i2s2-bus {
+		samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
+				"gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pcm2_bus: pcm2-bus {
+		samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
+				"gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spdif_bus: spdif-bus {
+		samsung,pins = "gpc1-0", "gpc1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c6_bus: i2c6-bus {
+		samsung,pins = "gpc1-3", "gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi2_bus: spi2-bus {
+		samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c7_bus: i2c7-bus {
+		samsung,pins = "gpd0-2", "gpd0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c0_bus: i2c0-bus {
+		samsung,pins = "gpd1-0", "gpd1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c1_bus: i2c1-bus {
+		samsung,pins = "gpd1-2", "gpd1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm0_out: pwm0-out {
+		samsung,pins = "gpd0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm1_out: pwm1-out {
+		samsung,pins = "gpd0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm2_out: pwm2-out {
+		samsung,pins = "gpd0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm3_out: pwm3-out {
+		samsung,pins = "gpd0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_ctrl: lcd-ctrl {
+		samsung,pins = "gpd0-0", "gpd0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_sync: lcd-sync {
+		samsung,pins = "gpf0-0", "gpf0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_en: lcd-en {
+		samsung,pins = "gpe3-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_clk: lcd-clk {
+		samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_data16: lcd-data-width16 {
+		samsung,pins = "gpf0-7", "gpf1-0", "gpf1-1", "gpf1-2",
+				"gpf1-3", "gpf1-6", "gpf1-7", "gpf2-0",
+				"gpf2-1", "gpf2-2", "gpf2-3", "gpf2-7",
+				"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_data18: lcd-data-width18 {
+		samsung,pins = "gpf0-6", "gpf0-7", "gpf1-0", "gpf1-1",
+				"gpf1-2", "gpf1-3", "gpf1-6", "gpf1-7",
+				"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
+				"gpf2-6", "gpf2-7", "gpf3-0", "gpf3-1",
+				"gpf3-2", "gpf3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_data24: lcd-data-width24 {
+		samsung,pins = "gpf0-4", "gpf0-5", "gpf0-6", "gpf0-7",
+				"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3",
+				"gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7",
+				"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
+				"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
+				"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+};
+
+&pinctrl_1 {
+	gpj0: gpj0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpj1: gpj1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk0: gpk0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk1: gpk1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk2: gpk2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk3: gpk3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpl0: gpl0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpl1: gpl1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpl2: gpl2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpy0: gpy0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy1: gpy1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy2: gpy2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
 
-		gpa1: gpa1 {
-			gpio-controller;
-			#gpio-cells = <2>;
+	gpy3: gpy3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy4: gpy4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy5: gpy5 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy6: gpy6 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpx0: gpx0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <2>;
+	};
+
+	gpx1: gpx1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <2>;
+	};
+
+	gpx2: gpx2 {
+		gpio-controller;
+		#gpio-cells = <2>;
 
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpx3: gpx3 {
+		gpio-controller;
+		#gpio-cells = <2>;
 
-		gpb: gpb {
-			gpio-controller;
-			#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
 
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
+	sd0_clk: sd0-clk {
+		samsung,pins = "gpk0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
 
-		gpc0: gpc0 {
-			gpio-controller;
-			#gpio-cells = <2>;
+	sd0_cmd: sd0-cmd {
+		samsung,pins = "gpk0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_cd: sd0-cd {
+		samsung,pins = "gpk0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_bus1: sd0-bus-width1 {
+		samsung,pins = "gpk0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_bus4: sd0-bus-width4 {
+		samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_bus8: sd0-bus-width8 {
+		samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_clk: sd4-clk {
+		samsung,pins = "gpk0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_cmd: sd4-cmd {
+		samsung,pins = "gpk0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_cd: sd4-cd {
+		samsung,pins = "gpk0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_bus1: sd4-bus-width1 {
+		samsung,pins = "gpk0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_bus4: sd4-bus-width4 {
+		samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_bus8: sd4-bus-width8 {
+		samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_clk: sd1-clk {
+		samsung,pins = "gpk1-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_cmd: sd1-cmd {
+		samsung,pins = "gpk1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_cd: sd1-cd {
+		samsung,pins = "gpk1-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_bus1: sd1-bus-width1 {
+		samsung,pins = "gpk1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_bus4: sd1-bus-width4 {
+		samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_clk: sd2-clk {
+		samsung,pins = "gpk2-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_cmd: sd2-cmd {
+		samsung,pins = "gpk2-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_cd: sd2-cd {
+		samsung,pins = "gpk2-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_bus1: sd2-bus-width1 {
+		samsung,pins = "gpk2-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_bus4: sd2-bus-width4 {
+		samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_bus8: sd2-bus-width8 {
+		samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_clk: sd3-clk {
+		samsung,pins = "gpk3-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_cmd: sd3-cmd {
+		samsung,pins = "gpk3-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_cd: sd3-cd {
+		samsung,pins = "gpk3-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_bus1: sd3-bus-width1 {
+		samsung,pins = "gpk3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_bus4: sd3-bus-width4 {
+		samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	eint0: ext-int0 {
+		samsung,pins = "gpx0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint8: ext-int8 {
+		samsung,pins = "gpx1-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint15: ext-int15 {
+		samsung,pins = "gpx1-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint16: ext-int16 {
+		samsung,pins = "gpx2-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint31: ext-int31 {
+		samsung,pins = "gpx3-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	cam_port_a_io: cam-port-a-io {
+		samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
+				"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
+				"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	cam_port_a_clk_active: cam-port-a-clk-active {
+		samsung,pins = "gpj1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	cam_port_a_clk_idle: cam-port-a-clk-idle {
+		samsung,pins = "gpj1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hdmi_cec: hdmi-cec {
+		samsung,pins = "gpx3-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+};
+
+&pinctrl_2 {
+	gpz: gpz {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	i2s0_bus: i2s0-bus {
+		samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
+				"gpz-4", "gpz-5", "gpz-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
 
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpc1: gpc1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpd0: gpd0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpd1: gpd1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpe0: gpe0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpe1: gpe1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpe2: gpe2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpe3: gpe3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpe4: gpe4 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf0: gpf0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf1: gpf1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf2: gpf2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf3: gpf3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		uart0_data: uart0-data {
-			samsung,pins = "gpa0-0", "gpa0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart0_fctl: uart0-fctl {
-			samsung,pins = "gpa0-2", "gpa0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart1_data: uart1-data {
-			samsung,pins = "gpa0-4", "gpa0-5";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart1_fctl: uart1-fctl {
-			samsung,pins = "gpa0-6", "gpa0-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c2_bus: i2c2-bus {
-			samsung,pins = "gpa0-6", "gpa0-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart2_data: uart2-data {
-			samsung,pins = "gpa1-0", "gpa1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart2_fctl: uart2-fctl {
-			samsung,pins = "gpa1-2", "gpa1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart_audio_a: uart-audio-a {
-			samsung,pins = "gpa1-0", "gpa1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c3_bus: i2c3-bus {
-			samsung,pins = "gpa1-2", "gpa1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart3_data: uart3-data {
-			samsung,pins = "gpa1-4", "gpa1-5";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart_audio_b: uart-audio-b {
-			samsung,pins = "gpa1-4", "gpa1-5";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spi0_bus: spi0-bus {
-			samsung,pins = "gpb-0", "gpb-2", "gpb-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c4_bus: i2c4-bus {
-			samsung,pins = "gpb-2", "gpb-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spi1_bus: spi1-bus {
-			samsung,pins = "gpb-4", "gpb-6", "gpb-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c5_bus: i2c5-bus {
-			samsung,pins = "gpb-6", "gpb-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2s1_bus: i2s1-bus {
-			samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
-					"gpc0-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pcm1_bus: pcm1-bus {
-			samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
-					"gpc0-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		ac97_bus: ac97-bus {
-			samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
-					"gpc0-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2s2_bus: i2s2-bus {
-			samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
-					"gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pcm2_bus: pcm2-bus {
-			samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
-					"gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spdif_bus: spdif-bus {
-			samsung,pins = "gpc1-0", "gpc1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c6_bus: i2c6-bus {
-			samsung,pins = "gpc1-3", "gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spi2_bus: spi2-bus {
-			samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c7_bus: i2c7-bus {
-			samsung,pins = "gpd0-2", "gpd0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c0_bus: i2c0-bus {
-			samsung,pins = "gpd1-0", "gpd1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c1_bus: i2c1-bus {
-			samsung,pins = "gpd1-2", "gpd1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm0_out: pwm0-out {
-			samsung,pins = "gpd0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm1_out: pwm1-out {
-			samsung,pins = "gpd0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm2_out: pwm2-out {
-			samsung,pins = "gpd0-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm3_out: pwm3-out {
-			samsung,pins = "gpd0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_ctrl: lcd-ctrl {
-			samsung,pins = "gpd0-0", "gpd0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_sync: lcd-sync {
-			samsung,pins = "gpf0-0", "gpf0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_en: lcd-en {
-			samsung,pins = "gpe3-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_clk: lcd-clk {
-			samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_data16: lcd-data-width16 {
-			samsung,pins = "gpf0-7", "gpf1-0", "gpf1-1", "gpf1-2",
-					"gpf1-3", "gpf1-6", "gpf1-7", "gpf2-0",
-					"gpf2-1", "gpf2-2", "gpf2-3", "gpf2-7",
-					"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_data18: lcd-data-width18 {
-			samsung,pins = "gpf0-6", "gpf0-7", "gpf1-0", "gpf1-1",
-					"gpf1-2", "gpf1-3", "gpf1-6", "gpf1-7",
-					"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
-					"gpf2-6", "gpf2-7", "gpf3-0", "gpf3-1",
-					"gpf3-2", "gpf3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_data24: lcd-data-width24 {
-			samsung,pins = "gpf0-4", "gpf0-5", "gpf0-6", "gpf0-7",
-					"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3",
-					"gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7",
-					"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
-					"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
-					"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-	};
-
-	pinctrl@11000000 {
-		gpj0: gpj0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpj1: gpj1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk0: gpk0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk1: gpk1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk2: gpk2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk3: gpk3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpl0: gpl0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpl1: gpl1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpl2: gpl2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpy0: gpy0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy1: gpy1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy2: gpy2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy3: gpy3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy4: gpy4 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy5: gpy5 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy6: gpy6 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpx0: gpx0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-			#interrupt-cells = <2>;
-		};
-
-		gpx1: gpx1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-			#interrupt-cells = <2>;
-		};
-
-		gpx2: gpx2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpx3: gpx3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		sd0_clk: sd0-clk {
-			samsung,pins = "gpk0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_cmd: sd0-cmd {
-			samsung,pins = "gpk0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_cd: sd0-cd {
-			samsung,pins = "gpk0-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_bus1: sd0-bus-width1 {
-			samsung,pins = "gpk0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_bus4: sd0-bus-width4 {
-			samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_bus8: sd0-bus-width8 {
-			samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_clk: sd4-clk {
-			samsung,pins = "gpk0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_cmd: sd4-cmd {
-			samsung,pins = "gpk0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_cd: sd4-cd {
-			samsung,pins = "gpk0-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_bus1: sd4-bus-width1 {
-			samsung,pins = "gpk0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_bus4: sd4-bus-width4 {
-			samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_bus8: sd4-bus-width8 {
-			samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_clk: sd1-clk {
-			samsung,pins = "gpk1-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_cmd: sd1-cmd {
-			samsung,pins = "gpk1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_cd: sd1-cd {
-			samsung,pins = "gpk1-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_bus1: sd1-bus-width1 {
-			samsung,pins = "gpk1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_bus4: sd1-bus-width4 {
-			samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_clk: sd2-clk {
-			samsung,pins = "gpk2-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_cmd: sd2-cmd {
-			samsung,pins = "gpk2-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_cd: sd2-cd {
-			samsung,pins = "gpk2-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_bus1: sd2-bus-width1 {
-			samsung,pins = "gpk2-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_bus4: sd2-bus-width4 {
-			samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_bus8: sd2-bus-width8 {
-			samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_clk: sd3-clk {
-			samsung,pins = "gpk3-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_cmd: sd3-cmd {
-			samsung,pins = "gpk3-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_cd: sd3-cd {
-			samsung,pins = "gpk3-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_bus1: sd3-bus-width1 {
-			samsung,pins = "gpk3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_bus4: sd3-bus-width4 {
-			samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		eint0: ext-int0 {
-			samsung,pins = "gpx0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint8: ext-int8 {
-			samsung,pins = "gpx1-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint15: ext-int15 {
-			samsung,pins = "gpx1-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint16: ext-int16 {
-			samsung,pins = "gpx2-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint31: ext-int31 {
-			samsung,pins = "gpx3-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		cam_port_a_io: cam-port-a-io {
-			samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
-					"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
-					"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		cam_port_a_clk_active: cam-port-a-clk-active {
-			samsung,pins = "gpj1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		cam_port_a_clk_idle: cam-port-a-clk-idle {
-			samsung,pins = "gpj1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		hdmi_cec: hdmi-cec {
-			samsung,pins = "gpx3-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-	};
-
-	pinctrl@3860000 {
-		gpz: gpz {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		i2s0_bus: i2s0-bus {
-			samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
-					"gpz-4", "gpz-5", "gpz-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pcm0_bus: pcm0-bus {
-			samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
-					"gpz-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
+	pcm0_bus: pcm0-bus {
+		samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
+				"gpz-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
 	};
 };
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index aaade17b140e..268bd38510e7 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -148,43 +148,12 @@
 		};
 	};
 
-	camera {
-		pinctrl-names = "default";
-		pinctrl-0 = <>;
-		status = "okay";
-
-		fimc_0: fimc@11800000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC0>,
-					<&clock CLK_SCLK_FIMC0>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-
-		fimc_1: fimc@11810000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC1>,
-					<&clock CLK_SCLK_FIMC1>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-
-		fimc_2: fimc@11820000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC2>,
-					<&clock CLK_SCLK_FIMC2>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
+};
 
-		fimc_3: fimc@11830000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC3>,
-					<&clock CLK_SCLK_FIMC3>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-	};
+&camera {
+	pinctrl-names = "default";
+	pinctrl-0 = <>;
+	status = "okay";
 };
 
 &cpu0 {
@@ -234,6 +203,38 @@
 	vbus-supply = <&safe1_sreg>;
 };
 
+&fimc_0 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+			  <&clock CLK_SCLK_FIMC0>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
+&fimc_1 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+			  <&clock CLK_SCLK_FIMC1>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
+&fimc_2 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+			  <&clock CLK_SCLK_FIMC2>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+		assigned-clock-rates = <0>, <160000000>;
+};
+
+&fimc_3 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+			  <&clock CLK_SCLK_FIMC3>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
 &fimd {
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index 21fff7cd3aa4..4e6ff97e1ec4 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -28,24 +28,6 @@
 		stdout-path = &serial_2;
 	};
 
-	sysram@2020000 {
-		smp-sysram@0 {
-			status = "disabled";
-		};
-
-		smp-sysram@5000 {
-			compatible = "samsung,exynos4210-sysram";
-			reg = <0x5000 0x1000>;
-		};
-
-		smp-sysram@1f000 {
-			status = "disabled";
-		};
-	};
-
-	mct@10050000 {
-		compatible = "none";
-	};
 
 	fixed-rate-clocks {
 		xxti {
@@ -173,45 +155,6 @@
 		};
 	};
 
-	camera {
-		status = "okay";
-
-		pinctrl-names = "default";
-		pinctrl-0 = <>;
-
-		fimc_0: fimc@11800000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC0>,
-					<&clock CLK_SCLK_FIMC0>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-
-		fimc_1: fimc@11810000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC1>,
-					<&clock CLK_SCLK_FIMC1>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-
-		fimc_2: fimc@11820000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC2>,
-					<&clock CLK_SCLK_FIMC2>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-
-		fimc_3: fimc@11830000 {
-			status = "okay";
-			assigned-clocks = <&clock CLK_MOUT_FIMC3>,
-					<&clock CLK_SCLK_FIMC3>;
-			assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
-			assigned-clock-rates = <0>, <160000000>;
-		};
-	};
-
 	hdmi_en: voltage-regulator-hdmi-5v {
 		compatible = "regulator-fixed";
 		regulator-name = "HDMI_5V";
@@ -234,6 +177,13 @@
 	};
 };
 
+&camera {
+	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <>;
+};
+
 &cpu0 {
 	cpu0-supply = <&vdd_arm_reg>;
 };
@@ -250,6 +200,38 @@
 	vbus-supply = <&safeout1_reg>;
 };
 
+&fimc_0 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+			  <&clock CLK_SCLK_FIMC0>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
+&fimc_1 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+			  <&clock CLK_SCLK_FIMC1>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
+&fimc_2 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+			  <&clock CLK_SCLK_FIMC2>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
+&fimc_3 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+			  <&clock CLK_SCLK_FIMC3>;
+	assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+	assigned-clock-rates = <0>, <160000000>;
+};
+
 &fimd {
 	pinctrl-0 = <&lcd_clk>, <&lcd_data24>;
 	pinctrl-names = "default";
@@ -501,6 +483,10 @@
 	status = "okay";
 };
 
+&mct {
+	compatible = "none";
+};
+
 &mdma1 {
 	reg = <0x12840000 0x1000>;
 };
@@ -579,3 +565,18 @@
 	/delete-property/dmas;
 	/delete-property/dma-names;
 };
+
+&sysram {
+	smp-sysram@0 {
+		status = "disabled";
+	};
+
+	smp-sysram@5000 {
+		compatible = "samsung,exynos4210-sysram";
+		reg = <0x5000 0x1000>;
+	};
+
+	smp-sysram@1f000 {
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index cc978cf28267..853604d91158 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -17,7 +17,6 @@
  */
 
 #include "exynos4.dtsi"
-#include "exynos4210-pinctrl.dtsi"
 #include "exynos4-cpu-thermal.dtsi"
 
 / {
@@ -49,8 +48,6 @@
 				400000	975000
 				200000	950000
 			>;
-			cooling-min-level = <4>;
-			cooling-max-level = <2>;
 			#cooling-cells = <2>; /* min followed by max */
 		};
 
@@ -61,365 +58,317 @@
 		};
 	};
 
-	sysram: sysram@2020000 {
-		compatible = "mmio-sram";
-		reg = <0x02020000 0x20000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0x02020000 0x20000>;
+	soc: soc {
+		sysram: sysram@2020000 {
+			compatible = "mmio-sram";
+			reg = <0x02020000 0x20000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x02020000 0x20000>;
 
-		smp-sysram@0 {
-			compatible = "samsung,exynos4210-sysram";
-			reg = <0x0 0x1000>;
-		};
+			smp-sysram@0 {
+				compatible = "samsung,exynos4210-sysram";
+				reg = <0x0 0x1000>;
+			};
 
-		smp-sysram@1f000 {
-			compatible = "samsung,exynos4210-sysram-ns";
-			reg = <0x1f000 0x1000>;
+			smp-sysram@1f000 {
+				compatible = "samsung,exynos4210-sysram-ns";
+				reg = <0x1f000 0x1000>;
+			};
 		};
-	};
 
-	pd_lcd1: lcd1-power-domain@10023ca0 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023CA0 0x20>;
-		#power-domain-cells = <0>;
-		label = "LCD1";
-	};
+		pd_lcd1: lcd1-power-domain@10023ca0 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023CA0 0x20>;
+			#power-domain-cells = <0>;
+			label = "LCD1";
+		};
 
-	l2c: l2-cache-controller@10502000 {
-		compatible = "arm,pl310-cache";
-		reg = <0x10502000 0x1000>;
-		cache-unified;
-		cache-level = <2>;
-		arm,tag-latency = <2 2 1>;
-		arm,data-latency = <2 2 1>;
-	};
+		l2c: l2-cache-controller@10502000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x10502000 0x1000>;
+			cache-unified;
+			cache-level = <2>;
+			arm,tag-latency = <2 2 1>;
+			arm,data-latency = <2 2 1>;
+		};
 
-	mct: mct@10050000 {
-		compatible = "samsung,exynos4210-mct";
-		reg = <0x10050000 0x800>;
-		interrupt-parent = <&mct_map>;
-		interrupts = <0>, <1>, <2>, <3>, <4>, <5>;
-		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
-		clock-names = "fin_pll", "mct";
-
-		mct_map: mct-map {
-			#interrupt-cells = <1>;
-			#address-cells = <0>;
-			#size-cells = <0>;
-			interrupt-map = <0 &gic 0 57 IRQ_TYPE_LEVEL_HIGH>,
+		mct: mct@10050000 {
+			compatible = "samsung,exynos4210-mct";
+			reg = <0x10050000 0x800>;
+			interrupt-parent = <&mct_map>;
+			interrupts = <0>, <1>, <2>, <3>, <4>, <5>;
+			clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
+			clock-names = "fin_pll", "mct";
+
+			mct_map: mct-map {
+				#interrupt-cells = <1>;
+				#address-cells = <0>;
+				#size-cells = <0>;
+				interrupt-map =
+					<0 &gic 0 57 IRQ_TYPE_LEVEL_HIGH>,
 					<1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>,
 					<2 &combiner 12 6>,
 					<3 &combiner 12 7>,
 					<4 &gic 0 42 IRQ_TYPE_LEVEL_HIGH>,
 					<5 &gic 0 48 IRQ_TYPE_LEVEL_HIGH>;
+			};
 		};
-	};
 
-	watchdog: watchdog@10060000 {
-		compatible = "samsung,s3c6410-wdt";
-		reg = <0x10060000 0x100>;
-		interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_WDT>;
-		clock-names = "watchdog";
-	};
-
-	clock: clock-controller@10030000 {
-		compatible = "samsung,exynos4210-clock";
-		reg = <0x10030000 0x20000>;
-		#clock-cells = <1>;
-	};
-
-	pinctrl_0: pinctrl@11400000 {
-		compatible = "samsung,exynos4210-pinctrl";
-		reg = <0x11400000 0x1000>;
-		interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
-	};
-
-	pinctrl_1: pinctrl@11000000 {
-		compatible = "samsung,exynos4210-pinctrl";
-		reg = <0x11000000 0x1000>;
-		interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
-
-		wakup_eint: wakeup-interrupt-controller {
-			compatible = "samsung,exynos4210-wakeup-eint";
-			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		watchdog: watchdog@10060000 {
+			compatible = "samsung,s3c6410-wdt";
+			reg = <0x10060000 0x100>;
+			interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_WDT>;
+			clock-names = "watchdog";
 		};
-	};
 
-	pinctrl_2: pinctrl@3860000 {
-		compatible = "samsung,exynos4210-pinctrl";
-		reg = <0x03860000 0x1000>;
-	};
+		clock: clock-controller@10030000 {
+			compatible = "samsung,exynos4210-clock";
+			reg = <0x10030000 0x20000>;
+			#clock-cells = <1>;
+		};
 
-	tmu: tmu@100c0000 {
-		compatible = "samsung,exynos4210-tmu";
-		interrupt-parent = <&combiner>;
-		reg = <0x100C0000 0x100>;
-		interrupts = <2 4>;
-		clocks = <&clock CLK_TMU_APBIF>;
-		clock-names = "tmu_apbif";
-		samsung,tmu_gain = <15>;
-		samsung,tmu_reference_voltage = <7>;
-		status = "disabled";
-	};
+		pinctrl_0: pinctrl@11400000 {
+			compatible = "samsung,exynos4210-pinctrl";
+			reg = <0x11400000 0x1000>;
+			interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+		};
 
-	thermal-zones {
-		cpu_thermal: cpu-thermal {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tmu 0>;
+		pinctrl_1: pinctrl@11000000 {
+			compatible = "samsung,exynos4210-pinctrl";
+			reg = <0x11000000 0x1000>;
+			interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 
-			trips {
-			      cpu_alert0: cpu-alert-0 {
-				      temperature = <85000>; /* millicelsius */
-			      };
-			      cpu_alert1: cpu-alert-1 {
-				      temperature = <100000>; /* millicelsius */
-			      };
-			      cpu_alert2: cpu-alert-2 {
-				      temperature = <110000>; /* millicelsius */
-			      };
+			wakup_eint: wakeup-interrupt-controller {
+				compatible = "samsung,exynos4210-wakeup-eint";
+				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 			};
 		};
-	};
-
-	g2d: g2d@12800000 {
-		compatible = "samsung,s5pv210-g2d";
-		reg = <0x12800000 0x1000>;
-		interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
-		clock-names = "sclk_fimg2d", "fimg2d";
-		power-domains = <&pd_lcd0>;
-		iommus = <&sysmmu_g2d>;
-	};
 
-	camera {
-		clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>,
-			 <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>;
-		clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
-
-		fimc_0: fimc@11800000 {
-			samsung,pix-limits = <4224 8192 1920 4224>;
-			samsung,mainscaler-ext;
-			samsung,cam-if;
+		pinctrl_2: pinctrl@3860000 {
+			compatible = "samsung,exynos4210-pinctrl";
+			reg = <0x03860000 0x1000>;
 		};
 
-		fimc_1: fimc@11810000 {
-			samsung,pix-limits = <4224 8192 1920 4224>;
-			samsung,mainscaler-ext;
-			samsung,cam-if;
+		g2d: g2d@12800000 {
+			compatible = "samsung,s5pv210-g2d";
+			reg = <0x12800000 0x1000>;
+			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
+			clock-names = "sclk_fimg2d", "fimg2d";
+			power-domains = <&pd_lcd0>;
+			iommus = <&sysmmu_g2d>;
 		};
 
-		fimc_2: fimc@11820000 {
-			samsung,pix-limits = <4224 8192 1920 4224>;
-			samsung,mainscaler-ext;
-			samsung,lcd-wb;
+		ppmu_lcd1: ppmu_lcd1@12240000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12240000 0x2000>;
+			clocks = <&clock CLK_PPMULCD1>;
+			clock-names = "ppmu";
+			status = "disabled";
 		};
 
-		fimc_3: fimc@11830000 {
-			samsung,pix-limits = <1920 8192 1366 1920>;
-			samsung,rotators = <0>;
-			samsung,mainscaler-ext;
-			samsung,lcd-wb;
+		sysmmu_g2d: sysmmu@12a20000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x12A20000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 7>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
+			power-domains = <&pd_lcd0>;
+			#iommu-cells = <0>;
 		};
-	};
 
-	mixer: mixer@12c10000 {
-		clock-names = "mixer", "hdmi", "sclk_hdmi", "vp", "mout_mixer",
-			"sclk_mixer";
-		clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
-			<&clock CLK_SCLK_HDMI>, <&clock CLK_VP>,
-			<&clock CLK_MOUT_MIXER>, <&clock CLK_SCLK_MIXER>;
-	};
+		sysmmu_fimd1: sysmmu@12220000 {
+			compatible = "samsung,exynos-sysmmu";
+			interrupt-parent = <&combiner>;
+			reg = <0x12220000 0x1000>;
+			interrupts = <5 3>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_FIMD1>, <&clock CLK_FIMD1>;
+			power-domains = <&pd_lcd1>;
+			#iommu-cells = <0>;
+		};
 
-	ppmu_lcd1: ppmu_lcd1@12240000 {
-		compatible = "samsung,exynos-ppmu";
-		reg = <0x12240000 0x2000>;
-		clocks = <&clock CLK_PPMULCD1>;
-		clock-names = "ppmu";
-		status = "disabled";
-	};
+		bus_dmc: bus_dmc {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_DMC>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_dmc_opp_table>;
+			status = "disabled";
+		};
 
-	sysmmu_g2d: sysmmu@12a20000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x12A20000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 7>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
-		power-domains = <&pd_lcd0>;
-		#iommu-cells = <0>;
-	};
+		bus_acp: bus_acp {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_ACP>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_acp_opp_table>;
+			status = "disabled";
+		};
 
-	sysmmu_fimd1: sysmmu@12220000 {
-		compatible = "samsung,exynos-sysmmu";
-		interrupt-parent = <&combiner>;
-		reg = <0x12220000 0x1000>;
-		interrupts = <5 3>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_FIMD1>, <&clock CLK_FIMD1>;
-		power-domains = <&pd_lcd1>;
-		#iommu-cells = <0>;
-	};
+		bus_peri: bus_peri {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK100>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_peri_opp_table>;
+			status = "disabled";
+		};
 
-	bus_dmc: bus_dmc {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_DMC>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_dmc_opp_table>;
-		status = "disabled";
-	};
+		bus_fsys: bus_fsys {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK133>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_fsys_opp_table>;
+			status = "disabled";
+		};
 
-	bus_acp: bus_acp {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_ACP>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_acp_opp_table>;
-		status = "disabled";
-	};
+		bus_display: bus_display {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK160>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_display_opp_table>;
+			status = "disabled";
+		};
 
-	bus_peri: bus_peri {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK100>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_peri_opp_table>;
-		status = "disabled";
-	};
+		bus_lcd0: bus_lcd0 {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK200>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
+		};
 
-	bus_fsys: bus_fsys {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK133>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_fsys_opp_table>;
-		status = "disabled";
-	};
+		bus_leftbus: bus_leftbus {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_GDL>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
+		};
 
-	bus_display: bus_display {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK160>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_display_opp_table>;
-		status = "disabled";
-	};
+		bus_rightbus: bus_rightbus {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_GDR>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
+		};
 
-	bus_lcd0: bus_lcd0 {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK200>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
+		bus_mfc: bus_mfc {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_SCLK_MFC>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
+		};
 
-	bus_leftbus: bus_leftbus {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_GDL>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
+		bus_dmc_opp_table: opp_table1 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-	bus_rightbus: bus_rightbus {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_GDR>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
-
-	bus_mfc: bus_mfc {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_SCLK_MFC>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+				opp-microvolt = <1025000>;
+			};
+			opp-267000000 {
+				opp-hz = /bits/ 64 <267000000>;
+				opp-microvolt = <1050000>;
+			};
+			opp-400000000 {
+				opp-hz = /bits/ 64 <400000000>;
+				opp-microvolt = <1150000>;
+			};
+		};
 
-	bus_dmc_opp_table: opp_table1 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_acp_opp_table: opp_table2 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
-			opp-microvolt = <1025000>;
-		};
-		opp-267000000 {
-			opp-hz = /bits/ 64 <267000000>;
-			opp-microvolt = <1050000>;
-		};
-		opp-400000000 {
-			opp-hz = /bits/ 64 <400000000>;
-			opp-microvolt = <1150000>;
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+			};
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+			};
+			opp-200000000 {
+				opp-hz = /bits/ 64 <200000000>;
+			};
 		};
-	};
 
-	bus_acp_opp_table: opp_table2 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_peri_opp_table: opp_table3 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
-		};
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
-		};
-		opp-200000000 {
-			opp-hz = /bits/ 64 <200000000>;
+			opp-5000000 {
+				opp-hz = /bits/ 64 <5000000>;
+			};
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+			};
 		};
-	};
 
-	bus_peri_opp_table: opp_table3 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_fsys_opp_table: opp_table4 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-5000000 {
-			opp-hz = /bits/ 64 <5000000>;
-		};
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
+			opp-10000000 {
+				opp-hz = /bits/ 64 <10000000>;
+			};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+			};
 		};
-	};
 
-	bus_fsys_opp_table: opp_table4 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_display_opp_table: opp_table5 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-10000000 {
-			opp-hz = /bits/ 64 <10000000>;
-		};
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+			};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+			};
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+			};
 		};
-	};
 
-	bus_display_opp_table: opp_table5 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_leftbus_opp_table: opp_table6 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-		};
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
-		};
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+			};
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+			};
+			opp-200000000 {
+				opp-hz = /bits/ 64 <200000000>;
+			};
 		};
 	};
 
-	bus_leftbus_opp_table: opp_table6 {
-		compatible = "operating-points-v2";
-		opp-shared;
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tmu 0>;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-		};
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
-		};
-		opp-200000000 {
-			opp-hz = /bits/ 64 <200000000>;
+			trips {
+				cpu_alert0: cpu-alert-0 {
+				temperature = <85000>; /* millicelsius */
+				};
+				cpu_alert1: cpu-alert-1 {
+				temperature = <100000>; /* millicelsius */
+				};
+				cpu_alert2: cpu-alert-2 {
+				temperature = <110000>; /* millicelsius */
+				};
+			};
 		};
 	};
 };
@@ -428,6 +377,12 @@
 	cpu-offset = <0x8000>;
 };
 
+&camera {
+	clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>,
+		 <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>;
+	clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
+};
+
 &combiner {
 	samsung,combiner-nr = <16>;
 	interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
@@ -448,10 +403,43 @@
 		     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
 };
 
+&fimc_0 {
+	samsung,pix-limits = <4224 8192 1920 4224>;
+	samsung,mainscaler-ext;
+	samsung,cam-if;
+};
+
+&fimc_1 {
+	samsung,pix-limits = <4224 8192 1920 4224>;
+	samsung,mainscaler-ext;
+	samsung,cam-if;
+};
+
+&fimc_2 {
+	samsung,pix-limits = <4224 8192 1920 4224>;
+	samsung,mainscaler-ext;
+	samsung,lcd-wb;
+};
+
+&fimc_3 {
+	samsung,pix-limits = <1920 8192 1366 1920>;
+	samsung,rotators = <0>;
+	samsung,mainscaler-ext;
+	samsung,lcd-wb;
+};
+
 &mdma1 {
 	power-domains = <&pd_lcd0>;
 };
 
+&mixer {
+	clock-names = "mixer", "hdmi", "sclk_hdmi", "vp", "mout_mixer",
+		      "sclk_mixer";
+	clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+		 <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>,
+		 <&clock CLK_MOUT_MIXER>, <&clock CLK_SCLK_MIXER>;
+};
+
 &pmu_system_controller {
 	clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
 			"clkout4", "clkout8", "clkout9";
@@ -468,3 +456,13 @@
 &sysmmu_rotator {
 	power-domains = <&pd_lcd0>;
 };
+
+&tmu {
+	compatible = "samsung,exynos4210-tmu";
+	clocks = <&clock CLK_TMU_APBIF>;
+	clock-names = "tmu_apbif";
+	samsung,tmu_gain = <15>;
+	samsung,tmu_reference_voltage = <7>;
+};
+
+#include "exynos4210-pinctrl.dtsi"
diff --git a/arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi b/arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
new file mode 100644
index 000000000000..ee8e1f445370
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Samsung's Exynos4412 based Galaxy S3 board device tree source
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ */
+
+/dts-v1/;
+#include "exynos4412-midas.dtsi"
+
+/ {
+	aliases {
+		i2c9 = &i2c_ak8975;
+		i2c10 = &i2c_cm36651;
+	};
+
+	regulators {
+		lcd_vdd3_reg: voltage-regulator-2 {
+			compatible = "regulator-fixed";
+			regulator-name = "LCD_VDD_2.2V";
+			regulator-min-microvolt = <2200000>;
+			regulator-max-microvolt = <2200000>;
+			gpio = <&gpc0 1 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+
+		ps_als_reg: voltage-regulator-5 {
+			compatible = "regulator-fixed";
+			regulator-name = "LED_A_3.0V";
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			gpio = <&gpj0 5 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+	};
+
+	i2c_ak8975: i2c-gpio-0 {
+		compatible = "i2c-gpio";
+		gpios = <&gpy2 4 GPIO_ACTIVE_HIGH>, <&gpy2 5 GPIO_ACTIVE_HIGH>;
+		i2c-gpio,delay-us = <2>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+
+		ak8975@c {
+			compatible = "asahi-kasei,ak8975";
+			reg = <0x0c>;
+			gpios = <&gpj0 7 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	i2c_cm36651: i2c-gpio-2 {
+		compatible = "i2c-gpio";
+		gpios = <&gpf0 0 GPIO_ACTIVE_LOW>, <&gpf0 1 GPIO_ACTIVE_LOW>;
+		i2c-gpio,delay-us = <2>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cm36651@18 {
+			compatible = "capella,cm36651";
+			reg = <0x18>;
+			interrupt-parent = <&gpx0>;
+			interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+			vled-supply = <&ps_als_reg>;
+		};
+	};
+};
+
+&buck9_reg {
+	maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>;
+};
+
+&cam_af_reg {
+	gpio = <&gpm0 4 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&cam_io_reg {
+	gpio = <&gpm0 2 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&dsi_0 {
+	status = "okay";
+
+	panel@0 {
+		compatible = "samsung,s6e8aa0";
+		reg = <0>;
+		vdd3-supply = <&lcd_vdd3_reg>;
+		vci-supply = <&ldo25_reg>;
+		reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>;
+		power-on-delay= <50>;
+		reset-delay = <100>;
+		init-delay = <100>;
+		flip-horizontal;
+		flip-vertical;
+		panel-width-mm = <58>;
+		panel-height-mm = <103>;
+
+		display-timings {
+			timing-0 {
+				clock-frequency = <57153600>;
+				hactive = <720>;
+				vactive = <1280>;
+				hfront-porch = <5>;
+				hback-porch = <5>;
+				hsync-len = <5>;
+				vfront-porch = <13>;
+				vback-porch = <1>;
+				vsync-len = <2>;
+			};
+		};
+	};
+};
+
+&i2c_3 {
+	mms114-touchscreen@48 {
+		compatible = "melfas,mms114";
+		reg = <0x48>;
+		interrupt-parent = <&gpm2>;
+		interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+		x-size = <720>;
+		y-size = <1280>;
+		avdd-supply = <&ldo23_reg>;
+		vdd-supply = <&ldo24_reg>;
+	};
+};
+
+&ldo25_reg {
+	regulator-name = "LCD_VCC_3.3V";
+	regulator-min-microvolt = <2800000>;
+	regulator-max-microvolt = <2800000>;
+};
+
+&s5c73m3 {
+	standby-gpios = <&gpm0 1 GPIO_ACTIVE_LOW>;   /* ISP_STANDBY */
+	vdda-supply = <&ldo17_reg>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4412-i9300.dts b/arch/arm/boot/dts/exynos4412-i9300.dts
new file mode 100644
index 000000000000..f8125a945f8d
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4412-i9300.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Samsung's Exynos4412 based M0 (GT-I9300) board device tree source
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ */
+
+/dts-v1/;
+#include "exynos4412-galaxy-s3.dtsi"
+
+/ {
+	model = "Samsung Galaxy S3 (GT-I9300) based on Exynos4412";
+	compatible = "samsung,i9300", "samsung,midas", "samsung,exynos4412", "samsung,exynos4";
+
+	/* bootargs are passed in by bootloader */
+
+	memory@40000000 {
+		device_type = "memory";
+		reg =  <0x40000000 0x40000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/exynos4412-i9305.dts b/arch/arm/boot/dts/exynos4412-i9305.dts
new file mode 100644
index 000000000000..54a2a55dbf70
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4412-i9305.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+#include "exynos4412-galaxy-s3.dtsi"
+
+/ {
+	model = "Samsung Galaxy S3 (GT-I9305) based on Exynos4412";
+	compatible = "samsung,i9305", "samsung,midas", "samsung,exynos4412", "samsung,exynos4";
+
+	/* bootargs are passed in by bootloader */
+
+	memory@40000000 {
+		device_type = "memory";
+		reg =  <0x40000000 0x80000000>;
+	};
+};
+
+&i2c0_bus {
+	/* SCL and SDA pins are swapped */
+	samsung,pins = "gpd1-1", "gpd1-0";
+};
diff --git a/arch/arm/boot/dts/exynos4412-itop-elite.dts b/arch/arm/boot/dts/exynos4412-itop-elite.dts
index a4cd4939fe9a..0dedeba89b5f 100644
--- a/arch/arm/boot/dts/exynos4412-itop-elite.dts
+++ b/arch/arm/boot/dts/exynos4412-itop-elite.dts
@@ -116,14 +116,6 @@
 		compatible = "pwm-beeper";
 		pwms = <&pwm 0 4000000 PWM_POLARITY_INVERTED>;
 	};
-
-	camera: camera {
-		pinctrl-0 = <&cam_port_a_clk_active>;
-		pinctrl-names = "default";
-		status = "okay";
-		assigned-clocks = <&clock CLK_MOUT_CAM0>;
-		assigned-clock-parents = <&clock CLK_XUSBXTI>;
-	};
 };
 
 &adc {
@@ -131,6 +123,14 @@
 	status = "okay";
 };
 
+&camera {
+	pinctrl-0 = <&cam_port_a_clk_active>;
+	pinctrl-names = "default";
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_CAM0>;
+	assigned-clock-parents = <&clock CLK_XUSBXTI>;
+};
+
 &clock_audss {
 	assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
 			<&clock_audss EXYNOS_MOUT_I2S>,
diff --git a/arch/arm/boot/dts/exynos4412-midas.dtsi b/arch/arm/boot/dts/exynos4412-midas.dtsi
new file mode 100644
index 000000000000..43266765377a
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4412-midas.dtsi
@@ -0,0 +1,1308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Samsung's Exynos4412 based Trats 2 board device tree source
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Device tree source file for Samsung's Trats 2 board which is based on
+ * Samsung's Exynos4412 SoC.
+ */
+
+/dts-v1/;
+#include "exynos4412.dtsi"
+#include "exynos4412-ppmu-common.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/maxim,max77686.h>
+#include <dt-bindings/pinctrl/samsung.h>
+
+/ {
+	compatible = "samsung,midas", "samsung,exynos4412", "samsung,exynos4";
+
+	aliases {
+		i2c11 = &i2c_max77693;
+		i2c12 = &i2c_max77693_fuel;
+	};
+
+	chosen {
+		stdout-path = &serial_2;
+	};
+
+	firmware@204f000 {
+		compatible = "samsung,secure-firmware";
+		reg = <0x0204F000 0x1000>;
+	};
+
+	fixed-rate-clocks {
+		xxti {
+			compatible = "samsung,clock-xxti", "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		xusbxti {
+			compatible = "samsung,clock-xusbxti", "fixed-clock";
+			clock-frequency = <24000000>;
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cam_io_reg: voltage-regulator-1 {
+			compatible = "regulator-fixed";
+			regulator-name = "CAM_SENSOR_A";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			enable-active-high;
+			status = "disabled";
+		};
+
+		cam_af_reg: voltage-regulator-3 {
+			compatible = "regulator-fixed";
+			regulator-name = "CAM_AF";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			enable-active-high;
+			status = "disabled";
+		};
+
+		vsil12: voltage-regulator-6 {
+			compatible = "regulator-fixed";
+			regulator-name = "VSIL_1.2V";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+			vin-supply = <&buck7_reg>;
+		};
+
+		vcc33mhl: voltage-regulator-7 {
+			compatible = "regulator-fixed";
+			regulator-name = "VCC_3.3_MHL";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+
+		vcc18mhl: voltage-regulator-8 {
+			compatible = "regulator-fixed";
+			regulator-name = "VCC_1.8_MHL";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		key-down {
+			gpios = <&gpx3 3 GPIO_ACTIVE_LOW>;
+			linux,code = <114>;
+			label = "volume down";
+			debounce-interval = <10>;
+		};
+
+		key-up {
+			gpios = <&gpx2 2 GPIO_ACTIVE_LOW>;
+			linux,code = <115>;
+			label = "volume up";
+			debounce-interval = <10>;
+		};
+
+		key-power {
+			gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
+			linux,code = <116>;
+			label = "power";
+			debounce-interval = <10>;
+			wakeup-source;
+		};
+
+		key-ok {
+			gpios = <&gpx0 1 GPIO_ACTIVE_LOW>;
+			linux,code = <139>;
+			label = "ok";
+			debounce-inteval = <10>;
+			wakeup-source;
+		};
+	};
+
+	i2c_max77693: i2c-gpio-1 {
+		compatible = "i2c-gpio";
+		gpios = <&gpm2 0 GPIO_ACTIVE_HIGH>, <&gpm2 1 GPIO_ACTIVE_HIGH>;
+		i2c-gpio,delay-us = <2>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+
+		max77693@66 {
+			compatible = "maxim,max77693";
+			interrupt-parent = <&gpx1>;
+			interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+			reg = <0x66>;
+
+			regulators {
+				esafeout1_reg: ESAFEOUT1 {
+					regulator-name = "ESAFEOUT1";
+				};
+				esafeout2_reg: ESAFEOUT2 {
+					regulator-name = "ESAFEOUT2";
+				};
+				charger_reg: CHARGER {
+					regulator-name = "CHARGER";
+					regulator-min-microamp = <60000>;
+					regulator-max-microamp = <2580000>;
+				};
+			};
+
+			max77693_haptic {
+				compatible = "maxim,max77693-haptic";
+				haptic-supply = <&ldo26_reg>;
+				pwms = <&pwm 0 38022 0>;
+			};
+
+			charger {
+				compatible = "maxim,max77693-charger";
+
+				maxim,constant-microvolt = <4350000>;
+				maxim,min-system-microvolt = <3600000>;
+				maxim,thermal-regulation-celsius = <100>;
+				maxim,battery-overcurrent-microamp = <3500000>;
+				maxim,charge-input-threshold-microvolt = <4300000>;
+			};
+		};
+	};
+
+	i2c_max77693_fuel: i2c-gpio-3 {
+		compatible = "i2c-gpio";
+		gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>, <&gpf1 4 GPIO_ACTIVE_HIGH>;
+		i2c-gpio,delay-us = <2>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+
+		max77693-fuel-gauge@36 {
+			compatible = "maxim,max17047";
+			interrupt-parent = <&gpx2>;
+			interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+			reg = <0x36>;
+
+			maxim,over-heat-temp = <700>;
+			maxim,over-volt = <4500>;
+		};
+	};
+
+	i2c-mhl {
+		compatible = "i2c-gpio";
+		gpios = <&gpf0 4 GPIO_ACTIVE_HIGH>, <&gpf0 6 GPIO_ACTIVE_HIGH>;
+		i2c-gpio,delay-us = <100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		pinctrl-0 = <&i2c_mhl_bus>;
+		pinctrl-names = "default";
+		status = "okay";
+
+		sii9234: hdmi-bridge@39 {
+			compatible = "sil,sii9234";
+			avcc33-supply = <&vcc33mhl>;
+			iovcc18-supply = <&vcc18mhl>;
+			avcc12-supply = <&vsil12>;
+			cvcc12-supply = <&vsil12>;
+			reset-gpios = <&gpf3 4 GPIO_ACTIVE_LOW>;
+			interrupt-parent = <&gpf3>;
+			interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0x39>;
+
+			port {
+				mhl_to_hdmi: endpoint {
+					remote-endpoint = <&hdmi_to_mhl>;
+				};
+			};
+		};
+	};
+
+	wlan_pwrseq: sdhci3-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpj0 0 GPIO_ACTIVE_LOW>;
+		clocks = <&max77686 MAX77686_CLK_PMIC>;
+		clock-names = "ext_clock";
+	};
+
+	sound {
+		compatible = "samsung,trats2-audio";
+		samsung,i2s-controller = <&i2s0>;
+		samsung,model = "Trats2";
+		samsung,audio-codec = <&wm1811>;
+		samsung,audio-routing =
+			"SPK", "SPKOUTLN",
+			"SPK", "SPKOUTLP",
+			"SPK", "SPKOUTRN",
+			"SPK", "SPKOUTRP";
+	};
+
+	thermistor-ap {
+		compatible = "murata,ncp15wb473";
+		pullup-uv = <1800000>;	 /* VCC_1.8V_AP */
+		pullup-ohm = <100000>;	 /* 100K */
+		pulldown-ohm = <100000>; /* 100K */
+		io-channels = <&adc 1>;  /* AP temperature */
+	};
+
+	thermistor-battery {
+		compatible = "murata,ncp15wb473";
+		pullup-uv = <1800000>;	 /* VCC_1.8V_AP */
+		pullup-ohm = <100000>;	 /* 100K */
+		pulldown-ohm = <100000>; /* 100K */
+		io-channels = <&adc 2>;  /* Battery temperature */
+	};
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			cooling-maps {
+				map0 {
+				     /* Corresponds to 800MHz at freq_table */
+				     cooling-device = <&cpu0 7 7>;
+				};
+				map1 {
+				     /* Corresponds to 200MHz at freq_table */
+				     cooling-device = <&cpu0 13 13>;
+			       };
+		       };
+		};
+	};
+};
+
+&adc {
+	vdd-supply = <&ldo3_reg>;
+	status = "okay";
+};
+
+&bus_dmc {
+	devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
+	vdd-supply = <&buck1_reg>;
+	status = "okay";
+};
+
+&bus_acp {
+	devfreq = <&bus_dmc>;
+	status = "okay";
+};
+
+&bus_c2c {
+	devfreq = <&bus_dmc>;
+	status = "okay";
+};
+
+&bus_leftbus {
+	devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
+	vdd-supply = <&buck3_reg>;
+	status = "okay";
+};
+
+&bus_rightbus {
+	devfreq = <&bus_leftbus>;
+	status = "okay";
+};
+
+&bus_display {
+	devfreq = <&bus_leftbus>;
+	status = "okay";
+};
+
+&bus_fsys {
+	devfreq = <&bus_leftbus>;
+	status = "okay";
+};
+
+&bus_peri {
+	devfreq = <&bus_leftbus>;
+	status = "okay";
+};
+
+&bus_mfc {
+	devfreq = <&bus_leftbus>;
+	status = "okay";
+};
+
+&camera {
+	pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>;
+	pinctrl-names = "default";
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_CAM0>,
+		<&clock CLK_MOUT_CAM1>;
+	assigned-clock-parents = <&clock CLK_XUSBXTI>,
+		<&clock CLK_XUSBXTI>;
+};
+
+&cpu0 {
+	cpu0-supply = <&buck2_reg>;
+};
+
+&csis_0 {
+	status = "okay";
+	vddcore-supply = <&ldo8_reg>;
+	vddio-supply = <&ldo10_reg>;
+	assigned-clocks = <&clock CLK_MOUT_CSIS0>,
+			<&clock CLK_SCLK_CSIS0>;
+	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+	assigned-clock-rates = <0>, <176000000>;
+
+	/* Camera C (3) MIPI CSI-2 (CSIS0) */
+	port@3 {
+		reg = <3>;
+		csis0_ep: endpoint {
+			remote-endpoint = <&s5c73m3_ep>;
+			data-lanes = <1 2 3 4>;
+			samsung,csis-hs-settle = <12>;
+		};
+	};
+};
+
+&csis_1 {
+	status = "okay";
+	vddcore-supply = <&ldo8_reg>;
+	vddio-supply = <&ldo10_reg>;
+	assigned-clocks = <&clock CLK_MOUT_CSIS1>,
+			<&clock CLK_SCLK_CSIS1>;
+	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+	assigned-clock-rates = <0>, <176000000>;
+
+	/* Camera D (4) MIPI CSI-2 (CSIS1) */
+	port@4 {
+		reg = <4>;
+		csis1_ep: endpoint {
+			remote-endpoint = <&is_s5k6a3_ep>;
+			data-lanes = <1>;
+			samsung,csis-hs-settle = <18>;
+			samsung,csis-wclk;
+		};
+	};
+};
+
+&dsi_0 {
+	vddcore-supply = <&ldo8_reg>;
+	vddio-supply = <&ldo10_reg>;
+	samsung,burst-clock-frequency = <500000000>;
+	samsung,esc-clock-frequency = <20000000>;
+	samsung,pll-clock-frequency = <24000000>;
+};
+
+&exynos_usbphy {
+	vbus-supply = <&esafeout1_reg>;
+	status = "okay";
+};
+
+&fimc_0 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+			<&clock CLK_SCLK_FIMC0>;
+	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+	assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_1 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+			<&clock CLK_SCLK_FIMC1>;
+	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+	assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_2 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+			<&clock CLK_SCLK_FIMC2>;
+	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+	assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_3 {
+	status = "okay";
+	assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+			<&clock CLK_SCLK_FIMC3>;
+	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+	assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_is {
+	pinctrl-0 = <&fimc_is_uart>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	};
+
+&fimc_lite_0 {
+	status = "okay";
+};
+
+&fimc_lite_1 {
+	status = "okay";
+};
+
+&fimd {
+	status = "okay";
+};
+
+&hdmi {
+	hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_hpd>;
+	vdd-supply = <&ldo3_reg>;
+	vdd_osc-supply = <&ldo4_reg>;
+	vdd_pll-supply = <&ldo3_reg>;
+	ddc = <&i2c_5>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@1 {
+			reg = <1>;
+			hdmi_to_mhl: endpoint {
+				remote-endpoint = <&mhl_to_hdmi>;
+			};
+		};
+	};
+};
+
+&hsotg {
+	vusb_d-supply = <&ldo15_reg>;
+	vusb_a-supply = <&ldo12_reg>;
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&i2c_0 {
+	samsung,i2c-sda-delay = <100>;
+	samsung,i2c-slave-addr = <0x10>;
+	samsung,i2c-max-bus-freq = <400000>;
+	pinctrl-0 = <&i2c0_bus>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	s5c73m3: s5c73m3@3c {
+		compatible = "samsung,s5c73m3";
+		reg = <0x3c>;
+		xshutdown-gpios = <&gpf1 3 GPIO_ACTIVE_LOW>; /* ISP_RESET */
+		vdd-int-supply = <&buck9_reg>;
+		vddio-cis-supply = <&ldo9_reg>;
+		vddio-host-supply = <&ldo18_reg>;
+		vdd-af-supply = <&cam_af_reg>;
+		vdd-reg-supply = <&cam_io_reg>;
+		clock-frequency = <24000000>;
+		/* CAM_A_CLKOUT */
+		clocks = <&camera 0>;
+		clock-names = "cis_extclk";
+		status = "disabled";
+		port {
+			s5c73m3_ep: endpoint {
+				remote-endpoint = <&csis0_ep>;
+				data-lanes = <1 2 3 4>;
+			};
+		};
+	};
+};
+
+&i2c1_isp {
+	pinctrl-0 = <&fimc_is_i2c1>;
+	pinctrl-names = "default";
+
+	s5k6a3@10 {
+		compatible = "samsung,s5k6a3";
+		reg = <0x10>;
+		svdda-supply = <&cam_io_reg>;
+		svddio-supply = <&ldo19_reg>;
+		afvdd-supply = <&ldo19_reg>;
+		clock-frequency = <24000000>;
+		/* CAM_B_CLKOUT */
+		clocks = <&camera 1>;
+		clock-names = "extclk";
+		samsung,camclk-out = <1>;
+		gpios = <&gpm1 6 GPIO_ACTIVE_HIGH>;
+
+		port {
+			is_s5k6a3_ep: endpoint {
+				remote-endpoint = <&csis1_ep>;
+				data-lanes = <1>;
+			};
+		};
+	};
+};
+
+&i2c_3 {
+	samsung,i2c-sda-delay = <100>;
+	samsung,i2c-slave-addr = <0x10>;
+	samsung,i2c-max-bus-freq = <400000>;
+	pinctrl-0 = <&i2c3_bus>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2c_4 {
+	samsung,i2c-sda-delay = <100>;
+	samsung,i2c-slave-addr = <0x10>;
+	samsung,i2c-max-bus-freq = <100000>;
+	pinctrl-0 = <&i2c4_bus>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	wm1811: wm1811@1a {
+		compatible = "wlf,wm1811";
+		reg = <0x1a>;
+		clocks = <&pmu_system_controller 0>;
+		clock-names = "MCLK1";
+		DCVDD-supply = <&ldo3_reg>;
+		DBVDD1-supply = <&ldo3_reg>;
+		wlf,ldo1ena = <&gpj0 4 0>;
+	};
+};
+
+&i2c_5 {
+	status = "okay";
+};
+
+&i2c_7 {
+	samsung,i2c-sda-delay = <100>;
+	samsung,i2c-slave-addr = <0x10>;
+	samsung,i2c-max-bus-freq = <100000>;
+	pinctrl-0 = <&i2c7_bus>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	max77686: max77686_pmic@9 {
+		compatible = "maxim,max77686";
+		interrupt-parent = <&gpx0>;
+		interrupts = <7 IRQ_TYPE_NONE>;
+		reg = <0x09>;
+		#clock-cells = <1>;
+
+		voltage-regulators {
+			ldo1_reg: LDO1 {
+				regulator-name = "VALIVE_1.0V_AP";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				regulator-name = "VM1M2_1.2V_AP";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			ldo3_reg: LDO3 {
+				regulator-name = "VCC_1.8V_AP";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				regulator-name = "VCC_2.8V_AP";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+			};
+
+			ldo5_reg: LDO5 {
+				regulator-name = "VCC_1.8V_IO";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo6_reg: LDO6 {
+				regulator-name = "VMPLL_1.0V_AP";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			ldo7_reg: LDO7 {
+				regulator-name = "VPLL_1.0V_AP";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			ldo8_reg: LDO8 {
+				regulator-name = "VMIPI_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo9_reg: LDO9 {
+				regulator-name = "CAM_ISP_MIPI_1.2V";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+
+			ldo10_reg: LDO10 {
+				regulator-name = "VMIPI_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo11_reg: LDO11 {
+				regulator-name = "VABB1_1.95V";
+				regulator-min-microvolt = <1950000>;
+				regulator-max-microvolt = <1950000>;
+				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo12_reg: LDO12 {
+				regulator-name = "VUOTG_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo13_reg: LDO13 {
+				regulator-name = "NFC_AVDD_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo14_reg: LDO14 {
+				regulator-name = "VABB2_1.95V";
+				regulator-min-microvolt = <1950000>;
+				regulator-max-microvolt = <1950000>;
+				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			ldo15_reg: LDO15 {
+				regulator-name = "VHSIC_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			ldo16_reg: LDO16 {
+				regulator-name = "VHSIC_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			ldo17_reg: LDO17 {
+				regulator-name = "CAM_SENSOR_CORE_1.2V";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+
+			ldo18_reg: LDO18 {
+				regulator-name = "CAM_ISP_SEN_IO_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo19_reg: LDO19 {
+				regulator-name = "VT_CAM_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo20_reg: LDO20 {
+				regulator-name = "VDDQ_PRE_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo21_reg: LDO21 {
+				regulator-name = "VTF_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				maxim,ena-gpios = <&gpy2 0 GPIO_ACTIVE_HIGH>;
+			};
+
+			ldo22_reg: LDO22 {
+				regulator-name = "VMEM_VDD_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
+			};
+
+			ldo23_reg: LDO23 {
+				regulator-name = "TSP_AVDD_3.3V";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo24_reg: LDO24 {
+				regulator-name = "TSP_VDD_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo25_reg: LDO25 {
+				regulator-name = "LDO25";
+			};
+
+			ldo26_reg: LDO26 {
+				regulator-name = "MOTOR_VCC_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+
+			buck1_reg: BUCK1 {
+				regulator-name = "vdd_mif";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			buck2_reg: BUCK2 {
+				regulator-name = "vdd_arm";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			buck3_reg: BUCK3 {
+				regulator-name = "vdd_int";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1150000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			buck4_reg: BUCK4 {
+				regulator-name = "vdd_g3d";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1150000>;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			buck5_reg: BUCK5 {
+				regulator-name = "VMEM_1.2V_AP";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			buck6_reg: BUCK6 {
+				regulator-name = "VCC_SUB_1.35V";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+			};
+
+			buck7_reg: BUCK7 {
+				regulator-name = "VCC_SUB_2.0V";
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-always-on;
+			};
+
+			buck8_reg: BUCK8 {
+				regulator-name = "VMEM_VDDF_3.0V";
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
+			};
+
+			buck9_reg: BUCK9 {
+				regulator-name = "CAM_ISP_CORE_1.2V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1200000>;
+			};
+		};
+	};
+};
+
+&i2c_8 {
+	status = "okay";
+};
+
+&i2s0 {
+	pinctrl-0 = <&i2s0_bus>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&mixer {
+	status = "okay";
+};
+
+&mshc_0 {
+	broken-cd;
+	non-removable;
+	card-detect-delay = <200>;
+	vmmc-supply = <&ldo22_reg>;
+	clock-frequency = <400000000>;
+	samsung,dw-mshc-ciu-div = <0>;
+	samsung,dw-mshc-sdr-timing = <2 3>;
+	samsung,dw-mshc-ddr-timing = <1 2>;
+	pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
+	pinctrl-names = "default";
+	status = "okay";
+	bus-width = <8>;
+	cap-mmc-highspeed;
+};
+
+&pmu_system_controller {
+	assigned-clocks = <&pmu_system_controller 0>;
+	assigned-clock-parents =  <&clock CLK_XUSBXTI>;
+};
+
+&pinctrl_0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sleep0>;
+
+	mhl_int: mhl-int {
+		samsung,pins = "gpf3-5";
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+	};
+
+	i2c_mhl_bus: i2c-mhl-bus {
+		samsung,pins = "gpf0-4", "gpf0-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	sleep0: sleep-states {
+		PIN_SLP(gpa0-0, INPUT, NONE);
+		PIN_SLP(gpa0-1, OUT0, NONE);
+		PIN_SLP(gpa0-2, INPUT, NONE);
+		PIN_SLP(gpa0-3, INPUT, UP);
+		PIN_SLP(gpa0-4, INPUT, NONE);
+		PIN_SLP(gpa0-5, INPUT, DOWN);
+		PIN_SLP(gpa0-6, INPUT, DOWN);
+		PIN_SLP(gpa0-7, INPUT, UP);
+
+		PIN_SLP(gpa1-0, INPUT, DOWN);
+		PIN_SLP(gpa1-1, INPUT, DOWN);
+		PIN_SLP(gpa1-2, INPUT, DOWN);
+		PIN_SLP(gpa1-3, INPUT, DOWN);
+		PIN_SLP(gpa1-4, INPUT, DOWN);
+		PIN_SLP(gpa1-5, INPUT, DOWN);
+
+		PIN_SLP(gpb-0, INPUT, NONE);
+		PIN_SLP(gpb-1, INPUT, NONE);
+		PIN_SLP(gpb-2, INPUT, NONE);
+		PIN_SLP(gpb-3, INPUT, NONE);
+		PIN_SLP(gpb-4, INPUT, DOWN);
+		PIN_SLP(gpb-5, INPUT, UP);
+		PIN_SLP(gpb-6, INPUT, DOWN);
+		PIN_SLP(gpb-7, INPUT, DOWN);
+
+		PIN_SLP(gpc0-0, INPUT, DOWN);
+		PIN_SLP(gpc0-1, INPUT, DOWN);
+		PIN_SLP(gpc0-2, INPUT, DOWN);
+		PIN_SLP(gpc0-3, INPUT, DOWN);
+		PIN_SLP(gpc0-4, INPUT, DOWN);
+
+		PIN_SLP(gpc1-0, INPUT, NONE);
+		PIN_SLP(gpc1-1, PREV, NONE);
+		PIN_SLP(gpc1-2, INPUT, NONE);
+		PIN_SLP(gpc1-3, INPUT, NONE);
+		PIN_SLP(gpc1-4, INPUT, NONE);
+
+		PIN_SLP(gpd0-0, INPUT, DOWN);
+		PIN_SLP(gpd0-1, INPUT, DOWN);
+		PIN_SLP(gpd0-2, INPUT, NONE);
+		PIN_SLP(gpd0-3, INPUT, NONE);
+
+		PIN_SLP(gpd1-0, INPUT, DOWN);
+		PIN_SLP(gpd1-1, INPUT, DOWN);
+		PIN_SLP(gpd1-2, INPUT, NONE);
+		PIN_SLP(gpd1-3, INPUT, NONE);
+
+		PIN_SLP(gpf0-0, INPUT, NONE);
+		PIN_SLP(gpf0-1, INPUT, NONE);
+		PIN_SLP(gpf0-2, INPUT, DOWN);
+		PIN_SLP(gpf0-3, INPUT, DOWN);
+		PIN_SLP(gpf0-4, INPUT, NONE);
+		PIN_SLP(gpf0-5, INPUT, DOWN);
+		PIN_SLP(gpf0-6, INPUT, NONE);
+		PIN_SLP(gpf0-7, INPUT, DOWN);
+
+		PIN_SLP(gpf1-0, INPUT, DOWN);
+		PIN_SLP(gpf1-1, INPUT, DOWN);
+		PIN_SLP(gpf1-2, INPUT, DOWN);
+		PIN_SLP(gpf1-3, INPUT, DOWN);
+		PIN_SLP(gpf1-4, INPUT, NONE);
+		PIN_SLP(gpf1-5, INPUT, NONE);
+		PIN_SLP(gpf1-6, INPUT, DOWN);
+		PIN_SLP(gpf1-7, PREV, NONE);
+
+		PIN_SLP(gpf2-0, PREV, NONE);
+		PIN_SLP(gpf2-1, INPUT, DOWN);
+		PIN_SLP(gpf2-2, INPUT, DOWN);
+		PIN_SLP(gpf2-3, INPUT, DOWN);
+		PIN_SLP(gpf2-4, INPUT, DOWN);
+		PIN_SLP(gpf2-5, INPUT, DOWN);
+		PIN_SLP(gpf2-6, INPUT, NONE);
+		PIN_SLP(gpf2-7, INPUT, NONE);
+
+		PIN_SLP(gpf3-0, INPUT, NONE);
+		PIN_SLP(gpf3-1, PREV, NONE);
+		PIN_SLP(gpf3-2, PREV, NONE);
+		PIN_SLP(gpf3-3, PREV, NONE);
+		PIN_SLP(gpf3-4, OUT1, NONE);
+		PIN_SLP(gpf3-5, INPUT, DOWN);
+
+		PIN_SLP(gpj0-0, PREV, NONE);
+		PIN_SLP(gpj0-1, PREV, NONE);
+		PIN_SLP(gpj0-2, PREV, NONE);
+		PIN_SLP(gpj0-3, INPUT, DOWN);
+		PIN_SLP(gpj0-4, PREV, NONE);
+		PIN_SLP(gpj0-5, PREV, NONE);
+		PIN_SLP(gpj0-6, INPUT, DOWN);
+		PIN_SLP(gpj0-7, INPUT, DOWN);
+
+		PIN_SLP(gpj1-0, INPUT, DOWN);
+		PIN_SLP(gpj1-1, PREV, NONE);
+		PIN_SLP(gpj1-2, PREV, NONE);
+		PIN_SLP(gpj1-3, INPUT, DOWN);
+		PIN_SLP(gpj1-4, INPUT, DOWN);
+	};
+};
+
+&pinctrl_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sleep1>;
+
+	hdmi_hpd: hdmi-hpd {
+		samsung,pins = "gpx3-7";
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+	};
+
+	sleep1: sleep-states {
+		PIN_SLP(gpk0-0, PREV, NONE);
+		PIN_SLP(gpk0-1, PREV, NONE);
+		PIN_SLP(gpk0-2, OUT0, NONE);
+		PIN_SLP(gpk0-3, PREV, NONE);
+		PIN_SLP(gpk0-4, PREV, NONE);
+		PIN_SLP(gpk0-5, PREV, NONE);
+		PIN_SLP(gpk0-6, PREV, NONE);
+
+		PIN_SLP(gpk1-0, INPUT, DOWN);
+		PIN_SLP(gpk1-1, INPUT, DOWN);
+		PIN_SLP(gpk1-2, INPUT, DOWN);
+		PIN_SLP(gpk1-3, PREV, NONE);
+		PIN_SLP(gpk1-4, PREV, NONE);
+		PIN_SLP(gpk1-5, PREV, NONE);
+		PIN_SLP(gpk1-6, PREV, NONE);
+
+		PIN_SLP(gpk2-0, INPUT, DOWN);
+		PIN_SLP(gpk2-1, INPUT, DOWN);
+		PIN_SLP(gpk2-2, INPUT, DOWN);
+		PIN_SLP(gpk2-3, INPUT, DOWN);
+		PIN_SLP(gpk2-4, INPUT, DOWN);
+		PIN_SLP(gpk2-5, INPUT, DOWN);
+		PIN_SLP(gpk2-6, INPUT, DOWN);
+
+		PIN_SLP(gpk3-0, OUT0, NONE);
+		PIN_SLP(gpk3-1, INPUT, NONE);
+		PIN_SLP(gpk3-2, INPUT, DOWN);
+		PIN_SLP(gpk3-3, INPUT, NONE);
+		PIN_SLP(gpk3-4, INPUT, NONE);
+		PIN_SLP(gpk3-5, INPUT, NONE);
+		PIN_SLP(gpk3-6, INPUT, NONE);
+
+		PIN_SLP(gpl0-0, INPUT, DOWN);
+		PIN_SLP(gpl0-1, INPUT, DOWN);
+		PIN_SLP(gpl0-2, INPUT, DOWN);
+		PIN_SLP(gpl0-3, INPUT, DOWN);
+		PIN_SLP(gpl0-4, PREV, NONE);
+		PIN_SLP(gpl0-6, PREV, NONE);
+
+		PIN_SLP(gpl1-0, INPUT, DOWN);
+		PIN_SLP(gpl1-1, INPUT, DOWN);
+		PIN_SLP(gpl2-0, INPUT, DOWN);
+		PIN_SLP(gpl2-1, INPUT, DOWN);
+		PIN_SLP(gpl2-2, INPUT, DOWN);
+		PIN_SLP(gpl2-3, INPUT, DOWN);
+		PIN_SLP(gpl2-4, INPUT, DOWN);
+		PIN_SLP(gpl2-5, INPUT, DOWN);
+		PIN_SLP(gpl2-6, PREV, NONE);
+		PIN_SLP(gpl2-7, INPUT, DOWN);
+
+		PIN_SLP(gpm0-0, INPUT, DOWN);
+		PIN_SLP(gpm0-1, INPUT, DOWN);
+		PIN_SLP(gpm0-2, INPUT, DOWN);
+		PIN_SLP(gpm0-3, INPUT, DOWN);
+		PIN_SLP(gpm0-4, INPUT, DOWN);
+		PIN_SLP(gpm0-5, INPUT, DOWN);
+		PIN_SLP(gpm0-6, INPUT, DOWN);
+		PIN_SLP(gpm0-7, INPUT, DOWN);
+
+		PIN_SLP(gpm1-0, INPUT, DOWN);
+		PIN_SLP(gpm1-1, INPUT, DOWN);
+		PIN_SLP(gpm1-2, INPUT, NONE);
+		PIN_SLP(gpm1-3, INPUT, NONE);
+		PIN_SLP(gpm1-4, INPUT, NONE);
+		PIN_SLP(gpm1-5, INPUT, NONE);
+		PIN_SLP(gpm1-6, INPUT, DOWN);
+
+		PIN_SLP(gpm2-0, INPUT, NONE);
+		PIN_SLP(gpm2-1, INPUT, NONE);
+		PIN_SLP(gpm2-2, INPUT, DOWN);
+		PIN_SLP(gpm2-3, INPUT, DOWN);
+		PIN_SLP(gpm2-4, INPUT, DOWN);
+
+		PIN_SLP(gpm3-0, PREV, NONE);
+		PIN_SLP(gpm3-1, PREV, NONE);
+		PIN_SLP(gpm3-2, PREV, NONE);
+		PIN_SLP(gpm3-3, OUT1, NONE);
+		PIN_SLP(gpm3-4, INPUT, DOWN);
+		PIN_SLP(gpm3-5, INPUT, DOWN);
+		PIN_SLP(gpm3-6, INPUT, DOWN);
+		PIN_SLP(gpm3-7, INPUT, DOWN);
+
+		PIN_SLP(gpm4-0, INPUT, DOWN);
+		PIN_SLP(gpm4-1, INPUT, DOWN);
+		PIN_SLP(gpm4-2, INPUT, DOWN);
+		PIN_SLP(gpm4-3, INPUT, DOWN);
+		PIN_SLP(gpm4-4, INPUT, DOWN);
+		PIN_SLP(gpm4-5, INPUT, DOWN);
+		PIN_SLP(gpm4-6, INPUT, DOWN);
+		PIN_SLP(gpm4-7, INPUT, DOWN);
+
+		PIN_SLP(gpy0-0, INPUT, DOWN);
+		PIN_SLP(gpy0-1, INPUT, DOWN);
+		PIN_SLP(gpy0-2, INPUT, DOWN);
+		PIN_SLP(gpy0-3, INPUT, DOWN);
+		PIN_SLP(gpy0-4, INPUT, DOWN);
+		PIN_SLP(gpy0-5, INPUT, DOWN);
+
+		PIN_SLP(gpy1-0, INPUT, DOWN);
+		PIN_SLP(gpy1-1, INPUT, DOWN);
+		PIN_SLP(gpy1-2, INPUT, DOWN);
+		PIN_SLP(gpy1-3, INPUT, DOWN);
+
+		PIN_SLP(gpy2-0, PREV, NONE);
+		PIN_SLP(gpy2-1, INPUT, DOWN);
+		PIN_SLP(gpy2-2, INPUT, NONE);
+		PIN_SLP(gpy2-3, INPUT, NONE);
+		PIN_SLP(gpy2-4, INPUT, NONE);
+		PIN_SLP(gpy2-5, INPUT, NONE);
+
+		PIN_SLP(gpy3-0, INPUT, DOWN);
+		PIN_SLP(gpy3-1, INPUT, DOWN);
+		PIN_SLP(gpy3-2, INPUT, DOWN);
+		PIN_SLP(gpy3-3, INPUT, DOWN);
+		PIN_SLP(gpy3-4, INPUT, DOWN);
+		PIN_SLP(gpy3-5, INPUT, DOWN);
+		PIN_SLP(gpy3-6, INPUT, DOWN);
+		PIN_SLP(gpy3-7, INPUT, DOWN);
+
+		PIN_SLP(gpy4-0, INPUT, DOWN);
+		PIN_SLP(gpy4-1, INPUT, DOWN);
+		PIN_SLP(gpy4-2, INPUT, DOWN);
+		PIN_SLP(gpy4-3, INPUT, DOWN);
+		PIN_SLP(gpy4-4, INPUT, DOWN);
+		PIN_SLP(gpy4-5, INPUT, DOWN);
+		PIN_SLP(gpy4-6, INPUT, DOWN);
+		PIN_SLP(gpy4-7, INPUT, DOWN);
+
+		PIN_SLP(gpy5-0, INPUT, DOWN);
+		PIN_SLP(gpy5-1, INPUT, DOWN);
+		PIN_SLP(gpy5-2, INPUT, DOWN);
+		PIN_SLP(gpy5-3, INPUT, DOWN);
+		PIN_SLP(gpy5-4, INPUT, DOWN);
+		PIN_SLP(gpy5-5, INPUT, DOWN);
+		PIN_SLP(gpy5-6, INPUT, DOWN);
+		PIN_SLP(gpy5-7, INPUT, DOWN);
+
+		PIN_SLP(gpy6-0, INPUT, DOWN);
+		PIN_SLP(gpy6-1, INPUT, DOWN);
+		PIN_SLP(gpy6-2, INPUT, DOWN);
+		PIN_SLP(gpy6-3, INPUT, DOWN);
+		PIN_SLP(gpy6-4, INPUT, DOWN);
+		PIN_SLP(gpy6-5, INPUT, DOWN);
+		PIN_SLP(gpy6-6, INPUT, DOWN);
+		PIN_SLP(gpy6-7, INPUT, DOWN);
+	};
+};
+
+&pinctrl_2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sleep2>;
+
+	sleep2: sleep-states {
+		PIN_SLP(gpz-0, INPUT, DOWN);
+		PIN_SLP(gpz-1, INPUT, DOWN);
+		PIN_SLP(gpz-2, INPUT, DOWN);
+		PIN_SLP(gpz-3, INPUT, DOWN);
+		PIN_SLP(gpz-4, INPUT, DOWN);
+		PIN_SLP(gpz-5, INPUT, DOWN);
+		PIN_SLP(gpz-6, INPUT, DOWN);
+	};
+};
+
+&pinctrl_3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sleep3>;
+
+	sleep3: sleep-states {
+		PIN_SLP(gpv0-0, INPUT, DOWN);
+		PIN_SLP(gpv0-1, INPUT, DOWN);
+		PIN_SLP(gpv0-2, INPUT, DOWN);
+		PIN_SLP(gpv0-3, INPUT, DOWN);
+		PIN_SLP(gpv0-4, INPUT, DOWN);
+		PIN_SLP(gpv0-5, INPUT, DOWN);
+		PIN_SLP(gpv0-6, INPUT, DOWN);
+		PIN_SLP(gpv0-7, INPUT, DOWN);
+
+		PIN_SLP(gpv1-0, INPUT, DOWN);
+		PIN_SLP(gpv1-1, INPUT, DOWN);
+		PIN_SLP(gpv1-2, INPUT, DOWN);
+		PIN_SLP(gpv1-3, INPUT, DOWN);
+		PIN_SLP(gpv1-4, INPUT, DOWN);
+		PIN_SLP(gpv1-5, INPUT, DOWN);
+		PIN_SLP(gpv1-6, INPUT, DOWN);
+		PIN_SLP(gpv1-7, INPUT, DOWN);
+
+		PIN_SLP(gpv2-0, INPUT, DOWN);
+		PIN_SLP(gpv2-1, INPUT, DOWN);
+		PIN_SLP(gpv2-2, INPUT, DOWN);
+		PIN_SLP(gpv2-3, INPUT, DOWN);
+		PIN_SLP(gpv2-4, INPUT, DOWN);
+		PIN_SLP(gpv2-5, INPUT, DOWN);
+		PIN_SLP(gpv2-6, INPUT, DOWN);
+		PIN_SLP(gpv2-7, INPUT, DOWN);
+
+		PIN_SLP(gpv3-0, INPUT, DOWN);
+		PIN_SLP(gpv3-1, INPUT, DOWN);
+		PIN_SLP(gpv3-2, INPUT, DOWN);
+		PIN_SLP(gpv3-3, INPUT, DOWN);
+		PIN_SLP(gpv3-4, INPUT, DOWN);
+		PIN_SLP(gpv3-5, INPUT, DOWN);
+		PIN_SLP(gpv3-6, INPUT, DOWN);
+		PIN_SLP(gpv3-7, INPUT, DOWN);
+
+		PIN_SLP(gpv4-0, INPUT, DOWN);
+	};
+};
+
+&pwm {
+	pinctrl-0 = <&pwm0_out>;
+	pinctrl-names = "default";
+	samsung,pwm-outputs = <0>;
+	status = "okay";
+};
+
+&rtc {
+	status = "okay";
+	clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
+	clock-names = "rtc", "rtc_src";
+};
+
+&sdhci_2 {
+	bus-width = <4>;
+	cd-gpios = <&gpx3 4 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
+	pinctrl-names = "default";
+	vmmc-supply = <&ldo21_reg>;
+	status = "okay";
+};
+
+&sdhci_3 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	non-removable;
+	bus-width = <4>;
+
+	mmc-pwrseq = <&wlan_pwrseq>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4>;
+	status = "okay";
+
+	brcmf: wifi@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&gpx2>;
+		interrupts = <5 IRQ_TYPE_NONE>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&serial_0 {
+	status = "okay";
+};
+
+&serial_1 {
+	status = "okay";
+};
+
+&serial_2 {
+	status = "okay";
+};
+
+&serial_3 {
+	status = "okay";
+};
+
+&spi_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi1_bus>;
+	cs-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	s5c73m3_spi: s5c73m3@0 {
+		compatible = "samsung,s5c73m3";
+		spi-max-frequency = <50000000>;
+		reg = <0>;
+		controller-data {
+			samsung,spi-feedback-delay = <2>;
+		};
+	};
+};
+
+&tmu {
+	vtmu-supply = <&ldo10_reg>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4412-n710x.dts b/arch/arm/boot/dts/exynos4412-n710x.dts
new file mode 100644
index 000000000000..7d289c257920
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4412-n710x.dts
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+#include "exynos4412-midas.dtsi"
+
+/ {
+	compatible = "samsung,n710x", "samsung,midas", "samsung,exynos4412", "samsung,exynos4";
+	model = "Samsung Galaxy Note 2 (GT-N7100, GT-N7105) based on Exynos4412";
+
+	memory@40000000 {
+		device_type = "memory";
+		reg =  <0x40000000 0x80000000>;
+	};
+
+	/* bootargs are passed in by bootloader */
+
+	regulators {
+		cam_vdda_reg: voltage-regulator-9 {
+			compatible = "regulator-fixed";
+			regulator-name = "CAM_SENSOR_CORE_1.2V";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			gpio = <&gpm4 1 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+	};
+};
+
+&buck9_reg {
+	maxim,ena-gpios = <&gpm1 0 GPIO_ACTIVE_HIGH>;
+};
+
+&cam_af_reg {
+	gpio = <&gpm1 1 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&cam_io_reg {
+	gpio = <&gpm0 7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&ldo13_reg {
+	regulator-name = "VCC_1.8V_LCD";
+	regulator-always-on;
+};
+
+&ldo25_reg {
+	regulator-name = "VCI_3.0V_LCD";
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+};
+
+&s5c73m3 {
+	standby-gpios = <&gpm0 6 GPIO_ACTIVE_LOW>;   /* ISP_STANDBY */
+	vdda-supply = <&cam_vdda_reg>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 556ea78b8e32..d7ad07fd48f9 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -61,12 +61,6 @@
 		reset-gpios = <&gpk1 2 GPIO_ACTIVE_LOW>;
 	};
 
-	camera {
-		status = "okay";
-		pinctrl-names = "default";
-		pinctrl-0 = <>;
-	};
-
 	fixed-rate-clocks {
 		xxti {
 			compatible = "samsung,clock-xxti";
@@ -142,6 +136,12 @@
 	status = "okay";
 };
 
+&camera {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <>;
+};
+
 &clock_audss {
 	assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
 			<&clock_audss EXYNOS_MOUT_I2S>,
diff --git a/arch/arm/boot/dts/exynos4412-pinctrl.dtsi b/arch/arm/boot/dts/exynos4412-pinctrl.dtsi
index e8dd5f2d976f..d7d5fdc230d8 100644
--- a/arch/arm/boot/dts/exynos4412-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4412-pinctrl.dtsi
@@ -18,964 +18,962 @@
 		samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_ ##_pull>;	\
 	}
 
-/ {
-	pinctrl_0: pinctrl@11400000 {
-		gpa0: gpa0 {
-			gpio-controller;
-			#gpio-cells = <2>;
+&pinctrl_0 {
+	gpa0: gpa0 {
+		gpio-controller;
+		#gpio-cells = <2>;
 
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpa1: gpa1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpb: gpb {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpc0: gpc0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpc1: gpc1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpd0: gpd0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpd1: gpd1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf0: gpf0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf1: gpf1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf2: gpf2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpf3: gpf3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpj0: gpj0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpj1: gpj1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		uart0_data: uart0-data {
-			samsung,pins = "gpa0-0", "gpa0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart0_fctl: uart0-fctl {
-			samsung,pins = "gpa0-2", "gpa0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart1_data: uart1-data {
-			samsung,pins = "gpa0-4", "gpa0-5";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart1_fctl: uart1-fctl {
-			samsung,pins = "gpa0-6", "gpa0-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c2_bus: i2c2-bus {
-			samsung,pins = "gpa0-6", "gpa0-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart2_data: uart2-data {
-			samsung,pins = "gpa1-0", "gpa1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart2_fctl: uart2-fctl {
-			samsung,pins = "gpa1-2", "gpa1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart_audio_a: uart-audio-a {
-			samsung,pins = "gpa1-0", "gpa1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c3_bus: i2c3-bus {
-			samsung,pins = "gpa1-2", "gpa1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart3_data: uart3-data {
-			samsung,pins = "gpa1-4", "gpa1-5";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		uart_audio_b: uart-audio-b {
-			samsung,pins = "gpa1-4", "gpa1-5";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spi0_bus: spi0-bus {
-			samsung,pins = "gpb-0", "gpb-2", "gpb-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c4_bus: i2c4-bus {
-			samsung,pins = "gpb-0", "gpb-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spi1_bus: spi1-bus {
-			samsung,pins = "gpb-4", "gpb-6", "gpb-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c5_bus: i2c5-bus {
-			samsung,pins = "gpb-2", "gpb-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2s1_bus: i2s1-bus {
-			samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
-					"gpc0-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pcm1_bus: pcm1-bus {
-			samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
-					"gpc0-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		ac97_bus: ac97-bus {
-			samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
-					"gpc0-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2s2_bus: i2s2-bus {
-			samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
-					"gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pcm2_bus: pcm2-bus {
-			samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
-					"gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spdif_bus: spdif-bus {
-			samsung,pins = "gpc1-0", "gpc1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c6_bus: i2c6-bus {
-			samsung,pins = "gpc1-3", "gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		spi2_bus: spi2-bus {
-			samsung,pins = "gpc1-1", "gpc1-3", "gpc1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm0_out: pwm0-out {
-			samsung,pins = "gpd0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm1_out: pwm1-out {
-			samsung,pins = "gpd0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_ctrl: lcd-ctrl {
-			samsung,pins = "gpd0-0", "gpd0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c7_bus: i2c7-bus {
-			samsung,pins = "gpd0-2", "gpd0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm2_out: pwm2-out {
-			samsung,pins = "gpd0-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pwm3_out: pwm3-out {
-			samsung,pins = "gpd0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c0_bus: i2c0-bus {
-			samsung,pins = "gpd1-0", "gpd1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		mipi0_clk: mipi0-clk {
-			samsung,pins = "gpd1-0", "gpd1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		i2c1_bus: i2c1-bus {
-			samsung,pins = "gpd1-2", "gpd1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		mipi1_clk: mipi1-clk {
-			samsung,pins = "gpd1-2", "gpd1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_clk: lcd-clk {
-			samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_data16: lcd-data-width16 {
-			samsung,pins = "gpf0-7", "gpf1-0", "gpf1-1", "gpf1-2",
-					"gpf1-3", "gpf1-6", "gpf1-7", "gpf2-0",
-					"gpf2-1", "gpf2-2", "gpf2-3", "gpf2-7",
-					"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_data18: lcd-data-width18 {
-			samsung,pins = "gpf0-6", "gpf0-7", "gpf1-0", "gpf1-1",
-					"gpf1-2", "gpf1-3", "gpf1-6", "gpf1-7",
-					"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
-					"gpf2-6", "gpf2-7", "gpf3-0", "gpf3-1",
-					"gpf3-2", "gpf3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_data24: lcd-data-width24 {
-			samsung,pins = "gpf0-4", "gpf0-5", "gpf0-6", "gpf0-7",
-					"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3",
-					"gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7",
-					"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
-					"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
-					"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		lcd_ldi: lcd-ldi {
-			samsung,pins = "gpf3-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		cam_port_a_io: cam-port-a-io {
-			samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
-					"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
-					"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		cam_port_a_clk_active: cam-port-a-clk-active {
-			samsung,pins = "gpj1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		cam_port_a_clk_idle: cam-port-a-clk-idle {
-			samsung,pins = "gpj1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-	};
-
-	pinctrl_1: pinctrl@11000000 {
-		gpk0: gpk0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk1: gpk1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk2: gpk2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpk3: gpk3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpl0: gpl0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpl1: gpl1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpl2: gpl2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpm0: gpm0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpm1: gpm1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpm2: gpm2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpm3: gpm3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpm4: gpm4 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpy0: gpy0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy1: gpy1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy2: gpy2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy3: gpy3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy4: gpy4 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy5: gpy5 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpy6: gpy6 {
-			gpio-controller;
-			#gpio-cells = <2>;
-		};
-
-		gpx0: gpx0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-			#interrupt-cells = <2>;
-		};
-
-		gpx1: gpx1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			interrupt-parent = <&gic>;
-			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-			#interrupt-cells = <2>;
-		};
-
-		gpx2: gpx2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpx3: gpx3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		sd0_clk: sd0-clk {
-			samsung,pins = "gpk0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_cmd: sd0-cmd {
-			samsung,pins = "gpk0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_cd: sd0-cd {
-			samsung,pins = "gpk0-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_bus1: sd0-bus-width1 {
-			samsung,pins = "gpk0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_bus4: sd0-bus-width4 {
-			samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd0_bus8: sd0-bus-width8 {
-			samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_clk: sd4-clk {
-			samsung,pins = "gpk0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_cmd: sd4-cmd {
-			samsung,pins = "gpk0-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_cd: sd4-cd {
-			samsung,pins = "gpk0-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_bus1: sd4-bus-width1 {
-			samsung,pins = "gpk0-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_bus4: sd4-bus-width4 {
-			samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd4_bus8: sd4-bus-width8 {
-			samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_clk: sd1-clk {
-			samsung,pins = "gpk1-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_cmd: sd1-cmd {
-			samsung,pins = "gpk1-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_cd: sd1-cd {
-			samsung,pins = "gpk1-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_bus1: sd1-bus-width1 {
-			samsung,pins = "gpk1-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd1_bus4: sd1-bus-width4 {
-			samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_clk: sd2-clk {
-			samsung,pins = "gpk2-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_cmd: sd2-cmd {
-			samsung,pins = "gpk2-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_cd: sd2-cd {
-			samsung,pins = "gpk2-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_bus1: sd2-bus-width1 {
-			samsung,pins = "gpk2-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_bus4: sd2-bus-width4 {
-			samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd2_bus8: sd2-bus-width8 {
-			samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_clk: sd3-clk {
-			samsung,pins = "gpk3-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_cmd: sd3-cmd {
-			samsung,pins = "gpk3-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_cd: sd3-cd {
-			samsung,pins = "gpk3-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_bus1: sd3-bus-width1 {
-			samsung,pins = "gpk3-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		sd3_bus4: sd3-bus-width4 {
-			samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		cam_port_b_io: cam-port-b-io {
-			samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
-					"gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
-					"gpm1-0", "gpm1-1", "gpm2-0", "gpm2-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		cam_port_b_clk_active: cam-port-b-clk-active {
-			samsung,pins = "gpm2-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
-		};
-
-		cam_port_b_clk_idle: cam-port-b-clk-idle {
-			samsung,pins = "gpm2-2";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint0: ext-int0 {
-			samsung,pins = "gpx0-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint8: ext-int8 {
-			samsung,pins = "gpx1-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint15: ext-int15 {
-			samsung,pins = "gpx1-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint16: ext-int16 {
-			samsung,pins = "gpx2-0";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		eint31: ext-int31 {
-			samsung,pins = "gpx3-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		fimc_is_i2c0: fimc-is-i2c0 {
-			samsung,pins = "gpm4-0", "gpm4-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		fimc_is_i2c1: fimc-is-i2c1 {
-			samsung,pins = "gpm4-2", "gpm4-3";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		fimc_is_uart: fimc-is-uart {
-			samsung,pins = "gpm3-5", "gpm3-7";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		hdmi_cec: hdmi-cec {
-			samsung,pins = "gpx3-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-	};
-
-	pinctrl_2: pinctrl@3860000 {
-		gpz: gpz {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		i2s0_bus: i2s0-bus {
-			samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
-					"gpz-4", "gpz-5", "gpz-6";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-
-		pcm0_bus: pcm0-bus {
-			samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
-					"gpz-4";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
-	};
-
-	pinctrl_3: pinctrl@106e0000 {
-		gpv0: gpv0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpv1: gpv1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpv2: gpv2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpv3: gpv3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		gpv4: gpv4 {
-			gpio-controller;
-			#gpio-cells = <2>;
-
-			interrupt-controller;
-			#interrupt-cells = <2>;
-		};
-
-		c2c_bus: c2c-bus {
-			samsung,pins = "gpv0-0", "gpv0-1", "gpv0-2", "gpv0-3",
-					"gpv0-4", "gpv0-5", "gpv0-6", "gpv0-7",
-					"gpv1-0", "gpv1-1", "gpv1-2", "gpv1-3",
-					"gpv1-4", "gpv1-5", "gpv1-6", "gpv1-7",
-					"gpv2-0", "gpv2-1", "gpv2-2", "gpv2-3",
-					"gpv2-4", "gpv2-5", "gpv2-6", "gpv2-7",
-					"gpv3-0", "gpv3-1", "gpv3-2", "gpv3-3",
-					"gpv3-4", "gpv3-5", "gpv3-6", "gpv3-7",
-					"gpv4-0", "gpv4-1";
-			samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-			samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-			samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-		};
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpa1: gpa1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb: gpb {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpc0: gpc0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpc1: gpc1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd0: gpd0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd1: gpd1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf0: gpf0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf1: gpf1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf2: gpf2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf3: gpf3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpj0: gpj0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpj1: gpj1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	uart0_data: uart0-data {
+		samsung,pins = "gpa0-0", "gpa0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart0_fctl: uart0-fctl {
+		samsung,pins = "gpa0-2", "gpa0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart1_data: uart1-data {
+		samsung,pins = "gpa0-4", "gpa0-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart1_fctl: uart1-fctl {
+		samsung,pins = "gpa0-6", "gpa0-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c2_bus: i2c2-bus {
+		samsung,pins = "gpa0-6", "gpa0-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart2_data: uart2-data {
+		samsung,pins = "gpa1-0", "gpa1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart2_fctl: uart2-fctl {
+		samsung,pins = "gpa1-2", "gpa1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart_audio_a: uart-audio-a {
+		samsung,pins = "gpa1-0", "gpa1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c3_bus: i2c3-bus {
+		samsung,pins = "gpa1-2", "gpa1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart3_data: uart3-data {
+		samsung,pins = "gpa1-4", "gpa1-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart_audio_b: uart-audio-b {
+		samsung,pins = "gpa1-4", "gpa1-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi0_bus: spi0-bus {
+		samsung,pins = "gpb-0", "gpb-2", "gpb-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c4_bus: i2c4-bus {
+		samsung,pins = "gpb-0", "gpb-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi1_bus: spi1-bus {
+		samsung,pins = "gpb-4", "gpb-6", "gpb-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c5_bus: i2c5-bus {
+		samsung,pins = "gpb-2", "gpb-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2s1_bus: i2s1-bus {
+		samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+				"gpc0-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pcm1_bus: pcm1-bus {
+		samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+				"gpc0-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	ac97_bus: ac97-bus {
+		samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+				"gpc0-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2s2_bus: i2s2-bus {
+		samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
+				"gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pcm2_bus: pcm2-bus {
+		samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
+				"gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spdif_bus: spdif-bus {
+		samsung,pins = "gpc1-0", "gpc1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c6_bus: i2c6-bus {
+		samsung,pins = "gpc1-3", "gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi2_bus: spi2-bus {
+		samsung,pins = "gpc1-1", "gpc1-3", "gpc1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_5>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm0_out: pwm0-out {
+		samsung,pins = "gpd0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm1_out: pwm1-out {
+		samsung,pins = "gpd0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_ctrl: lcd-ctrl {
+		samsung,pins = "gpd0-0", "gpd0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c7_bus: i2c7-bus {
+		samsung,pins = "gpd0-2", "gpd0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm2_out: pwm2-out {
+		samsung,pins = "gpd0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pwm3_out: pwm3-out {
+		samsung,pins = "gpd0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c0_bus: i2c0-bus {
+		samsung,pins = "gpd1-0", "gpd1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	mipi0_clk: mipi0-clk {
+		samsung,pins = "gpd1-0", "gpd1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	i2c1_bus: i2c1-bus {
+		samsung,pins = "gpd1-2", "gpd1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	mipi1_clk: mipi1-clk {
+		samsung,pins = "gpd1-2", "gpd1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_clk: lcd-clk {
+		samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_data16: lcd-data-width16 {
+		samsung,pins = "gpf0-7", "gpf1-0", "gpf1-1", "gpf1-2",
+				"gpf1-3", "gpf1-6", "gpf1-7", "gpf2-0",
+				"gpf2-1", "gpf2-2", "gpf2-3", "gpf2-7",
+				"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_data18: lcd-data-width18 {
+		samsung,pins = "gpf0-6", "gpf0-7", "gpf1-0", "gpf1-1",
+				"gpf1-2", "gpf1-3", "gpf1-6", "gpf1-7",
+				"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
+				"gpf2-6", "gpf2-7", "gpf3-0", "gpf3-1",
+				"gpf3-2", "gpf3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_data24: lcd-data-width24 {
+		samsung,pins = "gpf0-4", "gpf0-5", "gpf0-6", "gpf0-7",
+				"gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3",
+				"gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7",
+				"gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
+				"gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7",
+				"gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	lcd_ldi: lcd-ldi {
+		samsung,pins = "gpf3-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	cam_port_a_io: cam-port-a-io {
+		samsung,pins = "gpj0-0", "gpj0-1", "gpj0-2", "gpj0-3",
+				"gpj0-4", "gpj0-5", "gpj0-6", "gpj0-7",
+				"gpj1-0", "gpj1-1", "gpj1-2", "gpj1-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	cam_port_a_clk_active: cam-port-a-clk-active {
+		samsung,pins = "gpj1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	cam_port_a_clk_idle: cam-port-a-clk-idle {
+		samsung,pins = "gpj1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+};
+
+&pinctrl_1 {
+	gpk0: gpk0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk1: gpk1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk2: gpk2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpk3: gpk3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpl0: gpl0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpl1: gpl1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpl2: gpl2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpm0: gpm0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpm1: gpm1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpm2: gpm2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpm3: gpm3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpm4: gpm4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpy0: gpy0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy1: gpy1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy2: gpy2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy3: gpy3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy4: gpy4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy5: gpy5 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpy6: gpy6 {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	gpx0: gpx0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <2>;
+	};
+
+	gpx1: gpx1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <2>;
+	};
+
+	gpx2: gpx2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpx3: gpx3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	sd0_clk: sd0-clk {
+		samsung,pins = "gpk0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_cmd: sd0-cmd {
+		samsung,pins = "gpk0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_cd: sd0-cd {
+		samsung,pins = "gpk0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_bus1: sd0-bus-width1 {
+		samsung,pins = "gpk0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_bus4: sd0-bus-width4 {
+		samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd0_bus8: sd0-bus-width8 {
+		samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_clk: sd4-clk {
+		samsung,pins = "gpk0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_cmd: sd4-cmd {
+		samsung,pins = "gpk0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_cd: sd4-cd {
+		samsung,pins = "gpk0-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_bus1: sd4-bus-width1 {
+		samsung,pins = "gpk0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_bus4: sd4-bus-width4 {
+		samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd4_bus8: sd4-bus-width8 {
+		samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_4>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_clk: sd1-clk {
+		samsung,pins = "gpk1-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_cmd: sd1-cmd {
+		samsung,pins = "gpk1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_cd: sd1-cd {
+		samsung,pins = "gpk1-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_bus1: sd1-bus-width1 {
+		samsung,pins = "gpk1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd1_bus4: sd1-bus-width4 {
+		samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_clk: sd2-clk {
+		samsung,pins = "gpk2-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_cmd: sd2-cmd {
+		samsung,pins = "gpk2-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_cd: sd2-cd {
+		samsung,pins = "gpk2-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_bus1: sd2-bus-width1 {
+		samsung,pins = "gpk2-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_bus4: sd2-bus-width4 {
+		samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd2_bus8: sd2-bus-width8 {
+		samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_clk: sd3-clk {
+		samsung,pins = "gpk3-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_cmd: sd3-cmd {
+		samsung,pins = "gpk3-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_cd: sd3-cd {
+		samsung,pins = "gpk3-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_bus1: sd3-bus-width1 {
+		samsung,pins = "gpk3-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	sd3_bus4: sd3-bus-width4 {
+		samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	cam_port_b_io: cam-port-b-io {
+		samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
+				"gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
+				"gpm1-0", "gpm1-1", "gpm2-0", "gpm2-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	cam_port_b_clk_active: cam-port-b-clk-active {
+		samsung,pins = "gpm2-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;
+	};
+
+	cam_port_b_clk_idle: cam-port-b-clk-idle {
+		samsung,pins = "gpm2-2";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint0: ext-int0 {
+		samsung,pins = "gpx0-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint8: ext-int8 {
+		samsung,pins = "gpx1-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint15: ext-int15 {
+		samsung,pins = "gpx1-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint16: ext-int16 {
+		samsung,pins = "gpx2-0";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	eint31: ext-int31 {
+		samsung,pins = "gpx3-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_F>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	fimc_is_i2c0: fimc-is-i2c0 {
+		samsung,pins = "gpm4-0", "gpm4-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	fimc_is_i2c1: fimc-is-i2c1 {
+		samsung,pins = "gpm4-2", "gpm4-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	fimc_is_uart: fimc-is-uart {
+		samsung,pins = "gpm3-5", "gpm3-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hdmi_cec: hdmi-cec {
+		samsung,pins = "gpx3-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+};
+
+&pinctrl_2 {
+	gpz: gpz {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	i2s0_bus: i2s0-bus {
+		samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
+				"gpz-4", "gpz-5", "gpz-6";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	pcm0_bus: pcm0-bus {
+		samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
+				"gpz-4";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_3>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+};
+
+&pinctrl_3 {
+	gpv0: gpv0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpv1: gpv1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpv2: gpv2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpv3: gpv3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpv4: gpv4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	c2c_bus: c2c-bus {
+		samsung,pins = "gpv0-0", "gpv0-1", "gpv0-2", "gpv0-3",
+				"gpv0-4", "gpv0-5", "gpv0-6", "gpv0-7",
+				"gpv1-0", "gpv1-1", "gpv1-2", "gpv1-3",
+				"gpv1-4", "gpv1-5", "gpv1-6", "gpv1-7",
+				"gpv2-0", "gpv2-1", "gpv2-2", "gpv2-3",
+				"gpv2-4", "gpv2-5", "gpv2-6", "gpv2-7",
+				"gpv3-0", "gpv3-1", "gpv3-2", "gpv3-3",
+				"gpv3-4", "gpv3-5", "gpv3-6", "gpv3-7",
+				"gpv4-0", "gpv4-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
 	};
 };
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
index 5504398e6e37..01f37b5ac9c4 100644
--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * FriendlyARM's Exynos4412 based TINY4412 board device tree source
  *
@@ -5,11 +6,7 @@
  *
  * Device tree source file for FriendlyARM's TINY4412 board which is based on
  * Samsung's Exynos4412 SoC.
- *
- * 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.
-*/
+ */
 
 /dts-v1/;
 #include "exynos4412.dtsi"
diff --git a/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi
index e3f7934d19d0..489b58c619ee 100644
--- a/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi
+++ b/arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Device tree sources for Exynos4412 TMU sensor configuration
  *
  * Copyright (c) 2014 Lukasz Majewski <l.majewski@samsung.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 <dt-bindings/thermal/thermal_exynos.h>
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index f285790e8e04..327ee980d3a5 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Samsung's Exynos4412 based Trats 2 board device tree source
  *
@@ -6,30 +7,14 @@
  *
  * Device tree source file for Samsung's Trats 2 board which is based on
  * Samsung's Exynos4412 SoC.
- *
- * 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.
-*/
+ */
 
 /dts-v1/;
-#include "exynos4412.dtsi"
-#include "exynos4412-ppmu-common.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/clock/maxim,max77686.h>
-#include <dt-bindings/pinctrl/samsung.h>
+#include "exynos4412-galaxy-s3.dtsi"
 
 / {
 	model = "Samsung Trats 2 based on Exynos4412";
-	compatible = "samsung,trats2", "samsung,exynos4412", "samsung,exynos4";
-
-	aliases {
-		i2c9 = &i2c_ak8975;
-		i2c10 = &i2c_cm36651;
-		i2c11 = &i2c_max77693;
-		i2c12 = &i2c_max77693_fuel;
-	};
+	compatible = "samsung,trats2", "samsung,midas", "samsung,exynos4412", "samsung,exynos4";
 
 	memory@40000000 {
 		device_type = "memory";
@@ -38,1378 +23,5 @@
 
 	chosen {
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
-		stdout-path = &serial_2;
-	};
-
-	firmware@204f000 {
-		compatible = "samsung,secure-firmware";
-		reg = <0x0204F000 0x1000>;
-	};
-
-	fixed-rate-clocks {
-		xxti {
-			compatible = "samsung,clock-xxti", "fixed-clock";
-			clock-frequency = <0>;
-		};
-
-		xusbxti {
-			compatible = "samsung,clock-xusbxti", "fixed-clock";
-			clock-frequency = <24000000>;
-		};
-	};
-
-	regulators {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cam_io_reg: voltage-regulator-1 {
-			compatible = "regulator-fixed";
-			regulator-name = "CAM_SENSOR_A";
-			regulator-min-microvolt = <2800000>;
-			regulator-max-microvolt = <2800000>;
-			gpio = <&gpm0 2 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-		};
-
-		lcd_vdd3_reg: voltage-regulator-2 {
-			compatible = "regulator-fixed";
-			regulator-name = "LCD_VDD_2.2V";
-			regulator-min-microvolt = <2200000>;
-			regulator-max-microvolt = <2200000>;
-			gpio = <&gpc0 1 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-		};
-
-		cam_af_reg: voltage-regulator-3 {
-			compatible = "regulator-fixed";
-			regulator-name = "CAM_AF";
-			regulator-min-microvolt = <2800000>;
-			regulator-max-microvolt = <2800000>;
-			gpio = <&gpm0 4 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-		};
-
-		ps_als_reg: voltage-regulator-5 {
-			compatible = "regulator-fixed";
-			regulator-name = "LED_A_3.0V";
-			regulator-min-microvolt = <3000000>;
-			regulator-max-microvolt = <3000000>;
-			gpio = <&gpj0 5 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-		};
-
-		vsil12: voltage-regulator-6 {
-			compatible = "regulator-fixed";
-			regulator-name = "VSIL_1.2V";
-			regulator-min-microvolt = <1200000>;
-			regulator-max-microvolt = <1200000>;
-			gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-			vin-supply = <&buck7_reg>;
-		};
-
-		vcc33mhl: voltage-regulator-7 {
-			compatible = "regulator-fixed";
-			regulator-name = "VCC_3.3_MHL";
-			regulator-min-microvolt = <3300000>;
-			regulator-max-microvolt = <3300000>;
-			gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-		};
-
-		vcc18mhl: voltage-regulator-8 {
-			compatible = "regulator-fixed";
-			regulator-name = "VCC_1.8_MHL";
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
-			enable-active-high;
-		};
-	};
-
-	gpio-keys {
-		compatible = "gpio-keys";
-
-		key-down {
-			gpios = <&gpx3 3 GPIO_ACTIVE_LOW>;
-			linux,code = <114>;
-			label = "volume down";
-			debounce-interval = <10>;
-		};
-
-		key-up {
-			gpios = <&gpx2 2 GPIO_ACTIVE_LOW>;
-			linux,code = <115>;
-			label = "volume up";
-			debounce-interval = <10>;
-		};
-
-		key-power {
-			gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
-			linux,code = <116>;
-			label = "power";
-			debounce-interval = <10>;
-			wakeup-source;
-		};
-
-		key-ok {
-			gpios = <&gpx0 1 GPIO_ACTIVE_LOW>;
-			linux,code = <139>;
-			label = "ok";
-			debounce-inteval = <10>;
-			wakeup-source;
-		};
-	};
-
-	i2c_max77693: i2c-gpio-1 {
-		compatible = "i2c-gpio";
-		gpios = <&gpm2 0 GPIO_ACTIVE_HIGH>, <&gpm2 1 GPIO_ACTIVE_HIGH>;
-		i2c-gpio,delay-us = <2>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "okay";
-
-		max77693@66 {
-			compatible = "maxim,max77693";
-			interrupt-parent = <&gpx1>;
-			interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
-			reg = <0x66>;
-
-			regulators {
-				esafeout1_reg: ESAFEOUT1 {
-					regulator-name = "ESAFEOUT1";
-				};
-				esafeout2_reg: ESAFEOUT2 {
-					regulator-name = "ESAFEOUT2";
-				};
-				charger_reg: CHARGER {
-					regulator-name = "CHARGER";
-					regulator-min-microamp = <60000>;
-					regulator-max-microamp = <2580000>;
-				};
-			};
-
-			max77693_haptic {
-				compatible = "maxim,max77693-haptic";
-				haptic-supply = <&ldo26_reg>;
-				pwms = <&pwm 0 38022 0>;
-			};
-
-			charger {
-				compatible = "maxim,max77693-charger";
-
-				maxim,constant-microvolt = <4350000>;
-				maxim,min-system-microvolt = <3600000>;
-				maxim,thermal-regulation-celsius = <100>;
-				maxim,battery-overcurrent-microamp = <3500000>;
-				maxim,charge-input-threshold-microvolt = <4300000>;
-			};
-		};
-	};
-
-	i2c_max77693_fuel: i2c-gpio-3 {
-		compatible = "i2c-gpio";
-		gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>, <&gpf1 4 GPIO_ACTIVE_HIGH>;
-		i2c-gpio,delay-us = <2>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "okay";
-
-		max77693-fuel-gauge@36 {
-			compatible = "maxim,max17047";
-			interrupt-parent = <&gpx2>;
-			interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
-			reg = <0x36>;
-
-			maxim,over-heat-temp = <700>;
-			maxim,over-volt = <4500>;
-		};
-	};
-
-	i2c_ak8975: i2c-gpio-0 {
-		compatible = "i2c-gpio";
-		gpios = <&gpy2 4 GPIO_ACTIVE_HIGH>, <&gpy2 5 GPIO_ACTIVE_HIGH>;
-		i2c-gpio,delay-us = <2>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "okay";
-
-		ak8975@c {
-			compatible = "asahi-kasei,ak8975";
-			reg = <0x0c>;
-			gpios = <&gpj0 7 GPIO_ACTIVE_HIGH>;
-		};
-	};
-
-	i2c_cm36651: i2c-gpio-2 {
-		compatible = "i2c-gpio";
-		gpios = <&gpf0 0 GPIO_ACTIVE_LOW>, <&gpf0 1 GPIO_ACTIVE_LOW>;
-		i2c-gpio,delay-us = <2>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cm36651@18 {
-			compatible = "capella,cm36651";
-			reg = <0x18>;
-			interrupt-parent = <&gpx0>;
-			interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
-			vled-supply = <&ps_als_reg>;
-		};
-	};
-
-	i2c-mhl {
-		compatible = "i2c-gpio";
-		gpios = <&gpf0 4 GPIO_ACTIVE_HIGH>, <&gpf0 6 GPIO_ACTIVE_HIGH>;
-		i2c-gpio,delay-us = <100>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		pinctrl-0 = <&i2c_mhl_bus>;
-		pinctrl-names = "default";
-		status = "okay";
-
-		sii9234: hdmi-bridge@39 {
-			compatible = "sil,sii9234";
-			avcc33-supply = <&vcc33mhl>;
-			iovcc18-supply = <&vcc18mhl>;
-			avcc12-supply = <&vsil12>;
-			cvcc12-supply = <&vsil12>;
-			reset-gpios = <&gpf3 4 GPIO_ACTIVE_LOW>;
-			interrupt-parent = <&gpf3>;
-			interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
-			reg = <0x39>;
-
-			port {
-				mhl_to_hdmi: endpoint {
-					remote-endpoint = <&hdmi_to_mhl>;
-				};
-			};
-		};
-	};
-
-	camera: camera {
-		pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>;
-		pinctrl-names = "default";
-		status = "okay";
-		assigned-clocks = <&clock CLK_MOUT_CAM0>,
-				  <&clock CLK_MOUT_CAM1>;
-		assigned-clock-parents = <&clock CLK_XUSBXTI>,
-					 <&clock CLK_XUSBXTI>;
-
-
-	};
-
-	wlan_pwrseq: sdhci3-pwrseq {
-		compatible = "mmc-pwrseq-simple";
-		reset-gpios = <&gpj0 0 GPIO_ACTIVE_LOW>;
-		clocks = <&max77686 MAX77686_CLK_PMIC>;
-		clock-names = "ext_clock";
-	};
-
-	sound {
-		compatible = "samsung,trats2-audio";
-		samsung,i2s-controller = <&i2s0>;
-		samsung,model = "Trats2";
-		samsung,audio-codec = <&wm1811>;
-		samsung,audio-routing =
-			"SPK", "SPKOUTLN",
-			"SPK", "SPKOUTLP",
-			"SPK", "SPKOUTRN",
-			"SPK", "SPKOUTRP";
-	};
-
-	thermistor-ap {
-		compatible = "murata,ncp15wb473";
-		pullup-uv = <1800000>;	 /* VCC_1.8V_AP */
-		pullup-ohm = <100000>;	 /* 100K */
-		pulldown-ohm = <100000>; /* 100K */
-		io-channels = <&adc 1>;  /* AP temperature */
-	};
-
-	thermistor-battery {
-		compatible = "murata,ncp15wb473";
-		pullup-uv = <1800000>;	 /* VCC_1.8V_AP */
-		pullup-ohm = <100000>;	 /* 100K */
-		pulldown-ohm = <100000>; /* 100K */
-		io-channels = <&adc 2>;  /* Battery temperature */
-	};
-
-	thermal-zones {
-		cpu_thermal: cpu-thermal {
-			cooling-maps {
-				map0 {
-				     /* Corresponds to 800MHz at freq_table */
-				     cooling-device = <&cpu0 7 7>;
-				};
-				map1 {
-				     /* Corresponds to 200MHz at freq_table */
-				     cooling-device = <&cpu0 13 13>;
-			       };
-		       };
-		};
-	};
-};
-
-&adc {
-	vdd-supply = <&ldo3_reg>;
-	status = "okay";
-};
-
-&bus_dmc {
-	devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
-	vdd-supply = <&buck1_reg>;
-	status = "okay";
-};
-
-&bus_acp {
-	devfreq = <&bus_dmc>;
-	status = "okay";
-};
-
-&bus_c2c {
-	devfreq = <&bus_dmc>;
-	status = "okay";
-};
-
-&bus_leftbus {
-	devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
-	vdd-supply = <&buck3_reg>;
-	status = "okay";
-};
-
-&bus_rightbus {
-	devfreq = <&bus_leftbus>;
-	status = "okay";
-};
-
-&bus_display {
-	devfreq = <&bus_leftbus>;
-	status = "okay";
-};
-
-&bus_fsys {
-	devfreq = <&bus_leftbus>;
-	status = "okay";
-};
-
-&bus_peri {
-	devfreq = <&bus_leftbus>;
-	status = "okay";
-};
-
-&bus_mfc {
-	devfreq = <&bus_leftbus>;
-	status = "okay";
-};
-
-&cpu0 {
-	cpu0-supply = <&buck2_reg>;
-};
-
-&csis_0 {
-	status = "okay";
-	vddcore-supply = <&ldo8_reg>;
-	vddio-supply = <&ldo10_reg>;
-	assigned-clocks = <&clock CLK_MOUT_CSIS0>,
-			<&clock CLK_SCLK_CSIS0>;
-	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
-	assigned-clock-rates = <0>, <176000000>;
-
-	/* Camera C (3) MIPI CSI-2 (CSIS0) */
-	port@3 {
-		reg = <3>;
-		csis0_ep: endpoint {
-			remote-endpoint = <&s5c73m3_ep>;
-			data-lanes = <1 2 3 4>;
-			samsung,csis-hs-settle = <12>;
-		};
-	};
-};
-
-&csis_1 {
-	status = "okay";
-	vddcore-supply = <&ldo8_reg>;
-	vddio-supply = <&ldo10_reg>;
-	assigned-clocks = <&clock CLK_MOUT_CSIS1>,
-			<&clock CLK_SCLK_CSIS1>;
-	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
-	assigned-clock-rates = <0>, <176000000>;
-
-	/* Camera D (4) MIPI CSI-2 (CSIS1) */
-	port@4 {
-		reg = <4>;
-		csis1_ep: endpoint {
-			remote-endpoint = <&is_s5k6a3_ep>;
-			data-lanes = <1>;
-			samsung,csis-hs-settle = <18>;
-			samsung,csis-wclk;
-		};
-	};
-};
-
-&dsi_0 {
-	vddcore-supply = <&ldo8_reg>;
-	vddio-supply = <&ldo10_reg>;
-	samsung,burst-clock-frequency = <500000000>;
-	samsung,esc-clock-frequency = <20000000>;
-	samsung,pll-clock-frequency = <24000000>;
-	status = "okay";
-
-	panel@0 {
-		compatible = "samsung,s6e8aa0";
-		reg = <0>;
-		vdd3-supply = <&lcd_vdd3_reg>;
-		vci-supply = <&ldo25_reg>;
-		reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>;
-		power-on-delay= <50>;
-		reset-delay = <100>;
-		init-delay = <100>;
-		flip-horizontal;
-		flip-vertical;
-		panel-width-mm = <58>;
-		panel-height-mm = <103>;
-
-		display-timings {
-			timing-0 {
-				clock-frequency = <57153600>;
-				hactive = <720>;
-				vactive = <1280>;
-				hfront-porch = <5>;
-				hback-porch = <5>;
-				hsync-len = <5>;
-				vfront-porch = <13>;
-				vback-porch = <1>;
-				vsync-len = <2>;
-			};
-		};
-	};
-};
-
-&exynos_usbphy {
-	vbus-supply = <&esafeout1_reg>;
-	status = "okay";
-};
-
-&fimc_0 {
-	status = "okay";
-	assigned-clocks = <&clock CLK_MOUT_FIMC0>,
-			<&clock CLK_SCLK_FIMC0>;
-	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
-	assigned-clock-rates = <0>, <176000000>;
-};
-
-&fimc_1 {
-	status = "okay";
-	assigned-clocks = <&clock CLK_MOUT_FIMC1>,
-			<&clock CLK_SCLK_FIMC1>;
-	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
-	assigned-clock-rates = <0>, <176000000>;
-};
-
-&fimc_2 {
-	status = "okay";
-	assigned-clocks = <&clock CLK_MOUT_FIMC2>,
-			<&clock CLK_SCLK_FIMC2>;
-	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
-	assigned-clock-rates = <0>, <176000000>;
-};
-
-&fimc_3 {
-	status = "okay";
-	assigned-clocks = <&clock CLK_MOUT_FIMC3>,
-			<&clock CLK_SCLK_FIMC3>;
-	assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
-	assigned-clock-rates = <0>, <176000000>;
-};
-
-&fimc_is {
-	pinctrl-0 = <&fimc_is_uart>;
-	pinctrl-names = "default";
-	status = "okay";
-
-	i2c1_isp: i2c-isp@12140000 {
-		pinctrl-0 = <&fimc_is_i2c1>;
-		pinctrl-names = "default";
-
-		s5k6a3@10 {
-			compatible = "samsung,s5k6a3";
-			reg = <0x10>;
-			svdda-supply = <&cam_io_reg>;
-			svddio-supply = <&ldo19_reg>;
-			afvdd-supply = <&ldo19_reg>;
-			clock-frequency = <24000000>;
-			/* CAM_B_CLKOUT */
-			clocks = <&camera 1>;
-			clock-names = "extclk";
-			samsung,camclk-out = <1>;
-			gpios = <&gpm1 6 GPIO_ACTIVE_HIGH>;
-
-			port {
-				is_s5k6a3_ep: endpoint {
-					remote-endpoint = <&csis1_ep>;
-					data-lanes = <1>;
-				};
-			};
-		};
-	};
-};
-
-&fimc_lite_0 {
-	status = "okay";
-};
-
-&fimc_lite_1 {
-	status = "okay";
-};
-
-&fimd {
-	status = "okay";
-};
-
-&hdmi {
-	hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&hdmi_hpd>;
-	vdd-supply = <&ldo3_reg>;
-	vdd_osc-supply = <&ldo4_reg>;
-	vdd_pll-supply = <&ldo3_reg>;
-	ddc = <&i2c_5>;
-	status = "okay";
-
-	ports {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		port@1 {
-			reg = <1>;
-			hdmi_to_mhl: endpoint {
-				remote-endpoint = <&mhl_to_hdmi>;
-			};
-		};
-	};
-};
-
-&hsotg {
-	vusb_d-supply = <&ldo15_reg>;
-	vusb_a-supply = <&ldo12_reg>;
-	dr_mode = "peripheral";
-	status = "okay";
-};
-
-&i2c_0 {
-	samsung,i2c-sda-delay = <100>;
-	samsung,i2c-slave-addr = <0x10>;
-	samsung,i2c-max-bus-freq = <400000>;
-	pinctrl-0 = <&i2c0_bus>;
-	pinctrl-names = "default";
-	status = "okay";
-
-	s5c73m3@3c {
-		compatible = "samsung,s5c73m3";
-		reg = <0x3c>;
-		standby-gpios = <&gpm0 1 GPIO_ACTIVE_LOW>;   /* ISP_STANDBY */
-		xshutdown-gpios = <&gpf1 3 GPIO_ACTIVE_LOW>; /* ISP_RESET */
-		vdd-int-supply = <&buck9_reg>;
-		vddio-cis-supply = <&ldo9_reg>;
-		vdda-supply = <&ldo17_reg>;
-		vddio-host-supply = <&ldo18_reg>;
-		vdd-af-supply = <&cam_af_reg>;
-		vdd-reg-supply = <&cam_io_reg>;
-		clock-frequency = <24000000>;
-		/* CAM_A_CLKOUT */
-		clocks = <&camera 0>;
-		clock-names = "cis_extclk";
-		port {
-			s5c73m3_ep: endpoint {
-				remote-endpoint = <&csis0_ep>;
-				data-lanes = <1 2 3 4>;
-			};
-		};
-	};
-};
-
-&i2c_3 {
-	samsung,i2c-sda-delay = <100>;
-	samsung,i2c-slave-addr = <0x10>;
-	samsung,i2c-max-bus-freq = <400000>;
-	pinctrl-0 = <&i2c3_bus>;
-	pinctrl-names = "default";
-	status = "okay";
-
-	mms114-touchscreen@48 {
-		compatible = "melfas,mms114";
-		reg = <0x48>;
-		interrupt-parent = <&gpm2>;
-		interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
-		x-size = <720>;
-		y-size = <1280>;
-		avdd-supply = <&ldo23_reg>;
-		vdd-supply = <&ldo24_reg>;
-	};
-};
-
-&i2c_4 {
-	samsung,i2c-sda-delay = <100>;
-	samsung,i2c-slave-addr = <0x10>;
-	samsung,i2c-max-bus-freq = <100000>;
-	pinctrl-0 = <&i2c4_bus>;
-	pinctrl-names = "default";
-	status = "okay";
-
-	wm1811: wm1811@1a {
-		compatible = "wlf,wm1811";
-		reg = <0x1a>;
-		clocks = <&pmu_system_controller 0>;
-		clock-names = "MCLK1";
-		DCVDD-supply = <&ldo3_reg>;
-		DBVDD1-supply = <&ldo3_reg>;
-		wlf,ldo1ena = <&gpj0 4 0>;
 	};
 };
-
-&i2c_5 {
-	status = "okay";
-};
-
-&i2c_7 {
-	samsung,i2c-sda-delay = <100>;
-	samsung,i2c-slave-addr = <0x10>;
-	samsung,i2c-max-bus-freq = <100000>;
-	pinctrl-0 = <&i2c7_bus>;
-	pinctrl-names = "default";
-	status = "okay";
-
-	max77686: max77686_pmic@9 {
-		compatible = "maxim,max77686";
-		interrupt-parent = <&gpx0>;
-		interrupts = <7 IRQ_TYPE_NONE>;
-		reg = <0x09>;
-		#clock-cells = <1>;
-
-		voltage-regulators {
-			ldo1_reg: LDO1 {
-				regulator-name = "VALIVE_1.0V_AP";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1000000>;
-				regulator-always-on;
-			};
-
-			ldo2_reg: LDO2 {
-				regulator-name = "VM1M2_1.2V_AP";
-				regulator-min-microvolt = <1200000>;
-				regulator-max-microvolt = <1200000>;
-				regulator-always-on;
-				regulator-state-mem {
-					regulator-on-in-suspend;
-				};
-			};
-
-			ldo3_reg: LDO3 {
-				regulator-name = "VCC_1.8V_AP";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-always-on;
-			};
-
-			ldo4_reg: LDO4 {
-				regulator-name = "VCC_2.8V_AP";
-				regulator-min-microvolt = <2800000>;
-				regulator-max-microvolt = <2800000>;
-				regulator-always-on;
-			};
-
-			ldo5_reg: LDO5 {
-				regulator-name = "VCC_1.8V_IO";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-always-on;
-			};
-
-			ldo6_reg: LDO6 {
-				regulator-name = "VMPLL_1.0V_AP";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1000000>;
-				regulator-always-on;
-				regulator-state-mem {
-					regulator-on-in-suspend;
-				};
-			};
-
-			ldo7_reg: LDO7 {
-				regulator-name = "VPLL_1.0V_AP";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1000000>;
-				regulator-always-on;
-				regulator-state-mem {
-					regulator-on-in-suspend;
-				};
-			};
-
-			ldo8_reg: LDO8 {
-				regulator-name = "VMIPI_1.0V";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1000000>;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			ldo9_reg: LDO9 {
-				regulator-name = "CAM_ISP_MIPI_1.2V";
-				regulator-min-microvolt = <1200000>;
-				regulator-max-microvolt = <1200000>;
-			};
-
-			ldo10_reg: LDO10 {
-				regulator-name = "VMIPI_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			ldo11_reg: LDO11 {
-				regulator-name = "VABB1_1.95V";
-				regulator-min-microvolt = <1950000>;
-				regulator-max-microvolt = <1950000>;
-				regulator-always-on;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			ldo12_reg: LDO12 {
-				regulator-name = "VUOTG_3.0V";
-				regulator-min-microvolt = <3000000>;
-				regulator-max-microvolt = <3000000>;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			ldo13_reg: LDO13 {
-				regulator-name = "NFC_AVDD_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-			};
-
-			ldo14_reg: LDO14 {
-				regulator-name = "VABB2_1.95V";
-				regulator-min-microvolt = <1950000>;
-				regulator-max-microvolt = <1950000>;
-				regulator-always-on;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			ldo15_reg: LDO15 {
-				regulator-name = "VHSIC_1.0V";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1000000>;
-				regulator-state-mem {
-					regulator-on-in-suspend;
-				};
-			};
-
-			ldo16_reg: LDO16 {
-				regulator-name = "VHSIC_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-				regulator-state-mem {
-					regulator-on-in-suspend;
-				};
-			};
-
-			ldo17_reg: LDO17 {
-				regulator-name = "CAM_SENSOR_CORE_1.2V";
-				regulator-min-microvolt = <1200000>;
-				regulator-max-microvolt = <1200000>;
-			};
-
-			ldo18_reg: LDO18 {
-				regulator-name = "CAM_ISP_SEN_IO_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-			};
-
-			ldo19_reg: LDO19 {
-				regulator-name = "VT_CAM_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-			};
-
-			ldo20_reg: LDO20 {
-				regulator-name = "VDDQ_PRE_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-			};
-
-			ldo21_reg: LDO21 {
-				regulator-name = "VTF_2.8V";
-				regulator-min-microvolt = <2800000>;
-				regulator-max-microvolt = <2800000>;
-				maxim,ena-gpios = <&gpy2 0 GPIO_ACTIVE_HIGH>;
-			};
-
-			ldo22_reg: LDO22 {
-				regulator-name = "VMEM_VDD_2.8V";
-				regulator-min-microvolt = <2800000>;
-				regulator-max-microvolt = <2800000>;
-				maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
-			};
-
-			ldo23_reg: LDO23 {
-				regulator-name = "TSP_AVDD_3.3V";
-				regulator-min-microvolt = <3300000>;
-				regulator-max-microvolt = <3300000>;
-			};
-
-			ldo24_reg: LDO24 {
-				regulator-name = "TSP_VDD_1.8V";
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <1800000>;
-			};
-
-			ldo25_reg: LDO25 {
-				regulator-name = "LCD_VCC_3.3V";
-				regulator-min-microvolt = <2800000>;
-				regulator-max-microvolt = <2800000>;
-			};
-
-			ldo26_reg: LDO26 {
-				regulator-name = "MOTOR_VCC_3.0V";
-				regulator-min-microvolt = <3000000>;
-				regulator-max-microvolt = <3000000>;
-			};
-
-			buck1_reg: BUCK1 {
-				regulator-name = "vdd_mif";
-				regulator-min-microvolt = <850000>;
-				regulator-max-microvolt = <1100000>;
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			buck2_reg: BUCK2 {
-				regulator-name = "vdd_arm";
-				regulator-min-microvolt = <850000>;
-				regulator-max-microvolt = <1500000>;
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-state-mem {
-					regulator-on-in-suspend;
-				};
-			};
-
-			buck3_reg: BUCK3 {
-				regulator-name = "vdd_int";
-				regulator-min-microvolt = <850000>;
-				regulator-max-microvolt = <1150000>;
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			buck4_reg: BUCK4 {
-				regulator-name = "vdd_g3d";
-				regulator-min-microvolt = <850000>;
-				regulator-max-microvolt = <1150000>;
-				regulator-boot-on;
-				regulator-state-mem {
-					regulator-off-in-suspend;
-				};
-			};
-
-			buck5_reg: BUCK5 {
-				regulator-name = "VMEM_1.2V_AP";
-				regulator-min-microvolt = <1200000>;
-				regulator-max-microvolt = <1200000>;
-				regulator-always-on;
-			};
-
-			buck6_reg: BUCK6 {
-				regulator-name = "VCC_SUB_1.35V";
-				regulator-min-microvolt = <1350000>;
-				regulator-max-microvolt = <1350000>;
-				regulator-always-on;
-			};
-
-			buck7_reg: BUCK7 {
-				regulator-name = "VCC_SUB_2.0V";
-				regulator-min-microvolt = <2000000>;
-				regulator-max-microvolt = <2000000>;
-				regulator-always-on;
-			};
-
-			buck8_reg: BUCK8 {
-				regulator-name = "VMEM_VDDF_3.0V";
-				regulator-min-microvolt = <2850000>;
-				regulator-max-microvolt = <2850000>;
-				maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
-			};
-
-			buck9_reg: BUCK9 {
-				regulator-name = "CAM_ISP_CORE_1.2V";
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <1200000>;
-				maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>;
-			};
-		};
-	};
-};
-
-&i2c_8 {
-	status = "okay";
-};
-
-&i2s0 {
-	pinctrl-0 = <&i2s0_bus>;
-	pinctrl-names = "default";
-	status = "okay";
-};
-
-&mixer {
-	status = "okay";
-};
-
-&mshc_0 {
-	broken-cd;
-	non-removable;
-	card-detect-delay = <200>;
-	vmmc-supply = <&ldo22_reg>;
-	clock-frequency = <400000000>;
-	samsung,dw-mshc-ciu-div = <0>;
-	samsung,dw-mshc-sdr-timing = <2 3>;
-	samsung,dw-mshc-ddr-timing = <1 2>;
-	pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
-	pinctrl-names = "default";
-	status = "okay";
-	bus-width = <8>;
-	cap-mmc-highspeed;
-};
-
-&pmu_system_controller {
-	assigned-clocks = <&pmu_system_controller 0>;
-	assigned-clock-parents =  <&clock CLK_XUSBXTI>;
-};
-
-&pinctrl_0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&sleep0>;
-
-	mhl_int: mhl-int {
-		samsung,pins = "gpf3-5";
-		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
-	};
-
-	i2c_mhl_bus: i2c-mhl-bus {
-		samsung,pins = "gpf0-4", "gpf0-6";
-		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
-		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
-		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
-	};
-
-	sleep0: sleep-states {
-		PIN_SLP(gpa0-0, INPUT, NONE);
-		PIN_SLP(gpa0-1, OUT0, NONE);
-		PIN_SLP(gpa0-2, INPUT, NONE);
-		PIN_SLP(gpa0-3, INPUT, UP);
-		PIN_SLP(gpa0-4, INPUT, NONE);
-		PIN_SLP(gpa0-5, INPUT, DOWN);
-		PIN_SLP(gpa0-6, INPUT, DOWN);
-		PIN_SLP(gpa0-7, INPUT, UP);
-
-		PIN_SLP(gpa1-0, INPUT, DOWN);
-		PIN_SLP(gpa1-1, INPUT, DOWN);
-		PIN_SLP(gpa1-2, INPUT, DOWN);
-		PIN_SLP(gpa1-3, INPUT, DOWN);
-		PIN_SLP(gpa1-4, INPUT, DOWN);
-		PIN_SLP(gpa1-5, INPUT, DOWN);
-
-		PIN_SLP(gpb-0, INPUT, NONE);
-		PIN_SLP(gpb-1, INPUT, NONE);
-		PIN_SLP(gpb-2, INPUT, NONE);
-		PIN_SLP(gpb-3, INPUT, NONE);
-		PIN_SLP(gpb-4, INPUT, DOWN);
-		PIN_SLP(gpb-5, INPUT, UP);
-		PIN_SLP(gpb-6, INPUT, DOWN);
-		PIN_SLP(gpb-7, INPUT, DOWN);
-
-		PIN_SLP(gpc0-0, INPUT, DOWN);
-		PIN_SLP(gpc0-1, INPUT, DOWN);
-		PIN_SLP(gpc0-2, INPUT, DOWN);
-		PIN_SLP(gpc0-3, INPUT, DOWN);
-		PIN_SLP(gpc0-4, INPUT, DOWN);
-
-		PIN_SLP(gpc1-0, INPUT, NONE);
-		PIN_SLP(gpc1-1, PREV, NONE);
-		PIN_SLP(gpc1-2, INPUT, NONE);
-		PIN_SLP(gpc1-3, INPUT, NONE);
-		PIN_SLP(gpc1-4, INPUT, NONE);
-
-		PIN_SLP(gpd0-0, INPUT, DOWN);
-		PIN_SLP(gpd0-1, INPUT, DOWN);
-		PIN_SLP(gpd0-2, INPUT, NONE);
-		PIN_SLP(gpd0-3, INPUT, NONE);
-
-		PIN_SLP(gpd1-0, INPUT, DOWN);
-		PIN_SLP(gpd1-1, INPUT, DOWN);
-		PIN_SLP(gpd1-2, INPUT, NONE);
-		PIN_SLP(gpd1-3, INPUT, NONE);
-
-		PIN_SLP(gpf0-0, INPUT, NONE);
-		PIN_SLP(gpf0-1, INPUT, NONE);
-		PIN_SLP(gpf0-2, INPUT, DOWN);
-		PIN_SLP(gpf0-3, INPUT, DOWN);
-		PIN_SLP(gpf0-4, INPUT, NONE);
-		PIN_SLP(gpf0-5, INPUT, DOWN);
-		PIN_SLP(gpf0-6, INPUT, NONE);
-		PIN_SLP(gpf0-7, INPUT, DOWN);
-
-		PIN_SLP(gpf1-0, INPUT, DOWN);
-		PIN_SLP(gpf1-1, INPUT, DOWN);
-		PIN_SLP(gpf1-2, INPUT, DOWN);
-		PIN_SLP(gpf1-3, INPUT, DOWN);
-		PIN_SLP(gpf1-4, INPUT, NONE);
-		PIN_SLP(gpf1-5, INPUT, NONE);
-		PIN_SLP(gpf1-6, INPUT, DOWN);
-		PIN_SLP(gpf1-7, PREV, NONE);
-
-		PIN_SLP(gpf2-0, PREV, NONE);
-		PIN_SLP(gpf2-1, INPUT, DOWN);
-		PIN_SLP(gpf2-2, INPUT, DOWN);
-		PIN_SLP(gpf2-3, INPUT, DOWN);
-		PIN_SLP(gpf2-4, INPUT, DOWN);
-		PIN_SLP(gpf2-5, INPUT, DOWN);
-		PIN_SLP(gpf2-6, INPUT, NONE);
-		PIN_SLP(gpf2-7, INPUT, NONE);
-
-		PIN_SLP(gpf3-0, INPUT, NONE);
-		PIN_SLP(gpf3-1, PREV, NONE);
-		PIN_SLP(gpf3-2, PREV, NONE);
-		PIN_SLP(gpf3-3, PREV, NONE);
-		PIN_SLP(gpf3-4, OUT1, NONE);
-		PIN_SLP(gpf3-5, INPUT, DOWN);
-
-		PIN_SLP(gpj0-0, PREV, NONE);
-		PIN_SLP(gpj0-1, PREV, NONE);
-		PIN_SLP(gpj0-2, PREV, NONE);
-		PIN_SLP(gpj0-3, INPUT, DOWN);
-		PIN_SLP(gpj0-4, PREV, NONE);
-		PIN_SLP(gpj0-5, PREV, NONE);
-		PIN_SLP(gpj0-6, INPUT, DOWN);
-		PIN_SLP(gpj0-7, INPUT, DOWN);
-
-		PIN_SLP(gpj1-0, INPUT, DOWN);
-		PIN_SLP(gpj1-1, PREV, NONE);
-		PIN_SLP(gpj1-2, PREV, NONE);
-		PIN_SLP(gpj1-3, INPUT, DOWN);
-		PIN_SLP(gpj1-4, INPUT, DOWN);
-	};
-};
-
-&pinctrl_1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&sleep1>;
-
-	hdmi_hpd: hdmi-hpd {
-		samsung,pins = "gpx3-7";
-		samsung,pin-pud = <EXYNOS_PIN_PULL_DOWN>;
-	};
-
-	sleep1: sleep-states {
-		PIN_SLP(gpk0-0, PREV, NONE);
-		PIN_SLP(gpk0-1, PREV, NONE);
-		PIN_SLP(gpk0-2, OUT0, NONE);
-		PIN_SLP(gpk0-3, PREV, NONE);
-		PIN_SLP(gpk0-4, PREV, NONE);
-		PIN_SLP(gpk0-5, PREV, NONE);
-		PIN_SLP(gpk0-6, PREV, NONE);
-
-		PIN_SLP(gpk1-0, INPUT, DOWN);
-		PIN_SLP(gpk1-1, INPUT, DOWN);
-		PIN_SLP(gpk1-2, INPUT, DOWN);
-		PIN_SLP(gpk1-3, PREV, NONE);
-		PIN_SLP(gpk1-4, PREV, NONE);
-		PIN_SLP(gpk1-5, PREV, NONE);
-		PIN_SLP(gpk1-6, PREV, NONE);
-
-		PIN_SLP(gpk2-0, INPUT, DOWN);
-		PIN_SLP(gpk2-1, INPUT, DOWN);
-		PIN_SLP(gpk2-2, INPUT, DOWN);
-		PIN_SLP(gpk2-3, INPUT, DOWN);
-		PIN_SLP(gpk2-4, INPUT, DOWN);
-		PIN_SLP(gpk2-5, INPUT, DOWN);
-		PIN_SLP(gpk2-6, INPUT, DOWN);
-
-		PIN_SLP(gpk3-0, OUT0, NONE);
-		PIN_SLP(gpk3-1, INPUT, NONE);
-		PIN_SLP(gpk3-2, INPUT, DOWN);
-		PIN_SLP(gpk3-3, INPUT, NONE);
-		PIN_SLP(gpk3-4, INPUT, NONE);
-		PIN_SLP(gpk3-5, INPUT, NONE);
-		PIN_SLP(gpk3-6, INPUT, NONE);
-
-		PIN_SLP(gpl0-0, INPUT, DOWN);
-		PIN_SLP(gpl0-1, INPUT, DOWN);
-		PIN_SLP(gpl0-2, INPUT, DOWN);
-		PIN_SLP(gpl0-3, INPUT, DOWN);
-		PIN_SLP(gpl0-4, PREV, NONE);
-		PIN_SLP(gpl0-6, PREV, NONE);
-
-		PIN_SLP(gpl1-0, INPUT, DOWN);
-		PIN_SLP(gpl1-1, INPUT, DOWN);
-		PIN_SLP(gpl2-0, INPUT, DOWN);
-		PIN_SLP(gpl2-1, INPUT, DOWN);
-		PIN_SLP(gpl2-2, INPUT, DOWN);
-		PIN_SLP(gpl2-3, INPUT, DOWN);
-		PIN_SLP(gpl2-4, INPUT, DOWN);
-		PIN_SLP(gpl2-5, INPUT, DOWN);
-		PIN_SLP(gpl2-6, PREV, NONE);
-		PIN_SLP(gpl2-7, INPUT, DOWN);
-
-		PIN_SLP(gpm0-0, INPUT, DOWN);
-		PIN_SLP(gpm0-1, INPUT, DOWN);
-		PIN_SLP(gpm0-2, INPUT, DOWN);
-		PIN_SLP(gpm0-3, INPUT, DOWN);
-		PIN_SLP(gpm0-4, INPUT, DOWN);
-		PIN_SLP(gpm0-5, INPUT, DOWN);
-		PIN_SLP(gpm0-6, INPUT, DOWN);
-		PIN_SLP(gpm0-7, INPUT, DOWN);
-
-		PIN_SLP(gpm1-0, INPUT, DOWN);
-		PIN_SLP(gpm1-1, INPUT, DOWN);
-		PIN_SLP(gpm1-2, INPUT, NONE);
-		PIN_SLP(gpm1-3, INPUT, NONE);
-		PIN_SLP(gpm1-4, INPUT, NONE);
-		PIN_SLP(gpm1-5, INPUT, NONE);
-		PIN_SLP(gpm1-6, INPUT, DOWN);
-
-		PIN_SLP(gpm2-0, INPUT, NONE);
-		PIN_SLP(gpm2-1, INPUT, NONE);
-		PIN_SLP(gpm2-2, INPUT, DOWN);
-		PIN_SLP(gpm2-3, INPUT, DOWN);
-		PIN_SLP(gpm2-4, INPUT, DOWN);
-
-		PIN_SLP(gpm3-0, PREV, NONE);
-		PIN_SLP(gpm3-1, PREV, NONE);
-		PIN_SLP(gpm3-2, PREV, NONE);
-		PIN_SLP(gpm3-3, OUT1, NONE);
-		PIN_SLP(gpm3-4, INPUT, DOWN);
-		PIN_SLP(gpm3-5, INPUT, DOWN);
-		PIN_SLP(gpm3-6, INPUT, DOWN);
-		PIN_SLP(gpm3-7, INPUT, DOWN);
-
-		PIN_SLP(gpm4-0, INPUT, DOWN);
-		PIN_SLP(gpm4-1, INPUT, DOWN);
-		PIN_SLP(gpm4-2, INPUT, DOWN);
-		PIN_SLP(gpm4-3, INPUT, DOWN);
-		PIN_SLP(gpm4-4, INPUT, DOWN);
-		PIN_SLP(gpm4-5, INPUT, DOWN);
-		PIN_SLP(gpm4-6, INPUT, DOWN);
-		PIN_SLP(gpm4-7, INPUT, DOWN);
-
-		PIN_SLP(gpy0-0, INPUT, DOWN);
-		PIN_SLP(gpy0-1, INPUT, DOWN);
-		PIN_SLP(gpy0-2, INPUT, DOWN);
-		PIN_SLP(gpy0-3, INPUT, DOWN);
-		PIN_SLP(gpy0-4, INPUT, DOWN);
-		PIN_SLP(gpy0-5, INPUT, DOWN);
-
-		PIN_SLP(gpy1-0, INPUT, DOWN);
-		PIN_SLP(gpy1-1, INPUT, DOWN);
-		PIN_SLP(gpy1-2, INPUT, DOWN);
-		PIN_SLP(gpy1-3, INPUT, DOWN);
-
-		PIN_SLP(gpy2-0, PREV, NONE);
-		PIN_SLP(gpy2-1, INPUT, DOWN);
-		PIN_SLP(gpy2-2, INPUT, NONE);
-		PIN_SLP(gpy2-3, INPUT, NONE);
-		PIN_SLP(gpy2-4, INPUT, NONE);
-		PIN_SLP(gpy2-5, INPUT, NONE);
-
-		PIN_SLP(gpy3-0, INPUT, DOWN);
-		PIN_SLP(gpy3-1, INPUT, DOWN);
-		PIN_SLP(gpy3-2, INPUT, DOWN);
-		PIN_SLP(gpy3-3, INPUT, DOWN);
-		PIN_SLP(gpy3-4, INPUT, DOWN);
-		PIN_SLP(gpy3-5, INPUT, DOWN);
-		PIN_SLP(gpy3-6, INPUT, DOWN);
-		PIN_SLP(gpy3-7, INPUT, DOWN);
-
-		PIN_SLP(gpy4-0, INPUT, DOWN);
-		PIN_SLP(gpy4-1, INPUT, DOWN);
-		PIN_SLP(gpy4-2, INPUT, DOWN);
-		PIN_SLP(gpy4-3, INPUT, DOWN);
-		PIN_SLP(gpy4-4, INPUT, DOWN);
-		PIN_SLP(gpy4-5, INPUT, DOWN);
-		PIN_SLP(gpy4-6, INPUT, DOWN);
-		PIN_SLP(gpy4-7, INPUT, DOWN);
-
-		PIN_SLP(gpy5-0, INPUT, DOWN);
-		PIN_SLP(gpy5-1, INPUT, DOWN);
-		PIN_SLP(gpy5-2, INPUT, DOWN);
-		PIN_SLP(gpy5-3, INPUT, DOWN);
-		PIN_SLP(gpy5-4, INPUT, DOWN);
-		PIN_SLP(gpy5-5, INPUT, DOWN);
-		PIN_SLP(gpy5-6, INPUT, DOWN);
-		PIN_SLP(gpy5-7, INPUT, DOWN);
-
-		PIN_SLP(gpy6-0, INPUT, DOWN);
-		PIN_SLP(gpy6-1, INPUT, DOWN);
-		PIN_SLP(gpy6-2, INPUT, DOWN);
-		PIN_SLP(gpy6-3, INPUT, DOWN);
-		PIN_SLP(gpy6-4, INPUT, DOWN);
-		PIN_SLP(gpy6-5, INPUT, DOWN);
-		PIN_SLP(gpy6-6, INPUT, DOWN);
-		PIN_SLP(gpy6-7, INPUT, DOWN);
-	};
-};
-
-&pinctrl_2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&sleep2>;
-
-	sleep2: sleep-states {
-		PIN_SLP(gpz-0, INPUT, DOWN);
-		PIN_SLP(gpz-1, INPUT, DOWN);
-		PIN_SLP(gpz-2, INPUT, DOWN);
-		PIN_SLP(gpz-3, INPUT, DOWN);
-		PIN_SLP(gpz-4, INPUT, DOWN);
-		PIN_SLP(gpz-5, INPUT, DOWN);
-		PIN_SLP(gpz-6, INPUT, DOWN);
-	};
-};
-
-&pinctrl_3 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&sleep3>;
-
-	sleep3: sleep-states {
-		PIN_SLP(gpv0-0, INPUT, DOWN);
-		PIN_SLP(gpv0-1, INPUT, DOWN);
-		PIN_SLP(gpv0-2, INPUT, DOWN);
-		PIN_SLP(gpv0-3, INPUT, DOWN);
-		PIN_SLP(gpv0-4, INPUT, DOWN);
-		PIN_SLP(gpv0-5, INPUT, DOWN);
-		PIN_SLP(gpv0-6, INPUT, DOWN);
-		PIN_SLP(gpv0-7, INPUT, DOWN);
-
-		PIN_SLP(gpv1-0, INPUT, DOWN);
-		PIN_SLP(gpv1-1, INPUT, DOWN);
-		PIN_SLP(gpv1-2, INPUT, DOWN);
-		PIN_SLP(gpv1-3, INPUT, DOWN);
-		PIN_SLP(gpv1-4, INPUT, DOWN);
-		PIN_SLP(gpv1-5, INPUT, DOWN);
-		PIN_SLP(gpv1-6, INPUT, DOWN);
-		PIN_SLP(gpv1-7, INPUT, DOWN);
-
-		PIN_SLP(gpv2-0, INPUT, DOWN);
-		PIN_SLP(gpv2-1, INPUT, DOWN);
-		PIN_SLP(gpv2-2, INPUT, DOWN);
-		PIN_SLP(gpv2-3, INPUT, DOWN);
-		PIN_SLP(gpv2-4, INPUT, DOWN);
-		PIN_SLP(gpv2-5, INPUT, DOWN);
-		PIN_SLP(gpv2-6, INPUT, DOWN);
-		PIN_SLP(gpv2-7, INPUT, DOWN);
-
-		PIN_SLP(gpv3-0, INPUT, DOWN);
-		PIN_SLP(gpv3-1, INPUT, DOWN);
-		PIN_SLP(gpv3-2, INPUT, DOWN);
-		PIN_SLP(gpv3-3, INPUT, DOWN);
-		PIN_SLP(gpv3-4, INPUT, DOWN);
-		PIN_SLP(gpv3-5, INPUT, DOWN);
-		PIN_SLP(gpv3-6, INPUT, DOWN);
-		PIN_SLP(gpv3-7, INPUT, DOWN);
-
-		PIN_SLP(gpv4-0, INPUT, DOWN);
-	};
-};
-
-&pwm {
-	pinctrl-0 = <&pwm0_out>;
-	pinctrl-names = "default";
-	samsung,pwm-outputs = <0>;
-	status = "okay";
-};
-
-&rtc {
-	status = "okay";
-	clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
-	clock-names = "rtc", "rtc_src";
-};
-
-&sdhci_2 {
-	bus-width = <4>;
-	cd-gpios = <&gpx3 4 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
-	pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
-	pinctrl-names = "default";
-	vmmc-supply = <&ldo21_reg>;
-	status = "okay";
-};
-
-&sdhci_3 {
-	#address-cells = <1>;
-	#size-cells = <0>;
-	non-removable;
-	bus-width = <4>;
-
-	mmc-pwrseq = <&wlan_pwrseq>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4>;
-	status = "okay";
-
-	brcmf: wifi@1 {
-		reg = <1>;
-		compatible = "brcm,bcm4329-fmac";
-		interrupt-parent = <&gpx2>;
-		interrupts = <5 IRQ_TYPE_NONE>;
-		interrupt-names = "host-wake";
-	};
-};
-
-&serial_0 {
-	status = "okay";
-};
-
-&serial_1 {
-	status = "okay";
-};
-
-&serial_2 {
-	status = "okay";
-};
-
-&serial_3 {
-	status = "okay";
-};
-
-&spi_1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&spi1_bus>;
-	cs-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>;
-	status = "okay";
-
-	s5c73m3_spi: s5c73m3@0 {
-		compatible = "samsung,s5c73m3";
-		spi-max-frequency = <50000000>;
-		reg = <0>;
-		controller-data {
-			samsung,spi-feedback-delay = <2>;
-		};
-	};
-};
-
-&tmu {
-	vtmu-supply = <&ldo10_reg>;
-	status = "okay";
-};
diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
index e4ad2fc0329e..2ae1ab602f4b 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -15,7 +15,7 @@
  */
 
 #include "exynos4.dtsi"
-#include "exynos4412-pinctrl.dtsi"
+
 #include "exynos4-cpu-thermal.dtsi"
 
 / {
@@ -42,8 +42,6 @@
 			clocks = <&clock CLK_ARM_CLK>;
 			clock-names = "cpu";
 			operating-points-v2 = <&cpu0_opp_table>;
-			cooling-min-level = <13>;
-			cooling-max-level = <7>;
 			#cooling-cells = <2>; /* min followed by max */
 		};
 
@@ -147,463 +145,410 @@
 		};
 	};
 
-	sysram@2020000 {
-		compatible = "mmio-sram";
-		reg = <0x02020000 0x40000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0x02020000 0x40000>;
 
-		smp-sysram@0 {
-			compatible = "samsung,exynos4210-sysram";
-			reg = <0x0 0x1000>;
-		};
+	soc: soc {
 
-		smp-sysram@2f000 {
-			compatible = "samsung,exynos4210-sysram-ns";
-			reg = <0x2f000 0x1000>;
+		pinctrl_0: pinctrl@11400000 {
+			compatible = "samsung,exynos4x12-pinctrl";
+			reg = <0x11400000 0x1000>;
+			interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
 		};
-	};
-
-	pd_isp: isp-power-domain@10023ca0 {
-		compatible = "samsung,exynos4210-pd";
-		reg = <0x10023CA0 0x20>;
-		#power-domain-cells = <0>;
-		label = "ISP";
-	};
-
-	l2c: l2-cache-controller@10502000 {
-		compatible = "arm,pl310-cache";
-		reg = <0x10502000 0x1000>;
-		cache-unified;
-		cache-level = <2>;
-		arm,tag-latency = <2 2 1>;
-		arm,data-latency = <3 2 1>;
-		arm,double-linefill = <1>;
-		arm,double-linefill-incr = <0>;
-		arm,double-linefill-wrap = <1>;
-		arm,prefetch-drop = <1>;
-		arm,prefetch-offset = <7>;
-	};
 
-	clock: clock-controller@10030000 {
-		compatible = "samsung,exynos4412-clock";
-		reg = <0x10030000 0x18000>;
-		#clock-cells = <1>;
-	};
-
-	isp_clock: clock-controller@10048000 {
-		compatible = "samsung,exynos4412-isp-clock";
-		reg = <0x10048000 0x1000>;
-		#clock-cells = <1>;
-		power-domains = <&pd_isp>;
-		clocks = <&clock CLK_ACLK200>, <&clock CLK_ACLK400_MCUISP>;
-		clock-names = "aclk200", "aclk400_mcuisp";
-	};
+		pinctrl_1: pinctrl@11000000 {
+			compatible = "samsung,exynos4x12-pinctrl";
+			reg = <0x11000000 0x1000>;
+			interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 
-	mct@10050000 {
-		compatible = "samsung,exynos4412-mct";
-		reg = <0x10050000 0x800>;
-		interrupt-parent = <&mct_map>;
-		interrupts = <0>, <1>, <2>, <3>, <4>;
-		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
-		clock-names = "fin_pll", "mct";
-
-		mct_map: mct-map {
-			#interrupt-cells = <1>;
-			#address-cells = <0>;
-			#size-cells = <0>;
-			interrupt-map = <0 &gic 0 57 IRQ_TYPE_LEVEL_HIGH>,
-					<1 &combiner 12 5>,
-					<2 &combiner 12 6>,
-					<3 &combiner 12 7>,
-					<4 &gic 1 12 IRQ_TYPE_LEVEL_HIGH>;
+			wakup_eint: wakeup-interrupt-controller {
+				compatible = "samsung,exynos4210-wakeup-eint";
+				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+			};
 		};
-	};
-
-	watchdog: watchdog@10060000 {
-		compatible = "samsung,exynos5250-wdt";
-		reg = <0x10060000 0x100>;
-		interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_WDT>;
-		clock-names = "watchdog";
-		samsung,syscon-phandle = <&pmu_system_controller>;
-	};
-
-	adc: adc@126c0000 {
-		compatible = "samsung,exynos-adc-v1";
-		reg = <0x126C0000 0x100>;
-		interrupt-parent = <&combiner>;
-		interrupts = <10 3>;
-		clocks = <&clock CLK_TSADC>;
-		clock-names = "adc";
-		#io-channel-cells = <1>;
-		io-channel-ranges;
-		samsung,syscon-phandle = <&pmu_system_controller>;
-		status = "disabled";
-	};
-
-	g2d: g2d@10800000 {
-		compatible = "samsung,exynos4212-g2d";
-		reg = <0x10800000 0x1000>;
-		interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
-		clock-names = "sclk_fimg2d", "fimg2d";
-		iommus = <&sysmmu_g2d>;
-	};
-
-	camera {
-		clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>,
-			 <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>;
-		clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
 
-		/* fimc_[0-3] are configured outside, under phandles */
-		fimc_lite_0: fimc-lite@12390000 {
-			compatible = "samsung,exynos4212-fimc-lite";
-			reg = <0x12390000 0x1000>;
-			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
-			power-domains = <&pd_isp>;
-			clocks = <&isp_clock CLK_ISP_FIMC_LITE0>;
-			clock-names = "flite";
-			iommus = <&sysmmu_fimc_lite0>;
-			status = "disabled";
+		pinctrl_2: pinctrl@3860000 {
+			compatible = "samsung,exynos4x12-pinctrl";
+			reg = <0x03860000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <10 0>;
 		};
 
-		fimc_lite_1: fimc-lite@123a0000 {
-			compatible = "samsung,exynos4212-fimc-lite";
-			reg = <0x123A0000 0x1000>;
-			interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-			power-domains = <&pd_isp>;
-			clocks = <&isp_clock CLK_ISP_FIMC_LITE1>;
-			clock-names = "flite";
-			iommus = <&sysmmu_fimc_lite1>;
-			status = "disabled";
+		pinctrl_3: pinctrl@106e0000 {
+			compatible = "samsung,exynos4x12-pinctrl";
+			reg = <0x106E0000 0x1000>;
+			interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
-		fimc_is: fimc-is@12000000 {
-			compatible = "samsung,exynos4212-fimc-is";
-			reg = <0x12000000 0x260000>;
-			interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
-			power-domains = <&pd_isp>;
-			clocks = <&isp_clock CLK_ISP_FIMC_LITE0>,
-				 <&isp_clock CLK_ISP_FIMC_LITE1>,
-				 <&isp_clock CLK_ISP_PPMUISPX>,
-				 <&isp_clock CLK_ISP_PPMUISPMX>,
-				 <&isp_clock CLK_ISP_FIMC_ISP>,
-				 <&isp_clock CLK_ISP_FIMC_DRC>,
-				 <&isp_clock CLK_ISP_FIMC_FD>,
-				 <&isp_clock CLK_ISP_MCUISP>,
-				 <&isp_clock CLK_ISP_GICISP>,
-				 <&isp_clock CLK_ISP_MCUCTL_ISP>,
-				 <&isp_clock CLK_ISP_PWM_ISP>,
-				 <&isp_clock CLK_ISP_DIV_ISP0>,
-				 <&isp_clock CLK_ISP_DIV_ISP1>,
-				 <&isp_clock CLK_ISP_DIV_MCUISP0>,
-				 <&isp_clock CLK_ISP_DIV_MCUISP1>,
-				 <&clock CLK_MOUT_MPLL_USER_T>,
-				 <&clock CLK_ACLK200>,
-				 <&clock CLK_ACLK400_MCUISP>,
-				 <&clock CLK_DIV_ACLK200>,
-				 <&clock CLK_DIV_ACLK400_MCUISP>,
-				 <&clock CLK_UART_ISP_SCLK>;
-			clock-names = "lite0", "lite1", "ppmuispx",
-				      "ppmuispmx", "isp",
-				      "drc", "fd", "mcuisp",
-				      "gicisp", "mcuctl_isp", "pwm_isp",
-				      "ispdiv0", "ispdiv1", "mcuispdiv0",
-				      "mcuispdiv1", "mpll", "aclk200",
-				      "aclk400mcuisp", "div_aclk200",
-				      "div_aclk400mcuisp", "uart";
-			iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>,
-				 <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>;
-			iommu-names = "isp", "drc", "fd", "mcuctl";
+		sysram@2020000 {
+			compatible = "mmio-sram";
+			reg = <0x02020000 0x40000>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			ranges;
-			status = "disabled";
+			ranges = <0 0x02020000 0x40000>;
 
-			pmu@10020000 {
-				reg = <0x10020000 0x3000>;
+			smp-sysram@0 {
+				compatible = "samsung,exynos4210-sysram";
+				reg = <0x0 0x1000>;
 			};
 
-			i2c1_isp: i2c-isp@12140000 {
-				compatible = "samsung,exynos4212-i2c-isp";
-				reg = <0x12140000 0x100>;
-				clocks = <&isp_clock CLK_ISP_I2C1_ISP>;
-				clock-names = "i2c_isp";
-				#address-cells = <1>;
-				#size-cells = <0>;
+			smp-sysram@2f000 {
+				compatible = "samsung,exynos4210-sysram-ns";
+				reg = <0x2f000 0x1000>;
 			};
 		};
-	};
-
-	mshc_0: mmc@12550000 {
-		compatible = "samsung,exynos4412-dw-mshc";
-		reg = <0x12550000 0x1000>;
-		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		fifo-depth = <0x80>;
-		clocks = <&clock CLK_SDMMC4>, <&clock CLK_SCLK_MMC4>;
-		clock-names = "biu", "ciu";
-		status = "disabled";
-	};
-
-	sysmmu_g2d: sysmmu@10A40000{
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x10A40000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <4 7>;
-		clock-names = "sysmmu", "master";
-		clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
-		#iommu-cells = <0>;
-	};
-
-	sysmmu_fimc_isp: sysmmu@12260000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x12260000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <16 2>;
-		power-domains = <&pd_isp>;
-		clock-names = "sysmmu";
-		clocks = <&isp_clock CLK_ISP_SMMU_ISP>;
-		#iommu-cells = <0>;
-	};
-
-	sysmmu_fimc_drc: sysmmu@12270000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x12270000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <16 3>;
-		power-domains = <&pd_isp>;
-		clock-names = "sysmmu";
-		clocks = <&isp_clock CLK_ISP_SMMU_DRC>;
-		#iommu-cells = <0>;
-	};
-
-	sysmmu_fimc_fd: sysmmu@122a0000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x122A0000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <16 4>;
-		power-domains = <&pd_isp>;
-		clock-names = "sysmmu";
-		clocks = <&isp_clock CLK_ISP_SMMU_FD>;
-		#iommu-cells = <0>;
-	};
-
-	sysmmu_fimc_mcuctl: sysmmu@122b0000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x122B0000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <16 5>;
-		power-domains = <&pd_isp>;
-		clock-names = "sysmmu";
-		clocks = <&isp_clock CLK_ISP_SMMU_ISPCX>;
-		#iommu-cells = <0>;
-	};
 
-	sysmmu_fimc_lite0: sysmmu@123b0000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x123B0000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <16 0>;
-		power-domains = <&pd_isp>;
-		clock-names = "sysmmu", "master";
-		clocks = <&isp_clock CLK_ISP_SMMU_LITE0>,
-			 <&isp_clock CLK_ISP_FIMC_LITE0>;
-		#iommu-cells = <0>;
-	};
+		pd_isp: isp-power-domain@10023ca0 {
+			compatible = "samsung,exynos4210-pd";
+			reg = <0x10023CA0 0x20>;
+			#power-domain-cells = <0>;
+			label = "ISP";
+		};
 
-	sysmmu_fimc_lite1: sysmmu@123c0000 {
-		compatible = "samsung,exynos-sysmmu";
-		reg = <0x123C0000 0x1000>;
-		interrupt-parent = <&combiner>;
-		interrupts = <16 1>;
-		power-domains = <&pd_isp>;
-		clock-names = "sysmmu", "master";
-		clocks = <&isp_clock CLK_ISP_SMMU_LITE1>,
-			 <&isp_clock CLK_ISP_FIMC_LITE1>;
-		#iommu-cells = <0>;
-	};
+		l2c: l2-cache-controller@10502000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x10502000 0x1000>;
+			cache-unified;
+			cache-level = <2>;
+			arm,tag-latency = <2 2 1>;
+			arm,data-latency = <3 2 1>;
+			arm,double-linefill = <1>;
+			arm,double-linefill-incr = <0>;
+			arm,double-linefill-wrap = <1>;
+			arm,prefetch-drop = <1>;
+			arm,prefetch-offset = <7>;
+		};
 
-	bus_dmc: bus_dmc {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_DMC>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_dmc_opp_table>;
-		status = "disabled";
-	};
+		clock: clock-controller@10030000 {
+			compatible = "samsung,exynos4412-clock";
+			reg = <0x10030000 0x18000>;
+			#clock-cells = <1>;
+		};
 
-	bus_acp: bus_acp {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_ACP>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_acp_opp_table>;
-		status = "disabled";
-	};
+		isp_clock: clock-controller@10048000 {
+			compatible = "samsung,exynos4412-isp-clock";
+			reg = <0x10048000 0x1000>;
+			#clock-cells = <1>;
+			power-domains = <&pd_isp>;
+			clocks = <&clock CLK_ACLK200>,
+				 <&clock CLK_ACLK400_MCUISP>;
+			clock-names = "aclk200", "aclk400_mcuisp";
+		};
+
+		mct@10050000 {
+			compatible = "samsung,exynos4412-mct";
+			reg = <0x10050000 0x800>;
+			interrupt-parent = <&mct_map>;
+			interrupts = <0>, <1>, <2>, <3>, <4>;
+			clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MCT>;
+			clock-names = "fin_pll", "mct";
+
+			mct_map: mct-map {
+				#interrupt-cells = <1>;
+				#address-cells = <0>;
+				#size-cells = <0>;
+				interrupt-map =
+					<0 &gic 0 57 IRQ_TYPE_LEVEL_HIGH>,
+					<1 &combiner 12 5>,
+					<2 &combiner 12 6>,
+					<3 &combiner 12 7>,
+					<4 &gic 1 12 IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
 
-	bus_c2c: bus_c2c {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_C2C>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_dmc_opp_table>;
-		status = "disabled";
-	};
+		watchdog: watchdog@10060000 {
+			compatible = "samsung,exynos5250-wdt";
+			reg = <0x10060000 0x100>;
+			interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_WDT>;
+			clock-names = "watchdog";
+			samsung,syscon-phandle = <&pmu_system_controller>;
+		};
+
+		adc: adc@126c0000 {
+			compatible = "samsung,exynos-adc-v1";
+			reg = <0x126C0000 0x100>;
+			interrupt-parent = <&combiner>;
+			interrupts = <10 3>;
+			clocks = <&clock CLK_TSADC>;
+			clock-names = "adc";
+			#io-channel-cells = <1>;
+			io-channel-ranges;
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			status = "disabled";
+		};
 
-	bus_dmc_opp_table: opp_table1 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		g2d: g2d@10800000 {
+			compatible = "samsung,exynos4212-g2d";
+			reg = <0x10800000 0x1000>;
+			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
+			clock-names = "sclk_fimg2d", "fimg2d";
+			iommus = <&sysmmu_g2d>;
+		};
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <900000>;
+		mshc_0: mmc@12550000 {
+			compatible = "samsung,exynos4412-dw-mshc";
+			reg = <0x12550000 0x1000>;
+			interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			fifo-depth = <0x80>;
+			clocks = <&clock CLK_SDMMC4>, <&clock CLK_SCLK_MMC4>;
+			clock-names = "biu", "ciu";
+			status = "disabled";
 		};
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
-			opp-microvolt = <900000>;
+
+		sysmmu_g2d: sysmmu@10A40000{
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x10A40000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <4 7>;
+			clock-names = "sysmmu", "master";
+			clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
+			#iommu-cells = <0>;
 		};
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
-			opp-microvolt = <900000>;
+
+		sysmmu_fimc_isp: sysmmu@12260000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x12260000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <16 2>;
+			power-domains = <&pd_isp>;
+			clock-names = "sysmmu";
+			clocks = <&isp_clock CLK_ISP_SMMU_ISP>;
+			#iommu-cells = <0>;
 		};
-		opp-267000000 {
-			opp-hz = /bits/ 64 <267000000>;
-			opp-microvolt = <950000>;
+
+		sysmmu_fimc_drc: sysmmu@12270000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x12270000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <16 3>;
+			power-domains = <&pd_isp>;
+			clock-names = "sysmmu";
+			clocks = <&isp_clock CLK_ISP_SMMU_DRC>;
+			#iommu-cells = <0>;
 		};
-		opp-400000000 {
-			opp-hz = /bits/ 64 <400000000>;
-			opp-microvolt = <1050000>;
+
+		sysmmu_fimc_fd: sysmmu@122a0000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x122A0000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <16 4>;
+			power-domains = <&pd_isp>;
+			clock-names = "sysmmu";
+			clocks = <&isp_clock CLK_ISP_SMMU_FD>;
+			#iommu-cells = <0>;
 		};
-	};
 
-	bus_acp_opp_table: opp_table2 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		sysmmu_fimc_mcuctl: sysmmu@122b0000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x122B0000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <16 5>;
+			power-domains = <&pd_isp>;
+			clock-names = "sysmmu";
+			clocks = <&isp_clock CLK_ISP_SMMU_ISPCX>;
+			#iommu-cells = <0>;
+		};
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
+		sysmmu_fimc_lite0: sysmmu@123b0000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x123B0000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <16 0>;
+			power-domains = <&pd_isp>;
+			clock-names = "sysmmu", "master";
+			clocks = <&isp_clock CLK_ISP_SMMU_LITE0>,
+				 <&isp_clock CLK_ISP_FIMC_LITE0>;
+			#iommu-cells = <0>;
 		};
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
+
+		sysmmu_fimc_lite1: sysmmu@123c0000 {
+			compatible = "samsung,exynos-sysmmu";
+			reg = <0x123C0000 0x1000>;
+			interrupt-parent = <&combiner>;
+			interrupts = <16 1>;
+			power-domains = <&pd_isp>;
+			clock-names = "sysmmu", "master";
+			clocks = <&isp_clock CLK_ISP_SMMU_LITE1>,
+				 <&isp_clock CLK_ISP_FIMC_LITE1>;
+			#iommu-cells = <0>;
 		};
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
+
+		bus_dmc: bus_dmc {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_DMC>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_dmc_opp_table>;
+			status = "disabled";
 		};
-		opp-267000000 {
-			opp-hz = /bits/ 64 <267000000>;
+
+		bus_acp: bus_acp {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_ACP>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_acp_opp_table>;
+			status = "disabled";
 		};
-	};
 
-	bus_leftbus: bus_leftbus {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_GDL>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
+		bus_c2c: bus_c2c {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_C2C>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_dmc_opp_table>;
+			status = "disabled";
+		};
 
-	bus_rightbus: bus_rightbus {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_DIV_GDR>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
+		bus_dmc_opp_table: opp_table1 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-	bus_display: bus_display {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK160>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_display_opp_table>;
-		status = "disabled";
-	};
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+				opp-microvolt = <900000>;
+			};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+				opp-microvolt = <900000>;
+			};
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+				opp-microvolt = <900000>;
+			};
+			opp-267000000 {
+				opp-hz = /bits/ 64 <267000000>;
+				opp-microvolt = <950000>;
+			};
+			opp-400000000 {
+				opp-hz = /bits/ 64 <400000000>;
+				opp-microvolt = <1050000>;
+			};
+		};
 
-	bus_fsys: bus_fsys {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK133>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_fsys_opp_table>;
-		status = "disabled";
-	};
+		bus_acp_opp_table: opp_table2 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-	bus_peri: bus_peri {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_ACLK100>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_peri_opp_table>;
-		status = "disabled";
-	};
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+			};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+			};
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+			};
+			opp-267000000 {
+				opp-hz = /bits/ 64 <267000000>;
+			};
+		};
 
-	bus_mfc: bus_mfc {
-		compatible = "samsung,exynos-bus";
-		clocks = <&clock CLK_SCLK_MFC>;
-		clock-names = "bus";
-		operating-points-v2 = <&bus_leftbus_opp_table>;
-		status = "disabled";
-	};
+		bus_leftbus: bus_leftbus {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_GDL>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
+		};
 
-	bus_leftbus_opp_table: opp_table3 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_rightbus: bus_rightbus {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_DIV_GDR>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
+		};
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-			opp-microvolt = <900000>;
+		bus_display: bus_display {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK160>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_display_opp_table>;
+			status = "disabled";
 		};
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
-			opp-microvolt = <925000>;
+
+		bus_fsys: bus_fsys {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK133>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_fsys_opp_table>;
+			status = "disabled";
 		};
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
-			opp-microvolt = <950000>;
+
+		bus_peri: bus_peri {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_ACLK100>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_peri_opp_table>;
+			status = "disabled";
 		};
-		opp-200000000 {
-			opp-hz = /bits/ 64 <200000000>;
-			opp-microvolt = <1000000>;
+
+		bus_mfc: bus_mfc {
+			compatible = "samsung,exynos-bus";
+			clocks = <&clock CLK_SCLK_MFC>;
+			clock-names = "bus";
+			operating-points-v2 = <&bus_leftbus_opp_table>;
+			status = "disabled";
 		};
-	};
 
-	bus_display_opp_table: opp_table4 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_leftbus_opp_table: opp_table3 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-160000000 {
-			opp-hz = /bits/ 64 <160000000>;
-		};
-		opp-200000000 {
-			opp-hz = /bits/ 64 <200000000>;
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+				opp-microvolt = <900000>;
+			};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+				opp-microvolt = <925000>;
+			};
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+				opp-microvolt = <950000>;
+			};
+			opp-200000000 {
+				opp-hz = /bits/ 64 <200000000>;
+				opp-microvolt = <1000000>;
+			};
 		};
-	};
 
-	bus_fsys_opp_table: opp_table5 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_display_opp_table: opp_table4 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
-		};
-		opp-134000000 {
-			opp-hz = /bits/ 64 <134000000>;
+			opp-160000000 {
+				opp-hz = /bits/ 64 <160000000>;
+			};
+			opp-200000000 {
+				opp-hz = /bits/ 64 <200000000>;
+			};
 		};
-	};
 
-	bus_peri_opp_table: opp_table6 {
-		compatible = "operating-points-v2";
-		opp-shared;
+		bus_fsys_opp_table: opp_table5 {
+			compatible = "operating-points-v2";
+			opp-shared;
 
-		opp-50000000 {
-			opp-hz = /bits/ 64 <50000000>;
-		};
-		opp-100000000 {
-			opp-hz = /bits/ 64 <100000000>;
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+			};
+			opp-134000000 {
+				opp-hz = /bits/ 64 <134000000>;
+			};
 		};
-	};
 
-	pmu {
-		interrupts = <2 2>, <3 2>, <18 2>, <19 2>;
+		bus_peri_opp_table: opp_table6 {
+			compatible = "operating-points-v2";
+			opp-shared;
+
+			opp-50000000 {
+				opp-hz = /bits/ 64 <50000000>;
+			};
+			opp-100000000 {
+				opp-hz = /bits/ 64 <100000000>;
+			};
+		};
 	};
 };
 
@@ -631,6 +576,92 @@
 		     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
 };
 
+&camera {
+	clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>,
+		 <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>;
+	clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
+
+	/* fimc_[0-3] are configured outside, under phandles */
+	fimc_lite_0: fimc-lite@12390000 {
+		compatible = "samsung,exynos4212-fimc-lite";
+		reg = <0x12390000 0x1000>;
+		interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+		power-domains = <&pd_isp>;
+		clocks = <&isp_clock CLK_ISP_FIMC_LITE0>;
+		clock-names = "flite";
+		iommus = <&sysmmu_fimc_lite0>;
+		status = "disabled";
+	};
+
+	fimc_lite_1: fimc-lite@123a0000 {
+		compatible = "samsung,exynos4212-fimc-lite";
+		reg = <0x123A0000 0x1000>;
+		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+		power-domains = <&pd_isp>;
+		clocks = <&isp_clock CLK_ISP_FIMC_LITE1>;
+		clock-names = "flite";
+		iommus = <&sysmmu_fimc_lite1>;
+		status = "disabled";
+	};
+
+	fimc_is: fimc-is@12000000 {
+		compatible = "samsung,exynos4212-fimc-is";
+		reg = <0x12000000 0x260000>;
+		interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+		power-domains = <&pd_isp>;
+		clocks = <&isp_clock CLK_ISP_FIMC_LITE0>,
+			 <&isp_clock CLK_ISP_FIMC_LITE1>,
+			 <&isp_clock CLK_ISP_PPMUISPX>,
+			 <&isp_clock CLK_ISP_PPMUISPMX>,
+			 <&isp_clock CLK_ISP_FIMC_ISP>,
+			 <&isp_clock CLK_ISP_FIMC_DRC>,
+			 <&isp_clock CLK_ISP_FIMC_FD>,
+			 <&isp_clock CLK_ISP_MCUISP>,
+			 <&isp_clock CLK_ISP_GICISP>,
+			 <&isp_clock CLK_ISP_MCUCTL_ISP>,
+			 <&isp_clock CLK_ISP_PWM_ISP>,
+			 <&isp_clock CLK_ISP_DIV_ISP0>,
+			 <&isp_clock CLK_ISP_DIV_ISP1>,
+			 <&isp_clock CLK_ISP_DIV_MCUISP0>,
+			 <&isp_clock CLK_ISP_DIV_MCUISP1>,
+			 <&clock CLK_MOUT_MPLL_USER_T>,
+			 <&clock CLK_ACLK200>,
+			 <&clock CLK_ACLK400_MCUISP>,
+			 <&clock CLK_DIV_ACLK200>,
+			 <&clock CLK_DIV_ACLK400_MCUISP>,
+			 <&clock CLK_UART_ISP_SCLK>;
+		clock-names = "lite0", "lite1", "ppmuispx",
+			      "ppmuispmx", "isp",
+			      "drc", "fd", "mcuisp",
+			      "gicisp", "mcuctl_isp", "pwm_isp",
+			      "ispdiv0", "ispdiv1", "mcuispdiv0",
+			      "mcuispdiv1", "mpll", "aclk200",
+			      "aclk400mcuisp", "div_aclk200",
+			      "div_aclk400mcuisp", "uart";
+		iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>,
+			 <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>;
+		iommu-names = "isp", "drc", "fd", "mcuctl";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		status = "disabled";
+
+		pmu@10020000 {
+			reg = <0x10020000 0x3000>;
+		};
+
+		i2c1_isp: i2c-isp@12140000 {
+			compatible = "samsung,exynos4212-i2c-isp";
+			reg = <0x12140000 0x100>;
+			clocks = <&isp_clock CLK_ISP_I2C1_ISP>;
+			clock-names = "i2c_isp";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
+
 &exynos_usbphy {
 	compatible = "samsung,exynos4x12-usb2-phy";
 	samsung,sysreg-phandle = <&sys_reg>;
@@ -693,35 +724,8 @@
 		 <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>;
 };
 
-&pinctrl_0 {
-	compatible = "samsung,exynos4x12-pinctrl";
-	reg = <0x11400000 0x1000>;
-	interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
-};
-
-&pinctrl_1 {
-	compatible = "samsung,exynos4x12-pinctrl";
-	reg = <0x11000000 0x1000>;
-	interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
-
-	wakup_eint: wakeup-interrupt-controller {
-		compatible = "samsung,exynos4210-wakeup-eint";
-		interrupt-parent = <&gic>;
-		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
-	};
-};
-
-&pinctrl_2 {
-	compatible = "samsung,exynos4x12-pinctrl";
-	reg = <0x03860000 0x1000>;
-	interrupt-parent = <&combiner>;
-	interrupts = <10 0>;
-};
-
-&pinctrl_3 {
-	compatible = "samsung,exynos4x12-pinctrl";
-	reg = <0x106E0000 0x1000>;
-	interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+&pmu {
+	interrupts = <2 2>, <3 2>, <18 2>, <19 2>;
 };
 
 &pmu_system_controller {
@@ -743,3 +747,5 @@
 	clock-names = "tmu_apbif";
 	status = "disabled";
 };
+
+#include "exynos4412-pinctrl.dtsi"
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 56626d1a4235..bb4180ef7885 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -77,8 +77,6 @@
 				 300000  937500
 				 200000  925000
 			>;
-			cooling-min-level = <15>;
-			cooling-max-level = <9>;
 			#cooling-cells = <2>; /* min followed by max */
 		};
 		cpu@1 {
diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi
index 1886aa00b2db..1e6b57d013c4 100644
--- a/arch/arm/boot/dts/exynos5410.dtsi
+++ b/arch/arm/boot/dts/exynos5410.dtsi
@@ -11,7 +11,6 @@
  */
 
 #include "exynos54xx.dtsi"
-#include "exynos-syscon-restart.dtsi"
 #include <dt-bindings/clock/exynos5410.h>
 #include <dt-bindings/clock/exynos-audss-clk.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/arch/arm/boot/dts/exynos5420-cpus.dtsi b/arch/arm/boot/dts/exynos5420-cpus.dtsi
index 123f0cef658d..a8e449471304 100644
--- a/arch/arm/boot/dts/exynos5420-cpus.dtsi
+++ b/arch/arm/boot/dts/exynos5420-cpus.dtsi
@@ -30,8 +30,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -43,8 +41,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -56,8 +52,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -69,8 +63,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -83,8 +75,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <7>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -96,8 +86,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <7>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -109,8 +97,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <7>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -122,8 +108,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <7>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
diff --git a/arch/arm/boot/dts/exynos5422-cpus.dtsi b/arch/arm/boot/dts/exynos5422-cpus.dtsi
index c593809c7f08..7c130a00d1a8 100644
--- a/arch/arm/boot/dts/exynos5422-cpus.dtsi
+++ b/arch/arm/boot/dts/exynos5422-cpus.dtsi
@@ -29,8 +29,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -42,8 +40,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -55,8 +51,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -68,8 +62,6 @@
 			clock-frequency = <1000000000>;
 			cci-control-port = <&cci_control0>;
 			operating-points-v2 = <&cluster_a7_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <11>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <539>;
 		};
@@ -82,8 +74,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <15>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -95,8 +85,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <15>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -108,8 +96,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <15>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
@@ -121,8 +107,6 @@
 			clock-frequency = <1800000000>;
 			cci-control-port = <&cci_control1>;
 			operating-points-v2 = <&cluster_a15_opp_table>;
-			cooling-min-level = <0>;
-			cooling-max-level = <15>;
 			#cooling-cells = <2>; /* min followed by max */
 			capacity-dmips-mhz = <1024>;
 		};
diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
index fce9e26b5930..f3abecc44657 100644
--- a/arch/arm/boot/dts/exynos5440.dtsi
+++ b/arch/arm/boot/dts/exynos5440.dtsi
@@ -26,24 +26,6 @@
 		tmuctrl2 = &tmuctrl_2;
 	};
 
-	clock: clock-controller@160000 {
-		compatible = "samsung,exynos5440-clock";
-		reg = <0x160000 0x1000>;
-		#clock-cells = <1>;
-	};
-
-	gic: interrupt-controller@2e0000 {
-		compatible = "arm,cortex-a15-gic";
-		#interrupt-cells = <3>;
-		interrupt-controller;
-		reg =	<0x2E1000 0x1000>,
-			<0x2E2000 0x2000>,
-			<0x2E4000 0x2000>,
-			<0x2E6000 0x2000>;
-		interrupts = <GIC_PPI 9
-				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
-	};
-
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -70,182 +52,290 @@
 		};
 	};
 
-	arm-pmu {
-		compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu";
-		interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
-	};
+	soc: soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 
-	timer {
-		compatible = "arm,cortex-a15-timer",
-			     "arm,armv7-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
-		clock-frequency = <50000000>;
-	};
+		clock: clock-controller@160000 {
+			compatible = "samsung,exynos5440-clock";
+			reg = <0x160000 0x1000>;
+			#clock-cells = <1>;
+		};
 
-	cpufreq@160000 {
-		compatible = "samsung,exynos5440-cpufreq";
-		reg = <0x160000 0x1000>;
-		interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
-		operating-points = <
-				/* KHz	  uV */
-				1500000 1100000
-				1400000 1075000
-				1300000 1050000
-				1200000 1025000
-				1100000 1000000
-				1000000 975000
-				900000  950000
-				800000  925000
-		>;
-	};
+		gic: interrupt-controller@2e0000 {
+			compatible = "arm,cortex-a15-gic";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg =	<0x2E1000 0x1000>,
+				<0x2E2000 0x2000>,
+				<0x2E4000 0x2000>,
+				<0x2E6000 0x2000>;
+			interrupts = <GIC_PPI 9
+					(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		};
 
-	serial_0: serial@b0000 {
-		compatible = "samsung,exynos4210-uart";
-		reg = <0xB0000 0x1000>;
-		interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>, <&clock CLK_B_125>;
-		clock-names = "uart", "clk_uart_baud0";
-	};
 
-	serial_1: serial@c0000 {
-		compatible = "samsung,exynos4210-uart";
-		reg = <0xC0000 0x1000>;
-		interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>, <&clock CLK_B_125>;
-		clock-names = "uart", "clk_uart_baud0";
-	};
+		arm-pmu {
+			compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu";
+			interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+		};
 
-	spi_0: spi@d0000 {
-		compatible = "samsung,exynos5440-spi";
-		reg = <0xD0000 0x100>;
-		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		samsung,spi-src-clk = <0>;
-		num-cs = <1>;
-		clocks = <&clock CLK_B_125>, <&clock CLK_SPI_BAUD>;
-		clock-names = "spi", "spi_busclk0";
-	};
+		timer {
+			compatible = "arm,cortex-a15-timer",
+				     "arm,armv7-timer";
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+			clock-frequency = <50000000>;
+		};
 
-	pin_ctrl: pinctrl@e0000 {
-		compatible = "samsung,exynos5440-pinctrl";
-		reg = <0xE0000 0x1000>;
-		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-controller;
-		#interrupt-cells = <2>;
-		#gpio-cells = <2>;
+		cpufreq@160000 {
+			compatible = "samsung,exynos5440-cpufreq";
+			reg = <0x160000 0x1000>;
+			interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+			operating-points = <
+					/* KHz	  uV */
+					1500000 1100000
+					1400000 1075000
+					1300000 1050000
+					1200000 1025000
+					1100000 1000000
+					1000000 975000
+					900000  950000
+					800000  925000
+			>;
+		};
 
-		fan: fan {
-			samsung,exynos5440-pin-function = <1>;
+		serial_0: serial@b0000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0xB0000 0x1000>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>, <&clock CLK_B_125>;
+			clock-names = "uart", "clk_uart_baud0";
 		};
 
-		hdd_led0: hdd_led0 {
-			samsung,exynos5440-pin-function = <2>;
+		serial_1: serial@c0000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0xC0000 0x1000>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>, <&clock CLK_B_125>;
+			clock-names = "uart", "clk_uart_baud0";
 		};
 
-		hdd_led1: hdd_led1 {
-			samsung,exynos5440-pin-function = <3>;
+		spi_0: spi@d0000 {
+			compatible = "samsung,exynos5440-spi";
+			reg = <0xD0000 0x100>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			samsung,spi-src-clk = <0>;
+			num-cs = <1>;
+			clocks = <&clock CLK_B_125>, <&clock CLK_SPI_BAUD>;
+			clock-names = "spi", "spi_busclk0";
 		};
 
-		uart1: uart1 {
-			samsung,exynos5440-pin-function = <4>;
+		pin_ctrl: pinctrl@e0000 {
+			compatible = "samsung,exynos5440-pinctrl";
+			reg = <0xE0000 0x1000>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#gpio-cells = <2>;
+
+			fan: fan {
+				samsung,exynos5440-pin-function = <1>;
+			};
+
+			hdd_led0: hdd_led0 {
+				samsung,exynos5440-pin-function = <2>;
+			};
+
+			hdd_led1: hdd_led1 {
+				samsung,exynos5440-pin-function = <3>;
+			};
+
+			uart1: uart1 {
+				samsung,exynos5440-pin-function = <4>;
+			};
 		};
-	};
 
-	i2c@f0000 {
-		compatible = "samsung,exynos5440-i2c";
-		reg = <0xF0000 0x1000>;
-		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "i2c";
-	};
+		i2c@f0000 {
+			compatible = "samsung,exynos5440-i2c";
+			reg = <0xF0000 0x1000>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "i2c";
+		};
 
-	i2c@100000 {
-		compatible = "samsung,exynos5440-i2c";
-		reg = <0x100000 0x1000>;
-		interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "i2c";
-	};
+		i2c@100000 {
+			compatible = "samsung,exynos5440-i2c";
+			reg = <0x100000 0x1000>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "i2c";
+		};
 
-	watchdog@110000 {
-		compatible = "samsung,s3c6410-wdt";
-		reg = <0x110000 0x1000>;
-		interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "watchdog";
-	};
+		watchdog@110000 {
+			compatible = "samsung,s3c6410-wdt";
+			reg = <0x110000 0x1000>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "watchdog";
+		};
 
-	gmac: ethernet@230000 {
-		compatible = "snps,dwmac-3.70a", "snps,dwmac";
-		reg = <0x00230000 0x8000>;
-		interrupt-parent = <&gic>;
-		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "macirq";
-		phy-mode = "sgmii";
-		clocks = <&clock CLK_GMAC0>;
-		clock-names = "stmmaceth";
-	};
+		gmac: ethernet@230000 {
+			compatible = "snps,dwmac-3.70a", "snps,dwmac";
+			reg = <0x00230000 0x8000>;
+			interrupt-parent = <&gic>;
+			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+			phy-mode = "sgmii";
+			clocks = <&clock CLK_GMAC0>;
+			clock-names = "stmmaceth";
+		};
 
-	amba {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		compatible = "simple-bus";
-		interrupt-parent = <&gic>;
-		ranges;
-	};
+		amba {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "simple-bus";
+			interrupt-parent = <&gic>;
+			ranges;
+		};
 
-	rtc@130000 {
-		compatible = "samsung,s3c6410-rtc";
-		reg = <0x130000 0x1000>;
-		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "rtc";
-	};
+		rtc@130000 {
+			compatible = "samsung,s3c6410-rtc";
+			reg = <0x130000 0x1000>;
+			interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "rtc";
+		};
 
-	tmuctrl_0: tmuctrl@160118 {
-		compatible = "samsung,exynos5440-tmu";
-		reg = <0x160118 0x230>, <0x160368 0x10>;
-		interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "tmu_apbif";
-		#include "exynos5440-tmu-sensor-conf.dtsi"
-	};
+		tmuctrl_0: tmuctrl@160118 {
+			compatible = "samsung,exynos5440-tmu";
+			reg = <0x160118 0x230>, <0x160368 0x10>;
+			interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "tmu_apbif";
+			#include "exynos5440-tmu-sensor-conf.dtsi"
+		};
 
-	tmuctrl_1: tmuctrl@16011c {
-		compatible = "samsung,exynos5440-tmu";
-		reg = <0x16011C 0x230>, <0x160368 0x10>;
-		interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "tmu_apbif";
-		#include "exynos5440-tmu-sensor-conf.dtsi"
-	};
+		tmuctrl_1: tmuctrl@16011c {
+			compatible = "samsung,exynos5440-tmu";
+			reg = <0x16011C 0x230>, <0x160368 0x10>;
+			interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "tmu_apbif";
+			#include "exynos5440-tmu-sensor-conf.dtsi"
+		};
+
+		tmuctrl_2: tmuctrl@160120 {
+			compatible = "samsung,exynos5440-tmu";
+			reg = <0x160120 0x230>, <0x160368 0x10>;
+			interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_B_125>;
+			clock-names = "tmu_apbif";
+			#include "exynos5440-tmu-sensor-conf.dtsi"
+		};
 
-	tmuctrl_2: tmuctrl@160120 {
-		compatible = "samsung,exynos5440-tmu";
-		reg = <0x160120 0x230>, <0x160368 0x10>;
-		interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_B_125>;
-		clock-names = "tmu_apbif";
-		#include "exynos5440-tmu-sensor-conf.dtsi"
+		sata@210000 {
+			compatible = "snps,exynos5440-ahci";
+			reg = <0x210000 0x10000>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_SATA>;
+			clock-names = "sata";
+		};
+
+		ohci@220000 {
+			compatible = "samsung,exynos5440-ohci";
+			reg = <0x220000 0x1000>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_USB>;
+			clock-names = "usbhost";
+		};
+
+		ehci@221000 {
+			compatible = "samsung,exynos5440-ehci";
+			reg = <0x221000 0x1000>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_USB>;
+			clock-names = "usbhost";
+		};
+
+		pcie_phy0: pcie-phy@270000 {
+			#phy-cells = <0>;
+			compatible = "samsung,exynos5440-pcie-phy";
+			reg = <0x270000 0x1000>, <0x271000 0x40>;
+		};
+
+		pcie_phy1: pcie-phy@272000 {
+			#phy-cells = <0>;
+			compatible = "samsung,exynos5440-pcie-phy";
+			reg = <0x272000 0x1000>, <0x271040 0x40>;
+		};
+
+		pcie_0: pcie@290000 {
+			compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
+			reg = <0x290000 0x1000>, <0x40000000 0x1000>;
+			reg-names = "elbi", "config";
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_PR0_250_O>, <&clock CLK_PB0_250_O>;
+			clock-names = "pcie", "pcie_bus";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			device_type = "pci";
+			phys = <&pcie_phy0>;
+			ranges = <0x81000000 0 0	  0x40001000 0 0x00010000   /* downstream I/O */
+				  0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */
+			bus-range = <0x00 0xff>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0x0 0 &gic 53>;
+			num-lanes = <4>;
+			status = "disabled";
+		};
+
+		pcie_1: pcie@2a0000 {
+			compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
+			reg = <0x2a0000 0x1000>, <0x60000000 0x1000>;
+			reg-names = "elbi", "config";
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clock CLK_PR1_250_O>, <&clock CLK_PB0_250_O>;
+			clock-names = "pcie", "pcie_bus";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			device_type = "pci";
+			phys = <&pcie_phy1>;
+			ranges = <0x81000000 0 0	  0x60001000 0 0x00010000   /* downstream I/O */
+				  0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */
+			bus-range = <0x00 0xff>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0x0 0 &gic 56>;
+			num-lanes = <4>;
+			status = "disabled";
+		};
 	};
 
 	thermal-zones {
@@ -262,86 +352,4 @@
 		       #include "exynos5440-trip-points.dtsi"
 		};
 	};
-
-	sata@210000 {
-		compatible = "snps,exynos5440-ahci";
-		reg = <0x210000 0x10000>;
-		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_SATA>;
-		clock-names = "sata";
-	};
-
-	ohci@220000 {
-		compatible = "samsung,exynos5440-ohci";
-		reg = <0x220000 0x1000>;
-		interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_USB>;
-		clock-names = "usbhost";
-	};
-
-	ehci@221000 {
-		compatible = "samsung,exynos5440-ehci";
-		reg = <0x221000 0x1000>;
-		interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_USB>;
-		clock-names = "usbhost";
-	};
-
-	pcie_phy0: pcie-phy@270000 {
-		#phy-cells = <0>;
-		compatible = "samsung,exynos5440-pcie-phy";
-		reg = <0x270000 0x1000>, <0x271000 0x40>;
-	};
-
-	pcie_phy1: pcie-phy@272000 {
-		#phy-cells = <0>;
-		compatible = "samsung,exynos5440-pcie-phy";
-		reg = <0x272000 0x1000>, <0x271040 0x40>;
-	};
-
-	pcie_0: pcie@290000 {
-		compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
-		reg = <0x290000 0x1000>, <0x40000000 0x1000>;
-		reg-names = "elbi", "config";
-		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_PR0_250_O>, <&clock CLK_PB0_250_O>;
-		clock-names = "pcie", "pcie_bus";
-		#address-cells = <3>;
-		#size-cells = <2>;
-		device_type = "pci";
-		phys = <&pcie_phy0>;
-		ranges = <0x81000000 0 0	  0x40001000 0 0x00010000   /* downstream I/O */
-			  0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */
-		bus-range = <0x00 0xff>;
-		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0x0 0 &gic 53>;
-		num-lanes = <4>;
-		status = "disabled";
-	};
-
-	pcie_1: pcie@2a0000 {
-		compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
-		reg = <0x2a0000 0x1000>, <0x60000000 0x1000>;
-		reg-names = "elbi", "config";
-		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&clock CLK_PR1_250_O>, <&clock CLK_PB0_250_O>;
-		clock-names = "pcie", "pcie_bus";
-		#address-cells = <3>;
-		#size-cells = <2>;
-		device_type = "pci";
-		phys = <&pcie_phy1>;
-		ranges = <0x81000000 0 0	  0x60001000 0 0x00010000   /* downstream I/O */
-			  0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */
-		bus-range = <0x00 0xff>;
-		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0x0 0 &gic 56>;
-		num-lanes = <4>;
-		status = "disabled";
-	};
 };
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 0029ec27819c..c8a66a12dbeb 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Google Peach Pi Rev 10+ board device tree source
  *
  * Copyright (c) 2014 Google, Inc
- *
- * 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.
  */
 
 /dts-v1/;
diff --git a/arch/arm/boot/dts/exynos5800.dtsi b/arch/arm/boot/dts/exynos5800.dtsi
index 9ddb6bacac5a..57d3b319fd65 100644
--- a/arch/arm/boot/dts/exynos5800.dtsi
+++ b/arch/arm/boot/dts/exynos5800.dtsi
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * SAMSUNG EXYNOS5800 SoC device tree source
  *
@@ -7,10 +8,6 @@
  * SAMSUNG EXYNOS5800 SoC device nodes are listed in this file.
  * EXYNOS5800 based board files can include this file and provide
  * values for board specfic bindings.
- *
- * 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 "exynos5420.dtsi"
diff --git a/arch/arm/boot/dts/imx1-ads.dts b/arch/arm/boot/dts/imx1-ads.dts
index 5ea28ee07cf4..6354e4c87313 100644
--- a/arch/arm/boot/dts/imx1-ads.dts
+++ b/arch/arm/boot/dts/imx1-ads.dts
@@ -20,7 +20,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@8000000 {
 		reg = <0x08000000 0x04000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx1-apf9328.dts b/arch/arm/boot/dts/imx1-apf9328.dts
index e8b4b52c2418..11515c0cb195 100644
--- a/arch/arm/boot/dts/imx1-apf9328.dts
+++ b/arch/arm/boot/dts/imx1-apf9328.dts
@@ -20,7 +20,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@8000000 {
 		reg = <0x08000000 0x00800000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx1.dtsi b/arch/arm/boot/dts/imx1.dtsi
index 20f6565c337d..f7b9edf93f5e 100644
--- a/arch/arm/boot/dts/imx1.dtsi
+++ b/arch/arm/boot/dts/imx1.dtsi
@@ -25,7 +25,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		gpio0 = &gpio1;
diff --git a/arch/arm/boot/dts/imx23-evk.dts b/arch/arm/boot/dts/imx23-evk.dts
index 57e29977ba06..9d92ece82560 100644
--- a/arch/arm/boot/dts/imx23-evk.dts
+++ b/arch/arm/boot/dts/imx23-evk.dts
@@ -16,7 +16,7 @@
 	model = "Freescale i.MX23 Evaluation Kit";
 	compatible = "fsl,imx23-evk", "fsl,imx23";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx23-olinuxino.dts b/arch/arm/boot/dts/imx23-olinuxino.dts
index a8b1c53ebe46..e9351774c619 100644
--- a/arch/arm/boot/dts/imx23-olinuxino.dts
+++ b/arch/arm/boot/dts/imx23-olinuxino.dts
@@ -19,7 +19,7 @@
 	model = "i.MX23 Olinuxino Low Cost Board";
 	compatible = "olimex,imx23-olinuxino", "fsl,imx23";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x04000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx23-sansa.dts b/arch/arm/boot/dts/imx23-sansa.dts
index 221fd55e967e..67de7863ad79 100644
--- a/arch/arm/boot/dts/imx23-sansa.dts
+++ b/arch/arm/boot/dts/imx23-sansa.dts
@@ -49,7 +49,7 @@
 	model = "SanDisk Sansa Fuze+";
 	compatible = "sandisk,sansa_fuze_plus", "fsl,imx23";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x04000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx23-stmp378x_devb.dts b/arch/arm/boot/dts/imx23-stmp378x_devb.dts
index 455169e99d49..95c7b918f6d6 100644
--- a/arch/arm/boot/dts/imx23-stmp378x_devb.dts
+++ b/arch/arm/boot/dts/imx23-stmp378x_devb.dts
@@ -16,7 +16,7 @@
 	model = "Freescale STMP378x Development Board";
 	compatible = "fsl,stmp378x-devb", "fsl,imx23";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x04000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx23-xfi3.dts b/arch/arm/boot/dts/imx23-xfi3.dts
index 025cf949662d..9616e500b996 100644
--- a/arch/arm/boot/dts/imx23-xfi3.dts
+++ b/arch/arm/boot/dts/imx23-xfi3.dts
@@ -48,7 +48,7 @@
 	model = "Creative ZEN X-Fi3";
 	compatible = "creative,x-fi3", "fsl,imx23";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x04000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi
index 10d57f9cbb42..cb0a3fe32718 100644
--- a/arch/arm/boot/dts/imx23.dtsi
+++ b/arch/arm/boot/dts/imx23.dtsi
@@ -23,7 +23,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		gpio0 = &gpio0;
@@ -222,7 +222,8 @@
 					fsl,pull-up = <MXS_PULL_DISABLE>;
 				};
 
-				gpmi_pins_fixup: gpmi-pins-fixup {
+				gpmi_pins_fixup: gpmi-pins-fixup@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX23_PAD_GPMI_WPN__GPMI_WPN
 						MX23_PAD_GPMI_WRN__GPMI_WRN
@@ -266,7 +267,8 @@
 					fsl,pull-up = <MXS_PULL_ENABLE>;
 				};
 
-				mmc0_pins_fixup: mmc0-pins-fixup {
+				mmc0_pins_fixup: mmc0-pins-fixup@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX23_PAD_SSP1_DETECT__SSP1_DETECT
 						MX23_PAD_SSP1_SCK__SSP1_SCK
diff --git a/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi b/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi
index d6f27641c0ef..e316fe08837a 100644
--- a/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi
+++ b/arch/arm/boot/dts/imx25-eukrea-cpuimx25.dtsi
@@ -17,7 +17,7 @@
 	model = "Eukrea CPUIMX25";
 	compatible = "eukrea,cpuimx25", "fsl,imx25";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x4000000>; /* 64M */
 	};
 };
diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts
index 0f053721d80f..6273a1f243ed 100644
--- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts
+++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard.dts
@@ -88,12 +88,12 @@
 
 		pinctrl_esdhc1: esdhc1grp {
 			fsl,pins = <
-				MX25_PAD_SD1_CMD__SD1_CMD		0x400000c0
-				MX25_PAD_SD1_CLK__SD1_CLK		0x400000c0
-				MX25_PAD_SD1_DATA0__SD1_DATA0		0x400000c0
-				MX25_PAD_SD1_DATA1__SD1_DATA1		0x400000c0
-				MX25_PAD_SD1_DATA2__SD1_DATA2		0x400000c0
-				MX25_PAD_SD1_DATA3__SD1_DATA3		0x400000c0
+				MX25_PAD_SD1_CMD__ESDHC1_CMD		0x400000c0
+				MX25_PAD_SD1_CLK__ESDHC1_CLK		0x400000c0
+				MX25_PAD_SD1_DATA0__ESDHC1_DAT0		0x400000c0
+				MX25_PAD_SD1_DATA1__ESDHC1_DAT1		0x400000c0
+				MX25_PAD_SD1_DATA2__ESDHC1_DAT2		0x400000c0
+				MX25_PAD_SD1_DATA3__ESDHC1_DAT3		0x400000c0
 			>;
 		};
 
diff --git a/arch/arm/boot/dts/imx25-karo-tx25.dts b/arch/arm/boot/dts/imx25-karo-tx25.dts
index 30a62d4be8d9..5cb6967866c0 100644
--- a/arch/arm/boot/dts/imx25-karo-tx25.dts
+++ b/arch/arm/boot/dts/imx25-karo-tx25.dts
@@ -36,7 +36,7 @@
 		};
 	};
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x02000000 0x90000000 0x02000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx25-pdk.dts b/arch/arm/boot/dts/imx25-pdk.dts
index 2d15ce72d006..7f9bd052b84e 100644
--- a/arch/arm/boot/dts/imx25-pdk.dts
+++ b/arch/arm/boot/dts/imx25-pdk.dts
@@ -18,7 +18,7 @@
 	model = "Freescale i.MX25 Product Development Kit";
 	compatible = "fsl,imx25-pdk", "fsl,imx25";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x4000000>;
 	};
 
@@ -165,12 +165,12 @@
 
 		pinctrl_esdhc1: esdhc1grp {
 			fsl,pins = <
-				MX25_PAD_SD1_CMD__SD1_CMD		0x80000000
-				MX25_PAD_SD1_CLK__SD1_CLK		0x80000000
-				MX25_PAD_SD1_DATA0__SD1_DATA0		0x80000000
-				MX25_PAD_SD1_DATA1__SD1_DATA1		0x80000000
-				MX25_PAD_SD1_DATA2__SD1_DATA2		0x80000000
-				MX25_PAD_SD1_DATA3__SD1_DATA3		0x80000000
+				MX25_PAD_SD1_CMD__ESDHC1_CMD		0x80000000
+				MX25_PAD_SD1_CLK__ESDHC1_CLK		0x80000000
+				MX25_PAD_SD1_DATA0__ESDHC1_DAT0		0x80000000
+				MX25_PAD_SD1_DATA1__ESDHC1_DAT1		0x80000000
+				MX25_PAD_SD1_DATA2__ESDHC1_DAT2		0x80000000
+				MX25_PAD_SD1_DATA3__ESDHC1_DAT3		0x80000000
 				MX25_PAD_A14__GPIO_2_0			0x80000000
 				MX25_PAD_A15__GPIO_2_1			0x80000000
 			>;
diff --git a/arch/arm/boot/dts/imx25-pinfunc.h b/arch/arm/boot/dts/imx25-pinfunc.h
index 6c63dca1b9b8..a4807062a90f 100644
--- a/arch/arm/boot/dts/imx25-pinfunc.h
+++ b/arch/arm/boot/dts/imx25-pinfunc.h
@@ -151,21 +151,21 @@
 #define MX25_PAD_D15__D15			0x088 0x280 0x000 0x00 0x000
 #define MX25_PAD_D15__LD16			0x088 0x280 0x000 0x01 0x000
 #define MX25_PAD_D15__GPIO_4_5			0x088 0x280 0x000 0x05 0x000
-#define MX25_PAD_D15__SDHC1_DAT7		0x088 0x280 0x4d8 0x06 0x000
+#define MX25_PAD_D15__ESDHC1_DAT7		0x088 0x280 0x4d8 0x06 0x000
 
 #define MX25_PAD_D14__D14			0x08c 0x284 0x000 0x00 0x000
 #define MX25_PAD_D14__LD17			0x08c 0x284 0x000 0x01 0x000
 #define MX25_PAD_D14__GPIO_4_6			0x08c 0x284 0x000 0x05 0x000
-#define MX25_PAD_D14__SDHC1_DAT6		0x08c 0x284 0x4d4 0x06 0x000
+#define MX25_PAD_D14__ESDHC1_DAT6		0x08c 0x284 0x4d4 0x06 0x000
 
 #define MX25_PAD_D13__D13			0x090 0x288 0x000 0x00 0x000
 #define MX25_PAD_D13__LD18			0x090 0x288 0x000 0x01 0x000
 #define MX25_PAD_D13__GPIO_4_7			0x090 0x288 0x000 0x05 0x000
-#define MX25_PAD_D13__SDHC1_DAT5		0x090 0x288 0x4d0 0x06 0x000
+#define MX25_PAD_D13__ESDHC1_DAT5		0x090 0x288 0x4d0 0x06 0x000
 
 #define MX25_PAD_D12__D12			0x094 0x28c 0x000 0x00 0x000
 #define MX25_PAD_D12__GPIO_4_8			0x094 0x28c 0x000 0x05 0x000
-#define MX25_PAD_D12__SDHC1_DAT4		0x094 0x28c 0x4cc 0x06 0x000
+#define MX25_PAD_D12__ESDHC1_DAT4		0x094 0x28c 0x4cc 0x06 0x000
 
 #define MX25_PAD_D11__D11			0x098 0x290 0x000 0x00 0x000
 #define MX25_PAD_D11__GPIO_4_9			0x098 0x290 0x000 0x05 0x000
@@ -236,12 +236,13 @@
 #define MX25_PAD_LD8__LD8			0x0e8 0x2e0 0x000 0x00 0x000
 #define MX25_PAD_LD8__UART4_RXD			0x0e8 0x2e0 0x570 0x02 0x000
 #define MX25_PAD_LD8__FEC_TX_ERR		0x0e8 0x2e0 0x000 0x05 0x000
-#define MX25_PAD_LD8__SDHC2_CMD			0x0e8 0x2e0 0x4e0 0x06 0x000
+/* SION must be set; see the comment for MX25_PAD_SD1_CMD__ESDHC1_CMD. */
+#define MX25_PAD_LD8__ESDHC2_CMD		0x0e8 0x2e0 0x4e0 0x16 0x000
 
 #define MX25_PAD_LD9__LD9			0x0ec 0x2e4 0x000 0x00 0x000
 #define MX25_PAD_LD9__UART4_TXD			0x0ec 0x2e4 0x000 0x02 0x000
 #define MX25_PAD_LD9__FEC_COL			0x0ec 0x2e4 0x504 0x05 0x001
-#define MX25_PAD_LD9__SDHC2_CLK			0x0ec 0x2e4 0x4dc 0x06 0x000
+#define MX25_PAD_LD9__ESDHC2_CLK		0x0ec 0x2e4 0x4dc 0x06 0x000
 
 #define MX25_PAD_LD10__LD10			0x0f0 0x2e8 0x000 0x00 0x000
 #define MX25_PAD_LD10__UART4_RTS		0x0f0 0x2e8 0x56c 0x02 0x000
@@ -250,7 +251,7 @@
 #define MX25_PAD_LD11__LD11			0x0f4 0x2ec 0x000 0x00 0x000
 #define MX25_PAD_LD11__UART4_CTS		0x0f4 0x2ec 0x000 0x02 0x000
 #define MX25_PAD_LD11__FEC_RDATA2		0x0f4 0x2ec 0x50c 0x05 0x001
-#define MX25_PAD_LD11__SDHC2_DAT1		0x0f4 0x2ec 0x4e8 0x06 0x000
+#define MX25_PAD_LD11__ESDHC2_DAT1		0x0f4 0x2ec 0x4e8 0x06 0x000
 
 #define MX25_PAD_LD12__LD12			0x0f8 0x2f0 0x000 0x00 0x000
 #define MX25_PAD_LD12__CSPI2_MOSI		0x0f8 0x2f0 0x4a0 0x02 0x000
@@ -316,12 +317,13 @@
 #define MX25_PAD_CSI_D5__CSPI3_RDY		0x12c 0x324 0x000 0x07 0x000
 
 #define MX25_PAD_CSI_D6__CSI_D6			0x130 0x328 0x000 0x00 0x000
-#define MX25_PAD_CSI_D6__SDHC2_CMD		0x130 0x328 0x4e0 0x02 0x001
+/* SION must be set; see the comment for MX25_PAD_SD1_CMD__ESDHC1_CMD. */
+#define MX25_PAD_CSI_D6__ESDHC2_CMD		0x130 0x328 0x4e0 0x12 0x001
 #define MX25_PAD_CSI_D6__SIM1_PD0		0x130 0x328 0x000 0x04 0x000
 #define MX25_PAD_CSI_D6__GPIO_1_31		0x130 0x328 0x000 0x05 0x000
 
 #define MX25_PAD_CSI_D7__CSI_D7			0x134 0x32c 0x000 0x00 0x000
-#define MX25_PAD_CSI_D7__SDHC2_DAT_CLK		0x134 0x32C 0x4dc 0x02 0x001
+#define MX25_PAD_CSI_D7__ESDHC2_CLK		0x134 0x32C 0x4dc 0x02 0x001
 #define MX25_PAD_CSI_D7__GPIO_1_6		0x134 0x32c 0x000 0x05 0x000
 
 #define MX25_PAD_CSI_D8__CSI_D8			0x138 0x330 0x000 0x00 0x000
@@ -336,22 +338,22 @@
 
 #define MX25_PAD_CSI_MCLK__CSI_MCLK		0x140 0x338 0x000 0x00 0x000
 #define MX25_PAD_CSI_MCLK__AUD6_TXD		0x140 0x338 0x000 0x01 0x000
-#define MX25_PAD_CSI_MCLK__SDHC2_DAT0		0x140 0x338 0x4e4 0x02 0x001
+#define MX25_PAD_CSI_MCLK__ESDHC2_DAT0		0x140 0x338 0x4e4 0x02 0x001
 #define MX25_PAD_CSI_MCLK__GPIO_1_8		0x140 0x338 0x000 0x05 0x000
 
 #define MX25_PAD_CSI_VSYNC__CSI_VSYNC		0x144 0x33c 0x000 0x00 0x000
 #define MX25_PAD_CSI_VSYNC__AUD6_RXD		0x144 0x33c 0x000 0x01 0x000
-#define MX25_PAD_CSI_VSYNC__SDHC2_DAT1		0x144 0x33c 0x4e8 0x02 0x001
+#define MX25_PAD_CSI_VSYNC__ESDHC2_DAT1		0x144 0x33c 0x4e8 0x02 0x001
 #define MX25_PAD_CSI_VSYNC__GPIO_1_9		0x144 0x33c 0x000 0x05 0x000
 
 #define MX25_PAD_CSI_HSYNC__CSI_HSYNC		0x148 0x340 0x000 0x00 0x000
 #define MX25_PAD_CSI_HSYNC__AUD6_TXC		0x148 0x340 0x000 0x01 0x000
-#define MX25_PAD_CSI_HSYNC__SDHC2_DAT2		0x148 0x340 0x4ec 0x02 0x001
+#define MX25_PAD_CSI_HSYNC__ESDHC2_DAT2		0x148 0x340 0x4ec 0x02 0x001
 #define MX25_PAD_CSI_HSYNC__GPIO_1_10		0x148 0x340 0x000 0x05 0x000
 
 #define MX25_PAD_CSI_PIXCLK__CSI_PIXCLK		0x14c 0x344 0x000 0x00 0x000
 #define MX25_PAD_CSI_PIXCLK__AUD6_TXFS		0x14c 0x344 0x000 0x01 0x000
-#define MX25_PAD_CSI_PIXCLK__SDHC2_DAT3		0x14c 0x344 0x4f0 0x02 0x001
+#define MX25_PAD_CSI_PIXCLK__ESDHC2_DAT3	0x14c 0x344 0x4f0 0x02 0x001
 #define MX25_PAD_CSI_PIXCLK__GPIO_1_11		0x14c 0x344 0x000 0x05 0x000
 
 #define MX25_PAD_I2C1_CLK__I2C1_CLK		0x150 0x348 0x000 0x00 0x000
@@ -419,37 +421,37 @@
 #define MX25_PAD_UART2_CTS__GPIO_4_29		0x18c 0x384 0x000 0x05 0x000
 
 /*
- * Removing the SION bit from MX25_PAD_SD1_CMD__SD1_CMD breaks detecting an SD
+ * Removing the SION bit from MX25_PAD_*__ESDHCn_CMD breaks detecting an SD
  * card. According to the i.MX25 reference manual (e.g. Figure 23-2 in IMX25RM
  * Rev. 2 from 01/2011) this pin is bidirectional. So it seems to be a silicon
- * bug that configuring the SD1_CMD function doesn't enable the input path for
- * this pin.
+ * bug that configuring the ESDHCn_CMD function doesn't enable the input path
+ * for this pin.
  * This might have side effects for other hardware units that are connected to
  * that pin and use the respective function as input.
  */
-#define MX25_PAD_SD1_CMD__SD1_CMD		0x190 0x388 0x000 0x10 0x000
+#define MX25_PAD_SD1_CMD__ESDHC1_CMD		0x190 0x388 0x000 0x10 0x000
 #define MX25_PAD_SD1_CMD__CSPI2_MOSI		0x190 0x388 0x4a0 0x01 0x001
 #define MX25_PAD_SD1_CMD__FEC_RDATA2		0x190 0x388 0x50c 0x02 0x002
 #define MX25_PAD_SD1_CMD__GPIO_2_23		0x190 0x388 0x000 0x05 0x000
 
-#define MX25_PAD_SD1_CLK__SD1_CLK		0x194 0x38c 0x000 0x00 0x000
+#define MX25_PAD_SD1_CLK__ESDHC1_CLK		0x194 0x38c 0x000 0x00 0x000
 #define MX25_PAD_SD1_CLK__CSPI2_MISO		0x194 0x38c 0x49c 0x01 0x001
 #define MX25_PAD_SD1_CLK__FEC_RDATA3		0x194 0x38c 0x510 0x02 0x002
 #define MX25_PAD_SD1_CLK__GPIO_2_24		0x194 0x38c 0x000 0x05 0x000
 
-#define MX25_PAD_SD1_DATA0__SD1_DATA0		0x198 0x390 0x000 0x00 0x000
+#define MX25_PAD_SD1_DATA0__ESDHC1_DAT0		0x198 0x390 0x000 0x00 0x000
 #define MX25_PAD_SD1_DATA0__CSPI2_SCLK		0x198 0x390 0x494 0x01 0x001
 #define MX25_PAD_SD1_DATA0__GPIO_2_25		0x198 0x390 0x000 0x05 0x000
 
-#define MX25_PAD_SD1_DATA1__SD1_DATA1		0x19c 0x394 0x000 0x00 0x000
+#define MX25_PAD_SD1_DATA1__ESDHC1_DAT1		0x19c 0x394 0x000 0x00 0x000
 #define MX25_PAD_SD1_DATA1__AUD7_RXD		0x19c 0x394 0x478 0x03 0x000
 #define MX25_PAD_SD1_DATA1__GPIO_2_26		0x19c 0x394 0x000 0x05 0x000
 
-#define MX25_PAD_SD1_DATA2__SD1_DATA2		0x1a0 0x398 0x000 0x00 0x000
+#define MX25_PAD_SD1_DATA2__ESDHC1_DAT2		0x1a0 0x398 0x000 0x00 0x000
 #define MX25_PAD_SD1_DATA2__FEC_RX_CLK		0x1a0 0x398 0x514 0x02 0x002
 #define MX25_PAD_SD1_DATA2__GPIO_2_27		0x1a0 0x398 0x000 0x05 0x000
 
-#define MX25_PAD_SD1_DATA3__SD1_DATA3		0x1a4 0x39c 0x000 0x00 0x000
+#define MX25_PAD_SD1_DATA3__ESDHC1_DAT3		0x1a4 0x39c 0x000 0x00 0x000
 #define MX25_PAD_SD1_DATA3__FEC_CRS		0x1a4 0x39c 0x508 0x02 0x002
 #define MX25_PAD_SD1_DATA3__GPIO_2_28		0x1a4 0x39c 0x000 0x05 0x000
 
@@ -496,6 +498,8 @@
 #define MX25_PAD_KPP_COL3__GPIO_3_4		0x1c4 0x3bc 0x000 0x05 0x000
 
 #define MX25_PAD_FEC_MDC__FEC_MDC		0x1c8 0x3c0 0x000 0x00 0x000
+/* SION must be set; see the comment for MX25_PAD_SD1_CMD__ESDHC1_CMD. */
+#define MX25_PAD_FEC_MDC__ESDHC2_CMD		0x1c8 0x3c0 0x4e0 0x11 0x002
 #define MX25_PAD_FEC_MDC__AUD4_TXD		0x1c8 0x3c0 0x464 0x02 0x001
 #define MX25_PAD_FEC_MDC__GPIO_3_5		0x1c8 0x3c0 0x000 0x05 0x000
 
@@ -601,4 +605,28 @@
 #define MX25_PAD_BOOT_MODE1__BOOT_MODE1		0x228 0x000 0x000 0x00 0x000
 #define MX25_PAD_BOOT_MODE1__GPIO_4_31		0x228 0x000 0x000 0x05 0x000
 
+/*
+ * Compatibility defines for out-of-tree users. You should update if you make
+ * use of one of them.
+ */
+#define MX25_PAD_D15__SDHC1_DAT7		MX25_PAD_D15__ESDHC1_DAT7
+#define MX25_PAD_D14__SDHC1_DAT6		MX25_PAD_D14__ESDHC1_DAT6
+#define MX25_PAD_D13__SDHC1_DAT5		MX25_PAD_D13__ESDHC1_DAT5
+#define MX25_PAD_D12__SDHC1_DAT4		MX25_PAD_D12__ESDHC1_DAT4
+#define MX25_PAD_LD8__SDHC2_CMD			MX25_PAD_LD8__ESDHC2_CMD
+#define MX25_PAD_LD9__SDHC2_CLK			MX25_PAD_LD9__ESDHC2_CLK
+#define MX25_PAD_LD11__SDHC2_DAT1		MX25_PAD_LD11__ESDHC2_DAT1
+#define MX25_PAD_CSI_D6__SDHC2_CMD		MX25_PAD_CSI_D6__ESDHC2_CMD
+#define MX25_PAD_CSI_D7__SDHC2_DAT_CLK		MX25_PAD_CSI_D7__ESDHC2_CLK
+#define MX25_PAD_CSI_MCLK__SDHC2_DAT0		MX25_PAD_CSI_MCLK__ESDHC2_DAT0
+#define MX25_PAD_CSI_VSYNC__SDHC2_DAT1		MX25_PAD_CSI_VSYNC__ESDHC2_DAT1
+#define MX25_PAD_CSI_HSYNC__SDHC2_DAT2		MX25_PAD_CSI_HSYNC__ESDHC2_DAT2
+#define MX25_PAD_CSI_PIXCLK__SDHC2_DAT3		MX25_PAD_CSI_PIXCLK__ESDHC2_DAT3
+#define MX25_PAD_SD1_CMD__SD1_CMD		MX25_PAD_SD1_CMD__ESDHC1_CMD
+#define MX25_PAD_SD1_CLK__SD1_CLK		MX25_PAD_SD1_CLK__ESDHC1_CLK
+#define MX25_PAD_SD1_DATA0__SD1_DATA0		MX25_PAD_SD1_DATA0__ESDHC1_DAT0
+#define MX25_PAD_SD1_DATA1__SD1_DATA1		MX25_PAD_SD1_DATA1__ESDHC1_DAT1
+#define MX25_PAD_SD1_DATA2__SD1_DATA2		MX25_PAD_SD1_DATA2__ESDHC1_DAT2
+#define MX25_PAD_SD1_DATA3__SD1_DATA3		MX25_PAD_SD1_DATA3__ESDHC1_DAT3
+
 #endif /* __DTS_IMX25_PINFUNC_H */
diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi
index 9445f8e1473c..972570568c01 100644
--- a/arch/arm/boot/dts/imx25.dtsi
+++ b/arch/arm/boot/dts/imx25.dtsi
@@ -22,7 +22,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx27-apf27.dts b/arch/arm/boot/dts/imx27-apf27.dts
index 73aae4f5e539..66941cdbf244 100644
--- a/arch/arm/boot/dts/imx27-apf27.dts
+++ b/arch/arm/boot/dts/imx27-apf27.dts
@@ -19,7 +19,7 @@
 	model = "Armadeus Systems APF27 module";
 	compatible = "armadeus,imx27-apf27", "fsl,imx27";
 
-	memory {
+	memory@a0000000 {
 		reg = <0xa0000000 0x04000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi
index 2cf896c505f9..9c455dcbe6eb 100644
--- a/arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi
+++ b/arch/arm/boot/dts/imx27-eukrea-cpuimx27.dtsi
@@ -16,21 +16,14 @@
 	model = "Eukrea CPUIMX27";
 	compatible = "eukrea,cpuimx27", "fsl,imx27";
 
-	memory {
+	memory@a0000000 {
 		reg = <0xa0000000 0x04000000>;
 	};
 
-	clocks {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "simple-bus";
-
-		clk14745600: clock@0 {
-			#clock-cells = <0>;
-			compatible = "fixed-clock";
-			clock-frequency = <14745600>;
-			reg = <0>;
-		};
+	clk14745600: clk-uart {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <14745600>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts
index f56535768ee8..15145e7f9778 100644
--- a/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts
+++ b/arch/arm/boot/dts/imx27-eukrea-mbimxsd27-baseboard.dts
@@ -84,7 +84,7 @@
 	cs-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>;
 	status = "okay";
 
-	ads7846 {
+	ads7846@0 {
 		compatible = "ti,ads7846";
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_touch>;
diff --git a/arch/arm/boot/dts/imx27-pdk.dts b/arch/arm/boot/dts/imx27-pdk.dts
index 2a140c8ae6d2..924b90c9985d 100644
--- a/arch/arm/boot/dts/imx27-pdk.dts
+++ b/arch/arm/boot/dts/imx27-pdk.dts
@@ -16,7 +16,7 @@
 	model = "Freescale i.MX27 Product Development Kit";
 	compatible = "fsl,imx27-pdk", "fsl,imx27";
 
-	memory {
+	memory@a0000000 {
 		reg = <0xa0000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dtsi b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dtsi
index 0b8490b21a38..cbad7c88c58c 100644
--- a/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dtsi
+++ b/arch/arm/boot/dts/imx27-phytec-phycard-s-som.dtsi
@@ -17,7 +17,7 @@
 	model = "Phytec pca100";
 	compatible = "phytec,imx27-pca100", "fsl,imx27";
 
-	memory {
+	memory@a0000000 {
 		reg = <0xa0000000 0x08000000>; /* 128MB */
 	};
 };
diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi
index c9095b7654c6..ec466b4bfd41 100644
--- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi
+++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi
@@ -16,7 +16,7 @@
 	model = "Phytec pcm038";
 	compatible = "phytec,imx27-pcm038", "fsl,imx27";
 
-	memory {
+	memory@a0000000 {
 		reg = <0xa0000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi
index 15d85f1f85fd..6585b00c3917 100644
--- a/arch/arm/boot/dts/imx27.dtsi
+++ b/arch/arm/boot/dts/imx27.dtsi
@@ -26,7 +26,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx28-apf28.dts b/arch/arm/boot/dts/imx28-apf28.dts
index 070e59cbdd8b..bab78346fa9f 100644
--- a/arch/arm/boot/dts/imx28-apf28.dts
+++ b/arch/arm/boot/dts/imx28-apf28.dts
@@ -16,7 +16,7 @@
 	model = "Armadeus Systems APF28 module";
 	compatible = "armadeus,imx28-apf28", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-apx4devkit.dts b/arch/arm/boot/dts/imx28-apx4devkit.dts
index ae078341fb60..1416a4b4f599 100644
--- a/arch/arm/boot/dts/imx28-apx4devkit.dts
+++ b/arch/arm/boot/dts/imx28-apx4devkit.dts
@@ -6,7 +6,7 @@
 	model = "Bluegiga APX4 Development Kit";
 	compatible = "bluegiga,apx4devkit", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x04000000>;
 	};
 
@@ -82,7 +82,8 @@
 					fsl,pull-up = <MXS_PULL_ENABLE>;
 				};
 
-				mmc2_sck_cfg_apx4: mmc2-sck-cfg-apx4 {
+				mmc2_sck_cfg_apx4: mmc2-sck-cfg-apx4@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_SSP0_DATA7__SSP2_SCK
 					>;
diff --git a/arch/arm/boot/dts/imx28-cfa10036.dts b/arch/arm/boot/dts/imx28-cfa10036.dts
index 570aa339a05e..e54f5aba7091 100644
--- a/arch/arm/boot/dts/imx28-cfa10036.dts
+++ b/arch/arm/boot/dts/imx28-cfa10036.dts
@@ -16,7 +16,7 @@
 	model = "Crystalfontz CFA-10036 Board";
 	compatible = "crystalfontz,cfa10036", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts
index 4cd52d53cf00..60e5c7fd5035 100644
--- a/arch/arm/boot/dts/imx28-cfa10049.dts
+++ b/arch/arm/boot/dts/imx28-cfa10049.dts
@@ -19,6 +19,71 @@
 	model = "Crystalfontz CFA-10049 Board";
 	compatible = "crystalfontz,cfa10049", "crystalfontz,cfa10036", "fsl,imx28";
 
+	i2cmux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2cmux_pins_cfa10049>;
+		mux-gpios = <&gpio1 22 0 &gpio1 23 0>;
+		i2c-parent = <&i2c1>;
+
+		i2c@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			adc0: nau7802@2a {
+				compatible = "nuvoton,nau7802";
+				reg = <0x2a>;
+				nuvoton,vldo = <3000>;
+			};
+		};
+
+		i2c@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			adc1: nau7802@2a {
+				compatible = "nuvoton,nau7802";
+				reg = <0x2a>;
+				nuvoton,vldo = <3000>;
+			};
+		};
+
+		i2c@2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2>;
+
+				adc2: nau7802@2a {
+				compatible = "nuvoton,nau7802";
+				reg = <0x2a>;
+				nuvoton,vldo = <3000>;
+			};
+		};
+
+		i2c@3 {
+			reg = <3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			pca9555: pca9555@20 {
+				compatible = "nxp,pca9555";
+				pinctrl-names = "default";
+				pinctrl-0 = <&pca_pins_cfa10049>;
+				interrupt-parent = <&gpio2>;
+				interrupts = <19 0x2>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x20>;
+			};
+		};
+	};
+
 	apb@80000000 {
 		apbh@80000000 {
 			pinctrl@80018000 {
@@ -219,71 +284,6 @@
 				status = "okay";
 			};
 
-			i2cmux {
-				compatible = "i2c-mux-gpio";
-				#address-cells = <1>;
-				#size-cells = <0>;
-				pinctrl-names = "default";
-				pinctrl-0 = <&i2cmux_pins_cfa10049>;
-				mux-gpios = <&gpio1 22 0 &gpio1 23 0>;
-				i2c-parent = <&i2c1>;
-
-				i2c@0 {
-					#address-cells = <1>;
-					#size-cells = <0>;
-					reg = <0>;
-
-					adc0: nau7802@2a {
-						compatible = "nuvoton,nau7802";
-						reg = <0x2a>;
-						nuvoton,vldo = <3000>;
-					};
-				};
-
-				i2c@1 {
-					#address-cells = <1>;
-					#size-cells = <0>;
-					reg = <1>;
-
-					adc1: nau7802@2a {
-						compatible = "nuvoton,nau7802";
-						reg = <0x2a>;
-						nuvoton,vldo = <3000>;
-					};
-				};
-
-				i2c@2 {
-					#address-cells = <1>;
-					#size-cells = <0>;
-					reg = <2>;
-
-					adc2: nau7802@2a {
-						compatible = "nuvoton,nau7802";
-						reg = <0x2a>;
-						nuvoton,vldo = <3000>;
-					};
-				};
-
-				i2c@3 {
-					reg = <3>;
-					#address-cells = <1>;
-					#size-cells = <0>;
-
-					pca9555: pca9555@20 {
-						compatible = "nxp,pca9555";
-						pinctrl-names = "default";
-						pinctrl-0 = <&pca_pins_cfa10049>;
-						interrupt-parent = <&gpio2>;
-						interrupts = <19 0x2>;
-						gpio-controller;
-						#gpio-cells = <2>;
-						interrupt-controller;
-						#interrupt-cells = <2>;
-						reg = <0x20>;
-					};
-				};
-			};
-
 			usbphy1: usbphy@8007e000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/imx28-duckbill-2-485.dts b/arch/arm/boot/dts/imx28-duckbill-2-485.dts
index bd3fd470f9c3..97084e463d7c 100644
--- a/arch/arm/boot/dts/imx28-duckbill-2-485.dts
+++ b/arch/arm/boot/dts/imx28-duckbill-2-485.dts
@@ -19,7 +19,7 @@
 	model = "I2SE Duckbill 2 485";
 	compatible = "i2se,duckbill-2-485", "i2se,duckbill-2", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts b/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts
index 4450047885eb..7f8d40a9c67e 100644
--- a/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts
+++ b/arch/arm/boot/dts/imx28-duckbill-2-enocean.dts
@@ -20,7 +20,7 @@
 	model = "I2SE Duckbill 2 EnOcean";
 	compatible = "i2se,duckbill-2-enocean", "i2se,duckbill-2", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-duckbill-2-spi.dts b/arch/arm/boot/dts/imx28-duckbill-2-spi.dts
index 927732efca98..13e7b134da9e 100644
--- a/arch/arm/boot/dts/imx28-duckbill-2-spi.dts
+++ b/arch/arm/boot/dts/imx28-duckbill-2-spi.dts
@@ -23,7 +23,7 @@
 		ethernet1 = &qca7000;
 	};
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-duckbill-2.dts b/arch/arm/boot/dts/imx28-duckbill-2.dts
index 7fa3d759505c..88556c93b00f 100644
--- a/arch/arm/boot/dts/imx28-duckbill-2.dts
+++ b/arch/arm/boot/dts/imx28-duckbill-2.dts
@@ -19,7 +19,7 @@
 	model = "I2SE Duckbill 2";
 	compatible = "i2se,duckbill-2", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-duckbill.dts b/arch/arm/boot/dts/imx28-duckbill.dts
index 3e4385d4ed78..f286bfe699be 100644
--- a/arch/arm/boot/dts/imx28-duckbill.dts
+++ b/arch/arm/boot/dts/imx28-duckbill.dts
@@ -18,7 +18,7 @@
 	model = "I2SE Duckbill";
 	compatible = "i2se,duckbill", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts b/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts
index 7c1572c5a4fb..b70f3349c350 100644
--- a/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts
+++ b/arch/arm/boot/dts/imx28-eukrea-mbmx283lc.dts
@@ -23,7 +23,7 @@
 	model = "Eukrea Electromatique MBMX283LC";
 	compatible = "eukrea,mbmx283lc", "eukrea,mbmx28lc", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x04000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts b/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts
index b61fd61eb1c7..65efb78ac040 100644
--- a/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts
+++ b/arch/arm/boot/dts/imx28-eukrea-mbmx287lc.dts
@@ -22,7 +22,7 @@
 	model = "Eukrea Electromatique MBMX287LC";
 	compatible = "eukrea,mbmx287lc", "eukrea,mbmx283lc", "eukrea,mbmx28lc", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts
index 7f5b80402c54..8ccbcc153c50 100644
--- a/arch/arm/boot/dts/imx28-evk.dts
+++ b/arch/arm/boot/dts/imx28-evk.dts
@@ -16,7 +16,7 @@
 	model = "Freescale i.MX28 Evaluation Kit";
 	compatible = "fsl,imx28-evk", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-m28.dtsi b/arch/arm/boot/dts/imx28-m28.dtsi
index a69856e41ba4..0ec415e1ff58 100644
--- a/arch/arm/boot/dts/imx28-m28.dtsi
+++ b/arch/arm/boot/dts/imx28-m28.dtsi
@@ -15,7 +15,7 @@
 	model = "Aries/DENX M28";
 	compatible = "aries,m28", "denx,m28", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-m28cu3.dts b/arch/arm/boot/dts/imx28-m28cu3.dts
index 9d6c8fe28d74..3bb5ffc644d6 100644
--- a/arch/arm/boot/dts/imx28-m28cu3.dts
+++ b/arch/arm/boot/dts/imx28-m28cu3.dts
@@ -16,7 +16,7 @@
 	model = "MSR M28CU3";
 	compatible = "msr,m28cu3", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-sps1.dts b/arch/arm/boot/dts/imx28-sps1.dts
index 0ce3cb8e7914..2393e83979e0 100644
--- a/arch/arm/boot/dts/imx28-sps1.dts
+++ b/arch/arm/boot/dts/imx28-sps1.dts
@@ -16,7 +16,7 @@
 	model = "SchulerControl GmbH, SC SPS 1";
 	compatible = "schulercontrol,imx28-sps1", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx28-ts4600.dts b/arch/arm/boot/dts/imx28-ts4600.dts
index 1e391c9f1b7a..f8a09a8c2c36 100644
--- a/arch/arm/boot/dts/imx28-ts4600.dts
+++ b/arch/arm/boot/dts/imx28-ts4600.dts
@@ -19,7 +19,7 @@
 	model = "Technologic Systems i.MX28 TS-4600";
 	compatible = "technologic,imx28-ts4600", "fsl,imx28";
 
-	memory {
+	memory@40000000 {
 		reg = <0x40000000 0x10000000>;   /* 256MB */
 	};
 
diff --git a/arch/arm/boot/dts/imx28-tx28.dts b/arch/arm/boot/dts/imx28-tx28.dts
index 152621ea37db..8a4f5bc19a57 100644
--- a/arch/arm/boot/dts/imx28-tx28.dts
+++ b/arch/arm/boot/dts/imx28-tx28.dts
@@ -531,7 +531,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_edt_ft5x06_pins: tx28-edt-ft5x06-pins {
+	tx28_edt_ft5x06_pins: tx28-edt-ft5x06-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_SSP0_DATA6__GPIO_2_6 /* RESET */
 			MX28_PAD_SSP0_DATA5__GPIO_2_5 /* IRQ */
@@ -542,7 +543,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_flexcan_xcvr_pins: tx28-flexcan-xcvr-pins {
+	tx28_flexcan_xcvr_pins: tx28-flexcan-xcvr-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_LCD_D00__GPIO_1_0
 		>;
@@ -551,7 +553,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_lcdif_23bit_pins: tx28-lcdif-23bit {
+	tx28_lcdif_23bit_pins: tx28-lcdif-23bit@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			/* LCD_D00 may be used as Flexcan Transceiver Enable on STK5-V5 */
 			MX28_PAD_LCD_D01__LCD_D1
@@ -583,7 +586,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_lcdif_ctrl_pins: tx28-lcdif-ctrl {
+	tx28_lcdif_ctrl_pins: tx28-lcdif-ctrl@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_LCD_ENABLE__GPIO_1_31 /* Enable */
 			MX28_PAD_LCD_RESET__GPIO_3_30  /* Reset */
@@ -593,7 +597,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_mac0_pins_gpio: tx28-mac0-gpio-pins {
+	tx28_mac0_pins_gpio: tx28-mac0-gpio-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_ENET0_MDC__GPIO_4_0
 			MX28_PAD_ENET0_MDIO__GPIO_4_1
@@ -610,7 +615,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_pca9554_pins: tx28-pca9554-pins {
+	tx28_pca9554_pins: tx28-pca9554-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_PWM3__GPIO_3_28
 		>;
@@ -619,7 +625,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_spi_gpio_pins: spi-gpiogrp {
+	tx28_spi_gpio_pins: spi-gpiogrp@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_AUART2_RX__GPIO_3_8
 			MX28_PAD_AUART2_TX__GPIO_3_9
@@ -633,7 +640,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_tsc2007_pins: tx28-tsc2007-pins {
+	tx28_tsc2007_pins: tx28-tsc2007-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_SAIF0_MCLK__GPIO_3_20 /* TSC2007 IRQ */
 		>;
@@ -643,7 +651,8 @@
 	};
 
 
-	tx28_usbphy0_pins: tx28-usbphy0-pins {
+	tx28_usbphy0_pins: tx28-usbphy0-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_GPMI_CE2N__GPIO_0_18 /* USBOTG_VBUSEN */
 			MX28_PAD_GPMI_CE3N__GPIO_0_19 /* USBOTH_OC */
@@ -653,7 +662,8 @@
 		fsl,pull-up = <MXS_PULL_DISABLE>;
 	};
 
-	tx28_usbphy1_pins: tx28-usbphy1-pins {
+	tx28_usbphy1_pins: tx28-usbphy1-pins@0 {
+		reg = <0>;
 		fsl,pinmux-ids = <
 			MX28_PAD_SPDIF__GPIO_3_27 /* USBH_VBUSEN */
 			MX28_PAD_JTAG_RTCK__GPIO_4_20 /* USBH_OC */
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index e52e05c0fe56..9ad8d3556859 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -24,7 +24,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &mac0;
@@ -283,7 +283,8 @@
 					fsl,pull-up = <MXS_PULL_DISABLE>;
 				};
 
-				gpmi_status_cfg: gpmi-status-cfg {
+				gpmi_status_cfg: gpmi-status-cfg@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_GPMI_RDN__GPMI_RDN
 						MX28_PAD_GPMI_WRN__GPMI_WRN
@@ -527,14 +528,16 @@
 					fsl,pull-up = <MXS_PULL_ENABLE>;
 				};
 
-				mmc0_cd_cfg: mmc0-cd-cfg {
+				mmc0_cd_cfg: mmc0-cd-cfg@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT
 					>;
 					fsl,pull-up = <MXS_PULL_DISABLE>;
 				};
 
-				mmc0_sck_cfg: mmc0-sck-cfg {
+				mmc0_sck_cfg: mmc0-sck-cfg@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_SSP0_SCK__SSP0_SCK
 					>;
@@ -558,14 +561,16 @@
 					fsl,pull-up = <MXS_PULL_ENABLE>;
 				};
 
-				mmc1_cd_cfg: mmc1-cd-cfg {
+				mmc1_cd_cfg: mmc1-cd-cfg@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_GPMI_RDY0__SSP1_CARD_DETECT
 					>;
 					fsl,pull-up = <MXS_PULL_DISABLE>;
 				};
 
-				mmc1_sck_cfg: mmc1-sck-cfg {
+				mmc1_sck_cfg: mmc1-sck-cfg@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_GPMI_WRN__SSP1_SCK
 					>;
@@ -606,7 +611,8 @@
 					fsl,pull-up = <MXS_PULL_ENABLE>;
 				};
 
-				mmc2_cd_cfg: mmc2-cd-cfg {
+				mmc2_cd_cfg: mmc2-cd-cfg@0 {
+					reg = <0>;
 					fsl,pinmux-ids = <
 						MX28_PAD_AUART1_RX__SSP2_CARD_DETECT
 					>;
diff --git a/arch/arm/boot/dts/imx31-bug.dts b/arch/arm/boot/dts/imx31-bug.dts
index ae6cebbed84b..6ee4ff8e4e8f 100644
--- a/arch/arm/boot/dts/imx31-bug.dts
+++ b/arch/arm/boot/dts/imx31-bug.dts
@@ -16,7 +16,7 @@
 	model = "Buglabs i.MX31 Bug 1.x";
 	compatible = "buglabs,imx31-bug", "fsl,imx31";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x8000000>; /* 128M */
 	};
 };
diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi
index a72031407ebd..ebc3f2dbb6fd 100644
--- a/arch/arm/boot/dts/imx31.dtsi
+++ b/arch/arm/boot/dts/imx31.dtsi
@@ -19,7 +19,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		serial0 = &uart1;
diff --git a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
index 9c2b715ab8bf..ba39d938f289 100644
--- a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
+++ b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
@@ -17,7 +17,7 @@
 	model = "Eukrea CPUIMX35";
 	compatible = "eukrea,cpuimx35", "fsl,imx35";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x8000000>; /* 128M */
 	};
 };
diff --git a/arch/arm/boot/dts/imx35-pdk.dts b/arch/arm/boot/dts/imx35-pdk.dts
index 9bb628f22502..646b1257bba2 100644
--- a/arch/arm/boot/dts/imx35-pdk.dts
+++ b/arch/arm/boot/dts/imx35-pdk.dts
@@ -17,7 +17,7 @@
 	model = "Freescale i.MX35 Product Development Kit";
 	compatible = "fsl,imx35-pdk", "fsl,imx35";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x8000000>,
 		      <0x90000000 0x8000000>;
 	};
diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi
index e08c0c193767..bf343195697e 100644
--- a/arch/arm/boot/dts/imx35.dtsi
+++ b/arch/arm/boot/dts/imx35.dtsi
@@ -20,7 +20,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx50-evk.dts b/arch/arm/boot/dts/imx50-evk.dts
index 98b5faa06e27..23f1833e23fa 100644
--- a/arch/arm/boot/dts/imx50-evk.dts
+++ b/arch/arm/boot/dts/imx50-evk.dts
@@ -18,7 +18,7 @@
 	model = "Freescale i.MX50 Evaluation Kit";
 	compatible = "fsl,imx50-evk", "fsl,imx50";
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx50.dtsi b/arch/arm/boot/dts/imx50.dtsi
index 35955e63d6c5..7954e79d0a16 100644
--- a/arch/arm/boot/dts/imx50.dtsi
+++ b/arch/arm/boot/dts/imx50.dtsi
@@ -25,7 +25,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx51-apf51.dts b/arch/arm/boot/dts/imx51-apf51.dts
index c83ac1600322..79d80036f74d 100644
--- a/arch/arm/boot/dts/imx51-apf51.dts
+++ b/arch/arm/boot/dts/imx51-apf51.dts
@@ -21,7 +21,7 @@
 	model = "Armadeus Systems APF51 module";
 	compatible = "armadeus,imx51-apf51", "fsl,imx51";
 
-	memory {
+	memory@90000000 {
 		reg = <0x90000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index 4ac5ab614a7f..51b12114b0fe 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -21,7 +21,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@90000000 {
 		reg = <0x90000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi
index b821066a0d2a..5761a66e8a0d 100644
--- a/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi
+++ b/arch/arm/boot/dts/imx51-digi-connectcore-som.dtsi
@@ -16,7 +16,7 @@
 	model = "Digi ConnectCore CC(W)-MX51";
 	compatible = "digi,connectcore-ccxmx51-som", "fsl,imx51";
 
-	memory {
+	memory@90000000 {
 		reg = <0x90000000 0x08000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
index 63164266af83..f8902a338e49 100644
--- a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
+++ b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
@@ -22,7 +22,7 @@
 	model = "Eukrea CPUIMX51";
 	compatible = "eukrea,cpuimx51", "fsl,imx51";
 
-	memory {
+	memory@90000000 {
 		reg = <0x90000000 0x10000000>; /* 256M */
 	};
 };
diff --git a/arch/arm/boot/dts/imx51-ts4800.dts b/arch/arm/boot/dts/imx51-ts4800.dts
index f59b02bae68d..39eb067904c3 100644
--- a/arch/arm/boot/dts/imx51-ts4800.dts
+++ b/arch/arm/boot/dts/imx51-ts4800.dts
@@ -17,7 +17,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@90000000 {
 		reg = <0x90000000 0x10000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts
index 5306b78de0ca..aa36204f917f 100644
--- a/arch/arm/boot/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts
@@ -51,6 +51,11 @@
 		stdout-path = &uart1;
 	};
 
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	aliases {
 		mdio-gpio0 = &mdio_gpio;
 		rtc0 = &ds1341;
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index 00d30bd70068..5d390a64e976 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -26,7 +26,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts
index 4486bc47d140..80fc00705d92 100644
--- a/arch/arm/boot/dts/imx53-ard.dts
+++ b/arch/arm/boot/dts/imx53-ard.dts
@@ -17,7 +17,7 @@
 	model = "Freescale i.MX53 Automotive Reference Design Board";
 	compatible = "fsl,imx53-ard", "fsl,imx53";
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx53-cx9020.dts b/arch/arm/boot/dts/imx53-cx9020.dts
index 5e67e43004e7..cf70ebc4399a 100644
--- a/arch/arm/boot/dts/imx53-cx9020.dts
+++ b/arch/arm/boot/dts/imx53-cx9020.dts
@@ -21,7 +21,7 @@
 		stdout-path = &uart2;
 	};
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x20000000>,
 		      <0xb0000000 0x20000000>;
 	};
diff --git a/arch/arm/boot/dts/imx53-m53.dtsi b/arch/arm/boot/dts/imx53-m53.dtsi
index 7ce69c63510c..3da6dd5edb79 100644
--- a/arch/arm/boot/dts/imx53-m53.dtsi
+++ b/arch/arm/boot/dts/imx53-m53.dtsi
@@ -15,7 +15,7 @@
 	model = "Aries/DENX M53";
 	compatible = "aries,imx53-m53", "denx,imx53-m53", "fsl,imx53";
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x20000000>,
 		      <0xb0000000 0x20000000>;
 	};
diff --git a/arch/arm/boot/dts/imx53-ppd.dts b/arch/arm/boot/dts/imx53-ppd.dts
index cce959438a79..57730ddfe000 100644
--- a/arch/arm/boot/dts/imx53-ppd.dts
+++ b/arch/arm/boot/dts/imx53-ppd.dts
@@ -132,6 +132,14 @@
 		enable-active-high;
 	};
 
+	reg_tsiref: regulator-tsiref {
+		compatible = "regulator-fixed";
+		regulator-name = "tsiref";
+		regulator-min-microvolt = <2500000>;
+		regulator-max-microvolt = <2500000>;
+		regulator-always-on;
+	};
+
 	pwm_bl: backlight {
 		compatible = "pwm-backlight";
 		pwms = <&pwm2 0 50000>;
@@ -294,6 +302,8 @@
 		interrupt-parent = <&gpio3>;
 		interrupts = <12 0x8>;
 		spi-max-frequency = <1000000>;
+		dlg,tsi-as-adc;
+		tsiref-supply = <&reg_tsiref>;
 
 		regulators {
 			buck1_reg: buck1 {
@@ -525,6 +535,7 @@
 
 	touchscreen@4b {
 		compatible = "atmel,maxtouch";
+		reset-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;
 		reg = <0x4b>;
 		interrupt-parent = <&gpio5>;
 		interrupts = <4 0x8>;
diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi b/arch/arm/boot/dts/imx53-qsb-common.dtsi
index 41a2e2a2b079..08ac46e564c3 100644
--- a/arch/arm/boot/dts/imx53-qsb-common.dtsi
+++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi
@@ -17,7 +17,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x20000000>,
 		      <0xb0000000 0x20000000>;
 	};
diff --git a/arch/arm/boot/dts/imx53-smd.dts b/arch/arm/boot/dts/imx53-smd.dts
index 51f4a42a55e2..fd030128666c 100644
--- a/arch/arm/boot/dts/imx53-smd.dts
+++ b/arch/arm/boot/dts/imx53-smd.dts
@@ -17,7 +17,7 @@
 	model = "Freescale i.MX53 Smart Mobile Reference Design Board";
 	compatible = "fsl,imx53-smd", "fsl,imx53";
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx53-tqma53.dtsi b/arch/arm/boot/dts/imx53-tqma53.dtsi
index eecdc1c55eef..a72b8981fc3b 100644
--- a/arch/arm/boot/dts/imx53-tqma53.dtsi
+++ b/arch/arm/boot/dts/imx53-tqma53.dtsi
@@ -16,7 +16,7 @@
 	model = "TQ TQMa53";
 	compatible = "tq,tqma53", "fsl,imx53";
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x40000000>; /* Up to 1GiB */
 	};
 
diff --git a/arch/arm/boot/dts/imx53-tx53.dtsi b/arch/arm/boot/dts/imx53-tx53.dtsi
index a22e461fc168..e77dd0a4e1b9 100644
--- a/arch/arm/boot/dts/imx53-tx53.dtsi
+++ b/arch/arm/boot/dts/imx53-tx53.dtsi
@@ -49,6 +49,11 @@
 	model = "Ka-Ro electronics TX53 module";
 	compatible = "karo,tx53", "fsl,imx53";
 
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	aliases {
 		can0 = &can2; /* Make the can interface indices consistent with TX28/TX48 modules */
 		can1 = &can1;
diff --git a/arch/arm/boot/dts/imx53-usbarmory.dts b/arch/arm/boot/dts/imx53-usbarmory.dts
index 6782d7fc5961..f6268d0ded29 100644
--- a/arch/arm/boot/dts/imx53-usbarmory.dts
+++ b/arch/arm/boot/dts/imx53-usbarmory.dts
@@ -57,7 +57,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@70000000 {
 		reg = <0x70000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 1040251f2951..7d647d043f52 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -26,7 +26,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx6dl-apf6dev.dts b/arch/arm/boot/dts/imx6dl-apf6dev.dts
index df26e542ab3a..4a7f86de6c39 100644
--- a/arch/arm/boot/dts/imx6dl-apf6dev.dts
+++ b/arch/arm/boot/dts/imx6dl-apf6dev.dts
@@ -54,7 +54,7 @@
 	model = "Armadeus APF6 Solo Module on APF6Dev Board";
 	compatible = "armadeus,imx6dl-apf6dev", "armadeus,imx6dl-apf6", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts b/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts
index 5f0d196495d0..7128c76d5721 100644
--- a/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts
+++ b/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts
@@ -48,7 +48,7 @@
 	model = "aristainetos2 i.MX6 Dual Lite Board 4";
 	compatible = "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts b/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts
index 805b1318b7f7..240f3661469f 100644
--- a/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts
+++ b/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts
@@ -48,7 +48,7 @@
 	model = "aristainetos2 i.MX6 Dual Lite Board 7";
 	compatible = "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6dl-aristainetos_4.dts b/arch/arm/boot/dts/imx6dl-aristainetos_4.dts
index 3c9f4af9e9ff..ad7733662fe5 100644
--- a/arch/arm/boot/dts/imx6dl-aristainetos_4.dts
+++ b/arch/arm/boot/dts/imx6dl-aristainetos_4.dts
@@ -27,7 +27,7 @@
 		status = "okay";
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6dl-aristainetos_7.dts b/arch/arm/boot/dts/imx6dl-aristainetos_7.dts
index 96cd835ccbf6..64ed84e3c512 100644
--- a/arch/arm/boot/dts/imx6dl-aristainetos_7.dts
+++ b/arch/arm/boot/dts/imx6dl-aristainetos_7.dts
@@ -16,7 +16,7 @@
 	model = "aristainetos i.MX6 Dual Lite Board 7";
 	compatible = "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
index dcf9206f3e0d..700e129d3865 100644
--- a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
@@ -53,6 +53,11 @@
 	compatible = "toradex,colibri_imx6dl-eval-v3", "toradex,colibri_imx6dl",
 		     "fsl,imx6dl";
 
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	aliases {
 		i2c0 = &i2c2;
 		i2c1 = &i2c3;
diff --git a/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts b/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts
index 994f96a3fb54..c195ad629024 100644
--- a/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts
+++ b/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts
@@ -20,4 +20,9 @@
 / {
 	model = "DFI FS700-M60-6DL i.MX6dl Q7 Board";
 	compatible = "dfi,fs700-m60-6dl", "dfi,fs700e-m60", "fsl,imx6dl";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts b/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts
new file mode 100644
index 000000000000..a8adcb2ec3fd
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-phytec-mira-rdk-nand.dts
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
+ */
+
+/dts-v1/;
+#include "imx6dl.dtsi"
+#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
+
+/ {
+	model = "PHYTEC phyBOARD-Mira DualLite/Solo Carrier-Board with NAND";
+	compatible = "phytec,imx6dl-pbac06-nand", "phytec,imx6dl-pbac06",
+		     "phytec,imx6qdl-pcm058", "fsl,imx6dl";
+
+	chosen {
+		linux,stdout-path = &uart2;
+	};
+};
+
+&ethphy {
+	max-speed = <100>;
+};
+
+&fec {
+	status = "okay";
+};
+
+&gpmi {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+};
+
+&i2c_rtc {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&usbh1 {
+	status = "okay";
+};
+
+&usbotg {
+	status = "okay";
+};
+
+&usdhc1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi
index 964bc2ad3c5d..7d9888937f12 100644
--- a/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi
+++ b/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi
@@ -16,7 +16,7 @@
 	model = "Phytec phyFLEX-i.MX6 DualLite/Solo";
 	compatible = "phytec,imx6dl-pfla02", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-rex-basic.dts b/arch/arm/boot/dts/imx6dl-rex-basic.dts
index c3a14a4330a2..3fb7f4ee2496 100644
--- a/arch/arm/boot/dts/imx6dl-rex-basic.dts
+++ b/arch/arm/boot/dts/imx6dl-rex-basic.dts
@@ -16,7 +16,7 @@
 	model = "Rex Basic i.MX6 Dual Lite Board";
 	compatible = "rex,imx6dl-rex-basic", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-riotboard.dts b/arch/arm/boot/dts/imx6dl-riotboard.dts
index 23e108204e1e..2e98c92adff7 100644
--- a/arch/arm/boot/dts/imx6dl-riotboard.dts
+++ b/arch/arm/boot/dts/imx6dl-riotboard.dts
@@ -15,7 +15,7 @@
 	model = "RIoTboard i.MX6S";
 	compatible = "riot,imx6s-riotboard", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6dl-ts4900.dts b/arch/arm/boot/dts/imx6dl-ts4900.dts
index 6ea0b780677d..e23f7891cf15 100644
--- a/arch/arm/boot/dts/imx6dl-ts4900.dts
+++ b/arch/arm/boot/dts/imx6dl-ts4900.dts
@@ -46,4 +46,9 @@
 / {
 	model = "Technologic Systems i.MX6 Solo/DualLite TS-4900 (Default Device Tree)";
 	compatible = "technologic,imx6dl-ts4900", "fsl,imx6dl";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-ts7970.dts b/arch/arm/boot/dts/imx6dl-ts7970.dts
index d104daf305d9..cae3313201a1 100644
--- a/arch/arm/boot/dts/imx6dl-ts7970.dts
+++ b/arch/arm/boot/dts/imx6dl-ts7970.dts
@@ -47,4 +47,9 @@
 / {
 	model = "Technologic Systems i.MX6 Solo/DualLite TS-7970 (Default Device Tree)";
 	compatible = "technologic,imx6dl-ts7970", "fsl,imx6dl";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-wandboard-revb1.dts b/arch/arm/boot/dts/imx6dl-wandboard-revb1.dts
index 8c314eee4fdd..5727fa48cfd5 100644
--- a/arch/arm/boot/dts/imx6dl-wandboard-revb1.dts
+++ b/arch/arm/boot/dts/imx6dl-wandboard-revb1.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 Dual Lite Board rev B1";
 	compatible = "wand,imx6dl-wandboard", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-wandboard-revd1.dts b/arch/arm/boot/dts/imx6dl-wandboard-revd1.dts
index aa4d4faaaec4..a72c07db7dda 100644
--- a/arch/arm/boot/dts/imx6dl-wandboard-revd1.dts
+++ b/arch/arm/boot/dts/imx6dl-wandboard-revd1.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 Dual Lite Board revD1";
 	compatible = "wand,imx6dl-wandboard", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6dl-wandboard.dts b/arch/arm/boot/dts/imx6dl-wandboard.dts
index bbb616723097..a09f274cd1f4 100644
--- a/arch/arm/boot/dts/imx6dl-wandboard.dts
+++ b/arch/arm/boot/dts/imx6dl-wandboard.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 Dual Lite Board";
 	compatible = "wand,imx6dl-wandboard", "fsl,imx6dl";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-apf6dev.dts b/arch/arm/boot/dts/imx6q-apf6dev.dts
index 4e4de821d9e5..5e72f81cdf8b 100644
--- a/arch/arm/boot/dts/imx6q-apf6dev.dts
+++ b/arch/arm/boot/dts/imx6q-apf6dev.dts
@@ -54,7 +54,7 @@
 	model = "Armadeus APF6 Quad / Dual Module on APF6Dev Board";
 	compatible = "armadeus,imx6q-apf6dev", "armadeus,imx6q-apf6", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts
index 4989d0bff10f..953a5b5a8ea4 100644
--- a/arch/arm/boot/dts/imx6q-arm2.dts
+++ b/arch/arm/boot/dts/imx6q-arm2.dts
@@ -18,7 +18,7 @@
 	model = "Freescale i.MX6 Quad Armadillo2 Board";
 	compatible = "fsl,imx6q-arm2", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-ba16.dtsi b/arch/arm/boot/dts/imx6q-ba16.dtsi
index 5fcb0372d58b..bf4bdb385de9 100644
--- a/arch/arm/boot/dts/imx6q-ba16.dtsi
+++ b/arch/arm/boot/dts/imx6q-ba16.dtsi
@@ -46,7 +46,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/imx6q-bx50v3.dtsi
index 916ea94d75ca..990e411cbca0 100644
--- a/arch/arm/boot/dts/imx6q-bx50v3.dtsi
+++ b/arch/arm/boot/dts/imx6q-bx50v3.dtsi
@@ -353,6 +353,14 @@
 	};
 };
 
+&pmu {
+	secure-reg-access;
+};
+
+&usdhc2 {
+	status = "disabled";
+};
+
 &usdhc4 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc4>;
diff --git a/arch/arm/boot/dts/imx6q-cm-fx6.dts b/arch/arm/boot/dts/imx6q-cm-fx6.dts
index bc7587c383f6..65ef4cacbc71 100644
--- a/arch/arm/boot/dts/imx6q-cm-fx6.dts
+++ b/arch/arm/boot/dts/imx6q-cm-fx6.dts
@@ -50,7 +50,7 @@
 	model = "CompuLab CM-FX6";
 	compatible = "compulab,cm-fx6", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts b/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts
index fd0ad9a8866c..a266fe6adaa3 100644
--- a/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts
+++ b/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts
@@ -20,4 +20,9 @@
 / {
 	model = "DFI FS700-M60-6QD i.MX6qd Q7 Board";
 	compatible = "dfi,fs700-m60-6qd", "dfi,fs700e-m60", "fsl,imx6q";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6q-display5.dtsi b/arch/arm/boot/dts/imx6q-display5.dtsi
index 09085fde3341..85232c7c36a0 100644
--- a/arch/arm/boot/dts/imx6q-display5.dtsi
+++ b/arch/arm/boot/dts/imx6q-display5.dtsi
@@ -47,7 +47,7 @@
 	model = "Liebherr (LWN) display5 i.MX6 Quad Board";
 	compatible = "lwn,display5", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
index f0316ea96898..b3c6a4a7897d 100644
--- a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
+++ b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
@@ -29,7 +29,7 @@
 		stmpe-i2c1 = &stmpe2;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
index e0aea782c666..fcd257bc5ac3 100644
--- a/arch/arm/boot/dts/imx6q-evi.dts
+++ b/arch/arm/boot/dts/imx6q-evi.dts
@@ -50,7 +50,7 @@
 	model = "Uniwest Evi";
 	compatible = "uniwest,imx6q-evi", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-gk802.dts b/arch/arm/boot/dts/imx6q-gk802.dts
index b715deb4ea46..0be375611382 100644
--- a/arch/arm/boot/dts/imx6q-gk802.dts
+++ b/arch/arm/boot/dts/imx6q-gk802.dts
@@ -18,7 +18,7 @@
 		stdout-path = &uart4;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-gw5400-a.dts b/arch/arm/boot/dts/imx6q-gw5400-a.dts
index 29adaa7c72f8..a8f70b4266ef 100644
--- a/arch/arm/boot/dts/imx6q-gw5400-a.dts
+++ b/arch/arm/boot/dts/imx6q-gw5400-a.dts
@@ -60,7 +60,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-h100.dts b/arch/arm/boot/dts/imx6q-h100.dts
index 8a2ea6c58902..dd24b465a4e5 100644
--- a/arch/arm/boot/dts/imx6q-h100.dts
+++ b/arch/arm/boot/dts/imx6q-h100.dts
@@ -49,6 +49,11 @@
 	model = "Auvidea H100";
 	compatible = "auvidea,h100", "fsl,imx6q";
 
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	aliases {
 		rtc0 = &rtc;
 		rtc1 = &snvs_rtc;
@@ -161,7 +166,7 @@
 	status = "okay";
 
 	eeprom: 24c02@51 {
-		compatible = "microchip,24c02", "at24";
+		compatible = "microchip,24c02", "atmel,24c02";
 		reg = <0x51>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-marsboard.dts b/arch/arm/boot/dts/imx6q-marsboard.dts
index 432291bedcf1..dd763f205819 100644
--- a/arch/arm/boot/dts/imx6q-marsboard.dts
+++ b/arch/arm/boot/dts/imx6q-marsboard.dts
@@ -47,7 +47,7 @@
 	model = "Embest MarS Board i.MX6Dual";
 	compatible = "embest,imx6q-marsboard", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-mccmon6.dts b/arch/arm/boot/dts/imx6q-mccmon6.dts
index cab36f48d5f1..b7e9f38cec72 100644
--- a/arch/arm/boot/dts/imx6q-mccmon6.dts
+++ b/arch/arm/boot/dts/imx6q-mccmon6.dts
@@ -19,7 +19,7 @@
 	model = "Liebherr (LWN) monitor6 i.MX6 Quad Board";
 	compatible = "lwn,mccmon6", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-novena.dts b/arch/arm/boot/dts/imx6q-novena.dts
index 7d7dc59507cf..43a0c32ea85f 100644
--- a/arch/arm/boot/dts/imx6q-novena.dts
+++ b/arch/arm/boot/dts/imx6q-novena.dts
@@ -55,6 +55,11 @@
 	model = "Kosagi Novena Dual/Quad";
 	compatible = "kosagi,imx6q-novena", "fsl,imx6q";
 
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	chosen {
 		stdout-path = &uart2;
 	};
diff --git a/arch/arm/boot/dts/imx6q-phytec-mira-rdk-emmc.dts b/arch/arm/boot/dts/imx6q-phytec-mira-rdk-emmc.dts
new file mode 100644
index 000000000000..8fdce3c8e5fa
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-phytec-mira-rdk-emmc.dts
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
+
+/ {
+	model = "PHYTEC phyBOARD-Mira Quad Carrier-Board with eMMC";
+	compatible = "phytec,imx6q-pbac06-emmc", "phytec,imx6q-pbac06",
+		     "phytec,imx6qdl-pcm058", "fsl,imx6q";
+
+	chosen {
+		linux,stdout-path = &uart2;
+	};
+};
+
+&can1 {
+	status = "okay";
+};
+
+&fec {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+};
+
+&i2c_rtc {
+	status = "okay";
+};
+
+&m25p80 {
+	status = "okay";
+};
+
+&pcie {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&usbh1 {
+	status = "okay";
+};
+
+&usbotg {
+	status = "okay";
+};
+
+&usdhc1 {
+	status = "okay";
+};
+
+&usdhc4 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-phytec-mira-rdk-nand.dts b/arch/arm/boot/dts/imx6q-phytec-mira-rdk-nand.dts
new file mode 100644
index 000000000000..8afa5ceb7d7c
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-phytec-mira-rdk-nand.dts
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
+
+/ {
+	model = "PHYTEC phyBOARD-Mira Quad Carrier-Board with NAND";
+	compatible = "phytec,imx6q-pbac06-nand", "phytec,imx6q-pbac06",
+		     "phytec,imx6qdl-pcm058", "fsl,imx6q";
+
+	chosen {
+		linux,stdout-path = &uart2;
+	};
+};
+
+&can1 {
+	status = "okay";
+};
+
+&fec {
+	status = "okay";
+};
+
+&gpmi {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+};
+
+&i2c_rtc {
+	status = "okay";
+};
+
+&m25p80 {
+	status = "okay";
+};
+
+&pcie {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&usbh1 {
+	status = "okay";
+};
+
+&usbotg {
+	status = "okay";
+};
+
+&usdhc1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi
index cd20d0a948de..fad858c30fe9 100644
--- a/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi
+++ b/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi
@@ -16,7 +16,7 @@
 	model = "Phytec phyFLEX-i.MX6 Quad";
 	compatible = "phytec,imx6q-pfla02", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-pistachio.dts b/arch/arm/boot/dts/imx6q-pistachio.dts
index 1effb58f304c..bd57b3b74db7 100644
--- a/arch/arm/boot/dts/imx6q-pistachio.dts
+++ b/arch/arm/boot/dts/imx6q-pistachio.dts
@@ -56,7 +56,7 @@
 		stdout-path = &uart4;
 	};
 
-	memory: memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-rex-pro.dts b/arch/arm/boot/dts/imx6q-rex-pro.dts
index 90ea61ae04e9..d6cae73b1927 100644
--- a/arch/arm/boot/dts/imx6q-rex-pro.dts
+++ b/arch/arm/boot/dts/imx6q-rex-pro.dts
@@ -16,7 +16,7 @@
 	model = "Rex Pro i.MX6 Quad Board";
 	compatible = "rex,imx6q-rex-pro", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-sbc6x.dts b/arch/arm/boot/dts/imx6q-sbc6x.dts
index 255733063ea4..b7aa2f0b9f53 100644
--- a/arch/arm/boot/dts/imx6q-sbc6x.dts
+++ b/arch/arm/boot/dts/imx6q-sbc6x.dts
@@ -12,7 +12,7 @@
 	model = "MicroSys sbc6x board";
 	compatible = "microsys,sbc6x", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-tbs2910.dts b/arch/arm/boot/dts/imx6q-tbs2910.dts
index a3cd7afac20a..505cba776a2d 100644
--- a/arch/arm/boot/dts/imx6q-tbs2910.dts
+++ b/arch/arm/boot/dts/imx6q-tbs2910.dts
@@ -59,7 +59,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6q-ts4900.dts b/arch/arm/boot/dts/imx6q-ts4900.dts
index fab76f8cd076..9cf7b375588d 100644
--- a/arch/arm/boot/dts/imx6q-ts4900.dts
+++ b/arch/arm/boot/dts/imx6q-ts4900.dts
@@ -46,6 +46,11 @@
 / {
 	model = "Technologic Systems i.MX6 Quad TS-4900 (Default Device Tree)";
 	compatible = "technologic,imx6q-ts4900", "fsl,imx6q";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
 
 &sata {
diff --git a/arch/arm/boot/dts/imx6q-ts7970.dts b/arch/arm/boot/dts/imx6q-ts7970.dts
index f19e18995e68..fd84fc53f1ea 100644
--- a/arch/arm/boot/dts/imx6q-ts7970.dts
+++ b/arch/arm/boot/dts/imx6q-ts7970.dts
@@ -47,6 +47,11 @@
 / {
 	model = "Technologic Systems i.MX6 Quad TS-7970 (Default Device Tree)";
 	compatible = "technologic,imx6q-ts7970", "fsl,imx6q";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
 
 &sata {
diff --git a/arch/arm/boot/dts/imx6q-wandboard-revb1.dts b/arch/arm/boot/dts/imx6q-wandboard-revb1.dts
index 9207d80f9cfb..b763352cddae 100644
--- a/arch/arm/boot/dts/imx6q-wandboard-revb1.dts
+++ b/arch/arm/boot/dts/imx6q-wandboard-revb1.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 Quad Board rev B1";
 	compatible = "wand,imx6q-wandboard", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-wandboard-revd1.dts b/arch/arm/boot/dts/imx6q-wandboard-revd1.dts
index e87ddb168669..8691fab21058 100644
--- a/arch/arm/boot/dts/imx6q-wandboard-revd1.dts
+++ b/arch/arm/boot/dts/imx6q-wandboard-revd1.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 Quad Board revD1";
 	compatible = "wand,imx6q-wandboard", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-wandboard.dts b/arch/arm/boot/dts/imx6q-wandboard.dts
index 4a8a6ee13e9f..2a3d98c1489a 100644
--- a/arch/arm/boot/dts/imx6q-wandboard.dts
+++ b/arch/arm/boot/dts/imx6q-wandboard.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 Quad Board";
 	compatible = "wand,imx6q-wandboard", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-zii-rdu2.dts b/arch/arm/boot/dts/imx6q-zii-rdu2.dts
index 6be8a1eea895..fe8b12f31a4c 100644
--- a/arch/arm/boot/dts/imx6q-zii-rdu2.dts
+++ b/arch/arm/boot/dts/imx6q-zii-rdu2.dts
@@ -47,4 +47,9 @@
 / {
 	model = "ZII RDU2 Board";
 	compatible = "zii,imx6q-zii-rdu2", "fsl,imx6q";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/imx6qdl-apalis.dtsi
index 4e776e036cbc..bd658db01290 100644
--- a/arch/arm/boot/dts/imx6qdl-apalis.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-apalis.dtsi
@@ -47,6 +47,11 @@
 	model = "Toradex Apalis iMX6Q/D Module";
 	compatible = "toradex,apalis_imx6q", "fsl,imx6q";
 
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	backlight: backlight {
 		compatible = "pwm-backlight";
 		pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index d1cfdc264126..4c5f5132345e 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -42,6 +42,11 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	ir_recv: ir-receiver {
 		compatible = "gpio-ir-receiver";
 		gpios = <&gpio3 9 1>;
diff --git a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
index dea8fc43c692..17a7b9c083d0 100644
--- a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
@@ -44,7 +44,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
index 363a44394dad..b8044681006c 100644
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -59,7 +59,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
index c75385c0cad0..629908fbaa32 100644
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -59,7 +59,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index eab75f3dbaf3..a1a6fb5541e1 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -59,7 +59,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
index 30d4662d4480..4e21b3849394 100644
--- a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
@@ -74,7 +74,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
index c67c10605070..81dae5b5bc87 100644
--- a/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw552x.dtsi
@@ -51,7 +51,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw553x.dtsi b/arch/arm/boot/dts/imx6qdl-gw553x.dtsi
index 1a0faa1a14c8..c5d95e8d2e09 100644
--- a/arch/arm/boot/dts/imx6qdl-gw553x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw553x.dtsi
@@ -80,7 +80,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw5903.dtsi b/arch/arm/boot/dts/imx6qdl-gw5903.dtsi
index 444425153fc7..368132274a91 100644
--- a/arch/arm/boot/dts/imx6qdl-gw5903.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw5903.dtsi
@@ -83,7 +83,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-gw5904.dtsi b/arch/arm/boot/dts/imx6qdl-gw5904.dtsi
index fd4b68be9fe9..58124adfd65b 100644
--- a/arch/arm/boot/dts/imx6qdl-gw5904.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw5904.dtsi
@@ -93,7 +93,7 @@
 		};
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
index 92583238ca4a..52eeeed11eb1 100644
--- a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
@@ -40,6 +40,11 @@
  */
 
 / {
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	chosen {
 		stdout-path = &uart1;
 	};
diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi
index dffbc92e0023..e68e7db0f3bd 100644
--- a/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi
@@ -40,6 +40,11 @@
  */
 
 / {
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
+
 	chosen {
 		stdout-path = &uart1;
 	};
diff --git a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
index b6220d62f6de..49daa2b7892d 100644
--- a/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore-rqs.dtsi
@@ -44,7 +44,7 @@
 #include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-icore.dtsi b/arch/arm/boot/dts/imx6qdl-icore.dtsi
index a1b469c142f1..b3a463a5908b 100644
--- a/arch/arm/boot/dts/imx6qdl-icore.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-icore.dtsi
@@ -45,7 +45,7 @@
 #include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
index 4cc4e23cf99c..aab088f318e8 100644
--- a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
@@ -46,7 +46,7 @@
 		stdout-path = &uart2;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
index fd05f7caa472..87ca6ead4098 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -46,7 +46,7 @@
 		stdout-path = &uart2;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0xF0000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
index 40942d6b94b3..f5b763d39285 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
@@ -46,7 +46,7 @@
 		stdout-path = &uart2;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
index 919b6b7619a4..596866b0a0d2 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
@@ -48,7 +48,7 @@
 		stdout-path = &uart2;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi
new file mode 100644
index 000000000000..9ebd438dce7d
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-phytec-mira.dtsi
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
+ */
+
+
+/ {
+	aliases {
+		rtc0 = &i2c_rtc;
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <7>;
+		power-supply = <&reg_backlight>;
+		pwms = <&pwm1 0 5000000>;
+		status = "okay";
+	};
+
+	gpio_leds: leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpioleds>;
+		status = "disabled";
+
+		red {
+			label = "phyboard-mira:red";
+			gpios = <&gpio5 22 GPIO_ACTIVE_HIGH>;
+		};
+
+		green {
+			label = "phyboard-mira:green";
+			gpios = <&gpio5 23 GPIO_ACTIVE_HIGH>;
+		};
+
+		blue {
+			label = "phyboard-mira:blue";
+			gpios = <&gpio5 24 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
+		};
+	};
+
+	reg_backlight: regulator-backlight {
+		compatible = "regulator-fixed";
+		regulator-name = "backlight_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	reg_en_switch: regulator-en-switch {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_en_switch>;
+		regulator-name = "Enable Switch";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		enable-active-high;
+		gpio = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+		regulator-always-on;
+	};
+
+	reg_flexcan1: regulator-flexcan1 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_flexcan1_en>;
+		regulator-name = "flexcan1-reg";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		gpio = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_panel: regulator-panel {
+		compatible = "regulator-fixed";
+		regulator-name = "panel-power-supply";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+	};
+
+	reg_pcie: regulator-pcie {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pcie_reg>;
+		regulator-name = "mPCIe_1V5";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		gpio = <&gpio3 0 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usb_h1_vbus: usb-h1-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usbh1_vbus>;
+		regulator-name = "usb_h1_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio2 18 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	reg_usbotg_vbus: usbotg-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usbotg_vbus>;
+		regulator-name = "usb_otg_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	panel {
+		compatible = "auo,g104sn02";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_panel_en>;
+		power-supply = <&reg_panel>;
+		enable-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
+		backlight = <&backlight>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&lvds0_out>;
+			};
+		};
+	};
+};
+
+&can1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_flexcan1>;
+	xceiver-supply = <&reg_flexcan1>;
+	status = "disabled";
+};
+
+&hdmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hdmicec>;
+	ddc-i2c-bus = <&i2c2>;
+	status = "disabled";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	clock-frequency = <400000>;
+	status = "disabled";
+
+	stmpe: touchctrl@44 {
+		compatible = "st,stmpe811";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_stmpe>;
+		reg = <0x44>;
+		interrupt-parent = <&gpio7>;
+		interrupts = <12 IRQ_TYPE_NONE>;
+		status = "disabled";
+
+		stmpe_touchscreen {
+			compatible = "st,stmpe-ts";
+			st,sample-time = <4>;
+			st,mod-12b = <1>;
+			st,ref-sel = <0>;
+			st,adc-freq = <1>;
+			st,ave-ctrl = <1>;
+			st,touch-det-delay = <2>;
+			st,settling = <2>;
+			st,fraction-z = <7>;
+			st,i-drive = <1>;
+		};
+	};
+
+	i2c_rtc: rtc@68 {
+		compatible = "microcrystal,rv4162";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_rtc_int>;
+		reg = <0x68>;
+		interrupt-parent = <&gpio7>;
+		interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	clock-frequency = <100000>;
+	status = "disabled";
+};
+
+&ldb {
+	status = "okay";
+
+	lvds-channel@0 {
+		fsl,data-mapping = "spwg";
+		fsl,data-width = <24>;
+		status = "disabled";
+
+		port@4 {
+			reg = <4>;
+
+			lvds0_out: endpoint {
+				remote-endpoint = <&panel_in>;
+			};
+		};
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	reset-gpio = <&gpio2 25 GPIO_ACTIVE_LOW>;
+	vpcie-supply = <&reg_pcie>;
+	status = "disabled";
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	uart-has-rtscts;
+	status = "disabled";
+};
+
+&usbh1 {
+	vbus-supply = <&reg_usb_h1_vbus>;
+	disable-over-current;
+	status = "disabled";
+};
+
+&usbotg {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg>;
+	vbus-supply = <&reg_usbotg_vbus>;
+	disable-over-current;
+	status = "disabled";
+};
+
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	cd-gpios = <&gpio6 31 GPIO_ACTIVE_LOW>;
+	no-1-8-v;
+	status = "disabled";
+};
+
+&iomuxc {
+	pinctrl_panel_en: panelen1grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_EB0__GPIO2_IO28		0xb0b1
+		>;
+	};
+
+	pinctrl_en_switch: enswitchgrp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_DA4__GPIO3_IO04		0xb0b1
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_7__FLEXCAN1_TX		0x1b0b0
+			MX6QDL_PAD_GPIO_8__FLEXCAN1_RX		0x1b0b0
+		>;
+	};
+
+	pinctrl_flexcan1_en: flexcan1engrp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_A18__GPIO2_IO20		0xb0b1
+		>;
+	};
+
+	pinctrl_gpioleds: gpioledsgrp {
+		fsl,pins = <
+			MX6QDL_PAD_CSI0_DAT4__GPIO5_IO22	0x1b0b0
+			MX6QDL_PAD_CSI0_DAT5__GPIO5_IO23	0x1b0b0
+			MX6QDL_PAD_CSI0_DAT6__GPIO5_IO24	0x1b0b0
+		>;
+	};
+
+	pinctrl_hdmicec: hdmicecgrp {
+		fsl,pins = <
+			MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE	0x1f8b0
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
+			MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D21__I2C1_SCL		0x4001b8b1
+			MX6QDL_PAD_EIM_D28__I2C1_SDA		0x4001b8b1
+		>;
+	};
+
+	pinctrl_pcie: pciegrp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_OE__GPIO2_IO25		0xb0b1
+		>;
+	};
+
+	pinctrl_pcie_reg: pciereggrp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_DA0__GPIO3_IO00		0xb0b1
+		>;
+	};
+
+	pinctrl_pwm1: pwm1grp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_9__PWM1_OUT		0x1b0b1
+		>;
+	};
+
+	pinctrl_rtc_int: rtcintgrp {
+		fsl,pins = <
+			MX6QDL_PAD_SD3_RST__GPIO7_IO08		0x1b0b0
+		>;
+	};
+
+	pinctrl_stmpe: stmpegrp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_17__GPIO7_IO12		0x1b0b0
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D26__UART2_TX_DATA	0x1b0b1
+			MX6QDL_PAD_EIM_D27__UART2_RX_DATA	0x1b0b1
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_EB3__UART3_CTS_B		0x1b0b1
+			MX6QDL_PAD_EIM_D23__UART3_RTS_B		0x1b0b1
+			MX6QDL_PAD_EIM_D24__UART3_TX_DATA	0x1b0b1
+			MX6QDL_PAD_EIM_D25__UART3_RX_DATA	0x1b0b1
+		>;
+	};
+
+	pinctrl_usbh1_vbus: usbh1vbusgrp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_A20__GPIO2_IO18		0xb0b1
+		>;
+	};
+
+	pinctrl_usbotg: usbotggrp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_1__USB_OTG_ID		0x17059
+		>;
+	};
+
+	pinctrl_usbotg_vbus: usbotgvbusgrp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_A19__GPIO2_IO19		0xb0b1
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX6QDL_PAD_SD1_CMD__SD1_CMD		0x170f9
+			MX6QDL_PAD_SD1_CLK__SD1_CLK		0x100f9
+			MX6QDL_PAD_SD1_DAT0__SD1_DATA0		0x170f9
+			MX6QDL_PAD_SD1_DAT1__SD1_DATA1		0x170f9
+			MX6QDL_PAD_SD1_DAT2__SD1_DATA2		0x170f9
+			MX6QDL_PAD_SD1_DAT3__SD1_DATA3		0x170f9
+			MX6QDL_PAD_EIM_BCLK__GPIO6_IO31		0xb0b1  /* CD */
+		>;
+	};
+};
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
index d81b0078a100..c58f3443d55d 100644
--- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
@@ -15,7 +15,7 @@
 	model = "Phytec phyFLEX-i.MX6 Quad";
 	compatible = "phytec,imx6q-pfla02", "fsl,imx6q";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi
new file mode 100644
index 000000000000..6486df3e2942
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 PHYTEC Messtechnik GmbH
+ * Author: Christian Hemp <c.hemp@phytec.de>
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	aliases {
+		rtc1 = &da9062_rtc;
+		rtc2 = &snvs_rtc;
+	};
+
+	/*
+	 * Set the minimum memory size here and
+	 * let the bootloader set the real size.
+	 */
+	memory@10000000 {
+		device_type = "memory";
+		reg = <0x10000000 0x8000000>;
+	};
+
+	gpio_leds_som: somleds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpioleds_som>;
+
+		som-led-green {
+			label = "phycore:green";
+			gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+};
+
+&ecspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	cs-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	m25p80: flash@0 {
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+		status = "disabled";
+	};
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet>;
+	phy-handle = <&ethphy>;
+	phy-mode = "rgmii";
+	phy-supply = <&vdd_eth_io>;
+	phy-reset-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+	status = "disabled";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy: ethernet-phy@3 {
+			reg = <3>;
+			txc-skew-ps = <1680>;
+			rxc-skew-ps = <1860>;
+		};
+	};
+};
+
+&gpmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpmi_nand>;
+	nand-on-flash-bbt;
+	status = "disabled";
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	clock-frequency = <400000>;
+	status = "okay";
+
+	eeprom@50 {
+		compatible = "atmel,24c32";
+		reg = <0x50>;
+	};
+
+	pmic@58 {
+		compatible = "dlg,da9062";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pmic>;
+		reg = <0x58>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-controller;
+
+		da9062_rtc: rtc {
+			compatible = "dlg,da9062-rtc";
+		};
+
+		watchdog {
+			compatible = "dlg,da9062-watchdog";
+		};
+
+		regulators {
+			vdd_arm: buck1 {
+				regulator-name = "vdd_arm";
+				regulator-min-microvolt = <730000>;
+				regulator-max-microvolt = <1380000>;
+				regulator-always-on;
+			};
+
+			vdd_soc: buck2 {
+				regulator-name = "vdd_soc";
+				regulator-min-microvolt = <730000>;
+				regulator-max-microvolt = <1380000>;
+				regulator-always-on;
+			};
+
+			vdd_ddr3_1p5: buck3 {
+				regulator-name = "vdd_ddr3";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+			};
+
+			vdd_eth_1p2: buck4 {
+				regulator-name = "vdd_eth";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			vdd_snvs: ldo1 {
+				regulator-name = "vdd_snvs";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+
+			vdd_high: ldo2 {
+				regulator-name = "vdd_high";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+
+			vdd_eth_io: ldo3 {
+				regulator-name = "vdd_eth_io";
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+			};
+
+			vdd_emmc_1p8: ldo4 {
+				regulator-name = "vdd_emmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+		};
+	};
+};
+
+&reg_arm {
+	vin-supply = <&vdd_arm>;
+};
+
+&reg_pu {
+	vin-supply = <&vdd_soc>;
+};
+
+&reg_soc {
+	vin-supply = <&vdd_soc>;
+};
+
+&snvs_poweroff {
+	status = "okay";
+};
+
+&usdhc4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc4>;
+	bus-width = <8>;
+	non-removable;
+	vmmc-supply = <&vdd_emmc_1p8>;
+	status = "disabled";
+};
+
+&iomuxc {
+	pinctrl_enet: enetgrp {
+		fsl,pins = <
+			MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x1b0b0
+			MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
+			MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x1b0b0
+			MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b0b0
+			MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b0b0
+			MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b0b0
+			MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b0b0
+			MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b0b0
+			MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x1b0b0
+			MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
+			MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b0b0
+			MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b0b0
+			MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
+			MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
+			MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
+			MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN	0x1b0b0
+			MX6QDL_PAD_SD2_DAT1__GPIO1_IO14		0x1b0b0
+		>;
+	};
+
+	pinctrl_gpioleds_som: gpioledssomgrp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_4__GPIO1_IO04		0x1b0b0
+		>;
+	};
+
+	pinctrl_gpmi_nand: gpminandgrp {
+		fsl,pins = <
+			MX6QDL_PAD_NANDF_CLE__NAND_CLE		0xb0b1
+			MX6QDL_PAD_NANDF_ALE__NAND_ALE		0xb0b1
+			MX6QDL_PAD_NANDF_WP_B__NAND_WP_B	0xb0b1
+			MX6QDL_PAD_NANDF_RB0__NAND_READY_B	0xb000
+			MX6QDL_PAD_NANDF_CS0__NAND_CE0_B	0xb0b1
+			MX6QDL_PAD_NANDF_CS1__NAND_CE1_B	0xb0b1
+			MX6QDL_PAD_NANDF_CS2__NAND_CE2_B	0xb0b1
+			MX6QDL_PAD_NANDF_CS3__NAND_CE3_B	0xb0b1
+			MX6QDL_PAD_SD4_CMD__NAND_RE_B		0xb0b1
+			MX6QDL_PAD_SD4_CLK__NAND_WE_B		0xb0b1
+			MX6QDL_PAD_NANDF_D0__NAND_DATA00	0xb0b1
+			MX6QDL_PAD_NANDF_D1__NAND_DATA01	0xb0b1
+			MX6QDL_PAD_NANDF_D2__NAND_DATA02	0xb0b1
+			MX6QDL_PAD_NANDF_D3__NAND_DATA03	0xb0b1
+			MX6QDL_PAD_NANDF_D4__NAND_DATA04	0xb0b1
+			MX6QDL_PAD_NANDF_D5__NAND_DATA05	0xb0b1
+			MX6QDL_PAD_NANDF_D6__NAND_DATA06	0xb0b1
+			MX6QDL_PAD_NANDF_D7__NAND_DATA07	0xb0b1
+			MX6QDL_PAD_SD4_DAT0__NAND_DQS		0x00b1
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_6__I2C3_SDA		0x4001b8b1
+			MX6QDL_PAD_GPIO_5__I2C3_SCL		0x4001b8b1
+		>;
+	};
+
+	pinctrl_ecspi1: ecspi1grp {
+		fsl,pins = <
+			MX6QDL_PAD_EIM_D16__ECSPI1_SCLK		0x100b1
+			MX6QDL_PAD_EIM_D17__ECSPI1_MISO		0x100b1
+			MX6QDL_PAD_EIM_D18__ECSPI1_MOSI		0x100b1
+			MX6QDL_PAD_EIM_D19__GPIO3_IO19		0x1b0b0
+		>;
+	};
+
+	pinctrl_pmic: pmicgrp {
+		fsl,pins = <
+			MX6QDL_PAD_GPIO_2__GPIO1_IO02		0x1b0b0
+		>;
+	};
+
+	pinctrl_usdhc4: usdhc4grp {
+		fsl,pins = <
+			MX6QDL_PAD_SD4_CMD__SD4_CMD		0x17059
+			MX6QDL_PAD_SD4_CLK__SD4_CLK		0x10059
+			MX6QDL_PAD_SD4_DAT0__SD4_DATA0		0x17059
+			MX6QDL_PAD_SD4_DAT1__SD4_DATA1		0x17059
+			MX6QDL_PAD_SD4_DAT2__SD4_DATA2		0x17059
+			MX6QDL_PAD_SD4_DAT3__SD4_DATA3		0x17059
+			MX6QDL_PAD_SD4_DAT4__SD4_DATA4		0x17059
+			MX6QDL_PAD_SD4_DAT5__SD4_DATA5		0x17059
+			MX6QDL_PAD_SD4_DAT6__SD4_DATA6		0x17059
+			MX6QDL_PAD_SD4_DAT7__SD4_DATA7		0x17059
+		>;
+	};
+};
diff --git a/arch/arm/boot/dts/imx6qdl-rex.dtsi b/arch/arm/boot/dts/imx6qdl-rex.dtsi
index 6e9549ff11da..039e3b8306c4 100644
--- a/arch/arm/boot/dts/imx6qdl-rex.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-rex.dtsi
@@ -137,7 +137,7 @@
 	status = "okay";
 
 	eeprom@57 {
-		compatible = "at,24c02";
+		compatible = "atmel,24c02";
 		reg = <0x57>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 82d6ccb46982..54b0139e978d 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -13,7 +13,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index 35de7adc997b..18b65052553d 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -49,7 +49,7 @@
 		stdout-path = &uart2;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index 0a50705b9c18..f019f9900369 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -19,7 +19,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
index 4161b7d4323a..906387915dc5 100644
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
@@ -35,7 +35,7 @@
 		pinctrl-names = "default";
 	};
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-var-dart.dtsi b/arch/arm/boot/dts/imx6qdl-var-dart.dtsi
index 421d6f527609..38080c1dfaec 100644
--- a/arch/arm/boot/dts/imx6qdl-var-dart.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-var-dart.dtsi
@@ -10,7 +10,7 @@
 #include <dt-bindings/sound/fsl-imx-audmux.h>
 
 / {
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
index 72f52fcecee1..f81ae0cfc6ac 100644
--- a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi
@@ -498,7 +498,7 @@
 	};
 
 	eeprom@54 {
-		compatible = "at,24c128";
+		compatible = "atmel,24c128";
 		reg = <0x54>;
 	};
 
@@ -805,6 +805,10 @@
 	};
 };
 
+&wdog1 {
+	status = "disabled";
+};
+
 &iomuxc {
 	pinctrl_accel: accelgrp {
 		fsl,pins = <
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 59ff86695a14..c003e62bf290 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -23,7 +23,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
@@ -143,7 +143,7 @@
 		};
 	};
 
-	pmu {
+	pmu: pmu {
 		compatible = "arm,cortex-a9-pmu";
 		interrupt-parent = <&gpc>;
 		interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/imx6qp-phytec-mira-rdk-nand.dts b/arch/arm/boot/dts/imx6qp-phytec-mira-rdk-nand.dts
new file mode 100644
index 000000000000..3618e5316bf4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qp-phytec-mira-rdk-nand.dts
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2018 PHYTEC Messtechnik GmbH
+ * Author: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
+ */
+
+/dts-v1/;
+#include "imx6qp.dtsi"
+#include "imx6qdl-phytec-phycore-som.dtsi"
+#include "imx6qdl-phytec-mira.dtsi"
+
+/ {
+	model = "PHYTEC phyBOARD-Mira QuadPlus Carrier-Board with NAND";
+	compatible = "phytec,imx6qp-pbac06-nand", "phytec,imx6qp-pbac06",
+		     "phytec,imx6qdl-pcm058", "fsl,imx6qp";
+
+	chosen {
+		linux,stdout-path = &uart2;
+	};
+};
+
+&can1 {
+	status = "okay";
+};
+
+&fec {
+	status = "okay";
+};
+
+&gpmi {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+};
+
+&i2c_rtc {
+	status = "okay";
+};
+
+&m25p80 {
+	status = "okay";
+};
+
+&pcie {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&usbh1 {
+	status = "okay";
+};
+
+&usbotg {
+	status = "okay";
+};
+
+&usdhc1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qp-wandboard-revd1.dts b/arch/arm/boot/dts/imx6qp-wandboard-revd1.dts
index f7badd82ce8a..907ba0c74ba6 100644
--- a/arch/arm/boot/dts/imx6qp-wandboard-revd1.dts
+++ b/arch/arm/boot/dts/imx6qp-wandboard-revd1.dts
@@ -16,7 +16,7 @@
 	model = "Wandboard i.MX6 QuadPlus Board revD1";
 	compatible = "wand,imx6qp-wandboard", "fsl,imx6qp";
 
-	memory {
+	memory@10000000 {
 		reg = <0x10000000 0x80000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6qp-zii-rdu2.dts b/arch/arm/boot/dts/imx6qp-zii-rdu2.dts
index 547a76677ab3..96ab983918e4 100644
--- a/arch/arm/boot/dts/imx6qp-zii-rdu2.dts
+++ b/arch/arm/boot/dts/imx6qp-zii-rdu2.dts
@@ -47,4 +47,9 @@
 / {
 	model = "ZII RDU2+ Board";
 	compatible = "zii,imx6qp-zii-rdu2", "fsl,imx6qp";
+
+	/* Will be filled by the bootloader */
+	memory {
+		reg = <0 0>;
+	};
 };
diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 2844ab541759..37e792fdc160 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -16,7 +16,7 @@
 	model = "Freescale i.MX6 SoloLite EVK Board";
 	compatible = "fsl,imx6sl-evk", "fsl,imx6sl";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6sl-warp.dts b/arch/arm/boot/dts/imx6sl-warp.dts
index 72c7745f51d3..404e602e6781 100644
--- a/arch/arm/boot/dts/imx6sl-warp.dts
+++ b/arch/arm/boot/dts/imx6sl-warp.dts
@@ -54,7 +54,7 @@
 	model = "WaRP Board";
 	compatible = "warp,imx6sl-warp", "fsl,imx6sl";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index ae8df3cf687e..ab6a7e2e7e8f 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -21,7 +21,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec;
diff --git a/arch/arm/boot/dts/imx6sx-nitrogen6sx.dts b/arch/arm/boot/dts/imx6sx-nitrogen6sx.dts
index f9d40ee14982..b58f770c40d9 100644
--- a/arch/arm/boot/dts/imx6sx-nitrogen6sx.dts
+++ b/arch/arm/boot/dts/imx6sx-nitrogen6sx.dts
@@ -52,7 +52,7 @@
 		t_lcd = &t_lcd;
 	};
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6sx-sabreauto.dts b/arch/arm/boot/dts/imx6sx-sabreauto.dts
index 240a2864d044..72da5acf35a2 100644
--- a/arch/arm/boot/dts/imx6sx-sabreauto.dts
+++ b/arch/arm/boot/dts/imx6sx-sabreauto.dts
@@ -14,7 +14,7 @@
 	model = "Freescale i.MX6 SoloX Sabre Auto Board";
 	compatible = "fsl,imx6sx-sabreauto", "fsl,imx6sx";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6sx-sdb.dtsi b/arch/arm/boot/dts/imx6sx-sdb.dtsi
index d35aa858f9db..f8f31872fa14 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dtsi
+++ b/arch/arm/boot/dts/imx6sx-sdb.dtsi
@@ -20,7 +20,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6sx-softing-vining-2000.dts b/arch/arm/boot/dts/imx6sx-softing-vining-2000.dts
index 4d8c6521845f..252175b59247 100644
--- a/arch/arm/boot/dts/imx6sx-softing-vining-2000.dts
+++ b/arch/arm/boot/dts/imx6sx-softing-vining-2000.dts
@@ -20,7 +20,7 @@
 		stdout-path = &uart1;
 	};
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6sx-udoo-neo-basic.dts b/arch/arm/boot/dts/imx6sx-udoo-neo-basic.dts
index 0c1fc1a8f913..40ccdf43dffc 100644
--- a/arch/arm/boot/dts/imx6sx-udoo-neo-basic.dts
+++ b/arch/arm/boot/dts/imx6sx-udoo-neo-basic.dts
@@ -48,7 +48,7 @@
 	model = "UDOO Neo Basic";
 	compatible = "udoo,neobasic", "fsl,imx6sx";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x20000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6sx-udoo-neo-extended.dts b/arch/arm/boot/dts/imx6sx-udoo-neo-extended.dts
index 5d6c2274ee2b..42bfc8f8f7f6 100644
--- a/arch/arm/boot/dts/imx6sx-udoo-neo-extended.dts
+++ b/arch/arm/boot/dts/imx6sx-udoo-neo-extended.dts
@@ -48,7 +48,7 @@
 	model = "UDOO Neo Extended";
 	compatible = "udoo,neoextended", "fsl,imx6sx";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6sx-udoo-neo-full.dts b/arch/arm/boot/dts/imx6sx-udoo-neo-full.dts
index 653ceb29e28b..c84c877f09d4 100644
--- a/arch/arm/boot/dts/imx6sx-udoo-neo-full.dts
+++ b/arch/arm/boot/dts/imx6sx-udoo-neo-full.dts
@@ -48,7 +48,7 @@
 	model = "UDOO Neo Full";
 	compatible = "udoo,neofull", "fsl,imx6sx";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index fd7879342d0d..3d04201b599c 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -22,7 +22,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		can0 = &flexcan1;
@@ -188,6 +188,7 @@
 				 <&clks IMX6SX_CLK_GPU>,
 				 <&clks IMX6SX_CLK_GPU>;
 			clock-names = "bus", "core", "shader";
+			power-domains = <&pd_pu>;
 		};
 
 		dma_apbh: dma-apbh@1804000 {
@@ -767,6 +768,18 @@
 					#address-cells = <1>;
 					#size-cells = <0>;
 
+					power-domain@0 {
+						reg = <0>;
+						#power-domain-cells = <0>;
+					};
+
+					pd_pu: power-domain@1 {
+						reg = <1>;
+						#power-domain-cells = <0>;
+						power-supply = <&reg_soc>;
+						clocks = <&clks IMX6SX_CLK_GPU>;
+					};
+
 					pd_pci: power-domain@3 {
 						reg = <3>;
 						#power-domain-cells = <0>;
diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
index 18fdb088ba1e..6d720b20e7ed 100644
--- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
@@ -9,487 +9,9 @@
 /dts-v1/;
 
 #include "imx6ul.dtsi"
+#include "imx6ul-14x14-evk.dtsi"
 
 / {
 	model = "Freescale i.MX6 UltraLite 14x14 EVK Board";
 	compatible = "fsl,imx6ul-14x14-evk", "fsl,imx6ul";
-
-	chosen {
-		stdout-path = &uart1;
-	};
-
-	memory {
-		reg = <0x80000000 0x20000000>;
-	};
-
-	backlight_display: backlight-display {
-		compatible = "pwm-backlight";
-		pwms = <&pwm1 0 5000000>;
-		brightness-levels = <0 4 8 16 32 64 128 255>;
-		default-brightness-level = <6>;
-		status = "okay";
-	};
-
-
-	reg_sd1_vmmc: regulator-sd1-vmmc {
-		compatible = "regulator-fixed";
-		regulator-name = "VSD_3V3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-	};
-
-	sound {
-		compatible = "simple-audio-card";
-		simple-audio-card,name = "mx6ul-wm8960";
-		simple-audio-card,format = "i2s";
-		simple-audio-card,bitclock-master = <&dailink_master>;
-		simple-audio-card,frame-master = <&dailink_master>;
-		simple-audio-card,widgets =
-			"Microphone", "Mic Jack",
-			"Line", "Line In",
-			"Line", "Line Out",
-			"Speaker", "Speaker",
-			"Headphone", "Headphone Jack";
-		simple-audio-card,routing =
-			"Headphone Jack", "HP_L",
-			"Headphone Jack", "HP_R",
-			"Speaker", "SPK_LP",
-			"Speaker", "SPK_LN",
-			"Speaker", "SPK_RP",
-			"Speaker", "SPK_RN",
-			"LINPUT1", "Mic Jack",
-			"LINPUT3", "Mic Jack",
-			"RINPUT1", "Mic Jack",
-			"RINPUT2", "Mic Jack";
-
-		simple-audio-card,cpu {
-			sound-dai = <&sai2>;
-		};
-
-		dailink_master: simple-audio-card,codec {
-			sound-dai = <&codec>;
-			clocks = <&clks IMX6UL_CLK_SAI2>;
-		};
-	};
-
-	panel {
-		compatible = "innolux,at043tn24";
-		backlight = <&backlight_display>;
-
-		port {
-			panel_in: endpoint {
-				remote-endpoint = <&display_out>;
-			};
-		};
-	};
-};
-
-&clks {
-	assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
-	assigned-clock-rates = <786432000>;
-};
-
-&i2c2 {
-	clock_frequency = <100000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c2>;
-	status = "okay";
-
-	codec: wm8960@1a {
-		#sound-dai-cells = <0>;
-		compatible = "wlf,wm8960";
-		reg = <0x1a>;
-		wlf,shared-lrclk;
-	};
-};
-
-&fec1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_enet1>;
-	phy-mode = "rmii";
-	phy-handle = <&ethphy0>;
-	status = "okay";
-};
-
-&fec2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_enet2>;
-	phy-mode = "rmii";
-	phy-handle = <&ethphy1>;
-	status = "okay";
-
-	mdio {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		ethphy0: ethernet-phy@2 {
-			reg = <2>;
-			micrel,led-mode = <1>;
-			clocks = <&clks IMX6UL_CLK_ENET_REF>;
-			clock-names = "rmii-ref";
-		};
-
-		ethphy1: ethernet-phy@1 {
-			reg = <1>;
-			micrel,led-mode = <1>;
-			clocks = <&clks IMX6UL_CLK_ENET2_REF>;
-			clock-names = "rmii-ref";
-		};
-	};
-};
-
-
-&lcdif {
-	assigned-clocks = <&clks IMX6UL_CLK_LCDIF_PRE_SEL>;
-	assigned-clock-parents = <&clks IMX6UL_CLK_PLL5_VIDEO_DIV>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_lcdif_dat
-		     &pinctrl_lcdif_ctrl>;
-	status = "okay";
-
-	port {
-		display_out: endpoint {
-			remote-endpoint = <&panel_in>;
-		};
-	};
-};
-
-&pwm1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_pwm1>;
-	status = "okay";
-};
-
-&qspi {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_qspi>;
-	status = "okay";
-
-	flash0: n25q256a@0 {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		compatible = "micron,n25q256a";
-		spi-max-frequency = <29000000>;
-		reg = <0>;
-	};
-};
-
-&sai2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sai2>;
-	assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
-			  <&clks IMX6UL_CLK_SAI2>;
-	assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
-	assigned-clock-rates = <0>, <12288000>;
-	fsl,sai-mclk-direction-output;
-	status = "okay";
-};
-
-&snvs_poweroff {
-	status = "okay";
-};
-
-&tsc {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_tsc>;
-	xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
-	measure-delay-time = <0xffff>;
-	pre-charge-time = <0xfff>;
-	status = "okay";
-};
-
-&uart1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart1>;
-	status = "okay";
-};
-
-&uart2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart2>;
-	uart-has-rtscts;
-	status = "okay";
-};
-
-&usbotg1 {
-	dr_mode = "otg";
-	status = "okay";
-};
-
-&usbotg2 {
-	dr_mode = "host";
-	disable-over-current;
-	status = "okay";
-};
-
-&usbphy1 {
-	fsl,tx-d-cal = <106>;
-};
-
-&usbphy2 {
-	fsl,tx-d-cal = <106>;
-};
-
-&usdhc1 {
-	pinctrl-names = "default", "state_100mhz", "state_200mhz";
-	pinctrl-0 = <&pinctrl_usdhc1>;
-	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
-	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
-	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
-	keep-power-in-suspend;
-	wakeup-source;
-	vmmc-supply = <&reg_sd1_vmmc>;
-	status = "okay";
-};
-
-&usdhc2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usdhc2>;
-	no-1-8-v;
-	keep-power-in-suspend;
-	wakeup-source;
-	status = "okay";
-};
-
-&wdog1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_wdog>;
-	fsl,ext-reset-output;
-};
-
-&iomuxc {
-	pinctrl-names = "default";
-
-	pinctrl_csi1: csi1grp {
-		fsl,pins = <
-			MX6UL_PAD_CSI_MCLK__CSI_MCLK		0x1b088
-			MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK	0x1b088
-			MX6UL_PAD_CSI_VSYNC__CSI_VSYNC		0x1b088
-			MX6UL_PAD_CSI_HSYNC__CSI_HSYNC		0x1b088
-			MX6UL_PAD_CSI_DATA00__CSI_DATA02	0x1b088
-			MX6UL_PAD_CSI_DATA01__CSI_DATA03	0x1b088
-			MX6UL_PAD_CSI_DATA02__CSI_DATA04	0x1b088
-			MX6UL_PAD_CSI_DATA03__CSI_DATA05	0x1b088
-			MX6UL_PAD_CSI_DATA04__CSI_DATA06	0x1b088
-			MX6UL_PAD_CSI_DATA05__CSI_DATA07	0x1b088
-			MX6UL_PAD_CSI_DATA06__CSI_DATA08	0x1b088
-			MX6UL_PAD_CSI_DATA07__CSI_DATA09	0x1b088
-		>;
-	};
-
-	pinctrl_enet1: enet1grp {
-		fsl,pins = <
-			MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN	0x1b0b0
-			MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER	0x1b0b0
-			MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00	0x1b0b0
-			MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01	0x1b0b0
-			MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN	0x1b0b0
-			MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00	0x1b0b0
-			MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01	0x1b0b0
-			MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x4001b031
-		>;
-	};
-
-	pinctrl_enet2: enet2grp {
-		fsl,pins = <
-			MX6UL_PAD_GPIO1_IO07__ENET2_MDC		0x1b0b0
-			MX6UL_PAD_GPIO1_IO06__ENET2_MDIO	0x1b0b0
-			MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN	0x1b0b0
-			MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER	0x1b0b0
-			MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00	0x1b0b0
-			MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01	0x1b0b0
-			MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN	0x1b0b0
-			MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00	0x1b0b0
-			MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01	0x1b0b0
-			MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b031
-		>;
-	};
-
-	pinctrl_flexcan1: flexcan1grp{
-		fsl,pins = <
-			MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX	0x1b020
-			MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX	0x1b020
-		>;
-	};
-
-	pinctrl_flexcan2: flexcan2grp{
-		fsl,pins = <
-			MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX	0x1b020
-			MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX	0x1b020
-		>;
-	};
-
-	pinctrl_i2c1: i2c1grp {
-		fsl,pins = <
-			MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
-			MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
-		>;
-	};
-
-	pinctrl_i2c2: i2c2grp {
-		fsl,pins = <
-			MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
-			MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
-		>;
-	};
-
-	pinctrl_lcdif_dat: lcdifdatgrp {
-		fsl,pins = <
-			MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
-			MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
-			MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
-			MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
-			MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
-			MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
-			MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
-			MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
-			MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
-			MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
-			MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
-			MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
-			MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
-			MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
-			MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
-			MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
-			MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79
-			MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79
-			MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79
-			MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79
-			MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79
-			MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79
-			MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79
-			MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79
-		>;
-	};
-
-	pinctrl_lcdif_ctrl: lcdifctrlgrp {
-		fsl,pins = <
-			MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x79
-			MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
-			MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
-			MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
-			/* used for lcd reset */
-			MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x79
-		>;
-	};
-
-	pinctrl_qspi: qspigrp {
-		fsl,pins = <
-			MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK	0x70a1
-			MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00	0x70a1
-			MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01	0x70a1
-			MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02	0x70a1
-			MX6UL_PAD_NAND_CLE__QSPI_A_DATA03	0x70a1
-			MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B	0x70a1
-		>;
-	};
-
-	pinctrl_sai2: sai2grp {
-		fsl,pins = <
-			MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK	0x17088
-			MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC	0x17088
-			MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA	0x11088
-			MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA	0x11088
-			MX6UL_PAD_JTAG_TMS__SAI2_MCLK		0x17088
-			MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04	0x17059
-		>;
-	};
-
-	pinctrl_pwm1: pwm1grp {
-		fsl,pins = <
-			MX6UL_PAD_GPIO1_IO08__PWM1_OUT   0x110b0
-		>;
-	};
-
-	pinctrl_sim2: sim2grp {
-		fsl,pins = <
-			MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD		0xb808
-			MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK		0x31
-			MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B		0xb808
-			MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN		0xb808
-			MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD		0xb809
-			MX6UL_PAD_CSI_DATA02__GPIO4_IO23		0x3008
-		>;
-	};
-
-	pinctrl_tsc: tscgrp {
-		fsl,pins = <
-			MX6UL_PAD_GPIO1_IO01__GPIO1_IO01		0xb0
-			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02		0xb0
-			MX6UL_PAD_GPIO1_IO03__GPIO1_IO03		0xb0
-			MX6UL_PAD_GPIO1_IO04__GPIO1_IO04		0xb0
-		>;
-	};
-
-	pinctrl_uart1: uart1grp {
-		fsl,pins = <
-			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
-			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
-		>;
-	};
-
-	pinctrl_uart2: uart2grp {
-		fsl,pins = <
-			MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX	0x1b0b1
-			MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX	0x1b0b1
-			MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS	0x1b0b1
-			MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS	0x1b0b1
-		>;
-	};
-
-	pinctrl_usdhc1: usdhc1grp {
-		fsl,pins = <
-			MX6UL_PAD_SD1_CMD__USDHC1_CMD     	0x17059
-			MX6UL_PAD_SD1_CLK__USDHC1_CLK     	0x10059
-			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 	0x17059
-			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 	0x17059
-			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 	0x17059
-			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 	0x17059
-			MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x17059 /* SD1 CD */
-			MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT    0x17059 /* SD1 VSELECT */
-			MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 /* SD1 RESET */
-		>;
-	};
-
-	pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
-		fsl,pins = <
-			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170b9
-			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100b9
-			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
-			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
-			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
-			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
-
-		>;
-	};
-
-	pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
-		fsl,pins = <
-			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170f9
-			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100f9
-			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
-			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
-			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
-			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
-		>;
-	};
-
-	pinctrl_usdhc2: usdhc2grp {
-		fsl,pins = <
-			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x17059
-			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
-			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
-			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
-			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
-			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
-		>;
-	};
-
-	pinctrl_wdog: wdoggrp {
-		fsl,pins = <
-			MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY    0x30b0
-		>;
-	};
 };
diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
new file mode 100644
index 000000000000..32a07232c034
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dtsi
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+/ {
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	memory@80000000 {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	backlight_display: backlight-display {
+		compatible = "pwm-backlight";
+		pwms = <&pwm1 0 5000000>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <6>;
+		status = "okay";
+	};
+
+
+	reg_sd1_vmmc: regulator-sd1-vmmc {
+		compatible = "regulator-fixed";
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "mx6ul-wm8960";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,bitclock-master = <&dailink_master>;
+		simple-audio-card,frame-master = <&dailink_master>;
+		simple-audio-card,widgets =
+			"Microphone", "Mic Jack",
+			"Line", "Line In",
+			"Line", "Line Out",
+			"Speaker", "Speaker",
+			"Headphone", "Headphone Jack";
+		simple-audio-card,routing =
+			"Headphone Jack", "HP_L",
+			"Headphone Jack", "HP_R",
+			"Speaker", "SPK_LP",
+			"Speaker", "SPK_LN",
+			"Speaker", "SPK_RP",
+			"Speaker", "SPK_RN",
+			"LINPUT1", "Mic Jack",
+			"LINPUT3", "Mic Jack",
+			"RINPUT1", "Mic Jack",
+			"RINPUT2", "Mic Jack";
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai2>;
+		};
+
+		dailink_master: simple-audio-card,codec {
+			sound-dai = <&codec>;
+			clocks = <&clks IMX6UL_CLK_SAI2>;
+		};
+	};
+
+	panel {
+		compatible = "innolux,at043tn24";
+		backlight = <&backlight_display>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
+	};
+};
+
+&clks {
+	assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
+	assigned-clock-rates = <786432000>;
+};
+
+&i2c2 {
+	clock_frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	codec: wm8960@1a {
+		#sound-dai-cells = <0>;
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+		wlf,shared-lrclk;
+	};
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet1>;
+	phy-mode = "rmii";
+	phy-handle = <&ethphy0>;
+	status = "okay";
+};
+
+&fec2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet2>;
+	phy-mode = "rmii";
+	phy-handle = <&ethphy1>;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@2 {
+			reg = <2>;
+			micrel,led-mode = <1>;
+			clocks = <&clks IMX6UL_CLK_ENET_REF>;
+			clock-names = "rmii-ref";
+		};
+
+		ethphy1: ethernet-phy@1 {
+			reg = <1>;
+			micrel,led-mode = <1>;
+			clocks = <&clks IMX6UL_CLK_ENET2_REF>;
+			clock-names = "rmii-ref";
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	mag3110@e {
+		compatible = "fsl,mag3110";
+		reg = <0x0e>;
+	};
+};
+
+&lcdif {
+	assigned-clocks = <&clks IMX6UL_CLK_LCDIF_PRE_SEL>;
+	assigned-clock-parents = <&clks IMX6UL_CLK_PLL5_VIDEO_DIV>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lcdif_dat
+		     &pinctrl_lcdif_ctrl>;
+	status = "okay";
+
+	port {
+		display_out: endpoint {
+			remote-endpoint = <&panel_in>;
+		};
+	};
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "okay";
+};
+
+&qspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi>;
+	status = "okay";
+
+	flash0: n25q256a@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "micron,n25q256a";
+		spi-max-frequency = <29000000>;
+		reg = <0>;
+	};
+};
+
+&sai2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sai2>;
+	assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
+			  <&clks IMX6UL_CLK_SAI2>;
+	assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
+	assigned-clock-rates = <0>, <12288000>;
+	fsl,sai-mclk-direction-output;
+	status = "okay";
+};
+
+&snvs_poweroff {
+	status = "okay";
+};
+
+&tsc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_tsc>;
+	xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+	measure-delay-time = <0xffff>;
+	pre-charge-time = <0xfff>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&usbotg1 {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbotg2 {
+	dr_mode = "host";
+	disable-over-current;
+	status = "okay";
+};
+
+&usbphy1 {
+	fsl,tx-d-cal = <106>;
+};
+
+&usbphy2 {
+	fsl,tx-d-cal = <106>;
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
+	keep-power-in-suspend;
+	wakeup-source;
+	vmmc-supply = <&reg_sd1_vmmc>;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	no-1-8-v;
+	keep-power-in-suspend;
+	wakeup-source;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	pinctrl_csi1: csi1grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_MCLK__CSI_MCLK		0x1b088
+			MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK	0x1b088
+			MX6UL_PAD_CSI_VSYNC__CSI_VSYNC		0x1b088
+			MX6UL_PAD_CSI_HSYNC__CSI_HSYNC		0x1b088
+			MX6UL_PAD_CSI_DATA00__CSI_DATA02	0x1b088
+			MX6UL_PAD_CSI_DATA01__CSI_DATA03	0x1b088
+			MX6UL_PAD_CSI_DATA02__CSI_DATA04	0x1b088
+			MX6UL_PAD_CSI_DATA03__CSI_DATA05	0x1b088
+			MX6UL_PAD_CSI_DATA04__CSI_DATA06	0x1b088
+			MX6UL_PAD_CSI_DATA05__CSI_DATA07	0x1b088
+			MX6UL_PAD_CSI_DATA06__CSI_DATA08	0x1b088
+			MX6UL_PAD_CSI_DATA07__CSI_DATA09	0x1b088
+		>;
+	};
+
+	pinctrl_enet1: enet1grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN	0x1b0b0
+			MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER	0x1b0b0
+			MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00	0x1b0b0
+			MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01	0x1b0b0
+			MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN	0x1b0b0
+			MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00	0x1b0b0
+			MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01	0x1b0b0
+			MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x4001b031
+		>;
+	};
+
+	pinctrl_enet2: enet2grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO07__ENET2_MDC		0x1b0b0
+			MX6UL_PAD_GPIO1_IO06__ENET2_MDIO	0x1b0b0
+			MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN	0x1b0b0
+			MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER	0x1b0b0
+			MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00	0x1b0b0
+			MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01	0x1b0b0
+			MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN	0x1b0b0
+			MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00	0x1b0b0
+			MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01	0x1b0b0
+			MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b031
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp{
+		fsl,pins = <
+			MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX	0x1b020
+			MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX	0x1b020
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp{
+		fsl,pins = <
+			MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX	0x1b020
+			MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX	0x1b020
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
+			MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
+			MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
+		>;
+	};
+
+	pinctrl_lcdif_dat: lcdifdatgrp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
+			MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
+			MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
+			MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
+			MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
+			MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
+			MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
+			MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
+			MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
+			MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
+			MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
+			MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
+			MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
+			MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
+			MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
+			MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
+			MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79
+			MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79
+			MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79
+			MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79
+			MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79
+			MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79
+			MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79
+			MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79
+		>;
+	};
+
+	pinctrl_lcdif_ctrl: lcdifctrlgrp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x79
+			MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
+			MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
+			MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
+			/* used for lcd reset */
+			MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x79
+		>;
+	};
+
+	pinctrl_qspi: qspigrp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK	0x70a1
+			MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00	0x70a1
+			MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01	0x70a1
+			MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02	0x70a1
+			MX6UL_PAD_NAND_CLE__QSPI_A_DATA03	0x70a1
+			MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B	0x70a1
+		>;
+	};
+
+	pinctrl_sai2: sai2grp {
+		fsl,pins = <
+			MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK	0x17088
+			MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC	0x17088
+			MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA	0x11088
+			MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA	0x11088
+			MX6UL_PAD_JTAG_TMS__SAI2_MCLK		0x17088
+			MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04	0x17059
+		>;
+	};
+
+	pinctrl_pwm1: pwm1grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO08__PWM1_OUT   0x110b0
+		>;
+	};
+
+	pinctrl_sim2: sim2grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD		0xb808
+			MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK		0x31
+			MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B		0xb808
+			MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN		0xb808
+			MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD		0xb809
+			MX6UL_PAD_CSI_DATA02__GPIO4_IO23		0x3008
+		>;
+	};
+
+	pinctrl_tsc: tscgrp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO01__GPIO1_IO01		0xb0
+			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02		0xb0
+			MX6UL_PAD_GPIO1_IO03__GPIO1_IO03		0xb0
+			MX6UL_PAD_GPIO1_IO04__GPIO1_IO04		0xb0
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
+			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX	0x1b0b1
+			MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX	0x1b0b1
+			MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS	0x1b0b1
+			MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS	0x1b0b1
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     	0x17059
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     	0x10059
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 	0x17059
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 	0x17059
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 	0x17059
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 	0x17059
+			MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x17059 /* SD1 CD */
+			MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT    0x17059 /* SD1 VSELECT */
+			MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 /* SD1 RESET */
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170b9
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100b9
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
+
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170f9
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100f9
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x17059
+			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
+			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
+			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
+			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
+			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY    0x30b0
+		>;
+	};
+};
diff --git a/arch/arm/boot/dts/imx6ul-geam.dts b/arch/arm/boot/dts/imx6ul-geam.dts
index 571eea7f1c6b..0dbbd78c867f 100644
--- a/arch/arm/boot/dts/imx6ul-geam.dts
+++ b/arch/arm/boot/dts/imx6ul-geam.dts
@@ -50,7 +50,7 @@
 	model = "Engicam GEAM6UL Starter Kit";
 	compatible = "engicam,imx6ul-geam", "fsl,imx6ul";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x08000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6ul-isiot.dtsi b/arch/arm/boot/dts/imx6ul-isiot.dtsi
index 950fb28b630a..b0ecebb512b3 100644
--- a/arch/arm/boot/dts/imx6ul-isiot.dtsi
+++ b/arch/arm/boot/dts/imx6ul-isiot.dtsi
@@ -45,7 +45,7 @@
 #include "imx6ul.dtsi"
 
 / {
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x20000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6ul-litesom.dtsi b/arch/arm/boot/dts/imx6ul-litesom.dtsi
index 039721d3dcb4..8f775f6974d1 100644
--- a/arch/arm/boot/dts/imx6ul-litesom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-litesom.dtsi
@@ -47,7 +47,7 @@
 	model = "Grinn i.MX6UL liteSOM";
 	compatible = "grinn,imx6ul-litesom", "fsl,imx6ul";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x20000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6ul-opos6ul.dtsi b/arch/arm/boot/dts/imx6ul-opos6ul.dtsi
index aec5ccce0321..a031bee311df 100644
--- a/arch/arm/boot/dts/imx6ul-opos6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul-opos6ul.dtsi
@@ -48,7 +48,7 @@
 #include "imx6ul.dtsi"
 
 / {
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0>; /* will be filled by U-Boot */
 	};
 
diff --git a/arch/arm/boot/dts/imx6ul-pico-hobbit.dts b/arch/arm/boot/dts/imx6ul-pico-hobbit.dts
index 3bf26ebd4df9..47682b8c023c 100644
--- a/arch/arm/boot/dts/imx6ul-pico-hobbit.dts
+++ b/arch/arm/boot/dts/imx6ul-pico-hobbit.dts
@@ -51,7 +51,7 @@
 	model = "Technexion Pico i.MX6UL Board";
 	compatible = "technexion,imx6ul-pico-hobbit", "fsl,imx6ul";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x10000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx6ul-pinfunc.h b/arch/arm/boot/dts/imx6ul-pinfunc.h
index 0034eeb84542..7b9a4dc38456 100644
--- a/arch/arm/boot/dts/imx6ul-pinfunc.h
+++ b/arch/arm/boot/dts/imx6ul-pinfunc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright 2014 - 2015 Freescale Semiconductor, Inc.
  *
  * 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
@@ -34,14 +34,14 @@
 #define MX6UL_PAD_JTAG_MOD__ENET1_REF_CLK_25M		0x0044 0x02d0 0x0000 3 0
 #define MX6UL_PAD_JTAG_MOD__CCM_PMIC_RDY		0x0044 0x02d0 0x04c0 4 0
 #define MX6UL_PAD_JTAG_MOD__GPIO1_IO10			0x0044 0x02d0 0x0000 5 0
-#define MX6UL_PAD_JTAG_MOD__SDMA_EXT_EVENT00		0x0044 0x02d0 0x0000 6 0
+#define MX6UL_PAD_JTAG_MOD__SDMA_EXT_EVENT00		0x0044 0x02d0 0x0610 6 0
 #define MX6UL_PAD_JTAG_TMS__SJC_TMS			0x0048 0x02d4 0x0000 0 0
 #define MX6UL_PAD_JTAG_TMS__GPT2_CAPTURE1		0x0048 0x02d4 0x0598 1 0
-#define MX6UL_PAD_JTAG_TMS__SAI2_MCLK			0x0048 0x02d4 0x0000 2 0
+#define MX6UL_PAD_JTAG_TMS__SAI2_MCLK			0x0048 0x02d4 0x05f0 2 0
 #define MX6UL_PAD_JTAG_TMS__CCM_CLKO1			0x0048 0x02d4 0x0000 3 0
 #define MX6UL_PAD_JTAG_TMS__CCM_WAIT			0x0048 0x02d4 0x0000 4 0
 #define MX6UL_PAD_JTAG_TMS__GPIO1_IO11			0x0048 0x02d4 0x0000 5 0
-#define MX6UL_PAD_JTAG_TMS__SDMA_EXT_EVENT01		0x0048 0x02d4 0x0000 6 0
+#define MX6UL_PAD_JTAG_TMS__SDMA_EXT_EVENT01		0x0048 0x02d4 0x0614 6 0
 #define MX6UL_PAD_JTAG_TMS__EPIT1_OUT			0x0048 0x02d4 0x0000 8 0
 #define MX6UL_PAD_JTAG_TDO__SJC_TDO			0x004c 0x02d8 0x0000 0 0
 #define MX6UL_PAD_JTAG_TDO__GPT2_CAPTURE2		0x004c 0x02d8 0x059c 1 0
@@ -63,12 +63,14 @@
 #define MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA		0x0054 0x02e0 0x05f4 2 0
 #define MX6UL_PAD_JTAG_TCK__PWM7_OUT			0x0054 0x02e0 0x0000 4 0
 #define MX6UL_PAD_JTAG_TCK__GPIO1_IO14			0x0054 0x02e0 0x0000 5 0
+#define MX6UL_PAD_JTAG_TCK__OSC32K_32K_OUT			0x0054 0x02e0 0x0000 6 0
 #define MX6UL_PAD_JTAG_TCK__SIM2_POWER_FAIL		0x0054 0x02e0 0x0000 8 0
 #define MX6UL_PAD_JTAG_TRST_B__SJC_TRSTB		0x0058 0x02e4 0x0000 0 0
 #define MX6UL_PAD_JTAG_TRST_B__GPT2_COMPARE3		0x0058 0x02e4 0x0000 1 0
 #define MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA		0x0058 0x02e4 0x0000 2 0
 #define MX6UL_PAD_JTAG_TRST_B__PWM8_OUT			0x0058 0x02e4 0x0000 4 0
 #define MX6UL_PAD_JTAG_TRST_B__GPIO1_IO15		0x0058 0x02e4 0x0000 5 0
+#define MX6UL_PAD_JTAG_TRST_B__REF_CLK_24M		0x0058 0x02e4 0x0000 6 0
 #define MX6UL_PAD_JTAG_TRST_B__CAAM_RNG_OSC_OBS		0x0058 0x02e4 0x0000 8 0
 #define MX6UL_PAD_GPIO1_IO00__I2C2_SCL			0x005c 0x02e8 0x05ac 0 1
 #define MX6UL_PAD_GPIO1_IO00__GPT1_CAPTURE1		0x005c 0x02e8 0x058c 1 0
@@ -94,22 +96,24 @@
 #define MX6UL_PAD_GPIO1_IO02__ENET1_REF_CLK_25M		0x0064 0x02f0 0x0000 3 0
 #define MX6UL_PAD_GPIO1_IO02__USDHC1_WP			0x0064 0x02f0 0x066c 4 0
 #define MX6UL_PAD_GPIO1_IO02__GPIO1_IO02		0x0064 0x02f0 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO02__SDMA_EXT_EVENT00		0x0064 0x02f0 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO02__SDMA_EXT_EVENT00		0x0064 0x02f0 0x0610 6 1
 #define MX6UL_PAD_GPIO1_IO02__SRC_ANY_PU_RESET		0x0064 0x02f0 0x0000 7 0
 #define MX6UL_PAD_GPIO1_IO02__UART1_DCE_TX		0x0064 0x02f0 0x0000 8 0
 #define MX6UL_PAD_GPIO1_IO02__UART1_DTE_RX		0x0064 0x02f0 0x0624 8 0
 #define MX6UL_PAD_GPIO1_IO03__I2C1_SDA			0x0068 0x02f4 0x05a8 0 1
 #define MX6UL_PAD_GPIO1_IO03__GPT1_COMPARE3		0x0068 0x02f4 0x0000 1 0
 #define MX6UL_PAD_GPIO1_IO03__USB_OTG2_OC		0x0068 0x02f4 0x0660 2 0
+#define MX6UL_PAD_GPIO1_IO03__OSC32K_32K_OUT		0x0068 0x02f4 0x0000 3 0
 #define MX6UL_PAD_GPIO1_IO03__USDHC1_CD_B		0x0068 0x02f4 0x0668 4 0
 #define MX6UL_PAD_GPIO1_IO03__GPIO1_IO03		0x0068 0x02f4 0x0000 5 0
-#define MX6UL_PAD_GPIO1_IO03__CCM_DI0_eXT_CLK		0x0068 0x02f4 0x0000 6 0
+#define MX6UL_PAD_GPIO1_IO03__CCM_DI0_EXT_CLK		0x0068 0x02f4 0x0000 6 0
 #define MX6UL_PAD_GPIO1_IO03__SRC_TESTER_ACK		0x0068 0x02f4 0x0000 7 0
-#define MX6UL_PAD_GPIO1_IO03__UART1_DTE_TX		0x0068 0x02f4 0x0000 8 0
 #define MX6UL_PAD_GPIO1_IO03__UART1_DCE_RX		0x0068 0x02f4 0x0624 8 1
+#define MX6UL_PAD_GPIO1_IO03__UART1_DTE_TX		0x0068 0x02f4 0x0000 8 0
 #define MX6UL_PAD_GPIO1_IO04__ENET1_REF_CLK1		0x006c 0x02f8 0x0574 0 1
 #define MX6UL_PAD_GPIO1_IO04__PWM3_OUT			0x006c 0x02f8 0x0000 1 0
 #define MX6UL_PAD_GPIO1_IO04__USB_OTG1_PWR		0x006c 0x02f8 0x0000 2 0
+#define MX6UL_PAD_GPIO1_IO04__REF_CLK_24M		0x006c 0x02f8 0x0000 3 0
 #define MX6UL_PAD_GPIO1_IO04__USDHC1_RESET_B		0x006c 0x02f8 0x0000 4 0
 #define MX6UL_PAD_GPIO1_IO04__GPIO1_IO04		0x006c 0x02f8 0x0000 5 0
 #define MX6UL_PAD_GPIO1_IO04__ENET2_1588_EVENT0_IN	0x006c 0x02f8 0x0000 6 0
@@ -200,7 +204,7 @@
 #define MX6UL_PAD_UART2_TX_DATA__CSI_DATA06		0x0094 0x0320 0x04dc 3 0
 #define MX6UL_PAD_UART2_TX_DATA__GPT1_CAPTURE1		0x0094 0x0320 0x058c 4 1
 #define MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20		0x0094 0x0320 0x0000 5 0
-#define MX6UL_PAD_UART2_TX_DATA__ECSPI3_SS0		0x0094 0x0320 0x0000 8 0
+#define MX6UL_PAD_UART2_TX_DATA__ECSPI3_SS0		0x0094 0x0320 0x0560 8 0
 #define MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX		0x0098 0x0324 0x062c 0 1
 #define MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX		0x0098 0x0324 0x0000 0 0
 #define MX6UL_PAD_UART2_RX_DATA__ENET1_TDATA03		0x0098 0x0324 0x0000 1 0
@@ -232,7 +236,7 @@
 #define MX6UL_PAD_UART3_TX_DATA__UART3_DTE_RX		0x00a4 0x0330 0x0634 0 0
 #define MX6UL_PAD_UART3_TX_DATA__ENET2_RDATA02		0x00a4 0x0330 0x0000 1 0
 #define MX6UL_PAD_UART3_TX_DATA__SIM1_PORT0_PD		0x00a4 0x0330 0x0000 2 0
-#define MX6UL_PAD_UART3_TX_DATA__CSI_DATA01		0x00a4 0x0330 0x0000 3 0
+#define MX6UL_PAD_UART3_TX_DATA__CSI_DATA01		0x00a4 0x0330 0x04d4 3 0
 #define MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS		0x00a4 0x0330 0x0000 4 0
 #define MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS		0x00a4 0x0330 0x0628 4 2
 #define MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24		0x00a4 0x0330 0x0000 5 0
@@ -242,7 +246,7 @@
 #define MX6UL_PAD_UART3_RX_DATA__UART3_DTE_TX		0x00a8 0x0334 0x0000 0 0
 #define MX6UL_PAD_UART3_RX_DATA__ENET2_RDATA03		0x00a8 0x0334 0x0000 1 0
 #define MX6UL_PAD_UART3_RX_DATA__SIM2_PORT0_PD		0x00a8 0x0334 0x0000 2 0
-#define MX6UL_PAD_UART3_RX_DATA__CSI_DATA00		0x00a8 0x0334 0x0000 3 0
+#define MX6UL_PAD_UART3_RX_DATA__CSI_DATA00		0x00a8 0x0334 0x04d0 3 0
 #define MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS		0x00a8 0x0334 0x0628 4 3
 #define MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS		0x00a8 0x0334 0x0000 4 0
 #define MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25		0x00a8 0x0334 0x0000 5 0
@@ -251,7 +255,7 @@
 #define MX6UL_PAD_UART3_CTS_B__UART3_DTE_RTS		0x00ac 0x0338 0x0630 0 0
 #define MX6UL_PAD_UART3_CTS_B__ENET2_RX_CLK		0x00ac 0x0338 0x0000 1 0
 #define MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX		0x00ac 0x0338 0x0000 2 0
-#define MX6UL_PAD_UART3_CTS_B__CSI_DATA10		0x00ac 0x0338 0x0000 3 0
+#define MX6UL_PAD_UART3_CTS_B__CSI_DATA10		0x00ac 0x0338 0x04ec 3 0
 #define MX6UL_PAD_UART3_CTS_B__ENET1_1588_EVENT1_IN	0x00ac 0x0338 0x0000 4 0
 #define MX6UL_PAD_UART3_CTS_B__GPIO1_IO26		0x00ac 0x0338 0x0000 5 0
 #define MX6UL_PAD_UART3_CTS_B__EPIT2_OUT		0x00ac 0x0338 0x0000 8 0
@@ -259,7 +263,7 @@
 #define MX6UL_PAD_UART3_RTS_B__UART3_DTE_CTS		0x00b0 0x033c 0x0000 0 0
 #define MX6UL_PAD_UART3_RTS_B__ENET2_TX_ER		0x00b0 0x033c 0x0000 1 0
 #define MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX		0x00b0 0x033c 0x0584 2 0
-#define MX6UL_PAD_UART3_RTS_B__CSI_DATA11		0x00b0 0x033c 0x0000 3 0
+#define MX6UL_PAD_UART3_RTS_B__CSI_DATA11		0x00b0 0x033c 0x04f0 3 0
 #define MX6UL_PAD_UART3_RTS_B__ENET1_1588_EVENT1_OUT	0x00b0 0x033c 0x0000 4 0
 #define MX6UL_PAD_UART3_RTS_B__GPIO1_IO27		0x00b0 0x033c 0x0000 5 0
 #define MX6UL_PAD_UART3_RTS_B__WDOG1_WDOG_B		0x00b0 0x033c 0x0000 8 0
@@ -267,7 +271,7 @@
 #define MX6UL_PAD_UART4_TX_DATA__UART4_DTE_RX		0x00b4 0x0340 0x063c 0 0
 #define MX6UL_PAD_UART4_TX_DATA__ENET2_TDATA02		0x00b4 0x0340 0x0000 1 0
 #define MX6UL_PAD_UART4_TX_DATA__I2C1_SCL		0x00b4 0x0340 0x05a4 2 1
-#define MX6UL_PAD_UART4_TX_DATA__CSI_DATA12		0x00b4 0x0340 0x0000 3 0
+#define MX6UL_PAD_UART4_TX_DATA__CSI_DATA12		0x00b4 0x0340 0x04f4 3 0
 #define MX6UL_PAD_UART4_TX_DATA__CSU_CSU_ALARM_AUT02	0x00b4 0x0340 0x0000 4 0
 #define MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28		0x00b4 0x0340 0x0000 5 0
 #define MX6UL_PAD_UART4_TX_DATA__ECSPI2_SCLK		0x00b4 0x0340 0x0544 8 1
@@ -275,23 +279,23 @@
 #define MX6UL_PAD_UART4_RX_DATA__UART4_DTE_TX		0x00b8 0x0344 0x0000 0 0
 #define MX6UL_PAD_UART4_RX_DATA__ENET2_TDATA03		0x00b8 0x0344 0x0000 1 0
 #define MX6UL_PAD_UART4_RX_DATA__I2C1_SDA		0x00b8 0x0344 0x05a8 2 2
-#define MX6UL_PAD_UART4_RX_DATA__CSI_DATA13		0x00b8 0x0344 0x0000 3 0
+#define MX6UL_PAD_UART4_RX_DATA__CSI_DATA13		0x00b8 0x0344 0x04f8 3 0
 #define MX6UL_PAD_UART4_RX_DATA__CSU_CSU_ALARM_AUT01	0x00b8 0x0344 0x0000 4 0
 #define MX6UL_PAD_UART4_RX_DATA__GPIO1_IO29		0x00b8 0x0344 0x0000 5 0
-#define MX6UL_PAD_UART4_RX_DATA__ECSPI2_SS0		0x00b8 0x0344 0x0000 8 0
+#define MX6UL_PAD_UART4_RX_DATA__ECSPI2_SS0		0x00b8 0x0344 0x0550 8 1
 #define MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30		0x00bc 0x0348 0x0000 5 0
 #define MX6UL_PAD_UART5_TX_DATA__ECSPI2_MOSI		0x00bc 0x0348 0x054c 8 0
 #define MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX		0x00bc 0x0348 0x0000 0 0
 #define MX6UL_PAD_UART5_TX_DATA__UART5_DTE_RX		0x00bc 0x0348 0x0644 0 4
 #define MX6UL_PAD_UART5_TX_DATA__ENET2_CRS		0x00bc 0x0348 0x0000 1 0
 #define MX6UL_PAD_UART5_TX_DATA__I2C2_SCL		0x00bc 0x0348 0x05ac 2 2
-#define MX6UL_PAD_UART5_TX_DATA__CSI_DATA14		0x00bc 0x0348 0x0000 3 0
+#define MX6UL_PAD_UART5_TX_DATA__CSI_DATA14		0x00bc 0x0348 0x04fc 3 0
 #define MX6UL_PAD_UART5_TX_DATA__CSU_CSU_ALARM_AUT00	0x00bc 0x0348 0x0000 4 0
 #define MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX		0x00c0 0x034c 0x0644 0 5
 #define MX6UL_PAD_UART5_RX_DATA__UART5_DTE_TX		0x00c0 0x034c 0x0000 0 0
 #define MX6UL_PAD_UART5_RX_DATA__ENET2_COL		0x00c0 0x034c 0x0000 1 0
 #define MX6UL_PAD_UART5_RX_DATA__I2C2_SDA		0x00c0 0x034c 0x05b0 2 2
-#define MX6UL_PAD_UART5_RX_DATA__CSI_DATA15		0x00c0 0x034c 0x0000 3 0
+#define MX6UL_PAD_UART5_RX_DATA__CSI_DATA15		0x00c0 0x034c 0x0500 3 0
 #define MX6UL_PAD_UART5_RX_DATA__CSU_CSU_INT_DEB	0x00c0 0x034c 0x0000 4 0
 #define MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31		0x00c0 0x034c 0x0000 5 0
 #define MX6UL_PAD_UART5_RX_DATA__ECSPI2_MISO		0x00c0 0x034c 0x0548 8 1
@@ -299,59 +303,61 @@
 #define MX6UL_PAD_ENET1_RX_DATA0__UART4_DCE_RTS		0x00c4 0x0350 0x0638 1 0
 #define MX6UL_PAD_ENET1_RX_DATA0__UART4_DTE_CTS		0x00c4 0x0350 0x0000 1 0
 #define MX6UL_PAD_ENET1_RX_DATA0__PWM1_OUT		0x00c4 0x0350 0x0000 2 0
-#define MX6UL_PAD_ENET1_RX_DATA0__CSI_DATA16		0x00c4 0x0350 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_DATA0__CSI_DATA16		0x00c4 0x0350 0x0504 3 0
 #define MX6UL_PAD_ENET1_RX_DATA0__FLEXCAN1_TX		0x00c4 0x0350 0x0000 4 0
 #define MX6UL_PAD_ENET1_RX_DATA0__GPIO2_IO00		0x00c4 0x0350 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_DATA0__KPP_ROW00		0x00c4 0x0350 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_DATA0__KPP_ROW00		0x00c4 0x0350 0x05d0 6 0
 #define MX6UL_PAD_ENET1_RX_DATA0__USDHC1_LCTL		0x00c4 0x0350 0x0000 8 0
 #define MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01		0x00c8 0x0354 0x0000 0 0
 #define MX6UL_PAD_ENET1_RX_DATA1__UART4_DCE_CTS		0x00c8 0x0354 0x0000 1 0
 #define MX6UL_PAD_ENET1_RX_DATA1__UART4_DTE_RTS		0x00c8 0x0354 0x0638 1 1
 #define MX6UL_PAD_ENET1_RX_DATA1__PWM2_OUT		0x00c8 0x0354 0x0000 2 0
-#define MX6UL_PAD_ENET1_RX_DATA1__CSI_DATA17		0x00c8 0x0354 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_DATA1__CSI_DATA17		0x00c8 0x0354 0x0508 3 0
 #define MX6UL_PAD_ENET1_RX_DATA1__FLEXCAN1_RX		0x00c8 0x0354 0x0584 4 1
 #define MX6UL_PAD_ENET1_RX_DATA1__GPIO2_IO01		0x00c8 0x0354 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_DATA1__KPP_COL00		0x00c8 0x0354 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_DATA1__KPP_COL00		0x00c8 0x0354 0x05c4 6 0
 #define MX6UL_PAD_ENET1_RX_DATA1__USDHC2_LCTL		0x00c8 0x0354 0x0000 8 0
 #define MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN		0x00cc 0x0358 0x0000 0 0
 #define MX6UL_PAD_ENET1_RX_EN__UART5_DCE_RTS		0x00cc 0x0358 0x0640 1 3
 #define MX6UL_PAD_ENET1_RX_EN__UART5_DTE_CTS		0x00cc 0x0358 0x0000 1 0
-#define MX6UL_PAD_ENET1_RX_EN__CSI_DATA18		0x00cc 0x0358 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_EN__OSC32K_32K_OUT		0x00cc 0x0358 0x0000 2 0
+#define MX6UL_PAD_ENET1_RX_EN__CSI_DATA18		0x00cc 0x0358 0x050c 3 0
 #define MX6UL_PAD_ENET1_RX_EN__FLEXCAN2_TX		0x00cc 0x0358 0x0000 4 0
 #define MX6UL_PAD_ENET1_RX_EN__GPIO2_IO02		0x00cc 0x0358 0x0000 5 0
-#define MX6UL_PAD_ENET1_RX_EN__KPP_ROW01		0x00cc 0x0358 0x0000 6 0
+#define MX6UL_PAD_ENET1_RX_EN__KPP_ROW01		0x00cc 0x0358 0x05d4 6 0
 #define MX6UL_PAD_ENET1_RX_EN__USDHC1_VSELECT		0x00cc 0x0358 0x0000 8 0
 #define MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00		0x00d0 0x035c 0x0000 0 0
 #define MX6UL_PAD_ENET1_TX_DATA0__UART5_DCE_CTS		0x00d0 0x035c 0x0000 1 0
 #define MX6UL_PAD_ENET1_TX_DATA0__UART5_DTE_RTS		0x00d0 0x035c 0x0640 1 4
-#define MX6UL_PAD_ENET1_TX_DATA0__CSI_DATA19		0x00d0 0x035c 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_DATA0__REF_CLK_24M		0x00d0 0x035c 0x0000 2 0
+#define MX6UL_PAD_ENET1_TX_DATA0__CSI_DATA19		0x00d0 0x035c 0x0510 3 0
 #define MX6UL_PAD_ENET1_TX_DATA0__FLEXCAN2_RX		0x00d0 0x035c 0x0588 4 1
 #define MX6UL_PAD_ENET1_TX_DATA0__GPIO2_IO03		0x00d0 0x035c 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_DATA0__KPP_COL01		0x00d0 0x035c 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_DATA0__KPP_COL01		0x00d0 0x035c 0x05c8 6 0
 #define MX6UL_PAD_ENET1_TX_DATA0__USDHC2_VSELECT	0x00d0 0x035c 0x0000 8 0
 #define MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01		0x00d4 0x0360 0x0000 0 0
 #define MX6UL_PAD_ENET1_TX_DATA1__UART6_DCE_CTS		0x00d4 0x0360 0x0000 1 0
 #define MX6UL_PAD_ENET1_TX_DATA1__UART6_DTE_RTS		0x00d4 0x0360 0x0648 1 2
 #define MX6UL_PAD_ENET1_TX_DATA1__PWM5_OUT		0x00d4 0x0360 0x0000 2 0
-#define MX6UL_PAD_ENET1_TX_DATA1__CSI_DATA20		0x00d4 0x0360 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_DATA1__CSI_DATA20		0x00d4 0x0360 0x0514 3 0
 #define MX6UL_PAD_ENET1_TX_DATA1__ENET2_MDIO		0x00d4 0x0360 0x0580 4 1
 #define MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04		0x00d4 0x0360 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_DATA1__KPP_ROW02		0x00d4 0x0360 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_DATA1__KPP_ROW02		0x00d4 0x0360 0x05d8 6 0
 #define MX6UL_PAD_ENET1_TX_DATA1__WDOG1_WDOG_RST_B_DEB	0x00d4 0x0360 0x0000 8 0
 #define MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN		0x00d8 0x0364 0x0000 0 0
 #define MX6UL_PAD_ENET1_TX_EN__UART6_DCE_RTS		0x00d8 0x0364 0x0648 1 3
 #define MX6UL_PAD_ENET1_TX_EN__UART6_DTE_CTS		0x00d8 0x0364 0x0000 1 0
 #define MX6UL_PAD_ENET1_TX_EN__PWM6_OUT			0x00d8 0x0364 0x0000 2 0
-#define MX6UL_PAD_ENET1_TX_EN__CSI_DATA21		0x00d8 0x0364 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_EN__CSI_DATA21		0x00d8 0x0364 0x0518 3 0
 #define MX6UL_PAD_ENET1_TX_EN__ENET2_MDC		0x00d8 0x0364 0x0000 4 0
 #define MX6UL_PAD_ENET1_TX_EN__GPIO2_IO05		0x00d8 0x0364 0x0000 5 0
-#define MX6UL_PAD_ENET1_TX_EN__KPP_COL02		0x00d8 0x0364 0x0000 6 0
+#define MX6UL_PAD_ENET1_TX_EN__KPP_COL02		0x00d8 0x0364 0x05cc 6 0
 #define MX6UL_PAD_ENET1_TX_EN__WDOG2_WDOG_RST_B_DEB	0x00d8 0x0364 0x0000 8 0
 #define MX6UL_PAD_ENET1_TX_CLK__ENET1_TX_CLK		0x00dc 0x0368 0x0000 0 0
 #define MX6UL_PAD_ENET1_TX_CLK__UART7_DCE_CTS		0x00dc 0x0368 0x0000 1 0
 #define MX6UL_PAD_ENET1_TX_CLK__UART7_DTE_RTS		0x00dc 0x0368 0x0650 1 0
 #define MX6UL_PAD_ENET1_TX_CLK__PWM7_OUT		0x00dc 0x0368 0x0000 2 0
-#define MX6UL_PAD_ENET1_TX_CLK__CSI_DATA22		0x00dc 0x0368 0x0000 3 0
+#define MX6UL_PAD_ENET1_TX_CLK__CSI_DATA22		0x00dc 0x0368 0x051c 3 0
 #define MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1		0x00dc 0x0368 0x0574 4 2
 #define MX6UL_PAD_ENET1_TX_CLK__GPIO2_IO06		0x00dc 0x0368 0x0000 5 0
 #define MX6UL_PAD_ENET1_TX_CLK__KPP_ROW03		0x00dc 0x0368 0x0000 6 0
@@ -360,7 +366,7 @@
 #define MX6UL_PAD_ENET1_RX_ER__UART7_DCE_RTS		0x00e0 0x036c 0x0650 1 1
 #define MX6UL_PAD_ENET1_RX_ER__UART7_DTE_CTS		0x00e0 0x036c 0x0000 1 0
 #define MX6UL_PAD_ENET1_RX_ER__PWM8_OUT			0x00e0 0x036c 0x0000 2 0
-#define MX6UL_PAD_ENET1_RX_ER__CSI_DATA23		0x00e0 0x036c 0x0000 3 0
+#define MX6UL_PAD_ENET1_RX_ER__CSI_DATA23		0x00e0 0x036c 0x0520 3 0
 #define MX6UL_PAD_ENET1_RX_ER__EIM_CRE			0x00e0 0x036c 0x0000 4 0
 #define MX6UL_PAD_ENET1_RX_ER__GPIO2_IO07		0x00e0 0x036c 0x0000 5 0
 #define MX6UL_PAD_ENET1_RX_ER__KPP_COL03		0x00e0 0x036c 0x0000 6 0
@@ -377,7 +383,7 @@
 #define MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01		0x00e8 0x0374 0x0000 0 0
 #define MX6UL_PAD_ENET2_RX_DATA1__UART6_DCE_RX		0x00e8 0x0374 0x064c 1 2
 #define MX6UL_PAD_ENET2_RX_DATA1__UART6_DTE_TX		0x00e8 0x0374 0x0000 1 0
-#define MX6UL_PAD_ENET2_RX_DATA1__SIM1_PORT0_cLK	0x00e8 0x0374 0x0000 2 0
+#define MX6UL_PAD_ENET2_RX_DATA1__SIM1_PORT0_CLK	0x00e8 0x0374 0x0000 2 0
 #define MX6UL_PAD_ENET2_RX_DATA1__I2C3_SDA		0x00e8 0x0374 0x05b8 3 1
 #define MX6UL_PAD_ENET2_RX_DATA1__ENET1_MDC		0x00e8 0x0374 0x0000 4 0
 #define MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09		0x00e8 0x0374 0x0000 5 0
@@ -400,6 +406,7 @@
 #define MX6UL_PAD_ENET2_TX_DATA0__EIM_EB_B02		0x00f0 0x037c 0x0000 4 0
 #define MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11		0x00f0 0x037c 0x0000 5 0
 #define MX6UL_PAD_ENET2_TX_DATA0__KPP_COL05		0x00f0 0x037c 0x0000 6 0
+#define MX6UL_PAD_ENET2_TX_DATA0__REF_CLK_24M		0x00f0 0x037c 0x0000 8 0
 #define MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01		0x00f4 0x0380 0x0000 0 0
 #define MX6UL_PAD_ENET2_TX_DATA1__UART8_DCE_TX		0x00f4 0x0380 0x0000 1 0
 #define MX6UL_PAD_ENET2_TX_DATA1__UART8_DTE_RX		0x00f4 0x0380 0x065c 1 0
@@ -412,7 +419,7 @@
 #define MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN		0x00f8 0x0384 0x0000 0 0
 #define MX6UL_PAD_ENET2_TX_EN__UART8_DCE_RX		0x00f8 0x0384 0x065c 1 1
 #define MX6UL_PAD_ENET2_TX_EN__UART8_DTE_TX		0x00f8 0x0384 0x0000 1 0
-#define MX6UL_PAD_ENET2_TX_EN__SIM2_PORT0_cLK		0x00f8 0x0384 0x0000 2 0
+#define MX6UL_PAD_ENET2_TX_EN__SIM2_PORT0_CLK		0x00f8 0x0384 0x0000 2 0
 #define MX6UL_PAD_ENET2_TX_EN__ECSPI4_MOSI		0x00f8 0x0384 0x056c 3 0
 #define MX6UL_PAD_ENET2_TX_EN__EIM_ACLK_FREERUN		0x00f8 0x0384 0x0000 4 0
 #define MX6UL_PAD_ENET2_TX_EN__GPIO2_IO13		0x00f8 0x0384 0x0000 5 0
@@ -431,7 +438,7 @@
 #define MX6UL_PAD_ENET2_RX_ER__UART8_DCE_RTS		0x0100 0x038c 0x0658 1 1
 #define MX6UL_PAD_ENET2_RX_ER__UART8_DTE_CTS		0x0100 0x038c 0x0000 1 0
 #define MX6UL_PAD_ENET2_RX_ER__SIM2_PORT0_SVEN		0x0100 0x038c 0x0000 2 0
-#define MX6UL_PAD_ENET2_RX_ER__ECSPI4_SS0		0x0100 0x038c 0x0000 3 0
+#define MX6UL_PAD_ENET2_RX_ER__ECSPI4_SS0		0x0100 0x038c 0x0570 3 0
 #define MX6UL_PAD_ENET2_RX_ER__EIM_ADDR25		0x0100 0x038c 0x0000 4 0
 #define MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15		0x0100 0x038c 0x0000 5 0
 #define MX6UL_PAD_ENET2_RX_ER__KPP_COL07		0x0100 0x038c 0x0000 6 0
@@ -440,7 +447,7 @@
 #define MX6UL_PAD_LCD_CLK__LCDIF_WR_RWN			0x0104 0x0390 0x0000 1 0
 #define MX6UL_PAD_LCD_CLK__UART4_DCE_TX			0x0104 0x0390 0x0000 2 0
 #define MX6UL_PAD_LCD_CLK__UART4_DTE_RX			0x0104 0x0390 0x063c 2 2
-#define MX6UL_PAD_LCD_CLK__SAI3_MCLK			0x0104 0x0390 0x0000 3 0
+#define MX6UL_PAD_LCD_CLK__SAI3_MCLK			0x0104 0x0390 0x0600 3 0
 #define MX6UL_PAD_LCD_CLK__EIM_CS2_B			0x0104 0x0390 0x0000 4 0
 #define MX6UL_PAD_LCD_CLK__GPIO3_IO00			0x0104 0x0390 0x0000 5 0
 #define MX6UL_PAD_LCD_CLK__WDOG1_WDOG_RST_B_DEB		0x0104 0x0390 0x0000 8 0
@@ -464,7 +471,7 @@
 #define MX6UL_PAD_LCD_VSYNC__LCDIF_BUSY			0x0110 0x039c 0x05dc 1 1
 #define MX6UL_PAD_LCD_VSYNC__UART4_DCE_RTS		0x0110 0x039c 0x0638 2 3
 #define MX6UL_PAD_LCD_VSYNC__UART4_DTE_CTS		0x0110 0x039c 0x0000 2 0
-#define MX6UL_PAD_LCD_VSYNC__SAI3_RX_DATA		0x0110 0x039c 0x0000 3 0
+#define MX6UL_PAD_LCD_VSYNC__SAI3_RX_DATA		0x0110 0x039c 0x0604 3 0
 #define MX6UL_PAD_LCD_VSYNC__WDOG2_WDOG_B		0x0110 0x039c 0x0000 4 0
 #define MX6UL_PAD_LCD_VSYNC__GPIO3_IO03			0x0110 0x039c 0x0000 5 0
 #define MX6UL_PAD_LCD_VSYNC__ECSPI2_SS2			0x0110 0x039c 0x0000 8 0
@@ -477,13 +484,15 @@
 #define MX6UL_PAD_LCD_RESET__ECSPI2_SS3			0x0114 0x03a0 0x0000 8 0
 #define MX6UL_PAD_LCD_DATA00__LCDIF_DATA00		0x0118 0x03a4 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA00__PWM1_OUT			0x0118 0x03a4 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA00__CA7_MX6UL_TRACE0		0x0118 0x03a4 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA00__ENET1_1588_EVENT2_IN	0x0118 0x03a4 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA00__I2C3_SDA			0x0118 0x03a4 0x05b8 4 2
 #define MX6UL_PAD_LCD_DATA00__GPIO3_IO05		0x0118 0x03a4 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA00__SRC_BT_CFG00		0x0118 0x03a4 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA00__SAI1_MCLK			0x0118 0x03a4 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA00__SAI1_MCLK			0x0118 0x03a4 0x05e0 8 1
 #define MX6UL_PAD_LCD_DATA01__LCDIF_DATA01		0x011c 0x03a8 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA01__PWM2_OUT			0x011c 0x03a8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA01__CA7_MX6UL_TRACE1		0x011c 0x03a8 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA01__ENET1_1588_EVENT2_OUT	0x011c 0x03a8 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA01__I2C3_SCL			0x011c 0x03a8 0x05b4 4 2
 #define MX6UL_PAD_LCD_DATA01__GPIO3_IO06		0x011c 0x03a8 0x0000 5 0
@@ -491,6 +500,7 @@
 #define MX6UL_PAD_LCD_DATA01__SAI1_TX_SYNC		0x011c 0x03a8 0x05ec 8 0
 #define MX6UL_PAD_LCD_DATA02__LCDIF_DATA02		0x0120 0x03ac 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA02__PWM3_OUT			0x0120 0x03ac 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA02__CA7_MX6UL_TRACE2		0x0120 0x03ac 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA02__ENET1_1588_EVENT3_IN	0x0120 0x03ac 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA02__I2C4_SDA			0x0120 0x03ac 0x05c0 4 2
 #define MX6UL_PAD_LCD_DATA02__GPIO3_IO07		0x0120 0x03ac 0x0000 5 0
@@ -498,14 +508,16 @@
 #define MX6UL_PAD_LCD_DATA02__SAI1_TX_BCLK		0x0120 0x03ac 0x05e8 8 0
 #define MX6UL_PAD_LCD_DATA03__LCDIF_DATA03		0x0124 0x03b0 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA03__PWM4_OUT			0x0124 0x03b0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA03__CA7_MX6UL_TRACE3		0x0124 0x03b0 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA03__ENET1_1588_EVENT3_OUT	0x0124 0x03b0 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA03__I2C4_SCL			0x0124 0x03b0 0x05bc 4 2
 #define MX6UL_PAD_LCD_DATA03__GPIO3_IO08		0x0124 0x03b0 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA03__SRC_BT_CFG03		0x0124 0x03b0 0x0000 6 0
-#define MX6UL_PAD_LCD_DATA03__SAI1_RX_DATA		0x0124 0x03b0 0x0000 8 0
+#define MX6UL_PAD_LCD_DATA03__SAI1_RX_DATA		0x0124 0x03b0 0x05e4 8 0
 #define MX6UL_PAD_LCD_DATA04__LCDIF_DATA04		0x0128 0x03b4 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA04__UART8_DCE_CTS		0x0128 0x03b4 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA04__UART8_DTE_RTS		0x0128 0x03b4 0x0658 1 2
+#define MX6UL_PAD_LCD_DATA04__CA7_MX6UL_TRACE4		0x0128 0x03b4 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA04__ENET2_1588_EVENT2_IN	0x0128 0x03b4 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA04__SPDIF_SR_CLK		0x0128 0x03b4 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA04__GPIO3_IO09		0x0128 0x03b4 0x0000 5 0
@@ -514,6 +526,7 @@
 #define MX6UL_PAD_LCD_DATA05__LCDIF_DATA05		0x012c 0x03b8 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA05__UART8_DCE_RTS		0x012c 0x03b8 0x0658 1 3
 #define MX6UL_PAD_LCD_DATA05__UART8_DTE_CTS		0x012c 0x03b8 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA05__CA7_MX6UL_TRACE5		0x012c 0x03b8 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA05__ENET2_1588_EVENT2_OUT	0x012c 0x03b8 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA05__SPDIF_OUT			0x012c 0x03b8 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA05__GPIO3_IO10		0x012c 0x03b8 0x0000 5 0
@@ -522,6 +535,7 @@
 #define MX6UL_PAD_LCD_DATA06__LCDIF_DATA06		0x0130 0x03bc 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA06__UART7_DCE_CTS		0x0130 0x03bc 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA06__UART7_DTE_RTS		0x0130 0x03bc 0x0650 1 2
+#define MX6UL_PAD_LCD_DATA06__CA7_MX6UL_TRACE6		0x0130 0x03bc 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA06__ENET2_1588_EVENT3_IN	0x0130 0x03bc 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA06__SPDIF_LOCK		0x0130 0x03bc 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA06__GPIO3_IO11		0x0130 0x03bc 0x0000 5 0
@@ -530,6 +544,7 @@
 #define MX6UL_PAD_LCD_DATA07__LCDIF_DATA07		0x0134 0x03c0 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA07__UART7_DCE_RTS		0x0134 0x03c0 0x0650 1 3
 #define MX6UL_PAD_LCD_DATA07__UART7_DTE_CTS		0x0134 0x03c0 0x0000 1 0
+#define MX6UL_PAD_LCD_DATA07__CA7_MX6UL_TRACE7		0x0134 0x03c0 0x0000 2 0
 #define MX6UL_PAD_LCD_DATA07__ENET2_1588_EVENT3_OUT	0x0134 0x03c0 0x0000 3 0
 #define MX6UL_PAD_LCD_DATA07__SPDIF_EXT_CLK		0x0134 0x03c0 0x061c 4 0
 #define MX6UL_PAD_LCD_DATA07__GPIO3_IO12		0x0134 0x03c0 0x0000 5 0
@@ -537,56 +552,64 @@
 #define MX6UL_PAD_LCD_DATA07__ECSPI1_SS3		0x0134 0x03c0 0x0000 8 0
 #define MX6UL_PAD_LCD_DATA08__LCDIF_DATA08		0x0138 0x03c4 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA08__SPDIF_IN			0x0138 0x03c4 0x0618 1 2
-#define MX6UL_PAD_LCD_DATA08__CSI_DATA16		0x0138 0x03c4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA08__CA7_MX6UL_TRACE8		0x0138 0x03c4 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA08__CSI_DATA16		0x0138 0x03c4 0x0504 3 1
 #define MX6UL_PAD_LCD_DATA08__EIM_DATA00		0x0138 0x03c4 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA08__GPIO3_IO13		0x0138 0x03c4 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA08__SRC_BT_CFG08		0x0138 0x03c4 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA08__FLEXCAN1_TX		0x0138 0x03c4 0x0000 8 0
 #define MX6UL_PAD_LCD_DATA09__LCDIF_DATA09		0x013c 0x03c8 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA09__SAI3_MCLK			0x013c 0x03c8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA09__CSI_DATA17		0x013c 0x03c8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA09__SAI3_MCLK			0x013c 0x03c8 0x0600 1 1
+#define MX6UL_PAD_LCD_DATA09__CA7_MX6UL_TRACE9		0x013c 0x03c8 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA09__CSI_DATA17		0x013c 0x03c8 0x0508 3 1
 #define MX6UL_PAD_LCD_DATA09__EIM_DATA01		0x013c 0x03c8 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA09__GPIO3_IO14		0x013c 0x03c8 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA09__SRC_BT_CFG09		0x013c 0x03c8 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA09__FLEXCAN1_RX		0x013c 0x03c8 0x0584 8 2
 #define MX6UL_PAD_LCD_DATA10__LCDIF_DATA10		0x0140 0x03cc 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA10__SAI3_RX_SYNC		0x0140 0x03cc 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA10__CSI_DATA18		0x0140 0x03cc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA10__CA7_MX6UL_TRACE10		0x0140 0x03cc 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA10__CSI_DATA18		0x0140 0x03cc 0x050c 3 1
 #define MX6UL_PAD_LCD_DATA10__EIM_DATA02		0x0140 0x03cc 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA10__GPIO3_IO15		0x0140 0x03cc 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA10__SRC_BT_CFG10		0x0140 0x03cc 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA10__FLEXCAN2_TX		0x0140 0x03cc 0x0000 8 0
 #define MX6UL_PAD_LCD_DATA11__LCDIF_DATA11		0x0144 0x03d0 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA11__SAI3_RX_BCLK		0x0144 0x03d0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA11__CSI_DATA19		0x0144 0x03d0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA11__CA7_MX6UL_TRACE11		0x0144 0x03d0 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA11__CSI_DATA19		0x0144 0x03d0 0x0510 3 1
 #define MX6UL_PAD_LCD_DATA11__EIM_DATA03		0x0144 0x03d0 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA11__GPIO3_IO16		0x0144 0x03d0 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA11__SRC_BT_CFG11		0x0144 0x03d0 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA11__FLEXCAN2_RX		0x0144 0x03d0 0x0588 8 2
 #define MX6UL_PAD_LCD_DATA12__LCDIF_DATA12		0x0148 0x03d4 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA12__SAI3_TX_SYNC		0x0148 0x03d4 0x060c 1 1
-#define MX6UL_PAD_LCD_DATA12__CSI_DATA20		0x0148 0x03d4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA12__CA7_MX6UL_TRACE12		0x0148 0x03d4 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA12__CSI_DATA20		0x0148 0x03d4 0x0514 3 1
 #define MX6UL_PAD_LCD_DATA12__EIM_DATA04		0x0148 0x03d4 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA12__GPIO3_IO17		0x0148 0x03d4 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA12__SRC_BT_CFG12		0x0148 0x03d4 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA12__ECSPI1_RDY		0x0148 0x03d4 0x0000 8 0
 #define MX6UL_PAD_LCD_DATA13__LCDIF_DATA13		0x014c 0x03d8 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA13__SAI3_TX_BCLK		0x014c 0x03d8 0x0608 1 1
-#define MX6UL_PAD_LCD_DATA13__CSI_DATA21		0x014c 0x03d8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA13__CA7_MX6UL_TRACE13		0x014c 0x03d8 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA13__CSI_DATA21		0x014c 0x03d8 0x0518 3 1
 #define MX6UL_PAD_LCD_DATA13__EIM_DATA05		0x014c 0x03d8 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA13__GPIO3_IO18		0x014c 0x03d8 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA13__SRC_BT_CFG13		0x014c 0x03d8 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA13__USDHC2_RESET_B		0x014c 0x03d8 0x0000 8 0
 #define MX6UL_PAD_LCD_DATA14__LCDIF_DATA14		0x0150 0x03dc 0x0000 0 0
-#define MX6UL_PAD_LCD_DATA14__SAI3_RX_DATA		0x0150 0x03dc 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA14__CSI_DATA22		0x0150 0x03dc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA14__SAI3_RX_DATA		0x0150 0x03dc 0x0604 1 1
+#define MX6UL_PAD_LCD_DATA14__CA7_MX6UL_TRACE14		0x0150 0x03dc 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA14__CSI_DATA22		0x0150 0x03dc 0x051c 3 1
 #define MX6UL_PAD_LCD_DATA14__EIM_DATA06		0x0150 0x03dc 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA14__GPIO3_IO19		0x0150 0x03dc 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA14__SRC_BT_CFG14		0x0150 0x03dc 0x0000 6 0
 #define MX6UL_PAD_LCD_DATA14__USDHC2_DATA4		0x0150 0x03dc 0x068c 8 0
 #define MX6UL_PAD_LCD_DATA15__LCDIF_DATA15		0x0154 0x03e0 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA15__SAI3_TX_DATA		0x0154 0x03e0 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA15__CSI_DATA23		0x0154 0x03e0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA15__CA7_MX6UL_TRACE15		0x0154 0x03e0 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA15__CSI_DATA23		0x0154 0x03e0 0x0520 3 1
 #define MX6UL_PAD_LCD_DATA15__EIM_DATA07		0x0154 0x03e0 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA15__GPIO3_IO20		0x0154 0x03e0 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA15__SRC_BT_CFG15		0x0154 0x03e0 0x0000 6 0
@@ -594,7 +617,8 @@
 #define MX6UL_PAD_LCD_DATA16__LCDIF_DATA16		0x0158 0x03e4 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA16__UART7_DCE_TX		0x0158 0x03e4 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA16__UART7_DTE_RX		0x0158 0x03e4 0x0654 1 2
-#define MX6UL_PAD_LCD_DATA16__CSI_DATA01		0x0158 0x03e4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA16__CA7_MX6UL_TRACE_CLK	0x0158 0x03e4 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA16__CSI_DATA01		0x0158 0x03e4 0x04d4 3 1
 #define MX6UL_PAD_LCD_DATA16__EIM_DATA08		0x0158 0x03e4 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA16__GPIO3_IO21		0x0158 0x03e4 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA16__SRC_BT_CFG24		0x0158 0x03e4 0x0000 6 0
@@ -602,7 +626,8 @@
 #define MX6UL_PAD_LCD_DATA17__LCDIF_DATA17		0x015c 0x03e8 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA17__UART7_DCE_RX		0x015c 0x03e8 0x0654 1 3
 #define MX6UL_PAD_LCD_DATA17__UART7_DTE_TX		0x015c 0x03e8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA17__CSI_DATA00		0x015c 0x03e8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA17__CA7_MX6UL_TRACE_CTL	0x015c 0x03e8 0x0000 2 0
+#define MX6UL_PAD_LCD_DATA17__CSI_DATA00		0x015c 0x03e8 0x04d0 3 1
 #define MX6UL_PAD_LCD_DATA17__EIM_DATA09		0x015c 0x03e8 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA17__GPIO3_IO22		0x015c 0x03e8 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA17__SRC_BT_CFG25		0x015c 0x03e8 0x0000 6 0
@@ -610,7 +635,7 @@
 #define MX6UL_PAD_LCD_DATA18__LCDIF_DATA18		0x0160 0x03ec 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA18__PWM5_OUT			0x0160 0x03ec 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA18__CA7_MX6UL_EVENTO		0x0160 0x03ec 0x0000 2 0
-#define MX6UL_PAD_LCD_DATA18__CSI_DATA10		0x0160 0x03ec 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA18__CSI_DATA10		0x0160 0x03ec 0x04ec 3 1
 #define MX6UL_PAD_LCD_DATA18__EIM_DATA10		0x0160 0x03ec 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA18__GPIO3_IO23		0x0160 0x03ec 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA18__SRC_BT_CFG26		0x0160 0x03ec 0x0000 6 0
@@ -622,7 +647,7 @@
 #define MX6UL_PAD_LCD_DATA19__LCDIF_DATA19		0x0164 0x03f0 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA19__PWM6_OUT			0x0164 0x03f0 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA19__WDOG1_WDOG_ANY		0x0164 0x03f0 0x0000 2 0
-#define MX6UL_PAD_LCD_DATA19__CSI_DATA11		0x0164 0x03f0 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA19__CSI_DATA11		0x0164 0x03f0 0x04f0 3 1
 #define MX6UL_PAD_LCD_DATA20__EIM_DATA12		0x0168 0x03f4 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA20__GPIO3_IO25		0x0168 0x03f4 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA20__SRC_BT_CFG28		0x0168 0x03f4 0x0000 6 0
@@ -631,12 +656,12 @@
 #define MX6UL_PAD_LCD_DATA20__UART8_DCE_TX		0x0168 0x03f4 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA20__UART8_DTE_RX		0x0168 0x03f4 0x065c 1 2
 #define MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK		0x0168 0x03f4 0x0534 2 0
-#define MX6UL_PAD_LCD_DATA20__CSI_DATA12		0x0168 0x03f4 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA20__CSI_DATA12		0x0168 0x03f4 0x04f4 3 1
 #define MX6UL_PAD_LCD_DATA21__LCDIF_DATA21		0x016c 0x03f8 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA21__UART8_DCE_RX		0x016c 0x03f8 0x065c 1 3
 #define MX6UL_PAD_LCD_DATA21__UART8_DTE_TX		0x016c 0x03f8 0x0000 1 0
-#define MX6UL_PAD_LCD_DATA21__ECSPI1_SS0		0x016c 0x03f8 0x0000 2 0
-#define MX6UL_PAD_LCD_DATA21__CSI_DATA13		0x016c 0x03f8 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA21__ECSPI1_SS0		0x016c 0x03f8 0x0540 2 0
+#define MX6UL_PAD_LCD_DATA21__CSI_DATA13		0x016c 0x03f8 0x04f8 3 1
 #define MX6UL_PAD_LCD_DATA21__EIM_DATA13		0x016c 0x03f8 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA21__GPIO3_IO26		0x016c 0x03f8 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA21__SRC_BT_CFG29		0x016c 0x03f8 0x0000 6 0
@@ -644,7 +669,7 @@
 #define MX6UL_PAD_LCD_DATA22__LCDIF_DATA22		0x0170 0x03fc 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA22__MQS_RIGHT			0x0170 0x03fc 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI		0x0170 0x03fc 0x053c 2 0
-#define MX6UL_PAD_LCD_DATA22__CSI_DATA14		0x0170 0x03fc 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA22__CSI_DATA14		0x0170 0x03fc 0x04fc 3 1
 #define MX6UL_PAD_LCD_DATA22__EIM_DATA14		0x0170 0x03fc 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA22__GPIO3_IO27		0x0170 0x03fc 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA22__SRC_BT_CFG30		0x0170 0x03fc 0x0000 6 0
@@ -652,7 +677,7 @@
 #define MX6UL_PAD_LCD_DATA23__LCDIF_DATA23		0x0174 0x0400 0x0000 0 0
 #define MX6UL_PAD_LCD_DATA23__MQS_LEFT			0x0174 0x0400 0x0000 1 0
 #define MX6UL_PAD_LCD_DATA23__ECSPI1_MISO		0x0174 0x0400 0x0538 2 0
-#define MX6UL_PAD_LCD_DATA23__CSI_DATA15		0x0174 0x0400 0x0000 3 0
+#define MX6UL_PAD_LCD_DATA23__CSI_DATA15		0x0174 0x0400 0x0500 3 1
 #define MX6UL_PAD_LCD_DATA23__EIM_DATA15		0x0174 0x0400 0x0000 4 0
 #define MX6UL_PAD_LCD_DATA23__GPIO3_IO28		0x0174 0x0400 0x0000 5 0
 #define MX6UL_PAD_LCD_DATA23__SRC_BT_CFG31		0x0174 0x0400 0x0000 6 0
@@ -660,42 +685,42 @@
 #define MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B		0x0178 0x0404 0x0000 0 0
 #define MX6UL_PAD_NAND_RE_B__USDHC2_CLK			0x0178 0x0404 0x0670 1 2
 #define MX6UL_PAD_NAND_RE_B__QSPI_B_SCLK		0x0178 0x0404 0x0000 2 0
-#define MX6UL_PAD_NAND_RE_B__KPP_ROW00			0x0178 0x0404 0x0000 3 0
+#define MX6UL_PAD_NAND_RE_B__KPP_ROW00			0x0178 0x0404 0x05d0 3 1
 #define MX6UL_PAD_NAND_RE_B__EIM_EB_B00			0x0178 0x0404 0x0000 4 0
 #define MX6UL_PAD_NAND_RE_B__GPIO4_IO00			0x0178 0x0404 0x0000 5 0
 #define MX6UL_PAD_NAND_RE_B__ECSPI3_SS2			0x0178 0x0404 0x0000 8 0
 #define MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B		0x017c 0x0408 0x0000 0 0
 #define MX6UL_PAD_NAND_WE_B__USDHC2_CMD			0x017c 0x0408 0x0678 1 2
 #define MX6UL_PAD_NAND_WE_B__QSPI_B_SS0_B		0x017c 0x0408 0x0000 2 0
-#define MX6UL_PAD_NAND_WE_B__KPP_COL00			0x017c 0x0408 0x0000 3 0
+#define MX6UL_PAD_NAND_WE_B__KPP_COL00			0x017c 0x0408 0x05c4 3 1
 #define MX6UL_PAD_NAND_WE_B__EIM_EB_B01			0x017c 0x0408 0x0000 4 0
 #define MX6UL_PAD_NAND_WE_B__GPIO4_IO01			0x017c 0x0408 0x0000 5 0
 #define MX6UL_PAD_NAND_WE_B__ECSPI3_SS3			0x017c 0x0408 0x0000 8 0
 #define MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00		0x0180 0x040c 0x0000 0 0
 #define MX6UL_PAD_NAND_DATA00__USDHC2_DATA0		0x0180 0x040c 0x067c 1 2
 #define MX6UL_PAD_NAND_DATA00__QSPI_B_SS1_B		0x0180 0x040c 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA00__KPP_ROW01		0x0180 0x040c 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA00__KPP_ROW01		0x0180 0x040c 0x05d4 3 1
 #define MX6UL_PAD_NAND_DATA00__EIM_AD08			0x0180 0x040c 0x0000 4 0
 #define MX6UL_PAD_NAND_DATA00__GPIO4_IO02		0x0180 0x040c 0x0000 5 0
 #define MX6UL_PAD_NAND_DATA00__ECSPI4_RDY		0x0180 0x040c 0x0000 8 0
 #define MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01		0x0184 0x0410 0x0000 0 0
 #define MX6UL_PAD_NAND_DATA01__USDHC2_DATA1		0x0184 0x0410 0x0680 1 2
 #define MX6UL_PAD_NAND_DATA01__QSPI_B_DQS		0x0184 0x0410 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA01__KPP_COL01		0x0184 0x0410 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA01__KPP_COL01		0x0184 0x0410 0x05c8 3 1
 #define MX6UL_PAD_NAND_DATA01__EIM_AD09			0x0184 0x0410 0x0000 4 0
 #define MX6UL_PAD_NAND_DATA01__GPIO4_IO03		0x0184 0x0410 0x0000 5 0
 #define MX6UL_PAD_NAND_DATA01__ECSPI4_SS1		0x0184 0x0410 0x0000 8 0
 #define MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02		0x0188 0x0414 0x0000 0 0
 #define MX6UL_PAD_NAND_DATA02__USDHC2_DATA2		0x0188 0x0414 0x0684 1 1
 #define MX6UL_PAD_NAND_DATA02__QSPI_B_DATA00		0x0188 0x0414 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA02__KPP_ROW02		0x0188 0x0414 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA02__KPP_ROW02		0x0188 0x0414 0x05d8 3 1
 #define MX6UL_PAD_NAND_DATA02__EIM_AD10			0x0188 0x0414 0x0000 4 0
 #define MX6UL_PAD_NAND_DATA02__GPIO4_IO04		0x0188 0x0414 0x0000 5 0
 #define MX6UL_PAD_NAND_DATA02__ECSPI4_SS2		0x0188 0x0414 0x0000 8 0
 #define MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03		0x018c 0x0418 0x0000 0 0
 #define MX6UL_PAD_NAND_DATA03__USDHC2_DATA3		0x018c 0x0418 0x0688 1 2
 #define MX6UL_PAD_NAND_DATA03__QSPI_B_DATA01		0x018c 0x0418 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA03__KPP_COL02		0x018c 0x0418 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA03__KPP_COL02		0x018c 0x0418 0x05cc 3 1
 #define MX6UL_PAD_NAND_DATA03__EIM_AD11			0x018c 0x0418 0x0000 4 0
 #define MX6UL_PAD_NAND_DATA03__GPIO4_IO05		0x018c 0x0418 0x0000 5 0
 #define MX6UL_PAD_NAND_DATA03__ECSPI4_SS3		0x018c 0x0418 0x0000 8 0
@@ -726,7 +751,7 @@
 #define MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07		0x019c 0x0428 0x0000 0 0
 #define MX6UL_PAD_NAND_DATA07__USDHC2_DATA7		0x019c 0x0428 0x0698 1 1
 #define MX6UL_PAD_NAND_DATA07__QSPI_A_SS1_B		0x019c 0x0428 0x0000 2 0
-#define MX6UL_PAD_NAND_DATA07__ECSPI4_SS0		0x019c 0x0428 0x0000 3 0
+#define MX6UL_PAD_NAND_DATA07__ECSPI4_SS0		0x019c 0x0428 0x0570 3 1
 #define MX6UL_PAD_NAND_DATA07__EIM_AD15			0x019c 0x0428 0x0000 4 0
 #define MX6UL_PAD_NAND_DATA07__GPIO4_IO09		0x019c 0x0428 0x0000 5 0
 #define MX6UL_PAD_NAND_DATA07__UART2_DCE_RTS		0x019c 0x0428 0x0628 8 5
@@ -748,7 +773,7 @@
 #define MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B		0x01a8 0x0434 0x0000 0 0
 #define MX6UL_PAD_NAND_READY_B__USDHC1_DATA4		0x01a8 0x0434 0x0000 1 0
 #define MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00		0x01a8 0x0434 0x0000 2 0
-#define MX6UL_PAD_NAND_READY_B__ECSPI3_SS0		0x01a8 0x0434 0x0000 3 0
+#define MX6UL_PAD_NAND_READY_B__ECSPI3_SS0		0x01a8 0x0434 0x0560 3 1
 #define MX6UL_PAD_NAND_READY_B__EIM_CS1_B		0x01a8 0x0434 0x0000 4 0
 #define MX6UL_PAD_NAND_READY_B__GPIO4_IO12		0x01a8 0x0434 0x0000 5 0
 #define MX6UL_PAD_NAND_READY_B__UART3_DCE_TX		0x01a8 0x0434 0x0000 8 0
@@ -783,7 +808,7 @@
 #define MX6UL_PAD_NAND_DQS__PWM5_OUT			0x01b8 0x0444 0x0000 3 0
 #define MX6UL_PAD_NAND_DQS__EIM_WAIT			0x01b8 0x0444 0x0000 4 0
 #define MX6UL_PAD_NAND_DQS__GPIO4_IO16			0x01b8 0x0444 0x0000 5 0
-#define MX6UL_PAD_NAND_DQS__SDMA_EXT_EVENT01		0x01b8 0x0444 0x0000 6 0
+#define MX6UL_PAD_NAND_DQS__SDMA_EXT_EVENT01		0x01b8 0x0444 0x0614 6 1
 #define MX6UL_PAD_NAND_DQS__SPDIF_EXT_CLK		0x01b8 0x0444 0x061c 8 1
 #define MX6UL_PAD_SD1_CMD__USDHC1_CMD			0x01bc 0x0448 0x0000 0 0
 #define MX6UL_PAD_SD1_CMD__GPT2_COMPARE1		0x01bc 0x0448 0x0000 1 0
@@ -791,11 +816,11 @@
 #define MX6UL_PAD_SD1_CMD__SPDIF_OUT			0x01bc 0x0448 0x0000 3 0
 #define MX6UL_PAD_SD1_CMD__EIM_ADDR19			0x01bc 0x0448 0x0000 4 0
 #define MX6UL_PAD_SD1_CMD__GPIO2_IO16			0x01bc 0x0448 0x0000 5 0
-#define MX6UL_PAD_SD1_CMD__SDMA_EXT_EVENT00		0x01bc 0x0448 0x0000 6 0
+#define MX6UL_PAD_SD1_CMD__SDMA_EXT_EVENT00		0x01bc 0x0448 0x0610 6 2
 #define MX6UL_PAD_SD1_CMD__USB_OTG1_PWR			0x01bc 0x0448 0x0000 8 0
 #define MX6UL_PAD_SD1_CLK__USDHC1_CLK			0x01c0 0x044c 0x0000 0 0
 #define MX6UL_PAD_SD1_CLK__GPT2_COMPARE2		0x01c0 0x044c 0x0000 1 0
-#define MX6UL_PAD_SD1_CLK__SAI2_MCLK			0x01c0 0x044c 0x0000 2 0
+#define MX6UL_PAD_SD1_CLK__SAI2_MCLK			0x01c0 0x044c 0x05f0 2 1
 #define MX6UL_PAD_SD1_CLK__SPDIF_IN			0x01c0 0x044c 0x0618 3 3
 #define MX6UL_PAD_SD1_CLK__EIM_ADDR20			0x01c0 0x044c 0x0000 4 0
 #define MX6UL_PAD_SD1_CLK__GPIO2_IO17			0x01c0 0x044c 0x0000 5 0
@@ -878,10 +903,10 @@
 #define MX6UL_PAD_CSI_DATA01__CSI_DATA03		0x01e8 0x0474 0x04c8 0 0
 #define MX6UL_PAD_CSI_DATA01__USDHC2_DATA1		0x01e8 0x0474 0x0680 1 0
 #define MX6UL_PAD_CSI_DATA01__SIM1_PORT1_SVEN		0x01e8 0x0474 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA01__ECSPI2_SS0		0x01e8 0x0474 0x0000 3 0
+#define MX6UL_PAD_CSI_DATA01__ECSPI2_SS0		0x01e8 0x0474 0x0550 3 0
 #define MX6UL_PAD_CSI_DATA01__EIM_AD01			0x01e8 0x0474 0x0000 4 0
 #define MX6UL_PAD_CSI_DATA01__GPIO4_IO22		0x01e8 0x0474 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA01__SAI1_MCLK			0x01e8 0x0474 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA01__SAI1_MCLK			0x01e8 0x0474 0x05e0 6 0
 #define MX6UL_PAD_CSI_DATA01__UART5_DCE_RX		0x01e8 0x0474 0x0644 8 1
 #define MX6UL_PAD_CSI_DATA01__UART5_DTE_TX		0x01e8 0x0474 0x0000 8 0
 #define MX6UL_PAD_CSI_DATA02__CSI_DATA04		0x01ec 0x0478 0x04d8 0 1
@@ -913,7 +938,7 @@
 #define MX6UL_PAD_CSI_DATA05__CSI_DATA07		0x01f8 0x0484 0x04e0 0 1
 #define MX6UL_PAD_CSI_DATA05__USDHC2_DATA5		0x01f8 0x0484 0x0690 1 2
 #define MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B		0x01f8 0x0484 0x0000 2 0
-#define MX6UL_PAD_CSI_DATA05__ECSPI1_SS0		0x01f8 0x0484 0x0000 3 0
+#define MX6UL_PAD_CSI_DATA05__ECSPI1_SS0		0x01f8 0x0484 0x0540 3 1
 #define MX6UL_PAD_CSI_DATA05__EIM_AD05			0x01f8 0x0484 0x0000 4 0
 #define MX6UL_PAD_CSI_DATA05__GPIO4_IO26		0x01f8 0x0484 0x0000 5 0
 #define MX6UL_PAD_CSI_DATA05__SAI1_TX_BCLK		0x01f8 0x0484 0x05e8 6 1
@@ -924,7 +949,7 @@
 #define MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI		0x01fc 0x0488 0x053c 3 1
 #define MX6UL_PAD_CSI_DATA06__EIM_AD06			0x01fc 0x0488 0x0000 4 0
 #define MX6UL_PAD_CSI_DATA06__GPIO4_IO27		0x01fc 0x0488 0x0000 5 0
-#define MX6UL_PAD_CSI_DATA06__SAI1_RX_DATA		0x01fc 0x0488 0x0000 6 0
+#define MX6UL_PAD_CSI_DATA06__SAI1_RX_DATA		0x01fc 0x0488 0x05e4 6 1
 #define MX6UL_PAD_CSI_DATA06__USDHC1_RESET_B		0x01fc 0x0488 0x0000 8 0
 #define MX6UL_PAD_CSI_DATA07__CSI_DATA09		0x0200 0x048c 0x04e8 0 1
 #define MX6UL_PAD_CSI_DATA07__USDHC2_DATA7		0x0200 0x048c 0x0698 1 2
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 5d6c3ba36cd1..81c426e1b664 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -22,7 +22,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		ethernet0 = &fec1;
@@ -86,15 +86,10 @@
 				 <&clks IMX6UL_CA7_SECONDARY_SEL>,
 				 <&clks IMX6UL_CLK_STEP>,
 				 <&clks IMX6UL_CLK_PLL1_SW>,
-				 <&clks IMX6UL_CLK_PLL1_SYS>,
-				 <&clks IMX6UL_PLL1_BYPASS>,
-				 <&clks IMX6UL_CLK_PLL1>,
-				 <&clks IMX6UL_PLL1_BYPASS_SRC>,
-				 <&clks IMX6UL_CLK_OSC>;
+				 <&clks IMX6UL_CLK_PLL1_SYS>;
 			clock-names = "arm", "pll2_bus",  "pll2_pfd2_396m",
 				      "secondary_sel", "step", "pll1_sw",
-				      "pll1_sys", "pll1_bypass", "pll1",
-				      "pll1_bypass_src", "osc";
+				      "pll1_sys";
 			arm-supply = <&reg_arm>;
 			soc-supply = <&reg_soc>;
 		};
@@ -102,14 +97,26 @@
 
 	intc: interrupt-controller@a01000 {
 		compatible = "arm,gic-400", "arm,cortex-a7-gic";
+		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		#interrupt-cells = <3>;
 		interrupt-controller;
+		interrupt-parent = <&intc>;
 		reg = <0x00a01000 0x1000>,
 		      <0x00a02000 0x2000>,
 		      <0x00a04000 0x2000>,
 		      <0x00a06000 0x2000>;
 	};
 
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+		interrupt-parent = <&intc>;
+		status = "disabled";
+	};
+
 	ckil: clock-cli {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
diff --git a/arch/arm/boot/dts/imx6ull-14x14-evk.dts b/arch/arm/boot/dts/imx6ull-14x14-evk.dts
index 4741871434dd..30ef60344af3 100644
--- a/arch/arm/boot/dts/imx6ull-14x14-evk.dts
+++ b/arch/arm/boot/dts/imx6ull-14x14-evk.dts
@@ -39,7 +39,10 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "imx6ul-14x14-evk.dts"
+/dts-v1/;
+
+#include "imx6ull.dtsi"
+#include "imx6ul-14x14-evk.dtsi"
 
 / {
 	model = "Freescale i.MX6 UlltraLite 14x14 EVK Board";
diff --git a/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts
new file mode 100644
index 000000000000..08669a18349e
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2018 Toradex AG
+ */
+
+/dts-v1/;
+
+#include "imx6ull-colibri-nonwifi.dtsi"
+#include "imx6ull-colibri-eval-v3.dtsi"
+
+/ {
+	model = "Toradex Colibri iMX6ULL 256MB on Colibri Evaluation Board V3";
+	compatible = "toradex,colibri-imx6ull-eval", "fsl,imx6ull";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi
new file mode 100644
index 000000000000..006690ea98c0
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-colibri-eval-v3.dtsi
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2017 Toradex AG
+ */
+
+/ {
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	/* fixed crystal dedicated to mcp2515 */
+	clk16m: clk16m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <16000000>;
+	};
+
+	panel: panel {
+		compatible = "edt,et057090dhu";
+		backlight = <&bl>;
+		power-supply = <&reg_3v3>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&lcdif_out>;
+			};
+		};
+	};
+
+	reg_3v3: regulator-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_5v0: regulator-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	reg_usbh_vbus: regulator-usbh-vbus {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usbh_reg>;
+		regulator-name = "VCC_USB[1-4]";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio1 2 GPIO_ACTIVE_LOW>;
+		vin-supply = <&reg_5v0>;
+	};
+};
+
+&adc1 {
+	status = "okay";
+};
+
+&bl {
+	brightness-levels = <0 4 8 16 32 64 128 255>;
+	default-brightness-level = <6>;
+	power-supply = <&reg_3v3>;
+	pwms = <&pwm4 0 5000000 1>;
+	status = "okay";
+};
+
+&ecspi1 {
+	status = "okay";
+
+	mcp2515: can@0 {
+		compatible = "microchip,mcp2515";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_can_int>;
+		reg = <0>;
+		clocks = <&clk16m>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+		spi-max-frequency = <10000000>;
+		vdd-supply = <&reg_3v3>;
+		xceiver-supply = <&reg_5v0>;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	status = "okay";
+
+	/* M41T0M6 real time clock on carrier board */
+	m41t0m6: rtc@68 {
+		compatible = "st,m41t0";
+		reg = <0x68>;
+	};
+};
+
+&lcdif {
+	status = "okay";
+
+	port {
+		lcdif_out: endpoint {
+			remote-endpoint = <&panel_in>;
+		};
+	};
+};
+
+/* PWM <A> */
+&pwm4 {
+	status = "okay";
+};
+
+/* PWM <B> */
+&pwm5 {
+	status = "okay";
+};
+
+/* PWM <C> */
+&pwm6 {
+	status = "okay";
+};
+
+/* PWM <D> */
+&pwm7 {
+	status = "okay";
+};
+
+&uart1 {
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&uart5 {
+	status = "okay";
+};
+
+&usbotg1 {
+	status = "okay";
+};
+
+&usbotg2 {
+	vbus-supply = <&reg_usbh_vbus>;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_snvs_usdhc1_cd>;
+	no-1-8-v;
+	cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	wakeup-source;
+	keep-power-in-suspend;
+	vmmc-supply = <&reg_3v3>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-nonwifi.dtsi b/arch/arm/boot/dts/imx6ull-colibri-nonwifi.dtsi
new file mode 100644
index 000000000000..cfda666a34f4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-colibri-nonwifi.dtsi
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2018 Toradex AG
+ */
+
+#include "imx6ull-colibri.dtsi"
+
+/ {
+	memory {
+		reg = <0x80000000 0x10000000>;
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3
+		&pinctrl_gpio4 &pinctrl_gpio5 &pinctrl_gpio6>;
+};
+
+&iomuxc_snvs {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_snvs_gpio1 &pinctrl_snvs_gpio2 &pinctrl_snvs_gpio3>;
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts b/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts
new file mode 100644
index 000000000000..df72ce1ae2cb
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-colibri-wifi-eval-v3.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2018 Toradex AG
+ */
+
+/dts-v1/;
+
+#include "imx6ull-colibri-wifi.dtsi"
+#include "imx6ull-colibri-eval-v3.dtsi"
+
+/ {
+	model = "Toradex Colibri iMX6ULL 512MB on Colibri Evaluation Board V3";
+	compatible = "toradex,colibri-imx6ull-wifi-eval", "fsl,imx6ull";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi b/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
new file mode 100644
index 000000000000..f48291b7cbf0
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-colibri-wifi.dtsi
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2018 Toradex AG
+ */
+
+#include "imx6ull-colibri.dtsi"
+
+/ {
+	memory {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	wifi_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_snvs_wifi_pdn>;
+		reset-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&cpu0 {
+	clock-frequency = <792000000>;
+	operating-points = <
+		/* kHz	uV */
+		792000  1225000
+		528000	1175000
+		396000	1025000
+		198000	950000
+	>;
+	fsl,soc-operating-points = <
+		/* KHz	uV */
+		792000  1175000
+		528000	1175000
+		396000	1175000
+		198000	1175000
+	>;
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3
+		&pinctrl_gpio4 &pinctrl_gpio5>;
+
+};
+
+&iomuxc_snvs {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_snvs_gpio1 &pinctrl_snvs_gpio2>;
+};
+
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	assigned-clocks = <&clks IMX6UL_CLK_USDHC2_SEL>, <&clks IMX6UL_CLK_USDHC2>;
+	assigned-clock-parents = <&clks IMX6UL_CLK_PLL2_PFD2>;
+	assigned-clock-rates = <0>, <198000000>;
+	cap-power-off-card;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	no-1-8-v;
+	non-removable;
+	vmmc-supply = <&reg_module_3v3>;
+	wakeup-source;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6ull-colibri.dtsi b/arch/arm/boot/dts/imx6ull-colibri.dtsi
new file mode 100644
index 000000000000..6c63a7384611
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-colibri.dtsi
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2018 Toradex AG
+ */
+
+#include "imx6ull.dtsi"
+
+/ {
+	aliases {
+		ethernet0 = &fec2;
+		ethernet1 = &fec1;
+	};
+
+	bl: backlight {
+		compatible = "pwm-backlight";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_bl_on>;
+		enable-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+		status = "disabled";
+	};
+
+	reg_module_3v3: regulator-module-3v3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "+V3.3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_module_3v3_avdd: regulator-module-3v3-avdd {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-name = "+V3.3_AVDD_AUDIO";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_sd1_vmmc: regulator-sd1-vmmc {
+		compatible = "regulator-gpio";
+		gpio = <&gpio5 9 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_snvs_reg_sd>;
+		regulator-always-on;
+		regulator-name = "+V3.3_1.8_SD";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+		states = <1800000 0x1 3300000 0x0>;
+		vin-supply = <&reg_module_3v3>;
+	};
+};
+
+&adc1 {
+	num-channels = <10>;
+	vref-supply = <&reg_module_3v3_avdd>;
+};
+
+/* Colibri SPI */
+&ecspi1 {
+	cs-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>;
+};
+
+&fec2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet2>;
+	phy-mode = "rmii";
+	phy-handle = <&ethphy1>;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy1: ethernet-phy@2 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			max-speed = <100>;
+			reg = <2>;
+		};
+	};
+};
+
+&gpmi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpmi_nand>;
+	nand-on-flash-bbt;
+	nand-ecc-mode = "hw";
+	nand-ecc-strength = <8>;
+	nand-ecc-step-size = <512>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+	sda-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>;
+	scl-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
+};
+
+&i2c2 {
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	sda-gpios = <&gpio1 31 GPIO_ACTIVE_LOW>;
+	scl-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	ad7879@2c {
+		compatible = "adi,ad7879-1";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_snvs_ad7879_int>;
+		reg = <0x2c>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+		touchscreen-max-pressure = <4096>;
+		adi,resistance-plate-x = <120>;
+		adi,first-conversion-delay = /bits/ 8 <3>;
+		adi,acquisition-time = /bits/ 8 <1>;
+		adi,median-filter-size = /bits/ 8 <2>;
+		adi,averaging = /bits/ 8 <1>;
+		adi,conversion-interval = /bits/ 8 <255>;
+	};
+};
+
+&lcdif {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lcdif_dat
+		     &pinctrl_lcdif_ctrl>;
+};
+
+&pwm4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm4>;
+	#pwm-cells = <3>;
+};
+
+&pwm5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm5>;
+	#pwm-cells = <3>;
+};
+
+&pwm6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm6>;
+	#pwm-cells = <3>;
+};
+
+&pwm7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm7>;
+	#pwm-cells = <3>;
+};
+
+&sdma {
+	status = "okay";
+};
+
+&snvs_pwrkey {
+	status = "disabled";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1 &pinctrl_uart1_ctrl1>;
+	uart-has-rtscts;
+	fsl,dte-mode;
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	uart-has-rtscts;
+	fsl,dte-mode;
+};
+
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>;
+	fsl,dte-mode;
+};
+
+&usbotg1 {
+	dr_mode = "otg";
+	srp-disable;
+	hnp-disable;
+	adp-disable;
+};
+
+&usbotg2 {
+	dr_mode = "host";
+};
+
+&usdhc1 {
+	assigned-clocks = <&clks IMX6UL_CLK_USDHC1_SEL>, <&clks IMX6UL_CLK_USDHC1>;
+	assigned-clock-parents = <&clks IMX6UL_CLK_PLL2_PFD2>;
+	assigned-clock-rates = <0>, <198000000>;
+};
+
+&iomuxc {
+	pinctrl_can_int: canint-grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04	0X14 /* SODIMM 73 */
+		>;
+	};
+
+	pinctrl_enet2: enet2-grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO06__ENET2_MDIO	0x1b0b0
+			MX6UL_PAD_GPIO1_IO07__ENET2_MDC		0x1b0b0
+			MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00	0x1b0b0
+			MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01	0x1b0b0
+			MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN	0x1b0b0
+			MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER	0x1b0b0
+			MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b031
+			MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00	0x1b0b0
+			MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01	0x1b0b0
+			MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN	0x1b0b0
+		>;
+	};
+
+	pinctrl_ecspi1_cs: ecspi1-cs-grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA21__GPIO3_IO26	0x000a0
+		>;
+	};
+
+	pinctrl_ecspi1: ecspi1-grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK	0x000a0
+			MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI	0x000a0
+			MX6UL_PAD_LCD_DATA23__ECSPI1_MISO	0x100a0
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2-grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_TX_DATA0__FLEXCAN2_RX	0x1b020
+			MX6UL_PAD_ENET1_RX_EN__FLEXCAN2_TX	0x1b020
+		>;
+	};
+
+	pinctrl_gpio_bl_on: gpio-bl-on-grp {
+		fsl,pins = <
+			MX6UL_PAD_JTAG_TMS__GPIO1_IO11		0x000a0
+		>;
+	};
+
+	pinctrl_gpio1: gpio1-grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_RX_DATA0__GPIO2_IO00	0x74 /* SODIMM 55 */
+			MX6UL_PAD_ENET1_RX_DATA1__GPIO2_IO01	0x74 /* SODIMM 63 */
+			MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25	0X14 /* SODIMM 77 */
+			MX6UL_PAD_JTAG_TCK__GPIO1_IO14		0x14 /* SODIMM 99 */
+			MX6UL_PAD_NAND_CE1_B__GPIO4_IO14	0x14 /* SODIMM 133 */
+			MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24	0x14 /* SODIMM 135 */
+			MX6UL_PAD_UART3_CTS_B__GPIO1_IO26	0x14 /* SODIMM 100 */
+			MX6UL_PAD_JTAG_TRST_B__GPIO1_IO15	0x14 /* SODIMM 102 */
+			MX6UL_PAD_ENET1_RX_ER__GPIO2_IO07	0x14 /* SODIMM 104 */
+			MX6UL_PAD_UART3_RTS_B__GPIO1_IO27	0x14 /* SODIMM 186 */
+		>;
+	};
+
+	pinctrl_gpio2: gpio2-grp { /* Camera */
+		fsl,pins = <
+			MX6UL_PAD_CSI_DATA04__GPIO4_IO25	0x74 /* SODIMM 69 */
+			MX6UL_PAD_CSI_MCLK__GPIO4_IO17		0x14 /* SODIMM 75 */
+			MX6UL_PAD_CSI_DATA06__GPIO4_IO27	0x14 /* SODIMM 85 */
+			MX6UL_PAD_CSI_PIXCLK__GPIO4_IO18	0x14 /* SODIMM 96 */
+			MX6UL_PAD_CSI_DATA05__GPIO4_IO26	0x14 /* SODIMM 98 */
+		>;
+	};
+
+	pinctrl_gpio3: gpio3-grp { /* CAN2 */
+		fsl,pins = <
+			MX6UL_PAD_ENET1_RX_EN__GPIO2_IO02	0x14 /* SODIMM 178 */
+			MX6UL_PAD_ENET1_TX_DATA0__GPIO2_IO03	0x14 /* SODIMM 188 */
+		>;
+	};
+
+	pinctrl_gpio4: gpio4-grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_DATA07__GPIO4_IO28	0x74 /* SODIMM 65 */
+		>;
+	};
+
+	pinctrl_gpio5: gpio5-grp { /* ATMEL MXT TOUCH */
+		fsl,pins = <
+			MX6UL_PAD_JTAG_MOD__GPIO1_IO10		0x74 /* SODIMM 106 */
+		>;
+	};
+
+	pinctrl_gpio6: gpio6-grp { /* Wifi pins */
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO03__GPIO1_IO03	0x14 /* SODIMM 89 */
+			MX6UL_PAD_CSI_DATA02__GPIO4_IO23	0x14 /* SODIMM 79 */
+			MX6UL_PAD_CSI_VSYNC__GPIO4_IO19		0x14 /* SODIMM 81 */
+			MX6UL_PAD_CSI_DATA03__GPIO4_IO24	0x14 /* SODIMM 97 */
+			MX6UL_PAD_CSI_DATA00__GPIO4_IO21	0x14 /* SODIMM 101 */
+			MX6UL_PAD_CSI_DATA01__GPIO4_IO22	0x14 /* SODIMM 103 */
+			MX6UL_PAD_CSI_HSYNC__GPIO4_IO20		0x14 /* SODIMM 94 */
+		>;
+	};
+
+	pinctrl_gpmi_nand: gpmi-nand-grp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00	0x100a9
+			MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01	0x100a9
+			MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02	0x100a9
+			MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03	0x100a9
+			MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04	0x100a9
+			MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05	0x100a9
+			MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06	0x100a9
+			MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07	0x100a9
+			MX6UL_PAD_NAND_CLE__RAWNAND_CLE		0x100a9
+			MX6UL_PAD_NAND_ALE__RAWNAND_ALE		0x100a9
+			MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B	0x100a9
+			MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B	0x100a9
+			MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B	0x100a9
+			MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B	0x100a9
+		>;
+	};
+
+	pinctrl_i2c1: i2c1-grp {
+		fsl,pins = <
+			MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
+			MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1-gpio-grp {
+		fsl,pins = <
+			MX6UL_PAD_UART4_TX_DATA__GPIO1_IO28 0x4001b8b0
+			MX6UL_PAD_UART4_RX_DATA__GPIO1_IO29 0x4001b8b0
+		>;
+	};
+
+	pinctrl_i2c2: i2c2-grp {
+		fsl,pins = <
+			MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
+			MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
+		>;
+	};
+
+	pinctrl_i2c2_gpio: i2c2-gpio-grp {
+		fsl,pins = <
+			MX6UL_PAD_UART5_TX_DATA__GPIO1_IO30 0x4001b8b0
+			MX6UL_PAD_UART5_RX_DATA__GPIO1_IO31 0x4001b8b0
+		>;
+	};
+
+	pinctrl_lcdif_dat: lcdif-dat-grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x00079
+			MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x00079
+			MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x00079
+			MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x00079
+			MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x00079
+			MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x00079
+			MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x00079
+			MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x00079
+			MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x00079
+			MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x00079
+			MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x00079
+			MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x00079
+			MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x00079
+			MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x00079
+			MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x00079
+			MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x00079
+			MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x00079
+			MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x00079
+		>;
+	};
+
+	pinctrl_lcdif_ctrl: lcdif-ctrl-grp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x00079
+			MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x00079
+			MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x00079
+			MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x00079
+		>;
+	};
+
+	pinctrl_pwm4: pwm4-grp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_WP_B__PWM4_OUT	0x00079
+		>;
+	};
+
+	pinctrl_pwm5: pwm5-grp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_DQS__PWM5_OUT	0x00079
+		>;
+	};
+
+	pinctrl_pwm6: pwm6-grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_TX_EN__PWM6_OUT	0x00079
+		>;
+	};
+
+	pinctrl_pwm7: pwm7-grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_TX_CLK__PWM7_OUT	0x00079
+		>;
+	};
+
+	pinctrl_uart1: uart1-grp {
+		fsl,pins = <
+			MX6UL_PAD_UART1_TX_DATA__UART1_DTE_RX	0x1b0b1
+			MX6UL_PAD_UART1_RX_DATA__UART1_DTE_TX	0x1b0b1
+			MX6UL_PAD_UART1_RTS_B__UART1_DTE_CTS	0x1b0b1
+			MX6UL_PAD_UART1_CTS_B__UART1_DTE_RTS	0x1b0b1
+		>;
+	};
+
+	pinctrl_uart1_ctrl1: uart1-ctrl1-grp { /* Additional DTR, DCD */
+		fsl,pins = <
+			MX6UL_PAD_JTAG_TDI__GPIO1_IO13		0x1b0b1 /* DCD */
+			MX6UL_PAD_LCD_DATA18__GPIO3_IO23	0x1b0b1 /* DSR */
+			MX6UL_PAD_JTAG_TDO__GPIO1_IO12		0x1b0b1 /* DTR */
+			MX6UL_PAD_LCD_DATA19__GPIO3_IO24        0x1b0b1 /* RI */
+		>;
+	};
+
+	pinctrl_uart2: uart2-grp {
+		fsl,pins = <
+			MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX	0x1b0b1
+			MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX	0x1b0b1
+			MX6UL_PAD_UART2_CTS_B__UART2_DTE_RTS	0x1b0b1
+			MX6UL_PAD_UART2_RTS_B__UART2_DTE_CTS	0x1b0b1
+		>;
+	};
+	pinctrl_uart5: uart5-grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO04__UART5_DTE_RX	0x1b0b1
+			MX6UL_PAD_GPIO1_IO05__UART5_DTE_TX	0x1b0b1
+		>;
+	};
+
+	pinctrl_usbh_reg: gpio-usbh-reg {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02	0x1b0b1 /* SODIMM 129 USBH PEN */
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1-grp {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK		0x17059
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD		0x10059
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0	0x17059
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1	0x17059
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2	0x17059
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3	0x17059
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1-100mhz-grp {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK		0x170b9
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD		0x100b9
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0	0x170b9
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1	0x170b9
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2	0x170b9
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3	0x170b9
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1-200mhz-grp {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK		0x170f9
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD		0x100f9
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0	0x170b9
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1	0x170b9
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2	0x170b9
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3	0x170b9
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2-grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_DATA00__USDHC2_DATA0	0x17059
+			MX6UL_PAD_CSI_DATA01__USDHC2_DATA1	0x17059
+			MX6UL_PAD_CSI_DATA02__USDHC2_DATA2	0x17059
+			MX6UL_PAD_CSI_DATA03__USDHC2_DATA3	0x17059
+			MX6UL_PAD_CSI_HSYNC__USDHC2_CMD		0x17059
+			MX6UL_PAD_CSI_VSYNC__USDHC2_CLK		0x17059
+
+			MX6UL_PAD_GPIO1_IO03__OSC32K_32K_OUT	0x14
+		>;
+	};
+};
+
+&iomuxc_snvs {
+	pinctrl_snvs_gpio1: snvs-gpio1-grp {
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06	0x14 /* SODIMM 93 */
+			MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03	0x14 /* SODIMM 95 */
+			MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10	0x74 /* SODIMM 105 */
+			MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05	0x14 /* SODIMM 131 USBH OC */
+			MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08	0x74 /* SODIMM 138 */
+		>;
+	};
+
+	pinctrl_snvs_gpio2: snvs-gpio2-grp { /* ATMEL MXT TOUCH */
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04	0x74 /* SODIMM 107 */
+		>;
+	};
+
+	pinctrl_snvs_gpio3: snvs-gpio3-grp { /* Wifi pins */
+		fsl,pins = <
+			MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11	0x14 /* SODIMM 127 */
+		>;
+	};
+
+	pinctrl_snvs_ad7879_int: snvs-ad7879-int-grp { /* TOUCH Interrupt */
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07	0x1b0b0
+		>;
+	};
+
+	pinctrl_snvs_reg_sd: snvs-reg-sd-grp {
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09	0x4001b8b0
+		>;
+	};
+
+	pinctrl_snvs_usbc_det: snvs-usbc-det-grp {
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02	0x1b0b0
+		>;
+	};
+
+	pinctrl_snvs_gpiokeys: snvs-gpiokeys-grp {
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01	0x130b0
+		>;
+	};
+
+	pinctrl_snvs_usdhc1_cd: snvs-usdhc1-cd-grp {
+		fsl,pins = <
+			MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00	0x1b0b0 /* CD */
+		>;
+	};
+
+	pinctrl_snvs_wifi_pdn: snvs-wifi-pdn-grp {
+		fsl,pins = <
+			MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11	0x14
+		>;
+	};
+};
diff --git a/arch/arm/boot/dts/imx6ull-pinfunc-snvs.h b/arch/arm/boot/dts/imx6ull-pinfunc-snvs.h
new file mode 100644
index 000000000000..f6fb6783c193
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ull-pinfunc-snvs.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ */
+
+#ifndef __DTS_IMX6ULL_PINFUNC_SNVS_H
+#define __DTS_IMX6ULL_PINFUNC_SNVS_H
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+#define MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10                          0x0000 0x0044 0x0000 0x5 0x0
+#define MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11                          0x0004 0x0048 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER0__GPIO5_IO00                        0x0008 0x004C 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01                        0x000C 0x0050 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02                        0x0010 0x0054 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03                        0x0014 0x0058 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04                        0x0018 0x005C 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05                        0x001C 0x0060 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06                        0x0020 0x0064 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07                        0x0024 0x0068 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08                        0x0028 0x006C 0x0000 0x5 0x0
+#define MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09                        0x002C 0x0070 0x0000 0x5 0x0
+
+#endif /* __DTS_IMX6ULL_PINFUNC_SNVS_H */
diff --git a/arch/arm/boot/dts/imx6ull.dtsi b/arch/arm/boot/dts/imx6ull.dtsi
index 0c182917b863..571ddd71cdba 100644
--- a/arch/arm/boot/dts/imx6ull.dtsi
+++ b/arch/arm/boot/dts/imx6ull.dtsi
@@ -41,3 +41,35 @@
 
 #include "imx6ul.dtsi"
 #include "imx6ull-pinfunc.h"
+#include "imx6ull-pinfunc-snvs.h"
+
+/* Delete UART8 in AIPS-1 (i.MX6UL specific) */
+/delete-node/ &uart8;
+
+/ {
+	soc {
+		aips3: aips-bus@2200000 {
+			compatible = "fsl,aips-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x02200000 0x100000>;
+			ranges;
+
+			iomuxc_snvs: iomuxc-snvs@2290000 {
+				compatible = "fsl,imx6ull-iomuxc-snvs";
+				reg = <0x02290000 0x4000>;
+			};
+
+			uart8: serial@2288000 {
+				compatible = "fsl,imx6ul-uart",
+					     "fsl,imx6q-uart";
+				reg = <0x02288000 0x4000>;
+				interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6UL_CLK_UART8_IPG>,
+					 <&clks IMX6UL_CLK_UART8_SERIAL>;
+				clock-names = "ipg", "per";
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
index ae45af1ad062..7f645683f53b 100644
--- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
+++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
@@ -18,7 +18,7 @@
 	model = "CompuLab CL-SOM-iMX7";
 	compatible = "compulab,cl-som-imx7", "fsl,imx7d";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x10000000>; /* 256 MB - minimal configuration */
 	};
 
@@ -213,37 +213,37 @@
 &iomuxc {
 	pinctrl_enet1: enet1grp {
 		fsl,pins = <
-			MX7D_PAD_SD2_CD_B__ENET1_MDIO			0x3
-			MX7D_PAD_SD2_WP__ENET1_MDC			0x3
-			MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC	0x1
-			MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0	0x1
-			MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1	0x1
-			MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2	0x1
-			MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3	0x1
-			MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL	0x1
-			MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC	0x1
-			MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0	0x1
-			MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1	0x1
-			MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2	0x1
-			MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3	0x1
-			MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL	0x1
+			MX7D_PAD_SD2_CD_B__ENET1_MDIO			0x30
+			MX7D_PAD_SD2_WP__ENET1_MDC			0x30
+			MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC	0x11
+			MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0	0x11
+			MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1	0x11
+			MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2	0x11
+			MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3	0x11
+			MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL	0x11
+			MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC	0x11
+			MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0	0x11
+			MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1	0x11
+			MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2	0x11
+			MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3	0x11
+			MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL	0x11
 		>;
 	};
 
 	pinctrl_enet2: enet2grp {
 		fsl,pins = <
-			MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC		0x1
-			MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0		0x1
-			MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1		0x1
-			MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2		0x1
-			MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3		0x1
-			MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL		0x1
-			MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC		0x1
-			MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0		0x1
-			MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1		0x1
-			MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2		0x1
-			MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3		0x1
-			MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL		0x1
+			MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC		0x11
+			MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0		0x11
+			MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1		0x11
+			MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2		0x11
+			MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3		0x11
+			MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL		0x11
+			MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC		0x11
+			MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0		0x11
+			MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1		0x11
+			MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2		0x11
+			MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3		0x11
+			MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL		0x11
 		>;
 	};
 
diff --git a/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi b/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi
index 9b63b9c89e4b..04d24ee17b14 100644
--- a/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi
+++ b/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi
@@ -7,7 +7,7 @@
 #include "imx7-colibri.dtsi"
 
 / {
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx7d-colibri.dtsi b/arch/arm/boot/dts/imx7d-colibri.dtsi
index 6f2bb70c1fbd..d9f8fb69511b 100644
--- a/arch/arm/boot/dts/imx7d-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7d-colibri.dtsi
@@ -44,7 +44,7 @@
 #include "imx7-colibri.dtsi"
 
 / {
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x20000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx7d-nitrogen7.dts b/arch/arm/boot/dts/imx7d-nitrogen7.dts
index 2b05898bb3f6..52167298984d 100644
--- a/arch/arm/boot/dts/imx7d-nitrogen7.dts
+++ b/arch/arm/boot/dts/imx7d-nitrogen7.dts
@@ -53,7 +53,7 @@
 		t_lcd = &t_lcd;
 	};
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x40000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx7d-pico.dtsi b/arch/arm/boot/dts/imx7d-pico.dtsi
index e307462a48ec..21973eb55671 100644
--- a/arch/arm/boot/dts/imx7d-pico.dtsi
+++ b/arch/arm/boot/dts/imx7d-pico.dtsi
@@ -48,7 +48,7 @@
 	model = "Technexion Pico i.MX7D Board";
 	compatible = "technexion,imx7d-pico", "fsl,imx7d";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x80000000>;
 	};
 
diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
index a7a5dc7b2700..7f241afc15ea 100644
--- a/arch/arm/boot/dts/imx7d-sdb.dts
+++ b/arch/arm/boot/dts/imx7d-sdb.dts
@@ -48,7 +48,7 @@
 	model = "Freescale i.MX7 SabreSD Board";
 	compatible = "fsl,imx7d-sdb", "fsl,imx7d";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x80000000>;
 	};
 
@@ -336,6 +336,11 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_i2c2>;
 	status = "okay";
+
+	mpl3115@60 {
+		compatible = "fsl,mpl3115";
+		reg = <0x60>;
+	};
 };
 
 &i2c3 {
diff --git a/arch/arm/boot/dts/imx7s-colibri.dtsi b/arch/arm/boot/dts/imx7s-colibri.dtsi
index b81013455b21..fe8344cee864 100644
--- a/arch/arm/boot/dts/imx7s-colibri.dtsi
+++ b/arch/arm/boot/dts/imx7s-colibri.dtsi
@@ -44,7 +44,7 @@
 #include "imx7-colibri.dtsi"
 
 / {
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x10000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-warp.dts
index 9bdf121f7e43..8a30b148534d 100644
--- a/arch/arm/boot/dts/imx7s-warp.dts
+++ b/arch/arm/boot/dts/imx7s-warp.dts
@@ -50,7 +50,7 @@
 	model = "Warp i.MX7 Board";
 	compatible = "warp,imx7s-warp", "fsl,imx7s";
 
-	memory {
+	memory@80000000 {
 		reg = <0x80000000 0x20000000>;
 	};
 
@@ -271,6 +271,15 @@
 	status = "okay";
 };
 
+&uart6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart6>;
+	assigned-clocks = <&clks IMX7D_UART6_ROOT_SRC>;
+	assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+	fsl,dte-mode;
+	status = "okay";
+};
+
 &usbotg1 {
 	dr_mode = "peripheral";
 	status = "okay";
@@ -379,6 +388,13 @@
 		>;
 	};
 
+	pinctrl_uart6: uart6grp {
+		fsl,pins = <
+			MX7D_PAD_ECSPI1_MOSI__UART6_DTE_RX	0x79
+			MX7D_PAD_ECSPI1_SCLK__UART6_DTE_TX	0x79
+		>;
+	};
+
 	pinctrl_usdhc1: usdhc1grp {
 		fsl,pins = <
 			MX7D_PAD_SD1_CMD__SD1_CMD	0x59
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 9aa2bb998552..ec6292c5b2e4 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -58,7 +58,7 @@
 	 * Also for U-Boot there must be a pre-existing /memory node.
 	 */
 	chosen {};
-	memory { device_type = "memory"; reg = <0 0>; };
+	memory { device_type = "memory"; };
 
 	aliases {
 		gpio0 = &gpio1;
diff --git a/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts b/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts
index 5ce220ac9611..5aa4669ae254 100644
--- a/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts
+++ b/arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts
@@ -35,7 +35,7 @@
 		pinctrl-names = "default";
 
 		eject {
-			debounce_interval = <50>;
+			debounce-interval = <50>;
 			wakeup-source;
 			linux,code = <KEY_EJECTCD>;
 			label = "Eject Button";
diff --git a/arch/arm/boot/dts/logicpd-som-lv.dtsi b/arch/arm/boot/dts/logicpd-som-lv.dtsi
index c1aa7a4518fb..a30ee9fcb3ae 100644
--- a/arch/arm/boot/dts/logicpd-som-lv.dtsi
+++ b/arch/arm/boot/dts/logicpd-som-lv.dtsi
@@ -71,6 +71,8 @@
 };
 
 &i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
 	clock-frequency = <2600000>;
 
 	twl: twl@48 {
@@ -189,7 +191,12 @@
 		>;
 	};
 
-
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0)        /* i2c1_scl.i2c1_scl */
+			OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0)        /* i2c1_sda.i2c1_sda */
+		>;
+	};
 };
 
 &omap3_pmx_wkup {
diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
index b50b796e15c7..47915447a826 100644
--- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
+++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
@@ -66,6 +66,8 @@
 };
 
 &i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
 	clock-frequency = <2600000>;
 
 	twl: twl@48 {
@@ -136,6 +138,12 @@
 			OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT | MUX_MODE0)	/* hsusb0_data7.hsusb0_data7 */
 		>;
 	};
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0)        /* i2c1_scl.i2c1_scl */
+			OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0)        /* i2c1_sda.i2c1_sda */
+		>;
+	};
 };
 
 &uart2 {
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index c31dad98f989..fbd2897566c3 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -788,5 +788,21 @@
 			clock-names = "ipg", "per";
 			big-endian;
 		};
+
+		ocram1: sram@10000000 {
+			compatible = "mmio-sram";
+			reg = <0x0 0x10000000 0x0 0x10000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x0 0x10000000 0x10000>;
+		};
+
+		ocram2: sram@10010000 {
+			compatible = "mmio-sram";
+			reg = <0x0 0x10010000 0x0 0x10000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x0 0x10010000 0x10000>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index d2e3eeaa1a5f..dcc9292d2ffa 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -46,6 +46,7 @@
 #include <dt-bindings/clock/meson8b-clkc.h>
 #include <dt-bindings/gpio/meson8-gpio.h>
 #include <dt-bindings/reset/amlogic,meson8b-clkc-reset.h>
+#include <dt-bindings/reset/amlogic,meson8b-reset.h>
 #include "meson.dtsi"
 
 / {
@@ -187,6 +188,12 @@
 		reg = <0x8000 0x4>, <0x4000 0x460>;
 	};
 
+	reset: reset-controller@4404 {
+		compatible = "amlogic,meson8b-reset";
+		reg = <0x4404 0x9c>;
+		#reset-cells = <1>;
+	};
+
 	analog_top: analog-top@81a8 {
 		compatible = "amlogic,meson8-analog-top", "syscon";
 		reg = <0x81a8 0x14>;
@@ -383,10 +390,12 @@
 	compatible = "amlogic,meson8-usb2-phy", "amlogic,meson-mx-usb2-phy";
 	clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
 	clock-names = "usb_general", "usb";
+	resets = <&reset RESET_USB_OTG>;
 };
 
 &usb1_phy {
 	compatible = "amlogic,meson8-usb2-phy", "amlogic,meson-mx-usb2-phy";
 	clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1>;
 	clock-names = "usb_general", "usb";
+	resets = <&reset RESET_USB_OTG>;
 };
diff --git a/arch/arm/boot/dts/meson8b-odroidc1.dts b/arch/arm/boot/dts/meson8b-odroidc1.dts
index 9ff6ca4e20d0..d5e83051bb54 100644
--- a/arch/arm/boot/dts/meson8b-odroidc1.dts
+++ b/arch/arm/boot/dts/meson8b-odroidc1.dts
@@ -99,3 +99,33 @@
 &usb1 {
 	status = "okay";
 };
+
+&ethmac {
+	status = "okay";
+
+	snps,reset-gpio = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 30000>;
+
+	pinctrl-0 = <&eth_rgmii_pins>;
+	pinctrl-names = "default";
+
+	phy-mode = "rgmii";
+	phy-handle = <&eth_phy>;
+	amlogic,tx-delay-ns = <4>;
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		/* Realtek RTL8211F (0x001cc916) */
+		eth_phy: ethernet-phy@0 {
+			reg = <0>;
+			eee-broken-1000t;
+			interrupt-parent = <&gpio_intc>;
+			/* GPIOH_3 */
+			interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 7cd03ed3742e..1a7c16640ea5 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -152,7 +152,7 @@
 
 	reset: reset-controller@4404 {
 		compatible = "amlogic,meson8b-reset";
-		reg = <0x4404 0x20>;
+		reg = <0x4404 0x9c>;
 		#reset-cells = <1>;
 	};
 
@@ -185,6 +185,27 @@
 			#gpio-cells = <2>;
 			gpio-ranges = <&pinctrl_cbus 0 0 130>;
 		};
+
+		eth_rgmii_pins: eth-rgmii {
+			mux {
+				groups = "eth_tx_clk",
+					 "eth_tx_en",
+					 "eth_txd1_0",
+					 "eth_txd1_1",
+					 "eth_txd0_0",
+					 "eth_txd0_1",
+					 "eth_rx_clk",
+					 "eth_rx_dv",
+					 "eth_rxd1",
+					 "eth_rxd0",
+					 "eth_mdio_en",
+					 "eth_mdc",
+					 "eth_ref_clk",
+					 "eth_txd2",
+					 "eth_txd3";
+				function = "ethernet";
+			};
+		};
 	};
 };
 
@@ -203,8 +224,18 @@
 };
 
 &ethmac {
-	clocks = <&clkc CLKID_ETH>;
-	clock-names = "stmmaceth";
+	compatible = "amlogic,meson8b-dwmac", "snps,dwmac-3.70a", "snps,dwmac";
+
+	reg = <0xc9410000 0x10000
+	       0xc1108140 0x4>;
+
+	clocks = <&clkc CLKID_ETH>,
+		 <&clkc CLKID_MPLL2>,
+		 <&clkc CLKID_MPLL2>;
+	clock-names = "stmmaceth", "clkin0", "clkin1";
+
+	resets = <&reset RESET_ETHERNET>;
+	reset-names = "stmmaceth";
 };
 
 &gpio_intc {
diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts
index e44d93fc644c..ded5fcf084eb 100644
--- a/arch/arm/boot/dts/omap3-n9.dts
+++ b/arch/arm/boot/dts/omap3-n9.dts
@@ -39,6 +39,13 @@
 	};
 };
 
+&i2c3 {
+	ak8975@0f {
+		compatible = "asahi-kasei,ak8975";
+		reg = <0x0f>;
+	};
+};
+
 &isp {
 	vdd-csiphy1-supply = <&vaux2>;
 	vdd-csiphy2-supply = <&vaux2>;
diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts
index b21084da490b..65c2cc6a9a30 100644
--- a/arch/arm/boot/dts/omap4-droid4-xt894.dts
+++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts
@@ -124,13 +124,6 @@
 };
 
 &gpio6 {
-	touchscreen_reset {
-		gpio-hog;
-		gpios = <13 0>;
-		output-high;
-		line-name = "touchscreen-reset";
-	};
-
 	pwm8: dmtimer-pwm-8 {
 		pinctrl-names = "default";
 		pinctrl-0 = <&vibrator_direction_pin>;
@@ -362,22 +355,18 @@
 	};
 };
 
-/*
- * REVISIT: Add gpio173 reset pin handling to the driver, see gpio-hog above.
- * If the GPIO reset is used, we probably need to have /lib/firmware/maxtouch.fw
- * available. See "mxt-app" and "droid4-touchscreen-firmware" tools for more
- * information.
- */
 &i2c2 {
-	tsp@4a {
+	touchscreen@4a {
 		compatible = "atmel,maxtouch";
 		reg = <0x4a>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&touchscreen_pins>;
 
+		reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */
+
 		/* gpio_183 with sys_nirq2 pad as wakeup */
-		interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING
-				       &omap4_pmx_core 0x160>;
+		interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING>,
+				      <&omap4_pmx_core 0x160>;
 		interrupt-names = "irq", "wakeup";
 		wakeup-source;
 	};
@@ -435,6 +424,7 @@
 
 	touchscreen_pins: pinmux_touchscreen_pins {
 		pinctrl-single,pins = <
+		OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3)
 		OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3)
 		>;
 	};
diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi
index 03c8ad91ddac..cbcdcb4e7d1c 100644
--- a/arch/arm/boot/dts/omap443x.dtsi
+++ b/arch/arm/boot/dts/omap443x.dtsi
@@ -24,8 +24,6 @@
 			clock-latency = <300000>; /* From legacy driver */
 
 			/* cooling options */
-			cooling-min-level = <0>;
-			cooling-max-level = <3>;
 			#cooling-cells = <2>; /* min followed by max */
 		};
 	};
diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi
index c43f2a2d0a1e..ad97493e4e46 100644
--- a/arch/arm/boot/dts/omap4460.dtsi
+++ b/arch/arm/boot/dts/omap4460.dtsi
@@ -22,8 +22,6 @@
 			clock-latency = <300000>; /* From legacy driver */
 
 			/* cooling options */
-			cooling-min-level = <0>;
-			cooling-max-level = <2>;
 			#cooling-cells = <2>; /* min followed by max */
 		};
 	};
diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts
index ec2c8baef62a..592e17fd4eeb 100644
--- a/arch/arm/boot/dts/omap5-uevm.dts
+++ b/arch/arm/boot/dts/omap5-uevm.dts
@@ -47,7 +47,7 @@
 			gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;	/* gpio3_83 */
 			wakeup-source;
 			autorepeat;
-			debounce_interval = <50>;
+			debounce-interval = <50>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 35d4298da83d..511606c17a04 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -55,8 +55,6 @@
 			clock-latency = <300000>; /* From omap-cpufreq driver */
 
 			/* cooling options */
-			cooling-min-level = <0>;
-			cooling-max-level = <2>;
 			#cooling-cells = <2>; /* min followed by max */
 		};
 		cpu@1 {
diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
index ab9645a42eca..ecf9516bcda8 100644
--- a/arch/arm/boot/dts/r7s72100.dtsi
+++ b/arch/arm/boot/dts/r7s72100.dtsi
@@ -15,7 +15,6 @@
 
 / {
 	compatible = "renesas,r7s72100";
-	interrupt-parent = <&gic>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 
@@ -31,61 +30,356 @@
 		spi4 = &spi4;
 	};
 
-	clocks {
-		ranges;
+	/* Fixed factor clocks */
+	b_clk: b {
+		#clock-cells = <0>;
+		compatible = "fixed-factor-clock";
+		clocks = <&cpg_clocks R7S72100_CLK_PLL>;
+		clock-mult = <1>;
+		clock-div = <3>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			clock-frequency = <400000000>;
+			clocks = <&cpg_clocks R7S72100_CLK_I>;
+			next-level-cache = <&L2>;
+		};
+	};
+
+	/* External clocks */
+	extal_clk: extal {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		/* If clk present, value must be set by board */
+		clock-frequency = <0>;
+	};
+
+	p0_clk: p0 {
+		#clock-cells = <0>;
+		compatible = "fixed-factor-clock";
+		clocks = <&cpg_clocks R7S72100_CLK_PLL>;
+		clock-mult = <1>;
+		clock-div = <12>;
+	};
+
+	p1_clk: p1 {
+		#clock-cells = <0>;
+		compatible = "fixed-factor-clock";
+		clocks = <&cpg_clocks R7S72100_CLK_PLL>;
+		clock-mult = <1>;
+		clock-div = <6>;
+	};
+
+	rtc_x1_clk: rtc_x1 {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		/* If clk present, value must be set by board to 32678 */
+		clock-frequency = <0>;
+	};
+
+	rtc_x3_clk: rtc_x3 {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		/* If clk present, value must be set by board to 4000000 */
+		clock-frequency = <0>;
+	};
+
+	soc {
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
+
 		#address-cells = <1>;
 		#size-cells = <1>;
+		ranges;
+
+		L2: cache-controller@3ffff000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x3ffff000 0x1000>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			arm,early-bresp-disable;
+			arm,full-line-zero-disable;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		scif0: serial@e8007000 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe8007000 64>;
+			interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF0>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif1: serial@e8007800 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe8007800 64>;
+			interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF1>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif2: serial@e8008000 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe8008000 64>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF2>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif3: serial@e8008800 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe8008800 64>;
+			interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF3>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif4: serial@e8009000 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe8009000 64>;
+			interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF4>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif5: serial@e8009800 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe8009800 64>;
+			interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF5>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif6: serial@e800a000 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe800a000 64>;
+			interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF6>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		scif7: serial@e800a800 {
+			compatible = "renesas,scif-r7s72100", "renesas,scif";
+			reg = <0xe800a800 64>;
+			interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp4_clks R7S72100_CLK_SCIF7>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
+		};
+
+		spi0: spi@e800c800 {
+			compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+			reg = <0xe800c800 0x24>;
+			interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error", "rx", "tx";
+			clocks = <&mstp10_clks R7S72100_CLK_SPI0>;
+			power-domains = <&cpg_clocks>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		spi1: spi@e800d000 {
+			compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+			reg = <0xe800d000 0x24>;
+			interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error", "rx", "tx";
+			clocks = <&mstp10_clks R7S72100_CLK_SPI1>;
+			power-domains = <&cpg_clocks>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		spi2: spi@e800d800 {
+			compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+			reg = <0xe800d800 0x24>;
+			interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error", "rx", "tx";
+			clocks = <&mstp10_clks R7S72100_CLK_SPI2>;
+			power-domains = <&cpg_clocks>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		spi3: spi@e800e000 {
+			compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+			reg = <0xe800e000 0x24>;
+			interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error", "rx", "tx";
+			clocks = <&mstp10_clks R7S72100_CLK_SPI3>;
+			power-domains = <&cpg_clocks>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-		/* External clocks */
-		extal_clk: extal {
-			#clock-cells = <0>;
-			compatible = "fixed-clock";
-			/* If clk present, value must be set by board */
-			clock-frequency = <0>;
+		spi4: spi@e800e800 {
+			compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+			reg = <0xe800e800 0x24>;
+			interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error", "rx", "tx";
+			clocks = <&mstp10_clks R7S72100_CLK_SPI4>;
+			power-domains = <&cpg_clocks>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
 		};
 
-		usb_x1_clk: usb_x1 {
-			#clock-cells = <0>;
-			compatible = "fixed-clock";
-			/* If clk present, value must be set by board */
-			clock-frequency = <0>;
+		usbhs0: usb@e8010000 {
+			compatible = "renesas,usbhs-r7s72100", "renesas,rza1-usbhs";
+			reg = <0xe8010000 0x1a0>;
+			interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp7_clks R7S72100_CLK_USB0>;
+			renesas,buswait = <4>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		rtc_x1_clk: rtc_x1 {
-			#clock-cells = <0>;
-			compatible = "fixed-clock";
-			/* If clk present, value must be set by board to 32678 */
-			clock-frequency = <0>;
+		usbhs1: usb@e8207000 {
+			compatible = "renesas,usbhs-r7s72100", "renesas,rza1-usbhs";
+			reg = <0xe8207000 0x1a0>;
+			interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp7_clks R7S72100_CLK_USB1>;
+			renesas,buswait = <4>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		rtc_x3_clk: rtc_x3 {
-			#clock-cells = <0>;
-			compatible = "fixed-clock";
-			/* If clk present, value must be set by board to 4000000 */
-			clock-frequency = <0>;
+		mmcif: mmc@e804c800 {
+			compatible = "renesas,mmcif-r7s72100", "renesas,sh-mmcif";
+			reg = <0xe804c800 0x80>;
+			interrupts = <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp8_clks R7S72100_CLK_MMCIF>;
+			power-domains = <&cpg_clocks>;
+			reg-io-width = <4>;
+			bus-width = <8>;
+			status = "disabled";
 		};
 
-		/* Fixed factor clocks */
-		b_clk: b {
-			#clock-cells = <0>;
-			compatible = "fixed-factor-clock";
-			clocks = <&cpg_clocks R7S72100_CLK_PLL>;
-			clock-mult = <1>;
-			clock-div = <3>;
+		sdhi0: sd@e804e000 {
+			compatible = "renesas,sdhi-r7s72100";
+			reg = <0xe804e000 0x100>;
+			interrupts = <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+
+			clocks = <&mstp12_clks R7S72100_CLK_SDHI00>,
+				 <&mstp12_clks R7S72100_CLK_SDHI01>;
+			clock-names = "core", "cd";
+			power-domains = <&cpg_clocks>;
+			cap-sd-highspeed;
+			cap-sdio-irq;
+			status = "disabled";
 		};
-		p1_clk: p1 {
-			#clock-cells = <0>;
-			compatible = "fixed-factor-clock";
-			clocks = <&cpg_clocks R7S72100_CLK_PLL>;
-			clock-mult = <1>;
-			clock-div = <6>;
+
+		sdhi1: sd@e804e800 {
+			compatible = "renesas,sdhi-r7s72100";
+			reg = <0xe804e800 0x100>;
+			interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>;
+
+			clocks = <&mstp12_clks R7S72100_CLK_SDHI10>,
+				 <&mstp12_clks R7S72100_CLK_SDHI11>;
+			clock-names = "core", "cd";
+			power-domains = <&cpg_clocks>;
+			cap-sd-highspeed;
+			cap-sdio-irq;
+			status = "disabled";
+		};
+
+		gic: interrupt-controller@e8201000 {
+			compatible = "arm,pl390";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0xe8201000 0x1000>,
+				<0xe8202000 0x1000>;
+		};
+
+		ether: ethernet@e8203000 {
+			compatible = "renesas,ether-r7s72100";
+			reg = <0xe8203000 0x800>,
+			      <0xe8204800 0x200>;
+			interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp7_clks R7S72100_CLK_ETHER>;
+			power-domains = <&cpg_clocks>;
+			phy-mode = "mii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
 		};
-		p0_clk: p0 {
-			#clock-cells = <0>;
-			compatible = "fixed-factor-clock";
-			clocks = <&cpg_clocks R7S72100_CLK_PLL>;
-			clock-mult = <1>;
-			clock-div = <12>;
+
+		wdt: watchdog@fcfe0000 {
+			compatible = "renesas,r7s72100-wdt", "renesas,rza-wdt";
+			reg = <0xfcfe0000 0x6>;
+			interrupts = <GIC_SPI 106 IRQ_TYPE_EDGE_RISING>;
+			clocks = <&p0_clk>;
 		};
 
 		/* Special CPG clocks */
@@ -192,479 +486,209 @@
 			>;
 			clock-output-names = "sdhi00", "sdhi01", "sdhi10", "sdhi11";
 		};
-	};
-
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cpu@0 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a9";
-			reg = <0>;
-			clock-frequency = <400000000>;
-			clocks = <&cpg_clocks R7S72100_CLK_I>;
-			next-level-cache = <&L2>;
-		};
-	};
-
-	pinctrl: pin-controller@fcfe3000 {
-		compatible = "renesas,r7s72100-ports";
 
-		reg = <0xfcfe3000 0x4230>;
-
-		port0: gpio-0 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 0 6>;
+		pinctrl: pin-controller@fcfe3000 {
+			compatible = "renesas,r7s72100-ports";
+
+			reg = <0xfcfe3000 0x4230>;
+
+			port0: gpio-0 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 0 6>;
+			};
+
+			port1: gpio-1 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 16 16>;
+			};
+
+			port2: gpio-2 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 32 16>;
+			};
+
+			port3: gpio-3 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 48 16>;
+			};
+
+			port4: gpio-4 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 64 16>;
+			};
+
+			port5: gpio-5 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 80 11>;
+			};
+
+			port6: gpio-6 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 96 16>;
+			};
+
+			port7: gpio-7 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 112 16>;
+			};
+
+			port8: gpio-8 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 128 16>;
+			};
+
+			port9: gpio-9 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 144 8>;
+			};
+
+			port10: gpio-10 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 160 16>;
+			};
+
+			port11: gpio-11 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				gpio-ranges = <&pinctrl 0 176 16>;
+			};
 		};
 
-		port1: gpio-1 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 16 16>;
+		ostm0: timer@fcfec000 {
+			compatible = "renesas,r7s72100-ostm", "renesas,ostm";
+			reg = <0xfcfec000 0x30>;
+			interrupts = <GIC_SPI 102 IRQ_TYPE_EDGE_RISING>;
+			clocks = <&mstp5_clks R7S72100_CLK_OSTM0>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port2: gpio-2 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 32 16>;
+		ostm1: timer@fcfec400 {
+			compatible = "renesas,r7s72100-ostm", "renesas,ostm";
+			reg = <0xfcfec400 0x30>;
+			interrupts = <GIC_SPI 103 IRQ_TYPE_EDGE_RISING>;
+			clocks = <&mstp5_clks R7S72100_CLK_OSTM1>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port3: gpio-3 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 48 16>;
+		i2c0: i2c@fcfee000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+			reg = <0xfcfee000 0x44>;
+			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 158 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 159 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp9_clks R7S72100_CLK_I2C0>;
+			clock-frequency = <100000>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port4: gpio-4 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 64 16>;
+		i2c1: i2c@fcfee400 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+			reg = <0xfcfee400 0x44>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 167 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp9_clks R7S72100_CLK_I2C1>;
+			clock-frequency = <100000>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port5: gpio-5 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 80 11>;
+		i2c2: i2c@fcfee800 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+			reg = <0xfcfee800 0x44>;
+			interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp9_clks R7S72100_CLK_I2C2>;
+			clock-frequency = <100000>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port6: gpio-6 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 96 16>;
+		i2c3: i2c@fcfeec00 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+			reg = <0xfcfeec00 0x44>;
+			interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
+				     <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp9_clks R7S72100_CLK_I2C3>;
+			clock-frequency = <100000>;
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port7: gpio-7 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 112 16>;
+		mtu2: timer@fcff0000 {
+			compatible = "renesas,mtu2-r7s72100", "renesas,mtu2";
+			reg = <0xfcff0000 0x400>;
+			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "tgi0a";
+			clocks = <&mstp3_clks R7S72100_CLK_MTU2>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
 
-		port8: gpio-8 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 128 16>;
+		rtc: rtc@fcff1000 {
+			compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc";
+			reg = <0xfcff1000 0x2e>;
+			interrupts = <GIC_SPI 276 IRQ_TYPE_EDGE_RISING
+				      GIC_SPI 277 IRQ_TYPE_EDGE_RISING
+				      GIC_SPI 278 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "alarm", "period", "carry";
+			clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>,
+				 <&rtc_x3_clk>, <&extal_clk>;
+			clock-names = "fck", "rtc_x1", "rtc_x3", "extal";
+			power-domains = <&cpg_clocks>;
+			status = "disabled";
 		};
-
-		port9: gpio-9 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 144 8>;
-		};
-
-		port10: gpio-10 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 160 16>;
-		};
-
-		port11: gpio-11 {
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl 0 176 16>;
-		};
-	};
-
-	scif0: serial@e8007000 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe8007000 64>;
-		interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF0>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif1: serial@e8007800 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe8007800 64>;
-		interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF1>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif2: serial@e8008000 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe8008000 64>;
-		interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF2>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif3: serial@e8008800 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe8008800 64>;
-		interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF3>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif4: serial@e8009000 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe8009000 64>;
-		interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF4>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif5: serial@e8009800 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe8009800 64>;
-		interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF5>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif6: serial@e800a000 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe800a000 64>;
-		interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF6>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	scif7: serial@e800a800 {
-		compatible = "renesas,scif-r7s72100", "renesas,scif";
-		reg = <0xe800a800 64>;
-		interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp4_clks R7S72100_CLK_SCIF7>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	spi0: spi@e800c800 {
-		compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
-		reg = <0xe800c800 0x24>;
-		interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error", "rx", "tx";
-		clocks = <&mstp10_clks R7S72100_CLK_SPI0>;
-		power-domains = <&cpg_clocks>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	spi1: spi@e800d000 {
-		compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
-		reg = <0xe800d000 0x24>;
-		interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error", "rx", "tx";
-		clocks = <&mstp10_clks R7S72100_CLK_SPI1>;
-		power-domains = <&cpg_clocks>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	spi2: spi@e800d800 {
-		compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
-		reg = <0xe800d800 0x24>;
-		interrupts = <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error", "rx", "tx";
-		clocks = <&mstp10_clks R7S72100_CLK_SPI2>;
-		power-domains = <&cpg_clocks>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	spi3: spi@e800e000 {
-		compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
-		reg = <0xe800e000 0x24>;
-		interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error", "rx", "tx";
-		clocks = <&mstp10_clks R7S72100_CLK_SPI3>;
-		power-domains = <&cpg_clocks>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	spi4: spi@e800e800 {
-		compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
-		reg = <0xe800e800 0x24>;
-		interrupts = <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error", "rx", "tx";
-		clocks = <&mstp10_clks R7S72100_CLK_SPI4>;
-		power-domains = <&cpg_clocks>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	gic: interrupt-controller@e8201000 {
-		compatible = "arm,pl390";
-		#interrupt-cells = <3>;
-		#address-cells = <0>;
-		interrupt-controller;
-		reg = <0xe8201000 0x1000>,
-			<0xe8202000 0x1000>;
-	};
-
-	L2: cache-controller@3ffff000 {
-		compatible = "arm,pl310-cache";
-		reg = <0x3ffff000 0x1000>;
-		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-		arm,early-bresp-disable;
-		arm,full-line-zero-disable;
-		cache-unified;
-		cache-level = <2>;
-	};
-
-	wdt: watchdog@fcfe0000 {
-		compatible = "renesas,r7s72100-wdt", "renesas,rza-wdt";
-		reg = <0xfcfe0000 0x6>;
-		interrupts = <GIC_SPI 106 IRQ_TYPE_EDGE_RISING>;
-		clocks = <&p0_clk>;
-	};
-
-	i2c0: i2c@fcfee000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
-		reg = <0xfcfee000 0x44>;
-		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 158 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 159 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp9_clks R7S72100_CLK_I2C0>;
-		clock-frequency = <100000>;
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	i2c1: i2c@fcfee400 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
-		reg = <0xfcfee400 0x44>;
-		interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 167 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp9_clks R7S72100_CLK_I2C1>;
-		clock-frequency = <100000>;
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	i2c2: i2c@fcfee800 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
-		reg = <0xfcfee800 0x44>;
-		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp9_clks R7S72100_CLK_I2C2>;
-		clock-frequency = <100000>;
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	i2c3: i2c@fcfeec00 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
-		reg = <0xfcfeec00 0x44>;
-		interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>,
-			     <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp9_clks R7S72100_CLK_I2C3>;
-		clock-frequency = <100000>;
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	mtu2: timer@fcff0000 {
-		compatible = "renesas,mtu2-r7s72100", "renesas,mtu2";
-		reg = <0xfcff0000 0x400>;
-		interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "tgi0a";
-		clocks = <&mstp3_clks R7S72100_CLK_MTU2>;
-		clock-names = "fck";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	ether: ethernet@e8203000 {
-		compatible = "renesas,ether-r7s72100";
-		reg = <0xe8203000 0x800>,
-		      <0xe8204800 0x200>;
-		interrupts = <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp7_clks R7S72100_CLK_ETHER>;
-		power-domains = <&cpg_clocks>;
-		phy-mode = "mii";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
-
-	mmcif: mmc@e804c800 {
-		compatible = "renesas,mmcif-r7s72100", "renesas,sh-mmcif";
-		reg = <0xe804c800 0x80>;
-		interrupts = <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&mstp8_clks R7S72100_CLK_MMCIF>;
-		power-domains = <&cpg_clocks>;
-		reg-io-width = <4>;
-		bus-width = <8>;
-		status = "disabled";
-	};
-
-	sdhi0: sd@e804e000 {
-		compatible = "renesas,sdhi-r7s72100";
-		reg = <0xe804e000 0x100>;
-		interrupts = <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
-
-		clocks = <&mstp12_clks R7S72100_CLK_SDHI00>,
-			 <&mstp12_clks R7S72100_CLK_SDHI01>;
-		clock-names = "core", "cd";
-		power-domains = <&cpg_clocks>;
-		cap-sd-highspeed;
-		cap-sdio-irq;
-		status = "disabled";
-	};
-
-	sdhi1: sd@e804e800 {
-		compatible = "renesas,sdhi-r7s72100";
-		reg = <0xe804e800 0x100>;
-		interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>;
-
-		clocks = <&mstp12_clks R7S72100_CLK_SDHI10>,
-			 <&mstp12_clks R7S72100_CLK_SDHI11>;
-		clock-names = "core", "cd";
-		power-domains = <&cpg_clocks>;
-		cap-sd-highspeed;
-		cap-sdio-irq;
-		status = "disabled";
-	};
-
-	ostm0: timer@fcfec000 {
-		compatible = "renesas,r7s72100-ostm", "renesas,ostm";
-		reg = <0xfcfec000 0x30>;
-		interrupts = <GIC_SPI 102 IRQ_TYPE_EDGE_RISING>;
-		clocks = <&mstp5_clks R7S72100_CLK_OSTM0>;
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
-	};
-
-	ostm1: timer@fcfec400 {
-		compatible = "renesas,r7s72100-ostm", "renesas,ostm";
-		reg = <0xfcfec400 0x30>;
-		interrupts = <GIC_SPI 103 IRQ_TYPE_EDGE_RISING>;
-		clocks = <&mstp5_clks R7S72100_CLK_OSTM1>;
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
 	};
 
-	rtc: rtc@fcff1000 {
-		compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc";
-		reg = <0xfcff1000 0x2e>;
-		interrupts = <GIC_SPI 276 IRQ_TYPE_EDGE_RISING
-			      GIC_SPI 277 IRQ_TYPE_EDGE_RISING
-			      GIC_SPI 278 IRQ_TYPE_EDGE_RISING>;
-		interrupt-names = "alarm", "period", "carry";
-		clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>,
-			 <&rtc_x3_clk>, <&extal_clk>;
-		clock-names = "fck", "rtc_x1", "rtc_x3", "extal";
-		power-domains = <&cpg_clocks>;
-		status = "disabled";
+	usb_x1_clk: usb_x1 {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		/* If clk present, value must be set by board */
+		clock-frequency = <0>;
 	};
 };
diff --git a/arch/arm/boot/dts/r8a7743-iwg20m.dtsi b/arch/arm/boot/dts/r8a7743-iwg20m.dtsi
index 75a8ca571846..d364685d9184 100644
--- a/arch/arm/boot/dts/r8a7743-iwg20m.dtsi
+++ b/arch/arm/boot/dts/r8a7743-iwg20m.dtsi
@@ -34,6 +34,10 @@
 	};
 };
 
+&cmt0 {
+	status = "okay";
+};
+
 &extal_clk {
 	clock-frequency = <20000000>;
 };
@@ -87,6 +91,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &sdhi0 {
 	pinctrl-0 = <&sdhi0_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7743.dtsi b/arch/arm/boot/dts/r8a7743.dtsi
index 0b74c6c7d21d..69d8f7e0f053 100644
--- a/arch/arm/boot/dts/r8a7743.dtsi
+++ b/arch/arm/boot/dts/r8a7743.dtsi
@@ -141,29 +141,6 @@
 		#size-cells = <2>;
 		ranges;
 
-		apmu@e6152000 {
-			compatible = "renesas,r8a7743-apmu", "renesas,apmu";
-			reg = <0 0xe6152000 0 0x188>;
-			cpus = <&cpu0 &cpu1>;
-		};
-
-		gic: interrupt-controller@f1001000 {
-			compatible = "arm,gic-400";
-			#interrupt-cells = <3>;
-			#address-cells = <0>;
-			interrupt-controller;
-			reg = <0 0xf1001000 0 0x1000>,
-			      <0 0xf1002000 0 0x2000>,
-			      <0 0xf1004000 0 0x2000>,
-			      <0 0xf1006000 0 0x2000>;
-			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
-						 IRQ_TYPE_LEVEL_HIGH)>;
-			clocks = <&cpg CPG_MOD 408>;
-			clock-names = "clk";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 408>;
-		};
-
 		gpio0: gpio@e6050000 {
 			compatible = "renesas,gpio-r8a7743",
 				     "renesas,rcar-gen2-gpio";
@@ -284,6 +261,58 @@
 			resets = <&cpg 904>;
 		};
 
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7743";
+			reg = <0 0xe6060000 0 0x250>;
+		};
+
+		tpu: pwm@e60f0000 {
+			compatible = "renesas,tpu-r8a7743", "renesas,tpu";
+			reg = <0 0xe60f0000 0 0x148>;
+			clocks = <&cpg CPG_MOD 304>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 304>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a7743-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>, <&usb_extal_clk>;
+			clock-names = "extal", "usb_extal";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
+
+		apmu@e6152000 {
+			compatible = "renesas,r8a7743-apmu", "renesas,apmu";
+			reg = <0 0xe6152000 0 0x188>;
+			cpus = <&cpu0 &cpu1>;
+		};
+
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a7743-rst";
+			reg = <0 0xe6160000 0 0x100>;
+		};
+
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7743-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 402>;
+			status = "disabled";
+		};
+
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a7743-sysc";
+			reg = <0 0xe6180000 0 0x200>;
+			#power-domain-cells = <1>;
+		};
+
 		irqc: interrupt-controller@e61c0000 {
 			compatible = "renesas,irqc-r8a7743", "renesas,irqc";
 			#interrupt-cells = <2>;
@@ -316,268 +345,130 @@
 			#thermal-sensor-cells = <0>;
 		};
 
-		cmt0: timer@ffca0000 {
-			compatible = "renesas,r8a7743-cmt0",
-				     "renesas,rcar-gen2-cmt0";
-			reg = <0 0xffca0000 0 0x1004>;
-			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 124>;
-			clock-names = "fck";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 124>;
+		ipmmu_sy0: mmu@e6280000 {
+			compatible = "renesas,ipmmu-r8a7743",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6280000 0 0x1000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
 			status = "disabled";
 		};
 
-		cmt1: timer@e6130000 {
-			compatible = "renesas,r8a7743-cmt1",
-				     "renesas,rcar-gen2-cmt1";
-			reg = <0 0xe6130000 0 0x1004>;
-			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 329>;
-			clock-names = "fck";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 329>;
+		ipmmu_sy1: mmu@e6290000 {
+			compatible = "renesas,ipmmu-r8a7743",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6290000 0 0x1000>;
+			interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
 			status = "disabled";
 		};
 
-		cpg: clock-controller@e6150000 {
-			compatible = "renesas,r8a7743-cpg-mssr";
-			reg = <0 0xe6150000 0 0x1000>;
-			clocks = <&extal_clk>, <&usb_extal_clk>;
-			clock-names = "extal", "usb_extal";
-			#clock-cells = <2>;
-			#power-domain-cells = <0>;
-			#reset-cells = <1>;
+		ipmmu_ds: mmu@e6740000 {
+			compatible = "renesas,ipmmu-r8a7743",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6740000 0 0x1000>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		prr: chipid@ff000044 {
-			compatible = "renesas,prr";
-			reg = <0 0xff000044 0 4>;
+		ipmmu_mp: mmu@ec680000 {
+			compatible = "renesas,ipmmu-r8a7743",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xec680000 0 0x1000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		rst: reset-controller@e6160000 {
-			compatible = "renesas,r8a7743-rst";
-			reg = <0 0xe6160000 0 0x100>;
+		ipmmu_mx: mmu@fe951000 {
+			compatible = "renesas,ipmmu-r8a7743",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xfe951000 0 0x1000>;
+			interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		sysc: system-controller@e6180000 {
-			compatible = "renesas,r8a7743-sysc";
-			reg = <0 0xe6180000 0 0x200>;
-			#power-domain-cells = <1>;
+		ipmmu_gp: mmu@e62a0000 {
+			compatible = "renesas,ipmmu-r8a7743",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe62a0000 0 0x1000>;
+			interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		pfc: pin-controller@e6060000 {
-			compatible = "renesas,pfc-r8a7743";
-			reg = <0 0xe6060000 0 0x250>;
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
 		};
 
-		dmac0: dma-controller@e6700000 {
-			compatible = "renesas,dmac-r8a7743",
-				     "renesas,rcar-dmac";
-			reg = <0 0xe6700000 0 0x20000>;
-			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					"ch0", "ch1", "ch2", "ch3",
-					"ch4", "ch5", "ch6", "ch7",
-					"ch8", "ch9", "ch10", "ch11",
-					"ch12", "ch13", "ch14";
-			clocks = <&cpg CPG_MOD 219>;
-			clock-names = "fck";
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
+
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
+		};
+
+		icram2:	sram@e6300000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe6300000 0 0x40000>;
+		};
+
+		/* The memory map in the User's Manual maps the cores to
+		 * bus numbers
+		 */
+		i2c0: i2c@e6508000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7743",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
 			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 219>;
-			#dma-cells = <1>;
-			dma-channels = <15>;
+			resets = <&cpg 931>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
 		};
 
-		dmac1: dma-controller@e6720000 {
-			compatible = "renesas,dmac-r8a7743",
-				     "renesas,rcar-dmac";
-			reg = <0 0xe6720000 0 0x20000>;
-			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					"ch0", "ch1", "ch2", "ch3",
-					"ch4", "ch5", "ch6", "ch7",
-					"ch8", "ch9", "ch10", "ch11",
-					"ch12", "ch13", "ch14";
-			clocks = <&cpg CPG_MOD 218>;
-			clock-names = "fck";
+		i2c1: i2c@e6518000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7743",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
 			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 218>;
-			#dma-cells = <1>;
-			dma-channels = <15>;
+			resets = <&cpg 930>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
 		};
 
-		audma0: dma-controller@ec700000 {
-			compatible = "renesas,dmac-r8a7743",
-				     "renesas,rcar-dmac";
-			reg = <0 0xec700000 0 0x10000>;
-			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					  "ch0", "ch1", "ch2", "ch3",
-					  "ch4", "ch5", "ch6", "ch7",
-					  "ch8", "ch9", "ch10", "ch11",
-					  "ch12";
-			clocks = <&cpg CPG_MOD 502>;
-			clock-names = "fck";
+		i2c2: i2c@e6530000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7743",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
 			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 502>;
-			#dma-cells = <1>;
-			dma-channels = <13>;
-		};
-
-		audma1: dma-controller@ec720000 {
-			compatible = "renesas,dmac-r8a7743",
-				     "renesas,rcar-dmac";
-			reg = <0 0xec720000 0 0x10000>;
-			interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					  "ch0", "ch1", "ch2", "ch3",
-					  "ch4", "ch5", "ch6", "ch7",
-					  "ch8", "ch9", "ch10", "ch11",
-					  "ch12";
-			clocks = <&cpg CPG_MOD 501>;
-			clock-names = "fck";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 501>;
-			#dma-cells = <1>;
-			dma-channels = <13>;
-		};
-
-		usb_dmac0: dma-controller@e65a0000 {
-			compatible = "renesas,r8a7743-usb-dmac",
-				     "renesas,usb-dmac";
-			reg = <0 0xe65a0000 0 0x100>;
-			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "ch0", "ch1";
-			clocks = <&cpg CPG_MOD 330>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 330>;
-			#dma-cells = <1>;
-			dma-channels = <2>;
-		};
-
-		usb_dmac1: dma-controller@e65b0000 {
-			compatible = "renesas,r8a7743-usb-dmac",
-				     "renesas,usb-dmac";
-			reg = <0 0xe65b0000 0 0x100>;
-			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "ch0", "ch1";
-			clocks = <&cpg CPG_MOD 331>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 331>;
-			#dma-cells = <1>;
-			dma-channels = <2>;
-		};
-
-		/* The memory map in the User's Manual maps the cores to bus
-		 *  numbers
-		 */
-		i2c0: i2c@e6508000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7743",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6508000 0 0x40>;
-			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 931>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 931>;
-			i2c-scl-internal-delay-ns = <6>;
-			status = "disabled";
-		};
-
-		i2c1: i2c@e6518000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7743",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6518000 0 0x40>;
-			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 930>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 930>;
-			i2c-scl-internal-delay-ns = <6>;
-			status = "disabled";
-		};
-
-		i2c2: i2c@e6530000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7743",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6530000 0 0x40>;
-			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 929>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 929>;
-			i2c-scl-internal-delay-ns = <6>;
-			status = "disabled";
+			resets = <&cpg 929>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
 		};
 
 		i2c3: i2c@e6540000 {
@@ -675,6 +566,168 @@
 			status = "disabled";
 		};
 
+		hsusb: usb@e6590000 {
+			compatible = "renesas,usbhs-r8a7743",
+				     "renesas,rcar-gen2-usbhs";
+			reg = <0 0xe6590000 0 0x100>;
+			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 704>;
+			dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+			       <&usb_dmac1 0>, <&usb_dmac1 1>;
+			dma-names = "ch0", "ch1", "ch2", "ch3";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			renesas,buswait = <4>;
+			phys = <&usb0 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
+
+		usbphy: usb-phy@e6590100 {
+			compatible = "renesas,usb-phy-r8a7743",
+				     "renesas,rcar-gen2-usb-phy";
+			reg = <0 0xe6590100 0 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&cpg CPG_MOD 704>;
+			clock-names = "usbhs";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			status = "disabled";
+
+			usb0: usb-channel@0 {
+				reg = <0>;
+				#phy-cells = <1>;
+			};
+			usb2: usb-channel@2 {
+				reg = <2>;
+				#phy-cells = <1>;
+			};
+		};
+
+		usb_dmac0: dma-controller@e65a0000 {
+			compatible = "renesas,r8a7743-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65a0000 0 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 330>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 330>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
+		};
+
+		usb_dmac1: dma-controller@e65b0000 {
+			compatible = "renesas,r8a7743-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65b0000 0 0x100>;
+			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 331>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 331>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
+		};
+
+		dmac0: dma-controller@e6700000 {
+			compatible = "renesas,dmac-r8a7743",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6700000 0 0x20000>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 219>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 219>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
+
+		dmac1: dma-controller@e6720000 {
+			compatible = "renesas,dmac-r8a7743",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6720000 0 0x20000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
+
+		avb: ethernet@e6800000 {
+			compatible = "renesas,etheravb-r8a7743",
+				     "renesas,etheravb-rcar-gen2";
+			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 812>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 812>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7743", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			resets = <&cpg 917>;
+			status = "disabled";
+		};
+
 		scifa0: serial@e6c40000 {
 			compatible = "renesas,scifa-r8a7743",
 				     "renesas,rcar-gen2-scifa", "renesas,scifa";
@@ -954,88 +1007,6 @@
 			status = "disabled";
 		};
 
-		icram2:	sram@e6300000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe6300000 0 0x40000>;
-		};
-
-		icram0:	sram@e63a0000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe63a0000 0 0x12000>;
-		};
-
-		icram1:	sram@e63c0000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe63c0000 0 0x1000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0 0 0xe63c0000 0x1000>;
-
-			smp-sram@0 {
-				compatible = "renesas,smp-sram";
-				reg = <0 0x10>;
-			};
-		};
-
-		ether: ethernet@ee700000 {
-			compatible = "renesas,ether-r8a7743",
-				     "renesas,rcar-gen2-ether";
-			reg = <0 0xee700000 0 0x400>;
-			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 813>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 813>;
-			phy-mode = "rmii";
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		avb: ethernet@e6800000 {
-			compatible = "renesas,etheravb-r8a7743",
-				     "renesas,etheravb-rcar-gen2";
-			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
-			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 812>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 812>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		mmcif0: mmc@ee200000 {
-			compatible = "renesas,mmcif-r8a7743",
-				     "renesas,sh-mmcif";
-			reg = <0 0xee200000 0 0x80>;
-			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 315>;
-			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
-			       <&dmac1 0xd1>, <&dmac1 0xd2>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 315>;
-			reg-io-width = <4>;
-			max-frequency = <97500000>;
-			status = "disabled";
-		};
-
-		qspi: spi@e6b10000 {
-			compatible = "renesas,qspi-r8a7743", "renesas,qspi";
-			reg = <0 0xe6b10000 0 0x2c>;
-			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 917>;
-			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-			       <&dmac1 0x17>, <&dmac1 0x18>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			num-cs = <1>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			resets = <&cpg 917>;
-			status = "disabled";
-		};
-
 		msiof0: spi@e6e20000 {
 			compatible = "renesas,msiof-r8a7743",
 				     "renesas,rcar-gen2-msiof";
@@ -1084,26 +1055,6 @@
 			status = "disabled";
 		};
 
-		/*
-		 * pci1 and xhci share the same phy, therefore only one of them
-		 * can be active at any one time. If both of them are enabled,
-		 * a race condition will determine who'll control the phy.
-		 * A firmware file is needed by the xhci driver in order for
-		 * USB 3.0 to work properly.
-		 */
-		xhci: usb@ee000000 {
-			compatible = "renesas,xhci-r8a7743",
-				     "renesas,rcar-gen2-xhci";
-			reg = <0 0xee000000 0 0xc00>;
-			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 328>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 328>;
-			phys = <&usb2 1>;
-			phy-names = "usb";
-			status = "disabled";
-		};
-
 		pwm0: pwm@e6e30000 {
 			compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar";
 			reg = <0 0xe6e30000 0 0x8>;
@@ -1174,98 +1125,32 @@
 			status = "disabled";
 		};
 
-		tpu: pwm@e60f0000 {
-			compatible = "renesas,tpu-r8a7743", "renesas,tpu";
-			reg = <0 0xe60f0000 0 0x148>;
-			clocks = <&cpg CPG_MOD 304>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 304>;
-			#pwm-cells = <3>;
-			status = "disabled";
-		};
-
-		sdhi0: sd@ee100000 {
-			compatible = "renesas,sdhi-r8a7743",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee100000 0 0x328>;
-			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 314>;
-			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-			       <&dmac1 0xcd>, <&dmac1 0xce>;
-			dma-names = "tx", "rx", "tx", "rx";
-			max-frequency = <195000000>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 314>;
-			status = "disabled";
-		};
-
-		sdhi1: sd@ee140000 {
-			compatible = "renesas,sdhi-r8a7743",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee140000 0 0x100>;
-			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 312>;
-			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-			       <&dmac1 0xc1>, <&dmac1 0xc2>;
-			dma-names = "tx", "rx", "tx", "rx";
-			max-frequency = <97500000>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 312>;
-			status = "disabled";
-		};
-
-		sdhi2: sd@ee160000 {
-			compatible = "renesas,sdhi-r8a7743",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee160000 0 0x100>;
-			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 311>;
-			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-			       <&dmac1 0xd3>, <&dmac1 0xd4>;
-			dma-names = "tx", "rx", "tx", "rx";
-			max-frequency = <97500000>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 311>;
-			status = "disabled";
-		};
-
-		hsusb: usb@e6590000 {
-			compatible = "renesas,usbhs-r8a7743",
-				     "renesas,rcar-gen2-usbhs";
-			reg = <0 0xe6590000 0 0x100>;
-			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 704>;
-			dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
-			       <&usb_dmac1 0>, <&usb_dmac1 1>;
-			dma-names = "ch0", "ch1", "ch2", "ch3";
+		can0: can@e6e80000 {
+			compatible = "renesas,can-r8a7743",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e80000 0 0x1000>;
+			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 916>,
+				 <&cpg CPG_CORE R8A7743_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
 			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 704>;
-			renesas,buswait = <4>;
-			phys = <&usb0 1>;
-			phy-names = "usb";
+			resets = <&cpg 916>;
 			status = "disabled";
 		};
 
-		usbphy: usb-phy@e6590100 {
-			compatible = "renesas,usb-phy-r8a7743",
-				     "renesas,rcar-gen2-usb-phy";
-			reg = <0 0xe6590100 0 0x100>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			clocks = <&cpg CPG_MOD 704>;
-			clock-names = "usbhs";
+		can1: can@e6e88000 {
+			compatible = "renesas,can-r8a7743",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e88000 0 0x1000>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 915>,
+				 <&cpg CPG_CORE R8A7743_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
 			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 704>;
+			resets = <&cpg 915>;
 			status = "disabled";
-
-			usb0: usb-channel@0 {
-				reg = <0>;
-				#phy-cells = <1>;
-			};
-			usb2: usb-channel@2 {
-				reg = <2>;
-				#phy-cells = <1>;
-			};
 		};
 
 		vin0: video@e6ef0000 {
@@ -1301,177 +1186,21 @@
 			status = "disabled";
 		};
 
-		du: display@feb00000 {
-			compatible = "renesas,du-r8a7743";
-			reg = <0 0xfeb00000 0 0x40000>,
-			      <0 0xfeb90000 0 0x1c>;
-			reg-names = "du", "lvds.0";
-			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 724>,
-				 <&cpg CPG_MOD 723>,
-				 <&cpg CPG_MOD 726>;
-			clock-names = "du.0", "du.1", "lvds.0";
-			status = "disabled";
-
-			ports {
-				#address-cells = <1>;
-				#size-cells = <0>;
-
-				port@0 {
-					reg = <0>;
-					du_out_rgb: endpoint {
-					};
-				};
-				port@1 {
-					reg = <1>;
-					du_out_lvds0: endpoint {
-					};
-				};
-			};
-		};
-
-		can0: can@e6e80000 {
-			compatible = "renesas,can-r8a7743",
-				     "renesas,rcar-gen2-can";
-			reg = <0 0xe6e80000 0 0x1000>;
-			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 916>,
-				 <&cpg CPG_CORE R8A7743_CLK_RCAN>,
-				 <&can_clk>;
-			clock-names = "clkp1", "clkp2", "can_clk";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 916>;
-			status = "disabled";
-		};
-
-		can1: can@e6e88000 {
-			compatible = "renesas,can-r8a7743",
-				     "renesas,rcar-gen2-can";
-			reg = <0 0xe6e88000 0 0x1000>;
-			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 915>,
-				 <&cpg CPG_CORE R8A7743_CLK_RCAN>,
-				 <&can_clk>;
-			clock-names = "clkp1", "clkp2", "can_clk";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 915>;
-			status = "disabled";
-		};
-
-		pci0: pci@ee090000 {
-			compatible = "renesas,pci-r8a7743",
-				     "renesas,pci-rcar-gen2";
-			device_type = "pci";
-			reg = <0 0xee090000 0 0xc00>,
-			      <0 0xee080000 0 0x1100>;
-			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 703>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 703>;
-			status = "disabled";
-
-			bus-range = <0 0>;
-			#address-cells = <3>;
-			#size-cells = <2>;
-			#interrupt-cells = <1>;
-			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
-			interrupt-map-mask = <0xff00 0 0 0x7>;
-			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-
-			usb@1,0 {
-				reg = <0x800 0 0 0 0>;
-				phys = <&usb0 0>;
-				phy-names = "usb";
-			};
-
-			usb@2,0 {
-				reg = <0x1000 0 0 0 0>;
-				phys = <&usb0 0>;
-				phy-names = "usb";
-			};
-		};
-
-		pci1: pci@ee0d0000 {
-			compatible = "renesas,pci-r8a7743",
-				     "renesas,pci-rcar-gen2";
-			device_type = "pci";
-			reg = <0 0xee0d0000 0 0xc00>,
-			      <0 0xee0c0000 0 0x1100>;
-			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 703>;
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 703>;
-			status = "disabled";
-
-			bus-range = <1 1>;
-			#address-cells = <3>;
-			#size-cells = <2>;
-			#interrupt-cells = <1>;
-			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
-			interrupt-map-mask = <0xff00 0 0 0x7>;
-			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-
-			usb@1,0 {
-				reg = <0x10800 0 0 0 0>;
-				phys = <&usb2 0>;
-				phy-names = "usb";
-			};
-
-			usb@2,0 {
-				reg = <0x11000 0 0 0 0>;
-				phys = <&usb2 0>;
-				phy-names = "usb";
-			};
-		};
-
-		pciec: pcie@fe000000 {
-			compatible = "renesas,pcie-r8a7743",
-				     "renesas,pcie-rcar-gen2";
-			reg = <0 0xfe000000 0 0x80000>;
-			#address-cells = <3>;
-			#size-cells = <2>;
-			bus-range = <0x00 0xff>;
-			device_type = "pci";
-			ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
-				  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
-				  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
-				  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
-			/* Map all possible DDR as inbound ranges */
-			dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
-				      0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>;
-			interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-			#interrupt-cells = <1>;
-			interrupt-map-mask = <0 0 0 0>;
-			interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
-			clock-names = "pcie", "pcie_bus";
-			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
-			resets = <&cpg 319>;
-			status = "disabled";
-		};
-
-		rcar_sound: sound@ec500000 {
-			/*
-			 * #sound-dai-cells is required
-			 *
-			 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
-			 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
-			 */
-			compatible = "renesas,rcar_sound-r8a7743",
-				     "renesas,rcar_sound-gen2";
-			reg = <0 0xec500000 0 0x1000>, /* SCU */
-			      <0 0xec5a0000 0 0x100>,  /* ADG */
-			      <0 0xec540000 0 0x1000>, /* SSIU */
-			      <0 0xec541000 0 0x280>,  /* SSI */
-			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
-			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+		rcar_sound: sound@ec500000 {
+			/*
+			 * #sound-dai-cells is required
+			 *
+			 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
+			 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
+			 */
+			compatible = "renesas,rcar_sound-r8a7743",
+				     "renesas,rcar_sound-gen2";
+			reg = <0 0xec500000 0 0x1000>, /* SCU */
+			      <0 0xec5a0000 0 0x100>,  /* ADG */
+			      <0 0xec540000 0 0x1000>, /* SSIU */
+			      <0 0xec541000 0 0x280>,  /* SSI */
+			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
 
 			clocks = <&cpg CPG_MOD 1005>,
 				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
@@ -1641,6 +1370,369 @@
 				};
 			};
 		};
+
+		audma0: dma-controller@ec700000 {
+			compatible = "renesas,dmac-r8a7743",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec700000 0 0x10000>;
+			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 502>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 502>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
+
+		audma1: dma-controller@ec720000 {
+			compatible = "renesas,dmac-r8a7743",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec720000 0 0x10000>;
+			interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 501>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 501>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
+
+		/*
+		 * pci1 and xhci share the same phy, therefore only one of them
+		 * can be active at any one time. If both of them are enabled,
+		 * a race condition will determine who'll control the phy.
+		 * A firmware file is needed by the xhci driver in order for
+		 * USB 3.0 to work properly.
+		 */
+		xhci: usb@ee000000 {
+			compatible = "renesas,xhci-r8a7743",
+				     "renesas,rcar-gen2-xhci";
+			reg = <0 0xee000000 0 0xc00>;
+			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 328>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 328>;
+			phys = <&usb2 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
+
+		pci0: pci@ee090000 {
+			compatible = "renesas,pci-r8a7743",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee090000 0 0xc00>,
+			      <0 0xee080000 0 0x1100>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x800 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+
+			usb@2,0 {
+				reg = <0x1000 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+		};
+
+		pci1: pci@ee0d0000 {
+			compatible = "renesas,pci-r8a7743",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee0d0000 0 0xc00>,
+			      <0 0xee0c0000 0 0x1100>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <1 1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x10800 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+
+			usb@2,0 {
+				reg = <0x11000 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+		};
+
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7743",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 314>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
+
+		sdhi1: sd@ee140000 {
+			compatible = "renesas,sdhi-r8a7743",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee140000 0 0x100>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 312>;
+			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+			       <&dmac1 0xc1>, <&dmac1 0xc2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 312>;
+			status = "disabled";
+		};
+
+		sdhi2: sd@ee160000 {
+			compatible = "renesas,sdhi-r8a7743",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee160000 0 0x100>;
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 311>;
+			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+			       <&dmac1 0xd3>, <&dmac1 0xd4>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 311>;
+			status = "disabled";
+		};
+
+		mmcif0: mmc@ee200000 {
+			compatible = "renesas,mmcif-r8a7743",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee200000 0 0x80>;
+			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 315>;
+			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
+			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 315>;
+			reg-io-width = <4>;
+			max-frequency = <97500000>;
+			status = "disabled";
+		};
+
+		ether: ethernet@ee700000 {
+			compatible = "renesas,ether-r8a7743",
+				     "renesas,rcar-gen2-ether";
+			reg = <0 0xee700000 0 0x400>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 813>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 813>;
+			phy-mode = "rmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>, <0 0xf1002000 0 0x2000>,
+			      <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
+
+		pciec: pcie@fe000000 {
+			compatible = "renesas,pcie-r8a7743",
+				     "renesas,pcie-rcar-gen2";
+			reg = <0 0xfe000000 0 0x80000>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			bus-range = <0x00 0xff>;
+			device_type = "pci";
+			ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+				  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+				  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+				  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+			/* Map all possible DDR as inbound ranges */
+			dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
+				      0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>;
+			interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
+			clock-names = "pcie", "pcie_bus";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 319>;
+			status = "disabled";
+		};
+
+		vsp@fe928000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe928000 0 0x8000>;
+			interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 131>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 131>;
+		};
+
+		vsp@fe930000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe930000 0 0x8000>;
+			interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 128>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 128>;
+		};
+
+		vsp@fe938000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe938000 0 0x8000>;
+			interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 127>;
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 127>;
+		};
+
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7743";
+			reg = <0 0xfeb00000 0 0x40000>,
+			      <0 0xfeb90000 0 0x1c>;
+			reg-names = "du", "lvds.0";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>,
+				 <&cpg CPG_MOD 723>,
+				 <&cpg CPG_MOD 726>;
+			clock-names = "du.0", "du.1", "lvds.0";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_lvds0: endpoint {
+					};
+				};
+			};
+		};
+
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
+		};
+
+		cmt0: timer@ffca0000 {
+			compatible = "renesas,r8a7743-cmt0",
+				     "renesas,rcar-gen2-cmt0";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 124>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 124>;
+			status = "disabled";
+		};
+
+		cmt1: timer@e6130000 {
+			compatible = "renesas,r8a7743-cmt1",
+				     "renesas,rcar-gen2-cmt1";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 329>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7743_PD_ALWAYS_ON>;
+			resets = <&cpg 329>;
+			status = "disabled";
+		};
 	};
 
 	thermal-zones {
diff --git a/arch/arm/boot/dts/r8a7745-iwg22m.dtsi b/arch/arm/boot/dts/r8a7745-iwg22m.dtsi
index ed9a8cf3fe36..29b6e10fdf96 100644
--- a/arch/arm/boot/dts/r8a7745-iwg22m.dtsi
+++ b/arch/arm/boot/dts/r8a7745-iwg22m.dtsi
@@ -29,6 +29,10 @@
 	};
 };
 
+&cmt0 {
+	status = "okay";
+};
+
 &extal_clk {
 	clock-frequency = <20000000>;
 };
@@ -87,6 +91,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &sdhi1 {
 	pinctrl-0 = <&sdhi1_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7745.dtsi b/arch/arm/boot/dts/r8a7745.dtsi
index ae918e9cce21..3de69cb66c44 100644
--- a/arch/arm/boot/dts/r8a7745.dtsi
+++ b/arch/arm/boot/dts/r8a7745.dtsi
@@ -121,29 +121,6 @@
 		#size-cells = <2>;
 		ranges;
 
-		apmu@e6151000 {
-			compatible = "renesas,r8a7745-apmu", "renesas,apmu";
-			reg = <0 0xe6151000 0 0x188>;
-			cpus = <&cpu0 &cpu1>;
-		};
-
-		gic: interrupt-controller@f1001000 {
-			compatible = "arm,gic-400";
-			#interrupt-cells = <3>;
-			#address-cells = <0>;
-			interrupt-controller;
-			reg = <0 0xf1001000 0 0x1000>,
-			      <0 0xf1002000 0 0x2000>,
-			      <0 0xf1004000 0 0x2000>,
-			      <0 0xf1006000 0 0x2000>;
-			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
-						 IRQ_TYPE_LEVEL_HIGH)>;
-			clocks = <&cpg CPG_MOD 408>;
-			clock-names = "clk";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 408>;
-		};
-
 		gpio0: gpio@e6050000 {
 			compatible = "renesas,gpio-r8a7745",
 				     "renesas,rcar-gen2-gpio";
@@ -249,55 +226,18 @@
 			resets = <&cpg 905>;
 		};
 
-		irqc: interrupt-controller@e61c0000 {
-			compatible = "renesas,irqc-r8a7745", "renesas,irqc";
-			#interrupt-cells = <2>;
-			interrupt-controller;
-			reg = <0 0xe61c0000 0 0x200>;
-			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 407>;
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 407>;
-		};
-
-		cmt0: timer@ffca0000 {
-			compatible = "renesas,r8a7745-cmt0",
-				     "renesas,rcar-gen2-cmt0";
-			reg = <0 0xffca0000 0 0x1004>;
-			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 124>;
-			clock-names = "fck";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 124>;
-			status = "disabled";
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7745";
+			reg = <0 0xe6060000 0 0x11c>;
 		};
 
-		cmt1: timer@e6130000 {
-			compatible = "renesas,r8a7745-cmt1",
-				     "renesas,rcar-gen2-cmt1";
-			reg = <0 0xe6130000 0 0x1004>;
-			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 329>;
-			clock-names = "fck";
+		tpu: pwm@e60f0000 {
+			compatible = "renesas,tpu-r8a7745", "renesas,tpu";
+			reg = <0 0xe60f0000 0 0x148>;
+			clocks = <&cpg CPG_MOD 304>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 329>;
+			resets = <&cpg 304>;
+			#pwm-cells = <3>;
 			status = "disabled";
 		};
 
@@ -311,9 +251,10 @@
 			#reset-cells = <1>;
 		};
 
-		prr: chipid@ff000044 {
-			compatible = "renesas,prr";
-			reg = <0 0xff000044 0 4>;
+		apmu@e6151000 {
+			compatible = "renesas,r8a7745-apmu", "renesas,apmu";
+			reg = <0 0xe6151000 0 0x188>;
+			cpus = <&cpu0 &cpu1>;
 		};
 
 		rst: reset-controller@e6160000 {
@@ -321,456 +262,371 @@
 			reg = <0 0xe6160000 0 0x100>;
 		};
 
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7745-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 402>;
+			status = "disabled";
+		};
+
 		sysc: system-controller@e6180000 {
 			compatible = "renesas,r8a7745-sysc";
 			reg = <0 0xe6180000 0 0x200>;
 			#power-domain-cells = <1>;
 		};
 
-		pfc: pin-controller@e6060000 {
-			compatible = "renesas,pfc-r8a7745";
-			reg = <0 0xe6060000 0 0x11c>;
-		};
-
-		dmac0: dma-controller@e6700000 {
-			compatible = "renesas,dmac-r8a7745",
-				     "renesas,rcar-dmac";
-			reg = <0 0xe6700000 0 0x20000>;
-			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					"ch0", "ch1", "ch2", "ch3",
-					"ch4", "ch5", "ch6", "ch7",
-					"ch8", "ch9", "ch10", "ch11",
-					"ch12", "ch13", "ch14";
-			clocks = <&cpg CPG_MOD 219>;
-			clock-names = "fck";
+		irqc: interrupt-controller@e61c0000 {
+			compatible = "renesas,irqc-r8a7745", "renesas,irqc";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0 0xe61c0000 0 0x200>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 407>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 219>;
-			#dma-cells = <1>;
-			dma-channels = <15>;
+			resets = <&cpg 407>;
 		};
 
-		dmac1: dma-controller@e6720000 {
-			compatible = "renesas,dmac-r8a7745",
-				     "renesas,rcar-dmac";
-			reg = <0 0xe6720000 0 0x20000>;
-			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					"ch0", "ch1", "ch2", "ch3",
-					"ch4", "ch5", "ch6", "ch7",
-					"ch8", "ch9", "ch10", "ch11",
-					"ch12", "ch13", "ch14";
-			clocks = <&cpg CPG_MOD 218>;
-			clock-names = "fck";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 218>;
-			#dma-cells = <1>;
-			dma-channels = <15>;
+		ipmmu_sy0: mmu@e6280000 {
+			compatible = "renesas,ipmmu-r8a7745",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6280000 0 0x1000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		audma0: dma-controller@ec700000 {
-			compatible = "renesas,dmac-r8a7745",
-				     "renesas,rcar-dmac";
-			reg = <0 0xec700000 0 0x10000>;
-			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "error",
-					  "ch0", "ch1", "ch2", "ch3",
-					  "ch4", "ch5", "ch6", "ch7",
-					  "ch8", "ch9", "ch10", "ch11",
-					  "ch12";
-			clocks = <&cpg CPG_MOD 502>;
-			clock-names = "fck";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 502>;
-			#dma-cells = <1>;
-			dma-channels = <13>;
+		ipmmu_sy1: mmu@e6290000 {
+			compatible = "renesas,ipmmu-r8a7745",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6290000 0 0x1000>;
+			interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		usb_dmac0: dma-controller@e65a0000 {
-			compatible = "renesas,r8a7745-usb-dmac",
-				     "renesas,usb-dmac";
-			reg = <0 0xe65a0000 0 0x100>;
-			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "ch0", "ch1";
-			clocks = <&cpg CPG_MOD 330>;
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 330>;
-			#dma-cells = <1>;
-			dma-channels = <2>;
+		ipmmu_ds: mmu@e6740000 {
+			compatible = "renesas,ipmmu-r8a7745",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6740000 0 0x1000>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		usb_dmac1: dma-controller@e65b0000 {
-			compatible = "renesas,r8a7745-usb-dmac",
-				     "renesas,usb-dmac";
-			reg = <0 0xe65b0000 0 0x100>;
-			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
-				      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-			interrupt-names = "ch0", "ch1";
-			clocks = <&cpg CPG_MOD 331>;
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 331>;
-			#dma-cells = <1>;
-			dma-channels = <2>;
+		ipmmu_mp: mmu@ec680000 {
+			compatible = "renesas,ipmmu-r8a7745",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xec680000 0 0x1000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
 		};
 
-		scifa0: serial@e6c40000 {
-			compatible = "renesas,scifa-r8a7745",
-				     "renesas,rcar-gen2-scifa", "renesas,scifa";
-			reg = <0 0xe6c40000 0 0x40>;
-			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 204>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x21>, <&dmac0 0x22>,
-			       <&dmac1 0x21>, <&dmac1 0x22>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 204>;
+		ipmmu_mx: mmu@fe951000 {
+			compatible = "renesas,ipmmu-r8a7745",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xfe951000 0 0x1000>;
+			interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
 			status = "disabled";
 		};
 
-		scifa1: serial@e6c50000 {
-			compatible = "renesas,scifa-r8a7745",
-				     "renesas,rcar-gen2-scifa", "renesas,scifa";
-			reg = <0 0xe6c50000 0 0x40>;
-			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 203>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x25>, <&dmac0 0x26>,
-			       <&dmac1 0x25>, <&dmac1 0x26>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 203>;
+		ipmmu_gp: mmu@e62a0000 {
+			compatible = "renesas,ipmmu-r8a7745",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe62a0000 0 0x1000>;
+			interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
 			status = "disabled";
 		};
 
-		scifa2: serial@e6c60000 {
-			compatible = "renesas,scifa-r8a7745",
-				     "renesas,rcar-gen2-scifa", "renesas,scifa";
-			reg = <0 0xe6c60000 0 0x40>;
-			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 202>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x27>, <&dmac0 0x28>,
-			       <&dmac1 0x27>, <&dmac1 0x28>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 202>;
-			status = "disabled";
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
 		};
 
-		scifa3: serial@e6c70000 {
-			compatible = "renesas,scifa-r8a7745",
-				     "renesas,rcar-gen2-scifa", "renesas,scifa";
-			reg = <0 0xe6c70000 0 0x40>;
-			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 1106>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
-			       <&dmac1 0x1b>, <&dmac1 0x1c>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 1106>;
-			status = "disabled";
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
+
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
 		};
 
-		scifa4: serial@e6c78000 {
-			compatible = "renesas,scifa-r8a7745",
-				     "renesas,rcar-gen2-scifa", "renesas,scifa";
-			reg = <0 0xe6c78000 0 0x40>;
-			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 1107>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
-			       <&dmac1 0x1f>, <&dmac1 0x20>;
-			dma-names = "tx", "rx", "tx", "rx";
+		icram2:	sram@e6300000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe6300000 0 0x40000>;
+		};
+		i2c0: i2c@e6508000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7745",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 1107>;
+			resets = <&cpg 931>;
+			i2c-scl-internal-delay-ns = <6>;
 			status = "disabled";
 		};
 
-		scifa5: serial@e6c80000 {
-			compatible = "renesas,scifa-r8a7745",
-				     "renesas,rcar-gen2-scifa", "renesas,scifa";
-			reg = <0 0xe6c80000 0 0x40>;
-			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 1108>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x23>, <&dmac0 0x24>,
-			       <&dmac1 0x23>, <&dmac1 0x24>;
-			dma-names = "tx", "rx", "tx", "rx";
+		i2c1: i2c@e6518000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7745",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 1108>;
+			resets = <&cpg 930>;
+			i2c-scl-internal-delay-ns = <6>;
 			status = "disabled";
 		};
 
-		scifb0: serial@e6c20000 {
-			compatible = "renesas,scifb-r8a7745",
-				     "renesas,rcar-gen2-scifb", "renesas,scifb";
-			reg = <0 0xe6c20000 0 0x100>;
-			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 206>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
-			       <&dmac1 0x3d>, <&dmac1 0x3e>;
-			dma-names = "tx", "rx", "tx", "rx";
+		i2c2: i2c@e6530000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7745",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 206>;
+			resets = <&cpg 929>;
+			i2c-scl-internal-delay-ns = <6>;
 			status = "disabled";
 		};
 
-		scifb1: serial@e6c30000 {
-			compatible = "renesas,scifb-r8a7745",
-				     "renesas,rcar-gen2-scifb", "renesas,scifb";
-			reg = <0 0xe6c30000 0 0x100>;
-			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 207>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
-			       <&dmac1 0x19>, <&dmac1 0x1a>;
-			dma-names = "tx", "rx", "tx", "rx";
+		i2c3: i2c@e6540000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7745",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6540000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 207>;
+			resets = <&cpg 928>;
+			i2c-scl-internal-delay-ns = <6>;
 			status = "disabled";
 		};
 
-		scifb2: serial@e6ce0000 {
-			compatible = "renesas,scifb-r8a7745",
-				     "renesas,rcar-gen2-scifb", "renesas,scifb";
-			reg = <0 0xe6ce0000 0 0x100>;
-			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 216>;
-			clock-names = "fck";
-			dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
-			       <&dmac1 0x1d>, <&dmac1 0x1e>;
-			dma-names = "tx", "rx", "tx", "rx";
+		i2c4: i2c@e6520000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7745",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6520000 0 0x40>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 927>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 216>;
+			resets = <&cpg 927>;
+			i2c-scl-internal-delay-ns = <6>;
 			status = "disabled";
 		};
 
-		scif0: serial@e6e60000 {
-			compatible = "renesas,scif-r8a7745",
-				     "renesas,rcar-gen2-scif", "renesas,scif";
-			reg = <0 0xe6e60000 0 0x40>;
-			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 721>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
-			       <&dmac1 0x29>, <&dmac1 0x2a>;
-			dma-names = "tx", "rx", "tx", "rx";
+		i2c5: i2c@e6528000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7745",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6528000 0 0x40>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 925>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 721>;
+			resets = <&cpg 925>;
+			i2c-scl-internal-delay-ns = <6>;
 			status = "disabled";
 		};
 
-		scif1: serial@e6e68000 {
-			compatible = "renesas,scif-r8a7745",
-				     "renesas,rcar-gen2-scif", "renesas,scif";
-			reg = <0 0xe6e68000 0 0x40>;
-			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 720>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
-			       <&dmac1 0x2d>, <&dmac1 0x2e>;
+		iic0: i2c@e6500000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7745",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6500000 0 0x425>;
+			interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 318>;
+			dmas = <&dmac0 0x61>, <&dmac0 0x62>,
+			       <&dmac1 0x61>, <&dmac1 0x62>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 720>;
+			resets = <&cpg 318>;
 			status = "disabled";
 		};
 
-		scif2: serial@e6e58000 {
-			compatible = "renesas,scif-r8a7745",
-				     "renesas,rcar-gen2-scif", "renesas,scif";
-			reg = <0 0xe6e58000 0 0x40>;
-			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 719>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
-			       <&dmac1 0x2b>, <&dmac1 0x2c>;
+		iic1: i2c@e6510000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7745",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6510000 0 0x425>;
+			interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 323>;
+			dmas = <&dmac0 0x65>, <&dmac0 0x66>,
+			       <&dmac1 0x65>, <&dmac1 0x66>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 719>;
+			resets = <&cpg 323>;
 			status = "disabled";
 		};
 
-		scif3: serial@e6ea8000 {
-			compatible = "renesas,scif-r8a7745",
-				     "renesas,rcar-gen2-scif", "renesas,scif";
-			reg = <0 0xe6ea8000 0 0x40>;
-			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 718>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
-			       <&dmac1 0x2f>, <&dmac1 0x30>;
-			dma-names = "tx", "rx", "tx", "rx";
+		hsusb: usb@e6590000 {
+			compatible = "renesas,usbhs-r8a7745",
+				     "renesas,rcar-gen2-usbhs";
+			reg = <0 0xe6590000 0 0x100>;
+			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 704>;
+			dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+			       <&usb_dmac1 0>, <&usb_dmac1 1>;
+			dma-names = "ch0", "ch1", "ch2", "ch3";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 718>;
+			resets = <&cpg 704>;
+			renesas,buswait = <4>;
+			phys = <&usb0 1>;
+			phy-names = "usb";
 			status = "disabled";
 		};
 
-		scif4: serial@e6ee0000 {
-			compatible = "renesas,scif-r8a7745",
-				     "renesas,rcar-gen2-scif", "renesas,scif";
-			reg = <0 0xe6ee0000 0 0x40>;
-			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 715>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
-			       <&dmac1 0xfb>, <&dmac1 0xfc>;
-			dma-names = "tx", "rx", "tx", "rx";
+		usbphy: usb-phy@e6590100 {
+			compatible = "renesas,usb-phy-r8a7745",
+				     "renesas,rcar-gen2-usb-phy";
+			reg = <0 0xe6590100 0 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&cpg CPG_MOD 704>;
+			clock-names = "usbhs";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 715>;
+			resets = <&cpg 704>;
 			status = "disabled";
+
+			usb0: usb-channel@0 {
+				reg = <0>;
+				#phy-cells = <1>;
+			};
+			usb2: usb-channel@2 {
+				reg = <2>;
+				#phy-cells = <1>;
+			};
 		};
 
-		scif5: serial@e6ee8000 {
-			compatible = "renesas,scif-r8a7745",
-				     "renesas,rcar-gen2-scif", "renesas,scif";
-			reg = <0 0xe6ee8000 0 0x40>;
-			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 714>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
-			       <&dmac1 0xfd>, <&dmac1 0xfe>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 714>;
-			status = "disabled";
-		};
-
-		hscif0: serial@e62c0000 {
-			compatible = "renesas,hscif-r8a7745",
-				     "renesas,rcar-gen2-hscif", "renesas,hscif";
-			reg = <0 0xe62c0000 0 0x60>;
-			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 717>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
-			       <&dmac1 0x39>, <&dmac1 0x3a>;
-			dma-names = "tx", "rx", "tx", "rx";
+		usb_dmac0: dma-controller@e65a0000 {
+			compatible = "renesas,r8a7745-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65a0000 0 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 330>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 717>;
-			status = "disabled";
+			resets = <&cpg 330>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
 		};
 
-		hscif1: serial@e62c8000 {
-			compatible = "renesas,hscif-r8a7745",
-				     "renesas,rcar-gen2-hscif", "renesas,hscif";
-			reg = <0 0xe62c8000 0 0x60>;
-			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 716>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
-			       <&dmac1 0x4d>, <&dmac1 0x4e>;
-			dma-names = "tx", "rx", "tx", "rx";
+		usb_dmac1: dma-controller@e65b0000 {
+			compatible = "renesas,r8a7745-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65b0000 0 0x100>;
+			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 331>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 716>;
-			status = "disabled";
+			resets = <&cpg 331>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
 		};
 
-		hscif2: serial@e62d0000 {
-			compatible = "renesas,hscif-r8a7745",
-				     "renesas,rcar-gen2-hscif", "renesas,hscif";
-			reg = <0 0xe62d0000 0 0x60>;
-			interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 713>,
-				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
-			clock-names = "fck", "brg_int", "scif_clk";
-			dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
-			       <&dmac1 0x3b>, <&dmac1 0x3c>;
-			dma-names = "tx", "rx", "tx", "rx";
+		dmac0: dma-controller@e6700000 {
+			compatible = "renesas,dmac-r8a7745",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6700000 0 0x20000>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 219>;
+			clock-names = "fck";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 713>;
-			status = "disabled";
-		};
-
-		icram2:	sram@e6300000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe6300000 0 0x40000>;
-		};
-
-		icram0:	sram@e63a0000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe63a0000 0 0x12000>;
-		};
-
-		icram1:	sram@e63c0000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe63c0000 0 0x1000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0 0 0xe63c0000 0x1000>;
-
-			smp-sram@0 {
-				compatible = "renesas,smp-sram";
-				reg = <0 0x10>;
-			};
+			resets = <&cpg 219>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
 		};
 
-		ether: ethernet@ee700000 {
-			compatible = "renesas,ether-r8a7745",
-				     "renesas,rcar-gen2-ether";
-			reg = <0 0xee700000 0 0x400>;
-			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 813>;
+		dmac1: dma-controller@e6720000 {
+			compatible = "renesas,dmac-r8a7745",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6720000 0 0x20000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 813>;
-			phy-mode = "rmii";
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
 		};
 
 		avb: ethernet@e6800000 {
@@ -786,257 +642,353 @@
 			status = "disabled";
 		};
 
-		i2c0: i2c@e6508000 {
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7745", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			num-cs = <1>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7745",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6508000 0 0x40>;
-			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 931>;
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 931>;
-			i2c-scl-internal-delay-ns = <6>;
+			resets = <&cpg 917>;
 			status = "disabled";
 		};
 
-		i2c1: i2c@e6518000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7745",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6518000 0 0x40>;
-			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 930>;
+		scifa0: serial@e6c40000 {
+			compatible = "renesas,scifa-r8a7745",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c40000 0 0x40>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 204>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x21>, <&dmac0 0x22>,
+			       <&dmac1 0x21>, <&dmac1 0x22>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 930>;
-			i2c-scl-internal-delay-ns = <6>;
+			resets = <&cpg 204>;
 			status = "disabled";
 		};
 
-		i2c2: i2c@e6530000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7745",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6530000 0 0x40>;
-			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 929>;
+		scifa1: serial@e6c50000 {
+			compatible = "renesas,scifa-r8a7745",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c50000 0 0x40>;
+			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 203>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x25>, <&dmac0 0x26>,
+			       <&dmac1 0x25>, <&dmac1 0x26>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 929>;
-			i2c-scl-internal-delay-ns = <6>;
+			resets = <&cpg 203>;
 			status = "disabled";
 		};
 
-		i2c3: i2c@e6540000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7745",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6540000 0 0x40>;
-			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 928>;
+		scifa2: serial@e6c60000 {
+			compatible = "renesas,scifa-r8a7745",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c60000 0 0x40>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 202>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x27>, <&dmac0 0x28>,
+			       <&dmac1 0x27>, <&dmac1 0x28>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 928>;
-			i2c-scl-internal-delay-ns = <6>;
+			resets = <&cpg 202>;
 			status = "disabled";
 		};
 
-		i2c4: i2c@e6520000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7745",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6520000 0 0x40>;
-			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 927>;
+		scifa3: serial@e6c70000 {
+			compatible = "renesas,scifa-r8a7745",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c70000 0 0x40>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1106>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
+			       <&dmac1 0x1b>, <&dmac1 0x1c>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 927>;
-			i2c-scl-internal-delay-ns = <6>;
+			resets = <&cpg 1106>;
 			status = "disabled";
 		};
 
-		i2c5: i2c@e6528000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,i2c-r8a7745",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6528000 0 0x40>;
-			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 925>;
+		scifa4: serial@e6c78000 {
+			compatible = "renesas,scifa-r8a7745",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c78000 0 0x40>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1107>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
+			       <&dmac1 0x1f>, <&dmac1 0x20>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 925>;
-			i2c-scl-internal-delay-ns = <6>;
+			resets = <&cpg 1107>;
 			status = "disabled";
 		};
 
-		iic0: i2c@e6500000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,iic-r8a7745",
-				     "renesas,rcar-gen2-iic",
-				     "renesas,rmobile-iic";
-			reg = <0 0xe6500000 0 0x425>;
-			interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 318>;
-			dmas = <&dmac0 0x61>, <&dmac0 0x62>,
-			       <&dmac1 0x61>, <&dmac1 0x62>;
+		scifa5: serial@e6c80000 {
+			compatible = "renesas,scifa-r8a7745",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c80000 0 0x40>;
+			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1108>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x23>, <&dmac0 0x24>,
+			       <&dmac1 0x23>, <&dmac1 0x24>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 318>;
+			resets = <&cpg 1108>;
 			status = "disabled";
 		};
 
-		iic1: i2c@e6510000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "renesas,iic-r8a7745",
-				     "renesas,rcar-gen2-iic",
-				     "renesas,rmobile-iic";
-			reg = <0 0xe6510000 0 0x425>;
-			interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 323>;
-			dmas = <&dmac0 0x65>, <&dmac0 0x66>,
-			       <&dmac1 0x65>, <&dmac1 0x66>;
+		scifb0: serial@e6c20000 {
+			compatible = "renesas,scifb-r8a7745",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c20000 0 0x100>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 206>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
+			       <&dmac1 0x3d>, <&dmac1 0x3e>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 323>;
+			resets = <&cpg 206>;
 			status = "disabled";
 		};
 
-		mmcif0: mmc@ee200000 {
-			compatible = "renesas,mmcif-r8a7745",
-				     "renesas,sh-mmcif";
-			reg = <0 0xee200000 0 0x80>;
-			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 315>;
-			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
-			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+		scifb1: serial@e6c30000 {
+			compatible = "renesas,scifb-r8a7745",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c30000 0 0x100>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 207>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
+			       <&dmac1 0x19>, <&dmac1 0x1a>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 315>;
-			reg-io-width = <4>;
-			max-frequency = <97500000>;
+			resets = <&cpg 207>;
 			status = "disabled";
 		};
 
-		qspi: spi@e6b10000 {
-			compatible = "renesas,qspi-r8a7745", "renesas,qspi";
-			reg = <0 0xe6b10000 0 0x2c>;
-			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 917>;
-			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-			       <&dmac1 0x17>, <&dmac1 0x18>;
+		scifb2: serial@e6ce0000 {
+			compatible = "renesas,scifb-r8a7745",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6ce0000 0 0x100>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 216>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
+			       <&dmac1 0x1d>, <&dmac1 0x1e>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			num-cs = <1>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			resets = <&cpg 917>;
+			resets = <&cpg 216>;
 			status = "disabled";
 		};
 
-		vin0: video@e6ef0000 {
-			compatible = "renesas,vin-r8a7745",
-				     "renesas,rcar-gen2-vin";
-			reg = <0 0xe6ef0000 0 0x1000>;
-			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 811>;
+		scif0: serial@e6e60000 {
+			compatible = "renesas,scif-r8a7745",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e60000 0 0x40>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 721>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
+			       <&dmac1 0x29>, <&dmac1 0x2a>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 811>;
+			resets = <&cpg 721>;
 			status = "disabled";
 		};
 
-		vin1: video@e6ef1000 {
-			compatible = "renesas,vin-r8a7745",
-				     "renesas,rcar-gen2-vin";
-			reg = <0 0xe6ef1000 0 0x1000>;
-			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 810>;
+		scif1: serial@e6e68000 {
+			compatible = "renesas,scif-r8a7745",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e68000 0 0x40>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 720>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
+			       <&dmac1 0x2d>, <&dmac1 0x2e>;
+			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 810>;
-			status = "disabled";
-		};
-
-		du: display@feb00000 {
-			compatible = "renesas,du-r8a7745";
-			reg = <0 0xfeb00000 0 0x40000>;
-			reg-names = "du";
-			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>;
-			clock-names = "du.0", "du.1";
+			resets = <&cpg 720>;
 			status = "disabled";
-
-			ports {
-				#address-cells = <1>;
-				#size-cells = <0>;
-
-				port@0 {
-					reg = <0>;
-					du_out_rgb0: endpoint {
-					};
-				};
-				port@1 {
-					reg = <1>;
-					du_out_rgb1: endpoint {
-					};
-				};
-			};
 		};
 
-		msiof0: spi@e6e20000 {
-			compatible = "renesas,msiof-r8a7745",
-				     "renesas,rcar-gen2-msiof";
-			reg = <0 0xe6e20000 0 0x0064>;
-			interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 000>;
-			dmas = <&dmac0 0x51>, <&dmac0 0x52>,
-			       <&dmac1 0x51>, <&dmac1 0x52>;
+		scif2: serial@e6e58000 {
+			compatible = "renesas,scif-r8a7745",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e58000 0 0x40>;
+			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 719>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
+			       <&dmac1 0x2b>, <&dmac1 0x2c>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			resets = <&cpg 000>;
+			resets = <&cpg 719>;
 			status = "disabled";
 		};
 
-		msiof1: spi@e6e10000 {
-			compatible = "renesas,msiof-r8a7745",
-				     "renesas,rcar-gen2-msiof";
-			reg = <0 0xe6e10000 0 0x0064>;
-			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 208>;
-			dmas = <&dmac0 0x55>, <&dmac0 0x56>,
-			       <&dmac1 0x55>, <&dmac1 0x56>;
+		scif3: serial@e6ea8000 {
+			compatible = "renesas,scif-r8a7745",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ea8000 0 0x40>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 718>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
+			       <&dmac1 0x2f>, <&dmac1 0x30>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			resets = <&cpg 208>;
+			resets = <&cpg 718>;
 			status = "disabled";
 		};
 
-		msiof2: spi@e6e00000 {
-			compatible = "renesas,msiof-r8a7745",
-				     "renesas,rcar-gen2-msiof";
-			reg = <0 0xe6e00000 0 0x0064>;
-			interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 205>;
-			dmas = <&dmac0 0x41>, <&dmac0 0x42>,
-			       <&dmac1 0x41>, <&dmac1 0x42>;
+		scif4: serial@e6ee0000 {
+			compatible = "renesas,scif-r8a7745",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee0000 0 0x40>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 715>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
+			       <&dmac1 0xfb>, <&dmac1 0xfc>;
 			dma-names = "tx", "rx", "tx", "rx";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			resets = <&cpg 205>;
+			resets = <&cpg 715>;
 			status = "disabled";
 		};
 
-		pwm0: pwm@e6e30000 {
-			compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar";
-			reg = <0 0xe6e30000 0 0x8>;
-			clocks = <&cpg CPG_MOD 523>;
+		scif5: serial@e6ee8000 {
+			compatible = "renesas,scif-r8a7745",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee8000 0 0x40>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 714>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
+			       <&dmac1 0xfd>, <&dmac1 0xfe>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 714>;
+			status = "disabled";
+		};
+
+		hscif0: serial@e62c0000 {
+			compatible = "renesas,hscif-r8a7745",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c0000 0 0x60>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 717>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
+			       <&dmac1 0x39>, <&dmac1 0x3a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 717>;
+			status = "disabled";
+		};
+
+		hscif1: serial@e62c8000 {
+			compatible = "renesas,hscif-r8a7745",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c8000 0 0x60>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 716>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
+			       <&dmac1 0x4d>, <&dmac1 0x4e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 716>;
+			status = "disabled";
+		};
+
+		hscif2: serial@e62d0000 {
+			compatible = "renesas,hscif-r8a7745",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62d0000 0 0x60>;
+			interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 713>,
+				 <&cpg CPG_CORE R8A7745_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
+			       <&dmac1 0x3b>, <&dmac1 0x3c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 713>;
+			status = "disabled";
+		};
+
+		msiof0: spi@e6e20000 {
+			compatible = "renesas,msiof-r8a7745",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e20000 0 0x0064>;
+			interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 000>;
+			dmas = <&dmac0 0x51>, <&dmac0 0x52>,
+			       <&dmac1 0x51>, <&dmac1 0x52>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			resets = <&cpg 000>;
+			status = "disabled";
+		};
+
+		msiof1: spi@e6e10000 {
+			compatible = "renesas,msiof-r8a7745",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e10000 0 0x0064>;
+			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 208>;
+			dmas = <&dmac0 0x55>, <&dmac0 0x56>,
+			       <&dmac1 0x55>, <&dmac1 0x56>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			resets = <&cpg 208>;
+			status = "disabled";
+		};
+
+		msiof2: spi@e6e00000 {
+			compatible = "renesas,msiof-r8a7745",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e00000 0 0x0064>;
+			interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 205>;
+			dmas = <&dmac0 0x41>, <&dmac0 0x42>,
+			       <&dmac1 0x41>, <&dmac1 0x42>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			resets = <&cpg 205>;
+			status = "disabled";
+		};
+
+		pwm0: pwm@e6e30000 {
+			compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar";
+			reg = <0 0xe6e30000 0 0x8>;
+			clocks = <&cpg CPG_MOD 523>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
 			resets = <&cpg 523>;
 			#pwm-cells = <2>;
@@ -1103,249 +1055,107 @@
 			status = "disabled";
 		};
 
-		tpu: pwm@e60f0000 {
-			compatible = "renesas,tpu-r8a7745", "renesas,tpu";
-			reg = <0 0xe60f0000 0 0x148>;
-			clocks = <&cpg CPG_MOD 304>;
+		can0: can@e6e80000 {
+			compatible = "renesas,can-r8a7745",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e80000 0 0x1000>;
+			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 916>,
+				 <&cpg CPG_CORE R8A7745_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 304>;
-			#pwm-cells = <3>;
+			resets = <&cpg 916>;
 			status = "disabled";
 		};
 
-		sdhi0: sd@ee100000 {
-			compatible = "renesas,sdhi-r8a7745",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee100000 0 0x328>;
-			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 314>;
-			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-			       <&dmac1 0xcd>, <&dmac1 0xce>;
-			dma-names = "tx", "rx", "tx", "rx";
-			max-frequency = <195000000>;
+		can1: can@e6e88000 {
+			compatible = "renesas,can-r8a7745",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e88000 0 0x1000>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 915>,
+				 <&cpg CPG_CORE R8A7745_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 314>;
+			resets = <&cpg 915>;
 			status = "disabled";
 		};
 
-		sdhi1: sd@ee140000 {
-			compatible = "renesas,sdhi-r8a7745",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee140000 0 0x100>;
-			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 312>;
-			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-			       <&dmac1 0xc1>, <&dmac1 0xc2>;
-			dma-names = "tx", "rx", "tx", "rx";
-			max-frequency = <97500000>;
+		vin0: video@e6ef0000 {
+			compatible = "renesas,vin-r8a7745",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef0000 0 0x1000>;
+			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 811>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 312>;
+			resets = <&cpg 811>;
 			status = "disabled";
 		};
 
-		sdhi2: sd@ee160000 {
-			compatible = "renesas,sdhi-r8a7745",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee160000 0 0x100>;
-			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 311>;
-			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-			       <&dmac1 0xd3>, <&dmac1 0xd4>;
-			dma-names = "tx", "rx", "tx", "rx";
-			max-frequency = <97500000>;
+		vin1: video@e6ef1000 {
+			compatible = "renesas,vin-r8a7745",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef1000 0 0x1000>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 810>;
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 311>;
+			resets = <&cpg 810>;
 			status = "disabled";
 		};
 
-		pci0: pci@ee090000 {
-			compatible = "renesas,pci-r8a7745",
-				     "renesas,pci-rcar-gen2";
-			device_type = "pci";
-			reg = <0 0xee090000 0 0xc00>,
-			      <0 0xee080000 0 0x1100>;
-			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 703>;
+		rcar_sound: sound@ec500000 {
+			/*
+			 * #sound-dai-cells is required
+			 *
+			 * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
+			 * Multi  DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
+			 */
+			compatible = "renesas,rcar_sound-r8a7745",
+				     "renesas,rcar_sound-gen2";
+			reg = <0 0xec500000 0 0x1000>, /* SCU */
+			      <0 0xec5a0000 0 0x100>,  /* ADG */
+			      <0 0xec540000 0 0x1000>, /* SSIU */
+			      <0 0xec541000 0 0x280>,  /* SSI */
+			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri */
+			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+			clocks = <&cpg CPG_MOD 1005>,
+				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+				 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+				 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+				 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+				 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+				 <&cpg CPG_MOD 1025>, <&cpg CPG_MOD 1026>,
+				 <&cpg CPG_MOD 1027>, <&cpg CPG_MOD 1028>,
+				 <&cpg CPG_MOD 1029>, <&cpg CPG_MOD 1030>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+				 <&audio_clka>, <&audio_clkb>, <&audio_clkc>,
+				 <&cpg CPG_CORE R8A7745_CLK_M2>;
+			clock-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0",
+				      "src.6", "src.5", "src.4", "src.3",
+				      "src.2", "src.1",
+				      "ctu.0", "ctu.1",
+				      "mix.0", "mix.1",
+				      "dvc.0", "dvc.1",
+				      "clk_a", "clk_b", "clk_c", "clk_i";
 			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 703>;
-			status = "disabled";
-
-			bus-range = <0 0>;
-			#address-cells = <3>;
-			#size-cells = <2>;
-			#interrupt-cells = <1>;
-			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
-			interrupt-map-mask = <0xff00 0 0 0x7>;
-			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-
-			usb@1,0 {
-				reg = <0x800 0 0 0 0>;
-				phys = <&usb0 0>;
-				phy-names = "usb";
-			};
-
-			usb@2,0 {
-				reg = <0x1000 0 0 0 0>;
-				phys = <&usb0 0>;
-				phy-names = "usb";
-			};
-		};
-
-		pci1: pci@ee0d0000 {
-			compatible = "renesas,pci-r8a7745",
-				     "renesas,pci-rcar-gen2";
-			device_type = "pci";
-			reg = <0 0xee0d0000 0 0xc00>,
-			      <0 0xee0c0000 0 0x1100>;
-			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 703>;
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 703>;
-			status = "disabled";
-
-			bus-range = <1 1>;
-			#address-cells = <3>;
-			#size-cells = <2>;
-			#interrupt-cells = <1>;
-			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
-			interrupt-map-mask = <0xff00 0 0 0x7>;
-			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-
-			usb@1,0 {
-				reg = <0x10800 0 0 0 0>;
-				phys = <&usb2 0>;
-				phy-names = "usb";
-			};
-
-			usb@2,0 {
-				reg = <0x11000 0 0 0 0>;
-				phys = <&usb2 0>;
-				phy-names = "usb";
-			};
-		};
-
-		hsusb: usb@e6590000 {
-			compatible = "renesas,usbhs-r8a7745",
-				     "renesas,rcar-gen2-usbhs";
-			reg = <0 0xe6590000 0 0x100>;
-			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 704>;
-			dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
-			       <&usb_dmac1 0>, <&usb_dmac1 1>;
-			dma-names = "ch0", "ch1", "ch2", "ch3";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 704>;
-			renesas,buswait = <4>;
-			phys = <&usb0 1>;
-			phy-names = "usb";
-			status = "disabled";
-		};
-
-		usbphy: usb-phy@e6590100 {
-			compatible = "renesas,usb-phy-r8a7745",
-				     "renesas,rcar-gen2-usb-phy";
-			reg = <0 0xe6590100 0 0x100>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			clocks = <&cpg CPG_MOD 704>;
-			clock-names = "usbhs";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 704>;
-			status = "disabled";
-
-			usb0: usb-channel@0 {
-				reg = <0>;
-				#phy-cells = <1>;
-			};
-			usb2: usb-channel@2 {
-				reg = <2>;
-				#phy-cells = <1>;
-			};
-		};
-
-		can0: can@e6e80000 {
-			compatible = "renesas,can-r8a7745",
-				     "renesas,rcar-gen2-can";
-			reg = <0 0xe6e80000 0 0x1000>;
-			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 916>,
-				 <&cpg CPG_CORE R8A7745_CLK_RCAN>,
-				 <&can_clk>;
-			clock-names = "clkp1", "clkp2", "can_clk";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 916>;
-			status = "disabled";
-		};
-
-		can1: can@e6e88000 {
-			compatible = "renesas,can-r8a7745",
-				     "renesas,rcar-gen2-can";
-			reg = <0 0xe6e88000 0 0x1000>;
-			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 915>,
-				 <&cpg CPG_CORE R8A7745_CLK_RCAN>,
-				 <&can_clk>;
-			clock-names = "clkp1", "clkp2", "can_clk";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 915>;
-			status = "disabled";
-		};
-
-		rcar_sound: sound@ec500000 {
-			/*
-			 * #sound-dai-cells is required
-			 *
-			 * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>;
-			 * Multi  DAI : #sound-dai-cells = <1>; <&rcar_sound N>;
-			 */
-			compatible = "renesas,rcar_sound-r8a7745",
-				     "renesas,rcar_sound-gen2";
-			reg = <0 0xec500000 0 0x1000>, /* SCU */
-			      <0 0xec5a0000 0 0x100>,  /* ADG */
-			      <0 0xec540000 0 0x1000>, /* SSIU */
-			      <0 0xec541000 0 0x280>,  /* SSI */
-			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri */
-			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
-
-			clocks = <&cpg CPG_MOD 1005>,
-				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
-				 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
-				 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
-				 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
-				 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
-				 <&cpg CPG_MOD 1025>, <&cpg CPG_MOD 1026>,
-				 <&cpg CPG_MOD 1027>, <&cpg CPG_MOD 1028>,
-				 <&cpg CPG_MOD 1029>, <&cpg CPG_MOD 1030>,
-				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-				 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
-				 <&audio_clka>, <&audio_clkb>, <&audio_clkc>,
-				 <&cpg CPG_CORE R8A7745_CLK_M2>;
-			clock-names = "ssi-all",
-				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
-				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
-				      "ssi.1", "ssi.0",
-				      "src.6", "src.5", "src.4", "src.3",
-				      "src.2", "src.1",
-				      "ctu.0", "ctu.1",
-				      "mix.0", "mix.1",
-				      "dvc.0", "dvc.1",
-				      "clk_a", "clk_b", "clk_c", "clk_i";
-			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
-			resets = <&cpg 1005>,
-				 <&cpg 1006>, <&cpg 1007>, <&cpg 1008>,
-				 <&cpg 1009>, <&cpg 1010>, <&cpg 1011>,
-				 <&cpg 1012>, <&cpg 1013>, <&cpg 1014>,
-				 <&cpg 1015>;
-			reset-names = "ssi-all",
-				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
-				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
-				      "ssi.1", "ssi.0";
-
+			resets = <&cpg 1005>,
+				 <&cpg 1006>, <&cpg 1007>, <&cpg 1008>,
+				 <&cpg 1009>, <&cpg 1010>, <&cpg 1011>,
+				 <&cpg 1012>, <&cpg 1013>, <&cpg 1014>,
+				 <&cpg 1015>;
+			reset-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0";
+
 			status = "disabled";
 
 			rcar_sound,dvc {
@@ -1474,6 +1284,278 @@
 				};
 			};
 		};
+
+		audma0: dma-controller@ec700000 {
+			compatible = "renesas,dmac-r8a7745",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec700000 0 0x10000>;
+			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 502>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 502>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
+
+		pci0: pci@ee090000 {
+			compatible = "renesas,pci-r8a7745",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee090000 0 0xc00>,
+			      <0 0xee080000 0 0x1100>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x800 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+
+			usb@2,0 {
+				reg = <0x1000 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+		};
+
+		pci1: pci@ee0d0000 {
+			compatible = "renesas,pci-r8a7745",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee0d0000 0 0xc00>,
+			      <0 0xee0c0000 0 0x1100>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <1 1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x10800 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+
+			usb@2,0 {
+				reg = <0x11000 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+		};
+
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7745",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 314>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
+
+		sdhi1: sd@ee140000 {
+			compatible = "renesas,sdhi-r8a7745",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee140000 0 0x100>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 312>;
+			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+			       <&dmac1 0xc1>, <&dmac1 0xc2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 312>;
+			status = "disabled";
+		};
+
+		sdhi2: sd@ee160000 {
+			compatible = "renesas,sdhi-r8a7745",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee160000 0 0x100>;
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 311>;
+			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+			       <&dmac1 0xd3>, <&dmac1 0xd4>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 311>;
+			status = "disabled";
+		};
+
+		mmcif0: mmc@ee200000 {
+			compatible = "renesas,mmcif-r8a7745",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee200000 0 0x80>;
+			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 315>;
+			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
+			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 315>;
+			reg-io-width = <4>;
+			max-frequency = <97500000>;
+			status = "disabled";
+		};
+
+		ether: ethernet@ee700000 {
+			compatible = "renesas,ether-r8a7745",
+				     "renesas,rcar-gen2-ether";
+			reg = <0 0xee700000 0 0x400>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 813>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 813>;
+			phy-mode = "rmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>, <0 0xf1002000 0 0x2000>,
+			      <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
+
+		vsp@fe928000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe928000 0 0x8000>;
+			interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 131>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 131>;
+		};
+
+		vsp@fe930000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe930000 0 0x8000>;
+			interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 128>;
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 128>;
+		};
+
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7745";
+			reg = <0 0xfeb00000 0 0x40000>;
+			reg-names = "du";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>;
+			clock-names = "du.0", "du.1";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb0: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_rgb1: endpoint {
+					};
+				};
+			};
+		};
+
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
+		};
+
+		cmt0: timer@ffca0000 {
+			compatible = "renesas,r8a7745-cmt0",
+				     "renesas,rcar-gen2-cmt0";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 124>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 124>;
+			status = "disabled";
+		};
+
+		cmt1: timer@e6130000 {
+			compatible = "renesas,r8a7745-cmt1",
+				     "renesas,rcar-gen2-cmt1";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 329>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7745_PD_ALWAYS_ON>;
+			resets = <&cpg 329>;
+			status = "disabled";
+		};
 	};
 
 	timer {
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index f2ea632381e7..3c66366f7c55 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -51,8 +51,11 @@
 		serial0 = &scif0;
 		serial1 = &scifa1;
 		i2c8 = &gpioi2c1;
+		i2c9 = &gpioi2c2;
 		i2c10 = &i2cexio0;
 		i2c11 = &i2cexio1;
+		i2c12 = &i2chdmi;
+		i2c13 = &i2cpwr;
 	};
 
 	chosen {
@@ -244,6 +247,12 @@
 		};
 	};
 
+	cec_clock: cec-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <12000000>;
+	};
+
 	hdmi-out {
 		compatible = "hdmi-connector";
 		type = "a";
@@ -272,8 +281,18 @@
 		#size-cells = <0>;
 		compatible = "i2c-gpio";
 		status = "disabled";
-		sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 		scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	gpioi2c2: i2c-9 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio5 5 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio5 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 		i2c-gpio,delay-us = <5>;
 	};
 
@@ -308,6 +327,138 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 	};
+
+        /*
+         * IIC2 and I2C2 may be switched using pinmux.
+         * A fallback to GPIO is also provided.
+         */
+	i2chdmi: i2c-12 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&iic2>, <&i2c2>, <&gpioi2c2>;
+		i2c-bus-name = "i2c-hdmi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ak4643: codec@12 {
+			compatible = "asahi-kasei,ak4643";
+			#sound-dai-cells = <0>;
+			reg = <0x12>;
+		};
+
+		composite-in@20 {
+			compatible = "adi,adv7180";
+			reg = <0x20>;
+			remote = <&vin1>;
+
+			port {
+				adv7180: endpoint {
+					bus-width = <8>;
+					remote-endpoint = <&vin1ep0>;
+				};
+			};
+		};
+
+		hdmi@39 {
+			compatible = "adi,adv7511w";
+			reg = <0x39>;
+			interrupt-parent = <&gpio1>;
+			interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&cec_clock>;
+			clock-names = "cec";
+
+			adi,input-depth = <8>;
+			adi,input-colorspace = "rgb";
+			adi,input-clock = "1x";
+			adi,input-style = <1>;
+			adi,input-justification = "evenly";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7511_in: endpoint {
+						remote-endpoint = <&du_out_lvds0>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					adv7511_out: endpoint {
+						remote-endpoint = <&hdmi_con_out>;
+					};
+				};
+			};
+		};
+
+		hdmi-in@4c {
+			compatible = "adi,adv7612";
+			reg = <0x4c>;
+			interrupt-parent = <&gpio1>;
+			interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
+			default-input = <0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7612_in: endpoint {
+						remote-endpoint = <&hdmi_con_in>;
+					};
+				};
+
+				port@2 {
+					reg = <2>;
+					adv7612_out: endpoint {
+						remote-endpoint = <&vin0ep2>;
+					};
+				};
+			};
+		};
+	};
+
+	/*
+	 * IIC3 and I2C3 may be switched using pinmux.
+	 * IIC3/I2C3 does not appear to support fallback to GPIO.
+	 */
+	i2cpwr: i2c-13 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&iic3>, <&i2c3>;
+		i2c-bus-name = "i2c-pwr";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		pmic@58 {
+			compatible = "dlg,da9063";
+			reg = <0x58>;
+			interrupt-parent = <&irqc0>;
+			interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+			interrupt-controller;
+
+			rtc {
+				compatible = "dlg,da9063-rtc";
+			};
+
+			wdt {
+				compatible = "dlg,da9063-watchdog";
+			};
+		};
+
+		vdd_dvfs: regulator@68 {
+			compatible = "dlg,da9210";
+			reg = <0x68>;
+			interrupt-parent = <&irqc0>;
+			interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+	};
 };
 
 &du {
@@ -437,11 +588,21 @@
 		function = "iic1";
 	};
 
+	i2c2_pins: i2c2 {
+		groups = "i2c2";
+		function = "i2c2";
+	};
+
 	iic2_pins: iic2 {
 		groups = "iic2";
 		function = "iic2";
 	};
 
+	i2c3_pins: i2c3 {
+		groups = "i2c3";
+		function = "i2c3";
+	};
+
 	iic3_pins: iic3 {
 		groups = "iic3";
 		function = "iic3";
@@ -643,124 +804,28 @@
 	pinctrl-names = "i2c-exio1";
 };
 
-&iic2	{
-	status = "okay";
-	pinctrl-0 = <&iic2_pins>;
-	pinctrl-names = "default";
+&i2c2	{
+	pinctrl-0 = <&i2c2_pins>;
+	pinctrl-names = "i2c-hdmi";
 
 	clock-frequency = <100000>;
+};
 
-	ak4643: codec@12 {
-		compatible = "asahi-kasei,ak4643";
-		#sound-dai-cells = <0>;
-		reg = <0x12>;
-	};
-
-	composite-in@20 {
-		compatible = "adi,adv7180";
-		reg = <0x20>;
-		remote = <&vin1>;
-
-		port {
-			adv7180: endpoint {
-				bus-width = <8>;
-				remote-endpoint = <&vin1ep0>;
-			};
-		};
-	};
-
-	hdmi@39 {
-		compatible = "adi,adv7511w";
-		reg = <0x39>;
-		interrupt-parent = <&gpio1>;
-		interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
-
-		adi,input-depth = <8>;
-		adi,input-colorspace = "rgb";
-		adi,input-clock = "1x";
-		adi,input-style = <1>;
-		adi,input-justification = "evenly";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7511_in: endpoint {
-					remote-endpoint = <&du_out_lvds0>;
-				};
-			};
-
-			port@1 {
-				reg = <1>;
-				adv7511_out: endpoint {
-					remote-endpoint = <&hdmi_con_out>;
-				};
-			};
-		};
-	};
-
-	hdmi-in@4c {
-		compatible = "adi,adv7612";
-		reg = <0x4c>;
-		interrupt-parent = <&gpio1>;
-		interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
-		default-input = <0>;
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
+&iic2	{
+	pinctrl-0 = <&iic2_pins>;
+	pinctrl-names = "i2c-hdmi";
 
-			port@0 {
-				reg = <0>;
-				adv7612_in: endpoint {
-					remote-endpoint = <&hdmi_con_in>;
-				};
-			};
+	clock-frequency = <100000>;
+};
 
-			port@2 {
-				reg = <2>;
-				adv7612_out: endpoint {
-					remote-endpoint = <&vin0ep2>;
-				};
-			};
-		};
-	};
+&i2c3	{
+	pinctrl-0 = <&i2c3_pins>;
+	pinctrl-names = "i2c-pwr";
 };
 
-&iic3 {
-	pinctrl-names = "default";
+&iic3	{
 	pinctrl-0 = <&iic3_pins>;
-	status = "okay";
-
-	pmic@58 {
-		compatible = "dlg,da9063";
-		reg = <0x58>;
-		interrupt-parent = <&irqc0>;
-		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
-		interrupt-controller;
-
-		rtc {
-			compatible = "dlg,da9063-rtc";
-		};
-
-		wdt {
-			compatible = "dlg,da9063-watchdog";
-		};
-	};
-
-	vdd_dvfs: regulator@68 {
-		compatible = "dlg,da9210";
-		reg = <0x68>;
-		interrupt-parent = <&irqc0>;
-		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
-
-		regulator-min-microvolt = <1000000>;
-		regulator-max-microvolt = <1000000>;
-		regulator-boot-on;
-		regulator-always-on;
-	};
+	pinctrl-names = "i2c-pwr";
 };
 
 &pci0 {
@@ -852,6 +917,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &ssi1 {
 	shared-pin;
 };
diff --git a/arch/arm/boot/dts/r8a7790-stout.dts b/arch/arm/boot/dts/r8a7790-stout.dts
new file mode 100644
index 000000000000..a13a92c26645
--- /dev/null
+++ b/arch/arm/boot/dts/r8a7790-stout.dts
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the Stout board
+ *
+ * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+/dts-v1/;
+#include "r8a7790.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Stout";
+	compatible = "renesas,stout", "renesas,r8a7790";
+
+	aliases {
+		serial0 = &scifa0;
+	};
+
+	chosen {
+		bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+		stdout-path = "serial0:115200n8";
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0 0x40000000>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		led1 {
+			gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+		};
+		led2 {
+			gpios = <&gpio4 23 GPIO_ACTIVE_LOW>;
+		};
+		led3 {
+			gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+		};
+		led5 {
+			gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	fixedregulator3v3: regulator-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	vcc_sdhi0: regulator-vcc-sdhi0 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "SDHI0 Vcc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&gpio5 24 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	hdmi-out {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_out: endpoint {
+				remote-endpoint = <&adv7511_out>;
+			};
+		};
+	};
+
+	osc1_clk: osc1-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <148500000>;
+	};
+
+	osc4_clk: osc4-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <12000000>;
+	};
+};
+
+&du {
+	pinctrl-0 = <&du_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, <&cpg CPG_MOD 722>,
+		 <&cpg CPG_MOD 726>, <&cpg CPG_MOD 725>,
+		 <&osc1_clk>;
+	clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1", "dclkin.0";
+
+	ports {
+		port@0 {
+			endpoint {
+				remote-endpoint = <&adv7511_in>;
+			};
+		};
+		port@1 {
+			lvds_connector0: endpoint {
+			};
+		};
+		port@2 {
+			lvds_connector1: endpoint {
+			};
+		};
+	};
+};
+
+&extal_clk {
+	clock-frequency = <20000000>;
+};
+
+&pfc {
+
+	pinctrl-0 = <&scif_clk_pins>;
+	pinctrl-names = "default";
+
+	du_pins: du {
+		groups = "du_rgb888", "du_sync_1", "du_clk_out_0";
+		function = "du";
+	};
+
+	scifa0_pins: scifa0 {
+		groups = "scifa0_data_b";
+		function = "scifa0";
+	};
+
+	scif_clk_pins: scif_clk {
+		groups = "scif_clk";
+		function = "scif_clk";
+	};
+
+	ether_pins: ether {
+		groups = "eth_link", "eth_mdio", "eth_rmii";
+		function = "eth";
+	};
+
+	phy1_pins: phy1 {
+		groups = "intc_irq1";
+		function = "intc";
+	};
+
+	sdhi0_pins: sd0 {
+		groups = "sdhi0_data4", "sdhi0_ctrl";
+		function = "sdhi0";
+		power-source = <3300>;
+	};
+
+	qspi_pins: qspi {
+		groups = "qspi_ctrl", "qspi_data4";
+		function = "qspi";
+	};
+
+	iic2_pins: iic2 {
+		groups = "iic2_b";
+		function = "iic2";
+	};
+
+	iic3_pins: iic3 {
+		groups = "iic3";
+		function = "iic3";
+	};
+
+	usb0_pins: usb0 {
+		groups = "usb0";
+		function = "usb0";
+	};
+};
+
+&ether {
+	pinctrl-0 = <&ether_pins &phy1_pins>;
+	pinctrl-names = "default";
+
+	phy-handle = <&phy1>;
+	renesas,ether-link-active-low;
+	status = "okay";
+
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+		interrupt-parent = <&irqc0>;
+		interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+		micrel,led-mode = <1>;
+	};
+};
+
+&cmt0 {
+	status = "okay";
+};
+
+&qspi {
+	pinctrl-0 = <&qspi_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+
+	flash: flash@0 {
+		compatible = "spansion,s25fl512s", "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <30000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+		spi-cpha;
+		spi-cpol;
+		m25p,fast-read;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "loader";
+				reg = <0x00000000 0x00080000>;
+				read-only;
+			};
+			partition@80000 {
+				label = "uboot";
+				reg = <0x00080000 0x00040000>;
+				read-only;
+			};
+			partition@c0000 {
+				label = "uboot-env";
+				reg = <0x000c0000 0x00040000>;
+				read-only;
+			};
+			partition@100000 {
+				label = "flash";
+				reg = <0x00100000 0x03f00000>;
+			};
+		};
+	};
+};
+
+&scifa0 {
+	pinctrl-0 = <&scifa0_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+};
+
+&scif_clk {
+	clock-frequency = <14745600>;
+};
+
+&sdhi0 {
+	pinctrl-0 = <&sdhi0_pins>;
+	pinctrl-names = "default";
+
+	vmmc-supply = <&vcc_sdhi0>;
+	cd-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&cpu0 {
+	cpu0-supply = <&vdd_dvfs>;
+};
+
+&iic2	{
+	status = "okay";
+	pinctrl-0 = <&iic2_pins>;
+	pinctrl-names = "default";
+
+	clock-frequency = <100000>;
+
+	hdmi@39 {
+		compatible = "adi,adv7511w";
+		reg = <0x39>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&osc4_clk>;
+		clock-names = "cec";
+
+		adi,input-depth = <8>;
+		adi,input-colorspace = "rgb";
+		adi,input-clock = "1x";
+		adi,input-style = <1>;
+		adi,input-justification = "evenly";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				adv7511_in: endpoint {
+					remote-endpoint = <&du_out_rgb>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				adv7511_out: endpoint {
+					remote-endpoint = <&hdmi_con_out>;
+				};
+			};
+		};
+	};
+};
+
+&iic3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&iic3_pins>;
+	status = "okay";
+
+	pmic@58 {
+		compatible = "dlg,da9063";
+		reg = <0x58>;
+		interrupt-parent = <&irqc0>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-controller;
+
+		rtc {
+			compatible = "dlg,da9063-rtc";
+		};
+
+		wdt {
+			compatible = "dlg,da9063-watchdog";
+		};
+	};
+
+	vdd_dvfs: regulator@68 {
+		compatible = "dlg,da9210";
+		reg = <0x68>;
+		interrupt-parent = <&irqc0>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	vdd: regulator@70 {
+		compatible = "dlg,da9210";
+		reg = <0x70>;
+		interrupt-parent = <&irqc0>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&pci0 {
+	status = "okay";
+	pinctrl-0 = <&usb0_pins>;
+	pinctrl-names = "default";
+};
+
+&usbphy {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index ed9a68538a55..7ba62b7aa0ba 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -17,7 +17,6 @@
 
 / {
 	compatible = "renesas,r8a7790";
-	interrupt-parent = <&gic>;
 	#address-cells = <2>;
 	#size-cells = <2>;
 
@@ -41,6 +40,35 @@
 		vin3 = &vin3;
 	};
 
+	/*
+	 * The external audio clocks are configured as 0 Hz fixed frequency
+	 * clocks by default.
+	 * Boards that provide audio clocks should override them.
+	 */
+	audio_clk_a: audio_clk_a {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clk_b: audio_clk_b {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clk_c: audio_clk_c {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+
+	/* External CAN clock */
+	can_clk: can {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -159,1510 +187,1563 @@
 		};
 	};
 
-	thermal-zones {
-		cpu_thermal: cpu-thermal {
-			polling-delay-passive	= <0>;
-			polling-delay		= <0>;
-
-			thermal-sensors = <&thermal>;
-
-			trips {
-				cpu-crit {
-					temperature	= <95000>;
-					hysteresis	= <0>;
-					type		= "critical";
-				};
-			};
-			cooling-maps {
-			};
-		};
-	};
-
-	apmu@e6151000 {
-		compatible = "renesas,r8a7790-apmu", "renesas,apmu";
-		reg = <0 0xe6151000 0 0x188>;
-		cpus = <&cpu4 &cpu5 &cpu6 &cpu7>;
+	/* External root clock */
+	extal_clk: extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	apmu@e6152000 {
-		compatible = "renesas,r8a7790-apmu", "renesas,apmu";
-		reg = <0 0xe6152000 0 0x188>;
-		cpus = <&cpu0 &cpu1 &cpu2 &cpu3>;
+	/* External PCIe clock - can be overridden by the board */
+	pcie_bus_clk: pcie_bus {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
 	};
 
-	gic: interrupt-controller@f1001000 {
-		compatible = "arm,gic-400";
-		#interrupt-cells = <3>;
-		#address-cells = <0>;
-		interrupt-controller;
-		reg = <0 0xf1001000 0 0x1000>,
-			<0 0xf1002000 0 0x2000>,
-			<0 0xf1004000 0 0x2000>,
-			<0 0xf1006000 0 0x2000>;
-		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
-		clocks = <&cpg CPG_MOD 408>;
-		clock-names = "clk";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 408>;
+	/* External SCIF clock */
+	scif_clk: scif {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	gpio0: gpio@e6050000 {
-		compatible = "renesas,gpio-r8a7790", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6050000 0 0x50>;
-		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 0 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 912>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 912>;
-	};
+	soc {
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
 
-	gpio1: gpio@e6051000 {
-		compatible = "renesas,gpio-r8a7790", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6051000 0 0x50>;
-		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 32 30>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 911>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 911>;
-	};
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7790-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 402>;
+			status = "disabled";
+		};
 
-	gpio2: gpio@e6052000 {
-		compatible = "renesas,gpio-r8a7790", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6052000 0 0x50>;
-		interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 64 30>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 910>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 910>;
-	};
+		gpio0: gpio@e6050000 {
+			compatible = "renesas,gpio-r8a7790",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6050000 0 0x50>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 0 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 912>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 912>;
+		};
 
-	gpio3: gpio@e6053000 {
-		compatible = "renesas,gpio-r8a7790", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6053000 0 0x50>;
-		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 96 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 909>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 909>;
-	};
+		gpio1: gpio@e6051000 {
+			compatible = "renesas,gpio-r8a7790",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6051000 0 0x50>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 32 30>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 911>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 911>;
+		};
 
-	gpio4: gpio@e6054000 {
-		compatible = "renesas,gpio-r8a7790", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6054000 0 0x50>;
-		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 128 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 908>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 908>;
-	};
+		gpio2: gpio@e6052000 {
+			compatible = "renesas,gpio-r8a7790",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6052000 0 0x50>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 64 30>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 910>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 910>;
+		};
 
-	gpio5: gpio@e6055000 {
-		compatible = "renesas,gpio-r8a7790", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055000 0 0x50>;
-		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 160 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 907>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 907>;
-	};
+		gpio3: gpio@e6053000 {
+			compatible = "renesas,gpio-r8a7790",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6053000 0 0x50>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 96 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 909>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 909>;
+		};
 
-	thermal: thermal@e61f0000 {
-		compatible =	"renesas,thermal-r8a7790",
-				"renesas,rcar-gen2-thermal",
-				"renesas,rcar-thermal";
-		reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>;
-		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 522>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 522>;
-		#thermal-sensor-cells = <0>;
-	};
+		gpio4: gpio@e6054000 {
+			compatible = "renesas,gpio-r8a7790",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6054000 0 0x50>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 128 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 908>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 908>;
+		};
 
-	timer {
-		compatible = "arm,armv7-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
-	};
+		gpio5: gpio@e6055000 {
+			compatible = "renesas,gpio-r8a7790",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055000 0 0x50>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 160 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 907>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 907>;
+		};
 
-	cmt0: timer@ffca0000 {
-		compatible = "renesas,r8a7790-cmt0", "renesas,rcar-gen2-cmt0";
-		reg = <0 0xffca0000 0 0x1004>;
-		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 124>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 124>;
-
-		status = "disabled";
-	};
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7790";
+			reg = <0 0xe6060000 0 0x250>;
+		};
 
-	cmt1: timer@e6130000 {
-		compatible = "renesas,r8a7790-cmt1", "renesas,rcar-gen2-cmt1";
-		reg = <0 0xe6130000 0 0x1004>;
-		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 329>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 329>;
-
-		status = "disabled";
-	};
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a7790-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>, <&usb_extal_clk>;
+			clock-names = "extal", "usb_extal";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
 
-	irqc0: interrupt-controller@e61c0000 {
-		compatible = "renesas,irqc-r8a7790", "renesas,irqc";
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0 0xe61c0000 0 0x200>;
-		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 407>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 407>;
-	};
+		apmu@e6151000 {
+			compatible = "renesas,r8a7790-apmu", "renesas,apmu";
+			reg = <0 0xe6151000 0 0x188>;
+			cpus = <&cpu4 &cpu5 &cpu6 &cpu7>;
+		};
 
-	dmac0: dma-controller@e6700000 {
-		compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
-		reg = <0 0xe6700000 0 0x20000>;
-		interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 219>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 219>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		apmu@e6152000 {
+			compatible = "renesas,r8a7790-apmu", "renesas,apmu";
+			reg = <0 0xe6152000 0 0x188>;
+			cpus = <&cpu0 &cpu1 &cpu2 &cpu3>;
+		};
 
-	dmac1: dma-controller@e6720000 {
-		compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
-		reg = <0 0xe6720000 0 0x20000>;
-		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 218>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 218>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a7790-rst";
+			reg = <0 0xe6160000 0 0x0100>;
+		};
 
-	audma0: dma-controller@ec700000 {
-		compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
-		reg = <0 0xec700000 0 0x10000>;
-		interrupts =	<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12";
-		clocks = <&cpg CPG_MOD 502>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 502>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a7790-sysc";
+			reg = <0 0xe6180000 0 0x0200>;
+			#power-domain-cells = <1>;
+		};
 
-	audma1: dma-controller@ec720000 {
-		compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
-		reg = <0 0xec720000 0 0x10000>;
-		interrupts =	<GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12";
-		clocks = <&cpg CPG_MOD 501>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 501>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		irqc0: interrupt-controller@e61c0000 {
+			compatible = "renesas,irqc-r8a7790", "renesas,irqc";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0 0xe61c0000 0 0x200>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 407>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 407>;
+		};
 
-	usb_dmac0: dma-controller@e65a0000 {
-		compatible = "renesas,r8a7790-usb-dmac", "renesas,usb-dmac";
-		reg = <0 0xe65a0000 0 0x100>;
-		interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "ch0", "ch1";
-		clocks = <&cpg CPG_MOD 330>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 330>;
-		#dma-cells = <1>;
-		dma-channels = <2>;
-	};
+		thermal: thermal@e61f0000 {
+			compatible = "renesas,thermal-r8a7790",
+				     "renesas,rcar-gen2-thermal",
+				     "renesas,rcar-thermal";
+			reg = <0 0xe61f0000 0 0x10>, <0 0xe61f0100 0 0x38>;
+			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 522>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 522>;
+			#thermal-sensor-cells = <0>;
+		};
 
-	usb_dmac1: dma-controller@e65b0000 {
-		compatible = "renesas,r8a7790-usb-dmac", "renesas,usb-dmac";
-		reg = <0 0xe65b0000 0 0x100>;
-		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "ch0", "ch1";
-		clocks = <&cpg CPG_MOD 331>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 331>;
-		#dma-cells = <1>;
-		dma-channels = <2>;
-	};
+		ipmmu_sy0: mmu@e6280000 {
+			compatible = "renesas,ipmmu-r8a7790",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6280000 0 0x1000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c0: i2c@e6508000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7790", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6508000 0 0x40>;
-		interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 931>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 931>;
-		i2c-scl-internal-delay-ns = <110>;
-		status = "disabled";
-	};
+		ipmmu_sy1: mmu@e6290000 {
+			compatible = "renesas,ipmmu-r8a7790",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6290000 0 0x1000>;
+			interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c1: i2c@e6518000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7790", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6518000 0 0x40>;
-		interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 930>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 930>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_ds: mmu@e6740000 {
+			compatible = "renesas,ipmmu-r8a7790",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6740000 0 0x1000>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c2: i2c@e6530000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7790", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6530000 0 0x40>;
-		interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 929>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 929>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_mp: mmu@ec680000 {
+			compatible = "renesas,ipmmu-r8a7790",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xec680000 0 0x1000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c3: i2c@e6540000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7790", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6540000 0 0x40>;
-		interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 928>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 928>;
-		i2c-scl-internal-delay-ns = <110>;
-		status = "disabled";
-	};
+		ipmmu_mx: mmu@fe951000 {
+			compatible = "renesas,ipmmu-r8a7790",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xfe951000 0 0x1000>;
+			interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	iic0: i2c@e6500000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6500000 0 0x425>;
-		interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 318>;
-		dmas = <&dmac0 0x61>, <&dmac0 0x62>,
-		       <&dmac1 0x61>, <&dmac1 0x62>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 318>;
-		status = "disabled";
-	};
+		ipmmu_rt: mmu@ffc80000 {
+			compatible = "renesas,ipmmu-r8a7790",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xffc80000 0 0x1000>;
+			interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	iic1: i2c@e6510000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6510000 0 0x425>;
-		interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 323>;
-		dmas = <&dmac0 0x65>, <&dmac0 0x66>,
-		       <&dmac1 0x65>, <&dmac1 0x66>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 323>;
-		status = "disabled";
-	};
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
+		};
 
-	iic2: i2c@e6520000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6520000 0 0x425>;
-		interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 300>;
-		dmas = <&dmac0 0x69>, <&dmac0 0x6a>,
-		       <&dmac1 0x69>, <&dmac1 0x6a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 300>;
-		status = "disabled";
-	};
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
 
-	iic3: i2c@e60b0000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe60b0000 0 0x425>;
-		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 926>;
-		dmas = <&dmac0 0x77>, <&dmac0 0x78>,
-		       <&dmac1 0x77>, <&dmac1 0x78>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 926>;
-		status = "disabled";
-	};
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
+		};
 
-	mmcif0: mmc@ee200000 {
-		compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif";
-		reg = <0 0xee200000 0 0x80>;
-		interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 315>;
-		dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
-		       <&dmac1 0xd1>, <&dmac1 0xd2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 315>;
-		reg-io-width = <4>;
-		status = "disabled";
-		max-frequency = <97500000>;
-	};
+		i2c0: i2c@e6508000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7790",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 931>;
+			i2c-scl-internal-delay-ns = <110>;
+			status = "disabled";
+		};
 
-	mmcif1: mmc@ee220000 {
-		compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif";
-		reg = <0 0xee220000 0 0x80>;
-		interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 305>;
-		dmas = <&dmac0 0xe1>, <&dmac0 0xe2>,
-		       <&dmac1 0xe1>, <&dmac1 0xe2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 305>;
-		reg-io-width = <4>;
-		status = "disabled";
-		max-frequency = <97500000>;
-	};
+		i2c1: i2c@e6518000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7790",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 930>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	pfc: pin-controller@e6060000 {
-		compatible = "renesas,pfc-r8a7790";
-		reg = <0 0xe6060000 0 0x250>;
-	};
+		i2c2: i2c@e6530000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7790",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 929>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	sdhi0: sd@ee100000 {
-		compatible = "renesas,sdhi-r8a7790",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee100000 0 0x328>;
-		interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 314>;
-		dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-		       <&dmac1 0xcd>, <&dmac1 0xce>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <195000000>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 314>;
-		status = "disabled";
-	};
+		i2c3: i2c@e6540000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7790",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6540000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 928>;
+			i2c-scl-internal-delay-ns = <110>;
+			status = "disabled";
+		};
 
-	sdhi1: sd@ee120000 {
-		compatible = "renesas,sdhi-r8a7790",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee120000 0 0x328>;
-		interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 313>;
-		dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
-		       <&dmac1 0xc9>, <&dmac1 0xca>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <195000000>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 313>;
-		status = "disabled";
-	};
+		iic0: i2c@e6500000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7790",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6500000 0 0x425>;
+			interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 318>;
+			dmas = <&dmac0 0x61>, <&dmac0 0x62>,
+			       <&dmac1 0x61>, <&dmac1 0x62>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 318>;
+			status = "disabled";
+		};
 
-	sdhi2: sd@ee140000 {
-		compatible = "renesas,sdhi-r8a7790",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee140000 0 0x100>;
-		interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 312>;
-		dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-		       <&dmac1 0xc1>, <&dmac1 0xc2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 312>;
-		status = "disabled";
-	};
+		iic1: i2c@e6510000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7790",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6510000 0 0x425>;
+			interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 323>;
+			dmas = <&dmac0 0x65>, <&dmac0 0x66>,
+			       <&dmac1 0x65>, <&dmac1 0x66>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 323>;
+			status = "disabled";
+		};
 
-	sdhi3: sd@ee160000 {
-		compatible = "renesas,sdhi-r8a7790",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee160000 0 0x100>;
-		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 311>;
-		dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-		       <&dmac1 0xd3>, <&dmac1 0xd4>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 311>;
-		status = "disabled";
-	};
+		iic2: i2c@e6520000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7790",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6520000 0 0x425>;
+			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 300>;
+			dmas = <&dmac0 0x69>, <&dmac0 0x6a>,
+			       <&dmac1 0x69>, <&dmac1 0x6a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 300>;
+			status = "disabled";
+		};
 
-	scifa0: serial@e6c40000 {
-		compatible = "renesas,scifa-r8a7790",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c40000 0 64>;
-		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 204>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x21>, <&dmac0 0x22>,
-		       <&dmac1 0x21>, <&dmac1 0x22>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 204>;
-		status = "disabled";
-	};
+		iic3: i2c@e60b0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7790",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe60b0000 0 0x425>;
+			interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 926>;
+			dmas = <&dmac0 0x77>, <&dmac0 0x78>,
+			       <&dmac1 0x77>, <&dmac1 0x78>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 926>;
+			status = "disabled";
+		};
 
-	scifa1: serial@e6c50000 {
-		compatible = "renesas,scifa-r8a7790",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c50000 0 64>;
-		interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 203>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x25>, <&dmac0 0x26>,
-		       <&dmac1 0x25>, <&dmac1 0x26>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 203>;
-		status = "disabled";
-	};
+		hsusb: usb@e6590000 {
+			compatible = "renesas,usbhs-r8a7790",
+				     "renesas,rcar-gen2-usbhs";
+			reg = <0 0xe6590000 0 0x100>;
+			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 704>;
+			dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+			       <&usb_dmac1 0>, <&usb_dmac1 1>;
+			dma-names = "ch0", "ch1", "ch2", "ch3";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			renesas,buswait = <4>;
+			phys = <&usb0 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
 
-	scifa2: serial@e6c60000 {
-		compatible = "renesas,scifa-r8a7790",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c60000 0 64>;
-		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 202>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x27>, <&dmac0 0x28>,
-		       <&dmac1 0x27>, <&dmac1 0x28>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 202>;
-		status = "disabled";
-	};
+		usbphy: usb-phy@e6590100 {
+			compatible = "renesas,usb-phy-r8a7790",
+				     "renesas,rcar-gen2-usb-phy";
+			reg = <0 0xe6590100 0 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&cpg CPG_MOD 704>;
+			clock-names = "usbhs";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			status = "disabled";
 
-	scifb0: serial@e6c20000 {
-		compatible = "renesas,scifb-r8a7790",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c20000 0 0x100>;
-		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 206>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
-		       <&dmac1 0x3d>, <&dmac1 0x3e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 206>;
-		status = "disabled";
-	};
+			usb0: usb-channel@0 {
+				reg = <0>;
+				#phy-cells = <1>;
+			};
+			usb2: usb-channel@2 {
+				reg = <2>;
+				#phy-cells = <1>;
+			};
+		};
 
-	scifb1: serial@e6c30000 {
-		compatible = "renesas,scifb-r8a7790",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c30000 0 0x100>;
-		interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 207>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
-		       <&dmac1 0x19>, <&dmac1 0x1a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 207>;
-		status = "disabled";
-	};
+		usb_dmac0: dma-controller@e65a0000 {
+			compatible = "renesas,r8a7790-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65a0000 0 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 330>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 330>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
+		};
 
-	scifb2: serial@e6ce0000 {
-		compatible = "renesas,scifb-r8a7790",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6ce0000 0 0x100>;
-		interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 216>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
-		       <&dmac1 0x1d>, <&dmac1 0x1e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 216>;
-		status = "disabled";
-	};
+		usb_dmac1: dma-controller@e65b0000 {
+			compatible = "renesas,r8a7790-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65b0000 0 0x100>;
+			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 331>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 331>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
+		};
 
-	scif0: serial@e6e60000 {
-		compatible = "renesas,scif-r8a7790", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e60000 0 64>;
-		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7790_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
-		       <&dmac1 0x29>, <&dmac1 0x2a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 721>;
-		status = "disabled";
-	};
+		dmac0: dma-controller@e6700000 {
+			compatible = "renesas,dmac-r8a7790",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6700000 0 0x20000>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 219>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 219>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	scif1: serial@e6e68000 {
-		compatible = "renesas,scif-r8a7790", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e68000 0 64>;
-		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7790_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
-		       <&dmac1 0x2d>, <&dmac1 0x2e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 720>;
-		status = "disabled";
-	};
+		dmac1: dma-controller@e6720000 {
+			compatible = "renesas,dmac-r8a7790",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6720000 0 0x20000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	scif2: serial@e6e56000 {
-		compatible = "renesas,scif-r8a7790", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e56000 0 64>;
-		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 310>, <&cpg CPG_CORE R8A7790_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
-		       <&dmac1 0x2b>, <&dmac1 0x2c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 310>;
-		status = "disabled";
-	};
+		avb: ethernet@e6800000 {
+			compatible = "renesas,etheravb-r8a7790",
+				     "renesas,etheravb-rcar-gen2";
+			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 812>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 812>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	hscif0: serial@e62c0000 {
-		compatible = "renesas,hscif-r8a7790",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c0000 0 96>;
-		interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 717>, <&cpg CPG_CORE R8A7790_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
-		       <&dmac1 0x39>, <&dmac1 0x3a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 717>;
-		status = "disabled";
-	};
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7790", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 917>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	hscif1: serial@e62c8000 {
-		compatible = "renesas,hscif-r8a7790",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c8000 0 96>;
-		interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 716>, <&cpg CPG_CORE R8A7790_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
-		       <&dmac1 0x4d>, <&dmac1 0x4e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 716>;
-		status = "disabled";
-	};
+		scifa0: serial@e6c40000 {
+			compatible = "renesas,scifa-r8a7790",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c40000 0 64>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 204>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x21>, <&dmac0 0x22>,
+			       <&dmac1 0x21>, <&dmac1 0x22>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 204>;
+			status = "disabled";
+		};
 
-	icram0:	sram@e63a0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63a0000 0 0x12000>;
-	};
+		scifa1: serial@e6c50000 {
+			compatible = "renesas,scifa-r8a7790",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c50000 0 64>;
+			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 203>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x25>, <&dmac0 0x26>,
+			       <&dmac1 0x25>, <&dmac1 0x26>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 203>;
+			status = "disabled";
+		};
 
-	icram1:	sram@e63c0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63c0000 0 0x1000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0 0xe63c0000 0x1000>;
+		scifa2: serial@e6c60000 {
+			compatible = "renesas,scifa-r8a7790",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c60000 0 64>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 202>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x27>, <&dmac0 0x28>,
+			       <&dmac1 0x27>, <&dmac1 0x28>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 202>;
+			status = "disabled";
+		};
 
-		smp-sram@0 {
-			compatible = "renesas,smp-sram";
-			reg = <0 0x10>;
+		scifb0: serial@e6c20000 {
+			compatible = "renesas,scifb-r8a7790",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c20000 0 0x100>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 206>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
+			       <&dmac1 0x3d>, <&dmac1 0x3e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 206>;
+			status = "disabled";
 		};
-	};
 
-	ether: ethernet@ee700000 {
-		compatible = "renesas,ether-r8a7790",
-			     "renesas,rcar-gen2-ether";
-		reg = <0 0xee700000 0 0x400>;
-		interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 813>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 813>;
-		phy-mode = "rmii";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scifb1: serial@e6c30000 {
+			compatible = "renesas,scifb-r8a7790",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c30000 0 0x100>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 207>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
+			       <&dmac1 0x19>, <&dmac1 0x1a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 207>;
+			status = "disabled";
+		};
 
-	avb: ethernet@e6800000 {
-		compatible = "renesas,etheravb-r8a7790",
-			     "renesas,etheravb-rcar-gen2";
-		reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
-		interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 812>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 812>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scifb2: serial@e6ce0000 {
+			compatible = "renesas,scifb-r8a7790",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6ce0000 0 0x100>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 216>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
+			       <&dmac1 0x1d>, <&dmac1 0x1e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 216>;
+			status = "disabled";
+		};
 
-	sata0: sata@ee300000 {
-		compatible = "renesas,sata-r8a7790", "renesas,rcar-gen2-sata";
-		reg = <0 0xee300000 0 0x2000>;
-		interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 815>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 815>;
-		status = "disabled";
-	};
+		scif0: serial@e6e60000 {
+			compatible = "renesas,scif-r8a7790",
+				     "renesas,rcar-gen2-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e60000 0 64>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 721>,
+				 <&cpg CPG_CORE R8A7790_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
+			       <&dmac1 0x29>, <&dmac1 0x2a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 721>;
+			status = "disabled";
+		};
 
-	sata1: sata@ee500000 {
-		compatible = "renesas,sata-r8a7790", "renesas,rcar-gen2-sata";
-		reg = <0 0xee500000 0 0x2000>;
-		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 814>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 814>;
-		status = "disabled";
-	};
+		scif1: serial@e6e68000 {
+			compatible = "renesas,scif-r8a7790",
+				     "renesas,rcar-gen2-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e68000 0 64>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 720>,
+				 <&cpg CPG_CORE R8A7790_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
+			       <&dmac1 0x2d>, <&dmac1 0x2e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 720>;
+			status = "disabled";
+		};
 
-	hsusb: usb@e6590000 {
-		compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs";
-		reg = <0 0xe6590000 0 0x100>;
-		interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 704>;
-		dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
-		       <&usb_dmac1 0>, <&usb_dmac1 1>;
-		dma-names = "ch0", "ch1", "ch2", "ch3";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 704>;
-		renesas,buswait = <4>;
-		phys = <&usb0 1>;
-		phy-names = "usb";
-		status = "disabled";
-	};
+		scif2: serial@e6e56000 {
+			compatible = "renesas,scif-r8a7790",
+				     "renesas,rcar-gen2-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e56000 0 64>;
+			interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 310>,
+				 <&cpg CPG_CORE R8A7790_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
+			       <&dmac1 0x2b>, <&dmac1 0x2c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 310>;
+			status = "disabled";
+		};
 
-	usbphy: usb-phy@e6590100 {
-		compatible = "renesas,usb-phy-r8a7790",
-			     "renesas,rcar-gen2-usb-phy";
-		reg = <0 0xe6590100 0 0x100>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&cpg CPG_MOD 704>;
-		clock-names = "usbhs";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 704>;
-		status = "disabled";
+		hscif0: serial@e62c0000 {
+			compatible = "renesas,hscif-r8a7790",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c0000 0 96>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 717>,
+				 <&cpg CPG_CORE R8A7790_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
+			       <&dmac1 0x39>, <&dmac1 0x3a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 717>;
+			status = "disabled";
+		};
 
-		usb0: usb-channel@0 {
-			reg = <0>;
-			#phy-cells = <1>;
+		hscif1: serial@e62c8000 {
+			compatible = "renesas,hscif-r8a7790",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c8000 0 96>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 716>,
+				 <&cpg CPG_CORE R8A7790_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
+			       <&dmac1 0x4d>, <&dmac1 0x4e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 716>;
+			status = "disabled";
 		};
-		usb2: usb-channel@2 {
-			reg = <2>;
-			#phy-cells = <1>;
+
+		msiof0: spi@e6e20000 {
+			compatible = "renesas,msiof-r8a7790",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e20000 0 0x0064>;
+			interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 0>;
+			dmas = <&dmac0 0x51>, <&dmac0 0x52>,
+			       <&dmac1 0x51>, <&dmac1 0x52>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
 		};
-	};
 
-	vin0: video@e6ef0000 {
-		compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef0000 0 0x1000>;
-		interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 811>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 811>;
-		status = "disabled";
-	};
+		msiof1: spi@e6e10000 {
+			compatible = "renesas,msiof-r8a7790",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e10000 0 0x0064>;
+			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 208>;
+			dmas = <&dmac0 0x55>, <&dmac0 0x56>,
+			       <&dmac1 0x55>, <&dmac1 0x56>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 208>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	vin1: video@e6ef1000 {
-		compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef1000 0 0x1000>;
-		interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 810>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 810>;
-		status = "disabled";
-	};
+		msiof2: spi@e6e00000 {
+			compatible = "renesas,msiof-r8a7790",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e00000 0 0x0064>;
+			interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 205>;
+			dmas = <&dmac0 0x41>, <&dmac0 0x42>,
+			       <&dmac1 0x41>, <&dmac1 0x42>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 205>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	vin2: video@e6ef2000 {
-		compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef2000 0 0x1000>;
-		interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 809>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 809>;
-		status = "disabled";
-	};
+		msiof3: spi@e6c90000 {
+			compatible = "renesas,msiof-r8a7790",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6c90000 0 0x0064>;
+			interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 215>;
+			dmas = <&dmac0 0x45>, <&dmac0 0x46>,
+			       <&dmac1 0x45>, <&dmac1 0x46>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 215>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	vin3: video@e6ef3000 {
-		compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef3000 0 0x1000>;
-		interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 808>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 808>;
-		status = "disabled";
-	};
+		can0: can@e6e80000 {
+			compatible = "renesas,can-r8a7790",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e80000 0 0x1000>;
+			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 916>,
+				 <&cpg CPG_CORE R8A7790_CLK_RCAN>, <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 916>;
+			status = "disabled";
+		};
 
-	vsp@fe920000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe920000 0 0x8000>;
-		interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 130>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 130>;
-	};
+		can1: can@e6e88000 {
+			compatible = "renesas,can-r8a7790",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e88000 0 0x1000>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 915>,
+				 <&cpg CPG_CORE R8A7790_CLK_RCAN>, <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 915>;
+			status = "disabled";
+		};
 
-	vsp@fe928000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe928000 0 0x8000>;
-		interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 131>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 131>;
-	};
+		vin0: video@e6ef0000 {
+			compatible = "renesas,vin-r8a7790",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef0000 0 0x1000>;
+			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 811>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 811>;
+			status = "disabled";
+		};
 
-	vsp@fe930000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe930000 0 0x8000>;
-		interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 128>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 128>;
-	};
+		vin1: video@e6ef1000 {
+			compatible = "renesas,vin-r8a7790",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef1000 0 0x1000>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 810>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 810>;
+			status = "disabled";
+		};
 
-	vsp@fe938000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe938000 0 0x8000>;
-		interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 127>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 127>;
-	};
+		vin2: video@e6ef2000 {
+			compatible = "renesas,vin-r8a7790",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef2000 0 0x1000>;
+			interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 809>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 809>;
+			status = "disabled";
+		};
 
-	du: display@feb00000 {
-		compatible = "renesas,du-r8a7790";
-		reg = <0 0xfeb00000 0 0x70000>,
-		      <0 0xfeb90000 0 0x1c>,
-		      <0 0xfeb94000 0 0x1c>;
-		reg-names = "du", "lvds.0", "lvds.1";
-		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>,
-			 <&cpg CPG_MOD 722>, <&cpg CPG_MOD 726>,
-			 <&cpg CPG_MOD 725>;
-		clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
-		status = "disabled";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
+		vin3: video@e6ef3000 {
+			compatible = "renesas,vin-r8a7790",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef3000 0 0x1000>;
+			interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 808>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 808>;
+			status = "disabled";
+		};
 
-			port@0 {
-				reg = <0>;
-				du_out_rgb: endpoint {
+		rcar_sound: sound@ec500000 {
+			/*
+			 * #sound-dai-cells is required
+			 *
+			 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
+			 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
+			 */
+			compatible = "renesas,rcar_sound-r8a7790",
+				     "renesas,rcar_sound-gen2";
+			reg = <0 0xec500000 0 0x1000>, /* SCU */
+			      <0 0xec5a0000 0 0x100>,  /* ADG */
+			      <0 0xec540000 0 0x1000>, /* SSIU */
+			      <0 0xec541000 0 0x280>,  /* SSI */
+			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+			clocks = <&cpg CPG_MOD 1005>,
+				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+				 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+				 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+				 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+				 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+				 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+				 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+				 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+				 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+				 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+				 <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>,
+				 <&cpg CPG_CORE R8A7790_CLK_M2>;
+			clock-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0",
+				      "src.9", "src.8", "src.7", "src.6",
+				      "src.5", "src.4", "src.3", "src.2",
+				      "src.1", "src.0",
+				      "ctu.0", "ctu.1",
+				      "mix.0", "mix.1",
+				      "dvc.0", "dvc.1",
+				      "clk_a", "clk_b", "clk_c", "clk_i";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 1005>,
+				 <&cpg 1006>, <&cpg 1007>,
+				 <&cpg 1008>, <&cpg 1009>,
+				 <&cpg 1010>, <&cpg 1011>,
+				 <&cpg 1012>, <&cpg 1013>,
+				 <&cpg 1014>, <&cpg 1015>;
+			reset-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0";
+
+			status = "disabled";
+
+			rcar_sound,dvc {
+				dvc0: dvc-0 {
+					dmas = <&audma1 0xbc>;
+					dma-names = "tx";
 				};
-			};
-			port@1 {
-				reg = <1>;
-				du_out_lvds0: endpoint {
+				dvc1: dvc-1 {
+					dmas = <&audma1 0xbe>;
+					dma-names = "tx";
 				};
 			};
-			port@2 {
-				reg = <2>;
-				du_out_lvds1: endpoint {
-				};
-			};
-		};
-	};
 
-	can0: can@e6e80000 {
-		compatible = "renesas,can-r8a7790", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e80000 0 0x1000>;
-		interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 916>, <&cpg CPG_CORE R8A7790_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 916>;
-		status = "disabled";
-	};
+			rcar_sound,mix {
+				mix0: mix-0 { };
+				mix1: mix-1 { };
+			};
 
-	can1: can@e6e88000 {
-		compatible = "renesas,can-r8a7790", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e88000 0 0x1000>;
-		interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 915>, <&cpg CPG_CORE R8A7790_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 915>;
-		status = "disabled";
-	};
+			rcar_sound,ctu {
+				ctu00: ctu-0 { };
+				ctu01: ctu-1 { };
+				ctu02: ctu-2 { };
+				ctu03: ctu-3 { };
+				ctu10: ctu-4 { };
+				ctu11: ctu-5 { };
+				ctu12: ctu-6 { };
+				ctu13: ctu-7 { };
+			};
 
-	jpu: jpeg-codec@fe980000 {
-		compatible = "renesas,jpu-r8a7790", "renesas,rcar-gen2-jpu";
-		reg = <0 0xfe980000 0 0x10300>;
-		interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 106>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 106>;
-	};
+			rcar_sound,src {
+				src0: src-0 {
+					interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x85>, <&audma1 0x9a>;
+					dma-names = "rx", "tx";
+				};
+				src1: src-1 {
+					interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x87>, <&audma1 0x9c>;
+					dma-names = "rx", "tx";
+				};
+				src2: src-2 {
+					interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x89>, <&audma1 0x9e>;
+					dma-names = "rx", "tx";
+				};
+				src3: src-3 {
+					interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+					dma-names = "rx", "tx";
+				};
+				src4: src-4 {
+					interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+					dma-names = "rx", "tx";
+				};
+				src5: src-5 {
+					interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+					dma-names = "rx", "tx";
+				};
+				src6: src-6 {
+					interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x91>, <&audma1 0xb4>;
+					dma-names = "rx", "tx";
+				};
+				src7: src-7 {
+					interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x93>, <&audma1 0xb6>;
+					dma-names = "rx", "tx";
+				};
+				src8: src-8 {
+					interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x95>, <&audma1 0xb8>;
+					dma-names = "rx", "tx";
+				};
+				src9: src-9 {
+					interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x97>, <&audma1 0xba>;
+					dma-names = "rx", "tx";
+				};
+			};
 
-	/* External root clock */
-	extal_clk: extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+			rcar_sound,ssi {
+				ssi0: ssi-0 {
+					interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x01>, <&audma1 0x02>,
+					       <&audma0 0x15>, <&audma1 0x16>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi1: ssi-1 {
+					 interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x03>, <&audma1 0x04>,
+					       <&audma0 0x49>, <&audma1 0x4a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi2: ssi-2 {
+					interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x05>, <&audma1 0x06>,
+					       <&audma0 0x63>, <&audma1 0x64>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi3: ssi-3 {
+					interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x07>, <&audma1 0x08>,
+					       <&audma0 0x6f>, <&audma1 0x70>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi4: ssi-4 {
+					interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x09>, <&audma1 0x0a>,
+					       <&audma0 0x71>, <&audma1 0x72>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi5: ssi-5 {
+					interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0b>, <&audma1 0x0c>,
+					       <&audma0 0x73>, <&audma1 0x74>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi6: ssi-6 {
+					interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0d>, <&audma1 0x0e>,
+					       <&audma0 0x75>, <&audma1 0x76>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi7: ssi-7 {
+					interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0f>, <&audma1 0x10>,
+					       <&audma0 0x79>, <&audma1 0x7a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi8: ssi-8 {
+					interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x11>, <&audma1 0x12>,
+					       <&audma0 0x7b>, <&audma1 0x7c>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi9: ssi-9 {
+					interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x13>, <&audma1 0x14>,
+					       <&audma0 0x7d>, <&audma1 0x7e>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+			};
+		};
 
-	/* External PCIe clock - can be overridden by the board */
-	pcie_bus_clk: pcie_bus {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
+		audma0: dma-controller@ec700000 {
+			compatible = "renesas,dmac-r8a7790",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec700000 0 0x10000>;
+			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 502>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 502>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	/*
-	 * The external audio clocks are configured as 0 Hz fixed frequency
-	 * clocks by default.
-	 * Boards that provide audio clocks should override them.
-	 */
-	audio_clk_a: audio_clk_a {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clk_b: audio_clk_b {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clk_c: audio_clk_c {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
+		audma1: dma-controller@ec720000 {
+			compatible = "renesas,dmac-r8a7790",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec720000 0 0x10000>;
+			interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 501>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 501>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	/* External SCIF clock */
-	scif_clk: scif {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+		xhci: usb@ee000000 {
+			compatible = "renesas,xhci-r8a7790",
+				     "renesas,rcar-gen2-xhci";
+			reg = <0 0xee000000 0 0xc00>;
+			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 328>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 328>;
+			phys = <&usb2 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
 
-	/* External USB clock - can be overridden by the board */
-	usb_extal_clk: usb_extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <48000000>;
-	};
+		pci0: pci@ee090000 {
+			compatible = "renesas,pci-r8a7790",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee090000 0 0xc00>,
+			      <0 0xee080000 0 0x1100>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x800 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
 
-	/* External CAN clock */
-	can_clk: can {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+			usb@2,0 {
+				reg = <0x1000 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+		};
 
-	cpg: clock-controller@e6150000 {
-		compatible = "renesas,r8a7790-cpg-mssr";
-		reg = <0 0xe6150000 0 0x1000>;
-		clocks = <&extal_clk>, <&usb_extal_clk>;
-		clock-names = "extal", "usb_extal";
-		#clock-cells = <2>;
-		#power-domain-cells = <0>;
-		#reset-cells = <1>;
-	};
+		pci1: pci@ee0b0000 {
+			compatible = "renesas,pci-r8a7790",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee0b0000 0 0xc00>,
+			      <0 0xee0a0000 0 0x1100>;
+			interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <1 1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee0a0000 0 0xee0a0000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+		};
 
-	prr: chipid@ff000044 {
-		compatible = "renesas,prr";
-		reg = <0 0xff000044 0 4>;
-	};
+		pci2: pci@ee0d0000 {
+			compatible = "renesas,pci-r8a7790",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			reg = <0 0xee0d0000 0 0xc00>,
+			      <0 0xee0c0000 0 0x1100>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+
+			bus-range = <2 2>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x20800 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
 
-	rst: reset-controller@e6160000 {
-		compatible = "renesas,r8a7790-rst";
-		reg = <0 0xe6160000 0 0x0100>;
-	};
+			usb@2,0 {
+				reg = <0x21000 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+		};
 
-	sysc: system-controller@e6180000 {
-		compatible = "renesas,r8a7790-sysc";
-		reg = <0 0xe6180000 0 0x0200>;
-		#power-domain-cells = <1>;
-	};
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7790",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 314>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
 
-	qspi: spi@e6b10000 {
-		compatible = "renesas,qspi-r8a7790", "renesas,qspi";
-		reg = <0 0xe6b10000 0 0x2c>;
-		interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 917>;
-		dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-		       <&dmac1 0x17>, <&dmac1 0x18>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 917>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		sdhi1: sd@ee120000 {
+			compatible = "renesas,sdhi-r8a7790",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee120000 0 0x328>;
+			interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 313>;
+			dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
+			       <&dmac1 0xc9>, <&dmac1 0xca>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 313>;
+			status = "disabled";
+		};
 
-	msiof0: spi@e6e20000 {
-		compatible = "renesas,msiof-r8a7790",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6e20000 0 0x0064>;
-		interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 0>;
-		dmas = <&dmac0 0x51>, <&dmac0 0x52>,
-		       <&dmac1 0x51>, <&dmac1 0x52>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 0>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		sdhi2: sd@ee140000 {
+			compatible = "renesas,sdhi-r8a7790",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee140000 0 0x100>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 312>;
+			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+			       <&dmac1 0xc1>, <&dmac1 0xc2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 312>;
+			status = "disabled";
+		};
 
-	msiof1: spi@e6e10000 {
-		compatible = "renesas,msiof-r8a7790",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6e10000 0 0x0064>;
-		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 208>;
-		dmas = <&dmac0 0x55>, <&dmac0 0x56>,
-		       <&dmac1 0x55>, <&dmac1 0x56>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 208>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		sdhi3: sd@ee160000 {
+			compatible = "renesas,sdhi-r8a7790",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee160000 0 0x100>;
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 311>;
+			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+			       <&dmac1 0xd3>, <&dmac1 0xd4>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 311>;
+			status = "disabled";
+		};
 
-	msiof2: spi@e6e00000 {
-		compatible = "renesas,msiof-r8a7790",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6e00000 0 0x0064>;
-		interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 205>;
-		dmas = <&dmac0 0x41>, <&dmac0 0x42>,
-		       <&dmac1 0x41>, <&dmac1 0x42>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 205>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		mmcif0: mmc@ee200000 {
+			compatible = "renesas,mmcif-r8a7790",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee200000 0 0x80>;
+			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 315>;
+			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
+			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 315>;
+			reg-io-width = <4>;
+			status = "disabled";
+			max-frequency = <97500000>;
+		};
 
-	msiof3: spi@e6c90000 {
-		compatible = "renesas,msiof-r8a7790",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6c90000 0 0x0064>;
-		interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 215>;
-		dmas = <&dmac0 0x45>, <&dmac0 0x46>,
-		       <&dmac1 0x45>, <&dmac1 0x46>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 215>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		mmcif1: mmc@ee220000 {
+			compatible = "renesas,mmcif-r8a7790",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee220000 0 0x80>;
+			interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 305>;
+			dmas = <&dmac0 0xe1>, <&dmac0 0xe2>,
+			       <&dmac1 0xe1>, <&dmac1 0xe2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 305>;
+			reg-io-width = <4>;
+			status = "disabled";
+			max-frequency = <97500000>;
+		};
 
-	xhci: usb@ee000000 {
-		compatible = "renesas,xhci-r8a7790", "renesas,rcar-gen2-xhci";
-		reg = <0 0xee000000 0 0xc00>;
-		interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 328>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 328>;
-		phys = <&usb2 1>;
-		phy-names = "usb";
-		status = "disabled";
-	};
+		sata0: sata@ee300000 {
+			compatible = "renesas,sata-r8a7790",
+				     "renesas,rcar-gen2-sata";
+			reg = <0 0xee300000 0 0x2000>;
+			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 815>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 815>;
+			status = "disabled";
+		};
 
-	pci0: pci@ee090000 {
-		compatible = "renesas,pci-r8a7790", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		reg = <0 0xee090000 0 0xc00>,
-		      <0 0xee080000 0 0x1100>;
-		interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		status = "disabled";
-
-		bus-range = <0 0>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-
-		usb@1,0 {
-			reg = <0x800 0 0 0 0>;
-			phys = <&usb0 0>;
-			phy-names = "usb";
+		sata1: sata@ee500000 {
+			compatible = "renesas,sata-r8a7790",
+				     "renesas,rcar-gen2-sata";
+			reg = <0 0xee500000 0 0x2000>;
+			interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 814>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 814>;
+			status = "disabled";
 		};
 
-		usb@2,0 {
-			reg = <0x1000 0 0 0 0>;
-			phys = <&usb0 0>;
-			phy-names = "usb";
+		ether: ethernet@ee700000 {
+			compatible = "renesas,ether-r8a7790",
+				     "renesas,rcar-gen2-ether";
+			reg = <0 0xee700000 0 0x400>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 813>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 813>;
+			phy-mode = "rmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
 		};
-	};
 
-	pci1: pci@ee0b0000 {
-		compatible = "renesas,pci-r8a7790", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		reg = <0 0xee0b0000 0 0xc00>,
-		      <0 0xee0a0000 0 0x1100>;
-		interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		status = "disabled";
-
-		bus-range = <1 1>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee0a0000 0 0xee0a0000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-	};
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>, <0 0xf1002000 0 0x2000>,
+			      <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
 
-	pci2: pci@ee0d0000 {
-		compatible = "renesas,pci-r8a7790", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		reg = <0 0xee0d0000 0 0xc00>,
-		      <0 0xee0c0000 0 0x1100>;
-		interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-		status = "disabled";
-
-		bus-range = <2 2>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-
-		usb@1,0 {
-			reg = <0x20800 0 0 0 0>;
-			phys = <&usb2 0>;
-			phy-names = "usb";
+		pciec: pcie@fe000000 {
+			compatible = "renesas,pcie-r8a7790",
+				     "renesas,pcie-rcar-gen2";
+			reg = <0 0xfe000000 0 0x80000>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			bus-range = <0x00 0xff>;
+			device_type = "pci";
+			ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+				  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+				  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+				  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+			/* Map all possible DDR as inbound ranges */
+			dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
+				      0x43000000 1 0x80000000 1 0x80000000 0 0x80000000>;
+			interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
+			clock-names = "pcie", "pcie_bus";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 319>;
+			status = "disabled";
 		};
 
-		usb@2,0 {
-			reg = <0x21000 0 0 0 0>;
-			phys = <&usb2 0>;
-			phy-names = "usb";
+		vsp@fe920000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe920000 0 0x8000>;
+			interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 130>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 130>;
 		};
-	};
 
-	pciec: pcie@fe000000 {
-		compatible = "renesas,pcie-r8a7790", "renesas,pcie-rcar-gen2";
-		reg = <0 0xfe000000 0 0x80000>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		bus-range = <0x00 0xff>;
-		device_type = "pci";
-		ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
-			  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
-			  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
-			  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
-		/* Map all possible DDR as inbound ranges */
-		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
-			      0x43000000 1 0x80000000 1 0x80000000 0 0x80000000>;
-		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
-		clock-names = "pcie", "pcie_bus";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 319>;
-		status = "disabled";
-	};
+		vsp@fe928000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe928000 0 0x8000>;
+			interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 131>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 131>;
+		};
 
-	rcar_sound: sound@ec500000 {
-		/*
-		 * #sound-dai-cells is required
-		 *
-		 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
-		 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
-		 */
-		compatible =  "renesas,rcar_sound-r8a7790", "renesas,rcar_sound-gen2";
-		reg =	<0 0xec500000 0 0x1000>, /* SCU */
-			<0 0xec5a0000 0 0x100>,  /* ADG */
-			<0 0xec540000 0 0x1000>, /* SSIU */
-			<0 0xec541000 0 0x280>,  /* SSI */
-			<0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
-		reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
-
-		clocks = <&cpg CPG_MOD 1005>,
-			 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
-			 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
-			 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
-			 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
-			 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
-			 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
-			 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
-			 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
-			 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
-			 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
-			 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-			 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-			 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
-			 <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>,
-			 <&cpg CPG_CORE R8A7790_CLK_M2>;
-		clock-names = "ssi-all",
-				"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-				"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
-				"src.9", "src.8", "src.7", "src.6", "src.5",
-				"src.4", "src.3", "src.2", "src.1", "src.0",
-				"ctu.0", "ctu.1",
-				"mix.0", "mix.1",
-				"dvc.0", "dvc.1",
-				"clk_a", "clk_b", "clk_c", "clk_i";
-		power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
-		resets = <&cpg 1005>,
-			 <&cpg 1006>, <&cpg 1007>, <&cpg 1008>, <&cpg 1009>,
-			 <&cpg 1010>, <&cpg 1011>, <&cpg 1012>, <&cpg 1013>,
-			 <&cpg 1014>, <&cpg 1015>;
-		reset-names = "ssi-all",
-			      "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-			      "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0";
-
-		status = "disabled";
-
-		rcar_sound,dvc {
-			dvc0: dvc-0 {
-				dmas = <&audma1 0xbc>;
-				dma-names = "tx";
-			};
-			dvc1: dvc-1 {
-				dmas = <&audma1 0xbe>;
-				dma-names = "tx";
-			};
+		vsp@fe930000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe930000 0 0x8000>;
+			interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 128>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 128>;
 		};
 
-		rcar_sound,mix {
-			mix0: mix-0 { };
-			mix1: mix-1 { };
+		vsp@fe938000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe938000 0 0x8000>;
+			interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 127>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 127>;
 		};
 
-		rcar_sound,ctu {
-			ctu00: ctu-0 { };
-			ctu01: ctu-1 { };
-			ctu02: ctu-2 { };
-			ctu03: ctu-3 { };
-			ctu10: ctu-4 { };
-			ctu11: ctu-5 { };
-			ctu12: ctu-6 { };
-			ctu13: ctu-7 { };
+		jpu: jpeg-codec@fe980000 {
+			compatible = "renesas,jpu-r8a7790",
+				     "renesas,rcar-gen2-jpu";
+			reg = <0 0xfe980000 0 0x10300>;
+			interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 106>;
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 106>;
 		};
 
-		rcar_sound,src {
-			src0: src-0 {
-				interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x85>, <&audma1 0x9a>;
-				dma-names = "rx", "tx";
-			};
-			src1: src-1 {
-				interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x87>, <&audma1 0x9c>;
-				dma-names = "rx", "tx";
-			};
-			src2: src-2 {
-				interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x89>, <&audma1 0x9e>;
-				dma-names = "rx", "tx";
-			};
-			src3: src-3 {
-				interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8b>, <&audma1 0xa0>;
-				dma-names = "rx", "tx";
-			};
-			src4: src-4 {
-				interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8d>, <&audma1 0xb0>;
-				dma-names = "rx", "tx";
-			};
-			src5: src-5 {
-				interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8f>, <&audma1 0xb2>;
-				dma-names = "rx", "tx";
-			};
-			src6: src-6 {
-				interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x91>, <&audma1 0xb4>;
-				dma-names = "rx", "tx";
-			};
-			src7: src-7 {
-				interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x93>, <&audma1 0xb6>;
-				dma-names = "rx", "tx";
-			};
-			src8: src-8 {
-				interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x95>, <&audma1 0xb8>;
-				dma-names = "rx", "tx";
-			};
-			src9: src-9 {
-				interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x97>, <&audma1 0xba>;
-				dma-names = "rx", "tx";
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7790";
+			reg = <0 0xfeb00000 0 0x70000>,
+			      <0 0xfeb90000 0 0x1c>,
+			      <0 0xfeb94000 0 0x1c>;
+			reg-names = "du", "lvds.0", "lvds.1";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>,
+				 <&cpg CPG_MOD 722>, <&cpg CPG_MOD 726>,
+				 <&cpg CPG_MOD 725>;
+			clock-names = "du.0", "du.1", "du.2", "lvds.0",
+				      "lvds.1";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_lvds0: endpoint {
+					};
+				};
+				port@2 {
+					reg = <2>;
+					du_out_lvds1: endpoint {
+					};
+				};
 			};
 		};
 
-		rcar_sound,ssi {
-			ssi0: ssi-0 {
-				interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi1: ssi-1 {
-				 interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi2: ssi-2 {
-				interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi3: ssi-3 {
-				interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi4: ssi-4 {
-				interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi5: ssi-5 {
-				interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi6: ssi-6 {
-				interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi7: ssi-7 {
-				interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi8: ssi-8 {
-				interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi9: ssi-9 {
-				interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
 		};
-	};
 
-	ipmmu_sy0: mmu@e6280000 {
-		compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6280000 0 0x1000>;
-		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		cmt0: timer@ffca0000 {
+			compatible = "renesas,r8a7790-cmt0",
+				     "renesas,rcar-gen2-cmt0";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 124>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 124>;
+
+			status = "disabled";
+		};
 
-	ipmmu_sy1: mmu@e6290000 {
-		compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6290000 0 0x1000>;
-		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
+		cmt1: timer@e6130000 {
+			compatible = "renesas,r8a7790-cmt1",
+				     "renesas,rcar-gen2-cmt1";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 329>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+			resets = <&cpg 329>;
+
+			status = "disabled";
+		};
 	};
 
-	ipmmu_ds: mmu@e6740000 {
-		compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6740000 0 0x1000>;
-		interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
 
-	ipmmu_mp: mmu@ec680000 {
-		compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
-		reg = <0 0xec680000 0 0x1000>;
-		interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
+			thermal-sensors = <&thermal>;
+
+			trips {
+				cpu-crit {
+					temperature = <95000>;
+					hysteresis = <0>;
+					type = "critical";
+				};
+			};
+			cooling-maps {
+			};
+		};
 	};
 
-	ipmmu_mx: mmu@fe951000 {
-		compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
-		reg = <0 0xfe951000 0 0x1000>;
-		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
 	};
 
-	ipmmu_rt: mmu@ffc80000 {
-		compatible = "renesas,ipmmu-r8a7790", "renesas,ipmmu-vmsa";
-		reg = <0 0xffc80000 0 0x1000>;
-		interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
+	/* External USB clock - can be overridden by the board */
+	usb_extal_clk: usb_extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <48000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index a50924d12b6f..fcdd0164142b 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -51,7 +51,11 @@
 		serial0 = &scif0;
 		serial1 = &scif1;
 		i2c9 = &gpioi2c1;
+		i2c10 = &gpioi2c2;
+		i2c11 = &gpioi2c4;
 		i2c12 = &i2cexio1;
+		i2c13 = &i2chdmi;
+		i2c14 = &i2cexio4;
 	};
 
 	chosen {
@@ -312,8 +316,28 @@
 		#size-cells = <0>;
 		compatible = "i2c-gpio";
 		status = "disabled";
-		sda-gpios = <&gpio7 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 		scl-gpios = <&gpio7 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio7 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	gpioi2c2: i2c-10 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio2 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	gpioi2c4: i2c-11 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio7 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio7 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 		i2c-gpio,delay-us = <5>;
 	};
 
@@ -328,6 +352,115 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 	};
+
+	/*
+	 * A fallback to GPIO is provided for I2C2.
+	 */
+	i2chdmi: i2c-13 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c2>, <&gpioi2c2>;
+		i2c-bus-name = "i2c-hdmi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ak4643: codec@12 {
+			compatible = "asahi-kasei,ak4643";
+			#sound-dai-cells = <0>;
+			reg = <0x12>;
+		};
+
+		composite-in@20 {
+			compatible = "adi,adv7180";
+			reg = <0x20>;
+			remote = <&vin1>;
+
+			port {
+				adv7180: endpoint {
+					bus-width = <8>;
+					remote-endpoint = <&vin1ep>;
+				};
+			};
+		};
+
+		hdmi@39 {
+			compatible = "adi,adv7511w";
+			reg = <0x39>;
+			interrupt-parent = <&gpio3>;
+			interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&cec_clock>;
+			clock-names = "cec";
+
+			adi,input-depth = <8>;
+			adi,input-colorspace = "rgb";
+			adi,input-clock = "1x";
+			adi,input-style = <1>;
+			adi,input-justification = "evenly";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7511_in: endpoint {
+						remote-endpoint = <&du_out_rgb>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					adv7511_out: endpoint {
+						remote-endpoint = <&hdmi_con_out>;
+					};
+				};
+			};
+		};
+
+		hdmi-in@4c {
+			compatible = "adi,adv7612";
+			reg = <0x4c>;
+			interrupt-parent = <&gpio4>;
+			interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+			default-input = <0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7612_in: endpoint {
+						remote-endpoint = <&hdmi_con_in>;
+					};
+				};
+
+				port@2 {
+					reg = <2>;
+					adv7612_out: endpoint {
+						remote-endpoint = <&vin0ep2>;
+					};
+				};
+			};
+		};
+
+		eeprom@50 {
+			compatible = "renesas,r1ex24002", "atmel,24c02";
+			reg = <0x50>;
+			pagesize = <16>;
+		};
+	};
+
+	/*
+	 * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA).
+	 * A fallback to GPIO is provided.
+	 */
+	i2cexio4: i2c-14 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c4>, <&gpioi2c4>;
+		i2c-bus-name = "i2c-exio4";
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
 };
 
 &du {
@@ -371,6 +504,11 @@
 		function = "i2c2";
 	};
 
+	i2c4_pins: i2c4 {
+		groups = "i2c4_c";
+		function = "i2c4";
+	};
+
 	du_pins: du {
 		groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
 		function = "du";
@@ -499,6 +637,11 @@
 	status = "okay";
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &sata0 {
 	status = "okay";
 };
@@ -621,96 +764,14 @@
 
 &i2c2 {
 	pinctrl-0 = <&i2c2_pins>;
-	pinctrl-names = "default";
+	pinctrl-names = "i2c-hdmi";
 
-	status = "okay";
 	clock-frequency = <100000>;
+};
 
-	ak4643: codec@12 {
-		compatible = "asahi-kasei,ak4643";
-		#sound-dai-cells = <0>;
-		reg = <0x12>;
-	};
-
-	composite-in@20 {
-		compatible = "adi,adv7180";
-		reg = <0x20>;
-		remote = <&vin1>;
-
-		port {
-			adv7180: endpoint {
-				bus-width = <8>;
-				remote-endpoint = <&vin1ep>;
-			};
-		};
-	};
-
-	hdmi@39 {
-		compatible = "adi,adv7511w";
-		reg = <0x39>;
-		interrupt-parent = <&gpio3>;
-		interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
-		clocks = <&cec_clock>;
-		clock-names = "cec";
-
-		adi,input-depth = <8>;
-		adi,input-colorspace = "rgb";
-		adi,input-clock = "1x";
-		adi,input-style = <1>;
-		adi,input-justification = "evenly";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7511_in: endpoint {
-					remote-endpoint = <&du_out_rgb>;
-				};
-			};
-
-			port@1 {
-				reg = <1>;
-				adv7511_out: endpoint {
-					remote-endpoint = <&hdmi_con_out>;
-				};
-			};
-		};
-	};
-
-	hdmi-in@4c {
-		compatible = "adi,adv7612";
-		reg = <0x4c>;
-		interrupt-parent = <&gpio4>;
-		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
-		default-input = <0>;
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7612_in: endpoint {
-					remote-endpoint = <&hdmi_con_in>;
-				};
-			};
-
-			port@2 {
-				reg = <2>;
-				adv7612_out: endpoint {
-					remote-endpoint = <&vin0ep2>;
-				};
-			};
-		};
-	};
-
-	eeprom@50 {
-		compatible = "renesas,r1ex24002", "atmel,24c02";
-		reg = <0x50>;
-		pagesize = <16>;
-	};
+&i2c4 {
+	pinctrl-0 = <&i2c4_pins>;
+	pinctrl-names = "i2c-exio4";
 };
 
 &i2c6 {
diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts
index eb374956294f..4dd5a5db2de8 100644
--- a/arch/arm/boot/dts/r8a7791-porter.dts
+++ b/arch/arm/boot/dts/r8a7791-porter.dts
@@ -29,6 +29,8 @@
 
 	aliases {
 		serial0 = &scif0;
+		i2c9 = &gpioi2c2;
+		i2c10 = &i2chdmi;
 	};
 
 	chosen {
@@ -135,6 +137,78 @@
 			clocks = <&x14_clk>;
 		};
 	};
+
+	gpioi2c2: i2c-9 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio2 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	/*
+	 * A fallback to GPIO is provided for I2C2.
+	 */
+	i2chdmi: i2c-10 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c2>, <&gpioi2c2>;
+		i2c-bus-name = "i2c-hdmi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ak4642: codec@12 {
+			compatible = "asahi-kasei,ak4642";
+			#sound-dai-cells = <0>;
+			reg = <0x12>;
+		};
+
+		composite-in@20 {
+			compatible = "adi,adv7180";
+			reg = <0x20>;
+			remote = <&vin0>;
+
+			port {
+				adv7180: endpoint {
+					bus-width = <8>;
+					remote-endpoint = <&vin0ep>;
+				};
+			};
+		};
+
+		hdmi@39 {
+			compatible = "adi,adv7511w";
+			reg = <0x39>;
+			interrupt-parent = <&gpio3>;
+			interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+			adi,input-depth = <8>;
+			adi,input-colorspace = "rgb";
+			adi,input-clock = "1x";
+			adi,input-style = <1>;
+			adi,input-justification = "evenly";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7511_in: endpoint {
+						remote-endpoint = <&du_out_rgb>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					adv7511_out: endpoint {
+						remote-endpoint = <&hdmi_con>;
+					};
+				};
+			};
+		};
+	};
 };
 
 &extal_clk {
@@ -296,61 +370,9 @@
 
 &i2c2 {
 	pinctrl-0 = <&i2c2_pins>;
-	pinctrl-names = "default";
+	pinctrl-names = "i2c-hdmi";
 
-	status = "okay";
 	clock-frequency = <400000>;
-
-	ak4642: codec@12 {
-		compatible = "asahi-kasei,ak4642";
-		#sound-dai-cells = <0>;
-		reg = <0x12>;
-	};
-
-	composite-in@20 {
-		compatible = "adi,adv7180";
-		reg = <0x20>;
-		remote = <&vin0>;
-
-		port {
-			adv7180: endpoint {
-				bus-width = <8>;
-				remote-endpoint = <&vin0ep>;
-			};
-		};
-	};
-
-	hdmi@39 {
-		compatible = "adi,adv7511w";
-		reg = <0x39>;
-		interrupt-parent = <&gpio3>;
-		interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
-
-		adi,input-depth = <8>;
-		adi,input-colorspace = "rgb";
-		adi,input-clock = "1x";
-		adi,input-style = <1>;
-		adi,input-justification = "evenly";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7511_in: endpoint {
-					remote-endpoint = <&du_out_rgb>;
-				};
-			};
-
-			port@1 {
-				reg = <1>;
-				adv7511_out: endpoint {
-					remote-endpoint = <&hdmi_con>;
-				};
-			};
-		};
-	};
 };
 
 &sata0 {
@@ -425,7 +447,7 @@
 		      "dclkin.0", "dclkin.1";
 
 	ports {
-		port@1 {
+		port@0 {
 			endpoint {
 				remote-endpoint = <&adv7511_in>;
 			};
@@ -449,6 +471,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &ssi1 {
 	shared-pin;
 };
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 008a260f86a5..1f440a32f184 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -17,7 +17,6 @@
 
 / {
 	compatible = "renesas,r8a7791";
-	interrupt-parent = <&gic>;
 	#address-cells = <2>;
 	#size-cells = <2>;
 
@@ -40,6 +39,35 @@
 		vin2 = &vin2;
 	};
 
+	/*
+	 * The external audio clocks are configured as 0 Hz fixed frequency
+	 * clocks by default.
+	 * Boards that provide audio clocks should override them.
+	 */
+	audio_clk_a: audio_clk_a {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clk_b: audio_clk_b {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clk_c: audio_clk_c {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+
+	/* External CAN clock */
+	can_clk: can {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -83,1585 +111,1637 @@
 		};
 	};
 
-	thermal-zones {
-		cpu_thermal: cpu-thermal {
-			polling-delay-passive	= <0>;
-			polling-delay		= <0>;
-
-			thermal-sensors = <&thermal>;
-
-			trips {
-				cpu-crit {
-					temperature	= <95000>;
-					hysteresis	= <0>;
-					type		= "critical";
-				};
-			};
-			cooling-maps {
-			};
-		};
-	};
-
-	apmu@e6152000 {
-		compatible = "renesas,r8a7791-apmu", "renesas,apmu";
-		reg = <0 0xe6152000 0 0x188>;
-		cpus = <&cpu0 &cpu1>;
-	};
-
-	gic: interrupt-controller@f1001000 {
-		compatible = "arm,gic-400";
-		#interrupt-cells = <3>;
-		#address-cells = <0>;
-		interrupt-controller;
-		reg = <0 0xf1001000 0 0x1000>,
-			<0 0xf1002000 0 0x2000>,
-			<0 0xf1004000 0 0x2000>,
-			<0 0xf1006000 0 0x2000>;
-		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
-		clocks = <&cpg CPG_MOD 408>;
-		clock-names = "clk";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 408>;
-	};
-
-	gpio0: gpio@e6050000 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6050000 0 0x50>;
-		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 0 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 912>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 912>;
-	};
-
-	gpio1: gpio@e6051000 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6051000 0 0x50>;
-		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 32 26>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 911>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 911>;
+	/* External root clock */
+	extal_clk: extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	gpio2: gpio@e6052000 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6052000 0 0x50>;
-		interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 64 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 910>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 910>;
+	/* External PCIe clock - can be overridden by the board */
+	pcie_bus_clk: pcie_bus {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
 	};
 
-	gpio3: gpio@e6053000 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6053000 0 0x50>;
-		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 96 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 909>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 909>;
+	/* External SCIF clock */
+	scif_clk: scif {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	gpio4: gpio@e6054000 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6054000 0 0x50>;
-		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 128 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 908>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 908>;
-	};
+	soc {
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
 
-	gpio5: gpio@e6055000 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055000 0 0x50>;
-		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 160 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 907>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 907>;
-	};
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7791-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 402>;
+			status = "disabled";
+		};
 
-	gpio6: gpio@e6055400 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055400 0 0x50>;
-		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 192 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 905>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 905>;
-	};
+		gpio0: gpio@e6050000 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6050000 0 0x50>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 0 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 912>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 912>;
+		};
 
-	gpio7: gpio@e6055800 {
-		compatible = "renesas,gpio-r8a7791", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055800 0 0x50>;
-		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 224 26>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 904>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 904>;
-	};
+		gpio1: gpio@e6051000 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6051000 0 0x50>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 32 26>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 911>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 911>;
+		};
 
-	thermal: thermal@e61f0000 {
-		compatible =	"renesas,thermal-r8a7791",
-				"renesas,rcar-gen2-thermal",
-				"renesas,rcar-thermal";
-		reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>;
-		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 522>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 522>;
-		#thermal-sensor-cells = <0>;
-	};
+		gpio2: gpio@e6052000 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6052000 0 0x50>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 64 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 910>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 910>;
+		};
 
-	timer {
-		compatible = "arm,armv7-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
-	};
+		gpio3: gpio@e6053000 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6053000 0 0x50>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 96 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 909>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 909>;
+		};
 
-	cmt0: timer@ffca0000 {
-		compatible = "renesas,r8a7791-cmt0", "renesas,rcar-gen2-cmt0";
-		reg = <0 0xffca0000 0 0x1004>;
-		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 124>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 124>;
-
-		status = "disabled";
-	};
+		gpio4: gpio@e6054000 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6054000 0 0x50>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 128 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 908>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 908>;
+		};
 
-	cmt1: timer@e6130000 {
-		compatible = "renesas,r8a7791-cmt1", "renesas,rcar-gen2-cmt1";
-		reg = <0 0xe6130000 0 0x1004>;
-		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 329>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 329>;
-
-		status = "disabled";
-	};
+		gpio5: gpio@e6055000 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055000 0 0x50>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 160 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 907>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 907>;
+		};
 
-	irqc0: interrupt-controller@e61c0000 {
-		compatible = "renesas,irqc-r8a7791", "renesas,irqc";
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0 0xe61c0000 0 0x200>;
-		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 407>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 407>;
-	};
+		gpio6: gpio@e6055400 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055400 0 0x50>;
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 192 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 905>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 905>;
+		};
 
-	dmac0: dma-controller@e6700000 {
-		compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
-		reg = <0 0xe6700000 0 0x20000>;
-		interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 219>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 219>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		gpio7: gpio@e6055800 {
+			compatible = "renesas,gpio-r8a7791",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055800 0 0x50>;
+			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 224 26>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 904>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 904>;
+		};
 
-	dmac1: dma-controller@e6720000 {
-		compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
-		reg = <0 0xe6720000 0 0x20000>;
-		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 218>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 218>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7791";
+			reg = <0 0xe6060000 0 0x250>;
+		};
 
-	audma0: dma-controller@ec700000 {
-		compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
-		reg = <0 0xec700000 0 0x10000>;
-		interrupts =	<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12";
-		clocks = <&cpg CPG_MOD 502>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 502>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a7791-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>, <&usb_extal_clk>;
+			clock-names = "extal", "usb_extal";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
 
-	audma1: dma-controller@ec720000 {
-		compatible = "renesas,dmac-r8a7791", "renesas,rcar-dmac";
-		reg = <0 0xec720000 0 0x10000>;
-		interrupts =	<GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12";
-		clocks = <&cpg CPG_MOD 501>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 501>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		apmu@e6152000 {
+			compatible = "renesas,r8a7791-apmu", "renesas,apmu";
+			reg = <0 0xe6152000 0 0x188>;
+			cpus = <&cpu0 &cpu1>;
+		};
 
-	usb_dmac0: dma-controller@e65a0000 {
-		compatible = "renesas,r8a7791-usb-dmac", "renesas,usb-dmac";
-		reg = <0 0xe65a0000 0 0x100>;
-		interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "ch0", "ch1";
-		clocks = <&cpg CPG_MOD 330>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 330>;
-		#dma-cells = <1>;
-		dma-channels = <2>;
-	};
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a7791-rst";
+			reg = <0 0xe6160000 0 0x0100>;
+		};
 
-	usb_dmac1: dma-controller@e65b0000 {
-		compatible = "renesas,r8a7791-usb-dmac", "renesas,usb-dmac";
-		reg = <0 0xe65b0000 0 0x100>;
-		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "ch0", "ch1";
-		clocks = <&cpg CPG_MOD 331>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 331>;
-		#dma-cells = <1>;
-		dma-channels = <2>;
-	};
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a7791-sysc";
+			reg = <0 0xe6180000 0 0x0200>;
+			#power-domain-cells = <1>;
+		};
 
-	/* The memory map in the User's Manual maps the cores to bus numbers */
-	i2c0: i2c@e6508000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6508000 0 0x40>;
-		interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 931>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 931>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		irqc0: interrupt-controller@e61c0000 {
+			compatible = "renesas,irqc-r8a7791", "renesas,irqc";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0 0xe61c0000 0 0x200>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 407>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 407>;
+		};
 
-	i2c1: i2c@e6518000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6518000 0 0x40>;
-		interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 930>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 930>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		thermal: thermal@e61f0000 {
+			compatible = "renesas,thermal-r8a7791",
+				     "renesas,rcar-gen2-thermal",
+				     "renesas,rcar-thermal";
+			reg = <0 0xe61f0000 0 0x10>, <0 0xe61f0100 0 0x38>;
+			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 522>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 522>;
+			#thermal-sensor-cells = <0>;
+		};
 
-	i2c2: i2c@e6530000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6530000 0 0x40>;
-		interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 929>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 929>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_sy0: mmu@e6280000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6280000 0 0x1000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c3: i2c@e6540000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6540000 0 0x40>;
-		interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 928>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 928>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_sy1: mmu@e6290000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6290000 0 0x1000>;
+			interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c4: i2c@e6520000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6520000 0 0x40>;
-		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 927>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 927>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_ds: mmu@e6740000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6740000 0 0x1000>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c5: i2c@e6528000 {
-		/* doesn't need pinmux */
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6528000 0 0x40>;
-		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 925>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 925>;
-		i2c-scl-internal-delay-ns = <110>;
-		status = "disabled";
-	};
+		ipmmu_mp: mmu@ec680000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xec680000 0 0x1000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c6: i2c@e60b0000 {
-		/* doesn't need pinmux */
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7791", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe60b0000 0 0x425>;
-		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 926>;
-		dmas = <&dmac0 0x77>, <&dmac0 0x78>,
-		       <&dmac1 0x77>, <&dmac1 0x78>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 926>;
-		status = "disabled";
-	};
+		ipmmu_mx: mmu@fe951000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xfe951000 0 0x1000>;
+			interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c7: i2c@e6500000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7791", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6500000 0 0x425>;
-		interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 318>;
-		dmas = <&dmac0 0x61>, <&dmac0 0x62>,
-		       <&dmac1 0x61>, <&dmac1 0x62>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 318>;
-		status = "disabled";
-	};
+		ipmmu_rt: mmu@ffc80000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xffc80000 0 0x1000>;
+			interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c8: i2c@e6510000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7791", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6510000 0 0x425>;
-		interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 323>;
-		dmas = <&dmac0 0x65>, <&dmac0 0x66>,
-		       <&dmac1 0x65>, <&dmac1 0x66>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 323>;
-		status = "disabled";
-	};
+		ipmmu_gp: mmu@e62a0000 {
+			compatible = "renesas,ipmmu-r8a7791",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe62a0000 0 0x1000>;
+			interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	pfc: pin-controller@e6060000 {
-		compatible = "renesas,pfc-r8a7791";
-		reg = <0 0xe6060000 0 0x250>;
-	};
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
+		};
 
-	mmcif0: mmc@ee200000 {
-		compatible = "renesas,mmcif-r8a7791", "renesas,sh-mmcif";
-		reg = <0 0xee200000 0 0x80>;
-		interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 315>;
-		dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
-		       <&dmac1 0xd1>, <&dmac1 0xd2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 315>;
-		reg-io-width = <4>;
-		status = "disabled";
-		max-frequency = <97500000>;
-	};
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
 
-	sdhi0: sd@ee100000 {
-		compatible = "renesas,sdhi-r8a7791",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee100000 0 0x328>;
-		interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 314>;
-		dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-		       <&dmac1 0xcd>, <&dmac1 0xce>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <195000000>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 314>;
-		status = "disabled";
-	};
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
+		};
 
-	sdhi1: sd@ee140000 {
-		compatible = "renesas,sdhi-r8a7791",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee140000 0 0x100>;
-		interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 312>;
-		dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-		       <&dmac1 0xc1>, <&dmac1 0xc2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 312>;
-		status = "disabled";
-	};
+		/* The memory map in the User's Manual maps the cores to
+		 * bus numbers
+		 */
+		i2c0: i2c@e6508000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7791",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 931>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	sdhi2: sd@ee160000 {
-		compatible = "renesas,sdhi-r8a7791",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee160000 0 0x100>;
-		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 311>;
-		dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-		       <&dmac1 0xd3>, <&dmac1 0xd4>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 311>;
-		status = "disabled";
-	};
+		i2c1: i2c@e6518000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7791",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 930>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scifa0: serial@e6c40000 {
-		compatible = "renesas,scifa-r8a7791",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c40000 0 64>;
-		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 204>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x21>, <&dmac0 0x22>,
-		       <&dmac1 0x21>, <&dmac1 0x22>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 204>;
-		status = "disabled";
-	};
+		i2c2: i2c@e6530000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7791",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 929>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scifa1: serial@e6c50000 {
-		compatible = "renesas,scifa-r8a7791",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c50000 0 64>;
-		interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 203>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x25>, <&dmac0 0x26>,
-		       <&dmac1 0x25>, <&dmac1 0x26>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 203>;
-		status = "disabled";
-	};
+		i2c3: i2c@e6540000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7791",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6540000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 928>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scifa2: serial@e6c60000 {
-		compatible = "renesas,scifa-r8a7791",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c60000 0 64>;
-		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 202>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x27>, <&dmac0 0x28>,
-		       <&dmac1 0x27>, <&dmac1 0x28>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 202>;
-		status = "disabled";
-	};
+		i2c4: i2c@e6520000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7791",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6520000 0 0x40>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 927>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 927>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scifa3: serial@e6c70000 {
-		compatible = "renesas,scifa-r8a7791",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c70000 0 64>;
-		interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1106>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
-		       <&dmac1 0x1b>, <&dmac1 0x1c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 1106>;
-		status = "disabled";
-	};
+		i2c5: i2c@e6528000 {
+			/* doesn't need pinmux */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7791",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6528000 0 0x40>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 925>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 925>;
+			i2c-scl-internal-delay-ns = <110>;
+			status = "disabled";
+		};
 
-	scifa4: serial@e6c78000 {
-		compatible = "renesas,scifa-r8a7791",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c78000 0 64>;
-		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1107>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
-		       <&dmac1 0x1f>, <&dmac1 0x20>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 1107>;
-		status = "disabled";
-	};
+		i2c6: i2c@e60b0000 {
+			/* doesn't need pinmux */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7791",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe60b0000 0 0x425>;
+			interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 926>;
+			dmas = <&dmac0 0x77>, <&dmac0 0x78>,
+			       <&dmac1 0x77>, <&dmac1 0x78>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 926>;
+			status = "disabled";
+		};
 
-	scifa5: serial@e6c80000 {
-		compatible = "renesas,scifa-r8a7791",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c80000 0 64>;
-		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1108>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x23>, <&dmac0 0x24>,
-		       <&dmac1 0x23>, <&dmac1 0x24>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 1108>;
-		status = "disabled";
-	};
+		i2c7: i2c@e6500000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7791",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6500000 0 0x425>;
+			interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 318>;
+			dmas = <&dmac0 0x61>, <&dmac0 0x62>,
+			       <&dmac1 0x61>, <&dmac1 0x62>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 318>;
+			status = "disabled";
+		};
 
-	scifb0: serial@e6c20000 {
-		compatible = "renesas,scifb-r8a7791",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c20000 0 0x100>;
-		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 206>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
-		       <&dmac1 0x3d>, <&dmac1 0x3e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 206>;
-		status = "disabled";
-	};
+		i2c8: i2c@e6510000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7791",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6510000 0 0x425>;
+			interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 323>;
+			dmas = <&dmac0 0x65>, <&dmac0 0x66>,
+			       <&dmac1 0x65>, <&dmac1 0x66>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 323>;
+			status = "disabled";
+		};
 
-	scifb1: serial@e6c30000 {
-		compatible = "renesas,scifb-r8a7791",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c30000 0 0x100>;
-		interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 207>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
-		       <&dmac1 0x19>, <&dmac1 0x1a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 207>;
-		status = "disabled";
-	};
+		hsusb: usb@e6590000 {
+			compatible = "renesas,usbhs-r8a7791",
+				     "renesas,rcar-gen2-usbhs";
+			reg = <0 0xe6590000 0 0x100>;
+			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 704>;
+			dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+			       <&usb_dmac1 0>, <&usb_dmac1 1>;
+			dma-names = "ch0", "ch1", "ch2", "ch3";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			renesas,buswait = <4>;
+			phys = <&usb0 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
 
-	scifb2: serial@e6ce0000 {
-		compatible = "renesas,scifb-r8a7791",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6ce0000 0 0x100>;
-		interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 216>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
-		       <&dmac1 0x1d>, <&dmac1 0x1e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 216>;
-		status = "disabled";
-	};
+		usbphy: usb-phy@e6590100 {
+			compatible = "renesas,usb-phy-r8a7791",
+				     "renesas,rcar-gen2-usb-phy";
+			reg = <0 0xe6590100 0 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&cpg CPG_MOD 704>;
+			clock-names = "usbhs";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			status = "disabled";
 
-	scif0: serial@e6e60000 {
-		compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e60000 0 64>;
-		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
-		       <&dmac1 0x29>, <&dmac1 0x2a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 721>;
-		status = "disabled";
-	};
+			usb0: usb-channel@0 {
+				reg = <0>;
+				#phy-cells = <1>;
+			};
+			usb2: usb-channel@2 {
+				reg = <2>;
+				#phy-cells = <1>;
+			};
+		};
 
-	scif1: serial@e6e68000 {
-		compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e68000 0 64>;
-		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
-		       <&dmac1 0x2d>, <&dmac1 0x2e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 720>;
-		status = "disabled";
-	};
+		usb_dmac0: dma-controller@e65a0000 {
+			compatible = "renesas,r8a7791-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65a0000 0 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 330>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 330>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
+		};
 
-	adc: adc@e6e54000 {
-		compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
-		reg = <0 0xe6e54000 0 64>;
-		clocks = <&cpg CPG_MOD 901>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 901>;
-		status = "disabled";
-	};
+		usb_dmac1: dma-controller@e65b0000 {
+			compatible = "renesas,r8a7791-usb-dmac",
+				     "renesas,usb-dmac";
+			reg = <0 0xe65b0000 0 0x100>;
+			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1";
+			clocks = <&cpg CPG_MOD 331>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 331>;
+			#dma-cells = <1>;
+			dma-channels = <2>;
+		};
 
-	scif2: serial@e6e58000 {
-		compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e58000 0 64>;
-		interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 719>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
-		       <&dmac1 0x2b>, <&dmac1 0x2c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 719>;
-		status = "disabled";
-	};
+		dmac0: dma-controller@e6700000 {
+			compatible = "renesas,dmac-r8a7791",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6700000 0 0x20000>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 219>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 219>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	scif3: serial@e6ea8000 {
-		compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ea8000 0 64>;
-		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 718>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
-		       <&dmac1 0x2f>, <&dmac1 0x30>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 718>;
-		status = "disabled";
-	};
+		dmac1: dma-controller@e6720000 {
+			compatible = "renesas,dmac-r8a7791",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6720000 0 0x20000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	scif4: serial@e6ee0000 {
-		compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ee0000 0 64>;
-		interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 715>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
-		       <&dmac1 0xfb>, <&dmac1 0xfc>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 715>;
-		status = "disabled";
-	};
+		avb: ethernet@e6800000 {
+			compatible = "renesas,etheravb-r8a7791",
+				     "renesas,etheravb-rcar-gen2";
+			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 812>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 812>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	scif5: serial@e6ee8000 {
-		compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ee8000 0 64>;
-		interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 714>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
-		       <&dmac1 0xfd>, <&dmac1 0xfe>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 714>;
-		status = "disabled";
-	};
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7791", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 917>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	hscif0: serial@e62c0000 {
-		compatible = "renesas,hscif-r8a7791",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c0000 0 96>;
-		interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 717>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
-		       <&dmac1 0x39>, <&dmac1 0x3a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 717>;
-		status = "disabled";
-	};
+		scifa0: serial@e6c40000 {
+			compatible = "renesas,scifa-r8a7791",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c40000 0 64>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 204>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x21>, <&dmac0 0x22>,
+			       <&dmac1 0x21>, <&dmac1 0x22>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 204>;
+			status = "disabled";
+		};
 
-	hscif1: serial@e62c8000 {
-		compatible = "renesas,hscif-r8a7791",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c8000 0 96>;
-		interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 716>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
-		       <&dmac1 0x4d>, <&dmac1 0x4e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 716>;
-		status = "disabled";
-	};
+		scifa1: serial@e6c50000 {
+			compatible = "renesas,scifa-r8a7791",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c50000 0 64>;
+			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 203>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x25>, <&dmac0 0x26>,
+			       <&dmac1 0x25>, <&dmac1 0x26>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 203>;
+			status = "disabled";
+		};
 
-	hscif2: serial@e62d0000 {
-		compatible = "renesas,hscif-r8a7791",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62d0000 0 96>;
-		interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 713>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
-		       <&dmac1 0x3b>, <&dmac1 0x3c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 713>;
-		status = "disabled";
-	};
+		scifa2: serial@e6c60000 {
+			compatible = "renesas,scifa-r8a7791",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c60000 0 64>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 202>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x27>, <&dmac0 0x28>,
+			       <&dmac1 0x27>, <&dmac1 0x28>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 202>;
+			status = "disabled";
+		};
 
-	icram0:	sram@e63a0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63a0000 0 0x12000>;
-	};
+		scifa3: serial@e6c70000 {
+			compatible = "renesas,scifa-r8a7791",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c70000 0 64>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1106>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
+			       <&dmac1 0x1b>, <&dmac1 0x1c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 1106>;
+			status = "disabled";
+		};
 
-	icram1:	sram@e63c0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63c0000 0 0x1000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0 0xe63c0000 0x1000>;
+		scifa4: serial@e6c78000 {
+			compatible = "renesas,scifa-r8a7791",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c78000 0 64>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1107>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
+			       <&dmac1 0x1f>, <&dmac1 0x20>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 1107>;
+			status = "disabled";
+		};
 
-		smp-sram@0 {
-			compatible = "renesas,smp-sram";
-			reg = <0 0x10>;
+		scifa5: serial@e6c80000 {
+			compatible = "renesas,scifa-r8a7791",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c80000 0 64>;
+			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1108>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x23>, <&dmac0 0x24>,
+			       <&dmac1 0x23>, <&dmac1 0x24>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 1108>;
+			status = "disabled";
 		};
-	};
 
-	ether: ethernet@ee700000 {
-		compatible = "renesas,ether-r8a7791",
-			     "renesas,rcar-gen2-ether";
-		reg = <0 0xee700000 0 0x400>;
-		interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 813>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 813>;
-		phy-mode = "rmii";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scifb0: serial@e6c20000 {
+			compatible = "renesas,scifb-r8a7791",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c20000 0 0x100>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 206>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
+			       <&dmac1 0x3d>, <&dmac1 0x3e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 206>;
+			status = "disabled";
+		};
 
-	avb: ethernet@e6800000 {
-		compatible = "renesas,etheravb-r8a7791",
-			     "renesas,etheravb-rcar-gen2";
-		reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
-		interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 812>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 812>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scifb1: serial@e6c30000 {
+			compatible = "renesas,scifb-r8a7791",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c30000 0 0x100>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 207>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
+			       <&dmac1 0x19>, <&dmac1 0x1a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 207>;
+			status = "disabled";
+		};
 
-	sata0: sata@ee300000 {
-		compatible = "renesas,sata-r8a7791", "renesas,rcar-gen2-sata";
-		reg = <0 0xee300000 0 0x2000>;
-		interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 815>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 815>;
-		status = "disabled";
-	};
+		scifb2: serial@e6ce0000 {
+			compatible = "renesas,scifb-r8a7791",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6ce0000 0 0x100>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 216>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
+			       <&dmac1 0x1d>, <&dmac1 0x1e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 216>;
+			status = "disabled";
+		};
 
-	sata1: sata@ee500000 {
-		compatible = "renesas,sata-r8a7791", "renesas,rcar-gen2-sata";
-		reg = <0 0xee500000 0 0x2000>;
-		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 814>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 814>;
-		status = "disabled";
-	};
+		scif0: serial@e6e60000 {
+			compatible = "renesas,scif-r8a7791",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e60000 0 64>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
+			       <&dmac1 0x29>, <&dmac1 0x2a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 721>;
+			status = "disabled";
+		};
 
-	hsusb: usb@e6590000 {
-		compatible = "renesas,usbhs-r8a7791", "renesas,rcar-gen2-usbhs";
-		reg = <0 0xe6590000 0 0x100>;
-		interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 704>;
-		dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
-		       <&usb_dmac1 0>, <&usb_dmac1 1>;
-		dma-names = "ch0", "ch1", "ch2", "ch3";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 704>;
-		renesas,buswait = <4>;
-		phys = <&usb0 1>;
-		phy-names = "usb";
-		status = "disabled";
-	};
+		scif1: serial@e6e68000 {
+			compatible = "renesas,scif-r8a7791",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e68000 0 64>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
+			       <&dmac1 0x2d>, <&dmac1 0x2e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 720>;
+			status = "disabled";
+		};
 
-	usbphy: usb-phy@e6590100 {
-		compatible = "renesas,usb-phy-r8a7791",
-			     "renesas,rcar-gen2-usb-phy";
-		reg = <0 0xe6590100 0 0x100>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&cpg CPG_MOD 704>;
-		clock-names = "usbhs";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 704>;
-		status = "disabled";
+		scif2: serial@e6e58000 {
+			compatible = "renesas,scif-r8a7791",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e58000 0 64>;
+			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 719>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
+			       <&dmac1 0x2b>, <&dmac1 0x2c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 719>;
+			status = "disabled";
+		};
 
-		usb0: usb-channel@0 {
-			reg = <0>;
-			#phy-cells = <1>;
+		scif3: serial@e6ea8000 {
+			compatible = "renesas,scif-r8a7791",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ea8000 0 64>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 718>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
+			       <&dmac1 0x2f>, <&dmac1 0x30>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 718>;
+			status = "disabled";
 		};
-		usb2: usb-channel@2 {
-			reg = <2>;
-			#phy-cells = <1>;
+
+		scif4: serial@e6ee0000 {
+			compatible = "renesas,scif-r8a7791",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee0000 0 64>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 715>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
+			       <&dmac1 0xfb>, <&dmac1 0xfc>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 715>;
+			status = "disabled";
 		};
-	};
 
-	vin0: video@e6ef0000 {
-		compatible = "renesas,vin-r8a7791", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef0000 0 0x1000>;
-		interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 811>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 811>;
-		status = "disabled";
-	};
+		scif5: serial@e6ee8000 {
+			compatible = "renesas,scif-r8a7791",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee8000 0 64>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 714>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
+			       <&dmac1 0xfd>, <&dmac1 0xfe>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 714>;
+			status = "disabled";
+		};
 
-	vin1: video@e6ef1000 {
-		compatible = "renesas,vin-r8a7791", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef1000 0 0x1000>;
-		interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 810>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 810>;
-		status = "disabled";
-	};
+		hscif0: serial@e62c0000 {
+			compatible = "renesas,hscif-r8a7791",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c0000 0 96>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 717>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
+			       <&dmac1 0x39>, <&dmac1 0x3a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 717>;
+			status = "disabled";
+		};
 
-	vin2: video@e6ef2000 {
-		compatible = "renesas,vin-r8a7791", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef2000 0 0x1000>;
-		interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 809>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 809>;
-		status = "disabled";
-	};
+		hscif1: serial@e62c8000 {
+			compatible = "renesas,hscif-r8a7791",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c8000 0 96>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 716>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
+			       <&dmac1 0x4d>, <&dmac1 0x4e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 716>;
+			status = "disabled";
+		};
 
-	vsp@fe928000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe928000 0 0x8000>;
-		interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 131>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 131>;
-	};
+		hscif2: serial@e62d0000 {
+			compatible = "renesas,hscif-r8a7791",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62d0000 0 96>;
+			interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 713>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
+			       <&dmac1 0x3b>, <&dmac1 0x3c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 713>;
+			status = "disabled";
+		};
 
-	vsp@fe930000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe930000 0 0x8000>;
-		interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 128>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 128>;
-	};
+		msiof0: spi@e6e20000 {
+			compatible = "renesas,msiof-r8a7791",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e20000 0 0x0064>;
+			interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 000>;
+			dmas = <&dmac0 0x51>, <&dmac0 0x52>,
+			       <&dmac1 0x51>, <&dmac1 0x52>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	vsp@fe938000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe938000 0 0x8000>;
-		interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 127>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 127>;
-	};
+		msiof1: spi@e6e10000 {
+			compatible = "renesas,msiof-r8a7791",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e10000 0 0x0064>;
+			interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 208>;
+			dmas = <&dmac0 0x55>, <&dmac0 0x56>,
+			       <&dmac1 0x55>, <&dmac1 0x56>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 208>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	du: display@feb00000 {
-		compatible = "renesas,du-r8a7791";
-		reg = <0 0xfeb00000 0 0x40000>,
-		      <0 0xfeb90000 0 0x1c>;
-		reg-names = "du", "lvds.0";
-		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 724>,
-			 <&cpg CPG_MOD 723>,
-			 <&cpg CPG_MOD 726>;
-		clock-names = "du.0", "du.1", "lvds.0";
-		status = "disabled";
-
-		ports {
+		msiof2: spi@e6e00000 {
+			compatible = "renesas,msiof-r8a7791",
+				     "renesas,rcar-gen2-msiof";
+			reg = <0 0xe6e00000 0 0x0064>;
+			interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 205>;
+			dmas = <&dmac0 0x41>, <&dmac0 0x42>,
+			       <&dmac1 0x41>, <&dmac1 0x42>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 205>;
 			#address-cells = <1>;
 			#size-cells = <0>;
+			status = "disabled";
+		};
 
-			port@0 {
-				reg = <0>;
-				du_out_rgb: endpoint {
-				};
-			};
-			port@1 {
-				reg = <1>;
-				du_out_lvds0: endpoint {
-				};
-			};
+		adc: adc@e6e54000 {
+			compatible = "renesas,r8a7791-gyroadc",
+				     "renesas,rcar-gyroadc";
+			reg = <0 0xe6e54000 0 64>;
+			clocks = <&cpg CPG_MOD 901>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 901>;
+			status = "disabled";
 		};
-	};
 
-	can0: can@e6e80000 {
-		compatible = "renesas,can-r8a7791", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e80000 0 0x1000>;
-		interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 916>, <&cpg CPG_CORE R8A7791_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 916>;
-		status = "disabled";
-	};
+		can0: can@e6e80000 {
+			compatible = "renesas,can-r8a7791",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e80000 0 0x1000>;
+			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 916>,
+				 <&cpg CPG_CORE R8A7791_CLK_RCAN>, <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 916>;
+			status = "disabled";
+		};
 
-	can1: can@e6e88000 {
-		compatible = "renesas,can-r8a7791", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e88000 0 0x1000>;
-		interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 915>, <&cpg CPG_CORE R8A7791_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 915>;
-		status = "disabled";
-	};
+		can1: can@e6e88000 {
+			compatible = "renesas,can-r8a7791",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e88000 0 0x1000>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 915>,
+				 <&cpg CPG_CORE R8A7791_CLK_RCAN>, <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 915>;
+			status = "disabled";
+		};
 
-	jpu: jpeg-codec@fe980000 {
-		compatible = "renesas,jpu-r8a7791", "renesas,rcar-gen2-jpu";
-		reg = <0 0xfe980000 0 0x10300>;
-		interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 106>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 106>;
-	};
+		vin0: video@e6ef0000 {
+			compatible = "renesas,vin-r8a7791",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef0000 0 0x1000>;
+			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 811>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 811>;
+			status = "disabled";
+		};
 
-	/* External root clock */
-	extal_clk: extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+		vin1: video@e6ef1000 {
+			compatible = "renesas,vin-r8a7791",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef1000 0 0x1000>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 810>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 810>;
+			status = "disabled";
+		};
 
-	/*
-	 * The external audio clocks are configured as 0 Hz fixed frequency
-	 * clocks by default.
-	 * Boards that provide audio clocks should override them.
-	 */
-	audio_clk_a: audio_clk_a {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clk_b: audio_clk_b {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clk_c: audio_clk_c {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
+		vin2: video@e6ef2000 {
+			compatible = "renesas,vin-r8a7791",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef2000 0 0x1000>;
+			interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 809>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 809>;
+			status = "disabled";
+		};
 
-	/* External PCIe clock - can be overridden by the board */
-	pcie_bus_clk: pcie_bus {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
+		rcar_sound: sound@ec500000 {
+			/*
+			 * #sound-dai-cells is required
+			 *
+			 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
+			 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
+			 */
+			compatible = "renesas,rcar_sound-r8a7791",
+				     "renesas,rcar_sound-gen2";
+			reg = <0 0xec500000 0 0x1000>, /* SCU */
+			      <0 0xec5a0000 0 0x100>,  /* ADG */
+			      <0 0xec540000 0 0x1000>, /* SSIU */
+			      <0 0xec541000 0 0x280>,  /* SSI */
+			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+			clocks = <&cpg CPG_MOD 1005>,
+				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+				 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+				 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+				 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+				 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+				 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+				 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+				 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+				 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+				 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+				 <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>,
+				 <&cpg CPG_CORE R8A7791_CLK_M2>;
+			clock-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0", "src.9", "src.8",
+				      "src.7", "src.6", "src.5", "src.4",
+				      "src.3", "src.2", "src.1", "src.0",
+				      "ctu.0", "ctu.1",
+				      "mix.0", "mix.1",
+				      "dvc.0", "dvc.1",
+				      "clk_a", "clk_b", "clk_c", "clk_i";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 1005>,
+				 <&cpg 1006>, <&cpg 1007>,
+				 <&cpg 1008>, <&cpg 1009>,
+				 <&cpg 1010>, <&cpg 1011>,
+				 <&cpg 1012>, <&cpg 1013>,
+				 <&cpg 1014>, <&cpg 1015>;
+			reset-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0";
+
+			status = "disabled";
+
+			rcar_sound,dvc {
+				dvc0: dvc-0 {
+					dmas = <&audma1 0xbc>;
+					dma-names = "tx";
+				};
+				dvc1: dvc-1 {
+					dmas = <&audma1 0xbe>;
+					dma-names = "tx";
+				};
+			};
 
-	/* External SCIF clock */
-	scif_clk: scif {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+			rcar_sound,mix {
+				mix0: mix-0 { };
+				mix1: mix-1 { };
+			};
 
-	/* External USB clock - can be overridden by the board */
-	usb_extal_clk: usb_extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <48000000>;
-	};
+			rcar_sound,ctu {
+				ctu00: ctu-0 { };
+				ctu01: ctu-1 { };
+				ctu02: ctu-2 { };
+				ctu03: ctu-3 { };
+				ctu10: ctu-4 { };
+				ctu11: ctu-5 { };
+				ctu12: ctu-6 { };
+				ctu13: ctu-7 { };
+			};
 
-	/* External CAN clock */
-	can_clk: can {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+			rcar_sound,src {
+				src0: src-0 {
+					interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x85>, <&audma1 0x9a>;
+					dma-names = "rx", "tx";
+				};
+				src1: src-1 {
+					interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x87>, <&audma1 0x9c>;
+					dma-names = "rx", "tx";
+				};
+				src2: src-2 {
+					interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x89>, <&audma1 0x9e>;
+					dma-names = "rx", "tx";
+				};
+				src3: src-3 {
+					interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+					dma-names = "rx", "tx";
+				};
+				src4: src-4 {
+					interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+					dma-names = "rx", "tx";
+				};
+				src5: src-5 {
+					interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+					dma-names = "rx", "tx";
+				};
+				src6: src-6 {
+					interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x91>, <&audma1 0xb4>;
+					dma-names = "rx", "tx";
+				};
+				src7: src-7 {
+					interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x93>, <&audma1 0xb6>;
+					dma-names = "rx", "tx";
+				};
+				src8: src-8 {
+					interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x95>, <&audma1 0xb8>;
+					dma-names = "rx", "tx";
+				};
+				src9: src-9 {
+					interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x97>, <&audma1 0xba>;
+					dma-names = "rx", "tx";
+				};
+			};
 
-	cpg: clock-controller@e6150000 {
-		compatible = "renesas,r8a7791-cpg-mssr";
-		reg = <0 0xe6150000 0 0x1000>;
-		clocks = <&extal_clk>, <&usb_extal_clk>;
-		clock-names = "extal", "usb_extal";
-		#clock-cells = <2>;
-		#power-domain-cells = <0>;
-		#reset-cells = <1>;
-	};
+			rcar_sound,ssi {
+				ssi0: ssi-0 {
+					interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x01>, <&audma1 0x02>,
+					       <&audma0 0x15>, <&audma1 0x16>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi1: ssi-1 {
+					 interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x03>, <&audma1 0x04>,
+					       <&audma0 0x49>, <&audma1 0x4a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi2: ssi-2 {
+					interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x05>, <&audma1 0x06>,
+					       <&audma0 0x63>, <&audma1 0x64>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi3: ssi-3 {
+					interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x07>, <&audma1 0x08>,
+					       <&audma0 0x6f>, <&audma1 0x70>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi4: ssi-4 {
+					interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x09>, <&audma1 0x0a>,
+					       <&audma0 0x71>, <&audma1 0x72>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi5: ssi-5 {
+					interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0b>, <&audma1 0x0c>,
+					       <&audma0 0x73>, <&audma1 0x74>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi6: ssi-6 {
+					interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0d>, <&audma1 0x0e>,
+					       <&audma0 0x75>, <&audma1 0x76>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi7: ssi-7 {
+					interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0f>, <&audma1 0x10>,
+					       <&audma0 0x79>, <&audma1 0x7a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi8: ssi-8 {
+					interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x11>, <&audma1 0x12>,
+					       <&audma0 0x7b>, <&audma1 0x7c>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi9: ssi-9 {
+					interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x13>, <&audma1 0x14>,
+					       <&audma0 0x7d>, <&audma1 0x7e>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+			};
+		};
 
-	rst: reset-controller@e6160000 {
-		compatible = "renesas,r8a7791-rst";
-		reg = <0 0xe6160000 0 0x0100>;
-	};
+		audma0: dma-controller@ec700000 {
+			compatible = "renesas,dmac-r8a7791",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec700000 0 0x10000>;
+			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 502>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 502>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	prr: chipid@ff000044 {
-		compatible = "renesas,prr";
-		reg = <0 0xff000044 0 4>;
-	};
+		audma1: dma-controller@ec720000 {
+			compatible = "renesas,dmac-r8a7791",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec720000 0 0x10000>;
+			interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 501>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 501>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	sysc: system-controller@e6180000 {
-		compatible = "renesas,r8a7791-sysc";
-		reg = <0 0xe6180000 0 0x0200>;
-		#power-domain-cells = <1>;
-	};
+		xhci: usb@ee000000 {
+			compatible = "renesas,xhci-r8a7791",
+				     "renesas,rcar-gen2-xhci";
+			reg = <0 0xee000000 0 0xc00>;
+			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 328>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 328>;
+			phys = <&usb2 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
 
-	qspi: spi@e6b10000 {
-		compatible = "renesas,qspi-r8a7791", "renesas,qspi";
-		reg = <0 0xe6b10000 0 0x2c>;
-		interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 917>;
-		dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-		       <&dmac1 0x17>, <&dmac1 0x18>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 917>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		pci0: pci@ee090000 {
+			compatible = "renesas,pci-r8a7791",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee090000 0 0xc00>,
+			      <0 0xee080000 0 0x1100>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x800 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
 
-	msiof0: spi@e6e20000 {
-		compatible = "renesas,msiof-r8a7791",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6e20000 0 0x0064>;
-		interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 000>;
-		dmas = <&dmac0 0x51>, <&dmac0 0x52>,
-		       <&dmac1 0x51>, <&dmac1 0x52>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 0>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+			usb@2,0 {
+				reg = <0x1000 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+		};
 
-	msiof1: spi@e6e10000 {
-		compatible = "renesas,msiof-r8a7791",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6e10000 0 0x0064>;
-		interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 208>;
-		dmas = <&dmac0 0x55>, <&dmac0 0x56>,
-		       <&dmac1 0x55>, <&dmac1 0x56>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 208>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		pci1: pci@ee0d0000 {
+			compatible = "renesas,pci-r8a7791",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee0d0000 0 0xc00>,
+			      <0 0xee0c0000 0 0x1100>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <1 1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x10800 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
 
-	msiof2: spi@e6e00000 {
-		compatible = "renesas,msiof-r8a7791",
-			     "renesas,rcar-gen2-msiof";
-		reg = <0 0xe6e00000 0 0x0064>;
-		interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 205>;
-		dmas = <&dmac0 0x41>, <&dmac0 0x42>,
-		       <&dmac1 0x41>, <&dmac1 0x42>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 205>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+			usb@2,0 {
+				reg = <0x11000 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+		};
 
-	xhci: usb@ee000000 {
-		compatible = "renesas,xhci-r8a7791", "renesas,rcar-gen2-xhci";
-		reg = <0 0xee000000 0 0xc00>;
-		interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 328>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 328>;
-		phys = <&usb2 1>;
-		phy-names = "usb";
-		status = "disabled";
-	};
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7791",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 314>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
 
-	pci0: pci@ee090000 {
-		compatible = "renesas,pci-r8a7791", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		reg = <0 0xee090000 0 0xc00>,
-		      <0 0xee080000 0 0x1100>;
-		interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		status = "disabled";
-
-		bus-range = <0 0>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-
-		usb@1,0 {
-			reg = <0x800 0 0 0 0>;
-			phys = <&usb0 0>;
-			phy-names = "usb";
+		sdhi1: sd@ee140000 {
+			compatible = "renesas,sdhi-r8a7791",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee140000 0 0x100>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 312>;
+			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+			       <&dmac1 0xc1>, <&dmac1 0xc2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 312>;
+			status = "disabled";
 		};
 
-		usb@2,0 {
-			reg = <0x1000 0 0 0 0>;
-			phys = <&usb0 0>;
-			phy-names = "usb";
+		sdhi2: sd@ee160000 {
+			compatible = "renesas,sdhi-r8a7791",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee160000 0 0x100>;
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 311>;
+			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+			       <&dmac1 0xd3>, <&dmac1 0xd4>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 311>;
+			status = "disabled";
 		};
-	};
 
-	pci1: pci@ee0d0000 {
-		compatible = "renesas,pci-r8a7791", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		reg = <0 0xee0d0000 0 0xc00>,
-		      <0 0xee0c0000 0 0x1100>;
-		interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		status = "disabled";
-
-		bus-range = <1 1>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-
-		usb@1,0 {
-			reg = <0x10800 0 0 0 0>;
-			phys = <&usb2 0>;
-			phy-names = "usb";
+		mmcif0: mmc@ee200000 {
+			compatible = "renesas,mmcif-r8a7791",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee200000 0 0x80>;
+			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 315>;
+			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
+			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 315>;
+			reg-io-width = <4>;
+			status = "disabled";
+			max-frequency = <97500000>;
 		};
 
-		usb@2,0 {
-			reg = <0x11000 0 0 0 0>;
-			phys = <&usb2 0>;
-			phy-names = "usb";
+		sata0: sata@ee300000 {
+			compatible = "renesas,sata-r8a7791",
+				     "renesas,rcar-gen2-sata";
+			reg = <0 0xee300000 0 0x2000>;
+			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 815>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 815>;
+			status = "disabled";
 		};
-	};
 
-	pciec: pcie@fe000000 {
-		compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
-		reg = <0 0xfe000000 0 0x80000>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		bus-range = <0x00 0xff>;
-		device_type = "pci";
-		ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
-			  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
-			  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
-			  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
-		/* Map all possible DDR as inbound ranges */
-		dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
-			      0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>;
-		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-		#interrupt-cells = <1>;
-		interrupt-map-mask = <0 0 0 0>;
-		interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
-		clock-names = "pcie", "pcie_bus";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 319>;
-		status = "disabled";
-	};
+		sata1: sata@ee500000 {
+			compatible = "renesas,sata-r8a7791",
+				     "renesas,rcar-gen2-sata";
+			reg = <0 0xee500000 0 0x2000>;
+			interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 814>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 814>;
+			status = "disabled";
+		};
 
-	ipmmu_sy0: mmu@e6280000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6280000 0 0x1000>;
-		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		ether: ethernet@ee700000 {
+			compatible = "renesas,ether-r8a7791",
+				     "renesas,rcar-gen2-ether";
+			reg = <0 0xee700000 0 0x400>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 813>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 813>;
+			phy-mode = "rmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	ipmmu_sy1: mmu@e6290000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6290000 0 0x1000>;
-		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>, <0 0xf1002000 0 0x2000>,
+			      <0 0xf1004000 0 0x2000>, <0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
 
-	ipmmu_ds: mmu@e6740000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6740000 0 0x1000>;
-		interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		pciec: pcie@fe000000 {
+			compatible = "renesas,pcie-r8a7791",
+				     "renesas,pcie-rcar-gen2";
+			reg = <0 0xfe000000 0 0x80000>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			bus-range = <0x00 0xff>;
+			device_type = "pci";
+			ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
+				  0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
+				  0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
+				  0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
+			/* Map all possible DDR as inbound ranges */
+			dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000
+				      0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>;
+			interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
+			clock-names = "pcie", "pcie_bus";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 319>;
+			status = "disabled";
+		};
 
-	ipmmu_mp: mmu@ec680000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xec680000 0 0x1000>;
-		interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		vsp@fe928000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe928000 0 0x8000>;
+			interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 131>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 131>;
+		};
 
-	ipmmu_mx: mmu@fe951000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xfe951000 0 0x1000>;
-		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		vsp@fe930000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe930000 0 0x8000>;
+			interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 128>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 128>;
+		};
 
-	ipmmu_rt: mmu@ffc80000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xffc80000 0 0x1000>;
-		interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		vsp@fe938000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe938000 0 0x8000>;
+			interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 127>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 127>;
+		};
 
-	ipmmu_gp: mmu@e62a0000 {
-		compatible = "renesas,ipmmu-r8a7791", "renesas,ipmmu-vmsa";
-		reg = <0 0xe62a0000 0 0x1000>;
-		interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		jpu: jpeg-codec@fe980000 {
+			compatible = "renesas,jpu-r8a7791",
+				     "renesas,rcar-gen2-jpu";
+			reg = <0 0xfe980000 0 0x10300>;
+			interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 106>;
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 106>;
+		};
 
-	rcar_sound: sound@ec500000 {
-		/*
-		 * #sound-dai-cells is required
-		 *
-		 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
-		 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
-		 */
-		compatible =  "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
-		reg =	<0 0xec500000 0 0x1000>, /* SCU */
-			<0 0xec5a0000 0 0x100>,  /* ADG */
-			<0 0xec540000 0 0x1000>, /* SSIU */
-			<0 0xec541000 0 0x280>,  /* SSI */
-			<0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
-		reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
-
-		clocks = <&cpg CPG_MOD 1005>,
-			 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
-			 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
-			 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
-			 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
-			 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
-			 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
-			 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
-			 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
-			 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
-			 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
-			 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-			 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-			 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
-			 <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>,
-			 <&cpg CPG_CORE R8A7791_CLK_M2>;
-		clock-names = "ssi-all",
-				"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-				"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
-				"src.9", "src.8", "src.7", "src.6", "src.5",
-				"src.4", "src.3", "src.2", "src.1", "src.0",
-				"ctu.0", "ctu.1",
-				"mix.0", "mix.1",
-				"dvc.0", "dvc.1",
-				"clk_a", "clk_b", "clk_c", "clk_i";
-		power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
-		resets = <&cpg 1005>,
-			 <&cpg 1006>, <&cpg 1007>, <&cpg 1008>, <&cpg 1009>,
-			 <&cpg 1010>, <&cpg 1011>, <&cpg 1012>, <&cpg 1013>,
-			 <&cpg 1014>, <&cpg 1015>;
-		reset-names = "ssi-all",
-			      "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-			      "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0";
-
-		status = "disabled";
-
-		rcar_sound,dvc {
-			dvc0: dvc-0 {
-				dmas = <&audma1 0xbc>;
-				dma-names = "tx";
-			};
-			dvc1: dvc-1 {
-				dmas = <&audma1 0xbe>;
-				dma-names = "tx";
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7791";
+			reg = <0 0xfeb00000 0 0x40000>,
+			      <0 0xfeb90000 0 0x1c>;
+			reg-names = "du", "lvds.0";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>,
+				 <&cpg CPG_MOD 723>,
+				 <&cpg CPG_MOD 726>;
+			clock-names = "du.0", "du.1", "lvds.0";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_lvds0: endpoint {
+					};
+				};
 			};
 		};
 
-		rcar_sound,mix {
-			mix0: mix-0 { };
-			mix1: mix-1 { };
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
 		};
 
-		rcar_sound,ctu {
-			ctu00: ctu-0 { };
-			ctu01: ctu-1 { };
-			ctu02: ctu-2 { };
-			ctu03: ctu-3 { };
-			ctu10: ctu-4 { };
-			ctu11: ctu-5 { };
-			ctu12: ctu-6 { };
-			ctu13: ctu-7 { };
+		cmt0: timer@ffca0000 {
+			compatible = "renesas,r8a7791-cmt0",
+				     "renesas,rcar-gen2-cmt0";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 124>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 124>;
+
+			status = "disabled";
 		};
 
-		rcar_sound,src {
-			src0: src-0 {
-				interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x85>, <&audma1 0x9a>;
-				dma-names = "rx", "tx";
-			};
-			src1: src-1 {
-				interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x87>, <&audma1 0x9c>;
-				dma-names = "rx", "tx";
-			};
-			src2: src-2 {
-				interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x89>, <&audma1 0x9e>;
-				dma-names = "rx", "tx";
-			};
-			src3: src-3 {
-				interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8b>, <&audma1 0xa0>;
-				dma-names = "rx", "tx";
-			};
-			src4: src-4 {
-				interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8d>, <&audma1 0xb0>;
-				dma-names = "rx", "tx";
-			};
-			src5: src-5 {
-				interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8f>, <&audma1 0xb2>;
-				dma-names = "rx", "tx";
-			};
-			src6: src-6 {
-				interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x91>, <&audma1 0xb4>;
-				dma-names = "rx", "tx";
-			};
-			src7: src-7 {
-				interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x93>, <&audma1 0xb6>;
-				dma-names = "rx", "tx";
-			};
-			src8: src-8 {
-				interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x95>, <&audma1 0xb8>;
-				dma-names = "rx", "tx";
-			};
-			src9: src-9 {
-				interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x97>, <&audma1 0xba>;
-				dma-names = "rx", "tx";
-			};
+		cmt1: timer@e6130000 {
+			compatible = "renesas,r8a7791-cmt1",
+				     "renesas,rcar-gen2-cmt1";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 329>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+			resets = <&cpg 329>;
+
+			status = "disabled";
 		};
+	};
 
-		rcar_sound,ssi {
-			ssi0: ssi-0 {
-				interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi1: ssi-1 {
-				 interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi2: ssi-2 {
-				interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi3: ssi-3 {
-				interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi4: ssi-4 {
-				interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi5: ssi-5 {
-				interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi6: ssi-6 {
-				interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi7: ssi-7 {
-				interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi8: ssi-8 {
-				interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
-				dma-names = "rx", "tx", "rxu", "txu";
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+
+			thermal-sensors = <&thermal>;
+
+			trips {
+				cpu-crit {
+					temperature = <95000>;
+					hysteresis = <0>;
+					type = "critical";
+				};
 			};
-			ssi9: ssi-9 {
-				interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
-				dma-names = "rx", "tx", "rxu", "txu";
+			cooling-maps {
 			};
 		};
 	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+	};
+
+	/* External USB clock - can be overridden by the board */
+	usb_extal_clk: usb_extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <48000000>;
+	};
 };
diff --git a/arch/arm/boot/dts/r8a7792-blanche.dts b/arch/arm/boot/dts/r8a7792-blanche.dts
index 9b67dca6c9ef..04fb70931b3b 100644
--- a/arch/arm/boot/dts/r8a7792-blanche.dts
+++ b/arch/arm/boot/dts/r8a7792-blanche.dts
@@ -239,6 +239,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &scif0 {
 	pinctrl-0 = <&scif0_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7792-wheat.dts b/arch/arm/boot/dts/r8a7792-wheat.dts
index b9471b67b728..293b9e3b3e70 100644
--- a/arch/arm/boot/dts/r8a7792-wheat.dts
+++ b/arch/arm/boot/dts/r8a7792-wheat.dts
@@ -168,6 +168,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &scif0 {
 	pinctrl-0 = <&scif0_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi
index 3be15a158bad..d2cf8dd2d9b0 100644
--- a/arch/arm/boot/dts/r8a7792.dtsi
+++ b/arch/arm/boot/dts/r8a7792.dtsi
@@ -101,61 +101,14 @@
 		#size-cells = <2>;
 		ranges;
 
-		apmu@e6152000 {
-			compatible = "renesas,r8a7792-apmu", "renesas,apmu";
-			reg = <0 0xe6152000 0 0x188>;
-			cpus = <&cpu0 &cpu1>;
-		};
-
-		gic: interrupt-controller@f1001000 {
-			compatible = "arm,gic-400";
-			#interrupt-cells = <3>;
-			interrupt-controller;
-			reg = <0 0xf1001000 0 0x1000>,
-			      <0 0xf1002000 0 0x2000>,
-			      <0 0xf1004000 0 0x2000>,
-			      <0 0xf1006000 0 0x2000>;
-			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
-				      IRQ_TYPE_LEVEL_HIGH)>;
-			clocks = <&cpg CPG_MOD 408>;
-			clock-names = "clk";
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 408>;
-		};
-
-		irqc: interrupt-controller@e61c0000 {
-			compatible = "renesas,irqc-r8a7792", "renesas,irqc";
-			#interrupt-cells = <2>;
-			interrupt-controller;
-			reg = <0 0xe61c0000 0 0x200>;
-			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 407>;
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7792-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
 			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 407>;
-		};
-
-		rst: reset-controller@e6160000 {
-			compatible = "renesas,r8a7792-rst";
-			reg = <0 0xe6160000 0 0x0100>;
-		};
-
-		prr: chipid@ff000044 {
-			compatible = "renesas,prr";
-			reg = <0 0xff000044 0 4>;
-		};
-
-		sysc: system-controller@e6180000 {
-			compatible = "renesas,r8a7792-sysc";
-			reg = <0 0xe6180000 0 0x0200>;
-			#power-domain-cells = <1>;
-		};
-
-		pfc: pin-controller@e6060000 {
-			compatible = "renesas,pfc-r8a7792";
-			reg = <0 0xe6060000 0 0x144>;
+			resets = <&cpg 402>;
+			status = "disabled";
 		};
 
 		gpio0: gpio@e6050000 {
@@ -338,6 +291,155 @@
 			resets = <&cpg 913>;
 		};
 
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7792";
+			reg = <0 0xe6060000 0 0x144>;
+		};
+
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a7792-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>;
+			clock-names = "extal";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
+
+		apmu@e6152000 {
+			compatible = "renesas,r8a7792-apmu", "renesas,apmu";
+			reg = <0 0xe6152000 0 0x188>;
+			cpus = <&cpu0 &cpu1>;
+		};
+
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a7792-rst";
+			reg = <0 0xe6160000 0 0x0100>;
+		};
+
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a7792-sysc";
+			reg = <0 0xe6180000 0 0x0200>;
+			#power-domain-cells = <1>;
+		};
+
+		irqc: interrupt-controller@e61c0000 {
+			compatible = "renesas,irqc-r8a7792", "renesas,irqc";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0 0xe61c0000 0 0x200>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 407>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 407>;
+		};
+
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
+		};
+
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
+
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
+		};
+
+		/* I2C doesn't need pinmux */
+		i2c0: i2c@e6508000 {
+			compatible = "renesas,i2c-r8a7792",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 931>;
+			i2c-scl-internal-delay-ns = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c1: i2c@e6518000 {
+			compatible = "renesas,i2c-r8a7792",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 930>;
+			i2c-scl-internal-delay-ns = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c2: i2c@e6530000 {
+			compatible = "renesas,i2c-r8a7792",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 929>;
+			i2c-scl-internal-delay-ns = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c3: i2c@e6540000 {
+			compatible = "renesas,i2c-r8a7792",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6540000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 928>;
+			i2c-scl-internal-delay-ns = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c4: i2c@e6520000 {
+			compatible = "renesas,i2c-r8a7792",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6520000 0 0x40>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 927>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 927>;
+			i2c-scl-internal-delay-ns = <6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c5: i2c@e6528000 {
+			compatible = "renesas,i2c-r8a7792",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6528000 0 0x40>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 925>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 925>;
+			i2c-scl-internal-delay-ns = <110>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		dmac0: dma-controller@e6700000 {
 			compatible = "renesas,dmac-r8a7792",
 				     "renesas,rcar-dmac";
@@ -404,6 +506,35 @@
 			dma-channels = <15>;
 		};
 
+		avb: ethernet@e6800000 {
+			compatible = "renesas,etheravb-r8a7792",
+				     "renesas,etheravb-rcar-gen2";
+			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 812>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 812>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7792", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 917>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		scif0: serial@e6e60000 {
 			compatible = "renesas,scif-r8a7792",
 				     "renesas,rcar-gen2-scif", "renesas,scif";
@@ -500,162 +631,6 @@
 			status = "disabled";
 		};
 
-		icram0:	sram@e63a0000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe63a0000 0 0x12000>;
-		};
-
-		icram1:	sram@e63c0000 {
-			compatible = "mmio-sram";
-			reg = <0 0xe63c0000 0 0x1000>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0 0 0xe63c0000 0x1000>;
-
-			smp-sram@0 {
-				compatible = "renesas,smp-sram";
-				reg = <0 0x10>;
-			};
-		};
-
-		sdhi0: sd@ee100000 {
-			compatible = "renesas,sdhi-r8a7792",
-				     "renesas,rcar-gen2-sdhi";
-			reg = <0 0xee100000 0 0x328>;
-			interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>;
-			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-			       <&dmac1 0xcd>, <&dmac1 0xce>;
-			dma-names = "tx", "rx", "tx", "rx";
-			clocks = <&cpg CPG_MOD 314>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 314>;
-			status = "disabled";
-		};
-
-		jpu: jpeg-codec@fe980000 {
-			compatible = "renesas,jpu-r8a7792",
-				     "renesas,rcar-gen2-jpu";
-			reg = <0 0xfe980000 0 0x10300>;
-			interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 106>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 106>;
-		};
-
-		avb: ethernet@e6800000 {
-			compatible = "renesas,etheravb-r8a7792",
-				     "renesas,etheravb-rcar-gen2";
-			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
-			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 812>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 812>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		/* I2C doesn't need pinmux */
-		i2c0: i2c@e6508000 {
-			compatible = "renesas,i2c-r8a7792",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6508000 0 0x40>;
-			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 931>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 931>;
-			i2c-scl-internal-delay-ns = <6>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		i2c1: i2c@e6518000 {
-			compatible = "renesas,i2c-r8a7792",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6518000 0 0x40>;
-			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 930>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 930>;
-			i2c-scl-internal-delay-ns = <6>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		i2c2: i2c@e6530000 {
-			compatible = "renesas,i2c-r8a7792",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6530000 0 0x40>;
-			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 929>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 929>;
-			i2c-scl-internal-delay-ns = <6>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		i2c3: i2c@e6540000 {
-			compatible = "renesas,i2c-r8a7792",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6540000 0 0x40>;
-			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 928>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 928>;
-			i2c-scl-internal-delay-ns = <6>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		i2c4: i2c@e6520000 {
-			compatible = "renesas,i2c-r8a7792",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6520000 0 0x40>;
-			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 927>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 927>;
-			i2c-scl-internal-delay-ns = <6>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		i2c5: i2c@e6528000 {
-			compatible = "renesas,i2c-r8a7792",
-				     "renesas,rcar-gen2-i2c";
-			reg = <0 0xe6528000 0 0x40>;
-			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 925>;
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 925>;
-			i2c-scl-internal-delay-ns = <110>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
-		qspi: spi@e6b10000 {
-			compatible = "renesas,qspi-r8a7792", "renesas,qspi";
-			reg = <0 0xe6b10000 0 0x2c>;
-			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 917>;
-			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-			       <&dmac1 0x17>, <&dmac1 0x18>;
-			dma-names = "tx", "rx", "tx", "rx";
-			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
-			resets = <&cpg 917>;
-			num-cs = <1>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-		};
-
 		msiof0: spi@e6e20000 {
 			compatible = "renesas,msiof-r8a7792",
 				     "renesas,rcar-gen2-msiof";
@@ -688,34 +663,6 @@
 			status = "disabled";
 		};
 
-		du: display@feb00000 {
-			compatible = "renesas,du-r8a7792";
-			reg = <0 0xfeb00000 0 0x40000>;
-			reg-names = "du";
-			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&cpg CPG_MOD 724>,
-				 <&cpg CPG_MOD 723>;
-			clock-names = "du.0", "du.1";
-			status = "disabled";
-
-			ports {
-				#address-cells = <1>;
-				#size-cells = <0>;
-
-				port@0 {
-					reg = <0>;
-					du_out_rgb0: endpoint {
-					};
-				};
-				port@1 {
-					reg = <1>;
-					du_out_rgb1: endpoint {
-					};
-				};
-			};
-		};
-
 		can0: can@e6e80000 {
 			compatible = "renesas,can-r8a7792",
 				     "renesas,rcar-gen2-can";
@@ -808,6 +755,36 @@
 			status = "disabled";
 		};
 
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7792",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			clocks = <&cpg CPG_MOD 314>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
+
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>,
+			      <0 0xf1002000 0 0x2000>,
+			      <0 0xf1004000 0 0x2000>,
+			      <0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) |
+				      IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
+
 		vsp@fe928000 {
 			compatible = "renesas,vsp1";
 			reg = <0 0xfe928000 0 0x8000>;
@@ -835,14 +812,47 @@
 			resets = <&cpg 127>;
 		};
 
-		cpg: clock-controller@e6150000 {
-			compatible = "renesas,r8a7792-cpg-mssr";
-			reg = <0 0xe6150000 0 0x1000>;
-			clocks = <&extal_clk>;
-			clock-names = "extal";
-			#clock-cells = <2>;
-			#power-domain-cells = <0>;
-			#reset-cells = <1>;
+		jpu: jpeg-codec@fe980000 {
+			compatible = "renesas,jpu-r8a7792",
+				     "renesas,rcar-gen2-jpu";
+			reg = <0 0xfe980000 0 0x10300>;
+			interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 106>;
+			power-domains = <&sysc R8A7792_PD_ALWAYS_ON>;
+			resets = <&cpg 106>;
+		};
+
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7792";
+			reg = <0 0xfeb00000 0 0x40000>;
+			reg-names = "du";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>,
+				 <&cpg CPG_MOD 723>;
+			clock-names = "du.0", "du.1";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb0: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_rgb1: endpoint {
+					};
+				};
+			};
+		};
+
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/r8a7793-gose.dts b/arch/arm/boot/dts/r8a7793-gose.dts
index 51b3ffac8efa..7a66d885e657 100644
--- a/arch/arm/boot/dts/r8a7793-gose.dts
+++ b/arch/arm/boot/dts/r8a7793-gose.dts
@@ -48,6 +48,10 @@
 	aliases {
 		serial0 = &scif0;
 		serial1 = &scif1;
+		i2c9 = &gpioi2c2;
+		i2c10 = &gpioi2c4;
+		i2c11 = &i2chdmi;
+		i2c12 = &i2cexio4;
 	};
 
 	chosen {
@@ -296,6 +300,146 @@
 		#clock-cells = <0>;
 		clock-frequency = <148500000>;
 	};
+
+	gpioi2c2: i2c-9 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio2 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	gpioi2c4: i2c-10 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio7 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio7 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	/*
+	 * A fallback to GPIO is provided for I2C2.
+	 */
+	i2chdmi: i2c-11 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c2>, <&gpioi2c2>;
+		i2c-bus-name = "i2c-hdmi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ak4643: codec@12 {
+			compatible = "asahi-kasei,ak4643";
+			#sound-dai-cells = <0>;
+			reg = <0x12>;
+		};
+
+		composite-in@20 {
+			compatible = "adi,adv7180cp";
+			reg = <0x20>;
+			remote = <&vin1>;
+
+			port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7180_in: endpoint {
+						remote-endpoint = <&composite_con_in>;
+					};
+				};
+
+				port@3 {
+					reg = <3>;
+					adv7180_out: endpoint {
+						bus-width = <8>;
+						remote-endpoint = <&vin1ep>;
+					};
+				};
+			};
+		};
+
+		hdmi@39 {
+			compatible = "adi,adv7511w";
+			reg = <0x39>;
+			interrupt-parent = <&gpio3>;
+			interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+			adi,input-depth = <8>;
+			adi,input-colorspace = "rgb";
+			adi,input-clock = "1x";
+			adi,input-style = <1>;
+			adi,input-justification = "evenly";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7511_in: endpoint {
+						remote-endpoint = <&du_out_rgb>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					adv7511_out: endpoint {
+						remote-endpoint = <&hdmi_con_out>;
+					};
+				};
+			};
+		};
+
+		hdmi-in@4c {
+			compatible = "adi,adv7612";
+			reg = <0x4c>;
+			interrupt-parent = <&gpio4>;
+			interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+			default-input = <0>;
+
+			port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7612_in: endpoint {
+						remote-endpoint = <&hdmi_con_in>;
+					};
+				};
+
+				port@2 {
+					reg = <2>;
+					adv7612_out: endpoint {
+						remote-endpoint = <&vin0ep2>;
+					};
+				};
+			};
+		};
+
+		eeprom@50 {
+			compatible = "renesas,r1ex24002", "atmel,24c02";
+			reg = <0x50>;
+			pagesize = <16>;
+		};
+	};
+
+	/*
+	 * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA).
+	 * A fallback to GPIO is provided.
+	 */
+	i2cexio4: i2c-12 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c4>, <&gpioi2c4>;
+		i2c-bus-name = "i2c-exio4";
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
 };
 
 &du {
@@ -334,6 +478,11 @@
 		function = "i2c2";
 	};
 
+	i2c4_pins: i2c4 {
+		groups = "i2c4_c";
+		function = "i2c4";
+	};
+
 	du_pins: du {
 		groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
 		function = "du";
@@ -446,6 +595,11 @@
 	status = "okay";
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &scif0 {
 	pinctrl-0 = <&scif0_pins>;
 	pinctrl-names = "default";
@@ -544,107 +698,11 @@
 
 &i2c2 {
 	pinctrl-0 = <&i2c2_pins>;
-	pinctrl-names = "default";
+	pinctrl-names = "i2c-hdmi";
 
 	status = "okay";
 	clock-frequency = <100000>;
 
-	ak4643: codec@12 {
-		compatible = "asahi-kasei,ak4643";
-		#sound-dai-cells = <0>;
-		reg = <0x12>;
-	};
-
-	composite-in@20 {
-		compatible = "adi,adv7180cp";
-		reg = <0x20>;
-		remote = <&vin1>;
-
-		port {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7180_in: endpoint {
-					remote-endpoint = <&composite_con_in>;
-				};
-			};
-
-			port@3 {
-				reg = <3>;
-				adv7180_out: endpoint {
-					bus-width = <8>;
-					remote-endpoint = <&vin1ep>;
-				};
-			};
-		};
-	};
-
-	hdmi@39 {
-		compatible = "adi,adv7511w";
-		reg = <0x39>;
-		interrupt-parent = <&gpio3>;
-		interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
-
-		adi,input-depth = <8>;
-		adi,input-colorspace = "rgb";
-		adi,input-clock = "1x";
-		adi,input-style = <1>;
-		adi,input-justification = "evenly";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7511_in: endpoint {
-					remote-endpoint = <&du_out_rgb>;
-				};
-			};
-
-			port@1 {
-				reg = <1>;
-				adv7511_out: endpoint {
-					remote-endpoint = <&hdmi_con_out>;
-				};
-			};
-		};
-	};
-
-	hdmi-in@4c {
-		compatible = "adi,adv7612";
-		reg = <0x4c>;
-		interrupt-parent = <&gpio4>;
-		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
-		default-input = <0>;
-
-		port {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7612_in: endpoint {
-					remote-endpoint = <&hdmi_con_in>;
-				};
-			};
-
-			port@2 {
-				reg = <2>;
-				adv7612_out: endpoint {
-					remote-endpoint = <&vin0ep2>;
-				};
-			};
-		};
-	};
-
-	eeprom@50 {
-		compatible = "renesas,r1ex24002", "atmel,24c02";
-		reg = <0x50>;
-		pagesize = <16>;
-	};
 };
 
 &i2c6 {
@@ -668,6 +726,11 @@
 	};
 };
 
+&i2c4 {
+	pinctrl-0 = <&i2c4_pins>;
+	pinctrl-names = "i2c-exio4";
+};
+
 &rcar_sound {
 	pinctrl-0 = <&sound_pins &sound_clk_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi
index 039b22517526..5a06ad1788b2 100644
--- a/arch/arm/boot/dts/r8a7793.dtsi
+++ b/arch/arm/boot/dts/r8a7793.dtsi
@@ -15,7 +15,6 @@
 
 / {
 	compatible = "renesas,r8a7793";
-	interrupt-parent = <&gic>;
 	#address-cells = <2>;
 	#size-cells = <2>;
 
@@ -32,6 +31,35 @@
 		spi0 = &qspi;
 	};
 
+	/*
+	 * The external audio clocks are configured as 0 Hz fixed frequency
+	 * clocks by default.
+	 * Boards that provide audio clocks should override them.
+	 */
+	audio_clk_a: audio_clk_a {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clk_b: audio_clk_b {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clk_c: audio_clk_c {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+
+	/* External CAN clock */
+	can_clk: can {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -74,1261 +102,1305 @@
 		};
 	};
 
-	apmu@e6152000 {
-		compatible = "renesas,r8a7793-apmu", "renesas,apmu";
-		reg = <0 0xe6152000 0 0x188>;
-		cpus = <&cpu0 &cpu1>;
+	/* External root clock */
+	extal_clk: extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	thermal-zones {
-		cpu_thermal: cpu-thermal {
-			polling-delay-passive	= <0>;
-			polling-delay		= <0>;
+	/* External SCIF clock */
+	scif_clk: scif {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
+	};
 
-			thermal-sensors = <&thermal>;
+	soc {
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
 
-			trips {
-				cpu-crit {
-					temperature	= <95000>;
-					hysteresis	= <0>;
-					type		= "critical";
-				};
-			};
-			cooling-maps {
-			};
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7793-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 402>;
+			status = "disabled";
 		};
-	};
 
-	gic: interrupt-controller@f1001000 {
-		compatible = "arm,gic-400";
-		#interrupt-cells = <3>;
-		#address-cells = <0>;
-		interrupt-controller;
-		reg = <0 0xf1001000 0 0x1000>,
-			<0 0xf1002000 0 0x2000>,
-			<0 0xf1004000 0 0x2000>,
-			<0 0xf1006000 0 0x2000>;
-		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
-		clocks = <&cpg CPG_MOD 408>;
-		clock-names = "clk";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 408>;
-	};
+		gpio0: gpio@e6050000 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6050000 0 0x50>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 0 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 912>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 912>;
+		};
 
-	gpio0: gpio@e6050000 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6050000 0 0x50>;
-		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 0 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 912>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 912>;
-	};
+		gpio1: gpio@e6051000 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6051000 0 0x50>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 32 26>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 911>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 911>;
+		};
 
-	gpio1: gpio@e6051000 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6051000 0 0x50>;
-		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 32 26>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 911>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 911>;
-	};
+		gpio2: gpio@e6052000 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6052000 0 0x50>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 64 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 910>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 910>;
+		};
 
-	gpio2: gpio@e6052000 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6052000 0 0x50>;
-		interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 64 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 910>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 910>;
-	};
+		gpio3: gpio@e6053000 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6053000 0 0x50>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 96 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 909>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 909>;
+		};
 
-	gpio3: gpio@e6053000 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6053000 0 0x50>;
-		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 96 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 909>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 909>;
-	};
+		gpio4: gpio@e6054000 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6054000 0 0x50>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 128 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 908>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 908>;
+		};
 
-	gpio4: gpio@e6054000 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6054000 0 0x50>;
-		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 128 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 908>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 908>;
-	};
+		gpio5: gpio@e6055000 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055000 0 0x50>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 160 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 907>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 907>;
+		};
 
-	gpio5: gpio@e6055000 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055000 0 0x50>;
-		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 160 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 907>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 907>;
-	};
+		gpio6: gpio@e6055400 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055400 0 0x50>;
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 192 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 905>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 905>;
+		};
 
-	gpio6: gpio@e6055400 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055400 0 0x50>;
-		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 192 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 905>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 905>;
-	};
+		gpio7: gpio@e6055800 {
+			compatible = "renesas,gpio-r8a7793",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055800 0 0x50>;
+			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 224 26>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 904>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 904>;
+		};
 
-	gpio7: gpio@e6055800 {
-		compatible = "renesas,gpio-r8a7793", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055800 0 0x50>;
-		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 224 26>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 904>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 904>;
-	};
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7793";
+			reg = <0 0xe6060000 0 0x250>;
+		};
 
-	thermal: thermal@e61f0000 {
-		compatible =	"renesas,thermal-r8a7793",
-				"renesas,rcar-gen2-thermal",
-				"renesas,rcar-thermal";
-		reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>;
-		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 522>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 522>;
-		#thermal-sensor-cells = <0>;
-	};
+		/* Special CPG clocks */
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a7793-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>, <&usb_extal_clk>;
+			clock-names = "extal", "usb_extal";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
 
-	timer {
-		compatible = "arm,armv7-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
-	};
+		apmu@e6152000 {
+			compatible = "renesas,r8a7793-apmu", "renesas,apmu";
+			reg = <0 0xe6152000 0 0x188>;
+			cpus = <&cpu0 &cpu1>;
+		};
 
-	cmt0: timer@ffca0000 {
-		compatible = "renesas,r8a7793-cmt0", "renesas,rcar-gen2-cmt0";
-		reg = <0 0xffca0000 0 0x1004>;
-		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 124>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 124>;
-
-		status = "disabled";
-	};
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a7793-rst";
+			reg = <0 0xe6160000 0 0x0100>;
+		};
 
-	cmt1: timer@e6130000 {
-		compatible = "renesas,r8a7793-cmt1", "renesas,rcar-gen2-cmt1";
-		reg = <0 0xe6130000 0 0x1004>;
-		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 329>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 329>;
-
-		status = "disabled";
-	};
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a7793-sysc";
+			reg = <0 0xe6180000 0 0x0200>;
+			#power-domain-cells = <1>;
+		};
 
-	irqc0: interrupt-controller@e61c0000 {
-		compatible = "renesas,irqc-r8a7793", "renesas,irqc";
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0 0xe61c0000 0 0x200>;
-		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 407>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 407>;
-	};
+		irqc0: interrupt-controller@e61c0000 {
+			compatible = "renesas,irqc-r8a7793", "renesas,irqc";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0 0xe61c0000 0 0x200>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 407>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 407>;
+		};
 
-	dmac0: dma-controller@e6700000 {
-		compatible = "renesas,dmac-r8a7793", "renesas,rcar-dmac";
-		reg = <0 0xe6700000 0 0x20000>;
-		interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 219>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 219>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		thermal: thermal@e61f0000 {
+			compatible = "renesas,thermal-r8a7793",
+				     "renesas,rcar-gen2-thermal",
+				     "renesas,rcar-thermal";
+			reg = <0 0xe61f0000 0 0x10>, <0 0xe61f0100 0 0x38>;
+			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 522>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 522>;
+			#thermal-sensor-cells = <0>;
+		};
 
-	dmac1: dma-controller@e6720000 {
-		compatible = "renesas,dmac-r8a7793", "renesas,rcar-dmac";
-		reg = <0 0xe6720000 0 0x20000>;
-		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 218>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 218>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		ipmmu_sy0: mmu@e6280000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6280000 0 0x1000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	audma0: dma-controller@ec700000 {
-		compatible = "renesas,dmac-r8a7793", "renesas,rcar-dmac";
-		reg = <0 0xec700000 0 0x10000>;
-		interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12";
-		clocks = <&cpg CPG_MOD 502>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 502>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		ipmmu_sy1: mmu@e6290000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6290000 0 0x1000>;
+			interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	audma1: dma-controller@ec720000 {
-		compatible = "renesas,dmac-r8a7793", "renesas,rcar-dmac";
-		reg = <0 0xec720000 0 0x10000>;
-		interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12";
-		clocks = <&cpg CPG_MOD 501>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 501>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		ipmmu_ds: mmu@e6740000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6740000 0 0x1000>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	/* The memory map in the User's Manual maps the cores to bus numbers */
-	i2c0: i2c@e6508000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7793", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6508000 0 0x40>;
-		interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 931>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 931>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_mp: mmu@ec680000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xec680000 0 0x1000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c1: i2c@e6518000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7793", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6518000 0 0x40>;
-		interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 930>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 930>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_mx: mmu@fe951000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xfe951000 0 0x1000>;
+			interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c2: i2c@e6530000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7793", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6530000 0 0x40>;
-		interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 929>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 929>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_rt: mmu@ffc80000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xffc80000 0 0x1000>;
+			interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c3: i2c@e6540000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7793", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6540000 0 0x40>;
-		interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 928>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 928>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		ipmmu_gp: mmu@e62a0000 {
+			compatible = "renesas,ipmmu-r8a7793",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe62a0000 0 0x1000>;
+			interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	i2c4: i2c@e6520000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7793", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6520000 0 0x40>;
-		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 927>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 927>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
+		};
 
-	i2c5: i2c@e6528000 {
-		/* doesn't need pinmux */
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,i2c-r8a7793", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6528000 0 0x40>;
-		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 925>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 925>;
-		i2c-scl-internal-delay-ns = <110>;
-		status = "disabled";
-	};
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
 
-	i2c6: i2c@e60b0000 {
-		/* doesn't need pinmux */
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7793", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe60b0000 0 0x425>;
-		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 926>;
-		dmas = <&dmac0 0x77>, <&dmac0 0x78>,
-		       <&dmac1 0x77>, <&dmac1 0x78>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 926>;
-		status = "disabled";
-	};
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
+		};
 
-	i2c7: i2c@e6500000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7793", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6500000 0 0x425>;
-		interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 318>;
-		dmas = <&dmac0 0x61>, <&dmac0 0x62>,
-		       <&dmac1 0x61>, <&dmac1 0x62>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 318>;
-		status = "disabled";
-	};
+		/* The memory map in the User's Manual maps the cores to
+		 * bus numbers
+		 */
+		i2c0: i2c@e6508000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7793",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 931>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	i2c8: i2c@e6510000 {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		compatible = "renesas,iic-r8a7793", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6510000 0 0x425>;
-		interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 323>;
-		dmas = <&dmac0 0x65>, <&dmac0 0x66>,
-		       <&dmac1 0x65>, <&dmac1 0x66>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 323>;
-		status = "disabled";
-	};
+		i2c1: i2c@e6518000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7793",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 930>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	pfc: pin-controller@e6060000 {
-		compatible = "renesas,pfc-r8a7793";
-		reg = <0 0xe6060000 0 0x250>;
-	};
+		i2c2: i2c@e6530000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7793",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 929>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	sdhi0: sd@ee100000 {
-		compatible = "renesas,sdhi-r8a7793",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee100000 0 0x328>;
-		interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 314>;
-		dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-		       <&dmac1 0xcd>, <&dmac1 0xce>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <195000000>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 314>;
-		status = "disabled";
-	};
+		i2c3: i2c@e6540000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7793",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6540000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 928>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	sdhi1: sd@ee140000 {
-		compatible = "renesas,sdhi-r8a7793",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee140000 0 0x100>;
-		interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 312>;
-		dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-		       <&dmac1 0xc1>, <&dmac1 0xc2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 312>;
-		status = "disabled";
-	};
+		i2c4: i2c@e6520000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7793",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6520000 0 0x40>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 927>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 927>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	sdhi2: sd@ee160000 {
-		compatible = "renesas,sdhi-r8a7793",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee160000 0 0x100>;
-		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 311>;
-		dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-		       <&dmac1 0xd3>, <&dmac1 0xd4>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 311>;
-		status = "disabled";
-	};
+		i2c5: i2c@e6528000 {
+			/* doesn't need pinmux */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a7793",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6528000 0 0x40>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 925>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 925>;
+			i2c-scl-internal-delay-ns = <110>;
+			status = "disabled";
+		};
 
-	mmcif0: mmc@ee200000 {
-		compatible = "renesas,mmcif-r8a7793", "renesas,sh-mmcif";
-		reg = <0 0xee200000 0 0x80>;
-		interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 315>;
-		dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
-		       <&dmac1 0xd1>, <&dmac1 0xd2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 315>;
-		reg-io-width = <4>;
-		status = "disabled";
-		max-frequency = <97500000>;
-	};
+		i2c6: i2c@e60b0000 {
+			/* doesn't need pinmux */
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7793",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe60b0000 0 0x425>;
+			interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 926>;
+			dmas = <&dmac0 0x77>, <&dmac0 0x78>,
+			       <&dmac1 0x77>, <&dmac1 0x78>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 926>;
+			status = "disabled";
+		};
 
-	scifa0: serial@e6c40000 {
-		compatible = "renesas,scifa-r8a7793",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c40000 0 64>;
-		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 204>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x21>, <&dmac0 0x22>,
-		       <&dmac1 0x21>, <&dmac1 0x22>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 204>;
-		status = "disabled";
-	};
+		i2c7: i2c@e6500000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7793",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6500000 0 0x425>;
+			interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 318>;
+			dmas = <&dmac0 0x61>, <&dmac0 0x62>,
+			       <&dmac1 0x61>, <&dmac1 0x62>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 318>;
+			status = "disabled";
+		};
 
-	scifa1: serial@e6c50000 {
-		compatible = "renesas,scifa-r8a7793",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c50000 0 64>;
-		interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 203>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x25>, <&dmac0 0x26>,
-		       <&dmac1 0x25>, <&dmac1 0x26>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 203>;
-		status = "disabled";
-	};
+		i2c8: i2c@e6510000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,iic-r8a7793",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6510000 0 0x425>;
+			interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 323>;
+			dmas = <&dmac0 0x65>, <&dmac0 0x66>,
+			       <&dmac1 0x65>, <&dmac1 0x66>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 323>;
+			status = "disabled";
+		};
 
-	scifa2: serial@e6c60000 {
-		compatible = "renesas,scifa-r8a7793",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c60000 0 64>;
-		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 202>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x27>, <&dmac0 0x28>,
-		       <&dmac1 0x27>, <&dmac1 0x28>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 202>;
-		status = "disabled";
-	};
+		dmac0: dma-controller@e6700000 {
+			compatible = "renesas,dmac-r8a7793",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6700000 0 0x20000>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 219>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 219>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	scifa3: serial@e6c70000 {
-		compatible = "renesas,scifa-r8a7793",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c70000 0 64>;
-		interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1106>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
-		       <&dmac1 0x1b>, <&dmac1 0x1c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 1106>;
-		status = "disabled";
-	};
+		dmac1: dma-controller@e6720000 {
+			compatible = "renesas,dmac-r8a7793",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6720000 0 0x20000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	scifa4: serial@e6c78000 {
-		compatible = "renesas,scifa-r8a7793",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c78000 0 64>;
-		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1107>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
-		       <&dmac1 0x1f>, <&dmac1 0x20>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 1107>;
-		status = "disabled";
-	};
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7793", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 917>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	scifa5: serial@e6c80000 {
-		compatible = "renesas,scifa-r8a7793",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c80000 0 64>;
-		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1108>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x23>, <&dmac0 0x24>,
-		       <&dmac1 0x23>, <&dmac1 0x24>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 1108>;
-		status = "disabled";
-	};
+		scifa0: serial@e6c40000 {
+			compatible = "renesas,scifa-r8a7793",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c40000 0 64>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 204>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x21>, <&dmac0 0x22>,
+			       <&dmac1 0x21>, <&dmac1 0x22>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 204>;
+			status = "disabled";
+		};
 
-	scifb0: serial@e6c20000 {
-		compatible = "renesas,scifb-r8a7793",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c20000 0 0x100>;
-		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 206>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
-		       <&dmac1 0x3d>, <&dmac1 0x3e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 206>;
-		status = "disabled";
-	};
+		scifa1: serial@e6c50000 {
+			compatible = "renesas,scifa-r8a7793",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c50000 0 64>;
+			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 203>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x25>, <&dmac0 0x26>,
+			       <&dmac1 0x25>, <&dmac1 0x26>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 203>;
+			status = "disabled";
+		};
 
-	scifb1: serial@e6c30000 {
-		compatible = "renesas,scifb-r8a7793",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c30000 0 0x100>;
-		interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 207>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
-		       <&dmac1 0x19>, <&dmac1 0x1a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 207>;
-		status = "disabled";
-	};
+		scifa2: serial@e6c60000 {
+			compatible = "renesas,scifa-r8a7793",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c60000 0 64>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 202>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x27>, <&dmac0 0x28>,
+			       <&dmac1 0x27>, <&dmac1 0x28>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 202>;
+			status = "disabled";
+		};
 
-	scifb2: serial@e6ce0000 {
-		compatible = "renesas,scifb-r8a7793",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6ce0000 0 0x100>;
-		interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 216>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
-		       <&dmac1 0x1d>, <&dmac1 0x1e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 216>;
-		status = "disabled";
-	};
+		scifa3: serial@e6c70000 {
+			compatible = "renesas,scifa-r8a7793",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c70000 0 64>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1106>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
+			       <&dmac1 0x1b>, <&dmac1 0x1c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 1106>;
+			status = "disabled";
+		};
 
-	scif0: serial@e6e60000 {
-		compatible = "renesas,scif-r8a7793", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e60000 0 64>;
-		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
-		       <&dmac1 0x29>, <&dmac1 0x2a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 721>;
-		status = "disabled";
-	};
+		scifa4: serial@e6c78000 {
+			compatible = "renesas,scifa-r8a7793",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c78000 0 64>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1107>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
+			       <&dmac1 0x1f>, <&dmac1 0x20>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 1107>;
+			status = "disabled";
+		};
 
-	scif1: serial@e6e68000 {
-		compatible = "renesas,scif-r8a7793", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e68000 0 64>;
-		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
-		       <&dmac1 0x2d>, <&dmac1 0x2e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 720>;
-		status = "disabled";
-	};
+		scifa5: serial@e6c80000 {
+			compatible = "renesas,scifa-r8a7793",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c80000 0 64>;
+			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1108>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x23>, <&dmac0 0x24>,
+			       <&dmac1 0x23>, <&dmac1 0x24>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 1108>;
+			status = "disabled";
+		};
 
-	scif2: serial@e6e58000 {
-		compatible = "renesas,scif-r8a7793", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e58000 0 64>;
-		interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 719>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
-		       <&dmac1 0x2b>, <&dmac1 0x2c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 719>;
-		status = "disabled";
-	};
+		scifb0: serial@e6c20000 {
+			compatible = "renesas,scifb-r8a7793",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c20000 0 0x100>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 206>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
+			       <&dmac1 0x3d>, <&dmac1 0x3e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 206>;
+			status = "disabled";
+		};
 
-	scif3: serial@e6ea8000 {
-		compatible = "renesas,scif-r8a7793", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ea8000 0 64>;
-		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 718>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
-		       <&dmac1 0x2f>, <&dmac1 0x30>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 718>;
-		status = "disabled";
-	};
+		scifb1: serial@e6c30000 {
+			compatible = "renesas,scifb-r8a7793",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c30000 0 0x100>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 207>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
+			       <&dmac1 0x19>, <&dmac1 0x1a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 207>;
+			status = "disabled";
+		};
 
-	scif4: serial@e6ee0000 {
-		compatible = "renesas,scif-r8a7793", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ee0000 0 64>;
-		interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 715>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
-		       <&dmac1 0xfb>, <&dmac1 0xfc>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 715>;
-		status = "disabled";
-	};
+		scifb2: serial@e6ce0000 {
+			compatible = "renesas,scifb-r8a7793",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6ce0000 0 0x100>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 216>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
+			       <&dmac1 0x1d>, <&dmac1 0x1e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 216>;
+			status = "disabled";
+		};
 
-	scif5: serial@e6ee8000 {
-		compatible = "renesas,scif-r8a7793", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ee8000 0 64>;
-		interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 714>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
-		       <&dmac1 0xfd>, <&dmac1 0xfe>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 714>;
-		status = "disabled";
-	};
+		scif0: serial@e6e60000 {
+			compatible = "renesas,scif-r8a7793",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e60000 0 64>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
+			       <&dmac1 0x29>, <&dmac1 0x2a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 721>;
+			status = "disabled";
+		};
 
-	hscif0: serial@e62c0000 {
-		compatible = "renesas,hscif-r8a7793",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c0000 0 96>;
-		interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 717>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
-		       <&dmac1 0x39>, <&dmac1 0x3a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 717>;
-		status = "disabled";
-	};
+		scif1: serial@e6e68000 {
+			compatible = "renesas,scif-r8a7793",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e68000 0 64>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
+			       <&dmac1 0x2d>, <&dmac1 0x2e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 720>;
+			status = "disabled";
+		};
 
-	hscif1: serial@e62c8000 {
-		compatible = "renesas,hscif-r8a7793",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c8000 0 96>;
-		interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 716>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
-		       <&dmac1 0x4d>, <&dmac1 0x4e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 716>;
-		status = "disabled";
-	};
+		scif2: serial@e6e58000 {
+			compatible = "renesas,scif-r8a7793",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e58000 0 64>;
+			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 719>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
+			       <&dmac1 0x2b>, <&dmac1 0x2c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 719>;
+			status = "disabled";
+		};
 
-	hscif2: serial@e62d0000 {
-		compatible = "renesas,hscif-r8a7793",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62d0000 0 96>;
-		interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 713>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
-		       <&dmac1 0x3b>, <&dmac1 0x3c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 713>;
-		status = "disabled";
-	};
+		scif3: serial@e6ea8000 {
+			compatible = "renesas,scif-r8a7793",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ea8000 0 64>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 718>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
+			       <&dmac1 0x2f>, <&dmac1 0x30>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 718>;
+			status = "disabled";
+		};
 
-	icram0:	sram@e63a0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63a0000 0 0x12000>;
-	};
+		scif4: serial@e6ee0000 {
+			compatible = "renesas,scif-r8a7793",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee0000 0 64>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 715>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
+			       <&dmac1 0xfb>, <&dmac1 0xfc>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 715>;
+			status = "disabled";
+		};
 
-	icram1:	sram@e63c0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63c0000 0 0x1000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0 0xe63c0000 0x1000>;
+		scif5: serial@e6ee8000 {
+			compatible = "renesas,scif-r8a7793",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee8000 0 64>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 714>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
+			       <&dmac1 0xfd>, <&dmac1 0xfe>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 714>;
+			status = "disabled";
+		};
 
-		smp-sram@0 {
-			compatible = "renesas,smp-sram";
-			reg = <0 0x10>;
+		hscif0: serial@e62c0000 {
+			compatible = "renesas,hscif-r8a7793",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c0000 0 96>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 717>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
+			       <&dmac1 0x39>, <&dmac1 0x3a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 717>;
+			status = "disabled";
 		};
-	};
 
-	ether: ethernet@ee700000 {
-		compatible = "renesas,ether-r8a7793",
-			     "renesas,rcar-gen2-ether";
-		reg = <0 0xee700000 0 0x400>;
-		interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 813>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 813>;
-		phy-mode = "rmii";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		hscif1: serial@e62c8000 {
+			compatible = "renesas,hscif-r8a7793",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c8000 0 96>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 716>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
+			       <&dmac1 0x4d>, <&dmac1 0x4e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 716>;
+			status = "disabled";
+		};
 
-	vin0: video@e6ef0000 {
-		compatible = "renesas,vin-r8a7793", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef0000 0 0x1000>;
-		interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 811>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 811>;
-		status = "disabled";
-	};
+		hscif2: serial@e62d0000 {
+			compatible = "renesas,hscif-r8a7793",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62d0000 0 96>;
+			interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 713>, <&cpg CPG_CORE R8A7793_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
+			       <&dmac1 0x3b>, <&dmac1 0x3c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 713>;
+			status = "disabled";
+		};
 
-	vin1: video@e6ef1000 {
-		compatible = "renesas,vin-r8a7793", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef1000 0 0x1000>;
-		interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 810>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 810>;
-		status = "disabled";
-	};
+		can0: can@e6e80000 {
+			compatible = "renesas,can-r8a7793",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e80000 0 0x1000>;
+			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 916>, <&cpg CPG_CORE R8A7793_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 916>;
+			status = "disabled";
+		};
 
-	vin2: video@e6ef2000 {
-		compatible = "renesas,vin-r8a7793", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef2000 0 0x1000>;
-		interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 809>;
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 809>;
-		status = "disabled";
-	};
+		can1: can@e6e88000 {
+			compatible = "renesas,can-r8a7793",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e88000 0 0x1000>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 915>, <&cpg CPG_CORE R8A7793_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 915>;
+			status = "disabled";
+		};
 
-	qspi: spi@e6b10000 {
-		compatible = "renesas,qspi-r8a7793", "renesas,qspi";
-		reg = <0 0xe6b10000 0 0x2c>;
-		interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 917>;
-		dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-		       <&dmac1 0x17>, <&dmac1 0x18>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 917>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		vin0: video@e6ef0000 {
+			compatible = "renesas,vin-r8a7793",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef0000 0 0x1000>;
+			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 811>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 811>;
+			status = "disabled";
+		};
 
-	du: display@feb00000 {
-		compatible = "renesas,du-r8a7793";
-		reg = <0 0xfeb00000 0 0x40000>,
-		      <0 0xfeb90000 0 0x1c>;
-		reg-names = "du", "lvds.0";
-		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 724>,
-			 <&cpg CPG_MOD 723>,
-			 <&cpg CPG_MOD 726>;
-		clock-names = "du.0", "du.1", "lvds.0";
-		status = "disabled";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
+		vin1: video@e6ef1000 {
+			compatible = "renesas,vin-r8a7793",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef1000 0 0x1000>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 810>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 810>;
+			status = "disabled";
+		};
+
+		vin2: video@e6ef2000 {
+			compatible = "renesas,vin-r8a7793",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef2000 0 0x1000>;
+			interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 809>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 809>;
+			status = "disabled";
+		};
 
-			port@0 {
-				reg = <0>;
-				du_out_rgb: endpoint {
+		rcar_sound: sound@ec500000 {
+			/*
+			 * #sound-dai-cells is required
+			 *
+			 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
+			 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
+			 */
+			compatible = "renesas,rcar_sound-r8a7793",
+				     "renesas,rcar_sound-gen2";
+			reg = <0 0xec500000 0 0x1000>, /* SCU */
+			      <0 0xec5a0000 0 0x100>,  /* ADG */
+			      <0 0xec540000 0 0x1000>, /* SSIU */
+			      <0 0xec541000 0 0x280>,  /* SSI */
+			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+			clocks = <&cpg CPG_MOD 1005>,
+				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+				 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+				 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+				 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+				 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+				 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+				 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+				 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+				 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+				 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+				 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+				 <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>,
+				 <&cpg CPG_CORE R8A7793_CLK_M2>;
+			clock-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0",
+				      "src.9", "src.8", "src.7", "src.6",
+				      "src.5", "src.4", "src.3", "src.2",
+				      "src.1", "src.0",
+				      "dvc.0", "dvc.1",
+				      "clk_a", "clk_b", "clk_c", "clk_i";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 1005>,
+				 <&cpg 1006>, <&cpg 1007>,
+				 <&cpg 1008>, <&cpg 1009>,
+				 <&cpg 1010>, <&cpg 1011>,
+				 <&cpg 1012>, <&cpg 1013>,
+				 <&cpg 1014>, <&cpg 1015>;
+			reset-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0";
+
+			status = "disabled";
+
+			rcar_sound,dvc {
+				dvc0: dvc-0 {
+					dmas = <&audma1 0xbc>;
+					dma-names = "tx";
 				};
-			};
-			port@1 {
-				reg = <1>;
-				du_out_lvds0: endpoint {
+				dvc1: dvc-1 {
+					dmas = <&audma1 0xbe>;
+					dma-names = "tx";
 				};
 			};
-		};
-	};
 
-	can0: can@e6e80000 {
-		compatible = "renesas,can-r8a7793", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e80000 0 0x1000>;
-		interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 916>, <&cpg CPG_CORE R8A7793_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 916>;
-		status = "disabled";
-	};
-
-	can1: can@e6e88000 {
-		compatible = "renesas,can-r8a7793", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e88000 0 0x1000>;
-		interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 915>, <&cpg CPG_CORE R8A7793_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 915>;
-		status = "disabled";
-	};
-
-	/* External root clock */
-	extal_clk: extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+			rcar_sound,src {
+				src0: src-0 {
+					interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x85>, <&audma1 0x9a>;
+					dma-names = "rx", "tx";
+				};
+				src1: src-1 {
+					interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x87>, <&audma1 0x9c>;
+					dma-names = "rx", "tx";
+				};
+				src2: src-2 {
+					interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x89>, <&audma1 0x9e>;
+					dma-names = "rx", "tx";
+				};
+				src3: src-3 {
+					interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+					dma-names = "rx", "tx";
+				};
+				src4: src-4 {
+					interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+					dma-names = "rx", "tx";
+				};
+				src5: src-5 {
+					interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+					dma-names = "rx", "tx";
+				};
+				src6: src-6 {
+					interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x91>, <&audma1 0xb4>;
+					dma-names = "rx", "tx";
+				};
+				src7: src-7 {
+					interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x93>, <&audma1 0xb6>;
+					dma-names = "rx", "tx";
+				};
+				src8: src-8 {
+					interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x95>, <&audma1 0xb8>;
+					dma-names = "rx", "tx";
+				};
+				src9: src-9 {
+					interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x97>, <&audma1 0xba>;
+					dma-names = "rx", "tx";
+				};
+			};
 
-	/*
-	 * The external audio clocks are configured as 0 Hz fixed frequency
-	 * clocks by default.
-	 * Boards that provide audio clocks should override them.
-	 */
-	audio_clk_a: audio_clk_a {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clk_b: audio_clk_b {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clk_c: audio_clk_c {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
+			rcar_sound,ssi {
+				ssi0: ssi-0 {
+					interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x01>, <&audma1 0x02>,
+					       <&audma0 0x15>, <&audma1 0x16>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi1: ssi-1 {
+					 interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x03>, <&audma1 0x04>,
+					       <&audma0 0x49>, <&audma1 0x4a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi2: ssi-2 {
+					interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x05>, <&audma1 0x06>,
+					       <&audma0 0x63>, <&audma1 0x64>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi3: ssi-3 {
+					interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x07>, <&audma1 0x08>,
+					       <&audma0 0x6f>, <&audma1 0x70>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi4: ssi-4 {
+					interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x09>, <&audma1 0x0a>,
+					       <&audma0 0x71>, <&audma1 0x72>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi5: ssi-5 {
+					interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0b>, <&audma1 0x0c>,
+					       <&audma0 0x73>, <&audma1 0x74>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi6: ssi-6 {
+					interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0d>, <&audma1 0x0e>,
+					       <&audma0 0x75>, <&audma1 0x76>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi7: ssi-7 {
+					interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0f>, <&audma1 0x10>,
+					       <&audma0 0x79>, <&audma1 0x7a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi8: ssi-8 {
+					interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x11>, <&audma1 0x12>,
+					       <&audma0 0x7b>, <&audma1 0x7c>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi9: ssi-9 {
+					interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x13>, <&audma1 0x14>,
+					       <&audma0 0x7d>, <&audma1 0x7e>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+			};
+		};
 
-	/* External USB clock - can be overridden by the board */
-	usb_extal_clk: usb_extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <48000000>;
-	};
+		audma0: dma-controller@ec700000 {
+			compatible = "renesas,dmac-r8a7793",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec700000 0 0x10000>;
+			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 502>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 502>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	/* External CAN clock */
-	can_clk: can {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+		audma1: dma-controller@ec720000 {
+			compatible = "renesas,dmac-r8a7793",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec720000 0 0x10000>;
+			interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 501>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 501>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	/* External SCIF clock */
-	scif_clk: scif {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7793",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 314>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
 
-	/* Special CPG clocks */
-	cpg: clock-controller@e6150000 {
-		compatible = "renesas,r8a7793-cpg-mssr";
-		reg = <0 0xe6150000 0 0x1000>;
-		clocks = <&extal_clk>, <&usb_extal_clk>;
-		clock-names = "extal", "usb_extal";
-		#clock-cells = <2>;
-		#power-domain-cells = <0>;
-		#reset-cells = <1>;
-	};
+		sdhi1: sd@ee140000 {
+			compatible = "renesas,sdhi-r8a7793",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee140000 0 0x100>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 312>;
+			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+			       <&dmac1 0xc1>, <&dmac1 0xc2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 312>;
+			status = "disabled";
+		};
 
-	rst: reset-controller@e6160000 {
-		compatible = "renesas,r8a7793-rst";
-		reg = <0 0xe6160000 0 0x0100>;
-	};
+		sdhi2: sd@ee160000 {
+			compatible = "renesas,sdhi-r8a7793",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee160000 0 0x100>;
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 311>;
+			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+			       <&dmac1 0xd3>, <&dmac1 0xd4>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 311>;
+			status = "disabled";
+		};
 
-	prr: chipid@ff000044 {
-		compatible = "renesas,prr";
-		reg = <0 0xff000044 0 4>;
-	};
+		mmcif0: mmc@ee200000 {
+			compatible = "renesas,mmcif-r8a7793",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee200000 0 0x80>;
+			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 315>;
+			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
+			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 315>;
+			reg-io-width = <4>;
+			status = "disabled";
+			max-frequency = <97500000>;
+		};
 
-	sysc: system-controller@e6180000 {
-		compatible = "renesas,r8a7793-sysc";
-		reg = <0 0xe6180000 0 0x0200>;
-		#power-domain-cells = <1>;
-	};
+		ether: ethernet@ee700000 {
+			compatible = "renesas,ether-r8a7793",
+				     "renesas,rcar-gen2-ether";
+			reg = <0 0xee700000 0 0x400>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 813>;
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 813>;
+			phy-mode = "rmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	ipmmu_sy0: mmu@e6280000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6280000 0 0x1000>;
-		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>,
+				<0 0xf1002000 0 0x2000>,
+				<0 0xf1004000 0 0x2000>,
+				<0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
 
-	ipmmu_sy1: mmu@e6290000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6290000 0 0x1000>;
-		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7793";
+			reg = <0 0xfeb00000 0 0x40000>,
+			      <0 0xfeb90000 0 0x1c>;
+			reg-names = "du", "lvds.0";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>,
+				 <&cpg CPG_MOD 723>,
+				 <&cpg CPG_MOD 726>;
+			clock-names = "du.0", "du.1", "lvds.0";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_lvds0: endpoint {
+					};
+				};
+			};
+		};
 
-	ipmmu_ds: mmu@e6740000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6740000 0 0x1000>;
-		interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
+		};
 
-	ipmmu_mp: mmu@ec680000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xec680000 0 0x1000>;
-		interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		cmt0: timer@ffca0000 {
+			compatible = "renesas,r8a7793-cmt0",
+				     "renesas,rcar-gen2-cmt0";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 124>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 124>;
+
+			status = "disabled";
+		};
 
-	ipmmu_mx: mmu@fe951000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xfe951000 0 0x1000>;
-		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
+		cmt1: timer@e6130000 {
+			compatible = "renesas,r8a7793-cmt1",
+				     "renesas,rcar-gen2-cmt1";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 329>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
+			resets = <&cpg 329>;
+
+			status = "disabled";
+		};
 	};
 
-	ipmmu_rt: mmu@ffc80000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xffc80000 0 0x1000>;
-		interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
 
-	ipmmu_gp: mmu@e62a0000 {
-		compatible = "renesas,ipmmu-r8a7793", "renesas,ipmmu-vmsa";
-		reg = <0 0xe62a0000 0 0x1000>;
-		interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+			thermal-sensors = <&thermal>;
 
-	rcar_sound: sound@ec500000 {
-		/*
-		 * #sound-dai-cells is required
-		 *
-		 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
-		 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
-		 */
-		compatible =  "renesas,rcar_sound-r8a7793", "renesas,rcar_sound-gen2";
-		reg =	<0 0xec500000 0 0x1000>, /* SCU */
-			<0 0xec5a0000 0 0x100>,  /* ADG */
-			<0 0xec540000 0 0x1000>, /* SSIU */
-			<0 0xec541000 0 0x280>,  /* SSI */
-			<0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
-		reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
-
-		clocks = <&cpg CPG_MOD 1005>,
-			 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
-			 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
-			 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
-			 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
-			 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
-			 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
-			 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
-			 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
-			 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
-			 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
-			 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
-			 <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>,
-			 <&cpg CPG_CORE R8A7793_CLK_M2>;
-		clock-names = "ssi-all",
-				"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-				"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
-				"src.9", "src.8", "src.7", "src.6", "src.5",
-				"src.4", "src.3", "src.2", "src.1", "src.0",
-				"dvc.0", "dvc.1",
-				"clk_a", "clk_b", "clk_c", "clk_i";
-		power-domains = <&sysc R8A7793_PD_ALWAYS_ON>;
-		resets = <&cpg 1005>,
-			 <&cpg 1006>, <&cpg 1007>, <&cpg 1008>, <&cpg 1009>,
-			 <&cpg 1010>, <&cpg 1011>, <&cpg 1012>, <&cpg 1013>,
-			 <&cpg 1014>, <&cpg 1015>;
-		reset-names = "ssi-all",
-			      "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-			      "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0";
-
-		status = "disabled";
-
-		rcar_sound,dvc {
-			dvc0: dvc-0 {
-				dmas = <&audma1 0xbc>;
-				dma-names = "tx";
+			trips {
+				cpu-crit {
+					temperature = <95000>;
+					hysteresis = <0>;
+					type = "critical";
+				};
 			};
-			dvc1: dvc-1 {
-				dmas = <&audma1 0xbe>;
-				dma-names = "tx";
+			cooling-maps {
 			};
 		};
+	};
 
-		rcar_sound,src {
-			src0: src-0 {
-				interrupts = <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x85>, <&audma1 0x9a>;
-				dma-names = "rx", "tx";
-			};
-			src1: src-1 {
-				interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x87>, <&audma1 0x9c>;
-				dma-names = "rx", "tx";
-			};
-			src2: src-2 {
-				interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x89>, <&audma1 0x9e>;
-				dma-names = "rx", "tx";
-			};
-			src3: src-3 {
-				interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8b>, <&audma1 0xa0>;
-				dma-names = "rx", "tx";
-			};
-			src4: src-4 {
-				interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8d>, <&audma1 0xb0>;
-				dma-names = "rx", "tx";
-			};
-			src5: src-5 {
-				interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8f>, <&audma1 0xb2>;
-				dma-names = "rx", "tx";
-			};
-			src6: src-6 {
-				interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x91>, <&audma1 0xb4>;
-				dma-names = "rx", "tx";
-			};
-			src7: src-7 {
-				interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x93>, <&audma1 0xb6>;
-				dma-names = "rx", "tx";
-			};
-			src8: src-8 {
-				interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x95>, <&audma1 0xb8>;
-				dma-names = "rx", "tx";
-			};
-			src9: src-9 {
-				interrupts = <GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x97>, <&audma1 0xba>;
-				dma-names = "rx", "tx";
-			};
-		};
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+	};
 
-		rcar_sound,ssi {
-			ssi0: ssi-0 {
-				interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi1: ssi-1 {
-				 interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi2: ssi-2 {
-				interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi3: ssi-3 {
-				interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi4: ssi-4 {
-				interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi5: ssi-5 {
-				interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi6: ssi-6 {
-				interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi7: ssi-7 {
-				interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi8: ssi-8 {
-				interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi9: ssi-9 {
-				interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-		};
+	/* External USB clock - can be overridden by the board */
+	usb_extal_clk: usb_extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <48000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index 60c6515c4996..1ecc5b9135f3 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -18,7 +18,9 @@
 
 	aliases {
 		serial0 = &scif2;
+		i2c9 = &gpioi2c1;
 		i2c10 = &gpioi2c4;
+		i2c11 = &i2chdmi;
 		i2c12 = &i2cexio4;
 	};
 
@@ -138,16 +140,49 @@
 		clock-frequency = <148500000>;
 	};
 
+	gpioi2c1: i2c-9 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio4 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio4 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	};
+
 	gpioi2c4: i2c-10 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "i2c-gpio";
 		status = "disabled";
-		sda-gpios = <&gpio4 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 		scl-gpios = <&gpio4 8 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio4 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
 		i2c-gpio,delay-us = <5>;
 	};
 
+	/*
+	 * A fallback to GPIO is provided for I2C1.
+	 */
+	i2chdmi: i2c-11 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c1>, <&gpioi2c1>;
+		i2c-bus-name = "i2c-hdmi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		composite-in@20 {
+			compatible = "adi,adv7180";
+			reg = <0x20>;
+			remote = <&vin0>;
+
+			port {
+				adv7180: endpoint {
+					bus-width = <8>;
+					remote-endpoint = <&vin0ep>;
+				};
+			};
+		};
+	};
+
 	/*
 	 * I2C4 is routed to EXIO connector B, pins 73 (SCL) + 74 (SDA).
 	 * A fallback to GPIO is provided.
@@ -295,6 +330,11 @@
 	status = "okay";
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &sdhi0 {
 	pinctrl-0 = <&sdhi0_pins>;
 	pinctrl-1 = <&sdhi0_pins_uhs>;
@@ -324,23 +364,9 @@
 
 &i2c1 {
 	pinctrl-0 = <&i2c1_pins>;
-	pinctrl-names = "default";
+	pinctrl-names = "i2c-hdmi";
 
-	status = "okay";
 	clock-frequency = <400000>;
-
-	composite-in@20 {
-		compatible = "adi,adv7180";
-		reg = <0x20>;
-		remote = <&vin0>;
-
-		port {
-			adv7180: endpoint {
-				bus-width = <8>;
-				remote-endpoint = <&vin0ep>;
-			};
-		};
-	};
 };
 
 &i2c4 {
diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts
index edfad0e5ac53..047508cbefab 100644
--- a/arch/arm/boot/dts/r8a7794-silk.dts
+++ b/arch/arm/boot/dts/r8a7794-silk.dts
@@ -31,6 +31,8 @@
 
 	aliases {
 		serial0 = &scif2;
+		i2c9 = &gpioi2c1;
+		i2c10 = &i2chdmi;
 	};
 
 	chosen {
@@ -153,6 +155,78 @@
 			clocks = <&x9_clk>;
 		};
 	};
+
+	gpioi2c1: i2c-9 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		status = "disabled";
+		scl-gpios = <&gpio4 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		sda-gpios = <&gpio4 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+		i2c-gpio,delay-us = <5>;
+	};
+
+	/*
+	 * A fallback to GPIO is provided for I2C1.
+	 */
+	i2chdmi: i2c-10 {
+		compatible = "i2c-demux-pinctrl";
+		i2c-parent = <&i2c1>, <&gpioi2c1>;
+		i2c-bus-name = "i2c-hdmi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ak4643: codec@12 {
+			compatible = "asahi-kasei,ak4643";
+			#sound-dai-cells = <0>;
+			reg = <0x12>;
+		};
+
+		composite-in@20 {
+			compatible = "adi,adv7180";
+			reg = <0x20>;
+			remote = <&vin0>;
+
+			port {
+				adv7180: endpoint {
+					bus-width = <8>;
+					remote-endpoint = <&vin0ep>;
+				};
+			};
+		};
+
+		hdmi@39 {
+			compatible = "adi,adv7511w";
+			reg = <0x39>;
+			interrupt-parent = <&gpio5>;
+			interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+
+			adi,input-depth = <8>;
+			adi,input-colorspace = "rgb";
+			adi,input-clock = "1x";
+			adi,input-style = <1>;
+			adi,input-justification = "evenly";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					adv7511_in: endpoint {
+						remote-endpoint = <&du_out_rgb0>;
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					adv7511_out: endpoint {
+						remote-endpoint = <&hdmi_con>;
+					};
+				};
+			};
+		};
+	};
 };
 
 &extal_clk {
@@ -268,61 +342,9 @@
 
 &i2c1 {
 	pinctrl-0 = <&i2c1_pins>;
-	pinctrl-names = "default";
+	pinctrl-names = "i2c-hdmi";
 
-	status = "okay";
 	clock-frequency = <400000>;
-
-	ak4643: codec@12 {
-		compatible = "asahi-kasei,ak4643";
-		#sound-dai-cells = <0>;
-		reg = <0x12>;
-	};
-
-	composite-in@20 {
-		compatible = "adi,adv7180";
-		reg = <0x20>;
-		remote = <&vin0>;
-
-		port {
-			adv7180: endpoint {
-				bus-width = <8>;
-				remote-endpoint = <&vin0ep>;
-			};
-		};
-	};
-
-	hdmi@39 {
-		compatible = "adi,adv7511w";
-		reg = <0x39>;
-		interrupt-parent = <&gpio5>;
-		interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
-
-		adi,input-depth = <8>;
-		adi,input-colorspace = "rgb";
-		adi,input-clock = "1x";
-		adi,input-style = <1>;
-		adi,input-justification = "evenly";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-				adv7511_in: endpoint {
-					remote-endpoint = <&du_out_rgb0>;
-				};
-			};
-
-			port@1 {
-				reg = <1>;
-				adv7511_out: endpoint {
-					remote-endpoint = <&hdmi_con>;
-				};
-			};
-		};
-	};
 };
 
 &mmcif0 {
@@ -457,6 +479,11 @@
 	};
 };
 
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
 &ssi1 {
 	shared-pin;
 };
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index 106b4e1649ff..1c9b149819b1 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -16,7 +16,6 @@
 
 / {
 	compatible = "renesas,r8a7794";
-	interrupt-parent = <&gic>;
 	#address-cells = <2>;
 	#size-cells = <2>;
 
@@ -34,6 +33,35 @@
 		vin1 = &vin1;
 	};
 
+	/*
+	 * The external audio clocks are configured as 0 Hz fixed frequency
+	 * clocks by default.
+	 * Boards that provide audio clocks should override them.
+	 */
+	audio_clka: audio_clka {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clkb: audio_clkb {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+	audio_clkc: audio_clkc {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+
+	/* External CAN clock */
+	can_clk: can {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -67,1290 +95,1323 @@
 		};
 	};
 
-	apmu@e6151000 {
-		compatible = "renesas,r8a7794-apmu", "renesas,apmu";
-		reg = <0 0xe6151000 0 0x188>;
-		cpus = <&cpu0 &cpu1>;
+	/* External root clock */
+	extal_clk: extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	gic: interrupt-controller@f1001000 {
-		compatible = "arm,gic-400";
-		#interrupt-cells = <3>;
-		#address-cells = <0>;
-		interrupt-controller;
-		reg = <0 0xf1001000 0 0x1000>,
-			<0 0xf1002000 0 0x2000>,
-			<0 0xf1004000 0 0x2000>,
-			<0 0xf1006000 0 0x2000>;
-		interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
-		clocks = <&cpg CPG_MOD 408>;
-		clock-names = "clk";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 408>;
+	/* External SCIF clock */
+	scif_clk: scif {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board. */
+		clock-frequency = <0>;
 	};
 
-	gpio0: gpio@e6050000 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6050000 0 0x50>;
-		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 0 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 912>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 912>;
-	};
+	soc {
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
 
-	gpio1: gpio@e6051000 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6051000 0 0x50>;
-		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 32 26>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 911>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 911>;
-	};
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		rwdt: watchdog@e6020000 {
+			compatible = "renesas,r8a7794-wdt",
+				     "renesas,rcar-gen2-wdt";
+			reg = <0 0xe6020000 0 0x0c>;
+			clocks = <&cpg CPG_MOD 402>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 402>;
+			status = "disabled";
+		};
 
-	gpio2: gpio@e6052000 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6052000 0 0x50>;
-		interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 64 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 910>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 910>;
-	};
+		gpio0: gpio@e6050000 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6050000 0 0x50>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 0 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 912>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 912>;
+		};
 
-	gpio3: gpio@e6053000 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6053000 0 0x50>;
-		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 96 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 909>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 909>;
-	};
+		gpio1: gpio@e6051000 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6051000 0 0x50>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 32 26>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 911>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 911>;
+		};
 
-	gpio4: gpio@e6054000 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6054000 0 0x50>;
-		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 128 32>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 908>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 908>;
-	};
+		gpio2: gpio@e6052000 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6052000 0 0x50>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 64 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 910>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 910>;
+		};
 
-	gpio5: gpio@e6055000 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055000 0 0x50>;
-		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 160 28>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 907>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 907>;
-	};
+		gpio3: gpio@e6053000 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6053000 0 0x50>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 96 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 909>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 909>;
+		};
 
-	gpio6: gpio@e6055400 {
-		compatible = "renesas,gpio-r8a7794", "renesas,rcar-gen2-gpio";
-		reg = <0 0xe6055400 0 0x50>;
-		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-		#gpio-cells = <2>;
-		gpio-controller;
-		gpio-ranges = <&pfc 0 192 26>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		clocks = <&cpg CPG_MOD 905>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 905>;
-	};
+		gpio4: gpio@e6054000 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6054000 0 0x50>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 128 32>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 908>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 908>;
+		};
 
-	cmt0: timer@ffca0000 {
-		compatible = "renesas,r8a7794-cmt0", "renesas,rcar-gen2-cmt0";
-		reg = <0 0xffca0000 0 0x1004>;
-		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 124>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 124>;
-
-		status = "disabled";
-	};
+		gpio5: gpio@e6055000 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055000 0 0x50>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 160 28>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 907>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 907>;
+		};
 
-	cmt1: timer@e6130000 {
-		compatible = "renesas,r8a7794-cmt1", "renesas,rcar-gen2-cmt1";
-		reg = <0 0xe6130000 0 0x1004>;
-		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 329>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 329>;
-
-		status = "disabled";
-	};
+		gpio6: gpio@e6055400 {
+			compatible = "renesas,gpio-r8a7794",
+				     "renesas,rcar-gen2-gpio";
+			reg = <0 0xe6055400 0 0x50>;
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 192 26>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 905>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 905>;
+		};
 
-	timer {
-		compatible = "arm,armv7-timer";
-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
-	};
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a7794";
+			reg = <0 0xe6060000 0 0x11c>;
+		};
 
-	irqc0: interrupt-controller@e61c0000 {
-		compatible = "renesas,irqc-r8a7794", "renesas,irqc";
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0 0xe61c0000 0 0x200>;
-		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 407>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 407>;
-	};
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a7794-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>, <&usb_extal_clk>;
+			clock-names = "extal", "usb_extal";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
 
-	pfc: pin-controller@e6060000 {
-		compatible = "renesas,pfc-r8a7794";
-		reg = <0 0xe6060000 0 0x11c>;
-	};
+		apmu@e6151000 {
+			compatible = "renesas,r8a7794-apmu", "renesas,apmu";
+			reg = <0 0xe6151000 0 0x188>;
+			cpus = <&cpu0 &cpu1>;
+		};
 
-	dmac0: dma-controller@e6700000 {
-		compatible = "renesas,dmac-r8a7794", "renesas,rcar-dmac";
-		reg = <0 0xe6700000 0 0x20000>;
-		interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 219>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 219>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a7794-rst";
+			reg = <0 0xe6160000 0 0x0100>;
+		};
 
-	dmac1: dma-controller@e6720000 {
-		compatible = "renesas,dmac-r8a7794", "renesas,rcar-dmac";
-		reg = <0 0xe6720000 0 0x20000>;
-		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
-			      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				"ch0", "ch1", "ch2", "ch3",
-				"ch4", "ch5", "ch6", "ch7",
-				"ch8", "ch9", "ch10", "ch11",
-				"ch12", "ch13", "ch14";
-		clocks = <&cpg CPG_MOD 218>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 218>;
-		#dma-cells = <1>;
-		dma-channels = <15>;
-	};
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a7794-sysc";
+			reg = <0 0xe6180000 0 0x0200>;
+			#power-domain-cells = <1>;
+		};
 
-	audma0: dma-controller@ec700000 {
-		compatible = "renesas,dmac-r8a7794", "renesas,rcar-dmac";
-		reg = <0 0xec700000 0 0x10000>;
-		interrupts =	<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
-				 GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
-		interrupt-names = "error",
-				  "ch0", "ch1", "ch2", "ch3", "ch4", "ch5",
-				  "ch6", "ch7", "ch8", "ch9", "ch10", "ch11",
-				  "ch12";
-		clocks = <&cpg CPG_MOD 502>;
-		clock-names = "fck";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 502>;
-		#dma-cells = <1>;
-		dma-channels = <13>;
-	};
+		irqc0: interrupt-controller@e61c0000 {
+			compatible = "renesas,irqc-r8a7794", "renesas,irqc";
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			reg = <0 0xe61c0000 0 0x200>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 407>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 407>;
+		};
 
-	scifa0: serial@e6c40000 {
-		compatible = "renesas,scifa-r8a7794",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c40000 0 64>;
-		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 204>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x21>, <&dmac0 0x22>,
-		       <&dmac1 0x21>, <&dmac1 0x22>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 204>;
-		status = "disabled";
-	};
+		ipmmu_sy0: mmu@e6280000 {
+			compatible = "renesas,ipmmu-r8a7794",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6280000 0 0x1000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	scifa1: serial@e6c50000 {
-		compatible = "renesas,scifa-r8a7794",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c50000 0 64>;
-		interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 203>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x25>, <&dmac0 0x26>,
-		       <&dmac1 0x25>, <&dmac1 0x26>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 203>;
-		status = "disabled";
-	};
+		ipmmu_sy1: mmu@e6290000 {
+			compatible = "renesas,ipmmu-r8a7794",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6290000 0 0x1000>;
+			interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	scifa2: serial@e6c60000 {
-		compatible = "renesas,scifa-r8a7794",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c60000 0 64>;
-		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 202>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x27>, <&dmac0 0x28>,
-		       <&dmac1 0x27>, <&dmac1 0x28>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 202>;
-		status = "disabled";
-	};
+		ipmmu_ds: mmu@e6740000 {
+			compatible = "renesas,ipmmu-r8a7794",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe6740000 0 0x1000>;
+			interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	scifa3: serial@e6c70000 {
-		compatible = "renesas,scifa-r8a7794",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c70000 0 64>;
-		interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1106>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
-		       <&dmac1 0x1b>, <&dmac1 0x1c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 1106>;
-		status = "disabled";
-	};
+		ipmmu_mp: mmu@ec680000 {
+			compatible = "renesas,ipmmu-r8a7794",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xec680000 0 0x1000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	scifa4: serial@e6c78000 {
-		compatible = "renesas,scifa-r8a7794",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c78000 0 64>;
-		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1107>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
-		       <&dmac1 0x1f>, <&dmac1 0x20>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 1107>;
-		status = "disabled";
-	};
+		ipmmu_mx: mmu@fe951000 {
+			compatible = "renesas,ipmmu-r8a7794",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xfe951000 0 0x1000>;
+			interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	scifa5: serial@e6c80000 {
-		compatible = "renesas,scifa-r8a7794",
-			     "renesas,rcar-gen2-scifa", "renesas,scifa";
-		reg = <0 0xe6c80000 0 64>;
-		interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 1108>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x23>, <&dmac0 0x24>,
-		       <&dmac1 0x23>, <&dmac1 0x24>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 1108>;
-		status = "disabled";
-	};
+		ipmmu_gp: mmu@e62a0000 {
+			compatible = "renesas,ipmmu-r8a7794",
+				     "renesas,ipmmu-vmsa";
+			reg = <0 0xe62a0000 0 0x1000>;
+			interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			status = "disabled";
+		};
 
-	scifb0: serial@e6c20000 {
-		compatible = "renesas,scifb-r8a7794",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c20000 0 0x100>;
-		interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 206>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
-		       <&dmac1 0x3d>, <&dmac1 0x3e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 206>;
-		status = "disabled";
-	};
+		icram0:	sram@e63a0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63a0000 0 0x12000>;
+		};
 
-	scifb1: serial@e6c30000 {
-		compatible = "renesas,scifb-r8a7794",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6c30000 0 0x100>;
-		interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 207>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
-		       <&dmac1 0x19>, <&dmac1 0x1a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 207>;
-		status = "disabled";
-	};
+		icram1:	sram@e63c0000 {
+			compatible = "mmio-sram";
+			reg = <0 0xe63c0000 0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0 0xe63c0000 0x1000>;
 
-	scifb2: serial@e6ce0000 {
-		compatible = "renesas,scifb-r8a7794",
-			     "renesas,rcar-gen2-scifb", "renesas,scifb";
-		reg = <0 0xe6ce0000 0 0x100>;
-		interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 216>;
-		clock-names = "fck";
-		dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
-		       <&dmac1 0x1d>, <&dmac1 0x1e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 216>;
-		status = "disabled";
-	};
+			smp-sram@0 {
+				compatible = "renesas,smp-sram";
+				reg = <0 0x100>;
+			};
+		};
 
-	scif0: serial@e6e60000 {
-		compatible = "renesas,scif-r8a7794", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e60000 0 64>;
-		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
-		       <&dmac1 0x29>, <&dmac1 0x2a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 721>;
-		status = "disabled";
-	};
+		/* The memory map in the User's Manual maps the cores to
+		 * bus numbers
+		 */
+		i2c0: i2c@e6508000 {
+			compatible = "renesas,i2c-r8a7794",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 931>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scif1: serial@e6e68000 {
-		compatible = "renesas,scif-r8a7794", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e68000 0 64>;
-		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
-		       <&dmac1 0x2d>, <&dmac1 0x2e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 720>;
-		status = "disabled";
-	};
+		i2c1: i2c@e6518000 {
+			compatible = "renesas,i2c-r8a7794",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6518000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 930>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scif2: serial@e6e58000 {
-		compatible = "renesas,scif-r8a7794", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6e58000 0 64>;
-		interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 719>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
-		       <&dmac1 0x2b>, <&dmac1 0x2c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 719>;
-		status = "disabled";
-	};
+		i2c2: i2c@e6530000 {
+			compatible = "renesas,i2c-r8a7794",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6530000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 929>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scif3: serial@e6ea8000 {
-		compatible = "renesas,scif-r8a7794", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ea8000 0 64>;
-		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 718>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
-		       <&dmac1 0x2f>, <&dmac1 0x30>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 718>;
-		status = "disabled";
-	};
+		i2c3: i2c@e6540000 {
+			compatible = "renesas,i2c-r8a7794",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6540000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 928>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scif4: serial@e6ee0000 {
-		compatible = "renesas,scif-r8a7794", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ee0000 0 64>;
-		interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 715>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
-		       <&dmac1 0xfb>, <&dmac1 0xfc>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 715>;
-		status = "disabled";
-	};
+		i2c4: i2c@e6520000 {
+			compatible = "renesas,i2c-r8a7794",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6520000 0 0x40>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 927>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 927>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	scif5: serial@e6ee8000 {
-		compatible = "renesas,scif-r8a7794", "renesas,rcar-gen2-scif",
-			     "renesas,scif";
-		reg = <0 0xe6ee8000 0 64>;
-		interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 714>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
-		       <&dmac1 0xfd>, <&dmac1 0xfe>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 714>;
-		status = "disabled";
-	};
+		i2c5: i2c@e6528000 {
+			compatible = "renesas,i2c-r8a7794",
+				     "renesas,rcar-gen2-i2c";
+			reg = <0 0xe6528000 0 0x40>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 925>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 925>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
 
-	hscif0: serial@e62c0000 {
-		compatible = "renesas,hscif-r8a7794",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c0000 0 96>;
-		interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 717>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
-		       <&dmac1 0x39>, <&dmac1 0x3a>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 717>;
-		status = "disabled";
-	};
+		i2c6: i2c@e6500000 {
+			compatible = "renesas,iic-r8a7794",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6500000 0 0x425>;
+			interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 318>;
+			dmas = <&dmac0 0x61>, <&dmac0 0x62>,
+			       <&dmac1 0x61>, <&dmac1 0x62>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 318>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	hscif1: serial@e62c8000 {
-		compatible = "renesas,hscif-r8a7794",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62c8000 0 96>;
-		interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 716>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
-		       <&dmac1 0x4d>, <&dmac1 0x4e>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 716>;
-		status = "disabled";
-	};
+		i2c7: i2c@e6510000 {
+			compatible = "renesas,iic-r8a7794",
+				     "renesas,rcar-gen2-iic",
+				     "renesas,rmobile-iic";
+			reg = <0 0xe6510000 0 0x425>;
+			interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 323>;
+			dmas = <&dmac0 0x65>, <&dmac0 0x66>,
+			       <&dmac1 0x65>, <&dmac1 0x66>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 323>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	hscif2: serial@e62d0000 {
-		compatible = "renesas,hscif-r8a7794",
-			     "renesas,rcar-gen2-hscif", "renesas,hscif";
-		reg = <0 0xe62d0000 0 96>;
-		interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 713>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
-			 <&scif_clk>;
-		clock-names = "fck", "brg_int", "scif_clk";
-		dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
-		       <&dmac1 0x3b>, <&dmac1 0x3c>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 713>;
-		status = "disabled";
-	};
+		hsusb: usb@e6590000 {
+			compatible = "renesas,usbhs-r8a7794",
+				     "renesas,rcar-gen2-usbhs";
+			reg = <0 0xe6590000 0 0x100>;
+			interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 704>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			renesas,buswait = <4>;
+			phys = <&usb0 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
 
-	icram0:	sram@e63a0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63a0000 0 0x12000>;
-	};
+		usbphy: usb-phy@e6590100 {
+			compatible = "renesas,usb-phy-r8a7794",
+				     "renesas,rcar-gen2-usb-phy";
+			reg = <0 0xe6590100 0 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&cpg CPG_MOD 704>;
+			clock-names = "usbhs";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 704>;
+			status = "disabled";
 
-	icram1:	sram@e63c0000 {
-		compatible = "mmio-sram";
-		reg = <0 0xe63c0000 0 0x1000>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0 0 0xe63c0000 0x1000>;
+			usb0: usb-channel@0 {
+				reg = <0>;
+				#phy-cells = <1>;
+			};
+			usb2: usb-channel@2 {
+				reg = <2>;
+				#phy-cells = <1>;
+			};
+		};
 
-		smp-sram@0 {
-			compatible = "renesas,smp-sram";
-			reg = <0 0x10>;
+		dmac0: dma-controller@e6700000 {
+			compatible = "renesas,dmac-r8a7794",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6700000 0 0x20000>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 219>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 219>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
 		};
-	};
 
-	ether: ethernet@ee700000 {
-		compatible = "renesas,ether-r8a7794",
-			     "renesas,rcar-gen2-ether";
-		reg = <0 0xee700000 0 0x400>;
-		interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 813>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 813>;
-		phy-mode = "rmii";
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		dmac1: dma-controller@e6720000 {
+			compatible = "renesas,dmac-r8a7794",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe6720000 0 0x20000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <15>;
+		};
 
-	avb: ethernet@e6800000 {
-		compatible = "renesas,etheravb-r8a7794",
-			     "renesas,etheravb-rcar-gen2";
-		reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
-		interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 812>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 812>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		avb: ethernet@e6800000 {
+			compatible = "renesas,etheravb-r8a7794",
+				     "renesas,etheravb-rcar-gen2";
+			reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+			interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 812>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 812>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	/* The memory map in the User's Manual maps the cores to bus numbers */
-	i2c0: i2c@e6508000 {
-		compatible = "renesas,i2c-r8a7794", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6508000 0 0x40>;
-		interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 931>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 931>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		qspi: spi@e6b10000 {
+			compatible = "renesas,qspi-r8a7794", "renesas,qspi";
+			reg = <0 0xe6b10000 0 0x2c>;
+			interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 917>;
+			dmas = <&dmac0 0x17>, <&dmac0 0x18>,
+			       <&dmac1 0x17>, <&dmac1 0x18>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 917>;
+			num-cs = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	i2c1: i2c@e6518000 {
-		compatible = "renesas,i2c-r8a7794", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6518000 0 0x40>;
-		interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 930>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 930>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		scifa0: serial@e6c40000 {
+			compatible = "renesas,scifa-r8a7794",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c40000 0 64>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 204>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x21>, <&dmac0 0x22>,
+			       <&dmac1 0x21>, <&dmac1 0x22>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 204>;
+			status = "disabled";
+		};
 
-	i2c2: i2c@e6530000 {
-		compatible = "renesas,i2c-r8a7794", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6530000 0 0x40>;
-		interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 929>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 929>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		scifa1: serial@e6c50000 {
+			compatible = "renesas,scifa-r8a7794",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c50000 0 64>;
+			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 203>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x25>, <&dmac0 0x26>,
+			       <&dmac1 0x25>, <&dmac1 0x26>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 203>;
+			status = "disabled";
+		};
 
-	i2c3: i2c@e6540000 {
-		compatible = "renesas,i2c-r8a7794", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6540000 0 0x40>;
-		interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 928>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 928>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		scifa2: serial@e6c60000 {
+			compatible = "renesas,scifa-r8a7794",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c60000 0 64>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 202>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x27>, <&dmac0 0x28>,
+			       <&dmac1 0x27>, <&dmac1 0x28>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 202>;
+			status = "disabled";
+		};
 
-	i2c4: i2c@e6520000 {
-		compatible = "renesas,i2c-r8a7794", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6520000 0 0x40>;
-		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 927>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 927>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		scifa3: serial@e6c70000 {
+			compatible = "renesas,scifa-r8a7794",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c70000 0 64>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1106>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1b>, <&dmac0 0x1c>,
+			       <&dmac1 0x1b>, <&dmac1 0x1c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 1106>;
+			status = "disabled";
+		};
 
-	i2c5: i2c@e6528000 {
-		compatible = "renesas,i2c-r8a7794", "renesas,rcar-gen2-i2c";
-		reg = <0 0xe6528000 0 0x40>;
-		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 925>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 925>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		i2c-scl-internal-delay-ns = <6>;
-		status = "disabled";
-	};
+		scifa4: serial@e6c78000 {
+			compatible = "renesas,scifa-r8a7794",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c78000 0 64>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1107>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1f>, <&dmac0 0x20>,
+			       <&dmac1 0x1f>, <&dmac1 0x20>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 1107>;
+			status = "disabled";
+		};
 
-	i2c6: i2c@e6500000 {
-		compatible = "renesas,iic-r8a7794", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6500000 0 0x425>;
-		interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 318>;
-		dmas = <&dmac0 0x61>, <&dmac0 0x62>,
-		       <&dmac1 0x61>, <&dmac1 0x62>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 318>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scifa5: serial@e6c80000 {
+			compatible = "renesas,scifa-r8a7794",
+				     "renesas,rcar-gen2-scifa", "renesas,scifa";
+			reg = <0 0xe6c80000 0 64>;
+			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 1108>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x23>, <&dmac0 0x24>,
+			       <&dmac1 0x23>, <&dmac1 0x24>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 1108>;
+			status = "disabled";
+		};
 
-	i2c7: i2c@e6510000 {
-		compatible = "renesas,iic-r8a7794", "renesas,rcar-gen2-iic",
-			     "renesas,rmobile-iic";
-		reg = <0 0xe6510000 0 0x425>;
-		interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 323>;
-		dmas = <&dmac0 0x65>, <&dmac0 0x66>,
-		       <&dmac1 0x65>, <&dmac1 0x66>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 323>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scifb0: serial@e6c20000 {
+			compatible = "renesas,scifb-r8a7794",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c20000 0 0x100>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 206>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x3d>, <&dmac0 0x3e>,
+			       <&dmac1 0x3d>, <&dmac1 0x3e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 206>;
+			status = "disabled";
+		};
 
-	mmcif0: mmc@ee200000 {
-		compatible = "renesas,mmcif-r8a7794", "renesas,sh-mmcif";
-		reg = <0 0xee200000 0 0x80>;
-		interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 315>;
-		dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
-		       <&dmac1 0xd1>, <&dmac1 0xd2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 315>;
-		reg-io-width = <4>;
-		status = "disabled";
-	};
+		scifb1: serial@e6c30000 {
+			compatible = "renesas,scifb-r8a7794",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6c30000 0 0x100>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 207>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x19>, <&dmac0 0x1a>,
+			       <&dmac1 0x19>, <&dmac1 0x1a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 207>;
+			status = "disabled";
+		};
 
-	sdhi0: sd@ee100000 {
-		compatible = "renesas,sdhi-r8a7794",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee100000 0 0x328>;
-		interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 314>;
-		dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
-		       <&dmac1 0xcd>, <&dmac1 0xce>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <195000000>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 314>;
-		status = "disabled";
-	};
+		scifb2: serial@e6ce0000 {
+			compatible = "renesas,scifb-r8a7794",
+				     "renesas,rcar-gen2-scifb", "renesas,scifb";
+			reg = <0 0xe6ce0000 0 0x100>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 216>;
+			clock-names = "fck";
+			dmas = <&dmac0 0x1d>, <&dmac0 0x1e>,
+			       <&dmac1 0x1d>, <&dmac1 0x1e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 216>;
+			status = "disabled";
+		};
 
-	sdhi1: sd@ee140000 {
-		compatible = "renesas,sdhi-r8a7794",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee140000 0 0x100>;
-		interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 312>;
-		dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
-		       <&dmac1 0xc1>, <&dmac1 0xc2>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 312>;
-		status = "disabled";
-	};
+		scif0: serial@e6e60000 {
+			compatible = "renesas,scif-r8a7794",
+				     "renesas,rcar-gen2-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e60000 0 64>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x29>, <&dmac0 0x2a>,
+			       <&dmac1 0x29>, <&dmac1 0x2a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 721>;
+			status = "disabled";
+		};
 
-	sdhi2: sd@ee160000 {
-		compatible = "renesas,sdhi-r8a7794",
-			     "renesas,rcar-gen2-sdhi";
-		reg = <0 0xee160000 0 0x100>;
-		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 311>;
-		dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
-		       <&dmac1 0xd3>, <&dmac1 0xd4>;
-		dma-names = "tx", "rx", "tx", "rx";
-		max-frequency = <97500000>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 311>;
-		status = "disabled";
-	};
+		scif1: serial@e6e68000 {
+			compatible = "renesas,scif-r8a7794",
+				     "renesas,rcar-gen2-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e68000 0 64>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 720>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2d>, <&dmac0 0x2e>,
+			       <&dmac1 0x2d>, <&dmac1 0x2e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 720>;
+			status = "disabled";
+		};
 
-	qspi: spi@e6b10000 {
-		compatible = "renesas,qspi-r8a7794", "renesas,qspi";
-		reg = <0 0xe6b10000 0 0x2c>;
-		interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 917>;
-		dmas = <&dmac0 0x17>, <&dmac0 0x18>,
-		       <&dmac1 0x17>, <&dmac1 0x18>;
-		dma-names = "tx", "rx", "tx", "rx";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 917>;
-		num-cs = <1>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		status = "disabled";
-	};
+		scif2: serial@e6e58000 {
+			compatible = "renesas,scif-r8a7794",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6e58000 0 64>;
+			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 719>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2b>, <&dmac0 0x2c>,
+			       <&dmac1 0x2b>, <&dmac1 0x2c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 719>;
+			status = "disabled";
+		};
 
-	vin0: video@e6ef0000 {
-		compatible = "renesas,vin-r8a7794", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef0000 0 0x1000>;
-		interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 811>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 811>;
-		status = "disabled";
-	};
+		scif3: serial@e6ea8000 {
+			compatible = "renesas,scif-r8a7794",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ea8000 0 64>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 718>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x2f>, <&dmac0 0x30>,
+			       <&dmac1 0x2f>, <&dmac1 0x30>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 718>;
+			status = "disabled";
+		};
 
-	vin1: video@e6ef1000 {
-		compatible = "renesas,vin-r8a7794", "renesas,rcar-gen2-vin";
-		reg = <0 0xe6ef1000 0 0x1000>;
-		interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 810>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 810>;
-		status = "disabled";
-	};
+		scif4: serial@e6ee0000 {
+			compatible = "renesas,scif-r8a7794",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee0000 0 64>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 715>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfb>, <&dmac0 0xfc>,
+			       <&dmac1 0xfb>, <&dmac1 0xfc>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 715>;
+			status = "disabled";
+		};
 
-	pci0: pci@ee090000 {
-		compatible = "renesas,pci-r8a7794", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		reg = <0 0xee090000 0 0xc00>,
-		      <0 0xee080000 0 0x1100>;
-		interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		status = "disabled";
-
-		bus-range = <0 0>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-
-		usb@1,0 {
-			reg = <0x800 0 0 0 0>;
-			phys = <&usb0 0>;
-			phy-names = "usb";
+		scif5: serial@e6ee8000 {
+			compatible = "renesas,scif-r8a7794",
+				     "renesas,rcar-gen2-scif", "renesas,scif";
+			reg = <0 0xe6ee8000 0 64>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 714>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0xfd>, <&dmac0 0xfe>,
+			       <&dmac1 0xfd>, <&dmac1 0xfe>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 714>;
+			status = "disabled";
 		};
 
-		usb@2,0 {
-			reg = <0x1000 0 0 0 0>;
-			phys = <&usb0 0>;
-			phy-names = "usb";
+		hscif0: serial@e62c0000 {
+			compatible = "renesas,hscif-r8a7794",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c0000 0 96>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 717>,
+				 <&cpg CPG_CORE R8A7794_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x39>, <&dmac0 0x3a>,
+			       <&dmac1 0x39>, <&dmac1 0x3a>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 717>;
+			status = "disabled";
 		};
-	};
 
-	pci1: pci@ee0d0000 {
-		compatible = "renesas,pci-r8a7794", "renesas,pci-rcar-gen2";
-		device_type = "pci";
-		reg = <0 0xee0d0000 0 0xc00>,
-		      <0 0xee0c0000 0 0x1100>;
-		interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 703>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 703>;
-		status = "disabled";
-
-		bus-range = <1 1>;
-		#address-cells = <3>;
-		#size-cells = <2>;
-		#interrupt-cells = <1>;
-		ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
-		interrupt-map-mask = <0xff00 0 0 0x7>;
-		interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-				 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
-				 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
-
-		usb@1,0 {
-			reg = <0x10800 0 0 0 0>;
-			phys = <&usb2 0>;
-			phy-names = "usb";
+		hscif1: serial@e62c8000 {
+			compatible = "renesas,hscif-r8a7794",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62c8000 0 96>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 716>,
+				 <&cpg CPG_CORE R8A7794_CLK_ZS>, <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x4d>, <&dmac0 0x4e>,
+			       <&dmac1 0x4d>, <&dmac1 0x4e>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 716>;
+			status = "disabled";
 		};
 
-		usb@2,0 {
-			reg = <0x11000 0 0 0 0>;
-			phys = <&usb2 0>;
-			phy-names = "usb";
+		hscif2: serial@e62d0000 {
+			compatible = "renesas,hscif-r8a7794",
+				     "renesas,rcar-gen2-hscif", "renesas,hscif";
+			reg = <0 0xe62d0000 0 96>;
+			interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 713>, <&cpg CPG_CORE R8A7794_CLK_ZS>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac0 0x3b>, <&dmac0 0x3c>,
+			       <&dmac1 0x3b>, <&dmac1 0x3c>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 713>;
+			status = "disabled";
 		};
-	};
 
-	hsusb: usb@e6590000 {
-		compatible = "renesas,usbhs-r8a7794", "renesas,rcar-gen2-usbhs";
-		reg = <0 0xe6590000 0 0x100>;
-		interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 704>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 704>;
-		renesas,buswait = <4>;
-		phys = <&usb0 1>;
-		phy-names = "usb";
-		status = "disabled";
-	};
+		can0: can@e6e80000 {
+			compatible = "renesas,can-r8a7794",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e80000 0 0x1000>;
+			interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 916>, <&cpg CPG_CORE R8A7794_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 916>;
+			status = "disabled";
+		};
 
-	usbphy: usb-phy@e6590100 {
-		compatible = "renesas,usb-phy-r8a7794",
-			     "renesas,rcar-gen2-usb-phy";
-		reg = <0 0xe6590100 0 0x100>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		clocks = <&cpg CPG_MOD 704>;
-		clock-names = "usbhs";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 704>;
-		status = "disabled";
+		can1: can@e6e88000 {
+			compatible = "renesas,can-r8a7794",
+				     "renesas,rcar-gen2-can";
+			reg = <0 0xe6e88000 0 0x1000>;
+			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 915>, <&cpg CPG_CORE R8A7794_CLK_RCAN>,
+				 <&can_clk>;
+			clock-names = "clkp1", "clkp2", "can_clk";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 915>;
+			status = "disabled";
+		};
 
-		usb0: usb-channel@0 {
-			reg = <0>;
-			#phy-cells = <1>;
+		vin0: video@e6ef0000 {
+			compatible = "renesas,vin-r8a7794",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef0000 0 0x1000>;
+			interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 811>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 811>;
+			status = "disabled";
 		};
-		usb2: usb-channel@2 {
-			reg = <2>;
-			#phy-cells = <1>;
+
+		vin1: video@e6ef1000 {
+			compatible = "renesas,vin-r8a7794",
+				     "renesas,rcar-gen2-vin";
+			reg = <0 0xe6ef1000 0 0x1000>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 810>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 810>;
+			status = "disabled";
 		};
-	};
 
-	vsp@fe928000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe928000 0 0x8000>;
-		interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 131>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 131>;
-	};
+		rcar_sound: sound@ec500000 {
+			/*
+			 * #sound-dai-cells is required
+			 *
+			 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
+			 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
+			 */
+			compatible = "renesas,rcar_sound-r8a7794",
+				     "renesas,rcar_sound-gen2";
+			reg = <0 0xec500000 0 0x1000>, /* SCU */
+			      <0 0xec5a0000 0 0x100>,  /* ADG */
+			      <0 0xec540000 0 0x1000>, /* SSIU */
+			      <0 0xec541000 0 0x280>,  /* SSI */
+			      <0 0xec740000 0 0x200>;  /* Audio DMAC peri peri */
+			reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+			clocks = <&cpg CPG_MOD 1005>,
+				 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+				 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+				 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+				 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+				 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+				 <&cpg CPG_MOD 1025>, <&cpg CPG_MOD 1026>,
+				 <&cpg CPG_MOD 1027>, <&cpg CPG_MOD 1028>,
+				 <&cpg CPG_MOD 1029>, <&cpg CPG_MOD 1030>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
+				 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+				 <&audio_clka>, <&audio_clkb>, <&audio_clkc>,
+				 <&cpg CPG_CORE R8A7794_CLK_M2>;
+			clock-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0",
+				      "src.6", "src.5", "src.4", "src.3",
+				      "src.2", "src.1",
+				      "ctu.0", "ctu.1",
+				      "mix.0", "mix.1",
+				      "dvc.0", "dvc.1",
+				      "clk_a", "clk_b", "clk_c", "clk_i";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 1005>,
+				 <&cpg 1006>, <&cpg 1007>,
+				 <&cpg 1008>, <&cpg 1009>,
+				 <&cpg 1010>, <&cpg 1011>,
+				 <&cpg 1012>, <&cpg 1013>,
+				 <&cpg 1014>, <&cpg 1015>;
+			reset-names = "ssi-all",
+				      "ssi.9", "ssi.8", "ssi.7", "ssi.6",
+				      "ssi.5", "ssi.4", "ssi.3", "ssi.2",
+				      "ssi.1", "ssi.0";
+
+			status = "disabled";
+
+			rcar_sound,dvc {
+				dvc0: dvc-0 {
+					dmas = <&audma0 0xbc>;
+					dma-names = "tx";
+				};
+				dvc1: dvc-1 {
+					dmas = <&audma0 0xbe>;
+					dma-names = "tx";
+				};
+			};
 
-	vsp@fe930000 {
-		compatible = "renesas,vsp1";
-		reg = <0 0xfe930000 0 0x8000>;
-		interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 128>;
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 128>;
-	};
+			rcar_sound,mix {
+				mix0: mix-0 { };
+				mix1: mix-1 { };
+			};
 
-	du: display@feb00000 {
-		compatible = "renesas,du-r8a7794";
-		reg = <0 0xfeb00000 0 0x40000>;
-		reg-names = "du";
-		interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>;
-		clock-names = "du.0", "du.1";
-		status = "disabled";
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
+			rcar_sound,ctu {
+				ctu00: ctu-0 { };
+				ctu01: ctu-1 { };
+				ctu02: ctu-2 { };
+				ctu03: ctu-3 { };
+				ctu10: ctu-4 { };
+				ctu11: ctu-5 { };
+				ctu12: ctu-6 { };
+				ctu13: ctu-7 { };
+			};
 
-			port@0 {
-				reg = <0>;
-				du_out_rgb0: endpoint {
+			rcar_sound,src {
+				src-0 {
+					status = "disabled";
+				};
+				src1: src-1 {
+					interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x87>, <&audma0 0x9c>;
+					dma-names = "rx", "tx";
+				};
+				src2: src-2 {
+					interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x89>, <&audma0 0x9e>;
+					dma-names = "rx", "tx";
+				};
+				src3: src-3 {
+					interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8b>, <&audma0 0xa0>;
+					dma-names = "rx", "tx";
+				};
+				src4: src-4 {
+					interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8d>, <&audma0 0xb0>;
+					dma-names = "rx", "tx";
+				};
+				src5: src-5 {
+					interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x8f>, <&audma0 0xb2>;
+					dma-names = "rx", "tx";
+				};
+				src6: src-6 {
+					interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x91>, <&audma0 0xb4>;
+					dma-names = "rx", "tx";
 				};
 			};
-			port@1 {
-				reg = <1>;
-				du_out_rgb1: endpoint {
+
+			rcar_sound,ssi {
+				ssi0: ssi-0 {
+					interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x01>, <&audma0 0x02>,
+					       <&audma0 0x15>, <&audma0 0x16>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi1: ssi-1 {
+					interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x03>, <&audma0 0x04>,
+					       <&audma0 0x49>, <&audma0 0x4a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi2: ssi-2 {
+					interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x05>, <&audma0 0x06>,
+					       <&audma0 0x63>, <&audma0 0x64>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi3: ssi-3 {
+					interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x07>, <&audma0 0x08>,
+					       <&audma0 0x6f>, <&audma0 0x70>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi4: ssi-4 {
+					interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x09>, <&audma0 0x0a>,
+					       <&audma0 0x71>, <&audma0 0x72>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi5: ssi-5 {
+					interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0b>, <&audma0 0x0c>,
+					       <&audma0 0x73>, <&audma0 0x74>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi6: ssi-6 {
+					interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0d>, <&audma0 0x0e>,
+					       <&audma0 0x75>, <&audma0 0x76>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi7: ssi-7 {
+					interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x0f>, <&audma0 0x10>,
+					       <&audma0 0x79>, <&audma0 0x7a>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi8: ssi-8 {
+					interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x11>, <&audma0 0x12>,
+					       <&audma0 0x7b>, <&audma0 0x7c>;
+					dma-names = "rx", "tx", "rxu", "txu";
+				};
+				ssi9: ssi-9 {
+					interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&audma0 0x13>, <&audma0 0x14>,
+					       <&audma0 0x7d>, <&audma0 0x7e>;
+					dma-names = "rx", "tx", "rxu", "txu";
 				};
 			};
 		};
-	};
-
-	can0: can@e6e80000 {
-		compatible = "renesas,can-r8a7794", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e80000 0 0x1000>;
-		interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 916>, <&cpg CPG_CORE R8A7794_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 916>;
-		status = "disabled";
-	};
 
-	can1: can@e6e88000 {
-		compatible = "renesas,can-r8a7794", "renesas,rcar-gen2-can";
-		reg = <0 0xe6e88000 0 0x1000>;
-		interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg CPG_MOD 915>, <&cpg CPG_CORE R8A7794_CLK_RCAN>,
-			 <&can_clk>;
-		clock-names = "clkp1", "clkp2", "can_clk";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 915>;
-		status = "disabled";
-	};
-
-	/* External root clock */
-	extal_clk: extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
-
-	/* External USB clock - can be overridden by the board */
-	usb_extal_clk: usb_extal {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <48000000>;
-	};
-
-	/* External CAN clock */
-	can_clk: can {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+		audma0: dma-controller@ec700000 {
+			compatible = "renesas,dmac-r8a7794",
+				     "renesas,rcar-dmac";
+			reg = <0 0xec700000 0 0x10000>;
+			interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3", "ch4",
+					  "ch5", "ch6", "ch7", "ch8", "ch9",
+					  "ch10", "ch11",
+					  "ch12";
+			clocks = <&cpg CPG_MOD 502>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 502>;
+			#dma-cells = <1>;
+			dma-channels = <13>;
+		};
 
-	/* External SCIF clock */
-	scif_clk: scif {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		/* This value must be overridden by the board. */
-		clock-frequency = <0>;
-	};
+		pci0: pci@ee090000 {
+			compatible = "renesas,pci-r8a7794",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee090000 0 0xc00>,
+			      <0 0xee080000 0 0x1100>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x800 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
 
-	/*
-	 * The external audio clocks are configured  as 0 Hz fixed
-	 * frequency clocks by default.  Boards that provide audio
-	 * clocks should override them.
-	 */
-	audio_clka: audio_clka {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clkb: audio_clkb {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
-	audio_clkc: audio_clkc {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
-	};
+			usb@2,0 {
+				reg = <0x1000 0 0 0 0>;
+				phys = <&usb0 0>;
+				phy-names = "usb";
+			};
+		};
 
-	cpg: clock-controller@e6150000 {
-		compatible = "renesas,r8a7794-cpg-mssr";
-		reg = <0 0xe6150000 0 0x1000>;
-		clocks = <&extal_clk>, <&usb_extal_clk>;
-		clock-names = "extal", "usb_extal";
-		#clock-cells = <2>;
-		#power-domain-cells = <0>;
-		#reset-cells = <1>;
-	};
+		pci1: pci@ee0d0000 {
+			compatible = "renesas,pci-r8a7794",
+				     "renesas,pci-rcar-gen2";
+			device_type = "pci";
+			reg = <0 0xee0d0000 0 0xc00>,
+			      <0 0xee0c0000 0 0x1100>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 703>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 703>;
+			status = "disabled";
+
+			bus-range = <1 1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
+			interrupt-map-mask = <0xff00 0 0 0x7>;
+			interrupt-map = <0x0000 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x0800 0 0 1 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
+					 0x1000 0 0 2 &gic GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+
+			usb@1,0 {
+				reg = <0x10800 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
 
-	rst: reset-controller@e6160000 {
-		compatible = "renesas,r8a7794-rst";
-		reg = <0 0xe6160000 0 0x0100>;
-	};
+			usb@2,0 {
+				reg = <0x11000 0 0 0 0>;
+				phys = <&usb2 0>;
+				phy-names = "usb";
+			};
+		};
 
-	prr: chipid@ff000044 {
-		compatible = "renesas,prr";
-		reg = <0 0xff000044 0 4>;
-	};
+		sdhi0: sd@ee100000 {
+			compatible = "renesas,sdhi-r8a7794",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee100000 0 0x328>;
+			interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 314>;
+			dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
+			       <&dmac1 0xcd>, <&dmac1 0xce>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <195000000>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 314>;
+			status = "disabled";
+		};
 
-	sysc: system-controller@e6180000 {
-		compatible = "renesas,r8a7794-sysc";
-		reg = <0 0xe6180000 0 0x0200>;
-		#power-domain-cells = <1>;
-	};
+		sdhi1: sd@ee140000 {
+			compatible = "renesas,sdhi-r8a7794",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee140000 0 0x100>;
+			interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 312>;
+			dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
+			       <&dmac1 0xc1>, <&dmac1 0xc2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 312>;
+			status = "disabled";
+		};
 
-	ipmmu_sy0: mmu@e6280000 {
-		compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6280000 0 0x1000>;
-		interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		sdhi2: sd@ee160000 {
+			compatible = "renesas,sdhi-r8a7794",
+				     "renesas,rcar-gen2-sdhi";
+			reg = <0 0xee160000 0 0x100>;
+			interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 311>;
+			dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
+			       <&dmac1 0xd3>, <&dmac1 0xd4>;
+			dma-names = "tx", "rx", "tx", "rx";
+			max-frequency = <97500000>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 311>;
+			status = "disabled";
+		};
 
-	ipmmu_sy1: mmu@e6290000 {
-		compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6290000 0 0x1000>;
-		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		mmcif0: mmc@ee200000 {
+			compatible = "renesas,mmcif-r8a7794",
+				     "renesas,sh-mmcif";
+			reg = <0 0xee200000 0 0x80>;
+			interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 315>;
+			dmas = <&dmac0 0xd1>, <&dmac0 0xd2>,
+			       <&dmac1 0xd1>, <&dmac1 0xd2>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 315>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
 
-	ipmmu_ds: mmu@e6740000 {
-		compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
-		reg = <0 0xe6740000 0 0x1000>;
-		interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		ether: ethernet@ee700000 {
+			compatible = "renesas,ether-r8a7794",
+				     "renesas,rcar-gen2-ether";
+			reg = <0 0xee700000 0 0x400>;
+			interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 813>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 813>;
+			phy-mode = "rmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 
-	ipmmu_mp: mmu@ec680000 {
-		compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
-		reg = <0 0xec680000 0 0x1000>;
-		interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		gic: interrupt-controller@f1001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0 0xf1001000 0 0x1000>,
+			      <0 0xf1002000 0 0x2000>,
+			      <0 0xf1004000 0 0x2000>,
+			      <0 0xf1006000 0 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 408>;
+		};
 
-	ipmmu_mx: mmu@fe951000 {
-		compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
-		reg = <0 0xfe951000 0 0x1000>;
-		interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		vsp@fe928000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe928000 0 0x8000>;
+			interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 131>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 131>;
+		};
 
-	ipmmu_gp: mmu@e62a0000 {
-		compatible = "renesas,ipmmu-r8a7794", "renesas,ipmmu-vmsa";
-		reg = <0 0xe62a0000 0 0x1000>;
-		interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
-			     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
-		#iommu-cells = <1>;
-		status = "disabled";
-	};
+		vsp@fe930000 {
+			compatible = "renesas,vsp1";
+			reg = <0 0xfe930000 0 0x8000>;
+			interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 128>;
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 128>;
+		};
 
-	rcar_sound: sound@ec500000 {
-		/*
-		 * #sound-dai-cells is required
-		 *
-		 * Single DAI : #sound-dai-cells = <0>;         <&rcar_sound>;
-		 * Multi  DAI : #sound-dai-cells = <1>;         <&rcar_sound N>;
-		 */
-		compatible = "renesas,rcar_sound-r8a7794",
-			     "renesas,rcar_sound-gen2";
-		reg =	<0 0xec500000 0 0x1000>, /* SCU */
-			<0 0xec5a0000 0 0x100>,  /* ADG */
-			<0 0xec540000 0 0x1000>, /* SSIU */
-			<0 0xec541000 0 0x280>,  /* SSI */
-			<0 0xec740000 0 0x200>;  /* Audio DMAC peri peri */
-		reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
-
-		clocks = <&cpg CPG_MOD 1005>,
-			 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
-			 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
-			 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
-			 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
-			 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
-			 <&cpg CPG_MOD 1025>, <&cpg CPG_MOD 1026>,
-			 <&cpg CPG_MOD 1027>, <&cpg CPG_MOD 1028>,
-			 <&cpg CPG_MOD 1029>, <&cpg CPG_MOD 1030>,
-			 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-			 <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>,
-			 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
-			 <&audio_clka>, <&audio_clkb>, <&audio_clkc>,
-			 <&cpg CPG_CORE R8A7794_CLK_M2>;
-		clock-names = "ssi-all",
-			      "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-			      "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
-			      "src.6", "src.5", "src.4", "src.3", "src.2",
-			      "src.1",
-			      "ctu.0", "ctu.1",
-			      "mix.0", "mix.1",
-			      "dvc.0", "dvc.1",
-			      "clk_a", "clk_b", "clk_c", "clk_i";
-		power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
-		resets = <&cpg 1005>,
-			 <&cpg 1006>, <&cpg 1007>, <&cpg 1008>, <&cpg 1009>,
-			 <&cpg 1010>, <&cpg 1011>, <&cpg 1012>, <&cpg 1013>,
-			 <&cpg 1014>, <&cpg 1015>;
-		reset-names = "ssi-all",
-			      "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
-			      "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0";
-
-		status = "disabled";
-
-		rcar_sound,dvc {
-			dvc0: dvc-0 {
-				dmas = <&audma0 0xbc>;
-				dma-names = "tx";
-			};
-			dvc1: dvc-1 {
-				dmas = <&audma0 0xbe>;
-				dma-names = "tx";
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a7794";
+			reg = <0 0xfeb00000 0 0x40000>;
+			reg-names = "du";
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>;
+			clock-names = "du.0", "du.1";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb0: endpoint {
+					};
+				};
+				port@1 {
+					reg = <1>;
+					du_out_rgb1: endpoint {
+					};
+				};
 			};
 		};
 
-		rcar_sound,mix {
-			mix0: mix-0 { };
-			mix1: mix-1 { };
+		prr: chipid@ff000044 {
+			compatible = "renesas,prr";
+			reg = <0 0xff000044 0 4>;
 		};
 
-		rcar_sound,ctu {
-			ctu00: ctu-0 { };
-			ctu01: ctu-1 { };
-			ctu02: ctu-2 { };
-			ctu03: ctu-3 { };
-			ctu10: ctu-4 { };
-			ctu11: ctu-5 { };
-			ctu12: ctu-6 { };
-			ctu13: ctu-7 { };
+		cmt0: timer@ffca0000 {
+			compatible = "renesas,r8a7794-cmt0",
+				     "renesas,rcar-gen2-cmt0";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 124>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 124>;
+
+			status = "disabled";
 		};
 
-		rcar_sound,src {
-			src-0 {
-				status = "disabled";
-			};
-			src1: src-1 {
-				interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x87>, <&audma0 0x9c>;
-				dma-names = "rx", "tx";
-			};
-			src2: src-2 {
-				interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x89>, <&audma0 0x9e>;
-				dma-names = "rx", "tx";
-			};
-			src3: src-3 {
-				interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8b>, <&audma0 0xa0>;
-				dma-names = "rx", "tx";
-			};
-			src4: src-4 {
-				interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8d>, <&audma0 0xb0>;
-				dma-names = "rx", "tx";
-			};
-			src5: src-5 {
-				interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x8f>, <&audma0 0xb2>;
-				dma-names = "rx", "tx";
-			};
-			src6: src-6 {
-				interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x91>, <&audma0 0xb4>;
-				dma-names = "rx", "tx";
-			};
+		cmt1: timer@e6130000 {
+			compatible = "renesas,r8a7794-cmt1",
+				     "renesas,rcar-gen2-cmt1";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 329>;
+			clock-names = "fck";
+			power-domains = <&sysc R8A7794_PD_ALWAYS_ON>;
+			resets = <&cpg 329>;
+
+			status = "disabled";
 		};
+	};
 
-		rcar_sound,ssi {
-			ssi0: ssi-0 {
-				interrupts = <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x01>, <&audma0 0x02>,
-				       <&audma0 0x15>, <&audma0 0x16>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi1: ssi-1 {
-				interrupts = <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x03>, <&audma0 0x04>,
-				       <&audma0 0x49>, <&audma0 0x4a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi2: ssi-2 {
-				interrupts = <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x05>, <&audma0 0x06>,
-				       <&audma0 0x63>, <&audma0 0x64>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi3: ssi-3 {
-				interrupts = <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x07>, <&audma0 0x08>,
-				       <&audma0 0x6f>, <&audma0 0x70>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi4: ssi-4 {
-				interrupts = <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x09>, <&audma0 0x0a>,
-				       <&audma0 0x71>, <&audma0 0x72>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi5: ssi-5 {
-				interrupts = <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0b>, <&audma0 0x0c>,
-				       <&audma0 0x73>, <&audma0 0x74>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi6: ssi-6 {
-				interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0d>, <&audma0 0x0e>,
-				       <&audma0 0x75>, <&audma0 0x76>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi7: ssi-7 {
-				interrupts = <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x0f>, <&audma0 0x10>,
-				       <&audma0 0x79>, <&audma0 0x7a>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi8: ssi-8 {
-				interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x11>, <&audma0 0x12>,
-				       <&audma0 0x7b>, <&audma0 0x7c>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-			ssi9: ssi-9 {
-				interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
-				dmas = <&audma0 0x13>, <&audma0 0x14>,
-				       <&audma0 0x7d>, <&audma0 0x7e>;
-				dma-names = "rx", "tx", "rxu", "txu";
-			};
-		};
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+	};
+
+	/* External USB clock - can be overridden by the board */
+	usb_extal_clk: usb_extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <48000000>;
 	};
 };
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index 3b704cfed69a..a97458112ff6 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -280,7 +280,7 @@
 		max-frequency = <37500000>;
 		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
 			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
 		resets = <&cru SRST_SDIO>;
@@ -298,7 +298,7 @@
 		max-frequency = <37500000>;
 		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
 			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		default-sample-phase = <158>;
 		disable-wp;
 		dmas = <&pdma 12>;
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 780ec3a99b21..df1e47858675 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -233,7 +233,7 @@
 	};
 
 	grf: syscon@11000000 {
-		compatible = "syscon", "simple-mfd";
+		compatible = "rockchip,rk3228-grf", "syscon", "simple-mfd";
 		reg = <0x11000000 0x1000>;
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -621,7 +621,7 @@
 		interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
 			 <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;
@@ -634,7 +634,7 @@
 		interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
 			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>;
@@ -649,7 +649,7 @@
 		max-frequency = <37500000>;
 		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
 			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		bus-width = <8>;
 		default-sample-phase = <158>;
 		fifo-depth = <0x100>;
diff --git a/arch/arm/boot/dts/rk3288-phycore-rdk.dts b/arch/arm/boot/dts/rk3288-phycore-rdk.dts
index 1241cbcfc16f..985743fa134c 100644
--- a/arch/arm/boot/dts/rk3288-phycore-rdk.dts
+++ b/arch/arm/boot/dts/rk3288-phycore-rdk.dts
@@ -265,7 +265,11 @@
 	disable-wp;
 	pinctrl-names = "default";
 	pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
-	vmmc-supply = <&vdd_io_sd>;
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vdd_sd>;
 	vqmmc-supply = <&vdd_io_sd>;
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/rk3288-phycore-som.dtsi b/arch/arm/boot/dts/rk3288-phycore-som.dtsi
index 99cfae875e12..f13bcb1cd3d9 100644
--- a/arch/arm/boot/dts/rk3288-phycore-som.dtsi
+++ b/arch/arm/boot/dts/rk3288-phycore-som.dtsi
@@ -110,26 +110,6 @@
 	};
 };
 
-&cpu0 {
-	cpu0-supply = <&vdd_cpu>;
-	operating-points = <
-		/* KHz    uV */
-		1800000	1400000
-		1608000	1350000
-		1512000 1300000
-		1416000 1200000
-		1200000 1100000
-		1008000 1050000
-		 816000 1000000
-		 696000  950000
-		 600000  900000
-		 408000  900000
-		 312000  900000
-		 216000  900000
-		 126000  900000
-	>;
-};
-
 &emmc {
 	status = "okay";
 	bus-width = <8>;
@@ -356,11 +336,10 @@
 				regulator-name = "vdd_io_sd";
 				regulator-always-on;
 				regulator-boot-on;
-				regulator-min-microvolt = <3300000>;
+				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-state-mem {
-					regulator-on-in-suspend;
-					regulator-suspend-microvolt = <3300000>;
+					regulator-off-in-suspend;
 				};
 			};
 		};
diff --git a/arch/arm/boot/dts/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
index b9c471fcbd42..51f36a1b698e 100644
--- a/arch/arm/boot/dts/rk3288-rock2-som.dtsi
+++ b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
@@ -280,6 +280,10 @@
 	};
 };
 
+&saradc {
+	vref-supply = <&vcc_18>;
+};
+
 &tsadc {
 	rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */
 	rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */
diff --git a/arch/arm/boot/dts/rk3288-rock2-square.dts b/arch/arm/boot/dts/rk3288-rock2-square.dts
index 0e084b8a86ac..8ccc89dbdfaf 100644
--- a/arch/arm/boot/dts/rk3288-rock2-square.dts
+++ b/arch/arm/boot/dts/rk3288-rock2-square.dts
@@ -39,6 +39,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/input/input.h>
 #include "rk3288-rock2-som.dtsi"
 
 / {
@@ -49,6 +50,32 @@
 		stdout-path = "serial2:115200n8";
 	};
 
+	adc-keys {
+		compatible = "adc-keys";
+		io-channels = <&saradc 1>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+
+		button-recovery {
+			label = "Recovery";
+			linux,code = <KEY_VENDOR>;
+			press-threshold-microvolt = <0>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		power {
+			gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
+			label = "GPIO Power";
+			linux,code = <KEY_POWER>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pwr_key>;
+			wakeup-source;
+		};
+	};
+
 	gpio-leds {
 		compatible = "gpio-leds";
 
@@ -220,6 +247,12 @@
 		};
 	};
 
+	keys {
+		pwr_key: pwr-key {
+			rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
 	pmic {
 		pmic_int: pmic-int {
 			rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -261,6 +294,10 @@
 	};
 };
 
+&saradc {
+	status = "okay";
+};
+
 &spdif {
 	status = "okay";
 };
@@ -284,3 +321,7 @@
 &usb_host1 {
 	status = "okay";
 };
+
+&usb_otg {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
index d752a315f884..be487111d025 100644
--- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
@@ -92,7 +92,6 @@
 			248 249 250 251 252 253 254 255>;
 		default-brightness-level = <128>;
 		enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>;
-		backlight-boot-off;
 		pinctrl-names = "default";
 		pinctrl-0 = <&bl_en>;
 		pwms = <&pwm0 0 1000000 0>;
diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 9842a006e823..14c896bfc639 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -155,6 +155,17 @@
 	cpu0-supply = <&vdd_cpu>;
 };
 
+&emmc {
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	disable-wp;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>;
+	vmmc-supply = <&vcc_io>;
+	status = "okay";
+};
+
 &gmac {
 	assigned-clocks = <&cru SCLK_MAC>;
 	assigned-clock-parents = <&ext_gmac>;
diff --git a/arch/arm/boot/dts/samsung_k3pe0e000b.dtsi b/arch/arm/boot/dts/samsung_k3pe0e000b.dtsi
deleted file mode 100644
index dbdda36179ee..000000000000
--- a/arch/arm/boot/dts/samsung_k3pe0e000b.dtsi
+++ /dev/null
@@ -1,68 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Timings and Geometry for Samsung K3PE0E000B memory part
- */
-
-/ {
-	samsung_K3PE0E000B: lpddr2 {
-		compatible	= "Samsung,K3PE0E000B","jedec,lpddr2-s4";
-		density		= <4096>;
-		io-width	= <32>;
-
-		tRPab-min-tck	= <3>;
-		tRCD-min-tck	= <3>;
-		tWR-min-tck	= <3>;
-		tRASmin-min-tck	= <3>;
-		tRRD-min-tck	= <2>;
-		tWTR-min-tck	= <2>;
-		tXP-min-tck	= <2>;
-		tRTP-min-tck	= <2>;
-		tCKE-min-tck	= <3>;
-		tCKESR-min-tck	= <3>;
-		tFAW-min-tck	= <8>;
-
-		timings_samsung_K3PE0E000B_533MHz: lpddr2-timings@0 {
-			compatible	= "jedec,lpddr2-timings";
-			min-freq	= <10000000>;
-			max-freq	= <533333333>;
-			tRPab		= <21000>;
-			tRCD		= <18000>;
-			tWR		= <15000>;
-			tRAS-min	= <42000>;
-			tRRD		= <10000>;
-			tWTR		= <7500>;
-			tXP		= <7500>;
-			tRTP		= <7500>;
-			tCKESR		= <15000>;
-			tDQSCK-max	= <5500>;
-			tFAW		= <50000>;
-			tZQCS		= <90000>;
-			tZQCL		= <360000>;
-			tZQinit		= <1000000>;
-			tRAS-max-ns	= <70000>;
-			tDQSCK-max-derated = <6000>;
-		};
-
-		timings_samsung_K3PE0E000B_266MHz: lpddr2-timings@1 {
-			compatible	= "jedec,lpddr2-timings";
-			min-freq	= <10000000>;
-			max-freq	= <266666666>;
-			tRPab		= <21000>;
-			tRCD		= <18000>;
-			tWR		= <15000>;
-			tRAS-min	= <42000>;
-			tRRD		= <10000>;
-			tWTR		= <7500>;
-			tXP		= <7500>;
-			tRTP		= <7500>;
-			tCKESR		= <15000>;
-			tDQSCK-max	= <5500>;
-			tFAW		= <50000>;
-			tZQCS		= <90000>;
-			tZQCL		= <360000>;
-			tZQinit		= <1000000>;
-			tRAS-max-ns	= <70000>;
-			tDQSCK-max-derated = <6000>;
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index 09e909576c61..6c254ec4c85b 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -164,8 +164,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
index 39ba4ccb9e2e..38a2c4134952 100644
--- a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
+++ b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
@@ -106,8 +106,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
index dfc88aee4fe3..cf7b392dff31 100644
--- a/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
+++ b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
@@ -123,8 +123,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 1982c8c238c5..197a1f2b75ff 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -162,8 +162,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts b/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts
index 147cbc5e08ac..896e27a08727 100644
--- a/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts
+++ b/arch/arm/boot/dts/sun4i-a10-dserve-dsrv9703c.dts
@@ -150,8 +150,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
index 41ca8bded89f..ea7a59dcf8f9 100644
--- a/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
+++ b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
@@ -141,8 +141,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH01 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH01 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index f33e42d6ce8b..cc988ccd5ca7 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -106,8 +106,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts b/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
index 35c57d065dd8..f63767cddd8e 100644
--- a/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
@@ -78,8 +78,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-inet1.dts b/arch/arm/boot/dts/sun4i-a10-inet1.dts
index 9482e831a9a1..26d0c1d6a02b 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet1.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet1.dts
@@ -152,8 +152,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
index 4b5c91c8e85b..5d096528e75a 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
@@ -142,8 +142,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
index 13224f5ac166..221acd10f6c8 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
@@ -300,8 +300,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts b/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts
index d22bd79562d8..80ecd78247ac 100644
--- a/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts
+++ b/arch/arm/boot/dts/sun4i-a10-itead-iteaduino-plus.dts
@@ -106,8 +106,7 @@
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
index 879141ca6027..247fa27ef717 100644
--- a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
+++ b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
@@ -133,8 +133,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-marsboard.dts b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
index 435c551aef0f..0dbf69576512 100644
--- a/arch/arm/boot/dts/sun4i-a10-marsboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
@@ -132,8 +132,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
index 1b639e5f9172..f9d74e21031d 100644
--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
@@ -96,8 +96,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-mk802.dts b/arch/arm/boot/dts/sun4i-a10-mk802.dts
index 7198b34e2e50..059fe9c5d024 100644
--- a/arch/arm/boot/dts/sun4i-a10-mk802.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mk802.dts
@@ -56,12 +56,27 @@
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
 };
 
 &codec {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -70,11 +85,20 @@
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-mk802ii.dts b/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
index e460da2eb139..17dcdf031118 100644
--- a/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
@@ -82,8 +82,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
index 49247fbe6acd..b74a61496537 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -97,7 +97,6 @@
 		864000  1300000
 		624000  1250000
 		>;
-	cooling-max-level = <2>;
 };
 
 &de {
@@ -165,8 +164,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
index 6e140547b638..b97a0f2f20b9 100644
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -140,8 +140,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
index 5081303f79e7..84b25be1ac94 100644
--- a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
@@ -138,8 +138,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 4f2f2eea0755..77e8436beed4 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -123,8 +123,6 @@
 				624000	1250000
 				>;
 			#cooling-cells = <2>;
-			cooling-min-level = <0>;
-			cooling-max-level = <3>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts
index d2dee8d434bf..39504d720efc 100644
--- a/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts
@@ -93,8 +93,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_t003>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
-	cd-inverted;
+	cd-gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
index 16f839df4227..8d4fb9331212 100644
--- a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
@@ -104,8 +104,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_t004>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
-	cd-inverted;
+	cd-gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a10s-mk802.dts b/arch/arm/boot/dts/sun5i-a10s-mk802.dts
index 020aa9d6c31d..dd7fd5c3d76f 100644
--- a/arch/arm/boot/dts/sun5i-a10s-mk802.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-mk802.dts
@@ -92,8 +92,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_mk802>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
-	cd-inverted;
+	cd-gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
index da95118af4dc..2c902ed2c87a 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -201,8 +201,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino_micro>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
-	cd-inverted;
+	cd-gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
 	status = "okay";
 };
 
@@ -211,8 +210,7 @@
 	pinctrl-0 = <&mmc1_pins_a>, <&mmc1_cd_pin_olinuxino_micro>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
-	cd-inverted;
+	cd-gpios = <&pio 6 13 GPIO_ACTIVE_LOW>; /* PG13 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
index 262b3669f04d..034853d1c08f 100644
--- a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
@@ -80,8 +80,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_r7>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
-	cd-inverted;
+	cd-gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
index 5482be174e12..3f68ef5d92a0 100644
--- a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
@@ -130,8 +130,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_wobo_i5>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
-	cd-inverted;
+	cd-gpios = <&pio 1 3 GPIO_ACTIVE_LOW>; /* PB3 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts b/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts
index 3dbb0d7c2f8c..378214d8316e 100644
--- a/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts
+++ b/arch/arm/boot/dts/sun5i-a13-empire-electronix-d709.dts
@@ -125,8 +125,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_d709>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
-	cd-inverted;
+	cd-gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
index 584fa579ded2..7ee0c3f6d7a1 100644
--- a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
+++ b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
@@ -120,8 +120,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_h702>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
-	cd-inverted;
+	cd-gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
index 3a831eaf1dfc..aa4b34fd9126 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -99,8 +99,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxinom>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
-	cd-inverted;
+	cd-gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index 4b9af423c6d5..437ad913a373 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -194,8 +194,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
-	cd-inverted;
+	cd-gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 4e830f5cb7f1..b1d827765530 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -116,8 +116,6 @@
 		432000	1200000
 		>;
 	#cooling-cells = <2>;
-	cooling-min-level = <0>;
-	cooling-max-level = <5>;
 };
 
 &pio {
diff --git a/arch/arm/boot/dts/sun5i-gr8-evb.dts b/arch/arm/boot/dts/sun5i-gr8-evb.dts
index 558c16a30543..5f0adc0f7bb4 100644
--- a/arch/arm/boot/dts/sun5i-gr8-evb.dts
+++ b/arch/arm/boot/dts/sun5i-gr8-evb.dts
@@ -236,8 +236,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_gr8_evb>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
-	cd-inverted;
+	cd-gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun5i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun5i-reference-design-tablet.dtsi
index 49229b3d5492..8acbaab14fe5 100644
--- a/arch/arm/boot/dts/sun5i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun5i-reference-design-tablet.dtsi
@@ -127,8 +127,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v0>;
 	bus-width = <4>;
-	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
-	cd-inverted;
+	cd-gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts
index 85eff0307ca4..939c497a6f70 100644
--- a/arch/arm/boot/dts/sun6i-a31-colombus.dts
+++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts
@@ -117,8 +117,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_colombus>;
 	vmmc-supply = <&reg_vcc3v0>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
-	cd-inverted;
+	cd-gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 19e382a11297..ce4f9e9834bf 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -218,8 +218,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_hummingbird>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
-	cd-inverted;
+	cd-gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31-i7.dts b/arch/arm/boot/dts/sun6i-a31-i7.dts
index 010a84c7c012..d659be9dbc50 100644
--- a/arch/arm/boot/dts/sun6i-a31-i7.dts
+++ b/arch/arm/boot/dts/sun6i-a31-i7.dts
@@ -58,6 +58,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -93,6 +104,10 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -113,6 +128,16 @@
 	};
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
@@ -124,8 +149,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_i7>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
-	cd-inverted;
+	cd-gpios = <&pio 7 22 GPIO_ACTIVE_LOW>; /* PH22 */
 	status = "okay";
 };
 
@@ -161,6 +185,10 @@
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index 50605fd4449e..9698f6d38d03 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -107,8 +107,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_m9>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
-	cd-inverted;
+	cd-gpios = <&pio 7 22 GPIO_ACTIVE_LOW>; /* PH22 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
index 5219556e9f73..bb14b171b160 100644
--- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
+++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
@@ -107,8 +107,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_m9>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
-	cd-inverted;
+	cd-gpios = <&pio 7 22 GPIO_ACTIVE_LOW>; /* PH22 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 72d3fe44ecaf..c72992556a86 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -113,8 +113,6 @@
 				480000	1000000
 				>;
 			#cooling-cells = <2>;
-			cooling-min-level = <0>;
-			cooling-max-level = <3>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
index 0cdb38ab3377..4cb9664cdb29 100644
--- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -151,8 +151,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_primo81>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
-	cd-inverted;
+	cd-gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
index 298476485bb4..da0ccf5a2c44 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
@@ -167,8 +167,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_sina31s>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */
-	cd-inverted;
+	cd-gpios = <&pio 0 4 GPIO_ACTIVE_LOW>; /* PA4 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
index 51e6f1d21c32..b8b79c0e9ee0 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
@@ -42,7 +42,6 @@
 
 /dts-v1/;
 #include "sun6i-a31s.dtsi"
-#include "sunxi-common-regulators.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
 / {
@@ -99,6 +98,7 @@
 	pinctrl-0 = <&gmac_pins_rgmii_a>, <&gmac_phy_reset_pin_bpi_m2>;
 	phy = <&phy1>;
 	phy-mode = "rgmii";
+	phy-supply = <&reg_dldo1>;
 	snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>; /* PA21 */
 	snps,reset-active-low;
 	snps,reset-delays-us = <0 10000 30000>;
@@ -118,10 +118,9 @@
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bpi_m2>;
-	vmmc-supply = <&reg_vcc3v0>;
+	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */
-	cd-inverted;
+	cd-gpios = <&pio 0 4 GPIO_ACTIVE_LOW>; /* PA4 */
 	status = "okay";
 };
 
@@ -132,7 +131,7 @@
 &mmc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_pins_a>;
-	vmmc-supply = <&reg_vcc3v0>;
+	vmmc-supply = <&reg_aldo1>;
 	mmc-pwrseq = <&mmc2_pwrseq>;
 	bus-width = <4>;
 	non-removable;
@@ -163,6 +162,8 @@
 		reg = <0x68>;
 		interrupt-parent = <&nmi_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		eldoin-supply = <&reg_dcdc1>;
+		x-powers,drive-vbus-en;
 	};
 };
 
@@ -193,7 +194,28 @@
 
 #include "axp22x.dtsi"
 
+&reg_aldo1 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi";
+};
+
+&reg_aldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <2500000>;
+	regulator-max-microvolt = <2500000>;
+	regulator-name = "vcc-gmac";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
 &reg_dc5ldo {
+	regulator-always-on;
 	regulator-min-microvolt = <700000>;
 	regulator-max-microvolt = <1320000>;
 	regulator-name = "vdd-cpus";
@@ -233,6 +255,40 @@
 	regulator-name = "vcc-dram";
 };
 
+&reg_dldo1 {
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "vcc-mac";
+};
+
+&reg_dldo2 {
+	regulator-min-microvolt = <2800000>;
+	regulator-max-microvolt = <2800000>;
+	regulator-name = "avdd-csi";
+};
+
+&reg_dldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-pb";
+};
+
+&reg_eldo1 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vdd-csi";
+	status = "okay";
+};
+
+&reg_ldo_io1 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vcc-pm-cpus";
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
index f3edf9ca435c..aab6c1720ef7 100644
--- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -102,8 +102,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bs1078v2>;
 	vmmc-supply = <&reg_vcc3v0>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
-	cd-inverted;
+	cd-gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
index 3cc4046b904a..4e72e4f3ef96 100644
--- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
@@ -69,8 +69,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_e708_q1>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
-	cd-inverted;
+	cd-gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts b/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts
index 4ed3162e3e5a..763cb03033c4 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi-m1-plus.dts
@@ -184,8 +184,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bpi_m1p>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
-	cd-inverted;
+	cd-gpios = <&pio 7 10 GPIO_ACTIVE_LOW>; /* PH10 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index 88a1c2363c6c..70dfc4ac0bb5 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -63,6 +63,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -109,6 +120,10 @@
 		>;
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -130,6 +145,16 @@
 	};
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins_a>;
@@ -159,8 +184,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
-	cd-inverted;
+	cd-gpios = <&pio 7 10 GPIO_ACTIVE_LOW>; /* PH10 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
index e7af1b7c33d5..0898eb6162f5 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
@@ -158,8 +158,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapro>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
-	cd-inverted;
+	cd-gpios = <&pio 7 10 GPIO_ACTIVE_LOW>; /* PH10 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 39f43e4eb742..942ac9dfd4a5 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -165,8 +165,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 8c9bedc602ec..5649161de1d7 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -206,8 +206,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
index 6e6264cd69f8..1f0e5ecbf0c4 100644
--- a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
+++ b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
@@ -163,8 +163,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v0>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
index 55809973a568..2e3f2f29d124 100644
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -160,8 +160,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts
index 794e7617f545..926fa194eb1b 100644
--- a/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts
+++ b/arch/arm/boot/dts/sun7i-a20-icnova-swac.dts
@@ -107,8 +107,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 8 5 GPIO_ACTIVE_HIGH>; /* PI5 */
-	cd-inverted;
+	cd-gpios = <&pio 8 5 GPIO_ACTIVE_LOW>; /* PI5 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts b/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts
index 8a8a6dbcd414..1b05ba466e7d 100644
--- a/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-itead-ibox.dts
@@ -124,8 +124,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
index 442f3c755f36..b1ab7c1c33e3 100644
--- a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
+++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
@@ -227,8 +227,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_lamobo_r1>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
-	cd-inverted;
+	cd-gpios = <&pio 7 10 GPIO_ACTIVE_LOW>; /* PH10 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-m3.dts b/arch/arm/boot/dts/sun7i-a20-m3.dts
index 43c94787ef07..e91a209850bc 100644
--- a/arch/arm/boot/dts/sun7i-a20-m3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-m3.dts
@@ -120,8 +120,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-mk808c.dts b/arch/arm/boot/dts/sun7i-a20-mk808c.dts
index f7413094183c..6109f794a9c1 100644
--- a/arch/arm/boot/dts/sun7i-a20-mk808c.dts
+++ b/arch/arm/boot/dts/sun7i-a20-mk808c.dts
@@ -66,12 +66,27 @@
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
 };
 
 &codec {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -80,6 +95,16 @@
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+	remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins_a>;
@@ -112,8 +137,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v0>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
index 64c8ef9a2756..f080f82b58ef 100644
--- a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
@@ -61,6 +61,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -79,6 +90,10 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -107,6 +122,16 @@
 	};
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins_a>;
@@ -190,8 +215,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
@@ -200,8 +224,7 @@
 	pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olimex_som_evb>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 0 GPIO_ACTIVE_HIGH>; /* PH0 */
-	cd-inverted;
+	cd-gpios = <&pio 7 0 GPIO_ACTIVE_LOW>; /* PH0 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb-emmc.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb-emmc.dts
new file mode 100644
index 000000000000..c56620a8fb20
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb-emmc.dts
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree Source for A20-SOM204-EVB-eMMC Board
+ *
+ * Copyright (C) 2018 Olimex Ltd.
+ *   Author: Stefan Mavrodiev <stefan@olimex.com>
+ */
+
+/dts-v1/;
+#include "sun7i-a20-olimex-som204-evb.dts"
+
+/ {
+	model = "Olimex A20-SOM204-EVB-eMMC";
+	compatible = "olimex,a20-olimex-som204-evb-emmc", "allwinner,sun7i-a20";
+
+	mmc2_pwrseq: mmc2_pwrseq {
+		compatible = "mmc-pwrseq-emmc";
+		reset-gpios = <&pio 2 16 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&mmc2_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	emmc: emmc@0 {
+		reg = <0>;
+		compatible = "mmc-card";
+		broken-hpi;
+	};
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts
new file mode 100644
index 000000000000..eae8e267b9ef
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-olimex-som204-evb.dts
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Device Tree Source for A20-SOM204-EVB Board
+ *
+ * Copyright (C) 2018 Olimex Ltd.
+ *   Author: Stefan Mavrodiev <stefan@olimex.com>
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+	model = "Olimex A20-SOM204-EVB";
+	compatible = "olimex,a20-olimex-som204-evb", "allwinner,sun7i-a20";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart4;
+		serial2 = &uart7;
+		spi0 = &spi1;
+		spi1 = &spi2;
+		ethernet1 = &rtl8723bs;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		stat {
+			label = "a20-som204-evb:green:stat";
+			gpios = <&pio 8 0 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		led1 {
+			label = "a20-som204-evb:green:led1";
+			gpios = <&pio 8 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		led2 {
+			label = "a20-som204-evb:yellow:led2";
+			gpios = <&pio 8 11 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	rtl_pwrseq: rtl_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pio 6 9 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&ahci {
+	target-supply = <&reg_ahci_5v>;
+	status = "okay";
+};
+
+&can0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&can0_pins_a>;
+	status = "okay";
+};
+
+&codec {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&reg_dcdc2>;
+};
+
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&gmac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac_pins_rgmii_a>;
+	phy = <&phy3>;
+	phy-mode = "rgmii";
+	phy-supply = <&reg_vcc3v3>;
+
+	snps,reset-gpio = <&pio 0 17 GPIO_ACTIVE_HIGH>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 1000000>;
+	status = "okay";
+
+	phy3: ethernet-phy@3 {
+		reg = <3>;
+	};
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic@34 {
+		reg = <0x34>;
+		interrupt-parent = <&nmi_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+/* Exposed to UEXT1 */
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "okay";
+
+	eeprom: eeprom@50 {
+		compatible = "atmel,24c16";
+		reg = <0x50>;
+		pagesize = <16>;
+	};
+};
+
+/* Exposed to UEXT2 */
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins_a>;
+	status = "okay";
+};
+
+&ir0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ir0_rx_pins_a>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc3_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&rtl_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	rtl8723bs: sdio_wifi@1 {
+		reg = <1>;
+	};
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&otg_sram {
+	status = "okay";
+};
+
+&pio {
+	bt_uart_pins: bt_uart_pins@0 {
+		pins = "PG6", "PG7", "PG8";
+		function = "uart3";
+	};
+};
+
+#include "axp209.dtsi"
+
+&ac_power_supply {
+	status = "okay";
+};
+
+&battery_power_supply {
+	status = "okay";
+};
+
+&reg_ahci_5v {
+	gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+	regulator-always-on;
+	regulator-min-microvolt = <1300000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
+&reg_ldo4 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-pg";
+};
+
+&reg_usb0_vbus {
+	gpio = <&pio 2 17 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&reg_usb1_vbus {
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	status = "okay";
+};
+
+/* Exposed to UEXT1 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi1_pins_a>,
+		    <&spi1_cs0_pins_a>;
+	status = "okay";
+};
+
+/* Exposed to UEXT2 */
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_pins_a>,
+		    <&spi2_cs0_pins_a>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+/* Used for RTL8723BS bluetooth */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&bt_uart_pins>;
+	status = "okay";
+};
+
+/* Exposed to UEXT1 */
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins_a>;
+	status = "okay";
+};
+
+/* Exposed to UEXT2 */
+&uart7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart7_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usb_power_supply {
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+	usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+	usb0_vbus_power-supply = <&usb_power_supply>;
+	usb0_vbus-supply = <&reg_usb0_vbus>;
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
index edf9c3c6c0d7..d20fd03596e9 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
@@ -158,8 +158,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index ba250189d07f..b828677f331d 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -159,8 +159,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index dffbaa24b3ee..866d230593be 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -226,8 +226,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
@@ -236,8 +235,7 @@
 	pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olinuxinom>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
-	cd-inverted;
+	cd-gpios = <&pio 7 11 GPIO_ACTIVE_LOW>; /* PH11 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
index 7af4c8fc1865..f5c7178eb063 100644
--- a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
@@ -61,6 +61,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -98,6 +109,10 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -119,6 +134,16 @@
 	};
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &i2c0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c0_pins_a>;
@@ -144,8 +169,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_orangepi>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
-	cd-inverted;
+	cd-gpios = <&pio 7 10 GPIO_ACTIVE_LOW>; /* PH10 */
 	status = "okay";
 };
 
@@ -154,8 +178,7 @@
 	pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_orangepi>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
-	cd-inverted;
+	cd-gpios = <&pio 7 11 GPIO_ACTIVE_LOW>; /* PH11 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi.dts b/arch/arm/boot/dts/sun7i-a20-orangepi.dts
index 0a8d4a05e8a0..7a4244e57589 100644
--- a/arch/arm/boot/dts/sun7i-a20-orangepi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi.dts
@@ -135,8 +135,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_orangepi>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
-	cd-inverted;
+	cd-gpios = <&pio 7 10 GPIO_ACTIVE_LOW>; /* PH10 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
index fb591f32252c..bfca960b03e0 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
@@ -158,8 +158,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
index 777152a3df0f..c576f101fbde 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -159,8 +159,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
index f8d0aafb9f88..8202c87ca6a3 100644
--- a/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
+++ b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
@@ -154,8 +154,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
index 7f8405a0dd0f..ff5c1086585c 100644
--- a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
+++ b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
@@ -123,8 +123,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
-	cd-inverted;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index bd0cd3204273..e529e4ff2174 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -47,7 +47,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/thermal/thermal.h>
 #include <dt-bindings/dma/sun4i-a10.h>
-#include <dt-bindings/clock/sun4i-a10-ccu.h>
+#include <dt-bindings/clock/sun7i-a20-ccu.h>
 #include <dt-bindings/reset/sun4i-a10-ccu.h>
 
 / {
@@ -116,8 +116,6 @@
 				144000	1000000
 				>;
 			#cooling-cells = <2>;
-			cooling-min-level = <0>;
-			cooling-max-level = <6>;
 		};
 
 		cpu@1 {
@@ -1217,6 +1215,31 @@
 			#size-cells = <0>;
 		};
 
+		mali: gpu@1c40000 {
+			compatible = "allwinner,sun7i-a20-mali", "arm,mali-400";
+			reg = <0x01c40000 0x10000>;
+			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "gp",
+					  "gpmmu",
+					  "pp0",
+					  "ppmmu0",
+					  "pp1",
+					  "ppmmu1",
+					  "pmu";
+			clocks = <&ccu CLK_AHB_GPU>, <&ccu CLK_GPU>;
+			clock-names = "bus", "core";
+			resets = <&ccu RST_GPU>;
+
+			assigned-clocks = <&ccu CLK_GPU>;
+			assigned-clock-rates = <384000000>;
+		};
+
 		gmac: ethernet@1c50000 {
 			compatible = "allwinner,sun7i-a20-gmac";
 			reg = <0x01c50000 0x10000>;
diff --git a/arch/arm/boot/dts/sun8i-a23-evb.dts b/arch/arm/boot/dts/sun8i-a23-evb.dts
index 87289a60c520..8a93697df3a5 100644
--- a/arch/arm/boot/dts/sun8i-a23-evb.dts
+++ b/arch/arm/boot/dts/sun8i-a23-evb.dts
@@ -107,8 +107,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_evb>;
 	vmmc-supply = <&reg_vcc3v0>;
 	bus-width = <4>;
-	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
-	cd-inverted;
+	cd-gpios = <&pio 1 4 GPIO_ACTIVE_LOW>; /* PB4 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
index be9a6b8d7a1e..9757265c58d4 100644
--- a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
+++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
@@ -81,8 +81,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
-	cd-inverted;
+	cd-gpios = <&pio 1 4 GPIO_ACTIVE_LOW>; /* PB4 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
index 433cf2a2a9a2..541acb4d2b91 100644
--- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -144,8 +144,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_sina33>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
-	cd-inverted;
+	cd-gpios = <&pio 1 4 GPIO_ACTIVE_LOW>; /* PB4 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 50eb84fa246a..a21f2ed07a52 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -289,7 +289,6 @@
 			clock-names = "ahb", "mod",
 				      "ram";
 			resets = <&ccu RST_BUS_DE_FE>;
-			status = "disabled";
 
 			ports {
 				#address-cells = <1>;
diff --git a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
index 5091cecbcd1e..36ecebaff3c0 100644
--- a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
@@ -87,9 +87,8 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	bus-width = <4>;
-	cd-inverted;
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
index 6550bf0e594b..3b579d7567c8 100644
--- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -60,6 +60,31 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		blue {
+			label = "bananapi-m3:blue:usr";
+			gpios = <&axp_gpio 1 GPIO_ACTIVE_HIGH>;
+		};
+
+		green {
+			label = "bananapi-m3:green:usr";
+			gpios = <&axp_gpio 0 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
 	reg_usb1_vbus: reg-usb1-vbus {
 		compatible = "regulator-fixed";
 		regulator-name = "usb1-vbus";
@@ -82,6 +107,10 @@
 	};
 };
 
+&de {
+	status = "okay";
+};
+
 &ehci0 {
 	/* Terminus Tech FE 1.1s 4-port USB 2.0 hub here */
 	status = "okay";
@@ -100,6 +129,16 @@
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
 &mdio {
 	rgmii_phy: ethernet-phy@1 {
 		compatible = "ethernet-phy-ieee802.3-c22";
@@ -112,8 +151,7 @@
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
index 6da08cd0e107..88decb0747ac 100644
--- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
@@ -176,8 +176,7 @@
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 7f4955a5fab7..46ae4faa5894 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -155,7 +155,7 @@
 
 	de: display-engine {
 		compatible = "allwinner,sun8i-a83t-display-engine";
-		allwinner,pipelines = <&mixer0>;
+		allwinner,pipelines = <&mixer0>, <&mixer1>;
 		status = "disabled";
 	};
 
@@ -208,6 +208,29 @@
 			};
 		};
 
+		mixer1: mixer@1200000 {
+			compatible = "allwinner,sun8i-a83t-de2-mixer-1";
+			reg = <0x01200000 0x100000>;
+			clocks = <&display_clocks CLK_BUS_MIXER1>,
+				 <&display_clocks CLK_MIXER1>;
+			clock-names = "bus",
+				      "mod";
+			resets = <&display_clocks RST_WB>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mixer1_out: port@1 {
+					reg = <1>;
+
+					mixer1_out_tcon1: endpoint {
+						remote-endpoint = <&tcon1_in_mixer1>;
+					};
+				};
+			};
+		};
+
 		syscon: syscon@1c00000 {
 			compatible = "allwinner,sun8i-a83t-system-controller",
 				"syscon";
@@ -256,6 +279,40 @@
 			};
 		};
 
+		tcon1: lcd-controller@1c0d000 {
+			compatible = "allwinner,sun8i-a83t-tcon-tv";
+			reg = <0x01c0d000 0x1000>;
+			interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TCON1>, <&ccu CLK_TCON1>;
+			clock-names = "ahb", "tcon-ch1";
+			resets = <&ccu RST_BUS_TCON1>;
+			reset-names = "lcd";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon1_in: port@0 {
+					reg = <0>;
+
+					tcon1_in_mixer1: endpoint {
+						remote-endpoint = <&mixer1_out_tcon1>;
+					};
+				};
+
+				tcon1_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					tcon1_out_hdmi: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&hdmi_in_tcon1>;
+					};
+				};
+			};
+		};
+
 		mmc0: mmc@1c0f000 {
 			compatible = "allwinner,sun8i-a83t-mmc",
 				     "allwinner,sun7i-a20-mmc";
@@ -427,6 +484,11 @@
 				drive-strength = <40>;
 			};
 
+			hdmi_pins: hdmi-pins {
+				pins = "PH6", "PH7", "PH8";
+				function = "hdmi";
+			};
+
 			i2c0_pins: i2c0-pins {
 				pins = "PH0", "PH1";
 				function = "i2c0";
@@ -685,6 +747,50 @@
 			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
+		hdmi: hdmi@1ee0000 {
+			compatible = "allwinner,sun8i-a83t-dw-hdmi";
+			reg = <0x01ee0000 0x10000>;
+			reg-io-width = <1>;
+			interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>,
+				 <&ccu CLK_HDMI>;
+			clock-names = "iahb", "isfr", "tmds";
+			resets = <&ccu RST_BUS_HDMI1>;
+			reset-names = "ctrl";
+			phys = <&hdmi_phy>;
+			phy-names = "hdmi-phy";
+			pinctrl-names = "default";
+			pinctrl-0 = <&hdmi_pins>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				hdmi_in: port@0 {
+					reg = <0>;
+
+					hdmi_in_tcon1: endpoint {
+						remote-endpoint = <&tcon1_out_hdmi>;
+					};
+				};
+
+				hdmi_out: port@1 {
+					reg = <1>;
+				};
+			};
+		};
+
+		hdmi_phy: hdmi-phy@1ef0000 {
+			compatible = "allwinner,sun8i-a83t-hdmi-phy";
+			reg = <0x01ef0000 0x10000>;
+			clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>;
+			clock-names = "bus", "mod";
+			resets = <&ccu RST_BUS_HDMI0>;
+			reset-names = "phy";
+			#phy-cells = <0>;
+		};
+
 		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun8i-a83t-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
new file mode 100644
index 000000000000..7d01f9322658
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun8i-h3-bananapi-m2-plus.dts, which is:
+ *   Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Banana Pi BPI-M2-Zero";
+	compatible = "sinovoip,bpi-m2-zero", "allwinner,sun8i-h2-plus";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+
+		pwr_led {
+			label = "bananapi-m2-zero:red:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+			default-state = "on";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+
+		sw4 {
+			label = "power";
+			linux,code = <BTN_0>;
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&mmc0 {
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	/*
+	 * On the production batch of this board the card detect GPIO is
+	 * high active (card inserted), although on the early samples it's
+	 * low active.
+	 */
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	status = "okay";
+};
+
+&mmc1 {
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: wifi@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+	/*
+	 * There're two micro-USB connectors, one is power-only and another is
+	 * OTG. The Vbus of these two connectors are connected together, so
+	 * the external USB device will be powered just by the power input
+	 * from the power-only USB port.
+	 */
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts
index 112f09c67d67..3356f4210d45 100644
--- a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts
+++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts
@@ -68,6 +68,14 @@
 	};
 };
 
+&spi0 {
+	status = "okay";
+
+	flash@0 {
+		compatible = "mxicy,mx25l12805d", "jedec,spi-nor";
+	};
+};
+
 &ohci1 {
 	/*
 	 * RTL8152B USB-Ethernet adapter is connected to USB1,
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
index 6713d0f2b3f4..0bc031fe4c56 100644
--- a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
+++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
@@ -112,18 +112,13 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc_wifi>;
 	mmc-pwrseq = <&wifi_pwrseq>;
 	bus-width = <4>;
@@ -139,10 +134,6 @@
 	};
 };
 
-&mmc1_pins_a {
-	bias-pull-up;
-};
-
 &ohci0 {
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
index f1c3f1cc4d97..9c1bc472fb1c 100644
--- a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
@@ -136,18 +136,13 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	vqmmc-supply = <&reg_vcc3v3>;
 	mmc-pwrseq = <&wifi_pwrseq>;
diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
index 10da56e86ab8..870aabcbb2d8 100644
--- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
@@ -115,18 +115,13 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	non-removable;
diff --git a/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts b/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts
index d406571a0dd6..d0d41eb86cb4 100644
--- a/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts
@@ -150,12 +150,9 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc_io>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts
index a6e61915d648..07b51a2f14c6 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts
@@ -101,8 +101,6 @@
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	vqmmc-supply = <&reg_vcc3v3>;
 	mmc-pwrseq = <&wifi_pwrseq>;
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
index 03ff6f8b93ff..6246d3eff39d 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
@@ -72,16 +72,35 @@
 			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */
 		};
 	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+	};
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+	status = "okay";
+};
+
+&mmc1 {
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
 	status = "okay";
+
+	brcmf: bcrmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+		interrupt-names = "host-wake";
+	};
 };
 
 &uart0 {
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi b/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
index 7646e331bd29..f110ee382239 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
@@ -95,10 +95,7 @@
 
 &mmc0 {
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	status = "okay";
 	vmmc-supply = <&reg_vcc3v3>;
 };
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
index b20be95b49d5..7569bd05e249 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
@@ -132,18 +132,13 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	mmc-pwrseq = <&wifi_pwrseq>;
 	bus-width = <4>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
index a70a1daf4e2c..2e59fd296717 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
@@ -106,18 +106,13 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	non-removable;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index 82e5d28cd698..c1a8cd93c463 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -106,12 +106,9 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
index a10281b455f5..71fb73208939 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
@@ -59,8 +59,6 @@
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	non-removable;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index d22546df1b82..537227b85935 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -128,12 +128,9 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index eaf09666720d..0dbdb29a8fff 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -150,8 +150,7 @@
 	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
-	cd-inverted;
+	cd-gpios = <&pio 1 4 GPIO_ACTIVE_LOW>; /* PB4 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
index 8c5efe2a9881..27d9ccd0ef2f 100644
--- a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
+++ b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -164,8 +164,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; /* PH13 */
-	cd-inverted;
+	cd-gpios = <&pio 7 13 GPIO_ACTIVE_LOW>; /* PH13 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
index d6bd15898db6..f51f37cc721d 100644
--- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
@@ -85,8 +85,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
-	cd-inverted;
+	cd-gpios = <&pio 1 4 GPIO_ACTIVE_LOW>; /* PB4 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts b/arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
index fe16fc0eb518..a26d72c3f9b5 100644
--- a/arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
+++ b/arch/arm/boot/dts/sun8i-v40-bananapi-m2-berry.dts
@@ -150,8 +150,7 @@
 &mmc0 {
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; /* PH13 */
-	cd-inverted;
+	cd-gpios = <&pio 7 13 GPIO_ACTIVE_LOW>; /* PH13 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
index 4024639aa005..31b06ecbc306 100644
--- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -88,8 +88,7 @@
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 18 GPIO_ACTIVE_HIGH>; /* PH18 */
-	cd-inverted;
+	cd-gpios = <&pio 7 18 GPIO_ACTIVE_LOW>; /* PH18 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index a9b807be99a0..58a199b0e494 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -125,8 +125,7 @@
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 18 GPIO_ACTIVE_HIGH>; /* PH8 */
-	cd-inverted;
+	cd-gpios = <&pio 7 18 GPIO_ACTIVE_LOW>; /* PH8 */
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 90eac0b2a193..b1c86b76ac3c 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -63,48 +63,64 @@
 		cpu0: cpu@0 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x0>;
 		};
 
 		cpu1: cpu@1 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x1>;
 		};
 
 		cpu2: cpu@2 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x2>;
 		};
 
 		cpu3: cpu@3 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x3>;
 		};
 
 		cpu4: cpu@100 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x100>;
 		};
 
 		cpu5: cpu@101 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x101>;
 		};
 
 		cpu6: cpu@102 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x102>;
 		};
 
 		cpu7: cpu@103 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x103>;
 		};
 	};
@@ -234,6 +250,25 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		sram_b: sram@20000 {
+			/* 256 KiB secure SRAM at 0x20000 */
+			compatible = "mmio-sram";
+			reg = <0x00020000 0x40000>;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x00020000 0x40000>;
+
+			smp-sram@1000 {
+				/*
+				 * This is checked by BROM to determine if
+				 * cpu0 should jump to SMP entry vector
+				 */
+				compatible = "allwinner,sun9i-a80-smp-sram";
+				reg = <0x1000 0x8>;
+			};
+		};
+
 		ehci0: usb@a00000 {
 			compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
 			reg = <0x00a00000 0x100>;
@@ -347,6 +382,11 @@
 			#reset-cells = <1>;
 		};
 
+		cpucfg@1700000 {
+			compatible = "allwinner,sun9i-a80-cpucfg";
+			reg = <0x01700000 0x100>;
+		};
+
 		mmc0: mmc@1c0f000 {
 			compatible = "allwinner,sun9i-a80-mmc";
 			reg = <0x01c0f000 0x1000>;
@@ -431,6 +471,36 @@
 			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
+		cci: cci@1c90000 {
+			compatible = "arm,cci-400";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x01c90000 0x1000>;
+			ranges = <0x0 0x01c90000 0x10000>;
+
+			cci_control0: slave-if@4000 {
+				compatible = "arm,cci-400-ctrl-if";
+				interface-type = "ace";
+				reg = <0x4000 0x1000>;
+			};
+
+			cci_control1: slave-if@5000 {
+				compatible = "arm,cci-400-ctrl-if";
+				interface-type = "ace";
+				reg = <0x5000 0x1000>;
+			};
+
+			pmu@9000 {
+				 compatible = "arm,cci-400-pmu,r1";
+				 reg = <0x9000 0x5000>;
+				 interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
+
 		de_clocks: clock@3000000 {
 			compatible = "allwinner,sun9i-a80-de-clks";
 			reg = <0x03000000 0x30>;
@@ -658,6 +728,11 @@
 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		prcm@8001400 {
+			compatible = "allwinner,sun9i-a80-prcm";
+			reg = <0x08001400 0x200>;
+		};
+
 		apbs_rst: reset@80014b0 {
 			reg = <0x080014b0 0x4>;
 			compatible = "allwinner,sun6i-a31-clock-reset";
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 7a83b15225c7..7741166d34d8 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -141,6 +141,8 @@
 		mmc0: mmc@1c0f000 {
 			/* compatible and clocks are in per SoC .dtsi file */
 			reg = <0x01c0f000 0x1000>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc0_pins>;
 			resets = <&ccu RST_BUS_MMC0>;
 			reset-names = "ahb";
 			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
@@ -152,6 +154,8 @@
 		mmc1: mmc@1c10000 {
 			/* compatible and clocks are in per SoC .dtsi file */
 			reg = <0x01c10000 0x1000>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc1_pins>;
 			resets = <&ccu RST_BUS_MMC1>;
 			reset-names = "ahb";
 			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
@@ -348,7 +352,7 @@
 				function = "i2c2";
 			};
 
-			mmc0_pins_a: mmc0 {
+			mmc0_pins: mmc0 {
 				pins = "PF0", "PF1", "PF2", "PF3",
 				       "PF4", "PF5";
 				function = "mmc0";
@@ -356,13 +360,7 @@
 				bias-pull-up;
 			};
 
-			mmc0_cd_pin: mmc0_cd_pin {
-				pins = "PF6";
-				function = "gpio_in";
-				bias-pull-up;
-			};
-
-			mmc1_pins_a: mmc1 {
+			mmc1_pins: mmc1 {
 				pins = "PG0", "PG1", "PG2", "PG3",
 				       "PG4", "PG5";
 				function = "mmc1";
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 4cb9829fccd1..f32697d52478 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -60,6 +60,7 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_ARM_IMX6Q_CPUFREQ=y
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
@@ -220,8 +221,10 @@ CONFIG_THERMAL_WRITABLE_TRIPS=y
 CONFIG_CPU_THERMAL=y
 CONFIG_IMX_THERMAL=y
 CONFIG_WATCHDOG=y
+CONFIG_DA9062_WATCHDOG=y
 CONFIG_IMX2_WDT=y
 CONFIG_MFD_DA9052_I2C=y
+CONFIG_MFD_DA9062=y
 CONFIG_MFD_MC13XXX_SPI=y
 CONFIG_MFD_MC13XXX_I2C=y
 CONFIG_MFD_STMPE=y
@@ -229,6 +232,7 @@ CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_ANATOP=y
 CONFIG_REGULATOR_DA9052=y
+CONFIG_REGULATOR_DA9062=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_MC13783=y
 CONFIG_REGULATOR_MC13892=y
@@ -285,6 +289,7 @@ CONFIG_SND_SOC_IMX_SGTL5000=y
 CONFIG_SND_SOC_IMX_SPDIF=y
 CONFIG_SND_SOC_IMX_MC13783=y
 CONFIG_SND_SOC_FSL_ASOC_CARD=y
+CONFIG_SND_SOC_AC97_CODEC=y
 CONFIG_SND_SOC_CS42XX8_I2C=y
 CONFIG_SND_SOC_TLV320AIC3X=y
 CONFIG_SND_SOC_WM8960=y
@@ -354,6 +359,7 @@ CONFIG_RTC_DRV_ISL1208=y
 CONFIG_RTC_DRV_PCF8523=y
 CONFIG_RTC_DRV_PCF8563=y
 CONFIG_RTC_DRV_M41T80=y
+CONFIG_RTC_DRV_DA9063=y
 CONFIG_RTC_DRV_MC13XXX=y
 CONFIG_RTC_DRV_MXC=y
 CONFIG_RTC_DRV_MXC_V2=y
@@ -369,11 +375,14 @@ CONFIG_COMMON_CLK_PWM=y
 CONFIG_IIO=y
 CONFIG_IMX7D_ADC=y
 CONFIG_VF610_ADC=y
+CONFIG_MAG3110=y
 CONFIG_MPL3115=y
 CONFIG_PWM=y
 CONFIG_PWM_FSL_FTM=y
 CONFIG_PWM_IMX=y
 CONFIG_NVMEM_IMX_OCOTP=y
+CONFIG_TEE=y
+CONFIG_OPTEE=y
 CONFIG_MUX_MMIO=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index 578434cfd1a0..79b2b7c12264 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -120,6 +120,7 @@ CONFIG_SPI=y
 CONFIG_SPI_RSPI=y
 CONFIG_SPI_SH_MSIOF=y
 CONFIG_SPI_SH_HSPI=y
+CONFIG_PINCTRL_RZA1=y
 CONFIG_GPIO_EM=y
 CONFIG_GPIO_RCAR=y
 CONFIG_GPIO_PCF857X=y
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 4355f0ec44d6..f98baaec0a15 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -17,6 +17,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/personality.h>	/* For READ_IMPLIES_EXEC */
+
 #ifndef CONFIG_MMU
 
 #include <asm/page-nommu.h>
diff --git a/arch/arm/include/debug/exynos.S b/arch/arm/include/debug/exynos.S
index 60bf3c23200d..74b56769f9cb 100644
--- a/arch/arm/include/debug/exynos.S
+++ b/arch/arm/include/debug/exynos.S
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *		http://www.samsung.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.
-*/
+ */
 
 /* pull in the relevant register and map files. */
 
diff --git a/arch/arm/include/debug/samsung.S b/arch/arm/include/debug/samsung.S
index f4eeed2a1981..69201d7fb48f 100644
--- a/arch/arm/include/debug/samsung.S
+++ b/arch/arm/include/debug/samsung.S
@@ -1,13 +1,9 @@
-/* arch/arm/plat-samsung/include/plat/debug-macro.S
- *
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
  * Copyright 2005, 2007 Simtec Electronics
  *	http://armlinux.simtec.co.uk/
  *	Ben Dooks <ben@simtec.co.uk>
- *
- * 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/serial_s3c.h>
 
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index fbd108ce8745..8c4f5e342dc1 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -192,7 +192,8 @@ static void __init exynos_dt_machine_init(void)
 #endif
 	if (of_machine_is_compatible("samsung,exynos4210") ||
 	    (of_machine_is_compatible("samsung,exynos4412") &&
-	     of_machine_is_compatible("samsung,trats2")) ||
+	     (of_machine_is_compatible("samsung,trats2") ||
+		  of_machine_is_compatible("samsung,midas"))) ||
 	    of_machine_is_compatible("samsung,exynos3250") ||
 	    of_machine_is_compatible("samsung,exynos5250"))
 		platform_device_register(&exynos_cpuidle);
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 782699e67600..1831319a679c 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -32,18 +32,6 @@ config MXC_DEBUG_BOARD
 	  data/address de-multiplexing and decode, signal level shift,
 	  interrupt control and various board functions.
 
-config HAVE_EPIT
-	bool
-
-config MXC_USE_EPIT
-	bool "Use EPIT instead of GPT"
-	depends on HAVE_EPIT
-	help
-	  Use EPIT as the system timer on systems that have it. Normally you
-	  don't have a reason to do so as the EPIT has the same features and
-	  uses the same clocks as the GPT. Anyway, on some systems the GPT
-	  may be in use for other purposes.
-
 config HAVE_IMX_ANATOP
 	bool
 
@@ -85,7 +73,6 @@ config SOC_IMX31
 config SOC_IMX35
 	bool
 	select ARCH_MXC_IOMUX_V3
-	select HAVE_EPIT
 	select MXC_AVIC
 	select PINCTRL_IMX35
 
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 8ff71058207d..04ba789ca34c 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
 obj-$(CONFIG_MXC_TZIC) += tzic.o
 obj-$(CONFIG_MXC_AVIC) += avic.o
 
-obj-$(CONFIG_MXC_USE_EPIT) += epit.o
 obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
 
 ifeq ($(CONFIG_CPU_IDLE),y)
diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c
index 649a84c251ad..61f3d94f1633 100644
--- a/arch/arm/mach-imx/anatop.c
+++ b/arch/arm/mach-imx/anatop.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP.
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
@@ -116,6 +117,7 @@ void __init imx_init_revision_from_anatop(void)
 	unsigned int revision;
 	u32 digprog;
 	u16 offset = ANADIG_DIGPROG;
+	u8 major_part, minor_part;
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
 	anatop_base = of_iomap(np, 0);
@@ -127,45 +129,25 @@ void __init imx_init_revision_from_anatop(void)
 	digprog = readl_relaxed(anatop_base + offset);
 	iounmap(anatop_base);
 
-	switch (digprog & 0xff) {
-	case 0:
-		/*
-		 * For i.MX6QP, most of the code for i.MX6Q can be resued,
-		 * so internally, we identify it as i.MX6Q Rev 2.0
-		 */
-		if (digprog >> 8 & 0x01)
-			revision = IMX_CHIP_REVISION_2_0;
-		else
-			revision = IMX_CHIP_REVISION_1_0;
-		break;
-	case 1:
-		revision = IMX_CHIP_REVISION_1_1;
-		break;
-	case 2:
-		revision = IMX_CHIP_REVISION_1_2;
-		break;
-	case 3:
-		revision = IMX_CHIP_REVISION_1_3;
-		break;
-	case 4:
-		revision = IMX_CHIP_REVISION_1_4;
-		break;
-	case 5:
-		/*
-		 * i.MX6DQ TO1.5 is defined as Rev 1.3 in Data Sheet, marked
-		 * as 'D' in Part Number last character.
-		 */
-		revision = IMX_CHIP_REVISION_1_5;
-		break;
-	default:
+	/*
+	 * On i.MX7D digprog value match linux version format, so
+	 * it needn't map again and we can use register value directly.
+	 */
+	if (of_device_is_compatible(np, "fsl,imx7d-anatop")) {
+		revision = digprog & 0xff;
+	} else {
 		/*
-		 * Fail back to return raw register value instead of 0xff.
-		 * It will be easy to know version information in SOC if it
-		 * can't be recognized by known version. And some chip's (i.MX7D)
-		 * digprog value match linux version format, so it needn't map
-		 * again and we can use register value directly.
+		 * MAJOR: [15:8], the major silicon revison;
+		 * MINOR: [7: 0], the minor silicon revison;
+		 *
+		 * please refer to the i.MX RM for the detailed
+		 * silicon revison bit define.
+		 * format the major part and minor part to match the
+		 * linux kernel soc version format.
 		 */
-		revision = digprog & 0xff;
+		major_part = (digprog >> 8) & 0xf;
+		minor_part = digprog & 0xf;
+		revision = ((major_part + 1) << 4) | minor_part;
 	}
 
 	mxc_set_cpu_type(digprog >> 16 & 0xff);
diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c
index c5a5c3a70ab1..d0f14b761ff7 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sx.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sx.c
@@ -89,6 +89,7 @@ static struct cpuidle_driver imx6sx_cpuidle_driver = {
 			 */
 			.exit_latency = 300,
 			.target_residency = 500,
+			.flags = CPUIDLE_FLAG_TIMER_STOP,
 			.enter = imx6sx_enter_wait,
 			.name = "LOW-POWER-IDLE",
 			.desc = "ARM power off",
diff --git a/arch/arm/mach-imx/epit.c b/arch/arm/mach-imx/epit.c
deleted file mode 100644
index fb9a73a57d00..000000000000
--- a/arch/arm/mach-imx/epit.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- *  linux/arch/arm/plat-mxc/epit.c
- *
- *  Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#define EPITCR		0x00
-#define EPITSR		0x04
-#define EPITLR		0x08
-#define EPITCMPR	0x0c
-#define EPITCNR		0x10
-
-#define EPITCR_EN			(1 << 0)
-#define EPITCR_ENMOD			(1 << 1)
-#define EPITCR_OCIEN			(1 << 2)
-#define EPITCR_RLD			(1 << 3)
-#define EPITCR_PRESC(x)			(((x) & 0xfff) << 4)
-#define EPITCR_SWR			(1 << 16)
-#define EPITCR_IOVW			(1 << 17)
-#define EPITCR_DBGEN			(1 << 18)
-#define EPITCR_WAITEN			(1 << 19)
-#define EPITCR_RES			(1 << 20)
-#define EPITCR_STOPEN			(1 << 21)
-#define EPITCR_OM_DISCON		(0 << 22)
-#define EPITCR_OM_TOGGLE		(1 << 22)
-#define EPITCR_OM_CLEAR			(2 << 22)
-#define EPITCR_OM_SET			(3 << 22)
-#define EPITCR_CLKSRC_OFF		(0 << 24)
-#define EPITCR_CLKSRC_PERIPHERAL	(1 << 24)
-#define EPITCR_CLKSRC_REF_HIGH		(1 << 24)
-#define EPITCR_CLKSRC_REF_LOW		(3 << 24)
-
-#define EPITSR_OCIF			(1 << 0)
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/clockchips.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-#include "hardware.h"
-
-static struct clock_event_device clockevent_epit;
-
-static void __iomem *timer_base;
-
-static inline void epit_irq_disable(void)
-{
-	u32 val;
-
-	val = imx_readl(timer_base + EPITCR);
-	val &= ~EPITCR_OCIEN;
-	imx_writel(val, timer_base + EPITCR);
-}
-
-static inline void epit_irq_enable(void)
-{
-	u32 val;
-
-	val = imx_readl(timer_base + EPITCR);
-	val |= EPITCR_OCIEN;
-	imx_writel(val, timer_base + EPITCR);
-}
-
-static void epit_irq_acknowledge(void)
-{
-	imx_writel(EPITSR_OCIF, timer_base + EPITSR);
-}
-
-static int __init epit_clocksource_init(struct clk *timer_clk)
-{
-	unsigned int c = clk_get_rate(timer_clk);
-
-	return clocksource_mmio_init(timer_base + EPITCNR, "epit", c, 200, 32,
-			clocksource_mmio_readl_down);
-}
-
-/* clock event */
-
-static int epit_set_next_event(unsigned long evt,
-			      struct clock_event_device *unused)
-{
-	unsigned long tcmp;
-
-	tcmp = imx_readl(timer_base + EPITCNR);
-
-	imx_writel(tcmp - evt, timer_base + EPITCMPR);
-
-	return 0;
-}
-
-/* Left event sources disabled, no more interrupts appear */
-static int epit_shutdown(struct clock_event_device *evt)
-{
-	unsigned long flags;
-
-	/*
-	 * The timer interrupt generation is disabled at least
-	 * for enough time to call epit_set_next_event()
-	 */
-	local_irq_save(flags);
-
-	/* Disable interrupt in GPT module */
-	epit_irq_disable();
-
-	/* Clear pending interrupt */
-	epit_irq_acknowledge();
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-static int epit_set_oneshot(struct clock_event_device *evt)
-{
-	unsigned long flags;
-
-	/*
-	 * The timer interrupt generation is disabled at least
-	 * for enough time to call epit_set_next_event()
-	 */
-	local_irq_save(flags);
-
-	/* Disable interrupt in GPT module */
-	epit_irq_disable();
-
-	/* Clear pending interrupt, only while switching mode */
-	if (!clockevent_state_oneshot(evt))
-		epit_irq_acknowledge();
-
-	/*
-	 * Do not put overhead of interrupt enable/disable into
-	 * epit_set_next_event(), the core has about 4 minutes
-	 * to call epit_set_next_event() or shutdown clock after
-	 * mode switching
-	 */
-	epit_irq_enable();
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = &clockevent_epit;
-
-	epit_irq_acknowledge();
-
-	evt->event_handler(evt);
-
-	return IRQ_HANDLED;
-}
-
-static struct irqaction epit_timer_irq = {
-	.name		= "i.MX EPIT Timer Tick",
-	.flags		= IRQF_TIMER | IRQF_IRQPOLL,
-	.handler	= epit_timer_interrupt,
-};
-
-static struct clock_event_device clockevent_epit = {
-	.name			= "epit",
-	.features		= CLOCK_EVT_FEAT_ONESHOT,
-	.set_state_shutdown	= epit_shutdown,
-	.tick_resume		= epit_shutdown,
-	.set_state_oneshot	= epit_set_oneshot,
-	.set_next_event		= epit_set_next_event,
-	.rating			= 200,
-};
-
-static int __init epit_clockevent_init(struct clk *timer_clk)
-{
-	clockevent_epit.cpumask = cpumask_of(0);
-	clockevents_config_and_register(&clockevent_epit,
-					clk_get_rate(timer_clk),
-					0x800, 0xfffffffe);
-
-	return 0;
-}
-
-void __init epit_timer_init(void __iomem *base, int irq)
-{
-	struct clk *timer_clk;
-
-	timer_clk = clk_get_sys("imx-epit.0", NULL);
-	if (IS_ERR(timer_clk)) {
-		pr_err("i.MX epit: unable to get clk\n");
-		return;
-	}
-
-	clk_prepare_enable(timer_clk);
-
-	timer_base = base;
-
-	/*
-	 * Initialise to a known state (all timers off, and timing reset)
-	 */
-	imx_writel(0x0, timer_base + EPITCR);
-
-	imx_writel(0xffffffff, timer_base + EPITLR);
-	imx_writel(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
-		   timer_base + EPITCR);
-
-	/* init and register the timer to the framework */
-	epit_clocksource_init(timer_clk);
-	epit_clockevent_init(timer_clk);
-
-	/* Make irqs happen */
-	setup_irq(irq, &epit_timer_irq);
-}
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 6b32dc527edc..2c20599cc350 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -41,7 +41,7 @@ config MACH_ARMADA_375
 	depends on ARCH_MULTI_V7
 	select ARMADA_370_XP_IRQ
 	select ARM_ERRATA_720789
-	select ARM_ERRATA_753970
+	select PL310_ERRATA_753970
 	select ARM_GIC
 	select ARMADA_375_CLK
 	select HAVE_ARM_SCU
@@ -57,7 +57,7 @@ config MACH_ARMADA_38X
 	bool "Marvell Armada 380/385 boards"
 	depends on ARCH_MULTI_V7
 	select ARM_ERRATA_720789
-	select ARM_ERRATA_753970
+	select PL310_ERRATA_753970
 	select ARM_GIC
 	select ARM_GLOBAL_TIMER
 	select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 43e3e188f521..fa512413a471 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -1011,17 +1011,17 @@ static int clk_debugfs_register_one(struct clk *c)
 		return -ENOMEM;
 	c->dent = d;
 
-	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
+	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
 	if (!d) {
 		err = -ENOMEM;
 		goto err_out;
 	}
-	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+	d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
 	if (!d) {
 		err = -ENOMEM;
 		goto err_out;
 	}
-	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
+	d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
 	if (!d) {
 		err = -ENOMEM;
 		goto err_out;
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index 65bb6e8085de..d83ff257eaa8 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -32,11 +32,10 @@
 
 #include <asm/exception.h>
 
-#include <plat/i2c.h>
-
 #include <mach/irqs.h>
 
 #include "soc.h"
+#include "i2c.h"
 
 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
 void omap7xx_map_io(void);
diff --git a/arch/arm/mach-omap1/i2c.c b/arch/arm/mach-omap1/i2c.c
index 32f6c53367bf..5bdf3c4190f9 100644
--- a/arch/arm/mach-omap1/i2c.c
+++ b/arch/arm/mach-omap1/i2c.c
@@ -24,8 +24,6 @@
 #include <mach/mux.h>
 #include "soc.h"
 
-#include <plat/i2c.h>
-
 #define OMAP_I2C_SIZE		0x3f
 #define OMAP1_I2C_BASE		0xfffb3800
 
diff --git a/arch/arm/mach-omap1/i2c.h b/arch/arm/mach-omap1/i2c.h
new file mode 100644
index 000000000000..54a2bce7879e
--- /dev/null
+++ b/arch/arm/mach-omap1/i2c.h
@@ -0,0 +1,50 @@
+/*
+ * Helper module for board specific I2C bus registration
+ *
+ * Copyright (C) 2009 Nokia 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_I2C_H
+#define __ARCH_ARM_MACH_OMAP1_I2C_H
+
+struct i2c_board_info;
+struct omap_i2c_bus_platform_data;
+
+int omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
+			int bus_id);
+
+#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
+				 struct i2c_board_info const *info,
+				 unsigned len);
+extern int omap_register_i2c_bus_cmdline(void);
+#else
+static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
+				 struct i2c_board_info const *info,
+				 unsigned len)
+{
+	return 0;
+}
+
+static inline int omap_register_i2c_bus_cmdline(void)
+{
+	return 0;
+}
+#endif
+
+#endif /* __ARCH_ARM_MACH_OMAP1_I2C_H */
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 93057fb65f44..ed6f074ea672 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -8,7 +8,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
-#include <linux/gpio.h>
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 6d28aa20a7d3..b064066d431c 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -13,9 +13,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
 #include <linux/mmc/host.h>
-#include <linux/platform_data/gpio-omap.h>
 #include <linux/platform_data/hsmmc-omap.h>
 
 #include "soc.h"
diff --git a/arch/arm/mach-omap2/i2c.h b/arch/arm/mach-omap2/i2c.h
index 42b6f2e7d190..4d085c7ad425 100644
--- a/arch/arm/mach-omap2/i2c.h
+++ b/arch/arm/mach-omap2/i2c.h
@@ -19,23 +19,10 @@
  *
  */
 
-#include <plat/i2c.h>
-
 #ifndef __MACH_OMAP2_I2C_H
 #define __MACH_OMAP2_I2C_H
 
-/**
- * i2c_dev_attr - OMAP I2C controller device attributes for omap_hwmod
- * @fifo_depth: total controller FIFO size (in bytes)
- * @flags: differences in hardware support capability
- *
- * @fifo_depth represents what exists on the hardware, not what is
- * actually configured at runtime by the device driver.
- */
-struct omap_i2c_dev_attr {
-	u8	fifo_depth;
-	u32	flags;
-};
+struct omap_hwmod;
 
 int omap_i2c_reset(struct omap_hwmod *oh);
 
diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c
index 5a3bc3de58d0..978fba722b82 100644
--- a/arch/arm/mach-omap2/msdi.c
+++ b/arch/arm/mach-omap2/msdi.c
@@ -23,7 +23,6 @@
 
 #include <linux/kernel.h>
 #include <linux/err.h>
-#include <linux/platform_data/gpio-omap.h>
 
 #include "prm.h"
 #include "common.h"
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 4bb6751864a5..fc5fb776a710 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -299,8 +299,6 @@ static void irq_save_context(void)
 	if (soc_is_dra7xx())
 		return;
 
-	if (!sar_base)
-		sar_base = omap4_get_sar_ram_base();
 	if (wakeupgen_ops && wakeupgen_ops->save_context)
 		wakeupgen_ops->save_context();
 }
@@ -598,6 +596,8 @@ static int __init wakeupgen_init(struct device_node *node,
 	irq_hotplug_init();
 	irq_pm_init();
 
+	sar_base = omap4_get_sar_ram_base();
+
 	return 0;
 }
 IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 124f9af34a15..34156eca8e23 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -977,6 +977,9 @@ static int _enable_clocks(struct omap_hwmod *oh)
 
 	pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name);
 
+	if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
+		_enable_optional_clocks(oh);
+
 	if (oh->_clk)
 		clk_enable(oh->_clk);
 
@@ -985,9 +988,6 @@ static int _enable_clocks(struct omap_hwmod *oh)
 			clk_enable(os->_clk);
 	}
 
-	if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
-		_enable_optional_clocks(oh);
-
 	/* The opt clocks are controlled by the device driver. */
 
 	return 0;
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index 0afb014b211f..fe66cf247874 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -14,9 +14,7 @@
  */
 
 #include <linux/i2c-omap.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/omap-dma.h>
-#include <plat/dmtimer.h>
 
 #include "omap_hwmod.h"
 #include "l3_2xxx.h"
@@ -97,13 +95,6 @@ static struct omap_hwmod_class i2c_class = {
 	.reset		= &omap_i2c_reset,
 };
 
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.flags		= OMAP_I2C_FLAG_NO_FIFO |
-			  OMAP_I2C_FLAG_SIMPLE_CLOCK |
-			  OMAP_I2C_FLAG_16BIT_DATA_REG |
-			  OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
 /* I2C1 */
 static struct omap_hwmod omap2420_i2c1_hwmod = {
 	.name		= "i2c1",
@@ -116,7 +107,6 @@ static struct omap_hwmod omap2420_i2c1_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c_dev_attr,
 	/*
 	 * From mach-omap2/pm24xx.c: "Putting MPU into the WFI state
 	 * while a transfer is active seems to cause the I2C block to
@@ -137,7 +127,6 @@ static struct omap_hwmod omap2420_i2c2_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c_dev_attr,
 	.flags		= HWMOD_16BIT_REG,
 };
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 013b26b305d2..74eefd30518c 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -14,11 +14,8 @@
  */
 
 #include <linux/i2c-omap.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
 #include <linux/platform_data/hsmmc-omap.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/omap-dma.h>
-#include <plat/dmtimer.h>
 
 #include "omap_hwmod.h"
 #include "l3_2xxx.h"
@@ -75,12 +72,6 @@ static struct omap_hwmod_class i2c_class = {
 	.reset		= &omap_i2c_reset,
 };
 
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.fifo_depth	= 8, /* bytes */
-	.flags		= OMAP_I2C_FLAG_BUS_SHIFT_2 |
-			  OMAP_I2C_FLAG_FORCE_19200_INT_CLK,
-};
-
 /* I2C1 */
 static struct omap_hwmod omap2430_i2c1_hwmod = {
 	.name		= "i2c1",
@@ -102,7 +93,6 @@ static struct omap_hwmod omap2430_i2c1_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* I2C2 */
@@ -118,7 +108,6 @@ static struct omap_hwmod omap2430_i2c2_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* gpio5 */
@@ -134,7 +123,6 @@ static struct omap_hwmod omap2430_gpio5_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &omap2xxx_gpio_dev_attr,
 };
 
 /* dma attributes */
@@ -167,10 +155,6 @@ static struct omap_hwmod omap2430_mailbox_hwmod = {
 };
 
 /* mcspi3 */
-static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
-	.num_chipselect = 2,
-};
-
 static struct omap_hwmod omap2430_mcspi3_hwmod = {
 	.name		= "mcspi3",
 	.main_clk	= "mcspi3_fck",
@@ -182,7 +166,6 @@ static struct omap_hwmod omap2430_mcspi3_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi3_dev_attr,
 };
 
 /* usbhsotg */
@@ -239,7 +222,6 @@ static struct omap_hwmod_class_sysconfig omap2430_mcbsp_sysc = {
 static struct omap_hwmod_class omap2430_mcbsp_hwmod_class = {
 	.name = "mcbsp",
 	.sysc = &omap2430_mcbsp_sysc,
-	.rev  = MCBSP_CONFIG_TYPE2,
 };
 
 static struct omap_hwmod_opt_clk mcbsp_opt_clks[] = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 4b094cb384cb..5345919a81f8 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -9,10 +9,8 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/platform_data/gpio-omap.h>
+#include <linux/types.h>
 #include <linux/omap-dma.h>
-#include <plat/dmtimer.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
 
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
@@ -159,7 +157,6 @@ static struct omap_hwmod_class_sysconfig omap2xxx_mcspi_sysc = {
 struct omap_hwmod_class omap2xxx_mcspi_class = {
 	.name	= "mcspi",
 	.sysc	= &omap2xxx_mcspi_sysc,
-	.rev	= OMAP2_MCSPI_REV,
 };
 
 /*
@@ -220,23 +217,7 @@ struct omap_hwmod omap2xxx_iva_hwmod = {
 	.class		= &iva_hwmod_class,
 };
 
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability       = OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_PWM,
-};
-
-/* timers with DSP interrupt dev attribute */
-static struct omap_timer_capability_dev_attr capability_dsp_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_DSP_IRQ,
-};
-
 /* timer1 */
-
 struct omap_hwmod omap2xxx_timer1_hwmod = {
 	.name		= "timer1",
 	.main_clk	= "gpt1_fck",
@@ -247,13 +228,11 @@ struct omap_hwmod omap2xxx_timer1_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer2 */
-
 struct omap_hwmod omap2xxx_timer2_hwmod = {
 	.name		= "timer2",
 	.main_clk	= "gpt2_fck",
@@ -269,7 +248,6 @@ struct omap_hwmod omap2xxx_timer2_hwmod = {
 };
 
 /* timer3 */
-
 struct omap_hwmod omap2xxx_timer3_hwmod = {
 	.name		= "timer3",
 	.main_clk	= "gpt3_fck",
@@ -285,7 +263,6 @@ struct omap_hwmod omap2xxx_timer3_hwmod = {
 };
 
 /* timer4 */
-
 struct omap_hwmod omap2xxx_timer4_hwmod = {
 	.name		= "timer4",
 	.main_clk	= "gpt4_fck",
@@ -301,7 +278,6 @@ struct omap_hwmod omap2xxx_timer4_hwmod = {
 };
 
 /* timer5 */
-
 struct omap_hwmod omap2xxx_timer5_hwmod = {
 	.name		= "timer5",
 	.main_clk	= "gpt5_fck",
@@ -312,13 +288,11 @@ struct omap_hwmod omap2xxx_timer5_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer6 */
-
 struct omap_hwmod omap2xxx_timer6_hwmod = {
 	.name		= "timer6",
 	.main_clk	= "gpt6_fck",
@@ -329,13 +303,11 @@ struct omap_hwmod omap2xxx_timer6_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer7 */
-
 struct omap_hwmod omap2xxx_timer7_hwmod = {
 	.name		= "timer7",
 	.main_clk	= "gpt7_fck",
@@ -346,13 +318,11 @@ struct omap_hwmod omap2xxx_timer7_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer8 */
-
 struct omap_hwmod omap2xxx_timer8_hwmod = {
 	.name		= "timer8",
 	.main_clk	= "gpt8_fck",
@@ -363,13 +333,11 @@ struct omap_hwmod omap2xxx_timer8_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer9 */
-
 struct omap_hwmod omap2xxx_timer9_hwmod = {
 	.name		= "timer9",
 	.main_clk	= "gpt9_fck",
@@ -380,13 +348,11 @@ struct omap_hwmod omap2xxx_timer9_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer10 */
-
 struct omap_hwmod omap2xxx_timer10_hwmod = {
 	.name		= "timer10",
 	.main_clk	= "gpt10_fck",
@@ -397,13 +363,11 @@ struct omap_hwmod omap2xxx_timer10_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer11 */
-
 struct omap_hwmod omap2xxx_timer11_hwmod = {
 	.name		= "timer11",
 	.main_clk	= "gpt11_fck",
@@ -414,13 +378,11 @@ struct omap_hwmod omap2xxx_timer11_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer12 */
-
 struct omap_hwmod omap2xxx_timer12_hwmod = {
 	.name		= "timer12",
 	.main_clk	= "gpt12_fck",
@@ -431,7 +393,6 @@ struct omap_hwmod omap2xxx_timer12_hwmod = {
 			.idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap2xxx_timer_hwmod_class,
 	.flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -568,12 +529,6 @@ struct omap_hwmod omap2xxx_dss_venc_hwmod = {
 	.flags		= HWMOD_NO_IDLEST,
 };
 
-/* gpio dev_attr */
-struct omap_gpio_dev_attr omap2xxx_gpio_dev_attr = {
-	.bank_width = 32,
-	.dbck_flag = false,
-};
-
 /* gpio1 */
 struct omap_hwmod omap2xxx_gpio1_hwmod = {
 	.name		= "gpio1",
@@ -587,7 +542,6 @@ struct omap_hwmod omap2xxx_gpio1_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &omap2xxx_gpio_dev_attr,
 };
 
 /* gpio2 */
@@ -603,7 +557,6 @@ struct omap_hwmod omap2xxx_gpio2_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &omap2xxx_gpio_dev_attr,
 };
 
 /* gpio3 */
@@ -619,7 +572,6 @@ struct omap_hwmod omap2xxx_gpio3_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &omap2xxx_gpio_dev_attr,
 };
 
 /* gpio4 */
@@ -635,14 +587,9 @@ struct omap_hwmod omap2xxx_gpio4_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_gpio_hwmod_class,
-	.dev_attr	= &omap2xxx_gpio_dev_attr,
 };
 
 /* mcspi1 */
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
-	.num_chipselect = 4,
-};
-
 struct omap_hwmod omap2xxx_mcspi1_hwmod = {
 	.name		= "mcspi1",
 	.main_clk	= "mcspi1_fck",
@@ -654,14 +601,9 @@ struct omap_hwmod omap2xxx_mcspi1_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi1_dev_attr,
 };
 
 /* mcspi2 */
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
-	.num_chipselect = 2,
-};
-
 struct omap_hwmod omap2xxx_mcspi2_hwmod = {
 	.name		= "mcspi2",
 	.main_clk	= "mcspi2_fck",
@@ -673,7 +615,6 @@ struct omap_hwmod omap2xxx_mcspi2_hwmod = {
 		},
 	},
 	.class		= &omap2xxx_mcspi_class,
-	.dev_attr	= &omap_mcspi2_dev_attr,
 };
 
 static struct omap_hwmod_class omap2xxx_counter_hwmod_class = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
index 434bd1a77229..6f81d7a4fec1 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
@@ -139,9 +139,6 @@ extern struct omap_hwmod_class am33xx_epwmss_hwmod_class;
 extern struct omap_hwmod_class am33xx_ehrpwm_hwmod_class;
 extern struct omap_hwmod_class am33xx_spi_hwmod_class;
 
-extern struct omap_gpio_dev_attr gpio_dev_attr;
-extern struct omap2_mcspi_dev_attr mcspi_attrib;
-
 void omap_hwmod_am33xx_reg(void);
 void omap_hwmod_am43xx_reg(void);
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
index 4bcf9f3e1544..5efe91c6e95b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -14,9 +14,9 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/platform_data/gpio-omap.h>
+#include <linux/types.h>
+
 #include <linux/platform_data/hsmmc-omap.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
 #include "omap_hwmod.h"
 #include "i2c.h"
 #include "wd_timer.h"
@@ -537,11 +537,6 @@ struct omap_hwmod_class am33xx_gpio_hwmod_class = {
 	.rev		= 2,
 };
 
-struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width	= 32,
-	.dbck_flag	= true,
-};
-
 /* gpio1 */
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 	{ .role = "dbclk", .clk = "gpio1_dbclk" },
@@ -560,7 +555,6 @@ struct omap_hwmod am33xx_gpio1_hwmod = {
 	},
 	.opt_clks	= gpio1_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio2 */
@@ -581,7 +575,6 @@ struct omap_hwmod am33xx_gpio2_hwmod = {
 	},
 	.opt_clks	= gpio2_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio3 */
@@ -602,7 +595,6 @@ struct omap_hwmod am33xx_gpio3_hwmod = {
 	},
 	.opt_clks	= gpio3_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpmc */
@@ -654,10 +646,6 @@ static struct omap_hwmod_class i2c_class = {
 	.reset		= &omap_i2c_reset,
 };
 
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE,
-};
-
 /* i2c1 */
 struct omap_hwmod am33xx_i2c1_hwmod = {
 	.name		= "i2c1",
@@ -670,7 +658,6 @@ struct omap_hwmod am33xx_i2c1_hwmod = {
 			.modulemode	= MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c1 */
@@ -685,7 +672,6 @@ struct omap_hwmod am33xx_i2c2_hwmod = {
 			.modulemode	= MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c3 */
@@ -700,7 +686,6 @@ struct omap_hwmod am33xx_i2c3_hwmod = {
 			.modulemode	= MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /*
@@ -893,13 +878,9 @@ static struct omap_hwmod_class_sysconfig am33xx_mcspi_sysc = {
 struct omap_hwmod_class am33xx_spi_hwmod_class = {
 	.name		= "mcspi",
 	.sysc		= &am33xx_mcspi_sysc,
-	.rev		= OMAP4_MCSPI_REV,
 };
 
 /* spi0 */
-struct omap2_mcspi_dev_attr mcspi_attrib = {
-	.num_chipselect	= 2,
-};
 struct omap_hwmod am33xx_spi0_hwmod = {
 	.name		= "spi0",
 	.class		= &am33xx_spi_hwmod_class,
@@ -910,7 +891,6 @@ struct omap_hwmod am33xx_spi0_hwmod = {
 			.modulemode	= MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi_attrib,
 };
 
 /* spi1 */
@@ -924,7 +904,6 @@ struct omap_hwmod am33xx_spi1_hwmod = {
 			.modulemode	= MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi_attrib,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
index 4d16b15bb0cf..53e1ac3724f2 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -17,9 +17,6 @@
 #include <linux/i2c-omap.h>
 
 #include "omap_hwmod.h"
-#include <linux/platform_data/gpio-omap.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-
 #include "omap_hwmod_common_data.h"
 
 #include "control.h"
@@ -252,7 +249,6 @@ static struct omap_hwmod am33xx_gpio0_hwmod = {
 	},
 	.opt_clks	= gpio0_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio0_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* lcdc */
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 1a2f2242e31b..23336b6c7125 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -17,15 +17,11 @@
 
 #include <linux/i2c-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/platform_data/gpio-omap.h>
 #include <linux/platform_data/hsmmc-omap.h>
 
 #include <linux/omap-dma.h>
 #include "l3_3xxx.h"
 #include "l4_3xxx.h"
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <plat/dmtimer.h>
 
 #include "soc.h"
 #include "omap_hwmod.h"
@@ -155,31 +151,6 @@ static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
 	.sysc = &omap3xxx_timer_sysc,
 };
 
-/* secure timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_secure_dev_attr = {
-	.timer_capability	= OMAP_TIMER_ALWON | OMAP_TIMER_SECURE,
-};
-
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability	= OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability	= OMAP_TIMER_HAS_PWM,
-};
-
-/* timers with DSP interrupt dev attribute */
-static struct omap_timer_capability_dev_attr capability_dsp_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_DSP_IRQ,
-};
-
-/* pwm timers with DSP interrupt dev attribute */
-static struct omap_timer_capability_dev_attr capability_dsp_pwm_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_DSP_IRQ | OMAP_TIMER_HAS_PWM,
-};
-
 /* timer1 */
 static struct omap_hwmod omap3xxx_timer1_hwmod = {
 	.name		= "timer1",
@@ -191,7 +162,6 @@ static struct omap_hwmod omap3xxx_timer1_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -252,7 +222,6 @@ static struct omap_hwmod omap3xxx_timer5_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -268,7 +237,6 @@ static struct omap_hwmod omap3xxx_timer6_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -284,7 +252,6 @@ static struct omap_hwmod omap3xxx_timer7_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -300,7 +267,6 @@ static struct omap_hwmod omap3xxx_timer8_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_dsp_pwm_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -316,7 +282,6 @@ static struct omap_hwmod omap3xxx_timer9_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -332,7 +297,6 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -348,13 +312,11 @@ static struct omap_hwmod omap3xxx_timer11_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
 /* timer12 */
-
 static struct omap_hwmod omap3xxx_timer12_hwmod = {
 	.name		= "timer12",
 	.main_clk	= "gpt12_fck",
@@ -365,7 +327,6 @@ static struct omap_hwmod omap3xxx_timer12_hwmod = {
 			.idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
 		},
 	},
-	.dev_attr	= &capability_secure_dev_attr,
 	.class		= &omap3xxx_timer_hwmod_class,
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
 };
@@ -683,11 +644,6 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = {
 };
 
 /* I2C1 */
-static struct omap_i2c_dev_attr i2c1_dev_attr = {
-	.fifo_depth	= 8, /* bytes */
-	.flags		= OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
 static struct omap_hwmod omap3xxx_i2c1_hwmod = {
 	.name		= "i2c1",
 	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
@@ -700,15 +656,9 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c1_dev_attr,
 };
 
 /* I2C2 */
-static struct omap_i2c_dev_attr i2c2_dev_attr = {
-	.fifo_depth	= 8, /* bytes */
-	.flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
 static struct omap_hwmod omap3xxx_i2c2_hwmod = {
 	.name		= "i2c2",
 	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
@@ -721,17 +671,9 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c2_dev_attr,
 };
 
 /* I2C3 */
-static struct omap_i2c_dev_attr i2c3_dev_attr = {
-	.fifo_depth	= 64, /* bytes */
-	.flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
-
-
 static struct omap_hwmod omap3xxx_i2c3_hwmod = {
 	.name		= "i2c3",
 	.flags		= HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
@@ -744,7 +686,6 @@ static struct omap_hwmod omap3xxx_i2c3_hwmod = {
 		},
 	},
 	.class		= &i2c_class,
-	.dev_attr	= &i2c3_dev_attr,
 };
 
 /*
@@ -769,12 +710,6 @@ static struct omap_hwmod_class omap3xxx_gpio_hwmod_class = {
 	.rev = 1,
 };
 
-/* gpio_dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width = 32,
-	.dbck_flag = true,
-};
-
 /* gpio1 */
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 	{ .role = "dbclk", .clk = "gpio1_dbck", },
@@ -794,7 +729,6 @@ static struct omap_hwmod omap3xxx_gpio1_hwmod = {
 		},
 	},
 	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio2 */
@@ -816,7 +750,6 @@ static struct omap_hwmod omap3xxx_gpio2_hwmod = {
 		},
 	},
 	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio3 */
@@ -838,7 +771,6 @@ static struct omap_hwmod omap3xxx_gpio3_hwmod = {
 		},
 	},
 	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio4 */
@@ -860,7 +792,6 @@ static struct omap_hwmod omap3xxx_gpio4_hwmod = {
 		},
 	},
 	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio5 */
@@ -883,7 +814,6 @@ static struct omap_hwmod omap3xxx_gpio5_hwmod = {
 		},
 	},
 	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio6 */
@@ -906,7 +836,6 @@ static struct omap_hwmod omap3xxx_gpio6_hwmod = {
 		},
 	},
 	.class		= &omap3xxx_gpio_hwmod_class,
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* dma attributes */
@@ -966,7 +895,6 @@ static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sysc = {
 static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = {
 	.name = "mcbsp",
 	.sysc = &omap3xxx_mcbsp_sysc,
-	.rev  = MCBSP_CONFIG_TYPE3,
 };
 
 /* McBSP functional clock mapping */
@@ -981,7 +909,6 @@ static struct omap_hwmod_opt_clk mcbsp234_opt_clks[] = {
 };
 
 /* mcbsp1 */
-
 static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
 	.name		= "mcbsp1",
 	.class		= &omap3xxx_mcbsp_hwmod_class,
@@ -998,11 +925,6 @@ static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
 };
 
 /* mcbsp2 */
-
-static struct omap_mcbsp_dev_attr omap34xx_mcbsp2_dev_attr = {
-	.sidetone	= "mcbsp2_sidetone",
-};
-
 static struct omap_hwmod omap3xxx_mcbsp2_hwmod = {
 	.name		= "mcbsp2",
 	.class		= &omap3xxx_mcbsp_hwmod_class,
@@ -1016,15 +938,9 @@ static struct omap_hwmod omap3xxx_mcbsp2_hwmod = {
 	},
 	.opt_clks	= mcbsp234_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(mcbsp234_opt_clks),
-	.dev_attr	= &omap34xx_mcbsp2_dev_attr,
 };
 
 /* mcbsp3 */
-
-static struct omap_mcbsp_dev_attr omap34xx_mcbsp3_dev_attr = {
-	.sidetone	= "mcbsp3_sidetone",
-};
-
 static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
 	.name		= "mcbsp3",
 	.class		= &omap3xxx_mcbsp_hwmod_class,
@@ -1038,12 +954,9 @@ static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
 	},
 	.opt_clks	= mcbsp234_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(mcbsp234_opt_clks),
-	.dev_attr	= &omap34xx_mcbsp3_dev_attr,
 };
 
 /* mcbsp4 */
-
-
 static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
 	.name		= "mcbsp4",
 	.class		= &omap3xxx_mcbsp_hwmod_class,
@@ -1060,8 +973,6 @@ static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
 };
 
 /* mcbsp5 */
-
-
 static struct omap_hwmod omap3xxx_mcbsp5_hwmod = {
 	.name		= "mcbsp5",
 	.class		= &omap3xxx_mcbsp_hwmod_class,
@@ -1090,7 +1001,6 @@ static struct omap_hwmod_class omap3xxx_mcbsp_sidetone_hwmod_class = {
 };
 
 /* mcbsp2_sidetone */
-
 static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
 	.name		= "mcbsp2_sidetone",
 	.class		= &omap3xxx_mcbsp_sidetone_hwmod_class,
@@ -1099,7 +1009,6 @@ static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
 };
 
 /* mcbsp3_sidetone */
-
 static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod = {
 	.name		= "mcbsp3_sidetone",
 	.class		= &omap3xxx_mcbsp_sidetone_hwmod_class,
@@ -1258,14 +1167,9 @@ static struct omap_hwmod_class_sysconfig omap34xx_mcspi_sysc = {
 static struct omap_hwmod_class omap34xx_mcspi_class = {
 	.name = "mcspi",
 	.sysc = &omap34xx_mcspi_sysc,
-	.rev = OMAP3_MCSPI_REV,
 };
 
 /* mcspi1 */
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
-	.num_chipselect = 4,
-};
-
 static struct omap_hwmod omap34xx_mcspi1 = {
 	.name		= "mcspi1",
 	.main_clk	= "mcspi1_fck",
@@ -1277,14 +1181,9 @@ static struct omap_hwmod omap34xx_mcspi1 = {
 		},
 	},
 	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi1_dev_attr,
 };
 
 /* mcspi2 */
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
-	.num_chipselect = 2,
-};
-
 static struct omap_hwmod omap34xx_mcspi2 = {
 	.name		= "mcspi2",
 	.main_clk	= "mcspi2_fck",
@@ -1296,16 +1195,9 @@ static struct omap_hwmod omap34xx_mcspi2 = {
 		},
 	},
 	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi2_dev_attr,
 };
 
 /* mcspi3 */
-
-
-static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
-	.num_chipselect = 2,
-};
-
 static struct omap_hwmod omap34xx_mcspi3 = {
 	.name		= "mcspi3",
 	.main_clk	= "mcspi3_fck",
@@ -1317,16 +1209,9 @@ static struct omap_hwmod omap34xx_mcspi3 = {
 		},
 	},
 	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi3_dev_attr,
 };
 
 /* mcspi4 */
-
-
-static struct omap2_mcspi_dev_attr omap_mcspi4_dev_attr = {
-	.num_chipselect = 1,
-};
-
 static struct omap_hwmod omap34xx_mcspi4 = {
 	.name		= "mcspi4",
 	.main_clk	= "mcspi4_fck",
@@ -1338,7 +1223,6 @@ static struct omap_hwmod omap34xx_mcspi4 = {
 		},
 	},
 	.class		= &omap34xx_mcspi_class,
-	.dev_attr       = &omap_mcspi4_dev_attr,
 };
 
 /* usbhsotg */
diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
index afbce1f6f641..5f73b730d4fc 100644
--- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
@@ -14,8 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/platform_data/gpio-omap.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
 #include "omap_hwmod.h"
 #include "omap_hwmod_33xx_43xx_common_data.h"
 #include "prcm43xx.h"
@@ -107,7 +105,6 @@ static struct omap_hwmod am43xx_gpio0_hwmod = {
 	},
 	.opt_clks	= gpio0_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio0_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 static struct omap_hwmod_class_sysconfig am43xx_synctimer_sysc = {
@@ -239,7 +236,6 @@ static struct omap_hwmod am43xx_spi2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi_attrib,
 };
 
 static struct omap_hwmod am43xx_spi3_hwmod = {
@@ -253,7 +249,6 @@ static struct omap_hwmod am43xx_spi3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi_attrib,
 };
 
 static struct omap_hwmod am43xx_spi4_hwmod = {
@@ -267,7 +262,6 @@ static struct omap_hwmod am43xx_spi4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi_attrib,
 };
 
 static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
@@ -288,7 +282,6 @@ static struct omap_hwmod am43xx_gpio4_hwmod = {
 	},
 	.opt_clks	= gpio4_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
@@ -309,7 +302,6 @@ static struct omap_hwmod am43xx_gpio5_hwmod = {
 	},
 	.opt_clks	= gpio5_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 static struct omap_hwmod_class am43xx_ocp2scp_hwmod_class = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index a1901c22a0f0..e4f8ae9cd637 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -21,17 +21,12 @@
  */
 
 #include <linux/io.h>
-#include <linux/platform_data/gpio-omap.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
 #include <linux/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <plat/dmtimer.h>
-
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
 #include "cm1_44xx.h"
@@ -1083,12 +1078,6 @@ static struct omap_hwmod_class omap44xx_gpio_hwmod_class = {
 	.rev	= 2,
 };
 
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width	= 32,
-	.dbck_flag	= true,
-};
-
 /* gpio1 */
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 	{ .role = "dbclk", .clk = "gpio1_dbclk" },
@@ -1108,7 +1097,6 @@ static struct omap_hwmod omap44xx_gpio1_hwmod = {
 	},
 	.opt_clks	= gpio1_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio2 */
@@ -1131,7 +1119,6 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = {
 	},
 	.opt_clks	= gpio2_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio3 */
@@ -1154,7 +1141,6 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = {
 	},
 	.opt_clks	= gpio3_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio4 */
@@ -1177,7 +1163,6 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = {
 	},
 	.opt_clks	= gpio4_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio5 */
@@ -1200,7 +1185,6 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = {
 	},
 	.opt_clks	= gpio5_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio6 */
@@ -1223,7 +1207,6 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = {
 	},
 	.opt_clks	= gpio6_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /*
@@ -1394,10 +1377,6 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
 	.reset	= &omap_i2c_reset,
 };
 
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.flags	= OMAP_I2C_FLAG_BUS_SHIFT_NONE,
-};
-
 /* i2c1 */
 static struct omap_hwmod omap44xx_i2c1_hwmod = {
 	.name		= "i2c1",
@@ -1412,7 +1391,6 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c2 */
@@ -1429,7 +1407,6 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c3 */
@@ -1446,7 +1423,6 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c4 */
@@ -1463,7 +1439,6 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /*
@@ -1702,7 +1677,6 @@ static struct omap_hwmod_class_sysconfig omap44xx_mcbsp_sysc = {
 static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = {
 	.name	= "mcbsp",
 	.sysc	= &omap44xx_mcbsp_sysc,
-	.rev	= MCBSP_CONFIG_TYPE4,
 };
 
 /* mcbsp1 */
@@ -1860,14 +1834,9 @@ static struct omap_hwmod_class_sysconfig omap44xx_mcspi_sysc = {
 static struct omap_hwmod_class omap44xx_mcspi_hwmod_class = {
 	.name	= "mcspi",
 	.sysc	= &omap44xx_mcspi_sysc,
-	.rev	= OMAP4_MCSPI_REV,
 };
 
 /* mcspi1 */
-static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
-	.num_chipselect	= 4,
-};
-
 static struct omap_hwmod omap44xx_mcspi1_hwmod = {
 	.name		= "mcspi1",
 	.class		= &omap44xx_mcspi_hwmod_class,
@@ -1880,14 +1849,9 @@ static struct omap_hwmod omap44xx_mcspi1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi1_dev_attr,
 };
 
 /* mcspi2 */
-static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
-	.num_chipselect	= 2,
-};
-
 static struct omap_hwmod omap44xx_mcspi2_hwmod = {
 	.name		= "mcspi2",
 	.class		= &omap44xx_mcspi_hwmod_class,
@@ -1900,14 +1864,9 @@ static struct omap_hwmod omap44xx_mcspi2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi2_dev_attr,
 };
 
 /* mcspi3 */
-static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
-	.num_chipselect	= 2,
-};
-
 static struct omap_hwmod omap44xx_mcspi3_hwmod = {
 	.name		= "mcspi3",
 	.class		= &omap44xx_mcspi_hwmod_class,
@@ -1920,14 +1879,9 @@ static struct omap_hwmod omap44xx_mcspi3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi3_dev_attr,
 };
 
 /* mcspi4 */
-static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
-	.num_chipselect	= 1,
-};
-
 static struct omap_hwmod omap44xx_mcspi4_hwmod = {
 	.name		= "mcspi4",
 	.class		= &omap44xx_mcspi_hwmod_class,
@@ -1940,7 +1894,6 @@ static struct omap_hwmod omap44xx_mcspi4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi4_dev_attr,
 };
 
 /*
@@ -2547,26 +2500,6 @@ static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
 	.sysc	= &omap44xx_timer_sysc,
 };
 
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability	= OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
-	.timer_capability	= OMAP_TIMER_HAS_PWM,
-};
-
-/* timers with DSP interrupt dev attribute */
-static struct omap_timer_capability_dev_attr capability_dsp_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_DSP_IRQ,
-};
-
-/* pwm timers with DSP interrupt dev attribute */
-static struct omap_timer_capability_dev_attr capability_dsp_pwm_dev_attr = {
-	.timer_capability       = OMAP_TIMER_HAS_DSP_IRQ | OMAP_TIMER_HAS_PWM,
-};
-
 /* timer1 */
 static struct omap_hwmod omap44xx_timer1_hwmod = {
 	.name		= "timer1",
@@ -2581,7 +2514,6 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 };
 
 /* timer2 */
@@ -2643,7 +2575,6 @@ static struct omap_hwmod omap44xx_timer5_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 };
 
 /* timer6 */
@@ -2659,7 +2590,6 @@ static struct omap_hwmod omap44xx_timer6_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 };
 
 /* timer7 */
@@ -2675,7 +2605,6 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_dsp_dev_attr,
 };
 
 /* timer8 */
@@ -2691,7 +2620,6 @@ static struct omap_hwmod omap44xx_timer8_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_dsp_pwm_dev_attr,
 };
 
 /* timer9 */
@@ -2707,7 +2635,6 @@ static struct omap_hwmod omap44xx_timer9_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 };
 
 /* timer10 */
@@ -2724,7 +2651,6 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 };
 
 /* timer11 */
@@ -2740,7 +2666,6 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_pwm_dev_attr,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
index 988e7eaa1330..c72cd84b07ec 100644
--- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
@@ -18,15 +18,11 @@
  */
 
 #include <linux/io.h>
-#include <linux/platform_data/gpio-omap.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
 #include <linux/i2c-omap.h>
 
 #include <linux/omap-dma.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <plat/dmtimer.h>
 
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
@@ -627,12 +623,6 @@ static struct omap_hwmod_class omap54xx_gpio_hwmod_class = {
 	.rev	= 2,
 };
 
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width	= 32,
-	.dbck_flag	= true,
-};
-
 /* gpio1 */
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 	{ .role = "dbclk", .clk = "gpio1_dbclk" },
@@ -652,7 +642,6 @@ static struct omap_hwmod omap54xx_gpio1_hwmod = {
 	},
 	.opt_clks	= gpio1_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio2 */
@@ -675,7 +664,6 @@ static struct omap_hwmod omap54xx_gpio2_hwmod = {
 	},
 	.opt_clks	= gpio2_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio3 */
@@ -698,7 +686,6 @@ static struct omap_hwmod omap54xx_gpio3_hwmod = {
 	},
 	.opt_clks	= gpio3_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio4 */
@@ -721,7 +708,6 @@ static struct omap_hwmod omap54xx_gpio4_hwmod = {
 	},
 	.opt_clks	= gpio4_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio5 */
@@ -744,7 +730,6 @@ static struct omap_hwmod omap54xx_gpio5_hwmod = {
 	},
 	.opt_clks	= gpio5_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio6 */
@@ -767,7 +752,6 @@ static struct omap_hwmod omap54xx_gpio6_hwmod = {
 	},
 	.opt_clks	= gpio6_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio7 */
@@ -790,7 +774,6 @@ static struct omap_hwmod omap54xx_gpio7_hwmod = {
 	},
 	.opt_clks	= gpio7_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio7_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio8 */
@@ -813,7 +796,6 @@ static struct omap_hwmod omap54xx_gpio8_hwmod = {
 	},
 	.opt_clks	= gpio8_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio8_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /*
@@ -839,11 +821,6 @@ static struct omap_hwmod_class omap54xx_i2c_hwmod_class = {
 	.rev	= OMAP_I2C_IP_VERSION_2,
 };
 
-/* i2c dev_attr */
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.flags	= OMAP_I2C_FLAG_BUS_SHIFT_NONE,
-};
-
 /* i2c1 */
 static struct omap_hwmod omap54xx_i2c1_hwmod = {
 	.name		= "i2c1",
@@ -858,7 +835,6 @@ static struct omap_hwmod omap54xx_i2c1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c2 */
@@ -875,7 +851,6 @@ static struct omap_hwmod omap54xx_i2c2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c3 */
@@ -892,7 +867,6 @@ static struct omap_hwmod omap54xx_i2c3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c4 */
@@ -909,7 +883,6 @@ static struct omap_hwmod omap54xx_i2c4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c5 */
@@ -926,7 +899,6 @@ static struct omap_hwmod omap54xx_i2c5_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /*
@@ -1012,7 +984,6 @@ static struct omap_hwmod_class_sysconfig omap54xx_mcbsp_sysc = {
 static struct omap_hwmod_class omap54xx_mcbsp_hwmod_class = {
 	.name	= "mcbsp",
 	.sysc	= &omap54xx_mcbsp_sysc,
-	.rev	= MCBSP_CONFIG_TYPE4,
 };
 
 /* mcbsp1 */
@@ -1149,15 +1120,9 @@ static struct omap_hwmod_class_sysconfig omap54xx_mcspi_sysc = {
 static struct omap_hwmod_class omap54xx_mcspi_hwmod_class = {
 	.name	= "mcspi",
 	.sysc	= &omap54xx_mcspi_sysc,
-	.rev	= OMAP4_MCSPI_REV,
 };
 
 /* mcspi1 */
-/* mcspi1 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
-	.num_chipselect	= 4,
-};
-
 static struct omap_hwmod omap54xx_mcspi1_hwmod = {
 	.name		= "mcspi1",
 	.class		= &omap54xx_mcspi_hwmod_class,
@@ -1170,15 +1135,9 @@ static struct omap_hwmod omap54xx_mcspi1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi1_dev_attr,
 };
 
 /* mcspi2 */
-/* mcspi2 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
-	.num_chipselect	= 2,
-};
-
 static struct omap_hwmod omap54xx_mcspi2_hwmod = {
 	.name		= "mcspi2",
 	.class		= &omap54xx_mcspi_hwmod_class,
@@ -1191,15 +1150,9 @@ static struct omap_hwmod omap54xx_mcspi2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi2_dev_attr,
 };
 
 /* mcspi3 */
-/* mcspi3 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
-	.num_chipselect	= 2,
-};
-
 static struct omap_hwmod omap54xx_mcspi3_hwmod = {
 	.name		= "mcspi3",
 	.class		= &omap54xx_mcspi_hwmod_class,
@@ -1212,15 +1165,9 @@ static struct omap_hwmod omap54xx_mcspi3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi3_dev_attr,
 };
 
 /* mcspi4 */
-/* mcspi4 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
-	.num_chipselect	= 1,
-};
-
 static struct omap_hwmod omap54xx_mcspi4_hwmod = {
 	.name		= "mcspi4",
 	.class		= &omap54xx_mcspi_hwmod_class,
@@ -1233,7 +1180,6 @@ static struct omap_hwmod omap54xx_mcspi4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi4_dev_attr,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index 4c2a05b1bd19..62352d1e6361 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -18,15 +18,11 @@
  */
 
 #include <linux/io.h>
-#include <linux/platform_data/gpio-omap.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
 #include <linux/i2c-omap.h>
 
 #include <linux/omap-dma.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <plat/dmtimer.h>
 
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
@@ -818,12 +814,6 @@ static struct omap_hwmod_class dra7xx_gpio_hwmod_class = {
 	.rev	= 2,
 };
 
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width	= 32,
-	.dbck_flag	= true,
-};
-
 /* gpio1 */
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 	{ .role = "dbclk", .clk = "gpio1_dbclk" },
@@ -844,7 +834,6 @@ static struct omap_hwmod dra7xx_gpio1_hwmod = {
 	},
 	.opt_clks	= gpio1_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio2 */
@@ -867,7 +856,6 @@ static struct omap_hwmod dra7xx_gpio2_hwmod = {
 	},
 	.opt_clks	= gpio2_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio3 */
@@ -890,7 +878,6 @@ static struct omap_hwmod dra7xx_gpio3_hwmod = {
 	},
 	.opt_clks	= gpio3_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio3_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio4 */
@@ -913,7 +900,6 @@ static struct omap_hwmod dra7xx_gpio4_hwmod = {
 	},
 	.opt_clks	= gpio4_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio4_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio5 */
@@ -936,7 +922,6 @@ static struct omap_hwmod dra7xx_gpio5_hwmod = {
 	},
 	.opt_clks	= gpio5_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio5_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio6 */
@@ -959,7 +944,6 @@ static struct omap_hwmod dra7xx_gpio6_hwmod = {
 	},
 	.opt_clks	= gpio6_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio6_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio7 */
@@ -982,7 +966,6 @@ static struct omap_hwmod dra7xx_gpio7_hwmod = {
 	},
 	.opt_clks	= gpio7_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio7_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /* gpio8 */
@@ -1005,7 +988,6 @@ static struct omap_hwmod dra7xx_gpio8_hwmod = {
 	},
 	.opt_clks	= gpio8_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio8_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 /*
@@ -1105,11 +1087,6 @@ static struct omap_hwmod_class dra7xx_i2c_hwmod_class = {
 	.rev	= OMAP_I2C_IP_VERSION_2,
 };
 
-/* i2c dev_attr */
-static struct omap_i2c_dev_attr i2c_dev_attr = {
-	.flags	= OMAP_I2C_FLAG_BUS_SHIFT_NONE,
-};
-
 /* i2c1 */
 static struct omap_hwmod dra7xx_i2c1_hwmod = {
 	.name		= "i2c1",
@@ -1124,7 +1101,6 @@ static struct omap_hwmod dra7xx_i2c1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c2 */
@@ -1141,7 +1117,6 @@ static struct omap_hwmod dra7xx_i2c2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c3 */
@@ -1158,7 +1133,6 @@ static struct omap_hwmod dra7xx_i2c3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c4 */
@@ -1175,7 +1149,6 @@ static struct omap_hwmod dra7xx_i2c4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /* i2c5 */
@@ -1192,7 +1165,6 @@ static struct omap_hwmod dra7xx_i2c5_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &i2c_dev_attr,
 };
 
 /*
@@ -1401,15 +1373,9 @@ static struct omap_hwmod_class_sysconfig dra7xx_mcspi_sysc = {
 static struct omap_hwmod_class dra7xx_mcspi_hwmod_class = {
 	.name	= "mcspi",
 	.sysc	= &dra7xx_mcspi_sysc,
-	.rev	= OMAP4_MCSPI_REV,
 };
 
 /* mcspi1 */
-/* mcspi1 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
-	.num_chipselect	= 4,
-};
-
 static struct omap_hwmod dra7xx_mcspi1_hwmod = {
 	.name		= "mcspi1",
 	.class		= &dra7xx_mcspi_hwmod_class,
@@ -1422,15 +1388,9 @@ static struct omap_hwmod dra7xx_mcspi1_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi1_dev_attr,
 };
 
 /* mcspi2 */
-/* mcspi2 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
-	.num_chipselect	= 2,
-};
-
 static struct omap_hwmod dra7xx_mcspi2_hwmod = {
 	.name		= "mcspi2",
 	.class		= &dra7xx_mcspi_hwmod_class,
@@ -1443,15 +1403,9 @@ static struct omap_hwmod dra7xx_mcspi2_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi2_dev_attr,
 };
 
 /* mcspi3 */
-/* mcspi3 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
-	.num_chipselect	= 2,
-};
-
 static struct omap_hwmod dra7xx_mcspi3_hwmod = {
 	.name		= "mcspi3",
 	.class		= &dra7xx_mcspi_hwmod_class,
@@ -1464,15 +1418,9 @@ static struct omap_hwmod dra7xx_mcspi3_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi3_dev_attr,
 };
 
 /* mcspi4 */
-/* mcspi4 dev_attr */
-static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
-	.num_chipselect	= 1,
-};
-
 static struct omap_hwmod dra7xx_mcspi4_hwmod = {
 	.name		= "mcspi4",
 	.class		= &dra7xx_mcspi_hwmod_class,
@@ -1485,7 +1433,6 @@ static struct omap_hwmod dra7xx_mcspi4_hwmod = {
 			.modulemode   = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &mcspi4_dev_attr,
 };
 
 /*
diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
index 84f118280a0e..686655f884c1 100644
--- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
@@ -15,10 +15,9 @@
  *
  */
 
-#include <linux/platform_data/gpio-omap.h>
+#include <linux/types.h>
+
 #include <linux/platform_data/hsmmc-omap.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <plat/dmtimer.h>
 
 #include "omap_hwmod_common_data.h"
 #include "cm81xx.h"
@@ -488,11 +487,6 @@ static struct omap_hwmod_class dm81xx_gpio_hwmod_class = {
 	.rev	= 2,
 };
 
-static struct omap_gpio_dev_attr gpio_dev_attr = {
-	.bank_width	= 32,
-	.dbck_flag	= true,
-};
-
 static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
 	{ .role = "dbclk", .clk = "sysclk18_ck" },
 };
@@ -510,7 +504,6 @@ static struct omap_hwmod dm81xx_gpio1_hwmod = {
 	},
 	.opt_clks	= gpio1_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio1_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 static struct omap_hwmod_ocp_if dm81xx_l4_ls__gpio1 = {
@@ -537,7 +530,6 @@ static struct omap_hwmod dm81xx_gpio2_hwmod = {
 	},
 	.opt_clks	= gpio2_opt_clks,
 	.opt_clks_cnt	= ARRAY_SIZE(gpio2_opt_clks),
-	.dev_attr	= &gpio_dev_attr,
 };
 
 static struct omap_hwmod_ocp_if dm81xx_l4_ls__gpio2 = {
@@ -654,15 +646,10 @@ static struct omap_hwmod_class dm816x_timer_hwmod_class = {
 	.sysc = &dm816x_timer_sysc,
 };
 
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
-	.timer_capability	= OMAP_TIMER_ALWON,
-};
-
 static struct omap_hwmod dm814x_timer1_hwmod = {
 	.name		= "timer1",
 	.clkdm_name	= "alwon_l3s_clkdm",
 	.main_clk	= "timer1_fck",
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 	.flags		= HWMOD_NO_IDLEST,
 };
@@ -684,7 +671,6 @@ static struct omap_hwmod dm816x_timer1_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -699,7 +685,6 @@ static struct omap_hwmod dm814x_timer2_hwmod = {
 	.name		= "timer2",
 	.clkdm_name	= "alwon_l3s_clkdm",
 	.main_clk	= "timer2_fck",
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 	.flags		= HWMOD_NO_IDLEST,
 };
@@ -721,7 +706,6 @@ static struct omap_hwmod dm816x_timer2_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -742,7 +726,6 @@ static struct omap_hwmod dm816x_timer3_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -763,7 +746,6 @@ static struct omap_hwmod dm816x_timer4_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -784,7 +766,6 @@ static struct omap_hwmod dm816x_timer5_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -805,7 +786,6 @@ static struct omap_hwmod dm816x_timer6_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -826,7 +806,6 @@ static struct omap_hwmod dm816x_timer7_hwmod = {
 			.modulemode = MODULEMODE_SWCTRL,
 		},
 	},
-	.dev_attr	= &capability_alwon_dev_attr,
 	.class		= &dm816x_timer_hwmod_class,
 };
 
@@ -1138,11 +1117,6 @@ static struct omap_hwmod_class_sysconfig dm816x_mcspi_sysc = {
 static struct omap_hwmod_class dm816x_mcspi_class = {
 	.name = "mcspi",
 	.sysc = &dm816x_mcspi_sysc,
-	.rev = OMAP3_MCSPI_REV,
-};
-
-static struct omap2_mcspi_dev_attr dm816x_mcspi1_dev_attr = {
-	.num_chipselect = 4,
 };
 
 static struct omap_hwmod dm81xx_mcspi1_hwmod = {
@@ -1156,7 +1130,6 @@ static struct omap_hwmod dm81xx_mcspi1_hwmod = {
 		},
 	},
 	.class		= &dm816x_mcspi_class,
-	.dev_attr	= &dm816x_mcspi1_dev_attr,
 };
 
 static struct omap_hwmod_ocp_if dm81xx_l4_ls__mcspi1 = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.h b/arch/arm/mach-omap2/omap_hwmod_common_data.h
index 29a52df2de26..56dbaca9a728 100644
--- a/arch/arm/mach-omap2/omap_hwmod_common_data.h
+++ b/arch/arm/mach-omap2/omap_hwmod_common_data.h
@@ -19,7 +19,6 @@
 #include "display.h"
 
 /* Common IP block data across OMAP2xxx */
-extern struct omap_gpio_dev_attr omap2xxx_gpio_dev_attr;
 extern struct omap_hwmod omap2xxx_l3_main_hwmod;
 extern struct omap_hwmod omap2xxx_l4_core_hwmod;
 extern struct omap_hwmod omap2xxx_l4_wkup_hwmod;
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 366158a54fcd..6f68576e5695 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -186,7 +186,7 @@ static void omap_pm_end(void)
 	cpu_idle_poll_ctrl(false);
 }
 
-static void omap_pm_finish(void)
+static void omap_pm_wake(void)
 {
 	if (soc_is_omap34xx())
 		omap_prcm_irq_complete();
@@ -196,7 +196,7 @@ static const struct platform_suspend_ops omap_pm_ops = {
 	.begin		= omap_pm_begin,
 	.end		= omap_pm_end,
 	.enter		= omap_pm_enter,
-	.finish		= omap_pm_finish,
+	.wake		= omap_pm_wake,
 	.valid		= suspend_valid_only_mem,
 };
 
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index ece09c9461f7..d61fbd7a2840 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -156,12 +156,6 @@ static struct clock_event_device clockevent_gpt = {
 	.tick_resume		= omap2_gp_timer_shutdown,
 };
 
-static struct property device_disabled = {
-	.name = "status",
-	.length = sizeof("disabled"),
-	.value = "disabled",
-};
-
 static const struct of_device_id omap_timer_match[] __initconst = {
 	{ .compatible = "ti,omap2420-timer", },
 	{ .compatible = "ti,omap3430-timer", },
@@ -203,8 +197,17 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id *
 				  of_get_property(np, "ti,timer-secure", NULL)))
 			continue;
 
-		if (!of_device_is_compatible(np, "ti,omap-counter32k"))
-			of_add_property(np, &device_disabled);
+		if (!of_device_is_compatible(np, "ti,omap-counter32k")) {
+			struct property *prop;
+
+			prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+			if (!prop)
+				return NULL;
+			prop->name = "status";
+			prop->value = "disabled";
+			prop->length = strlen(prop->value);
+			of_add_property(np, prop);
+		}
 		return np;
 	}
 
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index c487401b6fdb..69d7f48a4183 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -23,6 +23,7 @@
 #include <linux/clk.h>
 
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/dm9000.h>
 #include <linux/leds.h>
 #include <linux/platform_data/rtc-v3020.h>
@@ -343,9 +344,6 @@ static inline void cm_x300_init_bl(void) {}
 #define LCD_SPI_BUS_NUM	(1)
 
 static struct spi_gpio_platform_data cm_x300_spi_gpio_pdata = {
-	.sck		= GPIO_LCD_SCL,
-	.mosi		= GPIO_LCD_DIN,
-	.miso		= GPIO_LCD_DOUT,
 	.num_chipselect	= 1,
 };
 
@@ -357,6 +355,21 @@ static struct platform_device cm_x300_spi_gpio = {
 	},
 };
 
+static struct gpiod_lookup_table cm_x300_spi_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_SCL,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DIN,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_DOUT,
+			    "miso", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio-pxa", GPIO_LCD_CS,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 static struct tdo24m_platform_data cm_x300_tdo24m_pdata = {
 	.model = TDO35S,
 };
@@ -367,7 +380,6 @@ static struct spi_board_info cm_x300_spi_devices[] __initdata = {
 		.max_speed_hz		= 1000000,
 		.bus_num		= LCD_SPI_BUS_NUM,
 		.chip_select		= 0,
-		.controller_data	= (void *) GPIO_LCD_CS,
 		.platform_data		= &cm_x300_tdo24m_pdata,
 	},
 };
@@ -376,6 +388,7 @@ static void __init cm_x300_init_spi(void)
 {
 	spi_register_board_info(cm_x300_spi_devices,
 				ARRAY_SIZE(cm_x300_spi_devices));
+	gpiod_add_lookup_table(&cm_x300_spi_gpiod_table);
 	platform_device_register(&cm_x300_spi_gpio);
 }
 #else
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 4d5d05cf87d6..e7ac7dcb95e9 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -646,9 +646,6 @@ static void __init raumfeld_lcd_init(void)
  */
 
 static struct spi_gpio_platform_data raumfeld_spi_platform_data = {
-	.sck		= GPIO_SPI_CLK,
-	.mosi		= GPIO_SPI_MOSI,
-	.miso		= GPIO_SPI_MISO,
 	.num_chipselect	= 3,
 };
 
@@ -660,6 +657,25 @@ static struct platform_device raumfeld_spi_device = {
 	}
 };
 
+static struct gpiod_lookup_table raumfeld_spi_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("gpio-0", GPIO_SPI_CLK,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio-0", GPIO_SPI_MOSI,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio-0", GPIO_SPI_MISO,
+			    "miso", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio-0", GPIO_SPDIF_CS,
+				"cs", 0, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio-0", GPIO_ACCEL_CS,
+				"cs", 1, GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP_IDX("gpio-0", GPIO_MCLK_DAC_CS,
+				"cs", 2, GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 static struct lis3lv02d_platform_data lis3_pdata = {
 	.click_flags 	= LIS3_CLICK_SINGLE_X |
 			  LIS3_CLICK_SINGLE_Y |
@@ -680,7 +696,6 @@ static struct lis3lv02d_platform_data lis3_pdata = {
 	.max_speed_hz	= 10000,		\
 	.bus_num	= 0,			\
 	.chip_select	= 0,			\
-	.controller_data = (void *) GPIO_SPDIF_CS,	\
 }
 
 #define SPI_LIS3	\
@@ -689,7 +704,6 @@ static struct lis3lv02d_platform_data lis3_pdata = {
 	.max_speed_hz	= 1000000,		\
 	.bus_num	= 0,			\
 	.chip_select	= 1,			\
-	.controller_data = (void *) GPIO_ACCEL_CS,	\
 	.platform_data	= &lis3_pdata,		\
 	.irq		= PXA_GPIO_TO_IRQ(GPIO_ACCEL_IRQ),	\
 }
@@ -700,7 +714,6 @@ static struct lis3lv02d_platform_data lis3_pdata = {
 	.max_speed_hz	= 1000000,		\
 	.bus_num	= 0,			\
 	.chip_select	= 2,			\
-	.controller_data = (void *) GPIO_MCLK_DAC_CS,	\
 }
 
 static struct spi_board_info connector_spi_devices[] __initdata = {
@@ -1066,6 +1079,7 @@ static void __init raumfeld_common_init(void)
 	else
 		gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0);
 
+	gpiod_add_lookup_table(&raumfeld_spi_gpiod_table);
 	platform_add_devices(ARRAY_AND_SIZE(raumfeld_common_devices));
 	i2c_register_board_info(1, &raumfeld_pwri2c_board_info, 1);
 }
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index a3ddbbbd6d92..59589a4a0d4b 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -12,6 +12,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/syscore_ops.h>
 #include <linux/serial_core.h>
 #include <linux/serial_s3c.h>
@@ -388,32 +389,53 @@ static struct ili9320_platdata jive_lcm_config = {
 /* LCD SPI support */
 
 static struct spi_gpio_platform_data jive_lcd_spi = {
-	.sck		= S3C2410_GPG(8),
-	.mosi		= S3C2410_GPB(8),
-	.miso		= SPI_GPIO_NO_MISO,
+	.num_chipselect	= 1,
 };
 
 static struct platform_device jive_device_lcdspi = {
-	.name		= "spi-gpio",
+	.name		= "spi_gpio",
 	.id		= 1,
 	.dev.platform_data = &jive_lcd_spi,
 };
 
+static struct gpiod_lookup_table jive_lcdspi_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("GPIOG", 8,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOB", 8,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOB", 7,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
 
 /* WM8750 audio code SPI definition */
 
 static struct spi_gpio_platform_data jive_wm8750_spi = {
-	.sck		= S3C2410_GPB(4),
-	.mosi		= S3C2410_GPB(9),
-	.miso		= SPI_GPIO_NO_MISO,
+	.num_chipselect	= 1,
 };
 
 static struct platform_device jive_device_wm8750 = {
-	.name		= "spi-gpio",
+	.name		= "spi_gpio",
 	.id		= 2,
 	.dev.platform_data = &jive_wm8750_spi,
 };
 
+static struct gpiod_lookup_table jive_wm8750_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("GPIOB", 4,
+			    "gpio-sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOB", 9,
+			    "gpio-mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOH", 10,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 /* JIVE SPI devices. */
 
 static struct spi_board_info __initdata jive_spi_devs[] = {
@@ -424,14 +446,12 @@ static struct spi_board_info __initdata jive_spi_devs[] = {
 		.mode		= SPI_MODE_3,	/* CPOL=1, CPHA=1 */
 		.max_speed_hz	= 100000,
 		.platform_data	= &jive_lcm_config,
-		.controller_data = (void *)S3C2410_GPB(7),
 	}, {
 		.modalias	= "WM8750",
 		.bus_num	= 2,
 		.chip_select	= 0,
 		.mode		= SPI_MODE_0,	/* CPOL=0, CPHA=0 */
 		.max_speed_hz	= 100000,
-		.controller_data = (void *)S3C2410_GPH(10),
 	},
 };
 
@@ -619,25 +639,12 @@ static void __init jive_machine_init(void)
 	/** TODO - check that this is after the cmdline option! */
 	s3c_nand_set_platdata(&jive_nand_info);
 
-	/* initialise the spi */
-
 	gpio_request(S3C2410_GPG(13), "lcm reset");
 	gpio_direction_output(S3C2410_GPG(13), 0);
 
-	gpio_request(S3C2410_GPB(7), "jive spi");
-	gpio_direction_output(S3C2410_GPB(7), 1);
-
 	gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL);
 	gpio_free(S3C2410_GPB(6));
 
-	gpio_request_one(S3C2410_GPG(8), GPIOF_OUT_INIT_HIGH, NULL);
-	gpio_free(S3C2410_GPG(8));
-
-	/* initialise the WM8750 spi */
-
-	gpio_request(S3C2410_GPH(10), "jive wm8750 spi");
-	gpio_direction_output(S3C2410_GPH(10), 1);
-
 	/* Turn off suspend on both USB ports, and switch the
 	 * selectable USB port to USB device mode. */
 
@@ -655,6 +662,8 @@ static void __init jive_machine_init(void)
 
 	pm_power_off = jive_power_off;
 
+	gpiod_add_lookup_table(&jive_lcdspi_gpiod_table);
+	gpiod_add_lookup_table(&jive_wm8750_gpiod_table);
 	platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices));
 }
 
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 9c8373b8d9c3..5d48e5b6e738 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -11,6 +11,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
@@ -194,17 +195,30 @@ static struct platform_device qt2410_led = {
 /* SPI */
 
 static struct spi_gpio_platform_data spi_gpio_cfg = {
-	.sck		= S3C2410_GPG(7),
-	.mosi		= S3C2410_GPG(6),
-	.miso		= S3C2410_GPG(5),
+	.num_chipselect	= 1,
 };
 
 static struct platform_device qt2410_spi = {
-	.name		= "spi-gpio",
+	.name		= "spi_gpio",
 	.id		= 1,
 	.dev.platform_data = &spi_gpio_cfg,
 };
 
+static struct gpiod_lookup_table qt2410_spi_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("GPIOG", 7,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOG", 6,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOG", 5,
+			    "miso", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOB", 5,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 /* Board devices */
 
 static struct platform_device *qt2410_devices[] __initdata = {
@@ -323,9 +337,7 @@ static void __init qt2410_machine_init(void)
 	s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
 	s3c_i2c0_set_platdata(NULL);
 
-	WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs"));
-	gpio_direction_output(S3C2410_GPB(5), 1);
-
+	gpiod_add_lookup_table(&qt2410_spi_gpiod_table);
 	platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
 	s3c_pm_init();
 }
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index 5655fe968b1f..951208f168e7 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -206,17 +206,30 @@ static int __init smartq_lcd_setup_gpio(void)
 
 /* GPM0 -> CS */
 static struct spi_gpio_platform_data smartq_lcd_control = {
-	.sck			= S3C64XX_GPM(1),
-	.mosi			= S3C64XX_GPM(2),
-	.miso			= S3C64XX_GPM(2),
+	.num_chipselect	= 1,
 };
 
 static struct platform_device smartq_lcd_control_device = {
-	.name			= "spi-gpio",
+	.name			= "spi_gpio",
 	.id			= 1,
 	.dev.platform_data	= &smartq_lcd_control,
 };
 
+static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("GPIOM", 1,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOM", 2,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOM", 3,
+			    "miso", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOM", 0,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power)
 {
 	gpio_direction_output(S3C64XX_GPM(3), power);
@@ -404,6 +417,7 @@ void __init smartq_machine_init(void)
 	WARN_ON(smartq_wifi_init());
 
 	pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
+	gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table);
 	platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
 
 	gpiod_add_lookup_table(&smartq_audio_gpios);
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 58153cdf025b..ce53ceaf4cc5 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -48,4 +48,11 @@ config MACH_SUN9I
 	default ARCH_SUNXI
 	select ARM_GIC
 
+config ARCH_SUNXI_MC_SMP
+	bool
+	depends on SMP
+	default MACH_SUN9I
+	select ARM_CCI400_PORT_CTRL
+	select ARM_CPU_SUSPEND
+
 endif
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 27b168f121a1..3e741e959c7c 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ARCH_SUNXI) += sunxi.o
+obj-$(CONFIG_ARCH_SUNXI_MC_SMP) += mc_smp.o
 obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-sunxi/mc_smp.c b/arch/arm/mach-sunxi/mc_smp.c
new file mode 100644
index 000000000000..11e46c6efb90
--- /dev/null
+++ b/arch/arm/mach-sunxi/mc_smp.c
@@ -0,0 +1,791 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * arch/arm/mach-sunxi/mc_smp.c
+ *
+ * Based on Allwinner code, arch/arm/mach-exynos/mcpm-exynos.c, and
+ * arch/arm/mach-hisi/platmcpm.c
+ * Cluster cache enable trampoline code adapted from MCPM framework
+ */
+
+#include <linux/arm-cci.h>
+#include <linux/cpu_pm.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cp15.h>
+#include <asm/cputype.h>
+#include <asm/idmap.h>
+#include <asm/smp_plat.h>
+#include <asm/suspend.h>
+
+#define SUNXI_CPUS_PER_CLUSTER		4
+#define SUNXI_NR_CLUSTERS		2
+
+#define POLL_USEC	100
+#define TIMEOUT_USEC	100000
+
+#define CPUCFG_CX_CTRL_REG0(c)		(0x10 * (c))
+#define CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE(n)	BIT(n)
+#define CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE_ALL	0xf
+#define CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A7	BIT(4)
+#define CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A15	BIT(0)
+#define CPUCFG_CX_CTRL_REG1(c)		(0x10 * (c) + 0x4)
+#define CPUCFG_CX_CTRL_REG1_ACINACTM	BIT(0)
+#define CPUCFG_CX_STATUS(c)		(0x30 + 0x4 * (c))
+#define CPUCFG_CX_STATUS_STANDBYWFI(n)	BIT(16 + (n))
+#define CPUCFG_CX_STATUS_STANDBYWFIL2	BIT(0)
+#define CPUCFG_CX_RST_CTRL(c)		(0x80 + 0x4 * (c))
+#define CPUCFG_CX_RST_CTRL_DBG_SOC_RST	BIT(24)
+#define CPUCFG_CX_RST_CTRL_ETM_RST(n)	BIT(20 + (n))
+#define CPUCFG_CX_RST_CTRL_ETM_RST_ALL	(0xf << 20)
+#define CPUCFG_CX_RST_CTRL_DBG_RST(n)	BIT(16 + (n))
+#define CPUCFG_CX_RST_CTRL_DBG_RST_ALL	(0xf << 16)
+#define CPUCFG_CX_RST_CTRL_H_RST	BIT(12)
+#define CPUCFG_CX_RST_CTRL_L2_RST	BIT(8)
+#define CPUCFG_CX_RST_CTRL_CX_RST(n)	BIT(4 + (n))
+#define CPUCFG_CX_RST_CTRL_CORE_RST(n)	BIT(n)
+
+#define PRCM_CPU_PO_RST_CTRL(c)		(0x4 + 0x4 * (c))
+#define PRCM_CPU_PO_RST_CTRL_CORE(n)	BIT(n)
+#define PRCM_CPU_PO_RST_CTRL_CORE_ALL	0xf
+#define PRCM_PWROFF_GATING_REG(c)	(0x100 + 0x4 * (c))
+#define PRCM_PWROFF_GATING_REG_CLUSTER	BIT(4)
+#define PRCM_PWROFF_GATING_REG_CORE(n)	BIT(n)
+#define PRCM_PWR_SWITCH_REG(c, cpu)	(0x140 + 0x10 * (c) + 0x4 * (cpu))
+#define PRCM_CPU_SOFT_ENTRY_REG		0x164
+
+#define CPU0_SUPPORT_HOTPLUG_MAGIC0	0xFA50392F
+#define CPU0_SUPPORT_HOTPLUG_MAGIC1	0x790DCA3A
+
+static void __iomem *cpucfg_base;
+static void __iomem *prcm_base;
+static void __iomem *sram_b_smp_base;
+
+static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster)
+{
+	struct device_node *node;
+	int cpu = cluster * SUNXI_CPUS_PER_CLUSTER + core;
+
+	node = of_cpu_device_node_get(cpu);
+
+	/* In case of_cpu_device_node_get fails */
+	if (!node)
+		node = of_get_cpu_node(cpu, NULL);
+
+	if (!node) {
+		/*
+		 * There's no point in returning an error, since we
+		 * would be mid way in a core or cluster power sequence.
+		 */
+		pr_err("%s: Couldn't get CPU cluster %u core %u device node\n",
+		       __func__, cluster, core);
+
+		return false;
+	}
+
+	return of_device_is_compatible(node, "arm,cortex-a15");
+}
+
+static int sunxi_cpu_power_switch_set(unsigned int cpu, unsigned int cluster,
+				      bool enable)
+{
+	u32 reg;
+
+	/* control sequence from Allwinner A80 user manual v1.2 PRCM section */
+	reg = readl(prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+	if (enable) {
+		if (reg == 0x00) {
+			pr_debug("power clamp for cluster %u cpu %u already open\n",
+				 cluster, cpu);
+			return 0;
+		}
+
+		writel(0xff, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0xfe, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0xf8, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0xf0, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0x00, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+	} else {
+		writel(0xff, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+	}
+
+	return 0;
+}
+
+static void sunxi_cpu0_hotplug_support_set(bool enable)
+{
+	if (enable) {
+		writel(CPU0_SUPPORT_HOTPLUG_MAGIC0, sram_b_smp_base);
+		writel(CPU0_SUPPORT_HOTPLUG_MAGIC1, sram_b_smp_base + 0x4);
+	} else {
+		writel(0x0, sram_b_smp_base);
+		writel(0x0, sram_b_smp_base + 0x4);
+	}
+}
+
+static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cluster %u cpu %u\n", __func__, cluster, cpu);
+	if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* Set hotplug support magic flags for cpu0 */
+	if (cluster == 0 && cpu == 0)
+		sunxi_cpu0_hotplug_support_set(true);
+
+	/* assert processor power-on reset */
+	reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+	reg &= ~PRCM_CPU_PO_RST_CTRL_CORE(cpu);
+	writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+
+	/* Cortex-A7: hold L1 reset disable signal low */
+	if (!sunxi_core_is_cortex_a15(cpu, cluster)) {
+		reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+		reg &= ~CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE(cpu);
+		writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+	}
+
+	/* assert processor related resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_RST(cpu);
+
+	/*
+	 * Allwinner code also asserts resets for NEON on A15. According
+	 * to ARM manuals, asserting power-on reset is sufficient.
+	 */
+	if (!sunxi_core_is_cortex_a15(cpu, cluster))
+		reg &= ~CPUCFG_CX_RST_CTRL_ETM_RST(cpu);
+
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* open power switch */
+	sunxi_cpu_power_switch_set(cpu, cluster, true);
+
+	/* clear processor power gate */
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg &= ~PRCM_PWROFF_GATING_REG_CORE(cpu);
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	/* de-assert processor power-on reset */
+	reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+	reg |= PRCM_CPU_PO_RST_CTRL_CORE(cpu);
+	writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+
+	/* de-assert all processor resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg |= CPUCFG_CX_RST_CTRL_DBG_RST(cpu);
+	reg |= CPUCFG_CX_RST_CTRL_CORE_RST(cpu);
+	if (!sunxi_core_is_cortex_a15(cpu, cluster))
+		reg |= CPUCFG_CX_RST_CTRL_ETM_RST(cpu);
+	else
+		reg |= CPUCFG_CX_RST_CTRL_CX_RST(cpu); /* NEON */
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	return 0;
+}
+
+static int sunxi_cluster_powerup(unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+	if (cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* assert ACINACTM */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+	reg |= CPUCFG_CX_CTRL_REG1_ACINACTM;
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+
+	/* assert cluster processor power-on resets */
+	reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+	reg &= ~PRCM_CPU_PO_RST_CTRL_CORE_ALL;
+	writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+
+	/* assert cluster resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_RST_ALL;
+	reg &= ~CPUCFG_CX_RST_CTRL_H_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_L2_RST;
+
+	/*
+	 * Allwinner code also asserts resets for NEON on A15. According
+	 * to ARM manuals, asserting power-on reset is sufficient.
+	 */
+	if (!sunxi_core_is_cortex_a15(0, cluster))
+		reg &= ~CPUCFG_CX_RST_CTRL_ETM_RST_ALL;
+
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* hold L1/L2 reset disable signals low */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+	if (sunxi_core_is_cortex_a15(0, cluster)) {
+		/* Cortex-A15: hold L2RSTDISABLE low */
+		reg &= ~CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A15;
+	} else {
+		/* Cortex-A7: hold L1RSTDISABLE and L2RSTDISABLE low */
+		reg &= ~CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE_ALL;
+		reg &= ~CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A7;
+	}
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+
+	/* clear cluster power gate */
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg &= ~PRCM_PWROFF_GATING_REG_CLUSTER;
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	/* de-assert cluster resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg |= CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
+	reg |= CPUCFG_CX_RST_CTRL_H_RST;
+	reg |= CPUCFG_CX_RST_CTRL_L2_RST;
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* de-assert ACINACTM */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+	reg &= ~CPUCFG_CX_CTRL_REG1_ACINACTM;
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+
+	return 0;
+}
+
+/*
+ * This bit is shared between the initial nocache_trampoline call to
+ * enable CCI-400 and proper cluster cache disable before power down.
+ */
+static void sunxi_cluster_cache_disable_without_axi(void)
+{
+	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
+		/*
+		 * On the Cortex-A15 we need to disable
+		 * L2 prefetching before flushing the cache.
+		 */
+		asm volatile(
+		"mcr	p15, 1, %0, c15, c0, 3\n"
+		"isb\n"
+		"dsb"
+		: : "r" (0x400));
+	}
+
+	/* Flush all cache levels for this cluster. */
+	v7_exit_coherency_flush(all);
+
+	/*
+	 * Disable cluster-level coherency by masking
+	 * incoming snoops and DVM messages:
+	 */
+	cci_disable_port_by_cpu(read_cpuid_mpidr());
+}
+
+static int sunxi_mc_smp_cpu_table[SUNXI_NR_CLUSTERS][SUNXI_CPUS_PER_CLUSTER];
+static int sunxi_mc_smp_first_comer;
+
+/*
+ * Enable cluster-level coherency, in preparation for turning on the MMU.
+ *
+ * Also enable regional clock gating and L2 data latency settings for
+ * Cortex-A15. These settings are from the vendor kernel.
+ */
+static void __naked sunxi_mc_smp_cluster_cache_enable(void)
+{
+	asm volatile (
+		"mrc	p15, 0, r1, c0, c0, 0\n"
+		"movw	r2, #" __stringify(ARM_CPU_PART_MASK & 0xffff) "\n"
+		"movt	r2, #" __stringify(ARM_CPU_PART_MASK >> 16) "\n"
+		"and	r1, r1, r2\n"
+		"movw	r2, #" __stringify(ARM_CPU_PART_CORTEX_A15 & 0xffff) "\n"
+		"movt	r2, #" __stringify(ARM_CPU_PART_CORTEX_A15 >> 16) "\n"
+		"cmp	r1, r2\n"
+		"bne	not_a15\n"
+
+		/* The following is Cortex-A15 specific */
+
+		/* ACTLR2: Enable CPU regional clock gates */
+		"mrc p15, 1, r1, c15, c0, 4\n"
+		"orr r1, r1, #(0x1<<31)\n"
+		"mcr p15, 1, r1, c15, c0, 4\n"
+
+		/* L2ACTLR */
+		"mrc p15, 1, r1, c15, c0, 0\n"
+		/* Enable L2, GIC, and Timer regional clock gates */
+		"orr r1, r1, #(0x1<<26)\n"
+		/* Disable clean/evict from being pushed to external */
+		"orr r1, r1, #(0x1<<3)\n"
+		"mcr p15, 1, r1, c15, c0, 0\n"
+
+		/* L2CTRL: L2 data RAM latency */
+		"mrc p15, 1, r1, c9, c0, 2\n"
+		"bic r1, r1, #(0x7<<0)\n"
+		"orr r1, r1, #(0x3<<0)\n"
+		"mcr p15, 1, r1, c9, c0, 2\n"
+
+		/* End of Cortex-A15 specific setup */
+		"not_a15:\n"
+
+		/* Get value of sunxi_mc_smp_first_comer */
+		"adr	r1, first\n"
+		"ldr	r0, [r1]\n"
+		"ldr	r0, [r1, r0]\n"
+
+		/* Skip cci_enable_port_for_self if not first comer */
+		"cmp	r0, #0\n"
+		"bxeq	lr\n"
+		"b	cci_enable_port_for_self\n"
+
+		".align 2\n"
+		"first: .word sunxi_mc_smp_first_comer - .\n"
+	);
+}
+
+static void __naked sunxi_mc_smp_secondary_startup(void)
+{
+	asm volatile(
+		"bl	sunxi_mc_smp_cluster_cache_enable\n"
+		"b	secondary_startup"
+		/* Let compiler know about sunxi_mc_smp_cluster_cache_enable */
+		:: "i" (sunxi_mc_smp_cluster_cache_enable)
+	);
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static bool sunxi_mc_smp_cluster_is_down(unsigned int cluster)
+{
+	int i;
+
+	for (i = 0; i < SUNXI_CPUS_PER_CLUSTER; i++)
+		if (sunxi_mc_smp_cpu_table[cluster][i])
+			return false;
+	return true;
+}
+
+static void sunxi_mc_smp_secondary_init(unsigned int cpu)
+{
+	/* Clear hotplug support magic flags for cpu0 */
+	if (cpu == 0)
+		sunxi_cpu0_hotplug_support_set(false);
+}
+
+static int sunxi_mc_smp_boot_secondary(unsigned int l_cpu, struct task_struct *idle)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = cpu_logical_map(l_cpu);
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	if (!cpucfg_base)
+		return -ENODEV;
+	if (cluster >= SUNXI_NR_CLUSTERS || cpu >= SUNXI_CPUS_PER_CLUSTER)
+		return -EINVAL;
+
+	spin_lock_irq(&boot_lock);
+
+	if (sunxi_mc_smp_cpu_table[cluster][cpu])
+		goto out;
+
+	if (sunxi_mc_smp_cluster_is_down(cluster)) {
+		sunxi_mc_smp_first_comer = true;
+		sunxi_cluster_powerup(cluster);
+	} else {
+		sunxi_mc_smp_first_comer = false;
+	}
+
+	/* This is read by incoming CPUs with their cache and MMU disabled */
+	sync_cache_w(&sunxi_mc_smp_first_comer);
+	sunxi_cpu_powerup(cpu, cluster);
+
+out:
+	sunxi_mc_smp_cpu_table[cluster][cpu]++;
+	spin_unlock_irq(&boot_lock);
+
+	return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void sunxi_cluster_cache_disable(void)
+{
+	unsigned int cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+
+	sunxi_cluster_cache_disable_without_axi();
+
+	/* last man standing, assert ACINACTM */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+	reg |= CPUCFG_CX_CTRL_REG1_ACINACTM;
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+}
+
+static void sunxi_mc_smp_cpu_die(unsigned int l_cpu)
+{
+	unsigned int mpidr, cpu, cluster;
+	bool last_man;
+
+	mpidr = cpu_logical_map(l_cpu);
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	pr_debug("%s: cluster %u cpu %u\n", __func__, cluster, cpu);
+
+	spin_lock(&boot_lock);
+	sunxi_mc_smp_cpu_table[cluster][cpu]--;
+	if (sunxi_mc_smp_cpu_table[cluster][cpu] == 1) {
+		/* A power_up request went ahead of us. */
+		pr_debug("%s: aborting due to a power up request\n",
+			 __func__);
+		spin_unlock(&boot_lock);
+		return;
+	} else if (sunxi_mc_smp_cpu_table[cluster][cpu] > 1) {
+		pr_err("Cluster %d CPU%d boots multiple times\n",
+		       cluster, cpu);
+		BUG();
+	}
+
+	last_man = sunxi_mc_smp_cluster_is_down(cluster);
+	spin_unlock(&boot_lock);
+
+	gic_cpu_if_down(0);
+	if (last_man)
+		sunxi_cluster_cache_disable();
+	else
+		v7_exit_coherency_flush(louis);
+
+	for (;;)
+		wfi();
+}
+
+static int sunxi_cpu_powerdown(unsigned int cpu, unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cluster %u cpu %u\n", __func__, cluster, cpu);
+	if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* gate processor power */
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg |= PRCM_PWROFF_GATING_REG_CORE(cpu);
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	/* close power switch */
+	sunxi_cpu_power_switch_set(cpu, cluster, false);
+
+	return 0;
+}
+
+static int sunxi_cluster_powerdown(unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+	if (cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* assert cluster resets or system will hang */
+	pr_debug("%s: assert cluster reset\n", __func__);
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_H_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_L2_RST;
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* gate cluster power */
+	pr_debug("%s: gate cluster power\n", __func__);
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg |= PRCM_PWROFF_GATING_REG_CLUSTER;
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	return 0;
+}
+
+static int sunxi_mc_smp_cpu_kill(unsigned int l_cpu)
+{
+	unsigned int mpidr, cpu, cluster;
+	unsigned int tries, count;
+	int ret = 0;
+	u32 reg;
+
+	mpidr = cpu_logical_map(l_cpu);
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	/* This should never happen */
+	if (WARN_ON(cluster >= SUNXI_NR_CLUSTERS ||
+		    cpu >= SUNXI_CPUS_PER_CLUSTER))
+		return 0;
+
+	/* wait for CPU core to die and enter WFI */
+	count = TIMEOUT_USEC / POLL_USEC;
+	spin_lock_irq(&boot_lock);
+	for (tries = 0; tries < count; tries++) {
+		spin_unlock_irq(&boot_lock);
+		usleep_range(POLL_USEC / 2, POLL_USEC);
+		spin_lock_irq(&boot_lock);
+
+		/*
+		 * If the user turns off a bunch of cores at the same
+		 * time, the kernel might call cpu_kill before some of
+		 * them are ready. This is because boot_lock serializes
+		 * both cpu_die and cpu_kill callbacks. Either one could
+		 * run first. We should wait for cpu_die to complete.
+		 */
+		if (sunxi_mc_smp_cpu_table[cluster][cpu])
+			continue;
+
+		reg = readl(cpucfg_base + CPUCFG_CX_STATUS(cluster));
+		if (reg & CPUCFG_CX_STATUS_STANDBYWFI(cpu))
+			break;
+	}
+
+	if (tries >= count) {
+		ret = ETIMEDOUT;
+		goto out;
+	}
+
+	/* power down CPU core */
+	sunxi_cpu_powerdown(cpu, cluster);
+
+	if (!sunxi_mc_smp_cluster_is_down(cluster))
+		goto out;
+
+	/* wait for cluster L2 WFI */
+	ret = readl_poll_timeout(cpucfg_base + CPUCFG_CX_STATUS(cluster), reg,
+				 reg & CPUCFG_CX_STATUS_STANDBYWFIL2,
+				 POLL_USEC, TIMEOUT_USEC);
+	if (ret) {
+		/*
+		 * Ignore timeout on the cluster. Leaving the cluster on
+		 * will not affect system execution, just use a bit more
+		 * power. But returning an error here will only confuse
+		 * the user as the CPU has already been shutdown.
+		 */
+		ret = 0;
+		goto out;
+	}
+
+	/* Power down cluster */
+	sunxi_cluster_powerdown(cluster);
+
+out:
+	spin_unlock_irq(&boot_lock);
+	pr_debug("%s: cluster %u cpu %u powerdown: %d\n",
+		 __func__, cluster, cpu, ret);
+	return !ret;
+}
+
+static bool sunxi_mc_smp_cpu_can_disable(unsigned int __unused)
+{
+	return true;
+}
+#endif
+
+static const struct smp_operations sunxi_mc_smp_smp_ops __initconst = {
+	.smp_secondary_init	= sunxi_mc_smp_secondary_init,
+	.smp_boot_secondary	= sunxi_mc_smp_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_die		= sunxi_mc_smp_cpu_die,
+	.cpu_kill		= sunxi_mc_smp_cpu_kill,
+	.cpu_can_disable	= sunxi_mc_smp_cpu_can_disable,
+#endif
+};
+
+static bool __init sunxi_mc_smp_cpu_table_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	if (cluster >= SUNXI_NR_CLUSTERS || cpu >= SUNXI_CPUS_PER_CLUSTER) {
+		pr_err("%s: boot CPU is out of bounds!\n", __func__);
+		return false;
+	}
+	sunxi_mc_smp_cpu_table[cluster][cpu] = 1;
+	return true;
+}
+
+/*
+ * Adapted from arch/arm/common/mc_smp_entry.c
+ *
+ * We need the trampoline code to enable CCI-400 on the first cluster
+ */
+typedef typeof(cpu_reset) phys_reset_t;
+
+static void __init __naked sunxi_mc_smp_resume(void)
+{
+	asm volatile(
+		"bl	sunxi_mc_smp_cluster_cache_enable\n"
+		"b	cpu_resume"
+		/* Let compiler know about sunxi_mc_smp_cluster_cache_enable */
+		:: "i" (sunxi_mc_smp_cluster_cache_enable)
+	);
+}
+
+static int __init nocache_trampoline(unsigned long __unused)
+{
+	phys_reset_t phys_reset;
+
+	setup_mm_for_reboot();
+	sunxi_cluster_cache_disable_without_axi();
+
+	phys_reset = (phys_reset_t)(unsigned long)__pa_symbol(cpu_reset);
+	phys_reset(__pa_symbol(sunxi_mc_smp_resume), false);
+	BUG();
+}
+
+static int __init sunxi_mc_smp_lookback(void)
+{
+	int ret;
+
+	/*
+	 * We're going to soft-restart the current CPU through the
+	 * low-level MCPM code by leveraging the suspend/resume
+	 * infrastructure. Let's play it safe by using cpu_pm_enter()
+	 * in case the CPU init code path resets the VFP or similar.
+	 */
+	sunxi_mc_smp_first_comer = true;
+	local_irq_disable();
+	local_fiq_disable();
+	ret = cpu_pm_enter();
+	if (!ret) {
+		ret = cpu_suspend(0, nocache_trampoline);
+		cpu_pm_exit();
+	}
+	local_fiq_enable();
+	local_irq_enable();
+	sunxi_mc_smp_first_comer = false;
+
+	return ret;
+}
+
+static int __init sunxi_mc_smp_init(void)
+{
+	struct device_node *cpucfg_node, *sram_node, *node;
+	struct resource res;
+	int ret;
+
+	if (!of_machine_is_compatible("allwinner,sun9i-a80"))
+		return -ENODEV;
+
+	if (!sunxi_mc_smp_cpu_table_init())
+		return -EINVAL;
+
+	if (!cci_probed()) {
+		pr_err("%s: CCI-400 not available\n", __func__);
+		return -ENODEV;
+	}
+
+	node = of_find_compatible_node(NULL, NULL, "allwinner,sun9i-a80-prcm");
+	if (!node) {
+		pr_err("%s: PRCM not available\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * Unfortunately we can not request the I/O region for the PRCM.
+	 * It is shared with the PRCM clock.
+	 */
+	prcm_base = of_iomap(node, 0);
+	of_node_put(node);
+	if (!prcm_base) {
+		pr_err("%s: failed to map PRCM registers\n", __func__);
+		return -ENOMEM;
+	}
+
+	cpucfg_node = of_find_compatible_node(NULL, NULL,
+					      "allwinner,sun9i-a80-cpucfg");
+	if (!cpucfg_node) {
+		ret = -ENODEV;
+		pr_err("%s: CPUCFG not available\n", __func__);
+		goto err_unmap_prcm;
+	}
+
+	cpucfg_base = of_io_request_and_map(cpucfg_node, 0, "sunxi-mc-smp");
+	if (IS_ERR(cpucfg_base)) {
+		ret = PTR_ERR(cpucfg_base);
+		pr_err("%s: failed to map CPUCFG registers: %d\n",
+		       __func__, ret);
+		goto err_put_cpucfg_node;
+	}
+
+	sram_node = of_find_compatible_node(NULL, NULL,
+					    "allwinner,sun9i-a80-smp-sram");
+	if (!sram_node) {
+		ret = -ENODEV;
+		goto err_unmap_release_cpucfg;
+	}
+
+	sram_b_smp_base = of_io_request_and_map(sram_node, 0, "sunxi-mc-smp");
+	if (IS_ERR(sram_b_smp_base)) {
+		ret = PTR_ERR(sram_b_smp_base);
+		pr_err("%s: failed to map secure SRAM\n", __func__);
+		goto err_put_sram_node;
+	}
+
+	/* Configure CCI-400 for boot cluster */
+	ret = sunxi_mc_smp_lookback();
+	if (ret) {
+		pr_err("%s: failed to configure boot cluster: %d\n",
+		       __func__, ret);
+		goto err_unmap_release_secure_sram;
+	}
+
+	/* We don't need the CPUCFG and SRAM device nodes anymore */
+	of_node_put(cpucfg_node);
+	of_node_put(sram_node);
+
+	/* Set the hardware entry point address */
+	writel(__pa_symbol(sunxi_mc_smp_secondary_startup),
+	       prcm_base + PRCM_CPU_SOFT_ENTRY_REG);
+
+	/* Actually enable multi cluster SMP */
+	smp_set_ops(&sunxi_mc_smp_smp_ops);
+
+	pr_info("sunxi multi cluster SMP support installed\n");
+
+	return 0;
+
+err_unmap_release_secure_sram:
+	iounmap(sram_b_smp_base);
+	of_address_to_resource(sram_node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+err_put_sram_node:
+	of_node_put(sram_node);
+err_unmap_release_cpucfg:
+	iounmap(cpucfg_base);
+	of_address_to_resource(cpucfg_node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+err_put_cpucfg_node:
+	of_node_put(cpucfg_node);
+err_unmap_prcm:
+	iounmap(prcm_base);
+	return ret;
+}
+
+early_initcall(sunxi_mc_smp_init);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index ada8eb206a90..8c398fedbbb6 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -466,6 +466,12 @@ void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size)
 void __init dma_contiguous_remap(void)
 {
 	int i;
+
+	if (!dma_mmu_remap_num)
+		return;
+
+	/* call flush_cache_all() since CMA area would be large enough */
+	flush_cache_all();
 	for (i = 0; i < dma_mmu_remap_num; i++) {
 		phys_addr_t start = dma_mmu_remap[i].base;
 		phys_addr_t end = start + dma_mmu_remap[i].size;
@@ -498,7 +504,15 @@ void __init dma_contiguous_remap(void)
 		flush_tlb_kernel_range(__phys_to_virt(start),
 				       __phys_to_virt(end));
 
-		iotable_init(&map, 1);
+		/*
+		 * All the memory in CMA region will be on ZONE_MOVABLE.
+		 * If that zone is considered as highmem, the memory in CMA
+		 * region is also considered as highmem even if it's
+		 * physical address belong to lowmem. In this case,
+		 * re-mapping isn't required.
+		 */
+		if (!is_highmem_idx(ZONE_MOVABLE))
+			iotable_init(&map, 1);
 	}
 }
 
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index dd79f3005cdf..8b7d8a6e02cc 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -75,10 +75,6 @@
  */
 #define OMAP_TIMER_ERRATA_I103_I767			0x80000000
 
-struct omap_timer_capability_dev_attr {
-	u32 timer_capability;
-};
-
 struct timer_regs {
 	u32 tidr;
 	u32 tier;
diff --git a/arch/arm/plat-omap/include/plat/i2c.h b/arch/arm/plat-omap/include/plat/i2c.h
deleted file mode 100644
index 810629d79668..000000000000
--- a/arch/arm/plat-omap/include/plat/i2c.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Helper module for board specific I2C bus registration
- *
- * Copyright (C) 2009 Nokia 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __PLAT_OMAP_I2C_H
-#define __PLAT_OMAP_I2C_H
-
-struct i2c_board_info;
-struct omap_i2c_bus_platform_data;
-
-int omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
-			int bus_id);
-
-#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
-extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
-				 struct i2c_board_info const *info,
-				 unsigned len);
-extern int omap_register_i2c_bus_cmdline(void);
-#else
-static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
-				 struct i2c_board_info const *info,
-				 unsigned len)
-{
-	return 0;
-}
-
-static inline int omap_register_i2c_bus_cmdline(void)
-{
-	return 0;
-}
-#endif
-
-struct omap_hwmod;
-int omap_i2c_reset(struct omap_hwmod *oh);
-
-#endif /* __PLAT_OMAP_I2C_H */
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index fbedbd8f619a..b51db26f6eaa 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -196,6 +196,12 @@ config ARCH_R8A77970
 	help
 	  This enables support for the Renesas R-Car V3M SoC.
 
+config ARCH_R8A77980
+	bool "Renesas R-Car V3H SoC Platform"
+	depends on ARCH_RENESAS
+	help
+	  This enables support for the Renesas R-Car V3H SoC.
+
 config ARCH_R8A77995
 	bool "Renesas R-Car D3 SoC Platform"
 	depends on ARCH_RENESAS
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
index a6975670cd1c..2250dec9974c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
@@ -120,8 +120,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	disable-wp;
 	bus-width = <4>;
 	status = "okay";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
index 2beef9e6cb88..e2dce48fa29a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
@@ -82,8 +82,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	disable-wp;
 	bus-width = <4>;
 	status = "okay";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
index 8807664f363a..3b3081b10ecb 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
@@ -68,8 +68,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	disable-wp;
 	bus-width = <4>;
 	status = "okay";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
index 240d35731d10..bf42690a3361 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
@@ -67,8 +67,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
index 604cdaedac38..a75825798a71 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
@@ -103,8 +103,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
 	vmmc-supply = <&reg_dcdc1>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
-	cd-inverted;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	disable-wp;
 	bus-width = <4>;
 	status = "okay";
@@ -230,6 +229,11 @@
 	regulator-name = "vcc-rtc";
 };
 
+/* On Euler connector */
+&spdif {
+	status = "disabled";
+};
+
 /* On Exp and Euler connectors */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index d783d164b9c3..1b6dc31e7d91 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -112,6 +112,24 @@
 		method = "smc";
 	};
 
+	sound_spdif {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "On-board SPDIF";
+
+		simple-audio-card,cpu {
+			sound-dai = <&spdif>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&spdif_out>;
+		};
+	};
+
+	spdif_out: spdif-out {
+		#sound-dai-cells = <0>;
+		compatible = "linux,spdif-dit";
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 13
@@ -336,6 +354,11 @@
 				drive-strength = <40>;
 			};
 
+			spdif_tx_pin: spdif {
+				pins = "PH8";
+				function = "spdif";
+			};
+
 			spi0_pins: spi0 {
 				pins = "PC0", "PC1", "PC2", "PC3";
 				function = "spi0";
@@ -382,6 +405,50 @@
 			};
 		};
 
+		spdif: spdif@1c21000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun50i-a64-spdif",
+				     "allwinner,sun8i-h3-spdif";
+			reg = <0x01c21000 0x400>;
+			interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>;
+			resets = <&ccu RST_BUS_SPDIF>;
+			clock-names = "apb", "spdif";
+			dmas = <&dma 2>;
+			dma-names = "tx";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spdif_tx_pin>;
+			status = "disabled";
+		};
+
+		i2s0: i2s@1c22000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun50i-a64-i2s",
+				     "allwinner,sun8i-h3-i2s";
+			reg = <0x01c22000 0x400>;
+			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>;
+			clock-names = "apb", "mod";
+			resets = <&ccu RST_BUS_I2S0>;
+			dma-names = "rx", "tx";
+			dmas = <&dma 3>, <&dma 3>;
+			status = "disabled";
+		};
+
+		i2s1: i2s@1c22400 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun50i-a64-i2s",
+				     "allwinner,sun8i-h3-i2s";
+			reg = <0x01c22400 0x400>;
+			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+			clock-names = "apb", "mod";
+			resets = <&ccu RST_BUS_I2S1>;
+			dma-names = "rx", "tx";
+			dmas = <&dma 4>, <&dma 4>;
+			status = "disabled";
+		};
+
 		uart0: serial@1c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
index 1ed9f219deaf..506e25ba028a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
@@ -151,8 +151,6 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
@@ -160,8 +158,6 @@
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	vqmmc-supply = <&reg_vcc3v3>;
 	mmc-pwrseq = <&wifi_pwrseq>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
index f1447003ea3c..cc268a69786c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
@@ -126,8 +126,6 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
index 9e51d3a5f4e6..58505fbc2667 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
@@ -160,8 +160,6 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
index 0f25c4a6f15d..803566608ed8 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
@@ -167,8 +167,6 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
@@ -176,8 +174,6 @@
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	mmc-pwrseq = <&wifi_pwrseq>;
 	bus-width = <4>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
index af43533c7134..eda24d813282 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
@@ -74,8 +74,6 @@
 };
 
 &mmc0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc0_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
@@ -83,8 +81,6 @@
 };
 
 &mmc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
 	vqmmc-supply = <&reg_vcc3v3>;
 	mmc-pwrseq = <&wifi_pwrseq>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts b/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
index 447b98d30921..913e63e718ff 100644
--- a/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
@@ -14,6 +14,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		serial1 = &uart_A;
 	};
 };
 
@@ -24,8 +25,16 @@
 	pinctrl-names = "default";
 };
 
+&uart_A {
+	status = "okay";
+	pinctrl-0 = <&uart_a_pins>;
+	pinctrl-names = "default";
+};
+
 &uart_AO {
 	status = "okay";
+	pinctrl-0 = <&uart_ao_a_pins>;
+	pinctrl-names = "default";
 };
 
 &ir {
@@ -33,3 +42,9 @@
 	pinctrl-0 = <&remote_input_ao_pins>;
 	pinctrl-names = "default";
 };
+
+&i2c1 {
+	status = "okay";
+	pinctrl-0 = <&i2c1_z_pins>;
+	pinctrl-names = "default";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
index a80632641b39..bce914b0d5bb 100644
--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
@@ -163,18 +163,70 @@
 				status = "disabled";
 			};
 
+			i2c0: i2c@1f000 {
+				compatible = "amlogic,meson-axg-i2c";
+				status = "disabled";
+				reg = <0x0 0x1f000 0x0 0x20>;
+				interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 47 IRQ_TYPE_EDGE_RISING>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&clkc CLKID_I2C>;
+				clock-names = "clk_i2c";
+			};
+
+			i2c1: i2c@1e000 {
+				compatible = "amlogic,meson-axg-i2c";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x0 0x1e000 0x0 0x20>;
+				status = "disabled";
+				interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 48 IRQ_TYPE_EDGE_RISING>;
+				clocks = <&clkc CLKID_I2C>;
+				clock-names = "clk_i2c";
+			};
+
+			i2c2: i2c@1d000 {
+				compatible = "amlogic,meson-axg-i2c";
+				status = "disabled";
+				reg = <0x0 0x1d000 0x0 0x20>;
+				interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 49 IRQ_TYPE_EDGE_RISING>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&clkc CLKID_I2C>;
+				clock-names = "clk_i2c";
+			};
+
+			i2c3: i2c@1c000 {
+				compatible = "amlogic,meson-axg-i2c";
+				status = "disabled";
+				reg = <0x0 0x1c000 0x0 0x20>;
+				interrupts = <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&clkc CLKID_I2C>;
+				clock-names = "clk_i2c";
+			};
+
 			uart_A: serial@24000 {
-				compatible = "amlogic,meson-gx-uart", "amlogic,meson-uart";
-				reg = <0x0 0x24000 0x0 0x14>;
+				compatible = "amlogic,meson-gx-uart";
+				reg = <0x0 0x24000 0x0 0x18>;
 				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
+				clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>;
+				clock-names = "xtal", "pclk", "baud";
 			};
 
 			uart_B: serial@23000 {
-				compatible = "amlogic,meson-gx-uart", "amlogic,meson-uart";
-				reg = <0x0 0x23000 0x0 0x14>;
+				compatible = "amlogic,meson-gx-uart";
+				reg = <0x0 0x23000 0x0 0x18>;
 				interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
+				clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>;
+				clock-names = "xtal", "pclk", "baud";
 			};
 		};
 
@@ -234,6 +286,13 @@
 			#size-cells = <2>;
 			ranges = <0x0 0x0 0x0 0xff634000 0x0 0x2000>;
 
+			hwrng: rng {
+				compatible = "amlogic,meson-rng";
+				reg = <0x0 0x18 0x0 0x4>;
+				clocks = <&clkc CLKID_RNG0>;
+				clock-names = "core";
+			};
+
 			pinctrl_periphs: pinctrl@480 {
 				compatible = "amlogic,meson-axg-periphs-pinctrl";
 				#address-cells = <2>;
@@ -251,6 +310,36 @@
 					gpio-ranges = <&pinctrl_periphs 0 0 86>;
 				};
 
+				eth_rmii_x_pins: eth-x-rmii {
+					mux {
+						groups = "eth_mdio_x",
+						       "eth_mdc_x",
+						       "eth_rgmii_rx_clk_x",
+						       "eth_rx_dv_x",
+						       "eth_rxd0_x",
+						       "eth_rxd1_x",
+						       "eth_txen_x",
+						       "eth_txd0_x",
+						       "eth_txd1_x";
+						function = "eth";
+					};
+				};
+
+				eth_rmii_y_pins: eth-y-rmii {
+					mux {
+						groups = "eth_mdio_y",
+						       "eth_mdc_y",
+						       "eth_rgmii_rx_clk_y",
+						       "eth_rx_dv_y",
+						       "eth_rxd0_y",
+						       "eth_rxd1_y",
+						       "eth_txen_y",
+						       "eth_txd0_y",
+						       "eth_txd1_y";
+						function = "eth";
+					};
+				};
+
 				eth_rgmii_x_pins: eth-x-rgmii {
 					mux {
 						groups = "eth_mdio_x",
@@ -444,6 +533,134 @@
 						function = "spi1";
 					};
 				};
+
+				i2c0_pins: i2c0 {
+					mux {
+						groups = "i2c0_sck",
+							"i2c0_sda";
+						function = "i2c0";
+					};
+				};
+
+				i2c1_z_pins: i2c1_z {
+					mux {
+						groups = "i2c1_sck_z",
+							"i2c1_sda_z";
+						function = "i2c1";
+					};
+				};
+
+				i2c1_x_pins: i2c1_x {
+					mux {
+						groups = "i2c1_sck_x",
+							"i2c1_sda_x";
+						function = "i2c1";
+					};
+				};
+
+				i2c2_x_pins: i2c2_x {
+					mux {
+						groups = "i2c2_sck_x",
+							"i2c2_sda_x";
+						function = "i2c2";
+					};
+				};
+
+				i2c2_a_pins: i2c2_a {
+					mux {
+						groups = "i2c2_sck_a",
+							"i2c2_sda_a";
+						function = "i2c2";
+					};
+				};
+
+				i2c3_a6_pins: i2c3_a6 {
+					mux {
+						groups = "i2c3_sda_a6",
+							"i2c3_sck_a7";
+						function = "i2c3";
+					};
+				};
+
+				i2c3_a12_pins: i2c3_a12 {
+					mux {
+						groups = "i2c3_sda_a12",
+							"i2c3_sck_a13";
+						function = "i2c3";
+					};
+				};
+
+				i2c3_a19_pins: i2c3_a19 {
+					mux {
+						groups = "i2c3_sda_a19",
+							"i2c3_sck_a20";
+						function = "i2c3";
+					};
+				};
+
+				uart_a_pins: uart_a {
+					mux {
+						groups = "uart_tx_a",
+							"uart_rx_a";
+						function = "uart_a";
+					};
+				};
+
+				uart_a_cts_rts_pins: uart_a_cts_rts {
+					mux {
+						groups = "uart_cts_a",
+							"uart_rts_a";
+						function = "uart_a";
+					};
+				};
+
+				uart_b_x_pins: uart_b_x {
+					mux {
+						groups = "uart_tx_b_x",
+							"uart_rx_b_x";
+						function = "uart_b";
+					};
+				};
+
+				uart_b_x_cts_rts_pins: uart_b_x_cts_rts {
+					mux {
+						groups = "uart_cts_b_x",
+							"uart_rts_b_x";
+						function = "uart_b";
+					};
+				};
+
+				uart_b_z_pins: uart_b_z {
+					mux {
+						groups = "uart_tx_b_z",
+							"uart_rx_b_z";
+						function = "uart_b";
+					};
+				};
+
+				uart_b_z_cts_rts_pins: uart_b_z_cts_rts {
+					mux {
+						groups = "uart_cts_b_z",
+							"uart_rts_b_z";
+						function = "uart_b";
+					};
+				};
+
+				uart_ao_b_z_pins: uart_ao_b_z {
+					mux {
+						groups = "uart_ao_tx_b_z",
+							"uart_ao_rx_b_z";
+						function = "uart_ao_b_z";
+					};
+				};
+
+				uart_ao_b_z_cts_rts_pins: uart_ao_b_z_cts_rts {
+					mux {
+						groups = "uart_ao_cts_b_z",
+							"uart_ao_rts_b_z";
+						function = "uart_ao_b_z";
+					};
+				};
 			};
 		};
 
@@ -494,6 +711,38 @@
 						function = "remote_input_ao";
 					};
 				};
+
+				uart_ao_a_pins: uart_ao_a {
+					mux {
+						groups = "uart_ao_tx_a",
+							"uart_ao_rx_a";
+						function = "uart_ao_a";
+					};
+				};
+
+				uart_ao_a_cts_rts_pins: uart_ao_a_cts_rts {
+					mux {
+						groups = "uart_ao_cts_a",
+							"uart_ao_rts_a";
+						function = "uart_ao_a";
+					};
+				};
+
+				uart_ao_b_pins: uart_ao_b {
+					mux {
+						groups = "uart_ao_tx_b",
+							"uart_ao_rx_b";
+						function = "uart_ao_b";
+					};
+				};
+
+				uart_ao_b_cts_rts_pins: uart_ao_b_cts_rts {
+					mux {
+						groups = "uart_ao_cts_b",
+							"uart_ao_rts_b";
+						function = "uart_ao_b";
+					};
+				};
 			};
 
 			pwm_AO_ab: pwm@7000 {
@@ -510,6 +759,17 @@
 				status = "disabled";
 			};
 
+			i2c_AO: i2c@5000 {
+				compatible = "amlogic,meson-axg-i2c";
+				status = "disabled";
+				reg = <0x0 0x05000 0x0 0x20>;
+				interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&clkc CLKID_I2C>;
+				clock-names = "clk_i2c";
+			};
+
 			uart_AO: serial@3000 {
 				compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart";
 				reg = <0x0 0x3000 0x0 0x18>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
index aeb6d21a3bec..4b28a6e31175 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
@@ -48,6 +48,7 @@
 / {
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 6cb3c2a52baf..4ee2e7951482 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -235,14 +235,14 @@
 
 			uart_A: serial@84c0 {
 				compatible = "amlogic,meson-gx-uart";
-				reg = <0x0 0x84c0 0x0 0x14>;
+				reg = <0x0 0x84c0 0x0 0x18>;
 				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
 			};
 
 			uart_B: serial@84dc {
 				compatible = "amlogic,meson-gx-uart";
-				reg = <0x0 0x84dc 0x0 0x14>;
+				reg = <0x0 0x84dc 0x0 0x18>;
 				interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
 			};
@@ -287,7 +287,7 @@
 
 			uart_C: serial@8700 {
 				compatible = "amlogic,meson-gx-uart";
-				reg = <0x0 0x8700 0x0 0x14>;
+				reg = <0x0 0x8700 0x0 0x18>;
 				interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
 			};
@@ -404,14 +404,14 @@
 
 			uart_AO: serial@4c0 {
 				compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart";
-				reg = <0x0 0x004c0 0x0 0x14>;
+				reg = <0x0 0x004c0 0x0 0x18>;
 				interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
 			};
 
 			uart_AO_B: serial@4e0 {
 				compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart";
-				reg = <0x0 0x004e0 0x0 0x14>;
+				reg = <0x0 0x004e0 0x0 0x18>;
 				interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>;
 				status = "disabled";
 			};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
index 011e8e08e429..2ce7258a147b 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
@@ -52,6 +52,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
index 818954b1d57f..855dd9ae0716 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
@@ -54,6 +54,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index ee4ada61c59c..73a030a5ecf3 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -53,6 +53,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 932158a778ef..c6f7b51e2ec8 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -47,6 +47,7 @@
 / {
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
index 1fe8e24cf675..383f9de734c1 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
@@ -47,6 +47,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts
index e82582574160..386fab4d1c8f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-hwacom-amazetv.dts
@@ -16,6 +16,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
index 71a6e1ce7ad5..94cddf59646a 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
@@ -29,6 +29,7 @@
 
 	aliases {
 		serial2 = &uart_AO_B;
+		ethernet0 = &ethmac;
 	};
 
 	gpio-keys-polled {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
index 9671f1e3c74a..a011d51fec24 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
@@ -18,6 +18,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
index 271f14279180..6b05c0e57724 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
@@ -52,6 +52,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
index 7005068346a0..9cde3d2eef97 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
@@ -17,6 +17,7 @@
 	aliases {
 		serial0 = &uart_AO;
 		serial1 = &uart_A;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index 4f355f17eed6..c8514110b9da 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -631,6 +631,7 @@
 
 			internal_phy: ethernet-phy@8 {
 				compatible = "ethernet-phy-id0181.4400", "ethernet-phy-ieee802.3-c22";
+				interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
 				reg = <8>;
 				max-speed = <100>;
 			};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
index e7a228f6cc7e..15cdd938f6a2 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
@@ -54,6 +54,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
index a5e9b955d5ed..67fadea68e07 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts
@@ -58,6 +58,7 @@
 
 	aliases {
 		serial0 = &uart_AO;
+		ethernet0 = &ethmac;
 	};
 
 	chosen {
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
index a77462da4a36..b73c389e1a8b 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
@@ -14,6 +14,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/sound/samsung-i2s.h>
 
 / {
 	aliases {
@@ -112,8 +113,8 @@
 
 	sound {
 		compatible = "samsung,tm2-audio";
-		audio-codec = <&wm5110>;
-		i2s-controller = <&i2s0>;
+		audio-codec = <&wm5110>, <&hdmi>;
+		i2s-controller = <&i2s0 0>, <&i2s1 0>;
 		audio-amplifier = <&max98504>;
 		mic-bias-gpios = <&gpr3 2 GPIO_ACTIVE_HIGH>;
 		model = "wm5110";
@@ -217,8 +218,40 @@
 };
 
 &cmu_aud {
-	assigned-clocks = <&cmu_aud CLK_MOUT_AUD_PLL_USER>;
-	assigned-clock-parents = <&cmu_top CLK_FOUT_AUD_PLL>;
+	assigned-clocks = <&cmu_aud CLK_MOUT_AUD_PLL_USER>,
+		<&cmu_aud CLK_MOUT_SCLK_AUD_I2S>,
+		<&cmu_aud CLK_MOUT_SCLK_AUD_PCM>,
+		<&cmu_top CLK_MOUT_AUD_PLL>,
+		<&cmu_top CLK_MOUT_AUD_PLL_USER_T>,
+		<&cmu_top CLK_MOUT_SCLK_AUDIO0>,
+		<&cmu_top CLK_MOUT_SCLK_AUDIO1>,
+		<&cmu_top CLK_MOUT_SCLK_SPDIF>,
+
+		<&cmu_aud CLK_DIV_AUD_CA5>,
+		<&cmu_aud CLK_DIV_ACLK_AUD>,
+		<&cmu_aud CLK_DIV_PCLK_DBG_AUD>,
+		<&cmu_aud CLK_DIV_SCLK_AUD_I2S>,
+		<&cmu_aud CLK_DIV_SCLK_AUD_PCM>,
+		<&cmu_aud CLK_DIV_SCLK_AUD_SLIMBUS>,
+		<&cmu_aud CLK_DIV_SCLK_AUD_UART>,
+		<&cmu_top CLK_DIV_SCLK_AUDIO0>,
+		<&cmu_top CLK_DIV_SCLK_AUDIO1>,
+		<&cmu_top CLK_DIV_SCLK_PCM1>,
+		<&cmu_top CLK_DIV_SCLK_I2S1>;
+
+	assigned-clock-parents = <&cmu_top CLK_FOUT_AUD_PLL>,
+		<&cmu_aud CLK_MOUT_AUD_PLL_USER>,
+		<&cmu_aud CLK_MOUT_AUD_PLL_USER>,
+		<&cmu_top CLK_FOUT_AUD_PLL>,
+		<&cmu_top CLK_MOUT_AUD_PLL>,
+		<&cmu_top CLK_MOUT_AUD_PLL_USER_T>,
+		<&cmu_top CLK_MOUT_AUD_PLL_USER_T>,
+		<&cmu_top CLK_SCLK_AUDIO0>;
+
+	assigned-clock-rates = <0>, <0>, <0>, <0>, <0>, <0>, <0>, <0>,
+		<196608001>, <65536001>, <32768001>, <49152001>,
+		<2048001>, <24576001>, <196608001>,
+		<24576001>, <98304001>, <2048001>, <49152001>;
 };
 
 &cmu_fsys {
@@ -267,6 +300,11 @@
 				 <&cmu_top CLK_MOUT_BUS_PLL_USER>;
 };
 
+&cmu_top {
+	assigned-clocks = <&cmu_top CLK_FOUT_AUD_PLL>;
+	assigned-clock-rates = <196608001>;
+};
+
 &cpu0 {
 	cpu-supply = <&buck3_reg>;
 };
@@ -838,6 +876,12 @@
 	status = "okay";
 };
 
+&i2s1 {
+	assigned-clocks = <&i2s1 CLK_I2S_RCLK_SRC>;
+	assigned-clock-parents = <&cmu_peric CLK_SCLK_I2S1>;
+	status = "okay";
+};
+
 &mshc_0 {
 	status = "okay";
 	mmc-hs200-1_8v;
diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
index 62f276970174..c0231d077fa6 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
@@ -969,6 +969,7 @@
 			ddc = <&hsi2c_11>;
 			samsung,syscon-phandle = <&pmu_system_controller>;
 			samsung,sysreg-phandle = <&syscon_disp>;
+			#sound-dai-cells = <0>;
 			status = "disabled";
 		};
 
@@ -1311,6 +1312,25 @@
 			status = "disabled";
 		};
 
+		i2s1: i2s@14d60000 {
+			compatible = "samsung,exynos7-i2s";
+			reg = <0x14d60000 0x100>;
+			dmas = <&pdma0 31 &pdma0 30>;
+			dma-names = "tx", "rx";
+			interrupts = <GIC_SPI 435 IRQ_TYPE_NONE>;
+			clocks = <&cmu_peric CLK_PCLK_I2S1>,
+				 <&cmu_peric CLK_PCLK_I2S1>,
+				 <&cmu_peric CLK_SCLK_I2S1>;
+			clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+			#clock-cells = <1>;
+			samsung,supports-6ch;
+			samsung,supports-rstclr;
+			samsung,supports-tdm;
+			samsung,supports-low-rfs;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+		};
+
 		pwm: pwm@14dd0000 {
 			compatible = "samsung,exynos4210-pwm";
 			reg = <0x14dd0000 0x100>;
@@ -1639,7 +1659,7 @@
 				power-domains = <&pd_aud>;
 			};
 
-			i2s0: i2s0@11440000 {
+			i2s0: i2s@11440000 {
 				compatible = "samsung,exynos7-i2s";
 				reg = <0x11440000 0x100>;
 				dmas = <&adma 0 &adma 2>;
@@ -1651,9 +1671,11 @@
 					<&cmu_aud CLK_SCLK_AUD_I2S>,
 					<&cmu_aud CLK_SCLK_I2S_BCLK>;
 				clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+				#clock-cells = <1>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&i2s0_bus>;
 				power-domains = <&pd_aud>;
+				#sound-dai-cells = <1>;
 				status = "disabled";
 			};
 
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
index 82b272fb41b9..4e98d057253b 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
@@ -118,6 +118,37 @@
 		mask = <0x02>;
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <5000>;
+			thermal-sensors = <&tmu 0>;
+
+			trips {
+				cpu_alert: cpu-alert {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu-crit {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu0 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
@@ -304,37 +335,6 @@
 			#thermal-sensor-cells = <1>;
 		};
 
-		thermal-zones {
-			cpu_thermal: cpu-thermal {
-				polling-delay-passive = <1000>;
-				polling-delay = <5000>;
-				thermal-sensors = <&tmu 0>;
-
-				trips {
-					cpu_alert: cpu-alert {
-						temperature = <85000>;
-						hysteresis = <2000>;
-						type = "passive";
-					};
-
-					cpu_crit: cpu-crit {
-						temperature = <95000>;
-						hysteresis = <2000>;
-						type = "critical";
-					};
-				};
-
-				cooling-maps {
-					map0 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu0 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-				};
-			};
-		};
-
 		i2c0: i2c@2180000 {
 			compatible = "fsl,vf610-i2c";
 			#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 380e7c713395..4d15e111cf12 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -159,6 +159,37 @@
 		mask = <0x02>;
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <5000>;
+
+			thermal-sensors = <&tmu 3>;
+
+			trips {
+				cpu_alert: cpu-alert {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit: cpu-crit {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu0 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <1 13 0xf08>, /* Physical Secure PPI */
@@ -342,37 +373,6 @@
 			#thermal-sensor-cells = <1>;
 		};
 
-		thermal-zones {
-			cpu_thermal: cpu-thermal {
-				polling-delay-passive = <1000>;
-				polling-delay = <5000>;
-
-				thermal-sensors = <&tmu 3>;
-
-				trips {
-					cpu_alert: cpu-alert {
-						temperature = <85000>;
-						hysteresis = <2000>;
-						type = "passive";
-					};
-					cpu_crit: cpu-crit {
-						temperature = <95000>;
-						hysteresis = <2000>;
-						type = "critical";
-					};
-				};
-
-				cooling-maps {
-					map0 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu0 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-				};
-			};
-		};
-
 		qman: qman@1880000 {
 			compatible = "fsl,qman";
 			reg = <0x0 0x1880000 0x0 0x10000>;
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 06b5e12d04d8..3f8b62010c7c 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -147,6 +147,37 @@
 		mask = <0x02>;
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <5000>;
+			thermal-sensors = <&tmu 3>;
+
+			trips {
+				cpu_alert: cpu-alert {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu-crit {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu0 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_RAW(0xf) |
@@ -362,37 +393,6 @@
 			#thermal-sensor-cells = <1>;
 		};
 
-		thermal-zones {
-			cpu_thermal: cpu-thermal {
-				polling-delay-passive = <1000>;
-				polling-delay = <5000>;
-				thermal-sensors = <&tmu 3>;
-
-				trips {
-					cpu_alert: cpu-alert {
-						temperature = <85000>;
-						hysteresis = <2000>;
-						type = "passive";
-					};
-
-					cpu_crit: cpu-crit {
-						temperature = <95000>;
-						hysteresis = <2000>;
-						type = "critical";
-					};
-				};
-
-				cooling-maps {
-					map0 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu0 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-				};
-			};
-		};
-
 		dspi: dspi@2100000 {
 			compatible = "fsl,ls1021a-v1.0-dspi";
 			#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
index 4fc150cd4ca5..12ffa584d173 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
@@ -158,6 +158,44 @@
 		};
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <5000>;
+			thermal-sensors = <&tmu 0>;
+
+			trips {
+				cpu_alert: cpu-alert {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu-crit {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu0 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+
+				map1 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu4 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,/* Physical Secure PPI */
@@ -315,44 +353,6 @@
 			#thermal-sensor-cells = <1>;
 		};
 
-		thermal-zones {
-			cpu_thermal: cpu-thermal {
-				polling-delay-passive = <1000>;
-				polling-delay = <5000>;
-				thermal-sensors = <&tmu 0>;
-
-				trips {
-					cpu_alert: cpu-alert {
-						temperature = <85000>;
-						hysteresis = <2000>;
-						type = "passive";
-					};
-
-					cpu_crit: cpu-crit {
-						temperature = <95000>;
-						hysteresis = <2000>;
-						type = "critical";
-					};
-				};
-
-				cooling-maps {
-					map0 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu0 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-
-					map1 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu4 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-				};
-			};
-		};
-
 		duart0: serial@21c0500 {
 			compatible = "fsl,ns16550", "ns16550a";
 			reg = <0x0 0x21c0500 0x0 0x100>;
@@ -612,6 +612,62 @@
 					<0000 0 0 3 &gic 0 0 0 121 IRQ_TYPE_LEVEL_HIGH>,
 					<0000 0 0 4 &gic 0 0 0 122 IRQ_TYPE_LEVEL_HIGH>;
 		};
+
+		cluster1_core0_watchdog: wdt@c000000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc000000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster1_core1_watchdog: wdt@c010000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc010000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster1_core2_watchdog: wdt@c020000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc020000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster1_core3_watchdog: wdt@c030000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc030000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster2_core0_watchdog: wdt@c100000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc100000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster2_core1_watchdog: wdt@c110000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc110000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster2_core2_watchdog: wdt@c120000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc120000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
+
+		cluster2_core3_watchdog: wdt@c130000 {
+			compatible = "arm,sp805-wdt", "arm,primecell";
+			reg = <0x0 0xc130000 0x0 0x1000>;
+			clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+			clock-names = "apb_pclk", "wdog_clk";
+		};
 	};
 
 	firmware {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi
index b2374469a830..1de618801c73 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi
@@ -140,21 +140,21 @@
 
 &dspi {
 	status = "okay";
-	dflash0: n25q128a {
+	dflash0: n25q128a@0 {
 		#address-cells = <1>;
 		#size-cells = <1>;
 		compatible = "st,m25p80";
 		spi-max-frequency = <3000000>;
 		reg = <0>;
 	};
-	dflash1: sst25wf040b {
+	dflash1: sst25wf040b@1 {
 		#address-cells = <1>;
 		#size-cells = <1>;
 		compatible = "st,m25p80";
 		spi-max-frequency = <3000000>;
 		reg = <1>;
 	};
-	dflash2: en25s64 {
+	dflash2: en25s64@2 {
 		#address-cells = <1>;
 		#size-cells = <1>;
 		compatible = "st,m25p80";
@@ -177,7 +177,7 @@
 		#size-cells = <1>;
 		compatible = "st,m25p80";
 		spi-max-frequency = <20000000>;
-		reg = <0>;
+		reg = <2>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
index f3a40af33af8..137ef4dfc3e9 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
@@ -111,6 +111,55 @@
 		mask = <0x2>;
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <5000>;
+
+			thermal-sensors = <&tmu 4>;
+
+			trips {
+				cpu_alert: cpu-alert {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit: cpu-crit {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu0 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+				map1 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu2 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+				map2 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu4 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+				map3 {
+					trip = <&cpu_alert>;
+					cooling-device =
+						<&cpu6 THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <1 13 4>, /* Physical Secure PPI, active-low */
@@ -194,55 +243,6 @@
 			#thermal-sensor-cells = <1>;
 		};
 
-		thermal-zones {
-			cpu_thermal: cpu-thermal {
-				polling-delay-passive = <1000>;
-				polling-delay = <5000>;
-
-				thermal-sensors = <&tmu 4>;
-
-				trips {
-					cpu_alert: cpu-alert {
-						temperature = <75000>;
-						hysteresis = <2000>;
-						type = "passive";
-					};
-					cpu_crit: cpu-crit {
-						temperature = <85000>;
-						hysteresis = <2000>;
-						type = "critical";
-					};
-				};
-
-				cooling-maps {
-					map0 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu0 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-					map1 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu2 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-					map2 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu4 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-					map3 {
-						trip = <&cpu_alert>;
-						cooling-device =
-							<&cpu6 THERMAL_NO_LIMIT
-							THERMAL_NO_LIMIT>;
-					};
-				};
-			};
-		};
-
 		serial0: serial@21c0500 {
 			compatible = "fsl,ns16550", "ns16550a";
 			reg = <0x0 0x21c0500 0x0 0x100>;
diff --git a/arch/arm64/boot/dts/freescale/qoriq-bman-portals.dtsi b/arch/arm64/boot/dts/freescale/qoriq-bman-portals.dtsi
index c3c2be4f5072..ae15307f6e8b 100644
--- a/arch/arm64/boot/dts/freescale/qoriq-bman-portals.dtsi
+++ b/arch/arm64/boot/dts/freescale/qoriq-bman-portals.dtsi
@@ -68,4 +68,10 @@
 		reg = <0x80000 0x4000>, <0x4080000 0x4000>;
 		interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+	bman-portal@90000 {
+		compatible = "fsl,bman-portal";
+		reg = <0x90000 0x4000>, <0x4090000 0x4000>;
+		interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+	};
 };
diff --git a/arch/arm64/boot/dts/freescale/qoriq-qman-portals.dtsi b/arch/arm64/boot/dts/freescale/qoriq-qman-portals.dtsi
index 2a9aa060efda..6a93a4a9be0e 100644
--- a/arch/arm64/boot/dts/freescale/qoriq-qman-portals.dtsi
+++ b/arch/arm64/boot/dts/freescale/qoriq-qman-portals.dtsi
@@ -77,4 +77,11 @@
 		interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
 		cell-index = <8>;
 	};
+
+	qportal9: qman-portal@90000 {
+		compatible = "fsl,qman-portal";
+		reg = <0x90000 0x4000>, <0x4090000 0x4000>;
+		interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+		cell-index = <9>;
+	};
 };
diff --git a/arch/arm64/boot/dts/marvell/armada-371x.dtsi b/arch/arm64/boot/dts/marvell/armada-371x.dtsi
index 11226f7b9ed9..dc1182ec9fa1 100644
--- a/arch/arm64/boot/dts/marvell/armada-371x.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-371x.dtsi
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree Include file for Marvell Armada 371x family of SoCs
  * (also named 88F3710)
@@ -6,43 +7,6 @@
  *
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "armada-37xx.dtsi"
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 0f3468e777f7..f2cc00594d64 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree file for Marvell Armada 3720 development board
  * (DB-88F3720-DDR3)
@@ -5,44 +6,6 @@
  *
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- *
  * This file is compatible with the version 1.4 and the version 2.0 of
  * the board, however the CON numbers are different between the 2
  * version
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
index bdfb5553ddb5..31efd6a96e9d 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
@@ -1,46 +1,10 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree file for Globalscale Marvell ESPRESSOBin Board
  * Copyright (C) 2016 Marvell
  *
  * Romain Perier <romain.perier@free-electrons.com>
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
diff --git a/arch/arm64/boot/dts/marvell/armada-372x.dtsi b/arch/arm64/boot/dts/marvell/armada-372x.dtsi
index 2554e0baea6b..97558a64e276 100644
--- a/arch/arm64/boot/dts/marvell/armada-372x.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-372x.dtsi
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree Include file for Marvell Armada 372x family of SoCs
  * (also named 88F3720)
@@ -6,43 +7,6 @@
  *
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "armada-37xx.dtsi"
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 375026867342..97207a61bc79 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Device Tree Include file for Marvell Armada 37xx family of SoCs.
  *
@@ -5,43 +6,6 @@
  *
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/arch/arm64/boot/dts/marvell/armada-7020.dtsi b/arch/arm64/boot/dts/marvell/armada-7020.dtsi
index 4ab012991d9d..4e46326dd123 100644
--- a/arch/arm64/boot/dts/marvell/armada-7020.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-7020.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for the Armada 7020 SoC, made of an AP806 Dual and
  * one CP110.
  */
diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
index 3ae05eee2c9a..c470ea89a864 100644
--- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada 7040 Development board platform
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-7040.dtsi b/arch/arm64/boot/dts/marvell/armada-7040.dtsi
index cbe460b8fc00..47247215770d 100644
--- a/arch/arm64/boot/dts/marvell/armada-7040.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-7040.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for the Armada 7040 SoC, made of an AP806 Quad and
  * one CP110.
  */
diff --git a/arch/arm64/boot/dts/marvell/armada-70x0.dtsi b/arch/arm64/boot/dts/marvell/armada-70x0.dtsi
index f63b4fbd642b..e5c6d7c25819 100644
--- a/arch/arm64/boot/dts/marvell/armada-70x0.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-70x0.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2017 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for the Armada 70x0 SoC
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-8020.dtsi b/arch/arm64/boot/dts/marvell/armada-8020.dtsi
index 3318d6b0214b..ba1307c0fadb 100644
--- a/arch/arm64/boot/dts/marvell/armada-8020.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-8020.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for the Armada 8020 SoC, made of an AP806 Dual and
  * two CP110.
  */
diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
index dba55baff20f..3ecea815f861 100644
--- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada 8040 Development board platform
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
index 626e9d0462c3..81de03ef860d 100644
--- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
+++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for MACCHIATOBin Armada 8040 community board platform
  */
 
@@ -49,7 +10,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	model = "Marvell 8040 MACHIATOBin";
+	model = "Marvell 8040 MACCHIATOBin";
 	compatible = "marvell,armada8040-mcbin", "marvell,armada8040",
 			"marvell,armada-ap806-quad", "marvell,armada-ap806";
 
@@ -163,6 +124,13 @@
 	};
 };
 
+/* J25 UART header */
+&cp0_uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&cp0_uart1_pins>;
+	status = "okay";
+};
+
 &cp0_mdio {
 	pinctrl-names = "default";
 	pinctrl-0 = <&cp0_ge_mdio_pins>;
@@ -195,6 +163,10 @@
 		marvell,pins = "mpp37", "mpp38";
 		marvell,function = "i2c0";
 	};
+	cp0_uart1_pins: uart1-pins {
+		marvell,pins = "mpp40", "mpp41";
+		marvell,function = "uart1";
+	};
 	cp0_xhci_vbus_pins: xhci0-vbus-pins {
 		marvell,pins = "mpp47";
 		marvell,function = "gpio";
@@ -290,6 +262,17 @@
 		marvell,pins = "mpp12", "mpp13", "mpp14", "mpp15", "mpp16";
 		marvell,function = "spi1";
 	};
+	cp1_uart0_pins: uart0-pins {
+		marvell,pins = "mpp6", "mpp7";
+		marvell,function = "uart0";
+	};
+};
+
+/* J27 UART header */
+&cp1_uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&cp1_uart0_pins>;
+	status = "okay";
 };
 
 &cp1_sata0 {
diff --git a/arch/arm64/boot/dts/marvell/armada-8040.dtsi b/arch/arm64/boot/dts/marvell/armada-8040.dtsi
index 83d2b40e5981..7699b19224c2 100644
--- a/arch/arm64/boot/dts/marvell/armada-8040.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-8040.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for the Armada 8040 SoC, made of an AP806 Quad and
  * two CP110.
  */
diff --git a/arch/arm64/boot/dts/marvell/armada-8080-db.dts b/arch/arm64/boot/dts/marvell/armada-8080-db.dts
index 85b58a19a9fb..4ba158f415ce 100644
--- a/arch/arm64/boot/dts/marvell/armada-8080-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-8080-db.dts
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2017 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada-8080 Development board platform
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-8080.dtsi b/arch/arm64/boot/dts/marvell/armada-8080.dtsi
index d5535b716735..299e814d1ded 100644
--- a/arch/arm64/boot/dts/marvell/armada-8080.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-8080.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2017 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada-8080 SoC, made of an AP810 OCTA.
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-80x0.dtsi b/arch/arm64/boot/dts/marvell/armada-80x0.dtsi
index e9c84a1d3c4d..8129b40f12a4 100644
--- a/arch/arm64/boot/dts/marvell/armada-80x0.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-80x0.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2017 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for the Armada 80x0 SoC family
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
index b98ea137371d..64b5e61a698e 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806-dual.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada AP806.
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
index 116164ff260f..746e792767f5 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806-quad.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada AP806.
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
index f9b66b81f9fc..176e38d54872 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada AP806.
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-ap810-ap0-octa-core.dtsi b/arch/arm64/boot/dts/marvell/armada-ap810-ap0-octa-core.dtsi
index 7f0661e12f5e..7d00ae78fc79 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap810-ap0-octa-core.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap810-ap0-octa-core.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2017 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada AP810 OCTA cores.
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-ap810-ap0.dtsi b/arch/arm64/boot/dts/marvell/armada-ap810-ap0.dtsi
index 7e6f039f0f80..8107d120a8a7 100644
--- a/arch/arm64/boot/dts/marvell/armada-ap810-ap0.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-ap810-ap0.dtsi
@@ -1,46 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2017 Marvell Technology Group Ltd.
  *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
  * Device Tree file for Marvell Armada AP810.
  */
 
diff --git a/arch/arm64/boot/dts/marvell/armada-common.dtsi b/arch/arm64/boot/dts/marvell/armada-common.dtsi
index c6dd1d81c68d..d5e8aedec188 100644
--- a/arch/arm64/boot/dts/marvell/armada-common.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-common.dtsi
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR X11)
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  */
diff --git a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
index a8af4136dbe7..0709b19eb328 100644
--- a/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-cp110.dtsi
@@ -1,9 +1,7 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR X11)
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 /*
  * Copyright (C) 2016 Marvell Technology Group Ltd.
- */
-
-/*
+ *
  * Device Tree file for Marvell Armada CP110.
  */
 
@@ -257,7 +255,9 @@
 			reg = <0x700600 0x50>;
 			#address-cells = <0x1>;
 			#size-cells = <0x0>;
-			clocks = <&CP110_LABEL(clk) 1 21>;
+			clock-names = "core", "axi";
+			clocks = <&CP110_LABEL(clk) 1 21>,
+				 <&CP110_LABEL(clk) 1 17>;
 			status = "disabled";
 		};
 
@@ -266,7 +266,9 @@
 			reg = <0x700680 0x50>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			clocks = <&CP110_LABEL(clk) 1 21>;
+			clock-names = "core", "axi";
+			clocks = <&CP110_LABEL(clk) 1 21>,
+				 <&CP110_LABEL(clk) 1 17>;
 			status = "disabled";
 		};
 
@@ -276,7 +278,9 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			interrupts = <ICU_GRP_NSR 120 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&CP110_LABEL(clk) 1 21>;
+			clock-names = "core", "reg";
+			clocks = <&CP110_LABEL(clk) 1 21>,
+				 <&CP110_LABEL(clk) 1 17>;
 			status = "disabled";
 		};
 
@@ -286,6 +290,48 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			interrupts = <ICU_GRP_NSR 121 IRQ_TYPE_LEVEL_HIGH>;
+			clock-names = "core", "reg";
+			clocks = <&CP110_LABEL(clk) 1 21>,
+				 <&CP110_LABEL(clk) 1 17>;
+			status = "disabled";
+		};
+
+		CP110_LABEL(uart0): serial@702000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x702000 0x100>;
+			reg-shift = <2>;
+			interrupts = <ICU_GRP_NSR 122 IRQ_TYPE_LEVEL_HIGH>;
+			reg-io-width = <1>;
+			clocks = <&CP110_LABEL(clk) 1 21>;
+			status = "disabled";
+		};
+
+		CP110_LABEL(uart1): serial@702100 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x702100 0x100>;
+			reg-shift = <2>;
+			interrupts = <ICU_GRP_NSR 123 IRQ_TYPE_LEVEL_HIGH>;
+			reg-io-width = <1>;
+			clocks = <&CP110_LABEL(clk) 1 21>;
+			status = "disabled";
+		};
+
+		CP110_LABEL(uart2): serial@702200 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x702200 0x100>;
+			reg-shift = <2>;
+			interrupts = <ICU_GRP_NSR 124 IRQ_TYPE_LEVEL_HIGH>;
+			reg-io-width = <1>;
+			clocks = <&CP110_LABEL(clk) 1 21>;
+			status = "disabled";
+		};
+
+		CP110_LABEL(uart3): serial@702300 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x702300 0x100>;
+			reg-shift = <2>;
+			interrupts = <ICU_GRP_NSR 125 IRQ_TYPE_LEVEL_HIGH>;
+			reg-io-width = <1>;
 			clocks = <&CP110_LABEL(clk) 1 21>;
 			status = "disabled";
 		};
diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
index 2186d0193b73..c885eef4e660 100644
--- a/arch/arm64/boot/dts/renesas/Makefile
+++ b/arch/arm64/boot/dts/renesas/Makefile
@@ -8,4 +8,5 @@ dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-x.dtb r8a7796-m3ulcb.dtb
 dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-kf.dtb
 dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-xs.dtb
 dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle.dtb r8a77970-v3msk.dtb
+dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-condor.dtb
 dtb-$(CONFIG_ARCH_R8A77995) += r8a77995-draak.dtb
diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
index 26769a11a190..f1d5e90503d5 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795-es1.dtsi
@@ -80,7 +80,7 @@
 
 	vspd3: vsp@fea38000 {
 		compatible = "renesas,vsp2";
-		reg = <0 0xfea38000 0 0x4000>;
+		reg = <0 0xfea38000 0 0x8000>;
 		interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cpg CPG_MOD 620>;
 		power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
index d12df6f2ff09..6d53e1cb7b29 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -41,6 +41,9 @@
 			power-domains = <&sysc R8A7795_PD_CA57_CPU0>;
 			next-level-cache = <&L2_CA57>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z>;
+			operating-points-v2 = <&cluster0_opp>;
+			#cooling-cells = <2>;
 		};
 
 		a57_1: cpu@1 {
@@ -50,6 +53,9 @@
 			power-domains = <&sysc R8A7795_PD_CA57_CPU1>;
 			next-level-cache = <&L2_CA57>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z>;
+			operating-points-v2 = <&cluster0_opp>;
+			#cooling-cells = <2>;
 		};
 
 		a57_2: cpu@2 {
@@ -59,6 +65,9 @@
 			power-domains = <&sysc R8A7795_PD_CA57_CPU2>;
 			next-level-cache = <&L2_CA57>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z>;
+			operating-points-v2 = <&cluster0_opp>;
+			#cooling-cells = <2>;
 		};
 
 		a57_3: cpu@3 {
@@ -68,6 +77,9 @@
 			power-domains = <&sysc R8A7795_PD_CA57_CPU3>;
 			next-level-cache = <&L2_CA57>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z>;
+			operating-points-v2 = <&cluster0_opp>;
+			#cooling-cells = <2>;
 		};
 
 		a53_0: cpu@100 {
@@ -77,6 +89,8 @@
 			power-domains = <&sysc R8A7795_PD_CA53_CPU0>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		a53_1: cpu@101 {
@@ -86,6 +100,8 @@
 			power-domains = <&sysc R8A7795_PD_CA53_CPU1>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		a53_2: cpu@102 {
@@ -95,6 +111,8 @@
 			power-domains = <&sysc R8A7795_PD_CA53_CPU2>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		a53_3: cpu@103 {
@@ -104,6 +122,8 @@
 			power-domains = <&sysc R8A7795_PD_CA53_CPU3>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7795_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		L2_CA57: cache-controller-0 {
@@ -165,11 +185,59 @@
 		clock-frequency = <0>;
 	};
 
-	/* External SCIF clock - to be overridden by boards that provide it */
-	scif_clk: scif {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <0>;
+	cluster0_opp: opp_table0 {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp-500000000 {
+			opp-hz = /bits/ 64 <500000000>;
+			opp-microvolt = <830000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <830000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <830000>;
+			clock-latency-ns = <300000>;
+			opp-suspend;
+		};
+		opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <900000>;
+			clock-latency-ns = <300000>;
+			turbo-mode;
+		};
+		opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <960000>;
+			clock-latency-ns = <300000>;
+			turbo-mode;
+		};
+	};
+
+	cluster1_opp: opp_table1 {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
 	};
 
 	/* External PCIe clock - can be overridden by the board */
@@ -208,6 +276,13 @@
 		method = "smc";
 	};
 
+	/* External SCIF clock - to be overridden by boards that provide it */
+	scif_clk: scif {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+
 	soc: soc {
 		compatible = "simple-bus";
 		interrupt-parent = <&gic>;
@@ -2143,7 +2218,7 @@
 
 		vspd0: vsp@fea20000 {
 			compatible = "renesas,vsp2";
-			reg = <0 0xfea20000 0 0x4000>;
+			reg = <0 0xfea20000 0 0x8000>;
 			interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 623>;
 			power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
@@ -2163,7 +2238,7 @@
 
 		vspd1: vsp@fea28000 {
 			compatible = "renesas,vsp2";
-			reg = <0 0xfea28000 0 0x4000>;
+			reg = <0 0xfea28000 0 0x8000>;
 			interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 622>;
 			power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
@@ -2183,7 +2258,7 @@
 
 		vspd2: vsp@fea30000 {
 			compatible = "renesas,vsp2";
-			reg = <0 0xfea30000 0 0x4000>;
+			reg = <0 0xfea30000 0 0x8000>;
 			interrupts = <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 621>;
 			power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
@@ -2320,9 +2395,9 @@
 
 		tsc: thermal@e6198000 {
 			compatible = "renesas,r8a7795-thermal";
-			reg = <0 0xe6198000 0 0x68>,
-			      <0 0xe61a0000 0 0x5c>,
-			      <0 0xe61a8000 0 0x5c>;
+			reg = <0 0xe6198000 0 0x100>,
+			      <0 0xe61a0000 0 0x100>,
+			      <0 0xe61a8000 0 0x100>;
 			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
@@ -2357,12 +2432,24 @@
 			thermal-sensors = <&tsc 0>;
 
 			trips {
+				sensor1_passive: sensor1-passive {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
 				sensor1_crit: sensor1-crit {
 					temperature = <120000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&sensor1_passive>;
+					cooling-device = <&a57_0 4 4>;
+				};
+			};
 		};
 
 		sensor_thermal2: sensor-thermal2 {
@@ -2371,12 +2458,24 @@
 			thermal-sensors = <&tsc 1>;
 
 			trips {
+				sensor2_passive: sensor2-passive {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
 				sensor2_crit: sensor2-crit {
 					temperature = <120000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&sensor2_passive>;
+					cooling-device = <&a57_0 4 4>;
+				};
+			};
 		};
 
 		sensor_thermal3: sensor-thermal3 {
@@ -2385,12 +2484,24 @@
 			thermal-sensors = <&tsc 2>;
 
 			trips {
+				sensor3_passive: sensor3-passive {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
 				sensor3_crit: sensor3-crit {
 					temperature = <120000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&sensor3_passive>;
+					cooling-device = <&a57_0 4 4>;
+				};
+			};
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
index c5192d513d7d..076a9c9346ae 100644
--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
@@ -71,6 +71,9 @@
 			power-domains = <&sysc R8A7796_PD_CA57_CPU0>;
 			next-level-cache = <&L2_CA57>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7796_CLK_Z>;
+			operating-points-v2 = <&cluster0_opp>;
+			#cooling-cells = <2>;
 		};
 
 		a57_1: cpu@1 {
@@ -80,6 +83,9 @@
 			power-domains = <&sysc R8A7796_PD_CA57_CPU1>;
 			next-level-cache = <&L2_CA57>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7796_CLK_Z>;
+			operating-points-v2 = <&cluster0_opp>;
+			#cooling-cells = <2>;
 		};
 
 		a53_0: cpu@100 {
@@ -89,6 +95,8 @@
 			power-domains = <&sysc R8A7796_PD_CA53_CPU0>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7796_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		a53_1: cpu@101 {
@@ -98,6 +106,8 @@
 			power-domains = <&sysc R8A7796_PD_CA53_CPU1>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7796_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		a53_2: cpu@102 {
@@ -107,6 +117,8 @@
 			power-domains = <&sysc R8A7796_PD_CA53_CPU2>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7796_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		a53_3: cpu@103 {
@@ -116,6 +128,8 @@
 			power-domains = <&sysc R8A7796_PD_CA53_CPU3>;
 			next-level-cache = <&L2_CA53>;
 			enable-method = "psci";
+			clocks =<&cpg CPG_CORE R8A7796_CLK_Z2>;
+			operating-points-v2 = <&cluster1_opp>;
 		};
 
 		L2_CA57: cache-controller-0 {
@@ -147,6 +161,72 @@
 		clock-frequency = <0>;
 	};
 
+	cluster0_opp: opp_table0 {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp-500000000 {
+			opp-hz = /bits/ 64 <500000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1500000000 {
+			opp-hz = /bits/ 64 <1500000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <900000>;
+			clock-latency-ns = <300000>;
+			turbo-mode;
+		};
+		opp-1700000000 {
+			opp-hz = /bits/ 64 <1700000000>;
+			opp-microvolt = <900000>;
+			clock-latency-ns = <300000>;
+			turbo-mode;
+		};
+		opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <960000>;
+			clock-latency-ns = <300000>;
+			turbo-mode;
+		};
+	};
+
+	cluster1_opp: opp_table1 {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp-800000000 {
+			opp-hz = /bits/ 64 <800000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+		};
+		opp-1300000000 {
+			opp-hz = /bits/ 64 <1300000000>;
+			opp-microvolt = <820000>;
+			clock-latency-ns = <300000>;
+			turbo-mode;
+		};
+	};
+
 	/* External PCIe clock - can be overridden by the board */
 	pcie_bus_clk: pcie_bus {
 		compatible = "fixed-clock";
@@ -1561,9 +1641,9 @@
 
 		tsc: thermal@e6198000 {
 			compatible = "renesas,r8a7796-thermal";
-			reg = <0 0xe6198000 0 0x68>,
-			      <0 0xe61a0000 0 0x5c>,
-			      <0 0xe61a8000 0 0x5c>;
+			reg = <0 0xe6198000 0 0x100>,
+			      <0 0xe61a0000 0 0x100>,
+			      <0 0xe61a8000 0 0x100>;
 			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
@@ -1839,7 +1919,7 @@
 
 		vspd0: vsp@fea20000 {
 			compatible = "renesas,vsp2";
-			reg = <0 0xfea20000 0 0x4000>;
+			reg = <0 0xfea20000 0 0x8000>;
 			interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 623>;
 			power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
@@ -1859,7 +1939,7 @@
 
 		vspd1: vsp@fea28000 {
 			compatible = "renesas,vsp2";
-			reg = <0 0xfea28000 0 0x4000>;
+			reg = <0 0xfea28000 0 0x8000>;
 			interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 622>;
 			power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
@@ -1879,7 +1959,7 @@
 
 		vspd2: vsp@fea30000 {
 			compatible = "renesas,vsp2";
-			reg = <0 0xfea30000 0 0x4000>;
+			reg = <0 0xfea30000 0 0x8000>;
 			interrupts = <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&cpg CPG_MOD 621>;
 			power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
@@ -1998,12 +2078,24 @@
 			thermal-sensors = <&tsc 0>;
 
 			trips {
+				sensor1_passive: sensor1-passive {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
 				sensor1_crit: sensor1-crit {
 					temperature = <120000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&sensor1_passive>;
+					cooling-device = <&a57_0 5 5>;
+				};
+			};
 		};
 
 		sensor_thermal2: sensor-thermal2 {
@@ -2012,12 +2104,24 @@
 			thermal-sensors = <&tsc 1>;
 
 			trips {
+				sensor2_passive: sensor2-passive {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
 				sensor2_crit: sensor2-crit {
 					temperature = <120000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&sensor2_passive>;
+					cooling-device = <&a57_0 5 5>;
+				};
+			};
 		};
 
 		sensor_thermal3: sensor-thermal3 {
@@ -2026,12 +2130,24 @@
 			thermal-sensors = <&tsc 2>;
 
 			trips {
+				sensor3_passive: sensor3-passive {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
 				sensor3_crit: sensor3-crit {
 					temperature = <120000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&sensor3_passive>;
+					cooling-device = <&a57_0 5 5>;
+				};
+			};
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
index 8fe5c193e049..cb4bd40584cf 100644
--- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
+++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
@@ -41,6 +41,8 @@
 	phy0: ethernet-phy@0 {
 		rxc-skew-ps = <1500>;
 		reg = <0>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
@@ -52,11 +54,21 @@
 	clock-frequency = <32768>;
 };
 
+&pfc {
+	scif0_pins: scif0 {
+		groups = "scif0_data";
+		function = "scif0";
+	};
+};
+
 &rwdt {
 	timeout-sec = <60>;
 	status = "okay";
 };
 
 &scif0 {
+	pinctrl-0 = <&scif0_pins>;
+	pinctrl-names = "default";
+
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi
index c35a117fc447..31eeca1531f6 100644
--- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi
@@ -92,18 +92,6 @@
 			resets = <&cpg 408>;
 		};
 
-		timer {
-			compatible = "arm,armv8-timer";
-			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) |
-						  IRQ_TYPE_LEVEL_LOW)>,
-				     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) |
-						  IRQ_TYPE_LEVEL_LOW)>,
-				     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) |
-						  IRQ_TYPE_LEVEL_LOW)>,
-				     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) |
-						  IRQ_TYPE_LEVEL_LOW)>;
-		};
-
 		rwdt: watchdog@e6020000 {
 			compatible = "renesas,r8a77970-wdt",
 				     "renesas,rcar-gen3-wdt";
@@ -178,6 +166,101 @@
 			#iommu-cells = <1>;
 		};
 
+		pfc: pin-controller@e6060000 {
+			compatible = "renesas,pfc-r8a77970";
+			reg = <0 0xe6060000 0 0x504>;
+		};
+
+		gpio0: gpio@e6050000 {
+			compatible = "renesas,gpio-r8a77970",
+				     "renesas,rcar-gen3-gpio";
+			reg = <0 0xe6050000 0 0x50>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 0 22>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 912>;
+			power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+			resets = <&cpg 912>;
+		};
+
+		gpio1: gpio@e6051000 {
+			compatible = "renesas,gpio-r8a77970",
+				     "renesas,rcar-gen3-gpio";
+			reg = <0 0xe6051000 0 0x50>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 32 28>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 911>;
+			power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+			resets = <&cpg 911>;
+		};
+
+		gpio2: gpio@e6052000 {
+			compatible = "renesas,gpio-r8a77970",
+				     "renesas,rcar-gen3-gpio";
+			reg = <0 0xe6052000 0 0x50>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 64 17>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 910>;
+			power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+			resets = <&cpg 910>;
+		};
+
+		gpio3: gpio@e6053000 {
+			compatible = "renesas,gpio-r8a77970",
+				     "renesas,rcar-gen3-gpio";
+			reg = <0 0xe6053000 0 0x50>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 96 17>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 909>;
+			power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+			resets = <&cpg 909>;
+		};
+
+		gpio4: gpio@e6054000 {
+			compatible = "renesas,gpio-r8a77970",
+				     "renesas,rcar-gen3-gpio";
+			reg = <0 0xe6054000 0 0x50>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 128 6>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 908>;
+			power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+			resets = <&cpg 908>;
+		};
+
+		gpio5: gpio@e6055000 {
+			compatible = "renesas,gpio-r8a77970",
+				     "renesas,rcar-gen3-gpio";
+			reg = <0 0xe6055000 0 0x50>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			#gpio-cells = <2>;
+			gpio-controller;
+			gpio-ranges = <&pfc 0 160 15>;
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			clocks = <&cpg CPG_MOD 907>;
+			power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+			resets = <&cpg 907>;
+		};
+
 		intc_ex: interrupt-controller@e61c0000 {
 			compatible = "renesas,intc-ex-r8a77970", "renesas,irqc";
 			#interrupt-cells = <2>;
@@ -400,7 +483,7 @@
 		avb: ethernet@e6800000 {
 			compatible = "renesas,etheravb-r8a77970",
 				     "renesas,etheravb-rcar-gen3";
-			reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>;
+			reg = <0 0xe6800000 0 0x800>;
 			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
@@ -442,4 +525,12 @@
 			#size-cells = <0>;
 		};
 	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
+	};
 };
diff --git a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
new file mode 100644
index 000000000000..06cf6845765a
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the Condor board
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ * Copyright (C) 2018 Cogent Embedded, Inc.
+ */
+
+/dts-v1/;
+#include "r8a77980.dtsi"
+
+/ {
+	model = "Renesas Condor board based on r8a77980";
+	compatible = "renesas,condor", "renesas,r8a77980";
+
+	aliases {
+		serial0 = &scif0;
+		ethernet0 = &avb;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	memory@48000000 {
+		device_type = "memory";
+		/* first 128MB is reserved for secure area. */
+		reg = <0 0x48000000 0 0x78000000>;
+	};
+};
+
+&avb {
+	phy-mode = "rgmii-id";
+	phy-handle = <&phy0>;
+	renesas,no-ether-link;
+	status = "okay";
+
+	phy0: ethernet-phy@0 {
+		rxc-skew-ps = <1500>;
+		reg = <0>;
+	};
+};
+
+&extal_clk {
+	clock-frequency = <16666666>;
+};
+
+&extalr_clk {
+	clock-frequency = <32768>;
+};
+
+&scif0 {
+	status = "okay";
+};
+
+&scif_clk {
+	clock-frequency = <14745600>;
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
new file mode 100644
index 000000000000..03845fd74996
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the r8a77980 SoC
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ * Copyright (C) 2018 Cogent Embedded, Inc.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/ {
+	compatible = "renesas,r8a77980";
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		a53_0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53", "arm,armv8";
+			reg = <0>;
+			clocks = <&cpg CPG_CORE 0>;
+			power-domains = <&sysc 5>;
+			next-level-cache = <&L2_CA53>;
+			enable-method = "psci";
+		};
+
+		L2_CA53: cache-controller {
+			compatible = "cache";
+			power-domains = <&sysc 21>;
+			cache-unified;
+			cache-level = <2>;
+		};
+	};
+
+	extal_clk: extal {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board */
+		clock-frequency = <0>;
+	};
+
+	extalr_clk: extalr {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		/* This value must be overridden by the board */
+		clock-frequency = <0>;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2";
+		method = "smc";
+	};
+
+	/* External SCIF clock - to be overridden by boards that provide it */
+	scif_clk: scif {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+	};
+
+	soc {
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
+
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		cpg: clock-controller@e6150000 {
+			compatible = "renesas,r8a77980-cpg-mssr";
+			reg = <0 0xe6150000 0 0x1000>;
+			clocks = <&extal_clk>, <&extalr_clk>;
+			clock-names = "extal", "extalr";
+			#clock-cells = <2>;
+			#power-domain-cells = <0>;
+			#reset-cells = <1>;
+		};
+
+		rst: reset-controller@e6160000 {
+			compatible = "renesas,r8a77980-rst";
+			reg = <0 0xe6160000 0 0x200>;
+		};
+
+		sysc: system-controller@e6180000 {
+			compatible = "renesas,r8a77980-sysc";
+			reg = <0 0xe6180000 0 0x440>;
+			#power-domain-cells = <1>;
+		};
+
+		hscif0: serial@e6540000 {
+			compatible = "renesas,hscif-r8a77980",
+				     "renesas,rcar-gen3-hscif",
+				     "renesas,hscif";
+			reg = <0 0xe6540000 0 0x60>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 520>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x31>, <&dmac1 0x30>,
+			       <&dmac2 0x31>, <&dmac2 0x30>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 520>;
+			status = "disabled";
+		};
+
+		hscif1: serial@e6550000 {
+			compatible = "renesas,hscif-r8a77980",
+				     "renesas,rcar-gen3-hscif",
+				     "renesas,hscif";
+			reg = <0 0xe6550000 0 0x60>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 519>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x33>, <&dmac1 0x32>,
+			       <&dmac2 0x33>, <&dmac2 0x32>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 519>;
+			status = "disabled";
+		};
+
+		hscif2: serial@e6560000 {
+			compatible = "renesas,hscif-r8a77980",
+				     "renesas,rcar-gen3-hscif",
+				     "renesas,hscif";
+			reg = <0 0xe6560000 0 0x60>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 518>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x35>, <&dmac1 0x34>,
+			       <&dmac2 0x35>, <&dmac2 0x34>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 518>;
+			status = "disabled";
+		};
+
+		hscif3: serial@e66a0000 {
+			compatible = "renesas,hscif-r8a77980",
+				     "renesas,rcar-gen3-hscif",
+				     "renesas,hscif";
+			reg = <0 0xe66a0000 0 0x60>;
+			interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 517>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x37>, <&dmac1 0x36>,
+			       <&dmac2 0x37>, <&dmac2 0x36>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 517>;
+			status = "disabled";
+		};
+
+		avb: ethernet@e6800000 {
+			compatible = "renesas,etheravb-r8a77980",
+				     "renesas,etheravb-rcar-gen3";
+			reg = <0 0xe6800000 0 0x800>;
+			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14", "ch15",
+					  "ch16", "ch17", "ch18", "ch19",
+					  "ch20", "ch21", "ch22", "ch23",
+					  "ch24";
+			clocks = <&cpg CPG_MOD 812>;
+			power-domains = <&sysc 32>;
+			resets = <&cpg 812>;
+			phy-mode = "rgmii";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		scif0: serial@e6e60000 {
+			compatible = "renesas,scif-r8a77980",
+				     "renesas,rcar-gen3-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e60000 0 0x40>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 207>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x51>, <&dmac1 0x50>,
+			       <&dmac2 0x51>, <&dmac2 0x50>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 207>;
+			status = "disabled";
+		};
+
+		scif1: serial@e6e68000 {
+			compatible = "renesas,scif-r8a77980",
+				     "renesas,rcar-gen3-scif",
+				     "renesas,scif";
+			reg = <0 0xe6e68000 0 0x40>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 206>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x53>, <&dmac1 0x52>,
+			       <&dmac2 0x53>, <&dmac2 0x52>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 206>;
+			status = "disabled";
+		};
+
+		scif3: serial@e6c50000 {
+			compatible = "renesas,scif-r8a77980",
+				     "renesas,rcar-gen3-scif",
+				     "renesas,scif";
+			reg = <0 0xe6c50000 0 0x40>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 204>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x57>, <&dmac1 0x56>,
+			       <&dmac2 0x57>, <&dmac2 0x56>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 204>;
+			status = "disabled";
+		};
+
+		scif4: serial@e6c40000 {
+			compatible = "renesas,scif-r8a77980",
+				     "renesas,rcar-gen3-scif",
+				     "renesas,scif";
+			reg = <0 0xe6c40000 0 0x40>;
+			interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 203>,
+				 <&cpg CPG_CORE 19>,
+				 <&scif_clk>;
+			clock-names = "fck", "brg_int", "scif_clk";
+			dmas = <&dmac1 0x59>, <&dmac1 0x58>,
+			       <&dmac2 0x59>, <&dmac2 0x58>;
+			dma-names = "tx", "rx", "tx", "rx";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 203>;
+			status = "disabled";
+		};
+
+		dmac1: dma-controller@e7300000 {
+			compatible = "renesas,dmac-r8a77980",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe7300000 0 0x10000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14", "ch15";
+			clocks = <&cpg CPG_MOD 218>;
+			clock-names = "fck";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 218>;
+			#dma-cells = <1>;
+			dma-channels = <16>;
+		};
+
+		dmac2: dma-controller@e7310000 {
+			compatible = "renesas,dmac-r8a77980",
+				     "renesas,rcar-dmac";
+			reg = <0 0xe7310000 0 0x10000>;
+			interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 363 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH
+				      GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "error",
+					  "ch0", "ch1", "ch2", "ch3",
+					  "ch4", "ch5", "ch6", "ch7",
+					  "ch8", "ch9", "ch10", "ch11",
+					  "ch12", "ch13", "ch14", "ch15";
+			clocks = <&cpg CPG_MOD 217>;
+			clock-names = "fck";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 217>;
+			#dma-cells = <1>;
+			dma-channels = <16>;
+		};
+
+		gic: interrupt-controller@f1010000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <0x0 0xf1010000 0 0x1000>,
+			      <0x0 0xf1020000 0 0x20000>,
+			      <0x0 0xf1040000 0 0x20000>,
+			      <0x0 0xf1060000 0 0x20000>;
+			interrupts = <GIC_PPI 9	(GIC_CPU_MASK_SIMPLE(1) |
+				      IRQ_TYPE_LEVEL_HIGH)>;
+			clocks = <&cpg CPG_MOD 408>;
+			clock-names = "clk";
+			power-domains = <&sysc 32>;
+			resets = <&cpg 408>;
+		};
+
+		prr: chipid@fff00044 {
+			compatible = "renesas,prr";
+			reg = <0 0xfff00044 0 4>;
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) |
+				       IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) |
+				       IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) |
+				       IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) |
+				       IRQ_TYPE_LEVEL_LOW)>;
+	};
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts
index 09de73b11db8..34c7f58417ba 100644
--- a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts
+++ b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts
@@ -27,11 +27,61 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	vga {
+		compatible = "vga-connector";
+
+		port {
+			vga_in: endpoint {
+				remote-endpoint = <&adv7123_out>;
+			};
+		};
+	};
+
+	vga-encoder {
+		compatible = "adi,adv7123";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				adv7123_in: endpoint {
+					remote-endpoint = <&du_out_rgb>;
+				};
+			};
+			port@1 {
+				reg = <1>;
+				adv7123_out: endpoint {
+					remote-endpoint = <&vga_in>;
+				};
+			};
+		};
+	};
+
 	memory@48000000 {
 		device_type = "memory";
 		/* first 128MB is reserved for secure area. */
 		reg = <0x0 0x48000000 0x0 0x18000000>;
 	};
+
+	reg_1p8v: regulator0 {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator1 {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
 };
 
 &extal_clk {
@@ -46,6 +96,21 @@
 		};
 	};
 
+	du_pins: du {
+		groups = "du_rgb888", "du_sync", "du_disp", "du_clk_out_0";
+		function = "du";
+	};
+
+	i2c0_pins: i2c0 {
+		groups = "i2c0";
+		function = "i2c0";
+	};
+
+	i2c1_pins: i2c1 {
+		groups = "i2c1";
+		function = "i2c1";
+	};
+
 	pwm0_pins: pwm0 {
 		groups = "pwm0_c";
 		function = "pwm0";
@@ -61,12 +126,56 @@
 		function = "scif2";
 	};
 
+	sdhi2_pins: sd2 {
+		groups = "mmc_data8", "mmc_ctrl";
+		function = "mmc";
+		power-source = <1800>;
+	};
+
+	sdhi2_pins_uhs: sd2_uhs {
+		groups = "mmc_data8", "mmc_ctrl";
+		function = "mmc";
+		power-source = <1800>;
+	};
+
 	usb0_pins: usb0 {
 		groups = "usb0";
 		function = "usb0";
 	};
 };
 
+&i2c0 {
+	pinctrl-0 = <&i2c0_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	eeprom@50 {
+		compatible = "rohm,br24t01", "atmel,24c01";
+		reg = <0x50>;
+		pagesize = <8>;
+	};
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&du {
+	pinctrl-0 = <&du_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	ports {
+		port@0 {
+			endpoint {
+				remote-endpoint = <&adv7123_in>;
+			};
+		};
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -97,6 +206,20 @@
 	status = "okay";
 };
 
+&sdhi2 {
+	/* used for on-board eMMC */
+	pinctrl-0 = <&sdhi2_pins>;
+	pinctrl-1 = <&sdhi2_pins_uhs>;
+	pinctrl-names = "default", "state_uhs";
+
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	bus-width = <8>;
+	mmc-hs200-1_8v;
+	non-removable;
+	status = "okay";
+};
+
 &usb2_phy0 {
 	pinctrl-0 = <&usb0_pins>;
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/renesas/r8a77995.dtsi b/arch/arm64/boot/dts/renesas/r8a77995.dtsi
index cff42cd1a6c8..bcf737a20636 100644
--- a/arch/arm64/boot/dts/renesas/r8a77995.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a77995.dtsi
@@ -58,6 +58,11 @@
 		clock-frequency = <0>;
 	};
 
+	pmu_a53 {
+		compatible = "arm,cortex-a53-pmu";
+		interrupts-extended = <&gic GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
 	scif_clk: scif {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -88,18 +93,6 @@
 			resets = <&cpg 408>;
 		};
 
-		timer {
-			compatible = "arm,armv8-timer";
-			interrupts = <GIC_PPI 13
-					(GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
-				     <GIC_PPI 14
-					(GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
-				     <GIC_PPI 11
-					(GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
-				     <GIC_PPI 10
-					(GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
-		};
-
 		rwdt: watchdog@e6020000 {
 			compatible = "renesas,r8a77995-wdt",
 				     "renesas,rcar-gen3-wdt";
@@ -110,11 +103,6 @@
 			status = "disabled";
 		};
 
-		pmu_a53 {
-			compatible = "arm,cortex-a53-pmu";
-			interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
-		};
-
 		ipmmu_vi0: mmu@febd0000 {
 			compatible = "renesas,ipmmu-r8a77995";
 			reg = <0 0xfebd0000 0 0x1000>;
@@ -488,7 +476,7 @@
 		avb: ethernet@e6800000 {
 			compatible = "renesas,etheravb-r8a77995",
 				     "renesas,etheravb-rcar-gen3";
-			reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>;
+			reg = <0 0xe6800000 0 0x800>;
 			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
@@ -548,6 +536,73 @@
 			status = "disabled";
 		};
 
+		i2c0: i2c@e6500000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a77995",
+				     "renesas,rcar-gen3-i2c";
+			reg = <0 0xe6500000 0 0x40>;
+			interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 931>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 931>;
+			dmas = <&dmac1 0x91>, <&dmac1 0x90>,
+			       <&dmac2 0x91>, <&dmac2 0x90>;
+			dma-names = "tx", "rx", "tx", "rx";
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
+
+		i2c1: i2c@e6508000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a77995",
+				     "renesas,rcar-gen3-i2c";
+			reg = <0 0xe6508000 0 0x40>;
+			interrupts = <GIC_SPI 288 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 930>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 930>;
+			dmas = <&dmac1 0x93>, <&dmac1 0x92>,
+			       <&dmac2 0x93>, <&dmac2 0x92>;
+			dma-names = "tx", "rx", "tx", "rx";
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
+
+		i2c2: i2c@e6510000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a77995",
+				     "renesas,rcar-gen3-i2c";
+			reg = <0 0xe6510000 0 0x40>;
+			interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 929>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 929>;
+			dmas = <&dmac1 0x95>, <&dmac1 0x94>,
+			       <&dmac2 0x95>, <&dmac2 0x94>;
+			dma-names = "tx", "rx", "tx", "rx";
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
+
+		i2c3: i2c@e66d0000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "renesas,i2c-r8a77995",
+				     "renesas,rcar-gen3-i2c";
+			reg = <0 0xe66d0000 0 0x40>;
+			interrupts = <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 928>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 928>;
+			dmas = <&dmac0 0x97>, <&dmac0 0x96>;
+			dma-names = "tx", "rx";
+			i2c-scl-internal-delay-ns = <6>;
+			status = "disabled";
+		};
+
 		pwm0: pwm@e6e30000 {
 			compatible = "renesas,pwm-r8a77995", "renesas,pwm-rcar";
 			reg = <0 0xe6e30000 0 0x8>;
@@ -636,5 +691,105 @@
 			#phy-cells = <0>;
 			status = "disabled";
 		};
+
+		vspbs: vsp@fe960000 {
+			compatible = "renesas,vsp2";
+			reg = <0 0xfe960000 0 0x8000>;
+			interrupts = <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 627>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 627>;
+			renesas,fcp = <&fcpvb0>;
+		};
+
+		fcpvb0: fcp@fe96f000 {
+			compatible = "renesas,fcpv";
+			reg = <0 0xfe96f000 0 0x200>;
+			clocks = <&cpg CPG_MOD 607>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 607>;
+			iommus = <&ipmmu_vp0 5>;
+		};
+
+		vspd0: vsp@fea20000 {
+			compatible = "renesas,vsp2";
+			reg = <0 0xfea20000 0 0x8000>;
+			interrupts = <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 623>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 623>;
+			renesas,fcp = <&fcpvd0>;
+		};
+
+		fcpvd0: fcp@fea27000 {
+			compatible = "renesas,fcpv";
+			reg = <0 0xfea27000 0 0x200>;
+			clocks = <&cpg CPG_MOD 603>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 603>;
+			iommus = <&ipmmu_vi0 8>;
+		};
+
+		vspd1: vsp@fea28000 {
+			compatible = "renesas,vsp2";
+			reg = <0 0xfea28000 0 0x8000>;
+			interrupts = <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 622>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 622>;
+			renesas,fcp = <&fcpvd1>;
+		};
+
+		fcpvd1: fcp@fea2f000 {
+			compatible = "renesas,fcpv";
+			reg = <0 0xfea2f000 0 0x200>;
+			clocks = <&cpg CPG_MOD 602>;
+			power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
+			resets = <&cpg 602>;
+			iommus = <&ipmmu_vi0 9>;
+		};
+
+		du: display@feb00000 {
+			compatible = "renesas,du-r8a77995";
+			reg = <0 0xfeb00000 0 0x80000>;
+			interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&cpg CPG_MOD 724>,
+				 <&cpg CPG_MOD 723>;
+			clock-names = "du.0", "du.1";
+			vsps = <&vspd0 0 &vspd1 0>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					du_out_rgb: endpoint {
+					};
+				};
+
+				port@1 {
+					reg = <1>;
+					du_out_lvds0: endpoint {
+					};
+				};
+
+				port@2 {
+					reg = <2>;
+					du_out_lvds1: endpoint {
+					};
+				};
+			};
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>,
+				      <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_LOW)>;
 	};
 };
diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
index c3fafb6025b3..89cbb3b95acd 100644
--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
@@ -338,6 +338,13 @@
 &i2c4 {
 	status = "okay";
 
+	pca9654: gpio@20 {
+		compatible = "onnn,pca9654";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
 	csa_vdd: adc@7c {
 		compatible = "maxim,max9611";
 		reg = <0x7c>;
diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index ce2701e37d00..1e57f87f30c4 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rock64.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-roc-cc.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-geekbox.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-lion-haikou.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
new file mode 100644
index 000000000000..246c317f6a68
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2017 T-Chip Intelligent Technology Co., Ltd
+ */
+
+/dts-v1/;
+#include "rk3328.dtsi"
+
+/ {
+	model = "Firefly roc-rk3328-cc";
+	compatible = "firefly,roc-rk3328-cc", "rockchip,rk3328";
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	gmac_clkin: external-gmac-clock {
+		compatible = "fixed-clock";
+		clock-frequency = <125000000>;
+		clock-output-names = "gmac_clkin";
+		#clock-cells = <0>;
+	};
+
+	dc_12v: dc-12v {
+		compatible = "regulator-fixed";
+		regulator-name = "dc_12v";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc_sd: sdmmc-regulator {
+		compatible = "regulator-fixed";
+		gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc0m1_gpio>;
+		regulator-name = "vcc_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc_io>;
+	};
+
+	vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb20_host_drv>;
+		regulator-name = "vcc_host1_5v";
+		regulator-always-on;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vcc_sys: vcc-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&dc_12v>;
+	};
+
+	vcc_phy: vcc-phy-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_phy";
+		regulator-always-on;
+		regulator-boot-on;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&vdd_arm>;
+};
+
+&emmc {
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+	status = "okay";
+};
+
+&gmac2io {
+	assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
+	assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>;
+	clock_in_out = "input";
+	phy-supply = <&vcc_phy>;
+	phy-mode = "rgmii";
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmiim1_pins>;
+	snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 50000>;
+	tx_delay = <0x25>;
+	rx_delay = <0x11>;
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+
+	rk805: pmic@18 {
+		compatible = "rockchip,rk805";
+		reg = <0x18>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+		#clock-cells = <1>;
+		clock-output-names = "xin32k", "rk805-clkout2";
+		gpio-controller;
+		#gpio-cells = <2>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_int_l>;
+		rockchip,system-power-controller;
+		wakeup-source;
+
+		vcc1-supply = <&vcc_sys>;
+		vcc2-supply = <&vcc_sys>;
+		vcc3-supply = <&vcc_sys>;
+		vcc4-supply = <&vcc_sys>;
+		vcc5-supply = <&vcc_io>;
+		vcc6-supply = <&vcc_io>;
+
+		regulators {
+			vdd_logic: DCDC_REG1 {
+				regulator-name = "vdd_logic";
+				regulator-min-microvolt = <712500>;
+				regulator-max-microvolt = <1450000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1000000>;
+				};
+			};
+
+			vdd_arm: DCDC_REG2 {
+				regulator-name = "vdd_arm";
+				regulator-min-microvolt = <712500>;
+				regulator-max-microvolt = <1450000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <950000>;
+				};
+			};
+
+			vcc_ddr: DCDC_REG3 {
+				regulator-name = "vcc_ddr";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_io: DCDC_REG4 {
+				regulator-name = "vcc_io";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vcc_18: LDO_REG1 {
+				regulator-name = "vcc_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vcc18_emmc: LDO_REG2 {
+				regulator-name = "vcc18_emmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_10: LDO_REG3 {
+				regulator-name = "vdd_10";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1000000>;
+				};
+			};
+		};
+	};
+};
+
+&pinctrl {
+	pmic {
+		pmic_int_l: pmic-int-l {
+			rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb2 {
+		usb20_host_drv: usb20-host-drv {
+			rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>;
+	vmmc-supply = <&vcc_sd>;
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+
+&u2phy {
+	status = "okay";
+};
+
+&u2phy_host {
+	status = "okay";
+};
+
+&u2phy_otg {
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&usb20_otg {
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
index 3890468678ce..28257724a56e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
@@ -132,17 +132,16 @@
 	assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
 	assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>;
 	clock_in_out = "input";
-	/* shows instability at 1GBit right now */
-	max-speed = <100>;
 	phy-supply = <&vcc_io>;
 	phy-mode = "rgmii";
 	pinctrl-names = "default";
 	pinctrl-0 = <&rgmiim1_pins>;
+	snps,force_thresh_dma_mode;
 	snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
 	snps,reset-active-low;
 	snps,reset-delays-us = <0 10000 50000>;
-	tx_delay = <0x26>;
-	rx_delay = <0x11>;
+	tx_delay = <0x24>;
+	rx_delay = <0x18>;
 	status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index a037ee56fead..be2bfbc6b483 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -318,7 +318,7 @@
 		clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
 		clock-names = "baudclk", "apb_pclk";
 		dmas = <&dmac 2>, <&dmac 3>;
-		#dma-cells = <2>;
+		dma-names = "tx", "rx";
 		pinctrl-names = "default";
 		pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
 		reg-io-width = <4>;
@@ -333,7 +333,7 @@
 		clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
 		clock-names = "sclk_uart", "pclk_uart";
 		dmas = <&dmac 4>, <&dmac 5>;
-		#dma-cells = <2>;
+		dma-names = "tx", "rx";
 		pinctrl-names = "default";
 		pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>;
 		reg-io-width = <4>;
@@ -348,7 +348,7 @@
 		clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
 		clock-names = "baudclk", "apb_pclk";
 		dmas = <&dmac 6>, <&dmac 7>;
-		#dma-cells = <2>;
+		dma-names = "tx", "rx";
 		pinctrl-names = "default";
 		pinctrl-0 = <&uart2m1_xfer>;
 		reg-io-width = <4>;
@@ -730,7 +730,7 @@
 		interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
 			 <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		status = "disabled";
 	};
@@ -741,7 +741,7 @@
 		interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
 			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		status = "disabled";
 	};
@@ -752,7 +752,7 @@
 		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
 			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		status = "disabled";
 	};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
new file mode 100644
index 000000000000..fca8e87d8f52
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+/dts-v1/;
+#include "rk3368-lion.dtsi"
+
+/ {
+	model = "Theobroma Systems RK3368-uQ7 Baseboard";
+	compatible = "tsd,rk3368-lion-haikou", "rockchip,rk3368";
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	i2cmux2 {
+		i2c@0 {
+			eeprom: eeprom@50 {
+				compatible = "atmel,24c01";
+				pagesize = <8>;
+				reg = <0x50>;
+			};
+		};
+	};
+
+	leds {
+		pinctrl-0 = <&led_pins_module>, <&led_sd_haikou>;
+
+		sd-card-led {
+			label = "sd_card_led";
+			gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
+		};
+	};
+
+	dc_12v: dc-12v {
+		compatible = "regulator-fixed";
+		regulator-name = "dc_12v";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_baseboard: vcc3v3-baseboard {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_baseboard";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&dc_12v>;
+	};
+
+	vcc5v0_otg: vcc5v0-otg-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&otg_vbus_drv>;
+		regulator-name = "vcc5v0_otg";
+		regulator-always-on;
+	};
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio2 RK_PB3 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <25000000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;
+	rockchip,default-sample-phase = <90>;
+	vmmc-supply = <&vcc3v3_baseboard>;
+	status = "okay";
+};
+
+&spi2 {
+	cs-gpios = <0>, <&gpio2 RK_PC3 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
+	status = "okay";
+};
+
+&uart1 {
+	/* alternate function of GPIO5/6 */
+	status = "disabled";
+};
+
+&pinctrl {
+	pinctrl-names = "default";
+	pinctrl-0 = <&haikou_pin_hog>;
+
+	hog {
+		haikou_pin_hog: haikou-pin-hog {
+			rockchip,pins =
+				/* LID_BTN */
+				<RK_GPIO3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* BATLOW# */
+				<RK_GPIO0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* SLP_BTN# */
+				<RK_GPIO3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
+				/* BIOS_DISABLE# */
+				<RK_GPIO3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	leds {
+		led_sd_haikou: led-sd-gpio {
+			rockchip,pins =
+				<RK_GPIO0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	sdmmc {
+		sdmmc_cd_gpio: sdmmc-cd-gpio {
+			rockchip,pins =
+				<RK_GPIO2 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	usb_otg {
+		otg_vbus_drv: otg-vbus-drv {
+			rockchip,pins =
+				<RK_GPIO0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
new file mode 100644
index 000000000000..1315972412df
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+/dts-v1/;
+#include "rk3368.dtsi"
+
+/ {
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	ext_gmac: gmac-clk {
+		compatible = "fixed-clock";
+		clock-frequency = <125000000>;
+		clock-output-names = "ext_gmac";
+		#clock-cells = <0>;
+	};
+
+	i2cmux1 {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-parent = <&i2c1>;
+		mux-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
+
+		/* Q7_GPO_I2C */
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		/* Q7_SMB */
+		i2c@1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	i2cmux2 {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		i2c-parent = <&i2c2>;
+		mux-gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>;
+
+		/* Q7_LVDS_BLC_I2C */
+		i2c@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			fan: fan@18 {
+				compatible = "ti,amc6821";
+				reg = <0x18>;
+				cooling-min-state = <0>;
+				cooling-max-state = <9>;
+				#cooling-cells = <2>;
+			};
+
+			rtc_twi: rtc@6f {
+				compatible = "isil,isl1208";
+				reg = <0x6f>;
+			};
+		};
+
+		/* Q7_GP2_I2C */
+		i2c@1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_module>;
+
+		module_led1 {
+			label = "module_led1";
+			gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+			panic-indicator;
+		};
+
+		module_led2 {
+			label = "module_led2";
+			gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+	};
+
+	vcc_sys: vcc-sys-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_sys";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu>;
+};
+
+&emmc {
+	bus-width = <8>;
+	clock-frequency = <150000000>;
+	disable-wp;
+	mmc-hs200-1_8v;
+	non-removable;
+	vmmc-supply = <&vcc33_io>;
+	vqmmc-supply = <&vcc18_io>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_bus8>;
+	status = "okay";
+};
+
+&gmac {
+	assigned-clocks = <&cru SCLK_MAC>;
+	assigned-clock-parents = <&ext_gmac>;
+	clock_in_out = "input";
+	phy-supply = <&vcc33_io>;
+	phy-mode = "rgmii";
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 50000>;
+	snps,reset-gpio = <&gpio3 RK_PB3 GPIO_ACTIVE_HIGH>;
+	tx_delay = <0x10>;
+	rx_delay = <0x10>;
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	rk808: pmic@1b {
+		compatible = "rockchip,rk808";
+		reg = <0x1b>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
+		clock-output-names = "xin32k", "rk808-clkout2";
+		#clock-cells = <1>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_int_l>, <&pmic_sleep>;
+		rockchip,system-power-controller;
+		vcc1-supply = <&vcc_sys>;
+		vcc2-supply = <&vcc_sys>;
+		vcc3-supply = <&vcc_sys>;
+		vcc4-supply = <&vcc_sys>;
+		vcc6-supply = <&vcc_sys>;
+		vcc7-supply = <&vcc_sys>;
+		vcc8-supply = <&vcc_sys>;
+		vcc9-supply = <&vcc_sys>;
+		vcc10-supply = <&vcc_sys>;
+		vcc11-supply = <&vcc_sys>;
+		vcc12-supply = <&vcc_sys>;
+
+		regulators {
+			vdd_cpu: DCDC_REG1 {
+				regulator-name = "vdd_cpu";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vdd_log: DCDC_REG2 {
+				regulator-name = "vdd_log";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc_ddr: DCDC_REG3 {
+				regulator-name = "vcc_ddr";
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc33_io: DCDC_REG4 {
+				regulator-name = "vcc33_io";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc33_video: LDO_REG2 {
+				regulator-name = "vcc33_video";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vdd10_pll: LDO_REG3 {
+				regulator-name = "vdd10_pll";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc18_io: LDO_REG4 {
+				regulator-name = "vcc18_io";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-boot-on;
+			};
+
+			vdd10_video: LDO_REG6 {
+				regulator-name = "vdd10_video";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc18_video: LDO_REG8 {
+				regulator-name = "vcc18_video";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+		};
+	};
+};
+
+&i2c1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+};
+
+&pinctrl {
+	leds {
+		led_pins_module: led-module-gpio {
+			rockchip,pins =
+				<RK_GPIO2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>,
+				<RK_GPIO3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+	pmic {
+		pmic_int_l: pmic-int-l {
+			rockchip,pins = <RK_GPIO0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		pmic_sleep: pmic-sleep {
+			rockchip,pins = <RK_GPIO0 RK_PA0 RK_FUNC_2 &pcfg_pull_none>;
+		};
+	};
+};
+
+&spi1 {
+	status = "okay";
+
+	norflash: flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+	};
+};
+
+&uart1 {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&wdt {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index aa4d07046a7b..03458ac44201 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -257,7 +257,7 @@
 		max-frequency = <150000000>;
 		clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>,
 			 <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>;
-		clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+		clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
 		fifo-depth = <0x100>;
 		interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
 		resets = <&cru SRST_SDIO0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 03f195025390..6e50768a34ce 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -515,10 +515,15 @@
 		compatible = "rockchip,rk3399-gru-sound";
 		rockchip,cpu = <&i2s0 &i2s2>;
 		rockchip,codec = <&max98357a &headsetcodec
-				  &codec &wacky_spi_audio>;
+				  &codec &wacky_spi_audio &cdn_dp>;
 	};
 };
 
+&cdn_dp {
+	status = "okay";
+	extcon = <&usbc_extcon0>, <&usbc_extcon1>;
+};
+
 /*
  * Set some suspend operating points to avoid OVP in suspend
  *
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
index 9a7486058455..7d3e8bfd51dd 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
@@ -61,6 +61,30 @@
 		};
 	};
 
+	i2s0-sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,name = "Haikou,I2S-codec";
+		simple-audio-card,mclk-fs = <512>;
+
+		simple-audio-card,codec {
+			clocks = <&sgtl5000_clk>;
+			sound-dai = <&sgtl5000>;
+		};
+
+		simple-audio-card,cpu {
+			bitclock-master;
+			frame-master;
+			sound-dai = <&i2s0>;
+		};
+	};
+
+	sgtl5000_clk: sgtl5000-oscillator  {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency  = <24576000>;
+	};
+
 	dc_12v: dc-12v {
 		compatible = "regulator-fixed";
 		regulator-name = "dc_12v";
@@ -80,6 +104,16 @@
 		vin-supply = <&dc_12v>;
 	};
 
+	vcc5v0_baseboard: vcc5v0-baseboard {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_baseboard";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&dc_12v>;
+	};
+
 	vcc5v0_otg: vcc5v0-otg-regulator {
 		compatible = "regulator-fixed";
 		enable-active-high;
@@ -89,6 +123,24 @@
 		regulator-name = "vcc5v0_otg";
 		regulator-always-on;
 	};
+
+	vdda_codec: vdda-codec {
+		compatible = "regulator-fixed";
+		regulator-name = "vdda_codec";
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc5v0_baseboard>;
+	};
+
+	vddd_codec: vddd-codec {
+		compatible = "regulator-fixed";
+		regulator-name = "vddd_codec";
+		regulator-boot-on;
+		regulator-min-microvolt = <1600000>;
+		regulator-max-microvolt = <1600000>;
+		vin-supply = <&vcc5v0_baseboard>;
+	};
 };
 
 &i2c1 {
@@ -110,6 +162,17 @@
 &i2c4 {
 	status = "okay";
 	clock-frequency = <400000>;
+
+	sgtl5000: codec@0a {
+		compatible = "fsl,sgtl5000";
+		reg = <0x0a>;
+		clocks = <&sgtl5000_clk>;
+		#sound-dai-cells = <0>;
+		VDDA-supply = <&vdda_codec>;
+		VDDIO-supply = <&vdda_codec>;
+		VDDD-supply = <&vddd_codec>;
+		status = "okay";
+	};
 };
 
 &i2c6 {
@@ -117,14 +180,6 @@
 	clock-frequency = <400000>;
 };
 
-&i2s0 {
-	status = "okay";
-	rockchip,playback-channels = <8>;
-	rockchip,capture-channels = <8>;
-	#sound-dai-cells = <0>;
-	status = "okay";
-};
-
 &pcie_phy {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
index 1fc5060d7027..4a2d06abe9c1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
@@ -435,6 +435,28 @@
 	};
 };
 
+&i2s0 {
+	pinctrl-0 = <&i2s0_2ch_bus>;
+	rockchip,playback-channels = <2>;
+	rockchip,capture-channels = <2>;
+	#sound-dai-cells = <0>;
+	status = "okay";
+};
+
+/*
+ * As Q7 does not specify neither a global nor a RX clock for I2S these
+ * signals are not used. Furthermore I2S0_LRCK_RX is used as GPIO.
+ * Therefore we have to redefine the i2s0_2ch_bus definition to prevent
+ * conflicts.
+ */
+&i2s0_2ch_bus {
+	rockchip,pins =
+		<RK_GPIO3 RK_PD0 RK_FUNC_1 &pcfg_pull_none>,
+		<RK_GPIO3 RK_PD2 RK_FUNC_1 &pcfg_pull_none>,
+		<RK_GPIO3 RK_PD3 RK_FUNC_1 &pcfg_pull_none>,
+		<RK_GPIO3 RK_PD7 RK_FUNC_1 &pcfg_pull_none>;
+};
+
 &io_domains {
 	status = "okay";
 	bt656-supply = <&vcc_1v8>;
@@ -505,6 +527,12 @@
 	};
 };
 
+&tsadc {
+	rockchip,hw-tshut-mode = <1>;
+	rockchip,hw-tshut-polarity = <1>;
+	status = "okay";
+};
+
 &u2phy1 {
 	status = "okay";
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
index 0f873c897d0d..f7bfa70fce68 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
@@ -143,6 +143,17 @@
 		regulator-always-on;
 		vin-supply = <&vcc_sys>;
 	};
+
+	vdd_log: vdd-log {
+		compatible = "pwm-regulator";
+		pwms = <&pwm2 0 25000 1>;
+		regulator-name = "vdd_log";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <800000>;
+		regulator-max-microvolt = <1400000>;
+		vin-supply = <&vcc_sys>;
+	};
 };
 
 &cpu_l0 {
@@ -421,17 +432,6 @@
 			regulator-off-in-suspend;
 		};
 	};
-
-	vdd_log: vdd-log {
-		compatible = "pwm-regulator";
-		pwms = <&pwm2 0 25000 1>;
-		regulator-name = "vdd_log";
-		regulator-always-on;
-		regulator-boot-on;
-		regulator-min-microvolt = <800000>;
-		regulator-max-microvolt = <1400000>;
-		vin-supply = <&vcc_sys>;
-	};
 };
 
 &i2c3 {
@@ -457,7 +457,7 @@
 	assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
 	assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
 	assigned-clock-rates = <100000000>;
-	ep-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>;
+	ep-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
 	num-lanes = <4>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie_clkreqn_cpm>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 7aa2144e0d47..da0078eda485 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -457,6 +457,42 @@
 		};
 	};
 
+	cdn_dp: dp@fec00000 {
+		compatible = "rockchip,rk3399-cdn-dp";
+		reg = <0x0 0xfec00000 0x0 0x100000>;
+		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH 0>;
+		assigned-clocks = <&cru SCLK_DP_CORE>;
+		assigned-clock-rates = <100000000>;
+		clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
+			 <&cru SCLK_SPDIF_REC_DPTX>, <&cru PCLK_VIO_GRF>;
+		clock-names = "core-clk", "pclk", "spdif", "grf";
+		phys = <&tcphy0_dp>, <&tcphy1_dp>;
+		power-domains = <&power RK3399_PD_HDCP>;
+		resets = <&cru SRST_DPTX_SPDIF_REC>, <&cru SRST_P_UPHY0_DPTX>,
+			 <&cru SRST_P_UPHY0_APB>, <&cru SRST_DP_CORE>;
+		reset-names = "spdif", "dptx", "apb", "core";
+		rockchip,grf = <&grf>;
+		#sound-dai-cells = <1>;
+		status = "disabled";
+
+		ports {
+			dp_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				dp_in_vopb: endpoint@0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_dp>;
+				};
+
+				dp_in_vopl: endpoint@1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_dp>;
+				};
+			};
+		};
+	};
+
 	gic: interrupt-controller@fee00000 {
 		compatible = "arm,gic-v3";
 		#interrupt-cells = <4>;
@@ -1547,6 +1583,11 @@
 				reg = <3>;
 				remote-endpoint = <&mipi1_in_vopl>;
 			};
+
+			vopl_out_dp: endpoint@4 {
+				reg = <4>;
+				remote-endpoint = <&dp_in_vopl>;
+			};
 		};
 	};
 
@@ -1599,6 +1640,11 @@
 				reg = <3>;
 				remote-endpoint = <&mipi1_in_vopb>;
 			};
+
+			vopb_out_dp: endpoint@4 {
+				reg = <4>;
+				remote-endpoint = <&dp_in_vopb>;
+			};
 		};
 	};
 
@@ -1739,8 +1785,8 @@
 		compatible = "rockchip,rk3399-edp";
 		reg = <0x0 0xff970000 0x0 0x8000>;
 		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH 0>;
-		clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>;
-		clock-names = "dp", "pclk";
+		clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>, <&cru PCLK_VIO_GRF>;
+		clock-names = "dp", "pclk", "grf";
 		pinctrl-names = "default";
 		pinctrl-0 = <&edp_hpd>;
 		power-domains = <&power RK3399_PD_EDP>;
@@ -2043,6 +2089,16 @@
 		};
 
 		i2s0 {
+			i2s0_2ch_bus: i2s0-2ch-bus {
+				rockchip,pins =
+					<3 24 RK_FUNC_1 &pcfg_pull_none>,
+					<3 25 RK_FUNC_1 &pcfg_pull_none>,
+					<3 26 RK_FUNC_1 &pcfg_pull_none>,
+					<3 27 RK_FUNC_1 &pcfg_pull_none>,
+					<3 31 RK_FUNC_1 &pcfg_pull_none>,
+					<4 0 RK_FUNC_1 &pcfg_pull_none>;
+			};
+
 			i2s0_8ch_bus: i2s0-8ch-bus {
 				rockchip,pins =
 					<3 24 RK_FUNC_1 &pcfg_pull_none>,
@@ -2293,6 +2349,23 @@
 			};
 		};
 
+		testclk {
+			test_clkout0: test-clkout0 {
+				rockchip,pins =
+					<0 0 RK_FUNC_1 &pcfg_pull_none>;
+			};
+
+			test_clkout1: test-clkout1 {
+				rockchip,pins =
+					<2 25 RK_FUNC_2 &pcfg_pull_none>;
+			};
+
+			test_clkout2: test-clkout2 {
+				rockchip,pins =
+					<0 8 RK_FUNC_3 &pcfg_pull_none>;
+			};
+		};
+
 		tsadc {
 			otp_gpio: otp-gpio {
 				rockchip,pins = <1 6 RK_FUNC_GPIO &pcfg_pull_none>;
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 634b373785c4..09f8f19ca8fa 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -52,6 +52,7 @@ CONFIG_ARCH_RENESAS=y
 CONFIG_ARCH_R8A7795=y
 CONFIG_ARCH_R8A7796=y
 CONFIG_ARCH_R8A77970=y
+CONFIG_ARCH_R8A77980=y
 CONFIG_ARCH_R8A77995=y
 CONFIG_ARCH_STRATIX10=y
 CONFIG_ARCH_TEGRA=y
@@ -562,6 +563,7 @@ CONFIG_PHY_XGENE=y
 CONFIG_PHY_TEGRA_XUSB=y
 CONFIG_QCOM_L2_PMU=y
 CONFIG_QCOM_L3_PMU=y
+CONFIG_MESON_EFUSE=m
 CONFIG_UNIPHIER_EFUSE=y
 CONFIG_TEE=y
 CONFIG_OPTEE=y
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
index 68096e8f787f..c0038eeb9e29 100644
--- a/arch/blackfin/kernel/bfin_ksyms.c
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(memchr);
 /*
  * Because string functions are both inline and exported functions and
  * folder arch/blackfin/lib is configured as a library path in Makefile,
- * symbols exported in folder lib  is not linked into built-in.o but
+ * symbols exported in folder lib  is not linked into built-in.a but
  * inlined only. In order to export string symbols to kernel module
  * properly, they should be exported here.
  */
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c
index cff57764fcad..0f8fde494875 100644
--- a/arch/c6x/kernel/asm-offsets.c
+++ b/arch/c6x/kernel/asm-offsets.c
@@ -107,7 +107,6 @@ void foo(void)
 	/* These would be unneccessary if we ran asm files
 	 * through the preprocessor.
 	 */
-	DEFINE(KTHREAD_SIZE, THREAD_SIZE);
 	DEFINE(KTHREAD_SHIFT, THREAD_SHIFT);
 	DEFINE(KTHREAD_START_SP, THREAD_START_SP);
 	DEFINE(ENOSYS_, ENOSYS);
diff --git a/arch/c6x/platforms/plldata.c b/arch/c6x/platforms/plldata.c
index e8b6cc6a7b5a..1ef04b5ab93f 100644
--- a/arch/c6x/platforms/plldata.c
+++ b/arch/c6x/platforms/plldata.c
@@ -19,6 +19,7 @@
 
 #include <asm/clock.h>
 #include <asm/setup.h>
+#include <asm/special_insns.h>
 #include <asm/irq.h>
 
 /*
diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
index 925a98eb6d68..7ec29d2d3661 100644
--- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (c) 2007
  *
- *  Derived from drivers/mtd/nand/spia.c
+ *  Derived from drivers/mtd/nand/spia.c (removed in v3.8)
  *	  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
index 53b56a429dde..7ce72906039a 100644
--- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
+++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (c) 2004
  *
- *  Derived from drivers/mtd/nand/spia.c
+ *  Derived from drivers/mtd/nand/spia.c (removed in v3.8)
  *	  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/arch/cris/include/arch-v10/arch/bug.h b/arch/cris/include/arch-v10/arch/bug.h
index 905afeacfedf..06da9d49152a 100644
--- a/arch/cris/include/arch-v10/arch/bug.h
+++ b/arch/cris/include/arch-v10/arch/bug.h
@@ -44,18 +44,25 @@ struct bug_frame {
  * not be used like this with newer versions of gcc.
  */
 #define BUG()								\
+do {									\
 	__asm__ __volatile__ ("clear.d [" __stringify(BUG_MAGIC) "]\n\t"\
 			      "movu.w " __stringify(__LINE__) ",$r0\n\t"\
 			      "jump 0f\n\t"				\
 			      ".section .rodata\n"			\
 			      "0:\t.string \"" __FILE__ "\"\n\t"	\
-			      ".previous")
+			      ".previous");				\
+	unreachable();							\
+} while (0)
 #endif
 
 #else
 
 /* This just causes an oops. */
-#define BUG() (*(int *)0 = 0)
+#define BUG()								\
+do {									\
+	barrier_before_unreachable();					\
+	__builtin_trap();						\
+} while (0)
 
 #endif
 
diff --git a/arch/ia64/include/asm/bug.h b/arch/ia64/include/asm/bug.h
index bd3eeb8d1cfa..66b37a532765 100644
--- a/arch/ia64/include/asm/bug.h
+++ b/arch/ia64/include/asm/bug.h
@@ -4,7 +4,11 @@
 
 #ifdef CONFIG_BUG
 #define ia64_abort()	__builtin_trap()
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
+#define BUG() do {						\
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__);	\
+	barrier_before_unreachable();				\
+	ia64_abort();						\
+} while (0)
 
 /* should this BUG be made generic? */
 #define HAVE_ARCH_BUG
diff --git a/arch/m68k/include/asm/bug.h b/arch/m68k/include/asm/bug.h
index b7e2bf1ba4a6..275dca1435bf 100644
--- a/arch/m68k/include/asm/bug.h
+++ b/arch/m68k/include/asm/bug.h
@@ -8,16 +8,19 @@
 #ifndef CONFIG_SUN3
 #define BUG() do { \
 	pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	barrier_before_unreachable(); \
 	__builtin_trap(); \
 } while (0)
 #else
 #define BUG() do { \
 	pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	barrier_before_unreachable(); \
 	panic("BUG!"); \
 } while (0)
 #endif
 #else
 #define BUG() do { \
+	barrier_before_unreachable(); \
 	__builtin_trap(); \
 } while (0)
 #endif
diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c
index 0909834c83a7..0cca2c95a091 100644
--- a/arch/metag/kernel/process.c
+++ b/arch/metag/kernel/process.c
@@ -399,7 +399,7 @@ unsigned long __metag_elf_map(struct file *filep, unsigned long addr,
 	tcm_tag = tcm_lookup_tag(addr);
 
 	if (tcm_tag != TCM_INVALID_TAG)
-		type &= ~MAP_FIXED;
+		type &= ~(MAP_FIXED | MAP_FIXED_NOREPLACE);
 
 	/*
 	* total_size is the size of the ELF (interpreter) image.
@@ -417,6 +417,10 @@ unsigned long __metag_elf_map(struct file *filep, unsigned long addr,
 	} else
 		map_addr = vm_mmap(filep, addr, size, prot, type, off);
 
+	if ((type & MAP_FIXED_NOREPLACE) && BAD_ADDR(map_addr))
+		pr_info("%d (%s): Uhuuh, elf segment at %p requested but the memory is mapped already\n",
+				task_pid_nr(current), current->comm, (void *)addr);
+
 	if (!BAD_ADDR(map_addr) && tcm_tag != TCM_INVALID_TAG) {
 		struct tcm_allocation *tcm;
 		unsigned long tcm_addr;
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8128c3b68d6b..79cf7ac918b8 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2028,6 +2028,7 @@ config CPU_MIPSR6
 	select CPU_HAS_RIXI
 	select HAVE_ARCH_BITREVERSE
 	select MIPS_ASID_BITS_VARIABLE
+	select MIPS_CRC_SUPPORT
 	select MIPS_SPRAM
 
 config EVA
@@ -2501,6 +2502,9 @@ config MIPS_ASID_BITS
 config MIPS_ASID_BITS_VARIABLE
 	bool
 
+config MIPS_CRC_SUPPORT
+	bool
+
 #
 # - Highmem only makes sense for the 32-bit kernel.
 # - The current highmem code will only work properly on physically indexed
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index d1ca839c3981..44a6ed53d018 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -222,6 +222,8 @@ xpa-cflags-y				:= $(mips-cflags)
 xpa-cflags-$(micromips-ase)		+= -mmicromips -Wa$(comma)-fatal-warnings
 toolchain-xpa				:= $(call cc-option-yn,$(xpa-cflags-y) -mxpa)
 cflags-$(toolchain-xpa)			+= -DTOOLCHAIN_SUPPORTS_XPA
+toolchain-crc				:= $(call cc-option-yn,$(mips-cflags) -Wa$(comma)-mcrc)
+cflags-$(toolchain-crc)			+= -DTOOLCHAIN_SUPPORTS_CRC
 
 #
 # Firmware support
@@ -330,6 +332,7 @@ libs-y			+= arch/mips/math-emu/
 # See arch/mips/Kbuild for content of core part of the kernel
 core-y += arch/mips/
 
+drivers-$(CONFIG_MIPS_CRC_SUPPORT) += arch/mips/crypto/
 drivers-$(CONFIG_OPROFILE)	+= arch/mips/oprofile/
 
 # suspend and hibernation support
diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c
index 328d697e72b4..4e79dbd54a33 100644
--- a/arch/mips/alchemy/board-gpr.c
+++ b/arch/mips/alchemy/board-gpr.c
@@ -190,7 +190,7 @@ static struct platform_device gpr_mtd_device = {
 /*
  * LEDs
  */
-static struct gpio_led gpr_gpio_leds[] = {
+static const struct gpio_led gpr_gpio_leds[] = {
 	{	/* green */
 		.name			= "gpr:green",
 		.gpio			= 4,
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c
index 85bb75669b0d..aab55aaf3d62 100644
--- a/arch/mips/alchemy/board-mtx1.c
+++ b/arch/mips/alchemy/board-mtx1.c
@@ -145,7 +145,7 @@ static struct platform_device mtx1_wdt = {
 	.resource = mtx1_wdt_res,
 };
 
-static struct gpio_led default_leds[] = {
+static const struct gpio_led default_leds[] = {
 	{
 		.name	= "mtx1:green",
 		.gpio = 211,
diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c
index 433c4b9a9f0a..13e3c84859fe 100644
--- a/arch/mips/alchemy/devboards/db1000.c
+++ b/arch/mips/alchemy/devboards/db1000.c
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/leds.h>
@@ -447,9 +448,6 @@ static struct ads7846_platform_data db1100_touch_pd = {
 };
 
 static struct spi_gpio_platform_data db1100_spictl_pd = {
-	.sck		= 209,
-	.mosi		= 208,
-	.miso		= 207,
 	.num_chipselect = 1,
 };
 
@@ -462,7 +460,6 @@ static struct spi_board_info db1100_spi_info[] __initdata = {
 		.mode		 = 0,
 		.irq		 = AU1100_GPIO21_INT,
 		.platform_data	 = &db1100_touch_pd,
-		.controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */
 	},
 };
 
@@ -474,6 +471,24 @@ static struct platform_device db1100_spi_dev = {
 	},
 };
 
+/*
+ * Alchemy GPIO 2 has its base at 200 so the GPIO lines
+ * 207 thru 210 are GPIOs at offset 7 thru 10 at this chip.
+ */
+static struct gpiod_lookup_table db1100_spi_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("alchemy-gpio2", 9,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("alchemy-gpio2", 8,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("alchemy-gpio2", 7,
+			    "miso", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("alchemy-gpio2", 10,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
 
 static struct platform_device *db1x00_devs[] = {
 	&db1x00_codec_dev,
@@ -541,6 +556,7 @@ int __init db1000_dev_setup(void)
 			clk_put(p);
 
 		platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
+		gpiod_add_lookup_table(&db1100_spi_gpiod_table);
 		platform_device_register(&db1100_spi_dev);
 	} else if (board == BCSR_WHOAMI_DB1000) {
 		c0 = AU1000_GPIO2_INT;
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
index e1675c25d5d4..f09262e0a72f 100644
--- a/arch/mips/ar7/platform.c
+++ b/arch/mips/ar7/platform.c
@@ -346,7 +346,7 @@ static struct platform_device ar7_udc = {
 /*****************************************************************************
  * LEDs
  ****************************************************************************/
-static struct gpio_led default_leds[] = {
+static const struct gpio_led default_leds[] = {
 	{
 		.name			= "status",
 		.gpio			= 8,
@@ -354,12 +354,12 @@ static struct gpio_led default_leds[] = {
 	},
 };
 
-static struct gpio_led titan_leds[] = {
+static const struct gpio_led titan_leds[] = {
 	{ .name = "status", .gpio = 8, .active_low = 1, },
 	{ .name = "wifi", .gpio = 13, .active_low = 1, },
 };
 
-static struct gpio_led dsl502t_leds[] = {
+static const struct gpio_led dsl502t_leds[] = {
 	{
 		.name			= "status",
 		.gpio			= 9,
@@ -377,7 +377,7 @@ static struct gpio_led dsl502t_leds[] = {
 	},
 };
 
-static struct gpio_led dg834g_leds[] = {
+static const struct gpio_led dg834g_leds[] = {
 	{
 		.name			= "ppp",
 		.gpio			= 6,
@@ -406,7 +406,7 @@ static struct gpio_led dg834g_leds[] = {
 	},
 };
 
-static struct gpio_led fb_sl_leds[] = {
+static const struct gpio_led fb_sl_leds[] = {
 	{
 		.name			= "1",
 		.gpio			= 7,
@@ -433,7 +433,7 @@ static struct gpio_led fb_sl_leds[] = {
 	},
 };
 
-static struct gpio_led fb_fon_leds[] = {
+static const struct gpio_led fb_fon_leds[] = {
 	{
 		.name			= "1",
 		.gpio			= 8,
@@ -459,7 +459,7 @@ static struct gpio_led fb_fon_leds[] = {
 	},
 };
 
-static struct gpio_led gt701_leds[] = {
+static const struct gpio_led gt701_leds[] = {
 	{
 		.name			= "inet:green",
 		.gpio			= 13,
diff --git a/arch/mips/boot/dts/img/boston.dts b/arch/mips/boot/dts/img/boston.dts
index 2cd49b60e030..1bd105428f61 100644
--- a/arch/mips/boot/dts/img/boston.dts
+++ b/arch/mips/boot/dts/img/boston.dts
@@ -157,7 +157,7 @@
 					#address-cells = <1>;
 					#size-cells = <0>;
 
-					rtc@0x68 {
+					rtc@68 {
 						compatible = "st,m41t81s";
 						reg = <0x68>;
 					};
diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index a4cc52214dbd..38078594cf97 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -110,22 +110,22 @@
 					reg = <0x0 0x0 0x0 0x800000>;
 				};
 
-				partition@0x800000 {
+				partition@800000 {
 					label = "u-boot";
 					reg = <0x0 0x800000 0x0 0x200000>;
 				};
 
-				partition@0xa00000 {
+				partition@a00000 {
 					label = "u-boot-env";
 					reg = <0x0 0xa00000 0x0 0x200000>;
 				};
 
-				partition@0xc00000 {
+				partition@c00000 {
 					label = "boot";
 					reg = <0x0 0xc00000 0x0 0x4000000>;
 				};
 
-				partition@0x8c00000 {
+				partition@4c00000 {
 					label = "system";
 					reg = <0x0 0x4c00000 0x1 0xfb400000>;
 				};
diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig
index b5eee1a57d6c..a283b73b7fc6 100644
--- a/arch/mips/cavium-octeon/Kconfig
+++ b/arch/mips/cavium-octeon/Kconfig
@@ -11,21 +11,26 @@ config CAVIUM_CN63XXP1
 	  non-CN63XXP1 hardware, so it is recommended to select "n"
 	  unless it is known the workarounds are needed.
 
-config CAVIUM_OCTEON_CVMSEG_SIZE
-	int "Number of L1 cache lines reserved for CVMSEG memory"
-	range 0 54
-	default 1
-	help
-	  CVMSEG LM is a segment that accesses portions of the dcache as a
-	  local memory; the larger CVMSEG is, the smaller the cache is.
-	  This selects the size of CVMSEG LM, which is in cache blocks. The
-	  legally range is from zero to 54 cache blocks (i.e. CVMSEG LM is
-	  between zero and 6192 bytes).
-
 endif # CPU_CAVIUM_OCTEON
 
 if CAVIUM_OCTEON_SOC
 
+config CAVIUM_OCTEON_EXTRA_CVMSEG
+	int "Number of extra L1 cache lines reserved for CVMSEG memory"
+	range 0 50
+	default 0
+	help
+	  CVMSEG LM is a segment that accesses portions of the dcache
+	  as a local memory; the larger CVMSEG is, the smaller the
+	  cache is.  The kernel uses two or three blocks (one for TLB
+	  exception handlers, one for driver IOBDMA operations, and on
+	  models that need it, one for LMTDMA operations). This
+	  selects an optional extra number of CVMSEG lines for use by
+	  other software.
+
+	  Normally no extra lines are required, and this parameter
+	  should be set to zero.
+
 config CAVIUM_OCTEON_LOCK_L2
 	bool "Lock often used kernel code in the L2"
 	default "y"
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 7c02e542959a..28c0bb75d1a4 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -10,6 +10,7 @@
 #
 
 obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
+obj-y += resource-mgr.o
 obj-y += dma-octeon.o
 obj-y += octeon-memcpy.o
 obj-y += executive/
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 5b3a3f6a9ad3..b993d9f2c9b9 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -2271,7 +2271,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node,
 
 	parent_irq = irq_of_parse_and_map(ciu_node, 0);
 	if (!parent_irq) {
-		pr_err("ERROR: Couldn't acquire parent_irq for %s\n.",
+		pr_err("ERROR: Couldn't acquire parent_irq for %s\n",
 			ciu_node->name);
 		return -EINVAL;
 	}
@@ -2281,7 +2281,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node,
 
 	addr = of_get_address(ciu_node, 0, NULL, NULL);
 	if (!addr) {
-		pr_err("ERROR: Couldn't acquire reg(0) %s\n.", ciu_node->name);
+		pr_err("ERROR: Couldn't acquire reg(0) %s\n", ciu_node->name);
 		return -EINVAL;
 	}
 	host_data->raw_reg = (u64)phys_to_virt(
@@ -2289,7 +2289,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node,
 
 	addr = of_get_address(ciu_node, 1, NULL, NULL);
 	if (!addr) {
-		pr_err("ERROR: Couldn't acquire reg(1) %s\n.", ciu_node->name);
+		pr_err("ERROR: Couldn't acquire reg(1) %s\n", ciu_node->name);
 		return -EINVAL;
 	}
 	host_data->en_reg = (u64)phys_to_virt(
@@ -2297,7 +2297,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node,
 
 	r = of_property_read_u32(ciu_node, "cavium,max-bits", &val);
 	if (r) {
-		pr_err("ERROR: Couldn't read cavium,max-bits from %s\n.",
+		pr_err("ERROR: Couldn't read cavium,max-bits from %s\n",
 			ciu_node->name);
 		return r;
 	}
@@ -2307,7 +2307,7 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node,
 					   &octeon_irq_domain_cib_ops,
 					   host_data);
 	if (!cib_domain) {
-		pr_err("ERROR: Couldn't irq_domain_add_linear()\n.");
+		pr_err("ERROR: Couldn't irq_domain_add_linear()\n");
 		return -ENOMEM;
 	}
 
diff --git a/arch/mips/cavium-octeon/resource-mgr.c b/arch/mips/cavium-octeon/resource-mgr.c
new file mode 100644
index 000000000000..74efda5420ff
--- /dev/null
+++ b/arch/mips/cavium-octeon/resource-mgr.c
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Resource manager for Octeon.
+ *
+ * Copyright (C) 2017 Cavium, Inc.
+ */
+#include <linux/module.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-bootmem.h>
+
+#define RESOURCE_MGR_BLOCK_NAME		"cvmx-global-resources"
+#define MAX_RESOURCES			128
+#define INST_AVAILABLE			-88
+#define OWNER				0xbadc0de
+
+struct global_resource_entry {
+	struct global_resource_tag tag;
+	u64 phys_addr;
+	u64 size;
+};
+
+struct global_resources {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	u32 rlock;
+	u32 pad;
+#else
+	u32 pad;
+	u32 rlock;
+#endif
+	u64 entry_cnt;
+	struct global_resource_entry resource_entry[];
+};
+
+static struct global_resources *res_mgr_info;
+
+
+/*
+ * The resource manager interacts with software running outside of the
+ * Linux kernel, which necessitates locking to maintain data structure
+ * consistency.  These custom locking functions implement the locking
+ * protocol, and cannot be replaced by kernel locking functions that
+ * may use different in-memory structures.
+ */
+
+static void res_mgr_lock(void)
+{
+	while (cmpxchg(&res_mgr_info->rlock, 0, 1))
+		; /* Loop while not zero */
+	rmb();
+}
+
+static void res_mgr_unlock(void)
+{
+	/* Wait until all resource operations finish before unlocking. */
+	wmb();
+	WRITE_ONCE(res_mgr_info->rlock, 0);
+	/* Force a write buffer flush. */
+	wmb();
+}
+
+static int res_mgr_find_resource(struct global_resource_tag tag)
+{
+	struct global_resource_entry *res_entry;
+	int i;
+
+	for (i = 0; i < res_mgr_info->entry_cnt; i++) {
+		res_entry = &res_mgr_info->resource_entry[i];
+		if (res_entry->tag.lo == tag.lo && res_entry->tag.hi == tag.hi)
+			return i;
+	}
+	return -1;
+}
+
+/**
+ * res_mgr_create_resource() - Create a resource.
+ * @tag: Identifies the resource.
+ * @inst_cnt: Number of resource instances to create.
+ *
+ * Returns 0 if the source was created successfully.
+ * Returns < 0 for error codes.
+ */
+int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt)
+{
+	struct global_resource_entry *res_entry;
+	u64 size;
+	u64 *res_addr;
+	int res_index, i, rc = 0;
+
+	res_mgr_lock();
+
+	/* Make sure resource doesn't already exist. */
+	res_index = res_mgr_find_resource(tag);
+	if (res_index >= 0) {
+		rc = -EEXIST;
+		goto err;
+	}
+
+	if (res_mgr_info->entry_cnt >= MAX_RESOURCES) {
+		pr_err("Resource max limit reached, not created\n");
+		rc = -ENOSPC;
+		goto err;
+	}
+
+	/*
+	 * Each instance is kept in an array of u64s. The first array element
+	 * holds the number of allocated instances.
+	 */
+	size = sizeof(u64) * (inst_cnt + 1);
+	res_addr = cvmx_bootmem_alloc_range(size, CVMX_CACHE_LINE_SIZE, 0, 0);
+	if (!res_addr) {
+		pr_err("Failed to allocate resource. not created\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	/* Initialize the newly created resource. */
+	*res_addr = inst_cnt;
+	for (i = 1; i <= inst_cnt; i++)
+		res_addr[i] = INST_AVAILABLE;
+
+	res_index = res_mgr_info->entry_cnt;
+	res_entry = &res_mgr_info->resource_entry[res_index];
+	res_entry->tag = tag;
+	res_entry->phys_addr = virt_to_phys(res_addr);
+	res_entry->size = size;
+	res_mgr_info->entry_cnt++;
+
+err:
+	res_mgr_unlock();
+
+	return rc;
+}
+EXPORT_SYMBOL(res_mgr_create_resource);
+
+/**
+ * res_mgr_alloc_range() - Allocate a range of resource instances.
+ * @tag: Identifies the resource.
+ * @req_inst: Requested start of instance range to allocate.
+ *	      Range instances are guaranteed to be sequential
+ *	      (-1 for don't care).
+ * @req_cnt: Number of instances to allocate.
+ * @use_last_avail: Set to request the last available instance.
+ * @inst: Updated with the allocated instances.
+ *
+ * Returns 0 if the source was created successfully.
+ * Returns < 0 for error codes.
+ */
+int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
+			int req_cnt, bool use_last_avail, int *inst)
+{
+	struct global_resource_entry *res_entry;
+	int res_index;
+	u64 *res_addr;
+	u64 inst_cnt;
+	int alloc_cnt, i, rc = -ENOENT;
+
+	/* Start with no instances allocated. */
+	for (i = 0; i < req_cnt; i++)
+		inst[i] = INST_AVAILABLE;
+
+	res_mgr_lock();
+
+	/* Find the resource. */
+	res_index = res_mgr_find_resource(tag);
+	if (res_index < 0) {
+		pr_err("Resource not found, can't allocate instance\n");
+		goto err;
+	}
+
+	/* Get resource data. */
+	res_entry = &res_mgr_info->resource_entry[res_index];
+	res_addr = phys_to_virt(res_entry->phys_addr);
+	inst_cnt = *res_addr;
+
+	/* Allocate the requested instances. */
+	if (req_inst >= 0) {
+		/* Specific instance range requested. */
+		if (req_inst + req_cnt >= inst_cnt) {
+			pr_err("Requested instance out of range\n");
+			goto err;
+		}
+
+		for (i = 0; i < req_cnt; i++) {
+			if (*(res_addr + req_inst + 1 + i) == INST_AVAILABLE) {
+				inst[i] = req_inst + i;
+			} else {
+				inst[0] = INST_AVAILABLE;
+				break;
+			}
+		}
+	} else if (use_last_avail) {
+		/* Last available instance requested. */
+		alloc_cnt = 0;
+		for (i = inst_cnt; i > 0; i--) {
+			if (*(res_addr + i) == INST_AVAILABLE) {
+				/*
+				 * Instance off by 1 (first element holds the
+				 * count).
+				 */
+				inst[alloc_cnt] = i - 1;
+
+				alloc_cnt++;
+				if (alloc_cnt == req_cnt)
+					break;
+			}
+		}
+
+		if (i == 0)
+			inst[0] = INST_AVAILABLE;
+	} else {
+		/* Next available instance requested. */
+		alloc_cnt = 0;
+		for (i = 1; i <= inst_cnt; i++) {
+			if (*(res_addr + i) == INST_AVAILABLE) {
+				/*
+				 * Instance off by 1 (first element holds the
+				 * count).
+				 */
+				inst[alloc_cnt] = i - 1;
+
+				alloc_cnt++;
+				if (alloc_cnt == req_cnt)
+					break;
+			}
+		}
+
+		if (i > inst_cnt)
+			inst[0] = INST_AVAILABLE;
+	}
+
+	if (inst[0] != INST_AVAILABLE) {
+		for (i = 0; i < req_cnt; i++)
+			*(res_addr + inst[i] + 1) = OWNER;
+		rc = 0;
+	}
+
+err:
+	res_mgr_unlock();
+
+	return rc;
+}
+EXPORT_SYMBOL(res_mgr_alloc_range);
+
+/**
+ * res_mgr_alloc() - Allocate a resource instance.
+ * @tag: Identifies the resource.
+ * @req_inst: Requested instance to allocate (-1 for don't care).
+ * @use_last_avail: Set to request the last available instance.
+ *
+ * Returns: Allocated resource instance if successful.
+ * Returns <0 for error codes.
+ */
+int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
+		  bool use_last_avail)
+{
+	int inst, rc;
+
+	rc = res_mgr_alloc_range(tag, req_inst, 1, use_last_avail, &inst);
+	if (!rc)
+		return inst;
+	return rc;
+}
+EXPORT_SYMBOL(res_mgr_alloc);
+
+/**
+ * res_mgr_free_range() - Free a resource instance range.
+ * @tag: Identifies the resource.
+ * @inst: Requested instance to free.
+ * @req_cnt: Number of instances to free.
+ */
+void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
+			int req_cnt)
+{
+	struct global_resource_entry *res_entry;
+	int res_index, i;
+	u64 *res_addr;
+
+	res_mgr_lock();
+
+	/* Find the resource. */
+	res_index = res_mgr_find_resource(tag);
+	if (res_index < 0) {
+		pr_err("Resource not found, can't free instance\n");
+		goto err;
+	}
+
+	/* Get the resource data. */
+	res_entry = &res_mgr_info->resource_entry[res_index];
+	res_addr = phys_to_virt(res_entry->phys_addr);
+
+	/* Free the resource instances. */
+	for (i = 0; i < req_cnt; i++) {
+		/* Instance off by 1 (first element holds the count). */
+		*(res_addr + inst[i] + 1) = INST_AVAILABLE;
+	}
+
+err:
+	res_mgr_unlock();
+}
+EXPORT_SYMBOL(res_mgr_free_range);
+
+/**
+ * res_mgr_free() - Free a resource instance.
+ * @tag: Identifies the resource.
+ * @req_inst: Requested instance to free.
+ */
+void res_mgr_free(struct global_resource_tag tag, int inst)
+{
+	res_mgr_free_range(tag, &inst, 1);
+}
+EXPORT_SYMBOL(res_mgr_free);
+
+static int __init res_mgr_init(void)
+{
+	struct cvmx_bootmem_named_block_desc *block;
+	int block_size;
+	u64 addr;
+
+	cvmx_bootmem_lock();
+
+	/* Search for the resource manager data in boot memory. */
+	block = cvmx_bootmem_phy_named_block_find(RESOURCE_MGR_BLOCK_NAME,
+						  CVMX_BOOTMEM_FLAG_NO_LOCKING);
+	if (block) {
+		/* Found. */
+		res_mgr_info = phys_to_virt(block->base_addr);
+	} else {
+		/* Create it. */
+		block_size = sizeof(struct global_resources) +
+			sizeof(struct global_resource_entry) * MAX_RESOURCES;
+		addr = cvmx_bootmem_phy_named_block_alloc(block_size, 0, 0,
+				CVMX_CACHE_LINE_SIZE, RESOURCE_MGR_BLOCK_NAME,
+				CVMX_BOOTMEM_FLAG_NO_LOCKING);
+		if (!addr) {
+			pr_err("Failed to allocate name block %s\n",
+			       RESOURCE_MGR_BLOCK_NAME);
+		} else {
+			res_mgr_info = phys_to_virt(addr);
+			memset(res_mgr_info, 0, block_size);
+		}
+	}
+
+	cvmx_bootmem_unlock();
+
+	return 0;
+}
+device_initcall(res_mgr_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cavium, Inc. Octeon resource manager");
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index a8034d0dcade..51c4d3c3cada 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -68,6 +68,12 @@ extern void pci_console_init(const char *arg);
 static unsigned long long max_memory = ULLONG_MAX;
 static unsigned long long reserve_low_mem;
 
+/*
+ * modified in hernel-entry-init.h, must have an initial value to keep
+ * it from being clobbered when bss is zeroed.
+ */
+u32 octeon_cvmseg_lines = 2;
+
 DEFINE_SEMAPHORE(octeon_bootbus_sem);
 EXPORT_SYMBOL(octeon_bootbus_sem);
 
@@ -604,11 +610,13 @@ void octeon_user_io_init(void)
 
 	/* R/W If set, CVMSEG is available for loads/stores in
 	 * kernel/debug mode. */
-#if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
 	cvmmemctl.s.cvmsegenak = 1;
-#else
-	cvmmemctl.s.cvmsegenak = 0;
-#endif
+	if (OCTEON_IS_OCTEON3()) {
+		/* Enable LMTDMA */
+		cvmmemctl.s.lmtena = 1;
+		/* Scratch line to use for LMT operation */
+		cvmmemctl.s.lmtline = 2;
+	}
 	/* R/W If set, CVMSEG is available for loads/stores in
 	 * supervisor mode. */
 	cvmmemctl.s.cvmsegenas = 0;
@@ -620,9 +628,9 @@ void octeon_user_io_init(void)
 
 	/* Setup of CVMSEG is done in kernel-entry-init.h */
 	if (smp_processor_id() == 0)
-		pr_notice("CVMSEG size: %d cache lines (%d bytes)\n",
-			  CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE,
-			  CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128);
+		pr_notice("CVMSEG size: %u cache lines (%u bytes)\n",
+			  octeon_cvmseg_lines,
+			  octeon_cvmseg_lines * 128);
 
 	if (octeon_has_feature(OCTEON_FEATURE_FAU)) {
 		union cvmx_iob_fau_timeout fau_timeout;
diff --git a/arch/mips/configs/bmips_stb_defconfig b/arch/mips/configs/bmips_stb_defconfig
index 3cefa6bc01dd..47aecb8750e6 100644
--- a/arch/mips/configs/bmips_stb_defconfig
+++ b/arch/mips/configs/bmips_stb_defconfig
@@ -72,6 +72,7 @@ CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
+CONFIG_SOC_BRCMSTB=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
diff --git a/arch/mips/configs/generic/32r6.config b/arch/mips/configs/generic/32r6.config
index ca606e71f4d0..1a5d5ea4ab2b 100644
--- a/arch/mips/configs/generic/32r6.config
+++ b/arch/mips/configs/generic/32r6.config
@@ -1,2 +1,4 @@
 CONFIG_CPU_MIPS32_R6=y
 CONFIG_HIGHMEM=y
+
+CONFIG_CRYPTO_CRC32_MIPS=y
diff --git a/arch/mips/configs/generic/64r6.config b/arch/mips/configs/generic/64r6.config
index 7cac0339c4d5..5dd8e8503e34 100644
--- a/arch/mips/configs/generic/64r6.config
+++ b/arch/mips/configs/generic/64r6.config
@@ -2,3 +2,5 @@ CONFIG_CPU_MIPS64_R6=y
 CONFIG_64BIT=y
 CONFIG_MIPS32_O32=y
 CONFIG_MIPS32_N32=y
+
+CONFIG_CRYPTO_CRC32_MIPS=y
diff --git a/arch/mips/crypto/Makefile b/arch/mips/crypto/Makefile
new file mode 100644
index 000000000000..e07aca572c2e
--- /dev/null
+++ b/arch/mips/crypto/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for MIPS crypto files..
+#
+
+obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32-mips.o
diff --git a/arch/mips/crypto/crc32-mips.c b/arch/mips/crypto/crc32-mips.c
new file mode 100644
index 000000000000..7d1d2425746f
--- /dev/null
+++ b/arch/mips/crypto/crc32-mips.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * crc32-mips.c - CRC32 and CRC32C using optional MIPSr6 instructions
+ *
+ * Module based on arm64/crypto/crc32-arm.c
+ *
+ * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org>
+ * Copyright (C) 2018 MIPS Tech, LLC
+ */
+
+#include <linux/unaligned/access_ok.h>
+#include <linux/cpufeature.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <asm/mipsregs.h>
+
+#include <crypto/internal/hash.h>
+
+enum crc_op_size {
+	b, h, w, d,
+};
+
+enum crc_type {
+	crc32,
+	crc32c,
+};
+
+#ifndef TOOLCHAIN_SUPPORTS_CRC
+#define _ASM_MACRO_CRC32(OP, SZ, TYPE)					  \
+_ASM_MACRO_3R(OP, rt, rs, rt2,						  \
+	".ifnc	\\rt, \\rt2\n\t"					  \
+	".error	\"invalid operands \\\"" #OP " \\rt,\\rs,\\rt2\\\"\"\n\t" \
+	".endif\n\t"							  \
+	_ASM_INSN_IF_MIPS(0x7c00000f | (__rt << 16) | (__rs << 21) |	  \
+			  ((SZ) <<  6) | ((TYPE) << 8))			  \
+	_ASM_INSN32_IF_MM(0x00000030 | (__rs << 16) | (__rt << 21) |	  \
+			  ((SZ) << 14) | ((TYPE) << 3)))
+_ASM_MACRO_CRC32(crc32b,  0, 0);
+_ASM_MACRO_CRC32(crc32h,  1, 0);
+_ASM_MACRO_CRC32(crc32w,  2, 0);
+_ASM_MACRO_CRC32(crc32d,  3, 0);
+_ASM_MACRO_CRC32(crc32cb, 0, 1);
+_ASM_MACRO_CRC32(crc32ch, 1, 1);
+_ASM_MACRO_CRC32(crc32cw, 2, 1);
+_ASM_MACRO_CRC32(crc32cd, 3, 1);
+#define _ASM_SET_CRC ""
+#else /* !TOOLCHAIN_SUPPORTS_CRC */
+#define _ASM_SET_CRC ".set\tcrc\n\t"
+#endif
+
+#define _CRC32(crc, value, size, type)		\
+do {						\
+	__asm__ __volatile__(			\
+		".set	push\n\t"		\
+		_ASM_SET_CRC			\
+		#type #size "	%0, %1, %0\n\t"	\
+		".set	pop"			\
+		: "+r" (crc)			\
+		: "r" (value));			\
+} while (0)
+
+#define CRC32(crc, value, size) \
+	_CRC32(crc, value, size, crc32)
+
+#define CRC32C(crc, value, size) \
+	_CRC32(crc, value, size, crc32c)
+
+static u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
+{
+	u32 crc = crc_;
+
+#ifdef CONFIG_64BIT
+	while (len >= sizeof(u64)) {
+		u64 value = get_unaligned_le64(p);
+
+		CRC32(crc, value, d);
+		p += sizeof(u64);
+		len -= sizeof(u64);
+	}
+
+	if (len & sizeof(u32)) {
+#else /* !CONFIG_64BIT */
+	while (len >= sizeof(u32)) {
+#endif
+		u32 value = get_unaligned_le32(p);
+
+		CRC32(crc, value, w);
+		p += sizeof(u32);
+		len -= sizeof(u32);
+	}
+
+	if (len & sizeof(u16)) {
+		u16 value = get_unaligned_le16(p);
+
+		CRC32(crc, value, h);
+		p += sizeof(u16);
+	}
+
+	if (len & sizeof(u8)) {
+		u8 value = *p++;
+
+		CRC32(crc, value, b);
+	}
+
+	return crc;
+}
+
+static u32 crc32c_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
+{
+	u32 crc = crc_;
+
+#ifdef CONFIG_64BIT
+	while (len >= sizeof(u64)) {
+		u64 value = get_unaligned_le64(p);
+
+		CRC32C(crc, value, d);
+		p += sizeof(u64);
+		len -= sizeof(u64);
+	}
+
+	if (len & sizeof(u32)) {
+#else /* !CONFIG_64BIT */
+	while (len >= sizeof(u32)) {
+#endif
+		u32 value = get_unaligned_le32(p);
+
+		CRC32C(crc, value, w);
+		p += sizeof(u32);
+		len -= sizeof(u32);
+	}
+
+	if (len & sizeof(u16)) {
+		u16 value = get_unaligned_le16(p);
+
+		CRC32C(crc, value, h);
+		p += sizeof(u16);
+	}
+
+	if (len & sizeof(u8)) {
+		u8 value = *p++;
+
+		CRC32C(crc, value, b);
+	}
+	return crc;
+}
+
+#define CHKSUM_BLOCK_SIZE	1
+#define CHKSUM_DIGEST_SIZE	4
+
+struct chksum_ctx {
+	u32 key;
+};
+
+struct chksum_desc_ctx {
+	u32 crc;
+};
+
+static int chksum_init(struct shash_desc *desc)
+{
+	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	ctx->crc = mctx->key;
+
+	return 0;
+}
+
+/*
+ * Setting the seed allows arbitrary accumulators and flexible XOR policy
+ * If your algorithm starts with ~0, then XOR with ~0 before you set
+ * the seed.
+ */
+static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
+			 unsigned int keylen)
+{
+	struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
+
+	if (keylen != sizeof(mctx->key)) {
+		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+	mctx->key = get_unaligned_le32(key);
+	return 0;
+}
+
+static int chksum_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int length)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	ctx->crc = crc32_mips_le_hw(ctx->crc, data, length);
+	return 0;
+}
+
+static int chksumc_update(struct shash_desc *desc, const u8 *data,
+			 unsigned int length)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	ctx->crc = crc32c_mips_le_hw(ctx->crc, data, length);
+	return 0;
+}
+
+static int chksum_final(struct shash_desc *desc, u8 *out)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	put_unaligned_le32(ctx->crc, out);
+	return 0;
+}
+
+static int chksumc_final(struct shash_desc *desc, u8 *out)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	put_unaligned_le32(~ctx->crc, out);
+	return 0;
+}
+
+static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
+{
+	put_unaligned_le32(crc32_mips_le_hw(crc, data, len), out);
+	return 0;
+}
+
+static int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
+{
+	put_unaligned_le32(~crc32c_mips_le_hw(crc, data, len), out);
+	return 0;
+}
+
+static int chksum_finup(struct shash_desc *desc, const u8 *data,
+			unsigned int len, u8 *out)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	return __chksum_finup(ctx->crc, data, len, out);
+}
+
+static int chksumc_finup(struct shash_desc *desc, const u8 *data,
+			unsigned int len, u8 *out)
+{
+	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+	return __chksumc_finup(ctx->crc, data, len, out);
+}
+
+static int chksum_digest(struct shash_desc *desc, const u8 *data,
+			 unsigned int length, u8 *out)
+{
+	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+
+	return __chksum_finup(mctx->key, data, length, out);
+}
+
+static int chksumc_digest(struct shash_desc *desc, const u8 *data,
+			 unsigned int length, u8 *out)
+{
+	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
+
+	return __chksumc_finup(mctx->key, data, length, out);
+}
+
+static int chksum_cra_init(struct crypto_tfm *tfm)
+{
+	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
+
+	mctx->key = ~0;
+	return 0;
+}
+
+static struct shash_alg crc32_alg = {
+	.digestsize		=	CHKSUM_DIGEST_SIZE,
+	.setkey			=	chksum_setkey,
+	.init			=	chksum_init,
+	.update			=	chksum_update,
+	.final			=	chksum_final,
+	.finup			=	chksum_finup,
+	.digest			=	chksum_digest,
+	.descsize		=	sizeof(struct chksum_desc_ctx),
+	.base			=	{
+		.cra_name		=	"crc32",
+		.cra_driver_name	=	"crc32-mips-hw",
+		.cra_priority		=	300,
+		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
+		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
+		.cra_alignmask		=	0,
+		.cra_ctxsize		=	sizeof(struct chksum_ctx),
+		.cra_module		=	THIS_MODULE,
+		.cra_init		=	chksum_cra_init,
+	}
+};
+
+static struct shash_alg crc32c_alg = {
+	.digestsize		=	CHKSUM_DIGEST_SIZE,
+	.setkey			=	chksum_setkey,
+	.init			=	chksum_init,
+	.update			=	chksumc_update,
+	.final			=	chksumc_final,
+	.finup			=	chksumc_finup,
+	.digest			=	chksumc_digest,
+	.descsize		=	sizeof(struct chksum_desc_ctx),
+	.base			=	{
+		.cra_name		=	"crc32c",
+		.cra_driver_name	=	"crc32c-mips-hw",
+		.cra_priority		=	300,
+		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
+		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
+		.cra_alignmask		=	0,
+		.cra_ctxsize		=	sizeof(struct chksum_ctx),
+		.cra_module		=	THIS_MODULE,
+		.cra_init		=	chksum_cra_init,
+	}
+};
+
+static int __init crc32_mod_init(void)
+{
+	int err;
+
+	err = crypto_register_shash(&crc32_alg);
+
+	if (err)
+		return err;
+
+	err = crypto_register_shash(&crc32c_alg);
+
+	if (err) {
+		crypto_unregister_shash(&crc32_alg);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit crc32_mod_exit(void)
+{
+	crypto_unregister_shash(&crc32_alg);
+	crypto_unregister_shash(&crc32c_alg);
+}
+
+MODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com");
+MODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions");
+MODULE_LICENSE("GPL v2");
+
+module_cpu_feature_match(MIPS_CRC32, crc32_mod_init);
+module_exit(crc32_mod_exit);
diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h
index a5eb1bb199a7..0e8e6afbf80a 100644
--- a/arch/mips/include/asm/barrier.h
+++ b/arch/mips/include/asm/barrier.h
@@ -216,7 +216,7 @@
 #else
 #define smp_mb__before_llsc() smp_llsc_mb()
 #define __smp_mb__before_llsc() smp_llsc_mb()
-#define nudge_writes() mb()
+#define nudge_writes() do { } while (0)
 #endif
 
 #define __smp_mb__before_atomic()	__smp_mb__before_llsc()
diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
index c38b38ce5a3d..cdcca60978a2 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
@@ -26,11 +26,18 @@
 	# a3 = address of boot descriptor block
 	.set push
 	.set arch=octeon
+	mfc0	v1, CP0_PRID_REG
+	andi	v1, 0xff00
+	li	v0, 0x9500		# cn78XX or later
+	subu	v1, v1, v0
+	li	t2, 2 + CONFIG_CAVIUM_OCTEON_EXTRA_CVMSEG
+	bltz	v1, 1f
+	addiu	t2, 1			# t2 has cvmseg_size
+1:
 	# Read the cavium mem control register
 	dmfc0	v0, CP0_CVMMEMCTL_REG
 	# Clear the lower 6 bits, the CVMSEG size
-	dins	v0, $0, 0, 6
-	ori	v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
+	dins	v0, t2, 0, 6
 	dmtc0	v0, CP0_CVMMEMCTL_REG	# Write the cavium mem control register
 	dmfc0	v0, CP0_CVMCTL_REG	# Read the cavium control register
 	# Disable unaligned load/store support but leave HW fixup enabled
@@ -70,7 +77,7 @@
 	# Flush dcache after config change
 	cache	9, 0($0)
 	# Zero all of CVMSEG to make sure parity is correct
-	dli	v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
+	move	v0, t2
 	dsll	v0, 7
 	beqz	v0, 2f
 1:	dsubu	v0, 8
@@ -126,12 +133,7 @@
 	LONG_L	sp, (t0)
 	# Set the SP global variable to zero so the master knows we've started
 	LONG_S	zero, (t0)
-#ifdef __OCTEON__
-	syncw
-	syncw
-#else
 	sync
-#endif
 	# Jump to the normal Linux SMP entry point
 	j   smp_bootstrap
 	nop
@@ -148,6 +150,8 @@
 
 #endif /* CONFIG_SMP */
 octeon_main_processor:
+	dla	v0, octeon_cvmseg_lines
+	sw	t2, 0(v0)
 	.set pop
 .endm
 
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 858752dac337..dfe8235123e3 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -664,6 +664,7 @@
 #define MIPS_CONF5_FRE		(_ULCAST_(1) << 8)
 #define MIPS_CONF5_UFE		(_ULCAST_(1) << 9)
 #define MIPS_CONF5_CA2		(_ULCAST_(1) << 14)
+#define MIPS_CONF5_CRCP		(_ULCAST_(1) << 18)
 #define MIPS_CONF5_MSAEN	(_ULCAST_(1) << 27)
 #define MIPS_CONF5_EVA		(_ULCAST_(1) << 28)
 #define MIPS_CONF5_CV		(_ULCAST_(1) << 29)
@@ -1126,6 +1127,8 @@
 #define FPU_CSR_RD	0x3	/* towards -Infinity */
 
 
+#define CAVIUM_OCTEON_SCRATCH_OFFSET (2 * 128 - 16 - 32768)
+
 #ifndef __ASSEMBLY__
 
 /*
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
index c99c4b6a79f4..4dafeaf262b5 100644
--- a/arch/mips/include/asm/octeon/octeon.h
+++ b/arch/mips/include/asm/octeon/octeon.h
@@ -179,7 +179,15 @@ union octeon_cvmemctl {
 		/* RO 1 = BIST fail, 0 = BIST pass */
 		__BITFIELD_FIELD(uint64_t wbfbist:1,
 		/* Reserved */
-		__BITFIELD_FIELD(uint64_t reserved:17,
+		__BITFIELD_FIELD(uint64_t reserved_52_57:6,
+		/* When set, LMTDMA/LMTST operations are permitted */
+		__BITFIELD_FIELD(uint64_t lmtena:1,
+		/* Selects the CVMSEG LM cacheline used by LMTDMA
+		 * LMTST and wide atomic store operations.
+		 */
+		__BITFIELD_FIELD(uint64_t lmtline:6,
+		/* Reserved */
+		__BITFIELD_FIELD(uint64_t reserved_41_44:4,
 		/* OCTEON II - TLB replacement policy: 0 = bitmask LRU; 1 = NLU.
 		 * This field selects between the TLB replacement policies:
 		 * bitmask LRU or NLU. Bitmask LRU maintains a mask of
@@ -275,7 +283,7 @@ union octeon_cvmemctl {
 		/* R/W Size of local memory in cache blocks, 54 (6912
 		 * bytes) is max legal value. */
 		__BITFIELD_FIELD(uint64_t lmemsz:6,
-		;)))))))))))))))))))))))))))))))))
+		;))))))))))))))))))))))))))))))))))))
 	} s;
 };
 
@@ -338,6 +346,24 @@ void octeon_mult_restore3_end(void);
 void octeon_mult_restore2(void);
 void octeon_mult_restore2_end(void);
 
+/*
+ * This definition must be kept in sync with the one in
+ * cvmx-global-resources.c
+ */
+struct global_resource_tag {
+	uint64_t lo;
+	uint64_t hi;
+};
+
+void res_mgr_free(struct global_resource_tag tag, int inst);
+void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
+			int req_cnt);
+int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
+		  bool use_last_avail);
+int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
+			int req_cnt, bool use_last_avail, int *inst);
+int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt);
+
 /**
  * Read a 32bit value from the Octeon NPI register space
  *
@@ -351,6 +377,8 @@ static inline uint32_t octeon_npi_read32(uint64_t address)
 
 extern struct cvmx_bootinfo *octeon_bootinfo;
 
+extern u32 octeon_cvmseg_lines;
+
 extern uint64_t octeon_bootloader_entry_addr;
 
 extern void (*octeon_irq_setup_secondary)(void);
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index af34afbc32d9..1a20f9c5509f 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -216,7 +216,7 @@ struct octeon_cop2_state {
 	.cp2			= {0,},
 
 struct octeon_cvmseg_state {
-	unsigned long cvmseg[CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE]
+	unsigned long cvmseg[CONFIG_CAVIUM_OCTEON_EXTRA_CVMSEG + 3]
 			    [cpu_dcache_line_size() / sizeof(unsigned long)];
 };
 
diff --git a/arch/mips/include/uapi/asm/hwcap.h b/arch/mips/include/uapi/asm/hwcap.h
index 600ad8fd6835..a2aba4b059e6 100644
--- a/arch/mips/include/uapi/asm/hwcap.h
+++ b/arch/mips/include/uapi/asm/hwcap.h
@@ -5,5 +5,6 @@
 /* HWCAP flags */
 #define HWCAP_MIPS_R6		(1 << 0)
 #define HWCAP_MIPS_MSA		(1 << 1)
+#define HWCAP_MIPS_CRC32	(1 << 2)
 
 #endif /* _UAPI_ASM_HWCAP_H */
diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h
index 606e02ca4b6c..3035ca499cd8 100644
--- a/arch/mips/include/uapi/asm/mman.h
+++ b/arch/mips/include/uapi/asm/mman.h
@@ -50,6 +50,7 @@
 #define MAP_NONBLOCK	0x20000		/* do not block on IO */
 #define MAP_STACK	0x40000		/* give out an address that is best suited for process/thread stacks */
 #define MAP_HUGETLB	0x80000		/* create a huge page mapping */
+#define MAP_FIXED_NOREPLACE 0x100000	/* MAP_FIXED which doesn't unmap underlying mapping */
 
 /*
  * Flags for msync
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 6d7f97552200..60f0767507c6 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -313,25 +313,34 @@ static struct jz4740_fb_platform_data qi_lb60_fb_pdata = {
 	.pixclk_falling_edge = 1,
 };
 
-struct spi_gpio_platform_data spigpio_platform_data = {
-	.sck = JZ_GPIO_PORTC(23),
-	.mosi = JZ_GPIO_PORTC(22),
-	.miso = -1,
+struct spi_gpio_platform_data qi_lb60_spigpio_platform_data = {
 	.num_chipselect = 1,
 };
 
-static struct platform_device spigpio_device = {
+static struct platform_device qi_lb60_spigpio_device = {
 	.name = "spi_gpio",
 	.id   = 1,
 	.dev = {
-		.platform_data = &spigpio_platform_data,
+		.platform_data = &qi_lb60_spigpio_platform_data,
+	},
+};
+
+static struct gpiod_lookup_table qi_lb60_spigpio_gpio_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("GPIOC", 23,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOC", 22,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("GPIOC", 21,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
 	},
 };
 
 static struct spi_board_info qi_lb60_spi_board_info[] = {
 	{
 		.modalias = "ili8960",
-		.controller_data = (void *)JZ_GPIO_PORTC(21),
 		.chip_select = 0,
 		.bus_num = 1,
 		.max_speed_hz = 30 * 1000,
@@ -435,7 +444,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
 	&jz4740_mmc_device,
 	&jz4740_nand_device,
 	&qi_lb60_keypad,
-	&spigpio_device,
+	&qi_lb60_spigpio_device,
 	&jz4740_framebuffer_device,
 	&jz4740_pcm_device,
 	&jz4740_i2s_device,
@@ -489,6 +498,7 @@ static int __init qi_lb60_init_platform_devices(void)
 
 	gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
 	gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
+	gpiod_add_lookup_table(&qi_lb60_spigpio_gpio_table);
 
 	spi_register_board_info(qi_lb60_spi_board_info,
 				ARRAY_SIZE(qi_lb60_spi_board_info));
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index cf3fd549e16d..6b07b739f914 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -848,6 +848,9 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
 	if (config5 & MIPS_CONF5_CA2)
 		c->ases |= MIPS_ASE_MIPS16E2;
 
+	if (config5 & MIPS_CONF5_CRCP)
+		elf_hwcap |= HWCAP_MIPS_CRC32;
+
 	return config5 & MIPS_CONF_M;
 }
 
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S
index e42113fe2762..4f56902d5ee7 100644
--- a/arch/mips/kernel/octeon_switch.S
+++ b/arch/mips/kernel/octeon_switch.S
@@ -29,7 +29,6 @@
 	cpu_save_nonscratch a0
 	LONG_S	ra, THREAD_REG31(a0)
 
-#if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
 	/* Check if we need to store CVMSEG state */
 	dmfc0	t0, $11,7	/* CvmMemCtl */
 	bbit0	t0, 6, 3f	/* Is user access enabled? */
@@ -58,7 +57,6 @@
 	dmfc0	t0, $11,7	/* CvmMemCtl */
 	xori	t0, t0, 0x40	/* Bit 6 is CVMSEG user enable */
 	dmtc0	t0, $11,7	/* CvmMemCtl */
-#endif
 3:
 
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 5f8b0a9e30b3..563188ac6fa2 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -155,7 +155,8 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
 	add_memory_region(start, size, BOOT_MEM_RAM);
 }
 
-bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
+static bool __init __maybe_unused memory_region_available(phys_addr_t start,
+							  phys_addr_t size)
 {
 	int i;
 	bool in_ram = false, free = true;
@@ -453,7 +454,7 @@ static void __init bootmem_init(void)
 		pr_info("Wasting %lu bytes for tracking %lu unused pages\n",
 			(min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
 			min_low_pfn - ARCH_PFN_OFFSET);
-	} else if (min_low_pfn < ARCH_PFN_OFFSET) {
+	} else if (ARCH_PFN_OFFSET - min_low_pfn > 0UL) {
 		pr_info("%lu free pages won't be used\n",
 			ARCH_PFN_OFFSET - min_low_pfn);
 	}
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 84b7b592b834..400676ce03f4 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -30,7 +30,6 @@
 #include <linux/hardirq.h>
 #include <linux/gfp.h>
 #include <linux/kcore.h>
-#include <linux/export.h>
 #include <linux/initrd.h>
 
 #include <asm/asm-offsets.h>
@@ -46,7 +45,6 @@
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/fixmap.h>
-#include <asm/maar.h>
 
 /*
  * We have up to 8 empty zeroed pages so we can map one of the right colour
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 79b9f2ad3ff5..3d3dfba465ae 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -115,33 +115,17 @@ static int use_lwx_insns(void)
 		return 0;
 	}
 }
-#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \
-    CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
-static bool scratchpad_available(void)
-{
-	return true;
-}
-static int scratchpad_offset(int i)
-{
-	/*
-	 * CVMSEG starts at address -32768 and extends for
-	 * CAVIUM_OCTEON_CVMSEG_SIZE 128 byte cache lines.
-	 */
-	i += 1; /* Kernel use starts at the top and works down. */
-	return CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128 - (8 * i) - 32768;
-}
-#else
-static bool scratchpad_available(void)
-{
-	return false;
-}
+
 static int scratchpad_offset(int i)
 {
+	if (IS_ENABLED(CONFIG_CPU_CAVIUM_OCTEON))
+		return (CAVIUM_OCTEON_SCRATCH_OFFSET - (8 * i));
+
 	BUG();
 	/* Really unreachable, but evidently some GCC want this. */
 	return 0;
 }
-#endif
+
 /*
  * Found by experiment: At least some revisions of the 4kc throw under
  * some circumstances a machine check exception, triggered by invalid
@@ -1302,7 +1286,8 @@ static void build_r4000_tlb_refill_handler(void)
 	memset(relocs, 0, sizeof(relocs));
 	memset(final_handler, 0, sizeof(final_handler));
 
-	if (IS_ENABLED(CONFIG_64BIT) && (scratch_reg >= 0 || scratchpad_available()) && use_bbit_insns()) {
+	if (IS_ENABLED(CONFIG_64BIT) && use_bbit_insns() &&
+	   (scratch_reg >= 0 || IS_ENABLED(CONFIG_CPU_CAVIUM_OCTEON))) {
 		htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1,
 							  scratch_reg);
 		vmalloc_mode = refill_scratch;
diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c
index f5b367e20dff..31955c1d5555 100644
--- a/arch/mips/txx9/rbtx4927/setup.c
+++ b/arch/mips/txx9/rbtx4927/setup.c
@@ -319,7 +319,7 @@ static void __init rbtx4927_mtd_init(void)
 
 static void __init rbtx4927_gpioled_init(void)
 {
-	static struct gpio_led leds[] = {
+	static const struct gpio_led leds[] = {
 		{ .name = "gpioled:green:0", .gpio = 0, .active_low = 1, },
 		{ .name = "gpioled:green:1", .gpio = 1, .active_low = 1, },
 	};
diff --git a/arch/openrisc/include/uapi/asm/unistd.h b/arch/openrisc/include/uapi/asm/unistd.h
index 9a3ee389631e..11c5a58ab333 100644
--- a/arch/openrisc/include/uapi/asm/unistd.h
+++ b/arch/openrisc/include/uapi/asm/unistd.h
@@ -17,8 +17,6 @@
  * (at your option) any later version.
  */
 
-#define __ARCH_HAVE_MMU
-
 #define sys_mmap2 sys_mmap_pgoff
 
 #define __ARCH_WANT_RENAMEAT
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index 3742508cc534..bd5ce31936f5 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -26,6 +26,7 @@ void flush_user_icache_range_asm(unsigned long, unsigned long);
 void flush_kernel_icache_range_asm(unsigned long, unsigned long);
 void flush_user_dcache_range_asm(unsigned long, unsigned long);
 void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
+void purge_kernel_dcache_range_asm(unsigned long, unsigned long);
 void flush_kernel_dcache_page_asm(void *);
 void flush_kernel_icache_page(void *);
 
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index 0e6ab6e4a4e9..2dbe5580a1a4 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -316,6 +316,8 @@ extern int _parisc_requires_coherency;
 #define parisc_requires_coherency()	(0)
 #endif
 
+extern int running_on_qemu;
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
index 80510ba44c08..0ebe24344a34 100644
--- a/arch/parisc/include/uapi/asm/mman.h
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -26,6 +26,7 @@
 #define MAP_NONBLOCK	0x20000		/* do not block on IO */
 #define MAP_STACK	0x40000		/* give out an address that is best suited for process/thread stacks */
 #define MAP_HUGETLB	0x80000		/* create a huge page mapping */
+#define MAP_FIXED_NOREPLACE 0x100000	/* MAP_FIXED which doesn't unmap underlying mapping */
 
 #define MS_SYNC		1		/* synchronous memory sync */
 #define MS_ASYNC	2		/* sync memory asynchronously */
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 19c0c141bc3f..7c1bde80ada4 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -539,13 +539,10 @@ void flush_cache_mm(struct mm_struct *mm)
 	struct vm_area_struct *vma;
 	pgd_t *pgd;
 
-	/* Flush the TLB to avoid speculation if coherency is required. */
-	if (parisc_requires_coherency())
-		flush_tlb_all();
-
 	/* Flushing the whole cache on each cpu takes forever on
 	   rp3440, etc.  So, avoid it if the mm isn't too big.  */
 	if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
+		flush_tlb_all();
 		flush_cache_all();
 		return;
 	}
@@ -553,9 +550,9 @@ void flush_cache_mm(struct mm_struct *mm)
 	if (mm->context == mfsp(3)) {
 		for (vma = mm->mmap; vma; vma = vma->vm_next) {
 			flush_user_dcache_range_asm(vma->vm_start, vma->vm_end);
-			if ((vma->vm_flags & VM_EXEC) == 0)
-				continue;
-			flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
+			if (vma->vm_flags & VM_EXEC)
+				flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
+			flush_tlb_range(vma, vma->vm_start, vma->vm_end);
 		}
 		return;
 	}
@@ -581,21 +578,18 @@ void flush_cache_mm(struct mm_struct *mm)
 void flush_cache_range(struct vm_area_struct *vma,
 		unsigned long start, unsigned long end)
 {
-	BUG_ON(!vma->vm_mm->context);
-
-	/* Flush the TLB to avoid speculation if coherency is required. */
-	if (parisc_requires_coherency())
+	if ((end - start) >= parisc_cache_flush_threshold) {
 		flush_tlb_range(vma, start, end);
-
-	if ((end - start) >= parisc_cache_flush_threshold
-	    || vma->vm_mm->context != mfsp(3)) {
 		flush_cache_all();
 		return;
 	}
 
+	BUG_ON(vma->vm_mm->context != mfsp(3));
+
 	flush_user_dcache_range_asm(start, end);
 	if (vma->vm_flags & VM_EXEC)
 		flush_user_icache_range_asm(start, end);
+	flush_tlb_range(vma, start, end);
 }
 
 void
@@ -604,8 +598,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 	BUG_ON(!vma->vm_mm->context);
 
 	if (pfn_valid(pfn)) {
-		if (parisc_requires_coherency())
-			flush_tlb_page(vma, vmaddr);
+		flush_tlb_page(vma, vmaddr);
 		__flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
 	}
 }
@@ -613,21 +606,35 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 void flush_kernel_vmap_range(void *vaddr, int size)
 {
 	unsigned long start = (unsigned long)vaddr;
+	unsigned long end = start + size;
 
-	if ((unsigned long)size > parisc_cache_flush_threshold)
+#if defined(CONFIG_PA20) || !defined(CONFIG_SMP)
+	/* The IPI interrupts used by flush_data_cache() cause a stall
+	   in the PA 1.1 dynamic DMA mapping code in SMP kernels. */
+	if ((unsigned long)size >= parisc_cache_flush_threshold) {
+		flush_tlb_kernel_range (start, end);
 		flush_data_cache();
-	else
-		flush_kernel_dcache_range_asm(start, start + size);
+		return;
+	}
+#endif
+
+	flush_kernel_dcache_range_asm(start, end);
+	flush_tlb_kernel_range (start, end);
 }
 EXPORT_SYMBOL(flush_kernel_vmap_range);
 
 void invalidate_kernel_vmap_range(void *vaddr, int size)
 {
 	unsigned long start = (unsigned long)vaddr;
+	unsigned long end = start + size;
 
-	if ((unsigned long)size > parisc_cache_flush_threshold)
+	if ((unsigned long)size >= parisc_cache_flush_threshold) {
+		flush_tlb_kernel_range (start, end);
 		flush_data_cache();
-	else
-		flush_kernel_dcache_range_asm(start, start + size);
+		return;
+	}
+
+	purge_kernel_dcache_range_asm(start, end);
+	flush_tlb_kernel_range (start, end);
 }
 EXPORT_SYMBOL(invalidate_kernel_vmap_range);
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index bbbe360b458f..fbb4e43fda05 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -138,6 +138,16 @@ $pgt_fill_loop:
 	std		%dp,0x18(%r10)
 #endif
 
+#ifdef CONFIG_64BIT
+	/* Get PDCE_PROC for monarch CPU. */
+#define MEM_PDC_LO 0x388
+#define MEM_PDC_HI 0x35C
+	ldw             MEM_PDC_LO(%r0),%r3
+	ldw             MEM_PDC_HI(%r0),%r10
+	depd            %r10, 31, 32, %r3        /* move to upper word */
+#endif
+
+
 #ifdef CONFIG_SMP
 	/* Set the smp rendezvous address into page zero.
 	** It would be safer to do this in init_smp_config() but
@@ -196,12 +206,6 @@ common_stext:
         ** Someday, palo might not do this for the Monarch either.
         */
 2:
-#define MEM_PDC_LO 0x388
-#define MEM_PDC_HI 0x35C
-	ldw             MEM_PDC_LO(%r0),%r3
-	ldw             MEM_PDC_HI(%r0),%r6
-	depd            %r6, 31, 32, %r3        /* move to upper word */
-
 	mfctl		%cr30,%r6		/* PCX-W2 firmware bug */
 
 	ldo             PDC_PSW(%r0),%arg0              /* 21 */
@@ -268,6 +272,8 @@ $install_iva:
 aligned_rfi:
 	pcxt_ssm_bug
 
+	copy		%r3, %arg0	/* PDCE_PROC for smp_callin() */
+
 	rsm		PSW_SM_QUIET,%r0	/* off troublesome PSW bits */
 	/* Don't need NOPs, have 8 compliant insn before rfi */
 
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index 2d40c4ff3f69..67b0f7532e83 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -1110,6 +1110,28 @@ ENTRY_CFI(flush_kernel_dcache_range_asm)
 	.procend
 ENDPROC_CFI(flush_kernel_dcache_range_asm)
 
+ENTRY_CFI(purge_kernel_dcache_range_asm)
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil		L%dcache_stride, %r1
+	ldw		R%dcache_stride(%r1), %r23
+	ldo		-1(%r23), %r21
+	ANDCM		%r26, %r21, %r26
+
+1:      cmpb,COND(<<),n	%r26, %r25,1b
+	pdc,m		%r23(%r26)
+
+	sync
+	syncdma
+	bv		%r0(%r2)
+	nop
+	.exit
+
+	.procend
+ENDPROC_CFI(purge_kernel_dcache_range_asm)
+
 ENTRY_CFI(flush_user_icache_range_asm)
 	.proc
 	.callinfo NO_CALLS
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 30c28ab14540..4065b5e48c9d 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -292,10 +292,15 @@ smp_cpu_init(int cpunum)
  * Slaves start using C here. Indirectly called from smp_slave_stext.
  * Do what start_kernel() and main() do for boot strap processor (aka monarch)
  */
-void __init smp_callin(void)
+void __init smp_callin(unsigned long pdce_proc)
 {
 	int slave_id = cpu_now_booting;
 
+#ifdef CONFIG_64BIT
+	WARN_ON(((unsigned long)(PAGE0->mem_pdc_hi) << 32
+			| PAGE0->mem_pdc) != pdce_proc);
+#endif
+
 	smp_cpu_init(slave_id);
 	preempt_disable();
 
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 4b8fd6dc22da..f7e684560186 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -76,10 +76,10 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 	next_tick = cpuinfo->it_value;
 
 	/* Calculate how many ticks have elapsed. */
+	now = mfctl(16);
 	do {
 		++ticks_elapsed;
 		next_tick += cpt;
-		now = mfctl(16);
 	} while (next_tick - now > cpt);
 
 	/* Store (in CR16 cycles) up to when we are accounting right now. */
@@ -103,16 +103,17 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 	 * if one or the other wrapped. If "now" is "bigger" we'll end up
 	 * with a very large unsigned number.
 	 */
-	while (next_tick - mfctl(16) > cpt)
+	now = mfctl(16);
+	while (next_tick - now > cpt)
 		next_tick += cpt;
 
 	/* Program the IT when to deliver the next interrupt.
 	 * Only bottom 32-bits of next_tick are writable in CR16!
 	 * Timer interrupt will be delivered at least a few hundred cycles
-	 * after the IT fires, so if we are too close (<= 500 cycles) to the
+	 * after the IT fires, so if we are too close (<= 8000 cycles) to the
 	 * next cycle, simply skip it.
 	 */
-	if (next_tick - mfctl(16) <= 500)
+	if (next_tick - now <= 8000)
 		next_tick += cpt;
 	mtctl(next_tick, 16);
 
@@ -248,7 +249,7 @@ static int __init init_cr16_clocksource(void)
 	 * different sockets, so mark them unstable and lower rating on
 	 * multi-socket SMP systems.
 	 */
-	if (num_online_cpus() > 1) {
+	if (num_online_cpus() > 1 && !running_on_qemu) {
 		int cpu;
 		unsigned long cpu0_loc;
 		cpu0_loc = per_cpu(cpu_data, 0).cpu_loc;
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 48f41399fc0b..cab32ee824d2 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -629,7 +629,12 @@ void __init mem_init(void)
 #endif
 
 	mem_init_print_info(NULL);
-#ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */
+
+#if 0
+	/*
+	 * Do not expose the virtual kernel memory layout to userspace.
+	 * But keep code for debugging purposes.
+	 */
 	printk("virtual kernel memory layout:\n"
 	       "    vmalloc : 0x%px - 0x%px   (%4ld MB)\n"
 	       "    memory  : 0x%px - 0x%px   (%4ld MB)\n"
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1b6bc7fba996..2358f97d62ec 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -165,7 +165,7 @@ systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
 	$(call cmd,systbl_chk)
 
 ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y)
-$(obj)/built-in.o:		prom_init_check
+$(obj)/built-in.a:		prom_init_check
 
 quiet_cmd_prom_init_check = CALL    $<
       cmd_prom_init_check = $(CONFIG_SHELL) $< "$(NM)" "$(obj)/prom_init.o"
diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c
index e0a2d8e806ed..91ee2231c527 100644
--- a/arch/powerpc/mm/mmu_context_iommu.c
+++ b/arch/powerpc/mm/mmu_context_iommu.c
@@ -75,8 +75,7 @@ EXPORT_SYMBOL_GPL(mm_iommu_preregistered);
 /*
  * Taken from alloc_migrate_target with changes to remove CMA allocations
  */
-struct page *new_iommu_non_cma_page(struct page *page, unsigned long private,
-					int **resultp)
+struct page *new_iommu_non_cma_page(struct page *page, unsigned long private)
 {
 	gfp_t gfp_mask = GFP_USER;
 	struct page *new_page;
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index c7b4333d1de0..f0f9bcf94c03 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -151,4 +151,7 @@ void vmem_map_init(void);
 void *vmem_crst_alloc(unsigned long val);
 pte_t *vmem_pte_alloc(void);
 
+unsigned long base_asce_alloc(unsigned long addr, unsigned long num_pages);
+void base_asce_free(unsigned long asce);
+
 #endif /* _S390_PGALLOC_H */
diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c
index 69d7fcf48158..9aff72d3abda 100644
--- a/arch/s390/kernel/nospec-branch.c
+++ b/arch/s390/kernel/nospec-branch.c
@@ -2,8 +2,8 @@
 #include <linux/module.h>
 #include <asm/nospec-branch.h>
 
-int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF);
-int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL);
+int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
+int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL);
 
 static int __init nospectre_v2_setup_early(char *str)
 {
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 9c7d70715862..07c6e81163bf 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -22,22 +22,6 @@
 #include "trace.h"
 #include "trace-s390.h"
 
-
-static const intercept_handler_t instruction_handlers[256] = {
-	[0x01] = kvm_s390_handle_01,
-	[0x82] = kvm_s390_handle_lpsw,
-	[0x83] = kvm_s390_handle_diag,
-	[0xaa] = kvm_s390_handle_aa,
-	[0xae] = kvm_s390_handle_sigp,
-	[0xb2] = kvm_s390_handle_b2,
-	[0xb6] = kvm_s390_handle_stctl,
-	[0xb7] = kvm_s390_handle_lctl,
-	[0xb9] = kvm_s390_handle_b9,
-	[0xe3] = kvm_s390_handle_e3,
-	[0xe5] = kvm_s390_handle_e5,
-	[0xeb] = kvm_s390_handle_eb,
-};
-
 u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
@@ -129,16 +113,39 @@ static int handle_validity(struct kvm_vcpu *vcpu)
 
 static int handle_instruction(struct kvm_vcpu *vcpu)
 {
-	intercept_handler_t handler;
-
 	vcpu->stat.exit_instruction++;
 	trace_kvm_s390_intercept_instruction(vcpu,
 					     vcpu->arch.sie_block->ipa,
 					     vcpu->arch.sie_block->ipb);
-	handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8];
-	if (handler)
-		return handler(vcpu);
-	return -EOPNOTSUPP;
+
+	switch (vcpu->arch.sie_block->ipa >> 8) {
+	case 0x01:
+		return kvm_s390_handle_01(vcpu);
+	case 0x82:
+		return kvm_s390_handle_lpsw(vcpu);
+	case 0x83:
+		return kvm_s390_handle_diag(vcpu);
+	case 0xaa:
+		return kvm_s390_handle_aa(vcpu);
+	case 0xae:
+		return kvm_s390_handle_sigp(vcpu);
+	case 0xb2:
+		return kvm_s390_handle_b2(vcpu);
+	case 0xb6:
+		return kvm_s390_handle_stctl(vcpu);
+	case 0xb7:
+		return kvm_s390_handle_lctl(vcpu);
+	case 0xb9:
+		return kvm_s390_handle_b9(vcpu);
+	case 0xe3:
+		return kvm_s390_handle_e3(vcpu);
+	case 0xe5:
+		return kvm_s390_handle_e5(vcpu);
+	case 0xeb:
+		return kvm_s390_handle_eb(vcpu);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int inject_prog_on_prog_intercept(struct kvm_vcpu *vcpu)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index aabf46f5f883..3f2c49b1a393 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -187,12 +187,6 @@ static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu)
 	return kvm_s390_get_cpu_timer(vcpu) >> 63;
 }
 
-static inline int is_ioirq(unsigned long irq_type)
-{
-	return ((irq_type >= IRQ_PEND_IO_ISC_7) &&
-		(irq_type <= IRQ_PEND_IO_ISC_0));
-}
-
 static uint64_t isc_to_isc_bits(int isc)
 {
 	return (0x80 >> isc) << 24;
@@ -236,10 +230,15 @@ static inline int kvm_s390_gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gis
 	return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
 }
 
-static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
+static inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu)
 {
 	return vcpu->kvm->arch.float_int.pending_irqs |
-		vcpu->arch.local_int.pending_irqs |
+		vcpu->arch.local_int.pending_irqs;
+}
+
+static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
+{
+	return pending_irqs_no_gisa(vcpu) |
 		kvm_s390_gisa_get_ipm(vcpu->kvm->arch.gisa) << IRQ_PEND_IO_ISC_7;
 }
 
@@ -337,7 +336,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
 
 static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
 {
-	if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK))
+	if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_IO_MASK))
 		return;
 	else if (psw_ioint_disabled(vcpu))
 		kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT);
@@ -1011,24 +1010,6 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
 	return rc;
 }
 
-typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu);
-
-static const deliver_irq_t deliver_irq_funcs[] = {
-	[IRQ_PEND_MCHK_EX]        = __deliver_machine_check,
-	[IRQ_PEND_MCHK_REP]       = __deliver_machine_check,
-	[IRQ_PEND_PROG]           = __deliver_prog,
-	[IRQ_PEND_EXT_EMERGENCY]  = __deliver_emergency_signal,
-	[IRQ_PEND_EXT_EXTERNAL]   = __deliver_external_call,
-	[IRQ_PEND_EXT_CLOCK_COMP] = __deliver_ckc,
-	[IRQ_PEND_EXT_CPU_TIMER]  = __deliver_cpu_timer,
-	[IRQ_PEND_RESTART]        = __deliver_restart,
-	[IRQ_PEND_SET_PREFIX]     = __deliver_set_prefix,
-	[IRQ_PEND_PFAULT_INIT]    = __deliver_pfault_init,
-	[IRQ_PEND_EXT_SERVICE]    = __deliver_service,
-	[IRQ_PEND_PFAULT_DONE]    = __deliver_pfault_done,
-	[IRQ_PEND_VIRTIO]         = __deliver_virtio,
-};
-
 /* Check whether an external call is pending (deliverable or not) */
 int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
 {
@@ -1192,7 +1173,6 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
 int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
 {
 	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-	deliver_irq_t func;
 	int rc = 0;
 	unsigned long irq_type;
 	unsigned long irqs;
@@ -1212,16 +1192,57 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
 	while ((irqs = deliverable_irqs(vcpu)) && !rc) {
 		/* bits are in the reverse order of interrupt priority */
 		irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT);
-		if (is_ioirq(irq_type)) {
+		switch (irq_type) {
+		case IRQ_PEND_IO_ISC_0:
+		case IRQ_PEND_IO_ISC_1:
+		case IRQ_PEND_IO_ISC_2:
+		case IRQ_PEND_IO_ISC_3:
+		case IRQ_PEND_IO_ISC_4:
+		case IRQ_PEND_IO_ISC_5:
+		case IRQ_PEND_IO_ISC_6:
+		case IRQ_PEND_IO_ISC_7:
 			rc = __deliver_io(vcpu, irq_type);
-		} else {
-			func = deliver_irq_funcs[irq_type];
-			if (!func) {
-				WARN_ON_ONCE(func == NULL);
-				clear_bit(irq_type, &li->pending_irqs);
-				continue;
-			}
-			rc = func(vcpu);
+			break;
+		case IRQ_PEND_MCHK_EX:
+		case IRQ_PEND_MCHK_REP:
+			rc = __deliver_machine_check(vcpu);
+			break;
+		case IRQ_PEND_PROG:
+			rc = __deliver_prog(vcpu);
+			break;
+		case IRQ_PEND_EXT_EMERGENCY:
+			rc = __deliver_emergency_signal(vcpu);
+			break;
+		case IRQ_PEND_EXT_EXTERNAL:
+			rc = __deliver_external_call(vcpu);
+			break;
+		case IRQ_PEND_EXT_CLOCK_COMP:
+			rc = __deliver_ckc(vcpu);
+			break;
+		case IRQ_PEND_EXT_CPU_TIMER:
+			rc = __deliver_cpu_timer(vcpu);
+			break;
+		case IRQ_PEND_RESTART:
+			rc = __deliver_restart(vcpu);
+			break;
+		case IRQ_PEND_SET_PREFIX:
+			rc = __deliver_set_prefix(vcpu);
+			break;
+		case IRQ_PEND_PFAULT_INIT:
+			rc = __deliver_pfault_init(vcpu);
+			break;
+		case IRQ_PEND_EXT_SERVICE:
+			rc = __deliver_service(vcpu);
+			break;
+		case IRQ_PEND_PFAULT_DONE:
+			rc = __deliver_pfault_done(vcpu);
+			break;
+		case IRQ_PEND_VIRTIO:
+			rc = __deliver_virtio(vcpu);
+			break;
+		default:
+			WARN_ONCE(1, "Unknown pending irq type %ld", irq_type);
+			clear_bit(irq_type, &li->pending_irqs);
 		}
 	}
 
@@ -1701,7 +1722,8 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)
 		kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT);
 		break;
 	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-		kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);
+		if (!(type & KVM_S390_INT_IO_AI_MASK && kvm->arch.gisa))
+			kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);
 		break;
 	default:
 		kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT);
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index bd31b37b0e6f..3c0a975c2477 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -19,8 +19,6 @@
 #include <asm/processor.h>
 #include <asm/sclp.h>
 
-typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
-
 /* Transactional Memory Execution related macros */
 #define IS_TE_ENABLED(vcpu)	((vcpu->arch.sie_block->ecb & ECB_TE))
 #define TDB_FORMAT1		1
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index c4c4e157c036..a74578cdd3f3 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -795,55 +795,60 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
 	return rc;
 }
 
-static const intercept_handler_t b2_handlers[256] = {
-	[0x02] = handle_stidp,
-	[0x04] = handle_set_clock,
-	[0x10] = handle_set_prefix,
-	[0x11] = handle_store_prefix,
-	[0x12] = handle_store_cpu_address,
-	[0x14] = kvm_s390_handle_vsie,
-	[0x21] = handle_ipte_interlock,
-	[0x29] = handle_iske,
-	[0x2a] = handle_rrbe,
-	[0x2b] = handle_sske,
-	[0x2c] = handle_test_block,
-	[0x30] = handle_io_inst,
-	[0x31] = handle_io_inst,
-	[0x32] = handle_io_inst,
-	[0x33] = handle_io_inst,
-	[0x34] = handle_io_inst,
-	[0x35] = handle_io_inst,
-	[0x36] = handle_io_inst,
-	[0x37] = handle_io_inst,
-	[0x38] = handle_io_inst,
-	[0x39] = handle_io_inst,
-	[0x3a] = handle_io_inst,
-	[0x3b] = handle_io_inst,
-	[0x3c] = handle_io_inst,
-	[0x50] = handle_ipte_interlock,
-	[0x56] = handle_sthyi,
-	[0x5f] = handle_io_inst,
-	[0x74] = handle_io_inst,
-	[0x76] = handle_io_inst,
-	[0x7d] = handle_stsi,
-	[0xb1] = handle_stfl,
-	[0xb2] = handle_lpswe,
-};
-
 int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
 {
-	intercept_handler_t handler;
-
-	/*
-	 * A lot of B2 instructions are priviledged. Here we check for
-	 * the privileged ones, that we can handle in the kernel.
-	 * Anything else goes to userspace.
-	 */
-	handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-	if (handler)
-		return handler(vcpu);
-
-	return -EOPNOTSUPP;
+	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+	case 0x02:
+		return handle_stidp(vcpu);
+	case 0x04:
+		return handle_set_clock(vcpu);
+	case 0x10:
+		return handle_set_prefix(vcpu);
+	case 0x11:
+		return handle_store_prefix(vcpu);
+	case 0x12:
+		return handle_store_cpu_address(vcpu);
+	case 0x14:
+		return kvm_s390_handle_vsie(vcpu);
+	case 0x21:
+	case 0x50:
+		return handle_ipte_interlock(vcpu);
+	case 0x29:
+		return handle_iske(vcpu);
+	case 0x2a:
+		return handle_rrbe(vcpu);
+	case 0x2b:
+		return handle_sske(vcpu);
+	case 0x2c:
+		return handle_test_block(vcpu);
+	case 0x30:
+	case 0x31:
+	case 0x32:
+	case 0x33:
+	case 0x34:
+	case 0x35:
+	case 0x36:
+	case 0x37:
+	case 0x38:
+	case 0x39:
+	case 0x3a:
+	case 0x3b:
+	case 0x3c:
+	case 0x5f:
+	case 0x74:
+	case 0x76:
+		return handle_io_inst(vcpu);
+	case 0x56:
+		return handle_sthyi(vcpu);
+	case 0x7d:
+		return handle_stsi(vcpu);
+	case 0xb1:
+		return handle_stfl(vcpu);
+	case 0xb2:
+		return handle_lpswe(vcpu);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int handle_epsw(struct kvm_vcpu *vcpu)
@@ -1105,25 +1110,22 @@ static int handle_essa(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
-static const intercept_handler_t b9_handlers[256] = {
-	[0x8a] = handle_ipte_interlock,
-	[0x8d] = handle_epsw,
-	[0x8e] = handle_ipte_interlock,
-	[0x8f] = handle_ipte_interlock,
-	[0xab] = handle_essa,
-	[0xaf] = handle_pfmf,
-};
-
 int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
 {
-	intercept_handler_t handler;
-
-	/* This is handled just as for the B2 instructions. */
-	handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-	if (handler)
-		return handler(vcpu);
-
-	return -EOPNOTSUPP;
+	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+	case 0x8a:
+	case 0x8e:
+	case 0x8f:
+		return handle_ipte_interlock(vcpu);
+	case 0x8d:
+		return handle_epsw(vcpu);
+	case 0xab:
+		return handle_essa(vcpu);
+	case 0xaf:
+		return handle_pfmf(vcpu);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu)
@@ -1271,22 +1273,20 @@ static int handle_stctg(struct kvm_vcpu *vcpu)
 	return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0;
 }
 
-static const intercept_handler_t eb_handlers[256] = {
-	[0x2f] = handle_lctlg,
-	[0x25] = handle_stctg,
-	[0x60] = handle_ri,
-	[0x61] = handle_ri,
-	[0x62] = handle_ri,
-};
-
 int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
 {
-	intercept_handler_t handler;
-
-	handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
-	if (handler)
-		return handler(vcpu);
-	return -EOPNOTSUPP;
+	switch (vcpu->arch.sie_block->ipb & 0x000000ff) {
+	case 0x25:
+		return handle_stctg(vcpu);
+	case 0x2f:
+		return handle_lctlg(vcpu);
+	case 0x60:
+	case 0x61:
+	case 0x62:
+		return handle_ri(vcpu);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int handle_tprot(struct kvm_vcpu *vcpu)
@@ -1346,10 +1346,12 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
 
 int kvm_s390_handle_e5(struct kvm_vcpu *vcpu)
 {
-	/* For e5xx... instructions we only handle TPROT */
-	if ((vcpu->arch.sie_block->ipa & 0x00ff) == 0x01)
+	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+	case 0x01:
 		return handle_tprot(vcpu);
-	return -EOPNOTSUPP;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int handle_sckpf(struct kvm_vcpu *vcpu)
@@ -1380,17 +1382,14 @@ static int handle_ptff(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
-static const intercept_handler_t x01_handlers[256] = {
-	[0x04] = handle_ptff,
-	[0x07] = handle_sckpf,
-};
-
 int kvm_s390_handle_01(struct kvm_vcpu *vcpu)
 {
-	intercept_handler_t handler;
-
-	handler = x01_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-	if (handler)
-		return handler(vcpu);
-	return -EOPNOTSUPP;
+	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+	case 0x04:
+		return handle_ptff(vcpu);
+	case 0x07:
+		return handle_sckpf(vcpu);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index ec772700ff96..8961e3970901 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -821,6 +821,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 {
 	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
 	struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+	int guest_bp_isolation;
 	int rc;
 
 	handle_last_fault(vcpu, vsie_page);
@@ -831,6 +832,20 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 		s390_handle_mcck();
 
 	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+
+	/* save current guest state of bp isolation override */
+	guest_bp_isolation = test_thread_flag(TIF_ISOLATE_BP_GUEST);
+
+	/*
+	 * The guest is running with BPBC, so we have to force it on for our
+	 * nested guest. This is done by enabling BPBC globally, so the BPBC
+	 * control in the SCB (which the nested guest can modify) is simply
+	 * ignored.
+	 */
+	if (test_kvm_facility(vcpu->kvm, 82) &&
+	    vcpu->arch.sie_block->fpf & FPF_BPBC)
+		set_thread_flag(TIF_ISOLATE_BP_GUEST);
+
 	local_irq_disable();
 	guest_enter_irqoff();
 	local_irq_enable();
@@ -840,6 +855,11 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	local_irq_disable();
 	guest_exit_irqoff();
 	local_irq_enable();
+
+	/* restore guest state for bp isolation override */
+	if (!guest_bp_isolation)
+		clear_thread_flag(TIF_ISOLATE_BP_GUEST);
+
 	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
 
 	if (rc == -EINTR) {
diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c
index cb364153c43c..562f72955956 100644
--- a/arch/s390/mm/pgalloc.c
+++ b/arch/s390/mm/pgalloc.c
@@ -6,8 +6,9 @@
  *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
-#include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/gmap.h>
@@ -366,3 +367,293 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)
 	if ((*batch)->nr == MAX_TABLE_BATCH)
 		tlb_flush_mmu(tlb);
 }
+
+/*
+ * Base infrastructure required to generate basic asces, region, segment,
+ * and page tables that do not make use of enhanced features like EDAT1.
+ */
+
+static struct kmem_cache *base_pgt_cache;
+
+static unsigned long base_pgt_alloc(void)
+{
+	u64 *table;
+
+	table = kmem_cache_alloc(base_pgt_cache, GFP_KERNEL);
+	if (table)
+		memset64(table, _PAGE_INVALID, PTRS_PER_PTE);
+	return (unsigned long) table;
+}
+
+static void base_pgt_free(unsigned long table)
+{
+	kmem_cache_free(base_pgt_cache, (void *) table);
+}
+
+static unsigned long base_crst_alloc(unsigned long val)
+{
+	unsigned long table;
+
+	table =	 __get_free_pages(GFP_KERNEL, CRST_ALLOC_ORDER);
+	if (table)
+		crst_table_init((unsigned long *)table, val);
+	return table;
+}
+
+static void base_crst_free(unsigned long table)
+{
+	free_pages(table, CRST_ALLOC_ORDER);
+}
+
+#define BASE_ADDR_END_FUNC(NAME, SIZE)					\
+static inline unsigned long base_##NAME##_addr_end(unsigned long addr,	\
+						   unsigned long end)	\
+{									\
+	unsigned long next = (addr + (SIZE)) & ~((SIZE) - 1);		\
+									\
+	return (next - 1) < (end - 1) ? next : end;			\
+}
+
+BASE_ADDR_END_FUNC(page,    _PAGE_SIZE)
+BASE_ADDR_END_FUNC(segment, _SEGMENT_SIZE)
+BASE_ADDR_END_FUNC(region3, _REGION3_SIZE)
+BASE_ADDR_END_FUNC(region2, _REGION2_SIZE)
+BASE_ADDR_END_FUNC(region1, _REGION1_SIZE)
+
+static inline unsigned long base_lra(unsigned long address)
+{
+	unsigned long real;
+
+	asm volatile(
+		"	lra	%0,0(%1)\n"
+		: "=d" (real) : "a" (address) : "cc");
+	return real;
+}
+
+static int base_page_walk(unsigned long origin, unsigned long addr,
+			  unsigned long end, int alloc)
+{
+	unsigned long *pte, next;
+
+	if (!alloc)
+		return 0;
+	pte = (unsigned long *) origin;
+	pte += (addr & _PAGE_INDEX) >> _PAGE_SHIFT;
+	do {
+		next = base_page_addr_end(addr, end);
+		*pte = base_lra(addr);
+	} while (pte++, addr = next, addr < end);
+	return 0;
+}
+
+static int base_segment_walk(unsigned long origin, unsigned long addr,
+			     unsigned long end, int alloc)
+{
+	unsigned long *ste, next, table;
+	int rc;
+
+	ste = (unsigned long *) origin;
+	ste += (addr & _SEGMENT_INDEX) >> _SEGMENT_SHIFT;
+	do {
+		next = base_segment_addr_end(addr, end);
+		if (*ste & _SEGMENT_ENTRY_INVALID) {
+			if (!alloc)
+				continue;
+			table = base_pgt_alloc();
+			if (!table)
+				return -ENOMEM;
+			*ste = table | _SEGMENT_ENTRY;
+		}
+		table = *ste & _SEGMENT_ENTRY_ORIGIN;
+		rc = base_page_walk(table, addr, next, alloc);
+		if (rc)
+			return rc;
+		if (!alloc)
+			base_pgt_free(table);
+		cond_resched();
+	} while (ste++, addr = next, addr < end);
+	return 0;
+}
+
+static int base_region3_walk(unsigned long origin, unsigned long addr,
+			     unsigned long end, int alloc)
+{
+	unsigned long *rtte, next, table;
+	int rc;
+
+	rtte = (unsigned long *) origin;
+	rtte += (addr & _REGION3_INDEX) >> _REGION3_SHIFT;
+	do {
+		next = base_region3_addr_end(addr, end);
+		if (*rtte & _REGION_ENTRY_INVALID) {
+			if (!alloc)
+				continue;
+			table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY);
+			if (!table)
+				return -ENOMEM;
+			*rtte = table | _REGION3_ENTRY;
+		}
+		table = *rtte & _REGION_ENTRY_ORIGIN;
+		rc = base_segment_walk(table, addr, next, alloc);
+		if (rc)
+			return rc;
+		if (!alloc)
+			base_crst_free(table);
+	} while (rtte++, addr = next, addr < end);
+	return 0;
+}
+
+static int base_region2_walk(unsigned long origin, unsigned long addr,
+			     unsigned long end, int alloc)
+{
+	unsigned long *rste, next, table;
+	int rc;
+
+	rste = (unsigned long *) origin;
+	rste += (addr & _REGION2_INDEX) >> _REGION2_SHIFT;
+	do {
+		next = base_region2_addr_end(addr, end);
+		if (*rste & _REGION_ENTRY_INVALID) {
+			if (!alloc)
+				continue;
+			table = base_crst_alloc(_REGION3_ENTRY_EMPTY);
+			if (!table)
+				return -ENOMEM;
+			*rste = table | _REGION2_ENTRY;
+		}
+		table = *rste & _REGION_ENTRY_ORIGIN;
+		rc = base_region3_walk(table, addr, next, alloc);
+		if (rc)
+			return rc;
+		if (!alloc)
+			base_crst_free(table);
+	} while (rste++, addr = next, addr < end);
+	return 0;
+}
+
+static int base_region1_walk(unsigned long origin, unsigned long addr,
+			     unsigned long end, int alloc)
+{
+	unsigned long *rfte, next, table;
+	int rc;
+
+	rfte = (unsigned long *) origin;
+	rfte += (addr & _REGION1_INDEX) >> _REGION1_SHIFT;
+	do {
+		next = base_region1_addr_end(addr, end);
+		if (*rfte & _REGION_ENTRY_INVALID) {
+			if (!alloc)
+				continue;
+			table = base_crst_alloc(_REGION2_ENTRY_EMPTY);
+			if (!table)
+				return -ENOMEM;
+			*rfte = table | _REGION1_ENTRY;
+		}
+		table = *rfte & _REGION_ENTRY_ORIGIN;
+		rc = base_region2_walk(table, addr, next, alloc);
+		if (rc)
+			return rc;
+		if (!alloc)
+			base_crst_free(table);
+	} while (rfte++, addr = next, addr < end);
+	return 0;
+}
+
+/**
+ * base_asce_free - free asce and tables returned from base_asce_alloc()
+ * @asce: asce to be freed
+ *
+ * Frees all region, segment, and page tables that were allocated with a
+ * corresponding base_asce_alloc() call.
+ */
+void base_asce_free(unsigned long asce)
+{
+	unsigned long table = asce & _ASCE_ORIGIN;
+
+	if (!asce)
+		return;
+	switch (asce & _ASCE_TYPE_MASK) {
+	case _ASCE_TYPE_SEGMENT:
+		base_segment_walk(table, 0, _REGION3_SIZE, 0);
+		break;
+	case _ASCE_TYPE_REGION3:
+		base_region3_walk(table, 0, _REGION2_SIZE, 0);
+		break;
+	case _ASCE_TYPE_REGION2:
+		base_region2_walk(table, 0, _REGION1_SIZE, 0);
+		break;
+	case _ASCE_TYPE_REGION1:
+		base_region1_walk(table, 0, -_PAGE_SIZE, 0);
+		break;
+	}
+	base_crst_free(table);
+}
+
+static int base_pgt_cache_init(void)
+{
+	static DEFINE_MUTEX(base_pgt_cache_mutex);
+	unsigned long sz = _PAGE_TABLE_SIZE;
+
+	if (base_pgt_cache)
+		return 0;
+	mutex_lock(&base_pgt_cache_mutex);
+	if (!base_pgt_cache)
+		base_pgt_cache = kmem_cache_create("base_pgt", sz, sz, 0, NULL);
+	mutex_unlock(&base_pgt_cache_mutex);
+	return base_pgt_cache ? 0 : -ENOMEM;
+}
+
+/**
+ * base_asce_alloc - create kernel mapping without enhanced DAT features
+ * @addr: virtual start address of kernel mapping
+ * @num_pages: number of consecutive pages
+ *
+ * Generate an asce, including all required region, segment and page tables,
+ * that can be used to access the virtual kernel mapping. The difference is
+ * that the returned asce does not make use of any enhanced DAT features like
+ * e.g. large pages. This is required for some I/O functions that pass an
+ * asce, like e.g. some service call requests.
+ *
+ * Note: the returned asce may NEVER be attached to any cpu. It may only be
+ *	 used for I/O requests. tlb entries that might result because the
+ *	 asce was attached to a cpu won't be cleared.
+ */
+unsigned long base_asce_alloc(unsigned long addr, unsigned long num_pages)
+{
+	unsigned long asce, table, end;
+	int rc;
+
+	if (base_pgt_cache_init())
+		return 0;
+	end = addr + num_pages * PAGE_SIZE;
+	if (end <= _REGION3_SIZE) {
+		table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY);
+		if (!table)
+			return 0;
+		rc = base_segment_walk(table, addr, end, 1);
+		asce = table | _ASCE_TYPE_SEGMENT | _ASCE_TABLE_LENGTH;
+	} else if (end <= _REGION2_SIZE) {
+		table = base_crst_alloc(_REGION3_ENTRY_EMPTY);
+		if (!table)
+			return 0;
+		rc = base_region3_walk(table, addr, end, 1);
+		asce = table | _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
+	} else if (end <= _REGION1_SIZE) {
+		table = base_crst_alloc(_REGION2_ENTRY_EMPTY);
+		if (!table)
+			return 0;
+		rc = base_region2_walk(table, addr, end, 1);
+		asce = table | _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
+	} else {
+		table = base_crst_alloc(_REGION1_ENTRY_EMPTY);
+		if (!table)
+			return 0;
+		rc = base_region1_walk(table, addr, end, 1);
+		asce = table | _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH;
+	}
+	if (rc) {
+		base_asce_free(asce);
+		asce = 0;
+	}
+	return asce;
+}
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 5deb2d82f19f..6af7777332fc 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -375,8 +375,8 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
 static struct tmio_mmc_data sh7724_sdhi0_data = {
 	.chan_priv_tx	= (void *)SHDMA_SLAVE_SDHI0_TX,
 	.chan_priv_rx	= (void *)SHDMA_SLAVE_SDHI0_RX,
-	.flags		= TMIO_MMC_WRPROTECT_DISABLE,
 	.capabilities	= MMC_CAP_SDIO_IRQ,
+	.capabilities2	= MMC_CAP2_NO_WRITE_PROTECT,
 };
 
 static struct platform_device kfr2r09_sh_sdhi0_device = {
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile
index 715def00a436..01d0f7fb14cc 100644
--- a/arch/sh/boot/dts/Makefile
+++ b/arch/sh/boot/dts/Makefile
@@ -1 +1,3 @@
-obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+ifneq ($(CONFIG_BUILTIN_DTB_SOURCE),"")
+obj-y += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+endif
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index 15bf07bfa96b..6d192f4908a7 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -37,10 +37,7 @@ static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
 	pagefault_disable();
 
 	do {
-		if (op == FUTEX_OP_SET)
-			ret = oldval = 0;
-		else
-			ret = get_user(oldval, uaddr);
+		ret = get_user(oldval, uaddr);
 
 		if (ret) break;
 
diff --git a/arch/sparc/include/asm/bug.h b/arch/sparc/include/asm/bug.h
index 6f17528356b2..ea53e418f6c0 100644
--- a/arch/sparc/include/asm/bug.h
+++ b/arch/sparc/include/asm/bug.h
@@ -9,10 +9,14 @@
 void do_BUG(const char *file, int line);
 #define BUG() do {					\
 	do_BUG(__FILE__, __LINE__);			\
+	barrier_before_unreachable();			\
 	__builtin_trap();				\
 } while (0)
 #else
-#define BUG()		__builtin_trap()
+#define BUG() do {					\
+	barrier_before_unreachable();			\
+	__builtin_trap();				\
+} while (0)
 #endif
 
 #define HAVE_ARCH_BUG
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 220d0f36560a..41b20edb427d 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -664,12 +664,12 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
 	printk("PCI: Scanning PBM %s\n", node->full_name);
 
 	pci_add_resource_offset(&resources, &pbm->io_space,
-				pbm->io_space.start);
+				pbm->io_offset);
 	pci_add_resource_offset(&resources, &pbm->mem_space,
-				pbm->mem_space.start);
+				pbm->mem_offset);
 	if (pbm->mem64_space.flags)
 		pci_add_resource_offset(&resources, &pbm->mem64_space,
-					pbm->mem_space.start);
+					pbm->mem64_offset);
 	pbm->busn.start = pbm->pci_first_busno;
 	pbm->busn.end	= pbm->pci_last_busno;
 	pbm->busn.flags	= IORESOURCE_BUS;
diff --git a/arch/sparc/kernel/pci_common.c b/arch/sparc/kernel/pci_common.c
index 1e10fb26fa88..38d46bcc8634 100644
--- a/arch/sparc/kernel/pci_common.c
+++ b/arch/sparc/kernel/pci_common.c
@@ -344,26 +344,6 @@ static void pci_register_legacy_regions(struct resource *io_res,
 	p->end = p->start + 0x1ffffUL;
 	p->flags = IORESOURCE_BUSY;
 	request_resource(mem_res, p);
-
-	p = kzalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return;
-
-	p->name = "System ROM";
-	p->start = mem_res->start + 0xf0000UL;
-	p->end = p->start + 0xffffUL;
-	p->flags = IORESOURCE_BUSY;
-	request_resource(mem_res, p);
-
-	p = kzalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return;
-
-	p->name = "Video ROM";
-	p->start = mem_res->start + 0xc0000UL;
-	p->end = p->start + 0x7fffUL;
-	p->flags = IORESOURCE_BUSY;
-	request_resource(mem_res, p);
 }
 
 static void pci_register_iommu_region(struct pci_pbm_info *pbm)
@@ -397,6 +377,8 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 	int i, saw_mem, saw_io;
 	int num_pbm_ranges;
 
+	/* Corresponding generic code in of_pci_get_host_bridge_resources() */
+
 	saw_mem = saw_io = 0;
 	pbm_ranges = of_get_property(pbm->op->dev.of_node, "ranges", &i);
 	if (!pbm_ranges) {
@@ -411,13 +393,16 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 
 	for (i = 0; i < num_pbm_ranges; i++) {
 		const struct linux_prom_pci_ranges *pr = &pbm_ranges[i];
-		unsigned long a, size;
+		unsigned long a, size, region_a;
 		u32 parent_phys_hi, parent_phys_lo;
+		u32 child_phys_mid, child_phys_lo;
 		u32 size_hi, size_lo;
 		int type;
 
 		parent_phys_hi = pr->parent_phys_hi;
 		parent_phys_lo = pr->parent_phys_lo;
+		child_phys_mid = pr->child_phys_mid;
+		child_phys_lo = pr->child_phys_lo;
 		if (tlb_type == hypervisor)
 			parent_phys_hi &= 0x0fffffff;
 
@@ -427,6 +412,8 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 		type = (pr->child_phys_hi >> 24) & 0x3;
 		a = (((unsigned long)parent_phys_hi << 32UL) |
 		     ((unsigned long)parent_phys_lo  <<  0UL));
+		region_a = (((unsigned long)child_phys_mid << 32UL) |
+		     ((unsigned long)child_phys_lo  <<  0UL));
 		size = (((unsigned long)size_hi << 32UL) |
 			((unsigned long)size_lo  <<  0UL));
 
@@ -441,6 +428,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 			pbm->io_space.start = a;
 			pbm->io_space.end = a + size - 1UL;
 			pbm->io_space.flags = IORESOURCE_IO;
+			pbm->io_offset = a - region_a;
 			saw_io = 1;
 			break;
 
@@ -449,6 +437,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 			pbm->mem_space.start = a;
 			pbm->mem_space.end = a + size - 1UL;
 			pbm->mem_space.flags = IORESOURCE_MEM;
+			pbm->mem_offset = a - region_a;
 			saw_mem = 1;
 			break;
 
@@ -457,6 +446,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 			pbm->mem64_space.start = a;
 			pbm->mem64_space.end = a + size - 1UL;
 			pbm->mem64_space.flags = IORESOURCE_MEM;
+			pbm->mem64_offset = a - region_a;
 			saw_mem = 1;
 			break;
 
@@ -472,14 +462,22 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 		prom_halt();
 	}
 
-	printk("%s: PCI IO[%llx] MEM[%llx]",
-	       pbm->name,
-	       pbm->io_space.start,
-	       pbm->mem_space.start);
+	if (pbm->io_space.flags)
+		printk("%s: PCI IO %pR offset %llx\n",
+		       pbm->name, &pbm->io_space, pbm->io_offset);
+	if (pbm->mem_space.flags)
+		printk("%s: PCI MEM %pR offset %llx\n",
+		       pbm->name, &pbm->mem_space, pbm->mem_offset);
+	if (pbm->mem64_space.flags && pbm->mem_space.flags) {
+		if (pbm->mem64_space.start <= pbm->mem_space.end)
+			pbm->mem64_space.start = pbm->mem_space.end + 1;
+		if (pbm->mem64_space.start > pbm->mem64_space.end)
+			pbm->mem64_space.flags = 0;
+	}
+
 	if (pbm->mem64_space.flags)
-		printk(" MEM64[%llx]",
-		       pbm->mem64_space.start);
-	printk("\n");
+		printk("%s: PCI MEM64 %pR offset %llx\n",
+		       pbm->name, &pbm->mem64_space, pbm->mem64_offset);
 
 	pbm->io_space.name = pbm->mem_space.name = pbm->name;
 	pbm->mem64_space.name = pbm->name;
diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h
index ac172961d276..4e3d15189fa9 100644
--- a/arch/sparc/kernel/pci_impl.h
+++ b/arch/sparc/kernel/pci_impl.h
@@ -100,6 +100,10 @@ struct pci_pbm_info {
 	struct resource			mem_space;
 	struct resource			mem64_space;
 	struct resource			busn;
+	/* offset */
+	resource_size_t			io_offset;
+	resource_size_t			mem_offset;
+	resource_size_t			mem64_offset;
 
 	/* Base of PCI Config space, can be per-PBM or shared. */
 	unsigned long			config_space;
diff --git a/arch/sparc/lib/NG4memset.S b/arch/sparc/lib/NG4memset.S
index f81ee5419e2c..d0c4d195fd40 100644
--- a/arch/sparc/lib/NG4memset.S
+++ b/arch/sparc/lib/NG4memset.S
@@ -14,14 +14,14 @@
 	.globl		NG4memset
 NG4memset:
 	andcc		%o1, 0xff, %o4
-	be,pt		%icc, 1f
+	be,pt		%xcc, 1f
 	 mov		%o2, %o1
 	sllx		%o4, 8, %g1
 	or		%g1, %o4, %o2
 	sllx		%o2, 16, %g1
 	or		%g1, %o2, %o2
 	sllx		%o2, 32, %g1
-	ba,pt		%icc, 1f
+	ba,pt		%xcc, 1f
 	 or		%g1, %o2, %o4
 	.size		NG4memset,.-NG4memset
 
@@ -30,7 +30,7 @@ NG4memset:
 NG4bzero:
 	clr		%o4
 1:	cmp		%o1, 16
-	ble		%icc, .Ltiny
+	ble		%xcc, .Ltiny
 	 mov		%o0, %o3
 	sub		%g0, %o0, %g1
 	and		%g1, 0x7, %g1
@@ -38,7 +38,7 @@ NG4bzero:
 	 sub		%o1, %g1, %o1
 1:	stb		%o4, [%o0 + 0x00]
 	subcc		%g1, 1, %g1
-	bne,pt		%icc, 1b
+	bne,pt		%xcc, 1b
 	 add		%o0, 1, %o0
 .Laligned8:
 	cmp		%o1, 64 + (64 - 8)
@@ -49,7 +49,7 @@ NG4bzero:
 	 sub		%o1, %g1, %o1
 1:	stx		%o4, [%o0 + 0x00]
 	subcc		%g1, 8, %g1
-	bne,pt		%icc, 1b
+	bne,pt		%xcc, 1b
 	 add		%o0, 0x8, %o0
 .Laligned64:
 	andn		%o1, 64 - 1, %g1
@@ -59,30 +59,30 @@ NG4bzero:
 1:	stxa		%o4, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
 	subcc		%g1, 0x40, %g1
 	stxa		%o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
-	bne,pt		%icc, 1b
+	bne,pt		%xcc, 1b
 	 add		%o0, 0x40, %o0
 .Lpostloop:
 	cmp		%o1, 8
-	bl,pn		%icc, .Ltiny
+	bl,pn		%xcc, .Ltiny
 	 membar		#StoreStore|#StoreLoad
 .Lmedium:
 	andn		%o1, 0x7, %g1
 	sub		%o1, %g1, %o1
 1:	stx		%o4, [%o0 + 0x00]
 	subcc		%g1, 0x8, %g1
-	bne,pt		%icc, 1b
+	bne,pt		%xcc, 1b
 	 add		%o0, 0x08, %o0
 	andcc		%o1, 0x4, %g1
-	be,pt		%icc, .Ltiny
+	be,pt		%xcc, .Ltiny
 	 sub		%o1, %g1, %o1
 	stw		%o4, [%o0 + 0x00]
 	add		%o0, 0x4, %o0
 .Ltiny:
 	cmp		%o1, 0
-	be,pn		%icc, .Lexit
+	be,pn		%xcc, .Lexit
 1:	 subcc		%o1, 1, %o1
 	stb		%o4, [%o0 + 0x00]
-	bne,pt		%icc, 1b
+	bne,pt		%xcc, 1b
 	 add		%o0, 1, %o0
 .Lexit:
 	retl
@@ -100,8 +100,8 @@ NG4bzero:
 	stxa		%o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
 	stxa		%o4, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
 	stxa		%o4, [%o0 + %o5] ASI_BLK_INIT_QUAD_LDD_P
-	bne,pt		%icc, 1b
+	bne,pt		%xcc, 1b
 	 add		%o0, 0x30, %o0
-	ba,a,pt		%icc, .Lpostloop
+	ba,a,pt		%xcc, .Lpostloop
 	 nop
 	.size		NG4bzero,.-NG4bzero
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 995f9490334d..a9f94e911e0a 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -3089,6 +3089,20 @@ static struct resource bss_resource = {
 	.flags	= IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM
 };
 
+static struct resource system_rom_resource = {
+	.name	= "System ROM",
+	.start  = 0xf0000,
+	.end    = 0xfffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource video_rom_resource = {
+	.name	= "Video ROM",
+	.start  = 0xc0000,
+	.end    = 0xc7fff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
 static inline resource_size_t compute_kern_paddr(void *addr)
 {
 	return (resource_size_t) (addr - KERNBASE + kern_base);
@@ -3134,6 +3148,9 @@ static int __init report_memory(void)
 		insert_resource(res, &bss_resource);
 	}
 
+	request_resource(&iomem_resource, &system_rom_resource);
+	request_resource(&iomem_resource, &video_rom_resource);
+
 	return 0;
 }
 arch_initcall(report_memory);
diff --git a/arch/um/Kconfig.net b/arch/um/Kconfig.net
index e871af24d9cd..c390f3deb0dc 100644
--- a/arch/um/Kconfig.net
+++ b/arch/um/Kconfig.net
@@ -109,6 +109,17 @@ config UML_NET_DAEMON
         more than one without conflict.  If you don't need UML networking,
         say N.
 
+config UML_NET_VECTOR
+	bool "Vector I/O high performance network devices"
+	depends on UML_NET
+	help
+	This User-Mode Linux network driver uses multi-message send
+	and receive functions. The host running the UML guest must have
+	a linux kernel version above 3.0 and a libc version > 2.13.
+	This driver provides tap, raw, gre and l2tpv3 network transports
+	with up to 4 times higher network throughput than the UML network
+	drivers.
+
 config UML_NET_VDE
 	bool "VDE transport"
 	depends on UML_NET
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index e7582e1d248c..16b3cebddafb 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -9,6 +9,7 @@
 slip-objs := slip_kern.o slip_user.o
 slirp-objs := slirp_kern.o slirp_user.o
 daemon-objs := daemon_kern.o daemon_user.o
+vector-objs := vector_kern.o vector_user.o vector_transports.o
 umcast-objs := umcast_kern.o umcast_user.o
 net-objs := net_kern.o net_user.o
 mconsole-objs := mconsole_kern.o mconsole_user.o
@@ -43,6 +44,7 @@ obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
 obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
 obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
 obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
+obj-$(CONFIG_UML_NET_VECTOR) += vector.o
 obj-$(CONFIG_UML_NET_VDE) += vde.o
 obj-$(CONFIG_UML_NET_MCAST) += umcast.o
 obj-$(CONFIG_UML_NET_PCAP) += pcap.o
@@ -61,7 +63,7 @@ obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
 obj-$(CONFIG_UML_RANDOM) += random.o
 
 # pcap_user.o must be added explicitly.
-USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o
+USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o
 CFLAGS_null.o = -DDEV_NULL=$(DEV_NULL_PATH)
 
 include arch/um/scripts/Makefile.rules
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index acbe6c67afba..05588f9466c7 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -171,56 +171,19 @@ int enable_chan(struct line *line)
 	return err;
 }
 
-/* Items are added in IRQ context, when free_irq can't be called, and
- * removed in process context, when it can.
- * This handles interrupt sources which disappear, and which need to
- * be permanently disabled.  This is discovered in IRQ context, but
- * the freeing of the IRQ must be done later.
- */
-static DEFINE_SPINLOCK(irqs_to_free_lock);
-static LIST_HEAD(irqs_to_free);
-
-void free_irqs(void)
-{
-	struct chan *chan;
-	LIST_HEAD(list);
-	struct list_head *ele;
-	unsigned long flags;
-
-	spin_lock_irqsave(&irqs_to_free_lock, flags);
-	list_splice_init(&irqs_to_free, &list);
-	spin_unlock_irqrestore(&irqs_to_free_lock, flags);
-
-	list_for_each(ele, &list) {
-		chan = list_entry(ele, struct chan, free_list);
-
-		if (chan->input && chan->enabled)
-			um_free_irq(chan->line->driver->read_irq, chan);
-		if (chan->output && chan->enabled)
-			um_free_irq(chan->line->driver->write_irq, chan);
-		chan->enabled = 0;
-	}
-}
-
 static void close_one_chan(struct chan *chan, int delay_free_irq)
 {
-	unsigned long flags;
-
 	if (!chan->opened)
 		return;
 
-	if (delay_free_irq) {
-		spin_lock_irqsave(&irqs_to_free_lock, flags);
-		list_add(&chan->free_list, &irqs_to_free);
-		spin_unlock_irqrestore(&irqs_to_free_lock, flags);
-	}
-	else {
-		if (chan->input && chan->enabled)
-			um_free_irq(chan->line->driver->read_irq, chan);
-		if (chan->output && chan->enabled)
-			um_free_irq(chan->line->driver->write_irq, chan);
-		chan->enabled = 0;
-	}
+    /* we can safely call free now - it will be marked
+     *  as free and freed once the IRQ stopped processing
+     */
+	if (chan->input && chan->enabled)
+		um_free_irq(chan->line->driver->read_irq, chan);
+	if (chan->output && chan->enabled)
+		um_free_irq(chan->line->driver->write_irq, chan);
+	chan->enabled = 0;
 	if (chan->ops->close != NULL)
 		(*chan->ops->close)(chan->fd, chan->data);
 
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 366e57f5e8d6..8d80b27502e6 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -284,7 +284,7 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
 	if (err)
 		return err;
 	if (output)
-		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
+		err = um_request_irq(driver->write_irq, fd, IRQ_NONE,
 				     line_write_interrupt, IRQF_SHARED,
 				     driver->write_irq_name, data);
 	return err;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index b305f8247909..3ef1b48e064a 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -288,7 +288,7 @@ static void uml_net_user_timer_expire(struct timer_list *t)
 #endif
 }
 
-static void setup_etheraddr(struct net_device *dev, char *str)
+void uml_net_setup_etheraddr(struct net_device *dev, char *str)
 {
 	unsigned char *addr = dev->dev_addr;
 	char *end;
@@ -412,7 +412,7 @@ static void eth_configure(int n, void *init, char *mac,
 	 */
 	snprintf(dev->name, sizeof(dev->name), "eth%d", n);
 
-	setup_etheraddr(dev, mac);
+	uml_net_setup_etheraddr(dev, mac);
 
 	printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr);
 
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index 37c51a6be690..778a0e52d5a5 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -13,6 +13,7 @@
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
 #include <linux/uaccess.h>
+#include <init.h>
 #include <irq_kern.h>
 #include <os.h>
 
@@ -154,7 +155,14 @@ static int __init rng_init (void)
 /*
  * rng_cleanup - shutdown RNG module
  */
-static void __exit rng_cleanup (void)
+
+static void cleanup(void)
+{
+	free_irq_by_fd(random_fd);
+	os_close_file(random_fd);
+}
+
+static void __exit rng_cleanup(void)
 {
 	os_close_file(random_fd);
 	misc_deregister (&rng_miscdev);
@@ -162,6 +170,7 @@ static void __exit rng_cleanup (void)
 
 module_init (rng_init);
 module_exit (rng_cleanup);
+__uml_exitcall(cleanup);
 
 MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
 MODULE_LICENSE("GPL");
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index b55fe9bf5d3e..d4e8c497ae86 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -1587,11 +1587,11 @@ int io_thread(void *arg)
 
 		do {
 			res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
-			if (res > 0) {
+			if (res >= 0) {
 				written += res;
 			} else {
 				if (res != -EAGAIN) {
-					printk("io_thread - read failed, fd = %d, "
+					printk("io_thread - write failed, fd = %d, "
 					       "err = %d\n", kernel_fd, -n);
 				}
 			}
diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c
new file mode 100644
index 000000000000..4daa4fe18ad7
--- /dev/null
+++ b/arch/um/drivers/vector_kern.c
@@ -0,0 +1,1632 @@
+/*
+ * Copyright (C) 2017 - Cambridge Greys Limited
+ * Copyright (C) 2011 - 2014 Cisco Systems Inc
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include <linux/version.h>
+#include <linux/bootmem.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/inetdevice.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <init.h>
+#include <irq_kern.h>
+#include <irq_user.h>
+#include <net_kern.h>
+#include <os.h>
+#include "mconsole_kern.h"
+#include "vector_user.h"
+#include "vector_kern.h"
+
+/*
+ * Adapted from network devices with the following major changes:
+ * All transports are static - simplifies the code significantly
+ * Multiple FDs/IRQs per device
+ * Vector IO optionally used for read/write, falling back to legacy
+ * based on configuration and/or availability
+ * Configuration is no longer positional - L2TPv3 and GRE require up to
+ * 10 parameters, passing this as positional is not fit for purpose.
+ * Only socket transports are supported
+ */
+
+
+#define DRIVER_NAME "uml-vector"
+#define DRIVER_VERSION "01"
+struct vector_cmd_line_arg {
+	struct list_head list;
+	int unit;
+	char *arguments;
+};
+
+struct vector_device {
+	struct list_head list;
+	struct net_device *dev;
+	struct platform_device pdev;
+	int unit;
+	int opened;
+};
+
+static LIST_HEAD(vec_cmd_line);
+
+static DEFINE_SPINLOCK(vector_devices_lock);
+static LIST_HEAD(vector_devices);
+
+static int driver_registered;
+
+static void vector_eth_configure(int n, struct arglist *def);
+
+/* Argument accessors to set variables (and/or set default values)
+ * mtu, buffer sizing, default headroom, etc
+ */
+
+#define DEFAULT_HEADROOM 2
+#define SAFETY_MARGIN 32
+#define DEFAULT_VECTOR_SIZE 64
+#define TX_SMALL_PACKET 128
+#define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1)
+
+static const struct {
+	const char string[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "rx_queue_max" },
+	{ "rx_queue_running_average" },
+	{ "tx_queue_max" },
+	{ "tx_queue_running_average" },
+	{ "rx_encaps_errors" },
+	{ "tx_timeout_count" },
+	{ "tx_restart_queue" },
+	{ "tx_kicks" },
+	{ "tx_flow_control_xon" },
+	{ "tx_flow_control_xoff" },
+	{ "rx_csum_offload_good" },
+	{ "rx_csum_offload_errors"},
+	{ "sg_ok"},
+	{ "sg_linearized"},
+};
+
+#define VECTOR_NUM_STATS	ARRAY_SIZE(ethtool_stats_keys)
+
+static void vector_reset_stats(struct vector_private *vp)
+{
+	vp->estats.rx_queue_max = 0;
+	vp->estats.rx_queue_running_average = 0;
+	vp->estats.tx_queue_max = 0;
+	vp->estats.tx_queue_running_average = 0;
+	vp->estats.rx_encaps_errors = 0;
+	vp->estats.tx_timeout_count = 0;
+	vp->estats.tx_restart_queue = 0;
+	vp->estats.tx_kicks = 0;
+	vp->estats.tx_flow_control_xon = 0;
+	vp->estats.tx_flow_control_xoff = 0;
+	vp->estats.sg_ok = 0;
+	vp->estats.sg_linearized = 0;
+}
+
+static int get_mtu(struct arglist *def)
+{
+	char *mtu = uml_vector_fetch_arg(def, "mtu");
+	long result;
+
+	if (mtu != NULL) {
+		if (kstrtoul(mtu, 10, &result) == 0)
+			return result;
+	}
+	return ETH_MAX_PACKET;
+}
+
+static int get_depth(struct arglist *def)
+{
+	char *mtu = uml_vector_fetch_arg(def, "depth");
+	long result;
+
+	if (mtu != NULL) {
+		if (kstrtoul(mtu, 10, &result) == 0)
+			return result;
+	}
+	return DEFAULT_VECTOR_SIZE;
+}
+
+static int get_headroom(struct arglist *def)
+{
+	char *mtu = uml_vector_fetch_arg(def, "headroom");
+	long result;
+
+	if (mtu != NULL) {
+		if (kstrtoul(mtu, 10, &result) == 0)
+			return result;
+	}
+	return DEFAULT_HEADROOM;
+}
+
+static int get_req_size(struct arglist *def)
+{
+	char *gro = uml_vector_fetch_arg(def, "gro");
+	long result;
+
+	if (gro != NULL) {
+		if (kstrtoul(gro, 10, &result) == 0) {
+			if (result > 0)
+				return 65536;
+		}
+	}
+	return get_mtu(def) + ETH_HEADER_OTHER +
+		get_headroom(def) + SAFETY_MARGIN;
+}
+
+
+static int get_transport_options(struct arglist *def)
+{
+	char *transport = uml_vector_fetch_arg(def, "transport");
+	char *vector = uml_vector_fetch_arg(def, "vec");
+
+	int vec_rx = VECTOR_RX;
+	int vec_tx = VECTOR_TX;
+	long parsed;
+
+	if (vector != NULL) {
+		if (kstrtoul(vector, 10, &parsed) == 0) {
+			if (parsed == 0) {
+				vec_rx = 0;
+				vec_tx = 0;
+			}
+		}
+	}
+
+
+	if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
+		return (vec_rx | VECTOR_BPF);
+	if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
+		return (vec_rx | vec_tx | VECTOR_BPF);
+	return (vec_rx | vec_tx);
+}
+
+
+/* A mini-buffer for packet drop read
+ * All of our supported transports are datagram oriented and we always
+ * read using recvmsg or recvmmsg. If we pass a buffer which is smaller
+ * than the packet size it still counts as full packet read and will
+ * clean the incoming stream to keep sigio/epoll happy
+ */
+
+#define DROP_BUFFER_SIZE 32
+
+static char *drop_buffer;
+
+/* Array backed queues optimized for bulk enqueue/dequeue and
+ * 1:N (small values of N) or 1:1 enqueuer/dequeuer ratios.
+ * For more details and full design rationale see
+ * http://foswiki.cambridgegreys.com/Main/EatYourTailAndEnjoyIt
+ */
+
+
+/*
+ * Advance the mmsg queue head by n = advance. Resets the queue to
+ * maximum enqueue/dequeue-at-once capacity if possible. Called by
+ * dequeuers. Caller must hold the head_lock!
+ */
+
+static int vector_advancehead(struct vector_queue *qi, int advance)
+{
+	int queue_depth;
+
+	qi->head =
+		(qi->head + advance)
+			% qi->max_depth;
+
+
+	spin_lock(&qi->tail_lock);
+	qi->queue_depth -= advance;
+
+	/* we are at 0, use this to
+	 * reset head and tail so we can use max size vectors
+	 */
+
+	if (qi->queue_depth == 0) {
+		qi->head = 0;
+		qi->tail = 0;
+	}
+	queue_depth = qi->queue_depth;
+	spin_unlock(&qi->tail_lock);
+	return queue_depth;
+}
+
+/*	Advance the queue tail by n = advance.
+ *	This is called by enqueuers which should hold the
+ *	head lock already
+ */
+
+static int vector_advancetail(struct vector_queue *qi, int advance)
+{
+	int queue_depth;
+
+	qi->tail =
+		(qi->tail + advance)
+			% qi->max_depth;
+	spin_lock(&qi->head_lock);
+	qi->queue_depth += advance;
+	queue_depth = qi->queue_depth;
+	spin_unlock(&qi->head_lock);
+	return queue_depth;
+}
+
+static int prep_msg(struct vector_private *vp,
+	struct sk_buff *skb,
+	struct iovec *iov)
+{
+	int iov_index = 0;
+	int nr_frags, frag;
+	skb_frag_t *skb_frag;
+
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	if (nr_frags > MAX_IOV_SIZE) {
+		if (skb_linearize(skb) != 0)
+			goto drop;
+	}
+	if (vp->header_size > 0) {
+		iov[iov_index].iov_len = vp->header_size;
+		vp->form_header(iov[iov_index].iov_base, skb, vp);
+		iov_index++;
+	}
+	iov[iov_index].iov_base = skb->data;
+	if (nr_frags > 0) {
+		iov[iov_index].iov_len = skb->len - skb->data_len;
+		vp->estats.sg_ok++;
+	} else
+		iov[iov_index].iov_len = skb->len;
+	iov_index++;
+	for (frag = 0; frag < nr_frags; frag++) {
+		skb_frag = &skb_shinfo(skb)->frags[frag];
+		iov[iov_index].iov_base = skb_frag_address_safe(skb_frag);
+		iov[iov_index].iov_len = skb_frag_size(skb_frag);
+		iov_index++;
+	}
+	return iov_index;
+drop:
+	return -1;
+}
+/*
+ * Generic vector enqueue with support for forming headers using transport
+ * specific callback. Allows GRE, L2TPv3, RAW and other transports
+ * to use a common enqueue procedure in vector mode
+ */
+
+static int vector_enqueue(struct vector_queue *qi, struct sk_buff *skb)
+{
+	struct vector_private *vp = netdev_priv(qi->dev);
+	int queue_depth;
+	int packet_len;
+	struct mmsghdr *mmsg_vector = qi->mmsg_vector;
+	int iov_count;
+
+	spin_lock(&qi->tail_lock);
+	spin_lock(&qi->head_lock);
+	queue_depth = qi->queue_depth;
+	spin_unlock(&qi->head_lock);
+
+	if (skb)
+		packet_len = skb->len;
+
+	if (queue_depth < qi->max_depth) {
+
+		*(qi->skbuff_vector + qi->tail) = skb;
+		mmsg_vector += qi->tail;
+		iov_count = prep_msg(
+			vp,
+			skb,
+			mmsg_vector->msg_hdr.msg_iov
+		);
+		if (iov_count < 1)
+			goto drop;
+		mmsg_vector->msg_hdr.msg_iovlen = iov_count;
+		mmsg_vector->msg_hdr.msg_name = vp->fds->remote_addr;
+		mmsg_vector->msg_hdr.msg_namelen = vp->fds->remote_addr_size;
+		queue_depth = vector_advancetail(qi, 1);
+	} else
+		goto drop;
+	spin_unlock(&qi->tail_lock);
+	return queue_depth;
+drop:
+	qi->dev->stats.tx_dropped++;
+	if (skb != NULL) {
+		packet_len = skb->len;
+		dev_consume_skb_any(skb);
+		netdev_completed_queue(qi->dev, 1, packet_len);
+	}
+	spin_unlock(&qi->tail_lock);
+	return queue_depth;
+}
+
+static int consume_vector_skbs(struct vector_queue *qi, int count)
+{
+	struct sk_buff *skb;
+	int skb_index;
+	int bytes_compl = 0;
+
+	for (skb_index = qi->head; skb_index < qi->head + count; skb_index++) {
+		skb = *(qi->skbuff_vector + skb_index);
+		/* mark as empty to ensure correct destruction if
+		 * needed
+		 */
+		bytes_compl += skb->len;
+		*(qi->skbuff_vector + skb_index) = NULL;
+		dev_consume_skb_any(skb);
+	}
+	qi->dev->stats.tx_bytes += bytes_compl;
+	qi->dev->stats.tx_packets += count;
+	netdev_completed_queue(qi->dev, count, bytes_compl);
+	return vector_advancehead(qi, count);
+}
+
+/*
+ * Generic vector deque via sendmmsg with support for forming headers
+ * using transport specific callback. Allows GRE, L2TPv3, RAW and
+ * other transports to use a common dequeue procedure in vector mode
+ */
+
+
+static int vector_send(struct vector_queue *qi)
+{
+	struct vector_private *vp = netdev_priv(qi->dev);
+	struct mmsghdr *send_from;
+	int result = 0, send_len, queue_depth = qi->max_depth;
+
+	if (spin_trylock(&qi->head_lock)) {
+		if (spin_trylock(&qi->tail_lock)) {
+			/* update queue_depth to current value */
+			queue_depth = qi->queue_depth;
+			spin_unlock(&qi->tail_lock);
+			while (queue_depth > 0) {
+				/* Calculate the start of the vector */
+				send_len = queue_depth;
+				send_from = qi->mmsg_vector;
+				send_from += qi->head;
+				/* Adjust vector size if wraparound */
+				if (send_len + qi->head > qi->max_depth)
+					send_len = qi->max_depth - qi->head;
+				/* Try to TX as many packets as possible */
+				if (send_len > 0) {
+					result = uml_vector_sendmmsg(
+						 vp->fds->tx_fd,
+						 send_from,
+						 send_len,
+						 0
+					);
+					vp->in_write_poll =
+						(result != send_len);
+				}
+				/* For some of the sendmmsg error scenarios
+				 * we may end being unsure in the TX success
+				 * for all packets. It is safer to declare
+				 * them all TX-ed and blame the network.
+				 */
+				if (result < 0) {
+					if (net_ratelimit())
+						netdev_err(vp->dev, "sendmmsg err=%i\n",
+							result);
+					result = send_len;
+				}
+				if (result > 0) {
+					queue_depth =
+						consume_vector_skbs(qi, result);
+					/* This is equivalent to an TX IRQ.
+					 * Restart the upper layers to feed us
+					 * more packets.
+					 */
+					if (result > vp->estats.tx_queue_max)
+						vp->estats.tx_queue_max = result;
+					vp->estats.tx_queue_running_average =
+						(vp->estats.tx_queue_running_average + result) >> 1;
+				}
+				netif_trans_update(qi->dev);
+				netif_wake_queue(qi->dev);
+				/* if TX is busy, break out of the send loop,
+				 *  poll write IRQ will reschedule xmit for us
+				 */
+				if (result != send_len) {
+					vp->estats.tx_restart_queue++;
+					break;
+				}
+			}
+		}
+		spin_unlock(&qi->head_lock);
+	} else {
+		tasklet_schedule(&vp->tx_poll);
+	}
+	return queue_depth;
+}
+
+/* Queue destructor. Deliberately stateless so we can use
+ * it in queue cleanup if initialization fails.
+ */
+
+static void destroy_queue(struct vector_queue *qi)
+{
+	int i;
+	struct iovec *iov;
+	struct vector_private *vp = netdev_priv(qi->dev);
+	struct mmsghdr *mmsg_vector;
+
+	if (qi == NULL)
+		return;
+	/* deallocate any skbuffs - we rely on any unused to be
+	 * set to NULL.
+	 */
+	if (qi->skbuff_vector != NULL) {
+		for (i = 0; i < qi->max_depth; i++) {
+			if (*(qi->skbuff_vector + i) != NULL)
+				dev_kfree_skb_any(*(qi->skbuff_vector + i));
+		}
+		kfree(qi->skbuff_vector);
+	}
+	/* deallocate matching IOV structures including header buffs */
+	if (qi->mmsg_vector != NULL) {
+		mmsg_vector = qi->mmsg_vector;
+		for (i = 0; i < qi->max_depth; i++) {
+			iov = mmsg_vector->msg_hdr.msg_iov;
+			if (iov != NULL) {
+				if ((vp->header_size > 0) &&
+					(iov->iov_base != NULL))
+					kfree(iov->iov_base);
+				kfree(iov);
+			}
+			mmsg_vector++;
+		}
+		kfree(qi->mmsg_vector);
+	}
+	kfree(qi);
+}
+
+/*
+ * Queue constructor. Create a queue with a given side.
+ */
+static struct vector_queue *create_queue(
+	struct vector_private *vp,
+	int max_size,
+	int header_size,
+	int num_extra_frags)
+{
+	struct vector_queue *result;
+	int i;
+	struct iovec *iov;
+	struct mmsghdr *mmsg_vector;
+
+	result = kmalloc(sizeof(struct vector_queue), GFP_KERNEL);
+	if (result == NULL)
+		goto out_fail;
+	result->max_depth = max_size;
+	result->dev = vp->dev;
+	result->mmsg_vector = kmalloc(
+		(sizeof(struct mmsghdr) * max_size), GFP_KERNEL);
+	result->skbuff_vector = kmalloc(
+		(sizeof(void *) * max_size), GFP_KERNEL);
+	if (result->mmsg_vector == NULL || result->skbuff_vector == NULL)
+		goto out_fail;
+
+	mmsg_vector = result->mmsg_vector;
+	for (i = 0; i < max_size; i++) {
+		/* Clear all pointers - we use non-NULL as marking on
+		 * what to free on destruction
+		 */
+		*(result->skbuff_vector + i) = NULL;
+		mmsg_vector->msg_hdr.msg_iov = NULL;
+		mmsg_vector++;
+	}
+	mmsg_vector = result->mmsg_vector;
+	result->max_iov_frags = num_extra_frags;
+	for (i = 0; i < max_size; i++) {
+		if (vp->header_size > 0)
+			iov = kmalloc(
+				sizeof(struct iovec) * (3 + num_extra_frags),
+				GFP_KERNEL
+			);
+		else
+			iov = kmalloc(
+				sizeof(struct iovec) * (2 + num_extra_frags),
+				GFP_KERNEL
+			);
+		if (iov == NULL)
+			goto out_fail;
+		mmsg_vector->msg_hdr.msg_iov = iov;
+		mmsg_vector->msg_hdr.msg_iovlen = 1;
+		mmsg_vector->msg_hdr.msg_control = NULL;
+		mmsg_vector->msg_hdr.msg_controllen = 0;
+		mmsg_vector->msg_hdr.msg_flags = MSG_DONTWAIT;
+		mmsg_vector->msg_hdr.msg_name = NULL;
+		mmsg_vector->msg_hdr.msg_namelen = 0;
+		if (vp->header_size > 0) {
+			iov->iov_base = kmalloc(header_size, GFP_KERNEL);
+			if (iov->iov_base == NULL)
+				goto out_fail;
+			iov->iov_len = header_size;
+			mmsg_vector->msg_hdr.msg_iovlen = 2;
+			iov++;
+		}
+		iov->iov_base = NULL;
+		iov->iov_len = 0;
+		mmsg_vector++;
+	}
+	spin_lock_init(&result->head_lock);
+	spin_lock_init(&result->tail_lock);
+	result->queue_depth = 0;
+	result->head = 0;
+	result->tail = 0;
+	return result;
+out_fail:
+	destroy_queue(result);
+	return NULL;
+}
+
+/*
+ * We do not use the RX queue as a proper wraparound queue for now
+ * This is not necessary because the consumption via netif_rx()
+ * happens in-line. While we can try using the return code of
+ * netif_rx() for flow control there are no drivers doing this today.
+ * For this RX specific use we ignore the tail/head locks and
+ * just read into a prepared queue filled with skbuffs.
+ */
+
+static struct sk_buff *prep_skb(
+	struct vector_private *vp,
+	struct user_msghdr *msg)
+{
+	int linear = vp->max_packet + vp->headroom + SAFETY_MARGIN;
+	struct sk_buff *result;
+	int iov_index = 0, len;
+	struct iovec *iov = msg->msg_iov;
+	int err, nr_frags, frag;
+	skb_frag_t *skb_frag;
+
+	if (vp->req_size <= linear)
+		len = linear;
+	else
+		len = vp->req_size;
+	result = alloc_skb_with_frags(
+		linear,
+		len - vp->max_packet,
+		3,
+		&err,
+		GFP_ATOMIC
+	);
+	if (vp->header_size > 0)
+		iov_index++;
+	if (result == NULL) {
+		iov[iov_index].iov_base = NULL;
+		iov[iov_index].iov_len = 0;
+		goto done;
+	}
+	skb_reserve(result, vp->headroom);
+	result->dev = vp->dev;
+	skb_put(result, vp->max_packet);
+	result->data_len = len - vp->max_packet;
+	result->len += len - vp->max_packet;
+	skb_reset_mac_header(result);
+	result->ip_summed = CHECKSUM_NONE;
+	iov[iov_index].iov_base = result->data;
+	iov[iov_index].iov_len = vp->max_packet;
+	iov_index++;
+
+	nr_frags = skb_shinfo(result)->nr_frags;
+	for (frag = 0; frag < nr_frags; frag++) {
+		skb_frag = &skb_shinfo(result)->frags[frag];
+		iov[iov_index].iov_base = skb_frag_address_safe(skb_frag);
+		if (iov[iov_index].iov_base != NULL)
+			iov[iov_index].iov_len = skb_frag_size(skb_frag);
+		else
+			iov[iov_index].iov_len = 0;
+		iov_index++;
+	}
+done:
+	msg->msg_iovlen = iov_index;
+	return result;
+}
+
+
+/* Prepare queue for recvmmsg one-shot rx - fill with fresh sk_buffs*/
+
+static void prep_queue_for_rx(struct vector_queue *qi)
+{
+	struct vector_private *vp = netdev_priv(qi->dev);
+	struct mmsghdr *mmsg_vector = qi->mmsg_vector;
+	void **skbuff_vector = qi->skbuff_vector;
+	int i;
+
+	if (qi->queue_depth == 0)
+		return;
+	for (i = 0; i < qi->queue_depth; i++) {
+		/* it is OK if allocation fails - recvmmsg with NULL data in
+		 * iov argument still performs an RX, just drops the packet
+		 * This allows us stop faffing around with a "drop buffer"
+		 */
+
+		*skbuff_vector = prep_skb(vp, &mmsg_vector->msg_hdr);
+		skbuff_vector++;
+		mmsg_vector++;
+	}
+	qi->queue_depth = 0;
+}
+
+static struct vector_device *find_device(int n)
+{
+	struct vector_device *device;
+	struct list_head *ele;
+
+	spin_lock(&vector_devices_lock);
+	list_for_each(ele, &vector_devices) {
+		device = list_entry(ele, struct vector_device, list);
+		if (device->unit == n)
+			goto out;
+	}
+	device = NULL;
+ out:
+	spin_unlock(&vector_devices_lock);
+	return device;
+}
+
+static int vector_parse(char *str, int *index_out, char **str_out,
+			char **error_out)
+{
+	int n, len, err;
+	char *start = str;
+
+	len = strlen(str);
+
+	while ((*str != ':') && (strlen(str) > 1))
+		str++;
+	if (*str != ':') {
+		*error_out = "Expected ':' after device number";
+		return -EINVAL;
+	}
+	*str = '\0';
+
+	err = kstrtouint(start, 0, &n);
+	if (err < 0) {
+		*error_out = "Bad device number";
+		return err;
+	}
+
+	str++;
+	if (find_device(n)) {
+		*error_out = "Device already configured";
+		return -EINVAL;
+	}
+
+	*index_out = n;
+	*str_out = str;
+	return 0;
+}
+
+static int vector_config(char *str, char **error_out)
+{
+	int err, n;
+	char *params;
+	struct arglist *parsed;
+
+	err = vector_parse(str, &n, &params, error_out);
+	if (err != 0)
+		return err;
+
+	/* This string is broken up and the pieces used by the underlying
+	 * driver. We should copy it to make sure things do not go wrong
+	 * later.
+	 */
+
+	params = kstrdup(params, GFP_KERNEL);
+	if (params == NULL) {
+		*error_out = "vector_config failed to strdup string";
+		return -ENOMEM;
+	}
+
+	parsed = uml_parse_vector_ifspec(params);
+
+	if (parsed == NULL) {
+		*error_out = "vector_config failed to parse parameters";
+		return -EINVAL;
+	}
+
+	vector_eth_configure(n, parsed);
+	return 0;
+}
+
+static int vector_id(char **str, int *start_out, int *end_out)
+{
+	char *end;
+	int n;
+
+	n = simple_strtoul(*str, &end, 0);
+	if ((*end != '\0') || (end == *str))
+		return -1;
+
+	*start_out = n;
+	*end_out = n;
+	*str = end;
+	return n;
+}
+
+static int vector_remove(int n, char **error_out)
+{
+	struct vector_device *vec_d;
+	struct net_device *dev;
+	struct vector_private *vp;
+
+	vec_d = find_device(n);
+	if (vec_d == NULL)
+		return -ENODEV;
+	dev = vec_d->dev;
+	vp = netdev_priv(dev);
+	if (vp->fds != NULL)
+		return -EBUSY;
+	unregister_netdev(dev);
+	platform_device_unregister(&vec_d->pdev);
+	return 0;
+}
+
+/*
+ * There is no shared per-transport initialization code, so
+ * we will just initialize each interface one by one and
+ * add them to a list
+ */
+
+static struct platform_driver uml_net_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+};
+
+
+static void vector_device_release(struct device *dev)
+{
+	struct vector_device *device = dev_get_drvdata(dev);
+	struct net_device *netdev = device->dev;
+
+	list_del(&device->list);
+	kfree(device);
+	free_netdev(netdev);
+}
+
+/* Bog standard recv using recvmsg - not used normally unless the user
+ * explicitly specifies not to use recvmmsg vector RX.
+ */
+
+static int vector_legacy_rx(struct vector_private *vp)
+{
+	int pkt_len;
+	struct user_msghdr hdr;
+	struct iovec iov[2 + MAX_IOV_SIZE]; /* header + data use case only */
+	int iovpos = 0;
+	struct sk_buff *skb;
+	int header_check;
+
+	hdr.msg_name = NULL;
+	hdr.msg_namelen = 0;
+	hdr.msg_iov = (struct iovec *) &iov;
+	hdr.msg_control = NULL;
+	hdr.msg_controllen = 0;
+	hdr.msg_flags = 0;
+
+	if (vp->header_size > 0) {
+		iov[0].iov_base = vp->header_rxbuffer;
+		iov[0].iov_len = vp->header_size;
+	}
+
+	skb = prep_skb(vp, &hdr);
+
+	if (skb == NULL) {
+		/* Read a packet into drop_buffer and don't do
+		 * anything with it.
+		 */
+		iov[iovpos].iov_base = drop_buffer;
+		iov[iovpos].iov_len = DROP_BUFFER_SIZE;
+		hdr.msg_iovlen = 1;
+		vp->dev->stats.rx_dropped++;
+	}
+
+	pkt_len = uml_vector_recvmsg(vp->fds->rx_fd, &hdr, 0);
+
+	if (skb != NULL) {
+		if (pkt_len > vp->header_size) {
+			if (vp->header_size > 0) {
+				header_check = vp->verify_header(
+					vp->header_rxbuffer, skb, vp);
+				if (header_check < 0) {
+					dev_kfree_skb_irq(skb);
+					vp->dev->stats.rx_dropped++;
+					vp->estats.rx_encaps_errors++;
+					return 0;
+				}
+				if (header_check > 0) {
+					vp->estats.rx_csum_offload_good++;
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+				}
+			}
+			pskb_trim(skb, pkt_len - vp->rx_header_size);
+			skb->protocol = eth_type_trans(skb, skb->dev);
+			vp->dev->stats.rx_bytes += skb->len;
+			vp->dev->stats.rx_packets++;
+			netif_rx(skb);
+		} else {
+			dev_kfree_skb_irq(skb);
+		}
+	}
+	return pkt_len;
+}
+
+/*
+ * Packet at a time TX which falls back to vector TX if the
+ * underlying transport is busy.
+ */
+
+
+
+static int writev_tx(struct vector_private *vp, struct sk_buff *skb)
+{
+	struct iovec iov[3 + MAX_IOV_SIZE];
+	int iov_count, pkt_len = 0;
+
+	iov[0].iov_base = vp->header_txbuffer;
+	iov_count = prep_msg(vp, skb, (struct iovec *) &iov);
+
+	if (iov_count < 1)
+		goto drop;
+	pkt_len = uml_vector_writev(
+		vp->fds->tx_fd,
+		(struct iovec *) &iov,
+		iov_count
+	);
+
+	netif_trans_update(vp->dev);
+	netif_wake_queue(vp->dev);
+
+	if (pkt_len > 0) {
+		vp->dev->stats.tx_bytes += skb->len;
+		vp->dev->stats.tx_packets++;
+	} else {
+		vp->dev->stats.tx_dropped++;
+	}
+	consume_skb(skb);
+	return pkt_len;
+drop:
+	vp->dev->stats.tx_dropped++;
+	consume_skb(skb);
+	return pkt_len;
+}
+
+/*
+ * Receive as many messages as we can in one call using the special
+ * mmsg vector matched to an skb vector which we prepared earlier.
+ */
+
+static int vector_mmsg_rx(struct vector_private *vp)
+{
+	int packet_count, i;
+	struct vector_queue *qi = vp->rx_queue;
+	struct sk_buff *skb;
+	struct mmsghdr *mmsg_vector = qi->mmsg_vector;
+	void **skbuff_vector = qi->skbuff_vector;
+	int header_check;
+
+	/* Refresh the vector and make sure it is with new skbs and the
+	 * iovs are updated to point to them.
+	 */
+
+	prep_queue_for_rx(qi);
+
+	/* Fire the Lazy Gun - get as many packets as we can in one go. */
+
+	packet_count = uml_vector_recvmmsg(
+		vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0);
+
+	if (packet_count <= 0)
+		return packet_count;
+
+	/* We treat packet processing as enqueue, buffer refresh as dequeue
+	 * The queue_depth tells us how many buffers have been used and how
+	 * many do we need to prep the next time prep_queue_for_rx() is called.
+	 */
+
+	qi->queue_depth = packet_count;
+
+	for (i = 0; i < packet_count; i++) {
+		skb = (*skbuff_vector);
+		if (mmsg_vector->msg_len > vp->header_size) {
+			if (vp->header_size > 0) {
+				header_check = vp->verify_header(
+					mmsg_vector->msg_hdr.msg_iov->iov_base,
+					skb,
+					vp
+				);
+				if (header_check < 0) {
+				/* Overlay header failed to verify - discard.
+				 * We can actually keep this skb and reuse it,
+				 * but that will make the prep logic too
+				 * complex.
+				 */
+					dev_kfree_skb_irq(skb);
+					vp->estats.rx_encaps_errors++;
+					continue;
+				}
+				if (header_check > 0) {
+					vp->estats.rx_csum_offload_good++;
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+				}
+			}
+			pskb_trim(skb,
+				mmsg_vector->msg_len - vp->rx_header_size);
+			skb->protocol = eth_type_trans(skb, skb->dev);
+			/*
+			 * We do not need to lock on updating stats here
+			 * The interrupt loop is non-reentrant.
+			 */
+			vp->dev->stats.rx_bytes += skb->len;
+			vp->dev->stats.rx_packets++;
+			netif_rx(skb);
+		} else {
+			/* Overlay header too short to do anything - discard.
+			 * We can actually keep this skb and reuse it,
+			 * but that will make the prep logic too complex.
+			 */
+			if (skb != NULL)
+				dev_kfree_skb_irq(skb);
+		}
+		(*skbuff_vector) = NULL;
+		/* Move to the next buffer element */
+		mmsg_vector++;
+		skbuff_vector++;
+	}
+	if (packet_count > 0) {
+		if (vp->estats.rx_queue_max < packet_count)
+			vp->estats.rx_queue_max = packet_count;
+		vp->estats.rx_queue_running_average =
+			(vp->estats.rx_queue_running_average + packet_count) >> 1;
+	}
+	return packet_count;
+}
+
+static void vector_rx(struct vector_private *vp)
+{
+	int err;
+
+	if ((vp->options & VECTOR_RX) > 0)
+		while ((err = vector_mmsg_rx(vp)) > 0)
+			;
+	else
+		while ((err = vector_legacy_rx(vp)) > 0)
+			;
+	if ((err != 0) && net_ratelimit())
+		netdev_err(vp->dev, "vector_rx: error(%d)\n", err);
+}
+
+static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vector_private *vp = netdev_priv(dev);
+	int queue_depth = 0;
+
+	if ((vp->options & VECTOR_TX) == 0) {
+		writev_tx(vp, skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* We do BQL only in the vector path, no point doing it in
+	 * packet at a time mode as there is no device queue
+	 */
+
+	netdev_sent_queue(vp->dev, skb->len);
+	queue_depth = vector_enqueue(vp->tx_queue, skb);
+
+	/* if the device queue is full, stop the upper layers and
+	 * flush it.
+	 */
+
+	if (queue_depth >= vp->tx_queue->max_depth - 1) {
+		vp->estats.tx_kicks++;
+		netif_stop_queue(dev);
+		vector_send(vp->tx_queue);
+		return NETDEV_TX_OK;
+	}
+	if (skb->xmit_more) {
+		mod_timer(&vp->tl, vp->coalesce);
+		return NETDEV_TX_OK;
+	}
+	if (skb->len < TX_SMALL_PACKET) {
+		vp->estats.tx_kicks++;
+		vector_send(vp->tx_queue);
+	} else
+		tasklet_schedule(&vp->tx_poll);
+	return NETDEV_TX_OK;
+}
+
+static irqreturn_t vector_rx_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct vector_private *vp = netdev_priv(dev);
+
+	if (!netif_running(dev))
+		return IRQ_NONE;
+	vector_rx(vp);
+	return IRQ_HANDLED;
+
+}
+
+static irqreturn_t vector_tx_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct vector_private *vp = netdev_priv(dev);
+
+	if (!netif_running(dev))
+		return IRQ_NONE;
+	/* We need to pay attention to it only if we got
+	 * -EAGAIN or -ENOBUFFS from sendmmsg. Otherwise
+	 * we ignore it. In the future, it may be worth
+	 * it to improve the IRQ controller a bit to make
+	 * tweaking the IRQ mask less costly
+	 */
+
+	if (vp->in_write_poll)
+		tasklet_schedule(&vp->tx_poll);
+	return IRQ_HANDLED;
+
+}
+
+static int irq_rr;
+
+static int vector_net_close(struct net_device *dev)
+{
+	struct vector_private *vp = netdev_priv(dev);
+	unsigned long flags;
+
+	netif_stop_queue(dev);
+	del_timer(&vp->tl);
+
+	if (vp->fds == NULL)
+		return 0;
+
+	/* Disable and free all IRQS */
+	if (vp->rx_irq > 0) {
+		um_free_irq(vp->rx_irq, dev);
+		vp->rx_irq = 0;
+	}
+	if (vp->tx_irq > 0) {
+		um_free_irq(vp->tx_irq, dev);
+		vp->tx_irq = 0;
+	}
+	tasklet_kill(&vp->tx_poll);
+	if (vp->fds->rx_fd > 0) {
+		os_close_file(vp->fds->rx_fd);
+		vp->fds->rx_fd = -1;
+	}
+	if (vp->fds->tx_fd > 0) {
+		os_close_file(vp->fds->tx_fd);
+		vp->fds->tx_fd = -1;
+	}
+	if (vp->bpf != NULL)
+		kfree(vp->bpf);
+	if (vp->fds->remote_addr != NULL)
+		kfree(vp->fds->remote_addr);
+	if (vp->transport_data != NULL)
+		kfree(vp->transport_data);
+	if (vp->header_rxbuffer != NULL)
+		kfree(vp->header_rxbuffer);
+	if (vp->header_txbuffer != NULL)
+		kfree(vp->header_txbuffer);
+	if (vp->rx_queue != NULL)
+		destroy_queue(vp->rx_queue);
+	if (vp->tx_queue != NULL)
+		destroy_queue(vp->tx_queue);
+	kfree(vp->fds);
+	vp->fds = NULL;
+	spin_lock_irqsave(&vp->lock, flags);
+	vp->opened = false;
+	spin_unlock_irqrestore(&vp->lock, flags);
+	return 0;
+}
+
+/* TX tasklet */
+
+static void vector_tx_poll(unsigned long data)
+{
+	struct vector_private *vp = (struct vector_private *)data;
+
+	vp->estats.tx_kicks++;
+	vector_send(vp->tx_queue);
+}
+static void vector_reset_tx(struct work_struct *work)
+{
+	struct vector_private *vp =
+		container_of(work, struct vector_private, reset_tx);
+	netdev_reset_queue(vp->dev);
+	netif_start_queue(vp->dev);
+	netif_wake_queue(vp->dev);
+}
+static int vector_net_open(struct net_device *dev)
+{
+	struct vector_private *vp = netdev_priv(dev);
+	unsigned long flags;
+	int err = -EINVAL;
+	struct vector_device *vdevice;
+
+	spin_lock_irqsave(&vp->lock, flags);
+	if (vp->opened) {
+		spin_unlock_irqrestore(&vp->lock, flags);
+		return -ENXIO;
+	}
+	vp->opened = true;
+	spin_unlock_irqrestore(&vp->lock, flags);
+
+	vp->fds = uml_vector_user_open(vp->unit, vp->parsed);
+
+	if (vp->fds == NULL)
+		goto out_close;
+
+	if (build_transport_data(vp) < 0)
+		goto out_close;
+
+	if ((vp->options & VECTOR_RX) > 0) {
+		vp->rx_queue = create_queue(
+			vp,
+			get_depth(vp->parsed),
+			vp->rx_header_size,
+			MAX_IOV_SIZE
+		);
+		vp->rx_queue->queue_depth = get_depth(vp->parsed);
+	} else {
+		vp->header_rxbuffer = kmalloc(
+			vp->rx_header_size,
+			GFP_KERNEL
+		);
+		if (vp->header_rxbuffer == NULL)
+			goto out_close;
+	}
+	if ((vp->options & VECTOR_TX) > 0) {
+		vp->tx_queue = create_queue(
+			vp,
+			get_depth(vp->parsed),
+			vp->header_size,
+			MAX_IOV_SIZE
+		);
+	} else {
+		vp->header_txbuffer = kmalloc(vp->header_size, GFP_KERNEL);
+		if (vp->header_txbuffer == NULL)
+			goto out_close;
+	}
+
+	/* READ IRQ */
+	err = um_request_irq(
+		irq_rr + VECTOR_BASE_IRQ, vp->fds->rx_fd,
+			IRQ_READ, vector_rx_interrupt,
+			IRQF_SHARED, dev->name, dev);
+	if (err != 0) {
+		netdev_err(dev, "vector_open: failed to get rx irq(%d)\n", err);
+		err = -ENETUNREACH;
+		goto out_close;
+	}
+	vp->rx_irq = irq_rr + VECTOR_BASE_IRQ;
+	dev->irq = irq_rr + VECTOR_BASE_IRQ;
+	irq_rr = (irq_rr + 1) % VECTOR_IRQ_SPACE;
+
+	/* WRITE IRQ - we need it only if we have vector TX */
+	if ((vp->options & VECTOR_TX) > 0) {
+		err = um_request_irq(
+			irq_rr + VECTOR_BASE_IRQ, vp->fds->tx_fd,
+				IRQ_WRITE, vector_tx_interrupt,
+				IRQF_SHARED, dev->name, dev);
+		if (err != 0) {
+			netdev_err(dev,
+				"vector_open: failed to get tx irq(%d)\n", err);
+			err = -ENETUNREACH;
+			goto out_close;
+		}
+		vp->tx_irq = irq_rr + VECTOR_BASE_IRQ;
+		irq_rr = (irq_rr + 1) % VECTOR_IRQ_SPACE;
+	}
+
+	if ((vp->options & VECTOR_BPF) != 0)
+		vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr);
+
+	/* Write Timeout Timer */
+
+	vp->tl.data = (unsigned long) vp;
+	netif_start_queue(dev);
+
+	/* clear buffer - it can happen that the host side of the interface
+	 * is full when we get here. In this case, new data is never queued,
+	 * SIGIOs never arrive, and the net never works.
+	 */
+
+	vector_rx(vp);
+
+	vector_reset_stats(vp);
+	vdevice = find_device(vp->unit);
+	vdevice->opened = 1;
+
+	if ((vp->options & VECTOR_TX) != 0)
+		add_timer(&vp->tl);
+	return 0;
+out_close:
+	vector_net_close(dev);
+	return err;
+}
+
+
+static void vector_net_set_multicast_list(struct net_device *dev)
+{
+	/* TODO: - we can do some BPF games here */
+	return;
+}
+
+static void vector_net_tx_timeout(struct net_device *dev)
+{
+	struct vector_private *vp = netdev_priv(dev);
+
+	vp->estats.tx_timeout_count++;
+	netif_trans_update(dev);
+	schedule_work(&vp->reset_tx);
+}
+
+static netdev_features_t vector_fix_features(struct net_device *dev,
+	netdev_features_t features)
+{
+	features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
+	return features;
+}
+
+static int vector_set_features(struct net_device *dev,
+	netdev_features_t features)
+{
+	struct vector_private *vp = netdev_priv(dev);
+	/* Adjust buffer sizes for GSO/GRO. Unfortunately, there is
+	 * no way to negotiate it on raw sockets, so we can change
+	 * only our side.
+	 */
+	if (features & NETIF_F_GRO)
+		/* All new frame buffers will be GRO-sized */
+		vp->req_size = 65536;
+	else
+		/* All new frame buffers will be normal sized */
+		vp->req_size = vp->max_packet + vp->headroom + SAFETY_MARGIN;
+	return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void vector_net_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	vector_rx_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
+}
+#endif
+
+static void vector_net_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+}
+
+static void vector_get_ringparam(struct net_device *netdev,
+				struct ethtool_ringparam *ring)
+{
+	struct vector_private *vp = netdev_priv(netdev);
+
+	ring->rx_max_pending = vp->rx_queue->max_depth;
+	ring->tx_max_pending = vp->tx_queue->max_depth;
+	ring->rx_pending = vp->rx_queue->max_depth;
+	ring->tx_pending = vp->tx_queue->max_depth;
+}
+
+static void vector_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch (stringset) {
+	case ETH_SS_TEST:
+		*buf = '\0';
+		break;
+	case ETH_SS_STATS:
+		memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+}
+
+static int vector_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_TEST:
+		return 0;
+	case ETH_SS_STATS:
+		return VECTOR_NUM_STATS;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void vector_get_ethtool_stats(struct net_device *dev,
+	struct ethtool_stats *estats,
+	u64 *tmp_stats)
+{
+	struct vector_private *vp = netdev_priv(dev);
+
+	memcpy(tmp_stats, &vp->estats, sizeof(struct vector_estats));
+}
+
+static int vector_get_coalesce(struct net_device *netdev,
+					struct ethtool_coalesce *ec)
+{
+	struct vector_private *vp = netdev_priv(netdev);
+
+	ec->tx_coalesce_usecs = (vp->coalesce * 1000000) / HZ;
+	return 0;
+}
+
+static int vector_set_coalesce(struct net_device *netdev,
+					struct ethtool_coalesce *ec)
+{
+	struct vector_private *vp = netdev_priv(netdev);
+
+	vp->coalesce = (ec->tx_coalesce_usecs * HZ) / 1000000;
+	if (vp->coalesce == 0)
+		vp->coalesce = 1;
+	return 0;
+}
+
+static const struct ethtool_ops vector_net_ethtool_ops = {
+	.get_drvinfo	= vector_net_get_drvinfo,
+	.get_link	= ethtool_op_get_link,
+	.get_ts_info	= ethtool_op_get_ts_info,
+	.get_ringparam	= vector_get_ringparam,
+	.get_strings	= vector_get_strings,
+	.get_sset_count	= vector_get_sset_count,
+	.get_ethtool_stats = vector_get_ethtool_stats,
+	.get_coalesce	= vector_get_coalesce,
+	.set_coalesce	= vector_set_coalesce,
+};
+
+
+static const struct net_device_ops vector_netdev_ops = {
+	.ndo_open		= vector_net_open,
+	.ndo_stop		= vector_net_close,
+	.ndo_start_xmit		= vector_net_start_xmit,
+	.ndo_set_rx_mode	= vector_net_set_multicast_list,
+	.ndo_tx_timeout		= vector_net_tx_timeout,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_fix_features	= vector_fix_features,
+	.ndo_set_features	= vector_set_features,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller = vector_net_poll_controller,
+#endif
+};
+
+
+static void vector_timer_expire(unsigned long _conn)
+{
+	struct vector_private *vp = (struct vector_private *)_conn;
+
+	vp->estats.tx_kicks++;
+	vector_send(vp->tx_queue);
+}
+
+static void vector_eth_configure(
+		int n,
+		struct arglist *def
+	)
+{
+	struct vector_device *device;
+	struct net_device *dev;
+	struct vector_private *vp;
+	int err;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (device == NULL) {
+		printk(KERN_ERR "eth_configure failed to allocate struct "
+				 "vector_device\n");
+		return;
+	}
+	dev = alloc_etherdev(sizeof(struct vector_private));
+	if (dev == NULL) {
+		printk(KERN_ERR "eth_configure: failed to allocate struct "
+				 "net_device for vec%d\n", n);
+		goto out_free_device;
+	}
+
+	dev->mtu = get_mtu(def);
+
+	INIT_LIST_HEAD(&device->list);
+	device->unit = n;
+
+	/* If this name ends up conflicting with an existing registered
+	 * netdevice, that is OK, register_netdev{,ice}() will notice this
+	 * and fail.
+	 */
+	snprintf(dev->name, sizeof(dev->name), "vec%d", n);
+	uml_net_setup_etheraddr(dev, uml_vector_fetch_arg(def, "mac"));
+	vp = netdev_priv(dev);
+
+	/* sysfs register */
+	if (!driver_registered) {
+		platform_driver_register(&uml_net_driver);
+		driver_registered = 1;
+	}
+	device->pdev.id = n;
+	device->pdev.name = DRIVER_NAME;
+	device->pdev.dev.release = vector_device_release;
+	dev_set_drvdata(&device->pdev.dev, device);
+	if (platform_device_register(&device->pdev))
+		goto out_free_netdev;
+	SET_NETDEV_DEV(dev, &device->pdev.dev);
+
+	device->dev = dev;
+
+	*vp = ((struct vector_private)
+		{
+		.list			= LIST_HEAD_INIT(vp->list),
+		.dev			= dev,
+		.unit			= n,
+		.options		= get_transport_options(def),
+		.rx_irq			= 0,
+		.tx_irq			= 0,
+		.parsed			= def,
+		.max_packet		= get_mtu(def) + ETH_HEADER_OTHER,
+		/* TODO - we need to calculate headroom so that ip header
+		 * is 16 byte aligned all the time
+		 */
+		.headroom		= get_headroom(def),
+		.form_header		= NULL,
+		.verify_header		= NULL,
+		.header_rxbuffer	= NULL,
+		.header_txbuffer	= NULL,
+		.header_size		= 0,
+		.rx_header_size		= 0,
+		.rexmit_scheduled	= false,
+		.opened			= false,
+		.transport_data		= NULL,
+		.in_write_poll		= false,
+		.coalesce		= 2,
+		.req_size		= get_req_size(def)
+		});
+
+	dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST);
+	tasklet_init(&vp->tx_poll, vector_tx_poll, (unsigned long)vp);
+	INIT_WORK(&vp->reset_tx, vector_reset_tx);
+
+	init_timer(&vp->tl);
+	spin_lock_init(&vp->lock);
+	vp->tl.function = vector_timer_expire;
+
+	/* FIXME */
+	dev->netdev_ops = &vector_netdev_ops;
+	dev->ethtool_ops = &vector_net_ethtool_ops;
+	dev->watchdog_timeo = (HZ >> 1);
+	/* primary IRQ - fixme */
+	dev->irq = 0; /* we will adjust this once opened */
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err)
+		goto out_undo_user_init;
+
+	spin_lock(&vector_devices_lock);
+	list_add(&device->list, &vector_devices);
+	spin_unlock(&vector_devices_lock);
+
+	return;
+
+out_undo_user_init:
+	return;
+out_free_netdev:
+	free_netdev(dev);
+out_free_device:
+	kfree(device);
+}
+
+
+
+
+/*
+ * Invoked late in the init
+ */
+
+static int __init vector_init(void)
+{
+	struct list_head *ele;
+	struct vector_cmd_line_arg *def;
+	struct arglist *parsed;
+
+	list_for_each(ele, &vec_cmd_line) {
+		def = list_entry(ele, struct vector_cmd_line_arg, list);
+		parsed = uml_parse_vector_ifspec(def->arguments);
+		if (parsed != NULL)
+			vector_eth_configure(def->unit, parsed);
+	}
+	return 0;
+}
+
+
+/* Invoked at initial argument parsing, only stores
+ * arguments until a proper vector_init is called
+ * later
+ */
+
+static int __init vector_setup(char *str)
+{
+	char *error;
+	int n, err;
+	struct vector_cmd_line_arg *new;
+
+	err = vector_parse(str, &n, &str, &error);
+	if (err) {
+		printk(KERN_ERR "vector_setup - Couldn't parse '%s' : %s\n",
+				 str, error);
+		return 1;
+	}
+	new = alloc_bootmem(sizeof(*new));
+	INIT_LIST_HEAD(&new->list);
+	new->unit = n;
+	new->arguments = str;
+	list_add_tail(&new->list, &vec_cmd_line);
+	return 1;
+}
+
+__setup("vec", vector_setup);
+__uml_help(vector_setup,
+"vec[0-9]+:<option>=<value>,<option>=<value>\n"
+"	 Configure a vector io network device.\n\n"
+);
+
+late_initcall(vector_init);
+
+static struct mc_device vector_mc = {
+	.list		= LIST_HEAD_INIT(vector_mc.list),
+	.name		= "vec",
+	.config		= vector_config,
+	.get_config	= NULL,
+	.id		= vector_id,
+	.remove		= vector_remove,
+};
+
+#ifdef CONFIG_INET
+static int vector_inetaddr_event(
+	struct notifier_block *this,
+	unsigned long event,
+	void *ptr)
+{
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block vector_inetaddr_notifier = {
+	.notifier_call		= vector_inetaddr_event,
+};
+
+static void inet_register(void)
+{
+	register_inetaddr_notifier(&vector_inetaddr_notifier);
+}
+#else
+static inline void inet_register(void)
+{
+}
+#endif
+
+static int vector_net_init(void)
+{
+	mconsole_register_dev(&vector_mc);
+	inet_register();
+	return 0;
+}
+
+__initcall(vector_net_init);
+
+
+
diff --git a/arch/um/drivers/vector_kern.h b/arch/um/drivers/vector_kern.h
new file mode 100644
index 000000000000..699696deb396
--- /dev/null
+++ b/arch/um/drivers/vector_kern.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2002 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_VECTOR_KERN_H
+#define __UM_VECTOR_KERN_H
+
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include "vector_user.h"
+
+/* Queue structure specially adapted for multiple enqueue/dequeue
+ * in a mmsgrecv/mmsgsend context
+ */
+
+/* Dequeue method */
+
+#define QUEUE_SENDMSG 0
+#define QUEUE_SENDMMSG 1
+
+#define VECTOR_RX 1
+#define VECTOR_TX (1 << 1)
+#define VECTOR_BPF (1 << 2)
+
+#define ETH_MAX_PACKET 1500
+#define ETH_HEADER_OTHER 32 /* just in case someone decides to go mad on QnQ */
+
+struct vector_queue {
+	struct mmsghdr *mmsg_vector;
+	void **skbuff_vector;
+	 /* backlink to device which owns us */
+	struct net_device *dev;
+	spinlock_t head_lock;
+	spinlock_t tail_lock;
+	int queue_depth, head, tail, max_depth, max_iov_frags;
+	short options;
+};
+
+struct vector_estats {
+	uint64_t rx_queue_max;
+	uint64_t rx_queue_running_average;
+	uint64_t tx_queue_max;
+	uint64_t tx_queue_running_average;
+	uint64_t rx_encaps_errors;
+	uint64_t tx_timeout_count;
+	uint64_t tx_restart_queue;
+	uint64_t tx_kicks;
+	uint64_t tx_flow_control_xon;
+	uint64_t tx_flow_control_xoff;
+	uint64_t rx_csum_offload_good;
+	uint64_t rx_csum_offload_errors;
+	uint64_t sg_ok;
+	uint64_t sg_linearized;
+};
+
+#define VERIFY_HEADER_NOK -1
+#define VERIFY_HEADER_OK 0
+#define VERIFY_CSUM_OK 1
+
+struct vector_private {
+	struct list_head list;
+	spinlock_t lock;
+	struct net_device *dev;
+
+	int unit;
+
+	/* Timeout timer in TX */
+
+	struct timer_list tl;
+
+	/* Scheduled "remove device" work */
+	struct work_struct reset_tx;
+	struct vector_fds *fds;
+
+	struct vector_queue *rx_queue;
+	struct vector_queue *tx_queue;
+
+	int rx_irq;
+	int tx_irq;
+
+	struct arglist *parsed;
+
+	void *transport_data; /* transport specific params if needed */
+
+	int max_packet;
+	int req_size; /* different from max packet - used for TSO */
+	int headroom;
+
+	int options;
+
+	/* remote address if any - some transports will leave this as null */
+
+	int header_size;
+	int rx_header_size;
+	int coalesce;
+
+	void *header_rxbuffer;
+	void *header_txbuffer;
+
+	int (*form_header)(uint8_t *header,
+		struct sk_buff *skb, struct vector_private *vp);
+	int (*verify_header)(uint8_t *header,
+		struct sk_buff *skb, struct vector_private *vp);
+
+	spinlock_t stats_lock;
+
+	struct tasklet_struct tx_poll;
+	bool rexmit_scheduled;
+	bool opened;
+	bool in_write_poll;
+
+	/* ethtool stats */
+
+	struct vector_estats estats;
+	void *bpf;
+
+	char user[0];
+};
+
+extern int build_transport_data(struct vector_private *vp);
+
+#endif
diff --git a/arch/um/drivers/vector_transports.c b/arch/um/drivers/vector_transports.c
new file mode 100644
index 000000000000..9065047f844b
--- /dev/null
+++ b/arch/um/drivers/vector_transports.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2017 - Cambridge Greys Limited
+ * Copyright (C) 2011 - 2014 Cisco Systems Inc
+ * Licensed under the GPL.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/virtio_net.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_byteorder.h>
+#include <linux/netdev_features.h>
+#include "vector_user.h"
+#include "vector_kern.h"
+
+#define GOOD_LINEAR 512
+#define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface"
+
+struct gre_minimal_header {
+	uint16_t header;
+	uint16_t arptype;
+};
+
+
+struct uml_gre_data {
+	uint32_t rx_key;
+	uint32_t tx_key;
+	uint32_t sequence;
+
+	bool ipv6;
+	bool has_sequence;
+	bool pin_sequence;
+	bool checksum;
+	bool key;
+	struct gre_minimal_header expected_header;
+
+	uint32_t checksum_offset;
+	uint32_t key_offset;
+	uint32_t sequence_offset;
+
+};
+
+struct uml_l2tpv3_data {
+	uint64_t rx_cookie;
+	uint64_t tx_cookie;
+	uint64_t rx_session;
+	uint64_t tx_session;
+	uint32_t counter;
+
+	bool udp;
+	bool ipv6;
+	bool has_counter;
+	bool pin_counter;
+	bool cookie;
+	bool cookie_is_64;
+
+	uint32_t cookie_offset;
+	uint32_t session_offset;
+	uint32_t counter_offset;
+};
+
+static int l2tpv3_form_header(uint8_t *header,
+	struct sk_buff *skb, struct vector_private *vp)
+{
+	struct uml_l2tpv3_data *td = vp->transport_data;
+	uint32_t *counter;
+
+	if (td->udp)
+		*(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET);
+	(*(uint32_t *) (header + td->session_offset)) = td->tx_session;
+
+	if (td->cookie) {
+		if (td->cookie_is_64)
+			(*(uint64_t *)(header + td->cookie_offset)) =
+				td->tx_cookie;
+		else
+			(*(uint32_t *)(header + td->cookie_offset)) =
+				td->tx_cookie;
+	}
+	if (td->has_counter) {
+		counter = (uint32_t *)(header + td->counter_offset);
+		if (td->pin_counter) {
+			*counter = 0;
+		} else {
+			td->counter++;
+			*counter = cpu_to_be32(td->counter);
+		}
+	}
+	return 0;
+}
+
+static int gre_form_header(uint8_t *header,
+		struct sk_buff *skb, struct vector_private *vp)
+{
+	struct uml_gre_data *td = vp->transport_data;
+	uint32_t *sequence;
+	*((uint32_t *) header) = *((uint32_t *) &td->expected_header);
+	if (td->key)
+		(*(uint32_t *) (header + td->key_offset)) = td->tx_key;
+	if (td->has_sequence) {
+		sequence = (uint32_t *)(header + td->sequence_offset);
+		if (td->pin_sequence)
+			*sequence = 0;
+		else
+			*sequence = cpu_to_be32(++td->sequence);
+	}
+	return 0;
+}
+
+static int raw_form_header(uint8_t *header,
+		struct sk_buff *skb, struct vector_private *vp)
+{
+	struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
+
+	virtio_net_hdr_from_skb(
+		skb,
+		vheader,
+		virtio_legacy_is_little_endian(),
+		false
+	);
+
+	return 0;
+}
+
+static int l2tpv3_verify_header(
+	uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
+{
+	struct uml_l2tpv3_data *td = vp->transport_data;
+	uint32_t *session;
+	uint64_t cookie;
+
+	if ((!td->udp) && (!td->ipv6))
+		header += sizeof(struct iphdr) /* fix for ipv4 raw */;
+
+	/* we do not do a strict check for "data" packets as per
+	 * the RFC spec because the pure IP spec does not have
+	 * that anyway.
+	 */
+
+	if (td->cookie) {
+		if (td->cookie_is_64)
+			cookie = *(uint64_t *)(header + td->cookie_offset);
+		else
+			cookie = *(uint32_t *)(header + td->cookie_offset);
+		if (cookie != td->rx_cookie) {
+			if (net_ratelimit())
+				netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id");
+			return -1;
+		}
+	}
+	session = (uint32_t *) (header + td->session_offset);
+	if (*session != td->rx_session) {
+		if (net_ratelimit())
+			netdev_err(vp->dev, "uml_l2tpv3: session mismatch");
+		return -1;
+	}
+	return 0;
+}
+
+static int gre_verify_header(
+	uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
+{
+
+	uint32_t key;
+	struct uml_gre_data *td = vp->transport_data;
+
+	if (!td->ipv6)
+		header += sizeof(struct iphdr) /* fix for ipv4 raw */;
+
+	if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) {
+		if (net_ratelimit())
+			netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x",
+				*((uint32_t *) &td->expected_header),
+				*((uint32_t *) header)
+			);
+		return -1;
+	}
+
+	if (td->key) {
+		key = (*(uint32_t *)(header + td->key_offset));
+		if (key != td->rx_key) {
+			if (net_ratelimit())
+				netdev_err(vp->dev, "unknown key id %0x, expecting %0x",
+						key, td->rx_key);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int raw_verify_header(
+	uint8_t *header, struct sk_buff *skb, struct vector_private *vp)
+{
+	struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header;
+
+	if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) &&
+		(vp->req_size != 65536)) {
+		if (net_ratelimit())
+			netdev_err(
+				vp->dev,
+				GSO_ERROR
+		);
+	}
+	if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0)
+		return 1;
+
+	virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian());
+	return 0;
+}
+
+static bool get_uint_param(
+	struct arglist *def, char *param, unsigned int *result)
+{
+	char *arg = uml_vector_fetch_arg(def, param);
+
+	if (arg != NULL) {
+		if (kstrtoint(arg, 0, result) == 0)
+			return true;
+	}
+	return false;
+}
+
+static bool get_ulong_param(
+	struct arglist *def, char *param, unsigned long *result)
+{
+	char *arg = uml_vector_fetch_arg(def, param);
+
+	if (arg != NULL) {
+		if (kstrtoul(arg, 0, result) == 0)
+			return true;
+		return true;
+	}
+	return false;
+}
+
+static int build_gre_transport_data(struct vector_private *vp)
+{
+	struct uml_gre_data *td;
+	int temp_int;
+	int temp_rx;
+	int temp_tx;
+
+	vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL);
+	if (vp->transport_data == NULL)
+		return -ENOMEM;
+	td = vp->transport_data;
+	td->sequence = 0;
+
+	td->expected_header.arptype = GRE_IRB;
+	td->expected_header.header = 0;
+
+	vp->form_header = &gre_form_header;
+	vp->verify_header = &gre_verify_header;
+	vp->header_size = 4;
+	td->key_offset = 4;
+	td->sequence_offset = 4;
+	td->checksum_offset = 4;
+
+	td->ipv6 = false;
+	if (get_uint_param(vp->parsed, "v6", &temp_int)) {
+		if (temp_int > 0)
+			td->ipv6 = true;
+	}
+	td->key = false;
+	if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) {
+		if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) {
+			td->key = true;
+			td->expected_header.header |= GRE_MODE_KEY;
+			td->rx_key = cpu_to_be32(temp_rx);
+			td->tx_key = cpu_to_be32(temp_tx);
+			vp->header_size += 4;
+			td->sequence_offset += 4;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	td->sequence = false;
+	if (get_uint_param(vp->parsed, "sequence", &temp_int)) {
+		if (temp_int > 0) {
+			vp->header_size += 4;
+			td->has_sequence = true;
+			td->expected_header.header |= GRE_MODE_SEQUENCE;
+			if (get_uint_param(
+				vp->parsed, "pin_sequence", &temp_int)) {
+				if (temp_int > 0)
+					td->pin_sequence = true;
+			}
+		}
+	}
+	vp->rx_header_size = vp->header_size;
+	if (!td->ipv6)
+		vp->rx_header_size += sizeof(struct iphdr);
+	return 0;
+}
+
+static int build_l2tpv3_transport_data(struct vector_private *vp)
+{
+
+	struct uml_l2tpv3_data *td;
+	int temp_int, temp_rxs, temp_txs;
+	unsigned long temp_rx;
+	unsigned long temp_tx;
+
+	vp->transport_data = kmalloc(
+		sizeof(struct uml_l2tpv3_data), GFP_KERNEL);
+
+	if (vp->transport_data == NULL)
+		return -ENOMEM;
+
+	td = vp->transport_data;
+
+	vp->form_header = &l2tpv3_form_header;
+	vp->verify_header = &l2tpv3_verify_header;
+	td->counter = 0;
+
+	vp->header_size = 4;
+	td->session_offset = 0;
+	td->cookie_offset = 4;
+	td->counter_offset = 4;
+
+
+	td->ipv6 = false;
+	if (get_uint_param(vp->parsed, "v6", &temp_int)) {
+		if (temp_int > 0)
+			td->ipv6 = true;
+	}
+
+	if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) {
+		if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) {
+			td->tx_session = cpu_to_be32(temp_txs);
+			td->rx_session = cpu_to_be32(temp_rxs);
+		} else {
+			return -EINVAL;
+		}
+	} else {
+		return -EINVAL;
+	}
+
+	td->cookie_is_64  = false;
+	if (get_uint_param(vp->parsed, "cookie64", &temp_int)) {
+		if (temp_int > 0)
+			td->cookie_is_64  = true;
+	}
+	td->cookie = false;
+	if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) {
+		if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) {
+			td->cookie = true;
+			if (td->cookie_is_64) {
+				td->rx_cookie = cpu_to_be64(temp_rx);
+				td->tx_cookie = cpu_to_be64(temp_tx);
+				vp->header_size += 8;
+				td->counter_offset += 8;
+			} else {
+				td->rx_cookie = cpu_to_be32(temp_rx);
+				td->tx_cookie = cpu_to_be32(temp_tx);
+				vp->header_size += 4;
+				td->counter_offset += 4;
+			}
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	td->has_counter = false;
+	if (get_uint_param(vp->parsed, "counter", &temp_int)) {
+		if (temp_int > 0) {
+			td->has_counter = true;
+			vp->header_size += 4;
+			if (get_uint_param(
+				vp->parsed, "pin_counter", &temp_int)) {
+				if (temp_int > 0)
+					td->pin_counter = true;
+			}
+		}
+	}
+
+	if (get_uint_param(vp->parsed, "udp", &temp_int)) {
+		if (temp_int > 0) {
+			td->udp = true;
+			vp->header_size += 4;
+			td->counter_offset += 4;
+			td->session_offset += 4;
+			td->cookie_offset += 4;
+		}
+	}
+
+	vp->rx_header_size = vp->header_size;
+	if ((!td->ipv6) && (!td->udp))
+		vp->rx_header_size += sizeof(struct iphdr);
+
+	return 0;
+}
+
+static int build_raw_transport_data(struct vector_private *vp)
+{
+	if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
+		if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd))
+			return -1;
+		vp->form_header = &raw_form_header;
+		vp->verify_header = &raw_verify_header;
+		vp->header_size = sizeof(struct virtio_net_hdr);
+		vp->rx_header_size = sizeof(struct virtio_net_hdr);
+		vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO);
+		vp->dev->features |=
+			(NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
+				NETIF_F_TSO | NETIF_F_GRO);
+		netdev_info(
+			vp->dev,
+			"raw: using vnet headers for tso and tx/rx checksum"
+		);
+	}
+	return 0;
+}
+
+static int build_tap_transport_data(struct vector_private *vp)
+{
+	if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) {
+		vp->form_header = &raw_form_header;
+		vp->verify_header = &raw_verify_header;
+		vp->header_size = sizeof(struct virtio_net_hdr);
+		vp->rx_header_size = sizeof(struct virtio_net_hdr);
+		vp->dev->hw_features |=
+			(NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
+		vp->dev->features |=
+			(NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
+				NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO);
+		netdev_info(
+			vp->dev,
+			"tap/raw: using vnet headers for tso and tx/rx checksum"
+		);
+	} else {
+		return 0; /* do not try to enable tap too if raw failed */
+	}
+	if (uml_tap_enable_vnet_headers(vp->fds->tx_fd))
+		return 0;
+	return -1;
+}
+
+int build_transport_data(struct vector_private *vp)
+{
+	char *transport = uml_vector_fetch_arg(vp->parsed, "transport");
+
+	if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
+		return build_gre_transport_data(vp);
+	if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
+		return build_l2tpv3_transport_data(vp);
+	if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
+		return build_raw_transport_data(vp);
+	if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
+		return build_tap_transport_data(vp);
+	return 0;
+}
+
diff --git a/arch/um/drivers/vector_user.c b/arch/um/drivers/vector_user.c
new file mode 100644
index 000000000000..4291f1a5d342
--- /dev/null
+++ b/arch/um/drivers/vector_user.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <netinet/ether.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <linux/virtio_net.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <os.h>
+#include <um_malloc.h>
+#include "vector_user.h"
+
+#define ID_GRE 0
+#define ID_L2TPV3 1
+#define ID_MAX 1
+
+#define TOKEN_IFNAME "ifname"
+
+#define TRANS_RAW "raw"
+#define TRANS_RAW_LEN strlen(TRANS_RAW)
+
+#define QDISC_FAIL "user_init_raw: could not disable qdisc on interface"
+#define VNET_HDR_FAIL "could not enable vnet headers on fd %d"
+#define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
+#define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
+#define BPF_ATTACH_FAIL "Failed to attach filter size %d to %d, err %d\n"
+
+/* This is very ugly and brute force lookup, but it is done
+ * only once at initialization so not worth doing hashes or
+ * anything more intelligent
+ */
+
+char *uml_vector_fetch_arg(struct arglist *ifspec, char *token)
+{
+	int i;
+
+	for (i = 0; i < ifspec->numargs; i++) {
+		if (strcmp(ifspec->tokens[i], token) == 0)
+			return ifspec->values[i];
+	}
+	return NULL;
+
+}
+
+struct arglist *uml_parse_vector_ifspec(char *arg)
+{
+	struct arglist *result;
+	int pos, len;
+	bool parsing_token = true, next_starts = true;
+
+	if (arg == NULL)
+		return NULL;
+	result = uml_kmalloc(sizeof(struct arglist), UM_GFP_KERNEL);
+	if (result == NULL)
+		return NULL;
+	result->numargs = 0;
+	len = strlen(arg);
+	for (pos = 0; pos < len; pos++) {
+		if (next_starts) {
+			if (parsing_token) {
+				result->tokens[result->numargs] = arg + pos;
+			} else {
+				result->values[result->numargs] = arg + pos;
+				result->numargs++;
+			}
+			next_starts = false;
+		}
+		if (*(arg + pos) == '=') {
+			if (parsing_token)
+				parsing_token = false;
+			else
+				goto cleanup;
+			next_starts = true;
+			(*(arg + pos)) = '\0';
+		}
+		if (*(arg + pos) == ',') {
+			parsing_token = true;
+			next_starts = true;
+			(*(arg + pos)) = '\0';
+		}
+	}
+	return result;
+cleanup:
+	printk(UM_KERN_ERR "vector_setup - Couldn't parse '%s'\n", arg);
+	kfree(result);
+	return NULL;
+}
+
+/*
+ * Socket/FD configuration functions. These return an structure
+ * of rx and tx descriptors to cover cases where these are not
+ * the same (f.e. read via raw socket and write via tap).
+ */
+
+#define PATH_NET_TUN "/dev/net/tun"
+
+static struct vector_fds *user_init_tap_fds(struct arglist *ifspec)
+{
+	struct ifreq ifr;
+	int fd = -1;
+	struct sockaddr_ll sock;
+	int err = -ENOMEM, offload;
+	char *iface;
+	struct vector_fds *result = NULL;
+
+	iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
+	if (iface == NULL) {
+		printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n");
+		goto tap_cleanup;
+	}
+
+	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
+	if (result == NULL) {
+		printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n");
+		goto tap_cleanup;
+	}
+	result->rx_fd = -1;
+	result->tx_fd = -1;
+	result->remote_addr = NULL;
+	result->remote_addr_size = 0;
+
+	/* TAP */
+
+	fd = open(PATH_NET_TUN, O_RDWR);
+	if (fd < 0) {
+		printk(UM_KERN_ERR "uml_tap: failed to open tun device\n");
+		goto tap_cleanup;
+	}
+	result->tx_fd = fd;
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+	strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
+
+	err = ioctl(fd, TUNSETIFF, (void *) &ifr);
+	if (err != 0) {
+		printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n");
+		goto tap_cleanup;
+	}
+
+	offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
+	ioctl(fd, TUNSETOFFLOAD, offload);
+
+	/* RAW */
+
+	fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (fd == -1) {
+		printk(UM_KERN_ERR
+			"uml_tap: failed to create socket: %i\n", -errno);
+		goto tap_cleanup;
+	}
+	result->rx_fd = fd;
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
+	if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) {
+		printk(UM_KERN_ERR
+			"uml_tap: failed to set interface: %i\n", -errno);
+		goto tap_cleanup;
+	}
+
+	sock.sll_family = AF_PACKET;
+	sock.sll_protocol = htons(ETH_P_ALL);
+	sock.sll_ifindex = ifr.ifr_ifindex;
+
+	if (bind(fd,
+		(struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
+		printk(UM_KERN_ERR
+			"user_init_tap: failed to bind raw pair, err %d\n",
+				-errno);
+		goto tap_cleanup;
+	}
+	return result;
+tap_cleanup:
+	printk(UM_KERN_ERR "user_init_tap: init failed, error %d", err);
+	if (result != NULL) {
+		if (result->rx_fd >= 0)
+			os_close_file(result->rx_fd);
+		if (result->tx_fd >= 0)
+			os_close_file(result->tx_fd);
+		kfree(result);
+	}
+	return NULL;
+}
+
+
+static struct vector_fds *user_init_raw_fds(struct arglist *ifspec)
+{
+	struct ifreq ifr;
+	int rxfd = -1, txfd = -1;
+	struct sockaddr_ll sock;
+	int err = -ENOMEM;
+	char *iface;
+	struct vector_fds *result = NULL;
+	int optval = 1;
+
+
+	iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
+	if (iface == NULL)
+		goto cleanup;
+
+	rxfd = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL);
+	if (rxfd == -1) {
+		err = -errno;
+		goto cleanup;
+	}
+	txfd = socket(AF_PACKET, SOCK_RAW, 0); /* Turn off RX on this fd */
+	if (txfd == -1) {
+		err = -errno;
+		goto cleanup;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
+	if (ioctl(rxfd, SIOCGIFINDEX, (void *) &ifr) < 0) {
+		err = -errno;
+		goto cleanup;
+	}
+
+	sock.sll_family = AF_PACKET;
+	sock.sll_protocol = htons(ETH_P_ALL);
+	sock.sll_ifindex = ifr.ifr_ifindex;
+
+	if (bind(rxfd,
+		(struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
+		err = -errno;
+		goto cleanup;
+	}
+
+	sock.sll_family = AF_PACKET;
+	sock.sll_protocol = htons(ETH_P_IP);
+	sock.sll_ifindex = ifr.ifr_ifindex;
+
+	if (bind(txfd,
+		(struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
+		err = -errno;
+		goto cleanup;
+	}
+
+	if (setsockopt(txfd,
+		SOL_PACKET, PACKET_QDISC_BYPASS,
+		&optval, sizeof(optval)) != 0) {
+		printk(UM_KERN_INFO QDISC_FAIL);
+	}
+
+	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
+	if (result != NULL) {
+		result->rx_fd = rxfd;
+		result->tx_fd = txfd;
+		result->remote_addr = NULL;
+		result->remote_addr_size = 0;
+	}
+	return result;
+cleanup:
+	printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
+	if (rxfd >= 0)
+		os_close_file(rxfd);
+	if (txfd >= 0)
+		os_close_file(txfd);
+	if (result != NULL)
+		kfree(result);
+	return NULL;
+}
+
+bool uml_raw_enable_vnet_headers(int fd)
+{
+	int optval = 1;
+
+	if (setsockopt(fd,
+		SOL_PACKET, PACKET_VNET_HDR,
+		&optval, sizeof(optval)) != 0) {
+		printk(UM_KERN_INFO VNET_HDR_FAIL, fd);
+		return false;
+	}
+	return true;
+}
+bool uml_tap_enable_vnet_headers(int fd)
+{
+	unsigned int features;
+	int len = sizeof(struct virtio_net_hdr);
+
+	if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
+		printk(UM_KERN_INFO TUN_GET_F_FAIL, strerror(errno));
+		return false;
+	}
+	if ((features & IFF_VNET_HDR) == 0) {
+		printk(UM_KERN_INFO "tapraw: No VNET HEADER support");
+		return false;
+	}
+	ioctl(fd, TUNSETVNETHDRSZ, &len);
+	return true;
+}
+
+static struct vector_fds *user_init_socket_fds(struct arglist *ifspec, int id)
+{
+	int err = -ENOMEM;
+	int fd = -1, gairet;
+	struct addrinfo srchints;
+	struct addrinfo dsthints;
+	bool v6, udp;
+	char *value;
+	char *src, *dst, *srcport, *dstport;
+	struct addrinfo *gairesult = NULL;
+	struct vector_fds *result = NULL;
+
+
+	value = uml_vector_fetch_arg(ifspec, "v6");
+	v6 = false;
+	udp = false;
+	if (value != NULL) {
+		if (strtol((const char *) value, NULL, 10) > 0)
+			v6 = true;
+	}
+
+	value = uml_vector_fetch_arg(ifspec, "udp");
+	if (value != NULL) {
+		if (strtol((const char *) value, NULL, 10) > 0)
+			udp = true;
+	}
+	src = uml_vector_fetch_arg(ifspec, "src");
+	dst = uml_vector_fetch_arg(ifspec, "dst");
+	srcport = uml_vector_fetch_arg(ifspec, "srcport");
+	dstport = uml_vector_fetch_arg(ifspec, "dstport");
+
+	memset(&dsthints, 0, sizeof(dsthints));
+
+	if (v6)
+		dsthints.ai_family = AF_INET6;
+	else
+		dsthints.ai_family = AF_INET;
+
+	switch (id) {
+	case ID_GRE:
+		dsthints.ai_socktype = SOCK_RAW;
+		dsthints.ai_protocol = IPPROTO_GRE;
+		break;
+	case ID_L2TPV3:
+		if (udp) {
+			dsthints.ai_socktype = SOCK_DGRAM;
+			dsthints.ai_protocol = 0;
+		} else {
+			dsthints.ai_socktype = SOCK_RAW;
+			dsthints.ai_protocol = IPPROTO_L2TP;
+		}
+		break;
+	default:
+		printk(KERN_ERR "Unsupported socket type\n");
+		return NULL;
+	}
+	memcpy(&srchints, &dsthints, sizeof(struct addrinfo));
+
+	gairet = getaddrinfo(src, srcport, &dsthints, &gairesult);
+	if ((gairet != 0) || (gairesult == NULL)) {
+		printk(UM_KERN_ERR
+			"socket_open : could not resolve src, error = %s",
+			gai_strerror(gairet)
+		);
+		return NULL;
+	}
+	fd = socket(gairesult->ai_family,
+		gairesult->ai_socktype, gairesult->ai_protocol);
+	if (fd == -1) {
+		printk(UM_KERN_ERR
+			"socket_open : could not open socket, error = %d",
+			-errno
+		);
+		goto cleanup;
+	}
+	if (bind(fd,
+		(struct sockaddr *) gairesult->ai_addr,
+		gairesult->ai_addrlen)) {
+		printk(UM_KERN_ERR L2TPV3_BIND_FAIL, errno);
+		goto cleanup;
+	}
+
+	if (gairesult != NULL)
+		freeaddrinfo(gairesult);
+
+	gairesult = NULL;
+
+	gairet = getaddrinfo(dst, dstport, &dsthints, &gairesult);
+	if ((gairet != 0) || (gairesult == NULL)) {
+		printk(UM_KERN_ERR
+			"socket_open : could not resolve dst, error = %s",
+			gai_strerror(gairet)
+		);
+		return NULL;
+	}
+
+	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
+	if (result != NULL) {
+		result->rx_fd = fd;
+		result->tx_fd = fd;
+		result->remote_addr = uml_kmalloc(
+			gairesult->ai_addrlen, UM_GFP_KERNEL);
+		if (result->remote_addr == NULL)
+			goto cleanup;
+		result->remote_addr_size = gairesult->ai_addrlen;
+		memcpy(
+			result->remote_addr,
+			gairesult->ai_addr,
+			gairesult->ai_addrlen
+		);
+	}
+	freeaddrinfo(gairesult);
+	return result;
+cleanup:
+	if (gairesult != NULL)
+		freeaddrinfo(gairesult);
+	printk(UM_KERN_ERR "user_init_socket: init failed, error %d", err);
+	if (fd >= 0)
+		os_close_file(fd);
+	if (result != NULL) {
+		if (result->remote_addr != NULL)
+			kfree(result->remote_addr);
+		kfree(result);
+	}
+	return NULL;
+}
+
+struct vector_fds *uml_vector_user_open(
+	int unit,
+	struct arglist *parsed
+)
+{
+	char *transport;
+
+	if (parsed == NULL) {
+		printk(UM_KERN_ERR "no parsed config for unit %d\n", unit);
+		return NULL;
+	}
+	transport = uml_vector_fetch_arg(parsed, "transport");
+	if (transport == NULL) {
+		printk(UM_KERN_ERR "missing transport for unit %d\n", unit);
+		return NULL;
+	}
+	if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
+		return user_init_raw_fds(parsed);
+	if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
+		return user_init_tap_fds(parsed);
+	if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
+		return user_init_socket_fds(parsed, ID_GRE);
+	if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
+		return user_init_socket_fds(parsed, ID_L2TPV3);
+	return NULL;
+}
+
+
+int uml_vector_sendmsg(int fd, void *hdr, int flags)
+{
+	int n;
+
+	CATCH_EINTR(n = sendmsg(fd, (struct msghdr *) hdr,  flags));
+	if ((n < 0) && (errno == EAGAIN))
+		return 0;
+	if (n >= 0)
+		return n;
+	else
+		return -errno;
+}
+
+int uml_vector_recvmsg(int fd, void *hdr, int flags)
+{
+	int n;
+
+	CATCH_EINTR(n = recvmsg(fd, (struct msghdr *) hdr,  flags));
+	if ((n < 0) && (errno == EAGAIN))
+		return 0;
+	if (n >= 0)
+		return n;
+	else
+		return -errno;
+}
+
+int uml_vector_writev(int fd, void *hdr, int iovcount)
+{
+	int n;
+
+	CATCH_EINTR(n = writev(fd, (struct iovec *) hdr,  iovcount));
+	if ((n < 0) && (errno == EAGAIN))
+		return 0;
+	if (n >= 0)
+		return n;
+	else
+		return -errno;
+}
+
+int uml_vector_sendmmsg(
+	int fd,
+	void *msgvec,
+	unsigned int vlen,
+	unsigned int flags)
+{
+	int n;
+
+	CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags));
+	if ((n < 0) && (errno == EAGAIN))
+		return 0;
+	if (n >= 0)
+		return n;
+	else
+		return -errno;
+}
+
+int uml_vector_recvmmsg(
+	int fd,
+	void *msgvec,
+	unsigned int vlen,
+	unsigned int flags)
+{
+	int n;
+
+	CATCH_EINTR(
+		n = recvmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags, 0));
+	if ((n < 0) && (errno == EAGAIN))
+		return 0;
+	if (n >= 0)
+		return n;
+	else
+		return -errno;
+}
+int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len)
+{
+	int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, bpf_len);
+
+	if (err < 0)
+		printk(KERN_ERR BPF_ATTACH_FAIL, bpf_len, fd, -errno);
+	return err;
+}
+
+#define DEFAULT_BPF_LEN 6
+
+void *uml_vector_default_bpf(int fd, void *mac)
+{
+	struct sock_filter *bpf;
+	uint32_t *mac1 = (uint32_t *)(mac + 2);
+	uint16_t *mac2 = (uint16_t *) mac;
+	struct sock_fprog bpf_prog = {
+		.len = 6,
+		.filter = NULL,
+	};
+
+	bpf = uml_kmalloc(
+		sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL);
+	if (bpf != NULL) {
+		bpf_prog.filter = bpf;
+		/* ld	[8] */
+		bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 };
+		/* jeq	#0xMAC[2-6] jt 2 jf 5*/
+		bpf[1] = (struct sock_filter){ 0x15, 0, 3, ntohl(*mac1)};
+		/* ldh	[6] */
+		bpf[2] = (struct sock_filter){ 0x28, 0, 0, 0x00000006 };
+		/* jeq	#0xMAC[0-1] jt 4 jf 5 */
+		bpf[3] = (struct sock_filter){ 0x15, 0, 1, ntohs(*mac2)};
+		/* ret	#0 */
+		bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 };
+		/* ret	#0x40000 */
+		bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 };
+		if (uml_vector_attach_bpf(
+			fd, &bpf_prog, sizeof(struct sock_fprog)) < 0) {
+			kfree(bpf);
+			bpf = NULL;
+		}
+	}
+	return bpf;
+}
+
diff --git a/arch/um/drivers/vector_user.h b/arch/um/drivers/vector_user.h
new file mode 100644
index 000000000000..421092c57bb7
--- /dev/null
+++ b/arch/um/drivers/vector_user.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2002 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_VECTOR_USER_H
+#define __UM_VECTOR_USER_H
+
+#define MAXVARGS	20
+
+#define TOKEN_IFNAME "ifname"
+
+#define TRANS_RAW "raw"
+#define TRANS_RAW_LEN strlen(TRANS_RAW)
+
+#define TRANS_TAP "tap"
+#define TRANS_TAP_LEN strlen(TRANS_TAP)
+
+
+#define TRANS_GRE "gre"
+#define TRANS_GRE_LEN strlen(TRANS_RAW)
+
+#define TRANS_L2TPV3 "l2tpv3"
+#define TRANS_L2TPV3_LEN strlen(TRANS_L2TPV3)
+
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 0x2F
+#endif
+
+#define GRE_MODE_CHECKSUM	cpu_to_be16(8 << 12)	/* checksum */
+#define GRE_MODE_RESERVED	cpu_to_be16(4 << 12)	/* unused */
+#define GRE_MODE_KEY		cpu_to_be16(2 << 12)	/* KEY present */
+#define GRE_MODE_SEQUENCE	cpu_to_be16(1 << 12)	/* sequence */
+
+#define GRE_IRB cpu_to_be16(0x6558)
+
+#define L2TPV3_DATA_PACKET 0x30000
+
+/* IANA-assigned IP protocol ID for L2TPv3 */
+
+#ifndef IPPROTO_L2TP
+#define IPPROTO_L2TP 0x73
+#endif
+
+struct arglist {
+	int	numargs;
+	char	*tokens[MAXVARGS];
+	char	*values[MAXVARGS];
+};
+
+/* Separating read and write FDs allows us to have different
+ * rx and tx method. Example - read tap via raw socket using
+ * recvmmsg, write using legacy tap write calls
+ */
+
+struct vector_fds {
+	int rx_fd;
+	int tx_fd;
+	void *remote_addr;
+	int remote_addr_size;
+};
+
+#define VECTOR_READ	1
+#define VECTOR_WRITE	(1 < 1)
+#define VECTOR_HEADERS	(1 < 2)
+
+extern struct arglist *uml_parse_vector_ifspec(char *arg);
+
+extern struct vector_fds *uml_vector_user_open(
+	int unit,
+	struct arglist *parsed
+);
+
+extern char *uml_vector_fetch_arg(
+	struct arglist *ifspec,
+	char *token
+);
+
+extern int uml_vector_recvmsg(int fd, void *hdr, int flags);
+extern int uml_vector_sendmsg(int fd, void *hdr, int flags);
+extern int uml_vector_writev(int fd, void *hdr, int iovcount);
+extern int uml_vector_sendmmsg(
+	int fd, void *msgvec,
+	unsigned int vlen,
+	unsigned int flags
+);
+extern int uml_vector_recvmmsg(
+	int fd,
+	void *msgvec,
+	unsigned int vlen,
+	unsigned int flags
+);
+extern void *uml_vector_default_bpf(int fd, void *mac);
+extern int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len);
+extern bool uml_raw_enable_vnet_headers(int fd);
+extern bool uml_tap_enable_vnet_headers(int fd);
+
+
+#endif
diff --git a/arch/um/include/asm/asm-prototypes.h b/arch/um/include/asm/asm-prototypes.h
new file mode 100644
index 000000000000..5898a26daa0d
--- /dev/null
+++ b/arch/um/include/asm/asm-prototypes.h
@@ -0,0 +1 @@
+#include <asm-generic/asm-prototypes.h>
diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h
index b5cdd3f91157..49ed3e35b35a 100644
--- a/arch/um/include/asm/irq.h
+++ b/arch/um/include/asm/irq.h
@@ -18,7 +18,19 @@
 #define XTERM_IRQ 		13
 #define RANDOM_IRQ 		14
 
+#ifdef CONFIG_UML_NET_VECTOR
+
+#define VECTOR_BASE_IRQ		15
+#define VECTOR_IRQ_SPACE	8
+
+#define LAST_IRQ (VECTOR_IRQ_SPACE + VECTOR_BASE_IRQ)
+
+#else
+
 #define LAST_IRQ RANDOM_IRQ
+
+#endif
+
 #define NR_IRQS (LAST_IRQ + 1)
 
 #endif
diff --git a/arch/um/include/shared/irq_user.h b/arch/um/include/shared/irq_user.h
index df5633053957..a7a6120f19d5 100644
--- a/arch/um/include/shared/irq_user.h
+++ b/arch/um/include/shared/irq_user.h
@@ -7,6 +7,7 @@
 #define __IRQ_USER_H__
 
 #include <sysdep/ptrace.h>
+#include <stdbool.h>
 
 struct irq_fd {
 	struct irq_fd *next;
@@ -15,10 +16,17 @@ struct irq_fd {
 	int type;
 	int irq;
 	int events;
-	int current_events;
+	bool active;
+	bool pending;
+	bool purge;
 };
 
-enum { IRQ_READ, IRQ_WRITE };
+#define IRQ_READ  0
+#define IRQ_WRITE 1
+#define IRQ_NONE 2
+#define MAX_IRQ_TYPE (IRQ_NONE + 1)
+
+
 
 struct siginfo;
 extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
diff --git a/arch/um/include/shared/net_kern.h b/arch/um/include/shared/net_kern.h
index 012ac87d4900..40442b98b173 100644
--- a/arch/um/include/shared/net_kern.h
+++ b/arch/um/include/shared/net_kern.h
@@ -65,5 +65,7 @@ extern int tap_setup_common(char *str, char *type, char **dev_name,
 			    char **mac_out, char **gate_addr);
 extern void register_transport(struct transport *new);
 extern unsigned short eth_protocol(struct sk_buff *skb);
+extern void uml_net_setup_etheraddr(struct net_device *dev, char *str);
+
 
 #endif
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index d8ddaf9790d2..048ae37eb5aa 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -290,15 +290,16 @@ extern void halt_skas(void);
 extern void reboot_skas(void);
 
 /* irq.c */
-extern int os_waiting_for_events(struct irq_fd *active_fds);
-extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds);
-extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
-		struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2);
-extern void os_free_irq_later(struct irq_fd *active_fds,
-		int irq, void *dev_id);
-extern int os_get_pollfd(int i);
-extern void os_set_pollfd(int i, int fd);
+extern int os_waiting_for_events_epoll(void);
+extern void *os_epoll_get_data_pointer(int index);
+extern int os_epoll_triggered(int index, int events);
+extern int os_event_mask(int irq_type);
+extern int os_setup_epoll(void);
+extern int os_add_epoll_fd(int events, int fd, void *data);
+extern int os_mod_epoll_fd(int events, int fd, void *data);
+extern int os_del_epoll_fd(int fd);
 extern void os_set_ioignore(void);
+extern void os_close_epoll_fd(void);
 
 /* sigio.c */
 extern int add_sigio_fd(int fd);
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 23cb9350d47e..6b7f3827d6e4 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2017 - Cambridge Greys Ltd
+ * Copyright (C) 2011 - 2014 Cisco Systems Inc
  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
@@ -16,243 +18,362 @@
 #include <as-layout.h>
 #include <kern_util.h>
 #include <os.h>
+#include <irq_user.h>
 
-/*
- * This list is accessed under irq_lock, except in sigio_handler,
- * where it is safe from being modified.  IRQ handlers won't change it -
- * if an IRQ source has vanished, it will be freed by free_irqs just
- * before returning from sigio_handler.  That will process a separate
- * list of irqs to free, with its own locking, coming back here to
- * remove list elements, taking the irq_lock to do so.
+
+/* When epoll triggers we do not know why it did so
+ * we can also have different IRQs for read and write.
+ * This is why we keep a small irq_fd array for each fd -
+ * one entry per IRQ type
  */
-static struct irq_fd *active_fds = NULL;
-static struct irq_fd **last_irq_ptr = &active_fds;
 
-extern void free_irqs(void);
+struct irq_entry {
+	struct irq_entry *next;
+	int fd;
+	struct irq_fd *irq_array[MAX_IRQ_TYPE + 1];
+};
+
+static struct irq_entry *active_fds;
+
+static DEFINE_SPINLOCK(irq_lock);
+
+static void irq_io_loop(struct irq_fd *irq, struct uml_pt_regs *regs)
+{
+/*
+ * irq->active guards against reentry
+ * irq->pending accumulates pending requests
+ * if pending is raised the irq_handler is re-run
+ * until pending is cleared
+ */
+	if (irq->active) {
+		irq->active = false;
+		do {
+			irq->pending = false;
+			do_IRQ(irq->irq, regs);
+		} while (irq->pending && (!irq->purge));
+		if (!irq->purge)
+			irq->active = true;
+	} else {
+		irq->pending = true;
+	}
+}
 
 void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
 {
-	struct irq_fd *irq_fd;
-	int n;
+	struct irq_entry *irq_entry;
+	struct irq_fd *irq;
+
+	int n, i, j;
 
 	while (1) {
-		n = os_waiting_for_events(active_fds);
+		/* This is now lockless - epoll keeps back-referencesto the irqs
+		 * which have trigger it so there is no need to walk the irq
+		 * list and lock it every time. We avoid locking by turning off
+		 * IO for a specific fd by executing os_del_epoll_fd(fd) before
+		 * we do any changes to the actual data structures
+		 */
+		n = os_waiting_for_events_epoll();
+
 		if (n <= 0) {
 			if (n == -EINTR)
 				continue;
-			else break;
+			else
+				break;
 		}
 
-		for (irq_fd = active_fds; irq_fd != NULL;
-		     irq_fd = irq_fd->next) {
-			if (irq_fd->current_events != 0) {
-				irq_fd->current_events = 0;
-				do_IRQ(irq_fd->irq, regs);
+		for (i = 0; i < n ; i++) {
+			/* Epoll back reference is the entry with 3 irq_fd
+			 * leaves - one for each irq type.
+			 */
+			irq_entry = (struct irq_entry *)
+				os_epoll_get_data_pointer(i);
+			for (j = 0; j < MAX_IRQ_TYPE ; j++) {
+				irq = irq_entry->irq_array[j];
+				if (irq == NULL)
+					continue;
+				if (os_epoll_triggered(i, irq->events) > 0)
+					irq_io_loop(irq, regs);
+				if (irq->purge) {
+					irq_entry->irq_array[j] = NULL;
+					kfree(irq);
+				}
 			}
 		}
 	}
+}
+
+static int assign_epoll_events_to_irq(struct irq_entry *irq_entry)
+{
+	int i;
+	int events = 0;
+	struct irq_fd *irq;
 
-	free_irqs();
+	for (i = 0; i < MAX_IRQ_TYPE ; i++) {
+		irq = irq_entry->irq_array[i];
+		if (irq != NULL)
+			events = irq->events | events;
+	}
+	if (events > 0) {
+	/* os_add_epoll will call os_mod_epoll if this already exists */
+		return os_add_epoll_fd(events, irq_entry->fd, irq_entry);
+	}
+	/* No events - delete */
+	return os_del_epoll_fd(irq_entry->fd);
 }
 
-static DEFINE_SPINLOCK(irq_lock);
+
 
 static int activate_fd(int irq, int fd, int type, void *dev_id)
 {
-	struct pollfd *tmp_pfd;
-	struct irq_fd *new_fd, *irq_fd;
+	struct irq_fd *new_fd;
+	struct irq_entry *irq_entry;
+	int i, err, events;
 	unsigned long flags;
-	int events, err, n;
 
 	err = os_set_fd_async(fd);
 	if (err < 0)
 		goto out;
 
-	err = -ENOMEM;
-	new_fd = kmalloc(sizeof(struct irq_fd), GFP_KERNEL);
-	if (new_fd == NULL)
-		goto out;
+	spin_lock_irqsave(&irq_lock, flags);
 
-	if (type == IRQ_READ)
-		events = UM_POLLIN | UM_POLLPRI;
-	else events = UM_POLLOUT;
-	*new_fd = ((struct irq_fd) { .next  		= NULL,
-				     .id 		= dev_id,
-				     .fd 		= fd,
-				     .type 		= type,
-				     .irq 		= irq,
-				     .events 		= events,
-				     .current_events 	= 0 } );
+	/* Check if we have an entry for this fd */
 
 	err = -EBUSY;
-	spin_lock_irqsave(&irq_lock, flags);
-	for (irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next) {
-		if ((irq_fd->fd == fd) && (irq_fd->type == type)) {
-			printk(KERN_ERR "Registering fd %d twice\n", fd);
-			printk(KERN_ERR "Irqs : %d, %d\n", irq_fd->irq, irq);
-			printk(KERN_ERR "Ids : 0x%p, 0x%p\n", irq_fd->id,
-			       dev_id);
+	for (irq_entry = active_fds;
+		irq_entry != NULL; irq_entry = irq_entry->next) {
+		if (irq_entry->fd == fd)
+			break;
+	}
+
+	if (irq_entry == NULL) {
+		/* This needs to be atomic as it may be called from an
+		 * IRQ context.
+		 */
+		irq_entry = kmalloc(sizeof(struct irq_entry), GFP_ATOMIC);
+		if (irq_entry == NULL) {
+			printk(KERN_ERR
+				"Failed to allocate new IRQ entry\n");
 			goto out_unlock;
 		}
+		irq_entry->fd = fd;
+		for (i = 0; i < MAX_IRQ_TYPE; i++)
+			irq_entry->irq_array[i] = NULL;
+		irq_entry->next = active_fds;
+		active_fds = irq_entry;
 	}
 
-	if (type == IRQ_WRITE)
-		fd = -1;
-
-	tmp_pfd = NULL;
-	n = 0;
+	/* Check if we are trying to re-register an interrupt for a
+	 * particular fd
+	 */
 
-	while (1) {
-		n = os_create_pollfd(fd, events, tmp_pfd, n);
-		if (n == 0)
-			break;
+	if (irq_entry->irq_array[type] != NULL) {
+		printk(KERN_ERR
+			"Trying to reregister IRQ %d FD %d TYPE %d ID %p\n",
+			irq, fd, type, dev_id
+		);
+		goto out_unlock;
+	} else {
+		/* New entry for this fd */
+
+		err = -ENOMEM;
+		new_fd = kmalloc(sizeof(struct irq_fd), GFP_ATOMIC);
+		if (new_fd == NULL)
+			goto out_unlock;
 
-		/*
-		 * n > 0
-		 * It means we couldn't put new pollfd to current pollfds
-		 * and tmp_fds is NULL or too small for new pollfds array.
-		 * Needed size is equal to n as minimum.
-		 *
-		 * Here we have to drop the lock in order to call
-		 * kmalloc, which might sleep.
-		 * If something else came in and changed the pollfds array
-		 * so we will not be able to put new pollfd struct to pollfds
-		 * then we free the buffer tmp_fds and try again.
+		events = os_event_mask(type);
+
+		*new_fd = ((struct irq_fd) {
+			.id		= dev_id,
+			.irq		= irq,
+			.type		= type,
+			.events		= events,
+			.active		= true,
+			.pending	= false,
+			.purge		= false
+		});
+		/* Turn off any IO on this fd - allows us to
+		 * avoid locking the IRQ loop
 		 */
-		spin_unlock_irqrestore(&irq_lock, flags);
-		kfree(tmp_pfd);
-
-		tmp_pfd = kmalloc(n, GFP_KERNEL);
-		if (tmp_pfd == NULL)
-			goto out_kfree;
-
-		spin_lock_irqsave(&irq_lock, flags);
+		os_del_epoll_fd(irq_entry->fd);
+		irq_entry->irq_array[type] = new_fd;
 	}
 
-	*last_irq_ptr = new_fd;
-	last_irq_ptr = &new_fd->next;
-
+	/* Turn back IO on with the correct (new) IO event mask */
+	assign_epoll_events_to_irq(irq_entry);
 	spin_unlock_irqrestore(&irq_lock, flags);
-
-	/*
-	 * This calls activate_fd, so it has to be outside the critical
-	 * section.
-	 */
-	maybe_sigio_broken(fd, (type == IRQ_READ));
+	maybe_sigio_broken(fd, (type != IRQ_NONE));
 
 	return 0;
-
- out_unlock:
+out_unlock:
 	spin_unlock_irqrestore(&irq_lock, flags);
- out_kfree:
-	kfree(new_fd);
- out:
+out:
 	return err;
 }
 
-static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+/*
+ * Walk the IRQ list and dispose of any unused entries.
+ * Should be done under irq_lock.
+ */
+
+static void garbage_collect_irq_entries(void)
 {
-	unsigned long flags;
+	int i;
+	bool reap;
+	struct irq_entry *walk;
+	struct irq_entry *previous = NULL;
+	struct irq_entry *to_free;
 
-	spin_lock_irqsave(&irq_lock, flags);
-	os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr);
-	spin_unlock_irqrestore(&irq_lock, flags);
+	if (active_fds == NULL)
+		return;
+	walk = active_fds;
+	while (walk != NULL) {
+		reap = true;
+		for (i = 0; i < MAX_IRQ_TYPE ; i++) {
+			if (walk->irq_array[i] != NULL) {
+				reap = false;
+				break;
+			}
+		}
+		if (reap) {
+			if (previous == NULL)
+				active_fds = walk->next;
+			else
+				previous->next = walk->next;
+			to_free = walk;
+		} else {
+			to_free = NULL;
+		}
+		walk = walk->next;
+		if (to_free != NULL)
+			kfree(to_free);
+	}
 }
 
-struct irq_and_dev {
-	int irq;
-	void *dev;
-};
+/*
+ * Walk the IRQ list and get the descriptor for our FD
+ */
 
-static int same_irq_and_dev(struct irq_fd *irq, void *d)
+static struct irq_entry *get_irq_entry_by_fd(int fd)
 {
-	struct irq_and_dev *data = d;
+	struct irq_entry *walk = active_fds;
 
-	return ((irq->irq == data->irq) && (irq->id == data->dev));
+	while (walk != NULL) {
+		if (walk->fd == fd)
+			return walk;
+		walk = walk->next;
+	}
+	return NULL;
 }
 
-static void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
-{
-	struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
-							  .dev  = dev });
 
-	free_irq_by_cb(same_irq_and_dev, &data);
-}
+/*
+ * Walk the IRQ list and dispose of an entry for a specific
+ * device, fd and number. Note - if sharing an IRQ for read
+ * and writefor the same FD it will be disposed in either case.
+ * If this behaviour is undesirable use different IRQ ids.
+ */
 
-static int same_fd(struct irq_fd *irq, void *fd)
-{
-	return (irq->fd == *((int *)fd));
-}
+#define IGNORE_IRQ 1
+#define IGNORE_DEV (1<<1)
 
-void free_irq_by_fd(int fd)
+static void do_free_by_irq_and_dev(
+	struct irq_entry *irq_entry,
+	unsigned int irq,
+	void *dev,
+	int flags
+)
 {
-	free_irq_by_cb(same_fd, &fd);
+	int i;
+	struct irq_fd *to_free;
+
+	for (i = 0; i < MAX_IRQ_TYPE ; i++) {
+		if (irq_entry->irq_array[i] != NULL) {
+			if (
+			((flags & IGNORE_IRQ) ||
+				(irq_entry->irq_array[i]->irq == irq)) &&
+			((flags & IGNORE_DEV) ||
+				(irq_entry->irq_array[i]->id == dev))
+			) {
+				/* Turn off any IO on this fd - allows us to
+				 * avoid locking the IRQ loop
+				 */
+				os_del_epoll_fd(irq_entry->fd);
+				to_free = irq_entry->irq_array[i];
+				irq_entry->irq_array[i] = NULL;
+				assign_epoll_events_to_irq(irq_entry);
+				if (to_free->active)
+					to_free->purge = true;
+				else
+					kfree(to_free);
+			}
+		}
+	}
 }
 
-/* Must be called with irq_lock held */
-static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
+void free_irq_by_fd(int fd)
 {
-	struct irq_fd *irq;
-	int i = 0;
-	int fdi;
+	struct irq_entry *to_free;
+	unsigned long flags;
 
-	for (irq = active_fds; irq != NULL; irq = irq->next) {
-		if ((irq->fd == fd) && (irq->irq == irqnum))
-			break;
-		i++;
-	}
-	if (irq == NULL) {
-		printk(KERN_ERR "find_irq_by_fd doesn't have descriptor %d\n",
-		       fd);
-		goto out;
-	}
-	fdi = os_get_pollfd(i);
-	if ((fdi != -1) && (fdi != fd)) {
-		printk(KERN_ERR "find_irq_by_fd - mismatch between active_fds "
-		       "and pollfds, fd %d vs %d, need %d\n", irq->fd,
-		       fdi, fd);
-		irq = NULL;
-		goto out;
+	spin_lock_irqsave(&irq_lock, flags);
+	to_free = get_irq_entry_by_fd(fd);
+	if (to_free != NULL) {
+		do_free_by_irq_and_dev(
+			to_free,
+			-1,
+			NULL,
+			IGNORE_IRQ | IGNORE_DEV
+		);
 	}
-	*index_out = i;
- out:
-	return irq;
+	garbage_collect_irq_entries();
+	spin_unlock_irqrestore(&irq_lock, flags);
 }
+EXPORT_SYMBOL(free_irq_by_fd);
 
-void reactivate_fd(int fd, int irqnum)
+static void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
 {
-	struct irq_fd *irq;
+	struct irq_entry *to_free;
 	unsigned long flags;
-	int i;
 
 	spin_lock_irqsave(&irq_lock, flags);
-	irq = find_irq_by_fd(fd, irqnum, &i);
-	if (irq == NULL) {
-		spin_unlock_irqrestore(&irq_lock, flags);
-		return;
+	to_free = active_fds;
+	while (to_free != NULL) {
+		do_free_by_irq_and_dev(
+			to_free,
+			irq,
+			dev,
+			0
+		);
+		to_free = to_free->next;
 	}
-	os_set_pollfd(i, irq->fd);
+	garbage_collect_irq_entries();
 	spin_unlock_irqrestore(&irq_lock, flags);
+}
 
-	add_sigio_fd(fd);
+
+void reactivate_fd(int fd, int irqnum)
+{
+	/** NOP - we do auto-EOI now **/
 }
 
 void deactivate_fd(int fd, int irqnum)
 {
-	struct irq_fd *irq;
+	struct irq_entry *to_free;
 	unsigned long flags;
-	int i;
 
+	os_del_epoll_fd(fd);
 	spin_lock_irqsave(&irq_lock, flags);
-	irq = find_irq_by_fd(fd, irqnum, &i);
-	if (irq == NULL) {
-		spin_unlock_irqrestore(&irq_lock, flags);
-		return;
+	to_free = get_irq_entry_by_fd(fd);
+	if (to_free != NULL) {
+		do_free_by_irq_and_dev(
+			to_free,
+			irqnum,
+			NULL,
+			IGNORE_DEV
+		);
 	}
-
-	os_set_pollfd(i, -1);
+	garbage_collect_irq_entries();
 	spin_unlock_irqrestore(&irq_lock, flags);
-
 	ignore_sigio_fd(fd);
 }
 EXPORT_SYMBOL(deactivate_fd);
@@ -265,17 +386,28 @@ EXPORT_SYMBOL(deactivate_fd);
  */
 int deactivate_all_fds(void)
 {
-	struct irq_fd *irq;
-	int err;
+	unsigned long flags;
+	struct irq_entry *to_free;
 
-	for (irq = active_fds; irq != NULL; irq = irq->next) {
-		err = os_clear_fd_async(irq->fd);
-		if (err)
-			return err;
-	}
-	/* If there is a signal already queued, after unblocking ignore it */
+	spin_lock_irqsave(&irq_lock, flags);
+	/* Stop IO. The IRQ loop has no lock so this is our
+	 * only way of making sure we are safe to dispose
+	 * of all IRQ handlers
+	 */
 	os_set_ioignore();
-
+	to_free = active_fds;
+	while (to_free != NULL) {
+		do_free_by_irq_and_dev(
+			to_free,
+			-1,
+			NULL,
+			IGNORE_IRQ | IGNORE_DEV
+		);
+		to_free = to_free->next;
+	}
+	garbage_collect_irq_entries();
+	spin_unlock_irqrestore(&irq_lock, flags);
+	os_close_epoll_fd();
 	return 0;
 }
 
@@ -353,8 +485,11 @@ void __init init_IRQ(void)
 
 	irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
 
+
 	for (i = 1; i < NR_IRQS; i++)
 		irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
+	/* Initialize EPOLL Loop */
+	os_setup_epoll();
 }
 
 /*
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 7f69d17de354..052de4c8acb2 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -121,12 +121,12 @@ static void __init um_timer_setup(void)
 	clockevents_register_device(&timer_clockevent);
 }
 
-void read_persistent_clock(struct timespec *ts)
+void read_persistent_clock64(struct timespec64 *ts)
 {
 	long long nsecs = os_persistent_clock_emulation();
 
-	set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
-				nsecs % NSEC_PER_SEC);
+	set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
+				  nsecs % NSEC_PER_SEC);
 }
 
 void __init time_init(void)
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
index b9afb74b79ad..365823010346 100644
--- a/arch/um/os-Linux/irq.c
+++ b/arch/um/os-Linux/irq.c
@@ -1,135 +1,147 @@
 /*
+ * Copyright (C) 2017 - Cambridge Greys Ltd
+ * Copyright (C) 2011 - 2014 Cisco Systems Inc
  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <stdlib.h>
 #include <errno.h>
-#include <poll.h>
+#include <sys/epoll.h>
 #include <signal.h>
 #include <string.h>
 #include <irq_user.h>
 #include <os.h>
 #include <um_malloc.h>
 
+/* Epoll support */
+
+static int epollfd = -1;
+
+#define MAX_EPOLL_EVENTS 64
+
+static struct epoll_event epoll_events[MAX_EPOLL_EVENTS];
+
+/* Helper to return an Epoll data pointer from an epoll event structure.
+ * We need to keep this one on the userspace side to keep includes separate
+ */
+
+void *os_epoll_get_data_pointer(int index)
+{
+	return epoll_events[index].data.ptr;
+}
+
+/* Helper to compare events versus the events in the epoll structure.
+ * Same as above - needs to be on the userspace side
+ */
+
+
+int os_epoll_triggered(int index, int events)
+{
+	return epoll_events[index].events & events;
+}
+/* Helper to set the event mask.
+ * The event mask is opaque to the kernel side, because it does not have
+ * access to the right includes/defines for EPOLL constants.
+ */
+
+int os_event_mask(int irq_type)
+{
+	if (irq_type == IRQ_READ)
+		return EPOLLIN | EPOLLPRI;
+	if (irq_type == IRQ_WRITE)
+		return EPOLLOUT;
+	return 0;
+}
+
 /*
- * Locked by irq_lock in arch/um/kernel/irq.c.  Changed by os_create_pollfd
- * and os_free_irq_by_cb, which are called under irq_lock.
+ * Initial Epoll Setup
  */
-static struct pollfd *pollfds = NULL;
-static int pollfds_num = 0;
-static int pollfds_size = 0;
+int os_setup_epoll(void)
+{
+	epollfd = epoll_create(MAX_EPOLL_EVENTS);
+	return epollfd;
+}
 
-int os_waiting_for_events(struct irq_fd *active_fds)
+/*
+ * Helper to run the actual epoll_wait
+ */
+int os_waiting_for_events_epoll(void)
 {
-	struct irq_fd *irq_fd;
-	int i, n, err;
+	int n, err;
 
-	n = poll(pollfds, pollfds_num, 0);
+	n = epoll_wait(epollfd,
+		(struct epoll_event *) &epoll_events, MAX_EPOLL_EVENTS, 0);
 	if (n < 0) {
 		err = -errno;
 		if (errno != EINTR)
-			printk(UM_KERN_ERR "os_waiting_for_events:"
-			       " poll returned %d, errno = %d\n", n, errno);
+			printk(
+				UM_KERN_ERR "os_waiting_for_events:"
+				" epoll returned %d, error = %s\n", n,
+				strerror(errno)
+			);
 		return err;
 	}
-
-	if (n == 0)
-		return 0;
-
-	irq_fd = active_fds;
-
-	for (i = 0; i < pollfds_num; i++) {
-		if (pollfds[i].revents != 0) {
-			irq_fd->current_events = pollfds[i].revents;
-			pollfds[i].fd = -1;
-		}
-		irq_fd = irq_fd->next;
-	}
 	return n;
 }
 
-int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds)
-{
-	if (pollfds_num == pollfds_size) {
-		if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) {
-			/* return min size needed for new pollfds area */
-			return (pollfds_size + 1) * sizeof(pollfds[0]);
-		}
-
-		if (pollfds != NULL) {
-			memcpy(tmp_pfd, pollfds,
-			       sizeof(pollfds[0]) * pollfds_size);
-			/* remove old pollfds */
-			kfree(pollfds);
-		}
-		pollfds = tmp_pfd;
-		pollfds_size++;
-	} else
-		kfree(tmp_pfd);	/* remove not used tmp_pfd */
-
-	pollfds[pollfds_num] = ((struct pollfd) { .fd		= fd,
-						  .events	= events,
-						  .revents	= 0 });
-	pollfds_num++;
-
-	return 0;
-}
 
-void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
-		struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2)
+/*
+ * Helper to add a fd to epoll
+ */
+int os_add_epoll_fd(int events, int fd, void *data)
 {
-	struct irq_fd **prev;
-	int i = 0;
-
-	prev = &active_fds;
-	while (*prev != NULL) {
-		if ((*test)(*prev, arg)) {
-			struct irq_fd *old_fd = *prev;
-			if ((pollfds[i].fd != -1) &&
-			    (pollfds[i].fd != (*prev)->fd)) {
-				printk(UM_KERN_ERR "os_free_irq_by_cb - "
-				       "mismatch between active_fds and "
-				       "pollfds, fd %d vs %d\n",
-				       (*prev)->fd, pollfds[i].fd);
-				goto out;
-			}
-
-			pollfds_num--;
-
-			/*
-			 * This moves the *whole* array after pollfds[i]
-			 * (though it doesn't spot as such)!
-			 */
-			memmove(&pollfds[i], &pollfds[i + 1],
-			       (pollfds_num - i) * sizeof(pollfds[0]));
-			if (*last_irq_ptr2 == &old_fd->next)
-				*last_irq_ptr2 = prev;
-
-			*prev = (*prev)->next;
-			if (old_fd->type == IRQ_WRITE)
-				ignore_sigio_fd(old_fd->fd);
-			kfree(old_fd);
-			continue;
-		}
-		prev = &(*prev)->next;
-		i++;
-	}
- out:
-	return;
+	struct epoll_event event;
+	int result;
+
+	event.data.ptr = data;
+	event.events = events | EPOLLET;
+	result = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
+	if ((result) && (errno == EEXIST))
+		result = os_mod_epoll_fd(events, fd, data);
+	if (result)
+		printk("epollctl add err fd %d, %s\n", fd, strerror(errno));
+	return result;
 }
 
-int os_get_pollfd(int i)
+/*
+ * Helper to mod the fd event mask and/or data backreference
+ */
+int os_mod_epoll_fd(int events, int fd, void *data)
 {
-	return pollfds[i].fd;
+	struct epoll_event event;
+	int result;
+
+	event.data.ptr = data;
+	event.events = events;
+	result = epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
+	if (result)
+		printk(UM_KERN_ERR
+			"epollctl mod err fd %d, %s\n", fd, strerror(errno));
+	return result;
 }
 
-void os_set_pollfd(int i, int fd)
+/*
+ * Helper to delete the epoll fd
+ */
+int os_del_epoll_fd(int fd)
 {
-	pollfds[i].fd = fd;
+	struct epoll_event event;
+	int result;
+	/* This is quiet as we use this as IO ON/OFF - so it is often
+	 * invoked on a non-existent fd
+	 */
+	result = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &event);
+	return result;
 }
 
 void os_set_ioignore(void)
 {
 	signal(SIGIO, SIG_IGN);
 }
+
+void os_close_epoll_fd(void)
+{
+	/* Needed so we do not leak an fd when rebooting */
+	os_close_file(epollfd);
+}
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index a86d7cc2c2d8..a5c0c909c48b 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -159,7 +159,7 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
 
 static void hard_handler(int sig, siginfo_t *si, void *p)
 {
-	struct ucontext *uc = p;
+	ucontext_t *uc = p;
 	mcontext_t *mc = &uc->uc_mcontext;
 	unsigned long pending = 1UL << sig;
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c1236b187824..552b3d0eae36 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1471,6 +1471,8 @@ config X86_PAE
 
 config X86_5LEVEL
 	bool "Enable 5-level page tables support"
+	select DYNAMIC_MEMORY_LAYOUT
+	select SPARSEMEM_VMEMMAP
 	depends on X86_64
 	---help---
 	  5-level paging enables access to larger address space:
@@ -1479,8 +1481,8 @@ config X86_5LEVEL
 
 	  It will be supported by future Intel CPUs.
 
-	  Note: a kernel with this option enabled can only be booted
-	  on machines that support the feature.
+	  A kernel with the option enabled can be booted on machines that
+	  support 4- or 5-level paging.
 
 	  See Documentation/x86/x86_64/5level-paging.txt for more
 	  information.
@@ -2184,10 +2186,17 @@ config PHYSICAL_ALIGN
 
 	  Don't change this unless you know what you are doing.
 
+config DYNAMIC_MEMORY_LAYOUT
+	bool
+	---help---
+	  This option makes base addresses of vmalloc and vmemmap as well as
+	  __PAGE_OFFSET movable during boot.
+
 config RANDOMIZE_MEMORY
 	bool "Randomize the kernel memory sections"
 	depends on X86_64
 	depends on RANDOMIZE_BASE
+	select DYNAMIC_MEMORY_LAYOUT
 	default RANDOMIZE_BASE
 	---help---
 	   Randomizes the base virtual address of kernel memory sections
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index f25e1530e064..1f734cd98fd3 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -78,7 +78,7 @@ vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
 vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o
 vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o
 ifdef CONFIG_X86_64
-	vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/pagetable.o
+	vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr_64.o
 	vmlinux-objs-y += $(obj)/mem_encrypt.o
 	vmlinux-objs-y += $(obj)/pgtable_64.o
 endif
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index fc313e29fe2c..99a0e7993252 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -33,6 +33,7 @@
 #include <asm/processor-flags.h>
 #include <asm/asm-offsets.h>
 #include <asm/bootparam.h>
+#include "pgtable.h"
 
 /*
  * Locally defined symbols should be marked hidden:
@@ -304,55 +305,78 @@ ENTRY(startup_64)
 	/* Set up the stack */
 	leaq	boot_stack_end(%rbx), %rsp
 
-#ifdef CONFIG_X86_5LEVEL
 	/*
-	 * Check if we need to enable 5-level paging.
-	 * RSI holds real mode data and need to be preserved across
-	 * a function call.
+	 * At this point we are in long mode with 4-level paging enabled,
+	 * but we might want to enable 5-level paging or vice versa.
+	 *
+	 * The problem is that we cannot do it directly. Setting or clearing
+	 * CR4.LA57 in long mode would trigger #GP. So we need to switch off
+	 * long mode and paging first.
+	 *
+	 * We also need a trampoline in lower memory to switch over from
+	 * 4- to 5-level paging for cases when the bootloader puts the kernel
+	 * above 4G, but didn't enable 5-level paging for us.
+	 *
+	 * The same trampoline can be used to switch from 5- to 4-level paging
+	 * mode, like when starting 4-level paging kernel via kexec() when
+	 * original kernel worked in 5-level paging mode.
+	 *
+	 * For the trampoline, we need the top page table to reside in lower
+	 * memory as we don't have a way to load 64-bit values into CR3 in
+	 * 32-bit mode.
+	 *
+	 * We go though the trampoline even if we don't have to: if we're
+	 * already in a desired paging mode. This way the trampoline code gets
+	 * tested on every boot.
 	 */
-	pushq	%rsi
-	call	l5_paging_required
-	popq	%rsi
 
-	/* If l5_paging_required() returned zero, we're done here. */
-	cmpq	$0, %rax
-	je	lvl5
+	/* Make sure we have GDT with 32-bit code segment */
+	leaq	gdt(%rip), %rax
+	movq	%rax, gdt64+2(%rip)
+	lgdt	gdt64(%rip)
 
 	/*
-	 * At this point we are in long mode with 4-level paging enabled,
-	 * but we want to enable 5-level paging.
+	 * paging_prepare() sets up the trampoline and checks if we need to
+	 * enable 5-level paging.
 	 *
-	 * The problem is that we cannot do it directly. Setting LA57 in
-	 * long mode would trigger #GP. So we need to switch off long mode
-	 * first.
+	 * Address of the trampoline is returned in RAX.
+	 * Non zero RDX on return means we need to enable 5-level paging.
 	 *
-	 * NOTE: This is not going to work if bootloader put us above 4G
-	 * limit.
-	 *
-	 * The first step is go into compatibility mode.
+	 * RSI holds real mode data and needs to be preserved across
+	 * this function call.
 	 */
+	pushq	%rsi
+	call	paging_prepare
+	popq	%rsi
 
-	/* Clear additional page table */
-	leaq	lvl5_pgtable(%rbx), %rdi
-	xorq	%rax, %rax
-	movq	$(PAGE_SIZE/8), %rcx
-	rep	stosq
+	/* Save the trampoline address in RCX */
+	movq	%rax, %rcx
 
 	/*
-	 * Setup current CR3 as the first and only entry in a new top level
-	 * page table.
+	 * Load the address of trampoline_return() into RDI.
+	 * It will be used by the trampoline to return to the main code.
 	 */
-	movq	%cr3, %rdi
-	leaq	0x7 (%rdi), %rax
-	movq	%rax, lvl5_pgtable(%rbx)
+	leaq	trampoline_return(%rip), %rdi
 
 	/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
 	pushq	$__KERNEL32_CS
-	leaq	compatible_mode(%rip), %rax
+	leaq	TRAMPOLINE_32BIT_CODE_OFFSET(%rax), %rax
 	pushq	%rax
 	lretq
-lvl5:
-#endif
+trampoline_return:
+	/* Restore the stack, the 32-bit trampoline uses its own stack */
+	leaq	boot_stack_end(%rbx), %rsp
+
+	/*
+	 * cleanup_trampoline() would restore trampoline memory.
+	 *
+	 * RSI holds real mode data and needs to be preserved across
+	 * this function call.
+	 */
+	pushq	%rsi
+	movq	%rcx, %rdi
+	call	cleanup_trampoline
+	popq	%rsi
 
 	/* Zero EFLAGS */
 	pushq	$0
@@ -490,46 +514,82 @@ relocated:
 	jmp	*%rax
 
 	.code32
-#ifdef CONFIG_X86_5LEVEL
-compatible_mode:
-	/* Setup data and stack segments */
+/*
+ * This is the 32-bit trampoline that will be copied over to low memory.
+ *
+ * RDI contains the return address (might be above 4G).
+ * ECX contains the base address of the trampoline memory.
+ * Non zero RDX on return means we need to enable 5-level paging.
+ */
+ENTRY(trampoline_32bit_src)
+	/* Set up data and stack segments */
 	movl	$__KERNEL_DS, %eax
 	movl	%eax, %ds
 	movl	%eax, %ss
 
+	/* Setup new stack */
+	leal	TRAMPOLINE_32BIT_STACK_END(%ecx), %esp
+
 	/* Disable paging */
 	movl	%cr0, %eax
 	btrl	$X86_CR0_PG_BIT, %eax
 	movl	%eax, %cr0
 
-	/* Point CR3 to 5-level paging */
-	leal	lvl5_pgtable(%ebx), %eax
-	movl	%eax, %cr3
+	/* Check what paging mode we want to be in after the trampoline */
+	cmpl	$0, %edx
+	jz	1f
 
-	/* Enable PAE and LA57 mode */
+	/* We want 5-level paging: don't touch CR3 if it already points to 5-level page tables */
 	movl	%cr4, %eax
-	orl	$(X86_CR4_PAE | X86_CR4_LA57), %eax
+	testl	$X86_CR4_LA57, %eax
+	jnz	3f
+	jmp	2f
+1:
+	/* We want 4-level paging: don't touch CR3 if it already points to 4-level page tables */
+	movl	%cr4, %eax
+	testl	$X86_CR4_LA57, %eax
+	jz	3f
+2:
+	/* Point CR3 to the trampoline's new top level page table */
+	leal	TRAMPOLINE_32BIT_PGTABLE_OFFSET(%ecx), %eax
+	movl	%eax, %cr3
+3:
+	/* Enable PAE and LA57 (if required) paging modes */
+	movl	$X86_CR4_PAE, %eax
+	cmpl	$0, %edx
+	jz	1f
+	orl	$X86_CR4_LA57, %eax
+1:
 	movl	%eax, %cr4
 
-	/* Calculate address we are running at */
-	call	1f
-1:	popl	%edi
-	subl	$1b, %edi
+	/* Calculate address of paging_enabled() once we are executing in the trampoline */
+	leal	paging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%ecx), %eax
 
-	/* Prepare stack for far return to Long Mode */
+	/* Prepare the stack for far return to Long Mode */
 	pushl	$__KERNEL_CS
-	leal	lvl5(%edi), %eax
-	push	%eax
+	pushl	%eax
 
-	/* Enable paging back */
+	/* Enable paging again */
 	movl	$(X86_CR0_PG | X86_CR0_PE), %eax
 	movl	%eax, %cr0
 
 	lret
-#endif
 
+	.code64
+paging_enabled:
+	/* Return from the trampoline */
+	jmp	*%rdi
+
+	/*
+         * The trampoline code has a size limit.
+         * Make sure we fail to compile if the trampoline code grows
+         * beyond TRAMPOLINE_32BIT_CODE_SIZE bytes.
+	 */
+	.org	trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE
+
+	.code32
 no_longmode:
-	/* This isn't an x86-64 CPU so hang */
+	/* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */
 1:
 	hlt
 	jmp     1b
@@ -537,6 +597,11 @@ no_longmode:
 #include "../../kernel/verify_cpu.S"
 
 	.data
+gdt64:
+	.word	gdt_end - gdt
+	.long	0
+	.word	0
+	.quad   0
 gdt:
 	.word	gdt_end - gdt
 	.long	gdt
@@ -578,6 +643,11 @@ boot_stack:
 	.fill BOOT_STACK_SIZE, 1, 0
 boot_stack_end:
 
+/* Space to preserve trampoline memory */
+	.global trampoline_save
+trampoline_save:
+	.fill TRAMPOLINE_32BIT_SIZE, 1, 0
+
 /*
  * Space for page tables (not in .bss so not zeroed)
  */
@@ -585,7 +655,7 @@ boot_stack_end:
 	.balign 4096
 pgtable:
 	.fill BOOT_PGT_SIZE, 1, 0
-#ifdef CONFIG_X86_5LEVEL
-lvl5_pgtable:
-	.fill PAGE_SIZE, 1, 0
-#endif
+
+	.global pgtable_trampoline
+pgtable_trampoline:
+	.fill 4096, 1, 0
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
index 8199a6187251..66e42a098d70 100644
--- a/arch/x86/boot/compressed/kaslr.c
+++ b/arch/x86/boot/compressed/kaslr.c
@@ -46,6 +46,12 @@
 #define STATIC
 #include <linux/decompress/mm.h>
 
+#ifdef CONFIG_X86_5LEVEL
+unsigned int pgtable_l5_enabled __ro_after_init;
+unsigned int pgdir_shift __ro_after_init = 39;
+unsigned int ptrs_per_p4d __ro_after_init = 1;
+#endif
+
 extern unsigned long get_cmd_line_ptr(void);
 
 /* Simplified build-specific string for starting entropy. */
@@ -723,6 +729,14 @@ void choose_random_location(unsigned long input,
 		return;
 	}
 
+#ifdef CONFIG_X86_5LEVEL
+	if (__read_cr4() & X86_CR4_LA57) {
+		pgtable_l5_enabled = 1;
+		pgdir_shift = 48;
+		ptrs_per_p4d = 512;
+	}
+#endif
+
 	boot_params->hdr.loadflags |= KASLR_FLAG;
 
 	/* Prepare to add new identity pagetables on demand. */
diff --git a/arch/x86/boot/compressed/kaslr_64.c b/arch/x86/boot/compressed/kaslr_64.c
new file mode 100644
index 000000000000..b5e5e02f8cde
--- /dev/null
+++ b/arch/x86/boot/compressed/kaslr_64.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This code is used on x86_64 to create page table identity mappings on
+ * demand by building up a new set of page tables (or appending to the
+ * existing ones), and then switching over to them when ready.
+ *
+ * Copyright (C) 2015-2016  Yinghai Lu
+ * Copyright (C)      2016  Kees Cook
+ */
+
+/*
+ * Since we're dealing with identity mappings, physical and virtual
+ * addresses are the same, so override these defines which are ultimately
+ * used by the headers in misc.h.
+ */
+#define __pa(x)  ((unsigned long)(x))
+#define __va(x)  ((void *)((unsigned long)(x)))
+
+/*
+ * The pgtable.h and mm/ident_map.c includes make use of the SME related
+ * information which is not used in the compressed image support. Un-define
+ * the SME support to avoid any compile and link errors.
+ */
+#undef CONFIG_AMD_MEM_ENCRYPT
+
+/* No PAGE_TABLE_ISOLATION support needed either: */
+#undef CONFIG_PAGE_TABLE_ISOLATION
+
+#include "misc.h"
+
+/* These actually do the work of building the kernel identity maps. */
+#include <asm/init.h>
+#include <asm/pgtable.h>
+/* Use the static base for this part of the boot process */
+#undef __PAGE_OFFSET
+#define __PAGE_OFFSET __PAGE_OFFSET_BASE
+#include "../../mm/ident_map.c"
+
+/* Used by pgtable.h asm code to force instruction serialization. */
+unsigned long __force_order;
+
+/* Used to track our page table allocation area. */
+struct alloc_pgt_data {
+	unsigned char *pgt_buf;
+	unsigned long pgt_buf_size;
+	unsigned long pgt_buf_offset;
+};
+
+/*
+ * Allocates space for a page table entry, using struct alloc_pgt_data
+ * above. Besides the local callers, this is used as the allocation
+ * callback in mapping_info below.
+ */
+static void *alloc_pgt_page(void *context)
+{
+	struct alloc_pgt_data *pages = (struct alloc_pgt_data *)context;
+	unsigned char *entry;
+
+	/* Validate there is space available for a new page. */
+	if (pages->pgt_buf_offset >= pages->pgt_buf_size) {
+		debug_putstr("out of pgt_buf in " __FILE__ "!?\n");
+		debug_putaddr(pages->pgt_buf_offset);
+		debug_putaddr(pages->pgt_buf_size);
+		return NULL;
+	}
+
+	entry = pages->pgt_buf + pages->pgt_buf_offset;
+	pages->pgt_buf_offset += PAGE_SIZE;
+
+	return entry;
+}
+
+/* Used to track our allocated page tables. */
+static struct alloc_pgt_data pgt_data;
+
+/* The top level page table entry pointer. */
+static unsigned long top_level_pgt;
+
+/*
+ * Mapping information structure passed to kernel_ident_mapping_init().
+ * Due to relocation, pointers must be assigned at run time not build time.
+ */
+static struct x86_mapping_info mapping_info;
+
+/* Locates and clears a region for a new top level page table. */
+void initialize_identity_maps(void)
+{
+	unsigned long sev_me_mask = get_sev_encryption_mask();
+
+	/* Init mapping_info with run-time function/buffer pointers. */
+	mapping_info.alloc_pgt_page = alloc_pgt_page;
+	mapping_info.context = &pgt_data;
+	mapping_info.page_flag = __PAGE_KERNEL_LARGE_EXEC | sev_me_mask;
+	mapping_info.kernpg_flag = _KERNPG_TABLE | sev_me_mask;
+
+	/*
+	 * It should be impossible for this not to already be true,
+	 * but since calling this a second time would rewind the other
+	 * counters, let's just make sure this is reset too.
+	 */
+	pgt_data.pgt_buf_offset = 0;
+
+	/*
+	 * If we came here via startup_32(), cr3 will be _pgtable already
+	 * and we must append to the existing area instead of entirely
+	 * overwriting it.
+	 *
+	 * With 5-level paging, we use '_pgtable' to allocate the p4d page table,
+	 * the top-level page table is allocated separately.
+	 *
+	 * p4d_offset(top_level_pgt, 0) would cover both the 4- and 5-level
+	 * cases. On 4-level paging it's equal to 'top_level_pgt'.
+	 */
+	top_level_pgt = read_cr3_pa();
+	if (p4d_offset((pgd_t *)top_level_pgt, 0) == (p4d_t *)_pgtable) {
+		debug_putstr("booted via startup_32()\n");
+		pgt_data.pgt_buf = _pgtable + BOOT_INIT_PGT_SIZE;
+		pgt_data.pgt_buf_size = BOOT_PGT_SIZE - BOOT_INIT_PGT_SIZE;
+		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
+	} else {
+		debug_putstr("booted via startup_64()\n");
+		pgt_data.pgt_buf = _pgtable;
+		pgt_data.pgt_buf_size = BOOT_PGT_SIZE;
+		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
+		top_level_pgt = (unsigned long)alloc_pgt_page(&pgt_data);
+	}
+}
+
+/*
+ * Adds the specified range to what will become the new identity mappings.
+ * Once all ranges have been added, the new mapping is activated by calling
+ * finalize_identity_maps() below.
+ */
+void add_identity_map(unsigned long start, unsigned long size)
+{
+	unsigned long end = start + size;
+
+	/* Align boundary to 2M. */
+	start = round_down(start, PMD_SIZE);
+	end = round_up(end, PMD_SIZE);
+	if (start >= end)
+		return;
+
+	/* Build the mapping. */
+	kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt,
+				  start, end);
+}
+
+/*
+ * This switches the page tables to the new level4 that has been built
+ * via calls to add_identity_map() above. If booted via startup_32(),
+ * this is effectively a no-op.
+ */
+void finalize_identity_maps(void)
+{
+	write_cr3(top_level_pgt);
+}
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 98761a1576ce..b50c42455e25 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -169,16 +169,6 @@ void __puthex(unsigned long value)
 	}
 }
 
-static bool l5_supported(void)
-{
-	/* Check if leaf 7 is supported. */
-	if (native_cpuid_eax(0) < 7)
-		return 0;
-
-	/* Check if la57 is supported. */
-	return native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31));
-}
-
 #if CONFIG_X86_NEED_RELOCS
 static void handle_relocations(void *output, unsigned long output_len,
 			       unsigned long virt_addr)
@@ -372,12 +362,6 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
 	console_init();
 	debug_putstr("early console in extract_kernel\n");
 
-	if (IS_ENABLED(CONFIG_X86_5LEVEL) && !l5_supported()) {
-		error("This linux kernel as configured requires 5-level paging\n"
-			"This CPU does not support the required 'cr4.la57' feature\n"
-			"Unable to boot - please use a kernel appropriate for your CPU\n");
-	}
-
 	free_mem_ptr     = heap;	/* Heap */
 	free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
 
diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c
deleted file mode 100644
index b5e5e02f8cde..000000000000
--- a/arch/x86/boot/compressed/pagetable.c
+++ /dev/null
@@ -1,157 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This code is used on x86_64 to create page table identity mappings on
- * demand by building up a new set of page tables (or appending to the
- * existing ones), and then switching over to them when ready.
- *
- * Copyright (C) 2015-2016  Yinghai Lu
- * Copyright (C)      2016  Kees Cook
- */
-
-/*
- * Since we're dealing with identity mappings, physical and virtual
- * addresses are the same, so override these defines which are ultimately
- * used by the headers in misc.h.
- */
-#define __pa(x)  ((unsigned long)(x))
-#define __va(x)  ((void *)((unsigned long)(x)))
-
-/*
- * The pgtable.h and mm/ident_map.c includes make use of the SME related
- * information which is not used in the compressed image support. Un-define
- * the SME support to avoid any compile and link errors.
- */
-#undef CONFIG_AMD_MEM_ENCRYPT
-
-/* No PAGE_TABLE_ISOLATION support needed either: */
-#undef CONFIG_PAGE_TABLE_ISOLATION
-
-#include "misc.h"
-
-/* These actually do the work of building the kernel identity maps. */
-#include <asm/init.h>
-#include <asm/pgtable.h>
-/* Use the static base for this part of the boot process */
-#undef __PAGE_OFFSET
-#define __PAGE_OFFSET __PAGE_OFFSET_BASE
-#include "../../mm/ident_map.c"
-
-/* Used by pgtable.h asm code to force instruction serialization. */
-unsigned long __force_order;
-
-/* Used to track our page table allocation area. */
-struct alloc_pgt_data {
-	unsigned char *pgt_buf;
-	unsigned long pgt_buf_size;
-	unsigned long pgt_buf_offset;
-};
-
-/*
- * Allocates space for a page table entry, using struct alloc_pgt_data
- * above. Besides the local callers, this is used as the allocation
- * callback in mapping_info below.
- */
-static void *alloc_pgt_page(void *context)
-{
-	struct alloc_pgt_data *pages = (struct alloc_pgt_data *)context;
-	unsigned char *entry;
-
-	/* Validate there is space available for a new page. */
-	if (pages->pgt_buf_offset >= pages->pgt_buf_size) {
-		debug_putstr("out of pgt_buf in " __FILE__ "!?\n");
-		debug_putaddr(pages->pgt_buf_offset);
-		debug_putaddr(pages->pgt_buf_size);
-		return NULL;
-	}
-
-	entry = pages->pgt_buf + pages->pgt_buf_offset;
-	pages->pgt_buf_offset += PAGE_SIZE;
-
-	return entry;
-}
-
-/* Used to track our allocated page tables. */
-static struct alloc_pgt_data pgt_data;
-
-/* The top level page table entry pointer. */
-static unsigned long top_level_pgt;
-
-/*
- * Mapping information structure passed to kernel_ident_mapping_init().
- * Due to relocation, pointers must be assigned at run time not build time.
- */
-static struct x86_mapping_info mapping_info;
-
-/* Locates and clears a region for a new top level page table. */
-void initialize_identity_maps(void)
-{
-	unsigned long sev_me_mask = get_sev_encryption_mask();
-
-	/* Init mapping_info with run-time function/buffer pointers. */
-	mapping_info.alloc_pgt_page = alloc_pgt_page;
-	mapping_info.context = &pgt_data;
-	mapping_info.page_flag = __PAGE_KERNEL_LARGE_EXEC | sev_me_mask;
-	mapping_info.kernpg_flag = _KERNPG_TABLE | sev_me_mask;
-
-	/*
-	 * It should be impossible for this not to already be true,
-	 * but since calling this a second time would rewind the other
-	 * counters, let's just make sure this is reset too.
-	 */
-	pgt_data.pgt_buf_offset = 0;
-
-	/*
-	 * If we came here via startup_32(), cr3 will be _pgtable already
-	 * and we must append to the existing area instead of entirely
-	 * overwriting it.
-	 *
-	 * With 5-level paging, we use '_pgtable' to allocate the p4d page table,
-	 * the top-level page table is allocated separately.
-	 *
-	 * p4d_offset(top_level_pgt, 0) would cover both the 4- and 5-level
-	 * cases. On 4-level paging it's equal to 'top_level_pgt'.
-	 */
-	top_level_pgt = read_cr3_pa();
-	if (p4d_offset((pgd_t *)top_level_pgt, 0) == (p4d_t *)_pgtable) {
-		debug_putstr("booted via startup_32()\n");
-		pgt_data.pgt_buf = _pgtable + BOOT_INIT_PGT_SIZE;
-		pgt_data.pgt_buf_size = BOOT_PGT_SIZE - BOOT_INIT_PGT_SIZE;
-		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
-	} else {
-		debug_putstr("booted via startup_64()\n");
-		pgt_data.pgt_buf = _pgtable;
-		pgt_data.pgt_buf_size = BOOT_PGT_SIZE;
-		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
-		top_level_pgt = (unsigned long)alloc_pgt_page(&pgt_data);
-	}
-}
-
-/*
- * Adds the specified range to what will become the new identity mappings.
- * Once all ranges have been added, the new mapping is activated by calling
- * finalize_identity_maps() below.
- */
-void add_identity_map(unsigned long start, unsigned long size)
-{
-	unsigned long end = start + size;
-
-	/* Align boundary to 2M. */
-	start = round_down(start, PMD_SIZE);
-	end = round_up(end, PMD_SIZE);
-	if (start >= end)
-		return;
-
-	/* Build the mapping. */
-	kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt,
-				  start, end);
-}
-
-/*
- * This switches the page tables to the new level4 that has been built
- * via calls to add_identity_map() above. If booted via startup_32(),
- * this is effectively a no-op.
- */
-void finalize_identity_maps(void)
-{
-	write_cr3(top_level_pgt);
-}
diff --git a/arch/x86/boot/compressed/pgtable.h b/arch/x86/boot/compressed/pgtable.h
new file mode 100644
index 000000000000..6e0db2260147
--- /dev/null
+++ b/arch/x86/boot/compressed/pgtable.h
@@ -0,0 +1,18 @@
+#ifndef BOOT_COMPRESSED_PAGETABLE_H
+#define BOOT_COMPRESSED_PAGETABLE_H
+
+#define TRAMPOLINE_32BIT_SIZE		(2 * PAGE_SIZE)
+
+#define TRAMPOLINE_32BIT_PGTABLE_OFFSET	0
+
+#define TRAMPOLINE_32BIT_CODE_OFFSET	PAGE_SIZE
+#define TRAMPOLINE_32BIT_CODE_SIZE	0x60
+
+#define TRAMPOLINE_32BIT_STACK_END	TRAMPOLINE_32BIT_SIZE
+
+#ifndef __ASSEMBLER__
+
+extern void (*trampoline_32bit_src)(void *return_ptr);
+
+#endif /* __ASSEMBLER__ */
+#endif /* BOOT_COMPRESSED_PAGETABLE_H */
diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
index b4469a37e9a1..dad5da7b4c1a 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -1,4 +1,6 @@
 #include <asm/processor.h>
+#include "pgtable.h"
+#include "../string.h"
 
 /*
  * __force_order is used by special_insns.h asm code to force instruction
@@ -9,20 +11,96 @@
  */
 unsigned long __force_order;
 
-int l5_paging_required(void)
+#define BIOS_START_MIN		0x20000U	/* 128K, less than this is insane */
+#define BIOS_START_MAX		0x9f000U	/* 640K, absolute maximum */
+
+struct paging_config {
+	unsigned long trampoline_start;
+	unsigned long l5_required;
+};
+
+extern void *trampoline_save;
+extern void *pgtable_trampoline;
+
+struct paging_config paging_prepare(void)
 {
-	/* Check if leaf 7 is supported. */
+	struct paging_config paging_config = {};
+	unsigned long bios_start, ebda_start, *trampoline;
+
+	/* Check if LA57 is desired and supported */
+	if (IS_ENABLED(CONFIG_X86_5LEVEL) && native_cpuid_eax(0) >= 7 &&
+			(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31))))
+		paging_config.l5_required = 1;
+
+	/*
+	 * Find a suitable spot for the trampoline.
+	 * This code is based on reserve_bios_regions().
+	 */
+
+	ebda_start = *(unsigned short *)0x40e << 4;
+	bios_start = *(unsigned short *)0x413 << 10;
+
+	if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX)
+		bios_start = BIOS_START_MAX;
+
+	if (ebda_start > BIOS_START_MIN && ebda_start < bios_start)
+		bios_start = ebda_start;
+
+	/* Place the trampoline just below the end of low memory, aligned to 4k */
+	paging_config.trampoline_start = bios_start - TRAMPOLINE_32BIT_SIZE;
+	paging_config.trampoline_start = round_down(paging_config.trampoline_start, PAGE_SIZE);
 
-	if (native_cpuid_eax(0) < 7)
-		return 0;
+	trampoline = (unsigned long *)paging_config.trampoline_start;
 
-	/* Check if la57 is supported. */
-	if (!(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31))))
-		return 0;
+	/* Preserve trampoline memory */
+	memcpy(trampoline_save, trampoline, TRAMPOLINE_32BIT_SIZE);
+
+	/* Clear trampoline memory first */
+	memset(trampoline, 0, TRAMPOLINE_32BIT_SIZE);
+
+	/* Copy trampoline code in place */
+	memcpy(trampoline + TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long),
+			&trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE);
+
+	/*
+	 * Set up a new page table that will be used for switching from 4-
+	 * to 5-level paging or vice versa. In other cases trampoline
+	 * wouldn't touch CR3.
+	 *
+	 * For 4- to 5-level paging transition, set up current CR3 as the
+	 * first and the only entry in a new top-level page table.
+	 *
+	 * For 5- to 4-level paging transition, copy page table pointed by
+	 * first entry in the current top-level page table as our new
+	 * top-level page table. We just cannot point to the page table
+	 * from trampoline as it may be above 4G.
+	 */
+	if (paging_config.l5_required) {
+		trampoline[TRAMPOLINE_32BIT_PGTABLE_OFFSET] = __native_read_cr3() + _PAGE_TABLE_NOENC;
+	} else if (native_read_cr4() & X86_CR4_LA57) {
+		unsigned long src;
+
+		src = *(unsigned long *)__native_read_cr3() & PAGE_MASK;
+		memcpy(trampoline + TRAMPOLINE_32BIT_PGTABLE_OFFSET / sizeof(unsigned long),
+		       (void *)src, PAGE_SIZE);
+	}
+
+	return paging_config;
+}
+
+void cleanup_trampoline(void *trampoline)
+{
+	void *cr3 = (void *)__native_read_cr3();
 
-	/* Check if 5-level paging has already been enabled. */
-	if (native_read_cr4() & X86_CR4_LA57)
-		return 0;
+	/*
+	 * Move the top level page table out of trampoline memory,
+	 * if it's there.
+	 */
+	if (cr3 == trampoline + TRAMPOLINE_32BIT_PGTABLE_OFFSET) {
+		memcpy(pgtable_trampoline, trampoline + TRAMPOLINE_32BIT_PGTABLE_OFFSET, PAGE_SIZE);
+		native_write_cr3((unsigned long)pgtable_trampoline);
+	}
 
-	return 1;
+	/* Restore trampoline memory */
+	memcpy(trampoline, trampoline_save, TRAMPOLINE_32BIT_SIZE);
 }
diff --git a/arch/x86/crypto/sha1-mb/sha1_mb.c b/arch/x86/crypto/sha1-mb/sha1_mb.c
index acf9fdf01671..e17655ffde79 100644
--- a/arch/x86/crypto/sha1-mb/sha1_mb.c
+++ b/arch/x86/crypto/sha1-mb/sha1_mb.c
@@ -106,13 +106,6 @@ static asmlinkage struct job_sha1* (*sha1_job_mgr_flush)
 static asmlinkage struct job_sha1* (*sha1_job_mgr_get_comp_job)
 						(struct sha1_mb_mgr *state);
 
-static inline void sha1_init_digest(uint32_t *digest)
-{
-	static const uint32_t initial_digest[SHA1_DIGEST_LENGTH] = {SHA1_H0,
-					SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 };
-	memcpy(digest, initial_digest, sizeof(initial_digest));
-}
-
 static inline uint32_t sha1_pad(uint8_t padblock[SHA1_BLOCK_SIZE * 2],
 			 uint64_t total_len)
 {
@@ -244,11 +237,8 @@ static struct sha1_hash_ctx *sha1_ctx_mgr_submit(struct sha1_ctx_mgr *mgr,
 					  uint32_t len,
 					  int flags)
 {
-	if (flags & (~HASH_ENTIRE)) {
-		/*
-		 * User should not pass anything other than FIRST, UPDATE, or
-		 * LAST
-		 */
+	if (flags & ~(HASH_UPDATE | HASH_LAST)) {
+		/* User should not pass anything other than UPDATE or LAST */
 		ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
 		return ctx;
 	}
@@ -259,24 +249,12 @@ static struct sha1_hash_ctx *sha1_ctx_mgr_submit(struct sha1_ctx_mgr *mgr,
 		return ctx;
 	}
 
-	if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
+	if (ctx->status & HASH_CTX_STS_COMPLETE) {
 		/* Cannot update a finished job. */
 		ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
 		return ctx;
 	}
 
-
-	if (flags & HASH_FIRST) {
-		/* Init digest */
-		sha1_init_digest(ctx->job.result_digest);
-
-		/* Reset byte counter */
-		ctx->total_length = 0;
-
-		/* Clear extra blocks */
-		ctx->partial_block_buffer_length = 0;
-	}
-
 	/*
 	 * If we made it here, there were no errors during this call to
 	 * submit
diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
index 13590ccf965c..9454bd16f9f8 100644
--- a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
+++ b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
@@ -57,11 +57,9 @@
 #include "sha1_mb_mgr.h"
 
 #define HASH_UPDATE          0x00
-#define HASH_FIRST           0x01
-#define HASH_LAST            0x02
-#define HASH_ENTIRE          0x03
-#define HASH_DONE	     0x04
-#define HASH_FINAL	     0x08
+#define HASH_LAST            0x01
+#define HASH_DONE	     0x02
+#define HASH_FINAL	     0x04
 
 #define HASH_CTX_STS_IDLE       0x00
 #define HASH_CTX_STS_PROCESSING 0x01
diff --git a/arch/x86/crypto/sha256-mb/sha256_mb.c b/arch/x86/crypto/sha256-mb/sha256_mb.c
index 7926a226b120..4c46ac1b6653 100644
--- a/arch/x86/crypto/sha256-mb/sha256_mb.c
+++ b/arch/x86/crypto/sha256-mb/sha256_mb.c
@@ -106,14 +106,6 @@ static asmlinkage struct job_sha256* (*sha256_job_mgr_flush)
 static asmlinkage struct job_sha256* (*sha256_job_mgr_get_comp_job)
 			(struct sha256_mb_mgr *state);
 
-inline void sha256_init_digest(uint32_t *digest)
-{
-	static const uint32_t initial_digest[SHA256_DIGEST_LENGTH] = {
-				SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
-				SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7};
-	memcpy(digest, initial_digest, sizeof(initial_digest));
-}
-
 inline uint32_t sha256_pad(uint8_t padblock[SHA256_BLOCK_SIZE * 2],
 			 uint64_t total_len)
 {
@@ -245,10 +237,8 @@ static struct sha256_hash_ctx *sha256_ctx_mgr_submit(struct sha256_ctx_mgr *mgr,
 					  uint32_t len,
 					  int flags)
 {
-	if (flags & (~HASH_ENTIRE)) {
-		/* User should not pass anything other than FIRST, UPDATE
-		 * or LAST
-		 */
+	if (flags & ~(HASH_UPDATE | HASH_LAST)) {
+		/* User should not pass anything other than UPDATE or LAST */
 		ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
 		return ctx;
 	}
@@ -259,23 +249,12 @@ static struct sha256_hash_ctx *sha256_ctx_mgr_submit(struct sha256_ctx_mgr *mgr,
 		return ctx;
 	}
 
-	if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
+	if (ctx->status & HASH_CTX_STS_COMPLETE) {
 		/* Cannot update a finished job. */
 		ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
 		return ctx;
 	}
 
-	if (flags & HASH_FIRST) {
-		/* Init digest */
-		sha256_init_digest(ctx->job.result_digest);
-
-		/* Reset byte counter */
-		ctx->total_length = 0;
-
-		/* Clear extra blocks */
-		ctx->partial_block_buffer_length = 0;
-	}
-
 	/* If we made it here, there was no error during this call to submit */
 	ctx->error = HASH_CTX_ERROR_NONE;
 
diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
index aabb30320af0..7c432543dc7f 100644
--- a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
+++ b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
@@ -57,11 +57,9 @@
 #include "sha256_mb_mgr.h"
 
 #define HASH_UPDATE          0x00
-#define HASH_FIRST           0x01
-#define HASH_LAST            0x02
-#define HASH_ENTIRE          0x03
-#define HASH_DONE	     0x04
-#define HASH_FINAL	     0x08
+#define HASH_LAST            0x01
+#define HASH_DONE	     0x02
+#define HASH_FINAL	     0x04
 
 #define HASH_CTX_STS_IDLE       0x00
 #define HASH_CTX_STS_PROCESSING 0x01
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb.c b/arch/x86/crypto/sha512-mb/sha512_mb.c
index 458409b7568d..39e2bbdc1836 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb.c
+++ b/arch/x86/crypto/sha512-mb/sha512_mb.c
@@ -107,15 +107,6 @@ static asmlinkage struct job_sha512* (*sha512_job_mgr_flush)
 static asmlinkage struct job_sha512* (*sha512_job_mgr_get_comp_job)
 						(struct sha512_mb_mgr *state);
 
-inline void sha512_init_digest(uint64_t *digest)
-{
-	static const uint64_t initial_digest[SHA512_DIGEST_LENGTH] = {
-					SHA512_H0, SHA512_H1, SHA512_H2,
-					SHA512_H3, SHA512_H4, SHA512_H5,
-					SHA512_H6, SHA512_H7 };
-	memcpy(digest, initial_digest, sizeof(initial_digest));
-}
-
 inline uint32_t sha512_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2],
 			 uint64_t total_len)
 {
@@ -263,11 +254,8 @@ static struct sha512_hash_ctx
 
 	mgr = cstate->mgr;
 	spin_lock_irqsave(&cstate->work_lock, irqflags);
-	if (flags & (~HASH_ENTIRE)) {
-		/*
-		 * User should not pass anything other than FIRST, UPDATE, or
-		 * LAST
-		 */
+	if (flags & ~(HASH_UPDATE | HASH_LAST)) {
+		/* User should not pass anything other than UPDATE or LAST */
 		ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
 		goto unlock;
 	}
@@ -278,24 +266,12 @@ static struct sha512_hash_ctx
 		goto unlock;
 	}
 
-	if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
+	if (ctx->status & HASH_CTX_STS_COMPLETE) {
 		/* Cannot update a finished job. */
 		ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
 		goto unlock;
 	}
 
-
-	if (flags & HASH_FIRST) {
-		/* Init digest */
-		sha512_init_digest(ctx->job.result_digest);
-
-		/* Reset byte counter */
-		ctx->total_length = 0;
-
-		/* Clear extra blocks */
-		ctx->partial_block_buffer_length = 0;
-	}
-
 	/*
 	 * If we made it here, there were no errors during this call to
 	 * submit
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
index e4653f5eec3f..e5c465bd821e 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
+++ b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
@@ -57,11 +57,9 @@
 #include "sha512_mb_mgr.h"
 
 #define HASH_UPDATE          0x00
-#define HASH_FIRST           0x01
-#define HASH_LAST            0x02
-#define HASH_ENTIRE          0x03
-#define HASH_DONE            0x04
-#define HASH_FINAL           0x08
+#define HASH_LAST            0x01
+#define HASH_DONE            0x02
+#define HASH_FINAL           0x04
 
 #define HASH_CTX_STS_IDLE       0x00
 #define HASH_CTX_STS_PROCESSING 0x01
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h
index dce7092ab24a..5d10b7a85cad 100644
--- a/arch/x86/entry/calling.h
+++ b/arch/x86/entry/calling.h
@@ -97,7 +97,7 @@ For 32-bit we have the following conventions - kernel is built with
 
 #define SIZEOF_PTREGS	21*8
 
-.macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax
+.macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0
 	/*
 	 * Push registers and sanitize registers of values that a
 	 * speculation attack might otherwise want to exploit. The
@@ -105,32 +105,41 @@ For 32-bit we have the following conventions - kernel is built with
 	 * could be put to use in a speculative execution gadget.
 	 * Interleave XOR with PUSH for better uop scheduling:
 	 */
+	.if \save_ret
+	pushq	%rsi		/* pt_regs->si */
+	movq	8(%rsp), %rsi	/* temporarily store the return address in %rsi */
+	movq	%rdi, 8(%rsp)	/* pt_regs->di (overwriting original return address) */
+	.else
 	pushq   %rdi		/* pt_regs->di */
 	pushq   %rsi		/* pt_regs->si */
+	.endif
 	pushq	\rdx		/* pt_regs->dx */
 	pushq   %rcx		/* pt_regs->cx */
 	pushq   \rax		/* pt_regs->ax */
 	pushq   %r8		/* pt_regs->r8 */
-	xorq    %r8, %r8	/* nospec   r8 */
+	xorl	%r8d, %r8d	/* nospec   r8 */
 	pushq   %r9		/* pt_regs->r9 */
-	xorq    %r9, %r9	/* nospec   r9 */
+	xorl	%r9d, %r9d	/* nospec   r9 */
 	pushq   %r10		/* pt_regs->r10 */
-	xorq    %r10, %r10	/* nospec   r10 */
+	xorl	%r10d, %r10d	/* nospec   r10 */
 	pushq   %r11		/* pt_regs->r11 */
-	xorq    %r11, %r11	/* nospec   r11*/
+	xorl	%r11d, %r11d	/* nospec   r11*/
 	pushq	%rbx		/* pt_regs->rbx */
 	xorl    %ebx, %ebx	/* nospec   rbx*/
 	pushq	%rbp		/* pt_regs->rbp */
 	xorl    %ebp, %ebp	/* nospec   rbp*/
 	pushq	%r12		/* pt_regs->r12 */
-	xorq    %r12, %r12	/* nospec   r12*/
+	xorl	%r12d, %r12d	/* nospec   r12*/
 	pushq	%r13		/* pt_regs->r13 */
-	xorq    %r13, %r13	/* nospec   r13*/
+	xorl	%r13d, %r13d	/* nospec   r13*/
 	pushq	%r14		/* pt_regs->r14 */
-	xorq    %r14, %r14	/* nospec   r14*/
+	xorl	%r14d, %r14d	/* nospec   r14*/
 	pushq	%r15		/* pt_regs->r15 */
-	xorq    %r15, %r15	/* nospec   r15*/
+	xorl	%r15d, %r15d	/* nospec   r15*/
 	UNWIND_HINT_REGS
+	.if \save_ret
+	pushq	%rsi		/* return address on top of stack */
+	.endif
 .endm
 
 .macro POP_REGS pop_rdi=1 skip_r11rcx=0
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 8971bd64d515..a9606d56eb60 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -260,8 +260,20 @@ GLOBAL(entry_SYSCALL_64_after_hwframe)
 	 * Change top bits to match most significant bit (47th or 56th bit
 	 * depending on paging mode) in the address.
 	 */
+#ifdef CONFIG_X86_5LEVEL
+	testl	$1, pgtable_l5_enabled(%rip)
+	jz	1f
+	shl	$(64 - 57), %rcx
+	sar	$(64 - 57), %rcx
+	jmp	2f
+1:
+	shl	$(64 - 48), %rcx
+	sar	$(64 - 48), %rcx
+2:
+#else
 	shl	$(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
 	sar	$(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
+#endif
 
 	/* If this changed %rcx, it was not canonical */
 	cmpq	%rcx, %r11
@@ -875,12 +887,8 @@ ENTRY(\sym)
 	pushq	$-1				/* ORIG_RAX: no syscall to restart */
 	.endif
 
-	/* Save all registers in pt_regs */
-	PUSH_AND_CLEAR_REGS
-	ENCODE_FRAME_POINTER
-
 	.if \paranoid < 2
-	testb	$3, CS(%rsp)			/* If coming from userspace, switch stacks */
+	testb	$3, CS-ORIG_RAX(%rsp)		/* If coming from userspace, switch stacks */
 	jnz	.Lfrom_usermode_switch_stack_\@
 	.endif
 
@@ -1130,13 +1138,15 @@ idtentry machine_check		do_mce			has_error_code=0	paranoid=1
 #endif
 
 /*
- * Switch gs if needed.
+ * Save all registers in pt_regs, and switch gs if needed.
  * Use slow, but surefire "are we in kernel?" check.
  * Return: ebx=0: need swapgs on exit, ebx=1: otherwise
  */
 ENTRY(paranoid_entry)
 	UNWIND_HINT_FUNC
 	cld
+	PUSH_AND_CLEAR_REGS save_ret=1
+	ENCODE_FRAME_POINTER 8
 	movl	$1, %ebx
 	movl	$MSR_GS_BASE, %ecx
 	rdmsr
@@ -1181,12 +1191,14 @@ ENTRY(paranoid_exit)
 END(paranoid_exit)
 
 /*
- * Switch gs if needed.
+ * Save all registers in pt_regs, and switch GS if needed.
  * Return: EBX=0: came from user mode; EBX=1: otherwise
  */
 ENTRY(error_entry)
-	UNWIND_HINT_REGS offset=8
+	UNWIND_HINT_FUNC
 	cld
+	PUSH_AND_CLEAR_REGS save_ret=1
+	ENCODE_FRAME_POINTER 8
 	testb	$3, CS+8(%rsp)
 	jz	.Lerror_kernelspace
 
@@ -1577,8 +1589,6 @@ end_repeat_nmi:
 	 * frame to point back to repeat_nmi.
 	 */
 	pushq	$-1				/* ORIG_RAX: no syscall to restart */
-	PUSH_AND_CLEAR_REGS
-	ENCODE_FRAME_POINTER
 
 	/*
 	 * Use paranoid_entry to handle SWAPGS, but no need to use paranoid_exit
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index fd65e016e413..364ea4a207be 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -85,25 +85,25 @@ ENTRY(entry_SYSENTER_compat)
 	pushq	%rcx			/* pt_regs->cx */
 	pushq	$-ENOSYS		/* pt_regs->ax */
 	pushq   $0			/* pt_regs->r8  = 0 */
-	xorq	%r8, %r8		/* nospec   r8 */
+	xorl	%r8d, %r8d		/* nospec   r8 */
 	pushq   $0			/* pt_regs->r9  = 0 */
-	xorq	%r9, %r9		/* nospec   r9 */
+	xorl	%r9d, %r9d		/* nospec   r9 */
 	pushq   $0			/* pt_regs->r10 = 0 */
-	xorq	%r10, %r10		/* nospec   r10 */
+	xorl	%r10d, %r10d		/* nospec   r10 */
 	pushq   $0			/* pt_regs->r11 = 0 */
-	xorq	%r11, %r11		/* nospec   r11 */
+	xorl	%r11d, %r11d		/* nospec   r11 */
 	pushq   %rbx                    /* pt_regs->rbx */
 	xorl	%ebx, %ebx		/* nospec   rbx */
 	pushq   %rbp                    /* pt_regs->rbp (will be overwritten) */
 	xorl	%ebp, %ebp		/* nospec   rbp */
 	pushq   $0			/* pt_regs->r12 = 0 */
-	xorq	%r12, %r12		/* nospec   r12 */
+	xorl	%r12d, %r12d		/* nospec   r12 */
 	pushq   $0			/* pt_regs->r13 = 0 */
-	xorq	%r13, %r13		/* nospec   r13 */
+	xorl	%r13d, %r13d		/* nospec   r13 */
 	pushq   $0			/* pt_regs->r14 = 0 */
-	xorq	%r14, %r14		/* nospec   r14 */
+	xorl	%r14d, %r14d		/* nospec   r14 */
 	pushq   $0			/* pt_regs->r15 = 0 */
-	xorq	%r15, %r15		/* nospec   r15 */
+	xorl	%r15d, %r15d		/* nospec   r15 */
 	cld
 
 	/*
@@ -224,25 +224,25 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe)
 	pushq	%rbp			/* pt_regs->cx (stashed in bp) */
 	pushq	$-ENOSYS		/* pt_regs->ax */
 	pushq   $0			/* pt_regs->r8  = 0 */
-	xorq	%r8, %r8		/* nospec   r8 */
+	xorl	%r8d, %r8d		/* nospec   r8 */
 	pushq   $0			/* pt_regs->r9  = 0 */
-	xorq	%r9, %r9		/* nospec   r9 */
+	xorl	%r9d, %r9d		/* nospec   r9 */
 	pushq   $0			/* pt_regs->r10 = 0 */
-	xorq	%r10, %r10		/* nospec   r10 */
+	xorl	%r10d, %r10d		/* nospec   r10 */
 	pushq   $0			/* pt_regs->r11 = 0 */
-	xorq	%r11, %r11		/* nospec   r11 */
+	xorl	%r11d, %r11d		/* nospec   r11 */
 	pushq   %rbx                    /* pt_regs->rbx */
 	xorl	%ebx, %ebx		/* nospec   rbx */
 	pushq   %rbp                    /* pt_regs->rbp (will be overwritten) */
 	xorl	%ebp, %ebp		/* nospec   rbp */
 	pushq   $0			/* pt_regs->r12 = 0 */
-	xorq	%r12, %r12		/* nospec   r12 */
+	xorl	%r12d, %r12d		/* nospec   r12 */
 	pushq   $0			/* pt_regs->r13 = 0 */
-	xorq	%r13, %r13		/* nospec   r13 */
+	xorl	%r13d, %r13d		/* nospec   r13 */
 	pushq   $0			/* pt_regs->r14 = 0 */
-	xorq	%r14, %r14		/* nospec   r14 */
+	xorl	%r14d, %r14d		/* nospec   r14 */
 	pushq   $0			/* pt_regs->r15 = 0 */
-	xorq	%r15, %r15		/* nospec   r15 */
+	xorl	%r15d, %r15d		/* nospec   r15 */
 
 	/*
 	 * User mode is traced as though IRQs are on, and SYSENTER
@@ -298,9 +298,9 @@ sysret32_from_system_call:
 	 */
 	SWITCH_TO_USER_CR3_NOSTACK scratch_reg=%r8 scratch_reg2=%r9
 
-	xorq	%r8, %r8
-	xorq	%r9, %r9
-	xorq	%r10, %r10
+	xorl	%r8d, %r8d
+	xorl	%r9d, %r9d
+	xorl	%r10d, %r10d
 	swapgs
 	sysretl
 END(entry_SYSCALL_compat)
@@ -358,25 +358,25 @@ ENTRY(entry_INT80_compat)
 	pushq	%rcx			/* pt_regs->cx */
 	pushq	$-ENOSYS		/* pt_regs->ax */
 	pushq   $0			/* pt_regs->r8  = 0 */
-	xorq	%r8, %r8		/* nospec   r8 */
+	xorl	%r8d, %r8d		/* nospec   r8 */
 	pushq   $0			/* pt_regs->r9  = 0 */
-	xorq	%r9, %r9		/* nospec   r9 */
+	xorl	%r9d, %r9d		/* nospec   r9 */
 	pushq   $0			/* pt_regs->r10 = 0 */
-	xorq	%r10, %r10		/* nospec   r10 */
+	xorl	%r10d, %r10d		/* nospec   r10 */
 	pushq   $0			/* pt_regs->r11 = 0 */
-	xorq	%r11, %r11		/* nospec   r11 */
+	xorl	%r11d, %r11d		/* nospec   r11 */
 	pushq   %rbx                    /* pt_regs->rbx */
 	xorl	%ebx, %ebx		/* nospec   rbx */
 	pushq   %rbp                    /* pt_regs->rbp */
 	xorl	%ebp, %ebp		/* nospec   rbp */
 	pushq   %r12                    /* pt_regs->r12 */
-	xorq	%r12, %r12		/* nospec   r12 */
+	xorl	%r12d, %r12d		/* nospec   r12 */
 	pushq   %r13                    /* pt_regs->r13 */
-	xorq	%r13, %r13		/* nospec   r13 */
+	xorl	%r13d, %r13d		/* nospec   r13 */
 	pushq   %r14                    /* pt_regs->r14 */
-	xorq	%r14, %r14		/* nospec   r14 */
+	xorl	%r14d, %r14d		/* nospec   r14 */
 	pushq   %r15                    /* pt_regs->r15 */
-	xorq	%r15, %r15		/* nospec   r15 */
+	xorl	%r15d, %r15d		/* nospec   r15 */
 	cld
 
 	/*
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 98722773391d..c6a32019ff54 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -138,7 +138,6 @@ extern void lapic_shutdown(void);
 extern void sync_Arb_IDs(void);
 extern void init_bsp_APIC(void);
 extern void apic_intr_mode_init(void);
-extern void setup_local_APIC(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
 extern void setup_boot_APIC_clock(void);
@@ -183,6 +182,7 @@ static inline void disable_local_APIC(void) { }
 # define setup_boot_APIC_clock x86_init_noop
 # define setup_secondary_APIC_clock x86_init_noop
 static inline void lapic_update_tsc_freq(void) { }
+static inline void init_bsp_APIC(void) { }
 static inline void apic_intr_mode_init(void) { }
 static inline void lapic_assign_system_vectors(void) { }
 static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index a8834dd546cd..fd20a2334885 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -183,16 +183,17 @@ extern void disable_ioapic_support(void);
 
 extern void __init io_apic_init_mappings(void);
 extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
-extern void native_disable_io_apic(void);
+extern void native_restore_boot_irq_mode(void);
 
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
-	return x86_io_apic_ops.read(apic, reg);
+	return x86_apic_ops.io_apic_read(apic, reg);
 }
 
 extern void setup_IO_APIC(void);
 extern void enable_IO_APIC(void);
-extern void disable_IO_APIC(void);
+extern void clear_IO_APIC(void);
+extern void restore_boot_irq_mode(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin);
 extern void print_IO_APICs(void);
 #else  /* !CONFIG_X86_IO_APIC */
@@ -228,10 +229,11 @@ static inline void mp_save_irq(struct mpc_intsrc *m) { }
 static inline void disable_ioapic_support(void) { }
 static inline void io_apic_init_mappings(void) { }
 #define native_io_apic_read		NULL
-#define native_disable_io_apic		NULL
+#define native_restore_boot_irq_mode	NULL
 
 static inline void setup_IO_APIC(void) { }
 static inline void enable_IO_APIC(void) { }
+static inline void restore_boot_irq_mode(void) { }
 
 #endif
 
diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h
index 460991e3b529..db7ba2feb947 100644
--- a/arch/x86/include/asm/kaslr.h
+++ b/arch/x86/include/asm/kaslr.h
@@ -5,10 +5,6 @@
 unsigned long kaslr_get_random_long(const char *purpose);
 
 #ifdef CONFIG_RANDOMIZE_MEMORY
-extern unsigned long page_offset_base;
-extern unsigned long vmalloc_base;
-extern unsigned long vmemmap_base;
-
 void kernel_randomize_memory(void);
 #else
 static inline void kernel_randomize_memory(void) { }
diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
index 22c5f3e6f820..8fe61ad21047 100644
--- a/arch/x86/include/asm/mem_encrypt.h
+++ b/arch/x86/include/asm/mem_encrypt.h
@@ -22,6 +22,7 @@
 #ifdef CONFIG_AMD_MEM_ENCRYPT
 
 extern u64 sme_me_mask;
+extern bool sev_enabled;
 
 void sme_encrypt_execute(unsigned long encrypted_kernel_vaddr,
 			 unsigned long decrypted_kernel_vaddr,
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 55520cec8b27..7fb1047d61c7 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -37,7 +37,12 @@ struct cpu_signature {
 
 struct device;
 
-enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND };
+enum ucode_state {
+	UCODE_OK	= 0,
+	UCODE_UPDATED,
+	UCODE_NFOUND,
+	UCODE_ERROR,
+};
 
 struct microcode_ops {
 	enum ucode_state (*request_microcode_user) (int cpu,
@@ -54,7 +59,7 @@ struct microcode_ops {
 	 * are being called.
 	 * See also the "Synchronization" section in microcode_core.c.
 	 */
-	int (*apply_microcode) (int cpu);
+	enum ucode_state (*apply_microcode) (int cpu);
 	int (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
 };
 
diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
index d652a3808065..939b1cff4a7b 100644
--- a/arch/x86/include/asm/page_64.h
+++ b/arch/x86/include/asm/page_64.h
@@ -11,6 +11,10 @@
 extern unsigned long max_pfn;
 extern unsigned long phys_base;
 
+extern unsigned long page_offset_base;
+extern unsigned long vmalloc_base;
+extern unsigned long vmemmap_base;
+
 static inline unsigned long __phys_addr_nodebug(unsigned long x)
 {
 	unsigned long y = x - __START_KERNEL_map;
@@ -47,7 +51,7 @@ static inline void clear_page(void *page)
 			   clear_page_erms, X86_FEATURE_ERMS,
 			   "=D" (page),
 			   "0" (page)
-			   : "memory", "rax", "rcx");
+			   : "cc", "memory", "rax", "rcx");
 }
 
 void copy_page(void *to, void *from);
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index e1407312c412..2c5a966dc222 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -37,26 +37,24 @@
  * hypervisor to fit.  Choosing 16 slots here is arbitrary, but it's
  * what Xen requires.
  */
-#ifdef CONFIG_X86_5LEVEL
-#define __PAGE_OFFSET_BASE      _AC(0xff10000000000000, UL)
-#else
-#define __PAGE_OFFSET_BASE      _AC(0xffff880000000000, UL)
-#endif
+#define __PAGE_OFFSET_BASE_L5	_AC(0xff10000000000000, UL)
+#define __PAGE_OFFSET_BASE_L4	_AC(0xffff880000000000, UL)
 
-#ifdef CONFIG_RANDOMIZE_MEMORY
+#ifdef CONFIG_DYNAMIC_MEMORY_LAYOUT
 #define __PAGE_OFFSET           page_offset_base
 #else
-#define __PAGE_OFFSET           __PAGE_OFFSET_BASE
-#endif /* CONFIG_RANDOMIZE_MEMORY */
+#define __PAGE_OFFSET           __PAGE_OFFSET_BASE_L4
+#endif /* CONFIG_DYNAMIC_MEMORY_LAYOUT */
 
 #define __START_KERNEL_map	_AC(0xffffffff80000000, UL)
 
 /* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */
-#ifdef CONFIG_X86_5LEVEL
+
 #define __PHYSICAL_MASK_SHIFT	52
-#define __VIRTUAL_MASK_SHIFT	56
+
+#ifdef CONFIG_X86_5LEVEL
+#define __VIRTUAL_MASK_SHIFT	(pgtable_l5_enabled ? 56 : 47)
 #else
-#define __PHYSICAL_MASK_SHIFT	46
 #define __VIRTUAL_MASK_SHIFT	47
 #endif
 
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 554841fab717..70d3c86927de 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -569,14 +569,16 @@ static inline p4dval_t p4d_val(p4d_t p4d)
 
 static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-	pgdval_t val = native_pgd_val(pgd);
-
-	PVOP_VCALL2(pv_mmu_ops.set_pgd, pgdp, val);
+	if (pgtable_l5_enabled)
+		PVOP_VCALL2(pv_mmu_ops.set_pgd, pgdp, native_pgd_val(pgd));
+	else
+		set_p4d((p4d_t *)(pgdp), (p4d_t) { pgd.pgd });
 }
 
 static inline void pgd_clear(pgd_t *pgdp)
 {
-	set_pgd(pgdp, __pgd(0));
+	if (pgtable_l5_enabled)
+		set_pgd(pgdp, __pgd(0));
 }
 
 #endif  /* CONFIG_PGTABLE_LEVELS == 5 */
diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h
index aff42e1da6ee..263c142a6a6c 100644
--- a/arch/x86/include/asm/pgalloc.h
+++ b/arch/x86/include/asm/pgalloc.h
@@ -167,6 +167,8 @@ static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
 #if CONFIG_PGTABLE_LEVELS > 4
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
 {
+	if (!pgtable_l5_enabled)
+		return;
 	paravirt_alloc_p4d(mm, __pa(p4d) >> PAGE_SHIFT);
 	set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(p4d)));
 }
@@ -191,7 +193,8 @@ extern void ___p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d);
 static inline void __p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d,
 				  unsigned long address)
 {
-	___p4d_free_tlb(tlb, p4d);
+	if (pgtable_l5_enabled)
+		___p4d_free_tlb(tlb, p4d);
 }
 
 #endif	/* CONFIG_PGTABLE_LEVELS > 4 */
diff --git a/arch/x86/include/asm/pgtable-3level_types.h b/arch/x86/include/asm/pgtable-3level_types.h
index 876b4c77d983..6a59a6d0cc50 100644
--- a/arch/x86/include/asm/pgtable-3level_types.h
+++ b/arch/x86/include/asm/pgtable-3level_types.h
@@ -44,5 +44,6 @@ typedef union {
  */
 #define PTRS_PER_PTE	512
 
+#define MAX_POSSIBLE_PHYSMEM_BITS	36
 
 #endif /* _ASM_X86_PGTABLE_3LEVEL_DEFS_H */
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 63c2552b6b65..c8baa7f12d1b 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -65,7 +65,7 @@ extern pmdval_t early_pmd_flags;
 
 #ifndef __PAGETABLE_P4D_FOLDED
 #define set_pgd(pgdp, pgd)		native_set_pgd(pgdp, pgd)
-#define pgd_clear(pgd)			native_pgd_clear(pgd)
+#define pgd_clear(pgd)			(pgtable_l5_enabled ? native_pgd_clear(pgd) : 0)
 #endif
 
 #ifndef set_p4d
@@ -859,6 +859,8 @@ static inline unsigned long p4d_index(unsigned long address)
 #if CONFIG_PGTABLE_LEVELS > 4
 static inline int pgd_present(pgd_t pgd)
 {
+	if (!pgtable_l5_enabled)
+		return 1;
 	return pgd_flags(pgd) & _PAGE_PRESENT;
 }
 
@@ -876,6 +878,8 @@ static inline unsigned long pgd_page_vaddr(pgd_t pgd)
 /* to find an entry in a page-table-directory. */
 static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
 {
+	if (!pgtable_l5_enabled)
+		return (p4d_t *)pgd;
 	return (p4d_t *)pgd_page_vaddr(*pgd) + p4d_index(address);
 }
 
@@ -883,6 +887,9 @@ static inline int pgd_bad(pgd_t pgd)
 {
 	unsigned long ignore_flags = _PAGE_USER;
 
+	if (!pgtable_l5_enabled)
+		return 0;
+
 	if (IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION))
 		ignore_flags |= _PAGE_NX;
 
@@ -891,6 +898,8 @@ static inline int pgd_bad(pgd_t pgd)
 
 static inline int pgd_none(pgd_t pgd)
 {
+	if (!pgtable_l5_enabled)
+		return 0;
 	/*
 	 * There is no need to do a workaround for the KNL stray
 	 * A/D bit erratum here.  PGDs only point to page tables
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index e55466760ff8..b838c51d8c78 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -33,6 +33,8 @@ static inline void pgtable_cache_init(void) { }
 static inline void check_pgt_cache(void) { }
 void paging_init(void);
 
+static inline int pgd_large(pgd_t pgd) { return 0; }
+
 /*
  * Define this if things work differently on an i386 and an i486:
  * it will (on an i486) warn about kernel memory accesses that are
diff --git a/arch/x86/include/asm/pgtable_32_types.h b/arch/x86/include/asm/pgtable_32_types.h
index 0777e18a1d23..e3225e83db7d 100644
--- a/arch/x86/include/asm/pgtable_32_types.h
+++ b/arch/x86/include/asm/pgtable_32_types.h
@@ -15,6 +15,8 @@
 # include <asm/pgtable-2level_types.h>
 #endif
 
+#define pgtable_l5_enabled 0
+
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE - 1))
 
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index 81462e9a34f6..81dda8d1d0bd 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -217,29 +217,26 @@ static inline pgd_t pti_set_user_pgd(pgd_t *pgdp, pgd_t pgd)
 
 static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d)
 {
-#if defined(CONFIG_PAGE_TABLE_ISOLATION) && !defined(CONFIG_X86_5LEVEL)
-	p4dp->pgd = pti_set_user_pgd(&p4dp->pgd, p4d.pgd);
-#else
-	*p4dp = p4d;
-#endif
+	pgd_t pgd;
+
+	if (pgtable_l5_enabled || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) {
+		*p4dp = p4d;
+		return;
+	}
+
+	pgd = native_make_pgd(p4d_val(p4d));
+	pgd = pti_set_user_pgd((pgd_t *)p4dp, pgd);
+	*p4dp = native_make_p4d(pgd_val(pgd));
 }
 
 static inline void native_p4d_clear(p4d_t *p4d)
 {
-#ifdef CONFIG_X86_5LEVEL
 	native_set_p4d(p4d, native_make_p4d(0));
-#else
-	native_set_p4d(p4d, (p4d_t) { .pgd = native_make_pgd(0)});
-#endif
 }
 
 static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-#ifdef CONFIG_PAGE_TABLE_ISOLATION
 	*pgdp = pti_set_user_pgd(pgdp, pgd);
-#else
-	*pgdp = pgd;
-#endif
 }
 
 static inline void native_pgd_clear(pgd_t *pgd)
diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h
index 6b8f73dcbc2c..68909a68e5b9 100644
--- a/arch/x86/include/asm/pgtable_64_types.h
+++ b/arch/x86/include/asm/pgtable_64_types.h
@@ -20,6 +20,15 @@ typedef unsigned long	pgprotval_t;
 
 typedef struct { pteval_t pte; } pte_t;
 
+#ifdef CONFIG_X86_5LEVEL
+extern unsigned int pgtable_l5_enabled;
+#else
+#define pgtable_l5_enabled 0
+#endif
+
+extern unsigned int pgdir_shift;
+extern unsigned int ptrs_per_p4d;
+
 #endif	/* !__ASSEMBLY__ */
 
 #define SHARED_KERNEL_PMD	0
@@ -29,24 +38,28 @@ typedef struct { pteval_t pte; } pte_t;
 /*
  * PGDIR_SHIFT determines what a top-level page table entry can map
  */
-#define PGDIR_SHIFT	48
+#define PGDIR_SHIFT	pgdir_shift
 #define PTRS_PER_PGD	512
 
 /*
  * 4th level page in 5-level paging case
  */
-#define P4D_SHIFT	39
-#define PTRS_PER_P4D	512
-#define P4D_SIZE	(_AC(1, UL) << P4D_SHIFT)
-#define P4D_MASK	(~(P4D_SIZE - 1))
+#define P4D_SHIFT		39
+#define MAX_PTRS_PER_P4D	512
+#define PTRS_PER_P4D		ptrs_per_p4d
+#define P4D_SIZE		(_AC(1, UL) << P4D_SHIFT)
+#define P4D_MASK		(~(P4D_SIZE - 1))
+
+#define MAX_POSSIBLE_PHYSMEM_BITS	52
 
 #else /* CONFIG_X86_5LEVEL */
 
 /*
  * PGDIR_SHIFT determines what a top-level page table entry can map
  */
-#define PGDIR_SHIFT	39
-#define PTRS_PER_PGD	512
+#define PGDIR_SHIFT		39
+#define PTRS_PER_PGD		512
+#define MAX_PTRS_PER_P4D	1
 
 #endif /* CONFIG_X86_5LEVEL */
 
@@ -82,31 +95,33 @@ typedef struct { pteval_t pte; } pte_t;
  * range must not overlap with anything except the KASAN shadow area, which
  * is correct as KASAN disables KASLR.
  */
-#define MAXMEM			_AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL)
+#define MAXMEM			(1UL << MAX_PHYSMEM_BITS)
 
-#ifdef CONFIG_X86_5LEVEL
-# define VMALLOC_SIZE_TB	_AC(12800, UL)
-# define __VMALLOC_BASE		_AC(0xffa0000000000000, UL)
-# define __VMEMMAP_BASE		_AC(0xffd4000000000000, UL)
-# define LDT_PGD_ENTRY		_AC(-112, UL)
-# define LDT_BASE_ADDR		(LDT_PGD_ENTRY << PGDIR_SHIFT)
-#else
-# define VMALLOC_SIZE_TB	_AC(32, UL)
-# define __VMALLOC_BASE		_AC(0xffffc90000000000, UL)
-# define __VMEMMAP_BASE		_AC(0xffffea0000000000, UL)
-# define LDT_PGD_ENTRY		_AC(-3, UL)
-# define LDT_BASE_ADDR		(LDT_PGD_ENTRY << PGDIR_SHIFT)
-#endif
+#define LDT_PGD_ENTRY_L4	-3UL
+#define LDT_PGD_ENTRY_L5	-112UL
+#define LDT_PGD_ENTRY		(pgtable_l5_enabled ? LDT_PGD_ENTRY_L5 : LDT_PGD_ENTRY_L4)
+#define LDT_BASE_ADDR		(LDT_PGD_ENTRY << PGDIR_SHIFT)
+
+#define __VMALLOC_BASE_L4	0xffffc90000000000
+#define __VMALLOC_BASE_L5 	0xffa0000000000000
+
+#define VMALLOC_SIZE_TB_L4	32UL
+#define VMALLOC_SIZE_TB_L5	12800UL
+
+#define __VMEMMAP_BASE_L4	0xffffea0000000000
+#define __VMEMMAP_BASE_L5	0xffd4000000000000
 
-#ifdef CONFIG_RANDOMIZE_MEMORY
+#ifdef CONFIG_DYNAMIC_MEMORY_LAYOUT
 # define VMALLOC_START		vmalloc_base
+# define VMALLOC_SIZE_TB	(pgtable_l5_enabled ? VMALLOC_SIZE_TB_L5 : VMALLOC_SIZE_TB_L4)
 # define VMEMMAP_START		vmemmap_base
 #else
-# define VMALLOC_START		__VMALLOC_BASE
-# define VMEMMAP_START		__VMEMMAP_BASE
-#endif /* CONFIG_RANDOMIZE_MEMORY */
+# define VMALLOC_START		__VMALLOC_BASE_L4
+# define VMALLOC_SIZE_TB	VMALLOC_SIZE_TB_L4
+# define VMEMMAP_START		__VMEMMAP_BASE_L4
+#endif /* CONFIG_DYNAMIC_MEMORY_LAYOUT */
 
-#define VMALLOC_END		(VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))
+#define VMALLOC_END		(VMALLOC_START + (VMALLOC_SIZE_TB << 40) - 1)
 
 #define MODULES_VADDR		(__START_KERNEL_map + KERNEL_IMAGE_SIZE)
 /* The module sections ends with the start of the fixmap */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 1bd9ed87606f..b0ccd4847a58 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -977,4 +977,5 @@ bool xen_set_default_idle(void);
 
 void stop_this_cpu(void *dummy);
 void df_debug(struct pt_regs *regs, long error_code);
+void microcode_check(void);
 #endif /* _ASM_X86_PROCESSOR_H */
diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h
index fb3a6de7440b..6847d85400a8 100644
--- a/arch/x86/include/asm/required-features.h
+++ b/arch/x86/include/asm/required-features.h
@@ -53,12 +53,6 @@
 # define NEED_MOVBE	0
 #endif
 
-#ifdef CONFIG_X86_5LEVEL
-# define NEED_LA57	(1<<(X86_FEATURE_LA57 & 31))
-#else
-# define NEED_LA57	0
-#endif
-
 #ifdef CONFIG_X86_64
 #ifdef CONFIG_PARAVIRT
 /* Paravirtualized systems may not have PSE or PGE available */
@@ -104,7 +98,7 @@
 #define REQUIRED_MASK13	0
 #define REQUIRED_MASK14	0
 #define REQUIRED_MASK15	0
-#define REQUIRED_MASK16	(NEED_LA57)
+#define REQUIRED_MASK16	0
 #define REQUIRED_MASK17	0
 #define REQUIRED_MASK18	0
 #define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
diff --git a/arch/x86/include/asm/sparsemem.h b/arch/x86/include/asm/sparsemem.h
index 4fc1e9d3c43e..4617a2bf123c 100644
--- a/arch/x86/include/asm/sparsemem.h
+++ b/arch/x86/include/asm/sparsemem.h
@@ -27,13 +27,8 @@
 # endif
 #else /* CONFIG_X86_32 */
 # define SECTION_SIZE_BITS	27 /* matt - 128 is convenient right now */
-# ifdef CONFIG_X86_5LEVEL
-#  define MAX_PHYSADDR_BITS	52
-#  define MAX_PHYSMEM_BITS	52
-# else
-#  define MAX_PHYSADDR_BITS	44
-#  define MAX_PHYSMEM_BITS	46
-# endif
+# define MAX_PHYSADDR_BITS	(pgtable_l5_enabled ? 52 : 44)
+# define MAX_PHYSMEM_BITS	(pgtable_l5_enabled ? 52 : 46)
 #endif
 
 #endif /* CONFIG_SPARSEMEM */
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index fc2f082ac635..88306054bd98 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -274,16 +274,16 @@ struct x86_msi_ops {
 	void (*restore_msi_irqs)(struct pci_dev *dev);
 };
 
-struct x86_io_apic_ops {
-	unsigned int	(*read)   (unsigned int apic, unsigned int reg);
-	void		(*disable)(void);
+struct x86_apic_ops {
+	unsigned int	(*io_apic_read)   (unsigned int apic, unsigned int reg);
+	void		(*restore)(void);
 };
 
 extern struct x86_init_ops x86_init;
 extern struct x86_cpuinit_ops x86_cpuinit;
 extern struct x86_platform_ops x86_platform;
 extern struct x86_msi_ops x86_msi;
-extern struct x86_io_apic_ops x86_io_apic_ops;
+extern struct x86_apic_ops x86_apic_ops;
 
 extern void x86_early_init_platform_quirks(void);
 extern void x86_init_noop(void);
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index b203af0855b5..84b244ec49ed 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1414,7 +1414,7 @@ static void lapic_setup_esr(void)
  * Used to setup local APIC while initializing BSP or bringing up APs.
  * Always called with preemption disabled.
  */
-void setup_local_APIC(void)
+static void setup_local_APIC(void)
 {
 	int cpu = smp_processor_id();
 	unsigned int value, queued;
@@ -1570,7 +1570,7 @@ void setup_local_APIC(void)
 	 * TODO: set up through-local-APIC from through-I/O-APIC? --macro
 	 */
 	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
-	if (!cpu && (pic_mode || !value)) {
+	if (!cpu && (pic_mode || !value || skip_ioapic_setup)) {
 		value = APIC_DM_EXTINT;
 		apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu);
 	} else {
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 8ad2e410974f..68129f11e7db 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -587,7 +587,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 		       mpc_ioapic_id(apic), pin);
 }
 
-static void clear_IO_APIC (void)
+void clear_IO_APIC (void)
 {
 	int apic, pin;
 
@@ -1410,7 +1410,7 @@ void __init enable_IO_APIC(void)
 	clear_IO_APIC();
 }
 
-void native_disable_io_apic(void)
+void native_restore_boot_irq_mode(void)
 {
 	/*
 	 * If the i8259 is routed through an IOAPIC
@@ -1438,20 +1438,12 @@ void native_disable_io_apic(void)
 		disconnect_bsp_APIC(ioapic_i8259.pin != -1);
 }
 
-/*
- * Not an __init, needed by the reboot code
- */
-void disable_IO_APIC(void)
+void restore_boot_irq_mode(void)
 {
-	/*
-	 * Clear the IO-APIC before rebooting:
-	 */
-	clear_IO_APIC();
-
 	if (!nr_legacy_irqs())
 		return;
 
-	x86_io_apic_ops.disable();
+	x86_apic_ops.restore();
 }
 
 #ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index f8d9d69994e6..e2829bf40e4a 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -14,7 +14,7 @@ int x2apic_phys;
 
 static struct apic apic_x2apic_phys;
 
-static int set_x2apic_phys_mode(char *arg)
+static int __init set_x2apic_phys_mode(char *arg)
 {
 	x2apic_phys = 1;
 	return 0;
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 824aee0117bb..348cf4821240 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1749,3 +1749,33 @@ static int __init init_cpu_syscore(void)
 	return 0;
 }
 core_initcall(init_cpu_syscore);
+
+/*
+ * The microcode loader calls this upon late microcode load to recheck features,
+ * only when microcode has been updated. Caller holds microcode_mutex and CPU
+ * hotplug lock.
+ */
+void microcode_check(void)
+{
+	struct cpuinfo_x86 info;
+
+	perf_check_microcode();
+
+	/* Reload CPUID max function as it might've changed. */
+	info.cpuid_level = cpuid_eax(0);
+
+	/*
+	 * Copy all capability leafs to pick up the synthetic ones so that
+	 * memcmp() below doesn't fail on that. The ones coming from CPUID will
+	 * get overwritten in get_cpu_cap().
+	 */
+	memcpy(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability));
+
+	get_cpu_cap(&info);
+
+	if (!memcmp(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability)))
+		return;
+
+	pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n");
+	pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
+}
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 8ff94d1e2dce..3d8c573a9a27 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -1088,19 +1088,7 @@ static void mce_unmap_kpfn(unsigned long pfn)
 	 * a legal address.
 	 */
 
-/*
- * Build time check to see if we have a spare virtual bit. Don't want
- * to leave this until run time because most developers don't have a
- * system that can exercise this code path. This will only become a
- * problem if/when we move beyond 5-level page tables.
- *
- * Hard code "9" here because cpp doesn't grok ilog2(PTRS_PER_PGD)
- */
-#if PGDIR_SHIFT + 9 < 63
 	decoy_addr = (pfn << PAGE_SHIFT) + (PAGE_OFFSET ^ BIT(63));
-#else
-#error "no unused virtual bit available"
-#endif
 
 	if (set_memory_np(decoy_addr, 1))
 		pr_warn("Could not invalidate pfn=0x%lx from 1:1 map\n", pfn);
@@ -2333,6 +2321,12 @@ static __init int mcheck_init_device(void)
 {
 	int err;
 
+	/*
+	 * Check if we have a spare virtual bit. This will only become
+	 * a problem if/when we move beyond 5-level page tables.
+	 */
+	MAYBE_BUILD_BUG_ON(__VIRTUAL_MASK_SHIFT >= 63);
+
 	if (!mce_available(&boot_cpu_data)) {
 		err = -EIO;
 		goto err_out;
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index 330b8462d426..a998e1a7d46f 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -498,7 +498,7 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size,
 	return patch_size;
 }
 
-static int apply_microcode_amd(int cpu)
+static enum ucode_state apply_microcode_amd(int cpu)
 {
 	struct cpuinfo_x86 *c = &cpu_data(cpu);
 	struct microcode_amd *mc_amd;
@@ -512,7 +512,7 @@ static int apply_microcode_amd(int cpu)
 
 	p = find_patch(cpu);
 	if (!p)
-		return 0;
+		return UCODE_NFOUND;
 
 	mc_amd  = p->data;
 	uci->mc = p->data;
@@ -523,13 +523,13 @@ static int apply_microcode_amd(int cpu)
 	if (rev >= mc_amd->hdr.patch_id) {
 		c->microcode = rev;
 		uci->cpu_sig.rev = rev;
-		return 0;
+		return UCODE_OK;
 	}
 
 	if (__apply_microcode_amd(mc_amd)) {
 		pr_err("CPU%d: update failed for patch_level=0x%08x\n",
 			cpu, mc_amd->hdr.patch_id);
-		return -1;
+		return UCODE_ERROR;
 	}
 	pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
 		mc_amd->hdr.patch_id);
@@ -537,7 +537,7 @@ static int apply_microcode_amd(int cpu)
 	uci->cpu_sig.rev = mc_amd->hdr.patch_id;
 	c->microcode = mc_amd->hdr.patch_id;
 
-	return 0;
+	return UCODE_UPDATED;
 }
 
 static int install_equiv_cpu_table(const u8 *buf)
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 319dd65f98a2..aa1b9a422f2b 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -374,7 +374,7 @@ static int collect_cpu_info(int cpu)
 }
 
 struct apply_microcode_ctx {
-	int err;
+	enum ucode_state err;
 };
 
 static void apply_microcode_local(void *arg)
@@ -489,31 +489,30 @@ static void __exit microcode_dev_exit(void)
 /* fake device for request_firmware */
 static struct platform_device	*microcode_pdev;
 
-static int reload_for_cpu(int cpu)
+static enum ucode_state reload_for_cpu(int cpu)
 {
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 	enum ucode_state ustate;
-	int err = 0;
 
 	if (!uci->valid)
-		return err;
+		return UCODE_OK;
 
 	ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, true);
-	if (ustate == UCODE_OK)
-		apply_microcode_on_target(cpu);
-	else
-		if (ustate == UCODE_ERROR)
-			err = -EINVAL;
-	return err;
+	if (ustate != UCODE_OK)
+		return ustate;
+
+	return apply_microcode_on_target(cpu);
 }
 
 static ssize_t reload_store(struct device *dev,
 			    struct device_attribute *attr,
 			    const char *buf, size_t size)
 {
+	enum ucode_state tmp_ret = UCODE_OK;
+	bool do_callback = false;
 	unsigned long val;
+	ssize_t ret = 0;
 	int cpu;
-	ssize_t ret = 0, tmp_ret;
 
 	ret = kstrtoul(buf, 0, &val);
 	if (ret)
@@ -526,15 +525,21 @@ static ssize_t reload_store(struct device *dev,
 	mutex_lock(&microcode_mutex);
 	for_each_online_cpu(cpu) {
 		tmp_ret = reload_for_cpu(cpu);
-		if (tmp_ret != 0)
+		if (tmp_ret > UCODE_NFOUND) {
 			pr_warn("Error reloading microcode on CPU %d\n", cpu);
 
-		/* save retval of the first encountered reload error */
-		if (!ret)
-			ret = tmp_ret;
+			/* set retval for the first encountered reload error */
+			if (!ret)
+				ret = -EINVAL;
+		}
+
+		if (tmp_ret == UCODE_UPDATED)
+			do_callback = true;
 	}
-	if (!ret)
-		perf_check_microcode();
+
+	if (!ret && do_callback)
+		microcode_check();
+
 	mutex_unlock(&microcode_mutex);
 	put_online_cpus();
 
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index a15db2b4e0d6..923054a6b760 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -772,7 +772,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
 	return 0;
 }
 
-static int apply_microcode_intel(int cpu)
+static enum ucode_state apply_microcode_intel(int cpu)
 {
 	struct microcode_intel *mc;
 	struct ucode_cpu_info *uci;
@@ -782,7 +782,7 @@ static int apply_microcode_intel(int cpu)
 
 	/* We should bind the task to the CPU */
 	if (WARN_ON(raw_smp_processor_id() != cpu))
-		return -1;
+		return UCODE_ERROR;
 
 	uci = ucode_cpu_info + cpu;
 	mc = uci->mc;
@@ -790,7 +790,7 @@ static int apply_microcode_intel(int cpu)
 		/* Look for a newer patch in our cache: */
 		mc = find_patch(uci);
 		if (!mc)
-			return 0;
+			return UCODE_NFOUND;
 	}
 
 	/* write microcode via MSR 0x79 */
@@ -801,7 +801,7 @@ static int apply_microcode_intel(int cpu)
 	if (rev != mc->hdr.rev) {
 		pr_err("CPU%d update to revision 0x%x failed\n",
 		       cpu, mc->hdr.rev);
-		return -1;
+		return UCODE_ERROR;
 	}
 
 	if (rev != prev_rev) {
@@ -818,7 +818,7 @@ static int apply_microcode_intel(int cpu)
 	uci->cpu_sig.rev = rev;
 	c->microcode = rev;
 
-	return 0;
+	return UCODE_UPDATED;
 }
 
 static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 10e74d4778a1..1f6680427ff0 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -199,9 +199,10 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
 #ifdef CONFIG_X86_IO_APIC
 	/* Prevent crash_kexec() from deadlocking on ioapic_lock. */
 	ioapic_zap_locks();
-	disable_IO_APIC();
+	clear_IO_APIC();
 #endif
 	lapic_shutdown();
+	restore_boot_irq_mode();
 #ifdef CONFIG_HPET_TIMER
 	hpet_disable();
 #endif
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 71c11ad5643e..6a2cb1442e05 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -924,6 +924,24 @@ static int __init parse_memmap_one(char *p)
 	} else if (*p == '!') {
 		start_at = memparse(p+1, &p);
 		e820__range_add(start_at, mem_size, E820_TYPE_PRAM);
+	} else if (*p == '%') {
+		enum e820_type from = 0, to = 0;
+
+		start_at = memparse(p + 1, &p);
+		if (*p == '-')
+			from = simple_strtoull(p + 1, &p, 0);
+		if (*p == '+')
+			to = simple_strtoull(p + 1, &p, 0);
+		if (*p != '\0')
+			return -EINVAL;
+		if (from && to)
+			e820__range_update(start_at, mem_size, from, to);
+		else if (to)
+			e820__range_add(start_at, mem_size, to);
+		else if (from)
+			e820__range_remove(start_at, mem_size, from, 1);
+		else
+			e820__range_remove(start_at, mem_size, 0, 0);
 	} else {
 		e820__range_remove(mem_size, ULLONG_MAX - mem_size, E820_TYPE_RAM, 1);
 	}
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 7ba5d819ebe3..8161e719a20f 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -39,6 +39,24 @@ extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
 static unsigned int __initdata next_early_pgt;
 pmdval_t early_pmd_flags = __PAGE_KERNEL_LARGE & ~(_PAGE_GLOBAL | _PAGE_NX);
 
+#ifdef CONFIG_X86_5LEVEL
+unsigned int pgtable_l5_enabled __ro_after_init;
+EXPORT_SYMBOL(pgtable_l5_enabled);
+unsigned int pgdir_shift __ro_after_init = 39;
+EXPORT_SYMBOL(pgdir_shift);
+unsigned int ptrs_per_p4d __ro_after_init = 1;
+EXPORT_SYMBOL(ptrs_per_p4d);
+#endif
+
+#ifdef CONFIG_DYNAMIC_MEMORY_LAYOUT
+unsigned long page_offset_base __ro_after_init = __PAGE_OFFSET_BASE_L4;
+EXPORT_SYMBOL(page_offset_base);
+unsigned long vmalloc_base __ro_after_init = __VMALLOC_BASE_L4;
+EXPORT_SYMBOL(vmalloc_base);
+unsigned long vmemmap_base __ro_after_init = __VMEMMAP_BASE_L4;
+EXPORT_SYMBOL(vmemmap_base);
+#endif
+
 #define __head	__section(.head.text)
 
 static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
@@ -46,6 +64,41 @@ static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
 	return ptr - (void *)_text + (void *)physaddr;
 }
 
+static unsigned long __head *fixup_long(void *ptr, unsigned long physaddr)
+{
+	return fixup_pointer(ptr, physaddr);
+}
+
+#ifdef CONFIG_X86_5LEVEL
+static unsigned int __head *fixup_int(void *ptr, unsigned long physaddr)
+{
+	return fixup_pointer(ptr, physaddr);
+}
+
+static bool __head check_la57_support(unsigned long physaddr)
+{
+	if (native_cpuid_eax(0) < 7)
+		return false;
+
+	if (!(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31))))
+		return false;
+
+	*fixup_int(&pgtable_l5_enabled, physaddr) = 1;
+	*fixup_int(&pgdir_shift, physaddr) = 48;
+	*fixup_int(&ptrs_per_p4d, physaddr) = 512;
+	*fixup_long(&page_offset_base, physaddr) = __PAGE_OFFSET_BASE_L5;
+	*fixup_long(&vmalloc_base, physaddr) = __VMALLOC_BASE_L5;
+	*fixup_long(&vmemmap_base, physaddr) = __VMEMMAP_BASE_L5;
+
+	return true;
+}
+#else
+static bool __head check_la57_support(unsigned long physaddr)
+{
+	return false;
+}
+#endif
+
 unsigned long __head __startup_64(unsigned long physaddr,
 				  struct boot_params *bp)
 {
@@ -55,9 +108,12 @@ unsigned long __head __startup_64(unsigned long physaddr,
 	p4dval_t *p4d;
 	pudval_t *pud;
 	pmdval_t *pmd, pmd_entry;
+	bool la57;
 	int i;
 	unsigned int *next_pgt_ptr;
 
+	la57 = check_la57_support(physaddr);
+
 	/* Is the address too large? */
 	if (physaddr >> MAX_PHYSMEM_BITS)
 		for (;;);
@@ -81,9 +137,14 @@ unsigned long __head __startup_64(unsigned long physaddr,
 	/* Fixup the physical addresses in the page table */
 
 	pgd = fixup_pointer(&early_top_pgt, physaddr);
-	pgd[pgd_index(__START_KERNEL_map)] += load_delta;
-
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+	p = pgd + pgd_index(__START_KERNEL_map);
+	if (la57)
+		*p = (unsigned long)level4_kernel_pgt;
+	else
+		*p = (unsigned long)level3_kernel_pgt;
+	*p += _PAGE_TABLE_NOENC - __START_KERNEL_map + load_delta;
+
+	if (la57) {
 		p4d = fixup_pointer(&level4_kernel_pgt, physaddr);
 		p4d[511] += load_delta;
 	}
@@ -108,7 +169,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
 
 	pgtable_flags = _KERNPG_TABLE_NOENC + sme_get_me_mask();
 
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+	if (la57) {
 		p4d = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
 
 		i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
@@ -154,8 +215,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
 	 * Fixup phys_base - remove the memory encryption mask to obtain
 	 * the true physical address.
 	 */
-	p = fixup_pointer(&phys_base, physaddr);
-	*p += load_delta - sme_get_me_mask();
+	*fixup_long(&phys_base, physaddr) += load_delta - sme_get_me_mask();
 
 	/* Encrypt the kernel and related (if SME is active) */
 	sme_encrypt_kernel(bp);
@@ -206,7 +266,7 @@ int __init __early_make_pgtable(unsigned long address, pmdval_t pmd)
 	 * critical -- __PAGE_OFFSET would point us back into the dynamic
 	 * range and we might end up looping forever...
 	 */
-	if (!IS_ENABLED(CONFIG_X86_5LEVEL))
+	if (!pgtable_l5_enabled)
 		p4d_p = pgd_p;
 	else if (pgd)
 		p4d_p = (p4dval_t *)((pgd & PTE_PFN_MASK) + __START_KERNEL_map - phys_base);
@@ -322,7 +382,7 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
 	BUILD_BUG_ON((__START_KERNEL_map & ~PMD_MASK) != 0);
 	BUILD_BUG_ON((MODULES_VADDR & ~PMD_MASK) != 0);
 	BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL));
-	BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) ==
+	MAYBE_BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) ==
 				(__START_KERNEL & PGDIR_MASK)));
 	BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
 
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 04a625f0fcda..145d7b95ae29 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -41,7 +41,7 @@
 #define pud_index(x)	(((x) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
 
 #if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH)
-PGD_PAGE_OFFSET = pgd_index(__PAGE_OFFSET_BASE)
+PGD_PAGE_OFFSET = pgd_index(__PAGE_OFFSET_BASE_L4)
 PGD_START_KERNEL = pgd_index(__START_KERNEL_map)
 #endif
 L3_START_KERNEL = pud_index(__START_KERNEL_map)
@@ -124,7 +124,10 @@ ENTRY(secondary_startup_64)
 	/* Enable PAE mode, PGE and LA57 */
 	movl	$(X86_CR4_PAE | X86_CR4_PGE), %ecx
 #ifdef CONFIG_X86_5LEVEL
+	testl	$1, pgtable_l5_enabled(%rip)
+	jz	1f
 	orl	$X86_CR4_LA57, %ecx
+1:
 #endif
 	movq	%rcx, %cr4
 
@@ -372,12 +375,7 @@ GLOBAL(name)
 
 	__INITDATA
 NEXT_PGD_PAGE(early_top_pgt)
-	.fill	511,8,0
-#ifdef CONFIG_X86_5LEVEL
-	.quad	level4_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
-#else
-	.quad	level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
-#endif
+	.fill	512,8,0
 	.fill	PTI_USER_PGD_FILL,8,0
 
 NEXT_PAGE(early_dynamic_pgts)
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index a539410c4ea9..772196c1b8c4 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -61,9 +61,14 @@ void __init init_ISA_irqs(void)
 	struct irq_chip *chip = legacy_pic->chip;
 	int i;
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
+	/*
+	 * Try to set up the through-local-APIC virtual wire mode earlier.
+	 *
+	 * On some 32-bit UP machines, whose APIC has been disabled by BIOS
+	 * and then got re-enabled by "lapic", it hangs at boot time without this.
+	 */
 	init_bsp_APIC();
-#endif
+
 	legacy_pic->init(0);
 
 	for (i = 0; i < nr_legacy_irqs(); i++)
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c
index edfede768688..60cdec6628b0 100644
--- a/arch/x86/kernel/machine_kexec_32.c
+++ b/arch/x86/kernel/machine_kexec_32.c
@@ -195,11 +195,11 @@ void machine_kexec(struct kimage *image)
 		/*
 		 * We need to put APICs in legacy mode so that we can
 		 * get timer interrupts in second kernel. kexec/kdump
-		 * paths already have calls to disable_IO_APIC() in
-		 * one form or other. kexec jump path also need
-		 * one.
+		 * paths already have calls to restore_boot_irq_mode()
+		 * in one form or other. kexec jump path also need one.
 		 */
-		disable_IO_APIC();
+		clear_IO_APIC();
+		restore_boot_irq_mode();
 #endif
 	}
 
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index 1f790cf9d38f..fbc0af5cafb2 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -293,11 +293,11 @@ void machine_kexec(struct kimage *image)
 		/*
 		 * We need to put APICs in legacy mode so that we can
 		 * get timer interrupts in second kernel. kexec/kdump
-		 * paths already have calls to disable_IO_APIC() in
-		 * one form or other. kexec jump path also need
-		 * one.
+		 * paths already have calls to restore_boot_irq_mode()
+		 * in one form or other. kexec jump path also need one.
 		 */
-		disable_IO_APIC();
+		clear_IO_APIC();
+		restore_boot_irq_mode();
 #endif
 	}
 
@@ -358,6 +358,7 @@ void arch_crash_save_vmcoreinfo(void)
 	vmcoreinfo_append_str("KERNELOFFSET=%lx\n",
 			      kaslr_offset());
 	VMCOREINFO_NUMBER(KERNEL_IMAGE_SIZE);
+	VMCOREINFO_PHYS_BASE(phys_base);
 }
 
 /* arch-dependent functionality related to kexec file-based syscall */
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 2126b9d27c34..725624b6c0c0 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -666,7 +666,7 @@ void native_machine_shutdown(void)
 	 * Even without the erratum, it still makes sense to quiet IO APIC
 	 * before disabling Local APIC.
 	 */
-	disable_IO_APIC();
+	clear_IO_APIC();
 #endif
 
 #ifdef CONFIG_SMP
@@ -680,6 +680,7 @@ void native_machine_shutdown(void)
 #endif
 
 	lapic_shutdown();
+	restore_boot_irq_mode();
 
 #ifdef CONFIG_HPET_TIMER
 	hpet_disable();
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1ae67e982af7..399d0f7fa8f1 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -189,9 +189,7 @@ struct ist_info ist_info;
 #endif
 
 #else
-struct cpuinfo_x86 boot_cpu_data __read_mostly = {
-	.x86_phys_bits = MAX_PHYSMEM_BITS,
-};
+struct cpuinfo_x86 boot_cpu_data __read_mostly;
 EXPORT_SYMBOL(boot_cpu_data);
 #endif
 
@@ -851,6 +849,7 @@ void __init setup_arch(char **cmdline_p)
 	__flush_tlb_all();
 #else
 	printk(KERN_INFO "Command line: %s\n", boot_command_line);
+	boot_cpu_data.x86_phys_bits = MAX_PHYSMEM_BITS;
 #endif
 
 	/*
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 9b138a06c1a4..1c43a2e839fa 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -102,7 +102,6 @@ SECTIONS
 		_stext = .;
 		/* bootstrapping code */
 		HEAD_TEXT
-		. = ALIGN(8);
 		TEXT_TEXT
 		SCHED_TEXT
 		CPUIDLE_TEXT
@@ -198,7 +197,7 @@ SECTIONS
 		. = __vvar_beginning_hack + PAGE_SIZE;
 	} :data
 
-       . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE);
+	. = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE);
 
 	/* Init code and data - will be freed after init */
 	. = ALIGN(PAGE_SIZE);
@@ -366,8 +365,8 @@ SECTIONS
 	. = ALIGN(PAGE_SIZE);		/* keep VO_INIT_SIZE page aligned */
 	_end = .;
 
-        STABS_DEBUG
-        DWARF_DEBUG
+	STABS_DEBUG
+	DWARF_DEBUG
 
 	/* Sections to be discarded */
 	DISCARDS
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 1151ccd72ce9..2bccd03bd654 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -146,7 +146,7 @@ void arch_restore_msi_irqs(struct pci_dev *dev)
 }
 #endif
 
-struct x86_io_apic_ops x86_io_apic_ops __ro_after_init = {
-	.read			= native_io_apic_read,
-	.disable		= native_disable_io_apic,
+struct x86_apic_ops x86_apic_ops __ro_after_init = {
+	.io_apic_read	= native_io_apic_read,
+	.restore	= native_restore_boot_irq_mode,
 };
diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S
index 81b1635d67de..88acd349911b 100644
--- a/arch/x86/lib/clear_page_64.S
+++ b/arch/x86/lib/clear_page_64.S
@@ -1,6 +1,4 @@
 #include <linux/linkage.h>
-#include <asm/cpufeatures.h>
-#include <asm/alternative-asm.h>
 #include <asm/export.h>
 
 /*
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 27e9e90a8d35..03c6c8561623 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -1,12 +1,15 @@
 # SPDX-License-Identifier: GPL-2.0
-# Kernel does not boot with instrumentation of tlb.c and mem_encrypt.c
-KCOV_INSTRUMENT_tlb.o		:= n
-KCOV_INSTRUMENT_mem_encrypt.o	:= n
+# Kernel does not boot with instrumentation of tlb.c and mem_encrypt*.c
+KCOV_INSTRUMENT_tlb.o			:= n
+KCOV_INSTRUMENT_mem_encrypt.o		:= n
+KCOV_INSTRUMENT_mem_encrypt_identity.o	:= n
 
-KASAN_SANITIZE_mem_encrypt.o	:= n
+KASAN_SANITIZE_mem_encrypt.o		:= n
+KASAN_SANITIZE_mem_encrypt_identity.o	:= n
 
 ifdef CONFIG_FUNCTION_TRACER
-CFLAGS_REMOVE_mem_encrypt.o	= -pg
+CFLAGS_REMOVE_mem_encrypt.o		= -pg
+CFLAGS_REMOVE_mem_encrypt_identity.o	= -pg
 endif
 
 obj-y	:=  init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
@@ -47,4 +50,5 @@ obj-$(CONFIG_RANDOMIZE_MEMORY)			+= kaslr.o
 obj-$(CONFIG_PAGE_TABLE_ISOLATION)		+= pti.o
 
 obj-$(CONFIG_AMD_MEM_ENCRYPT)	+= mem_encrypt.o
+obj-$(CONFIG_AMD_MEM_ENCRYPT)	+= mem_encrypt_identity.o
 obj-$(CONFIG_AMD_MEM_ENCRYPT)	+= mem_encrypt_boot.o
diff --git a/arch/x86/mm/debug_pagetables.c b/arch/x86/mm/debug_pagetables.c
index 421f2664ffa0..51a6f92da2bf 100644
--- a/arch/x86/mm/debug_pagetables.c
+++ b/arch/x86/mm/debug_pagetables.c
@@ -72,6 +72,31 @@ static const struct file_operations ptdump_curusr_fops = {
 };
 #endif
 
+#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
+extern pgd_t *efi_pgd;
+static struct dentry *pe_efi;
+
+static int ptdump_show_efi(struct seq_file *m, void *v)
+{
+	if (efi_pgd)
+		ptdump_walk_pgd_level_debugfs(m, efi_pgd, false);
+	return 0;
+}
+
+static int ptdump_open_efi(struct inode *inode, struct file *filp)
+{
+	return single_open(filp, ptdump_show_efi, NULL);
+}
+
+static const struct file_operations ptdump_efi_fops = {
+	.owner		= THIS_MODULE,
+	.open		= ptdump_open_efi,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif
+
 static struct dentry *dir, *pe_knl, *pe_curknl;
 
 static int __init pt_dump_debug_init(void)
@@ -96,6 +121,13 @@ static int __init pt_dump_debug_init(void)
 	if (!pe_curusr)
 		goto err;
 #endif
+
+#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
+	pe_efi = debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops);
+	if (!pe_efi)
+		goto err;
+#endif
+
 	return 0;
 err:
 	debugfs_remove_recursive(dir);
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 2a4849e92831..0d6d67d18ad6 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -85,11 +85,15 @@ static struct addr_marker address_markers[] = {
 	[VMALLOC_START_NR]	= { 0UL,		"vmalloc() Area" },
 	[VMEMMAP_START_NR]	= { 0UL,		"Vmemmap" },
 #ifdef CONFIG_KASAN
-	[KASAN_SHADOW_START_NR]	= { KASAN_SHADOW_START,	"KASAN shadow" },
-	[KASAN_SHADOW_END_NR]	= { KASAN_SHADOW_END,	"KASAN shadow end" },
+	/*
+	 * These fields get initialized with the (dynamic)
+	 * KASAN_SHADOW_{START,END} values in pt_dump_init().
+	 */
+	[KASAN_SHADOW_START_NR]	= { 0UL,		"KASAN shadow" },
+	[KASAN_SHADOW_END_NR]	= { 0UL,		"KASAN shadow end" },
 #endif
 #ifdef CONFIG_MODIFY_LDT_SYSCALL
-	[LDT_NR]		= { LDT_BASE_ADDR,	"LDT remap" },
+	[LDT_NR]		= { 0UL,		"LDT remap" },
 #endif
 	[CPU_ENTRY_AREA_NR]	= { CPU_ENTRY_AREA_BASE,"CPU entry Area" },
 #ifdef CONFIG_X86_ESPFIX64
@@ -344,9 +348,7 @@ static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
 				void *pt)
 {
 	if (__pa(pt) == __pa(kasan_zero_pmd) ||
-#ifdef CONFIG_X86_5LEVEL
-	    __pa(pt) == __pa(kasan_zero_p4d) ||
-#endif
+	    (pgtable_l5_enabled && __pa(pt) == __pa(kasan_zero_p4d)) ||
 	    __pa(pt) == __pa(kasan_zero_pud)) {
 		pgprotval_t prot = pte_flags(kasan_zero_pte[0]);
 		note_page(m, st, __pgprot(prot), 5);
@@ -428,14 +430,15 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr,
 #define p4d_none(a)  pud_none(__pud(p4d_val(a)))
 #endif
 
-#if PTRS_PER_P4D > 1
-
 static void walk_p4d_level(struct seq_file *m, struct pg_state *st, pgd_t addr, unsigned long P)
 {
 	int i;
 	p4d_t *start, *p4d_start;
 	pgprotval_t prot;
 
+	if (PTRS_PER_P4D == 1)
+		return walk_pud_level(m, st, __p4d(pgd_val(addr)), P);
+
 	p4d_start = start = (p4d_t *)pgd_page_vaddr(addr);
 
 	for (i = 0; i < PTRS_PER_P4D; i++) {
@@ -455,11 +458,8 @@ static void walk_p4d_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
 	}
 }
 
-#else
-#define walk_p4d_level(m,s,a,p) walk_pud_level(m,s,__p4d(pgd_val(a)),p)
-#define pgd_large(a) p4d_large(__p4d(pgd_val(a)))
-#define pgd_none(a)  p4d_none(__p4d(pgd_val(a)))
-#endif
+#define pgd_large(a) (pgtable_l5_enabled ? pgd_large(a) : p4d_large(__p4d(pgd_val(a))))
+#define pgd_none(a)  (pgtable_l5_enabled ? pgd_none(a) : p4d_none(__p4d(pgd_val(a))))
 
 static inline bool is_hypervisor_range(int idx)
 {
@@ -570,6 +570,13 @@ static int __init pt_dump_init(void)
 	address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET;
 	address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
 	address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START;
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+	address_markers[LDT_NR].start_address = LDT_BASE_ADDR;
+#endif
+#ifdef CONFIG_KASAN
+	address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START;
+	address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END;
+#endif
 #endif
 #ifdef CONFIG_X86_32
 	address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 800de815519c..321b78060e93 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -439,7 +439,7 @@ static noinline int vmalloc_fault(unsigned long address)
 	if (pgd_none(*pgd_ref))
 		return -1;
 
-	if (CONFIG_PGTABLE_LEVELS > 4) {
+	if (pgtable_l5_enabled) {
 		if (pgd_none(*pgd)) {
 			set_pgd(pgd, *pgd_ref);
 			arch_flush_lazy_mmu_mode();
@@ -454,7 +454,7 @@ static noinline int vmalloc_fault(unsigned long address)
 	if (p4d_none(*p4d_ref))
 		return -1;
 
-	if (p4d_none(*p4d) && CONFIG_PGTABLE_LEVELS == 4) {
+	if (p4d_none(*p4d) && !pgtable_l5_enabled) {
 		set_p4d(p4d, *p4d_ref);
 		arch_flush_lazy_mmu_mode();
 	} else {
diff --git a/arch/x86/mm/ident_map.c b/arch/x86/mm/ident_map.c
index ab33a32df2a8..9aa22be8331e 100644
--- a/arch/x86/mm/ident_map.c
+++ b/arch/x86/mm/ident_map.c
@@ -120,7 +120,7 @@ int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
 		result = ident_p4d_init(info, p4d, addr, next);
 		if (result)
 			return result;
-		if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+		if (pgtable_l5_enabled) {
 			set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag));
 		} else {
 			/*
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 8b72923f1d35..9bbc51ae54a6 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -88,12 +88,7 @@ static int __init nonx32_setup(char *str)
 }
 __setup("noexec32=", nonx32_setup);
 
-/*
- * When memory was added make sure all the processes MM have
- * suitable PGD entries in the local PGD level page.
- */
-#ifdef CONFIG_X86_5LEVEL
-void sync_global_pgds(unsigned long start, unsigned long end)
+static void sync_global_pgds_l5(unsigned long start, unsigned long end)
 {
 	unsigned long addr;
 
@@ -129,8 +124,8 @@ void sync_global_pgds(unsigned long start, unsigned long end)
 		spin_unlock(&pgd_lock);
 	}
 }
-#else
-void sync_global_pgds(unsigned long start, unsigned long end)
+
+static void sync_global_pgds_l4(unsigned long start, unsigned long end)
 {
 	unsigned long addr;
 
@@ -143,7 +138,7 @@ void sync_global_pgds(unsigned long start, unsigned long end)
 		 * With folded p4d, pgd_none() is always false, we need to
 		 * handle synchonization on p4d level.
 		 */
-		BUILD_BUG_ON(pgd_none(*pgd_ref));
+		MAYBE_BUILD_BUG_ON(pgd_none(*pgd_ref));
 		p4d_ref = p4d_offset(pgd_ref, addr);
 
 		if (p4d_none(*p4d_ref))
@@ -173,7 +168,18 @@ void sync_global_pgds(unsigned long start, unsigned long end)
 		spin_unlock(&pgd_lock);
 	}
 }
-#endif
+
+/*
+ * When memory was added make sure all the processes MM have
+ * suitable PGD entries in the local PGD level page.
+ */
+void sync_global_pgds(unsigned long start, unsigned long end)
+{
+	if (pgtable_l5_enabled)
+		sync_global_pgds_l5(start, end);
+	else
+		sync_global_pgds_l4(start, end);
+}
 
 /*
  * NOTE: This function is marked __ref because it calls __init function
@@ -632,7 +638,7 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
 	unsigned long vaddr = (unsigned long)__va(paddr);
 	int i = p4d_index(vaddr);
 
-	if (!IS_ENABLED(CONFIG_X86_5LEVEL))
+	if (!pgtable_l5_enabled)
 		return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end, page_size_mask);
 
 	for (; i < PTRS_PER_P4D; i++, paddr = paddr_next) {
@@ -712,7 +718,7 @@ kernel_physical_mapping_init(unsigned long paddr_start,
 					   page_size_mask);
 
 		spin_lock(&init_mm.page_table_lock);
-		if (IS_ENABLED(CONFIG_X86_5LEVEL))
+		if (pgtable_l5_enabled)
 			pgd_populate(&init_mm, pgd, p4d);
 		else
 			p4d_populate(&init_mm, p4d_offset(pgd, vaddr), (pud_t *) p4d);
@@ -1093,7 +1099,7 @@ remove_p4d_table(p4d_t *p4d_start, unsigned long addr, unsigned long end,
 		 * 5-level case we should free them. This code will have to change
 		 * to adapt for boot-time switching between 4 and 5 level page tables.
 		 */
-		if (CONFIG_PGTABLE_LEVELS == 5)
+		if (pgtable_l5_enabled)
 			free_pud_table(pud_base, p4d, altmap);
 	}
 
diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
index af6f2f9c6a26..0df0dd13a71d 100644
--- a/arch/x86/mm/kasan_init_64.c
+++ b/arch/x86/mm/kasan_init_64.c
@@ -19,7 +19,7 @@
 
 extern struct range pfn_mapped[E820_MAX_ENTRIES];
 
-static p4d_t tmp_p4d_table[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
+static p4d_t tmp_p4d_table[MAX_PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
 
 static __init void *early_alloc(size_t size, int nid, bool panic)
 {
@@ -176,10 +176,10 @@ static void __init clear_pgds(unsigned long start,
 		 * With folded p4d, pgd_clear() is nop, use p4d_clear()
 		 * instead.
 		 */
-		if (CONFIG_PGTABLE_LEVELS < 5)
-			p4d_clear(p4d_offset(pgd, start));
-		else
+		if (pgtable_l5_enabled)
 			pgd_clear(pgd);
+		else
+			p4d_clear(p4d_offset(pgd, start));
 	}
 
 	pgd = pgd_offset_k(start);
@@ -191,7 +191,7 @@ static inline p4d_t *early_p4d_offset(pgd_t *pgd, unsigned long addr)
 {
 	unsigned long p4d;
 
-	if (!IS_ENABLED(CONFIG_X86_5LEVEL))
+	if (!pgtable_l5_enabled)
 		return (p4d_t *)pgd;
 
 	p4d = __pa_nodebug(pgd_val(*pgd)) & PTE_PFN_MASK;
@@ -272,7 +272,7 @@ void __init kasan_early_init(void)
 	for (i = 0; i < PTRS_PER_PUD; i++)
 		kasan_zero_pud[i] = __pud(pud_val);
 
-	for (i = 0; IS_ENABLED(CONFIG_X86_5LEVEL) && i < PTRS_PER_P4D; i++)
+	for (i = 0; pgtable_l5_enabled && i < PTRS_PER_P4D; i++)
 		kasan_zero_p4d[i] = __p4d(p4d_val);
 
 	kasan_map_early_shadow(early_top_pgt);
@@ -303,7 +303,7 @@ void __init kasan_init(void)
 	 * bunch of things like kernel code, modules, EFI mapping, etc.
 	 * We need to take extra steps to not overwrite them.
 	 */
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+	if (pgtable_l5_enabled) {
 		void *ptr;
 
 		ptr = (void *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END));
diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c
index aedebd2ebf1e..615cc03ced84 100644
--- a/arch/x86/mm/kaslr.c
+++ b/arch/x86/mm/kaslr.c
@@ -34,23 +34,12 @@
 #define TB_SHIFT 40
 
 /*
- * Virtual address start and end range for randomization.
- *
  * The end address could depend on more configuration options to make the
  * highest amount of space for randomization available, but that's too hard
  * to keep straight and caused issues already.
  */
-static const unsigned long vaddr_start = __PAGE_OFFSET_BASE;
 static const unsigned long vaddr_end = CPU_ENTRY_AREA_BASE;
 
-/* Default values */
-unsigned long page_offset_base = __PAGE_OFFSET_BASE;
-EXPORT_SYMBOL(page_offset_base);
-unsigned long vmalloc_base = __VMALLOC_BASE;
-EXPORT_SYMBOL(vmalloc_base);
-unsigned long vmemmap_base = __VMEMMAP_BASE;
-EXPORT_SYMBOL(vmemmap_base);
-
 /*
  * Memory regions randomized by KASLR (except modules that use a separate logic
  * earlier during boot). The list is ordered based on virtual addresses. This
@@ -60,8 +49,8 @@ static __initdata struct kaslr_memory_region {
 	unsigned long *base;
 	unsigned long size_tb;
 } kaslr_regions[] = {
-	{ &page_offset_base, 1 << (__PHYSICAL_MASK_SHIFT - TB_SHIFT) /* Maximum */ },
-	{ &vmalloc_base, VMALLOC_SIZE_TB },
+	{ &page_offset_base, 0 },
+	{ &vmalloc_base, 0 },
 	{ &vmemmap_base, 1 },
 };
 
@@ -84,11 +73,14 @@ static inline bool kaslr_memory_enabled(void)
 void __init kernel_randomize_memory(void)
 {
 	size_t i;
-	unsigned long vaddr = vaddr_start;
+	unsigned long vaddr_start, vaddr;
 	unsigned long rand, memory_tb;
 	struct rnd_state rand_state;
 	unsigned long remain_entropy;
 
+	vaddr_start = pgtable_l5_enabled ? __PAGE_OFFSET_BASE_L5 : __PAGE_OFFSET_BASE_L4;
+	vaddr = vaddr_start;
+
 	/*
 	 * These BUILD_BUG_ON checks ensure the memory layout is consistent
 	 * with the vaddr_start/vaddr_end variables. These checks are very
@@ -101,6 +93,9 @@ void __init kernel_randomize_memory(void)
 	if (!kaslr_memory_enabled())
 		return;
 
+	kaslr_regions[0].size_tb = 1 << (__PHYSICAL_MASK_SHIFT - TB_SHIFT);
+	kaslr_regions[1].size_tb = VMALLOC_SIZE_TB;
+
 	/*
 	 * Update Physical memory mapping to available and
 	 * add padding if needed (especially for memory hotplug support).
@@ -129,7 +124,7 @@ void __init kernel_randomize_memory(void)
 		 */
 		entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i);
 		prandom_bytes_state(&rand_state, &rand, sizeof(rand));
-		if (IS_ENABLED(CONFIG_X86_5LEVEL))
+		if (pgtable_l5_enabled)
 			entropy = (rand % (entropy + 1)) & P4D_MASK;
 		else
 			entropy = (rand % (entropy + 1)) & PUD_MASK;
@@ -141,7 +136,7 @@ void __init kernel_randomize_memory(void)
 		 * randomization alignment.
 		 */
 		vaddr += get_padding(&kaslr_regions[i]);
-		if (IS_ENABLED(CONFIG_X86_5LEVEL))
+		if (pgtable_l5_enabled)
 			vaddr = round_up(vaddr + 1, P4D_SIZE);
 		else
 			vaddr = round_up(vaddr + 1, PUD_SIZE);
@@ -217,7 +212,7 @@ void __meminit init_trampoline(void)
 		return;
 	}
 
-	if (IS_ENABLED(CONFIG_X86_5LEVEL))
+	if (pgtable_l5_enabled)
 		init_trampoline_p4d();
 	else
 		init_trampoline_pud();
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 1a53071e2e17..3a1b5fe4c2ca 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -25,17 +25,12 @@
 #include <asm/bootparam.h>
 #include <asm/set_memory.h>
 #include <asm/cacheflush.h>
-#include <asm/sections.h>
 #include <asm/processor-flags.h>
 #include <asm/msr.h>
 #include <asm/cmdline.h>
 
 #include "mm_internal.h"
 
-static char sme_cmdline_arg[] __initdata = "mem_encrypt";
-static char sme_cmdline_on[]  __initdata = "on";
-static char sme_cmdline_off[] __initdata = "off";
-
 /*
  * Since SME related variables are set early in the boot process they must
  * reside in the .data section so as not to be zeroed out when the .bss
@@ -46,7 +41,7 @@ EXPORT_SYMBOL(sme_me_mask);
 DEFINE_STATIC_KEY_FALSE(sev_enable_key);
 EXPORT_SYMBOL_GPL(sev_enable_key);
 
-static bool sev_enabled __section(.data);
+bool sev_enabled __section(.data);
 
 /* Buffer used for early in-place encryption by BSP, no locking needed */
 static char sme_early_buffer[PAGE_SIZE] __aligned(PAGE_SIZE);
@@ -463,574 +458,3 @@ void swiotlb_set_mem_attributes(void *vaddr, unsigned long size)
 	/* Make the SWIOTLB buffer area decrypted */
 	set_memory_decrypted((unsigned long)vaddr, size >> PAGE_SHIFT);
 }
-
-struct sme_populate_pgd_data {
-	void	*pgtable_area;
-	pgd_t	*pgd;
-
-	pmdval_t pmd_flags;
-	pteval_t pte_flags;
-	unsigned long paddr;
-
-	unsigned long vaddr;
-	unsigned long vaddr_end;
-};
-
-static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
-{
-	unsigned long pgd_start, pgd_end, pgd_size;
-	pgd_t *pgd_p;
-
-	pgd_start = ppd->vaddr & PGDIR_MASK;
-	pgd_end = ppd->vaddr_end & PGDIR_MASK;
-
-	pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t);
-
-	pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
-
-	memset(pgd_p, 0, pgd_size);
-}
-
-#define PGD_FLAGS		_KERNPG_TABLE_NOENC
-#define P4D_FLAGS		_KERNPG_TABLE_NOENC
-#define PUD_FLAGS		_KERNPG_TABLE_NOENC
-#define PMD_FLAGS		_KERNPG_TABLE_NOENC
-
-#define PMD_FLAGS_LARGE		(__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
-
-#define PMD_FLAGS_DEC		PMD_FLAGS_LARGE
-#define PMD_FLAGS_DEC_WP	((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
-				 (_PAGE_PAT | _PAGE_PWT))
-
-#define PMD_FLAGS_ENC		(PMD_FLAGS_LARGE | _PAGE_ENC)
-
-#define PTE_FLAGS		(__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL)
-
-#define PTE_FLAGS_DEC		PTE_FLAGS
-#define PTE_FLAGS_DEC_WP	((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
-				 (_PAGE_PAT | _PAGE_PWT))
-
-#define PTE_FLAGS_ENC		(PTE_FLAGS | _PAGE_ENC)
-
-static pmd_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
-{
-	pgd_t *pgd_p;
-	p4d_t *p4d_p;
-	pud_t *pud_p;
-	pmd_t *pmd_p;
-
-	pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
-	if (native_pgd_val(*pgd_p)) {
-		if (IS_ENABLED(CONFIG_X86_5LEVEL))
-			p4d_p = (p4d_t *)(native_pgd_val(*pgd_p) & ~PTE_FLAGS_MASK);
-		else
-			pud_p = (pud_t *)(native_pgd_val(*pgd_p) & ~PTE_FLAGS_MASK);
-	} else {
-		pgd_t pgd;
-
-		if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
-			p4d_p = ppd->pgtable_area;
-			memset(p4d_p, 0, sizeof(*p4d_p) * PTRS_PER_P4D);
-			ppd->pgtable_area += sizeof(*p4d_p) * PTRS_PER_P4D;
-
-			pgd = native_make_pgd((pgdval_t)p4d_p + PGD_FLAGS);
-		} else {
-			pud_p = ppd->pgtable_area;
-			memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);
-			ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
-
-			pgd = native_make_pgd((pgdval_t)pud_p + PGD_FLAGS);
-		}
-		native_set_pgd(pgd_p, pgd);
-	}
-
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
-		p4d_p += p4d_index(ppd->vaddr);
-		if (native_p4d_val(*p4d_p)) {
-			pud_p = (pud_t *)(native_p4d_val(*p4d_p) & ~PTE_FLAGS_MASK);
-		} else {
-			p4d_t p4d;
-
-			pud_p = ppd->pgtable_area;
-			memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);
-			ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
-
-			p4d = native_make_p4d((pudval_t)pud_p + P4D_FLAGS);
-			native_set_p4d(p4d_p, p4d);
-		}
-	}
-
-	pud_p += pud_index(ppd->vaddr);
-	if (native_pud_val(*pud_p)) {
-		if (native_pud_val(*pud_p) & _PAGE_PSE)
-			return NULL;
-
-		pmd_p = (pmd_t *)(native_pud_val(*pud_p) & ~PTE_FLAGS_MASK);
-	} else {
-		pud_t pud;
-
-		pmd_p = ppd->pgtable_area;
-		memset(pmd_p, 0, sizeof(*pmd_p) * PTRS_PER_PMD);
-		ppd->pgtable_area += sizeof(*pmd_p) * PTRS_PER_PMD;
-
-		pud = native_make_pud((pmdval_t)pmd_p + PUD_FLAGS);
-		native_set_pud(pud_p, pud);
-	}
-
-	return pmd_p;
-}
-
-static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
-{
-	pmd_t *pmd_p;
-
-	pmd_p = sme_prepare_pgd(ppd);
-	if (!pmd_p)
-		return;
-
-	pmd_p += pmd_index(ppd->vaddr);
-	if (!native_pmd_val(*pmd_p) || !(native_pmd_val(*pmd_p) & _PAGE_PSE))
-		native_set_pmd(pmd_p, native_make_pmd(ppd->paddr | ppd->pmd_flags));
-}
-
-static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
-{
-	pmd_t *pmd_p;
-	pte_t *pte_p;
-
-	pmd_p = sme_prepare_pgd(ppd);
-	if (!pmd_p)
-		return;
-
-	pmd_p += pmd_index(ppd->vaddr);
-	if (native_pmd_val(*pmd_p)) {
-		if (native_pmd_val(*pmd_p) & _PAGE_PSE)
-			return;
-
-		pte_p = (pte_t *)(native_pmd_val(*pmd_p) & ~PTE_FLAGS_MASK);
-	} else {
-		pmd_t pmd;
-
-		pte_p = ppd->pgtable_area;
-		memset(pte_p, 0, sizeof(*pte_p) * PTRS_PER_PTE);
-		ppd->pgtable_area += sizeof(*pte_p) * PTRS_PER_PTE;
-
-		pmd = native_make_pmd((pteval_t)pte_p + PMD_FLAGS);
-		native_set_pmd(pmd_p, pmd);
-	}
-
-	pte_p += pte_index(ppd->vaddr);
-	if (!native_pte_val(*pte_p))
-		native_set_pte(pte_p, native_make_pte(ppd->paddr | ppd->pte_flags));
-}
-
-static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
-{
-	while (ppd->vaddr < ppd->vaddr_end) {
-		sme_populate_pgd_large(ppd);
-
-		ppd->vaddr += PMD_PAGE_SIZE;
-		ppd->paddr += PMD_PAGE_SIZE;
-	}
-}
-
-static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
-{
-	while (ppd->vaddr < ppd->vaddr_end) {
-		sme_populate_pgd(ppd);
-
-		ppd->vaddr += PAGE_SIZE;
-		ppd->paddr += PAGE_SIZE;
-	}
-}
-
-static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
-				   pmdval_t pmd_flags, pteval_t pte_flags)
-{
-	unsigned long vaddr_end;
-
-	ppd->pmd_flags = pmd_flags;
-	ppd->pte_flags = pte_flags;
-
-	/* Save original end value since we modify the struct value */
-	vaddr_end = ppd->vaddr_end;
-
-	/* If start is not 2MB aligned, create PTE entries */
-	ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_PAGE_SIZE);
-	__sme_map_range_pte(ppd);
-
-	/* Create PMD entries */
-	ppd->vaddr_end = vaddr_end & PMD_PAGE_MASK;
-	__sme_map_range_pmd(ppd);
-
-	/* If end is not 2MB aligned, create PTE entries */
-	ppd->vaddr_end = vaddr_end;
-	__sme_map_range_pte(ppd);
-}
-
-static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
-{
-	__sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC);
-}
-
-static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
-{
-	__sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC);
-}
-
-static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
-{
-	__sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP);
-}
-
-static unsigned long __init sme_pgtable_calc(unsigned long len)
-{
-	unsigned long p4d_size, pud_size, pmd_size, pte_size;
-	unsigned long total;
-
-	/*
-	 * Perform a relatively simplistic calculation of the pagetable
-	 * entries that are needed. Those mappings will be covered mostly
-	 * by 2MB PMD entries so we can conservatively calculate the required
-	 * number of P4D, PUD and PMD structures needed to perform the
-	 * mappings.  For mappings that are not 2MB aligned, PTE mappings
-	 * would be needed for the start and end portion of the address range
-	 * that fall outside of the 2MB alignment.  This results in, at most,
-	 * two extra pages to hold PTE entries for each range that is mapped.
-	 * Incrementing the count for each covers the case where the addresses
-	 * cross entries.
-	 */
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
-		p4d_size = (ALIGN(len, PGDIR_SIZE) / PGDIR_SIZE) + 1;
-		p4d_size *= sizeof(p4d_t) * PTRS_PER_P4D;
-		pud_size = (ALIGN(len, P4D_SIZE) / P4D_SIZE) + 1;
-		pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
-	} else {
-		p4d_size = 0;
-		pud_size = (ALIGN(len, PGDIR_SIZE) / PGDIR_SIZE) + 1;
-		pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
-	}
-	pmd_size = (ALIGN(len, PUD_SIZE) / PUD_SIZE) + 1;
-	pmd_size *= sizeof(pmd_t) * PTRS_PER_PMD;
-	pte_size = 2 * sizeof(pte_t) * PTRS_PER_PTE;
-
-	total = p4d_size + pud_size + pmd_size + pte_size;
-
-	/*
-	 * Now calculate the added pagetable structures needed to populate
-	 * the new pagetables.
-	 */
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
-		p4d_size = ALIGN(total, PGDIR_SIZE) / PGDIR_SIZE;
-		p4d_size *= sizeof(p4d_t) * PTRS_PER_P4D;
-		pud_size = ALIGN(total, P4D_SIZE) / P4D_SIZE;
-		pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
-	} else {
-		p4d_size = 0;
-		pud_size = ALIGN(total, PGDIR_SIZE) / PGDIR_SIZE;
-		pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
-	}
-	pmd_size = ALIGN(total, PUD_SIZE) / PUD_SIZE;
-	pmd_size *= sizeof(pmd_t) * PTRS_PER_PMD;
-
-	total += p4d_size + pud_size + pmd_size;
-
-	return total;
-}
-
-void __init __nostackprotector sme_encrypt_kernel(struct boot_params *bp)
-{
-	unsigned long workarea_start, workarea_end, workarea_len;
-	unsigned long execute_start, execute_end, execute_len;
-	unsigned long kernel_start, kernel_end, kernel_len;
-	unsigned long initrd_start, initrd_end, initrd_len;
-	struct sme_populate_pgd_data ppd;
-	unsigned long pgtable_area_len;
-	unsigned long decrypted_base;
-
-	if (!sme_active())
-		return;
-
-	/*
-	 * Prepare for encrypting the kernel and initrd by building new
-	 * pagetables with the necessary attributes needed to encrypt the
-	 * kernel in place.
-	 *
-	 *   One range of virtual addresses will map the memory occupied
-	 *   by the kernel and initrd as encrypted.
-	 *
-	 *   Another range of virtual addresses will map the memory occupied
-	 *   by the kernel and initrd as decrypted and write-protected.
-	 *
-	 *     The use of write-protect attribute will prevent any of the
-	 *     memory from being cached.
-	 */
-
-	/* Physical addresses gives us the identity mapped virtual addresses */
-	kernel_start = __pa_symbol(_text);
-	kernel_end = ALIGN(__pa_symbol(_end), PMD_PAGE_SIZE);
-	kernel_len = kernel_end - kernel_start;
-
-	initrd_start = 0;
-	initrd_end = 0;
-	initrd_len = 0;
-#ifdef CONFIG_BLK_DEV_INITRD
-	initrd_len = (unsigned long)bp->hdr.ramdisk_size |
-		     ((unsigned long)bp->ext_ramdisk_size << 32);
-	if (initrd_len) {
-		initrd_start = (unsigned long)bp->hdr.ramdisk_image |
-			       ((unsigned long)bp->ext_ramdisk_image << 32);
-		initrd_end = PAGE_ALIGN(initrd_start + initrd_len);
-		initrd_len = initrd_end - initrd_start;
-	}
-#endif
-
-	/* Set the encryption workarea to be immediately after the kernel */
-	workarea_start = kernel_end;
-
-	/*
-	 * Calculate required number of workarea bytes needed:
-	 *   executable encryption area size:
-	 *     stack page (PAGE_SIZE)
-	 *     encryption routine page (PAGE_SIZE)
-	 *     intermediate copy buffer (PMD_PAGE_SIZE)
-	 *   pagetable structures for the encryption of the kernel
-	 *   pagetable structures for workarea (in case not currently mapped)
-	 */
-	execute_start = workarea_start;
-	execute_end = execute_start + (PAGE_SIZE * 2) + PMD_PAGE_SIZE;
-	execute_len = execute_end - execute_start;
-
-	/*
-	 * One PGD for both encrypted and decrypted mappings and a set of
-	 * PUDs and PMDs for each of the encrypted and decrypted mappings.
-	 */
-	pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD;
-	pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2;
-	if (initrd_len)
-		pgtable_area_len += sme_pgtable_calc(initrd_len) * 2;
-
-	/* PUDs and PMDs needed in the current pagetables for the workarea */
-	pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len);
-
-	/*
-	 * The total workarea includes the executable encryption area and
-	 * the pagetable area. The start of the workarea is already 2MB
-	 * aligned, align the end of the workarea on a 2MB boundary so that
-	 * we don't try to create/allocate PTE entries from the workarea
-	 * before it is mapped.
-	 */
-	workarea_len = execute_len + pgtable_area_len;
-	workarea_end = ALIGN(workarea_start + workarea_len, PMD_PAGE_SIZE);
-
-	/*
-	 * Set the address to the start of where newly created pagetable
-	 * structures (PGDs, PUDs and PMDs) will be allocated. New pagetable
-	 * structures are created when the workarea is added to the current
-	 * pagetables and when the new encrypted and decrypted kernel
-	 * mappings are populated.
-	 */
-	ppd.pgtable_area = (void *)execute_end;
-
-	/*
-	 * Make sure the current pagetable structure has entries for
-	 * addressing the workarea.
-	 */
-	ppd.pgd = (pgd_t *)native_read_cr3_pa();
-	ppd.paddr = workarea_start;
-	ppd.vaddr = workarea_start;
-	ppd.vaddr_end = workarea_end;
-	sme_map_range_decrypted(&ppd);
-
-	/* Flush the TLB - no globals so cr3 is enough */
-	native_write_cr3(__native_read_cr3());
-
-	/*
-	 * A new pagetable structure is being built to allow for the kernel
-	 * and initrd to be encrypted. It starts with an empty PGD that will
-	 * then be populated with new PUDs and PMDs as the encrypted and
-	 * decrypted kernel mappings are created.
-	 */
-	ppd.pgd = ppd.pgtable_area;
-	memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
-	ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD;
-
-	/*
-	 * A different PGD index/entry must be used to get different
-	 * pagetable entries for the decrypted mapping. Choose the next
-	 * PGD index and convert it to a virtual address to be used as
-	 * the base of the mapping.
-	 */
-	decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1);
-	if (initrd_len) {
-		unsigned long check_base;
-
-		check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1);
-		decrypted_base = max(decrypted_base, check_base);
-	}
-	decrypted_base <<= PGDIR_SHIFT;
-
-	/* Add encrypted kernel (identity) mappings */
-	ppd.paddr = kernel_start;
-	ppd.vaddr = kernel_start;
-	ppd.vaddr_end = kernel_end;
-	sme_map_range_encrypted(&ppd);
-
-	/* Add decrypted, write-protected kernel (non-identity) mappings */
-	ppd.paddr = kernel_start;
-	ppd.vaddr = kernel_start + decrypted_base;
-	ppd.vaddr_end = kernel_end + decrypted_base;
-	sme_map_range_decrypted_wp(&ppd);
-
-	if (initrd_len) {
-		/* Add encrypted initrd (identity) mappings */
-		ppd.paddr = initrd_start;
-		ppd.vaddr = initrd_start;
-		ppd.vaddr_end = initrd_end;
-		sme_map_range_encrypted(&ppd);
-		/*
-		 * Add decrypted, write-protected initrd (non-identity) mappings
-		 */
-		ppd.paddr = initrd_start;
-		ppd.vaddr = initrd_start + decrypted_base;
-		ppd.vaddr_end = initrd_end + decrypted_base;
-		sme_map_range_decrypted_wp(&ppd);
-	}
-
-	/* Add decrypted workarea mappings to both kernel mappings */
-	ppd.paddr = workarea_start;
-	ppd.vaddr = workarea_start;
-	ppd.vaddr_end = workarea_end;
-	sme_map_range_decrypted(&ppd);
-
-	ppd.paddr = workarea_start;
-	ppd.vaddr = workarea_start + decrypted_base;
-	ppd.vaddr_end = workarea_end + decrypted_base;
-	sme_map_range_decrypted(&ppd);
-
-	/* Perform the encryption */
-	sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
-			    kernel_len, workarea_start, (unsigned long)ppd.pgd);
-
-	if (initrd_len)
-		sme_encrypt_execute(initrd_start, initrd_start + decrypted_base,
-				    initrd_len, workarea_start,
-				    (unsigned long)ppd.pgd);
-
-	/*
-	 * At this point we are running encrypted.  Remove the mappings for
-	 * the decrypted areas - all that is needed for this is to remove
-	 * the PGD entry/entries.
-	 */
-	ppd.vaddr = kernel_start + decrypted_base;
-	ppd.vaddr_end = kernel_end + decrypted_base;
-	sme_clear_pgd(&ppd);
-
-	if (initrd_len) {
-		ppd.vaddr = initrd_start + decrypted_base;
-		ppd.vaddr_end = initrd_end + decrypted_base;
-		sme_clear_pgd(&ppd);
-	}
-
-	ppd.vaddr = workarea_start + decrypted_base;
-	ppd.vaddr_end = workarea_end + decrypted_base;
-	sme_clear_pgd(&ppd);
-
-	/* Flush the TLB - no globals so cr3 is enough */
-	native_write_cr3(__native_read_cr3());
-}
-
-void __init __nostackprotector sme_enable(struct boot_params *bp)
-{
-	const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off;
-	unsigned int eax, ebx, ecx, edx;
-	unsigned long feature_mask;
-	bool active_by_default;
-	unsigned long me_mask;
-	char buffer[16];
-	u64 msr;
-
-	/* Check for the SME/SEV support leaf */
-	eax = 0x80000000;
-	ecx = 0;
-	native_cpuid(&eax, &ebx, &ecx, &edx);
-	if (eax < 0x8000001f)
-		return;
-
-#define AMD_SME_BIT	BIT(0)
-#define AMD_SEV_BIT	BIT(1)
-	/*
-	 * Set the feature mask (SME or SEV) based on whether we are
-	 * running under a hypervisor.
-	 */
-	eax = 1;
-	ecx = 0;
-	native_cpuid(&eax, &ebx, &ecx, &edx);
-	feature_mask = (ecx & BIT(31)) ? AMD_SEV_BIT : AMD_SME_BIT;
-
-	/*
-	 * Check for the SME/SEV feature:
-	 *   CPUID Fn8000_001F[EAX]
-	 *   - Bit 0 - Secure Memory Encryption support
-	 *   - Bit 1 - Secure Encrypted Virtualization support
-	 *   CPUID Fn8000_001F[EBX]
-	 *   - Bits 5:0 - Pagetable bit position used to indicate encryption
-	 */
-	eax = 0x8000001f;
-	ecx = 0;
-	native_cpuid(&eax, &ebx, &ecx, &edx);
-	if (!(eax & feature_mask))
-		return;
-
-	me_mask = 1UL << (ebx & 0x3f);
-
-	/* Check if memory encryption is enabled */
-	if (feature_mask == AMD_SME_BIT) {
-		/* For SME, check the SYSCFG MSR */
-		msr = __rdmsr(MSR_K8_SYSCFG);
-		if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
-			return;
-	} else {
-		/* For SEV, check the SEV MSR */
-		msr = __rdmsr(MSR_AMD64_SEV);
-		if (!(msr & MSR_AMD64_SEV_ENABLED))
-			return;
-
-		/* SEV state cannot be controlled by a command line option */
-		sme_me_mask = me_mask;
-		sev_enabled = true;
-		return;
-	}
-
-	/*
-	 * Fixups have not been applied to phys_base yet and we're running
-	 * identity mapped, so we must obtain the address to the SME command
-	 * line argument data using rip-relative addressing.
-	 */
-	asm ("lea sme_cmdline_arg(%%rip), %0"
-	     : "=r" (cmdline_arg)
-	     : "p" (sme_cmdline_arg));
-	asm ("lea sme_cmdline_on(%%rip), %0"
-	     : "=r" (cmdline_on)
-	     : "p" (sme_cmdline_on));
-	asm ("lea sme_cmdline_off(%%rip), %0"
-	     : "=r" (cmdline_off)
-	     : "p" (sme_cmdline_off));
-
-	if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT))
-		active_by_default = true;
-	else
-		active_by_default = false;
-
-	cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
-				     ((u64)bp->ext_cmd_line_ptr << 32));
-
-	cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer));
-
-	if (!strncmp(buffer, cmdline_on, sizeof(buffer)))
-		sme_me_mask = me_mask;
-	else if (!strncmp(buffer, cmdline_off, sizeof(buffer)))
-		sme_me_mask = 0;
-	else
-		sme_me_mask = active_by_default ? me_mask : 0;
-}
diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c
new file mode 100644
index 000000000000..b4139c5ab972
--- /dev/null
+++ b/arch/x86/mm/mem_encrypt_identity.c
@@ -0,0 +1,564 @@
+/*
+ * AMD Memory Encryption Support
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Tom Lendacky <thomas.lendacky@amd.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.
+ */
+
+#define DISABLE_BRANCH_PROFILING
+
+/*
+ * Since we're dealing with identity mappings, physical and virtual
+ * addresses are the same, so override these defines which are ultimately
+ * used by the headers in misc.h.
+ */
+#define __pa(x)  ((unsigned long)(x))
+#define __va(x)  ((void *)((unsigned long)(x)))
+
+/*
+ * Special hack: we have to be careful, because no indirections are
+ * allowed here, and paravirt_ops is a kind of one. As it will only run in
+ * baremetal anyway, we just keep it from happening. (This list needs to
+ * be extended when new paravirt and debugging variants are added.)
+ */
+#undef CONFIG_PARAVIRT
+#undef CONFIG_PARAVIRT_SPINLOCKS
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mem_encrypt.h>
+
+#include <asm/setup.h>
+#include <asm/sections.h>
+#include <asm/cmdline.h>
+
+#include "mm_internal.h"
+
+#define PGD_FLAGS		_KERNPG_TABLE_NOENC
+#define P4D_FLAGS		_KERNPG_TABLE_NOENC
+#define PUD_FLAGS		_KERNPG_TABLE_NOENC
+#define PMD_FLAGS		_KERNPG_TABLE_NOENC
+
+#define PMD_FLAGS_LARGE		(__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
+
+#define PMD_FLAGS_DEC		PMD_FLAGS_LARGE
+#define PMD_FLAGS_DEC_WP	((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
+				 (_PAGE_PAT | _PAGE_PWT))
+
+#define PMD_FLAGS_ENC		(PMD_FLAGS_LARGE | _PAGE_ENC)
+
+#define PTE_FLAGS		(__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL)
+
+#define PTE_FLAGS_DEC		PTE_FLAGS
+#define PTE_FLAGS_DEC_WP	((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
+				 (_PAGE_PAT | _PAGE_PWT))
+
+#define PTE_FLAGS_ENC		(PTE_FLAGS | _PAGE_ENC)
+
+struct sme_populate_pgd_data {
+	void    *pgtable_area;
+	pgd_t   *pgd;
+
+	pmdval_t pmd_flags;
+	pteval_t pte_flags;
+	unsigned long paddr;
+
+	unsigned long vaddr;
+	unsigned long vaddr_end;
+};
+
+static char sme_cmdline_arg[] __initdata = "mem_encrypt";
+static char sme_cmdline_on[]  __initdata = "on";
+static char sme_cmdline_off[] __initdata = "off";
+
+static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
+{
+	unsigned long pgd_start, pgd_end, pgd_size;
+	pgd_t *pgd_p;
+
+	pgd_start = ppd->vaddr & PGDIR_MASK;
+	pgd_end = ppd->vaddr_end & PGDIR_MASK;
+
+	pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t);
+
+	pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
+
+	memset(pgd_p, 0, pgd_size);
+}
+
+static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
+{
+	pgd_t *pgd;
+	p4d_t *p4d;
+	pud_t *pud;
+	pmd_t *pmd;
+
+	pgd = ppd->pgd + pgd_index(ppd->vaddr);
+	if (pgd_none(*pgd)) {
+		p4d = ppd->pgtable_area;
+		memset(p4d, 0, sizeof(*p4d) * PTRS_PER_P4D);
+		ppd->pgtable_area += sizeof(*p4d) * PTRS_PER_P4D;
+		set_pgd(pgd, __pgd(PGD_FLAGS | __pa(p4d)));
+	}
+
+	p4d = p4d_offset(pgd, ppd->vaddr);
+	if (p4d_none(*p4d)) {
+		pud = ppd->pgtable_area;
+		memset(pud, 0, sizeof(*pud) * PTRS_PER_PUD);
+		ppd->pgtable_area += sizeof(*pud) * PTRS_PER_PUD;
+		set_p4d(p4d, __p4d(P4D_FLAGS | __pa(pud)));
+	}
+
+	pud = pud_offset(p4d, ppd->vaddr);
+	if (pud_none(*pud)) {
+		pmd = ppd->pgtable_area;
+		memset(pmd, 0, sizeof(*pmd) * PTRS_PER_PMD);
+		ppd->pgtable_area += sizeof(*pmd) * PTRS_PER_PMD;
+		set_pud(pud, __pud(PUD_FLAGS | __pa(pmd)));
+	}
+
+	if (pud_large(*pud))
+		return NULL;
+
+	return pud;
+}
+
+static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
+{
+	pud_t *pud;
+	pmd_t *pmd;
+
+	pud = sme_prepare_pgd(ppd);
+	if (!pud)
+		return;
+
+	pmd = pmd_offset(pud, ppd->vaddr);
+	if (pmd_large(*pmd))
+		return;
+
+	set_pmd(pmd, __pmd(ppd->paddr | ppd->pmd_flags));
+}
+
+static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
+{
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	pud = sme_prepare_pgd(ppd);
+	if (!pud)
+		return;
+
+	pmd = pmd_offset(pud, ppd->vaddr);
+	if (pmd_none(*pmd)) {
+		pte = ppd->pgtable_area;
+		memset(pte, 0, sizeof(pte) * PTRS_PER_PTE);
+		ppd->pgtable_area += sizeof(pte) * PTRS_PER_PTE;
+		set_pmd(pmd, __pmd(PMD_FLAGS | __pa(pte)));
+	}
+
+	if (pmd_large(*pmd))
+		return;
+
+	pte = pte_offset_map(pmd, ppd->vaddr);
+	if (pte_none(*pte))
+		set_pte(pte, __pte(ppd->paddr | ppd->pte_flags));
+}
+
+static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
+{
+	while (ppd->vaddr < ppd->vaddr_end) {
+		sme_populate_pgd_large(ppd);
+
+		ppd->vaddr += PMD_PAGE_SIZE;
+		ppd->paddr += PMD_PAGE_SIZE;
+	}
+}
+
+static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
+{
+	while (ppd->vaddr < ppd->vaddr_end) {
+		sme_populate_pgd(ppd);
+
+		ppd->vaddr += PAGE_SIZE;
+		ppd->paddr += PAGE_SIZE;
+	}
+}
+
+static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
+				   pmdval_t pmd_flags, pteval_t pte_flags)
+{
+	unsigned long vaddr_end;
+
+	ppd->pmd_flags = pmd_flags;
+	ppd->pte_flags = pte_flags;
+
+	/* Save original end value since we modify the struct value */
+	vaddr_end = ppd->vaddr_end;
+
+	/* If start is not 2MB aligned, create PTE entries */
+	ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_PAGE_SIZE);
+	__sme_map_range_pte(ppd);
+
+	/* Create PMD entries */
+	ppd->vaddr_end = vaddr_end & PMD_PAGE_MASK;
+	__sme_map_range_pmd(ppd);
+
+	/* If end is not 2MB aligned, create PTE entries */
+	ppd->vaddr_end = vaddr_end;
+	__sme_map_range_pte(ppd);
+}
+
+static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
+{
+	__sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC);
+}
+
+static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
+{
+	__sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC);
+}
+
+static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
+{
+	__sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP);
+}
+
+static unsigned long __init sme_pgtable_calc(unsigned long len)
+{
+	unsigned long entries = 0, tables = 0;
+
+	/*
+	 * Perform a relatively simplistic calculation of the pagetable
+	 * entries that are needed. Those mappings will be covered mostly
+	 * by 2MB PMD entries so we can conservatively calculate the required
+	 * number of P4D, PUD and PMD structures needed to perform the
+	 * mappings.  For mappings that are not 2MB aligned, PTE mappings
+	 * would be needed for the start and end portion of the address range
+	 * that fall outside of the 2MB alignment.  This results in, at most,
+	 * two extra pages to hold PTE entries for each range that is mapped.
+	 * Incrementing the count for each covers the case where the addresses
+	 * cross entries.
+	 */
+
+	/* PGDIR_SIZE is equal to P4D_SIZE on 4-level machine. */
+	if (PTRS_PER_P4D > 1)
+		entries += (DIV_ROUND_UP(len, PGDIR_SIZE) + 1) * sizeof(p4d_t) * PTRS_PER_P4D;
+	entries += (DIV_ROUND_UP(len, P4D_SIZE) + 1) * sizeof(pud_t) * PTRS_PER_PUD;
+	entries += (DIV_ROUND_UP(len, PUD_SIZE) + 1) * sizeof(pmd_t) * PTRS_PER_PMD;
+	entries += 2 * sizeof(pte_t) * PTRS_PER_PTE;
+
+	/*
+	 * Now calculate the added pagetable structures needed to populate
+	 * the new pagetables.
+	 */
+
+	if (PTRS_PER_P4D > 1)
+		tables += DIV_ROUND_UP(entries, PGDIR_SIZE) * sizeof(p4d_t) * PTRS_PER_P4D;
+	tables += DIV_ROUND_UP(entries, P4D_SIZE) * sizeof(pud_t) * PTRS_PER_PUD;
+	tables += DIV_ROUND_UP(entries, PUD_SIZE) * sizeof(pmd_t) * PTRS_PER_PMD;
+
+	return entries + tables;
+}
+
+void __init __nostackprotector sme_encrypt_kernel(struct boot_params *bp)
+{
+	unsigned long workarea_start, workarea_end, workarea_len;
+	unsigned long execute_start, execute_end, execute_len;
+	unsigned long kernel_start, kernel_end, kernel_len;
+	unsigned long initrd_start, initrd_end, initrd_len;
+	struct sme_populate_pgd_data ppd;
+	unsigned long pgtable_area_len;
+	unsigned long decrypted_base;
+
+	if (!sme_active())
+		return;
+
+	/*
+	 * Prepare for encrypting the kernel and initrd by building new
+	 * pagetables with the necessary attributes needed to encrypt the
+	 * kernel in place.
+	 *
+	 *   One range of virtual addresses will map the memory occupied
+	 *   by the kernel and initrd as encrypted.
+	 *
+	 *   Another range of virtual addresses will map the memory occupied
+	 *   by the kernel and initrd as decrypted and write-protected.
+	 *
+	 *     The use of write-protect attribute will prevent any of the
+	 *     memory from being cached.
+	 */
+
+	/* Physical addresses gives us the identity mapped virtual addresses */
+	kernel_start = __pa_symbol(_text);
+	kernel_end = ALIGN(__pa_symbol(_end), PMD_PAGE_SIZE);
+	kernel_len = kernel_end - kernel_start;
+
+	initrd_start = 0;
+	initrd_end = 0;
+	initrd_len = 0;
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_len = (unsigned long)bp->hdr.ramdisk_size |
+		     ((unsigned long)bp->ext_ramdisk_size << 32);
+	if (initrd_len) {
+		initrd_start = (unsigned long)bp->hdr.ramdisk_image |
+			       ((unsigned long)bp->ext_ramdisk_image << 32);
+		initrd_end = PAGE_ALIGN(initrd_start + initrd_len);
+		initrd_len = initrd_end - initrd_start;
+	}
+#endif
+
+	/* Set the encryption workarea to be immediately after the kernel */
+	workarea_start = kernel_end;
+
+	/*
+	 * Calculate required number of workarea bytes needed:
+	 *   executable encryption area size:
+	 *     stack page (PAGE_SIZE)
+	 *     encryption routine page (PAGE_SIZE)
+	 *     intermediate copy buffer (PMD_PAGE_SIZE)
+	 *   pagetable structures for the encryption of the kernel
+	 *   pagetable structures for workarea (in case not currently mapped)
+	 */
+	execute_start = workarea_start;
+	execute_end = execute_start + (PAGE_SIZE * 2) + PMD_PAGE_SIZE;
+	execute_len = execute_end - execute_start;
+
+	/*
+	 * One PGD for both encrypted and decrypted mappings and a set of
+	 * PUDs and PMDs for each of the encrypted and decrypted mappings.
+	 */
+	pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD;
+	pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2;
+	if (initrd_len)
+		pgtable_area_len += sme_pgtable_calc(initrd_len) * 2;
+
+	/* PUDs and PMDs needed in the current pagetables for the workarea */
+	pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len);
+
+	/*
+	 * The total workarea includes the executable encryption area and
+	 * the pagetable area. The start of the workarea is already 2MB
+	 * aligned, align the end of the workarea on a 2MB boundary so that
+	 * we don't try to create/allocate PTE entries from the workarea
+	 * before it is mapped.
+	 */
+	workarea_len = execute_len + pgtable_area_len;
+	workarea_end = ALIGN(workarea_start + workarea_len, PMD_PAGE_SIZE);
+
+	/*
+	 * Set the address to the start of where newly created pagetable
+	 * structures (PGDs, PUDs and PMDs) will be allocated. New pagetable
+	 * structures are created when the workarea is added to the current
+	 * pagetables and when the new encrypted and decrypted kernel
+	 * mappings are populated.
+	 */
+	ppd.pgtable_area = (void *)execute_end;
+
+	/*
+	 * Make sure the current pagetable structure has entries for
+	 * addressing the workarea.
+	 */
+	ppd.pgd = (pgd_t *)native_read_cr3_pa();
+	ppd.paddr = workarea_start;
+	ppd.vaddr = workarea_start;
+	ppd.vaddr_end = workarea_end;
+	sme_map_range_decrypted(&ppd);
+
+	/* Flush the TLB - no globals so cr3 is enough */
+	native_write_cr3(__native_read_cr3());
+
+	/*
+	 * A new pagetable structure is being built to allow for the kernel
+	 * and initrd to be encrypted. It starts with an empty PGD that will
+	 * then be populated with new PUDs and PMDs as the encrypted and
+	 * decrypted kernel mappings are created.
+	 */
+	ppd.pgd = ppd.pgtable_area;
+	memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
+	ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD;
+
+	/*
+	 * A different PGD index/entry must be used to get different
+	 * pagetable entries for the decrypted mapping. Choose the next
+	 * PGD index and convert it to a virtual address to be used as
+	 * the base of the mapping.
+	 */
+	decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1);
+	if (initrd_len) {
+		unsigned long check_base;
+
+		check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1);
+		decrypted_base = max(decrypted_base, check_base);
+	}
+	decrypted_base <<= PGDIR_SHIFT;
+
+	/* Add encrypted kernel (identity) mappings */
+	ppd.paddr = kernel_start;
+	ppd.vaddr = kernel_start;
+	ppd.vaddr_end = kernel_end;
+	sme_map_range_encrypted(&ppd);
+
+	/* Add decrypted, write-protected kernel (non-identity) mappings */
+	ppd.paddr = kernel_start;
+	ppd.vaddr = kernel_start + decrypted_base;
+	ppd.vaddr_end = kernel_end + decrypted_base;
+	sme_map_range_decrypted_wp(&ppd);
+
+	if (initrd_len) {
+		/* Add encrypted initrd (identity) mappings */
+		ppd.paddr = initrd_start;
+		ppd.vaddr = initrd_start;
+		ppd.vaddr_end = initrd_end;
+		sme_map_range_encrypted(&ppd);
+		/*
+		 * Add decrypted, write-protected initrd (non-identity) mappings
+		 */
+		ppd.paddr = initrd_start;
+		ppd.vaddr = initrd_start + decrypted_base;
+		ppd.vaddr_end = initrd_end + decrypted_base;
+		sme_map_range_decrypted_wp(&ppd);
+	}
+
+	/* Add decrypted workarea mappings to both kernel mappings */
+	ppd.paddr = workarea_start;
+	ppd.vaddr = workarea_start;
+	ppd.vaddr_end = workarea_end;
+	sme_map_range_decrypted(&ppd);
+
+	ppd.paddr = workarea_start;
+	ppd.vaddr = workarea_start + decrypted_base;
+	ppd.vaddr_end = workarea_end + decrypted_base;
+	sme_map_range_decrypted(&ppd);
+
+	/* Perform the encryption */
+	sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
+			    kernel_len, workarea_start, (unsigned long)ppd.pgd);
+
+	if (initrd_len)
+		sme_encrypt_execute(initrd_start, initrd_start + decrypted_base,
+				    initrd_len, workarea_start,
+				    (unsigned long)ppd.pgd);
+
+	/*
+	 * At this point we are running encrypted.  Remove the mappings for
+	 * the decrypted areas - all that is needed for this is to remove
+	 * the PGD entry/entries.
+	 */
+	ppd.vaddr = kernel_start + decrypted_base;
+	ppd.vaddr_end = kernel_end + decrypted_base;
+	sme_clear_pgd(&ppd);
+
+	if (initrd_len) {
+		ppd.vaddr = initrd_start + decrypted_base;
+		ppd.vaddr_end = initrd_end + decrypted_base;
+		sme_clear_pgd(&ppd);
+	}
+
+	ppd.vaddr = workarea_start + decrypted_base;
+	ppd.vaddr_end = workarea_end + decrypted_base;
+	sme_clear_pgd(&ppd);
+
+	/* Flush the TLB - no globals so cr3 is enough */
+	native_write_cr3(__native_read_cr3());
+}
+
+void __init __nostackprotector sme_enable(struct boot_params *bp)
+{
+	const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off;
+	unsigned int eax, ebx, ecx, edx;
+	unsigned long feature_mask;
+	bool active_by_default;
+	unsigned long me_mask;
+	char buffer[16];
+	u64 msr;
+
+	/* Check for the SME/SEV support leaf */
+	eax = 0x80000000;
+	ecx = 0;
+	native_cpuid(&eax, &ebx, &ecx, &edx);
+	if (eax < 0x8000001f)
+		return;
+
+#define AMD_SME_BIT	BIT(0)
+#define AMD_SEV_BIT	BIT(1)
+	/*
+	 * Set the feature mask (SME or SEV) based on whether we are
+	 * running under a hypervisor.
+	 */
+	eax = 1;
+	ecx = 0;
+	native_cpuid(&eax, &ebx, &ecx, &edx);
+	feature_mask = (ecx & BIT(31)) ? AMD_SEV_BIT : AMD_SME_BIT;
+
+	/*
+	 * Check for the SME/SEV feature:
+	 *   CPUID Fn8000_001F[EAX]
+	 *   - Bit 0 - Secure Memory Encryption support
+	 *   - Bit 1 - Secure Encrypted Virtualization support
+	 *   CPUID Fn8000_001F[EBX]
+	 *   - Bits 5:0 - Pagetable bit position used to indicate encryption
+	 */
+	eax = 0x8000001f;
+	ecx = 0;
+	native_cpuid(&eax, &ebx, &ecx, &edx);
+	if (!(eax & feature_mask))
+		return;
+
+	me_mask = 1UL << (ebx & 0x3f);
+
+	/* Check if memory encryption is enabled */
+	if (feature_mask == AMD_SME_BIT) {
+		/* For SME, check the SYSCFG MSR */
+		msr = __rdmsr(MSR_K8_SYSCFG);
+		if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
+			return;
+	} else {
+		/* For SEV, check the SEV MSR */
+		msr = __rdmsr(MSR_AMD64_SEV);
+		if (!(msr & MSR_AMD64_SEV_ENABLED))
+			return;
+
+		/* SEV state cannot be controlled by a command line option */
+		sme_me_mask = me_mask;
+		sev_enabled = true;
+		return;
+	}
+
+	/*
+	 * Fixups have not been applied to phys_base yet and we're running
+	 * identity mapped, so we must obtain the address to the SME command
+	 * line argument data using rip-relative addressing.
+	 */
+	asm ("lea sme_cmdline_arg(%%rip), %0"
+	     : "=r" (cmdline_arg)
+	     : "p" (sme_cmdline_arg));
+	asm ("lea sme_cmdline_on(%%rip), %0"
+	     : "=r" (cmdline_on)
+	     : "p" (sme_cmdline_on));
+	asm ("lea sme_cmdline_off(%%rip), %0"
+	     : "=r" (cmdline_off)
+	     : "p" (sme_cmdline_off));
+
+	if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT))
+		active_by_default = true;
+	else
+		active_by_default = false;
+
+	cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
+				     ((u64)bp->ext_cmd_line_ptr << 32));
+
+	cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer));
+
+	if (!strncmp(buffer, cmdline_on, sizeof(buffer)))
+		sme_me_mask = me_mask;
+	else if (!strncmp(buffer, cmdline_off, sizeof(buffer)))
+		sme_me_mask = 0;
+	else
+		sme_me_mask = active_by_default ? me_mask : 0;
+}
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 7f1a51399674..e055d1a06699 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -157,7 +157,7 @@ static void sync_current_stack_to_mm(struct mm_struct *mm)
 	unsigned long sp = current_stack_pointer;
 	pgd_t *pgd = pgd_offset(mm, sp);
 
-	if (CONFIG_PGTABLE_LEVELS > 4) {
+	if (pgtable_l5_enabled) {
 		if (unlikely(pgd_none(*pgd))) {
 			pgd_t *pgd_ref = pgd_offset_k(sp);
 
@@ -613,7 +613,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
 {
 	int cpu;
 
-	struct flush_tlb_info info = {
+	struct flush_tlb_info info __aligned(SMP_CACHE_BYTES) = {
 		.mm = mm,
 	};
 
diff --git a/arch/x86/platform/atom/punit_atom_debug.c b/arch/x86/platform/atom/punit_atom_debug.c
index d49d3be81953..034813d4ab1e 100644
--- a/arch/x86/platform/atom/punit_atom_debug.c
+++ b/arch/x86/platform/atom/punit_atom_debug.c
@@ -109,18 +109,7 @@ static int punit_dev_state_show(struct seq_file *seq_file, void *unused)
 
 	return 0;
 }
-
-static int punit_dev_state_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, punit_dev_state_show, inode->i_private);
-}
-
-static const struct file_operations punit_dev_state_ops = {
-	.open		= punit_dev_state_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(punit_dev_state);
 
 static struct dentry *punit_dbg_file;
 
@@ -132,9 +121,9 @@ static int punit_dbgfs_register(struct punit_device *punit_device)
 	if (!punit_dbg_file)
 		return -ENXIO;
 
-	dev_state = debugfs_create_file("dev_power_state", S_IFREG | S_IRUGO,
+	dev_state = debugfs_create_file("dev_power_state", 0444,
 					punit_dbg_file, punit_device,
-					&punit_dev_state_ops);
+					&punit_dev_state_fops);
 	if (!dev_state) {
 		pr_err("punit_dev_state register failed\n");
 		debugfs_remove(punit_dbg_file);
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index c310a8284358..4845871a2006 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -27,6 +27,7 @@
 #include <linux/ioport.h>
 #include <linux/mc146818rtc.h>
 #include <linux/efi.h>
+#include <linux/export.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/reboot.h>
@@ -190,7 +191,8 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd)
 	early_code_mapping_set_exec(0);
 }
 
-static pgd_t *efi_pgd;
+pgd_t *efi_pgd;
+EXPORT_SYMBOL_GPL(efi_pgd);
 
 /*
  * We need our own copy of the higher levels of the page tables
@@ -225,7 +227,7 @@ int __init efi_alloc_page_tables(void)
 
 	pud = pud_alloc(&init_mm, p4d, EFI_VA_END);
 	if (!pud) {
-		if (CONFIG_PGTABLE_LEVELS > 4)
+		if (pgtable_l5_enabled)
 			free_page((unsigned long) pgd_page_vaddr(*pgd));
 		free_page((unsigned long)efi_pgd);
 		return -ENOMEM;
@@ -255,8 +257,8 @@ void efi_sync_low_kernel_mappings(void)
 	 * only span a single PGD entry and that the entry also maps
 	 * other important kernel regions.
 	 */
-	BUILD_BUG_ON(pgd_index(EFI_VA_END) != pgd_index(MODULES_END));
-	BUILD_BUG_ON((EFI_VA_START & PGDIR_MASK) !=
+	MAYBE_BUILD_BUG_ON(pgd_index(EFI_VA_END) != pgd_index(MODULES_END));
+	MAYBE_BUILD_BUG_ON((EFI_VA_START & PGDIR_MASK) !=
 			(EFI_VA_END & PGDIR_MASK));
 
 	pgd_efi = efi_pgd + pgd_index(PAGE_OFFSET);
diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c
index 17d6d2296e4d..49828c2707ac 100644
--- a/arch/x86/platform/intel-quark/imr.c
+++ b/arch/x86/platform/intel-quark/imr.c
@@ -224,25 +224,7 @@ static int imr_dbgfs_state_show(struct seq_file *s, void *unused)
 	mutex_unlock(&idev->lock);
 	return ret;
 }
-
-/**
- * imr_state_open - debugfs open callback.
- *
- * @inode:	pointer to struct inode.
- * @file:	pointer to struct file.
- * @return:	result of single open.
- */
-static int imr_state_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, imr_dbgfs_state_show, inode->i_private);
-}
-
-static const struct file_operations imr_state_ops = {
-	.open		= imr_state_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(imr_dbgfs_state);
 
 /**
  * imr_debugfs_register - register debugfs hooks.
@@ -252,8 +234,8 @@ static const struct file_operations imr_state_ops = {
  */
 static int imr_debugfs_register(struct imr_device *idev)
 {
-	idev->file = debugfs_create_file("imr_state", S_IFREG | S_IRUGO, NULL,
-					 idev, &imr_state_ops);
+	idev->file = debugfs_create_file("imr_state", 0444, NULL, idev,
+					 &imr_dbgfs_state_fops);
 	return PTR_ERR_OR_ZERO(idev->file);
 }
 
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index 0ef5e5204968..74a532989308 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -50,7 +50,7 @@ static int set_up_temporary_text_mapping(pgd_t *pgd)
 {
 	pmd_t *pmd;
 	pud_t *pud;
-	p4d_t *p4d;
+	p4d_t *p4d = NULL;
 
 	/*
 	 * The new mapping only has to cover the page containing the image
@@ -66,7 +66,7 @@ static int set_up_temporary_text_mapping(pgd_t *pgd)
 	 * tables used by the image kernel.
 	 */
 
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+	if (pgtable_l5_enabled) {
 		p4d = (p4d_t *)get_safe_page(GFP_ATOMIC);
 		if (!p4d)
 			return -ENOMEM;
@@ -84,7 +84,7 @@ static int set_up_temporary_text_mapping(pgd_t *pgd)
 		__pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC));
 	set_pud(pud + pud_index(restore_jump_address),
 		__pud(__pa(pmd) | _KERNPG_TABLE));
-	if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+	if (p4d) {
 		set_p4d(p4d + p4d_index(restore_jump_address), __p4d(__pa(pud) | _KERNPG_TABLE));
 		set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(p4d) | _KERNPG_TABLE));
 	} else {
diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c
index 1518d2805ae8..fd6825537b97 100644
--- a/arch/x86/um/stub_segv.c
+++ b/arch/x86/um/stub_segv.c
@@ -10,7 +10,7 @@
 void __attribute__ ((__section__ (".__syscall_stub")))
 stub_segv_handler(int sig, siginfo_t *info, void *p)
 {
-	struct ucontext *uc = p;
+	ucontext_t *uc = p;
 
 	GET_FAULTINFO_FROM_MC(*((struct faultinfo *) STUB_DATA),
 			      &uc->uc_mcontext);
diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c
index de58533d3664..2163888497d3 100644
--- a/arch/x86/xen/apic.c
+++ b/arch/x86/xen/apic.c
@@ -215,7 +215,7 @@ static void __init xen_apic_check(void)
 }
 void __init xen_init_apic(void)
 {
-	x86_io_apic_ops.read = xen_io_apic_read;
+	x86_apic_ops.io_apic_read = xen_io_apic_read;
 	/* On PV guests the APIC CPUID bit is disabled so none of the
 	 * routines end up executing. */
 	if (!xen_initial_domain())
diff --git a/arch/xtensa/include/uapi/asm/mman.h b/arch/xtensa/include/uapi/asm/mman.h
index 3e9d01ada81f..58f29a9d895d 100644
--- a/arch/xtensa/include/uapi/asm/mman.h
+++ b/arch/xtensa/include/uapi/asm/mman.h
@@ -57,6 +57,7 @@
 #define MAP_NONBLOCK	0x20000		/* do not block on IO */
 #define MAP_STACK	0x40000		/* give out an address that is best suited for process/thread stacks */
 #define MAP_HUGETLB	0x80000		/* create a huge page mapping */
+#define MAP_FIXED_NOREPLACE 0x100000	/* MAP_FIXED which doesn't unmap underlying mapping */
 #ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
 # define MAP_UNINITIALIZED 0x4000000	/* For anonymous mmap, memory could be
 					 * uninitialized */
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
index 623720a11143..db250bbc2586 100644
--- a/arch/xtensa/kernel/pci-dma.c
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/dma-contiguous.h>
+#include <linux/dma-direct.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
@@ -123,7 +124,7 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 			      unsigned long attrs)
 {
 	unsigned long ret;
-	unsigned long uncached = 0;
+	unsigned long uncached;
 	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 	struct page *page = NULL;
 
@@ -144,15 +145,31 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 	if (!page)
 		return NULL;
 
-	ret = (unsigned long)page_address(page);
+	*handle = phys_to_dma(dev, page_to_phys(page));
+
+	if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+		return page;
+	}
 
-	/* We currently don't support coherent memory outside KSEG */
+#ifdef CONFIG_MMU
+	if (PageHighMem(page)) {
+		void *p;
 
+		p = dma_common_contiguous_remap(page, size, VM_MAP,
+						pgprot_noncached(PAGE_KERNEL),
+						__builtin_return_address(0));
+		if (!p) {
+			if (!dma_release_from_contiguous(dev, page, count))
+				__free_pages(page, get_order(size));
+		}
+		return p;
+	}
+#endif
+	ret = (unsigned long)page_address(page);
 	BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
 	       ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
 	uncached = ret + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR;
-	*handle = virt_to_bus((void *)ret);
 	__invalidate_dcache_range(ret, size);
 
 	return (void *)uncached;
@@ -161,13 +178,22 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr,
 			    dma_addr_t dma_handle, unsigned long attrs)
 {
-	unsigned long addr = (unsigned long)vaddr +
-		XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
-	struct page *page = virt_to_page(addr);
 	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-	BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
-	       addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
+	unsigned long addr = (unsigned long)vaddr;
+	struct page *page;
+
+	if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) {
+		page = vaddr;
+	} else if (addr >= XCHAL_KSEG_BYPASS_VADDR &&
+		   addr - XCHAL_KSEG_BYPASS_VADDR < XCHAL_KSEG_SIZE) {
+		addr += XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
+		page = virt_to_page(addr);
+	} else {
+#ifdef CONFIG_MMU
+		dma_common_free_remap(vaddr, size, VM_MAP);
+#endif
+		page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle)));
+	}
 
 	if (!dma_release_from_contiguous(dev, page, count))
 		__free_pages(page, get_order(size));
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index d776ec0d7b22..34aead7dcb48 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -79,19 +79,75 @@ void __init zones_init(void)
 	free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
 }
 
+#ifdef CONFIG_HIGHMEM
+static void __init free_area_high(unsigned long pfn, unsigned long end)
+{
+	for (; pfn < end; pfn++)
+		free_highmem_page(pfn_to_page(pfn));
+}
+
+static void __init free_highpages(void)
+{
+	unsigned long max_low = max_low_pfn;
+	struct memblock_region *mem, *res;
+
+	reset_all_zones_managed_pages();
+	/* set highmem page free */
+	for_each_memblock(memory, mem) {
+		unsigned long start = memblock_region_memory_base_pfn(mem);
+		unsigned long end = memblock_region_memory_end_pfn(mem);
+
+		/* Ignore complete lowmem entries */
+		if (end <= max_low)
+			continue;
+
+		if (memblock_is_nomap(mem))
+			continue;
+
+		/* Truncate partial highmem entries */
+		if (start < max_low)
+			start = max_low;
+
+		/* Find and exclude any reserved regions */
+		for_each_memblock(reserved, res) {
+			unsigned long res_start, res_end;
+
+			res_start = memblock_region_reserved_base_pfn(res);
+			res_end = memblock_region_reserved_end_pfn(res);
+
+			if (res_end < start)
+				continue;
+			if (res_start < start)
+				res_start = start;
+			if (res_start > end)
+				res_start = end;
+			if (res_end > end)
+				res_end = end;
+			if (res_start != start)
+				free_area_high(start, res_start);
+			start = res_end;
+			if (start == end)
+				break;
+		}
+
+		/* And now free anything which remains */
+		if (start < end)
+			free_area_high(start, end);
+	}
+}
+#else
+static void __init free_highpages(void)
+{
+}
+#endif
+
 /*
  * Initialize memory pages.
  */
 
 void __init mem_init(void)
 {
-#ifdef CONFIG_HIGHMEM
-	unsigned long tmp;
-
-	reset_all_zones_managed_pages();
-	for (tmp = max_low_pfn; tmp < max_pfn; tmp++)
-		free_highmem_page(pfn_to_page(tmp));
-#endif
+	free_highpages();
 
 	max_mapnr = max_pfn - ARCH_PFN_OFFSET;
 	high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 4117524ca45b..9c3d980e1c63 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -45,6 +45,7 @@ struct blkcg blkcg_root;
 EXPORT_SYMBOL_GPL(blkcg_root);
 
 struct cgroup_subsys_state * const blkcg_root_css = &blkcg_root.css;
+EXPORT_SYMBOL_GPL(blkcg_root_css);
 
 static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
 
diff --git a/block/genhd.c b/block/genhd.c
index 88a53c188cb7..4d42ae5e8382 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -970,7 +970,7 @@ static int show_partition(struct seq_file *seqf, void *v)
 	char buf[BDEVNAME_SIZE];
 
 	/* Don't show non-partitionable removeable devices or empty devices */
-	if (!get_capacity(sgp) || (!disk_max_parts(sgp) &&
+	if (!get_capacity(sgp) || (!(disk_max_parts(sgp) > 1) &&
 				   (sgp->flags & GENHD_FL_REMOVABLE)))
 		return 0;
 	if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
diff --git a/certs/blacklist_nohashes.c b/certs/blacklist_nohashes.c
index 73fd99098ad7..753b703ef0ef 100644
--- a/certs/blacklist_nohashes.c
+++ b/certs/blacklist_nohashes.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "blacklist.h"
 
-const char __initdata *const blacklist_hashes[] = {
+const char __initconst *const blacklist_hashes[] = {
 	NULL
 };
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b75264b09a46..6591c3a78f57 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -496,6 +496,15 @@ config CRYPTO_CRC32_PCLMUL
 	  which will enable any routine to use the CRC-32-IEEE 802.3 checksum
 	  and gain better performance as compared with the table implementation.
 
+config CRYPTO_CRC32_MIPS
+	tristate "CRC32c and CRC32 CRC algorithm (MIPS)"
+	depends on MIPS_CRC_SUPPORT
+	select CRYPTO_HASH
+	help
+	  CRC32c and CRC32 CRC algorithms implemented using mips crypto
+	  instructions, when available.
+
+
 config CRYPTO_CRCT10DIF
 	tristate "CRCT10DIF algorithm"
 	select CRYPTO_HASH
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 266fc1d64f61..f732dd9dedf9 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -446,24 +446,12 @@ static int ahash_def_finup(struct ahash_request *req)
 	return ahash_def_finup_finish1(req, err);
 }
 
-static int ahash_no_export(struct ahash_request *req, void *out)
-{
-	return -ENOSYS;
-}
-
-static int ahash_no_import(struct ahash_request *req, const void *in)
-{
-	return -ENOSYS;
-}
-
 static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
 {
 	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
 	struct ahash_alg *alg = crypto_ahash_alg(hash);
 
 	hash->setkey = ahash_nosetkey;
-	hash->export = ahash_no_export;
-	hash->import = ahash_no_import;
 
 	if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
 		return crypto_init_shash_ops_async(tfm);
@@ -473,16 +461,14 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
 	hash->final = alg->final;
 	hash->finup = alg->finup ?: ahash_def_finup;
 	hash->digest = alg->digest;
+	hash->export = alg->export;
+	hash->import = alg->import;
 
 	if (alg->setkey) {
 		hash->setkey = alg->setkey;
 		if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
 			crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
 	}
-	if (alg->export)
-		hash->export = alg->export;
-	if (alg->import)
-		hash->import = alg->import;
 
 	return 0;
 }
diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c
index 61e7c4e02fd2..992e8d8dcdd9 100644
--- a/crypto/crypto_engine.c
+++ b/crypto/crypto_engine.c
@@ -15,12 +15,49 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <crypto/engine.h>
-#include <crypto/internal/hash.h>
 #include <uapi/linux/sched/types.h>
 #include "internal.h"
 
 #define CRYPTO_ENGINE_MAX_QLEN 10
 
+/**
+ * crypto_finalize_request - finalize one request if the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+static void crypto_finalize_request(struct crypto_engine *engine,
+			     struct crypto_async_request *req, int err)
+{
+	unsigned long flags;
+	bool finalize_cur_req = false;
+	int ret;
+	struct crypto_engine_ctx *enginectx;
+
+	spin_lock_irqsave(&engine->queue_lock, flags);
+	if (engine->cur_req == req)
+		finalize_cur_req = true;
+	spin_unlock_irqrestore(&engine->queue_lock, flags);
+
+	if (finalize_cur_req) {
+		enginectx = crypto_tfm_ctx(req->tfm);
+		if (engine->cur_req_prepared &&
+		    enginectx->op.unprepare_request) {
+			ret = enginectx->op.unprepare_request(engine, req);
+			if (ret)
+				dev_err(engine->dev, "failed to unprepare request\n");
+		}
+		spin_lock_irqsave(&engine->queue_lock, flags);
+		engine->cur_req = NULL;
+		engine->cur_req_prepared = false;
+		spin_unlock_irqrestore(&engine->queue_lock, flags);
+	}
+
+	req->complete(req, err);
+
+	kthread_queue_work(engine->kworker, &engine->pump_requests);
+}
+
 /**
  * crypto_pump_requests - dequeue one request from engine queue to process
  * @engine: the hardware engine
@@ -34,11 +71,10 @@ static void crypto_pump_requests(struct crypto_engine *engine,
 				 bool in_kthread)
 {
 	struct crypto_async_request *async_req, *backlog;
-	struct ahash_request *hreq;
-	struct ablkcipher_request *breq;
 	unsigned long flags;
 	bool was_busy = false;
-	int ret, rtype;
+	int ret;
+	struct crypto_engine_ctx *enginectx;
 
 	spin_lock_irqsave(&engine->queue_lock, flags);
 
@@ -94,7 +130,6 @@ static void crypto_pump_requests(struct crypto_engine *engine,
 
 	spin_unlock_irqrestore(&engine->queue_lock, flags);
 
-	rtype = crypto_tfm_alg_type(engine->cur_req->tfm);
 	/* Until here we get the request need to be encrypted successfully */
 	if (!was_busy && engine->prepare_crypt_hardware) {
 		ret = engine->prepare_crypt_hardware(engine);
@@ -104,57 +139,31 @@ static void crypto_pump_requests(struct crypto_engine *engine,
 		}
 	}
 
-	switch (rtype) {
-	case CRYPTO_ALG_TYPE_AHASH:
-		hreq = ahash_request_cast(engine->cur_req);
-		if (engine->prepare_hash_request) {
-			ret = engine->prepare_hash_request(engine, hreq);
-			if (ret) {
-				dev_err(engine->dev, "failed to prepare request: %d\n",
-					ret);
-				goto req_err;
-			}
-			engine->cur_req_prepared = true;
-		}
-		ret = engine->hash_one_request(engine, hreq);
-		if (ret) {
-			dev_err(engine->dev, "failed to hash one request from queue\n");
-			goto req_err;
-		}
-		return;
-	case CRYPTO_ALG_TYPE_ABLKCIPHER:
-		breq = ablkcipher_request_cast(engine->cur_req);
-		if (engine->prepare_cipher_request) {
-			ret = engine->prepare_cipher_request(engine, breq);
-			if (ret) {
-				dev_err(engine->dev, "failed to prepare request: %d\n",
-					ret);
-				goto req_err;
-			}
-			engine->cur_req_prepared = true;
-		}
-		ret = engine->cipher_one_request(engine, breq);
+	enginectx = crypto_tfm_ctx(async_req->tfm);
+
+	if (enginectx->op.prepare_request) {
+		ret = enginectx->op.prepare_request(engine, async_req);
 		if (ret) {
-			dev_err(engine->dev, "failed to cipher one request from queue\n");
+			dev_err(engine->dev, "failed to prepare request: %d\n",
+				ret);
 			goto req_err;
 		}
-		return;
-	default:
-		dev_err(engine->dev, "failed to prepare request of unknown type\n");
-		return;
+		engine->cur_req_prepared = true;
+	}
+	if (!enginectx->op.do_one_request) {
+		dev_err(engine->dev, "failed to do request\n");
+		ret = -EINVAL;
+		goto req_err;
 	}
+	ret = enginectx->op.do_one_request(engine, async_req);
+	if (ret) {
+		dev_err(engine->dev, "Failed to do one request from queue: %d\n", ret);
+		goto req_err;
+	}
+	return;
 
 req_err:
-	switch (rtype) {
-	case CRYPTO_ALG_TYPE_AHASH:
-		hreq = ahash_request_cast(engine->cur_req);
-		crypto_finalize_hash_request(engine, hreq, ret);
-		break;
-	case CRYPTO_ALG_TYPE_ABLKCIPHER:
-		breq = ablkcipher_request_cast(engine->cur_req);
-		crypto_finalize_cipher_request(engine, breq, ret);
-		break;
-	}
+	crypto_finalize_request(engine, async_req, ret);
 	return;
 
 out:
@@ -170,13 +179,12 @@ static void crypto_pump_work(struct kthread_work *work)
 }
 
 /**
- * crypto_transfer_cipher_request - transfer the new request into the
- * enginequeue
+ * crypto_transfer_request - transfer the new request into the engine queue
  * @engine: the hardware engine
  * @req: the request need to be listed into the engine queue
  */
-int crypto_transfer_cipher_request(struct crypto_engine *engine,
-				   struct ablkcipher_request *req,
+static int crypto_transfer_request(struct crypto_engine *engine,
+				   struct crypto_async_request *req,
 				   bool need_pump)
 {
 	unsigned long flags;
@@ -189,7 +197,7 @@ int crypto_transfer_cipher_request(struct crypto_engine *engine,
 		return -ESHUTDOWN;
 	}
 
-	ret = ablkcipher_enqueue_request(&engine->queue, req);
+	ret = crypto_enqueue_request(&engine->queue, req);
 
 	if (!engine->busy && need_pump)
 		kthread_queue_work(engine->kworker, &engine->pump_requests);
@@ -197,102 +205,131 @@ int crypto_transfer_cipher_request(struct crypto_engine *engine,
 	spin_unlock_irqrestore(&engine->queue_lock, flags);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(crypto_transfer_cipher_request);
 
 /**
- * crypto_transfer_cipher_request_to_engine - transfer one request to list
+ * crypto_transfer_request_to_engine - transfer one request to list
  * into the engine queue
  * @engine: the hardware engine
  * @req: the request need to be listed into the engine queue
  */
-int crypto_transfer_cipher_request_to_engine(struct crypto_engine *engine,
-					     struct ablkcipher_request *req)
+static int crypto_transfer_request_to_engine(struct crypto_engine *engine,
+					     struct crypto_async_request *req)
 {
-	return crypto_transfer_cipher_request(engine, req, true);
+	return crypto_transfer_request(engine, req, true);
 }
-EXPORT_SYMBOL_GPL(crypto_transfer_cipher_request_to_engine);
 
 /**
- * crypto_transfer_hash_request - transfer the new request into the
- * enginequeue
+ * crypto_transfer_ablkcipher_request_to_engine - transfer one ablkcipher_request
+ * to list into the engine queue
  * @engine: the hardware engine
  * @req: the request need to be listed into the engine queue
+ * TODO: Remove this function when skcipher conversion is finished
  */
-int crypto_transfer_hash_request(struct crypto_engine *engine,
-				 struct ahash_request *req, bool need_pump)
+int crypto_transfer_ablkcipher_request_to_engine(struct crypto_engine *engine,
+						 struct ablkcipher_request *req)
 {
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&engine->queue_lock, flags);
-
-	if (!engine->running) {
-		spin_unlock_irqrestore(&engine->queue_lock, flags);
-		return -ESHUTDOWN;
-	}
-
-	ret = ahash_enqueue_request(&engine->queue, req);
+	return crypto_transfer_request_to_engine(engine, &req->base);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_ablkcipher_request_to_engine);
 
-	if (!engine->busy && need_pump)
-		kthread_queue_work(engine->kworker, &engine->pump_requests);
+/**
+ * crypto_transfer_aead_request_to_engine - transfer one aead_request
+ * to list into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_aead_request_to_engine(struct crypto_engine *engine,
+					   struct aead_request *req)
+{
+	return crypto_transfer_request_to_engine(engine, &req->base);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_aead_request_to_engine);
 
-	spin_unlock_irqrestore(&engine->queue_lock, flags);
-	return ret;
+/**
+ * crypto_transfer_akcipher_request_to_engine - transfer one akcipher_request
+ * to list into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine,
+					       struct akcipher_request *req)
+{
+	return crypto_transfer_request_to_engine(engine, &req->base);
 }
-EXPORT_SYMBOL_GPL(crypto_transfer_hash_request);
+EXPORT_SYMBOL_GPL(crypto_transfer_akcipher_request_to_engine);
 
 /**
- * crypto_transfer_hash_request_to_engine - transfer one request to list
- * into the engine queue
+ * crypto_transfer_hash_request_to_engine - transfer one ahash_request
+ * to list into the engine queue
  * @engine: the hardware engine
  * @req: the request need to be listed into the engine queue
  */
 int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine,
 					   struct ahash_request *req)
 {
-	return crypto_transfer_hash_request(engine, req, true);
+	return crypto_transfer_request_to_engine(engine, &req->base);
 }
 EXPORT_SYMBOL_GPL(crypto_transfer_hash_request_to_engine);
 
 /**
- * crypto_finalize_cipher_request - finalize one request if the request is done
+ * crypto_transfer_skcipher_request_to_engine - transfer one skcipher_request
+ * to list into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine,
+					       struct skcipher_request *req)
+{
+	return crypto_transfer_request_to_engine(engine, &req->base);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_skcipher_request_to_engine);
+
+/**
+ * crypto_finalize_ablkcipher_request - finalize one ablkcipher_request if
+ * the request is done
  * @engine: the hardware engine
  * @req: the request need to be finalized
  * @err: error number
+ * TODO: Remove this function when skcipher conversion is finished
  */
-void crypto_finalize_cipher_request(struct crypto_engine *engine,
-				    struct ablkcipher_request *req, int err)
+void crypto_finalize_ablkcipher_request(struct crypto_engine *engine,
+					struct ablkcipher_request *req, int err)
 {
-	unsigned long flags;
-	bool finalize_cur_req = false;
-	int ret;
-
-	spin_lock_irqsave(&engine->queue_lock, flags);
-	if (engine->cur_req == &req->base)
-		finalize_cur_req = true;
-	spin_unlock_irqrestore(&engine->queue_lock, flags);
-
-	if (finalize_cur_req) {
-		if (engine->cur_req_prepared &&
-		    engine->unprepare_cipher_request) {
-			ret = engine->unprepare_cipher_request(engine, req);
-			if (ret)
-				dev_err(engine->dev, "failed to unprepare request\n");
-		}
-		spin_lock_irqsave(&engine->queue_lock, flags);
-		engine->cur_req = NULL;
-		engine->cur_req_prepared = false;
-		spin_unlock_irqrestore(&engine->queue_lock, flags);
-	}
+	return crypto_finalize_request(engine, &req->base, err);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_ablkcipher_request);
 
-	req->base.complete(&req->base, err);
+/**
+ * crypto_finalize_aead_request - finalize one aead_request if
+ * the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_aead_request(struct crypto_engine *engine,
+				  struct aead_request *req, int err)
+{
+	return crypto_finalize_request(engine, &req->base, err);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_aead_request);
 
-	kthread_queue_work(engine->kworker, &engine->pump_requests);
+/**
+ * crypto_finalize_akcipher_request - finalize one akcipher_request if
+ * the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_akcipher_request(struct crypto_engine *engine,
+				      struct akcipher_request *req, int err)
+{
+	return crypto_finalize_request(engine, &req->base, err);
 }
-EXPORT_SYMBOL_GPL(crypto_finalize_cipher_request);
+EXPORT_SYMBOL_GPL(crypto_finalize_akcipher_request);
 
 /**
- * crypto_finalize_hash_request - finalize one request if the request is done
+ * crypto_finalize_hash_request - finalize one ahash_request if
+ * the request is done
  * @engine: the hardware engine
  * @req: the request need to be finalized
  * @err: error number
@@ -300,34 +337,24 @@ EXPORT_SYMBOL_GPL(crypto_finalize_cipher_request);
 void crypto_finalize_hash_request(struct crypto_engine *engine,
 				  struct ahash_request *req, int err)
 {
-	unsigned long flags;
-	bool finalize_cur_req = false;
-	int ret;
-
-	spin_lock_irqsave(&engine->queue_lock, flags);
-	if (engine->cur_req == &req->base)
-		finalize_cur_req = true;
-	spin_unlock_irqrestore(&engine->queue_lock, flags);
-
-	if (finalize_cur_req) {
-		if (engine->cur_req_prepared &&
-		    engine->unprepare_hash_request) {
-			ret = engine->unprepare_hash_request(engine, req);
-			if (ret)
-				dev_err(engine->dev, "failed to unprepare request\n");
-		}
-		spin_lock_irqsave(&engine->queue_lock, flags);
-		engine->cur_req = NULL;
-		engine->cur_req_prepared = false;
-		spin_unlock_irqrestore(&engine->queue_lock, flags);
-	}
-
-	req->base.complete(&req->base, err);
-
-	kthread_queue_work(engine->kworker, &engine->pump_requests);
+	return crypto_finalize_request(engine, &req->base, err);
 }
 EXPORT_SYMBOL_GPL(crypto_finalize_hash_request);
 
+/**
+ * crypto_finalize_skcipher_request - finalize one skcipher_request if
+ * the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_skcipher_request(struct crypto_engine *engine,
+				      struct skcipher_request *req, int err)
+{
+	return crypto_finalize_request(engine, &req->base, err);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_skcipher_request);
+
 /**
  * crypto_engine_start - start the hardware engine
  * @engine: the hardware engine need to be started
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index 5c291eedaa70..0e89b5457cab 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -271,7 +271,7 @@ static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
 		return -ENOENT;
 
 	err = -ENOMEM;
-	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 	if (!skb)
 		goto drop_alg;
 
diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c
index fe5129d6ff4e..f14152147ce8 100644
--- a/crypto/mcryptd.c
+++ b/crypto/mcryptd.c
@@ -367,7 +367,7 @@ static void mcryptd_hash_update(struct crypto_async_request *req_async, int err)
 		goto out;
 
 	rctx->out = req->result;
-	err = ahash_mcryptd_update(&rctx->areq);
+	err = crypto_ahash_update(&rctx->areq);
 	if (err) {
 		req->base.complete = rctx->complete;
 		goto out;
@@ -394,7 +394,7 @@ static void mcryptd_hash_final(struct crypto_async_request *req_async, int err)
 		goto out;
 
 	rctx->out = req->result;
-	err = ahash_mcryptd_final(&rctx->areq);
+	err = crypto_ahash_final(&rctx->areq);
 	if (err) {
 		req->base.complete = rctx->complete;
 		goto out;
@@ -420,7 +420,7 @@ static void mcryptd_hash_finup(struct crypto_async_request *req_async, int err)
 	if (unlikely(err == -EINPROGRESS))
 		goto out;
 	rctx->out = req->result;
-	err = ahash_mcryptd_finup(&rctx->areq);
+	err = crypto_ahash_finup(&rctx->areq);
 
 	if (err) {
 		req->base.complete = rctx->complete;
@@ -455,7 +455,7 @@ static void mcryptd_hash_digest(struct crypto_async_request *req_async, int err)
 						rctx->complete, req_async);
 
 	rctx->out = req->result;
-	err = ahash_mcryptd_digest(desc);
+	err = crypto_ahash_init(desc) ?: crypto_ahash_finup(desc);
 
 out:
 	local_bh_disable();
@@ -612,32 +612,6 @@ struct mcryptd_ahash *mcryptd_alloc_ahash(const char *alg_name,
 }
 EXPORT_SYMBOL_GPL(mcryptd_alloc_ahash);
 
-int ahash_mcryptd_digest(struct ahash_request *desc)
-{
-	return crypto_ahash_init(desc) ?: ahash_mcryptd_finup(desc);
-}
-
-int ahash_mcryptd_update(struct ahash_request *desc)
-{
-	/* alignment is to be done by multi-buffer crypto algorithm if needed */
-
-	return crypto_ahash_update(desc);
-}
-
-int ahash_mcryptd_finup(struct ahash_request *desc)
-{
-	/* alignment is to be done by multi-buffer crypto algorithm if needed */
-
-	return crypto_ahash_finup(desc);
-}
-
-int ahash_mcryptd_final(struct ahash_request *desc)
-{
-	/* alignment is to be done by multi-buffer crypto algorithm if needed */
-
-	return crypto_ahash_final(desc);
-}
-
 struct crypto_ahash *mcryptd_ahash_child(struct mcryptd_ahash *tfm)
 {
 	struct mcryptd_hash_ctx *ctx = crypto_ahash_ctx(&tfm->base);
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 2908f93c3e55..9893dbfc1af4 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -192,7 +192,7 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
 	if (likely(!pad_len))
 		goto out;
 
-	out_buf = kzalloc(ctx->key_size, GFP_ATOMIC);
+	out_buf = kzalloc(ctx->key_size, GFP_KERNEL);
 	err = -ENOMEM;
 	if (!out_buf)
 		goto out;
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 95255ecfae7c..e2f7bddf5522 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -39,6 +39,7 @@
 struct iort_its_msi_chip {
 	struct list_head	list;
 	struct fwnode_handle	*fw_node;
+	phys_addr_t		base_addr;
 	u32			translation_id;
 };
 
@@ -161,14 +162,16 @@ static LIST_HEAD(iort_msi_chip_list);
 static DEFINE_SPINLOCK(iort_msi_chip_lock);
 
 /**
- * iort_register_domain_token() - register domain token and related ITS ID
- * to the list from where we can get it back later on.
+ * iort_register_domain_token() - register domain token along with related
+ * ITS ID and base address to the list from where we can get it back later on.
  * @trans_id: ITS ID.
+ * @base: ITS base address.
  * @fw_node: Domain token.
  *
  * Returns: 0 on success, -ENOMEM if no memory when allocating list element
  */
-int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+int iort_register_domain_token(int trans_id, phys_addr_t base,
+			       struct fwnode_handle *fw_node)
 {
 	struct iort_its_msi_chip *its_msi_chip;
 
@@ -178,6 +181,7 @@ int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
 
 	its_msi_chip->fw_node = fw_node;
 	its_msi_chip->translation_id = trans_id;
+	its_msi_chip->base_addr = base;
 
 	spin_lock(&iort_msi_chip_lock);
 	list_add(&its_msi_chip->list, &iort_msi_chip_list);
@@ -581,6 +585,24 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
 	return -ENODEV;
 }
 
+static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
+{
+	struct iort_its_msi_chip *its_msi_chip;
+	int ret = -ENODEV;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == its_id) {
+			*base = its_msi_chip->base_addr;
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+
+	return ret;
+}
+
 /**
  * iort_dev_find_its_id() - Find the ITS identifier for a device
  * @dev: The device.
@@ -766,6 +788,24 @@ static inline bool iort_iommu_driver_enabled(u8 type)
 }
 
 #ifdef CONFIG_IOMMU_API
+static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev)
+{
+	struct acpi_iort_node *iommu;
+	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+	iommu = iort_get_iort_node(fwspec->iommu_fwnode);
+
+	if (iommu && (iommu->type == ACPI_IORT_NODE_SMMU_V3)) {
+		struct acpi_iort_smmu_v3 *smmu;
+
+		smmu = (struct acpi_iort_smmu_v3 *)iommu->node_data;
+		if (smmu->model == ACPI_IORT_SMMU_V3_HISILICON_HI161X)
+			return iommu;
+	}
+
+	return NULL;
+}
+
 static inline const struct iommu_ops *iort_fwspec_iommu_ops(
 				struct iommu_fwspec *fwspec)
 {
@@ -782,6 +822,69 @@ static inline int iort_add_device_replay(const struct iommu_ops *ops,
 
 	return err;
 }
+
+/**
+ * iort_iommu_msi_get_resv_regions - Reserved region driver helper
+ * @dev: Device from iommu_get_resv_regions()
+ * @head: Reserved region list from iommu_get_resv_regions()
+ *
+ * Returns: Number of msi reserved regions on success (0 if platform
+ *          doesn't require the reservation or no associated msi regions),
+ *          appropriate error value otherwise. The ITS interrupt translation
+ *          spaces (ITS_base + SZ_64K, SZ_64K) associated with the device
+ *          are the msi reserved regions.
+ */
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{
+	struct acpi_iort_its_group *its;
+	struct acpi_iort_node *iommu_node, *its_node = NULL;
+	int i, resv = 0;
+
+	iommu_node = iort_get_msi_resv_iommu(dev);
+	if (!iommu_node)
+		return 0;
+
+	/*
+	 * Current logic to reserve ITS regions relies on HW topologies
+	 * where a given PCI or named component maps its IDs to only one
+	 * ITS group; if a PCI or named component can map its IDs to
+	 * different ITS groups through IORT mappings this function has
+	 * to be reworked to ensure we reserve regions for all ITS groups
+	 * a given PCI or named component may map IDs to.
+	 */
+
+	for (i = 0; i < dev->iommu_fwspec->num_ids; i++) {
+		its_node = iort_node_map_id(iommu_node,
+					dev->iommu_fwspec->ids[i],
+					NULL, IORT_MSI_TYPE);
+		if (its_node)
+			break;
+	}
+
+	if (!its_node)
+		return 0;
+
+	/* Move to ITS specific data */
+	its = (struct acpi_iort_its_group *)its_node->node_data;
+
+	for (i = 0; i < its->its_count; i++) {
+		phys_addr_t base;
+
+		if (!iort_find_its_base(its->identifiers[i], &base)) {
+			int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+			struct iommu_resv_region *region;
+
+			region = iommu_alloc_resv_region(base + SZ_64K, SZ_64K,
+							 prot, IOMMU_RESV_MSI);
+			if (region) {
+				list_add_tail(&region->list, head);
+				resv++;
+			}
+		}
+	}
+
+	return (resv == its->its_count) ? resv : -ENODEV;
+}
 #else
 static inline const struct iommu_ops *iort_fwspec_iommu_ops(
 				struct iommu_fwspec *fwspec)
@@ -789,6 +892,8 @@ static inline const struct iommu_ops *iort_fwspec_iommu_ops(
 static inline int iort_add_device_replay(const struct iommu_ops *ops,
 					 struct device *dev)
 { return 0; }
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{ return 0; }
 #endif
 
 static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 15e3d3c2260d..764b63a5aade 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1991,8 +1991,14 @@ static void binder_send_failed_reply(struct binder_transaction *t,
 					&target_thread->reply_error.work);
 				wake_up_interruptible(&target_thread->wait);
 			} else {
-				WARN(1, "Unexpected reply error: %u\n",
-						target_thread->reply_error.cmd);
+				/*
+				 * Cannot get here for normal operation, but
+				 * we can if multiple synchronous transactions
+				 * are sent without blocking for responses.
+				 * Just ignore the 2nd error in this case.
+				 */
+				pr_warn("Unexpected reply error: %u\n",
+					target_thread->reply_error.cmd);
 			}
 			binder_inner_proc_unlock(target_thread->proc);
 			binder_thread_dec_tmpref(target_thread);
@@ -2193,7 +2199,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
 	int debug_id = buffer->debug_id;
 
 	binder_debug(BINDER_DEBUG_TRANSACTION,
-		     "%d buffer release %d, size %zd-%zd, failed at %p\n",
+		     "%d buffer release %d, size %zd-%zd, failed at %pK\n",
 		     proc->pid, buffer->debug_id,
 		     buffer->data_size, buffer->offsets_size, failed_at);
 
@@ -3705,7 +3711,7 @@ static int binder_thread_write(struct binder_proc *proc,
 				}
 			}
 			binder_debug(BINDER_DEBUG_DEAD_BINDER,
-				     "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
+				     "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n",
 				     proc->pid, thread->pid, (u64)cookie,
 				     death);
 			if (death == NULL) {
@@ -4376,6 +4382,15 @@ static int binder_thread_release(struct binder_proc *proc,
 
 	binder_inner_proc_unlock(thread->proc);
 
+	/*
+	 * This is needed to avoid races between wake_up_poll() above and
+	 * and ep_remove_waitqueue() called for other reasons (eg the epoll file
+	 * descriptor being closed); ep_remove_waitqueue() holds an RCU read
+	 * lock, so we can be sure it's done after calling synchronize_rcu().
+	 */
+	if (thread->looper & BINDER_LOOPER_STATE_POLL)
+		synchronize_rcu();
+
 	if (send_reply)
 		binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
 	binder_release_work(proc, &thread->todo);
@@ -4391,6 +4406,8 @@ static __poll_t binder_poll(struct file *filp,
 	bool wait_for_proc_work;
 
 	thread = binder_get_thread(proc);
+	if (!thread)
+		return POLLERR;
 
 	binder_inner_proc_lock(thread->proc);
 	thread->looper |= BINDER_LOOPER_STATE_POLL;
@@ -5034,7 +5051,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
 	spin_lock(&t->lock);
 	to_proc = t->to_proc;
 	seq_printf(m,
-		   "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+		   "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
 		   prefix, t->debug_id, t,
 		   t->from ? t->from->proc->pid : 0,
 		   t->from ? t->from->pid : 0,
@@ -5058,7 +5075,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
 	}
 	if (buffer->target_node)
 		seq_printf(m, " node %d", buffer->target_node->debug_id);
-	seq_printf(m, " size %zd:%zd data %p\n",
+	seq_printf(m, " size %zd:%zd data %pK\n",
 		   buffer->data_size, buffer->offsets_size,
 		   buffer->data);
 }
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index a0de7a38430c..7adcf3caabd0 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -665,6 +665,16 @@ int ahci_stop_engine(struct ata_port *ap)
 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
 		return 0;
 
+	/*
+	 * Don't try to issue commands but return with ENODEV if the
+	 * AHCI controller not available anymore (e.g. due to PCIe hot
+	 * unplugging). Otherwise a 500ms delay for each port is added.
+	 */
+	if (tmp == 0xffffffff) {
+		dev_err(ap->host->dev, "AHCI controller unavailable!\n");
+		return -ENODEV;
+	}
+
 	/* setting HBA to idle */
 	tmp &= ~PORT_CMD_START;
 	writel(tmp, port_mmio + PORT_CMD);
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 341d0ef82cbd..30cc8f1a31e1 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -340,7 +340,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
  * 2) regulator for controlling the targets power (optional)
  * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
  *    or for non devicetree enabled platforms a single clock
- *	4) phys (optional)
+ * 4) phys (optional)
  *
  * RETURNS:
  * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3c09122bf038..28cad49fc846 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4530,6 +4530,11 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 	{ "PIONEER DVD-RW  DVR-212D",	NULL,	ATA_HORKAGE_NOSETXFER },
 	{ "PIONEER DVD-RW  DVR-216D",	NULL,	ATA_HORKAGE_NOSETXFER },
 
+	/* The 512GB version of the MX100 has both queued TRIM and LPM issues */
+	{ "Crucial_CT512MX100*",	NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
+						ATA_HORKAGE_ZERO_AFTER_TRIM |
+						ATA_HORKAGE_NOLPM, },
+
 	/* devices that don't properly handle queued TRIM commands */
 	{ "Micron_M500_*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM |
 						ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -5401,8 +5406,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
 	 * We guarantee to LLDs that they will have at least one
 	 * non-zero sg if the command is a data command.
 	 */
-	if (WARN_ON_ONCE(ata_is_data(prot) &&
-			 (!qc->sg || !qc->n_elem || !qc->nbytes)))
+	if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes))
 		goto sys_err;
 
 	if (ata_is_dma(prot) || (ata_is_pio(prot) &&
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 66be961c93a4..89a9d4a2efc8 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3316,6 +3316,12 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
 		goto invalid_fld;
 	}
 
+	/* We may not issue NCQ commands to devices not supporting NCQ */
+	if (ata_is_ncq(tf->protocol) && !ata_ncq_enabled(dev)) {
+		fp = 1;
+		goto invalid_fld;
+	}
+
 	/* sanity check for pio multi commands */
 	if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) {
 		fp = 1;
@@ -4282,7 +4288,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
 #ifdef ATA_DEBUG
 	struct scsi_device *scsidev = cmd->device;
 
-	DPRINTK("CDB (%u:%d,%d,%d) %9ph\n",
+	DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n",
 		ap->print_id,
 		scsidev->channel, scsidev->id, scsidev->lun,
 		cmd->cmnd);
@@ -4309,7 +4315,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
 		if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
 			/* relay SCSI command to ATAPI device */
 			int len = COMMAND_SIZE(scsi_op);
-			if (unlikely(len > scmd->cmd_len || len > dev->cdb_len))
+			if (unlikely(len > scmd->cmd_len ||
+				     len > dev->cdb_len ||
+				     scmd->cmd_len > ATAPI_CDB_LEN))
 				goto bad_cdb_len;
 
 			xlat_func = atapi_xlat;
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index b4d54771c9fe..ebecab8c3f36 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -796,7 +796,7 @@ static int arasan_cf_probe(struct platform_device *pdev)
 	struct resource *res;
 	u32 quirk;
 	irq_handler_t irq_handler = NULL;
-	int ret = 0;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -809,10 +809,8 @@ static int arasan_cf_probe(struct platform_device *pdev)
 	}
 
 	acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL);
-	if (!acdev) {
-		dev_warn(&pdev->dev, "kzalloc fail\n");
+	if (!acdev)
 		return -ENOMEM;
-	}
 
 	if (pdata)
 		quirk = pdata->quirk;
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 8468b300193b..9bac79edbc2c 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -658,10 +658,10 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
 	u8 status;
 	int n = 0;
 	u16 *buf = kmalloc(len, GFP_KERNEL);
-	if (buf == NULL) {
-		printk(KERN_ERR "it821x_firmware_command: Out of memory\n");
+
+	if (!buf)
 		return NULL;
-	}
+
 	/* This isn't quite a normal ATA command as we are talking to the
 	   firmware not the drives */
 	ap->ctl |= ATA_NIEN;
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index 0adcb40d2794..9588e685d994 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -1131,11 +1131,9 @@ static int pata_macio_attach(struct macio_dev *mdev,
 	/* Allocate and init private data structure */
 	priv = devm_kzalloc(&mdev->ofdev.dev,
 			    sizeof(struct pata_macio_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		dev_err(&mdev->ofdev.dev,
-			"Failed to allocate private memory\n");
+	if (!priv)
 		return -ENOMEM;
-	}
+
 	priv->node = of_node_get(mdev->ofdev.dev.of_node);
 	priv->mdev = mdev;
 	priv->dev = &mdev->ofdev.dev;
@@ -1277,11 +1275,9 @@ static int pata_macio_pci_attach(struct pci_dev *pdev,
 	/* Allocate and init private data structure */
 	priv = devm_kzalloc(&pdev->dev,
 			    sizeof(struct pata_macio_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		dev_err(&pdev->dev,
-			"Failed to allocate private memory\n");
+	if (!priv)
 		return -ENOMEM;
-	}
+
 	priv->node = of_node_get(np);
 	priv->pdev = pdev;
 	priv->dev = &pdev->dev;
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 9730125530f6..f1d352d5f128 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -738,7 +738,6 @@ static int mpc52xx_ata_probe(struct platform_device *op)
 	/* Prepare our private structure */
 	priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
 	if (!priv) {
-		dev_err(&op->dev, "error allocating private structure\n");
 		rv = -ENOMEM;
 		goto err1;
 	}
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 50801c40b029..bb96dc35950d 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -505,10 +505,8 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
 	cpu_type = platform_get_device_id(pdev)->driver_data;
 
 	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
-	if (!info) {
-		dev_err(dev, "failed to allocate memory for device data\n");
+	if (!info)
 		return -ENOMEM;
-	}
 
 	info->irq = platform_get_irq(pdev, 0);
 
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 6af4ec3c88c3..ce3d6674ef80 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -901,7 +901,6 @@ static int sata_dwc_port_start(struct ata_port *ap)
 	/* Allocate Port Struct */
 	hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
 	if (!hsdevp) {
-		dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
 		err = -ENOMEM;
 		goto CLEANUP;
 	}
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 80ee2f2a50d0..6456e07db72a 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -146,6 +146,7 @@
 enum sata_rcar_type {
 	RCAR_GEN1_SATA,
 	RCAR_GEN2_SATA,
+	RCAR_GEN3_SATA,
 	RCAR_R8A7790_ES1_SATA,
 };
 
@@ -784,26 +785,11 @@ static void sata_rcar_setup_port(struct ata_host *host)
 	ioaddr->command_addr	= ioaddr->cmd_addr + (ATA_REG_CMD << 2);
 }
 
-static void sata_rcar_init_controller(struct ata_host *host)
+static void sata_rcar_init_module(struct sata_rcar_priv *priv)
 {
-	struct sata_rcar_priv *priv = host->private_data;
 	void __iomem *base = priv->base;
 	u32 val;
 
-	/* reset and setup phy */
-	switch (priv->type) {
-	case RCAR_GEN1_SATA:
-		sata_rcar_gen1_phy_init(priv);
-		break;
-	case RCAR_GEN2_SATA:
-	case RCAR_R8A7790_ES1_SATA:
-		sata_rcar_gen2_phy_init(priv);
-		break;
-	default:
-		dev_warn(host->dev, "SATA phy is not initialized\n");
-		break;
-	}
-
 	/* SATA-IP reset state */
 	val = ioread32(base + ATAPI_CONTROL1_REG);
 	val |= ATAPI_CONTROL1_RESET;
@@ -824,10 +810,33 @@ static void sata_rcar_init_controller(struct ata_host *host)
 	/* ack and mask */
 	iowrite32(0, base + SATAINTSTAT_REG);
 	iowrite32(0x7ff, base + SATAINTMASK_REG);
+
 	/* enable interrupts */
 	iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
 }
 
+static void sata_rcar_init_controller(struct ata_host *host)
+{
+	struct sata_rcar_priv *priv = host->private_data;
+
+	/* reset and setup phy */
+	switch (priv->type) {
+	case RCAR_GEN1_SATA:
+		sata_rcar_gen1_phy_init(priv);
+		break;
+	case RCAR_GEN2_SATA:
+	case RCAR_GEN3_SATA:
+	case RCAR_R8A7790_ES1_SATA:
+		sata_rcar_gen2_phy_init(priv);
+		break;
+	default:
+		dev_warn(host->dev, "SATA phy is not initialized\n");
+		break;
+	}
+
+	sata_rcar_init_module(priv);
+}
+
 static const struct of_device_id sata_rcar_match[] = {
 	{
 		/* Deprecated by "renesas,sata-r8a7779" */
@@ -856,7 +865,7 @@ static const struct of_device_id sata_rcar_match[] = {
 	},
 	{
 		.compatible = "renesas,sata-r8a7795",
-		.data = (void *)RCAR_GEN2_SATA
+		.data = (void *)RCAR_GEN3_SATA
 	},
 	{
 		.compatible = "renesas,rcar-gen2-sata",
@@ -864,7 +873,7 @@ static const struct of_device_id sata_rcar_match[] = {
 	},
 	{
 		.compatible = "renesas,rcar-gen3-sata",
-		.data = (void *)RCAR_GEN2_SATA
+		.data = (void *)RCAR_GEN3_SATA
 	},
 	{ },
 };
@@ -982,11 +991,18 @@ static int sata_rcar_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	/* ack and mask */
-	iowrite32(0, base + SATAINTSTAT_REG);
-	iowrite32(0x7ff, base + SATAINTMASK_REG);
-	/* enable interrupts */
-	iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
+	if (priv->type == RCAR_GEN3_SATA) {
+		sata_rcar_gen2_phy_init(priv);
+		sata_rcar_init_module(priv);
+	} else {
+		/* ack and mask */
+		iowrite32(0, base + SATAINTSTAT_REG);
+		iowrite32(0x7ff, base + SATAINTMASK_REG);
+
+		/* enable interrupts */
+		iowrite32(ATAPI_INT_ENABLE_SATAINT,
+			  base + ATAPI_INT_ENABLE_REG);
+	}
 
 	ata_host_resume(host);
 
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 4735318f4268..056acde5e7d3 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -217,8 +217,6 @@ static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
 
 	if (count < 1)
 		return -EINVAL;
-	if (count >= I2C_SMBUS_BLOCK_MAX)
-		return -E2BIG;
 
 	--count;
 	return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
@@ -235,8 +233,6 @@ static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
 
 	if (reg_size != 1 || val_size < 1)
 		return -EINVAL;
-	if (val_size >= I2C_SMBUS_BLOCK_MAX)
-		return -E2BIG;
 
 	ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
 	if (ret == val_size)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index ee302ccdfbc8..872be065e3fe 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -99,7 +99,7 @@ bool regmap_cached(struct regmap *map, unsigned int reg)
 	int ret;
 	unsigned int val;
 
-	if (map->cache == REGCACHE_NONE)
+	if (map->cache_type == REGCACHE_NONE)
 		return false;
 
 	if (!map->cache_ops)
@@ -174,7 +174,7 @@ static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
 	unsigned int i;
 
 	for (i = 0; i < num; i++)
-		if (!regmap_volatile(map, reg + i))
+		if (!regmap_volatile(map, reg + regmap_get_offset(map, i)))
 			return false;
 
 	return true;
@@ -1831,7 +1831,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 		return -EINVAL;
 	if (val_len % map->format.val_bytes)
 		return -EINVAL;
-	if (map->max_raw_write && map->max_raw_write > val_len)
+	if (map->max_raw_write && map->max_raw_write < val_len)
 		return -E2BIG;
 
 	map->lock(map->lock_arg);
@@ -1993,7 +1993,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 				return -EINVAL;
 			}
 
-			ret = regmap_write(map, reg + (i * map->reg_stride),
+			ret = regmap_write(map, reg + regmap_get_offset(map, i),
 					   ival);
 			if (ret)
 				return ret;
@@ -2542,18 +2542,39 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 
 	if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
 	    map->cache_type == REGCACHE_NONE) {
+		size_t chunk_count, chunk_bytes;
+		size_t chunk_regs = val_count;
+
 		if (!map->bus->read) {
 			ret = -ENOTSUPP;
 			goto out;
 		}
-		if (map->max_raw_read && map->max_raw_read < val_len) {
-			ret = -E2BIG;
-			goto out;
-		}
 
-		/* Physical block read if there's no cache involved */
-		ret = _regmap_raw_read(map, reg, val, val_len);
+		if (map->use_single_read)
+			chunk_regs = 1;
+		else if (map->max_raw_read && val_len > map->max_raw_read)
+			chunk_regs = map->max_raw_read / val_bytes;
+
+		chunk_count = val_count / chunk_regs;
+		chunk_bytes = chunk_regs * val_bytes;
+
+		/* Read bytes that fit into whole chunks */
+		for (i = 0; i < chunk_count; i++) {
+			ret = _regmap_raw_read(map, reg, val, chunk_bytes);
+			if (ret != 0)
+				goto out;
+
+			reg += regmap_get_offset(map, chunk_regs);
+			val += chunk_bytes;
+			val_len -= chunk_bytes;
+		}
 
+		/* Read remaining bytes */
+		if (val_len) {
+			ret = _regmap_raw_read(map, reg, val, val_len);
+			if (ret != 0)
+				goto out;
+		}
 	} else {
 		/* Otherwise go word by word for the cache; should be low
 		 * cost as we expect to hit the cache.
@@ -2653,108 +2674,60 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 
 	if (!IS_ALIGNED(reg, map->reg_stride))
 		return -EINVAL;
+	if (val_count == 0)
+		return -EINVAL;
 
 	if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
-		/*
-		 * Some devices does not support bulk read, for
-		 * them we have a series of single read operations.
-		 */
-		size_t total_size = val_bytes * val_count;
-
-		if (!map->use_single_read &&
-		    (!map->max_raw_read || map->max_raw_read > total_size)) {
-			ret = regmap_raw_read(map, reg, val,
-					      val_bytes * val_count);
-			if (ret != 0)
-				return ret;
-		} else {
-			/*
-			 * Some devices do not support bulk read or do not
-			 * support large bulk reads, for them we have a series
-			 * of read operations.
-			 */
-			int chunk_stride = map->reg_stride;
-			size_t chunk_size = val_bytes;
-			size_t chunk_count = val_count;
-
-			if (!map->use_single_read) {
-				chunk_size = map->max_raw_read;
-				if (chunk_size % val_bytes)
-					chunk_size -= chunk_size % val_bytes;
-				chunk_count = total_size / chunk_size;
-				chunk_stride *= chunk_size / val_bytes;
-			}
-
-			/* Read bytes that fit into a multiple of chunk_size */
-			for (i = 0; i < chunk_count; i++) {
-				ret = regmap_raw_read(map,
-						      reg + (i * chunk_stride),
-						      val + (i * chunk_size),
-						      chunk_size);
-				if (ret != 0)
-					return ret;
-			}
-
-			/* Read remaining bytes */
-			if (chunk_size * i < total_size) {
-				ret = regmap_raw_read(map,
-						      reg + (i * chunk_stride),
-						      val + (i * chunk_size),
-						      total_size - i * chunk_size);
-				if (ret != 0)
-					return ret;
-			}
-		}
+		ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
+		if (ret != 0)
+			return ret;
 
 		for (i = 0; i < val_count * val_bytes; i += val_bytes)
 			map->format.parse_inplace(val + i);
 	} else {
+#ifdef CONFIG_64BIT
+		u64 *u64 = val;
+#endif
+		u32 *u32 = val;
+		u16 *u16 = val;
+		u8 *u8 = val;
+
+		map->lock(map->lock_arg);
+
 		for (i = 0; i < val_count; i++) {
 			unsigned int ival;
-			ret = regmap_read(map, reg + regmap_get_offset(map, i),
-					  &ival);
-			if (ret != 0)
-				return ret;
 
-			if (map->format.format_val) {
-				map->format.format_val(val + (i * val_bytes), ival, 0);
-			} else {
-				/* Devices providing read and write
-				 * operations can use the bulk I/O
-				 * functions if they define a val_bytes,
-				 * we assume that the values are native
-				 * endian.
-				 */
-#ifdef CONFIG_64BIT
-				u64 *u64 = val;
-#endif
-				u32 *u32 = val;
-				u16 *u16 = val;
-				u8 *u8 = val;
+			ret = _regmap_read(map, reg + regmap_get_offset(map, i),
+					   &ival);
+			if (ret != 0)
+				goto out;
 
-				switch (map->format.val_bytes) {
+			switch (map->format.val_bytes) {
 #ifdef CONFIG_64BIT
-				case 8:
-					u64[i] = ival;
-					break;
+			case 8:
+				u64[i] = ival;
+				break;
 #endif
-				case 4:
-					u32[i] = ival;
-					break;
-				case 2:
-					u16[i] = ival;
-					break;
-				case 1:
-					u8[i] = ival;
-					break;
-				default:
-					return -EINVAL;
-				}
+			case 4:
+				u32[i] = ival;
+				break;
+			case 2:
+				u16[i] = ival;
+				break;
+			case 1:
+				u8[i] = ival;
+				break;
+			default:
+				ret = -EINVAL;
+				goto out;
 			}
 		}
+
+out:
+		map->unlock(map->lock_arg);
 	}
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_read);
 
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 204afe66de92..3d7a5c149af3 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -203,6 +203,12 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
 	{ }	/* Terminating entry */
 };
 
+static inline void ath3k_log_failed_loading(int err, int len, int size)
+{
+	BT_ERR("Error in firmware loading err = %d, len = %d, size = %d",
+			err, len, size);
+}
+
 #define USB_REQ_DFU_DNLOAD	1
 #define BULK_SIZE		4096
 #define FW_HDR_SIZE		20
@@ -227,15 +233,16 @@ static int ath3k_load_firmware(struct usb_device *udev,
 		return -ENOMEM;
 	}
 
-	memcpy(send_buf, firmware->data, 20);
+	memcpy(send_buf, firmware->data, FW_HDR_SIZE);
 	err = usb_control_msg(udev, pipe, USB_REQ_DFU_DNLOAD, USB_TYPE_VENDOR,
-			      0, 0, send_buf, 20, USB_CTRL_SET_TIMEOUT);
+			      0, 0, send_buf, FW_HDR_SIZE,
+			      USB_CTRL_SET_TIMEOUT);
 	if (err < 0) {
 		BT_ERR("Can't change to loading configuration err");
 		goto error;
 	}
-	sent += 20;
-	count -= 20;
+	sent += FW_HDR_SIZE;
+	count -= FW_HDR_SIZE;
 
 	pipe = usb_sndbulkpipe(udev, 0x02);
 
@@ -250,8 +257,7 @@ static int ath3k_load_firmware(struct usb_device *udev,
 					&len, 3000);
 
 		if (err || (len != size)) {
-			BT_ERR("Error in firmware loading err = %d,"
-				"len = %d, size = %d", err, len, size);
+			ath3k_log_failed_loading(err, len, size);
 			goto error;
 		}
 
@@ -350,8 +356,7 @@ static int ath3k_load_fwfile(struct usb_device *udev,
 		err = usb_bulk_msg(udev, pipe, send_buf, size,
 					&len, 3000);
 		if (err || (len != size)) {
-			BT_ERR("Error in firmware loading err = %d,"
-				"len = %d, size = %d", err, len, size);
+			ath3k_log_failed_loading(err, len, size);
 			kfree(send_buf);
 			return err;
 		}
@@ -398,7 +403,7 @@ static int ath3k_set_normal_mode(struct usb_device *udev)
 static int ath3k_load_patch(struct usb_device *udev)
 {
 	unsigned char fw_state;
-	char filename[ATH3K_NAME_LEN] = {0};
+	char filename[ATH3K_NAME_LEN];
 	const struct firmware *firmware;
 	struct ath3k_version fw_version;
 	__u32 pt_rom_version, pt_build_version;
@@ -451,7 +456,7 @@ static int ath3k_load_patch(struct usb_device *udev)
 static int ath3k_load_syscfg(struct usb_device *udev)
 {
 	unsigned char fw_state;
-	char filename[ATH3K_NAME_LEN] = {0};
+	char filename[ATH3K_NAME_LEN];
 	const struct firmware *firmware;
 	struct ath3k_version fw_version;
 	int clk_value, ret;
@@ -522,7 +527,6 @@ static int ath3k_probe(struct usb_interface *intf,
 
 	/* load patch and sysconfig files for AR3012 */
 	if (id->driver_info & BTUSB_ATH3012) {
-
 		/* New firmware with patch and sysconfig files already loaded */
 		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001)
 			return -ENODEV;
@@ -565,7 +569,7 @@ static int ath3k_probe(struct usb_interface *intf,
 
 static void ath3k_disconnect(struct usb_interface *intf)
 {
-	BT_DBG("ath3k_disconnect intf %p", intf);
+	BT_DBG("%s intf %p", __func__, intf);
 }
 
 static struct usb_driver ath3k_driver = {
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index b280d466f05b..f6c694a1b9b0 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -183,7 +183,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
 		return -EFAULT;
 	}
 
-	skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
+	skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_KERNEL);
 	if (!skb) {
 		BT_ERR("No free skb");
 		return -ENOMEM;
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 6e2ad748abba..437f080deaab 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -35,6 +35,60 @@
 #define RTL_ROM_LMP_8761A	0x8761
 #define RTL_ROM_LMP_8822B	0x8822
 
+#define IC_MATCH_FL_LMPSUBV	(1 << 0)
+#define IC_MATCH_FL_HCIREV	(1 << 1)
+#define IC_INFO(lmps, hcir) \
+	.match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \
+	.lmp_subver = (lmps), \
+	.hci_rev = (hcir)
+
+struct id_table {
+	__u16 match_flags;
+	__u16 lmp_subver;
+	__u16 hci_rev;
+	bool config_needed;
+	char *fw_name;
+	char *cfg_name;
+};
+
+static const struct id_table ic_id_table[] = {
+	/* 8723B */
+	{ IC_INFO(RTL_ROM_LMP_8723B, 0xb),
+	  .config_needed = false,
+	  .fw_name  = "rtl_bt/rtl8723b_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8723b_config.bin" },
+
+	/* 8723D */
+	{ IC_INFO(RTL_ROM_LMP_8723B, 0xd),
+	  .config_needed = true,
+	  .fw_name  = "rtl_bt/rtl8723d_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8723d_config.bin" },
+
+	/* 8821A */
+	{ IC_INFO(RTL_ROM_LMP_8821A, 0xa),
+	  .config_needed = false,
+	  .fw_name  = "rtl_bt/rtl8821a_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8821a_config.bin" },
+
+	/* 8821C */
+	{ IC_INFO(RTL_ROM_LMP_8821A, 0xc),
+	  .config_needed = false,
+	  .fw_name  = "rtl_bt/rtl8821c_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8821c_config.bin" },
+
+	/* 8761A */
+	{ IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0,
+	  .config_needed = false,
+	  .fw_name  = "rtl_bt/rtl8761a_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8761a_config.bin" },
+
+	/* 8822B */
+	{ IC_INFO(RTL_ROM_LMP_8822B, 0xb),
+	  .config_needed = true,
+	  .fw_name  = "rtl_bt/rtl8822b_fw.bin",
+	  .cfg_name = "rtl_bt/rtl8822b_config.bin" },
+	};
+
 static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
 {
 	struct rtl_rom_version_evt *rom_version;
@@ -64,9 +118,9 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
 	return 0;
 }
 
-static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
-				   const struct firmware *fw,
-				   unsigned char **_buf)
+static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
+				const struct firmware *fw,
+				unsigned char **_buf)
 {
 	const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
 	struct rtl_epatch_header *epatch_info;
@@ -88,6 +142,8 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
 		{ RTL_ROM_LMP_8821A, 2 },
 		{ RTL_ROM_LMP_8761A, 3 },
 		{ RTL_ROM_LMP_8822B, 8 },
+		{ RTL_ROM_LMP_8723B, 9 },	/* 8723D */
+		{ RTL_ROM_LMP_8821A, 10 },	/* 8821C */
 	};
 
 	ret = rtl_read_rom_version(hdev, &rom_version);
@@ -320,8 +376,8 @@ static int btrtl_setup_rtl8723a(struct hci_dev *hdev)
 	return ret;
 }
 
-static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
-				const char *fw_name)
+static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev,
+				u16 lmp_subver)
 {
 	unsigned char *fw_data = NULL;
 	const struct firmware *fw;
@@ -330,39 +386,40 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
 	u8 *cfg_buff = NULL;
 	u8 *tbuff;
 	char *cfg_name = NULL;
-	bool config_needed = false;
+	char *fw_name = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ic_id_table); i++) {
+		if ((ic_id_table[i].match_flags & IC_MATCH_FL_LMPSUBV) &&
+		    (ic_id_table[i].lmp_subver != lmp_subver))
+			continue;
+		if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIREV) &&
+		    (ic_id_table[i].hci_rev != hci_rev))
+			continue;
 
-	switch (lmp_subver) {
-	case RTL_ROM_LMP_8723B:
-		cfg_name = "rtl_bt/rtl8723b_config.bin";
-		break;
-	case RTL_ROM_LMP_8821A:
-		cfg_name = "rtl_bt/rtl8821a_config.bin";
-		break;
-	case RTL_ROM_LMP_8761A:
-		cfg_name = "rtl_bt/rtl8761a_config.bin";
-		break;
-	case RTL_ROM_LMP_8822B:
-		cfg_name = "rtl_bt/rtl8822b_config.bin";
-		config_needed = true;
-		break;
-	default:
-		BT_ERR("%s: rtl: no config according to lmp_subver %04x",
-		       hdev->name, lmp_subver);
 		break;
 	}
 
+	if (i >= ARRAY_SIZE(ic_id_table)) {
+		BT_ERR("%s: unknown IC info, lmp subver %04x, hci rev %04x",
+		       hdev->name, lmp_subver, hci_rev);
+		return -EINVAL;
+	}
+
+	cfg_name = ic_id_table[i].cfg_name;
+
 	if (cfg_name) {
 		cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff);
 		if (cfg_sz < 0) {
 			cfg_sz = 0;
-			if (config_needed)
+			if (ic_id_table[i].config_needed)
 				BT_ERR("Necessary config file %s not found\n",
 				       cfg_name);
 		}
 	} else
 		cfg_sz = 0;
 
+	fw_name = ic_id_table[i].fw_name;
 	bt_dev_info(hdev, "rtl: loading %s", fw_name);
 	ret = request_firmware(&fw, fw_name, &hdev->dev);
 	if (ret < 0) {
@@ -370,7 +427,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
 		goto err_req_fw;
 	}
 
-	ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
+	ret = rtlbt_parse_firmware(hdev, lmp_subver, fw, &fw_data);
 	if (ret < 0)
 		goto out;
 
@@ -429,7 +486,7 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
 {
 	struct sk_buff *skb;
 	struct hci_rp_read_local_version *resp;
-	u16 lmp_subver;
+	u16 hci_rev, lmp_subver;
 
 	skb = btrtl_read_local_version(hdev);
 	if (IS_ERR(skb))
@@ -441,6 +498,7 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
 		    resp->hci_ver, resp->hci_rev,
 		    resp->lmp_ver, resp->lmp_subver);
 
+	hci_rev = le16_to_cpu(resp->hci_rev);
 	lmp_subver = le16_to_cpu(resp->lmp_subver);
 	kfree_skb(skb);
 
@@ -455,17 +513,10 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
 	case RTL_ROM_LMP_3499:
 		return btrtl_setup_rtl8723a(hdev);
 	case RTL_ROM_LMP_8723B:
-		return btrtl_setup_rtl8723b(hdev, lmp_subver,
-					    "rtl_bt/rtl8723b_fw.bin");
 	case RTL_ROM_LMP_8821A:
-		return btrtl_setup_rtl8723b(hdev, lmp_subver,
-					    "rtl_bt/rtl8821a_fw.bin");
 	case RTL_ROM_LMP_8761A:
-		return btrtl_setup_rtl8723b(hdev, lmp_subver,
-					    "rtl_bt/rtl8761a_fw.bin");
 	case RTL_ROM_LMP_8822B:
-		return btrtl_setup_rtl8723b(hdev, lmp_subver,
-					    "rtl_bt/rtl8822b_fw.bin");
+		return btrtl_setup_rtl8723b(hdev, hci_rev, lmp_subver);
 	default:
 		bt_dev_info(hdev, "rtl: assuming no firmware upload needed");
 		return 0;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 2a55380ad730..c8e9ae6b99e1 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -339,6 +339,7 @@ static const struct usb_device_id blacklist_table[] = {
 
 	/* Intel Bluetooth devices */
 	{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW },
+	{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW },
 	{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
 	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
 	{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
@@ -373,6 +374,9 @@ static const struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK },
 	{ USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },
 
+	/* Additional Realtek 8822BE Bluetooth devices */
+	{ USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },
+
 	/* Silicon Wave based devices */
 	{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
 
@@ -2057,6 +2061,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
 	case 0x0c:	/* WsP */
 	case 0x11:	/* JfP */
 	case 0x12:	/* ThP */
+	case 0x13:	/* HrP */
+	case 0x14:	/* QnJ, IcP */
 		break;
 	default:
 		BT_ERR("%s: Unsupported Intel hardware variant (%u)",
@@ -2149,6 +2155,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
 		break;
 	case 0x11:	/* JfP */
 	case 0x12:	/* ThP */
+	case 0x13:	/* HrP */
+	case 0x14:	/* QnJ, IcP */
 		snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi",
 			 le16_to_cpu(ver.hw_variant),
 			 le16_to_cpu(ver.hw_revision),
@@ -2180,6 +2188,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
 		break;
 	case 0x11:	/* JfP */
 	case 0x12:	/* ThP */
+	case 0x13:	/* HrP */
+	case 0x14:	/* QnJ, IcP */
 		snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc",
 			 le16_to_cpu(ver.hw_variant),
 			 le16_to_cpu(ver.hw_revision),
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 14ae7ee88acb..d568fbd94d6c 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -71,12 +71,12 @@ static int ath_wakeup_ar3k(struct tty_struct *tty)
 	/* Clear RTS first */
 	tty->driver->ops->tiocmget(tty);
 	tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS);
-	mdelay(20);
+	msleep(20);
 
 	/* Set RTS, wake up board */
 	tty->driver->ops->tiocmget(tty);
 	tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00);
-	mdelay(20);
+	msleep(20);
 
 	status = tty->driver->ops->tiocmget(tty);
 	return status;
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 1b4417a623a4..2f30dcad96bd 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -650,7 +650,7 @@ static int download_firmware(struct ll_device *lldev)
 			break;
 		case ACTION_DELAY:	/* sleep */
 			bt_dev_info(lldev->hu.hdev, "sleep command in scr");
-			mdelay(((struct bts_action_delay *)action_ptr)->msec);
+			msleep(((struct bts_action_delay *)action_ptr)->msec);
 			break;
 		}
 		len -= (sizeof(struct bts_action) +
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index 4d46003c46cf..cdaeeea7999c 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -630,7 +630,7 @@ static int sysc_init_dts_quirks(struct sysc *ddata)
 	for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
 		prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
 		if (!prop)
-			break;
+			continue;
 
 		ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
 	}
diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c
index eca87249bcff..250123bc4905 100644
--- a/drivers/char/hw_random/imx-rngc.c
+++ b/drivers/char/hw_random/imx-rngc.c
@@ -300,7 +300,7 @@ static int __maybe_unused imx_rngc_resume(struct device *dev)
 	return 0;
 }
 
-SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume);
+static SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume);
 
 static const struct of_device_id imx_rngc_dt_ids[] = {
 	{ .compatible = "fsl,imx25-rngb", .data = NULL, },
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index 3544abc0f9f9..3bda116c8aa0 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -96,6 +96,21 @@ config IPMI_POWEROFF
 
 endif # IPMI_HANDLER
 
+config IPMI_KCS_BMC
+	tristate
+
+config ASPEED_KCS_IPMI_BMC
+	depends on ARCH_ASPEED || COMPILE_TEST
+	select IPMI_KCS_BMC
+	select REGMAP_MMIO
+	tristate "Aspeed KCS IPMI BMC driver"
+	help
+	  Provides a driver for the KCS (Keyboard Controller Style) IPMI
+	  interface found on Aspeed SOCs (AST2400 and AST2500).
+
+	  The driver implements the BMC side of the KCS contorller, it
+	  provides the access of KCS IO space for BMC side.
+
 config ASPEED_BT_IPMI_BMC
 	depends on ARCH_ASPEED || COMPILE_TEST
        depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 33b899fcf14a..21e9e872d973 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -21,4 +21,6 @@ obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
 obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
 obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
 obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
+obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
 obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
+obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o
diff --git a/drivers/char/ipmi/kcs_bmc.c b/drivers/char/ipmi/kcs_bmc.c
new file mode 100644
index 000000000000..6476bfb79f44
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2018, Intel Corporation.
+
+#define pr_fmt(fmt) "kcs-bmc: " fmt
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ipmi_bmc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "kcs_bmc.h"
+
+#define KCS_MSG_BUFSIZ    1000
+
+#define KCS_ZERO_DATA     0
+
+
+/* IPMI 2.0 - Table 9-1, KCS Interface Status Register Bits */
+#define KCS_STATUS_STATE(state) (state << 6)
+#define KCS_STATUS_STATE_MASK   GENMASK(7, 6)
+#define KCS_STATUS_CMD_DAT      BIT(3)
+#define KCS_STATUS_SMS_ATN      BIT(2)
+#define KCS_STATUS_IBF          BIT(1)
+#define KCS_STATUS_OBF          BIT(0)
+
+/* IPMI 2.0 - Table 9-2, KCS Interface State Bits */
+enum kcs_states {
+	IDLE_STATE  = 0,
+	READ_STATE  = 1,
+	WRITE_STATE = 2,
+	ERROR_STATE = 3,
+};
+
+/* IPMI 2.0 - Table 9-3, KCS Interface Control Codes */
+#define KCS_CMD_GET_STATUS_ABORT  0x60
+#define KCS_CMD_WRITE_START       0x61
+#define KCS_CMD_WRITE_END         0x62
+#define KCS_CMD_READ_BYTE         0x68
+
+static inline u8 read_data(struct kcs_bmc *kcs_bmc)
+{
+	return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
+}
+
+static inline void write_data(struct kcs_bmc *kcs_bmc, u8 data)
+{
+	kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
+}
+
+static inline u8 read_status(struct kcs_bmc *kcs_bmc)
+{
+	return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
+}
+
+static inline void write_status(struct kcs_bmc *kcs_bmc, u8 data)
+{
+	kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
+}
+
+static void update_status_bits(struct kcs_bmc *kcs_bmc, u8 mask, u8 val)
+{
+	u8 tmp = read_status(kcs_bmc);
+
+	tmp &= ~mask;
+	tmp |= val & mask;
+
+	write_status(kcs_bmc, tmp);
+}
+
+static inline void set_state(struct kcs_bmc *kcs_bmc, u8 state)
+{
+	update_status_bits(kcs_bmc, KCS_STATUS_STATE_MASK,
+					KCS_STATUS_STATE(state));
+}
+
+static void kcs_force_abort(struct kcs_bmc *kcs_bmc)
+{
+	set_state(kcs_bmc, ERROR_STATE);
+	read_data(kcs_bmc);
+	write_data(kcs_bmc, KCS_ZERO_DATA);
+
+	kcs_bmc->phase = KCS_PHASE_ERROR;
+	kcs_bmc->data_in_avail = false;
+	kcs_bmc->data_in_idx = 0;
+}
+
+static void kcs_bmc_handle_data(struct kcs_bmc *kcs_bmc)
+{
+	u8 data;
+
+	switch (kcs_bmc->phase) {
+	case KCS_PHASE_WRITE_START:
+		kcs_bmc->phase = KCS_PHASE_WRITE_DATA;
+		/* fall through */
+
+	case KCS_PHASE_WRITE_DATA:
+		if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
+			set_state(kcs_bmc, WRITE_STATE);
+			write_data(kcs_bmc, KCS_ZERO_DATA);
+			kcs_bmc->data_in[kcs_bmc->data_in_idx++] =
+						read_data(kcs_bmc);
+		} else {
+			kcs_force_abort(kcs_bmc);
+			kcs_bmc->error = KCS_LENGTH_ERROR;
+		}
+		break;
+
+	case KCS_PHASE_WRITE_END_CMD:
+		if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
+			set_state(kcs_bmc, READ_STATE);
+			kcs_bmc->data_in[kcs_bmc->data_in_idx++] =
+						read_data(kcs_bmc);
+			kcs_bmc->phase = KCS_PHASE_WRITE_DONE;
+			kcs_bmc->data_in_avail = true;
+			wake_up_interruptible(&kcs_bmc->queue);
+		} else {
+			kcs_force_abort(kcs_bmc);
+			kcs_bmc->error = KCS_LENGTH_ERROR;
+		}
+		break;
+
+	case KCS_PHASE_READ:
+		if (kcs_bmc->data_out_idx == kcs_bmc->data_out_len)
+			set_state(kcs_bmc, IDLE_STATE);
+
+		data = read_data(kcs_bmc);
+		if (data != KCS_CMD_READ_BYTE) {
+			set_state(kcs_bmc, ERROR_STATE);
+			write_data(kcs_bmc, KCS_ZERO_DATA);
+			break;
+		}
+
+		if (kcs_bmc->data_out_idx == kcs_bmc->data_out_len) {
+			write_data(kcs_bmc, KCS_ZERO_DATA);
+			kcs_bmc->phase = KCS_PHASE_IDLE;
+			break;
+		}
+
+		write_data(kcs_bmc,
+			kcs_bmc->data_out[kcs_bmc->data_out_idx++]);
+		break;
+
+	case KCS_PHASE_ABORT_ERROR1:
+		set_state(kcs_bmc, READ_STATE);
+		read_data(kcs_bmc);
+		write_data(kcs_bmc, kcs_bmc->error);
+		kcs_bmc->phase = KCS_PHASE_ABORT_ERROR2;
+		break;
+
+	case KCS_PHASE_ABORT_ERROR2:
+		set_state(kcs_bmc, IDLE_STATE);
+		read_data(kcs_bmc);
+		write_data(kcs_bmc, KCS_ZERO_DATA);
+		kcs_bmc->phase = KCS_PHASE_IDLE;
+		break;
+
+	default:
+		kcs_force_abort(kcs_bmc);
+		break;
+	}
+}
+
+static void kcs_bmc_handle_cmd(struct kcs_bmc *kcs_bmc)
+{
+	u8 cmd;
+
+	set_state(kcs_bmc, WRITE_STATE);
+	write_data(kcs_bmc, KCS_ZERO_DATA);
+
+	cmd = read_data(kcs_bmc);
+	switch (cmd) {
+	case KCS_CMD_WRITE_START:
+		kcs_bmc->phase = KCS_PHASE_WRITE_START;
+		kcs_bmc->error = KCS_NO_ERROR;
+		kcs_bmc->data_in_avail = false;
+		kcs_bmc->data_in_idx = 0;
+		break;
+
+	case KCS_CMD_WRITE_END:
+		if (kcs_bmc->phase != KCS_PHASE_WRITE_DATA) {
+			kcs_force_abort(kcs_bmc);
+			break;
+		}
+
+		kcs_bmc->phase = KCS_PHASE_WRITE_END_CMD;
+		break;
+
+	case KCS_CMD_GET_STATUS_ABORT:
+		if (kcs_bmc->error == KCS_NO_ERROR)
+			kcs_bmc->error = KCS_ABORTED_BY_COMMAND;
+
+		kcs_bmc->phase = KCS_PHASE_ABORT_ERROR1;
+		kcs_bmc->data_in_avail = false;
+		kcs_bmc->data_in_idx = 0;
+		break;
+
+	default:
+		kcs_force_abort(kcs_bmc);
+		kcs_bmc->error = KCS_ILLEGAL_CONTROL_CODE;
+		break;
+	}
+}
+
+int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc)
+{
+	unsigned long flags;
+	int ret = 0;
+	u8 status;
+
+	spin_lock_irqsave(&kcs_bmc->lock, flags);
+
+	if (!kcs_bmc->running) {
+		kcs_force_abort(kcs_bmc);
+		ret = -ENODEV;
+		goto out_unlock;
+	}
+
+	status = read_status(kcs_bmc) & (KCS_STATUS_IBF | KCS_STATUS_CMD_DAT);
+
+	switch (status) {
+	case KCS_STATUS_IBF | KCS_STATUS_CMD_DAT:
+		kcs_bmc_handle_cmd(kcs_bmc);
+		break;
+
+	case KCS_STATUS_IBF:
+		kcs_bmc_handle_data(kcs_bmc);
+		break;
+
+	default:
+		ret = -ENODATA;
+		break;
+	}
+
+out_unlock:
+	spin_unlock_irqrestore(&kcs_bmc->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(kcs_bmc_handle_event);
+
+static inline struct kcs_bmc *file_to_kcs_bmc(struct file *filp)
+{
+	return container_of(filp->private_data, struct kcs_bmc, miscdev);
+}
+
+static int kcs_bmc_open(struct inode *inode, struct file *filp)
+{
+	struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
+	int ret = 0;
+
+	spin_lock_irq(&kcs_bmc->lock);
+	if (!kcs_bmc->running)
+		kcs_bmc->running = 1;
+	else
+		ret = -EBUSY;
+	spin_unlock_irq(&kcs_bmc->lock);
+
+	return ret;
+}
+
+static unsigned int kcs_bmc_poll(struct file *filp, poll_table *wait)
+{
+	struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
+	unsigned int mask = 0;
+
+	poll_wait(filp, &kcs_bmc->queue, wait);
+
+	spin_lock_irq(&kcs_bmc->lock);
+	if (kcs_bmc->data_in_avail)
+		mask |= POLLIN;
+	spin_unlock_irq(&kcs_bmc->lock);
+
+	return mask;
+}
+
+static ssize_t kcs_bmc_read(struct file *filp, char *buf,
+			    size_t count, loff_t *offset)
+{
+	struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
+	bool data_avail;
+	size_t data_len;
+	ssize_t ret;
+
+	if (!(filp->f_flags & O_NONBLOCK))
+		wait_event_interruptible(kcs_bmc->queue,
+					 kcs_bmc->data_in_avail);
+
+	mutex_lock(&kcs_bmc->mutex);
+
+	spin_lock_irq(&kcs_bmc->lock);
+	data_avail = kcs_bmc->data_in_avail;
+	if (data_avail) {
+		data_len = kcs_bmc->data_in_idx;
+		memcpy(kcs_bmc->kbuffer, kcs_bmc->data_in, data_len);
+	}
+	spin_unlock_irq(&kcs_bmc->lock);
+
+	if (!data_avail) {
+		ret = -EAGAIN;
+		goto out_unlock;
+	}
+
+	if (count < data_len) {
+		pr_err("channel=%u with too large data : %zu\n",
+			kcs_bmc->channel, data_len);
+
+		spin_lock_irq(&kcs_bmc->lock);
+		kcs_force_abort(kcs_bmc);
+		spin_unlock_irq(&kcs_bmc->lock);
+
+		ret = -EOVERFLOW;
+		goto out_unlock;
+	}
+
+	if (copy_to_user(buf, kcs_bmc->kbuffer, data_len)) {
+		ret = -EFAULT;
+		goto out_unlock;
+	}
+
+	ret = data_len;
+
+	spin_lock_irq(&kcs_bmc->lock);
+	if (kcs_bmc->phase == KCS_PHASE_WRITE_DONE) {
+		kcs_bmc->phase = KCS_PHASE_WAIT_READ;
+		kcs_bmc->data_in_avail = false;
+		kcs_bmc->data_in_idx = 0;
+	} else {
+		ret = -EAGAIN;
+	}
+	spin_unlock_irq(&kcs_bmc->lock);
+
+out_unlock:
+	mutex_unlock(&kcs_bmc->mutex);
+
+	return ret;
+}
+
+static ssize_t kcs_bmc_write(struct file *filp, const char *buf,
+			     size_t count, loff_t *offset)
+{
+	struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
+	ssize_t ret;
+
+	/* a minimum response size '3' : netfn + cmd + ccode */
+	if (count < 3 || count > KCS_MSG_BUFSIZ)
+		return -EINVAL;
+
+	mutex_lock(&kcs_bmc->mutex);
+
+	if (copy_from_user(kcs_bmc->kbuffer, buf, count)) {
+		ret = -EFAULT;
+		goto out_unlock;
+	}
+
+	spin_lock_irq(&kcs_bmc->lock);
+	if (kcs_bmc->phase == KCS_PHASE_WAIT_READ) {
+		kcs_bmc->phase = KCS_PHASE_READ;
+		kcs_bmc->data_out_idx = 1;
+		kcs_bmc->data_out_len = count;
+		memcpy(kcs_bmc->data_out, kcs_bmc->kbuffer, count);
+		write_data(kcs_bmc, kcs_bmc->data_out[0]);
+		ret = count;
+	} else {
+		ret = -EINVAL;
+	}
+	spin_unlock_irq(&kcs_bmc->lock);
+
+out_unlock:
+	mutex_unlock(&kcs_bmc->mutex);
+
+	return ret;
+}
+
+static long kcs_bmc_ioctl(struct file *filp, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
+	long ret = 0;
+
+	spin_lock_irq(&kcs_bmc->lock);
+
+	switch (cmd) {
+	case IPMI_BMC_IOCTL_SET_SMS_ATN:
+		update_status_bits(kcs_bmc, KCS_STATUS_SMS_ATN,
+				   KCS_STATUS_SMS_ATN);
+		break;
+
+	case IPMI_BMC_IOCTL_CLEAR_SMS_ATN:
+		update_status_bits(kcs_bmc, KCS_STATUS_SMS_ATN,
+				   0);
+		break;
+
+	case IPMI_BMC_IOCTL_FORCE_ABORT:
+		kcs_force_abort(kcs_bmc);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	spin_unlock_irq(&kcs_bmc->lock);
+
+	return ret;
+}
+
+static int kcs_bmc_release(struct inode *inode, struct file *filp)
+{
+	struct kcs_bmc *kcs_bmc = file_to_kcs_bmc(filp);
+
+	spin_lock_irq(&kcs_bmc->lock);
+	kcs_bmc->running = 0;
+	kcs_force_abort(kcs_bmc);
+	spin_unlock_irq(&kcs_bmc->lock);
+
+	return 0;
+}
+
+static const struct file_operations kcs_bmc_fops = {
+	.owner          = THIS_MODULE,
+	.open           = kcs_bmc_open,
+	.read           = kcs_bmc_read,
+	.write          = kcs_bmc_write,
+	.release        = kcs_bmc_release,
+	.poll           = kcs_bmc_poll,
+	.unlocked_ioctl = kcs_bmc_ioctl,
+};
+
+struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv, u32 channel)
+{
+	struct kcs_bmc *kcs_bmc;
+
+	kcs_bmc = devm_kzalloc(dev, sizeof(*kcs_bmc) + sizeof_priv, GFP_KERNEL);
+	if (!kcs_bmc)
+		return NULL;
+
+	dev_set_name(dev, "ipmi-kcs%u", channel);
+
+	spin_lock_init(&kcs_bmc->lock);
+	kcs_bmc->channel = channel;
+
+	mutex_init(&kcs_bmc->mutex);
+	init_waitqueue_head(&kcs_bmc->queue);
+
+	kcs_bmc->data_in = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+	kcs_bmc->data_out = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+	kcs_bmc->kbuffer = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+	if (!kcs_bmc->data_in || !kcs_bmc->data_out || !kcs_bmc->kbuffer)
+		return NULL;
+
+	kcs_bmc->miscdev.minor = MISC_DYNAMIC_MINOR;
+	kcs_bmc->miscdev.name = dev_name(dev);
+	kcs_bmc->miscdev.fops = &kcs_bmc_fops;
+
+	return kcs_bmc;
+}
+EXPORT_SYMBOL(kcs_bmc_alloc);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");
diff --git a/drivers/char/ipmi/kcs_bmc.h b/drivers/char/ipmi/kcs_bmc.h
new file mode 100644
index 000000000000..c19501db0236
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc.h
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2018, Intel Corporation.
+
+#ifndef __KCS_BMC_H__
+#define __KCS_BMC_H__
+
+#include <linux/miscdevice.h>
+
+/* Different phases of the KCS BMC module :
+ *  KCS_PHASE_IDLE :
+ *            BMC should not be expecting nor sending any data.
+ *  KCS_PHASE_WRITE_START :
+ *            BMC is receiving a WRITE_START command from system software.
+ *  KCS_PHASE_WRITE_DATA :
+ *            BMC is receiving a data byte from system software.
+ *  KCS_PHASE_WRITE_END_CMD :
+ *            BMC is waiting a last data byte from system software.
+ *  KCS_PHASE_WRITE_DONE :
+ *            BMC has received the whole request from system software.
+ *  KCS_PHASE_WAIT_READ :
+ *            BMC is waiting the response from the upper IPMI service.
+ *  KCS_PHASE_READ :
+ *            BMC is transferring the response to system software.
+ *  KCS_PHASE_ABORT_ERROR1 :
+ *            BMC is waiting error status request from system software.
+ *  KCS_PHASE_ABORT_ERROR2 :
+ *            BMC is waiting for idle status afer error from system software.
+ *  KCS_PHASE_ERROR :
+ *            BMC has detected a protocol violation at the interface level.
+ */
+enum kcs_phases {
+	KCS_PHASE_IDLE,
+
+	KCS_PHASE_WRITE_START,
+	KCS_PHASE_WRITE_DATA,
+	KCS_PHASE_WRITE_END_CMD,
+	KCS_PHASE_WRITE_DONE,
+
+	KCS_PHASE_WAIT_READ,
+	KCS_PHASE_READ,
+
+	KCS_PHASE_ABORT_ERROR1,
+	KCS_PHASE_ABORT_ERROR2,
+	KCS_PHASE_ERROR
+};
+
+/* IPMI 2.0 - Table 9-4, KCS Interface Status Codes */
+enum kcs_errors {
+	KCS_NO_ERROR                = 0x00,
+	KCS_ABORTED_BY_COMMAND      = 0x01,
+	KCS_ILLEGAL_CONTROL_CODE    = 0x02,
+	KCS_LENGTH_ERROR            = 0x06,
+	KCS_UNSPECIFIED_ERROR       = 0xFF
+};
+
+/* IPMI 2.0 - 9.5, KCS Interface Registers
+ * @idr : Input Data Register
+ * @odr : Output Data Register
+ * @str : Status Register
+ */
+struct kcs_ioreg {
+	u32 idr;
+	u32 odr;
+	u32 str;
+};
+
+struct kcs_bmc {
+	spinlock_t lock;
+
+	u32 channel;
+	int running;
+
+	/* Setup by BMC KCS controller driver */
+	struct kcs_ioreg ioreg;
+	u8 (*io_inputb)(struct kcs_bmc *kcs_bmc, u32 reg);
+	void (*io_outputb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 b);
+
+	enum kcs_phases phase;
+	enum kcs_errors error;
+
+	wait_queue_head_t queue;
+	bool data_in_avail;
+	int  data_in_idx;
+	u8  *data_in;
+
+	int  data_out_idx;
+	int  data_out_len;
+	u8  *data_out;
+
+	struct mutex mutex;
+	u8 *kbuffer;
+
+	struct miscdevice miscdev;
+
+	unsigned long priv[];
+};
+
+static inline void *kcs_bmc_priv(struct kcs_bmc *kcs_bmc)
+{
+	return kcs_bmc->priv;
+}
+
+int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc);
+struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv,
+					u32 channel);
+#endif
diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
new file mode 100644
index 000000000000..0c4d1a36dae4
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2018, Intel Corporation.
+
+#define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
+
+#include <linux/atomic.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include "kcs_bmc.h"
+
+
+#define DEVICE_NAME     "ast-kcs-bmc"
+
+#define KCS_CHANNEL_MAX     4
+
+/* mapped to lpc-bmc@0 IO space */
+#define LPC_HICR0            0x000
+#define     LPC_HICR0_LPC3E          BIT(7)
+#define     LPC_HICR0_LPC2E          BIT(6)
+#define     LPC_HICR0_LPC1E          BIT(5)
+#define LPC_HICR2            0x008
+#define     LPC_HICR2_IBFIF3         BIT(3)
+#define     LPC_HICR2_IBFIF2         BIT(2)
+#define     LPC_HICR2_IBFIF1         BIT(1)
+#define LPC_HICR4            0x010
+#define     LPC_HICR4_LADR12AS       BIT(7)
+#define     LPC_HICR4_KCSENBL        BIT(2)
+#define LPC_LADR3H           0x014
+#define LPC_LADR3L           0x018
+#define LPC_LADR12H          0x01C
+#define LPC_LADR12L          0x020
+#define LPC_IDR1             0x024
+#define LPC_IDR2             0x028
+#define LPC_IDR3             0x02C
+#define LPC_ODR1             0x030
+#define LPC_ODR2             0x034
+#define LPC_ODR3             0x038
+#define LPC_STR1             0x03C
+#define LPC_STR2             0x040
+#define LPC_STR3             0x044
+
+/* mapped to lpc-host@80 IO space */
+#define LPC_HICRB            0x080
+#define     LPC_HICRB_IBFIF4         BIT(1)
+#define     LPC_HICRB_LPC4E          BIT(0)
+#define LPC_LADR4            0x090
+#define LPC_IDR4             0x094
+#define LPC_ODR4             0x098
+#define LPC_STR4             0x09C
+
+struct aspeed_kcs_bmc {
+	struct regmap *map;
+};
+
+
+static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
+{
+	struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+	u32 val = 0;
+	int rc;
+
+	rc = regmap_read(priv->map, reg, &val);
+	WARN(rc != 0, "regmap_read() failed: %d\n", rc);
+
+	return rc == 0 ? (u8) val : 0;
+}
+
+static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
+{
+	struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+	int rc;
+
+	rc = regmap_write(priv->map, reg, data);
+	WARN(rc != 0, "regmap_write() failed: %d\n", rc);
+}
+
+
+/*
+ * AST_usrGuide_KCS.pdf
+ * 2. Background:
+ *   we note D for Data, and C for Cmd/Status, default rules are
+ *     A. KCS1 / KCS2 ( D / C:X / X+4 )
+ *        D / C : CA0h / CA4h
+ *        D / C : CA8h / CACh
+ *     B. KCS3 ( D / C:XX2h / XX3h )
+ *        D / C : CA2h / CA3h
+ *        D / C : CB2h / CB3h
+ *     C. KCS4
+ *        D / C : CA4h / CA5h
+ */
+static void aspeed_kcs_set_address(struct kcs_bmc *kcs_bmc, u16 addr)
+{
+	struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+
+	switch (kcs_bmc->channel) {
+	case 1:
+		regmap_update_bits(priv->map, LPC_HICR4,
+				LPC_HICR4_LADR12AS, 0);
+		regmap_write(priv->map, LPC_LADR12H, addr >> 8);
+		regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
+		break;
+
+	case 2:
+		regmap_update_bits(priv->map, LPC_HICR4,
+				LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
+		regmap_write(priv->map, LPC_LADR12H, addr >> 8);
+		regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
+		break;
+
+	case 3:
+		regmap_write(priv->map, LPC_LADR3H, addr >> 8);
+		regmap_write(priv->map, LPC_LADR3L, addr & 0xFF);
+		break;
+
+	case 4:
+		regmap_write(priv->map, LPC_LADR4, ((addr + 1) << 16) |
+			addr);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void aspeed_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
+{
+	struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+
+	switch (kcs_bmc->channel) {
+	case 1:
+		if (enable) {
+			regmap_update_bits(priv->map, LPC_HICR2,
+					LPC_HICR2_IBFIF1, LPC_HICR2_IBFIF1);
+			regmap_update_bits(priv->map, LPC_HICR0,
+					LPC_HICR0_LPC1E, LPC_HICR0_LPC1E);
+		} else {
+			regmap_update_bits(priv->map, LPC_HICR0,
+					LPC_HICR0_LPC1E, 0);
+			regmap_update_bits(priv->map, LPC_HICR2,
+					LPC_HICR2_IBFIF1, 0);
+		}
+		break;
+
+	case 2:
+		if (enable) {
+			regmap_update_bits(priv->map, LPC_HICR2,
+					LPC_HICR2_IBFIF2, LPC_HICR2_IBFIF2);
+			regmap_update_bits(priv->map, LPC_HICR0,
+					LPC_HICR0_LPC2E, LPC_HICR0_LPC2E);
+		} else {
+			regmap_update_bits(priv->map, LPC_HICR0,
+					LPC_HICR0_LPC2E, 0);
+			regmap_update_bits(priv->map, LPC_HICR2,
+					LPC_HICR2_IBFIF2, 0);
+		}
+		break;
+
+	case 3:
+		if (enable) {
+			regmap_update_bits(priv->map, LPC_HICR2,
+					LPC_HICR2_IBFIF3, LPC_HICR2_IBFIF3);
+			regmap_update_bits(priv->map, LPC_HICR0,
+					LPC_HICR0_LPC3E, LPC_HICR0_LPC3E);
+			regmap_update_bits(priv->map, LPC_HICR4,
+					LPC_HICR4_KCSENBL, LPC_HICR4_KCSENBL);
+		} else {
+			regmap_update_bits(priv->map, LPC_HICR0,
+					LPC_HICR0_LPC3E, 0);
+			regmap_update_bits(priv->map, LPC_HICR4,
+					LPC_HICR4_KCSENBL, 0);
+			regmap_update_bits(priv->map, LPC_HICR2,
+					LPC_HICR2_IBFIF3, 0);
+		}
+		break;
+
+	case 4:
+		if (enable)
+			regmap_update_bits(priv->map, LPC_HICRB,
+					LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
+					LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E);
+		else
+			regmap_update_bits(priv->map, LPC_HICRB,
+					LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
+					0);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
+{
+	struct kcs_bmc *kcs_bmc = arg;
+
+	if (!kcs_bmc_handle_event(kcs_bmc))
+		return IRQ_HANDLED;
+
+	return IRQ_NONE;
+}
+
+static int aspeed_kcs_config_irq(struct kcs_bmc *kcs_bmc,
+			struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	return devm_request_irq(dev, irq, aspeed_kcs_irq, IRQF_SHARED,
+				dev_name(dev), kcs_bmc);
+}
+
+static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
+	{ .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 },
+	{ .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 },
+	{ .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 },
+	{ .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
+};
+
+static int aspeed_kcs_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct aspeed_kcs_bmc *priv;
+	struct kcs_bmc *kcs_bmc;
+	u32 chan, addr;
+	int rc;
+
+	rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
+	if ((rc != 0) || (chan == 0 || chan > KCS_CHANNEL_MAX)) {
+		dev_err(dev, "no valid 'kcs_chan' configured\n");
+		return -ENODEV;
+	}
+
+	rc = of_property_read_u32(dev->of_node, "kcs_addr", &addr);
+	if (rc) {
+		dev_err(dev, "no valid 'kcs_addr' configured\n");
+		return -ENODEV;
+	}
+
+	kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
+	if (!kcs_bmc)
+		return -ENOMEM;
+
+	priv = kcs_bmc_priv(kcs_bmc);
+	priv->map = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(priv->map)) {
+		dev_err(dev, "Couldn't get regmap\n");
+		return -ENODEV;
+	}
+
+	kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
+	kcs_bmc->io_inputb = aspeed_kcs_inb;
+	kcs_bmc->io_outputb = aspeed_kcs_outb;
+
+	dev_set_drvdata(dev, kcs_bmc);
+
+	aspeed_kcs_set_address(kcs_bmc, addr);
+	aspeed_kcs_enable_channel(kcs_bmc, true);
+	rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
+	if (rc)
+		return rc;
+
+	rc = misc_register(&kcs_bmc->miscdev);
+	if (rc) {
+		dev_err(dev, "Unable to register device\n");
+		return rc;
+	}
+
+	pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
+		chan, addr,
+		kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
+
+	return 0;
+}
+
+static int aspeed_kcs_remove(struct platform_device *pdev)
+{
+	struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
+
+	misc_deregister(&kcs_bmc->miscdev);
+
+	return 0;
+}
+
+static const struct of_device_id ast_kcs_bmc_match[] = {
+	{ .compatible = "aspeed,ast2400-kcs-bmc" },
+	{ .compatible = "aspeed,ast2500-kcs-bmc" },
+	{ }
+};
+
+static struct platform_driver ast_kcs_bmc_driver = {
+	.driver = {
+		.name           = DEVICE_NAME,
+		.of_match_table = ast_kcs_bmc_match,
+	},
+	.probe = aspeed_kcs_probe,
+	.remove = aspeed_kcs_remove,
+};
+
+module_platform_driver(ast_kcs_bmc_driver);
+
+MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+MODULE_DESCRIPTION("Aspeed device interface to the KCS BMC device");
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 0c858d027bf3..57dc546628b5 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -809,89 +809,6 @@ static __poll_t rtc_poll(struct file *file, poll_table *wait)
 }
 #endif
 
-int rtc_register(rtc_task_t *task)
-{
-#ifndef RTC_IRQ
-	return -EIO;
-#else
-	if (task == NULL || task->func == NULL)
-		return -EINVAL;
-	spin_lock_irq(&rtc_lock);
-	if (rtc_status & RTC_IS_OPEN) {
-		spin_unlock_irq(&rtc_lock);
-		return -EBUSY;
-	}
-	spin_lock(&rtc_task_lock);
-	if (rtc_callback) {
-		spin_unlock(&rtc_task_lock);
-		spin_unlock_irq(&rtc_lock);
-		return -EBUSY;
-	}
-	rtc_status |= RTC_IS_OPEN;
-	rtc_callback = task;
-	spin_unlock(&rtc_task_lock);
-	spin_unlock_irq(&rtc_lock);
-	return 0;
-#endif
-}
-EXPORT_SYMBOL(rtc_register);
-
-int rtc_unregister(rtc_task_t *task)
-{
-#ifndef RTC_IRQ
-	return -EIO;
-#else
-	unsigned char tmp;
-
-	spin_lock_irq(&rtc_lock);
-	spin_lock(&rtc_task_lock);
-	if (rtc_callback != task) {
-		spin_unlock(&rtc_task_lock);
-		spin_unlock_irq(&rtc_lock);
-		return -ENXIO;
-	}
-	rtc_callback = NULL;
-
-	/* disable controls */
-	if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
-		tmp = CMOS_READ(RTC_CONTROL);
-		tmp &= ~RTC_PIE;
-		tmp &= ~RTC_AIE;
-		tmp &= ~RTC_UIE;
-		CMOS_WRITE(tmp, RTC_CONTROL);
-		CMOS_READ(RTC_INTR_FLAGS);
-	}
-	if (rtc_status & RTC_TIMER_ON) {
-		rtc_status &= ~RTC_TIMER_ON;
-		del_timer(&rtc_irq_timer);
-	}
-	rtc_status &= ~RTC_IS_OPEN;
-	spin_unlock(&rtc_task_lock);
-	spin_unlock_irq(&rtc_lock);
-	return 0;
-#endif
-}
-EXPORT_SYMBOL(rtc_unregister);
-
-int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
-{
-#ifndef RTC_IRQ
-	return -EIO;
-#else
-	unsigned long flags;
-	if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
-		return -EINVAL;
-	spin_lock_irqsave(&rtc_task_lock, flags);
-	if (rtc_callback != task) {
-		spin_unlock_irqrestore(&rtc_task_lock, flags);
-		return -ENXIO;
-	}
-	spin_unlock_irqrestore(&rtc_task_lock, flags);
-	return rtc_do_ioctl(cmd, arg, 1);
-#endif
-}
-EXPORT_SYMBOL(rtc_control);
-
 /*
  *	The various file operations we support.
  */
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 76df4fbcf089..9e80a953d693 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -1190,6 +1190,10 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
 			break;
 
 		recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
+		if (recd > num_bytes) {
+			total = -EFAULT;
+			break;
+		}
 
 		rlength = be32_to_cpu(tpm_cmd.header.out.length);
 		if (rlength < offsetof(struct tpm_getrandom_out, rng_data) +
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index c17e75348a99..a700f8f9ead7 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -683,6 +683,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
 	if (!rc) {
 		data_len = be16_to_cpup(
 			(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
+		if (data_len < MIN_KEY_SIZE ||  data_len > MAX_KEY_SIZE + 1) {
+			rc = -EFAULT;
+			goto out;
+		}
 
 		rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)
 					->header.out.length);
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
index b04f29774ee7..f680b421b6d5 100644
--- a/drivers/clk/rockchip/clk-rk3328.c
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -304,7 +304,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 	COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
 			RK3328_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
 			RK3328_CLKGATE_CON(7), 1, GFLAGS),
-	GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED,
+	GATE(0, "aclk_core_niu", "aclk_core", 0,
 			RK3328_CLKGATE_CON(13), 0, GFLAGS),
 	GATE(0, "aclk_gic400", "aclk_core", CLK_IGNORE_UNUSED,
 			RK3328_CLKGATE_CON(13), 1, GFLAGS),
@@ -318,7 +318,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 			RK3328_CLKGATE_CON(6), 6, GFLAGS),
 	GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", CLK_SET_RATE_PARENT,
 			RK3328_CLKGATE_CON(14), 0, GFLAGS),
-	GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", CLK_IGNORE_UNUSED,
+	GATE(0, "aclk_gpu_niu", "aclk_gpu_pre", 0,
 			RK3328_CLKGATE_CON(14), 1, GFLAGS),
 
 	/* PD_DDR */
@@ -513,9 +513,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 			RK3328_CLKGATE_CON(24), 0, GFLAGS),
 	GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", CLK_SET_RATE_PARENT,
 			RK3328_CLKGATE_CON(24), 1, GFLAGS),
-	GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+	GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", 0,
 			RK3328_CLKGATE_CON(24), 2, GFLAGS),
-	GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED,
+	GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", 0,
 			RK3328_CLKGATE_CON(24), 3, GFLAGS),
 
 	COMPOSITE(SCLK_VDEC_CABAC, "sclk_vdec_cabac", mux_4plls_p, 0,
@@ -535,9 +535,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 			RK3328_CLKGATE_CON(23), 0, GFLAGS),
 	GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", CLK_SET_RATE_PARENT,
 			RK3328_CLKGATE_CON(23), 1, GFLAGS),
-	GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED,
+	GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", 0,
 			RK3328_CLKGATE_CON(23), 2, GFLAGS),
-	GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED,
+	GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", 0,
 			RK3328_CLKGATE_CON(23), 3, GFLAGS),
 
 	COMPOSITE(ACLK_RKVENC, "aclk_rkvenc", mux_4plls_p, 0,
@@ -545,9 +545,9 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 			RK3328_CLKGATE_CON(6), 3, GFLAGS),
 	FACTOR_GATE(HCLK_RKVENC, "hclk_rkvenc", "aclk_rkvenc", 0, 1, 4,
 			RK3328_CLKGATE_CON(11), 4, GFLAGS),
-	GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", CLK_IGNORE_UNUSED,
+	GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc", 0,
 			RK3328_CLKGATE_CON(25), 0, GFLAGS),
-	GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", CLK_IGNORE_UNUSED,
+	GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc", 0,
 			RK3328_CLKGATE_CON(25), 1, GFLAGS),
 	GATE(ACLK_H265, "aclk_h265", "aclk_rkvenc", 0,
 			RK3328_CLKGATE_CON(25), 0, GFLAGS),
@@ -588,7 +588,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 	COMPOSITE(ACLK_VOP_PRE, "aclk_vop_pre", mux_4plls_p, 0,
 			RK3328_CLKSEL_CON(39), 6, 2, MFLAGS, 0, 5, DFLAGS,
 			RK3328_CLKGATE_CON(5), 5, GFLAGS),
-	GATE(0, "clk_hdmi_sfc", "xin24m", 0,
+	GATE(SCLK_HDMI_SFC, "sclk_hdmi_sfc", "xin24m", 0,
 			RK3328_CLKGATE_CON(5), 4, GFLAGS),
 
 	COMPOSITE_NODIV(0, "clk_cif_src", mux_2plls_p, 0,
@@ -602,7 +602,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 			RK3328_CLKGATE_CON(5), 6, GFLAGS),
 	DIV(DCLK_HDMIPHY, "dclk_hdmiphy", "dclk_lcdc_src", 0,
 			RK3328_CLKSEL_CON(40), 3, 3, DFLAGS),
-	MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p, 0,
+	MUX(DCLK_LCDC, "dclk_lcdc", mux_dclk_lcdc_p,  CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
 			RK3328_CLKSEL_CON(40), 1, 1, MFLAGS),
 
 	/*
@@ -709,14 +709,14 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 
 	/* PD_VOP */
 	GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(21), 10, GFLAGS),
-	GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 3, GFLAGS),
+	GATE(0, "aclk_rga_niu", "aclk_rga_pre", 0, RK3328_CLKGATE_CON(22), 3, GFLAGS),
 	GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 2, GFLAGS),
-	GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 4, GFLAGS),
+	GATE(0, "aclk_vop_niu", "aclk_vop_pre", 0, RK3328_CLKGATE_CON(21), 4, GFLAGS),
 
 	GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 6, GFLAGS),
 	GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 8, GFLAGS),
 	GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 15, GFLAGS),
-	GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(22), 2, GFLAGS),
+	GATE(0, "aclk_vio_niu", "aclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 2, GFLAGS),
 
 	GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 3, GFLAGS),
 	GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 5, GFLAGS),
@@ -724,10 +724,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 	GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 9, GFLAGS),
 	GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 11, GFLAGS),
 	GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 12, GFLAGS),
-	GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 13, GFLAGS),
-	GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(21), 14, GFLAGS),
+	GATE(0, "pclk_vio_h2p", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 13, GFLAGS),
+	GATE(0, "hclk_vio_h2p", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(21), 14, GFLAGS),
 	GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 0, GFLAGS),
-	GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS),
+	GATE(0, "hclk_vio_niu", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 1, GFLAGS),
 	GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 4, GFLAGS),
 	GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK3328_CLKGATE_CON(22), 5, GFLAGS),
 
@@ -743,19 +743,19 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 	GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 7, GFLAGS),
 	GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 8, GFLAGS),
 	GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 9, GFLAGS),
-	GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 12, GFLAGS),
-	GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(19), 13, GFLAGS),
+	GATE(0, "hclk_peri_niu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 12, GFLAGS),
+	GATE(0, "pclk_peri_niu", "hclk_peri", 0, RK3328_CLKGATE_CON(19), 13, GFLAGS),
 
 	/* PD_GMAC */
 	GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 0, GFLAGS),
 	GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 2, GFLAGS),
-	GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 4, GFLAGS),
+	GATE(0, "aclk_gmac_niu", "aclk_gmac", 0, RK3328_CLKGATE_CON(26), 4, GFLAGS),
 	GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 1, GFLAGS),
 	GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 3, GFLAGS),
-	GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(26), 5, GFLAGS),
+	GATE(0, "pclk_gmac_niu", "pclk_gmac", 0, RK3328_CLKGATE_CON(26), 5, GFLAGS),
 
 	/* PD_BUS */
-	GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 12, GFLAGS),
+	GATE(0, "aclk_bus_niu", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 12, GFLAGS),
 	GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 11, GFLAGS),
 	GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 12, GFLAGS),
 	GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 0, GFLAGS),
@@ -769,10 +769,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 	GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(17), 11, GFLAGS),
 	GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 7, GFLAGS),
 	GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 8, GFLAGS),
-	GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 13, GFLAGS),
+	GATE(0, "hclk_bus_niu", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(15), 13, GFLAGS),
 	GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, RK3328_CLKGATE_CON(28), 0, GFLAGS),
 
-	GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 14, GFLAGS),
+	GATE(0, "pclk_bus_niu", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 14, GFLAGS),
 	GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 9, GFLAGS),
 	GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(28), 4, GFLAGS),
 	GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3328_CLKGATE_CON(15), 10, GFLAGS),
@@ -807,7 +807,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 	GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 5, GFLAGS),
 	GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 7, GFLAGS),
 	GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(17), 8, GFLAGS),
-	GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK3328_CLKGATE_CON(15), 15, GFLAGS),
+	GATE(0, "pclk_phy_niu", "pclk_phy_pre", 0, RK3328_CLKGATE_CON(15), 15, GFLAGS),
 
 	/* PD_MMC */
 	MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc",
@@ -833,11 +833,16 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 
 static const char *const rk3328_critical_clocks[] __initconst = {
 	"aclk_bus",
+	"aclk_bus_niu",
 	"pclk_bus",
+	"pclk_bus_niu",
 	"hclk_bus",
+	"hclk_bus_niu",
 	"aclk_peri",
 	"hclk_peri",
+	"hclk_peri_niu",
 	"pclk_peri",
+	"pclk_peri_niu",
 	"pclk_dbg",
 	"aclk_core_niu",
 	"aclk_gic400",
@@ -861,6 +866,20 @@ static const char *const rk3328_critical_clocks[] __initconst = {
 	"aclk_rga_niu",
 	"pclk_vio_h2p",
 	"hclk_vio_h2p",
+	"aclk_vio_niu",
+	"hclk_vio_niu",
+	"aclk_vop_niu",
+	"hclk_vop_niu",
+	"aclk_gpu_niu",
+	"aclk_rkvdec_niu",
+	"hclk_rkvdec_niu",
+	"aclk_vpu_niu",
+	"hclk_vpu_niu",
+	"aclk_rkvenc_niu",
+	"hclk_rkvenc_niu",
+	"aclk_gmac_niu",
+	"pclk_gmac_niu",
+	"pclk_phy_niu",
 };
 
 static void __init rk3328_clk_init(struct device_node *np)
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index 5bfc92ee3129..b4b057c7301c 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -143,10 +143,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	reg_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(reg_base)) {
-		dev_err(dev, "failed to map audss registers\n");
+	if (IS_ERR(reg_base))
 		return PTR_ERR(reg_base);
-	}
 
 	epll = ERR_PTR(-ENODEV);
 
diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index db270908037a..57a41824ee2e 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -765,6 +765,7 @@ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initcons
 	PLL_36XX_RATE(294912000U,  98, 1, 3,  19923),
 	PLL_36XX_RATE(288000000U,  96, 1, 3,      0),
 	PLL_36XX_RATE(252000000U,  84, 1, 3,      0),
+	PLL_36XX_RATE(196608001U, 197, 3, 3, -25690),
 	{ /* sentinel */ }
 };
 
@@ -1672,7 +1673,7 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = {
 			ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk",
 			"ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10,
-			CLK_SET_RATE_PARENT, 0),
+			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
 	GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric",
 			ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric",
@@ -5513,10 +5514,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	reg_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(reg_base)) {
-		dev_err(dev, "failed to map registers\n");
+	if (IS_ERR(reg_base))
 		return PTR_ERR(reg_base);
-	}
 
 	for (i = 0; i < info->nr_clk_ids; ++i)
 		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
index b8340a49921b..1555e407529e 100644
--- a/drivers/clk/samsung/clk-s3c2412.c
+++ b/drivers/clk/samsung/clk-s3c2412.c
@@ -27,11 +27,6 @@
 #define CLKSRC		0x1c
 #define SWRST		0x30
 
-/* list of PLLs to be registered */
-enum s3c2412_plls {
-	mpll, upll,
-};
-
 static void __iomem *reg_base;
 
 #ifdef CONFIG_PM_SLEEP
@@ -144,10 +139,8 @@ struct samsung_mux_clock s3c2412_muxes[] __initdata = {
 };
 
 static struct samsung_pll_clock s3c2412_plls[] __initdata = {
-	[mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti",
-						LOCKTIME, MPLLCON, NULL),
-	[upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk",
-						LOCKTIME, UPLLCON, NULL),
+	PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", LOCKTIME, MPLLCON, NULL),
+	PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", LOCKTIME, UPLLCON, NULL),
 };
 
 struct samsung_gate_clock s3c2412_gates[] __initdata = {
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
index d94b85a42356..9580a6baf4d7 100644
--- a/drivers/clk/samsung/clk-s3c2443.c
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -41,11 +41,6 @@ enum supported_socs {
 	S3C2450,
 };
 
-/* list of PLLs to be registered */
-enum s3c2443_plls {
-	mpll, epll,
-};
-
 static void __iomem *reg_base;
 
 #ifdef CONFIG_PM_SLEEP
@@ -225,10 +220,8 @@ struct samsung_clock_alias s3c2443_common_aliases[] __initdata = {
 /* S3C2416 specific clocks */
 
 static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = {
-	[mpll] = PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref",
-						LOCKCON0, MPLLCON, NULL),
-	[epll] = PLL(pll_6553, EPLL, "epll", "epllref",
-						LOCKCON1, EPLLCON, NULL),
+	PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL),
+	PLL(pll_6553, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL),
 };
 
 PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" };
@@ -279,10 +272,8 @@ struct samsung_clock_alias s3c2416_aliases[] __initdata = {
 /* S3C2443 specific clocks */
 
 static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = {
-	[mpll] = PLL(pll_3000, MPLL, "mpll", "mpllref",
-						LOCKCON0, MPLLCON, NULL),
-	[epll] = PLL(pll_2126, EPLL, "epll", "epllref",
-						LOCKCON1, EPLLCON, NULL),
+	PLL(pll_3000, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL),
+	PLL(pll_2126, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL),
 };
 
 static struct clk_div_table armdiv_s3c2443_d[] = {
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 7306867a0ab8..6db01cf5ab83 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -56,11 +56,6 @@
 #define GATE_ON(_id, cname, pname, o, b) \
 		GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0)
 
-/* list of PLLs to be registered */
-enum s3c64xx_plls {
-	apll, mpll, epll,
-};
-
 static void __iomem *reg_base;
 static bool is_s3c6400;
 
@@ -364,12 +359,12 @@ GATE_CLOCKS(s3c6410_gate_clks) __initdata = {
 
 /* List of PLL clocks. */
 static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = {
-	[apll] = PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll",
-						APLL_LOCK, APLL_CON, NULL),
-	[mpll] = PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll",
-						MPLL_LOCK, MPLL_CON, NULL),
-	[epll] = PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll",
-						EPLL_LOCK, EPLL_CON0, NULL),
+	PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll",
+					APLL_LOCK, APLL_CON, NULL),
+	PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll",
+					MPLL_LOCK, MPLL_CON, NULL),
+	PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll",
+					EPLL_LOCK, EPLL_CON0, NULL),
 };
 
 /* Aliases for common s3c64xx clocks. */
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 6427d0ebe2de..33168f94ee39 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -13,13 +13,6 @@ config SUN50I_A64_CCU
 
 config SUN4I_A10_CCU
 	bool "Support for the Allwinner A10/A20 CCU"
-	select SUNXI_CCU_DIV
-	select SUNXI_CCU_MULT
-	select SUNXI_CCU_NK
-	select SUNXI_CCU_NKM
-	select SUNXI_CCU_NM
-	select SUNXI_CCU_MP
-	select SUNXI_CCU_PHASE
 	default MACH_SUN4I
 	default MACH_SUN7I
 	depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
index 72b16ed1012b..3b97f60540ad 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
@@ -762,7 +762,7 @@ static struct ccu_mp out_a_clk = {
 		.features	= CCU_FEATURE_FIXED_PREDIV,
 		.hw.init	= CLK_HW_INIT_PARENTS("out-a",
 						      clk_out_parents,
-						      &ccu_div_ops,
+						      &ccu_mp_ops,
 						      0),
 	},
 };
@@ -783,7 +783,7 @@ static struct ccu_mp out_b_clk = {
 		.features	= CCU_FEATURE_FIXED_PREDIV,
 		.hw.init	= CLK_HW_INIT_PARENTS("out-b",
 						      clk_out_parents,
-						      &ccu_div_ops,
+						      &ccu_mp_ops,
 						      0),
 	},
 };
@@ -804,7 +804,7 @@ static struct ccu_mp out_c_clk = {
 		.features	= CCU_FEATURE_FIXED_PREDIV,
 		.hw.init	= CLK_HW_INIT_PARENTS("out-c",
 						      clk_out_parents,
-						      &ccu_div_ops,
+						      &ccu_mp_ops,
 						      0),
 	},
 };
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
index e58c95787f94..c3f6fe7be565 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -20,6 +20,18 @@ struct _ccu_nkmp {
 	unsigned long	p, min_p, max_p;
 };
 
+static unsigned long ccu_nkmp_calc_rate(unsigned long parent,
+					unsigned long n, unsigned long k,
+					unsigned long m, unsigned long p)
+{
+	u64 rate = parent;
+
+	rate *= n * k;
+	do_div(rate, m * p);
+
+	return rate;
+}
+
 static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
 			       struct _ccu_nkmp *nkmp)
 {
@@ -33,7 +45,9 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
 				for (_p = nkmp->min_p; _p <= nkmp->max_p; _p <<= 1) {
 					unsigned long tmp_rate;
 
-					tmp_rate = parent * _n * _k / (_m * _p);
+					tmp_rate = ccu_nkmp_calc_rate(parent,
+								      _n, _k,
+								      _m, _p);
 
 					if (tmp_rate > rate)
 						continue;
@@ -107,7 +121,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
 	p = reg >> nkmp->p.shift;
 	p &= (1 << nkmp->p.width) - 1;
 
-	return (parent_rate * n * k >> p) / m;
+	return ccu_nkmp_calc_rate(parent_rate, n, k, m, 1 << p);
 }
 
 static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -127,13 +141,15 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
 
 	ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
 
-	return *parent_rate * _nkmp.n * _nkmp.k / (_nkmp.m * _nkmp.p);
+	return ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k,
+				  _nkmp.m, _nkmp.p);
 }
 
 static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
 			   unsigned long parent_rate)
 {
 	struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
+	u32 n_mask, k_mask, m_mask, p_mask;
 	struct _ccu_nkmp _nkmp;
 	unsigned long flags;
 	u32 reg;
@@ -149,18 +165,20 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
 
 	ccu_nkmp_find_best(parent_rate, rate, &_nkmp);
 
+	n_mask = GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift);
+	k_mask = GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
+	m_mask = GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
+	p_mask = GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
+
 	spin_lock_irqsave(nkmp->common.lock, flags);
 
 	reg = readl(nkmp->common.base + nkmp->common.reg);
-	reg &= ~GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift);
-	reg &= ~GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
-	reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
-	reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
-
-	reg |= (_nkmp.n - nkmp->n.offset) << nkmp->n.shift;
-	reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift;
-	reg |= (_nkmp.m - nkmp->m.offset) << nkmp->m.shift;
-	reg |= ilog2(_nkmp.p) << nkmp->p.shift;
+	reg &= ~(n_mask | k_mask | m_mask | p_mask);
+
+	reg |= ((_nkmp.n - nkmp->n.offset) << nkmp->n.shift) & n_mask;
+	reg |= ((_nkmp.k - nkmp->k.offset) << nkmp->k.shift) & k_mask;
+	reg |= ((_nkmp.m - nkmp->m.offset) << nkmp->m.shift) & m_mask;
+	reg |= (ilog2(_nkmp.p) << nkmp->p.shift) & p_mask;
 
 	writel(reg, nkmp->common.base + nkmp->common.reg);
 
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 4b741b83e23f..b26e5d2b99a4 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -730,4 +730,31 @@ config CRYPTO_DEV_ARTPEC6
 
 	  To compile this driver as a module, choose M here.
 
+config CRYPTO_DEV_CCREE
+	tristate "Support for ARM TrustZone CryptoCell family of security processors"
+	depends on CRYPTO && CRYPTO_HW && OF && HAS_DMA
+	default n
+	select CRYPTO_HASH
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_DES
+	select CRYPTO_AEAD
+	select CRYPTO_AUTHENC
+	select CRYPTO_SHA1
+	select CRYPTO_MD5
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	select CRYPTO_HMAC
+	select CRYPTO_AES
+	select CRYPTO_CBC
+	select CRYPTO_ECB
+	select CRYPTO_CTR
+	select CRYPTO_XTS
+	help
+	  Say 'Y' to enable a driver for the Arm TrustZone CryptoCell
+	  family of processors. Currently only the CryptoCell 712 REE
+	  is supported.
+	  Choose this if you wish to use hardware acceleration of
+	  cryptographic operations on the system REE.
+	  If unsure say Y.
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 2513d13ea2c4..ee5ec5c94383 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o
 obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
 obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/
 obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
+obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
 obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/
 obj-$(CONFIG_CRYPTO_DEV_CPT) += cavium/cpt/
 obj-$(CONFIG_CRYPTO_DEV_NITROX) += cavium/nitrox/
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index bfbf8bf77f03..5ece3240531e 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -450,6 +450,16 @@ static int bfin_crypto_crc_digest(struct ahash_request *req)
 	return bfin_crypto_crc_finup(req);
 }
 
+static int bfin_crypto_crc_noimport(struct ahash_request *req, const void *in)
+{
+	return -ENOSYS;
+}
+
+static int bfin_crypto_crc_noexport(struct ahash_request *req, void *out)
+{
+	return -ENOSYS;
+}
+
 static int bfin_crypto_crc_setkey(struct crypto_ahash *tfm, const u8 *key,
 			unsigned int keylen)
 {
@@ -487,6 +497,8 @@ static struct ahash_alg algs = {
 	.final		= bfin_crypto_crc_final,
 	.finup		= bfin_crypto_crc_finup,
 	.digest		= bfin_crypto_crc_digest,
+	.export		= bfin_crypto_crc_noexport,
+	.import		= bfin_crypto_crc_noimport,
 	.setkey		= bfin_crypto_crc_setkey,
 	.halg.digestsize	= CHKSUM_DIGEST_SIZE,
 	.halg.base	= {
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 2188235be02d..584a6c183548 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -328,6 +328,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
 {
 	struct caam_ctx *ctx = crypto_aead_ctx(aead);
 	struct device *jrdev = ctx->jrdev;
+	unsigned int ivsize = crypto_aead_ivsize(aead);
 	u32 *desc;
 	int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
 			ctx->cdata.keylen;
@@ -349,7 +350,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
 	}
 
 	desc = ctx->sh_desc_enc;
-	cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ctx->authsize);
+	cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, false);
 	dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
 				   desc_bytes(desc), ctx->dir);
 
@@ -366,7 +367,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
 	}
 
 	desc = ctx->sh_desc_dec;
-	cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ctx->authsize);
+	cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, false);
 	dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
 				   desc_bytes(desc), ctx->dir);
 
@@ -387,6 +388,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
 {
 	struct caam_ctx *ctx = crypto_aead_ctx(aead);
 	struct device *jrdev = ctx->jrdev;
+	unsigned int ivsize = crypto_aead_ivsize(aead);
 	u32 *desc;
 	int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
 			ctx->cdata.keylen;
@@ -408,7 +410,8 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
 	}
 
 	desc = ctx->sh_desc_enc;
-	cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ctx->authsize);
+	cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
+				  false);
 	dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
 				   desc_bytes(desc), ctx->dir);
 
@@ -425,7 +428,8 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
 	}
 
 	desc = ctx->sh_desc_dec;
-	cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ctx->authsize);
+	cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
+				  false);
 	dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
 				   desc_bytes(desc), ctx->dir);
 
@@ -447,6 +451,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
 {
 	struct caam_ctx *ctx = crypto_aead_ctx(aead);
 	struct device *jrdev = ctx->jrdev;
+	unsigned int ivsize = crypto_aead_ivsize(aead);
 	u32 *desc;
 	int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
 			ctx->cdata.keylen;
@@ -468,7 +473,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
 	}
 
 	desc = ctx->sh_desc_enc;
-	cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ctx->authsize);
+	cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
+				  false);
 	dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
 				   desc_bytes(desc), ctx->dir);
 
@@ -485,7 +491,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
 	}
 
 	desc = ctx->sh_desc_dec;
-	cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ctx->authsize);
+	cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
+				  false);
 	dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
 				   desc_bytes(desc), ctx->dir);
 
diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c
index ceb93fbb76e6..8ae7a1be7dfd 100644
--- a/drivers/crypto/caam/caamalg_desc.c
+++ b/drivers/crypto/caam/caamalg_desc.c
@@ -625,10 +625,13 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_givencap);
  * @desc: pointer to buffer used for descriptor construction
  * @cdata: pointer to block cipher transform definitions
  *         Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
  */
 void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
-			   unsigned int icvsize)
+			   unsigned int ivsize, unsigned int icvsize,
+			   const bool is_qi)
 {
 	u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1,
 	    *zero_assoc_jump_cmd2;
@@ -650,11 +653,35 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
 	append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
 			 OP_ALG_ENCRYPT);
 
+	if (is_qi) {
+		u32 *wait_load_cmd;
+
+		/* REG3 = assoclen */
+		append_seq_load(desc, 4, LDST_CLASS_DECO |
+				LDST_SRCDST_WORD_DECO_MATH3 |
+				(4 << LDST_OFFSET_SHIFT));
+
+		wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+					    JUMP_COND_CALM | JUMP_COND_NCP |
+					    JUMP_COND_NOP | JUMP_COND_NIP |
+					    JUMP_COND_NIFP);
+		set_jump_tgt_here(desc, wait_load_cmd);
+
+		append_math_sub_imm_u32(desc, VARSEQOUTLEN, SEQINLEN, IMM,
+					ivsize);
+	} else {
+		append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0,
+				CAAM_CMD_SZ);
+	}
+
 	/* if assoclen + cryptlen is ZERO, skip to ICV write */
-	append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
 	zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL |
 						 JUMP_COND_MATH_Z);
 
+	if (is_qi)
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+
 	/* if assoclen is ZERO, skip reading the assoc data */
 	append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
 	zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
@@ -686,8 +713,11 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
 	append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
 			     FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1);
 
-	/* jump the zero-payload commands */
-	append_jump(desc, JUMP_TEST_ALL | 2);
+	/* jump to ICV writing */
+	if (is_qi)
+		append_jump(desc, JUMP_TEST_ALL | 4);
+	else
+		append_jump(desc, JUMP_TEST_ALL | 2);
 
 	/* zero-payload commands */
 	set_jump_tgt_here(desc, zero_payload_jump_cmd);
@@ -695,10 +725,18 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
 	/* read assoc data */
 	append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
 			     FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1);
+	if (is_qi)
+		/* jump to ICV writing */
+		append_jump(desc, JUMP_TEST_ALL | 2);
 
 	/* There is no input data */
 	set_jump_tgt_here(desc, zero_assoc_jump_cmd2);
 
+	if (is_qi)
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 |
+				     FIFOLD_TYPE_LAST1);
+
 	/* write ICV */
 	append_seq_store(desc, icvsize, LDST_CLASS_1_CCB |
 			 LDST_SRCDST_BYTE_CONTEXT);
@@ -715,10 +753,13 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_encap);
  * @desc: pointer to buffer used for descriptor construction
  * @cdata: pointer to block cipher transform definitions
  *         Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
  */
 void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
-			   unsigned int icvsize)
+			   unsigned int ivsize, unsigned int icvsize,
+			   const bool is_qi)
 {
 	u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1;
 
@@ -739,6 +780,24 @@ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
 	append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
 			 OP_ALG_DECRYPT | OP_ALG_ICV_ON);
 
+	if (is_qi) {
+		u32 *wait_load_cmd;
+
+		/* REG3 = assoclen */
+		append_seq_load(desc, 4, LDST_CLASS_DECO |
+				LDST_SRCDST_WORD_DECO_MATH3 |
+				(4 << LDST_OFFSET_SHIFT));
+
+		wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+					    JUMP_COND_CALM | JUMP_COND_NCP |
+					    JUMP_COND_NOP | JUMP_COND_NIP |
+					    JUMP_COND_NIFP);
+		set_jump_tgt_here(desc, wait_load_cmd);
+
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+	}
+
 	/* if assoclen is ZERO, skip reading the assoc data */
 	append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
 	zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
@@ -791,10 +850,13 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_decap);
  * @desc: pointer to buffer used for descriptor construction
  * @cdata: pointer to block cipher transform definitions
  *         Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
  */
 void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize)
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi)
 {
 	u32 *key_jump_cmd;
 
@@ -815,7 +877,29 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
 	append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
 			 OP_ALG_ENCRYPT);
 
-	append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8);
+	if (is_qi) {
+		u32 *wait_load_cmd;
+
+		/* REG3 = assoclen */
+		append_seq_load(desc, 4, LDST_CLASS_DECO |
+				LDST_SRCDST_WORD_DECO_MATH3 |
+				(4 << LDST_OFFSET_SHIFT));
+
+		wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+					    JUMP_COND_CALM | JUMP_COND_NCP |
+					    JUMP_COND_NOP | JUMP_COND_NIP |
+					    JUMP_COND_NIFP);
+		set_jump_tgt_here(desc, wait_load_cmd);
+
+		/* Read salt and IV */
+		append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+					cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+					FIFOLD_TYPE_IV);
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+	}
+
+	append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize);
 	append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
 
 	/* Read assoc data */
@@ -823,7 +907,7 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
 			     FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
 
 	/* Skip IV */
-	append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
+	append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP);
 
 	/* Will read cryptlen bytes */
 	append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
@@ -862,10 +946,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap);
  * @desc: pointer to buffer used for descriptor construction
  * @cdata: pointer to block cipher transform definitions
  *         Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
  */
 void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize)
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi)
 {
 	u32 *key_jump_cmd;
 
@@ -887,7 +974,29 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
 	append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
 			 OP_ALG_DECRYPT | OP_ALG_ICV_ON);
 
-	append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8);
+	if (is_qi) {
+		u32 *wait_load_cmd;
+
+		/* REG3 = assoclen */
+		append_seq_load(desc, 4, LDST_CLASS_DECO |
+				LDST_SRCDST_WORD_DECO_MATH3 |
+				(4 << LDST_OFFSET_SHIFT));
+
+		wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+					    JUMP_COND_CALM | JUMP_COND_NCP |
+					    JUMP_COND_NOP | JUMP_COND_NIP |
+					    JUMP_COND_NIFP);
+		set_jump_tgt_here(desc, wait_load_cmd);
+
+		/* Read salt and IV */
+		append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+					cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+					FIFOLD_TYPE_IV);
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+	}
+
+	append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize);
 	append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
 
 	/* Read assoc data */
@@ -895,7 +1004,7 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
 			     FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
 
 	/* Skip IV */
-	append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
+	append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP);
 
 	/* Will read cryptlen bytes */
 	append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ);
@@ -934,10 +1043,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap);
  * @desc: pointer to buffer used for descriptor construction
  * @cdata: pointer to block cipher transform definitions
  *         Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
  */
 void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize)
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi)
 {
 	u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
 
@@ -958,6 +1070,18 @@ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
 	append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
 			 OP_ALG_ENCRYPT);
 
+	if (is_qi) {
+		/* assoclen is not needed, skip it */
+		append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP);
+
+		/* Read salt and IV */
+		append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+					cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+					FIFOLD_TYPE_IV);
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+	}
+
 	/* assoclen + cryptlen = seqinlen */
 	append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ);
 
@@ -1004,10 +1128,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap);
  * @desc: pointer to buffer used for descriptor construction
  * @cdata: pointer to block cipher transform definitions
  *         Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
  * @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
  */
 void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize)
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi)
 {
 	u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
 
@@ -1028,6 +1155,18 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
 	append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
 			 OP_ALG_DECRYPT | OP_ALG_ICV_ON);
 
+	if (is_qi) {
+		/* assoclen is not needed, skip it */
+		append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP);
+
+		/* Read salt and IV */
+		append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+					cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+					FIFOLD_TYPE_IV);
+		append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+				     FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+	}
+
 	/* assoclen + cryptlen = seqoutlen */
 	append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ);
 
diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h
index 5f9445ae2114..a917af5776ce 100644
--- a/drivers/crypto/caam/caamalg_desc.h
+++ b/drivers/crypto/caam/caamalg_desc.h
@@ -27,14 +27,20 @@
 #define DESC_GCM_BASE			(3 * CAAM_CMD_SZ)
 #define DESC_GCM_ENC_LEN		(DESC_GCM_BASE + 16 * CAAM_CMD_SZ)
 #define DESC_GCM_DEC_LEN		(DESC_GCM_BASE + 12 * CAAM_CMD_SZ)
+#define DESC_QI_GCM_ENC_LEN		(DESC_GCM_ENC_LEN + 6 * CAAM_CMD_SZ)
+#define DESC_QI_GCM_DEC_LEN		(DESC_GCM_DEC_LEN + 3 * CAAM_CMD_SZ)
 
 #define DESC_RFC4106_BASE		(3 * CAAM_CMD_SZ)
 #define DESC_RFC4106_ENC_LEN		(DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ)
 #define DESC_RFC4106_DEC_LEN		(DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4106_ENC_LEN		(DESC_RFC4106_ENC_LEN + 5 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4106_DEC_LEN		(DESC_RFC4106_DEC_LEN + 5 * CAAM_CMD_SZ)
 
 #define DESC_RFC4543_BASE		(3 * CAAM_CMD_SZ)
 #define DESC_RFC4543_ENC_LEN		(DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ)
 #define DESC_RFC4543_DEC_LEN		(DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4543_ENC_LEN		(DESC_RFC4543_ENC_LEN + 4 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4543_DEC_LEN		(DESC_RFC4543_DEC_LEN + 4 * CAAM_CMD_SZ)
 
 #define DESC_ABLKCIPHER_BASE		(3 * CAAM_CMD_SZ)
 #define DESC_ABLKCIPHER_ENC_LEN		(DESC_ABLKCIPHER_BASE + \
@@ -67,22 +73,28 @@ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata,
 			       const bool is_qi, int era);
 
 void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
-			   unsigned int icvsize);
+			   unsigned int ivsize, unsigned int icvsize,
+			   const bool is_qi);
 
 void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
-			   unsigned int icvsize);
+			   unsigned int ivsize, unsigned int icvsize,
+			   const bool is_qi);
 
 void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize);
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi);
 
 void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize);
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi);
 
 void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize);
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi);
 
 void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
-			       unsigned int icvsize);
+			       unsigned int ivsize, unsigned int icvsize,
+			       const bool is_qi);
 
 void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata,
 				  unsigned int ivsize, const bool is_rfc3686,
diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c
index 4aecc9435f69..c2b5762d56a0 100644
--- a/drivers/crypto/caam/caamalg_qi.c
+++ b/drivers/crypto/caam/caamalg_qi.c
@@ -284,6 +284,309 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key,
 	return -EINVAL;
 }
 
+static int gcm_set_sh_desc(struct crypto_aead *aead)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(aead);
+	unsigned int ivsize = crypto_aead_ivsize(aead);
+	int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+			ctx->cdata.keylen;
+
+	if (!ctx->cdata.keylen || !ctx->authsize)
+		return 0;
+
+	/*
+	 * Job Descriptor and Shared Descriptor
+	 * must fit into the 64-word Descriptor h/w Buffer
+	 */
+	if (rem_bytes >= DESC_QI_GCM_ENC_LEN) {
+		ctx->cdata.key_inline = true;
+		ctx->cdata.key_virt = ctx->key;
+	} else {
+		ctx->cdata.key_inline = false;
+		ctx->cdata.key_dma = ctx->key_dma;
+	}
+
+	cnstr_shdsc_gcm_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+			      ctx->authsize, true);
+
+	/*
+	 * Job Descriptor and Shared Descriptor
+	 * must fit into the 64-word Descriptor h/w Buffer
+	 */
+	if (rem_bytes >= DESC_QI_GCM_DEC_LEN) {
+		ctx->cdata.key_inline = true;
+		ctx->cdata.key_virt = ctx->key;
+	} else {
+		ctx->cdata.key_inline = false;
+		ctx->cdata.key_dma = ctx->key_dma;
+	}
+
+	cnstr_shdsc_gcm_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+			      ctx->authsize, true);
+
+	return 0;
+}
+
+static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+	ctx->authsize = authsize;
+	gcm_set_sh_desc(authenc);
+
+	return 0;
+}
+
+static int gcm_setkey(struct crypto_aead *aead,
+		      const u8 *key, unsigned int keylen)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(aead);
+	struct device *jrdev = ctx->jrdev;
+	int ret;
+
+#ifdef DEBUG
+	print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
+		       DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+
+	memcpy(ctx->key, key, keylen);
+	dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir);
+	ctx->cdata.keylen = keylen;
+
+	ret = gcm_set_sh_desc(aead);
+	if (ret)
+		return ret;
+
+	/* Now update the driver contexts with the new shared descriptor */
+	if (ctx->drv_ctx[ENCRYPT]) {
+		ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
+					  ctx->sh_desc_enc);
+		if (ret) {
+			dev_err(jrdev, "driver enc context update failed\n");
+			return ret;
+		}
+	}
+
+	if (ctx->drv_ctx[DECRYPT]) {
+		ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
+					  ctx->sh_desc_dec);
+		if (ret) {
+			dev_err(jrdev, "driver dec context update failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rfc4106_set_sh_desc(struct crypto_aead *aead)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(aead);
+	unsigned int ivsize = crypto_aead_ivsize(aead);
+	int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+			ctx->cdata.keylen;
+
+	if (!ctx->cdata.keylen || !ctx->authsize)
+		return 0;
+
+	ctx->cdata.key_virt = ctx->key;
+
+	/*
+	 * Job Descriptor and Shared Descriptor
+	 * must fit into the 64-word Descriptor h/w Buffer
+	 */
+	if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) {
+		ctx->cdata.key_inline = true;
+	} else {
+		ctx->cdata.key_inline = false;
+		ctx->cdata.key_dma = ctx->key_dma;
+	}
+
+	cnstr_shdsc_rfc4106_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+				  ctx->authsize, true);
+
+	/*
+	 * Job Descriptor and Shared Descriptor
+	 * must fit into the 64-word Descriptor h/w Buffer
+	 */
+	if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) {
+		ctx->cdata.key_inline = true;
+	} else {
+		ctx->cdata.key_inline = false;
+		ctx->cdata.key_dma = ctx->key_dma;
+	}
+
+	cnstr_shdsc_rfc4106_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+				  ctx->authsize, true);
+
+	return 0;
+}
+
+static int rfc4106_setauthsize(struct crypto_aead *authenc,
+			       unsigned int authsize)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+	ctx->authsize = authsize;
+	rfc4106_set_sh_desc(authenc);
+
+	return 0;
+}
+
+static int rfc4106_setkey(struct crypto_aead *aead,
+			  const u8 *key, unsigned int keylen)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(aead);
+	struct device *jrdev = ctx->jrdev;
+	int ret;
+
+	if (keylen < 4)
+		return -EINVAL;
+
+#ifdef DEBUG
+	print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
+		       DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+
+	memcpy(ctx->key, key, keylen);
+	/*
+	 * The last four bytes of the key material are used as the salt value
+	 * in the nonce. Update the AES key length.
+	 */
+	ctx->cdata.keylen = keylen - 4;
+	dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
+				   ctx->dir);
+
+	ret = rfc4106_set_sh_desc(aead);
+	if (ret)
+		return ret;
+
+	/* Now update the driver contexts with the new shared descriptor */
+	if (ctx->drv_ctx[ENCRYPT]) {
+		ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
+					  ctx->sh_desc_enc);
+		if (ret) {
+			dev_err(jrdev, "driver enc context update failed\n");
+			return ret;
+		}
+	}
+
+	if (ctx->drv_ctx[DECRYPT]) {
+		ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
+					  ctx->sh_desc_dec);
+		if (ret) {
+			dev_err(jrdev, "driver dec context update failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rfc4543_set_sh_desc(struct crypto_aead *aead)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(aead);
+	unsigned int ivsize = crypto_aead_ivsize(aead);
+	int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+			ctx->cdata.keylen;
+
+	if (!ctx->cdata.keylen || !ctx->authsize)
+		return 0;
+
+	ctx->cdata.key_virt = ctx->key;
+
+	/*
+	 * Job Descriptor and Shared Descriptor
+	 * must fit into the 64-word Descriptor h/w Buffer
+	 */
+	if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) {
+		ctx->cdata.key_inline = true;
+	} else {
+		ctx->cdata.key_inline = false;
+		ctx->cdata.key_dma = ctx->key_dma;
+	}
+
+	cnstr_shdsc_rfc4543_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+				  ctx->authsize, true);
+
+	/*
+	 * Job Descriptor and Shared Descriptor
+	 * must fit into the 64-word Descriptor h/w Buffer
+	 */
+	if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) {
+		ctx->cdata.key_inline = true;
+	} else {
+		ctx->cdata.key_inline = false;
+		ctx->cdata.key_dma = ctx->key_dma;
+	}
+
+	cnstr_shdsc_rfc4543_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+				  ctx->authsize, true);
+
+	return 0;
+}
+
+static int rfc4543_setauthsize(struct crypto_aead *authenc,
+			       unsigned int authsize)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+	ctx->authsize = authsize;
+	rfc4543_set_sh_desc(authenc);
+
+	return 0;
+}
+
+static int rfc4543_setkey(struct crypto_aead *aead,
+			  const u8 *key, unsigned int keylen)
+{
+	struct caam_ctx *ctx = crypto_aead_ctx(aead);
+	struct device *jrdev = ctx->jrdev;
+	int ret;
+
+	if (keylen < 4)
+		return -EINVAL;
+
+#ifdef DEBUG
+	print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
+		       DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+
+	memcpy(ctx->key, key, keylen);
+	/*
+	 * The last four bytes of the key material are used as the salt value
+	 * in the nonce. Update the AES key length.
+	 */
+	ctx->cdata.keylen = keylen - 4;
+	dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
+				   ctx->dir);
+
+	ret = rfc4543_set_sh_desc(aead);
+	if (ret)
+		return ret;
+
+	/* Now update the driver contexts with the new shared descriptor */
+	if (ctx->drv_ctx[ENCRYPT]) {
+		ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
+					  ctx->sh_desc_enc);
+		if (ret) {
+			dev_err(jrdev, "driver enc context update failed\n");
+			return ret;
+		}
+	}
+
+	if (ctx->drv_ctx[DECRYPT]) {
+		ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
+					  ctx->sh_desc_dec);
+		if (ret) {
+			dev_err(jrdev, "driver dec context update failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
 			     const u8 *key, unsigned int keylen)
 {
@@ -562,8 +865,18 @@ static void aead_done(struct caam_drv_req *drv_req, u32 status)
 	qidev = caam_ctx->qidev;
 
 	if (unlikely(status)) {
+		u32 ssrc = status & JRSTA_SSRC_MASK;
+		u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
+
 		caam_jr_strstatus(qidev, status);
-		ecode = -EIO;
+		/*
+		 * verify hw auth check passed else return -EBADMSG
+		 */
+		if (ssrc == JRSTA_SSRC_CCB_ERROR &&
+		    err_id == JRSTA_CCBERR_ERRID_ICVCHK)
+			ecode = -EBADMSG;
+		else
+			ecode = -EIO;
 	}
 
 	edesc = container_of(drv_req, typeof(*edesc), drv_req);
@@ -807,6 +1120,22 @@ static int aead_decrypt(struct aead_request *req)
 	return aead_crypt(req, false);
 }
 
+static int ipsec_gcm_encrypt(struct aead_request *req)
+{
+	if (req->assoclen < 8)
+		return -EINVAL;
+
+	return aead_crypt(req, true);
+}
+
+static int ipsec_gcm_decrypt(struct aead_request *req)
+{
+	if (req->assoclen < 8)
+		return -EINVAL;
+
+	return aead_crypt(req, false);
+}
+
 static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status)
 {
 	struct ablkcipher_edesc *edesc;
@@ -1327,6 +1656,61 @@ static struct caam_alg_template driver_algs[] = {
 };
 
 static struct caam_aead_alg driver_aeads[] = {
+	{
+		.aead = {
+			.base = {
+				.cra_name = "rfc4106(gcm(aes))",
+				.cra_driver_name = "rfc4106-gcm-aes-caam-qi",
+				.cra_blocksize = 1,
+			},
+			.setkey = rfc4106_setkey,
+			.setauthsize = rfc4106_setauthsize,
+			.encrypt = ipsec_gcm_encrypt,
+			.decrypt = ipsec_gcm_decrypt,
+			.ivsize = 8,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.caam = {
+			.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+		},
+	},
+	{
+		.aead = {
+			.base = {
+				.cra_name = "rfc4543(gcm(aes))",
+				.cra_driver_name = "rfc4543-gcm-aes-caam-qi",
+				.cra_blocksize = 1,
+			},
+			.setkey = rfc4543_setkey,
+			.setauthsize = rfc4543_setauthsize,
+			.encrypt = ipsec_gcm_encrypt,
+			.decrypt = ipsec_gcm_decrypt,
+			.ivsize = 8,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.caam = {
+			.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+		},
+	},
+	/* Galois Counter Mode */
+	{
+		.aead = {
+			.base = {
+				.cra_name = "gcm(aes)",
+				.cra_driver_name = "gcm-aes-caam-qi",
+				.cra_blocksize = 1,
+			},
+			.setkey = gcm_setkey,
+			.setauthsize = gcm_setauthsize,
+			.encrypt = aead_encrypt,
+			.decrypt = aead_decrypt,
+			.ivsize = 12,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.caam = {
+			.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+		}
+	},
 	/* single-pass ipsec_esp descriptor */
 	{
 		.aead = {
diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c
index f9a44f485aac..b9480828da38 100644
--- a/drivers/crypto/caam/qi.c
+++ b/drivers/crypto/caam/qi.c
@@ -579,8 +579,15 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
 
 	fd = &dqrr->fd;
 	status = be32_to_cpu(fd->status);
-	if (unlikely(status))
-		dev_err(qidev, "Error: %#x in CAAM response FD\n", status);
+	if (unlikely(status)) {
+		u32 ssrc = status & JRSTA_SSRC_MASK;
+		u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
+
+		if (ssrc != JRSTA_SSRC_CCB_ERROR ||
+		    err_id != JRSTA_CCBERR_ERRID_ICVCHK)
+			dev_err(qidev, "Error: %#x in CAAM response FD\n",
+				status);
+	}
 
 	if (unlikely(qm_fd_get_format(fd) != qm_fd_compound)) {
 		dev_err(qidev, "Non-compound FD from CAAM\n");
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index 8b9da58459df..67155cb21636 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -38,7 +38,7 @@ static unsigned int dma_chan_attr = CCP_DMA_DFLT;
 module_param(dma_chan_attr, uint, 0444);
 MODULE_PARM_DESC(dma_chan_attr, "Set DMA channel visibility: 0 (default) = device defaults, 1 = make private, 2 = make public");
 
-unsigned int ccp_get_dma_chan_attr(struct ccp_device *ccp)
+static unsigned int ccp_get_dma_chan_attr(struct ccp_device *ccp)
 {
 	switch (dma_chan_attr) {
 	case CCP_DMA_DFLT:
diff --git a/drivers/crypto/ccree/Makefile b/drivers/crypto/ccree/Makefile
new file mode 100644
index 000000000000..bdc27970f95f
--- /dev/null
+++ b/drivers/crypto/ccree/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_CRYPTO_DEV_CCREE) := ccree.o
+ccree-y := cc_driver.o cc_buffer_mgr.o cc_request_mgr.o cc_cipher.o cc_hash.o cc_aead.o cc_ivgen.o cc_sram_mgr.o
+ccree-$(CONFIG_CRYPTO_FIPS) += cc_fips.o
+ccree-$(CONFIG_DEBUG_FS) += cc_debugfs.o
+ccree-$(CONFIG_PM) += cc_pm.o
diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c
new file mode 100644
index 000000000000..3e1046a87a01
--- /dev/null
+++ b/drivers/crypto/ccree/cc_aead.c
@@ -0,0 +1,2702 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/des.h>
+#include <linux/rtnetlink.h>
+#include "cc_driver.h"
+#include "cc_buffer_mgr.h"
+#include "cc_aead.h"
+#include "cc_request_mgr.h"
+#include "cc_hash.h"
+#include "cc_sram_mgr.h"
+
+#define template_aead	template_u.aead
+
+#define MAX_AEAD_SETKEY_SEQ 12
+#define MAX_AEAD_PROCESS_SEQ 23
+
+#define MAX_HMAC_DIGEST_SIZE (SHA256_DIGEST_SIZE)
+#define MAX_HMAC_BLOCK_SIZE (SHA256_BLOCK_SIZE)
+
+#define AES_CCM_RFC4309_NONCE_SIZE 3
+#define MAX_NONCE_SIZE CTR_RFC3686_NONCE_SIZE
+
+/* Value of each ICV_CMP byte (of 8) in case of success */
+#define ICV_VERIF_OK 0x01
+
+struct cc_aead_handle {
+	cc_sram_addr_t sram_workspace_addr;
+	struct list_head aead_list;
+};
+
+struct cc_hmac_s {
+	u8 *padded_authkey;
+	u8 *ipad_opad; /* IPAD, OPAD*/
+	dma_addr_t padded_authkey_dma_addr;
+	dma_addr_t ipad_opad_dma_addr;
+};
+
+struct cc_xcbc_s {
+	u8 *xcbc_keys; /* K1,K2,K3 */
+	dma_addr_t xcbc_keys_dma_addr;
+};
+
+struct cc_aead_ctx {
+	struct cc_drvdata *drvdata;
+	u8 ctr_nonce[MAX_NONCE_SIZE]; /* used for ctr3686 iv and aes ccm */
+	u8 *enckey;
+	dma_addr_t enckey_dma_addr;
+	union {
+		struct cc_hmac_s hmac;
+		struct cc_xcbc_s xcbc;
+	} auth_state;
+	unsigned int enc_keylen;
+	unsigned int auth_keylen;
+	unsigned int authsize; /* Actual (reduced?) size of the MAC/ICv */
+	enum drv_cipher_mode cipher_mode;
+	enum cc_flow_mode flow_mode;
+	enum drv_hash_mode auth_mode;
+};
+
+static inline bool valid_assoclen(struct aead_request *req)
+{
+	return ((req->assoclen == 16) || (req->assoclen == 20));
+}
+
+static void cc_aead_exit(struct crypto_aead *tfm)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "Clearing context @%p for %s\n", crypto_aead_ctx(tfm),
+		crypto_tfm_alg_name(&tfm->base));
+
+	/* Unmap enckey buffer */
+	if (ctx->enckey) {
+		dma_free_coherent(dev, AES_MAX_KEY_SIZE, ctx->enckey,
+				  ctx->enckey_dma_addr);
+		dev_dbg(dev, "Freed enckey DMA buffer enckey_dma_addr=%pad\n",
+			&ctx->enckey_dma_addr);
+		ctx->enckey_dma_addr = 0;
+		ctx->enckey = NULL;
+	}
+
+	if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */
+		struct cc_xcbc_s *xcbc = &ctx->auth_state.xcbc;
+
+		if (xcbc->xcbc_keys) {
+			dma_free_coherent(dev, CC_AES_128_BIT_KEY_SIZE * 3,
+					  xcbc->xcbc_keys,
+					  xcbc->xcbc_keys_dma_addr);
+		}
+		dev_dbg(dev, "Freed xcbc_keys DMA buffer xcbc_keys_dma_addr=%pad\n",
+			&xcbc->xcbc_keys_dma_addr);
+		xcbc->xcbc_keys_dma_addr = 0;
+		xcbc->xcbc_keys = NULL;
+	} else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC auth. */
+		struct cc_hmac_s *hmac = &ctx->auth_state.hmac;
+
+		if (hmac->ipad_opad) {
+			dma_free_coherent(dev, 2 * MAX_HMAC_DIGEST_SIZE,
+					  hmac->ipad_opad,
+					  hmac->ipad_opad_dma_addr);
+			dev_dbg(dev, "Freed ipad_opad DMA buffer ipad_opad_dma_addr=%pad\n",
+				&hmac->ipad_opad_dma_addr);
+			hmac->ipad_opad_dma_addr = 0;
+			hmac->ipad_opad = NULL;
+		}
+		if (hmac->padded_authkey) {
+			dma_free_coherent(dev, MAX_HMAC_BLOCK_SIZE,
+					  hmac->padded_authkey,
+					  hmac->padded_authkey_dma_addr);
+			dev_dbg(dev, "Freed padded_authkey DMA buffer padded_authkey_dma_addr=%pad\n",
+				&hmac->padded_authkey_dma_addr);
+			hmac->padded_authkey_dma_addr = 0;
+			hmac->padded_authkey = NULL;
+		}
+	}
+}
+
+static int cc_aead_init(struct crypto_aead *tfm)
+{
+	struct aead_alg *alg = crypto_aead_alg(tfm);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct cc_crypto_alg *cc_alg =
+			container_of(alg, struct cc_crypto_alg, aead_alg);
+	struct device *dev = drvdata_to_dev(cc_alg->drvdata);
+
+	dev_dbg(dev, "Initializing context @%p for %s\n", ctx,
+		crypto_tfm_alg_name(&tfm->base));
+
+	/* Initialize modes in instance */
+	ctx->cipher_mode = cc_alg->cipher_mode;
+	ctx->flow_mode = cc_alg->flow_mode;
+	ctx->auth_mode = cc_alg->auth_mode;
+	ctx->drvdata = cc_alg->drvdata;
+	crypto_aead_set_reqsize(tfm, sizeof(struct aead_req_ctx));
+
+	/* Allocate key buffer, cache line aligned */
+	ctx->enckey = dma_alloc_coherent(dev, AES_MAX_KEY_SIZE,
+					 &ctx->enckey_dma_addr, GFP_KERNEL);
+	if (!ctx->enckey) {
+		dev_err(dev, "Failed allocating key buffer\n");
+		goto init_failed;
+	}
+	dev_dbg(dev, "Allocated enckey buffer in context ctx->enckey=@%p\n",
+		ctx->enckey);
+
+	/* Set default authlen value */
+
+	if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */
+		struct cc_xcbc_s *xcbc = &ctx->auth_state.xcbc;
+		const unsigned int key_size = CC_AES_128_BIT_KEY_SIZE * 3;
+
+		/* Allocate dma-coherent buffer for XCBC's K1+K2+K3 */
+		/* (and temporary for user key - up to 256b) */
+		xcbc->xcbc_keys = dma_alloc_coherent(dev, key_size,
+						     &xcbc->xcbc_keys_dma_addr,
+						     GFP_KERNEL);
+		if (!xcbc->xcbc_keys) {
+			dev_err(dev, "Failed allocating buffer for XCBC keys\n");
+			goto init_failed;
+		}
+	} else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC authentication */
+		struct cc_hmac_s *hmac = &ctx->auth_state.hmac;
+		const unsigned int digest_size = 2 * MAX_HMAC_DIGEST_SIZE;
+		dma_addr_t *pkey_dma = &hmac->padded_authkey_dma_addr;
+
+		/* Allocate dma-coherent buffer for IPAD + OPAD */
+		hmac->ipad_opad = dma_alloc_coherent(dev, digest_size,
+						     &hmac->ipad_opad_dma_addr,
+						     GFP_KERNEL);
+
+		if (!hmac->ipad_opad) {
+			dev_err(dev, "Failed allocating IPAD/OPAD buffer\n");
+			goto init_failed;
+		}
+
+		dev_dbg(dev, "Allocated authkey buffer in context ctx->authkey=@%p\n",
+			hmac->ipad_opad);
+
+		hmac->padded_authkey = dma_alloc_coherent(dev,
+							  MAX_HMAC_BLOCK_SIZE,
+							  pkey_dma,
+							  GFP_KERNEL);
+
+		if (!hmac->padded_authkey) {
+			dev_err(dev, "failed to allocate padded_authkey\n");
+			goto init_failed;
+		}
+	} else {
+		ctx->auth_state.hmac.ipad_opad = NULL;
+		ctx->auth_state.hmac.padded_authkey = NULL;
+	}
+
+	return 0;
+
+init_failed:
+	cc_aead_exit(tfm);
+	return -ENOMEM;
+}
+
+static void cc_aead_complete(struct device *dev, void *cc_req, int err)
+{
+	struct aead_request *areq = (struct aead_request *)cc_req;
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+	struct crypto_aead *tfm = crypto_aead_reqtfm(cc_req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+	cc_unmap_aead_request(dev, areq);
+
+	/* Restore ordinary iv pointer */
+	areq->iv = areq_ctx->backup_iv;
+
+	if (err)
+		goto done;
+
+	if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+		if (memcmp(areq_ctx->mac_buf, areq_ctx->icv_virt_addr,
+			   ctx->authsize) != 0) {
+			dev_dbg(dev, "Payload authentication failure, (auth-size=%d, cipher=%d)\n",
+				ctx->authsize, ctx->cipher_mode);
+			/* In case of payload authentication failure, MUST NOT
+			 * revealed the decrypted message --> zero its memory.
+			 */
+			cc_zero_sgl(areq->dst, areq_ctx->cryptlen);
+			err = -EBADMSG;
+		}
+	} else { /*ENCRYPT*/
+		if (areq_ctx->is_icv_fragmented) {
+			u32 skip = areq->cryptlen + areq_ctx->dst_offset;
+
+			cc_copy_sg_portion(dev, areq_ctx->mac_buf,
+					   areq_ctx->dst_sgl, skip,
+					   (skip + ctx->authsize),
+					   CC_SG_FROM_BUF);
+		}
+
+		/* If an IV was generated, copy it back to the user provided
+		 * buffer.
+		 */
+		if (areq_ctx->backup_giv) {
+			if (ctx->cipher_mode == DRV_CIPHER_CTR)
+				memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv +
+				       CTR_RFC3686_NONCE_SIZE,
+				       CTR_RFC3686_IV_SIZE);
+			else if (ctx->cipher_mode == DRV_CIPHER_CCM)
+				memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv +
+				       CCM_BLOCK_IV_OFFSET, CCM_BLOCK_IV_SIZE);
+		}
+	}
+done:
+	aead_request_complete(areq, err);
+}
+
+static unsigned int xcbc_setkey(struct cc_hw_desc *desc,
+				struct cc_aead_ctx *ctx)
+{
+	/* Load the AES key */
+	hw_desc_init(&desc[0]);
+	/* We are using for the source/user key the same buffer
+	 * as for the output keys, * because after this key loading it
+	 * is not needed anymore
+	 */
+	set_din_type(&desc[0], DMA_DLLI,
+		     ctx->auth_state.xcbc.xcbc_keys_dma_addr, ctx->auth_keylen,
+		     NS_BIT);
+	set_cipher_mode(&desc[0], DRV_CIPHER_ECB);
+	set_cipher_config0(&desc[0], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_key_size_aes(&desc[0], ctx->auth_keylen);
+	set_flow_mode(&desc[0], S_DIN_to_AES);
+	set_setup_mode(&desc[0], SETUP_LOAD_KEY0);
+
+	hw_desc_init(&desc[1]);
+	set_din_const(&desc[1], 0x01010101, CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[1], DIN_AES_DOUT);
+	set_dout_dlli(&desc[1], ctx->auth_state.xcbc.xcbc_keys_dma_addr,
+		      AES_KEYSIZE_128, NS_BIT, 0);
+
+	hw_desc_init(&desc[2]);
+	set_din_const(&desc[2], 0x02020202, CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[2], DIN_AES_DOUT);
+	set_dout_dlli(&desc[2], (ctx->auth_state.xcbc.xcbc_keys_dma_addr
+					 + AES_KEYSIZE_128),
+			      AES_KEYSIZE_128, NS_BIT, 0);
+
+	hw_desc_init(&desc[3]);
+	set_din_const(&desc[3], 0x03030303, CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[3], DIN_AES_DOUT);
+	set_dout_dlli(&desc[3], (ctx->auth_state.xcbc.xcbc_keys_dma_addr
+					  + 2 * AES_KEYSIZE_128),
+			      AES_KEYSIZE_128, NS_BIT, 0);
+
+	return 4;
+}
+
+static int hmac_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
+{
+	unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST };
+	unsigned int digest_ofs = 0;
+	unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+			DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+	unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ?
+			CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
+	struct cc_hmac_s *hmac = &ctx->auth_state.hmac;
+
+	unsigned int idx = 0;
+	int i;
+
+	/* calc derived HMAC key */
+	for (i = 0; i < 2; i++) {
+		/* Load hash initial state */
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], hash_mode);
+		set_din_sram(&desc[idx],
+			     cc_larval_digest_addr(ctx->drvdata,
+						   ctx->auth_mode),
+			     digest_size);
+		set_flow_mode(&desc[idx], S_DIN_to_HASH);
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+		idx++;
+
+		/* Load the hash current length*/
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], hash_mode);
+		set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+		set_flow_mode(&desc[idx], S_DIN_to_HASH);
+		set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+		idx++;
+
+		/* Prepare ipad key */
+		hw_desc_init(&desc[idx]);
+		set_xor_val(&desc[idx], hmac_pad_const[i]);
+		set_cipher_mode(&desc[idx], hash_mode);
+		set_flow_mode(&desc[idx], S_DIN_to_HASH);
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+		idx++;
+
+		/* Perform HASH update */
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     hmac->padded_authkey_dma_addr,
+			     SHA256_BLOCK_SIZE, NS_BIT);
+		set_cipher_mode(&desc[idx], hash_mode);
+		set_xor_active(&desc[idx]);
+		set_flow_mode(&desc[idx], DIN_HASH);
+		idx++;
+
+		/* Get the digset */
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], hash_mode);
+		set_dout_dlli(&desc[idx],
+			      (hmac->ipad_opad_dma_addr + digest_ofs),
+			      digest_size, NS_BIT, 0);
+		set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+		set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+		set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
+		idx++;
+
+		digest_ofs += digest_size;
+	}
+
+	return idx;
+}
+
+static int validate_keys_sizes(struct cc_aead_ctx *ctx)
+{
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "enc_keylen=%u  authkeylen=%u\n",
+		ctx->enc_keylen, ctx->auth_keylen);
+
+	switch (ctx->auth_mode) {
+	case DRV_HASH_SHA1:
+	case DRV_HASH_SHA256:
+		break;
+	case DRV_HASH_XCBC_MAC:
+		if (ctx->auth_keylen != AES_KEYSIZE_128 &&
+		    ctx->auth_keylen != AES_KEYSIZE_192 &&
+		    ctx->auth_keylen != AES_KEYSIZE_256)
+			return -ENOTSUPP;
+		break;
+	case DRV_HASH_NULL: /* Not authenc (e.g., CCM) - no auth_key) */
+		if (ctx->auth_keylen > 0)
+			return -EINVAL;
+		break;
+	default:
+		dev_err(dev, "Invalid auth_mode=%d\n", ctx->auth_mode);
+		return -EINVAL;
+	}
+	/* Check cipher key size */
+	if (ctx->flow_mode == S_DIN_to_DES) {
+		if (ctx->enc_keylen != DES3_EDE_KEY_SIZE) {
+			dev_err(dev, "Invalid cipher(3DES) key size: %u\n",
+				ctx->enc_keylen);
+			return -EINVAL;
+		}
+	} else { /* Default assumed to be AES ciphers */
+		if (ctx->enc_keylen != AES_KEYSIZE_128 &&
+		    ctx->enc_keylen != AES_KEYSIZE_192 &&
+		    ctx->enc_keylen != AES_KEYSIZE_256) {
+			dev_err(dev, "Invalid cipher(AES) key size: %u\n",
+				ctx->enc_keylen);
+			return -EINVAL;
+		}
+	}
+
+	return 0; /* All tests of keys sizes passed */
+}
+
+/* This function prepers the user key so it can pass to the hmac processing
+ * (copy to intenral buffer or hash in case of key longer than block
+ */
+static int cc_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key,
+				 unsigned int keylen)
+{
+	dma_addr_t key_dma_addr = 0;
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	u32 larval_addr = cc_larval_digest_addr(ctx->drvdata, ctx->auth_mode);
+	struct cc_crypto_req cc_req = {};
+	unsigned int blocksize;
+	unsigned int digestsize;
+	unsigned int hashmode;
+	unsigned int idx = 0;
+	int rc = 0;
+	struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ];
+	dma_addr_t padded_authkey_dma_addr =
+		ctx->auth_state.hmac.padded_authkey_dma_addr;
+
+	switch (ctx->auth_mode) { /* auth_key required and >0 */
+	case DRV_HASH_SHA1:
+		blocksize = SHA1_BLOCK_SIZE;
+		digestsize = SHA1_DIGEST_SIZE;
+		hashmode = DRV_HASH_HW_SHA1;
+		break;
+	case DRV_HASH_SHA256:
+	default:
+		blocksize = SHA256_BLOCK_SIZE;
+		digestsize = SHA256_DIGEST_SIZE;
+		hashmode = DRV_HASH_HW_SHA256;
+	}
+
+	if (keylen != 0) {
+		key_dma_addr = dma_map_single(dev, (void *)key, keylen,
+					      DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, key_dma_addr)) {
+			dev_err(dev, "Mapping key va=0x%p len=%u for DMA failed\n",
+				key, keylen);
+			return -ENOMEM;
+		}
+		if (keylen > blocksize) {
+			/* Load hash initial state */
+			hw_desc_init(&desc[idx]);
+			set_cipher_mode(&desc[idx], hashmode);
+			set_din_sram(&desc[idx], larval_addr, digestsize);
+			set_flow_mode(&desc[idx], S_DIN_to_HASH);
+			set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+			idx++;
+
+			/* Load the hash current length*/
+			hw_desc_init(&desc[idx]);
+			set_cipher_mode(&desc[idx], hashmode);
+			set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+			set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+			set_flow_mode(&desc[idx], S_DIN_to_HASH);
+			set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+			idx++;
+
+			hw_desc_init(&desc[idx]);
+			set_din_type(&desc[idx], DMA_DLLI,
+				     key_dma_addr, keylen, NS_BIT);
+			set_flow_mode(&desc[idx], DIN_HASH);
+			idx++;
+
+			/* Get hashed key */
+			hw_desc_init(&desc[idx]);
+			set_cipher_mode(&desc[idx], hashmode);
+			set_dout_dlli(&desc[idx], padded_authkey_dma_addr,
+				      digestsize, NS_BIT, 0);
+			set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+			set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+			set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
+			set_cipher_config0(&desc[idx],
+					   HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+			idx++;
+
+			hw_desc_init(&desc[idx]);
+			set_din_const(&desc[idx], 0, (blocksize - digestsize));
+			set_flow_mode(&desc[idx], BYPASS);
+			set_dout_dlli(&desc[idx], (padded_authkey_dma_addr +
+				      digestsize), (blocksize - digestsize),
+				      NS_BIT, 0);
+			idx++;
+		} else {
+			hw_desc_init(&desc[idx]);
+			set_din_type(&desc[idx], DMA_DLLI, key_dma_addr,
+				     keylen, NS_BIT);
+			set_flow_mode(&desc[idx], BYPASS);
+			set_dout_dlli(&desc[idx], padded_authkey_dma_addr,
+				      keylen, NS_BIT, 0);
+			idx++;
+
+			if ((blocksize - keylen) != 0) {
+				hw_desc_init(&desc[idx]);
+				set_din_const(&desc[idx], 0,
+					      (blocksize - keylen));
+				set_flow_mode(&desc[idx], BYPASS);
+				set_dout_dlli(&desc[idx],
+					      (padded_authkey_dma_addr +
+					       keylen),
+					      (blocksize - keylen), NS_BIT, 0);
+				idx++;
+			}
+		}
+	} else {
+		hw_desc_init(&desc[idx]);
+		set_din_const(&desc[idx], 0, (blocksize - keylen));
+		set_flow_mode(&desc[idx], BYPASS);
+		set_dout_dlli(&desc[idx], padded_authkey_dma_addr,
+			      blocksize, NS_BIT, 0);
+		idx++;
+	}
+
+	rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx);
+	if (rc)
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+
+	if (key_dma_addr)
+		dma_unmap_single(dev, key_dma_addr, keylen, DMA_TO_DEVICE);
+
+	return rc;
+}
+
+static int cc_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+			  unsigned int keylen)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct rtattr *rta = (struct rtattr *)key;
+	struct cc_crypto_req cc_req = {};
+	struct crypto_authenc_key_param *param;
+	struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ];
+	int rc = -EINVAL;
+	unsigned int seq_len = 0;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "Setting key in context @%p for %s. key=%p keylen=%u\n",
+		ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), key, keylen);
+
+	/* STAT_PHASE_0: Init and sanity checks */
+
+	if (ctx->auth_mode != DRV_HASH_NULL) { /* authenc() alg. */
+		if (!RTA_OK(rta, keylen))
+			goto badkey;
+		if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+			goto badkey;
+		if (RTA_PAYLOAD(rta) < sizeof(*param))
+			goto badkey;
+		param = RTA_DATA(rta);
+		ctx->enc_keylen = be32_to_cpu(param->enckeylen);
+		key += RTA_ALIGN(rta->rta_len);
+		keylen -= RTA_ALIGN(rta->rta_len);
+		if (keylen < ctx->enc_keylen)
+			goto badkey;
+		ctx->auth_keylen = keylen - ctx->enc_keylen;
+
+		if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+			/* the nonce is stored in bytes at end of key */
+			if (ctx->enc_keylen <
+			    (AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE))
+				goto badkey;
+			/* Copy nonce from last 4 bytes in CTR key to
+			 *  first 4 bytes in CTR IV
+			 */
+			memcpy(ctx->ctr_nonce, key + ctx->auth_keylen +
+			       ctx->enc_keylen - CTR_RFC3686_NONCE_SIZE,
+			       CTR_RFC3686_NONCE_SIZE);
+			/* Set CTR key size */
+			ctx->enc_keylen -= CTR_RFC3686_NONCE_SIZE;
+		}
+	} else { /* non-authenc - has just one key */
+		ctx->enc_keylen = keylen;
+		ctx->auth_keylen = 0;
+	}
+
+	rc = validate_keys_sizes(ctx);
+	if (rc)
+		goto badkey;
+
+	/* STAT_PHASE_1: Copy key to ctx */
+
+	/* Get key material */
+	memcpy(ctx->enckey, key + ctx->auth_keylen, ctx->enc_keylen);
+	if (ctx->enc_keylen == 24)
+		memset(ctx->enckey + 24, 0, CC_AES_KEY_SIZE_MAX - 24);
+	if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
+		memcpy(ctx->auth_state.xcbc.xcbc_keys, key, ctx->auth_keylen);
+	} else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC */
+		rc = cc_get_plain_hmac_key(tfm, key, ctx->auth_keylen);
+		if (rc)
+			goto badkey;
+	}
+
+	/* STAT_PHASE_2: Create sequence */
+
+	switch (ctx->auth_mode) {
+	case DRV_HASH_SHA1:
+	case DRV_HASH_SHA256:
+		seq_len = hmac_setkey(desc, ctx);
+		break;
+	case DRV_HASH_XCBC_MAC:
+		seq_len = xcbc_setkey(desc, ctx);
+		break;
+	case DRV_HASH_NULL: /* non-authenc modes, e.g., CCM */
+		break; /* No auth. key setup */
+	default:
+		dev_err(dev, "Unsupported authenc (%d)\n", ctx->auth_mode);
+		rc = -ENOTSUPP;
+		goto badkey;
+	}
+
+	/* STAT_PHASE_3: Submit sequence to HW */
+
+	if (seq_len > 0) { /* For CCM there is no sequence to setup the key */
+		rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, seq_len);
+		if (rc) {
+			dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+			goto setkey_error;
+		}
+	}
+
+	/* Update STAT_PHASE_3 */
+	return rc;
+
+badkey:
+	crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+setkey_error:
+	return rc;
+}
+
+static int cc_rfc4309_ccm_setkey(struct crypto_aead *tfm, const u8 *key,
+				 unsigned int keylen)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+	if (keylen < 3)
+		return -EINVAL;
+
+	keylen -= 3;
+	memcpy(ctx->ctr_nonce, key + keylen, 3);
+
+	return cc_aead_setkey(tfm, key, keylen);
+}
+
+static int cc_aead_setauthsize(struct crypto_aead *authenc,
+			       unsigned int authsize)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(authenc);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	/* Unsupported auth. sizes */
+	if (authsize == 0 ||
+	    authsize > crypto_aead_maxauthsize(authenc)) {
+		return -ENOTSUPP;
+	}
+
+	ctx->authsize = authsize;
+	dev_dbg(dev, "authlen=%d\n", ctx->authsize);
+
+	return 0;
+}
+
+static int cc_rfc4309_ccm_setauthsize(struct crypto_aead *authenc,
+				      unsigned int authsize)
+{
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return cc_aead_setauthsize(authenc, authsize);
+}
+
+static int cc_ccm_setauthsize(struct crypto_aead *authenc,
+			      unsigned int authsize)
+{
+	switch (authsize) {
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return cc_aead_setauthsize(authenc, authsize);
+}
+
+static void cc_set_assoc_desc(struct aead_request *areq, unsigned int flow_mode,
+			      struct cc_hw_desc desc[], unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(areq);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+	enum cc_req_dma_buf_type assoc_dma_type = areq_ctx->assoc_buff_type;
+	unsigned int idx = *seq_size;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	switch (assoc_dma_type) {
+	case CC_DMA_BUF_DLLI:
+		dev_dbg(dev, "ASSOC buffer type DLLI\n");
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI, sg_dma_address(areq->src),
+			     areq->assoclen, NS_BIT);
+		set_flow_mode(&desc[idx], flow_mode);
+		if (ctx->auth_mode == DRV_HASH_XCBC_MAC &&
+		    areq_ctx->cryptlen > 0)
+			set_din_not_last_indication(&desc[idx]);
+		break;
+	case CC_DMA_BUF_MLLI:
+		dev_dbg(dev, "ASSOC buffer type MLLI\n");
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_MLLI, areq_ctx->assoc.sram_addr,
+			     areq_ctx->assoc.mlli_nents, NS_BIT);
+		set_flow_mode(&desc[idx], flow_mode);
+		if (ctx->auth_mode == DRV_HASH_XCBC_MAC &&
+		    areq_ctx->cryptlen > 0)
+			set_din_not_last_indication(&desc[idx]);
+		break;
+	case CC_DMA_BUF_NULL:
+	default:
+		dev_err(dev, "Invalid ASSOC buffer type\n");
+	}
+
+	*seq_size = (++idx);
+}
+
+static void cc_proc_authen_desc(struct aead_request *areq,
+				unsigned int flow_mode,
+				struct cc_hw_desc desc[],
+				unsigned int *seq_size, int direct)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+	enum cc_req_dma_buf_type data_dma_type = areq_ctx->data_buff_type;
+	unsigned int idx = *seq_size;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(areq);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	switch (data_dma_type) {
+	case CC_DMA_BUF_DLLI:
+	{
+		struct scatterlist *cipher =
+			(direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+			areq_ctx->dst_sgl : areq_ctx->src_sgl;
+
+		unsigned int offset =
+			(direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+			areq_ctx->dst_offset : areq_ctx->src_offset;
+		dev_dbg(dev, "AUTHENC: SRC/DST buffer type DLLI\n");
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     (sg_dma_address(cipher) + offset),
+			     areq_ctx->cryptlen, NS_BIT);
+		set_flow_mode(&desc[idx], flow_mode);
+		break;
+	}
+	case CC_DMA_BUF_MLLI:
+	{
+		/* DOUBLE-PASS flow (as default)
+		 * assoc. + iv + data -compact in one table
+		 * if assoclen is ZERO only IV perform
+		 */
+		cc_sram_addr_t mlli_addr = areq_ctx->assoc.sram_addr;
+		u32 mlli_nents = areq_ctx->assoc.mlli_nents;
+
+		if (areq_ctx->is_single_pass) {
+			if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+				mlli_addr = areq_ctx->dst.sram_addr;
+				mlli_nents = areq_ctx->dst.mlli_nents;
+			} else {
+				mlli_addr = areq_ctx->src.sram_addr;
+				mlli_nents = areq_ctx->src.mlli_nents;
+			}
+		}
+
+		dev_dbg(dev, "AUTHENC: SRC/DST buffer type MLLI\n");
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_MLLI, mlli_addr, mlli_nents,
+			     NS_BIT);
+		set_flow_mode(&desc[idx], flow_mode);
+		break;
+	}
+	case CC_DMA_BUF_NULL:
+	default:
+		dev_err(dev, "AUTHENC: Invalid SRC/DST buffer type\n");
+	}
+
+	*seq_size = (++idx);
+}
+
+static void cc_proc_cipher_desc(struct aead_request *areq,
+				unsigned int flow_mode,
+				struct cc_hw_desc desc[],
+				unsigned int *seq_size)
+{
+	unsigned int idx = *seq_size;
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+	enum cc_req_dma_buf_type data_dma_type = areq_ctx->data_buff_type;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(areq);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	if (areq_ctx->cryptlen == 0)
+		return; /*null processing*/
+
+	switch (data_dma_type) {
+	case CC_DMA_BUF_DLLI:
+		dev_dbg(dev, "CIPHER: SRC/DST buffer type DLLI\n");
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     (sg_dma_address(areq_ctx->src_sgl) +
+			      areq_ctx->src_offset), areq_ctx->cryptlen,
+			      NS_BIT);
+		set_dout_dlli(&desc[idx],
+			      (sg_dma_address(areq_ctx->dst_sgl) +
+			       areq_ctx->dst_offset),
+			      areq_ctx->cryptlen, NS_BIT, 0);
+		set_flow_mode(&desc[idx], flow_mode);
+		break;
+	case CC_DMA_BUF_MLLI:
+		dev_dbg(dev, "CIPHER: SRC/DST buffer type MLLI\n");
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_MLLI, areq_ctx->src.sram_addr,
+			     areq_ctx->src.mlli_nents, NS_BIT);
+		set_dout_mlli(&desc[idx], areq_ctx->dst.sram_addr,
+			      areq_ctx->dst.mlli_nents, NS_BIT, 0);
+		set_flow_mode(&desc[idx], flow_mode);
+		break;
+	case CC_DMA_BUF_NULL:
+	default:
+		dev_err(dev, "CIPHER: Invalid SRC/DST buffer type\n");
+	}
+
+	*seq_size = (++idx);
+}
+
+static void cc_proc_digest_desc(struct aead_request *req,
+				struct cc_hw_desc desc[],
+				unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	unsigned int idx = *seq_size;
+	unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+				DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+	int direct = req_ctx->gen_ctx.op_type;
+
+	/* Get final ICV result */
+	if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+		hw_desc_init(&desc[idx]);
+		set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+		set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+		set_dout_dlli(&desc[idx], req_ctx->icv_dma_addr, ctx->authsize,
+			      NS_BIT, 1);
+		set_queue_last_ind(&desc[idx]);
+		if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
+			set_aes_not_hash_mode(&desc[idx]);
+			set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+		} else {
+			set_cipher_config0(&desc[idx],
+					   HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+			set_cipher_mode(&desc[idx], hash_mode);
+		}
+	} else { /*Decrypt*/
+		/* Get ICV out from hardware */
+		hw_desc_init(&desc[idx]);
+		set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+		set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+		set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr,
+			      ctx->authsize, NS_BIT, 1);
+		set_queue_last_ind(&desc[idx]);
+		set_cipher_config0(&desc[idx],
+				   HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+		set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
+		if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
+			set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+			set_aes_not_hash_mode(&desc[idx]);
+		} else {
+			set_cipher_mode(&desc[idx], hash_mode);
+		}
+	}
+
+	*seq_size = (++idx);
+}
+
+static void cc_set_cipher_desc(struct aead_request *req,
+			       struct cc_hw_desc desc[],
+			       unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	unsigned int hw_iv_size = req_ctx->hw_iv_size;
+	unsigned int idx = *seq_size;
+	int direct = req_ctx->gen_ctx.op_type;
+
+	/* Setup cipher state */
+	hw_desc_init(&desc[idx]);
+	set_cipher_config0(&desc[idx], direct);
+	set_flow_mode(&desc[idx], ctx->flow_mode);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->gen_ctx.iv_dma_addr,
+		     hw_iv_size, NS_BIT);
+	if (ctx->cipher_mode == DRV_CIPHER_CTR)
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+	else
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	set_cipher_mode(&desc[idx], ctx->cipher_mode);
+	idx++;
+
+	/* Setup enc. key */
+	hw_desc_init(&desc[idx]);
+	set_cipher_config0(&desc[idx], direct);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_flow_mode(&desc[idx], ctx->flow_mode);
+	if (ctx->flow_mode == S_DIN_to_AES) {
+		set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+			     ((ctx->enc_keylen == 24) ? CC_AES_KEY_SIZE_MAX :
+			      ctx->enc_keylen), NS_BIT);
+		set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	} else {
+		set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+			     ctx->enc_keylen, NS_BIT);
+		set_key_size_des(&desc[idx], ctx->enc_keylen);
+	}
+	set_cipher_mode(&desc[idx], ctx->cipher_mode);
+	idx++;
+
+	*seq_size = idx;
+}
+
+static void cc_proc_cipher(struct aead_request *req, struct cc_hw_desc desc[],
+			   unsigned int *seq_size, unsigned int data_flow_mode)
+{
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	int direct = req_ctx->gen_ctx.op_type;
+	unsigned int idx = *seq_size;
+
+	if (req_ctx->cryptlen == 0)
+		return; /*null processing*/
+
+	cc_set_cipher_desc(req, desc, &idx);
+	cc_proc_cipher_desc(req, data_flow_mode, desc, &idx);
+	if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+		/* We must wait for DMA to write all cipher */
+		hw_desc_init(&desc[idx]);
+		set_din_no_dma(&desc[idx], 0, 0xfffff0);
+		set_dout_no_dma(&desc[idx], 0, 0, 1);
+		idx++;
+	}
+
+	*seq_size = idx;
+}
+
+static void cc_set_hmac_desc(struct aead_request *req, struct cc_hw_desc desc[],
+			     unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+				DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+	unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ?
+				CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
+	unsigned int idx = *seq_size;
+
+	/* Loading hash ipad xor key state */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], hash_mode);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     ctx->auth_state.hmac.ipad_opad_dma_addr, digest_size,
+		     NS_BIT);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	idx++;
+
+	/* Load init. digest len (64 bytes) */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], hash_mode);
+	set_din_sram(&desc[idx], cc_digest_len_addr(ctx->drvdata, hash_mode),
+		     HASH_LEN_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	*seq_size = idx;
+}
+
+static void cc_set_xcbc_desc(struct aead_request *req, struct cc_hw_desc desc[],
+			     unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	unsigned int idx = *seq_size;
+
+	/* Loading MAC state */
+	hw_desc_init(&desc[idx]);
+	set_din_const(&desc[idx], 0, CC_AES_BLOCK_SIZE);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	/* Setup XCBC MAC K1 */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     ctx->auth_state.xcbc.xcbc_keys_dma_addr,
+		     AES_KEYSIZE_128, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	/* Setup XCBC MAC K2 */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     (ctx->auth_state.xcbc.xcbc_keys_dma_addr +
+		      AES_KEYSIZE_128), AES_KEYSIZE_128, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	/* Setup XCBC MAC K3 */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     (ctx->auth_state.xcbc.xcbc_keys_dma_addr +
+		      2 * AES_KEYSIZE_128), AES_KEYSIZE_128, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE2);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	*seq_size = idx;
+}
+
+static void cc_proc_header_desc(struct aead_request *req,
+				struct cc_hw_desc desc[],
+				unsigned int *seq_size)
+{
+	unsigned int idx = *seq_size;
+	/* Hash associated data */
+	if (req->assoclen > 0)
+		cc_set_assoc_desc(req, DIN_HASH, desc, &idx);
+
+	/* Hash IV */
+	*seq_size = idx;
+}
+
+static void cc_proc_scheme_desc(struct aead_request *req,
+				struct cc_hw_desc desc[],
+				unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct cc_aead_handle *aead_handle = ctx->drvdata->aead_handle;
+	unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+				DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+	unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ?
+				CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
+	unsigned int idx = *seq_size;
+
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], hash_mode);
+	set_dout_sram(&desc[idx], aead_handle->sram_workspace_addr,
+		      HASH_LEN_SIZE);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
+	set_cipher_do(&desc[idx], DO_PAD);
+	idx++;
+
+	/* Get final ICV result */
+	hw_desc_init(&desc[idx]);
+	set_dout_sram(&desc[idx], aead_handle->sram_workspace_addr,
+		      digest_size);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_cipher_config0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+	set_cipher_mode(&desc[idx], hash_mode);
+	idx++;
+
+	/* Loading hash opad xor key state */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], hash_mode);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     (ctx->auth_state.hmac.ipad_opad_dma_addr + digest_size),
+		     digest_size, NS_BIT);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	idx++;
+
+	/* Load init. digest len (64 bytes) */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], hash_mode);
+	set_din_sram(&desc[idx], cc_digest_len_addr(ctx->drvdata, hash_mode),
+		     HASH_LEN_SIZE);
+	set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	/* Perform HASH update */
+	hw_desc_init(&desc[idx]);
+	set_din_sram(&desc[idx], aead_handle->sram_workspace_addr,
+		     digest_size);
+	set_flow_mode(&desc[idx], DIN_HASH);
+	idx++;
+
+	*seq_size = idx;
+}
+
+static void cc_mlli_to_sram(struct aead_request *req,
+			    struct cc_hw_desc desc[], unsigned int *seq_size)
+{
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	if (req_ctx->assoc_buff_type == CC_DMA_BUF_MLLI ||
+	    req_ctx->data_buff_type == CC_DMA_BUF_MLLI ||
+	    !req_ctx->is_single_pass) {
+		dev_dbg(dev, "Copy-to-sram: mlli_dma=%08x, mlli_size=%u\n",
+			(unsigned int)ctx->drvdata->mlli_sram_addr,
+			req_ctx->mlli_params.mlli_len);
+		/* Copy MLLI table host-to-sram */
+		hw_desc_init(&desc[*seq_size]);
+		set_din_type(&desc[*seq_size], DMA_DLLI,
+			     req_ctx->mlli_params.mlli_dma_addr,
+			     req_ctx->mlli_params.mlli_len, NS_BIT);
+		set_dout_sram(&desc[*seq_size],
+			      ctx->drvdata->mlli_sram_addr,
+			      req_ctx->mlli_params.mlli_len);
+		set_flow_mode(&desc[*seq_size], BYPASS);
+		(*seq_size)++;
+	}
+}
+
+static enum cc_flow_mode cc_get_data_flow(enum drv_crypto_direction direct,
+					  enum cc_flow_mode setup_flow_mode,
+					  bool is_single_pass)
+{
+	enum cc_flow_mode data_flow_mode;
+
+	if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+		if (setup_flow_mode == S_DIN_to_AES)
+			data_flow_mode = is_single_pass ?
+				AES_to_HASH_and_DOUT : DIN_AES_DOUT;
+		else
+			data_flow_mode = is_single_pass ?
+				DES_to_HASH_and_DOUT : DIN_DES_DOUT;
+	} else { /* Decrypt */
+		if (setup_flow_mode == S_DIN_to_AES)
+			data_flow_mode = is_single_pass ?
+				AES_and_HASH : DIN_AES_DOUT;
+		else
+			data_flow_mode = is_single_pass ?
+				DES_and_HASH : DIN_DES_DOUT;
+	}
+
+	return data_flow_mode;
+}
+
+static void cc_hmac_authenc(struct aead_request *req, struct cc_hw_desc desc[],
+			    unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	int direct = req_ctx->gen_ctx.op_type;
+	unsigned int data_flow_mode =
+		cc_get_data_flow(direct, ctx->flow_mode,
+				 req_ctx->is_single_pass);
+
+	if (req_ctx->is_single_pass) {
+		/**
+		 * Single-pass flow
+		 */
+		cc_set_hmac_desc(req, desc, seq_size);
+		cc_set_cipher_desc(req, desc, seq_size);
+		cc_proc_header_desc(req, desc, seq_size);
+		cc_proc_cipher_desc(req, data_flow_mode, desc, seq_size);
+		cc_proc_scheme_desc(req, desc, seq_size);
+		cc_proc_digest_desc(req, desc, seq_size);
+		return;
+	}
+
+	/**
+	 * Double-pass flow
+	 * Fallback for unsupported single-pass modes,
+	 * i.e. using assoc. data of non-word-multiple
+	 */
+	if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+		/* encrypt first.. */
+		cc_proc_cipher(req, desc, seq_size, data_flow_mode);
+		/* authenc after..*/
+		cc_set_hmac_desc(req, desc, seq_size);
+		cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct);
+		cc_proc_scheme_desc(req, desc, seq_size);
+		cc_proc_digest_desc(req, desc, seq_size);
+
+	} else { /*DECRYPT*/
+		/* authenc first..*/
+		cc_set_hmac_desc(req, desc, seq_size);
+		cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct);
+		cc_proc_scheme_desc(req, desc, seq_size);
+		/* decrypt after.. */
+		cc_proc_cipher(req, desc, seq_size, data_flow_mode);
+		/* read the digest result with setting the completion bit
+		 * must be after the cipher operation
+		 */
+		cc_proc_digest_desc(req, desc, seq_size);
+	}
+}
+
+static void
+cc_xcbc_authenc(struct aead_request *req, struct cc_hw_desc desc[],
+		unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	int direct = req_ctx->gen_ctx.op_type;
+	unsigned int data_flow_mode =
+		cc_get_data_flow(direct, ctx->flow_mode,
+				 req_ctx->is_single_pass);
+
+	if (req_ctx->is_single_pass) {
+		/**
+		 * Single-pass flow
+		 */
+		cc_set_xcbc_desc(req, desc, seq_size);
+		cc_set_cipher_desc(req, desc, seq_size);
+		cc_proc_header_desc(req, desc, seq_size);
+		cc_proc_cipher_desc(req, data_flow_mode, desc, seq_size);
+		cc_proc_digest_desc(req, desc, seq_size);
+		return;
+	}
+
+	/**
+	 * Double-pass flow
+	 * Fallback for unsupported single-pass modes,
+	 * i.e. using assoc. data of non-word-multiple
+	 */
+	if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+		/* encrypt first.. */
+		cc_proc_cipher(req, desc, seq_size, data_flow_mode);
+		/* authenc after.. */
+		cc_set_xcbc_desc(req, desc, seq_size);
+		cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct);
+		cc_proc_digest_desc(req, desc, seq_size);
+	} else { /*DECRYPT*/
+		/* authenc first.. */
+		cc_set_xcbc_desc(req, desc, seq_size);
+		cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct);
+		/* decrypt after..*/
+		cc_proc_cipher(req, desc, seq_size, data_flow_mode);
+		/* read the digest result with setting the completion bit
+		 * must be after the cipher operation
+		 */
+		cc_proc_digest_desc(req, desc, seq_size);
+	}
+}
+
+static int validate_data_size(struct cc_aead_ctx *ctx,
+			      enum drv_crypto_direction direct,
+			      struct aead_request *req)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	unsigned int assoclen = req->assoclen;
+	unsigned int cipherlen = (direct == DRV_CRYPTO_DIRECTION_DECRYPT) ?
+			(req->cryptlen - ctx->authsize) : req->cryptlen;
+
+	if (direct == DRV_CRYPTO_DIRECTION_DECRYPT &&
+	    req->cryptlen < ctx->authsize)
+		goto data_size_err;
+
+	areq_ctx->is_single_pass = true; /*defaulted to fast flow*/
+
+	switch (ctx->flow_mode) {
+	case S_DIN_to_AES:
+		if (ctx->cipher_mode == DRV_CIPHER_CBC &&
+		    !IS_ALIGNED(cipherlen, AES_BLOCK_SIZE))
+			goto data_size_err;
+		if (ctx->cipher_mode == DRV_CIPHER_CCM)
+			break;
+		if (ctx->cipher_mode == DRV_CIPHER_GCTR) {
+			if (areq_ctx->plaintext_authenticate_only)
+				areq_ctx->is_single_pass = false;
+			break;
+		}
+
+		if (!IS_ALIGNED(assoclen, sizeof(u32)))
+			areq_ctx->is_single_pass = false;
+
+		if (ctx->cipher_mode == DRV_CIPHER_CTR &&
+		    !IS_ALIGNED(cipherlen, sizeof(u32)))
+			areq_ctx->is_single_pass = false;
+
+		break;
+	case S_DIN_to_DES:
+		if (!IS_ALIGNED(cipherlen, DES_BLOCK_SIZE))
+			goto data_size_err;
+		if (!IS_ALIGNED(assoclen, DES_BLOCK_SIZE))
+			areq_ctx->is_single_pass = false;
+		break;
+	default:
+		dev_err(dev, "Unexpected flow mode (%d)\n", ctx->flow_mode);
+		goto data_size_err;
+	}
+
+	return 0;
+
+data_size_err:
+	return -EINVAL;
+}
+
+static unsigned int format_ccm_a0(u8 *pa0_buff, u32 header_size)
+{
+	unsigned int len = 0;
+
+	if (header_size == 0)
+		return 0;
+
+	if (header_size < ((1UL << 16) - (1UL << 8))) {
+		len = 2;
+
+		pa0_buff[0] = (header_size >> 8) & 0xFF;
+		pa0_buff[1] = header_size & 0xFF;
+	} else {
+		len = 6;
+
+		pa0_buff[0] = 0xFF;
+		pa0_buff[1] = 0xFE;
+		pa0_buff[2] = (header_size >> 24) & 0xFF;
+		pa0_buff[3] = (header_size >> 16) & 0xFF;
+		pa0_buff[4] = (header_size >> 8) & 0xFF;
+		pa0_buff[5] = header_size & 0xFF;
+	}
+
+	return len;
+}
+
+static int set_msg_len(u8 *block, unsigned int msglen, unsigned int csize)
+{
+	__be32 data;
+
+	memset(block, 0, csize);
+	block += csize;
+
+	if (csize >= 4)
+		csize = 4;
+	else if (msglen > (1 << (8 * csize)))
+		return -EOVERFLOW;
+
+	data = cpu_to_be32(msglen);
+	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+	return 0;
+}
+
+static int cc_ccm(struct aead_request *req, struct cc_hw_desc desc[],
+		  unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	unsigned int idx = *seq_size;
+	unsigned int cipher_flow_mode;
+	dma_addr_t mac_result;
+
+	if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+		cipher_flow_mode = AES_to_HASH_and_DOUT;
+		mac_result = req_ctx->mac_buf_dma_addr;
+	} else { /* Encrypt */
+		cipher_flow_mode = AES_and_HASH;
+		mac_result = req_ctx->icv_dma_addr;
+	}
+
+	/* load key */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CTR);
+	set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+		     ((ctx->enc_keylen == 24) ?  CC_AES_KEY_SIZE_MAX :
+		      ctx->enc_keylen), NS_BIT);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* load ctr state */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CTR);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     req_ctx->gen_ctx.iv_dma_addr, AES_BLOCK_SIZE, NS_BIT);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* load MAC key */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC);
+	set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+		     ((ctx->enc_keylen == 24) ?  CC_AES_KEY_SIZE_MAX :
+		      ctx->enc_keylen), NS_BIT);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	/* load MAC state */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr,
+		     AES_BLOCK_SIZE, NS_BIT);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	/* process assoc data */
+	if (req->assoclen > 0) {
+		cc_set_assoc_desc(req, DIN_HASH, desc, &idx);
+	} else {
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     sg_dma_address(&req_ctx->ccm_adata_sg),
+			     AES_BLOCK_SIZE + req_ctx->ccm_hdr_size, NS_BIT);
+		set_flow_mode(&desc[idx], DIN_HASH);
+		idx++;
+	}
+
+	/* process the cipher */
+	if (req_ctx->cryptlen)
+		cc_proc_cipher_desc(req, cipher_flow_mode, desc, &idx);
+
+	/* Read temporal MAC */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC);
+	set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr, ctx->authsize,
+		      NS_BIT, 0);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_cipher_config0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_aes_not_hash_mode(&desc[idx]);
+	idx++;
+
+	/* load AES-CTR state (for last MAC calculation)*/
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CTR);
+	set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->ccm_iv0_dma_addr,
+		     AES_BLOCK_SIZE, NS_BIT);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	hw_desc_init(&desc[idx]);
+	set_din_no_dma(&desc[idx], 0, 0xfffff0);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	idx++;
+
+	/* encrypt the "T" value and store MAC in mac_state */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr,
+		     ctx->authsize, NS_BIT);
+	set_dout_dlli(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], DIN_AES_DOUT);
+	idx++;
+
+	*seq_size = idx;
+	return 0;
+}
+
+static int config_ccm_adata(struct aead_request *req)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	//unsigned int size_of_a = 0, rem_a_size = 0;
+	unsigned int lp = req->iv[0];
+	/* Note: The code assume that req->iv[0] already contains the value
+	 * of L' of RFC3610
+	 */
+	unsigned int l = lp + 1;  /* This is L' of RFC 3610. */
+	unsigned int m = ctx->authsize;  /* This is M' of RFC 3610. */
+	u8 *b0 = req_ctx->ccm_config + CCM_B0_OFFSET;
+	u8 *a0 = req_ctx->ccm_config + CCM_A0_OFFSET;
+	u8 *ctr_count_0 = req_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET;
+	unsigned int cryptlen = (req_ctx->gen_ctx.op_type ==
+				 DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+				req->cryptlen :
+				(req->cryptlen - ctx->authsize);
+	int rc;
+
+	memset(req_ctx->mac_buf, 0, AES_BLOCK_SIZE);
+	memset(req_ctx->ccm_config, 0, AES_BLOCK_SIZE * 3);
+
+	/* taken from crypto/ccm.c */
+	/* 2 <= L <= 8, so 1 <= L' <= 7. */
+	if (l < 2 || l > 8) {
+		dev_err(dev, "illegal iv value %X\n", req->iv[0]);
+		return -EINVAL;
+	}
+	memcpy(b0, req->iv, AES_BLOCK_SIZE);
+
+	/* format control info per RFC 3610 and
+	 * NIST Special Publication 800-38C
+	 */
+	*b0 |= (8 * ((m - 2) / 2));
+	if (req->assoclen > 0)
+		*b0 |= 64;  /* Enable bit 6 if Adata exists. */
+
+	rc = set_msg_len(b0 + 16 - l, cryptlen, l);  /* Write L'. */
+	if (rc) {
+		dev_err(dev, "message len overflow detected");
+		return rc;
+	}
+	 /* END of "taken from crypto/ccm.c" */
+
+	/* l(a) - size of associated data. */
+	req_ctx->ccm_hdr_size = format_ccm_a0(a0, req->assoclen);
+
+	memset(req->iv + 15 - req->iv[0], 0, req->iv[0] + 1);
+	req->iv[15] = 1;
+
+	memcpy(ctr_count_0, req->iv, AES_BLOCK_SIZE);
+	ctr_count_0[15] = 0;
+
+	return 0;
+}
+
+static void cc_proc_rfc4309_ccm(struct aead_request *req)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+
+	/* L' */
+	memset(areq_ctx->ctr_iv, 0, AES_BLOCK_SIZE);
+	/* For RFC 4309, always use 4 bytes for message length
+	 * (at most 2^32-1 bytes).
+	 */
+	areq_ctx->ctr_iv[0] = 3;
+
+	/* In RFC 4309 there is an 11-bytes nonce+IV part,
+	 * that we build here.
+	 */
+	memcpy(areq_ctx->ctr_iv + CCM_BLOCK_NONCE_OFFSET, ctx->ctr_nonce,
+	       CCM_BLOCK_NONCE_SIZE);
+	memcpy(areq_ctx->ctr_iv + CCM_BLOCK_IV_OFFSET, req->iv,
+	       CCM_BLOCK_IV_SIZE);
+	req->iv = areq_ctx->ctr_iv;
+	req->assoclen -= CCM_BLOCK_IV_SIZE;
+}
+
+static void cc_set_ghash_desc(struct aead_request *req,
+			      struct cc_hw_desc desc[], unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	unsigned int idx = *seq_size;
+
+	/* load key to AES*/
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_ECB);
+	set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+		     ctx->enc_keylen, NS_BIT);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* process one zero block to generate hkey */
+	hw_desc_init(&desc[idx]);
+	set_din_const(&desc[idx], 0x0, AES_BLOCK_SIZE);
+	set_dout_dlli(&desc[idx], req_ctx->hkey_dma_addr, AES_BLOCK_SIZE,
+		      NS_BIT, 0);
+	set_flow_mode(&desc[idx], DIN_AES_DOUT);
+	idx++;
+
+	/* Memory Barrier */
+	hw_desc_init(&desc[idx]);
+	set_din_no_dma(&desc[idx], 0, 0xfffff0);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	idx++;
+
+	/* Load GHASH subkey */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->hkey_dma_addr,
+		     AES_BLOCK_SIZE, NS_BIT);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH);
+	set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	/* Configure Hash Engine to work with GHASH.
+	 * Since it was not possible to extend HASH submodes to add GHASH,
+	 * The following command is necessary in order to
+	 * select GHASH (according to HW designers)
+	 */
+	hw_desc_init(&desc[idx]);
+	set_din_no_dma(&desc[idx], 0, 0xfffff0);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH);
+	set_cipher_do(&desc[idx], 1); //1=AES_SK RKEK
+	set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	/* Load GHASH initial STATE (which is 0). (for any hash there is an
+	 * initial state)
+	 */
+	hw_desc_init(&desc[idx]);
+	set_din_const(&desc[idx], 0x0, AES_BLOCK_SIZE);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_aes_not_hash_mode(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH);
+	set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	idx++;
+
+	*seq_size = idx;
+}
+
+static void cc_set_gctr_desc(struct aead_request *req, struct cc_hw_desc desc[],
+			     unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	unsigned int idx = *seq_size;
+
+	/* load key to AES*/
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR);
+	set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+		     ctx->enc_keylen, NS_BIT);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	if (req_ctx->cryptlen && !req_ctx->plaintext_authenticate_only) {
+		/* load AES/CTR initial CTR value inc by 2*/
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR);
+		set_key_size_aes(&desc[idx], ctx->enc_keylen);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     req_ctx->gcm_iv_inc2_dma_addr, AES_BLOCK_SIZE,
+			     NS_BIT);
+		set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+		set_flow_mode(&desc[idx], S_DIN_to_AES);
+		idx++;
+	}
+
+	*seq_size = idx;
+}
+
+static void cc_proc_gcm_result(struct aead_request *req,
+			       struct cc_hw_desc desc[],
+			       unsigned int *seq_size)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	dma_addr_t mac_result;
+	unsigned int idx = *seq_size;
+
+	if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+		mac_result = req_ctx->mac_buf_dma_addr;
+	} else { /* Encrypt */
+		mac_result = req_ctx->icv_dma_addr;
+	}
+
+	/* process(ghash) gcm_block_len */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->gcm_block_len_dma_addr,
+		     AES_BLOCK_SIZE, NS_BIT);
+	set_flow_mode(&desc[idx], DIN_HASH);
+	idx++;
+
+	/* Store GHASH state after GHASH(Associated Data + Cipher +LenBlock) */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH);
+	set_din_no_dma(&desc[idx], 0, 0xfffff0);
+	set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr, AES_BLOCK_SIZE,
+		      NS_BIT, 0);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_aes_not_hash_mode(&desc[idx]);
+
+	idx++;
+
+	/* load AES/CTR initial CTR value inc by 1*/
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR);
+	set_key_size_aes(&desc[idx], ctx->enc_keylen);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->gcm_iv_inc1_dma_addr,
+		     AES_BLOCK_SIZE, NS_BIT);
+	set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* Memory Barrier */
+	hw_desc_init(&desc[idx]);
+	set_din_no_dma(&desc[idx], 0, 0xfffff0);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	idx++;
+
+	/* process GCTR on stored GHASH and store MAC in mac_state*/
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR);
+	set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr,
+		     AES_BLOCK_SIZE, NS_BIT);
+	set_dout_dlli(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], DIN_AES_DOUT);
+	idx++;
+
+	*seq_size = idx;
+}
+
+static int cc_gcm(struct aead_request *req, struct cc_hw_desc desc[],
+		  unsigned int *seq_size)
+{
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	unsigned int cipher_flow_mode;
+
+	if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+		cipher_flow_mode = AES_and_HASH;
+	} else { /* Encrypt */
+		cipher_flow_mode = AES_to_HASH_and_DOUT;
+	}
+
+	//in RFC4543 no data to encrypt. just copy data from src to dest.
+	if (req_ctx->plaintext_authenticate_only) {
+		cc_proc_cipher_desc(req, BYPASS, desc, seq_size);
+		cc_set_ghash_desc(req, desc, seq_size);
+		/* process(ghash) assoc data */
+		cc_set_assoc_desc(req, DIN_HASH, desc, seq_size);
+		cc_set_gctr_desc(req, desc, seq_size);
+		cc_proc_gcm_result(req, desc, seq_size);
+		return 0;
+	}
+
+	// for gcm and rfc4106.
+	cc_set_ghash_desc(req, desc, seq_size);
+	/* process(ghash) assoc data */
+	if (req->assoclen > 0)
+		cc_set_assoc_desc(req, DIN_HASH, desc, seq_size);
+	cc_set_gctr_desc(req, desc, seq_size);
+	/* process(gctr+ghash) */
+	if (req_ctx->cryptlen)
+		cc_proc_cipher_desc(req, cipher_flow_mode, desc, seq_size);
+	cc_proc_gcm_result(req, desc, seq_size);
+
+	return 0;
+}
+
+static int config_gcm_context(struct aead_request *req)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	unsigned int cryptlen = (req_ctx->gen_ctx.op_type ==
+				 DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+				req->cryptlen :
+				(req->cryptlen - ctx->authsize);
+	__be32 counter = cpu_to_be32(2);
+
+	dev_dbg(dev, "%s() cryptlen = %d, req->assoclen = %d ctx->authsize = %d\n",
+		__func__, cryptlen, req->assoclen, ctx->authsize);
+
+	memset(req_ctx->hkey, 0, AES_BLOCK_SIZE);
+
+	memset(req_ctx->mac_buf, 0, AES_BLOCK_SIZE);
+
+	memcpy(req->iv + 12, &counter, 4);
+	memcpy(req_ctx->gcm_iv_inc2, req->iv, 16);
+
+	counter = cpu_to_be32(1);
+	memcpy(req->iv + 12, &counter, 4);
+	memcpy(req_ctx->gcm_iv_inc1, req->iv, 16);
+
+	if (!req_ctx->plaintext_authenticate_only) {
+		__be64 temp64;
+
+		temp64 = cpu_to_be64(req->assoclen * 8);
+		memcpy(&req_ctx->gcm_len_block.len_a, &temp64, sizeof(temp64));
+		temp64 = cpu_to_be64(cryptlen * 8);
+		memcpy(&req_ctx->gcm_len_block.len_c, &temp64, 8);
+	} else {
+		/* rfc4543=>  all data(AAD,IV,Plain) are considered additional
+		 * data that is nothing is encrypted.
+		 */
+		__be64 temp64;
+
+		temp64 = cpu_to_be64((req->assoclen + GCM_BLOCK_RFC4_IV_SIZE +
+				      cryptlen) * 8);
+		memcpy(&req_ctx->gcm_len_block.len_a, &temp64, sizeof(temp64));
+		temp64 = 0;
+		memcpy(&req_ctx->gcm_len_block.len_c, &temp64, 8);
+	}
+
+	return 0;
+}
+
+static void cc_proc_rfc4_gcm(struct aead_request *req)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+
+	memcpy(areq_ctx->ctr_iv + GCM_BLOCK_RFC4_NONCE_OFFSET,
+	       ctx->ctr_nonce, GCM_BLOCK_RFC4_NONCE_SIZE);
+	memcpy(areq_ctx->ctr_iv + GCM_BLOCK_RFC4_IV_OFFSET, req->iv,
+	       GCM_BLOCK_RFC4_IV_SIZE);
+	req->iv = areq_ctx->ctr_iv;
+	req->assoclen -= GCM_BLOCK_RFC4_IV_SIZE;
+}
+
+static int cc_proc_aead(struct aead_request *req,
+			enum drv_crypto_direction direct)
+{
+	int rc = 0;
+	int seq_len = 0;
+	struct cc_hw_desc desc[MAX_AEAD_PROCESS_SEQ];
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct cc_crypto_req cc_req = {};
+
+	dev_dbg(dev, "%s context=%p req=%p iv=%p src=%p src_ofs=%d dst=%p dst_ofs=%d cryptolen=%d\n",
+		((direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? "Enc" : "Dec"),
+		ctx, req, req->iv, sg_virt(req->src), req->src->offset,
+		sg_virt(req->dst), req->dst->offset, req->cryptlen);
+
+	/* STAT_PHASE_0: Init and sanity checks */
+
+	/* Check data length according to mode */
+	if (validate_data_size(ctx, direct, req)) {
+		dev_err(dev, "Unsupported crypt/assoc len %d/%d.\n",
+			req->cryptlen, req->assoclen);
+		crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN);
+		return -EINVAL;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = (void *)cc_aead_complete;
+	cc_req.user_arg = (void *)req;
+
+	/* Setup request context */
+	areq_ctx->gen_ctx.op_type = direct;
+	areq_ctx->req_authsize = ctx->authsize;
+	areq_ctx->cipher_mode = ctx->cipher_mode;
+
+	/* STAT_PHASE_1: Map buffers */
+
+	if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+		/* Build CTR IV - Copy nonce from last 4 bytes in
+		 * CTR key to first 4 bytes in CTR IV
+		 */
+		memcpy(areq_ctx->ctr_iv, ctx->ctr_nonce,
+		       CTR_RFC3686_NONCE_SIZE);
+		if (!areq_ctx->backup_giv) /*User none-generated IV*/
+			memcpy(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE,
+			       req->iv, CTR_RFC3686_IV_SIZE);
+		/* Initialize counter portion of counter block */
+		*(__be32 *)(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE +
+			    CTR_RFC3686_IV_SIZE) = cpu_to_be32(1);
+
+		/* Replace with counter iv */
+		req->iv = areq_ctx->ctr_iv;
+		areq_ctx->hw_iv_size = CTR_RFC3686_BLOCK_SIZE;
+	} else if ((ctx->cipher_mode == DRV_CIPHER_CCM) ||
+		   (ctx->cipher_mode == DRV_CIPHER_GCTR)) {
+		areq_ctx->hw_iv_size = AES_BLOCK_SIZE;
+		if (areq_ctx->ctr_iv != req->iv) {
+			memcpy(areq_ctx->ctr_iv, req->iv,
+			       crypto_aead_ivsize(tfm));
+			req->iv = areq_ctx->ctr_iv;
+		}
+	}  else {
+		areq_ctx->hw_iv_size = crypto_aead_ivsize(tfm);
+	}
+
+	if (ctx->cipher_mode == DRV_CIPHER_CCM) {
+		rc = config_ccm_adata(req);
+		if (rc) {
+			dev_dbg(dev, "config_ccm_adata() returned with a failure %d!",
+				rc);
+			goto exit;
+		}
+	} else {
+		areq_ctx->ccm_hdr_size = ccm_header_size_null;
+	}
+
+	if (ctx->cipher_mode == DRV_CIPHER_GCTR) {
+		rc = config_gcm_context(req);
+		if (rc) {
+			dev_dbg(dev, "config_gcm_context() returned with a failure %d!",
+				rc);
+			goto exit;
+		}
+	}
+
+	rc = cc_map_aead_request(ctx->drvdata, req);
+	if (rc) {
+		dev_err(dev, "map_request() failed\n");
+		goto exit;
+	}
+
+	/* do we need to generate IV? */
+	if (areq_ctx->backup_giv) {
+		/* set the DMA mapped IV address*/
+		if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+			cc_req.ivgen_dma_addr[0] =
+				areq_ctx->gen_ctx.iv_dma_addr +
+				CTR_RFC3686_NONCE_SIZE;
+			cc_req.ivgen_dma_addr_len = 1;
+		} else if (ctx->cipher_mode == DRV_CIPHER_CCM) {
+			/* In ccm, the IV needs to exist both inside B0 and
+			 * inside the counter.It is also copied to iv_dma_addr
+			 * for other reasons (like returning it to the user).
+			 * So, using 3 (identical) IV outputs.
+			 */
+			cc_req.ivgen_dma_addr[0] =
+				areq_ctx->gen_ctx.iv_dma_addr +
+				CCM_BLOCK_IV_OFFSET;
+			cc_req.ivgen_dma_addr[1] =
+				sg_dma_address(&areq_ctx->ccm_adata_sg) +
+				CCM_B0_OFFSET + CCM_BLOCK_IV_OFFSET;
+			cc_req.ivgen_dma_addr[2] =
+				sg_dma_address(&areq_ctx->ccm_adata_sg) +
+				CCM_CTR_COUNT_0_OFFSET + CCM_BLOCK_IV_OFFSET;
+			cc_req.ivgen_dma_addr_len = 3;
+		} else {
+			cc_req.ivgen_dma_addr[0] =
+				areq_ctx->gen_ctx.iv_dma_addr;
+			cc_req.ivgen_dma_addr_len = 1;
+		}
+
+		/* set the IV size (8/16 B long)*/
+		cc_req.ivgen_size = crypto_aead_ivsize(tfm);
+	}
+
+	/* STAT_PHASE_2: Create sequence */
+
+	/* Load MLLI tables to SRAM if necessary */
+	cc_mlli_to_sram(req, desc, &seq_len);
+
+	/*TODO: move seq len by reference */
+	switch (ctx->auth_mode) {
+	case DRV_HASH_SHA1:
+	case DRV_HASH_SHA256:
+		cc_hmac_authenc(req, desc, &seq_len);
+		break;
+	case DRV_HASH_XCBC_MAC:
+		cc_xcbc_authenc(req, desc, &seq_len);
+		break;
+	case DRV_HASH_NULL:
+		if (ctx->cipher_mode == DRV_CIPHER_CCM)
+			cc_ccm(req, desc, &seq_len);
+		if (ctx->cipher_mode == DRV_CIPHER_GCTR)
+			cc_gcm(req, desc, &seq_len);
+		break;
+	default:
+		dev_err(dev, "Unsupported authenc (%d)\n", ctx->auth_mode);
+		cc_unmap_aead_request(dev, req);
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	/* STAT_PHASE_3: Lock HW and push sequence */
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, seq_len, &req->base);
+
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_aead_request(dev, req);
+	}
+
+exit:
+	return rc;
+}
+
+static int cc_aead_encrypt(struct aead_request *req)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc;
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+	areq_ctx->is_gcm4543 = false;
+
+	areq_ctx->plaintext_authenticate_only = false;
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+
+	return rc;
+}
+
+static int cc_rfc4309_ccm_encrypt(struct aead_request *req)
+{
+	/* Very similar to cc_aead_encrypt() above. */
+
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	int rc = -EINVAL;
+
+	if (!valid_assoclen(req)) {
+		dev_err(dev, "invalid Assoclen:%u\n", req->assoclen);
+		goto out;
+	}
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+	areq_ctx->is_gcm4543 = true;
+
+	cc_proc_rfc4309_ccm(req);
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+out:
+	return rc;
+}
+
+static int cc_aead_decrypt(struct aead_request *req)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc;
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+	areq_ctx->is_gcm4543 = false;
+
+	areq_ctx->plaintext_authenticate_only = false;
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+
+	return rc;
+}
+
+static int cc_rfc4309_ccm_decrypt(struct aead_request *req)
+{
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc = -EINVAL;
+
+	if (!valid_assoclen(req)) {
+		dev_err(dev, "invalid Assoclen:%u\n", req->assoclen);
+		goto out;
+	}
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+
+	areq_ctx->is_gcm4543 = true;
+	cc_proc_rfc4309_ccm(req);
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+
+out:
+	return rc;
+}
+
+static int cc_rfc4106_gcm_setkey(struct crypto_aead *tfm, const u8 *key,
+				 unsigned int keylen)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "%s()  keylen %d, key %p\n", __func__, keylen, key);
+
+	if (keylen < 4)
+		return -EINVAL;
+
+	keylen -= 4;
+	memcpy(ctx->ctr_nonce, key + keylen, 4);
+
+	return cc_aead_setkey(tfm, key, keylen);
+}
+
+static int cc_rfc4543_gcm_setkey(struct crypto_aead *tfm, const u8 *key,
+				 unsigned int keylen)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "%s()  keylen %d, key %p\n", __func__, keylen, key);
+
+	if (keylen < 4)
+		return -EINVAL;
+
+	keylen -= 4;
+	memcpy(ctx->ctr_nonce, key + keylen, 4);
+
+	return cc_aead_setkey(tfm, key, keylen);
+}
+
+static int cc_gcm_setauthsize(struct crypto_aead *authenc,
+			      unsigned int authsize)
+{
+	switch (authsize) {
+	case 4:
+	case 8:
+	case 12:
+	case 13:
+	case 14:
+	case 15:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return cc_aead_setauthsize(authenc, authsize);
+}
+
+static int cc_rfc4106_gcm_setauthsize(struct crypto_aead *authenc,
+				      unsigned int authsize)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(authenc);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "authsize %d\n", authsize);
+
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return cc_aead_setauthsize(authenc, authsize);
+}
+
+static int cc_rfc4543_gcm_setauthsize(struct crypto_aead *authenc,
+				      unsigned int authsize)
+{
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(authenc);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "authsize %d\n", authsize);
+
+	if (authsize != 16)
+		return -EINVAL;
+
+	return cc_aead_setauthsize(authenc, authsize);
+}
+
+static int cc_rfc4106_gcm_encrypt(struct aead_request *req)
+{
+	/* Very similar to cc_aead_encrypt() above. */
+
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc = -EINVAL;
+
+	if (!valid_assoclen(req)) {
+		dev_err(dev, "invalid Assoclen:%u\n", req->assoclen);
+		goto out;
+	}
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+
+	areq_ctx->plaintext_authenticate_only = false;
+
+	cc_proc_rfc4_gcm(req);
+	areq_ctx->is_gcm4543 = true;
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+out:
+	return rc;
+}
+
+static int cc_rfc4543_gcm_encrypt(struct aead_request *req)
+{
+	/* Very similar to cc_aead_encrypt() above. */
+
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc;
+
+	//plaintext is not encryped with rfc4543
+	areq_ctx->plaintext_authenticate_only = true;
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+
+	cc_proc_rfc4_gcm(req);
+	areq_ctx->is_gcm4543 = true;
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+
+	return rc;
+}
+
+static int cc_rfc4106_gcm_decrypt(struct aead_request *req)
+{
+	/* Very similar to cc_aead_decrypt() above. */
+
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc = -EINVAL;
+
+	if (!valid_assoclen(req)) {
+		dev_err(dev, "invalid Assoclen:%u\n", req->assoclen);
+		goto out;
+	}
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+
+	areq_ctx->plaintext_authenticate_only = false;
+
+	cc_proc_rfc4_gcm(req);
+	areq_ctx->is_gcm4543 = true;
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+out:
+	return rc;
+}
+
+static int cc_rfc4543_gcm_decrypt(struct aead_request *req)
+{
+	/* Very similar to cc_aead_decrypt() above. */
+
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc;
+
+	//plaintext is not decryped with rfc4543
+	areq_ctx->plaintext_authenticate_only = true;
+
+	/* No generated IV required */
+	areq_ctx->backup_iv = req->iv;
+	areq_ctx->backup_giv = NULL;
+
+	cc_proc_rfc4_gcm(req);
+	areq_ctx->is_gcm4543 = true;
+
+	rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+	if (rc != -EINPROGRESS && rc != -EBUSY)
+		req->iv = areq_ctx->backup_iv;
+
+	return rc;
+}
+
+/* aead alg */
+static struct cc_alg_template aead_algs[] = {
+	{
+		.name = "authenc(hmac(sha1),cbc(aes))",
+		.driver_name = "authenc-hmac-sha1-cbc-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = AES_BLOCK_SIZE,
+			.maxauthsize = SHA1_DIGEST_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_SHA1,
+	},
+	{
+		.name = "authenc(hmac(sha1),cbc(des3_ede))",
+		.driver_name = "authenc-hmac-sha1-cbc-des3-ccree",
+		.blocksize = DES3_EDE_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = DES3_EDE_BLOCK_SIZE,
+			.maxauthsize = SHA1_DIGEST_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_DES,
+		.auth_mode = DRV_HASH_SHA1,
+	},
+	{
+		.name = "authenc(hmac(sha256),cbc(aes))",
+		.driver_name = "authenc-hmac-sha256-cbc-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = AES_BLOCK_SIZE,
+			.maxauthsize = SHA256_DIGEST_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_SHA256,
+	},
+	{
+		.name = "authenc(hmac(sha256),cbc(des3_ede))",
+		.driver_name = "authenc-hmac-sha256-cbc-des3-ccree",
+		.blocksize = DES3_EDE_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = DES3_EDE_BLOCK_SIZE,
+			.maxauthsize = SHA256_DIGEST_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_DES,
+		.auth_mode = DRV_HASH_SHA256,
+	},
+	{
+		.name = "authenc(xcbc(aes),cbc(aes))",
+		.driver_name = "authenc-xcbc-aes-cbc-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = AES_BLOCK_SIZE,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_XCBC_MAC,
+	},
+	{
+		.name = "authenc(hmac(sha1),rfc3686(ctr(aes)))",
+		.driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = CTR_RFC3686_IV_SIZE,
+			.maxauthsize = SHA1_DIGEST_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CTR,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_SHA1,
+	},
+	{
+		.name = "authenc(hmac(sha256),rfc3686(ctr(aes)))",
+		.driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = CTR_RFC3686_IV_SIZE,
+			.maxauthsize = SHA256_DIGEST_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CTR,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_SHA256,
+	},
+	{
+		.name = "authenc(xcbc(aes),rfc3686(ctr(aes)))",
+		.driver_name = "authenc-xcbc-aes-rfc3686-ctr-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_aead_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = CTR_RFC3686_IV_SIZE,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CTR,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_XCBC_MAC,
+	},
+	{
+		.name = "ccm(aes)",
+		.driver_name = "ccm-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_ccm_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = AES_BLOCK_SIZE,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CCM,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_NULL,
+	},
+	{
+		.name = "rfc4309(ccm(aes))",
+		.driver_name = "rfc4309-ccm-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_rfc4309_ccm_setkey,
+			.setauthsize = cc_rfc4309_ccm_setauthsize,
+			.encrypt = cc_rfc4309_ccm_encrypt,
+			.decrypt = cc_rfc4309_ccm_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = CCM_BLOCK_IV_SIZE,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CCM,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_NULL,
+	},
+	{
+		.name = "gcm(aes)",
+		.driver_name = "gcm-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_aead_setkey,
+			.setauthsize = cc_gcm_setauthsize,
+			.encrypt = cc_aead_encrypt,
+			.decrypt = cc_aead_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = 12,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_GCTR,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_NULL,
+	},
+	{
+		.name = "rfc4106(gcm(aes))",
+		.driver_name = "rfc4106-gcm-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_rfc4106_gcm_setkey,
+			.setauthsize = cc_rfc4106_gcm_setauthsize,
+			.encrypt = cc_rfc4106_gcm_encrypt,
+			.decrypt = cc_rfc4106_gcm_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = GCM_BLOCK_RFC4_IV_SIZE,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_GCTR,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_NULL,
+	},
+	{
+		.name = "rfc4543(gcm(aes))",
+		.driver_name = "rfc4543-gcm-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_AEAD,
+		.template_aead = {
+			.setkey = cc_rfc4543_gcm_setkey,
+			.setauthsize = cc_rfc4543_gcm_setauthsize,
+			.encrypt = cc_rfc4543_gcm_encrypt,
+			.decrypt = cc_rfc4543_gcm_decrypt,
+			.init = cc_aead_init,
+			.exit = cc_aead_exit,
+			.ivsize = GCM_BLOCK_RFC4_IV_SIZE,
+			.maxauthsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_GCTR,
+		.flow_mode = S_DIN_to_AES,
+		.auth_mode = DRV_HASH_NULL,
+	},
+};
+
+static struct cc_crypto_alg *cc_create_aead_alg(struct cc_alg_template *tmpl,
+						struct device *dev)
+{
+	struct cc_crypto_alg *t_alg;
+	struct aead_alg *alg;
+
+	t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
+	if (!t_alg)
+		return ERR_PTR(-ENOMEM);
+
+	alg = &tmpl->template_aead;
+
+	snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
+	snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+		 tmpl->driver_name);
+	alg->base.cra_module = THIS_MODULE;
+	alg->base.cra_priority = CC_CRA_PRIO;
+
+	alg->base.cra_ctxsize = sizeof(struct cc_aead_ctx);
+	alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+			 tmpl->type;
+	alg->init = cc_aead_init;
+	alg->exit = cc_aead_exit;
+
+	t_alg->aead_alg = *alg;
+
+	t_alg->cipher_mode = tmpl->cipher_mode;
+	t_alg->flow_mode = tmpl->flow_mode;
+	t_alg->auth_mode = tmpl->auth_mode;
+
+	return t_alg;
+}
+
+int cc_aead_free(struct cc_drvdata *drvdata)
+{
+	struct cc_crypto_alg *t_alg, *n;
+	struct cc_aead_handle *aead_handle =
+		(struct cc_aead_handle *)drvdata->aead_handle;
+
+	if (aead_handle) {
+		/* Remove registered algs */
+		list_for_each_entry_safe(t_alg, n, &aead_handle->aead_list,
+					 entry) {
+			crypto_unregister_aead(&t_alg->aead_alg);
+			list_del(&t_alg->entry);
+			kfree(t_alg);
+		}
+		kfree(aead_handle);
+		drvdata->aead_handle = NULL;
+	}
+
+	return 0;
+}
+
+int cc_aead_alloc(struct cc_drvdata *drvdata)
+{
+	struct cc_aead_handle *aead_handle;
+	struct cc_crypto_alg *t_alg;
+	int rc = -ENOMEM;
+	int alg;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	aead_handle = kmalloc(sizeof(*aead_handle), GFP_KERNEL);
+	if (!aead_handle) {
+		rc = -ENOMEM;
+		goto fail0;
+	}
+
+	INIT_LIST_HEAD(&aead_handle->aead_list);
+	drvdata->aead_handle = aead_handle;
+
+	aead_handle->sram_workspace_addr = cc_sram_alloc(drvdata,
+							 MAX_HMAC_DIGEST_SIZE);
+
+	if (aead_handle->sram_workspace_addr == NULL_SRAM_ADDR) {
+		dev_err(dev, "SRAM pool exhausted\n");
+		rc = -ENOMEM;
+		goto fail1;
+	}
+
+	/* Linux crypto */
+	for (alg = 0; alg < ARRAY_SIZE(aead_algs); alg++) {
+		t_alg = cc_create_aead_alg(&aead_algs[alg], dev);
+		if (IS_ERR(t_alg)) {
+			rc = PTR_ERR(t_alg);
+			dev_err(dev, "%s alg allocation failed\n",
+				aead_algs[alg].driver_name);
+			goto fail1;
+		}
+		t_alg->drvdata = drvdata;
+		rc = crypto_register_aead(&t_alg->aead_alg);
+		if (rc) {
+			dev_err(dev, "%s alg registration failed\n",
+				t_alg->aead_alg.base.cra_driver_name);
+			goto fail2;
+		} else {
+			list_add_tail(&t_alg->entry, &aead_handle->aead_list);
+			dev_dbg(dev, "Registered %s\n",
+				t_alg->aead_alg.base.cra_driver_name);
+		}
+	}
+
+	return 0;
+
+fail2:
+	kfree(t_alg);
+fail1:
+	cc_aead_free(drvdata);
+fail0:
+	return rc;
+}
diff --git a/drivers/crypto/ccree/cc_aead.h b/drivers/crypto/ccree/cc_aead.h
new file mode 100644
index 000000000000..5edf3b351fa4
--- /dev/null
+++ b/drivers/crypto/ccree/cc_aead.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_aead.h
+ * ARM CryptoCell AEAD Crypto API
+ */
+
+#ifndef __CC_AEAD_H__
+#define __CC_AEAD_H__
+
+#include <linux/kernel.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+
+/* mac_cmp - HW writes 8 B but all bytes hold the same value */
+#define ICV_CMP_SIZE 8
+#define CCM_CONFIG_BUF_SIZE (AES_BLOCK_SIZE * 3)
+#define MAX_MAC_SIZE SHA256_DIGEST_SIZE
+
+/* defines for AES GCM configuration buffer */
+#define GCM_BLOCK_LEN_SIZE 8
+
+#define GCM_BLOCK_RFC4_IV_OFFSET	4
+#define GCM_BLOCK_RFC4_IV_SIZE		8  /* IV size for rfc's */
+#define GCM_BLOCK_RFC4_NONCE_OFFSET	0
+#define GCM_BLOCK_RFC4_NONCE_SIZE	4
+
+/* Offsets into AES CCM configuration buffer */
+#define CCM_B0_OFFSET 0
+#define CCM_A0_OFFSET 16
+#define CCM_CTR_COUNT_0_OFFSET 32
+/* CCM B0 and CTR_COUNT constants. */
+#define CCM_BLOCK_NONCE_OFFSET 1  /* Nonce offset inside B0 and CTR_COUNT */
+#define CCM_BLOCK_NONCE_SIZE   3  /* Nonce size inside B0 and CTR_COUNT */
+#define CCM_BLOCK_IV_OFFSET    4  /* IV offset inside B0 and CTR_COUNT */
+#define CCM_BLOCK_IV_SIZE      8  /* IV size inside B0 and CTR_COUNT */
+
+enum aead_ccm_header_size {
+	ccm_header_size_null = -1,
+	ccm_header_size_zero = 0,
+	ccm_header_size_2 = 2,
+	ccm_header_size_6 = 6,
+	ccm_header_size_max = S32_MAX
+};
+
+struct aead_req_ctx {
+	/* Allocate cache line although only 4 bytes are needed to
+	 *  assure next field falls @ cache line
+	 *  Used for both: digest HW compare and CCM/GCM MAC value
+	 */
+	u8 mac_buf[MAX_MAC_SIZE] ____cacheline_aligned;
+	u8 ctr_iv[AES_BLOCK_SIZE] ____cacheline_aligned;
+
+	//used in gcm
+	u8 gcm_iv_inc1[AES_BLOCK_SIZE] ____cacheline_aligned;
+	u8 gcm_iv_inc2[AES_BLOCK_SIZE] ____cacheline_aligned;
+	u8 hkey[AES_BLOCK_SIZE] ____cacheline_aligned;
+	struct {
+		u8 len_a[GCM_BLOCK_LEN_SIZE] ____cacheline_aligned;
+		u8 len_c[GCM_BLOCK_LEN_SIZE];
+	} gcm_len_block;
+
+	u8 ccm_config[CCM_CONFIG_BUF_SIZE] ____cacheline_aligned;
+	/* HW actual size input */
+	unsigned int hw_iv_size ____cacheline_aligned;
+	/* used to prevent cache coherence problem */
+	u8 backup_mac[MAX_MAC_SIZE];
+	u8 *backup_iv; /*store iv for generated IV flow*/
+	u8 *backup_giv; /*store iv for rfc3686(ctr) flow*/
+	dma_addr_t mac_buf_dma_addr; /* internal ICV DMA buffer */
+	/* buffer for internal ccm configurations */
+	dma_addr_t ccm_iv0_dma_addr;
+	dma_addr_t icv_dma_addr; /* Phys. address of ICV */
+
+	//used in gcm
+	/* buffer for internal gcm configurations */
+	dma_addr_t gcm_iv_inc1_dma_addr;
+	/* buffer for internal gcm configurations */
+	dma_addr_t gcm_iv_inc2_dma_addr;
+	dma_addr_t hkey_dma_addr; /* Phys. address of hkey */
+	dma_addr_t gcm_block_len_dma_addr; /* Phys. address of gcm block len */
+	bool is_gcm4543;
+
+	u8 *icv_virt_addr; /* Virt. address of ICV */
+	struct async_gen_req_ctx gen_ctx;
+	struct cc_mlli assoc;
+	struct cc_mlli src;
+	struct cc_mlli dst;
+	struct scatterlist *src_sgl;
+	struct scatterlist *dst_sgl;
+	unsigned int src_offset;
+	unsigned int dst_offset;
+	enum cc_req_dma_buf_type assoc_buff_type;
+	enum cc_req_dma_buf_type data_buff_type;
+	struct mlli_params mlli_params;
+	unsigned int cryptlen;
+	struct scatterlist ccm_adata_sg;
+	enum aead_ccm_header_size ccm_hdr_size;
+	unsigned int req_authsize;
+	enum drv_cipher_mode cipher_mode;
+	bool is_icv_fragmented;
+	bool is_single_pass;
+	bool plaintext_authenticate_only; //for gcm_rfc4543
+};
+
+int cc_aead_alloc(struct cc_drvdata *drvdata);
+int cc_aead_free(struct cc_drvdata *drvdata);
+
+#endif /*__CC_AEAD_H__*/
diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c
new file mode 100644
index 000000000000..b32577477b4c
--- /dev/null
+++ b/drivers/crypto/ccree/cc_buffer_mgr.c
@@ -0,0 +1,1651 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <crypto/internal/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+
+#include "cc_buffer_mgr.h"
+#include "cc_lli_defs.h"
+#include "cc_cipher.h"
+#include "cc_hash.h"
+#include "cc_aead.h"
+
+enum dma_buffer_type {
+	DMA_NULL_TYPE = -1,
+	DMA_SGL_TYPE = 1,
+	DMA_BUFF_TYPE = 2,
+};
+
+struct buff_mgr_handle {
+	struct dma_pool *mlli_buffs_pool;
+};
+
+union buffer_array_entry {
+	struct scatterlist *sgl;
+	dma_addr_t buffer_dma;
+};
+
+struct buffer_array {
+	unsigned int num_of_buffers;
+	union buffer_array_entry entry[MAX_NUM_OF_BUFFERS_IN_MLLI];
+	unsigned int offset[MAX_NUM_OF_BUFFERS_IN_MLLI];
+	int nents[MAX_NUM_OF_BUFFERS_IN_MLLI];
+	int total_data_len[MAX_NUM_OF_BUFFERS_IN_MLLI];
+	enum dma_buffer_type type[MAX_NUM_OF_BUFFERS_IN_MLLI];
+	bool is_last[MAX_NUM_OF_BUFFERS_IN_MLLI];
+	u32 *mlli_nents[MAX_NUM_OF_BUFFERS_IN_MLLI];
+};
+
+static inline char *cc_dma_buf_type(enum cc_req_dma_buf_type type)
+{
+	switch (type) {
+	case CC_DMA_BUF_NULL:
+		return "BUF_NULL";
+	case CC_DMA_BUF_DLLI:
+		return "BUF_DLLI";
+	case CC_DMA_BUF_MLLI:
+		return "BUF_MLLI";
+	default:
+		return "BUF_INVALID";
+	}
+}
+
+/**
+ * cc_copy_mac() - Copy MAC to temporary location
+ *
+ * @dev: device object
+ * @req: aead request object
+ * @dir: [IN] copy from/to sgl
+ */
+static void cc_copy_mac(struct device *dev, struct aead_request *req,
+			enum cc_sg_cpy_direct dir)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	u32 skip = req->assoclen + req->cryptlen;
+
+	if (areq_ctx->is_gcm4543)
+		skip += crypto_aead_ivsize(tfm);
+
+	cc_copy_sg_portion(dev, areq_ctx->backup_mac, req->src,
+			   (skip - areq_ctx->req_authsize), skip, dir);
+}
+
+/**
+ * cc_get_sgl_nents() - Get scatterlist number of entries.
+ *
+ * @sg_list: SG list
+ * @nbytes: [IN] Total SGL data bytes.
+ * @lbytes: [OUT] Returns the amount of bytes at the last entry
+ */
+static unsigned int cc_get_sgl_nents(struct device *dev,
+				     struct scatterlist *sg_list,
+				     unsigned int nbytes, u32 *lbytes,
+				     bool *is_chained)
+{
+	unsigned int nents = 0;
+
+	while (nbytes && sg_list) {
+		if (sg_list->length) {
+			nents++;
+			/* get the number of bytes in the last entry */
+			*lbytes = nbytes;
+			nbytes -= (sg_list->length > nbytes) ?
+					nbytes : sg_list->length;
+			sg_list = sg_next(sg_list);
+		} else {
+			sg_list = (struct scatterlist *)sg_page(sg_list);
+			if (is_chained)
+				*is_chained = true;
+		}
+	}
+	dev_dbg(dev, "nents %d last bytes %d\n", nents, *lbytes);
+	return nents;
+}
+
+/**
+ * cc_zero_sgl() - Zero scatter scatter list data.
+ *
+ * @sgl:
+ */
+void cc_zero_sgl(struct scatterlist *sgl, u32 data_len)
+{
+	struct scatterlist *current_sg = sgl;
+	int sg_index = 0;
+
+	while (sg_index <= data_len) {
+		if (!current_sg) {
+			/* reached the end of the sgl --> just return back */
+			return;
+		}
+		memset(sg_virt(current_sg), 0, current_sg->length);
+		sg_index += current_sg->length;
+		current_sg = sg_next(current_sg);
+	}
+}
+
+/**
+ * cc_copy_sg_portion() - Copy scatter list data,
+ * from to_skip to end, to dest and vice versa
+ *
+ * @dest:
+ * @sg:
+ * @to_skip:
+ * @end:
+ * @direct:
+ */
+void cc_copy_sg_portion(struct device *dev, u8 *dest, struct scatterlist *sg,
+			u32 to_skip, u32 end, enum cc_sg_cpy_direct direct)
+{
+	u32 nents, lbytes;
+
+	nents = cc_get_sgl_nents(dev, sg, end, &lbytes, NULL);
+	sg_copy_buffer(sg, nents, (void *)dest, (end - to_skip + 1), to_skip,
+		       (direct == CC_SG_TO_BUF));
+}
+
+static int cc_render_buff_to_mlli(struct device *dev, dma_addr_t buff_dma,
+				  u32 buff_size, u32 *curr_nents,
+				  u32 **mlli_entry_pp)
+{
+	u32 *mlli_entry_p = *mlli_entry_pp;
+	u32 new_nents;
+
+	/* Verify there is no memory overflow*/
+	new_nents = (*curr_nents + buff_size / CC_MAX_MLLI_ENTRY_SIZE + 1);
+	if (new_nents > MAX_NUM_OF_TOTAL_MLLI_ENTRIES)
+		return -ENOMEM;
+
+	/*handle buffer longer than 64 kbytes */
+	while (buff_size > CC_MAX_MLLI_ENTRY_SIZE) {
+		cc_lli_set_addr(mlli_entry_p, buff_dma);
+		cc_lli_set_size(mlli_entry_p, CC_MAX_MLLI_ENTRY_SIZE);
+		dev_dbg(dev, "entry[%d]: single_buff=0x%08X size=%08X\n",
+			*curr_nents, mlli_entry_p[LLI_WORD0_OFFSET],
+			mlli_entry_p[LLI_WORD1_OFFSET]);
+		buff_dma += CC_MAX_MLLI_ENTRY_SIZE;
+		buff_size -= CC_MAX_MLLI_ENTRY_SIZE;
+		mlli_entry_p = mlli_entry_p + 2;
+		(*curr_nents)++;
+	}
+	/*Last entry */
+	cc_lli_set_addr(mlli_entry_p, buff_dma);
+	cc_lli_set_size(mlli_entry_p, buff_size);
+	dev_dbg(dev, "entry[%d]: single_buff=0x%08X size=%08X\n",
+		*curr_nents, mlli_entry_p[LLI_WORD0_OFFSET],
+		mlli_entry_p[LLI_WORD1_OFFSET]);
+	mlli_entry_p = mlli_entry_p + 2;
+	*mlli_entry_pp = mlli_entry_p;
+	(*curr_nents)++;
+	return 0;
+}
+
+static int cc_render_sg_to_mlli(struct device *dev, struct scatterlist *sgl,
+				u32 sgl_data_len, u32 sgl_offset,
+				u32 *curr_nents, u32 **mlli_entry_pp)
+{
+	struct scatterlist *curr_sgl = sgl;
+	u32 *mlli_entry_p = *mlli_entry_pp;
+	s32 rc = 0;
+
+	for ( ; (curr_sgl && sgl_data_len);
+	      curr_sgl = sg_next(curr_sgl)) {
+		u32 entry_data_len =
+			(sgl_data_len > sg_dma_len(curr_sgl) - sgl_offset) ?
+				sg_dma_len(curr_sgl) - sgl_offset :
+				sgl_data_len;
+		sgl_data_len -= entry_data_len;
+		rc = cc_render_buff_to_mlli(dev, sg_dma_address(curr_sgl) +
+					    sgl_offset, entry_data_len,
+					    curr_nents, &mlli_entry_p);
+		if (rc)
+			return rc;
+
+		sgl_offset = 0;
+	}
+	*mlli_entry_pp = mlli_entry_p;
+	return 0;
+}
+
+static int cc_generate_mlli(struct device *dev, struct buffer_array *sg_data,
+			    struct mlli_params *mlli_params, gfp_t flags)
+{
+	u32 *mlli_p;
+	u32 total_nents = 0, prev_total_nents = 0;
+	int rc = 0, i;
+
+	dev_dbg(dev, "NUM of SG's = %d\n", sg_data->num_of_buffers);
+
+	/* Allocate memory from the pointed pool */
+	mlli_params->mlli_virt_addr =
+		dma_pool_alloc(mlli_params->curr_pool, flags,
+			       &mlli_params->mlli_dma_addr);
+	if (!mlli_params->mlli_virt_addr) {
+		dev_err(dev, "dma_pool_alloc() failed\n");
+		rc = -ENOMEM;
+		goto build_mlli_exit;
+	}
+	/* Point to start of MLLI */
+	mlli_p = (u32 *)mlli_params->mlli_virt_addr;
+	/* go over all SG's and link it to one MLLI table */
+	for (i = 0; i < sg_data->num_of_buffers; i++) {
+		union buffer_array_entry *entry = &sg_data->entry[i];
+		u32 tot_len = sg_data->total_data_len[i];
+		u32 offset = sg_data->offset[i];
+
+		if (sg_data->type[i] == DMA_SGL_TYPE)
+			rc = cc_render_sg_to_mlli(dev, entry->sgl, tot_len,
+						  offset, &total_nents,
+						  &mlli_p);
+		else /*DMA_BUFF_TYPE*/
+			rc = cc_render_buff_to_mlli(dev, entry->buffer_dma,
+						    tot_len, &total_nents,
+						    &mlli_p);
+		if (rc)
+			return rc;
+
+		/* set last bit in the current table */
+		if (sg_data->mlli_nents[i]) {
+			/*Calculate the current MLLI table length for the
+			 *length field in the descriptor
+			 */
+			*sg_data->mlli_nents[i] +=
+				(total_nents - prev_total_nents);
+			prev_total_nents = total_nents;
+		}
+	}
+
+	/* Set MLLI size for the bypass operation */
+	mlli_params->mlli_len = (total_nents * LLI_ENTRY_BYTE_SIZE);
+
+	dev_dbg(dev, "MLLI params: virt_addr=%pK dma_addr=%pad mlli_len=0x%X\n",
+		mlli_params->mlli_virt_addr, &mlli_params->mlli_dma_addr,
+		mlli_params->mlli_len);
+
+build_mlli_exit:
+	return rc;
+}
+
+static void cc_add_buffer_entry(struct device *dev,
+				struct buffer_array *sgl_data,
+				dma_addr_t buffer_dma, unsigned int buffer_len,
+				bool is_last_entry, u32 *mlli_nents)
+{
+	unsigned int index = sgl_data->num_of_buffers;
+
+	dev_dbg(dev, "index=%u single_buff=%pad buffer_len=0x%08X is_last=%d\n",
+		index, &buffer_dma, buffer_len, is_last_entry);
+	sgl_data->nents[index] = 1;
+	sgl_data->entry[index].buffer_dma = buffer_dma;
+	sgl_data->offset[index] = 0;
+	sgl_data->total_data_len[index] = buffer_len;
+	sgl_data->type[index] = DMA_BUFF_TYPE;
+	sgl_data->is_last[index] = is_last_entry;
+	sgl_data->mlli_nents[index] = mlli_nents;
+	if (sgl_data->mlli_nents[index])
+		*sgl_data->mlli_nents[index] = 0;
+	sgl_data->num_of_buffers++;
+}
+
+static void cc_add_sg_entry(struct device *dev, struct buffer_array *sgl_data,
+			    unsigned int nents, struct scatterlist *sgl,
+			    unsigned int data_len, unsigned int data_offset,
+			    bool is_last_table, u32 *mlli_nents)
+{
+	unsigned int index = sgl_data->num_of_buffers;
+
+	dev_dbg(dev, "index=%u nents=%u sgl=%pK data_len=0x%08X is_last=%d\n",
+		index, nents, sgl, data_len, is_last_table);
+	sgl_data->nents[index] = nents;
+	sgl_data->entry[index].sgl = sgl;
+	sgl_data->offset[index] = data_offset;
+	sgl_data->total_data_len[index] = data_len;
+	sgl_data->type[index] = DMA_SGL_TYPE;
+	sgl_data->is_last[index] = is_last_table;
+	sgl_data->mlli_nents[index] = mlli_nents;
+	if (sgl_data->mlli_nents[index])
+		*sgl_data->mlli_nents[index] = 0;
+	sgl_data->num_of_buffers++;
+}
+
+static int cc_dma_map_sg(struct device *dev, struct scatterlist *sg, u32 nents,
+			 enum dma_data_direction direction)
+{
+	u32 i, j;
+	struct scatterlist *l_sg = sg;
+
+	for (i = 0; i < nents; i++) {
+		if (!l_sg)
+			break;
+		if (dma_map_sg(dev, l_sg, 1, direction) != 1) {
+			dev_err(dev, "dma_map_page() sg buffer failed\n");
+			goto err;
+		}
+		l_sg = sg_next(l_sg);
+	}
+	return nents;
+
+err:
+	/* Restore mapped parts */
+	for (j = 0; j < i; j++) {
+		if (!sg)
+			break;
+		dma_unmap_sg(dev, sg, 1, direction);
+		sg = sg_next(sg);
+	}
+	return 0;
+}
+
+static int cc_map_sg(struct device *dev, struct scatterlist *sg,
+		     unsigned int nbytes, int direction, u32 *nents,
+		     u32 max_sg_nents, u32 *lbytes, u32 *mapped_nents)
+{
+	bool is_chained = false;
+
+	if (sg_is_last(sg)) {
+		/* One entry only case -set to DLLI */
+		if (dma_map_sg(dev, sg, 1, direction) != 1) {
+			dev_err(dev, "dma_map_sg() single buffer failed\n");
+			return -ENOMEM;
+		}
+		dev_dbg(dev, "Mapped sg: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n",
+			&sg_dma_address(sg), sg_page(sg), sg_virt(sg),
+			sg->offset, sg->length);
+		*lbytes = nbytes;
+		*nents = 1;
+		*mapped_nents = 1;
+	} else {  /*sg_is_last*/
+		*nents = cc_get_sgl_nents(dev, sg, nbytes, lbytes,
+					  &is_chained);
+		if (*nents > max_sg_nents) {
+			*nents = 0;
+			dev_err(dev, "Too many fragments. current %d max %d\n",
+				*nents, max_sg_nents);
+			return -ENOMEM;
+		}
+		if (!is_chained) {
+			/* In case of mmu the number of mapped nents might
+			 * be changed from the original sgl nents
+			 */
+			*mapped_nents = dma_map_sg(dev, sg, *nents, direction);
+			if (*mapped_nents == 0) {
+				*nents = 0;
+				dev_err(dev, "dma_map_sg() sg buffer failed\n");
+				return -ENOMEM;
+			}
+		} else {
+			/*In this case the driver maps entry by entry so it
+			 * must have the same nents before and after map
+			 */
+			*mapped_nents = cc_dma_map_sg(dev, sg, *nents,
+						      direction);
+			if (*mapped_nents != *nents) {
+				*nents = *mapped_nents;
+				dev_err(dev, "dma_map_sg() sg buffer failed\n");
+				return -ENOMEM;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int
+cc_set_aead_conf_buf(struct device *dev, struct aead_req_ctx *areq_ctx,
+		     u8 *config_data, struct buffer_array *sg_data,
+		     unsigned int assoclen)
+{
+	dev_dbg(dev, " handle additional data config set to DLLI\n");
+	/* create sg for the current buffer */
+	sg_init_one(&areq_ctx->ccm_adata_sg, config_data,
+		    AES_BLOCK_SIZE + areq_ctx->ccm_hdr_size);
+	if (dma_map_sg(dev, &areq_ctx->ccm_adata_sg, 1, DMA_TO_DEVICE) != 1) {
+		dev_err(dev, "dma_map_sg() config buffer failed\n");
+		return -ENOMEM;
+	}
+	dev_dbg(dev, "Mapped curr_buff: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n",
+		&sg_dma_address(&areq_ctx->ccm_adata_sg),
+		sg_page(&areq_ctx->ccm_adata_sg),
+		sg_virt(&areq_ctx->ccm_adata_sg),
+		areq_ctx->ccm_adata_sg.offset, areq_ctx->ccm_adata_sg.length);
+	/* prepare for case of MLLI */
+	if (assoclen > 0) {
+		cc_add_sg_entry(dev, sg_data, 1, &areq_ctx->ccm_adata_sg,
+				(AES_BLOCK_SIZE + areq_ctx->ccm_hdr_size),
+				0, false, NULL);
+	}
+	return 0;
+}
+
+static int cc_set_hash_buf(struct device *dev, struct ahash_req_ctx *areq_ctx,
+			   u8 *curr_buff, u32 curr_buff_cnt,
+			   struct buffer_array *sg_data)
+{
+	dev_dbg(dev, " handle curr buff %x set to   DLLI\n", curr_buff_cnt);
+	/* create sg for the current buffer */
+	sg_init_one(areq_ctx->buff_sg, curr_buff, curr_buff_cnt);
+	if (dma_map_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE) != 1) {
+		dev_err(dev, "dma_map_sg() src buffer failed\n");
+		return -ENOMEM;
+	}
+	dev_dbg(dev, "Mapped curr_buff: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n",
+		&sg_dma_address(areq_ctx->buff_sg), sg_page(areq_ctx->buff_sg),
+		sg_virt(areq_ctx->buff_sg), areq_ctx->buff_sg->offset,
+		areq_ctx->buff_sg->length);
+	areq_ctx->data_dma_buf_type = CC_DMA_BUF_DLLI;
+	areq_ctx->curr_sg = areq_ctx->buff_sg;
+	areq_ctx->in_nents = 0;
+	/* prepare for case of MLLI */
+	cc_add_sg_entry(dev, sg_data, 1, areq_ctx->buff_sg, curr_buff_cnt, 0,
+			false, NULL);
+	return 0;
+}
+
+void cc_unmap_cipher_request(struct device *dev, void *ctx,
+				unsigned int ivsize, struct scatterlist *src,
+				struct scatterlist *dst)
+{
+	struct cipher_req_ctx *req_ctx = (struct cipher_req_ctx *)ctx;
+
+	if (req_ctx->gen_ctx.iv_dma_addr) {
+		dev_dbg(dev, "Unmapped iv: iv_dma_addr=%pad iv_size=%u\n",
+			&req_ctx->gen_ctx.iv_dma_addr, ivsize);
+		dma_unmap_single(dev, req_ctx->gen_ctx.iv_dma_addr,
+				 ivsize,
+				 req_ctx->is_giv ? DMA_BIDIRECTIONAL :
+				 DMA_TO_DEVICE);
+	}
+	/* Release pool */
+	if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI &&
+	    req_ctx->mlli_params.mlli_virt_addr) {
+		dma_pool_free(req_ctx->mlli_params.curr_pool,
+			      req_ctx->mlli_params.mlli_virt_addr,
+			      req_ctx->mlli_params.mlli_dma_addr);
+	}
+
+	dma_unmap_sg(dev, src, req_ctx->in_nents, DMA_BIDIRECTIONAL);
+	dev_dbg(dev, "Unmapped req->src=%pK\n", sg_virt(src));
+
+	if (src != dst) {
+		dma_unmap_sg(dev, dst, req_ctx->out_nents, DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "Unmapped req->dst=%pK\n", sg_virt(dst));
+	}
+}
+
+int cc_map_cipher_request(struct cc_drvdata *drvdata, void *ctx,
+			  unsigned int ivsize, unsigned int nbytes,
+			  void *info, struct scatterlist *src,
+			  struct scatterlist *dst, gfp_t flags)
+{
+	struct cipher_req_ctx *req_ctx = (struct cipher_req_ctx *)ctx;
+	struct mlli_params *mlli_params = &req_ctx->mlli_params;
+	struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+	struct device *dev = drvdata_to_dev(drvdata);
+	struct buffer_array sg_data;
+	u32 dummy = 0;
+	int rc = 0;
+	u32 mapped_nents = 0;
+
+	req_ctx->dma_buf_type = CC_DMA_BUF_DLLI;
+	mlli_params->curr_pool = NULL;
+	sg_data.num_of_buffers = 0;
+
+	/* Map IV buffer */
+	if (ivsize) {
+		dump_byte_array("iv", (u8 *)info, ivsize);
+		req_ctx->gen_ctx.iv_dma_addr =
+			dma_map_single(dev, (void *)info,
+				       ivsize,
+				       req_ctx->is_giv ? DMA_BIDIRECTIONAL :
+				       DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, req_ctx->gen_ctx.iv_dma_addr)) {
+			dev_err(dev, "Mapping iv %u B at va=%pK for DMA failed\n",
+				ivsize, info);
+			return -ENOMEM;
+		}
+		dev_dbg(dev, "Mapped iv %u B at va=%pK to dma=%pad\n",
+			ivsize, info, &req_ctx->gen_ctx.iv_dma_addr);
+	} else {
+		req_ctx->gen_ctx.iv_dma_addr = 0;
+	}
+
+	/* Map the src SGL */
+	rc = cc_map_sg(dev, src, nbytes, DMA_BIDIRECTIONAL, &req_ctx->in_nents,
+		       LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents);
+	if (rc) {
+		rc = -ENOMEM;
+		goto cipher_exit;
+	}
+	if (mapped_nents > 1)
+		req_ctx->dma_buf_type = CC_DMA_BUF_MLLI;
+
+	if (src == dst) {
+		/* Handle inplace operation */
+		if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI) {
+			req_ctx->out_nents = 0;
+			cc_add_sg_entry(dev, &sg_data, req_ctx->in_nents, src,
+					nbytes, 0, true,
+					&req_ctx->in_mlli_nents);
+		}
+	} else {
+		/* Map the dst sg */
+		if (cc_map_sg(dev, dst, nbytes, DMA_BIDIRECTIONAL,
+			      &req_ctx->out_nents, LLI_MAX_NUM_OF_DATA_ENTRIES,
+			      &dummy, &mapped_nents)) {
+			rc = -ENOMEM;
+			goto cipher_exit;
+		}
+		if (mapped_nents > 1)
+			req_ctx->dma_buf_type = CC_DMA_BUF_MLLI;
+
+		if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI) {
+			cc_add_sg_entry(dev, &sg_data, req_ctx->in_nents, src,
+					nbytes, 0, true,
+					&req_ctx->in_mlli_nents);
+			cc_add_sg_entry(dev, &sg_data, req_ctx->out_nents, dst,
+					nbytes, 0, true,
+					&req_ctx->out_mlli_nents);
+		}
+	}
+
+	if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI) {
+		mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+		rc = cc_generate_mlli(dev, &sg_data, mlli_params, flags);
+		if (rc)
+			goto cipher_exit;
+	}
+
+	dev_dbg(dev, "areq_ctx->dma_buf_type = %s\n",
+		cc_dma_buf_type(req_ctx->dma_buf_type));
+
+	return 0;
+
+cipher_exit:
+	cc_unmap_cipher_request(dev, req_ctx, ivsize, src, dst);
+	return rc;
+}
+
+void cc_unmap_aead_request(struct device *dev, struct aead_request *req)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	unsigned int hw_iv_size = areq_ctx->hw_iv_size;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
+	u32 dummy;
+	bool chained;
+	u32 size_to_unmap = 0;
+
+	if (areq_ctx->mac_buf_dma_addr) {
+		dma_unmap_single(dev, areq_ctx->mac_buf_dma_addr,
+				 MAX_MAC_SIZE, DMA_BIDIRECTIONAL);
+	}
+
+	if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) {
+		if (areq_ctx->hkey_dma_addr) {
+			dma_unmap_single(dev, areq_ctx->hkey_dma_addr,
+					 AES_BLOCK_SIZE, DMA_BIDIRECTIONAL);
+		}
+
+		if (areq_ctx->gcm_block_len_dma_addr) {
+			dma_unmap_single(dev, areq_ctx->gcm_block_len_dma_addr,
+					 AES_BLOCK_SIZE, DMA_TO_DEVICE);
+		}
+
+		if (areq_ctx->gcm_iv_inc1_dma_addr) {
+			dma_unmap_single(dev, areq_ctx->gcm_iv_inc1_dma_addr,
+					 AES_BLOCK_SIZE, DMA_TO_DEVICE);
+		}
+
+		if (areq_ctx->gcm_iv_inc2_dma_addr) {
+			dma_unmap_single(dev, areq_ctx->gcm_iv_inc2_dma_addr,
+					 AES_BLOCK_SIZE, DMA_TO_DEVICE);
+		}
+	}
+
+	if (areq_ctx->ccm_hdr_size != ccm_header_size_null) {
+		if (areq_ctx->ccm_iv0_dma_addr) {
+			dma_unmap_single(dev, areq_ctx->ccm_iv0_dma_addr,
+					 AES_BLOCK_SIZE, DMA_TO_DEVICE);
+		}
+
+		dma_unmap_sg(dev, &areq_ctx->ccm_adata_sg, 1, DMA_TO_DEVICE);
+	}
+	if (areq_ctx->gen_ctx.iv_dma_addr) {
+		dma_unmap_single(dev, areq_ctx->gen_ctx.iv_dma_addr,
+				 hw_iv_size, DMA_BIDIRECTIONAL);
+	}
+
+	/*In case a pool was set, a table was
+	 *allocated and should be released
+	 */
+	if (areq_ctx->mlli_params.curr_pool) {
+		dev_dbg(dev, "free MLLI buffer: dma=%pad virt=%pK\n",
+			&areq_ctx->mlli_params.mlli_dma_addr,
+			areq_ctx->mlli_params.mlli_virt_addr);
+		dma_pool_free(areq_ctx->mlli_params.curr_pool,
+			      areq_ctx->mlli_params.mlli_virt_addr,
+			      areq_ctx->mlli_params.mlli_dma_addr);
+	}
+
+	dev_dbg(dev, "Unmapping src sgl: req->src=%pK areq_ctx->src.nents=%u areq_ctx->assoc.nents=%u assoclen:%u cryptlen=%u\n",
+		sg_virt(req->src), areq_ctx->src.nents, areq_ctx->assoc.nents,
+		req->assoclen, req->cryptlen);
+	size_to_unmap = req->assoclen + req->cryptlen;
+	if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT)
+		size_to_unmap += areq_ctx->req_authsize;
+	if (areq_ctx->is_gcm4543)
+		size_to_unmap += crypto_aead_ivsize(tfm);
+
+	dma_unmap_sg(dev, req->src,
+		     cc_get_sgl_nents(dev, req->src, size_to_unmap,
+				      &dummy, &chained),
+		     DMA_BIDIRECTIONAL);
+	if (req->src != req->dst) {
+		dev_dbg(dev, "Unmapping dst sgl: req->dst=%pK\n",
+			sg_virt(req->dst));
+		dma_unmap_sg(dev, req->dst,
+			     cc_get_sgl_nents(dev, req->dst, size_to_unmap,
+					      &dummy, &chained),
+			     DMA_BIDIRECTIONAL);
+	}
+	if (drvdata->coherent &&
+	    areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT &&
+	    req->src == req->dst) {
+		/* copy back mac from temporary location to deal with possible
+		 * data memory overriding that caused by cache coherence
+		 * problem.
+		 */
+		cc_copy_mac(dev, req, CC_SG_FROM_BUF);
+	}
+}
+
+static int cc_get_aead_icv_nents(struct device *dev, struct scatterlist *sgl,
+				 unsigned int sgl_nents, unsigned int authsize,
+				 u32 last_entry_data_size,
+				 bool *is_icv_fragmented)
+{
+	unsigned int icv_max_size = 0;
+	unsigned int icv_required_size = authsize > last_entry_data_size ?
+					(authsize - last_entry_data_size) :
+					authsize;
+	unsigned int nents;
+	unsigned int i;
+
+	if (sgl_nents < MAX_ICV_NENTS_SUPPORTED) {
+		*is_icv_fragmented = false;
+		return 0;
+	}
+
+	for (i = 0 ; i < (sgl_nents - MAX_ICV_NENTS_SUPPORTED) ; i++) {
+		if (!sgl)
+			break;
+		sgl = sg_next(sgl);
+	}
+
+	if (sgl)
+		icv_max_size = sgl->length;
+
+	if (last_entry_data_size > authsize) {
+		/* ICV attached to data in last entry (not fragmented!) */
+		nents = 0;
+		*is_icv_fragmented = false;
+	} else if (last_entry_data_size == authsize) {
+		/* ICV placed in whole last entry (not fragmented!) */
+		nents = 1;
+		*is_icv_fragmented = false;
+	} else if (icv_max_size > icv_required_size) {
+		nents = 1;
+		*is_icv_fragmented = true;
+	} else if (icv_max_size == icv_required_size) {
+		nents = 2;
+		*is_icv_fragmented = true;
+	} else {
+		dev_err(dev, "Unsupported num. of ICV fragments (> %d)\n",
+			MAX_ICV_NENTS_SUPPORTED);
+		nents = -1; /*unsupported*/
+	}
+	dev_dbg(dev, "is_frag=%s icv_nents=%u\n",
+		(*is_icv_fragmented ? "true" : "false"), nents);
+
+	return nents;
+}
+
+static int cc_aead_chain_iv(struct cc_drvdata *drvdata,
+			    struct aead_request *req,
+			    struct buffer_array *sg_data,
+			    bool is_last, bool do_chain)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	unsigned int hw_iv_size = areq_ctx->hw_iv_size;
+	struct device *dev = drvdata_to_dev(drvdata);
+	int rc = 0;
+
+	if (!req->iv) {
+		areq_ctx->gen_ctx.iv_dma_addr = 0;
+		goto chain_iv_exit;
+	}
+
+	areq_ctx->gen_ctx.iv_dma_addr = dma_map_single(dev, req->iv,
+						       hw_iv_size,
+						       DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, areq_ctx->gen_ctx.iv_dma_addr)) {
+		dev_err(dev, "Mapping iv %u B at va=%pK for DMA failed\n",
+			hw_iv_size, req->iv);
+		rc = -ENOMEM;
+		goto chain_iv_exit;
+	}
+
+	dev_dbg(dev, "Mapped iv %u B at va=%pK to dma=%pad\n",
+		hw_iv_size, req->iv, &areq_ctx->gen_ctx.iv_dma_addr);
+	// TODO: what about CTR?? ask Ron
+	if (do_chain && areq_ctx->plaintext_authenticate_only) {
+		struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+		unsigned int iv_size_to_authenc = crypto_aead_ivsize(tfm);
+		unsigned int iv_ofs = GCM_BLOCK_RFC4_IV_OFFSET;
+		/* Chain to given list */
+		cc_add_buffer_entry(dev, sg_data,
+				    (areq_ctx->gen_ctx.iv_dma_addr + iv_ofs),
+				    iv_size_to_authenc, is_last,
+				    &areq_ctx->assoc.mlli_nents);
+		areq_ctx->assoc_buff_type = CC_DMA_BUF_MLLI;
+	}
+
+chain_iv_exit:
+	return rc;
+}
+
+static int cc_aead_chain_assoc(struct cc_drvdata *drvdata,
+			       struct aead_request *req,
+			       struct buffer_array *sg_data,
+			       bool is_last, bool do_chain)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	int rc = 0;
+	u32 mapped_nents = 0;
+	struct scatterlist *current_sg = req->src;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	unsigned int sg_index = 0;
+	u32 size_of_assoc = req->assoclen;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	if (areq_ctx->is_gcm4543)
+		size_of_assoc += crypto_aead_ivsize(tfm);
+
+	if (!sg_data) {
+		rc = -EINVAL;
+		goto chain_assoc_exit;
+	}
+
+	if (req->assoclen == 0) {
+		areq_ctx->assoc_buff_type = CC_DMA_BUF_NULL;
+		areq_ctx->assoc.nents = 0;
+		areq_ctx->assoc.mlli_nents = 0;
+		dev_dbg(dev, "Chain assoc of length 0: buff_type=%s nents=%u\n",
+			cc_dma_buf_type(areq_ctx->assoc_buff_type),
+			areq_ctx->assoc.nents);
+		goto chain_assoc_exit;
+	}
+
+	//iterate over the sgl to see how many entries are for associated data
+	//it is assumed that if we reach here , the sgl is already mapped
+	sg_index = current_sg->length;
+	//the first entry in the scatter list contains all the associated data
+	if (sg_index > size_of_assoc) {
+		mapped_nents++;
+	} else {
+		while (sg_index <= size_of_assoc) {
+			current_sg = sg_next(current_sg);
+			/* if have reached the end of the sgl, then this is
+			 * unexpected
+			 */
+			if (!current_sg) {
+				dev_err(dev, "reached end of sg list. unexpected\n");
+				return -EINVAL;
+			}
+			sg_index += current_sg->length;
+			mapped_nents++;
+		}
+	}
+	if (mapped_nents > LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES) {
+		dev_err(dev, "Too many fragments. current %d max %d\n",
+			mapped_nents, LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES);
+		return -ENOMEM;
+	}
+	areq_ctx->assoc.nents = mapped_nents;
+
+	/* in CCM case we have additional entry for
+	 * ccm header configurations
+	 */
+	if (areq_ctx->ccm_hdr_size != ccm_header_size_null) {
+		if ((mapped_nents + 1) > LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES) {
+			dev_err(dev, "CCM case.Too many fragments. Current %d max %d\n",
+				(areq_ctx->assoc.nents + 1),
+				LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES);
+			rc = -ENOMEM;
+			goto chain_assoc_exit;
+		}
+	}
+
+	if (mapped_nents == 1 && areq_ctx->ccm_hdr_size == ccm_header_size_null)
+		areq_ctx->assoc_buff_type = CC_DMA_BUF_DLLI;
+	else
+		areq_ctx->assoc_buff_type = CC_DMA_BUF_MLLI;
+
+	if (do_chain || areq_ctx->assoc_buff_type == CC_DMA_BUF_MLLI) {
+		dev_dbg(dev, "Chain assoc: buff_type=%s nents=%u\n",
+			cc_dma_buf_type(areq_ctx->assoc_buff_type),
+			areq_ctx->assoc.nents);
+		cc_add_sg_entry(dev, sg_data, areq_ctx->assoc.nents, req->src,
+				req->assoclen, 0, is_last,
+				&areq_ctx->assoc.mlli_nents);
+		areq_ctx->assoc_buff_type = CC_DMA_BUF_MLLI;
+	}
+
+chain_assoc_exit:
+	return rc;
+}
+
+static void cc_prepare_aead_data_dlli(struct aead_request *req,
+				      u32 *src_last_bytes, u32 *dst_last_bytes)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
+	unsigned int authsize = areq_ctx->req_authsize;
+
+	areq_ctx->is_icv_fragmented = false;
+	if (req->src == req->dst) {
+		/*INPLACE*/
+		areq_ctx->icv_dma_addr = sg_dma_address(areq_ctx->src_sgl) +
+			(*src_last_bytes - authsize);
+		areq_ctx->icv_virt_addr = sg_virt(areq_ctx->src_sgl) +
+			(*src_last_bytes - authsize);
+	} else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) {
+		/*NON-INPLACE and DECRYPT*/
+		areq_ctx->icv_dma_addr = sg_dma_address(areq_ctx->src_sgl) +
+			(*src_last_bytes - authsize);
+		areq_ctx->icv_virt_addr = sg_virt(areq_ctx->src_sgl) +
+			(*src_last_bytes - authsize);
+	} else {
+		/*NON-INPLACE and ENCRYPT*/
+		areq_ctx->icv_dma_addr = sg_dma_address(areq_ctx->dst_sgl) +
+			(*dst_last_bytes - authsize);
+		areq_ctx->icv_virt_addr = sg_virt(areq_ctx->dst_sgl) +
+			(*dst_last_bytes - authsize);
+	}
+}
+
+static int cc_prepare_aead_data_mlli(struct cc_drvdata *drvdata,
+				     struct aead_request *req,
+				     struct buffer_array *sg_data,
+				     u32 *src_last_bytes, u32 *dst_last_bytes,
+				     bool is_last_table)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
+	unsigned int authsize = areq_ctx->req_authsize;
+	int rc = 0, icv_nents;
+	struct device *dev = drvdata_to_dev(drvdata);
+	struct scatterlist *sg;
+
+	if (req->src == req->dst) {
+		/*INPLACE*/
+		cc_add_sg_entry(dev, sg_data, areq_ctx->src.nents,
+				areq_ctx->src_sgl, areq_ctx->cryptlen,
+				areq_ctx->src_offset, is_last_table,
+				&areq_ctx->src.mlli_nents);
+
+		icv_nents = cc_get_aead_icv_nents(dev, areq_ctx->src_sgl,
+						  areq_ctx->src.nents,
+						  authsize, *src_last_bytes,
+						  &areq_ctx->is_icv_fragmented);
+		if (icv_nents < 0) {
+			rc = -ENOTSUPP;
+			goto prepare_data_mlli_exit;
+		}
+
+		if (areq_ctx->is_icv_fragmented) {
+			/* Backup happens only when ICV is fragmented, ICV
+			 * verification is made by CPU compare in order to
+			 * simplify MAC verification upon request completion
+			 */
+			if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) {
+				/* In coherent platforms (e.g. ACP)
+				 * already copying ICV for any
+				 * INPLACE-DECRYPT operation, hence
+				 * we must neglect this code.
+				 */
+				if (!drvdata->coherent)
+					cc_copy_mac(dev, req, CC_SG_TO_BUF);
+
+				areq_ctx->icv_virt_addr = areq_ctx->backup_mac;
+			} else {
+				areq_ctx->icv_virt_addr = areq_ctx->mac_buf;
+				areq_ctx->icv_dma_addr =
+					areq_ctx->mac_buf_dma_addr;
+			}
+		} else { /* Contig. ICV */
+			sg = &areq_ctx->src_sgl[areq_ctx->src.nents - 1];
+			/*Should hanlde if the sg is not contig.*/
+			areq_ctx->icv_dma_addr = sg_dma_address(sg) +
+				(*src_last_bytes - authsize);
+			areq_ctx->icv_virt_addr = sg_virt(sg) +
+				(*src_last_bytes - authsize);
+		}
+
+	} else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) {
+		/*NON-INPLACE and DECRYPT*/
+		cc_add_sg_entry(dev, sg_data, areq_ctx->src.nents,
+				areq_ctx->src_sgl, areq_ctx->cryptlen,
+				areq_ctx->src_offset, is_last_table,
+				&areq_ctx->src.mlli_nents);
+		cc_add_sg_entry(dev, sg_data, areq_ctx->dst.nents,
+				areq_ctx->dst_sgl, areq_ctx->cryptlen,
+				areq_ctx->dst_offset, is_last_table,
+				&areq_ctx->dst.mlli_nents);
+
+		icv_nents = cc_get_aead_icv_nents(dev, areq_ctx->src_sgl,
+						  areq_ctx->src.nents,
+						  authsize, *src_last_bytes,
+						  &areq_ctx->is_icv_fragmented);
+		if (icv_nents < 0) {
+			rc = -ENOTSUPP;
+			goto prepare_data_mlli_exit;
+		}
+
+		/* Backup happens only when ICV is fragmented, ICV
+		 * verification is made by CPU compare in order to simplify
+		 * MAC verification upon request completion
+		 */
+		if (areq_ctx->is_icv_fragmented) {
+			cc_copy_mac(dev, req, CC_SG_TO_BUF);
+			areq_ctx->icv_virt_addr = areq_ctx->backup_mac;
+
+		} else { /* Contig. ICV */
+			sg = &areq_ctx->src_sgl[areq_ctx->src.nents - 1];
+			/*Should hanlde if the sg is not contig.*/
+			areq_ctx->icv_dma_addr = sg_dma_address(sg) +
+				(*src_last_bytes - authsize);
+			areq_ctx->icv_virt_addr = sg_virt(sg) +
+				(*src_last_bytes - authsize);
+		}
+
+	} else {
+		/*NON-INPLACE and ENCRYPT*/
+		cc_add_sg_entry(dev, sg_data, areq_ctx->dst.nents,
+				areq_ctx->dst_sgl, areq_ctx->cryptlen,
+				areq_ctx->dst_offset, is_last_table,
+				&areq_ctx->dst.mlli_nents);
+		cc_add_sg_entry(dev, sg_data, areq_ctx->src.nents,
+				areq_ctx->src_sgl, areq_ctx->cryptlen,
+				areq_ctx->src_offset, is_last_table,
+				&areq_ctx->src.mlli_nents);
+
+		icv_nents = cc_get_aead_icv_nents(dev, areq_ctx->dst_sgl,
+						  areq_ctx->dst.nents,
+						  authsize, *dst_last_bytes,
+						  &areq_ctx->is_icv_fragmented);
+		if (icv_nents < 0) {
+			rc = -ENOTSUPP;
+			goto prepare_data_mlli_exit;
+		}
+
+		if (!areq_ctx->is_icv_fragmented) {
+			sg = &areq_ctx->dst_sgl[areq_ctx->dst.nents - 1];
+			/* Contig. ICV */
+			areq_ctx->icv_dma_addr = sg_dma_address(sg) +
+				(*dst_last_bytes - authsize);
+			areq_ctx->icv_virt_addr = sg_virt(sg) +
+				(*dst_last_bytes - authsize);
+		} else {
+			areq_ctx->icv_dma_addr = areq_ctx->mac_buf_dma_addr;
+			areq_ctx->icv_virt_addr = areq_ctx->mac_buf;
+		}
+	}
+
+prepare_data_mlli_exit:
+	return rc;
+}
+
+static int cc_aead_chain_data(struct cc_drvdata *drvdata,
+			      struct aead_request *req,
+			      struct buffer_array *sg_data,
+			      bool is_last_table, bool do_chain)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	struct device *dev = drvdata_to_dev(drvdata);
+	enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
+	unsigned int authsize = areq_ctx->req_authsize;
+	unsigned int src_last_bytes = 0, dst_last_bytes = 0;
+	int rc = 0;
+	u32 src_mapped_nents = 0, dst_mapped_nents = 0;
+	u32 offset = 0;
+	/* non-inplace mode */
+	unsigned int size_for_map = req->assoclen + req->cryptlen;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	u32 sg_index = 0;
+	bool chained = false;
+	bool is_gcm4543 = areq_ctx->is_gcm4543;
+	u32 size_to_skip = req->assoclen;
+
+	if (is_gcm4543)
+		size_to_skip += crypto_aead_ivsize(tfm);
+
+	offset = size_to_skip;
+
+	if (!sg_data)
+		return -EINVAL;
+
+	areq_ctx->src_sgl = req->src;
+	areq_ctx->dst_sgl = req->dst;
+
+	if (is_gcm4543)
+		size_for_map += crypto_aead_ivsize(tfm);
+
+	size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+			authsize : 0;
+	src_mapped_nents = cc_get_sgl_nents(dev, req->src, size_for_map,
+					    &src_last_bytes, &chained);
+	sg_index = areq_ctx->src_sgl->length;
+	//check where the data starts
+	while (sg_index <= size_to_skip) {
+		offset -= areq_ctx->src_sgl->length;
+		areq_ctx->src_sgl = sg_next(areq_ctx->src_sgl);
+		//if have reached the end of the sgl, then this is unexpected
+		if (!areq_ctx->src_sgl) {
+			dev_err(dev, "reached end of sg list. unexpected\n");
+			return -EINVAL;
+		}
+		sg_index += areq_ctx->src_sgl->length;
+		src_mapped_nents--;
+	}
+	if (src_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES) {
+		dev_err(dev, "Too many fragments. current %d max %d\n",
+			src_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES);
+		return -ENOMEM;
+	}
+
+	areq_ctx->src.nents = src_mapped_nents;
+
+	areq_ctx->src_offset = offset;
+
+	if (req->src != req->dst) {
+		size_for_map = req->assoclen + req->cryptlen;
+		size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+				authsize : 0;
+		if (is_gcm4543)
+			size_for_map += crypto_aead_ivsize(tfm);
+
+		rc = cc_map_sg(dev, req->dst, size_for_map, DMA_BIDIRECTIONAL,
+			       &areq_ctx->dst.nents,
+			       LLI_MAX_NUM_OF_DATA_ENTRIES, &dst_last_bytes,
+			       &dst_mapped_nents);
+		if (rc) {
+			rc = -ENOMEM;
+			goto chain_data_exit;
+		}
+	}
+
+	dst_mapped_nents = cc_get_sgl_nents(dev, req->dst, size_for_map,
+					    &dst_last_bytes, &chained);
+	sg_index = areq_ctx->dst_sgl->length;
+	offset = size_to_skip;
+
+	//check where the data starts
+	while (sg_index <= size_to_skip) {
+		offset -= areq_ctx->dst_sgl->length;
+		areq_ctx->dst_sgl = sg_next(areq_ctx->dst_sgl);
+		//if have reached the end of the sgl, then this is unexpected
+		if (!areq_ctx->dst_sgl) {
+			dev_err(dev, "reached end of sg list. unexpected\n");
+			return -EINVAL;
+		}
+		sg_index += areq_ctx->dst_sgl->length;
+		dst_mapped_nents--;
+	}
+	if (dst_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES) {
+		dev_err(dev, "Too many fragments. current %d max %d\n",
+			dst_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES);
+		return -ENOMEM;
+	}
+	areq_ctx->dst.nents = dst_mapped_nents;
+	areq_ctx->dst_offset = offset;
+	if (src_mapped_nents > 1 ||
+	    dst_mapped_nents  > 1 ||
+	    do_chain) {
+		areq_ctx->data_buff_type = CC_DMA_BUF_MLLI;
+		rc = cc_prepare_aead_data_mlli(drvdata, req, sg_data,
+					       &src_last_bytes,
+					       &dst_last_bytes, is_last_table);
+	} else {
+		areq_ctx->data_buff_type = CC_DMA_BUF_DLLI;
+		cc_prepare_aead_data_dlli(req, &src_last_bytes,
+					  &dst_last_bytes);
+	}
+
+chain_data_exit:
+	return rc;
+}
+
+static void cc_update_aead_mlli_nents(struct cc_drvdata *drvdata,
+				      struct aead_request *req)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	u32 curr_mlli_size = 0;
+
+	if (areq_ctx->assoc_buff_type == CC_DMA_BUF_MLLI) {
+		areq_ctx->assoc.sram_addr = drvdata->mlli_sram_addr;
+		curr_mlli_size = areq_ctx->assoc.mlli_nents *
+						LLI_ENTRY_BYTE_SIZE;
+	}
+
+	if (areq_ctx->data_buff_type == CC_DMA_BUF_MLLI) {
+		/*Inplace case dst nents equal to src nents*/
+		if (req->src == req->dst) {
+			areq_ctx->dst.mlli_nents = areq_ctx->src.mlli_nents;
+			areq_ctx->src.sram_addr = drvdata->mlli_sram_addr +
+								curr_mlli_size;
+			areq_ctx->dst.sram_addr = areq_ctx->src.sram_addr;
+			if (!areq_ctx->is_single_pass)
+				areq_ctx->assoc.mlli_nents +=
+					areq_ctx->src.mlli_nents;
+		} else {
+			if (areq_ctx->gen_ctx.op_type ==
+					DRV_CRYPTO_DIRECTION_DECRYPT) {
+				areq_ctx->src.sram_addr =
+						drvdata->mlli_sram_addr +
+								curr_mlli_size;
+				areq_ctx->dst.sram_addr =
+						areq_ctx->src.sram_addr +
+						areq_ctx->src.mlli_nents *
+						LLI_ENTRY_BYTE_SIZE;
+				if (!areq_ctx->is_single_pass)
+					areq_ctx->assoc.mlli_nents +=
+						areq_ctx->src.mlli_nents;
+			} else {
+				areq_ctx->dst.sram_addr =
+						drvdata->mlli_sram_addr +
+								curr_mlli_size;
+				areq_ctx->src.sram_addr =
+						areq_ctx->dst.sram_addr +
+						areq_ctx->dst.mlli_nents *
+						LLI_ENTRY_BYTE_SIZE;
+				if (!areq_ctx->is_single_pass)
+					areq_ctx->assoc.mlli_nents +=
+						areq_ctx->dst.mlli_nents;
+			}
+		}
+	}
+}
+
+int cc_map_aead_request(struct cc_drvdata *drvdata, struct aead_request *req)
+{
+	struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+	struct mlli_params *mlli_params = &areq_ctx->mlli_params;
+	struct device *dev = drvdata_to_dev(drvdata);
+	struct buffer_array sg_data;
+	unsigned int authsize = areq_ctx->req_authsize;
+	struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+	int rc = 0;
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	bool is_gcm4543 = areq_ctx->is_gcm4543;
+	dma_addr_t dma_addr;
+	u32 mapped_nents = 0;
+	u32 dummy = 0; /*used for the assoc data fragments */
+	u32 size_to_map = 0;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	mlli_params->curr_pool = NULL;
+	sg_data.num_of_buffers = 0;
+
+	/* copy mac to a temporary location to deal with possible
+	 * data memory overriding that caused by cache coherence problem.
+	 */
+	if (drvdata->coherent &&
+	    areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT &&
+	    req->src == req->dst)
+		cc_copy_mac(dev, req, CC_SG_TO_BUF);
+
+	/* cacluate the size for cipher remove ICV in decrypt*/
+	areq_ctx->cryptlen = (areq_ctx->gen_ctx.op_type ==
+				 DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+				req->cryptlen :
+				(req->cryptlen - authsize);
+
+	dma_addr = dma_map_single(dev, areq_ctx->mac_buf, MAX_MAC_SIZE,
+				  DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, dma_addr)) {
+		dev_err(dev, "Mapping mac_buf %u B at va=%pK for DMA failed\n",
+			MAX_MAC_SIZE, areq_ctx->mac_buf);
+		rc = -ENOMEM;
+		goto aead_map_failure;
+	}
+	areq_ctx->mac_buf_dma_addr = dma_addr;
+
+	if (areq_ctx->ccm_hdr_size != ccm_header_size_null) {
+		void *addr = areq_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET;
+
+		dma_addr = dma_map_single(dev, addr, AES_BLOCK_SIZE,
+					  DMA_TO_DEVICE);
+
+		if (dma_mapping_error(dev, dma_addr)) {
+			dev_err(dev, "Mapping mac_buf %u B at va=%pK for DMA failed\n",
+				AES_BLOCK_SIZE, addr);
+			areq_ctx->ccm_iv0_dma_addr = 0;
+			rc = -ENOMEM;
+			goto aead_map_failure;
+		}
+		areq_ctx->ccm_iv0_dma_addr = dma_addr;
+
+		if (cc_set_aead_conf_buf(dev, areq_ctx, areq_ctx->ccm_config,
+					 &sg_data, req->assoclen)) {
+			rc = -ENOMEM;
+			goto aead_map_failure;
+		}
+	}
+
+	if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) {
+		dma_addr = dma_map_single(dev, areq_ctx->hkey, AES_BLOCK_SIZE,
+					  DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(dev, dma_addr)) {
+			dev_err(dev, "Mapping hkey %u B at va=%pK for DMA failed\n",
+				AES_BLOCK_SIZE, areq_ctx->hkey);
+			rc = -ENOMEM;
+			goto aead_map_failure;
+		}
+		areq_ctx->hkey_dma_addr = dma_addr;
+
+		dma_addr = dma_map_single(dev, &areq_ctx->gcm_len_block,
+					  AES_BLOCK_SIZE, DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, dma_addr)) {
+			dev_err(dev, "Mapping gcm_len_block %u B at va=%pK for DMA failed\n",
+				AES_BLOCK_SIZE, &areq_ctx->gcm_len_block);
+			rc = -ENOMEM;
+			goto aead_map_failure;
+		}
+		areq_ctx->gcm_block_len_dma_addr = dma_addr;
+
+		dma_addr = dma_map_single(dev, areq_ctx->gcm_iv_inc1,
+					  AES_BLOCK_SIZE, DMA_TO_DEVICE);
+
+		if (dma_mapping_error(dev, dma_addr)) {
+			dev_err(dev, "Mapping gcm_iv_inc1 %u B at va=%pK for DMA failed\n",
+				AES_BLOCK_SIZE, (areq_ctx->gcm_iv_inc1));
+			areq_ctx->gcm_iv_inc1_dma_addr = 0;
+			rc = -ENOMEM;
+			goto aead_map_failure;
+		}
+		areq_ctx->gcm_iv_inc1_dma_addr = dma_addr;
+
+		dma_addr = dma_map_single(dev, areq_ctx->gcm_iv_inc2,
+					  AES_BLOCK_SIZE, DMA_TO_DEVICE);
+
+		if (dma_mapping_error(dev, dma_addr)) {
+			dev_err(dev, "Mapping gcm_iv_inc2 %u B at va=%pK for DMA failed\n",
+				AES_BLOCK_SIZE, (areq_ctx->gcm_iv_inc2));
+			areq_ctx->gcm_iv_inc2_dma_addr = 0;
+			rc = -ENOMEM;
+			goto aead_map_failure;
+		}
+		areq_ctx->gcm_iv_inc2_dma_addr = dma_addr;
+	}
+
+	size_to_map = req->cryptlen + req->assoclen;
+	if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT)
+		size_to_map += authsize;
+
+	if (is_gcm4543)
+		size_to_map += crypto_aead_ivsize(tfm);
+	rc = cc_map_sg(dev, req->src, size_to_map, DMA_BIDIRECTIONAL,
+		       &areq_ctx->src.nents,
+		       (LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES +
+			LLI_MAX_NUM_OF_DATA_ENTRIES),
+		       &dummy, &mapped_nents);
+	if (rc) {
+		rc = -ENOMEM;
+		goto aead_map_failure;
+	}
+
+	if (areq_ctx->is_single_pass) {
+		/*
+		 * Create MLLI table for:
+		 *   (1) Assoc. data
+		 *   (2) Src/Dst SGLs
+		 *   Note: IV is contg. buffer (not an SGL)
+		 */
+		rc = cc_aead_chain_assoc(drvdata, req, &sg_data, true, false);
+		if (rc)
+			goto aead_map_failure;
+		rc = cc_aead_chain_iv(drvdata, req, &sg_data, true, false);
+		if (rc)
+			goto aead_map_failure;
+		rc = cc_aead_chain_data(drvdata, req, &sg_data, true, false);
+		if (rc)
+			goto aead_map_failure;
+	} else { /* DOUBLE-PASS flow */
+		/*
+		 * Prepare MLLI table(s) in this order:
+		 *
+		 * If ENCRYPT/DECRYPT (inplace):
+		 *   (1) MLLI table for assoc
+		 *   (2) IV entry (chained right after end of assoc)
+		 *   (3) MLLI for src/dst (inplace operation)
+		 *
+		 * If ENCRYPT (non-inplace)
+		 *   (1) MLLI table for assoc
+		 *   (2) IV entry (chained right after end of assoc)
+		 *   (3) MLLI for dst
+		 *   (4) MLLI for src
+		 *
+		 * If DECRYPT (non-inplace)
+		 *   (1) MLLI table for assoc
+		 *   (2) IV entry (chained right after end of assoc)
+		 *   (3) MLLI for src
+		 *   (4) MLLI for dst
+		 */
+		rc = cc_aead_chain_assoc(drvdata, req, &sg_data, false, true);
+		if (rc)
+			goto aead_map_failure;
+		rc = cc_aead_chain_iv(drvdata, req, &sg_data, false, true);
+		if (rc)
+			goto aead_map_failure;
+		rc = cc_aead_chain_data(drvdata, req, &sg_data, true, true);
+		if (rc)
+			goto aead_map_failure;
+	}
+
+	/* Mlli support -start building the MLLI according to the above
+	 * results
+	 */
+	if (areq_ctx->assoc_buff_type == CC_DMA_BUF_MLLI ||
+	    areq_ctx->data_buff_type == CC_DMA_BUF_MLLI) {
+		mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+		rc = cc_generate_mlli(dev, &sg_data, mlli_params, flags);
+		if (rc)
+			goto aead_map_failure;
+
+		cc_update_aead_mlli_nents(drvdata, req);
+		dev_dbg(dev, "assoc params mn %d\n",
+			areq_ctx->assoc.mlli_nents);
+		dev_dbg(dev, "src params mn %d\n", areq_ctx->src.mlli_nents);
+		dev_dbg(dev, "dst params mn %d\n", areq_ctx->dst.mlli_nents);
+	}
+	return 0;
+
+aead_map_failure:
+	cc_unmap_aead_request(dev, req);
+	return rc;
+}
+
+int cc_map_hash_request_final(struct cc_drvdata *drvdata, void *ctx,
+			      struct scatterlist *src, unsigned int nbytes,
+			      bool do_update, gfp_t flags)
+{
+	struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx;
+	struct device *dev = drvdata_to_dev(drvdata);
+	u8 *curr_buff = cc_hash_buf(areq_ctx);
+	u32 *curr_buff_cnt = cc_hash_buf_cnt(areq_ctx);
+	struct mlli_params *mlli_params = &areq_ctx->mlli_params;
+	struct buffer_array sg_data;
+	struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+	u32 dummy = 0;
+	u32 mapped_nents = 0;
+
+	dev_dbg(dev, "final params : curr_buff=%pK curr_buff_cnt=0x%X nbytes = 0x%X src=%pK curr_index=%u\n",
+		curr_buff, *curr_buff_cnt, nbytes, src, areq_ctx->buff_index);
+	/* Init the type of the dma buffer */
+	areq_ctx->data_dma_buf_type = CC_DMA_BUF_NULL;
+	mlli_params->curr_pool = NULL;
+	sg_data.num_of_buffers = 0;
+	areq_ctx->in_nents = 0;
+
+	if (nbytes == 0 && *curr_buff_cnt == 0) {
+		/* nothing to do */
+		return 0;
+	}
+
+	/*TODO: copy data in case that buffer is enough for operation */
+	/* map the previous buffer */
+	if (*curr_buff_cnt) {
+		if (cc_set_hash_buf(dev, areq_ctx, curr_buff, *curr_buff_cnt,
+				    &sg_data)) {
+			return -ENOMEM;
+		}
+	}
+
+	if (src && nbytes > 0 && do_update) {
+		if (cc_map_sg(dev, src, nbytes, DMA_TO_DEVICE,
+			      &areq_ctx->in_nents, LLI_MAX_NUM_OF_DATA_ENTRIES,
+			      &dummy, &mapped_nents)) {
+			goto unmap_curr_buff;
+		}
+		if (src && mapped_nents == 1 &&
+		    areq_ctx->data_dma_buf_type == CC_DMA_BUF_NULL) {
+			memcpy(areq_ctx->buff_sg, src,
+			       sizeof(struct scatterlist));
+			areq_ctx->buff_sg->length = nbytes;
+			areq_ctx->curr_sg = areq_ctx->buff_sg;
+			areq_ctx->data_dma_buf_type = CC_DMA_BUF_DLLI;
+		} else {
+			areq_ctx->data_dma_buf_type = CC_DMA_BUF_MLLI;
+		}
+	}
+
+	/*build mlli */
+	if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_MLLI) {
+		mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+		/* add the src data to the sg_data */
+		cc_add_sg_entry(dev, &sg_data, areq_ctx->in_nents, src, nbytes,
+				0, true, &areq_ctx->mlli_nents);
+		if (cc_generate_mlli(dev, &sg_data, mlli_params, flags))
+			goto fail_unmap_din;
+	}
+	/* change the buffer index for the unmap function */
+	areq_ctx->buff_index = (areq_ctx->buff_index ^ 1);
+	dev_dbg(dev, "areq_ctx->data_dma_buf_type = %s\n",
+		cc_dma_buf_type(areq_ctx->data_dma_buf_type));
+	return 0;
+
+fail_unmap_din:
+	dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE);
+
+unmap_curr_buff:
+	if (*curr_buff_cnt)
+		dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE);
+
+	return -ENOMEM;
+}
+
+int cc_map_hash_request_update(struct cc_drvdata *drvdata, void *ctx,
+			       struct scatterlist *src, unsigned int nbytes,
+			       unsigned int block_size, gfp_t flags)
+{
+	struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx;
+	struct device *dev = drvdata_to_dev(drvdata);
+	u8 *curr_buff = cc_hash_buf(areq_ctx);
+	u32 *curr_buff_cnt = cc_hash_buf_cnt(areq_ctx);
+	u8 *next_buff = cc_next_buf(areq_ctx);
+	u32 *next_buff_cnt = cc_next_buf_cnt(areq_ctx);
+	struct mlli_params *mlli_params = &areq_ctx->mlli_params;
+	unsigned int update_data_len;
+	u32 total_in_len = nbytes + *curr_buff_cnt;
+	struct buffer_array sg_data;
+	struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+	unsigned int swap_index = 0;
+	u32 dummy = 0;
+	u32 mapped_nents = 0;
+
+	dev_dbg(dev, " update params : curr_buff=%pK curr_buff_cnt=0x%X nbytes=0x%X src=%pK curr_index=%u\n",
+		curr_buff, *curr_buff_cnt, nbytes, src, areq_ctx->buff_index);
+	/* Init the type of the dma buffer */
+	areq_ctx->data_dma_buf_type = CC_DMA_BUF_NULL;
+	mlli_params->curr_pool = NULL;
+	areq_ctx->curr_sg = NULL;
+	sg_data.num_of_buffers = 0;
+	areq_ctx->in_nents = 0;
+
+	if (total_in_len < block_size) {
+		dev_dbg(dev, " less than one block: curr_buff=%pK *curr_buff_cnt=0x%X copy_to=%pK\n",
+			curr_buff, *curr_buff_cnt, &curr_buff[*curr_buff_cnt]);
+		areq_ctx->in_nents =
+			cc_get_sgl_nents(dev, src, nbytes, &dummy, NULL);
+		sg_copy_to_buffer(src, areq_ctx->in_nents,
+				  &curr_buff[*curr_buff_cnt], nbytes);
+		*curr_buff_cnt += nbytes;
+		return 1;
+	}
+
+	/* Calculate the residue size*/
+	*next_buff_cnt = total_in_len & (block_size - 1);
+	/* update data len */
+	update_data_len = total_in_len - *next_buff_cnt;
+
+	dev_dbg(dev, " temp length : *next_buff_cnt=0x%X update_data_len=0x%X\n",
+		*next_buff_cnt, update_data_len);
+
+	/* Copy the new residue to next buffer */
+	if (*next_buff_cnt) {
+		dev_dbg(dev, " handle residue: next buff %pK skip data %u residue %u\n",
+			next_buff, (update_data_len - *curr_buff_cnt),
+			*next_buff_cnt);
+		cc_copy_sg_portion(dev, next_buff, src,
+				   (update_data_len - *curr_buff_cnt),
+				   nbytes, CC_SG_TO_BUF);
+		/* change the buffer index for next operation */
+		swap_index = 1;
+	}
+
+	if (*curr_buff_cnt) {
+		if (cc_set_hash_buf(dev, areq_ctx, curr_buff, *curr_buff_cnt,
+				    &sg_data)) {
+			return -ENOMEM;
+		}
+		/* change the buffer index for next operation */
+		swap_index = 1;
+	}
+
+	if (update_data_len > *curr_buff_cnt) {
+		if (cc_map_sg(dev, src, (update_data_len - *curr_buff_cnt),
+			      DMA_TO_DEVICE, &areq_ctx->in_nents,
+			      LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy,
+			      &mapped_nents)) {
+			goto unmap_curr_buff;
+		}
+		if (mapped_nents == 1 &&
+		    areq_ctx->data_dma_buf_type == CC_DMA_BUF_NULL) {
+			/* only one entry in the SG and no previous data */
+			memcpy(areq_ctx->buff_sg, src,
+			       sizeof(struct scatterlist));
+			areq_ctx->buff_sg->length = update_data_len;
+			areq_ctx->data_dma_buf_type = CC_DMA_BUF_DLLI;
+			areq_ctx->curr_sg = areq_ctx->buff_sg;
+		} else {
+			areq_ctx->data_dma_buf_type = CC_DMA_BUF_MLLI;
+		}
+	}
+
+	if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_MLLI) {
+		mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+		/* add the src data to the sg_data */
+		cc_add_sg_entry(dev, &sg_data, areq_ctx->in_nents, src,
+				(update_data_len - *curr_buff_cnt), 0, true,
+				&areq_ctx->mlli_nents);
+		if (cc_generate_mlli(dev, &sg_data, mlli_params, flags))
+			goto fail_unmap_din;
+	}
+	areq_ctx->buff_index = (areq_ctx->buff_index ^ swap_index);
+
+	return 0;
+
+fail_unmap_din:
+	dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE);
+
+unmap_curr_buff:
+	if (*curr_buff_cnt)
+		dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE);
+
+	return -ENOMEM;
+}
+
+void cc_unmap_hash_request(struct device *dev, void *ctx,
+			   struct scatterlist *src, bool do_revert)
+{
+	struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx;
+	u32 *prev_len = cc_next_buf_cnt(areq_ctx);
+
+	/*In case a pool was set, a table was
+	 *allocated and should be released
+	 */
+	if (areq_ctx->mlli_params.curr_pool) {
+		dev_dbg(dev, "free MLLI buffer: dma=%pad virt=%pK\n",
+			&areq_ctx->mlli_params.mlli_dma_addr,
+			areq_ctx->mlli_params.mlli_virt_addr);
+		dma_pool_free(areq_ctx->mlli_params.curr_pool,
+			      areq_ctx->mlli_params.mlli_virt_addr,
+			      areq_ctx->mlli_params.mlli_dma_addr);
+	}
+
+	if (src && areq_ctx->in_nents) {
+		dev_dbg(dev, "Unmapped sg src: virt=%pK dma=%pad len=0x%X\n",
+			sg_virt(src), &sg_dma_address(src), sg_dma_len(src));
+		dma_unmap_sg(dev, src,
+			     areq_ctx->in_nents, DMA_TO_DEVICE);
+	}
+
+	if (*prev_len) {
+		dev_dbg(dev, "Unmapped buffer: areq_ctx->buff_sg=%pK dma=%pad len 0x%X\n",
+			sg_virt(areq_ctx->buff_sg),
+			&sg_dma_address(areq_ctx->buff_sg),
+			sg_dma_len(areq_ctx->buff_sg));
+		dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE);
+		if (!do_revert) {
+			/* clean the previous data length for update
+			 * operation
+			 */
+			*prev_len = 0;
+		} else {
+			areq_ctx->buff_index ^= 1;
+		}
+	}
+}
+
+int cc_buffer_mgr_init(struct cc_drvdata *drvdata)
+{
+	struct buff_mgr_handle *buff_mgr_handle;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	buff_mgr_handle = kmalloc(sizeof(*buff_mgr_handle), GFP_KERNEL);
+	if (!buff_mgr_handle)
+		return -ENOMEM;
+
+	drvdata->buff_mgr_handle = buff_mgr_handle;
+
+	buff_mgr_handle->mlli_buffs_pool =
+		dma_pool_create("dx_single_mlli_tables", dev,
+				MAX_NUM_OF_TOTAL_MLLI_ENTRIES *
+				LLI_ENTRY_BYTE_SIZE,
+				MLLI_TABLE_MIN_ALIGNMENT, 0);
+
+	if (!buff_mgr_handle->mlli_buffs_pool)
+		goto error;
+
+	return 0;
+
+error:
+	cc_buffer_mgr_fini(drvdata);
+	return -ENOMEM;
+}
+
+int cc_buffer_mgr_fini(struct cc_drvdata *drvdata)
+{
+	struct buff_mgr_handle *buff_mgr_handle = drvdata->buff_mgr_handle;
+
+	if (buff_mgr_handle) {
+		dma_pool_destroy(buff_mgr_handle->mlli_buffs_pool);
+		kfree(drvdata->buff_mgr_handle);
+		drvdata->buff_mgr_handle = NULL;
+	}
+	return 0;
+}
diff --git a/drivers/crypto/ccree/cc_buffer_mgr.h b/drivers/crypto/ccree/cc_buffer_mgr.h
new file mode 100644
index 000000000000..3ec4b4db5247
--- /dev/null
+++ b/drivers/crypto/ccree/cc_buffer_mgr.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_buffer_mgr.h
+ * Buffer Manager
+ */
+
+#ifndef __CC_BUFFER_MGR_H__
+#define __CC_BUFFER_MGR_H__
+
+#include <crypto/algapi.h>
+
+#include "cc_driver.h"
+
+enum cc_req_dma_buf_type {
+	CC_DMA_BUF_NULL = 0,
+	CC_DMA_BUF_DLLI,
+	CC_DMA_BUF_MLLI
+};
+
+enum cc_sg_cpy_direct {
+	CC_SG_TO_BUF = 0,
+	CC_SG_FROM_BUF = 1
+};
+
+struct cc_mlli {
+	cc_sram_addr_t sram_addr;
+	unsigned int nents; //sg nents
+	unsigned int mlli_nents; //mlli nents might be different than the above
+};
+
+struct mlli_params {
+	struct dma_pool *curr_pool;
+	u8 *mlli_virt_addr;
+	dma_addr_t mlli_dma_addr;
+	u32 mlli_len;
+};
+
+int cc_buffer_mgr_init(struct cc_drvdata *drvdata);
+
+int cc_buffer_mgr_fini(struct cc_drvdata *drvdata);
+
+int cc_map_cipher_request(struct cc_drvdata *drvdata, void *ctx,
+			  unsigned int ivsize, unsigned int nbytes,
+			  void *info, struct scatterlist *src,
+			  struct scatterlist *dst, gfp_t flags);
+
+void cc_unmap_cipher_request(struct device *dev, void *ctx, unsigned int ivsize,
+			     struct scatterlist *src, struct scatterlist *dst);
+
+int cc_map_aead_request(struct cc_drvdata *drvdata, struct aead_request *req);
+
+void cc_unmap_aead_request(struct device *dev, struct aead_request *req);
+
+int cc_map_hash_request_final(struct cc_drvdata *drvdata, void *ctx,
+			      struct scatterlist *src, unsigned int nbytes,
+			      bool do_update, gfp_t flags);
+
+int cc_map_hash_request_update(struct cc_drvdata *drvdata, void *ctx,
+			       struct scatterlist *src, unsigned int nbytes,
+			       unsigned int block_size, gfp_t flags);
+
+void cc_unmap_hash_request(struct device *dev, void *ctx,
+			   struct scatterlist *src, bool do_revert);
+
+void cc_copy_sg_portion(struct device *dev, u8 *dest, struct scatterlist *sg,
+			u32 to_skip, u32 end, enum cc_sg_cpy_direct direct);
+
+void cc_zero_sgl(struct scatterlist *sgl, u32 data_len);
+
+#endif /*__BUFFER_MGR_H__*/
diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c
new file mode 100644
index 000000000000..5760ca9481ea
--- /dev/null
+++ b/drivers/crypto/ccree/cc_cipher.c
@@ -0,0 +1,1130 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/des.h>
+#include <crypto/xts.h>
+#include <crypto/scatterwalk.h>
+
+#include "cc_driver.h"
+#include "cc_lli_defs.h"
+#include "cc_buffer_mgr.h"
+#include "cc_cipher.h"
+#include "cc_request_mgr.h"
+
+#define MAX_ABLKCIPHER_SEQ_LEN 6
+
+#define template_skcipher	template_u.skcipher
+
+#define CC_MIN_AES_XTS_SIZE 0x10
+#define CC_MAX_AES_XTS_SIZE 0x2000
+struct cc_cipher_handle {
+	struct list_head alg_list;
+};
+
+struct cc_user_key_info {
+	u8 *key;
+	dma_addr_t key_dma_addr;
+};
+
+struct cc_hw_key_info {
+	enum cc_hw_crypto_key key1_slot;
+	enum cc_hw_crypto_key key2_slot;
+};
+
+struct cc_cipher_ctx {
+	struct cc_drvdata *drvdata;
+	int keylen;
+	int key_round_number;
+	int cipher_mode;
+	int flow_mode;
+	unsigned int flags;
+	struct cc_user_key_info user;
+	struct cc_hw_key_info hw;
+	struct crypto_shash *shash_tfm;
+};
+
+static void cc_cipher_complete(struct device *dev, void *cc_req, int err);
+
+static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size)
+{
+	switch (ctx_p->flow_mode) {
+	case S_DIN_to_AES:
+		switch (size) {
+		case CC_AES_128_BIT_KEY_SIZE:
+		case CC_AES_192_BIT_KEY_SIZE:
+			if (ctx_p->cipher_mode != DRV_CIPHER_XTS &&
+			    ctx_p->cipher_mode != DRV_CIPHER_ESSIV &&
+			    ctx_p->cipher_mode != DRV_CIPHER_BITLOCKER)
+				return 0;
+			break;
+		case CC_AES_256_BIT_KEY_SIZE:
+			return 0;
+		case (CC_AES_192_BIT_KEY_SIZE * 2):
+		case (CC_AES_256_BIT_KEY_SIZE * 2):
+			if (ctx_p->cipher_mode == DRV_CIPHER_XTS ||
+			    ctx_p->cipher_mode == DRV_CIPHER_ESSIV ||
+			    ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER)
+				return 0;
+			break;
+		default:
+			break;
+		}
+	case S_DIN_to_DES:
+		if (size == DES3_EDE_KEY_SIZE || size == DES_KEY_SIZE)
+			return 0;
+		break;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int validate_data_size(struct cc_cipher_ctx *ctx_p,
+			      unsigned int size)
+{
+	switch (ctx_p->flow_mode) {
+	case S_DIN_to_AES:
+		switch (ctx_p->cipher_mode) {
+		case DRV_CIPHER_XTS:
+			if (size >= CC_MIN_AES_XTS_SIZE &&
+			    size <= CC_MAX_AES_XTS_SIZE &&
+			    IS_ALIGNED(size, AES_BLOCK_SIZE))
+				return 0;
+			break;
+		case DRV_CIPHER_CBC_CTS:
+			if (size >= AES_BLOCK_SIZE)
+				return 0;
+			break;
+		case DRV_CIPHER_OFB:
+		case DRV_CIPHER_CTR:
+				return 0;
+		case DRV_CIPHER_ECB:
+		case DRV_CIPHER_CBC:
+		case DRV_CIPHER_ESSIV:
+		case DRV_CIPHER_BITLOCKER:
+			if (IS_ALIGNED(size, AES_BLOCK_SIZE))
+				return 0;
+			break;
+		default:
+			break;
+		}
+		break;
+	case S_DIN_to_DES:
+		if (IS_ALIGNED(size, DES_BLOCK_SIZE))
+			return 0;
+		break;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int cc_cipher_init(struct crypto_tfm *tfm)
+{
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct cc_crypto_alg *cc_alg =
+			container_of(tfm->__crt_alg, struct cc_crypto_alg,
+				     skcipher_alg.base);
+	struct device *dev = drvdata_to_dev(cc_alg->drvdata);
+	unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
+	int rc = 0;
+
+	dev_dbg(dev, "Initializing context @%p for %s\n", ctx_p,
+		crypto_tfm_alg_name(tfm));
+
+	crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
+				    sizeof(struct cipher_req_ctx));
+
+	ctx_p->cipher_mode = cc_alg->cipher_mode;
+	ctx_p->flow_mode = cc_alg->flow_mode;
+	ctx_p->drvdata = cc_alg->drvdata;
+
+	/* Allocate key buffer, cache line aligned */
+	ctx_p->user.key = kmalloc(max_key_buf_size, GFP_KERNEL);
+	if (!ctx_p->user.key)
+		return -ENOMEM;
+
+	dev_dbg(dev, "Allocated key buffer in context. key=@%p\n",
+		ctx_p->user.key);
+
+	/* Map key buffer */
+	ctx_p->user.key_dma_addr = dma_map_single(dev, (void *)ctx_p->user.key,
+						  max_key_buf_size,
+						  DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) {
+		dev_err(dev, "Mapping Key %u B at va=%pK for DMA failed\n",
+			max_key_buf_size, ctx_p->user.key);
+		return -ENOMEM;
+	}
+	dev_dbg(dev, "Mapped key %u B at va=%pK to dma=%pad\n",
+		max_key_buf_size, ctx_p->user.key, &ctx_p->user.key_dma_addr);
+
+	if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+		/* Alloc hash tfm for essiv */
+		ctx_p->shash_tfm = crypto_alloc_shash("sha256-generic", 0, 0);
+		if (IS_ERR(ctx_p->shash_tfm)) {
+			dev_err(dev, "Error allocating hash tfm for ESSIV.\n");
+			return PTR_ERR(ctx_p->shash_tfm);
+		}
+	}
+
+	return rc;
+}
+
+static void cc_cipher_exit(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct cc_crypto_alg *cc_alg =
+			container_of(alg, struct cc_crypto_alg,
+				     skcipher_alg.base);
+	unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
+
+	dev_dbg(dev, "Clearing context @%p for %s\n",
+		crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm));
+
+	if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+		/* Free hash tfm for essiv */
+		crypto_free_shash(ctx_p->shash_tfm);
+		ctx_p->shash_tfm = NULL;
+	}
+
+	/* Unmap key buffer */
+	dma_unmap_single(dev, ctx_p->user.key_dma_addr, max_key_buf_size,
+			 DMA_TO_DEVICE);
+	dev_dbg(dev, "Unmapped key buffer key_dma_addr=%pad\n",
+		&ctx_p->user.key_dma_addr);
+
+	/* Free key buffer in context */
+	kzfree(ctx_p->user.key);
+	dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key);
+}
+
+struct tdes_keys {
+	u8	key1[DES_KEY_SIZE];
+	u8	key2[DES_KEY_SIZE];
+	u8	key3[DES_KEY_SIZE];
+};
+
+static enum cc_hw_crypto_key hw_key_to_cc_hw_key(int slot_num)
+{
+	switch (slot_num) {
+	case 0:
+		return KFDE0_KEY;
+	case 1:
+		return KFDE1_KEY;
+	case 2:
+		return KFDE2_KEY;
+	case 3:
+		return KFDE3_KEY;
+	}
+	return END_OF_KEYS;
+}
+
+static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key,
+			    unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm);
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
+	u32 tmp[DES3_EDE_EXPKEY_WORDS];
+	struct cc_crypto_alg *cc_alg =
+			container_of(tfm->__crt_alg, struct cc_crypto_alg,
+				     skcipher_alg.base);
+	unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
+
+	dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n",
+		ctx_p, crypto_tfm_alg_name(tfm), keylen);
+	dump_byte_array("key", (u8 *)key, keylen);
+
+	/* STAT_PHASE_0: Init and sanity checks */
+
+	if (validate_keys_sizes(ctx_p, keylen)) {
+		dev_err(dev, "Unsupported key size %d.\n", keylen);
+		crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	if (cc_is_hw_key(tfm)) {
+		/* setting HW key slots */
+		struct arm_hw_key_info *hki = (struct arm_hw_key_info *)key;
+
+		if (ctx_p->flow_mode != S_DIN_to_AES) {
+			dev_err(dev, "HW key not supported for non-AES flows\n");
+			return -EINVAL;
+		}
+
+		ctx_p->hw.key1_slot = hw_key_to_cc_hw_key(hki->hw_key1);
+		if (ctx_p->hw.key1_slot == END_OF_KEYS) {
+			dev_err(dev, "Unsupported hw key1 number (%d)\n",
+				hki->hw_key1);
+			return -EINVAL;
+		}
+
+		if (ctx_p->cipher_mode == DRV_CIPHER_XTS ||
+		    ctx_p->cipher_mode == DRV_CIPHER_ESSIV ||
+		    ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) {
+			if (hki->hw_key1 == hki->hw_key2) {
+				dev_err(dev, "Illegal hw key numbers (%d,%d)\n",
+					hki->hw_key1, hki->hw_key2);
+				return -EINVAL;
+			}
+			ctx_p->hw.key2_slot =
+				hw_key_to_cc_hw_key(hki->hw_key2);
+			if (ctx_p->hw.key2_slot == END_OF_KEYS) {
+				dev_err(dev, "Unsupported hw key2 number (%d)\n",
+					hki->hw_key2);
+				return -EINVAL;
+			}
+		}
+
+		ctx_p->keylen = keylen;
+		dev_dbg(dev, "cc_is_hw_key ret 0");
+
+		return 0;
+	}
+
+	/*
+	 * Verify DES weak keys
+	 * Note that we're dropping the expanded key since the
+	 * HW does the expansion on its own.
+	 */
+	if (ctx_p->flow_mode == S_DIN_to_DES) {
+		if (keylen == DES3_EDE_KEY_SIZE &&
+		    __des3_ede_setkey(tmp, &tfm->crt_flags, key,
+				      DES3_EDE_KEY_SIZE)) {
+			dev_dbg(dev, "weak 3DES key");
+			return -EINVAL;
+		} else if (!des_ekey(tmp, key) &&
+		    (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_WEAK_KEY)) {
+			tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
+			dev_dbg(dev, "weak DES key");
+			return -EINVAL;
+		}
+	}
+
+	if (ctx_p->cipher_mode == DRV_CIPHER_XTS &&
+	    xts_check_key(tfm, key, keylen)) {
+		dev_dbg(dev, "weak XTS key");
+		return -EINVAL;
+	}
+
+	/* STAT_PHASE_1: Copy key to ctx */
+	dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr,
+				max_key_buf_size, DMA_TO_DEVICE);
+
+	memcpy(ctx_p->user.key, key, keylen);
+	if (keylen == 24)
+		memset(ctx_p->user.key + 24, 0, CC_AES_KEY_SIZE_MAX - 24);
+
+	if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+		/* sha256 for key2 - use sw implementation */
+		int key_len = keylen >> 1;
+		int err;
+
+		SHASH_DESC_ON_STACK(desc, ctx_p->shash_tfm);
+
+		desc->tfm = ctx_p->shash_tfm;
+
+		err = crypto_shash_digest(desc, ctx_p->user.key, key_len,
+					  ctx_p->user.key + key_len);
+		if (err) {
+			dev_err(dev, "Failed to hash ESSIV key.\n");
+			return err;
+		}
+	}
+	dma_sync_single_for_device(dev, ctx_p->user.key_dma_addr,
+				   max_key_buf_size, DMA_TO_DEVICE);
+	ctx_p->keylen = keylen;
+
+	dev_dbg(dev, "return safely");
+	return 0;
+}
+
+static void cc_setup_cipher_desc(struct crypto_tfm *tfm,
+				 struct cipher_req_ctx *req_ctx,
+				 unsigned int ivsize, unsigned int nbytes,
+				 struct cc_hw_desc desc[],
+				 unsigned int *seq_size)
+{
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
+	int cipher_mode = ctx_p->cipher_mode;
+	int flow_mode = ctx_p->flow_mode;
+	int direction = req_ctx->gen_ctx.op_type;
+	dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr;
+	unsigned int key_len = ctx_p->keylen;
+	dma_addr_t iv_dma_addr = req_ctx->gen_ctx.iv_dma_addr;
+	unsigned int du_size = nbytes;
+
+	struct cc_crypto_alg *cc_alg =
+		container_of(tfm->__crt_alg, struct cc_crypto_alg,
+			     skcipher_alg.base);
+
+	if (cc_alg->data_unit)
+		du_size = cc_alg->data_unit;
+
+	switch (cipher_mode) {
+	case DRV_CIPHER_CBC:
+	case DRV_CIPHER_CBC_CTS:
+	case DRV_CIPHER_CTR:
+	case DRV_CIPHER_OFB:
+		/* Load cipher state */
+		hw_desc_init(&desc[*seq_size]);
+		set_din_type(&desc[*seq_size], DMA_DLLI, iv_dma_addr, ivsize,
+			     NS_BIT);
+		set_cipher_config0(&desc[*seq_size], direction);
+		set_flow_mode(&desc[*seq_size], flow_mode);
+		set_cipher_mode(&desc[*seq_size], cipher_mode);
+		if (cipher_mode == DRV_CIPHER_CTR ||
+		    cipher_mode == DRV_CIPHER_OFB) {
+			set_setup_mode(&desc[*seq_size], SETUP_LOAD_STATE1);
+		} else {
+			set_setup_mode(&desc[*seq_size], SETUP_LOAD_STATE0);
+		}
+		(*seq_size)++;
+		/*FALLTHROUGH*/
+	case DRV_CIPHER_ECB:
+		/* Load key */
+		hw_desc_init(&desc[*seq_size]);
+		set_cipher_mode(&desc[*seq_size], cipher_mode);
+		set_cipher_config0(&desc[*seq_size], direction);
+		if (flow_mode == S_DIN_to_AES) {
+			if (cc_is_hw_key(tfm)) {
+				set_hw_crypto_key(&desc[*seq_size],
+						  ctx_p->hw.key1_slot);
+			} else {
+				set_din_type(&desc[*seq_size], DMA_DLLI,
+					     key_dma_addr, ((key_len == 24) ?
+							    AES_MAX_KEY_SIZE :
+							    key_len), NS_BIT);
+			}
+			set_key_size_aes(&desc[*seq_size], key_len);
+		} else {
+			/*des*/
+			set_din_type(&desc[*seq_size], DMA_DLLI, key_dma_addr,
+				     key_len, NS_BIT);
+			set_key_size_des(&desc[*seq_size], key_len);
+		}
+		set_flow_mode(&desc[*seq_size], flow_mode);
+		set_setup_mode(&desc[*seq_size], SETUP_LOAD_KEY0);
+		(*seq_size)++;
+		break;
+	case DRV_CIPHER_XTS:
+	case DRV_CIPHER_ESSIV:
+	case DRV_CIPHER_BITLOCKER:
+		/* Load AES key */
+		hw_desc_init(&desc[*seq_size]);
+		set_cipher_mode(&desc[*seq_size], cipher_mode);
+		set_cipher_config0(&desc[*seq_size], direction);
+		if (cc_is_hw_key(tfm)) {
+			set_hw_crypto_key(&desc[*seq_size],
+					  ctx_p->hw.key1_slot);
+		} else {
+			set_din_type(&desc[*seq_size], DMA_DLLI, key_dma_addr,
+				     (key_len / 2), NS_BIT);
+		}
+		set_key_size_aes(&desc[*seq_size], (key_len / 2));
+		set_flow_mode(&desc[*seq_size], flow_mode);
+		set_setup_mode(&desc[*seq_size], SETUP_LOAD_KEY0);
+		(*seq_size)++;
+
+		/* load XEX key */
+		hw_desc_init(&desc[*seq_size]);
+		set_cipher_mode(&desc[*seq_size], cipher_mode);
+		set_cipher_config0(&desc[*seq_size], direction);
+		if (cc_is_hw_key(tfm)) {
+			set_hw_crypto_key(&desc[*seq_size],
+					  ctx_p->hw.key2_slot);
+		} else {
+			set_din_type(&desc[*seq_size], DMA_DLLI,
+				     (key_dma_addr + (key_len / 2)),
+				     (key_len / 2), NS_BIT);
+		}
+		set_xex_data_unit_size(&desc[*seq_size], du_size);
+		set_flow_mode(&desc[*seq_size], S_DIN_to_AES2);
+		set_key_size_aes(&desc[*seq_size], (key_len / 2));
+		set_setup_mode(&desc[*seq_size], SETUP_LOAD_XEX_KEY);
+		(*seq_size)++;
+
+		/* Set state */
+		hw_desc_init(&desc[*seq_size]);
+		set_setup_mode(&desc[*seq_size], SETUP_LOAD_STATE1);
+		set_cipher_mode(&desc[*seq_size], cipher_mode);
+		set_cipher_config0(&desc[*seq_size], direction);
+		set_key_size_aes(&desc[*seq_size], (key_len / 2));
+		set_flow_mode(&desc[*seq_size], flow_mode);
+		set_din_type(&desc[*seq_size], DMA_DLLI, iv_dma_addr,
+			     CC_AES_BLOCK_SIZE, NS_BIT);
+		(*seq_size)++;
+		break;
+	default:
+		dev_err(dev, "Unsupported cipher mode (%d)\n", cipher_mode);
+	}
+}
+
+static void cc_setup_cipher_data(struct crypto_tfm *tfm,
+				 struct cipher_req_ctx *req_ctx,
+				 struct scatterlist *dst,
+				 struct scatterlist *src, unsigned int nbytes,
+				 void *areq, struct cc_hw_desc desc[],
+				 unsigned int *seq_size)
+{
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
+	unsigned int flow_mode = ctx_p->flow_mode;
+
+	switch (ctx_p->flow_mode) {
+	case S_DIN_to_AES:
+		flow_mode = DIN_AES_DOUT;
+		break;
+	case S_DIN_to_DES:
+		flow_mode = DIN_DES_DOUT;
+		break;
+	default:
+		dev_err(dev, "invalid flow mode, flow_mode = %d\n", flow_mode);
+		return;
+	}
+	/* Process */
+	if (req_ctx->dma_buf_type == CC_DMA_BUF_DLLI) {
+		dev_dbg(dev, " data params addr %pad length 0x%X\n",
+			&sg_dma_address(src), nbytes);
+		dev_dbg(dev, " data params addr %pad length 0x%X\n",
+			&sg_dma_address(dst), nbytes);
+		hw_desc_init(&desc[*seq_size]);
+		set_din_type(&desc[*seq_size], DMA_DLLI, sg_dma_address(src),
+			     nbytes, NS_BIT);
+		set_dout_dlli(&desc[*seq_size], sg_dma_address(dst),
+			      nbytes, NS_BIT, (!areq ? 0 : 1));
+		if (areq)
+			set_queue_last_ind(&desc[*seq_size]);
+
+		set_flow_mode(&desc[*seq_size], flow_mode);
+		(*seq_size)++;
+	} else {
+		/* bypass */
+		dev_dbg(dev, " bypass params addr %pad length 0x%X addr 0x%08X\n",
+			&req_ctx->mlli_params.mlli_dma_addr,
+			req_ctx->mlli_params.mlli_len,
+			(unsigned int)ctx_p->drvdata->mlli_sram_addr);
+		hw_desc_init(&desc[*seq_size]);
+		set_din_type(&desc[*seq_size], DMA_DLLI,
+			     req_ctx->mlli_params.mlli_dma_addr,
+			     req_ctx->mlli_params.mlli_len, NS_BIT);
+		set_dout_sram(&desc[*seq_size],
+			      ctx_p->drvdata->mlli_sram_addr,
+			      req_ctx->mlli_params.mlli_len);
+		set_flow_mode(&desc[*seq_size], BYPASS);
+		(*seq_size)++;
+
+		hw_desc_init(&desc[*seq_size]);
+		set_din_type(&desc[*seq_size], DMA_MLLI,
+			     ctx_p->drvdata->mlli_sram_addr,
+			     req_ctx->in_mlli_nents, NS_BIT);
+		if (req_ctx->out_nents == 0) {
+			dev_dbg(dev, " din/dout params addr 0x%08X addr 0x%08X\n",
+				(unsigned int)ctx_p->drvdata->mlli_sram_addr,
+				(unsigned int)ctx_p->drvdata->mlli_sram_addr);
+			set_dout_mlli(&desc[*seq_size],
+				      ctx_p->drvdata->mlli_sram_addr,
+				      req_ctx->in_mlli_nents, NS_BIT,
+				      (!areq ? 0 : 1));
+		} else {
+			dev_dbg(dev, " din/dout params addr 0x%08X addr 0x%08X\n",
+				(unsigned int)ctx_p->drvdata->mlli_sram_addr,
+				(unsigned int)ctx_p->drvdata->mlli_sram_addr +
+				(u32)LLI_ENTRY_BYTE_SIZE * req_ctx->in_nents);
+			set_dout_mlli(&desc[*seq_size],
+				      (ctx_p->drvdata->mlli_sram_addr +
+				       (LLI_ENTRY_BYTE_SIZE *
+					req_ctx->in_mlli_nents)),
+				      req_ctx->out_mlli_nents, NS_BIT,
+				      (!areq ? 0 : 1));
+		}
+		if (areq)
+			set_queue_last_ind(&desc[*seq_size]);
+
+		set_flow_mode(&desc[*seq_size], flow_mode);
+		(*seq_size)++;
+	}
+}
+
+static void cc_cipher_complete(struct device *dev, void *cc_req, int err)
+{
+	struct skcipher_request *req = (struct skcipher_request *)cc_req;
+	struct scatterlist *dst = req->dst;
+	struct scatterlist *src = req->src;
+	struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	unsigned int ivsize = crypto_skcipher_ivsize(tfm);
+
+	cc_unmap_cipher_request(dev, req_ctx, ivsize, src, dst);
+	kzfree(req_ctx->iv);
+
+	/*
+	 * The crypto API expects us to set the req->iv to the last
+	 * ciphertext block. For encrypt, simply copy from the result.
+	 * For decrypt, we must copy from a saved buffer since this
+	 * could be an in-place decryption operation and the src is
+	 * lost by this point.
+	 */
+	if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT)  {
+		memcpy(req->iv, req_ctx->backup_info, ivsize);
+		kzfree(req_ctx->backup_info);
+	} else if (!err) {
+		scatterwalk_map_and_copy(req->iv, req->dst,
+					 (req->cryptlen - ivsize),
+					 ivsize, 0);
+	}
+
+	skcipher_request_complete(req, err);
+}
+
+static int cc_cipher_process(struct skcipher_request *req,
+			     enum drv_crypto_direction direction)
+{
+	struct crypto_skcipher *sk_tfm = crypto_skcipher_reqtfm(req);
+	struct crypto_tfm *tfm = crypto_skcipher_tfm(sk_tfm);
+	struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+	unsigned int ivsize = crypto_skcipher_ivsize(sk_tfm);
+	struct scatterlist *dst = req->dst;
+	struct scatterlist *src = req->src;
+	unsigned int nbytes = req->cryptlen;
+	void *iv = req->iv;
+	struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
+	struct cc_hw_desc desc[MAX_ABLKCIPHER_SEQ_LEN];
+	struct cc_crypto_req cc_req = {};
+	int rc, cts_restore_flag = 0;
+	unsigned int seq_len = 0;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "%s req=%p iv=%p nbytes=%d\n",
+		((direction == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+		"Encrypt" : "Decrypt"), req, iv, nbytes);
+
+	/* STAT_PHASE_0: Init and sanity checks */
+
+	/* TODO: check data length according to mode */
+	if (validate_data_size(ctx_p, nbytes)) {
+		dev_err(dev, "Unsupported data size %d.\n", nbytes);
+		crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN);
+		rc = -EINVAL;
+		goto exit_process;
+	}
+	if (nbytes == 0) {
+		/* No data to process is valid */
+		rc = 0;
+		goto exit_process;
+	}
+
+	/* The IV we are handed may be allocted from the stack so
+	 * we must copy it to a DMAable buffer before use.
+	 */
+	req_ctx->iv = kmalloc(ivsize, flags);
+	if (!req_ctx->iv) {
+		rc = -ENOMEM;
+		goto exit_process;
+	}
+	memcpy(req_ctx->iv, iv, ivsize);
+
+	/*For CTS in case of data size aligned to 16 use CBC mode*/
+	if (((nbytes % AES_BLOCK_SIZE) == 0) &&
+	    ctx_p->cipher_mode == DRV_CIPHER_CBC_CTS) {
+		ctx_p->cipher_mode = DRV_CIPHER_CBC;
+		cts_restore_flag = 1;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = (void *)cc_cipher_complete;
+	cc_req.user_arg = (void *)req;
+
+#ifdef ENABLE_CYCLE_COUNT
+	cc_req.op_type = (direction == DRV_CRYPTO_DIRECTION_DECRYPT) ?
+		STAT_OP_TYPE_DECODE : STAT_OP_TYPE_ENCODE;
+
+#endif
+
+	/* Setup request context */
+	req_ctx->gen_ctx.op_type = direction;
+
+	/* STAT_PHASE_1: Map buffers */
+
+	rc = cc_map_cipher_request(ctx_p->drvdata, req_ctx, ivsize, nbytes,
+				      req_ctx->iv, src, dst, flags);
+	if (rc) {
+		dev_err(dev, "map_request() failed\n");
+		goto exit_process;
+	}
+
+	/* STAT_PHASE_2: Create sequence */
+
+	/* Setup processing */
+	cc_setup_cipher_desc(tfm, req_ctx, ivsize, nbytes, desc, &seq_len);
+	/* Data processing */
+	cc_setup_cipher_data(tfm, req_ctx, dst, src, nbytes, req, desc,
+			     &seq_len);
+
+	/* do we need to generate IV? */
+	if (req_ctx->is_giv) {
+		cc_req.ivgen_dma_addr[0] = req_ctx->gen_ctx.iv_dma_addr;
+		cc_req.ivgen_dma_addr_len = 1;
+		/* set the IV size (8/16 B long)*/
+		cc_req.ivgen_size = ivsize;
+	}
+
+	/* STAT_PHASE_3: Lock HW and push sequence */
+
+	rc = cc_send_request(ctx_p->drvdata, &cc_req, desc, seq_len,
+			     &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		/* Failed to send the request or request completed
+		 * synchronously
+		 */
+		cc_unmap_cipher_request(dev, req_ctx, ivsize, src, dst);
+	}
+
+exit_process:
+	if (cts_restore_flag)
+		ctx_p->cipher_mode = DRV_CIPHER_CBC_CTS;
+
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		kzfree(req_ctx->backup_info);
+		kzfree(req_ctx->iv);
+	}
+
+	return rc;
+}
+
+static int cc_cipher_encrypt(struct skcipher_request *req)
+{
+	struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+
+	req_ctx->is_giv = false;
+	req_ctx->backup_info = NULL;
+
+	return cc_cipher_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+}
+
+static int cc_cipher_decrypt(struct skcipher_request *req)
+{
+	struct crypto_skcipher *sk_tfm = crypto_skcipher_reqtfm(req);
+	struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+	unsigned int ivsize = crypto_skcipher_ivsize(sk_tfm);
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	/*
+	 * Allocate and save the last IV sized bytes of the source, which will
+	 * be lost in case of in-place decryption and might be needed for CTS.
+	 */
+	req_ctx->backup_info = kmalloc(ivsize, flags);
+	if (!req_ctx->backup_info)
+		return -ENOMEM;
+
+	scatterwalk_map_and_copy(req_ctx->backup_info, req->src,
+				 (req->cryptlen - ivsize), ivsize, 0);
+	req_ctx->is_giv = false;
+
+	return cc_cipher_process(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+}
+
+/* Block cipher alg */
+static const struct cc_alg_template skcipher_algs[] = {
+	{
+		.name = "xts(aes)",
+		.driver_name = "xts-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_XTS,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "xts512(aes)",
+		.driver_name = "xts-aes-du512-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_XTS,
+		.flow_mode = S_DIN_to_AES,
+		.data_unit = 512,
+	},
+	{
+		.name = "xts4096(aes)",
+		.driver_name = "xts-aes-du4096-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_XTS,
+		.flow_mode = S_DIN_to_AES,
+		.data_unit = 4096,
+	},
+	{
+		.name = "essiv(aes)",
+		.driver_name = "essiv-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_ESSIV,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "essiv512(aes)",
+		.driver_name = "essiv-aes-du512-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_ESSIV,
+		.flow_mode = S_DIN_to_AES,
+		.data_unit = 512,
+	},
+	{
+		.name = "essiv4096(aes)",
+		.driver_name = "essiv-aes-du4096-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_ESSIV,
+		.flow_mode = S_DIN_to_AES,
+		.data_unit = 4096,
+	},
+	{
+		.name = "bitlocker(aes)",
+		.driver_name = "bitlocker-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_BITLOCKER,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "bitlocker512(aes)",
+		.driver_name = "bitlocker-aes-du512-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_BITLOCKER,
+		.flow_mode = S_DIN_to_AES,
+		.data_unit = 512,
+	},
+	{
+		.name = "bitlocker4096(aes)",
+		.driver_name = "bitlocker-aes-du4096-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_BITLOCKER,
+		.flow_mode = S_DIN_to_AES,
+		.data_unit = 4096,
+	},
+	{
+		.name = "ecb(aes)",
+		.driver_name = "ecb-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = 0,
+			},
+		.cipher_mode = DRV_CIPHER_ECB,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "cbc(aes)",
+		.driver_name = "cbc-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+		},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "ofb(aes)",
+		.driver_name = "ofb-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_OFB,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "cts1(cbc(aes))",
+		.driver_name = "cts1-cbc-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_CBC_CTS,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "ctr(aes)",
+		.driver_name = "ctr-aes-ccree",
+		.blocksize = 1,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_CTR,
+		.flow_mode = S_DIN_to_AES,
+	},
+	{
+		.name = "cbc(des3_ede)",
+		.driver_name = "cbc-3des-ccree",
+		.blocksize = DES3_EDE_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = DES3_EDE_KEY_SIZE,
+			.max_keysize = DES3_EDE_KEY_SIZE,
+			.ivsize = DES3_EDE_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_DES,
+	},
+	{
+		.name = "ecb(des3_ede)",
+		.driver_name = "ecb-3des-ccree",
+		.blocksize = DES3_EDE_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = DES3_EDE_KEY_SIZE,
+			.max_keysize = DES3_EDE_KEY_SIZE,
+			.ivsize = 0,
+			},
+		.cipher_mode = DRV_CIPHER_ECB,
+		.flow_mode = S_DIN_to_DES,
+	},
+	{
+		.name = "cbc(des)",
+		.driver_name = "cbc-des-ccree",
+		.blocksize = DES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = DES_KEY_SIZE,
+			.max_keysize = DES_KEY_SIZE,
+			.ivsize = DES_BLOCK_SIZE,
+			},
+		.cipher_mode = DRV_CIPHER_CBC,
+		.flow_mode = S_DIN_to_DES,
+	},
+	{
+		.name = "ecb(des)",
+		.driver_name = "ecb-des-ccree",
+		.blocksize = DES_BLOCK_SIZE,
+		.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+		.template_skcipher = {
+			.setkey = cc_cipher_setkey,
+			.encrypt = cc_cipher_encrypt,
+			.decrypt = cc_cipher_decrypt,
+			.min_keysize = DES_KEY_SIZE,
+			.max_keysize = DES_KEY_SIZE,
+			.ivsize = 0,
+			},
+		.cipher_mode = DRV_CIPHER_ECB,
+		.flow_mode = S_DIN_to_DES,
+	},
+};
+
+static struct cc_crypto_alg *cc_create_alg(const struct cc_alg_template *tmpl,
+					   struct device *dev)
+{
+	struct cc_crypto_alg *t_alg;
+	struct skcipher_alg *alg;
+
+	t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
+	if (!t_alg)
+		return ERR_PTR(-ENOMEM);
+
+	alg = &t_alg->skcipher_alg;
+
+	memcpy(alg, &tmpl->template_skcipher, sizeof(*alg));
+
+	snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
+	snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+		 tmpl->driver_name);
+	alg->base.cra_module = THIS_MODULE;
+	alg->base.cra_priority = CC_CRA_PRIO;
+	alg->base.cra_blocksize = tmpl->blocksize;
+	alg->base.cra_alignmask = 0;
+	alg->base.cra_ctxsize = sizeof(struct cc_cipher_ctx);
+
+	alg->base.cra_init = cc_cipher_init;
+	alg->base.cra_exit = cc_cipher_exit;
+	alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+				CRYPTO_ALG_TYPE_SKCIPHER;
+
+	t_alg->cipher_mode = tmpl->cipher_mode;
+	t_alg->flow_mode = tmpl->flow_mode;
+	t_alg->data_unit = tmpl->data_unit;
+
+	return t_alg;
+}
+
+int cc_cipher_free(struct cc_drvdata *drvdata)
+{
+	struct cc_crypto_alg *t_alg, *n;
+	struct cc_cipher_handle *cipher_handle = drvdata->cipher_handle;
+
+	if (cipher_handle) {
+		/* Remove registered algs */
+		list_for_each_entry_safe(t_alg, n, &cipher_handle->alg_list,
+					 entry) {
+			crypto_unregister_skcipher(&t_alg->skcipher_alg);
+			list_del(&t_alg->entry);
+			kfree(t_alg);
+		}
+		kfree(cipher_handle);
+		drvdata->cipher_handle = NULL;
+	}
+	return 0;
+}
+
+int cc_cipher_alloc(struct cc_drvdata *drvdata)
+{
+	struct cc_cipher_handle *cipher_handle;
+	struct cc_crypto_alg *t_alg;
+	struct device *dev = drvdata_to_dev(drvdata);
+	int rc = -ENOMEM;
+	int alg;
+
+	cipher_handle = kmalloc(sizeof(*cipher_handle), GFP_KERNEL);
+	if (!cipher_handle)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&cipher_handle->alg_list);
+	drvdata->cipher_handle = cipher_handle;
+
+	/* Linux crypto */
+	dev_dbg(dev, "Number of algorithms = %zu\n",
+		ARRAY_SIZE(skcipher_algs));
+	for (alg = 0; alg < ARRAY_SIZE(skcipher_algs); alg++) {
+		dev_dbg(dev, "creating %s\n", skcipher_algs[alg].driver_name);
+		t_alg = cc_create_alg(&skcipher_algs[alg], dev);
+		if (IS_ERR(t_alg)) {
+			rc = PTR_ERR(t_alg);
+			dev_err(dev, "%s alg allocation failed\n",
+				skcipher_algs[alg].driver_name);
+			goto fail0;
+		}
+		t_alg->drvdata = drvdata;
+
+		dev_dbg(dev, "registering %s\n",
+			skcipher_algs[alg].driver_name);
+		rc = crypto_register_skcipher(&t_alg->skcipher_alg);
+		dev_dbg(dev, "%s alg registration rc = %x\n",
+			t_alg->skcipher_alg.base.cra_driver_name, rc);
+		if (rc) {
+			dev_err(dev, "%s alg registration failed\n",
+				t_alg->skcipher_alg.base.cra_driver_name);
+			kfree(t_alg);
+			goto fail0;
+		} else {
+			list_add_tail(&t_alg->entry,
+				      &cipher_handle->alg_list);
+			dev_dbg(dev, "Registered %s\n",
+				t_alg->skcipher_alg.base.cra_driver_name);
+		}
+	}
+	return 0;
+
+fail0:
+	cc_cipher_free(drvdata);
+	return rc;
+}
diff --git a/drivers/crypto/ccree/cc_cipher.h b/drivers/crypto/ccree/cc_cipher.h
new file mode 100644
index 000000000000..2a2a6f46c515
--- /dev/null
+++ b/drivers/crypto/ccree/cc_cipher.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_cipher.h
+ * ARM CryptoCell Cipher Crypto API
+ */
+
+#ifndef __CC_CIPHER_H__
+#define __CC_CIPHER_H__
+
+#include <linux/kernel.h>
+#include <crypto/algapi.h>
+#include "cc_driver.h"
+#include "cc_buffer_mgr.h"
+
+/* Crypto cipher flags */
+#define CC_CRYPTO_CIPHER_KEY_KFDE0	BIT(0)
+#define CC_CRYPTO_CIPHER_KEY_KFDE1	BIT(1)
+#define CC_CRYPTO_CIPHER_KEY_KFDE2	BIT(2)
+#define CC_CRYPTO_CIPHER_KEY_KFDE3	BIT(3)
+#define CC_CRYPTO_CIPHER_DU_SIZE_512B	BIT(4)
+
+#define CC_CRYPTO_CIPHER_KEY_KFDE_MASK (CC_CRYPTO_CIPHER_KEY_KFDE0 | \
+					CC_CRYPTO_CIPHER_KEY_KFDE1 | \
+					CC_CRYPTO_CIPHER_KEY_KFDE2 | \
+					CC_CRYPTO_CIPHER_KEY_KFDE3)
+
+struct cipher_req_ctx {
+	struct async_gen_req_ctx gen_ctx;
+	enum cc_req_dma_buf_type dma_buf_type;
+	u32 in_nents;
+	u32 in_mlli_nents;
+	u32 out_nents;
+	u32 out_mlli_nents;
+	u8 *backup_info; /*store iv for generated IV flow*/
+	u8 *iv;
+	bool is_giv;
+	struct mlli_params mlli_params;
+};
+
+int cc_cipher_alloc(struct cc_drvdata *drvdata);
+
+int cc_cipher_free(struct cc_drvdata *drvdata);
+
+struct arm_hw_key_info {
+	int hw_key1;
+	int hw_key2;
+};
+
+/*
+ * This is a stub function that will replaced when we
+ * implement secure keys
+ */
+static inline bool cc_is_hw_key(struct crypto_tfm *tfm)
+{
+	return false;
+}
+
+#endif /*__CC_CIPHER_H__*/
diff --git a/drivers/crypto/ccree/cc_crypto_ctx.h b/drivers/crypto/ccree/cc_crypto_ctx.h
new file mode 100644
index 000000000000..5cb4dde0236e
--- /dev/null
+++ b/drivers/crypto/ccree/cc_crypto_ctx.h
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef _CC_CRYPTO_CTX_H_
+#define _CC_CRYPTO_CTX_H_
+
+#include <linux/types.h>
+
+/* context size */
+#ifndef CC_CTX_SIZE_LOG2
+#if (CC_DEV_SHA_MAX > 256)
+#define CC_CTX_SIZE_LOG2 8
+#else
+#define CC_CTX_SIZE_LOG2 7
+#endif
+#endif
+#define CC_CTX_SIZE BIT(CC_CTX_SIZE_LOG2)
+#define CC_DRV_CTX_SIZE_WORDS (CC_CTX_SIZE >> 2)
+
+#define CC_DRV_DES_IV_SIZE 8
+#define CC_DRV_DES_BLOCK_SIZE 8
+
+#define CC_DRV_DES_ONE_KEY_SIZE 8
+#define CC_DRV_DES_DOUBLE_KEY_SIZE 16
+#define CC_DRV_DES_TRIPLE_KEY_SIZE 24
+#define CC_DRV_DES_KEY_SIZE_MAX CC_DRV_DES_TRIPLE_KEY_SIZE
+
+#define CC_AES_IV_SIZE 16
+#define CC_AES_IV_SIZE_WORDS (CC_AES_IV_SIZE >> 2)
+
+#define CC_AES_BLOCK_SIZE 16
+#define CC_AES_BLOCK_SIZE_WORDS 4
+
+#define CC_AES_128_BIT_KEY_SIZE 16
+#define CC_AES_128_BIT_KEY_SIZE_WORDS	(CC_AES_128_BIT_KEY_SIZE >> 2)
+#define CC_AES_192_BIT_KEY_SIZE 24
+#define CC_AES_192_BIT_KEY_SIZE_WORDS	(CC_AES_192_BIT_KEY_SIZE >> 2)
+#define CC_AES_256_BIT_KEY_SIZE 32
+#define CC_AES_256_BIT_KEY_SIZE_WORDS	(CC_AES_256_BIT_KEY_SIZE >> 2)
+#define CC_AES_KEY_SIZE_MAX			CC_AES_256_BIT_KEY_SIZE
+#define CC_AES_KEY_SIZE_WORDS_MAX		(CC_AES_KEY_SIZE_MAX >> 2)
+
+#define CC_MD5_DIGEST_SIZE	16
+#define CC_SHA1_DIGEST_SIZE	20
+#define CC_SHA224_DIGEST_SIZE	28
+#define CC_SHA256_DIGEST_SIZE	32
+#define CC_SHA256_DIGEST_SIZE_IN_WORDS 8
+#define CC_SHA384_DIGEST_SIZE	48
+#define CC_SHA512_DIGEST_SIZE	64
+
+#define CC_SHA1_BLOCK_SIZE 64
+#define CC_SHA1_BLOCK_SIZE_IN_WORDS 16
+#define CC_MD5_BLOCK_SIZE 64
+#define CC_MD5_BLOCK_SIZE_IN_WORDS 16
+#define CC_SHA224_BLOCK_SIZE 64
+#define CC_SHA256_BLOCK_SIZE 64
+#define CC_SHA256_BLOCK_SIZE_IN_WORDS 16
+#define CC_SHA1_224_256_BLOCK_SIZE 64
+#define CC_SHA384_BLOCK_SIZE 128
+#define CC_SHA512_BLOCK_SIZE 128
+
+#if (CC_DEV_SHA_MAX > 256)
+#define CC_DIGEST_SIZE_MAX CC_SHA512_DIGEST_SIZE
+#define CC_HASH_BLOCK_SIZE_MAX CC_SHA512_BLOCK_SIZE /*1024b*/
+#else /* Only up to SHA256 */
+#define CC_DIGEST_SIZE_MAX CC_SHA256_DIGEST_SIZE
+#define CC_HASH_BLOCK_SIZE_MAX CC_SHA256_BLOCK_SIZE /*512b*/
+#endif
+
+#define CC_HMAC_BLOCK_SIZE_MAX CC_HASH_BLOCK_SIZE_MAX
+
+#define CC_DRV_ALG_MAX_BLOCK_SIZE CC_HASH_BLOCK_SIZE_MAX
+
+enum drv_engine_type {
+	DRV_ENGINE_NULL = 0,
+	DRV_ENGINE_AES = 1,
+	DRV_ENGINE_DES = 2,
+	DRV_ENGINE_HASH = 3,
+	DRV_ENGINE_RC4 = 4,
+	DRV_ENGINE_DOUT = 5,
+	DRV_ENGINE_RESERVE32B = S32_MAX,
+};
+
+enum drv_crypto_alg {
+	DRV_CRYPTO_ALG_NULL = -1,
+	DRV_CRYPTO_ALG_AES  = 0,
+	DRV_CRYPTO_ALG_DES  = 1,
+	DRV_CRYPTO_ALG_HASH = 2,
+	DRV_CRYPTO_ALG_C2   = 3,
+	DRV_CRYPTO_ALG_HMAC = 4,
+	DRV_CRYPTO_ALG_AEAD = 5,
+	DRV_CRYPTO_ALG_BYPASS = 6,
+	DRV_CRYPTO_ALG_NUM = 7,
+	DRV_CRYPTO_ALG_RESERVE32B = S32_MAX
+};
+
+enum drv_crypto_direction {
+	DRV_CRYPTO_DIRECTION_NULL = -1,
+	DRV_CRYPTO_DIRECTION_ENCRYPT = 0,
+	DRV_CRYPTO_DIRECTION_DECRYPT = 1,
+	DRV_CRYPTO_DIRECTION_DECRYPT_ENCRYPT = 3,
+	DRV_CRYPTO_DIRECTION_RESERVE32B = S32_MAX
+};
+
+enum drv_cipher_mode {
+	DRV_CIPHER_NULL_MODE = -1,
+	DRV_CIPHER_ECB = 0,
+	DRV_CIPHER_CBC = 1,
+	DRV_CIPHER_CTR = 2,
+	DRV_CIPHER_CBC_MAC = 3,
+	DRV_CIPHER_XTS = 4,
+	DRV_CIPHER_XCBC_MAC = 5,
+	DRV_CIPHER_OFB = 6,
+	DRV_CIPHER_CMAC = 7,
+	DRV_CIPHER_CCM = 8,
+	DRV_CIPHER_CBC_CTS = 11,
+	DRV_CIPHER_GCTR = 12,
+	DRV_CIPHER_ESSIV = 13,
+	DRV_CIPHER_BITLOCKER = 14,
+	DRV_CIPHER_RESERVE32B = S32_MAX
+};
+
+enum drv_hash_mode {
+	DRV_HASH_NULL = -1,
+	DRV_HASH_SHA1 = 0,
+	DRV_HASH_SHA256 = 1,
+	DRV_HASH_SHA224 = 2,
+	DRV_HASH_SHA512 = 3,
+	DRV_HASH_SHA384 = 4,
+	DRV_HASH_MD5 = 5,
+	DRV_HASH_CBC_MAC = 6,
+	DRV_HASH_XCBC_MAC = 7,
+	DRV_HASH_CMAC = 8,
+	DRV_HASH_MODE_NUM = 9,
+	DRV_HASH_RESERVE32B = S32_MAX
+};
+
+enum drv_hash_hw_mode {
+	DRV_HASH_HW_MD5 = 0,
+	DRV_HASH_HW_SHA1 = 1,
+	DRV_HASH_HW_SHA256 = 2,
+	DRV_HASH_HW_SHA224 = 10,
+	DRV_HASH_HW_SHA512 = 4,
+	DRV_HASH_HW_SHA384 = 12,
+	DRV_HASH_HW_GHASH = 6,
+	DRV_HASH_HW_RESERVE32B = S32_MAX
+};
+
+/* drv_crypto_key_type[1:0] is mapped to cipher_do[1:0] */
+/* drv_crypto_key_type[2] is mapped to cipher_config2 */
+enum drv_crypto_key_type {
+	DRV_NULL_KEY = -1,
+	DRV_USER_KEY = 0,		/* 0x000 */
+	DRV_ROOT_KEY = 1,		/* 0x001 */
+	DRV_PROVISIONING_KEY = 2,	/* 0x010 */
+	DRV_SESSION_KEY = 3,		/* 0x011 */
+	DRV_APPLET_KEY = 4,		/* NA */
+	DRV_PLATFORM_KEY = 5,		/* 0x101 */
+	DRV_CUSTOMER_KEY = 6,		/* 0x110 */
+	DRV_END_OF_KEYS = S32_MAX,
+};
+
+enum drv_crypto_padding_type {
+	DRV_PADDING_NONE = 0,
+	DRV_PADDING_PKCS7 = 1,
+	DRV_PADDING_RESERVE32B = S32_MAX
+};
+
+#endif /* _CC_CRYPTO_CTX_H_ */
diff --git a/drivers/crypto/ccree/cc_debugfs.c b/drivers/crypto/ccree/cc_debugfs.c
new file mode 100644
index 000000000000..08f8db489cf0
--- /dev/null
+++ b/drivers/crypto/ccree/cc_debugfs.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/stringify.h>
+#include "cc_driver.h"
+#include "cc_crypto_ctx.h"
+#include "cc_debugfs.h"
+
+struct cc_debugfs_ctx {
+	struct dentry *dir;
+};
+
+#define CC_DEBUG_REG(_X) {	\
+	.name = __stringify(_X),\
+	.offset = CC_REG(_X)	\
+	}
+
+/*
+ * This is a global var for the dentry of the
+ * debugfs ccree/ dir. It is not tied down to
+ * a specific instance of ccree, hence it is
+ * global.
+ */
+static struct dentry *cc_debugfs_dir;
+
+static struct debugfs_reg32 debug_regs[] = {
+	CC_DEBUG_REG(HOST_SIGNATURE),
+	CC_DEBUG_REG(HOST_IRR),
+	CC_DEBUG_REG(HOST_POWER_DOWN_EN),
+	CC_DEBUG_REG(AXIM_MON_ERR),
+	CC_DEBUG_REG(DSCRPTR_QUEUE_CONTENT),
+	CC_DEBUG_REG(HOST_IMR),
+	CC_DEBUG_REG(AXIM_CFG),
+	CC_DEBUG_REG(AXIM_CACHE_PARAMS),
+	CC_DEBUG_REG(HOST_VERSION),
+	CC_DEBUG_REG(GPR_HOST),
+	CC_DEBUG_REG(AXIM_MON_COMP),
+};
+
+int __init cc_debugfs_global_init(void)
+{
+	cc_debugfs_dir = debugfs_create_dir("ccree", NULL);
+
+	return !cc_debugfs_dir;
+}
+
+void __exit cc_debugfs_global_fini(void)
+{
+	debugfs_remove(cc_debugfs_dir);
+}
+
+int cc_debugfs_init(struct cc_drvdata *drvdata)
+{
+	struct device *dev = drvdata_to_dev(drvdata);
+	struct cc_debugfs_ctx *ctx;
+	struct debugfs_regset32 *regset;
+	struct dentry *file;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
+	if (!regset)
+		return -ENOMEM;
+
+	regset->regs = debug_regs;
+	regset->nregs = ARRAY_SIZE(debug_regs);
+	regset->base = drvdata->cc_base;
+
+	ctx->dir = debugfs_create_dir(drvdata->plat_dev->name, cc_debugfs_dir);
+	if (!ctx->dir)
+		return -ENFILE;
+
+	file = debugfs_create_regset32("regs", 0400, ctx->dir, regset);
+	if (!file) {
+		debugfs_remove(ctx->dir);
+		return -ENFILE;
+	}
+
+	file = debugfs_create_bool("coherent", 0400, ctx->dir,
+				   &drvdata->coherent);
+
+	if (!file) {
+		debugfs_remove_recursive(ctx->dir);
+		return -ENFILE;
+	}
+
+	drvdata->debugfs = ctx;
+
+	return 0;
+}
+
+void cc_debugfs_fini(struct cc_drvdata *drvdata)
+{
+	struct cc_debugfs_ctx *ctx = (struct cc_debugfs_ctx *)drvdata->debugfs;
+
+	debugfs_remove_recursive(ctx->dir);
+}
diff --git a/drivers/crypto/ccree/cc_debugfs.h b/drivers/crypto/ccree/cc_debugfs.h
new file mode 100644
index 000000000000..5b5320eca7d2
--- /dev/null
+++ b/drivers/crypto/ccree/cc_debugfs.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_DEBUGFS_H__
+#define __CC_DEBUGFS_H__
+
+#ifdef CONFIG_DEBUG_FS
+int cc_debugfs_global_init(void);
+void cc_debugfs_global_fini(void);
+
+int cc_debugfs_init(struct cc_drvdata *drvdata);
+void cc_debugfs_fini(struct cc_drvdata *drvdata);
+
+#else
+
+static inline int cc_debugfs_global_init(void)
+{
+	return 0;
+}
+
+static inline void cc_debugfs_global_fini(void) {}
+
+static inline int cc_debugfs_init(struct cc_drvdata *drvdata)
+{
+	return 0;
+}
+
+static inline void cc_debugfs_fini(struct cc_drvdata *drvdata) {}
+
+#endif
+
+#endif /*__CC_SYSFS_H__*/
diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c
new file mode 100644
index 000000000000..827e32923c60
--- /dev/null
+++ b/drivers/crypto/ccree/cc_driver.c
@@ -0,0 +1,476 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/crypto.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/of_address.h>
+
+#include "cc_driver.h"
+#include "cc_request_mgr.h"
+#include "cc_buffer_mgr.h"
+#include "cc_debugfs.h"
+#include "cc_cipher.h"
+#include "cc_aead.h"
+#include "cc_hash.h"
+#include "cc_ivgen.h"
+#include "cc_sram_mgr.h"
+#include "cc_pm.h"
+#include "cc_fips.h"
+
+bool cc_dump_desc;
+module_param_named(dump_desc, cc_dump_desc, bool, 0600);
+MODULE_PARM_DESC(cc_dump_desc, "Dump descriptors to kernel log as debugging aid");
+
+bool cc_dump_bytes;
+module_param_named(dump_bytes, cc_dump_bytes, bool, 0600);
+MODULE_PARM_DESC(cc_dump_bytes, "Dump buffers to kernel log as debugging aid");
+
+void __dump_byte_array(const char *name, const u8 *buf, size_t len)
+{
+	char prefix[64];
+
+	if (!buf)
+		return;
+
+	snprintf(prefix, sizeof(prefix), "%s[%zu]: ", name, len);
+
+	print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_ADDRESS, 16, 1, buf,
+		       len, false);
+}
+
+static irqreturn_t cc_isr(int irq, void *dev_id)
+{
+	struct cc_drvdata *drvdata = (struct cc_drvdata *)dev_id;
+	struct device *dev = drvdata_to_dev(drvdata);
+	u32 irr;
+	u32 imr;
+
+	/* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */
+
+	/* read the interrupt status */
+	irr = cc_ioread(drvdata, CC_REG(HOST_IRR));
+	dev_dbg(dev, "Got IRR=0x%08X\n", irr);
+	if (irr == 0) { /* Probably shared interrupt line */
+		dev_err(dev, "Got interrupt with empty IRR\n");
+		return IRQ_NONE;
+	}
+	imr = cc_ioread(drvdata, CC_REG(HOST_IMR));
+
+	/* clear interrupt - must be before processing events */
+	cc_iowrite(drvdata, CC_REG(HOST_ICR), irr);
+
+	drvdata->irq = irr;
+	/* Completion interrupt - most probable */
+	if (irr & CC_COMP_IRQ_MASK) {
+		/* Mask AXI completion interrupt - will be unmasked in
+		 * Deferred service handler
+		 */
+		cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | CC_COMP_IRQ_MASK);
+		irr &= ~CC_COMP_IRQ_MASK;
+		complete_request(drvdata);
+	}
+#ifdef CONFIG_CRYPTO_FIPS
+	/* TEE FIPS interrupt */
+	if (irr & CC_GPR0_IRQ_MASK) {
+		/* Mask interrupt - will be unmasked in Deferred service
+		 * handler
+		 */
+		cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | CC_GPR0_IRQ_MASK);
+		irr &= ~CC_GPR0_IRQ_MASK;
+		fips_handler(drvdata);
+	}
+#endif
+	/* AXI error interrupt */
+	if (irr & CC_AXI_ERR_IRQ_MASK) {
+		u32 axi_err;
+
+		/* Read the AXI error ID */
+		axi_err = cc_ioread(drvdata, CC_REG(AXIM_MON_ERR));
+		dev_dbg(dev, "AXI completion error: axim_mon_err=0x%08X\n",
+			axi_err);
+
+		irr &= ~CC_AXI_ERR_IRQ_MASK;
+	}
+
+	if (irr) {
+		dev_dbg(dev, "IRR includes unknown cause bits (0x%08X)\n",
+			irr);
+		/* Just warning */
+	}
+
+	return IRQ_HANDLED;
+}
+
+int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe)
+{
+	unsigned int val, cache_params;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	/* Unmask all AXI interrupt sources AXI_CFG1 register */
+	val = cc_ioread(drvdata, CC_REG(AXIM_CFG));
+	cc_iowrite(drvdata, CC_REG(AXIM_CFG), val & ~CC_AXI_IRQ_MASK);
+	dev_dbg(dev, "AXIM_CFG=0x%08X\n",
+		cc_ioread(drvdata, CC_REG(AXIM_CFG)));
+
+	/* Clear all pending interrupts */
+	val = cc_ioread(drvdata, CC_REG(HOST_IRR));
+	dev_dbg(dev, "IRR=0x%08X\n", val);
+	cc_iowrite(drvdata, CC_REG(HOST_ICR), val);
+
+	/* Unmask relevant interrupt cause */
+	val = (unsigned int)(~(CC_COMP_IRQ_MASK | CC_AXI_ERR_IRQ_MASK |
+			       CC_GPR0_IRQ_MASK));
+	cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
+
+	cache_params = (drvdata->coherent ? CC_COHERENT_CACHE_PARAMS : 0x0);
+
+	val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS));
+
+	if (is_probe)
+		dev_info(dev, "Cache params previous: 0x%08X\n", val);
+
+	cc_iowrite(drvdata, CC_REG(AXIM_CACHE_PARAMS), cache_params);
+	val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS));
+
+	if (is_probe)
+		dev_info(dev, "Cache params current: 0x%08X (expect: 0x%08X)\n",
+			 val, cache_params);
+
+	return 0;
+}
+
+static int init_cc_resources(struct platform_device *plat_dev)
+{
+	struct resource *req_mem_cc_regs = NULL;
+	struct cc_drvdata *new_drvdata;
+	struct device *dev = &plat_dev->dev;
+	struct device_node *np = dev->of_node;
+	u32 signature_val;
+	u64 dma_mask;
+	int rc = 0;
+
+	new_drvdata = devm_kzalloc(dev, sizeof(*new_drvdata), GFP_KERNEL);
+	if (!new_drvdata)
+		return -ENOMEM;
+
+	platform_set_drvdata(plat_dev, new_drvdata);
+	new_drvdata->plat_dev = plat_dev;
+
+	new_drvdata->clk = of_clk_get(np, 0);
+	new_drvdata->coherent = of_dma_is_coherent(np);
+
+	/* Get device resources */
+	/* First CC registers space */
+	req_mem_cc_regs = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
+	/* Map registers space */
+	new_drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs);
+	if (IS_ERR(new_drvdata->cc_base)) {
+		dev_err(dev, "Failed to ioremap registers");
+		return PTR_ERR(new_drvdata->cc_base);
+	}
+
+	dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name,
+		req_mem_cc_regs);
+	dev_dbg(dev, "CC registers mapped from %pa to 0x%p\n",
+		&req_mem_cc_regs->start, new_drvdata->cc_base);
+
+	/* Then IRQ */
+	new_drvdata->irq = platform_get_irq(plat_dev, 0);
+	if (new_drvdata->irq < 0) {
+		dev_err(dev, "Failed getting IRQ resource\n");
+		return new_drvdata->irq;
+	}
+
+	rc = devm_request_irq(dev, new_drvdata->irq, cc_isr,
+			      IRQF_SHARED, "ccree", new_drvdata);
+	if (rc) {
+		dev_err(dev, "Could not register to interrupt %d\n",
+			new_drvdata->irq);
+		return rc;
+	}
+	dev_dbg(dev, "Registered to IRQ: %d\n", new_drvdata->irq);
+
+	init_completion(&new_drvdata->hw_queue_avail);
+
+	if (!plat_dev->dev.dma_mask)
+		plat_dev->dev.dma_mask = &plat_dev->dev.coherent_dma_mask;
+
+	dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN);
+	while (dma_mask > 0x7fffffffUL) {
+		if (dma_supported(&plat_dev->dev, dma_mask)) {
+			rc = dma_set_coherent_mask(&plat_dev->dev, dma_mask);
+			if (!rc)
+				break;
+		}
+		dma_mask >>= 1;
+	}
+
+	if (rc) {
+		dev_err(dev, "Failed in dma_set_mask, mask=%pad\n", &dma_mask);
+		return rc;
+	}
+
+	rc = cc_clk_on(new_drvdata);
+	if (rc) {
+		dev_err(dev, "Failed to enable clock");
+		return rc;
+	}
+
+	/* Verify correct mapping */
+	signature_val = cc_ioread(new_drvdata, CC_REG(HOST_SIGNATURE));
+	if (signature_val != CC_DEV_SIGNATURE) {
+		dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n",
+			signature_val, (u32)CC_DEV_SIGNATURE);
+		rc = -EINVAL;
+		goto post_clk_err;
+	}
+	dev_dbg(dev, "CC SIGNATURE=0x%08X\n", signature_val);
+
+	/* Display HW versions */
+	dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X, Driver version %s\n",
+		 CC_DEV_NAME_STR,
+		 cc_ioread(new_drvdata, CC_REG(HOST_VERSION)),
+		 DRV_MODULE_VERSION);
+
+	rc = init_cc_regs(new_drvdata, true);
+	if (rc) {
+		dev_err(dev, "init_cc_regs failed\n");
+		goto post_clk_err;
+	}
+
+	rc = cc_debugfs_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "Failed registering debugfs interface\n");
+		goto post_regs_err;
+	}
+
+	rc = cc_fips_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "CC_FIPS_INIT failed 0x%x\n", rc);
+		goto post_debugfs_err;
+	}
+	rc = cc_sram_mgr_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "cc_sram_mgr_init failed\n");
+		goto post_fips_init_err;
+	}
+
+	new_drvdata->mlli_sram_addr =
+		cc_sram_alloc(new_drvdata, MAX_MLLI_BUFF_SIZE);
+	if (new_drvdata->mlli_sram_addr == NULL_SRAM_ADDR) {
+		dev_err(dev, "Failed to alloc MLLI Sram buffer\n");
+		rc = -ENOMEM;
+		goto post_sram_mgr_err;
+	}
+
+	rc = cc_req_mgr_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "cc_req_mgr_init failed\n");
+		goto post_sram_mgr_err;
+	}
+
+	rc = cc_buffer_mgr_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "buffer_mgr_init failed\n");
+		goto post_req_mgr_err;
+	}
+
+	rc = cc_pm_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "ssi_power_mgr_init failed\n");
+		goto post_buf_mgr_err;
+	}
+
+	rc = cc_ivgen_init(new_drvdata);
+	if (rc) {
+		dev_err(dev, "cc_ivgen_init failed\n");
+		goto post_power_mgr_err;
+	}
+
+	/* Allocate crypto algs */
+	rc = cc_cipher_alloc(new_drvdata);
+	if (rc) {
+		dev_err(dev, "cc_cipher_alloc failed\n");
+		goto post_ivgen_err;
+	}
+
+	/* hash must be allocated before aead since hash exports APIs */
+	rc = cc_hash_alloc(new_drvdata);
+	if (rc) {
+		dev_err(dev, "cc_hash_alloc failed\n");
+		goto post_cipher_err;
+	}
+
+	rc = cc_aead_alloc(new_drvdata);
+	if (rc) {
+		dev_err(dev, "cc_aead_alloc failed\n");
+		goto post_hash_err;
+	}
+
+	/* If we got here and FIPS mode is enabled
+	 * it means all FIPS test passed, so let TEE
+	 * know we're good.
+	 */
+	cc_set_ree_fips_status(new_drvdata, true);
+
+	return 0;
+
+post_hash_err:
+	cc_hash_free(new_drvdata);
+post_cipher_err:
+	cc_cipher_free(new_drvdata);
+post_ivgen_err:
+	cc_ivgen_fini(new_drvdata);
+post_power_mgr_err:
+	cc_pm_fini(new_drvdata);
+post_buf_mgr_err:
+	 cc_buffer_mgr_fini(new_drvdata);
+post_req_mgr_err:
+	cc_req_mgr_fini(new_drvdata);
+post_sram_mgr_err:
+	cc_sram_mgr_fini(new_drvdata);
+post_fips_init_err:
+	cc_fips_fini(new_drvdata);
+post_debugfs_err:
+	cc_debugfs_fini(new_drvdata);
+post_regs_err:
+	fini_cc_regs(new_drvdata);
+post_clk_err:
+	cc_clk_off(new_drvdata);
+	return rc;
+}
+
+void fini_cc_regs(struct cc_drvdata *drvdata)
+{
+	/* Mask all interrupts */
+	cc_iowrite(drvdata, CC_REG(HOST_IMR), 0xFFFFFFFF);
+}
+
+static void cleanup_cc_resources(struct platform_device *plat_dev)
+{
+	struct cc_drvdata *drvdata =
+		(struct cc_drvdata *)platform_get_drvdata(plat_dev);
+
+	cc_aead_free(drvdata);
+	cc_hash_free(drvdata);
+	cc_cipher_free(drvdata);
+	cc_ivgen_fini(drvdata);
+	cc_pm_fini(drvdata);
+	cc_buffer_mgr_fini(drvdata);
+	cc_req_mgr_fini(drvdata);
+	cc_sram_mgr_fini(drvdata);
+	cc_fips_fini(drvdata);
+	cc_debugfs_fini(drvdata);
+	fini_cc_regs(drvdata);
+	cc_clk_off(drvdata);
+}
+
+int cc_clk_on(struct cc_drvdata *drvdata)
+{
+	struct clk *clk = drvdata->clk;
+	int rc;
+
+	if (IS_ERR(clk))
+		/* Not all devices have a clock associated with CCREE  */
+		return 0;
+
+	rc = clk_prepare_enable(clk);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+void cc_clk_off(struct cc_drvdata *drvdata)
+{
+	struct clk *clk = drvdata->clk;
+
+	if (IS_ERR(clk))
+		/* Not all devices have a clock associated with CCREE */
+		return;
+
+	clk_disable_unprepare(clk);
+}
+
+static int ccree_probe(struct platform_device *plat_dev)
+{
+	int rc;
+	struct device *dev = &plat_dev->dev;
+
+	/* Map registers space */
+	rc = init_cc_resources(plat_dev);
+	if (rc)
+		return rc;
+
+	dev_info(dev, "ARM ccree device initialized\n");
+
+	return 0;
+}
+
+static int ccree_remove(struct platform_device *plat_dev)
+{
+	struct device *dev = &plat_dev->dev;
+
+	dev_dbg(dev, "Releasing ccree resources...\n");
+
+	cleanup_cc_resources(plat_dev);
+
+	dev_info(dev, "ARM ccree device terminated\n");
+
+	return 0;
+}
+
+static const struct of_device_id arm_ccree_dev_of_match[] = {
+	{.compatible = "arm,cryptocell-712-ree"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, arm_ccree_dev_of_match);
+
+static struct platform_driver ccree_driver = {
+	.driver = {
+		   .name = "ccree",
+		   .of_match_table = arm_ccree_dev_of_match,
+#ifdef CONFIG_PM
+		   .pm = &ccree_pm,
+#endif
+	},
+	.probe = ccree_probe,
+	.remove = ccree_remove,
+};
+
+static int __init ccree_init(void)
+{
+	int ret;
+
+	cc_hash_global_init();
+
+	ret = cc_debugfs_global_init();
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&ccree_driver);
+}
+module_init(ccree_init);
+
+static void __exit ccree_exit(void)
+{
+	platform_driver_unregister(&ccree_driver);
+	cc_debugfs_global_fini();
+}
+module_exit(ccree_exit);
+
+/* Module description */
+MODULE_DESCRIPTION("ARM TrustZone CryptoCell REE Driver");
+MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_AUTHOR("ARM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/ccree/cc_driver.h b/drivers/crypto/ccree/cc_driver.h
new file mode 100644
index 000000000000..254a3cb50274
--- /dev/null
+++ b/drivers/crypto/ccree/cc_driver.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_driver.h
+ * ARM CryptoCell Linux Crypto Driver
+ */
+
+#ifndef __CC_DRIVER_H__
+#define __CC_DRIVER_H__
+
+#ifdef COMP_IN_WQ
+#include <linux/workqueue.h>
+#else
+#include <linux/interrupt.h>
+#endif
+#include <linux/dma-mapping.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
+#include <linux/version.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/* Registers definitions from shared/hw/ree_include */
+#include "cc_host_regs.h"
+#define CC_DEV_SHA_MAX 512
+#include "cc_crypto_ctx.h"
+#include "cc_hw_queue_defs.h"
+#include "cc_sram_mgr.h"
+
+extern bool cc_dump_desc;
+extern bool cc_dump_bytes;
+
+#define DRV_MODULE_VERSION "3.0"
+
+#define CC_DEV_NAME_STR "ccree"
+#define CC_COHERENT_CACHE_PARAMS 0xEEE
+
+/* Maximum DMA mask supported by IP */
+#define DMA_BIT_MASK_LEN 48
+
+#define CC_DEV_SIGNATURE 0xDCC71200UL
+
+#define CC_AXI_IRQ_MASK ((1 << CC_AXIM_CFG_BRESPMASK_BIT_SHIFT) | \
+			  (1 << CC_AXIM_CFG_RRESPMASK_BIT_SHIFT) | \
+			  (1 << CC_AXIM_CFG_INFLTMASK_BIT_SHIFT) | \
+			  (1 << CC_AXIM_CFG_COMPMASK_BIT_SHIFT))
+
+#define CC_AXI_ERR_IRQ_MASK BIT(CC_HOST_IRR_AXI_ERR_INT_BIT_SHIFT)
+
+#define CC_COMP_IRQ_MASK BIT(CC_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT)
+
+#define AXIM_MON_COMP_VALUE GENMASK(CC_AXIM_MON_COMP_VALUE_BIT_SIZE + \
+				    CC_AXIM_MON_COMP_VALUE_BIT_SHIFT, \
+				    CC_AXIM_MON_COMP_VALUE_BIT_SHIFT)
+
+/* Register name mangling macro */
+#define CC_REG(reg_name) CC_ ## reg_name ## _REG_OFFSET
+
+/* TEE FIPS status interrupt */
+#define CC_GPR0_IRQ_MASK BIT(CC_HOST_IRR_GPR0_BIT_SHIFT)
+
+#define CC_CRA_PRIO 400
+
+#define MIN_HW_QUEUE_SIZE 50 /* Minimum size required for proper function */
+
+#define MAX_REQUEST_QUEUE_SIZE 4096
+#define MAX_MLLI_BUFF_SIZE 2080
+#define MAX_ICV_NENTS_SUPPORTED 2
+
+/* Definitions for HW descriptors DIN/DOUT fields */
+#define NS_BIT 1
+#define AXI_ID 0
+/* AXI_ID is not actually the AXI ID of the transaction but the value of AXI_ID
+ * field in the HW descriptor. The DMA engine +8 that value.
+ */
+
+#define CC_MAX_IVGEN_DMA_ADDRESSES	3
+struct cc_crypto_req {
+	void (*user_cb)(struct device *dev, void *req, int err);
+	void *user_arg;
+	dma_addr_t ivgen_dma_addr[CC_MAX_IVGEN_DMA_ADDRESSES];
+	/* For the first 'ivgen_dma_addr_len' addresses of this array,
+	 * generated IV would be placed in it by send_request().
+	 * Same generated IV for all addresses!
+	 */
+	/* Amount of 'ivgen_dma_addr' elements to be filled. */
+	unsigned int ivgen_dma_addr_len;
+	/* The generated IV size required, 8/16 B allowed. */
+	unsigned int ivgen_size;
+	struct completion seq_compl; /* request completion */
+};
+
+/**
+ * struct cc_drvdata - driver private data context
+ * @cc_base:	virt address of the CC registers
+ * @irq:	device IRQ number
+ * @irq_mask:	Interrupt mask shadow (1 for masked interrupts)
+ * @fw_ver:	SeP loaded firmware version
+ */
+struct cc_drvdata {
+	void __iomem *cc_base;
+	int irq;
+	u32 irq_mask;
+	u32 fw_ver;
+	struct completion hw_queue_avail; /* wait for HW queue availability */
+	struct platform_device *plat_dev;
+	cc_sram_addr_t mlli_sram_addr;
+	void *buff_mgr_handle;
+	void *cipher_handle;
+	void *hash_handle;
+	void *aead_handle;
+	void *request_mgr_handle;
+	void *fips_handle;
+	void *ivgen_handle;
+	void *sram_mgr_handle;
+	void *debugfs;
+	struct clk *clk;
+	bool coherent;
+};
+
+struct cc_crypto_alg {
+	struct list_head entry;
+	int cipher_mode;
+	int flow_mode; /* Note: currently, refers to the cipher mode only. */
+	int auth_mode;
+	unsigned int data_unit;
+	struct cc_drvdata *drvdata;
+	struct skcipher_alg skcipher_alg;
+	struct aead_alg aead_alg;
+};
+
+struct cc_alg_template {
+	char name[CRYPTO_MAX_ALG_NAME];
+	char driver_name[CRYPTO_MAX_ALG_NAME];
+	unsigned int blocksize;
+	u32 type;
+	union {
+		struct skcipher_alg skcipher;
+		struct aead_alg aead;
+	} template_u;
+	int cipher_mode;
+	int flow_mode; /* Note: currently, refers to the cipher mode only. */
+	int auth_mode;
+	unsigned int data_unit;
+	struct cc_drvdata *drvdata;
+};
+
+struct async_gen_req_ctx {
+	dma_addr_t iv_dma_addr;
+	enum drv_crypto_direction op_type;
+};
+
+static inline struct device *drvdata_to_dev(struct cc_drvdata *drvdata)
+{
+	return &drvdata->plat_dev->dev;
+}
+
+void __dump_byte_array(const char *name, const u8 *buf, size_t len);
+static inline void dump_byte_array(const char *name, const u8 *the_array,
+				   size_t size)
+{
+	if (cc_dump_bytes)
+		__dump_byte_array(name, the_array, size);
+}
+
+int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe);
+void fini_cc_regs(struct cc_drvdata *drvdata);
+int cc_clk_on(struct cc_drvdata *drvdata);
+void cc_clk_off(struct cc_drvdata *drvdata);
+
+static inline void cc_iowrite(struct cc_drvdata *drvdata, u32 reg, u32 val)
+{
+	iowrite32(val, (drvdata->cc_base + reg));
+}
+
+static inline u32 cc_ioread(struct cc_drvdata *drvdata, u32 reg)
+{
+	return ioread32(drvdata->cc_base + reg);
+}
+
+static inline gfp_t cc_gfp_flags(struct crypto_async_request *req)
+{
+	return (req->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+			GFP_KERNEL : GFP_ATOMIC;
+}
+
+#endif /*__CC_DRIVER_H__*/
diff --git a/drivers/crypto/ccree/cc_fips.c b/drivers/crypto/ccree/cc_fips.c
new file mode 100644
index 000000000000..de08af976b7f
--- /dev/null
+++ b/drivers/crypto/ccree/cc_fips.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/fips.h>
+
+#include "cc_driver.h"
+#include "cc_fips.h"
+
+static void fips_dsr(unsigned long devarg);
+
+struct cc_fips_handle {
+	struct tasklet_struct tasklet;
+};
+
+/* The function called once at driver entry point to check
+ * whether TEE FIPS error occurred.
+ */
+static bool cc_get_tee_fips_status(struct cc_drvdata *drvdata)
+{
+	u32 reg;
+
+	reg = cc_ioread(drvdata, CC_REG(GPR_HOST));
+	return (reg == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK));
+}
+
+/*
+ * This function should push the FIPS REE library status towards the TEE library
+ * by writing the error state to HOST_GPR0 register.
+ */
+void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status)
+{
+	int val = CC_FIPS_SYNC_REE_STATUS;
+
+	val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR);
+
+	cc_iowrite(drvdata, CC_REG(HOST_GPR0), val);
+}
+
+void cc_fips_fini(struct cc_drvdata *drvdata)
+{
+	struct cc_fips_handle *fips_h = drvdata->fips_handle;
+
+	if (!fips_h)
+		return; /* Not allocated */
+
+	/* Kill tasklet */
+	tasklet_kill(&fips_h->tasklet);
+
+	kfree(fips_h);
+	drvdata->fips_handle = NULL;
+}
+
+void fips_handler(struct cc_drvdata *drvdata)
+{
+	struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle;
+
+	tasklet_schedule(&fips_handle_ptr->tasklet);
+}
+
+static inline void tee_fips_error(struct device *dev)
+{
+	if (fips_enabled)
+		panic("ccree: TEE reported cryptographic error in fips mode!\n");
+	else
+		dev_err(dev, "TEE reported error!\n");
+}
+
+/* Deferred service handler, run as interrupt-fired tasklet */
+static void fips_dsr(unsigned long devarg)
+{
+	struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg;
+	struct device *dev = drvdata_to_dev(drvdata);
+	u32 irq, state, val;
+
+	irq = (drvdata->irq & (CC_GPR0_IRQ_MASK));
+
+	if (irq) {
+		state = cc_ioread(drvdata, CC_REG(GPR_HOST));
+
+		if (state != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK))
+			tee_fips_error(dev);
+	}
+
+	/* after verifing that there is nothing to do,
+	 * unmask AXI completion interrupt.
+	 */
+	val = (CC_REG(HOST_IMR) & ~irq);
+	cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
+}
+
+/* The function called once at driver entry point .*/
+int cc_fips_init(struct cc_drvdata *p_drvdata)
+{
+	struct cc_fips_handle *fips_h;
+	struct device *dev = drvdata_to_dev(p_drvdata);
+
+	fips_h = kzalloc(sizeof(*fips_h), GFP_KERNEL);
+	if (!fips_h)
+		return -ENOMEM;
+
+	p_drvdata->fips_handle = fips_h;
+
+	dev_dbg(dev, "Initializing fips tasklet\n");
+	tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata);
+
+	if (!cc_get_tee_fips_status(p_drvdata))
+		tee_fips_error(dev);
+
+	return 0;
+}
diff --git a/drivers/crypto/ccree/cc_fips.h b/drivers/crypto/ccree/cc_fips.h
new file mode 100644
index 000000000000..645e096a7a82
--- /dev/null
+++ b/drivers/crypto/ccree/cc_fips.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_FIPS_H__
+#define __CC_FIPS_H__
+
+#ifdef CONFIG_CRYPTO_FIPS
+
+enum cc_fips_status {
+	CC_FIPS_SYNC_MODULE_OK = 0x0,
+	CC_FIPS_SYNC_MODULE_ERROR = 0x1,
+	CC_FIPS_SYNC_REE_STATUS = 0x4,
+	CC_FIPS_SYNC_TEE_STATUS = 0x8,
+	CC_FIPS_SYNC_STATUS_RESERVE32B = S32_MAX
+};
+
+int cc_fips_init(struct cc_drvdata *p_drvdata);
+void cc_fips_fini(struct cc_drvdata *drvdata);
+void fips_handler(struct cc_drvdata *drvdata);
+void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool ok);
+
+#else  /* CONFIG_CRYPTO_FIPS */
+
+static inline int cc_fips_init(struct cc_drvdata *p_drvdata)
+{
+	return 0;
+}
+
+static inline void cc_fips_fini(struct cc_drvdata *drvdata) {}
+static inline void cc_set_ree_fips_status(struct cc_drvdata *drvdata,
+					  bool ok) {}
+static inline void fips_handler(struct cc_drvdata *drvdata) {}
+
+#endif /* CONFIG_CRYPTO_FIPS */
+
+#endif  /*__CC_FIPS_H__*/
diff --git a/drivers/crypto/ccree/cc_hash.c b/drivers/crypto/ccree/cc_hash.c
new file mode 100644
index 000000000000..26bbbc6a4019
--- /dev/null
+++ b/drivers/crypto/ccree/cc_hash.c
@@ -0,0 +1,2295 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/internal/hash.h>
+
+#include "cc_driver.h"
+#include "cc_request_mgr.h"
+#include "cc_buffer_mgr.h"
+#include "cc_hash.h"
+#include "cc_sram_mgr.h"
+
+#define CC_MAX_HASH_SEQ_LEN 12
+#define CC_MAX_OPAD_KEYS_SIZE CC_MAX_HASH_BLCK_SIZE
+
+struct cc_hash_handle {
+	cc_sram_addr_t digest_len_sram_addr; /* const value in SRAM*/
+	cc_sram_addr_t larval_digest_sram_addr;   /* const value in SRAM */
+	struct list_head hash_list;
+};
+
+static const u32 digest_len_init[] = {
+	0x00000040, 0x00000000, 0x00000000, 0x00000000 };
+static const u32 md5_init[] = {
+	SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 };
+static const u32 sha1_init[] = {
+	SHA1_H4, SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 };
+static const u32 sha224_init[] = {
+	SHA224_H7, SHA224_H6, SHA224_H5, SHA224_H4,
+	SHA224_H3, SHA224_H2, SHA224_H1, SHA224_H0 };
+static const u32 sha256_init[] = {
+	SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4,
+	SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 };
+#if (CC_DEV_SHA_MAX > 256)
+static const u32 digest_len_sha512_init[] = {
+	0x00000080, 0x00000000, 0x00000000, 0x00000000 };
+static u64 sha384_init[] = {
+	SHA384_H7, SHA384_H6, SHA384_H5, SHA384_H4,
+	SHA384_H3, SHA384_H2, SHA384_H1, SHA384_H0 };
+static u64 sha512_init[] = {
+	SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4,
+	SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 };
+#endif
+
+static void cc_setup_xcbc(struct ahash_request *areq, struct cc_hw_desc desc[],
+			  unsigned int *seq_size);
+
+static void cc_setup_cmac(struct ahash_request *areq, struct cc_hw_desc desc[],
+			  unsigned int *seq_size);
+
+static const void *cc_larval_digest(struct device *dev, u32 mode);
+
+struct cc_hash_alg {
+	struct list_head entry;
+	int hash_mode;
+	int hw_mode;
+	int inter_digestsize;
+	struct cc_drvdata *drvdata;
+	struct ahash_alg ahash_alg;
+};
+
+struct hash_key_req_ctx {
+	u32 keylen;
+	dma_addr_t key_dma_addr;
+};
+
+/* hash per-session context */
+struct cc_hash_ctx {
+	struct cc_drvdata *drvdata;
+	/* holds the origin digest; the digest after "setkey" if HMAC,*
+	 * the initial digest if HASH.
+	 */
+	u8 digest_buff[CC_MAX_HASH_DIGEST_SIZE]  ____cacheline_aligned;
+	u8 opad_tmp_keys_buff[CC_MAX_OPAD_KEYS_SIZE]  ____cacheline_aligned;
+
+	dma_addr_t opad_tmp_keys_dma_addr  ____cacheline_aligned;
+	dma_addr_t digest_buff_dma_addr;
+	/* use for hmac with key large then mode block size */
+	struct hash_key_req_ctx key_params;
+	int hash_mode;
+	int hw_mode;
+	int inter_digestsize;
+	struct completion setkey_comp;
+	bool is_hmac;
+};
+
+static void cc_set_desc(struct ahash_req_ctx *areq_ctx, struct cc_hash_ctx *ctx,
+			unsigned int flow_mode, struct cc_hw_desc desc[],
+			bool is_not_last_data, unsigned int *seq_size);
+
+static void cc_set_endianity(u32 mode, struct cc_hw_desc *desc)
+{
+	if (mode == DRV_HASH_MD5 || mode == DRV_HASH_SHA384 ||
+	    mode == DRV_HASH_SHA512) {
+		set_bytes_swap(desc, 1);
+	} else {
+		set_cipher_config0(desc, HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+	}
+}
+
+static int cc_map_result(struct device *dev, struct ahash_req_ctx *state,
+			 unsigned int digestsize)
+{
+	state->digest_result_dma_addr =
+		dma_map_single(dev, state->digest_result_buff,
+			       digestsize, DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, state->digest_result_dma_addr)) {
+		dev_err(dev, "Mapping digest result buffer %u B for DMA failed\n",
+			digestsize);
+		return -ENOMEM;
+	}
+	dev_dbg(dev, "Mapped digest result buffer %u B at va=%pK to dma=%pad\n",
+		digestsize, state->digest_result_buff,
+		&state->digest_result_dma_addr);
+
+	return 0;
+}
+
+static void cc_init_req(struct device *dev, struct ahash_req_ctx *state,
+			struct cc_hash_ctx *ctx)
+{
+	bool is_hmac = ctx->is_hmac;
+
+	memset(state, 0, sizeof(*state));
+
+	if (is_hmac) {
+		if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC &&
+		    ctx->hw_mode != DRV_CIPHER_CMAC) {
+			dma_sync_single_for_cpu(dev, ctx->digest_buff_dma_addr,
+						ctx->inter_digestsize,
+						DMA_BIDIRECTIONAL);
+
+			memcpy(state->digest_buff, ctx->digest_buff,
+			       ctx->inter_digestsize);
+#if (CC_DEV_SHA_MAX > 256)
+			if (ctx->hash_mode == DRV_HASH_SHA512 ||
+			    ctx->hash_mode == DRV_HASH_SHA384)
+				memcpy(state->digest_bytes_len,
+				       digest_len_sha512_init, HASH_LEN_SIZE);
+			else
+				memcpy(state->digest_bytes_len,
+				       digest_len_init, HASH_LEN_SIZE);
+#else
+			memcpy(state->digest_bytes_len, digest_len_init,
+			       HASH_LEN_SIZE);
+#endif
+		}
+
+		if (ctx->hash_mode != DRV_HASH_NULL) {
+			dma_sync_single_for_cpu(dev,
+						ctx->opad_tmp_keys_dma_addr,
+						ctx->inter_digestsize,
+						DMA_BIDIRECTIONAL);
+			memcpy(state->opad_digest_buff,
+			       ctx->opad_tmp_keys_buff, ctx->inter_digestsize);
+		}
+	} else { /*hash*/
+		/* Copy the initial digests if hash flow. */
+		const void *larval = cc_larval_digest(dev, ctx->hash_mode);
+
+		memcpy(state->digest_buff, larval, ctx->inter_digestsize);
+	}
+}
+
+static int cc_map_req(struct device *dev, struct ahash_req_ctx *state,
+		      struct cc_hash_ctx *ctx)
+{
+	bool is_hmac = ctx->is_hmac;
+
+	state->digest_buff_dma_addr =
+		dma_map_single(dev, state->digest_buff,
+			       ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, state->digest_buff_dma_addr)) {
+		dev_err(dev, "Mapping digest len %d B at va=%pK for DMA failed\n",
+			ctx->inter_digestsize, state->digest_buff);
+		return -EINVAL;
+	}
+	dev_dbg(dev, "Mapped digest %d B at va=%pK to dma=%pad\n",
+		ctx->inter_digestsize, state->digest_buff,
+		&state->digest_buff_dma_addr);
+
+	if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC) {
+		state->digest_bytes_len_dma_addr =
+			dma_map_single(dev, state->digest_bytes_len,
+				       HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(dev, state->digest_bytes_len_dma_addr)) {
+			dev_err(dev, "Mapping digest len %u B at va=%pK for DMA failed\n",
+				HASH_LEN_SIZE, state->digest_bytes_len);
+			goto unmap_digest_buf;
+		}
+		dev_dbg(dev, "Mapped digest len %u B at va=%pK to dma=%pad\n",
+			HASH_LEN_SIZE, state->digest_bytes_len,
+			&state->digest_bytes_len_dma_addr);
+	}
+
+	if (is_hmac && ctx->hash_mode != DRV_HASH_NULL) {
+		state->opad_digest_dma_addr =
+			dma_map_single(dev, state->opad_digest_buff,
+				       ctx->inter_digestsize,
+				       DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(dev, state->opad_digest_dma_addr)) {
+			dev_err(dev, "Mapping opad digest %d B at va=%pK for DMA failed\n",
+				ctx->inter_digestsize,
+				state->opad_digest_buff);
+			goto unmap_digest_len;
+		}
+		dev_dbg(dev, "Mapped opad digest %d B at va=%pK to dma=%pad\n",
+			ctx->inter_digestsize, state->opad_digest_buff,
+			&state->opad_digest_dma_addr);
+	}
+
+	return 0;
+
+unmap_digest_len:
+	if (state->digest_bytes_len_dma_addr) {
+		dma_unmap_single(dev, state->digest_bytes_len_dma_addr,
+				 HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+		state->digest_bytes_len_dma_addr = 0;
+	}
+unmap_digest_buf:
+	if (state->digest_buff_dma_addr) {
+		dma_unmap_single(dev, state->digest_buff_dma_addr,
+				 ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+		state->digest_buff_dma_addr = 0;
+	}
+
+	return -EINVAL;
+}
+
+static void cc_unmap_req(struct device *dev, struct ahash_req_ctx *state,
+			 struct cc_hash_ctx *ctx)
+{
+	if (state->digest_buff_dma_addr) {
+		dma_unmap_single(dev, state->digest_buff_dma_addr,
+				 ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "Unmapped digest-buffer: digest_buff_dma_addr=%pad\n",
+			&state->digest_buff_dma_addr);
+		state->digest_buff_dma_addr = 0;
+	}
+	if (state->digest_bytes_len_dma_addr) {
+		dma_unmap_single(dev, state->digest_bytes_len_dma_addr,
+				 HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "Unmapped digest-bytes-len buffer: digest_bytes_len_dma_addr=%pad\n",
+			&state->digest_bytes_len_dma_addr);
+		state->digest_bytes_len_dma_addr = 0;
+	}
+	if (state->opad_digest_dma_addr) {
+		dma_unmap_single(dev, state->opad_digest_dma_addr,
+				 ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "Unmapped opad-digest: opad_digest_dma_addr=%pad\n",
+			&state->opad_digest_dma_addr);
+		state->opad_digest_dma_addr = 0;
+	}
+}
+
+static void cc_unmap_result(struct device *dev, struct ahash_req_ctx *state,
+			    unsigned int digestsize, u8 *result)
+{
+	if (state->digest_result_dma_addr) {
+		dma_unmap_single(dev, state->digest_result_dma_addr, digestsize,
+				 DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "unmpa digest result buffer va (%pK) pa (%pad) len %u\n",
+			state->digest_result_buff,
+			&state->digest_result_dma_addr, digestsize);
+		memcpy(result, state->digest_result_buff, digestsize);
+	}
+	state->digest_result_dma_addr = 0;
+}
+
+static void cc_update_complete(struct device *dev, void *cc_req, int err)
+{
+	struct ahash_request *req = (struct ahash_request *)cc_req;
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	dev_dbg(dev, "req=%pK\n", req);
+
+	cc_unmap_hash_request(dev, state, req->src, false);
+	cc_unmap_req(dev, state, ctx);
+	req->base.complete(&req->base, err);
+}
+
+static void cc_digest_complete(struct device *dev, void *cc_req, int err)
+{
+	struct ahash_request *req = (struct ahash_request *)cc_req;
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+
+	dev_dbg(dev, "req=%pK\n", req);
+
+	cc_unmap_hash_request(dev, state, req->src, false);
+	cc_unmap_result(dev, state, digestsize, req->result);
+	cc_unmap_req(dev, state, ctx);
+	req->base.complete(&req->base, err);
+}
+
+static void cc_hash_complete(struct device *dev, void *cc_req, int err)
+{
+	struct ahash_request *req = (struct ahash_request *)cc_req;
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+
+	dev_dbg(dev, "req=%pK\n", req);
+
+	cc_unmap_hash_request(dev, state, req->src, false);
+	cc_unmap_result(dev, state, digestsize, req->result);
+	cc_unmap_req(dev, state, ctx);
+	req->base.complete(&req->base, err);
+}
+
+static int cc_fin_result(struct cc_hw_desc *desc, struct ahash_request *req,
+			 int idx)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+
+	/* Get final MAC result */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	/* TODO */
+	set_dout_dlli(&desc[idx], state->digest_result_dma_addr, digestsize,
+		      NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
+	cc_set_endianity(ctx->hash_mode, &desc[idx]);
+	idx++;
+
+	return idx;
+}
+
+static int cc_fin_hmac(struct cc_hw_desc *desc, struct ahash_request *req,
+		       int idx)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+
+	/* store the hash digest result in the context */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_dout_dlli(&desc[idx], state->digest_buff_dma_addr, digestsize,
+		      NS_BIT, 0);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	cc_set_endianity(ctx->hash_mode, &desc[idx]);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	idx++;
+
+	/* Loading hash opad xor key state */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_din_type(&desc[idx], DMA_DLLI, state->opad_digest_dma_addr,
+		     ctx->inter_digestsize, NS_BIT);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	idx++;
+
+	/* Load the hash current length */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_din_sram(&desc[idx],
+		     cc_digest_len_addr(ctx->drvdata, ctx->hash_mode),
+		     HASH_LEN_SIZE);
+	set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	/* Memory Barrier: wait for IPAD/OPAD axi write to complete */
+	hw_desc_init(&desc[idx]);
+	set_din_no_dma(&desc[idx], 0, 0xfffff0);
+	set_dout_no_dma(&desc[idx], 0, 0, 1);
+	idx++;
+
+	/* Perform HASH update */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr,
+		     digestsize, NS_BIT);
+	set_flow_mode(&desc[idx], DIN_HASH);
+	idx++;
+
+	return idx;
+}
+
+static int cc_hash_digest(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+	struct scatterlist *src = req->src;
+	unsigned int nbytes = req->nbytes;
+	u8 *result = req->result;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	bool is_hmac = ctx->is_hmac;
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	cc_sram_addr_t larval_digest_addr =
+		cc_larval_digest_addr(ctx->drvdata, ctx->hash_mode);
+	int idx = 0;
+	int rc = 0;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "===== %s-digest (%d) ====\n", is_hmac ? "hmac" : "hash",
+		nbytes);
+
+	cc_init_req(dev, state, ctx);
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -ENOMEM;
+	}
+
+	if (cc_map_result(dev, state, digestsize)) {
+		dev_err(dev, "map_ahash_digest() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	if (cc_map_hash_request_final(ctx->drvdata, state, src, nbytes, 1,
+				      flags)) {
+		dev_err(dev, "map_ahash_request_final() failed\n");
+		cc_unmap_result(dev, state, digestsize, result);
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = cc_digest_complete;
+	cc_req.user_arg = req;
+
+	/* If HMAC then load hash IPAD xor key, if HASH then load initial
+	 * digest
+	 */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	if (is_hmac) {
+		set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr,
+			     ctx->inter_digestsize, NS_BIT);
+	} else {
+		set_din_sram(&desc[idx], larval_digest_addr,
+			     ctx->inter_digestsize);
+	}
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	idx++;
+
+	/* Load the hash current length */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+
+	if (is_hmac) {
+		set_din_type(&desc[idx], DMA_DLLI,
+			     state->digest_bytes_len_dma_addr, HASH_LEN_SIZE,
+			     NS_BIT);
+	} else {
+		set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+		if (nbytes)
+			set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+		else
+			set_cipher_do(&desc[idx], DO_PAD);
+	}
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	cc_set_desc(state, ctx, DIN_HASH, desc, false, &idx);
+
+	if (is_hmac) {
+		/* HW last hash block padding (aka. "DO_PAD") */
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_dout_dlli(&desc[idx], state->digest_buff_dma_addr,
+			      HASH_LEN_SIZE, NS_BIT, 0);
+		set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+		set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
+		set_cipher_do(&desc[idx], DO_PAD);
+		idx++;
+
+		idx = cc_fin_hmac(desc, req, idx);
+	}
+
+	idx = cc_fin_result(desc, req, idx);
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, src, true);
+		cc_unmap_result(dev, state, digestsize, result);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_restore_hash(struct cc_hw_desc *desc, struct cc_hash_ctx *ctx,
+			   struct ahash_req_ctx *state, unsigned int idx)
+{
+	/* Restore hash digest */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr,
+		     ctx->inter_digestsize, NS_BIT);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	idx++;
+
+	/* Restore hash current length */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
+	set_din_type(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr,
+		     HASH_LEN_SIZE, NS_BIT);
+	set_flow_mode(&desc[idx], S_DIN_to_HASH);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	cc_set_desc(state, ctx, DIN_HASH, desc, false, &idx);
+
+	return idx;
+}
+
+static int cc_hash_update(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	unsigned int block_size = crypto_tfm_alg_blocksize(&tfm->base);
+	struct scatterlist *src = req->src;
+	unsigned int nbytes = req->nbytes;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	u32 idx = 0;
+	int rc;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "===== %s-update (%d) ====\n", ctx->is_hmac ?
+		"hmac" : "hash", nbytes);
+
+	if (nbytes == 0) {
+		/* no real updates required */
+		return 0;
+	}
+
+	rc = cc_map_hash_request_update(ctx->drvdata, state, src, nbytes,
+					block_size, flags);
+	if (rc) {
+		if (rc == 1) {
+			dev_dbg(dev, " data size not require HW update %x\n",
+				nbytes);
+			/* No hardware updates are required */
+			return 0;
+		}
+		dev_err(dev, "map_ahash_request_update() failed\n");
+		return -ENOMEM;
+	}
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		cc_unmap_hash_request(dev, state, src, true);
+		return -EINVAL;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = cc_update_complete;
+	cc_req.user_arg = req;
+
+	idx = cc_restore_hash(desc, ctx, state, idx);
+
+	/* store the hash digest result in context */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_dout_dlli(&desc[idx], state->digest_buff_dma_addr,
+		      ctx->inter_digestsize, NS_BIT, 0);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	idx++;
+
+	/* store current hash length in context */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_dout_dlli(&desc[idx], state->digest_bytes_len_dma_addr,
+		      HASH_LEN_SIZE, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
+	idx++;
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, src, true);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_hash_finup(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+	struct scatterlist *src = req->src;
+	unsigned int nbytes = req->nbytes;
+	u8 *result = req->result;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	bool is_hmac = ctx->is_hmac;
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	unsigned int idx = 0;
+	int rc;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "===== %s-finup (%d) ====\n", is_hmac ? "hmac" : "hash",
+		nbytes);
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -EINVAL;
+	}
+
+	if (cc_map_hash_request_final(ctx->drvdata, state, src, nbytes, 1,
+				      flags)) {
+		dev_err(dev, "map_ahash_request_final() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+	if (cc_map_result(dev, state, digestsize)) {
+		dev_err(dev, "map_ahash_digest() failed\n");
+		cc_unmap_hash_request(dev, state, src, true);
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = cc_hash_complete;
+	cc_req.user_arg = req;
+
+	idx = cc_restore_hash(desc, ctx, state, idx);
+
+	if (is_hmac)
+		idx = cc_fin_hmac(desc, req, idx);
+
+	idx = cc_fin_result(desc, req, idx);
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, src, true);
+		cc_unmap_result(dev, state, digestsize, result);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_hash_final(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+	struct scatterlist *src = req->src;
+	unsigned int nbytes = req->nbytes;
+	u8 *result = req->result;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	bool is_hmac = ctx->is_hmac;
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	unsigned int idx = 0;
+	int rc;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "===== %s-final (%d) ====\n", is_hmac ? "hmac" : "hash",
+		nbytes);
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -EINVAL;
+	}
+
+	if (cc_map_hash_request_final(ctx->drvdata, state, src, nbytes, 0,
+				      flags)) {
+		dev_err(dev, "map_ahash_request_final() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	if (cc_map_result(dev, state, digestsize)) {
+		dev_err(dev, "map_ahash_digest() failed\n");
+		cc_unmap_hash_request(dev, state, src, true);
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = cc_hash_complete;
+	cc_req.user_arg = req;
+
+	idx = cc_restore_hash(desc, ctx, state, idx);
+
+	/* "DO-PAD" must be enabled only when writing current length to HW */
+	hw_desc_init(&desc[idx]);
+	set_cipher_do(&desc[idx], DO_PAD);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_dout_dlli(&desc[idx], state->digest_bytes_len_dma_addr,
+		      HASH_LEN_SIZE, NS_BIT, 0);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
+	set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+	idx++;
+
+	if (is_hmac)
+		idx = cc_fin_hmac(desc, req, idx);
+
+	idx = cc_fin_result(desc, req, idx);
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, src, true);
+		cc_unmap_result(dev, state, digestsize, result);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_hash_init(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "===== init (%d) ====\n", req->nbytes);
+
+	cc_init_req(dev, state, ctx);
+
+	return 0;
+}
+
+static int cc_hash_setkey(struct crypto_ahash *ahash, const u8 *key,
+			  unsigned int keylen)
+{
+	unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST };
+	struct cc_crypto_req cc_req = {};
+	struct cc_hash_ctx *ctx = NULL;
+	int blocksize = 0;
+	int digestsize = 0;
+	int i, idx = 0, rc = 0;
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	cc_sram_addr_t larval_addr;
+	struct device *dev;
+
+	ctx = crypto_ahash_ctx(ahash);
+	dev = drvdata_to_dev(ctx->drvdata);
+	dev_dbg(dev, "start keylen: %d", keylen);
+
+	blocksize = crypto_tfm_alg_blocksize(&ahash->base);
+	digestsize = crypto_ahash_digestsize(ahash);
+
+	larval_addr = cc_larval_digest_addr(ctx->drvdata, ctx->hash_mode);
+
+	/* The keylen value distinguishes HASH in case keylen is ZERO bytes,
+	 * any NON-ZERO value utilizes HMAC flow
+	 */
+	ctx->key_params.keylen = keylen;
+	ctx->key_params.key_dma_addr = 0;
+	ctx->is_hmac = true;
+
+	if (keylen) {
+		ctx->key_params.key_dma_addr =
+			dma_map_single(dev, (void *)key, keylen, DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, ctx->key_params.key_dma_addr)) {
+			dev_err(dev, "Mapping key va=0x%p len=%u for DMA failed\n",
+				key, keylen);
+			return -ENOMEM;
+		}
+		dev_dbg(dev, "mapping key-buffer: key_dma_addr=%pad keylen=%u\n",
+			&ctx->key_params.key_dma_addr, ctx->key_params.keylen);
+
+		if (keylen > blocksize) {
+			/* Load hash initial state */
+			hw_desc_init(&desc[idx]);
+			set_cipher_mode(&desc[idx], ctx->hw_mode);
+			set_din_sram(&desc[idx], larval_addr,
+				     ctx->inter_digestsize);
+			set_flow_mode(&desc[idx], S_DIN_to_HASH);
+			set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+			idx++;
+
+			/* Load the hash current length*/
+			hw_desc_init(&desc[idx]);
+			set_cipher_mode(&desc[idx], ctx->hw_mode);
+			set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+			set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
+			set_flow_mode(&desc[idx], S_DIN_to_HASH);
+			set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+			idx++;
+
+			hw_desc_init(&desc[idx]);
+			set_din_type(&desc[idx], DMA_DLLI,
+				     ctx->key_params.key_dma_addr, keylen,
+				     NS_BIT);
+			set_flow_mode(&desc[idx], DIN_HASH);
+			idx++;
+
+			/* Get hashed key */
+			hw_desc_init(&desc[idx]);
+			set_cipher_mode(&desc[idx], ctx->hw_mode);
+			set_dout_dlli(&desc[idx], ctx->opad_tmp_keys_dma_addr,
+				      digestsize, NS_BIT, 0);
+			set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+			set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+			set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
+			cc_set_endianity(ctx->hash_mode, &desc[idx]);
+			idx++;
+
+			hw_desc_init(&desc[idx]);
+			set_din_const(&desc[idx], 0, (blocksize - digestsize));
+			set_flow_mode(&desc[idx], BYPASS);
+			set_dout_dlli(&desc[idx],
+				      (ctx->opad_tmp_keys_dma_addr +
+				       digestsize),
+				      (blocksize - digestsize), NS_BIT, 0);
+			idx++;
+		} else {
+			hw_desc_init(&desc[idx]);
+			set_din_type(&desc[idx], DMA_DLLI,
+				     ctx->key_params.key_dma_addr, keylen,
+				     NS_BIT);
+			set_flow_mode(&desc[idx], BYPASS);
+			set_dout_dlli(&desc[idx], ctx->opad_tmp_keys_dma_addr,
+				      keylen, NS_BIT, 0);
+			idx++;
+
+			if ((blocksize - keylen)) {
+				hw_desc_init(&desc[idx]);
+				set_din_const(&desc[idx], 0,
+					      (blocksize - keylen));
+				set_flow_mode(&desc[idx], BYPASS);
+				set_dout_dlli(&desc[idx],
+					      (ctx->opad_tmp_keys_dma_addr +
+					       keylen), (blocksize - keylen),
+					      NS_BIT, 0);
+				idx++;
+			}
+		}
+	} else {
+		hw_desc_init(&desc[idx]);
+		set_din_const(&desc[idx], 0, blocksize);
+		set_flow_mode(&desc[idx], BYPASS);
+		set_dout_dlli(&desc[idx], (ctx->opad_tmp_keys_dma_addr),
+			      blocksize, NS_BIT, 0);
+		idx++;
+	}
+
+	rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx);
+	if (rc) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		goto out;
+	}
+
+	/* calc derived HMAC key */
+	for (idx = 0, i = 0; i < 2; i++) {
+		/* Load hash initial state */
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_din_sram(&desc[idx], larval_addr, ctx->inter_digestsize);
+		set_flow_mode(&desc[idx], S_DIN_to_HASH);
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+		idx++;
+
+		/* Load the hash current length*/
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+		set_flow_mode(&desc[idx], S_DIN_to_HASH);
+		set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+		idx++;
+
+		/* Prepare ipad key */
+		hw_desc_init(&desc[idx]);
+		set_xor_val(&desc[idx], hmac_pad_const[i]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_flow_mode(&desc[idx], S_DIN_to_HASH);
+		set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+		idx++;
+
+		/* Perform HASH update */
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI, ctx->opad_tmp_keys_dma_addr,
+			     blocksize, NS_BIT);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_xor_active(&desc[idx]);
+		set_flow_mode(&desc[idx], DIN_HASH);
+		idx++;
+
+		/* Get the IPAD/OPAD xor key (Note, IPAD is the initial digest
+		 * of the first HASH "update" state)
+		 */
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		if (i > 0) /* Not first iteration */
+			set_dout_dlli(&desc[idx], ctx->opad_tmp_keys_dma_addr,
+				      ctx->inter_digestsize, NS_BIT, 0);
+		else /* First iteration */
+			set_dout_dlli(&desc[idx], ctx->digest_buff_dma_addr,
+				      ctx->inter_digestsize, NS_BIT, 0);
+		set_flow_mode(&desc[idx], S_HASH_to_DOUT);
+		set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+		idx++;
+	}
+
+	rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx);
+
+out:
+	if (rc)
+		crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+	if (ctx->key_params.key_dma_addr) {
+		dma_unmap_single(dev, ctx->key_params.key_dma_addr,
+				 ctx->key_params.keylen, DMA_TO_DEVICE);
+		dev_dbg(dev, "Unmapped key-buffer: key_dma_addr=%pad keylen=%u\n",
+			&ctx->key_params.key_dma_addr, ctx->key_params.keylen);
+	}
+	return rc;
+}
+
+static int cc_xcbc_setkey(struct crypto_ahash *ahash,
+			  const u8 *key, unsigned int keylen)
+{
+	struct cc_crypto_req cc_req = {};
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	int rc = 0;
+	unsigned int idx = 0;
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+
+	dev_dbg(dev, "===== setkey (%d) ====\n", keylen);
+
+	switch (keylen) {
+	case AES_KEYSIZE_128:
+	case AES_KEYSIZE_192:
+	case AES_KEYSIZE_256:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ctx->key_params.keylen = keylen;
+
+	ctx->key_params.key_dma_addr =
+		dma_map_single(dev, (void *)key, keylen, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, ctx->key_params.key_dma_addr)) {
+		dev_err(dev, "Mapping key va=0x%p len=%u for DMA failed\n",
+			key, keylen);
+		return -ENOMEM;
+	}
+	dev_dbg(dev, "mapping key-buffer: key_dma_addr=%pad keylen=%u\n",
+		&ctx->key_params.key_dma_addr, ctx->key_params.keylen);
+
+	ctx->is_hmac = true;
+	/* 1. Load the AES key */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, ctx->key_params.key_dma_addr,
+		     keylen, NS_BIT);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_ECB);
+	set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+	set_key_size_aes(&desc[idx], keylen);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	idx++;
+
+	hw_desc_init(&desc[idx]);
+	set_din_const(&desc[idx], 0x01010101, CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], DIN_AES_DOUT);
+	set_dout_dlli(&desc[idx],
+		      (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K1_OFFSET),
+		      CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0);
+	idx++;
+
+	hw_desc_init(&desc[idx]);
+	set_din_const(&desc[idx], 0x02020202, CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], DIN_AES_DOUT);
+	set_dout_dlli(&desc[idx],
+		      (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K2_OFFSET),
+		      CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0);
+	idx++;
+
+	hw_desc_init(&desc[idx]);
+	set_din_const(&desc[idx], 0x03030303, CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], DIN_AES_DOUT);
+	set_dout_dlli(&desc[idx],
+		      (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K3_OFFSET),
+		      CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0);
+	idx++;
+
+	rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx);
+
+	if (rc)
+		crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+	dma_unmap_single(dev, ctx->key_params.key_dma_addr,
+			 ctx->key_params.keylen, DMA_TO_DEVICE);
+	dev_dbg(dev, "Unmapped key-buffer: key_dma_addr=%pad keylen=%u\n",
+		&ctx->key_params.key_dma_addr, ctx->key_params.keylen);
+
+	return rc;
+}
+
+static int cc_cmac_setkey(struct crypto_ahash *ahash,
+			  const u8 *key, unsigned int keylen)
+{
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "===== setkey (%d) ====\n", keylen);
+
+	ctx->is_hmac = true;
+
+	switch (keylen) {
+	case AES_KEYSIZE_128:
+	case AES_KEYSIZE_192:
+	case AES_KEYSIZE_256:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ctx->key_params.keylen = keylen;
+
+	/* STAT_PHASE_1: Copy key to ctx */
+
+	dma_sync_single_for_cpu(dev, ctx->opad_tmp_keys_dma_addr,
+				keylen, DMA_TO_DEVICE);
+
+	memcpy(ctx->opad_tmp_keys_buff, key, keylen);
+	if (keylen == 24) {
+		memset(ctx->opad_tmp_keys_buff + 24, 0,
+		       CC_AES_KEY_SIZE_MAX - 24);
+	}
+
+	dma_sync_single_for_device(dev, ctx->opad_tmp_keys_dma_addr,
+				   keylen, DMA_TO_DEVICE);
+
+	ctx->key_params.keylen = keylen;
+
+	return 0;
+}
+
+static void cc_free_ctx(struct cc_hash_ctx *ctx)
+{
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	if (ctx->digest_buff_dma_addr) {
+		dma_unmap_single(dev, ctx->digest_buff_dma_addr,
+				 sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "Unmapped digest-buffer: digest_buff_dma_addr=%pad\n",
+			&ctx->digest_buff_dma_addr);
+		ctx->digest_buff_dma_addr = 0;
+	}
+	if (ctx->opad_tmp_keys_dma_addr) {
+		dma_unmap_single(dev, ctx->opad_tmp_keys_dma_addr,
+				 sizeof(ctx->opad_tmp_keys_buff),
+				 DMA_BIDIRECTIONAL);
+		dev_dbg(dev, "Unmapped opad-digest: opad_tmp_keys_dma_addr=%pad\n",
+			&ctx->opad_tmp_keys_dma_addr);
+		ctx->opad_tmp_keys_dma_addr = 0;
+	}
+
+	ctx->key_params.keylen = 0;
+}
+
+static int cc_alloc_ctx(struct cc_hash_ctx *ctx)
+{
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	ctx->key_params.keylen = 0;
+
+	ctx->digest_buff_dma_addr =
+		dma_map_single(dev, (void *)ctx->digest_buff,
+			       sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, ctx->digest_buff_dma_addr)) {
+		dev_err(dev, "Mapping digest len %zu B at va=%pK for DMA failed\n",
+			sizeof(ctx->digest_buff), ctx->digest_buff);
+		goto fail;
+	}
+	dev_dbg(dev, "Mapped digest %zu B at va=%pK to dma=%pad\n",
+		sizeof(ctx->digest_buff), ctx->digest_buff,
+		&ctx->digest_buff_dma_addr);
+
+	ctx->opad_tmp_keys_dma_addr =
+		dma_map_single(dev, (void *)ctx->opad_tmp_keys_buff,
+			       sizeof(ctx->opad_tmp_keys_buff),
+			       DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, ctx->opad_tmp_keys_dma_addr)) {
+		dev_err(dev, "Mapping opad digest %zu B at va=%pK for DMA failed\n",
+			sizeof(ctx->opad_tmp_keys_buff),
+			ctx->opad_tmp_keys_buff);
+		goto fail;
+	}
+	dev_dbg(dev, "Mapped opad_tmp_keys %zu B at va=%pK to dma=%pad\n",
+		sizeof(ctx->opad_tmp_keys_buff), ctx->opad_tmp_keys_buff,
+		&ctx->opad_tmp_keys_dma_addr);
+
+	ctx->is_hmac = false;
+	return 0;
+
+fail:
+	cc_free_ctx(ctx);
+	return -ENOMEM;
+}
+
+static int cc_cra_init(struct crypto_tfm *tfm)
+{
+	struct cc_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct hash_alg_common *hash_alg_common =
+		container_of(tfm->__crt_alg, struct hash_alg_common, base);
+	struct ahash_alg *ahash_alg =
+		container_of(hash_alg_common, struct ahash_alg, halg);
+	struct cc_hash_alg *cc_alg =
+			container_of(ahash_alg, struct cc_hash_alg, ahash_alg);
+
+	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+				 sizeof(struct ahash_req_ctx));
+
+	ctx->hash_mode = cc_alg->hash_mode;
+	ctx->hw_mode = cc_alg->hw_mode;
+	ctx->inter_digestsize = cc_alg->inter_digestsize;
+	ctx->drvdata = cc_alg->drvdata;
+
+	return cc_alloc_ctx(ctx);
+}
+
+static void cc_cra_exit(struct crypto_tfm *tfm)
+{
+	struct cc_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	dev_dbg(dev, "cc_cra_exit");
+	cc_free_ctx(ctx);
+}
+
+static int cc_mac_update(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	unsigned int block_size = crypto_tfm_alg_blocksize(&tfm->base);
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	int rc;
+	u32 idx = 0;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	if (req->nbytes == 0) {
+		/* no real updates required */
+		return 0;
+	}
+
+	state->xcbc_count++;
+
+	rc = cc_map_hash_request_update(ctx->drvdata, state, req->src,
+					req->nbytes, block_size, flags);
+	if (rc) {
+		if (rc == 1) {
+			dev_dbg(dev, " data size not require HW update %x\n",
+				req->nbytes);
+			/* No hardware updates are required */
+			return 0;
+		}
+		dev_err(dev, "map_ahash_request_update() failed\n");
+		return -ENOMEM;
+	}
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -EINVAL;
+	}
+
+	if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC)
+		cc_setup_xcbc(req, desc, &idx);
+	else
+		cc_setup_cmac(req, desc, &idx);
+
+	cc_set_desc(state, ctx, DIN_AES_DOUT, desc, true, &idx);
+
+	/* store the hash digest result in context */
+	hw_desc_init(&desc[idx]);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	set_dout_dlli(&desc[idx], state->digest_buff_dma_addr,
+		      ctx->inter_digestsize, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], S_AES_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	idx++;
+
+	/* Setup request structure */
+	cc_req.user_cb = (void *)cc_update_complete;
+	cc_req.user_arg = (void *)req;
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, req->src, true);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_mac_final(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	int idx = 0;
+	int rc = 0;
+	u32 key_size, key_len;
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+	gfp_t flags = cc_gfp_flags(&req->base);
+	u32 rem_cnt = *cc_hash_buf_cnt(state);
+
+	if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+		key_size = CC_AES_128_BIT_KEY_SIZE;
+		key_len  = CC_AES_128_BIT_KEY_SIZE;
+	} else {
+		key_size = (ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE :
+			ctx->key_params.keylen;
+		key_len =  ctx->key_params.keylen;
+	}
+
+	dev_dbg(dev, "===== final  xcbc reminder (%d) ====\n", rem_cnt);
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -EINVAL;
+	}
+
+	if (cc_map_hash_request_final(ctx->drvdata, state, req->src,
+				      req->nbytes, 0, flags)) {
+		dev_err(dev, "map_ahash_request_final() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	if (cc_map_result(dev, state, digestsize)) {
+		dev_err(dev, "map_ahash_digest() failed\n");
+		cc_unmap_hash_request(dev, state, req->src, true);
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = (void *)cc_hash_complete;
+	cc_req.user_arg = (void *)req;
+
+	if (state->xcbc_count && rem_cnt == 0) {
+		/* Load key for ECB decryption */
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], DRV_CIPHER_ECB);
+		set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_DECRYPT);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K1_OFFSET),
+			     key_size, NS_BIT);
+		set_key_size_aes(&desc[idx], key_len);
+		set_flow_mode(&desc[idx], S_DIN_to_AES);
+		set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+		idx++;
+
+		/* Initiate decryption of block state to previous
+		 * block_state-XOR-M[n]
+		 */
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr,
+			     CC_AES_BLOCK_SIZE, NS_BIT);
+		set_dout_dlli(&desc[idx], state->digest_buff_dma_addr,
+			      CC_AES_BLOCK_SIZE, NS_BIT, 0);
+		set_flow_mode(&desc[idx], DIN_AES_DOUT);
+		idx++;
+
+		/* Memory Barrier: wait for axi write to complete */
+		hw_desc_init(&desc[idx]);
+		set_din_no_dma(&desc[idx], 0, 0xfffff0);
+		set_dout_no_dma(&desc[idx], 0, 0, 1);
+		idx++;
+	}
+
+	if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC)
+		cc_setup_xcbc(req, desc, &idx);
+	else
+		cc_setup_cmac(req, desc, &idx);
+
+	if (state->xcbc_count == 0) {
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_key_size_aes(&desc[idx], key_len);
+		set_cmac_size0_mode(&desc[idx]);
+		set_flow_mode(&desc[idx], S_DIN_to_AES);
+		idx++;
+	} else if (rem_cnt > 0) {
+		cc_set_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+	} else {
+		hw_desc_init(&desc[idx]);
+		set_din_const(&desc[idx], 0x00, CC_AES_BLOCK_SIZE);
+		set_flow_mode(&desc[idx], DIN_AES_DOUT);
+		idx++;
+	}
+
+	/* Get final MAC result */
+	hw_desc_init(&desc[idx]);
+	/* TODO */
+	set_dout_dlli(&desc[idx], state->digest_result_dma_addr,
+		      digestsize, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], S_AES_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	idx++;
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, req->src, true);
+		cc_unmap_result(dev, state, digestsize, req->result);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_mac_finup(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	int idx = 0;
+	int rc = 0;
+	u32 key_len = 0;
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "===== finup xcbc(%d) ====\n", req->nbytes);
+	if (state->xcbc_count > 0 && req->nbytes == 0) {
+		dev_dbg(dev, "No data to update. Call to fdx_mac_final\n");
+		return cc_mac_final(req);
+	}
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -EINVAL;
+	}
+
+	if (cc_map_hash_request_final(ctx->drvdata, state, req->src,
+				      req->nbytes, 1, flags)) {
+		dev_err(dev, "map_ahash_request_final() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+	if (cc_map_result(dev, state, digestsize)) {
+		dev_err(dev, "map_ahash_digest() failed\n");
+		cc_unmap_hash_request(dev, state, req->src, true);
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = (void *)cc_hash_complete;
+	cc_req.user_arg = (void *)req;
+
+	if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+		key_len = CC_AES_128_BIT_KEY_SIZE;
+		cc_setup_xcbc(req, desc, &idx);
+	} else {
+		key_len = ctx->key_params.keylen;
+		cc_setup_cmac(req, desc, &idx);
+	}
+
+	if (req->nbytes == 0) {
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_key_size_aes(&desc[idx], key_len);
+		set_cmac_size0_mode(&desc[idx]);
+		set_flow_mode(&desc[idx], S_DIN_to_AES);
+		idx++;
+	} else {
+		cc_set_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+	}
+
+	/* Get final MAC result */
+	hw_desc_init(&desc[idx]);
+	/* TODO */
+	set_dout_dlli(&desc[idx], state->digest_result_dma_addr,
+		      digestsize, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], S_AES_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	idx++;
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, req->src, true);
+		cc_unmap_result(dev, state, digestsize, req->result);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_mac_digest(struct ahash_request *req)
+{
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	u32 digestsize = crypto_ahash_digestsize(tfm);
+	struct cc_crypto_req cc_req = {};
+	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
+	u32 key_len;
+	unsigned int idx = 0;
+	int rc;
+	gfp_t flags = cc_gfp_flags(&req->base);
+
+	dev_dbg(dev, "===== -digest mac (%d) ====\n",  req->nbytes);
+
+	cc_init_req(dev, state, ctx);
+
+	if (cc_map_req(dev, state, ctx)) {
+		dev_err(dev, "map_ahash_source() failed\n");
+		return -ENOMEM;
+	}
+	if (cc_map_result(dev, state, digestsize)) {
+		dev_err(dev, "map_ahash_digest() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	if (cc_map_hash_request_final(ctx->drvdata, state, req->src,
+				      req->nbytes, 1, flags)) {
+		dev_err(dev, "map_ahash_request_final() failed\n");
+		cc_unmap_req(dev, state, ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup request structure */
+	cc_req.user_cb = (void *)cc_digest_complete;
+	cc_req.user_arg = (void *)req;
+
+	if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+		key_len = CC_AES_128_BIT_KEY_SIZE;
+		cc_setup_xcbc(req, desc, &idx);
+	} else {
+		key_len = ctx->key_params.keylen;
+		cc_setup_cmac(req, desc, &idx);
+	}
+
+	if (req->nbytes == 0) {
+		hw_desc_init(&desc[idx]);
+		set_cipher_mode(&desc[idx], ctx->hw_mode);
+		set_key_size_aes(&desc[idx], key_len);
+		set_cmac_size0_mode(&desc[idx]);
+		set_flow_mode(&desc[idx], S_DIN_to_AES);
+		idx++;
+	} else {
+		cc_set_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+	}
+
+	/* Get final MAC result */
+	hw_desc_init(&desc[idx]);
+	set_dout_dlli(&desc[idx], state->digest_result_dma_addr,
+		      CC_AES_BLOCK_SIZE, NS_BIT, 1);
+	set_queue_last_ind(&desc[idx]);
+	set_flow_mode(&desc[idx], S_AES_to_DOUT);
+	set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_cipher_mode(&desc[idx], ctx->hw_mode);
+	idx++;
+
+	rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base);
+	if (rc != -EINPROGRESS && rc != -EBUSY) {
+		dev_err(dev, "send_request() failed (rc=%d)\n", rc);
+		cc_unmap_hash_request(dev, state, req->src, true);
+		cc_unmap_result(dev, state, digestsize, req->result);
+		cc_unmap_req(dev, state, ctx);
+	}
+	return rc;
+}
+
+static int cc_hash_export(struct ahash_request *req, void *out)
+{
+	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	u8 *curr_buff = cc_hash_buf(state);
+	u32 curr_buff_cnt = *cc_hash_buf_cnt(state);
+	const u32 tmp = CC_EXPORT_MAGIC;
+
+	memcpy(out, &tmp, sizeof(u32));
+	out += sizeof(u32);
+
+	memcpy(out, state->digest_buff, ctx->inter_digestsize);
+	out += ctx->inter_digestsize;
+
+	memcpy(out, state->digest_bytes_len, HASH_LEN_SIZE);
+	out += HASH_LEN_SIZE;
+
+	memcpy(out, &curr_buff_cnt, sizeof(u32));
+	out += sizeof(u32);
+
+	memcpy(out, curr_buff, curr_buff_cnt);
+
+	return 0;
+}
+
+static int cc_hash_import(struct ahash_request *req, const void *in)
+{
+	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+	struct ahash_req_ctx *state = ahash_request_ctx(req);
+	u32 tmp;
+
+	memcpy(&tmp, in, sizeof(u32));
+	if (tmp != CC_EXPORT_MAGIC)
+		return -EINVAL;
+	in += sizeof(u32);
+
+	cc_init_req(dev, state, ctx);
+
+	memcpy(state->digest_buff, in, ctx->inter_digestsize);
+	in += ctx->inter_digestsize;
+
+	memcpy(state->digest_bytes_len, in, HASH_LEN_SIZE);
+	in += HASH_LEN_SIZE;
+
+	/* Sanity check the data as much as possible */
+	memcpy(&tmp, in, sizeof(u32));
+	if (tmp > CC_MAX_HASH_BLCK_SIZE)
+		return -EINVAL;
+	in += sizeof(u32);
+
+	state->buf_cnt[0] = tmp;
+	memcpy(state->buffers[0], in, tmp);
+
+	return 0;
+}
+
+struct cc_hash_template {
+	char name[CRYPTO_MAX_ALG_NAME];
+	char driver_name[CRYPTO_MAX_ALG_NAME];
+	char mac_name[CRYPTO_MAX_ALG_NAME];
+	char mac_driver_name[CRYPTO_MAX_ALG_NAME];
+	unsigned int blocksize;
+	bool synchronize;
+	struct ahash_alg template_ahash;
+	int hash_mode;
+	int hw_mode;
+	int inter_digestsize;
+	struct cc_drvdata *drvdata;
+};
+
+#define CC_STATE_SIZE(_x) \
+	((_x) + HASH_LEN_SIZE + CC_MAX_HASH_BLCK_SIZE + (2 * sizeof(u32)))
+
+/* hash descriptors */
+static struct cc_hash_template driver_hash[] = {
+	//Asynchronize hash template
+	{
+		.name = "sha1",
+		.driver_name = "sha1-ccree",
+		.mac_name = "hmac(sha1)",
+		.mac_driver_name = "hmac-sha1-ccree",
+		.blocksize = SHA1_BLOCK_SIZE,
+		.synchronize = false,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_hash_update,
+			.final = cc_hash_final,
+			.finup = cc_hash_finup,
+			.digest = cc_hash_digest,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.setkey = cc_hash_setkey,
+			.halg = {
+				.digestsize = SHA1_DIGEST_SIZE,
+				.statesize = CC_STATE_SIZE(SHA1_DIGEST_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_SHA1,
+		.hw_mode = DRV_HASH_HW_SHA1,
+		.inter_digestsize = SHA1_DIGEST_SIZE,
+	},
+	{
+		.name = "sha256",
+		.driver_name = "sha256-ccree",
+		.mac_name = "hmac(sha256)",
+		.mac_driver_name = "hmac-sha256-ccree",
+		.blocksize = SHA256_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_hash_update,
+			.final = cc_hash_final,
+			.finup = cc_hash_finup,
+			.digest = cc_hash_digest,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.setkey = cc_hash_setkey,
+			.halg = {
+				.digestsize = SHA256_DIGEST_SIZE,
+				.statesize = CC_STATE_SIZE(SHA256_DIGEST_SIZE)
+			},
+		},
+		.hash_mode = DRV_HASH_SHA256,
+		.hw_mode = DRV_HASH_HW_SHA256,
+		.inter_digestsize = SHA256_DIGEST_SIZE,
+	},
+	{
+		.name = "sha224",
+		.driver_name = "sha224-ccree",
+		.mac_name = "hmac(sha224)",
+		.mac_driver_name = "hmac-sha224-ccree",
+		.blocksize = SHA224_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_hash_update,
+			.final = cc_hash_final,
+			.finup = cc_hash_finup,
+			.digest = cc_hash_digest,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.setkey = cc_hash_setkey,
+			.halg = {
+				.digestsize = SHA224_DIGEST_SIZE,
+				.statesize = CC_STATE_SIZE(SHA224_DIGEST_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_SHA224,
+		.hw_mode = DRV_HASH_HW_SHA256,
+		.inter_digestsize = SHA256_DIGEST_SIZE,
+	},
+#if (CC_DEV_SHA_MAX > 256)
+	{
+		.name = "sha384",
+		.driver_name = "sha384-ccree",
+		.mac_name = "hmac(sha384)",
+		.mac_driver_name = "hmac-sha384-ccree",
+		.blocksize = SHA384_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_hash_update,
+			.final = cc_hash_final,
+			.finup = cc_hash_finup,
+			.digest = cc_hash_digest,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.setkey = cc_hash_setkey,
+			.halg = {
+				.digestsize = SHA384_DIGEST_SIZE,
+				.statesize = CC_STATE_SIZE(SHA384_DIGEST_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_SHA384,
+		.hw_mode = DRV_HASH_HW_SHA512,
+		.inter_digestsize = SHA512_DIGEST_SIZE,
+	},
+	{
+		.name = "sha512",
+		.driver_name = "sha512-ccree",
+		.mac_name = "hmac(sha512)",
+		.mac_driver_name = "hmac-sha512-ccree",
+		.blocksize = SHA512_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_hash_update,
+			.final = cc_hash_final,
+			.finup = cc_hash_finup,
+			.digest = cc_hash_digest,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.setkey = cc_hash_setkey,
+			.halg = {
+				.digestsize = SHA512_DIGEST_SIZE,
+				.statesize = CC_STATE_SIZE(SHA512_DIGEST_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_SHA512,
+		.hw_mode = DRV_HASH_HW_SHA512,
+		.inter_digestsize = SHA512_DIGEST_SIZE,
+	},
+#endif
+	{
+		.name = "md5",
+		.driver_name = "md5-ccree",
+		.mac_name = "hmac(md5)",
+		.mac_driver_name = "hmac-md5-ccree",
+		.blocksize = MD5_HMAC_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_hash_update,
+			.final = cc_hash_final,
+			.finup = cc_hash_finup,
+			.digest = cc_hash_digest,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.setkey = cc_hash_setkey,
+			.halg = {
+				.digestsize = MD5_DIGEST_SIZE,
+				.statesize = CC_STATE_SIZE(MD5_DIGEST_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_MD5,
+		.hw_mode = DRV_HASH_HW_MD5,
+		.inter_digestsize = MD5_DIGEST_SIZE,
+	},
+	{
+		.mac_name = "xcbc(aes)",
+		.mac_driver_name = "xcbc-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_mac_update,
+			.final = cc_mac_final,
+			.finup = cc_mac_finup,
+			.digest = cc_mac_digest,
+			.setkey = cc_xcbc_setkey,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.halg = {
+				.digestsize = AES_BLOCK_SIZE,
+				.statesize = CC_STATE_SIZE(AES_BLOCK_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_NULL,
+		.hw_mode = DRV_CIPHER_XCBC_MAC,
+		.inter_digestsize = AES_BLOCK_SIZE,
+	},
+	{
+		.mac_name = "cmac(aes)",
+		.mac_driver_name = "cmac-aes-ccree",
+		.blocksize = AES_BLOCK_SIZE,
+		.template_ahash = {
+			.init = cc_hash_init,
+			.update = cc_mac_update,
+			.final = cc_mac_final,
+			.finup = cc_mac_finup,
+			.digest = cc_mac_digest,
+			.setkey = cc_cmac_setkey,
+			.export = cc_hash_export,
+			.import = cc_hash_import,
+			.halg = {
+				.digestsize = AES_BLOCK_SIZE,
+				.statesize = CC_STATE_SIZE(AES_BLOCK_SIZE),
+			},
+		},
+		.hash_mode = DRV_HASH_NULL,
+		.hw_mode = DRV_CIPHER_CMAC,
+		.inter_digestsize = AES_BLOCK_SIZE,
+	},
+};
+
+static struct cc_hash_alg *cc_alloc_hash_alg(struct cc_hash_template *template,
+					     struct device *dev, bool keyed)
+{
+	struct cc_hash_alg *t_crypto_alg;
+	struct crypto_alg *alg;
+	struct ahash_alg *halg;
+
+	t_crypto_alg = kzalloc(sizeof(*t_crypto_alg), GFP_KERNEL);
+	if (!t_crypto_alg)
+		return ERR_PTR(-ENOMEM);
+
+	t_crypto_alg->ahash_alg = template->template_ahash;
+	halg = &t_crypto_alg->ahash_alg;
+	alg = &halg->halg.base;
+
+	if (keyed) {
+		snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
+			 template->mac_name);
+		snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+			 template->mac_driver_name);
+	} else {
+		halg->setkey = NULL;
+		snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
+			 template->name);
+		snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+			 template->driver_name);
+	}
+	alg->cra_module = THIS_MODULE;
+	alg->cra_ctxsize = sizeof(struct cc_hash_ctx);
+	alg->cra_priority = CC_CRA_PRIO;
+	alg->cra_blocksize = template->blocksize;
+	alg->cra_alignmask = 0;
+	alg->cra_exit = cc_cra_exit;
+
+	alg->cra_init = cc_cra_init;
+	alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_TYPE_AHASH |
+			CRYPTO_ALG_KERN_DRIVER_ONLY;
+	alg->cra_type = &crypto_ahash_type;
+
+	t_crypto_alg->hash_mode = template->hash_mode;
+	t_crypto_alg->hw_mode = template->hw_mode;
+	t_crypto_alg->inter_digestsize = template->inter_digestsize;
+
+	return t_crypto_alg;
+}
+
+int cc_init_hash_sram(struct cc_drvdata *drvdata)
+{
+	struct cc_hash_handle *hash_handle = drvdata->hash_handle;
+	cc_sram_addr_t sram_buff_ofs = hash_handle->digest_len_sram_addr;
+	unsigned int larval_seq_len = 0;
+	struct cc_hw_desc larval_seq[CC_DIGEST_SIZE_MAX / sizeof(u32)];
+	int rc = 0;
+
+	/* Copy-to-sram digest-len */
+	cc_set_sram_desc(digest_len_init, sram_buff_ofs,
+			 ARRAY_SIZE(digest_len_init), larval_seq,
+			 &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+
+	sram_buff_ofs += sizeof(digest_len_init);
+	larval_seq_len = 0;
+
+#if (CC_DEV_SHA_MAX > 256)
+	/* Copy-to-sram digest-len for sha384/512 */
+	cc_set_sram_desc(digest_len_sha512_init, sram_buff_ofs,
+			 ARRAY_SIZE(digest_len_sha512_init),
+			 larval_seq, &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+
+	sram_buff_ofs += sizeof(digest_len_sha512_init);
+	larval_seq_len = 0;
+#endif
+
+	/* The initial digests offset */
+	hash_handle->larval_digest_sram_addr = sram_buff_ofs;
+
+	/* Copy-to-sram initial SHA* digests */
+	cc_set_sram_desc(md5_init, sram_buff_ofs, ARRAY_SIZE(md5_init),
+			 larval_seq, &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+	sram_buff_ofs += sizeof(md5_init);
+	larval_seq_len = 0;
+
+	cc_set_sram_desc(sha1_init, sram_buff_ofs,
+			 ARRAY_SIZE(sha1_init), larval_seq,
+			 &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+	sram_buff_ofs += sizeof(sha1_init);
+	larval_seq_len = 0;
+
+	cc_set_sram_desc(sha224_init, sram_buff_ofs,
+			 ARRAY_SIZE(sha224_init), larval_seq,
+			 &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+	sram_buff_ofs += sizeof(sha224_init);
+	larval_seq_len = 0;
+
+	cc_set_sram_desc(sha256_init, sram_buff_ofs,
+			 ARRAY_SIZE(sha256_init), larval_seq,
+			 &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+	sram_buff_ofs += sizeof(sha256_init);
+	larval_seq_len = 0;
+
+#if (CC_DEV_SHA_MAX > 256)
+	cc_set_sram_desc((u32 *)sha384_init, sram_buff_ofs,
+			 (ARRAY_SIZE(sha384_init) * 2), larval_seq,
+			 &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+	sram_buff_ofs += sizeof(sha384_init);
+	larval_seq_len = 0;
+
+	cc_set_sram_desc((u32 *)sha512_init, sram_buff_ofs,
+			 (ARRAY_SIZE(sha512_init) * 2), larval_seq,
+			 &larval_seq_len);
+	rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+	if (rc)
+		goto init_digest_const_err;
+#endif
+
+init_digest_const_err:
+	return rc;
+}
+
+static void __init cc_swap_dwords(u32 *buf, unsigned long size)
+{
+	int i;
+	u32 tmp;
+
+	for (i = 0; i < size; i += 2) {
+		tmp = buf[i];
+		buf[i] = buf[i + 1];
+		buf[i + 1] = tmp;
+	}
+}
+
+/*
+ * Due to the way the HW works we need to swap every
+ * double word in the SHA384 and SHA512 larval hashes
+ */
+void __init cc_hash_global_init(void)
+{
+	cc_swap_dwords((u32 *)&sha384_init, (ARRAY_SIZE(sha384_init) * 2));
+	cc_swap_dwords((u32 *)&sha512_init, (ARRAY_SIZE(sha512_init) * 2));
+}
+
+int cc_hash_alloc(struct cc_drvdata *drvdata)
+{
+	struct cc_hash_handle *hash_handle;
+	cc_sram_addr_t sram_buff;
+	u32 sram_size_to_alloc;
+	struct device *dev = drvdata_to_dev(drvdata);
+	int rc = 0;
+	int alg;
+
+	hash_handle = kzalloc(sizeof(*hash_handle), GFP_KERNEL);
+	if (!hash_handle)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&hash_handle->hash_list);
+	drvdata->hash_handle = hash_handle;
+
+	sram_size_to_alloc = sizeof(digest_len_init) +
+#if (CC_DEV_SHA_MAX > 256)
+			sizeof(digest_len_sha512_init) +
+			sizeof(sha384_init) +
+			sizeof(sha512_init) +
+#endif
+			sizeof(md5_init) +
+			sizeof(sha1_init) +
+			sizeof(sha224_init) +
+			sizeof(sha256_init);
+
+	sram_buff = cc_sram_alloc(drvdata, sram_size_to_alloc);
+	if (sram_buff == NULL_SRAM_ADDR) {
+		dev_err(dev, "SRAM pool exhausted\n");
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	/* The initial digest-len offset */
+	hash_handle->digest_len_sram_addr = sram_buff;
+
+	/*must be set before the alg registration as it is being used there*/
+	rc = cc_init_hash_sram(drvdata);
+	if (rc) {
+		dev_err(dev, "Init digest CONST failed (rc=%d)\n", rc);
+		goto fail;
+	}
+
+	/* ahash registration */
+	for (alg = 0; alg < ARRAY_SIZE(driver_hash); alg++) {
+		struct cc_hash_alg *t_alg;
+		int hw_mode = driver_hash[alg].hw_mode;
+
+		/* register hmac version */
+		t_alg = cc_alloc_hash_alg(&driver_hash[alg], dev, true);
+		if (IS_ERR(t_alg)) {
+			rc = PTR_ERR(t_alg);
+			dev_err(dev, "%s alg allocation failed\n",
+				driver_hash[alg].driver_name);
+			goto fail;
+		}
+		t_alg->drvdata = drvdata;
+
+		rc = crypto_register_ahash(&t_alg->ahash_alg);
+		if (rc) {
+			dev_err(dev, "%s alg registration failed\n",
+				driver_hash[alg].driver_name);
+			kfree(t_alg);
+			goto fail;
+		} else {
+			list_add_tail(&t_alg->entry, &hash_handle->hash_list);
+		}
+
+		if (hw_mode == DRV_CIPHER_XCBC_MAC ||
+		    hw_mode == DRV_CIPHER_CMAC)
+			continue;
+
+		/* register hash version */
+		t_alg = cc_alloc_hash_alg(&driver_hash[alg], dev, false);
+		if (IS_ERR(t_alg)) {
+			rc = PTR_ERR(t_alg);
+			dev_err(dev, "%s alg allocation failed\n",
+				driver_hash[alg].driver_name);
+			goto fail;
+		}
+		t_alg->drvdata = drvdata;
+
+		rc = crypto_register_ahash(&t_alg->ahash_alg);
+		if (rc) {
+			dev_err(dev, "%s alg registration failed\n",
+				driver_hash[alg].driver_name);
+			kfree(t_alg);
+			goto fail;
+		} else {
+			list_add_tail(&t_alg->entry, &hash_handle->hash_list);
+		}
+	}
+
+	return 0;
+
+fail:
+	kfree(drvdata->hash_handle);
+	drvdata->hash_handle = NULL;
+	return rc;
+}
+
+int cc_hash_free(struct cc_drvdata *drvdata)
+{
+	struct cc_hash_alg *t_hash_alg, *hash_n;
+	struct cc_hash_handle *hash_handle = drvdata->hash_handle;
+
+	if (hash_handle) {
+		list_for_each_entry_safe(t_hash_alg, hash_n,
+					 &hash_handle->hash_list, entry) {
+			crypto_unregister_ahash(&t_hash_alg->ahash_alg);
+			list_del(&t_hash_alg->entry);
+			kfree(t_hash_alg);
+		}
+
+		kfree(hash_handle);
+		drvdata->hash_handle = NULL;
+	}
+	return 0;
+}
+
+static void cc_setup_xcbc(struct ahash_request *areq, struct cc_hw_desc desc[],
+			  unsigned int *seq_size)
+{
+	unsigned int idx = *seq_size;
+	struct ahash_req_ctx *state = ahash_request_ctx(areq);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	/* Setup XCBC MAC K1 */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, (ctx->opad_tmp_keys_dma_addr +
+					    XCBC_MAC_K1_OFFSET),
+		     CC_AES_128_BIT_KEY_SIZE, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* Setup XCBC MAC K2 */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K2_OFFSET),
+		     CC_AES_128_BIT_KEY_SIZE, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE1);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* Setup XCBC MAC K3 */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI,
+		     (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K3_OFFSET),
+		     CC_AES_128_BIT_KEY_SIZE, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE2);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* Loading MAC state */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr,
+		     CC_AES_BLOCK_SIZE, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+	*seq_size = idx;
+}
+
+static void cc_setup_cmac(struct ahash_request *areq, struct cc_hw_desc desc[],
+			  unsigned int *seq_size)
+{
+	unsigned int idx = *seq_size;
+	struct ahash_req_ctx *state = ahash_request_ctx(areq);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	/* Setup CMAC Key */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, ctx->opad_tmp_keys_dma_addr,
+		     ((ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE :
+		      ctx->key_params.keylen), NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], ctx->key_params.keylen);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+
+	/* Load MAC state */
+	hw_desc_init(&desc[idx]);
+	set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr,
+		     CC_AES_BLOCK_SIZE, NS_BIT);
+	set_setup_mode(&desc[idx], SETUP_LOAD_STATE0);
+	set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC);
+	set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_key_size_aes(&desc[idx], ctx->key_params.keylen);
+	set_flow_mode(&desc[idx], S_DIN_to_AES);
+	idx++;
+	*seq_size = idx;
+}
+
+static void cc_set_desc(struct ahash_req_ctx *areq_ctx,
+			struct cc_hash_ctx *ctx, unsigned int flow_mode,
+			struct cc_hw_desc desc[], bool is_not_last_data,
+			unsigned int *seq_size)
+{
+	unsigned int idx = *seq_size;
+	struct device *dev = drvdata_to_dev(ctx->drvdata);
+
+	if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_DLLI) {
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     sg_dma_address(areq_ctx->curr_sg),
+			     areq_ctx->curr_sg->length, NS_BIT);
+		set_flow_mode(&desc[idx], flow_mode);
+		idx++;
+	} else {
+		if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_NULL) {
+			dev_dbg(dev, " NULL mode\n");
+			/* nothing to build */
+			return;
+		}
+		/* bypass */
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_DLLI,
+			     areq_ctx->mlli_params.mlli_dma_addr,
+			     areq_ctx->mlli_params.mlli_len, NS_BIT);
+		set_dout_sram(&desc[idx], ctx->drvdata->mlli_sram_addr,
+			      areq_ctx->mlli_params.mlli_len);
+		set_flow_mode(&desc[idx], BYPASS);
+		idx++;
+		/* process */
+		hw_desc_init(&desc[idx]);
+		set_din_type(&desc[idx], DMA_MLLI,
+			     ctx->drvdata->mlli_sram_addr,
+			     areq_ctx->mlli_nents, NS_BIT);
+		set_flow_mode(&desc[idx], flow_mode);
+		idx++;
+	}
+	if (is_not_last_data)
+		set_din_not_last_indication(&desc[(idx - 1)]);
+	/* return updated desc sequence size */
+	*seq_size = idx;
+}
+
+static const void *cc_larval_digest(struct device *dev, u32 mode)
+{
+	switch (mode) {
+	case DRV_HASH_MD5:
+		return md5_init;
+	case DRV_HASH_SHA1:
+		return sha1_init;
+	case DRV_HASH_SHA224:
+		return sha224_init;
+	case DRV_HASH_SHA256:
+		return sha256_init;
+#if (CC_DEV_SHA_MAX > 256)
+	case DRV_HASH_SHA384:
+		return sha384_init;
+	case DRV_HASH_SHA512:
+		return sha512_init;
+#endif
+	default:
+		dev_err(dev, "Invalid hash mode (%d)\n", mode);
+		return md5_init;
+	}
+}
+
+/*!
+ * Gets the address of the initial digest in SRAM
+ * according to the given hash mode
+ *
+ * \param drvdata
+ * \param mode The Hash mode. Supported modes: MD5/SHA1/SHA224/SHA256
+ *
+ * \return u32 The address of the initial digest in SRAM
+ */
+cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode)
+{
+	struct cc_drvdata *_drvdata = (struct cc_drvdata *)drvdata;
+	struct cc_hash_handle *hash_handle = _drvdata->hash_handle;
+	struct device *dev = drvdata_to_dev(_drvdata);
+
+	switch (mode) {
+	case DRV_HASH_NULL:
+		break; /*Ignore*/
+	case DRV_HASH_MD5:
+		return (hash_handle->larval_digest_sram_addr);
+	case DRV_HASH_SHA1:
+		return (hash_handle->larval_digest_sram_addr +
+			sizeof(md5_init));
+	case DRV_HASH_SHA224:
+		return (hash_handle->larval_digest_sram_addr +
+			sizeof(md5_init) +
+			sizeof(sha1_init));
+	case DRV_HASH_SHA256:
+		return (hash_handle->larval_digest_sram_addr +
+			sizeof(md5_init) +
+			sizeof(sha1_init) +
+			sizeof(sha224_init));
+#if (CC_DEV_SHA_MAX > 256)
+	case DRV_HASH_SHA384:
+		return (hash_handle->larval_digest_sram_addr +
+			sizeof(md5_init) +
+			sizeof(sha1_init) +
+			sizeof(sha224_init) +
+			sizeof(sha256_init));
+	case DRV_HASH_SHA512:
+		return (hash_handle->larval_digest_sram_addr +
+			sizeof(md5_init) +
+			sizeof(sha1_init) +
+			sizeof(sha224_init) +
+			sizeof(sha256_init) +
+			sizeof(sha384_init));
+#endif
+	default:
+		dev_err(dev, "Invalid hash mode (%d)\n", mode);
+	}
+
+	/*This is valid wrong value to avoid kernel crash*/
+	return hash_handle->larval_digest_sram_addr;
+}
+
+cc_sram_addr_t
+cc_digest_len_addr(void *drvdata, u32 mode)
+{
+	struct cc_drvdata *_drvdata = (struct cc_drvdata *)drvdata;
+	struct cc_hash_handle *hash_handle = _drvdata->hash_handle;
+	cc_sram_addr_t digest_len_addr = hash_handle->digest_len_sram_addr;
+
+	switch (mode) {
+	case DRV_HASH_SHA1:
+	case DRV_HASH_SHA224:
+	case DRV_HASH_SHA256:
+	case DRV_HASH_MD5:
+		return digest_len_addr;
+#if (CC_DEV_SHA_MAX > 256)
+	case DRV_HASH_SHA384:
+	case DRV_HASH_SHA512:
+		return  digest_len_addr + sizeof(digest_len_init);
+#endif
+	default:
+		return digest_len_addr; /*to avoid kernel crash*/
+	}
+}
diff --git a/drivers/crypto/ccree/cc_hash.h b/drivers/crypto/ccree/cc_hash.h
new file mode 100644
index 000000000000..a444710d8f08
--- /dev/null
+++ b/drivers/crypto/ccree/cc_hash.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_hash.h
+ * ARM CryptoCell Hash Crypto API
+ */
+
+#ifndef __CC_HASH_H__
+#define __CC_HASH_H__
+
+#include "cc_buffer_mgr.h"
+
+#define HMAC_IPAD_CONST	0x36363636
+#define HMAC_OPAD_CONST	0x5C5C5C5C
+#if (CC_DEV_SHA_MAX > 256)
+#define HASH_LEN_SIZE 16
+#define CC_MAX_HASH_DIGEST_SIZE	SHA512_DIGEST_SIZE
+#define CC_MAX_HASH_BLCK_SIZE SHA512_BLOCK_SIZE
+#else
+#define HASH_LEN_SIZE 8
+#define CC_MAX_HASH_DIGEST_SIZE	SHA256_DIGEST_SIZE
+#define CC_MAX_HASH_BLCK_SIZE SHA256_BLOCK_SIZE
+#endif
+
+#define XCBC_MAC_K1_OFFSET 0
+#define XCBC_MAC_K2_OFFSET 16
+#define XCBC_MAC_K3_OFFSET 32
+
+#define CC_EXPORT_MAGIC 0xC2EE1070U
+
+/* this struct was taken from drivers/crypto/nx/nx-aes-xcbc.c and it is used
+ * for xcbc/cmac statesize
+ */
+struct aeshash_state {
+	u8 state[AES_BLOCK_SIZE];
+	unsigned int count;
+	u8 buffer[AES_BLOCK_SIZE];
+};
+
+/* ahash state */
+struct ahash_req_ctx {
+	u8 buffers[2][CC_MAX_HASH_BLCK_SIZE] ____cacheline_aligned;
+	u8 digest_result_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
+	u8 digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
+	u8 opad_digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
+	u8 digest_bytes_len[HASH_LEN_SIZE] ____cacheline_aligned;
+	struct async_gen_req_ctx gen_ctx ____cacheline_aligned;
+	enum cc_req_dma_buf_type data_dma_buf_type;
+	dma_addr_t opad_digest_dma_addr;
+	dma_addr_t digest_buff_dma_addr;
+	dma_addr_t digest_bytes_len_dma_addr;
+	dma_addr_t digest_result_dma_addr;
+	u32 buf_cnt[2];
+	u32 buff_index;
+	u32 xcbc_count; /* count xcbc update operatations */
+	struct scatterlist buff_sg[2];
+	struct scatterlist *curr_sg;
+	u32 in_nents;
+	u32 mlli_nents;
+	struct mlli_params mlli_params;
+};
+
+static inline u32 *cc_hash_buf_cnt(struct ahash_req_ctx *state)
+{
+	return &state->buf_cnt[state->buff_index];
+}
+
+static inline u8 *cc_hash_buf(struct ahash_req_ctx *state)
+{
+	return state->buffers[state->buff_index];
+}
+
+static inline u32 *cc_next_buf_cnt(struct ahash_req_ctx *state)
+{
+	return &state->buf_cnt[state->buff_index ^ 1];
+}
+
+static inline u8 *cc_next_buf(struct ahash_req_ctx *state)
+{
+	return state->buffers[state->buff_index ^ 1];
+}
+
+int cc_hash_alloc(struct cc_drvdata *drvdata);
+int cc_init_hash_sram(struct cc_drvdata *drvdata);
+int cc_hash_free(struct cc_drvdata *drvdata);
+
+/*!
+ * Gets the initial digest length
+ *
+ * \param drvdata
+ * \param mode The Hash mode. Supported modes:
+ *             MD5/SHA1/SHA224/SHA256/SHA384/SHA512
+ *
+ * \return u32 returns the address of the initial digest length in SRAM
+ */
+cc_sram_addr_t
+cc_digest_len_addr(void *drvdata, u32 mode);
+
+/*!
+ * Gets the address of the initial digest in SRAM
+ * according to the given hash mode
+ *
+ * \param drvdata
+ * \param mode The Hash mode. Supported modes:
+ *             MD5/SHA1/SHA224/SHA256/SHA384/SHA512
+ *
+ * \return u32 The address of the initial digest in SRAM
+ */
+cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode);
+
+void cc_hash_global_init(void);
+
+#endif /*__CC_HASH_H__*/
diff --git a/drivers/crypto/ccree/cc_host_regs.h b/drivers/crypto/ccree/cc_host_regs.h
new file mode 100644
index 000000000000..69ef2fa0cb9b
--- /dev/null
+++ b/drivers/crypto/ccree/cc_host_regs.h
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_HOST_H__
+#define __CC_HOST_H__
+
+// --------------------------------------
+// BLOCK: HOST_P
+// --------------------------------------
+#define CC_HOST_IRR_REG_OFFSET	0xA00UL
+#define CC_HOST_IRR_DSCRPTR_COMPLETION_LOW_INT_BIT_SHIFT	0x2UL
+#define CC_HOST_IRR_DSCRPTR_COMPLETION_LOW_INT_BIT_SIZE	0x1UL
+#define CC_HOST_IRR_AXI_ERR_INT_BIT_SHIFT	0x8UL
+#define CC_HOST_IRR_AXI_ERR_INT_BIT_SIZE	0x1UL
+#define CC_HOST_IRR_GPR0_BIT_SHIFT	0xBUL
+#define CC_HOST_IRR_GPR0_BIT_SIZE	0x1UL
+#define CC_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SHIFT	0x13UL
+#define CC_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SIZE	0x1UL
+#define CC_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT	0x17UL
+#define CC_HOST_IRR_AXIM_COMP_INT_BIT_SIZE	0x1UL
+#define CC_HOST_IMR_REG_OFFSET	0xA04UL
+#define CC_HOST_IMR_NOT_USED_MASK_BIT_SHIFT	0x1UL
+#define CC_HOST_IMR_NOT_USED_MASK_BIT_SIZE	0x1UL
+#define CC_HOST_IMR_DSCRPTR_COMPLETION_MASK_BIT_SHIFT	0x2UL
+#define CC_HOST_IMR_DSCRPTR_COMPLETION_MASK_BIT_SIZE	0x1UL
+#define CC_HOST_IMR_AXI_ERR_MASK_BIT_SHIFT	0x8UL
+#define CC_HOST_IMR_AXI_ERR_MASK_BIT_SIZE	0x1UL
+#define CC_HOST_IMR_GPR0_BIT_SHIFT	0xBUL
+#define CC_HOST_IMR_GPR0_BIT_SIZE	0x1UL
+#define CC_HOST_IMR_DSCRPTR_WATERMARK_MASK0_BIT_SHIFT	0x13UL
+#define CC_HOST_IMR_DSCRPTR_WATERMARK_MASK0_BIT_SIZE	0x1UL
+#define CC_HOST_IMR_AXIM_COMP_INT_MASK_BIT_SHIFT	0x17UL
+#define CC_HOST_IMR_AXIM_COMP_INT_MASK_BIT_SIZE	0x1UL
+#define CC_HOST_ICR_REG_OFFSET	0xA08UL
+#define CC_HOST_ICR_DSCRPTR_COMPLETION_BIT_SHIFT	0x2UL
+#define CC_HOST_ICR_DSCRPTR_COMPLETION_BIT_SIZE	0x1UL
+#define CC_HOST_ICR_AXI_ERR_CLEAR_BIT_SHIFT	0x8UL
+#define CC_HOST_ICR_AXI_ERR_CLEAR_BIT_SIZE	0x1UL
+#define CC_HOST_ICR_GPR_INT_CLEAR_BIT_SHIFT	0xBUL
+#define CC_HOST_ICR_GPR_INT_CLEAR_BIT_SIZE	0x1UL
+#define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SHIFT	0x13UL
+#define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SIZE	0x1UL
+#define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SHIFT	0x17UL
+#define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SIZE	0x1UL
+#define CC_HOST_SIGNATURE_REG_OFFSET	0xA24UL
+#define CC_HOST_SIGNATURE_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_SIGNATURE_VALUE_BIT_SIZE	0x20UL
+#define CC_HOST_BOOT_REG_OFFSET	0xA28UL
+#define CC_HOST_BOOT_SYNTHESIS_CONFIG_BIT_SHIFT	0x0UL
+#define CC_HOST_BOOT_SYNTHESIS_CONFIG_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_LARGE_RKEK_LOCAL_BIT_SHIFT	0x1UL
+#define CC_HOST_BOOT_LARGE_RKEK_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_HASH_IN_FUSES_LOCAL_BIT_SHIFT	0x2UL
+#define CC_HOST_BOOT_HASH_IN_FUSES_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_EXT_MEM_SECURED_LOCAL_BIT_SHIFT	0x3UL
+#define CC_HOST_BOOT_EXT_MEM_SECURED_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_RKEK_ECC_EXISTS_LOCAL_N_BIT_SHIFT	0x5UL
+#define CC_HOST_BOOT_RKEK_ECC_EXISTS_LOCAL_N_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_SRAM_SIZE_LOCAL_BIT_SHIFT	0x6UL
+#define CC_HOST_BOOT_SRAM_SIZE_LOCAL_BIT_SIZE	0x3UL
+#define CC_HOST_BOOT_DSCRPTR_EXISTS_LOCAL_BIT_SHIFT	0x9UL
+#define CC_HOST_BOOT_DSCRPTR_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_PAU_EXISTS_LOCAL_BIT_SHIFT	0xAUL
+#define CC_HOST_BOOT_PAU_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_RNG_EXISTS_LOCAL_BIT_SHIFT	0xBUL
+#define CC_HOST_BOOT_RNG_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_PKA_EXISTS_LOCAL_BIT_SHIFT	0xCUL
+#define CC_HOST_BOOT_PKA_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_RC4_EXISTS_LOCAL_BIT_SHIFT	0xDUL
+#define CC_HOST_BOOT_RC4_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_SHA_512_PRSNT_LOCAL_BIT_SHIFT	0xEUL
+#define CC_HOST_BOOT_SHA_512_PRSNT_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_SHA_256_PRSNT_LOCAL_BIT_SHIFT	0xFUL
+#define CC_HOST_BOOT_SHA_256_PRSNT_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_MD5_PRSNT_LOCAL_BIT_SHIFT	0x10UL
+#define CC_HOST_BOOT_MD5_PRSNT_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_HASH_EXISTS_LOCAL_BIT_SHIFT	0x11UL
+#define CC_HOST_BOOT_HASH_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_C2_EXISTS_LOCAL_BIT_SHIFT	0x12UL
+#define CC_HOST_BOOT_C2_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_DES_EXISTS_LOCAL_BIT_SHIFT	0x13UL
+#define CC_HOST_BOOT_DES_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_XCBC_MAC_EXISTS_LOCAL_BIT_SHIFT	0x14UL
+#define CC_HOST_BOOT_AES_XCBC_MAC_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_CMAC_EXISTS_LOCAL_BIT_SHIFT	0x15UL
+#define CC_HOST_BOOT_AES_CMAC_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_CCM_EXISTS_LOCAL_BIT_SHIFT	0x16UL
+#define CC_HOST_BOOT_AES_CCM_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_XEX_HW_T_CALC_LOCAL_BIT_SHIFT	0x17UL
+#define CC_HOST_BOOT_AES_XEX_HW_T_CALC_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_XEX_EXISTS_LOCAL_BIT_SHIFT	0x18UL
+#define CC_HOST_BOOT_AES_XEX_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_CTR_EXISTS_LOCAL_BIT_SHIFT	0x19UL
+#define CC_HOST_BOOT_CTR_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_DIN_BYTE_RESOLUTION_LOCAL_BIT_SHIFT	0x1AUL
+#define CC_HOST_BOOT_AES_DIN_BYTE_RESOLUTION_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_TUNNELING_ENB_LOCAL_BIT_SHIFT	0x1BUL
+#define CC_HOST_BOOT_TUNNELING_ENB_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_SUPPORT_256_192_KEY_LOCAL_BIT_SHIFT	0x1CUL
+#define CC_HOST_BOOT_SUPPORT_256_192_KEY_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SHIFT	0x1DUL
+#define CC_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SHIFT	0x1EUL
+#define CC_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SIZE	0x1UL
+#define CC_HOST_VERSION_REG_OFFSET	0xA40UL
+#define CC_HOST_VERSION_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_VERSION_VALUE_BIT_SIZE	0x20UL
+#define CC_HOST_KFDE0_VALID_REG_OFFSET	0xA60UL
+#define CC_HOST_KFDE0_VALID_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_KFDE0_VALID_VALUE_BIT_SIZE	0x1UL
+#define CC_HOST_KFDE1_VALID_REG_OFFSET	0xA64UL
+#define CC_HOST_KFDE1_VALID_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_KFDE1_VALID_VALUE_BIT_SIZE	0x1UL
+#define CC_HOST_KFDE2_VALID_REG_OFFSET	0xA68UL
+#define CC_HOST_KFDE2_VALID_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_KFDE2_VALID_VALUE_BIT_SIZE	0x1UL
+#define CC_HOST_KFDE3_VALID_REG_OFFSET	0xA6CUL
+#define CC_HOST_KFDE3_VALID_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_KFDE3_VALID_VALUE_BIT_SIZE	0x1UL
+#define CC_HOST_GPR0_REG_OFFSET	0xA70UL
+#define CC_HOST_GPR0_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_GPR0_VALUE_BIT_SIZE	0x20UL
+#define CC_GPR_HOST_REG_OFFSET	0xA74UL
+#define CC_GPR_HOST_VALUE_BIT_SHIFT	0x0UL
+#define CC_GPR_HOST_VALUE_BIT_SIZE	0x20UL
+#define CC_HOST_POWER_DOWN_EN_REG_OFFSET	0xA78UL
+#define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SHIFT	0x0UL
+#define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SIZE	0x1UL
+// --------------------------------------
+// BLOCK: HOST_SRAM
+// --------------------------------------
+#define CC_SRAM_DATA_REG_OFFSET	0xF00UL
+#define CC_SRAM_DATA_VALUE_BIT_SHIFT	0x0UL
+#define CC_SRAM_DATA_VALUE_BIT_SIZE	0x20UL
+#define CC_SRAM_ADDR_REG_OFFSET	0xF04UL
+#define CC_SRAM_ADDR_VALUE_BIT_SHIFT	0x0UL
+#define CC_SRAM_ADDR_VALUE_BIT_SIZE	0xFUL
+#define CC_SRAM_DATA_READY_REG_OFFSET	0xF08UL
+#define CC_SRAM_DATA_READY_VALUE_BIT_SHIFT	0x0UL
+#define CC_SRAM_DATA_READY_VALUE_BIT_SIZE	0x1UL
+
+#endif //__CC_HOST_H__
diff --git a/drivers/crypto/ccree/cc_hw_queue_defs.h b/drivers/crypto/ccree/cc_hw_queue_defs.h
new file mode 100644
index 000000000000..a79f28cec5ae
--- /dev/null
+++ b/drivers/crypto/ccree/cc_hw_queue_defs.h
@@ -0,0 +1,590 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_HW_QUEUE_DEFS_H__
+#define __CC_HW_QUEUE_DEFS_H__
+
+#include <linux/types.h>
+
+#include "cc_kernel_regs.h"
+#include <linux/bitfield.h>
+
+/******************************************************************************
+ *				DEFINITIONS
+ ******************************************************************************/
+
+#define HW_DESC_SIZE_WORDS		6
+/* Define max. available slots in HW queue */
+#define HW_QUEUE_SLOTS_MAX              15
+
+#define CC_REG_LOW(word, name)  \
+	(CC_DSCRPTR_QUEUE_WORD ## word ## _ ## name ## _BIT_SHIFT)
+
+#define CC_REG_HIGH(word, name) \
+	(CC_REG_LOW(word, name) + \
+	 CC_DSCRPTR_QUEUE_WORD ## word ## _ ## name ## _BIT_SIZE - 1)
+
+#define CC_GENMASK(word, name) \
+	GENMASK(CC_REG_HIGH(word, name), CC_REG_LOW(word, name))
+
+#define WORD0_VALUE		CC_GENMASK(0, VALUE)
+#define WORD1_DIN_CONST_VALUE	CC_GENMASK(1, DIN_CONST_VALUE)
+#define WORD1_DIN_DMA_MODE	CC_GENMASK(1, DIN_DMA_MODE)
+#define WORD1_DIN_SIZE		CC_GENMASK(1, DIN_SIZE)
+#define WORD1_NOT_LAST		CC_GENMASK(1, NOT_LAST)
+#define WORD1_NS_BIT		CC_GENMASK(1, NS_BIT)
+#define WORD2_VALUE		CC_GENMASK(2, VALUE)
+#define WORD3_DOUT_DMA_MODE	CC_GENMASK(3, DOUT_DMA_MODE)
+#define WORD3_DOUT_LAST_IND	CC_GENMASK(3, DOUT_LAST_IND)
+#define WORD3_DOUT_SIZE		CC_GENMASK(3, DOUT_SIZE)
+#define WORD3_HASH_XOR_BIT	CC_GENMASK(3, HASH_XOR_BIT)
+#define WORD3_NS_BIT		CC_GENMASK(3, NS_BIT)
+#define WORD3_QUEUE_LAST_IND	CC_GENMASK(3, QUEUE_LAST_IND)
+#define WORD4_ACK_NEEDED	CC_GENMASK(4, ACK_NEEDED)
+#define WORD4_AES_SEL_N_HASH	CC_GENMASK(4, AES_SEL_N_HASH)
+#define WORD4_BYTES_SWAP	CC_GENMASK(4, BYTES_SWAP)
+#define WORD4_CIPHER_CONF0	CC_GENMASK(4, CIPHER_CONF0)
+#define WORD4_CIPHER_CONF1	CC_GENMASK(4, CIPHER_CONF1)
+#define WORD4_CIPHER_CONF2	CC_GENMASK(4, CIPHER_CONF2)
+#define WORD4_CIPHER_DO		CC_GENMASK(4, CIPHER_DO)
+#define WORD4_CIPHER_MODE	CC_GENMASK(4, CIPHER_MODE)
+#define WORD4_CMAC_SIZE0	CC_GENMASK(4, CMAC_SIZE0)
+#define WORD4_DATA_FLOW_MODE	CC_GENMASK(4, DATA_FLOW_MODE)
+#define WORD4_KEY_SIZE		CC_GENMASK(4, KEY_SIZE)
+#define WORD4_SETUP_OPERATION	CC_GENMASK(4, SETUP_OPERATION)
+#define WORD5_DIN_ADDR_HIGH	CC_GENMASK(5, DIN_ADDR_HIGH)
+#define WORD5_DOUT_ADDR_HIGH	CC_GENMASK(5, DOUT_ADDR_HIGH)
+
+/******************************************************************************
+ *				TYPE DEFINITIONS
+ ******************************************************************************/
+
+struct cc_hw_desc {
+	union {
+		u32 word[HW_DESC_SIZE_WORDS];
+		u16 hword[HW_DESC_SIZE_WORDS * 2];
+	};
+};
+
+enum cc_axi_sec {
+	AXI_SECURE = 0,
+	AXI_NOT_SECURE = 1
+};
+
+enum cc_desc_direction {
+	DESC_DIRECTION_ILLEGAL = -1,
+	DESC_DIRECTION_ENCRYPT_ENCRYPT = 0,
+	DESC_DIRECTION_DECRYPT_DECRYPT = 1,
+	DESC_DIRECTION_DECRYPT_ENCRYPT = 3,
+	DESC_DIRECTION_END = S32_MAX,
+};
+
+enum cc_dma_mode {
+	DMA_MODE_NULL		= -1,
+	NO_DMA			= 0,
+	DMA_SRAM		= 1,
+	DMA_DLLI		= 2,
+	DMA_MLLI		= 3,
+	DMA_MODE_END		= S32_MAX,
+};
+
+enum cc_flow_mode {
+	FLOW_MODE_NULL		= -1,
+	/* data flows */
+	BYPASS			= 0,
+	DIN_AES_DOUT		= 1,
+	AES_to_HASH		= 2,
+	AES_and_HASH		= 3,
+	DIN_DES_DOUT		= 4,
+	DES_to_HASH		= 5,
+	DES_and_HASH		= 6,
+	DIN_HASH		= 7,
+	DIN_HASH_and_BYPASS	= 8,
+	AESMAC_and_BYPASS	= 9,
+	AES_to_HASH_and_DOUT	= 10,
+	DIN_RC4_DOUT		= 11,
+	DES_to_HASH_and_DOUT	= 12,
+	AES_to_AES_to_HASH_and_DOUT	= 13,
+	AES_to_AES_to_HASH	= 14,
+	AES_to_HASH_and_AES	= 15,
+	DIN_AES_AESMAC		= 17,
+	HASH_to_DOUT		= 18,
+	/* setup flows */
+	S_DIN_to_AES		= 32,
+	S_DIN_to_AES2		= 33,
+	S_DIN_to_DES		= 34,
+	S_DIN_to_RC4		= 35,
+	S_DIN_to_HASH		= 37,
+	S_AES_to_DOUT		= 38,
+	S_AES2_to_DOUT		= 39,
+	S_RC4_to_DOUT		= 41,
+	S_DES_to_DOUT		= 42,
+	S_HASH_to_DOUT		= 43,
+	SET_FLOW_ID		= 44,
+	FLOW_MODE_END = S32_MAX,
+};
+
+enum cc_tunnel_op {
+	TUNNEL_OP_INVALID = -1,
+	TUNNEL_OFF = 0,
+	TUNNEL_ON = 1,
+	TUNNEL_OP_END = S32_MAX,
+};
+
+enum cc_setup_op {
+	SETUP_LOAD_NOP		= 0,
+	SETUP_LOAD_STATE0	= 1,
+	SETUP_LOAD_STATE1	= 2,
+	SETUP_LOAD_STATE2	= 3,
+	SETUP_LOAD_KEY0		= 4,
+	SETUP_LOAD_XEX_KEY	= 5,
+	SETUP_WRITE_STATE0	= 8,
+	SETUP_WRITE_STATE1	= 9,
+	SETUP_WRITE_STATE2	= 10,
+	SETUP_WRITE_STATE3	= 11,
+	SETUP_OP_END = S32_MAX,
+};
+
+enum cc_aes_mac_selector {
+	AES_SK = 1,
+	AES_CMAC_INIT = 2,
+	AES_CMAC_SIZE0 = 3,
+	AES_MAC_END = S32_MAX,
+};
+
+#define HW_KEY_MASK_CIPHER_DO	  0x3
+#define HW_KEY_SHIFT_CIPHER_CFG2  2
+
+/* HwCryptoKey[1:0] is mapped to cipher_do[1:0] */
+/* HwCryptoKey[2:3] is mapped to cipher_config2[1:0] */
+enum cc_hw_crypto_key {
+	USER_KEY = 0,			/* 0x0000 */
+	ROOT_KEY = 1,			/* 0x0001 */
+	PROVISIONING_KEY = 2,		/* 0x0010 */ /* ==KCP */
+	SESSION_KEY = 3,		/* 0x0011 */
+	RESERVED_KEY = 4,		/* NA */
+	PLATFORM_KEY = 5,		/* 0x0101 */
+	CUSTOMER_KEY = 6,		/* 0x0110 */
+	KFDE0_KEY = 7,			/* 0x0111 */
+	KFDE1_KEY = 9,			/* 0x1001 */
+	KFDE2_KEY = 10,			/* 0x1010 */
+	KFDE3_KEY = 11,			/* 0x1011 */
+	END_OF_KEYS = S32_MAX,
+};
+
+enum cc_hw_aes_key_size {
+	AES_128_KEY = 0,
+	AES_192_KEY = 1,
+	AES_256_KEY = 2,
+	END_OF_AES_KEYS = S32_MAX,
+};
+
+enum cc_hw_des_key_size {
+	DES_ONE_KEY = 0,
+	DES_TWO_KEYS = 1,
+	DES_THREE_KEYS = 2,
+	END_OF_DES_KEYS = S32_MAX,
+};
+
+enum cc_hash_conf_pad {
+	HASH_PADDING_DISABLED = 0,
+	HASH_PADDING_ENABLED = 1,
+	HASH_DIGEST_RESULT_LITTLE_ENDIAN = 2,
+	HASH_CONFIG1_PADDING_RESERVE32 = S32_MAX,
+};
+
+enum cc_hash_cipher_pad {
+	DO_NOT_PAD = 0,
+	DO_PAD = 1,
+	HASH_CIPHER_DO_PADDING_RESERVE32 = S32_MAX,
+};
+
+/*****************************/
+/* Descriptor packing macros */
+/*****************************/
+
+/*
+ * Init a HW descriptor struct
+ * @pdesc: pointer HW descriptor struct
+ */
+static inline void hw_desc_init(struct cc_hw_desc *pdesc)
+{
+	memset(pdesc, 0, sizeof(struct cc_hw_desc));
+}
+
+/*
+ * Indicates the end of current HW descriptors flow and release the HW engines.
+ *
+ * @pdesc: pointer HW descriptor struct
+ */
+static inline void set_queue_last_ind(struct cc_hw_desc *pdesc)
+{
+	pdesc->word[3] |= FIELD_PREP(WORD3_QUEUE_LAST_IND, 1);
+}
+
+/*
+ * Set the DIN field of a HW descriptors
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @dma_mode: dmaMode The DMA mode: NO_DMA, SRAM, DLLI, MLLI, CONSTANT
+ * @addr: dinAdr DIN address
+ * @size: Data size in bytes
+ * @axi_sec: AXI secure bit
+ */
+static inline void set_din_type(struct cc_hw_desc *pdesc,
+				enum cc_dma_mode dma_mode, dma_addr_t addr,
+				u32 size, enum cc_axi_sec axi_sec)
+{
+	pdesc->word[0] = (u32)addr;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+	pdesc->word[5] |= FIELD_PREP(WORD5_DIN_ADDR_HIGH, ((u16)(addr >> 32)));
+#endif
+	pdesc->word[1] |= FIELD_PREP(WORD1_DIN_DMA_MODE, dma_mode) |
+				FIELD_PREP(WORD1_DIN_SIZE, size) |
+				FIELD_PREP(WORD1_NS_BIT, axi_sec);
+}
+
+/*
+ * Set the DIN field of a HW descriptors to NO DMA mode.
+ * Used for NOP descriptor, register patches and other special modes.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @addr: DIN address
+ * @size: Data size in bytes
+ */
+static inline void set_din_no_dma(struct cc_hw_desc *pdesc, u32 addr, u32 size)
+{
+	pdesc->word[0] = addr;
+	pdesc->word[1] |= FIELD_PREP(WORD1_DIN_SIZE, size);
+}
+
+/*
+ * Set the DIN field of a HW descriptors to SRAM mode.
+ * Note: No need to check SRAM alignment since host requests do not use SRAM and
+ * adaptor will enforce alignment check.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @addr: DIN address
+ * @size Data size in bytes
+ */
+static inline void set_din_sram(struct cc_hw_desc *pdesc, dma_addr_t addr,
+				u32 size)
+{
+	pdesc->word[0] = (u32)addr;
+	pdesc->word[1] |= FIELD_PREP(WORD1_DIN_SIZE, size) |
+				FIELD_PREP(WORD1_DIN_DMA_MODE, DMA_SRAM);
+}
+
+/*
+ * Set the DIN field of a HW descriptors to CONST mode
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @val: DIN const value
+ * @size: Data size in bytes
+ */
+static inline void set_din_const(struct cc_hw_desc *pdesc, u32 val, u32 size)
+{
+	pdesc->word[0] = val;
+	pdesc->word[1] |= FIELD_PREP(WORD1_DIN_CONST_VALUE, 1) |
+			FIELD_PREP(WORD1_DIN_DMA_MODE, DMA_SRAM) |
+			FIELD_PREP(WORD1_DIN_SIZE, size);
+}
+
+/*
+ * Set the DIN not last input data indicator
+ *
+ * @pdesc: pointer HW descriptor struct
+ */
+static inline void set_din_not_last_indication(struct cc_hw_desc *pdesc)
+{
+	pdesc->word[1] |= FIELD_PREP(WORD1_NOT_LAST, 1);
+}
+
+/*
+ * Set the DOUT field of a HW descriptors
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @dma_mode: The DMA mode: NO_DMA, SRAM, DLLI, MLLI, CONSTANT
+ * @addr: DOUT address
+ * @size: Data size in bytes
+ * @axi_sec: AXI secure bit
+ */
+static inline void set_dout_type(struct cc_hw_desc *pdesc,
+				 enum cc_dma_mode dma_mode, dma_addr_t addr,
+				 u32 size, enum cc_axi_sec axi_sec)
+{
+	pdesc->word[2] = (u32)addr;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+	pdesc->word[5] |= FIELD_PREP(WORD5_DOUT_ADDR_HIGH, ((u16)(addr >> 32)));
+#endif
+	pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_DMA_MODE, dma_mode) |
+				FIELD_PREP(WORD3_DOUT_SIZE, size) |
+				FIELD_PREP(WORD3_NS_BIT, axi_sec);
+}
+
+/*
+ * Set the DOUT field of a HW descriptors to DLLI type
+ * The LAST INDICATION is provided by the user
+ *
+ * @pdesc pointer HW descriptor struct
+ * @addr: DOUT address
+ * @size: Data size in bytes
+ * @last_ind: The last indication bit
+ * @axi_sec: AXI secure bit
+ */
+static inline void set_dout_dlli(struct cc_hw_desc *pdesc, dma_addr_t addr,
+				 u32 size, enum cc_axi_sec axi_sec,
+				 u32 last_ind)
+{
+	set_dout_type(pdesc, DMA_DLLI, addr, size, axi_sec);
+	pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_LAST_IND, last_ind);
+}
+
+/*
+ * Set the DOUT field of a HW descriptors to DLLI type
+ * The LAST INDICATION is provided by the user
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @addr: DOUT address
+ * @size: Data size in bytes
+ * @last_ind: The last indication bit
+ * @axi_sec: AXI secure bit
+ */
+static inline void set_dout_mlli(struct cc_hw_desc *pdesc, dma_addr_t addr,
+				 u32 size, enum cc_axi_sec axi_sec,
+				 bool last_ind)
+{
+	set_dout_type(pdesc, DMA_MLLI, addr, size, axi_sec);
+	pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_LAST_IND, last_ind);
+}
+
+/*
+ * Set the DOUT field of a HW descriptors to NO DMA mode.
+ * Used for NOP descriptor, register patches and other special modes.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @addr: DOUT address
+ * @size: Data size in bytes
+ * @write_enable: Enables a write operation to a register
+ */
+static inline void set_dout_no_dma(struct cc_hw_desc *pdesc, u32 addr,
+				   u32 size, bool write_enable)
+{
+	pdesc->word[2] = addr;
+	pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_SIZE, size) |
+			FIELD_PREP(WORD3_DOUT_LAST_IND, write_enable);
+}
+
+/*
+ * Set the word for the XOR operation.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @val: xor data value
+ */
+static inline void set_xor_val(struct cc_hw_desc *pdesc, u32 val)
+{
+	pdesc->word[2] = val;
+}
+
+/*
+ * Sets the XOR indicator bit in the descriptor
+ *
+ * @pdesc: pointer HW descriptor struct
+ */
+static inline void set_xor_active(struct cc_hw_desc *pdesc)
+{
+	pdesc->word[3] |= FIELD_PREP(WORD3_HASH_XOR_BIT, 1);
+}
+
+/*
+ * Select the AES engine instead of HASH engine when setting up combined mode
+ * with AES XCBC MAC
+ *
+ * @pdesc: pointer HW descriptor struct
+ */
+static inline void set_aes_not_hash_mode(struct cc_hw_desc *pdesc)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_AES_SEL_N_HASH, 1);
+}
+
+/*
+ * Set the DOUT field of a HW descriptors to SRAM mode
+ * Note: No need to check SRAM alignment since host requests do not use SRAM and
+ * adaptor will enforce alignment check.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @addr: DOUT address
+ * @size: Data size in bytes
+ */
+static inline void set_dout_sram(struct cc_hw_desc *pdesc, u32 addr, u32 size)
+{
+	pdesc->word[2] = addr;
+	pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_DMA_MODE, DMA_SRAM) |
+			FIELD_PREP(WORD3_DOUT_SIZE, size);
+}
+
+/*
+ * Sets the data unit size for XEX mode in data_out_addr[15:0]
+ *
+ * @pdesc: pDesc pointer HW descriptor struct
+ * @size: data unit size for XEX mode
+ */
+static inline void set_xex_data_unit_size(struct cc_hw_desc *pdesc, u32 size)
+{
+	pdesc->word[2] = size;
+}
+
+/*
+ * Set the number of rounds for Multi2 in data_out_addr[15:0]
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @num: number of rounds for Multi2
+ */
+static inline void set_multi2_num_rounds(struct cc_hw_desc *pdesc, u32 num)
+{
+	pdesc->word[2] = num;
+}
+
+/*
+ * Set the flow mode.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @mode: Any one of the modes defined in [CC7x-DESC]
+ */
+static inline void set_flow_mode(struct cc_hw_desc *pdesc,
+				 enum cc_flow_mode mode)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_DATA_FLOW_MODE, mode);
+}
+
+/*
+ * Set the cipher mode.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @mode:  Any one of the modes defined in [CC7x-DESC]
+ */
+static inline void set_cipher_mode(struct cc_hw_desc *pdesc,
+				   enum drv_cipher_mode mode)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_MODE, mode);
+}
+
+/*
+ * Set the cipher configuration fields.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @mode: Any one of the modes defined in [CC7x-DESC]
+ */
+static inline void set_cipher_config0(struct cc_hw_desc *pdesc,
+				      enum drv_crypto_direction mode)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_CONF0, mode);
+}
+
+/*
+ * Set the cipher configuration fields.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @config: Any one of the modes defined in [CC7x-DESC]
+ */
+static inline void set_cipher_config1(struct cc_hw_desc *pdesc,
+				      enum cc_hash_conf_pad config)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_CONF1, config);
+}
+
+/*
+ * Set HW key configuration fields.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @hw_key: The HW key slot asdefined in enum cc_hw_crypto_key
+ */
+static inline void set_hw_crypto_key(struct cc_hw_desc *pdesc,
+				     enum cc_hw_crypto_key hw_key)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_DO,
+				     (hw_key & HW_KEY_MASK_CIPHER_DO)) |
+			FIELD_PREP(WORD4_CIPHER_CONF2,
+				   (hw_key >> HW_KEY_SHIFT_CIPHER_CFG2));
+}
+
+/*
+ * Set byte order of all setup-finalize descriptors.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @config: Any one of the modes defined in [CC7x-DESC]
+ */
+static inline void set_bytes_swap(struct cc_hw_desc *pdesc, bool config)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_BYTES_SWAP, config);
+}
+
+/*
+ * Set CMAC_SIZE0 mode.
+ *
+ * @pdesc: pointer HW descriptor struct
+ */
+static inline void set_cmac_size0_mode(struct cc_hw_desc *pdesc)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_CMAC_SIZE0, 1);
+}
+
+/*
+ * Set key size descriptor field.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @size: key size in bytes (NOT size code)
+ */
+static inline void set_key_size(struct cc_hw_desc *pdesc, u32 size)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_KEY_SIZE, size);
+}
+
+/*
+ * Set AES key size.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @size: key size in bytes (NOT size code)
+ */
+static inline void set_key_size_aes(struct cc_hw_desc *pdesc, u32 size)
+{
+	set_key_size(pdesc, ((size >> 3) - 2));
+}
+
+/*
+ * Set DES key size.
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @size: key size in bytes (NOT size code)
+ */
+static inline void set_key_size_des(struct cc_hw_desc *pdesc, u32 size)
+{
+	set_key_size(pdesc, ((size >> 3) - 1));
+}
+
+/*
+ * Set the descriptor setup mode
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @mode: Any one of the setup modes defined in [CC7x-DESC]
+ */
+static inline void set_setup_mode(struct cc_hw_desc *pdesc,
+				  enum cc_setup_op mode)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_SETUP_OPERATION, mode);
+}
+
+/*
+ * Set the descriptor cipher DO
+ *
+ * @pdesc: pointer HW descriptor struct
+ * @config: Any one of the cipher do defined in [CC7x-DESC]
+ */
+static inline void set_cipher_do(struct cc_hw_desc *pdesc,
+				 enum cc_hash_cipher_pad config)
+{
+	pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_DO,
+				(config & HW_KEY_MASK_CIPHER_DO));
+}
+
+#endif /*__CC_HW_QUEUE_DEFS_H__*/
diff --git a/drivers/crypto/ccree/cc_ivgen.c b/drivers/crypto/ccree/cc_ivgen.c
new file mode 100644
index 000000000000..769458323394
--- /dev/null
+++ b/drivers/crypto/ccree/cc_ivgen.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <crypto/ctr.h>
+#include "cc_driver.h"
+#include "cc_ivgen.h"
+#include "cc_request_mgr.h"
+#include "cc_sram_mgr.h"
+#include "cc_buffer_mgr.h"
+
+/* The max. size of pool *MUST* be <= SRAM total size */
+#define CC_IVPOOL_SIZE 1024
+/* The first 32B fraction of pool are dedicated to the
+ * next encryption "key" & "IV" for pool regeneration
+ */
+#define CC_IVPOOL_META_SIZE (CC_AES_IV_SIZE + AES_KEYSIZE_128)
+#define CC_IVPOOL_GEN_SEQ_LEN	4
+
+/**
+ * struct cc_ivgen_ctx -IV pool generation context
+ * @pool:          the start address of the iv-pool resides in internal RAM
+ * @ctr_key_dma:   address of pool's encryption key material in internal RAM
+ * @ctr_iv_dma:    address of pool's counter iv in internal RAM
+ * @next_iv_ofs:   the offset to the next available IV in pool
+ * @pool_meta:     virt. address of the initial enc. key/IV
+ * @pool_meta_dma: phys. address of the initial enc. key/IV
+ */
+struct cc_ivgen_ctx {
+	cc_sram_addr_t pool;
+	cc_sram_addr_t ctr_key;
+	cc_sram_addr_t ctr_iv;
+	u32 next_iv_ofs;
+	u8 *pool_meta;
+	dma_addr_t pool_meta_dma;
+};
+
+/*!
+ * Generates CC_IVPOOL_SIZE of random bytes by
+ * encrypting 0's using AES128-CTR.
+ *
+ * \param ivgen iv-pool context
+ * \param iv_seq IN/OUT array to the descriptors sequence
+ * \param iv_seq_len IN/OUT pointer to the sequence length
+ */
+static int cc_gen_iv_pool(struct cc_ivgen_ctx *ivgen_ctx,
+			  struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len)
+{
+	unsigned int idx = *iv_seq_len;
+
+	if ((*iv_seq_len + CC_IVPOOL_GEN_SEQ_LEN) > CC_IVPOOL_SEQ_LEN) {
+		/* The sequence will be longer than allowed */
+		return -EINVAL;
+	}
+	/* Setup key */
+	hw_desc_init(&iv_seq[idx]);
+	set_din_sram(&iv_seq[idx], ivgen_ctx->ctr_key, AES_KEYSIZE_128);
+	set_setup_mode(&iv_seq[idx], SETUP_LOAD_KEY0);
+	set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_flow_mode(&iv_seq[idx], S_DIN_to_AES);
+	set_key_size_aes(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_cipher_mode(&iv_seq[idx], DRV_CIPHER_CTR);
+	idx++;
+
+	/* Setup cipher state */
+	hw_desc_init(&iv_seq[idx]);
+	set_din_sram(&iv_seq[idx], ivgen_ctx->ctr_iv, CC_AES_IV_SIZE);
+	set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+	set_flow_mode(&iv_seq[idx], S_DIN_to_AES);
+	set_setup_mode(&iv_seq[idx], SETUP_LOAD_STATE1);
+	set_key_size_aes(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE);
+	set_cipher_mode(&iv_seq[idx], DRV_CIPHER_CTR);
+	idx++;
+
+	/* Perform dummy encrypt to skip first block */
+	hw_desc_init(&iv_seq[idx]);
+	set_din_const(&iv_seq[idx], 0, CC_AES_IV_SIZE);
+	set_dout_sram(&iv_seq[idx], ivgen_ctx->pool, CC_AES_IV_SIZE);
+	set_flow_mode(&iv_seq[idx], DIN_AES_DOUT);
+	idx++;
+
+	/* Generate IV pool */
+	hw_desc_init(&iv_seq[idx]);
+	set_din_const(&iv_seq[idx], 0, CC_IVPOOL_SIZE);
+	set_dout_sram(&iv_seq[idx], ivgen_ctx->pool, CC_IVPOOL_SIZE);
+	set_flow_mode(&iv_seq[idx], DIN_AES_DOUT);
+	idx++;
+
+	*iv_seq_len = idx; /* Update sequence length */
+
+	/* queue ordering assures pool readiness */
+	ivgen_ctx->next_iv_ofs = CC_IVPOOL_META_SIZE;
+
+	return 0;
+}
+
+/*!
+ * Generates the initial pool in SRAM.
+ * This function should be invoked when resuming driver.
+ *
+ * \param drvdata
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_init_iv_sram(struct cc_drvdata *drvdata)
+{
+	struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle;
+	struct cc_hw_desc iv_seq[CC_IVPOOL_SEQ_LEN];
+	unsigned int iv_seq_len = 0;
+	int rc;
+
+	/* Generate initial enc. key/iv */
+	get_random_bytes(ivgen_ctx->pool_meta, CC_IVPOOL_META_SIZE);
+
+	/* The first 32B reserved for the enc. Key/IV */
+	ivgen_ctx->ctr_key = ivgen_ctx->pool;
+	ivgen_ctx->ctr_iv = ivgen_ctx->pool + AES_KEYSIZE_128;
+
+	/* Copy initial enc. key and IV to SRAM at a single descriptor */
+	hw_desc_init(&iv_seq[iv_seq_len]);
+	set_din_type(&iv_seq[iv_seq_len], DMA_DLLI, ivgen_ctx->pool_meta_dma,
+		     CC_IVPOOL_META_SIZE, NS_BIT);
+	set_dout_sram(&iv_seq[iv_seq_len], ivgen_ctx->pool,
+		      CC_IVPOOL_META_SIZE);
+	set_flow_mode(&iv_seq[iv_seq_len], BYPASS);
+	iv_seq_len++;
+
+	/* Generate initial pool */
+	rc = cc_gen_iv_pool(ivgen_ctx, iv_seq, &iv_seq_len);
+	if (rc)
+		return rc;
+
+	/* Fire-and-forget */
+	return send_request_init(drvdata, iv_seq, iv_seq_len);
+}
+
+/*!
+ * Free iv-pool and ivgen context.
+ *
+ * \param drvdata
+ */
+void cc_ivgen_fini(struct cc_drvdata *drvdata)
+{
+	struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle;
+	struct device *device = &drvdata->plat_dev->dev;
+
+	if (!ivgen_ctx)
+		return;
+
+	if (ivgen_ctx->pool_meta) {
+		memset(ivgen_ctx->pool_meta, 0, CC_IVPOOL_META_SIZE);
+		dma_free_coherent(device, CC_IVPOOL_META_SIZE,
+				  ivgen_ctx->pool_meta,
+				  ivgen_ctx->pool_meta_dma);
+	}
+
+	ivgen_ctx->pool = NULL_SRAM_ADDR;
+
+	/* release "this" context */
+	kfree(ivgen_ctx);
+}
+
+/*!
+ * Allocates iv-pool and maps resources.
+ * This function generates the first IV pool.
+ *
+ * \param drvdata Driver's private context
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_ivgen_init(struct cc_drvdata *drvdata)
+{
+	struct cc_ivgen_ctx *ivgen_ctx;
+	struct device *device = &drvdata->plat_dev->dev;
+	int rc;
+
+	/* Allocate "this" context */
+	ivgen_ctx = kzalloc(sizeof(*ivgen_ctx), GFP_KERNEL);
+	if (!ivgen_ctx)
+		return -ENOMEM;
+
+	/* Allocate pool's header for initial enc. key/IV */
+	ivgen_ctx->pool_meta = dma_alloc_coherent(device, CC_IVPOOL_META_SIZE,
+						  &ivgen_ctx->pool_meta_dma,
+						  GFP_KERNEL);
+	if (!ivgen_ctx->pool_meta) {
+		dev_err(device, "Not enough memory to allocate DMA of pool_meta (%u B)\n",
+			CC_IVPOOL_META_SIZE);
+		rc = -ENOMEM;
+		goto out;
+	}
+	/* Allocate IV pool in SRAM */
+	ivgen_ctx->pool = cc_sram_alloc(drvdata, CC_IVPOOL_SIZE);
+	if (ivgen_ctx->pool == NULL_SRAM_ADDR) {
+		dev_err(device, "SRAM pool exhausted\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	drvdata->ivgen_handle = ivgen_ctx;
+
+	return cc_init_iv_sram(drvdata);
+
+out:
+	cc_ivgen_fini(drvdata);
+	return rc;
+}
+
+/*!
+ * Acquires 16 Bytes IV from the iv-pool
+ *
+ * \param drvdata Driver private context
+ * \param iv_out_dma Array of physical IV out addresses
+ * \param iv_out_dma_len Length of iv_out_dma array (additional elements
+ *                       of iv_out_dma array are ignore)
+ * \param iv_out_size May be 8 or 16 bytes long
+ * \param iv_seq IN/OUT array to the descriptors sequence
+ * \param iv_seq_len IN/OUT pointer to the sequence length
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[],
+	      unsigned int iv_out_dma_len, unsigned int iv_out_size,
+	      struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len)
+{
+	struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle;
+	unsigned int idx = *iv_seq_len;
+	struct device *dev = drvdata_to_dev(drvdata);
+	unsigned int t;
+
+	if (iv_out_size != CC_AES_IV_SIZE &&
+	    iv_out_size != CTR_RFC3686_IV_SIZE) {
+		return -EINVAL;
+	}
+	if ((iv_out_dma_len + 1) > CC_IVPOOL_SEQ_LEN) {
+		/* The sequence will be longer than allowed */
+		return -EINVAL;
+	}
+
+	/* check that number of generated IV is limited to max dma address
+	 * iv buffer size
+	 */
+	if (iv_out_dma_len > CC_MAX_IVGEN_DMA_ADDRESSES) {
+		/* The sequence will be longer than allowed */
+		return -EINVAL;
+	}
+
+	for (t = 0; t < iv_out_dma_len; t++) {
+		/* Acquire IV from pool */
+		hw_desc_init(&iv_seq[idx]);
+		set_din_sram(&iv_seq[idx], (ivgen_ctx->pool +
+					    ivgen_ctx->next_iv_ofs),
+			     iv_out_size);
+		set_dout_dlli(&iv_seq[idx], iv_out_dma[t], iv_out_size,
+			      NS_BIT, 0);
+		set_flow_mode(&iv_seq[idx], BYPASS);
+		idx++;
+	}
+
+	/* Bypass operation is proceeded by crypto sequence, hence must
+	 *  assure bypass-write-transaction by a memory barrier
+	 */
+	hw_desc_init(&iv_seq[idx]);
+	set_din_no_dma(&iv_seq[idx], 0, 0xfffff0);
+	set_dout_no_dma(&iv_seq[idx], 0, 0, 1);
+	idx++;
+
+	*iv_seq_len = idx; /* update seq length */
+
+	/* Update iv index */
+	ivgen_ctx->next_iv_ofs += iv_out_size;
+
+	if ((CC_IVPOOL_SIZE - ivgen_ctx->next_iv_ofs) < CC_AES_IV_SIZE) {
+		dev_dbg(dev, "Pool exhausted, regenerating iv-pool\n");
+		/* pool is drained -regenerate it! */
+		return cc_gen_iv_pool(ivgen_ctx, iv_seq, iv_seq_len);
+	}
+
+	return 0;
+}
diff --git a/drivers/crypto/ccree/cc_ivgen.h b/drivers/crypto/ccree/cc_ivgen.h
new file mode 100644
index 000000000000..b6ac16903dda
--- /dev/null
+++ b/drivers/crypto/ccree/cc_ivgen.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_IVGEN_H__
+#define __CC_IVGEN_H__
+
+#include "cc_hw_queue_defs.h"
+
+#define CC_IVPOOL_SEQ_LEN 8
+
+/*!
+ * Allocates iv-pool and maps resources.
+ * This function generates the first IV pool.
+ *
+ * \param drvdata Driver's private context
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_ivgen_init(struct cc_drvdata *drvdata);
+
+/*!
+ * Free iv-pool and ivgen context.
+ *
+ * \param drvdata
+ */
+void cc_ivgen_fini(struct cc_drvdata *drvdata);
+
+/*!
+ * Generates the initial pool in SRAM.
+ * This function should be invoked when resuming DX driver.
+ *
+ * \param drvdata
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_init_iv_sram(struct cc_drvdata *drvdata);
+
+/*!
+ * Acquires 16 Bytes IV from the iv-pool
+ *
+ * \param drvdata Driver private context
+ * \param iv_out_dma Array of physical IV out addresses
+ * \param iv_out_dma_len Length of iv_out_dma array (additional elements of
+ *                       iv_out_dma array are ignore)
+ * \param iv_out_size May be 8 or 16 bytes long
+ * \param iv_seq IN/OUT array to the descriptors sequence
+ * \param iv_seq_len IN/OUT pointer to the sequence length
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[],
+	      unsigned int iv_out_dma_len, unsigned int iv_out_size,
+	      struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len);
+
+#endif /*__CC_IVGEN_H__*/
diff --git a/drivers/crypto/ccree/cc_kernel_regs.h b/drivers/crypto/ccree/cc_kernel_regs.h
new file mode 100644
index 000000000000..fa994406d610
--- /dev/null
+++ b/drivers/crypto/ccree/cc_kernel_regs.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_CRYS_KERNEL_H__
+#define __CC_CRYS_KERNEL_H__
+
+// --------------------------------------
+// BLOCK: DSCRPTR
+// --------------------------------------
+#define CC_DSCRPTR_COMPLETION_COUNTER_REG_OFFSET	0xE00UL
+#define CC_DSCRPTR_COMPLETION_COUNTER_COMPLETION_COUNTER_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_COMPLETION_COUNTER_COMPLETION_COUNTER_BIT_SIZE	0x6UL
+#define CC_DSCRPTR_COMPLETION_COUNTER_OVERFLOW_COUNTER_BIT_SHIFT	0x6UL
+#define CC_DSCRPTR_COMPLETION_COUNTER_OVERFLOW_COUNTER_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_SW_RESET_REG_OFFSET	0xE40UL
+#define CC_DSCRPTR_SW_RESET_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_SW_RESET_VALUE_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_REG_OFFSET	0xE60UL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_NUM_OF_DSCRPTR_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_NUM_OF_DSCRPTR_BIT_SIZE	0xAUL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_DSCRPTR_SRAM_SIZE_BIT_SHIFT	0xAUL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_DSCRPTR_SRAM_SIZE_BIT_SIZE	0xCUL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_SRAM_SIZE_BIT_SHIFT	0x16UL
+#define CC_DSCRPTR_QUEUE_SRAM_SIZE_SRAM_SIZE_BIT_SIZE	0x3UL
+#define CC_DSCRPTR_SINGLE_ADDR_EN_REG_OFFSET	0xE64UL
+#define CC_DSCRPTR_SINGLE_ADDR_EN_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_SINGLE_ADDR_EN_VALUE_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_MEASURE_CNTR_REG_OFFSET	0xE68UL
+#define CC_DSCRPTR_MEASURE_CNTR_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_MEASURE_CNTR_VALUE_BIT_SIZE	0x20UL
+#define CC_DSCRPTR_QUEUE_WORD0_REG_OFFSET	0xE80UL
+#define CC_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SIZE	0x20UL
+#define CC_DSCRPTR_QUEUE_WORD1_REG_OFFSET	0xE84UL
+#define CC_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SHIFT	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SIZE	0x18UL
+#define CC_DSCRPTR_QUEUE_WORD1_NS_BIT_BIT_SHIFT	0x1AUL
+#define CC_DSCRPTR_QUEUE_WORD1_NS_BIT_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD1_DIN_CONST_VALUE_BIT_SHIFT	0x1BUL
+#define CC_DSCRPTR_QUEUE_WORD1_DIN_CONST_VALUE_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD1_NOT_LAST_BIT_SHIFT	0x1CUL
+#define CC_DSCRPTR_QUEUE_WORD1_NOT_LAST_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD1_LOCK_QUEUE_BIT_SHIFT	0x1DUL
+#define CC_DSCRPTR_QUEUE_WORD1_LOCK_QUEUE_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD1_NOT_USED_BIT_SHIFT	0x1EUL
+#define CC_DSCRPTR_QUEUE_WORD1_NOT_USED_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD2_REG_OFFSET	0xE88UL
+#define CC_DSCRPTR_QUEUE_WORD2_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WORD2_VALUE_BIT_SIZE	0x20UL
+#define CC_DSCRPTR_QUEUE_WORD3_REG_OFFSET	0xE8CUL
+#define CC_DSCRPTR_QUEUE_WORD3_DOUT_DMA_MODE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WORD3_DOUT_DMA_MODE_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD3_DOUT_SIZE_BIT_SHIFT	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD3_DOUT_SIZE_BIT_SIZE	0x18UL
+#define CC_DSCRPTR_QUEUE_WORD3_NS_BIT_BIT_SHIFT	0x1AUL
+#define CC_DSCRPTR_QUEUE_WORD3_NS_BIT_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD3_DOUT_LAST_IND_BIT_SHIFT	0x1BUL
+#define CC_DSCRPTR_QUEUE_WORD3_DOUT_LAST_IND_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD3_HASH_XOR_BIT_BIT_SHIFT	0x1DUL
+#define CC_DSCRPTR_QUEUE_WORD3_HASH_XOR_BIT_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD3_NOT_USED_BIT_SHIFT	0x1EUL
+#define CC_DSCRPTR_QUEUE_WORD3_NOT_USED_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD3_QUEUE_LAST_IND_BIT_SHIFT	0x1FUL
+#define CC_DSCRPTR_QUEUE_WORD3_QUEUE_LAST_IND_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_REG_OFFSET	0xE90UL
+#define CC_DSCRPTR_QUEUE_WORD4_DATA_FLOW_MODE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WORD4_DATA_FLOW_MODE_BIT_SIZE	0x6UL
+#define CC_DSCRPTR_QUEUE_WORD4_AES_SEL_N_HASH_BIT_SHIFT	0x6UL
+#define CC_DSCRPTR_QUEUE_WORD4_AES_SEL_N_HASH_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_AES_XOR_CRYPTO_KEY_BIT_SHIFT	0x7UL
+#define CC_DSCRPTR_QUEUE_WORD4_AES_XOR_CRYPTO_KEY_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_ACK_NEEDED_BIT_SHIFT	0x8UL
+#define CC_DSCRPTR_QUEUE_WORD4_ACK_NEEDED_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_MODE_BIT_SHIFT	0xAUL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_MODE_BIT_SIZE	0x4UL
+#define CC_DSCRPTR_QUEUE_WORD4_CMAC_SIZE0_BIT_SHIFT	0xEUL
+#define CC_DSCRPTR_QUEUE_WORD4_CMAC_SIZE0_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_DO_BIT_SHIFT	0xFUL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_DO_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF0_BIT_SHIFT	0x11UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF0_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF1_BIT_SHIFT	0x13UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF1_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF2_BIT_SHIFT	0x14UL
+#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF2_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD4_KEY_SIZE_BIT_SHIFT	0x16UL
+#define CC_DSCRPTR_QUEUE_WORD4_KEY_SIZE_BIT_SIZE	0x2UL
+#define CC_DSCRPTR_QUEUE_WORD4_SETUP_OPERATION_BIT_SHIFT	0x18UL
+#define CC_DSCRPTR_QUEUE_WORD4_SETUP_OPERATION_BIT_SIZE	0x4UL
+#define CC_DSCRPTR_QUEUE_WORD4_DIN_SRAM_ENDIANNESS_BIT_SHIFT	0x1CUL
+#define CC_DSCRPTR_QUEUE_WORD4_DIN_SRAM_ENDIANNESS_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_DOUT_SRAM_ENDIANNESS_BIT_SHIFT	0x1DUL
+#define CC_DSCRPTR_QUEUE_WORD4_DOUT_SRAM_ENDIANNESS_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SHIFT	0x1EUL
+#define CC_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SHIFT	0x1FUL
+#define CC_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SIZE	0x1UL
+#define CC_DSCRPTR_QUEUE_WORD5_REG_OFFSET	0xE94UL
+#define CC_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SIZE	0x10UL
+#define CC_DSCRPTR_QUEUE_WORD5_DOUT_ADDR_HIGH_BIT_SHIFT	0x10UL
+#define CC_DSCRPTR_QUEUE_WORD5_DOUT_ADDR_HIGH_BIT_SIZE	0x10UL
+#define CC_DSCRPTR_QUEUE_WATERMARK_REG_OFFSET	0xE98UL
+#define CC_DSCRPTR_QUEUE_WATERMARK_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_WATERMARK_VALUE_BIT_SIZE	0xAUL
+#define CC_DSCRPTR_QUEUE_CONTENT_REG_OFFSET	0xE9CUL
+#define CC_DSCRPTR_QUEUE_CONTENT_VALUE_BIT_SHIFT	0x0UL
+#define CC_DSCRPTR_QUEUE_CONTENT_VALUE_BIT_SIZE	0xAUL
+// --------------------------------------
+// BLOCK: AXI_P
+// --------------------------------------
+#define CC_AXIM_MON_INFLIGHT_REG_OFFSET	0xB00UL
+#define CC_AXIM_MON_INFLIGHT_VALUE_BIT_SHIFT	0x0UL
+#define CC_AXIM_MON_INFLIGHT_VALUE_BIT_SIZE	0x8UL
+#define CC_AXIM_MON_INFLIGHTLAST_REG_OFFSET	0xB40UL
+#define CC_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SHIFT	0x0UL
+#define CC_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SIZE	0x8UL
+#define CC_AXIM_MON_COMP_REG_OFFSET	0xB80UL
+#define CC_AXIM_MON_COMP_VALUE_BIT_SHIFT	0x0UL
+#define CC_AXIM_MON_COMP_VALUE_BIT_SIZE	0x10UL
+#define CC_AXIM_MON_ERR_REG_OFFSET	0xBC4UL
+#define CC_AXIM_MON_ERR_BRESP_BIT_SHIFT	0x0UL
+#define CC_AXIM_MON_ERR_BRESP_BIT_SIZE	0x2UL
+#define CC_AXIM_MON_ERR_BID_BIT_SHIFT	0x2UL
+#define CC_AXIM_MON_ERR_BID_BIT_SIZE	0x4UL
+#define CC_AXIM_MON_ERR_RRESP_BIT_SHIFT	0x10UL
+#define CC_AXIM_MON_ERR_RRESP_BIT_SIZE	0x2UL
+#define CC_AXIM_MON_ERR_RID_BIT_SHIFT	0x12UL
+#define CC_AXIM_MON_ERR_RID_BIT_SIZE	0x4UL
+#define CC_AXIM_CFG_REG_OFFSET	0xBE8UL
+#define CC_AXIM_CFG_BRESPMASK_BIT_SHIFT	0x4UL
+#define CC_AXIM_CFG_BRESPMASK_BIT_SIZE	0x1UL
+#define CC_AXIM_CFG_RRESPMASK_BIT_SHIFT	0x5UL
+#define CC_AXIM_CFG_RRESPMASK_BIT_SIZE	0x1UL
+#define CC_AXIM_CFG_INFLTMASK_BIT_SHIFT	0x6UL
+#define CC_AXIM_CFG_INFLTMASK_BIT_SIZE	0x1UL
+#define CC_AXIM_CFG_COMPMASK_BIT_SHIFT	0x7UL
+#define CC_AXIM_CFG_COMPMASK_BIT_SIZE	0x1UL
+#define CC_AXIM_ACE_CONST_REG_OFFSET	0xBECUL
+#define CC_AXIM_ACE_CONST_ARDOMAIN_BIT_SHIFT	0x0UL
+#define CC_AXIM_ACE_CONST_ARDOMAIN_BIT_SIZE	0x2UL
+#define CC_AXIM_ACE_CONST_AWDOMAIN_BIT_SHIFT	0x2UL
+#define CC_AXIM_ACE_CONST_AWDOMAIN_BIT_SIZE	0x2UL
+#define CC_AXIM_ACE_CONST_ARBAR_BIT_SHIFT	0x4UL
+#define CC_AXIM_ACE_CONST_ARBAR_BIT_SIZE	0x2UL
+#define CC_AXIM_ACE_CONST_AWBAR_BIT_SHIFT	0x6UL
+#define CC_AXIM_ACE_CONST_AWBAR_BIT_SIZE	0x2UL
+#define CC_AXIM_ACE_CONST_ARSNOOP_BIT_SHIFT	0x8UL
+#define CC_AXIM_ACE_CONST_ARSNOOP_BIT_SIZE	0x4UL
+#define CC_AXIM_ACE_CONST_AWSNOOP_NOT_ALIGNED_BIT_SHIFT	0xCUL
+#define CC_AXIM_ACE_CONST_AWSNOOP_NOT_ALIGNED_BIT_SIZE	0x3UL
+#define CC_AXIM_ACE_CONST_AWSNOOP_ALIGNED_BIT_SHIFT	0xFUL
+#define CC_AXIM_ACE_CONST_AWSNOOP_ALIGNED_BIT_SIZE	0x3UL
+#define CC_AXIM_ACE_CONST_AWADDR_NOT_MASKED_BIT_SHIFT	0x12UL
+#define CC_AXIM_ACE_CONST_AWADDR_NOT_MASKED_BIT_SIZE	0x7UL
+#define CC_AXIM_ACE_CONST_AWLEN_VAL_BIT_SHIFT	0x19UL
+#define CC_AXIM_ACE_CONST_AWLEN_VAL_BIT_SIZE	0x4UL
+#define CC_AXIM_CACHE_PARAMS_REG_OFFSET	0xBF0UL
+#define CC_AXIM_CACHE_PARAMS_AWCACHE_LAST_BIT_SHIFT	0x0UL
+#define CC_AXIM_CACHE_PARAMS_AWCACHE_LAST_BIT_SIZE	0x4UL
+#define CC_AXIM_CACHE_PARAMS_AWCACHE_BIT_SHIFT	0x4UL
+#define CC_AXIM_CACHE_PARAMS_AWCACHE_BIT_SIZE	0x4UL
+#define CC_AXIM_CACHE_PARAMS_ARCACHE_BIT_SHIFT	0x8UL
+#define CC_AXIM_CACHE_PARAMS_ARCACHE_BIT_SIZE	0x4UL
+#endif	// __CC_CRYS_KERNEL_H__
diff --git a/drivers/crypto/ccree/cc_lli_defs.h b/drivers/crypto/ccree/cc_lli_defs.h
new file mode 100644
index 000000000000..64b15ac9f1d3
--- /dev/null
+++ b/drivers/crypto/ccree/cc_lli_defs.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef _CC_LLI_DEFS_H_
+#define _CC_LLI_DEFS_H_
+
+#include <linux/types.h>
+
+/* Max DLLI size
+ *  AKA CC_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SIZE
+ */
+#define DLLI_SIZE_BIT_SIZE	0x18
+
+#define CC_MAX_MLLI_ENTRY_SIZE 0xFFFF
+
+#define LLI_MAX_NUM_OF_DATA_ENTRIES 128
+#define LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES 4
+#define MLLI_TABLE_MIN_ALIGNMENT 4 /* 32 bit alignment */
+#define MAX_NUM_OF_BUFFERS_IN_MLLI 4
+#define MAX_NUM_OF_TOTAL_MLLI_ENTRIES \
+		(2 * LLI_MAX_NUM_OF_DATA_ENTRIES + \
+		 LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES)
+
+/* Size of entry */
+#define LLI_ENTRY_WORD_SIZE 2
+#define LLI_ENTRY_BYTE_SIZE (LLI_ENTRY_WORD_SIZE * sizeof(u32))
+
+/* Word0[31:0] = ADDR[31:0] */
+#define LLI_WORD0_OFFSET 0
+#define LLI_LADDR_BIT_OFFSET 0
+#define LLI_LADDR_BIT_SIZE 32
+/* Word1[31:16] = ADDR[47:32]; Word1[15:0] = SIZE */
+#define LLI_WORD1_OFFSET 1
+#define LLI_SIZE_BIT_OFFSET 0
+#define LLI_SIZE_BIT_SIZE 16
+#define LLI_HADDR_BIT_OFFSET 16
+#define LLI_HADDR_BIT_SIZE 16
+
+#define LLI_SIZE_MASK GENMASK((LLI_SIZE_BIT_SIZE - 1), LLI_SIZE_BIT_OFFSET)
+#define LLI_HADDR_MASK GENMASK( \
+			       (LLI_HADDR_BIT_OFFSET + LLI_HADDR_BIT_SIZE - 1),\
+				LLI_HADDR_BIT_OFFSET)
+
+static inline void cc_lli_set_addr(u32 *lli_p, dma_addr_t addr)
+{
+	lli_p[LLI_WORD0_OFFSET] = (addr & U32_MAX);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+	lli_p[LLI_WORD1_OFFSET] &= ~LLI_HADDR_MASK;
+	lli_p[LLI_WORD1_OFFSET] |= FIELD_PREP(LLI_HADDR_MASK, (addr >> 32));
+#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */
+}
+
+static inline void cc_lli_set_size(u32 *lli_p, u16 size)
+{
+	lli_p[LLI_WORD1_OFFSET] &= ~LLI_SIZE_MASK;
+	lli_p[LLI_WORD1_OFFSET] |= FIELD_PREP(LLI_SIZE_MASK, size);
+}
+
+#endif /*_CC_LLI_DEFS_H_*/
diff --git a/drivers/crypto/ccree/cc_pm.c b/drivers/crypto/ccree/cc_pm.c
new file mode 100644
index 000000000000..d990f472e89f
--- /dev/null
+++ b/drivers/crypto/ccree/cc_pm.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include "cc_driver.h"
+#include "cc_buffer_mgr.h"
+#include "cc_request_mgr.h"
+#include "cc_sram_mgr.h"
+#include "cc_ivgen.h"
+#include "cc_hash.h"
+#include "cc_pm.h"
+
+#define POWER_DOWN_ENABLE 0x01
+#define POWER_DOWN_DISABLE 0x00
+
+const struct dev_pm_ops ccree_pm = {
+	SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL)
+};
+
+int cc_pm_suspend(struct device *dev)
+{
+	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
+	int rc;
+
+	dev_dbg(dev, "set HOST_POWER_DOWN_EN\n");
+	cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE);
+	rc = cc_suspend_req_queue(drvdata);
+	if (rc) {
+		dev_err(dev, "cc_suspend_req_queue (%x)\n", rc);
+		return rc;
+	}
+	fini_cc_regs(drvdata);
+	cc_clk_off(drvdata);
+	return 0;
+}
+
+int cc_pm_resume(struct device *dev)
+{
+	int rc;
+	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n");
+	cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE);
+
+	rc = cc_clk_on(drvdata);
+	if (rc) {
+		dev_err(dev, "failed getting clock back on. We're toast.\n");
+		return rc;
+	}
+
+	rc = init_cc_regs(drvdata, false);
+	if (rc) {
+		dev_err(dev, "init_cc_regs (%x)\n", rc);
+		return rc;
+	}
+
+	rc = cc_resume_req_queue(drvdata);
+	if (rc) {
+		dev_err(dev, "cc_resume_req_queue (%x)\n", rc);
+		return rc;
+	}
+
+	/* must be after the queue resuming as it uses the HW queue*/
+	cc_init_hash_sram(drvdata);
+
+	cc_init_iv_sram(drvdata);
+	return 0;
+}
+
+int cc_pm_get(struct device *dev)
+{
+	int rc = 0;
+	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (cc_req_queue_suspended(drvdata))
+		rc = pm_runtime_get_sync(dev);
+	else
+		pm_runtime_get_noresume(dev);
+
+	return rc;
+}
+
+int cc_pm_put_suspend(struct device *dev)
+{
+	int rc = 0;
+	struct cc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (!cc_req_queue_suspended(drvdata)) {
+		pm_runtime_mark_last_busy(dev);
+		rc = pm_runtime_put_autosuspend(dev);
+	} else {
+		/* Something wrong happens*/
+		dev_err(dev, "request to suspend already suspended queue");
+		rc = -EBUSY;
+	}
+	return rc;
+}
+
+int cc_pm_init(struct cc_drvdata *drvdata)
+{
+	int rc = 0;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	/* must be before the enabling to avoid resdundent suspending */
+	pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT);
+	pm_runtime_use_autosuspend(dev);
+	/* activate the PM module */
+	rc = pm_runtime_set_active(dev);
+	if (rc)
+		return rc;
+	/* enable the PM module*/
+	pm_runtime_enable(dev);
+
+	return rc;
+}
+
+void cc_pm_fini(struct cc_drvdata *drvdata)
+{
+	pm_runtime_disable(drvdata_to_dev(drvdata));
+}
diff --git a/drivers/crypto/ccree/cc_pm.h b/drivers/crypto/ccree/cc_pm.h
new file mode 100644
index 000000000000..020a5403c58b
--- /dev/null
+++ b/drivers/crypto/ccree/cc_pm.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_pm.h
+ */
+
+#ifndef __CC_POWER_MGR_H__
+#define __CC_POWER_MGR_H__
+
+#include "cc_driver.h"
+
+#define CC_SUSPEND_TIMEOUT 3000
+
+#if defined(CONFIG_PM)
+
+extern const struct dev_pm_ops ccree_pm;
+
+int cc_pm_init(struct cc_drvdata *drvdata);
+void cc_pm_fini(struct cc_drvdata *drvdata);
+int cc_pm_suspend(struct device *dev);
+int cc_pm_resume(struct device *dev);
+int cc_pm_get(struct device *dev);
+int cc_pm_put_suspend(struct device *dev);
+
+#else
+
+static inline int cc_pm_init(struct cc_drvdata *drvdata)
+{
+	return 0;
+}
+
+static inline void cc_pm_fini(struct cc_drvdata *drvdata) {}
+
+static inline int cc_pm_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static inline int cc_pm_resume(struct device *dev)
+{
+	return 0;
+}
+
+static inline int cc_pm_get(struct device *dev)
+{
+	return 0;
+}
+
+static inline int cc_pm_put_suspend(struct device *dev)
+{
+	return 0;
+}
+
+#endif
+
+#endif /*__POWER_MGR_H__*/
diff --git a/drivers/crypto/ccree/cc_request_mgr.c b/drivers/crypto/ccree/cc_request_mgr.c
new file mode 100644
index 000000000000..0bea57c4b352
--- /dev/null
+++ b/drivers/crypto/ccree/cc_request_mgr.c
@@ -0,0 +1,712 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include <linux/kernel.h>
+#include "cc_driver.h"
+#include "cc_buffer_mgr.h"
+#include "cc_request_mgr.h"
+#include "cc_ivgen.h"
+#include "cc_pm.h"
+
+#define CC_MAX_POLL_ITER	10
+/* The highest descriptor count in used */
+#define CC_MAX_DESC_SEQ_LEN	23
+
+struct cc_req_mgr_handle {
+	/* Request manager resources */
+	unsigned int hw_queue_size; /* HW capability */
+	unsigned int min_free_hw_slots;
+	unsigned int max_used_sw_slots;
+	struct cc_crypto_req req_queue[MAX_REQUEST_QUEUE_SIZE];
+	u32 req_queue_head;
+	u32 req_queue_tail;
+	u32 axi_completed;
+	u32 q_free_slots;
+	/* This lock protects access to HW register
+	 * that must be single request at a time
+	 */
+	spinlock_t hw_lock;
+	struct cc_hw_desc compl_desc;
+	u8 *dummy_comp_buff;
+	dma_addr_t dummy_comp_buff_dma;
+
+	/* backlog queue */
+	struct list_head backlog;
+	unsigned int bl_len;
+	spinlock_t bl_lock; /* protect backlog queue */
+
+#ifdef COMP_IN_WQ
+	struct workqueue_struct *workq;
+	struct delayed_work compwork;
+#else
+	struct tasklet_struct comptask;
+#endif
+	bool is_runtime_suspended;
+};
+
+struct cc_bl_item {
+	struct cc_crypto_req creq;
+	struct cc_hw_desc desc[CC_MAX_DESC_SEQ_LEN];
+	unsigned int len;
+	struct list_head list;
+	bool notif;
+};
+
+static void comp_handler(unsigned long devarg);
+#ifdef COMP_IN_WQ
+static void comp_work_handler(struct work_struct *work);
+#endif
+
+void cc_req_mgr_fini(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	if (!req_mgr_h)
+		return; /* Not allocated */
+
+	if (req_mgr_h->dummy_comp_buff_dma) {
+		dma_free_coherent(dev, sizeof(u32), req_mgr_h->dummy_comp_buff,
+				  req_mgr_h->dummy_comp_buff_dma);
+	}
+
+	dev_dbg(dev, "max_used_hw_slots=%d\n", (req_mgr_h->hw_queue_size -
+						req_mgr_h->min_free_hw_slots));
+	dev_dbg(dev, "max_used_sw_slots=%d\n", req_mgr_h->max_used_sw_slots);
+
+#ifdef COMP_IN_WQ
+	flush_workqueue(req_mgr_h->workq);
+	destroy_workqueue(req_mgr_h->workq);
+#else
+	/* Kill tasklet */
+	tasklet_kill(&req_mgr_h->comptask);
+#endif
+	memset(req_mgr_h, 0, sizeof(struct cc_req_mgr_handle));
+	kfree(req_mgr_h);
+	drvdata->request_mgr_handle = NULL;
+}
+
+int cc_req_mgr_init(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *req_mgr_h;
+	struct device *dev = drvdata_to_dev(drvdata);
+	int rc = 0;
+
+	req_mgr_h = kzalloc(sizeof(*req_mgr_h), GFP_KERNEL);
+	if (!req_mgr_h) {
+		rc = -ENOMEM;
+		goto req_mgr_init_err;
+	}
+
+	drvdata->request_mgr_handle = req_mgr_h;
+
+	spin_lock_init(&req_mgr_h->hw_lock);
+	spin_lock_init(&req_mgr_h->bl_lock);
+	INIT_LIST_HEAD(&req_mgr_h->backlog);
+
+#ifdef COMP_IN_WQ
+	dev_dbg(dev, "Initializing completion workqueue\n");
+	req_mgr_h->workq = create_singlethread_workqueue("ccree");
+	if (!req_mgr_h->workq) {
+		dev_err(dev, "Failed creating work queue\n");
+		rc = -ENOMEM;
+		goto req_mgr_init_err;
+	}
+	INIT_DELAYED_WORK(&req_mgr_h->compwork, comp_work_handler);
+#else
+	dev_dbg(dev, "Initializing completion tasklet\n");
+	tasklet_init(&req_mgr_h->comptask, comp_handler,
+		     (unsigned long)drvdata);
+#endif
+	req_mgr_h->hw_queue_size = cc_ioread(drvdata,
+					     CC_REG(DSCRPTR_QUEUE_SRAM_SIZE));
+	dev_dbg(dev, "hw_queue_size=0x%08X\n", req_mgr_h->hw_queue_size);
+	if (req_mgr_h->hw_queue_size < MIN_HW_QUEUE_SIZE) {
+		dev_err(dev, "Invalid HW queue size = %u (Min. required is %u)\n",
+			req_mgr_h->hw_queue_size, MIN_HW_QUEUE_SIZE);
+		rc = -ENOMEM;
+		goto req_mgr_init_err;
+	}
+	req_mgr_h->min_free_hw_slots = req_mgr_h->hw_queue_size;
+	req_mgr_h->max_used_sw_slots = 0;
+
+	/* Allocate DMA word for "dummy" completion descriptor use */
+	req_mgr_h->dummy_comp_buff =
+		dma_alloc_coherent(dev, sizeof(u32),
+				   &req_mgr_h->dummy_comp_buff_dma,
+				   GFP_KERNEL);
+	if (!req_mgr_h->dummy_comp_buff) {
+		dev_err(dev, "Not enough memory to allocate DMA (%zu) dropped buffer\n",
+			sizeof(u32));
+		rc = -ENOMEM;
+		goto req_mgr_init_err;
+	}
+
+	/* Init. "dummy" completion descriptor */
+	hw_desc_init(&req_mgr_h->compl_desc);
+	set_din_const(&req_mgr_h->compl_desc, 0, sizeof(u32));
+	set_dout_dlli(&req_mgr_h->compl_desc, req_mgr_h->dummy_comp_buff_dma,
+		      sizeof(u32), NS_BIT, 1);
+	set_flow_mode(&req_mgr_h->compl_desc, BYPASS);
+	set_queue_last_ind(&req_mgr_h->compl_desc);
+
+	return 0;
+
+req_mgr_init_err:
+	cc_req_mgr_fini(drvdata);
+	return rc;
+}
+
+static void enqueue_seq(struct cc_drvdata *drvdata, struct cc_hw_desc seq[],
+			unsigned int seq_len)
+{
+	int i, w;
+	void __iomem *reg = drvdata->cc_base + CC_REG(DSCRPTR_QUEUE_WORD0);
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	/*
+	 * We do indeed write all 6 command words to the same
+	 * register. The HW supports this.
+	 */
+
+	for (i = 0; i < seq_len; i++) {
+		for (w = 0; w <= 5; w++)
+			writel_relaxed(seq[i].word[w], reg);
+
+		if (cc_dump_desc)
+			dev_dbg(dev, "desc[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
+				i, seq[i].word[0], seq[i].word[1],
+				seq[i].word[2], seq[i].word[3],
+				seq[i].word[4], seq[i].word[5]);
+	}
+}
+
+/*!
+ * Completion will take place if and only if user requested completion
+ * by cc_send_sync_request().
+ *
+ * \param dev
+ * \param dx_compl_h The completion event to signal
+ */
+static void request_mgr_complete(struct device *dev, void *dx_compl_h,
+				 int dummy)
+{
+	struct completion *this_compl = dx_compl_h;
+
+	complete(this_compl);
+}
+
+static int cc_queues_status(struct cc_drvdata *drvdata,
+			    struct cc_req_mgr_handle *req_mgr_h,
+			    unsigned int total_seq_len)
+{
+	unsigned long poll_queue;
+	struct device *dev = drvdata_to_dev(drvdata);
+
+	/* SW queue is checked only once as it will not
+	 * be chaned during the poll because the spinlock_bh
+	 * is held by the thread
+	 */
+	if (((req_mgr_h->req_queue_head + 1) & (MAX_REQUEST_QUEUE_SIZE - 1)) ==
+	    req_mgr_h->req_queue_tail) {
+		dev_err(dev, "SW FIFO is full. req_queue_head=%d sw_fifo_len=%d\n",
+			req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE);
+		return -ENOSPC;
+	}
+
+	if (req_mgr_h->q_free_slots >= total_seq_len)
+		return 0;
+
+	/* Wait for space in HW queue. Poll constant num of iterations. */
+	for (poll_queue = 0; poll_queue < CC_MAX_POLL_ITER ; poll_queue++) {
+		req_mgr_h->q_free_slots =
+			cc_ioread(drvdata, CC_REG(DSCRPTR_QUEUE_CONTENT));
+		if (req_mgr_h->q_free_slots < req_mgr_h->min_free_hw_slots)
+			req_mgr_h->min_free_hw_slots = req_mgr_h->q_free_slots;
+
+		if (req_mgr_h->q_free_slots >= total_seq_len) {
+			/* If there is enough place return */
+			return 0;
+		}
+
+		dev_dbg(dev, "HW FIFO is full. q_free_slots=%d total_seq_len=%d\n",
+			req_mgr_h->q_free_slots, total_seq_len);
+	}
+	/* No room in the HW queue try again later */
+	dev_dbg(dev, "HW FIFO full, timeout. req_queue_head=%d sw_fifo_len=%d q_free_slots=%d total_seq_len=%d\n",
+		req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE,
+		req_mgr_h->q_free_slots, total_seq_len);
+	return -ENOSPC;
+}
+
+/*!
+ * Enqueue caller request to crypto hardware.
+ * Need to be called with HW lock held and PM running
+ *
+ * \param drvdata
+ * \param cc_req The request to enqueue
+ * \param desc The crypto sequence
+ * \param len The crypto sequence length
+ * \param add_comp If "true": add an artificial dout DMA to mark completion
+ *
+ * \return int Returns -EINPROGRESS or error code
+ */
+static int cc_do_send_request(struct cc_drvdata *drvdata,
+			      struct cc_crypto_req *cc_req,
+			      struct cc_hw_desc *desc, unsigned int len,
+				bool add_comp, bool ivgen)
+{
+	struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
+	unsigned int used_sw_slots;
+	unsigned int iv_seq_len = 0;
+	unsigned int total_seq_len = len; /*initial sequence length*/
+	struct cc_hw_desc iv_seq[CC_IVPOOL_SEQ_LEN];
+	struct device *dev = drvdata_to_dev(drvdata);
+	int rc;
+
+	if (ivgen) {
+		dev_dbg(dev, "Acquire IV from pool into %d DMA addresses %pad, %pad, %pad, IV-size=%u\n",
+			cc_req->ivgen_dma_addr_len,
+			&cc_req->ivgen_dma_addr[0],
+			&cc_req->ivgen_dma_addr[1],
+			&cc_req->ivgen_dma_addr[2],
+			cc_req->ivgen_size);
+
+		/* Acquire IV from pool */
+		rc = cc_get_iv(drvdata, cc_req->ivgen_dma_addr,
+			       cc_req->ivgen_dma_addr_len,
+			       cc_req->ivgen_size, iv_seq, &iv_seq_len);
+
+		if (rc) {
+			dev_err(dev, "Failed to generate IV (rc=%d)\n", rc);
+			return rc;
+		}
+
+		total_seq_len += iv_seq_len;
+	}
+
+	used_sw_slots = ((req_mgr_h->req_queue_head -
+			  req_mgr_h->req_queue_tail) &
+			 (MAX_REQUEST_QUEUE_SIZE - 1));
+	if (used_sw_slots > req_mgr_h->max_used_sw_slots)
+		req_mgr_h->max_used_sw_slots = used_sw_slots;
+
+	/* Enqueue request - must be locked with HW lock*/
+	req_mgr_h->req_queue[req_mgr_h->req_queue_head] = *cc_req;
+	req_mgr_h->req_queue_head = (req_mgr_h->req_queue_head + 1) &
+				    (MAX_REQUEST_QUEUE_SIZE - 1);
+	/* TODO: Use circ_buf.h ? */
+
+	dev_dbg(dev, "Enqueue request head=%u\n", req_mgr_h->req_queue_head);
+
+	/*
+	 * We are about to push command to the HW via the command registers
+	 * that may refernece hsot memory. We need to issue a memory barrier
+	 * to make sure there are no outstnading memory writes
+	 */
+	wmb();
+
+	/* STAT_PHASE_4: Push sequence */
+	if (ivgen)
+		enqueue_seq(drvdata, iv_seq, iv_seq_len);
+
+	enqueue_seq(drvdata, desc, len);
+
+	if (add_comp) {
+		enqueue_seq(drvdata, &req_mgr_h->compl_desc, 1);
+		total_seq_len++;
+	}
+
+	if (req_mgr_h->q_free_slots < total_seq_len) {
+		/* This situation should never occur. Maybe indicating problem
+		 * with resuming power. Set the free slot count to 0 and hope
+		 * for the best.
+		 */
+		dev_err(dev, "HW free slot count mismatch.");
+		req_mgr_h->q_free_slots = 0;
+	} else {
+		/* Update the free slots in HW queue */
+		req_mgr_h->q_free_slots -= total_seq_len;
+	}
+
+	/* Operation still in process */
+	return -EINPROGRESS;
+}
+
+static void cc_enqueue_backlog(struct cc_drvdata *drvdata,
+			       struct cc_bl_item *bli)
+{
+	struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
+
+	spin_lock_bh(&mgr->bl_lock);
+	list_add_tail(&bli->list, &mgr->backlog);
+	++mgr->bl_len;
+	spin_unlock_bh(&mgr->bl_lock);
+	tasklet_schedule(&mgr->comptask);
+}
+
+static void cc_proc_backlog(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
+	struct cc_bl_item *bli;
+	struct cc_crypto_req *creq;
+	struct crypto_async_request *req;
+	bool ivgen;
+	unsigned int total_len;
+	struct device *dev = drvdata_to_dev(drvdata);
+	int rc;
+
+	spin_lock(&mgr->bl_lock);
+
+	while (mgr->bl_len) {
+		bli = list_first_entry(&mgr->backlog, struct cc_bl_item, list);
+		spin_unlock(&mgr->bl_lock);
+
+		creq = &bli->creq;
+		req = (struct crypto_async_request *)creq->user_arg;
+
+		/*
+		 * Notify the request we're moving out of the backlog
+		 * but only if we haven't done so already.
+		 */
+		if (!bli->notif) {
+			req->complete(req, -EINPROGRESS);
+			bli->notif = true;
+		}
+
+		ivgen = !!creq->ivgen_dma_addr_len;
+		total_len = bli->len + (ivgen ? CC_IVPOOL_SEQ_LEN : 0);
+
+		spin_lock(&mgr->hw_lock);
+
+		rc = cc_queues_status(drvdata, mgr, total_len);
+		if (rc) {
+			/*
+			 * There is still not room in the FIFO for
+			 * this request. Bail out. We'll return here
+			 * on the next completion irq.
+			 */
+			spin_unlock(&mgr->hw_lock);
+			return;
+		}
+
+		rc = cc_do_send_request(drvdata, &bli->creq, bli->desc,
+					bli->len, false, ivgen);
+
+		spin_unlock(&mgr->hw_lock);
+
+		if (rc != -EINPROGRESS) {
+			cc_pm_put_suspend(dev);
+			creq->user_cb(dev, req, rc);
+		}
+
+		/* Remove ourselves from the backlog list */
+		spin_lock(&mgr->bl_lock);
+		list_del(&bli->list);
+		--mgr->bl_len;
+	}
+
+	spin_unlock(&mgr->bl_lock);
+}
+
+int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req,
+		    struct cc_hw_desc *desc, unsigned int len,
+		    struct crypto_async_request *req)
+{
+	int rc;
+	struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
+	bool ivgen = !!cc_req->ivgen_dma_addr_len;
+	unsigned int total_len = len + (ivgen ? CC_IVPOOL_SEQ_LEN : 0);
+	struct device *dev = drvdata_to_dev(drvdata);
+	bool backlog_ok = req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG;
+	gfp_t flags = cc_gfp_flags(req);
+	struct cc_bl_item *bli;
+
+	rc = cc_pm_get(dev);
+	if (rc) {
+		dev_err(dev, "ssi_power_mgr_runtime_get returned %x\n", rc);
+		return rc;
+	}
+
+	spin_lock_bh(&mgr->hw_lock);
+	rc = cc_queues_status(drvdata, mgr, total_len);
+
+#ifdef CC_DEBUG_FORCE_BACKLOG
+	if (backlog_ok)
+		rc = -ENOSPC;
+#endif /* CC_DEBUG_FORCE_BACKLOG */
+
+	if (rc == -ENOSPC && backlog_ok) {
+		spin_unlock_bh(&mgr->hw_lock);
+
+		bli = kmalloc(sizeof(*bli), flags);
+		if (!bli) {
+			cc_pm_put_suspend(dev);
+			return -ENOMEM;
+		}
+
+		memcpy(&bli->creq, cc_req, sizeof(*cc_req));
+		memcpy(&bli->desc, desc, len * sizeof(*desc));
+		bli->len = len;
+		bli->notif = false;
+		cc_enqueue_backlog(drvdata, bli);
+		return -EBUSY;
+	}
+
+	if (!rc)
+		rc = cc_do_send_request(drvdata, cc_req, desc, len, false,
+					ivgen);
+
+	spin_unlock_bh(&mgr->hw_lock);
+	return rc;
+}
+
+int cc_send_sync_request(struct cc_drvdata *drvdata,
+			 struct cc_crypto_req *cc_req, struct cc_hw_desc *desc,
+			 unsigned int len)
+{
+	int rc;
+	struct device *dev = drvdata_to_dev(drvdata);
+	struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
+
+	init_completion(&cc_req->seq_compl);
+	cc_req->user_cb = request_mgr_complete;
+	cc_req->user_arg = &cc_req->seq_compl;
+
+	rc = cc_pm_get(dev);
+	if (rc) {
+		dev_err(dev, "ssi_power_mgr_runtime_get returned %x\n", rc);
+		return rc;
+	}
+
+	while (true) {
+		spin_lock_bh(&mgr->hw_lock);
+		rc = cc_queues_status(drvdata, mgr, len + 1);
+
+		if (!rc)
+			break;
+
+		spin_unlock_bh(&mgr->hw_lock);
+		if (rc != -EAGAIN) {
+			cc_pm_put_suspend(dev);
+			return rc;
+		}
+		wait_for_completion_interruptible(&drvdata->hw_queue_avail);
+		reinit_completion(&drvdata->hw_queue_avail);
+	}
+
+	rc = cc_do_send_request(drvdata, cc_req, desc, len, true, false);
+	spin_unlock_bh(&mgr->hw_lock);
+
+	if (rc != -EINPROGRESS) {
+		cc_pm_put_suspend(dev);
+		return rc;
+	}
+
+	wait_for_completion(&cc_req->seq_compl);
+	return 0;
+}
+
+/*!
+ * Enqueue caller request to crypto hardware during init process.
+ * assume this function is not called in middle of a flow,
+ * since we set QUEUE_LAST_IND flag in the last descriptor.
+ *
+ * \param drvdata
+ * \param desc The crypto sequence
+ * \param len The crypto sequence length
+ *
+ * \return int Returns "0" upon success
+ */
+int send_request_init(struct cc_drvdata *drvdata, struct cc_hw_desc *desc,
+		      unsigned int len)
+{
+	struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
+	unsigned int total_seq_len = len; /*initial sequence length*/
+	int rc = 0;
+
+	/* Wait for space in HW and SW FIFO. Poll for as much as FIFO_TIMEOUT.
+	 */
+	rc = cc_queues_status(drvdata, req_mgr_h, total_seq_len);
+	if (rc)
+		return rc;
+
+	set_queue_last_ind(&desc[(len - 1)]);
+
+	/*
+	 * We are about to push command to the HW via the command registers
+	 * that may refernece hsot memory. We need to issue a memory barrier
+	 * to make sure there are no outstnading memory writes
+	 */
+	wmb();
+	enqueue_seq(drvdata, desc, len);
+
+	/* Update the free slots in HW queue */
+	req_mgr_h->q_free_slots =
+		cc_ioread(drvdata, CC_REG(DSCRPTR_QUEUE_CONTENT));
+
+	return 0;
+}
+
+void complete_request(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *request_mgr_handle =
+						drvdata->request_mgr_handle;
+
+	complete(&drvdata->hw_queue_avail);
+#ifdef COMP_IN_WQ
+	queue_delayed_work(request_mgr_handle->workq,
+			   &request_mgr_handle->compwork, 0);
+#else
+	tasklet_schedule(&request_mgr_handle->comptask);
+#endif
+}
+
+#ifdef COMP_IN_WQ
+static void comp_work_handler(struct work_struct *work)
+{
+	struct cc_drvdata *drvdata =
+		container_of(work, struct cc_drvdata, compwork.work);
+
+	comp_handler((unsigned long)drvdata);
+}
+#endif
+
+static void proc_completions(struct cc_drvdata *drvdata)
+{
+	struct cc_crypto_req *cc_req;
+	struct device *dev = drvdata_to_dev(drvdata);
+	struct cc_req_mgr_handle *request_mgr_handle =
+						drvdata->request_mgr_handle;
+	unsigned int *tail = &request_mgr_handle->req_queue_tail;
+	unsigned int *head = &request_mgr_handle->req_queue_head;
+
+	while (request_mgr_handle->axi_completed) {
+		request_mgr_handle->axi_completed--;
+
+		/* Dequeue request */
+		if (*head == *tail) {
+			/* We are supposed to handle a completion but our
+			 * queue is empty. This is not normal. Return and
+			 * hope for the best.
+			 */
+			dev_err(dev, "Request queue is empty head == tail %u\n",
+				*head);
+			break;
+		}
+
+		cc_req = &request_mgr_handle->req_queue[*tail];
+
+		if (cc_req->user_cb)
+			cc_req->user_cb(dev, cc_req->user_arg, 0);
+		*tail = (*tail + 1) & (MAX_REQUEST_QUEUE_SIZE - 1);
+		dev_dbg(dev, "Dequeue request tail=%u\n", *tail);
+		dev_dbg(dev, "Request completed. axi_completed=%d\n",
+			request_mgr_handle->axi_completed);
+		cc_pm_put_suspend(dev);
+	}
+}
+
+static inline u32 cc_axi_comp_count(struct cc_drvdata *drvdata)
+{
+	return FIELD_GET(AXIM_MON_COMP_VALUE,
+			 cc_ioread(drvdata, CC_REG(AXIM_MON_COMP)));
+}
+
+/* Deferred service handler, run as interrupt-fired tasklet */
+static void comp_handler(unsigned long devarg)
+{
+	struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg;
+	struct cc_req_mgr_handle *request_mgr_handle =
+						drvdata->request_mgr_handle;
+
+	u32 irq;
+
+	irq = (drvdata->irq & CC_COMP_IRQ_MASK);
+
+	if (irq & CC_COMP_IRQ_MASK) {
+		/* To avoid the interrupt from firing as we unmask it,
+		 * we clear it now
+		 */
+		cc_iowrite(drvdata, CC_REG(HOST_ICR), CC_COMP_IRQ_MASK);
+
+		/* Avoid race with above clear: Test completion counter
+		 * once more
+		 */
+		request_mgr_handle->axi_completed +=
+				cc_axi_comp_count(drvdata);
+
+		while (request_mgr_handle->axi_completed) {
+			do {
+				proc_completions(drvdata);
+				/* At this point (after proc_completions()),
+				 * request_mgr_handle->axi_completed is 0.
+				 */
+				request_mgr_handle->axi_completed =
+						cc_axi_comp_count(drvdata);
+			} while (request_mgr_handle->axi_completed > 0);
+
+			cc_iowrite(drvdata, CC_REG(HOST_ICR),
+				   CC_COMP_IRQ_MASK);
+
+			request_mgr_handle->axi_completed +=
+					cc_axi_comp_count(drvdata);
+		}
+	}
+	/* after verifing that there is nothing to do,
+	 * unmask AXI completion interrupt
+	 */
+	cc_iowrite(drvdata, CC_REG(HOST_IMR),
+		   cc_ioread(drvdata, CC_REG(HOST_IMR)) & ~irq);
+
+	cc_proc_backlog(drvdata);
+}
+
+/*
+ * resume the queue configuration - no need to take the lock as this happens
+ * inside the spin lock protection
+ */
+#if defined(CONFIG_PM)
+int cc_resume_req_queue(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *request_mgr_handle =
+		drvdata->request_mgr_handle;
+
+	spin_lock_bh(&request_mgr_handle->hw_lock);
+	request_mgr_handle->is_runtime_suspended = false;
+	spin_unlock_bh(&request_mgr_handle->hw_lock);
+
+	return 0;
+}
+
+/*
+ * suspend the queue configuration. Since it is used for the runtime suspend
+ * only verify that the queue can be suspended.
+ */
+int cc_suspend_req_queue(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *request_mgr_handle =
+						drvdata->request_mgr_handle;
+
+	/* lock the send_request */
+	spin_lock_bh(&request_mgr_handle->hw_lock);
+	if (request_mgr_handle->req_queue_head !=
+	    request_mgr_handle->req_queue_tail) {
+		spin_unlock_bh(&request_mgr_handle->hw_lock);
+		return -EBUSY;
+	}
+	request_mgr_handle->is_runtime_suspended = true;
+	spin_unlock_bh(&request_mgr_handle->hw_lock);
+
+	return 0;
+}
+
+bool cc_req_queue_suspended(struct cc_drvdata *drvdata)
+{
+	struct cc_req_mgr_handle *request_mgr_handle =
+						drvdata->request_mgr_handle;
+
+	return	request_mgr_handle->is_runtime_suspended;
+}
+
+#endif
diff --git a/drivers/crypto/ccree/cc_request_mgr.h b/drivers/crypto/ccree/cc_request_mgr.h
new file mode 100644
index 000000000000..573cb97af085
--- /dev/null
+++ b/drivers/crypto/ccree/cc_request_mgr.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+/* \file cc_request_mgr.h
+ * Request Manager
+ */
+
+#ifndef __REQUEST_MGR_H__
+#define __REQUEST_MGR_H__
+
+#include "cc_hw_queue_defs.h"
+
+int cc_req_mgr_init(struct cc_drvdata *drvdata);
+
+/*!
+ * Enqueue caller request to crypto hardware.
+ *
+ * \param drvdata
+ * \param cc_req The request to enqueue
+ * \param desc The crypto sequence
+ * \param len The crypto sequence length
+ * \param is_dout If "true": completion is handled by the caller
+ *	  If "false": this function adds a dummy descriptor completion
+ *	  and waits upon completion signal.
+ *
+ * \return int Returns -EINPROGRESS or error
+ */
+int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req,
+		    struct cc_hw_desc *desc, unsigned int len,
+		    struct crypto_async_request *req);
+
+int cc_send_sync_request(struct cc_drvdata *drvdata,
+			 struct cc_crypto_req *cc_req, struct cc_hw_desc *desc,
+			 unsigned int len);
+
+int send_request_init(struct cc_drvdata *drvdata, struct cc_hw_desc *desc,
+		      unsigned int len);
+
+void complete_request(struct cc_drvdata *drvdata);
+
+void cc_req_mgr_fini(struct cc_drvdata *drvdata);
+
+#if defined(CONFIG_PM)
+int cc_resume_req_queue(struct cc_drvdata *drvdata);
+
+int cc_suspend_req_queue(struct cc_drvdata *drvdata);
+
+bool cc_req_queue_suspended(struct cc_drvdata *drvdata);
+#endif
+
+#endif /*__REQUEST_MGR_H__*/
diff --git a/drivers/crypto/ccree/cc_sram_mgr.c b/drivers/crypto/ccree/cc_sram_mgr.c
new file mode 100644
index 000000000000..fed877d35d3e
--- /dev/null
+++ b/drivers/crypto/ccree/cc_sram_mgr.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#include "cc_driver.h"
+#include "cc_sram_mgr.h"
+
+/**
+ * struct cc_sram_ctx -Internal RAM context manager
+ * @sram_free_offset:   the offset to the non-allocated area
+ */
+struct cc_sram_ctx {
+	cc_sram_addr_t sram_free_offset;
+};
+
+/**
+ * cc_sram_mgr_fini() - Cleanup SRAM pool.
+ *
+ * @drvdata: Associated device driver context
+ */
+void cc_sram_mgr_fini(struct cc_drvdata *drvdata)
+{
+	/* Free "this" context */
+	kfree(drvdata->sram_mgr_handle);
+}
+
+/**
+ * cc_sram_mgr_init() - Initializes SRAM pool.
+ *      The pool starts right at the beginning of SRAM.
+ *      Returns zero for success, negative value otherwise.
+ *
+ * @drvdata: Associated device driver context
+ */
+int cc_sram_mgr_init(struct cc_drvdata *drvdata)
+{
+	struct cc_sram_ctx *ctx;
+
+	/* Allocate "this" context */
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+
+	if (!ctx)
+		return -ENOMEM;
+
+	drvdata->sram_mgr_handle = ctx;
+
+	return 0;
+}
+
+/*!
+ * Allocated buffer from SRAM pool.
+ * Note: Caller is responsible to free the LAST allocated buffer.
+ * This function does not taking care of any fragmentation may occur
+ * by the order of calls to alloc/free.
+ *
+ * \param drvdata
+ * \param size The requested bytes to allocate
+ */
+cc_sram_addr_t cc_sram_alloc(struct cc_drvdata *drvdata, u32 size)
+{
+	struct cc_sram_ctx *smgr_ctx = drvdata->sram_mgr_handle;
+	struct device *dev = drvdata_to_dev(drvdata);
+	cc_sram_addr_t p;
+
+	if ((size & 0x3)) {
+		dev_err(dev, "Requested buffer size (%u) is not multiple of 4",
+			size);
+		return NULL_SRAM_ADDR;
+	}
+	if (size > (CC_CC_SRAM_SIZE - smgr_ctx->sram_free_offset)) {
+		dev_err(dev, "Not enough space to allocate %u B (at offset %llu)\n",
+			size, smgr_ctx->sram_free_offset);
+		return NULL_SRAM_ADDR;
+	}
+
+	p = smgr_ctx->sram_free_offset;
+	smgr_ctx->sram_free_offset += size;
+	dev_dbg(dev, "Allocated %u B @ %u\n", size, (unsigned int)p);
+	return p;
+}
+
+/**
+ * cc_set_sram_desc() - Create const descriptors sequence to
+ *	set values in given array into SRAM.
+ * Note: each const value can't exceed word size.
+ *
+ * @src:	  A pointer to array of words to set as consts.
+ * @dst:	  The target SRAM buffer to set into
+ * @nelements:	  The number of words in "src" array
+ * @seq:	  A pointer to the given IN/OUT descriptor sequence
+ * @seq_len:	  A pointer to the given IN/OUT sequence length
+ */
+void cc_set_sram_desc(const u32 *src, cc_sram_addr_t dst,
+		      unsigned int nelement, struct cc_hw_desc *seq,
+		      unsigned int *seq_len)
+{
+	u32 i;
+	unsigned int idx = *seq_len;
+
+	for (i = 0; i < nelement; i++, idx++) {
+		hw_desc_init(&seq[idx]);
+		set_din_const(&seq[idx], src[i], sizeof(u32));
+		set_dout_sram(&seq[idx], dst + (i * sizeof(u32)), sizeof(u32));
+		set_flow_mode(&seq[idx], BYPASS);
+	}
+
+	*seq_len = idx;
+}
diff --git a/drivers/crypto/ccree/cc_sram_mgr.h b/drivers/crypto/ccree/cc_sram_mgr.h
new file mode 100644
index 000000000000..d48649fb3323
--- /dev/null
+++ b/drivers/crypto/ccree/cc_sram_mgr.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
+
+#ifndef __CC_SRAM_MGR_H__
+#define __CC_SRAM_MGR_H__
+
+#ifndef CC_CC_SRAM_SIZE
+#define CC_CC_SRAM_SIZE 4096
+#endif
+
+struct cc_drvdata;
+
+/**
+ * Address (offset) within CC internal SRAM
+ */
+
+typedef u64 cc_sram_addr_t;
+
+#define NULL_SRAM_ADDR ((cc_sram_addr_t)-1)
+
+/*!
+ * Initializes SRAM pool.
+ * The first X bytes of SRAM are reserved for ROM usage, hence, pool
+ * starts right after X bytes.
+ *
+ * \param drvdata
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int cc_sram_mgr_init(struct cc_drvdata *drvdata);
+
+/*!
+ * Uninits SRAM pool.
+ *
+ * \param drvdata
+ */
+void cc_sram_mgr_fini(struct cc_drvdata *drvdata);
+
+/*!
+ * Allocated buffer from SRAM pool.
+ * Note: Caller is responsible to free the LAST allocated buffer.
+ * This function does not taking care of any fragmentation may occur
+ * by the order of calls to alloc/free.
+ *
+ * \param drvdata
+ * \param size The requested bytes to allocate
+ */
+cc_sram_addr_t cc_sram_alloc(struct cc_drvdata *drvdata, u32 size);
+
+/**
+ * cc_set_sram_desc() - Create const descriptors sequence to
+ *	set values in given array into SRAM.
+ * Note: each const value can't exceed word size.
+ *
+ * @src:	  A pointer to array of words to set as consts.
+ * @dst:	  The target SRAM buffer to set into
+ * @nelements:	  The number of words in "src" array
+ * @seq:	  A pointer to the given IN/OUT descriptor sequence
+ * @seq_len:	  A pointer to the given IN/OUT sequence length
+ */
+void cc_set_sram_desc(const u32 *src, cc_sram_addr_t dst,
+		      unsigned int nelement, struct cc_hw_desc *seq,
+		      unsigned int *seq_len);
+
+#endif /*__CC_SRAM_MGR_H__*/
diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c
index 34a02d690548..8a67884512e4 100644
--- a/drivers/crypto/chelsio/chcr_algo.c
+++ b/drivers/crypto/chelsio/chcr_algo.c
@@ -2636,10 +2636,10 @@ static void fill_sec_cpl_for_aead(struct cpl_tx_sec_pdu *sec_cpl,
 					0, dst_size);
 }
 
-int aead_ccm_validate_input(unsigned short op_type,
-			    struct aead_request *req,
-			    struct chcr_aead_ctx *aeadctx,
-			    unsigned int sub_type)
+static int aead_ccm_validate_input(unsigned short op_type,
+				   struct aead_request *req,
+				   struct chcr_aead_ctx *aeadctx,
+				   unsigned int sub_type)
 {
 	if (sub_type != CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) {
 		if (crypto_ccm_check_iv(req->iv)) {
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index 764be3e6933c..a10c418d4e5c 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -759,6 +759,16 @@ static int dcp_sha_digest(struct ahash_request *req)
 	return dcp_sha_finup(req);
 }
 
+static int dcp_sha_noimport(struct ahash_request *req, const void *in)
+{
+	return -ENOSYS;
+}
+
+static int dcp_sha_noexport(struct ahash_request *req, void *out)
+{
+	return -ENOSYS;
+}
+
 static int dcp_sha_cra_init(struct crypto_tfm *tfm)
 {
 	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
@@ -829,6 +839,8 @@ static struct ahash_alg dcp_sha1_alg = {
 	.final	= dcp_sha_final,
 	.finup	= dcp_sha_finup,
 	.digest	= dcp_sha_digest,
+	.import = dcp_sha_noimport,
+	.export = dcp_sha_noexport,
 	.halg	= {
 		.digestsize	= SHA1_DIGEST_SIZE,
 		.base		= {
@@ -853,6 +865,8 @@ static struct ahash_alg dcp_sha256_alg = {
 	.final	= dcp_sha_final,
 	.finup	= dcp_sha_finup,
 	.digest	= dcp_sha_digest,
+	.import = dcp_sha_noimport,
+	.export = dcp_sha_noexport,
 	.halg	= {
 		.digestsize	= SHA256_DIGEST_SIZE,
 		.base		= {
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 662e709812cc..80e9c842aad4 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -359,6 +359,16 @@ static int n2_hash_async_finup(struct ahash_request *req)
 	return crypto_ahash_finup(&rctx->fallback_req);
 }
 
+static int n2_hash_async_noimport(struct ahash_request *req, const void *in)
+{
+	return -ENOSYS;
+}
+
+static int n2_hash_async_noexport(struct ahash_request *req, void *out)
+{
+	return -ENOSYS;
+}
+
 static int n2_hash_cra_init(struct crypto_tfm *tfm)
 {
 	const char *fallback_driver_name = crypto_tfm_alg_name(tfm);
@@ -1467,6 +1477,8 @@ static int __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
 	ahash->final = n2_hash_async_final;
 	ahash->finup = n2_hash_async_finup;
 	ahash->digest = n2_hash_async_digest;
+	ahash->export = n2_hash_async_noexport;
+	ahash->import = n2_hash_async_noimport;
 
 	halg = &ahash->halg;
 	halg->digestsize = tmpl->digest_size;
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index fbec0a2e76dd..5bd383ed3dec 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -388,7 +388,7 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
 
 	pr_debug("err: %d\n", err);
 
-	crypto_finalize_cipher_request(dd->engine, req, err);
+	crypto_finalize_ablkcipher_request(dd->engine, req, err);
 
 	pm_runtime_mark_last_busy(dd->dev);
 	pm_runtime_put_autosuspend(dd->dev);
@@ -408,14 +408,15 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
 				 struct ablkcipher_request *req)
 {
 	if (req)
-		return crypto_transfer_cipher_request_to_engine(dd->engine, req);
+		return crypto_transfer_ablkcipher_request_to_engine(dd->engine, req);
 
 	return 0;
 }
 
 static int omap_aes_prepare_req(struct crypto_engine *engine,
-				struct ablkcipher_request *req)
+				void *areq)
 {
+	struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
 	struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
 			crypto_ablkcipher_reqtfm(req));
 	struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
@@ -468,8 +469,9 @@ static int omap_aes_prepare_req(struct crypto_engine *engine,
 }
 
 static int omap_aes_crypt_req(struct crypto_engine *engine,
-			      struct ablkcipher_request *req)
+			      void *areq)
 {
+	struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
 	struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
 	struct omap_aes_dev *dd = rctx->dd;
 
@@ -601,6 +603,11 @@ static int omap_aes_ctr_decrypt(struct ablkcipher_request *req)
 	return omap_aes_crypt(req, FLAGS_CTR);
 }
 
+static int omap_aes_prepare_req(struct crypto_engine *engine,
+				void *req);
+static int omap_aes_crypt_req(struct crypto_engine *engine,
+			      void *req);
+
 static int omap_aes_cra_init(struct crypto_tfm *tfm)
 {
 	const char *name = crypto_tfm_alg_name(tfm);
@@ -616,6 +623,10 @@ static int omap_aes_cra_init(struct crypto_tfm *tfm)
 
 	tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
 
+	ctx->enginectx.op.prepare_request = omap_aes_prepare_req;
+	ctx->enginectx.op.unprepare_request = NULL;
+	ctx->enginectx.op.do_one_request = omap_aes_crypt_req;
+
 	return 0;
 }
 
@@ -1119,8 +1130,6 @@ static int omap_aes_probe(struct platform_device *pdev)
 		goto err_engine;
 	}
 
-	dd->engine->prepare_cipher_request = omap_aes_prepare_req;
-	dd->engine->cipher_one_request = omap_aes_crypt_req;
 	err = crypto_engine_start(dd->engine);
 	if (err)
 		goto err_engine;
diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h
index 8906342e2b9a..fc3b46a85809 100644
--- a/drivers/crypto/omap-aes.h
+++ b/drivers/crypto/omap-aes.h
@@ -13,6 +13,8 @@
 #ifndef __OMAP_AES_H__
 #define __OMAP_AES_H__
 
+#include <crypto/engine.h>
+
 #define DST_MAXBURST			4
 #define DMA_MIN				(DST_MAXBURST * sizeof(u32))
 
@@ -95,6 +97,7 @@ struct omap_aes_gcm_result {
 };
 
 struct omap_aes_ctx {
+	struct crypto_engine_ctx enginectx;
 	int		keylen;
 	u32		key[AES_KEYSIZE_256 / sizeof(u32)];
 	u8		nonce[4];
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index ebc5c0f11f03..eb95b0d7f184 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -86,6 +86,7 @@
 #define FLAGS_OUT_DATA_ST_SHIFT	10
 
 struct omap_des_ctx {
+	struct crypto_engine_ctx enginectx;
 	struct omap_des_dev *dd;
 
 	int		keylen;
@@ -498,7 +499,7 @@ static void omap_des_finish_req(struct omap_des_dev *dd, int err)
 
 	pr_debug("err: %d\n", err);
 
-	crypto_finalize_cipher_request(dd->engine, req, err);
+	crypto_finalize_ablkcipher_request(dd->engine, req, err);
 
 	pm_runtime_mark_last_busy(dd->dev);
 	pm_runtime_put_autosuspend(dd->dev);
@@ -520,14 +521,15 @@ static int omap_des_handle_queue(struct omap_des_dev *dd,
 				 struct ablkcipher_request *req)
 {
 	if (req)
-		return crypto_transfer_cipher_request_to_engine(dd->engine, req);
+		return crypto_transfer_ablkcipher_request_to_engine(dd->engine, req);
 
 	return 0;
 }
 
 static int omap_des_prepare_req(struct crypto_engine *engine,
-				struct ablkcipher_request *req)
+				void *areq)
 {
+	struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
 	struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
 			crypto_ablkcipher_reqtfm(req));
 	struct omap_des_dev *dd = omap_des_find_dev(ctx);
@@ -582,8 +584,9 @@ static int omap_des_prepare_req(struct crypto_engine *engine,
 }
 
 static int omap_des_crypt_req(struct crypto_engine *engine,
-			      struct ablkcipher_request *req)
+			      void *areq)
 {
+	struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
 	struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
 			crypto_ablkcipher_reqtfm(req));
 	struct omap_des_dev *dd = omap_des_find_dev(ctx);
@@ -695,12 +698,23 @@ static int omap_des_cbc_decrypt(struct ablkcipher_request *req)
 	return omap_des_crypt(req, FLAGS_CBC);
 }
 
+static int omap_des_prepare_req(struct crypto_engine *engine,
+				void *areq);
+static int omap_des_crypt_req(struct crypto_engine *engine,
+			      void *areq);
+
 static int omap_des_cra_init(struct crypto_tfm *tfm)
 {
+	struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm);
+
 	pr_debug("enter\n");
 
 	tfm->crt_ablkcipher.reqsize = sizeof(struct omap_des_reqctx);
 
+	ctx->enginectx.op.prepare_request = omap_des_prepare_req;
+	ctx->enginectx.op.unprepare_request = NULL;
+	ctx->enginectx.op.do_one_request = omap_des_crypt_req;
+
 	return 0;
 }
 
@@ -1046,8 +1060,6 @@ static int omap_des_probe(struct platform_device *pdev)
 		goto err_engine;
 	}
 
-	dd->engine->prepare_cipher_request = omap_des_prepare_req;
-	dd->engine->cipher_one_request = omap_des_crypt_req;
 	err = crypto_engine_start(dd->engine);
 	if (err)
 		goto err_engine;
diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
index 13c52d6bf630..320e7854b4ee 100644
--- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
@@ -969,7 +969,8 @@ static int qat_rsa_dec(struct akcipher_request *req)
 	return ret;
 }
 
-int qat_rsa_set_n(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
+static int qat_rsa_set_n(struct qat_rsa_ctx *ctx, const char *value,
+			 size_t vlen)
 {
 	struct qat_crypto_instance *inst = ctx->inst;
 	struct device *dev = &GET_DEV(inst->accel_dev);
@@ -1000,7 +1001,8 @@ int qat_rsa_set_n(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
 	return ret;
 }
 
-int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
+static int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value,
+			 size_t vlen)
 {
 	struct qat_crypto_instance *inst = ctx->inst;
 	struct device *dev = &GET_DEV(inst->accel_dev);
@@ -1024,7 +1026,8 @@ int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
 	return 0;
 }
 
-int qat_rsa_set_d(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
+static int qat_rsa_set_d(struct qat_rsa_ctx *ctx, const char *value,
+			 size_t vlen)
 {
 	struct qat_crypto_instance *inst = ctx->inst;
 	struct device *dev = &GET_DEV(inst->accel_dev);
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index 188f44b7eb27..5d64c08b7f47 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -1922,15 +1922,21 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
 	uint32_t aes_control;
 	unsigned long flags;
 	int err;
+	u8 *iv;
 
 	aes_control = SSS_AES_KEY_CHANGE_MODE;
 	if (mode & FLAGS_AES_DECRYPT)
 		aes_control |= SSS_AES_MODE_DECRYPT;
 
-	if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
+	if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
 		aes_control |= SSS_AES_CHAIN_MODE_CBC;
-	else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
+		iv = req->info;
+	} else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
 		aes_control |= SSS_AES_CHAIN_MODE_CTR;
+		iv = req->info;
+	} else {
+		iv = NULL; /* AES_ECB */
+	}
 
 	if (dev->ctx->keylen == AES_KEYSIZE_192)
 		aes_control |= SSS_AES_KEY_SIZE_192;
@@ -1961,7 +1967,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
 		goto outdata_error;
 
 	SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
-	s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
+	s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
 
 	s5p_set_dma_indata(dev,  dev->sg_src);
 	s5p_set_dma_outdata(dev, dev->sg_dst);
diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c
index 4a06a7a665ee..c5d3efc54a4f 100644
--- a/drivers/crypto/stm32/stm32-cryp.c
+++ b/drivers/crypto/stm32/stm32-cryp.c
@@ -17,6 +17,7 @@
 #include <crypto/des.h>
 #include <crypto/engine.h>
 #include <crypto/scatterwalk.h>
+#include <crypto/internal/aead.h>
 
 #define DRIVER_NAME             "stm32-cryp"
 
@@ -29,8 +30,12 @@
 #define FLG_ECB                 BIT(4)
 #define FLG_CBC                 BIT(5)
 #define FLG_CTR                 BIT(6)
+#define FLG_GCM                 BIT(7)
+#define FLG_CCM                 BIT(8)
 /* Mode mask = bits [15..0] */
 #define FLG_MODE_MASK           GENMASK(15, 0)
+/* Bit [31..16] status  */
+#define FLG_CCM_PADDED_WA       BIT(16)
 
 /* Registers */
 #define CRYP_CR                 0x00000000
@@ -53,6 +58,8 @@
 #define CRYP_IV0RR              0x00000044
 #define CRYP_IV1LR              0x00000048
 #define CRYP_IV1RR              0x0000004C
+#define CRYP_CSGCMCCM0R         0x00000050
+#define CRYP_CSGCM0R            0x00000070
 
 /* Registers values */
 #define CR_DEC_NOT_ENC          0x00000004
@@ -64,6 +71,8 @@
 #define CR_AES_CBC              0x00000028
 #define CR_AES_CTR              0x00000030
 #define CR_AES_KP               0x00000038
+#define CR_AES_GCM              0x00080000
+#define CR_AES_CCM              0x00080008
 #define CR_AES_UNKNOWN          0xFFFFFFFF
 #define CR_ALGO_MASK            0x00080038
 #define CR_DATA32               0x00000000
@@ -75,6 +84,12 @@
 #define CR_KEY256               0x00000200
 #define CR_FFLUSH               0x00004000
 #define CR_CRYPEN               0x00008000
+#define CR_PH_INIT              0x00000000
+#define CR_PH_HEADER            0x00010000
+#define CR_PH_PAYLOAD           0x00020000
+#define CR_PH_FINAL             0x00030000
+#define CR_PH_MASK              0x00030000
+#define CR_NBPBL_SHIFT          20
 
 #define SR_BUSY                 0x00000010
 #define SR_OFNE                 0x00000004
@@ -87,10 +102,17 @@
 
 /* Misc */
 #define AES_BLOCK_32            (AES_BLOCK_SIZE / sizeof(u32))
+#define GCM_CTR_INIT            2
 #define _walked_in              (cryp->in_walk.offset - cryp->in_sg->offset)
 #define _walked_out             (cryp->out_walk.offset - cryp->out_sg->offset)
 
+struct stm32_cryp_caps {
+	bool                    swap_final;
+	bool                    padding_wa;
+};
+
 struct stm32_cryp_ctx {
+	struct crypto_engine_ctx enginectx;
 	struct stm32_cryp       *cryp;
 	int                     keylen;
 	u32                     key[AES_KEYSIZE_256 / sizeof(u32)];
@@ -108,13 +130,16 @@ struct stm32_cryp {
 	struct clk              *clk;
 	unsigned long           flags;
 	u32                     irq_status;
+	const struct stm32_cryp_caps *caps;
 	struct stm32_cryp_ctx   *ctx;
 
 	struct crypto_engine    *engine;
 
-	struct mutex            lock; /* protects req */
+	struct mutex            lock; /* protects req / areq */
 	struct ablkcipher_request *req;
+	struct aead_request     *areq;
 
+	size_t                  authsize;
 	size_t                  hw_blocksize;
 
 	size_t                  total_in;
@@ -137,6 +162,7 @@ struct stm32_cryp {
 	struct scatter_walk     out_walk;
 
 	u32                     last_ctr[4];
+	u32                     gcm_ctr;
 };
 
 struct stm32_cryp_list {
@@ -179,6 +205,16 @@ static inline bool is_ctr(struct stm32_cryp *cryp)
 	return cryp->flags & FLG_CTR;
 }
 
+static inline bool is_gcm(struct stm32_cryp *cryp)
+{
+	return cryp->flags & FLG_GCM;
+}
+
+static inline bool is_ccm(struct stm32_cryp *cryp)
+{
+	return cryp->flags & FLG_CCM;
+}
+
 static inline bool is_encrypt(struct stm32_cryp *cryp)
 {
 	return cryp->flags & FLG_ENCRYPT;
@@ -207,6 +243,24 @@ static inline int stm32_cryp_wait_busy(struct stm32_cryp *cryp)
 			!(status & SR_BUSY), 10, 100000);
 }
 
+static inline int stm32_cryp_wait_enable(struct stm32_cryp *cryp)
+{
+	u32 status;
+
+	return readl_relaxed_poll_timeout(cryp->regs + CRYP_CR, status,
+			!(status & CR_CRYPEN), 10, 100000);
+}
+
+static inline int stm32_cryp_wait_output(struct stm32_cryp *cryp)
+{
+	u32 status;
+
+	return readl_relaxed_poll_timeout(cryp->regs + CRYP_SR, status,
+			status & SR_OFNE, 10, 100000);
+}
+
+static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp);
+
 static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx)
 {
 	struct stm32_cryp *tmp, *cryp = NULL;
@@ -365,6 +419,12 @@ static u32 stm32_cryp_get_hw_mode(struct stm32_cryp *cryp)
 	if (is_aes(cryp) && is_ctr(cryp))
 		return CR_AES_CTR;
 
+	if (is_aes(cryp) && is_gcm(cryp))
+		return CR_AES_GCM;
+
+	if (is_aes(cryp) && is_ccm(cryp))
+		return CR_AES_CCM;
+
 	if (is_des(cryp) && is_ecb(cryp))
 		return CR_DES_ECB;
 
@@ -381,6 +441,79 @@ static u32 stm32_cryp_get_hw_mode(struct stm32_cryp *cryp)
 	return CR_AES_UNKNOWN;
 }
 
+static unsigned int stm32_cryp_get_input_text_len(struct stm32_cryp *cryp)
+{
+	return is_encrypt(cryp) ? cryp->areq->cryptlen :
+				  cryp->areq->cryptlen - cryp->authsize;
+}
+
+static int stm32_cryp_gcm_init(struct stm32_cryp *cryp, u32 cfg)
+{
+	int ret;
+	u32 iv[4];
+
+	/* Phase 1 : init */
+	memcpy(iv, cryp->areq->iv, 12);
+	iv[3] = cpu_to_be32(GCM_CTR_INIT);
+	cryp->gcm_ctr = GCM_CTR_INIT;
+	stm32_cryp_hw_write_iv(cryp, iv);
+
+	stm32_cryp_write(cryp, CRYP_CR, cfg | CR_PH_INIT | CR_CRYPEN);
+
+	/* Wait for end of processing */
+	ret = stm32_cryp_wait_enable(cryp);
+	if (ret)
+		dev_err(cryp->dev, "Timeout (gcm init)\n");
+
+	return ret;
+}
+
+static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg)
+{
+	int ret;
+	u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE];
+	u32 *d;
+	unsigned int i, textlen;
+
+	/* Phase 1 : init. Firstly set the CTR value to 1 (not 0) */
+	memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE);
+	memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
+	iv[AES_BLOCK_SIZE - 1] = 1;
+	stm32_cryp_hw_write_iv(cryp, (u32 *)iv);
+
+	/* Build B0 */
+	memcpy(b0, iv, AES_BLOCK_SIZE);
+
+	b0[0] |= (8 * ((cryp->authsize - 2) / 2));
+
+	if (cryp->areq->assoclen)
+		b0[0] |= 0x40;
+
+	textlen = stm32_cryp_get_input_text_len(cryp);
+
+	b0[AES_BLOCK_SIZE - 2] = textlen >> 8;
+	b0[AES_BLOCK_SIZE - 1] = textlen & 0xFF;
+
+	/* Enable HW */
+	stm32_cryp_write(cryp, CRYP_CR, cfg | CR_PH_INIT | CR_CRYPEN);
+
+	/* Write B0 */
+	d = (u32 *)b0;
+
+	for (i = 0; i < AES_BLOCK_32; i++) {
+		if (!cryp->caps->padding_wa)
+			*d = cpu_to_be32(*d);
+		stm32_cryp_write(cryp, CRYP_DIN, *d++);
+	}
+
+	/* Wait for end of processing */
+	ret = stm32_cryp_wait_enable(cryp);
+	if (ret)
+		dev_err(cryp->dev, "Timeout (ccm init)\n");
+
+	return ret;
+}
+
 static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
 {
 	int ret;
@@ -436,6 +569,29 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
 	stm32_cryp_write(cryp, CRYP_CR, cfg);
 
 	switch (hw_mode) {
+	case CR_AES_GCM:
+	case CR_AES_CCM:
+		/* Phase 1 : init */
+		if (hw_mode == CR_AES_CCM)
+			ret = stm32_cryp_ccm_init(cryp, cfg);
+		else
+			ret = stm32_cryp_gcm_init(cryp, cfg);
+
+		if (ret)
+			return ret;
+
+		/* Phase 2 : header (authenticated data) */
+		if (cryp->areq->assoclen) {
+			cfg |= CR_PH_HEADER;
+		} else if (stm32_cryp_get_input_text_len(cryp)) {
+			cfg |= CR_PH_PAYLOAD;
+			stm32_cryp_write(cryp, CRYP_CR, cfg);
+		} else {
+			cfg |= CR_PH_INIT;
+		}
+
+		break;
+
 	case CR_DES_CBC:
 	case CR_TDES_CBC:
 	case CR_AES_CBC:
@@ -452,12 +608,16 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
 
 	stm32_cryp_write(cryp, CRYP_CR, cfg);
 
+	cryp->flags &= ~FLG_CCM_PADDED_WA;
+
 	return 0;
 }
 
-static void stm32_cryp_finish_req(struct stm32_cryp *cryp)
+static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err)
 {
-	int err = 0;
+	if (!err && (is_gcm(cryp) || is_ccm(cryp)))
+		/* Phase 4 : output tag */
+		err = stm32_cryp_read_auth_tag(cryp);
 
 	if (cryp->sgs_copied) {
 		void *buf_in, *buf_out;
@@ -478,8 +638,14 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp)
 		free_pages((unsigned long)buf_out, pages);
 	}
 
-	crypto_finalize_cipher_request(cryp->engine, cryp->req, err);
-	cryp->req = NULL;
+	if (is_gcm(cryp) || is_ccm(cryp)) {
+		crypto_finalize_aead_request(cryp->engine, cryp->areq, err);
+		cryp->areq = NULL;
+	} else {
+		crypto_finalize_ablkcipher_request(cryp->engine, cryp->req,
+						   err);
+		cryp->req = NULL;
+	}
 
 	memset(cryp->ctx->key, 0, cryp->ctx->keylen);
 
@@ -494,10 +660,36 @@ static int stm32_cryp_cpu_start(struct stm32_cryp *cryp)
 	return 0;
 }
 
+static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq);
+static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine,
+					 void *areq);
+
 static int stm32_cryp_cra_init(struct crypto_tfm *tfm)
 {
+	struct stm32_cryp_ctx *ctx = crypto_tfm_ctx(tfm);
+
 	tfm->crt_ablkcipher.reqsize = sizeof(struct stm32_cryp_reqctx);
 
+	ctx->enginectx.op.do_one_request = stm32_cryp_cipher_one_req;
+	ctx->enginectx.op.prepare_request = stm32_cryp_prepare_cipher_req;
+	ctx->enginectx.op.unprepare_request = NULL;
+	return 0;
+}
+
+static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq);
+static int stm32_cryp_prepare_aead_req(struct crypto_engine *engine,
+				       void *areq);
+
+static int stm32_cryp_aes_aead_init(struct crypto_aead *tfm)
+{
+	struct stm32_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+	tfm->reqsize = sizeof(struct stm32_cryp_reqctx);
+
+	ctx->enginectx.op.do_one_request = stm32_cryp_aead_one_req;
+	ctx->enginectx.op.prepare_request = stm32_cryp_prepare_aead_req;
+	ctx->enginectx.op.unprepare_request = NULL;
+
 	return 0;
 }
 
@@ -513,7 +705,21 @@ static int stm32_cryp_crypt(struct ablkcipher_request *req, unsigned long mode)
 
 	rctx->mode = mode;
 
-	return crypto_transfer_cipher_request_to_engine(cryp->engine, req);
+	return crypto_transfer_ablkcipher_request_to_engine(cryp->engine, req);
+}
+
+static int stm32_cryp_aead_crypt(struct aead_request *req, unsigned long mode)
+{
+	struct stm32_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+	struct stm32_cryp_reqctx *rctx = aead_request_ctx(req);
+	struct stm32_cryp *cryp = stm32_cryp_find_dev(ctx);
+
+	if (!cryp)
+		return -ENODEV;
+
+	rctx->mode = mode;
+
+	return crypto_transfer_aead_request_to_engine(cryp->engine, req);
 }
 
 static int stm32_cryp_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
@@ -555,6 +761,46 @@ static int stm32_cryp_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
 		return stm32_cryp_setkey(tfm, key, keylen);
 }
 
+static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+				      unsigned int keylen)
+{
+	struct stm32_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+	if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+	    keylen != AES_KEYSIZE_256)
+		return -EINVAL;
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	return 0;
+}
+
+static int stm32_cryp_aes_gcm_setauthsize(struct crypto_aead *tfm,
+					  unsigned int authsize)
+{
+	return authsize == AES_BLOCK_SIZE ? 0 : -EINVAL;
+}
+
+static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm,
+					  unsigned int authsize)
+{
+	switch (authsize) {
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int stm32_cryp_aes_ecb_encrypt(struct ablkcipher_request *req)
 {
 	return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT);
@@ -585,6 +831,26 @@ static int stm32_cryp_aes_ctr_decrypt(struct ablkcipher_request *req)
 	return stm32_cryp_crypt(req, FLG_AES | FLG_CTR);
 }
 
+static int stm32_cryp_aes_gcm_encrypt(struct aead_request *req)
+{
+	return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM | FLG_ENCRYPT);
+}
+
+static int stm32_cryp_aes_gcm_decrypt(struct aead_request *req)
+{
+	return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM);
+}
+
+static int stm32_cryp_aes_ccm_encrypt(struct aead_request *req)
+{
+	return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM | FLG_ENCRYPT);
+}
+
+static int stm32_cryp_aes_ccm_decrypt(struct aead_request *req)
+{
+	return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM);
+}
+
 static int stm32_cryp_des_ecb_encrypt(struct ablkcipher_request *req)
 {
 	return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT);
@@ -625,18 +891,19 @@ static int stm32_cryp_tdes_cbc_decrypt(struct ablkcipher_request *req)
 	return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC);
 }
 
-static int stm32_cryp_prepare_req(struct crypto_engine *engine,
-				  struct ablkcipher_request *req)
+static int stm32_cryp_prepare_req(struct ablkcipher_request *req,
+				  struct aead_request *areq)
 {
 	struct stm32_cryp_ctx *ctx;
 	struct stm32_cryp *cryp;
 	struct stm32_cryp_reqctx *rctx;
 	int ret;
 
-	if (!req)
+	if (!req && !areq)
 		return -EINVAL;
 
-	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+	ctx = req ? crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)) :
+		    crypto_aead_ctx(crypto_aead_reqtfm(areq));
 
 	cryp = ctx->cryp;
 
@@ -645,7 +912,7 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
 
 	mutex_lock(&cryp->lock);
 
-	rctx = ablkcipher_request_ctx(req);
+	rctx = req ? ablkcipher_request_ctx(req) : aead_request_ctx(areq);
 	rctx->mode &= FLG_MODE_MASK;
 
 	ctx->cryp = cryp;
@@ -654,15 +921,48 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
 	cryp->hw_blocksize = is_aes(cryp) ? AES_BLOCK_SIZE : DES_BLOCK_SIZE;
 	cryp->ctx = ctx;
 
-	cryp->req = req;
-	cryp->total_in = req->nbytes;
-	cryp->total_out = cryp->total_in;
+	if (req) {
+		cryp->req = req;
+		cryp->total_in = req->nbytes;
+		cryp->total_out = cryp->total_in;
+	} else {
+		/*
+		 * Length of input and output data:
+		 * Encryption case:
+		 *  INPUT  =   AssocData  ||   PlainText
+		 *          <- assoclen ->  <- cryptlen ->
+		 *          <------- total_in ----------->
+		 *
+		 *  OUTPUT =   AssocData  ||  CipherText  ||   AuthTag
+		 *          <- assoclen ->  <- cryptlen ->  <- authsize ->
+		 *          <---------------- total_out ----------------->
+		 *
+		 * Decryption case:
+		 *  INPUT  =   AssocData  ||  CipherText  ||  AuthTag
+		 *          <- assoclen ->  <--------- cryptlen --------->
+		 *                                          <- authsize ->
+		 *          <---------------- total_in ------------------>
+		 *
+		 *  OUTPUT =   AssocData  ||   PlainText
+		 *          <- assoclen ->  <- crypten - authsize ->
+		 *          <---------- total_out ----------------->
+		 */
+		cryp->areq = areq;
+		cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq));
+		cryp->total_in = areq->assoclen + areq->cryptlen;
+		if (is_encrypt(cryp))
+			/* Append auth tag to output */
+			cryp->total_out = cryp->total_in + cryp->authsize;
+		else
+			/* No auth tag in output */
+			cryp->total_out = cryp->total_in - cryp->authsize;
+	}
 
 	cryp->total_in_save = cryp->total_in;
 	cryp->total_out_save = cryp->total_out;
 
-	cryp->in_sg = req->src;
-	cryp->out_sg = req->dst;
+	cryp->in_sg = req ? req->src : areq->src;
+	cryp->out_sg = req ? req->dst : areq->dst;
 	cryp->out_sg_save = cryp->out_sg;
 
 	cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in);
@@ -686,6 +986,12 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
 	scatterwalk_start(&cryp->in_walk, cryp->in_sg);
 	scatterwalk_start(&cryp->out_walk, cryp->out_sg);
 
+	if (is_gcm(cryp) || is_ccm(cryp)) {
+		/* In output, jump after assoc data */
+		scatterwalk_advance(&cryp->out_walk, cryp->areq->assoclen);
+		cryp->total_out -= cryp->areq->assoclen;
+	}
+
 	ret = stm32_cryp_hw_init(cryp);
 out:
 	if (ret)
@@ -695,14 +1001,20 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
 }
 
 static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine,
-					 struct ablkcipher_request *req)
+					 void *areq)
 {
-	return stm32_cryp_prepare_req(engine, req);
+	struct ablkcipher_request *req = container_of(areq,
+						      struct ablkcipher_request,
+						      base);
+
+	return stm32_cryp_prepare_req(req, NULL);
 }
 
-static int stm32_cryp_cipher_one_req(struct crypto_engine *engine,
-				     struct ablkcipher_request *req)
+static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq)
 {
+	struct ablkcipher_request *req = container_of(areq,
+						      struct ablkcipher_request,
+						      base);
 	struct stm32_cryp_ctx *ctx = crypto_ablkcipher_ctx(
 			crypto_ablkcipher_reqtfm(req));
 	struct stm32_cryp *cryp = ctx->cryp;
@@ -713,6 +1025,34 @@ static int stm32_cryp_cipher_one_req(struct crypto_engine *engine,
 	return stm32_cryp_cpu_start(cryp);
 }
 
+static int stm32_cryp_prepare_aead_req(struct crypto_engine *engine, void *areq)
+{
+	struct aead_request *req = container_of(areq, struct aead_request,
+						base);
+
+	return stm32_cryp_prepare_req(NULL, req);
+}
+
+static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq)
+{
+	struct aead_request *req = container_of(areq, struct aead_request,
+						base);
+	struct stm32_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+	struct stm32_cryp *cryp = ctx->cryp;
+
+	if (!cryp)
+		return -ENODEV;
+
+	if (unlikely(!cryp->areq->assoclen &&
+		     !stm32_cryp_get_input_text_len(cryp))) {
+		/* No input data to process: get tag and finish */
+		stm32_cryp_finish_req(cryp, 0);
+		return 0;
+	}
+
+	return stm32_cryp_cpu_start(cryp);
+}
+
 static u32 *stm32_cryp_next_out(struct stm32_cryp *cryp, u32 *dst,
 				unsigned int n)
 {
@@ -745,6 +1085,111 @@ static u32 *stm32_cryp_next_in(struct stm32_cryp *cryp, u32 *src,
 	return (u32 *)((u8 *)src + n);
 }
 
+static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp)
+{
+	u32 cfg, size_bit, *dst, d32;
+	u8 *d8;
+	unsigned int i, j;
+	int ret = 0;
+
+	/* Update Config */
+	cfg = stm32_cryp_read(cryp, CRYP_CR);
+
+	cfg &= ~CR_PH_MASK;
+	cfg |= CR_PH_FINAL;
+	cfg &= ~CR_DEC_NOT_ENC;
+	cfg |= CR_CRYPEN;
+
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	if (is_gcm(cryp)) {
+		/* GCM: write aad and payload size (in bits) */
+		size_bit = cryp->areq->assoclen * 8;
+		if (cryp->caps->swap_final)
+			size_bit = cpu_to_be32(size_bit);
+
+		stm32_cryp_write(cryp, CRYP_DIN, 0);
+		stm32_cryp_write(cryp, CRYP_DIN, size_bit);
+
+		size_bit = is_encrypt(cryp) ? cryp->areq->cryptlen :
+				cryp->areq->cryptlen - AES_BLOCK_SIZE;
+		size_bit *= 8;
+		if (cryp->caps->swap_final)
+			size_bit = cpu_to_be32(size_bit);
+
+		stm32_cryp_write(cryp, CRYP_DIN, 0);
+		stm32_cryp_write(cryp, CRYP_DIN, size_bit);
+	} else {
+		/* CCM: write CTR0 */
+		u8 iv[AES_BLOCK_SIZE];
+		u32 *iv32 = (u32 *)iv;
+
+		memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE);
+		memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
+
+		for (i = 0; i < AES_BLOCK_32; i++) {
+			if (!cryp->caps->padding_wa)
+				*iv32 = cpu_to_be32(*iv32);
+			stm32_cryp_write(cryp, CRYP_DIN, *iv32++);
+		}
+	}
+
+	/* Wait for output data */
+	ret = stm32_cryp_wait_output(cryp);
+	if (ret) {
+		dev_err(cryp->dev, "Timeout (read tag)\n");
+		return ret;
+	}
+
+	if (is_encrypt(cryp)) {
+		/* Get and write tag */
+		dst = sg_virt(cryp->out_sg) + _walked_out;
+
+		for (i = 0; i < AES_BLOCK_32; i++) {
+			if (cryp->total_out >= sizeof(u32)) {
+				/* Read a full u32 */
+				*dst = stm32_cryp_read(cryp, CRYP_DOUT);
+
+				dst = stm32_cryp_next_out(cryp, dst,
+							  sizeof(u32));
+				cryp->total_out -= sizeof(u32);
+			} else if (!cryp->total_out) {
+				/* Empty fifo out (data from input padding) */
+				stm32_cryp_read(cryp, CRYP_DOUT);
+			} else {
+				/* Read less than an u32 */
+				d32 = stm32_cryp_read(cryp, CRYP_DOUT);
+				d8 = (u8 *)&d32;
+
+				for (j = 0; j < cryp->total_out; j++) {
+					*((u8 *)dst) = *(d8++);
+					dst = stm32_cryp_next_out(cryp, dst, 1);
+				}
+				cryp->total_out = 0;
+			}
+		}
+	} else {
+		/* Get and check tag */
+		u32 in_tag[AES_BLOCK_32], out_tag[AES_BLOCK_32];
+
+		scatterwalk_map_and_copy(in_tag, cryp->in_sg,
+					 cryp->total_in_save - cryp->authsize,
+					 cryp->authsize, 0);
+
+		for (i = 0; i < AES_BLOCK_32; i++)
+			out_tag[i] = stm32_cryp_read(cryp, CRYP_DOUT);
+
+		if (crypto_memneq(in_tag, out_tag, cryp->authsize))
+			ret = -EBADMSG;
+	}
+
+	/* Disable cryp */
+	cfg &= ~CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	return ret;
+}
+
 static void stm32_cryp_check_ctr_counter(struct stm32_cryp *cryp)
 {
 	u32 cr;
@@ -777,17 +1222,24 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp)
 	unsigned int i, j;
 	u32 d32, *dst;
 	u8 *d8;
+	size_t tag_size;
+
+	/* Do no read tag now (if any) */
+	if (is_encrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp)))
+		tag_size = cryp->authsize;
+	else
+		tag_size = 0;
 
 	dst = sg_virt(cryp->out_sg) + _walked_out;
 
 	for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) {
-		if (likely(cryp->total_out >= sizeof(u32))) {
+		if (likely(cryp->total_out - tag_size >= sizeof(u32))) {
 			/* Read a full u32 */
 			*dst = stm32_cryp_read(cryp, CRYP_DOUT);
 
 			dst = stm32_cryp_next_out(cryp, dst, sizeof(u32));
 			cryp->total_out -= sizeof(u32);
-		} else if (!cryp->total_out) {
+		} else if (cryp->total_out == tag_size) {
 			/* Empty fifo out (data from input padding) */
 			d32 = stm32_cryp_read(cryp, CRYP_DOUT);
 		} else {
@@ -795,15 +1247,15 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp)
 			d32 = stm32_cryp_read(cryp, CRYP_DOUT);
 			d8 = (u8 *)&d32;
 
-			for (j = 0; j < cryp->total_out; j++) {
+			for (j = 0; j < cryp->total_out - tag_size; j++) {
 				*((u8 *)dst) = *(d8++);
 				dst = stm32_cryp_next_out(cryp, dst, 1);
 			}
-			cryp->total_out = 0;
+			cryp->total_out = tag_size;
 		}
 	}
 
-	return !cryp->total_out || !cryp->total_in;
+	return !(cryp->total_out - tag_size) || !cryp->total_in;
 }
 
 static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp)
@@ -811,33 +1263,219 @@ static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp)
 	unsigned int i, j;
 	u32 *src;
 	u8 d8[4];
+	size_t tag_size;
+
+	/* Do no write tag (if any) */
+	if (is_decrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp)))
+		tag_size = cryp->authsize;
+	else
+		tag_size = 0;
 
 	src = sg_virt(cryp->in_sg) + _walked_in;
 
 	for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) {
-		if (likely(cryp->total_in >= sizeof(u32))) {
+		if (likely(cryp->total_in - tag_size >= sizeof(u32))) {
 			/* Write a full u32 */
 			stm32_cryp_write(cryp, CRYP_DIN, *src);
 
 			src = stm32_cryp_next_in(cryp, src, sizeof(u32));
 			cryp->total_in -= sizeof(u32);
-		} else if (!cryp->total_in) {
+		} else if (cryp->total_in == tag_size) {
 			/* Write padding data */
 			stm32_cryp_write(cryp, CRYP_DIN, 0);
 		} else {
 			/* Write less than an u32 */
 			memset(d8, 0, sizeof(u32));
-			for (j = 0; j < cryp->total_in; j++) {
+			for (j = 0; j < cryp->total_in - tag_size; j++) {
 				d8[j] = *((u8 *)src);
 				src = stm32_cryp_next_in(cryp, src, 1);
 			}
 
 			stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
-			cryp->total_in = 0;
+			cryp->total_in = tag_size;
 		}
 	}
 }
 
+static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp)
+{
+	int err;
+	u32 cfg, tmp[AES_BLOCK_32];
+	size_t total_in_ori = cryp->total_in;
+	struct scatterlist *out_sg_ori = cryp->out_sg;
+	unsigned int i;
+
+	/* 'Special workaround' procedure described in the datasheet */
+
+	/* a) disable ip */
+	stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+	cfg = stm32_cryp_read(cryp, CRYP_CR);
+	cfg &= ~CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* b) Update IV1R */
+	stm32_cryp_write(cryp, CRYP_IV1RR, cryp->gcm_ctr - 2);
+
+	/* c) change mode to CTR */
+	cfg &= ~CR_ALGO_MASK;
+	cfg |= CR_AES_CTR;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* a) enable IP */
+	cfg |= CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* b) pad and write the last block */
+	stm32_cryp_irq_write_block(cryp);
+	cryp->total_in = total_in_ori;
+	err = stm32_cryp_wait_output(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Timeout (write gcm header)\n");
+		return stm32_cryp_finish_req(cryp, err);
+	}
+
+	/* c) get and store encrypted data */
+	stm32_cryp_irq_read_data(cryp);
+	scatterwalk_map_and_copy(tmp, out_sg_ori,
+				 cryp->total_in_save - total_in_ori,
+				 total_in_ori, 0);
+
+	/* d) change mode back to AES GCM */
+	cfg &= ~CR_ALGO_MASK;
+	cfg |= CR_AES_GCM;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* e) change phase to Final */
+	cfg &= ~CR_PH_MASK;
+	cfg |= CR_PH_FINAL;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* f) write padded data */
+	for (i = 0; i < AES_BLOCK_32; i++) {
+		if (cryp->total_in)
+			stm32_cryp_write(cryp, CRYP_DIN, tmp[i]);
+		else
+			stm32_cryp_write(cryp, CRYP_DIN, 0);
+
+		cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in);
+	}
+
+	/* g) Empty fifo out */
+	err = stm32_cryp_wait_output(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Timeout (write gcm header)\n");
+		return stm32_cryp_finish_req(cryp, err);
+	}
+
+	for (i = 0; i < AES_BLOCK_32; i++)
+		stm32_cryp_read(cryp, CRYP_DOUT);
+
+	/* h) run the he normal Final phase */
+	stm32_cryp_finish_req(cryp, 0);
+}
+
+static void stm32_cryp_irq_set_npblb(struct stm32_cryp *cryp)
+{
+	u32 cfg, payload_bytes;
+
+	/* disable ip, set NPBLB and reneable ip */
+	cfg = stm32_cryp_read(cryp, CRYP_CR);
+	cfg &= ~CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	payload_bytes = is_decrypt(cryp) ? cryp->total_in - cryp->authsize :
+					   cryp->total_in;
+	cfg |= (cryp->hw_blocksize - payload_bytes) << CR_NBPBL_SHIFT;
+	cfg |= CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+}
+
+static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp)
+{
+	int err = 0;
+	u32 cfg, iv1tmp;
+	u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32], tmp[AES_BLOCK_32];
+	size_t last_total_out, total_in_ori = cryp->total_in;
+	struct scatterlist *out_sg_ori = cryp->out_sg;
+	unsigned int i;
+
+	/* 'Special workaround' procedure described in the datasheet */
+	cryp->flags |= FLG_CCM_PADDED_WA;
+
+	/* a) disable ip */
+	stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+
+	cfg = stm32_cryp_read(cryp, CRYP_CR);
+	cfg &= ~CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* b) get IV1 from CRYP_CSGCMCCM7 */
+	iv1tmp = stm32_cryp_read(cryp, CRYP_CSGCMCCM0R + 7 * 4);
+
+	/* c) Load CRYP_CSGCMCCMxR */
+	for (i = 0; i < ARRAY_SIZE(cstmp1); i++)
+		cstmp1[i] = stm32_cryp_read(cryp, CRYP_CSGCMCCM0R + i * 4);
+
+	/* d) Write IV1R */
+	stm32_cryp_write(cryp, CRYP_IV1RR, iv1tmp);
+
+	/* e) change mode to CTR */
+	cfg &= ~CR_ALGO_MASK;
+	cfg |= CR_AES_CTR;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* a) enable IP */
+	cfg |= CR_CRYPEN;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* b) pad and write the last block */
+	stm32_cryp_irq_write_block(cryp);
+	cryp->total_in = total_in_ori;
+	err = stm32_cryp_wait_output(cryp);
+	if (err) {
+		dev_err(cryp->dev, "Timeout (wite ccm padded data)\n");
+		return stm32_cryp_finish_req(cryp, err);
+	}
+
+	/* c) get and store decrypted data */
+	last_total_out = cryp->total_out;
+	stm32_cryp_irq_read_data(cryp);
+
+	memset(tmp, 0, sizeof(tmp));
+	scatterwalk_map_and_copy(tmp, out_sg_ori,
+				 cryp->total_out_save - last_total_out,
+				 last_total_out, 0);
+
+	/* d) Load again CRYP_CSGCMCCMxR */
+	for (i = 0; i < ARRAY_SIZE(cstmp2); i++)
+		cstmp2[i] = stm32_cryp_read(cryp, CRYP_CSGCMCCM0R + i * 4);
+
+	/* e) change mode back to AES CCM */
+	cfg &= ~CR_ALGO_MASK;
+	cfg |= CR_AES_CCM;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* f) change phase to header */
+	cfg &= ~CR_PH_MASK;
+	cfg |= CR_PH_HEADER;
+	stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+	/* g) XOR and write padded data */
+	for (i = 0; i < ARRAY_SIZE(tmp); i++) {
+		tmp[i] ^= cstmp1[i];
+		tmp[i] ^= cstmp2[i];
+		stm32_cryp_write(cryp, CRYP_DIN, tmp[i]);
+	}
+
+	/* h) wait for completion */
+	err = stm32_cryp_wait_busy(cryp);
+	if (err)
+		dev_err(cryp->dev, "Timeout (wite ccm padded data)\n");
+
+	/* i) run the he normal Final phase */
+	stm32_cryp_finish_req(cryp, err);
+}
+
 static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp)
 {
 	if (unlikely(!cryp->total_in)) {
@@ -845,28 +1483,220 @@ static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp)
 		return;
 	}
 
+	if (unlikely(cryp->total_in < AES_BLOCK_SIZE &&
+		     (stm32_cryp_get_hw_mode(cryp) == CR_AES_GCM) &&
+		     is_encrypt(cryp))) {
+		/* Padding for AES GCM encryption */
+		if (cryp->caps->padding_wa)
+			/* Special case 1 */
+			return stm32_cryp_irq_write_gcm_padded_data(cryp);
+
+		/* Setting padding bytes (NBBLB) */
+		stm32_cryp_irq_set_npblb(cryp);
+	}
+
+	if (unlikely((cryp->total_in - cryp->authsize < AES_BLOCK_SIZE) &&
+		     (stm32_cryp_get_hw_mode(cryp) == CR_AES_CCM) &&
+		     is_decrypt(cryp))) {
+		/* Padding for AES CCM decryption */
+		if (cryp->caps->padding_wa)
+			/* Special case 2 */
+			return stm32_cryp_irq_write_ccm_padded_data(cryp);
+
+		/* Setting padding bytes (NBBLB) */
+		stm32_cryp_irq_set_npblb(cryp);
+	}
+
 	if (is_aes(cryp) && is_ctr(cryp))
 		stm32_cryp_check_ctr_counter(cryp);
 
 	stm32_cryp_irq_write_block(cryp);
 }
 
+static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp)
+{
+	int err;
+	unsigned int i, j;
+	u32 cfg, *src;
+
+	src = sg_virt(cryp->in_sg) + _walked_in;
+
+	for (i = 0; i < AES_BLOCK_32; i++) {
+		stm32_cryp_write(cryp, CRYP_DIN, *src);
+
+		src = stm32_cryp_next_in(cryp, src, sizeof(u32));
+		cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in);
+
+		/* Check if whole header written */
+		if ((cryp->total_in_save - cryp->total_in) ==
+				cryp->areq->assoclen) {
+			/* Write padding if needed */
+			for (j = i + 1; j < AES_BLOCK_32; j++)
+				stm32_cryp_write(cryp, CRYP_DIN, 0);
+
+			/* Wait for completion */
+			err = stm32_cryp_wait_busy(cryp);
+			if (err) {
+				dev_err(cryp->dev, "Timeout (gcm header)\n");
+				return stm32_cryp_finish_req(cryp, err);
+			}
+
+			if (stm32_cryp_get_input_text_len(cryp)) {
+				/* Phase 3 : payload */
+				cfg = stm32_cryp_read(cryp, CRYP_CR);
+				cfg &= ~CR_CRYPEN;
+				stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+				cfg &= ~CR_PH_MASK;
+				cfg |= CR_PH_PAYLOAD;
+				cfg |= CR_CRYPEN;
+				stm32_cryp_write(cryp, CRYP_CR, cfg);
+			} else {
+				/* Phase 4 : tag */
+				stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+				stm32_cryp_finish_req(cryp, 0);
+			}
+
+			break;
+		}
+
+		if (!cryp->total_in)
+			break;
+	}
+}
+
+static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp)
+{
+	int err;
+	unsigned int i = 0, j, k;
+	u32 alen, cfg, *src;
+	u8 d8[4];
+
+	src = sg_virt(cryp->in_sg) + _walked_in;
+	alen = cryp->areq->assoclen;
+
+	if (!_walked_in) {
+		if (cryp->areq->assoclen <= 65280) {
+			/* Write first u32 of B1 */
+			d8[0] = (alen >> 8) & 0xFF;
+			d8[1] = alen & 0xFF;
+			d8[2] = *((u8 *)src);
+			src = stm32_cryp_next_in(cryp, src, 1);
+			d8[3] = *((u8 *)src);
+			src = stm32_cryp_next_in(cryp, src, 1);
+
+			stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+			i++;
+
+			cryp->total_in -= min_t(size_t, 2, cryp->total_in);
+		} else {
+			/* Build the two first u32 of B1 */
+			d8[0] = 0xFF;
+			d8[1] = 0xFE;
+			d8[2] = alen & 0xFF000000;
+			d8[3] = alen & 0x00FF0000;
+
+			stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+			i++;
+
+			d8[0] = alen & 0x0000FF00;
+			d8[1] = alen & 0x000000FF;
+			d8[2] = *((u8 *)src);
+			src = stm32_cryp_next_in(cryp, src, 1);
+			d8[3] = *((u8 *)src);
+			src = stm32_cryp_next_in(cryp, src, 1);
+
+			stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+			i++;
+
+			cryp->total_in -= min_t(size_t, 2, cryp->total_in);
+		}
+	}
+
+	/* Write next u32 */
+	for (; i < AES_BLOCK_32; i++) {
+		/* Build an u32 */
+		memset(d8, 0, sizeof(u32));
+		for (k = 0; k < sizeof(u32); k++) {
+			d8[k] = *((u8 *)src);
+			src = stm32_cryp_next_in(cryp, src, 1);
+
+			cryp->total_in -= min_t(size_t, 1, cryp->total_in);
+			if ((cryp->total_in_save - cryp->total_in) == alen)
+				break;
+		}
+
+		stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+
+		if ((cryp->total_in_save - cryp->total_in) == alen) {
+			/* Write padding if needed */
+			for (j = i + 1; j < AES_BLOCK_32; j++)
+				stm32_cryp_write(cryp, CRYP_DIN, 0);
+
+			/* Wait for completion */
+			err = stm32_cryp_wait_busy(cryp);
+			if (err) {
+				dev_err(cryp->dev, "Timeout (ccm header)\n");
+				return stm32_cryp_finish_req(cryp, err);
+			}
+
+			if (stm32_cryp_get_input_text_len(cryp)) {
+				/* Phase 3 : payload */
+				cfg = stm32_cryp_read(cryp, CRYP_CR);
+				cfg &= ~CR_CRYPEN;
+				stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+				cfg &= ~CR_PH_MASK;
+				cfg |= CR_PH_PAYLOAD;
+				cfg |= CR_CRYPEN;
+				stm32_cryp_write(cryp, CRYP_CR, cfg);
+			} else {
+				/* Phase 4 : tag */
+				stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+				stm32_cryp_finish_req(cryp, 0);
+			}
+
+			break;
+		}
+	}
+}
+
 static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg)
 {
 	struct stm32_cryp *cryp = arg;
+	u32 ph;
 
 	if (cryp->irq_status & MISR_OUT)
 		/* Output FIFO IRQ: read data */
 		if (unlikely(stm32_cryp_irq_read_data(cryp))) {
 			/* All bytes processed, finish */
 			stm32_cryp_write(cryp, CRYP_IMSCR, 0);
-			stm32_cryp_finish_req(cryp);
+			stm32_cryp_finish_req(cryp, 0);
 			return IRQ_HANDLED;
 		}
 
 	if (cryp->irq_status & MISR_IN) {
-		/* Input FIFO IRQ: write data */
-		stm32_cryp_irq_write_data(cryp);
+		if (is_gcm(cryp)) {
+			ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK;
+			if (unlikely(ph == CR_PH_HEADER))
+				/* Write Header */
+				stm32_cryp_irq_write_gcm_header(cryp);
+			else
+				/* Input FIFO IRQ: write data */
+				stm32_cryp_irq_write_data(cryp);
+			cryp->gcm_ctr++;
+		} else if (is_ccm(cryp)) {
+			ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK;
+			if (unlikely(ph == CR_PH_HEADER))
+				/* Write Header */
+				stm32_cryp_irq_write_ccm_header(cryp);
+			else
+				/* Input FIFO IRQ: write data */
+				stm32_cryp_irq_write_data(cryp);
+		} else {
+			/* Input FIFO IRQ: write data */
+			stm32_cryp_irq_write_data(cryp);
+		}
 	}
 
 	return IRQ_HANDLED;
@@ -1028,8 +1858,62 @@ static struct crypto_alg crypto_algs[] = {
 },
 };
 
+static struct aead_alg aead_algs[] = {
+{
+	.setkey		= stm32_cryp_aes_aead_setkey,
+	.setauthsize	= stm32_cryp_aes_gcm_setauthsize,
+	.encrypt	= stm32_cryp_aes_gcm_encrypt,
+	.decrypt	= stm32_cryp_aes_gcm_decrypt,
+	.init		= stm32_cryp_aes_aead_init,
+	.ivsize		= 12,
+	.maxauthsize	= AES_BLOCK_SIZE,
+
+	.base = {
+		.cra_name		= "gcm(aes)",
+		.cra_driver_name	= "stm32-gcm-aes",
+		.cra_priority		= 200,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= 1,
+		.cra_ctxsize		= sizeof(struct stm32_cryp_ctx),
+		.cra_alignmask		= 0xf,
+		.cra_module		= THIS_MODULE,
+	},
+},
+{
+	.setkey		= stm32_cryp_aes_aead_setkey,
+	.setauthsize	= stm32_cryp_aes_ccm_setauthsize,
+	.encrypt	= stm32_cryp_aes_ccm_encrypt,
+	.decrypt	= stm32_cryp_aes_ccm_decrypt,
+	.init		= stm32_cryp_aes_aead_init,
+	.ivsize		= AES_BLOCK_SIZE,
+	.maxauthsize	= AES_BLOCK_SIZE,
+
+	.base = {
+		.cra_name		= "ccm(aes)",
+		.cra_driver_name	= "stm32-ccm-aes",
+		.cra_priority		= 200,
+		.cra_flags		= CRYPTO_ALG_ASYNC,
+		.cra_blocksize		= 1,
+		.cra_ctxsize		= sizeof(struct stm32_cryp_ctx),
+		.cra_alignmask		= 0xf,
+		.cra_module		= THIS_MODULE,
+	},
+},
+};
+
+static const struct stm32_cryp_caps f7_data = {
+	.swap_final = true,
+	.padding_wa = true,
+};
+
+static const struct stm32_cryp_caps mp1_data = {
+	.swap_final = false,
+	.padding_wa = false,
+};
+
 static const struct of_device_id stm32_dt_ids[] = {
-	{ .compatible = "st,stm32f756-cryp", },
+	{ .compatible = "st,stm32f756-cryp", .data = &f7_data},
+	{ .compatible = "st,stm32mp1-cryp", .data = &mp1_data},
 	{},
 };
 MODULE_DEVICE_TABLE(of, stm32_dt_ids);
@@ -1046,6 +1930,10 @@ static int stm32_cryp_probe(struct platform_device *pdev)
 	if (!cryp)
 		return -ENOMEM;
 
+	cryp->caps = of_device_get_match_data(dev);
+	if (!cryp->caps)
+		return -ENODEV;
+
 	cryp->dev = dev;
 
 	mutex_init(&cryp->lock);
@@ -1102,9 +1990,6 @@ static int stm32_cryp_probe(struct platform_device *pdev)
 		goto err_engine1;
 	}
 
-	cryp->engine->prepare_cipher_request = stm32_cryp_prepare_cipher_req;
-	cryp->engine->cipher_one_request = stm32_cryp_cipher_one_req;
-
 	ret = crypto_engine_start(cryp->engine);
 	if (ret) {
 		dev_err(dev, "Could not start crypto engine\n");
@@ -1117,10 +2002,16 @@ static int stm32_cryp_probe(struct platform_device *pdev)
 		goto err_algs;
 	}
 
+	ret = crypto_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+	if (ret)
+		goto err_aead_algs;
+
 	dev_info(dev, "Initialized\n");
 
 	return 0;
 
+err_aead_algs:
+	crypto_unregister_algs(crypto_algs, ARRAY_SIZE(crypto_algs));
 err_algs:
 err_engine2:
 	crypto_engine_exit(cryp->engine);
@@ -1141,6 +2032,7 @@ static int stm32_cryp_remove(struct platform_device *pdev)
 	if (!cryp)
 		return -ENODEV;
 
+	crypto_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
 	crypto_unregister_algs(crypto_algs, ARRAY_SIZE(crypto_algs));
 
 	crypto_engine_exit(cryp->engine);
diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c
index 4ca4a264a833..981e45692695 100644
--- a/drivers/crypto/stm32/stm32-hash.c
+++ b/drivers/crypto/stm32/stm32-hash.c
@@ -122,6 +122,7 @@ enum stm32_hash_data_format {
 #define HASH_DMA_THRESHOLD		50
 
 struct stm32_hash_ctx {
+	struct crypto_engine_ctx enginectx;
 	struct stm32_hash_dev	*hdev;
 	unsigned long		flags;
 
@@ -626,7 +627,7 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev)
 			writesl(hdev->io_base + HASH_DIN, buffer,
 				DIV_ROUND_UP(ncp, sizeof(u32)));
 		}
-		stm32_hash_set_nblw(hdev, DIV_ROUND_UP(ncp, sizeof(u32)));
+		stm32_hash_set_nblw(hdev, ncp);
 		reg = stm32_hash_read(hdev, HASH_STR);
 		reg |= HASH_STR_DCAL;
 		stm32_hash_write(hdev, HASH_STR, reg);
@@ -743,13 +744,15 @@ static int stm32_hash_final_req(struct stm32_hash_dev *hdev)
 	struct ahash_request *req = hdev->req;
 	struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
 	int err;
+	int buflen = rctx->bufcnt;
+
+	rctx->bufcnt = 0;
 
 	if (!(rctx->flags & HASH_FLAGS_CPU))
 		err = stm32_hash_dma_send(hdev);
 	else
-		err = stm32_hash_xmit_cpu(hdev, rctx->buffer, rctx->bufcnt, 1);
+		err = stm32_hash_xmit_cpu(hdev, rctx->buffer, buflen, 1);
 
-	rctx->bufcnt = 0;
 
 	return err;
 }
@@ -828,15 +831,19 @@ static int stm32_hash_hw_init(struct stm32_hash_dev *hdev,
 	return 0;
 }
 
+static int stm32_hash_one_request(struct crypto_engine *engine, void *areq);
+static int stm32_hash_prepare_req(struct crypto_engine *engine, void *areq);
+
 static int stm32_hash_handle_queue(struct stm32_hash_dev *hdev,
 				   struct ahash_request *req)
 {
 	return crypto_transfer_hash_request_to_engine(hdev->engine, req);
 }
 
-static int stm32_hash_prepare_req(struct crypto_engine *engine,
-				  struct ahash_request *req)
+static int stm32_hash_prepare_req(struct crypto_engine *engine, void *areq)
 {
+	struct ahash_request *req = container_of(areq, struct ahash_request,
+						 base);
 	struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
 	struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
 	struct stm32_hash_request_ctx *rctx;
@@ -854,9 +861,10 @@ static int stm32_hash_prepare_req(struct crypto_engine *engine,
 	return stm32_hash_hw_init(hdev, rctx);
 }
 
-static int stm32_hash_one_request(struct crypto_engine *engine,
-				  struct ahash_request *req)
+static int stm32_hash_one_request(struct crypto_engine *engine, void *areq)
 {
+	struct ahash_request *req = container_of(areq, struct ahash_request,
+						 base);
 	struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
 	struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
 	struct stm32_hash_request_ctx *rctx;
@@ -1033,6 +1041,9 @@ static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm,
 	if (algs_hmac_name)
 		ctx->flags |= HASH_FLAGS_HMAC;
 
+	ctx->enginectx.op.do_one_request = stm32_hash_one_request;
+	ctx->enginectx.op.prepare_request = stm32_hash_prepare_req;
+	ctx->enginectx.op.unprepare_request = NULL;
 	return 0;
 }
 
@@ -1096,6 +1107,8 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id)
 		reg &= ~HASH_SR_OUTPUT_READY;
 		stm32_hash_write(hdev, HASH_SR, reg);
 		hdev->flags |= HASH_FLAGS_OUTPUT_READY;
+		/* Disable IT*/
+		stm32_hash_write(hdev, HASH_IMR, 0);
 		return IRQ_WAKE_THREAD;
 	}
 
@@ -1404,18 +1417,19 @@ MODULE_DEVICE_TABLE(of, stm32_hash_of_match);
 static int stm32_hash_get_of_match(struct stm32_hash_dev *hdev,
 				   struct device *dev)
 {
-	int err;
-
 	hdev->pdata = of_device_get_match_data(dev);
 	if (!hdev->pdata) {
 		dev_err(dev, "no compatible OF match\n");
 		return -EINVAL;
 	}
 
-	err = of_property_read_u32(dev->of_node, "dma-maxburst",
-				   &hdev->dma_maxburst);
+	if (of_property_read_u32(dev->of_node, "dma-maxburst",
+				 &hdev->dma_maxburst)) {
+		dev_info(dev, "dma-maxburst not specified, using 0\n");
+		hdev->dma_maxburst = 0;
+	}
 
-	return err;
+	return 0;
 }
 
 static int stm32_hash_probe(struct platform_device *pdev)
@@ -1493,9 +1507,6 @@ static int stm32_hash_probe(struct platform_device *pdev)
 		goto err_engine;
 	}
 
-	hdev->engine->prepare_hash_request = stm32_hash_prepare_req;
-	hdev->engine->hash_one_request = stm32_hash_one_request;
-
 	ret = crypto_engine_start(hdev->engine);
 	if (ret)
 		goto err_engine_start;
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
index 9acccad26928..2d0a677bcc76 100644
--- a/drivers/crypto/ux500/hash/hash_core.c
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -1403,6 +1403,16 @@ static int ahash_sha256_digest(struct ahash_request *req)
 	return ret1 ? ret1 : ret2;
 }
 
+static int ahash_noimport(struct ahash_request *req, const void *in)
+{
+	return -ENOSYS;
+}
+
+static int ahash_noexport(struct ahash_request *req, void *out)
+{
+	return -ENOSYS;
+}
+
 static int hmac_sha1_init(struct ahash_request *req)
 {
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -1507,6 +1517,8 @@ static struct hash_algo_template hash_algs[] = {
 			.update = ahash_update,
 			.final = ahash_final,
 			.digest = ahash_sha1_digest,
+			.export = ahash_noexport,
+			.import = ahash_noimport,
 			.halg.digestsize = SHA1_DIGEST_SIZE,
 			.halg.statesize = sizeof(struct hash_ctx),
 			.halg.base = {
@@ -1529,6 +1541,8 @@ static struct hash_algo_template hash_algs[] = {
 			.update	= ahash_update,
 			.final = ahash_final,
 			.digest = ahash_sha256_digest,
+			.export = ahash_noexport,
+			.import = ahash_noimport,
 			.halg.digestsize = SHA256_DIGEST_SIZE,
 			.halg.statesize = sizeof(struct hash_ctx),
 			.halg.base = {
@@ -1553,6 +1567,8 @@ static struct hash_algo_template hash_algs[] = {
 			.final = ahash_final,
 			.digest = hmac_sha1_digest,
 			.setkey = hmac_sha1_setkey,
+			.export = ahash_noexport,
+			.import = ahash_noimport,
 			.halg.digestsize = SHA1_DIGEST_SIZE,
 			.halg.statesize = sizeof(struct hash_ctx),
 			.halg.base = {
@@ -1577,6 +1593,8 @@ static struct hash_algo_template hash_algs[] = {
 			.final = ahash_final,
 			.digest = hmac_sha256_digest,
 			.setkey = hmac_sha256_setkey,
+			.export = ahash_noexport,
+			.import = ahash_noimport,
 			.halg.digestsize = SHA256_DIGEST_SIZE,
 			.halg.statesize = sizeof(struct hash_ctx),
 			.halg.base = {
diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c
index abe8c15450df..ba190cfa7aa1 100644
--- a/drivers/crypto/virtio/virtio_crypto_algs.c
+++ b/drivers/crypto/virtio/virtio_crypto_algs.c
@@ -29,6 +29,7 @@
 
 
 struct virtio_crypto_ablkcipher_ctx {
+	struct crypto_engine_ctx enginectx;
 	struct virtio_crypto *vcrypto;
 	struct crypto_tfm *tfm;
 
@@ -491,7 +492,7 @@ static int virtio_crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
 	vc_sym_req->ablkcipher_req = req;
 	vc_sym_req->encrypt = true;
 
-	return crypto_transfer_cipher_request_to_engine(data_vq->engine, req);
+	return crypto_transfer_ablkcipher_request_to_engine(data_vq->engine, req);
 }
 
 static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
@@ -511,7 +512,7 @@ static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
 	vc_sym_req->ablkcipher_req = req;
 	vc_sym_req->encrypt = false;
 
-	return crypto_transfer_cipher_request_to_engine(data_vq->engine, req);
+	return crypto_transfer_ablkcipher_request_to_engine(data_vq->engine, req);
 }
 
 static int virtio_crypto_ablkcipher_init(struct crypto_tfm *tfm)
@@ -521,6 +522,9 @@ static int virtio_crypto_ablkcipher_init(struct crypto_tfm *tfm)
 	tfm->crt_ablkcipher.reqsize = sizeof(struct virtio_crypto_sym_request);
 	ctx->tfm = tfm;
 
+	ctx->enginectx.op.do_one_request = virtio_crypto_ablkcipher_crypt_req;
+	ctx->enginectx.op.prepare_request = NULL;
+	ctx->enginectx.op.unprepare_request = NULL;
 	return 0;
 }
 
@@ -538,9 +542,9 @@ static void virtio_crypto_ablkcipher_exit(struct crypto_tfm *tfm)
 }
 
 int virtio_crypto_ablkcipher_crypt_req(
-	struct crypto_engine *engine,
-	struct ablkcipher_request *req)
+	struct crypto_engine *engine, void *vreq)
 {
+	struct ablkcipher_request *req = container_of(vreq, struct ablkcipher_request, base);
 	struct virtio_crypto_sym_request *vc_sym_req =
 				ablkcipher_request_ctx(req);
 	struct virtio_crypto_request *vc_req = &vc_sym_req->base;
@@ -561,8 +565,8 @@ static void virtio_crypto_ablkcipher_finalize_req(
 	struct ablkcipher_request *req,
 	int err)
 {
-	crypto_finalize_cipher_request(vc_sym_req->base.dataq->engine,
-					req, err);
+	crypto_finalize_ablkcipher_request(vc_sym_req->base.dataq->engine,
+					   req, err);
 	kzfree(vc_sym_req->iv);
 	virtcrypto_clear_request(&vc_sym_req->base);
 }
diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h
index e976539a05d9..72621bd67211 100644
--- a/drivers/crypto/virtio/virtio_crypto_common.h
+++ b/drivers/crypto/virtio/virtio_crypto_common.h
@@ -107,8 +107,7 @@ struct virtio_crypto *virtcrypto_get_dev_node(int node);
 int virtcrypto_dev_start(struct virtio_crypto *vcrypto);
 void virtcrypto_dev_stop(struct virtio_crypto *vcrypto);
 int virtio_crypto_ablkcipher_crypt_req(
-	struct crypto_engine *engine,
-	struct ablkcipher_request *req);
+	struct crypto_engine *engine, void *vreq);
 
 void
 virtcrypto_clear_request(struct virtio_crypto_request *vc_req);
diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c
index ff1410a32c2b..83326986c113 100644
--- a/drivers/crypto/virtio/virtio_crypto_core.c
+++ b/drivers/crypto/virtio/virtio_crypto_core.c
@@ -111,9 +111,6 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi)
 			ret = -ENOMEM;
 			goto err_engine;
 		}
-
-		vi->data_vq[i].engine->cipher_one_request =
-			virtio_crypto_ablkcipher_crypt_req;
 	}
 
 	kfree(names);
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
index 04ebe2204c12..314eb1071cce 100644
--- a/drivers/dma-buf/reservation.c
+++ b/drivers/dma-buf/reservation.c
@@ -374,8 +374,9 @@ EXPORT_SYMBOL(reservation_object_copy_fences);
  * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
  * the required size, and must be freed by caller)
  *
- * RETURNS
- * Zero or -errno
+ * Retrieve all fences from the reservation object. If the pointer for the
+ * exclusive fence is not specified the fence is put into the array of the
+ * shared fences as well. Returns either zero or -ENOMEM.
  */
 int reservation_object_get_fences_rcu(struct reservation_object *obj,
 				      struct dma_fence **pfence_excl,
@@ -389,8 +390,8 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 
 	do {
 		struct reservation_object_list *fobj;
-		unsigned seq;
-		unsigned int i;
+		unsigned int i, seq;
+		size_t sz = 0;
 
 		shared_count = i = 0;
 
@@ -402,9 +403,14 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 			goto unlock;
 
 		fobj = rcu_dereference(obj->fence);
-		if (fobj) {
+		if (fobj)
+			sz += sizeof(*shared) * fobj->shared_max;
+
+		if (!pfence_excl && fence_excl)
+			sz += sizeof(*shared);
+
+		if (sz) {
 			struct dma_fence **nshared;
-			size_t sz = sizeof(*shared) * fobj->shared_max;
 
 			nshared = krealloc(shared, sz,
 					   GFP_NOWAIT | __GFP_NOWARN);
@@ -420,13 +426,19 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 				break;
 			}
 			shared = nshared;
-			shared_count = fobj->shared_count;
-
+			shared_count = fobj ? fobj->shared_count : 0;
 			for (i = 0; i < shared_count; ++i) {
 				shared[i] = rcu_dereference(fobj->shared[i]);
 				if (!dma_fence_get_rcu(shared[i]))
 					break;
 			}
+
+			if (!pfence_excl && fence_excl) {
+				shared[i] = fence_excl;
+				fence_excl = NULL;
+				++i;
+				++shared_count;
+			}
 		}
 
 		if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
@@ -448,7 +460,8 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 
 	*pshared_count = shared_count;
 	*pshared = shared;
-	*pfence_excl = fence_excl;
+	if (pfence_excl)
+		*pfence_excl = fence_excl;
 
 	return ret;
 }
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
index 24f83f9eeaed..7779bdbd18d1 100644
--- a/drivers/dma-buf/sw_sync.c
+++ b/drivers/dma-buf/sw_sync.c
@@ -43,14 +43,14 @@
  * timelines.
  *
  * Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct
- * sw_sync_ioctl_create_fence as parameter.
+ * sw_sync_create_fence_data as parameter.
  *
  * To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used
  * with the increment as u32. This will update the last signaled value
  * from the timeline and signal any fence that has a seqno smaller or equal
  * to it.
  *
- * struct sw_sync_ioctl_create_fence
+ * struct sw_sync_create_fence_data
  * @value:	the seqno to initialise the fence with
  * @name:	the name of the new sync point
  * @fence:	return the fd of the new sync_file with the created fence
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 80cc2be6483c..b9339524d5bd 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -74,7 +74,11 @@ MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
 
 static bool noverify;
 module_param(noverify, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(noverify, "Disable random data setup and verification");
+MODULE_PARM_DESC(noverify, "Disable data verification (default: verify)");
+
+static bool norandom;
+module_param(norandom, bool, 0644);
+MODULE_PARM_DESC(norandom, "Disable random offset setup (default: random)");
 
 static bool verbose;
 module_param(verbose, bool, S_IRUGO | S_IWUSR);
@@ -103,6 +107,7 @@ struct dmatest_params {
 	unsigned int	pq_sources;
 	int		timeout;
 	bool		noverify;
+	bool		norandom;
 };
 
 /**
@@ -575,7 +580,7 @@ static int dmatest_func(void *data)
 			break;
 		}
 
-		if (params->noverify)
+		if (params->norandom)
 			len = params->buf_size;
 		else
 			len = dmatest_random() % params->buf_size + 1;
@@ -586,17 +591,19 @@ static int dmatest_func(void *data)
 
 		total_len += len;
 
-		if (params->noverify) {
+		if (params->norandom) {
 			src_off = 0;
 			dst_off = 0;
 		} else {
-			start = ktime_get();
 			src_off = dmatest_random() % (params->buf_size - len + 1);
 			dst_off = dmatest_random() % (params->buf_size - len + 1);
 
 			src_off = (src_off >> align) << align;
 			dst_off = (dst_off >> align) << align;
+		}
 
+		if (!params->noverify) {
+			start = ktime_get();
 			dmatest_init_srcs(thread->srcs, src_off, len,
 					  params->buf_size, is_memset);
 			dmatest_init_dsts(thread->dsts, dst_off, len,
@@ -975,6 +982,7 @@ static void run_threaded_test(struct dmatest_info *info)
 	params->pq_sources = pq_sources;
 	params->timeout = timeout;
 	params->noverify = noverify;
+	params->norandom = norandom;
 
 	request_channels(info, DMA_MEMCPY);
 	request_channels(info, DMA_MEMSET);
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 0b951ca78ec4..987126c4c6f6 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/gpio-davinci.h>
 #include <linux/irqchip/chained_irq.h>
@@ -225,6 +226,11 @@ static int davinci_gpio_probe(struct platform_device *pdev)
 	chips->chip.of_gpio_n_cells = 2;
 	chips->chip.parent = dev;
 	chips->chip.of_node = dev->of_node;
+
+	if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
+		chips->chip.request = gpiochip_generic_request;
+		chips->chip.free = gpiochip_generic_free;
+	}
 #endif
 	spin_lock_init(&chips->lock);
 	bank_base += ngpio;
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 938bbe3f831c..324813e8304e 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -182,7 +182,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 			dev_err(wm831x->dev,
 				"GPIO control %d read failed: %d\n",
 				gpio, reg);
-			seq_printf(s, "\n");
+			seq_putc(s, '\n');
 			continue;
 		}
 
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 564bb7a31da4..1856ee5e70bb 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -111,8 +111,8 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
 	struct gpio_desc *desc;
 	int ret;
 
-	ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
-					 &gpiospec);
+	ret = of_parse_phandle_with_args_map(np, propname, "gpio", index,
+					     &gpiospec);
 	if (ret) {
 		pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n",
 			__func__, propname, np, index);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index d5a2eefd6c3e..31126df06c8c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1504,6 +1504,7 @@ struct amdgpu_device {
 	const struct amdgpu_asic_funcs	*asic_funcs;
 	bool				shutdown;
 	bool				need_dma32;
+	bool				need_swiotlb;
 	bool				accel_working;
 	struct work_struct		reset_work;
 	struct notifier_block		acpi_nb;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 8ca3783f2deb..74d2efaec52f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -736,9 +736,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	if (encoder) {
 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
@@ -757,8 +759,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
 	/* check acpi lid status ??? */
 
 	amdgpu_connector_update_scratch_regs(connector, ret);
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
+
 	return ret;
 }
 
@@ -868,9 +874,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	encoder = amdgpu_connector_best_single_encoder(connector);
 	if (!encoder)
@@ -924,8 +932,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
 	amdgpu_connector_update_scratch_regs(connector, ret);
 
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -988,9 +998,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status ret = connector_status_disconnected;
 	bool dret = false, broken_edid = false;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
 		ret = connector->status;
@@ -1115,8 +1127,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
 	amdgpu_connector_update_scratch_regs(connector, ret);
 
 exit:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1359,9 +1373,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
 		ret = connector->status;
@@ -1429,8 +1445,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
 
 	amdgpu_connector_update_scratch_regs(connector, ret);
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 38d47559f098..c2fa5d55f04e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -207,7 +207,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
 	amdgpu_bo_unreserve(new_abo);
 
 	work->base = base;
-	work->target_vblank = target - drm_crtc_vblank_count(crtc) +
+	work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
 		amdgpu_get_vblank_counter_kms(dev, work->crtc_id);
 
 	/* we borrow the event spin lock for protecting flip_wrok */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index e4bb435e614b..d897c4c61a01 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1018,7 +1018,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm,
 	}
 
 #ifdef CONFIG_SWIOTLB
-	if (swiotlb_nr_tbl()) {
+	if (adev->need_swiotlb && swiotlb_nr_tbl()) {
 		return ttm_dma_populate(&gtt->ttm, adev->dev, ctx);
 	}
 #endif
@@ -1045,7 +1045,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm)
 	adev = amdgpu_ttm_adev(ttm->bdev);
 
 #ifdef CONFIG_SWIOTLB
-	if (swiotlb_nr_tbl()) {
+	if (adev->need_swiotlb && swiotlb_nr_tbl()) {
 		ttm_dma_unpopulate(&gtt->ttm, adev->dev);
 		return;
 	}
@@ -2010,7 +2010,7 @@ static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
 	count = ARRAY_SIZE(amdgpu_ttm_debugfs_list);
 
 #ifdef CONFIG_SWIOTLB
-	if (!swiotlb_nr_tbl())
+	if (!(adev->need_swiotlb && swiotlb_nr_tbl()))
 		--count;
 #endif
 
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index 8e28270d1ea9..5f5eb15ccf4a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -22,6 +22,7 @@
  */
 #include <linux/firmware.h>
 #include <drm/drmP.h>
+#include <drm/drm_cache.h>
 #include "amdgpu.h"
 #include "gmc_v6_0.h"
 #include "amdgpu_ucode.h"
@@ -851,6 +852,7 @@ static int gmc_v6_0_sw_init(void *handle)
 		pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32));
 		dev_warn(adev->dev, "amdgpu: No coherent DMA available.\n");
 	}
+	adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 
 	r = gmc_v6_0_init_microcode(adev);
 	if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index 86e9d682c59e..12e49bd8fd2d 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -22,6 +22,7 @@
  */
 #include <linux/firmware.h>
 #include <drm/drmP.h>
+#include <drm/drm_cache.h>
 #include "amdgpu.h"
 #include "cikd.h"
 #include "cik.h"
@@ -999,6 +1000,7 @@ static int gmc_v7_0_sw_init(void *handle)
 		pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32));
 		pr_warn("amdgpu: No coherent DMA available\n");
 	}
+	adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 
 	r = gmc_v7_0_init_microcode(adev);
 	if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 9a813d834f1a..9a170e37fbe7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -22,6 +22,7 @@
  */
 #include <linux/firmware.h>
 #include <drm/drmP.h>
+#include <drm/drm_cache.h>
 #include "amdgpu.h"
 #include "gmc_v8_0.h"
 #include "amdgpu_ucode.h"
@@ -1085,6 +1086,7 @@ static int gmc_v8_0_sw_init(void *handle)
 	 */
 	adev->need_dma32 = false;
 	dma_bits = adev->need_dma32 ? 32 : 40;
+	adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 	r = pci_set_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits));
 	if (r) {
 		adev->need_dma32 = true;
@@ -1096,6 +1098,7 @@ static int gmc_v8_0_sw_init(void *handle)
 		pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32));
 		pr_warn("amdgpu: No coherent DMA available\n");
 	}
+	adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 
 	r = gmc_v8_0_init_microcode(adev);
 	if (r) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 2719937e09d6..100ec69f020a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -21,6 +21,7 @@
  *
  */
 #include <linux/firmware.h>
+#include <drm/drm_cache.h>
 #include "amdgpu.h"
 #include "gmc_v9_0.h"
 #include "amdgpu_atomfirmware.h"
@@ -852,6 +853,7 @@ static int gmc_v9_0_sw_init(void *handle)
 		pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32));
 		printk(KERN_WARNING "amdgpu: No coherent DMA available.\n");
 	}
+	adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 
 	r = gmc_v9_0_mc_init(adev);
 	if (r)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 1ce4c98385e3..b7254a29b34a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3836,7 +3836,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
 
 
 	/* Prepare wait for target vblank early - before the fence-waits */
-	target_vblank = target - drm_crtc_vblank_count(crtc) +
+	target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
 			amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id);
 
 	/* TODO This might fail and hence better not used, wait
@@ -3982,7 +3982,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
 			amdgpu_dm_do_flip(
 				crtc,
 				fb,
-				drm_crtc_vblank_count(crtc) + *wait_for_vblank,
+				(uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank,
 				dm_state->context);
 		}
 
diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c
index 0ce7f398bcff..977dfa55162f 100644
--- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
+++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
@@ -15,7 +15,8 @@
  */
 
 #include <drm/drm_crtc.h>
-#include <drm/drm_encoder_slave.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_device.h>
 
 #include "arcpgu.h"
 
diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c
index bca3a678c955..b8f6f9a5dfbe 100644
--- a/drivers/gpu/drm/arc/arcpgu_sim.c
+++ b/drivers/gpu/drm/arc/arcpgu_sim.c
@@ -15,7 +15,6 @@
  */
 
 #include <drm/drm_crtc_helper.h>
-#include <drm/drm_encoder_slave.h>
 #include <drm/drm_atomic_helper.h>
 
 #include "arcpgu.h"
@@ -29,7 +28,6 @@
 
 struct arcpgu_drm_connector {
 	struct drm_connector connector;
-	struct drm_encoder_slave *encoder_slave;
 };
 
 static int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
@@ -68,7 +66,7 @@ static struct drm_encoder_funcs arcpgu_drm_encoder_funcs = {
 int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np)
 {
 	struct arcpgu_drm_connector *arcpgu_connector;
-	struct drm_encoder_slave *encoder;
+	struct drm_encoder *encoder;
 	struct drm_connector *connector;
 	int ret;
 
@@ -76,10 +74,10 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np)
 	if (encoder == NULL)
 		return -ENOMEM;
 
-	encoder->base.possible_crtcs = 1;
-	encoder->base.possible_clones = 0;
+	encoder->possible_crtcs = 1;
+	encoder->possible_clones = 0;
 
-	ret = drm_encoder_init(drm, &encoder->base, &arcpgu_drm_encoder_funcs,
+	ret = drm_encoder_init(drm, encoder, &arcpgu_drm_encoder_funcs,
 			       DRM_MODE_ENCODER_VIRTUAL, NULL);
 	if (ret)
 		return ret;
@@ -101,21 +99,19 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np)
 		goto error_encoder_cleanup;
 	}
 
-	ret = drm_mode_connector_attach_encoder(connector, &encoder->base);
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
 	if (ret < 0) {
 		dev_err(drm->dev, "could not attach connector to encoder\n");
 		drm_connector_unregister(connector);
 		goto error_connector_cleanup;
 	}
 
-	arcpgu_connector->encoder_slave = encoder;
-
 	return 0;
 
 error_connector_cleanup:
 	drm_connector_cleanup(connector);
 
 error_encoder_cleanup:
-	drm_encoder_cleanup(&encoder->base);
+	drm_encoder_cleanup(encoder);
 	return ret;
 }
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index 630721f429f7..877647ef35a9 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -249,8 +249,9 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						   DRM_PLANE_HELPER_NO_SCALING,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 33c5ef96ced0..2885d69af456 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -148,8 +148,10 @@ static int malidp_se_check_scaling(struct malidp_plane *mp,
 	if (!crtc_state)
 		return -EINVAL;
 
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
+
 	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						  0, INT_MAX, true, true);
 	if (ret)
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 703c2d13603f..e18800ed7cd1 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -194,20 +194,6 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
 	return 0;
 }
 
-static bool atmel_hlcdc_format_embeds_alpha(u32 format)
-{
-	int i;
-
-	for (i = 0; i < sizeof(format); i++) {
-		char tmp = (format >> (8 * i)) & 0xff;
-
-		if (tmp == 'A')
-			return true;
-	}
-
-	return false;
-}
-
 static u32 heo_downscaling_xcoef[] = {
 	0x11343311,
 	0x000000f7,
@@ -377,13 +363,13 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
 {
 	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
 	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
-	u32 format = state->base.fb->format->format;
+	const struct drm_format_info *format = state->base.fb->format;
 
 	/*
 	 * Rotation optimization is not working on RGB888 (rotation is still
 	 * working but without any optimization).
 	 */
-	if (format == DRM_FORMAT_RGB888)
+	if (format->format == DRM_FORMAT_RGB888)
 		cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
 
 	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
@@ -395,7 +381,7 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
 		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
 		       ATMEL_HLCDC_LAYER_ITER;
 
-		if (atmel_hlcdc_format_embeds_alpha(format))
+		if (format->has_alpha)
 			cfg |= ATMEL_HLCDC_LAYER_LAEN;
 		else
 			cfg |= ATMEL_HLCDC_LAYER_GAEN |
@@ -566,7 +552,7 @@ atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
 		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
 
 		if (!ovl_s->fb ||
-		    atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) ||
+		    ovl_s->fb->format->has_alpha ||
 		    ovl_state->alpha != 255)
 			continue;
 
@@ -769,7 +755,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
 
 	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
 	    (!desc->layout.memsize ||
-	     atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format)))
+	     state->base.fb->format->has_alpha))
 		return -EINVAL;
 
 	if (state->crtc_x < 0 || state->crtc_y < 0)
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c
index ed12a7ddd64a..b49043866be6 100644
--- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c
@@ -1301,8 +1301,7 @@ static void unregister_i2c_dummy_clients(struct anx78xx *anx78xx)
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(anx78xx->i2c_dummy); i++)
-		if (anx78xx->i2c_dummy[i])
-			i2c_unregister_device(anx78xx->i2c_dummy[i]);
+		i2c_unregister_device(anx78xx->i2c_dummy[i]);
 }
 
 static const struct regmap_config anx78xx_regmap_config = {
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index a8905049b9da..b2756bc4225a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -727,7 +727,6 @@ static int analogix_dp_set_link_train(struct analogix_dp_device *dp,
 
 static int analogix_dp_config_video(struct analogix_dp_device *dp)
 {
-	int retval = 0;
 	int timeout_loop = 0;
 	int done_count = 0;
 
@@ -783,10 +782,7 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
 		usleep_range(1000, 1001);
 	}
 
-	if (retval != 0)
-		dev_err(dp->dev, "Video stream is not detected!\n");
-
-	return retval;
+	return 0;
 }
 
 static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
index de5e7dee7ad6..498d5948d1a8 100644
--- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
+++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/regulator/consumer.h>
 
@@ -204,6 +205,7 @@ static int dumb_vga_probe(struct platform_device *pdev)
 
 	vga->bridge.funcs = &dumb_vga_bridge_funcs;
 	vga->bridge.of_node = pdev->dev.of_node;
+	vga->bridge.timings = of_device_get_match_data(&pdev->dev);
 
 	drm_bridge_add(&vga->bridge);
 
@@ -222,10 +224,61 @@ static int dumb_vga_remove(struct platform_device *pdev)
 	return 0;
 }
 
+/*
+ * We assume the ADV7123 DAC is the "default" for historical reasons
+ * Information taken from the ADV7123 datasheet, revision D.
+ * NOTE: the ADV7123EP seems to have other timings and need a new timings
+ * set if used.
+ */
+static const struct drm_bridge_timings default_dac_timings = {
+	/* Timing specifications, datasheet page 7 */
+	.sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE,
+	.setup_time_ps = 500,
+	.hold_time_ps = 1500,
+};
+
+/*
+ * Information taken from the THS8134, THS8134A, THS8134B datasheet named
+ * "SLVS205D", dated May 1990, revised March 2000.
+ */
+static const struct drm_bridge_timings ti_ths8134_dac_timings = {
+	/* From timing diagram, datasheet page 9 */
+	.sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE,
+	/* From datasheet, page 12 */
+	.setup_time_ps = 3000,
+	/* I guess this means latched input */
+	.hold_time_ps = 0,
+};
+
+/*
+ * Information taken from the THS8135 datasheet named "SLAS343B", dated
+ * May 2001, revised April 2013.
+ */
+static const struct drm_bridge_timings ti_ths8135_dac_timings = {
+	/* From timing diagram, datasheet page 14 */
+	.sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE,
+	/* From datasheet, page 16 */
+	.setup_time_ps = 2000,
+	.hold_time_ps = 500,
+};
+
 static const struct of_device_id dumb_vga_match[] = {
-	{ .compatible = "dumb-vga-dac" },
-	{ .compatible = "adi,adv7123" },
-	{ .compatible = "ti,ths8135" },
+	{
+		.compatible = "dumb-vga-dac",
+		.data = NULL,
+	},
+	{
+		.compatible = "adi,adv7123",
+		.data = &default_dac_timings,
+	},
+	{
+		.compatible = "ti,ths8135",
+		.data = &ti_ths8135_dac_timings,
+	},
+	{
+		.compatible = "ti,ths8134",
+		.data = &ti_ths8134_dac_timings,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, dumb_vga_match);
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index d9cca4fd66ec..7bac101c285c 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -29,7 +29,10 @@
 #include <drm/bridge/dw_mipi_dsi.h>
 #include <video/mipi_display.h>
 
+#define HWVER_131			0x31333100	/* IP version 1.31 */
+
 #define DSI_VERSION			0x00
+#define VERSION				GENMASK(31, 8)
 
 #define DSI_PWR_UP			0x04
 #define RESET				0
@@ -136,10 +139,6 @@
 					 GEN_SW_0P_TX_LP)
 
 #define DSI_GEN_HDR			0x6c
-/* TODO These 2 defines will be reworked thanks to mipi_dsi_create_packet() */
-#define GEN_HDATA(data)			(((data) & 0xffff) << 8)
-#define GEN_HTYPE(type)			(((type) & 0xff) << 0)
-
 #define DSI_GEN_PLD_DATA		0x70
 
 #define DSI_CMD_PKT_STATUS		0x74
@@ -169,11 +168,12 @@
 #define PHY_CLKHS2LP_TIME(lbcc)		(((lbcc) & 0x3ff) << 16)
 #define PHY_CLKLP2HS_TIME(lbcc)		((lbcc) & 0x3ff)
 
-/* TODO Next register is slightly different between 1.30 & 1.31 IP version */
 #define DSI_PHY_TMR_CFG			0x9c
 #define PHY_HS2LP_TIME(lbcc)		(((lbcc) & 0xff) << 24)
 #define PHY_LP2HS_TIME(lbcc)		(((lbcc) & 0xff) << 16)
 #define MAX_RD_TIME(lbcc)		((lbcc) & 0x7fff)
+#define PHY_HS2LP_TIME_V131(lbcc)	(((lbcc) & 0x3ff) << 16)
+#define PHY_LP2HS_TIME_V131(lbcc)	((lbcc) & 0x3ff)
 
 #define DSI_PHY_RSTZ			0xa0
 #define PHY_DISFORCEPLL			0
@@ -212,7 +212,9 @@
 #define DSI_INT_ST1			0xc0
 #define DSI_INT_MSK0			0xc4
 #define DSI_INT_MSK1			0xc8
+
 #define DSI_PHY_TMR_RD_CFG		0xf4
+#define MAX_RD_TIME_V131(lbcc)		((lbcc) & 0x7fff)
 
 #define PHY_STATUS_TIMEOUT_US		10000
 #define CMD_PKT_STATUS_TIMEOUT_US	20000
@@ -359,52 +361,23 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
 	return 0;
 }
 
-static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
-				       const struct mipi_dsi_msg *msg)
+static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
+			     const struct mipi_dsi_packet *packet)
 {
-	const u8 *tx_buf = msg->tx_buf;
-	u16 data = 0;
+	const u8 *tx_buf = packet->payload;
+	int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret;
+	__le32 word;
 	u32 val;
 
-	if (msg->tx_len > 0)
-		data |= tx_buf[0];
-	if (msg->tx_len > 1)
-		data |= tx_buf[1] << 8;
-
-	if (msg->tx_len > 2) {
-		dev_err(dsi->dev, "too long tx buf length %zu for short write\n",
-			msg->tx_len);
-		return -EINVAL;
-	}
-
-	val = GEN_HDATA(data) | GEN_HTYPE(msg->type);
-	return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
-}
-
-static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
-				      const struct mipi_dsi_msg *msg)
-{
-	const u8 *tx_buf = msg->tx_buf;
-	int len = msg->tx_len, pld_data_bytes = sizeof(u32), ret;
-	u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
-	u32 remainder;
-	u32 val;
-
-	if (msg->tx_len < 3) {
-		dev_err(dsi->dev, "wrong tx buf length %zu for long write\n",
-			msg->tx_len);
-		return -EINVAL;
-	}
-
-	while (DIV_ROUND_UP(len, pld_data_bytes)) {
+	while (len) {
 		if (len < pld_data_bytes) {
-			remainder = 0;
-			memcpy(&remainder, tx_buf, len);
-			dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
+			word = 0;
+			memcpy(&word, tx_buf, len);
+			dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word));
 			len = 0;
 		} else {
-			memcpy(&remainder, tx_buf, pld_data_bytes);
-			dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
+			memcpy(&word, tx_buf, pld_data_bytes);
+			dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word));
 			tx_buf += pld_data_bytes;
 			len -= pld_data_bytes;
 		}
@@ -419,40 +392,74 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
 		}
 	}
 
-	return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val);
+	word = 0;
+	memcpy(&word, packet->header, sizeof(packet->header));
+	return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word));
+}
+
+static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
+			    const struct mipi_dsi_msg *msg)
+{
+	int i, j, ret, len = msg->rx_len;
+	u8 *buf = msg->rx_buf;
+	u32 val;
+
+	/* Wait end of the read operation */
+	ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
+				 val, !(val & GEN_RD_CMD_BUSY),
+				 1000, CMD_PKT_STATUS_TIMEOUT_US);
+	if (ret) {
+		dev_err(dsi->dev, "Timeout during read operation\n");
+		return ret;
+	}
+
+	for (i = 0; i < len; i += 4) {
+		/* Read fifo must not be empty before all bytes are read */
+		ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
+					 val, !(val & GEN_PLD_R_EMPTY),
+					 1000, CMD_PKT_STATUS_TIMEOUT_US);
+		if (ret) {
+			dev_err(dsi->dev, "Read payload FIFO is empty\n");
+			return ret;
+		}
+
+		val = dsi_read(dsi, DSI_GEN_PLD_DATA);
+		for (j = 0; j < 4 && j + i < len; j++)
+			buf[i + j] = val >> (8 * j);
+	}
+
+	return ret;
 }
 
 static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
 					 const struct mipi_dsi_msg *msg)
 {
 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
-	int ret;
+	struct mipi_dsi_packet packet;
+	int ret, nb_bytes;
+
+	ret = mipi_dsi_create_packet(&packet, msg);
+	if (ret) {
+		dev_err(dsi->dev, "failed to create packet: %d\n", ret);
+		return ret;
+	}
 
-	/*
-	 * TODO dw drv improvements
-	 * use mipi_dsi_create_packet() instead of all following
-	 * functions and code (no switch cases, no
-	 * dw_mipi_dsi_dcs_short_write(), only the loop in long_write...)
-	 * and use packet.header...
-	 */
 	dw_mipi_message_config(dsi, msg);
 
-	switch (msg->type) {
-	case MIPI_DSI_DCS_SHORT_WRITE:
-	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
-	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
-		ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
-		break;
-	case MIPI_DSI_DCS_LONG_WRITE:
-		ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
-		break;
-	default:
-		dev_err(dsi->dev, "unsupported message type 0x%02x\n",
-			msg->type);
-		ret = -EINVAL;
+	ret = dw_mipi_dsi_write(dsi, &packet);
+	if (ret)
+		return ret;
+
+	if (msg->rx_buf && msg->rx_len) {
+		ret = dw_mipi_dsi_read(dsi, msg);
+		if (ret)
+			return ret;
+		nb_bytes = msg->rx_len;
+	} else {
+		nb_bytes = packet.size;
 	}
 
-	return ret;
+	return nb_bytes;
 }
 
 static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
@@ -658,6 +665,8 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
 
 static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
 {
+	u32 hw_version;
+
 	/*
 	 * TODO dw drv improvements
 	 * data & clock lane timers should be computed according to panel
@@ -665,8 +674,17 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
 	 * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with
 	 * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP)
 	 */
-	dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40)
-		  | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
+
+	hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
+
+	if (hw_version >= HWVER_131) {
+		dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) |
+			  PHY_LP2HS_TIME_V131(0x40));
+		dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000));
+	} else {
+		dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) |
+			  PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
+	}
 
 	dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40)
 		  | PHY_CLKLP2HS_TIME(0x40));
@@ -746,9 +764,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
 	pm_runtime_put(dsi->dev);
 }
 
-void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
-				 struct drm_display_mode *mode,
-				 struct drm_display_mode *adjusted_mode)
+static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
+					struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted_mode)
 {
 	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
 	const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
@@ -922,8 +940,6 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
 	dsi->bridge.of_node = pdev->dev.of_node;
 #endif
 
-	dev_set_drvdata(dev, dsi);
-
 	return dsi;
 }
 
@@ -935,23 +951,16 @@ static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
 /*
  * Probe/remove API, used from platforms based on the DRM bridge API.
  */
-int dw_mipi_dsi_probe(struct platform_device *pdev,
-		      const struct dw_mipi_dsi_plat_data *plat_data)
+struct dw_mipi_dsi *
+dw_mipi_dsi_probe(struct platform_device *pdev,
+		  const struct dw_mipi_dsi_plat_data *plat_data)
 {
-	struct dw_mipi_dsi *dsi;
-
-	dsi = __dw_mipi_dsi_probe(pdev, plat_data);
-	if (IS_ERR(dsi))
-		return PTR_ERR(dsi);
-
-	return 0;
+	return __dw_mipi_dsi_probe(pdev, plat_data);
 }
 EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe);
 
-void dw_mipi_dsi_remove(struct platform_device *pdev)
+void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
 {
-	struct dw_mipi_dsi *dsi = platform_get_drvdata(pdev);
-
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 
 	__dw_mipi_dsi_remove(dsi);
@@ -961,31 +970,30 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
 /*
  * Bind/unbind API, used from platforms based on the component framework.
  */
-int dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-		     const struct dw_mipi_dsi_plat_data *plat_data)
+struct dw_mipi_dsi *
+dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+		 const struct dw_mipi_dsi_plat_data *plat_data)
 {
 	struct dw_mipi_dsi *dsi;
 	int ret;
 
 	dsi = __dw_mipi_dsi_probe(pdev, plat_data);
 	if (IS_ERR(dsi))
-		return PTR_ERR(dsi);
+		return dsi;
 
 	ret = drm_bridge_attach(encoder, &dsi->bridge, NULL);
 	if (ret) {
-		dw_mipi_dsi_remove(pdev);
+		dw_mipi_dsi_remove(dsi);
 		DRM_ERROR("Failed to initialize bridge with drm\n");
-		return ret;
+		return ERR_PTR(ret);
 	}
 
-	return 0;
+	return dsi;
 }
 EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind);
 
-void dw_mipi_dsi_unbind(struct device *dev)
+void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi)
 {
-	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
-
 	__dw_mipi_dsi_remove(dsi);
 }
 EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index cd23b1b28259..c91b9b054e3f 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -294,22 +294,7 @@ static void cirrus_crtc_prepare(struct drm_crtc *crtc)
 {
 }
 
-/*
- * This is called after a mode is programmed. It should reverse anything done
- * by the prepare function
- */
-static void cirrus_crtc_commit(struct drm_crtc *crtc)
-{
-}
-
-/*
- * The core can pass us a set of gamma values to program. We actually only
- * use this for 8-bit mode so can't perform smooth fades on deeper modes,
- * but it's a requirement that we provide the function
- */
-static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-				 u16 *blue, uint32_t size,
-				 struct drm_modeset_acquire_ctx *ctx)
+static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct cirrus_device *cdev = dev->dev_private;
@@ -317,7 +302,7 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 	int i;
 
 	if (!crtc->enabled)
-		return 0;
+		return;
 
 	r = crtc->gamma_store;
 	g = r + crtc->gamma_size;
@@ -330,6 +315,27 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 		WREG8(PALETTE_DATA, *g++ >> 8);
 		WREG8(PALETTE_DATA, *b++ >> 8);
 	}
+}
+
+/*
+ * This is called after a mode is programmed. It should reverse anything done
+ * by the prepare function
+ */
+static void cirrus_crtc_commit(struct drm_crtc *crtc)
+{
+	cirrus_crtc_load_lut(crtc);
+}
+
+/*
+ * The core can pass us a set of gamma values to program. We actually only
+ * use this for 8-bit mode so can't perform smooth fades on deeper modes,
+ * but it's a requirement that we provide the function
+ */
+static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+				 u16 *blue, uint32_t size,
+				 struct drm_modeset_acquire_ctx *ctx)
+{
+	cirrus_crtc_load_lut(crtc);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index b76d49218cf1..46733d534587 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -390,7 +390,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
 
 	if (blob) {
 		if (blob->length != sizeof(struct drm_mode_modeinfo) ||
-		    drm_mode_convert_umode(&state->mode,
+		    drm_mode_convert_umode(state->crtc->dev, &state->mode,
 		                           (const struct drm_mode_modeinfo *)
 		                            blob->data))
 			return -EINVAL;
@@ -863,10 +863,10 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
 	int ret;
 
 	/* either *both* CRTC and FB must be set, or neither */
-	if (WARN_ON(state->crtc && !state->fb)) {
+	if (state->crtc && !state->fb) {
 		DRM_DEBUG_ATOMIC("CRTC set but no FB\n");
 		return -EINVAL;
-	} else if (WARN_ON(state->fb && !state->crtc)) {
+	} else if (state->fb && !state->crtc) {
 		DRM_DEBUG_ATOMIC("FB set but no CRTC\n");
 		return -EINVAL;
 	}
@@ -1224,6 +1224,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		state->picture_aspect_ratio = val;
 	} else if (property == connector->scaling_mode_property) {
 		state->scaling_mode = val;
+	} else if (property == connector->content_protection_property) {
+		if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+			DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
+			return -EINVAL;
+		}
+		state->content_protection = val;
 	} else if (connector->funcs->atomic_set_property) {
 		return connector->funcs->atomic_set_property(connector,
 				state, property, val);
@@ -1303,6 +1309,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = state->picture_aspect_ratio;
 	} else if (property == connector->scaling_mode_property) {
 		*val = state->scaling_mode;
+	} else if (property == connector->content_protection_property) {
+		*val = state->content_protection;
 	} else if (connector->funcs->atomic_get_property) {
 		return connector->funcs->atomic_get_property(connector,
 				state, property, val);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ab4032167094..ae3cbfe9e01c 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
 		new_crtc_state->event->base.completion = &commit->flip_done;
 		new_crtc_state->event->base.completion_release = release_crtc_commit;
 		drm_crtc_commit_get(commit);
+
+		commit->abort_completion = true;
 	}
 
 	for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
 {
 	if (state->commit) {
+		/*
+		 * In the event that a non-blocking commit returns
+		 * -ERESTARTSYS before the commit_tail work is queued, we will
+		 * have an extra reference to the commit object. Release it, if
+		 * the event has not been consumed by the worker.
+		 *
+		 * state->event may be freed, so we can't directly look at
+		 * state->event->base.completion.
+		 */
+		if (state->event && state->commit->abort_completion)
+			drm_crtc_commit_put(state->commit);
+
 		kfree(state->commit->event);
 		state->commit->event = NULL;
+
 		drm_crtc_commit_put(state->commit);
 	}
 
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index e6a21e69059c..16b9c3810af2 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -205,9 +205,14 @@ int drm_connector_init(struct drm_device *dev,
 	connector->dev = dev;
 	connector->funcs = funcs;
 
-	ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
-	if (ret < 0)
+	/* connector index is used with 32bit bitmasks */
+	ret = ida_simple_get(&config->connector_ida, 0, 32, GFP_KERNEL);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("Failed to allocate %s connector index: %d\n",
+			      drm_connector_enum_list[connector_type].name,
+			      ret);
 		goto out_put;
+	}
 	connector->index = ret;
 	ret = 0;
 
@@ -756,6 +761,13 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
 DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
 		 drm_tv_subconnector_enum_list)
 
+static struct drm_prop_enum_list drm_cp_enum_list[] = {
+	{ DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" },
+	{ DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" },
+	{ DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" },
+};
+DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
+
 /**
  * DOC: standard connector properties
  *
@@ -817,14 +829,50 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
  * 	should update this value using drm_mode_connector_set_tile_property().
  * 	Userspace cannot change this property.
  * link-status:
- *      Connector link-status property to indicate the status of link. The default
- *      value of link-status is "GOOD". If something fails during or after modeset,
- *      the kernel driver may set this to "BAD" and issue a hotplug uevent. Drivers
- *      should update this value using drm_mode_connector_set_link_status_property().
+ *      Connector link-status property to indicate the status of link. The
+ *      default value of link-status is "GOOD". If something fails during or
+ *      after modeset, the kernel driver may set this to "BAD" and issue a
+ *      hotplug uevent. Drivers should update this value using
+ *      drm_mode_connector_set_link_status_property().
  * non_desktop:
  * 	Indicates the output should be ignored for purposes of displaying a
  * 	standard desktop environment or console. This is most likely because
  * 	the output device is not rectilinear.
+ * Content Protection:
+ *	This property is used by userspace to request the kernel protect future
+ *	content communicated over the link. When requested, kernel will apply
+ *	the appropriate means of protection (most often HDCP), and use the
+ *	property to tell userspace the protection is active.
+ *
+ *	Drivers can set this up by calling
+ *	drm_connector_attach_content_protection_property() on initialization.
+ *
+ *	The value of this property can be one of the following:
+ *
+ *	- DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0
+ *		The link is not protected, content is transmitted in the clear.
+ *	- DRM_MODE_CONTENT_PROTECTION_DESIRED = 1
+ *		Userspace has requested content protection, but the link is not
+ *		currently protected. When in this state, kernel should enable
+ *		Content Protection as soon as possible.
+ *	- DRM_MODE_CONTENT_PROTECTION_ENABLED = 2
+ *		Userspace has requested content protection, and the link is
+ *		protected. Only the driver can set the property to this value.
+ *		If userspace attempts to set to ENABLED, kernel will return
+ *		-EINVAL.
+ *
+ *	A few guidelines:
+ *
+ *	- DESIRED state should be preserved until userspace de-asserts it by
+ *	  setting the property to UNDESIRED. This means ENABLED should only
+ *	  transition to UNDESIRED when the user explicitly requests it.
+ *	- If the state is DESIRED, kernel should attempt to re-authenticate the
+ *	  link whenever possible. This includes across disable/enable, dpms,
+ *	  hotplug, downstream device changes, link status failures, etc..
+ *	- Userspace is responsible for polling the property to determine when
+ *	  the value transitions from ENABLED to DESIRED. This signifies the link
+ *	  is no longer protected and userspace should take appropriate action
+ *	  (whatever that might be).
  *
  * Connectors also have one standardized atomic property:
  *
@@ -1125,6 +1173,42 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property);
 
+/**
+ * drm_connector_attach_content_protection_property - attach content protection
+ * property
+ *
+ * @connector: connector to attach CP property on.
+ *
+ * This is used to add support for content protection on select connectors.
+ * Content Protection is intentionally vague to allow for different underlying
+ * technologies, however it is most implemented by HDCP.
+ *
+ * The content protection will be set to &drm_connector_state.content_protection
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_content_protection_property(
+		struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_property *prop;
+
+	prop = drm_property_create_enum(dev, 0, "Content Protection",
+					drm_cp_enum_list,
+					ARRAY_SIZE(drm_cp_enum_list));
+	if (!prop)
+		return -ENOMEM;
+
+	drm_object_attach_property(&connector->base, prop,
+				   DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
+
+	connector->content_protection_property = prop;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_content_protection_property);
+
 /**
  * drm_mode_create_aspect_ratio_property - create aspect ratio property
  * @dev: DRM device
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f0556e654116..353e24fcde9e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -282,6 +282,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
 	WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
 	WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
 
+	/* crtc index is used with 32bit bitmasks */
+	if (WARN_ON(config->num_crtc >= 32))
+		return -EINVAL;
+
 	crtc->dev = dev;
 	crtc->funcs = funcs;
 
@@ -610,7 +614,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 			goto out;
 		}
 
-		ret = drm_mode_convert_umode(mode, &crtc_req->mode);
+		ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode);
 		if (ret) {
 			DRM_DEBUG_KMS("Invalid mode\n");
 			goto out;
diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c
index 9dd879589a2c..9f8312137cad 100644
--- a/drivers/gpu/drm/drm_debugfs_crc.c
+++ b/drivers/gpu/drm/drm_debugfs_crc.c
@@ -307,10 +307,29 @@ static ssize_t crtc_crc_read(struct file *filep, char __user *user_buf,
 	return LINE_LEN(crc->values_cnt);
 }
 
+static unsigned int crtc_crc_poll(struct file *file, poll_table *wait)
+{
+	struct drm_crtc *crtc = file->f_inode->i_private;
+	struct drm_crtc_crc *crc = &crtc->crc;
+	unsigned ret;
+
+	poll_wait(file, &crc->wq, wait);
+
+	spin_lock_irq(&crc->lock);
+	if (crc->source && crtc_crc_data_count(crc))
+		ret = POLLIN | POLLRDNORM;
+	else
+		ret = 0;
+	spin_unlock_irq(&crc->lock);
+
+	return ret;
+}
+
 static const struct file_operations drm_crtc_crc_data_fops = {
 	.owner = THIS_MODULE,
 	.open = crtc_crc_open,
 	.read = crtc_crc_read,
+	.poll = crtc_crc_poll,
 	.release = crtc_crc_release,
 };
 
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index adf79be42c1e..ffe14ec3e7f2 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -146,6 +146,8 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate)
 		return DP_LINK_BW_2_7;
 	case 540000:
 		return DP_LINK_BW_5_4;
+	case 810000:
+		return DP_LINK_BW_8_1;
 	}
 }
 EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code);
@@ -161,6 +163,8 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw)
 		return 270000;
 	case DP_LINK_BW_5_4:
 		return 540000;
+	case DP_LINK_BW_8_1:
+		return 810000;
 	}
 }
 EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 70dcfa58d3c2..36df7df5fe1a 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -2087,6 +2087,9 @@ static bool drm_dp_get_vc_payload_bw(int dp_link_bw,
 	case DP_LINK_BW_5_4:
 		*out = 10 * dp_link_count;
 		break;
+	case DP_LINK_BW_8_1:
+		*out = 15 * dp_link_count;
+		break;
 	}
 	return true;
 }
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index ddd537914575..f0cefcf33339 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -113,6 +113,9 @@ static const struct edid_quirk {
 	/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
 	{ "AEO", 0, EDID_QUIRK_FORCE_6BPC },
 
+	/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
+	{ "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },
+
 	/* Belinea 10 15 55 */
 	{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
 	{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
@@ -2767,7 +2770,7 @@ do_detailed_mode(struct detailed_timing *timing, void *c)
 
 		drm_mode_probed_add(closure->connector, newmode);
 		closure->modes++;
-		closure->preferred = 0;
+		closure->preferred = false;
 	}
 }
 
@@ -2784,7 +2787,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 	struct detailed_mode_closure closure = {
 		.connector = connector,
 		.edid = edid,
-		.preferred = 1,
+		.preferred = true,
 		.quirks = quirks,
 	};
 
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 59e0ebe733f8..273e1c59c54a 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -110,6 +110,10 @@ int drm_encoder_init(struct drm_device *dev,
 {
 	int ret;
 
+	/* encoder index is used with 32bit bitmasks */
+	if (WARN_ON(dev->mode_config.num_encoder >= 32))
+		return -EINVAL;
+
 	ret = drm_mode_object_add(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 9c0152df45ad..5ca6395cd4d3 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -112,18 +112,18 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_XBGR4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_RGBX4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGRX4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ARGB4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ABGR4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGBA4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGRA4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+		{ .format = DRM_FORMAT_ARGB4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_ABGR4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_RGBA4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGRA4444,	.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
 		{ .format = DRM_FORMAT_XRGB1555,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_XBGR1555,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_RGBX5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGRX5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ARGB1555,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ABGR1555,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGBA5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGRA5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+		{ .format = DRM_FORMAT_ARGB1555,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_ABGR1555,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_RGBA5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGRA5551,	.depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
 		{ .format = DRM_FORMAT_RGB565,		.depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGR565,		.depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_RGB888,		.depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
@@ -132,26 +132,26 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_XBGR8888,	.depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_RGBX8888,	.depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGRX8888,	.depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGB565_A8,	.depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGR565_A8,	.depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1 },
+		{ .format = DRM_FORMAT_RGB565_A8,	.depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGR565_A8,	.depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
 		{ .format = DRM_FORMAT_XRGB2101010,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_XBGR2101010,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_RGBX1010102,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
 		{ .format = DRM_FORMAT_BGRX1010102,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ARGB2101010,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ABGR2101010,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGBA1010102,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGRA1010102,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ARGB8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_ABGR8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGBA8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGRA8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGB888_A8,	.depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGR888_A8,	.depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_XRGB8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_XBGR8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_RGBX8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
-		{ .format = DRM_FORMAT_BGRX8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
+		{ .format = DRM_FORMAT_ARGB2101010,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_ABGR2101010,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_RGBA1010102,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGRA1010102,	.depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_ARGB8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_ABGR8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_RGBA8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGRA8888,	.depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_RGB888_A8,	.depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGR888_A8,	.depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_XRGB8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_XBGR8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_RGBX8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+		{ .format = DRM_FORMAT_BGRX8888_A8,	.depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
 		{ .format = DRM_FORMAT_YUV410,		.depth = 0,  .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 },
 		{ .format = DRM_FORMAT_YVU410,		.depth = 0,  .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 },
 		{ .format = DRM_FORMAT_YUV411,		.depth = 0,  .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 },
@@ -172,7 +172,7 @@ const struct drm_format_info *__drm_format_info(u32 format)
 		{ .format = DRM_FORMAT_YVYU,		.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
 		{ .format = DRM_FORMAT_UYVY,		.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
 		{ .format = DRM_FORMAT_VYUY,		.depth = 0,  .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
-		{ .format = DRM_FORMAT_AYUV,		.depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
+		{ .format = DRM_FORMAT_AYUV,		.depth = 0,  .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
 	};
 
 	unsigned int i;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 4aafe4802099..af782911c505 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -509,7 +509,7 @@ int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
 		return -EACCES;
 
 	/* MASTER is only for master or control clients */
-	if (unlikely((flags & DRM_MASTER) && 
+	if (unlikely((flags & DRM_MASTER) &&
 		     !drm_is_current_master(file_priv) &&
 		     !drm_is_control_client(file_priv)))
 		return -EACCES;
@@ -704,7 +704,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
  *
  *     ##define DRM_IOCTL_MY_DRIVER_OPERATION \
  *         DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation)
- * 
+ *
  * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to
  * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire
  * up the handlers and set the access rights::
@@ -848,7 +848,7 @@ long drm_ioctl(struct file *filp,
 	if (kdata != stack_kdata)
 		kfree(kdata);
 	if (retcode)
-		DRM_DEBUG("ret = %d\n", retcode);
+		DRM_DEBUG("pid=%d, ret = %d\n", task_pid_nr(current), retcode);
 	return retcode;
 }
 EXPORT_SYMBOL(drm_ioctl);
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index fc0ebd273ef8..7ca500b8c399 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -149,3 +149,16 @@ void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
 		iounmap(map->handle);
 }
 EXPORT_SYMBOL(drm_legacy_ioremapfree);
+
+u64 drm_get_max_iomem(void)
+{
+	struct resource *tmp;
+	u64 max_iomem = 0;
+
+	for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
+		max_iomem = max(max_iomem,  tmp->end);
+	}
+
+	return max_iomem;
+}
+EXPORT_SYMBOL(drm_get_max_iomem);
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 4b47226b90d4..bc73b7f5b9fc 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -498,8 +498,9 @@ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
 		.tx_buf = (u8 [2]) { 0, 0 },
 		.tx_len = 2,
 	};
+	int ret = mipi_dsi_device_transfer(dsi, &msg);
 
-	return mipi_dsi_device_transfer(dsi, &msg);
+	return (ret < 0) ? ret : 0;
 }
 EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral);
 
@@ -517,8 +518,9 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
 		.tx_buf = (u8 [2]) { 0, 0 },
 		.tx_len = 2,
 	};
+	int ret = mipi_dsi_device_transfer(dsi, &msg);
 
-	return mipi_dsi_device_transfer(dsi, &msg);
+	return (ret < 0) ? ret : 0;
 }
 EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
 
@@ -541,8 +543,9 @@ int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
 		.tx_len = sizeof(tx),
 		.tx_buf = tx,
 	};
+	int ret = mipi_dsi_device_transfer(dsi, &msg);
 
-	return mipi_dsi_device_transfer(dsi, &msg);
+	return (ret < 0) ? ret : 0;
 }
 EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);
 
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 4a3f68a33844..c397b523c945 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -833,7 +833,7 @@ EXPORT_SYMBOL(drm_mode_get_hv_timing);
  */
 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
 {
-	if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
+	if (!p)
 		return;
 
 	p->crtc_clock = p->clock;
@@ -1023,19 +1023,18 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
 }
 EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
 
-/**
- * drm_mode_validate_basic - make sure the mode is somewhat sane
- * @mode: mode to check
- *
- * Check that the mode timings are at least somewhat reasonable.
- * Any hardware specific limits are left up for each driver to check.
- *
- * Returns:
- * The mode status
- */
-enum drm_mode_status
+static enum drm_mode_status
 drm_mode_validate_basic(const struct drm_display_mode *mode)
 {
+	if (mode->type & ~DRM_MODE_TYPE_ALL)
+		return MODE_BAD;
+
+	if (mode->flags & ~DRM_MODE_FLAG_ALL)
+		return MODE_BAD;
+
+	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
+		return MODE_BAD;
+
 	if (mode->clock == 0)
 		return MODE_CLOCK_LOW;
 
@@ -1053,7 +1052,35 @@ drm_mode_validate_basic(const struct drm_display_mode *mode)
 
 	return MODE_OK;
 }
-EXPORT_SYMBOL(drm_mode_validate_basic);
+
+/**
+ * drm_mode_validate_driver - make sure the mode is somewhat sane
+ * @dev: drm device
+ * @mode: mode to check
+ *
+ * First do basic validation on the mode, and then allow the driver
+ * to check for device/driver specific limitations via the optional
+ * &drm_mode_config_helper_funcs.mode_valid hook.
+ *
+ * Returns:
+ * The mode status
+ */
+enum drm_mode_status
+drm_mode_validate_driver(struct drm_device *dev,
+			const struct drm_display_mode *mode)
+{
+	enum drm_mode_status status;
+
+	status = drm_mode_validate_basic(mode);
+	if (status != MODE_OK)
+		return status;
+
+	if (dev->mode_config.funcs->mode_valid)
+		return dev->mode_config.funcs->mode_valid(dev, mode);
+	else
+		return MODE_OK;
+}
+EXPORT_SYMBOL(drm_mode_validate_driver);
 
 /**
  * drm_mode_validate_size - make sure modes adhere to size constraints
@@ -1555,6 +1582,7 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
 
 /**
  * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode
+ * @dev: drm device
  * @out: drm_display_mode to return to the user
  * @in: drm_mode_modeinfo to use
  *
@@ -1564,7 +1592,8 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_convert_umode(struct drm_display_mode *out,
+int drm_mode_convert_umode(struct drm_device *dev,
+			   struct drm_display_mode *out,
 			   const struct drm_mode_modeinfo *in)
 {
 	int ret = -EINVAL;
@@ -1574,9 +1603,6 @@ int drm_mode_convert_umode(struct drm_display_mode *out,
 		goto out;
 	}
 
-	if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
-		goto out;
-
 	out->clock = in->clock;
 	out->hdisplay = in->hdisplay;
 	out->hsync_start = in->hsync_start;
@@ -1594,7 +1620,7 @@ int drm_mode_convert_umode(struct drm_display_mode *out,
 	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
 	out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
 
-	out->status = drm_mode_validate_basic(out);
+	out->status = drm_mode_validate_driver(dev, out);
 	if (out->status != MODE_OK)
 		goto out;
 
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 2c90519576a3..09de6ecb3968 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -173,6 +173,10 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	unsigned int format_modifier_count = 0;
 	int ret;
 
+	/* plane index is used with 32bit bitmasks */
+	if (WARN_ON(config->num_total_plane >= 32))
+		return -EINVAL;
+
 	ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
 	if (ret)
 		return ret;
@@ -944,7 +948,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 		if (r)
 			return r;
 
-		current_vblank = drm_crtc_vblank_count(crtc);
+		current_vblank = (u32)drm_crtc_vblank_count(crtc);
 
 		switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
 		case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 9a17725b0f7a..e82a976f0fba 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -73,6 +73,9 @@
  * Drivers should detect this situation and return back the gem object
  * from the dma-buf private.  Prime will do this automatically for drivers that
  * use the drm_gem_prime_{import,export} helpers.
+ *
+ * GEM struct &dma_buf_ops symbols are now exported. They can be resued by
+ * drivers which implement GEM interface.
  */
 
 struct drm_prime_member {
@@ -180,9 +183,20 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
 	return -ENOENT;
 }
 
-static int drm_gem_map_attach(struct dma_buf *dma_buf,
-			      struct device *target_dev,
-			      struct dma_buf_attachment *attach)
+/**
+ * drm_gem_map_attach - dma_buf attach implementation for GEM
+ * @dma_buf: buffer to attach device to
+ * @target_dev: not used
+ * @attach: buffer attachment data
+ *
+ * Allocates &drm_prime_attachment and calls &drm_driver.gem_prime_pin for
+ * device specific attachment. This can be used as the &dma_buf_ops.attach
+ * callback.
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int drm_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev,
+		       struct dma_buf_attachment *attach)
 {
 	struct drm_prime_attachment *prime_attach;
 	struct drm_gem_object *obj = dma_buf->priv;
@@ -200,9 +214,18 @@ static int drm_gem_map_attach(struct dma_buf *dma_buf,
 
 	return dev->driver->gem_prime_pin(obj);
 }
+EXPORT_SYMBOL(drm_gem_map_attach);
 
-static void drm_gem_map_detach(struct dma_buf *dma_buf,
-			       struct dma_buf_attachment *attach)
+/**
+ * drm_gem_map_detach - dma_buf detach implementation for GEM
+ * @dma_buf: buffer to detach from
+ * @attach: attachment to be detached
+ *
+ * Cleans up &dma_buf_attachment. This can be used as the &dma_buf_ops.detach
+ * callback.
+ */
+void drm_gem_map_detach(struct dma_buf *dma_buf,
+			struct dma_buf_attachment *attach)
 {
 	struct drm_prime_attachment *prime_attach = attach->priv;
 	struct drm_gem_object *obj = dma_buf->priv;
@@ -228,6 +251,7 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
 	kfree(prime_attach);
 	attach->priv = NULL;
 }
+EXPORT_SYMBOL(drm_gem_map_detach);
 
 void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
 					struct dma_buf *dma_buf)
@@ -254,8 +278,20 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr
 	}
 }
 
-static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
-					    enum dma_data_direction dir)
+/**
+ * drm_gem_map_dma_buf - map_dma_buf implementation for GEM
+ * @attach: attachment whose scatterlist is to be returned
+ * @dir: direction of DMA transfer
+ *
+ * Calls &drm_driver.gem_prime_get_sg_table and then maps the scatterlist. This
+ * can be used as the &dma_buf_ops.map_dma_buf callback.
+ *
+ * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR
+ * on error. May return -EINTR if it is interrupted by a signal.
+ */
+
+struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
+				     enum dma_data_direction dir)
 {
 	struct drm_prime_attachment *prime_attach = attach->priv;
 	struct drm_gem_object *obj = attach->dmabuf->priv;
@@ -291,13 +327,21 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
 
 	return sgt;
 }
+EXPORT_SYMBOL(drm_gem_map_dma_buf);
 
-static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
-				  struct sg_table *sgt,
-				  enum dma_data_direction dir)
+/**
+ * drm_gem_unmap_dma_buf - unmap_dma_buf implementation for GEM
+ *
+ * Not implemented. The unmap is done at drm_gem_map_detach().  This can be
+ * used as the &dma_buf_ops.unmap_dma_buf callback.
+ */
+void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
+			   struct sg_table *sgt,
+			   enum dma_data_direction dir)
 {
 	/* nothing to be done here */
 }
+EXPORT_SYMBOL(drm_gem_unmap_dma_buf);
 
 /**
  * drm_gem_dmabuf_export - dma_buf export implementation for GEM
@@ -348,47 +392,99 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_release);
 
-static void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
+/**
+ * drm_gem_dmabuf_vmap - dma_buf vmap implementation for GEM
+ * @dma_buf: buffer to be mapped
+ *
+ * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap
+ * callback.
+ *
+ * Returns the kernel virtual address.
+ */
+void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
 	struct drm_device *dev = obj->dev;
 
 	return dev->driver->gem_prime_vmap(obj);
 }
+EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
 
-static void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
+/**
+ * drm_gem_dmabuf_vunmap - dma_buf vunmap implementation for GEM
+ * @dma_buf: buffer to be unmapped
+ * @vaddr: the virtual address of the buffer
+ *
+ * Releases a kernel virtual mapping. This can be used as the
+ * &dma_buf_ops.vunmap callback.
+ */
+void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
 	struct drm_device *dev = obj->dev;
 
 	dev->driver->gem_prime_vunmap(obj, vaddr);
 }
+EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
 
-static void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
-					unsigned long page_num)
+/**
+ * drm_gem_dmabuf_kmap_atomic - map_atomic implementation for GEM
+ *
+ * Not implemented. This can be used as the &dma_buf_ops.map_atomic callback.
+ */
+void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
+				 unsigned long page_num)
 {
 	return NULL;
 }
+EXPORT_SYMBOL(drm_gem_dmabuf_kmap_atomic);
 
-static void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
-					 unsigned long page_num, void *addr)
+/**
+ * drm_gem_dmabuf_kunmap_atomic - unmap_atomic implementation for GEM
+ *
+ * Not implemented. This can be used as the &dma_buf_ops.unmap_atomic callback.
+ */
+void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
+				  unsigned long page_num, void *addr)
 {
 
 }
-static void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf,
-				 unsigned long page_num)
+EXPORT_SYMBOL(drm_gem_dmabuf_kunmap_atomic);
+
+/**
+ * drm_gem_dmabuf_kmap - map implementation for GEM
+ *
+ * Not implemented. This can be used as the &dma_buf_ops.map callback.
+ */
+void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
 {
 	return NULL;
 }
+EXPORT_SYMBOL(drm_gem_dmabuf_kmap);
 
-static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
-				  unsigned long page_num, void *addr)
+/**
+ * drm_gem_dmabuf_kunmap - unmap implementation for GEM
+ *
+ * Not implemented. This can be used as the &dma_buf_ops.unmap callback.
+ */
+void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num,
+			   void *addr)
 {
 
 }
+EXPORT_SYMBOL(drm_gem_dmabuf_kunmap);
 
-static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf,
-			       struct vm_area_struct *vma)
+/**
+ * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM
+ * @dma_buf: buffer to be mapped
+ * @vma: virtual address range
+ *
+ * Provides memory mapping for the buffer. This can be used as the
+ * &dma_buf_ops.mmap callback.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
 	struct drm_device *dev = obj->dev;
@@ -398,6 +494,7 @@ static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf,
 
 	return dev->driver->gem_prime_mmap(obj, vma);
 }
+EXPORT_SYMBOL(drm_gem_dmabuf_mmap);
 
 static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
 	.attach = drm_gem_map_attach,
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 555fbe54d6e2..527743394150 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -499,7 +499,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
 
 	list_for_each_entry(mode, &connector->modes, head) {
 		if (mode->status == MODE_OK)
-			mode->status = drm_mode_validate_basic(mode);
+			mode->status = drm_mode_validate_driver(dev, mode);
 
 		if (mode->status == MODE_OK)
 			mode->status = drm_mode_validate_size(mode, maxX, maxY);
@@ -653,6 +653,26 @@ static void output_poll_execute(struct work_struct *work)
 		schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
 }
 
+/**
+ * drm_kms_helper_is_poll_worker - is %current task an output poll worker?
+ *
+ * Determine if %current task is an output poll worker.  This can be used
+ * to select distinct code paths for output polling versus other contexts.
+ *
+ * One use case is to avoid a deadlock between the output poll worker and
+ * the autosuspend worker wherein the latter waits for polling to finish
+ * upon calling drm_kms_helper_poll_disable(), while the former waits for
+ * runtime suspend to finish upon calling pm_runtime_get_sync() in a
+ * connector ->detect hook.
+ */
+bool drm_kms_helper_is_poll_worker(void)
+{
+	struct work_struct *work = current_work();
+
+	return work && work->func == output_poll_execute;
+}
+EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
+
 /**
  * drm_kms_helper_poll_disable - disable output polling
  * @dev: drm_device
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 9f3b1c94802b..9d3f6b70812c 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -100,8 +100,9 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
 	if (!crtc_state->enable)
 		return 0; /* nothing to check when disabling or disabled */
 
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
 						  &clip,
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 32d9bcf5be7f..c781cb426bf1 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -271,7 +271,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	store_vblank(dev, pipe, diff, t_vblank, cur_vblank);
 }
 
-static u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe)
+static u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe)
 {
 	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 
@@ -292,11 +292,11 @@ static u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe)
  * This is mostly useful for hardware that can obtain the scanout position, but
  * doesn't have a hardware frame counter.
  */
-u32 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc)
+u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	unsigned int pipe = drm_crtc_index(crtc);
-	u32 vblank;
+	u64 vblank;
 	unsigned long flags;
 
 	WARN_ONCE(drm_debug & DRM_UT_VBL && !dev->driver->get_vblank_timestamp,
@@ -347,23 +347,25 @@ void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
 	spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
 
 	/*
-	 * Only disable vblank interrupts if they're enabled. This avoids
-	 * calling the ->disable_vblank() operation in atomic context with the
-	 * hardware potentially runtime suspended.
+	 * Update vblank count and disable vblank interrupts only if the
+	 * interrupts were enabled. This avoids calling the ->disable_vblank()
+	 * operation in atomic context with the hardware potentially runtime
+	 * suspended.
 	 */
-	if (vblank->enabled) {
-		__disable_vblank(dev, pipe);
-		vblank->enabled = false;
-	}
+	if (!vblank->enabled)
+		goto out;
 
 	/*
-	 * Always update the count and timestamp to maintain the
+	 * Update the count and timestamp to maintain the
 	 * appearance that the counter has been ticking all along until
 	 * this time. This makes the count account for the entire time
 	 * between drm_crtc_vblank_on() and drm_crtc_vblank_off().
 	 */
 	drm_update_vblank_count(dev, pipe, false);
+	__disable_vblank(dev, pipe);
+	vblank->enabled = false;
 
+out:
 	spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
 }
 
@@ -1055,7 +1057,7 @@ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe)
 {
 	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 	int ret;
-	u32 last;
+	u64 last;
 
 	if (WARN_ON(pipe >= dev->num_crtcs))
 		return;
@@ -1235,6 +1237,65 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_vblank_on);
 
+/**
+ * drm_vblank_restore - estimated vblanks using timestamps and update it.
+ *
+ * Power manamement features can cause frame counter resets between vblank
+ * disable and enable. Drivers can then use this function in their
+ * &drm_crtc_funcs.enable_vblank implementation to estimate the vblanks since
+ * the last &drm_crtc_funcs.disable_vblank.
+ *
+ * This function is the legacy version of drm_crtc_vblank_restore().
+ */
+void drm_vblank_restore(struct drm_device *dev, unsigned int pipe)
+{
+	ktime_t t_vblank;
+	struct drm_vblank_crtc *vblank;
+	int framedur_ns;
+	u64 diff_ns;
+	u32 cur_vblank, diff = 1;
+	int count = DRM_TIMESTAMP_MAXRETRIES;
+
+	if (WARN_ON(pipe >= dev->num_crtcs))
+		return;
+
+	assert_spin_locked(&dev->vbl_lock);
+	assert_spin_locked(&dev->vblank_time_lock);
+
+	vblank = &dev->vblank[pipe];
+	WARN_ONCE((drm_debug & DRM_UT_VBL) && !vblank->framedur_ns,
+		  "Cannot compute missed vblanks without frame duration\n");
+	framedur_ns = vblank->framedur_ns;
+
+	do {
+		cur_vblank = __get_vblank_counter(dev, pipe);
+		drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false);
+	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
+
+	diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
+	if (framedur_ns)
+		diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
+
+
+	DRM_DEBUG_VBL("missed %d vblanks in %lld ns, frame duration=%d ns, hw_diff=%d\n",
+		      diff, diff_ns, framedur_ns, cur_vblank - vblank->last);
+	store_vblank(dev, pipe, diff, t_vblank, cur_vblank);
+}
+EXPORT_SYMBOL(drm_vblank_restore);
+
+/**
+ * drm_crtc_vblank_restore - estimate vblanks using timestamps and update it.
+ * Power manamement features can cause frame counter resets between vblank
+ * disable and enable. Drivers can then use this function in their
+ * &drm_crtc_funcs.enable_vblank implementation to estimate the vblanks since
+ * the last &drm_crtc_funcs.disable_vblank.
+ */
+void drm_crtc_vblank_restore(struct drm_crtc *crtc)
+{
+	drm_vblank_restore(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_vblank_restore);
+
 static void drm_legacy_vblank_pre_modeset(struct drm_device *dev,
 					  unsigned int pipe)
 {
diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig
index 3f58b4077767..e5bfeca361bd 100644
--- a/drivers/gpu/drm/etnaviv/Kconfig
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -11,6 +11,7 @@ config DRM_ETNAVIV
 	select WANT_DEV_COREDUMP
 	select CMA if HAVE_DMA_CONTIGUOUS
 	select DMA_CMA if HAVE_DMA_CONTIGUOUS
+	select DRM_SCHED
 	help
 	  DRM driver for Vivante GPUs.
 
diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 1281c8d4fae5..9bb780c22501 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -12,6 +12,7 @@ etnaviv-y := \
 	etnaviv_iommu_v2.o \
 	etnaviv_iommu.o \
 	etnaviv_mmu.o \
-	etnaviv_perfmon.o
+	etnaviv_perfmon.o \
+	etnaviv_sched.o
 
 obj-$(CONFIG_DRM_ETNAVIV)	+= etnaviv.o
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 6faf4042db23..ab50090d066c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -101,12 +101,25 @@ static void load_gpu(struct drm_device *dev)
 
 static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
 {
+	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct etnaviv_file_private *ctx;
+	int i;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
+	for (i = 0; i < ETNA_MAX_PIPES; i++) {
+		struct etnaviv_gpu *gpu = priv->gpu[i];
+
+		if (gpu) {
+			drm_sched_entity_init(&gpu->sched,
+				&ctx->sched_entity[i],
+				&gpu->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL],
+				32, NULL);
+			}
+	}
+
 	file->driver_priv = ctx;
 
 	return 0;
@@ -126,6 +139,9 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
 			if (gpu->lastctx == ctx)
 				gpu->lastctx = NULL;
 			mutex_unlock(&gpu->lock);
+
+			drm_sched_entity_fini(&gpu->sched,
+					      &ctx->sched_entity[i]);
 		}
 	}
 
@@ -637,25 +653,21 @@ static int compare_str(struct device *dev, void *data)
 static int etnaviv_pdev_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *node = dev->of_node;
 	struct component_match *match = NULL;
 
 	dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 
-	if (node) {
+	if (!dev->platform_data) {
 		struct device_node *core_node;
-		int i;
 
-		for (i = 0; ; i++) {
-			core_node = of_parse_phandle(node, "cores", i);
-			if (!core_node)
-				break;
+		for_each_compatible_node(core_node, NULL, "vivante,gc") {
+			if (!of_device_is_available(core_node))
+				continue;
 
 			drm_of_component_match_add(&pdev->dev, &match,
 						   compare_of, core_node);
-			of_node_put(core_node);
 		}
-	} else if (dev->platform_data) {
+	} else {
 		char **names = dev->platform_data;
 		unsigned i;
 
@@ -673,25 +685,18 @@ static int etnaviv_pdev_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id dt_match[] = {
-	{ .compatible = "fsl,imx-gpu-subsystem" },
-	{ .compatible = "marvell,dove-gpu-subsystem" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, dt_match);
-
 static struct platform_driver etnaviv_platform_driver = {
 	.probe      = etnaviv_pdev_probe,
 	.remove     = etnaviv_pdev_remove,
 	.driver     = {
 		.name   = "etnaviv",
-		.of_match_table = dt_match,
 	},
 };
 
 static int __init etnaviv_init(void)
 {
 	int ret;
+	struct device_node *np;
 
 	etnaviv_validate_init();
 
@@ -703,6 +708,19 @@ static int __init etnaviv_init(void)
 	if (ret != 0)
 		platform_driver_unregister(&etnaviv_gpu_driver);
 
+	/*
+	 * If the DT contains at least one available GPU device, instantiate
+	 * the DRM platform device.
+	 */
+	for_each_compatible_node(np, NULL, "vivante,gc") {
+		if (!of_device_is_available(np))
+			continue;
+
+		platform_device_register_simple("etnaviv", -1, NULL, 0);
+		of_node_put(np);
+		break;
+	}
+
 	return ret;
 }
 module_init(etnaviv_init);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index a54f0b758a5c..1f055d931c6c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -34,6 +34,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/etnaviv_drm.h>
+#include <drm/gpu_scheduler.h>
 
 struct etnaviv_cmdbuf;
 struct etnaviv_gpu;
@@ -42,11 +43,11 @@ struct etnaviv_gem_object;
 struct etnaviv_gem_submit;
 
 struct etnaviv_file_private {
-	/* currently we don't do anything useful with this.. but when
-	 * per-context address spaces are supported we'd keep track of
+	/*
+	 * When per-context address spaces are supported we'd keep track of
 	 * the context's page-tables here.
 	 */
-	int dummy;
+	struct drm_sched_entity		sched_entity[ETNA_MAX_PIPES];
 };
 
 struct etnaviv_drm_private {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
index 6d0909c589d1..48aef6cf6a42 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -20,9 +20,13 @@
 #include "etnaviv_gem.h"
 #include "etnaviv_gpu.h"
 #include "etnaviv_mmu.h"
+#include "etnaviv_sched.h"
 #include "state.xml.h"
 #include "state_hi.xml.h"
 
+static bool etnaviv_dump_core = true;
+module_param_named(dump_core, etnaviv_dump_core, bool, 0600);
+
 struct core_dump_iterator {
 	void *start;
 	struct etnaviv_dump_object_header *hdr;
@@ -121,10 +125,16 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
 	struct etnaviv_vram_mapping *vram;
 	struct etnaviv_gem_object *obj;
 	struct etnaviv_gem_submit *submit;
+	struct drm_sched_job *s_job;
 	unsigned int n_obj, n_bomap_pages;
 	size_t file_size, mmu_size;
 	__le64 *bomap, *bomap_start;
 
+	/* Only catch the first event, or when manually re-armed */
+	if (!etnaviv_dump_core)
+		return;
+	etnaviv_dump_core = false;
+
 	mmu_size = etnaviv_iommu_dump_size(gpu->mmu);
 
 	/* We always dump registers, mmu, ring and end marker */
@@ -135,10 +145,13 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
 		    mmu_size + gpu->buffer.size;
 
 	/* Add in the active command buffers */
-	list_for_each_entry(submit, &gpu->active_submit_list, node) {
+	spin_lock(&gpu->sched.job_list_lock);
+	list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) {
+		submit = to_etnaviv_submit(s_job);
 		file_size += submit->cmdbuf.size;
 		n_obj++;
 	}
+	spin_unlock(&gpu->sched.job_list_lock);
 
 	/* Add in the active buffer objects */
 	list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
@@ -180,10 +193,14 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
 			      gpu->buffer.size,
 			      etnaviv_cmdbuf_get_va(&gpu->buffer));
 
-	list_for_each_entry(submit, &gpu->active_submit_list, node)
+	spin_lock(&gpu->sched.job_list_lock);
+	list_for_each_entry(s_job, &gpu->sched.ring_mirror_list, node) {
+		submit = to_etnaviv_submit(s_job);
 		etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD,
 				      submit->cmdbuf.vaddr, submit->cmdbuf.size,
 				      etnaviv_cmdbuf_get_va(&submit->cmdbuf));
+	}
+	spin_unlock(&gpu->sched.job_list_lock);
 
 	/* Reserve space for the bomap */
 	if (n_bomap_pages) {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index be72a9833f2b..93e696fcc14f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -94,6 +94,9 @@ struct etnaviv_gem_submit_bo {
 	u32 flags;
 	struct etnaviv_gem_object *obj;
 	struct etnaviv_vram_mapping *mapping;
+	struct dma_fence *excl;
+	unsigned int nr_shared;
+	struct dma_fence **shared;
 };
 
 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
@@ -101,9 +104,11 @@ struct etnaviv_gem_submit_bo {
  * make it easier to unwind when things go wrong, etc).
  */
 struct etnaviv_gem_submit {
+	struct drm_sched_job sched_job;
 	struct kref refcount;
 	struct etnaviv_gpu *gpu;
 	struct dma_fence *out_fence, *in_fence;
+	int out_fence_id;
 	struct list_head node; /* GPU active submit list */
 	struct etnaviv_cmdbuf cmdbuf;
 	bool runtime_resumed;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 1f8202bca061..46ecd3e66ac9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -22,6 +22,7 @@
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_perfmon.h"
+#include "etnaviv_sched.h"
 
 /*
  * Cmdstream submission:
@@ -169,29 +170,33 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit,
 	return ret;
 }
 
-static int submit_fence_sync(const struct etnaviv_gem_submit *submit)
+static int submit_fence_sync(struct etnaviv_gem_submit *submit)
 {
-	unsigned int context = submit->gpu->fence_context;
 	int i, ret = 0;
 
 	for (i = 0; i < submit->nr_bos; i++) {
-		struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
-		bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE;
-		bool explicit = !!(submit->flags & ETNA_SUBMIT_NO_IMPLICIT);
+		struct etnaviv_gem_submit_bo *bo = &submit->bos[i];
+		struct reservation_object *robj = bo->obj->resv;
 
-		ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write,
-						 explicit);
-		if (ret)
-			break;
-	}
+		if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) {
+			ret = reservation_object_reserve_shared(robj);
+			if (ret)
+				return ret;
+		}
+
+		if (submit->flags & ETNA_SUBMIT_NO_IMPLICIT)
+			continue;
+
+		if (bo->flags & ETNA_SUBMIT_BO_WRITE) {
+			ret = reservation_object_get_fences_rcu(robj, &bo->excl,
+								&bo->nr_shared,
+								&bo->shared);
+			if (ret)
+				return ret;
+		} else {
+			bo->excl = reservation_object_get_excl_rcu(robj);
+		}
 
-	if (submit->flags & ETNA_SUBMIT_FENCE_FD_IN) {
-		/*
-		 * Wait if the fence is from a foreign context, or if the fence
-		 * array contains any fence from a foreign context.
-		 */
-		if (!dma_fence_match_context(submit->in_fence, context))
-			ret = dma_fence_wait(submit->in_fence, true);
 	}
 
 	return ret;
@@ -381,8 +386,13 @@ static void submit_cleanup(struct kref *kref)
 
 	if (submit->in_fence)
 		dma_fence_put(submit->in_fence);
-	if (submit->out_fence)
+	if (submit->out_fence) {
+		/* first remove from IDR, so fence can not be found anymore */
+		mutex_lock(&submit->gpu->fence_idr_lock);
+		idr_remove(&submit->gpu->fence_idr, submit->out_fence_id);
+		mutex_unlock(&submit->gpu->fence_idr_lock);
 		dma_fence_put(submit->out_fence);
+	}
 	kfree(submit->pmrs);
 	kfree(submit);
 }
@@ -395,6 +405,7 @@ void etnaviv_submit_put(struct etnaviv_gem_submit *submit)
 int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		struct drm_file *file)
 {
+	struct etnaviv_file_private *ctx = file->driver_priv;
 	struct etnaviv_drm_private *priv = dev->dev_private;
 	struct drm_etnaviv_gem_submit *args = data;
 	struct drm_etnaviv_gem_submit_reloc *relocs;
@@ -503,10 +514,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	if (ret)
 		goto err_submit_objects;
 
-	ret = submit_lock_objects(submit, &ticket);
-	if (ret)
-		goto err_submit_objects;
-
 	if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4,
 				      relocs, args->nr_relocs)) {
 		ret = -EINVAL;
@@ -521,10 +528,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		}
 	}
 
-	ret = submit_fence_sync(submit);
-	if (ret)
-		goto err_submit_objects;
-
 	ret = submit_pin_objects(submit);
 	if (ret)
 		goto err_submit_objects;
@@ -539,9 +542,16 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 		goto err_submit_objects;
 
 	memcpy(submit->cmdbuf.vaddr, stream, args->stream_size);
-	submit->cmdbuf.user_size = ALIGN(args->stream_size, 8);
 
-	ret = etnaviv_gpu_submit(gpu, submit);
+	ret = submit_lock_objects(submit, &ticket);
+	if (ret)
+		goto err_submit_objects;
+
+	ret = submit_fence_sync(submit);
+	if (ret)
+		goto err_submit_objects;
+
+	ret = etnaviv_sched_push_job(&ctx->sched_entity[args->pipe], submit);
 	if (ret)
 		goto err_submit_objects;
 
@@ -563,7 +573,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
 	}
 
 	args->fence_fd = out_fence_fd;
-	args->fence = submit->out_fence->seqno;
+	args->fence = submit->out_fence_id;
 
 err_submit_objects:
 	etnaviv_submit_put(submit);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 21d0d22f1168..94fa3d3244fb 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -26,19 +26,21 @@
 #include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
 #include "etnaviv_perfmon.h"
+#include "etnaviv_sched.h"
 #include "common.xml.h"
 #include "state.xml.h"
 #include "state_hi.xml.h"
 #include "cmdstream.xml.h"
 
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET 0
+#endif
+
 static const struct platform_device_id gpu_ids[] = {
 	{ .name = "etnaviv-gpu,2d" },
 	{ },
 };
 
-static bool etnaviv_dump_core = true;
-module_param_named(dump_core, etnaviv_dump_core, bool, 0600);
-
 /*
  * Driver functions:
  */
@@ -807,6 +809,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
 	verify_dma(gpu, &debug);
 
 	seq_puts(m, "\tfeatures\n");
+	seq_printf(m, "\t major_features: 0x%08x\n",
+		   gpu->identity.features);
 	seq_printf(m, "\t minor_features0: 0x%08x\n",
 		   gpu->identity.minor_features0);
 	seq_printf(m, "\t minor_features1: 0x%08x\n",
@@ -912,38 +916,24 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
 }
 #endif
 
-/*
- * Hangcheck detection for locked gpu:
- */
-static void recover_worker(struct work_struct *work)
+void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu)
 {
-	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
-					       recover_work);
 	unsigned long flags;
 	unsigned int i = 0;
 
-	dev_err(gpu->dev, "hangcheck recover!\n");
+	dev_err(gpu->dev, "recover hung GPU!\n");
 
 	if (pm_runtime_get_sync(gpu->dev) < 0)
 		return;
 
 	mutex_lock(&gpu->lock);
 
-	/* Only catch the first event, or when manually re-armed */
-	if (etnaviv_dump_core) {
-		etnaviv_core_dump(gpu);
-		etnaviv_dump_core = false;
-	}
-
 	etnaviv_hw_reset(gpu);
 
 	/* complete all events, the GPU won't do it after the reset */
 	spin_lock_irqsave(&gpu->event_spinlock, flags);
-	for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) {
-		dma_fence_signal(gpu->event[i].fence);
-		gpu->event[i].fence = NULL;
+	for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS)
 		complete(&gpu->event_free);
-	}
 	bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS);
 	spin_unlock_irqrestore(&gpu->event_spinlock, flags);
 	gpu->completed_fence = gpu->active_fence;
@@ -955,56 +945,6 @@ static void recover_worker(struct work_struct *work)
 	mutex_unlock(&gpu->lock);
 	pm_runtime_mark_last_busy(gpu->dev);
 	pm_runtime_put_autosuspend(gpu->dev);
-
-	/* Retire the buffer objects in a work */
-	queue_work(gpu->wq, &gpu->retire_work);
-}
-
-static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
-{
-	DBG("%s", dev_name(gpu->dev));
-	mod_timer(&gpu->hangcheck_timer,
-		  round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES));
-}
-
-static void hangcheck_handler(struct timer_list *t)
-{
-	struct etnaviv_gpu *gpu = from_timer(gpu, t, hangcheck_timer);
-	u32 fence = gpu->completed_fence;
-	bool progress = false;
-
-	if (fence != gpu->hangcheck_fence) {
-		gpu->hangcheck_fence = fence;
-		progress = true;
-	}
-
-	if (!progress) {
-		u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
-		int change = dma_addr - gpu->hangcheck_dma_addr;
-
-		if (change < 0 || change > 16) {
-			gpu->hangcheck_dma_addr = dma_addr;
-			progress = true;
-		}
-	}
-
-	if (!progress && fence_after(gpu->active_fence, fence)) {
-		dev_err(gpu->dev, "hangcheck detected gpu lockup!\n");
-		dev_err(gpu->dev, "     completed fence: %u\n", fence);
-		dev_err(gpu->dev, "     active fence: %u\n",
-			gpu->active_fence);
-		queue_work(gpu->wq, &gpu->recover_work);
-	}
-
-	/* if still more pending work, reset the hangcheck timer: */
-	if (fence_after(gpu->active_fence, gpu->hangcheck_fence))
-		hangcheck_timer_reset(gpu);
-}
-
-static void hangcheck_disable(struct etnaviv_gpu *gpu)
-{
-	del_timer_sync(&gpu->hangcheck_timer);
-	cancel_work_sync(&gpu->recover_work);
 }
 
 /* fence object management */
@@ -1080,54 +1020,6 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu)
 	return &f->base;
 }
 
-int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
-	unsigned int context, bool exclusive, bool explicit)
-{
-	struct reservation_object *robj = etnaviv_obj->resv;
-	struct reservation_object_list *fobj;
-	struct dma_fence *fence;
-	int i, ret;
-
-	if (!exclusive) {
-		ret = reservation_object_reserve_shared(robj);
-		if (ret)
-			return ret;
-	}
-
-	if (explicit)
-		return 0;
-
-	/*
-	 * If we have any shared fences, then the exclusive fence
-	 * should be ignored as it will already have been signalled.
-	 */
-	fobj = reservation_object_get_list(robj);
-	if (!fobj || fobj->shared_count == 0) {
-		/* Wait on any existing exclusive fence which isn't our own */
-		fence = reservation_object_get_excl(robj);
-		if (fence && fence->context != context) {
-			ret = dma_fence_wait(fence, true);
-			if (ret)
-				return ret;
-		}
-	}
-
-	if (!exclusive || !fobj)
-		return 0;
-
-	for (i = 0; i < fobj->shared_count; i++) {
-		fence = rcu_dereference_protected(fobj->shared[i],
-						reservation_object_held(robj));
-		if (fence->context != context) {
-			ret = dma_fence_wait(fence, true);
-			if (ret)
-				return ret;
-		}
-	}
-
-	return 0;
-}
-
 /*
  * event management:
  */
@@ -1194,67 +1086,47 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
 /*
  * Cmdstream submission/retirement:
  */
-
-static void retire_worker(struct work_struct *work)
-{
-	struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
-					       retire_work);
-	u32 fence = gpu->completed_fence;
-	struct etnaviv_gem_submit *submit, *tmp;
-	LIST_HEAD(retire_list);
-
-	mutex_lock(&gpu->lock);
-	list_for_each_entry_safe(submit, tmp, &gpu->active_submit_list, node) {
-		if (!dma_fence_is_signaled(submit->out_fence))
-			break;
-
-		list_move(&submit->node, &retire_list);
-	}
-
-	gpu->retired_fence = fence;
-
-	mutex_unlock(&gpu->lock);
-
-	list_for_each_entry_safe(submit, tmp, &retire_list, node)
-		etnaviv_submit_put(submit);
-}
-
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
-	u32 fence, struct timespec *timeout)
+	u32 id, struct timespec *timeout)
 {
+	struct dma_fence *fence;
 	int ret;
 
-	if (fence_after(fence, gpu->next_fence)) {
-		DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
-				fence, gpu->next_fence);
-		return -EINVAL;
-	}
+	/*
+	 * Look up the fence and take a reference. We might still find a fence
+	 * whose refcount has already dropped to zero. dma_fence_get_rcu
+	 * pretends we didn't find a fence in that case.
+	 */
+	rcu_read_lock();
+	fence = idr_find(&gpu->fence_idr, id);
+	if (fence)
+		fence = dma_fence_get_rcu(fence);
+	rcu_read_unlock();
+
+	if (!fence)
+		return 0;
 
 	if (!timeout) {
 		/* No timeout was requested: just test for completion */
-		ret = fence_completed(gpu, fence) ? 0 : -EBUSY;
+		ret = dma_fence_is_signaled(fence) ? 0 : -EBUSY;
 	} else {
 		unsigned long remaining = etnaviv_timeout_to_jiffies(timeout);
 
-		ret = wait_event_interruptible_timeout(gpu->fence_event,
-						fence_completed(gpu, fence),
-						remaining);
-		if (ret == 0) {
-			DBG("timeout waiting for fence: %u (retired: %u completed: %u)",
-				fence, gpu->retired_fence,
-				gpu->completed_fence);
+		ret = dma_fence_wait_timeout(fence, true, remaining);
+		if (ret == 0)
 			ret = -ETIMEDOUT;
-		} else if (ret != -ERESTARTSYS) {
+		else if (ret != -ERESTARTSYS)
 			ret = 0;
-		}
+
 	}
 
+	dma_fence_put(fence);
 	return ret;
 }
 
 /*
  * Wait for an object to become inactive.  This, on it's own, is not race
- * free: the object is moved by the retire worker off the active list, and
+ * free: the object is moved by the scheduler off the active list, and
  * then the iova is put.  Moreover, the object could be re-submitted just
  * after we notice that it's become inactive.
  *
@@ -1343,16 +1215,19 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu,
 
 
 /* add bo's to gpu's ring, and kick gpu: */
-int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_submit *submit)
+struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit)
 {
+	struct etnaviv_gpu *gpu = submit->gpu;
+	struct dma_fence *gpu_fence;
 	unsigned int i, nr_events = 1, event[3];
 	int ret;
 
-	ret = pm_runtime_get_sync(gpu->dev);
-	if (ret < 0)
-		return ret;
-	submit->runtime_resumed = true;
+	if (!submit->runtime_resumed) {
+		ret = pm_runtime_get_sync(gpu->dev);
+		if (ret < 0)
+			return NULL;
+		submit->runtime_resumed = true;
+	}
 
 	/*
 	 * if there are performance monitor requests we need to have
@@ -1367,21 +1242,20 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 	ret = event_alloc(gpu, nr_events, event);
 	if (ret) {
 		DRM_ERROR("no free events\n");
-		return ret;
+		return NULL;
 	}
 
 	mutex_lock(&gpu->lock);
 
-	submit->out_fence = etnaviv_gpu_fence_alloc(gpu);
-	if (!submit->out_fence) {
+	gpu_fence = etnaviv_gpu_fence_alloc(gpu);
+	if (!gpu_fence) {
 		for (i = 0; i < nr_events; i++)
 			event_free(gpu, event[i]);
 
-		ret = -ENOMEM;
 		goto out_unlock;
 	}
 
-	gpu->active_fence = submit->out_fence->seqno;
+	gpu->active_fence = gpu_fence->seqno;
 
 	if (submit->nr_pmrs) {
 		gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre;
@@ -1390,8 +1264,8 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 		etnaviv_sync_point_queue(gpu, event[1]);
 	}
 
-	kref_get(&submit->refcount);
-	gpu->event[event[0]].fence = submit->out_fence;
+	gpu->event[event[0]].fence = gpu_fence;
+	submit->cmdbuf.user_size = submit->cmdbuf.size - 8;
 	etnaviv_buffer_queue(gpu, submit->exec_state, event[0],
 			     &submit->cmdbuf);
 
@@ -1402,15 +1276,10 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
 		etnaviv_sync_point_queue(gpu, event[2]);
 	}
 
-	list_add_tail(&submit->node, &gpu->active_submit_list);
-
-	hangcheck_timer_reset(gpu);
-	ret = 0;
-
 out_unlock:
 	mutex_unlock(&gpu->lock);
 
-	return ret;
+	return gpu_fence;
 }
 
 static void sync_point_worker(struct work_struct *work)
@@ -1484,7 +1353,6 @@ static irqreturn_t irq_handler(int irq, void *data)
 				continue;
 
 			gpu->event[event].fence = NULL;
-			dma_fence_signal(fence);
 
 			/*
 			 * Events can be processed out of order.  Eg,
@@ -1497,13 +1365,11 @@ static irqreturn_t irq_handler(int irq, void *data)
 			 */
 			if (fence_after(fence->seqno, gpu->completed_fence))
 				gpu->completed_fence = fence->seqno;
+			dma_fence_signal(fence);
 
 			event_free(gpu, event);
 		}
 
-		/* Retire the buffer objects in a work */
-		queue_work(gpu->wq, &gpu->retire_work);
-
 		ret = IRQ_HANDLED;
 	}
 
@@ -1675,41 +1541,49 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
 
 	gpu->wq = alloc_ordered_workqueue(dev_name(dev), 0);
 	if (!gpu->wq) {
-		if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
-			thermal_cooling_device_unregister(gpu->cooling);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out_thermal;
 	}
 
+	ret = etnaviv_sched_init(gpu);
+	if (ret)
+		goto out_workqueue;
+
 #ifdef CONFIG_PM
 	ret = pm_runtime_get_sync(gpu->dev);
 #else
 	ret = etnaviv_gpu_clk_enable(gpu);
 #endif
-	if (ret < 0) {
-		destroy_workqueue(gpu->wq);
-		if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
-			thermal_cooling_device_unregister(gpu->cooling);
-		return ret;
-	}
+	if (ret < 0)
+		goto out_sched;
+
 
 	gpu->drm = drm;
 	gpu->fence_context = dma_fence_context_alloc(1);
+	idr_init(&gpu->fence_idr);
 	spin_lock_init(&gpu->fence_spinlock);
 
-	INIT_LIST_HEAD(&gpu->active_submit_list);
-	INIT_WORK(&gpu->retire_work, retire_worker);
 	INIT_WORK(&gpu->sync_point_work, sync_point_worker);
-	INIT_WORK(&gpu->recover_work, recover_worker);
 	init_waitqueue_head(&gpu->fence_event);
 
-	timer_setup(&gpu->hangcheck_timer, hangcheck_handler, TIMER_DEFERRABLE);
-
 	priv->gpu[priv->num_gpus++] = gpu;
 
 	pm_runtime_mark_last_busy(gpu->dev);
 	pm_runtime_put_autosuspend(gpu->dev);
 
 	return 0;
+
+out_sched:
+	etnaviv_sched_fini(gpu);
+
+out_workqueue:
+	destroy_workqueue(gpu->wq);
+
+out_thermal:
+	if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
+		thermal_cooling_device_unregister(gpu->cooling);
+
+	return ret;
 }
 
 static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
@@ -1719,11 +1593,11 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
 
 	DBG("%s", dev_name(gpu->dev));
 
-	hangcheck_disable(gpu);
-
 	flush_workqueue(gpu->wq);
 	destroy_workqueue(gpu->wq);
 
+	etnaviv_sched_fini(gpu);
+
 #ifdef CONFIG_PM
 	pm_runtime_get_sync(gpu->dev);
 	pm_runtime_put_sync_suspend(gpu->dev);
@@ -1745,6 +1619,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
 	}
 
 	gpu->drm = NULL;
+	idr_destroy(&gpu->fence_idr);
 
 	if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
 		thermal_cooling_device_unregister(gpu->cooling);
@@ -1762,6 +1637,7 @@ static const struct of_device_id etnaviv_gpu_match[] = {
 	},
 	{ /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, etnaviv_gpu_match);
 
 static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
 {
@@ -1775,6 +1651,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
 
 	gpu->dev = &pdev->dev;
 	mutex_init(&gpu->lock);
+	mutex_init(&gpu->fence_idr_lock);
 
 	/* Map registers: */
 	gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev));
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 7623905210dc..186f7c7408b5 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -108,6 +108,7 @@ struct etnaviv_gpu {
 	struct etnaviv_chip_identity identity;
 	struct etnaviv_file_private *lastctx;
 	struct workqueue_struct *wq;
+	struct drm_gpu_scheduler sched;
 
 	/* 'ring'-buffer: */
 	struct etnaviv_cmdbuf buffer;
@@ -122,23 +123,18 @@ struct etnaviv_gpu {
 	struct completion event_free;
 	spinlock_t event_spinlock;
 
-	/* list of currently in-flight command buffers */
-	struct list_head active_submit_list;
-
 	u32 idle_mask;
 
 	/* Fencing support */
+	struct mutex fence_idr_lock;
+	struct idr fence_idr;
 	u32 next_fence;
 	u32 active_fence;
 	u32 completed_fence;
-	u32 retired_fence;
 	wait_queue_head_t fence_event;
 	u64 fence_context;
 	spinlock_t fence_spinlock;
 
-	/* worker for handling active-list retiring: */
-	struct work_struct retire_work;
-
 	/* worker for handling 'sync' points: */
 	struct work_struct sync_point_work;
 	int sync_point_event;
@@ -154,13 +150,6 @@ struct etnaviv_gpu {
 	struct clk *clk_core;
 	struct clk *clk_shader;
 
-	/* Hang Detction: */
-#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */
-#define DRM_ETNAVIV_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD)
-	struct timer_list hangcheck_timer;
-	u32 hangcheck_fence;
-	u32 hangcheck_dma_addr;
-	struct work_struct recover_work;
 	unsigned int freq_scale;
 	unsigned long base_rate_core;
 	unsigned long base_rate_shader;
@@ -181,11 +170,6 @@ static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence)
 	return fence_after_eq(gpu->completed_fence, fence);
 }
 
-static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence)
-{
-	return fence_after_eq(gpu->retired_fence, fence);
-}
-
 int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value);
 
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
@@ -194,16 +178,13 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m);
 #endif
 
-int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
-	unsigned int context, bool exclusive, bool implicit);
-
+void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
 	u32 fence, struct timespec *timeout);
 int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
 	struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
-int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
-	struct etnaviv_gem_submit *submit);
+struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit);
 int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
 void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
 int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
index 7a8c94731748..4b9b11ca6f03 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
@@ -158,7 +158,7 @@ void etnaviv_iommuv1_restore(struct etnaviv_gpu *gpu)
 	gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable);
 }
 
-const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = {
+static const struct etnaviv_iommu_domain_ops etnaviv_iommuv1_ops = {
 	.free = etnaviv_iommuv1_domain_free,
 	.map = etnaviv_iommuv1_map,
 	.unmap = etnaviv_iommuv1_unmap,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
index 1e956e266aa3..6e7c89247dc6 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
@@ -236,7 +236,7 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu)
 	gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE);
 }
 
-const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = {
+static const struct etnaviv_iommu_domain_ops etnaviv_iommuv2_ops = {
 	.free = etnaviv_iommuv2_domain_free,
 	.map = etnaviv_iommuv2_map,
 	.unmap = etnaviv_iommuv2_unmap,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index d113fe06e6b5..49e049713a52 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -29,7 +29,7 @@ static void etnaviv_domain_unmap(struct etnaviv_iommu_domain *domain,
 	size_t pgsize = SZ_4K;
 
 	if (!IS_ALIGNED(iova | size, pgsize)) {
-		pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
+		pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%zx\n",
 		       iova, size, pgsize);
 		return;
 	}
@@ -54,7 +54,7 @@ static int etnaviv_domain_map(struct etnaviv_iommu_domain *domain,
 	int ret = 0;
 
 	if (!IS_ALIGNED(iova | paddr | size, pgsize)) {
-		pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n",
+		pr_err("unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%zx\n",
 		       iova, &paddr, size, pgsize);
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
new file mode 100644
index 000000000000..3e334735ac17
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 Etnaviv Project
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kthread.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_dump.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_sched.h"
+
+static int etnaviv_job_hang_limit = 0;
+module_param_named(job_hang_limit, etnaviv_job_hang_limit, int , 0444);
+static int etnaviv_hw_jobs_limit = 2;
+module_param_named(hw_job_limit, etnaviv_hw_jobs_limit, int , 0444);
+
+struct dma_fence *etnaviv_sched_dependency(struct drm_sched_job *sched_job,
+					   struct drm_sched_entity *entity)
+{
+	struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
+	struct dma_fence *fence;
+	int i;
+
+	if (unlikely(submit->in_fence)) {
+		fence = submit->in_fence;
+		submit->in_fence = NULL;
+
+		if (!dma_fence_is_signaled(fence))
+			return fence;
+
+		dma_fence_put(fence);
+	}
+
+	for (i = 0; i < submit->nr_bos; i++) {
+		struct etnaviv_gem_submit_bo *bo = &submit->bos[i];
+		int j;
+
+		if (bo->excl) {
+			fence = bo->excl;
+			bo->excl = NULL;
+
+			if (!dma_fence_is_signaled(fence))
+				return fence;
+
+			dma_fence_put(fence);
+		}
+
+		for (j = 0; j < bo->nr_shared; j++) {
+			if (!bo->shared[j])
+				continue;
+
+			fence = bo->shared[j];
+			bo->shared[j] = NULL;
+
+			if (!dma_fence_is_signaled(fence))
+				return fence;
+
+			dma_fence_put(fence);
+		}
+		kfree(bo->shared);
+		bo->nr_shared = 0;
+		bo->shared = NULL;
+	}
+
+	return NULL;
+}
+
+struct dma_fence *etnaviv_sched_run_job(struct drm_sched_job *sched_job)
+{
+	struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
+	struct dma_fence *fence = NULL;
+
+	if (likely(!sched_job->s_fence->finished.error))
+		fence = etnaviv_gpu_submit(submit);
+	else
+		dev_dbg(submit->gpu->dev, "skipping bad job\n");
+
+	return fence;
+}
+
+static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
+{
+	struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
+	struct etnaviv_gpu *gpu = submit->gpu;
+
+	/* block scheduler */
+	kthread_park(gpu->sched.thread);
+	drm_sched_hw_job_reset(&gpu->sched, sched_job);
+
+	/* get the GPU back into the init state */
+	etnaviv_core_dump(gpu);
+	etnaviv_gpu_recover_hang(gpu);
+
+	/* restart scheduler after GPU is usable again */
+	drm_sched_job_recovery(&gpu->sched);
+	kthread_unpark(gpu->sched.thread);
+}
+
+static void etnaviv_sched_free_job(struct drm_sched_job *sched_job)
+{
+	struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
+
+	etnaviv_submit_put(submit);
+}
+
+static const struct drm_sched_backend_ops etnaviv_sched_ops = {
+	.dependency = etnaviv_sched_dependency,
+	.run_job = etnaviv_sched_run_job,
+	.timedout_job = etnaviv_sched_timedout_job,
+	.free_job = etnaviv_sched_free_job,
+};
+
+int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity,
+			   struct etnaviv_gem_submit *submit)
+{
+	int ret;
+
+	ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched,
+				 sched_entity, submit->cmdbuf.ctx);
+	if (ret)
+		return ret;
+
+	submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished);
+	mutex_lock(&submit->gpu->fence_idr_lock);
+	submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr,
+						submit->out_fence, 0,
+						INT_MAX, GFP_KERNEL);
+	mutex_unlock(&submit->gpu->fence_idr_lock);
+	if (submit->out_fence_id < 0)
+		return -ENOMEM;
+
+	/* the scheduler holds on to the job now */
+	kref_get(&submit->refcount);
+
+	drm_sched_entity_push_job(&submit->sched_job, sched_entity);
+
+	return 0;
+}
+
+int etnaviv_sched_init(struct etnaviv_gpu *gpu)
+{
+	int ret;
+
+	ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops,
+			     etnaviv_hw_jobs_limit, etnaviv_job_hang_limit,
+			     msecs_to_jiffies(500), dev_name(gpu->dev));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void etnaviv_sched_fini(struct etnaviv_gpu *gpu)
+{
+	drm_sched_fini(&gpu->sched);
+}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.h b/drivers/gpu/drm/etnaviv/etnaviv_sched.h
new file mode 100644
index 000000000000..097635fa78ae
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Etnaviv Project
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ETNAVIV_SCHED_H__
+#define __ETNAVIV_SCHED_H__
+
+#include <drm/gpu_scheduler.h>
+
+struct etnaviv_gpu;
+
+static inline
+struct etnaviv_gem_submit *to_etnaviv_submit(struct drm_sched_job *sched_job)
+{
+	return container_of(sched_job, struct etnaviv_gem_submit, sched_job);
+}
+
+int etnaviv_sched_init(struct etnaviv_gpu *gpu);
+void etnaviv_sched_fini(struct etnaviv_gpu *gpu);
+int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity,
+			   struct etnaviv_gem_submit *submit);
+
+#endif /* __ETNAVIV_SCHED_H__ */
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index dc5d79465f9b..257299ec95c4 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -179,18 +179,6 @@ static const u8 filter_cr_horiz_tap4[] = {
 	70,	59,	48,	37,	27,	19,	11,	5,
 };
 
-static inline bool is_alpha_format(unsigned int pixel_format)
-{
-	switch (pixel_format) {
-	case DRM_FORMAT_ARGB8888:
-	case DRM_FORMAT_ARGB1555:
-	case DRM_FORMAT_ARGB4444:
-		return true;
-	default:
-		return false;
-	}
-}
-
 static inline u32 vp_reg_read(struct mixer_context *ctx, u32 reg_id)
 {
 	return readl(ctx->vp_regs + reg_id);
@@ -625,7 +613,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
 	mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
 
 	mixer_cfg_layer(ctx, win, priority, true);
-	mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format));
+	mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha);
 
 	/* layer update mandatory for mixer 16.0.33.0 */
 	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
index ecaa58757529..c52d7a3af786 100644
--- a/drivers/gpu/drm/i2c/sil164_drv.c
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
@@ -326,8 +326,7 @@ sil164_encoder_destroy(struct drm_encoder *encoder)
 {
 	struct sil164_priv *priv = to_sil164_priv(encoder);
 
-	if (priv->duallink_slave)
-		i2c_unregister_device(priv->duallink_slave);
+	i2c_unregister_device(priv->duallink_slave);
 
 	kfree(priv);
 	drm_i2c_encoder_destroy(encoder);
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index cd3f0873bbdd..9e67a7b4e3a4 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1600,8 +1600,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
 	/* if encoder_init fails, the encoder slave is never registered,
 	 * so cleanup here:
 	 */
-	if (priv->cec)
-		i2c_unregister_device(priv->cec);
+	i2c_unregister_device(priv->cec);
 	return -ENXIO;
 }
 
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 091aef281963..f55cc028b2eb 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -17,6 +17,7 @@ subdir-ccflags-y += $(call cc-disable-warning, unused-parameter)
 subdir-ccflags-y += $(call cc-disable-warning, type-limits)
 subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers)
 subdir-ccflags-y += $(call cc-disable-warning, implicit-fallthrough)
+subdir-ccflags-y += $(call cc-disable-warning, unused-but-set-variable)
 subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror
 
 # Fine grained warnings disable
@@ -83,6 +84,7 @@ i915-y += i915_cmd_parser.o \
 i915-y += intel_uc.o \
 	  intel_uc_fw.o \
 	  intel_guc.o \
+	  intel_guc_ads.o \
 	  intel_guc_ct.o \
 	  intel_guc_fw.o \
 	  intel_guc_log.o \
@@ -108,6 +110,7 @@ i915-y += intel_audio.o \
 	  intel_fbc.o \
 	  intel_fifo_underrun.o \
 	  intel_frontbuffer.o \
+	  intel_hdcp.o \
 	  intel_hotplug.o \
 	  intel_modes.o \
 	  intel_overlay.o \
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index 4950b82f5b49..c73aff163908 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -59,28 +59,28 @@
  * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
  */
 # define VR01_LCD_ENABLE		(1 << 2)
-/** Enables the DVO repeater. */
+/* Enables the DVO repeater. */
 # define VR01_DVO_BYPASS_ENABLE		(1 << 1)
-/** Enables the DVO clock */
+/* Enables the DVO clock */
 # define VR01_DVO_ENABLE		(1 << 0)
-/** Enable dithering for 18bpp panels. Not documented. */
+/* Enable dithering for 18bpp panels. Not documented. */
 # define VR01_DITHER_ENABLE             (1 << 4)
 
 /*
  * LCD Interface Format
  */
 #define VR10		0x10
-/** Enables LVDS output instead of CMOS */
+/* Enables LVDS output instead of CMOS */
 # define VR10_LVDS_ENABLE		(1 << 4)
-/** Enables 18-bit LVDS output. */
+/* Enables 18-bit LVDS output. */
 # define VR10_INTERFACE_1X18		(0 << 2)
-/** Enables 24-bit LVDS or CMOS output */
+/* Enables 24-bit LVDS or CMOS output */
 # define VR10_INTERFACE_1X24		(1 << 2)
-/** Enables 2x18-bit LVDS or CMOS output. */
+/* Enables 2x18-bit LVDS or CMOS output. */
 # define VR10_INTERFACE_2X18		(2 << 2)
-/** Enables 2x24-bit LVDS output */
+/* Enables 2x24-bit LVDS output */
 # define VR10_INTERFACE_2X24		(3 << 2)
-/** Mask that defines the depth of the pipeline */
+/* Mask that defines the depth of the pipeline */
 # define VR10_INTERFACE_DEPTH_MASK      (3 << 2)
 
 /*
@@ -97,7 +97,7 @@
  * Panel power down status
  */
 #define VR30		0x30
-/** Read only bit indicating that the panel is not in a safe poweroff state. */
+/* Read only bit indicating that the panel is not in a safe poweroff state. */
 # define VR30_PANEL_ON			(1 << 15)
 
 #define VR40		0x40
@@ -183,7 +183,7 @@ struct ivch_priv {
 
 
 static void ivch_dump_regs(struct intel_dvo_device *dvo);
-/**
+/*
  * Reads a register on the ivch.
  *
  * Each of the 256 registers are 16 bits long.
@@ -230,7 +230,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 	return false;
 }
 
-/** Writes a 16-bit register on the ivch */
+/* Writes a 16-bit register on the ivch */
 static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 {
 	struct ivch_priv *priv = dvo->dev_priv;
@@ -258,7 +258,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 	return false;
 }
 
-/** Probes the given bus and slave address for an ivch */
+/* Probes the given bus and slave address for an ivch */
 static bool ivch_init(struct intel_dvo_device *dvo,
 		      struct i2c_adapter *adapter)
 {
@@ -338,7 +338,7 @@ static void ivch_reset(struct intel_dvo_device *dvo)
 		ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
 }
 
-/** Sets the power state of the panel connected to the ivch */
+/* Sets the power state of the panel connected to the ivch */
 static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
 {
 	int i;
diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c
index 2fb7b34ef561..9a471b0afb15 100644
--- a/drivers/gpu/drm/i915/gvt/dmabuf.c
+++ b/drivers/gpu/drm/i915/gvt/dmabuf.c
@@ -162,8 +162,8 @@ static struct drm_i915_gem_object *vgpu_create_gem(struct drm_device *dev,
 		info->size << PAGE_SHIFT);
 	i915_gem_object_init(obj, &intel_vgpu_gem_ops);
 
-	obj->base.read_domains = I915_GEM_DOMAIN_GTT;
-	obj->base.write_domain = 0;
+	obj->read_domains = I915_GEM_DOMAIN_GTT;
+	obj->write_domain = 0;
 	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
 		unsigned int tiling_mode = 0;
 		unsigned int stride = 0;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index e968aeae1d84..0cbe154e517d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -49,6 +49,7 @@ static int i915_capabilities(struct seq_file *m, void *data)
 
 	intel_device_info_dump_flags(info, &p);
 	intel_device_info_dump_runtime(info, &p);
+	intel_driver_caps_print(&dev_priv->caps, &p);
 
 	kernel_param_lock(THIS_MODULE);
 	i915_params_dump(&i915_modparams, &p);
@@ -149,8 +150,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
 		   get_global_flag(obj),
 		   get_pin_mapped_flag(obj),
 		   obj->base.size / 1024,
-		   obj->base.read_domains,
-		   obj->base.write_domain,
+		   obj->read_domains,
+		   obj->write_domain,
 		   i915_cache_level_str(dev_priv, obj->cache_level),
 		   obj->mm.dirty ? " dirty" : "",
 		   obj->mm.madv == I915_MADV_DONTNEED ? " purgeable" : "");
@@ -988,7 +989,10 @@ i915_next_seqno_set(void *data, u64 val)
 	if (ret)
 		return ret;
 
+	intel_runtime_pm_get(dev_priv);
 	ret = i915_gem_set_global_seqno(dev, val);
+	intel_runtime_pm_put(dev_priv);
+
 	mutex_unlock(&dev->struct_mutex);
 
 	return ret;
@@ -1457,19 +1461,6 @@ static int gen6_drpc_info(struct seq_file *m)
 	struct drm_i915_private *dev_priv = node_to_i915(m->private);
 	u32 gt_core_status, rcctl1, rc6vids = 0;
 	u32 gen9_powergate_enable = 0, gen9_powergate_status = 0;
-	unsigned forcewake_count;
-	int count = 0;
-
-	forcewake_count = READ_ONCE(dev_priv->uncore.fw_domain[FW_DOMAIN_ID_RENDER].wake_count);
-	if (forcewake_count) {
-		seq_puts(m, "RC information inaccurate because somebody "
-			    "holds a forcewake reference \n");
-	} else {
-		/* NB: we cannot use forcewake, else we read the wrong values */
-		while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
-			udelay(10);
-		seq_printf(m, "RC information accurate: %s\n", yesno(count < 51));
-	}
 
 	gt_core_status = I915_READ_FW(GEN6_GT_CORE_STATUS);
 	trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4, true);
@@ -1480,9 +1471,12 @@ static int gen6_drpc_info(struct seq_file *m)
 		gen9_powergate_status = I915_READ(GEN9_PWRGT_DOMAIN_STATUS);
 	}
 
-	mutex_lock(&dev_priv->pcu_lock);
-	sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
-	mutex_unlock(&dev_priv->pcu_lock);
+	if (INTEL_GEN(dev_priv) <= 7) {
+		mutex_lock(&dev_priv->pcu_lock);
+		sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS,
+				       &rc6vids);
+		mutex_unlock(&dev_priv->pcu_lock);
+	}
 
 	seq_printf(m, "RC1e Enabled: %s\n",
 		   yesno(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE));
@@ -1538,12 +1532,15 @@ static int gen6_drpc_info(struct seq_file *m)
 	print_rc6_res(m, "RC6+ residency since boot:", GEN6_GT_GFX_RC6p);
 	print_rc6_res(m, "RC6++ residency since boot:", GEN6_GT_GFX_RC6pp);
 
-	seq_printf(m, "RC6   voltage: %dmV\n",
-		   GEN6_DECODE_RC6_VID(((rc6vids >> 0) & 0xff)));
-	seq_printf(m, "RC6+  voltage: %dmV\n",
-		   GEN6_DECODE_RC6_VID(((rc6vids >> 8) & 0xff)));
-	seq_printf(m, "RC6++ voltage: %dmV\n",
-		   GEN6_DECODE_RC6_VID(((rc6vids >> 16) & 0xff)));
+	if (INTEL_GEN(dev_priv) <= 7) {
+		seq_printf(m, "RC6   voltage: %dmV\n",
+			   GEN6_DECODE_RC6_VID(((rc6vids >> 0) & 0xff)));
+		seq_printf(m, "RC6+  voltage: %dmV\n",
+			   GEN6_DECODE_RC6_VID(((rc6vids >> 8) & 0xff)));
+		seq_printf(m, "RC6++ voltage: %dmV\n",
+			   GEN6_DECODE_RC6_VID(((rc6vids >> 16) & 0xff)));
+	}
+
 	return i915_forcewake_domains(m, NULL);
 }
 
@@ -1596,7 +1593,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
 		seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason);
 
 	if (fbc->work.scheduled)
-		seq_printf(m, "FBC worker scheduled on vblank %u, now %llu\n",
+		seq_printf(m, "FBC worker scheduled on vblank %llu, now %llu\n",
 			   fbc->work.scheduled_vblank,
 			   drm_crtc_vblank_count(&fbc->crtc->base));
 
@@ -2335,7 +2332,6 @@ static int i915_guc_info(struct seq_file *m, void *data)
 		return -ENODEV;
 
 	GEM_BUG_ON(!guc->execbuf_client);
-	GEM_BUG_ON(!guc->preempt_client);
 
 	seq_printf(m, "Doorbell map:\n");
 	seq_printf(m, "\t%*pb\n", GUC_NUM_DOORBELLS, guc->doorbell_bitmap);
@@ -2343,8 +2339,11 @@ static int i915_guc_info(struct seq_file *m, void *data)
 
 	seq_printf(m, "\nGuC execbuf client @ %p:\n", guc->execbuf_client);
 	i915_guc_client_info(m, dev_priv, guc->execbuf_client);
-	seq_printf(m, "\nGuC preempt client @ %p:\n", guc->preempt_client);
-	i915_guc_client_info(m, dev_priv, guc->preempt_client);
+	if (guc->preempt_client) {
+		seq_printf(m, "\nGuC preempt client @ %p:\n",
+			   guc->preempt_client);
+		i915_guc_client_info(m, dev_priv, guc->preempt_client);
+	}
 
 	i915_guc_log_info(m, dev_priv);
 
@@ -2464,24 +2463,11 @@ static int i915_guc_log_control_get(void *data, u64 *val)
 static int i915_guc_log_control_set(void *data, u64 val)
 {
 	struct drm_i915_private *dev_priv = data;
-	int ret;
 
 	if (!HAS_GUC(dev_priv))
 		return -ENODEV;
 
-	if (!dev_priv->guc.log.vma)
-		return -EINVAL;
-
-	ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
-	if (ret)
-		return ret;
-
-	intel_runtime_pm_get(dev_priv);
-	ret = i915_guc_log_control(dev_priv, val);
-	intel_runtime_pm_put(dev_priv);
-
-	mutex_unlock(&dev_priv->drm.struct_mutex);
-	return ret;
+	return intel_guc_log_control(&dev_priv->guc, val);
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
@@ -2518,15 +2504,19 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 	u32 stat[3];
 	enum pipe pipe;
 	bool enabled = false;
+	bool sink_support;
 
 	if (!HAS_PSR(dev_priv))
 		return -ENODEV;
 
+	sink_support = dev_priv->psr.sink_support;
+	seq_printf(m, "Sink_Support: %s\n", yesno(sink_support));
+	if (!sink_support)
+		return 0;
+
 	intel_runtime_pm_get(dev_priv);
 
 	mutex_lock(&dev_priv->psr.lock);
-	seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
-	seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 	seq_printf(m, "Enabled: %s\n", yesno((bool)dev_priv->psr.enabled));
 	seq_printf(m, "Active: %s\n", yesno(dev_priv->psr.active));
 	seq_printf(m, "Busy frontbuffer bits: 0x%03x\n",
@@ -2584,9 +2574,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 		seq_printf(m, "Performance_Counter: %u\n", psrperf);
 	}
 	if (dev_priv->psr.psr2_support) {
-		u32 psr2 = I915_READ(EDP_PSR2_STATUS_CTL);
+		u32 psr2 = I915_READ(EDP_PSR2_STATUS);
 
-		seq_printf(m, "EDP_PSR2_STATUS_CTL: %x [%s]\n",
+		seq_printf(m, "EDP_PSR2_STATUS: %x [%s]\n",
 			   psr2, psr2_live_status(psr2));
 	}
 	mutex_unlock(&dev_priv->psr.lock);
@@ -2710,7 +2700,8 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused)
 	if (!HAS_RUNTIME_PM(dev_priv))
 		seq_puts(m, "Runtime power management not supported\n");
 
-	seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->gt.awake));
+	seq_printf(m, "GPU idle: %s (epoch %u)\n",
+		   yesno(!dev_priv->gt.awake), dev_priv->gt.epoch);
 	seq_printf(m, "IRQs disabled: %s\n",
 		   yesno(!intel_irqs_enabled(dev_priv)));
 #ifdef CONFIG_PM
@@ -3143,8 +3134,8 @@ static int i915_engine_info(struct seq_file *m, void *unused)
 
 	intel_runtime_pm_get(dev_priv);
 
-	seq_printf(m, "GT awake? %s\n",
-		   yesno(dev_priv->gt.awake));
+	seq_printf(m, "GT awake? %s (epoch %u)\n",
+		   yesno(dev_priv->gt.awake), dev_priv->gt.epoch);
 	seq_printf(m, "Global active requests: %d\n",
 		   dev_priv->gt.active_requests);
 	seq_printf(m, "CS timestamp frequency: %u kHz\n",
@@ -3363,7 +3354,10 @@ static void drrs_status_per_crtc(struct seq_file *m,
 
 		/* disable_drrs() will make drrs->dp NULL */
 		if (!drrs->dp) {
-			seq_puts(m, "Idleness DRRS: Disabled");
+			seq_puts(m, "Idleness DRRS: Disabled\n");
+			if (dev_priv->psr.enabled)
+				seq_puts(m,
+				"\tAs PSR is enabled, DRRS is not enabled\n");
 			mutex_unlock(&drrs->mutex);
 			return;
 		}
@@ -4606,6 +4600,46 @@ static const struct file_operations i915_hpd_storm_ctl_fops = {
 	.write = i915_hpd_storm_ctl_write
 };
 
+static int i915_drrs_ctl_set(void *data, u64 val)
+{
+	struct drm_i915_private *dev_priv = data;
+	struct drm_device *dev = &dev_priv->drm;
+	struct intel_crtc *intel_crtc;
+	struct intel_encoder *encoder;
+	struct intel_dp *intel_dp;
+
+	if (INTEL_GEN(dev_priv) < 7)
+		return -ENODEV;
+
+	drm_modeset_lock_all(dev);
+	for_each_intel_crtc(dev, intel_crtc) {
+		if (!intel_crtc->base.state->active ||
+					!intel_crtc->config->has_drrs)
+			continue;
+
+		for_each_encoder_on_crtc(dev, &intel_crtc->base, encoder) {
+			if (encoder->type != INTEL_OUTPUT_EDP)
+				continue;
+
+			DRM_DEBUG_DRIVER("Manually %sabling DRRS. %llu\n",
+						val ? "en" : "dis", val);
+
+			intel_dp = enc_to_intel_dp(&encoder->base);
+			if (val)
+				intel_edp_drrs_enable(intel_dp,
+							intel_crtc->config);
+			else
+				intel_edp_drrs_disable(intel_dp,
+							intel_crtc->config);
+		}
+	}
+	drm_modeset_unlock_all(dev);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(i915_drrs_ctl_fops, NULL, i915_drrs_ctl_set, "%llu\n");
+
 static const struct drm_info_list i915_debugfs_list[] = {
 	{"i915_capabilities", i915_capabilities, 0},
 	{"i915_gem_objects", i915_gem_object_info, 0},
@@ -4683,7 +4717,8 @@ static const struct i915_debugfs_files {
 	{"i915_dp_test_active", &i915_displayport_test_active_fops},
 	{"i915_guc_log_control", &i915_guc_log_control_fops},
 	{"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
-	{"i915_ipc_status", &i915_ipc_status_fops}
+	{"i915_ipc_status", &i915_ipc_status_fops},
+	{"i915_drrs_ctl", &i915_drrs_ctl_fops}
 };
 
 int i915_debugfs_register(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 2f5209de0391..d0015d9c693d 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -55,6 +55,7 @@
 
 static struct drm_driver driver;
 
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
 static unsigned int i915_load_fail_count;
 
 bool __i915_inject_load_failure(const char *func, int line)
@@ -70,6 +71,7 @@ bool __i915_inject_load_failure(const char *func, int line)
 
 	return false;
 }
+#endif
 
 #define FDO_BUG_URL "https://bugs.freedesktop.org/enter_bug.cgi?product=DRI"
 #define FDO_BUG_MSG "Please file a bug at " FDO_BUG_URL " against DRM/Intel " \
@@ -107,8 +109,12 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
 
 static bool i915_error_injected(struct drm_i915_private *dev_priv)
 {
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
 	return i915_modparams.inject_load_failure &&
 	       i915_load_fail_count == i915_modparams.inject_load_failure;
+#else
+	return false;
+#endif
 }
 
 #define i915_load_error(dev_priv, fmt, ...)				     \
@@ -116,10 +122,90 @@ static bool i915_error_injected(struct drm_i915_private *dev_priv)
 		      i915_error_injected(dev_priv) ? KERN_DEBUG : KERN_ERR, \
 		      fmt, ##__VA_ARGS__)
 
+/* Map PCH device id to PCH type, or PCH_NONE if unknown. */
+static enum intel_pch
+intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id)
+{
+	switch (id) {
+	case INTEL_PCH_IBX_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
+		WARN_ON(!IS_GEN5(dev_priv));
+		return PCH_IBX;
+	case INTEL_PCH_CPT_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found CougarPoint PCH\n");
+		WARN_ON(!IS_GEN6(dev_priv) && !IS_IVYBRIDGE(dev_priv));
+		return PCH_CPT;
+	case INTEL_PCH_PPT_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found PantherPoint PCH\n");
+		WARN_ON(!IS_GEN6(dev_priv) && !IS_IVYBRIDGE(dev_priv));
+		/* PantherPoint is CPT compatible */
+		return PCH_CPT;
+	case INTEL_PCH_LPT_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found LynxPoint PCH\n");
+		WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
+		WARN_ON(IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv));
+		return PCH_LPT;
+	case INTEL_PCH_LPT_LP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
+		WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
+		WARN_ON(!IS_HSW_ULT(dev_priv) && !IS_BDW_ULT(dev_priv));
+		return PCH_LPT;
+	case INTEL_PCH_WPT_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found WildcatPoint PCH\n");
+		WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
+		WARN_ON(IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv));
+		/* WildcatPoint is LPT compatible */
+		return PCH_LPT;
+	case INTEL_PCH_WPT_LP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found WildcatPoint LP PCH\n");
+		WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
+		WARN_ON(!IS_HSW_ULT(dev_priv) && !IS_BDW_ULT(dev_priv));
+		/* WildcatPoint is LPT compatible */
+		return PCH_LPT;
+	case INTEL_PCH_SPT_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found SunrisePoint PCH\n");
+		WARN_ON(!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv));
+		return PCH_SPT;
+	case INTEL_PCH_SPT_LP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
+		WARN_ON(!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv));
+		return PCH_SPT;
+	case INTEL_PCH_KBP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found Kaby Lake PCH (KBP)\n");
+		WARN_ON(!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv) &&
+			!IS_COFFEELAKE(dev_priv));
+		return PCH_KBP;
+	case INTEL_PCH_CNP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found Cannon Lake PCH (CNP)\n");
+		WARN_ON(!IS_CANNONLAKE(dev_priv) && !IS_COFFEELAKE(dev_priv));
+		return PCH_CNP;
+	case INTEL_PCH_CNP_LP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found Cannon Lake LP PCH (CNP-LP)\n");
+		WARN_ON(!IS_CANNONLAKE(dev_priv) && !IS_COFFEELAKE(dev_priv));
+		return PCH_CNP;
+	case INTEL_PCH_ICP_DEVICE_ID_TYPE:
+		DRM_DEBUG_KMS("Found Ice Lake PCH\n");
+		WARN_ON(!IS_ICELAKE(dev_priv));
+		return PCH_ICP;
+	default:
+		return PCH_NONE;
+	}
+}
+
+static bool intel_is_virt_pch(unsigned short id,
+			      unsigned short svendor, unsigned short sdevice)
+{
+	return (id == INTEL_PCH_P2X_DEVICE_ID_TYPE ||
+		id == INTEL_PCH_P3X_DEVICE_ID_TYPE ||
+		(id == INTEL_PCH_QEMU_DEVICE_ID_TYPE &&
+		 svendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET &&
+		 sdevice == PCI_SUBDEVICE_ID_QEMU));
+}
 
-static enum intel_pch intel_virt_detect_pch(struct drm_i915_private *dev_priv)
+static unsigned short
+intel_virt_detect_pch(const struct drm_i915_private *dev_priv)
 {
-	enum intel_pch ret = PCH_NOP;
+	unsigned short id = 0;
 
 	/*
 	 * In a virtualized passthrough environment we can be in a
@@ -128,28 +214,25 @@ static enum intel_pch intel_virt_detect_pch(struct drm_i915_private *dev_priv)
 	 * make an educated guess as to which PCH is really there.
 	 */
 
-	if (IS_GEN5(dev_priv)) {
-		ret = PCH_IBX;
-		DRM_DEBUG_KMS("Assuming Ibex Peak PCH\n");
-	} else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) {
-		ret = PCH_CPT;
-		DRM_DEBUG_KMS("Assuming CougarPoint PCH\n");
-	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
-		ret = PCH_LPT;
-		if (IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv))
-			dev_priv->pch_id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE;
-		else
-			dev_priv->pch_id = INTEL_PCH_LPT_DEVICE_ID_TYPE;
-		DRM_DEBUG_KMS("Assuming LynxPoint PCH\n");
-	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
-		ret = PCH_SPT;
-		DRM_DEBUG_KMS("Assuming SunrisePoint PCH\n");
-	} else if (IS_COFFEELAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) {
-		ret = PCH_CNP;
-		DRM_DEBUG_KMS("Assuming CannonPoint PCH\n");
-	}
+	if (IS_GEN5(dev_priv))
+		id = INTEL_PCH_IBX_DEVICE_ID_TYPE;
+	else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv))
+		id = INTEL_PCH_CPT_DEVICE_ID_TYPE;
+	else if (IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv))
+		id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE;
+	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+		id = INTEL_PCH_LPT_DEVICE_ID_TYPE;
+	else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+		id = INTEL_PCH_SPT_DEVICE_ID_TYPE;
+	else if (IS_COFFEELAKE(dev_priv) || IS_CANNONLAKE(dev_priv))
+		id = INTEL_PCH_CNP_DEVICE_ID_TYPE;
+
+	if (id)
+		DRM_DEBUG_KMS("Assuming PCH ID %04x\n", id);
+	else
+		DRM_DEBUG_KMS("Assuming no PCH\n");
 
-	return ret;
+	return id;
 }
 
 static void intel_detect_pch(struct drm_i915_private *dev_priv)
@@ -176,94 +259,31 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv)
 	 * of only checking the first one.
 	 */
 	while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
-		if (pch->vendor == PCI_VENDOR_ID_INTEL) {
-			unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+		unsigned short id;
+		enum intel_pch pch_type;
 
-			dev_priv->pch_id = id;
+		if (pch->vendor != PCI_VENDOR_ID_INTEL)
+			continue;
 
-			if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_IBX;
-				DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
-				WARN_ON(!IS_GEN5(dev_priv));
-			} else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_CPT;
-				DRM_DEBUG_KMS("Found CougarPoint PCH\n");
-				WARN_ON(!IS_GEN6(dev_priv) &&
-					!IS_IVYBRIDGE(dev_priv));
-			} else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
-				/* PantherPoint is CPT compatible */
-				dev_priv->pch_type = PCH_CPT;
-				DRM_DEBUG_KMS("Found PantherPoint PCH\n");
-				WARN_ON(!IS_GEN6(dev_priv) &&
-					!IS_IVYBRIDGE(dev_priv));
-			} else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_LPT;
-				DRM_DEBUG_KMS("Found LynxPoint PCH\n");
-				WARN_ON(!IS_HASWELL(dev_priv) &&
-					!IS_BROADWELL(dev_priv));
-				WARN_ON(IS_HSW_ULT(dev_priv) ||
-					IS_BDW_ULT(dev_priv));
-			} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_LPT;
-				DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
-				WARN_ON(!IS_HASWELL(dev_priv) &&
-					!IS_BROADWELL(dev_priv));
-				WARN_ON(!IS_HSW_ULT(dev_priv) &&
-					!IS_BDW_ULT(dev_priv));
-			} else if (id == INTEL_PCH_WPT_DEVICE_ID_TYPE) {
-				/* WildcatPoint is LPT compatible */
-				dev_priv->pch_type = PCH_LPT;
-				DRM_DEBUG_KMS("Found WildcatPoint PCH\n");
-				WARN_ON(!IS_HASWELL(dev_priv) &&
-					!IS_BROADWELL(dev_priv));
-				WARN_ON(IS_HSW_ULT(dev_priv) ||
-					IS_BDW_ULT(dev_priv));
-			} else if (id == INTEL_PCH_WPT_LP_DEVICE_ID_TYPE) {
-				/* WildcatPoint is LPT compatible */
-				dev_priv->pch_type = PCH_LPT;
-				DRM_DEBUG_KMS("Found WildcatPoint LP PCH\n");
-				WARN_ON(!IS_HASWELL(dev_priv) &&
-					!IS_BROADWELL(dev_priv));
-				WARN_ON(!IS_HSW_ULT(dev_priv) &&
-					!IS_BDW_ULT(dev_priv));
-			} else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_SPT;
-				DRM_DEBUG_KMS("Found SunrisePoint PCH\n");
-				WARN_ON(!IS_SKYLAKE(dev_priv) &&
-					!IS_KABYLAKE(dev_priv));
-			} else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_SPT;
-				DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
-				WARN_ON(!IS_SKYLAKE(dev_priv) &&
-					!IS_KABYLAKE(dev_priv));
-			} else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_KBP;
-				DRM_DEBUG_KMS("Found Kaby Lake PCH (KBP)\n");
-				WARN_ON(!IS_SKYLAKE(dev_priv) &&
-					!IS_KABYLAKE(dev_priv) &&
-					!IS_COFFEELAKE(dev_priv));
-			} else if (id == INTEL_PCH_CNP_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_CNP;
-				DRM_DEBUG_KMS("Found Cannon Lake PCH (CNP)\n");
-				WARN_ON(!IS_CANNONLAKE(dev_priv) &&
-					!IS_COFFEELAKE(dev_priv));
-			} else if (id == INTEL_PCH_CNP_LP_DEVICE_ID_TYPE) {
-				dev_priv->pch_type = PCH_CNP;
-				DRM_DEBUG_KMS("Found Cannon Lake LP PCH (CNP-LP)\n");
-				WARN_ON(!IS_CANNONLAKE(dev_priv) &&
-					!IS_COFFEELAKE(dev_priv));
-			} else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE ||
-				   id == INTEL_PCH_P3X_DEVICE_ID_TYPE ||
-				   (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE &&
-				    pch->subsystem_vendor ==
-					    PCI_SUBVENDOR_ID_REDHAT_QUMRANET &&
-				    pch->subsystem_device ==
-					    PCI_SUBDEVICE_ID_QEMU)) {
-				dev_priv->pch_type =
-					intel_virt_detect_pch(dev_priv);
-			} else
-				continue;
+		id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
 
+		pch_type = intel_pch_type(dev_priv, id);
+		if (pch_type != PCH_NONE) {
+			dev_priv->pch_type = pch_type;
+			dev_priv->pch_id = id;
+			break;
+		} else if (intel_is_virt_pch(id, pch->subsystem_vendor,
+					 pch->subsystem_device)) {
+			id = intel_virt_detect_pch(dev_priv);
+			if (id) {
+				pch_type = intel_pch_type(dev_priv, id);
+				if (WARN_ON(pch_type == PCH_NONE))
+					pch_type = PCH_NOP;
+			} else {
+				pch_type = PCH_NOP;
+			}
+			dev_priv->pch_type = pch_type;
+			dev_priv->pch_id = id;
 			break;
 		}
 	}
@@ -273,8 +293,8 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv)
 	pci_dev_put(pch);
 }
 
-static int i915_getparam(struct drm_device *dev, void *data,
-			 struct drm_file *file_priv)
+static int i915_getparam_ioctl(struct drm_device *dev, void *data,
+			       struct drm_file *file_priv)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct pci_dev *pdev = dev_priv->drm.pdev;
@@ -368,13 +388,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
 		value = i915_gem_mmap_gtt_version();
 		break;
 	case I915_PARAM_HAS_SCHEDULER:
-		value = 0;
-		if (dev_priv->engine[RCS] && dev_priv->engine[RCS]->schedule) {
-			value |= I915_SCHEDULER_CAP_ENABLED;
-			value |= I915_SCHEDULER_CAP_PRIORITY;
-			if (HAS_LOGICAL_RING_PREEMPTION(dev_priv))
-				value |= I915_SCHEDULER_CAP_PREEMPTION;
-		}
+		value = dev_priv->caps.scheduler;
 		break;
 
 	case I915_PARAM_MMAP_VERSION:
@@ -434,7 +448,10 @@ static int i915_getparam(struct drm_device *dev, void *data,
 
 static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
 {
-	dev_priv->bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
+	int domain = pci_domain_nr(dev_priv->drm.pdev->bus);
+
+	dev_priv->bridge_dev =
+		pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0));
 	if (!dev_priv->bridge_dev) {
 		DRM_ERROR("bridge device not found\n");
 		return -1;
@@ -622,7 +639,7 @@ static void i915_gem_fini(struct drm_i915_private *dev_priv)
 	i915_gem_contexts_fini(dev_priv);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
 
-	intel_uc_fini_wq(dev_priv);
+	intel_uc_fini_misc(dev_priv);
 	i915_gem_cleanup_userptr(dev_priv);
 
 	i915_gem_drain_freed_objects(dev_priv);
@@ -866,6 +883,7 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv)
 /**
  * i915_driver_init_early - setup state not requiring device access
  * @dev_priv: device private
+ * @ent: the matching pci_device_id
  *
  * Initialize everything that is a "SW-only" state, that is state not
  * requiring accessing the device or exposing the driver via kernel internal
@@ -891,11 +909,7 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
 
 	BUILD_BUG_ON(INTEL_MAX_PLATFORMS >
 		     sizeof(device_info->platform_mask) * BITS_PER_BYTE);
-	device_info->platform_mask = BIT(device_info->platform);
-
 	BUG_ON(device_info->gen > sizeof(device_info->gen_mask) * BITS_PER_BYTE);
-	device_info->gen_mask = BIT(device_info->gen - 1);
-
 	spin_lock_init(&dev_priv->irq_lock);
 	spin_lock_init(&dev_priv->gpu_error.lock);
 	mutex_init(&dev_priv->backlight_lock);
@@ -1900,7 +1914,6 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
 	ret = i915_gem_reset_prepare(i915);
 	if (ret) {
 		dev_err(i915->drm.dev, "GPU recovery failed\n");
-		intel_gpu_reset(i915, ALL_ENGINES);
 		goto taint;
 	}
 
@@ -1932,7 +1945,8 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
 	 */
 	ret = i915_ggtt_enable_hw(i915);
 	if (ret) {
-		DRM_ERROR("Failed to re-enable GGTT following reset %d\n", ret);
+		DRM_ERROR("Failed to re-enable GGTT following reset (%d)\n",
+			  ret);
 		goto error;
 	}
 
@@ -1949,7 +1963,8 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
 	 */
 	ret = i915_gem_init_hw(i915);
 	if (ret) {
-		DRM_ERROR("Failed hw init on reset %d\n", ret);
+		DRM_ERROR("Failed to initialise HW following reset (%d)\n",
+			  ret);
 		goto error;
 	}
 
@@ -1981,6 +1996,7 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
 error:
 	i915_gem_set_wedged(i915);
 	i915_gem_retire_requests(i915);
+	intel_gpu_reset(i915, ALL_ENGINES);
 	goto finish;
 }
 
@@ -2584,6 +2600,11 @@ static int intel_runtime_suspend(struct device *kdev)
 
 		intel_runtime_pm_enable_interrupts(dev_priv);
 
+		intel_guc_resume(dev_priv);
+
+		i915_gem_init_swizzling(dev_priv);
+		i915_gem_restore_fences(dev_priv);
+
 		enable_rpm_wakeref_asserts(dev_priv);
 
 		return ret;
@@ -2649,8 +2670,6 @@ static int intel_runtime_resume(struct device *kdev)
 	if (intel_uncore_unclaimed_mmio(dev_priv))
 		DRM_DEBUG_DRIVER("Unclaimed access during suspend, bios?\n");
 
-	intel_guc_resume(dev_priv);
-
 	if (IS_GEN9_LP(dev_priv)) {
 		bxt_disable_dc9(dev_priv);
 		bxt_display_core_init(dev_priv, true);
@@ -2665,6 +2684,10 @@ static int intel_runtime_resume(struct device *kdev)
 
 	intel_uncore_runtime_resume(dev_priv);
 
+	intel_runtime_pm_enable_interrupts(dev_priv);
+
+	intel_guc_resume(dev_priv);
+
 	/*
 	 * No point of rolling back things in case of an error, as the best
 	 * we can do is to hope that things will still work (and disable RPM).
@@ -2672,8 +2695,6 @@ static int intel_runtime_resume(struct device *kdev)
 	i915_gem_init_swizzling(dev_priv);
 	i915_gem_restore_fences(dev_priv);
 
-	intel_runtime_pm_enable_interrupts(dev_priv);
-
 	/*
 	 * On VLV/CHV display interrupts are part of the display
 	 * power well, so hpd is reinitialized from there. For
@@ -2765,7 +2786,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_BATCHBUFFER, drm_noop, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, drm_noop, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, drm_noop, DRM_AUTH),
-	DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_SETPARAM, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH),
@@ -2777,8 +2798,8 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-	DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
-	DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2_WR, i915_gem_execbuffer2, DRM_AUTH|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer_ioctl, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2_WR, i915_gem_execbuffer2_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
@@ -2797,11 +2818,11 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW),
-	DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
+	DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
-	DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW),
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d307429a5ae0..6b215c411338 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -83,8 +83,8 @@
 
 #define DRIVER_NAME		"i915"
 #define DRIVER_DESC		"Intel Graphics"
-#define DRIVER_DATE		"20171222"
-#define DRIVER_TIMESTAMP	1513971710
+#define DRIVER_DATE		"20180214"
+#define DRIVER_TIMESTAMP	1518601107
 
 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
  * WARN_ON()) for hw state sanity checks to check for unexpected conditions
@@ -104,9 +104,13 @@
 #define I915_STATE_WARN_ON(x)						\
 	I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")")
 
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
 bool __i915_inject_load_failure(const char *func, int line);
 #define i915_inject_load_failure() \
 	__i915_inject_load_failure(__func__, __LINE__)
+#else
+#define i915_inject_load_failure() false
+#endif
 
 typedef struct {
 	uint32_t val;
@@ -453,9 +457,9 @@ struct intel_display_error_state;
 
 struct i915_gpu_state {
 	struct kref ref;
-	struct timeval time;
-	struct timeval boottime;
-	struct timeval uptime;
+	ktime_t time;
+	ktime_t boottime;
+	ktime_t uptime;
 
 	struct drm_i915_private *i915;
 
@@ -468,6 +472,7 @@ struct i915_gpu_state {
 	u32 reset_count;
 	u32 suspend_count;
 	struct intel_device_info device_info;
+	struct intel_driver_caps driver_caps;
 	struct i915_params params;
 
 	struct i915_error_uc {
@@ -551,6 +556,7 @@ struct i915_gpu_state {
 			int ban_score;
 			int active;
 			int guilty;
+			bool bannable;
 		} context;
 
 		struct drm_i915_error_object {
@@ -717,7 +723,7 @@ struct intel_fbc {
 
 	struct intel_fbc_work {
 		bool scheduled;
-		u32 scheduled_vblank;
+		u64 scheduled_vblank;
 		struct work_struct work;
 	} work;
 
@@ -754,7 +760,6 @@ struct i915_drrs {
 struct i915_psr {
 	struct mutex lock;
 	bool sink_support;
-	bool source_ok;
 	struct intel_dp *enabled;
 	bool active;
 	struct delayed_work work;
@@ -783,6 +788,7 @@ enum intel_pch {
 	PCH_SPT,        /* Sunrisepoint PCH */
 	PCH_KBP,        /* Kaby Lake PCH */
 	PCH_CNP,        /* Cannon Lake PCH */
+	PCH_ICP,	/* Ice Lake PCH */
 	PCH_NOP,
 };
 
@@ -941,6 +947,8 @@ struct intel_rps {
 
 struct intel_rc6 {
 	bool enabled;
+	u64 prev_hw_residency[4];
+	u64 cur_residency[4];
 };
 
 struct intel_llc_pstate {
@@ -1255,6 +1263,7 @@ enum modeset_restore {
 #define DP_AUX_B 0x10
 #define DP_AUX_C 0x20
 #define DP_AUX_D 0x30
+#define DP_AUX_F 0x60
 
 #define DDC_PIN_B  0x05
 #define DDC_PIN_C  0x04
@@ -1281,6 +1290,7 @@ struct ddi_vbt_port_info {
 
 	uint8_t dp_boost_level;
 	uint8_t hdmi_boost_level;
+	int dp_max_link_rate;		/* 0 for not limited by VBT */
 };
 
 enum psr_lines_to_wait {
@@ -1461,6 +1471,7 @@ struct skl_wm_params {
 	uint_fixed_16_16_t plane_blocks_per_line;
 	uint_fixed_16_16_t y_tile_minimum;
 	uint32_t linetime_us;
+	uint32_t dbuf_block_size;
 };
 
 /*
@@ -1793,7 +1804,7 @@ struct i915_oa_ops {
 };
 
 struct intel_cdclk_state {
-	unsigned int cdclk, vco, ref;
+	unsigned int cdclk, vco, ref, bypass;
 	u8 voltage_level;
 };
 
@@ -1808,6 +1819,7 @@ struct drm_i915_private {
 	struct kmem_cache *priorities;
 
 	const struct intel_device_info info;
+	struct intel_driver_caps caps;
 
 	/**
 	 * Data Stolen Memory - aka "i915 stolen memory" gives us the start and
@@ -2313,6 +2325,12 @@ struct drm_i915_private {
 		 */
 		bool awake;
 
+		/**
+		 * The number of times we have woken up.
+		 */
+		unsigned int epoch;
+#define I915_EPOCH_INVALID 0
+
 		/**
 		 * We leave the user IRQ off as much as possible,
 		 * but this means that requests will finish and never
@@ -2405,16 +2423,11 @@ enum hdmi_force_audio {
  *
  * We have one bit per pipe and per scanout plane type.
  */
-#define INTEL_MAX_SPRITE_BITS_PER_PIPE 5
 #define INTEL_FRONTBUFFER_BITS_PER_PIPE 8
-#define INTEL_FRONTBUFFER_PRIMARY(pipe) \
-	(1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
-#define INTEL_FRONTBUFFER_CURSOR(pipe) \
-	(1 << (1 + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
-#define INTEL_FRONTBUFFER_SPRITE(pipe, plane) \
-	(1 << (2 + plane + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
+#define INTEL_FRONTBUFFER(pipe, plane_id) \
+	(1 << ((plane_id) + INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
 #define INTEL_FRONTBUFFER_OVERLAY(pipe) \
-	(1 << (2 + INTEL_MAX_SPRITE_BITS_PER_PIPE + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
+	(1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE - 1 + INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
 #define INTEL_FRONTBUFFER_ALL_MASK(pipe) \
 	(0xff << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
 
@@ -2596,6 +2609,7 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define IS_GEMINILAKE(dev_priv)	IS_PLATFORM(dev_priv, INTEL_GEMINILAKE)
 #define IS_COFFEELAKE(dev_priv)	IS_PLATFORM(dev_priv, INTEL_COFFEELAKE)
 #define IS_CANNONLAKE(dev_priv)	IS_PLATFORM(dev_priv, INTEL_CANNONLAKE)
+#define IS_ICELAKE(dev_priv)	IS_PLATFORM(dev_priv, INTEL_ICELAKE)
 #define IS_MOBILE(dev_priv)	((dev_priv)->info.is_mobile)
 #define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \
 				    (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00)
@@ -2647,6 +2661,8 @@ intel_info(const struct drm_i915_private *dev_priv)
 				 (dev_priv)->info.gt == 2)
 #define IS_CFL_GT3(dev_priv)	(IS_COFFEELAKE(dev_priv) && \
 				 (dev_priv)->info.gt == 3)
+#define IS_CNL_WITH_PORT_F(dev_priv)   (IS_CANNONLAKE(dev_priv) && \
+					(INTEL_DEVID(dev_priv) & 0x0004) == 0x0004)
 
 #define IS_ALPHA_SUPPORT(intel_info) ((intel_info)->is_alpha_support)
 
@@ -2707,6 +2723,7 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define IS_GEN8(dev_priv)	(!!((dev_priv)->info.gen_mask & BIT(7)))
 #define IS_GEN9(dev_priv)	(!!((dev_priv)->info.gen_mask & BIT(8)))
 #define IS_GEN10(dev_priv)	(!!((dev_priv)->info.gen_mask & BIT(9)))
+#define IS_GEN11(dev_priv)	(!!((dev_priv)->info.gen_mask & BIT(10)))
 
 #define IS_LP(dev_priv)	(INTEL_INFO(dev_priv)->is_lp)
 #define IS_GEN9_LP(dev_priv)	(IS_GEN9(dev_priv) && IS_LP(dev_priv))
@@ -2787,7 +2804,7 @@ intel_info(const struct drm_i915_private *dev_priv)
 
 #define HAS_FW_BLC(dev_priv) 	(INTEL_GEN(dev_priv) > 2)
 #define HAS_FBC(dev_priv)	((dev_priv)->info.has_fbc)
-#define HAS_CUR_FBC(dev_priv)	(!HAS_GMCH_DISPLAY(dev_priv) && INTEL_INFO(dev_priv)->gen >= 7)
+#define HAS_CUR_FBC(dev_priv)	(!HAS_GMCH_DISPLAY(dev_priv) && INTEL_GEN(dev_priv) >= 7)
 
 #define HAS_IPS(dev_priv)	(IS_HSW_ULT(dev_priv) || IS_BROADWELL(dev_priv))
 
@@ -2844,23 +2861,26 @@ intel_info(const struct drm_i915_private *dev_priv)
 #define INTEL_PCH_KBP_DEVICE_ID_TYPE		0xA280
 #define INTEL_PCH_CNP_DEVICE_ID_TYPE		0xA300
 #define INTEL_PCH_CNP_LP_DEVICE_ID_TYPE		0x9D80
+#define INTEL_PCH_ICP_DEVICE_ID_TYPE		0x3480
 #define INTEL_PCH_P2X_DEVICE_ID_TYPE		0x7100
 #define INTEL_PCH_P3X_DEVICE_ID_TYPE		0x7000
 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE		0x2900 /* qemu q35 has 2918 */
 
 #define INTEL_PCH_TYPE(dev_priv) ((dev_priv)->pch_type)
+#define INTEL_PCH_ID(dev_priv) ((dev_priv)->pch_id)
+#define HAS_PCH_ICP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_ICP)
 #define HAS_PCH_CNP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_CNP)
 #define HAS_PCH_CNP_LP(dev_priv) \
-	((dev_priv)->pch_id == INTEL_PCH_CNP_LP_DEVICE_ID_TYPE)
+	(INTEL_PCH_ID(dev_priv) == INTEL_PCH_CNP_LP_DEVICE_ID_TYPE)
 #define HAS_PCH_KBP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_KBP)
 #define HAS_PCH_SPT(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_SPT)
 #define HAS_PCH_LPT(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_LPT)
 #define HAS_PCH_LPT_LP(dev_priv) \
-	((dev_priv)->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE || \
-	 (dev_priv)->pch_id == INTEL_PCH_WPT_LP_DEVICE_ID_TYPE)
+	(INTEL_PCH_ID(dev_priv) == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE || \
+	 INTEL_PCH_ID(dev_priv) == INTEL_PCH_WPT_LP_DEVICE_ID_TYPE)
 #define HAS_PCH_LPT_H(dev_priv) \
-	((dev_priv)->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE || \
-	 (dev_priv)->pch_id == INTEL_PCH_WPT_DEVICE_ID_TYPE)
+	(INTEL_PCH_ID(dev_priv) == INTEL_PCH_LPT_DEVICE_ID_TYPE || \
+	 INTEL_PCH_ID(dev_priv) == INTEL_PCH_WPT_DEVICE_ID_TYPE)
 #define HAS_PCH_CPT(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_CPT)
 #define HAS_PCH_IBX(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_IBX)
 #define HAS_PCH_NOP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_NOP)
@@ -2951,8 +2971,10 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
 void intel_hpd_init(struct drm_i915_private *dev_priv);
 void intel_hpd_init_work(struct drm_i915_private *dev_priv);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
-enum port intel_hpd_pin_to_port(enum hpd_pin pin);
-enum hpd_pin intel_hpd_pin(enum port port);
+enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv,
+				enum hpd_pin pin);
+enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
+				   enum port port);
 bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
 void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
 
@@ -3065,10 +3087,10 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
-int i915_gem_execbuffer(struct drm_device *dev, void *data,
-			struct drm_file *file_priv);
-int i915_gem_execbuffer2(struct drm_device *dev, void *data,
-			 struct drm_file *file_priv);
+int i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data,
+			      struct drm_file *file_priv);
+int i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
+			       struct drm_file *file_priv);
 int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
@@ -3645,6 +3667,7 @@ extern int intel_setup_gmbus(struct drm_i915_private *dev_priv);
 extern void intel_teardown_gmbus(struct drm_i915_private *dev_priv);
 extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
 				     unsigned int pin);
+extern int intel_gmbus_output_aksv(struct i2c_adapter *adapter);
 
 extern struct i2c_adapter *
 intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
@@ -3720,9 +3743,10 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
 
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val);
 int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, u32 mbox,
-				    u32 val, int timeout_us);
+				    u32 val, int fast_timeout_us,
+				    int slow_timeout_ms);
 #define sandybridge_pcode_write(dev_priv, mbox, val)	\
-	sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500)
+	sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500, 0)
 
 int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request,
 		      u32 reply_mask, u32 reply, int timeout_base_ms);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index dd89abd2263d..f530cd247724 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -240,8 +240,8 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
 
 static void __start_cpu_write(struct drm_i915_gem_object *obj)
 {
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
 	if (cpu_write_needs_clflush(obj))
 		obj->cache_dirty = true;
 }
@@ -257,7 +257,7 @@ __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj,
 		obj->mm.dirty = false;
 
 	if (needs_clflush &&
-	    (obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0 &&
+	    (obj->read_domains & I915_GEM_DOMAIN_CPU) == 0 &&
 	    !(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ))
 		drm_clflush_sg(pages);
 
@@ -369,7 +369,8 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
 	if (i915_gem_request_completed(rq))
 		goto out;
 
-	/* This client is about to stall waiting for the GPU. In many cases
+	/*
+	 * This client is about to stall waiting for the GPU. In many cases
 	 * this is undesirable and limits the throughput of the system, as
 	 * many clients cannot continue processing user input/output whilst
 	 * blocked. RPS autotuning may take tens of milliseconds to respond
@@ -384,11 +385,9 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
 	 * forcing the clocks too high for the whole system, we only allow
 	 * each client to waitboost once in a busy period.
 	 */
-	if (rps_client) {
+	if (rps_client && !i915_gem_request_started(rq)) {
 		if (INTEL_GEN(rq->i915) >= 6)
 			gen6_rps_boost(rq, rps_client);
-		else
-			rps_client = NULL;
 	}
 
 	timeout = i915_wait_request(rq, flags, timeout);
@@ -704,10 +703,10 @@ flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains)
 	struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
 	struct i915_vma *vma;
 
-	if (!(obj->base.write_domain & flush_domains))
+	if (!(obj->write_domain & flush_domains))
 		return;
 
-	switch (obj->base.write_domain) {
+	switch (obj->write_domain) {
 	case I915_GEM_DOMAIN_GTT:
 		i915_gem_flush_ggtt_writes(dev_priv);
 
@@ -732,7 +731,7 @@ flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains)
 		break;
 	}
 
-	obj->base.write_domain = 0;
+	obj->write_domain = 0;
 }
 
 static inline int
@@ -832,7 +831,7 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
 	 * anyway again before the next pread happens.
 	 */
 	if (!obj->cache_dirty &&
-	    !(obj->base.read_domains & I915_GEM_DOMAIN_CPU))
+	    !(obj->read_domains & I915_GEM_DOMAIN_CPU))
 		*needs_clflush = CLFLUSH_BEFORE;
 
 out:
@@ -891,7 +890,7 @@ int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj,
 		 * Same trick applies to invalidate partially written
 		 * cachelines read before writing.
 		 */
-		if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU))
+		if (!(obj->read_domains & I915_GEM_DOMAIN_CPU))
 			*needs_clflush |= CLFLUSH_BEFORE;
 	}
 
@@ -2392,8 +2391,8 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 	 * wasn't in the GTT, there shouldn't be any way it could have been in
 	 * a GPU cache
 	 */
-	GEM_BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
-	GEM_BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
+	GEM_BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
+	GEM_BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
 	st = kmalloc(sizeof(*st), GFP_KERNEL);
 	if (st == NULL)
@@ -2824,24 +2823,23 @@ i915_gem_object_pwrite_gtt(struct drm_i915_gem_object *obj,
 	return 0;
 }
 
-static bool ban_context(const struct i915_gem_context *ctx,
-			unsigned int score)
-{
-	return (i915_gem_context_is_bannable(ctx) &&
-		score >= CONTEXT_SCORE_BAN_THRESHOLD);
-}
-
 static void i915_gem_context_mark_guilty(struct i915_gem_context *ctx)
 {
-	unsigned int score;
 	bool banned;
 
 	atomic_inc(&ctx->guilty_count);
 
-	score = atomic_add_return(CONTEXT_SCORE_GUILTY, &ctx->ban_score);
-	banned = ban_context(ctx, score);
-	DRM_DEBUG_DRIVER("context %s marked guilty (score %d) banned? %s\n",
-			 ctx->name, score, yesno(banned));
+	banned = false;
+	if (i915_gem_context_is_bannable(ctx)) {
+		unsigned int score;
+
+		score = atomic_add_return(CONTEXT_SCORE_GUILTY,
+					  &ctx->ban_score);
+		banned = score >= CONTEXT_SCORE_BAN_THRESHOLD;
+
+		DRM_DEBUG_DRIVER("context %s marked guilty (score %d) banned? %s\n",
+				 ctx->name, score, yesno(banned));
+	}
 	if (!banned)
 		return;
 
@@ -3135,7 +3133,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv)
 		 * an incoherent read by the CS (presumably stale TLB). An
 		 * empty request appears sufficient to paper over the glitch.
 		 */
-		if (list_empty(&engine->timeline->requests)) {
+		if (intel_engine_is_idle(engine)) {
 			struct drm_i915_gem_request *rq;
 
 			rq = i915_gem_request_alloc(engine,
@@ -3200,6 +3198,16 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
 	struct intel_engine_cs *engine;
 	enum intel_engine_id id;
 
+	if (drm_debug & DRM_UT_DRIVER) {
+		struct drm_printer p = drm_debug_printer(__func__);
+
+		for_each_engine(engine, i915, id)
+			intel_engine_dump(engine, &p, "%s\n", engine->name);
+	}
+
+	set_bit(I915_WEDGED, &i915->gpu_error.flags);
+	smp_mb__after_atomic();
+
 	/*
 	 * First, stop submission to hw, but do not yet complete requests by
 	 * rolling the global seqno forward (since this would complete requests
@@ -3224,8 +3232,11 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
 		 * start to complete all requests.
 		 */
 		engine->submit_request = nop_complete_submit_request;
+		engine->schedule = NULL;
 	}
 
+	i915->caps.scheduler = 0;
+
 	/*
 	 * Make sure no request can slip through without getting completed by
 	 * either this call here to intel_engine_init_global_seqno, or the one
@@ -3236,7 +3247,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
 	for_each_engine(engine, i915, id) {
 		unsigned long flags;
 
-		/* Mark all pending requests as complete so that any concurrent
+		/*
+		 * Mark all pending requests as complete so that any concurrent
 		 * (lockless) lookup doesn't try and wait upon the request as we
 		 * reset it.
 		 */
@@ -3246,7 +3258,6 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
 		spin_unlock_irqrestore(&engine->timeline->lock, flags);
 	}
 
-	set_bit(I915_WEDGED, &i915->gpu_error.flags);
 	wake_up_all(&i915->gpu_error.reset_queue);
 }
 
@@ -3334,6 +3345,65 @@ i915_gem_retire_work_handler(struct work_struct *work)
 				   round_jiffies_up_relative(HZ));
 }
 
+static void shrink_caches(struct drm_i915_private *i915)
+{
+	/*
+	 * kmem_cache_shrink() discards empty slabs and reorders partially
+	 * filled slabs to prioritise allocating from the mostly full slabs,
+	 * with the aim of reducing fragmentation.
+	 */
+	kmem_cache_shrink(i915->priorities);
+	kmem_cache_shrink(i915->dependencies);
+	kmem_cache_shrink(i915->requests);
+	kmem_cache_shrink(i915->luts);
+	kmem_cache_shrink(i915->vmas);
+	kmem_cache_shrink(i915->objects);
+}
+
+struct sleep_rcu_work {
+	union {
+		struct rcu_head rcu;
+		struct work_struct work;
+	};
+	struct drm_i915_private *i915;
+	unsigned int epoch;
+};
+
+static inline bool
+same_epoch(struct drm_i915_private *i915, unsigned int epoch)
+{
+	/*
+	 * There is a small chance that the epoch wrapped since we started
+	 * sleeping. If we assume that epoch is at least a u32, then it will
+	 * take at least 2^32 * 100ms for it to wrap, or about 326 years.
+	 */
+	return epoch == READ_ONCE(i915->gt.epoch);
+}
+
+static void __sleep_work(struct work_struct *work)
+{
+	struct sleep_rcu_work *s = container_of(work, typeof(*s), work);
+	struct drm_i915_private *i915 = s->i915;
+	unsigned int epoch = s->epoch;
+
+	kfree(s);
+	if (same_epoch(i915, epoch))
+		shrink_caches(i915);
+}
+
+static void __sleep_rcu(struct rcu_head *rcu)
+{
+	struct sleep_rcu_work *s = container_of(rcu, typeof(*s), rcu);
+	struct drm_i915_private *i915 = s->i915;
+
+	if (same_epoch(i915, s->epoch)) {
+		INIT_WORK(&s->work, __sleep_work);
+		queue_work(i915->wq, &s->work);
+	} else {
+		kfree(s);
+	}
+}
+
 static inline bool
 new_requests_since_last_retire(const struct drm_i915_private *i915)
 {
@@ -3346,6 +3416,7 @@ i915_gem_idle_work_handler(struct work_struct *work)
 {
 	struct drm_i915_private *dev_priv =
 		container_of(work, typeof(*dev_priv), gt.idle_work.work);
+	unsigned int epoch = I915_EPOCH_INVALID;
 	bool rearm_hangcheck;
 	ktime_t end;
 
@@ -3405,6 +3476,8 @@ i915_gem_idle_work_handler(struct work_struct *work)
 
 	GEM_BUG_ON(!dev_priv->gt.awake);
 	dev_priv->gt.awake = false;
+	epoch = dev_priv->gt.epoch;
+	GEM_BUG_ON(epoch == I915_EPOCH_INVALID);
 	rearm_hangcheck = false;
 
 	if (INTEL_GEN(dev_priv) >= 6)
@@ -3421,6 +3494,23 @@ i915_gem_idle_work_handler(struct work_struct *work)
 		GEM_BUG_ON(!dev_priv->gt.awake);
 		i915_queue_hangcheck(dev_priv);
 	}
+
+	/*
+	 * When we are idle, it is an opportune time to reap our caches.
+	 * However, we have many objects that utilise RCU and the ordered
+	 * i915->wq that this work is executing on. To try and flush any
+	 * pending frees now we are idle, we first wait for an RCU grace
+	 * period, and then queue a task (that will run last on the wq) to
+	 * shrink and re-optimize the caches.
+	 */
+	if (same_epoch(dev_priv, epoch)) {
+		struct sleep_rcu_work *s = kmalloc(sizeof(*s), GFP_KERNEL);
+		if (s) {
+			s->i915 = dev_priv;
+			s->epoch = epoch;
+			call_rcu(&s->rcu, __sleep_rcu);
+		}
+	}
 }
 
 void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
@@ -3566,7 +3656,7 @@ static int wait_for_engines(struct drm_i915_private *i915)
 
 			for_each_engine(engine, i915, id)
 				intel_engine_dump(engine, &p,
-						  "%s", engine->name);
+						  "%s\n", engine->name);
 		}
 
 		i915_gem_set_wedged(i915);
@@ -3613,7 +3703,7 @@ static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj)
 	flush_write_domain(obj, ~I915_GEM_DOMAIN_CPU);
 	if (obj->cache_dirty)
 		i915_gem_clflush_object(obj, I915_CLFLUSH_FORCE);
-	obj->base.write_domain = 0;
+	obj->write_domain = 0;
 }
 
 void i915_gem_object_flush_if_display(struct drm_i915_gem_object *obj)
@@ -3650,7 +3740,7 @@ i915_gem_object_set_to_wc_domain(struct drm_i915_gem_object *obj, bool write)
 	if (ret)
 		return ret;
 
-	if (obj->base.write_domain == I915_GEM_DOMAIN_WC)
+	if (obj->write_domain == I915_GEM_DOMAIN_WC)
 		return 0;
 
 	/* Flush and acquire obj->pages so that we are coherent through
@@ -3671,17 +3761,17 @@ i915_gem_object_set_to_wc_domain(struct drm_i915_gem_object *obj, bool write)
 	 * coherent writes from the GPU, by effectively invalidating the
 	 * WC domain upon first access.
 	 */
-	if ((obj->base.read_domains & I915_GEM_DOMAIN_WC) == 0)
+	if ((obj->read_domains & I915_GEM_DOMAIN_WC) == 0)
 		mb();
 
 	/* It should now be out of any other write domains, and we can update
 	 * the domain values for our changes.
 	 */
-	GEM_BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_WC) != 0);
-	obj->base.read_domains |= I915_GEM_DOMAIN_WC;
+	GEM_BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_WC) != 0);
+	obj->read_domains |= I915_GEM_DOMAIN_WC;
 	if (write) {
-		obj->base.read_domains = I915_GEM_DOMAIN_WC;
-		obj->base.write_domain = I915_GEM_DOMAIN_WC;
+		obj->read_domains = I915_GEM_DOMAIN_WC;
+		obj->write_domain = I915_GEM_DOMAIN_WC;
 		obj->mm.dirty = true;
 	}
 
@@ -3713,7 +3803,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 	if (ret)
 		return ret;
 
-	if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
+	if (obj->write_domain == I915_GEM_DOMAIN_GTT)
 		return 0;
 
 	/* Flush and acquire obj->pages so that we are coherent through
@@ -3734,17 +3824,17 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 	 * coherent writes from the GPU, by effectively invalidating the
 	 * GTT domain upon first access.
 	 */
-	if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0)
+	if ((obj->read_domains & I915_GEM_DOMAIN_GTT) == 0)
 		mb();
 
 	/* It should now be out of any other write domains, and we can update
 	 * the domain values for our changes.
 	 */
-	GEM_BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
-	obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
+	GEM_BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
+	obj->read_domains |= I915_GEM_DOMAIN_GTT;
 	if (write) {
-		obj->base.read_domains = I915_GEM_DOMAIN_GTT;
-		obj->base.write_domain = I915_GEM_DOMAIN_GTT;
+		obj->read_domains = I915_GEM_DOMAIN_GTT;
+		obj->write_domain = I915_GEM_DOMAIN_GTT;
 		obj->mm.dirty = true;
 	}
 
@@ -4056,7 +4146,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
 	/* It should now be out of any other write domains, and we can update
 	 * the domain values for our changes.
 	 */
-	obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
+	obj->read_domains |= I915_GEM_DOMAIN_GTT;
 
 	return vma;
 
@@ -4109,15 +4199,15 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
 	flush_write_domain(obj, ~I915_GEM_DOMAIN_CPU);
 
 	/* Flush the CPU cache if it's still invalid. */
-	if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) {
+	if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) {
 		i915_gem_clflush_object(obj, I915_CLFLUSH_SYNC);
-		obj->base.read_domains |= I915_GEM_DOMAIN_CPU;
+		obj->read_domains |= I915_GEM_DOMAIN_CPU;
 	}
 
 	/* It should now be out of any other write domains, and we can update
 	 * the domain values for our changes.
 	 */
-	GEM_BUG_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU);
+	GEM_BUG_ON(obj->write_domain & ~I915_GEM_DOMAIN_CPU);
 
 	/* If we're writing through the CPU, then the GPU read domains will
 	 * need to be invalidated at next use.
@@ -4553,8 +4643,8 @@ i915_gem_object_create(struct drm_i915_private *dev_priv, u64 size)
 
 	i915_gem_object_init(obj, &i915_gem_object_ops);
 
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
 
 	if (HAS_LLC(dev_priv))
 		/* On some devices, we can have the GPU use the LLC (the CPU
@@ -4698,7 +4788,8 @@ static void __i915_gem_free_work(struct work_struct *work)
 		container_of(work, struct drm_i915_private, mm.free_work);
 	struct llist_node *freed;
 
-	/* All file-owned VMA should have been released by this point through
+	/*
+	 * All file-owned VMA should have been released by this point through
 	 * i915_gem_close_object(), or earlier by i915_gem_context_close().
 	 * However, the object may also be bound into the global GTT (e.g.
 	 * older GPUs without per-process support, or for direct access through
@@ -4725,13 +4816,18 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head)
 		container_of(head, typeof(*obj), rcu);
 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
 
-	/* We can't simply use call_rcu() from i915_gem_free_object()
-	 * as we need to block whilst unbinding, and the call_rcu
-	 * task may be called from softirq context. So we take a
-	 * detour through a worker.
+	/*
+	 * Since we require blocking on struct_mutex to unbind the freed
+	 * object from the GPU before releasing resources back to the
+	 * system, we can not do that directly from the RCU callback (which may
+	 * be a softirq context), but must instead then defer that work onto a
+	 * kthread. We use the RCU callback rather than move the freed object
+	 * directly onto the work queue so that we can mix between using the
+	 * worker and performing frees directly from subsequent allocations for
+	 * crude but effective memory throttling.
 	 */
 	if (llist_add(&obj->freed, &i915->mm.free_list))
-		schedule_work(&i915->mm.free_work);
+		queue_work(i915->wq, &i915->mm.free_work);
 }
 
 void i915_gem_free_object(struct drm_gem_object *gem_obj)
@@ -4744,7 +4840,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 	if (discard_backing_storage(obj))
 		obj->mm.madv = I915_MADV_DONTNEED;
 
-	/* Before we free the object, make sure any pure RCU-only
+	/*
+	 * Before we free the object, make sure any pure RCU-only
 	 * read-side critical sections are complete, e.g.
 	 * i915_gem_busy_ioctl(). For the corresponding synchronized
 	 * lookup see i915_gem_object_lookup_rcu().
@@ -4791,10 +4888,8 @@ void i915_gem_sanitize(struct drm_i915_private *i915)
 	 * it may impact the display and we are uncertain about the stability
 	 * of the reset, so this could be applied to even earlier gen.
 	 */
-	if (INTEL_GEN(i915) >= 5) {
-		int reset = intel_gpu_reset(i915, ALL_ENGINES);
-		WARN_ON(reset && reset != -ENODEV);
-	}
+	if (INTEL_GEN(i915) >= 5 && intel_has_gpu_reset(i915))
+		WARN_ON(intel_gpu_reset(i915, ALL_ENGINES));
 }
 
 int i915_gem_suspend(struct drm_i915_private *dev_priv)
@@ -4974,8 +5069,11 @@ static int __i915_gem_restart_engines(void *data)
 
 	for_each_engine(engine, i915, id) {
 		err = engine->init_hw(engine);
-		if (err)
+		if (err) {
+			DRM_ERROR("Failed to restart %s (%d)\n",
+				  engine->name, err);
 			return err;
+		}
 	}
 
 	return 0;
@@ -5027,14 +5125,16 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv)
 
 	ret = i915_ppgtt_init_hw(dev_priv);
 	if (ret) {
-		DRM_ERROR("PPGTT enable HW failed %d\n", ret);
+		DRM_ERROR("Enabling PPGTT failed (%d)\n", ret);
 		goto out;
 	}
 
 	/* We can't enable contexts until all firmware is loaded */
 	ret = intel_uc_init_hw(dev_priv);
-	if (ret)
+	if (ret) {
+		DRM_ERROR("Enabling uc failed (%d)\n", ret);
 		goto out;
+	}
 
 	intel_mocs_init_l3cc_table(dev_priv);
 
@@ -5186,7 +5286,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
 	if (ret)
 		return ret;
 
-	ret = intel_uc_init_wq(dev_priv);
+	ret = intel_uc_init_misc(dev_priv);
 	if (ret)
 		return ret;
 
@@ -5282,7 +5382,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
 
-	intel_uc_fini_wq(dev_priv);
+	intel_uc_fini_misc(dev_priv);
 
 	if (ret != -EIO)
 		i915_gem_cleanup_userptr(dev_priv);
@@ -5324,10 +5424,10 @@ i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
 {
 	int i;
 
-	if (INTEL_INFO(dev_priv)->gen >= 7 && !IS_VALLEYVIEW(dev_priv) &&
+	if (INTEL_GEN(dev_priv) >= 7 && !IS_VALLEYVIEW(dev_priv) &&
 	    !IS_CHERRYVIEW(dev_priv))
 		dev_priv->num_fence_regs = 32;
-	else if (INTEL_INFO(dev_priv)->gen >= 4 ||
+	else if (INTEL_GEN(dev_priv) >= 4 ||
 		 IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
 		 IS_G33(dev_priv) || IS_PINEVIEW(dev_priv))
 		dev_priv->num_fence_regs = 16;
@@ -5602,7 +5702,7 @@ i915_gem_object_create_from_data(struct drm_i915_private *dev_priv,
 	if (IS_ERR(obj))
 		return obj;
 
-	GEM_BUG_ON(obj->base.write_domain != I915_GEM_DOMAIN_CPU);
+	GEM_BUG_ON(obj->write_domain != I915_GEM_DOMAIN_CPU);
 
 	file = obj->base.filp;
 	offset = 0;
diff --git a/drivers/gpu/drm/i915/i915_gem_clflush.c b/drivers/gpu/drm/i915/i915_gem_clflush.c
index b9b53ac14176..f5c570d35b2a 100644
--- a/drivers/gpu/drm/i915/i915_gem_clflush.c
+++ b/drivers/gpu/drm/i915/i915_gem_clflush.c
@@ -177,7 +177,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj,
 	} else if (obj->mm.pages) {
 		__i915_do_clflush(obj);
 	} else {
-		GEM_BUG_ON(obj->base.write_domain != I915_GEM_DOMAIN_CPU);
+		GEM_BUG_ON(obj->write_domain != I915_GEM_DOMAIN_CPU);
 	}
 
 	obj->cache_dirty = false;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 0c963fcf31ff..3d75f484f6e5 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -338,11 +338,6 @@ static void __destroy_hw_context(struct i915_gem_context *ctx,
 	context_close(ctx);
 }
 
-/**
- * The default context needs to exist per ring that uses contexts. It stores the
- * context state of the GPU for applications that don't utilize HW contexts, as
- * well as an idle case.
- */
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *dev_priv,
 			struct drm_i915_file_private *file_priv)
@@ -449,12 +444,18 @@ destroy_kernel_context(struct i915_gem_context **ctxp)
 	i915_gem_context_free(ctx);
 }
 
+static bool needs_preempt_context(struct drm_i915_private *i915)
+{
+	return HAS_LOGICAL_RING_PREEMPTION(i915);
+}
+
 int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
 {
 	struct i915_gem_context *ctx;
-	int err;
 
+	/* Reassure ourselves we are only called once */
 	GEM_BUG_ON(dev_priv->kernel_context);
+	GEM_BUG_ON(dev_priv->preempt_context);
 
 	INIT_LIST_HEAD(&dev_priv->contexts.list);
 	INIT_WORK(&dev_priv->contexts.free_work, contexts_free_worker);
@@ -468,8 +469,7 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
 	ctx = i915_gem_context_create_kernel(dev_priv, I915_PRIORITY_MIN);
 	if (IS_ERR(ctx)) {
 		DRM_ERROR("Failed to create default global context\n");
-		err = PTR_ERR(ctx);
-		goto err;
+		return PTR_ERR(ctx);
 	}
 	/*
 	 * For easy recognisablity, we want the kernel context to be 0 and then
@@ -479,23 +479,18 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
 	dev_priv->kernel_context = ctx;
 
 	/* highest priority; preempting task */
-	ctx = i915_gem_context_create_kernel(dev_priv, INT_MAX);
-	if (IS_ERR(ctx)) {
-		DRM_ERROR("Failed to create default preempt context\n");
-		err = PTR_ERR(ctx);
-		goto err_kernel_context;
+	if (needs_preempt_context(dev_priv)) {
+		ctx = i915_gem_context_create_kernel(dev_priv, INT_MAX);
+		if (!IS_ERR(ctx))
+			dev_priv->preempt_context = ctx;
+		else
+			DRM_ERROR("Failed to create preempt context; disabling preemption\n");
 	}
-	dev_priv->preempt_context = ctx;
 
 	DRM_DEBUG_DRIVER("%s context support initialized\n",
 			 dev_priv->engine[RCS]->context_size ? "logical" :
 			 "fake");
 	return 0;
-
-err_kernel_context:
-	destroy_kernel_context(&dev_priv->kernel_context);
-err:
-	return err;
 }
 
 void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
@@ -521,7 +516,8 @@ void i915_gem_contexts_fini(struct drm_i915_private *i915)
 {
 	lockdep_assert_held(&i915->drm.struct_mutex);
 
-	destroy_kernel_context(&i915->preempt_context);
+	if (i915->preempt_context)
+		destroy_kernel_context(&i915->preempt_context);
 	destroy_kernel_context(&i915->kernel_context);
 
 	/* Must free all deferred contexts (via flush_workqueue) first */
@@ -807,7 +803,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 
 			if (args->size)
 				ret = -EINVAL;
-			else if (!to_i915(dev)->engine[RCS]->schedule)
+			else if (!(to_i915(dev)->caps.scheduler & I915_SCHEDULER_CAP_PRIORITY))
 				ret = -ENODEV;
 			else if (priority > I915_CONTEXT_MAX_USER_PRIORITY ||
 				 priority < I915_CONTEXT_MIN_USER_PRIORITY)
diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
index 4bfb72f8e1cb..a681c5b891ff 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/i915_gem_context.h
@@ -29,6 +29,8 @@
 #include <linux/list.h>
 #include <linux/radix-tree.h>
 
+#include "i915_gem.h"
+
 struct pid;
 
 struct drm_device;
@@ -36,6 +38,7 @@ struct drm_file;
 
 struct drm_i915_private;
 struct drm_i915_file_private;
+struct drm_i915_gem_request;
 struct i915_hw_ppgtt;
 struct i915_vma;
 struct intel_ring;
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index 864439a214c8..69a7aec49e84 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -330,8 +330,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 	 * write-combined buffer or a delay through the chipset for GTT
 	 * writes that do require us to treat GTT as a separate cache domain.)
 	 */
-	obj->base.read_domains = I915_GEM_DOMAIN_GTT;
-	obj->base.write_domain = 0;
+	obj->read_domains = I915_GEM_DOMAIN_GTT;
+	obj->write_domain = 0;
 
 	return &obj->base;
 
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 4401068ff468..4eb28e84fda4 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -505,6 +505,8 @@ eb_add_vma(struct i915_execbuffer *eb, unsigned int i, struct i915_vma *vma)
 		list_add_tail(&vma->exec_link, &eb->unbound);
 		if (drm_mm_node_allocated(&vma->node))
 			err = i915_vma_unbind(vma);
+		if (unlikely(err))
+			vma->exec_flags = NULL;
 	}
 	return err;
 }
@@ -1073,7 +1075,7 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
 	u32 *cmd;
 	int err;
 
-	GEM_BUG_ON(vma->obj->base.write_domain & I915_GEM_DOMAIN_CPU);
+	GEM_BUG_ON(vma->obj->write_domain & I915_GEM_DOMAIN_CPU);
 
 	obj = i915_gem_batch_pool_get(&eb->engine->batch_pool, PAGE_SIZE);
 	if (IS_ERR(obj))
@@ -1861,16 +1863,16 @@ void i915_vma_move_to_active(struct i915_vma *vma,
 	i915_gem_active_set(&vma->last_read[idx], req);
 	list_move_tail(&vma->vm_link, &vma->vm->active_list);
 
-	obj->base.write_domain = 0;
+	obj->write_domain = 0;
 	if (flags & EXEC_OBJECT_WRITE) {
-		obj->base.write_domain = I915_GEM_DOMAIN_RENDER;
+		obj->write_domain = I915_GEM_DOMAIN_RENDER;
 
 		if (intel_fb_obj_invalidate(obj, ORIGIN_CS))
 			i915_gem_active_set(&obj->frontbuffer_write, req);
 
-		obj->base.read_domains = 0;
+		obj->read_domains = 0;
 	}
-	obj->base.read_domains |= I915_GEM_GPU_DOMAINS;
+	obj->read_domains |= I915_GEM_GPU_DOMAINS;
 
 	if (flags & EXEC_OBJECT_NEEDS_FENCE)
 		i915_gem_active_set(&vma->last_fence, req);
@@ -1973,7 +1975,7 @@ static int eb_submit(struct i915_execbuffer *eb)
 	return 0;
 }
 
-/**
+/*
  * Find one BSD ring to dispatch the corresponding BSD command.
  * The engine index is returned.
  */
@@ -2410,7 +2412,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 	if (out_fence) {
 		if (err == 0) {
 			fd_install(out_fence_fd, out_fence->file);
-			args->rsvd2 &= GENMASK_ULL(0, 31); /* keep in-fence */
+			args->rsvd2 &= GENMASK_ULL(31, 0); /* keep in-fence */
 			args->rsvd2 |= (u64)out_fence_fd << 32;
 			out_fence_fd = -1;
 		} else {
@@ -2463,8 +2465,8 @@ static bool check_buffer_count(size_t count)
  * list array and passes it to the real function.
  */
 int
-i915_gem_execbuffer(struct drm_device *dev, void *data,
-		    struct drm_file *file)
+i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *file)
 {
 	struct drm_i915_gem_execbuffer *args = data;
 	struct drm_i915_gem_execbuffer2 exec2;
@@ -2554,8 +2556,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 }
 
 int
-i915_gem_execbuffer2(struct drm_device *dev, void *data,
-		     struct drm_file *file)
+i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
+			   struct drm_file *file)
 {
 	struct drm_i915_gem_execbuffer2 *args = data;
 	struct drm_i915_gem_exec_object2 *exec2_list;
diff --git a/drivers/gpu/drm/i915/i915_gem_fence_reg.c b/drivers/gpu/drm/i915/i915_gem_fence_reg.c
index 012250f25255..d548ac05ccd7 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence_reg.c
+++ b/drivers/gpu/drm/i915/i915_gem_fence_reg.c
@@ -64,7 +64,7 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *fence,
 	int fence_pitch_shift;
 	u64 val;
 
-	if (INTEL_INFO(fence->i915)->gen >= 6) {
+	if (INTEL_GEN(fence->i915) >= 6) {
 		fence_reg_lo = FENCE_REG_GEN6_LO(fence->id);
 		fence_reg_hi = FENCE_REG_GEN6_HI(fence->id);
 		fence_pitch_shift = GEN6_FENCE_PITCH_SHIFT;
@@ -230,10 +230,14 @@ static int fence_update(struct drm_i915_fence_reg *fence,
 	}
 
 	if (fence->vma) {
-		ret = i915_gem_active_retire(&fence->vma->last_fence,
-				      &fence->vma->obj->base.dev->struct_mutex);
+		struct i915_vma *old = fence->vma;
+
+		ret = i915_gem_active_retire(&old->last_fence,
+					     &old->obj->base.dev->struct_mutex);
 		if (ret)
 			return ret;
+
+		i915_vma_flush_writes(old);
 	}
 
 	if (fence->vma && fence->vma != vma) {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 7e403eaa9e0f..cd5984246bc3 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -543,9 +543,7 @@ static void fill_page_dma_32(struct i915_address_space *vm,
 static int
 setup_scratch_page(struct i915_address_space *vm, gfp_t gfp)
 {
-	struct page *page = NULL;
-	dma_addr_t addr;
-	int order;
+	unsigned long size;
 
 	/*
 	 * In order to utilize 64K pages for an object with a size < 2M, we will
@@ -559,48 +557,47 @@ setup_scratch_page(struct i915_address_space *vm, gfp_t gfp)
 	 * TODO: we should really consider write-protecting the scratch-page and
 	 * sharing between ppgtt
 	 */
+	size = I915_GTT_PAGE_SIZE_4K;
 	if (i915_vm_is_48bit(vm) &&
 	    HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K)) {
-		order = get_order(I915_GTT_PAGE_SIZE_64K);
-		page = alloc_pages(gfp | __GFP_ZERO | __GFP_NOWARN, order);
-		if (page) {
-			addr = dma_map_page(vm->dma, page, 0,
-					    I915_GTT_PAGE_SIZE_64K,
-					    PCI_DMA_BIDIRECTIONAL);
-			if (unlikely(dma_mapping_error(vm->dma, addr))) {
-				__free_pages(page, order);
-				page = NULL;
-			}
-
-			if (!IS_ALIGNED(addr, I915_GTT_PAGE_SIZE_64K)) {
-				dma_unmap_page(vm->dma, addr,
-					       I915_GTT_PAGE_SIZE_64K,
-					       PCI_DMA_BIDIRECTIONAL);
-				__free_pages(page, order);
-				page = NULL;
-			}
-		}
+		size = I915_GTT_PAGE_SIZE_64K;
+		gfp |= __GFP_NOWARN;
 	}
+	gfp |= __GFP_ZERO | __GFP_RETRY_MAYFAIL;
+
+	do {
+		int order = get_order(size);
+		struct page *page;
+		dma_addr_t addr;
 
-	if (!page) {
-		order = 0;
-		page = alloc_page(gfp | __GFP_ZERO);
+		page = alloc_pages(gfp, order);
 		if (unlikely(!page))
-			return -ENOMEM;
+			goto skip;
 
-		addr = dma_map_page(vm->dma, page, 0, PAGE_SIZE,
+		addr = dma_map_page(vm->dma, page, 0, size,
 				    PCI_DMA_BIDIRECTIONAL);
-		if (unlikely(dma_mapping_error(vm->dma, addr))) {
-			__free_page(page);
-			return -ENOMEM;
-		}
-	}
+		if (unlikely(dma_mapping_error(vm->dma, addr)))
+			goto free_page;
 
-	vm->scratch_page.page = page;
-	vm->scratch_page.daddr = addr;
-	vm->scratch_page.order = order;
+		if (unlikely(!IS_ALIGNED(addr, size)))
+			goto unmap_page;
 
-	return 0;
+		vm->scratch_page.page = page;
+		vm->scratch_page.daddr = addr;
+		vm->scratch_page.order = order;
+		return 0;
+
+unmap_page:
+		dma_unmap_page(vm->dma, addr, size, PCI_DMA_BIDIRECTIONAL);
+free_page:
+		__free_pages(page, order);
+skip:
+		if (size == I915_GTT_PAGE_SIZE_4K)
+			return -ENOMEM;
+
+		size = I915_GTT_PAGE_SIZE_4K;
+		gfp &= ~__GFP_NOWARN;
+	} while (1);
 }
 
 static void cleanup_scratch_page(struct i915_address_space *vm)
@@ -676,27 +673,22 @@ static void free_pd(struct i915_address_space *vm,
 static void gen8_initialize_pd(struct i915_address_space *vm,
 			       struct i915_page_directory *pd)
 {
-	unsigned int i;
-
 	fill_px(vm, pd,
 		gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC));
-	for (i = 0; i < I915_PDES; i++)
-		pd->page_table[i] = vm->scratch_pt;
+	memset_p((void **)pd->page_table, vm->scratch_pt, I915_PDES);
 }
 
 static int __pdp_init(struct i915_address_space *vm,
 		      struct i915_page_directory_pointer *pdp)
 {
 	const unsigned int pdpes = i915_pdpes_per_pdp(vm);
-	unsigned int i;
 
 	pdp->page_directory = kmalloc_array(pdpes, sizeof(*pdp->page_directory),
 					    GFP_KERNEL | __GFP_NOWARN);
 	if (unlikely(!pdp->page_directory))
 		return -ENOMEM;
 
-	for (i = 0; i < pdpes; i++)
-		pdp->page_directory[i] = vm->scratch_pd;
+	memset_p((void **)pdp->page_directory, vm->scratch_pd, pdpes);
 
 	return 0;
 }
@@ -718,7 +710,7 @@ alloc_pdp(struct i915_address_space *vm)
 	struct i915_page_directory_pointer *pdp;
 	int ret = -ENOMEM;
 
-	WARN_ON(!use_4lvl(vm));
+	GEM_BUG_ON(!use_4lvl(vm));
 
 	pdp = kzalloc(sizeof(*pdp), GFP_KERNEL);
 	if (!pdp)
@@ -767,12 +759,9 @@ static void gen8_initialize_pdp(struct i915_address_space *vm,
 static void gen8_initialize_pml4(struct i915_address_space *vm,
 				 struct i915_pml4 *pml4)
 {
-	unsigned int i;
-
 	fill_px(vm, pml4,
 		gen8_pml4e_encode(px_dma(vm->scratch_pdp), I915_CACHE_LLC));
-	for (i = 0; i < GEN8_PML4ES_PER_PML4; i++)
-		pml4->pdps[i] = vm->scratch_pdp;
+	memset_p((void **)pml4->pdps, vm->scratch_pdp, GEN8_PML4ES_PER_PML4);
 }
 
 /* Broadwell Page Directory Pointer Descriptors */
@@ -2112,7 +2101,7 @@ static int __hw_ppgtt_init(struct i915_hw_ppgtt *ppgtt,
 	ppgtt->base.i915 = dev_priv;
 	ppgtt->base.dma = &dev_priv->drm.pdev->dev;
 
-	if (INTEL_INFO(dev_priv)->gen < 8)
+	if (INTEL_GEN(dev_priv) < 8)
 		return gen6_ppgtt_init(ppgtt);
 	else
 		return gen8_ppgtt_init(ppgtt);
@@ -2260,9 +2249,9 @@ void i915_ppgtt_release(struct kref *kref)
 	trace_i915_ppgtt_release(&ppgtt->base);
 
 	/* vmas should already be unbound and destroyed */
-	WARN_ON(!list_empty(&ppgtt->base.active_list));
-	WARN_ON(!list_empty(&ppgtt->base.inactive_list));
-	WARN_ON(!list_empty(&ppgtt->base.unbound_list));
+	GEM_BUG_ON(!list_empty(&ppgtt->base.active_list));
+	GEM_BUG_ON(!list_empty(&ppgtt->base.inactive_list));
+	GEM_BUG_ON(!list_empty(&ppgtt->base.unbound_list));
 
 	ppgtt->base.cleanup(&ppgtt->base);
 	i915_address_space_fini(&ppgtt->base);
@@ -2370,9 +2359,10 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
 			       struct sg_table *pages)
 {
 	do {
-		if (dma_map_sg(&obj->base.dev->pdev->dev,
-			       pages->sgl, pages->nents,
-			       PCI_DMA_BIDIRECTIONAL))
+		if (dma_map_sg_attrs(&obj->base.dev->pdev->dev,
+				     pages->sgl, pages->nents,
+				     PCI_DMA_BIDIRECTIONAL,
+				     DMA_ATTR_NO_WARN))
 			return 0;
 
 		/* If the DMA remap fails, one cause can be that we have
@@ -2824,10 +2814,10 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915)
 
 	i915->mm.aliasing_ppgtt = ppgtt;
 
-	WARN_ON(ggtt->base.bind_vma != ggtt_bind_vma);
+	GEM_BUG_ON(ggtt->base.bind_vma != ggtt_bind_vma);
 	ggtt->base.bind_vma = aliasing_gtt_bind_vma;
 
-	WARN_ON(ggtt->base.unbind_vma != ggtt_unbind_vma);
+	GEM_BUG_ON(ggtt->base.unbind_vma != ggtt_unbind_vma);
 	ggtt->base.unbind_vma = aliasing_gtt_unbind_vma;
 
 	return 0;
@@ -2918,7 +2908,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv)
 	ggtt->base.closed = true;
 
 	mutex_lock(&dev_priv->drm.struct_mutex);
-	WARN_ON(!list_empty(&ggtt->base.active_list));
+	GEM_BUG_ON(!list_empty(&ggtt->base.active_list));
 	list_for_each_entry_safe(vma, vn, &ggtt->base.inactive_list, vm_link)
 		WARN_ON(i915_vma_unbind(vma));
 	mutex_unlock(&dev_priv->drm.struct_mutex);
@@ -3811,6 +3801,9 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
 	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj));
 
 	switch (vma->ggtt_view.type) {
+	default:
+		GEM_BUG_ON(vma->ggtt_view.type);
+		/* fall through */
 	case I915_GGTT_VIEW_NORMAL:
 		vma->pages = vma->obj->mm.pages;
 		return 0;
@@ -3823,11 +3816,6 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
 	case I915_GGTT_VIEW_PARTIAL:
 		vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj);
 		break;
-
-	default:
-		WARN_ONCE(1, "GGTT view %u not implemented!\n",
-			  vma->ggtt_view.type);
-		return -EINVAL;
 	}
 
 	ret = 0;
diff --git a/drivers/gpu/drm/i915/i915_gem_internal.c b/drivers/gpu/drm/i915/i915_gem_internal.c
index a1d6956734f7..0d0144b2104c 100644
--- a/drivers/gpu/drm/i915/i915_gem_internal.c
+++ b/drivers/gpu/drm/i915/i915_gem_internal.c
@@ -167,6 +167,10 @@ static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = {
 };
 
 /**
+ * i915_gem_object_create_internal: create an object with volatile pages
+ * @i915: the i915 device
+ * @size: the size in bytes of backing storage to allocate for the object
+ *
  * Creates a new object that wraps some internal memory for private use.
  * This object is not backed by swappable storage, and as such its contents
  * are volatile and only valid whilst pinned. If the object is reaped by the
@@ -197,8 +201,8 @@ i915_gem_object_create_internal(struct drm_i915_private *i915,
 	drm_gem_private_object_init(&i915->drm, &obj->base, size);
 	i915_gem_object_init(obj, &i915_gem_object_internal_ops);
 
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
 
 	cache_level = HAS_LLC(i915) ? I915_CACHE_LLC : I915_CACHE_NONE;
 	i915_gem_object_set_cache_coherency(obj, cache_level);
diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h
index 05e89e1c0a08..ca2b3b62569d 100644
--- a/drivers/gpu/drm/i915/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/i915_gem_object.h
@@ -148,6 +148,21 @@ struct drm_i915_gem_object {
 #define I915_BO_CACHE_COHERENT_FOR_WRITE BIT(1)
 	unsigned int cache_dirty:1;
 
+	/**
+	 * @read_domains: Read memory domains.
+	 *
+	 * These monitor which caches contain read/write data related to the
+	 * object. When transitioning from one set of domains to another,
+	 * the driver is called to ensure that caches are suitably flushed and
+	 * invalidated.
+	 */
+	u16 read_domains;
+
+	/**
+	 * @write_domain: Corresponding unique write memory domain.
+	 */
+	u16 write_domain;
+
 	atomic_t frontbuffer_bits;
 	unsigned int frontbuffer_ggtt_origin; /* write once */
 	struct i915_gem_active frontbuffer_write;
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
index e09d18df8b7f..8bc7c50b8418 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -161,12 +161,16 @@ i915_priotree_fini(struct drm_i915_private *i915, struct i915_priotree *pt)
 
 	GEM_BUG_ON(!list_empty(&pt->link));
 
-	/* Everyone we depended upon (the fences we wait to be signaled)
+	/*
+	 * Everyone we depended upon (the fences we wait to be signaled)
 	 * should retire before us and remove themselves from our list.
 	 * However, retirement is run independently on each timeline and
 	 * so we may be called out-of-order.
 	 */
 	list_for_each_entry_safe(dep, next, &pt->signalers_list, signal_link) {
+		GEM_BUG_ON(!i915_priotree_signaled(dep->signaler));
+		GEM_BUG_ON(!list_empty(&dep->dfs_link));
+
 		list_del(&dep->wait_link);
 		if (dep->flags & I915_DEPENDENCY_ALLOC)
 			i915_dependency_free(i915, dep);
@@ -174,6 +178,9 @@ i915_priotree_fini(struct drm_i915_private *i915, struct i915_priotree *pt)
 
 	/* Remove ourselves from everyone who depends upon us */
 	list_for_each_entry_safe(dep, next, &pt->waiters_list, wait_link) {
+		GEM_BUG_ON(dep->signaler != pt);
+		GEM_BUG_ON(!list_empty(&dep->dfs_link));
+
 		list_del(&dep->signal_link);
 		if (dep->flags & I915_DEPENDENCY_ALLOC)
 			i915_dependency_free(i915, dep);
@@ -267,6 +274,8 @@ static void mark_busy(struct drm_i915_private *i915)
 	intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
 
 	i915->gt.awake = true;
+	if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */
+		i915->gt.epoch = 1;
 
 	intel_enable_gt_powersave(i915);
 	i915_update_gfx_val(i915);
@@ -434,9 +443,14 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
 	engine->last_retired_context = request->ctx;
 
 	spin_lock_irq(&request->lock);
-	if (request->waitboost)
+	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &request->fence.flags))
+		dma_fence_signal_locked(&request->fence);
+	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags))
+		intel_engine_cancel_signaling(request);
+	if (request->waitboost) {
+		GEM_BUG_ON(!atomic_read(&request->i915->gt_pm.rps.num_waiters));
 		atomic_dec(&request->i915->gt_pm.rps.num_waiters);
-	dma_fence_signal_locked(&request->fence);
+	}
 	spin_unlock_irq(&request->lock);
 
 	i915_priotree_fini(request->i915, &request->priotree);
@@ -530,6 +544,8 @@ void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
 	 */
 	GEM_BUG_ON(!request->global_seqno);
 	GEM_BUG_ON(request->global_seqno != engine->timeline->seqno);
+	GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine),
+				     request->global_seqno));
 	engine->timeline->seqno--;
 
 	/* We may be recursing from the signal callback of another i915 fence */
@@ -691,6 +707,17 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
 		if (ret)
 			goto err_unreserve;
 
+		/*
+		 * We've forced the client to stall and catch up with whatever
+		 * backlog there might have been. As we are assuming that we
+		 * caused the mempressure, now is an opportune time to
+		 * recover as much memory from the request pool as is possible.
+		 * Having already penalized the client to stall, we spend
+		 * a little extra time to re-optimise page allocation.
+		 */
+		kmem_cache_shrink(dev_priv->requests);
+		rcu_barrier(); /* Recover the TYPESAFE_BY_RCU pages */
+
 		req = kmem_cache_alloc(dev_priv->requests, GFP_KERNEL);
 		if (!req) {
 			ret = -ENOMEM;
@@ -722,6 +749,7 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
 
 	/* No zalloc, must clear what we need by hand */
 	req->global_seqno = 0;
+	req->signaling.wait.seqno = 0;
 	req->file_priv = NULL;
 	req->batch = NULL;
 	req->capture_list = NULL;
@@ -890,9 +918,9 @@ i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req,
 
 /**
  * i915_gem_request_await_object - set this request to (async) wait upon a bo
- *
  * @to: request we are wishing to use
  * @obj: object which may be in use on another ring.
+ * @write: whether the wait is on behalf of a writer
  *
  * This code is meant to abstract object synchronization with the GPU.
  * Conceptually we serialise writes between engines inside the GPU.
@@ -967,7 +995,8 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
 	lockdep_assert_held(&request->i915->drm.struct_mutex);
 	trace_i915_gem_request_add(request);
 
-	/* Make sure that no request gazumped us - if it was allocated after
+	/*
+	 * Make sure that no request gazumped us - if it was allocated after
 	 * our i915_gem_request_alloc() and called __i915_add_request() before
 	 * us, the timeline will hold its seqno which is later than ours.
 	 */
@@ -994,7 +1023,8 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
 		WARN(err, "engine->emit_flush() failed: %d!\n", err);
 	}
 
-	/* Record the position of the start of the breadcrumb so that
+	/*
+	 * Record the position of the start of the breadcrumb so that
 	 * should we detect the updated seqno part-way through the
 	 * GPU processing the request, we never over-estimate the
 	 * position of the ring's HEAD.
@@ -1003,7 +1033,8 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
 	GEM_BUG_ON(IS_ERR(cs));
 	request->postfix = intel_ring_offset(request, cs);
 
-	/* Seal the request and mark it as pending execution. Note that
+	/*
+	 * Seal the request and mark it as pending execution. Note that
 	 * we may inspect this state, without holding any locks, during
 	 * hangcheck. Hence we apply the barrier to ensure that we do not
 	 * see a more recent value in the hws than we are tracking.
@@ -1011,7 +1042,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
 
 	prev = i915_gem_active_raw(&timeline->last_request,
 				   &request->i915->drm.struct_mutex);
-	if (prev) {
+	if (prev && !i915_gem_request_completed(prev)) {
 		i915_sw_fence_await_sw_fence(&request->submit, &prev->submit,
 					     &request->submitq);
 		if (engine->schedule)
@@ -1031,7 +1062,8 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
 	list_add_tail(&request->ring_link, &ring->request_list);
 	request->emitted_jiffies = jiffies;
 
-	/* Let the backend know a new request has arrived that may need
+	/*
+	 * Let the backend know a new request has arrived that may need
 	 * to adjust the existing execution schedule due to a high priority
 	 * request - i.e. we may want to preempt the current request in order
 	 * to run a high priority dependency chain *before* we can execute this
@@ -1047,6 +1079,26 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
 	local_bh_disable();
 	i915_sw_fence_commit(&request->submit);
 	local_bh_enable(); /* Kick the execlists tasklet if just scheduled */
+
+	/*
+	 * In typical scenarios, we do not expect the previous request on
+	 * the timeline to be still tracked by timeline->last_request if it
+	 * has been completed. If the completed request is still here, that
+	 * implies that request retirement is a long way behind submission,
+	 * suggesting that we haven't been retiring frequently enough from
+	 * the combination of retire-before-alloc, waiters and the background
+	 * retirement worker. So if the last request on this timeline was
+	 * already completed, do a catch up pass, flushing the retirement queue
+	 * up to this client. Since we have now moved the heaviest operations
+	 * during retirement onto secondary workers, such as freeing objects
+	 * or contexts, retiring a bunch of requests is mostly list management
+	 * (and cache misses), and so we should not be overly penalizing this
+	 * client by performing excess work, though we may still performing
+	 * work on behalf of others -- but instead we should benefit from
+	 * improved resource management. (Well, that's the theory at least.)
+	 */
+	if (prev && i915_gem_request_completed(prev))
+		i915_gem_request_retire_upto(prev);
 }
 
 static unsigned long local_clock_us(unsigned int *cpu)
diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h
index 0d6d39f19506..2236e9188c5c 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.h
+++ b/drivers/gpu/drm/i915/i915_gem_request.h
@@ -245,18 +245,6 @@ i915_gem_request_put(struct drm_i915_gem_request *req)
 	dma_fence_put(&req->fence);
 }
 
-static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
-					   struct drm_i915_gem_request *src)
-{
-	if (src)
-		i915_gem_request_get(src);
-
-	if (*pdst)
-		i915_gem_request_put(*pdst);
-
-	*pdst = src;
-}
-
 /**
  * i915_gem_request_global_seqno - report the current global seqno
  * @request - the request
@@ -341,6 +329,27 @@ i915_gem_request_completed(const struct drm_i915_gem_request *req)
 	return __i915_gem_request_completed(req, seqno);
 }
 
+static inline bool
+i915_gem_request_started(const struct drm_i915_gem_request *req)
+{
+	u32 seqno;
+
+	seqno = i915_gem_request_global_seqno(req);
+	if (!seqno)
+		return false;
+
+	return i915_seqno_passed(intel_engine_get_seqno(req->engine),
+				 seqno - 1);
+}
+
+static inline bool i915_priotree_signaled(const struct i915_priotree *pt)
+{
+	const struct drm_i915_gem_request *rq =
+		container_of(pt, const struct drm_i915_gem_request, priotree);
+
+	return i915_gem_request_completed(rq);
+}
+
 /* We treat requests as fences. This is not be to confused with our
  * "fence registers" but pipeline synchronisation objects ala GL_ARB_sync.
  * We use the fences to synchronize access from the CPU with activity on the
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index d3f222fa6356..62aa67960bf4 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -356,7 +356,7 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv)
 	reserved_base = 0;
 	reserved_size = 0;
 
-	switch (INTEL_INFO(dev_priv)->gen) {
+	switch (INTEL_GEN(dev_priv)) {
 	case 2:
 	case 3:
 		break;
@@ -516,7 +516,7 @@ _i915_gem_object_create_stolen(struct drm_i915_private *dev_priv,
 	i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
 
 	obj->stolen = stolen;
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT;
+	obj->read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT;
 	cache_level = HAS_LLC(dev_priv) ? I915_CACHE_LLC : I915_CACHE_NONE;
 	i915_gem_object_set_cache_coherency(obj, cache_level);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index 382a77a1097e..d596a8302ca3 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -721,7 +721,7 @@ static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
 	.release = i915_gem_userptr_release,
 };
 
-/**
+/*
  * Creates a new mm object that wraps some normal memory from the process
  * context - user memory.
  *
@@ -757,7 +757,9 @@ static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
  * dma-buf instead.
  */
 int
-i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+i915_gem_userptr_ioctl(struct drm_device *dev,
+		       void *data,
+		       struct drm_file *file)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct drm_i915_gem_userptr *args = data;
@@ -796,8 +798,8 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file
 
 	drm_gem_private_object_init(dev, &obj->base, args->user_size);
 	i915_gem_object_init(obj, &i915_gem_userptr_ops);
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
 	i915_gem_object_set_cache_coherency(obj, I915_CACHE_LLC);
 
 	obj->userptr.ptr = args->user_ptr;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 944059322daa..65c0bef73ee5 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -34,16 +34,25 @@
 
 #include "i915_drv.h"
 
-static const char *engine_str(int engine)
-{
-	switch (engine) {
-	case RCS: return "render";
-	case VCS: return "bsd";
-	case BCS: return "blt";
-	case VECS: return "vebox";
-	case VCS2: return "bsd2";
-	default: return "";
-	}
+static inline const struct intel_engine_cs *
+engine_lookup(const struct drm_i915_private *i915, unsigned int id)
+{
+	if (id >= I915_NUM_ENGINES)
+		return NULL;
+
+	return i915->engine[id];
+}
+
+static inline const char *
+__engine_name(const struct intel_engine_cs *engine)
+{
+	return engine ? engine->name : "";
+}
+
+static const char *
+engine_name(const struct drm_i915_private *i915, unsigned int id)
+{
+	return __engine_name(engine_lookup(i915, id));
 }
 
 static const char *tiling_flag(int tiling)
@@ -345,7 +354,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
 		err_puts(m, purgeable_flag(err->purgeable));
 		err_puts(m, err->userptr ? " userptr" : "");
 		err_puts(m, err->engine != -1 ? " " : "");
-		err_puts(m, engine_str(err->engine));
+		err_puts(m, engine_name(m->i915, err->engine));
 		err_puts(m, i915_cache_level_str(m->i915, err->cache_level));
 
 		if (err->name)
@@ -387,6 +396,11 @@ static void error_print_instdone(struct drm_i915_error_state_buf *m,
 			   ee->instdone.row[slice][subslice]);
 }
 
+static const char *bannable(const struct drm_i915_error_context *ctx)
+{
+	return ctx->bannable ? "" : " (unbannable)";
+}
+
 static void error_print_request(struct drm_i915_error_state_buf *m,
 				const char *prefix,
 				const struct drm_i915_error_request *erq)
@@ -405,9 +419,10 @@ static void error_print_context(struct drm_i915_error_state_buf *m,
 				const char *header,
 				const struct drm_i915_error_context *ctx)
 {
-	err_printf(m, "%s%s[%d] user_handle %d hw_id %d, prio %d, ban score %d guilty %d active %d\n",
+	err_printf(m, "%s%s[%d] user_handle %d hw_id %d, prio %d, ban score %d%s guilty %d active %d\n",
 		   header, ctx->comm, ctx->pid, ctx->handle, ctx->hw_id,
-		   ctx->priority, ctx->ban_score, ctx->guilty, ctx->active);
+		   ctx->priority, ctx->ban_score, bannable(ctx),
+		   ctx->guilty, ctx->active);
 }
 
 static void error_print_engine(struct drm_i915_error_state_buf *m,
@@ -415,7 +430,8 @@ static void error_print_engine(struct drm_i915_error_state_buf *m,
 {
 	int n;
 
-	err_printf(m, "%s command stream:\n", engine_str(ee->engine_id));
+	err_printf(m, "%s command stream:\n",
+		   engine_name(m->i915, ee->engine_id));
 	err_printf(m, "  IDLE?: %s\n", yesno(ee->idle));
 	err_printf(m, "  START: 0x%08x\n", ee->start);
 	err_printf(m, "  HEAD:  0x%08x [0x%08x]\n", ee->head, ee->rq_head);
@@ -563,11 +579,13 @@ static void print_error_obj(struct drm_i915_error_state_buf *m,
 }
 
 static void err_print_capabilities(struct drm_i915_error_state_buf *m,
-				   const struct intel_device_info *info)
+				   const struct intel_device_info *info,
+				   const struct intel_driver_caps *caps)
 {
 	struct drm_printer p = i915_error_printer(m);
 
 	intel_device_info_dump_flags(info, &p);
+	intel_driver_caps_print(caps, &p);
 }
 
 static void err_print_params(struct drm_i915_error_state_buf *m,
@@ -610,6 +628,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 {
 	struct drm_i915_private *dev_priv = m->i915;
 	struct drm_i915_error_object *obj;
+	struct timespec64 ts;
 	int i, j;
 
 	if (!error) {
@@ -620,21 +639,25 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 	if (*error->error_msg)
 		err_printf(m, "%s\n", error->error_msg);
 	err_printf(m, "Kernel: " UTS_RELEASE "\n");
-	err_printf(m, "Time: %ld s %ld us\n",
-		   error->time.tv_sec, error->time.tv_usec);
-	err_printf(m, "Boottime: %ld s %ld us\n",
-		   error->boottime.tv_sec, error->boottime.tv_usec);
-	err_printf(m, "Uptime: %ld s %ld us\n",
-		   error->uptime.tv_sec, error->uptime.tv_usec);
+	ts = ktime_to_timespec64(error->time);
+	err_printf(m, "Time: %lld s %ld us\n",
+		   (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC);
+	ts = ktime_to_timespec64(error->boottime);
+	err_printf(m, "Boottime: %lld s %ld us\n",
+		   (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC);
+	ts = ktime_to_timespec64(error->uptime);
+	err_printf(m, "Uptime: %lld s %ld us\n",
+		   (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC);
 
 	for (i = 0; i < ARRAY_SIZE(error->engine); i++) {
 		if (error->engine[i].hangcheck_stalled &&
 		    error->engine[i].context.pid) {
-			err_printf(m, "Active process (on ring %s): %s [%d], score %d\n",
-				   engine_str(i),
+			err_printf(m, "Active process (on ring %s): %s [%d], score %d%s\n",
+				   engine_name(m->i915, i),
 				   error->engine[i].context.comm,
 				   error->engine[i].context.pid,
-				   error->engine[i].context.ban_score);
+				   error->engine[i].context.ban_score,
+				   bannable(&error->engine[i].context));
 		}
 	}
 	err_printf(m, "Reset count: %u\n", error->reset_count);
@@ -722,12 +745,13 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 		if (obj) {
 			err_puts(m, dev_priv->engine[i]->name);
 			if (ee->context.pid)
-				err_printf(m, " (submitted by %s [%d], ctx %d [%d], score %d)",
+				err_printf(m, " (submitted by %s [%d], ctx %d [%d], score %d%s)",
 					   ee->context.comm,
 					   ee->context.pid,
 					   ee->context.handle,
 					   ee->context.hw_id,
-					   ee->context.ban_score);
+					   ee->context.ban_score,
+					   bannable(&ee->context));
 			err_printf(m, " --- gtt_offset = 0x%08x %08x\n",
 				   upper_32_bits(obj->gtt_offset),
 				   lower_32_bits(obj->gtt_offset));
@@ -786,7 +810,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 	if (error->display)
 		intel_display_print_error_state(m, error->display);
 
-	err_print_capabilities(m, &error->device_info);
+	err_print_capabilities(m, &error->device_info, &error->driver_caps);
 	err_print_params(m, &error->params);
 	err_print_uc(m, &error->uc);
 
@@ -997,8 +1021,8 @@ static void capture_bo(struct drm_i915_error_buffer *err,
 	err->engine = __active_get_engine_id(&obj->frontbuffer_write);
 
 	err->gtt_offset = vma->node.start;
-	err->read_domains = obj->base.read_domains;
-	err->write_domain = obj->base.write_domain;
+	err->read_domains = obj->read_domains;
+	err->write_domain = obj->write_domain;
 	err->fence_reg = vma->fence ? vma->fence->id : -1;
 	err->tiling = i915_gem_object_get_tiling(obj);
 	err->dirty = obj->mm.dirty;
@@ -1369,6 +1393,7 @@ static void record_context(struct drm_i915_error_context *e,
 	e->hw_id = ctx->hw_id;
 	e->priority = ctx->priority;
 	e->ban_score = atomic_read(&ctx->ban_score);
+	e->bannable = i915_gem_context_is_bannable(ctx);
 	e->guilty = atomic_read(&ctx->guilty_count);
 	e->active = atomic_read(&ctx->active_count);
 }
@@ -1717,6 +1742,7 @@ static void i915_capture_gen_state(struct drm_i915_private *dev_priv,
 	memcpy(&error->device_info,
 	       INTEL_INFO(dev_priv),
 	       sizeof(error->device_info));
+	error->driver_caps = dev_priv->caps;
 }
 
 static __always_inline void dup_param(const char *type, void *x)
@@ -1737,11 +1763,10 @@ static int capture(void *data)
 {
 	struct i915_gpu_state *error = data;
 
-	do_gettimeofday(&error->time);
-	error->boottime = ktime_to_timeval(ktime_get_boottime());
-	error->uptime =
-		ktime_to_timeval(ktime_sub(ktime_get(),
-					   error->i915->gt.last_init_time));
+	error->time = ktime_get_real();
+	error->boottime = ktime_get_boottime();
+	error->uptime = ktime_sub(ktime_get(),
+				  error->i915->gt.last_init_time);
 
 	capture_params(error);
 	capture_uc_state(error);
@@ -1780,14 +1805,16 @@ i915_capture_gpu_state(struct drm_i915_private *i915)
 
 /**
  * i915_capture_error_state - capture an error record for later analysis
- * @dev: drm device
+ * @i915: i915 device
+ * @engine_mask: the mask of engines triggering the hang
+ * @error_msg: a message to insert into the error capture header
  *
  * Should be called when an error is detected (either a hang or an error
  * interrupt) to capture error state from the time of the error.  Fills
  * out a structure which becomes available in debugfs for user level tools
  * to pick up.
  */
-void i915_capture_error_state(struct drm_i915_private *dev_priv,
+void i915_capture_error_state(struct drm_i915_private *i915,
 			      u32 engine_mask,
 			      const char *error_msg)
 {
@@ -1798,25 +1825,25 @@ void i915_capture_error_state(struct drm_i915_private *dev_priv,
 	if (!i915_modparams.error_capture)
 		return;
 
-	if (READ_ONCE(dev_priv->gpu_error.first_error))
+	if (READ_ONCE(i915->gpu_error.first_error))
 		return;
 
-	error = i915_capture_gpu_state(dev_priv);
+	error = i915_capture_gpu_state(i915);
 	if (!error) {
 		DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
 		return;
 	}
 
-	i915_error_capture_msg(dev_priv, error, engine_mask, error_msg);
+	i915_error_capture_msg(i915, error, engine_mask, error_msg);
 	DRM_INFO("%s\n", error->error_msg);
 
 	if (!error->simulated) {
-		spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
-		if (!dev_priv->gpu_error.first_error) {
-			dev_priv->gpu_error.first_error = error;
+		spin_lock_irqsave(&i915->gpu_error.lock, flags);
+		if (!i915->gpu_error.first_error) {
+			i915->gpu_error.first_error = error;
 			error = NULL;
 		}
-		spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
+		spin_unlock_irqrestore(&i915->gpu_error.lock, flags);
 	}
 
 	if (error) {
@@ -1831,7 +1858,7 @@ void i915_capture_error_state(struct drm_i915_private *dev_priv,
 		DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n");
 		DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n");
 		DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n",
-			 dev_priv->drm.primary->index);
+			 i915->drm.primary->index);
 		warned = true;
 	}
 }
diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c
index 97f3a5640289..0e5c580d117c 100644
--- a/drivers/gpu/drm/i915/i915_ioc32.c
+++ b/drivers/gpu/drm/i915/i915_ioc32.c
@@ -1,11 +1,6 @@
-/**
- * \file i915_ioc32.c
- *
+/*
  * 32-bit ioctl compatibility routines for the i915 DRM.
  *
- * \author Alan Hourihane <alanh@fairlite.demon.co.uk>
- *
- *
  * Copyright (C) Paul Mackerras 2005
  * Copyright (C) Alan Hourihane 2005
  * All Rights Reserved.
@@ -28,6 +23,8 @@
  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  * IN THE SOFTWARE.
+ *
+ * Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
  */
 #include <linux/compat.h>
 
@@ -55,10 +52,10 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd,
 		return -EFAULT;
 
 	request = compat_alloc_user_space(sizeof(*request));
-	if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
-	    || __put_user(req32.param, &request->param)
-	    || __put_user((void __user *)(unsigned long)req32.value,
-			  &request->value))
+	if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) ||
+	    __put_user(req32.param, &request->param) ||
+	    __put_user((void __user *)(unsigned long)req32.value,
+		       &request->value))
 		return -EFAULT;
 
 	return drm_ioctl(file, DRM_IOCTL_I915_GETPARAM,
@@ -70,13 +67,13 @@ static drm_ioctl_compat_t *i915_compat_ioctls[] = {
 };
 
 /**
+ * i915_compat_ioctl - handle the mistakes of the past
+ * @filp: the file pointer
+ * @cmd: the ioctl command (and encoded flags)
+ * @arg: the ioctl argument (from userspace)
+ *
  * Called whenever a 32-bit process running under a 64-bit kernel
  * performs an ioctl on /dev/dri/card<n>.
- *
- * \param filp file pointer.
- * \param cmd command.
- * \param arg user argument.
- * \return zero on success or negative number on failure.
  */
 long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 3517c6548e2c..17de6cef2a30 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -452,6 +452,8 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
 
 void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
 {
+	assert_rpm_wakelock_held(dev_priv);
+
 	spin_lock_irq(&dev_priv->irq_lock);
 	gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
 	spin_unlock_irq(&dev_priv->irq_lock);
@@ -459,6 +461,8 @@ void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
 
 void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
 {
+	assert_rpm_wakelock_held(dev_priv);
+
 	spin_lock_irq(&dev_priv->irq_lock);
 	if (!dev_priv->guc.interrupts_enabled) {
 		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
@@ -471,6 +475,8 @@ void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
 
 void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
 {
+	assert_rpm_wakelock_held(dev_priv);
+
 	spin_lock_irq(&dev_priv->irq_lock);
 	dev_priv->guc.interrupts_enabled = false;
 
@@ -1407,80 +1413,73 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
 		tasklet_hi_schedule(&execlists->tasklet);
 }
 
-static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
-				   u32 master_ctl,
-				   u32 gt_iir[4])
+static void gen8_gt_irq_ack(struct drm_i915_private *i915,
+			    u32 master_ctl, u32 gt_iir[4])
 {
-	irqreturn_t ret = IRQ_NONE;
+	void __iomem * const regs = i915->regs;
+
+#define GEN8_GT_IRQS (GEN8_GT_RCS_IRQ | \
+		      GEN8_GT_BCS_IRQ | \
+		      GEN8_GT_VCS1_IRQ | \
+		      GEN8_GT_VCS2_IRQ | \
+		      GEN8_GT_VECS_IRQ | \
+		      GEN8_GT_PM_IRQ | \
+		      GEN8_GT_GUC_IRQ)
 
 	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
-		gt_iir[0] = I915_READ_FW(GEN8_GT_IIR(0));
-		if (gt_iir[0]) {
-			I915_WRITE_FW(GEN8_GT_IIR(0), gt_iir[0]);
-			ret = IRQ_HANDLED;
-		} else
-			DRM_ERROR("The master control interrupt lied (GT0)!\n");
+		gt_iir[0] = raw_reg_read(regs, GEN8_GT_IIR(0));
+		if (likely(gt_iir[0]))
+			raw_reg_write(regs, GEN8_GT_IIR(0), gt_iir[0]);
 	}
 
 	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
-		gt_iir[1] = I915_READ_FW(GEN8_GT_IIR(1));
-		if (gt_iir[1]) {
-			I915_WRITE_FW(GEN8_GT_IIR(1), gt_iir[1]);
-			ret = IRQ_HANDLED;
-		} else
-			DRM_ERROR("The master control interrupt lied (GT1)!\n");
-	}
-
-	if (master_ctl & GEN8_GT_VECS_IRQ) {
-		gt_iir[3] = I915_READ_FW(GEN8_GT_IIR(3));
-		if (gt_iir[3]) {
-			I915_WRITE_FW(GEN8_GT_IIR(3), gt_iir[3]);
-			ret = IRQ_HANDLED;
-		} else
-			DRM_ERROR("The master control interrupt lied (GT3)!\n");
+		gt_iir[1] = raw_reg_read(regs, GEN8_GT_IIR(1));
+		if (likely(gt_iir[1]))
+			raw_reg_write(regs, GEN8_GT_IIR(1), gt_iir[1]);
 	}
 
 	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
-		gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
-		if (gt_iir[2] & (dev_priv->pm_rps_events |
-				 dev_priv->pm_guc_events)) {
-			I915_WRITE_FW(GEN8_GT_IIR(2),
-				      gt_iir[2] & (dev_priv->pm_rps_events |
-						   dev_priv->pm_guc_events));
-			ret = IRQ_HANDLED;
-		} else
-			DRM_ERROR("The master control interrupt lied (PM)!\n");
+		gt_iir[2] = raw_reg_read(regs, GEN8_GT_IIR(2));
+		if (likely(gt_iir[2] & (i915->pm_rps_events |
+					i915->pm_guc_events)))
+			raw_reg_write(regs, GEN8_GT_IIR(2),
+				      gt_iir[2] & (i915->pm_rps_events |
+						   i915->pm_guc_events));
 	}
 
-	return ret;
+	if (master_ctl & GEN8_GT_VECS_IRQ) {
+		gt_iir[3] = raw_reg_read(regs, GEN8_GT_IIR(3));
+		if (likely(gt_iir[3]))
+			raw_reg_write(regs, GEN8_GT_IIR(3), gt_iir[3]);
+	}
 }
 
-static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
-				u32 gt_iir[4])
+static void gen8_gt_irq_handler(struct drm_i915_private *i915,
+				u32 master_ctl, u32 gt_iir[4])
 {
-	if (gt_iir[0]) {
-		gen8_cs_irq_handler(dev_priv->engine[RCS],
+	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
+		gen8_cs_irq_handler(i915->engine[RCS],
 				    gt_iir[0], GEN8_RCS_IRQ_SHIFT);
-		gen8_cs_irq_handler(dev_priv->engine[BCS],
+		gen8_cs_irq_handler(i915->engine[BCS],
 				    gt_iir[0], GEN8_BCS_IRQ_SHIFT);
 	}
 
-	if (gt_iir[1]) {
-		gen8_cs_irq_handler(dev_priv->engine[VCS],
+	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
+		gen8_cs_irq_handler(i915->engine[VCS],
 				    gt_iir[1], GEN8_VCS1_IRQ_SHIFT);
-		gen8_cs_irq_handler(dev_priv->engine[VCS2],
+		gen8_cs_irq_handler(i915->engine[VCS2],
 				    gt_iir[1], GEN8_VCS2_IRQ_SHIFT);
 	}
 
-	if (gt_iir[3])
-		gen8_cs_irq_handler(dev_priv->engine[VECS],
+	if (master_ctl & GEN8_GT_VECS_IRQ) {
+		gen8_cs_irq_handler(i915->engine[VECS],
 				    gt_iir[3], GEN8_VECS_IRQ_SHIFT);
+	}
 
-	if (gt_iir[2] & dev_priv->pm_rps_events)
-		gen6_rps_irq_handler(dev_priv, gt_iir[2]);
-
-	if (gt_iir[2] & dev_priv->pm_guc_events)
-		gen9_guc_irq_handler(dev_priv, gt_iir[2]);
+	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
+		gen6_rps_irq_handler(i915, gt_iir[2]);
+		gen9_guc_irq_handler(i915, gt_iir[2]);
+	}
 }
 
 static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
@@ -1568,10 +1567,11 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val)
  *
  * Note that the caller is expected to zero out the masks initially.
  */
-static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
-			     u32 hotplug_trigger, u32 dig_hotplug_reg,
-			     const u32 hpd[HPD_NUM_PINS],
-			     bool long_pulse_detect(enum port port, u32 val))
+static void intel_get_hpd_pins(struct drm_i915_private *dev_priv,
+			       u32 *pin_mask, u32 *long_mask,
+			       u32 hotplug_trigger, u32 dig_hotplug_reg,
+			       const u32 hpd[HPD_NUM_PINS],
+			       bool long_pulse_detect(enum port port, u32 val))
 {
 	enum port port;
 	int i;
@@ -1582,7 +1582,7 @@ static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
 
 		*pin_mask |= BIT(i);
 
-		port = intel_hpd_pin_to_port(i);
+		port = intel_hpd_pin_to_port(dev_priv, i);
 		if (port == PORT_NONE)
 			continue;
 
@@ -1970,8 +1970,9 @@ static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
 		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
 
 		if (hotplug_trigger) {
-			intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
-					   hotplug_trigger, hpd_status_g4x,
+			intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
+					   hotplug_trigger, hotplug_trigger,
+					   hpd_status_g4x,
 					   i9xx_port_hotplug_long_detect);
 
 			intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
@@ -1983,8 +1984,9 @@ static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
 		u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
 		if (hotplug_trigger) {
-			intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
-					   hotplug_trigger, hpd_status_i915,
+			intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
+					   hotplug_trigger, hotplug_trigger,
+					   hpd_status_i915,
 					   i9xx_port_hotplug_long_detect);
 			intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 		}
@@ -2092,9 +2094,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 
 	do {
 		u32 master_ctl, iir;
-		u32 gt_iir[4] = {};
 		u32 pipe_stats[I915_MAX_PIPES] = {};
 		u32 hotplug_status = 0;
+		u32 gt_iir[4];
 		u32 ier = 0;
 
 		master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
@@ -2147,7 +2149,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 		I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
 		POSTING_READ(GEN8_MASTER_IRQ);
 
-		gen8_gt_irq_handler(dev_priv, gt_iir);
+		gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
 
 		if (hotplug_status)
 			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
@@ -2185,7 +2187,7 @@ static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	if (!hotplug_trigger)
 		return;
 
-	intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger,
 			   dig_hotplug_reg, hpd,
 			   pch_port_hotplug_long_detect);
 
@@ -2327,8 +2329,8 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
 		I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
 
-		intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
-				   dig_hotplug_reg, hpd_spt,
+		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
+				   hotplug_trigger, dig_hotplug_reg, hpd_spt,
 				   spt_port_hotplug_long_detect);
 	}
 
@@ -2338,8 +2340,8 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
 		I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg);
 
-		intel_get_hpd_pins(&pin_mask, &long_mask, hotplug2_trigger,
-				   dig_hotplug_reg, hpd_spt,
+		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
+				   hotplug2_trigger, dig_hotplug_reg, hpd_spt,
 				   spt_port_hotplug2_long_detect);
 	}
 
@@ -2359,7 +2361,7 @@ static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
 	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg);
 
-	intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger,
 			   dig_hotplug_reg, hpd,
 			   ilk_port_hotplug_long_detect);
 
@@ -2536,7 +2538,7 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
 	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
 	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
 
-	intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger,
 			   dig_hotplug_reg, hpd,
 			   bxt_port_hotplug_long_detect);
 
@@ -2579,6 +2581,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 					    GEN9_AUX_CHANNEL_C |
 					    GEN9_AUX_CHANNEL_D;
 
+			if (IS_CNL_WITH_PORT_F(dev_priv))
+				tmp_mask |= CNL_AUX_CHANNEL_F;
+
 			if (iir & tmp_mask) {
 				dp_aux_irq_handler(dev_priv);
 				found = true;
@@ -2679,11 +2684,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 
 static irqreturn_t gen8_irq_handler(int irq, void *arg)
 {
-	struct drm_device *dev = arg;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(arg);
 	u32 master_ctl;
-	u32 gt_iir[4] = {};
-	irqreturn_t ret;
+	u32 gt_iir[4];
 
 	if (!intel_irqs_enabled(dev_priv))
 		return IRQ_NONE;
@@ -2695,20 +2698,21 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 
 	I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
 
-	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
-	disable_rpm_wakeref_asserts(dev_priv);
-
 	/* Find, clear, then process each source of interrupt */
-	ret = gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
-	gen8_gt_irq_handler(dev_priv, gt_iir);
-	ret |= gen8_de_irq_handler(dev_priv, master_ctl);
+	gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
+
+	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
+	if (master_ctl & ~GEN8_GT_IRQS) {
+		disable_rpm_wakeref_asserts(dev_priv);
+		gen8_de_irq_handler(dev_priv, master_ctl);
+		enable_rpm_wakeref_asserts(dev_priv);
+	}
 
 	I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
-	POSTING_READ_FW(GEN8_MASTER_IRQ);
 
-	enable_rpm_wakeref_asserts(dev_priv);
+	gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
 
-	return ret;
+	return IRQ_HANDLED;
 }
 
 struct wedge_me {
@@ -2956,6 +2960,12 @@ static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
 	ilk_enable_display_irq(dev_priv, bit);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
+	/* Even though there is no DMC, frame counter can get stuck when
+	 * PSR is active as no frames are generated.
+	 */
+	if (HAS_PSR(dev_priv))
+		drm_vblank_restore(dev, pipe);
+
 	return 0;
 }
 
@@ -2968,6 +2978,12 @@ static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
 	bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
+	/* Even if there is no DMC, frame counter can get stuck when
+	 * PSR is active as no frames are generated, so check only for PSR.
+	 */
+	if (HAS_PSR(dev_priv))
+		drm_vblank_restore(dev, pipe);
+
 	return 0;
 }
 
@@ -3611,6 +3627,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
 		de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
 	}
 
+	if (IS_CNL_WITH_PORT_F(dev_priv))
+		de_port_masked |= CNL_AUX_CHANNEL_F;
+
 	de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
 					   GEN8_PIPE_FIFO_UNDERRUN;
 
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index b5f3eb4fa8a3..08108ce5be21 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -155,7 +155,8 @@ i915_param_named_unsafe(enable_guc, int, 0400,
 	"(-1=auto, 0=disable [default], 1=GuC submission, 2=HuC load)");
 
 i915_param_named(guc_log_level, int, 0400,
-	"GuC firmware logging level (-1:disabled (default), 0-3:enabled)");
+	"GuC firmware logging level. Requires GuC to be loaded. "
+	"(-1=auto [default], 0=disable, 1..4=enable with verbosity min..max)");
 
 i915_param_named_unsafe(guc_firmware_path, charp, 0400,
 	"GuC firmware path to use instead of the default one");
@@ -166,8 +167,10 @@ i915_param_named_unsafe(huc_firmware_path, charp, 0400,
 i915_param_named_unsafe(enable_dp_mst, bool, 0600,
 	"Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)");
 
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
 i915_param_named_unsafe(inject_load_failure, uint, 0400,
 	"Force an error after a number of failure check points (0:disabled (default), N:force failure at the Nth failure check point)");
+#endif
 
 i915_param_named(enable_dpcd_backlight, bool, 0600,
 	"Enable support for DPCD backlight control (default:false)");
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index c96360398072..430f5f9d0ff4 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -48,7 +48,7 @@ struct drm_printer;
 	param(int, enable_ips, 1) \
 	param(int, invert_brightness, 0) \
 	param(int, enable_guc, 0) \
-	param(int, guc_log_level, -1) \
+	param(int, guc_log_level, 0) \
 	param(char *, guc_firmware_path, NULL) \
 	param(char *, huc_firmware_path, NULL) \
 	param(int, mmio_debug, 0) \
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index 1c30c688f23a..1eaabf28d7b7 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -29,6 +29,9 @@
 #include "i915_drv.h"
 #include "i915_selftest.h"
 
+#define PLATFORM(x) .platform = (x), .platform_mask = BIT(x)
+#define GEN(x) .gen = (x), .gen_mask = BIT((x) - 1)
+
 #define GEN_DEFAULT_PIPEOFFSETS \
 	.pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
 			  PIPE_C_OFFSET, PIPE_EDP_OFFSET }, \
@@ -63,7 +66,8 @@
 	.page_sizes = I915_GTT_PAGE_SIZE_4K
 
 #define GEN2_FEATURES \
-	.gen = 2, .num_pipes = 1, \
+	GEN(2), \
+	.num_pipes = 1, \
 	.has_overlay = 1, .overlay_needs_physical = 1, \
 	.has_gmch_display = 1, \
 	.hws_needs_physical = 1, \
@@ -76,19 +80,20 @@
 
 static const struct intel_device_info intel_i830_info = {
 	GEN2_FEATURES,
-	.platform = INTEL_I830,
+	PLATFORM(INTEL_I830),
 	.is_mobile = 1, .cursor_needs_physical = 1,
 	.num_pipes = 2, /* legal, last one wins */
 };
 
 static const struct intel_device_info intel_i845g_info = {
 	GEN2_FEATURES,
-	.platform = INTEL_I845G,
+	PLATFORM(INTEL_I845G),
 };
 
 static const struct intel_device_info intel_i85x_info = {
 	GEN2_FEATURES,
-	.platform = INTEL_I85X, .is_mobile = 1,
+	PLATFORM(INTEL_I85X),
+	.is_mobile = 1,
 	.num_pipes = 2, /* legal, last one wins */
 	.cursor_needs_physical = 1,
 	.has_fbc = 1,
@@ -96,11 +101,12 @@ static const struct intel_device_info intel_i85x_info = {
 
 static const struct intel_device_info intel_i865g_info = {
 	GEN2_FEATURES,
-	.platform = INTEL_I865G,
+	PLATFORM(INTEL_I865G),
 };
 
 #define GEN3_FEATURES \
-	.gen = 3, .num_pipes = 2, \
+	GEN(3), \
+	.num_pipes = 2, \
 	.has_gmch_display = 1, \
 	.ring_mask = RENDER_RING, \
 	.has_snoop = true, \
@@ -110,7 +116,8 @@ static const struct intel_device_info intel_i865g_info = {
 
 static const struct intel_device_info intel_i915g_info = {
 	GEN3_FEATURES,
-	.platform = INTEL_I915G, .cursor_needs_physical = 1,
+	PLATFORM(INTEL_I915G),
+	.cursor_needs_physical = 1,
 	.has_overlay = 1, .overlay_needs_physical = 1,
 	.hws_needs_physical = 1,
 	.unfenced_needs_alignment = 1,
@@ -118,7 +125,7 @@ static const struct intel_device_info intel_i915g_info = {
 
 static const struct intel_device_info intel_i915gm_info = {
 	GEN3_FEATURES,
-	.platform = INTEL_I915GM,
+	PLATFORM(INTEL_I915GM),
 	.is_mobile = 1,
 	.cursor_needs_physical = 1,
 	.has_overlay = 1, .overlay_needs_physical = 1,
@@ -130,7 +137,7 @@ static const struct intel_device_info intel_i915gm_info = {
 
 static const struct intel_device_info intel_i945g_info = {
 	GEN3_FEATURES,
-	.platform = INTEL_I945G,
+	PLATFORM(INTEL_I945G),
 	.has_hotplug = 1, .cursor_needs_physical = 1,
 	.has_overlay = 1, .overlay_needs_physical = 1,
 	.hws_needs_physical = 1,
@@ -139,7 +146,8 @@ static const struct intel_device_info intel_i945g_info = {
 
 static const struct intel_device_info intel_i945gm_info = {
 	GEN3_FEATURES,
-	.platform = INTEL_I945GM, .is_mobile = 1,
+	PLATFORM(INTEL_I945GM),
+	.is_mobile = 1,
 	.has_hotplug = 1, .cursor_needs_physical = 1,
 	.has_overlay = 1, .overlay_needs_physical = 1,
 	.supports_tv = 1,
@@ -150,20 +158,22 @@ static const struct intel_device_info intel_i945gm_info = {
 
 static const struct intel_device_info intel_g33_info = {
 	GEN3_FEATURES,
-	.platform = INTEL_G33,
+	PLATFORM(INTEL_G33),
 	.has_hotplug = 1,
 	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_pineview_info = {
 	GEN3_FEATURES,
-	.platform = INTEL_PINEVIEW, .is_mobile = 1,
+	PLATFORM(INTEL_PINEVIEW),
+	.is_mobile = 1,
 	.has_hotplug = 1,
 	.has_overlay = 1,
 };
 
 #define GEN4_FEATURES \
-	.gen = 4, .num_pipes = 2, \
+	GEN(4), \
+	.num_pipes = 2, \
 	.has_hotplug = 1, \
 	.has_gmch_display = 1, \
 	.ring_mask = RENDER_RING, \
@@ -174,7 +184,7 @@ static const struct intel_device_info intel_pineview_info = {
 
 static const struct intel_device_info intel_i965g_info = {
 	GEN4_FEATURES,
-	.platform = INTEL_I965G,
+	PLATFORM(INTEL_I965G),
 	.has_overlay = 1,
 	.hws_needs_physical = 1,
 	.has_snoop = false,
@@ -182,7 +192,7 @@ static const struct intel_device_info intel_i965g_info = {
 
 static const struct intel_device_info intel_i965gm_info = {
 	GEN4_FEATURES,
-	.platform = INTEL_I965GM,
+	PLATFORM(INTEL_I965GM),
 	.is_mobile = 1, .has_fbc = 1,
 	.has_overlay = 1,
 	.supports_tv = 1,
@@ -192,20 +202,21 @@ static const struct intel_device_info intel_i965gm_info = {
 
 static const struct intel_device_info intel_g45_info = {
 	GEN4_FEATURES,
-	.platform = INTEL_G45,
+	PLATFORM(INTEL_G45),
 	.ring_mask = RENDER_RING | BSD_RING,
 };
 
 static const struct intel_device_info intel_gm45_info = {
 	GEN4_FEATURES,
-	.platform = INTEL_GM45,
+	PLATFORM(INTEL_GM45),
 	.is_mobile = 1, .has_fbc = 1,
 	.supports_tv = 1,
 	.ring_mask = RENDER_RING | BSD_RING,
 };
 
 #define GEN5_FEATURES \
-	.gen = 5, .num_pipes = 2, \
+	GEN(5), \
+	.num_pipes = 2, \
 	.has_hotplug = 1, \
 	.ring_mask = RENDER_RING | BSD_RING, \
 	.has_snoop = true, \
@@ -217,17 +228,18 @@ static const struct intel_device_info intel_gm45_info = {
 
 static const struct intel_device_info intel_ironlake_d_info = {
 	GEN5_FEATURES,
-	.platform = INTEL_IRONLAKE,
+	PLATFORM(INTEL_IRONLAKE),
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
 	GEN5_FEATURES,
-	.platform = INTEL_IRONLAKE,
+	PLATFORM(INTEL_IRONLAKE),
 	.is_mobile = 1, .has_fbc = 1,
 };
 
 #define GEN6_FEATURES \
-	.gen = 6, .num_pipes = 2, \
+	GEN(6), \
+	.num_pipes = 2, \
 	.has_hotplug = 1, \
 	.has_fbc = 1, \
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
@@ -241,7 +253,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
 
 #define SNB_D_PLATFORM \
 	GEN6_FEATURES, \
-	.platform = INTEL_SANDYBRIDGE
+	PLATFORM(INTEL_SANDYBRIDGE)
 
 static const struct intel_device_info intel_sandybridge_d_gt1_info = {
 	SNB_D_PLATFORM,
@@ -255,7 +267,7 @@ static const struct intel_device_info intel_sandybridge_d_gt2_info = {
 
 #define SNB_M_PLATFORM \
 	GEN6_FEATURES, \
-	.platform = INTEL_SANDYBRIDGE, \
+	PLATFORM(INTEL_SANDYBRIDGE), \
 	.is_mobile = 1
 
 
@@ -270,7 +282,8 @@ static const struct intel_device_info intel_sandybridge_m_gt2_info = {
 };
 
 #define GEN7_FEATURES  \
-	.gen = 7, .num_pipes = 3, \
+	GEN(7), \
+	.num_pipes = 3, \
 	.has_hotplug = 1, \
 	.has_fbc = 1, \
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
@@ -285,7 +298,7 @@ static const struct intel_device_info intel_sandybridge_m_gt2_info = {
 
 #define IVB_D_PLATFORM \
 	GEN7_FEATURES, \
-	.platform = INTEL_IVYBRIDGE, \
+	PLATFORM(INTEL_IVYBRIDGE), \
 	.has_l3_dpf = 1
 
 static const struct intel_device_info intel_ivybridge_d_gt1_info = {
@@ -300,7 +313,7 @@ static const struct intel_device_info intel_ivybridge_d_gt2_info = {
 
 #define IVB_M_PLATFORM \
 	GEN7_FEATURES, \
-	.platform = INTEL_IVYBRIDGE, \
+	PLATFORM(INTEL_IVYBRIDGE), \
 	.is_mobile = 1, \
 	.has_l3_dpf = 1
 
@@ -316,15 +329,15 @@ static const struct intel_device_info intel_ivybridge_m_gt2_info = {
 
 static const struct intel_device_info intel_ivybridge_q_info = {
 	GEN7_FEATURES,
-	.platform = INTEL_IVYBRIDGE,
+	PLATFORM(INTEL_IVYBRIDGE),
 	.gt = 2,
 	.num_pipes = 0, /* legal, last one wins */
 	.has_l3_dpf = 1,
 };
 
 static const struct intel_device_info intel_valleyview_info = {
-	.platform = INTEL_VALLEYVIEW,
-	.gen = 7,
+	PLATFORM(INTEL_VALLEYVIEW),
+	GEN(7),
 	.is_lp = 1,
 	.num_pipes = 2,
 	.has_psr = 1,
@@ -355,7 +368,7 @@ static const struct intel_device_info intel_valleyview_info = {
 
 #define HSW_PLATFORM \
 	G75_FEATURES, \
-	.platform = INTEL_HASWELL, \
+	PLATFORM(INTEL_HASWELL), \
 	.has_l3_dpf = 1
 
 static const struct intel_device_info intel_haswell_gt1_info = {
@@ -375,6 +388,7 @@ static const struct intel_device_info intel_haswell_gt3_info = {
 
 #define GEN8_FEATURES \
 	G75_FEATURES, \
+	GEN(8), \
 	BDW_COLORS, \
 	.page_sizes = I915_GTT_PAGE_SIZE_4K | \
 		      I915_GTT_PAGE_SIZE_2M, \
@@ -385,8 +399,7 @@ static const struct intel_device_info intel_haswell_gt3_info = {
 
 #define BDW_PLATFORM \
 	GEN8_FEATURES, \
-	.gen = 8, \
-	.platform = INTEL_BROADWELL
+	PLATFORM(INTEL_BROADWELL)
 
 static const struct intel_device_info intel_broadwell_gt1_info = {
 	BDW_PLATFORM,
@@ -413,11 +426,12 @@ static const struct intel_device_info intel_broadwell_gt3_info = {
 };
 
 static const struct intel_device_info intel_cherryview_info = {
-	.gen = 8, .num_pipes = 3,
+	PLATFORM(INTEL_CHERRYVIEW),
+	GEN(8),
+	.num_pipes = 3,
 	.has_hotplug = 1,
 	.is_lp = 1,
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
-	.platform = INTEL_CHERRYVIEW,
 	.has_64bit_reloc = 1,
 	.has_psr = 1,
 	.has_runtime_pm = 1,
@@ -443,6 +457,7 @@ static const struct intel_device_info intel_cherryview_info = {
 
 #define GEN9_FEATURES \
 	GEN8_FEATURES, \
+	GEN(9), \
 	GEN9_DEFAULT_PAGE_SIZES, \
 	.has_logical_ring_preemption = 1, \
 	.has_csr = 1, \
@@ -452,8 +467,7 @@ static const struct intel_device_info intel_cherryview_info = {
 
 #define SKL_PLATFORM \
 	GEN9_FEATURES, \
-	.gen = 9, \
-	.platform = INTEL_SKYLAKE
+	PLATFORM(INTEL_SKYLAKE)
 
 static const struct intel_device_info intel_skylake_gt1_info = {
 	SKL_PLATFORM,
@@ -481,7 +495,7 @@ static const struct intel_device_info intel_skylake_gt4_info = {
 };
 
 #define GEN9_LP_FEATURES \
-	.gen = 9, \
+	GEN(9), \
 	.is_lp = 1, \
 	.has_hotplug = 1, \
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, \
@@ -513,21 +527,20 @@ static const struct intel_device_info intel_skylake_gt4_info = {
 
 static const struct intel_device_info intel_broxton_info = {
 	GEN9_LP_FEATURES,
-	.platform = INTEL_BROXTON,
+	PLATFORM(INTEL_BROXTON),
 	.ddb_size = 512,
 };
 
 static const struct intel_device_info intel_geminilake_info = {
 	GEN9_LP_FEATURES,
-	.platform = INTEL_GEMINILAKE,
+	PLATFORM(INTEL_GEMINILAKE),
 	.ddb_size = 1024,
 	GLK_COLORS,
 };
 
 #define KBL_PLATFORM \
 	GEN9_FEATURES, \
-	.gen = 9, \
-	.platform = INTEL_KABYLAKE
+	PLATFORM(INTEL_KABYLAKE)
 
 static const struct intel_device_info intel_kabylake_gt1_info = {
 	KBL_PLATFORM,
@@ -547,8 +560,7 @@ static const struct intel_device_info intel_kabylake_gt3_info = {
 
 #define CFL_PLATFORM \
 	GEN9_FEATURES, \
-	.gen = 9, \
-	.platform = INTEL_COFFEELAKE
+	PLATFORM(INTEL_COFFEELAKE)
 
 static const struct intel_device_info intel_coffeelake_gt1_info = {
 	CFL_PLATFORM,
@@ -568,17 +580,32 @@ static const struct intel_device_info intel_coffeelake_gt3_info = {
 
 #define GEN10_FEATURES \
 	GEN9_FEATURES, \
+	GEN(10), \
 	.ddb_size = 1024, \
 	GLK_COLORS
 
-static const struct intel_device_info intel_cannonlake_gt2_info = {
+static const struct intel_device_info intel_cannonlake_info = {
 	GEN10_FEATURES,
-	.is_alpha_support = 1,
-	.platform = INTEL_CANNONLAKE,
-	.gen = 10,
+	PLATFORM(INTEL_CANNONLAKE),
 	.gt = 2,
 };
 
+#define GEN11_FEATURES \
+	GEN10_FEATURES, \
+	GEN(11), \
+	.ddb_size = 2048, \
+	.has_csr = 0
+
+static const struct intel_device_info intel_icelake_11_info = {
+	GEN11_FEATURES,
+	PLATFORM(INTEL_ICELAKE),
+	.is_alpha_support = 1,
+	.has_resource_streamer = 0,
+};
+
+#undef GEN
+#undef PLATFORM
+
 /*
  * Make sure any device matches here are from most specific to most
  * general.  For example, since the Quanta match is based on the subsystem
@@ -636,8 +663,7 @@ static const struct pci_device_id pciidlist[] = {
 	INTEL_CFL_U_GT1_IDS(&intel_coffeelake_gt1_info),
 	INTEL_CFL_U_GT2_IDS(&intel_coffeelake_gt2_info),
 	INTEL_CFL_U_GT3_IDS(&intel_coffeelake_gt3_info),
-	INTEL_CNL_U_GT2_IDS(&intel_cannonlake_gt2_info),
-	INTEL_CNL_Y_GT2_IDS(&intel_cannonlake_gt2_info),
+	INTEL_CNL_IDS(&intel_cannonlake_info),
 	{0, 0, 0}
 };
 MODULE_DEVICE_TABLE(pci, pciidlist);
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 0e9b98c32b62..964467b03e4d 100644
--- a/drivers/gpu/drm/i915/i915_pmu.c
+++ b/drivers/gpu/drm/i915/i915_pmu.c
@@ -329,6 +329,32 @@ engine_event_status(struct intel_engine_cs *engine,
 	return 0;
 }
 
+static int
+config_status(struct drm_i915_private *i915, u64 config)
+{
+	switch (config) {
+	case I915_PMU_ACTUAL_FREQUENCY:
+		if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+			/* Requires a mutex for sampling! */
+			return -ENODEV;
+		/* Fall-through. */
+	case I915_PMU_REQUESTED_FREQUENCY:
+		if (INTEL_GEN(i915) < 6)
+			return -ENODEV;
+		break;
+	case I915_PMU_INTERRUPTS:
+		break;
+	case I915_PMU_RC6_RESIDENCY:
+		if (!HAS_RC6(i915))
+			return -ENODEV;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
 static int engine_event_init(struct perf_event *event)
 {
 	struct drm_i915_private *i915 =
@@ -376,30 +402,10 @@ static int i915_pmu_event_init(struct perf_event *event)
 	if (!cpumask_test_cpu(event->cpu, &i915_pmu_cpumask))
 		return -EINVAL;
 
-	if (is_engine_event(event)) {
+	if (is_engine_event(event))
 		ret = engine_event_init(event);
-	} else {
-		ret = 0;
-		switch (event->attr.config) {
-		case I915_PMU_ACTUAL_FREQUENCY:
-			if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
-				 /* Requires a mutex for sampling! */
-				ret = -ENODEV;
-		case I915_PMU_REQUESTED_FREQUENCY:
-			if (INTEL_GEN(i915) < 6)
-				ret = -ENODEV;
-			break;
-		case I915_PMU_INTERRUPTS:
-			break;
-		case I915_PMU_RC6_RESIDENCY:
-			if (!HAS_RC6(i915))
-				ret = -ENODEV;
-			break;
-		default:
-			ret = -ENOENT;
-			break;
-		}
-	}
+	else
+		ret = config_status(i915, event->attr.config);
 	if (ret)
 		return ret;
 
@@ -726,52 +732,9 @@ static ssize_t i915_pmu_event_show(struct device *dev,
 	return sprintf(buf, "config=0x%lx\n", eattr->val);
 }
 
-#define I915_EVENT_ATTR(_name, _config) \
-	(&((struct i915_ext_attribute[]) { \
-		{ .attr = __ATTR(_name, 0444, i915_pmu_event_show, NULL), \
-		  .val = _config, } \
-	})[0].attr.attr)
-
-#define I915_EVENT_STR(_name, _str) \
-	(&((struct perf_pmu_events_attr[]) { \
-		{ .attr	     = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \
-		  .id	     = 0, \
-		  .event_str = _str, } \
-	})[0].attr.attr)
-
-#define I915_EVENT(_name, _config, _unit) \
-	I915_EVENT_ATTR(_name, _config), \
-	I915_EVENT_STR(_name.unit, _unit)
-
-#define I915_ENGINE_EVENT(_name, _class, _instance, _sample) \
-	I915_EVENT_ATTR(_name, __I915_PMU_ENGINE(_class, _instance, _sample)), \
-	I915_EVENT_STR(_name.unit, "ns")
-
-#define I915_ENGINE_EVENTS(_name, _class, _instance) \
-	I915_ENGINE_EVENT(_name##_instance-busy, _class, _instance, I915_SAMPLE_BUSY), \
-	I915_ENGINE_EVENT(_name##_instance-sema, _class, _instance, I915_SAMPLE_SEMA), \
-	I915_ENGINE_EVENT(_name##_instance-wait, _class, _instance, I915_SAMPLE_WAIT)
-
-static struct attribute *i915_pmu_events_attrs[] = {
-	I915_ENGINE_EVENTS(rcs, I915_ENGINE_CLASS_RENDER, 0),
-	I915_ENGINE_EVENTS(bcs, I915_ENGINE_CLASS_COPY, 0),
-	I915_ENGINE_EVENTS(vcs, I915_ENGINE_CLASS_VIDEO, 0),
-	I915_ENGINE_EVENTS(vcs, I915_ENGINE_CLASS_VIDEO, 1),
-	I915_ENGINE_EVENTS(vecs, I915_ENGINE_CLASS_VIDEO_ENHANCE, 0),
-
-	I915_EVENT(actual-frequency,    I915_PMU_ACTUAL_FREQUENCY,    "MHz"),
-	I915_EVENT(requested-frequency, I915_PMU_REQUESTED_FREQUENCY, "MHz"),
-
-	I915_EVENT_ATTR(interrupts, I915_PMU_INTERRUPTS),
-
-	I915_EVENT(rc6-residency,   I915_PMU_RC6_RESIDENCY,   "ns"),
-
-	NULL,
-};
-
-static const struct attribute_group i915_pmu_events_attr_group = {
+static struct attribute_group i915_pmu_events_attr_group = {
 	.name = "events",
-	.attrs = i915_pmu_events_attrs,
+	/* Patch in attrs at runtime. */
 };
 
 static ssize_t
@@ -789,7 +752,7 @@ static struct attribute *i915_cpumask_attrs[] = {
 	NULL,
 };
 
-static struct attribute_group i915_pmu_cpumask_attr_group = {
+static const struct attribute_group i915_pmu_cpumask_attr_group = {
 	.attrs = i915_cpumask_attrs,
 };
 
@@ -800,6 +763,193 @@ static const struct attribute_group *i915_pmu_attr_groups[] = {
 	NULL
 };
 
+#define __event(__config, __name, __unit) \
+{ \
+	.config = (__config), \
+	.name = (__name), \
+	.unit = (__unit), \
+}
+
+#define __engine_event(__sample, __name) \
+{ \
+	.sample = (__sample), \
+	.name = (__name), \
+}
+
+static struct i915_ext_attribute *
+add_i915_attr(struct i915_ext_attribute *attr, const char *name, u64 config)
+{
+	sysfs_attr_init(&attr->attr.attr);
+	attr->attr.attr.name = name;
+	attr->attr.attr.mode = 0444;
+	attr->attr.show = i915_pmu_event_show;
+	attr->val = config;
+
+	return ++attr;
+}
+
+static struct perf_pmu_events_attr *
+add_pmu_attr(struct perf_pmu_events_attr *attr, const char *name,
+	     const char *str)
+{
+	sysfs_attr_init(&attr->attr.attr);
+	attr->attr.attr.name = name;
+	attr->attr.attr.mode = 0444;
+	attr->attr.show = perf_event_sysfs_show;
+	attr->event_str = str;
+
+	return ++attr;
+}
+
+static struct attribute **
+create_event_attributes(struct drm_i915_private *i915)
+{
+	static const struct {
+		u64 config;
+		const char *name;
+		const char *unit;
+	} events[] = {
+		__event(I915_PMU_ACTUAL_FREQUENCY, "actual-frequency", "MHz"),
+		__event(I915_PMU_REQUESTED_FREQUENCY, "requested-frequency", "MHz"),
+		__event(I915_PMU_INTERRUPTS, "interrupts", NULL),
+		__event(I915_PMU_RC6_RESIDENCY, "rc6-residency", "ns"),
+	};
+	static const struct {
+		enum drm_i915_pmu_engine_sample sample;
+		char *name;
+	} engine_events[] = {
+		__engine_event(I915_SAMPLE_BUSY, "busy"),
+		__engine_event(I915_SAMPLE_SEMA, "sema"),
+		__engine_event(I915_SAMPLE_WAIT, "wait"),
+	};
+	unsigned int count = 0;
+	struct perf_pmu_events_attr *pmu_attr = NULL, *pmu_iter;
+	struct i915_ext_attribute *i915_attr = NULL, *i915_iter;
+	struct attribute **attr = NULL, **attr_iter;
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+	unsigned int i;
+
+	/* Count how many counters we will be exposing. */
+	for (i = 0; i < ARRAY_SIZE(events); i++) {
+		if (!config_status(i915, events[i].config))
+			count++;
+	}
+
+	for_each_engine(engine, i915, id) {
+		for (i = 0; i < ARRAY_SIZE(engine_events); i++) {
+			if (!engine_event_status(engine,
+						 engine_events[i].sample))
+				count++;
+		}
+	}
+
+	/* Allocate attribute objects and table. */
+	i915_attr = kcalloc(count, sizeof(*i915_attr), GFP_KERNEL);
+	if (!i915_attr)
+		goto err_alloc;
+
+	pmu_attr = kcalloc(count, sizeof(*pmu_attr), GFP_KERNEL);
+	if (!pmu_attr)
+		goto err_alloc;
+
+	/* Max one pointer of each attribute type plus a termination entry. */
+	attr = kcalloc(count * 2 + 1, sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		goto err_alloc;
+
+	i915_iter = i915_attr;
+	pmu_iter = pmu_attr;
+	attr_iter = attr;
+
+	/* Initialize supported non-engine counters. */
+	for (i = 0; i < ARRAY_SIZE(events); i++) {
+		char *str;
+
+		if (config_status(i915, events[i].config))
+			continue;
+
+		str = kstrdup(events[i].name, GFP_KERNEL);
+		if (!str)
+			goto err;
+
+		*attr_iter++ = &i915_iter->attr.attr;
+		i915_iter = add_i915_attr(i915_iter, str, events[i].config);
+
+		if (events[i].unit) {
+			str = kasprintf(GFP_KERNEL, "%s.unit", events[i].name);
+			if (!str)
+				goto err;
+
+			*attr_iter++ = &pmu_iter->attr.attr;
+			pmu_iter = add_pmu_attr(pmu_iter, str, events[i].unit);
+		}
+	}
+
+	/* Initialize supported engine counters. */
+	for_each_engine(engine, i915, id) {
+		for (i = 0; i < ARRAY_SIZE(engine_events); i++) {
+			char *str;
+
+			if (engine_event_status(engine,
+						engine_events[i].sample))
+				continue;
+
+			str = kasprintf(GFP_KERNEL, "%s-%s",
+					engine->name, engine_events[i].name);
+			if (!str)
+				goto err;
+
+			*attr_iter++ = &i915_iter->attr.attr;
+			i915_iter =
+				add_i915_attr(i915_iter, str,
+					      __I915_PMU_ENGINE(engine->uabi_class,
+								engine->instance,
+								engine_events[i].sample));
+
+			str = kasprintf(GFP_KERNEL, "%s-%s.unit",
+					engine->name, engine_events[i].name);
+			if (!str)
+				goto err;
+
+			*attr_iter++ = &pmu_iter->attr.attr;
+			pmu_iter = add_pmu_attr(pmu_iter, str, "ns");
+		}
+	}
+
+	i915->pmu.i915_attr = i915_attr;
+	i915->pmu.pmu_attr = pmu_attr;
+
+	return attr;
+
+err:;
+	for (attr_iter = attr; *attr_iter; attr_iter++)
+		kfree((*attr_iter)->name);
+
+err_alloc:
+	kfree(attr);
+	kfree(i915_attr);
+	kfree(pmu_attr);
+
+	return NULL;
+}
+
+static void free_event_attributes(struct drm_i915_private *i915)
+{
+	struct attribute **attr_iter = i915_pmu_events_attr_group.attrs;
+
+	for (; *attr_iter; attr_iter++)
+		kfree((*attr_iter)->name);
+
+	kfree(i915_pmu_events_attr_group.attrs);
+	kfree(i915->pmu.i915_attr);
+	kfree(i915->pmu.pmu_attr);
+
+	i915_pmu_events_attr_group.attrs = NULL;
+	i915->pmu.i915_attr = NULL;
+	i915->pmu.pmu_attr = NULL;
+}
+
 static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
 {
 	struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), node);
@@ -873,6 +1023,12 @@ void i915_pmu_register(struct drm_i915_private *i915)
 		return;
 	}
 
+	i915_pmu_events_attr_group.attrs = create_event_attributes(i915);
+	if (!i915_pmu_events_attr_group.attrs) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
 	i915->pmu.base.attr_groups	= i915_pmu_attr_groups;
 	i915->pmu.base.task_ctx_nr	= perf_invalid_context;
 	i915->pmu.base.event_init	= i915_pmu_event_init;
@@ -901,6 +1057,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
 	perf_pmu_unregister(&i915->pmu.base);
 err:
 	i915->pmu.base.event_init = NULL;
+	free_event_attributes(i915);
 	DRM_NOTE("Failed to register PMU! (err=%d)\n", ret);
 }
 
@@ -917,4 +1074,5 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
 
 	perf_pmu_unregister(&i915->pmu.base);
 	i915->pmu.base.event_init = NULL;
+	free_event_attributes(i915);
 }
diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h
index bb62df15afa4..aa1b1a987ea1 100644
--- a/drivers/gpu/drm/i915/i915_pmu.h
+++ b/drivers/gpu/drm/i915/i915_pmu.h
@@ -100,6 +100,14 @@ struct i915_pmu {
 	 * @suspended_jiffies_last: Cached suspend time from PM core.
 	 */
 	unsigned long suspended_jiffies_last;
+	/**
+	 * @i915_attr: Memory block holding device attributes.
+	 */
+	void *i915_attr;
+	/**
+	 * @pmu_attr: Memory block holding device attributes.
+	 */
+	void *pmu_attr;
 };
 
 #ifdef CONFIG_PERF_EVENTS
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index a2108e35c599..1412abcb27d4 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1304,6 +1304,7 @@ enum i915_power_well_id {
 	SKL_DISP_PW_DDI_B,
 	SKL_DISP_PW_DDI_C,
 	SKL_DISP_PW_DDI_D,
+	CNL_DISP_PW_DDI_F = 6,
 
 	GLK_DISP_PW_AUX_A = 8,
 	GLK_DISP_PW_AUX_B,
@@ -1312,6 +1313,7 @@ enum i915_power_well_id {
 	CNL_DISP_PW_AUX_B = GLK_DISP_PW_AUX_B,
 	CNL_DISP_PW_AUX_C = GLK_DISP_PW_AUX_C,
 	CNL_DISP_PW_AUX_D,
+	CNL_DISP_PW_AUX_F,
 
 	SKL_DISP_PW_1 = 14,
 	SKL_DISP_PW_2,
@@ -1904,6 +1906,11 @@ enum i915_power_well_id {
 #define   CL_POWER_DOWN_ENABLE		(1 << 4)
 #define   SUS_CLOCK_CONFIG		(3 << 0)
 
+#define _ICL_PORT_CL_DW5_A	0x162014
+#define _ICL_PORT_CL_DW5_B	0x6C014
+#define ICL_PORT_CL_DW5(port)	_MMIO_PORT(port, _ICL_PORT_CL_DW5_A, \
+						 _ICL_PORT_CL_DW5_B)
+
 #define _PORT_CL1CM_DW9_A		0x162024
 #define _PORT_CL1CM_DW9_BC		0x6C024
 #define   IREF0RC_OFFSET_SHIFT		8
@@ -1963,7 +1970,7 @@ enum i915_power_well_id {
 #define _CNL_PORT_TX_DW2_LN0_B		0x162648
 #define _CNL_PORT_TX_DW2_LN0_C		0x162C48
 #define _CNL_PORT_TX_DW2_LN0_D		0x162E48
-#define _CNL_PORT_TX_DW2_LN0_F		0x162A48
+#define _CNL_PORT_TX_DW2_LN0_F		0x162848
 #define CNL_PORT_TX_DW2_GRP(port)	_MMIO_PORT6(port, \
 						    _CNL_PORT_TX_DW2_GRP_AE, \
 						    _CNL_PORT_TX_DW2_GRP_B, \
@@ -2027,7 +2034,7 @@ enum i915_power_well_id {
 #define _CNL_PORT_TX_DW5_LN0_AE		0x162454
 #define _CNL_PORT_TX_DW5_LN0_B		0x162654
 #define _CNL_PORT_TX_DW5_LN0_C		0x162C54
-#define _CNL_PORT_TX_DW5_LN0_D		0x162ED4
+#define _CNL_PORT_TX_DW5_LN0_D		0x162E54
 #define _CNL_PORT_TX_DW5_LN0_F		0x162854
 #define CNL_PORT_TX_DW5_GRP(port)	_MMIO_PORT6(port, \
 						    _CNL_PORT_TX_DW5_GRP_AE, \
@@ -2058,7 +2065,7 @@ enum i915_power_well_id {
 #define _CNL_PORT_TX_DW7_LN0_AE		0x16245C
 #define _CNL_PORT_TX_DW7_LN0_B		0x16265C
 #define _CNL_PORT_TX_DW7_LN0_C		0x162C5C
-#define _CNL_PORT_TX_DW7_LN0_D		0x162EDC
+#define _CNL_PORT_TX_DW7_LN0_D		0x162E5C
 #define _CNL_PORT_TX_DW7_LN0_F		0x16285C
 #define CNL_PORT_TX_DW7_GRP(port)	_MMIO_PORT6(port, \
 						    _CNL_PORT_TX_DW7_GRP_AE, \
@@ -2102,6 +2109,28 @@ enum i915_power_well_id {
 #define CNL_PORT_COMP_DW9		_MMIO(0x162124)
 #define CNL_PORT_COMP_DW10		_MMIO(0x162128)
 
+#define _ICL_PORT_COMP_DW0_A		0x162100
+#define _ICL_PORT_COMP_DW0_B		0x6C100
+#define ICL_PORT_COMP_DW0(port)		_MMIO_PORT(port, _ICL_PORT_COMP_DW0_A, \
+							 _ICL_PORT_COMP_DW0_B)
+#define _ICL_PORT_COMP_DW1_A		0x162104
+#define _ICL_PORT_COMP_DW1_B		0x6C104
+#define ICL_PORT_COMP_DW1(port)		_MMIO_PORT(port, _ICL_PORT_COMP_DW1_A, \
+							 _ICL_PORT_COMP_DW1_B)
+#define _ICL_PORT_COMP_DW3_A		0x16210C
+#define _ICL_PORT_COMP_DW3_B		0x6C10C
+#define ICL_PORT_COMP_DW3(port)		_MMIO_PORT(port, _ICL_PORT_COMP_DW3_A, \
+							 _ICL_PORT_COMP_DW3_B)
+#define _ICL_PORT_COMP_DW9_A		0x162124
+#define _ICL_PORT_COMP_DW9_B		0x6C124
+#define ICL_PORT_COMP_DW9(port)		_MMIO_PORT(port, _ICL_PORT_COMP_DW9_A, \
+							 _ICL_PORT_COMP_DW9_B)
+#define _ICL_PORT_COMP_DW10_A		0x162128
+#define _ICL_PORT_COMP_DW10_B		0x6C128
+#define ICL_PORT_COMP_DW10(port)	_MMIO_PORT(port, \
+						   _ICL_PORT_COMP_DW10_A, \
+						   _ICL_PORT_COMP_DW10_B)
+
 /* BXT PHY Ref registers */
 #define _PORT_REF_DW3_A			0x16218C
 #define _PORT_REF_DW3_BC		0x6C18C
@@ -2590,6 +2619,8 @@ enum i915_power_well_id {
 #define   GFX_FORWARD_VBLANK_ALWAYS	(1<<5)
 #define   GFX_FORWARD_VBLANK_COND	(2<<5)
 
+#define   GEN11_GFX_DISABLE_LEGACY_MODE	(1<<3)
+
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 #define BXT_MIPI_BASE 0x60000
@@ -2648,6 +2679,31 @@ enum i915_power_well_id {
 #define LM_FIFO_WATERMARK   0x0000001F
 #define MI_ARB_STATE	_MMIO(0x20e4) /* 915+ only */
 
+#define MBUS_ABOX_CTL			_MMIO(0x45038)
+#define MBUS_ABOX_BW_CREDIT_MASK	(3 << 20)
+#define MBUS_ABOX_BW_CREDIT(x)		((x) << 20)
+#define MBUS_ABOX_B_CREDIT_MASK		(0xF << 16)
+#define MBUS_ABOX_B_CREDIT(x)		((x) << 16)
+#define MBUS_ABOX_BT_CREDIT_POOL2_MASK	(0x1F << 8)
+#define MBUS_ABOX_BT_CREDIT_POOL2(x)	((x) << 8)
+#define MBUS_ABOX_BT_CREDIT_POOL1_MASK	(0x1F << 0)
+#define MBUS_ABOX_BT_CREDIT_POOL1(x)	((x) << 0)
+
+#define _PIPEA_MBUS_DBOX_CTL		0x7003C
+#define _PIPEB_MBUS_DBOX_CTL		0x7103C
+#define PIPE_MBUS_DBOX_CTL(pipe)	_MMIO_PIPE(pipe, _PIPEA_MBUS_DBOX_CTL, \
+						   _PIPEB_MBUS_DBOX_CTL)
+#define MBUS_DBOX_BW_CREDIT_MASK	(3 << 14)
+#define MBUS_DBOX_BW_CREDIT(x)		((x) << 14)
+#define MBUS_DBOX_B_CREDIT_MASK		(0x1F << 8)
+#define MBUS_DBOX_B_CREDIT(x)		((x) << 8)
+#define MBUS_DBOX_A_CREDIT_MASK		(0xF << 0)
+#define MBUS_DBOX_A_CREDIT(x)		((x) << 0)
+
+#define MBUS_UBOX_CTL			_MMIO(0x4503C)
+#define MBUS_BBOX_CTL_S1		_MMIO(0x45040)
+#define MBUS_BBOX_CTL_S2		_MMIO(0x45044)
+
 /* Make render/texture TLB fetches lower priorty than associated data
  *   fetches. This is not turned on by default
  */
@@ -3045,6 +3101,7 @@ enum i915_power_well_id {
 # define GPIO_DATA_PULLUP_DISABLE	(1 << 13)
 
 #define GMBUS0			_MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
+#define   GMBUS_AKSV_SELECT	(1<<11)
 #define   GMBUS_RATE_100KHZ	(0<<8)
 #define   GMBUS_RATE_50KHZ	(1<<8)
 #define   GMBUS_RATE_400KHZ	(2<<8) /* reserved on Pineview */
@@ -3063,7 +3120,12 @@ enum i915_power_well_id {
 #define   GMBUS_PIN_2_BXT	2
 #define   GMBUS_PIN_3_BXT	3
 #define   GMBUS_PIN_4_CNP	4
-#define   GMBUS_NUM_PINS	7 /* including 0 */
+#define   GMBUS_PIN_9_TC1_ICP	9
+#define   GMBUS_PIN_10_TC2_ICP	10
+#define   GMBUS_PIN_11_TC3_ICP	11
+#define   GMBUS_PIN_12_TC4_ICP	12
+
+#define   GMBUS_NUM_PINS	13 /* including 0 */
 #define GMBUS1			_MMIO(dev_priv->gpio_mmio_base + 0x5104) /* command/status */
 #define   GMBUS_SW_CLR_INT	(1<<31)
 #define   GMBUS_SW_RDY		(1<<30)
@@ -4066,7 +4128,7 @@ enum {
 #define EDP_PSR_AUX_CTL				_MMIO(dev_priv->psr_mmio_base + 0x10)
 #define EDP_PSR_AUX_DATA(i)			_MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */
 
-#define EDP_PSR_STATUS_CTL			_MMIO(dev_priv->psr_mmio_base + 0x40)
+#define EDP_PSR_STATUS				_MMIO(dev_priv->psr_mmio_base + 0x40)
 #define   EDP_PSR_STATUS_STATE_MASK		(7<<29)
 #define   EDP_PSR_STATUS_STATE_IDLE		(0<<29)
 #define   EDP_PSR_STATUS_STATE_SRDONACK		(1<<29)
@@ -4093,7 +4155,7 @@ enum {
 #define EDP_PSR_PERF_CNT		_MMIO(dev_priv->psr_mmio_base + 0x44)
 #define   EDP_PSR_PERF_CNT_MASK		0xffffff
 
-#define EDP_PSR_DEBUG_CTL		_MMIO(dev_priv->psr_mmio_base + 0x60)
+#define EDP_PSR_DEBUG				_MMIO(dev_priv->psr_mmio_base + 0x60)
 #define   EDP_PSR_DEBUG_MASK_MAX_SLEEP         (1<<28)
 #define   EDP_PSR_DEBUG_MASK_LPSP              (1<<27)
 #define   EDP_PSR_DEBUG_MASK_MEMUP             (1<<26)
@@ -4116,7 +4178,7 @@ enum {
 #define   EDP_PSR2_IDLE_MASK		0xf
 #define   EDP_PSR2_FRAME_BEFORE_SU(a)	((a)<<4)
 
-#define EDP_PSR2_STATUS_CTL            _MMIO(0x6f940)
+#define EDP_PSR2_STATUS			_MMIO(0x6f940)
 #define EDP_PSR2_STATUS_STATE_MASK     (0xf<<28)
 #define EDP_PSR2_STATUS_STATE_SHIFT    28
 
@@ -5278,6 +5340,13 @@ enum {
 #define _DPD_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64320)
 #define _DPD_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64324)
 
+#define _DPF_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64510)
+#define _DPF_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64514)
+#define _DPF_AUX_CH_DATA2	(dev_priv->info.display_mmio_offset + 0x64518)
+#define _DPF_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6451c)
+#define _DPF_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64520)
+#define _DPF_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64524)
+
 #define DP_AUX_CH_CTL(port)	_MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)
 #define DP_AUX_CH_DATA(port, i)	_MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
 
@@ -6310,6 +6379,11 @@ enum {
 #define _PLANE_CTL_3_A				0x70380
 #define   PLANE_CTL_ENABLE			(1 << 31)
 #define   PLANE_CTL_PIPE_GAMMA_ENABLE		(1 << 30)   /* Pre-GLK */
+/*
+ * ICL+ uses the same PLANE_CTL_FORMAT bits, but the field definition
+ * expanded to include bit 23 as well. However, the shift-24 based values
+ * correctly map to the same formats in ICL, as long as bit 23 is set to 0
+ */
 #define   PLANE_CTL_FORMAT_MASK			(0xf << 24)
 #define   PLANE_CTL_FORMAT_YUV422		(  0 << 24)
 #define   PLANE_CTL_FORMAT_NV12			(  1 << 24)
@@ -6319,6 +6393,7 @@ enum {
 #define   PLANE_CTL_FORMAT_AYUV			(  8 << 24)
 #define   PLANE_CTL_FORMAT_INDEXED		( 12 << 24)
 #define   PLANE_CTL_FORMAT_RGB_565		( 14 << 24)
+#define   ICL_PLANE_CTL_FORMAT_MASK		(0x1f << 23)
 #define   PLANE_CTL_PIPE_CSC_ENABLE		(1 << 23) /* Pre-GLK */
 #define   PLANE_CTL_KEY_ENABLE_MASK		(0x3 << 21)
 #define   PLANE_CTL_KEY_ENABLE_SOURCE		(  1 << 21)
@@ -6933,6 +7008,7 @@ enum {
 #define GEN8_DE_PORT_IMR _MMIO(0x44444)
 #define GEN8_DE_PORT_IIR _MMIO(0x44448)
 #define GEN8_DE_PORT_IER _MMIO(0x4444c)
+#define  CNL_AUX_CHANNEL_F		(1 << 28)
 #define  GEN9_AUX_CHANNEL_D		(1 << 27)
 #define  GEN9_AUX_CHANNEL_C		(1 << 26)
 #define  GEN9_AUX_CHANNEL_B		(1 << 25)
@@ -6957,6 +7033,69 @@ enum {
 #define GEN8_PCU_IIR _MMIO(0x444e8)
 #define GEN8_PCU_IER _MMIO(0x444ec)
 
+#define GEN11_GFX_MSTR_IRQ		_MMIO(0x190010)
+#define  GEN11_MASTER_IRQ		(1 << 31)
+#define  GEN11_PCU_IRQ			(1 << 30)
+#define  GEN11_DISPLAY_IRQ		(1 << 16)
+#define  GEN11_GT_DW_IRQ(x)		(1 << (x))
+#define  GEN11_GT_DW1_IRQ		(1 << 1)
+#define  GEN11_GT_DW0_IRQ		(1 << 0)
+
+#define GEN11_DISPLAY_INT_CTL		_MMIO(0x44200)
+#define  GEN11_DISPLAY_IRQ_ENABLE	(1 << 31)
+#define  GEN11_AUDIO_CODEC_IRQ		(1 << 24)
+#define  GEN11_DE_PCH_IRQ		(1 << 23)
+#define  GEN11_DE_MISC_IRQ		(1 << 22)
+#define  GEN11_DE_PORT_IRQ		(1 << 20)
+#define  GEN11_DE_PIPE_C		(1 << 18)
+#define  GEN11_DE_PIPE_B		(1 << 17)
+#define  GEN11_DE_PIPE_A		(1 << 16)
+
+#define GEN11_GT_INTR_DW0		_MMIO(0x190018)
+#define  GEN11_CSME			(31)
+#define  GEN11_GUNIT			(28)
+#define  GEN11_GUC			(25)
+#define  GEN11_WDPERF			(20)
+#define  GEN11_KCR			(19)
+#define  GEN11_GTPM			(16)
+#define  GEN11_BCS			(15)
+#define  GEN11_RCS0			(0)
+
+#define GEN11_GT_INTR_DW1		_MMIO(0x19001c)
+#define  GEN11_VECS(x)			(31 - (x))
+#define  GEN11_VCS(x)			(x)
+
+#define GEN11_GT_INTR_DW(x)		_MMIO(0x190018 + (x * 4))
+
+#define GEN11_INTR_IDENTITY_REG0	_MMIO(0x190060)
+#define GEN11_INTR_IDENTITY_REG1	_MMIO(0x190064)
+#define  GEN11_INTR_DATA_VALID		(1 << 31)
+#define  GEN11_INTR_ENGINE_MASK		(0xffff)
+
+#define GEN11_INTR_IDENTITY_REG(x)	_MMIO(0x190060 + (x * 4))
+
+#define GEN11_IIR_REG0_SELECTOR		_MMIO(0x190070)
+#define GEN11_IIR_REG1_SELECTOR		_MMIO(0x190074)
+
+#define GEN11_IIR_REG_SELECTOR(x)	_MMIO(0x190070 + (x * 4))
+
+#define GEN11_RENDER_COPY_INTR_ENABLE	_MMIO(0x190030)
+#define GEN11_VCS_VECS_INTR_ENABLE	_MMIO(0x190034)
+#define GEN11_GUC_SG_INTR_ENABLE	_MMIO(0x190038)
+#define GEN11_GPM_WGBOXPERF_INTR_ENABLE	_MMIO(0x19003c)
+#define GEN11_CRYPTO_RSVD_INTR_ENABLE	_MMIO(0x190040)
+#define GEN11_GUNIT_CSME_INTR_ENABLE	_MMIO(0x190044)
+
+#define GEN11_RCS0_RSVD_INTR_MASK	_MMIO(0x190090)
+#define GEN11_BCS_RSVD_INTR_MASK	_MMIO(0x1900a0)
+#define GEN11_VCS0_VCS1_INTR_MASK	_MMIO(0x1900a8)
+#define GEN11_VCS2_VCS3_INTR_MASK	_MMIO(0x1900ac)
+#define GEN11_VECS0_VECS1_INTR_MASK	_MMIO(0x1900d0)
+#define GEN11_GUC_SG_INTR_MASK		_MMIO(0x1900e8)
+#define GEN11_GPM_WGBOXPERF_INTR_MASK	_MMIO(0x1900ec)
+#define GEN11_CRYPTO_RSVD_INTR_MASK	_MMIO(0x1900f0)
+#define GEN11_GUNIT_CSME_INTR_MASK	_MMIO(0x1900f4)
+
 #define ILK_DISPLAY_CHICKEN2	_MMIO(0x42004)
 /* Required on all Ironlake and Sandybridge according to the B-Spec. */
 #define  ILK_ELPIN_409_SELECT	(1 << 25)
@@ -7011,8 +7150,12 @@ enum {
 #define CHICKEN_TRANS_A         0x420c0
 #define CHICKEN_TRANS_B         0x420c4
 #define CHICKEN_TRANS(trans) _MMIO_TRANS(trans, CHICKEN_TRANS_A, CHICKEN_TRANS_B)
-#define PSR2_VSC_ENABLE_PROG_HEADER    (1<<12)
-#define PSR2_ADD_VERTICAL_LINE_COUNT   (1<<15)
+#define  DDI_TRAINING_OVERRIDE_ENABLE	(1<<19)
+#define  DDI_TRAINING_OVERRIDE_VALUE	(1<<18)
+#define  DDIE_TRAINING_OVERRIDE_ENABLE	(1<<17) /* CHICKEN_TRANS_A only */
+#define  DDIE_TRAINING_OVERRIDE_VALUE	(1<<16) /* CHICKEN_TRANS_A only */
+#define  PSR2_ADD_VERTICAL_LINE_COUNT   (1<<15)
+#define  PSR2_VSC_ENABLE_PROG_HEADER    (1<<12)
 
 #define DISP_ARB_CTL	_MMIO(0x45000)
 #define  DISP_FBC_MEMORY_WAKE		(1<<31)
@@ -7022,6 +7165,8 @@ enum {
 #define  DISP_DATA_PARTITION_5_6	(1<<6)
 #define  DISP_IPC_ENABLE		(1<<3)
 #define DBUF_CTL	_MMIO(0x45008)
+#define DBUF_CTL_S1	_MMIO(0x45008)
+#define DBUF_CTL_S2	_MMIO(0x44FE8)
 #define  DBUF_POWER_REQUEST		(1<<31)
 #define  DBUF_POWER_STATE		(1<<30)
 #define GEN7_MSG_CTL	_MMIO(0x45010)
@@ -7031,8 +7176,9 @@ enum {
 #define  RESET_PCH_HANDSHAKE_ENABLE	(1<<4)
 
 #define GEN8_CHICKEN_DCPR_1		_MMIO(0x46430)
-#define   SKL_SELECT_ALTERNATE_DC_EXIT	(1<<30)
-#define   MASK_WAKEMEM			(1<<13)
+#define   SKL_SELECT_ALTERNATE_DC_EXIT	(1 << 30)
+#define   MASK_WAKEMEM			(1 << 13)
+#define   CNL_DDI_CLOCK_REG_ACCESS_ON	(1 << 7)
 
 #define SKL_DFSM			_MMIO(0x51000)
 #define SKL_DFSM_CDCLK_LIMIT_MASK	(3 << 23)
@@ -7044,8 +7190,12 @@ enum {
 #define SKL_DFSM_PIPE_B_DISABLE		(1 << 21)
 #define SKL_DFSM_PIPE_C_DISABLE		(1 << 28)
 
-#define SKL_DSSM			_MMIO(0x51004)
-#define CNL_DSSM_CDCLK_PLL_REFCLK_24MHz	(1 << 31)
+#define SKL_DSSM				_MMIO(0x51004)
+#define CNL_DSSM_CDCLK_PLL_REFCLK_24MHz		(1 << 31)
+#define ICL_DSSM_CDCLK_PLL_REFCLK_MASK		(7 << 29)
+#define ICL_DSSM_CDCLK_PLL_REFCLK_24MHz		(0 << 29)
+#define ICL_DSSM_CDCLK_PLL_REFCLK_19_2MHz	(1 << 29)
+#define ICL_DSSM_CDCLK_PLL_REFCLK_38_4MHz	(2 << 29)
 
 #define GEN7_FF_SLICE_CS_CHICKEN1	_MMIO(0x20e0)
 #define   GEN9_FFSC_PERCTX_PREEMPT_CTRL	(1<<14)
@@ -7351,6 +7501,8 @@ enum {
 #define  CNP_RAWCLK_DIV(div)	((div) << 16)
 #define  CNP_RAWCLK_FRAC_MASK	(0xf << 26)
 #define  CNP_RAWCLK_FRAC(frac)	((frac) << 26)
+#define  ICP_RAWCLK_DEN(den)	((den) << 26)
+#define  ICP_RAWCLK_NUM(num)	((num) << 11)
 
 #define PCH_DPLL_TMR_CFG        _MMIO(0xc6208)
 
@@ -8048,6 +8200,7 @@ enum {
 #define     GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT	8
 #define     GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT	16
 #define     GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT	24
+#define   SKL_PCODE_LOAD_HDCP_KEYS		0x5
 #define   SKL_PCODE_CDCLK_CONTROL		0x7
 #define     SKL_CDCLK_PREPARE_FOR_CHANGE	0x3
 #define     SKL_CDCLK_READY_FOR_CHANGE		0x1
@@ -8350,6 +8503,101 @@ enum skl_power_gate {
 #define  SKL_PW_TO_PG(pw)			((pw) - SKL_DISP_PW_1 + SKL_PG1)
 #define  SKL_FUSE_PG_DIST_STATUS(pg)		(1 << (27 - (pg)))
 
+#define _CNL_AUX_REG_IDX(pw)		((pw) - 9)
+#define _CNL_AUX_ANAOVRD1_B		0x162250
+#define _CNL_AUX_ANAOVRD1_C		0x162210
+#define _CNL_AUX_ANAOVRD1_D		0x1622D0
+#define _CNL_AUX_ANAOVRD1_F		0x162A90
+#define CNL_AUX_ANAOVRD1(pw)		_MMIO(_PICK(_CNL_AUX_REG_IDX(pw), \
+						    _CNL_AUX_ANAOVRD1_B, \
+						    _CNL_AUX_ANAOVRD1_C, \
+						    _CNL_AUX_ANAOVRD1_D, \
+						    _CNL_AUX_ANAOVRD1_F))
+#define   CNL_AUX_ANAOVRD1_ENABLE	(1<<16)
+#define   CNL_AUX_ANAOVRD1_LDO_BYPASS	(1<<23)
+
+/* HDCP Key Registers */
+#define HDCP_KEY_CONF			_MMIO(0x66c00)
+#define  HDCP_AKSV_SEND_TRIGGER		BIT(31)
+#define  HDCP_CLEAR_KEYS_TRIGGER	BIT(30)
+#define  HDCP_KEY_LOAD_TRIGGER		BIT(8)
+#define HDCP_KEY_STATUS			_MMIO(0x66c04)
+#define  HDCP_FUSE_IN_PROGRESS		BIT(7)
+#define  HDCP_FUSE_ERROR		BIT(6)
+#define  HDCP_FUSE_DONE			BIT(5)
+#define  HDCP_KEY_LOAD_STATUS		BIT(1)
+#define  HDCP_KEY_LOAD_DONE		BIT(0)
+#define HDCP_AKSV_LO			_MMIO(0x66c10)
+#define HDCP_AKSV_HI			_MMIO(0x66c14)
+
+/* HDCP Repeater Registers */
+#define HDCP_REP_CTL			_MMIO(0x66d00)
+#define  HDCP_DDIB_REP_PRESENT		BIT(30)
+#define  HDCP_DDIA_REP_PRESENT		BIT(29)
+#define  HDCP_DDIC_REP_PRESENT		BIT(28)
+#define  HDCP_DDID_REP_PRESENT		BIT(27)
+#define  HDCP_DDIF_REP_PRESENT		BIT(26)
+#define  HDCP_DDIE_REP_PRESENT		BIT(25)
+#define  HDCP_DDIB_SHA1_M0		(1 << 20)
+#define  HDCP_DDIA_SHA1_M0		(2 << 20)
+#define  HDCP_DDIC_SHA1_M0		(3 << 20)
+#define  HDCP_DDID_SHA1_M0		(4 << 20)
+#define  HDCP_DDIF_SHA1_M0		(5 << 20)
+#define  HDCP_DDIE_SHA1_M0		(6 << 20) /* Bspec says 5? */
+#define  HDCP_SHA1_BUSY			BIT(16)
+#define  HDCP_SHA1_READY		BIT(17)
+#define  HDCP_SHA1_COMPLETE		BIT(18)
+#define  HDCP_SHA1_V_MATCH		BIT(19)
+#define  HDCP_SHA1_TEXT_32		(1 << 1)
+#define  HDCP_SHA1_COMPLETE_HASH	(2 << 1)
+#define  HDCP_SHA1_TEXT_24		(4 << 1)
+#define  HDCP_SHA1_TEXT_16		(5 << 1)
+#define  HDCP_SHA1_TEXT_8		(6 << 1)
+#define  HDCP_SHA1_TEXT_0		(7 << 1)
+#define HDCP_SHA_V_PRIME_H0		_MMIO(0x66d04)
+#define HDCP_SHA_V_PRIME_H1		_MMIO(0x66d08)
+#define HDCP_SHA_V_PRIME_H2		_MMIO(0x66d0C)
+#define HDCP_SHA_V_PRIME_H3		_MMIO(0x66d10)
+#define HDCP_SHA_V_PRIME_H4		_MMIO(0x66d14)
+#define HDCP_SHA_V_PRIME(h)		_MMIO((0x66d04 + h * 4))
+#define HDCP_SHA_TEXT			_MMIO(0x66d18)
+
+/* HDCP Auth Registers */
+#define _PORTA_HDCP_AUTHENC		0x66800
+#define _PORTB_HDCP_AUTHENC		0x66500
+#define _PORTC_HDCP_AUTHENC		0x66600
+#define _PORTD_HDCP_AUTHENC		0x66700
+#define _PORTE_HDCP_AUTHENC		0x66A00
+#define _PORTF_HDCP_AUTHENC		0x66900
+#define _PORT_HDCP_AUTHENC(port, x)	_MMIO(_PICK(port, \
+					  _PORTA_HDCP_AUTHENC, \
+					  _PORTB_HDCP_AUTHENC, \
+					  _PORTC_HDCP_AUTHENC, \
+					  _PORTD_HDCP_AUTHENC, \
+					  _PORTE_HDCP_AUTHENC, \
+					  _PORTF_HDCP_AUTHENC) + x)
+#define PORT_HDCP_CONF(port)		_PORT_HDCP_AUTHENC(port, 0x0)
+#define  HDCP_CONF_CAPTURE_AN		BIT(0)
+#define  HDCP_CONF_AUTH_AND_ENC		(BIT(1) | BIT(0))
+#define PORT_HDCP_ANINIT(port)		_PORT_HDCP_AUTHENC(port, 0x4)
+#define PORT_HDCP_ANLO(port)		_PORT_HDCP_AUTHENC(port, 0x8)
+#define PORT_HDCP_ANHI(port)		_PORT_HDCP_AUTHENC(port, 0xC)
+#define PORT_HDCP_BKSVLO(port)		_PORT_HDCP_AUTHENC(port, 0x10)
+#define PORT_HDCP_BKSVHI(port)		_PORT_HDCP_AUTHENC(port, 0x14)
+#define PORT_HDCP_RPRIME(port)		_PORT_HDCP_AUTHENC(port, 0x18)
+#define PORT_HDCP_STATUS(port)		_PORT_HDCP_AUTHENC(port, 0x1C)
+#define  HDCP_STATUS_STREAM_A_ENC	BIT(31)
+#define  HDCP_STATUS_STREAM_B_ENC	BIT(30)
+#define  HDCP_STATUS_STREAM_C_ENC	BIT(29)
+#define  HDCP_STATUS_STREAM_D_ENC	BIT(28)
+#define  HDCP_STATUS_AUTH		BIT(21)
+#define  HDCP_STATUS_ENC		BIT(20)
+#define  HDCP_STATUS_RI_MATCH		BIT(19)
+#define  HDCP_STATUS_R0_READY		BIT(18)
+#define  HDCP_STATUS_AN_READY		BIT(17)
+#define  HDCP_STATUS_CIPHER		BIT(16)
+#define  HDCP_STATUS_FRAME_CNT(x)	((x >> 8) & 0xff)
+
 /* Per-pipe DDI Function Control */
 #define _TRANS_DDI_FUNC_CTL_A		0x60400
 #define _TRANS_DDI_FUNC_CTL_B		0x61400
@@ -8381,6 +8629,7 @@ enum skl_power_gate {
 #define  TRANS_DDI_EDP_INPUT_A_ONOFF	(4<<12)
 #define  TRANS_DDI_EDP_INPUT_B_ONOFF	(5<<12)
 #define  TRANS_DDI_EDP_INPUT_C_ONOFF	(6<<12)
+#define  TRANS_DDI_HDCP_SIGNALLING	(1<<9)
 #define  TRANS_DDI_DP_VC_PAYLOAD_ALLOC	(1<<8)
 #define  TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1<<7)
 #define  TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1<<6)
@@ -8579,20 +8828,21 @@ enum skl_power_gate {
 
 /* CDCLK_CTL */
 #define CDCLK_CTL			_MMIO(0x46000)
-#define  CDCLK_FREQ_SEL_MASK		(3<<26)
-#define  CDCLK_FREQ_450_432		(0<<26)
-#define  CDCLK_FREQ_540			(1<<26)
-#define  CDCLK_FREQ_337_308		(2<<26)
-#define  CDCLK_FREQ_675_617		(3<<26)
-#define  BXT_CDCLK_CD2X_DIV_SEL_MASK	(3<<22)
-#define  BXT_CDCLK_CD2X_DIV_SEL_1	(0<<22)
-#define  BXT_CDCLK_CD2X_DIV_SEL_1_5	(1<<22)
-#define  BXT_CDCLK_CD2X_DIV_SEL_2	(2<<22)
-#define  BXT_CDCLK_CD2X_DIV_SEL_4	(3<<22)
-#define  BXT_CDCLK_CD2X_PIPE(pipe)	((pipe)<<20)
-#define  CDCLK_DIVMUX_CD_OVERRIDE	(1<<19)
+#define  CDCLK_FREQ_SEL_MASK		(3 << 26)
+#define  CDCLK_FREQ_450_432		(0 << 26)
+#define  CDCLK_FREQ_540			(1 << 26)
+#define  CDCLK_FREQ_337_308		(2 << 26)
+#define  CDCLK_FREQ_675_617		(3 << 26)
+#define  BXT_CDCLK_CD2X_DIV_SEL_MASK	(3 << 22)
+#define  BXT_CDCLK_CD2X_DIV_SEL_1	(0 << 22)
+#define  BXT_CDCLK_CD2X_DIV_SEL_1_5	(1 << 22)
+#define  BXT_CDCLK_CD2X_DIV_SEL_2	(2 << 22)
+#define  BXT_CDCLK_CD2X_DIV_SEL_4	(3 << 22)
+#define  BXT_CDCLK_CD2X_PIPE(pipe)	((pipe) << 20)
+#define  CDCLK_DIVMUX_CD_OVERRIDE	(1 << 19)
 #define  BXT_CDCLK_CD2X_PIPE_NONE	BXT_CDCLK_CD2X_PIPE(3)
-#define  BXT_CDCLK_SSA_PRECHARGE_ENABLE	(1<<16)
+#define  ICL_CDCLK_CD2X_PIPE_NONE	(7 << 19)
+#define  BXT_CDCLK_SSA_PRECHARGE_ENABLE	(1 << 16)
 #define  CDCLK_FREQ_DECIMAL_MASK	(0x7ff)
 
 /* LCPLL_CTL */
@@ -8663,10 +8913,12 @@ enum skl_power_gate {
  * CNL Clocks
  */
 #define DPCLKA_CFGCR0				_MMIO(0x6C200)
-#define  DPCLKA_CFGCR0_DDI_CLK_OFF(port)	(1 << ((port)+10))
-#define  DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port)	(3 << ((port)*2))
-#define  DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)	((port)*2)
-#define  DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port)	((pll) << ((port)*2))
+#define  DPCLKA_CFGCR0_DDI_CLK_OFF(port)	(1 << ((port) ==  PORT_F ? 23 : \
+						      (port)+10))
+#define  DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)	((port) == PORT_F ? 21 : \
+						(port)*2)
+#define  DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port)	(3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port))
+#define  DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port)	((pll) << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port))
 
 /* CNL PLL */
 #define DPLL0_ENABLE		0x46010
@@ -8762,6 +9014,7 @@ enum skl_power_gate {
 #define  SFUSE_STRAP_RAW_FREQUENCY	(1<<8)
 #define  SFUSE_STRAP_DISPLAY_DISABLED	(1<<7)
 #define  SFUSE_STRAP_CRT_DISABLED	(1<<6)
+#define  SFUSE_STRAP_DDIF_DETECTED	(1<<3)
 #define  SFUSE_STRAP_DDIB_DETECTED	(1<<2)
 #define  SFUSE_STRAP_DDIC_DETECTED	(1<<1)
 #define  SFUSE_STRAP_DDID_DETECTED	(1<<0)
@@ -9498,4 +9751,10 @@ enum skl_power_gate {
 #define  MMCD_PCLA		(1 << 31)
 #define  MMCD_HOTSPOT_EN	(1 << 27)
 
+#define _ICL_PHY_MISC_A		0x64C00
+#define _ICL_PHY_MISC_B		0x64C04
+#define ICL_PHY_MISC(port)	_MMIO_PORT(port, _ICL_PHY_MISC_A, \
+						 _ICL_PHY_MISC_B)
+#define  ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN	(1 << 23)
+
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c
index 3669f5eeb91e..1de5173e53a2 100644
--- a/drivers/gpu/drm/i915/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/i915_sw_fence.c
@@ -365,18 +365,31 @@ int i915_sw_fence_await_sw_fence_gfp(struct i915_sw_fence *fence,
 struct i915_sw_dma_fence_cb {
 	struct dma_fence_cb base;
 	struct i915_sw_fence *fence;
+};
+
+struct i915_sw_dma_fence_cb_timer {
+	struct i915_sw_dma_fence_cb base;
 	struct dma_fence *dma;
 	struct timer_list timer;
 	struct irq_work work;
 	struct rcu_head rcu;
 };
 
+static void dma_i915_sw_fence_wake(struct dma_fence *dma,
+				   struct dma_fence_cb *data)
+{
+	struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
+
+	i915_sw_fence_complete(cb->fence);
+	kfree(cb);
+}
+
 static void timer_i915_sw_fence_wake(struct timer_list *t)
 {
-	struct i915_sw_dma_fence_cb *cb = from_timer(cb, t, timer);
+	struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer);
 	struct i915_sw_fence *fence;
 
-	fence = xchg(&cb->fence, NULL);
+	fence = xchg(&cb->base.fence, NULL);
 	if (!fence)
 		return;
 
@@ -388,13 +401,14 @@ static void timer_i915_sw_fence_wake(struct timer_list *t)
 	i915_sw_fence_complete(fence);
 }
 
-static void dma_i915_sw_fence_wake(struct dma_fence *dma,
-				   struct dma_fence_cb *data)
+static void dma_i915_sw_fence_wake_timer(struct dma_fence *dma,
+					 struct dma_fence_cb *data)
 {
-	struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
+	struct i915_sw_dma_fence_cb_timer *cb =
+		container_of(data, typeof(*cb), base.base);
 	struct i915_sw_fence *fence;
 
-	fence = xchg(&cb->fence, NULL);
+	fence = xchg(&cb->base.fence, NULL);
 	if (fence)
 		i915_sw_fence_complete(fence);
 
@@ -403,7 +417,8 @@ static void dma_i915_sw_fence_wake(struct dma_fence *dma,
 
 static void irq_i915_sw_fence_work(struct irq_work *wrk)
 {
-	struct i915_sw_dma_fence_cb *cb = container_of(wrk, typeof(*cb), work);
+	struct i915_sw_dma_fence_cb_timer *cb =
+		container_of(wrk, typeof(*cb), work);
 
 	del_timer_sync(&cb->timer);
 	dma_fence_put(cb->dma);
@@ -417,6 +432,7 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
 				  gfp_t gfp)
 {
 	struct i915_sw_dma_fence_cb *cb;
+	dma_fence_func_t func;
 	int ret;
 
 	debug_fence_assert(fence);
@@ -425,7 +441,10 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
 	if (dma_fence_is_signaled(dma))
 		return 0;
 
-	cb = kmalloc(sizeof(*cb), gfp);
+	cb = kmalloc(timeout ?
+		     sizeof(struct i915_sw_dma_fence_cb_timer) :
+		     sizeof(struct i915_sw_dma_fence_cb),
+		     gfp);
 	if (!cb) {
 		if (!gfpflags_allow_blocking(gfp))
 			return -ENOMEM;
@@ -436,19 +455,26 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
 	cb->fence = fence;
 	i915_sw_fence_await(fence);
 
-	cb->dma = NULL;
-	timer_setup(&cb->timer, timer_i915_sw_fence_wake, TIMER_IRQSAFE);
-	init_irq_work(&cb->work, irq_i915_sw_fence_work);
+	func = dma_i915_sw_fence_wake;
 	if (timeout) {
-		cb->dma = dma_fence_get(dma);
-		mod_timer(&cb->timer, round_jiffies_up(jiffies + timeout));
+		struct i915_sw_dma_fence_cb_timer *timer =
+			container_of(cb, typeof(*timer), base);
+
+		timer->dma = dma_fence_get(dma);
+		init_irq_work(&timer->work, irq_i915_sw_fence_work);
+
+		timer_setup(&timer->timer,
+			    timer_i915_sw_fence_wake, TIMER_IRQSAFE);
+		mod_timer(&timer->timer, round_jiffies_up(jiffies + timeout));
+
+		func = dma_i915_sw_fence_wake_timer;
 	}
 
-	ret = dma_fence_add_callback(dma, &cb->base, dma_i915_sw_fence_wake);
+	ret = dma_fence_add_callback(dma, &cb->base, func);
 	if (ret == 0) {
 		ret = 1;
 	} else {
-		dma_i915_sw_fence_wake(dma, &cb->base);
+		func(dma, &cb->base);
 		if (ret == -ENOENT) /* fence already signaled */
 			ret = 0;
 	}
diff --git a/drivers/gpu/drm/i915/i915_syncmap.c b/drivers/gpu/drm/i915/i915_syncmap.c
index 0087acf731a8..58f8d0cc125c 100644
--- a/drivers/gpu/drm/i915/i915_syncmap.c
+++ b/drivers/gpu/drm/i915/i915_syncmap.c
@@ -86,7 +86,7 @@ struct i915_syncmap {
 
 /**
  * i915_syncmap_init -- initialise the #i915_syncmap
- * @root - pointer to the #i915_syncmap
+ * @root: pointer to the #i915_syncmap
  */
 void i915_syncmap_init(struct i915_syncmap **root)
 {
@@ -139,9 +139,9 @@ static inline bool seqno_later(u32 a, u32 b)
 
 /**
  * i915_syncmap_is_later -- compare against the last know sync point
- * @root - pointer to the #i915_syncmap
- * @id - the context id (other timeline) we are synchronising to
- * @seqno - the sequence number along the other timeline
+ * @root: pointer to the #i915_syncmap
+ * @id: the context id (other timeline) we are synchronising to
+ * @seqno: the sequence number along the other timeline
  *
  * If we have already synchronised this @root timeline with another (@id) then
  * we can omit any repeated or earlier synchronisation requests. If the two
@@ -339,9 +339,9 @@ static noinline int __sync_set(struct i915_syncmap **root, u64 id, u32 seqno)
 
 /**
  * i915_syncmap_set -- mark the most recent syncpoint between contexts
- * @root - pointer to the #i915_syncmap
- * @id - the context id (other timeline) we have synchronised to
- * @seqno - the sequence number along the other timeline
+ * @root: pointer to the #i915_syncmap
+ * @id: the context id (other timeline) we have synchronised to
+ * @seqno: the sequence number along the other timeline
  *
  * When we synchronise this @root timeline with another (@id), we also know
  * that we have synchronized with all previous seqno along that timeline. If
@@ -382,7 +382,7 @@ static void __sync_free(struct i915_syncmap *p)
 
 /**
  * i915_syncmap_free -- free all memory associated with the syncmap
- * @root - pointer to the #i915_syncmap
+ * @root: pointer to the #i915_syncmap
  *
  * Either when the timeline is to be freed and we no longer need the sync
  * point tracking, or when the fences are all known to be signaled and the
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 36d4e635e4ce..e9fb692076d7 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -110,6 +110,8 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
 		to_intel_digital_connector_state(old_state);
 	struct drm_crtc_state *crtc_state;
 
+	intel_hdcp_atomic_check(conn, old_state, new_state);
+
 	if (!new_state->crtc)
 		return 0;
 
@@ -186,13 +188,14 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
 /**
  * intel_crtc_destroy_state - destroy crtc state
  * @crtc: drm crtc
+ * @state: the state to destroy
  *
  * Destroys the crtc state (both common and Intel-specific) for the
  * specified crtc.
  */
 void
 intel_crtc_destroy_state(struct drm_crtc *crtc,
-			  struct drm_crtc_state *state)
+			 struct drm_crtc_state *state)
 {
 	drm_atomic_helper_crtc_destroy_state(crtc, state);
 }
@@ -200,7 +203,7 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
 /**
  * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests
  * @dev_priv: i915 device
- * @crtc: intel crtc
+ * @intel_crtc: intel crtc
  * @crtc_state: incoming crtc_state to validate and setup scalers
  *
  * This function sets up scalers based on staged scaling requests for
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index 8e6dc159f64d..0ee32275994a 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -56,7 +56,6 @@ intel_create_plane_state(struct drm_plane *plane)
 
 	state->base.plane = plane;
 	state->base.rotation = DRM_MODE_ROTATE_0;
-	state->ckey.flags = I915_SET_COLORKEY_NONE;
 
 	return state;
 }
@@ -129,14 +128,6 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_
 	if (!intel_state->base.crtc && !old_plane_state->base.crtc)
 		return 0;
 
-	/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
-	intel_state->clip.x1 = 0;
-	intel_state->clip.y1 = 0;
-	intel_state->clip.x2 =
-		crtc_state->base.enable ? crtc_state->pipe_src_w : 0;
-	intel_state->clip.y2 =
-		crtc_state->base.enable ? crtc_state->pipe_src_h : 0;
-
 	if (state->fb && drm_rotation_90_or_270(state->rotation)) {
 		struct drm_format_name_buf format_name;
 
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 522d54fecb53..709d6ca68074 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -704,7 +704,7 @@ void intel_init_audio_hooks(struct drm_i915_private *dev_priv)
 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 		dev_priv->display.audio_codec_enable = ilk_audio_codec_enable;
 		dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
-	} else if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8) {
+	} else if (IS_HASWELL(dev_priv) || INTEL_GEN(dev_priv) >= 8) {
 		dev_priv->display.audio_codec_enable = hsw_audio_codec_enable;
 		dev_priv->display.audio_codec_disable = hsw_audio_codec_disable;
 	} else if (HAS_PCH_SPLIT(dev_priv)) {
@@ -779,11 +779,11 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv,
 {
 	struct intel_encoder *encoder;
 
-	if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map)))
-		return NULL;
-
 	/* MST */
 	if (pipe >= 0) {
+		if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map)))
+			return NULL;
+
 		encoder = dev_priv->av_enc_map[pipe];
 		/*
 		 * when bootup, audio driver may not know it is
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index b49a2df44430..c5c7530ba157 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -391,7 +391,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
 static int intel_bios_ssc_frequency(struct drm_i915_private *dev_priv,
 				    bool alternate)
 {
-	switch (INTEL_INFO(dev_priv)->gen) {
+	switch (INTEL_GEN(dev_priv)) {
 	case 2:
 		return alternate ? 66667 : 48000;
 	case 3:
@@ -1228,6 +1228,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
 		{DVO_PORT_HDMIC, DVO_PORT_DPC, -1},
 		{DVO_PORT_HDMID, DVO_PORT_DPD, -1},
 		{DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE},
+		{DVO_PORT_HDMIF, DVO_PORT_DPF, -1},
 	};
 
 	/*
@@ -1355,6 +1356,27 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
 		DRM_DEBUG_KMS("VBT HDMI boost level for port %c: %d\n",
 			      port_name(port), info->hdmi_boost_level);
 	}
+
+	/* DP max link rate for CNL+ */
+	if (bdb_version >= 216) {
+		switch (child->dp_max_link_rate) {
+		default:
+		case VBT_DP_MAX_LINK_RATE_HBR3:
+			info->dp_max_link_rate = 810000;
+			break;
+		case VBT_DP_MAX_LINK_RATE_HBR2:
+			info->dp_max_link_rate = 540000;
+			break;
+		case VBT_DP_MAX_LINK_RATE_HBR:
+			info->dp_max_link_rate = 270000;
+			break;
+		case VBT_DP_MAX_LINK_RATE_LBR:
+			info->dp_max_link_rate = 162000;
+			break;
+		}
+		DRM_DEBUG_KMS("VBT DP max link rate for port %c: %d\n",
+			      port_name(port), info->dp_max_link_rate);
+	}
 }
 
 static void parse_ddi_ports(struct drm_i915_private *dev_priv, u8 bdb_version)
@@ -1801,6 +1823,7 @@ bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port por
 		[PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, },
 		[PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
 		[PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
+		[PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, },
 	};
 	int i;
 
@@ -1839,6 +1862,7 @@ bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
 		[PORT_C] = DVO_PORT_DPC,
 		[PORT_D] = DVO_PORT_DPD,
 		[PORT_E] = DVO_PORT_DPE,
+		[PORT_F] = DVO_PORT_DPF,
 	};
 	int i;
 
@@ -1874,6 +1898,7 @@ static bool child_dev_is_dp_dual_mode(const struct child_device_config *child,
 		[PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, },
 		[PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
 		[PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
+		[PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, },
 	};
 
 	if (port == PORT_A || port >= ARRAY_SIZE(port_mapping))
@@ -2040,6 +2065,11 @@ intel_bios_is_lspcon_present(struct drm_i915_private *dev_priv,
 			if (port == PORT_D)
 				return true;
 			break;
+		case DVO_PORT_DPF:
+		case DVO_PORT_HDMIF:
+			if (port == PORT_F)
+				return true;
+			break;
 		default:
 			break;
 		}
diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c
index f54ddda9fdad..b955f7d7bd0f 100644
--- a/drivers/gpu/drm/i915/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c
@@ -224,7 +224,7 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
 	struct intel_wait *wait, *n;
 
 	if (!b->irq_armed)
-		goto wakeup_signaler;
+		return;
 
 	/*
 	 * We only disarm the irq when we are idle (all requests completed),
@@ -249,14 +249,6 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
 	b->waiters = RB_ROOT;
 
 	spin_unlock_irq(&b->rb_lock);
-
-	/*
-	 * The signaling thread may be asleep holding a reference to a request,
-	 * that had its signaling cancelled prior to being preempted. We need
-	 * to kick the signaler, just in case, to release any such reference.
-	 */
-wakeup_signaler:
-	wake_up_process(b->signaler);
 }
 
 static bool use_fake_irq(const struct intel_breadcrumbs *b)
@@ -385,6 +377,8 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
 	bool first, armed;
 	u32 seqno;
 
+	GEM_BUG_ON(!wait->seqno);
+
 	/* Insert the request into the retirement ordered list
 	 * of waiters by walking the rbtree. If we are the oldest
 	 * seqno in the tree (the first to be retired), then
@@ -618,6 +612,63 @@ static void signaler_set_rtpriority(void)
 	 sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
 }
 
+static void __intel_engine_remove_signal(struct intel_engine_cs *engine,
+					 struct drm_i915_gem_request *request)
+{
+	struct intel_breadcrumbs *b = &engine->breadcrumbs;
+
+	lockdep_assert_held(&b->rb_lock);
+
+	/*
+	 * Wake up all other completed waiters and select the
+	 * next bottom-half for the next user interrupt.
+	 */
+	__intel_engine_remove_wait(engine, &request->signaling.wait);
+
+	/*
+	 * Find the next oldest signal. Note that as we have
+	 * not been holding the lock, another client may
+	 * have installed an even older signal than the one
+	 * we just completed - so double check we are still
+	 * the oldest before picking the next one.
+	 */
+	if (request->signaling.wait.seqno) {
+		if (request == rcu_access_pointer(b->first_signal)) {
+			struct rb_node *rb = rb_next(&request->signaling.node);
+			rcu_assign_pointer(b->first_signal,
+					   rb ? to_signaler(rb) : NULL);
+		}
+
+		rb_erase(&request->signaling.node, &b->signals);
+		request->signaling.wait.seqno = 0;
+	}
+}
+
+static struct drm_i915_gem_request *
+get_first_signal_rcu(struct intel_breadcrumbs *b)
+{
+	/*
+	 * See the big warnings for i915_gem_active_get_rcu() and similarly
+	 * for dma_fence_get_rcu_safe() that explain the intricacies involved
+	 * here with defeating CPU/compiler speculation and enforcing
+	 * the required memory barriers.
+	 */
+	do {
+		struct drm_i915_gem_request *request;
+
+		request = rcu_dereference(b->first_signal);
+		if (request)
+			request = i915_gem_request_get_rcu(request);
+
+		barrier();
+
+		if (!request || request == rcu_access_pointer(b->first_signal))
+			return rcu_pointer_handoff(request);
+
+		i915_gem_request_put(request);
+	} while (1);
+}
+
 static int intel_breadcrumbs_signaler(void *arg)
 {
 	struct intel_engine_cs *engine = arg;
@@ -641,9 +692,7 @@ static int intel_breadcrumbs_signaler(void *arg)
 		 * a new client.
 		 */
 		rcu_read_lock();
-		request = rcu_dereference(b->first_signal);
-		if (request)
-			request = i915_gem_request_get_rcu(request);
+		request = get_first_signal_rcu(b);
 		rcu_read_unlock();
 		if (signal_complete(request)) {
 			if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
@@ -654,32 +703,11 @@ static int intel_breadcrumbs_signaler(void *arg)
 				local_bh_enable(); /* kick start the tasklets */
 			}
 
-			spin_lock_irq(&b->rb_lock);
-
-			/* Wake up all other completed waiters and select the
-			 * next bottom-half for the next user interrupt.
-			 */
-			__intel_engine_remove_wait(engine,
-						   &request->signaling.wait);
-
-			/* Find the next oldest signal. Note that as we have
-			 * not been holding the lock, another client may
-			 * have installed an even older signal than the one
-			 * we just completed - so double check we are still
-			 * the oldest before picking the next one.
-			 */
-			if (request == rcu_access_pointer(b->first_signal)) {
-				struct rb_node *rb =
-					rb_next(&request->signaling.node);
-				rcu_assign_pointer(b->first_signal,
-						   rb ? to_signaler(rb) : NULL);
+			if (READ_ONCE(request->signaling.wait.seqno)) {
+				spin_lock_irq(&b->rb_lock);
+				__intel_engine_remove_signal(engine, request);
+				spin_unlock_irq(&b->rb_lock);
 			}
-			rb_erase(&request->signaling.node, &b->signals);
-			RB_CLEAR_NODE(&request->signaling.node);
-
-			spin_unlock_irq(&b->rb_lock);
-
-			i915_gem_request_put(request);
 
 			/* If the engine is saturated we may be continually
 			 * processing completed requests. This angers the
@@ -690,19 +718,17 @@ static int intel_breadcrumbs_signaler(void *arg)
 			 */
 			do_schedule = need_resched();
 		}
+		i915_gem_request_put(request);
 
 		if (unlikely(do_schedule)) {
 			if (kthread_should_park())
 				kthread_parkme();
 
-			if (unlikely(kthread_should_stop())) {
-				i915_gem_request_put(request);
+			if (unlikely(kthread_should_stop()))
 				break;
-			}
 
 			schedule();
 		}
-		i915_gem_request_put(request);
 	} while (1);
 	__set_current_state(TASK_RUNNING);
 
@@ -731,12 +757,12 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
 	if (!seqno)
 		return;
 
+	spin_lock(&b->rb_lock);
+
+	GEM_BUG_ON(request->signaling.wait.seqno);
 	request->signaling.wait.tsk = b->signaler;
 	request->signaling.wait.request = request;
 	request->signaling.wait.seqno = seqno;
-	i915_gem_request_get(request);
-
-	spin_lock(&b->rb_lock);
 
 	/* First add ourselves into the list of waiters, but register our
 	 * bottom-half as the signaller thread. As per usual, only the oldest
@@ -775,7 +801,7 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
 			rcu_assign_pointer(b->first_signal, request);
 	} else {
 		__intel_engine_remove_wait(engine, &request->signaling.wait);
-		i915_gem_request_put(request);
+		request->signaling.wait.seqno = 0;
 		wakeup = false;
 	}
 
@@ -787,32 +813,17 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request,
 
 void intel_engine_cancel_signaling(struct drm_i915_gem_request *request)
 {
-	struct intel_engine_cs *engine = request->engine;
-	struct intel_breadcrumbs *b = &engine->breadcrumbs;
-
 	GEM_BUG_ON(!irqs_disabled());
 	lockdep_assert_held(&request->lock);
-	GEM_BUG_ON(!request->signaling.wait.seqno);
 
-	spin_lock(&b->rb_lock);
+	if (READ_ONCE(request->signaling.wait.seqno)) {
+		struct intel_engine_cs *engine = request->engine;
+		struct intel_breadcrumbs *b = &engine->breadcrumbs;
 
-	if (!RB_EMPTY_NODE(&request->signaling.node)) {
-		if (request == rcu_access_pointer(b->first_signal)) {
-			struct rb_node *rb =
-				rb_next(&request->signaling.node);
-			rcu_assign_pointer(b->first_signal,
-					   rb ? to_signaler(rb) : NULL);
-		}
-		rb_erase(&request->signaling.node, &b->signals);
-		RB_CLEAR_NODE(&request->signaling.node);
-		i915_gem_request_put(request);
+		spin_lock(&b->rb_lock);
+		__intel_engine_remove_signal(engine, request);
+		spin_unlock(&b->rb_lock);
 	}
-
-	__intel_engine_remove_wait(engine, &request->signaling.wait);
-
-	spin_unlock(&b->rb_lock);
-
-	request->signaling.wait.seqno = 0;
 }
 
 int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 1704c8897afd..dc7db8a2caf8 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -858,7 +858,7 @@ static void skl_get_cdclk(struct drm_i915_private *dev_priv,
 
 	skl_dpll0_update(dev_priv, cdclk_state);
 
-	cdclk_state->cdclk = cdclk_state->ref;
+	cdclk_state->cdclk = cdclk_state->bypass = cdclk_state->ref;
 
 	if (cdclk_state->vco == 0)
 		goto out;
@@ -1006,7 +1006,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,
 	/* Choose frequency for this cdclk */
 	switch (cdclk) {
 	default:
-		WARN_ON(cdclk != dev_priv->cdclk.hw.ref);
+		WARN_ON(cdclk != dev_priv->cdclk.hw.bypass);
 		WARN_ON(vco != 0);
 		/* fall through */
 	case 308571:
@@ -1085,7 +1085,7 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
 
 	/* Is PLL enabled and locked ? */
 	if (dev_priv->cdclk.hw.vco == 0 ||
-	    dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref)
+	    dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass)
 		goto sanitize;
 
 	/* DPLL okay; verify the cdclock
@@ -1159,7 +1159,7 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
 {
 	struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw;
 
-	cdclk_state.cdclk = cdclk_state.ref;
+	cdclk_state.cdclk = cdclk_state.bypass;
 	cdclk_state.vco = 0;
 	cdclk_state.voltage_level = skl_calc_voltage_level(cdclk_state.cdclk);
 
@@ -1199,7 +1199,7 @@ static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
 {
 	int ratio;
 
-	if (cdclk == dev_priv->cdclk.hw.ref)
+	if (cdclk == dev_priv->cdclk.hw.bypass)
 		return 0;
 
 	switch (cdclk) {
@@ -1224,7 +1224,7 @@ static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
 {
 	int ratio;
 
-	if (cdclk == dev_priv->cdclk.hw.ref)
+	if (cdclk == dev_priv->cdclk.hw.bypass)
 		return 0;
 
 	switch (cdclk) {
@@ -1268,7 +1268,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv,
 
 	bxt_de_pll_update(dev_priv, cdclk_state);
 
-	cdclk_state->cdclk = cdclk_state->ref;
+	cdclk_state->cdclk = cdclk_state->bypass = cdclk_state->ref;
 
 	if (cdclk_state->vco == 0)
 		goto out;
@@ -1352,7 +1352,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
 	/* cdclk = vco / 2 / div{1,1.5,2,4} */
 	switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
 	default:
-		WARN_ON(cdclk != dev_priv->cdclk.hw.ref);
+		WARN_ON(cdclk != dev_priv->cdclk.hw.bypass);
 		WARN_ON(vco != 0);
 		/* fall through */
 	case 2:
@@ -1378,7 +1378,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
 	mutex_lock(&dev_priv->pcu_lock);
 	ret = sandybridge_pcode_write_timeout(dev_priv,
 					      HSW_PCODE_DE_WRITE_FREQ_REQ,
-					      0x80000000, 2000);
+					      0x80000000, 150, 2);
 	mutex_unlock(&dev_priv->pcu_lock);
 
 	if (ret) {
@@ -1417,7 +1417,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
 	 */
 	ret = sandybridge_pcode_write_timeout(dev_priv,
 					      HSW_PCODE_DE_WRITE_FREQ_REQ,
-					      cdclk_state->voltage_level, 2000);
+					      cdclk_state->voltage_level, 150, 2);
 	mutex_unlock(&dev_priv->pcu_lock);
 
 	if (ret) {
@@ -1437,7 +1437,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
 	intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
 
 	if (dev_priv->cdclk.hw.vco == 0 ||
-	    dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref)
+	    dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass)
 		goto sanitize;
 
 	/* DPLL okay; verify the cdclock
@@ -1526,7 +1526,7 @@ void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
 {
 	struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw;
 
-	cdclk_state.cdclk = cdclk_state.ref;
+	cdclk_state.cdclk = cdclk_state.bypass;
 	cdclk_state.vco = 0;
 	cdclk_state.voltage_level = bxt_calc_voltage_level(cdclk_state.cdclk);
 
@@ -1586,7 +1586,7 @@ static void cnl_get_cdclk(struct drm_i915_private *dev_priv,
 
 	cnl_cdclk_pll_update(dev_priv, cdclk_state);
 
-	cdclk_state->cdclk = cdclk_state->ref;
+	cdclk_state->cdclk = cdclk_state->bypass = cdclk_state->ref;
 
 	if (cdclk_state->vco == 0)
 		goto out;
@@ -1672,7 +1672,7 @@ static void cnl_set_cdclk(struct drm_i915_private *dev_priv,
 	/* cdclk = vco / 2 / div{1,2} */
 	switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
 	default:
-		WARN_ON(cdclk != dev_priv->cdclk.hw.ref);
+		WARN_ON(cdclk != dev_priv->cdclk.hw.bypass);
 		WARN_ON(vco != 0);
 		/* fall through */
 	case 2:
@@ -1717,7 +1717,7 @@ static int cnl_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
 {
 	int ratio;
 
-	if (cdclk == dev_priv->cdclk.hw.ref)
+	if (cdclk == dev_priv->cdclk.hw.bypass)
 		return 0;
 
 	switch (cdclk) {
@@ -1744,7 +1744,7 @@ static void cnl_sanitize_cdclk(struct drm_i915_private *dev_priv)
 	intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
 
 	if (dev_priv->cdclk.hw.vco == 0 ||
-	    dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref)
+	    dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass)
 		goto sanitize;
 
 	/* DPLL okay; verify the cdclock
@@ -1778,6 +1778,199 @@ static void cnl_sanitize_cdclk(struct drm_i915_private *dev_priv)
 	dev_priv->cdclk.hw.vco = -1;
 }
 
+static int icl_calc_cdclk(int min_cdclk, unsigned int ref)
+{
+	int ranges_24[] = { 312000, 552000, 648000 };
+	int ranges_19_38[] = { 307200, 556800, 652800 };
+	int *ranges;
+
+	switch (ref) {
+	default:
+		MISSING_CASE(ref);
+	case 24000:
+		ranges = ranges_24;
+		break;
+	case 19200:
+	case 38400:
+		ranges = ranges_19_38;
+		break;
+	}
+
+	if (min_cdclk > ranges[1])
+		return ranges[2];
+	else if (min_cdclk > ranges[0])
+		return ranges[1];
+	else
+		return ranges[0];
+}
+
+static int icl_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
+{
+	int ratio;
+
+	if (cdclk == dev_priv->cdclk.hw.bypass)
+		return 0;
+
+	switch (cdclk) {
+	default:
+		MISSING_CASE(cdclk);
+	case 307200:
+	case 556800:
+	case 652800:
+		WARN_ON(dev_priv->cdclk.hw.ref != 19200 &&
+			dev_priv->cdclk.hw.ref != 38400);
+		break;
+	case 312000:
+	case 552000:
+	case 648000:
+		WARN_ON(dev_priv->cdclk.hw.ref != 24000);
+	}
+
+	ratio = cdclk / (dev_priv->cdclk.hw.ref / 2);
+
+	return dev_priv->cdclk.hw.ref * ratio;
+}
+
+static void icl_set_cdclk(struct drm_i915_private *dev_priv,
+			  const struct intel_cdclk_state *cdclk_state)
+{
+	unsigned int cdclk = cdclk_state->cdclk;
+	unsigned int vco = cdclk_state->vco;
+	int ret;
+
+	mutex_lock(&dev_priv->pcu_lock);
+	ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL,
+				SKL_CDCLK_PREPARE_FOR_CHANGE,
+				SKL_CDCLK_READY_FOR_CHANGE,
+				SKL_CDCLK_READY_FOR_CHANGE, 3);
+	mutex_unlock(&dev_priv->pcu_lock);
+	if (ret) {
+		DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n",
+			  ret);
+		return;
+	}
+
+	if (dev_priv->cdclk.hw.vco != 0 &&
+	    dev_priv->cdclk.hw.vco != vco)
+		cnl_cdclk_pll_disable(dev_priv);
+
+	if (dev_priv->cdclk.hw.vco != vco)
+		cnl_cdclk_pll_enable(dev_priv, vco);
+
+	I915_WRITE(CDCLK_CTL, ICL_CDCLK_CD2X_PIPE_NONE |
+			      skl_cdclk_decimal(cdclk));
+
+	mutex_lock(&dev_priv->pcu_lock);
+	/* TODO: add proper DVFS support. */
+	sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, 2);
+	mutex_unlock(&dev_priv->pcu_lock);
+
+	intel_update_cdclk(dev_priv);
+}
+
+static void icl_get_cdclk(struct drm_i915_private *dev_priv,
+			  struct intel_cdclk_state *cdclk_state)
+{
+	u32 val;
+
+	cdclk_state->bypass = 50000;
+
+	val = I915_READ(SKL_DSSM);
+	switch (val & ICL_DSSM_CDCLK_PLL_REFCLK_MASK) {
+	default:
+		MISSING_CASE(val);
+	case ICL_DSSM_CDCLK_PLL_REFCLK_24MHz:
+		cdclk_state->ref = 24000;
+		break;
+	case ICL_DSSM_CDCLK_PLL_REFCLK_19_2MHz:
+		cdclk_state->ref = 19200;
+		break;
+	case ICL_DSSM_CDCLK_PLL_REFCLK_38_4MHz:
+		cdclk_state->ref = 38400;
+		break;
+	}
+
+	val = I915_READ(BXT_DE_PLL_ENABLE);
+	if ((val & BXT_DE_PLL_PLL_ENABLE) == 0 ||
+	    (val & BXT_DE_PLL_LOCK) == 0) {
+		/*
+		 * CDCLK PLL is disabled, the VCO/ratio doesn't matter, but
+		 * setting it to zero is a way to signal that.
+		 */
+		cdclk_state->vco = 0;
+		cdclk_state->cdclk = cdclk_state->bypass;
+		return;
+	}
+
+	cdclk_state->vco = (val & BXT_DE_PLL_RATIO_MASK) * cdclk_state->ref;
+
+	val = I915_READ(CDCLK_CTL);
+	WARN_ON((val & BXT_CDCLK_CD2X_DIV_SEL_MASK) != 0);
+
+	cdclk_state->cdclk = cdclk_state->vco / 2;
+}
+
+/**
+ * icl_init_cdclk - Initialize CDCLK on ICL
+ * @dev_priv: i915 device
+ *
+ * Initialize CDCLK for ICL. This consists mainly of initializing
+ * dev_priv->cdclk.hw and sanitizing the state of the hardware if needed. This
+ * is generally done only during the display core initialization sequence, after
+ * which the DMC will take care of turning CDCLK off/on as needed.
+ */
+void icl_init_cdclk(struct drm_i915_private *dev_priv)
+{
+	struct intel_cdclk_state sanitized_state;
+	u32 val;
+
+	/* This sets dev_priv->cdclk.hw. */
+	intel_update_cdclk(dev_priv);
+	intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
+
+	/* This means CDCLK disabled. */
+	if (dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass)
+		goto sanitize;
+
+	val = I915_READ(CDCLK_CTL);
+
+	if ((val & BXT_CDCLK_CD2X_DIV_SEL_MASK) != 0)
+		goto sanitize;
+
+	if ((val & CDCLK_FREQ_DECIMAL_MASK) !=
+	    skl_cdclk_decimal(dev_priv->cdclk.hw.cdclk))
+		goto sanitize;
+
+	return;
+
+sanitize:
+	DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
+
+	sanitized_state.ref = dev_priv->cdclk.hw.ref;
+	sanitized_state.cdclk = icl_calc_cdclk(0, sanitized_state.ref);
+	sanitized_state.vco = icl_calc_cdclk_pll_vco(dev_priv,
+						     sanitized_state.cdclk);
+
+	icl_set_cdclk(dev_priv, &sanitized_state);
+}
+
+/**
+ * icl_uninit_cdclk - Uninitialize CDCLK on ICL
+ * @dev_priv: i915 device
+ *
+ * Uninitialize CDCLK for ICL. This is done only during the display core
+ * uninitialization sequence.
+ */
+void icl_uninit_cdclk(struct drm_i915_private *dev_priv)
+{
+	struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw;
+
+	cdclk_state.cdclk = cdclk_state.bypass;
+	cdclk_state.vco = 0;
+
+	icl_set_cdclk(dev_priv, &cdclk_state);
+}
+
 /**
  * cnl_init_cdclk - Initialize CDCLK on CNL
  * @dev_priv: i915 device
@@ -1817,7 +2010,7 @@ void cnl_uninit_cdclk(struct drm_i915_private *dev_priv)
 {
 	struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw;
 
-	cdclk_state.cdclk = cdclk_state.ref;
+	cdclk_state.cdclk = cdclk_state.bypass;
 	cdclk_state.vco = 0;
 	cdclk_state.voltage_level = cnl_calc_voltage_level(cdclk_state.cdclk);
 
@@ -1858,9 +2051,10 @@ bool intel_cdclk_changed(const struct intel_cdclk_state *a,
 void intel_dump_cdclk_state(const struct intel_cdclk_state *cdclk_state,
 			    const char *context)
 {
-	DRM_DEBUG_DRIVER("%s %d kHz, VCO %d kHz, ref %d kHz, voltage level %d\n",
+	DRM_DEBUG_DRIVER("%s %d kHz, VCO %d kHz, ref %d kHz, bypass %d kHz, voltage level %d\n",
 			 context, cdclk_state->cdclk, cdclk_state->vco,
-			 cdclk_state->ref, cdclk_state->voltage_level);
+			 cdclk_state->ref, cdclk_state->bypass,
+			 cdclk_state->voltage_level);
 }
 
 /**
@@ -2215,6 +2409,36 @@ static int cnl_modeset_calc_cdclk(struct drm_atomic_state *state)
 	return 0;
 }
 
+static int icl_modeset_calc_cdclk(struct drm_atomic_state *state)
+{
+	struct drm_i915_private *dev_priv = to_i915(state->dev);
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+	unsigned int ref = intel_state->cdclk.logical.ref;
+	int min_cdclk, cdclk, vco;
+
+	min_cdclk = intel_compute_min_cdclk(state);
+	if (min_cdclk < 0)
+		return min_cdclk;
+
+	cdclk = icl_calc_cdclk(min_cdclk, ref);
+	vco = icl_calc_cdclk_pll_vco(dev_priv, cdclk);
+
+	intel_state->cdclk.logical.vco = vco;
+	intel_state->cdclk.logical.cdclk = cdclk;
+
+	if (!intel_state->active_crtcs) {
+		cdclk = icl_calc_cdclk(0, ref);
+		vco = icl_calc_cdclk_pll_vco(dev_priv, cdclk);
+
+		intel_state->cdclk.actual.vco = vco;
+		intel_state->cdclk.actual.cdclk = cdclk;
+	} else {
+		intel_state->cdclk.actual = intel_state->cdclk.logical;
+	}
+
+	return 0;
+}
+
 static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
 {
 	int max_cdclk_freq = dev_priv->max_cdclk_freq;
@@ -2232,7 +2456,7 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
 		return max_cdclk_freq;
 	else if (IS_CHERRYVIEW(dev_priv))
 		return max_cdclk_freq*95/100;
-	else if (INTEL_INFO(dev_priv)->gen < 4)
+	else if (INTEL_GEN(dev_priv) < 4)
 		return 2*max_cdclk_freq*90/100;
 	else
 		return max_cdclk_freq*90/100;
@@ -2248,7 +2472,12 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
  */
 void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
 {
-	if (IS_CANNONLAKE(dev_priv)) {
+	if (IS_ICELAKE(dev_priv)) {
+		if (dev_priv->cdclk.hw.ref == 24000)
+			dev_priv->max_cdclk_freq = 648000;
+		else
+			dev_priv->max_cdclk_freq = 652800;
+	} else if (IS_CANNONLAKE(dev_priv)) {
 		dev_priv->max_cdclk_freq = 528000;
 	} else if (IS_GEN9_BC(dev_priv)) {
 		u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
@@ -2354,6 +2583,30 @@ static int cnp_rawclk(struct drm_i915_private *dev_priv)
 	return divider + fraction;
 }
 
+static int icp_rawclk(struct drm_i915_private *dev_priv)
+{
+	u32 rawclk;
+	int divider, numerator, denominator, frequency;
+
+	if (I915_READ(SFUSE_STRAP) & SFUSE_STRAP_RAW_FREQUENCY) {
+		frequency = 24000;
+		divider = 23;
+		numerator = 0;
+		denominator = 0;
+	} else {
+		frequency = 19200;
+		divider = 18;
+		numerator = 1;
+		denominator = 4;
+	}
+
+	rawclk = CNP_RAWCLK_DIV(divider) | ICP_RAWCLK_NUM(numerator) |
+		 ICP_RAWCLK_DEN(denominator);
+
+	I915_WRITE(PCH_RAWCLK_FREQ, rawclk);
+	return frequency;
+}
+
 static int pch_rawclk(struct drm_i915_private *dev_priv)
 {
 	return (I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000;
@@ -2401,8 +2654,9 @@ static int g4x_hrawclk(struct drm_i915_private *dev_priv)
  */
 void intel_update_rawclk(struct drm_i915_private *dev_priv)
 {
-
-	if (HAS_PCH_CNP(dev_priv))
+	if (HAS_PCH_ICP(dev_priv))
+		dev_priv->rawclk_freq = icp_rawclk(dev_priv);
+	else if (HAS_PCH_CNP(dev_priv))
 		dev_priv->rawclk_freq = cnp_rawclk(dev_priv);
 	else if (HAS_PCH_SPLIT(dev_priv))
 		dev_priv->rawclk_freq = pch_rawclk(dev_priv);
@@ -2447,9 +2701,14 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
 		dev_priv->display.set_cdclk = cnl_set_cdclk;
 		dev_priv->display.modeset_calc_cdclk =
 			cnl_modeset_calc_cdclk;
+	} else if (IS_ICELAKE(dev_priv)) {
+		dev_priv->display.set_cdclk = icl_set_cdclk;
+		dev_priv->display.modeset_calc_cdclk = icl_modeset_calc_cdclk;
 	}
 
-	if (IS_CANNONLAKE(dev_priv))
+	if (IS_ICELAKE(dev_priv))
+		dev_priv->display.get_cdclk = icl_get_cdclk;
+	else if (IS_CANNONLAKE(dev_priv))
 		dev_priv->display.get_cdclk = cnl_get_cdclk;
 	else if (IS_GEN9_BC(dev_priv))
 		dev_priv->display.get_cdclk = skl_get_cdclk;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 9f31aea51dff..391dd69ae0a4 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -304,9 +304,6 @@ intel_crt_mode_valid(struct drm_connector *connector,
 	int max_dotclk = dev_priv->max_dotclk_freq;
 	int max_clock;
 
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		return MODE_NO_DBLESCAN;
-
 	if (mode->clock < 25000)
 		return MODE_CLOCK_LOW;
 
@@ -477,14 +474,6 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
 	return ret;
 }
 
-/**
- * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
- *
- * Not for i915G/i915GM
- *
- * \return true if CRT is connected.
- * \return false if CRT is disconnected.
- */
 static bool intel_crt_detect_hotplug(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
@@ -810,10 +799,11 @@ intel_crt_detect(struct drm_connector *connector,
 		else
 			status = connector_status_unknown;
 		intel_release_load_detect_pipe(connector, &tmp, ctx);
-	} else if (ret == 0)
+	} else if (ret == 0) {
 		status = connector_status_unknown;
-	else if (ret < 0)
+	} else {
 		status = ret;
+	}
 
 out:
 	intel_display_power_put(dev_priv, intel_encoder->power_domain);
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index 7fe4aac0facc..41e6c75a7f3c 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -37,8 +37,9 @@
 #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin"
 #define GLK_CSR_VERSION_REQUIRED	CSR_VERSION(1, 4)
 
-#define I915_CSR_CNL "i915/cnl_dmc_ver1_06.bin"
-#define CNL_CSR_VERSION_REQUIRED	CSR_VERSION(1, 6)
+#define I915_CSR_CNL "i915/cnl_dmc_ver1_07.bin"
+MODULE_FIRMWARE(I915_CSR_CNL);
+#define CNL_CSR_VERSION_REQUIRED	CSR_VERSION(1, 7)
 
 #define I915_CSR_KBL "i915/kbl_dmc_ver1_04.bin"
 MODULE_FIRMWARE(I915_CSR_KBL);
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index f51645a08dca..8ca376aca8bd 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1615,6 +1615,35 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
 	I915_WRITE(reg, val);
 }
 
+int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
+				     bool enable)
+{
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum pipe pipe = 0;
+	int ret = 0;
+	uint32_t tmp;
+
+	if (WARN_ON(!intel_display_power_get_if_enabled(dev_priv,
+						intel_encoder->power_domain)))
+		return -ENXIO;
+
+	if (WARN_ON(!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
+		ret = -EIO;
+		goto out;
+	}
+
+	tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe));
+	if (enable)
+		tmp |= TRANS_DDI_HDCP_SIGNALLING;
+	else
+		tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
+	I915_WRITE(TRANS_DDI_FUNC_CTL(pipe), tmp);
+out:
+	intel_display_power_put(dev_priv, intel_encoder->power_domain);
+	return ret;
+}
+
 bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
 {
 	struct drm_device *dev = intel_connector->base.dev;
@@ -2123,7 +2152,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,
 
 		I915_WRITE(DPLL_CTRL2, val);
 
-	} else if (INTEL_INFO(dev_priv)->gen < 9) {
+	} else if (INTEL_GEN(dev_priv) < 9) {
 		I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
 	}
 
@@ -2404,6 +2433,48 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
 					  crtc_state->hdmi_high_tmds_clock_ratio,
 					  crtc_state->hdmi_scrambling);
 
+	/* Display WA #1143: skl,kbl,cfl */
+	if (IS_GEN9_BC(dev_priv)) {
+		/*
+		 * For some reason these chicken bits have been
+		 * stuffed into a transcoder register, event though
+		 * the bits affect a specific DDI port rather than
+		 * a specific transcoder.
+		 */
+		static const enum transcoder port_to_transcoder[] = {
+			[PORT_A] = TRANSCODER_EDP,
+			[PORT_B] = TRANSCODER_A,
+			[PORT_C] = TRANSCODER_B,
+			[PORT_D] = TRANSCODER_C,
+			[PORT_E] = TRANSCODER_A,
+		};
+		enum transcoder transcoder = port_to_transcoder[port];
+		u32 val;
+
+		val = I915_READ(CHICKEN_TRANS(transcoder));
+
+		if (port == PORT_E)
+			val |= DDIE_TRAINING_OVERRIDE_ENABLE |
+				DDIE_TRAINING_OVERRIDE_VALUE;
+		else
+			val |= DDI_TRAINING_OVERRIDE_ENABLE |
+				DDI_TRAINING_OVERRIDE_VALUE;
+
+		I915_WRITE(CHICKEN_TRANS(transcoder), val);
+		POSTING_READ(CHICKEN_TRANS(transcoder));
+
+		udelay(1);
+
+		if (port == PORT_E)
+			val &= ~(DDIE_TRAINING_OVERRIDE_ENABLE |
+				 DDIE_TRAINING_OVERRIDE_VALUE);
+		else
+			val &= ~(DDI_TRAINING_OVERRIDE_ENABLE |
+				 DDI_TRAINING_OVERRIDE_VALUE);
+
+		I915_WRITE(CHICKEN_TRANS(transcoder), val);
+	}
+
 	/* In HDMI/DVI mode, the port width, and swing/emphasis values
 	 * are ignored so nothing special needs to be done besides
 	 * enabling the port.
@@ -2423,6 +2494,11 @@ static void intel_enable_ddi(struct intel_encoder *encoder,
 		intel_enable_ddi_hdmi(encoder, crtc_state, conn_state);
 	else
 		intel_enable_ddi_dp(encoder, crtc_state, conn_state);
+
+	/* Enable hdcp if it's desired */
+	if (conn_state->content_protection ==
+	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
+		intel_hdcp_enable(to_intel_connector(conn_state->connector));
 }
 
 static void intel_disable_ddi_dp(struct intel_encoder *encoder,
@@ -2457,6 +2533,8 @@ static void intel_disable_ddi(struct intel_encoder *encoder,
 			      const struct intel_crtc_state *old_crtc_state,
 			      const struct drm_connector_state *old_conn_state)
 {
+	intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
+
 	if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
 		intel_disable_ddi_hdmi(encoder, old_crtc_state, old_conn_state);
 	else
@@ -2868,6 +2946,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 		intel_dig_port->ddi_io_power_domain =
 			POWER_DOMAIN_PORT_DDI_E_IO;
 		break;
+	case PORT_F:
+		intel_dig_port->ddi_io_power_domain =
+			POWER_DOMAIN_PORT_DDI_F_IO;
+		break;
 	default:
 		MISSING_CASE(port);
 	}
diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
index d28592e43512..298f8996cc54 100644
--- a/drivers/gpu/drm/i915/intel_device_info.c
+++ b/drivers/gpu/drm/i915/intel_device_info.c
@@ -56,6 +56,7 @@ static const char * const platform_names[] = {
 	PLATFORM_NAME(GEMINILAKE),
 	PLATFORM_NAME(COFFEELAKE),
 	PLATFORM_NAME(CANNONLAKE),
+	PLATFORM_NAME(ICELAKE),
 };
 #undef PLATFORM_NAME
 
@@ -585,3 +586,9 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
 	/* Initialize command stream timestamp frequency */
 	info->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv);
 }
+
+void intel_driver_caps_print(const struct intel_driver_caps *caps,
+			     struct drm_printer *p)
+{
+	drm_printf(p, "scheduler: %x\n", caps->scheduler);
+}
diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h
index 49cb27bd04c1..71fdfb0451ef 100644
--- a/drivers/gpu/drm/i915/intel_device_info.h
+++ b/drivers/gpu/drm/i915/intel_device_info.h
@@ -69,6 +69,8 @@ enum intel_platform {
 	INTEL_COFFEELAKE,
 	/* gen10 */
 	INTEL_CANNONLAKE,
+	/* gen11 */
+	INTEL_ICELAKE,
 	INTEL_MAX_PLATFORMS
 };
 
@@ -165,6 +167,10 @@ struct intel_device_info {
 	} color;
 };
 
+struct intel_driver_caps {
+	unsigned int scheduler;
+};
+
 static inline unsigned int sseu_subslice_total(const struct sseu_dev_info *sseu)
 {
 	return hweight8(sseu->slice_mask) * hweight8(sseu->subslice_mask);
@@ -180,4 +186,7 @@ void intel_device_info_dump_flags(const struct intel_device_info *info,
 void intel_device_info_dump_runtime(const struct intel_device_info *info,
 				    struct drm_printer *p);
 
+void intel_driver_caps_print(const struct intel_driver_caps *caps,
+			     struct drm_printer *p);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f288bcc7be22..280c04326f64 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -558,11 +558,11 @@ int chv_calc_dpll_params(int refclk, struct dpll *clock)
 }
 
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
-/**
+
+/*
  * Returns whether the given set of divisors are valid for a given refclk with
  * the given connectors.
  */
-
 static bool intel_PLL_is_valid(struct drm_i915_private *dev_priv,
 			       const struct intel_limit *limit,
 			       const struct dpll *clock)
@@ -2029,12 +2029,12 @@ static unsigned int intel_cursor_alignment(const struct drm_i915_private *dev_pr
 
 static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
 {
-	if (INTEL_INFO(dev_priv)->gen >= 9)
+	if (INTEL_GEN(dev_priv) >= 9)
 		return 256 * 1024;
 	else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
 		 IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 		return 128 * 1024;
-	else if (INTEL_INFO(dev_priv)->gen >= 4)
+	else if (INTEL_GEN(dev_priv) >= 4)
 		return 4 * 1024;
 	else
 		return 0;
@@ -2387,6 +2387,20 @@ static unsigned int intel_fb_modifier_to_tiling(uint64_t fb_modifier)
 	}
 }
 
+/*
+ * From the Sky Lake PRM:
+ * "The Color Control Surface (CCS) contains the compression status of
+ *  the cache-line pairs. The compression state of the cache-line pair
+ *  is specified by 2 bits in the CCS. Each CCS cache-line represents
+ *  an area on the main surface of 16 x16 sets of 128 byte Y-tiled
+ *  cache-line-pairs. CCS is always Y tiled."
+ *
+ * Since cache line pairs refers to horizontally adjacent cache lines,
+ * each cache line in the CCS corresponds to an area of 32x16 cache
+ * lines on the main surface. Since each pixel is 4 bytes, this gives
+ * us a ratio of one byte in the CCS for each 8x16 pixels in the
+ * main surface.
+ */
 static const struct drm_format_info ccs_formats[] = {
 	{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
 	{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
@@ -2917,14 +2931,19 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
 	return true;
 }
 
-static int skl_check_main_surface(struct intel_plane_state *plane_state)
+static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
+				  struct intel_plane_state *plane_state)
 {
+	struct drm_i915_private *dev_priv =
+		to_i915(plane_state->base.plane->dev);
 	const struct drm_framebuffer *fb = plane_state->base.fb;
 	unsigned int rotation = plane_state->base.rotation;
 	int x = plane_state->base.src.x1 >> 16;
 	int y = plane_state->base.src.y1 >> 16;
 	int w = drm_rect_width(&plane_state->base.src) >> 16;
 	int h = drm_rect_height(&plane_state->base.src) >> 16;
+	int dst_x = plane_state->base.dst.x1;
+	int pipe_src_w = crtc_state->pipe_src_w;
 	int max_width = skl_max_plane_width(fb, 0, rotation);
 	int max_height = 4096;
 	u32 alignment, offset, aux_offset = plane_state->aux.offset;
@@ -2935,6 +2954,24 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
 		return -EINVAL;
 	}
 
+	/*
+	 * Display WA #1175: cnl,glk
+	 * Planes other than the cursor may cause FIFO underflow and display
+	 * corruption if starting less than 4 pixels from the right edge of
+	 * the screen.
+	 * Besides the above WA fix the similar problem, where planes other
+	 * than the cursor ending less than 4 pixels from the left edge of the
+	 * screen may cause FIFO underflow and display corruption.
+	 */
+	if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
+	    (dst_x + w < 4 || dst_x > pipe_src_w - 4)) {
+		DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n",
+			      dst_x + w < 4 ? "end" : "start",
+			      dst_x + w < 4 ? dst_x + w : dst_x,
+			      4, pipe_src_w - 4);
+		return -ERANGE;
+	}
+
 	intel_add_fb_offsets(&x, &y, plane_state, 0);
 	offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
 	alignment = intel_surf_alignment(fb, 0);
@@ -3027,6 +3064,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
 static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
 {
 	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 	struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc);
 	const struct drm_framebuffer *fb = plane_state->base.fb;
 	int src_x = plane_state->base.src.x1 >> 16;
@@ -3037,17 +3075,8 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
 	int y = src_y / vsub;
 	u32 offset;
 
-	switch (plane->id) {
-	case PLANE_PRIMARY:
-	case PLANE_SPRITE0:
-		break;
-	default:
-		DRM_DEBUG_KMS("RC support only on plane 1 and 2\n");
-		return -EINVAL;
-	}
-
-	if (crtc->pipe == PIPE_C) {
-		DRM_DEBUG_KMS("No RC support on pipe C\n");
+	if (!skl_plane_has_ccs(dev_priv, crtc->pipe, plane->id)) {
+		DRM_DEBUG_KMS("No RC support on %s\n", plane->base.name);
 		return -EINVAL;
 	}
 
@@ -3067,7 +3096,8 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
 	return 0;
 }
 
-int skl_check_plane_surface(struct intel_plane_state *plane_state)
+int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
+			    struct intel_plane_state *plane_state)
 {
 	const struct drm_framebuffer *fb = plane_state->base.fb;
 	unsigned int rotation = plane_state->base.rotation;
@@ -3107,7 +3137,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
 		plane_state->aux.y = 0;
 	}
 
-	ret = skl_check_main_surface(plane_state);
+	ret = skl_check_main_surface(crtc_state, plane_state);
 	if (ret)
 		return ret;
 
@@ -4726,8 +4756,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
 
 /**
  * skl_update_scaler_plane - Stages update to scaler state for a given plane.
- *
- * @state: crtc's scaler state
+ * @crtc_state: crtc's scaler state
  * @plane_state: atomic plane state to update
  *
  * Return
@@ -4757,7 +4786,7 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
 		return ret;
 
 	/* check colorkey */
-	if (plane_state->ckey.flags != I915_SET_COLORKEY_NONE) {
+	if (plane_state->ckey.flags) {
 		DRM_DEBUG_KMS("[PLANE:%d:%s] scaling with color key not allowed",
 			      intel_plane->base.base.id,
 			      intel_plane->base.name);
@@ -4924,6 +4953,7 @@ static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc)
 /**
  * intel_post_enable_primary - Perform operations after enabling primary plane
  * @crtc: the CRTC whose primary plane was just enabled
+ * @new_crtc_state: the enabling state
  *
  * Performs potentially sleeping operations that must be done after the primary
  * plane is enabled, such as updating FBC and IPS.  Note that this may be
@@ -5388,6 +5418,20 @@ static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
 	I915_WRITE(CLKGATE_DIS_PSL(pipe), val);
 }
 
+static void icl_pipe_mbus_enable(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	enum pipe pipe = crtc->pipe;
+	uint32_t val;
+
+	val = MBUS_DBOX_BW_CREDIT(1) | MBUS_DBOX_A_CREDIT(2);
+
+	/* Program B credit equally to all pipes */
+	val |= MBUS_DBOX_B_CREDIT(24 / INTEL_INFO(dev_priv)->num_pipes);
+
+	I915_WRITE(PIPE_MBUS_DBOX_CTL(pipe), val);
+}
+
 static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 				struct drm_atomic_state *old_state)
 {
@@ -5465,6 +5509,9 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 	if (dev_priv->display.initial_watermarks != NULL)
 		dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
 
+	if (INTEL_GEN(dev_priv) >= 11)
+		icl_pipe_mbus_enable(intel_crtc);
+
 	/* XXX: Do the pipe assertions at the right place for BXT DSI. */
 	if (!transcoder_is_dsi(cpu_transcoder))
 		intel_enable_pipe(pipe_config);
@@ -5641,6 +5688,8 @@ enum intel_display_power_domain intel_port_to_power_domain(enum port port)
 		return POWER_DOMAIN_PORT_DDI_D_LANES;
 	case PORT_E:
 		return POWER_DOMAIN_PORT_DDI_E_LANES;
+	case PORT_F:
+		return POWER_DOMAIN_PORT_DDI_F_LANES;
 	default:
 		MISSING_CASE(port);
 		return POWER_DOMAIN_PORT_OTHER;
@@ -6275,7 +6324,7 @@ static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
 	const struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
 	/* GDG double wide on either pipe, otherwise pipe A only */
-	return INTEL_INFO(dev_priv)->gen < 4 &&
+	return INTEL_GEN(dev_priv) < 4 &&
 		(crtc->pipe == PIPE_A || IS_I915G(dev_priv));
 }
 
@@ -6372,9 +6421,18 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
 	 * - LVDS dual channel mode
 	 * - Double wide pipe
 	 */
-	if ((intel_crtc_has_type(pipe_config, INTEL_OUTPUT_LVDS) &&
-	     intel_is_dual_link_lvds(dev)) || pipe_config->double_wide)
-		pipe_config->pipe_src_w &= ~1;
+	if (pipe_config->pipe_src_w & 1) {
+		if (pipe_config->double_wide) {
+			DRM_DEBUG_KMS("Odd pipe source width not supported with double wide pipe\n");
+			return -EINVAL;
+		}
+
+		if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_LVDS) &&
+		    intel_is_dual_link_lvds(dev)) {
+			DRM_DEBUG_KMS("Odd pipe source width not supported with dual link LVDS\n");
+			return -EINVAL;
+		}
+	}
 
 	/* Cantiga+ cannot handle modes with a hsync front porch of 0.
 	 * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
@@ -8153,7 +8211,7 @@ static void haswell_set_pipemisc(struct drm_crtc *crtc)
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_crtc_state *config = intel_crtc->config;
 
-	if (IS_BROADWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 9) {
+	if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
 		u32 val = 0;
 
 		switch (intel_crtc->config->pipe_bpp) {
@@ -8495,7 +8553,10 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc,
 
 	val = I915_READ(PLANE_CTL(pipe, plane_id));
 
-	pixel_format = val & PLANE_CTL_FORMAT_MASK;
+	if (INTEL_GEN(dev_priv) >= 11)
+		pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK;
+	else
+		pixel_format = val & PLANE_CTL_FORMAT_MASK;
 
 	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
 		alpha = I915_READ(PLANE_COLOR_CTL(pipe, plane_id));
@@ -9308,13 +9369,18 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
 			      struct intel_plane_state *plane_state)
 {
 	const struct drm_framebuffer *fb = plane_state->base.fb;
+	struct drm_rect clip = {};
 	int src_x, src_y;
 	u32 offset;
 	int ret;
 
+	if (crtc_state->base.enable)
+		drm_mode_get_hv_timing(&crtc_state->base.mode,
+				       &clip.x2, &clip.y2);
+
 	ret = drm_atomic_helper_check_plane_state(&plane_state->base,
 						  &crtc_state->base,
-						  &plane_state->clip,
+						  &clip,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  true, true);
@@ -10653,6 +10719,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
 	struct drm_connector_list_iter conn_iter;
 	unsigned int used_ports = 0;
 	unsigned int used_mst_ports = 0;
+	bool ret = true;
 
 	/*
 	 * Walk the connector list instead of the encoder
@@ -10687,7 +10754,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
 
 			/* the same port mustn't appear more than once */
 			if (used_ports & port_mask)
-				return false;
+				ret = false;
 
 			used_ports |= port_mask;
 			break;
@@ -10705,7 +10772,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
 	if (used_ports & used_mst_ports)
 		return false;
 
-	return true;
+	return ret;
 }
 
 static void
@@ -12026,7 +12093,7 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
 	struct drm_device *dev = crtc->base.dev;
 
 	if (!dev->max_vblank_count)
-		return drm_crtc_accurate_vblank_count(&crtc->base);
+		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
 
 	return dev->driver->get_vblank_counter(dev, crtc->pipe);
 }
@@ -12519,7 +12586,13 @@ static int do_rps_boost(struct wait_queue_entry *_wait,
 	struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait);
 	struct drm_i915_gem_request *rq = wait->request;
 
-	gen6_rps_boost(rq, NULL);
+	/*
+	 * If we missed the vblank, but the request is already running it
+	 * is reasonable to assume that it will complete before the next
+	 * vblank without our intervention, so leave RPS alone.
+	 */
+	if (!i915_gem_request_started(rq))
+		gen6_rps_boost(rq, NULL);
 	i915_gem_request_put(rq);
 
 	drm_crtc_vblank_put(wait->crtc);
@@ -12561,7 +12634,7 @@ static void add_rps_boost_after_vblank(struct drm_crtc *crtc,
 /**
  * intel_prepare_plane_fb - Prepare fb for usage on plane
  * @plane: drm plane to prepare for
- * @fb: framebuffer to prepare for presentation
+ * @new_state: the plane state being prepared
  *
  * Prepares a framebuffer for usage on a display plane.  Generally this
  * involves pinning the underlying object and updating the frontbuffer tracking
@@ -12679,7 +12752,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 /**
  * intel_cleanup_plane_fb - Cleans up an fb after plane use
  * @plane: drm plane to clean up for
- * @fb: old framebuffer that was on plane
+ * @old_state: the state from the previous modeset
  *
  * Cleans up a framebuffer that has just been removed from a plane.
  *
@@ -12743,20 +12816,25 @@ intel_check_primary_plane(struct intel_plane *plane,
 	int min_scale = DRM_PLANE_HELPER_NO_SCALING;
 	int max_scale = DRM_PLANE_HELPER_NO_SCALING;
 	bool can_position = false;
+	struct drm_rect clip = {};
 	int ret;
 
 	if (INTEL_GEN(dev_priv) >= 9) {
 		/* use scaler when colorkey is not required */
-		if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
+		if (!state->ckey.flags) {
 			min_scale = 1;
 			max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state);
 		}
 		can_position = true;
 	}
 
+	if (crtc_state->base.enable)
+		drm_mode_get_hv_timing(&crtc_state->base.mode,
+				       &clip.x2, &clip.y2);
+
 	ret = drm_atomic_helper_check_plane_state(&state->base,
 						  &crtc_state->base,
-						  &state->clip,
+						  &clip,
 						  min_scale, max_scale,
 						  can_position, true);
 	if (ret)
@@ -12766,7 +12844,7 @@ intel_check_primary_plane(struct intel_plane *plane,
 		return 0;
 
 	if (INTEL_GEN(dev_priv) >= 9) {
-		ret = skl_check_plane_surface(state);
+		ret = skl_check_plane_surface(crtc_state, state);
 		if (ret)
 			return ret;
 
@@ -12944,8 +13022,6 @@ static bool intel_primary_plane_format_mod_supported(struct drm_plane *plane,
 		return i965_mod_supported(format, modifier);
 	else
 		return i8xx_mod_supported(format, modifier);
-
-	unreachable();
 }
 
 static bool intel_cursor_plane_format_mod_supported(struct drm_plane *plane,
@@ -13153,21 +13229,14 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 	else
 		primary->i9xx_plane = (enum i9xx_plane_id) pipe;
 	primary->id = PLANE_PRIMARY;
-	primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe);
+	primary->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, primary->id);
 	primary->check_plane = intel_check_primary_plane;
 
-	if (INTEL_GEN(dev_priv) >= 10) {
+	if (INTEL_GEN(dev_priv) >= 9) {
 		intel_primary_formats = skl_primary_formats;
 		num_formats = ARRAY_SIZE(skl_primary_formats);
-		modifiers = skl_format_modifiers_ccs;
 
-		primary->update_plane = skl_update_plane;
-		primary->disable_plane = skl_disable_plane;
-		primary->get_hw_state = skl_plane_get_hw_state;
-	} else if (INTEL_GEN(dev_priv) >= 9) {
-		intel_primary_formats = skl_primary_formats;
-		num_formats = ARRAY_SIZE(skl_primary_formats);
-		if (pipe < PIPE_C)
+		if (skl_plane_has_ccs(dev_priv, pipe, PLANE_PRIMARY))
 			modifiers = skl_format_modifiers_ccs;
 		else
 			modifiers = skl_format_modifiers_noccs;
@@ -13281,7 +13350,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
 	cursor->pipe = pipe;
 	cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
 	cursor->id = PLANE_CURSOR;
-	cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe);
+	cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
 
 	if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
 		cursor->update_plane = i845_update_cursor;
@@ -13447,8 +13516,8 @@ enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
 	return to_intel_crtc(connector->base.state->crtc)->pipe;
 }
 
-int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
-				struct drm_file *file)
+int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file)
 {
 	struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
 	struct drm_crtc *drmmode_crtc;
@@ -13597,7 +13666,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
 		if (found || IS_GEN9_BC(dev_priv))
 			intel_ddi_init(dev_priv, PORT_A);
 
-		/* DDI B, C and D detection is indicated by the SFUSE_STRAP
+		/* DDI B, C, D, and F detection is indicated by the SFUSE_STRAP
 		 * register */
 		found = I915_READ(SFUSE_STRAP);
 
@@ -13607,6 +13676,8 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
 			intel_ddi_init(dev_priv, PORT_C);
 		if (found & SFUSE_STRAP_DDID_DETECTED)
 			intel_ddi_init(dev_priv, PORT_D);
+		if (found & SFUSE_STRAP_DDIF_DETECTED)
+			intel_ddi_init(dev_priv, PORT_F);
 		/*
 		 * On SKL we don't have a way to detect DDI-E so we rely on VBT.
 		 */
@@ -13894,7 +13965,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
 	 * gen2/3 display engine uses the fence if present,
 	 * so the tiling mode must match the fb modifier exactly.
 	 */
-	if (INTEL_INFO(dev_priv)->gen < 4 &&
+	if (INTEL_GEN(dev_priv) < 4 &&
 	    tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
 		DRM_DEBUG_KMS("tiling_mode must match fb modifier exactly on gen2/3\n");
 		goto err;
@@ -14063,10 +14134,37 @@ static void intel_atomic_state_free(struct drm_atomic_state *state)
 	kfree(state);
 }
 
+static enum drm_mode_status
+intel_mode_valid(struct drm_device *dev,
+		 const struct drm_display_mode *mode)
+{
+	if (mode->vscan > 1)
+		return MODE_NO_VSCAN;
+
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
+	if (mode->flags & DRM_MODE_FLAG_HSKEW)
+		return MODE_H_ILLEGAL;
+
+	if (mode->flags & (DRM_MODE_FLAG_CSYNC |
+			   DRM_MODE_FLAG_NCSYNC |
+			   DRM_MODE_FLAG_PCSYNC))
+		return MODE_HSYNC;
+
+	if (mode->flags & (DRM_MODE_FLAG_BCAST |
+			   DRM_MODE_FLAG_PIXMUX |
+			   DRM_MODE_FLAG_CLKDIV2))
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
 static const struct drm_mode_config_funcs intel_mode_funcs = {
 	.fb_create = intel_user_framebuffer_create,
 	.get_format_info = intel_get_format_info,
 	.output_poll_changed = intel_fbdev_output_poll_changed,
+	.mode_valid = intel_mode_valid,
 	.atomic_check = intel_atomic_check,
 	.atomic_commit = intel_atomic_commit,
 	.atomic_state_alloc = intel_atomic_state_alloc,
@@ -14082,7 +14180,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 {
 	intel_init_cdclk_hooks(dev_priv);
 
-	if (INTEL_INFO(dev_priv)->gen >= 9) {
+	if (INTEL_GEN(dev_priv) >= 9) {
 		dev_priv->display.get_pipe_config = haswell_get_pipe_config;
 		dev_priv->display.get_initial_plane_config =
 			skylake_get_initial_plane_config;
@@ -15217,6 +15315,10 @@ static void intel_hpd_poll_fini(struct drm_device *dev)
 	for_each_intel_connector_iter(connector, &conn_iter) {
 		if (connector->modeset_retry_work.func)
 			cancel_work_sync(&connector->modeset_retry_work);
+		if (connector->hdcp_shim) {
+			cancel_delayed_work_sync(&connector->hdcp_check_work);
+			cancel_work_sync(&connector->hdcp_prop_work);
+		}
 	}
 	drm_connector_list_iter_end(&conn_iter);
 }
diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h
index a0d2b6169361..c4042e342f50 100644
--- a/drivers/gpu/drm/i915/intel_display.h
+++ b/drivers/gpu/drm/i915/intel_display.h
@@ -119,6 +119,7 @@ enum port {
 	PORT_C,
 	PORT_D,
 	PORT_E,
+	PORT_F,
 
 	I915_MAX_PORTS
 };
@@ -156,11 +157,13 @@ enum intel_display_power_domain {
 	POWER_DOMAIN_PORT_DDI_C_LANES,
 	POWER_DOMAIN_PORT_DDI_D_LANES,
 	POWER_DOMAIN_PORT_DDI_E_LANES,
+	POWER_DOMAIN_PORT_DDI_F_LANES,
 	POWER_DOMAIN_PORT_DDI_A_IO,
 	POWER_DOMAIN_PORT_DDI_B_IO,
 	POWER_DOMAIN_PORT_DDI_C_IO,
 	POWER_DOMAIN_PORT_DDI_D_IO,
 	POWER_DOMAIN_PORT_DDI_E_IO,
+	POWER_DOMAIN_PORT_DDI_F_IO,
 	POWER_DOMAIN_PORT_DSI,
 	POWER_DOMAIN_PORT_CRT,
 	POWER_DOMAIN_PORT_OTHER,
@@ -171,6 +174,7 @@ enum intel_display_power_domain {
 	POWER_DOMAIN_AUX_B,
 	POWER_DOMAIN_AUX_C,
 	POWER_DOMAIN_AUX_D,
+	POWER_DOMAIN_AUX_F,
 	POWER_DOMAIN_GMBUS,
 	POWER_DOMAIN_MODESET,
 	POWER_DOMAIN_GT_IRQ,
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 35c5299feab6..f20b25f98e5a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -36,7 +36,9 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_hdcp.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -155,6 +157,28 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
 	intel_dp->num_sink_rates = i;
 }
 
+/* Get length of rates array potentially limited by max_rate. */
+static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate)
+{
+	int i;
+
+	/* Limit results by potentially reduced max rate */
+	for (i = 0; i < len; i++) {
+		if (rates[len - i - 1] <= max_rate)
+			return len - i;
+	}
+
+	return 0;
+}
+
+/* Get length of common rates array potentially limited by max_rate. */
+static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
+					  int max_rate)
+{
+	return intel_dp_rate_limit_len(intel_dp->common_rates,
+				       intel_dp->num_common_rates, max_rate);
+}
+
 /* Theoretical max between source and sink */
 static int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 {
@@ -218,15 +242,38 @@ intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
 	return max_dotclk;
 }
 
+static int cnl_max_source_rate(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	enum port port = dig_port->base.port;
+
+	u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
+
+	/* Low voltage SKUs are limited to max of 5.4G */
+	if (voltage == VOLTAGE_INFO_0_85V)
+		return 540000;
+
+	/* For this SKU 8.1G is supported in all ports */
+	if (IS_CNL_WITH_PORT_F(dev_priv))
+		return 810000;
+
+	/* For other SKUs, max rate on ports A and D is 5.4G */
+	if (port == PORT_A || port == PORT_D)
+		return 540000;
+
+	return 810000;
+}
+
 static void
 intel_dp_set_source_rates(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-	enum port port = dig_port->base.port;
+	const struct ddi_vbt_port_info *info =
+		&dev_priv->vbt.ddi_port_info[dig_port->base.port];
 	const int *source_rates;
-	int size;
-	u32 voltage;
+	int size, max_rate = 0, vbt_max_rate = info->dp_max_link_rate;
 
 	/* This should only be done once */
 	WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates);
@@ -237,10 +284,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
 	} else if (IS_CANNONLAKE(dev_priv)) {
 		source_rates = cnl_rates;
 		size = ARRAY_SIZE(cnl_rates);
-		voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
-		if (port == PORT_A || port == PORT_D ||
-		    voltage == VOLTAGE_INFO_0_85V)
-			size -= 2;
+		max_rate = cnl_max_source_rate(intel_dp);
 	} else if (IS_GEN9_BC(dev_priv)) {
 		source_rates = skl_rates;
 		size = ARRAY_SIZE(skl_rates);
@@ -253,6 +297,14 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp)
 		size = ARRAY_SIZE(default_rates) - 1;
 	}
 
+	if (max_rate && vbt_max_rate)
+		max_rate = min(max_rate, vbt_max_rate);
+	else if (vbt_max_rate)
+		max_rate = vbt_max_rate;
+
+	if (max_rate)
+		size = intel_dp_rate_limit_len(source_rates, size, max_rate);
+
 	intel_dp->source_rates = source_rates;
 	intel_dp->num_source_rates = size;
 }
@@ -309,22 +361,6 @@ static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
 	}
 }
 
-/* get length of common rates potentially limited by max_rate */
-static int intel_dp_common_len_rate_limit(struct intel_dp *intel_dp,
-					  int max_rate)
-{
-	const int *common_rates = intel_dp->common_rates;
-	int i, common_len = intel_dp->num_common_rates;
-
-	/* Limit results by potentially reduced max rate */
-	for (i = 0; i < common_len; i++) {
-		if (common_rates[common_len - i - 1] <= max_rate)
-			return common_len - i;
-	}
-
-	return 0;
-}
-
 static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
 				       uint8_t lane_count)
 {
@@ -794,7 +830,8 @@ static void intel_pps_get_registers(struct intel_dp *intel_dp,
 	regs->pp_stat = PP_STATUS(pps_idx);
 	regs->pp_on = PP_ON_DELAYS(pps_idx);
 	regs->pp_off = PP_OFF_DELAYS(pps_idx);
-	if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv))
+	if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv) &&
+	    !HAS_PCH_ICP(dev_priv))
 		regs->pp_div = PP_DIVISOR(pps_idx);
 }
 
@@ -1025,10 +1062,29 @@ static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp,
 	       DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
 }
 
+static uint32_t intel_dp_get_aux_send_ctl(struct intel_dp *intel_dp,
+					  bool has_aux_irq,
+					  int send_bytes,
+					  uint32_t aux_clock_divider,
+					  bool aksv_write)
+{
+	uint32_t val = 0;
+
+	if (aksv_write) {
+		send_bytes += 5;
+		val |= DP_AUX_CH_CTL_AUX_AKSV_SELECT;
+	}
+
+	return val | intel_dp->get_aux_send_ctl(intel_dp,
+						has_aux_irq,
+						send_bytes,
+						aux_clock_divider);
+}
+
 static int
 intel_dp_aux_ch(struct intel_dp *intel_dp,
 		const uint8_t *send, int send_bytes,
-		uint8_t *recv, int recv_size)
+		uint8_t *recv, int recv_size, bool aksv_write)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_i915_private *dev_priv =
@@ -1088,10 +1144,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 	}
 
 	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
-		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
-							  has_aux_irq,
-							  send_bytes,
-							  aux_clock_divider);
+		u32 send_ctl = intel_dp_get_aux_send_ctl(intel_dp,
+							 has_aux_irq,
+							 send_bytes,
+							 aux_clock_divider,
+							 aksv_write);
 
 		/* Must try at least 3 times according to DP spec */
 		for (try = 0; try < 5; try++) {
@@ -1228,7 +1285,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 		if (msg->buffer)
 			memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
 
-		ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
+		ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize,
+				      false);
 		if (ret > 0) {
 			msg->reply = rxbuf[0] >> 4;
 
@@ -1250,7 +1308,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 		if (WARN_ON(rxsize > 20))
 			return -E2BIG;
 
-		ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
+		ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize,
+				      false);
 		if (ret > 0) {
 			msg->reply = rxbuf[0] >> 4;
 			/*
@@ -1298,6 +1357,9 @@ static enum port intel_aux_port(struct drm_i915_private *dev_priv,
 	case DP_AUX_D:
 		aux_port = PORT_D;
 		break;
+	case DP_AUX_F:
+		aux_port = PORT_F;
+		break;
 	default:
 		MISSING_CASE(info->alternate_aux_channel);
 		aux_port = PORT_A;
@@ -1378,6 +1440,7 @@ static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
 	case PORT_B:
 	case PORT_C:
 	case PORT_D:
+	case PORT_F:
 		return DP_AUX_CH_CTL(port);
 	default:
 		MISSING_CASE(port);
@@ -1393,6 +1456,7 @@ static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
 	case PORT_B:
 	case PORT_C:
 	case PORT_D:
+	case PORT_F:
 		return DP_AUX_CH_DATA(port, index);
 	default:
 		MISSING_CASE(port);
@@ -1403,7 +1467,7 @@ static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
 static i915_reg_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv,
 				    enum port port)
 {
-	if (INTEL_INFO(dev_priv)->gen >= 9)
+	if (INTEL_GEN(dev_priv) >= 9)
 		return skl_aux_ctl_reg(dev_priv, port);
 	else if (HAS_PCH_SPLIT(dev_priv))
 		return ilk_aux_ctl_reg(dev_priv, port);
@@ -1414,7 +1478,7 @@ static i915_reg_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv,
 static i915_reg_t intel_aux_data_reg(struct drm_i915_private *dev_priv,
 				     enum port port, int index)
 {
-	if (INTEL_INFO(dev_priv)->gen >= 9)
+	if (INTEL_GEN(dev_priv) >= 9)
 		return skl_aux_data_reg(dev_priv, port, index);
 	else if (HAS_PCH_SPLIT(dev_priv))
 		return ilk_aux_data_reg(dev_priv, port, index);
@@ -4455,173 +4519,174 @@ edp_detect(struct intel_dp *intel_dp)
 	return status;
 }
 
-static bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool ibx_digital_port_connected(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 bit;
 
-	switch (port->base.port) {
-	case PORT_B:
+	switch (encoder->hpd_pin) {
+	case HPD_PORT_B:
 		bit = SDE_PORTB_HOTPLUG;
 		break;
-	case PORT_C:
+	case HPD_PORT_C:
 		bit = SDE_PORTC_HOTPLUG;
 		break;
-	case PORT_D:
+	case HPD_PORT_D:
 		bit = SDE_PORTD_HOTPLUG;
 		break;
 	default:
-		MISSING_CASE(port->base.port);
+		MISSING_CASE(encoder->hpd_pin);
 		return false;
 	}
 
 	return I915_READ(SDEISR) & bit;
 }
 
-static bool cpt_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool cpt_digital_port_connected(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 bit;
 
-	switch (port->base.port) {
-	case PORT_B:
+	switch (encoder->hpd_pin) {
+	case HPD_PORT_B:
 		bit = SDE_PORTB_HOTPLUG_CPT;
 		break;
-	case PORT_C:
+	case HPD_PORT_C:
 		bit = SDE_PORTC_HOTPLUG_CPT;
 		break;
-	case PORT_D:
+	case HPD_PORT_D:
 		bit = SDE_PORTD_HOTPLUG_CPT;
 		break;
 	default:
-		MISSING_CASE(port->base.port);
+		MISSING_CASE(encoder->hpd_pin);
 		return false;
 	}
 
 	return I915_READ(SDEISR) & bit;
 }
 
-static bool spt_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool spt_digital_port_connected(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 bit;
 
-	switch (port->base.port) {
-	case PORT_A:
+	switch (encoder->hpd_pin) {
+	case HPD_PORT_A:
 		bit = SDE_PORTA_HOTPLUG_SPT;
 		break;
-	case PORT_E:
+	case HPD_PORT_E:
 		bit = SDE_PORTE_HOTPLUG_SPT;
 		break;
 	default:
-		return cpt_digital_port_connected(dev_priv, port);
+		return cpt_digital_port_connected(encoder);
 	}
 
 	return I915_READ(SDEISR) & bit;
 }
 
-static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool g4x_digital_port_connected(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 bit;
 
-	switch (port->base.port) {
-	case PORT_B:
+	switch (encoder->hpd_pin) {
+	case HPD_PORT_B:
 		bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
 		break;
-	case PORT_C:
+	case HPD_PORT_C:
 		bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
 		break;
-	case PORT_D:
+	case HPD_PORT_D:
 		bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
 		break;
 	default:
-		MISSING_CASE(port->base.port);
+		MISSING_CASE(encoder->hpd_pin);
 		return false;
 	}
 
 	return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
-static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv,
-					struct intel_digital_port *port)
+static bool gm45_digital_port_connected(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 bit;
 
-	switch (port->base.port) {
-	case PORT_B:
+	switch (encoder->hpd_pin) {
+	case HPD_PORT_B:
 		bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
 		break;
-	case PORT_C:
+	case HPD_PORT_C:
 		bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
 		break;
-	case PORT_D:
+	case HPD_PORT_D:
 		bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
 		break;
 	default:
-		MISSING_CASE(port->base.port);
+		MISSING_CASE(encoder->hpd_pin);
 		return false;
 	}
 
 	return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
-static bool ilk_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool ilk_digital_port_connected(struct intel_encoder *encoder)
 {
-	if (port->base.port == PORT_A)
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+	if (encoder->hpd_pin == HPD_PORT_A)
 		return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
 	else
-		return ibx_digital_port_connected(dev_priv, port);
+		return ibx_digital_port_connected(encoder);
 }
 
-static bool snb_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool snb_digital_port_connected(struct intel_encoder *encoder)
 {
-	if (port->base.port == PORT_A)
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+	if (encoder->hpd_pin == HPD_PORT_A)
 		return I915_READ(DEISR) & DE_DP_A_HOTPLUG;
 	else
-		return cpt_digital_port_connected(dev_priv, port);
+		return cpt_digital_port_connected(encoder);
 }
 
-static bool ivb_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool ivb_digital_port_connected(struct intel_encoder *encoder)
 {
-	if (port->base.port == PORT_A)
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+	if (encoder->hpd_pin == HPD_PORT_A)
 		return I915_READ(DEISR) & DE_DP_A_HOTPLUG_IVB;
 	else
-		return cpt_digital_port_connected(dev_priv, port);
+		return cpt_digital_port_connected(encoder);
 }
 
-static bool bdw_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *port)
+static bool bdw_digital_port_connected(struct intel_encoder *encoder)
 {
-	if (port->base.port == PORT_A)
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+	if (encoder->hpd_pin == HPD_PORT_A)
 		return I915_READ(GEN8_DE_PORT_ISR) & GEN8_PORT_DP_A_HOTPLUG;
 	else
-		return cpt_digital_port_connected(dev_priv, port);
+		return cpt_digital_port_connected(encoder);
 }
 
-static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
-				       struct intel_digital_port *intel_dig_port)
+static bool bxt_digital_port_connected(struct intel_encoder *encoder)
 {
-	struct intel_encoder *intel_encoder = &intel_dig_port->base;
-	enum port port;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 bit;
 
-	port = intel_hpd_pin_to_port(intel_encoder->hpd_pin);
-	switch (port) {
-	case PORT_A:
+	switch (encoder->hpd_pin) {
+	case HPD_PORT_A:
 		bit = BXT_DE_PORT_HP_DDIA;
 		break;
-	case PORT_B:
+	case HPD_PORT_B:
 		bit = BXT_DE_PORT_HP_DDIB;
 		break;
-	case PORT_C:
+	case HPD_PORT_C:
 		bit = BXT_DE_PORT_HP_DDIC;
 		break;
 	default:
-		MISSING_CASE(port);
+		MISSING_CASE(encoder->hpd_pin);
 		return false;
 	}
 
@@ -4630,33 +4695,33 @@ static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
 
 /*
  * intel_digital_port_connected - is the specified port connected?
- * @dev_priv: i915 private structure
- * @port: the port to test
+ * @encoder: intel_encoder
  *
- * Return %true if @port is connected, %false otherwise.
+ * Return %true if port is connected, %false otherwise.
  */
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
-				  struct intel_digital_port *port)
+bool intel_digital_port_connected(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
 	if (HAS_GMCH_DISPLAY(dev_priv)) {
 		if (IS_GM45(dev_priv))
-			return gm45_digital_port_connected(dev_priv, port);
+			return gm45_digital_port_connected(encoder);
 		else
-			return g4x_digital_port_connected(dev_priv, port);
+			return g4x_digital_port_connected(encoder);
 	}
 
 	if (IS_GEN5(dev_priv))
-		return ilk_digital_port_connected(dev_priv, port);
+		return ilk_digital_port_connected(encoder);
 	else if (IS_GEN6(dev_priv))
-		return snb_digital_port_connected(dev_priv, port);
+		return snb_digital_port_connected(encoder);
 	else if (IS_GEN7(dev_priv))
-		return ivb_digital_port_connected(dev_priv, port);
+		return ivb_digital_port_connected(encoder);
 	else if (IS_GEN8(dev_priv))
-		return bdw_digital_port_connected(dev_priv, port);
+		return bdw_digital_port_connected(encoder);
 	else if (IS_GEN9_LP(dev_priv))
-		return bxt_digital_port_connected(dev_priv, port);
+		return bxt_digital_port_connected(encoder);
 	else
-		return spt_digital_port_connected(dev_priv, port);
+		return spt_digital_port_connected(encoder);
 }
 
 static struct edid *
@@ -4715,8 +4780,7 @@ intel_dp_long_pulse(struct intel_connector *connector)
 	/* Can't disconnect eDP, but you can close the lid... */
 	if (intel_dp_is_edp(intel_dp))
 		status = edp_detect(intel_dp);
-	else if (intel_digital_port_connected(dev_priv,
-					      dp_to_dig_port(intel_dp)))
+	else if (intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base))
 		status = intel_dp_detect_dpcd(intel_dp);
 	else
 		status = connector_status_disconnected;
@@ -4985,6 +5049,236 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
 	pps_unlock(intel_dp);
 }
 
+static
+int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
+				u8 *an)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_dig_port->base.base);
+	uint8_t txbuf[4], rxbuf[2], reply = 0;
+	ssize_t dpcd_ret;
+	int ret;
+
+	/* Output An first, that's easy */
+	dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AN,
+				     an, DRM_HDCP_AN_LEN);
+	if (dpcd_ret != DRM_HDCP_AN_LEN) {
+		DRM_ERROR("Failed to write An over DP/AUX (%zd)\n", dpcd_ret);
+		return dpcd_ret >= 0 ? -EIO : dpcd_ret;
+	}
+
+	/*
+	 * Since Aksv is Oh-So-Secret, we can't access it in software. So in
+	 * order to get it on the wire, we need to create the AUX header as if
+	 * we were writing the data, and then tickle the hardware to output the
+	 * data once the header is sent out.
+	 */
+	txbuf[0] = (DP_AUX_NATIVE_WRITE << 4) |
+		   ((DP_AUX_HDCP_AKSV >> 16) & 0xf);
+	txbuf[1] = (DP_AUX_HDCP_AKSV >> 8) & 0xff;
+	txbuf[2] = DP_AUX_HDCP_AKSV & 0xff;
+	txbuf[3] = DRM_HDCP_KSV_LEN - 1;
+
+	ret = intel_dp_aux_ch(intel_dp, txbuf, sizeof(txbuf), rxbuf,
+			      sizeof(rxbuf), true);
+	if (ret < 0) {
+		DRM_ERROR("Write Aksv over DP/AUX failed (%d)\n", ret);
+		return ret;
+	} else if (ret == 0) {
+		DRM_ERROR("Aksv write over DP/AUX was empty\n");
+		return -EIO;
+	}
+
+	reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK;
+	return reply == DP_AUX_NATIVE_REPLY_ACK ? 0 : -EIO;
+}
+
+static int intel_dp_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
+				   u8 *bksv)
+{
+	ssize_t ret;
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
+			       DRM_HDCP_KSV_LEN);
+	if (ret != DRM_HDCP_KSV_LEN) {
+		DRM_ERROR("Read Bksv from DP/AUX failed (%zd)\n", ret);
+		return ret >= 0 ? -EIO : ret;
+	}
+	return 0;
+}
+
+static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
+				      u8 *bstatus)
+{
+	ssize_t ret;
+	/*
+	 * For some reason the HDMI and DP HDCP specs call this register
+	 * definition by different names. In the HDMI spec, it's called BSTATUS,
+	 * but in DP it's called BINFO.
+	 */
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BINFO,
+			       bstatus, DRM_HDCP_BSTATUS_LEN);
+	if (ret != DRM_HDCP_BSTATUS_LEN) {
+		DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
+		return ret >= 0 ? -EIO : ret;
+	}
+	return 0;
+}
+
+static
+int intel_dp_hdcp_read_bcaps(struct intel_digital_port *intel_dig_port,
+			     u8 *bcaps)
+{
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
+			       bcaps, 1);
+	if (ret != 1) {
+		DRM_ERROR("Read bcaps from DP/AUX failed (%zd)\n", ret);
+		return ret >= 0 ? -EIO : ret;
+	}
+
+	return 0;
+}
+
+static
+int intel_dp_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
+				   bool *repeater_present)
+{
+	ssize_t ret;
+	u8 bcaps;
+
+	ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
+	if (ret)
+		return ret;
+
+	*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
+	return 0;
+}
+
+static
+int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
+				u8 *ri_prime)
+{
+	ssize_t ret;
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
+			       ri_prime, DRM_HDCP_RI_LEN);
+	if (ret != DRM_HDCP_RI_LEN) {
+		DRM_ERROR("Read Ri' from DP/AUX failed (%zd)\n", ret);
+		return ret >= 0 ? -EIO : ret;
+	}
+	return 0;
+}
+
+static
+int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
+				 bool *ksv_ready)
+{
+	ssize_t ret;
+	u8 bstatus;
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
+			       &bstatus, 1);
+	if (ret != 1) {
+		DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
+		return ret >= 0 ? -EIO : ret;
+	}
+	*ksv_ready = bstatus & DP_BSTATUS_READY;
+	return 0;
+}
+
+static
+int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
+				int num_downstream, u8 *ksv_fifo)
+{
+	ssize_t ret;
+	int i;
+
+	/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
+	for (i = 0; i < num_downstream; i += 3) {
+		size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
+		ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+				       DP_AUX_HDCP_KSV_FIFO,
+				       ksv_fifo + i * DRM_HDCP_KSV_LEN,
+				       len);
+		if (ret != len) {
+			DRM_ERROR("Read ksv[%d] from DP/AUX failed (%zd)\n", i,
+				  ret);
+			return ret >= 0 ? -EIO : ret;
+		}
+	}
+	return 0;
+}
+
+static
+int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
+				    int i, u32 *part)
+{
+	ssize_t ret;
+
+	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
+		return -EINVAL;
+
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
+			       DP_AUX_HDCP_V_PRIME(i), part,
+			       DRM_HDCP_V_PRIME_PART_LEN);
+	if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
+		DRM_ERROR("Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
+		return ret >= 0 ? -EIO : ret;
+	}
+	return 0;
+}
+
+static
+int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
+				    bool enable)
+{
+	/* Not used for single stream DisplayPort setups */
+	return 0;
+}
+
+static
+bool intel_dp_hdcp_check_link(struct intel_digital_port *intel_dig_port)
+{
+	ssize_t ret;
+	u8 bstatus;
+
+	ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
+			       &bstatus, 1);
+	if (ret != 1) {
+		DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
+		return false;
+	}
+
+	return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
+}
+
+static
+int intel_dp_hdcp_capable(struct intel_digital_port *intel_dig_port,
+			  bool *hdcp_capable)
+{
+	ssize_t ret;
+	u8 bcaps;
+
+	ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
+	if (ret)
+		return ret;
+
+	*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
+	return 0;
+}
+
+static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
+	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
+	.read_bksv = intel_dp_hdcp_read_bksv,
+	.read_bstatus = intel_dp_hdcp_read_bstatus,
+	.repeater_present = intel_dp_hdcp_repeater_present,
+	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
+	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
+	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
+	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
+	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
+	.check_link = intel_dp_hdcp_check_link,
+	.hdcp_capable = intel_dp_hdcp_capable,
+};
+
 static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
 {
 	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
@@ -5150,6 +5444,9 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 		drm_modeset_acquire_fini(&ctx);
 		WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
 
+		/* Short pulse can signify loss of hdcp authentication */
+		intel_hdcp_check_link(intel_dp->attached_connector);
+
 		if (!handled) {
 			intel_dp->detect_done = false;
 			goto put_power;
@@ -5227,7 +5524,8 @@ intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq)
 
 	pp_on = I915_READ(regs.pp_on);
 	pp_off = I915_READ(regs.pp_off);
-	if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv)) {
+	if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv) &&
+	    !HAS_PCH_ICP(dev_priv)) {
 		I915_WRITE(regs.pp_ctrl, pp_ctl);
 		pp_div = I915_READ(regs.pp_div);
 	}
@@ -5245,7 +5543,8 @@ intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq)
 	seq->t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >>
 		   PANEL_POWER_DOWN_DELAY_SHIFT;
 
-	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) {
+	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) ||
+	    HAS_PCH_ICP(dev_priv)) {
 		seq->t11_t12 = ((pp_ctl & BXT_POWER_CYCLE_DELAY_MASK) >>
 				BXT_POWER_CYCLE_DELAY_SHIFT) * 1000;
 	} else {
@@ -5416,7 +5715,8 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
 		 (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
 	/* Compute the divisor for the pp clock, simply match the Bspec
 	 * formula. */
-	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) {
+	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) ||
+	    HAS_PCH_ICP(dev_priv)) {
 		pp_div = I915_READ(regs.pp_ctrl);
 		pp_div &= ~BXT_POWER_CYCLE_DELAY_MASK;
 		pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000)
@@ -5442,7 +5742,8 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
 
 	I915_WRITE(regs.pp_on, pp_on);
 	I915_WRITE(regs.pp_off, pp_off);
-	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv))
+	if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) ||
+	    HAS_PCH_ICP(dev_priv))
 		I915_WRITE(regs.pp_ctrl, pp_div);
 	else
 		I915_WRITE(regs.pp_div, pp_div);
@@ -5450,7 +5751,8 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp,
 	DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
 		      I915_READ(regs.pp_on),
 		      I915_READ(regs.pp_off),
-		      (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) ?
+		      (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)  ||
+		       HAS_PCH_ICP(dev_priv)) ?
 		      (I915_READ(regs.pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK) :
 		      I915_READ(regs.pp_div));
 }
@@ -5970,8 +6272,10 @@ intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port)
 {
 	struct intel_encoder *encoder = &intel_dig_port->base;
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
 
-	encoder->hpd_pin = intel_hpd_pin(encoder->port);
+	encoder->hpd_pin = intel_hpd_pin_default(dev_priv, encoder->port);
 
 	switch (encoder->port) {
 	case PORT_A:
@@ -5990,6 +6294,9 @@ intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port)
 		/* FIXME: Check VBT for actual wiring of PORT E */
 		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_D;
 		break;
+	case PORT_F:
+		intel_dp->aux_power_domain = POWER_DOMAIN_AUX_F;
+		break;
 	default:
 		MISSING_CASE(encoder->port);
 	}
@@ -6116,7 +6423,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 
 	/* init MST on ports that can support it */
 	if (HAS_DP_MST(dev_priv) && !intel_dp_is_edp(intel_dp) &&
-	    (port == PORT_B || port == PORT_C || port == PORT_D))
+	    (port == PORT_B || port == PORT_C ||
+	     port == PORT_D || port == PORT_F))
 		intel_dp_mst_encoder_init(intel_dig_port,
 					  intel_connector->base.base.id);
 
@@ -6128,6 +6436,12 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 
 	intel_dp_add_properties(intel_dp, connector);
 
+	if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) {
+		int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim);
+		if (ret)
+			DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
+	}
+
 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
 	 * 0xd.  Failure to do so will result in spurious interrupts being
 	 * generated on the port when a cable is not attached.
diff --git a/drivers/gpu/drm/i915/intel_dpio_phy.c b/drivers/gpu/drm/i915/intel_dpio_phy.c
index 76473e9836c6..c8e9e44e5981 100644
--- a/drivers/gpu/drm/i915/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/intel_dpio_phy.c
@@ -147,7 +147,7 @@ struct bxt_ddi_phy_info {
 	 */
 	struct {
 		/**
-		 * @port: which port maps to this channel.
+		 * @channel.port: which port maps to this channel.
 		 */
 		enum port port;
 	} channel[2];
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 30f791f89d64..898064e8bea7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -41,20 +41,21 @@
 #include <drm/drm_atomic.h>
 
 /**
- * _wait_for - magic (register) wait macro
+ * __wait_for - magic wait macro
  *
- * Does the right thing for modeset paths when run under kdgb or similar atomic
- * contexts. Note that it's important that we check the condition again after
- * having timed out, since the timeout could be due to preemption or similar and
- * we've never had a chance to check the condition before the timeout.
+ * Macro to help avoid open coding check/wait/timeout patterns. Note that it's
+ * important that we check the condition again after having timed out, since the
+ * timeout could be due to preemption or similar and we've never had a chance to
+ * check the condition before the timeout.
  */
-#define _wait_for(COND, US, Wmin, Wmax) ({ \
+#define __wait_for(OP, COND, US, Wmin, Wmax) ({ \
 	unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1;	\
 	long wait__ = (Wmin); /* recommended min for usleep is 10 us */	\
 	int ret__;							\
 	might_sleep();							\
 	for (;;) {							\
 		bool expired__ = time_after(jiffies, timeout__);	\
+		OP;							\
 		if (COND) {						\
 			ret__ = 0;					\
 			break;						\
@@ -70,7 +71,9 @@
 	ret__;								\
 })
 
-#define wait_for(COND, MS)	_wait_for((COND), (MS) * 1000, 10, 1000)
+#define _wait_for(COND, US, Wmin, Wmax)	__wait_for(, (COND), (US), (Wmin), \
+						   (Wmax))
+#define wait_for(COND, MS)		_wait_for((COND), (MS) * 1000, 10, 1000)
 
 /* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */
 #if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT)
@@ -298,6 +301,80 @@ struct intel_panel {
 	} backlight;
 };
 
+/*
+ * This structure serves as a translation layer between the generic HDCP code
+ * and the bus-specific code. What that means is that HDCP over HDMI differs
+ * from HDCP over DP, so to account for these differences, we need to
+ * communicate with the receiver through this shim.
+ *
+ * For completeness, the 2 buses differ in the following ways:
+ *	- DP AUX vs. DDC
+ *		HDCP registers on the receiver are set via DP AUX for DP, and
+ *		they are set via DDC for HDMI.
+ *	- Receiver register offsets
+ *		The offsets of the registers are different for DP vs. HDMI
+ *	- Receiver register masks/offsets
+ *		For instance, the ready bit for the KSV fifo is in a different
+ *		place on DP vs HDMI
+ *	- Receiver register names
+ *		Seriously. In the DP spec, the 16-bit register containing
+ *		downstream information is called BINFO, on HDMI it's called
+ *		BSTATUS. To confuse matters further, DP has a BSTATUS register
+ *		with a completely different definition.
+ *	- KSV FIFO
+ *		On HDMI, the ksv fifo is read all at once, whereas on DP it must
+ *		be read 3 keys at a time
+ *	- Aksv output
+ *		Since Aksv is hidden in hardware, there's different procedures
+ *		to send it over DP AUX vs DDC
+ */
+struct intel_hdcp_shim {
+	/* Outputs the transmitter's An and Aksv values to the receiver. */
+	int (*write_an_aksv)(struct intel_digital_port *intel_dig_port, u8 *an);
+
+	/* Reads the receiver's key selection vector */
+	int (*read_bksv)(struct intel_digital_port *intel_dig_port, u8 *bksv);
+
+	/*
+	 * Reads BINFO from DP receivers and BSTATUS from HDMI receivers. The
+	 * definitions are the same in the respective specs, but the names are
+	 * different. Call it BSTATUS since that's the name the HDMI spec
+	 * uses and it was there first.
+	 */
+	int (*read_bstatus)(struct intel_digital_port *intel_dig_port,
+			    u8 *bstatus);
+
+	/* Determines whether a repeater is present downstream */
+	int (*repeater_present)(struct intel_digital_port *intel_dig_port,
+				bool *repeater_present);
+
+	/* Reads the receiver's Ri' value */
+	int (*read_ri_prime)(struct intel_digital_port *intel_dig_port, u8 *ri);
+
+	/* Determines if the receiver's KSV FIFO is ready for consumption */
+	int (*read_ksv_ready)(struct intel_digital_port *intel_dig_port,
+			      bool *ksv_ready);
+
+	/* Reads the ksv fifo for num_downstream devices */
+	int (*read_ksv_fifo)(struct intel_digital_port *intel_dig_port,
+			     int num_downstream, u8 *ksv_fifo);
+
+	/* Reads a 32-bit part of V' from the receiver */
+	int (*read_v_prime_part)(struct intel_digital_port *intel_dig_port,
+				 int i, u32 *part);
+
+	/* Enables HDCP signalling on the port */
+	int (*toggle_signalling)(struct intel_digital_port *intel_dig_port,
+				 bool enable);
+
+	/* Ensures the link is still protected */
+	bool (*check_link)(struct intel_digital_port *intel_dig_port);
+
+	/* Detects panel's hdcp capability. This is optional for HDMI. */
+	int (*hdcp_capable)(struct intel_digital_port *intel_dig_port,
+			    bool *hdcp_capable);
+};
+
 struct intel_connector {
 	struct drm_connector base;
 	/*
@@ -329,6 +406,12 @@ struct intel_connector {
 
 	/* Work struct to schedule a uevent on link train failure */
 	struct work_struct modeset_retry_work;
+
+	const struct intel_hdcp_shim *hdcp_shim;
+	struct mutex hdcp_mutex;
+	uint64_t hdcp_value; /* protected by hdcp_mutex */
+	struct delayed_work hdcp_check_work;
+	struct work_struct hdcp_prop_work;
 };
 
 struct intel_digital_connector_state {
@@ -406,7 +489,6 @@ struct intel_atomic_state {
 
 struct intel_plane_state {
 	struct drm_plane_state base;
-	struct drm_rect clip;
 	struct i915_vma *vma;
 
 	struct {
@@ -1298,6 +1380,8 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
 u32 bxt_signal_levels(struct intel_dp *intel_dp);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder);
+int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
+				     bool enable);
 
 unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
 				   int plane, unsigned int height);
@@ -1323,6 +1407,8 @@ void cnl_init_cdclk(struct drm_i915_private *dev_priv);
 void cnl_uninit_cdclk(struct drm_i915_private *dev_priv);
 void bxt_init_cdclk(struct drm_i915_private *dev_priv);
 void bxt_uninit_cdclk(struct drm_i915_private *dev_priv);
+void icl_init_cdclk(struct drm_i915_private *dev_priv);
+void icl_uninit_cdclk(struct drm_i915_private *dev_priv);
 void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv);
 void intel_update_max_cdclk(struct drm_i915_private *dev_priv);
 void intel_update_cdclk(struct drm_i915_private *dev_priv);
@@ -1371,8 +1457,8 @@ struct drm_display_mode *
 intel_encoder_current_mode(struct intel_encoder *encoder);
 
 enum pipe intel_get_pipe_from_connector(struct intel_connector *connector);
-int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
-				struct drm_file *file_priv);
+int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file_priv);
 enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
 					     enum pipe pipe);
 static inline bool
@@ -1507,7 +1593,8 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
 		  const struct intel_plane_state *plane_state);
 u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
 		     unsigned int rotation);
-int skl_check_plane_surface(struct intel_plane_state *plane_state);
+int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
+			    struct intel_plane_state *plane_state);
 int i9xx_check_plane_surface(struct intel_plane_state *plane_state);
 
 /* intel_csr.c */
@@ -1590,8 +1677,7 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
 bool intel_dp_read_dpcd(struct intel_dp *intel_dp);
 int intel_dp_link_required(int pixel_clock, int bpp);
 int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
-				  struct intel_digital_port *port);
+bool intel_digital_port_connected(struct intel_encoder *encoder);
 
 /* intel_dp_aux_backlight.c */
 int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector);
@@ -1758,8 +1844,19 @@ static inline void intel_backlight_device_unregister(struct intel_connector *con
 }
 #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
 
+/* intel_hdcp.c */
+void intel_hdcp_atomic_check(struct drm_connector *connector,
+			     struct drm_connector_state *old_state,
+			     struct drm_connector_state *new_state);
+int intel_hdcp_init(struct intel_connector *connector,
+		    const struct intel_hdcp_shim *hdcp_shim);
+int intel_hdcp_enable(struct intel_connector *connector);
+int intel_hdcp_disable(struct intel_connector *connector);
+int intel_hdcp_check_link(struct intel_connector *connector);
+bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
 
 /* intel_psr.c */
+#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
 void intel_psr_enable(struct intel_dp *intel_dp,
 		      const struct intel_crtc_state *crtc_state);
 void intel_psr_disable(struct intel_dp *intel_dp,
@@ -1923,8 +2020,8 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
 			     int usecs);
 struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 					      enum pipe pipe, int plane);
-int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
-			      struct drm_file *file_priv);
+int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv);
 void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state);
 void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state);
 void skl_update_plane(struct intel_plane *plane,
@@ -1932,6 +2029,8 @@ void skl_update_plane(struct intel_plane *plane,
 		      const struct intel_plane_state *plane_state);
 void skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc);
 bool skl_plane_get_hw_state(struct intel_plane *plane);
+bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
+		       enum pipe pipe, enum plane_id plane_id);
 
 /* intel_tv.c */
 void intel_tv_init(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index f67d321376e4..51a1d6868b1e 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -1266,11 +1266,6 @@ intel_dsi_mode_valid(struct drm_connector *connector,
 
 	DRM_DEBUG_KMS("\n");
 
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
-		DRM_DEBUG_KMS("MODE_NO_DBLESCAN\n");
-		return MODE_NO_DBLESCAN;
-	}
-
 	if (fixed_mode) {
 		if (mode->hdisplay > fixed_mode->hdisplay)
 			return MODE_PANEL;
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 754baa00bea9..eb0c559b2715 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -219,9 +219,6 @@ intel_dvo_mode_valid(struct drm_connector *connector,
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
 	int target_clock = mode->clock;
 
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		return MODE_NO_DBLESCAN;
-
 	/* XXX: Validate clock range */
 
 	if (fixed_mode) {
@@ -248,7 +245,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
 		intel_dvo->attached_connector->panel.fixed_mode;
 	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 
-	/* If we have timings from the BIOS for the panel, put them in
+	/*
+	 * If we have timings from the BIOS for the panel, put them in
 	 * to the adjusted mode.  The CRTC will be set up for this mode,
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
@@ -296,11 +294,6 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder,
 	I915_WRITE(dvo_reg, dvo_val);
 }
 
-/**
- * Detect the output connection on our DVO device.
- *
- * Unimplemented.
- */
 static enum drm_connector_status
 intel_dvo_detect(struct drm_connector *connector, bool force)
 {
@@ -316,7 +309,8 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
 	const struct drm_display_mode *fixed_mode =
 		to_intel_connector(connector)->panel.fixed_mode;
 
-	/* We should probably have an i2c driver get_modes function for those
+	/*
+	 * We should probably have an i2c driver get_modes function for those
 	 * devices which will have a fixed set of modes determined by the chip
 	 * (TV-out, for example), but for now with just TMDS and LVDS,
 	 * that's not the case.
@@ -374,7 +368,7 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
 	.destroy = intel_dvo_enc_destroy,
 };
 
-/**
+/*
  * Attempts to get a fixed panel timing for LVDS (currently only the i830).
  *
  * Other chips with DVO LVDS will need to extend this to deal with the LVDS
@@ -446,7 +440,8 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
 		uint32_t dpll[I915_MAX_PIPES];
 		enum port port;
 
-		/* Allow the I2C driver info to specify the GPIO to be used in
+		/*
+		 * Allow the I2C driver info to specify the GPIO to be used in
 		 * special cases, but otherwise default to what's defined
 		 * in the spec.
 		 */
@@ -457,7 +452,8 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
 		else
 			gpio = GMBUS_PIN_DPB;
 
-		/* Set up the I2C bus necessary for the chip we're probing.
+		/*
+		 * Set up the I2C bus necessary for the chip we're probing.
 		 * It appears that everything is on GPIOE except for panels
 		 * on i830 laptops, which are on GPIOB (DVOA).
 		 */
@@ -465,12 +461,14 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
 
 		intel_dvo->dev = *dvo;
 
-		/* GMBUS NAK handling seems to be unstable, hence let the
+		/*
+		 * GMBUS NAK handling seems to be unstable, hence let the
 		 * transmitter detection run in bit banging mode for now.
 		 */
 		intel_gmbus_force_bit(i2c, true);
 
-		/* ns2501 requires the DVO 2x clock before it will
+		/*
+		 * ns2501 requires the DVO 2x clock before it will
 		 * respond to i2c accesses, so make sure we have
 		 * have the clock enabled before we attempt to
 		 * initialize the device.
@@ -528,7 +526,8 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
 
 		intel_connector_attach_encoder(intel_connector, intel_encoder);
 		if (dvo->type == INTEL_DVO_CHIP_LVDS) {
-			/* For our LVDS chipsets, we should hopefully be able
+			/*
+			 * For our LVDS chipsets, we should hopefully be able
 			 * to dig the fixed panel mode out of the BIOS data.
 			 * However, it's in a different format from the BIOS
 			 * data on chipsets with integrated LVDS (stored in AIM
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index fa960cfd2764..f3c5100d629e 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -38,9 +38,11 @@
  */
 #define HSW_CXT_TOTAL_SIZE		(17 * PAGE_SIZE)
 
+#define DEFAULT_LR_CONTEXT_RENDER_SIZE	(22 * PAGE_SIZE)
 #define GEN8_LR_CONTEXT_RENDER_SIZE	(20 * PAGE_SIZE)
 #define GEN9_LR_CONTEXT_RENDER_SIZE	(22 * PAGE_SIZE)
 #define GEN10_LR_CONTEXT_RENDER_SIZE	(18 * PAGE_SIZE)
+#define GEN11_LR_CONTEXT_RENDER_SIZE	(14 * PAGE_SIZE)
 
 #define GEN8_LR_CONTEXT_OTHER_SIZE	( 2 * PAGE_SIZE)
 
@@ -157,6 +159,9 @@ __intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class)
 		switch (INTEL_GEN(dev_priv)) {
 		default:
 			MISSING_CASE(INTEL_GEN(dev_priv));
+			return DEFAULT_LR_CONTEXT_RENDER_SIZE;
+		case 11:
+			return GEN11_LR_CONTEXT_RENDER_SIZE;
 		case 10:
 			return GEN10_LR_CONTEXT_RENDER_SIZE;
 		case 9:
@@ -626,7 +631,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
 	 * Similarly the preempt context must always be available so that
 	 * we can interrupt the engine at any time.
 	 */
-	if (HAS_LOGICAL_RING_PREEMPTION(engine->i915)) {
+	if (engine->i915->preempt_context) {
 		ring = engine->context_pin(engine,
 					   engine->i915->preempt_context);
 		if (IS_ERR(ring)) {
@@ -651,7 +656,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
 err_breadcrumbs:
 	intel_engine_fini_breadcrumbs(engine);
 err_unpin_preempt:
-	if (HAS_LOGICAL_RING_PREEMPTION(engine->i915))
+	if (engine->i915->preempt_context)
 		engine->context_unpin(engine, engine->i915->preempt_context);
 err_unpin_kernel:
 	engine->context_unpin(engine, engine->i915->kernel_context);
@@ -681,12 +686,12 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
 	if (engine->default_state)
 		i915_gem_object_put(engine->default_state);
 
-	if (HAS_LOGICAL_RING_PREEMPTION(engine->i915))
+	if (engine->i915->preempt_context)
 		engine->context_unpin(engine, engine->i915->preempt_context);
 	engine->context_unpin(engine, engine->i915->kernel_context);
 }
 
-u64 intel_engine_get_active_head(struct intel_engine_cs *engine)
+u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
 {
 	struct drm_i915_private *dev_priv = engine->i915;
 	u64 acthd;
@@ -702,7 +707,7 @@ u64 intel_engine_get_active_head(struct intel_engine_cs *engine)
 	return acthd;
 }
 
-u64 intel_engine_get_last_batch_head(struct intel_engine_cs *engine)
+u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine)
 {
 	struct drm_i915_private *dev_priv = engine->i915;
 	u64 bbaddr;
@@ -1389,7 +1394,8 @@ int init_workarounds_ring(struct intel_engine_cs *engine)
 	struct drm_i915_private *dev_priv = engine->i915;
 	int err;
 
-	WARN_ON(engine->id != RCS);
+	if (GEM_WARN_ON(engine->id != RCS))
+		return -EINVAL;
 
 	dev_priv->workarounds.count = 0;
 	dev_priv->workarounds.hw_whitelist_count[engine->id] = 0;
@@ -1499,10 +1505,6 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine)
 	if (I915_SELFTEST_ONLY(engine->breadcrumbs.mock))
 		return true;
 
-	/* Interrupt/tasklet pending? */
-	if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted))
-		return false;
-
 	/* Waiting to drain ELSP? */
 	if (READ_ONCE(engine->execlists.active))
 		return false;
@@ -1703,73 +1705,20 @@ static void hexdump(struct drm_printer *m, const void *buf, size_t len)
 	}
 }
 
-void intel_engine_dump(struct intel_engine_cs *engine,
-		       struct drm_printer *m,
-		       const char *header, ...)
+static void intel_engine_print_registers(const struct intel_engine_cs *engine,
+					 struct drm_printer *m)
 {
-	struct intel_breadcrumbs * const b = &engine->breadcrumbs;
-	const struct intel_engine_execlists * const execlists = &engine->execlists;
-	struct i915_gpu_error * const error = &engine->i915->gpu_error;
 	struct drm_i915_private *dev_priv = engine->i915;
-	struct drm_i915_gem_request *rq;
-	struct rb_node *rb;
-	char hdr[80];
+	const struct intel_engine_execlists * const execlists =
+		&engine->execlists;
 	u64 addr;
 
-	if (header) {
-		va_list ap;
-
-		va_start(ap, header);
-		drm_vprintf(m, header, &ap);
-		va_end(ap);
-	}
-
-	if (i915_terminally_wedged(&engine->i915->gpu_error))
-		drm_printf(m, "*** WEDGED ***\n");
-
-	drm_printf(m, "\tcurrent seqno %x, last %x, hangcheck %x [%d ms], inflight %d\n",
-		   intel_engine_get_seqno(engine),
-		   intel_engine_last_submit(engine),
-		   engine->hangcheck.seqno,
-		   jiffies_to_msecs(jiffies - engine->hangcheck.action_timestamp),
-		   engine->timeline->inflight_seqnos);
-	drm_printf(m, "\tReset count: %d (global %d)\n",
-		   i915_reset_engine_count(error, engine),
-		   i915_reset_count(error));
-
-	rcu_read_lock();
-
-	drm_printf(m, "\tRequests:\n");
-
-	rq = list_first_entry(&engine->timeline->requests,
-			      struct drm_i915_gem_request, link);
-	if (&rq->link != &engine->timeline->requests)
-		print_request(m, rq, "\t\tfirst  ");
-
-	rq = list_last_entry(&engine->timeline->requests,
-			     struct drm_i915_gem_request, link);
-	if (&rq->link != &engine->timeline->requests)
-		print_request(m, rq, "\t\tlast   ");
-
-	rq = i915_gem_find_active_request(engine);
-	if (rq) {
-		print_request(m, rq, "\t\tactive ");
-		drm_printf(m,
-			   "\t\t[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]\n",
-			   rq->head, rq->postfix, rq->tail,
-			   rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u,
-			   rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u);
-	}
-
-	drm_printf(m, "\tRING_START: 0x%08x [0x%08x]\n",
-		   I915_READ(RING_START(engine->mmio_base)),
-		   rq ? i915_ggtt_offset(rq->ring->vma) : 0);
-	drm_printf(m, "\tRING_HEAD:  0x%08x [0x%08x]\n",
-		   I915_READ(RING_HEAD(engine->mmio_base)) & HEAD_ADDR,
-		   rq ? rq->ring->head : 0);
-	drm_printf(m, "\tRING_TAIL:  0x%08x [0x%08x]\n",
-		   I915_READ(RING_TAIL(engine->mmio_base)) & TAIL_ADDR,
-		   rq ? rq->ring->tail : 0);
+	drm_printf(m, "\tRING_START: 0x%08x\n",
+		   I915_READ(RING_START(engine->mmio_base)));
+	drm_printf(m, "\tRING_HEAD:  0x%08x\n",
+		   I915_READ(RING_HEAD(engine->mmio_base)) & HEAD_ADDR);
+	drm_printf(m, "\tRING_TAIL:  0x%08x\n",
+		   I915_READ(RING_TAIL(engine->mmio_base)) & TAIL_ADDR);
 	drm_printf(m, "\tRING_CTL:   0x%08x%s\n",
 		   I915_READ(RING_CTL(engine->mmio_base)),
 		   I915_READ(RING_CTL(engine->mmio_base)) & (RING_WAIT | RING_WAIT_SEMAPHORE) ? " [waiting]" : "");
@@ -1778,6 +1727,11 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 			   I915_READ(RING_MI_MODE(engine->mmio_base)),
 			   I915_READ(RING_MI_MODE(engine->mmio_base)) & (MODE_IDLE) ? " [idle]" : "");
 	}
+
+	if (INTEL_GEN(dev_priv) >= 6) {
+		drm_printf(m, "\tRING_IMR: %08x\n", I915_READ_IMR(engine));
+	}
+
 	if (HAS_LEGACY_SEMAPHORES(dev_priv)) {
 		drm_printf(m, "\tSYNC_0: 0x%08x\n",
 			   I915_READ(RING_SYNC_0(engine->mmio_base)));
@@ -1788,8 +1742,6 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 				   I915_READ(RING_SYNC_2(engine->mmio_base)));
 	}
 
-	rcu_read_unlock();
-
 	addr = intel_engine_get_active_head(engine);
 	drm_printf(m, "\tACTHD:  0x%08x_%08x\n",
 		   upper_32_bits(addr), lower_32_bits(addr));
@@ -1851,10 +1803,13 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 
 		rcu_read_lock();
 		for (idx = 0; idx < execlists_num_ports(execlists); idx++) {
+			struct drm_i915_gem_request *rq;
 			unsigned int count;
 
 			rq = port_unpack(&execlists->port[idx], &count);
 			if (rq) {
+				char hdr[80];
+
 				snprintf(hdr, sizeof(hdr),
 					 "\t\tELSP[%d] count=%d, rq: ",
 					 idx, count);
@@ -1873,6 +1828,77 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 		drm_printf(m, "\tPP_DIR_DCLV: 0x%08x\n",
 			   I915_READ(RING_PP_DIR_DCLV(engine)));
 	}
+}
+
+void intel_engine_dump(struct intel_engine_cs *engine,
+		       struct drm_printer *m,
+		       const char *header, ...)
+{
+	struct intel_breadcrumbs * const b = &engine->breadcrumbs;
+	const struct intel_engine_execlists * const execlists = &engine->execlists;
+	struct i915_gpu_error * const error = &engine->i915->gpu_error;
+	struct drm_i915_gem_request *rq;
+	struct rb_node *rb;
+
+	if (header) {
+		va_list ap;
+
+		va_start(ap, header);
+		drm_vprintf(m, header, &ap);
+		va_end(ap);
+	}
+
+	if (i915_terminally_wedged(&engine->i915->gpu_error))
+		drm_printf(m, "*** WEDGED ***\n");
+
+	drm_printf(m, "\tcurrent seqno %x, last %x, hangcheck %x [%d ms], inflight %d\n",
+		   intel_engine_get_seqno(engine),
+		   intel_engine_last_submit(engine),
+		   engine->hangcheck.seqno,
+		   jiffies_to_msecs(jiffies - engine->hangcheck.action_timestamp),
+		   engine->timeline->inflight_seqnos);
+	drm_printf(m, "\tReset count: %d (global %d)\n",
+		   i915_reset_engine_count(error, engine),
+		   i915_reset_count(error));
+
+	rcu_read_lock();
+
+	drm_printf(m, "\tRequests:\n");
+
+	rq = list_first_entry(&engine->timeline->requests,
+			      struct drm_i915_gem_request, link);
+	if (&rq->link != &engine->timeline->requests)
+		print_request(m, rq, "\t\tfirst  ");
+
+	rq = list_last_entry(&engine->timeline->requests,
+			     struct drm_i915_gem_request, link);
+	if (&rq->link != &engine->timeline->requests)
+		print_request(m, rq, "\t\tlast   ");
+
+	rq = i915_gem_find_active_request(engine);
+	if (rq) {
+		print_request(m, rq, "\t\tactive ");
+		drm_printf(m,
+			   "\t\t[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]\n",
+			   rq->head, rq->postfix, rq->tail,
+			   rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u,
+			   rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u);
+		drm_printf(m, "\t\tring->start: 0x%08x\n",
+			   i915_ggtt_offset(rq->ring->vma));
+		drm_printf(m, "\t\tring->head:  0x%08x\n",
+			   rq->ring->head);
+		drm_printf(m, "\t\tring->tail:  0x%08x\n",
+			   rq->ring->tail);
+	}
+
+	rcu_read_unlock();
+
+	if (intel_runtime_pm_get_if_in_use(engine->i915)) {
+		intel_engine_print_registers(engine, m);
+		intel_runtime_pm_put(engine->i915);
+	} else {
+		drm_printf(m, "\tDevice is asleep; skipping register dump\n");
+	}
 
 	spin_lock_irq(&engine->timeline->lock);
 	list_for_each_entry(rq, &engine->timeline->requests, link)
@@ -1895,10 +1921,6 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 	}
 	spin_unlock_irq(&b->rb_lock);
 
-	if (INTEL_GEN(dev_priv) >= 6) {
-		drm_printf(m, "\tRING_IMR: %08x\n", I915_READ_IMR(engine));
-	}
-
 	drm_printf(m, "IRQ? 0x%lx (breadcrumbs? %s) (execlists? %s)\n",
 		   engine->irq_posted,
 		   yesno(test_bit(ENGINE_IRQ_BREADCRUMB,
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index f88c1b5dae4c..d7d1ac79c38a 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -492,7 +492,8 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc)
 	schedule_work(&work->work);
 }
 
-static void intel_fbc_deactivate(struct drm_i915_private *dev_priv)
+static void intel_fbc_deactivate(struct drm_i915_private *dev_priv,
+				 const char *reason)
 {
 	struct intel_fbc *fbc = &dev_priv->fbc;
 
@@ -505,6 +506,8 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv)
 
 	if (fbc->active)
 		intel_fbc_hw_deactivate(dev_priv);
+
+	fbc->no_fbc_reason = reason;
 }
 
 static bool multiple_pipes_ok(struct intel_crtc *crtc,
@@ -668,11 +671,13 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
 static bool stride_is_valid(struct drm_i915_private *dev_priv,
 			    unsigned int stride)
 {
-	/* These should have been caught earlier. */
-	WARN_ON(stride < 512);
-	WARN_ON((stride & (64 - 1)) != 0);
+	/* This should have been caught earlier. */
+	if (WARN_ON_ONCE((stride & (64 - 1)) != 0))
+		return false;
 
 	/* Below are the additional FBC restrictions. */
+	if (stride < 512)
+		return false;
 
 	if (IS_GEN2(dev_priv) || IS_GEN3(dev_priv))
 		return stride == 4096 || stride == 8192;
@@ -794,8 +799,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
 		return false;
 	}
 
-	if ((cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) ||
-	    (cache->crtc.mode_flags & DRM_MODE_FLAG_DBLSCAN)) {
+	if (cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) {
 		fbc->no_fbc_reason = "incompatible mode";
 		return false;
 	}
@@ -921,6 +925,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc,
 {
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	struct intel_fbc *fbc = &dev_priv->fbc;
+	const char *reason = "update pending";
 
 	if (!fbc_supported(dev_priv))
 		return;
@@ -928,7 +933,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc,
 	mutex_lock(&fbc->lock);
 
 	if (!multiple_pipes_ok(crtc, plane_state)) {
-		fbc->no_fbc_reason = "more than one pipe active";
+		reason = "more than one pipe active";
 		goto deactivate;
 	}
 
@@ -938,7 +943,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc,
 	intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
 
 deactivate:
-	intel_fbc_deactivate(dev_priv);
+	intel_fbc_deactivate(dev_priv, reason);
 unlock:
 	mutex_unlock(&fbc->lock);
 }
@@ -971,9 +976,8 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc)
 	    intel_fbc_reg_params_equal(&old_params, &fbc->params))
 		return;
 
-	intel_fbc_deactivate(dev_priv);
+	intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)");
 	intel_fbc_schedule_activation(crtc);
-	fbc->no_fbc_reason = "FBC enabled (active or scheduled)";
 }
 
 void intel_fbc_post_update(struct intel_crtc *crtc)
@@ -1014,7 +1018,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
 	fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits;
 
 	if (fbc->enabled && fbc->busy_bits)
-		intel_fbc_deactivate(dev_priv);
+		intel_fbc_deactivate(dev_priv, "frontbuffer write");
 
 	mutex_unlock(&fbc->lock);
 }
@@ -1244,7 +1248,7 @@ static void intel_fbc_underrun_work_fn(struct work_struct *work)
 	DRM_DEBUG_KMS("Disabling FBC due to FIFO underrun.\n");
 	fbc->underrun_detected = true;
 
-	intel_fbc_deactivate(dev_priv);
+	intel_fbc_deactivate(dev_priv, "FIFO underrun");
 out:
 	mutex_unlock(&fbc->lock);
 }
@@ -1371,7 +1375,7 @@ void intel_fbc_init(struct drm_i915_private *dev_priv)
 
 	for_each_pipe(dev_priv, pipe) {
 		fbc->possible_framebuffer_bits |=
-				INTEL_FRONTBUFFER_PRIMARY(pipe);
+			INTEL_FRONTBUFFER(pipe, PLANE_PRIMARY);
 
 		if (fbc_on_pipe_a_only(dev_priv))
 			break;
diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
index 3c6bf5a34c3c..21140ccd7a97 100644
--- a/drivers/gpu/drm/i915/intel_guc.c
+++ b/drivers/gpu/drm/i915/intel_guc.c
@@ -23,6 +23,7 @@
  */
 
 #include "intel_guc.h"
+#include "intel_guc_ads.h"
 #include "intel_guc_submission.h"
 #include "i915_drv.h"
 
@@ -63,6 +64,7 @@ void intel_guc_init_early(struct intel_guc *guc)
 {
 	intel_guc_fw_init_early(guc);
 	intel_guc_ct_init_early(&guc->ct);
+	intel_guc_log_init_early(guc);
 
 	mutex_init(&guc->send_mutex);
 	guc->send = intel_guc_send_nop;
@@ -86,8 +88,10 @@ int intel_guc_init_wq(struct intel_guc *guc)
 	 */
 	guc->log.runtime.flush_wq = alloc_ordered_workqueue("i915-guc_log",
 						WQ_HIGHPRI | WQ_FREEZABLE);
-	if (!guc->log.runtime.flush_wq)
+	if (!guc->log.runtime.flush_wq) {
+		DRM_ERROR("Couldn't allocate workqueue for GuC log\n");
 		return -ENOMEM;
+	}
 
 	/*
 	 * Even though both sending GuC action, and adding a new workitem to
@@ -108,6 +112,8 @@ int intel_guc_init_wq(struct intel_guc *guc)
 							  WQ_HIGHPRI);
 		if (!guc->preempt_wq) {
 			destroy_workqueue(guc->log.runtime.flush_wq);
+			DRM_ERROR("Couldn't allocate workqueue for GuC "
+				  "preemption\n");
 			return -ENOMEM;
 		}
 	}
@@ -163,10 +169,25 @@ int intel_guc_init(struct intel_guc *guc)
 		return ret;
 	GEM_BUG_ON(!guc->shared_data);
 
+	ret = intel_guc_log_create(guc);
+	if (ret)
+		goto err_shared;
+
+	ret = intel_guc_ads_create(guc);
+	if (ret)
+		goto err_log;
+	GEM_BUG_ON(!guc->ads_vma);
+
 	/* We need to notify the guc whenever we change the GGTT */
 	i915_ggtt_enable_guc(dev_priv);
 
 	return 0;
+
+err_log:
+	intel_guc_log_destroy(guc);
+err_shared:
+	guc_shared_data_destroy(guc);
+	return ret;
 }
 
 void intel_guc_fini(struct intel_guc *guc)
@@ -174,6 +195,8 @@ void intel_guc_fini(struct intel_guc *guc)
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 
 	i915_ggtt_disable_guc(dev_priv);
+	intel_guc_ads_destroy(guc);
+	intel_guc_log_destroy(guc);
 	guc_shared_data_destroy(guc);
 }
 
@@ -197,6 +220,19 @@ static u32 get_core_family(struct drm_i915_private *dev_priv)
 	}
 }
 
+static u32 get_log_verbosity_flags(void)
+{
+	if (i915_modparams.guc_log_level > 0) {
+		u32 verbosity = i915_modparams.guc_log_level - 1;
+
+		GEM_BUG_ON(verbosity > GUC_LOG_VERBOSITY_MAX);
+		return verbosity << GUC_LOG_VERBOSITY_SHIFT;
+	}
+
+	GEM_BUG_ON(i915_modparams.enable_guc < 0);
+	return GUC_LOG_DISABLED;
+}
+
 /*
  * Initialise the GuC parameter block before starting the firmware
  * transfer. These parameters are read by the firmware on startup
@@ -229,12 +265,7 @@ void intel_guc_init_params(struct intel_guc *guc)
 
 	params[GUC_CTL_LOG_PARAMS] = guc->log.flags;
 
-	if (i915_modparams.guc_log_level >= 0) {
-		params[GUC_CTL_DEBUG] =
-			i915_modparams.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
-	} else {
-		params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;
-	}
+	params[GUC_CTL_DEBUG] = get_log_verbosity_flags();
 
 	/* If GuC submission is enabled, set up additional parameters here */
 	if (USES_GUC_SUBMISSION(dev_priv)) {
@@ -427,7 +458,7 @@ int intel_guc_resume(struct drm_i915_private *dev_priv)
 	if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
 		return 0;
 
-	if (i915_modparams.guc_log_level >= 0)
+	if (i915_modparams.guc_log_level)
 		gen9_enable_guc_interrupts(dev_priv);
 
 	data[0] = INTEL_GUC_ACTION_EXIT_S_STATE;
diff --git a/drivers/gpu/drm/i915/intel_guc_ads.c b/drivers/gpu/drm/i915/intel_guc_ads.c
new file mode 100644
index 000000000000..ac627534667d
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_ads.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright © 2014-2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "intel_guc_ads.h"
+#include "intel_uc.h"
+#include "i915_drv.h"
+
+/*
+ * The Additional Data Struct (ADS) has pointers for different buffers used by
+ * the GuC. One single gem object contains the ADS struct itself (guc_ads), the
+ * scheduling policies (guc_policies), a structure describing a collection of
+ * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save
+ * its internal state for sleep.
+ */
+
+static void guc_policy_init(struct guc_policy *policy)
+{
+	policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US;
+	policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US;
+	policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US;
+	policy->policy_flags = 0;
+}
+
+static void guc_policies_init(struct guc_policies *policies)
+{
+	struct guc_policy *policy;
+	u32 p, i;
+
+	policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US;
+	policies->max_num_work_items = POLICY_MAX_NUM_WI;
+
+	for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) {
+		for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) {
+			policy = &policies->policy[p][i];
+
+			guc_policy_init(policy);
+		}
+	}
+
+	policies->is_valid = 1;
+}
+
+/*
+ * The first 80 dwords of the register state context, containing the
+ * execlists and ppgtt registers.
+ */
+#define LR_HW_CONTEXT_SIZE	(80 * sizeof(u32))
+
+/**
+ * intel_guc_ads_create() - creates GuC ADS
+ * @guc: intel_guc struct
+ *
+ */
+int intel_guc_ads_create(struct intel_guc *guc)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct i915_vma *vma;
+	struct page *page;
+	/* The ads obj includes the struct itself and buffers passed to GuC */
+	struct {
+		struct guc_ads ads;
+		struct guc_policies policies;
+		struct guc_mmio_reg_state reg_state;
+		u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
+	} __packed *blob;
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+	const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE;
+	const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
+	u32 base;
+
+	GEM_BUG_ON(guc->ads_vma);
+
+	vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob)));
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	guc->ads_vma = vma;
+
+	page = i915_vma_first_page(vma);
+	blob = kmap(page);
+
+	/* GuC scheduling policies */
+	guc_policies_init(&blob->policies);
+
+	/* MMIO reg state */
+	for_each_engine(engine, dev_priv, id) {
+		blob->reg_state.white_list[engine->guc_id].mmio_start =
+			engine->mmio_base + GUC_MMIO_WHITE_LIST_START;
+
+		/* Nothing to be saved or restored for now. */
+		blob->reg_state.white_list[engine->guc_id].count = 0;
+	}
+
+	/*
+	 * The GuC requires a "Golden Context" when it reinitialises
+	 * engines after a reset. Here we use the Render ring default
+	 * context, which must already exist and be pinned in the GGTT,
+	 * so its address won't change after we've told the GuC where
+	 * to find it. Note that we have to skip our header (1 page),
+	 * because our GuC shared data is there.
+	 */
+	blob->ads.golden_context_lrca =
+		guc_ggtt_offset(dev_priv->kernel_context->engine[RCS].state) +
+		skipped_offset;
+
+	/*
+	 * The GuC expects us to exclude the portion of the context image that
+	 * it skips from the size it is to read. It starts reading from after
+	 * the execlist context (so skipping the first page [PPHWSP] and 80
+	 * dwords). Weird guc is weird.
+	 */
+	for_each_engine(engine, dev_priv, id)
+		blob->ads.eng_state_size[engine->guc_id] =
+			engine->context_size - skipped_size;
+
+	base = guc_ggtt_offset(vma);
+	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
+	blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
+	blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
+
+	kunmap(page);
+
+	return 0;
+}
+
+void intel_guc_ads_destroy(struct intel_guc *guc)
+{
+	i915_vma_unpin_and_release(&guc->ads_vma);
+}
diff --git a/drivers/gpu/drm/i915/intel_guc_ads.h b/drivers/gpu/drm/i915/intel_guc_ads.h
new file mode 100644
index 000000000000..c4735742c564
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_ads.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2014-2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _INTEL_GUC_ADS_H_
+#define _INTEL_GUC_ADS_H_
+
+struct intel_guc;
+
+int intel_guc_ads_create(struct intel_guc *guc);
+void intel_guc_ads_destroy(struct intel_guc *guc);
+
+#endif
diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c
index eaedd63e3819..7b5074e2120c 100644
--- a/drivers/gpu/drm/i915/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/intel_guc_log.c
@@ -33,11 +33,10 @@ static void guc_log_capture_logs(struct intel_guc *guc);
 /**
  * DOC: GuC firmware log
  *
- * Firmware log is enabled by setting i915.guc_log_level to non-negative level.
+ * Firmware log is enabled by setting i915.guc_log_level to the positive level.
  * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
  * i915_guc_load_status will print out firmware loading status and scratch
  * registers value.
- *
  */
 
 static int guc_log_flush_complete(struct intel_guc *guc)
@@ -59,11 +58,15 @@ static int guc_log_flush(struct intel_guc *guc)
 	return intel_guc_send(guc, action, ARRAY_SIZE(action));
 }
 
-static int guc_log_control(struct intel_guc *guc, u32 control_val)
+static int guc_log_control(struct intel_guc *guc, bool enable, u32 verbosity)
 {
+	union guc_log_control control_val = {
+		.logging_enabled = enable,
+		.verbosity = verbosity,
+	};
 	u32 action[] = {
 		INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING,
-		control_val
+		control_val.value
 	};
 
 	return intel_guc_send(guc, action, ARRAY_SIZE(action));
@@ -78,7 +81,8 @@ static int subbuf_start_callback(struct rchan_buf *buf,
 				 void *prev_subbuf,
 				 size_t prev_padding)
 {
-	/* Use no-overwrite mode by default, where relay will stop accepting
+	/*
+	 * Use no-overwrite mode by default, where relay will stop accepting
 	 * new data if there are no empty sub buffers left.
 	 * There is no strict synchronization enforced by relay between Consumer
 	 * and Producer. In overwrite mode, there is a possibility of getting
@@ -104,7 +108,8 @@ static struct dentry *create_buf_file_callback(const char *filename,
 {
 	struct dentry *buf_file;
 
-	/* This to enable the use of a single buffer for the relay channel and
+	/*
+	 * This to enable the use of a single buffer for the relay channel and
 	 * correspondingly have a single file exposed to User, through which
 	 * it can collect the logs in order without any post-processing.
 	 * Need to set 'is_global' even if parent is NULL for early logging.
@@ -114,7 +119,8 @@ static struct dentry *create_buf_file_callback(const char *filename,
 	if (!parent)
 		return NULL;
 
-	/* Not using the channel filename passed as an argument, since for each
+	/*
+	 * Not using the channel filename passed as an argument, since for each
 	 * channel relay appends the corresponding CPU number to the filename
 	 * passed in relay_open(). This should be fine as relay just needs a
 	 * dentry of the file associated with the channel buffer and that file's
@@ -147,13 +153,16 @@ static int guc_log_relay_file_create(struct intel_guc *guc)
 	struct dentry *log_dir;
 	int ret;
 
-	if (i915_modparams.guc_log_level < 0)
+	if (!i915_modparams.guc_log_level)
 		return 0;
 
+	mutex_lock(&guc->log.runtime.relay_lock);
+
 	/* For now create the log file in /sys/kernel/debug/dri/0 dir */
 	log_dir = dev_priv->drm.primary->debugfs_root;
 
-	/* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
+	/*
+	 * If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
 	 * not mounted and so can't create the relay file.
 	 * The relay API seems to fit well with debugfs only, for availing relay
 	 * there are 3 requirements which can be met for debugfs file only in a
@@ -166,25 +175,41 @@ static int guc_log_relay_file_create(struct intel_guc *guc)
 	 */
 	if (!log_dir) {
 		DRM_ERROR("Debugfs dir not available yet for GuC log file\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out_unlock;
 	}
 
 	ret = relay_late_setup_files(guc->log.runtime.relay_chan, "guc_log", log_dir);
 	if (ret < 0 && ret != -EEXIST) {
 		DRM_ERROR("Couldn't associate relay chan with file %d\n", ret);
-		return ret;
+		goto out_unlock;
 	}
 
-	return 0;
+	ret = 0;
+
+out_unlock:
+	mutex_unlock(&guc->log.runtime.relay_lock);
+	return ret;
+}
+
+static bool guc_log_has_relay(struct intel_guc *guc)
+{
+	lockdep_assert_held(&guc->log.runtime.relay_lock);
+
+	return guc->log.runtime.relay_chan != NULL;
 }
 
 static void guc_move_to_next_buf(struct intel_guc *guc)
 {
-	/* Make sure the updates made in the sub buffer are visible when
+	/*
+	 * Make sure the updates made in the sub buffer are visible when
 	 * Consumer sees the following update to offset inside the sub buffer.
 	 */
 	smp_wmb();
 
+	if (!guc_log_has_relay(guc))
+		return;
+
 	/* All data has been written, so now move the offset of sub buffer. */
 	relay_reserve(guc->log.runtime.relay_chan, guc->log.vma->obj->base.size);
 
@@ -194,10 +219,11 @@ static void guc_move_to_next_buf(struct intel_guc *guc)
 
 static void *guc_get_write_buffer(struct intel_guc *guc)
 {
-	if (!guc->log.runtime.relay_chan)
+	if (!guc_log_has_relay(guc))
 		return NULL;
 
-	/* Just get the base address of a new sub buffer and copy data into it
+	/*
+	 * Just get the base address of a new sub buffer and copy data into it
 	 * ourselves. NULL will be returned in no-overwrite mode, if all sub
 	 * buffers are full. Could have used the relay_write() to indirectly
 	 * copy the data, but that would have been bit convoluted, as we need to
@@ -262,15 +288,30 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
 	/* Get the pointer to shared GuC log buffer */
 	log_buf_state = src_data = guc->log.runtime.buf_addr;
 
+	mutex_lock(&guc->log.runtime.relay_lock);
+
 	/* Get the pointer to local buffer to store the logs */
 	log_buf_snapshot_state = dst_data = guc_get_write_buffer(guc);
 
+	if (unlikely(!log_buf_snapshot_state)) {
+		/*
+		 * Used rate limited to avoid deluge of messages, logs might be
+		 * getting consumed by User at a slow rate.
+		 */
+		DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n");
+		guc->log.capture_miss_count++;
+		mutex_unlock(&guc->log.runtime.relay_lock);
+
+		return;
+	}
+
 	/* Actual logs are present from the 2nd page */
 	src_data += PAGE_SIZE;
 	dst_data += PAGE_SIZE;
 
 	for (type = GUC_ISR_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) {
-		/* Make a copy of the state structure, inside GuC log buffer
+		/*
+		 * Make a copy of the state structure, inside GuC log buffer
 		 * (which is uncached mapped), on the stack to avoid reading
 		 * from it multiple times.
 		 */
@@ -290,14 +331,12 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
 		log_buf_state->flush_to_file = 0;
 		log_buf_state++;
 
-		if (unlikely(!log_buf_snapshot_state))
-			continue;
-
 		/* First copy the state structure in snapshot buffer */
 		memcpy(log_buf_snapshot_state, &log_buf_state_local,
 		       sizeof(struct guc_log_buffer_state));
 
-		/* The write pointer could have been updated by GuC firmware,
+		/*
+		 * The write pointer could have been updated by GuC firmware,
 		 * after sending the flush interrupt to Host, for consistency
 		 * set write pointer value to same value of sampled_write_ptr
 		 * in the snapshot buffer.
@@ -332,15 +371,9 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
 		dst_data += buffer_size;
 	}
 
-	if (log_buf_snapshot_state)
-		guc_move_to_next_buf(guc);
-	else {
-		/* Used rate limited to avoid deluge of messages, logs might be
-		 * getting consumed by User at a slow rate.
-		 */
-		DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n");
-		guc->log.capture_miss_count++;
-	}
+	guc_move_to_next_buf(guc);
+
+	mutex_unlock(&guc->log.runtime.relay_lock);
 }
 
 static void capture_logs_work(struct work_struct *work)
@@ -360,19 +393,21 @@ static int guc_log_runtime_create(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	void *vaddr;
-	struct rchan *guc_log_relay_chan;
-	size_t n_subbufs, subbuf_size;
 	int ret;
 
 	lockdep_assert_held(&dev_priv->drm.struct_mutex);
 
+	if (!guc->log.vma)
+		return -ENODEV;
+
 	GEM_BUG_ON(guc_log_has_runtime(guc));
 
 	ret = i915_gem_object_set_to_wc_domain(guc->log.vma->obj, true);
 	if (ret)
 		return ret;
 
-	/* Create a WC (Uncached for read) vmalloc mapping of log
+	/*
+	 * Create a WC (Uncached for read) vmalloc mapping of log
 	 * buffer pages, so that we can directly get the data
 	 * (up-to-date) from memory.
 	 */
@@ -384,17 +419,55 @@ static int guc_log_runtime_create(struct intel_guc *guc)
 
 	guc->log.runtime.buf_addr = vaddr;
 
+	return 0;
+}
+
+static void guc_log_runtime_destroy(struct intel_guc *guc)
+{
+	/*
+	 * It's possible that the runtime stuff was never allocated because
+	 * GuC log was disabled at the boot time.
+	 */
+	if (!guc_log_has_runtime(guc))
+		return;
+
+	i915_gem_object_unpin_map(guc->log.vma->obj);
+	guc->log.runtime.buf_addr = NULL;
+}
+
+void intel_guc_log_init_early(struct intel_guc *guc)
+{
+	mutex_init(&guc->log.runtime.relay_lock);
+	INIT_WORK(&guc->log.runtime.flush_work, capture_logs_work);
+}
+
+int intel_guc_log_relay_create(struct intel_guc *guc)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct rchan *guc_log_relay_chan;
+	size_t n_subbufs, subbuf_size;
+	int ret;
+
+	if (!i915_modparams.guc_log_level)
+		return 0;
+
+	mutex_lock(&guc->log.runtime.relay_lock);
+
+	GEM_BUG_ON(guc_log_has_relay(guc));
+
 	 /* Keep the size of sub buffers same as shared log buffer */
-	subbuf_size = guc->log.vma->obj->base.size;
+	subbuf_size = GUC_LOG_SIZE;
 
-	/* Store up to 8 snapshots, which is large enough to buffer sufficient
+	/*
+	 * Store up to 8 snapshots, which is large enough to buffer sufficient
 	 * boot time logs and provides enough leeway to User, in terms of
 	 * latency, for consuming the logs from relay. Also doesn't take
 	 * up too much memory.
 	 */
 	n_subbufs = 8;
 
-	/* Create a relay channel, so that we have buffers for storing
+	/*
+	 * Create a relay channel, so that we have buffers for storing
 	 * the GuC firmware logs, the channel will be linked with a file
 	 * later on when debugfs is registered.
 	 */
@@ -404,33 +477,39 @@ static int guc_log_runtime_create(struct intel_guc *guc)
 		DRM_ERROR("Couldn't create relay chan for GuC logging\n");
 
 		ret = -ENOMEM;
-		goto err_vaddr;
+		goto err;
 	}
 
 	GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size);
 	guc->log.runtime.relay_chan = guc_log_relay_chan;
 
-	INIT_WORK(&guc->log.runtime.flush_work, capture_logs_work);
+	mutex_unlock(&guc->log.runtime.relay_lock);
+
 	return 0;
 
-err_vaddr:
-	i915_gem_object_unpin_map(guc->log.vma->obj);
-	guc->log.runtime.buf_addr = NULL;
+err:
+	mutex_unlock(&guc->log.runtime.relay_lock);
+	/* logging will be off */
+	i915_modparams.guc_log_level = 0;
 	return ret;
 }
 
-static void guc_log_runtime_destroy(struct intel_guc *guc)
+void intel_guc_log_relay_destroy(struct intel_guc *guc)
 {
+	mutex_lock(&guc->log.runtime.relay_lock);
+
 	/*
-	 * It's possible that the runtime stuff was never allocated because
-	 * guc_log_level was < 0 at the time
-	 **/
-	if (!guc_log_has_runtime(guc))
-		return;
+	 * It's possible that the relay was never allocated because
+	 * GuC log was disabled at the boot time.
+	 */
+	if (!guc_log_has_relay(guc))
+		goto out_unlock;
 
 	relay_close(guc->log.runtime.relay_chan);
-	i915_gem_object_unpin_map(guc->log.vma->obj);
-	guc->log.runtime.buf_addr = NULL;
+	guc->log.runtime.relay_chan = NULL;
+
+out_unlock:
+	mutex_unlock(&guc->log.runtime.relay_lock);
 }
 
 static int guc_log_late_setup(struct intel_guc *guc)
@@ -438,16 +517,24 @@ static int guc_log_late_setup(struct intel_guc *guc)
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	int ret;
 
-	lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
 	if (!guc_log_has_runtime(guc)) {
-		/* If log_level was set as -1 at boot time, then setup needed to
-		 * handle log buffer flush interrupts would not have been done yet,
-		 * so do that now.
+		/*
+		 * If log was disabled at boot time, then setup needed to handle
+		 * log buffer flush interrupts would not have been done yet, so
+		 * do that now.
 		 */
-		ret = guc_log_runtime_create(guc);
+		ret = intel_guc_log_relay_create(guc);
 		if (ret)
 			goto err;
+
+		mutex_lock(&dev_priv->drm.struct_mutex);
+		intel_runtime_pm_get(dev_priv);
+		ret = guc_log_runtime_create(guc);
+		intel_runtime_pm_put(dev_priv);
+		mutex_unlock(&dev_priv->drm.struct_mutex);
+
+		if (ret)
+			goto err_relay;
 	}
 
 	ret = guc_log_relay_file_create(guc);
@@ -457,10 +544,14 @@ static int guc_log_late_setup(struct intel_guc *guc)
 	return 0;
 
 err_runtime:
+	mutex_lock(&dev_priv->drm.struct_mutex);
 	guc_log_runtime_destroy(guc);
+	mutex_unlock(&dev_priv->drm.struct_mutex);
+err_relay:
+	intel_guc_log_relay_destroy(guc);
 err:
 	/* logging will remain off */
-	i915_modparams.guc_log_level = -1;
+	i915_modparams.guc_log_level = 0;
 	return ret;
 }
 
@@ -470,7 +561,8 @@ static void guc_log_capture_logs(struct intel_guc *guc)
 
 	guc_read_update_log_buffer(guc);
 
-	/* Generally device is expected to be active only at this
+	/*
+	 * Generally device is expected to be active only at this
 	 * time, so get/put should be really quick.
 	 */
 	intel_runtime_pm_get(dev_priv);
@@ -482,20 +574,26 @@ static void guc_flush_logs(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 
-	if (!USES_GUC_SUBMISSION(dev_priv) ||
-	    (i915_modparams.guc_log_level < 0))
+	if (!USES_GUC_SUBMISSION(dev_priv) || !i915_modparams.guc_log_level)
 		return;
 
 	/* First disable the interrupts, will be renabled afterwards */
+	mutex_lock(&dev_priv->drm.struct_mutex);
+	intel_runtime_pm_get(dev_priv);
 	gen9_disable_guc_interrupts(dev_priv);
+	intel_runtime_pm_put(dev_priv);
+	mutex_unlock(&dev_priv->drm.struct_mutex);
 
-	/* Before initiating the forceful flush, wait for any pending/ongoing
+	/*
+	 * Before initiating the forceful flush, wait for any pending/ongoing
 	 * flush to complete otherwise forceful flush may not actually happen.
 	 */
 	flush_work(&guc->log.runtime.flush_work);
 
 	/* Ask GuC to update the log buffer state */
+	intel_runtime_pm_get(dev_priv);
 	guc_log_flush(guc);
+	intel_runtime_pm_put(dev_priv);
 
 	/* GuC would have updated log buffer by now, so capture it */
 	guc_log_capture_logs(guc);
@@ -506,21 +604,12 @@ int intel_guc_log_create(struct intel_guc *guc)
 	struct i915_vma *vma;
 	unsigned long offset;
 	u32 flags;
-	u32 size;
 	int ret;
 
 	GEM_BUG_ON(guc->log.vma);
 
-	if (i915_modparams.guc_log_level > GUC_LOG_VERBOSITY_MAX)
-		i915_modparams.guc_log_level = GUC_LOG_VERBOSITY_MAX;
-
-	/* The first page is to save log buffer state. Allocate one
-	 * extra page for others in case for overlap */
-	size = (1 + GUC_LOG_DPC_PAGES + 1 +
-		GUC_LOG_ISR_PAGES + 1 +
-		GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
-
-	/* We require SSE 4.1 for fast reads from the GuC log buffer and
+	/*
+	 * We require SSE 4.1 for fast reads from the GuC log buffer and
 	 * it should be present on the chipsets supporting GuC based
 	 * submisssions.
 	 */
@@ -529,7 +618,7 @@ int intel_guc_log_create(struct intel_guc *guc)
 		goto err;
 	}
 
-	vma = intel_guc_allocate_vma(guc, size);
+	vma = intel_guc_allocate_vma(guc, GUC_LOG_SIZE);
 	if (IS_ERR(vma)) {
 		ret = PTR_ERR(vma);
 		goto err;
@@ -537,7 +626,7 @@ int intel_guc_log_create(struct intel_guc *guc)
 
 	guc->log.vma = vma;
 
-	if (i915_modparams.guc_log_level >= 0) {
+	if (i915_modparams.guc_log_level) {
 		ret = guc_log_runtime_create(guc);
 		if (ret < 0)
 			goto err_vma;
@@ -558,7 +647,7 @@ int intel_guc_log_create(struct intel_guc *guc)
 	i915_vma_unpin_and_release(&guc->log.vma);
 err:
 	/* logging will be off */
-	i915_modparams.guc_log_level = -1;
+	i915_modparams.guc_log_level = 0;
 	return ret;
 }
 
@@ -568,35 +657,46 @@ void intel_guc_log_destroy(struct intel_guc *guc)
 	i915_vma_unpin_and_release(&guc->log.vma);
 }
 
-int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
+int intel_guc_log_control(struct intel_guc *guc, u64 control_val)
 {
-	struct intel_guc *guc = &dev_priv->guc;
-
-	union guc_log_control log_param;
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	bool enable_logging = control_val > 0;
+	u32 verbosity;
 	int ret;
 
-	log_param.value = control_val;
+	if (!guc->log.vma)
+		return -ENODEV;
 
-	if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
-	    log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
+	BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN);
+	if (control_val > 1 + GUC_LOG_VERBOSITY_MAX)
 		return -EINVAL;
 
 	/* This combination doesn't make sense & won't have any effect */
-	if (!log_param.logging_enabled && (i915_modparams.guc_log_level < 0))
+	if (!enable_logging && !i915_modparams.guc_log_level)
 		return 0;
 
-	ret = guc_log_control(guc, log_param.value);
+	verbosity = enable_logging ? control_val - 1 : 0;
+
+	ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
+	if (ret)
+		return ret;
+	intel_runtime_pm_get(dev_priv);
+	ret = guc_log_control(guc, enable_logging, verbosity);
+	intel_runtime_pm_put(dev_priv);
+	mutex_unlock(&dev_priv->drm.struct_mutex);
+
 	if (ret < 0) {
 		DRM_DEBUG_DRIVER("guc_logging_control action failed %d\n", ret);
 		return ret;
 	}
 
-	if (log_param.logging_enabled) {
-		i915_modparams.guc_log_level = log_param.verbosity;
+	if (enable_logging) {
+		i915_modparams.guc_log_level = 1 + verbosity;
 
-		/* If log_level was set as -1 at boot time, then the relay channel file
-		 * wouldn't have been created by now and interrupts also would not have
-		 * been enabled. Try again now, just in case.
+		/*
+		 * If log was disabled at boot time, then the relay channel file
+		 * wouldn't have been created by now and interrupts also would
+		 * not have been enabled. Try again now, just in case.
 		 */
 		ret = guc_log_late_setup(guc);
 		if (ret < 0) {
@@ -605,9 +705,14 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
 		}
 
 		/* GuC logging is currently the only user of Guc2Host interrupts */
+		mutex_lock(&dev_priv->drm.struct_mutex);
+		intel_runtime_pm_get(dev_priv);
 		gen9_enable_guc_interrupts(dev_priv);
+		intel_runtime_pm_put(dev_priv);
+		mutex_unlock(&dev_priv->drm.struct_mutex);
 	} else {
-		/* Once logging is disabled, GuC won't generate logs & send an
+		/*
+		 * Once logging is disabled, GuC won't generate logs & send an
 		 * interrupt. But there could be some data in the log buffer
 		 * which is yet to be captured. So request GuC to update the log
 		 * buffer state and then collect the left over logs.
@@ -615,7 +720,7 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
 		guc_flush_logs(guc);
 
 		/* As logging is disabled, update log level to reflect that */
-		i915_modparams.guc_log_level = -1;
+		i915_modparams.guc_log_level = 0;
 	}
 
 	return ret;
@@ -623,23 +728,27 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val)
 
 void i915_guc_log_register(struct drm_i915_private *dev_priv)
 {
-	if (!USES_GUC_SUBMISSION(dev_priv) ||
-	    (i915_modparams.guc_log_level < 0))
+	if (!USES_GUC_SUBMISSION(dev_priv) || !i915_modparams.guc_log_level)
 		return;
 
-	mutex_lock(&dev_priv->drm.struct_mutex);
 	guc_log_late_setup(&dev_priv->guc);
-	mutex_unlock(&dev_priv->drm.struct_mutex);
 }
 
 void i915_guc_log_unregister(struct drm_i915_private *dev_priv)
 {
+	struct intel_guc *guc = &dev_priv->guc;
+
 	if (!USES_GUC_SUBMISSION(dev_priv))
 		return;
 
 	mutex_lock(&dev_priv->drm.struct_mutex);
 	/* GuC logging is currently the only user of Guc2Host interrupts */
+	intel_runtime_pm_get(dev_priv);
 	gen9_disable_guc_interrupts(dev_priv);
-	guc_log_runtime_destroy(&dev_priv->guc);
+	intel_runtime_pm_put(dev_priv);
+
+	guc_log_runtime_destroy(guc);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
+
+	intel_guc_log_relay_destroy(guc);
 }
diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h
index f512cf79339b..dab0e949567a 100644
--- a/drivers/gpu/drm/i915/intel_guc_log.h
+++ b/drivers/gpu/drm/i915/intel_guc_log.h
@@ -32,6 +32,13 @@
 struct drm_i915_private;
 struct intel_guc;
 
+/*
+ * The first page is to save log buffer state. Allocate one
+ * extra page for others in case for overlap
+ */
+#define GUC_LOG_SIZE	((1 + GUC_LOG_DPC_PAGES + 1 + GUC_LOG_ISR_PAGES + \
+			  1 + GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT)
+
 struct intel_guc_log {
 	u32 flags;
 	struct i915_vma *vma;
@@ -41,6 +48,8 @@ struct intel_guc_log {
 		struct workqueue_struct *flush_wq;
 		struct work_struct flush_work;
 		struct rchan *relay_chan;
+		/* To serialize the access to relay_chan */
+		struct mutex relay_lock;
 	} runtime;
 	/* logging related stats */
 	u32 capture_miss_count;
@@ -52,7 +61,10 @@ struct intel_guc_log {
 
 int intel_guc_log_create(struct intel_guc *guc);
 void intel_guc_log_destroy(struct intel_guc *guc);
-int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val);
+void intel_guc_log_init_early(struct intel_guc *guc);
+int intel_guc_log_relay_create(struct intel_guc *guc);
+void intel_guc_log_relay_destroy(struct intel_guc *guc);
+int intel_guc_log_control(struct intel_guc *guc, u64 control_val);
 void i915_guc_log_register(struct drm_i915_private *dev_priv);
 void i915_guc_log_unregister(struct drm_i915_private *dev_priv);
 
diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
index 4d2409466a3a..946766b62459 100644
--- a/drivers/gpu/drm/i915/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/intel_guc_submission.c
@@ -73,13 +73,6 @@
  * ELSP context descriptor dword into Work Item.
  * See guc_add_request()
  *
- * ADS:
- * The Additional Data Struct (ADS) has pointers for different buffers used by
- * the GuC. One single gem object contains the ADS struct itself (guc_ads), the
- * scheduling policies (guc_policies), a structure describing a collection of
- * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save
- * its internal state for sleep.
- *
  */
 
 static inline bool is_high_priority(struct intel_guc_client *client)
@@ -695,7 +688,7 @@ static void guc_dequeue(struct intel_engine_cs *engine)
 		goto unlock;
 
 	if (port_isset(port)) {
-		if (HAS_LOGICAL_RING_PREEMPTION(engine->i915)) {
+		if (engine->i915->preempt_context) {
 			struct guc_preempt_work *preempt_work =
 				&engine->i915->guc.preempt_work[engine->id];
 
@@ -754,6 +747,12 @@ static void guc_dequeue(struct intel_engine_cs *engine)
 		execlists_set_active(execlists, EXECLISTS_ACTIVE_USER);
 		guc_submit(engine);
 	}
+
+	/* We must always keep the beast fed if we have work piled up */
+	GEM_BUG_ON(port_isset(execlists->port) &&
+		   !execlists_is_active(execlists, EXECLISTS_ACTIVE_USER));
+	GEM_BUG_ON(execlists->first && !port_isset(execlists->port));
+
 unlock:
 	spin_unlock_irq(&engine->timeline->lock);
 }
@@ -839,10 +838,12 @@ static int guc_clients_doorbell_init(struct intel_guc *guc)
 	if (ret)
 		return ret;
 
-	ret = create_doorbell(guc->preempt_client);
-	if (ret) {
-		destroy_doorbell(guc->execbuf_client);
-		return ret;
+	if (guc->preempt_client) {
+		ret = create_doorbell(guc->preempt_client);
+		if (ret) {
+			destroy_doorbell(guc->execbuf_client);
+			return ret;
+		}
 	}
 
 	return 0;
@@ -855,8 +856,11 @@ static void guc_clients_doorbell_fini(struct intel_guc *guc)
 	 * Instead of trying (in vain) to communicate with it, let's just
 	 * cleanup the doorbell HW and our internal state.
 	 */
-	__destroy_doorbell(guc->preempt_client);
-	__update_doorbell_desc(guc->preempt_client, GUC_DOORBELL_INVALID);
+	if (guc->preempt_client) {
+		__destroy_doorbell(guc->preempt_client);
+		__update_doorbell_desc(guc->preempt_client,
+				       GUC_DOORBELL_INVALID);
+	}
 	__destroy_doorbell(guc->execbuf_client);
 	__update_doorbell_desc(guc->execbuf_client, GUC_DOORBELL_INVALID);
 }
@@ -986,17 +990,19 @@ static int guc_clients_create(struct intel_guc *guc)
 	}
 	guc->execbuf_client = client;
 
-	client = guc_client_alloc(dev_priv,
-				  INTEL_INFO(dev_priv)->ring_mask,
-				  GUC_CLIENT_PRIORITY_KMD_HIGH,
-				  dev_priv->preempt_context);
-	if (IS_ERR(client)) {
-		DRM_ERROR("Failed to create GuC client for preemption!\n");
-		guc_client_free(guc->execbuf_client);
-		guc->execbuf_client = NULL;
-		return PTR_ERR(client);
+	if (dev_priv->preempt_context) {
+		client = guc_client_alloc(dev_priv,
+					  INTEL_INFO(dev_priv)->ring_mask,
+					  GUC_CLIENT_PRIORITY_KMD_HIGH,
+					  dev_priv->preempt_context);
+		if (IS_ERR(client)) {
+			DRM_ERROR("Failed to create GuC client for preemption!\n");
+			guc_client_free(guc->execbuf_client);
+			guc->execbuf_client = NULL;
+			return PTR_ERR(client);
+		}
+		guc->preempt_client = client;
 	}
-	guc->preempt_client = client;
 
 	return 0;
 }
@@ -1005,122 +1011,12 @@ static void guc_clients_destroy(struct intel_guc *guc)
 {
 	struct intel_guc_client *client;
 
-	client = fetch_and_zero(&guc->execbuf_client);
-	guc_client_free(client);
-
 	client = fetch_and_zero(&guc->preempt_client);
-	guc_client_free(client);
-}
-
-static void guc_policy_init(struct guc_policy *policy)
-{
-	policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US;
-	policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US;
-	policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US;
-	policy->policy_flags = 0;
-}
-
-static void guc_policies_init(struct guc_policies *policies)
-{
-	struct guc_policy *policy;
-	u32 p, i;
-
-	policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US;
-	policies->max_num_work_items = POLICY_MAX_NUM_WI;
-
-	for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) {
-		for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) {
-			policy = &policies->policy[p][i];
-
-			guc_policy_init(policy);
-		}
-	}
-
-	policies->is_valid = 1;
-}
-
-/*
- * The first 80 dwords of the register state context, containing the
- * execlists and ppgtt registers.
- */
-#define LR_HW_CONTEXT_SIZE	(80 * sizeof(u32))
-
-static int guc_ads_create(struct intel_guc *guc)
-{
-	struct drm_i915_private *dev_priv = guc_to_i915(guc);
-	struct i915_vma *vma;
-	struct page *page;
-	/* The ads obj includes the struct itself and buffers passed to GuC */
-	struct {
-		struct guc_ads ads;
-		struct guc_policies policies;
-		struct guc_mmio_reg_state reg_state;
-		u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
-	} __packed *blob;
-	struct intel_engine_cs *engine;
-	enum intel_engine_id id;
-	const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE;
-	const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
-	u32 base;
-
-	GEM_BUG_ON(guc->ads_vma);
-
-	vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob)));
-	if (IS_ERR(vma))
-		return PTR_ERR(vma);
-
-	guc->ads_vma = vma;
-
-	page = i915_vma_first_page(vma);
-	blob = kmap(page);
+	if (client)
+		guc_client_free(client);
 
-	/* GuC scheduling policies */
-	guc_policies_init(&blob->policies);
-
-	/* MMIO reg state */
-	for_each_engine(engine, dev_priv, id) {
-		blob->reg_state.white_list[engine->guc_id].mmio_start =
-			engine->mmio_base + GUC_MMIO_WHITE_LIST_START;
-
-		/* Nothing to be saved or restored for now. */
-		blob->reg_state.white_list[engine->guc_id].count = 0;
-	}
-
-	/*
-	 * The GuC requires a "Golden Context" when it reinitialises
-	 * engines after a reset. Here we use the Render ring default
-	 * context, which must already exist and be pinned in the GGTT,
-	 * so its address won't change after we've told the GuC where
-	 * to find it. Note that we have to skip our header (1 page),
-	 * because our GuC shared data is there.
-	 */
-	blob->ads.golden_context_lrca =
-		guc_ggtt_offset(dev_priv->kernel_context->engine[RCS].state) +
-		skipped_offset;
-
-	/*
-	 * The GuC expects us to exclude the portion of the context image that
-	 * it skips from the size it is to read. It starts reading from after
-	 * the execlist context (so skipping the first page [PPHWSP] and 80
-	 * dwords). Weird guc is weird.
-	 */
-	for_each_engine(engine, dev_priv, id)
-		blob->ads.eng_state_size[engine->guc_id] =
-			engine->context_size - skipped_size;
-
-	base = guc_ggtt_offset(vma);
-	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
-	blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
-	blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
-
-	kunmap(page);
-
-	return 0;
-}
-
-static void guc_ads_destroy(struct intel_guc *guc)
-{
-	i915_vma_unpin_and_release(&guc->ads_vma);
+	client = fetch_and_zero(&guc->execbuf_client);
+	guc_client_free(client);
 }
 
 /*
@@ -1146,15 +1042,6 @@ int intel_guc_submission_init(struct intel_guc *guc)
 	 */
 	GEM_BUG_ON(!guc->stage_desc_pool);
 
-	ret = intel_guc_log_create(guc);
-	if (ret < 0)
-		goto err_stage_desc_pool;
-
-	ret = guc_ads_create(guc);
-	if (ret < 0)
-		goto err_log;
-	GEM_BUG_ON(!guc->ads_vma);
-
 	WARN_ON(!guc_verify_doorbells(guc));
 	ret = guc_clients_create(guc);
 	if (ret)
@@ -1167,11 +1054,6 @@ int intel_guc_submission_init(struct intel_guc *guc)
 
 	return 0;
 
-err_log:
-	intel_guc_log_destroy(guc);
-err_stage_desc_pool:
-	guc_stage_desc_pool_destroy(guc);
-	return ret;
 }
 
 void intel_guc_submission_fini(struct intel_guc *guc)
@@ -1186,8 +1068,6 @@ void intel_guc_submission_fini(struct intel_guc *guc)
 	guc_clients_destroy(guc);
 	WARN_ON(!guc_verify_doorbells(guc));
 
-	guc_ads_destroy(guc);
-	intel_guc_log_destroy(guc);
 	guc_stage_desc_pool_destroy(guc);
 }
 
@@ -1294,7 +1174,8 @@ int intel_guc_submission_enable(struct intel_guc *guc)
 	GEM_BUG_ON(!guc->execbuf_client);
 
 	guc_reset_wq(guc->execbuf_client);
-	guc_reset_wq(guc->preempt_client);
+	if (guc->preempt_client)
+		guc_reset_wq(guc->preempt_client);
 
 	err = intel_guc_sample_forcewake(guc);
 	if (err)
diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c
index 348a4f7ffb67..42e45ae87393 100644
--- a/drivers/gpu/drm/i915/intel_hangcheck.c
+++ b/drivers/gpu/drm/i915/intel_hangcheck.c
@@ -359,7 +359,7 @@ static void hangcheck_accumulate_sample(struct intel_engine_cs *engine,
 	case ENGINE_DEAD:
 		if (drm_debug & DRM_UT_DRIVER) {
 			struct drm_printer p = drm_debug_printer("hangcheck");
-			intel_engine_dump(engine, &p, "%s", engine->name);
+			intel_engine_dump(engine, &p, "%s\n", engine->name);
 		}
 		break;
 
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
new file mode 100644
index 000000000000..14ca5d3057a7
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -0,0 +1,807 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * Authors:
+ * Sean Paul <seanpaul@chromium.org>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_hdcp.h>
+#include <linux/i2c.h>
+#include <linux/random.h>
+
+#include "intel_drv.h"
+#include "i915_reg.h"
+
+#define KEY_LOAD_TRIES	5
+
+static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port,
+				    const struct intel_hdcp_shim *shim)
+{
+	int ret, read_ret;
+	bool ksv_ready;
+
+	/* Poll for ksv list ready (spec says max time allowed is 5s) */
+	ret = __wait_for(read_ret = shim->read_ksv_ready(intel_dig_port,
+							 &ksv_ready),
+			 read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
+			 100 * 1000);
+	if (ret)
+		return ret;
+	if (read_ret)
+		return read_ret;
+	if (!ksv_ready)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static void intel_hdcp_clear_keys(struct drm_i915_private *dev_priv)
+{
+	I915_WRITE(HDCP_KEY_CONF, HDCP_CLEAR_KEYS_TRIGGER);
+	I915_WRITE(HDCP_KEY_STATUS, HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS |
+		   HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
+}
+
+static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
+{
+	int ret;
+	u32 val;
+
+	val = I915_READ(HDCP_KEY_STATUS);
+	if ((val & HDCP_KEY_LOAD_DONE) && (val & HDCP_KEY_LOAD_STATUS))
+		return 0;
+
+	/*
+	 * On HSW and BDW HW loads the HDCP1.4 Key when Display comes
+	 * out of reset. So if Key is not already loaded, its an error state.
+	 */
+	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+		if (!(I915_READ(HDCP_KEY_STATUS) & HDCP_KEY_LOAD_DONE))
+			return -ENXIO;
+
+	/*
+	 * Initiate loading the HDCP key from fuses.
+	 *
+	 * BXT+ platforms, HDCP key needs to be loaded by SW. Only SKL and KBL
+	 * differ in the key load trigger process from other platforms.
+	 */
+	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		mutex_lock(&dev_priv->pcu_lock);
+		ret = sandybridge_pcode_write(dev_priv,
+					      SKL_PCODE_LOAD_HDCP_KEYS, 1);
+		mutex_unlock(&dev_priv->pcu_lock);
+		if (ret) {
+			DRM_ERROR("Failed to initiate HDCP key load (%d)\n",
+			          ret);
+			return ret;
+		}
+	} else {
+		I915_WRITE(HDCP_KEY_CONF, HDCP_KEY_LOAD_TRIGGER);
+	}
+
+	/* Wait for the keys to load (500us) */
+	ret = __intel_wait_for_register(dev_priv, HDCP_KEY_STATUS,
+					HDCP_KEY_LOAD_DONE, HDCP_KEY_LOAD_DONE,
+					10, 1, &val);
+	if (ret)
+		return ret;
+	else if (!(val & HDCP_KEY_LOAD_STATUS))
+		return -ENXIO;
+
+	/* Send Aksv over to PCH display for use in authentication */
+	I915_WRITE(HDCP_KEY_CONF, HDCP_AKSV_SEND_TRIGGER);
+
+	return 0;
+}
+
+/* Returns updated SHA-1 index */
+static int intel_write_sha_text(struct drm_i915_private *dev_priv, u32 sha_text)
+{
+	I915_WRITE(HDCP_SHA_TEXT, sha_text);
+	if (intel_wait_for_register(dev_priv, HDCP_REP_CTL,
+				    HDCP_SHA1_READY, HDCP_SHA1_READY, 1)) {
+		DRM_ERROR("Timed out waiting for SHA1 ready\n");
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static
+u32 intel_hdcp_get_repeater_ctl(struct intel_digital_port *intel_dig_port)
+{
+	enum port port = intel_dig_port->base.port;
+	switch (port) {
+	case PORT_A:
+		return HDCP_DDIA_REP_PRESENT | HDCP_DDIA_SHA1_M0;
+	case PORT_B:
+		return HDCP_DDIB_REP_PRESENT | HDCP_DDIB_SHA1_M0;
+	case PORT_C:
+		return HDCP_DDIC_REP_PRESENT | HDCP_DDIC_SHA1_M0;
+	case PORT_D:
+		return HDCP_DDID_REP_PRESENT | HDCP_DDID_SHA1_M0;
+	case PORT_E:
+		return HDCP_DDIE_REP_PRESENT | HDCP_DDIE_SHA1_M0;
+	default:
+		break;
+	}
+	DRM_ERROR("Unknown port %d\n", port);
+	return -EINVAL;
+}
+
+static
+bool intel_hdcp_is_ksv_valid(u8 *ksv)
+{
+	int i, ones = 0;
+	/* KSV has 20 1's and 20 0's */
+	for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
+		ones += hweight8(ksv[i]);
+	if (ones != 20)
+		return false;
+	return true;
+}
+
+/* Implements Part 2 of the HDCP authorization procedure */
+static
+int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port,
+			       const struct intel_hdcp_shim *shim)
+{
+	struct drm_i915_private *dev_priv;
+	u32 vprime, sha_text, sha_leftovers, rep_ctl;
+	u8 bstatus[2], num_downstream, *ksv_fifo;
+	int ret, i, j, sha_idx;
+
+	dev_priv = intel_dig_port->base.base.dev->dev_private;
+
+	ret = intel_hdcp_poll_ksv_fifo(intel_dig_port, shim);
+	if (ret) {
+		DRM_ERROR("KSV list failed to become ready (%d)\n", ret);
+		return ret;
+	}
+
+	ret = shim->read_bstatus(intel_dig_port, bstatus);
+	if (ret)
+		return ret;
+
+	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
+	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
+		DRM_ERROR("Max Topology Limit Exceeded\n");
+		return -EPERM;
+	}
+
+	/*
+	 * When repeater reports 0 device count, HDCP1.4 spec allows disabling
+	 * the HDCP encryption. That implies that repeater can't have its own
+	 * display. As there is no consumption of encrypted content in the
+	 * repeater with 0 downstream devices, we are failing the
+	 * authentication.
+	 */
+	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
+	if (num_downstream == 0)
+		return -EINVAL;
+
+	ksv_fifo = kzalloc(num_downstream * DRM_HDCP_KSV_LEN, GFP_KERNEL);
+	if (!ksv_fifo)
+		return -ENOMEM;
+
+	ret = shim->read_ksv_fifo(intel_dig_port, num_downstream, ksv_fifo);
+	if (ret)
+		return ret;
+
+	/* Process V' values from the receiver */
+	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
+		ret = shim->read_v_prime_part(intel_dig_port, i, &vprime);
+		if (ret)
+			return ret;
+		I915_WRITE(HDCP_SHA_V_PRIME(i), vprime);
+	}
+
+	/*
+	 * We need to write the concatenation of all device KSVs, BINFO (DP) ||
+	 * BSTATUS (HDMI), and M0 (which is added via HDCP_REP_CTL). This byte
+	 * stream is written via the HDCP_SHA_TEXT register in 32-bit
+	 * increments. Every 64 bytes, we need to write HDCP_REP_CTL again. This
+	 * index will keep track of our progress through the 64 bytes as well as
+	 * helping us work the 40-bit KSVs through our 32-bit register.
+	 *
+	 * NOTE: data passed via HDCP_SHA_TEXT should be big-endian
+	 */
+	sha_idx = 0;
+	sha_text = 0;
+	sha_leftovers = 0;
+	rep_ctl = intel_hdcp_get_repeater_ctl(intel_dig_port);
+	I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_32);
+	for (i = 0; i < num_downstream; i++) {
+		unsigned int sha_empty;
+		u8 *ksv = &ksv_fifo[i * DRM_HDCP_KSV_LEN];
+
+		/* Fill up the empty slots in sha_text and write it out */
+		sha_empty = sizeof(sha_text) - sha_leftovers;
+		for (j = 0; j < sha_empty; j++)
+			sha_text |= ksv[j] << ((sizeof(sha_text) - j - 1) * 8);
+
+		ret = intel_write_sha_text(dev_priv, sha_text);
+		if (ret < 0)
+			return ret;
+
+		/* Programming guide writes this every 64 bytes */
+		sha_idx += sizeof(sha_text);
+		if (!(sha_idx % 64))
+			I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_32);
+
+		/* Store the leftover bytes from the ksv in sha_text */
+		sha_leftovers = DRM_HDCP_KSV_LEN - sha_empty;
+		sha_text = 0;
+		for (j = 0; j < sha_leftovers; j++)
+			sha_text |= ksv[sha_empty + j] <<
+					((sizeof(sha_text) - j - 1) * 8);
+
+		/*
+		 * If we still have room in sha_text for more data, continue.
+		 * Otherwise, write it out immediately.
+		 */
+		if (sizeof(sha_text) > sha_leftovers)
+			continue;
+
+		ret = intel_write_sha_text(dev_priv, sha_text);
+		if (ret < 0)
+			return ret;
+		sha_leftovers = 0;
+		sha_text = 0;
+		sha_idx += sizeof(sha_text);
+	}
+
+	/*
+	 * We need to write BINFO/BSTATUS, and M0 now. Depending on how many
+	 * bytes are leftover from the last ksv, we might be able to fit them
+	 * all in sha_text (first 2 cases), or we might need to split them up
+	 * into 2 writes (last 2 cases).
+	 */
+	if (sha_leftovers == 0) {
+		/* Write 16 bits of text, 16 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_16);
+		ret = intel_write_sha_text(dev_priv,
+					   bstatus[0] << 8 | bstatus[1]);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 32 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0);
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 16 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_16);
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+	} else if (sha_leftovers == 1) {
+		/* Write 24 bits of text, 8 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_24);
+		sha_text |= bstatus[0] << 16 | bstatus[1] << 8;
+		/* Only 24-bits of data, must be in the LSB */
+		sha_text = (sha_text & 0xffffff00) >> 8;
+		ret = intel_write_sha_text(dev_priv, sha_text);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 32 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0);
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 24 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_8);
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+	} else if (sha_leftovers == 2) {
+		/* Write 32 bits of text */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_32);
+		sha_text |= bstatus[0] << 24 | bstatus[1] << 16;
+		ret = intel_write_sha_text(dev_priv, sha_text);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 64 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0);
+		for (i = 0; i < 2; i++) {
+			ret = intel_write_sha_text(dev_priv, 0);
+			if (ret < 0)
+				return ret;
+			sha_idx += sizeof(sha_text);
+		}
+	} else if (sha_leftovers == 3) {
+		/* Write 32 bits of text */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_32);
+		sha_text |= bstatus[0] << 24;
+		ret = intel_write_sha_text(dev_priv, sha_text);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 8 bits of text, 24 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_8);
+		ret = intel_write_sha_text(dev_priv, bstatus[1]);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 32 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0);
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+
+		/* Write 8 bits of M0 */
+		I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_24);
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+	} else {
+		DRM_ERROR("Invalid number of leftovers %d\n", sha_leftovers);
+		return -EINVAL;
+	}
+
+	I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_32);
+	/* Fill up to 64-4 bytes with zeros (leave the last write for length) */
+	while ((sha_idx % 64) < (64 - sizeof(sha_text))) {
+		ret = intel_write_sha_text(dev_priv, 0);
+		if (ret < 0)
+			return ret;
+		sha_idx += sizeof(sha_text);
+	}
+
+	/*
+	 * Last write gets the length of the concatenation in bits. That is:
+	 *  - 5 bytes per device
+	 *  - 10 bytes for BINFO/BSTATUS(2), M0(8)
+	 */
+	sha_text = (num_downstream * 5 + 10) * 8;
+	ret = intel_write_sha_text(dev_priv, sha_text);
+	if (ret < 0)
+		return ret;
+
+	/* Tell the HW we're done with the hash and wait for it to ACK */
+	I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_COMPLETE_HASH);
+	if (intel_wait_for_register(dev_priv, HDCP_REP_CTL,
+				    HDCP_SHA1_COMPLETE,
+				    HDCP_SHA1_COMPLETE, 1)) {
+		DRM_ERROR("Timed out waiting for SHA1 complete\n");
+		return -ETIMEDOUT;
+	}
+	if (!(I915_READ(HDCP_REP_CTL) & HDCP_SHA1_V_MATCH)) {
+		DRM_ERROR("SHA-1 mismatch, HDCP failed\n");
+		return -ENXIO;
+	}
+
+	DRM_DEBUG_KMS("HDCP is enabled (%d downstream devices)\n",
+		      num_downstream);
+	return 0;
+}
+
+/* Implements Part 1 of the HDCP authorization procedure */
+static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
+			   const struct intel_hdcp_shim *shim)
+{
+	struct drm_i915_private *dev_priv;
+	enum port port;
+	unsigned long r0_prime_gen_start;
+	int ret, i, tries = 2;
+	union {
+		u32 reg[2];
+		u8 shim[DRM_HDCP_AN_LEN];
+	} an;
+	union {
+		u32 reg[2];
+		u8 shim[DRM_HDCP_KSV_LEN];
+	} bksv;
+	union {
+		u32 reg;
+		u8 shim[DRM_HDCP_RI_LEN];
+	} ri;
+	bool repeater_present, hdcp_capable;
+
+	dev_priv = intel_dig_port->base.base.dev->dev_private;
+
+	port = intel_dig_port->base.port;
+
+	/*
+	 * Detects whether the display is HDCP capable. Although we check for
+	 * valid Bksv below, the HDCP over DP spec requires that we check
+	 * whether the display supports HDCP before we write An. For HDMI
+	 * displays, this is not necessary.
+	 */
+	if (shim->hdcp_capable) {
+		ret = shim->hdcp_capable(intel_dig_port, &hdcp_capable);
+		if (ret)
+			return ret;
+		if (!hdcp_capable) {
+			DRM_ERROR("Panel is not HDCP capable\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Initialize An with 2 random values and acquire it */
+	for (i = 0; i < 2; i++)
+		I915_WRITE(PORT_HDCP_ANINIT(port), get_random_u32());
+	I915_WRITE(PORT_HDCP_CONF(port), HDCP_CONF_CAPTURE_AN);
+
+	/* Wait for An to be acquired */
+	if (intel_wait_for_register(dev_priv, PORT_HDCP_STATUS(port),
+				    HDCP_STATUS_AN_READY,
+				    HDCP_STATUS_AN_READY, 1)) {
+		DRM_ERROR("Timed out waiting for An\n");
+		return -ETIMEDOUT;
+	}
+
+	an.reg[0] = I915_READ(PORT_HDCP_ANLO(port));
+	an.reg[1] = I915_READ(PORT_HDCP_ANHI(port));
+	ret = shim->write_an_aksv(intel_dig_port, an.shim);
+	if (ret)
+		return ret;
+
+	r0_prime_gen_start = jiffies;
+
+	memset(&bksv, 0, sizeof(bksv));
+
+	/* HDCP spec states that we must retry the bksv if it is invalid */
+	for (i = 0; i < tries; i++) {
+		ret = shim->read_bksv(intel_dig_port, bksv.shim);
+		if (ret)
+			return ret;
+		if (intel_hdcp_is_ksv_valid(bksv.shim))
+			break;
+	}
+	if (i == tries) {
+		DRM_ERROR("HDCP failed, Bksv is invalid\n");
+		return -ENODEV;
+	}
+
+	I915_WRITE(PORT_HDCP_BKSVLO(port), bksv.reg[0]);
+	I915_WRITE(PORT_HDCP_BKSVHI(port), bksv.reg[1]);
+
+	ret = shim->repeater_present(intel_dig_port, &repeater_present);
+	if (ret)
+		return ret;
+	if (repeater_present)
+		I915_WRITE(HDCP_REP_CTL,
+			   intel_hdcp_get_repeater_ctl(intel_dig_port));
+
+	ret = shim->toggle_signalling(intel_dig_port, true);
+	if (ret)
+		return ret;
+
+	I915_WRITE(PORT_HDCP_CONF(port), HDCP_CONF_AUTH_AND_ENC);
+
+	/* Wait for R0 ready */
+	if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) &
+		     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
+		DRM_ERROR("Timed out waiting for R0 ready\n");
+		return -ETIMEDOUT;
+	}
+
+	/*
+	 * Wait for R0' to become available. The spec says 100ms from Aksv, but
+	 * some monitors can take longer than this. We'll set the timeout at
+	 * 300ms just to be sure.
+	 *
+	 * On DP, there's an R0_READY bit available but no such bit
+	 * exists on HDMI. Since the upper-bound is the same, we'll just do
+	 * the stupid thing instead of polling on one and not the other.
+	 */
+	wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
+
+	ri.reg = 0;
+	ret = shim->read_ri_prime(intel_dig_port, ri.shim);
+	if (ret)
+		return ret;
+	I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg);
+
+	/* Wait for Ri prime match */
+	if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) &
+		     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
+		DRM_ERROR("Timed out waiting for Ri prime match (%x)\n",
+			  I915_READ(PORT_HDCP_STATUS(port)));
+		return -ETIMEDOUT;
+	}
+
+	/* Wait for encryption confirmation */
+	if (intel_wait_for_register(dev_priv, PORT_HDCP_STATUS(port),
+				    HDCP_STATUS_ENC, HDCP_STATUS_ENC, 20)) {
+		DRM_ERROR("Timed out waiting for encryption\n");
+		return -ETIMEDOUT;
+	}
+
+	/*
+	 * XXX: If we have MST-connected devices, we need to enable encryption
+	 * on those as well.
+	 */
+
+	if (repeater_present)
+		return intel_hdcp_auth_downstream(intel_dig_port, shim);
+
+	DRM_DEBUG_KMS("HDCP is enabled (no repeater present)\n");
+	return 0;
+}
+
+static
+struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector)
+{
+	return enc_to_dig_port(&intel_attached_encoder(&connector->base)->base);
+}
+
+static int _intel_hdcp_disable(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = connector->base.dev->dev_private;
+	struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
+	enum port port = intel_dig_port->base.port;
+	int ret;
+
+	DRM_DEBUG_KMS("[%s:%d] HDCP is being disabled...\n",
+		      connector->base.name, connector->base.base.id);
+
+	I915_WRITE(PORT_HDCP_CONF(port), 0);
+	if (intel_wait_for_register(dev_priv, PORT_HDCP_STATUS(port), ~0, 0,
+				    20)) {
+		DRM_ERROR("Failed to disable HDCP, timeout clearing status\n");
+		return -ETIMEDOUT;
+	}
+
+	ret = connector->hdcp_shim->toggle_signalling(intel_dig_port, false);
+	if (ret) {
+		DRM_ERROR("Failed to disable HDCP signalling\n");
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("HDCP is disabled\n");
+	return 0;
+}
+
+static int _intel_hdcp_enable(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = connector->base.dev->dev_private;
+	int i, ret, tries = 3;
+
+	DRM_DEBUG_KMS("[%s:%d] HDCP is being enabled...\n",
+		      connector->base.name, connector->base.base.id);
+
+	if (!(I915_READ(SKL_FUSE_STATUS) & SKL_FUSE_PG_DIST_STATUS(1))) {
+		DRM_ERROR("PG1 is disabled, cannot load keys\n");
+		return -ENXIO;
+	}
+
+	for (i = 0; i < KEY_LOAD_TRIES; i++) {
+		ret = intel_hdcp_load_keys(dev_priv);
+		if (!ret)
+			break;
+		intel_hdcp_clear_keys(dev_priv);
+	}
+	if (ret) {
+		DRM_ERROR("Could not load HDCP keys, (%d)\n", ret);
+		return ret;
+	}
+
+	/* Incase of authentication failures, HDCP spec expects reauth. */
+	for (i = 0; i < tries; i++) {
+		ret = intel_hdcp_auth(conn_to_dig_port(connector),
+				      connector->hdcp_shim);
+		if (!ret)
+			return 0;
+
+		DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret);
+
+		/* Ensuring HDCP encryption and signalling are stopped. */
+		_intel_hdcp_disable(connector);
+	}
+
+	DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret);
+	return ret;
+}
+
+static void intel_hdcp_check_work(struct work_struct *work)
+{
+	struct intel_connector *connector = container_of(to_delayed_work(work),
+							 struct intel_connector,
+							 hdcp_check_work);
+	if (!intel_hdcp_check_link(connector))
+		schedule_delayed_work(&connector->hdcp_check_work,
+				      DRM_HDCP_CHECK_PERIOD_MS);
+}
+
+static void intel_hdcp_prop_work(struct work_struct *work)
+{
+	struct intel_connector *connector = container_of(work,
+							 struct intel_connector,
+							 hdcp_prop_work);
+	struct drm_device *dev = connector->base.dev;
+	struct drm_connector_state *state;
+
+	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+	mutex_lock(&connector->hdcp_mutex);
+
+	/*
+	 * This worker is only used to flip between ENABLED/DESIRED. Either of
+	 * those to UNDESIRED is handled by core. If hdcp_value == UNDESIRED,
+	 * we're running just after hdcp has been disabled, so just exit
+	 */
+	if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+		state = connector->base.state;
+		state->content_protection = connector->hdcp_value;
+	}
+
+	mutex_unlock(&connector->hdcp_mutex);
+	drm_modeset_unlock(&dev->mode_config.connection_mutex);
+}
+
+bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
+{
+	/* PORT E doesn't have HDCP, and PORT F is disabled */
+	return ((INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv)) &&
+		!IS_CHERRYVIEW(dev_priv) && port < PORT_E);
+}
+
+int intel_hdcp_init(struct intel_connector *connector,
+		    const struct intel_hdcp_shim *hdcp_shim)
+{
+	int ret;
+
+	ret = drm_connector_attach_content_protection_property(
+			&connector->base);
+	if (ret)
+		return ret;
+
+	connector->hdcp_shim = hdcp_shim;
+	mutex_init(&connector->hdcp_mutex);
+	INIT_DELAYED_WORK(&connector->hdcp_check_work, intel_hdcp_check_work);
+	INIT_WORK(&connector->hdcp_prop_work, intel_hdcp_prop_work);
+	return 0;
+}
+
+int intel_hdcp_enable(struct intel_connector *connector)
+{
+	int ret;
+
+	if (!connector->hdcp_shim)
+		return -ENOENT;
+
+	mutex_lock(&connector->hdcp_mutex);
+
+	ret = _intel_hdcp_enable(connector);
+	if (ret)
+		goto out;
+
+	connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+	schedule_work(&connector->hdcp_prop_work);
+	schedule_delayed_work(&connector->hdcp_check_work,
+			      DRM_HDCP_CHECK_PERIOD_MS);
+out:
+	mutex_unlock(&connector->hdcp_mutex);
+	return ret;
+}
+
+int intel_hdcp_disable(struct intel_connector *connector)
+{
+	int ret = 0;
+
+	if (!connector->hdcp_shim)
+		return -ENOENT;
+
+	mutex_lock(&connector->hdcp_mutex);
+
+	if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+		connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+		ret = _intel_hdcp_disable(connector);
+	}
+
+	mutex_unlock(&connector->hdcp_mutex);
+	cancel_delayed_work_sync(&connector->hdcp_check_work);
+	return ret;
+}
+
+void intel_hdcp_atomic_check(struct drm_connector *connector,
+			     struct drm_connector_state *old_state,
+			     struct drm_connector_state *new_state)
+{
+	uint64_t old_cp = old_state->content_protection;
+	uint64_t new_cp = new_state->content_protection;
+	struct drm_crtc_state *crtc_state;
+
+	if (!new_state->crtc) {
+		/*
+		 * If the connector is being disabled with CP enabled, mark it
+		 * desired so it's re-enabled when the connector is brought back
+		 */
+		if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+			new_state->content_protection =
+				DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		return;
+	}
+
+	/*
+	 * Nothing to do if the state didn't change, or HDCP was activated since
+	 * the last commit
+	 */
+	if (old_cp == new_cp ||
+	    (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+	     new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED))
+		return;
+
+	crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
+						   new_state->crtc);
+	crtc_state->mode_changed = true;
+}
+
+/* Implements Part 3 of the HDCP authorization procedure */
+int intel_hdcp_check_link(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = connector->base.dev->dev_private;
+	struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
+	enum port port = intel_dig_port->base.port;
+	int ret = 0;
+
+	if (!connector->hdcp_shim)
+		return -ENOENT;
+
+	mutex_lock(&connector->hdcp_mutex);
+
+	if (connector->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+		goto out;
+
+	if (!(I915_READ(PORT_HDCP_STATUS(port)) & HDCP_STATUS_ENC)) {
+		DRM_ERROR("%s:%d HDCP check failed: link is not encrypted,%x\n",
+			  connector->base.name, connector->base.base.id,
+			  I915_READ(PORT_HDCP_STATUS(port)));
+		ret = -ENXIO;
+		connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		schedule_work(&connector->hdcp_prop_work);
+		goto out;
+	}
+
+	if (connector->hdcp_shim->check_link(intel_dig_port)) {
+		if (connector->hdcp_value !=
+		    DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+			connector->hdcp_value =
+				DRM_MODE_CONTENT_PROTECTION_ENABLED;
+			schedule_work(&connector->hdcp_prop_work);
+		}
+		goto out;
+	}
+
+	DRM_DEBUG_KMS("[%s:%d] HDCP link failed, retrying authentication\n",
+		      connector->base.name, connector->base.base.id);
+
+	ret = _intel_hdcp_disable(connector);
+	if (ret) {
+		DRM_ERROR("Failed to disable hdcp (%d)\n", ret);
+		connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		schedule_work(&connector->hdcp_prop_work);
+		goto out;
+	}
+
+	ret = _intel_hdcp_enable(connector);
+	if (ret) {
+		DRM_ERROR("Failed to enable hdcp (%d)\n", ret);
+		connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		schedule_work(&connector->hdcp_prop_work);
+		goto out;
+	}
+
+out:
+	mutex_unlock(&connector->hdcp_mutex);
+	return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 179d0ad3889d..f5d7bfb43006 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -34,6 +34,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_hdcp.h>
 #include <drm/drm_scdc_helper.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
@@ -876,6 +877,248 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
 					 adapter, enable);
 }
 
+static int intel_hdmi_hdcp_read(struct intel_digital_port *intel_dig_port,
+				unsigned int offset, void *buffer, size_t size)
+{
+	struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+	struct drm_i915_private *dev_priv =
+		intel_dig_port->base.base.dev->dev_private;
+	struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
+							      hdmi->ddc_bus);
+	int ret;
+	u8 start = offset & 0xff;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = DRM_HDCP_DDC_ADDR,
+			.flags = 0,
+			.len = 1,
+			.buf = &start,
+		},
+		{
+			.addr = DRM_HDCP_DDC_ADDR,
+			.flags = I2C_M_RD,
+			.len = size,
+			.buf = buffer
+		}
+	};
+	ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret == ARRAY_SIZE(msgs))
+		return 0;
+	return ret >= 0 ? -EIO : ret;
+}
+
+static int intel_hdmi_hdcp_write(struct intel_digital_port *intel_dig_port,
+				 unsigned int offset, void *buffer, size_t size)
+{
+	struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+	struct drm_i915_private *dev_priv =
+		intel_dig_port->base.base.dev->dev_private;
+	struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
+							      hdmi->ddc_bus);
+	int ret;
+	u8 *write_buf;
+	struct i2c_msg msg;
+
+	write_buf = kzalloc(size + 1, GFP_KERNEL);
+	if (!write_buf)
+		return -ENOMEM;
+
+	write_buf[0] = offset & 0xff;
+	memcpy(&write_buf[1], buffer, size);
+
+	msg.addr = DRM_HDCP_DDC_ADDR;
+	msg.flags = 0,
+	msg.len = size + 1,
+	msg.buf = write_buf;
+
+	ret = i2c_transfer(adapter, &msg, 1);
+	if (ret == 1)
+		return 0;
+	return ret >= 0 ? -EIO : ret;
+}
+
+static
+int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
+				  u8 *an)
+{
+	struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
+	struct drm_i915_private *dev_priv =
+		intel_dig_port->base.base.dev->dev_private;
+	struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
+							      hdmi->ddc_bus);
+	int ret;
+
+	ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an,
+				    DRM_HDCP_AN_LEN);
+	if (ret) {
+		DRM_ERROR("Write An over DDC failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = intel_gmbus_output_aksv(adapter);
+	if (ret < 0) {
+		DRM_ERROR("Failed to output aksv (%d)\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
+				     u8 *bksv)
+{
+	int ret;
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv,
+				   DRM_HDCP_KSV_LEN);
+	if (ret)
+		DRM_ERROR("Read Bksv over DDC failed (%d)\n", ret);
+	return ret;
+}
+
+static
+int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
+				 u8 *bstatus)
+{
+	int ret;
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS,
+				   bstatus, DRM_HDCP_BSTATUS_LEN);
+	if (ret)
+		DRM_ERROR("Read bstatus over DDC failed (%d)\n", ret);
+	return ret;
+}
+
+static
+int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
+				     bool *repeater_present)
+{
+	int ret;
+	u8 val;
+
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
+	if (ret) {
+		DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
+		return ret;
+	}
+	*repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
+	return 0;
+}
+
+static
+int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
+				  u8 *ri_prime)
+{
+	int ret;
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME,
+				   ri_prime, DRM_HDCP_RI_LEN);
+	if (ret)
+		DRM_ERROR("Read Ri' over DDC failed (%d)\n", ret);
+	return ret;
+}
+
+static
+int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
+				   bool *ksv_ready)
+{
+	int ret;
+	u8 val;
+
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
+	if (ret) {
+		DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
+		return ret;
+	}
+	*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
+	return 0;
+}
+
+static
+int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
+				  int num_downstream, u8 *ksv_fifo)
+{
+	int ret;
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO,
+				   ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
+	if (ret) {
+		DRM_ERROR("Read ksv fifo over DDC failed (%d)\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static
+int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
+				      int i, u32 *part)
+{
+	int ret;
+
+	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
+		return -EINVAL;
+
+	ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i),
+				   part, DRM_HDCP_V_PRIME_PART_LEN);
+	if (ret)
+		DRM_ERROR("Read V'[%d] over DDC failed (%d)\n", i, ret);
+	return ret;
+}
+
+static
+int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
+				      bool enable)
+{
+	int ret;
+
+	if (!enable)
+		usleep_range(6, 60); /* Bspec says >= 6us */
+
+	ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, enable);
+	if (ret) {
+		DRM_ERROR("%s HDCP signalling failed (%d)\n",
+			  enable ? "Enable" : "Disable", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static
+bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port)
+{
+	struct drm_i915_private *dev_priv =
+		intel_dig_port->base.base.dev->dev_private;
+	enum port port = intel_dig_port->base.port;
+	int ret;
+	union {
+		u32 reg;
+		u8 shim[DRM_HDCP_RI_LEN];
+	} ri;
+
+	ret = intel_hdmi_hdcp_read_ri_prime(intel_dig_port, ri.shim);
+	if (ret)
+		return false;
+
+	I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg);
+
+	/* Wait for Ri prime match */
+	if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) &
+		     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
+		DRM_ERROR("Ri' mismatch detected, link check failed (%x)\n",
+			  I915_READ(PORT_HDCP_STATUS(port)));
+		return false;
+	}
+	return true;
+}
+
+static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
+	.write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
+	.read_bksv = intel_hdmi_hdcp_read_bksv,
+	.read_bstatus = intel_hdmi_hdcp_read_bstatus,
+	.repeater_present = intel_hdmi_hdcp_repeater_present,
+	.read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
+	.read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
+	.read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
+	.read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
+	.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
+	.check_link = intel_hdmi_hdcp_check_link,
+};
+
 static void intel_hdmi_prepare(struct intel_encoder *encoder,
 			       const struct intel_crtc_state *crtc_state)
 {
@@ -1314,9 +1557,6 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
 	bool force_dvi =
 		READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
 
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		return MODE_NO_DBLESCAN;
-
 	clock = mode->clock;
 
 	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
@@ -1567,7 +1807,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
 	 * there's nothing connected to the port.
 	 */
 	if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
-		if (has_edid &&
+		/* An overridden EDID imply that we want this port for testing.
+		 * Make sure not to set limits for that port.
+		 */
+		if (has_edid && !connector->override_edid &&
 		    intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
 			DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n");
 			type = DRM_DP_DUAL_MODE_TYPE1_DVI;
@@ -1932,6 +2175,9 @@ static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv,
 	case PORT_D:
 		ddc_pin = GMBUS_PIN_4_CNP;
 		break;
+	case PORT_F:
+		ddc_pin = GMBUS_PIN_3_BXT;
+		break;
 	default:
 		MISSING_CASE(port);
 		ddc_pin = GMBUS_PIN_1_BXT;
@@ -1940,6 +2186,37 @@ static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv,
 	return ddc_pin;
 }
 
+static u8 icl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
+{
+	u8 ddc_pin;
+
+	switch (port) {
+	case PORT_A:
+		ddc_pin = GMBUS_PIN_1_BXT;
+		break;
+	case PORT_B:
+		ddc_pin = GMBUS_PIN_2_BXT;
+		break;
+	case PORT_C:
+		ddc_pin = GMBUS_PIN_9_TC1_ICP;
+		break;
+	case PORT_D:
+		ddc_pin = GMBUS_PIN_10_TC2_ICP;
+		break;
+	case PORT_E:
+		ddc_pin = GMBUS_PIN_11_TC3_ICP;
+		break;
+	case PORT_F:
+		ddc_pin = GMBUS_PIN_12_TC4_ICP;
+		break;
+	default:
+		MISSING_CASE(port);
+		ddc_pin = GMBUS_PIN_2_BXT;
+		break;
+	}
+	return ddc_pin;
+}
+
 static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv,
 			      enum port port)
 {
@@ -1982,6 +2259,8 @@ static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
 		ddc_pin = bxt_port_to_ddc_pin(dev_priv, port);
 	else if (HAS_PCH_CNP(dev_priv))
 		ddc_pin = cnp_port_to_ddc_pin(dev_priv, port);
+	else if (IS_ICELAKE(dev_priv))
+		ddc_pin = icl_port_to_ddc_pin(dev_priv, port);
 	else
 		ddc_pin = g4x_port_to_ddc_pin(dev_priv, port);
 
@@ -2052,7 +2331,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 
 	if (WARN_ON(port == PORT_A))
 		return;
-	intel_encoder->hpd_pin = intel_hpd_pin(port);
+	intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
 
 	if (HAS_DDI(dev_priv))
 		intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
@@ -2061,6 +2340,13 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 
 	intel_hdmi_add_properties(intel_hdmi, connector);
 
+	if (is_hdcp_supported(dev_priv, port)) {
+		int ret = intel_hdcp_init(intel_connector,
+					  &intel_hdmi_hdcp_shim);
+		if (ret)
+			DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
+	}
+
 	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_hdmi->attached_connector = intel_connector;
 
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index 875d5d218d5c..fe28c1ea84a5 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -78,12 +78,14 @@
 
 /**
  * intel_hpd_port - return port hard associated with certain pin.
+ * @dev_priv: private driver data pointer
  * @pin: the hpd pin to get associated port
  *
  * Return port that is associatade with @pin and PORT_NONE if no port is
  * hard associated with that @pin.
  */
-enum port intel_hpd_pin_to_port(enum hpd_pin pin)
+enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv,
+				enum hpd_pin pin)
 {
 	switch (pin) {
 	case HPD_PORT_A:
@@ -95,6 +97,8 @@ enum port intel_hpd_pin_to_port(enum hpd_pin pin)
 	case HPD_PORT_D:
 		return PORT_D;
 	case HPD_PORT_E:
+		if (IS_CNL_WITH_PORT_F(dev_priv))
+			return PORT_F;
 		return PORT_E;
 	default:
 		return PORT_NONE; /* no port for this pin */
@@ -102,13 +106,17 @@ enum port intel_hpd_pin_to_port(enum hpd_pin pin)
 }
 
 /**
- * intel_hpd_pin - return pin hard associated with certain port.
+ * intel_hpd_pin_default - return default pin associated with certain port.
+ * @dev_priv: private driver data pointer
  * @port: the hpd port to get associated pin
  *
+ * It is only valid and used by digital port encoder.
+ *
  * Return pin that is associatade with @port and HDP_NONE if no pin is
  * hard associated with that @port.
  */
-enum hpd_pin intel_hpd_pin(enum port port)
+enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
+				   enum port port)
 {
 	switch (port) {
 	case PORT_A:
@@ -121,6 +129,9 @@ enum hpd_pin intel_hpd_pin(enum port port)
 		return HPD_PORT_D;
 	case PORT_E:
 		return HPD_PORT_E;
+	case PORT_F:
+		if (IS_CNL_WITH_PORT_F(dev_priv))
+			return HPD_PORT_E;
 	default:
 		MISSING_CASE(port);
 		return HPD_NONE;
@@ -417,7 +428,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
 		if (!(BIT(i) & pin_mask))
 			continue;
 
-		port = intel_hpd_pin_to_port(i);
+		port = intel_hpd_pin_to_port(dev_priv, i);
 		is_dig_port = port != PORT_NONE &&
 			dev_priv->hotplug.irq_port[port];
 
diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c
index 8ed05182f944..ef9a05d8e5a9 100644
--- a/drivers/gpu/drm/i915/intel_huc.c
+++ b/drivers/gpu/drm/i915/intel_huc.c
@@ -118,7 +118,8 @@ void intel_huc_init_early(struct intel_huc *huc)
 
 /**
  * huc_ucode_xfer() - DMA's the firmware
- * @dev_priv: the drm_i915_private device
+ * @huc_fw: the firmware descriptor
+ * @vma: the firmware image (bound into the GGTT)
  *
  * Transfer the firmware image to RAM for execution by the microcontroller.
  *
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index ef9f91a0b0c9..e6875509bcd9 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -30,6 +30,7 @@
 #include <linux/i2c-algo-bit.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include <drm/drm_hdcp.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -75,11 +76,22 @@ static const struct gmbus_pin gmbus_pins_cnp[] = {
 	[GMBUS_PIN_4_CNP] = { "dpd", GPIOE },
 };
 
+static const struct gmbus_pin gmbus_pins_icp[] = {
+	[GMBUS_PIN_1_BXT] = { "dpa", GPIOA },
+	[GMBUS_PIN_2_BXT] = { "dpb", GPIOB },
+	[GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOC },
+	[GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOD },
+	[GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOE },
+	[GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOF },
+};
+
 /* pin is expected to be valid */
 static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv,
 					     unsigned int pin)
 {
-	if (HAS_PCH_CNP(dev_priv))
+	if (HAS_PCH_ICP(dev_priv))
+		return &gmbus_pins_icp[pin];
+	else if (HAS_PCH_CNP(dev_priv))
 		return &gmbus_pins_cnp[pin];
 	else if (IS_GEN9_LP(dev_priv))
 		return &gmbus_pins_bxt[pin];
@@ -96,7 +108,9 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
 {
 	unsigned int size;
 
-	if (HAS_PCH_CNP(dev_priv))
+	if (HAS_PCH_ICP(dev_priv))
+		size = ARRAY_SIZE(gmbus_pins_icp);
+	else if (HAS_PCH_CNP(dev_priv))
 		size = ARRAY_SIZE(gmbus_pins_cnp);
 	else if (IS_GEN9_LP(dev_priv))
 		size = ARRAY_SIZE(gmbus_pins_bxt);
@@ -402,7 +416,8 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
 
 static int
 gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
-		       unsigned short addr, u8 *buf, unsigned int len)
+		       unsigned short addr, u8 *buf, unsigned int len,
+		       u32 gmbus1_index)
 {
 	unsigned int chunk_size = len;
 	u32 val, loop;
@@ -415,7 +430,7 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
 
 	I915_WRITE_FW(GMBUS3, val);
 	I915_WRITE_FW(GMBUS1,
-		      GMBUS_CYCLE_WAIT |
+		      gmbus1_index | GMBUS_CYCLE_WAIT |
 		      (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
 		      (addr << GMBUS_SLAVE_ADDR_SHIFT) |
 		      GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
@@ -438,7 +453,8 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
 }
 
 static int
-gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
+gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
+		 u32 gmbus1_index)
 {
 	u8 *buf = msg->buf;
 	unsigned int tx_size = msg->len;
@@ -448,7 +464,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
 	do {
 		len = min(tx_size, GMBUS_BYTE_COUNT_MAX);
 
-		ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len);
+		ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len,
+					     gmbus1_index);
 		if (ret)
 			return ret;
 
@@ -460,21 +477,21 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
 }
 
 /*
- * The gmbus controller can combine a 1 or 2 byte write with a read that
- * immediately follows it by using an "INDEX" cycle.
+ * The gmbus controller can combine a 1 or 2 byte write with another read/write
+ * that immediately follows it by using an "INDEX" cycle.
  */
 static bool
-gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)
+gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num)
 {
 	return (i + 1 < num &&
 		msgs[i].addr == msgs[i + 1].addr &&
 		!(msgs[i].flags & I2C_M_RD) &&
 		(msgs[i].len == 1 || msgs[i].len == 2) &&
-		(msgs[i + 1].flags & I2C_M_RD));
+		msgs[i + 1].len > 0);
 }
 
 static int
-gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
+gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 {
 	u32 gmbus1_index = 0;
 	u32 gmbus5 = 0;
@@ -491,7 +508,10 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 	if (gmbus5)
 		I915_WRITE_FW(GMBUS5, gmbus5);
 
-	ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
+	if (msgs[1].flags & I2C_M_RD)
+		ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
+	else
+		ret = gmbus_xfer_write(dev_priv, &msgs[1], gmbus1_index);
 
 	/* Clear GMBUS5 after each index transfer */
 	if (gmbus5)
@@ -501,7 +521,8 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
 }
 
 static int
-do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
+	      u32 gmbus0_source)
 {
 	struct intel_gmbus *bus = container_of(adapter,
 					       struct intel_gmbus,
@@ -518,17 +539,17 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 		pch_gmbus_clock_gating(dev_priv, false);
 
 retry:
-	I915_WRITE_FW(GMBUS0, bus->reg0);
+	I915_WRITE_FW(GMBUS0, gmbus0_source | bus->reg0);
 
 	for (; i < num; i += inc) {
 		inc = 1;
-		if (gmbus_is_index_read(msgs, i, num)) {
-			ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
-			inc = 2; /* an index read is two msgs */
+		if (gmbus_is_index_xfer(msgs, i, num)) {
+			ret = gmbus_index_xfer(dev_priv, &msgs[i]);
+			inc = 2; /* an index transmission is two msgs */
 		} else if (msgs[i].flags & I2C_M_RD) {
 			ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
 		} else {
-			ret = gmbus_xfer_write(dev_priv, &msgs[i]);
+			ret = gmbus_xfer_write(dev_priv, &msgs[i], 0);
 		}
 
 		if (!ret)
@@ -643,7 +664,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 		if (ret < 0)
 			bus->force_bit &= ~GMBUS_FORCE_BIT_RETRY;
 	} else {
-		ret = do_gmbus_xfer(adapter, msgs, num);
+		ret = do_gmbus_xfer(adapter, msgs, num, 0);
 		if (ret == -EAGAIN)
 			bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
 	}
@@ -653,6 +674,45 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
 	return ret;
 }
 
+int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
+{
+	struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
+					       adapter);
+	struct drm_i915_private *dev_priv = bus->dev_priv;
+	int ret;
+	u8 cmd = DRM_HDCP_DDC_AKSV;
+	u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
+	struct i2c_msg msgs[] = {
+		{
+			.addr = DRM_HDCP_DDC_ADDR,
+			.flags = 0,
+			.len = sizeof(cmd),
+			.buf = &cmd,
+		},
+		{
+			.addr = DRM_HDCP_DDC_ADDR,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+	mutex_lock(&dev_priv->gmbus_mutex);
+
+	/*
+	 * In order to output Aksv to the receiver, use an indexed write to
+	 * pass the i2c command, and tell GMBUS to use the HW-provided value
+	 * instead of sourcing GMBUS3 for the data.
+	 */
+	ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
+
+	mutex_unlock(&dev_priv->gmbus_mutex);
+	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+
+	return ret;
+}
+
 static u32 gmbus_func(struct i2c_adapter *adapter)
 {
 	return i2c_bit_algo.functionality(adapter) &
diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c
index 5809b29044fc..6269750e2b54 100644
--- a/drivers/gpu/drm/i915/intel_lpe_audio.c
+++ b/drivers/gpu/drm/i915/intel_lpe_audio.c
@@ -74,7 +74,6 @@
 static struct platform_device *
 lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
 {
-	int ret;
 	struct drm_device *dev = &dev_priv->drm;
 	struct platform_device_info pinfo = {};
 	struct resource *rsc;
@@ -119,24 +118,19 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
 	spin_lock_init(&pdata->lpe_audio_slock);
 
 	platdev = platform_device_register_full(&pinfo);
+	kfree(rsc);
+	kfree(pdata);
+
 	if (IS_ERR(platdev)) {
-		ret = PTR_ERR(platdev);
 		DRM_ERROR("Failed to allocate LPE audio platform device\n");
-		goto err;
+		return platdev;
 	}
 
-	kfree(rsc);
-
 	pm_runtime_forbid(&platdev->dev);
 	pm_runtime_set_active(&platdev->dev);
 	pm_runtime_enable(&platdev->dev);
 
 	return platdev;
-
-err:
-	kfree(rsc);
-	kfree(pdata);
-	return ERR_PTR(ret);
 }
 
 static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 7ece2f061b9e..9b6d781b22ec 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -137,6 +137,7 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_gem_render_state.h"
+#include "intel_lrc_reg.h"
 #include "intel_mocs.h"
 
 #define RING_EXECLIST_QFULL		(1 << 0x2)
@@ -156,60 +157,10 @@
 #define GEN8_CTX_STATUS_COMPLETED_MASK \
 	 (GEN8_CTX_STATUS_COMPLETE | GEN8_CTX_STATUS_PREEMPTED)
 
-#define CTX_LRI_HEADER_0		0x01
-#define CTX_CONTEXT_CONTROL		0x02
-#define CTX_RING_HEAD			0x04
-#define CTX_RING_TAIL			0x06
-#define CTX_RING_BUFFER_START		0x08
-#define CTX_RING_BUFFER_CONTROL		0x0a
-#define CTX_BB_HEAD_U			0x0c
-#define CTX_BB_HEAD_L			0x0e
-#define CTX_BB_STATE			0x10
-#define CTX_SECOND_BB_HEAD_U		0x12
-#define CTX_SECOND_BB_HEAD_L		0x14
-#define CTX_SECOND_BB_STATE		0x16
-#define CTX_BB_PER_CTX_PTR		0x18
-#define CTX_RCS_INDIRECT_CTX		0x1a
-#define CTX_RCS_INDIRECT_CTX_OFFSET	0x1c
-#define CTX_LRI_HEADER_1		0x21
-#define CTX_CTX_TIMESTAMP		0x22
-#define CTX_PDP3_UDW			0x24
-#define CTX_PDP3_LDW			0x26
-#define CTX_PDP2_UDW			0x28
-#define CTX_PDP2_LDW			0x2a
-#define CTX_PDP1_UDW			0x2c
-#define CTX_PDP1_LDW			0x2e
-#define CTX_PDP0_UDW			0x30
-#define CTX_PDP0_LDW			0x32
-#define CTX_LRI_HEADER_2		0x41
-#define CTX_R_PWR_CLK_STATE		0x42
-#define CTX_GPGPU_CSR_BASE_ADDRESS	0x44
-
-#define CTX_REG(reg_state, pos, reg, val) do { \
-	(reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \
-	(reg_state)[(pos)+1] = (val); \
-} while (0)
-
-#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do {		\
-	const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n));	\
-	reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \
-	reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
-} while (0)
-
-#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \
-	reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \
-	reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \
-} while (0)
-
-#define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT	0x17
-#define GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT	0x26
-#define GEN10_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT	0x19
-
 /* Typical size of the average request (2 pipecontrols and a MI_BB) */
 #define EXECLISTS_REQUEST_SIZE 64 /* bytes */
 #define WA_TAIL_DWORDS 2
 #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS)
-#define PREEMPT_ID 0x1
 
 static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 					    struct intel_engine_cs *engine);
@@ -496,7 +447,8 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 		&engine->i915->preempt_context->engine[engine->id];
 	unsigned int n;
 
-	GEM_BUG_ON(engine->i915->preempt_context->hw_id != PREEMPT_ID);
+	GEM_BUG_ON(engine->execlists.preempt_complete_status !=
+		   upper_32_bits(ce->lrc_desc));
 	GEM_BUG_ON(!IS_ALIGNED(ce->ring->size, WA_TAIL_BYTES));
 
 	memset(ce->ring->vaddr + ce->ring->tail, 0, WA_TAIL_BYTES);
@@ -504,6 +456,12 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 	ce->ring->tail &= (ce->ring->size - 1);
 	ce->lrc_reg_state[CTX_RING_TAIL+1] = ce->ring->tail;
 
+	GEM_BUG_ON((ce->lrc_reg_state[CTX_CONTEXT_CONTROL + 1] &
+		    _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
+				       CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)) !=
+		   _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
+				      CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT));
+
 	GEM_TRACE("%s\n", engine->name);
 	for (n = execlists_num_ports(&engine->execlists); --n; )
 		elsp_write(0, engine->execlists.elsp);
@@ -570,7 +528,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 		if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_HWACK))
 			goto unlock;
 
-		if (HAS_LOGICAL_RING_PREEMPTION(engine->i915) &&
+		if (engine->i915->preempt_context &&
 		    rb_entry(rb, struct i915_priolist, node)->priority >
 		    max(last->priotree.priority, 0)) {
 			/*
@@ -684,6 +642,10 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 	execlists->first = rb;
 	if (submit)
 		port_assign(port, last);
+
+	/* We must always keep the beast fed if we have work piled up */
+	GEM_BUG_ON(execlists->first && !port_isset(execlists->port));
+
 unlock:
 	spin_unlock_irq(&engine->timeline->lock);
 
@@ -691,6 +653,9 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 		execlists_set_active(execlists, EXECLISTS_ACTIVE_USER);
 		execlists_submit_ports(engine);
 	}
+
+	GEM_BUG_ON(port_isset(execlists->port) &&
+		   !execlists_is_active(execlists, EXECLISTS_ACTIVE_USER));
 }
 
 void
@@ -778,6 +743,7 @@ static void execlists_submission_tasklet(unsigned long data)
 	struct intel_engine_execlists * const execlists = &engine->execlists;
 	struct execlist_port * const port = execlists->port;
 	struct drm_i915_private *dev_priv = engine->i915;
+	bool fw = false;
 
 	/* We can skip acquiring intel_runtime_pm_get() here as it was taken
 	 * on our behalf by the request (see i915_gem_mark_busy()) and it will
@@ -788,8 +754,6 @@ static void execlists_submission_tasklet(unsigned long data)
 	 */
 	GEM_BUG_ON(!dev_priv->gt.awake);
 
-	intel_uncore_forcewake_get(dev_priv, execlists->fw_domains);
-
 	/* Prefer doing test_and_clear_bit() as a two stage operation to avoid
 	 * imposing the cost of a locked atomic transaction when submitting a
 	 * new request (outside of the context-switch interrupt).
@@ -818,6 +782,12 @@ static void execlists_submission_tasklet(unsigned long data)
 		 */
 		__clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
 		if (unlikely(execlists->csb_head == -1)) { /* following a reset */
+			if (!fw) {
+				intel_uncore_forcewake_get(dev_priv,
+							   execlists->fw_domains);
+				fw = true;
+			}
+
 			head = readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)));
 			tail = GEN8_CSB_WRITE_PTR(head);
 			head = GEN8_CSB_READ_PTR(head);
@@ -830,10 +800,10 @@ static void execlists_submission_tasklet(unsigned long data)
 			head = execlists->csb_head;
 			tail = READ_ONCE(buf[write_idx]);
 		}
-		GEM_TRACE("%s cs-irq head=%d [%d], tail=%d [%d]\n",
+		GEM_TRACE("%s cs-irq head=%d [%d%s], tail=%d [%d%s]\n",
 			  engine->name,
-			  head, GEN8_CSB_READ_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))),
-			  tail, GEN8_CSB_WRITE_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))));
+			  head, GEN8_CSB_READ_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?",
+			  tail, GEN8_CSB_WRITE_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?");
 
 		while (head != tail) {
 			struct drm_i915_gem_request *rq;
@@ -881,7 +851,7 @@ static void execlists_submission_tasklet(unsigned long data)
 			GEM_BUG_ON(status & GEN8_CTX_STATUS_IDLE_ACTIVE);
 
 			if (status & GEN8_CTX_STATUS_COMPLETE &&
-			    buf[2*head + 1] == PREEMPT_ID) {
+			    buf[2*head + 1] == execlists->preempt_complete_status) {
 				GEM_TRACE("%s preempt-idle\n", engine->name);
 
 				execlists_cancel_port_requests(execlists);
@@ -943,7 +913,8 @@ static void execlists_submission_tasklet(unsigned long data)
 	if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT))
 		execlists_dequeue(engine);
 
-	intel_uncore_forcewake_put(dev_priv, execlists->fw_domains);
+	if (fw)
+		intel_uncore_forcewake_put(dev_priv, execlists->fw_domains);
 }
 
 static void insert_request(struct intel_engine_cs *engine,
@@ -1014,7 +985,8 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio)
 	stack.signaler = &request->priotree;
 	list_add(&stack.dfs_link, &dfs);
 
-	/* Recursively bump all dependent priorities to match the new request.
+	/*
+	 * Recursively bump all dependent priorities to match the new request.
 	 *
 	 * A naive approach would be to use recursion:
 	 * static void update_priorities(struct i915_priotree *pt, prio) {
@@ -1031,27 +1003,29 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio)
 	 * end result is a topological list of requests in reverse order, the
 	 * last element in the list is the request we must execute first.
 	 */
-	list_for_each_entry_safe(dep, p, &dfs, dfs_link) {
+	list_for_each_entry(dep, &dfs, dfs_link) {
 		struct i915_priotree *pt = dep->signaler;
 
-		/* Within an engine, there can be no cycle, but we may
+		/*
+		 * Within an engine, there can be no cycle, but we may
 		 * refer to the same dependency chain multiple times
 		 * (redundant dependencies are not eliminated) and across
 		 * engines.
 		 */
 		list_for_each_entry(p, &pt->signalers_list, signal_link) {
-			if (i915_gem_request_completed(pt_to_request(p->signaler)))
+			GEM_BUG_ON(p == dep); /* no cycles! */
+
+			if (i915_priotree_signaled(p->signaler))
 				continue;
 
 			GEM_BUG_ON(p->signaler->priority < pt->priority);
 			if (prio > READ_ONCE(p->signaler->priority))
 				list_move_tail(&p->dfs_link, &dfs);
 		}
-
-		list_safe_reset_next(dep, p, dfs_link);
 	}
 
-	/* If we didn't need to bump any existing priorities, and we haven't
+	/*
+	 * If we didn't need to bump any existing priorities, and we haven't
 	 * yet submitted this request (i.e. there is no potential race with
 	 * execlists_submit_request()), we can set our own priority and skip
 	 * acquiring the engine locks.
@@ -1125,11 +1099,9 @@ execlists_context_pin(struct intel_engine_cs *engine,
 		goto out;
 	GEM_BUG_ON(!ce->pin_count); /* no overflow please! */
 
-	if (!ce->state) {
-		ret = execlists_context_deferred_alloc(ctx, engine);
-		if (ret)
-			goto err;
-	}
+	ret = execlists_context_deferred_alloc(ctx, engine);
+	if (ret)
+		goto err;
 	GEM_BUG_ON(!ce->state);
 
 	ret = __context_pin(ctx, ce->state);
@@ -1363,6 +1335,40 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch)
 	return batch;
 }
 
+static u32 *
+gen10_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch)
+{
+	int i;
+
+	/*
+	 * WaPipeControlBefore3DStateSamplePattern: cnl
+	 *
+	 * Ensure the engine is idle prior to programming a
+	 * 3DSTATE_SAMPLE_PATTERN during a context restore.
+	 */
+	batch = gen8_emit_pipe_control(batch,
+				       PIPE_CONTROL_CS_STALL,
+				       0);
+	/*
+	 * WaPipeControlBefore3DStateSamplePattern says we need 4 dwords for
+	 * the PIPE_CONTROL followed by 12 dwords of 0x0, so 16 dwords in
+	 * total. However, a PIPE_CONTROL is 6 dwords long, not 4, which is
+	 * confusing. Since gen8_emit_pipe_control() already advances the
+	 * batch by 6 dwords, we advance the other 10 here, completing a
+	 * cacheline. It's not clear if the workaround requires this padding
+	 * before other commands, or if it's just the regular padding we would
+	 * already have for the workaround bb, so leave it here for now.
+	 */
+	for (i = 0; i < 10; i++)
+		*batch++ = MI_NOOP;
+
+	/* Pad to end of cacheline */
+	while ((unsigned long)batch % CACHELINE_BYTES)
+		*batch++ = MI_NOOP;
+
+	return batch;
+}
+
 #define CTX_WA_BB_OBJ_SIZE (PAGE_SIZE)
 
 static int lrc_setup_wa_ctx(struct intel_engine_cs *engine)
@@ -1411,12 +1417,14 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine)
 	unsigned int i;
 	int ret;
 
-	if (WARN_ON(engine->id != RCS || !engine->scratch))
+	if (GEM_WARN_ON(engine->id != RCS))
 		return -EINVAL;
 
 	switch (INTEL_GEN(engine->i915)) {
 	case 10:
-		return 0;
+		wa_bb_fn[0] = gen10_init_indirectctx_bb;
+		wa_bb_fn[1] = NULL;
+		break;
 	case 9:
 		wa_bb_fn[0] = gen9_init_indirectctx_bb;
 		wa_bb_fn[1] = NULL;
@@ -1446,7 +1454,8 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine)
 	 */
 	for (i = 0; i < ARRAY_SIZE(wa_bb_fn); i++) {
 		wa_bb[i]->offset = batch_ptr - batch;
-		if (WARN_ON(!IS_ALIGNED(wa_bb[i]->offset, CACHELINE_BYTES))) {
+		if (GEM_WARN_ON(!IS_ALIGNED(wa_bb[i]->offset,
+					    CACHELINE_BYTES))) {
 			ret = -EINVAL;
 			break;
 		}
@@ -1472,47 +1481,48 @@ static u8 gtiir[] = {
 	[VECS] = 3,
 };
 
-static int gen8_init_common_ring(struct intel_engine_cs *engine)
+static void enable_execlists(struct intel_engine_cs *engine)
 {
 	struct drm_i915_private *dev_priv = engine->i915;
-	struct intel_engine_execlists * const execlists = &engine->execlists;
-	int ret;
 
-	ret = intel_mocs_init_engine(engine);
-	if (ret)
-		return ret;
+	I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
 
-	intel_engine_reset_breadcrumbs(engine);
-	intel_engine_init_hangcheck(engine);
+	/*
+	 * Make sure we're not enabling the new 12-deep CSB
+	 * FIFO as that requires a slightly updated handling
+	 * in the ctx switch irq. Since we're currently only
+	 * using only 2 elements of the enhanced execlists the
+	 * deeper FIFO it's not needed and it's not worth adding
+	 * more statements to the irq handler to support it.
+	 */
+	if (INTEL_GEN(dev_priv) >= 11)
+		I915_WRITE(RING_MODE_GEN7(engine),
+			   _MASKED_BIT_DISABLE(GEN11_GFX_DISABLE_LEGACY_MODE));
+	else
+		I915_WRITE(RING_MODE_GEN7(engine),
+			   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
 
-	I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
-	I915_WRITE(RING_MODE_GEN7(engine),
-		   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
 	I915_WRITE(RING_HWS_PGA(engine->mmio_base),
 		   engine->status_page.ggtt_offset);
 	POSTING_READ(RING_HWS_PGA(engine->mmio_base));
 
-	DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name);
+	/* Following the reset, we need to reload the CSB read/write pointers */
+	engine->execlists.csb_head = -1;
+}
 
-	GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir));
+static int gen8_init_common_ring(struct intel_engine_cs *engine)
+{
+	struct intel_engine_execlists * const execlists = &engine->execlists;
+	int ret;
 
-	/*
-	 * Clear any pending interrupt state.
-	 *
-	 * We do it twice out of paranoia that some of the IIR are double
-	 * buffered, and if we only reset it once there may still be
-	 * an interrupt pending.
-	 */
-	I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]),
-		   GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift);
-	I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]),
-		   GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift);
-	clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
-	execlists->csb_head = -1;
-	execlists->active = 0;
+	ret = intel_mocs_init_engine(engine);
+	if (ret)
+		return ret;
 
-	execlists->elsp =
-		dev_priv->regs + i915_mmio_reg_offset(RING_ELSP(engine));
+	intel_engine_reset_breadcrumbs(engine);
+	intel_engine_init_hangcheck(engine);
+
+	enable_execlists(engine);
 
 	/* After a GPU reset, we may have requests to replay */
 	if (execlists->first)
@@ -1554,6 +1564,31 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine)
 	return init_workarounds_ring(engine);
 }
 
+static void reset_irq(struct intel_engine_cs *engine)
+{
+	struct drm_i915_private *dev_priv = engine->i915;
+	int i;
+
+	GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir));
+
+	/*
+	 * Clear any pending interrupt state.
+	 *
+	 * We do it twice out of paranoia that some of the IIR are double
+	 * buffered, and if we only reset it once there may still be
+	 * an interrupt pending.
+	 */
+	for (i = 0; i < 2; i++) {
+		I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]),
+			   GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift);
+		POSTING_READ(GEN8_GT_IIR(gtiir[engine->id]));
+	}
+	GEM_BUG_ON(I915_READ(GEN8_GT_IIR(gtiir[engine->id])) &
+		   (GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift));
+
+	clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
+}
+
 static void reset_common_ring(struct intel_engine_cs *engine,
 			      struct drm_i915_gem_request *request)
 {
@@ -1563,6 +1598,9 @@ static void reset_common_ring(struct intel_engine_cs *engine,
 
 	GEM_TRACE("%s seqno=%x\n",
 		  engine->name, request ? request->global_seqno : 0);
+
+	reset_irq(engine);
+
 	spin_lock_irqsave(&engine->timeline->lock, flags);
 
 	/*
@@ -1581,6 +1619,9 @@ static void reset_common_ring(struct intel_engine_cs *engine,
 
 	spin_unlock_irqrestore(&engine->timeline->lock, flags);
 
+	/* Mark all CS interrupts as complete */
+	execlists->active = 0;
+
 	/* If the request was innocent, we leave the request in the ELSP
 	 * and will try to replay it on restarting. The context image may
 	 * have been corrupted by the reset, in which case we may have
@@ -1912,6 +1953,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
 	intel_engine_cleanup_common(engine);
 
 	lrc_destroy_wa_ctx(engine);
+
 	engine->i915 = NULL;
 	dev_priv->engine[engine->id] = NULL;
 	kfree(engine);
@@ -1928,6 +1970,12 @@ static void execlists_set_default_submission(struct intel_engine_cs *engine)
 	engine->unpark = NULL;
 
 	engine->flags |= I915_ENGINE_SUPPORTS_STATS;
+
+	engine->i915->caps.scheduler =
+		I915_SCHEDULER_CAP_ENABLED |
+		I915_SCHEDULER_CAP_PRIORITY;
+	if (engine->i915->preempt_context)
+		engine->i915->caps.scheduler |= I915_SCHEDULER_CAP_PREEMPTION;
 }
 
 static void
@@ -2001,6 +2049,14 @@ static int logical_ring_init(struct intel_engine_cs *engine)
 	if (ret)
 		goto error;
 
+	engine->execlists.elsp =
+		engine->i915->regs + i915_mmio_reg_offset(RING_ELSP(engine));
+
+	engine->execlists.preempt_complete_status = ~0u;
+	if (engine->i915->preempt_context)
+		engine->execlists.preempt_complete_status =
+			upper_32_bits(engine->i915->preempt_context->engine[engine->id].lrc_desc);
+
 	return 0;
 
 error:
@@ -2142,6 +2198,8 @@ static void execlists_init_reg_state(u32 *regs,
 				 MI_LRI_FORCE_POSTED;
 
 	CTX_REG(regs, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(engine),
+		_MASKED_BIT_DISABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
+				    CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT) |
 		_MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
 				   (HAS_RESOURCE_STREAMER(dev_priv) ?
 				   CTX_CTRL_RS_CTX_ENABLE : 0)));
@@ -2261,6 +2319,10 @@ populate_lr_context(struct i915_gem_context *ctx,
 	if (!engine->default_state)
 		regs[CTX_CONTEXT_CONTROL + 1] |=
 			_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
+	if (ctx == ctx->i915->preempt_context)
+		regs[CTX_CONTEXT_CONTROL + 1] |=
+			_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
+					   CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT);
 
 	i915_gem_object_unpin_map(ctx_obj);
 
@@ -2277,7 +2339,8 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 	struct intel_ring *ring;
 	int ret;
 
-	WARN_ON(ce->state);
+	if (ce->state)
+		return 0;
 
 	context_size = round_up(engine->context_size, I915_GTT_PAGE_SIZE);
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 6d4f9b995a11..636ced41225d 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -37,6 +37,7 @@
 #define	  CTX_CTRL_INHIBIT_SYN_CTX_SWITCH	(1 << 3)
 #define	  CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT	(1 << 0)
 #define   CTX_CTRL_RS_CTX_ENABLE                (1 << 1)
+#define	  CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT	(1 << 2)
 #define RING_CONTEXT_STATUS_BUF_BASE(engine)	_MMIO((engine)->mmio_base + 0x370)
 #define RING_CONTEXT_STATUS_BUF_LO(engine, i)	_MMIO((engine)->mmio_base + 0x370 + (i) * 8)
 #define RING_CONTEXT_STATUS_BUF_HI(engine, i)	_MMIO((engine)->mmio_base + 0x370 + (i) * 8 + 4)
diff --git a/drivers/gpu/drm/i915/intel_lrc_reg.h b/drivers/gpu/drm/i915/intel_lrc_reg.h
new file mode 100644
index 000000000000..a53336e2fc97
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_lrc_reg.h
@@ -0,0 +1,67 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2014-2018 Intel Corporation
+ */
+
+#ifndef _INTEL_LRC_REG_H_
+#define _INTEL_LRC_REG_H_
+
+#include <linux/types.h>
+
+/* GEN8+ Reg State Context */
+#define CTX_LRI_HEADER_0		0x01
+#define CTX_CONTEXT_CONTROL		0x02
+#define CTX_RING_HEAD			0x04
+#define CTX_RING_TAIL			0x06
+#define CTX_RING_BUFFER_START		0x08
+#define CTX_RING_BUFFER_CONTROL		0x0a
+#define CTX_BB_HEAD_U			0x0c
+#define CTX_BB_HEAD_L			0x0e
+#define CTX_BB_STATE			0x10
+#define CTX_SECOND_BB_HEAD_U		0x12
+#define CTX_SECOND_BB_HEAD_L		0x14
+#define CTX_SECOND_BB_STATE		0x16
+#define CTX_BB_PER_CTX_PTR		0x18
+#define CTX_RCS_INDIRECT_CTX		0x1a
+#define CTX_RCS_INDIRECT_CTX_OFFSET	0x1c
+#define CTX_LRI_HEADER_1		0x21
+#define CTX_CTX_TIMESTAMP		0x22
+#define CTX_PDP3_UDW			0x24
+#define CTX_PDP3_LDW			0x26
+#define CTX_PDP2_UDW			0x28
+#define CTX_PDP2_LDW			0x2a
+#define CTX_PDP1_UDW			0x2c
+#define CTX_PDP1_LDW			0x2e
+#define CTX_PDP0_UDW			0x30
+#define CTX_PDP0_LDW			0x32
+#define CTX_LRI_HEADER_2		0x41
+#define CTX_R_PWR_CLK_STATE		0x42
+#define CTX_GPGPU_CSR_BASE_ADDRESS	0x44
+
+#define CTX_REG(reg_state, pos, reg, val) do { \
+	u32 *reg_state__ = (reg_state); \
+	const u32 pos__ = (pos); \
+	(reg_state__)[(pos__) + 0] = i915_mmio_reg_offset(reg); \
+	(reg_state__)[(pos__) + 1] = (val); \
+} while (0)
+
+#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \
+	u32 *reg_state__ = (reg_state); \
+	const u64 addr__ = i915_page_dir_dma_addr((ppgtt), (n)); \
+	(reg_state__)[CTX_PDP ## n ## _UDW + 1] = upper_32_bits(addr__); \
+	(reg_state__)[CTX_PDP ## n ## _LDW + 1] = lower_32_bits(addr__); \
+} while (0)
+
+#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \
+	u32 *reg_state__ = (reg_state); \
+	const u64 addr__ = px_dma(&ppgtt->pml4); \
+	(reg_state__)[CTX_PDP0_UDW + 1] = upper_32_bits(addr__); \
+	(reg_state__)[CTX_PDP0_LDW + 1] = lower_32_bits(addr__); \
+} while (0)
+
+#define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT	0x17
+#define GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT	0x26
+#define GEN10_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT	0x19
+
+#endif /* _INTEL_LRC_REG_H_ */
diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c
index dcbc786479f9..8ae8f42f430a 100644
--- a/drivers/gpu/drm/i915/intel_lspcon.c
+++ b/drivers/gpu/drm/i915/intel_lspcon.c
@@ -167,11 +167,10 @@ static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
 {
 	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
 	unsigned long start = jiffies;
 
 	while (1) {
-		if (intel_digital_port_connected(dev_priv, dig_port)) {
+		if (intel_digital_port_connected(&dig_port->base)) {
 			DRM_DEBUG_KMS("LSPCON recovering in PCON mode after %u ms\n",
 				      jiffies_to_msecs(jiffies - start));
 			return;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index ef80499113ee..d35d2d50f595 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -189,7 +189,7 @@ static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv,
 	/* Convert from 100ms to 100us units */
 	pps->t4 = val * 1000;
 
-	if (INTEL_INFO(dev_priv)->gen <= 4 &&
+	if (INTEL_GEN(dev_priv) <= 4 &&
 	    pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) {
 		DRM_DEBUG_KMS("Panel power timings uninitialized, "
 			      "setting defaults\n");
@@ -268,7 +268,9 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder,
 	/* set the corresponsding LVDS_BORDER bit */
 	temp &= ~LVDS_BORDER_ENABLE;
 	temp |= pipe_config->gmch_pfit.lvds_border_bits;
-	/* Set the B0-B3 data pairs corresponding to whether we're going to
+
+	/*
+	 * Set the B0-B3 data pairs corresponding to whether we're going to
 	 * set the DPLLs for dual-channel mode or not.
 	 */
 	if (lvds_encoder->is_dual_link)
@@ -276,7 +278,8 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder,
 	else
 		temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
-	/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+	/*
+	 * It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
 	 * appropriately here, but we need to look more thoroughly into how
 	 * panels behave in the two modes. For now, let's just maintain the
 	 * value we got from the BIOS.
@@ -284,12 +287,16 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder,
 	temp &= ~LVDS_A3_POWER_MASK;
 	temp |= lvds_encoder->a3_power;
 
-	/* Set the dithering flag on LVDS as needed, note that there is no
+	/*
+	 * Set the dithering flag on LVDS as needed, note that there is no
 	 * special lvds dither control bit on pch-split platforms, dithering is
-	 * only controlled through the PIPECONF reg. */
+	 * only controlled through the PIPECONF reg.
+	 */
 	if (IS_GEN4(dev_priv)) {
-		/* Bspec wording suggests that LVDS port dithering only exists
-		 * for 18bpp panels. */
+		/*
+		 * Bspec wording suggests that LVDS port dithering only exists
+		 * for 18bpp panels.
+		 */
 		if (pipe_config->dither && pipe_config->pipe_bpp == 18)
 			temp |= LVDS_ENABLE_DITHER;
 		else
@@ -304,7 +311,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder,
 	I915_WRITE(lvds_encoder->reg, temp);
 }
 
-/**
+/*
  * Sets the power state for the panel.
  */
 static void intel_enable_lvds(struct intel_encoder *encoder,
@@ -441,7 +448,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
 	return true;
 }
 
-/**
+/*
  * Detect the LVDS connection.
  *
  * Since LVDS doesn't have hotlug, we use the lid as a proxy.  Open means
@@ -464,7 +471,7 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
 	return connector_status_connected;
 }
 
-/**
+/*
  * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
  */
 static int intel_lvds_get_modes(struct drm_connector *connector)
@@ -893,7 +900,8 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
 	if (dmi_check_system(intel_dual_link_lvds))
 		return true;
 
-	/* BIOS should set the proper LVDS register value at boot, but
+	/*
+	 * BIOS should set the proper LVDS register value at boot, but
 	 * in reality, it doesn't set the value when the lid is closed;
 	 * we need to check "the value to be set" in VBT when LVDS
 	 * register is uninitialized.
@@ -907,13 +915,17 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
 
 static bool intel_lvds_supported(struct drm_i915_private *dev_priv)
 {
-	/* With the introduction of the PCH we gained a dedicated
-	 * LVDS presence pin, use it. */
+	/*
+	 * With the introduction of the PCH we gained a dedicated
+	 * LVDS presence pin, use it.
+	 */
 	if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
 		return true;
 
-	/* Otherwise LVDS was only attached to mobile products,
-	 * except for the inglorious 830gm */
+	/*
+	 * Otherwise LVDS was only attached to mobile products,
+	 * except for the inglorious 830gm
+	 */
 	if (INTEL_GEN(dev_priv) <= 4 &&
 	    IS_MOBILE(dev_priv) && !IS_I830(dev_priv))
 		return true;
@@ -923,7 +935,7 @@ static bool intel_lvds_supported(struct drm_i915_private *dev_priv)
 
 /**
  * intel_lvds_init - setup LVDS connectors on this device
- * @dev: drm device
+ * @dev_priv: i915 device
  *
  * Create the connector, register the LVDS DDC bus, and try to figure out what
  * modes we can display on the LVDS panel (if present).
diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
index f4c46b0b8f0a..abb7a8c1e340 100644
--- a/drivers/gpu/drm/i915/intel_mocs.c
+++ b/drivers/gpu/drm/i915/intel_mocs.c
@@ -187,7 +187,7 @@ static bool get_mocs_settings(struct drm_i915_private *dev_priv,
 		table->table = broxton_mocs_table;
 		result = true;
 	} else {
-		WARN_ONCE(INTEL_INFO(dev_priv)->gen >= 9,
+		WARN_ONCE(INTEL_GEN(dev_priv) >= 9,
 			  "Platform that should have a MOCS table does not.\n");
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 4e43f873c889..b39846613e3c 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -30,21 +30,6 @@
 #include "intel_drv.h"
 #include "i915_drv.h"
 
-static void intel_connector_update_eld_conn_type(struct drm_connector *connector)
-{
-	u8 conn_type;
-
-	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
-	    connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
-		conn_type = DRM_ELD_CONN_TYPE_DP;
-	} else {
-		conn_type = DRM_ELD_CONN_TYPE_HDMI;
-	}
-
-	connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] &= ~DRM_ELD_CONN_TYPE_MASK;
-	connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= conn_type;
-}
-
 /**
  * intel_connector_update_modes - update connector from edid
  * @connector: DRM connector device to use
@@ -58,8 +43,6 @@ int intel_connector_update_modes(struct drm_connector *connector,
 	drm_mode_connector_update_edid_property(connector, edid);
 	ret = drm_add_edid_modes(connector, edid);
 
-	intel_connector_update_eld_conn_type(connector);
-
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index fa6831f8c004..41d00b1603e3 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -397,8 +397,11 @@ intel_panel_detect(struct drm_i915_private *dev_priv)
 
 /**
  * scale - scale values from one range to another
- *
  * @source_val: value in range [@source_min..@source_max]
+ * @source_min: minimum legal value for @source_val
+ * @source_max: maximum legal value for @source_val
+ * @target_min: corresponding target value for @source_min
+ * @target_max: corresponding target value for @source_max
  *
  * Return @source_val in range [@source_min..@source_max] scaled to range
  * [@target_min..@target_max].
@@ -416,8 +419,9 @@ static uint32_t scale(uint32_t source_val,
 	source_val = clamp(source_val, source_min, source_max);
 
 	/* avoid overflows */
-	target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) *
-			(target_max - target_min), source_max - source_min);
+	target_val = mul_u32_u32(source_val - source_min,
+				 target_max - target_min);
+	target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min);
 	target_val += target_min;
 
 	return target_val;
@@ -497,7 +501,7 @@ static u32 i9xx_get_backlight(struct intel_connector *connector)
 	u32 val;
 
 	val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-	if (INTEL_INFO(dev_priv)->gen < 4)
+	if (INTEL_GEN(dev_priv) < 4)
 		val >>= 1;
 
 	if (panel->backlight.combination_mode) {
@@ -1719,9 +1723,9 @@ cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
 	u32 pwm_ctl, val;
 
 	/*
-	 * CNP has the BXT implementation of backlight, but with only
-	 * one controller. Future platforms could have multiple controllers
-	 * so let's make this extensible and prepared for the future.
+	 * CNP has the BXT implementation of backlight, but with only one
+	 * controller. TODO: ICP has multiple controllers but we only use
+	 * controller 0 for now.
 	 */
 	panel->backlight.controller = 0;
 
@@ -1865,7 +1869,7 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
 		panel->backlight.set = bxt_set_backlight;
 		panel->backlight.get = bxt_get_backlight;
 		panel->backlight.hz_to_pwm = bxt_hz_to_pwm;
-	} else if (HAS_PCH_CNP(dev_priv)) {
+	} else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_ICP(dev_priv)) {
 		panel->backlight.setup = cnp_setup_backlight;
 		panel->backlight.enable = cnp_enable_backlight;
 		panel->backlight.disable = cnp_disable_backlight;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1a6e699e19e0..a88f0f213604 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -729,6 +729,7 @@ static unsigned int intel_wm_method2(unsigned int pixel_rate,
  * intel_calculate_wm - calculate watermark level
  * @pixel_rate: pixel clock
  * @wm: chip FIFO params
+ * @fifo_size: size of the FIFO buffer
  * @cpp: bytes per pixel
  * @latency_ns: memory latency for the platform
  *
@@ -3694,11 +3695,18 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state)
 	struct intel_crtc_state *cstate;
 	enum pipe pipe;
 	int level, latency;
-	int sagv_block_time_us = IS_GEN9(dev_priv) ? 30 : 20;
+	int sagv_block_time_us;
 
 	if (!intel_has_sagv(dev_priv))
 		return false;
 
+	if (IS_GEN9(dev_priv))
+		sagv_block_time_us = 30;
+	else if (IS_GEN10(dev_priv))
+		sagv_block_time_us = 20;
+	else
+		sagv_block_time_us = 10;
+
 	/*
 	 * SKL+ workaround: bspec recommends we disable the SAGV when we have
 	 * more then one pipe enabled
@@ -3778,7 +3786,8 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
 	ddb_size = INTEL_INFO(dev_priv)->ddb_size;
 	WARN_ON(ddb_size == 0);
 
-	ddb_size -= 4; /* 4 blocks for bypass path allocation */
+	if (INTEL_GEN(dev_priv) < 11)
+		ddb_size -= 4; /* 4 blocks for bypass path allocation */
 
 	/*
 	 * If the state doesn't change the active CRTC's, then there's
@@ -4311,7 +4320,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 */
 static uint_fixed_16_16_t
 skl_wm_method1(const struct drm_i915_private *dev_priv, uint32_t pixel_rate,
-	       uint8_t cpp, uint32_t latency)
+	       uint8_t cpp, uint32_t latency, uint32_t dbuf_block_size)
 {
 	uint32_t wm_intermediate_val;
 	uint_fixed_16_16_t ret;
@@ -4320,7 +4329,7 @@ skl_wm_method1(const struct drm_i915_private *dev_priv, uint32_t pixel_rate,
 		return FP_16_16_MAX;
 
 	wm_intermediate_val = latency * pixel_rate * cpp;
-	ret = div_fixed16(wm_intermediate_val, 1000 * 512);
+	ret = div_fixed16(wm_intermediate_val, 1000 * dbuf_block_size);
 
 	if (INTEL_GEN(dev_priv) >= 10)
 		ret = add_fixed16_u32(ret, 1);
@@ -4430,6 +4439,12 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
 	wp->plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate,
 							     intel_pstate);
 
+	if (INTEL_GEN(dev_priv) >= 11 &&
+	    fb->modifier == I915_FORMAT_MOD_Yf_TILED && wp->cpp == 8)
+		wp->dbuf_block_size = 256;
+	else
+		wp->dbuf_block_size = 512;
+
 	if (drm_rotation_90_or_270(pstate->rotation)) {
 
 		switch (wp->cpp) {
@@ -4456,7 +4471,8 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
 	wp->plane_bytes_per_line = wp->width * wp->cpp;
 	if (wp->y_tiled) {
 		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line *
-					   wp->y_min_scanlines, 512);
+					   wp->y_min_scanlines,
+					   wp->dbuf_block_size);
 
 		if (INTEL_GEN(dev_priv) >= 10)
 			interm_pbpl++;
@@ -4464,10 +4480,12 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
 		wp->plane_blocks_per_line = div_fixed16(interm_pbpl,
 							wp->y_min_scanlines);
 	} else if (wp->x_tiled && IS_GEN9(dev_priv)) {
-		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, 512);
+		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line,
+					   wp->dbuf_block_size);
 		wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
 	} else {
-		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, 512) + 1;
+		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line,
+					   wp->dbuf_block_size) + 1;
 		wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
 	}
 
@@ -4497,6 +4515,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 	struct intel_atomic_state *state =
 		to_intel_atomic_state(cstate->base.state);
 	bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state);
+	uint32_t min_disp_buf_needed;
 
 	if (latency == 0 ||
 	    !intel_wm_plane_visible(cstate, intel_pstate)) {
@@ -4514,7 +4533,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 		latency += 15;
 
 	method1 = skl_wm_method1(dev_priv, wp->plane_pixel_rate,
-				 wp->cpp, latency);
+				 wp->cpp, latency, wp->dbuf_block_size);
 	method2 = skl_wm_method2(wp->plane_pixel_rate,
 				 cstate->base.adjusted_mode.crtc_htotal,
 				 latency,
@@ -4524,7 +4543,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 		selected_result = max_fixed16(method2, wp->y_tile_minimum);
 	} else {
 		if ((wp->cpp * cstate->base.adjusted_mode.crtc_htotal /
-		     512 < 1) && (wp->plane_bytes_per_line / 512 < 1))
+		     wp->dbuf_block_size < 1) &&
+		     (wp->plane_bytes_per_line / wp->dbuf_block_size < 1))
 			selected_result = method2;
 		else if (ddb_allocation >=
 			 fixed16_to_u32_round_up(wp->plane_blocks_per_line))
@@ -4554,7 +4574,32 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 		}
 	}
 
-	if (res_blocks >= ddb_allocation || res_lines > 31) {
+	if (INTEL_GEN(dev_priv) >= 11) {
+		if (wp->y_tiled) {
+			uint32_t extra_lines;
+			uint_fixed_16_16_t fp_min_disp_buf_needed;
+
+			if (res_lines % wp->y_min_scanlines == 0)
+				extra_lines = wp->y_min_scanlines;
+			else
+				extra_lines = wp->y_min_scanlines * 2 -
+					      res_lines % wp->y_min_scanlines;
+
+			fp_min_disp_buf_needed = mul_u32_fixed16(res_lines +
+						extra_lines,
+						wp->plane_blocks_per_line);
+			min_disp_buf_needed = fixed16_to_u32_round_up(
+						fp_min_disp_buf_needed);
+		} else {
+			min_disp_buf_needed = DIV_ROUND_UP(res_blocks * 11, 10);
+		}
+	} else {
+		min_disp_buf_needed = res_blocks;
+	}
+
+	if ((level > 0 && res_lines > 31) ||
+	    res_blocks >= ddb_allocation ||
+	    min_disp_buf_needed >= ddb_allocation) {
 		*enabled = false;
 
 		/*
@@ -4574,8 +4619,9 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 		}
 	}
 
+	/* The number of lines are ignored for the level 0 watermark. */
+	*out_lines = level ? res_lines : 0;
 	*out_blocks = res_blocks;
-	*out_lines = res_lines;
 	*enabled = true;
 
 	return 0;
@@ -4667,6 +4713,7 @@ static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
 	if (!dev_priv->ipc_enabled)
 		goto exit;
 
+	trans_min = 0;
 	if (INTEL_GEN(dev_priv) >= 10)
 		trans_min = 4;
 
@@ -4790,8 +4837,10 @@ static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
 
 	skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id),
 			    &ddb->plane[pipe][plane_id]);
-	skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane_id),
-			    &ddb->y_plane[pipe][plane_id]);
+	if (INTEL_GEN(dev_priv) < 11)
+		skl_ddb_entry_write(dev_priv,
+				    PLANE_NV12_BUF_CFG(pipe, plane_id),
+				    &ddb->y_plane[pipe][plane_id]);
 }
 
 static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
@@ -5819,6 +5868,7 @@ void ilk_wm_get_hw_state(struct drm_device *dev)
 
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
+ * @crtc: the #intel_crtc on which to compute the WM
  *
  * Calculate watermark values for the various WM regs based on current mode
  * and plane configuration.
@@ -6327,12 +6377,15 @@ void gen6_rps_boost(struct drm_i915_gem_request *rq,
 	if (!rps->enabled)
 		return;
 
+	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
+		return;
+
+	/* Serializes with i915_gem_request_retire() */
 	boost = false;
 	spin_lock_irqsave(&rq->lock, flags);
-	if (!rq->waitboost && !i915_gem_request_completed(rq)) {
-		atomic_inc(&rps->num_waiters);
+	if (!rq->waitboost && !dma_fence_is_signaled_locked(&rq->fence)) {
+		boost = !atomic_fetch_inc(&rps->num_waiters);
 		rq->waitboost = true;
-		boost = true;
 	}
 	spin_unlock_irqrestore(&rq->lock, flags);
 	if (!boost)
@@ -6626,9 +6679,29 @@ static void gen9_enable_rc6(struct drm_i915_private *dev_priv)
 
 	I915_WRITE(GEN6_RC_SLEEP, 0);
 
-	/* 2c: Program Coarse Power Gating Policies. */
-	I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 25);
-	I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25);
+	/*
+	 * 2c: Program Coarse Power Gating Policies.
+	 *
+	 * Bspec's guidance is to use 25us (really 25 * 1280ns) here. What we
+	 * use instead is a more conservative estimate for the maximum time
+	 * it takes us to service a CS interrupt and submit a new ELSP - that
+	 * is the time which the GPU is idle waiting for the CPU to select the
+	 * next request to execute. If the idle hysteresis is less than that
+	 * interrupt service latency, the hardware will automatically gate
+	 * the power well and we will then incur the wake up cost on top of
+	 * the service latency. A similar guide from intel_pstate is that we
+	 * do not want the enable hysteresis to less than the wakeup latency.
+	 *
+	 * igt/gem_exec_nop/sequential provides a rough estimate for the
+	 * service latency, and puts it around 10us for Broadwell (and other
+	 * big core) and around 40us for Broxton (and other low power cores).
+	 * [Note that for legacy ringbuffer submission, this is less than 1us!]
+	 * However, the wakeup latency on Broxton is closer to 100us. To be
+	 * conservative, we have to factor in a context switch on top (due
+	 * to ksoftirqd).
+	 */
+	I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 250);
+	I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 250);
 
 	/* 3a: Enable RC6 */
 	I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
@@ -6873,7 +6946,7 @@ static void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
 			 * No floor required for ring frequency on SKL.
 			 */
 			ring_freq = gpu_freq;
-		} else if (INTEL_INFO(dev_priv)->gen >= 8) {
+		} else if (INTEL_GEN(dev_priv) >= 8) {
 			/* max(2 * GT, DDR). NB: GT is 50MHz units */
 			ring_freq = max(min_ring_freq, gpu_freq);
 		} else if (IS_HASWELL(dev_priv)) {
@@ -7484,7 +7557,7 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
 {
 	unsigned long val;
 
-	if (INTEL_INFO(dev_priv)->gen != 5)
+	if (!IS_GEN5(dev_priv))
 		return 0;
 
 	spin_lock_irq(&mchdev_lock);
@@ -7568,7 +7641,7 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
 
 void i915_update_gfx_val(struct drm_i915_private *dev_priv)
 {
-	if (INTEL_INFO(dev_priv)->gen != 5)
+	if (!IS_GEN5(dev_priv))
 		return;
 
 	spin_lock_irq(&mchdev_lock);
@@ -7619,7 +7692,7 @@ unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
 {
 	unsigned long val;
 
-	if (INTEL_INFO(dev_priv)->gen != 5)
+	if (!IS_GEN5(dev_priv))
 		return 0;
 
 	spin_lock_irq(&mchdev_lock);
@@ -9150,7 +9223,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val
 }
 
 int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv,
-				    u32 mbox, u32 val, int timeout_us)
+				    u32 mbox, u32 val,
+				    int fast_timeout_us, int slow_timeout_ms)
 {
 	int status;
 
@@ -9173,7 +9247,8 @@ int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv,
 
 	if (__intel_wait_for_register_fw(dev_priv,
 					 GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0,
-					 timeout_us, 0, NULL)) {
+					 fast_timeout_us, slow_timeout_ms,
+					 NULL)) {
 		DRM_ERROR("timeout waiting for pcode write of 0x%08x to mbox %x to finish for %ps\n",
 			  val, mbox, __builtin_return_address(0));
 		return -ETIMEDOUT;
@@ -9348,15 +9423,16 @@ static u64 vlv_residency_raw(struct drm_i915_private *dev_priv,
 			     const i915_reg_t reg)
 {
 	u32 lower, upper, tmp;
-	unsigned long flags;
 	int loop = 2;
 
-	/* The register accessed do not need forcewake. We borrow
+	/*
+	 * The register accessed do not need forcewake. We borrow
 	 * uncore lock to prevent concurrent access to range reg.
 	 */
-	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+	lockdep_assert_held(&dev_priv->uncore.lock);
 
-	/* vlv and chv residency counters are 40 bits in width.
+	/*
+	 * vlv and chv residency counters are 40 bits in width.
 	 * With a control bit, we can choose between upper or lower
 	 * 32bit window into this counter.
 	 *
@@ -9380,29 +9456,49 @@ static u64 vlv_residency_raw(struct drm_i915_private *dev_priv,
 		upper = I915_READ_FW(reg);
 	} while (upper != tmp && --loop);
 
-	/* Everywhere else we always use VLV_COUNTER_CONTROL with the
+	/*
+	 * Everywhere else we always use VLV_COUNTER_CONTROL with the
 	 * VLV_COUNT_RANGE_HIGH bit set - so it is safe to leave it set
 	 * now.
 	 */
 
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
-
 	return lower | (u64)upper << 8;
 }
 
 u64 intel_rc6_residency_ns(struct drm_i915_private *dev_priv,
 			   const i915_reg_t reg)
 {
-	u64 time_hw;
+	u64 time_hw, prev_hw, overflow_hw;
+	unsigned int fw_domains;
+	unsigned long flags;
+	unsigned int i;
 	u32 mul, div;
 
 	if (!HAS_RC6(dev_priv))
 		return 0;
 
+	/*
+	 * Store previous hw counter values for counter wrap-around handling.
+	 *
+	 * There are only four interesting registers and they live next to each
+	 * other so we can use the relative address, compared to the smallest
+	 * one as the index into driver storage.
+	 */
+	i = (i915_mmio_reg_offset(reg) -
+	     i915_mmio_reg_offset(GEN6_GT_GFX_RC6_LOCKED)) / sizeof(u32);
+	if (WARN_ON_ONCE(i >= ARRAY_SIZE(dev_priv->gt_pm.rc6.cur_residency)))
+		return 0;
+
+	fw_domains = intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ);
+
+	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+	intel_uncore_forcewake_get__locked(dev_priv, fw_domains);
+
 	/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 		mul = 1000000;
 		div = dev_priv->czclk_freq;
+		overflow_hw = BIT_ULL(40);
 		time_hw = vlv_residency_raw(dev_priv, reg);
 	} else {
 		/* 833.33ns units on Gen9LP, 1.28us elsewhere. */
@@ -9414,10 +9510,33 @@ u64 intel_rc6_residency_ns(struct drm_i915_private *dev_priv,
 			div = 1;
 		}
 
-		time_hw = I915_READ(reg);
+		overflow_hw = BIT_ULL(32);
+		time_hw = I915_READ_FW(reg);
 	}
 
-	return DIV_ROUND_UP_ULL(time_hw * mul, div);
+	/*
+	 * Counter wrap handling.
+	 *
+	 * But relying on a sufficient frequency of queries otherwise counters
+	 * can still wrap.
+	 */
+	prev_hw = dev_priv->gt_pm.rc6.prev_hw_residency[i];
+	dev_priv->gt_pm.rc6.prev_hw_residency[i] = time_hw;
+
+	/* RC6 delta from last sample. */
+	if (time_hw >= prev_hw)
+		time_hw -= prev_hw;
+	else
+		time_hw += overflow_hw - prev_hw;
+
+	/* Add delta to RC6 extended raw driver copy. */
+	time_hw += dev_priv->gt_pm.rc6.cur_residency[i];
+	dev_priv->gt_pm.rc6.cur_residency[i] = time_hw;
+
+	intel_uncore_forcewake_put__locked(dev_priv, fw_domains);
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+
+	return mul_u64_u32_div(time_hw, mul, div);
 }
 
 u32 intel_get_cagf(struct drm_i915_private *dev_priv, u32 rpstat)
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 2e32615eeada..2ef374f936b9 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -56,14 +56,6 @@
 #include "intel_drv.h"
 #include "i915_drv.h"
 
-static bool is_edp_psr(struct intel_dp *intel_dp)
-{
-	if (!intel_dp_is_edp(intel_dp))
-		return false;
-
-	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
-}
-
 static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
@@ -134,7 +126,7 @@ static void vlv_psr_enable_sink(struct intel_dp *intel_dp)
 static i915_reg_t psr_aux_ctl_reg(struct drm_i915_private *dev_priv,
 				       enum port port)
 {
-	if (INTEL_INFO(dev_priv)->gen >= 9)
+	if (INTEL_GEN(dev_priv) >= 9)
 		return DP_AUX_CH_CTL(port);
 	else
 		return EDP_PSR_AUX_CTL;
@@ -143,7 +135,7 @@ static i915_reg_t psr_aux_ctl_reg(struct drm_i915_private *dev_priv,
 static i915_reg_t psr_aux_data_reg(struct drm_i915_private *dev_priv,
 					enum port port, int index)
 {
-	if (INTEL_INFO(dev_priv)->gen >= 9)
+	if (INTEL_GEN(dev_priv) >= 9)
 		return DP_AUX_CH_DATA(port, index);
 	else
 		return EDP_PSR_AUX_DATA(index);
@@ -358,10 +350,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
 		&crtc_state->base.adjusted_mode;
 	int psr_setup_time;
 
-	if (!HAS_PSR(dev_priv))
-		return;
-
-	if (!is_edp_psr(intel_dp))
+	if (!CAN_PSR(dev_priv))
 		return;
 
 	if (!i915_modparams.enable_psr) {
@@ -476,7 +465,7 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp,
 			chicken |= PSR2_ADD_VERTICAL_LINE_COUNT;
 		I915_WRITE(CHICKEN_TRANS(cpu_transcoder), chicken);
 
-		I915_WRITE(EDP_PSR_DEBUG_CTL,
+		I915_WRITE(EDP_PSR_DEBUG,
 			   EDP_PSR_DEBUG_MASK_MEMUP |
 			   EDP_PSR_DEBUG_MASK_HPD |
 			   EDP_PSR_DEBUG_MASK_LPSP |
@@ -490,7 +479,7 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp,
 		 * preventing  other hw tracking issues now we can rely
 		 * on frontbuffer tracking.
 		 */
-		I915_WRITE(EDP_PSR_DEBUG_CTL,
+		I915_WRITE(EDP_PSR_DEBUG,
 			   EDP_PSR_DEBUG_MASK_MEMUP |
 			   EDP_PSR_DEBUG_MASK_HPD |
 			   EDP_PSR_DEBUG_MASK_LPSP);
@@ -514,6 +503,9 @@ void intel_psr_enable(struct intel_dp *intel_dp,
 	if (!crtc_state->has_psr)
 		return;
 
+	if (WARN_ON(!CAN_PSR(dev_priv)))
+		return;
+
 	WARN_ON(dev_priv->drrs.dp);
 	mutex_lock(&dev_priv->psr.lock);
 	if (dev_priv->psr.enabled) {
@@ -522,8 +514,6 @@ void intel_psr_enable(struct intel_dp *intel_dp,
 	}
 
 	dev_priv->psr.psr2_support = crtc_state->has_psr2;
-	dev_priv->psr.source_ok = true;
-
 	dev_priv->psr.busy_frontbuffer_bits = 0;
 
 	dev_priv->psr.setup_vsc(intel_dp, crtc_state);
@@ -599,7 +589,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp,
 					0);
 
 		if (dev_priv->psr.psr2_support) {
-			psr_status = EDP_PSR2_STATUS_CTL;
+			psr_status = EDP_PSR2_STATUS;
 			psr_status_mask = EDP_PSR2_STATUS_STATE_MASK;
 
 			I915_WRITE(EDP_PSR2_CTL,
@@ -607,7 +597,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp,
 				   ~(EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE));
 
 		} else {
-			psr_status = EDP_PSR_STATUS_CTL;
+			psr_status = EDP_PSR_STATUS;
 			psr_status_mask = EDP_PSR_STATUS_STATE_MASK;
 
 			I915_WRITE(EDP_PSR_CTL,
@@ -646,6 +636,9 @@ void intel_psr_disable(struct intel_dp *intel_dp,
 	if (!old_crtc_state->has_psr)
 		return;
 
+	if (WARN_ON(!CAN_PSR(dev_priv)))
+		return;
+
 	mutex_lock(&dev_priv->psr.lock);
 	if (!dev_priv->psr.enabled) {
 		mutex_unlock(&dev_priv->psr.lock);
@@ -679,19 +672,19 @@ static void intel_psr_work(struct work_struct *work)
 	if (HAS_DDI(dev_priv)) {
 		if (dev_priv->psr.psr2_support) {
 			if (intel_wait_for_register(dev_priv,
-						EDP_PSR2_STATUS_CTL,
-						EDP_PSR2_STATUS_STATE_MASK,
-						0,
-						50)) {
+						    EDP_PSR2_STATUS,
+						    EDP_PSR2_STATUS_STATE_MASK,
+						    0,
+						    50)) {
 				DRM_ERROR("Timed out waiting for PSR2 Idle for re-enable\n");
 				return;
 			}
 		} else {
 			if (intel_wait_for_register(dev_priv,
-						EDP_PSR_STATUS_CTL,
-						EDP_PSR_STATUS_STATE_MASK,
-						0,
-						50)) {
+						    EDP_PSR_STATUS,
+						    EDP_PSR_STATUS_STATE_MASK,
+						    0,
+						    50)) {
 				DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
 				return;
 			}
@@ -796,7 +789,7 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv,
 	enum pipe pipe;
 	u32 val;
 
-	if (!HAS_PSR(dev_priv))
+	if (!CAN_PSR(dev_priv))
 		return;
 
 	/*
@@ -845,7 +838,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv,
 	struct drm_crtc *crtc;
 	enum pipe pipe;
 
-	if (!HAS_PSR(dev_priv))
+	if (!CAN_PSR(dev_priv))
 		return;
 
 	mutex_lock(&dev_priv->psr.lock);
@@ -885,7 +878,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
 	struct drm_crtc *crtc;
 	enum pipe pipe;
 
-	if (!HAS_PSR(dev_priv))
+	if (!CAN_PSR(dev_priv))
 		return;
 
 	mutex_lock(&dev_priv->psr.lock);
@@ -926,6 +919,9 @@ void intel_psr_init(struct drm_i915_private *dev_priv)
 	dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ?
 		HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE;
 
+	if (!dev_priv->psr.sink_support)
+		return;
+
 	/* Per platform default: all disabled. */
 	if (i915_modparams.enable_psr == -1)
 		i915_modparams.enable_psr = 0;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index e2085820b586..5718f37160c5 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -137,7 +137,7 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 mode)
 	return 0;
 }
 
-/**
+/*
  * Emits a PIPE_CONTROL with a non-zero post-sync operation, for
  * implementing two workarounds on gen6.  From section 1.4.7.1
  * "PIPE_CONTROL" of the Sandy Bridge PRM volume 2 part 1:
@@ -453,13 +453,13 @@ static int init_ring_common(struct intel_engine_cs *engine)
 
 	if (!stop_ring(engine)) {
 		/* G45 ring initialization often fails to reset head to zero */
-		DRM_DEBUG_KMS("%s head not reset to zero "
-			      "ctl %08x head %08x tail %08x start %08x\n",
-			      engine->name,
-			      I915_READ_CTL(engine),
-			      I915_READ_HEAD(engine),
-			      I915_READ_TAIL(engine),
-			      I915_READ_START(engine));
+		DRM_DEBUG_DRIVER("%s head not reset to zero "
+				"ctl %08x head %08x tail %08x start %08x\n",
+				engine->name,
+				I915_READ_CTL(engine),
+				I915_READ_HEAD(engine),
+				I915_READ_TAIL(engine),
+				I915_READ_START(engine));
 
 		if (!stop_ring(engine)) {
 			DRM_ERROR("failed to set %s head to zero "
@@ -492,8 +492,8 @@ static int init_ring_common(struct intel_engine_cs *engine)
 
 	/* WaClearRingBufHeadRegAtInit:ctg,elk */
 	if (I915_READ_HEAD(engine))
-		DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
-			  engine->name, I915_READ_HEAD(engine));
+		DRM_DEBUG_DRIVER("%s initialization failed [head=%08x], fudging\n",
+				 engine->name, I915_READ_HEAD(engine));
 
 	intel_ring_update_space(ring);
 	I915_WRITE_HEAD(engine, ring->head);
@@ -655,7 +655,7 @@ static int init_render_ring(struct intel_engine_cs *engine)
 	if (IS_GEN(dev_priv, 6, 7))
 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
 
-	if (INTEL_INFO(dev_priv)->gen >= 6)
+	if (INTEL_GEN(dev_priv) >= 6)
 		I915_WRITE_IMR(engine, ~engine->irq_keep_mask);
 
 	return init_workarounds_ring(engine);
@@ -729,14 +729,6 @@ static void i9xx_emit_breadcrumb(struct drm_i915_gem_request *req, u32 *cs)
 
 static const int i9xx_emit_breadcrumb_sz = 4;
 
-/**
- * gen6_sema_emit_breadcrumb - Update the semaphore mailbox registers
- *
- * @request - request to write to the ring
- *
- * Update the mailbox registers in the *other* rings with the current seqno.
- * This acts like a signal in the canonical semaphore.
- */
 static void gen6_sema_emit_breadcrumb(struct drm_i915_gem_request *req, u32 *cs)
 {
 	return i9xx_emit_breadcrumb(req,
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index a0e7a6c2a57c..51523ad049de 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -279,6 +279,11 @@ struct intel_engine_execlists {
 	 * @csb_use_mmio: access csb through mmio, instead of hwsp
 	 */
 	bool csb_use_mmio;
+
+	/**
+	 * @preempt_complete_status: expected CSB upon completing preemption
+	 */
+	u32 preempt_complete_status;
 };
 
 #define INTEL_ENGINE_CS_MAX_NAME 8
@@ -654,7 +659,7 @@ intel_engine_flag(const struct intel_engine_cs *engine)
 }
 
 static inline u32
-intel_read_status_page(struct intel_engine_cs *engine, int reg)
+intel_read_status_page(const struct intel_engine_cs *engine, int reg)
 {
 	/* Ensure that the compiler doesn't optimize away the load. */
 	return READ_ONCE(engine->status_page.page_addr[reg]);
@@ -812,8 +817,8 @@ int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine);
 int intel_init_blt_ring_buffer(struct intel_engine_cs *engine);
 int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine);
 
-u64 intel_engine_get_active_head(struct intel_engine_cs *engine);
-u64 intel_engine_get_last_batch_head(struct intel_engine_cs *engine);
+u64 intel_engine_get_active_head(const struct intel_engine_cs *engine);
+u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine);
 
 static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine)
 {
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index d758da6156a8..b7924feb9f27 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -94,6 +94,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
 		return "PORT_DDI_D_LANES";
 	case POWER_DOMAIN_PORT_DDI_E_LANES:
 		return "PORT_DDI_E_LANES";
+	case POWER_DOMAIN_PORT_DDI_F_LANES:
+		return "PORT_DDI_F_LANES";
 	case POWER_DOMAIN_PORT_DDI_A_IO:
 		return "PORT_DDI_A_IO";
 	case POWER_DOMAIN_PORT_DDI_B_IO:
@@ -104,6 +106,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
 		return "PORT_DDI_D_IO";
 	case POWER_DOMAIN_PORT_DDI_E_IO:
 		return "PORT_DDI_E_IO";
+	case POWER_DOMAIN_PORT_DDI_F_IO:
+		return "PORT_DDI_F_IO";
 	case POWER_DOMAIN_PORT_DSI:
 		return "PORT_DSI";
 	case POWER_DOMAIN_PORT_CRT:
@@ -124,6 +128,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
 		return "AUX_C";
 	case POWER_DOMAIN_AUX_D:
 		return "AUX_D";
+	case POWER_DOMAIN_AUX_F:
+		return "AUX_F";
 	case POWER_DOMAIN_GMBUS:
 		return "GMBUS";
 	case POWER_DOMAIN_INIT:
@@ -390,6 +396,15 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
 	I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id));
 	hsw_wait_for_power_well_enable(dev_priv, power_well);
 
+	/* Display WA #1178: cnl */
+	if (IS_CANNONLAKE(dev_priv) &&
+	    (id == CNL_DISP_PW_AUX_B || id == CNL_DISP_PW_AUX_C ||
+	     id == CNL_DISP_PW_AUX_D || id == CNL_DISP_PW_AUX_F)) {
+		val = I915_READ(CNL_AUX_ANAOVRD1(id));
+		val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS;
+		I915_WRITE(CNL_AUX_ANAOVRD1(id), val);
+	}
+
 	if (wait_fuses)
 		gen9_wait_for_power_well_fuses(dev_priv, pg);
 
@@ -1816,9 +1831,11 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
 	BIT_ULL(POWER_DOMAIN_PORT_DDI_B_LANES) |		\
 	BIT_ULL(POWER_DOMAIN_PORT_DDI_C_LANES) |		\
 	BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) |		\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_F_LANES) |		\
 	BIT_ULL(POWER_DOMAIN_AUX_B) |                       \
 	BIT_ULL(POWER_DOMAIN_AUX_C) |			\
 	BIT_ULL(POWER_DOMAIN_AUX_D) |			\
+	BIT_ULL(POWER_DOMAIN_AUX_F) |			\
 	BIT_ULL(POWER_DOMAIN_AUDIO) |			\
 	BIT_ULL(POWER_DOMAIN_VGA) |				\
 	BIT_ULL(POWER_DOMAIN_INIT))
@@ -1846,8 +1863,15 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
 #define CNL_DISPLAY_AUX_D_POWER_DOMAINS (		\
 	BIT_ULL(POWER_DOMAIN_AUX_D) |			\
 	BIT_ULL(POWER_DOMAIN_INIT))
+#define CNL_DISPLAY_AUX_F_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_AUX_F) |			\
+	BIT_ULL(POWER_DOMAIN_INIT))
+#define CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS (		\
+	BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO) |		\
+	BIT_ULL(POWER_DOMAIN_INIT))
 #define CNL_DISPLAY_DC_OFF_POWER_DOMAINS (		\
 	CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\
+	BIT_ULL(POWER_DOMAIN_GT_IRQ) |			\
 	BIT_ULL(POWER_DOMAIN_MODESET) |			\
 	BIT_ULL(POWER_DOMAIN_AUX_A) |			\
 	BIT_ULL(POWER_DOMAIN_INIT))
@@ -2395,6 +2419,18 @@ static struct i915_power_well cnl_power_wells[] = {
 		.ops = &hsw_power_well_ops,
 		.id = SKL_DISP_PW_DDI_D,
 	},
+	{
+		.name = "DDI F IO power well",
+		.domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS,
+		.ops = &hsw_power_well_ops,
+		.id = CNL_DISP_PW_DDI_F,
+	},
+	{
+		.name = "AUX F",
+		.domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS,
+		.ops = &hsw_power_well_ops,
+		.id = CNL_DISP_PW_AUX_F,
+	},
 };
 
 static int
@@ -2510,6 +2546,16 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
 		set_power_wells(power_domains, skl_power_wells);
 	} else if (IS_CANNONLAKE(dev_priv)) {
 		set_power_wells(power_domains, cnl_power_wells);
+
+		/*
+		 * DDI and Aux IO are getting enabled for all ports
+		 * regardless the presence or use. So, in order to avoid
+		 * timeouts, lets remove them from the list
+		 * for the SKUs without port F.
+		 */
+		if (!IS_CNL_WITH_PORT_F(dev_priv))
+			power_domains->power_well_count -= 2;
+
 	} else if (IS_BROXTON(dev_priv)) {
 		set_power_wells(power_domains, bxt_power_wells);
 	} else if (IS_GEMINILAKE(dev_priv)) {
@@ -2600,6 +2646,48 @@ static void gen9_dbuf_disable(struct drm_i915_private *dev_priv)
 		DRM_ERROR("DBuf power disable timeout!\n");
 }
 
+/*
+ * TODO: we shouldn't always enable DBUF_CTL_S2, we should only enable it when
+ * needed and keep it disabled as much as possible.
+ */
+static void icl_dbuf_enable(struct drm_i915_private *dev_priv)
+{
+	I915_WRITE(DBUF_CTL_S1, I915_READ(DBUF_CTL_S1) | DBUF_POWER_REQUEST);
+	I915_WRITE(DBUF_CTL_S2, I915_READ(DBUF_CTL_S2) | DBUF_POWER_REQUEST);
+	POSTING_READ(DBUF_CTL_S2);
+
+	udelay(10);
+
+	if (!(I915_READ(DBUF_CTL_S1) & DBUF_POWER_STATE) ||
+	    !(I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE))
+		DRM_ERROR("DBuf power enable timeout\n");
+}
+
+static void icl_dbuf_disable(struct drm_i915_private *dev_priv)
+{
+	I915_WRITE(DBUF_CTL_S1, I915_READ(DBUF_CTL_S1) & ~DBUF_POWER_REQUEST);
+	I915_WRITE(DBUF_CTL_S2, I915_READ(DBUF_CTL_S2) & ~DBUF_POWER_REQUEST);
+	POSTING_READ(DBUF_CTL_S2);
+
+	udelay(10);
+
+	if ((I915_READ(DBUF_CTL_S1) & DBUF_POWER_STATE) ||
+	    (I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE))
+		DRM_ERROR("DBuf power disable timeout!\n");
+}
+
+static void icl_mbus_init(struct drm_i915_private *dev_priv)
+{
+	uint32_t val;
+
+	val = MBUS_ABOX_BT_CREDIT_POOL1(16) |
+	      MBUS_ABOX_BT_CREDIT_POOL2(16) |
+	      MBUS_ABOX_B_CREDIT(1) |
+	      MBUS_ABOX_BW_CREDIT(1);
+
+	I915_WRITE(MBUS_ABOX_CTL, val);
+}
+
 static void skl_display_core_init(struct drm_i915_private *dev_priv,
 				   bool resume)
 {
@@ -2748,12 +2836,19 @@ static const struct cnl_procmon {
 		{ .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, },
 };
 
-static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv)
+/*
+ * CNL has just one set of registers, while ICL has two sets: one for port A and
+ * the other for port B. The CNL registers are equivalent to the ICL port A
+ * registers, that's why we call the ICL macros even though the function has CNL
+ * on its name.
+ */
+static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv,
+				       enum port port)
 {
 	const struct cnl_procmon *procmon;
 	u32 val;
 
-	val = I915_READ(CNL_PORT_COMP_DW3);
+	val = I915_READ(ICL_PORT_COMP_DW3(port));
 	switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) {
 	default:
 		MISSING_CASE(val);
@@ -2774,13 +2869,13 @@ static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv)
 		break;
 	}
 
-	val = I915_READ(CNL_PORT_COMP_DW1);
+	val = I915_READ(ICL_PORT_COMP_DW1(port));
 	val &= ~((0xff << 16) | 0xff);
 	val |= procmon->dw1;
-	I915_WRITE(CNL_PORT_COMP_DW1, val);
+	I915_WRITE(ICL_PORT_COMP_DW1(port), val);
 
-	I915_WRITE(CNL_PORT_COMP_DW9, procmon->dw9);
-	I915_WRITE(CNL_PORT_COMP_DW10, procmon->dw10);
+	I915_WRITE(ICL_PORT_COMP_DW9(port), procmon->dw9);
+	I915_WRITE(ICL_PORT_COMP_DW10(port), procmon->dw10);
 }
 
 static void cnl_display_core_init(struct drm_i915_private *dev_priv, bool resume)
@@ -2801,7 +2896,8 @@ static void cnl_display_core_init(struct drm_i915_private *dev_priv, bool resume
 	val &= ~CNL_COMP_PWR_DOWN;
 	I915_WRITE(CHICKEN_MISC_2, val);
 
-	cnl_set_procmon_ref_values(dev_priv);
+	/* Dummy PORT_A to get the correct CNL register from the ICL macro */
+	cnl_set_procmon_ref_values(dev_priv, PORT_A);
 
 	val = I915_READ(CNL_PORT_COMP_DW0);
 	val |= COMP_INIT;
@@ -2865,6 +2961,80 @@ static void cnl_display_core_uninit(struct drm_i915_private *dev_priv)
 	I915_WRITE(CHICKEN_MISC_2, val);
 }
 
+static void icl_display_core_init(struct drm_i915_private *dev_priv,
+				  bool resume)
+{
+	enum port port;
+	u32 val;
+
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+	/* 1. Enable PCH reset handshake. */
+	val = I915_READ(HSW_NDE_RSTWRN_OPT);
+	val |= RESET_PCH_HANDSHAKE_ENABLE;
+	I915_WRITE(HSW_NDE_RSTWRN_OPT, val);
+
+	for (port = PORT_A; port <= PORT_B; port++) {
+		/* 2. Enable DDI combo PHY comp. */
+		val = I915_READ(ICL_PHY_MISC(port));
+		val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
+		I915_WRITE(ICL_PHY_MISC(port), val);
+
+		cnl_set_procmon_ref_values(dev_priv, port);
+
+		val = I915_READ(ICL_PORT_COMP_DW0(port));
+		val |= COMP_INIT;
+		I915_WRITE(ICL_PORT_COMP_DW0(port), val);
+
+		/* 3. Set power down enable. */
+		val = I915_READ(ICL_PORT_CL_DW5(port));
+		val |= CL_POWER_DOWN_ENABLE;
+		I915_WRITE(ICL_PORT_CL_DW5(port), val);
+	}
+
+	/* 4. Enable power well 1 (PG1) and aux IO power. */
+	/* FIXME: ICL power wells code not here yet. */
+
+	/* 5. Enable CDCLK. */
+	icl_init_cdclk(dev_priv);
+
+	/* 6. Enable DBUF. */
+	icl_dbuf_enable(dev_priv);
+
+	/* 7. Setup MBUS. */
+	icl_mbus_init(dev_priv);
+
+	/* 8. CHICKEN_DCPR_1 */
+	I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) |
+					CNL_DDI_CLOCK_REG_ACCESS_ON);
+}
+
+static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
+{
+	enum port port;
+	u32 val;
+
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+	/* 1. Disable all display engine functions -> aready done */
+
+	/* 2. Disable DBUF */
+	icl_dbuf_disable(dev_priv);
+
+	/* 3. Disable CD clock */
+	icl_uninit_cdclk(dev_priv);
+
+	/* 4. Disable Power Well 1 (PG1) and Aux IO Power */
+	/* FIXME: ICL power wells code not here yet. */
+
+	/* 5. Disable Comp */
+	for (port = PORT_A; port <= PORT_B; port++) {
+		val = I915_READ(ICL_PHY_MISC(port));
+		val |= ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
+		I915_WRITE(ICL_PHY_MISC(port), val);
+	}
+}
+
 static void chv_phy_control_init(struct drm_i915_private *dev_priv)
 {
 	struct i915_power_well *cmn_bc =
@@ -2997,7 +3167,9 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
 
 	power_domains->initializing = true;
 
-	if (IS_CANNONLAKE(dev_priv)) {
+	if (IS_ICELAKE(dev_priv)) {
+		icl_display_core_init(dev_priv, resume);
+	} else if (IS_CANNONLAKE(dev_priv)) {
 		cnl_display_core_init(dev_priv, resume);
 	} else if (IS_GEN9_BC(dev_priv)) {
 		skl_display_core_init(dev_priv, resume);
@@ -3038,7 +3210,9 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
 	if (!i915_modparams.disable_power_well)
 		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
 
-	if (IS_CANNONLAKE(dev_priv))
+	if (IS_ICELAKE(dev_priv))
+		icl_display_core_uninit(dev_priv);
+	else if (IS_CANNONLAKE(dev_priv))
 		cnl_display_core_uninit(dev_priv);
 	else if (IS_GEN9_BC(dev_priv))
 		skl_display_core_uninit(dev_priv);
@@ -3154,18 +3328,19 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
  * @dev_priv: i915 device instance
  *
  * This function grabs a device-level runtime pm reference if the device is
- * already in use and ensures that it is powered up.
+ * already in use and ensures that it is powered up. It is illegal to try
+ * and access the HW should intel_runtime_pm_get_if_in_use() report failure.
  *
  * Any runtime pm reference obtained by this function must have a symmetric
  * call to intel_runtime_pm_put() to release the reference again.
+ *
+ * Returns: True if the wakeref was acquired, or False otherwise.
  */
 bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
 {
-	struct pci_dev *pdev = dev_priv->drm.pdev;
-	struct device *kdev = &pdev->dev;
-
 	if (IS_ENABLED(CONFIG_PM)) {
-		int ret = pm_runtime_get_if_in_use(kdev);
+		struct pci_dev *pdev = dev_priv->drm.pdev;
+		struct device *kdev = &pdev->dev;
 
 		/*
 		 * In cases runtime PM is disabled by the RPM core and we get
@@ -3173,9 +3348,7 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
 		 * function, since the power state is undefined. This applies
 		 * atm to the late/early system suspend/resume handlers.
 		 */
-		WARN_ONCE(ret < 0,
-			  "pm_runtime_get_if_in_use() failed: %d\n", ret);
-		if (ret <= 0)
+		if (pm_runtime_get_if_in_use(kdev) <= 0)
 			return false;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 2b8764897d68..0c14d1c04cbd 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -214,7 +214,7 @@ static bool
 intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
 				   struct intel_sdvo_connector *intel_sdvo_connector);
 
-/**
+/*
  * Writes the SDVOB or SDVOC with the given value, but always writes both
  * SDVOB and SDVOC to work around apparent hardware issues (according to
  * comments in the BIOS).
@@ -250,10 +250,10 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 	 * writing them only once doesn't appear to 'stick'.
 	 * The BIOS does this too. Yay, magic
 	 */
-	for (i = 0; i < 2; i++)
-	{
+	for (i = 0; i < 2; i++) {
 		I915_WRITE(GEN3_SDVOB, bval);
 		POSTING_READ(GEN3_SDVOB);
+
 		I915_WRITE(GEN3_SDVOC, cval);
 		POSTING_READ(GEN3_SDVOC);
 	}
@@ -643,7 +643,7 @@ static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo)
 				    &targets, sizeof(targets));
 }
 
-/**
+/*
  * Return whether each input is trained.
  *
  * This function is making an assumption about the layout of the response,
@@ -1061,8 +1061,10 @@ intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
 	return true;
 }
 
-/* Asks the sdvo controller for the preferred input mode given the output mode.
- * Unfortunately we have to set up the full output mode to do that. */
+/*
+ * Asks the sdvo controller for the preferred input mode given the output mode.
+ * Unfortunately we have to set up the full output mode to do that.
+ */
 static bool
 intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
 				    const struct drm_display_mode *mode,
@@ -1095,8 +1097,10 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
 	unsigned dotclock = pipe_config->port_clock;
 	struct dpll *clock = &pipe_config->dpll;
 
-	/* SDVO TV has fixed PLL values depend on its clock range,
-	   this mirrors vbios setting. */
+	/*
+	 * SDVO TV has fixed PLL values depend on its clock range,
+	 * this mirrors vbios setting.
+	 */
 	if (dotclock >= 100000 && dotclock < 140500) {
 		clock->p1 = 2;
 		clock->p2 = 10;
@@ -1132,7 +1136,8 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 	if (HAS_PCH_SPLIT(to_i915(encoder->base.dev)))
 		pipe_config->has_pch_encoder = true;
 
-	/* We need to construct preferred input timings based on our
+	/*
+	 * We need to construct preferred input timings based on our
 	 * output timings.  To do that, we have to set the output
 	 * timings, even though this isn't really the right place in
 	 * the sequence to do it. Oh well.
@@ -1155,7 +1160,8 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 							   adjusted_mode);
 	}
 
-	/* Make the CRTC code factor in the SDVO pixel multiplier.  The
+	/*
+	 * Make the CRTC code factor in the SDVO pixel multiplier.  The
 	 * SDVO device will factor out the multiplier during mode_set.
 	 */
 	pipe_config->pixel_multiplier =
@@ -1169,9 +1175,12 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 		pipe_config->has_audio = true;
 
 	if (intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
-		/* See CEA-861-E - 5.1 Default Encoding Parameters */
-		/* FIXME: This bit is only valid when using TMDS encoding and 8
-		 * bit per color mode. */
+		/*
+		 * See CEA-861-E - 5.1 Default Encoding Parameters
+		 *
+		 * FIXME: This bit is only valid when using TMDS encoding and 8
+		 * bit per color mode.
+		 */
 		if (pipe_config->has_hdmi_sink &&
 		    drm_match_cea_mode(adjusted_mode) > 1)
 			pipe_config->limited_color_range = true;
@@ -1272,7 +1281,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
 
 	intel_sdvo_update_props(intel_sdvo, sdvo_state);
 
-	/* First, set the input mapping for the first input to our controlled
+	/*
+	 * First, set the input mapping for the first input to our controlled
 	 * output. This is only correct if we're a single-input device, in
 	 * which case the first input is the output from the appropriate SDVO
 	 * channel on the motherboard.  In a two-input device, the first input
@@ -1435,8 +1445,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
 
 	ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
 	if (!ret) {
-		/* Some sdvo encoders are not spec compliant and don't
-		 * implement the mandatory get_timings function. */
+		/*
+		 * Some sdvo encoders are not spec compliant and don't
+		 * implement the mandatory get_timings function.
+		 */
 		DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
 		pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS;
 	} else {
@@ -1585,7 +1597,9 @@ static void intel_enable_sdvo(struct intel_encoder *encoder,
 		intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
 
 	success = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
-	/* Warn if the device reported failure to sync.
+	/*
+	 * Warn if the device reported failure to sync.
+	 *
 	 * A lot of SDVO devices fail to notify of sync, but it's
 	 * a given it the status is a success, we succeeded.
 	 */
@@ -1607,9 +1621,6 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
 	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
 
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		return MODE_NO_DBLESCAN;
-
 	if (intel_sdvo->pixel_clock_min > mode->clock)
 		return MODE_CLOCK_LOW;
 
@@ -1675,8 +1686,10 @@ static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
 	if (!I915_HAS_HOTPLUG(dev_priv))
 		return 0;
 
-	/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
-	 * on the line. */
+	/*
+	 * HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
+	 * on the line.
+	 */
 	if (IS_I945G(dev_priv) || IS_I945GM(dev_priv))
 		return 0;
 
@@ -1960,7 +1973,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 
-	/* Read the list of supported input resolutions for the selected TV
+	/*
+	 * Read the list of supported input resolutions for the selected TV
 	 * format.
 	 */
 	format_map = 1 << conn_state->tv.mode;
@@ -2271,7 +2285,8 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
 	uint16_t mask = 0;
 	unsigned int num_bits;
 
-	/* Make a mask of outputs less than or equal to our own priority in the
+	/*
+	 * Make a mask of outputs less than or equal to our own priority in the
 	 * list.
 	 */
 	switch (sdvo->controlled_output) {
@@ -2301,7 +2316,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
 	sdvo->ddc_bus = 1 << num_bits;
 }
 
-/**
+/*
  * Choose the appropriate DDC bus for control bus switch command for this
  * SDVO output based on the controlled output.
  *
@@ -2345,9 +2360,11 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
 
 	sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
 
-	/* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow
+	/*
+	 * With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow
 	 * our code totally fails once we start using gmbus. Hence fall back to
-	 * bit banging for now. */
+	 * bit banging for now.
+	 */
 	intel_gmbus_force_bit(sdvo->i2c, true);
 }
 
@@ -2382,7 +2399,8 @@ intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv,
 	if (my_mapping->slave_addr)
 		return my_mapping->slave_addr;
 
-	/* If the BIOS only described a different SDVO device, use the
+	/*
+	 * If the BIOS only described a different SDVO device, use the
 	 * address that it isn't using.
 	 */
 	if (other_mapping->slave_addr) {
@@ -2392,7 +2410,8 @@ intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv,
 			return 0x70;
 	}
 
-	/* No SDVO device info is found for another DVO port,
+	/*
+	 * No SDVO device info is found for another DVO port,
 	 * so use mapping assumption we had before BIOS parsing.
 	 */
 	if (sdvo->port == PORT_B)
@@ -2493,7 +2512,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 	if (intel_sdvo_get_hotplug_support(intel_sdvo) &
 		intel_sdvo_connector->output_flag) {
 		intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
-		/* Some SDVO devices have one-shot hotplug interrupts.
+		/*
+		 * Some SDVO devices have one-shot hotplug interrupts.
 		 * Ensure that they get re-enabled when an interrupt happens.
 		 */
 		intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
@@ -2792,7 +2812,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
 		to_intel_sdvo_connector_state(conn_state);
 	uint16_t response, data_value[2];
 
-	/* when horizontal overscan is supported, Add the left/right  property */
+	/* when horizontal overscan is supported, Add the left/right property */
 	if (enhancements.overscan_h) {
 		if (!intel_sdvo_get_value(intel_sdvo,
 					  SDVO_CMD_GET_MAX_OVERSCAN_H,
@@ -3077,7 +3097,8 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
 		goto err_output;
 	}
 
-	/* Only enable the hotplug irq if we need it, to work around noisy
+	/*
+	 * Only enable the hotplug irq if we need it, to work around noisy
 	 * hotplug lines.
 	 */
 	if (intel_sdvo->hotplug_active) {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index dd485f59eb1d..e098e4b2c85c 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -864,7 +864,8 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	uint32_t src_x, src_y, src_w, src_h;
 	struct drm_rect *src = &state->base.src;
 	struct drm_rect *dst = &state->base.dst;
-	const struct drm_rect *clip = &state->clip;
+	struct drm_rect clip = {};
+	int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384;
 	int hscale, vscale;
 	int max_scale, min_scale;
 	bool can_scale;
@@ -885,7 +886,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	}
 
 	/* FIXME check all gen limits */
-	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) {
+	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > max_stride) {
 		DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
 		return -EINVAL;
 	}
@@ -893,7 +894,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	/* setup can_scale, min_scale, max_scale */
 	if (INTEL_GEN(dev_priv) >= 9) {
 		/* use scaler when colorkey is not required */
-		if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
+		if (!state->ckey.flags) {
 			can_scale = 1;
 			min_scale = 1;
 			max_scale = skl_max_scale(crtc, crtc_state);
@@ -922,7 +923,11 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
 	BUG_ON(vscale < 0);
 
-	state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
+	if (crtc_state->base.enable)
+		drm_mode_get_hv_timing(&crtc_state->base.mode,
+				       &clip.x2, &clip.y2);
+
+	state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
 
 	crtc_x = dst->x1;
 	crtc_y = dst->y1;
@@ -1027,7 +1032,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	dst->y2 = crtc_y + crtc_h;
 
 	if (INTEL_GEN(dev_priv) >= 9) {
-		ret = skl_check_plane_surface(state);
+		ret = skl_check_plane_surface(crtc_state, state);
 		if (ret)
 			return ret;
 
@@ -1058,8 +1063,8 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	return 0;
 }
 
-int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
-			      struct drm_file *file_priv)
+int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct drm_intel_sprite_colorkey *set = data;
@@ -1069,6 +1074,12 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 	struct drm_modeset_acquire_ctx ctx;
 	int ret = 0;
 
+	/* ignore the pointless "none" flag */
+	set->flags &= ~I915_SET_COLORKEY_NONE;
+
+	if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
+		return -EINVAL;
+
 	/* Make sure we don't try to enable both src & dest simultaneously */
 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
 		return -EINVAL;
@@ -1161,18 +1172,27 @@ static uint32_t skl_plane_formats[] = {
 	DRM_FORMAT_VYUY,
 };
 
-static const uint64_t skl_plane_format_modifiers[] = {
+static const uint64_t skl_plane_format_modifiers_noccs[] = {
+	I915_FORMAT_MOD_Yf_TILED,
+	I915_FORMAT_MOD_Y_TILED,
+	I915_FORMAT_MOD_X_TILED,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static const uint64_t skl_plane_format_modifiers_ccs[] = {
+	I915_FORMAT_MOD_Yf_TILED_CCS,
+	I915_FORMAT_MOD_Y_TILED_CCS,
+	I915_FORMAT_MOD_Yf_TILED,
+	I915_FORMAT_MOD_Y_TILED,
 	I915_FORMAT_MOD_X_TILED,
 	DRM_FORMAT_MOD_LINEAR,
 	DRM_FORMAT_MOD_INVALID
 };
 
-static bool g4x_sprite_plane_format_mod_supported(struct drm_plane *plane,
-						  uint32_t format,
-						  uint64_t modifier)
+static bool g4x_mod_supported(uint32_t format, uint64_t modifier)
 {
 	switch (format) {
-	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_XRGB8888:
 	case DRM_FORMAT_YUYV:
 	case DRM_FORMAT_YVYU:
@@ -1187,22 +1207,38 @@ static bool g4x_sprite_plane_format_mod_supported(struct drm_plane *plane,
 	}
 }
 
-static bool vlv_sprite_plane_format_mod_supported(struct drm_plane *plane,
-						  uint32_t format,
-						  uint64_t modifier)
+static bool snb_mod_supported(uint32_t format, uint64_t modifier)
 {
 	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_YUYV:
 	case DRM_FORMAT_YVYU:
 	case DRM_FORMAT_UYVY:
 	case DRM_FORMAT_VYUY:
+		if (modifier == DRM_FORMAT_MOD_LINEAR ||
+		    modifier == I915_FORMAT_MOD_X_TILED)
+			return true;
+		/* fall through */
+	default:
+		return false;
+	}
+}
+
+static bool vlv_mod_supported(uint32_t format, uint64_t modifier)
+{
+	switch (format) {
 	case DRM_FORMAT_RGB565:
-	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
 	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_XRGB8888:
 	case DRM_FORMAT_XBGR2101010:
 	case DRM_FORMAT_ABGR2101010:
-	case DRM_FORMAT_XBGR8888:
-	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
 		if (modifier == DRM_FORMAT_MOD_LINEAR ||
 		    modifier == I915_FORMAT_MOD_X_TILED)
 			return true;
@@ -1212,16 +1248,17 @@ static bool vlv_sprite_plane_format_mod_supported(struct drm_plane *plane,
 	}
 }
 
-static bool skl_sprite_plane_format_mod_supported(struct drm_plane *plane,
-						  uint32_t format,
-						  uint64_t modifier)
+static bool skl_mod_supported(uint32_t format, uint64_t modifier)
 {
-	/* This is the same as primary plane since SKL has universal planes */
 	switch (format) {
 	case DRM_FORMAT_XRGB8888:
 	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ARGB8888:
 	case DRM_FORMAT_ABGR8888:
+		if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
+		    modifier == I915_FORMAT_MOD_Y_TILED_CCS)
+			return true;
+		/* fall through */
 	case DRM_FORMAT_RGB565:
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_XBGR2101010:
@@ -1257,13 +1294,13 @@ static bool intel_sprite_plane_format_mod_supported(struct drm_plane *plane,
 		return false;
 
 	if (INTEL_GEN(dev_priv) >= 9)
-		return skl_sprite_plane_format_mod_supported(plane, format, modifier);
+		return skl_mod_supported(format, modifier);
 	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-		return vlv_sprite_plane_format_mod_supported(plane, format, modifier);
+		return vlv_mod_supported(format, modifier);
+	else if (INTEL_GEN(dev_priv) >= 6)
+		return snb_mod_supported(format, modifier);
 	else
-		return g4x_sprite_plane_format_mod_supported(plane, format, modifier);
-
-	unreachable();
+		return g4x_mod_supported(format, modifier);
 }
 
 static const struct drm_plane_funcs intel_sprite_plane_funcs = {
@@ -1277,6 +1314,23 @@ static const struct drm_plane_funcs intel_sprite_plane_funcs = {
         .format_mod_supported = intel_sprite_plane_format_mod_supported,
 };
 
+bool skl_plane_has_ccs(struct drm_i915_private *dev_priv,
+		       enum pipe pipe, enum plane_id plane_id)
+{
+	if (plane_id == PLANE_CURSOR)
+		return false;
+
+	if (INTEL_GEN(dev_priv) >= 10)
+		return true;
+
+	if (IS_GEMINILAKE(dev_priv))
+		return pipe != PIPE_C;
+
+	return pipe != PIPE_C &&
+		(plane_id == PLANE_PRIMARY ||
+		 plane_id == PLANE_SPRITE0);
+}
+
 struct intel_plane *
 intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 			  enum pipe pipe, int plane)
@@ -1303,7 +1357,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 	}
 	intel_plane->base.state = &state->base;
 
-	if (INTEL_GEN(dev_priv) >= 10) {
+	if (INTEL_GEN(dev_priv) >= 9) {
 		intel_plane->can_scale = true;
 		state->scaler_id = -1;
 
@@ -1313,18 +1367,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 
 		plane_formats = skl_plane_formats;
 		num_plane_formats = ARRAY_SIZE(skl_plane_formats);
-		modifiers = skl_plane_format_modifiers;
-	} else if (INTEL_GEN(dev_priv) >= 9) {
-		intel_plane->can_scale = true;
-		state->scaler_id = -1;
 
-		intel_plane->update_plane = skl_update_plane;
-		intel_plane->disable_plane = skl_disable_plane;
-		intel_plane->get_hw_state = skl_plane_get_hw_state;
-
-		plane_formats = skl_plane_formats;
-		num_plane_formats = ARRAY_SIZE(skl_plane_formats);
-		modifiers = skl_plane_format_modifiers;
+		if (skl_plane_has_ccs(dev_priv, pipe, PLANE_SPRITE0 + plane))
+			modifiers = skl_plane_format_modifiers_ccs;
+		else
+			modifiers = skl_plane_format_modifiers_noccs;
 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 		intel_plane->can_scale = false;
 		intel_plane->max_downscale = 1;
@@ -1386,7 +1433,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
 	intel_plane->pipe = pipe;
 	intel_plane->i9xx_plane = plane;
 	intel_plane->id = PLANE_SPRITE0 + plane;
-	intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane);
+	intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id);
 	intel_plane->check_plane = intel_check_sprite_plane;
 
 	possible_crtcs = (1 << pipe);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index b3dabc219e6a..885fc3809f7f 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -43,7 +43,6 @@ enum tv_margin {
 	TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
 };
 
-/** Private structure for the integrated TV support */
 struct intel_tv {
 	struct intel_encoder base;
 
@@ -370,12 +369,11 @@ struct tv_mode {
  * The constants below were all computed using a 107.520MHz clock
  */
 
-/**
+/*
  * Register programming values for TV modes.
  *
  * These values account for -1s required.
  */
-
 static const struct tv_mode tv_modes[] = {
 	{
 		.name		= "NTSC-M",
@@ -1126,14 +1124,6 @@ static const struct drm_display_mode reported_modes[] = {
 	},
 };
 
-/**
- * Detects TV presence by checking for load.
- *
- * Requires that the current pipe's DPLL is active.
-
- * \return true if TV is connected.
- * \return false if TV is disconnected.
- */
 static int
 intel_tv_detect_type(struct intel_tv *intel_tv,
 		      struct drm_connector *connector)
@@ -1259,12 +1249,6 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
 	connector->state->tv.mode = i;
 }
 
-/**
- * Detect the TV connection.
- *
- * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
- * we have a pipe programmed in order to probe the TV.
- */
 static int
 intel_tv_detect(struct drm_connector *connector,
 		struct drm_modeset_acquire_ctx *ctx,
@@ -1339,13 +1323,6 @@ intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
 	}
 }
 
-/**
- * Stub get_modes function.
- *
- * This should probably return a set of fixed modes, unless we can figure out
- * how to probe modes off of TV connections.
- */
-
 static int
 intel_tv_get_modes(struct drm_connector *connector)
 {
@@ -1512,7 +1489,8 @@ intel_tv_init(struct drm_i915_private *dev_priv)
 	connector = &intel_connector->base;
 	state = connector->state;
 
-	/* The documentation, for the older chipsets at least, recommend
+	/*
+	 * The documentation, for the older chipsets at least, recommend
 	 * using a polling method rather than hotplug detection for TVs.
 	 * This is because in order to perform the hotplug detection, the PLLs
 	 * for the TV must be kept alive increasing power drain and starving
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
index d82ca0f438f5..9f1bac6398fb 100644
--- a/drivers/gpu/drm/i915/intel_uc.c
+++ b/drivers/gpu/drm/i915/intel_uc.c
@@ -27,6 +27,8 @@
 #include "intel_guc.h"
 #include "i915_drv.h"
 
+static void guc_free_load_err_log(struct intel_guc *guc);
+
 /* Reset GuC providing us with fresh state for both GuC and HuC.
  */
 static int __intel_uc_reset_hw(struct drm_i915_private *dev_priv)
@@ -65,6 +67,21 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv)
 	return enable_guc;
 }
 
+static int __get_default_guc_log_level(struct drm_i915_private *dev_priv)
+{
+	int guc_log_level = 0; /* disabled */
+
+	/* Enable if we're running on platform with GuC and debug config */
+	if (HAS_GUC(dev_priv) && intel_uc_is_using_guc() &&
+	    (IS_ENABLED(CONFIG_DRM_I915_DEBUG) ||
+	     IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)))
+		guc_log_level = 1 + GUC_LOG_VERBOSITY_MAX;
+
+	/* Any platform specific fine-tuning can be done here */
+
+	return guc_log_level;
+}
+
 /**
  * intel_uc_sanitize_options - sanitize uC related modparam options
  * @dev_priv: device private
@@ -74,6 +91,13 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv)
  * modparam varies between platforms and it is hardcoded in driver code.
  * Any other modparam value is only monitored against availability of the
  * related hardware or firmware definitions.
+ *
+ * In case of "guc_log_level" option this function will attempt to modify
+ * it only if it was initially set to "auto(-1)" or if initial value was
+ * "enable(1..4)" on platforms without the GuC. Default value for this
+ * modparam varies between platforms and is usually set to "disable(0)"
+ * unless GuC is enabled on given platform and the driver is compiled with
+ * debug config when this modparam will default to "enable(1..4)".
  */
 void intel_uc_sanitize_options(struct drm_i915_private *dev_priv)
 {
@@ -91,22 +115,48 @@ void intel_uc_sanitize_options(struct drm_i915_private *dev_priv)
 
 	/* Verify GuC firmware availability */
 	if (intel_uc_is_using_guc() && !intel_uc_fw_is_selected(guc_fw)) {
-		DRM_WARN("Incompatible option detected: enable_guc=%d, %s!\n",
-			 i915_modparams.enable_guc,
+		DRM_WARN("Incompatible option detected: %s=%d, %s!\n",
+			 "enable_guc", i915_modparams.enable_guc,
 			 !HAS_GUC(dev_priv) ? "no GuC hardware" :
 					      "no GuC firmware");
 	}
 
 	/* Verify HuC firmware availability */
 	if (intel_uc_is_using_huc() && !intel_uc_fw_is_selected(huc_fw)) {
-		DRM_WARN("Incompatible option detected: enable_guc=%d, %s!\n",
-			 i915_modparams.enable_guc,
+		DRM_WARN("Incompatible option detected: %s=%d, %s!\n",
+			 "enable_guc", i915_modparams.enable_guc,
 			 !HAS_HUC(dev_priv) ? "no HuC hardware" :
 					      "no HuC firmware");
 	}
 
+	/* A negative value means "use platform/config default" */
+	if (i915_modparams.guc_log_level < 0)
+		i915_modparams.guc_log_level =
+			__get_default_guc_log_level(dev_priv);
+
+	if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc()) {
+		DRM_WARN("Incompatible option detected: %s=%d, %s!\n",
+			 "guc_log_level", i915_modparams.guc_log_level,
+			 !HAS_GUC(dev_priv) ? "no GuC hardware" :
+					      "GuC not enabled");
+		i915_modparams.guc_log_level = 0;
+	}
+
+	if (i915_modparams.guc_log_level > 1 + GUC_LOG_VERBOSITY_MAX) {
+		DRM_WARN("Incompatible option detected: %s=%d, %s!\n",
+			 "guc_log_level", i915_modparams.guc_log_level,
+			 "verbosity too high");
+		i915_modparams.guc_log_level = 1 + GUC_LOG_VERBOSITY_MAX;
+	}
+
+	DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s verbosity:%d)\n",
+			 i915_modparams.guc_log_level,
+			 yesno(i915_modparams.guc_log_level),
+			 i915_modparams.guc_log_level - 1);
+
 	/* Make sure that sanitization was done */
 	GEM_BUG_ON(i915_modparams.enable_guc < 0);
+	GEM_BUG_ON(i915_modparams.guc_log_level < 0);
 }
 
 void intel_uc_init_early(struct drm_i915_private *dev_priv)
@@ -135,6 +185,8 @@ void intel_uc_fini_fw(struct drm_i915_private *dev_priv)
 
 	if (USES_HUC(dev_priv))
 		intel_uc_fw_fini(&dev_priv->huc.fw);
+
+	guc_free_load_err_log(&dev_priv->guc);
 }
 
 /**
@@ -152,7 +204,7 @@ void intel_uc_init_mmio(struct drm_i915_private *dev_priv)
 
 static void guc_capture_load_err_log(struct intel_guc *guc)
 {
-	if (!guc->log.vma || i915_modparams.guc_log_level < 0)
+	if (!guc->log.vma || !i915_modparams.guc_log_level)
 		return;
 
 	if (!guc->load_err_log)
@@ -188,28 +240,44 @@ static void guc_disable_communication(struct intel_guc *guc)
 	guc->send = intel_guc_send_nop;
 }
 
-int intel_uc_init_wq(struct drm_i915_private *dev_priv)
+int intel_uc_init_misc(struct drm_i915_private *dev_priv)
 {
+	struct intel_guc *guc = &dev_priv->guc;
 	int ret;
 
 	if (!USES_GUC(dev_priv))
 		return 0;
 
-	ret = intel_guc_init_wq(&dev_priv->guc);
+	ret = intel_guc_init_wq(guc);
 	if (ret) {
 		DRM_ERROR("Couldn't allocate workqueues for GuC\n");
-		return ret;
+		goto err;
+	}
+
+	ret = intel_guc_log_relay_create(guc);
+	if (ret) {
+		DRM_ERROR("Couldn't allocate relay for GuC log\n");
+		goto err_relay;
 	}
 
 	return 0;
+
+err_relay:
+	intel_guc_fini_wq(guc);
+err:
+	return ret;
 }
 
-void intel_uc_fini_wq(struct drm_i915_private *dev_priv)
+void intel_uc_fini_misc(struct drm_i915_private *dev_priv)
 {
+	struct intel_guc *guc = &dev_priv->guc;
+
 	if (!USES_GUC(dev_priv))
 		return;
 
-	intel_guc_fini_wq(&dev_priv->guc);
+	intel_guc_fini_wq(guc);
+
+	intel_guc_log_relay_destroy(guc);
 }
 
 int intel_uc_init(struct drm_i915_private *dev_priv)
@@ -322,7 +390,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv)
 	}
 
 	if (USES_GUC_SUBMISSION(dev_priv)) {
-		if (i915_modparams.guc_log_level >= 0)
+		if (i915_modparams.guc_log_level)
 			gen9_enable_guc_interrupts(dev_priv);
 
 		ret = intel_guc_submission_enable(guc);
@@ -364,8 +432,6 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc *guc = &dev_priv->guc;
 
-	guc_free_load_err_log(guc);
-
 	if (!USES_GUC(dev_priv))
 		return;
 
diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h
index 8a7249722ef1..f2984e01e257 100644
--- a/drivers/gpu/drm/i915/intel_uc.h
+++ b/drivers/gpu/drm/i915/intel_uc.h
@@ -33,8 +33,8 @@ void intel_uc_init_early(struct drm_i915_private *dev_priv);
 void intel_uc_init_mmio(struct drm_i915_private *dev_priv);
 void intel_uc_init_fw(struct drm_i915_private *dev_priv);
 void intel_uc_fini_fw(struct drm_i915_private *dev_priv);
-int intel_uc_init_wq(struct drm_i915_private *dev_priv);
-void intel_uc_fini_wq(struct drm_i915_private *dev_priv);
+int intel_uc_init_misc(struct drm_i915_private *dev_priv);
+void intel_uc_fini_misc(struct drm_i915_private *dev_priv);
 int intel_uc_init_hw(struct drm_i915_private *dev_priv);
 void intel_uc_fini_hw(struct drm_i915_private *dev_priv);
 int intel_uc_init(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c
index 784eff9cdfc8..3ec0ce505b76 100644
--- a/drivers/gpu/drm/i915/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/intel_uc_fw.c
@@ -197,11 +197,12 @@ void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
 
 /**
  * intel_uc_fw_upload - load uC firmware using custom loader
- *
  * @uc_fw: uC firmware
- * @loader: custom uC firmware loader function
+ * @xfer: custom uC firmware loader function
  *
  * Loads uC firmware using custom loader and updates internal flags.
+ *
+ * Return: 0 on success, non-zero on failure.
  */
 int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
 		       int (*xfer)(struct intel_uc_fw *uc_fw,
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 89547b614aa6..5ae9a62712ca 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -1452,7 +1452,7 @@ static const struct reg_whitelist {
 } reg_read_whitelist[] = { {
 	.offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE),
 	.offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE),
-	.gen_mask = INTEL_GEN_MASK(4, 10),
+	.gen_mask = INTEL_GEN_MASK(4, 11),
 	.size = 8
 } };
 
@@ -1522,9 +1522,11 @@ static void gen3_stop_engine(struct intel_engine_cs *engine)
 				 engine->name);
 
 	I915_WRITE_FW(RING_HEAD(base), I915_READ_FW(RING_TAIL(base)));
+	POSTING_READ_FW(RING_HEAD(base)); /* paranoia */
 
 	I915_WRITE_FW(RING_HEAD(base), 0);
 	I915_WRITE_FW(RING_TAIL(base), 0);
+	POSTING_READ_FW(RING_TAIL(base));
 
 	/* The ring must be empty before it is disabled */
 	I915_WRITE_FW(RING_CTL(base), 0);
@@ -1548,24 +1550,31 @@ static void i915_stop_engines(struct drm_i915_private *dev_priv,
 		gen3_stop_engine(engine);
 }
 
-static bool i915_reset_complete(struct pci_dev *pdev)
+static bool i915_in_reset(struct pci_dev *pdev)
 {
 	u8 gdrst;
 
 	pci_read_config_byte(pdev, I915_GDRST, &gdrst);
-	return (gdrst & GRDOM_RESET_STATUS) == 0;
+	return gdrst & GRDOM_RESET_STATUS;
 }
 
 static int i915_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask)
 {
 	struct pci_dev *pdev = dev_priv->drm.pdev;
+	int err;
 
-	/* assert reset for at least 20 usec */
+	/* Assert reset for at least 20 usec, and wait for acknowledgement. */
 	pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE);
 	usleep_range(50, 200);
+	err = wait_for(i915_in_reset(pdev), 500);
+
+	/* Clear the reset request. */
 	pci_write_config_byte(pdev, I915_GDRST, 0);
+	usleep_range(50, 200);
+	if (!err)
+		err = wait_for(!i915_in_reset(pdev), 500);
 
-	return wait_for(i915_reset_complete(pdev), 500);
+	return err;
 }
 
 static bool g4x_reset_complete(struct pci_dev *pdev)
@@ -1767,12 +1776,14 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
 }
 
 /**
- * intel_wait_for_register - wait until register matches expected state
+ * __intel_wait_for_register - wait until register matches expected state
  * @dev_priv: the i915 device
  * @reg: the register to read
  * @mask: mask to apply to register value
  * @value: expected value
- * @timeout_ms: timeout in millisecond
+ * @fast_timeout_us: fast timeout in microsecond for atomic/tight wait
+ * @slow_timeout_ms: slow timeout in millisecond
+ * @out_value: optional placeholder to hold registry value
  *
  * This routine waits until the target register @reg contains the expected
  * @value after applying the @mask, i.e. it waits until ::
@@ -1783,14 +1794,17 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
  *
  * Returns 0 if the register matches the desired condition, or -ETIMEOUT.
  */
-int intel_wait_for_register(struct drm_i915_private *dev_priv,
+int __intel_wait_for_register(struct drm_i915_private *dev_priv,
 			    i915_reg_t reg,
 			    u32 mask,
 			    u32 value,
-			    unsigned int timeout_ms)
+			    unsigned int fast_timeout_us,
+			    unsigned int slow_timeout_ms,
+			    u32 *out_value)
 {
 	unsigned fw =
 		intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ);
+	u32 reg_value;
 	int ret;
 
 	might_sleep();
@@ -1800,14 +1814,18 @@ int intel_wait_for_register(struct drm_i915_private *dev_priv,
 
 	ret = __intel_wait_for_register_fw(dev_priv,
 					   reg, mask, value,
-					   2, 0, NULL);
+					   fast_timeout_us, 0, &reg_value);
 
 	intel_uncore_forcewake_put__locked(dev_priv, fw);
 	spin_unlock_irq(&dev_priv->uncore.lock);
 
 	if (ret)
-		ret = wait_for((I915_READ_NOTRACE(reg) & mask) == value,
-			       timeout_ms);
+		ret = __wait_for(reg_value = I915_READ_NOTRACE(reg),
+				 (reg_value & mask) == value,
+				 slow_timeout_ms * 1000, 10, 1000);
+
+	if (out_value)
+		*out_value = reg_value;
 
 	return ret;
 }
@@ -1865,9 +1883,9 @@ static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv)
 	if (!i915_modparams.reset)
 		return NULL;
 
-	if (INTEL_INFO(dev_priv)->gen >= 8)
+	if (INTEL_GEN(dev_priv) >= 8)
 		return gen8_reset_engines;
-	else if (INTEL_INFO(dev_priv)->gen >= 6)
+	else if (INTEL_GEN(dev_priv) >= 6)
 		return gen6_reset_engines;
 	else if (IS_GEN5(dev_priv))
 		return ironlake_do_reset;
@@ -1875,7 +1893,7 @@ static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv)
 		return g4x_do_reset;
 	else if (IS_G33(dev_priv) || IS_PINEVIEW(dev_priv))
 		return g33_do_reset;
-	else if (INTEL_INFO(dev_priv)->gen >= 3)
+	else if (INTEL_GEN(dev_priv) >= 3)
 		return i915_do_reset;
 	else
 		return NULL;
@@ -1936,8 +1954,7 @@ int intel_reset_guc(struct drm_i915_private *dev_priv)
 {
 	int ret;
 
-	if (!HAS_GUC(dev_priv))
-		return -EINVAL;
+	GEM_BUG_ON(!HAS_GUC(dev_priv));
 
 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 	ret = gen6_hw_domain_reset(dev_priv, GEN9_GRDOM_GUC);
diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
index 9ce079b5dd0d..53ef77d0c97c 100644
--- a/drivers/gpu/drm/i915/intel_uncore.h
+++ b/drivers/gpu/drm/i915/intel_uncore.h
@@ -163,11 +163,23 @@ void intel_uncore_forcewake_put__locked(struct drm_i915_private *dev_priv,
 void intel_uncore_forcewake_user_get(struct drm_i915_private *dev_priv);
 void intel_uncore_forcewake_user_put(struct drm_i915_private *dev_priv);
 
+int __intel_wait_for_register(struct drm_i915_private *dev_priv,
+			      i915_reg_t reg,
+			      u32 mask,
+			      u32 value,
+			      unsigned int fast_timeout_us,
+			      unsigned int slow_timeout_ms,
+			      u32 *out_value);
+static inline
 int intel_wait_for_register(struct drm_i915_private *dev_priv,
 			    i915_reg_t reg,
 			    u32 mask,
 			    u32 value,
-			    unsigned int timeout_ms);
+			    unsigned int timeout_ms)
+{
+	return __intel_wait_for_register(dev_priv, reg, mask, value, 2,
+					 timeout_ms, NULL);
+}
 int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
 				 i915_reg_t reg,
 				 u32 mask,
@@ -186,4 +198,9 @@ int intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
 					    2, timeout_ms, NULL);
 }
 
+#define raw_reg_read(base, reg) \
+	readl(base + i915_mmio_reg_offset(reg))
+#define raw_reg_write(base, reg, value) \
+	writel(value, base + i915_mmio_reg_offset(reg))
+
 #endif /* !__INTEL_UNCORE_H__ */
diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h
index 98dff6058d3c..458468237b5f 100644
--- a/drivers/gpu/drm/i915/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/intel_vbt_defs.h
@@ -227,7 +227,7 @@ struct bdb_general_features {
 #define DEVICE_TYPE_COMPOSITE_OUTPUT	(1 << 9)
 #define DEVICE_TYPE_DUAL_CHANNEL	(1 << 8)
 #define DEVICE_TYPE_HIGH_SPEED_LINK	(1 << 6)
-#define DEVICE_TYPE_LVDS_SINGALING	(1 << 5)
+#define DEVICE_TYPE_LVDS_SIGNALING	(1 << 5)
 #define DEVICE_TYPE_TMDS_DVI_SIGNALING	(1 << 4)
 #define DEVICE_TYPE_VIDEO_SIGNALING	(1 << 3)
 #define DEVICE_TYPE_DISPLAYPORT_OUTPUT	(1 << 2)
@@ -243,7 +243,7 @@ struct bdb_general_features {
 	 DEVICE_TYPE_MIPI_OUTPUT |		\
 	 DEVICE_TYPE_COMPOSITE_OUTPUT |		\
 	 DEVICE_TYPE_DUAL_CHANNEL |		\
-	 DEVICE_TYPE_LVDS_SINGALING |		\
+	 DEVICE_TYPE_LVDS_SIGNALING |		\
 	 DEVICE_TYPE_TMDS_DVI_SIGNALING |	\
 	 DEVICE_TYPE_VIDEO_SIGNALING |		\
 	 DEVICE_TYPE_DISPLAYPORT_OUTPUT |	\
@@ -253,7 +253,7 @@ struct bdb_general_features {
 	(DEVICE_TYPE_INTERNAL_CONNECTOR |	\
 	 DEVICE_TYPE_MIPI_OUTPUT |		\
 	 DEVICE_TYPE_COMPOSITE_OUTPUT |		\
-	 DEVICE_TYPE_LVDS_SINGALING |		\
+	 DEVICE_TYPE_LVDS_SIGNALING |		\
 	 DEVICE_TYPE_TMDS_DVI_SIGNALING |	\
 	 DEVICE_TYPE_VIDEO_SIGNALING |		\
 	 DEVICE_TYPE_DISPLAYPORT_OUTPUT |	\
@@ -299,6 +299,8 @@ struct bdb_general_features {
 #define DVO_PORT_DPA		10
 #define DVO_PORT_DPE		11				/* 193 */
 #define DVO_PORT_HDMIE		12				/* 193 */
+#define DVO_PORT_DPF		13				/* N/A */
+#define DVO_PORT_HDMIF		14				/* N/A */
 #define DVO_PORT_MIPIA		21				/* 171 */
 #define DVO_PORT_MIPIB		22				/* 171 */
 #define DVO_PORT_MIPIC		23				/* 171 */
@@ -318,6 +320,11 @@ enum vbt_gmbus_ddi {
 	DDC_BUS_DDI_F,
 };
 
+#define VBT_DP_MAX_LINK_RATE_HBR3	0
+#define VBT_DP_MAX_LINK_RATE_HBR2	1
+#define VBT_DP_MAX_LINK_RATE_HBR	2
+#define VBT_DP_MAX_LINK_RATE_LBR	3
+
 /*
  * The child device config, aka the display device data structure, provides a
  * description of a port and its configuration on the platform.
diff --git a/drivers/gpu/drm/i915/selftests/huge_gem_object.c b/drivers/gpu/drm/i915/selftests/huge_gem_object.c
index a2632df39173..391f3d9ffdf1 100644
--- a/drivers/gpu/drm/i915/selftests/huge_gem_object.c
+++ b/drivers/gpu/drm/i915/selftests/huge_gem_object.c
@@ -129,8 +129,8 @@ huge_gem_object(struct drm_i915_private *i915,
 	drm_gem_private_object_init(&i915->drm, &obj->base, dma_size);
 	i915_gem_object_init(obj, &huge_ops);
 
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
 	cache_level = HAS_LLC(i915) ? I915_CACHE_LLC : I915_CACHE_NONE;
 	i915_gem_object_set_cache_coherency(obj, cache_level);
 	obj->scratch = phys_size;
diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c
index 2ea69394f428..52b1bd17bf46 100644
--- a/drivers/gpu/drm/i915/selftests/huge_pages.c
+++ b/drivers/gpu/drm/i915/selftests/huge_pages.c
@@ -178,8 +178,8 @@ huge_pages_object(struct drm_i915_private *i915,
 	drm_gem_private_object_init(&i915->drm, &obj->base, size);
 	i915_gem_object_init(obj, &huge_page_ops);
 
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
 	obj->cache_level = I915_CACHE_NONE;
 
 	obj->mm.page_mask = page_mask;
@@ -329,8 +329,8 @@ fake_huge_pages_object(struct drm_i915_private *i915, u64 size, bool single)
 	else
 		i915_gem_object_init(obj, &fake_ops);
 
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
 	obj->cache_level = I915_CACHE_NONE;
 
 	return obj;
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c
index 56a803d11916..6da2a2f29c54 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c
@@ -215,8 +215,8 @@ static int cpu_fill(struct drm_i915_gem_object *obj, u32 value)
 	}
 
 	i915_gem_obj_finish_shmem_access(obj);
-	obj->base.read_domains = I915_GEM_DOMAIN_GTT | I915_GEM_DOMAIN_CPU;
-	obj->base.write_domain = 0;
+	obj->read_domains = I915_GEM_DOMAIN_GTT | I915_GEM_DOMAIN_CPU;
+	obj->write_domain = 0;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 4a28d713a7d8..f7dc926f4ef1 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -113,8 +113,8 @@ fake_dma_object(struct drm_i915_private *i915, u64 size)
 	drm_gem_private_object_init(&i915->drm, &obj->base, size);
 	i915_gem_object_init(obj, &fake_ops);
 
-	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
 	obj->cache_level = I915_CACHE_NONE;
 
 	/* Preallocate the "backing storage" */
@@ -885,6 +885,84 @@ static int shrink_hole(struct drm_i915_private *i915,
 	return err;
 }
 
+static int shrink_boom(struct drm_i915_private *i915,
+		       struct i915_address_space *vm,
+		       u64 hole_start, u64 hole_end,
+		       unsigned long end_time)
+{
+	unsigned int sizes[] = { SZ_2M, SZ_1G };
+	struct drm_i915_gem_object *purge;
+	struct drm_i915_gem_object *explode;
+	int err;
+	int i;
+
+	/*
+	 * Catch the case which shrink_hole seems to miss. The setup here
+	 * requires invoking the shrinker as we do the alloc_pt/alloc_pd, while
+	 * ensuring that all vma assiocated with the respective pd/pdp are
+	 * unpinned at the time.
+	 */
+
+	for (i = 0; i < ARRAY_SIZE(sizes); ++i) {
+		unsigned int flags = PIN_USER | PIN_OFFSET_FIXED;
+		unsigned int size = sizes[i];
+		struct i915_vma *vma;
+
+		purge = fake_dma_object(i915, size);
+		if (IS_ERR(purge))
+			return PTR_ERR(purge);
+
+		vma = i915_vma_instance(purge, vm, NULL);
+		if (IS_ERR(vma)) {
+			err = PTR_ERR(vma);
+			goto err_purge;
+		}
+
+		err = i915_vma_pin(vma, 0, 0, flags);
+		if (err)
+			goto err_purge;
+
+		/* Should now be ripe for purging */
+		i915_vma_unpin(vma);
+
+		explode = fake_dma_object(i915, size);
+		if (IS_ERR(explode)) {
+			err = PTR_ERR(explode);
+			goto err_purge;
+		}
+
+		vm->fault_attr.probability = 100;
+		vm->fault_attr.interval = 1;
+		atomic_set(&vm->fault_attr.times, -1);
+
+		vma = i915_vma_instance(explode, vm, NULL);
+		if (IS_ERR(vma)) {
+			err = PTR_ERR(vma);
+			goto err_explode;
+		}
+
+		err = i915_vma_pin(vma, 0, 0, flags | size);
+		if (err)
+			goto err_explode;
+
+		i915_vma_unpin(vma);
+
+		i915_gem_object_put(purge);
+		i915_gem_object_put(explode);
+
+		memset(&vm->fault_attr, 0, sizeof(vm->fault_attr));
+	}
+
+	return 0;
+
+err_explode:
+	i915_gem_object_put(explode);
+err_purge:
+	i915_gem_object_put(purge);
+	memset(&vm->fault_attr, 0, sizeof(vm->fault_attr));
+	return err;
+}
+
 static int exercise_ppgtt(struct drm_i915_private *dev_priv,
 			  int (*func)(struct drm_i915_private *i915,
 				      struct i915_address_space *vm,
@@ -953,6 +1031,11 @@ static int igt_ppgtt_shrink(void *arg)
 	return exercise_ppgtt(arg, shrink_hole);
 }
 
+static int igt_ppgtt_shrink_boom(void *arg)
+{
+	return exercise_ppgtt(arg, shrink_boom);
+}
+
 static int sort_holes(void *priv, struct list_head *A, struct list_head *B)
 {
 	struct drm_mm_node *a = list_entry(A, typeof(*a), hole_stack);
@@ -1052,35 +1135,38 @@ static int igt_ggtt_page(void *arg)
 
 	memset(&tmp, 0, sizeof(tmp));
 	err = drm_mm_insert_node_in_range(&ggtt->base.mm, &tmp,
-					  1024 * PAGE_SIZE, 0,
+					  count * PAGE_SIZE, 0,
 					  I915_COLOR_UNEVICTABLE,
 					  0, ggtt->mappable_end,
 					  DRM_MM_INSERT_LOW);
 	if (err)
 		goto out_unpin;
 
+	intel_runtime_pm_get(i915);
+
+	for (n = 0; n < count; n++) {
+		u64 offset = tmp.start + n * PAGE_SIZE;
+
+		ggtt->base.insert_page(&ggtt->base,
+				       i915_gem_object_get_dma_address(obj, 0),
+				       offset, I915_CACHE_NONE, 0);
+	}
+
 	order = i915_random_order(count, &prng);
 	if (!order) {
 		err = -ENOMEM;
 		goto out_remove;
 	}
 
-	intel_runtime_pm_get(i915);
 	for (n = 0; n < count; n++) {
 		u64 offset = tmp.start + order[n] * PAGE_SIZE;
 		u32 __iomem *vaddr;
 
-		ggtt->base.insert_page(&ggtt->base,
-				       i915_gem_object_get_dma_address(obj, 0),
-				       offset, I915_CACHE_NONE, 0);
-
 		vaddr = io_mapping_map_atomic_wc(&ggtt->iomap, offset);
 		iowrite32(n, vaddr + n);
 		io_mapping_unmap_atomic(vaddr);
-
-		wmb();
-		ggtt->base.clear_range(&ggtt->base, offset, PAGE_SIZE);
 	}
+	i915_gem_flush_ggtt_writes(i915);
 
 	i915_random_reorder(order, count, &prng);
 	for (n = 0; n < count; n++) {
@@ -1088,16 +1174,10 @@ static int igt_ggtt_page(void *arg)
 		u32 __iomem *vaddr;
 		u32 val;
 
-		ggtt->base.insert_page(&ggtt->base,
-				       i915_gem_object_get_dma_address(obj, 0),
-				       offset, I915_CACHE_NONE, 0);
-
 		vaddr = io_mapping_map_atomic_wc(&ggtt->iomap, offset);
 		val = ioread32(vaddr + n);
 		io_mapping_unmap_atomic(vaddr);
 
-		ggtt->base.clear_range(&ggtt->base, offset, PAGE_SIZE);
-
 		if (val != n) {
 			pr_err("insert page failed: found %d, expected %d\n",
 			       val, n);
@@ -1105,10 +1185,11 @@ static int igt_ggtt_page(void *arg)
 			break;
 		}
 	}
-	intel_runtime_pm_put(i915);
 
 	kfree(order);
 out_remove:
+	ggtt->base.clear_range(&ggtt->base, tmp.start, tmp.size);
+	intel_runtime_pm_put(i915);
 	drm_mm_remove_node(&tmp);
 out_unpin:
 	i915_gem_object_unpin_pages(obj);
@@ -1579,6 +1660,7 @@ int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 		SUBTEST(igt_ppgtt_pot),
 		SUBTEST(igt_ppgtt_fill),
 		SUBTEST(igt_ppgtt_shrink),
+		SUBTEST(igt_ppgtt_shrink_boom),
 		SUBTEST(igt_ggtt_lowlevel),
 		SUBTEST(igt_ggtt_drunk),
 		SUBTEST(igt_ggtt_walk),
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
index f32aa6bb79e2..3c64815e910b 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c
@@ -212,8 +212,11 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
 		return -EINTR;
 
 	err = i915_gem_object_set_tiling(obj, tile->tiling, tile->stride);
-	if (err)
+	if (err) {
+		pr_err("Failed to set tiling mode=%u, stride=%u, err=%d\n",
+		       tile->tiling, tile->stride, err);
 		return err;
+	}
 
 	GEM_BUG_ON(i915_gem_object_get_tiling(obj) != tile->tiling);
 	GEM_BUG_ON(i915_gem_object_get_stride(obj) != tile->stride);
@@ -230,13 +233,16 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
 		GEM_BUG_ON(view.partial.size > nreal);
 
 		err = i915_gem_object_set_to_gtt_domain(obj, true);
-		if (err)
+		if (err) {
+			pr_err("Failed to flush to GTT write domain; err=%d\n",
+			       err);
 			return err;
+		}
 
 		vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
 		if (IS_ERR(vma)) {
-			pr_err("Failed to pin partial view: offset=%lu\n",
-			       page);
+			pr_err("Failed to pin partial view: offset=%lu; err=%d\n",
+			       page, (int)PTR_ERR(vma));
 			return PTR_ERR(vma);
 		}
 
@@ -246,8 +252,8 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
 		io = i915_vma_pin_iomap(vma);
 		i915_vma_unpin(vma);
 		if (IS_ERR(io)) {
-			pr_err("Failed to iomap partial view: offset=%lu\n",
-			       page);
+			pr_err("Failed to iomap partial view: offset=%lu; err=%d\n",
+			       page, (int)PTR_ERR(io));
 			return PTR_ERR(io);
 		}
 
diff --git a/drivers/gpu/drm/i915/selftests/i915_random.c b/drivers/gpu/drm/i915/selftests/i915_random.c
index 2088ae57aa89..1f415ce47018 100644
--- a/drivers/gpu/drm/i915/selftests/i915_random.c
+++ b/drivers/gpu/drm/i915/selftests/i915_random.c
@@ -57,7 +57,8 @@ unsigned int *i915_random_order(unsigned int count, struct rnd_state *state)
 {
 	unsigned int *order, i;
 
-	order = kmalloc_array(count, sizeof(*order), GFP_KERNEL | __GFP_NOWARN);
+	order = kmalloc_array(count, sizeof(*order),
+			      GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
 	if (!order)
 		return order;
 
diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c
index ea01d0fe3ace..570e325af93e 100644
--- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c
+++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c
@@ -606,6 +606,139 @@ static int test_timer(void *arg)
 	return -EINVAL;
 }
 
+static const char *mock_name(struct dma_fence *fence)
+{
+	return "mock";
+}
+
+static bool mock_enable_signaling(struct dma_fence *fence)
+{
+	return true;
+}
+
+static const struct dma_fence_ops mock_fence_ops = {
+	.get_driver_name = mock_name,
+	.get_timeline_name = mock_name,
+	.enable_signaling = mock_enable_signaling,
+	.wait = dma_fence_default_wait,
+	.release = dma_fence_free,
+};
+
+static DEFINE_SPINLOCK(mock_fence_lock);
+
+static struct dma_fence *alloc_dma_fence(void)
+{
+	struct dma_fence *dma;
+
+	dma = kmalloc(sizeof(*dma), GFP_KERNEL);
+	if (dma)
+		dma_fence_init(dma, &mock_fence_ops, &mock_fence_lock, 0, 0);
+
+	return dma;
+}
+
+static struct i915_sw_fence *
+wrap_dma_fence(struct dma_fence *dma, unsigned long delay)
+{
+	struct i915_sw_fence *fence;
+	int err;
+
+	fence = alloc_fence();
+	if (!fence)
+		return ERR_PTR(-ENOMEM);
+
+	err = i915_sw_fence_await_dma_fence(fence, dma, delay, GFP_NOWAIT);
+	i915_sw_fence_commit(fence);
+	if (err < 0) {
+		free_fence(fence);
+		return ERR_PTR(err);
+	}
+
+	return fence;
+}
+
+static int test_dma_fence(void *arg)
+{
+	struct i915_sw_fence *timeout = NULL, *not = NULL;
+	unsigned long delay = i915_selftest.timeout_jiffies;
+	unsigned long end, sleep;
+	struct dma_fence *dma;
+	int err;
+
+	dma = alloc_dma_fence();
+	if (!dma)
+		return -ENOMEM;
+
+	timeout = wrap_dma_fence(dma, delay);
+	if (IS_ERR(timeout)) {
+		err = PTR_ERR(timeout);
+		goto err;
+	}
+
+	not = wrap_dma_fence(dma, 0);
+	if (IS_ERR(not)) {
+		err = PTR_ERR(not);
+		goto err;
+	}
+
+	err = -EINVAL;
+	if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) {
+		pr_err("Fences immediately signaled\n");
+		goto err;
+	}
+
+	/* We round the timeout for the fence up to the next second */
+	end = round_jiffies_up(jiffies + delay);
+
+	sleep = jiffies_to_usecs(delay) / 3;
+	usleep_range(sleep, 2 * sleep);
+	if (time_after(jiffies, end)) {
+		pr_debug("Slept too long, delay=%lu, (target=%lu, now=%lu) skipping\n",
+			 delay, end, jiffies);
+		goto skip;
+	}
+
+	if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) {
+		pr_err("Fences signaled too early\n");
+		goto err;
+	}
+
+	if (!wait_event_timeout(timeout->wait,
+				i915_sw_fence_done(timeout),
+				2 * (end - jiffies) + 1)) {
+		pr_err("Timeout fence unsignaled!\n");
+		goto err;
+	}
+
+	if (i915_sw_fence_done(not)) {
+		pr_err("No timeout fence signaled!\n");
+		goto err;
+	}
+
+skip:
+	dma_fence_signal(dma);
+
+	if (!i915_sw_fence_done(timeout) || !i915_sw_fence_done(not)) {
+		pr_err("Fences unsignaled\n");
+		goto err;
+	}
+
+	free_fence(not);
+	free_fence(timeout);
+	dma_fence_put(dma);
+
+	return 0;
+
+err:
+	dma_fence_signal(dma);
+	if (!IS_ERR_OR_NULL(timeout))
+		free_fence(timeout);
+	if (!IS_ERR_OR_NULL(not))
+		free_fence(not);
+	dma_fence_put(dma);
+	return err;
+}
+
 int i915_sw_fence_mock_selftests(void)
 {
 	static const struct i915_subtest tests[] = {
@@ -618,6 +751,7 @@ int i915_sw_fence_mock_selftests(void)
 		SUBTEST(test_chain),
 		SUBTEST(test_ipc),
 		SUBTEST(test_timer),
+		SUBTEST(test_dma_fence),
 	};
 
 	return i915_subtests(tests, NULL);
diff --git a/drivers/gpu/drm/i915/selftests/intel_guc.c b/drivers/gpu/drm/i915/selftests/intel_guc.c
index 3f9016466dea..fb74e2cf8a0a 100644
--- a/drivers/gpu/drm/i915/selftests/intel_guc.c
+++ b/drivers/gpu/drm/i915/selftests/intel_guc.c
@@ -87,7 +87,7 @@ static int validate_client(struct intel_guc_client *client,
 
 static bool client_doorbell_in_sync(struct intel_guc_client *client)
 {
-	return doorbell_ok(client->guc, client->doorbell_id);
+	return !client || doorbell_ok(client->guc, client->doorbell_id);
 }
 
 /*
@@ -137,7 +137,6 @@ static int igt_guc_clients(void *args)
 		goto unlock;
 	}
 	GEM_BUG_ON(!guc->execbuf_client);
-	GEM_BUG_ON(!guc->preempt_client);
 
 	err = validate_client(guc->execbuf_client,
 			      GUC_CLIENT_PRIORITY_KMD_NORMAL, false);
@@ -146,16 +145,18 @@ static int igt_guc_clients(void *args)
 		goto out;
 	}
 
-	err = validate_client(guc->preempt_client,
-			      GUC_CLIENT_PRIORITY_KMD_HIGH, true);
-	if (err) {
-		pr_err("preempt client validation failed\n");
-		goto out;
+	if (guc->preempt_client) {
+		err = validate_client(guc->preempt_client,
+				      GUC_CLIENT_PRIORITY_KMD_HIGH, true);
+		if (err) {
+			pr_err("preempt client validation failed\n");
+			goto out;
+		}
 	}
 
 	/* each client should now have reserved a doorbell */
 	if (!has_doorbell(guc->execbuf_client) ||
-	    !has_doorbell(guc->preempt_client)) {
+	    (guc->preempt_client && !has_doorbell(guc->preempt_client))) {
 		pr_err("guc_clients_create didn't reserve doorbells\n");
 		err = -EINVAL;
 		goto out;
@@ -224,7 +225,8 @@ static int igt_guc_clients(void *args)
 	 * clients during unload.
 	 */
 	destroy_doorbell(guc->execbuf_client);
-	destroy_doorbell(guc->preempt_client);
+	if (guc->preempt_client)
+		destroy_doorbell(guc->preempt_client);
 	guc_clients_destroy(guc);
 	guc_clients_create(guc);
 	guc_clients_doorbell_init(guc);
diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c
index d1f91a533afa..d1d2c2456f69 100644
--- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c
+++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c
@@ -33,6 +33,7 @@ struct hang {
 	struct drm_i915_private *i915;
 	struct drm_i915_gem_object *hws;
 	struct drm_i915_gem_object *obj;
+	struct i915_gem_context *ctx;
 	u32 *seqno;
 	u32 *batch;
 };
@@ -45,9 +46,15 @@ static int hang_init(struct hang *h, struct drm_i915_private *i915)
 	memset(h, 0, sizeof(*h));
 	h->i915 = i915;
 
+	h->ctx = kernel_context(i915);
+	if (IS_ERR(h->ctx))
+		return PTR_ERR(h->ctx);
+
 	h->hws = i915_gem_object_create_internal(i915, PAGE_SIZE);
-	if (IS_ERR(h->hws))
-		return PTR_ERR(h->hws);
+	if (IS_ERR(h->hws)) {
+		err = PTR_ERR(h->hws);
+		goto err_ctx;
+	}
 
 	h->obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
 	if (IS_ERR(h->obj)) {
@@ -79,6 +86,8 @@ static int hang_init(struct hang *h, struct drm_i915_private *i915)
 	i915_gem_object_put(h->obj);
 err_hws:
 	i915_gem_object_put(h->hws);
+err_ctx:
+	kernel_context_close(h->ctx);
 	return err;
 }
 
@@ -196,9 +205,7 @@ static int emit_recurse_batch(struct hang *h,
 }
 
 static struct drm_i915_gem_request *
-hang_create_request(struct hang *h,
-		    struct intel_engine_cs *engine,
-		    struct i915_gem_context *ctx)
+hang_create_request(struct hang *h, struct intel_engine_cs *engine)
 {
 	struct drm_i915_gem_request *rq;
 	int err;
@@ -225,7 +232,7 @@ hang_create_request(struct hang *h,
 		h->batch = vaddr;
 	}
 
-	rq = i915_gem_request_alloc(engine, ctx);
+	rq = i915_gem_request_alloc(engine, h->ctx);
 	if (IS_ERR(rq))
 		return rq;
 
@@ -244,6 +251,58 @@ static u32 hws_seqno(const struct hang *h,
 	return READ_ONCE(h->seqno[rq->fence.context % (PAGE_SIZE/sizeof(u32))]);
 }
 
+struct wedge_me {
+	struct delayed_work work;
+	struct drm_i915_private *i915;
+	const void *symbol;
+};
+
+static void wedge_me(struct work_struct *work)
+{
+	struct wedge_me *w = container_of(work, typeof(*w), work.work);
+
+	pr_err("%pS timed out, cancelling all further testing.\n",
+	       w->symbol);
+	i915_gem_set_wedged(w->i915);
+}
+
+static void __init_wedge(struct wedge_me *w,
+			 struct drm_i915_private *i915,
+			 long timeout,
+			 const void *symbol)
+{
+	w->i915 = i915;
+	w->symbol = symbol;
+
+	INIT_DELAYED_WORK_ONSTACK(&w->work, wedge_me);
+	schedule_delayed_work(&w->work, timeout);
+}
+
+static void __fini_wedge(struct wedge_me *w)
+{
+	cancel_delayed_work_sync(&w->work);
+	destroy_delayed_work_on_stack(&w->work);
+	w->i915 = NULL;
+}
+
+#define wedge_on_timeout(W, DEV, TIMEOUT)				\
+	for (__init_wedge((W), (DEV), (TIMEOUT), __builtin_return_address(0)); \
+	     (W)->i915;							\
+	     __fini_wedge((W)))
+
+static noinline int
+flush_test(struct drm_i915_private *i915, unsigned int flags)
+{
+	struct wedge_me w;
+
+	cond_resched();
+
+	wedge_on_timeout(&w, i915, HZ)
+		i915_gem_wait_for_idle(i915, flags);
+
+	return i915_terminally_wedged(&i915->gpu_error) ? -EIO : 0;
+}
+
 static void hang_fini(struct hang *h)
 {
 	*h->batch = MI_BATCH_BUFFER_END;
@@ -255,7 +314,9 @@ static void hang_fini(struct hang *h)
 	i915_gem_object_unpin_map(h->hws);
 	i915_gem_object_put(h->hws);
 
-	i915_gem_wait_for_idle(h->i915, I915_WAIT_LOCKED);
+	kernel_context_close(h->ctx);
+
+	flush_test(h->i915, I915_WAIT_LOCKED);
 }
 
 static bool wait_for_hang(struct hang *h, struct drm_i915_gem_request *rq)
@@ -290,7 +351,7 @@ static int igt_hang_sanitycheck(void *arg)
 		if (!intel_engine_can_store_dword(engine))
 			continue;
 
-		rq = hang_create_request(&h, engine, i915->kernel_context);
+		rq = hang_create_request(&h, engine);
 		if (IS_ERR(rq)) {
 			err = PTR_ERR(rq);
 			pr_err("Failed to create request for %s, err=%d\n",
@@ -427,8 +488,7 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active)
 				struct drm_i915_gem_request *rq;
 
 				mutex_lock(&i915->drm.struct_mutex);
-				rq = hang_create_request(&h, engine,
-							 i915->kernel_context);
+				rq = hang_create_request(&h, engine);
 				if (IS_ERR(rq)) {
 					err = PTR_ERR(rq);
 					mutex_unlock(&i915->drm.struct_mutex);
@@ -487,7 +547,9 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active)
 		if (err)
 			break;
 
-		cond_resched();
+		err = flush_test(i915, 0);
+		if (err)
+			break;
 	}
 
 	if (i915_terminally_wedged(&i915->gpu_error))
@@ -633,8 +695,7 @@ static int __igt_reset_engine_others(struct drm_i915_private *i915,
 				struct drm_i915_gem_request *rq;
 
 				mutex_lock(&i915->drm.struct_mutex);
-				rq = hang_create_request(&h, engine,
-							 i915->kernel_context);
+				rq = hang_create_request(&h, engine);
 				if (IS_ERR(rq)) {
 					err = PTR_ERR(rq);
 					mutex_unlock(&i915->drm.struct_mutex);
@@ -726,7 +787,9 @@ static int __igt_reset_engine_others(struct drm_i915_private *i915,
 		if (err)
 			break;
 
-		cond_resched();
+		err = flush_test(i915, 0);
+		if (err)
+			break;
 	}
 
 	if (i915_terminally_wedged(&i915->gpu_error))
@@ -787,7 +850,7 @@ static int igt_wait_reset(void *arg)
 	if (err)
 		goto unlock;
 
-	rq = hang_create_request(&h, i915->engine[RCS], i915->kernel_context);
+	rq = hang_create_request(&h, i915->engine[RCS]);
 	if (IS_ERR(rq)) {
 		err = PTR_ERR(rq);
 		goto fini;
@@ -866,7 +929,7 @@ static int igt_reset_queue(void *arg)
 		if (!intel_engine_can_store_dword(engine))
 			continue;
 
-		prev = hang_create_request(&h, engine, i915->kernel_context);
+		prev = hang_create_request(&h, engine);
 		if (IS_ERR(prev)) {
 			err = PTR_ERR(prev);
 			goto fini;
@@ -880,9 +943,7 @@ static int igt_reset_queue(void *arg)
 			struct drm_i915_gem_request *rq;
 			unsigned int reset_count;
 
-			rq = hang_create_request(&h,
-						 engine,
-						 i915->kernel_context);
+			rq = hang_create_request(&h, engine);
 			if (IS_ERR(rq)) {
 				err = PTR_ERR(rq);
 				goto fini;
@@ -952,6 +1013,10 @@ static int igt_reset_queue(void *arg)
 		i915_gem_chipset_flush(i915);
 
 		i915_gem_request_put(prev);
+
+		err = flush_test(i915, I915_WAIT_LOCKED);
+		if (err)
+			break;
 	}
 
 fini:
@@ -989,7 +1054,7 @@ static int igt_handle_error(void *arg)
 	if (err)
 		goto err_unlock;
 
-	rq = hang_create_request(&h, engine, i915->kernel_context);
+	rq = hang_create_request(&h, engine);
 	if (IS_ERR(rq)) {
 		err = PTR_ERR(rq);
 		goto err_fini;
diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c
index bbf80d42e793..501becc47c0c 100644
--- a/drivers/gpu/drm/i915/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/selftests/mock_context.c
@@ -92,3 +92,14 @@ live_context(struct drm_i915_private *i915, struct drm_file *file)
 
 	return i915_gem_create_context(i915, file->driver_priv);
 }
+
+struct i915_gem_context *
+kernel_context(struct drm_i915_private *i915)
+{
+	return i915_gem_context_create_kernel(i915, I915_PRIORITY_NORMAL);
+}
+
+void kernel_context_close(struct i915_gem_context *ctx)
+{
+	context_close(ctx);
+}
diff --git a/drivers/gpu/drm/i915/selftests/mock_context.h b/drivers/gpu/drm/i915/selftests/mock_context.h
index 2f432c03d413..29b9d60a158b 100644
--- a/drivers/gpu/drm/i915/selftests/mock_context.h
+++ b/drivers/gpu/drm/i915/selftests/mock_context.h
@@ -36,4 +36,7 @@ void mock_context_close(struct i915_gem_context *ctx);
 struct i915_gem_context *
 live_context(struct drm_i915_private *i915, struct drm_file *file);
 
+struct i915_gem_context *kernel_context(struct drm_i915_private *i915);
+void kernel_context_close(struct i915_gem_context *ctx);
+
 #endif /* !__MOCK_CONTEXT_H */
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index 1bc61f3f76fc..3175db70cc6e 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -243,16 +243,10 @@ struct drm_i915_private *mock_gem_device(void)
 	if (!i915->kernel_context)
 		goto err_engine;
 
-	i915->preempt_context = mock_context(i915, NULL);
-	if (!i915->preempt_context)
-		goto err_kernel_context;
-
 	WARN_ON(i915_gemfs_init(i915));
 
 	return i915;
 
-err_kernel_context:
-	i915_gem_context_put(i915->kernel_context);
 err_engine:
 	for_each_engine(engine, i915, id)
 		mock_engine_free(engine);
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 57ed56d8623f..150628293c51 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -351,7 +351,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
 	struct drm_framebuffer *old_fb = old_state->fb;
 	unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
 	bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 	int hsub, vsub;
 	int ret;
 
@@ -367,10 +367,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
 	if (WARN_ON(!crtc_state))
 		return -EINVAL;
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
+
 	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  DRM_PLANE_HELPER_NO_SCALING,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 5ef898b93d8d..b5c6eec9a584 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -108,8 +108,9 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
 	if (IS_ERR(crtc_state))
 		return PTR_ERR(crtc_state);
 
-	clip.x2 = crtc_state->mode.hdisplay;
-	clip.y2 = crtc_state->mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						   DRM_PLANE_HELPER_NO_SCALING,
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index d0a6ac8390f3..3801bee1f9e6 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -58,8 +58,9 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
 	if (IS_ERR(crtc_state))
 		return PTR_ERR(crtc_state);
 
-	clip.x2 = crtc_state->mode.hdisplay;
-	clip.y2 = crtc_state->mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						   DRM_PLANE_HELPER_NO_SCALING,
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 68e5d9c94475..fb50a9ddaae8 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1620,8 +1620,8 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
 			return MODE_VIRTUAL_X;
 		if (mode->vdisplay > 1024)
 			return MODE_VIRTUAL_Y;
-		if (mga_vga_calculate_mode_bandwidth(mode,
-			bpp > (31877 * 1024)))
+		if (mga_vga_calculate_mode_bandwidth(mode, bpp) >
+		    (31877 * 1024))
 			return MODE_BANDWIDTH;
 	} else if (mdev->type == G200_EV &&
 		(mga_vga_calculate_mode_bandwidth(mode, bpp)
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 99d39b2aefa6..38cbde971b48 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -28,6 +28,19 @@ config DRM_MSM_REGISTER_LOGGING
 	  that can be parsed by envytools demsm tool.  If enabled, register
 	  logging can be switched on via msm.reglog=y module param.
 
+config DRM_MSM_GPU_SUDO
+	bool "Enable SUDO flag on submits"
+	depends on DRM_MSM && EXPERT
+	default n
+	help
+	  Enable userspace that has CAP_SYS_RAWIO to submit GPU commands
+	  that are run from RB instead of IB1.  This essentially gives
+	  userspace kernel level access, but is useful for firmware
+	  debugging.
+
+	  Only use this if you are a driver developer.  This should *not*
+	  be enabled for production kernels.  If unsure, say N.
+
 config DRM_MSM_HDMI_HDCP
 	bool "Enable HDMI HDCP support in MSM DRM driver"
 	depends on DRM_MSM && QCOM_SCM
@@ -81,3 +94,10 @@ config DRM_MSM_DSI_14NM_PHY
 	default y
 	help
 	  Choose this option if DSI PHY on 8996 is used on the platform.
+
+config DRM_MSM_DSI_10NM_PHY
+	bool "Enable DSI 10nm PHY driver in MSM DRM (used by SDM845)"
+	depends on DRM_MSM_DSI
+	default y
+	help
+	  Choose this option if DSI PHY on SDM845 is used on the platform.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 92b3844202d2..cd40c050b2d7 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -25,26 +25,26 @@ msm-y := \
 	edp/edp_connector.o \
 	edp/edp_ctrl.o \
 	edp/edp_phy.o \
-	mdp/mdp_format.o \
-	mdp/mdp_kms.o \
-	mdp/mdp4/mdp4_crtc.o \
-	mdp/mdp4/mdp4_dtv_encoder.o \
-	mdp/mdp4/mdp4_lcdc_encoder.o \
-	mdp/mdp4/mdp4_lvds_connector.o \
-	mdp/mdp4/mdp4_irq.o \
-	mdp/mdp4/mdp4_kms.o \
-	mdp/mdp4/mdp4_plane.o \
-	mdp/mdp5/mdp5_cfg.o \
-	mdp/mdp5/mdp5_ctl.o \
-	mdp/mdp5/mdp5_crtc.o \
-	mdp/mdp5/mdp5_encoder.o \
-	mdp/mdp5/mdp5_irq.o \
-	mdp/mdp5/mdp5_mdss.o \
-	mdp/mdp5/mdp5_kms.o \
-	mdp/mdp5/mdp5_pipe.o \
-	mdp/mdp5/mdp5_mixer.o \
-	mdp/mdp5/mdp5_plane.o \
-	mdp/mdp5/mdp5_smp.o \
+	disp/mdp_format.o \
+	disp/mdp_kms.o \
+	disp/mdp4/mdp4_crtc.o \
+	disp/mdp4/mdp4_dtv_encoder.o \
+	disp/mdp4/mdp4_lcdc_encoder.o \
+	disp/mdp4/mdp4_lvds_connector.o \
+	disp/mdp4/mdp4_irq.o \
+	disp/mdp4/mdp4_kms.o \
+	disp/mdp4/mdp4_plane.o \
+	disp/mdp5/mdp5_cfg.o \
+	disp/mdp5/mdp5_ctl.o \
+	disp/mdp5/mdp5_crtc.o \
+	disp/mdp5/mdp5_encoder.o \
+	disp/mdp5/mdp5_irq.o \
+	disp/mdp5/mdp5_mdss.o \
+	disp/mdp5/mdp5_kms.o \
+	disp/mdp5/mdp5_pipe.o \
+	disp/mdp5/mdp5_mixer.o \
+	disp/mdp5/mdp5_plane.o \
+	disp/mdp5/mdp5_smp.o \
 	msm_atomic.o \
 	msm_debugfs.o \
 	msm_drv.o \
@@ -62,31 +62,35 @@ msm-y := \
 	msm_ringbuffer.o \
 	msm_submitqueue.o
 
+msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o
+
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
-msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
+msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o
 msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o
 msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_phy_8996.o
 
 msm-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o
 
 msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
-			mdp/mdp4/mdp4_dsi_encoder.o \
+			disp/mdp4/mdp4_dsi_encoder.o \
 			dsi/dsi_cfg.o \
 			dsi/dsi_host.o \
 			dsi/dsi_manager.o \
 			dsi/phy/dsi_phy.o \
-			mdp/mdp5/mdp5_cmd_encoder.o
+			disp/mdp5/mdp5_cmd_encoder.o
 
 msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o
 msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o
 msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o
 msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/phy/dsi_phy_14nm.o
+msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/phy/dsi_phy_10nm.o
 
 ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y)
 msm-y += dsi/pll/dsi_pll.o
 msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o
 msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o
 msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/pll/dsi_pll_14nm.o
+msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/pll/dsi_pll_10nm.o
 endif
 
 obj-$(CONFIG_DRM_MSM)	+= msm.o
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index 4baef2738178..3ebbeb3a9b68 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -35,6 +35,7 @@
 	 A3XX_INT0_CP_RB_INT |             \
 	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \
 	 A3XX_INT0_CP_AHB_ERROR_HALT |     \
+	 A3XX_INT0_CACHE_FLUSH_TS |        \
 	 A3XX_INT0_UCHE_OOB_ACCESS)
 
 extern bool hang_debug;
@@ -256,8 +257,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
 	 */
 
 	/* Load PM4: */
-	ptr = (uint32_t *)(adreno_gpu->pm4->data);
-	len = adreno_gpu->pm4->size / 4;
+	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
+	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
 	DBG("loading PM4 ucode version: %x", ptr[1]);
 
 	gpu_write(gpu, REG_AXXX_CP_DEBUG,
@@ -268,8 +269,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
 		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
 
 	/* Load PFP: */
-	ptr = (uint32_t *)(adreno_gpu->pfp->data);
-	len = adreno_gpu->pfp->size / 4;
+	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
+	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
 	DBG("loading PFP ucode version: %x", ptr[5]);
 
 	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index 8199a4b9f2fa..16d3d596638e 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -27,6 +27,7 @@
 	 A4XX_INT0_CP_RB_INT |             \
 	 A4XX_INT0_CP_REG_PROTECT_FAULT |  \
 	 A4XX_INT0_CP_AHB_ERROR_HALT |     \
+	 A4XX_INT0_CACHE_FLUSH_TS |        \
 	 A4XX_INT0_UCHE_OOB_ACCESS)
 
 extern bool hang_debug;
@@ -274,16 +275,16 @@ static int a4xx_hw_init(struct msm_gpu *gpu)
 		return ret;
 
 	/* Load PM4: */
-	ptr = (uint32_t *)(adreno_gpu->pm4->data);
-	len = adreno_gpu->pm4->size / 4;
+	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
+	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
 	DBG("loading PM4 ucode version: %u", ptr[0]);
 	gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0);
 	for (i = 1; i < len; i++)
 		gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]);
 
 	/* Load PFP: */
-	ptr = (uint32_t *)(adreno_gpu->pfp->data);
-	len = adreno_gpu->pfp->size / 4;
+	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
+	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
 	DBG("loading PFP ucode version: %u", ptr[0]);
 
 	gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0);
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
new file mode 100644
index 000000000000..059ec7d394d0
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
@@ -0,0 +1,187 @@
+/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include <drm/drm_print.h>
+
+#include "a5xx_gpu.h"
+
+static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
+{
+	int i;
+
+	drm_printf(p, "PFP state:\n");
+
+	for (i = 0; i < 36; i++) {
+		gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
+		drm_printf(p, "  %02x: %08x\n", i,
+			gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
+	}
+
+	return 0;
+}
+
+static int me_print(struct msm_gpu *gpu, struct drm_printer *p)
+{
+	int i;
+
+	drm_printf(p, "ME state:\n");
+
+	for (i = 0; i < 29; i++) {
+		gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
+		drm_printf(p, "  %02x: %08x\n", i,
+			gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
+	}
+
+	return 0;
+}
+
+static int meq_print(struct msm_gpu *gpu, struct drm_printer *p)
+{
+	int i;
+
+	drm_printf(p, "MEQ state:\n");
+	gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
+
+	for (i = 0; i < 64; i++) {
+		drm_printf(p, "  %02x: %08x\n", i,
+			gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
+	}
+
+	return 0;
+}
+
+static int roq_print(struct msm_gpu *gpu, struct drm_printer *p)
+{
+	int i;
+
+	drm_printf(p, "ROQ state:\n");
+	gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
+
+	for (i = 0; i < 512 / 4; i++) {
+		uint32_t val[4];
+		int j;
+		for (j = 0; j < 4; j++)
+			val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
+		drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
+			val[0], val[1], val[2], val[3]);
+	}
+
+	return 0;
+}
+
+static int show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_printer p = drm_seq_file_printer(m);
+	int (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
+		node->info_ent->data;
+
+	return show(priv->gpu, &p);
+}
+
+#define ENT(n) { .name = #n, .show = show, .data = n ##_print }
+static struct drm_info_list a5xx_debugfs_list[] = {
+	ENT(pfp),
+	ENT(me),
+	ENT(meq),
+	ENT(roq),
+};
+
+/* for debugfs files that can be written to, we can't use drm helper: */
+static int
+reset_set(void *data, u64 val)
+{
+	struct drm_device *dev = data;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_gpu *gpu = priv->gpu;
+	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EINVAL;
+
+	/* TODO do we care about trying to make sure the GPU is idle?
+	 * Since this is just a debug feature limited to CAP_SYS_ADMIN,
+	 * maybe it is fine to let the user keep both pieces if they
+	 * try to reset an active GPU.
+	 */
+
+	mutex_lock(&dev->struct_mutex);
+
+	release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
+	adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
+
+	release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
+	adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
+
+	if (a5xx_gpu->pm4_bo) {
+		if (a5xx_gpu->pm4_iova)
+			msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace);
+		drm_gem_object_unreference(a5xx_gpu->pm4_bo);
+		a5xx_gpu->pm4_bo = NULL;
+	}
+
+	if (a5xx_gpu->pfp_bo) {
+		if (a5xx_gpu->pfp_iova)
+			msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace);
+		drm_gem_object_unreference(a5xx_gpu->pfp_bo);
+		a5xx_gpu->pfp_bo = NULL;
+	}
+
+	gpu->needs_hw_init = true;
+
+	pm_runtime_get_sync(&gpu->pdev->dev);
+	gpu->funcs->recover(gpu);
+
+	pm_runtime_put_sync(&gpu->pdev->dev);
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
+
+
+int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
+{
+	struct drm_device *dev;
+	struct dentry *ent;
+	int ret;
+
+	if (!minor)
+		return 0;
+
+	dev = minor->dev;
+
+	ret = drm_debugfs_create_files(a5xx_debugfs_list,
+			ARRAY_SIZE(a5xx_debugfs_list),
+			minor->debugfs_root, minor);
+
+	if (ret) {
+		dev_err(dev->dev, "could not install a5xx_debugfs_list\n");
+		return ret;
+	}
+
+	ent = debugfs_create_file("reset", S_IWUGO,
+		minor->debugfs_root,
+		dev, &reset_fops);
+	if (!ent)
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 7e09d44e4a15..d39400e5bc42 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -89,14 +89,14 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname)
 	 */
 	if (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY) {
 		ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID,
-				mem_region, mem_phys, mem_size);
+				mem_region, mem_phys, mem_size, NULL);
 	} else {
 		char newname[strlen("qcom/") + strlen(fwname) + 1];
 
 		sprintf(newname, "qcom/%s", fwname);
 
 		ret = qcom_mdt_load(dev, fw, newname, GPU_PAS_ID,
-				mem_region, mem_phys, mem_size);
+				mem_region, mem_phys, mem_size, NULL);
 	}
 	if (ret)
 		goto out;
@@ -140,6 +140,65 @@ static void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
 		gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr);
 }
 
+static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit,
+	struct msm_file_private *ctx)
+{
+	struct msm_drm_private *priv = gpu->dev->dev_private;
+	struct msm_ringbuffer *ring = submit->ring;
+	struct msm_gem_object *obj;
+	uint32_t *ptr, dwords;
+	unsigned int i;
+
+	for (i = 0; i < submit->nr_cmds; i++) {
+		switch (submit->cmd[i].type) {
+		case MSM_SUBMIT_CMD_IB_TARGET_BUF:
+			break;
+		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
+			if (priv->lastctx == ctx)
+				break;
+		case MSM_SUBMIT_CMD_BUF:
+			/* copy commands into RB: */
+			obj = submit->bos[submit->cmd[i].idx].obj;
+			dwords = submit->cmd[i].size;
+
+			ptr = msm_gem_get_vaddr(&obj->base);
+
+			/* _get_vaddr() shouldn't fail at this point,
+			 * since we've already mapped it once in
+			 * submit_reloc()
+			 */
+			if (WARN_ON(!ptr))
+				return;
+
+			for (i = 0; i < dwords; i++) {
+				/* normally the OUT_PKTn() would wait
+				 * for space for the packet.  But since
+				 * we just OUT_RING() the whole thing,
+				 * need to call adreno_wait_ring()
+				 * ourself:
+				 */
+				adreno_wait_ring(ring, 1);
+				OUT_RING(ring, ptr[i]);
+			}
+
+			msm_gem_put_vaddr(&obj->base);
+
+			break;
+		}
+	}
+
+	a5xx_flush(gpu, ring);
+	a5xx_preempt_trigger(gpu);
+
+	/* we might not necessarily have a cmd from userspace to
+	 * trigger an event to know that submit has completed, so
+	 * do this manually:
+	 */
+	a5xx_idle(gpu, ring);
+	ring->memptrs->fence = submit->seqno;
+	msm_gpu_retire(gpu);
+}
+
 static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 	struct msm_file_private *ctx)
 {
@@ -149,6 +208,12 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 	struct msm_ringbuffer *ring = submit->ring;
 	unsigned int i, ibs = 0;
 
+	if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) {
+		priv->lastctx = NULL;
+		a5xx_submit_in_rb(gpu, submit, ctx);
+		return;
+	}
+
 	OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1);
 	OUT_RING(ring, 0x02);
 
@@ -432,25 +497,6 @@ static int a5xx_preempt_start(struct msm_gpu *gpu)
 	return a5xx_idle(gpu, ring) ? 0 : -EINVAL;
 }
 
-
-static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu,
-		const struct firmware *fw, u64 *iova)
-{
-	struct drm_gem_object *bo;
-	void *ptr;
-
-	ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4,
-		MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova);
-
-	if (IS_ERR(ptr))
-		return ERR_CAST(ptr);
-
-	memcpy(ptr, &fw->data[4], fw->size - 4);
-
-	msm_gem_put_vaddr(bo);
-	return bo;
-}
-
 static int a5xx_ucode_init(struct msm_gpu *gpu)
 {
 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -458,8 +504,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
 	int ret;
 
 	if (!a5xx_gpu->pm4_bo) {
-		a5xx_gpu->pm4_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pm4,
-			&a5xx_gpu->pm4_iova);
+		a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu,
+			adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova);
 
 		if (IS_ERR(a5xx_gpu->pm4_bo)) {
 			ret = PTR_ERR(a5xx_gpu->pm4_bo);
@@ -471,8 +517,8 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
 	}
 
 	if (!a5xx_gpu->pfp_bo) {
-		a5xx_gpu->pfp_bo = a5xx_ucode_load_bo(gpu, adreno_gpu->pfp,
-			&a5xx_gpu->pfp_iova);
+		a5xx_gpu->pfp_bo = adreno_fw_create_bo(gpu,
+			adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova);
 
 		if (IS_ERR(a5xx_gpu->pfp_bo)) {
 			ret = PTR_ERR(a5xx_gpu->pfp_bo);
@@ -793,19 +839,19 @@ static void a5xx_destroy(struct msm_gpu *gpu)
 	if (a5xx_gpu->pm4_bo) {
 		if (a5xx_gpu->pm4_iova)
 			msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace);
-		drm_gem_object_unreference_unlocked(a5xx_gpu->pm4_bo);
+		drm_gem_object_put_unlocked(a5xx_gpu->pm4_bo);
 	}
 
 	if (a5xx_gpu->pfp_bo) {
 		if (a5xx_gpu->pfp_iova)
 			msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace);
-		drm_gem_object_unreference_unlocked(a5xx_gpu->pfp_bo);
+		drm_gem_object_put_unlocked(a5xx_gpu->pfp_bo);
 	}
 
 	if (a5xx_gpu->gpmu_bo) {
 		if (a5xx_gpu->gpmu_iova)
 			msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace);
-		drm_gem_object_unreference_unlocked(a5xx_gpu->gpmu_bo);
+		drm_gem_object_put_unlocked(a5xx_gpu->gpmu_bo);
 	}
 
 	adreno_gpu_cleanup(adreno_gpu);
@@ -1195,6 +1241,7 @@ static const struct adreno_gpu_funcs funcs = {
 		.destroy = a5xx_destroy,
 #ifdef CONFIG_DEBUG_FS
 		.show = a5xx_show,
+		.debugfs_init = a5xx_debugfs_init,
 #endif
 		.gpu_busy = a5xx_gpu_busy,
 	},
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
index 6fb8c2f9b9e4..7d71860c4bee 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
@@ -49,6 +49,10 @@ struct a5xx_gpu {
 
 #define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
 
+#ifdef CONFIG_DEBUG_FS
+int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor);
+#endif
+
 /*
  * In order to do lockless preemption we use a simple state machine to progress
  * through the process.
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c
index 4e4d965fd9ab..e9c0e56dbec0 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_power.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c
@@ -261,7 +261,6 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
 	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
 	struct drm_device *drm = gpu->dev;
-	const struct firmware *fw;
 	uint32_t dwords = 0, offset = 0, bosize;
 	unsigned int *data, *ptr, *cmds;
 	unsigned int cmds_size;
@@ -269,15 +268,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
 	if (a5xx_gpu->gpmu_bo)
 		return;
 
-	/* Get the firmware */
-	fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->gpmufw);
-	if (IS_ERR(fw)) {
-		DRM_ERROR("%s: Could not get GPMU firmware. GPMU will not be active\n",
-			gpu->name);
-		return;
-	}
-
-	data = (unsigned int *) fw->data;
+	data = (unsigned int *) adreno_gpu->fw[ADRENO_FW_GPMU]->data;
 
 	/*
 	 * The first dword is the size of the remaining data in dwords. Use it
@@ -285,12 +276,14 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
 	 * the firmware that we read
 	 */
 
-	if (fw->size < 8 || (data[0] < 2) || (data[0] >= (fw->size >> 2)))
-		goto out;
+	if (adreno_gpu->fw[ADRENO_FW_GPMU]->size < 8 ||
+		(data[0] < 2) || (data[0] >=
+			(adreno_gpu->fw[ADRENO_FW_GPMU]->size >> 2)))
+		return;
 
 	/* The second dword is an ID - look for 2 (GPMU_FIRMWARE_ID) */
 	if (data[1] != 2)
-		goto out;
+		return;
 
 	cmds = data + data[2] + 3;
 	cmds_size = data[0] - data[2] - 2;
@@ -325,8 +318,7 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
 	msm_gem_put_vaddr(a5xx_gpu->gpmu_bo);
 	a5xx_gpu->gpmu_dwords = dwords;
 
-	goto out;
-
+	return;
 err:
 	if (a5xx_gpu->gpmu_iova)
 		msm_gem_put_iova(a5xx_gpu->gpmu_bo, gpu->aspace);
@@ -336,8 +328,4 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
 	a5xx_gpu->gpmu_bo = NULL;
 	a5xx_gpu->gpmu_iova = 0;
 	a5xx_gpu->gpmu_dwords = 0;
-
-out:
-	/* No need to keep that firmware laying around anymore */
-	release_firmware(fw);
 }
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 62bdb7316da1..f07d3ec7d77b 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -30,61 +30,75 @@ static const struct adreno_info gpulist[] = {
 		.rev   = ADRENO_REV(3, 0, 5, ANY_ID),
 		.revn  = 305,
 		.name  = "A305",
-		.pm4fw = "a300_pm4.fw",
-		.pfpfw = "a300_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a300_pm4.fw",
+			[ADRENO_FW_PFP] = "a300_pfp.fw",
+		},
 		.gmem  = SZ_256K,
 		.init  = a3xx_gpu_init,
 	}, {
 		.rev   = ADRENO_REV(3, 0, 6, 0),
 		.revn  = 307,        /* because a305c is revn==306 */
 		.name  = "A306",
-		.pm4fw = "a300_pm4.fw",
-		.pfpfw = "a300_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a300_pm4.fw",
+			[ADRENO_FW_PFP] = "a300_pfp.fw",
+		},
 		.gmem  = SZ_128K,
 		.init  = a3xx_gpu_init,
 	}, {
 		.rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
 		.revn  = 320,
 		.name  = "A320",
-		.pm4fw = "a300_pm4.fw",
-		.pfpfw = "a300_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a300_pm4.fw",
+			[ADRENO_FW_PFP] = "a300_pfp.fw",
+		},
 		.gmem  = SZ_512K,
 		.init  = a3xx_gpu_init,
 	}, {
 		.rev   = ADRENO_REV(3, 3, 0, ANY_ID),
 		.revn  = 330,
 		.name  = "A330",
-		.pm4fw = "a330_pm4.fw",
-		.pfpfw = "a330_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a330_pm4.fw",
+			[ADRENO_FW_PFP] = "a330_pfp.fw",
+		},
 		.gmem  = SZ_1M,
 		.init  = a3xx_gpu_init,
 	}, {
 		.rev   = ADRENO_REV(4, 2, 0, ANY_ID),
 		.revn  = 420,
 		.name  = "A420",
-		.pm4fw = "a420_pm4.fw",
-		.pfpfw = "a420_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a420_pm4.fw",
+			[ADRENO_FW_PFP] = "a420_pfp.fw",
+		},
 		.gmem  = (SZ_1M + SZ_512K),
 		.init  = a4xx_gpu_init,
 	}, {
 		.rev   = ADRENO_REV(4, 3, 0, ANY_ID),
 		.revn  = 430,
 		.name  = "A430",
-		.pm4fw = "a420_pm4.fw",
-		.pfpfw = "a420_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a420_pm4.fw",
+			[ADRENO_FW_PFP] = "a420_pfp.fw",
+		},
 		.gmem  = (SZ_1M + SZ_512K),
 		.init  = a4xx_gpu_init,
 	}, {
 		.rev = ADRENO_REV(5, 3, 0, 2),
 		.revn = 530,
 		.name = "A530",
-		.pm4fw = "a530_pm4.fw",
-		.pfpfw = "a530_pfp.fw",
+		.fw = {
+			[ADRENO_FW_PM4] = "a530_pm4.fw",
+			[ADRENO_FW_PFP] = "a530_pfp.fw",
+			[ADRENO_FW_GPMU] = "a530v3_gpmu.fw2",
+		},
 		.gmem = SZ_1M,
 		.quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI |
 			ADRENO_QUIRK_FAULT_DETECT_MASK,
 		.init = a5xx_gpu_init,
-		.gpmufw = "a530v3_gpmu.fw2",
 		.zapfw = "a530_zap.mdt",
 	},
 };
@@ -150,6 +164,12 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
 		return NULL;
 	}
 
+	if (gpu->funcs->debugfs_init) {
+		gpu->funcs->debugfs_init(gpu, dev->primary);
+		gpu->funcs->debugfs_init(gpu, dev->render);
+		gpu->funcs->debugfs_init(gpu, dev->control);
+	}
+
 	return gpu;
 }
 
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index de63ff26a062..17d0506d058c 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -140,27 +140,47 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname)
 
 static int adreno_load_fw(struct adreno_gpu *adreno_gpu)
 {
-	const struct firmware *fw;
+	int i;
 
-	if (adreno_gpu->pm4)
-		return 0;
+	for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) {
+		const struct firmware *fw;
+
+		if (!adreno_gpu->info->fw[i])
+			continue;
+
+		/* Skip if the firmware has already been loaded */
+		if (adreno_gpu->fw[i])
+			continue;
 
-	fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pm4fw);
-	if (IS_ERR(fw))
-		return PTR_ERR(fw);
-	adreno_gpu->pm4 = fw;
+		fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->fw[i]);
+		if (IS_ERR(fw))
+			return PTR_ERR(fw);
 
-	fw = adreno_request_fw(adreno_gpu, adreno_gpu->info->pfpfw);
-	if (IS_ERR(fw)) {
-		release_firmware(adreno_gpu->pm4);
-		adreno_gpu->pm4 = NULL;
-		return PTR_ERR(fw);
+		adreno_gpu->fw[i] = fw;
 	}
-	adreno_gpu->pfp = fw;
 
 	return 0;
 }
 
+struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu,
+		const struct firmware *fw, u64 *iova)
+{
+	struct drm_gem_object *bo;
+	void *ptr;
+
+	ptr = msm_gem_kernel_new_locked(gpu->dev, fw->size - 4,
+		MSM_BO_UNCACHED | MSM_BO_GPU_READONLY, gpu->aspace, &bo, iova);
+
+	if (IS_ERR(ptr))
+		return ERR_CAST(ptr);
+
+	memcpy(ptr, &fw->data[4], fw->size - 4);
+
+	msm_gem_put_vaddr(bo);
+
+	return bo;
+}
+
 int adreno_hw_init(struct msm_gpu *gpu)
 {
 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -293,26 +313,12 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 		OUT_RING(ring, 0x00000000);
 	}
 
+	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
 	OUT_PKT3(ring, CP_EVENT_WRITE, 3);
-	OUT_RING(ring, CACHE_FLUSH_TS);
+	OUT_RING(ring, CACHE_FLUSH_TS | BIT(31));
 	OUT_RING(ring, rbmemptr(ring, fence));
 	OUT_RING(ring, submit->seqno);
 
-	/* we could maybe be clever and only CP_COND_EXEC the interrupt: */
-	OUT_PKT3(ring, CP_INTERRUPT, 1);
-	OUT_RING(ring, 0x80000000);
-
-	/* Workaround for missing irq issue on 8x16/a306.  Unsure if the
-	 * root cause is a platform issue or some a306 quirk, but this
-	 * keeps things humming along:
-	 */
-	if (adreno_is_a306(adreno_gpu)) {
-		OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
-		OUT_RING(ring, 0x00000000);
-		OUT_PKT3(ring, CP_INTERRUPT, 1);
-		OUT_RING(ring, 0x80000000);
-	}
-
 #if 0
 	if (adreno_is_a3xx(adreno_gpu)) {
 		/* Dummy set-constant to trigger context rollover */
@@ -569,8 +575,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
 void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu)
 {
-	release_firmware(adreno_gpu->pm4);
-	release_firmware(adreno_gpu->pfp);
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++)
+		release_firmware(adreno_gpu->fw[i]);
 
 	msm_gpu_cleanup(&adreno_gpu->base);
 }
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 8d3d0a924908..d6b0e7b813f4 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -48,6 +48,13 @@ enum adreno_regs {
 	REG_ADRENO_REGISTER_MAX,
 };
 
+enum {
+	ADRENO_FW_PM4 = 0,
+	ADRENO_FW_PFP = 1,
+	ADRENO_FW_GPMU = 2,
+	ADRENO_FW_MAX,
+};
+
 enum adreno_quirks {
 	ADRENO_QUIRK_TWO_PASS_USE_WFI = 1,
 	ADRENO_QUIRK_FAULT_DETECT_MASK = 2,
@@ -72,8 +79,7 @@ struct adreno_info {
 	struct adreno_rev rev;
 	uint32_t revn;
 	const char *name;
-	const char *pm4fw, *pfpfw;
-	const char *gpmufw;
+	const char *fw[ADRENO_FW_MAX];
 	uint32_t gmem;
 	enum adreno_quirks quirks;
 	struct msm_gpu *(*init)(struct drm_device *dev);
@@ -115,7 +121,7 @@ struct adreno_gpu {
 	} fwloc;
 
 	/* firmware: */
-	const struct firmware *pm4, *pfp;
+	const struct firmware *fw[ADRENO_FW_MAX];
 
 	/*
 	 * Register offsets are different between some GPUs.
@@ -200,6 +206,8 @@ static inline int adreno_is_a530(struct adreno_gpu *gpu)
 int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value);
 const struct firmware *adreno_request_fw(struct adreno_gpu *adreno_gpu,
 		const char *fwname);
+struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu,
+		const struct firmware *fw, u64 *iova);
 int adreno_hw_init(struct msm_gpu *gpu);
 void adreno_recover(struct msm_gpu *gpu);
 void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/disp/mdp4/mdp4.xml.h
new file mode 100644
index 000000000000..576cea30d391
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4.xml.h
@@ -0,0 +1,1174 @@
+#ifndef MDP4_XML
+#define MDP4_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
+
+Copyright (C) 2013-2017 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+enum mdp4_pipe {
+	VG1 = 0,
+	VG2 = 1,
+	RGB1 = 2,
+	RGB2 = 3,
+	RGB3 = 4,
+	VG3 = 5,
+	VG4 = 6,
+};
+
+enum mdp4_mixer {
+	MIXER0 = 0,
+	MIXER1 = 1,
+	MIXER2 = 2,
+};
+
+enum mdp4_intf {
+	INTF_LCDC_DTV = 0,
+	INTF_DSI_VIDEO = 1,
+	INTF_DSI_CMD = 2,
+	INTF_EBI2_TV = 3,
+};
+
+enum mdp4_cursor_format {
+	CURSOR_ARGB = 1,
+	CURSOR_XRGB = 2,
+};
+
+enum mdp4_frame_format {
+	FRAME_LINEAR = 0,
+	FRAME_TILE_ARGB_4X4 = 1,
+	FRAME_TILE_YCBCR_420 = 2,
+};
+
+enum mdp4_scale_unit {
+	SCALE_FIR = 0,
+	SCALE_MN_PHASE = 1,
+	SCALE_PIXEL_RPT = 2,
+};
+
+enum mdp4_dma {
+	DMA_P = 0,
+	DMA_S = 1,
+	DMA_E = 2,
+};
+
+#define MDP4_IRQ_OVERLAY0_DONE					0x00000001
+#define MDP4_IRQ_OVERLAY1_DONE					0x00000002
+#define MDP4_IRQ_DMA_S_DONE					0x00000004
+#define MDP4_IRQ_DMA_E_DONE					0x00000008
+#define MDP4_IRQ_DMA_P_DONE					0x00000010
+#define MDP4_IRQ_VG1_HISTOGRAM					0x00000020
+#define MDP4_IRQ_VG2_HISTOGRAM					0x00000040
+#define MDP4_IRQ_PRIMARY_VSYNC					0x00000080
+#define MDP4_IRQ_PRIMARY_INTF_UDERRUN				0x00000100
+#define MDP4_IRQ_EXTERNAL_VSYNC					0x00000200
+#define MDP4_IRQ_EXTERNAL_INTF_UDERRUN				0x00000400
+#define MDP4_IRQ_PRIMARY_RDPTR					0x00000800
+#define MDP4_IRQ_DMA_P_HISTOGRAM				0x00020000
+#define MDP4_IRQ_DMA_S_HISTOGRAM				0x04000000
+#define MDP4_IRQ_OVERLAY2_DONE					0x40000000
+#define REG_MDP4_VERSION					0x00000000
+#define MDP4_VERSION_MINOR__MASK				0x00ff0000
+#define MDP4_VERSION_MINOR__SHIFT				16
+static inline uint32_t MDP4_VERSION_MINOR(uint32_t val)
+{
+	return ((val) << MDP4_VERSION_MINOR__SHIFT) & MDP4_VERSION_MINOR__MASK;
+}
+#define MDP4_VERSION_MAJOR__MASK				0xff000000
+#define MDP4_VERSION_MAJOR__SHIFT				24
+static inline uint32_t MDP4_VERSION_MAJOR(uint32_t val)
+{
+	return ((val) << MDP4_VERSION_MAJOR__SHIFT) & MDP4_VERSION_MAJOR__MASK;
+}
+
+#define REG_MDP4_OVLP0_KICK					0x00000004
+
+#define REG_MDP4_OVLP1_KICK					0x00000008
+
+#define REG_MDP4_OVLP2_KICK					0x000000d0
+
+#define REG_MDP4_DMA_P_KICK					0x0000000c
+
+#define REG_MDP4_DMA_S_KICK					0x00000010
+
+#define REG_MDP4_DMA_E_KICK					0x00000014
+
+#define REG_MDP4_DISP_STATUS					0x00000018
+
+#define REG_MDP4_DISP_INTF_SEL					0x00000038
+#define MDP4_DISP_INTF_SEL_PRIM__MASK				0x00000003
+#define MDP4_DISP_INTF_SEL_PRIM__SHIFT				0
+static inline uint32_t MDP4_DISP_INTF_SEL_PRIM(enum mdp4_intf val)
+{
+	return ((val) << MDP4_DISP_INTF_SEL_PRIM__SHIFT) & MDP4_DISP_INTF_SEL_PRIM__MASK;
+}
+#define MDP4_DISP_INTF_SEL_SEC__MASK				0x0000000c
+#define MDP4_DISP_INTF_SEL_SEC__SHIFT				2
+static inline uint32_t MDP4_DISP_INTF_SEL_SEC(enum mdp4_intf val)
+{
+	return ((val) << MDP4_DISP_INTF_SEL_SEC__SHIFT) & MDP4_DISP_INTF_SEL_SEC__MASK;
+}
+#define MDP4_DISP_INTF_SEL_EXT__MASK				0x00000030
+#define MDP4_DISP_INTF_SEL_EXT__SHIFT				4
+static inline uint32_t MDP4_DISP_INTF_SEL_EXT(enum mdp4_intf val)
+{
+	return ((val) << MDP4_DISP_INTF_SEL_EXT__SHIFT) & MDP4_DISP_INTF_SEL_EXT__MASK;
+}
+#define MDP4_DISP_INTF_SEL_DSI_VIDEO				0x00000040
+#define MDP4_DISP_INTF_SEL_DSI_CMD				0x00000080
+
+#define REG_MDP4_RESET_STATUS					0x0000003c
+
+#define REG_MDP4_READ_CNFG					0x0000004c
+
+#define REG_MDP4_INTR_ENABLE					0x00000050
+
+#define REG_MDP4_INTR_STATUS					0x00000054
+
+#define REG_MDP4_INTR_CLEAR					0x00000058
+
+#define REG_MDP4_EBI2_LCD0					0x00000060
+
+#define REG_MDP4_EBI2_LCD1					0x00000064
+
+#define REG_MDP4_PORTMAP_MODE					0x00000070
+
+#define REG_MDP4_CS_CONTROLLER0					0x000000c0
+
+#define REG_MDP4_CS_CONTROLLER1					0x000000c4
+
+#define REG_MDP4_LAYERMIXER2_IN_CFG				0x000100f0
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK			0x00000007
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT			0
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE0_MIXER1			0x00000008
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK			0x00000070
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT			4
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE1_MIXER1			0x00000080
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK			0x00000700
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT			8
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE2_MIXER1			0x00000800
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK			0x00007000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT			12
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE3_MIXER1			0x00008000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK			0x00070000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT			16
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE4_MIXER1			0x00080000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK			0x00700000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT			20
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE5_MIXER1			0x00800000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK			0x07000000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT			24
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE6_MIXER1			0x08000000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK			0x70000000
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT			28
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK;
+}
+#define MDP4_LAYERMIXER2_IN_CFG_PIPE7_MIXER1			0x80000000
+
+#define REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD		0x000100fc
+
+#define REG_MDP4_LAYERMIXER_IN_CFG				0x00010100
+#define MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK			0x00000007
+#define MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT			0
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1			0x00000008
+#define MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK			0x00000070
+#define MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT			4
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1			0x00000080
+#define MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK			0x00000700
+#define MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT			8
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1			0x00000800
+#define MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK			0x00007000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT			12
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1			0x00008000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK			0x00070000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT			16
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1			0x00080000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK			0x00700000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT			20
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1			0x00800000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK			0x07000000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT			24
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1			0x08000000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK			0x70000000
+#define MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT			28
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK;
+}
+#define MDP4_LAYERMIXER_IN_CFG_PIPE7_MIXER1			0x80000000
+
+#define REG_MDP4_VG2_SRC_FORMAT					0x00030050
+
+#define REG_MDP4_VG2_CONST_COLOR				0x00031008
+
+#define REG_MDP4_OVERLAY_FLUSH					0x00018000
+#define MDP4_OVERLAY_FLUSH_OVLP0				0x00000001
+#define MDP4_OVERLAY_FLUSH_OVLP1				0x00000002
+#define MDP4_OVERLAY_FLUSH_VG1					0x00000004
+#define MDP4_OVERLAY_FLUSH_VG2					0x00000008
+#define MDP4_OVERLAY_FLUSH_RGB1					0x00000010
+#define MDP4_OVERLAY_FLUSH_RGB2					0x00000020
+
+static inline uint32_t __offset_OVLP(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return 0x00010000;
+		case 1: return 0x00018000;
+		case 2: return 0x00088000;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP4_OVLP(uint32_t i0) { return 0x00000000 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_CFG(uint32_t i0) { return 0x00000004 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_SIZE(uint32_t i0) { return 0x00000008 + __offset_OVLP(i0); }
+#define MDP4_OVLP_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP4_OVLP_SIZE_HEIGHT__SHIFT				16
+static inline uint32_t MDP4_OVLP_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_OVLP_SIZE_HEIGHT__SHIFT) & MDP4_OVLP_SIZE_HEIGHT__MASK;
+}
+#define MDP4_OVLP_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP4_OVLP_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP4_OVLP_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_OVLP_SIZE_WIDTH__SHIFT) & MDP4_OVLP_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP4_OVLP_BASE(uint32_t i0) { return 0x0000000c + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_STRIDE(uint32_t i0) { return 0x00000010 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_OPMODE(uint32_t i0) { return 0x00000014 + __offset_OVLP(i0); }
+
+static inline uint32_t __offset_STAGE(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return 0x00000104;
+		case 1: return 0x00000124;
+		case 2: return 0x00000144;
+		case 3: return 0x00000160;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP4_OVLP_STAGE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_OP(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+#define MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK			0x00000003
+#define MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT			0
+static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp_alpha_type val)
+{
+	return ((val) << MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK;
+}
+#define MDP4_OVLP_STAGE_OP_FG_INV_ALPHA				0x00000004
+#define MDP4_OVLP_STAGE_OP_FG_MOD_ALPHA				0x00000008
+#define MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK			0x00000030
+#define MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT			4
+static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp_alpha_type val)
+{
+	return ((val) << MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK;
+}
+#define MDP4_OVLP_STAGE_OP_BG_INV_ALPHA				0x00000040
+#define MDP4_OVLP_STAGE_OP_BG_MOD_ALPHA				0x00000080
+#define MDP4_OVLP_STAGE_OP_FG_TRANSP				0x00000100
+#define MDP4_OVLP_STAGE_OP_BG_TRANSP				0x00000200
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_OVLP(i0) + __offset_STAGE(i1); }
+
+static inline uint32_t __offset_STAGE_CO3(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return 0x00001004;
+		case 1: return 0x00001404;
+		case 2: return 0x00001804;
+		case 3: return 0x00001b84;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP4_OVLP_STAGE_CO3(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE_CO3(i1); }
+
+static inline uint32_t REG_MDP4_OVLP_STAGE_CO3_SEL(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE_CO3(i1); }
+#define MDP4_OVLP_STAGE_CO3_SEL_FG_ALPHA			0x00000001
+
+static inline uint32_t REG_MDP4_OVLP_TRANSP_LOW0(uint32_t i0) { return 0x00000180 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_TRANSP_LOW1(uint32_t i0) { return 0x00000184 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_TRANSP_HIGH0(uint32_t i0) { return 0x00000188 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_TRANSP_HIGH1(uint32_t i0) { return 0x0000018c + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_CONFIG(uint32_t i0) { return 0x00000200 + __offset_OVLP(i0); }
+
+static inline uint32_t REG_MDP4_OVLP_CSC(uint32_t i0) { return 0x00002000 + __offset_OVLP(i0); }
+
+
+static inline uint32_t REG_MDP4_OVLP_CSC_MV(uint32_t i0, uint32_t i1) { return 0x00002400 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_MV_VAL(uint32_t i0, uint32_t i1) { return 0x00002400 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_PRE_BV(uint32_t i0, uint32_t i1) { return 0x00002500 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_PRE_BV_VAL(uint32_t i0, uint32_t i1) { return 0x00002500 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_POST_BV(uint32_t i0, uint32_t i1) { return 0x00002580 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_POST_BV_VAL(uint32_t i0, uint32_t i1) { return 0x00002580 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_PRE_LV(uint32_t i0, uint32_t i1) { return 0x00002600 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_PRE_LV_VAL(uint32_t i0, uint32_t i1) { return 0x00002600 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_POST_LV(uint32_t i0, uint32_t i1) { return 0x00002680 + __offset_OVLP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_OVLP_CSC_POST_LV_VAL(uint32_t i0, uint32_t i1) { return 0x00002680 + __offset_OVLP(i0) + 0x4*i1; }
+
+#define REG_MDP4_DMA_P_OP_MODE					0x00090070
+
+static inline uint32_t REG_MDP4_LUTN(uint32_t i0) { return 0x00094800 + 0x400*i0; }
+
+static inline uint32_t REG_MDP4_LUTN_LUT(uint32_t i0, uint32_t i1) { return 0x00094800 + 0x400*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_LUTN_LUT_VAL(uint32_t i0, uint32_t i1) { return 0x00094800 + 0x400*i0 + 0x4*i1; }
+
+#define REG_MDP4_DMA_S_OP_MODE					0x000a0028
+
+static inline uint32_t REG_MDP4_DMA_E_QUANT(uint32_t i0) { return 0x000b0070 + 0x4*i0; }
+
+static inline uint32_t __offset_DMA(enum mdp4_dma idx)
+{
+	switch (idx) {
+		case DMA_P: return 0x00090000;
+		case DMA_S: return 0x000a0000;
+		case DMA_E: return 0x000b0000;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP4_DMA(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_CONFIG(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); }
+#define MDP4_DMA_CONFIG_G_BPC__MASK				0x00000003
+#define MDP4_DMA_CONFIG_G_BPC__SHIFT				0
+static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP4_DMA_CONFIG_G_BPC__SHIFT) & MDP4_DMA_CONFIG_G_BPC__MASK;
+}
+#define MDP4_DMA_CONFIG_B_BPC__MASK				0x0000000c
+#define MDP4_DMA_CONFIG_B_BPC__SHIFT				2
+static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP4_DMA_CONFIG_B_BPC__SHIFT) & MDP4_DMA_CONFIG_B_BPC__MASK;
+}
+#define MDP4_DMA_CONFIG_R_BPC__MASK				0x00000030
+#define MDP4_DMA_CONFIG_R_BPC__SHIFT				4
+static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP4_DMA_CONFIG_R_BPC__SHIFT) & MDP4_DMA_CONFIG_R_BPC__MASK;
+}
+#define MDP4_DMA_CONFIG_PACK_ALIGN_MSB				0x00000080
+#define MDP4_DMA_CONFIG_PACK__MASK				0x0000ff00
+#define MDP4_DMA_CONFIG_PACK__SHIFT				8
+static inline uint32_t MDP4_DMA_CONFIG_PACK(uint32_t val)
+{
+	return ((val) << MDP4_DMA_CONFIG_PACK__SHIFT) & MDP4_DMA_CONFIG_PACK__MASK;
+}
+#define MDP4_DMA_CONFIG_DEFLKR_EN				0x01000000
+#define MDP4_DMA_CONFIG_DITHER_EN				0x01000000
+
+static inline uint32_t REG_MDP4_DMA_SRC_SIZE(enum mdp4_dma i0) { return 0x00000004 + __offset_DMA(i0); }
+#define MDP4_DMA_SRC_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP4_DMA_SRC_SIZE_HEIGHT__SHIFT				16
+static inline uint32_t MDP4_DMA_SRC_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_DMA_SRC_SIZE_HEIGHT__SHIFT) & MDP4_DMA_SRC_SIZE_HEIGHT__MASK;
+}
+#define MDP4_DMA_SRC_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP4_DMA_SRC_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP4_DMA_SRC_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_DMA_SRC_SIZE_WIDTH__SHIFT) & MDP4_DMA_SRC_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP4_DMA_SRC_BASE(enum mdp4_dma i0) { return 0x00000008 + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_SRC_STRIDE(enum mdp4_dma i0) { return 0x0000000c + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_DST_SIZE(enum mdp4_dma i0) { return 0x00000010 + __offset_DMA(i0); }
+#define MDP4_DMA_DST_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP4_DMA_DST_SIZE_HEIGHT__SHIFT				16
+static inline uint32_t MDP4_DMA_DST_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_DMA_DST_SIZE_HEIGHT__SHIFT) & MDP4_DMA_DST_SIZE_HEIGHT__MASK;
+}
+#define MDP4_DMA_DST_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP4_DMA_DST_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP4_DMA_DST_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_DMA_DST_SIZE_WIDTH__SHIFT) & MDP4_DMA_DST_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP4_DMA_CURSOR_SIZE(enum mdp4_dma i0) { return 0x00000044 + __offset_DMA(i0); }
+#define MDP4_DMA_CURSOR_SIZE_WIDTH__MASK			0x0000007f
+#define MDP4_DMA_CURSOR_SIZE_WIDTH__SHIFT			0
+static inline uint32_t MDP4_DMA_CURSOR_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_DMA_CURSOR_SIZE_WIDTH__SHIFT) & MDP4_DMA_CURSOR_SIZE_WIDTH__MASK;
+}
+#define MDP4_DMA_CURSOR_SIZE_HEIGHT__MASK			0x007f0000
+#define MDP4_DMA_CURSOR_SIZE_HEIGHT__SHIFT			16
+static inline uint32_t MDP4_DMA_CURSOR_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_DMA_CURSOR_SIZE_HEIGHT__SHIFT) & MDP4_DMA_CURSOR_SIZE_HEIGHT__MASK;
+}
+
+static inline uint32_t REG_MDP4_DMA_CURSOR_BASE(enum mdp4_dma i0) { return 0x00000048 + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_CURSOR_POS(enum mdp4_dma i0) { return 0x0000004c + __offset_DMA(i0); }
+#define MDP4_DMA_CURSOR_POS_X__MASK				0x0000ffff
+#define MDP4_DMA_CURSOR_POS_X__SHIFT				0
+static inline uint32_t MDP4_DMA_CURSOR_POS_X(uint32_t val)
+{
+	return ((val) << MDP4_DMA_CURSOR_POS_X__SHIFT) & MDP4_DMA_CURSOR_POS_X__MASK;
+}
+#define MDP4_DMA_CURSOR_POS_Y__MASK				0xffff0000
+#define MDP4_DMA_CURSOR_POS_Y__SHIFT				16
+static inline uint32_t MDP4_DMA_CURSOR_POS_Y(uint32_t val)
+{
+	return ((val) << MDP4_DMA_CURSOR_POS_Y__SHIFT) & MDP4_DMA_CURSOR_POS_Y__MASK;
+}
+
+static inline uint32_t REG_MDP4_DMA_CURSOR_BLEND_CONFIG(enum mdp4_dma i0) { return 0x00000060 + __offset_DMA(i0); }
+#define MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN			0x00000001
+#define MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__MASK		0x00000006
+#define MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__SHIFT		1
+static inline uint32_t MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(enum mdp4_cursor_format val)
+{
+	return ((val) << MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__SHIFT) & MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__MASK;
+}
+#define MDP4_DMA_CURSOR_BLEND_CONFIG_TRANSP_EN			0x00000008
+
+static inline uint32_t REG_MDP4_DMA_CURSOR_BLEND_PARAM(enum mdp4_dma i0) { return 0x00000064 + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_BLEND_TRANS_LOW(enum mdp4_dma i0) { return 0x00000068 + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_BLEND_TRANS_HIGH(enum mdp4_dma i0) { return 0x0000006c + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_FETCH_CONFIG(enum mdp4_dma i0) { return 0x00001004 + __offset_DMA(i0); }
+
+static inline uint32_t REG_MDP4_DMA_CSC(enum mdp4_dma i0) { return 0x00003000 + __offset_DMA(i0); }
+
+
+static inline uint32_t REG_MDP4_DMA_CSC_MV(enum mdp4_dma i0, uint32_t i1) { return 0x00003400 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_MV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003400 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_PRE_BV(enum mdp4_dma i0, uint32_t i1) { return 0x00003500 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_PRE_BV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003500 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_POST_BV(enum mdp4_dma i0, uint32_t i1) { return 0x00003580 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_POST_BV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003580 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_PRE_LV(enum mdp4_dma i0, uint32_t i1) { return 0x00003600 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_PRE_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003600 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_POST_LV(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_DMA_CSC_POST_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_SRC_SIZE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; }
+#define MDP4_PIPE_SRC_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT			16
+static inline uint32_t MDP4_PIPE_SRC_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_SRC_SIZE_HEIGHT__MASK;
+}
+#define MDP4_PIPE_SRC_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP4_PIPE_SRC_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SRC_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_SRC_XY(enum mdp4_pipe i0) { return 0x00020004 + 0x10000*i0; }
+#define MDP4_PIPE_SRC_XY_Y__MASK				0xffff0000
+#define MDP4_PIPE_SRC_XY_Y__SHIFT				16
+static inline uint32_t MDP4_PIPE_SRC_XY_Y(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_XY_Y__SHIFT) & MDP4_PIPE_SRC_XY_Y__MASK;
+}
+#define MDP4_PIPE_SRC_XY_X__MASK				0x0000ffff
+#define MDP4_PIPE_SRC_XY_X__SHIFT				0
+static inline uint32_t MDP4_PIPE_SRC_XY_X(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_XY_X__SHIFT) & MDP4_PIPE_SRC_XY_X__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_DST_SIZE(enum mdp4_pipe i0) { return 0x00020008 + 0x10000*i0; }
+#define MDP4_PIPE_DST_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT			16
+static inline uint32_t MDP4_PIPE_DST_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_DST_SIZE_HEIGHT__MASK;
+}
+#define MDP4_PIPE_DST_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP4_PIPE_DST_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP4_PIPE_DST_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_DST_SIZE_WIDTH__SHIFT) & MDP4_PIPE_DST_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_DST_XY(enum mdp4_pipe i0) { return 0x0002000c + 0x10000*i0; }
+#define MDP4_PIPE_DST_XY_Y__MASK				0xffff0000
+#define MDP4_PIPE_DST_XY_Y__SHIFT				16
+static inline uint32_t MDP4_PIPE_DST_XY_Y(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_DST_XY_Y__SHIFT) & MDP4_PIPE_DST_XY_Y__MASK;
+}
+#define MDP4_PIPE_DST_XY_X__MASK				0x0000ffff
+#define MDP4_PIPE_DST_XY_X__SHIFT				0
+static inline uint32_t MDP4_PIPE_DST_XY_X(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_DST_XY_X__SHIFT) & MDP4_PIPE_DST_XY_X__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_SRCP0_BASE(enum mdp4_pipe i0) { return 0x00020010 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mdp4_pipe i0) { return 0x00020014 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mdp4_pipe i0) { return 0x00020018 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_SRCP3_BASE(enum mdp4_pipe i0) { return 0x0002001c + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mdp4_pipe i0) { return 0x00020040 + 0x10000*i0; }
+#define MDP4_PIPE_SRC_STRIDE_A_P0__MASK				0x0000ffff
+#define MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT			0
+static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P0(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P0__MASK;
+}
+#define MDP4_PIPE_SRC_STRIDE_A_P1__MASK				0xffff0000
+#define MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT			16
+static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P1(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P1__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_B(enum mdp4_pipe i0) { return 0x00020044 + 0x10000*i0; }
+#define MDP4_PIPE_SRC_STRIDE_B_P2__MASK				0x0000ffff
+#define MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT			0
+static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P2(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P2__MASK;
+}
+#define MDP4_PIPE_SRC_STRIDE_B_P3__MASK				0xffff0000
+#define MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT			16
+static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P3(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P3__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_SSTILE_FRAME_SIZE(enum mdp4_pipe i0) { return 0x00020048 + 0x10000*i0; }
+#define MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__MASK		0xffff0000
+#define MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__SHIFT		16
+static inline uint32_t MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__MASK;
+}
+#define MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__MASK			0x0000ffff
+#define MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__SHIFT		0
+static inline uint32_t MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; }
+#define MDP4_PIPE_SRC_FORMAT_G_BPC__MASK			0x00000003
+#define MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT			0
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_G_BPC__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_B_BPC__MASK			0x0000000c
+#define MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT			2
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_B_BPC__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_R_BPC__MASK			0x00000030
+#define MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT			4
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_R_BPC__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_A_BPC__MASK			0x000000c0
+#define MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT			6
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_A_BPC__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE			0x00000100
+#define MDP4_PIPE_SRC_FORMAT_CPP__MASK				0x00000600
+#define MDP4_PIPE_SRC_FORMAT_CPP__SHIFT				9
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_CPP(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CPP__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_ROTATED_90				0x00001000
+#define MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK			0x00006000
+#define MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT		13
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000
+#define MDP4_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000
+#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK			0x00180000
+#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT		19
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT) & MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_SOLID_FILL				0x00400000
+#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK			0x0c000000
+#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT			26
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK			0x60000000
+#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT		29
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(enum mdp4_frame_format val)
+{
+	return ((val) << MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT) & MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mdp4_pipe i0) { return 0x00020054 + 0x10000*i0; }
+#define MDP4_PIPE_SRC_UNPACK_ELEM0__MASK			0x000000ff
+#define MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT			0
+static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM0(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM0__MASK;
+}
+#define MDP4_PIPE_SRC_UNPACK_ELEM1__MASK			0x0000ff00
+#define MDP4_PIPE_SRC_UNPACK_ELEM1__SHIFT			8
+static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM1(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM1__MASK;
+}
+#define MDP4_PIPE_SRC_UNPACK_ELEM2__MASK			0x00ff0000
+#define MDP4_PIPE_SRC_UNPACK_ELEM2__SHIFT			16
+static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM2(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM2__MASK;
+}
+#define MDP4_PIPE_SRC_UNPACK_ELEM3__MASK			0xff000000
+#define MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT			24
+static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
+{
+	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM3__MASK;
+}
+
+static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mdp4_pipe i0) { return 0x00020058 + 0x10000*i0; }
+#define MDP4_PIPE_OP_MODE_SCALEX_EN				0x00000001
+#define MDP4_PIPE_OP_MODE_SCALEY_EN				0x00000002
+#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK			0x0000000c
+#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT		2
+static inline uint32_t MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(enum mdp4_scale_unit val)
+{
+	return ((val) << MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK;
+}
+#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK			0x00000030
+#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT		4
+static inline uint32_t MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(enum mdp4_scale_unit val)
+{
+	return ((val) << MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK;
+}
+#define MDP4_PIPE_OP_MODE_SRC_YCBCR				0x00000200
+#define MDP4_PIPE_OP_MODE_DST_YCBCR				0x00000400
+#define MDP4_PIPE_OP_MODE_CSC_EN				0x00000800
+#define MDP4_PIPE_OP_MODE_FLIP_LR				0x00002000
+#define MDP4_PIPE_OP_MODE_FLIP_UD				0x00004000
+#define MDP4_PIPE_OP_MODE_DITHER_EN				0x00008000
+#define MDP4_PIPE_OP_MODE_IGC_LUT_EN				0x00010000
+#define MDP4_PIPE_OP_MODE_DEINT_EN				0x00040000
+#define MDP4_PIPE_OP_MODE_DEINT_ODD_REF				0x00080000
+
+static inline uint32_t REG_MDP4_PIPE_PHASEX_STEP(enum mdp4_pipe i0) { return 0x0002005c + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_PHASEY_STEP(enum mdp4_pipe i0) { return 0x00020060 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_FETCH_CONFIG(enum mdp4_pipe i0) { return 0x00021004 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_SOLID_COLOR(enum mdp4_pipe i0) { return 0x00021008 + 0x10000*i0; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC(enum mdp4_pipe i0) { return 0x00024000 + 0x10000*i0; }
+
+
+static inline uint32_t REG_MDP4_PIPE_CSC_MV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_MV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
+
+#define REG_MDP4_LCDC						0x000c0000
+
+#define REG_MDP4_LCDC_ENABLE					0x000c0000
+
+#define REG_MDP4_LCDC_HSYNC_CTRL				0x000c0004
+#define MDP4_LCDC_HSYNC_CTRL_PULSEW__MASK			0x0000ffff
+#define MDP4_LCDC_HSYNC_CTRL_PULSEW__SHIFT			0
+static inline uint32_t MDP4_LCDC_HSYNC_CTRL_PULSEW(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_LCDC_HSYNC_CTRL_PULSEW__MASK;
+}
+#define MDP4_LCDC_HSYNC_CTRL_PERIOD__MASK			0xffff0000
+#define MDP4_LCDC_HSYNC_CTRL_PERIOD__SHIFT			16
+static inline uint32_t MDP4_LCDC_HSYNC_CTRL_PERIOD(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_LCDC_HSYNC_CTRL_PERIOD__MASK;
+}
+
+#define REG_MDP4_LCDC_VSYNC_PERIOD				0x000c0008
+
+#define REG_MDP4_LCDC_VSYNC_LEN					0x000c000c
+
+#define REG_MDP4_LCDC_DISPLAY_HCTRL				0x000c0010
+#define MDP4_LCDC_DISPLAY_HCTRL_START__MASK			0x0000ffff
+#define MDP4_LCDC_DISPLAY_HCTRL_START__SHIFT			0
+static inline uint32_t MDP4_LCDC_DISPLAY_HCTRL_START(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_DISPLAY_HCTRL_START__SHIFT) & MDP4_LCDC_DISPLAY_HCTRL_START__MASK;
+}
+#define MDP4_LCDC_DISPLAY_HCTRL_END__MASK			0xffff0000
+#define MDP4_LCDC_DISPLAY_HCTRL_END__SHIFT			16
+static inline uint32_t MDP4_LCDC_DISPLAY_HCTRL_END(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_DISPLAY_HCTRL_END__SHIFT) & MDP4_LCDC_DISPLAY_HCTRL_END__MASK;
+}
+
+#define REG_MDP4_LCDC_DISPLAY_VSTART				0x000c0014
+
+#define REG_MDP4_LCDC_DISPLAY_VEND				0x000c0018
+
+#define REG_MDP4_LCDC_ACTIVE_HCTL				0x000c001c
+#define MDP4_LCDC_ACTIVE_HCTL_START__MASK			0x00007fff
+#define MDP4_LCDC_ACTIVE_HCTL_START__SHIFT			0
+static inline uint32_t MDP4_LCDC_ACTIVE_HCTL_START(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_ACTIVE_HCTL_START__SHIFT) & MDP4_LCDC_ACTIVE_HCTL_START__MASK;
+}
+#define MDP4_LCDC_ACTIVE_HCTL_END__MASK				0x7fff0000
+#define MDP4_LCDC_ACTIVE_HCTL_END__SHIFT			16
+static inline uint32_t MDP4_LCDC_ACTIVE_HCTL_END(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_ACTIVE_HCTL_END__SHIFT) & MDP4_LCDC_ACTIVE_HCTL_END__MASK;
+}
+#define MDP4_LCDC_ACTIVE_HCTL_ACTIVE_START_X			0x80000000
+
+#define REG_MDP4_LCDC_ACTIVE_VSTART				0x000c0020
+
+#define REG_MDP4_LCDC_ACTIVE_VEND				0x000c0024
+
+#define REG_MDP4_LCDC_BORDER_CLR				0x000c0028
+
+#define REG_MDP4_LCDC_UNDERFLOW_CLR				0x000c002c
+#define MDP4_LCDC_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff
+#define MDP4_LCDC_UNDERFLOW_CLR_COLOR__SHIFT			0
+static inline uint32_t MDP4_LCDC_UNDERFLOW_CLR_COLOR(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_LCDC_UNDERFLOW_CLR_COLOR__MASK;
+}
+#define MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000
+
+#define REG_MDP4_LCDC_HSYNC_SKEW				0x000c0030
+
+#define REG_MDP4_LCDC_TEST_CNTL					0x000c0034
+
+#define REG_MDP4_LCDC_CTRL_POLARITY				0x000c0038
+#define MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW			0x00000001
+#define MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW			0x00000002
+#define MDP4_LCDC_CTRL_POLARITY_DATA_EN_LOW			0x00000004
+
+#define REG_MDP4_LCDC_LVDS_INTF_CTL				0x000c2000
+#define MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL			0x00000004
+#define MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT				0x00000008
+#define MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP				0x00000010
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_RES_BIT			0x00000020
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_RES_BIT			0x00000040
+#define MDP4_LCDC_LVDS_INTF_CTL_ENABLE				0x00000080
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN		0x00000100
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN		0x00000200
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN		0x00000400
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN		0x00000800
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN		0x00001000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN		0x00002000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN		0x00004000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN		0x00008000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN			0x00010000
+#define MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN			0x00020000
+
+static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
+
+static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK		0x000000ff
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT		0
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK		0x0000ff00
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT		8
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK		0x00ff0000
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT		16
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK		0xff000000
+#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT		24
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK;
+}
+
+static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(uint32_t i0) { return 0x000c2018 + 0x8*i0; }
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK		0x000000ff
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT		0
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK		0x0000ff00
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT		8
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK;
+}
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK		0x00ff0000
+#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT		16
+static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(uint32_t val)
+{
+	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK;
+}
+
+#define REG_MDP4_LCDC_LVDS_PHY_RESET				0x000c2034
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_0				0x000c3000
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_1				0x000c3004
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_2				0x000c3008
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_3				0x000c300c
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_5				0x000c3014
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_6				0x000c3018
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_7				0x000c301c
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_8				0x000c3020
+
+#define REG_MDP4_LVDS_PHY_PLL_CTRL_9				0x000c3024
+
+#define REG_MDP4_LVDS_PHY_PLL_LOCKED				0x000c3080
+
+#define REG_MDP4_LVDS_PHY_CFG2					0x000c3108
+
+#define REG_MDP4_LVDS_PHY_CFG0					0x000c3100
+#define MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE			0x00000010
+#define MDP4_LVDS_PHY_CFG0_CHANNEL0				0x00000040
+#define MDP4_LVDS_PHY_CFG0_CHANNEL1				0x00000080
+
+#define REG_MDP4_DTV						0x000d0000
+
+#define REG_MDP4_DTV_ENABLE					0x000d0000
+
+#define REG_MDP4_DTV_HSYNC_CTRL					0x000d0004
+#define MDP4_DTV_HSYNC_CTRL_PULSEW__MASK			0x0000ffff
+#define MDP4_DTV_HSYNC_CTRL_PULSEW__SHIFT			0
+static inline uint32_t MDP4_DTV_HSYNC_CTRL_PULSEW(uint32_t val)
+{
+	return ((val) << MDP4_DTV_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_DTV_HSYNC_CTRL_PULSEW__MASK;
+}
+#define MDP4_DTV_HSYNC_CTRL_PERIOD__MASK			0xffff0000
+#define MDP4_DTV_HSYNC_CTRL_PERIOD__SHIFT			16
+static inline uint32_t MDP4_DTV_HSYNC_CTRL_PERIOD(uint32_t val)
+{
+	return ((val) << MDP4_DTV_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_DTV_HSYNC_CTRL_PERIOD__MASK;
+}
+
+#define REG_MDP4_DTV_VSYNC_PERIOD				0x000d0008
+
+#define REG_MDP4_DTV_VSYNC_LEN					0x000d000c
+
+#define REG_MDP4_DTV_DISPLAY_HCTRL				0x000d0018
+#define MDP4_DTV_DISPLAY_HCTRL_START__MASK			0x0000ffff
+#define MDP4_DTV_DISPLAY_HCTRL_START__SHIFT			0
+static inline uint32_t MDP4_DTV_DISPLAY_HCTRL_START(uint32_t val)
+{
+	return ((val) << MDP4_DTV_DISPLAY_HCTRL_START__SHIFT) & MDP4_DTV_DISPLAY_HCTRL_START__MASK;
+}
+#define MDP4_DTV_DISPLAY_HCTRL_END__MASK			0xffff0000
+#define MDP4_DTV_DISPLAY_HCTRL_END__SHIFT			16
+static inline uint32_t MDP4_DTV_DISPLAY_HCTRL_END(uint32_t val)
+{
+	return ((val) << MDP4_DTV_DISPLAY_HCTRL_END__SHIFT) & MDP4_DTV_DISPLAY_HCTRL_END__MASK;
+}
+
+#define REG_MDP4_DTV_DISPLAY_VSTART				0x000d001c
+
+#define REG_MDP4_DTV_DISPLAY_VEND				0x000d0020
+
+#define REG_MDP4_DTV_ACTIVE_HCTL				0x000d002c
+#define MDP4_DTV_ACTIVE_HCTL_START__MASK			0x00007fff
+#define MDP4_DTV_ACTIVE_HCTL_START__SHIFT			0
+static inline uint32_t MDP4_DTV_ACTIVE_HCTL_START(uint32_t val)
+{
+	return ((val) << MDP4_DTV_ACTIVE_HCTL_START__SHIFT) & MDP4_DTV_ACTIVE_HCTL_START__MASK;
+}
+#define MDP4_DTV_ACTIVE_HCTL_END__MASK				0x7fff0000
+#define MDP4_DTV_ACTIVE_HCTL_END__SHIFT				16
+static inline uint32_t MDP4_DTV_ACTIVE_HCTL_END(uint32_t val)
+{
+	return ((val) << MDP4_DTV_ACTIVE_HCTL_END__SHIFT) & MDP4_DTV_ACTIVE_HCTL_END__MASK;
+}
+#define MDP4_DTV_ACTIVE_HCTL_ACTIVE_START_X			0x80000000
+
+#define REG_MDP4_DTV_ACTIVE_VSTART				0x000d0030
+
+#define REG_MDP4_DTV_ACTIVE_VEND				0x000d0038
+
+#define REG_MDP4_DTV_BORDER_CLR					0x000d0040
+
+#define REG_MDP4_DTV_UNDERFLOW_CLR				0x000d0044
+#define MDP4_DTV_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff
+#define MDP4_DTV_UNDERFLOW_CLR_COLOR__SHIFT			0
+static inline uint32_t MDP4_DTV_UNDERFLOW_CLR_COLOR(uint32_t val)
+{
+	return ((val) << MDP4_DTV_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_DTV_UNDERFLOW_CLR_COLOR__MASK;
+}
+#define MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000
+
+#define REG_MDP4_DTV_HSYNC_SKEW					0x000d0048
+
+#define REG_MDP4_DTV_TEST_CNTL					0x000d004c
+
+#define REG_MDP4_DTV_CTRL_POLARITY				0x000d0050
+#define MDP4_DTV_CTRL_POLARITY_HSYNC_LOW			0x00000001
+#define MDP4_DTV_CTRL_POLARITY_VSYNC_LOW			0x00000002
+#define MDP4_DTV_CTRL_POLARITY_DATA_EN_LOW			0x00000004
+
+#define REG_MDP4_DSI						0x000e0000
+
+#define REG_MDP4_DSI_ENABLE					0x000e0000
+
+#define REG_MDP4_DSI_HSYNC_CTRL					0x000e0004
+#define MDP4_DSI_HSYNC_CTRL_PULSEW__MASK			0x0000ffff
+#define MDP4_DSI_HSYNC_CTRL_PULSEW__SHIFT			0
+static inline uint32_t MDP4_DSI_HSYNC_CTRL_PULSEW(uint32_t val)
+{
+	return ((val) << MDP4_DSI_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_DSI_HSYNC_CTRL_PULSEW__MASK;
+}
+#define MDP4_DSI_HSYNC_CTRL_PERIOD__MASK			0xffff0000
+#define MDP4_DSI_HSYNC_CTRL_PERIOD__SHIFT			16
+static inline uint32_t MDP4_DSI_HSYNC_CTRL_PERIOD(uint32_t val)
+{
+	return ((val) << MDP4_DSI_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_DSI_HSYNC_CTRL_PERIOD__MASK;
+}
+
+#define REG_MDP4_DSI_VSYNC_PERIOD				0x000e0008
+
+#define REG_MDP4_DSI_VSYNC_LEN					0x000e000c
+
+#define REG_MDP4_DSI_DISPLAY_HCTRL				0x000e0010
+#define MDP4_DSI_DISPLAY_HCTRL_START__MASK			0x0000ffff
+#define MDP4_DSI_DISPLAY_HCTRL_START__SHIFT			0
+static inline uint32_t MDP4_DSI_DISPLAY_HCTRL_START(uint32_t val)
+{
+	return ((val) << MDP4_DSI_DISPLAY_HCTRL_START__SHIFT) & MDP4_DSI_DISPLAY_HCTRL_START__MASK;
+}
+#define MDP4_DSI_DISPLAY_HCTRL_END__MASK			0xffff0000
+#define MDP4_DSI_DISPLAY_HCTRL_END__SHIFT			16
+static inline uint32_t MDP4_DSI_DISPLAY_HCTRL_END(uint32_t val)
+{
+	return ((val) << MDP4_DSI_DISPLAY_HCTRL_END__SHIFT) & MDP4_DSI_DISPLAY_HCTRL_END__MASK;
+}
+
+#define REG_MDP4_DSI_DISPLAY_VSTART				0x000e0014
+
+#define REG_MDP4_DSI_DISPLAY_VEND				0x000e0018
+
+#define REG_MDP4_DSI_ACTIVE_HCTL				0x000e001c
+#define MDP4_DSI_ACTIVE_HCTL_START__MASK			0x00007fff
+#define MDP4_DSI_ACTIVE_HCTL_START__SHIFT			0
+static inline uint32_t MDP4_DSI_ACTIVE_HCTL_START(uint32_t val)
+{
+	return ((val) << MDP4_DSI_ACTIVE_HCTL_START__SHIFT) & MDP4_DSI_ACTIVE_HCTL_START__MASK;
+}
+#define MDP4_DSI_ACTIVE_HCTL_END__MASK				0x7fff0000
+#define MDP4_DSI_ACTIVE_HCTL_END__SHIFT				16
+static inline uint32_t MDP4_DSI_ACTIVE_HCTL_END(uint32_t val)
+{
+	return ((val) << MDP4_DSI_ACTIVE_HCTL_END__SHIFT) & MDP4_DSI_ACTIVE_HCTL_END__MASK;
+}
+#define MDP4_DSI_ACTIVE_HCTL_ACTIVE_START_X			0x80000000
+
+#define REG_MDP4_DSI_ACTIVE_VSTART				0x000e0020
+
+#define REG_MDP4_DSI_ACTIVE_VEND				0x000e0024
+
+#define REG_MDP4_DSI_BORDER_CLR					0x000e0028
+
+#define REG_MDP4_DSI_UNDERFLOW_CLR				0x000e002c
+#define MDP4_DSI_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff
+#define MDP4_DSI_UNDERFLOW_CLR_COLOR__SHIFT			0
+static inline uint32_t MDP4_DSI_UNDERFLOW_CLR_COLOR(uint32_t val)
+{
+	return ((val) << MDP4_DSI_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_DSI_UNDERFLOW_CLR_COLOR__MASK;
+}
+#define MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000
+
+#define REG_MDP4_DSI_HSYNC_SKEW					0x000e0030
+
+#define REG_MDP4_DSI_TEST_CNTL					0x000e0034
+
+#define REG_MDP4_DSI_CTRL_POLARITY				0x000e0038
+#define MDP4_DSI_CTRL_POLARITY_HSYNC_LOW			0x00000001
+#define MDP4_DSI_CTRL_POLARITY_VSYNC_LOW			0x00000002
+#define MDP4_DSI_CTRL_POLARITY_DATA_EN_LOW			0x00000004
+
+
+#endif /* MDP4_XML */
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
new file mode 100644
index 000000000000..6e5e1aa54ce1
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drm_mode.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_crtc {
+	struct drm_crtc base;
+	char name[8];
+	int id;
+	int ovlp;
+	enum mdp4_dma dma;
+	bool enabled;
+
+	/* which mixer/encoder we route output to: */
+	int mixer;
+
+	struct {
+		spinlock_t lock;
+		bool stale;
+		uint32_t width, height;
+		uint32_t x, y;
+
+		/* next cursor to scan-out: */
+		uint32_t next_iova;
+		struct drm_gem_object *next_bo;
+
+		/* current cursor being scanned out: */
+		struct drm_gem_object *scanout_bo;
+	} cursor;
+
+
+	/* if there is a pending flip, these will be non-null: */
+	struct drm_pending_vblank_event *event;
+
+	/* Bits have been flushed at the last commit,
+	 * used to decide if a vsync has happened since last commit.
+	 */
+	u32 flushed_mask;
+
+#define PENDING_CURSOR 0x1
+#define PENDING_FLIP   0x2
+	atomic_t pending;
+
+	/* for unref'ing cursor bo's after scanout completes: */
+	struct drm_flip_work unref_cursor_work;
+
+	struct mdp_irq vblank;
+	struct mdp_irq err;
+};
+#define to_mdp4_crtc(x) container_of(x, struct mdp4_crtc, base)
+
+static struct mdp4_kms *get_kms(struct drm_crtc *crtc)
+{
+	struct msm_drm_private *priv = crtc->dev->dev_private;
+	return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+static void request_pending(struct drm_crtc *crtc, uint32_t pending)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+	atomic_or(pending, &mdp4_crtc->pending);
+	mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
+}
+
+static void crtc_flush(struct drm_crtc *crtc)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	struct drm_plane *plane;
+	uint32_t flush = 0;
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+		flush |= pipe2flush(pipe_id);
+	}
+
+	flush |= ovlp2flush(mdp4_crtc->ovlp);
+
+	DBG("%s: flush=%08x", mdp4_crtc->name, flush);
+
+	mdp4_crtc->flushed_mask = flush;
+
+	mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
+}
+
+/* if file!=NULL, this is preclose potential cancel-flip path */
+static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct drm_pending_vblank_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = mdp4_crtc->event;
+	if (event) {
+		mdp4_crtc->event = NULL;
+		DBG("%s: send event: %p", mdp4_crtc->name, event);
+		drm_crtc_send_vblank_event(crtc, event);
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void unref_cursor_worker(struct drm_flip_work *work, void *val)
+{
+	struct mdp4_crtc *mdp4_crtc =
+		container_of(work, struct mdp4_crtc, unref_cursor_work);
+	struct mdp4_kms *mdp4_kms = get_kms(&mdp4_crtc->base);
+	struct msm_kms *kms = &mdp4_kms->base.base;
+
+	msm_gem_put_iova(val, kms->aspace);
+	drm_gem_object_put_unlocked(val);
+}
+
+static void mdp4_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work);
+
+	kfree(mdp4_crtc);
+}
+
+/* statically (for now) map planes to mixer stage (z-order): */
+static const int idxs[] = {
+		[VG1]  = 1,
+		[VG2]  = 2,
+		[RGB1] = 0,
+		[RGB2] = 0,
+		[RGB3] = 0,
+		[VG3]  = 3,
+		[VG4]  = 4,
+
+};
+
+/* setup mixer config, for which we need to consider all crtc's and
+ * the planes attached to them
+ *
+ * TODO may possibly need some extra locking here
+ */
+static void setup_mixer(struct mdp4_kms *mdp4_kms)
+{
+	struct drm_mode_config *config = &mdp4_kms->dev->mode_config;
+	struct drm_crtc *crtc;
+	uint32_t mixer_cfg = 0;
+	static const enum mdp_mixer_stage_id stages[] = {
+			STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
+	};
+
+	list_for_each_entry(crtc, &config->crtc_list, head) {
+		struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+		struct drm_plane *plane;
+
+		drm_atomic_crtc_for_each_plane(plane, crtc) {
+			enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+			int idx = idxs[pipe_id];
+			mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
+					pipe_id, stages[idx]);
+		}
+	}
+
+	mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
+}
+
+static void blend_setup(struct drm_crtc *crtc)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	struct drm_plane *plane;
+	int i, ovlp = mdp4_crtc->ovlp;
+	bool alpha[4]= { false, false, false, false };
+
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+		int idx = idxs[pipe_id];
+		if (idx > 0) {
+			const struct mdp_format *format =
+					to_mdp_format(msm_framebuffer_format(plane->fb));
+			alpha[idx-1] = format->alpha_enable;
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		uint32_t op;
+
+		if (alpha[i]) {
+			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) |
+					MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) |
+					MDP4_OVLP_STAGE_OP_BG_INV_ALPHA;
+		} else {
+			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
+					MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST);
+		}
+
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0);
+		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
+	}
+
+	setup_mixer(mdp4_kms);
+}
+
+static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	enum mdp4_dma dma = mdp4_crtc->dma;
+	int ovlp = mdp4_crtc->ovlp;
+	struct drm_display_mode *mode;
+
+	if (WARN_ON(!crtc->state))
+		return;
+
+	mode = &crtc->state->adjusted_mode;
+
+	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			mdp4_crtc->name, mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
+			MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
+			MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay));
+
+	/* take data from pipe: */
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
+			MDP4_DMA_DST_SIZE_WIDTH(0) |
+			MDP4_DMA_DST_SIZE_HEIGHT(0));
+
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_BASE(ovlp), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp),
+			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
+			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), 0);
+
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
+
+	if (dma == DMA_E) {
+		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000);
+		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000);
+		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
+	}
+}
+
+static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc,
+				     struct drm_crtc_state *old_state)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+
+	DBG("%s", mdp4_crtc->name);
+
+	if (WARN_ON(!mdp4_crtc->enabled))
+		return;
+
+	/* Disable/save vblank irq handling before power is disabled */
+	drm_crtc_vblank_off(crtc);
+
+	mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
+	mdp4_disable(mdp4_kms);
+
+	mdp4_crtc->enabled = false;
+}
+
+static void mdp4_crtc_atomic_enable(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+
+	DBG("%s", mdp4_crtc->name);
+
+	if (WARN_ON(mdp4_crtc->enabled))
+		return;
+
+	mdp4_enable(mdp4_kms);
+
+	/* Restore vblank irq handling after power is enabled */
+	drm_crtc_vblank_on(crtc);
+
+	mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
+
+	crtc_flush(crtc);
+
+	mdp4_crtc->enabled = true;
+}
+
+static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	DBG("%s: check", mdp4_crtc->name);
+	// TODO anything else to check?
+	return 0;
+}
+
+static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	DBG("%s: begin", mdp4_crtc->name);
+}
+
+static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	unsigned long flags;
+
+	DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event);
+
+	WARN_ON(mdp4_crtc->event);
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	mdp4_crtc->event = crtc->state->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	blend_setup(crtc);
+	crtc_flush(crtc);
+	request_pending(crtc, PENDING_FLIP);
+}
+
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+
+/* called from IRQ to update cursor related registers (if needed).  The
+ * cursor registers, other than x/y position, appear not to be double
+ * buffered, and changing them other than from vblank seems to trigger
+ * underflow.
+ */
+static void update_cursor(struct drm_crtc *crtc)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	struct msm_kms *kms = &mdp4_kms->base.base;
+	enum mdp4_dma dma = mdp4_crtc->dma;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
+	if (mdp4_crtc->cursor.stale) {
+		struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo;
+		struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo;
+		uint64_t iova = mdp4_crtc->cursor.next_iova;
+
+		if (next_bo) {
+			/* take a obj ref + iova ref when we start scanning out: */
+			drm_gem_object_get(next_bo);
+			msm_gem_get_iova(next_bo, kms->aspace, &iova);
+
+			/* enable cursor: */
+			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma),
+					MDP4_DMA_CURSOR_SIZE_WIDTH(mdp4_crtc->cursor.width) |
+					MDP4_DMA_CURSOR_SIZE_HEIGHT(mdp4_crtc->cursor.height));
+			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), iova);
+			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma),
+					MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB) |
+					MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN);
+		} else {
+			/* disable cursor: */
+			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma),
+					mdp4_kms->blank_cursor_iova);
+		}
+
+		/* and drop the iova ref + obj rev when done scanning out: */
+		if (prev_bo)
+			drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, prev_bo);
+
+		mdp4_crtc->cursor.scanout_bo = next_bo;
+		mdp4_crtc->cursor.stale = false;
+	}
+
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
+			MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) |
+			MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y));
+
+	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
+}
+
+static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
+		struct drm_file *file_priv, uint32_t handle,
+		uint32_t width, uint32_t height)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	struct msm_kms *kms = &mdp4_kms->base.base;
+	struct drm_device *dev = crtc->dev;
+	struct drm_gem_object *cursor_bo, *old_bo;
+	unsigned long flags;
+	uint64_t iova;
+	int ret;
+
+	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
+		return -EINVAL;
+	}
+
+	if (handle) {
+		cursor_bo = drm_gem_object_lookup(file_priv, handle);
+		if (!cursor_bo)
+			return -ENOENT;
+	} else {
+		cursor_bo = NULL;
+	}
+
+	if (cursor_bo) {
+		ret = msm_gem_get_iova(cursor_bo, kms->aspace, &iova);
+		if (ret)
+			goto fail;
+	} else {
+		iova = 0;
+	}
+
+	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
+	old_bo = mdp4_crtc->cursor.next_bo;
+	mdp4_crtc->cursor.next_bo   = cursor_bo;
+	mdp4_crtc->cursor.next_iova = iova;
+	mdp4_crtc->cursor.width     = width;
+	mdp4_crtc->cursor.height    = height;
+	mdp4_crtc->cursor.stale     = true;
+	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
+
+	if (old_bo) {
+		/* drop our previous reference: */
+		drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo);
+	}
+
+	request_pending(crtc, PENDING_CURSOR);
+
+	return 0;
+
+fail:
+	drm_gem_object_put_unlocked(cursor_bo);
+	return ret;
+}
+
+static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
+	mdp4_crtc->cursor.x = x;
+	mdp4_crtc->cursor.y = y;
+	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
+
+	crtc_flush(crtc);
+	request_pending(crtc, PENDING_CURSOR);
+
+	return 0;
+}
+
+static const struct drm_crtc_funcs mdp4_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = mdp4_crtc_destroy,
+	.page_flip = drm_atomic_helper_page_flip,
+	.cursor_set = mdp4_crtc_cursor_set,
+	.cursor_move = mdp4_crtc_cursor_move,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
+	.mode_set_nofb = mdp4_crtc_mode_set_nofb,
+	.atomic_check = mdp4_crtc_atomic_check,
+	.atomic_begin = mdp4_crtc_atomic_begin,
+	.atomic_flush = mdp4_crtc_atomic_flush,
+	.atomic_enable = mdp4_crtc_atomic_enable,
+	.atomic_disable = mdp4_crtc_atomic_disable,
+};
+
+static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank);
+	struct drm_crtc *crtc = &mdp4_crtc->base;
+	struct msm_drm_private *priv = crtc->dev->dev_private;
+	unsigned pending;
+
+	mdp_irq_unregister(&get_kms(crtc)->base, &mdp4_crtc->vblank);
+
+	pending = atomic_xchg(&mdp4_crtc->pending, 0);
+
+	if (pending & PENDING_FLIP) {
+		complete_flip(crtc, NULL);
+	}
+
+	if (pending & PENDING_CURSOR) {
+		update_cursor(crtc);
+		drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq);
+	}
+}
+
+static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, err);
+	struct drm_crtc *crtc = &mdp4_crtc->base;
+	DBG("%s: error: %08x", mdp4_crtc->name, irqstatus);
+	crtc_flush(crtc);
+}
+
+static void mdp4_crtc_wait_for_flush_done(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	int ret;
+
+	ret = drm_crtc_vblank_get(crtc);
+	if (ret)
+		return;
+
+	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
+		!(mdp4_read(mdp4_kms, REG_MDP4_OVERLAY_FLUSH) &
+			mdp4_crtc->flushed_mask),
+		msecs_to_jiffies(50));
+	if (ret <= 0)
+		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp4_crtc->id);
+
+	mdp4_crtc->flushed_mask = 0;
+
+	drm_crtc_vblank_put(crtc);
+}
+
+uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	return mdp4_crtc->vblank.irqmask;
+}
+
+/* set dma config, ie. the format the encoder wants. */
+void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_CONFIG(mdp4_crtc->dma), config);
+}
+
+/* set interface for routing crtc->encoder: */
+void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
+{
+	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+	uint32_t intf_sel;
+
+	intf_sel = mdp4_read(mdp4_kms, REG_MDP4_DISP_INTF_SEL);
+
+	switch (mdp4_crtc->dma) {
+	case DMA_P:
+		intf_sel &= ~MDP4_DISP_INTF_SEL_PRIM__MASK;
+		intf_sel |= MDP4_DISP_INTF_SEL_PRIM(intf);
+		break;
+	case DMA_S:
+		intf_sel &= ~MDP4_DISP_INTF_SEL_SEC__MASK;
+		intf_sel |= MDP4_DISP_INTF_SEL_SEC(intf);
+		break;
+	case DMA_E:
+		intf_sel &= ~MDP4_DISP_INTF_SEL_EXT__MASK;
+		intf_sel |= MDP4_DISP_INTF_SEL_EXT(intf);
+		break;
+	}
+
+	if (intf == INTF_DSI_VIDEO) {
+		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD;
+		intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO;
+	} else if (intf == INTF_DSI_CMD) {
+		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO;
+		intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD;
+	}
+
+	mdp4_crtc->mixer = mixer;
+
+	blend_setup(crtc);
+
+	DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
+}
+
+void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc)
+{
+	/* wait_for_flush_done is the only case for now.
+	 * Later we will have command mode CRTC to wait for
+	 * other event.
+	 */
+	mdp4_crtc_wait_for_flush_done(crtc);
+}
+
+static const char *dma_names[] = {
+		"DMA_P", "DMA_S", "DMA_E",
+};
+
+/* initialize crtc */
+struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
+		struct drm_plane *plane, int id, int ovlp_id,
+		enum mdp4_dma dma_id)
+{
+	struct drm_crtc *crtc = NULL;
+	struct mdp4_crtc *mdp4_crtc;
+
+	mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL);
+	if (!mdp4_crtc)
+		return ERR_PTR(-ENOMEM);
+
+	crtc = &mdp4_crtc->base;
+
+	mdp4_crtc->id = id;
+
+	mdp4_crtc->ovlp = ovlp_id;
+	mdp4_crtc->dma = dma_id;
+
+	mdp4_crtc->vblank.irqmask = dma2irq(mdp4_crtc->dma);
+	mdp4_crtc->vblank.irq = mdp4_crtc_vblank_irq;
+
+	mdp4_crtc->err.irqmask = dma2err(mdp4_crtc->dma);
+	mdp4_crtc->err.irq = mdp4_crtc_err_irq;
+
+	snprintf(mdp4_crtc->name, sizeof(mdp4_crtc->name), "%s:%d",
+			dma_names[dma_id], ovlp_id);
+
+	spin_lock_init(&mdp4_crtc->cursor.lock);
+
+	drm_flip_work_init(&mdp4_crtc->unref_cursor_work,
+			"unref cursor", unref_cursor_worker);
+
+	drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs,
+				  NULL);
+	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
+	plane->crtc = crtc;
+
+	return crtc;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
new file mode 100644
index 000000000000..6a1ebdace391
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, Inforce Computing. All rights reserved.
+ *
+ * Author: Vinay Simha <vinaysimha@inforcecomputing.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_dsi_encoder {
+	struct drm_encoder base;
+	struct drm_panel *panel;
+	bool enabled;
+};
+#define to_mdp4_dsi_encoder(x) container_of(x, struct mdp4_dsi_encoder, base)
+
+static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
+{
+	struct msm_drm_private *priv = encoder->dev->dev_private;
+	return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
+
+	drm_encoder_cleanup(encoder);
+	kfree(mdp4_dsi_encoder);
+}
+
+static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
+	.destroy = mdp4_dsi_encoder_destroy,
+};
+
+static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode,
+				      struct drm_display_mode *adjusted_mode)
+{
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	uint32_t dsi_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+	uint32_t display_v_start, display_v_end;
+	uint32_t hsync_start_x, hsync_end_x;
+
+	mode = adjusted_mode;
+
+	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+
+	ctrl_pol = 0;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		ctrl_pol |= MDP4_DSI_CTRL_POLARITY_HSYNC_LOW;
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		ctrl_pol |= MDP4_DSI_CTRL_POLARITY_VSYNC_LOW;
+	/* probably need to get DATA_EN polarity from panel.. */
+
+	dsi_hsync_skew = 0;  /* get this from panel? */
+
+	hsync_start_x = (mode->htotal - mode->hsync_start);
+	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
+
+	vsync_period = mode->vtotal * mode->htotal;
+	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
+	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dsi_hsync_skew;
+	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dsi_hsync_skew - 1;
+
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_CTRL,
+			MDP4_DSI_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
+			MDP4_DSI_HSYNC_CTRL_PERIOD(mode->htotal));
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_PERIOD, vsync_period);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_LEN, vsync_len);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_HCTRL,
+			MDP4_DSI_DISPLAY_HCTRL_START(hsync_start_x) |
+			MDP4_DSI_DISPLAY_HCTRL_END(hsync_end_x));
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VSTART, display_v_start);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VEND, display_v_end);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_CTRL_POLARITY, ctrl_pol);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_UNDERFLOW_CLR,
+			MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY |
+			MDP4_DSI_UNDERFLOW_CLR_COLOR(0xff));
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_HCTL,
+			MDP4_DSI_ACTIVE_HCTL_START(0) |
+			MDP4_DSI_ACTIVE_HCTL_END(0));
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_SKEW, dsi_hsync_skew);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_BORDER_CLR, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VSTART, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VEND, 0);
+}
+
+static void mdp4_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+
+	if (!mdp4_dsi_encoder->enabled)
+		return;
+
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
+
+	/*
+	 * Wait for a vsync so we know the ENABLE=0 latched before
+	 * the (connector) source of the vsync's gets disabled,
+	 * otherwise we end up in a funny state if we re-enable
+	 * before the disable latches, which results that some of
+	 * the settings changes for the new modeset (like new
+	 * scanout buffer) don't latch properly..
+	 */
+	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
+
+	mdp4_dsi_encoder->enabled = false;
+}
+
+static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+
+	if (mdp4_dsi_encoder->enabled)
+		return;
+
+	 mdp4_crtc_set_config(encoder->crtc,
+			MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
+			MDP4_DMA_CONFIG_DEFLKR_EN |
+			MDP4_DMA_CONFIG_DITHER_EN |
+			MDP4_DMA_CONFIG_R_BPC(BPC8) |
+			MDP4_DMA_CONFIG_G_BPC(BPC8) |
+			MDP4_DMA_CONFIG_B_BPC(BPC8) |
+			MDP4_DMA_CONFIG_PACK(0x21));
+
+	mdp4_crtc_set_intf(encoder->crtc, INTF_DSI_VIDEO, 0);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 1);
+
+	mdp4_dsi_encoder->enabled = true;
+}
+
+static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = {
+	.mode_set = mdp4_dsi_encoder_mode_set,
+	.disable = mdp4_dsi_encoder_disable,
+	.enable = mdp4_dsi_encoder_enable,
+};
+
+/* initialize encoder */
+struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
+{
+	struct drm_encoder *encoder = NULL;
+	struct mdp4_dsi_encoder *mdp4_dsi_encoder;
+	int ret;
+
+	mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL);
+	if (!mdp4_dsi_encoder) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	encoder = &mdp4_dsi_encoder->base;
+
+	drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs,
+			 DRM_MODE_ENCODER_DSI, NULL);
+	drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs);
+
+	return encoder;
+
+fail:
+	if (encoder)
+		mdp4_dsi_encoder_destroy(encoder);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
new file mode 100644
index 000000000000..ba8e587f734b
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_dtv_encoder {
+	struct drm_encoder base;
+	struct clk *hdmi_clk;
+	struct clk *mdp_clk;
+	unsigned long int pixclock;
+	bool enabled;
+	uint32_t bsc;
+};
+#define to_mdp4_dtv_encoder(x) container_of(x, struct mdp4_dtv_encoder, base)
+
+static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
+{
+	struct msm_drm_private *priv = encoder->dev->dev_private;
+	return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+/* not ironically named at all.. no, really.. */
+static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder)
+{
+	struct drm_device *dev = mdp4_dtv_encoder->base.dev;
+	struct lcdc_platform_data *dtv_pdata = mdp4_find_pdata("dtv.0");
+
+	if (!dtv_pdata) {
+		dev_err(dev->dev, "could not find dtv pdata\n");
+		return;
+	}
+
+	if (dtv_pdata->bus_scale_table) {
+		mdp4_dtv_encoder->bsc = msm_bus_scale_register_client(
+				dtv_pdata->bus_scale_table);
+		DBG("bus scale client: %08x", mdp4_dtv_encoder->bsc);
+		DBG("lcdc_power_save: %p", dtv_pdata->lcdc_power_save);
+		if (dtv_pdata->lcdc_power_save)
+			dtv_pdata->lcdc_power_save(1);
+	}
+}
+
+static void bs_fini(struct mdp4_dtv_encoder *mdp4_dtv_encoder)
+{
+	if (mdp4_dtv_encoder->bsc) {
+		msm_bus_scale_unregister_client(mdp4_dtv_encoder->bsc);
+		mdp4_dtv_encoder->bsc = 0;
+	}
+}
+
+static void bs_set(struct mdp4_dtv_encoder *mdp4_dtv_encoder, int idx)
+{
+	if (mdp4_dtv_encoder->bsc) {
+		DBG("set bus scaling: %d", idx);
+		msm_bus_scale_client_update_request(mdp4_dtv_encoder->bsc, idx);
+	}
+}
+#else
+static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder) {}
+static void bs_fini(struct mdp4_dtv_encoder *mdp4_dtv_encoder) {}
+static void bs_set(struct mdp4_dtv_encoder *mdp4_dtv_encoder, int idx) {}
+#endif
+
+static void mdp4_dtv_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+	bs_fini(mdp4_dtv_encoder);
+	drm_encoder_cleanup(encoder);
+	kfree(mdp4_dtv_encoder);
+}
+
+static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = {
+	.destroy = mdp4_dtv_encoder_destroy,
+};
+
+static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+	uint32_t display_v_start, display_v_end;
+	uint32_t hsync_start_x, hsync_end_x;
+
+	mode = adjusted_mode;
+
+	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+
+	mdp4_dtv_encoder->pixclock = mode->clock * 1000;
+
+	DBG("pixclock=%lu", mdp4_dtv_encoder->pixclock);
+
+	ctrl_pol = 0;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		ctrl_pol |= MDP4_DTV_CTRL_POLARITY_HSYNC_LOW;
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		ctrl_pol |= MDP4_DTV_CTRL_POLARITY_VSYNC_LOW;
+	/* probably need to get DATA_EN polarity from panel.. */
+
+	dtv_hsync_skew = 0;  /* get this from panel? */
+
+	hsync_start_x = (mode->htotal - mode->hsync_start);
+	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
+
+	vsync_period = mode->vtotal * mode->htotal;
+	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
+	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
+	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
+
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_HSYNC_CTRL,
+			MDP4_DTV_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
+			MDP4_DTV_HSYNC_CTRL_PERIOD(mode->htotal));
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_VSYNC_PERIOD, vsync_period);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_VSYNC_LEN, vsync_len);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_HCTRL,
+			MDP4_DTV_DISPLAY_HCTRL_START(hsync_start_x) |
+			MDP4_DTV_DISPLAY_HCTRL_END(hsync_end_x));
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_VSTART, display_v_start);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_VEND, display_v_end);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_BORDER_CLR, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_UNDERFLOW_CLR,
+			MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY |
+			MDP4_DTV_UNDERFLOW_CLR_COLOR(0xff));
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_HSYNC_SKEW, dtv_hsync_skew);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_CTRL_POLARITY, ctrl_pol);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_HCTL,
+			MDP4_DTV_ACTIVE_HCTL_START(0) |
+			MDP4_DTV_ACTIVE_HCTL_END(0));
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
+}
+
+static void mdp4_dtv_encoder_disable(struct drm_encoder *encoder)
+{
+	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+
+	if (WARN_ON(!mdp4_dtv_encoder->enabled))
+		return;
+
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
+
+	/*
+	 * Wait for a vsync so we know the ENABLE=0 latched before
+	 * the (connector) source of the vsync's gets disabled,
+	 * otherwise we end up in a funny state if we re-enable
+	 * before the disable latches, which results that some of
+	 * the settings changes for the new modeset (like new
+	 * scanout buffer) don't latch properly..
+	 */
+	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC);
+
+	clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
+	clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
+
+	bs_set(mdp4_dtv_encoder, 0);
+
+	mdp4_dtv_encoder->enabled = false;
+}
+
+static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	unsigned long pc = mdp4_dtv_encoder->pixclock;
+	int ret;
+
+	if (WARN_ON(mdp4_dtv_encoder->enabled))
+		return;
+
+	mdp4_crtc_set_config(encoder->crtc,
+			MDP4_DMA_CONFIG_R_BPC(BPC8) |
+			MDP4_DMA_CONFIG_G_BPC(BPC8) |
+			MDP4_DMA_CONFIG_B_BPC(BPC8) |
+			MDP4_DMA_CONFIG_PACK(0x21));
+	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1);
+
+	bs_set(mdp4_dtv_encoder, 1);
+
+	DBG("setting mdp_clk=%lu", pc);
+
+	ret = clk_set_rate(mdp4_dtv_encoder->mdp_clk, pc);
+	if (ret)
+		dev_err(dev->dev, "failed to set mdp_clk to %lu: %d\n",
+			pc, ret);
+
+	ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
+	if (ret)
+		dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
+
+	ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
+	if (ret)
+		dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1);
+
+	mdp4_dtv_encoder->enabled = true;
+}
+
+static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = {
+	.mode_set = mdp4_dtv_encoder_mode_set,
+	.enable = mdp4_dtv_encoder_enable,
+	.disable = mdp4_dtv_encoder_disable,
+};
+
+long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
+{
+	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+	return clk_round_rate(mdp4_dtv_encoder->mdp_clk, rate);
+}
+
+/* initialize encoder */
+struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev)
+{
+	struct drm_encoder *encoder = NULL;
+	struct mdp4_dtv_encoder *mdp4_dtv_encoder;
+	int ret;
+
+	mdp4_dtv_encoder = kzalloc(sizeof(*mdp4_dtv_encoder), GFP_KERNEL);
+	if (!mdp4_dtv_encoder) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	encoder = &mdp4_dtv_encoder->base;
+
+	drm_encoder_init(dev, encoder, &mdp4_dtv_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
+	drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs);
+
+	mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk");
+	if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) {
+		dev_err(dev->dev, "failed to get hdmi_clk\n");
+		ret = PTR_ERR(mdp4_dtv_encoder->hdmi_clk);
+		goto fail;
+	}
+
+	mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "tv_clk");
+	if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) {
+		dev_err(dev->dev, "failed to get tv_clk\n");
+		ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk);
+		goto fail;
+	}
+
+	bs_init(mdp4_dtv_encoder);
+
+	return encoder;
+
+fail:
+	if (encoder)
+		mdp4_dtv_encoder_destroy(encoder);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
new file mode 100644
index 000000000000..b764d7f10312
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_print.h>
+
+#include "msm_drv.h"
+#include "mdp4_kms.h"
+
+void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+		uint32_t old_irqmask)
+{
+	mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_CLEAR,
+		irqmask ^ (irqmask & old_irqmask));
+	mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask);
+}
+
+static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp4_kms *mdp4_kms = container_of(irq, struct mdp4_kms, error_handler);
+	static DEFINE_RATELIMIT_STATE(rs, 5*HZ, 1);
+	extern bool dumpstate;
+
+	DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
+
+	if (dumpstate && __ratelimit(&rs)) {
+		struct drm_printer p = drm_info_printer(mdp4_kms->dev->dev);
+		drm_state_dump(mdp4_kms->dev, &p);
+	}
+}
+
+void mdp4_irq_preinstall(struct msm_kms *kms)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	mdp4_enable(mdp4_kms);
+	mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
+	mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+	mdp4_disable(mdp4_kms);
+}
+
+int mdp4_irq_postinstall(struct msm_kms *kms)
+{
+	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
+	struct mdp_irq *error_handler = &mdp4_kms->error_handler;
+
+	error_handler->irq = mdp4_irq_error_handler;
+	error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN |
+			MDP4_IRQ_EXTERNAL_INTF_UDERRUN;
+
+	mdp_irq_register(mdp_kms, error_handler);
+
+	return 0;
+}
+
+void mdp4_irq_uninstall(struct msm_kms *kms)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	mdp4_enable(mdp4_kms);
+	mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+	mdp4_disable(mdp4_kms);
+}
+
+irqreturn_t mdp4_irq(struct msm_kms *kms)
+{
+	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
+	struct drm_device *dev = mdp4_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	unsigned int id;
+	uint32_t status, enable;
+
+	enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE);
+	status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS) & enable;
+	mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status);
+
+	VERB("status=%08x", status);
+
+	mdp_dispatch_irqs(mdp_kms, status);
+
+	for (id = 0; id < priv->num_crtcs; id++)
+		if (status & mdp4_crtc_vblank(priv->crtcs[id]))
+			drm_handle_vblank(dev, id);
+
+	return IRQ_HANDLED;
+}
+
+int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+
+	mdp4_enable(mdp4_kms);
+	mdp_update_vblank_mask(to_mdp_kms(kms),
+			mdp4_crtc_vblank(crtc), true);
+	mdp4_disable(mdp4_kms);
+
+	return 0;
+}
+
+void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+
+	mdp4_enable(mdp4_kms);
+	mdp_update_vblank_mask(to_mdp_kms(kms),
+			mdp4_crtc_vblank(crtc), false);
+	mdp4_disable(mdp4_kms);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
new file mode 100644
index 000000000000..4b646bf9c214
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "msm_drv.h"
+#include "msm_gem.h"
+#include "msm_mmu.h"
+#include "mdp4_kms.h"
+
+static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev);
+
+static int mdp4_hw_init(struct msm_kms *kms)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	struct drm_device *dev = mdp4_kms->dev;
+	uint32_t version, major, minor, dmap_cfg, vg_cfg;
+	unsigned long clk;
+	int ret = 0;
+
+	pm_runtime_get_sync(dev->dev);
+
+	mdp4_enable(mdp4_kms);
+	version = mdp4_read(mdp4_kms, REG_MDP4_VERSION);
+	mdp4_disable(mdp4_kms);
+
+	major = FIELD(version, MDP4_VERSION_MAJOR);
+	minor = FIELD(version, MDP4_VERSION_MINOR);
+
+	DBG("found MDP4 version v%d.%d", major, minor);
+
+	if (major != 4) {
+		dev_err(dev->dev, "unexpected MDP version: v%d.%d\n",
+				major, minor);
+		ret = -ENXIO;
+		goto out;
+	}
+
+	mdp4_kms->rev = minor;
+
+	if (mdp4_kms->rev > 1) {
+		mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER0, 0x0707ffff);
+		mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER1, 0x03073f3f);
+	}
+
+	mdp4_write(mdp4_kms, REG_MDP4_PORTMAP_MODE, 0x3);
+
+	/* max read pending cmd config, 3 pending requests: */
+	mdp4_write(mdp4_kms, REG_MDP4_READ_CNFG, 0x02222);
+
+	clk = clk_get_rate(mdp4_kms->clk);
+
+	if ((mdp4_kms->rev >= 1) || (clk >= 90000000)) {
+		dmap_cfg = 0x47;     /* 16 bytes-burst x 8 req */
+		vg_cfg = 0x47;       /* 16 bytes-burs x 8 req */
+	} else {
+		dmap_cfg = 0x27;     /* 8 bytes-burst x 8 req */
+		vg_cfg = 0x43;       /* 16 bytes-burst x 4 req */
+	}
+
+	DBG("fetch config: dmap=%02x, vg=%02x", dmap_cfg, vg_cfg);
+
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_P), dmap_cfg);
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_E), dmap_cfg);
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG1), vg_cfg);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG2), vg_cfg);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB1), vg_cfg);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB2), vg_cfg);
+
+	if (mdp4_kms->rev >= 2)
+		mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1);
+	mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0);
+
+	/* disable CSC matrix / YUV by default: */
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG2), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_P_OP_MODE, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DMA_S_OP_MODE, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(1), 0);
+	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(2), 0);
+
+	if (mdp4_kms->rev > 1)
+		mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1);
+
+	dev->mode_config.allow_fb_modifiers = true;
+
+out:
+	pm_runtime_put_sync(dev->dev);
+
+	return ret;
+}
+
+static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	int i;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+
+	mdp4_enable(mdp4_kms);
+
+	/* see 119ecb7fd */
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i)
+		drm_crtc_vblank_get(crtc);
+}
+
+static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	int i;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+
+	/* see 119ecb7fd */
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i)
+		drm_crtc_vblank_put(crtc);
+
+	mdp4_disable(mdp4_kms);
+}
+
+static void mdp4_wait_for_crtc_commit_done(struct msm_kms *kms,
+						struct drm_crtc *crtc)
+{
+	mdp4_crtc_wait_for_commit_done(crtc);
+}
+
+static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
+		struct drm_encoder *encoder)
+{
+	/* if we had >1 encoder, we'd need something more clever: */
+	switch (encoder->encoder_type) {
+	case DRM_MODE_ENCODER_TMDS:
+		return mdp4_dtv_round_pixclk(encoder, rate);
+	case DRM_MODE_ENCODER_LVDS:
+	case DRM_MODE_ENCODER_DSI:
+	default:
+		return rate;
+	}
+}
+
+static const char * const iommu_ports[] = {
+	"mdp_port0_cb0", "mdp_port1_cb0",
+};
+
+static void mdp4_destroy(struct msm_kms *kms)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	struct device *dev = mdp4_kms->dev->dev;
+	struct msm_gem_address_space *aspace = kms->aspace;
+
+	if (mdp4_kms->blank_cursor_iova)
+		msm_gem_put_iova(mdp4_kms->blank_cursor_bo, kms->aspace);
+	drm_gem_object_put_unlocked(mdp4_kms->blank_cursor_bo);
+
+	if (aspace) {
+		aspace->mmu->funcs->detach(aspace->mmu,
+				iommu_ports, ARRAY_SIZE(iommu_ports));
+		msm_gem_address_space_put(aspace);
+	}
+
+	if (mdp4_kms->rpm_enabled)
+		pm_runtime_disable(dev);
+
+	kfree(mdp4_kms);
+}
+
+static const struct mdp_kms_funcs kms_funcs = {
+	.base = {
+		.hw_init         = mdp4_hw_init,
+		.irq_preinstall  = mdp4_irq_preinstall,
+		.irq_postinstall = mdp4_irq_postinstall,
+		.irq_uninstall   = mdp4_irq_uninstall,
+		.irq             = mdp4_irq,
+		.enable_vblank   = mdp4_enable_vblank,
+		.disable_vblank  = mdp4_disable_vblank,
+		.prepare_commit  = mdp4_prepare_commit,
+		.complete_commit = mdp4_complete_commit,
+		.wait_for_crtc_commit_done = mdp4_wait_for_crtc_commit_done,
+		.get_format      = mdp_get_format,
+		.round_pixclk    = mdp4_round_pixclk,
+		.destroy         = mdp4_destroy,
+	},
+	.set_irqmask         = mdp4_set_irqmask,
+};
+
+int mdp4_disable(struct mdp4_kms *mdp4_kms)
+{
+	DBG("");
+
+	clk_disable_unprepare(mdp4_kms->clk);
+	if (mdp4_kms->pclk)
+		clk_disable_unprepare(mdp4_kms->pclk);
+	clk_disable_unprepare(mdp4_kms->lut_clk);
+	if (mdp4_kms->axi_clk)
+		clk_disable_unprepare(mdp4_kms->axi_clk);
+
+	return 0;
+}
+
+int mdp4_enable(struct mdp4_kms *mdp4_kms)
+{
+	DBG("");
+
+	clk_prepare_enable(mdp4_kms->clk);
+	if (mdp4_kms->pclk)
+		clk_prepare_enable(mdp4_kms->pclk);
+	clk_prepare_enable(mdp4_kms->lut_clk);
+	if (mdp4_kms->axi_clk)
+		clk_prepare_enable(mdp4_kms->axi_clk);
+
+	return 0;
+}
+
+
+static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
+				  int intf_type)
+{
+	struct drm_device *dev = mdp4_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct device_node *panel_node;
+	int dsi_id;
+	int ret;
+
+	switch (intf_type) {
+	case DRM_MODE_ENCODER_LVDS:
+		/*
+		 * bail out early if there is no panel node (no need to
+		 * initialize LCDC encoder and LVDS connector)
+		 */
+		panel_node = of_graph_get_remote_node(dev->dev->of_node, 0, 0);
+		if (!panel_node)
+			return 0;
+
+		encoder = mdp4_lcdc_encoder_init(dev, panel_node);
+		if (IS_ERR(encoder)) {
+			dev_err(dev->dev, "failed to construct LCDC encoder\n");
+			return PTR_ERR(encoder);
+		}
+
+		/* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
+		encoder->possible_crtcs = 1 << DMA_P;
+
+		connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
+		if (IS_ERR(connector)) {
+			dev_err(dev->dev, "failed to initialize LVDS connector\n");
+			return PTR_ERR(connector);
+		}
+
+		priv->encoders[priv->num_encoders++] = encoder;
+		priv->connectors[priv->num_connectors++] = connector;
+
+		break;
+	case DRM_MODE_ENCODER_TMDS:
+		encoder = mdp4_dtv_encoder_init(dev);
+		if (IS_ERR(encoder)) {
+			dev_err(dev->dev, "failed to construct DTV encoder\n");
+			return PTR_ERR(encoder);
+		}
+
+		/* DTV can be hooked to DMA_E: */
+		encoder->possible_crtcs = 1 << 1;
+
+		if (priv->hdmi) {
+			/* Construct bridge/connector for HDMI: */
+			ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);
+			if (ret) {
+				dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+				return ret;
+			}
+		}
+
+		priv->encoders[priv->num_encoders++] = encoder;
+
+		break;
+	case DRM_MODE_ENCODER_DSI:
+		/* only DSI1 supported for now */
+		dsi_id = 0;
+
+		if (!priv->dsi[dsi_id])
+			break;
+
+		encoder = mdp4_dsi_encoder_init(dev);
+		if (IS_ERR(encoder)) {
+			ret = PTR_ERR(encoder);
+			dev_err(dev->dev,
+				"failed to construct DSI encoder: %d\n", ret);
+			return ret;
+		}
+
+		/* TODO: Add DMA_S later? */
+		encoder->possible_crtcs = 1 << DMA_P;
+		priv->encoders[priv->num_encoders++] = encoder;
+
+		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
+		if (ret) {
+			dev_err(dev->dev, "failed to initialize DSI: %d\n",
+				ret);
+			return ret;
+		}
+
+		break;
+	default:
+		dev_err(dev->dev, "Invalid or unsupported interface\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int modeset_init(struct mdp4_kms *mdp4_kms)
+{
+	struct drm_device *dev = mdp4_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	int i, ret;
+	static const enum mdp4_pipe rgb_planes[] = {
+		RGB1, RGB2,
+	};
+	static const enum mdp4_pipe vg_planes[] = {
+		VG1, VG2,
+	};
+	static const enum mdp4_dma mdp4_crtcs[] = {
+		DMA_P, DMA_E,
+	};
+	static const char * const mdp4_crtc_names[] = {
+		"DMA_P", "DMA_E",
+	};
+	static const int mdp4_intfs[] = {
+		DRM_MODE_ENCODER_LVDS,
+		DRM_MODE_ENCODER_DSI,
+		DRM_MODE_ENCODER_TMDS,
+	};
+
+	/* construct non-private planes: */
+	for (i = 0; i < ARRAY_SIZE(vg_planes); i++) {
+		plane = mdp4_plane_init(dev, vg_planes[i], false);
+		if (IS_ERR(plane)) {
+			dev_err(dev->dev,
+				"failed to construct plane for VG%d\n", i + 1);
+			ret = PTR_ERR(plane);
+			goto fail;
+		}
+		priv->planes[priv->num_planes++] = plane;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mdp4_crtcs); i++) {
+		plane = mdp4_plane_init(dev, rgb_planes[i], true);
+		if (IS_ERR(plane)) {
+			dev_err(dev->dev,
+				"failed to construct plane for RGB%d\n", i + 1);
+			ret = PTR_ERR(plane);
+			goto fail;
+		}
+
+		crtc  = mdp4_crtc_init(dev, plane, priv->num_crtcs, i,
+				mdp4_crtcs[i]);
+		if (IS_ERR(crtc)) {
+			dev_err(dev->dev, "failed to construct crtc for %s\n",
+				mdp4_crtc_names[i]);
+			ret = PTR_ERR(crtc);
+			goto fail;
+		}
+
+		priv->crtcs[priv->num_crtcs++] = crtc;
+	}
+
+	/*
+	 * we currently set up two relatively fixed paths:
+	 *
+	 * LCDC/LVDS path: RGB1 -> DMA_P -> LCDC -> LVDS
+	 *			or
+	 * DSI path: RGB1 -> DMA_P -> DSI1 -> DSI Panel
+	 *
+	 * DTV/HDMI path: RGB2 -> DMA_E -> DTV -> HDMI
+	 */
+
+	for (i = 0; i < ARRAY_SIZE(mdp4_intfs); i++) {
+		ret = mdp4_modeset_init_intf(mdp4_kms, mdp4_intfs[i]);
+		if (ret) {
+			dev_err(dev->dev, "failed to initialize intf: %d, %d\n",
+				i, ret);
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+struct msm_kms *mdp4_kms_init(struct drm_device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev->dev);
+	struct mdp4_platform_config *config = mdp4_get_config(pdev);
+	struct mdp4_kms *mdp4_kms;
+	struct msm_kms *kms = NULL;
+	struct msm_gem_address_space *aspace;
+	int irq, ret;
+
+	mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
+	if (!mdp4_kms) {
+		dev_err(dev->dev, "failed to allocate kms\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	mdp_kms_init(&mdp4_kms->base, &kms_funcs);
+
+	kms = &mdp4_kms->base.base;
+
+	mdp4_kms->dev = dev;
+
+	mdp4_kms->mmio = msm_ioremap(pdev, NULL, "MDP4");
+	if (IS_ERR(mdp4_kms->mmio)) {
+		ret = PTR_ERR(mdp4_kms->mmio);
+		goto fail;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = irq;
+		dev_err(dev->dev, "failed to get irq: %d\n", ret);
+		goto fail;
+	}
+
+	kms->irq = irq;
+
+	/* NOTE: driver for this regulator still missing upstream.. use
+	 * _get_exclusive() and ignore the error if it does not exist
+	 * (and hope that the bootloader left it on for us)
+	 */
+	mdp4_kms->vdd = devm_regulator_get_exclusive(&pdev->dev, "vdd");
+	if (IS_ERR(mdp4_kms->vdd))
+		mdp4_kms->vdd = NULL;
+
+	if (mdp4_kms->vdd) {
+		ret = regulator_enable(mdp4_kms->vdd);
+		if (ret) {
+			dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret);
+			goto fail;
+		}
+	}
+
+	mdp4_kms->clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(mdp4_kms->clk)) {
+		dev_err(dev->dev, "failed to get core_clk\n");
+		ret = PTR_ERR(mdp4_kms->clk);
+		goto fail;
+	}
+
+	mdp4_kms->pclk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(mdp4_kms->pclk))
+		mdp4_kms->pclk = NULL;
+
+	// XXX if (rev >= MDP_REV_42) { ???
+	mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk");
+	if (IS_ERR(mdp4_kms->lut_clk)) {
+		dev_err(dev->dev, "failed to get lut_clk\n");
+		ret = PTR_ERR(mdp4_kms->lut_clk);
+		goto fail;
+	}
+
+	mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(mdp4_kms->axi_clk)) {
+		dev_err(dev->dev, "failed to get axi_clk\n");
+		ret = PTR_ERR(mdp4_kms->axi_clk);
+		goto fail;
+	}
+
+	clk_set_rate(mdp4_kms->clk, config->max_clk);
+	clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
+
+	pm_runtime_enable(dev->dev);
+	mdp4_kms->rpm_enabled = true;
+
+	/* make sure things are off before attaching iommu (bootloader could
+	 * have left things on, in which case we'll start getting faults if
+	 * we don't disable):
+	 */
+	mdp4_enable(mdp4_kms);
+	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
+	mdp4_disable(mdp4_kms);
+	mdelay(16);
+
+	if (config->iommu) {
+		aspace = msm_gem_address_space_create(&pdev->dev,
+				config->iommu, "mdp4");
+		if (IS_ERR(aspace)) {
+			ret = PTR_ERR(aspace);
+			goto fail;
+		}
+
+		kms->aspace = aspace;
+
+		ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
+				ARRAY_SIZE(iommu_ports));
+		if (ret)
+			goto fail;
+	} else {
+		dev_info(dev->dev, "no iommu, fallback to phys "
+				"contig buffers for scanout\n");
+		aspace = NULL;
+	}
+
+	ret = modeset_init(mdp4_kms);
+	if (ret) {
+		dev_err(dev->dev, "modeset_init failed: %d\n", ret);
+		goto fail;
+	}
+
+	mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC);
+	if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
+		ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
+		dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
+		mdp4_kms->blank_cursor_bo = NULL;
+		goto fail;
+	}
+
+	ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, kms->aspace,
+			&mdp4_kms->blank_cursor_iova);
+	if (ret) {
+		dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
+		goto fail;
+	}
+
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+	dev->mode_config.max_width = 2048;
+	dev->mode_config.max_height = 2048;
+
+	return kms;
+
+fail:
+	if (kms)
+		mdp4_destroy(kms);
+	return ERR_PTR(ret);
+}
+
+static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
+{
+	static struct mdp4_platform_config config = {};
+
+	/* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
+	config.max_clk = 266667000;
+	config.iommu = iommu_domain_alloc(&platform_bus_type);
+	if (config.iommu) {
+		config.iommu->geometry.aperture_start = 0x1000;
+		config.iommu->geometry.aperture_end = 0xffffffff;
+	}
+
+	return &config;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h
new file mode 100644
index 000000000000..0c13f8697bfe
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP4_KMS_H__
+#define __MDP4_KMS_H__
+
+#include <drm/drm_panel.h>
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "disp/mdp_kms.h"
+#include "mdp4.xml.h"
+
+struct device_node;
+
+struct mdp4_kms {
+	struct mdp_kms base;
+
+	struct drm_device *dev;
+
+	int rev;
+
+	void __iomem *mmio;
+
+	struct regulator *vdd;
+
+	struct clk *clk;
+	struct clk *pclk;
+	struct clk *lut_clk;
+	struct clk *axi_clk;
+
+	struct mdp_irq error_handler;
+
+	bool rpm_enabled;
+
+	/* empty/blank cursor bo to use when cursor is "disabled" */
+	struct drm_gem_object *blank_cursor_bo;
+	uint64_t blank_cursor_iova;
+};
+#define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base)
+
+/* platform config data (ie. from DT, or pdata) */
+struct mdp4_platform_config {
+	struct iommu_domain *iommu;
+	uint32_t max_clk;
+};
+
+static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data)
+{
+	msm_writel(data, mdp4_kms->mmio + reg);
+}
+
+static inline u32 mdp4_read(struct mdp4_kms *mdp4_kms, u32 reg)
+{
+	return msm_readl(mdp4_kms->mmio + reg);
+}
+
+static inline uint32_t pipe2flush(enum mdp4_pipe pipe)
+{
+	switch (pipe) {
+	case VG1:      return MDP4_OVERLAY_FLUSH_VG1;
+	case VG2:      return MDP4_OVERLAY_FLUSH_VG2;
+	case RGB1:     return MDP4_OVERLAY_FLUSH_RGB1;
+	case RGB2:     return MDP4_OVERLAY_FLUSH_RGB2;
+	default:       return 0;
+	}
+}
+
+static inline uint32_t ovlp2flush(int ovlp)
+{
+	switch (ovlp) {
+	case 0:        return MDP4_OVERLAY_FLUSH_OVLP0;
+	case 1:        return MDP4_OVERLAY_FLUSH_OVLP1;
+	default:       return 0;
+	}
+}
+
+static inline uint32_t dma2irq(enum mdp4_dma dma)
+{
+	switch (dma) {
+	case DMA_P:    return MDP4_IRQ_DMA_P_DONE;
+	case DMA_S:    return MDP4_IRQ_DMA_S_DONE;
+	case DMA_E:    return MDP4_IRQ_DMA_E_DONE;
+	default:       return 0;
+	}
+}
+
+static inline uint32_t dma2err(enum mdp4_dma dma)
+{
+	switch (dma) {
+	case DMA_P:    return MDP4_IRQ_PRIMARY_INTF_UDERRUN;
+	case DMA_S:    return 0;  // ???
+	case DMA_E:    return MDP4_IRQ_EXTERNAL_INTF_UDERRUN;
+	default:       return 0;
+	}
+}
+
+static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
+		enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage)
+{
+	switch (pipe) {
+	case VG1:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
+		break;
+	case VG2:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
+		break;
+	case RGB1:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
+		break;
+	case RGB2:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
+		break;
+	case RGB3:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
+		break;
+	case VG3:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
+		break;
+	case VG4:
+		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK |
+				MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
+		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
+			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
+		break;
+	default:
+		WARN(1, "invalid pipe");
+		break;
+	}
+
+	return mixer_cfg;
+}
+
+int mdp4_disable(struct mdp4_kms *mdp4_kms);
+int mdp4_enable(struct mdp4_kms *mdp4_kms);
+
+void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+		uint32_t old_irqmask);
+void mdp4_irq_preinstall(struct msm_kms *kms);
+int mdp4_irq_postinstall(struct msm_kms *kms);
+void mdp4_irq_uninstall(struct msm_kms *kms);
+irqreturn_t mdp4_irq(struct msm_kms *kms);
+int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+
+static inline uint32_t mdp4_pipe_caps(enum mdp4_pipe pipe)
+{
+	switch (pipe) {
+	case VG1:
+	case VG2:
+	case VG3:
+	case VG4:
+		return MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
+	case RGB1:
+	case RGB2:
+	case RGB3:
+		return MDP_PIPE_CAP_SCALE;
+	default:
+		return 0;
+	}
+}
+
+enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane);
+struct drm_plane *mdp4_plane_init(struct drm_device *dev,
+		enum mdp4_pipe pipe_id, bool private_plane);
+
+uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
+void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
+void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
+void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc);
+struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
+		struct drm_plane *plane, int id, int ovlp_id,
+		enum mdp4_dma dma_id);
+
+long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
+struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
+
+long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
+struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
+		struct device_node *panel_node);
+
+struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
+		struct device_node *panel_node, struct drm_encoder *encoder);
+
+#ifdef CONFIG_DRM_MSM_DSI
+struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev);
+#else
+static inline struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
+#ifdef CONFIG_COMMON_CLK
+struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
+#else
+static inline struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
+#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
+/* bus scaling data is associated with extra pointless platform devices,
+ * "dtv", etc.. this is a bit of a hack, but we need a way for encoders
+ * to find their pdata to make the bus-scaling stuff work.
+ */
+static inline void *mdp4_find_pdata(const char *devname)
+{
+	struct device *dev;
+	dev = bus_find_device_by_name(&platform_bus_type, NULL, devname);
+	return dev ? dev->platform_data : NULL;
+}
+#endif
+
+#endif /* __MDP4_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
new file mode 100644
index 000000000000..4a645926edb7
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ * Author: Vinay Simha <vinaysimha@inforcecomputing.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_lcdc_encoder {
+	struct drm_encoder base;
+	struct device_node *panel_node;
+	struct drm_panel *panel;
+	struct clk *lcdc_clk;
+	unsigned long int pixclock;
+	struct regulator *regs[3];
+	bool enabled;
+	uint32_t bsc;
+};
+#define to_mdp4_lcdc_encoder(x) container_of(x, struct mdp4_lcdc_encoder, base)
+
+static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
+{
+	struct msm_drm_private *priv = encoder->dev->dev_private;
+	return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
+{
+	struct drm_device *dev = mdp4_lcdc_encoder->base.dev;
+	struct lcdc_platform_data *lcdc_pdata = mdp4_find_pdata("lvds.0");
+
+	if (!lcdc_pdata) {
+		dev_err(dev->dev, "could not find lvds pdata\n");
+		return;
+	}
+
+	if (lcdc_pdata->bus_scale_table) {
+		mdp4_lcdc_encoder->bsc = msm_bus_scale_register_client(
+				lcdc_pdata->bus_scale_table);
+		DBG("lvds : bus scale client: %08x", mdp4_lcdc_encoder->bsc);
+	}
+}
+
+static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
+{
+	if (mdp4_lcdc_encoder->bsc) {
+		msm_bus_scale_unregister_client(mdp4_lcdc_encoder->bsc);
+		mdp4_lcdc_encoder->bsc = 0;
+	}
+}
+
+static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx)
+{
+	if (mdp4_lcdc_encoder->bsc) {
+		DBG("set bus scaling: %d", idx);
+		msm_bus_scale_client_update_request(mdp4_lcdc_encoder->bsc, idx);
+	}
+}
+#else
+static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
+static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
+static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx) {}
+#endif
+
+static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+			to_mdp4_lcdc_encoder(encoder);
+	bs_fini(mdp4_lcdc_encoder);
+	drm_encoder_cleanup(encoder);
+	kfree(mdp4_lcdc_encoder);
+}
+
+static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = {
+	.destroy = mdp4_lcdc_encoder_destroy,
+};
+
+/* this should probably be a helper: */
+static struct drm_connector *get_connector(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct drm_connector *connector;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+		if (connector->encoder == encoder)
+			return connector;
+
+	return NULL;
+}
+
+static void setup_phy(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct drm_connector *connector = get_connector(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	uint32_t lvds_intf = 0, lvds_phy_cfg0 = 0;
+	int bpp, nchan, swap;
+
+	if (!connector)
+		return;
+
+	bpp = 3 * connector->display_info.bpc;
+
+	if (!bpp)
+		bpp = 18;
+
+	/* TODO, these should come from panel somehow: */
+	nchan = 1;
+	swap = 0;
+
+	switch (bpp) {
+	case 24:
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x08) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x05) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x04) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x03));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x02) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x01) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x00));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x11) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x10) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0d) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0c));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0b) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0a) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x09));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x15));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x14) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x13) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x12));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(3),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1b) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x17) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x16) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0f));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(3),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0e) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x07) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x06));
+		if (nchan == 2) {
+			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+		} else {
+			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+		}
+		break;
+
+	case 18:
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x0a) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x07) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x06) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x05));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x04) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x03) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x02));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x13) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x12) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0f) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0e));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0d) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0c) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x0b));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
+				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x17));
+		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x16) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x15) |
+				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x14));
+		if (nchan == 2) {
+			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+		} else {
+			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
+					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
+		}
+		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT;
+		break;
+
+	default:
+		dev_err(dev->dev, "unknown bpp: %d\n", bpp);
+		return;
+	}
+
+	switch (nchan) {
+	case 1:
+		lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0;
+		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN |
+				MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL;
+		break;
+	case 2:
+		lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0 |
+				MDP4_LVDS_PHY_CFG0_CHANNEL1;
+		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN |
+				MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN;
+		break;
+	default:
+		dev_err(dev->dev, "unknown # of channels: %d\n", nchan);
+		return;
+	}
+
+	if (swap)
+		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP;
+
+	lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_ENABLE;
+
+	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_INTF_CTL, lvds_intf);
+	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG2, 0x30);
+
+	mb();
+	udelay(1);
+	lvds_phy_cfg0 |= MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE;
+	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
+}
+
+static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+			to_mdp4_lcdc_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	uint32_t lcdc_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+	uint32_t display_v_start, display_v_end;
+	uint32_t hsync_start_x, hsync_end_x;
+
+	mode = adjusted_mode;
+
+	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+
+	mdp4_lcdc_encoder->pixclock = mode->clock * 1000;
+
+	DBG("pixclock=%lu", mdp4_lcdc_encoder->pixclock);
+
+	ctrl_pol = 0;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW;
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW;
+	/* probably need to get DATA_EN polarity from panel.. */
+
+	lcdc_hsync_skew = 0;  /* get this from panel? */
+
+	hsync_start_x = (mode->htotal - mode->hsync_start);
+	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
+
+	vsync_period = mode->vtotal * mode->htotal;
+	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
+	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + lcdc_hsync_skew;
+	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + lcdc_hsync_skew - 1;
+
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_CTRL,
+			MDP4_LCDC_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
+			MDP4_LCDC_HSYNC_CTRL_PERIOD(mode->htotal));
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_PERIOD, vsync_period);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_LEN, vsync_len);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_HCTRL,
+			MDP4_LCDC_DISPLAY_HCTRL_START(hsync_start_x) |
+			MDP4_LCDC_DISPLAY_HCTRL_END(hsync_end_x));
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VSTART, display_v_start);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VEND, display_v_end);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_BORDER_CLR, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_UNDERFLOW_CLR,
+			MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY |
+			MDP4_LCDC_UNDERFLOW_CLR_COLOR(0xff));
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_SKEW, lcdc_hsync_skew);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_CTRL_POLARITY, ctrl_pol);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_HCTL,
+			MDP4_LCDC_ACTIVE_HCTL_START(0) |
+			MDP4_LCDC_ACTIVE_HCTL_END(0));
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VSTART, 0);
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
+}
+
+static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+			to_mdp4_lcdc_encoder(encoder);
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	struct drm_panel *panel;
+	int i, ret;
+
+	if (WARN_ON(!mdp4_lcdc_encoder->enabled))
+		return;
+
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
+
+	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
+	if (panel) {
+		drm_panel_disable(panel);
+		drm_panel_unprepare(panel);
+	}
+
+	/*
+	 * Wait for a vsync so we know the ENABLE=0 latched before
+	 * the (connector) source of the vsync's gets disabled,
+	 * otherwise we end up in a funny state if we re-enable
+	 * before the disable latches, which results that some of
+	 * the settings changes for the new modeset (like new
+	 * scanout buffer) don't latch properly..
+	 */
+	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
+
+	clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
+
+	for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
+		ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
+		if (ret)
+			dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
+	}
+
+	bs_set(mdp4_lcdc_encoder, 0);
+
+	mdp4_lcdc_encoder->enabled = false;
+}
+
+static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+			to_mdp4_lcdc_encoder(encoder);
+	unsigned long pc = mdp4_lcdc_encoder->pixclock;
+	struct mdp4_kms *mdp4_kms = get_kms(encoder);
+	struct drm_panel *panel;
+	int i, ret;
+
+	if (WARN_ON(mdp4_lcdc_encoder->enabled))
+		return;
+
+	/* TODO: hard-coded for 18bpp: */
+	mdp4_crtc_set_config(encoder->crtc,
+			MDP4_DMA_CONFIG_R_BPC(BPC6) |
+			MDP4_DMA_CONFIG_G_BPC(BPC6) |
+			MDP4_DMA_CONFIG_B_BPC(BPC6) |
+			MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
+			MDP4_DMA_CONFIG_PACK(0x21) |
+			MDP4_DMA_CONFIG_DEFLKR_EN |
+			MDP4_DMA_CONFIG_DITHER_EN);
+	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
+
+	bs_set(mdp4_lcdc_encoder, 1);
+
+	for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
+		ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
+		if (ret)
+			dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
+	}
+
+	DBG("setting lcdc_clk=%lu", pc);
+	ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
+	if (ret)
+		dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
+	ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
+	if (ret)
+		dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
+
+	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
+	if (panel) {
+		drm_panel_prepare(panel);
+		drm_panel_enable(panel);
+	}
+
+	setup_phy(encoder);
+
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
+
+	mdp4_lcdc_encoder->enabled = true;
+}
+
+static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
+	.mode_set = mdp4_lcdc_encoder_mode_set,
+	.disable = mdp4_lcdc_encoder_disable,
+	.enable = mdp4_lcdc_encoder_enable,
+};
+
+long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
+{
+	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+			to_mdp4_lcdc_encoder(encoder);
+	return clk_round_rate(mdp4_lcdc_encoder->lcdc_clk, rate);
+}
+
+/* initialize encoder */
+struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
+		struct device_node *panel_node)
+{
+	struct drm_encoder *encoder = NULL;
+	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
+	struct regulator *reg;
+	int ret;
+
+	mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL);
+	if (!mdp4_lcdc_encoder) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	mdp4_lcdc_encoder->panel_node = panel_node;
+
+	encoder = &mdp4_lcdc_encoder->base;
+
+	drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs,
+			 DRM_MODE_ENCODER_LVDS, NULL);
+	drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
+
+	/* TODO: do we need different pll in other cases? */
+	mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev);
+	if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
+		dev_err(dev->dev, "failed to get lvds_clk\n");
+		ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk);
+		goto fail;
+	}
+
+	/* TODO: different regulators in other cases? */
+	reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v");
+	if (IS_ERR(reg)) {
+		ret = PTR_ERR(reg);
+		dev_err(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
+		goto fail;
+	}
+	mdp4_lcdc_encoder->regs[0] = reg;
+
+	reg = devm_regulator_get(dev->dev, "lvds-pll-vdda");
+	if (IS_ERR(reg)) {
+		ret = PTR_ERR(reg);
+		dev_err(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
+		goto fail;
+	}
+	mdp4_lcdc_encoder->regs[1] = reg;
+
+	reg = devm_regulator_get(dev->dev, "lvds-vdda");
+	if (IS_ERR(reg)) {
+		ret = PTR_ERR(reg);
+		dev_err(dev->dev, "failed to get lvds-vdda: %d\n", ret);
+		goto fail;
+	}
+	mdp4_lcdc_encoder->regs[2] = reg;
+
+	bs_init(mdp4_lcdc_encoder);
+
+	return encoder;
+
+fail:
+	if (encoder)
+		mdp4_lcdc_encoder_destroy(encoder);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
new file mode 100644
index 000000000000..e3b1c86b7aae
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ * Author: Vinay Simha <vinaysimha@inforcecomputing.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/gpio.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_lvds_connector {
+	struct drm_connector base;
+	struct drm_encoder *encoder;
+	struct device_node *panel_node;
+	struct drm_panel *panel;
+};
+#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
+
+static enum drm_connector_status mdp4_lvds_connector_detect(
+		struct drm_connector *connector, bool force)
+{
+	struct mdp4_lvds_connector *mdp4_lvds_connector =
+			to_mdp4_lvds_connector(connector);
+
+	if (!mdp4_lvds_connector->panel)
+		mdp4_lvds_connector->panel =
+			of_drm_find_panel(mdp4_lvds_connector->panel_node);
+
+	return mdp4_lvds_connector->panel ?
+			connector_status_connected :
+			connector_status_disconnected;
+}
+
+static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
+{
+	struct mdp4_lvds_connector *mdp4_lvds_connector =
+			to_mdp4_lvds_connector(connector);
+
+	drm_connector_cleanup(connector);
+
+	kfree(mdp4_lvds_connector);
+}
+
+static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
+{
+	struct mdp4_lvds_connector *mdp4_lvds_connector =
+			to_mdp4_lvds_connector(connector);
+	struct drm_panel *panel = mdp4_lvds_connector->panel;
+	int ret = 0;
+
+	if (panel) {
+		drm_panel_attach(panel, connector);
+
+		ret = panel->funcs->get_modes(panel);
+
+		drm_panel_detach(panel);
+	}
+
+	return ret;
+}
+
+static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
+				 struct drm_display_mode *mode)
+{
+	struct mdp4_lvds_connector *mdp4_lvds_connector =
+			to_mdp4_lvds_connector(connector);
+	struct drm_encoder *encoder = mdp4_lvds_connector->encoder;
+	long actual, requested;
+
+	requested = 1000 * mode->clock;
+	actual = mdp4_lcdc_round_pixclk(encoder, requested);
+
+	DBG("requested=%ld, actual=%ld", requested, actual);
+
+	if (actual != requested)
+		return MODE_CLOCK_RANGE;
+
+	return MODE_OK;
+}
+
+static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
+	.detect = mdp4_lvds_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = mdp4_lvds_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
+	.get_modes = mdp4_lvds_connector_get_modes,
+	.mode_valid = mdp4_lvds_connector_mode_valid,
+};
+
+/* initialize connector */
+struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
+		struct device_node *panel_node, struct drm_encoder *encoder)
+{
+	struct drm_connector *connector = NULL;
+	struct mdp4_lvds_connector *mdp4_lvds_connector;
+
+	mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL);
+	if (!mdp4_lvds_connector)
+		return ERR_PTR(-ENOMEM);
+
+	mdp4_lvds_connector->encoder = encoder;
+	mdp4_lvds_connector->panel_node = panel_node;
+
+	connector = &mdp4_lvds_connector->base;
+
+	drm_connector_init(dev, connector, &mdp4_lvds_connector_funcs,
+			DRM_MODE_CONNECTOR_LVDS);
+	drm_connector_helper_add(connector, &mdp4_lvds_connector_helper_funcs);
+
+	connector->polled = 0;
+
+	connector->interlace_allowed = 0;
+	connector->doublescan_allowed = 0;
+
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	return connector;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c
new file mode 100644
index 000000000000..ce4245971673
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include "mdp4_kms.h"
+
+struct mdp4_lvds_pll {
+	struct clk_hw pll_hw;
+	struct drm_device *dev;
+	unsigned long pixclk;
+};
+#define to_mdp4_lvds_pll(x) container_of(x, struct mdp4_lvds_pll, pll_hw)
+
+static struct mdp4_kms *get_kms(struct mdp4_lvds_pll *lvds_pll)
+{
+	struct msm_drm_private *priv = lvds_pll->dev->dev_private;
+	return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+struct pll_rate {
+	unsigned long rate;
+	struct {
+		uint32_t val;
+		uint32_t reg;
+	} conf[32];
+};
+
+/* NOTE: keep sorted highest freq to lowest: */
+static const struct pll_rate freqtbl[] = {
+	{ 72000000, {
+		{ 0x8f, REG_MDP4_LVDS_PHY_PLL_CTRL_1 },
+		{ 0x30, REG_MDP4_LVDS_PHY_PLL_CTRL_2 },
+		{ 0xc6, REG_MDP4_LVDS_PHY_PLL_CTRL_3 },
+		{ 0x10, REG_MDP4_LVDS_PHY_PLL_CTRL_5 },
+		{ 0x07, REG_MDP4_LVDS_PHY_PLL_CTRL_6 },
+		{ 0x62, REG_MDP4_LVDS_PHY_PLL_CTRL_7 },
+		{ 0x41, REG_MDP4_LVDS_PHY_PLL_CTRL_8 },
+		{ 0x0d, REG_MDP4_LVDS_PHY_PLL_CTRL_9 },
+		{ 0, 0 } }
+	},
+};
+
+static const struct pll_rate *find_rate(unsigned long rate)
+{
+	int i;
+	for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
+		if (rate > freqtbl[i].rate)
+			return &freqtbl[i-1];
+	return &freqtbl[i-1];
+}
+
+static int mpd4_lvds_pll_enable(struct clk_hw *hw)
+{
+	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
+	const struct pll_rate *pll_rate = find_rate(lvds_pll->pixclk);
+	int i;
+
+	DBG("pixclk=%lu (%lu)", lvds_pll->pixclk, pll_rate->rate);
+
+	if (WARN_ON(!pll_rate))
+		return -EINVAL;
+
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_PHY_RESET, 0x33);
+
+	for (i = 0; pll_rate->conf[i].reg; i++)
+		mdp4_write(mdp4_kms, pll_rate->conf[i].reg, pll_rate->conf[i].val);
+
+	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x01);
+
+	/* Wait until LVDS PLL is locked and ready */
+	while (!mdp4_read(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_LOCKED))
+		cpu_relax();
+
+	return 0;
+}
+
+static void mpd4_lvds_pll_disable(struct clk_hw *hw)
+{
+	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
+
+	DBG("");
+
+	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, 0x0);
+	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
+}
+
+static unsigned long mpd4_lvds_pll_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+	return lvds_pll->pixclk;
+}
+
+static long mpd4_lvds_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	const struct pll_rate *pll_rate = find_rate(rate);
+	return pll_rate->rate;
+}
+
+static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
+	lvds_pll->pixclk = rate;
+	return 0;
+}
+
+
+static const struct clk_ops mpd4_lvds_pll_ops = {
+	.enable = mpd4_lvds_pll_enable,
+	.disable = mpd4_lvds_pll_disable,
+	.recalc_rate = mpd4_lvds_pll_recalc_rate,
+	.round_rate = mpd4_lvds_pll_round_rate,
+	.set_rate = mpd4_lvds_pll_set_rate,
+};
+
+static const char *mpd4_lvds_pll_parents[] = {
+	"pxo",
+};
+
+static struct clk_init_data pll_init = {
+	.name = "mpd4_lvds_pll",
+	.ops = &mpd4_lvds_pll_ops,
+	.parent_names = mpd4_lvds_pll_parents,
+	.num_parents = ARRAY_SIZE(mpd4_lvds_pll_parents),
+};
+
+struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
+{
+	struct mdp4_lvds_pll *lvds_pll;
+	struct clk *clk;
+	int ret;
+
+	lvds_pll = devm_kzalloc(dev->dev, sizeof(*lvds_pll), GFP_KERNEL);
+	if (!lvds_pll) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	lvds_pll->dev = dev;
+
+	lvds_pll->pll_hw.init = &pll_init;
+	clk = devm_clk_register(dev->dev, &lvds_pll->pll_hw);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		goto fail;
+	}
+
+	return clk;
+
+fail:
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
new file mode 100644
index 000000000000..7a1ad3af08e3
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mdp4_kms.h"
+
+#define DOWN_SCALE_MAX	8
+#define UP_SCALE_MAX	8
+
+struct mdp4_plane {
+	struct drm_plane base;
+	const char *name;
+
+	enum mdp4_pipe pipe;
+
+	uint32_t caps;
+	uint32_t nformats;
+	uint32_t formats[32];
+
+	bool enabled;
+};
+#define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base)
+
+/* MDP format helper functions */
+static inline
+enum mdp4_frame_format mdp4_get_frame_format(struct drm_framebuffer *fb)
+{
+	bool is_tile = false;
+
+	if (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
+		is_tile = true;
+
+	if (fb->format->format == DRM_FORMAT_NV12 && is_tile)
+		return FRAME_TILE_YCBCR_420;
+
+	return FRAME_LINEAR;
+}
+
+static void mdp4_plane_set_scanout(struct drm_plane *plane,
+		struct drm_framebuffer *fb);
+static int mdp4_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h);
+
+static struct mdp4_kms *get_kms(struct drm_plane *plane)
+{
+	struct msm_drm_private *priv = plane->dev->dev_private;
+	return to_mdp4_kms(to_mdp_kms(priv->kms));
+}
+
+static void mdp4_plane_destroy(struct drm_plane *plane)
+{
+	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+
+	drm_plane_helper_disable(plane);
+	drm_plane_cleanup(plane);
+
+	kfree(mdp4_plane);
+}
+
+/* helper to install properties which are common to planes and crtcs */
+static void mdp4_plane_install_properties(struct drm_plane *plane,
+		struct drm_mode_object *obj)
+{
+	// XXX
+}
+
+static int mdp4_plane_set_property(struct drm_plane *plane,
+		struct drm_property *property, uint64_t val)
+{
+	// XXX
+	return -EINVAL;
+}
+
+static const struct drm_plane_funcs mdp4_plane_funcs = {
+		.update_plane = drm_atomic_helper_update_plane,
+		.disable_plane = drm_atomic_helper_disable_plane,
+		.destroy = mdp4_plane_destroy,
+		.set_property = mdp4_plane_set_property,
+		.reset = drm_atomic_helper_plane_reset,
+		.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+		.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int mdp4_plane_prepare_fb(struct drm_plane *plane,
+				 struct drm_plane_state *new_state)
+{
+	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	struct mdp4_kms *mdp4_kms = get_kms(plane);
+	struct msm_kms *kms = &mdp4_kms->base.base;
+	struct drm_framebuffer *fb = new_state->fb;
+
+	if (!fb)
+		return 0;
+
+	DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id);
+	return msm_framebuffer_prepare(fb, kms->aspace);
+}
+
+static void mdp4_plane_cleanup_fb(struct drm_plane *plane,
+				  struct drm_plane_state *old_state)
+{
+	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	struct mdp4_kms *mdp4_kms = get_kms(plane);
+	struct msm_kms *kms = &mdp4_kms->base.base;
+	struct drm_framebuffer *fb = old_state->fb;
+
+	if (!fb)
+		return;
+
+	DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id);
+	msm_framebuffer_cleanup(fb, kms->aspace);
+}
+
+
+static int mdp4_plane_atomic_check(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	return 0;
+}
+
+static void mdp4_plane_atomic_update(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+	int ret;
+
+	ret = mdp4_plane_mode_set(plane,
+			state->crtc, state->fb,
+			state->crtc_x, state->crtc_y,
+			state->crtc_w, state->crtc_h,
+			state->src_x,  state->src_y,
+			state->src_w, state->src_h);
+	/* atomic_check should have ensured that this doesn't fail */
+	WARN_ON(ret < 0);
+}
+
+static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs = {
+		.prepare_fb = mdp4_plane_prepare_fb,
+		.cleanup_fb = mdp4_plane_cleanup_fb,
+		.atomic_check = mdp4_plane_atomic_check,
+		.atomic_update = mdp4_plane_atomic_update,
+};
+
+static void mdp4_plane_set_scanout(struct drm_plane *plane,
+		struct drm_framebuffer *fb)
+{
+	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	struct mdp4_kms *mdp4_kms = get_kms(plane);
+	struct msm_kms *kms = &mdp4_kms->base.base;
+	enum mdp4_pipe pipe = mdp4_plane->pipe;
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe),
+			MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
+			MDP4_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_B(pipe),
+			MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
+			MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 0));
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 1));
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 2));
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 3));
+
+	plane->fb = fb;
+}
+
+static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms,
+		enum mdp4_pipe pipe, struct csc_cfg *csc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(csc->matrix); i++) {
+		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_MV(pipe, i),
+				csc->matrix[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(csc->post_bias) ; i++) {
+		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_BV(pipe, i),
+				csc->pre_bias[i]);
+
+		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_BV(pipe, i),
+				csc->post_bias[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(csc->post_clamp) ; i++) {
+		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_LV(pipe, i),
+				csc->pre_clamp[i]);
+
+		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_LV(pipe, i),
+				csc->post_clamp[i]);
+	}
+}
+
+#define MDP4_VG_PHASE_STEP_DEFAULT	0x20000000
+
+static int mdp4_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h)
+{
+	struct drm_device *dev = plane->dev;
+	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	struct mdp4_kms *mdp4_kms = get_kms(plane);
+	enum mdp4_pipe pipe = mdp4_plane->pipe;
+	const struct mdp_format *format;
+	uint32_t op_mode = 0;
+	uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
+	uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
+	enum mdp4_frame_format frame_type;
+
+	if (!(crtc && fb)) {
+		DBG("%s: disabled!", mdp4_plane->name);
+		return 0;
+	}
+
+	frame_type = mdp4_get_frame_format(fb);
+
+	/* src values are in Q16 fixed point, convert to integer: */
+	src_x = src_x >> 16;
+	src_y = src_y >> 16;
+	src_w = src_w >> 16;
+	src_h = src_h >> 16;
+
+	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name,
+			fb->base.id, src_x, src_y, src_w, src_h,
+			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+
+	format = to_mdp_format(msm_framebuffer_format(fb));
+
+	if (src_w > (crtc_w * DOWN_SCALE_MAX)) {
+		dev_err(dev->dev, "Width down scaling exceeds limits!\n");
+		return -ERANGE;
+	}
+
+	if (src_h > (crtc_h * DOWN_SCALE_MAX)) {
+		dev_err(dev->dev, "Height down scaling exceeds limits!\n");
+		return -ERANGE;
+	}
+
+	if (crtc_w > (src_w * UP_SCALE_MAX)) {
+		dev_err(dev->dev, "Width up scaling exceeds limits!\n");
+		return -ERANGE;
+	}
+
+	if (crtc_h > (src_h * UP_SCALE_MAX)) {
+		dev_err(dev->dev, "Height up scaling exceeds limits!\n");
+		return -ERANGE;
+	}
+
+	if (src_w != crtc_w) {
+		uint32_t sel_unit = SCALE_FIR;
+		op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN;
+
+		if (MDP_FORMAT_IS_YUV(format)) {
+			if (crtc_w > src_w)
+				sel_unit = SCALE_PIXEL_RPT;
+			else if (crtc_w <= (src_w / 4))
+				sel_unit = SCALE_MN_PHASE;
+
+			op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit);
+			phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT,
+					src_w, crtc_w);
+		}
+	}
+
+	if (src_h != crtc_h) {
+		uint32_t sel_unit = SCALE_FIR;
+		op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN;
+
+		if (MDP_FORMAT_IS_YUV(format)) {
+
+			if (crtc_h > src_h)
+				sel_unit = SCALE_PIXEL_RPT;
+			else if (crtc_h <= (src_h / 4))
+				sel_unit = SCALE_MN_PHASE;
+
+			op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit);
+			phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT,
+					src_h, crtc_h);
+		}
+	}
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe),
+			MDP4_PIPE_SRC_SIZE_WIDTH(src_w) |
+			MDP4_PIPE_SRC_SIZE_HEIGHT(src_h));
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe),
+			MDP4_PIPE_SRC_XY_X(src_x) |
+			MDP4_PIPE_SRC_XY_Y(src_y));
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe),
+			MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) |
+			MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h));
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe),
+			MDP4_PIPE_DST_XY_X(crtc_x) |
+			MDP4_PIPE_DST_XY_Y(crtc_y));
+
+	mdp4_plane_set_scanout(plane, fb);
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe),
+			MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
+			MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
+			MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
+			MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
+			COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
+			MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
+			MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
+			MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) |
+			MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) |
+			MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type) |
+			COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT));
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe),
+			MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
+			MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
+			MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
+			MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
+
+	if (MDP_FORMAT_IS_YUV(format)) {
+		struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB);
+
+		op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR;
+		op_mode |= MDP4_PIPE_OP_MODE_CSC_EN;
+		mdp4_write_csc_config(mdp4_kms, pipe, csc);
+	}
+
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
+
+	if (frame_type != FRAME_LINEAR)
+		mdp4_write(mdp4_kms, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe),
+				MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w) |
+				MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h));
+
+	return 0;
+}
+
+static const char *pipe_names[] = {
+		"VG1", "VG2",
+		"RGB1", "RGB2", "RGB3",
+		"VG3", "VG4",
+};
+
+enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane)
+{
+	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+	return mdp4_plane->pipe;
+}
+
+/* initialize plane */
+struct drm_plane *mdp4_plane_init(struct drm_device *dev,
+		enum mdp4_pipe pipe_id, bool private_plane)
+{
+	struct drm_plane *plane = NULL;
+	struct mdp4_plane *mdp4_plane;
+	int ret;
+	enum drm_plane_type type;
+
+	mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL);
+	if (!mdp4_plane) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	plane = &mdp4_plane->base;
+
+	mdp4_plane->pipe = pipe_id;
+	mdp4_plane->name = pipe_names[pipe_id];
+	mdp4_plane->caps = mdp4_pipe_caps(pipe_id);
+
+	mdp4_plane->nformats = mdp_get_formats(mdp4_plane->formats,
+			ARRAY_SIZE(mdp4_plane->formats),
+			!pipe_supports_yuv(mdp4_plane->caps));
+
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
+				 mdp4_plane->formats, mdp4_plane->nformats,
+				 NULL, type, NULL);
+	if (ret)
+		goto fail;
+
+	drm_plane_helper_add(plane, &mdp4_plane_helper_funcs);
+
+	mdp4_plane_install_properties(plane, &plane->base);
+
+	return plane;
+
+fail:
+	if (plane)
+		mdp4_plane_destroy(plane);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5.xml.h
new file mode 100644
index 000000000000..d9c10e02ee41
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5.xml.h
@@ -0,0 +1,1968 @@
+#ifndef MDP5_XML
+#define MDP5_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
+
+Copyright (C) 2013-2017 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+enum mdp5_intf_type {
+	INTF_DISABLED = 0,
+	INTF_DSI = 1,
+	INTF_HDMI = 3,
+	INTF_LCDC = 5,
+	INTF_eDP = 9,
+	INTF_VIRTUAL = 100,
+	INTF_WB = 101,
+};
+
+enum mdp5_intfnum {
+	NO_INTF = 0,
+	INTF0 = 1,
+	INTF1 = 2,
+	INTF2 = 3,
+	INTF3 = 4,
+};
+
+enum mdp5_pipe {
+	SSPP_NONE = 0,
+	SSPP_VIG0 = 1,
+	SSPP_VIG1 = 2,
+	SSPP_VIG2 = 3,
+	SSPP_RGB0 = 4,
+	SSPP_RGB1 = 5,
+	SSPP_RGB2 = 6,
+	SSPP_DMA0 = 7,
+	SSPP_DMA1 = 8,
+	SSPP_VIG3 = 9,
+	SSPP_RGB3 = 10,
+	SSPP_CURSOR0 = 11,
+	SSPP_CURSOR1 = 12,
+};
+
+enum mdp5_ctl_mode {
+	MODE_NONE = 0,
+	MODE_WB_0_BLOCK = 1,
+	MODE_WB_1_BLOCK = 2,
+	MODE_WB_0_LINE = 3,
+	MODE_WB_1_LINE = 4,
+	MODE_WB_2_LINE = 5,
+};
+
+enum mdp5_pack_3d {
+	PACK_3D_FRAME_INT = 0,
+	PACK_3D_H_ROW_INT = 1,
+	PACK_3D_V_ROW_INT = 2,
+	PACK_3D_COL_INT = 3,
+};
+
+enum mdp5_scale_filter {
+	SCALE_FILTER_NEAREST = 0,
+	SCALE_FILTER_BIL = 1,
+	SCALE_FILTER_PCMN = 2,
+	SCALE_FILTER_CA = 3,
+};
+
+enum mdp5_pipe_bwc {
+	BWC_LOSSLESS = 0,
+	BWC_Q_HIGH = 1,
+	BWC_Q_MED = 2,
+};
+
+enum mdp5_cursor_format {
+	CURSOR_FMT_ARGB8888 = 0,
+	CURSOR_FMT_ARGB1555 = 2,
+	CURSOR_FMT_ARGB4444 = 4,
+};
+
+enum mdp5_cursor_alpha {
+	CURSOR_ALPHA_CONST = 0,
+	CURSOR_ALPHA_PER_PIXEL = 2,
+};
+
+enum mdp5_igc_type {
+	IGC_VIG = 0,
+	IGC_RGB = 1,
+	IGC_DMA = 2,
+	IGC_DSPP = 3,
+};
+
+enum mdp5_data_format {
+	DATA_FORMAT_RGB = 0,
+	DATA_FORMAT_YUV = 1,
+};
+
+enum mdp5_block_size {
+	BLOCK_SIZE_64 = 0,
+	BLOCK_SIZE_128 = 1,
+};
+
+enum mdp5_rotate_mode {
+	ROTATE_0 = 0,
+	ROTATE_90 = 1,
+};
+
+enum mdp5_chroma_downsample_method {
+	DS_MTHD_NO_PIXEL_DROP = 0,
+	DS_MTHD_PIXEL_DROP = 1,
+};
+
+#define MDP5_IRQ_WB_0_DONE					0x00000001
+#define MDP5_IRQ_WB_1_DONE					0x00000002
+#define MDP5_IRQ_WB_2_DONE					0x00000010
+#define MDP5_IRQ_PING_PONG_0_DONE				0x00000100
+#define MDP5_IRQ_PING_PONG_1_DONE				0x00000200
+#define MDP5_IRQ_PING_PONG_2_DONE				0x00000400
+#define MDP5_IRQ_PING_PONG_3_DONE				0x00000800
+#define MDP5_IRQ_PING_PONG_0_RD_PTR				0x00001000
+#define MDP5_IRQ_PING_PONG_1_RD_PTR				0x00002000
+#define MDP5_IRQ_PING_PONG_2_RD_PTR				0x00004000
+#define MDP5_IRQ_PING_PONG_3_RD_PTR				0x00008000
+#define MDP5_IRQ_PING_PONG_0_WR_PTR				0x00010000
+#define MDP5_IRQ_PING_PONG_1_WR_PTR				0x00020000
+#define MDP5_IRQ_PING_PONG_2_WR_PTR				0x00040000
+#define MDP5_IRQ_PING_PONG_3_WR_PTR				0x00080000
+#define MDP5_IRQ_PING_PONG_0_AUTO_REF				0x00100000
+#define MDP5_IRQ_PING_PONG_1_AUTO_REF				0x00200000
+#define MDP5_IRQ_PING_PONG_2_AUTO_REF				0x00400000
+#define MDP5_IRQ_PING_PONG_3_AUTO_REF				0x00800000
+#define MDP5_IRQ_INTF0_UNDER_RUN				0x01000000
+#define MDP5_IRQ_INTF0_VSYNC					0x02000000
+#define MDP5_IRQ_INTF1_UNDER_RUN				0x04000000
+#define MDP5_IRQ_INTF1_VSYNC					0x08000000
+#define MDP5_IRQ_INTF2_UNDER_RUN				0x10000000
+#define MDP5_IRQ_INTF2_VSYNC					0x20000000
+#define MDP5_IRQ_INTF3_UNDER_RUN				0x40000000
+#define MDP5_IRQ_INTF3_VSYNC					0x80000000
+#define REG_MDSS_HW_VERSION					0x00000000
+#define MDSS_HW_VERSION_STEP__MASK				0x0000ffff
+#define MDSS_HW_VERSION_STEP__SHIFT				0
+static inline uint32_t MDSS_HW_VERSION_STEP(uint32_t val)
+{
+	return ((val) << MDSS_HW_VERSION_STEP__SHIFT) & MDSS_HW_VERSION_STEP__MASK;
+}
+#define MDSS_HW_VERSION_MINOR__MASK				0x0fff0000
+#define MDSS_HW_VERSION_MINOR__SHIFT				16
+static inline uint32_t MDSS_HW_VERSION_MINOR(uint32_t val)
+{
+	return ((val) << MDSS_HW_VERSION_MINOR__SHIFT) & MDSS_HW_VERSION_MINOR__MASK;
+}
+#define MDSS_HW_VERSION_MAJOR__MASK				0xf0000000
+#define MDSS_HW_VERSION_MAJOR__SHIFT				28
+static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val)
+{
+	return ((val) << MDSS_HW_VERSION_MAJOR__SHIFT) & MDSS_HW_VERSION_MAJOR__MASK;
+}
+
+#define REG_MDSS_HW_INTR_STATUS					0x00000010
+#define MDSS_HW_INTR_STATUS_INTR_MDP				0x00000001
+#define MDSS_HW_INTR_STATUS_INTR_DSI0				0x00000010
+#define MDSS_HW_INTR_STATUS_INTR_DSI1				0x00000020
+#define MDSS_HW_INTR_STATUS_INTR_HDMI				0x00000100
+#define MDSS_HW_INTR_STATUS_INTR_EDP				0x00001000
+
+#define REG_MDP5_HW_VERSION					0x00000000
+#define MDP5_HW_VERSION_STEP__MASK				0x0000ffff
+#define MDP5_HW_VERSION_STEP__SHIFT				0
+static inline uint32_t MDP5_HW_VERSION_STEP(uint32_t val)
+{
+	return ((val) << MDP5_HW_VERSION_STEP__SHIFT) & MDP5_HW_VERSION_STEP__MASK;
+}
+#define MDP5_HW_VERSION_MINOR__MASK				0x0fff0000
+#define MDP5_HW_VERSION_MINOR__SHIFT				16
+static inline uint32_t MDP5_HW_VERSION_MINOR(uint32_t val)
+{
+	return ((val) << MDP5_HW_VERSION_MINOR__SHIFT) & MDP5_HW_VERSION_MINOR__MASK;
+}
+#define MDP5_HW_VERSION_MAJOR__MASK				0xf0000000
+#define MDP5_HW_VERSION_MAJOR__SHIFT				28
+static inline uint32_t MDP5_HW_VERSION_MAJOR(uint32_t val)
+{
+	return ((val) << MDP5_HW_VERSION_MAJOR__SHIFT) & MDP5_HW_VERSION_MAJOR__MASK;
+}
+
+#define REG_MDP5_DISP_INTF_SEL					0x00000004
+#define MDP5_DISP_INTF_SEL_INTF0__MASK				0x000000ff
+#define MDP5_DISP_INTF_SEL_INTF0__SHIFT				0
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val)
+{
+	return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK;
+}
+#define MDP5_DISP_INTF_SEL_INTF1__MASK				0x0000ff00
+#define MDP5_DISP_INTF_SEL_INTF1__SHIFT				8
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val)
+{
+	return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK;
+}
+#define MDP5_DISP_INTF_SEL_INTF2__MASK				0x00ff0000
+#define MDP5_DISP_INTF_SEL_INTF2__SHIFT				16
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val)
+{
+	return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK;
+}
+#define MDP5_DISP_INTF_SEL_INTF3__MASK				0xff000000
+#define MDP5_DISP_INTF_SEL_INTF3__SHIFT				24
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val)
+{
+	return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK;
+}
+
+#define REG_MDP5_INTR_EN					0x00000010
+
+#define REG_MDP5_INTR_STATUS					0x00000014
+
+#define REG_MDP5_INTR_CLEAR					0x00000018
+
+#define REG_MDP5_HIST_INTR_EN					0x0000001c
+
+#define REG_MDP5_HIST_INTR_STATUS				0x00000020
+
+#define REG_MDP5_HIST_INTR_CLEAR				0x00000024
+
+#define REG_MDP5_SPARE_0					0x00000028
+#define MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN			0x00000001
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000080 + 0x4*i0; }
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000080 + 0x4*i0; }
+#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK			0x000000ff
+#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT			0
+static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(uint32_t val)
+{
+	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
+}
+#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK			0x0000ff00
+#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT			8
+static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(uint32_t val)
+{
+	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
+}
+#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK			0x00ff0000
+#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT			16
+static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(uint32_t val)
+{
+	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
+}
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000130 + 0x4*i0; }
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000130 + 0x4*i0; }
+#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK			0x000000ff
+#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT			0
+static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(uint32_t val)
+{
+	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK;
+}
+#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK			0x0000ff00
+#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT			8
+static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(uint32_t val)
+{
+	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK;
+}
+#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK			0x00ff0000
+#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT			16
+static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(uint32_t val)
+{
+	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK;
+}
+
+static inline uint32_t __offset_IGC(enum mdp5_igc_type idx)
+{
+	switch (idx) {
+		case IGC_VIG: return 0x00000200;
+		case IGC_RGB: return 0x00000210;
+		case IGC_DMA: return 0x00000220;
+		case IGC_DSPP: return 0x00000300;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); }
+
+static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
+#define MDP5_IGC_LUT_REG_VAL__MASK				0x00000fff
+#define MDP5_IGC_LUT_REG_VAL__SHIFT				0
+static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val)
+{
+	return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK;
+}
+#define MDP5_IGC_LUT_REG_INDEX_UPDATE				0x02000000
+#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0				0x10000000
+#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1				0x20000000
+#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2				0x40000000
+
+#define REG_MDP5_SPLIT_DPL_EN					0x000002f4
+
+#define REG_MDP5_SPLIT_DPL_UPPER				0x000002f8
+#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL			0x00000002
+#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN		0x00000004
+#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX			0x00000010
+#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX			0x00000100
+
+#define REG_MDP5_SPLIT_DPL_LOWER				0x000003f0
+#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL			0x00000002
+#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN		0x00000004
+#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC			0x00000010
+#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC			0x00000100
+
+static inline uint32_t __offset_CTL(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return (mdp5_cfg->ctl.base[0]);
+		case 1: return (mdp5_cfg->ctl.base[1]);
+		case 2: return (mdp5_cfg->ctl.base[2]);
+		case 3: return (mdp5_cfg->ctl.base[3]);
+		case 4: return (mdp5_cfg->ctl.base[4]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_CTL(uint32_t i0) { return 0x00000000 + __offset_CTL(i0); }
+
+static inline uint32_t __offset_LAYER(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return 0x00000000;
+		case 1: return 0x00000004;
+		case 2: return 0x00000008;
+		case 3: return 0x0000000c;
+		case 4: return 0x00000010;
+		case 5: return 0x00000024;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER(i1); }
+
+static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER(i1); }
+#define MDP5_CTL_LAYER_REG_VIG0__MASK				0x00000007
+#define MDP5_CTL_LAYER_REG_VIG0__SHIFT				0
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_VIG0__SHIFT) & MDP5_CTL_LAYER_REG_VIG0__MASK;
+}
+#define MDP5_CTL_LAYER_REG_VIG1__MASK				0x00000038
+#define MDP5_CTL_LAYER_REG_VIG1__SHIFT				3
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_VIG1__SHIFT) & MDP5_CTL_LAYER_REG_VIG1__MASK;
+}
+#define MDP5_CTL_LAYER_REG_VIG2__MASK				0x000001c0
+#define MDP5_CTL_LAYER_REG_VIG2__SHIFT				6
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_VIG2__SHIFT) & MDP5_CTL_LAYER_REG_VIG2__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB0__MASK				0x00000e00
+#define MDP5_CTL_LAYER_REG_RGB0__SHIFT				9
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_RGB0__SHIFT) & MDP5_CTL_LAYER_REG_RGB0__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB1__MASK				0x00007000
+#define MDP5_CTL_LAYER_REG_RGB1__SHIFT				12
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_RGB1__SHIFT) & MDP5_CTL_LAYER_REG_RGB1__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB2__MASK				0x00038000
+#define MDP5_CTL_LAYER_REG_RGB2__SHIFT				15
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_RGB2__SHIFT) & MDP5_CTL_LAYER_REG_RGB2__MASK;
+}
+#define MDP5_CTL_LAYER_REG_DMA0__MASK				0x001c0000
+#define MDP5_CTL_LAYER_REG_DMA0__SHIFT				18
+static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_DMA0__SHIFT) & MDP5_CTL_LAYER_REG_DMA0__MASK;
+}
+#define MDP5_CTL_LAYER_REG_DMA1__MASK				0x00e00000
+#define MDP5_CTL_LAYER_REG_DMA1__SHIFT				21
+static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK;
+}
+#define MDP5_CTL_LAYER_REG_BORDER_COLOR				0x01000000
+#define MDP5_CTL_LAYER_REG_CURSOR_OUT				0x02000000
+#define MDP5_CTL_LAYER_REG_VIG3__MASK				0x1c000000
+#define MDP5_CTL_LAYER_REG_VIG3__SHIFT				26
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG3(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_VIG3__SHIFT) & MDP5_CTL_LAYER_REG_VIG3__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB3__MASK				0xe0000000
+#define MDP5_CTL_LAYER_REG_RGB3__SHIFT				29
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB3(uint32_t val)
+{
+	return ((val) << MDP5_CTL_LAYER_REG_RGB3__SHIFT) & MDP5_CTL_LAYER_REG_RGB3__MASK;
+}
+
+static inline uint32_t REG_MDP5_CTL_OP(uint32_t i0) { return 0x00000014 + __offset_CTL(i0); }
+#define MDP5_CTL_OP_MODE__MASK					0x0000000f
+#define MDP5_CTL_OP_MODE__SHIFT					0
+static inline uint32_t MDP5_CTL_OP_MODE(enum mdp5_ctl_mode val)
+{
+	return ((val) << MDP5_CTL_OP_MODE__SHIFT) & MDP5_CTL_OP_MODE__MASK;
+}
+#define MDP5_CTL_OP_INTF_NUM__MASK				0x00000070
+#define MDP5_CTL_OP_INTF_NUM__SHIFT				4
+static inline uint32_t MDP5_CTL_OP_INTF_NUM(enum mdp5_intfnum val)
+{
+	return ((val) << MDP5_CTL_OP_INTF_NUM__SHIFT) & MDP5_CTL_OP_INTF_NUM__MASK;
+}
+#define MDP5_CTL_OP_CMD_MODE					0x00020000
+#define MDP5_CTL_OP_PACK_3D_ENABLE				0x00080000
+#define MDP5_CTL_OP_PACK_3D__MASK				0x00300000
+#define MDP5_CTL_OP_PACK_3D__SHIFT				20
+static inline uint32_t MDP5_CTL_OP_PACK_3D(enum mdp5_pack_3d val)
+{
+	return ((val) << MDP5_CTL_OP_PACK_3D__SHIFT) & MDP5_CTL_OP_PACK_3D__MASK;
+}
+
+static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000018 + __offset_CTL(i0); }
+#define MDP5_CTL_FLUSH_VIG0					0x00000001
+#define MDP5_CTL_FLUSH_VIG1					0x00000002
+#define MDP5_CTL_FLUSH_VIG2					0x00000004
+#define MDP5_CTL_FLUSH_RGB0					0x00000008
+#define MDP5_CTL_FLUSH_RGB1					0x00000010
+#define MDP5_CTL_FLUSH_RGB2					0x00000020
+#define MDP5_CTL_FLUSH_LM0					0x00000040
+#define MDP5_CTL_FLUSH_LM1					0x00000080
+#define MDP5_CTL_FLUSH_LM2					0x00000100
+#define MDP5_CTL_FLUSH_LM3					0x00000200
+#define MDP5_CTL_FLUSH_LM4					0x00000400
+#define MDP5_CTL_FLUSH_DMA0					0x00000800
+#define MDP5_CTL_FLUSH_DMA1					0x00001000
+#define MDP5_CTL_FLUSH_DSPP0					0x00002000
+#define MDP5_CTL_FLUSH_DSPP1					0x00004000
+#define MDP5_CTL_FLUSH_DSPP2					0x00008000
+#define MDP5_CTL_FLUSH_WB					0x00010000
+#define MDP5_CTL_FLUSH_CTL					0x00020000
+#define MDP5_CTL_FLUSH_VIG3					0x00040000
+#define MDP5_CTL_FLUSH_RGB3					0x00080000
+#define MDP5_CTL_FLUSH_LM5					0x00100000
+#define MDP5_CTL_FLUSH_DSPP3					0x00200000
+#define MDP5_CTL_FLUSH_CURSOR_0					0x00400000
+#define MDP5_CTL_FLUSH_CURSOR_1					0x00800000
+#define MDP5_CTL_FLUSH_CHROMADOWN_0				0x04000000
+#define MDP5_CTL_FLUSH_TIMING_3					0x10000000
+#define MDP5_CTL_FLUSH_TIMING_2					0x20000000
+#define MDP5_CTL_FLUSH_TIMING_1					0x40000000
+#define MDP5_CTL_FLUSH_TIMING_0					0x80000000
+
+static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __offset_CTL(i0); }
+
+static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000020 + __offset_CTL(i0); }
+
+static inline uint32_t __offset_LAYER_EXT(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return 0x00000040;
+		case 1: return 0x00000044;
+		case 2: return 0x00000048;
+		case 3: return 0x0000004c;
+		case 4: return 0x00000050;
+		case 5: return 0x00000054;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_CTL_LAYER_EXT(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
+
+static inline uint32_t REG_MDP5_CTL_LAYER_EXT_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
+#define MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3			0x00000001
+#define MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3			0x00000004
+#define MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3			0x00000010
+#define MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3			0x00000040
+#define MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3			0x00000100
+#define MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3			0x00000400
+#define MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3			0x00001000
+#define MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3			0x00004000
+#define MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3			0x00010000
+#define MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3			0x00040000
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK			0x00f00000
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT			20
+static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR0(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK;
+}
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK			0x3c000000
+#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT			26
+static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR1(enum mdp_mixer_stage_id val)
+{
+	return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK;
+}
+
+static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
+{
+	switch (idx) {
+		case SSPP_NONE: return (INVALID_IDX(idx));
+		case SSPP_VIG0: return (mdp5_cfg->pipe_vig.base[0]);
+		case SSPP_VIG1: return (mdp5_cfg->pipe_vig.base[1]);
+		case SSPP_VIG2: return (mdp5_cfg->pipe_vig.base[2]);
+		case SSPP_RGB0: return (mdp5_cfg->pipe_rgb.base[0]);
+		case SSPP_RGB1: return (mdp5_cfg->pipe_rgb.base[1]);
+		case SSPP_RGB2: return (mdp5_cfg->pipe_rgb.base[2]);
+		case SSPP_DMA0: return (mdp5_cfg->pipe_dma.base[0]);
+		case SSPP_DMA1: return (mdp5_cfg->pipe_dma.base[1]);
+		case SSPP_VIG3: return (mdp5_cfg->pipe_vig.base[3]);
+		case SSPP_RGB3: return (mdp5_cfg->pipe_rgb.base[3]);
+		case SSPP_CURSOR0: return (mdp5_cfg->pipe_cursor.base[0]);
+		case SSPP_CURSOR1: return (mdp5_cfg->pipe_cursor.base[1]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_OP_MODE(enum mdp5_pipe i0) { return 0x00000200 + __offset_PIPE(i0); }
+#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK		0x00080000
+#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT		19
+static inline uint32_t MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(enum mdp5_data_format val)
+{
+	return ((val) << MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK;
+}
+#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK		0x00040000
+#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT		18
+static inline uint32_t MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(enum mdp5_data_format val)
+{
+	return ((val) << MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK;
+}
+#define MDP5_PIPE_OP_MODE_CSC_1_EN				0x00020000
+
+static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000002c4 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000002f0 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00000300 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(enum mdp5_pipe i0) { return 0x00000320 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK		0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK		0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT		16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(enum mdp5_pipe i0) { return 0x00000324 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK		0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK		0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT		16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(enum mdp5_pipe i0) { return 0x00000328 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK		0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK		0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT		16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(enum mdp5_pipe i0) { return 0x0000032c + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK		0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK		0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT		16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(enum mdp5_pipe i0) { return 0x00000330 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK		0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK		0x000000ff
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK;
+}
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK			0x0000ff00
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT		8
+static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK		0x000000ff
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK;
+}
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK		0x0000ff00
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT		8
+static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK		0x000001ff
+#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK		0x000001ff
+#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT		0
+static inline uint32_t MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT			16
+static inline uint32_t MDP5_PIPE_SRC_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_SIZE_HEIGHT__MASK;
+}
+#define MDP5_PIPE_SRC_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP5_PIPE_SRC_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_IMG_SIZE(enum mdp5_pipe i0) { return 0x00000004 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK			0xffff0000
+#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT			16
+static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK;
+}
+#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK			0x0000ffff
+#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT			0
+static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_XY(enum mdp5_pipe i0) { return 0x00000008 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_XY_Y__MASK				0xffff0000
+#define MDP5_PIPE_SRC_XY_Y__SHIFT				16
+static inline uint32_t MDP5_PIPE_SRC_XY_Y(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_XY_Y__SHIFT) & MDP5_PIPE_SRC_XY_Y__MASK;
+}
+#define MDP5_PIPE_SRC_XY_X__MASK				0x0000ffff
+#define MDP5_PIPE_SRC_XY_X__SHIFT				0
+static inline uint32_t MDP5_PIPE_SRC_XY_X(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_XY_X__SHIFT) & MDP5_PIPE_SRC_XY_X__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_OUT_SIZE(enum mdp5_pipe i0) { return 0x0000000c + __offset_PIPE(i0); }
+#define MDP5_PIPE_OUT_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT			16
+static inline uint32_t MDP5_PIPE_OUT_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_OUT_SIZE_HEIGHT__MASK;
+}
+#define MDP5_PIPE_OUT_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP5_PIPE_OUT_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT) & MDP5_PIPE_OUT_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_OUT_XY(enum mdp5_pipe i0) { return 0x00000010 + __offset_PIPE(i0); }
+#define MDP5_PIPE_OUT_XY_Y__MASK				0xffff0000
+#define MDP5_PIPE_OUT_XY_Y__SHIFT				16
+static inline uint32_t MDP5_PIPE_OUT_XY_Y(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_OUT_XY_Y__SHIFT) & MDP5_PIPE_OUT_XY_Y__MASK;
+}
+#define MDP5_PIPE_OUT_XY_X__MASK				0x0000ffff
+#define MDP5_PIPE_OUT_XY_X__SHIFT				0
+static inline uint32_t MDP5_PIPE_OUT_XY_X(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_OUT_XY_X__SHIFT) & MDP5_PIPE_OUT_XY_X__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC0_ADDR(enum mdp5_pipe i0) { return 0x00000014 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SRC1_ADDR(enum mdp5_pipe i0) { return 0x00000018 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SRC2_ADDR(enum mdp5_pipe i0) { return 0x0000001c + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SRC3_ADDR(enum mdp5_pipe i0) { return 0x00000020 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_A(enum mdp5_pipe i0) { return 0x00000024 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_STRIDE_A_P0__MASK				0x0000ffff
+#define MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT			0
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P0(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P0__MASK;
+}
+#define MDP5_PIPE_SRC_STRIDE_A_P1__MASK				0xffff0000
+#define MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT			16
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P1(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P1__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_B(enum mdp5_pipe i0) { return 0x00000028 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_STRIDE_B_P2__MASK				0x0000ffff
+#define MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT			0
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P2(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P2__MASK;
+}
+#define MDP5_PIPE_SRC_STRIDE_B_P3__MASK				0xffff0000
+#define MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT			16
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P3(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P3__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_STILE_FRAME_SIZE(enum mdp5_pipe i0) { return 0x0000002c + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_FORMAT(enum mdp5_pipe i0) { return 0x00000030 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_FORMAT_G_BPC__MASK			0x00000003
+#define MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT			0
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_G_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_B_BPC__MASK			0x0000000c
+#define MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT			2
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_B_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_R_BPC__MASK			0x00000030
+#define MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT			4
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_R_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_A_BPC__MASK			0x000000c0
+#define MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT			6
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_A_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE			0x00000100
+#define MDP5_PIPE_SRC_FORMAT_CPP__MASK				0x00000600
+#define MDP5_PIPE_SRC_FORMAT_CPP__SHIFT				9
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_CPP(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CPP__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_ROT90				0x00000800
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK			0x00003000
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT		12
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000
+#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK			0x00180000
+#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT			19
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(enum mdp_fetch_type val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT) & MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK			0x01800000
+#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT			23
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val)
+{
+	return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_UNPACK(enum mdp5_pipe i0) { return 0x00000034 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_UNPACK_ELEM0__MASK			0x000000ff
+#define MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT			0
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM0(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM0__MASK;
+}
+#define MDP5_PIPE_SRC_UNPACK_ELEM1__MASK			0x0000ff00
+#define MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT			8
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM1(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM1__MASK;
+}
+#define MDP5_PIPE_SRC_UNPACK_ELEM2__MASK			0x00ff0000
+#define MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT			16
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM2(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM2__MASK;
+}
+#define MDP5_PIPE_SRC_UNPACK_ELEM3__MASK			0xff000000
+#define MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT			24
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM3__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_OP_MODE(enum mdp5_pipe i0) { return 0x00000038 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SRC_OP_MODE_BWC_EN				0x00000001
+#define MDP5_PIPE_SRC_OP_MODE_BWC__MASK				0x00000006
+#define MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT			1
+static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val)
+{
+	return ((val) << MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT) & MDP5_PIPE_SRC_OP_MODE_BWC__MASK;
+}
+#define MDP5_PIPE_SRC_OP_MODE_FLIP_LR				0x00002000
+#define MDP5_PIPE_SRC_OP_MODE_FLIP_UD				0x00004000
+#define MDP5_PIPE_SRC_OP_MODE_IGC_EN				0x00010000
+#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_0				0x00020000
+#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1				0x00040000
+#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE			0x00400000
+#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD			0x00800000
+#define MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE		0x80000000
+
+static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000003c + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_FETCH_CONFIG(enum mdp5_pipe i0) { return 0x00000048 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_VC1_RANGE(enum mdp5_pipe i0) { return 0x0000004c + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(enum mdp5_pipe i0) { return 0x00000050 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(enum mdp5_pipe i0) { return 0x00000054 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(enum mdp5_pipe i0) { return 0x00000058 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(enum mdp5_pipe i0) { return 0x00000070 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC0_ADDR(enum mdp5_pipe i0) { return 0x000000a4 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC1_ADDR(enum mdp5_pipe i0) { return 0x000000a8 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC2_ADDR(enum mdp5_pipe i0) { return 0x000000ac + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC3_ADDR(enum mdp5_pipe i0) { return 0x000000b0 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_DECIMATION(enum mdp5_pipe i0) { return 0x000000b4 + __offset_PIPE(i0); }
+#define MDP5_PIPE_DECIMATION_VERT__MASK				0x000000ff
+#define MDP5_PIPE_DECIMATION_VERT__SHIFT			0
+static inline uint32_t MDP5_PIPE_DECIMATION_VERT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_DECIMATION_VERT__SHIFT) & MDP5_PIPE_DECIMATION_VERT__MASK;
+}
+#define MDP5_PIPE_DECIMATION_HORZ__MASK				0x0000ff00
+#define MDP5_PIPE_DECIMATION_HORZ__SHIFT			8
+static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK;
+}
+
+static inline uint32_t __offset_SW_PIX_EXT(enum mdp_component_type idx)
+{
+	switch (idx) {
+		case COMP_0: return 0x00000100;
+		case COMP_1_2: return 0x00000110;
+		case COMP_3: return 0x00000120;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
+
+static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_LR(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
+#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK			0x000000ff
+#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT			0
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK			0x0000ff00
+#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT			8
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(int32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK			0x00ff0000
+#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT		16
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK			0xff000000
+#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT		24
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(int32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_TB(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000004 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
+#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK			0x000000ff
+#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT			0
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK			0x0000ff00
+#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT			8
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(int32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK		0x00ff0000
+#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT		16
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK		0xff000000
+#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT		24
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(int32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000008 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
+#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK	0x0000ffff
+#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT	0
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK;
+}
+#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK	0xffff0000
+#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT	16
+static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(uint32_t val)
+{
+	return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00000204 + __offset_PIPE(i0); }
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN			0x00000001
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN			0x00000002
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK	0x00000300
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT	8
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(enum mdp5_scale_filter val)
+{
+	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK	0x00000c00
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT	10
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(enum mdp5_scale_filter val)
+{
+	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK	0x00003000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT	12
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(enum mdp5_scale_filter val)
+{
+	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK	0x0000c000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT	14
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(enum mdp5_scale_filter val)
+{
+	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK	0x00030000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT	16
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(enum mdp5_scale_filter val)
+{
+	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK	0x000c0000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT	18
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(enum mdp5_scale_filter val)
+{
+	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000210 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00000214 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000218 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x0000021c + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00000220 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00000224 + __offset_PIPE(i0); }
+
+static inline uint32_t __offset_LM(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return (mdp5_cfg->lm.base[0]);
+		case 1: return (mdp5_cfg->lm.base[1]);
+		case 2: return (mdp5_cfg->lm.base[2]);
+		case 3: return (mdp5_cfg->lm.base[3]);
+		case 4: return (mdp5_cfg->lm.base[4]);
+		case 5: return (mdp5_cfg->lm.base[5]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_LM(uint32_t i0) { return 0x00000000 + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_COLOR_OUT(uint32_t i0) { return 0x00000000 + __offset_LM(i0); }
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA			0x00000002
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA			0x00000004
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA			0x00000008
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA			0x00000010
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE4_FG_ALPHA			0x00000020
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE5_FG_ALPHA			0x00000040
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE6_FG_ALPHA			0x00000080
+#define MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT		0x80000000
+
+static inline uint32_t REG_MDP5_LM_OUT_SIZE(uint32_t i0) { return 0x00000004 + __offset_LM(i0); }
+#define MDP5_LM_OUT_SIZE_HEIGHT__MASK				0xffff0000
+#define MDP5_LM_OUT_SIZE_HEIGHT__SHIFT				16
+static inline uint32_t MDP5_LM_OUT_SIZE_HEIGHT(uint32_t val)
+{
+	return ((val) << MDP5_LM_OUT_SIZE_HEIGHT__SHIFT) & MDP5_LM_OUT_SIZE_HEIGHT__MASK;
+}
+#define MDP5_LM_OUT_SIZE_WIDTH__MASK				0x0000ffff
+#define MDP5_LM_OUT_SIZE_WIDTH__SHIFT				0
+static inline uint32_t MDP5_LM_OUT_SIZE_WIDTH(uint32_t val)
+{
+	return ((val) << MDP5_LM_OUT_SIZE_WIDTH__SHIFT) & MDP5_LM_OUT_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x00000008 + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00000010 + __offset_LM(i0); }
+
+static inline uint32_t __offset_BLEND(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return 0x00000020;
+		case 1: return 0x00000050;
+		case 2: return 0x00000080;
+		case 3: return 0x000000b0;
+		case 4: return 0x00000230;
+		case 5: return 0x00000260;
+		case 6: return 0x00000290;
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
+#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK			0x00000003
+#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT			0
+static inline uint32_t MDP5_LM_BLEND_OP_MODE_FG_ALPHA(enum mdp_alpha_type val)
+{
+	return ((val) << MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK;
+}
+#define MDP5_LM_BLEND_OP_MODE_FG_INV_ALPHA			0x00000004
+#define MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA			0x00000008
+#define MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA			0x00000010
+#define MDP5_LM_BLEND_OP_MODE_FG_TRANSP_EN			0x00000020
+#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK			0x00000300
+#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT			8
+static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val)
+{
+	return ((val) << MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK;
+}
+#define MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA			0x00000400
+#define MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA			0x00000800
+#define MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA			0x00001000
+#define MDP5_LM_BLEND_OP_MODE_BG_TRANSP_EN			0x00002000
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000001c + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000024 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000028 + __offset_LM(i0) + __offset_BLEND(i1); }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000000e0 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK			0x0000ffff
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT			0
+static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_W(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK;
+}
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK			0xffff0000
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT			16
+static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_H(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000000e4 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_SIZE_ROI_W__MASK				0x0000ffff
+#define MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT			0
+static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_W(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_W__MASK;
+}
+#define MDP5_LM_CURSOR_SIZE_ROI_H__MASK				0xffff0000
+#define MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT			16
+static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_H(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_H__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000000e8 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_XY_SRC_X__MASK				0x0000ffff
+#define MDP5_LM_CURSOR_XY_SRC_X__SHIFT				0
+static inline uint32_t MDP5_LM_CURSOR_XY_SRC_X(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_XY_SRC_X__SHIFT) & MDP5_LM_CURSOR_XY_SRC_X__MASK;
+}
+#define MDP5_LM_CURSOR_XY_SRC_Y__MASK				0xffff0000
+#define MDP5_LM_CURSOR_XY_SRC_Y__SHIFT				16
+static inline uint32_t MDP5_LM_CURSOR_XY_SRC_Y(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_XY_SRC_Y__SHIFT) & MDP5_LM_CURSOR_XY_SRC_Y__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000000dc + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_STRIDE_STRIDE__MASK			0x0000ffff
+#define MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT			0
+static inline uint32_t MDP5_LM_CURSOR_STRIDE_STRIDE(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT) & MDP5_LM_CURSOR_STRIDE_STRIDE__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000000ec + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_FORMAT_FORMAT__MASK			0x00000007
+#define MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT			0
+static inline uint32_t MDP5_LM_CURSOR_FORMAT_FORMAT(enum mdp5_cursor_format val)
+{
+	return ((val) << MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT) & MDP5_LM_CURSOR_FORMAT_FORMAT__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000000f0 + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000000f4 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_START_XY_X_START__MASK			0x0000ffff
+#define MDP5_LM_CURSOR_START_XY_X_START__SHIFT			0
+static inline uint32_t MDP5_LM_CURSOR_START_XY_X_START(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_START_XY_X_START__SHIFT) & MDP5_LM_CURSOR_START_XY_X_START__MASK;
+}
+#define MDP5_LM_CURSOR_START_XY_Y_START__MASK			0xffff0000
+#define MDP5_LM_CURSOR_START_XY_Y_START__SHIFT			16
+static inline uint32_t MDP5_LM_CURSOR_START_XY_Y_START(uint32_t val)
+{
+	return ((val) << MDP5_LM_CURSOR_START_XY_Y_START__SHIFT) & MDP5_LM_CURSOR_START_XY_Y_START__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000000f8 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN			0x00000001
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK	0x00000006
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT	1
+static inline uint32_t MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(enum mdp5_cursor_alpha val)
+{
+	return ((val) << MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT) & MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK;
+}
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN		0x00000008
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000000fc + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW0(uint32_t i0) { return 0x00000100 + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW1(uint32_t i0) { return 0x00000104 + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH0(uint32_t i0) { return 0x00000108 + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH1(uint32_t i0) { return 0x0000010c + __offset_LM(i0); }
+
+static inline uint32_t REG_MDP5_LM_GC_LUT_BASE(uint32_t i0) { return 0x00000110 + __offset_LM(i0); }
+
+static inline uint32_t __offset_DSPP(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return (mdp5_cfg->dspp.base[0]);
+		case 1: return (mdp5_cfg->dspp.base[1]);
+		case 2: return (mdp5_cfg->dspp.base[2]);
+		case 3: return (mdp5_cfg->dspp.base[3]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_DSPP(uint32_t i0) { return 0x00000000 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_OP_MODE(uint32_t i0) { return 0x00000000 + __offset_DSPP(i0); }
+#define MDP5_DSPP_OP_MODE_IGC_LUT_EN				0x00000001
+#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK			0x0000000e
+#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT			1
+static inline uint32_t MDP5_DSPP_OP_MODE_IGC_TBL_IDX(uint32_t val)
+{
+	return ((val) << MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT) & MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK;
+}
+#define MDP5_DSPP_OP_MODE_PCC_EN				0x00000010
+#define MDP5_DSPP_OP_MODE_DITHER_EN				0x00000100
+#define MDP5_DSPP_OP_MODE_HIST_EN				0x00010000
+#define MDP5_DSPP_OP_MODE_AUTO_CLEAR				0x00020000
+#define MDP5_DSPP_OP_MODE_HIST_LUT_EN				0x00080000
+#define MDP5_DSPP_OP_MODE_PA_EN					0x00100000
+#define MDP5_DSPP_OP_MODE_GAMUT_EN				0x00800000
+#define MDP5_DSPP_OP_MODE_GAMUT_ORDER				0x01000000
+
+static inline uint32_t REG_MDP5_DSPP_PCC_BASE(uint32_t i0) { return 0x00000030 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_DITHER_DEPTH(uint32_t i0) { return 0x00000150 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_HIST_CTL_BASE(uint32_t i0) { return 0x00000210 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_HIST_LUT_BASE(uint32_t i0) { return 0x00000230 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_HIST_LUT_SWAP(uint32_t i0) { return 0x00000234 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_PA_BASE(uint32_t i0) { return 0x00000238 + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000002dc + __offset_DSPP(i0); }
+
+static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000002b0 + __offset_DSPP(i0); }
+
+static inline uint32_t __offset_PP(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return (mdp5_cfg->pp.base[0]);
+		case 1: return (mdp5_cfg->pp.base[1]);
+		case 2: return (mdp5_cfg->pp.base[2]);
+		case 3: return (mdp5_cfg->pp.base[3]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_PP(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_TEAR_CHECK_EN(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_VSYNC(uint32_t i0) { return 0x00000004 + __offset_PP(i0); }
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK			0x0007ffff
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT			0
+static inline uint32_t MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT) & MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK;
+}
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN			0x00080000
+#define MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN				0x00100000
+
+static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_HEIGHT(uint32_t i0) { return 0x00000008 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_SYNC_WRCOUNT(uint32_t i0) { return 0x0000000c + __offset_PP(i0); }
+#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK			0x0000ffff
+#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT			0
+static inline uint32_t MDP5_PP_SYNC_WRCOUNT_LINE_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK;
+}
+#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK			0xffff0000
+#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT			16
+static inline uint32_t MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_VSYNC_INIT_VAL(uint32_t i0) { return 0x00000010 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_INT_COUNT_VAL(uint32_t i0) { return 0x00000014 + __offset_PP(i0); }
+#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK			0x0000ffff
+#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT			0
+static inline uint32_t MDP5_PP_INT_COUNT_VAL_LINE_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK;
+}
+#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK			0xffff0000
+#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT		16
+static inline uint32_t MDP5_PP_INT_COUNT_VAL_FRAME_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_SYNC_THRESH(uint32_t i0) { return 0x00000018 + __offset_PP(i0); }
+#define MDP5_PP_SYNC_THRESH_START__MASK				0x0000ffff
+#define MDP5_PP_SYNC_THRESH_START__SHIFT			0
+static inline uint32_t MDP5_PP_SYNC_THRESH_START(uint32_t val)
+{
+	return ((val) << MDP5_PP_SYNC_THRESH_START__SHIFT) & MDP5_PP_SYNC_THRESH_START__MASK;
+}
+#define MDP5_PP_SYNC_THRESH_CONTINUE__MASK			0xffff0000
+#define MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT			16
+static inline uint32_t MDP5_PP_SYNC_THRESH_CONTINUE(uint32_t val)
+{
+	return ((val) << MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT) & MDP5_PP_SYNC_THRESH_CONTINUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_START_POS(uint32_t i0) { return 0x0000001c + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_RD_PTR_IRQ(uint32_t i0) { return 0x00000020 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_WR_PTR_IRQ(uint32_t i0) { return 0x00000024 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_OUT_LINE_COUNT(uint32_t i0) { return 0x00000028 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_PP_LINE_COUNT(uint32_t i0) { return 0x0000002c + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_AUTOREFRESH_CONFIG(uint32_t i0) { return 0x00000030 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_MODE(uint32_t i0) { return 0x00000034 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x00000038 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); }
+
+static inline uint32_t __offset_WB(uint32_t idx)
+{
+	switch (idx) {
+#if 0  /* TEMPORARY until patch that adds wb.base[] is merged */
+		case 0: return (mdp5_cfg->wb.base[0]);
+		case 1: return (mdp5_cfg->wb.base[1]);
+		case 2: return (mdp5_cfg->wb.base[2]);
+		case 3: return (mdp5_cfg->wb.base[3]);
+		case 4: return (mdp5_cfg->wb.base[4]);
+#endif
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_WB(uint32_t i0) { return 0x00000000 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DST_FORMAT(uint32_t i0) { return 0x00000000 + __offset_WB(i0); }
+#define MDP5_WB_DST_FORMAT_DSTC0_OUT__MASK			0x00000003
+#define MDP5_WB_DST_FORMAT_DSTC0_OUT__SHIFT			0
+static inline uint32_t MDP5_WB_DST_FORMAT_DSTC0_OUT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DSTC0_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC0_OUT__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DSTC1_OUT__MASK			0x0000000c
+#define MDP5_WB_DST_FORMAT_DSTC1_OUT__SHIFT			2
+static inline uint32_t MDP5_WB_DST_FORMAT_DSTC1_OUT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DSTC1_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC1_OUT__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DSTC2_OUT__MASK			0x00000030
+#define MDP5_WB_DST_FORMAT_DSTC2_OUT__SHIFT			4
+static inline uint32_t MDP5_WB_DST_FORMAT_DSTC2_OUT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DSTC2_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC2_OUT__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DSTC3_OUT__MASK			0x000000c0
+#define MDP5_WB_DST_FORMAT_DSTC3_OUT__SHIFT			6
+static inline uint32_t MDP5_WB_DST_FORMAT_DSTC3_OUT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DSTC3_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC3_OUT__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DSTC3_EN				0x00000100
+#define MDP5_WB_DST_FORMAT_DST_BPP__MASK			0x00000600
+#define MDP5_WB_DST_FORMAT_DST_BPP__SHIFT			9
+static inline uint32_t MDP5_WB_DST_FORMAT_DST_BPP(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DST_BPP__SHIFT) & MDP5_WB_DST_FORMAT_DST_BPP__MASK;
+}
+#define MDP5_WB_DST_FORMAT_PACK_COUNT__MASK			0x00003000
+#define MDP5_WB_DST_FORMAT_PACK_COUNT__SHIFT			12
+static inline uint32_t MDP5_WB_DST_FORMAT_PACK_COUNT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_PACK_COUNT__SHIFT) & MDP5_WB_DST_FORMAT_PACK_COUNT__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DST_ALPHA_X				0x00004000
+#define MDP5_WB_DST_FORMAT_PACK_TIGHT				0x00020000
+#define MDP5_WB_DST_FORMAT_PACK_ALIGN_MSB			0x00040000
+#define MDP5_WB_DST_FORMAT_WRITE_PLANES__MASK			0x00180000
+#define MDP5_WB_DST_FORMAT_WRITE_PLANES__SHIFT			19
+static inline uint32_t MDP5_WB_DST_FORMAT_WRITE_PLANES(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_WRITE_PLANES__SHIFT) & MDP5_WB_DST_FORMAT_WRITE_PLANES__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DST_DITHER_EN			0x00400000
+#define MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__MASK		0x03800000
+#define MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__SHIFT		23
+static inline uint32_t MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__SHIFT) & MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__MASK;
+}
+#define MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__MASK		0x3c000000
+#define MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__SHIFT		26
+static inline uint32_t MDP5_WB_DST_FORMAT_DST_CHROMA_SITE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__SHIFT) & MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__MASK;
+}
+#define MDP5_WB_DST_FORMAT_FRAME_FORMAT__MASK			0xc0000000
+#define MDP5_WB_DST_FORMAT_FRAME_FORMAT__SHIFT			30
+static inline uint32_t MDP5_WB_DST_FORMAT_FRAME_FORMAT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_FORMAT_FRAME_FORMAT__SHIFT) & MDP5_WB_DST_FORMAT_FRAME_FORMAT__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_DST_OP_MODE(uint32_t i0) { return 0x00000004 + __offset_WB(i0); }
+#define MDP5_WB_DST_OP_MODE_BWC_ENC_EN				0x00000001
+#define MDP5_WB_DST_OP_MODE_BWC_ENC_OP__MASK			0x00000006
+#define MDP5_WB_DST_OP_MODE_BWC_ENC_OP__SHIFT			1
+static inline uint32_t MDP5_WB_DST_OP_MODE_BWC_ENC_OP(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_BWC_ENC_OP__SHIFT) & MDP5_WB_DST_OP_MODE_BWC_ENC_OP__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_BLOCK_SIZE__MASK			0x00000010
+#define MDP5_WB_DST_OP_MODE_BLOCK_SIZE__SHIFT			4
+static inline uint32_t MDP5_WB_DST_OP_MODE_BLOCK_SIZE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_BLOCK_SIZE__SHIFT) & MDP5_WB_DST_OP_MODE_BLOCK_SIZE__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_ROT_MODE__MASK			0x00000020
+#define MDP5_WB_DST_OP_MODE_ROT_MODE__SHIFT			5
+static inline uint32_t MDP5_WB_DST_OP_MODE_ROT_MODE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_ROT_MODE__SHIFT) & MDP5_WB_DST_OP_MODE_ROT_MODE__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_ROT_EN				0x00000040
+#define MDP5_WB_DST_OP_MODE_CSC_EN				0x00000100
+#define MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__MASK		0x00000200
+#define MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT		9
+static inline uint32_t MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__MASK		0x00000400
+#define MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT		10
+static inline uint32_t MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_EN		0x00000800
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__MASK	0x00001000
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__SHIFT	12
+static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__MASK	0x00002000
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__SHIFT	13
+static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__MASK;
+}
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__MASK	0x00004000
+#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__SHIFT	14
+static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_DST_PACK_PATTERN(uint32_t i0) { return 0x00000008 + __offset_WB(i0); }
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT0__MASK			0x00000003
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT0__SHIFT		0
+static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT0(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT0__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT0__MASK;
+}
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT1__MASK			0x00000300
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT1__SHIFT		8
+static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT1(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT1__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT1__MASK;
+}
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT2__MASK			0x00030000
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT2__SHIFT		16
+static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT2(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT2__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT2__MASK;
+}
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT3__MASK			0x03000000
+#define MDP5_WB_DST_PACK_PATTERN_ELEMENT3__SHIFT		24
+static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT3(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT3__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT3__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_DST0_ADDR(uint32_t i0) { return 0x0000000c + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DST1_ADDR(uint32_t i0) { return 0x00000010 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DST2_ADDR(uint32_t i0) { return 0x00000014 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DST3_ADDR(uint32_t i0) { return 0x00000018 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DST_YSTRIDE0(uint32_t i0) { return 0x0000001c + __offset_WB(i0); }
+#define MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__MASK			0x0000ffff
+#define MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__SHIFT		0
+static inline uint32_t MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__MASK;
+}
+#define MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__MASK			0xffff0000
+#define MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__SHIFT		16
+static inline uint32_t MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_DST_YSTRIDE1(uint32_t i0) { return 0x00000020 + __offset_WB(i0); }
+#define MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__MASK			0x0000ffff
+#define MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__SHIFT		0
+static inline uint32_t MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__MASK;
+}
+#define MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__MASK			0xffff0000
+#define MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__SHIFT		16
+static inline uint32_t MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE(uint32_t val)
+{
+	return ((val) << MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_DST_DITHER_BITDEPTH(uint32_t i0) { return 0x00000024 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW0(uint32_t i0) { return 0x00000030 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW1(uint32_t i0) { return 0x00000034 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW2(uint32_t i0) { return 0x00000038 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW3(uint32_t i0) { return 0x0000003c + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_DST_WRITE_CONFIG(uint32_t i0) { return 0x00000048 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_ROTATION_DNSCALER(uint32_t i0) { return 0x00000050 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_X_0_3(uint32_t i0) { return 0x00000060 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_X_1_2(uint32_t i0) { return 0x00000064 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_Y_0_3(uint32_t i0) { return 0x00000068 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_Y_1_2(uint32_t i0) { return 0x0000006c + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_OUT_SIZE(uint32_t i0) { return 0x00000074 + __offset_WB(i0); }
+#define MDP5_WB_OUT_SIZE_DST_W__MASK				0x0000ffff
+#define MDP5_WB_OUT_SIZE_DST_W__SHIFT				0
+static inline uint32_t MDP5_WB_OUT_SIZE_DST_W(uint32_t val)
+{
+	return ((val) << MDP5_WB_OUT_SIZE_DST_W__SHIFT) & MDP5_WB_OUT_SIZE_DST_W__MASK;
+}
+#define MDP5_WB_OUT_SIZE_DST_H__MASK				0xffff0000
+#define MDP5_WB_OUT_SIZE_DST_H__SHIFT				16
+static inline uint32_t MDP5_WB_OUT_SIZE_DST_H(uint32_t val)
+{
+	return ((val) << MDP5_WB_OUT_SIZE_DST_H__SHIFT) & MDP5_WB_OUT_SIZE_DST_H__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_ALPHA_X_VALUE(uint32_t i0) { return 0x00000078 + __offset_WB(i0); }
+
+static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_0(uint32_t i0) { return 0x00000260 + __offset_WB(i0); }
+#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__MASK		0x00001fff
+#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__MASK;
+}
+#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__MASK		0x1fff0000
+#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__SHIFT		16
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_1(uint32_t i0) { return 0x00000264 + __offset_WB(i0); }
+#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__MASK		0x00001fff
+#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__MASK;
+}
+#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__MASK		0x1fff0000
+#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__SHIFT		16
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_2(uint32_t i0) { return 0x00000268 + __offset_WB(i0); }
+#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__MASK		0x00001fff
+#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__MASK;
+}
+#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__MASK		0x1fff0000
+#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__SHIFT		16
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_3(uint32_t i0) { return 0x0000026c + __offset_WB(i0); }
+#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__MASK		0x00001fff
+#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__MASK;
+}
+#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__MASK		0x1fff0000
+#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__SHIFT		16
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_4(uint32_t i0) { return 0x00000270 + __offset_WB(i0); }
+#define MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__MASK		0x00001fff
+#define MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_PRECLAMP(uint32_t i0, uint32_t i1) { return 0x00000274 + __offset_WB(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_PRECLAMP_REG(uint32_t i0, uint32_t i1) { return 0x00000274 + __offset_WB(i0) + 0x4*i1; }
+#define MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__MASK		0x000000ff
+#define MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__SHIFT) & MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__MASK;
+}
+#define MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__MASK			0x0000ff00
+#define MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__SHIFT		8
+static inline uint32_t MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__SHIFT) & MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTCLAMP(uint32_t i0, uint32_t i1) { return 0x00000280 + __offset_WB(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTCLAMP_REG(uint32_t i0, uint32_t i1) { return 0x00000280 + __offset_WB(i0) + 0x4*i1; }
+#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__MASK		0x000000ff
+#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__SHIFT) & MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__MASK;
+}
+#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__MASK		0x0000ff00
+#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__SHIFT		8
+static inline uint32_t MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__SHIFT) & MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_PREBIAS(uint32_t i0, uint32_t i1) { return 0x0000028c + __offset_WB(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_PREBIAS_REG(uint32_t i0, uint32_t i1) { return 0x0000028c + __offset_WB(i0) + 0x4*i1; }
+#define MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__MASK		0x000001ff
+#define MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__SHIFT) & MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTBIAS(uint32_t i0, uint32_t i1) { return 0x00000298 + __offset_WB(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTBIAS_REG(uint32_t i0, uint32_t i1) { return 0x00000298 + __offset_WB(i0) + 0x4*i1; }
+#define MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__MASK		0x000001ff
+#define MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__SHIFT		0
+static inline uint32_t MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE(uint32_t val)
+{
+	return ((val) << MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__SHIFT) & MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__MASK;
+}
+
+static inline uint32_t __offset_INTF(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return (mdp5_cfg->intf.base[0]);
+		case 1: return (mdp5_cfg->intf.base[1]);
+		case 2: return (mdp5_cfg->intf.base[2]);
+		case 3: return (mdp5_cfg->intf.base[3]);
+		case 4: return (mdp5_cfg->intf.base[4]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_INTF(uint32_t i0) { return 0x00000000 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TIMING_ENGINE_EN(uint32_t i0) { return 0x00000000 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_CONFIG(uint32_t i0) { return 0x00000004 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_HSYNC_CTL(uint32_t i0) { return 0x00000008 + __offset_INTF(i0); }
+#define MDP5_INTF_HSYNC_CTL_PULSEW__MASK			0x0000ffff
+#define MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT			0
+static inline uint32_t MDP5_INTF_HSYNC_CTL_PULSEW(uint32_t val)
+{
+	return ((val) << MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT) & MDP5_INTF_HSYNC_CTL_PULSEW__MASK;
+}
+#define MDP5_INTF_HSYNC_CTL_PERIOD__MASK			0xffff0000
+#define MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT			16
+static inline uint32_t MDP5_INTF_HSYNC_CTL_PERIOD(uint32_t val)
+{
+	return ((val) << MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT) & MDP5_INTF_HSYNC_CTL_PERIOD__MASK;
+}
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F0(uint32_t i0) { return 0x0000000c + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F1(uint32_t i0) { return 0x00000010 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F0(uint32_t i0) { return 0x00000014 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F1(uint32_t i0) { return 0x00000018 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F0(uint32_t i0) { return 0x0000001c + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F1(uint32_t i0) { return 0x00000020 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F0(uint32_t i0) { return 0x00000024 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F1(uint32_t i0) { return 0x00000028 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F0(uint32_t i0) { return 0x0000002c + __offset_INTF(i0); }
+#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK			0x7fffffff
+#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT			0
+static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F0_VAL(uint32_t val)
+{
+	return ((val) << MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK;
+}
+#define MDP5_INTF_ACTIVE_VSTART_F0_ACTIVE_V_ENABLE		0x80000000
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F1(uint32_t i0) { return 0x00000030 + __offset_INTF(i0); }
+#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK			0x7fffffff
+#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT			0
+static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F1_VAL(uint32_t val)
+{
+	return ((val) << MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK;
+}
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F0(uint32_t i0) { return 0x00000034 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F1(uint32_t i0) { return 0x00000038 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_HCTL(uint32_t i0) { return 0x0000003c + __offset_INTF(i0); }
+#define MDP5_INTF_DISPLAY_HCTL_START__MASK			0x0000ffff
+#define MDP5_INTF_DISPLAY_HCTL_START__SHIFT			0
+static inline uint32_t MDP5_INTF_DISPLAY_HCTL_START(uint32_t val)
+{
+	return ((val) << MDP5_INTF_DISPLAY_HCTL_START__SHIFT) & MDP5_INTF_DISPLAY_HCTL_START__MASK;
+}
+#define MDP5_INTF_DISPLAY_HCTL_END__MASK			0xffff0000
+#define MDP5_INTF_DISPLAY_HCTL_END__SHIFT			16
+static inline uint32_t MDP5_INTF_DISPLAY_HCTL_END(uint32_t val)
+{
+	return ((val) << MDP5_INTF_DISPLAY_HCTL_END__SHIFT) & MDP5_INTF_DISPLAY_HCTL_END__MASK;
+}
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_HCTL(uint32_t i0) { return 0x00000040 + __offset_INTF(i0); }
+#define MDP5_INTF_ACTIVE_HCTL_START__MASK			0x00007fff
+#define MDP5_INTF_ACTIVE_HCTL_START__SHIFT			0
+static inline uint32_t MDP5_INTF_ACTIVE_HCTL_START(uint32_t val)
+{
+	return ((val) << MDP5_INTF_ACTIVE_HCTL_START__SHIFT) & MDP5_INTF_ACTIVE_HCTL_START__MASK;
+}
+#define MDP5_INTF_ACTIVE_HCTL_END__MASK				0x7fff0000
+#define MDP5_INTF_ACTIVE_HCTL_END__SHIFT			16
+static inline uint32_t MDP5_INTF_ACTIVE_HCTL_END(uint32_t val)
+{
+	return ((val) << MDP5_INTF_ACTIVE_HCTL_END__SHIFT) & MDP5_INTF_ACTIVE_HCTL_END__MASK;
+}
+#define MDP5_INTF_ACTIVE_HCTL_ACTIVE_H_ENABLE			0x80000000
+
+static inline uint32_t REG_MDP5_INTF_BORDER_COLOR(uint32_t i0) { return 0x00000044 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_UNDERFLOW_COLOR(uint32_t i0) { return 0x00000048 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_HSYNC_SKEW(uint32_t i0) { return 0x0000004c + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_POLARITY_CTL(uint32_t i0) { return 0x00000050 + __offset_INTF(i0); }
+#define MDP5_INTF_POLARITY_CTL_HSYNC_LOW			0x00000001
+#define MDP5_INTF_POLARITY_CTL_VSYNC_LOW			0x00000002
+#define MDP5_INTF_POLARITY_CTL_DATA_EN_LOW			0x00000004
+
+static inline uint32_t REG_MDP5_INTF_TEST_CTL(uint32_t i0) { return 0x00000054 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TP_COLOR0(uint32_t i0) { return 0x00000058 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TP_COLOR1(uint32_t i0) { return 0x0000005c + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DSI_CMD_MODE_TRIGGER_EN(uint32_t i0) { return 0x00000084 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_PANEL_FORMAT(uint32_t i0) { return 0x00000090 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_FRAME_LINE_COUNT_EN(uint32_t i0) { return 0x000000a8 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_FRAME_COUNT(uint32_t i0) { return 0x000000ac + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_LINE_COUNT(uint32_t i0) { return 0x000000b0 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DEFLICKER_CONFIG(uint32_t i0) { return 0x000000f0 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DEFLICKER_STRNG_COEFF(uint32_t i0) { return 0x000000f4 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_DEFLICKER_WEAK_COEFF(uint32_t i0) { return 0x000000f8 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_ENABLE(uint32_t i0) { return 0x00000100 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_MAIN_CONTROL(uint32_t i0) { return 0x00000104 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_VIDEO_CONFIG(uint32_t i0) { return 0x00000108 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_COMPONENT_LIMITS(uint32_t i0) { return 0x0000010c + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_RECTANGLE(uint32_t i0) { return 0x00000110 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_INITIAL_VALUE(uint32_t i0) { return 0x00000114 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_BLK_WHITE_PATTERN_FRAME(uint32_t i0) { return 0x00000118 + __offset_INTF(i0); }
+
+static inline uint32_t REG_MDP5_INTF_TPG_RGB_MAPPING(uint32_t i0) { return 0x0000011c + __offset_INTF(i0); }
+
+static inline uint32_t __offset_AD(uint32_t idx)
+{
+	switch (idx) {
+		case 0: return (mdp5_cfg->ad.base[0]);
+		case 1: return (mdp5_cfg->ad.base[1]);
+		default: return INVALID_IDX(idx);
+	}
+}
+static inline uint32_t REG_MDP5_AD(uint32_t i0) { return 0x00000000 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_BYPASS(uint32_t i0) { return 0x00000000 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CTRL_0(uint32_t i0) { return 0x00000004 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CTRL_1(uint32_t i0) { return 0x00000008 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_FRAME_SIZE(uint32_t i0) { return 0x0000000c + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CON_CTRL_0(uint32_t i0) { return 0x00000010 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CON_CTRL_1(uint32_t i0) { return 0x00000014 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_STR_MAN(uint32_t i0) { return 0x00000018 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_VAR(uint32_t i0) { return 0x0000001c + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_DITH(uint32_t i0) { return 0x00000020 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_DITH_CTRL(uint32_t i0) { return 0x00000024 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_AMP_LIM(uint32_t i0) { return 0x00000028 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_SLOPE(uint32_t i0) { return 0x0000002c + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_BW_LVL(uint32_t i0) { return 0x00000030 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_LOGO_POS(uint32_t i0) { return 0x00000034 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_LUT_FI(uint32_t i0) { return 0x00000038 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_LUT_CC(uint32_t i0) { return 0x0000007c + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_STR_LIM(uint32_t i0) { return 0x000000c8 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CALIB_AB(uint32_t i0) { return 0x000000cc + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CALIB_CD(uint32_t i0) { return 0x000000d0 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_MODE_SEL(uint32_t i0) { return 0x000000d4 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_TFILT_CTRL(uint32_t i0) { return 0x000000d8 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_BL_MINMAX(uint32_t i0) { return 0x000000dc + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_BL(uint32_t i0) { return 0x000000e0 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_BL_MAX(uint32_t i0) { return 0x000000e8 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_AL(uint32_t i0) { return 0x000000ec + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_AL_MIN(uint32_t i0) { return 0x000000f0 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_AL_FILT(uint32_t i0) { return 0x000000f4 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CFG_BUF(uint32_t i0) { return 0x000000f8 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_LUT_AL(uint32_t i0) { return 0x00000100 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_TARG_STR(uint32_t i0) { return 0x00000144 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_START_CALC(uint32_t i0) { return 0x00000148 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_STR_OUT(uint32_t i0) { return 0x0000014c + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_BL_OUT(uint32_t i0) { return 0x00000154 + __offset_AD(i0); }
+
+static inline uint32_t REG_MDP5_AD_CALC_DONE(uint32_t i0) { return 0x00000158 + __offset_AD(i0); }
+
+
+#endif /* MDP5_XML */
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
new file mode 100644
index 000000000000..824067d2d427
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "mdp5_kms.h"
+#include "mdp5_cfg.h"
+
+struct mdp5_cfg_handler {
+	int revision;
+	struct mdp5_cfg config;
+};
+
+/* mdp5_cfg must be exposed (used in mdp5.xml.h) */
+const struct mdp5_cfg_hw *mdp5_cfg = NULL;
+
+const struct mdp5_cfg_hw msm8x74v1_config = {
+	.name = "msm8x74v1",
+	.mdp = {
+		.count = 1,
+		.caps = MDP_CAP_SMP |
+			0,
+	},
+	.smp = {
+		.mmb_count = 22,
+		.mmb_size = 4096,
+		.clients = {
+			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
+			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
+		},
+	},
+	.ctl = {
+		.count = 5,
+		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
+		.flush_hw_mask = 0x0003ffff,
+	},
+	.pipe_vig = {
+		.count = 3,
+		.base = { 0x01100, 0x01500, 0x01900 },
+		.caps = MDP_PIPE_CAP_HFLIP |
+			MDP_PIPE_CAP_VFLIP |
+			MDP_PIPE_CAP_SCALE |
+			MDP_PIPE_CAP_CSC   |
+			0,
+	},
+	.pipe_rgb = {
+		.count = 3,
+		.base = { 0x01d00, 0x02100, 0x02500 },
+		.caps = MDP_PIPE_CAP_HFLIP |
+			MDP_PIPE_CAP_VFLIP |
+			MDP_PIPE_CAP_SCALE |
+			0,
+	},
+	.pipe_dma = {
+		.count = 2,
+		.base = { 0x02900, 0x02d00 },
+		.caps = MDP_PIPE_CAP_HFLIP |
+			MDP_PIPE_CAP_VFLIP |
+			0,
+	},
+	.lm = {
+		.count = 5,
+		.base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 1, .pp = 1, .dspp = 1,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 2, .pp = 2, .dspp = 2,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 3, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB },
+				{ .id = 4, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB },
+			     },
+		.nb_stages = 5,
+		.max_width = 2048,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 3,
+		.base = { 0x04500, 0x04900, 0x04d00 },
+	},
+	.pp = {
+		.count = 3,
+		.base = { 0x21a00, 0x21b00, 0x21c00 },
+	},
+	.intf = {
+		.base = { 0x21000, 0x21200, 0x21400, 0x21600 },
+		.connect = {
+			[0] = INTF_eDP,
+			[1] = INTF_DSI,
+			[2] = INTF_DSI,
+			[3] = INTF_HDMI,
+		},
+	},
+	.max_clk = 200000000,
+};
+
+const struct mdp5_cfg_hw msm8x74v2_config = {
+	.name = "msm8x74",
+	.mdp = {
+		.count = 1,
+		.caps = MDP_CAP_SMP |
+			0,
+	},
+	.smp = {
+		.mmb_count = 22,
+		.mmb_size = 4096,
+		.clients = {
+			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
+			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
+		},
+	},
+	.ctl = {
+		.count = 5,
+		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
+		.flush_hw_mask = 0x0003ffff,
+	},
+	.pipe_vig = {
+		.count = 3,
+		.base = { 0x01100, 0x01500, 0x01900 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+				MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_rgb = {
+		.count = 3,
+		.base = { 0x01d00, 0x02100, 0x02500 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_dma = {
+		.count = 2,
+		.base = { 0x02900, 0x02d00 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
+	},
+	.lm = {
+		.count = 5,
+		.base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 1, .pp = 1, .dspp = 1,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 2, .pp = 2, .dspp = 2,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 3, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 4, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+			     },
+		.nb_stages = 5,
+		.max_width = 2048,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 3,
+		.base = { 0x04500, 0x04900, 0x04d00 },
+	},
+	.ad = {
+		.count = 2,
+		.base = { 0x13000, 0x13200 },
+	},
+	.pp = {
+		.count = 3,
+		.base = { 0x12c00, 0x12d00, 0x12e00 },
+	},
+	.intf = {
+		.base = { 0x12400, 0x12600, 0x12800, 0x12a00 },
+		.connect = {
+			[0] = INTF_eDP,
+			[1] = INTF_DSI,
+			[2] = INTF_DSI,
+			[3] = INTF_HDMI,
+		},
+	},
+	.max_clk = 200000000,
+};
+
+const struct mdp5_cfg_hw apq8084_config = {
+	.name = "apq8084",
+	.mdp = {
+		.count = 1,
+		.caps = MDP_CAP_SMP |
+			MDP_CAP_SRC_SPLIT |
+			0,
+	},
+	.smp = {
+		.mmb_count = 44,
+		.mmb_size = 8192,
+		.clients = {
+			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
+			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
+			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
+			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
+		},
+		.reserved_state[0] = GENMASK(7, 0),	/* first 8 MMBs */
+		.reserved = {
+			/* Two SMP blocks are statically tied to RGB pipes: */
+			[16] = 2, [17] = 2, [18] = 2, [22] = 2,
+		},
+	},
+	.ctl = {
+		.count = 5,
+		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
+		.flush_hw_mask = 0x003fffff,
+	},
+	.pipe_vig = {
+		.count = 4,
+		.base = { 0x01100, 0x01500, 0x01900, 0x01d00 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+				MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_rgb = {
+		.count = 4,
+		.base = { 0x02100, 0x02500, 0x02900, 0x02d00 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_dma = {
+		.count = 2,
+		.base = { 0x03100, 0x03500 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
+	},
+	.lm = {
+		.count = 6,
+		.base = { 0x03900, 0x03d00, 0x04100, 0x04500, 0x04900, 0x04d00 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY |
+					  MDP_LM_CAP_PAIR, },
+				{ .id = 1, .pp = 1, .dspp = 1,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 2, .pp = 2, .dspp = 2,
+				  .caps = MDP_LM_CAP_DISPLAY |
+					  MDP_LM_CAP_PAIR, },
+				{ .id = 3, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 4, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 5, .pp = 3, .dspp = 3,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+			     },
+		.nb_stages = 5,
+		.max_width = 2048,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 4,
+		.base = { 0x05100, 0x05500, 0x05900, 0x05d00 },
+
+	},
+	.ad = {
+		.count = 3,
+		.base = { 0x13400, 0x13600, 0x13800 },
+	},
+	.pp = {
+		.count = 4,
+		.base = { 0x12e00, 0x12f00, 0x13000, 0x13100 },
+	},
+	.intf = {
+		.base = { 0x12400, 0x12600, 0x12800, 0x12a00, 0x12c00 },
+		.connect = {
+			[0] = INTF_eDP,
+			[1] = INTF_DSI,
+			[2] = INTF_DSI,
+			[3] = INTF_HDMI,
+		},
+	},
+	.max_clk = 320000000,
+};
+
+const struct mdp5_cfg_hw msm8x16_config = {
+	.name = "msm8x16",
+	.mdp = {
+		.count = 1,
+		.base = { 0x0 },
+		.caps = MDP_CAP_SMP |
+			0,
+	},
+	.smp = {
+		.mmb_count = 8,
+		.mmb_size = 8192,
+		.clients = {
+			[SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
+			[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
+		},
+	},
+	.ctl = {
+		.count = 5,
+		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
+		.flush_hw_mask = 0x4003ffff,
+	},
+	.pipe_vig = {
+		.count = 1,
+		.base = { 0x04000 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+				MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_rgb = {
+		.count = 2,
+		.base = { 0x14000, 0x16000 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_dma = {
+		.count = 1,
+		.base = { 0x24000 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
+	},
+	.lm = {
+		.count = 2, /* LM0 and LM3 */
+		.base = { 0x44000, 0x47000 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 3, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB },
+			     },
+		.nb_stages = 8,
+		.max_width = 2048,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 1,
+		.base = { 0x54000 },
+
+	},
+	.intf = {
+		.base = { 0x00000, 0x6a800 },
+		.connect = {
+			[0] = INTF_DISABLED,
+			[1] = INTF_DSI,
+		},
+	},
+	.max_clk = 320000000,
+};
+
+const struct mdp5_cfg_hw msm8x94_config = {
+	.name = "msm8x94",
+	.mdp = {
+		.count = 1,
+		.caps = MDP_CAP_SMP |
+			MDP_CAP_SRC_SPLIT |
+			0,
+	},
+	.smp = {
+		.mmb_count = 44,
+		.mmb_size = 8192,
+		.clients = {
+			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
+			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
+			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
+			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
+		},
+		.reserved_state[0] = GENMASK(23, 0),	/* first 24 MMBs */
+		.reserved = {
+			 [1] = 1,  [4] = 1,  [7] = 1, [19] = 1,
+			[16] = 5, [17] = 5, [18] = 5, [22] = 5,
+		},
+	},
+	.ctl = {
+		.count = 5,
+		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
+		.flush_hw_mask = 0xf0ffffff,
+	},
+	.pipe_vig = {
+		.count = 4,
+		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
+				MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_rgb = {
+		.count = 4,
+		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
+				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
+	},
+	.pipe_dma = {
+		.count = 2,
+		.base = { 0x24000, 0x26000 },
+		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
+	},
+	.lm = {
+		.count = 6,
+		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY |
+					  MDP_LM_CAP_PAIR, },
+				{ .id = 1, .pp = 1, .dspp = 1,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 2, .pp = 2, .dspp = 2,
+				  .caps = MDP_LM_CAP_DISPLAY |
+					  MDP_LM_CAP_PAIR, },
+				{ .id = 3, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 4, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 5, .pp = 3, .dspp = 3,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+			     },
+		.nb_stages = 8,
+		.max_width = 2048,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 4,
+		.base = { 0x54000, 0x56000, 0x58000, 0x5a000 },
+
+	},
+	.ad = {
+		.count = 3,
+		.base = { 0x78000, 0x78800, 0x79000 },
+	},
+	.pp = {
+		.count = 4,
+		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
+	},
+	.intf = {
+		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
+		.connect = {
+			[0] = INTF_DISABLED,
+			[1] = INTF_DSI,
+			[2] = INTF_DSI,
+			[3] = INTF_HDMI,
+		},
+	},
+	.max_clk = 400000000,
+};
+
+const struct mdp5_cfg_hw msm8x96_config = {
+	.name = "msm8x96",
+	.mdp = {
+		.count = 1,
+		.caps = MDP_CAP_DSC |
+			MDP_CAP_CDM |
+			MDP_CAP_SRC_SPLIT |
+			0,
+	},
+	.ctl = {
+		.count = 5,
+		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
+		.flush_hw_mask = 0xf4ffffff,
+	},
+	.pipe_vig = {
+		.count = 4,
+		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SCALE	|
+			MDP_PIPE_CAP_CSC	|
+			MDP_PIPE_CAP_DECIMATION	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			0,
+	},
+	.pipe_rgb = {
+		.count = 4,
+		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SCALE	|
+			MDP_PIPE_CAP_DECIMATION	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			0,
+	},
+	.pipe_dma = {
+		.count = 2,
+		.base = { 0x24000, 0x26000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			0,
+	},
+	.pipe_cursor = {
+		.count = 2,
+		.base = { 0x34000, 0x36000 },
+		.caps = MDP_PIPE_CAP_HFLIP	|
+			MDP_PIPE_CAP_VFLIP	|
+			MDP_PIPE_CAP_SW_PIX_EXT	|
+			MDP_PIPE_CAP_CURSOR	|
+			0,
+	},
+
+	.lm = {
+		.count = 6,
+		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
+		.instances = {
+				{ .id = 0, .pp = 0, .dspp = 0,
+				  .caps = MDP_LM_CAP_DISPLAY |
+					  MDP_LM_CAP_PAIR, },
+				{ .id = 1, .pp = 1, .dspp = 1,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+				{ .id = 2, .pp = 2, .dspp = -1,
+				  .caps = MDP_LM_CAP_DISPLAY |
+					  MDP_LM_CAP_PAIR, },
+				{ .id = 3, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 4, .pp = -1, .dspp = -1,
+				  .caps = MDP_LM_CAP_WB, },
+				{ .id = 5, .pp = 3, .dspp = -1,
+				  .caps = MDP_LM_CAP_DISPLAY, },
+			     },
+		.nb_stages = 8,
+		.max_width = 2560,
+		.max_height = 0xFFFF,
+	},
+	.dspp = {
+		.count = 2,
+		.base = { 0x54000, 0x56000 },
+	},
+	.ad = {
+		.count = 3,
+		.base = { 0x78000, 0x78800, 0x79000 },
+	},
+	.pp = {
+		.count = 4,
+		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
+	},
+	.cdm = {
+		.count = 1,
+		.base = { 0x79200 },
+	},
+	.dsc = {
+		.count = 2,
+		.base = { 0x80000, 0x80400 },
+	},
+	.intf = {
+		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
+		.connect = {
+			[0] = INTF_DISABLED,
+			[1] = INTF_DSI,
+			[2] = INTF_DSI,
+			[3] = INTF_HDMI,
+		},
+	},
+	.max_clk = 412500000,
+};
+
+static const struct mdp5_cfg_handler cfg_handlers[] = {
+	{ .revision = 0, .config = { .hw = &msm8x74v1_config } },
+	{ .revision = 2, .config = { .hw = &msm8x74v2_config } },
+	{ .revision = 3, .config = { .hw = &apq8084_config } },
+	{ .revision = 6, .config = { .hw = &msm8x16_config } },
+	{ .revision = 9, .config = { .hw = &msm8x94_config } },
+	{ .revision = 7, .config = { .hw = &msm8x96_config } },
+};
+
+static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
+
+const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
+{
+	return cfg_handler->config.hw;
+}
+
+struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler)
+{
+	return &cfg_handler->config;
+}
+
+int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler)
+{
+	return cfg_handler->revision;
+}
+
+void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler)
+{
+	kfree(cfg_handler);
+}
+
+struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
+		uint32_t major, uint32_t minor)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	struct platform_device *pdev = to_platform_device(dev->dev);
+	struct mdp5_cfg_handler *cfg_handler;
+	struct mdp5_cfg_platform *pconfig;
+	int i, ret = 0;
+
+	cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
+	if (unlikely(!cfg_handler)) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	if (major != 1) {
+		dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n",
+				major, minor);
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	/* only after mdp5_cfg global pointer's init can we access the hw */
+	for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
+		if (cfg_handlers[i].revision != minor)
+			continue;
+		mdp5_cfg = cfg_handlers[i].config.hw;
+
+		break;
+	}
+	if (unlikely(!mdp5_cfg)) {
+		dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
+				major, minor);
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	cfg_handler->revision = minor;
+	cfg_handler->config.hw = mdp5_cfg;
+
+	pconfig = mdp5_get_config(pdev);
+	memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig));
+
+	DBG("MDP5: %s hw config selected", mdp5_cfg->name);
+
+	return cfg_handler;
+
+fail:
+	if (cfg_handler)
+		mdp5_cfg_destroy(cfg_handler);
+
+	return NULL;
+}
+
+static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
+{
+	static struct mdp5_cfg_platform config = {};
+
+	config.iommu = iommu_domain_alloc(&platform_bus_type);
+	if (config.iommu) {
+		config.iommu->geometry.aperture_start = 0x1000;
+		config.iommu->geometry.aperture_end = 0xffffffff;
+	}
+
+	return &config;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h
new file mode 100644
index 000000000000..75910d0f2f4c
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDP5_CFG_H__
+#define __MDP5_CFG_H__
+
+#include "msm_drv.h"
+
+/*
+ * mdp5_cfg
+ *
+ * This module configures the dynamic offsets used by mdp5.xml.h
+ * (initialized in mdp5_cfg.c)
+ */
+extern const struct mdp5_cfg_hw *mdp5_cfg;
+
+#define MAX_CTL			8
+#define MAX_BASES		8
+#define MAX_SMP_BLOCKS		44
+#define MAX_CLIENTS		32
+
+typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS);
+
+#define MDP5_SUB_BLOCK_DEFINITION \
+	unsigned int count; \
+	uint32_t base[MAX_BASES]
+
+struct mdp5_sub_block {
+	MDP5_SUB_BLOCK_DEFINITION;
+};
+
+struct mdp5_lm_instance {
+	int id;
+	int pp;
+	int dspp;
+	uint32_t caps;
+};
+
+struct mdp5_lm_block {
+	MDP5_SUB_BLOCK_DEFINITION;
+	struct mdp5_lm_instance instances[MAX_BASES];
+	uint32_t nb_stages;		/* number of stages per blender */
+	uint32_t max_width;		/* Maximum output resolution */
+	uint32_t max_height;
+};
+
+struct mdp5_pipe_block {
+	MDP5_SUB_BLOCK_DEFINITION;
+	uint32_t caps;			/* pipe capabilities */
+};
+
+struct mdp5_ctl_block {
+	MDP5_SUB_BLOCK_DEFINITION;
+	uint32_t flush_hw_mask;		/* FLUSH register's hardware mask */
+};
+
+struct mdp5_smp_block {
+	int mmb_count;			/* number of SMP MMBs */
+	int mmb_size;			/* MMB: size in bytes */
+	uint32_t clients[MAX_CLIENTS];	/* SMP port allocation /pipe */
+	mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */
+	uint8_t reserved[MAX_CLIENTS];	/* # of MMBs allocated per client */
+};
+
+struct mdp5_mdp_block {
+	MDP5_SUB_BLOCK_DEFINITION;
+	uint32_t caps;			/* MDP capabilities: MDP_CAP_xxx bits */
+};
+
+#define MDP5_INTF_NUM_MAX	5
+
+struct mdp5_intf_block {
+	uint32_t base[MAX_BASES];
+	u32 connect[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
+};
+
+struct mdp5_cfg_hw {
+	char  *name;
+
+	struct mdp5_mdp_block mdp;
+	struct mdp5_smp_block smp;
+	struct mdp5_ctl_block ctl;
+	struct mdp5_pipe_block pipe_vig;
+	struct mdp5_pipe_block pipe_rgb;
+	struct mdp5_pipe_block pipe_dma;
+	struct mdp5_pipe_block pipe_cursor;
+	struct mdp5_lm_block  lm;
+	struct mdp5_sub_block dspp;
+	struct mdp5_sub_block ad;
+	struct mdp5_sub_block pp;
+	struct mdp5_sub_block dsc;
+	struct mdp5_sub_block cdm;
+	struct mdp5_intf_block intf;
+
+	uint32_t max_clk;
+};
+
+/* platform config data (ie. from DT, or pdata) */
+struct mdp5_cfg_platform {
+	struct iommu_domain *iommu;
+};
+
+struct mdp5_cfg {
+	const struct mdp5_cfg_hw *hw;
+	struct mdp5_cfg_platform platform;
+};
+
+struct mdp5_kms;
+struct mdp5_cfg_handler;
+
+const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hnd);
+struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd);
+int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd);
+
+#define mdp5_cfg_intf_is_virtual(intf_type) ({	\
+	typeof(intf_type) __val = (intf_type);	\
+	(__val) >= INTF_VIRTUAL ? true : false; })
+
+struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
+		uint32_t major, uint32_t minor);
+void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd);
+
+#endif /* __MDP5_CFG_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
new file mode 100644
index 000000000000..1abc7f5c345c
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "mdp5_kms.h"
+
+static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
+{
+	struct msm_drm_private *priv = encoder->dev->dev_private;
+	return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+
+static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx)
+{
+	if (mdp5_cmd_enc->bsc) {
+		DBG("set bus scaling: %d", idx);
+		/* HACK: scaling down, and then immediately back up
+		 * seems to leave things broken (underflow).. so
+		 * never disable:
+		 */
+		idx = 1;
+		msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx);
+	}
+}
+#else
+static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx) {}
+#endif
+
+#define VSYNC_CLK_RATE 19200000
+static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
+				    struct drm_display_mode *mode)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	struct device *dev = encoder->dev->dev;
+	u32 total_lines_x100, vclks_line, cfg;
+	long vsync_clk_speed;
+	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
+	int pp_id = mixer->pp;
+
+	if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
+		dev_err(dev, "vsync_clk is not initialized\n");
+		return -EINVAL;
+	}
+
+	total_lines_x100 = mode->vtotal * mode->vrefresh;
+	if (!total_lines_x100) {
+		dev_err(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
+				__func__, mode->vtotal, mode->vrefresh);
+		return -EINVAL;
+	}
+
+	vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
+	if (vsync_clk_speed <= 0) {
+		dev_err(dev, "vsync_clk round rate failed %ld\n",
+							vsync_clk_speed);
+		return -EINVAL;
+	}
+	vclks_line = vsync_clk_speed * 100 / total_lines_x100;
+
+	cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
+		| MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
+	cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
+
+	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
+	mdp5_write(mdp5_kms,
+		REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
+	mdp5_write(mdp5_kms,
+		REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
+	mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
+	mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
+	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
+			MDP5_PP_SYNC_THRESH_START(4) |
+			MDP5_PP_SYNC_THRESH_CONTINUE(4));
+
+	return 0;
+}
+
+static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
+	int pp_id = mixer->pp;
+	int ret;
+
+	ret = clk_set_rate(mdp5_kms->vsync_clk,
+		clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
+	if (ret) {
+		dev_err(encoder->dev->dev,
+			"vsync_clk clk_set_rate failed, %d\n", ret);
+		return ret;
+	}
+	ret = clk_prepare_enable(mdp5_kms->vsync_clk);
+	if (ret) {
+		dev_err(encoder->dev->dev,
+			"vsync_clk clk_prepare_enable failed, %d\n", ret);
+		return ret;
+	}
+
+	mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
+
+	return 0;
+}
+
+static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
+	int pp_id = mixer->pp;
+
+	mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
+	clk_disable_unprepare(mdp5_kms->vsync_clk);
+}
+
+void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+			       struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+	mode = adjusted_mode;
+
+	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+	pingpong_tearcheck_setup(encoder, mode);
+	mdp5_crtc_set_pipeline(encoder->crtc);
+}
+
+void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
+	struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
+	struct mdp5_interface *intf = mdp5_cmd_enc->intf;
+	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
+
+	if (WARN_ON(!mdp5_cmd_enc->enabled))
+		return;
+
+	pingpong_tearcheck_disable(encoder);
+
+	mdp5_ctl_set_encoder_state(ctl, pipeline, false);
+	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
+
+	bs_set(mdp5_cmd_enc, 0);
+
+	mdp5_cmd_enc->enabled = false;
+}
+
+void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
+	struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
+	struct mdp5_interface *intf = mdp5_cmd_enc->intf;
+	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
+
+	if (WARN_ON(mdp5_cmd_enc->enabled))
+		return;
+
+	bs_set(mdp5_cmd_enc, 1);
+	if (pingpong_tearcheck_enable(encoder))
+		return;
+
+	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
+
+	mdp5_ctl_set_encoder_state(ctl, pipeline, true);
+
+	mdp5_cmd_enc->enabled = true;
+}
+
+int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
+				       struct drm_encoder *slave_encoder)
+{
+	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms;
+	struct device *dev;
+	int intf_num;
+	u32 data = 0;
+
+	if (!encoder || !slave_encoder)
+		return -EINVAL;
+
+	mdp5_kms = get_kms(encoder);
+	intf_num = mdp5_cmd_enc->intf->num;
+
+	/* Switch slave encoder's trigger MUX, to use the master's
+	 * start signal for the slave encoder
+	 */
+	if (intf_num == 1)
+		data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
+	else if (intf_num == 2)
+		data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
+	else
+		return -EINVAL;
+
+	/* Smart Panel, Sync mode */
+	data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
+
+	dev = &mdp5_kms->pdev->dev;
+
+	/* Make sure clocks are on when connectors calling this function. */
+	pm_runtime_get_sync(dev);
+	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
+
+	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
+		   MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
+	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
new file mode 100644
index 000000000000..8c5ed0b59e46
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
@@ -0,0 +1,1194 @@
+/*
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/sort.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
+
+#include "mdp5_kms.h"
+
+#define CURSOR_WIDTH	64
+#define CURSOR_HEIGHT	64
+
+struct mdp5_crtc {
+	struct drm_crtc base;
+	int id;
+	bool enabled;
+
+	spinlock_t lm_lock;     /* protect REG_MDP5_LM_* registers */
+
+	/* if there is a pending flip, these will be non-null: */
+	struct drm_pending_vblank_event *event;
+
+	/* Bits have been flushed at the last commit,
+	 * used to decide if a vsync has happened since last commit.
+	 */
+	u32 flushed_mask;
+
+#define PENDING_CURSOR 0x1
+#define PENDING_FLIP   0x2
+	atomic_t pending;
+
+	/* for unref'ing cursor bo's after scanout completes: */
+	struct drm_flip_work unref_cursor_work;
+
+	struct mdp_irq vblank;
+	struct mdp_irq err;
+	struct mdp_irq pp_done;
+
+	struct completion pp_completion;
+
+	bool lm_cursor_enabled;
+
+	struct {
+		/* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
+		spinlock_t lock;
+
+		/* current cursor being scanned out: */
+		struct drm_gem_object *scanout_bo;
+		uint64_t iova;
+		uint32_t width, height;
+		uint32_t x, y;
+	} cursor;
+};
+#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
+
+static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc);
+
+static struct mdp5_kms *get_kms(struct drm_crtc *crtc)
+{
+	struct msm_drm_private *priv = crtc->dev->dev_private;
+	return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static void request_pending(struct drm_crtc *crtc, uint32_t pending)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+	atomic_or(pending, &mdp5_crtc->pending);
+	mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
+}
+
+static void request_pp_done_pending(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	reinit_completion(&mdp5_crtc->pp_completion);
+}
+
+static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
+	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+
+	DBG("%s: flush=%08x", crtc->name, flush_mask);
+	return mdp5_ctl_commit(ctl, pipeline, flush_mask);
+}
+
+/*
+ * flush updates, to make sure hw is updated to new scanout fb,
+ * so that we can safely queue unref to current fb (ie. next
+ * vblank we know hw is done w/ previous scanout_fb).
+ */
+static u32 crtc_flush_all(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_hw_mixer *mixer, *r_mixer;
+	struct drm_plane *plane;
+	uint32_t flush_mask = 0;
+
+	/* this should not happen: */
+	if (WARN_ON(!mdp5_cstate->ctl))
+		return 0;
+
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		if (!plane->state->visible)
+			continue;
+		flush_mask |= mdp5_plane_get_flush(plane);
+	}
+
+	mixer = mdp5_cstate->pipeline.mixer;
+	flush_mask |= mdp_ctl_flush_mask_lm(mixer->lm);
+
+	r_mixer = mdp5_cstate->pipeline.r_mixer;
+	if (r_mixer)
+		flush_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
+
+	return crtc_flush(crtc, flush_mask);
+}
+
+/* if file!=NULL, this is preclose potential cancel-flip path */
+static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
+	struct drm_device *dev = crtc->dev;
+	struct drm_pending_vblank_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = mdp5_crtc->event;
+	if (event) {
+		mdp5_crtc->event = NULL;
+		DBG("%s: send event: %p", crtc->name, event);
+		drm_crtc_send_vblank_event(crtc, event);
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (ctl && !crtc->state->enable) {
+		/* set STAGE_UNUSED for all layers */
+		mdp5_ctl_blend(ctl, pipeline, NULL, NULL, 0, 0);
+		/* XXX: What to do here? */
+		/* mdp5_crtc->ctl = NULL; */
+	}
+}
+
+static void unref_cursor_worker(struct drm_flip_work *work, void *val)
+{
+	struct mdp5_crtc *mdp5_crtc =
+		container_of(work, struct mdp5_crtc, unref_cursor_work);
+	struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base);
+	struct msm_kms *kms = &mdp5_kms->base.base;
+
+	msm_gem_put_iova(val, kms->aspace);
+	drm_gem_object_put_unlocked(val);
+}
+
+static void mdp5_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work);
+
+	kfree(mdp5_crtc);
+}
+
+static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage)
+{
+	switch (stage) {
+	case STAGE0: return MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA;
+	case STAGE1: return MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA;
+	case STAGE2: return MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA;
+	case STAGE3: return MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA;
+	case STAGE4: return MDP5_LM_BLEND_COLOR_OUT_STAGE4_FG_ALPHA;
+	case STAGE5: return MDP5_LM_BLEND_COLOR_OUT_STAGE5_FG_ALPHA;
+	case STAGE6: return MDP5_LM_BLEND_COLOR_OUT_STAGE6_FG_ALPHA;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * left/right pipe offsets for the stage array used in blend_setup()
+ */
+#define PIPE_LEFT	0
+#define PIPE_RIGHT	1
+
+/*
+ * blend_setup() - blend all the planes of a CRTC
+ *
+ * If no base layer is available, border will be enabled as the base layer.
+ * Otherwise all layers will be blended based on their stage calculated
+ * in mdp5_crtc_atomic_check.
+ */
+static void blend_setup(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct drm_plane *plane;
+	const struct mdp5_cfg_hw *hw_cfg;
+	struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL};
+	const struct mdp_format *format;
+	struct mdp5_hw_mixer *mixer = pipeline->mixer;
+	uint32_t lm = mixer->lm;
+	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
+	uint32_t r_lm = r_mixer ? r_mixer->lm : 0;
+	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
+	uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
+	unsigned long flags;
+	enum mdp5_pipe stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { { SSPP_NONE } };
+	enum mdp5_pipe r_stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { { SSPP_NONE } };
+	int i, plane_cnt = 0;
+	bool bg_alpha_enabled = false;
+	u32 mixer_op_mode = 0;
+	u32 val;
+#define blender(stage)	((stage) - STAGE0)
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	spin_lock_irqsave(&mdp5_crtc->lm_lock, flags);
+
+	/* ctl could be released already when we are shutting down: */
+	/* XXX: Can this happen now? */
+	if (!ctl)
+		goto out;
+
+	/* Collect all plane information */
+	drm_atomic_crtc_for_each_plane(plane, crtc) {
+		enum mdp5_pipe right_pipe;
+
+		if (!plane->state->visible)
+			continue;
+
+		pstate = to_mdp5_plane_state(plane->state);
+		pstates[pstate->stage] = pstate;
+		stage[pstate->stage][PIPE_LEFT] = mdp5_plane_pipe(plane);
+		/*
+		 * if we have a right mixer, stage the same pipe as we
+		 * have on the left mixer
+		 */
+		if (r_mixer)
+			r_stage[pstate->stage][PIPE_LEFT] =
+						mdp5_plane_pipe(plane);
+		/*
+		 * if we have a right pipe (i.e, the plane comprises of 2
+		 * hwpipes, then stage the right pipe on the right side of both
+		 * the layer mixers
+		 */
+		right_pipe = mdp5_plane_right_pipe(plane);
+		if (right_pipe) {
+			stage[pstate->stage][PIPE_RIGHT] = right_pipe;
+			r_stage[pstate->stage][PIPE_RIGHT] = right_pipe;
+		}
+
+		plane_cnt++;
+	}
+
+	if (!pstates[STAGE_BASE]) {
+		ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
+		DBG("Border Color is enabled");
+	} else if (plane_cnt) {
+		format = to_mdp_format(msm_framebuffer_format(pstates[STAGE_BASE]->base.fb));
+
+		if (format->alpha_enable)
+			bg_alpha_enabled = true;
+	}
+
+	/* The reset for blending */
+	for (i = STAGE0; i <= STAGE_MAX; i++) {
+		if (!pstates[i])
+			continue;
+
+		format = to_mdp_format(
+			msm_framebuffer_format(pstates[i]->base.fb));
+		plane = pstates[i]->base.plane;
+		blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
+			MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST);
+		fg_alpha = pstates[i]->alpha;
+		bg_alpha = 0xFF - pstates[i]->alpha;
+
+		if (!format->alpha_enable && bg_alpha_enabled)
+			mixer_op_mode = 0;
+		else
+			mixer_op_mode |= mdp5_lm_use_fg_alpha_mask(i);
+
+		DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha);
+
+		if (format->alpha_enable && pstates[i]->premultiplied) {
+			blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
+				MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
+			if (fg_alpha != 0xff) {
+				bg_alpha = fg_alpha;
+				blend_op |=
+					MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
+					MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
+			} else {
+				blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
+			}
+		} else if (format->alpha_enable) {
+			blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_PIXEL) |
+				MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
+			if (fg_alpha != 0xff) {
+				bg_alpha = fg_alpha;
+				blend_op |=
+				       MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA |
+				       MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA |
+				       MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
+				       MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
+			} else {
+				blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
+			}
+		}
+
+		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(lm,
+				blender(i)), blend_op);
+		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
+				blender(i)), fg_alpha);
+		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
+				blender(i)), bg_alpha);
+		if (r_mixer) {
+			mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(r_lm,
+					blender(i)), blend_op);
+			mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(r_lm,
+					blender(i)), fg_alpha);
+			mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(r_lm,
+					blender(i)), bg_alpha);
+		}
+	}
+
+	val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm));
+	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm),
+		   val | mixer_op_mode);
+	if (r_mixer) {
+		val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm));
+		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm),
+			   val | mixer_op_mode);
+	}
+
+	mdp5_ctl_blend(ctl, pipeline, stage, r_stage, plane_cnt,
+		       ctl_blend_flags);
+out:
+	spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
+}
+
+static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct mdp5_hw_mixer *mixer = mdp5_cstate->pipeline.mixer;
+	struct mdp5_hw_mixer *r_mixer = mdp5_cstate->pipeline.r_mixer;
+	uint32_t lm = mixer->lm;
+	u32 mixer_width, val;
+	unsigned long flags;
+	struct drm_display_mode *mode;
+
+	if (WARN_ON(!crtc->state))
+		return;
+
+	mode = &crtc->state->adjusted_mode;
+
+	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			crtc->name, mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+
+	mixer_width = mode->hdisplay;
+	if (r_mixer)
+		mixer_width /= 2;
+
+	spin_lock_irqsave(&mdp5_crtc->lm_lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(lm),
+			MDP5_LM_OUT_SIZE_WIDTH(mixer_width) |
+			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
+
+	/* Assign mixer to LEFT side in source split mode */
+	val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm));
+	val &= ~MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT;
+	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm), val);
+
+	if (r_mixer) {
+		u32 r_lm = r_mixer->lm;
+
+		mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(r_lm),
+			   MDP5_LM_OUT_SIZE_WIDTH(mixer_width) |
+			   MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
+
+		/* Assign mixer to RIGHT side in source split mode */
+		val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm));
+		val |= MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT;
+		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm), val);
+	}
+
+	spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
+}
+
+static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc,
+				     struct drm_crtc_state *old_state)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	DBG("%s", crtc->name);
+
+	if (WARN_ON(!mdp5_crtc->enabled))
+		return;
+
+	/* Disable/save vblank irq handling before power is disabled */
+	drm_crtc_vblank_off(crtc);
+
+	if (mdp5_cstate->cmd_mode)
+		mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done);
+
+	mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
+	pm_runtime_put_sync(dev);
+
+	mdp5_crtc->enabled = false;
+}
+
+static void mdp5_crtc_atomic_enable(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	DBG("%s", crtc->name);
+
+	if (WARN_ON(mdp5_crtc->enabled))
+		return;
+
+	pm_runtime_get_sync(dev);
+
+	if (mdp5_crtc->lm_cursor_enabled) {
+		/*
+		 * Restore LM cursor state, as it might have been lost
+		 * with suspend:
+		 */
+		if (mdp5_crtc->cursor.iova) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+			mdp5_crtc_restore_cursor(crtc);
+			spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+			mdp5_ctl_set_cursor(mdp5_cstate->ctl,
+					    &mdp5_cstate->pipeline, 0, true);
+		} else {
+			mdp5_ctl_set_cursor(mdp5_cstate->ctl,
+					    &mdp5_cstate->pipeline, 0, false);
+		}
+	}
+
+	/* Restore vblank irq handling after power is enabled */
+	drm_crtc_vblank_on(crtc);
+
+	mdp5_crtc_mode_set_nofb(crtc);
+
+	mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
+
+	if (mdp5_cstate->cmd_mode)
+		mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->pp_done);
+
+	mdp5_crtc->enabled = true;
+}
+
+int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
+			     struct drm_crtc_state *new_crtc_state,
+			     bool need_right_mixer)
+{
+	struct mdp5_crtc_state *mdp5_cstate =
+			to_mdp5_crtc_state(new_crtc_state);
+	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+	struct mdp5_interface *intf;
+	bool new_mixer = false;
+
+	new_mixer = !pipeline->mixer;
+
+	if ((need_right_mixer && !pipeline->r_mixer) ||
+	    (!need_right_mixer && pipeline->r_mixer))
+		new_mixer = true;
+
+	if (new_mixer) {
+		struct mdp5_hw_mixer *old_mixer = pipeline->mixer;
+		struct mdp5_hw_mixer *old_r_mixer = pipeline->r_mixer;
+		u32 caps;
+		int ret;
+
+		caps = MDP_LM_CAP_DISPLAY;
+		if (need_right_mixer)
+			caps |= MDP_LM_CAP_PAIR;
+
+		ret = mdp5_mixer_assign(new_crtc_state->state, crtc, caps,
+					&pipeline->mixer, need_right_mixer ?
+					&pipeline->r_mixer : NULL);
+		if (ret)
+			return ret;
+
+		mdp5_mixer_release(new_crtc_state->state, old_mixer);
+		if (old_r_mixer) {
+			mdp5_mixer_release(new_crtc_state->state, old_r_mixer);
+			if (!need_right_mixer)
+				pipeline->r_mixer = NULL;
+		}
+	}
+
+	/*
+	 * these should have been already set up in the encoder's atomic
+	 * check (called by drm_atomic_helper_check_modeset)
+	 */
+	intf = pipeline->intf;
+
+	mdp5_cstate->err_irqmask = intf2err(intf->num);
+	mdp5_cstate->vblank_irqmask = intf2vblank(pipeline->mixer, intf);
+
+	if ((intf->type == INTF_DSI) &&
+	    (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
+		mdp5_cstate->pp_done_irqmask = lm2ppdone(pipeline->mixer);
+		mdp5_cstate->cmd_mode = true;
+	} else {
+		mdp5_cstate->pp_done_irqmask = 0;
+		mdp5_cstate->cmd_mode = false;
+	}
+
+	return 0;
+}
+
+struct plane_state {
+	struct drm_plane *plane;
+	struct mdp5_plane_state *state;
+};
+
+static int pstate_cmp(const void *a, const void *b)
+{
+	struct plane_state *pa = (struct plane_state *)a;
+	struct plane_state *pb = (struct plane_state *)b;
+	return pa->state->zpos - pb->state->zpos;
+}
+
+/* is there a helper for this? */
+static bool is_fullscreen(struct drm_crtc_state *cstate,
+		struct drm_plane_state *pstate)
+{
+	return (pstate->crtc_x <= 0) && (pstate->crtc_y <= 0) &&
+		((pstate->crtc_x + pstate->crtc_w) >= cstate->mode.hdisplay) &&
+		((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay);
+}
+
+static enum mdp_mixer_stage_id get_start_stage(struct drm_crtc *crtc,
+					struct drm_crtc_state *new_crtc_state,
+					struct drm_plane_state *bpstate)
+{
+	struct mdp5_crtc_state *mdp5_cstate =
+			to_mdp5_crtc_state(new_crtc_state);
+
+	/*
+	 * if we're in source split mode, it's mandatory to have
+	 * border out on the base stage
+	 */
+	if (mdp5_cstate->pipeline.r_mixer)
+		return STAGE0;
+
+	/* if the bottom-most layer is not fullscreen, we need to use
+	 * it for solid-color:
+	 */
+	if (!is_fullscreen(new_crtc_state, bpstate))
+		return STAGE0;
+
+	return STAGE_BASE;
+}
+
+static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct drm_plane *plane;
+	struct drm_device *dev = crtc->dev;
+	struct plane_state pstates[STAGE_MAX + 1];
+	const struct mdp5_cfg_hw *hw_cfg;
+	const struct drm_plane_state *pstate;
+	const struct drm_display_mode *mode = &state->adjusted_mode;
+	bool cursor_plane = false;
+	bool need_right_mixer = false;
+	int cnt = 0, i;
+	int ret;
+	enum mdp_mixer_stage_id start;
+
+	DBG("%s: check", crtc->name);
+
+	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+		if (!pstate->visible)
+			continue;
+
+		pstates[cnt].plane = plane;
+		pstates[cnt].state = to_mdp5_plane_state(pstate);
+
+		/*
+		 * if any plane on this crtc uses 2 hwpipes, then we need
+		 * the crtc to have a right hwmixer.
+		 */
+		if (pstates[cnt].state->r_hwpipe)
+			need_right_mixer = true;
+		cnt++;
+
+		if (plane->type == DRM_PLANE_TYPE_CURSOR)
+			cursor_plane = true;
+	}
+
+	/* bail out early if there aren't any planes */
+	if (!cnt)
+		return 0;
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	/*
+	 * we need a right hwmixer if the mode's width is greater than a single
+	 * LM's max width
+	 */
+	if (mode->hdisplay > hw_cfg->lm.max_width)
+		need_right_mixer = true;
+
+	ret = mdp5_crtc_setup_pipeline(crtc, state, need_right_mixer);
+	if (ret) {
+		dev_err(dev->dev, "couldn't assign mixers %d\n", ret);
+		return ret;
+	}
+
+	/* assign a stage based on sorted zpos property */
+	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
+
+	/* trigger a warning if cursor isn't the highest zorder */
+	WARN_ON(cursor_plane &&
+		(pstates[cnt - 1].plane->type != DRM_PLANE_TYPE_CURSOR));
+
+	start = get_start_stage(crtc, state, &pstates[0].state->base);
+
+	/* verify that there are not too many planes attached to crtc
+	 * and that we don't have conflicting mixer stages:
+	 */
+	if ((cnt + start - 1) >= hw_cfg->lm.nb_stages) {
+		dev_err(dev->dev, "too many planes! cnt=%d, start stage=%d\n",
+			cnt, start);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (cursor_plane && (i == (cnt - 1)))
+			pstates[i].state->stage = hw_cfg->lm.nb_stages;
+		else
+			pstates[i].state->stage = start + i;
+		DBG("%s: assign pipe %s on stage=%d", crtc->name,
+				pstates[i].plane->name,
+				pstates[i].state->stage);
+	}
+
+	return 0;
+}
+
+static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	DBG("%s: begin", crtc->name);
+}
+
+static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc,
+				   struct drm_crtc_state *old_crtc_state)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct drm_device *dev = crtc->dev;
+	unsigned long flags;
+
+	DBG("%s: event: %p", crtc->name, crtc->state->event);
+
+	WARN_ON(mdp5_crtc->event);
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	mdp5_crtc->event = crtc->state->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	/*
+	 * If no CTL has been allocated in mdp5_crtc_atomic_check(),
+	 * it means we are trying to flush a CRTC whose state is disabled:
+	 * nothing else needs to be done.
+	 */
+	/* XXX: Can this happen now ? */
+	if (unlikely(!mdp5_cstate->ctl))
+		return;
+
+	blend_setup(crtc);
+
+	/* PP_DONE irq is only used by command mode for now.
+	 * It is better to request pending before FLUSH and START trigger
+	 * to make sure no pp_done irq missed.
+	 * This is safe because no pp_done will happen before SW trigger
+	 * in command mode.
+	 */
+	if (mdp5_cstate->cmd_mode)
+		request_pp_done_pending(crtc);
+
+	mdp5_crtc->flushed_mask = crtc_flush_all(crtc);
+
+	/* XXX are we leaking out state here? */
+	mdp5_crtc->vblank.irqmask = mdp5_cstate->vblank_irqmask;
+	mdp5_crtc->err.irqmask = mdp5_cstate->err_irqmask;
+	mdp5_crtc->pp_done.irqmask = mdp5_cstate->pp_done_irqmask;
+
+	request_pending(crtc, PENDING_FLIP);
+}
+
+static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	uint32_t xres = crtc->mode.hdisplay;
+	uint32_t yres = crtc->mode.vdisplay;
+
+	/*
+	 * Cursor Region Of Interest (ROI) is a plane read from cursor
+	 * buffer to render. The ROI region is determined by the visibility of
+	 * the cursor point. In the default Cursor image the cursor point will
+	 * be at the top left of the cursor image, unless it is specified
+	 * otherwise using hotspot feature.
+	 *
+	 * If the cursor point reaches the right (xres - x < cursor.width) or
+	 * bottom (yres - y < cursor.height) boundary of the screen, then ROI
+	 * width and ROI height need to be evaluated to crop the cursor image
+	 * accordingly.
+	 * (xres-x) will be new cursor width when x > (xres - cursor.width)
+	 * (yres-y) will be new cursor height when y > (yres - cursor.height)
+	 */
+	*roi_w = min(mdp5_crtc->cursor.width, xres -
+			mdp5_crtc->cursor.x);
+	*roi_h = min(mdp5_crtc->cursor.height, yres -
+			mdp5_crtc->cursor.y);
+}
+
+static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	const enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
+	uint32_t blendcfg, stride;
+	uint32_t x, y, width, height;
+	uint32_t roi_w, roi_h;
+	int lm;
+
+	assert_spin_locked(&mdp5_crtc->cursor.lock);
+
+	lm = mdp5_cstate->pipeline.mixer->lm;
+
+	x = mdp5_crtc->cursor.x;
+	y = mdp5_crtc->cursor.y;
+	width = mdp5_crtc->cursor.width;
+	height = mdp5_crtc->cursor.height;
+
+	stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0);
+
+	get_roi(crtc, &roi_w, &roi_h);
+
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
+			MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm),
+			MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
+			MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
+			MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
+			MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(lm),
+			MDP5_LM_CURSOR_START_XY_Y_START(y) |
+			MDP5_LM_CURSOR_START_XY_X_START(x));
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm),
+			mdp5_crtc->cursor.iova);
+
+	blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
+	blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
+}
+
+static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
+		struct drm_file *file, uint32_t handle,
+		uint32_t width, uint32_t height)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+	struct drm_device *dev = crtc->dev;
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct platform_device *pdev = mdp5_kms->pdev;
+	struct msm_kms *kms = &mdp5_kms->base.base;
+	struct drm_gem_object *cursor_bo, *old_bo = NULL;
+	struct mdp5_ctl *ctl;
+	int ret;
+	uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+	bool cursor_enable = true;
+	unsigned long flags;
+
+	if (!mdp5_crtc->lm_cursor_enabled) {
+		dev_warn(dev->dev,
+			 "cursor_set is deprecated with cursor planes\n");
+		return -EINVAL;
+	}
+
+	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
+		return -EINVAL;
+	}
+
+	ctl = mdp5_cstate->ctl;
+	if (!ctl)
+		return -EINVAL;
+
+	/* don't support LM cursors when we we have source split enabled */
+	if (mdp5_cstate->pipeline.r_mixer)
+		return -EINVAL;
+
+	if (!handle) {
+		DBG("Cursor off");
+		cursor_enable = false;
+		mdp5_crtc->cursor.iova = 0;
+		pm_runtime_get_sync(&pdev->dev);
+		goto set_cursor;
+	}
+
+	cursor_bo = drm_gem_object_lookup(file, handle);
+	if (!cursor_bo)
+		return -ENOENT;
+
+	ret = msm_gem_get_iova(cursor_bo, kms->aspace,
+			&mdp5_crtc->cursor.iova);
+	if (ret)
+		return -EINVAL;
+
+	pm_runtime_get_sync(&pdev->dev);
+
+	spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+	old_bo = mdp5_crtc->cursor.scanout_bo;
+
+	mdp5_crtc->cursor.scanout_bo = cursor_bo;
+	mdp5_crtc->cursor.width = width;
+	mdp5_crtc->cursor.height = height;
+
+	mdp5_crtc_restore_cursor(crtc);
+
+	spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+set_cursor:
+	ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable);
+	if (ret) {
+		dev_err(dev->dev, "failed to %sable cursor: %d\n",
+				cursor_enable ? "en" : "dis", ret);
+		goto end;
+	}
+
+	crtc_flush(crtc, flush_mask);
+
+end:
+	pm_runtime_put_sync(&pdev->dev);
+	if (old_bo) {
+		drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
+		/* enable vblank to complete cursor work: */
+		request_pending(crtc, PENDING_CURSOR);
+	}
+	return ret;
+}
+
+static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+	struct drm_device *dev = crtc->dev;
+	uint32_t roi_w;
+	uint32_t roi_h;
+	unsigned long flags;
+
+	if (!mdp5_crtc->lm_cursor_enabled) {
+		dev_warn(dev->dev,
+			 "cursor_move is deprecated with cursor planes\n");
+		return -EINVAL;
+	}
+
+	/* don't support LM cursors when we we have source split enabled */
+	if (mdp5_cstate->pipeline.r_mixer)
+		return -EINVAL;
+
+	/* In case the CRTC is disabled, just drop the cursor update */
+	if (unlikely(!crtc->state->enable))
+		return 0;
+
+	mdp5_crtc->cursor.x = x = max(x, 0);
+	mdp5_crtc->cursor.y = y = max(y, 0);
+
+	get_roi(crtc, &roi_w, &roi_h);
+
+	pm_runtime_get_sync(&mdp5_kms->pdev->dev);
+
+	spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+	mdp5_crtc_restore_cursor(crtc);
+	spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+	crtc_flush(crtc, flush_mask);
+
+	pm_runtime_put_sync(&mdp5_kms->pdev->dev);
+
+	return 0;
+}
+
+static void
+mdp5_crtc_atomic_print_state(struct drm_printer *p,
+			     const struct drm_crtc_state *state)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state);
+	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+	struct mdp5_kms *mdp5_kms = get_kms(state->crtc);
+
+	if (WARN_ON(!pipeline))
+		return;
+
+	drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ?
+			pipeline->mixer->name : "(null)");
+
+	if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
+		drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ?
+			   pipeline->r_mixer->name : "(null)");
+}
+
+static void mdp5_crtc_reset(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate;
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+		kfree(to_mdp5_crtc_state(crtc->state));
+	}
+
+	mdp5_cstate = kzalloc(sizeof(*mdp5_cstate), GFP_KERNEL);
+
+	if (mdp5_cstate) {
+		mdp5_cstate->base.crtc = crtc;
+		crtc->state = &mdp5_cstate->base;
+	}
+}
+
+static struct drm_crtc_state *
+mdp5_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	mdp5_cstate = kmemdup(to_mdp5_crtc_state(crtc->state),
+			      sizeof(*mdp5_cstate), GFP_KERNEL);
+	if (!mdp5_cstate)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base);
+
+	return &mdp5_cstate->base;
+}
+
+static void mdp5_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state);
+
+	__drm_atomic_helper_crtc_destroy_state(state);
+
+	kfree(mdp5_cstate);
+}
+
+static const struct drm_crtc_funcs mdp5_crtc_funcs = {
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = mdp5_crtc_destroy,
+	.page_flip = drm_atomic_helper_page_flip,
+	.reset = mdp5_crtc_reset,
+	.atomic_duplicate_state = mdp5_crtc_duplicate_state,
+	.atomic_destroy_state = mdp5_crtc_destroy_state,
+	.cursor_set = mdp5_crtc_cursor_set,
+	.cursor_move = mdp5_crtc_cursor_move,
+	.atomic_print_state = mdp5_crtc_atomic_print_state,
+};
+
+static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
+	.mode_set_nofb = mdp5_crtc_mode_set_nofb,
+	.atomic_check = mdp5_crtc_atomic_check,
+	.atomic_begin = mdp5_crtc_atomic_begin,
+	.atomic_flush = mdp5_crtc_atomic_flush,
+	.atomic_enable = mdp5_crtc_atomic_enable,
+	.atomic_disable = mdp5_crtc_atomic_disable,
+};
+
+static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
+	struct drm_crtc *crtc = &mdp5_crtc->base;
+	struct msm_drm_private *priv = crtc->dev->dev_private;
+	unsigned pending;
+
+	mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);
+
+	pending = atomic_xchg(&mdp5_crtc->pending, 0);
+
+	if (pending & PENDING_FLIP) {
+		complete_flip(crtc, NULL);
+	}
+
+	if (pending & PENDING_CURSOR)
+		drm_flip_work_commit(&mdp5_crtc->unref_cursor_work, priv->wq);
+}
+
+static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, err);
+
+	DBG("%s: error: %08x", mdp5_crtc->base.name, irqstatus);
+}
+
+static void mdp5_crtc_pp_done_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc,
+								pp_done);
+
+	complete(&mdp5_crtc->pp_completion);
+}
+
+static void mdp5_crtc_wait_for_pp_done(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	int ret;
+
+	ret = wait_for_completion_timeout(&mdp5_crtc->pp_completion,
+						msecs_to_jiffies(50));
+	if (ret == 0)
+		dev_warn(dev->dev, "pp done time out, lm=%d\n",
+			 mdp5_cstate->pipeline.mixer->lm);
+}
+
+static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
+	int ret;
+
+	/* Should not call this function if crtc is disabled. */
+	if (!ctl)
+		return;
+
+	ret = drm_crtc_vblank_get(crtc);
+	if (ret)
+		return;
+
+	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
+		((mdp5_ctl_get_commit_status(ctl) &
+		mdp5_crtc->flushed_mask) == 0),
+		msecs_to_jiffies(50));
+	if (ret <= 0)
+		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp5_crtc->id);
+
+	mdp5_crtc->flushed_mask = 0;
+
+	drm_crtc_vblank_put(crtc);
+}
+
+uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	return mdp5_crtc->vblank.irqmask;
+}
+
+void mdp5_crtc_set_pipeline(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+
+	/* should this be done elsewhere ? */
+	mdp_irq_update(&mdp5_kms->base);
+
+	mdp5_ctl_set_pipeline(mdp5_cstate->ctl, &mdp5_cstate->pipeline);
+}
+
+struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+
+	return mdp5_cstate->ctl;
+}
+
+struct mdp5_hw_mixer *mdp5_crtc_get_mixer(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate;
+
+	if (WARN_ON(!crtc))
+		return ERR_PTR(-EINVAL);
+
+	mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+
+	return WARN_ON(!mdp5_cstate->pipeline.mixer) ?
+		ERR_PTR(-EINVAL) : mdp5_cstate->pipeline.mixer;
+}
+
+struct mdp5_pipeline *mdp5_crtc_get_pipeline(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate;
+
+	if (WARN_ON(!crtc))
+		return ERR_PTR(-EINVAL);
+
+	mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+
+	return &mdp5_cstate->pipeline;
+}
+
+void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
+{
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
+
+	if (mdp5_cstate->cmd_mode)
+		mdp5_crtc_wait_for_pp_done(crtc);
+	else
+		mdp5_crtc_wait_for_flush_done(crtc);
+}
+
+/* initialize crtc */
+struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
+				struct drm_plane *plane,
+				struct drm_plane *cursor_plane, int id)
+{
+	struct drm_crtc *crtc = NULL;
+	struct mdp5_crtc *mdp5_crtc;
+
+	mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL);
+	if (!mdp5_crtc)
+		return ERR_PTR(-ENOMEM);
+
+	crtc = &mdp5_crtc->base;
+
+	mdp5_crtc->id = id;
+
+	spin_lock_init(&mdp5_crtc->lm_lock);
+	spin_lock_init(&mdp5_crtc->cursor.lock);
+	init_completion(&mdp5_crtc->pp_completion);
+
+	mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
+	mdp5_crtc->err.irq = mdp5_crtc_err_irq;
+	mdp5_crtc->pp_done.irq = mdp5_crtc_pp_done_irq;
+
+	mdp5_crtc->lm_cursor_enabled = cursor_plane ? false : true;
+
+	drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane,
+				  &mdp5_crtc_funcs, NULL);
+
+	drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
+			"unref cursor", unref_cursor_worker);
+
+	drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
+	plane->crtc = crtc;
+
+	return crtc;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c
new file mode 100644
index 000000000000..439e0a300e25
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "mdp5_kms.h"
+#include "mdp5_ctl.h"
+
+/*
+ * CTL - MDP Control Pool Manager
+ *
+ * Controls are shared between all display interfaces.
+ *
+ * They are intended to be used for data path configuration.
+ * The top level register programming describes the complete data path for
+ * a specific data path ID - REG_MDP5_CTL_*(<id>, ...)
+ *
+ * Hardware capabilities determine the number of concurrent data paths
+ *
+ * In certain use cases (high-resolution dual pipe), one single CTL can be
+ * shared across multiple CRTCs.
+ */
+
+#define CTL_STAT_BUSY		0x1
+#define CTL_STAT_BOOKED	0x2
+
+struct mdp5_ctl {
+	struct mdp5_ctl_manager *ctlm;
+
+	u32 id;
+
+	/* CTL status bitmask */
+	u32 status;
+
+	bool encoder_enabled;
+	uint32_t start_mask;
+
+	/* REG_MDP5_CTL_*(<id>) registers access info + lock: */
+	spinlock_t hw_lock;
+	u32 reg_offset;
+
+	/* when do CTL registers need to be flushed? (mask of trigger bits) */
+	u32 pending_ctl_trigger;
+
+	bool cursor_on;
+
+	/* True if the current CTL has FLUSH bits pending for single FLUSH. */
+	bool flush_pending;
+
+	struct mdp5_ctl *pair; /* Paired CTL to be flushed together */
+};
+
+struct mdp5_ctl_manager {
+	struct drm_device *dev;
+
+	/* number of CTL / Layer Mixers in this hw config: */
+	u32 nlm;
+	u32 nctl;
+
+	/* to filter out non-present bits in the current hardware config */
+	u32 flush_hw_mask;
+
+	/* status for single FLUSH */
+	bool single_flush_supported;
+	u32 single_flush_pending_mask;
+
+	/* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
+	spinlock_t pool_lock;
+	struct mdp5_ctl ctls[MAX_CTL];
+};
+
+static inline
+struct mdp5_kms *get_kms(struct mdp5_ctl_manager *ctl_mgr)
+{
+	struct msm_drm_private *priv = ctl_mgr->dev->dev_private;
+
+	return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static inline
+void ctl_write(struct mdp5_ctl *ctl, u32 reg, u32 data)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
+
+	(void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
+	mdp5_write(mdp5_kms, reg, data);
+}
+
+static inline
+u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
+
+	(void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
+	return mdp5_read(mdp5_kms, reg);
+}
+
+static void set_display_intf(struct mdp5_kms *mdp5_kms,
+		struct mdp5_interface *intf)
+{
+	unsigned long flags;
+	u32 intf_sel;
+
+	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
+	intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
+
+	switch (intf->num) {
+	case 0:
+		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
+		intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf->type);
+		break;
+	case 1:
+		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
+		intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf->type);
+		break;
+	case 2:
+		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
+		intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf->type);
+		break;
+	case 3:
+		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
+		intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf->type);
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
+	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+}
+
+static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
+{
+	unsigned long flags;
+	struct mdp5_interface *intf = pipeline->intf;
+	u32 ctl_op = 0;
+
+	if (!mdp5_cfg_intf_is_virtual(intf->type))
+		ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
+
+	switch (intf->type) {
+	case INTF_DSI:
+		if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+			ctl_op |= MDP5_CTL_OP_CMD_MODE;
+		break;
+
+	case INTF_WB:
+		if (intf->mode == MDP5_INTF_WB_MODE_LINE)
+			ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
+		break;
+
+	default:
+		break;
+	}
+
+	if (pipeline->r_mixer)
+		ctl_op |= MDP5_CTL_OP_PACK_3D_ENABLE |
+			  MDP5_CTL_OP_PACK_3D(1);
+
+	spin_lock_irqsave(&ctl->hw_lock, flags);
+	ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
+	spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
+{
+	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+	struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
+	struct mdp5_interface *intf = pipeline->intf;
+	struct mdp5_hw_mixer *mixer = pipeline->mixer;
+	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
+
+	ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) |
+			  mdp_ctl_flush_mask_encoder(intf);
+	if (r_mixer)
+		ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
+
+	/* Virtual interfaces need not set a display intf (e.g.: Writeback) */
+	if (!mdp5_cfg_intf_is_virtual(intf->type))
+		set_display_intf(mdp5_kms, intf);
+
+	set_ctl_op(ctl, pipeline);
+
+	return 0;
+}
+
+static bool start_signal_needed(struct mdp5_ctl *ctl,
+				struct mdp5_pipeline *pipeline)
+{
+	struct mdp5_interface *intf = pipeline->intf;
+
+	if (!ctl->encoder_enabled || ctl->start_mask != 0)
+		return false;
+
+	switch (intf->type) {
+	case INTF_WB:
+		return true;
+	case INTF_DSI:
+		return intf->mode == MDP5_INTF_DSI_MODE_COMMAND;
+	default:
+		return false;
+	}
+}
+
+/*
+ * send_start_signal() - Overlay Processor Start Signal
+ *
+ * For a given control operation (display pipeline), a START signal needs to be
+ * executed in order to kick off operation and activate all layers.
+ * e.g.: DSI command mode, Writeback
+ */
+static void send_start_signal(struct mdp5_ctl *ctl)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctl->hw_lock, flags);
+	ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1);
+	spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+static void refill_start_mask(struct mdp5_ctl *ctl,
+			      struct mdp5_pipeline *pipeline)
+{
+	struct mdp5_interface *intf = pipeline->intf;
+	struct mdp5_hw_mixer *mixer = pipeline->mixer;
+	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
+
+	ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm);
+	if (r_mixer)
+		ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
+
+	/*
+	 * Writeback encoder needs to program & flush
+	 * address registers for each page flip..
+	 */
+	if (intf->type == INTF_WB)
+		ctl->start_mask |= mdp_ctl_flush_mask_encoder(intf);
+}
+
+/**
+ * mdp5_ctl_set_encoder_state() - set the encoder state
+ *
+ * @enable: true, when encoder is ready for data streaming; false, otherwise.
+ *
+ * Note:
+ * This encoder state is needed to trigger START signal (data path kickoff).
+ */
+int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl,
+			       struct mdp5_pipeline *pipeline,
+			       bool enabled)
+{
+	struct mdp5_interface *intf = pipeline->intf;
+
+	if (WARN_ON(!ctl))
+		return -EINVAL;
+
+	ctl->encoder_enabled = enabled;
+	DBG("intf_%d: %s", intf->num, enabled ? "on" : "off");
+
+	if (start_signal_needed(ctl, pipeline)) {
+		send_start_signal(ctl);
+		refill_start_mask(ctl, pipeline);
+	}
+
+	return 0;
+}
+
+/*
+ * Note:
+ * CTL registers need to be flushed after calling this function
+ * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
+ */
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
+			int cursor_id, bool enable)
+{
+	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+	unsigned long flags;
+	u32 blend_cfg;
+	struct mdp5_hw_mixer *mixer = pipeline->mixer;
+
+	if (unlikely(WARN_ON(!mixer))) {
+		dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM",
+			ctl->id);
+		return -EINVAL;
+	}
+
+	if (pipeline->r_mixer) {
+		dev_err(ctl_mgr->dev->dev, "unsupported configuration");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ctl->hw_lock, flags);
+
+	blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm));
+
+	if (enable)
+		blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
+	else
+		blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
+
+	ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
+	ctl->cursor_on = enable;
+
+	spin_unlock_irqrestore(&ctl->hw_lock, flags);
+
+	ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
+
+	return 0;
+}
+
+static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
+		enum mdp_mixer_stage_id stage)
+{
+	switch (pipe) {
+	case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
+	case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
+	case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
+	case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
+	case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
+	case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
+	case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
+	case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
+	case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
+	case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
+	case SSPP_CURSOR0:
+	case SSPP_CURSOR1:
+	default:	return 0;
+	}
+}
+
+static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
+		enum mdp_mixer_stage_id stage)
+{
+	if (stage < STAGE6 && (pipe != SSPP_CURSOR0 && pipe != SSPP_CURSOR1))
+		return 0;
+
+	switch (pipe) {
+	case SSPP_VIG0: return MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3;
+	case SSPP_VIG1: return MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3;
+	case SSPP_VIG2: return MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3;
+	case SSPP_RGB0: return MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3;
+	case SSPP_RGB1: return MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3;
+	case SSPP_RGB2: return MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3;
+	case SSPP_DMA0: return MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3;
+	case SSPP_DMA1: return MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3;
+	case SSPP_VIG3: return MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3;
+	case SSPP_RGB3: return MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3;
+	case SSPP_CURSOR0: return MDP5_CTL_LAYER_EXT_REG_CURSOR0(stage);
+	case SSPP_CURSOR1: return MDP5_CTL_LAYER_EXT_REG_CURSOR1(stage);
+	default:	return 0;
+	}
+}
+
+static void mdp5_ctl_reset_blend_regs(struct mdp5_ctl *ctl)
+{
+	unsigned long flags;
+	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+	int i;
+
+	spin_lock_irqsave(&ctl->hw_lock, flags);
+
+	for (i = 0; i < ctl_mgr->nlm; i++) {
+		ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, i), 0x0);
+		ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, i), 0x0);
+	}
+
+	spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+#define PIPE_LEFT	0
+#define PIPE_RIGHT	1
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
+		   enum mdp5_pipe stage[][MAX_PIPE_STAGE],
+		   enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
+		   u32 stage_cnt, u32 ctl_blend_op_flags)
+{
+	struct mdp5_hw_mixer *mixer = pipeline->mixer;
+	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
+	unsigned long flags;
+	u32 blend_cfg = 0, blend_ext_cfg = 0;
+	u32 r_blend_cfg = 0, r_blend_ext_cfg = 0;
+	int i, start_stage;
+
+	mdp5_ctl_reset_blend_regs(ctl);
+
+	if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
+		start_stage = STAGE0;
+		blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
+		if (r_mixer)
+			r_blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
+	} else {
+		start_stage = STAGE_BASE;
+	}
+
+	for (i = start_stage; stage_cnt && i <= STAGE_MAX; i++) {
+		blend_cfg |=
+			mdp_ctl_blend_mask(stage[i][PIPE_LEFT], i) |
+			mdp_ctl_blend_mask(stage[i][PIPE_RIGHT], i);
+		blend_ext_cfg |=
+			mdp_ctl_blend_ext_mask(stage[i][PIPE_LEFT], i) |
+			mdp_ctl_blend_ext_mask(stage[i][PIPE_RIGHT], i);
+		if (r_mixer) {
+			r_blend_cfg |=
+				mdp_ctl_blend_mask(r_stage[i][PIPE_LEFT], i) |
+				mdp_ctl_blend_mask(r_stage[i][PIPE_RIGHT], i);
+			r_blend_ext_cfg |=
+			     mdp_ctl_blend_ext_mask(r_stage[i][PIPE_LEFT], i) |
+			     mdp_ctl_blend_ext_mask(r_stage[i][PIPE_RIGHT], i);
+		}
+	}
+
+	spin_lock_irqsave(&ctl->hw_lock, flags);
+	if (ctl->cursor_on)
+		blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
+
+	ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
+	ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, mixer->lm),
+		  blend_ext_cfg);
+	if (r_mixer) {
+		ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, r_mixer->lm),
+			  r_blend_cfg);
+		ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, r_mixer->lm),
+			  r_blend_ext_cfg);
+	}
+	spin_unlock_irqrestore(&ctl->hw_lock, flags);
+
+	ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(mixer->lm);
+	if (r_mixer)
+		ctl->pending_ctl_trigger |= mdp_ctl_flush_mask_lm(r_mixer->lm);
+
+	DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", mixer->lm,
+		blend_cfg, blend_ext_cfg);
+	if (r_mixer)
+		DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x",
+		    r_mixer->lm, r_blend_cfg, r_blend_ext_cfg);
+
+	return 0;
+}
+
+u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf)
+{
+	if (intf->type == INTF_WB)
+		return MDP5_CTL_FLUSH_WB;
+
+	switch (intf->num) {
+	case 0: return MDP5_CTL_FLUSH_TIMING_0;
+	case 1: return MDP5_CTL_FLUSH_TIMING_1;
+	case 2: return MDP5_CTL_FLUSH_TIMING_2;
+	case 3: return MDP5_CTL_FLUSH_TIMING_3;
+	default: return 0;
+	}
+}
+
+u32 mdp_ctl_flush_mask_cursor(int cursor_id)
+{
+	switch (cursor_id) {
+	case 0: return MDP5_CTL_FLUSH_CURSOR_0;
+	case 1: return MDP5_CTL_FLUSH_CURSOR_1;
+	default: return 0;
+	}
+}
+
+u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
+{
+	switch (pipe) {
+	case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
+	case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
+	case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
+	case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
+	case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
+	case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
+	case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
+	case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
+	case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
+	case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
+	case SSPP_CURSOR0: return MDP5_CTL_FLUSH_CURSOR_0;
+	case SSPP_CURSOR1: return MDP5_CTL_FLUSH_CURSOR_1;
+	default:        return 0;
+	}
+}
+
+u32 mdp_ctl_flush_mask_lm(int lm)
+{
+	switch (lm) {
+	case 0:  return MDP5_CTL_FLUSH_LM0;
+	case 1:  return MDP5_CTL_FLUSH_LM1;
+	case 2:  return MDP5_CTL_FLUSH_LM2;
+	case 5:  return MDP5_CTL_FLUSH_LM5;
+	default: return 0;
+	}
+}
+
+static u32 fix_sw_flush(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
+			u32 flush_mask)
+{
+	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+	u32 sw_mask = 0;
+#define BIT_NEEDS_SW_FIX(bit) \
+	(!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit))
+
+	/* for some targets, cursor bit is the same as LM bit */
+	if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0))
+		sw_mask |= mdp_ctl_flush_mask_lm(pipeline->mixer->lm);
+
+	return sw_mask;
+}
+
+static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask,
+		u32 *flush_id)
+{
+	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+
+	if (ctl->pair) {
+		DBG("CTL %d FLUSH pending mask %x", ctl->id, *flush_mask);
+		ctl->flush_pending = true;
+		ctl_mgr->single_flush_pending_mask |= (*flush_mask);
+		*flush_mask = 0;
+
+		if (ctl->pair->flush_pending) {
+			*flush_id = min_t(u32, ctl->id, ctl->pair->id);
+			*flush_mask = ctl_mgr->single_flush_pending_mask;
+
+			ctl->flush_pending = false;
+			ctl->pair->flush_pending = false;
+			ctl_mgr->single_flush_pending_mask = 0;
+
+			DBG("Single FLUSH mask %x,ID %d", *flush_mask,
+				*flush_id);
+		}
+	}
+}
+
+/**
+ * mdp5_ctl_commit() - Register Flush
+ *
+ * The flush register is used to indicate several registers are all
+ * programmed, and are safe to update to the back copy of the double
+ * buffered registers.
+ *
+ * Some registers FLUSH bits are shared when the hardware does not have
+ * dedicated bits for them; handling these is the job of fix_sw_flush().
+ *
+ * CTL registers need to be flushed in some circumstances; if that is the
+ * case, some trigger bits will be present in both flush mask and
+ * ctl->pending_ctl_trigger.
+ *
+ * Return H/W flushed bit mask.
+ */
+u32 mdp5_ctl_commit(struct mdp5_ctl *ctl,
+		    struct mdp5_pipeline *pipeline,
+		    u32 flush_mask)
+{
+	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+	unsigned long flags;
+	u32 flush_id = ctl->id;
+	u32 curr_ctl_flush_mask;
+
+	ctl->start_mask &= ~flush_mask;
+
+	VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask,
+			ctl->start_mask, ctl->pending_ctl_trigger);
+
+	if (ctl->pending_ctl_trigger & flush_mask) {
+		flush_mask |= MDP5_CTL_FLUSH_CTL;
+		ctl->pending_ctl_trigger = 0;
+	}
+
+	flush_mask |= fix_sw_flush(ctl, pipeline, flush_mask);
+
+	flush_mask &= ctl_mgr->flush_hw_mask;
+
+	curr_ctl_flush_mask = flush_mask;
+
+	fix_for_single_flush(ctl, &flush_mask, &flush_id);
+
+	if (flush_mask) {
+		spin_lock_irqsave(&ctl->hw_lock, flags);
+		ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask);
+		spin_unlock_irqrestore(&ctl->hw_lock, flags);
+	}
+
+	if (start_signal_needed(ctl, pipeline)) {
+		send_start_signal(ctl);
+		refill_start_mask(ctl, pipeline);
+	}
+
+	return curr_ctl_flush_mask;
+}
+
+u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
+{
+	return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id));
+}
+
+int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
+{
+	return WARN_ON(!ctl) ? -EINVAL : ctl->id;
+}
+
+/*
+ * mdp5_ctl_pair() - Associate 2 booked CTLs for single FLUSH
+ */
+int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable)
+{
+	struct mdp5_ctl_manager *ctl_mgr = ctlx->ctlm;
+	struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
+
+	/* do nothing silently if hw doesn't support */
+	if (!ctl_mgr->single_flush_supported)
+		return 0;
+
+	if (!enable) {
+		ctlx->pair = NULL;
+		ctly->pair = NULL;
+		mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, 0);
+		return 0;
+	} else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) {
+		dev_err(ctl_mgr->dev->dev, "CTLs already paired\n");
+		return -EINVAL;
+	} else if (!(ctlx->status & ctly->status & CTL_STAT_BOOKED)) {
+		dev_err(ctl_mgr->dev->dev, "Only pair booked CTLs\n");
+		return -EINVAL;
+	}
+
+	ctlx->pair = ctly;
+	ctly->pair = ctlx;
+
+	mdp5_write(mdp5_kms, REG_MDP5_SPARE_0,
+		   MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
+
+	return 0;
+}
+
+/*
+ * mdp5_ctl_request() - CTL allocation
+ *
+ * Try to return booked CTL for @intf_num is 1 or 2, unbooked for other INTFs.
+ * If no CTL is available in preferred category, allocate from the other one.
+ *
+ * @return fail if no CTL is available.
+ */
+struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
+		int intf_num)
+{
+	struct mdp5_ctl *ctl = NULL;
+	const u32 checkm = CTL_STAT_BUSY | CTL_STAT_BOOKED;
+	u32 match = ((intf_num == 1) || (intf_num == 2)) ? CTL_STAT_BOOKED : 0;
+	unsigned long flags;
+	int c;
+
+	spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
+
+	/* search the preferred */
+	for (c = 0; c < ctl_mgr->nctl; c++)
+		if ((ctl_mgr->ctls[c].status & checkm) == match)
+			goto found;
+
+	dev_warn(ctl_mgr->dev->dev,
+		"fall back to the other CTL category for INTF %d!\n", intf_num);
+
+	match ^= CTL_STAT_BOOKED;
+	for (c = 0; c < ctl_mgr->nctl; c++)
+		if ((ctl_mgr->ctls[c].status & checkm) == match)
+			goto found;
+
+	dev_err(ctl_mgr->dev->dev, "No more CTL available!");
+	goto unlock;
+
+found:
+	ctl = &ctl_mgr->ctls[c];
+	ctl->status |= CTL_STAT_BUSY;
+	ctl->pending_ctl_trigger = 0;
+	DBG("CTL %d allocated", ctl->id);
+
+unlock:
+	spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+	return ctl;
+}
+
+void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctl_mgr)
+{
+	unsigned long flags;
+	int c;
+
+	for (c = 0; c < ctl_mgr->nctl; c++) {
+		struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
+
+		spin_lock_irqsave(&ctl->hw_lock, flags);
+		ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), 0);
+		spin_unlock_irqrestore(&ctl->hw_lock, flags);
+	}
+}
+
+void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr)
+{
+	kfree(ctl_mgr);
+}
+
+struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
+		void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd)
+{
+	struct mdp5_ctl_manager *ctl_mgr;
+	const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd);
+	int rev = mdp5_cfg_get_hw_rev(cfg_hnd);
+	const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
+	unsigned long flags;
+	int c, ret;
+
+	ctl_mgr = kzalloc(sizeof(*ctl_mgr), GFP_KERNEL);
+	if (!ctl_mgr) {
+		dev_err(dev->dev, "failed to allocate CTL manager\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	if (unlikely(WARN_ON(ctl_cfg->count > MAX_CTL))) {
+		dev_err(dev->dev, "Increase static pool size to at least %d\n",
+				ctl_cfg->count);
+		ret = -ENOSPC;
+		goto fail;
+	}
+
+	/* initialize the CTL manager: */
+	ctl_mgr->dev = dev;
+	ctl_mgr->nlm = hw_cfg->lm.count;
+	ctl_mgr->nctl = ctl_cfg->count;
+	ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask;
+	spin_lock_init(&ctl_mgr->pool_lock);
+
+	/* initialize each CTL of the pool: */
+	spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
+	for (c = 0; c < ctl_mgr->nctl; c++) {
+		struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
+
+		if (WARN_ON(!ctl_cfg->base[c])) {
+			dev_err(dev->dev, "CTL_%d: base is null!\n", c);
+			ret = -EINVAL;
+			spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+			goto fail;
+		}
+		ctl->ctlm = ctl_mgr;
+		ctl->id = c;
+		ctl->reg_offset = ctl_cfg->base[c];
+		ctl->status = 0;
+		spin_lock_init(&ctl->hw_lock);
+	}
+
+	/*
+	 * In Dual DSI case, CTL0 and CTL1 are always assigned to two DSI
+	 * interfaces to support single FLUSH feature (Flush CTL0 and CTL1 when
+	 * only write into CTL0's FLUSH register) to keep two DSI pipes in sync.
+	 * Single FLUSH is supported from hw rev v3.0.
+	 */
+	if (rev >= 3) {
+		ctl_mgr->single_flush_supported = true;
+		/* Reserve CTL0/1 for INTF1/2 */
+		ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED;
+		ctl_mgr->ctls[1].status |= CTL_STAT_BOOKED;
+	}
+	spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+	DBG("Pool of %d CTLs created.", ctl_mgr->nctl);
+
+	return ctl_mgr;
+
+fail:
+	if (ctl_mgr)
+		mdp5_ctlm_destroy(ctl_mgr);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h
new file mode 100644
index 000000000000..b63120388dc6
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDP5_CTL_H__
+#define __MDP5_CTL_H__
+
+#include "msm_drv.h"
+
+/*
+ * CTL Manager prototypes:
+ * mdp5_ctlm_init() returns a ctlm (CTL Manager) handler,
+ * which is then used to call the other mdp5_ctlm_*(ctlm, ...) functions.
+ */
+struct mdp5_ctl_manager;
+struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
+		void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd);
+void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm);
+void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
+
+/*
+ * CTL prototypes:
+ * mdp5_ctl_request(ctlm, ...) returns a ctl (CTL resource) handler,
+ * which is then used to call the other mdp5_ctl_*(ctl, ...) functions.
+ */
+struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, int intf_num);
+
+int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl);
+
+struct mdp5_interface;
+struct mdp5_pipeline;
+int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *p);
+int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, struct mdp5_pipeline *p,
+			       bool enabled);
+
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
+			int cursor_id, bool enable);
+int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
+
+#define MAX_PIPE_STAGE		2
+
+/*
+ * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
+ *
+ * @stage: array to contain the pipe num for each stage
+ * @stage_cnt: valid stage number in stage array
+ * @ctl_blend_op_flags: blender operation mode flags
+ *
+ * Note:
+ * CTL registers need to be flushed after calling this function
+ * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
+ */
+#define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT	BIT(0)
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
+		   enum mdp5_pipe stage[][MAX_PIPE_STAGE],
+		   enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
+		   u32 stage_cnt, u32 ctl_blend_op_flags);
+
+/**
+ * mdp_ctl_flush_mask...() - Register FLUSH masks
+ *
+ * These masks are used to specify which block(s) need to be flushed
+ * through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask).
+ */
+u32 mdp_ctl_flush_mask_lm(int lm);
+u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe);
+u32 mdp_ctl_flush_mask_cursor(int cursor_id);
+u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
+
+/* @flush_mask: see CTL flush masks definitions below */
+u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
+		    u32 flush_mask);
+u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl);
+
+
+
+#endif /* __MDP5_CTL_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
new file mode 100644
index 000000000000..36ad3cbe5f79
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "mdp5_kms.h"
+
+static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
+{
+	struct msm_drm_private *priv = encoder->dev->dev_private;
+	return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+	{						\
+		.src = MSM_BUS_MASTER_MDP_PORT0,	\
+		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
+		.ab = (ab_val),				\
+		.ib = (ib_val),				\
+	}
+
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+	MDP_BUS_VECTOR_ENTRY(0, 0),
+	MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
+};
+static struct msm_bus_paths mdp_bus_usecases[] = { {
+		.num_paths = 1,
+		.vectors = &mdp_bus_vectors[0],
+}, {
+		.num_paths = 1,
+		.vectors = &mdp_bus_vectors[1],
+} };
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+	.usecase = mdp_bus_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+	.name = "mdss_mdp",
+};
+
+static void bs_init(struct mdp5_encoder *mdp5_encoder)
+{
+	mdp5_encoder->bsc = msm_bus_scale_register_client(
+			&mdp_bus_scale_table);
+	DBG("bus scale client: %08x", mdp5_encoder->bsc);
+}
+
+static void bs_fini(struct mdp5_encoder *mdp5_encoder)
+{
+	if (mdp5_encoder->bsc) {
+		msm_bus_scale_unregister_client(mdp5_encoder->bsc);
+		mdp5_encoder->bsc = 0;
+	}
+}
+
+static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx)
+{
+	if (mdp5_encoder->bsc) {
+		DBG("set bus scaling: %d", idx);
+		/* HACK: scaling down, and then immediately back up
+		 * seems to leave things broken (underflow).. so
+		 * never disable:
+		 */
+		idx = 1;
+		msm_bus_scale_client_update_request(mdp5_encoder->bsc, idx);
+	}
+}
+#else
+static void bs_init(struct mdp5_encoder *mdp5_encoder) {}
+static void bs_fini(struct mdp5_encoder *mdp5_encoder) {}
+static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) {}
+#endif
+
+static void mdp5_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	bs_fini(mdp5_encoder);
+	drm_encoder_cleanup(encoder);
+	kfree(mdp5_encoder);
+}
+
+static const struct drm_encoder_funcs mdp5_encoder_funcs = {
+	.destroy = mdp5_encoder_destroy,
+};
+
+static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode,
+				      struct drm_display_mode *adjusted_mode)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	struct drm_device *dev = encoder->dev;
+	struct drm_connector *connector;
+	int intf = mdp5_encoder->intf->num;
+	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+	uint32_t display_v_start, display_v_end;
+	uint32_t hsync_start_x, hsync_end_x;
+	uint32_t format = 0x2100;
+	unsigned long flags;
+
+	mode = adjusted_mode;
+
+	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+			mode->base.id, mode->name,
+			mode->vrefresh, mode->clock,
+			mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal,
+			mode->vdisplay, mode->vsync_start,
+			mode->vsync_end, mode->vtotal,
+			mode->type, mode->flags);
+
+	ctrl_pol = 0;
+
+	/* DSI controller cannot handle active-low sync signals. */
+	if (mdp5_encoder->intf->type != INTF_DSI) {
+		if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+			ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW;
+		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW;
+	}
+	/* probably need to get DATA_EN polarity from panel.. */
+
+	dtv_hsync_skew = 0;  /* get this from panel? */
+
+	/* Get color format from panel, default is 8bpc */
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			switch (connector->display_info.bpc) {
+			case 4:
+				format |= 0;
+				break;
+			case 5:
+				format |= 0x15;
+				break;
+			case 6:
+				format |= 0x2A;
+				break;
+			case 8:
+			default:
+				format |= 0x3F;
+				break;
+			}
+			break;
+		}
+	}
+
+	hsync_start_x = (mode->htotal - mode->hsync_start);
+	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
+
+	vsync_period = mode->vtotal * mode->htotal;
+	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
+	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
+	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
+
+	/*
+	 * For edp only:
+	 * DISPLAY_V_START = (VBP * HCYCLE) + HBP
+	 * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
+	 */
+	if (mdp5_encoder->intf->type == INTF_eDP) {
+		display_v_start += mode->htotal - mode->hsync_start;
+		display_v_end -= mode->hsync_start - mode->hdisplay;
+	}
+
+	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf),
+			MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) |
+			MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal));
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_PERIOD_F0(intf), vsync_period);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_LEN_F0(intf), vsync_len);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_HCTL(intf),
+			MDP5_INTF_DISPLAY_HCTL_START(hsync_start_x) |
+			MDP5_INTF_DISPLAY_HCTL_END(hsync_end_x));
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VSTART_F0(intf), display_v_start);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VEND_F0(intf), display_v_end);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_BORDER_COLOR(intf), 0);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_UNDERFLOW_COLOR(intf), 0xff);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_SKEW(intf), dtv_hsync_skew);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_POLARITY_CTL(intf), ctrl_pol);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_HCTL(intf),
+			MDP5_INTF_ACTIVE_HCTL_START(0) |
+			MDP5_INTF_ACTIVE_HCTL_END(0));
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VSTART_F0(intf), 0);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
+
+	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+	mdp5_crtc_set_pipeline(encoder->crtc);
+}
+
+static void mdp5_vid_encoder_disable(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
+	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
+	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+	int intfn = mdp5_encoder->intf->num;
+	unsigned long flags;
+
+	if (WARN_ON(!mdp5_encoder->enabled))
+		return;
+
+	mdp5_ctl_set_encoder_state(ctl, pipeline, false);
+
+	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
+	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
+
+	/*
+	 * Wait for a vsync so we know the ENABLE=0 latched before
+	 * the (connector) source of the vsync's gets disabled,
+	 * otherwise we end up in a funny state if we re-enable
+	 * before the disable latches, which results that some of
+	 * the settings changes for the new modeset (like new
+	 * scanout buffer) don't latch properly..
+	 */
+	mdp_irq_wait(&mdp5_kms->base, intf2vblank(mixer, intf));
+
+	bs_set(mdp5_encoder, 0);
+
+	mdp5_encoder->enabled = false;
+}
+
+static void mdp5_vid_encoder_enable(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
+	int intfn = intf->num;
+	unsigned long flags;
+
+	if (WARN_ON(mdp5_encoder->enabled))
+		return;
+
+	bs_set(mdp5_encoder, 1);
+	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
+	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
+
+	mdp5_ctl_set_encoder_state(ctl, pipeline, true);
+
+	mdp5_encoder->enabled = true;
+}
+
+static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
+				  struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+
+	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+		mdp5_cmd_encoder_mode_set(encoder, mode, adjusted_mode);
+	else
+		mdp5_vid_encoder_mode_set(encoder, mode, adjusted_mode);
+}
+
+static void mdp5_encoder_disable(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+
+	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+		mdp5_cmd_encoder_disable(encoder);
+	else
+		mdp5_vid_encoder_disable(encoder);
+}
+
+static void mdp5_encoder_enable(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+	/* this isn't right I think */
+	struct drm_crtc_state *cstate = encoder->crtc->state;
+
+	mdp5_encoder_mode_set(encoder, &cstate->mode, &cstate->adjusted_mode);
+
+	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+		mdp5_cmd_encoder_enable(encoder);
+	else
+		mdp5_vid_encoder_enable(encoder);
+}
+
+static int mdp5_encoder_atomic_check(struct drm_encoder *encoder,
+				     struct drm_crtc_state *crtc_state,
+				     struct drm_connector_state *conn_state)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc_state);
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
+
+	mdp5_cstate->ctl = ctl;
+	mdp5_cstate->pipeline.intf = intf;
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
+	.disable = mdp5_encoder_disable,
+	.enable = mdp5_encoder_enable,
+	.atomic_check = mdp5_encoder_atomic_check,
+};
+
+int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	int intf = mdp5_encoder->intf->num;
+
+	return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
+}
+
+u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_kms *mdp5_kms = get_kms(encoder);
+	int intf = mdp5_encoder->intf->num;
+
+	return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
+}
+
+int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
+				       struct drm_encoder *slave_encoder)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
+	struct mdp5_kms *mdp5_kms;
+	struct device *dev;
+	int intf_num;
+	u32 data = 0;
+
+	if (!encoder || !slave_encoder)
+		return -EINVAL;
+
+	mdp5_kms = get_kms(encoder);
+	intf_num = mdp5_encoder->intf->num;
+
+	/* Switch slave encoder's TimingGen Sync mode,
+	 * to use the master's enable signal for the slave encoder.
+	 */
+	if (intf_num == 1)
+		data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC;
+	else if (intf_num == 2)
+		data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC;
+	else
+		return -EINVAL;
+
+	dev = &mdp5_kms->pdev->dev;
+	/* Make sure clocks are on when connectors calling this function. */
+	pm_runtime_get_sync(dev);
+
+	/* Dumb Panel, Sync mode */
+	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
+	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
+	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
+
+	mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode)
+{
+	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+	struct mdp5_interface *intf = mdp5_encoder->intf;
+
+	/* TODO: Expand this to set writeback modes too */
+	if (cmd_mode) {
+		WARN_ON(intf->type != INTF_DSI);
+		intf->mode = MDP5_INTF_DSI_MODE_COMMAND;
+	} else {
+		if (intf->type == INTF_DSI)
+			intf->mode = MDP5_INTF_DSI_MODE_VIDEO;
+		else
+			intf->mode = MDP5_INTF_MODE_NONE;
+	}
+}
+
+/* initialize encoder */
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+				      struct mdp5_interface *intf,
+				      struct mdp5_ctl *ctl)
+{
+	struct drm_encoder *encoder = NULL;
+	struct mdp5_encoder *mdp5_encoder;
+	int enc_type = (intf->type == INTF_DSI) ?
+		DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS;
+	int ret;
+
+	mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
+	if (!mdp5_encoder) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	encoder = &mdp5_encoder->base;
+	mdp5_encoder->ctl = ctl;
+	mdp5_encoder->intf = intf;
+
+	spin_lock_init(&mdp5_encoder->intf_lock);
+
+	drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type, NULL);
+
+	drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
+
+	bs_init(mdp5_encoder);
+
+	return encoder;
+
+fail:
+	if (encoder)
+		mdp5_encoder_destroy(encoder);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
new file mode 100644
index 000000000000..280e368bc9bb
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irq.h>
+
+#include <drm/drm_print.h>
+
+#include "msm_drv.h"
+#include "mdp5_kms.h"
+
+void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+		uint32_t old_irqmask)
+{
+	mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_CLEAR,
+		   irqmask ^ (irqmask & old_irqmask));
+	mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask);
+}
+
+static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp5_kms *mdp5_kms = container_of(irq, struct mdp5_kms, error_handler);
+	static DEFINE_RATELIMIT_STATE(rs, 5*HZ, 1);
+	extern bool dumpstate;
+
+	DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
+
+	if (dumpstate && __ratelimit(&rs)) {
+		struct drm_printer p = drm_info_printer(mdp5_kms->dev->dev);
+		drm_state_dump(mdp5_kms->dev, &p);
+		if (mdp5_kms->smp)
+			mdp5_smp_dump(mdp5_kms->smp, &p);
+	}
+}
+
+void mdp5_irq_preinstall(struct msm_kms *kms)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	pm_runtime_get_sync(dev);
+	mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
+	mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+	pm_runtime_put_sync(dev);
+}
+
+int mdp5_irq_postinstall(struct msm_kms *kms)
+{
+	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
+	struct device *dev = &mdp5_kms->pdev->dev;
+	struct mdp_irq *error_handler = &mdp5_kms->error_handler;
+
+	error_handler->irq = mdp5_irq_error_handler;
+	error_handler->irqmask = MDP5_IRQ_INTF0_UNDER_RUN |
+			MDP5_IRQ_INTF1_UNDER_RUN |
+			MDP5_IRQ_INTF2_UNDER_RUN |
+			MDP5_IRQ_INTF3_UNDER_RUN;
+
+	pm_runtime_get_sync(dev);
+	mdp_irq_register(mdp_kms, error_handler);
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+void mdp5_irq_uninstall(struct msm_kms *kms)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	pm_runtime_get_sync(dev);
+	mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+	pm_runtime_put_sync(dev);
+}
+
+irqreturn_t mdp5_irq(struct msm_kms *kms)
+{
+	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
+	struct drm_device *dev = mdp5_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	unsigned int id;
+	uint32_t status, enable;
+
+	enable = mdp5_read(mdp5_kms, REG_MDP5_INTR_EN);
+	status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS) & enable;
+	mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status);
+
+	VERB("status=%08x", status);
+
+	mdp_dispatch_irqs(mdp_kms, status);
+
+	for (id = 0; id < priv->num_crtcs; id++)
+		if (status & mdp5_crtc_vblank(priv->crtcs[id]))
+			drm_handle_vblank(dev, id);
+
+	return IRQ_HANDLED;
+}
+
+int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	pm_runtime_get_sync(dev);
+	mdp_update_vblank_mask(to_mdp_kms(kms),
+			mdp5_crtc_vblank(crtc), true);
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	pm_runtime_get_sync(dev);
+	mdp_update_vblank_mask(to_mdp_kms(kms),
+			mdp5_crtc_vblank(crtc), false);
+	pm_runtime_put_sync(dev);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
new file mode 100644
index 000000000000..6d8e3a9a6fc0
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -0,0 +1,1067 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/of_irq.h>
+
+#include "msm_drv.h"
+#include "msm_gem.h"
+#include "msm_mmu.h"
+#include "mdp5_kms.h"
+
+static const char *iommu_ports[] = {
+		"mdp_0",
+};
+
+static int mdp5_hw_init(struct msm_kms *kms)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+	unsigned long flags;
+
+	pm_runtime_get_sync(dev);
+
+	/* Magic unknown register writes:
+	 *
+	 *    W VBIF:0x004 00000001      (mdss_mdp.c:839)
+	 *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839)
+	 *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839)
+	 *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839)
+	 *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839)
+	 *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839)
+	 *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839)
+	 *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839)
+	 *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839)
+	 *
+	 * Downstream fbdev driver gets these register offsets/values
+	 * from DT.. not really sure what these registers are or if
+	 * different values for different boards/SoC's, etc.  I guess
+	 * they are the golden registers.
+	 *
+	 * Not setting these does not seem to cause any problem.  But
+	 * we may be getting lucky with the bootloader initializing
+	 * them for us.  OTOH, if we can always count on the bootloader
+	 * setting the golden registers, then perhaps we don't need to
+	 * care.
+	 */
+
+	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
+	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+
+	mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+struct mdp5_state *mdp5_get_state(struct drm_atomic_state *s)
+{
+	struct msm_drm_private *priv = s->dev->dev_private;
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
+	struct msm_kms_state *state = to_kms_state(s);
+	struct mdp5_state *new_state;
+	int ret;
+
+	if (state->state)
+		return state->state;
+
+	ret = drm_modeset_lock(&mdp5_kms->state_lock, s->acquire_ctx);
+	if (ret)
+		return ERR_PTR(ret);
+
+	new_state = kmalloc(sizeof(*mdp5_kms->state), GFP_KERNEL);
+	if (!new_state)
+		return ERR_PTR(-ENOMEM);
+
+	/* Copy state: */
+	new_state->hwpipe = mdp5_kms->state->hwpipe;
+	new_state->hwmixer = mdp5_kms->state->hwmixer;
+	if (mdp5_kms->smp)
+		new_state->smp = mdp5_kms->state->smp;
+
+	state->state = new_state;
+
+	return new_state;
+}
+
+static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	swap(to_kms_state(state)->state, mdp5_kms->state);
+}
+
+static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	pm_runtime_get_sync(dev);
+
+	if (mdp5_kms->smp)
+		mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
+}
+
+static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct device *dev = &mdp5_kms->pdev->dev;
+
+	if (mdp5_kms->smp)
+		mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
+
+	pm_runtime_put_sync(dev);
+}
+
+static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms,
+						struct drm_crtc *crtc)
+{
+	mdp5_crtc_wait_for_commit_done(crtc);
+}
+
+static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
+		struct drm_encoder *encoder)
+{
+	return rate;
+}
+
+static int mdp5_set_split_display(struct msm_kms *kms,
+		struct drm_encoder *encoder,
+		struct drm_encoder *slave_encoder,
+		bool is_cmd_mode)
+{
+	if (is_cmd_mode)
+		return mdp5_cmd_encoder_set_split_display(encoder,
+							slave_encoder);
+	else
+		return mdp5_vid_encoder_set_split_display(encoder,
+							  slave_encoder);
+}
+
+static void mdp5_set_encoder_mode(struct msm_kms *kms,
+				  struct drm_encoder *encoder,
+				  bool cmd_mode)
+{
+	mdp5_encoder_set_intf_mode(encoder, cmd_mode);
+}
+
+static void mdp5_kms_destroy(struct msm_kms *kms)
+{
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+	struct msm_gem_address_space *aspace = kms->aspace;
+	int i;
+
+	for (i = 0; i < mdp5_kms->num_hwmixers; i++)
+		mdp5_mixer_destroy(mdp5_kms->hwmixers[i]);
+
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++)
+		mdp5_pipe_destroy(mdp5_kms->hwpipes[i]);
+
+	if (aspace) {
+		aspace->mmu->funcs->detach(aspace->mmu,
+				iommu_ports, ARRAY_SIZE(iommu_ports));
+		msm_gem_address_space_put(aspace);
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int smp_show(struct seq_file *m, void *arg)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
+	struct drm_printer p = drm_seq_file_printer(m);
+
+	if (!mdp5_kms->smp) {
+		drm_printf(&p, "no SMP pool\n");
+		return 0;
+	}
+
+	mdp5_smp_dump(mdp5_kms->smp, &p);
+
+	return 0;
+}
+
+static struct drm_info_list mdp5_debugfs_list[] = {
+		{"smp", smp_show },
+};
+
+static int mdp5_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
+{
+	struct drm_device *dev = minor->dev;
+	int ret;
+
+	ret = drm_debugfs_create_files(mdp5_debugfs_list,
+			ARRAY_SIZE(mdp5_debugfs_list),
+			minor->debugfs_root, minor);
+
+	if (ret) {
+		dev_err(dev->dev, "could not install mdp5_debugfs_list\n");
+		return ret;
+	}
+
+	return 0;
+}
+#endif
+
+static const struct mdp_kms_funcs kms_funcs = {
+	.base = {
+		.hw_init         = mdp5_hw_init,
+		.irq_preinstall  = mdp5_irq_preinstall,
+		.irq_postinstall = mdp5_irq_postinstall,
+		.irq_uninstall   = mdp5_irq_uninstall,
+		.irq             = mdp5_irq,
+		.enable_vblank   = mdp5_enable_vblank,
+		.disable_vblank  = mdp5_disable_vblank,
+		.swap_state      = mdp5_swap_state,
+		.prepare_commit  = mdp5_prepare_commit,
+		.complete_commit = mdp5_complete_commit,
+		.wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done,
+		.get_format      = mdp_get_format,
+		.round_pixclk    = mdp5_round_pixclk,
+		.set_split_display = mdp5_set_split_display,
+		.set_encoder_mode = mdp5_set_encoder_mode,
+		.destroy         = mdp5_kms_destroy,
+#ifdef CONFIG_DEBUG_FS
+		.debugfs_init    = mdp5_kms_debugfs_init,
+#endif
+	},
+	.set_irqmask         = mdp5_set_irqmask,
+};
+
+int mdp5_disable(struct mdp5_kms *mdp5_kms)
+{
+	DBG("");
+
+	mdp5_kms->enable_count--;
+	WARN_ON(mdp5_kms->enable_count < 0);
+
+	clk_disable_unprepare(mdp5_kms->ahb_clk);
+	clk_disable_unprepare(mdp5_kms->axi_clk);
+	clk_disable_unprepare(mdp5_kms->core_clk);
+	if (mdp5_kms->lut_clk)
+		clk_disable_unprepare(mdp5_kms->lut_clk);
+
+	return 0;
+}
+
+int mdp5_enable(struct mdp5_kms *mdp5_kms)
+{
+	DBG("");
+
+	mdp5_kms->enable_count++;
+
+	clk_prepare_enable(mdp5_kms->ahb_clk);
+	clk_prepare_enable(mdp5_kms->axi_clk);
+	clk_prepare_enable(mdp5_kms->core_clk);
+	if (mdp5_kms->lut_clk)
+		clk_prepare_enable(mdp5_kms->lut_clk);
+
+	return 0;
+}
+
+static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
+					     struct mdp5_interface *intf,
+					     struct mdp5_ctl *ctl)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_encoder *encoder;
+
+	encoder = mdp5_encoder_init(dev, intf, ctl);
+	if (IS_ERR(encoder)) {
+		dev_err(dev->dev, "failed to construct encoder\n");
+		return encoder;
+	}
+
+	priv->encoders[priv->num_encoders++] = encoder;
+
+	return encoder;
+}
+
+static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
+{
+	const enum mdp5_intf_type *intfs = hw_cfg->intf.connect;
+	const int intf_cnt = ARRAY_SIZE(hw_cfg->intf.connect);
+	int id = 0, i;
+
+	for (i = 0; i < intf_cnt; i++) {
+		if (intfs[i] == INTF_DSI) {
+			if (intf_num == i)
+				return id;
+
+			id++;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int modeset_init_intf(struct mdp5_kms *mdp5_kms,
+			     struct mdp5_interface *intf)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;
+	struct mdp5_ctl *ctl;
+	struct drm_encoder *encoder;
+	int ret = 0;
+
+	switch (intf->type) {
+	case INTF_eDP:
+		if (!priv->edp)
+			break;
+
+		ctl = mdp5_ctlm_request(ctlm, intf->num);
+		if (!ctl) {
+			ret = -EINVAL;
+			break;
+		}
+
+		encoder = construct_encoder(mdp5_kms, intf, ctl);
+		if (IS_ERR(encoder)) {
+			ret = PTR_ERR(encoder);
+			break;
+		}
+
+		ret = msm_edp_modeset_init(priv->edp, dev, encoder);
+		break;
+	case INTF_HDMI:
+		if (!priv->hdmi)
+			break;
+
+		ctl = mdp5_ctlm_request(ctlm, intf->num);
+		if (!ctl) {
+			ret = -EINVAL;
+			break;
+		}
+
+		encoder = construct_encoder(mdp5_kms, intf, ctl);
+		if (IS_ERR(encoder)) {
+			ret = PTR_ERR(encoder);
+			break;
+		}
+
+		ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);
+		break;
+	case INTF_DSI:
+	{
+		const struct mdp5_cfg_hw *hw_cfg =
+					mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+		int dsi_id = get_dsi_id_from_intf(hw_cfg, intf->num);
+
+		if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
+			dev_err(dev->dev, "failed to find dsi from intf %d\n",
+				intf->num);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!priv->dsi[dsi_id])
+			break;
+
+		ctl = mdp5_ctlm_request(ctlm, intf->num);
+		if (!ctl) {
+			ret = -EINVAL;
+			break;
+		}
+
+		encoder = construct_encoder(mdp5_kms, intf, ctl);
+		if (IS_ERR(encoder)) {
+			ret = PTR_ERR(encoder);
+			break;
+		}
+
+		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
+		break;
+	}
+	default:
+		dev_err(dev->dev, "unknown intf: %d\n", intf->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int modeset_init(struct mdp5_kms *mdp5_kms)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	const struct mdp5_cfg_hw *hw_cfg;
+	unsigned int num_crtcs;
+	int i, ret, pi = 0, ci = 0;
+	struct drm_plane *primary[MAX_BASES] = { NULL };
+	struct drm_plane *cursor[MAX_BASES] = { NULL };
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	/*
+	 * Construct encoders and modeset initialize connector devices
+	 * for each external display interface.
+	 */
+	for (i = 0; i < mdp5_kms->num_intfs; i++) {
+		ret = modeset_init_intf(mdp5_kms, mdp5_kms->intfs[i]);
+		if (ret)
+			goto fail;
+	}
+
+	/*
+	 * We should ideally have less number of encoders (set up by parsing
+	 * the MDP5 interfaces) than the number of layer mixers present in HW,
+	 * but let's be safe here anyway
+	 */
+	num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers);
+
+	/*
+	 * Construct planes equaling the number of hw pipes, and CRTCs for the
+	 * N encoders set up by the driver. The first N planes become primary
+	 * planes for the CRTCs, with the remainder as overlay planes:
+	 */
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
+		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
+		struct drm_plane *plane;
+		enum drm_plane_type type;
+
+		if (i < num_crtcs)
+			type = DRM_PLANE_TYPE_PRIMARY;
+		else if (hwpipe->caps & MDP_PIPE_CAP_CURSOR)
+			type = DRM_PLANE_TYPE_CURSOR;
+		else
+			type = DRM_PLANE_TYPE_OVERLAY;
+
+		plane = mdp5_plane_init(dev, type);
+		if (IS_ERR(plane)) {
+			ret = PTR_ERR(plane);
+			dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
+			goto fail;
+		}
+		priv->planes[priv->num_planes++] = plane;
+
+		if (type == DRM_PLANE_TYPE_PRIMARY)
+			primary[pi++] = plane;
+		if (type == DRM_PLANE_TYPE_CURSOR)
+			cursor[ci++] = plane;
+	}
+
+	for (i = 0; i < num_crtcs; i++) {
+		struct drm_crtc *crtc;
+
+		crtc  = mdp5_crtc_init(dev, primary[i], cursor[i], i);
+		if (IS_ERR(crtc)) {
+			ret = PTR_ERR(crtc);
+			dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
+			goto fail;
+		}
+		priv->crtcs[priv->num_crtcs++] = crtc;
+	}
+
+	/*
+	 * Now that we know the number of crtcs we've created, set the possible
+	 * crtcs for the encoders
+	 */
+	for (i = 0; i < priv->num_encoders; i++) {
+		struct drm_encoder *encoder = priv->encoders[i];
+
+		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,
+				 u32 *major, u32 *minor)
+{
+	struct device *dev = &mdp5_kms->pdev->dev;
+	u32 version;
+
+	pm_runtime_get_sync(dev);
+	version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION);
+	pm_runtime_put_sync(dev);
+
+	*major = FIELD(version, MDP5_HW_VERSION_MAJOR);
+	*minor = FIELD(version, MDP5_HW_VERSION_MINOR);
+
+	dev_info(dev, "MDP5 version v%d.%d", *major, *minor);
+}
+
+static int get_clk(struct platform_device *pdev, struct clk **clkp,
+		const char *name, bool mandatory)
+{
+	struct device *dev = &pdev->dev;
+	struct clk *clk = msm_clk_get(pdev, name);
+	if (IS_ERR(clk) && mandatory) {
+		dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
+	if (IS_ERR(clk))
+		DBG("skipping %s", name);
+	else
+		*clkp = clk;
+
+	return 0;
+}
+
+static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
+
+	drm_for_each_encoder(encoder, dev)
+		if (encoder->crtc == crtc)
+			return encoder;
+
+	return NULL;
+}
+
+static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
+				bool in_vblank_irq, int *vpos, int *hpos,
+				ktime_t *stime, ktime_t *etime,
+				const struct drm_display_mode *mode)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_crtc *crtc;
+	struct drm_encoder *encoder;
+	int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
+
+	crtc = priv->crtcs[pipe];
+	if (!crtc) {
+		DRM_ERROR("Invalid crtc %d\n", pipe);
+		return false;
+	}
+
+	encoder = get_encoder_from_crtc(crtc);
+	if (!encoder) {
+		DRM_ERROR("no encoder found for crtc %d\n", pipe);
+		return false;
+	}
+
+	vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
+
+	/*
+	 * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
+	 * the end of VFP. Translate the porch values relative to the line
+	 * counter positions.
+	 */
+
+	vactive_start = vsw + vbp + 1;
+
+	vactive_end = vactive_start + mode->crtc_vdisplay;
+
+	/* last scan line before VSYNC */
+	vfp_end = mode->crtc_vtotal;
+
+	if (stime)
+		*stime = ktime_get();
+
+	line = mdp5_encoder_get_linecount(encoder);
+
+	if (line < vactive_start) {
+		line -= vactive_start;
+	} else if (line > vactive_end) {
+		line = line - vfp_end - vactive_start;
+	} else {
+		line -= vactive_start;
+	}
+
+	*vpos = line;
+	*hpos = 0;
+
+	if (etime)
+		*etime = ktime_get();
+
+	return true;
+}
+
+static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_crtc *crtc;
+	struct drm_encoder *encoder;
+
+	if (pipe >= priv->num_crtcs)
+		return 0;
+
+	crtc = priv->crtcs[pipe];
+	if (!crtc)
+		return 0;
+
+	encoder = get_encoder_from_crtc(crtc);
+	if (!encoder)
+		return 0;
+
+	return mdp5_encoder_get_framecount(encoder);
+}
+
+struct msm_kms *mdp5_kms_init(struct drm_device *dev)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct platform_device *pdev;
+	struct mdp5_kms *mdp5_kms;
+	struct mdp5_cfg *config;
+	struct msm_kms *kms;
+	struct msm_gem_address_space *aspace;
+	int irq, i, ret;
+
+	/* priv->kms would have been populated by the MDP5 driver */
+	kms = priv->kms;
+	if (!kms)
+		return NULL;
+
+	mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+
+	mdp_kms_init(&mdp5_kms->base, &kms_funcs);
+
+	pdev = mdp5_kms->pdev;
+
+	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (irq < 0) {
+		ret = irq;
+		dev_err(&pdev->dev, "failed to get irq: %d\n", ret);
+		goto fail;
+	}
+
+	kms->irq = irq;
+
+	config = mdp5_cfg_get_config(mdp5_kms->cfg);
+
+	/* make sure things are off before attaching iommu (bootloader could
+	 * have left things on, in which case we'll start getting faults if
+	 * we don't disable):
+	 */
+	pm_runtime_get_sync(&pdev->dev);
+	for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
+		if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
+		    !config->hw->intf.base[i])
+			continue;
+		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
+
+		mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
+	}
+	mdelay(16);
+
+	if (config->platform.iommu) {
+		aspace = msm_gem_address_space_create(&pdev->dev,
+				config->platform.iommu, "mdp5");
+		if (IS_ERR(aspace)) {
+			ret = PTR_ERR(aspace);
+			goto fail;
+		}
+
+		kms->aspace = aspace;
+
+		ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
+				ARRAY_SIZE(iommu_ports));
+		if (ret) {
+			dev_err(&pdev->dev, "failed to attach iommu: %d\n",
+				ret);
+			goto fail;
+		}
+	} else {
+		dev_info(&pdev->dev,
+			 "no iommu, fallback to phys contig buffers for scanout\n");
+		aspace = NULL;
+	}
+
+	pm_runtime_put_sync(&pdev->dev);
+
+	ret = modeset_init(mdp5_kms);
+	if (ret) {
+		dev_err(&pdev->dev, "modeset_init failed: %d\n", ret);
+		goto fail;
+	}
+
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+	dev->mode_config.max_width = 0xffff;
+	dev->mode_config.max_height = 0xffff;
+
+	dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
+	dev->driver->get_scanout_position = mdp5_get_scanoutpos;
+	dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
+	dev->max_vblank_count = 0xffffffff;
+	dev->vblank_disable_immediate = true;
+
+	return kms;
+fail:
+	if (kms)
+		mdp5_kms_destroy(kms);
+	return ERR_PTR(ret);
+}
+
+static void mdp5_destroy(struct platform_device *pdev)
+{
+	struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
+	int i;
+
+	if (mdp5_kms->ctlm)
+		mdp5_ctlm_destroy(mdp5_kms->ctlm);
+	if (mdp5_kms->smp)
+		mdp5_smp_destroy(mdp5_kms->smp);
+	if (mdp5_kms->cfg)
+		mdp5_cfg_destroy(mdp5_kms->cfg);
+
+	for (i = 0; i < mdp5_kms->num_intfs; i++)
+		kfree(mdp5_kms->intfs[i]);
+
+	if (mdp5_kms->rpm_enabled)
+		pm_runtime_disable(&pdev->dev);
+
+	kfree(mdp5_kms->state);
+}
+
+static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt,
+		const enum mdp5_pipe *pipes, const uint32_t *offsets,
+		uint32_t caps)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	int i, ret;
+
+	for (i = 0; i < cnt; i++) {
+		struct mdp5_hw_pipe *hwpipe;
+
+		hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps);
+		if (IS_ERR(hwpipe)) {
+			ret = PTR_ERR(hwpipe);
+			dev_err(dev->dev, "failed to construct pipe for %s (%d)\n",
+					pipe2name(pipes[i]), ret);
+			return ret;
+		}
+		hwpipe->idx = mdp5_kms->num_hwpipes;
+		mdp5_kms->hwpipes[mdp5_kms->num_hwpipes++] = hwpipe;
+	}
+
+	return 0;
+}
+
+static int hwpipe_init(struct mdp5_kms *mdp5_kms)
+{
+	static const enum mdp5_pipe rgb_planes[] = {
+			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
+	};
+	static const enum mdp5_pipe vig_planes[] = {
+			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
+	};
+	static const enum mdp5_pipe dma_planes[] = {
+			SSPP_DMA0, SSPP_DMA1,
+	};
+	static const enum mdp5_pipe cursor_planes[] = {
+			SSPP_CURSOR0, SSPP_CURSOR1,
+	};
+	const struct mdp5_cfg_hw *hw_cfg;
+	int ret;
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	/* Construct RGB pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_rgb.count, rgb_planes,
+			hw_cfg->pipe_rgb.base, hw_cfg->pipe_rgb.caps);
+	if (ret)
+		return ret;
+
+	/* Construct video (VIG) pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_vig.count, vig_planes,
+			hw_cfg->pipe_vig.base, hw_cfg->pipe_vig.caps);
+	if (ret)
+		return ret;
+
+	/* Construct DMA pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_dma.count, dma_planes,
+			hw_cfg->pipe_dma.base, hw_cfg->pipe_dma.caps);
+	if (ret)
+		return ret;
+
+	/* Construct cursor pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_cursor.count,
+			cursor_planes, hw_cfg->pipe_cursor.base,
+			hw_cfg->pipe_cursor.caps);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int hwmixer_init(struct mdp5_kms *mdp5_kms)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	const struct mdp5_cfg_hw *hw_cfg;
+	int i, ret;
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	for (i = 0; i < hw_cfg->lm.count; i++) {
+		struct mdp5_hw_mixer *mixer;
+
+		mixer = mdp5_mixer_init(&hw_cfg->lm.instances[i]);
+		if (IS_ERR(mixer)) {
+			ret = PTR_ERR(mixer);
+			dev_err(dev->dev, "failed to construct LM%d (%d)\n",
+				i, ret);
+			return ret;
+		}
+
+		mixer->idx = mdp5_kms->num_hwmixers;
+		mdp5_kms->hwmixers[mdp5_kms->num_hwmixers++] = mixer;
+	}
+
+	return 0;
+}
+
+static int interface_init(struct mdp5_kms *mdp5_kms)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	const struct mdp5_cfg_hw *hw_cfg;
+	const enum mdp5_intf_type *intf_types;
+	int i;
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+	intf_types = hw_cfg->intf.connect;
+
+	for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
+		struct mdp5_interface *intf;
+
+		if (intf_types[i] == INTF_DISABLED)
+			continue;
+
+		intf = kzalloc(sizeof(*intf), GFP_KERNEL);
+		if (!intf) {
+			dev_err(dev->dev, "failed to construct INTF%d\n", i);
+			return -ENOMEM;
+		}
+
+		intf->num = i;
+		intf->type = intf_types[i];
+		intf->mode = MDP5_INTF_MODE_NONE;
+		intf->idx = mdp5_kms->num_intfs;
+		mdp5_kms->intfs[mdp5_kms->num_intfs++] = intf;
+	}
+
+	return 0;
+}
+
+static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct mdp5_kms *mdp5_kms;
+	struct mdp5_cfg *config;
+	u32 major, minor;
+	int ret;
+
+	mdp5_kms = devm_kzalloc(&pdev->dev, sizeof(*mdp5_kms), GFP_KERNEL);
+	if (!mdp5_kms) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, mdp5_kms);
+
+	spin_lock_init(&mdp5_kms->resource_lock);
+
+	mdp5_kms->dev = dev;
+	mdp5_kms->pdev = pdev;
+
+	drm_modeset_lock_init(&mdp5_kms->state_lock);
+	mdp5_kms->state = kzalloc(sizeof(*mdp5_kms->state), GFP_KERNEL);
+	if (!mdp5_kms->state) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
+	if (IS_ERR(mdp5_kms->mmio)) {
+		ret = PTR_ERR(mdp5_kms->mmio);
+		goto fail;
+	}
+
+	/* mandatory clocks: */
+	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &mdp5_kms->core_clk, "core", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync", true);
+	if (ret)
+		goto fail;
+
+	/* optional clocks: */
+	get_clk(pdev, &mdp5_kms->lut_clk, "lut", false);
+
+	/* we need to set a default rate before enabling.  Set a safe
+	 * rate first, then figure out hw revision, and then set a
+	 * more optimal rate:
+	 */
+	clk_set_rate(mdp5_kms->core_clk, 200000000);
+
+	pm_runtime_enable(&pdev->dev);
+	mdp5_kms->rpm_enabled = true;
+
+	read_mdp_hw_revision(mdp5_kms, &major, &minor);
+
+	mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor);
+	if (IS_ERR(mdp5_kms->cfg)) {
+		ret = PTR_ERR(mdp5_kms->cfg);
+		mdp5_kms->cfg = NULL;
+		goto fail;
+	}
+
+	config = mdp5_cfg_get_config(mdp5_kms->cfg);
+	mdp5_kms->caps = config->hw->mdp.caps;
+
+	/* TODO: compute core clock rate at runtime */
+	clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk);
+
+	/*
+	 * Some chipsets have a Shared Memory Pool (SMP), while others
+	 * have dedicated latency buffering per source pipe instead;
+	 * this section initializes the SMP:
+	 */
+	if (mdp5_kms->caps & MDP_CAP_SMP) {
+		mdp5_kms->smp = mdp5_smp_init(mdp5_kms, &config->hw->smp);
+		if (IS_ERR(mdp5_kms->smp)) {
+			ret = PTR_ERR(mdp5_kms->smp);
+			mdp5_kms->smp = NULL;
+			goto fail;
+		}
+	}
+
+	mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg);
+	if (IS_ERR(mdp5_kms->ctlm)) {
+		ret = PTR_ERR(mdp5_kms->ctlm);
+		mdp5_kms->ctlm = NULL;
+		goto fail;
+	}
+
+	ret = hwpipe_init(mdp5_kms);
+	if (ret)
+		goto fail;
+
+	ret = hwmixer_init(mdp5_kms);
+	if (ret)
+		goto fail;
+
+	ret = interface_init(mdp5_kms);
+	if (ret)
+		goto fail;
+
+	/* set uninit-ed kms */
+	priv->kms = &mdp5_kms->base.base;
+
+	return 0;
+fail:
+	mdp5_destroy(pdev);
+	return ret;
+}
+
+static int mdp5_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *ddev = dev_get_drvdata(master);
+	struct platform_device *pdev = to_platform_device(dev);
+
+	DBG("");
+
+	return mdp5_init(pdev, ddev);
+}
+
+static void mdp5_unbind(struct device *dev, struct device *master,
+			void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	mdp5_destroy(pdev);
+}
+
+static const struct component_ops mdp5_ops = {
+	.bind   = mdp5_bind,
+	.unbind = mdp5_unbind,
+};
+
+static int mdp5_dev_probe(struct platform_device *pdev)
+{
+	DBG("");
+	return component_add(&pdev->dev, &mdp5_ops);
+}
+
+static int mdp5_dev_remove(struct platform_device *pdev)
+{
+	DBG("");
+	component_del(&pdev->dev, &mdp5_ops);
+	return 0;
+}
+
+static __maybe_unused int mdp5_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
+
+	DBG("");
+
+	return mdp5_disable(mdp5_kms);
+}
+
+static __maybe_unused int mdp5_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
+
+	DBG("");
+
+	return mdp5_enable(mdp5_kms);
+}
+
+static const struct dev_pm_ops mdp5_pm_ops = {
+	SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL)
+};
+
+static const struct of_device_id mdp5_dt_match[] = {
+	{ .compatible = "qcom,mdp5", },
+	/* to support downstream DT files */
+	{ .compatible = "qcom,mdss_mdp", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mdp5_dt_match);
+
+static struct platform_driver mdp5_driver = {
+	.probe = mdp5_dev_probe,
+	.remove = mdp5_dev_remove,
+	.driver = {
+		.name = "msm_mdp",
+		.of_match_table = mdp5_dt_match,
+		.pm = &mdp5_pm_ops,
+	},
+};
+
+void __init msm_mdp_register(void)
+{
+	DBG("");
+	platform_driver_register(&mdp5_driver);
+}
+
+void __exit msm_mdp_unregister(void)
+{
+	DBG("");
+	platform_driver_unregister(&mdp5_driver);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
new file mode 100644
index 000000000000..aeb94aa461b5
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP5_KMS_H__
+#define __MDP5_KMS_H__
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "disp/mdp_kms.h"
+#include "mdp5_cfg.h"	/* must be included before mdp5.xml.h */
+#include "mdp5.xml.h"
+#include "mdp5_pipe.h"
+#include "mdp5_mixer.h"
+#include "mdp5_ctl.h"
+#include "mdp5_smp.h"
+
+struct mdp5_state;
+
+struct mdp5_kms {
+	struct mdp_kms base;
+
+	struct drm_device *dev;
+
+	struct platform_device *pdev;
+
+	unsigned num_hwpipes;
+	struct mdp5_hw_pipe *hwpipes[SSPP_MAX];
+
+	unsigned num_hwmixers;
+	struct mdp5_hw_mixer *hwmixers[8];
+
+	unsigned num_intfs;
+	struct mdp5_interface *intfs[5];
+
+	struct mdp5_cfg_handler *cfg;
+	uint32_t caps;	/* MDP capabilities (MDP_CAP_XXX bits) */
+
+	/**
+	 * Global atomic state.  Do not access directly, use mdp5_get_state()
+	 */
+	struct mdp5_state *state;
+	struct drm_modeset_lock state_lock;
+
+	struct mdp5_smp *smp;
+	struct mdp5_ctl_manager *ctlm;
+
+	/* io/register spaces: */
+	void __iomem *mmio;
+
+	struct clk *axi_clk;
+	struct clk *ahb_clk;
+	struct clk *core_clk;
+	struct clk *lut_clk;
+	struct clk *vsync_clk;
+
+	/*
+	 * lock to protect access to global resources: ie., following register:
+	 *	- REG_MDP5_DISP_INTF_SEL
+	 */
+	spinlock_t resource_lock;
+
+	bool rpm_enabled;
+
+	struct mdp_irq error_handler;
+
+	int enable_count;
+};
+#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)
+
+/* Global atomic state for tracking resources that are shared across
+ * multiple kms objects (planes/crtcs/etc).
+ *
+ * For atomic updates which require modifying global state,
+ */
+struct mdp5_state {
+	struct mdp5_hw_pipe_state hwpipe;
+	struct mdp5_hw_mixer_state hwmixer;
+	struct mdp5_smp_state smp;
+};
+
+struct mdp5_state *__must_check
+mdp5_get_state(struct drm_atomic_state *s);
+
+/* Atomic plane state.  Subclasses the base drm_plane_state in order to
+ * track assigned hwpipe and hw specific state.
+ */
+struct mdp5_plane_state {
+	struct drm_plane_state base;
+
+	struct mdp5_hw_pipe *hwpipe;
+	struct mdp5_hw_pipe *r_hwpipe;	/* right hwpipe */
+
+	/* aligned with property */
+	uint8_t premultiplied;
+	uint8_t zpos;
+	uint8_t alpha;
+
+	/* assigned by crtc blender */
+	enum mdp_mixer_stage_id stage;
+};
+#define to_mdp5_plane_state(x) \
+		container_of(x, struct mdp5_plane_state, base)
+
+struct mdp5_pipeline {
+	struct mdp5_interface *intf;
+	struct mdp5_hw_mixer *mixer;
+	struct mdp5_hw_mixer *r_mixer;	/* right mixer */
+};
+
+struct mdp5_crtc_state {
+	struct drm_crtc_state base;
+
+	struct mdp5_ctl *ctl;
+	struct mdp5_pipeline pipeline;
+
+	/* these are derivatives of intf/mixer state in mdp5_pipeline */
+	u32 vblank_irqmask;
+	u32 err_irqmask;
+	u32 pp_done_irqmask;
+
+	bool cmd_mode;
+};
+#define to_mdp5_crtc_state(x) \
+		container_of(x, struct mdp5_crtc_state, base)
+
+enum mdp5_intf_mode {
+	MDP5_INTF_MODE_NONE = 0,
+
+	/* Modes used for DSI interface (INTF_DSI type): */
+	MDP5_INTF_DSI_MODE_VIDEO,
+	MDP5_INTF_DSI_MODE_COMMAND,
+
+	/* Modes used for WB interface (INTF_WB type):  */
+	MDP5_INTF_WB_MODE_BLOCK,
+	MDP5_INTF_WB_MODE_LINE,
+};
+
+struct mdp5_interface {
+	int idx;
+	int num; /* display interface number */
+	enum mdp5_intf_type type;
+	enum mdp5_intf_mode mode;
+};
+
+struct mdp5_encoder {
+	struct drm_encoder base;
+	spinlock_t intf_lock;	/* protect REG_MDP5_INTF_* registers */
+	bool enabled;
+	uint32_t bsc;
+
+	struct mdp5_interface *intf;
+	struct mdp5_ctl *ctl;
+};
+#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
+
+static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
+{
+	WARN_ON(mdp5_kms->enable_count <= 0);
+	msm_writel(data, mdp5_kms->mmio + reg);
+}
+
+static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg)
+{
+	WARN_ON(mdp5_kms->enable_count <= 0);
+	return msm_readl(mdp5_kms->mmio + reg);
+}
+
+static inline const char *stage2name(enum mdp_mixer_stage_id stage)
+{
+	static const char *names[] = {
+#define NAME(n) [n] = #n
+		NAME(STAGE_UNUSED), NAME(STAGE_BASE),
+		NAME(STAGE0), NAME(STAGE1), NAME(STAGE2),
+		NAME(STAGE3), NAME(STAGE4), NAME(STAGE6),
+#undef NAME
+	};
+	return names[stage];
+}
+
+static inline const char *pipe2name(enum mdp5_pipe pipe)
+{
+	static const char *names[] = {
+#define NAME(n) [SSPP_ ## n] = #n
+		NAME(VIG0), NAME(VIG1), NAME(VIG2),
+		NAME(RGB0), NAME(RGB1), NAME(RGB2),
+		NAME(DMA0), NAME(DMA1),
+		NAME(VIG3), NAME(RGB3),
+		NAME(CURSOR0), NAME(CURSOR1),
+#undef NAME
+	};
+	return names[pipe];
+}
+
+static inline int pipe2nclients(enum mdp5_pipe pipe)
+{
+	switch (pipe) {
+	case SSPP_RGB0:
+	case SSPP_RGB1:
+	case SSPP_RGB2:
+	case SSPP_RGB3:
+		return 1;
+	default:
+		return 3;
+	}
+}
+
+static inline uint32_t intf2err(int intf_num)
+{
+	switch (intf_num) {
+	case 0:  return MDP5_IRQ_INTF0_UNDER_RUN;
+	case 1:  return MDP5_IRQ_INTF1_UNDER_RUN;
+	case 2:  return MDP5_IRQ_INTF2_UNDER_RUN;
+	case 3:  return MDP5_IRQ_INTF3_UNDER_RUN;
+	default: return 0;
+	}
+}
+
+static inline uint32_t intf2vblank(struct mdp5_hw_mixer *mixer,
+				   struct mdp5_interface *intf)
+{
+	/*
+	 * In case of DSI Command Mode, the Ping Pong's read pointer IRQ
+	 * acts as a Vblank signal. The Ping Pong buffer used is bound to
+	 * layer mixer.
+	 */
+
+	if ((intf->type == INTF_DSI) &&
+			(intf->mode == MDP5_INTF_DSI_MODE_COMMAND))
+		return MDP5_IRQ_PING_PONG_0_RD_PTR << mixer->pp;
+
+	if (intf->type == INTF_WB)
+		return MDP5_IRQ_WB_2_DONE;
+
+	switch (intf->num) {
+	case 0:  return MDP5_IRQ_INTF0_VSYNC;
+	case 1:  return MDP5_IRQ_INTF1_VSYNC;
+	case 2:  return MDP5_IRQ_INTF2_VSYNC;
+	case 3:  return MDP5_IRQ_INTF3_VSYNC;
+	default: return 0;
+	}
+}
+
+static inline uint32_t lm2ppdone(struct mdp5_hw_mixer *mixer)
+{
+	return MDP5_IRQ_PING_PONG_0_DONE << mixer->pp;
+}
+
+void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+		uint32_t old_irqmask);
+void mdp5_irq_preinstall(struct msm_kms *kms);
+int mdp5_irq_postinstall(struct msm_kms *kms);
+void mdp5_irq_uninstall(struct msm_kms *kms);
+irqreturn_t mdp5_irq(struct msm_kms *kms);
+int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
+void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
+
+uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
+enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
+enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane);
+struct drm_plane *mdp5_plane_init(struct drm_device *dev,
+				  enum drm_plane_type type);
+
+struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc);
+uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
+
+struct mdp5_hw_mixer *mdp5_crtc_get_mixer(struct drm_crtc *crtc);
+struct mdp5_pipeline *mdp5_crtc_get_pipeline(struct drm_crtc *crtc);
+void mdp5_crtc_set_pipeline(struct drm_crtc *crtc);
+void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc);
+struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
+				struct drm_plane *plane,
+				struct drm_plane *cursor_plane, int id);
+
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+		struct mdp5_interface *intf, struct mdp5_ctl *ctl);
+int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
+				       struct drm_encoder *slave_encoder);
+void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode);
+int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
+u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
+
+#ifdef CONFIG_DRM_MSM_DSI
+void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+			       struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode);
+void mdp5_cmd_encoder_disable(struct drm_encoder *encoder);
+void mdp5_cmd_encoder_enable(struct drm_encoder *encoder);
+int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
+				       struct drm_encoder *slave_encoder);
+#else
+static inline void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+					     struct drm_display_mode *mode,
+					     struct drm_display_mode *adjusted_mode)
+{
+}
+static inline void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
+{
+}
+static inline void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
+{
+}
+static inline int mdp5_cmd_encoder_set_split_display(
+	struct drm_encoder *encoder, struct drm_encoder *slave_encoder)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif /* __MDP5_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
new file mode 100644
index 000000000000..f2a0db7a8a03
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+
+#include "msm_drv.h"
+#include "mdp5_kms.h"
+
+/*
+ * If needed, this can become more specific: something like struct mdp5_mdss,
+ * which contains a 'struct msm_mdss base' member.
+ */
+struct msm_mdss {
+	struct drm_device *dev;
+
+	void __iomem *mmio, *vbif;
+
+	struct regulator *vdd;
+
+	struct clk *ahb_clk;
+	struct clk *axi_clk;
+	struct clk *vsync_clk;
+
+	struct {
+		volatile unsigned long enabled_mask;
+		struct irq_domain *domain;
+	} irqcontroller;
+};
+
+static inline void mdss_write(struct msm_mdss *mdss, u32 reg, u32 data)
+{
+	msm_writel(data, mdss->mmio + reg);
+}
+
+static inline u32 mdss_read(struct msm_mdss *mdss, u32 reg)
+{
+	return msm_readl(mdss->mmio + reg);
+}
+
+static irqreturn_t mdss_irq(int irq, void *arg)
+{
+	struct msm_mdss *mdss = arg;
+	u32 intr;
+
+	intr = mdss_read(mdss, REG_MDSS_HW_INTR_STATUS);
+
+	VERB("intr=%08x", intr);
+
+	while (intr) {
+		irq_hw_number_t hwirq = fls(intr) - 1;
+
+		generic_handle_irq(irq_find_mapping(
+				mdss->irqcontroller.domain, hwirq));
+		intr &= ~(1 << hwirq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * interrupt-controller implementation, so sub-blocks (MDP/HDMI/eDP/DSI/etc)
+ * can register to get their irq's delivered
+ */
+
+#define VALID_IRQS  (MDSS_HW_INTR_STATUS_INTR_MDP | \
+		MDSS_HW_INTR_STATUS_INTR_DSI0 | \
+		MDSS_HW_INTR_STATUS_INTR_DSI1 | \
+		MDSS_HW_INTR_STATUS_INTR_HDMI | \
+		MDSS_HW_INTR_STATUS_INTR_EDP)
+
+static void mdss_hw_mask_irq(struct irq_data *irqd)
+{
+	struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd);
+
+	smp_mb__before_atomic();
+	clear_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask);
+	smp_mb__after_atomic();
+}
+
+static void mdss_hw_unmask_irq(struct irq_data *irqd)
+{
+	struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd);
+
+	smp_mb__before_atomic();
+	set_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask);
+	smp_mb__after_atomic();
+}
+
+static struct irq_chip mdss_hw_irq_chip = {
+	.name		= "mdss",
+	.irq_mask	= mdss_hw_mask_irq,
+	.irq_unmask	= mdss_hw_unmask_irq,
+};
+
+static int mdss_hw_irqdomain_map(struct irq_domain *d, unsigned int irq,
+				 irq_hw_number_t hwirq)
+{
+	struct msm_mdss *mdss = d->host_data;
+
+	if (!(VALID_IRQS & (1 << hwirq)))
+		return -EPERM;
+
+	irq_set_chip_and_handler(irq, &mdss_hw_irq_chip, handle_level_irq);
+	irq_set_chip_data(irq, mdss);
+
+	return 0;
+}
+
+static const struct irq_domain_ops mdss_hw_irqdomain_ops = {
+	.map = mdss_hw_irqdomain_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+
+static int mdss_irq_domain_init(struct msm_mdss *mdss)
+{
+	struct device *dev = mdss->dev->dev;
+	struct irq_domain *d;
+
+	d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops,
+				  mdss);
+	if (!d) {
+		dev_err(dev, "mdss irq domain add failed\n");
+		return -ENXIO;
+	}
+
+	mdss->irqcontroller.enabled_mask = 0;
+	mdss->irqcontroller.domain = d;
+
+	return 0;
+}
+
+int msm_mdss_enable(struct msm_mdss *mdss)
+{
+	DBG("");
+
+	clk_prepare_enable(mdss->ahb_clk);
+	if (mdss->axi_clk)
+		clk_prepare_enable(mdss->axi_clk);
+	if (mdss->vsync_clk)
+		clk_prepare_enable(mdss->vsync_clk);
+
+	return 0;
+}
+
+int msm_mdss_disable(struct msm_mdss *mdss)
+{
+	DBG("");
+
+	if (mdss->vsync_clk)
+		clk_disable_unprepare(mdss->vsync_clk);
+	if (mdss->axi_clk)
+		clk_disable_unprepare(mdss->axi_clk);
+	clk_disable_unprepare(mdss->ahb_clk);
+
+	return 0;
+}
+
+static int msm_mdss_get_clocks(struct msm_mdss *mdss)
+{
+	struct platform_device *pdev = to_platform_device(mdss->dev->dev);
+
+	mdss->ahb_clk = msm_clk_get(pdev, "iface");
+	if (IS_ERR(mdss->ahb_clk))
+		mdss->ahb_clk = NULL;
+
+	mdss->axi_clk = msm_clk_get(pdev, "bus");
+	if (IS_ERR(mdss->axi_clk))
+		mdss->axi_clk = NULL;
+
+	mdss->vsync_clk = msm_clk_get(pdev, "vsync");
+	if (IS_ERR(mdss->vsync_clk))
+		mdss->vsync_clk = NULL;
+
+	return 0;
+}
+
+void msm_mdss_destroy(struct drm_device *dev)
+{
+	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_mdss *mdss = priv->mdss;
+
+	if (!mdss)
+		return;
+
+	irq_domain_remove(mdss->irqcontroller.domain);
+	mdss->irqcontroller.domain = NULL;
+
+	regulator_disable(mdss->vdd);
+
+	pm_runtime_disable(dev->dev);
+}
+
+int msm_mdss_init(struct drm_device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev->dev);
+	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_mdss *mdss;
+	int ret;
+
+	DBG("");
+
+	if (!of_device_is_compatible(dev->dev->of_node, "qcom,mdss"))
+		return 0;
+
+	mdss = devm_kzalloc(dev->dev, sizeof(*mdss), GFP_KERNEL);
+	if (!mdss) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	mdss->dev = dev;
+
+	mdss->mmio = msm_ioremap(pdev, "mdss_phys", "MDSS");
+	if (IS_ERR(mdss->mmio)) {
+		ret = PTR_ERR(mdss->mmio);
+		goto fail;
+	}
+
+	mdss->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF");
+	if (IS_ERR(mdss->vbif)) {
+		ret = PTR_ERR(mdss->vbif);
+		goto fail;
+	}
+
+	ret = msm_mdss_get_clocks(mdss);
+	if (ret) {
+		dev_err(dev->dev, "failed to get clocks: %d\n", ret);
+		goto fail;
+	}
+
+	/* Regulator to enable GDSCs in downstream kernels */
+	mdss->vdd = devm_regulator_get(dev->dev, "vdd");
+	if (IS_ERR(mdss->vdd)) {
+		ret = PTR_ERR(mdss->vdd);
+		goto fail;
+	}
+
+	ret = regulator_enable(mdss->vdd);
+	if (ret) {
+		dev_err(dev->dev, "failed to enable regulator vdd: %d\n",
+			ret);
+		goto fail;
+	}
+
+	ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0),
+			       mdss_irq, 0, "mdss_isr", mdss);
+	if (ret) {
+		dev_err(dev->dev, "failed to init irq: %d\n", ret);
+		goto fail_irq;
+	}
+
+	ret = mdss_irq_domain_init(mdss);
+	if (ret) {
+		dev_err(dev->dev, "failed to init sub-block irqs: %d\n", ret);
+		goto fail_irq;
+	}
+
+	priv->mdss = mdss;
+
+	pm_runtime_enable(dev->dev);
+
+	return 0;
+fail_irq:
+	regulator_disable(mdss->vdd);
+fail:
+	return ret;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
new file mode 100644
index 000000000000..8a00991f03c7
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mdp5_kms.h"
+
+/*
+ * As of now, there are only 2 combinations possible for source split:
+ *
+ * Left | Right
+ * -----|------
+ *  LM0 | LM1
+ *  LM2 | LM5
+ *
+ */
+static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 };
+
+static int get_right_pair_idx(struct mdp5_kms *mdp5_kms, int lm)
+{
+	int i;
+	int pair_lm;
+
+	pair_lm = lm_right_pair[lm];
+	if (pair_lm < 0)
+		return -EINVAL;
+
+	for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
+		struct mdp5_hw_mixer *mixer = mdp5_kms->hwmixers[i];
+
+		if (mixer->lm == pair_lm)
+			return mixer->idx;
+	}
+
+	return -1;
+}
+
+int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,
+		      uint32_t caps, struct mdp5_hw_mixer **mixer,
+		      struct mdp5_hw_mixer **r_mixer)
+{
+	struct msm_drm_private *priv = s->dev->dev_private;
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
+	struct mdp5_state *state = mdp5_get_state(s);
+	struct mdp5_hw_mixer_state *new_state;
+	int i;
+
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
+	new_state = &state->hwmixer;
+
+	for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
+		struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i];
+
+		/*
+		 * skip if already in-use by a different CRTC. If there is a
+		 * mixer already assigned to this CRTC, it means this call is
+		 * a request to get an additional right mixer. Assume that the
+		 * existing mixer is the 'left' one, and try to see if we can
+		 * get its corresponding 'right' pair.
+		 */
+		if (new_state->hwmixer_to_crtc[cur->idx] &&
+		    new_state->hwmixer_to_crtc[cur->idx] != crtc)
+			continue;
+
+		/* skip if doesn't support some required caps: */
+		if (caps & ~cur->caps)
+			continue;
+
+		if (r_mixer) {
+			int pair_idx;
+
+			pair_idx = get_right_pair_idx(mdp5_kms, cur->lm);
+			if (pair_idx < 0)
+				return -EINVAL;
+
+			if (new_state->hwmixer_to_crtc[pair_idx])
+				continue;
+
+			*r_mixer = mdp5_kms->hwmixers[pair_idx];
+		}
+
+		/*
+		 * prefer a pair-able LM over an unpairable one. We can
+		 * switch the CRTC from Normal mode to Source Split mode
+		 * without requiring a full modeset if we had already
+		 * assigned this CRTC a pair-able LM.
+		 *
+		 * TODO: There will be assignment sequences which would
+		 * result in the CRTC requiring a full modeset, even
+		 * if we have the LM resources to prevent it. For a platform
+		 * with a few displays, we don't run out of pair-able LMs
+		 * so easily. For now, ignore the possibility of requiring
+		 * a full modeset.
+		 */
+		if (!(*mixer) || cur->caps & MDP_LM_CAP_PAIR)
+			*mixer = cur;
+	}
+
+	if (!(*mixer))
+		return -ENOMEM;
+
+	if (r_mixer && !(*r_mixer))
+		return -ENOMEM;
+
+	DBG("assigning Layer Mixer %d to crtc %s", (*mixer)->lm, crtc->name);
+
+	new_state->hwmixer_to_crtc[(*mixer)->idx] = crtc;
+	if (r_mixer) {
+		DBG("assigning Right Layer Mixer %d to crtc %s", (*r_mixer)->lm,
+		    crtc->name);
+		new_state->hwmixer_to_crtc[(*r_mixer)->idx] = crtc;
+	}
+
+	return 0;
+}
+
+void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)
+{
+	struct mdp5_state *state = mdp5_get_state(s);
+	struct mdp5_hw_mixer_state *new_state = &state->hwmixer;
+
+	if (!mixer)
+		return;
+
+	if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx]))
+		return;
+
+	DBG("%s: release from crtc %s", mixer->name,
+	    new_state->hwmixer_to_crtc[mixer->idx]->name);
+
+	new_state->hwmixer_to_crtc[mixer->idx] = NULL;
+}
+
+void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer)
+{
+	kfree(mixer);
+}
+
+static const char * const mixer_names[] = {
+	"LM0", "LM1", "LM2", "LM3", "LM4", "LM5",
+};
+
+struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm)
+{
+	struct mdp5_hw_mixer *mixer;
+
+	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+	if (!mixer)
+		return ERR_PTR(-ENOMEM);
+
+	mixer->name = mixer_names[lm->id];
+	mixer->lm = lm->id;
+	mixer->caps = lm->caps;
+	mixer->pp = lm->pp;
+	mixer->dspp = lm->dspp;
+	mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id);
+
+	return mixer;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
new file mode 100644
index 000000000000..9be94f567fbd
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP5_LM_H__
+#define __MDP5_LM_H__
+
+/* represents a hw Layer Mixer, one (or more) is dynamically assigned to a crtc */
+struct mdp5_hw_mixer {
+	int idx;
+
+	const char *name;
+
+	int lm;			/* the LM instance # */
+	uint32_t caps;
+	int pp;
+	int dspp;
+
+	uint32_t flush_mask;      /* used to commit LM registers */
+};
+
+/* global atomic state of assignment between CRTCs and Layer Mixers: */
+struct mdp5_hw_mixer_state {
+	struct drm_crtc *hwmixer_to_crtc[8];
+};
+
+struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm);
+void mdp5_mixer_destroy(struct mdp5_hw_mixer *lm);
+int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,
+		      uint32_t caps, struct mdp5_hw_mixer **mixer,
+		      struct mdp5_hw_mixer **r_mixer);
+void mdp5_mixer_release(struct drm_atomic_state *s,
+			struct mdp5_hw_mixer *mixer);
+
+#endif /* __MDP5_LM_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
new file mode 100644
index 000000000000..ff52c49095f9
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mdp5_kms.h"
+
+int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane,
+		     uint32_t caps, uint32_t blkcfg,
+		     struct mdp5_hw_pipe **hwpipe,
+		     struct mdp5_hw_pipe **r_hwpipe)
+{
+	struct msm_drm_private *priv = s->dev->dev_private;
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
+	struct mdp5_state *state;
+	struct mdp5_hw_pipe_state *old_state, *new_state;
+	int i, j;
+
+	state = mdp5_get_state(s);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
+	/* grab old_state after mdp5_get_state(), since now we hold lock: */
+	old_state = &mdp5_kms->state->hwpipe;
+	new_state = &state->hwpipe;
+
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
+		struct mdp5_hw_pipe *cur = mdp5_kms->hwpipes[i];
+
+		/* skip if already in-use.. check both new and old state,
+		 * since we cannot immediately re-use a pipe that is
+		 * released in the current update in some cases:
+		 *  (1) mdp5 can have SMP (non-double-buffered)
+		 *  (2) hw pipe previously assigned to different CRTC
+		 *      (vblanks might not be aligned)
+		 */
+		if (new_state->hwpipe_to_plane[cur->idx] ||
+				old_state->hwpipe_to_plane[cur->idx])
+			continue;
+
+		/* skip if doesn't support some required caps: */
+		if (caps & ~cur->caps)
+			continue;
+
+		/*
+		 * don't assign a cursor pipe to a plane that isn't going to
+		 * be used as a cursor
+		 */
+		if (cur->caps & MDP_PIPE_CAP_CURSOR &&
+				plane->type != DRM_PLANE_TYPE_CURSOR)
+			continue;
+
+		/* possible candidate, take the one with the
+		 * fewest unneeded caps bits set:
+		 */
+		if (!(*hwpipe) || (hweight_long(cur->caps & ~caps) <
+				   hweight_long((*hwpipe)->caps & ~caps))) {
+			bool r_found = false;
+
+			if (r_hwpipe) {
+				for (j = i + 1; j < mdp5_kms->num_hwpipes;
+				     j++) {
+					struct mdp5_hw_pipe *r_cur =
+							mdp5_kms->hwpipes[j];
+
+					/* reject different types of hwpipes */
+					if (r_cur->caps != cur->caps)
+						continue;
+
+					/* respect priority, eg. VIG0 > VIG1 */
+					if (cur->pipe > r_cur->pipe)
+						continue;
+
+					*r_hwpipe = r_cur;
+					r_found = true;
+					break;
+				}
+			}
+
+			if (!r_hwpipe || r_found)
+				*hwpipe = cur;
+		}
+	}
+
+	if (!(*hwpipe))
+		return -ENOMEM;
+
+	if (r_hwpipe && !(*r_hwpipe))
+		return -ENOMEM;
+
+	if (mdp5_kms->smp) {
+		int ret;
+
+		/* We don't support SMP and 2 hwpipes/plane together */
+		WARN_ON(r_hwpipe);
+
+		DBG("%s: alloc SMP blocks", (*hwpipe)->name);
+		ret = mdp5_smp_assign(mdp5_kms->smp, &state->smp,
+				(*hwpipe)->pipe, blkcfg);
+		if (ret)
+			return -ENOMEM;
+
+		(*hwpipe)->blkcfg = blkcfg;
+	}
+
+	DBG("%s: assign to plane %s for caps %x",
+			(*hwpipe)->name, plane->name, caps);
+	new_state->hwpipe_to_plane[(*hwpipe)->idx] = plane;
+
+	if (r_hwpipe) {
+		DBG("%s: assign to right of plane %s for caps %x",
+		    (*r_hwpipe)->name, plane->name, caps);
+		new_state->hwpipe_to_plane[(*r_hwpipe)->idx] = plane;
+	}
+
+	return 0;
+}
+
+void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
+{
+	struct msm_drm_private *priv = s->dev->dev_private;
+	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
+	struct mdp5_state *state = mdp5_get_state(s);
+	struct mdp5_hw_pipe_state *new_state = &state->hwpipe;
+
+	if (!hwpipe)
+		return;
+
+	if (WARN_ON(!new_state->hwpipe_to_plane[hwpipe->idx]))
+		return;
+
+	DBG("%s: release from plane %s", hwpipe->name,
+		new_state->hwpipe_to_plane[hwpipe->idx]->name);
+
+	if (mdp5_kms->smp) {
+		DBG("%s: free SMP blocks", hwpipe->name);
+		mdp5_smp_release(mdp5_kms->smp, &state->smp, hwpipe->pipe);
+	}
+
+	new_state->hwpipe_to_plane[hwpipe->idx] = NULL;
+}
+
+void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe)
+{
+	kfree(hwpipe);
+}
+
+struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
+		uint32_t reg_offset, uint32_t caps)
+{
+	struct mdp5_hw_pipe *hwpipe;
+
+	hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL);
+	if (!hwpipe)
+		return ERR_PTR(-ENOMEM);
+
+	hwpipe->name = pipe2name(pipe);
+	hwpipe->pipe = pipe;
+	hwpipe->reg_offset = reg_offset;
+	hwpipe->caps = caps;
+	hwpipe->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
+
+	return hwpipe;
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
new file mode 100644
index 000000000000..bb2b0ac7aa2b
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP5_PIPE_H__
+#define __MDP5_PIPE_H__
+
+/* TODO: Add SSPP_MAX in mdp5.xml.h */
+#define SSPP_MAX	(SSPP_CURSOR1 + 1)
+
+/* represents a hw pipe, which is dynamically assigned to a plane */
+struct mdp5_hw_pipe {
+	int idx;
+
+	const char *name;
+	enum mdp5_pipe pipe;
+
+	uint32_t reg_offset;
+	uint32_t caps;
+
+	uint32_t flush_mask;      /* used to commit pipe registers */
+
+	/* number of smp blocks per plane, ie:
+	 *   nblks_y | (nblks_u << 8) | (nblks_v << 16)
+	 */
+	uint32_t blkcfg;
+};
+
+/* global atomic state of assignment between pipes and planes: */
+struct mdp5_hw_pipe_state {
+	struct drm_plane *hwpipe_to_plane[SSPP_MAX];
+};
+
+int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane,
+		     uint32_t caps, uint32_t blkcfg,
+		     struct mdp5_hw_pipe **hwpipe,
+		     struct mdp5_hw_pipe **r_hwpipe);
+void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe);
+
+struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
+		uint32_t reg_offset, uint32_t caps);
+void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe);
+
+#endif /* __MDP5_PIPE_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
new file mode 100644
index 000000000000..98d4d7331767
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -0,0 +1,1137 @@
+/*
+ * Copyright (C) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drm_print.h>
+#include "mdp5_kms.h"
+
+struct mdp5_plane {
+	struct drm_plane base;
+
+	uint32_t nformats;
+	uint32_t formats[32];
+};
+#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
+
+static int mdp5_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		struct drm_rect *src, struct drm_rect *dest);
+
+static struct mdp5_kms *get_kms(struct drm_plane *plane)
+{
+	struct msm_drm_private *priv = plane->dev->dev_private;
+	return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static bool plane_enabled(struct drm_plane_state *state)
+{
+	return state->visible;
+}
+
+static void mdp5_plane_destroy(struct drm_plane *plane)
+{
+	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+
+	drm_plane_helper_disable(plane);
+	drm_plane_cleanup(plane);
+
+	kfree(mdp5_plane);
+}
+
+static void mdp5_plane_install_rotation_property(struct drm_device *dev,
+		struct drm_plane *plane)
+{
+	drm_plane_create_rotation_property(plane,
+					   DRM_MODE_ROTATE_0,
+					   DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y);
+}
+
+/* helper to install properties which are common to planes and crtcs */
+static void mdp5_plane_install_properties(struct drm_plane *plane,
+		struct drm_mode_object *obj)
+{
+	struct drm_device *dev = plane->dev;
+	struct msm_drm_private *dev_priv = dev->dev_private;
+	struct drm_property *prop;
+
+#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
+		prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
+		if (!prop) { \
+			prop = drm_property_##fnc(dev, 0, #name, \
+				##__VA_ARGS__); \
+			if (!prop) { \
+				dev_warn(dev->dev, \
+					"Create property %s failed\n", \
+					#name); \
+				return; \
+			} \
+			dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
+		} \
+		drm_object_attach_property(&plane->base, prop, init_val); \
+	} while (0)
+
+#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
+		INSTALL_PROPERTY(name, NAME, init_val, \
+				create_range, min, max)
+
+#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
+		INSTALL_PROPERTY(name, NAME, init_val, \
+				create_enum, name##_prop_enum_list, \
+				ARRAY_SIZE(name##_prop_enum_list))
+
+	INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
+
+	mdp5_plane_install_rotation_property(dev, plane);
+
+#undef INSTALL_RANGE_PROPERTY
+#undef INSTALL_ENUM_PROPERTY
+#undef INSTALL_PROPERTY
+}
+
+static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state, struct drm_property *property,
+		uint64_t val)
+{
+	struct drm_device *dev = plane->dev;
+	struct mdp5_plane_state *pstate;
+	struct msm_drm_private *dev_priv = dev->dev_private;
+	int ret = 0;
+
+	pstate = to_mdp5_plane_state(state);
+
+#define SET_PROPERTY(name, NAME, type) do { \
+		if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
+			pstate->name = (type)val; \
+			DBG("Set property %s %d", #name, (type)val); \
+			goto done; \
+		} \
+	} while (0)
+
+	SET_PROPERTY(zpos, ZPOS, uint8_t);
+
+	dev_err(dev->dev, "Invalid property\n");
+	ret = -EINVAL;
+done:
+	return ret;
+#undef SET_PROPERTY
+}
+
+static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
+		const struct drm_plane_state *state,
+		struct drm_property *property, uint64_t *val)
+{
+	struct drm_device *dev = plane->dev;
+	struct mdp5_plane_state *pstate;
+	struct msm_drm_private *dev_priv = dev->dev_private;
+	int ret = 0;
+
+	pstate = to_mdp5_plane_state(state);
+
+#define GET_PROPERTY(name, NAME, type) do { \
+		if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
+			*val = pstate->name; \
+			DBG("Get property %s %lld", #name, *val); \
+			goto done; \
+		} \
+	} while (0)
+
+	GET_PROPERTY(zpos, ZPOS, uint8_t);
+
+	dev_err(dev->dev, "Invalid property\n");
+	ret = -EINVAL;
+done:
+	return ret;
+#undef SET_PROPERTY
+}
+
+static void
+mdp5_plane_atomic_print_state(struct drm_printer *p,
+		const struct drm_plane_state *state)
+{
+	struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
+	struct mdp5_kms *mdp5_kms = get_kms(state->plane);
+
+	drm_printf(p, "\thwpipe=%s\n", pstate->hwpipe ?
+			pstate->hwpipe->name : "(null)");
+	if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
+		drm_printf(p, "\tright-hwpipe=%s\n",
+			   pstate->r_hwpipe ? pstate->r_hwpipe->name :
+					      "(null)");
+	drm_printf(p, "\tpremultiplied=%u\n", pstate->premultiplied);
+	drm_printf(p, "\tzpos=%u\n", pstate->zpos);
+	drm_printf(p, "\talpha=%u\n", pstate->alpha);
+	drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage));
+}
+
+static void mdp5_plane_reset(struct drm_plane *plane)
+{
+	struct mdp5_plane_state *mdp5_state;
+
+	if (plane->state && plane->state->fb)
+		drm_framebuffer_unreference(plane->state->fb);
+
+	kfree(to_mdp5_plane_state(plane->state));
+	mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
+
+	/* assign default blend parameters */
+	mdp5_state->alpha = 255;
+	mdp5_state->premultiplied = 0;
+
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+		mdp5_state->zpos = STAGE_BASE;
+	else
+		mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
+
+	mdp5_state->base.plane = plane;
+
+	plane->state = &mdp5_state->base;
+}
+
+static struct drm_plane_state *
+mdp5_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct mdp5_plane_state *mdp5_state;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
+			sizeof(*mdp5_state), GFP_KERNEL);
+	if (!mdp5_state)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
+
+	return &mdp5_state->base;
+}
+
+static void mdp5_plane_destroy_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
+
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
+
+	kfree(pstate);
+}
+
+static const struct drm_plane_funcs mdp5_plane_funcs = {
+		.update_plane = drm_atomic_helper_update_plane,
+		.disable_plane = drm_atomic_helper_disable_plane,
+		.destroy = mdp5_plane_destroy,
+		.atomic_set_property = mdp5_plane_atomic_set_property,
+		.atomic_get_property = mdp5_plane_atomic_get_property,
+		.reset = mdp5_plane_reset,
+		.atomic_duplicate_state = mdp5_plane_duplicate_state,
+		.atomic_destroy_state = mdp5_plane_destroy_state,
+		.atomic_print_state = mdp5_plane_atomic_print_state,
+};
+
+static int mdp5_plane_prepare_fb(struct drm_plane *plane,
+				 struct drm_plane_state *new_state)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(plane);
+	struct msm_kms *kms = &mdp5_kms->base.base;
+	struct drm_framebuffer *fb = new_state->fb;
+
+	if (!new_state->fb)
+		return 0;
+
+	DBG("%s: prepare: FB[%u]", plane->name, fb->base.id);
+	return msm_framebuffer_prepare(fb, kms->aspace);
+}
+
+static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
+				  struct drm_plane_state *old_state)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(plane);
+	struct msm_kms *kms = &mdp5_kms->base.base;
+	struct drm_framebuffer *fb = old_state->fb;
+
+	if (!fb)
+		return;
+
+	DBG("%s: cleanup: FB[%u]", plane->name, fb->base.id);
+	msm_framebuffer_cleanup(fb, kms->aspace);
+}
+
+#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
+static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
+					      struct drm_plane_state *state)
+{
+	struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
+	struct drm_plane *plane = state->plane;
+	struct drm_plane_state *old_state = plane->state;
+	struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg);
+	bool new_hwpipe = false;
+	bool need_right_hwpipe = false;
+	uint32_t max_width, max_height;
+	bool out_of_bounds = false;
+	uint32_t caps = 0;
+	struct drm_rect clip = {};
+	int min_scale, max_scale;
+	int ret;
+
+	DBG("%s: check (%d -> %d)", plane->name,
+			plane_enabled(old_state), plane_enabled(state));
+
+	max_width = config->hw->lm.max_width << 16;
+	max_height = config->hw->lm.max_height << 16;
+
+	/* Make sure source dimensions are within bounds. */
+	if (state->src_h > max_height)
+		out_of_bounds = true;
+
+	if (state->src_w > max_width) {
+		/* If source split is supported, we can go up to 2x
+		 * the max LM width, but we'd need to stage another
+		 * hwpipe to the right LM. So, the drm_plane would
+		 * consist of 2 hwpipes.
+		 */
+		if (config->hw->mdp.caps & MDP_CAP_SRC_SPLIT &&
+		    (state->src_w <= 2 * max_width))
+			need_right_hwpipe = true;
+		else
+			out_of_bounds = true;
+	}
+
+	if (out_of_bounds) {
+		struct drm_rect src = drm_plane_state_src(state);
+		DBG("Invalid source size "DRM_RECT_FP_FMT,
+				DRM_RECT_FP_ARG(&src));
+		return -ERANGE;
+	}
+
+	min_scale = FRAC_16_16(1, 8);
+	max_scale = FRAC_16_16(8, 1);
+
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
+
+	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
+						  min_scale, max_scale,
+						  true, true);
+	if (ret)
+		return ret;
+
+	if (plane_enabled(state)) {
+		unsigned int rotation;
+		const struct mdp_format *format;
+		struct mdp5_kms *mdp5_kms = get_kms(plane);
+		uint32_t blkcfg = 0;
+
+		format = to_mdp_format(msm_framebuffer_format(state->fb));
+		if (MDP_FORMAT_IS_YUV(format))
+			caps |= MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
+
+		if (((state->src_w >> 16) != state->crtc_w) ||
+				((state->src_h >> 16) != state->crtc_h))
+			caps |= MDP_PIPE_CAP_SCALE;
+
+		rotation = drm_rotation_simplify(state->rotation,
+						 DRM_MODE_ROTATE_0 |
+						 DRM_MODE_REFLECT_X |
+						 DRM_MODE_REFLECT_Y);
+
+		if (rotation & DRM_MODE_REFLECT_X)
+			caps |= MDP_PIPE_CAP_HFLIP;
+
+		if (rotation & DRM_MODE_REFLECT_Y)
+			caps |= MDP_PIPE_CAP_VFLIP;
+
+		if (plane->type == DRM_PLANE_TYPE_CURSOR)
+			caps |= MDP_PIPE_CAP_CURSOR;
+
+		/* (re)allocate hw pipe if we don't have one or caps-mismatch: */
+		if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
+			new_hwpipe = true;
+
+		/*
+		 * (re)allocte hw pipe if we're either requesting for 2 hw pipes
+		 * or we're switching from 2 hw pipes to 1 hw pipe because the
+		 * new src_w can be supported by 1 hw pipe itself.
+		 */
+		if ((need_right_hwpipe && !mdp5_state->r_hwpipe) ||
+		    (!need_right_hwpipe && mdp5_state->r_hwpipe))
+			new_hwpipe = true;
+
+		if (mdp5_kms->smp) {
+			const struct mdp_format *format =
+				to_mdp_format(msm_framebuffer_format(state->fb));
+
+			blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format,
+					state->src_w >> 16, false);
+
+			if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg))
+				new_hwpipe = true;
+		}
+
+		/* (re)assign hwpipe if needed, otherwise keep old one: */
+		if (new_hwpipe) {
+			/* TODO maybe we want to re-assign hwpipe sometimes
+			 * in cases when we no-longer need some caps to make
+			 * it available for other planes?
+			 */
+			struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe;
+			struct mdp5_hw_pipe *old_right_hwpipe =
+							  mdp5_state->r_hwpipe;
+			struct mdp5_hw_pipe *new_hwpipe = NULL;
+			struct mdp5_hw_pipe *new_right_hwpipe = NULL;
+
+			ret = mdp5_pipe_assign(state->state, plane, caps,
+					       blkcfg, &new_hwpipe,
+					       need_right_hwpipe ?
+					       &new_right_hwpipe : NULL);
+			if (ret) {
+				DBG("%s: failed to assign hwpipe(s)!",
+				    plane->name);
+				return ret;
+			}
+
+			mdp5_state->hwpipe = new_hwpipe;
+			if (need_right_hwpipe)
+				mdp5_state->r_hwpipe = new_right_hwpipe;
+			else
+				/*
+				 * set it to NULL so that the driver knows we
+				 * don't have a right hwpipe when committing a
+				 * new state
+				 */
+				mdp5_state->r_hwpipe = NULL;
+
+
+			mdp5_pipe_release(state->state, old_hwpipe);
+			mdp5_pipe_release(state->state, old_right_hwpipe);
+		}
+	} else {
+		mdp5_pipe_release(state->state, mdp5_state->hwpipe);
+		mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
+		mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL;
+	}
+
+	return 0;
+}
+
+static int mdp5_plane_atomic_check(struct drm_plane *plane,
+				   struct drm_plane_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+
+	crtc = state->crtc ? state->crtc : plane->state->crtc;
+	if (!crtc)
+		return 0;
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
+	if (WARN_ON(!crtc_state))
+		return -EINVAL;
+
+	return mdp5_plane_atomic_check_with_state(crtc_state, state);
+}
+
+static void mdp5_plane_atomic_update(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct drm_plane_state *state = plane->state;
+
+	DBG("%s: update", plane->name);
+
+	if (plane_enabled(state)) {
+		int ret;
+
+		ret = mdp5_plane_mode_set(plane,
+				state->crtc, state->fb,
+				&state->src, &state->dst);
+		/* atomic_check should have ensured that this doesn't fail */
+		WARN_ON(ret < 0);
+	}
+}
+
+static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
+					 struct drm_plane_state *state)
+{
+	struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
+	struct drm_crtc_state *crtc_state;
+	struct drm_rect clip = {};
+	int min_scale, max_scale;
+	int ret;
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+							state->crtc);
+	if (WARN_ON(!crtc_state))
+		return -EINVAL;
+
+	if (!crtc_state->active)
+		return -EINVAL;
+
+	mdp5_state = to_mdp5_plane_state(state);
+
+	/* don't use fast path if we don't have a hwpipe allocated yet */
+	if (!mdp5_state->hwpipe)
+		return -EINVAL;
+
+	/* only allow changing of position(crtc x/y or src x/y) in fast path */
+	if (plane->state->crtc != state->crtc ||
+	    plane->state->src_w != state->src_w ||
+	    plane->state->src_h != state->src_h ||
+	    plane->state->crtc_w != state->crtc_w ||
+	    plane->state->crtc_h != state->crtc_h ||
+	    !plane->state->fb ||
+	    plane->state->fb != state->fb)
+		return -EINVAL;
+
+	min_scale = FRAC_16_16(1, 8);
+	max_scale = FRAC_16_16(8, 1);
+
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
+
+	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
+						  min_scale, max_scale,
+						  true, true);
+	if (ret)
+		return ret;
+
+	/*
+	 * if the visibility of the plane changes (i.e, if the cursor is
+	 * clipped out completely, we can't take the async path because
+	 * we need to stage/unstage the plane from the Layer Mixer(s). We
+	 * also assign/unassign the hwpipe(s) tied to the plane. We avoid
+	 * taking the fast path for both these reasons.
+	 */
+	if (state->visible != plane->state->visible)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
+					   struct drm_plane_state *new_state)
+{
+	plane->state->src_x = new_state->src_x;
+	plane->state->src_y = new_state->src_y;
+	plane->state->crtc_x = new_state->crtc_x;
+	plane->state->crtc_y = new_state->crtc_y;
+
+	if (plane_enabled(new_state)) {
+		struct mdp5_ctl *ctl;
+		struct mdp5_pipeline *pipeline =
+					mdp5_crtc_get_pipeline(plane->crtc);
+		int ret;
+
+		ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb,
+				&new_state->src, &new_state->dst);
+		WARN_ON(ret < 0);
+
+		ctl = mdp5_crtc_get_ctl(new_state->crtc);
+
+		mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane));
+	}
+
+	*to_mdp5_plane_state(plane->state) =
+		*to_mdp5_plane_state(new_state);
+}
+
+static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
+		.prepare_fb = mdp5_plane_prepare_fb,
+		.cleanup_fb = mdp5_plane_cleanup_fb,
+		.atomic_check = mdp5_plane_atomic_check,
+		.atomic_update = mdp5_plane_atomic_update,
+		.atomic_async_check = mdp5_plane_atomic_async_check,
+		.atomic_async_update = mdp5_plane_atomic_async_update,
+};
+
+static void set_scanout_locked(struct mdp5_kms *mdp5_kms,
+			       enum mdp5_pipe pipe,
+			       struct drm_framebuffer *fb)
+{
+	struct msm_kms *kms = &mdp5_kms->base.base;
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
+			MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
+			MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
+			MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
+			MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 0));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 1));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 2));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
+			msm_framebuffer_iova(fb, kms->aspace, 3));
+}
+
+/* Note: mdp5_plane->pipe_lock must be locked */
+static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
+{
+	uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
+			 ~MDP5_PIPE_OP_MODE_CSC_1_EN;
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
+}
+
+/* Note: mdp5_plane->pipe_lock must be locked */
+static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
+		struct csc_cfg *csc)
+{
+	uint32_t  i, mode = 0; /* RGB, no CSC */
+	uint32_t *matrix;
+
+	if (unlikely(!csc))
+		return;
+
+	if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
+		mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
+	if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
+		mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
+	mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
+
+	matrix = csc->matrix;
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
+			MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
+
+	for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
+		uint32_t *pre_clamp = csc->pre_clamp;
+		uint32_t *post_clamp = csc->post_clamp;
+
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
+			MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
+			MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
+
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
+			MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
+			MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
+
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
+			MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
+
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
+			MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
+	}
+}
+
+#define PHASE_STEP_SHIFT	21
+#define DOWN_SCALE_RATIO_MAX	32	/* 2^(26-21) */
+
+static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
+{
+	uint32_t unit;
+
+	if (src == 0 || dst == 0)
+		return -EINVAL;
+
+	/*
+	 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
+	 * where 2^21 represents the unity "1" in fixed-point hardware design.
+	 * This leaves 5 bits for the integer part (downscale case):
+	 *	-> maximum downscale ratio = 0b1_1111 = 31
+	 */
+	if (src > (dst * DOWN_SCALE_RATIO_MAX))
+		return -EOVERFLOW;
+
+	unit = 1 << PHASE_STEP_SHIFT;
+	*out_phase = mult_frac(unit, src, dst);
+
+	return 0;
+}
+
+static int calc_scalex_steps(struct drm_plane *plane,
+		uint32_t pixel_format, uint32_t src, uint32_t dest,
+		uint32_t phasex_steps[COMP_MAX])
+{
+	struct mdp5_kms *mdp5_kms = get_kms(plane);
+	struct device *dev = mdp5_kms->dev->dev;
+	uint32_t phasex_step;
+	unsigned int hsub;
+	int ret;
+
+	ret = calc_phase_step(src, dest, &phasex_step);
+	if (ret) {
+		dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
+		return ret;
+	}
+
+	hsub = drm_format_horz_chroma_subsampling(pixel_format);
+
+	phasex_steps[COMP_0]   = phasex_step;
+	phasex_steps[COMP_3]   = phasex_step;
+	phasex_steps[COMP_1_2] = phasex_step / hsub;
+
+	return 0;
+}
+
+static int calc_scaley_steps(struct drm_plane *plane,
+		uint32_t pixel_format, uint32_t src, uint32_t dest,
+		uint32_t phasey_steps[COMP_MAX])
+{
+	struct mdp5_kms *mdp5_kms = get_kms(plane);
+	struct device *dev = mdp5_kms->dev->dev;
+	uint32_t phasey_step;
+	unsigned int vsub;
+	int ret;
+
+	ret = calc_phase_step(src, dest, &phasey_step);
+	if (ret) {
+		dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
+		return ret;
+	}
+
+	vsub = drm_format_vert_chroma_subsampling(pixel_format);
+
+	phasey_steps[COMP_0]   = phasey_step;
+	phasey_steps[COMP_3]   = phasey_step;
+	phasey_steps[COMP_1_2] = phasey_step / vsub;
+
+	return 0;
+}
+
+static uint32_t get_scale_config(const struct mdp_format *format,
+		uint32_t src, uint32_t dst, bool horz)
+{
+	bool scaling = format->is_yuv ? true : (src != dst);
+	uint32_t sub, pix_fmt = format->base.pixel_format;
+	uint32_t ya_filter, uv_filter;
+	bool yuv = format->is_yuv;
+
+	if (!scaling)
+		return 0;
+
+	if (yuv) {
+		sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) :
+			     drm_format_vert_chroma_subsampling(pix_fmt);
+		uv_filter = ((src / sub) <= dst) ?
+				   SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+	}
+	ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+
+	if (horz)
+		return  MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
+			MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) |
+			MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) |
+			COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter));
+	else
+		return  MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
+			MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) |
+			MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) |
+			COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter));
+}
+
+static void calc_pixel_ext(const struct mdp_format *format,
+		uint32_t src, uint32_t dst, uint32_t phase_step[2],
+		int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX],
+		bool horz)
+{
+	bool scaling = format->is_yuv ? true : (src != dst);
+	int i;
+
+	/*
+	 * Note:
+	 * We assume here that:
+	 *     1. PCMN filter is used for downscale
+	 *     2. bilinear filter is used for upscale
+	 *     3. we are in a single pipe configuration
+	 */
+
+	for (i = 0; i < COMP_MAX; i++) {
+		pix_ext_edge1[i] = 0;
+		pix_ext_edge2[i] = scaling ? 1 : 0;
+	}
+}
+
+static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
+	const struct mdp_format *format,
+	uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX],
+	uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX])
+{
+	uint32_t pix_fmt = format->base.pixel_format;
+	uint32_t lr, tb, req;
+	int i;
+
+	for (i = 0; i < COMP_MAX; i++) {
+		uint32_t roi_w = src_w;
+		uint32_t roi_h = src_h;
+
+		if (format->is_yuv && i == COMP_1_2) {
+			roi_w /= drm_format_horz_chroma_subsampling(pix_fmt);
+			roi_h /= drm_format_vert_chroma_subsampling(pix_fmt);
+		}
+
+		lr  = (pe_left[i] >= 0) ?
+			MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) :
+			MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]);
+
+		lr |= (pe_right[i] >= 0) ?
+			MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) :
+			MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]);
+
+		tb  = (pe_top[i] >= 0) ?
+			MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) :
+			MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]);
+
+		tb |= (pe_bottom[i] >= 0) ?
+			MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) :
+			MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]);
+
+		req  = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w +
+				pe_left[i] + pe_right[i]);
+
+		req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h +
+				pe_top[i] + pe_bottom[i]);
+
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req);
+
+		DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i,
+			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT),
+			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT),
+			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF),
+			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF),
+			FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT));
+
+		DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i,
+			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT),
+			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT),
+			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF),
+			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF),
+			FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM));
+	}
+}
+
+struct pixel_ext {
+	int left[COMP_MAX];
+	int right[COMP_MAX];
+	int top[COMP_MAX];
+	int bottom[COMP_MAX];
+};
+
+struct phase_step {
+	u32 x[COMP_MAX];
+	u32 y[COMP_MAX];
+};
+
+static void mdp5_hwpipe_mode_set(struct mdp5_kms *mdp5_kms,
+				 struct mdp5_hw_pipe *hwpipe,
+				 struct drm_framebuffer *fb,
+				 struct phase_step *step,
+				 struct pixel_ext *pe,
+				 u32 scale_config, u32 hdecm, u32 vdecm,
+				 bool hflip, bool vflip,
+				 int crtc_x, int crtc_y,
+				 unsigned int crtc_w, unsigned int crtc_h,
+				 u32 src_img_w, u32 src_img_h,
+				 u32 src_x, u32 src_y,
+				 u32 src_w, u32 src_h)
+{
+	enum mdp5_pipe pipe = hwpipe->pipe;
+	bool has_pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT;
+	const struct mdp_format *format =
+			to_mdp_format(msm_framebuffer_format(fb));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
+			MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_img_w) |
+			MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_img_h));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
+			MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
+			MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
+			MDP5_PIPE_SRC_XY_X(src_x) |
+			MDP5_PIPE_SRC_XY_Y(src_y));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
+			MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
+			MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
+			MDP5_PIPE_OUT_XY_X(crtc_x) |
+			MDP5_PIPE_OUT_XY_Y(crtc_y));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
+			MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
+			MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
+			MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
+			MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
+			COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
+			MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
+			MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
+			COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
+			MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
+			MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
+			MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
+			MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
+			MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
+			MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
+
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
+			(hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
+			(vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
+			COND(has_pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) |
+			MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
+
+	/* not using secure mode: */
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
+
+	if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT)
+		mdp5_write_pixel_ext(mdp5_kms, pipe, format,
+				src_w, pe->left, pe->right,
+				src_h, pe->top, pe->bottom);
+
+	if (hwpipe->caps & MDP_PIPE_CAP_SCALE) {
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
+				step->x[COMP_0]);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
+				step->y[COMP_0]);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
+				step->x[COMP_1_2]);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
+				step->y[COMP_1_2]);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
+				MDP5_PIPE_DECIMATION_VERT(vdecm) |
+				MDP5_PIPE_DECIMATION_HORZ(hdecm));
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe),
+			   scale_config);
+	}
+
+	if (hwpipe->caps & MDP_PIPE_CAP_CSC) {
+		if (MDP_FORMAT_IS_YUV(format))
+			csc_enable(mdp5_kms, pipe,
+					mdp_get_default_csc_cfg(CSC_YUV2RGB));
+		else
+			csc_disable(mdp5_kms, pipe);
+	}
+
+	set_scanout_locked(mdp5_kms, pipe, fb);
+}
+
+static int mdp5_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		struct drm_rect *src, struct drm_rect *dest)
+{
+	struct drm_plane_state *pstate = plane->state;
+	struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe;
+	struct mdp5_kms *mdp5_kms = get_kms(plane);
+	enum mdp5_pipe pipe = hwpipe->pipe;
+	struct mdp5_hw_pipe *right_hwpipe;
+	const struct mdp_format *format;
+	uint32_t nplanes, config = 0;
+	struct phase_step step = { { 0 } };
+	struct pixel_ext pe = { { 0 } };
+	uint32_t hdecm = 0, vdecm = 0;
+	uint32_t pix_format;
+	unsigned int rotation;
+	bool vflip, hflip;
+	int crtc_x, crtc_y;
+	unsigned int crtc_w, crtc_h;
+	uint32_t src_x, src_y;
+	uint32_t src_w, src_h;
+	uint32_t src_img_w, src_img_h;
+	int ret;
+
+	nplanes = fb->format->num_planes;
+
+	/* bad formats should already be rejected: */
+	if (WARN_ON(nplanes > pipe2nclients(pipe)))
+		return -EINVAL;
+
+	format = to_mdp_format(msm_framebuffer_format(fb));
+	pix_format = format->base.pixel_format;
+
+	src_x = src->x1;
+	src_y = src->y1;
+	src_w = drm_rect_width(src);
+	src_h = drm_rect_height(src);
+
+	crtc_x = dest->x1;
+	crtc_y = dest->y1;
+	crtc_w = drm_rect_width(dest);
+	crtc_h = drm_rect_height(dest);
+
+	/* src values are in Q16 fixed point, convert to integer: */
+	src_x = src_x >> 16;
+	src_y = src_y >> 16;
+	src_w = src_w >> 16;
+	src_h = src_h >> 16;
+
+	src_img_w = min(fb->width, src_w);
+	src_img_h = min(fb->height, src_h);
+
+	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", plane->name,
+			fb->base.id, src_x, src_y, src_w, src_h,
+			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+
+	right_hwpipe = to_mdp5_plane_state(pstate)->r_hwpipe;
+	if (right_hwpipe) {
+		/*
+		 * if the plane comprises of 2 hw pipes, assume that the width
+		 * is split equally across them. The only parameters that varies
+		 * between the 2 pipes are src_x and crtc_x
+		 */
+		crtc_w /= 2;
+		src_w /= 2;
+		src_img_w /= 2;
+	}
+
+	ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, step.x);
+	if (ret)
+		return ret;
+
+	ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, step.y);
+	if (ret)
+		return ret;
+
+	if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
+		calc_pixel_ext(format, src_w, crtc_w, step.x,
+			       pe.left, pe.right, true);
+		calc_pixel_ext(format, src_h, crtc_h, step.y,
+			       pe.top, pe.bottom, false);
+	}
+
+	/* TODO calc hdecm, vdecm */
+
+	/* SCALE is used to both scale and up-sample chroma components */
+	config |= get_scale_config(format, src_w, crtc_w, true);
+	config |= get_scale_config(format, src_h, crtc_h, false);
+	DBG("scale config = %x", config);
+
+	rotation = drm_rotation_simplify(pstate->rotation,
+					 DRM_MODE_ROTATE_0 |
+					 DRM_MODE_REFLECT_X |
+					 DRM_MODE_REFLECT_Y);
+	hflip = !!(rotation & DRM_MODE_REFLECT_X);
+	vflip = !!(rotation & DRM_MODE_REFLECT_Y);
+
+	mdp5_hwpipe_mode_set(mdp5_kms, hwpipe, fb, &step, &pe,
+			     config, hdecm, vdecm, hflip, vflip,
+			     crtc_x, crtc_y, crtc_w, crtc_h,
+			     src_img_w, src_img_h,
+			     src_x, src_y, src_w, src_h);
+	if (right_hwpipe)
+		mdp5_hwpipe_mode_set(mdp5_kms, right_hwpipe, fb, &step, &pe,
+				     config, hdecm, vdecm, hflip, vflip,
+				     crtc_x + crtc_w, crtc_y, crtc_w, crtc_h,
+				     src_img_w, src_img_h,
+				     src_x + src_w, src_y, src_w, src_h);
+
+	plane->fb = fb;
+
+	return ret;
+}
+
+/*
+ * Use this func and the one below only after the atomic state has been
+ * successfully swapped
+ */
+enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
+{
+	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
+
+	if (WARN_ON(!pstate->hwpipe))
+		return SSPP_NONE;
+
+	return pstate->hwpipe->pipe;
+}
+
+enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane)
+{
+	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
+
+	if (!pstate->r_hwpipe)
+		return SSPP_NONE;
+
+	return pstate->r_hwpipe->pipe;
+}
+
+uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
+{
+	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
+	u32 mask;
+
+	if (WARN_ON(!pstate->hwpipe))
+		return 0;
+
+	mask = pstate->hwpipe->flush_mask;
+
+	if (pstate->r_hwpipe)
+		mask |= pstate->r_hwpipe->flush_mask;
+
+	return mask;
+}
+
+/* initialize plane */
+struct drm_plane *mdp5_plane_init(struct drm_device *dev,
+				  enum drm_plane_type type)
+{
+	struct drm_plane *plane = NULL;
+	struct mdp5_plane *mdp5_plane;
+	int ret;
+
+	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
+	if (!mdp5_plane) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	plane = &mdp5_plane->base;
+
+	mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
+		ARRAY_SIZE(mdp5_plane->formats), false);
+
+	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
+			mdp5_plane->formats, mdp5_plane->nformats,
+			NULL, type, NULL);
+	if (ret)
+		goto fail;
+
+	drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
+
+	mdp5_plane_install_properties(plane, &plane->base);
+
+	return plane;
+
+fail:
+	if (plane)
+		mdp5_plane_destroy(plane);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
new file mode 100644
index 000000000000..ae4983d9d0a5
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "mdp5_kms.h"
+#include "mdp5_smp.h"
+
+
+struct mdp5_smp {
+	struct drm_device *dev;
+
+	uint8_t reserved[MAX_CLIENTS]; /* fixed MMBs allocation per client */
+
+	int blk_cnt;
+	int blk_size;
+
+	/* register cache */
+	u32 alloc_w[22];
+	u32 alloc_r[22];
+	u32 pipe_reqprio_fifo_wm0[SSPP_MAX];
+	u32 pipe_reqprio_fifo_wm1[SSPP_MAX];
+	u32 pipe_reqprio_fifo_wm2[SSPP_MAX];
+};
+
+static inline
+struct mdp5_kms *get_kms(struct mdp5_smp *smp)
+{
+	struct msm_drm_private *priv = smp->dev->dev_private;
+
+	return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static inline u32 pipe2client(enum mdp5_pipe pipe, int plane)
+{
+#define CID_UNUSED	0
+
+	if (WARN_ON(plane >= pipe2nclients(pipe)))
+		return CID_UNUSED;
+
+	/*
+	 * Note on SMP clients:
+	 * For ViG pipes, fetch Y/Cr/Cb-components clients are always
+	 * consecutive, and in that order.
+	 *
+	 * e.g.:
+	 * if mdp5_cfg->smp.clients[SSPP_VIG0] = N,
+	 *	Y  plane's client ID is N
+	 *	Cr plane's client ID is N + 1
+	 *	Cb plane's client ID is N + 2
+	 */
+
+	return mdp5_cfg->smp.clients[pipe] + plane;
+}
+
+/* allocate blocks for the specified request: */
+static int smp_request_block(struct mdp5_smp *smp,
+		struct mdp5_smp_state *state,
+		u32 cid, int nblks)
+{
+	void *cs = state->client_state[cid];
+	int i, avail, cnt = smp->blk_cnt;
+	uint8_t reserved;
+
+	/* we shouldn't be requesting blocks for an in-use client: */
+	WARN_ON(bitmap_weight(cs, cnt) > 0);
+
+	reserved = smp->reserved[cid];
+
+	if (reserved) {
+		nblks = max(0, nblks - reserved);
+		DBG("%d MMBs allocated (%d reserved)", nblks, reserved);
+	}
+
+	avail = cnt - bitmap_weight(state->state, cnt);
+	if (nblks > avail) {
+		dev_err(smp->dev->dev, "out of blks (req=%d > avail=%d)\n",
+				nblks, avail);
+		return -ENOSPC;
+	}
+
+	for (i = 0; i < nblks; i++) {
+		int blk = find_first_zero_bit(state->state, cnt);
+		set_bit(blk, cs);
+		set_bit(blk, state->state);
+	}
+
+	return 0;
+}
+
+static void set_fifo_thresholds(struct mdp5_smp *smp,
+		enum mdp5_pipe pipe, int nblks)
+{
+	u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE);
+	u32 val;
+
+	/* 1/4 of SMP pool that is being fetched */
+	val = (nblks * smp_entries_per_blk) / 4;
+
+	smp->pipe_reqprio_fifo_wm0[pipe] = val * 1;
+	smp->pipe_reqprio_fifo_wm1[pipe] = val * 2;
+	smp->pipe_reqprio_fifo_wm2[pipe] = val * 3;
+}
+
+/*
+ * NOTE: looks like if horizontal decimation is used (if we supported that)
+ * then the width used to calculate SMP block requirements is the post-
+ * decimated width.  Ie. SMP buffering sits downstream of decimation (which
+ * presumably happens during the dma from scanout buffer).
+ */
+uint32_t mdp5_smp_calculate(struct mdp5_smp *smp,
+		const struct mdp_format *format,
+		u32 width, bool hdecim)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(smp);
+	int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg);
+	int i, hsub, nplanes, nlines;
+	u32 fmt = format->base.pixel_format;
+	uint32_t blkcfg = 0;
+
+	nplanes = drm_format_num_planes(fmt);
+	hsub = drm_format_horz_chroma_subsampling(fmt);
+
+	/* different if BWC (compressed framebuffer?) enabled: */
+	nlines = 2;
+
+	/* Newer MDPs have split/packing logic, which fetches sub-sampled
+	 * U and V components (splits them from Y if necessary) and packs
+	 * them together, writes to SMP using a single client.
+	 */
+	if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) {
+		fmt = DRM_FORMAT_NV24;
+		nplanes = 2;
+
+		/* if decimation is enabled, HW decimates less on the
+		 * sub sampled chroma components
+		 */
+		if (hdecim && (hsub > 1))
+			hsub = 1;
+	}
+
+	for (i = 0; i < nplanes; i++) {
+		int n, fetch_stride, cpp;
+
+		cpp = drm_format_plane_cpp(fmt, i);
+		fetch_stride = width * cpp / (i ? hsub : 1);
+
+		n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size);
+
+		/* for hw rev v1.00 */
+		if (rev == 0)
+			n = roundup_pow_of_two(n);
+
+		blkcfg |= (n << (8 * i));
+	}
+
+	return blkcfg;
+}
+
+int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state,
+		enum mdp5_pipe pipe, uint32_t blkcfg)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(smp);
+	struct drm_device *dev = mdp5_kms->dev;
+	int i, ret;
+
+	for (i = 0; i < pipe2nclients(pipe); i++) {
+		u32 cid = pipe2client(pipe, i);
+		int n = blkcfg & 0xff;
+
+		if (!n)
+			continue;
+
+		DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n);
+		ret = smp_request_block(smp, state, cid, n);
+		if (ret) {
+			dev_err(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
+					n, ret);
+			return ret;
+		}
+
+		blkcfg >>= 8;
+	}
+
+	state->assigned |= (1 << pipe);
+
+	return 0;
+}
+
+/* Release SMP blocks for all clients of the pipe */
+void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state,
+		enum mdp5_pipe pipe)
+{
+	int i;
+	int cnt = smp->blk_cnt;
+
+	for (i = 0; i < pipe2nclients(pipe); i++) {
+		u32 cid = pipe2client(pipe, i);
+		void *cs = state->client_state[cid];
+
+		/* update global state: */
+		bitmap_andnot(state->state, state->state, cs, cnt);
+
+		/* clear client's state */
+		bitmap_zero(cs, cnt);
+	}
+
+	state->released |= (1 << pipe);
+}
+
+/* NOTE: SMP_ALLOC_* regs are *not* double buffered, so release has to
+ * happen after scanout completes.
+ */
+static unsigned update_smp_state(struct mdp5_smp *smp,
+		u32 cid, mdp5_smp_state_t *assigned)
+{
+	int cnt = smp->blk_cnt;
+	unsigned nblks = 0;
+	u32 blk, val;
+
+	for_each_set_bit(blk, *assigned, cnt) {
+		int idx = blk / 3;
+		int fld = blk % 3;
+
+		val = smp->alloc_w[idx];
+
+		switch (fld) {
+		case 0:
+			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
+			val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
+			break;
+		case 1:
+			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
+			val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid);
+			break;
+		case 2:
+			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
+			val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid);
+			break;
+		}
+
+		smp->alloc_w[idx] = val;
+		smp->alloc_r[idx] = val;
+
+		nblks++;
+	}
+
+	return nblks;
+}
+
+static void write_smp_alloc_regs(struct mdp5_smp *smp)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(smp);
+	int i, num_regs;
+
+	num_regs = smp->blk_cnt / 3 + 1;
+
+	for (i = 0; i < num_regs; i++) {
+		mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(i),
+			   smp->alloc_w[i]);
+		mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(i),
+			   smp->alloc_r[i]);
+	}
+}
+
+static void write_smp_fifo_regs(struct mdp5_smp *smp)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(smp);
+	int i;
+
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
+		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
+		enum mdp5_pipe pipe = hwpipe->pipe;
+
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe),
+			   smp->pipe_reqprio_fifo_wm0[pipe]);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe),
+			   smp->pipe_reqprio_fifo_wm1[pipe]);
+		mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe),
+			   smp->pipe_reqprio_fifo_wm2[pipe]);
+	}
+}
+
+void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
+{
+	enum mdp5_pipe pipe;
+
+	for_each_set_bit(pipe, &state->assigned, sizeof(state->assigned) * 8) {
+		unsigned i, nblks = 0;
+
+		for (i = 0; i < pipe2nclients(pipe); i++) {
+			u32 cid = pipe2client(pipe, i);
+			void *cs = state->client_state[cid];
+
+			nblks += update_smp_state(smp, cid, cs);
+
+			DBG("assign %s:%u, %u blks",
+				pipe2name(pipe), i, nblks);
+		}
+
+		set_fifo_thresholds(smp, pipe, nblks);
+	}
+
+	write_smp_alloc_regs(smp);
+	write_smp_fifo_regs(smp);
+
+	state->assigned = 0;
+}
+
+void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
+{
+	enum mdp5_pipe pipe;
+
+	for_each_set_bit(pipe, &state->released, sizeof(state->released) * 8) {
+		DBG("release %s", pipe2name(pipe));
+		set_fifo_thresholds(smp, pipe, 0);
+	}
+
+	write_smp_fifo_regs(smp);
+
+	state->released = 0;
+}
+
+void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p)
+{
+	struct mdp5_kms *mdp5_kms = get_kms(smp);
+	struct mdp5_hw_pipe_state *hwpstate;
+	struct mdp5_smp_state *state;
+	int total = 0, i, j;
+
+	drm_printf(p, "name\tinuse\tplane\n");
+	drm_printf(p, "----\t-----\t-----\n");
+
+	if (drm_can_sleep())
+		drm_modeset_lock(&mdp5_kms->state_lock, NULL);
+
+	/* grab these *after* we hold the state_lock */
+	hwpstate = &mdp5_kms->state->hwpipe;
+	state = &mdp5_kms->state->smp;
+
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
+		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
+		struct drm_plane *plane = hwpstate->hwpipe_to_plane[hwpipe->idx];
+		enum mdp5_pipe pipe = hwpipe->pipe;
+		for (j = 0; j < pipe2nclients(pipe); j++) {
+			u32 cid = pipe2client(pipe, j);
+			void *cs = state->client_state[cid];
+			int inuse = bitmap_weight(cs, smp->blk_cnt);
+
+			drm_printf(p, "%s:%d\t%d\t%s\n",
+				pipe2name(pipe), j, inuse,
+				plane ? plane->name : NULL);
+
+			total += inuse;
+		}
+	}
+
+	drm_printf(p, "TOTAL:\t%d\t(of %d)\n", total, smp->blk_cnt);
+	drm_printf(p, "AVAIL:\t%d\n", smp->blk_cnt -
+			bitmap_weight(state->state, smp->blk_cnt));
+
+	if (drm_can_sleep())
+		drm_modeset_unlock(&mdp5_kms->state_lock);
+}
+
+void mdp5_smp_destroy(struct mdp5_smp *smp)
+{
+	kfree(smp);
+}
+
+struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg)
+{
+	struct mdp5_smp_state *state = &mdp5_kms->state->smp;
+	struct mdp5_smp *smp = NULL;
+	int ret;
+
+	smp = kzalloc(sizeof(*smp), GFP_KERNEL);
+	if (unlikely(!smp)) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	smp->dev = mdp5_kms->dev;
+	smp->blk_cnt = cfg->mmb_count;
+	smp->blk_size = cfg->mmb_size;
+
+	/* statically tied MMBs cannot be re-allocated: */
+	bitmap_copy(state->state, cfg->reserved_state, smp->blk_cnt);
+	memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved));
+
+	return smp;
+fail:
+	if (smp)
+		mdp5_smp_destroy(smp);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h
new file mode 100644
index 000000000000..b41d0448fbe8
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP5_SMP_H__
+#define __MDP5_SMP_H__
+
+#include <drm/drm_print.h>
+
+#include "msm_drv.h"
+
+/*
+ * SMP - Shared Memory Pool:
+ *
+ * SMP blocks are shared between all the clients, where each plane in
+ * a scanout buffer is a SMP client.  Ie. scanout of 3 plane I420 on
+ * pipe VIG0 => 3 clients: VIG0_Y, VIG0_CB, VIG0_CR.
+ *
+ * Based on the size of the attached scanout buffer, a certain # of
+ * blocks must be allocated to that client out of the shared pool.
+ *
+ * In some hw, some blocks are statically allocated for certain pipes
+ * and CANNOT be re-allocated (eg: MMB0 and MMB1 both tied to RGB0).
+ *
+ *
+ * Atomic SMP State:
+ *
+ * On atomic updates that modify SMP configuration, the state is cloned
+ * (copied) and modified.  For test-only, or in cases where atomic
+ * update fails (or if we hit ww_mutex deadlock/backoff condition) the
+ * new state is simply thrown away.
+ *
+ * Because the SMP registers are not double buffered, updates are a
+ * two step process:
+ *
+ * 1) in _prepare_commit() we configure things (via read-modify-write)
+ *    for the newly assigned pipes, so we don't take away blocks
+ *    assigned to pipes that are still scanning out
+ * 2) in _complete_commit(), after vblank/etc, we clear things for the
+ *    released clients, since at that point old pipes are no longer
+ *    scanning out.
+ */
+struct mdp5_smp_state {
+	/* global state of what blocks are in use: */
+	mdp5_smp_state_t state;
+
+	/* per client state of what blocks they are using: */
+	mdp5_smp_state_t client_state[MAX_CLIENTS];
+
+	/* assigned pipes (hw updated at _prepare_commit()): */
+	unsigned long assigned;
+
+	/* released pipes (hw updated at _complete_commit()): */
+	unsigned long released;
+};
+
+struct mdp5_kms;
+struct mdp5_smp;
+
+/*
+ * SMP module prototypes:
+ * mdp5_smp_init() returns a SMP @handler,
+ * which is then used to call the other mdp5_smp_*(handler, ...) functions.
+ */
+
+struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms,
+		const struct mdp5_smp_block *cfg);
+void  mdp5_smp_destroy(struct mdp5_smp *smp);
+
+void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p);
+
+uint32_t mdp5_smp_calculate(struct mdp5_smp *smp,
+		const struct mdp_format *format,
+		u32 width, bool hdecim);
+
+int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state,
+		enum mdp5_pipe pipe, uint32_t blkcfg);
+void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state,
+		enum mdp5_pipe pipe);
+
+void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state);
+void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state);
+
+#endif /* __MDP5_SMP_H__ */
diff --git a/drivers/gpu/drm/msm/disp/mdp_common.xml.h b/drivers/gpu/drm/msm/disp/mdp_common.xml.h
new file mode 100644
index 000000000000..1494c407be44
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp_common.xml.h
@@ -0,0 +1,104 @@
+#ifndef MDP_COMMON_XML
+#define MDP_COMMON_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
+
+Copyright (C) 2013-2017 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+enum mdp_chroma_samp_type {
+	CHROMA_FULL = 0,
+	CHROMA_H2V1 = 1,
+	CHROMA_H1V2 = 2,
+	CHROMA_420 = 3,
+};
+
+enum mdp_fetch_type {
+	MDP_PLANE_INTERLEAVED = 0,
+	MDP_PLANE_PLANAR = 1,
+	MDP_PLANE_PSEUDO_PLANAR = 2,
+};
+
+enum mdp_mixer_stage_id {
+	STAGE_UNUSED = 0,
+	STAGE_BASE = 1,
+	STAGE0 = 2,
+	STAGE1 = 3,
+	STAGE2 = 4,
+	STAGE3 = 5,
+	STAGE4 = 6,
+	STAGE5 = 7,
+	STAGE6 = 8,
+	STAGE_MAX = 8,
+};
+
+enum mdp_alpha_type {
+	FG_CONST = 0,
+	BG_CONST = 1,
+	FG_PIXEL = 2,
+	BG_PIXEL = 3,
+};
+
+enum mdp_component_type {
+	COMP_0 = 0,
+	COMP_1_2 = 1,
+	COMP_3 = 2,
+	COMP_MAX = 3,
+};
+
+enum mdp_bpc {
+	BPC1 = 0,
+	BPC5 = 1,
+	BPC6 = 2,
+	BPC8 = 3,
+};
+
+enum mdp_bpc_alpha {
+	BPC1A = 0,
+	BPC4A = 1,
+	BPC6A = 2,
+	BPC8A = 3,
+};
+
+
+#endif /* MDP_COMMON_XML */
diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c
new file mode 100644
index 000000000000..b4a8aa4490ee
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp_format.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "msm_drv.h"
+#include "mdp_kms.h"
+
+static struct csc_cfg csc_convert[CSC_MAX] = {
+	[CSC_RGB2RGB] = {
+		.type = CSC_RGB2RGB,
+		.matrix = {
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200
+		},
+		.pre_bias =	{ 0x0, 0x0, 0x0 },
+		.post_bias =	{ 0x0, 0x0, 0x0 },
+		.pre_clamp =	{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff },
+		.post_clamp =	{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff },
+	},
+	[CSC_YUV2RGB] = {
+		.type = CSC_YUV2RGB,
+		.matrix = {
+			0x0254, 0x0000, 0x0331,
+			0x0254, 0xff37, 0xfe60,
+			0x0254, 0x0409, 0x0000
+		},
+		.pre_bias =	{ 0xfff0, 0xff80, 0xff80 },
+		.post_bias =	{ 0x00, 0x00, 0x00 },
+		.pre_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+		.post_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+	},
+	[CSC_RGB2YUV] = {
+		.type = CSC_RGB2YUV,
+		.matrix = {
+			0x0083, 0x0102, 0x0032,
+			0x1fb5, 0x1f6c, 0x00e1,
+			0x00e1, 0x1f45, 0x1fdc
+		},
+		.pre_bias =	{ 0x00, 0x00, 0x00 },
+		.post_bias =	{ 0x10, 0x80, 0x80 },
+		.pre_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+		.post_clamp =	{ 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0 },
+	},
+	[CSC_YUV2YUV] = {
+		.type = CSC_YUV2YUV,
+		.matrix = {
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200
+		},
+		.pre_bias =	{ 0x00, 0x00, 0x00 },
+		.post_bias =	{ 0x00, 0x00, 0x00 },
+		.pre_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+		.post_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+	},
+};
+
+#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs, yuv) { \
+		.base = { .pixel_format = DRM_FORMAT_ ## name }, \
+		.bpc_a = BPC ## a ## A,                          \
+		.bpc_r = BPC ## r,                               \
+		.bpc_g = BPC ## g,                               \
+		.bpc_b = BPC ## b,                               \
+		.unpack = { e0, e1, e2, e3 },                    \
+		.alpha_enable = alpha,                           \
+		.unpack_tight = tight,                           \
+		.cpp = c,                                        \
+		.unpack_count = cnt,                             \
+		.fetch_type = fp,                                \
+		.chroma_sample = cs,                             \
+		.is_yuv = yuv,                                   \
+}
+
+#define BPC0A 0
+
+/*
+ * Note: Keep RGB formats 1st, followed by YUV formats to avoid breaking
+ * mdp_get_rgb_formats()'s implementation.
+ */
+static const struct mdp_format formats[] = {
+	/*  name      a  r  g  b   e0 e1 e2 e3  alpha   tight  cpp cnt ... */
+	FMT(ARGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  true,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(ABGR8888, 8, 8, 8, 8,  2, 0, 1, 3,  true,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(RGBA8888, 8, 8, 8, 8,  3, 1, 0, 2,  true,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(BGRA8888, 8, 8, 8, 8,  3, 2, 0, 1,  true,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(XBGR8888, 8, 8, 8, 8,  2, 0, 1, 3,  false,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(RGBX8888, 8, 8, 8, 8,  3, 1, 0, 2,  false,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(BGRX8888, 8, 8, 8, 8,  3, 2, 0, 1,  false,   true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(RGB565,   0, 5, 6, 5,  1, 0, 2, 0,  false,  true,  2,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+	FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+
+	/* --- RGB formats above / YUV formats below this line --- */
+
+	/* 2 plane YUV */
+	FMT(NV12,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
+			MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
+	FMT(NV21,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
+			MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
+	FMT(NV16,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
+			MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
+	FMT(NV61,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
+			MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
+	/* 1 plane YUV */
+	FMT(VYUY,     0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  2, 4,
+			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+	FMT(UYVY,     0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  2, 4,
+			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+	FMT(YUYV,     0, 8, 8, 8,  0, 1, 0, 2,  false,  true,  2, 4,
+			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+	FMT(YVYU,     0, 8, 8, 8,  0, 2, 0, 1,  false,  true,  2, 4,
+			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
+	/* 3 plane YUV */
+	FMT(YUV420,   0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  1, 1,
+			MDP_PLANE_PLANAR, CHROMA_420, true),
+	FMT(YVU420,   0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  1, 1,
+			MDP_PLANE_PLANAR, CHROMA_420, true),
+};
+
+/*
+ * Note:
+ * @rgb_only must be set to true, when requesting
+ * supported formats for RGB pipes.
+ */
+uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats,
+		bool rgb_only)
+{
+	uint32_t i;
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		const struct mdp_format *f = &formats[i];
+
+		if (i == max_formats)
+			break;
+
+		if (rgb_only && MDP_FORMAT_IS_YUV(f))
+			break;
+
+		pixel_formats[i] = f->base.pixel_format;
+	}
+
+	return i;
+}
+
+const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		const struct mdp_format *f = &formats[i];
+		if (f->base.pixel_format == format)
+			return &f->base;
+	}
+	return NULL;
+}
+
+struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type)
+{
+	if (unlikely(WARN_ON(type >= CSC_MAX)))
+		return NULL;
+
+	return &csc_convert[type];
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp_kms.c b/drivers/gpu/drm/msm/disp/mdp_kms.c
new file mode 100644
index 000000000000..64287304054d
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp_kms.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "msm_drv.h"
+#include "mdp_kms.h"
+
+
+struct mdp_irq_wait {
+	struct mdp_irq irq;
+	int count;
+};
+
+static DECLARE_WAIT_QUEUE_HEAD(wait_event);
+
+static DEFINE_SPINLOCK(list_lock);
+
+static void update_irq(struct mdp_kms *mdp_kms)
+{
+	struct mdp_irq *irq;
+	uint32_t irqmask = mdp_kms->vblank_mask;
+
+	assert_spin_locked(&list_lock);
+
+	list_for_each_entry(irq, &mdp_kms->irq_list, node)
+		irqmask |= irq->irqmask;
+
+	mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask);
+	mdp_kms->cur_irq_mask = irqmask;
+}
+
+/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder
+ * link changes, this must be called to figure out the new global irqmask
+ */
+void mdp_irq_update(struct mdp_kms *mdp_kms)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&list_lock, flags);
+	update_irq(mdp_kms);
+	spin_unlock_irqrestore(&list_lock, flags);
+}
+
+void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status)
+{
+	struct mdp_irq *handler, *n;
+	unsigned long flags;
+
+	spin_lock_irqsave(&list_lock, flags);
+	mdp_kms->in_irq = true;
+	list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) {
+		if (handler->irqmask & status) {
+			spin_unlock_irqrestore(&list_lock, flags);
+			handler->irq(handler, handler->irqmask & status);
+			spin_lock_irqsave(&list_lock, flags);
+		}
+	}
+	mdp_kms->in_irq = false;
+	update_irq(mdp_kms);
+	spin_unlock_irqrestore(&list_lock, flags);
+
+}
+
+void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&list_lock, flags);
+	if (enable)
+		mdp_kms->vblank_mask |= mask;
+	else
+		mdp_kms->vblank_mask &= ~mask;
+	update_irq(mdp_kms);
+	spin_unlock_irqrestore(&list_lock, flags);
+}
+
+static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+	struct mdp_irq_wait *wait =
+			container_of(irq, struct mdp_irq_wait, irq);
+	wait->count--;
+	wake_up_all(&wait_event);
+}
+
+void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask)
+{
+	struct mdp_irq_wait wait = {
+		.irq = {
+			.irq = wait_irq,
+			.irqmask = irqmask,
+		},
+		.count = 1,
+	};
+	mdp_irq_register(mdp_kms, &wait.irq);
+	wait_event_timeout(wait_event, (wait.count <= 0),
+			msecs_to_jiffies(100));
+	mdp_irq_unregister(mdp_kms, &wait.irq);
+}
+
+void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
+{
+	unsigned long flags;
+	bool needs_update = false;
+
+	spin_lock_irqsave(&list_lock, flags);
+
+	if (!irq->registered) {
+		irq->registered = true;
+		list_add(&irq->node, &mdp_kms->irq_list);
+		needs_update = !mdp_kms->in_irq;
+	}
+
+	spin_unlock_irqrestore(&list_lock, flags);
+
+	if (needs_update)
+		mdp_irq_update(mdp_kms);
+}
+
+void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
+{
+	unsigned long flags;
+	bool needs_update = false;
+
+	spin_lock_irqsave(&list_lock, flags);
+
+	if (irq->registered) {
+		irq->registered = false;
+		list_del(&irq->node);
+		needs_update = !mdp_kms->in_irq;
+	}
+
+	spin_unlock_irqrestore(&list_lock, flags);
+
+	if (needs_update)
+		mdp_irq_update(mdp_kms);
+}
diff --git a/drivers/gpu/drm/msm/disp/mdp_kms.h b/drivers/gpu/drm/msm/disp/mdp_kms.h
new file mode 100644
index 000000000000..1185487e7e5e
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/mdp_kms.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP_KMS_H__
+#define __MDP_KMS_H__
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "mdp_common.xml.h"
+
+struct mdp_kms;
+
+struct mdp_kms_funcs {
+	struct msm_kms_funcs base;
+	void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask,
+		uint32_t old_irqmask);
+};
+
+struct mdp_kms {
+	struct msm_kms base;
+
+	const struct mdp_kms_funcs *funcs;
+
+	/* irq handling: */
+	bool in_irq;
+	struct list_head irq_list;    /* list of mdp4_irq */
+	uint32_t vblank_mask;         /* irq bits set for userspace vblank */
+	uint32_t cur_irq_mask;        /* current irq mask */
+};
+#define to_mdp_kms(x) container_of(x, struct mdp_kms, base)
+
+static inline void mdp_kms_init(struct mdp_kms *mdp_kms,
+		const struct mdp_kms_funcs *funcs)
+{
+	mdp_kms->funcs = funcs;
+	INIT_LIST_HEAD(&mdp_kms->irq_list);
+	msm_kms_init(&mdp_kms->base, &funcs->base);
+}
+
+/*
+ * irq helpers:
+ */
+
+/* For transiently registering for different MDP irqs that various parts
+ * of the KMS code need during setup/configuration.  These are not
+ * necessarily the same as what drm_vblank_get/put() are requesting, and
+ * the hysteresis in drm_vblank_put() is not necessarily desirable for
+ * internal housekeeping related irq usage.
+ */
+struct mdp_irq {
+	struct list_head node;
+	uint32_t irqmask;
+	bool registered;
+	void (*irq)(struct mdp_irq *irq, uint32_t irqstatus);
+};
+
+void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status);
+void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable);
+void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask);
+void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
+void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
+void mdp_irq_update(struct mdp_kms *mdp_kms);
+
+/*
+ * pixel format helpers:
+ */
+
+struct mdp_format {
+	struct msm_format base;
+	enum mdp_bpc bpc_r, bpc_g, bpc_b;
+	enum mdp_bpc_alpha bpc_a;
+	uint8_t unpack[4];
+	bool alpha_enable, unpack_tight;
+	uint8_t cpp, unpack_count;
+	enum mdp_fetch_type fetch_type;
+	enum mdp_chroma_samp_type chroma_sample;
+	bool is_yuv;
+};
+#define to_mdp_format(x) container_of(x, struct mdp_format, base)
+#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->is_yuv)
+
+uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only);
+const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
+
+/* MDP capabilities */
+#define MDP_CAP_SMP		BIT(0)	/* Shared Memory Pool                 */
+#define MDP_CAP_DSC		BIT(1)	/* VESA Display Stream Compression    */
+#define MDP_CAP_CDM		BIT(2)	/* Chroma Down Module (HDMI 2.0 YUV)  */
+#define MDP_CAP_SRC_SPLIT	BIT(3)	/* Source Split of SSPPs */
+
+/* MDP pipe capabilities */
+#define MDP_PIPE_CAP_HFLIP			BIT(0)
+#define MDP_PIPE_CAP_VFLIP			BIT(1)
+#define MDP_PIPE_CAP_SCALE			BIT(2)
+#define MDP_PIPE_CAP_CSC			BIT(3)
+#define MDP_PIPE_CAP_DECIMATION			BIT(4)
+#define MDP_PIPE_CAP_SW_PIX_EXT			BIT(5)
+#define MDP_PIPE_CAP_CURSOR			BIT(6)
+
+/* MDP layer mixer caps */
+#define MDP_LM_CAP_DISPLAY			BIT(0)
+#define MDP_LM_CAP_WB				BIT(1)
+#define MDP_LM_CAP_PAIR				BIT(2)
+
+static inline bool pipe_supports_yuv(uint32_t pipe_caps)
+{
+	return (pipe_caps & MDP_PIPE_CAP_SCALE) &&
+		(pipe_caps & MDP_PIPE_CAP_CSC);
+}
+
+enum csc_type {
+	CSC_RGB2RGB = 0,
+	CSC_YUV2RGB,
+	CSC_RGB2YUV,
+	CSC_YUV2YUV,
+	CSC_MAX
+};
+
+struct csc_cfg {
+	enum csc_type type;
+	uint32_t matrix[9];
+	uint32_t pre_bias[3];
+	uint32_t post_bias[3];
+	uint32_t pre_clamp[6];
+	uint32_t post_clamp[6];
+};
+
+struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type);
+
+#endif /* __MDP_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 98742d7af6dc..b744bcc7d8ad 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -192,13 +192,14 @@ void __exit msm_dsi_unregister(void)
 int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 			 struct drm_encoder *encoder)
 {
-	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_drm_private *priv;
 	struct drm_bridge *ext_bridge;
 	int ret;
 
-	if (WARN_ON(!encoder))
+	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
 		return -EINVAL;
 
+	priv = dev->dev_private;
 	msm_dsi->dev = dev;
 
 	ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
@@ -245,19 +246,17 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 
 	return 0;
 fail:
-	if (msm_dsi) {
-		/* bridge/connector are normally destroyed by drm: */
-		if (msm_dsi->bridge) {
-			msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
-			msm_dsi->bridge = NULL;
-		}
+	/* bridge/connector are normally destroyed by drm: */
+	if (msm_dsi->bridge) {
+		msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
+		msm_dsi->bridge = NULL;
+	}
 
-		/* don't destroy connector if we didn't make it */
-		if (msm_dsi->connector && !msm_dsi->external_bridge)
-			msm_dsi->connector->funcs->destroy(msm_dsi->connector);
+	/* don't destroy connector if we didn't make it */
+	if (msm_dsi->connector && !msm_dsi->external_bridge)
+		msm_dsi->connector->funcs->destroy(msm_dsi->connector);
 
-		msm_dsi->connector = NULL;
-	}
+	msm_dsi->connector = NULL;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 2302046197a8..70d9a9a47acd 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -36,6 +36,7 @@ enum msm_dsi_phy_type {
 	MSM_DSI_PHY_20NM,
 	MSM_DSI_PHY_28NM_8960,
 	MSM_DSI_PHY_14NM,
+	MSM_DSI_PHY_10NM,
 	MSM_DSI_PHY_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h
index 479086ccf180..f6a9471b70c8 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.xml.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h
@@ -8,19 +8,10 @@ This file was generated by the rules-ng-ng headergen tool in this git repository
 git clone https://github.com/freedreno/envytools.git
 
 The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
-
-Copyright (C) 2013-2017 by the following authors:
+- /local/mnt/workspace/source_trees/envytools/rnndb/../rnndb/dsi/dsi.xml    (  37239 bytes, from 2018-01-12 09:09:22)
+- /local/mnt/workspace/source_trees/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2016-05-09 06:32:54)
+
+Copyright (C) 2013-2018 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 - Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
 
@@ -1556,5 +1547,175 @@ static inline uint32_t REG_DSI_14nm_PHY_LN_VREG_CNTRL(uint32_t i0) { return 0x00
 
 #define REG_DSI_14nm_PHY_PLL_PLL_BANDGAP			0x00000108
 
+#define REG_DSI_10nm_PHY_CMN_REVISION_ID0			0x00000000
+
+#define REG_DSI_10nm_PHY_CMN_REVISION_ID1			0x00000004
+
+#define REG_DSI_10nm_PHY_CMN_REVISION_ID2			0x00000008
+
+#define REG_DSI_10nm_PHY_CMN_REVISION_ID3			0x0000000c
+
+#define REG_DSI_10nm_PHY_CMN_CLK_CFG0				0x00000010
+
+#define REG_DSI_10nm_PHY_CMN_CLK_CFG1				0x00000014
+
+#define REG_DSI_10nm_PHY_CMN_GLBL_CTRL				0x00000018
+
+#define REG_DSI_10nm_PHY_CMN_RBUF_CTRL				0x0000001c
+
+#define REG_DSI_10nm_PHY_CMN_VREG_CTRL				0x00000020
+
+#define REG_DSI_10nm_PHY_CMN_CTRL_0				0x00000024
+
+#define REG_DSI_10nm_PHY_CMN_CTRL_1				0x00000028
+
+#define REG_DSI_10nm_PHY_CMN_CTRL_2				0x0000002c
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CFG0				0x00000030
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CFG1				0x00000034
+
+#define REG_DSI_10nm_PHY_CMN_PLL_CNTRL				0x00000038
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CTRL0				0x00000098
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CTRL1				0x0000009c
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CTRL2				0x000000a0
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CTRL3				0x000000a4
+
+#define REG_DSI_10nm_PHY_CMN_LANE_CTRL4				0x000000a8
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0			0x000000ac
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1			0x000000b0
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2			0x000000b4
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3			0x000000b8
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4			0x000000bc
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5			0x000000c0
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6			0x000000c4
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7			0x000000c8
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8			0x000000cc
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9			0x000000d0
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10			0x000000d4
+
+#define REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11			0x000000d8
+
+#define REG_DSI_10nm_PHY_CMN_PHY_STATUS				0x000000ec
+
+#define REG_DSI_10nm_PHY_CMN_LANE_STATUS0			0x000000f4
+
+#define REG_DSI_10nm_PHY_CMN_LANE_STATUS1			0x000000f8
+
+static inline uint32_t REG_DSI_10nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_CFG0(uint32_t i0) { return 0x00000000 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_CFG1(uint32_t i0) { return 0x00000004 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_CFG2(uint32_t i0) { return 0x00000008 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_CFG3(uint32_t i0) { return 0x0000000c + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000010 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_PIN_SWAP(uint32_t i0) { return 0x00000014 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(uint32_t i0) { return 0x00000018 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(uint32_t i0) { return 0x0000001c + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(uint32_t i0) { return 0x00000020 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(uint32_t i0) { return 0x00000024 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_LPRX_CTRL(uint32_t i0) { return 0x00000028 + 0x80*i0; }
+
+static inline uint32_t REG_DSI_10nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x0000002c + 0x80*i0; }
+
+#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE		0x00000000
+
+#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO		0x00000004
+
+#define REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE		0x00000010
+
+#define REG_DSI_10nm_PHY_PLL_DSM_DIVIDER			0x0000001c
+
+#define REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER			0x00000020
+
+#define REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES			0x00000024
+
+#define REG_DSI_10nm_PHY_PLL_CMODE				0x0000002c
+
+#define REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS		0x00000030
+
+#define REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE	0x00000054
+
+#define REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE		0x00000064
+
+#define REG_DSI_10nm_PHY_PLL_PFILT				0x0000007c
+
+#define REG_DSI_10nm_PHY_PLL_IFILT				0x00000080
+
+#define REG_DSI_10nm_PHY_PLL_OUTDIV				0x00000094
+
+#define REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE			0x000000a4
+
+#define REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE		0x000000a8
+
+#define REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO		0x000000b4
+
+#define REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1		0x000000cc
+
+#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1		0x000000d0
+
+#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1		0x000000d4
+
+#define REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1		0x000000d8
+
+#define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1			0x0000010c
+
+#define REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1		0x00000110
+
+#define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1			0x00000114
+
+#define REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1			0x00000118
+
+#define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1		0x0000011c
+
+#define REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1		0x00000120
+
+#define REG_DSI_10nm_PHY_PLL_SSC_CONTROL			0x0000013c
+
+#define REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE			0x00000140
+
+#define REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1			0x00000144
+
+#define REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1		0x0000014c
+
+#define REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1		0x00000154
+
+#define REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1		0x0000015c
+
+#define REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1	0x00000164
+
+#define REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE			0x00000180
+
+#define REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY			0x00000184
+
+#define REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS			0x0000018c
+
+#define REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE			0x000001a0
+
 
 #endif /* DSI_XML */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
index 65c1dfbbe019..0327bb54b01b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -118,6 +118,24 @@ static const struct msm_dsi_config msm8996_dsi_cfg = {
 	.num_dsi = 2,
 };
 
+static const char * const dsi_sdm845_bus_clk_names[] = {
+	"iface", "bus",
+};
+
+static const struct msm_dsi_config sdm845_dsi_cfg = {
+	.io_offset = DSI_6G_REG_SHIFT,
+	.reg_cfg = {
+		.num = 1,
+		.regs = {
+			{"vdda", 21800, 4 },	/* 1.2 V */
+		},
+	},
+	.bus_clk_names = dsi_sdm845_bus_clk_names,
+	.num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names),
+	.io_start = { 0xae94000, 0xae96000 },
+	.num_dsi = 2,
+};
+
 static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
 	{MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg},
 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0,
@@ -131,6 +149,7 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg},
 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg},
 	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg},
+	{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg},
 };
 
 const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
index 00a5da2663c6..9cfdcf1c95d5 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
@@ -25,6 +25,7 @@
 #define MSM_DSI_6G_VER_MINOR_V1_3	0x10030000
 #define MSM_DSI_6G_VER_MINOR_V1_3_1	0x10030001
 #define MSM_DSI_6G_VER_MINOR_V1_4_1	0x10040001
+#define MSM_DSI_6G_VER_MINOR_V2_2_1	0x20020001
 
 #define MSM_DSI_V2_VER_MINOR_8064	0x0
 
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 0f7324a686ca..7a03a9489708 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -115,6 +115,7 @@ struct msm_dsi_host {
 	struct clk *pixel_clk;
 	struct clk *byte_clk_src;
 	struct clk *pixel_clk_src;
+	struct clk *byte_intf_clk;
 
 	u32 byte_clk_rate;
 	u32 esc_clk_rate;
@@ -214,7 +215,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
 		goto exit;
 	}
 
-	ahb_clk = clk_get(dev, "iface_clk");
+	ahb_clk = msm_clk_get(msm_host->pdev, "iface");
 	if (IS_ERR(ahb_clk)) {
 		pr_err("%s: cannot get interface clock\n", __func__);
 		goto put_gdsc;
@@ -225,7 +226,7 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
 	ret = regulator_enable(gdsc_reg);
 	if (ret) {
 		pr_err("%s: unable to enable gdsc\n", __func__);
-		goto put_clk;
+		goto put_gdsc;
 	}
 
 	ret = clk_prepare_enable(ahb_clk);
@@ -249,8 +250,6 @@ static const struct msm_dsi_cfg_handler *dsi_get_config(
 disable_gdsc:
 	regulator_disable(gdsc_reg);
 	pm_runtime_put_sync(dev);
-put_clk:
-	clk_put(ahb_clk);
 put_gdsc:
 	regulator_put(gdsc_reg);
 exit:
@@ -379,6 +378,19 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host)
 		goto exit;
 	}
 
+	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G &&
+	    cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_2_1) {
+		msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf");
+		if (IS_ERR(msm_host->byte_intf_clk)) {
+			ret = PTR_ERR(msm_host->byte_intf_clk);
+			pr_err("%s: can't find byte_intf clock. ret=%d\n",
+			        __func__, ret);
+			goto exit;
+		}
+	} else {
+		msm_host->byte_intf_clk = NULL;
+	}
+
 	msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk);
 	if (!msm_host->byte_clk_src) {
 		ret = -ENODEV;
@@ -504,6 +516,16 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host)
 		goto error;
 	}
 
+	if (msm_host->byte_intf_clk) {
+		ret = clk_set_rate(msm_host->byte_intf_clk,
+				   msm_host->byte_clk_rate / 2);
+		if (ret) {
+			pr_err("%s: Failed to set rate byte intf clk, %d\n",
+			       __func__, ret);
+			goto error;
+		}
+	}
+
 	ret = clk_prepare_enable(msm_host->esc_clk);
 	if (ret) {
 		pr_err("%s: Failed to enable dsi esc clk\n", __func__);
@@ -522,8 +544,19 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host)
 		goto pixel_clk_err;
 	}
 
+	if (msm_host->byte_intf_clk) {
+		ret = clk_prepare_enable(msm_host->byte_intf_clk);
+		if (ret) {
+			pr_err("%s: Failed to enable byte intf clk\n",
+			       __func__);
+			goto byte_intf_clk_err;
+		}
+	}
+
 	return 0;
 
+byte_intf_clk_err:
+	clk_disable_unprepare(msm_host->pixel_clk);
 pixel_clk_err:
 	clk_disable_unprepare(msm_host->byte_clk);
 byte_clk_err:
@@ -617,6 +650,8 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
 	if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) {
 		clk_disable_unprepare(msm_host->esc_clk);
 		clk_disable_unprepare(msm_host->pixel_clk);
+		if (msm_host->byte_intf_clk)
+			clk_disable_unprepare(msm_host->byte_intf_clk);
 		clk_disable_unprepare(msm_host->byte_clk);
 	} else {
 		clk_disable_unprepare(msm_host->pixel_clk);
@@ -1028,10 +1063,8 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
 
 	if (msm_host->tx_gem_obj) {
 		msm_gem_put_iova(msm_host->tx_gem_obj, 0);
-		mutex_lock(&dev->struct_mutex);
-		msm_gem_free_object(msm_host->tx_gem_obj);
+		drm_gem_object_put_unlocked(msm_host->tx_gem_obj);
 		msm_host->tx_gem_obj = NULL;
-		mutex_unlock(&dev->struct_mutex);
 	}
 
 	if (msm_host->tx_buf)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 855248132b2b..4cb1cb68878b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -88,6 +88,8 @@ static int dsi_mgr_setup_components(int id)
 
 		msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
 		src_pll = msm_dsi_phy_get_pll(msm_dsi->phy);
+		if (IS_ERR(src_pll))
+			return PTR_ERR(src_pll);
 		ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
 	} else if (!other_dsi) {
 		ret = 0;
@@ -116,6 +118,8 @@ static int dsi_mgr_setup_components(int id)
 		msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
 					MSM_DSI_PHY_SLAVE);
 		src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy);
+		if (IS_ERR(src_pll))
+			return PTR_ERR(src_pll);
 		ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
 		if (ret)
 			return ret;
@@ -858,7 +862,7 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
 	int id = msm_dsi->id;
 	int ret;
 
-	if (id > DSI_MAX) {
+	if (id >= DSI_MAX) {
 		pr_err("%s: invalid id %d\n", __func__, id);
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index 790ca280cbfd..8e9d5c255820 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -394,6 +394,10 @@ static const struct of_device_id dsi_phy_dt_match[] = {
 #ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
 	{ .compatible = "qcom,dsi-phy-14nm",
 	  .data = &dsi_phy_14nm_cfgs },
+#endif
+#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
+	{ .compatible = "qcom,dsi-phy-10nm",
+	  .data = &dsi_phy_10nm_cfgs },
 #endif
 	{}
 };
@@ -503,10 +507,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
 		goto fail;
 
 	phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
-	if (!phy->pll)
+	if (IS_ERR_OR_NULL(phy->pll))
 		dev_info(dev,
-			"%s: pll init failed, need separate pll clk driver\n",
-			__func__);
+			"%s: pll init failed: %ld, need separate pll clk driver\n",
+			__func__, PTR_ERR(phy->pll));
 
 	dsi_phy_disable_resource(phy);
 
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index 1733f6608a09..c56268cbdb3d 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -48,6 +48,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs;
 extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
 extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs;
 extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs;
 
 struct msm_dsi_dphy_timing {
 	u32 clk_pre;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
new file mode 100644
index 000000000000..0af951aaeea1
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
@@ -0,0 +1,251 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright (c) 2018, The Linux Foundation
+ */
+
+#include <linux/iopoll.h>
+
+#include "dsi_phy.h"
+#include "dsi.xml.h"
+
+static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy)
+{
+	void __iomem *base = phy->base;
+	u32 data = 0;
+
+	data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL);
+	mb(); /* make sure read happened */
+
+	return (data & BIT(0));
+}
+
+static void dsi_phy_hw_v3_0_config_lpcdrx(struct msm_dsi_phy *phy, bool enable)
+{
+	void __iomem *lane_base = phy->lane_base;
+	int phy_lane_0 = 0;	/* TODO: Support all lane swap configs */
+
+	/*
+	 * LPRX and CDRX need to enabled only for physical data lane
+	 * corresponding to the logical data lane 0
+	 */
+	if (enable)
+		dsi_phy_write(lane_base +
+			      REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0x3);
+	else
+		dsi_phy_write(lane_base +
+			      REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0);
+}
+
+static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy)
+{
+	int i;
+	u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 };
+	void __iomem *lane_base = phy->lane_base;
+
+	/* Strength ctrl settings */
+	for (i = 0; i < 5; i++) {
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i),
+			      0x55);
+		/*
+		 * Disable LPRX and CDRX for all lanes. And later on, it will
+		 * be only enabled for the physical data lane corresponding
+		 * to the logical data lane 0
+		 */
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i), 0);
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i), 0x0);
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i),
+			      0x88);
+	}
+
+	dsi_phy_hw_v3_0_config_lpcdrx(phy, true);
+
+	/* other settings */
+	for (i = 0; i < 5; i++) {
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG0(i), 0x0);
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG1(i), 0x0);
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0);
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i),
+			      i == 4 ? 0x80 : 0x0);
+		dsi_phy_write(lane_base +
+			      REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0);
+		dsi_phy_write(lane_base +
+			      REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0);
+		dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i),
+			      tx_dctrl[i]);
+	}
+
+	/* Toggle BIT 0 to release freeze I/0 */
+	dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05);
+	dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04);
+}
+
+static int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
+				       struct msm_dsi_phy_clk_request *clk_req)
+{
+	/*
+	 * TODO: These params need to be computed, they're currently hardcoded
+	 * for a 1440x2560@60Hz panel with a byteclk of 100.618 Mhz, and a
+	 * default escape clock of 19.2 Mhz.
+	 */
+
+	timing->hs_halfbyte_en = 0;
+	timing->clk_zero = 0x1c;
+	timing->clk_prepare = 0x07;
+	timing->clk_trail = 0x07;
+	timing->hs_exit = 0x23;
+	timing->hs_zero = 0x21;
+	timing->hs_prepare = 0x07;
+	timing->hs_trail = 0x07;
+	timing->hs_rqst = 0x05;
+	timing->ta_sure = 0x00;
+	timing->ta_go = 0x03;
+	timing->ta_get = 0x04;
+
+	timing->shared_timings.clk_pre = 0x2d;
+	timing->shared_timings.clk_post = 0x0d;
+
+	return 0;
+}
+
+static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+			       struct msm_dsi_phy_clk_request *clk_req)
+{
+	int ret;
+	u32 status;
+	u32 const delay_us = 5;
+	u32 const timeout_us = 1000;
+	struct msm_dsi_dphy_timing *timing = &phy->timing;
+	void __iomem *base = phy->base;
+	u32 data;
+
+	DBG("");
+
+	if (msm_dsi_dphy_timing_calc_v3(timing, clk_req)) {
+		dev_err(&phy->pdev->dev,
+			"%s: D-PHY timing calculation failed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (dsi_phy_hw_v3_0_is_pll_on(phy))
+		pr_warn("PLL turned on before configuring PHY\n");
+
+	/* wait for REFGEN READY */
+	ret = readl_poll_timeout_atomic(base + REG_DSI_10nm_PHY_CMN_PHY_STATUS,
+					status, (status & BIT(0)),
+					delay_us, timeout_us);
+	if (ret) {
+		pr_err("Ref gen not ready. Aborting\n");
+		return -EINVAL;
+	}
+
+	/* de-assert digital and pll power down */
+	data = BIT(6) | BIT(5);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data);
+
+	/* Assert PLL core reset */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0x00);
+
+	/* turn off resync FIFO */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x00);
+
+	/* Select MS1 byte-clk */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10);
+
+	/* Enable LDO */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59);
+
+	/* Configure PHY lane swap (TODO: we need to calculate this) */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG1, 0x84);
+
+	/* DSI PHY timings */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0,
+		      timing->hs_halfbyte_en);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1,
+		      timing->clk_zero);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2,
+		      timing->clk_prepare);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3,
+		      timing->clk_trail);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4,
+		      timing->hs_exit);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5,
+		      timing->hs_zero);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6,
+		      timing->hs_prepare);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7,
+		      timing->hs_trail);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8,
+		      timing->hs_rqst);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9,
+		      timing->ta_go | (timing->ta_sure << 3));
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10,
+		      timing->ta_get);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11,
+		      0x00);
+
+	/* Remove power down from all blocks */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x7f);
+
+	/* power up lanes */
+	data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0);
+
+	/* TODO: only power up lanes that are used */
+	data |= 0x1F;
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data);
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0x1F);
+
+	/* Select full-rate mode */
+	dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40);
+
+	ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase);
+	if (ret) {
+		dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* DSI lane settings */
+	dsi_phy_hw_v3_0_lane_settings(phy);
+
+	DBG("DSI%d PHY enabled", phy->id);
+
+	return 0;
+}
+
+static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy)
+{
+}
+
+static int dsi_10nm_phy_init(struct msm_dsi_phy *phy)
+{
+	struct platform_device *pdev = phy->pdev;
+
+	phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane",
+				     "DSI_PHY_LANE");
+	if (IS_ERR(phy->lane_base)) {
+		dev_err(&pdev->dev, "%s: failed to map phy lane base\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = {
+	.type = MSM_DSI_PHY_10NM,
+	.src_pll_truthtable = { {false, false}, {true, false} },
+	.reg_cfg = {
+		.num = 1,
+		.regs = {
+			{"vdds", 36000, 32},
+		},
+	},
+	.ops = {
+		.enable = dsi_10nm_phy_enable,
+		.disable = dsi_10nm_phy_disable,
+		.init = dsi_10nm_phy_init,
+	},
+	.io_start = { 0xae94400, 0xae96400 },
+	.num_dsi_phy = 2,
+};
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
index bc289f5c9078..613e206fa4fc 100644
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
@@ -166,6 +166,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
 	case MSM_DSI_PHY_14NM:
 		pll = msm_dsi_pll_14nm_init(pdev, id);
 		break;
+	case MSM_DSI_PHY_10NM:
+		pll = msm_dsi_pll_10nm_init(pdev, id);
+		break;
 	default:
 		pll = ERR_PTR(-ENXIO);
 		break;
@@ -173,7 +176,7 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
 
 	if (IS_ERR(pll)) {
 		dev_err(dev, "%s: failed to init DSI PLL\n", __func__);
-		return NULL;
+		return pll;
 	}
 
 	pll->type = type;
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
index f63e7ada74a8..8b32271cbc24 100644
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
@@ -115,5 +115,14 @@ msm_dsi_pll_14nm_init(struct platform_device *pdev, int id)
 	return ERR_PTR(-ENODEV);
 }
 #endif
+#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
+struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id);
+#else
+static inline struct msm_dsi_pll *
+msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
 #endif /* __DSI_PLL_H__ */
 
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
new file mode 100644
index 000000000000..c4c37a7df637
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
@@ -0,0 +1,822 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright (c) 2018, The Linux Foundation
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/iopoll.h>
+
+#include "dsi_pll.h"
+#include "dsi.xml.h"
+
+/*
+ * DSI PLL 10nm - clock diagram (eg: DSI0):
+ *
+ *           dsi0_pll_out_div_clk  dsi0_pll_bit_clk
+ *                              |                |
+ *                              |                |
+ *                 +---------+  |  +----------+  |  +----+
+ *  dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0pllbyte
+ *                 +---------+  |  +----------+  |  +----+
+ *                              |                |
+ *                              |                |         dsi0_pll_by_2_bit_clk
+ *                              |                |          |
+ *                              |                |  +----+  |  |\  dsi0_pclk_mux
+ *                              |                |--| /2 |--o--| \   |
+ *                              |                |  +----+     |  \  |  +---------+
+ *                              |                --------------|  |--o--| div_7_4 |-- dsi0pll
+ *                              |------------------------------|  /     +---------+
+ *                              |          +-----+             | /
+ *                              -----------| /4? |--o----------|/
+ *                                         +-----+  |           |
+ *                                                  |           |dsiclk_sel
+ *                                                  |
+ *                                                  dsi0_pll_post_out_div_clk
+ */
+
+#define DSI_BYTE_PLL_CLK		0
+#define DSI_PIXEL_PLL_CLK		1
+#define NUM_PROVIDED_CLKS		2
+
+struct dsi_pll_regs {
+	u32 pll_prop_gain_rate;
+	u32 pll_lockdet_rate;
+	u32 decimal_div_start;
+	u32 frac_div_start_low;
+	u32 frac_div_start_mid;
+	u32 frac_div_start_high;
+	u32 pll_clock_inverters;
+	u32 ssc_stepsize_low;
+	u32 ssc_stepsize_high;
+	u32 ssc_div_per_low;
+	u32 ssc_div_per_high;
+	u32 ssc_adjper_low;
+	u32 ssc_adjper_high;
+	u32 ssc_control;
+};
+
+struct dsi_pll_config {
+	u32 ref_freq;
+	bool div_override;
+	u32 output_div;
+	bool ignore_frac;
+	bool disable_prescaler;
+	bool enable_ssc;
+	bool ssc_center;
+	u32 dec_bits;
+	u32 frac_bits;
+	u32 lock_timer;
+	u32 ssc_freq;
+	u32 ssc_offset;
+	u32 ssc_adj_per;
+	u32 thresh_cycles;
+	u32 refclk_cycles;
+};
+
+struct pll_10nm_cached_state {
+	unsigned long vco_rate;
+	u8 bit_clk_div;
+	u8 pix_clk_div;
+	u8 pll_out_div;
+	u8 pll_mux;
+};
+
+struct dsi_pll_10nm {
+	struct msm_dsi_pll base;
+
+	int id;
+	struct platform_device *pdev;
+
+	void __iomem *phy_cmn_mmio;
+	void __iomem *mmio;
+
+	u64 vco_ref_clk_rate;
+	u64 vco_current_rate;
+
+	/* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */
+	spinlock_t postdiv_lock;
+
+	int vco_delay;
+	struct dsi_pll_config pll_configuration;
+	struct dsi_pll_regs reg_setup;
+
+	/* private clocks: */
+	struct clk_hw *hws[NUM_DSI_CLOCKS_MAX];
+	u32 num_hws;
+
+	/* clock-provider: */
+	struct clk_hw_onecell_data *hw_data;
+
+	struct pll_10nm_cached_state cached_state;
+
+	enum msm_dsi_phy_usecase uc;
+	struct dsi_pll_10nm *slave;
+};
+
+#define to_pll_10nm(x)	container_of(x, struct dsi_pll_10nm, base)
+
+/*
+ * Global list of private DSI PLL struct pointers. We need this for Dual DSI
+ * mode, where the master PLL's clk_ops needs access the slave's private data
+ */
+static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX];
+
+static void dsi_pll_setup_config(struct dsi_pll_10nm *pll)
+{
+	struct dsi_pll_config *config = &pll->pll_configuration;
+
+	config->ref_freq = pll->vco_ref_clk_rate;
+	config->output_div = 1;
+	config->dec_bits = 8;
+	config->frac_bits = 18;
+	config->lock_timer = 64;
+	config->ssc_freq = 31500;
+	config->ssc_offset = 5000;
+	config->ssc_adj_per = 2;
+	config->thresh_cycles = 32;
+	config->refclk_cycles = 256;
+
+	config->div_override = false;
+	config->ignore_frac = false;
+	config->disable_prescaler = false;
+
+	config->enable_ssc = false;
+	config->ssc_center = 0;
+}
+
+static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll)
+{
+	struct dsi_pll_config *config = &pll->pll_configuration;
+	struct dsi_pll_regs *regs = &pll->reg_setup;
+	u64 fref = pll->vco_ref_clk_rate;
+	u64 pll_freq;
+	u64 divider;
+	u64 dec, dec_multiple;
+	u32 frac;
+	u64 multiplier;
+
+	pll_freq = pll->vco_current_rate;
+
+	if (config->disable_prescaler)
+		divider = fref;
+	else
+		divider = fref * 2;
+
+	multiplier = 1 << config->frac_bits;
+	dec_multiple = div_u64(pll_freq * multiplier, divider);
+	div_u64_rem(dec_multiple, multiplier, &frac);
+
+	dec = div_u64(dec_multiple, multiplier);
+
+	if (pll_freq <= 1900000000UL)
+		regs->pll_prop_gain_rate = 8;
+	else if (pll_freq <= 3000000000UL)
+		regs->pll_prop_gain_rate = 10;
+	else
+		regs->pll_prop_gain_rate = 12;
+	if (pll_freq < 1100000000UL)
+		regs->pll_clock_inverters = 8;
+	else
+		regs->pll_clock_inverters = 0;
+
+	regs->pll_lockdet_rate = config->lock_timer;
+	regs->decimal_div_start = dec;
+	regs->frac_div_start_low = (frac & 0xff);
+	regs->frac_div_start_mid = (frac & 0xff00) >> 8;
+	regs->frac_div_start_high = (frac & 0x30000) >> 16;
+}
+
+#define SSC_CENTER		BIT(0)
+#define SSC_EN			BIT(1)
+
+static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll)
+{
+	struct dsi_pll_config *config = &pll->pll_configuration;
+	struct dsi_pll_regs *regs = &pll->reg_setup;
+	u32 ssc_per;
+	u32 ssc_mod;
+	u64 ssc_step_size;
+	u64 frac;
+
+	if (!config->enable_ssc) {
+		DBG("SSC not enabled\n");
+		return;
+	}
+
+	ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1;
+	ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
+	ssc_per -= ssc_mod;
+
+	frac = regs->frac_div_start_low |
+			(regs->frac_div_start_mid << 8) |
+			(regs->frac_div_start_high << 16);
+	ssc_step_size = regs->decimal_div_start;
+	ssc_step_size *= (1 << config->frac_bits);
+	ssc_step_size += frac;
+	ssc_step_size *= config->ssc_offset;
+	ssc_step_size *= (config->ssc_adj_per + 1);
+	ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
+	ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
+
+	regs->ssc_div_per_low = ssc_per & 0xFF;
+	regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8;
+	regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF);
+	regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8);
+	regs->ssc_adjper_low = config->ssc_adj_per & 0xFF;
+	regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8;
+
+	regs->ssc_control = config->ssc_center ? SSC_CENTER : 0;
+
+	pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
+		 regs->decimal_div_start, frac, config->frac_bits);
+	pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
+		 ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
+}
+
+static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll)
+{
+	void __iomem *base = pll->mmio;
+	struct dsi_pll_regs *regs = &pll->reg_setup;
+
+	if (pll->pll_configuration.enable_ssc) {
+		pr_debug("SSC is enabled\n");
+
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1,
+			  regs->ssc_stepsize_low);
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1,
+			  regs->ssc_stepsize_high);
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1,
+			  regs->ssc_div_per_low);
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1,
+			  regs->ssc_div_per_high);
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1,
+			  regs->ssc_adjper_low);
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1,
+			  regs->ssc_adjper_high);
+		pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL,
+			  SSC_EN | regs->ssc_control);
+	}
+}
+
+static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll)
+{
+	void __iomem *base = pll->mmio;
+
+	pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE,
+		  0xba);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1,
+		  0x4c);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f);
+}
+
+static void dsi_pll_commit(struct dsi_pll_10nm *pll)
+{
+	void __iomem *base = pll->mmio;
+	struct dsi_pll_regs *reg = &pll->reg_setup;
+
+	pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1,
+		  reg->decimal_div_start);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1,
+		  reg->frac_div_start_low);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1,
+		  reg->frac_div_start_mid);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1,
+		  reg->frac_div_start_high);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10);
+	pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS,
+		  reg->pll_clock_inverters);
+}
+
+static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+
+	DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate,
+	    parent_rate);
+
+	pll_10nm->vco_current_rate = rate;
+	pll_10nm->vco_ref_clk_rate = parent_rate;
+
+	dsi_pll_setup_config(pll_10nm);
+
+	dsi_pll_calc_dec_frac(pll_10nm);
+
+	dsi_pll_calc_ssc(pll_10nm);
+
+	dsi_pll_commit(pll_10nm);
+
+	dsi_pll_config_hzindep_reg(pll_10nm);
+
+	dsi_pll_ssc_commit(pll_10nm);
+
+	/* flush, ensure all register writes are done*/
+	wmb();
+
+	return 0;
+}
+
+static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll)
+{
+	int rc;
+	u32 status = 0;
+	u32 const delay_us = 100;
+	u32 const timeout_us = 5000;
+
+	rc = readl_poll_timeout_atomic(pll->mmio +
+				       REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE,
+				       status,
+				       ((status & BIT(0)) > 0),
+				       delay_us,
+				       timeout_us);
+	if (rc)
+		pr_err("DSI PLL(%d) lock failed, status=0x%08x\n",
+		       pll->id, status);
+
+	return rc;
+}
+
+static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll)
+{
+	u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0);
+
+	pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0);
+	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0,
+		  data & ~BIT(5));
+	ndelay(250);
+}
+
+static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll)
+{
+	u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0);
+
+	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0,
+		  data | BIT(5));
+	pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0);
+	ndelay(250);
+}
+
+static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll)
+{
+	u32 data;
+
+	data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1,
+		  data & ~BIT(5));
+}
+
+static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll)
+{
+	u32 data;
+
+	data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1,
+		  data | BIT(5));
+}
+
+static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw)
+{
+	struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+	int rc;
+
+	dsi_pll_enable_pll_bias(pll_10nm);
+	if (pll_10nm->slave)
+		dsi_pll_enable_pll_bias(pll_10nm->slave);
+
+	/* Start PLL */
+	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL,
+		  0x01);
+
+	/*
+	 * ensure all PLL configurations are written prior to checking
+	 * for PLL lock.
+	 */
+	wmb();
+
+	/* Check for PLL lock */
+	rc = dsi_pll_10nm_lock_status(pll_10nm);
+	if (rc) {
+		pr_err("PLL(%d) lock failed\n", pll_10nm->id);
+		goto error;
+	}
+
+	pll->pll_on = true;
+
+	dsi_pll_enable_global_clk(pll_10nm);
+	if (pll_10nm->slave)
+		dsi_pll_enable_global_clk(pll_10nm->slave);
+
+	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL,
+		  0x01);
+	if (pll_10nm->slave)
+		pll_write(pll_10nm->slave->phy_cmn_mmio +
+			  REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01);
+
+error:
+	return rc;
+}
+
+static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll)
+{
+	pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0);
+	dsi_pll_disable_pll_bias(pll);
+}
+
+static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw)
+{
+	struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+
+	/*
+	 * To avoid any stray glitches while abruptly powering down the PLL
+	 * make sure to gate the clock using the clock enable bit before
+	 * powering down the PLL
+	 */
+	dsi_pll_disable_global_clk(pll_10nm);
+	pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0);
+	dsi_pll_disable_sub(pll_10nm);
+	if (pll_10nm->slave) {
+		dsi_pll_disable_global_clk(pll_10nm->slave);
+		dsi_pll_disable_sub(pll_10nm->slave);
+	}
+	/* flush, ensure all register writes are done */
+	wmb();
+	pll->pll_on = false;
+}
+
+static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+	void __iomem *base = pll_10nm->mmio;
+	u64 ref_clk = pll_10nm->vco_ref_clk_rate;
+	u64 vco_rate = 0x0;
+	u64 multiplier;
+	u32 frac;
+	u32 dec;
+	u64 pll_freq, tmp64;
+
+	dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1);
+	dec &= 0xff;
+
+	frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1);
+	frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) &
+		  0xff) << 8);
+	frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) &
+		  0x3) << 16);
+
+	/*
+	 * TODO:
+	 *	1. Assumes prescaler is disabled
+	 *	2. Multiplier is 2^18. it should be 2^(num_of_frac_bits)
+	 */
+	multiplier = 1 << 18;
+	pll_freq = dec * (ref_clk * 2);
+	tmp64 = (ref_clk * 2 * frac);
+	pll_freq += div_u64(tmp64, multiplier);
+
+	vco_rate = pll_freq;
+
+	DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
+	    pll_10nm->id, (unsigned long)vco_rate, dec, frac);
+
+	return (unsigned long)vco_rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_10nm_vco = {
+	.round_rate = msm_dsi_pll_helper_clk_round_rate,
+	.set_rate = dsi_pll_10nm_vco_set_rate,
+	.recalc_rate = dsi_pll_10nm_vco_recalc_rate,
+	.prepare = dsi_pll_10nm_vco_prepare,
+	.unprepare = dsi_pll_10nm_vco_unprepare,
+};
+
+/*
+ * PLL Callbacks
+ */
+
+static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll)
+{
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+	struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
+	void __iomem *phy_base = pll_10nm->phy_cmn_mmio;
+	u32 cmn_clk_cfg0, cmn_clk_cfg1;
+
+	cached->pll_out_div = pll_read(pll_10nm->mmio +
+				       REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
+	cached->pll_out_div &= 0x3;
+
+	cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0);
+	cached->bit_clk_div = cmn_clk_cfg0 & 0xf;
+	cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4;
+
+	cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+	cached->pll_mux = cmn_clk_cfg1 & 0x3;
+
+	DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
+	    pll_10nm->id, cached->pll_out_div, cached->bit_clk_div,
+	    cached->pix_clk_div, cached->pll_mux);
+}
+
+static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll)
+{
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+	struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
+	void __iomem *phy_base = pll_10nm->phy_cmn_mmio;
+	u32 val;
+
+	val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
+	val &= ~0x3;
+	val |= cached->pll_out_div;
+	pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val);
+
+	pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0,
+		  cached->bit_clk_div | (cached->pix_clk_div << 4));
+
+	val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+	val &= ~0x3;
+	val |= cached->pll_mux;
+	pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val);
+
+	DBG("DSI PLL%d", pll_10nm->id);
+
+	return 0;
+}
+
+static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll,
+				    enum msm_dsi_phy_usecase uc)
+{
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+	void __iomem *base = pll_10nm->phy_cmn_mmio;
+	u32 data = 0x0;	/* internal PLL */
+
+	DBG("DSI PLL%d", pll_10nm->id);
+
+	switch (uc) {
+	case MSM_DSI_PHY_STANDALONE:
+		break;
+	case MSM_DSI_PHY_MASTER:
+		pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX];
+		break;
+	case MSM_DSI_PHY_SLAVE:
+		data = 0x1; /* external PLL */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set PLL src */
+	pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2));
+
+	pll_10nm->uc = uc;
+
+	return 0;
+}
+
+static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll,
+				     struct clk **byte_clk_provider,
+				     struct clk **pixel_clk_provider)
+{
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+	struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data;
+
+	DBG("DSI PLL%d", pll_10nm->id);
+
+	if (byte_clk_provider)
+		*byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk;
+	if (pixel_clk_provider)
+		*pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk;
+
+	return 0;
+}
+
+static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll)
+{
+	struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
+
+	DBG("DSI PLL%d", pll_10nm->id);
+}
+
+/*
+ * The post dividers and mux clocks are created using the standard divider and
+ * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux
+ * state to follow the master PLL's divider/mux state. Therefore, we don't
+ * require special clock ops that also configure the slave PLL registers
+ */
+static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
+{
+	char clk_name[32], parent[32], vco_name[32];
+	char parent2[32], parent3[32], parent4[32];
+	struct clk_init_data vco_init = {
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.name = vco_name,
+		.flags = CLK_IGNORE_UNUSED,
+		.ops = &clk_ops_dsi_pll_10nm_vco,
+	};
+	struct device *dev = &pll_10nm->pdev->dev;
+	struct clk_hw **hws = pll_10nm->hws;
+	struct clk_hw_onecell_data *hw_data;
+	struct clk_hw *hw;
+	int num = 0;
+	int ret;
+
+	DBG("DSI%d", pll_10nm->id);
+
+	hw_data = devm_kzalloc(dev, sizeof(*hw_data) +
+			       NUM_PROVIDED_CLKS * sizeof(struct clk_hw *),
+			       GFP_KERNEL);
+	if (!hw_data)
+		return -ENOMEM;
+
+	snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id);
+	pll_10nm->base.clk_hw.init = &vco_init;
+
+	ret = clk_hw_register(dev, &pll_10nm->base.clk_hw);
+	if (ret)
+		return ret;
+
+	hws[num++] = &pll_10nm->base.clk_hw;
+
+	snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
+	snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id);
+
+	hw = clk_hw_register_divider(dev, clk_name,
+				     parent, CLK_SET_RATE_PARENT,
+				     pll_10nm->mmio +
+				     REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE,
+				     0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+
+	snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
+	snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
+
+	/* BIT CLK: DIV_CTRL_3_0 */
+	hw = clk_hw_register_divider(dev, clk_name, parent,
+				     CLK_SET_RATE_PARENT,
+				     pll_10nm->phy_cmn_mmio +
+				     REG_DSI_10nm_PHY_CMN_CLK_CFG0,
+				     0, 4, CLK_DIVIDER_ONE_BASED,
+				     &pll_10nm->postdiv_lock);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+
+	snprintf(clk_name, 32, "dsi%dpllbyte", pll_10nm->id);
+	snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
+
+	/* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
+	hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
+					  CLK_SET_RATE_PARENT, 1, 8);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+	hw_data->hws[DSI_BYTE_PLL_CLK] = hw;
+
+	snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id);
+	snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
+
+	hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
+					  0, 1, 2);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+
+	snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id);
+	snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
+
+	hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
+					  0, 1, 4);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+
+	snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id);
+	snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
+	snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id);
+	snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
+	snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id);
+
+	hw = clk_hw_register_mux(dev, clk_name,
+				 (const char *[]){
+				 parent, parent2, parent3, parent4
+				 }, 4, 0, pll_10nm->phy_cmn_mmio +
+				 REG_DSI_10nm_PHY_CMN_CLK_CFG1,
+				 0, 2, 0, NULL);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+
+	snprintf(clk_name, 32, "dsi%dpll", pll_10nm->id);
+	snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id);
+
+	/* PIX CLK DIV : DIV_CTRL_7_4*/
+	hw = clk_hw_register_divider(dev, clk_name, parent,
+				     0, pll_10nm->phy_cmn_mmio +
+					REG_DSI_10nm_PHY_CMN_CLK_CFG0,
+				     4, 4, CLK_DIVIDER_ONE_BASED,
+				     &pll_10nm->postdiv_lock);
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	hws[num++] = hw;
+	hw_data->hws[DSI_PIXEL_PLL_CLK] = hw;
+
+	pll_10nm->num_hws = num;
+
+	hw_data->num = NUM_PROVIDED_CLKS;
+	pll_10nm->hw_data = hw_data;
+
+	ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+				     pll_10nm->hw_data);
+	if (ret) {
+		dev_err(dev, "failed to register clk provider: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
+{
+	struct dsi_pll_10nm *pll_10nm;
+	struct msm_dsi_pll *pll;
+	int ret;
+
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL);
+	if (!pll_10nm)
+		return ERR_PTR(-ENOMEM);
+
+	DBG("DSI PLL%d", id);
+
+	pll_10nm->pdev = pdev;
+	pll_10nm->id = id;
+	pll_10nm_list[id] = pll_10nm;
+
+	pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
+	if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) {
+		dev_err(&pdev->dev, "failed to map CMN PHY base\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
+	if (IS_ERR_OR_NULL(pll_10nm->mmio)) {
+		dev_err(&pdev->dev, "failed to map PLL base\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pll = &pll_10nm->base;
+	pll->min_rate = 1000000000UL;
+	pll->max_rate = 3500000000UL;
+	pll->get_provider = dsi_pll_10nm_get_provider;
+	pll->destroy = dsi_pll_10nm_destroy;
+	pll->save_state = dsi_pll_10nm_save_state;
+	pll->restore_state = dsi_pll_10nm_restore_state;
+	pll->set_usecase = dsi_pll_10nm_set_usecase;
+
+	pll_10nm->vco_delay = 1;
+
+	ret = pll_10nm_register(pll_10nm);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
+		return ERR_PTR(ret);
+	}
+
+	/* TODO: Remove this when we have proper display handover support */
+	msm_dsi_pll_save_state(pll);
+
+	return pll;
+}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
index 6e767979aab3..3656155e3793 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
@@ -769,7 +769,7 @@ static int msm_hdmi_hdcp_auth_part1_key_exchange(struct hdmi_hdcp_ctrl *hdcp_ctr
 	if (rc) {
 		pr_err("%s: wait key and an ready failed\n", __func__);
 		return rc;
-	};
+	}
 
 	/* Read BCAPS and send to HDCP engine */
 	rc = msm_hdmi_hdcp_recv_bcaps(hdcp_ctrl);
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
deleted file mode 100644
index 576cea30d391..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
+++ /dev/null
@@ -1,1174 +0,0 @@
-#ifndef MDP4_XML
-#define MDP4_XML
-
-/* Autogenerated file, DO NOT EDIT manually!
-
-This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://github.com/freedreno/envytools/
-git clone https://github.com/freedreno/envytools.git
-
-The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
-
-Copyright (C) 2013-2017 by the following authors:
-- Rob Clark <robdclark@gmail.com> (robclark)
-- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice (including the
-next paragraph) shall be included in all copies or substantial
-portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-
-enum mdp4_pipe {
-	VG1 = 0,
-	VG2 = 1,
-	RGB1 = 2,
-	RGB2 = 3,
-	RGB3 = 4,
-	VG3 = 5,
-	VG4 = 6,
-};
-
-enum mdp4_mixer {
-	MIXER0 = 0,
-	MIXER1 = 1,
-	MIXER2 = 2,
-};
-
-enum mdp4_intf {
-	INTF_LCDC_DTV = 0,
-	INTF_DSI_VIDEO = 1,
-	INTF_DSI_CMD = 2,
-	INTF_EBI2_TV = 3,
-};
-
-enum mdp4_cursor_format {
-	CURSOR_ARGB = 1,
-	CURSOR_XRGB = 2,
-};
-
-enum mdp4_frame_format {
-	FRAME_LINEAR = 0,
-	FRAME_TILE_ARGB_4X4 = 1,
-	FRAME_TILE_YCBCR_420 = 2,
-};
-
-enum mdp4_scale_unit {
-	SCALE_FIR = 0,
-	SCALE_MN_PHASE = 1,
-	SCALE_PIXEL_RPT = 2,
-};
-
-enum mdp4_dma {
-	DMA_P = 0,
-	DMA_S = 1,
-	DMA_E = 2,
-};
-
-#define MDP4_IRQ_OVERLAY0_DONE					0x00000001
-#define MDP4_IRQ_OVERLAY1_DONE					0x00000002
-#define MDP4_IRQ_DMA_S_DONE					0x00000004
-#define MDP4_IRQ_DMA_E_DONE					0x00000008
-#define MDP4_IRQ_DMA_P_DONE					0x00000010
-#define MDP4_IRQ_VG1_HISTOGRAM					0x00000020
-#define MDP4_IRQ_VG2_HISTOGRAM					0x00000040
-#define MDP4_IRQ_PRIMARY_VSYNC					0x00000080
-#define MDP4_IRQ_PRIMARY_INTF_UDERRUN				0x00000100
-#define MDP4_IRQ_EXTERNAL_VSYNC					0x00000200
-#define MDP4_IRQ_EXTERNAL_INTF_UDERRUN				0x00000400
-#define MDP4_IRQ_PRIMARY_RDPTR					0x00000800
-#define MDP4_IRQ_DMA_P_HISTOGRAM				0x00020000
-#define MDP4_IRQ_DMA_S_HISTOGRAM				0x04000000
-#define MDP4_IRQ_OVERLAY2_DONE					0x40000000
-#define REG_MDP4_VERSION					0x00000000
-#define MDP4_VERSION_MINOR__MASK				0x00ff0000
-#define MDP4_VERSION_MINOR__SHIFT				16
-static inline uint32_t MDP4_VERSION_MINOR(uint32_t val)
-{
-	return ((val) << MDP4_VERSION_MINOR__SHIFT) & MDP4_VERSION_MINOR__MASK;
-}
-#define MDP4_VERSION_MAJOR__MASK				0xff000000
-#define MDP4_VERSION_MAJOR__SHIFT				24
-static inline uint32_t MDP4_VERSION_MAJOR(uint32_t val)
-{
-	return ((val) << MDP4_VERSION_MAJOR__SHIFT) & MDP4_VERSION_MAJOR__MASK;
-}
-
-#define REG_MDP4_OVLP0_KICK					0x00000004
-
-#define REG_MDP4_OVLP1_KICK					0x00000008
-
-#define REG_MDP4_OVLP2_KICK					0x000000d0
-
-#define REG_MDP4_DMA_P_KICK					0x0000000c
-
-#define REG_MDP4_DMA_S_KICK					0x00000010
-
-#define REG_MDP4_DMA_E_KICK					0x00000014
-
-#define REG_MDP4_DISP_STATUS					0x00000018
-
-#define REG_MDP4_DISP_INTF_SEL					0x00000038
-#define MDP4_DISP_INTF_SEL_PRIM__MASK				0x00000003
-#define MDP4_DISP_INTF_SEL_PRIM__SHIFT				0
-static inline uint32_t MDP4_DISP_INTF_SEL_PRIM(enum mdp4_intf val)
-{
-	return ((val) << MDP4_DISP_INTF_SEL_PRIM__SHIFT) & MDP4_DISP_INTF_SEL_PRIM__MASK;
-}
-#define MDP4_DISP_INTF_SEL_SEC__MASK				0x0000000c
-#define MDP4_DISP_INTF_SEL_SEC__SHIFT				2
-static inline uint32_t MDP4_DISP_INTF_SEL_SEC(enum mdp4_intf val)
-{
-	return ((val) << MDP4_DISP_INTF_SEL_SEC__SHIFT) & MDP4_DISP_INTF_SEL_SEC__MASK;
-}
-#define MDP4_DISP_INTF_SEL_EXT__MASK				0x00000030
-#define MDP4_DISP_INTF_SEL_EXT__SHIFT				4
-static inline uint32_t MDP4_DISP_INTF_SEL_EXT(enum mdp4_intf val)
-{
-	return ((val) << MDP4_DISP_INTF_SEL_EXT__SHIFT) & MDP4_DISP_INTF_SEL_EXT__MASK;
-}
-#define MDP4_DISP_INTF_SEL_DSI_VIDEO				0x00000040
-#define MDP4_DISP_INTF_SEL_DSI_CMD				0x00000080
-
-#define REG_MDP4_RESET_STATUS					0x0000003c
-
-#define REG_MDP4_READ_CNFG					0x0000004c
-
-#define REG_MDP4_INTR_ENABLE					0x00000050
-
-#define REG_MDP4_INTR_STATUS					0x00000054
-
-#define REG_MDP4_INTR_CLEAR					0x00000058
-
-#define REG_MDP4_EBI2_LCD0					0x00000060
-
-#define REG_MDP4_EBI2_LCD1					0x00000064
-
-#define REG_MDP4_PORTMAP_MODE					0x00000070
-
-#define REG_MDP4_CS_CONTROLLER0					0x000000c0
-
-#define REG_MDP4_CS_CONTROLLER1					0x000000c4
-
-#define REG_MDP4_LAYERMIXER2_IN_CFG				0x000100f0
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK			0x00000007
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT			0
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE0_MIXER1			0x00000008
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK			0x00000070
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT			4
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE1_MIXER1			0x00000080
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK			0x00000700
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT			8
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE2_MIXER1			0x00000800
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK			0x00007000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT			12
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE3_MIXER1			0x00008000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK			0x00070000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT			16
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE4_MIXER1			0x00080000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK			0x00700000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT			20
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE5_MIXER1			0x00800000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK			0x07000000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT			24
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE6_MIXER1			0x08000000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK			0x70000000
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT			28
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK;
-}
-#define MDP4_LAYERMIXER2_IN_CFG_PIPE7_MIXER1			0x80000000
-
-#define REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD		0x000100fc
-
-#define REG_MDP4_LAYERMIXER_IN_CFG				0x00010100
-#define MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK			0x00000007
-#define MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT			0
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1			0x00000008
-#define MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK			0x00000070
-#define MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT			4
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1			0x00000080
-#define MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK			0x00000700
-#define MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT			8
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1			0x00000800
-#define MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK			0x00007000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT			12
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1			0x00008000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK			0x00070000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT			16
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1			0x00080000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK			0x00700000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT			20
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1			0x00800000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK			0x07000000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT			24
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1			0x08000000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK			0x70000000
-#define MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT			28
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK;
-}
-#define MDP4_LAYERMIXER_IN_CFG_PIPE7_MIXER1			0x80000000
-
-#define REG_MDP4_VG2_SRC_FORMAT					0x00030050
-
-#define REG_MDP4_VG2_CONST_COLOR				0x00031008
-
-#define REG_MDP4_OVERLAY_FLUSH					0x00018000
-#define MDP4_OVERLAY_FLUSH_OVLP0				0x00000001
-#define MDP4_OVERLAY_FLUSH_OVLP1				0x00000002
-#define MDP4_OVERLAY_FLUSH_VG1					0x00000004
-#define MDP4_OVERLAY_FLUSH_VG2					0x00000008
-#define MDP4_OVERLAY_FLUSH_RGB1					0x00000010
-#define MDP4_OVERLAY_FLUSH_RGB2					0x00000020
-
-static inline uint32_t __offset_OVLP(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return 0x00010000;
-		case 1: return 0x00018000;
-		case 2: return 0x00088000;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP4_OVLP(uint32_t i0) { return 0x00000000 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_CFG(uint32_t i0) { return 0x00000004 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_SIZE(uint32_t i0) { return 0x00000008 + __offset_OVLP(i0); }
-#define MDP4_OVLP_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP4_OVLP_SIZE_HEIGHT__SHIFT				16
-static inline uint32_t MDP4_OVLP_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_OVLP_SIZE_HEIGHT__SHIFT) & MDP4_OVLP_SIZE_HEIGHT__MASK;
-}
-#define MDP4_OVLP_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP4_OVLP_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP4_OVLP_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_OVLP_SIZE_WIDTH__SHIFT) & MDP4_OVLP_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP4_OVLP_BASE(uint32_t i0) { return 0x0000000c + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_STRIDE(uint32_t i0) { return 0x00000010 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_OPMODE(uint32_t i0) { return 0x00000014 + __offset_OVLP(i0); }
-
-static inline uint32_t __offset_STAGE(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return 0x00000104;
-		case 1: return 0x00000124;
-		case 2: return 0x00000144;
-		case 3: return 0x00000160;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP4_OVLP_STAGE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_OP(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-#define MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK			0x00000003
-#define MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT			0
-static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp_alpha_type val)
-{
-	return ((val) << MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK;
-}
-#define MDP4_OVLP_STAGE_OP_FG_INV_ALPHA				0x00000004
-#define MDP4_OVLP_STAGE_OP_FG_MOD_ALPHA				0x00000008
-#define MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK			0x00000030
-#define MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT			4
-static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp_alpha_type val)
-{
-	return ((val) << MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK;
-}
-#define MDP4_OVLP_STAGE_OP_BG_INV_ALPHA				0x00000040
-#define MDP4_OVLP_STAGE_OP_BG_MOD_ALPHA				0x00000080
-#define MDP4_OVLP_STAGE_OP_FG_TRANSP				0x00000100
-#define MDP4_OVLP_STAGE_OP_BG_TRANSP				0x00000200
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_OVLP(i0) + __offset_STAGE(i1); }
-
-static inline uint32_t __offset_STAGE_CO3(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return 0x00001004;
-		case 1: return 0x00001404;
-		case 2: return 0x00001804;
-		case 3: return 0x00001b84;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP4_OVLP_STAGE_CO3(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE_CO3(i1); }
-
-static inline uint32_t REG_MDP4_OVLP_STAGE_CO3_SEL(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE_CO3(i1); }
-#define MDP4_OVLP_STAGE_CO3_SEL_FG_ALPHA			0x00000001
-
-static inline uint32_t REG_MDP4_OVLP_TRANSP_LOW0(uint32_t i0) { return 0x00000180 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_TRANSP_LOW1(uint32_t i0) { return 0x00000184 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_TRANSP_HIGH0(uint32_t i0) { return 0x00000188 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_TRANSP_HIGH1(uint32_t i0) { return 0x0000018c + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_CONFIG(uint32_t i0) { return 0x00000200 + __offset_OVLP(i0); }
-
-static inline uint32_t REG_MDP4_OVLP_CSC(uint32_t i0) { return 0x00002000 + __offset_OVLP(i0); }
-
-
-static inline uint32_t REG_MDP4_OVLP_CSC_MV(uint32_t i0, uint32_t i1) { return 0x00002400 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_MV_VAL(uint32_t i0, uint32_t i1) { return 0x00002400 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_PRE_BV(uint32_t i0, uint32_t i1) { return 0x00002500 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_PRE_BV_VAL(uint32_t i0, uint32_t i1) { return 0x00002500 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_POST_BV(uint32_t i0, uint32_t i1) { return 0x00002580 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_POST_BV_VAL(uint32_t i0, uint32_t i1) { return 0x00002580 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_PRE_LV(uint32_t i0, uint32_t i1) { return 0x00002600 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_PRE_LV_VAL(uint32_t i0, uint32_t i1) { return 0x00002600 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_POST_LV(uint32_t i0, uint32_t i1) { return 0x00002680 + __offset_OVLP(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_OVLP_CSC_POST_LV_VAL(uint32_t i0, uint32_t i1) { return 0x00002680 + __offset_OVLP(i0) + 0x4*i1; }
-
-#define REG_MDP4_DMA_P_OP_MODE					0x00090070
-
-static inline uint32_t REG_MDP4_LUTN(uint32_t i0) { return 0x00094800 + 0x400*i0; }
-
-static inline uint32_t REG_MDP4_LUTN_LUT(uint32_t i0, uint32_t i1) { return 0x00094800 + 0x400*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_LUTN_LUT_VAL(uint32_t i0, uint32_t i1) { return 0x00094800 + 0x400*i0 + 0x4*i1; }
-
-#define REG_MDP4_DMA_S_OP_MODE					0x000a0028
-
-static inline uint32_t REG_MDP4_DMA_E_QUANT(uint32_t i0) { return 0x000b0070 + 0x4*i0; }
-
-static inline uint32_t __offset_DMA(enum mdp4_dma idx)
-{
-	switch (idx) {
-		case DMA_P: return 0x00090000;
-		case DMA_S: return 0x000a0000;
-		case DMA_E: return 0x000b0000;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP4_DMA(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_CONFIG(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); }
-#define MDP4_DMA_CONFIG_G_BPC__MASK				0x00000003
-#define MDP4_DMA_CONFIG_G_BPC__SHIFT				0
-static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP4_DMA_CONFIG_G_BPC__SHIFT) & MDP4_DMA_CONFIG_G_BPC__MASK;
-}
-#define MDP4_DMA_CONFIG_B_BPC__MASK				0x0000000c
-#define MDP4_DMA_CONFIG_B_BPC__SHIFT				2
-static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP4_DMA_CONFIG_B_BPC__SHIFT) & MDP4_DMA_CONFIG_B_BPC__MASK;
-}
-#define MDP4_DMA_CONFIG_R_BPC__MASK				0x00000030
-#define MDP4_DMA_CONFIG_R_BPC__SHIFT				4
-static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP4_DMA_CONFIG_R_BPC__SHIFT) & MDP4_DMA_CONFIG_R_BPC__MASK;
-}
-#define MDP4_DMA_CONFIG_PACK_ALIGN_MSB				0x00000080
-#define MDP4_DMA_CONFIG_PACK__MASK				0x0000ff00
-#define MDP4_DMA_CONFIG_PACK__SHIFT				8
-static inline uint32_t MDP4_DMA_CONFIG_PACK(uint32_t val)
-{
-	return ((val) << MDP4_DMA_CONFIG_PACK__SHIFT) & MDP4_DMA_CONFIG_PACK__MASK;
-}
-#define MDP4_DMA_CONFIG_DEFLKR_EN				0x01000000
-#define MDP4_DMA_CONFIG_DITHER_EN				0x01000000
-
-static inline uint32_t REG_MDP4_DMA_SRC_SIZE(enum mdp4_dma i0) { return 0x00000004 + __offset_DMA(i0); }
-#define MDP4_DMA_SRC_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP4_DMA_SRC_SIZE_HEIGHT__SHIFT				16
-static inline uint32_t MDP4_DMA_SRC_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_DMA_SRC_SIZE_HEIGHT__SHIFT) & MDP4_DMA_SRC_SIZE_HEIGHT__MASK;
-}
-#define MDP4_DMA_SRC_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP4_DMA_SRC_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP4_DMA_SRC_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_DMA_SRC_SIZE_WIDTH__SHIFT) & MDP4_DMA_SRC_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP4_DMA_SRC_BASE(enum mdp4_dma i0) { return 0x00000008 + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_SRC_STRIDE(enum mdp4_dma i0) { return 0x0000000c + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_DST_SIZE(enum mdp4_dma i0) { return 0x00000010 + __offset_DMA(i0); }
-#define MDP4_DMA_DST_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP4_DMA_DST_SIZE_HEIGHT__SHIFT				16
-static inline uint32_t MDP4_DMA_DST_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_DMA_DST_SIZE_HEIGHT__SHIFT) & MDP4_DMA_DST_SIZE_HEIGHT__MASK;
-}
-#define MDP4_DMA_DST_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP4_DMA_DST_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP4_DMA_DST_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_DMA_DST_SIZE_WIDTH__SHIFT) & MDP4_DMA_DST_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP4_DMA_CURSOR_SIZE(enum mdp4_dma i0) { return 0x00000044 + __offset_DMA(i0); }
-#define MDP4_DMA_CURSOR_SIZE_WIDTH__MASK			0x0000007f
-#define MDP4_DMA_CURSOR_SIZE_WIDTH__SHIFT			0
-static inline uint32_t MDP4_DMA_CURSOR_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_DMA_CURSOR_SIZE_WIDTH__SHIFT) & MDP4_DMA_CURSOR_SIZE_WIDTH__MASK;
-}
-#define MDP4_DMA_CURSOR_SIZE_HEIGHT__MASK			0x007f0000
-#define MDP4_DMA_CURSOR_SIZE_HEIGHT__SHIFT			16
-static inline uint32_t MDP4_DMA_CURSOR_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_DMA_CURSOR_SIZE_HEIGHT__SHIFT) & MDP4_DMA_CURSOR_SIZE_HEIGHT__MASK;
-}
-
-static inline uint32_t REG_MDP4_DMA_CURSOR_BASE(enum mdp4_dma i0) { return 0x00000048 + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_CURSOR_POS(enum mdp4_dma i0) { return 0x0000004c + __offset_DMA(i0); }
-#define MDP4_DMA_CURSOR_POS_X__MASK				0x0000ffff
-#define MDP4_DMA_CURSOR_POS_X__SHIFT				0
-static inline uint32_t MDP4_DMA_CURSOR_POS_X(uint32_t val)
-{
-	return ((val) << MDP4_DMA_CURSOR_POS_X__SHIFT) & MDP4_DMA_CURSOR_POS_X__MASK;
-}
-#define MDP4_DMA_CURSOR_POS_Y__MASK				0xffff0000
-#define MDP4_DMA_CURSOR_POS_Y__SHIFT				16
-static inline uint32_t MDP4_DMA_CURSOR_POS_Y(uint32_t val)
-{
-	return ((val) << MDP4_DMA_CURSOR_POS_Y__SHIFT) & MDP4_DMA_CURSOR_POS_Y__MASK;
-}
-
-static inline uint32_t REG_MDP4_DMA_CURSOR_BLEND_CONFIG(enum mdp4_dma i0) { return 0x00000060 + __offset_DMA(i0); }
-#define MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN			0x00000001
-#define MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__MASK		0x00000006
-#define MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__SHIFT		1
-static inline uint32_t MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(enum mdp4_cursor_format val)
-{
-	return ((val) << MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__SHIFT) & MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT__MASK;
-}
-#define MDP4_DMA_CURSOR_BLEND_CONFIG_TRANSP_EN			0x00000008
-
-static inline uint32_t REG_MDP4_DMA_CURSOR_BLEND_PARAM(enum mdp4_dma i0) { return 0x00000064 + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_BLEND_TRANS_LOW(enum mdp4_dma i0) { return 0x00000068 + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_BLEND_TRANS_HIGH(enum mdp4_dma i0) { return 0x0000006c + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_FETCH_CONFIG(enum mdp4_dma i0) { return 0x00001004 + __offset_DMA(i0); }
-
-static inline uint32_t REG_MDP4_DMA_CSC(enum mdp4_dma i0) { return 0x00003000 + __offset_DMA(i0); }
-
-
-static inline uint32_t REG_MDP4_DMA_CSC_MV(enum mdp4_dma i0, uint32_t i1) { return 0x00003400 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_MV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003400 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_PRE_BV(enum mdp4_dma i0, uint32_t i1) { return 0x00003500 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_PRE_BV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003500 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_POST_BV(enum mdp4_dma i0, uint32_t i1) { return 0x00003580 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_POST_BV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003580 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_PRE_LV(enum mdp4_dma i0, uint32_t i1) { return 0x00003600 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_PRE_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003600 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_POST_LV(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_DMA_CSC_POST_LV_VAL(enum mdp4_dma i0, uint32_t i1) { return 0x00003680 + __offset_DMA(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_SRC_SIZE(enum mdp4_pipe i0) { return 0x00020000 + 0x10000*i0; }
-#define MDP4_PIPE_SRC_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT			16
-static inline uint32_t MDP4_PIPE_SRC_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_SRC_SIZE_HEIGHT__MASK;
-}
-#define MDP4_PIPE_SRC_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP4_PIPE_SRC_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SRC_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_SRC_XY(enum mdp4_pipe i0) { return 0x00020004 + 0x10000*i0; }
-#define MDP4_PIPE_SRC_XY_Y__MASK				0xffff0000
-#define MDP4_PIPE_SRC_XY_Y__SHIFT				16
-static inline uint32_t MDP4_PIPE_SRC_XY_Y(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_XY_Y__SHIFT) & MDP4_PIPE_SRC_XY_Y__MASK;
-}
-#define MDP4_PIPE_SRC_XY_X__MASK				0x0000ffff
-#define MDP4_PIPE_SRC_XY_X__SHIFT				0
-static inline uint32_t MDP4_PIPE_SRC_XY_X(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_XY_X__SHIFT) & MDP4_PIPE_SRC_XY_X__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_DST_SIZE(enum mdp4_pipe i0) { return 0x00020008 + 0x10000*i0; }
-#define MDP4_PIPE_DST_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT			16
-static inline uint32_t MDP4_PIPE_DST_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_DST_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_DST_SIZE_HEIGHT__MASK;
-}
-#define MDP4_PIPE_DST_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP4_PIPE_DST_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP4_PIPE_DST_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_DST_SIZE_WIDTH__SHIFT) & MDP4_PIPE_DST_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_DST_XY(enum mdp4_pipe i0) { return 0x0002000c + 0x10000*i0; }
-#define MDP4_PIPE_DST_XY_Y__MASK				0xffff0000
-#define MDP4_PIPE_DST_XY_Y__SHIFT				16
-static inline uint32_t MDP4_PIPE_DST_XY_Y(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_DST_XY_Y__SHIFT) & MDP4_PIPE_DST_XY_Y__MASK;
-}
-#define MDP4_PIPE_DST_XY_X__MASK				0x0000ffff
-#define MDP4_PIPE_DST_XY_X__SHIFT				0
-static inline uint32_t MDP4_PIPE_DST_XY_X(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_DST_XY_X__SHIFT) & MDP4_PIPE_DST_XY_X__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_SRCP0_BASE(enum mdp4_pipe i0) { return 0x00020010 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mdp4_pipe i0) { return 0x00020014 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mdp4_pipe i0) { return 0x00020018 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_SRCP3_BASE(enum mdp4_pipe i0) { return 0x0002001c + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mdp4_pipe i0) { return 0x00020040 + 0x10000*i0; }
-#define MDP4_PIPE_SRC_STRIDE_A_P0__MASK				0x0000ffff
-#define MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT			0
-static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P0(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P0__MASK;
-}
-#define MDP4_PIPE_SRC_STRIDE_A_P1__MASK				0xffff0000
-#define MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT			16
-static inline uint32_t MDP4_PIPE_SRC_STRIDE_A_P1(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP4_PIPE_SRC_STRIDE_A_P1__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_B(enum mdp4_pipe i0) { return 0x00020044 + 0x10000*i0; }
-#define MDP4_PIPE_SRC_STRIDE_B_P2__MASK				0x0000ffff
-#define MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT			0
-static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P2(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P2__MASK;
-}
-#define MDP4_PIPE_SRC_STRIDE_B_P3__MASK				0xffff0000
-#define MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT			16
-static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P3(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P3__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_SSTILE_FRAME_SIZE(enum mdp4_pipe i0) { return 0x00020048 + 0x10000*i0; }
-#define MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__MASK		0xffff0000
-#define MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__SHIFT		16
-static inline uint32_t MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__MASK;
-}
-#define MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__MASK			0x0000ffff
-#define MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__SHIFT		0
-static inline uint32_t MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; }
-#define MDP4_PIPE_SRC_FORMAT_G_BPC__MASK			0x00000003
-#define MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT			0
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_G_BPC__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_B_BPC__MASK			0x0000000c
-#define MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT			2
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_B_BPC__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_R_BPC__MASK			0x00000030
-#define MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT			4
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_R_BPC__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_A_BPC__MASK			0x000000c0
-#define MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT			6
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_A_BPC__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE			0x00000100
-#define MDP4_PIPE_SRC_FORMAT_CPP__MASK				0x00000600
-#define MDP4_PIPE_SRC_FORMAT_CPP__SHIFT				9
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_CPP(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CPP__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_ROTATED_90				0x00001000
-#define MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK			0x00006000
-#define MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT		13
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000
-#define MDP4_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000
-#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK			0x00180000
-#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT		19
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT) & MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_SOLID_FILL				0x00400000
-#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK			0x0c000000
-#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT			26
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
-}
-#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK			0x60000000
-#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT		29
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(enum mdp4_frame_format val)
-{
-	return ((val) << MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT) & MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mdp4_pipe i0) { return 0x00020054 + 0x10000*i0; }
-#define MDP4_PIPE_SRC_UNPACK_ELEM0__MASK			0x000000ff
-#define MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT			0
-static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM0(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM0__MASK;
-}
-#define MDP4_PIPE_SRC_UNPACK_ELEM1__MASK			0x0000ff00
-#define MDP4_PIPE_SRC_UNPACK_ELEM1__SHIFT			8
-static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM1(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM1__MASK;
-}
-#define MDP4_PIPE_SRC_UNPACK_ELEM2__MASK			0x00ff0000
-#define MDP4_PIPE_SRC_UNPACK_ELEM2__SHIFT			16
-static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM2(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM2__MASK;
-}
-#define MDP4_PIPE_SRC_UNPACK_ELEM3__MASK			0xff000000
-#define MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT			24
-static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
-{
-	return ((val) << MDP4_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP4_PIPE_SRC_UNPACK_ELEM3__MASK;
-}
-
-static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mdp4_pipe i0) { return 0x00020058 + 0x10000*i0; }
-#define MDP4_PIPE_OP_MODE_SCALEX_EN				0x00000001
-#define MDP4_PIPE_OP_MODE_SCALEY_EN				0x00000002
-#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK			0x0000000c
-#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT		2
-static inline uint32_t MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(enum mdp4_scale_unit val)
-{
-	return ((val) << MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK;
-}
-#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK			0x00000030
-#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT		4
-static inline uint32_t MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(enum mdp4_scale_unit val)
-{
-	return ((val) << MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK;
-}
-#define MDP4_PIPE_OP_MODE_SRC_YCBCR				0x00000200
-#define MDP4_PIPE_OP_MODE_DST_YCBCR				0x00000400
-#define MDP4_PIPE_OP_MODE_CSC_EN				0x00000800
-#define MDP4_PIPE_OP_MODE_FLIP_LR				0x00002000
-#define MDP4_PIPE_OP_MODE_FLIP_UD				0x00004000
-#define MDP4_PIPE_OP_MODE_DITHER_EN				0x00008000
-#define MDP4_PIPE_OP_MODE_IGC_LUT_EN				0x00010000
-#define MDP4_PIPE_OP_MODE_DEINT_EN				0x00040000
-#define MDP4_PIPE_OP_MODE_DEINT_ODD_REF				0x00080000
-
-static inline uint32_t REG_MDP4_PIPE_PHASEX_STEP(enum mdp4_pipe i0) { return 0x0002005c + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_PHASEY_STEP(enum mdp4_pipe i0) { return 0x00020060 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_FETCH_CONFIG(enum mdp4_pipe i0) { return 0x00021004 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_SOLID_COLOR(enum mdp4_pipe i0) { return 0x00021008 + 0x10000*i0; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC(enum mdp4_pipe i0) { return 0x00024000 + 0x10000*i0; }
-
-
-static inline uint32_t REG_MDP4_PIPE_CSC_MV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_MV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024400 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024500 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_BV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024580 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_PRE_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024600 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
-
-static inline uint32_t REG_MDP4_PIPE_CSC_POST_LV_VAL(enum mdp4_pipe i0, uint32_t i1) { return 0x00024680 + 0x10000*i0 + 0x4*i1; }
-
-#define REG_MDP4_LCDC						0x000c0000
-
-#define REG_MDP4_LCDC_ENABLE					0x000c0000
-
-#define REG_MDP4_LCDC_HSYNC_CTRL				0x000c0004
-#define MDP4_LCDC_HSYNC_CTRL_PULSEW__MASK			0x0000ffff
-#define MDP4_LCDC_HSYNC_CTRL_PULSEW__SHIFT			0
-static inline uint32_t MDP4_LCDC_HSYNC_CTRL_PULSEW(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_LCDC_HSYNC_CTRL_PULSEW__MASK;
-}
-#define MDP4_LCDC_HSYNC_CTRL_PERIOD__MASK			0xffff0000
-#define MDP4_LCDC_HSYNC_CTRL_PERIOD__SHIFT			16
-static inline uint32_t MDP4_LCDC_HSYNC_CTRL_PERIOD(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_LCDC_HSYNC_CTRL_PERIOD__MASK;
-}
-
-#define REG_MDP4_LCDC_VSYNC_PERIOD				0x000c0008
-
-#define REG_MDP4_LCDC_VSYNC_LEN					0x000c000c
-
-#define REG_MDP4_LCDC_DISPLAY_HCTRL				0x000c0010
-#define MDP4_LCDC_DISPLAY_HCTRL_START__MASK			0x0000ffff
-#define MDP4_LCDC_DISPLAY_HCTRL_START__SHIFT			0
-static inline uint32_t MDP4_LCDC_DISPLAY_HCTRL_START(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_DISPLAY_HCTRL_START__SHIFT) & MDP4_LCDC_DISPLAY_HCTRL_START__MASK;
-}
-#define MDP4_LCDC_DISPLAY_HCTRL_END__MASK			0xffff0000
-#define MDP4_LCDC_DISPLAY_HCTRL_END__SHIFT			16
-static inline uint32_t MDP4_LCDC_DISPLAY_HCTRL_END(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_DISPLAY_HCTRL_END__SHIFT) & MDP4_LCDC_DISPLAY_HCTRL_END__MASK;
-}
-
-#define REG_MDP4_LCDC_DISPLAY_VSTART				0x000c0014
-
-#define REG_MDP4_LCDC_DISPLAY_VEND				0x000c0018
-
-#define REG_MDP4_LCDC_ACTIVE_HCTL				0x000c001c
-#define MDP4_LCDC_ACTIVE_HCTL_START__MASK			0x00007fff
-#define MDP4_LCDC_ACTIVE_HCTL_START__SHIFT			0
-static inline uint32_t MDP4_LCDC_ACTIVE_HCTL_START(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_ACTIVE_HCTL_START__SHIFT) & MDP4_LCDC_ACTIVE_HCTL_START__MASK;
-}
-#define MDP4_LCDC_ACTIVE_HCTL_END__MASK				0x7fff0000
-#define MDP4_LCDC_ACTIVE_HCTL_END__SHIFT			16
-static inline uint32_t MDP4_LCDC_ACTIVE_HCTL_END(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_ACTIVE_HCTL_END__SHIFT) & MDP4_LCDC_ACTIVE_HCTL_END__MASK;
-}
-#define MDP4_LCDC_ACTIVE_HCTL_ACTIVE_START_X			0x80000000
-
-#define REG_MDP4_LCDC_ACTIVE_VSTART				0x000c0020
-
-#define REG_MDP4_LCDC_ACTIVE_VEND				0x000c0024
-
-#define REG_MDP4_LCDC_BORDER_CLR				0x000c0028
-
-#define REG_MDP4_LCDC_UNDERFLOW_CLR				0x000c002c
-#define MDP4_LCDC_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff
-#define MDP4_LCDC_UNDERFLOW_CLR_COLOR__SHIFT			0
-static inline uint32_t MDP4_LCDC_UNDERFLOW_CLR_COLOR(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_LCDC_UNDERFLOW_CLR_COLOR__MASK;
-}
-#define MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000
-
-#define REG_MDP4_LCDC_HSYNC_SKEW				0x000c0030
-
-#define REG_MDP4_LCDC_TEST_CNTL					0x000c0034
-
-#define REG_MDP4_LCDC_CTRL_POLARITY				0x000c0038
-#define MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW			0x00000001
-#define MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW			0x00000002
-#define MDP4_LCDC_CTRL_POLARITY_DATA_EN_LOW			0x00000004
-
-#define REG_MDP4_LCDC_LVDS_INTF_CTL				0x000c2000
-#define MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL			0x00000004
-#define MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT				0x00000008
-#define MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP				0x00000010
-#define MDP4_LCDC_LVDS_INTF_CTL_CH1_RES_BIT			0x00000020
-#define MDP4_LCDC_LVDS_INTF_CTL_CH2_RES_BIT			0x00000040
-#define MDP4_LCDC_LVDS_INTF_CTL_ENABLE				0x00000080
-#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN		0x00000100
-#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN		0x00000200
-#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN		0x00000400
-#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN		0x00000800
-#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN		0x00001000
-#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN		0x00002000
-#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN		0x00004000
-#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN		0x00008000
-#define MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN			0x00010000
-#define MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN			0x00020000
-
-static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
-
-static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK		0x000000ff
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT		0
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK;
-}
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK		0x0000ff00
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT		8
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK;
-}
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK		0x00ff0000
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT		16
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK;
-}
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK		0xff000000
-#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT		24
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK;
-}
-
-static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(uint32_t i0) { return 0x000c2018 + 0x8*i0; }
-#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK		0x000000ff
-#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT		0
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK;
-}
-#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK		0x0000ff00
-#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT		8
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK;
-}
-#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK		0x00ff0000
-#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT		16
-static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(uint32_t val)
-{
-	return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK;
-}
-
-#define REG_MDP4_LCDC_LVDS_PHY_RESET				0x000c2034
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_0				0x000c3000
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_1				0x000c3004
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_2				0x000c3008
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_3				0x000c300c
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_5				0x000c3014
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_6				0x000c3018
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_7				0x000c301c
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_8				0x000c3020
-
-#define REG_MDP4_LVDS_PHY_PLL_CTRL_9				0x000c3024
-
-#define REG_MDP4_LVDS_PHY_PLL_LOCKED				0x000c3080
-
-#define REG_MDP4_LVDS_PHY_CFG2					0x000c3108
-
-#define REG_MDP4_LVDS_PHY_CFG0					0x000c3100
-#define MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE			0x00000010
-#define MDP4_LVDS_PHY_CFG0_CHANNEL0				0x00000040
-#define MDP4_LVDS_PHY_CFG0_CHANNEL1				0x00000080
-
-#define REG_MDP4_DTV						0x000d0000
-
-#define REG_MDP4_DTV_ENABLE					0x000d0000
-
-#define REG_MDP4_DTV_HSYNC_CTRL					0x000d0004
-#define MDP4_DTV_HSYNC_CTRL_PULSEW__MASK			0x0000ffff
-#define MDP4_DTV_HSYNC_CTRL_PULSEW__SHIFT			0
-static inline uint32_t MDP4_DTV_HSYNC_CTRL_PULSEW(uint32_t val)
-{
-	return ((val) << MDP4_DTV_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_DTV_HSYNC_CTRL_PULSEW__MASK;
-}
-#define MDP4_DTV_HSYNC_CTRL_PERIOD__MASK			0xffff0000
-#define MDP4_DTV_HSYNC_CTRL_PERIOD__SHIFT			16
-static inline uint32_t MDP4_DTV_HSYNC_CTRL_PERIOD(uint32_t val)
-{
-	return ((val) << MDP4_DTV_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_DTV_HSYNC_CTRL_PERIOD__MASK;
-}
-
-#define REG_MDP4_DTV_VSYNC_PERIOD				0x000d0008
-
-#define REG_MDP4_DTV_VSYNC_LEN					0x000d000c
-
-#define REG_MDP4_DTV_DISPLAY_HCTRL				0x000d0018
-#define MDP4_DTV_DISPLAY_HCTRL_START__MASK			0x0000ffff
-#define MDP4_DTV_DISPLAY_HCTRL_START__SHIFT			0
-static inline uint32_t MDP4_DTV_DISPLAY_HCTRL_START(uint32_t val)
-{
-	return ((val) << MDP4_DTV_DISPLAY_HCTRL_START__SHIFT) & MDP4_DTV_DISPLAY_HCTRL_START__MASK;
-}
-#define MDP4_DTV_DISPLAY_HCTRL_END__MASK			0xffff0000
-#define MDP4_DTV_DISPLAY_HCTRL_END__SHIFT			16
-static inline uint32_t MDP4_DTV_DISPLAY_HCTRL_END(uint32_t val)
-{
-	return ((val) << MDP4_DTV_DISPLAY_HCTRL_END__SHIFT) & MDP4_DTV_DISPLAY_HCTRL_END__MASK;
-}
-
-#define REG_MDP4_DTV_DISPLAY_VSTART				0x000d001c
-
-#define REG_MDP4_DTV_DISPLAY_VEND				0x000d0020
-
-#define REG_MDP4_DTV_ACTIVE_HCTL				0x000d002c
-#define MDP4_DTV_ACTIVE_HCTL_START__MASK			0x00007fff
-#define MDP4_DTV_ACTIVE_HCTL_START__SHIFT			0
-static inline uint32_t MDP4_DTV_ACTIVE_HCTL_START(uint32_t val)
-{
-	return ((val) << MDP4_DTV_ACTIVE_HCTL_START__SHIFT) & MDP4_DTV_ACTIVE_HCTL_START__MASK;
-}
-#define MDP4_DTV_ACTIVE_HCTL_END__MASK				0x7fff0000
-#define MDP4_DTV_ACTIVE_HCTL_END__SHIFT				16
-static inline uint32_t MDP4_DTV_ACTIVE_HCTL_END(uint32_t val)
-{
-	return ((val) << MDP4_DTV_ACTIVE_HCTL_END__SHIFT) & MDP4_DTV_ACTIVE_HCTL_END__MASK;
-}
-#define MDP4_DTV_ACTIVE_HCTL_ACTIVE_START_X			0x80000000
-
-#define REG_MDP4_DTV_ACTIVE_VSTART				0x000d0030
-
-#define REG_MDP4_DTV_ACTIVE_VEND				0x000d0038
-
-#define REG_MDP4_DTV_BORDER_CLR					0x000d0040
-
-#define REG_MDP4_DTV_UNDERFLOW_CLR				0x000d0044
-#define MDP4_DTV_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff
-#define MDP4_DTV_UNDERFLOW_CLR_COLOR__SHIFT			0
-static inline uint32_t MDP4_DTV_UNDERFLOW_CLR_COLOR(uint32_t val)
-{
-	return ((val) << MDP4_DTV_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_DTV_UNDERFLOW_CLR_COLOR__MASK;
-}
-#define MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000
-
-#define REG_MDP4_DTV_HSYNC_SKEW					0x000d0048
-
-#define REG_MDP4_DTV_TEST_CNTL					0x000d004c
-
-#define REG_MDP4_DTV_CTRL_POLARITY				0x000d0050
-#define MDP4_DTV_CTRL_POLARITY_HSYNC_LOW			0x00000001
-#define MDP4_DTV_CTRL_POLARITY_VSYNC_LOW			0x00000002
-#define MDP4_DTV_CTRL_POLARITY_DATA_EN_LOW			0x00000004
-
-#define REG_MDP4_DSI						0x000e0000
-
-#define REG_MDP4_DSI_ENABLE					0x000e0000
-
-#define REG_MDP4_DSI_HSYNC_CTRL					0x000e0004
-#define MDP4_DSI_HSYNC_CTRL_PULSEW__MASK			0x0000ffff
-#define MDP4_DSI_HSYNC_CTRL_PULSEW__SHIFT			0
-static inline uint32_t MDP4_DSI_HSYNC_CTRL_PULSEW(uint32_t val)
-{
-	return ((val) << MDP4_DSI_HSYNC_CTRL_PULSEW__SHIFT) & MDP4_DSI_HSYNC_CTRL_PULSEW__MASK;
-}
-#define MDP4_DSI_HSYNC_CTRL_PERIOD__MASK			0xffff0000
-#define MDP4_DSI_HSYNC_CTRL_PERIOD__SHIFT			16
-static inline uint32_t MDP4_DSI_HSYNC_CTRL_PERIOD(uint32_t val)
-{
-	return ((val) << MDP4_DSI_HSYNC_CTRL_PERIOD__SHIFT) & MDP4_DSI_HSYNC_CTRL_PERIOD__MASK;
-}
-
-#define REG_MDP4_DSI_VSYNC_PERIOD				0x000e0008
-
-#define REG_MDP4_DSI_VSYNC_LEN					0x000e000c
-
-#define REG_MDP4_DSI_DISPLAY_HCTRL				0x000e0010
-#define MDP4_DSI_DISPLAY_HCTRL_START__MASK			0x0000ffff
-#define MDP4_DSI_DISPLAY_HCTRL_START__SHIFT			0
-static inline uint32_t MDP4_DSI_DISPLAY_HCTRL_START(uint32_t val)
-{
-	return ((val) << MDP4_DSI_DISPLAY_HCTRL_START__SHIFT) & MDP4_DSI_DISPLAY_HCTRL_START__MASK;
-}
-#define MDP4_DSI_DISPLAY_HCTRL_END__MASK			0xffff0000
-#define MDP4_DSI_DISPLAY_HCTRL_END__SHIFT			16
-static inline uint32_t MDP4_DSI_DISPLAY_HCTRL_END(uint32_t val)
-{
-	return ((val) << MDP4_DSI_DISPLAY_HCTRL_END__SHIFT) & MDP4_DSI_DISPLAY_HCTRL_END__MASK;
-}
-
-#define REG_MDP4_DSI_DISPLAY_VSTART				0x000e0014
-
-#define REG_MDP4_DSI_DISPLAY_VEND				0x000e0018
-
-#define REG_MDP4_DSI_ACTIVE_HCTL				0x000e001c
-#define MDP4_DSI_ACTIVE_HCTL_START__MASK			0x00007fff
-#define MDP4_DSI_ACTIVE_HCTL_START__SHIFT			0
-static inline uint32_t MDP4_DSI_ACTIVE_HCTL_START(uint32_t val)
-{
-	return ((val) << MDP4_DSI_ACTIVE_HCTL_START__SHIFT) & MDP4_DSI_ACTIVE_HCTL_START__MASK;
-}
-#define MDP4_DSI_ACTIVE_HCTL_END__MASK				0x7fff0000
-#define MDP4_DSI_ACTIVE_HCTL_END__SHIFT				16
-static inline uint32_t MDP4_DSI_ACTIVE_HCTL_END(uint32_t val)
-{
-	return ((val) << MDP4_DSI_ACTIVE_HCTL_END__SHIFT) & MDP4_DSI_ACTIVE_HCTL_END__MASK;
-}
-#define MDP4_DSI_ACTIVE_HCTL_ACTIVE_START_X			0x80000000
-
-#define REG_MDP4_DSI_ACTIVE_VSTART				0x000e0020
-
-#define REG_MDP4_DSI_ACTIVE_VEND				0x000e0024
-
-#define REG_MDP4_DSI_BORDER_CLR					0x000e0028
-
-#define REG_MDP4_DSI_UNDERFLOW_CLR				0x000e002c
-#define MDP4_DSI_UNDERFLOW_CLR_COLOR__MASK			0x00ffffff
-#define MDP4_DSI_UNDERFLOW_CLR_COLOR__SHIFT			0
-static inline uint32_t MDP4_DSI_UNDERFLOW_CLR_COLOR(uint32_t val)
-{
-	return ((val) << MDP4_DSI_UNDERFLOW_CLR_COLOR__SHIFT) & MDP4_DSI_UNDERFLOW_CLR_COLOR__MASK;
-}
-#define MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY			0x80000000
-
-#define REG_MDP4_DSI_HSYNC_SKEW					0x000e0030
-
-#define REG_MDP4_DSI_TEST_CNTL					0x000e0034
-
-#define REG_MDP4_DSI_CTRL_POLARITY				0x000e0038
-#define MDP4_DSI_CTRL_POLARITY_HSYNC_LOW			0x00000001
-#define MDP4_DSI_CTRL_POLARITY_VSYNC_LOW			0x00000002
-#define MDP4_DSI_CTRL_POLARITY_DATA_EN_LOW			0x00000004
-
-
-#endif /* MDP4_XML */
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
deleted file mode 100644
index 14bd3bd3e040..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_flip_work.h>
-#include <drm/drm_mode.h>
-
-#include "mdp4_kms.h"
-
-struct mdp4_crtc {
-	struct drm_crtc base;
-	char name[8];
-	int id;
-	int ovlp;
-	enum mdp4_dma dma;
-	bool enabled;
-
-	/* which mixer/encoder we route output to: */
-	int mixer;
-
-	struct {
-		spinlock_t lock;
-		bool stale;
-		uint32_t width, height;
-		uint32_t x, y;
-
-		/* next cursor to scan-out: */
-		uint32_t next_iova;
-		struct drm_gem_object *next_bo;
-
-		/* current cursor being scanned out: */
-		struct drm_gem_object *scanout_bo;
-	} cursor;
-
-
-	/* if there is a pending flip, these will be non-null: */
-	struct drm_pending_vblank_event *event;
-
-	/* Bits have been flushed at the last commit,
-	 * used to decide if a vsync has happened since last commit.
-	 */
-	u32 flushed_mask;
-
-#define PENDING_CURSOR 0x1
-#define PENDING_FLIP   0x2
-	atomic_t pending;
-
-	/* for unref'ing cursor bo's after scanout completes: */
-	struct drm_flip_work unref_cursor_work;
-
-	struct mdp_irq vblank;
-	struct mdp_irq err;
-};
-#define to_mdp4_crtc(x) container_of(x, struct mdp4_crtc, base)
-
-static struct mdp4_kms *get_kms(struct drm_crtc *crtc)
-{
-	struct msm_drm_private *priv = crtc->dev->dev_private;
-	return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-static void request_pending(struct drm_crtc *crtc, uint32_t pending)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-
-	atomic_or(pending, &mdp4_crtc->pending);
-	mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
-}
-
-static void crtc_flush(struct drm_crtc *crtc)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	struct drm_plane *plane;
-	uint32_t flush = 0;
-
-	drm_atomic_crtc_for_each_plane(plane, crtc) {
-		enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
-		flush |= pipe2flush(pipe_id);
-	}
-
-	flush |= ovlp2flush(mdp4_crtc->ovlp);
-
-	DBG("%s: flush=%08x", mdp4_crtc->name, flush);
-
-	mdp4_crtc->flushed_mask = flush;
-
-	mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
-}
-
-/* if file!=NULL, this is preclose potential cancel-flip path */
-static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct drm_device *dev = crtc->dev;
-	struct drm_pending_vblank_event *event;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-	event = mdp4_crtc->event;
-	if (event) {
-		mdp4_crtc->event = NULL;
-		DBG("%s: send event: %p", mdp4_crtc->name, event);
-		drm_crtc_send_vblank_event(crtc, event);
-	}
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
-static void unref_cursor_worker(struct drm_flip_work *work, void *val)
-{
-	struct mdp4_crtc *mdp4_crtc =
-		container_of(work, struct mdp4_crtc, unref_cursor_work);
-	struct mdp4_kms *mdp4_kms = get_kms(&mdp4_crtc->base);
-	struct msm_kms *kms = &mdp4_kms->base.base;
-
-	msm_gem_put_iova(val, kms->aspace);
-	drm_gem_object_unreference_unlocked(val);
-}
-
-static void mdp4_crtc_destroy(struct drm_crtc *crtc)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-
-	drm_crtc_cleanup(crtc);
-	drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work);
-
-	kfree(mdp4_crtc);
-}
-
-/* statically (for now) map planes to mixer stage (z-order): */
-static const int idxs[] = {
-		[VG1]  = 1,
-		[VG2]  = 2,
-		[RGB1] = 0,
-		[RGB2] = 0,
-		[RGB3] = 0,
-		[VG3]  = 3,
-		[VG4]  = 4,
-
-};
-
-/* setup mixer config, for which we need to consider all crtc's and
- * the planes attached to them
- *
- * TODO may possibly need some extra locking here
- */
-static void setup_mixer(struct mdp4_kms *mdp4_kms)
-{
-	struct drm_mode_config *config = &mdp4_kms->dev->mode_config;
-	struct drm_crtc *crtc;
-	uint32_t mixer_cfg = 0;
-	static const enum mdp_mixer_stage_id stages[] = {
-			STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
-	};
-
-	list_for_each_entry(crtc, &config->crtc_list, head) {
-		struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-		struct drm_plane *plane;
-
-		drm_atomic_crtc_for_each_plane(plane, crtc) {
-			enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
-			int idx = idxs[pipe_id];
-			mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
-					pipe_id, stages[idx]);
-		}
-	}
-
-	mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
-}
-
-static void blend_setup(struct drm_crtc *crtc)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	struct drm_plane *plane;
-	int i, ovlp = mdp4_crtc->ovlp;
-	bool alpha[4]= { false, false, false, false };
-
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
-
-	drm_atomic_crtc_for_each_plane(plane, crtc) {
-		enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
-		int idx = idxs[pipe_id];
-		if (idx > 0) {
-			const struct mdp_format *format =
-					to_mdp_format(msm_framebuffer_format(plane->fb));
-			alpha[idx-1] = format->alpha_enable;
-		}
-	}
-
-	for (i = 0; i < 4; i++) {
-		uint32_t op;
-
-		if (alpha[i]) {
-			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) |
-					MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) |
-					MDP4_OVLP_STAGE_OP_BG_INV_ALPHA;
-		} else {
-			op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
-					MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST);
-		}
-
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0);
-		mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
-	}
-
-	setup_mixer(mdp4_kms);
-}
-
-static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	enum mdp4_dma dma = mdp4_crtc->dma;
-	int ovlp = mdp4_crtc->ovlp;
-	struct drm_display_mode *mode;
-
-	if (WARN_ON(!crtc->state))
-		return;
-
-	mode = &crtc->state->adjusted_mode;
-
-	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			mdp4_crtc->name, mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
-			MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
-			MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay));
-
-	/* take data from pipe: */
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
-			MDP4_DMA_DST_SIZE_WIDTH(0) |
-			MDP4_DMA_DST_SIZE_HEIGHT(0));
-
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_BASE(ovlp), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp),
-			MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
-			MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), 0);
-
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
-
-	if (dma == DMA_E) {
-		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000);
-		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000);
-		mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
-	}
-}
-
-static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-
-	DBG("%s", mdp4_crtc->name);
-
-	if (WARN_ON(!mdp4_crtc->enabled))
-		return;
-
-	/* Disable/save vblank irq handling before power is disabled */
-	drm_crtc_vblank_off(crtc);
-
-	mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
-	mdp4_disable(mdp4_kms);
-
-	mdp4_crtc->enabled = false;
-}
-
-static void mdp4_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-
-	DBG("%s", mdp4_crtc->name);
-
-	if (WARN_ON(mdp4_crtc->enabled))
-		return;
-
-	mdp4_enable(mdp4_kms);
-
-	/* Restore vblank irq handling after power is enabled */
-	drm_crtc_vblank_on(crtc);
-
-	mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
-
-	crtc_flush(crtc);
-
-	mdp4_crtc->enabled = true;
-}
-
-static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
-		struct drm_crtc_state *state)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	DBG("%s: check", mdp4_crtc->name);
-	// TODO anything else to check?
-	return 0;
-}
-
-static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	DBG("%s: begin", mdp4_crtc->name);
-}
-
-static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct drm_device *dev = crtc->dev;
-	unsigned long flags;
-
-	DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event);
-
-	WARN_ON(mdp4_crtc->event);
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-	mdp4_crtc->event = crtc->state->event;
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-
-	blend_setup(crtc);
-	crtc_flush(crtc);
-	request_pending(crtc, PENDING_FLIP);
-}
-
-#define CURSOR_WIDTH 64
-#define CURSOR_HEIGHT 64
-
-/* called from IRQ to update cursor related registers (if needed).  The
- * cursor registers, other than x/y position, appear not to be double
- * buffered, and changing them other than from vblank seems to trigger
- * underflow.
- */
-static void update_cursor(struct drm_crtc *crtc)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	struct msm_kms *kms = &mdp4_kms->base.base;
-	enum mdp4_dma dma = mdp4_crtc->dma;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
-	if (mdp4_crtc->cursor.stale) {
-		struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo;
-		struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo;
-		uint64_t iova = mdp4_crtc->cursor.next_iova;
-
-		if (next_bo) {
-			/* take a obj ref + iova ref when we start scanning out: */
-			drm_gem_object_reference(next_bo);
-			msm_gem_get_iova(next_bo, kms->aspace, &iova);
-
-			/* enable cursor: */
-			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma),
-					MDP4_DMA_CURSOR_SIZE_WIDTH(mdp4_crtc->cursor.width) |
-					MDP4_DMA_CURSOR_SIZE_HEIGHT(mdp4_crtc->cursor.height));
-			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), iova);
-			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma),
-					MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB) |
-					MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN);
-		} else {
-			/* disable cursor: */
-			mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma),
-					mdp4_kms->blank_cursor_iova);
-		}
-
-		/* and drop the iova ref + obj rev when done scanning out: */
-		if (prev_bo)
-			drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, prev_bo);
-
-		mdp4_crtc->cursor.scanout_bo = next_bo;
-		mdp4_crtc->cursor.stale = false;
-	}
-
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
-			MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) |
-			MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y));
-
-	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
-}
-
-static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
-		struct drm_file *file_priv, uint32_t handle,
-		uint32_t width, uint32_t height)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	struct msm_kms *kms = &mdp4_kms->base.base;
-	struct drm_device *dev = crtc->dev;
-	struct drm_gem_object *cursor_bo, *old_bo;
-	unsigned long flags;
-	uint64_t iova;
-	int ret;
-
-	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
-		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
-		return -EINVAL;
-	}
-
-	if (handle) {
-		cursor_bo = drm_gem_object_lookup(file_priv, handle);
-		if (!cursor_bo)
-			return -ENOENT;
-	} else {
-		cursor_bo = NULL;
-	}
-
-	if (cursor_bo) {
-		ret = msm_gem_get_iova(cursor_bo, kms->aspace, &iova);
-		if (ret)
-			goto fail;
-	} else {
-		iova = 0;
-	}
-
-	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
-	old_bo = mdp4_crtc->cursor.next_bo;
-	mdp4_crtc->cursor.next_bo   = cursor_bo;
-	mdp4_crtc->cursor.next_iova = iova;
-	mdp4_crtc->cursor.width     = width;
-	mdp4_crtc->cursor.height    = height;
-	mdp4_crtc->cursor.stale     = true;
-	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
-
-	if (old_bo) {
-		/* drop our previous reference: */
-		drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo);
-	}
-
-	request_pending(crtc, PENDING_CURSOR);
-
-	return 0;
-
-fail:
-	drm_gem_object_unreference_unlocked(cursor_bo);
-	return ret;
-}
-
-static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	unsigned long flags;
-
-	spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
-	mdp4_crtc->cursor.x = x;
-	mdp4_crtc->cursor.y = y;
-	spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
-
-	crtc_flush(crtc);
-	request_pending(crtc, PENDING_CURSOR);
-
-	return 0;
-}
-
-static const struct drm_crtc_funcs mdp4_crtc_funcs = {
-	.set_config = drm_atomic_helper_set_config,
-	.destroy = mdp4_crtc_destroy,
-	.page_flip = drm_atomic_helper_page_flip,
-	.cursor_set = mdp4_crtc_cursor_set,
-	.cursor_move = mdp4_crtc_cursor_move,
-	.reset = drm_atomic_helper_crtc_reset,
-	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
-};
-
-static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
-	.mode_set_nofb = mdp4_crtc_mode_set_nofb,
-	.atomic_check = mdp4_crtc_atomic_check,
-	.atomic_begin = mdp4_crtc_atomic_begin,
-	.atomic_flush = mdp4_crtc_atomic_flush,
-	.atomic_enable = mdp4_crtc_atomic_enable,
-	.atomic_disable = mdp4_crtc_atomic_disable,
-};
-
-static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank);
-	struct drm_crtc *crtc = &mdp4_crtc->base;
-	struct msm_drm_private *priv = crtc->dev->dev_private;
-	unsigned pending;
-
-	mdp_irq_unregister(&get_kms(crtc)->base, &mdp4_crtc->vblank);
-
-	pending = atomic_xchg(&mdp4_crtc->pending, 0);
-
-	if (pending & PENDING_FLIP) {
-		complete_flip(crtc, NULL);
-	}
-
-	if (pending & PENDING_CURSOR) {
-		update_cursor(crtc);
-		drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq);
-	}
-}
-
-static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, err);
-	struct drm_crtc *crtc = &mdp4_crtc->base;
-	DBG("%s: error: %08x", mdp4_crtc->name, irqstatus);
-	crtc_flush(crtc);
-}
-
-static void mdp4_crtc_wait_for_flush_done(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	int ret;
-
-	ret = drm_crtc_vblank_get(crtc);
-	if (ret)
-		return;
-
-	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
-		!(mdp4_read(mdp4_kms, REG_MDP4_OVERLAY_FLUSH) &
-			mdp4_crtc->flushed_mask),
-		msecs_to_jiffies(50));
-	if (ret <= 0)
-		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp4_crtc->id);
-
-	mdp4_crtc->flushed_mask = 0;
-
-	drm_crtc_vblank_put(crtc);
-}
-
-uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	return mdp4_crtc->vblank.irqmask;
-}
-
-/* set dma config, ie. the format the encoder wants. */
-void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_CONFIG(mdp4_crtc->dma), config);
-}
-
-/* set interface for routing crtc->encoder: */
-void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	uint32_t intf_sel;
-
-	intf_sel = mdp4_read(mdp4_kms, REG_MDP4_DISP_INTF_SEL);
-
-	switch (mdp4_crtc->dma) {
-	case DMA_P:
-		intf_sel &= ~MDP4_DISP_INTF_SEL_PRIM__MASK;
-		intf_sel |= MDP4_DISP_INTF_SEL_PRIM(intf);
-		break;
-	case DMA_S:
-		intf_sel &= ~MDP4_DISP_INTF_SEL_SEC__MASK;
-		intf_sel |= MDP4_DISP_INTF_SEL_SEC(intf);
-		break;
-	case DMA_E:
-		intf_sel &= ~MDP4_DISP_INTF_SEL_EXT__MASK;
-		intf_sel |= MDP4_DISP_INTF_SEL_EXT(intf);
-		break;
-	}
-
-	if (intf == INTF_DSI_VIDEO) {
-		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD;
-		intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO;
-	} else if (intf == INTF_DSI_CMD) {
-		intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO;
-		intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD;
-	}
-
-	mdp4_crtc->mixer = mixer;
-
-	blend_setup(crtc);
-
-	DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
-}
-
-void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc)
-{
-	/* wait_for_flush_done is the only case for now.
-	 * Later we will have command mode CRTC to wait for
-	 * other event.
-	 */
-	mdp4_crtc_wait_for_flush_done(crtc);
-}
-
-static const char *dma_names[] = {
-		"DMA_P", "DMA_S", "DMA_E",
-};
-
-/* initialize crtc */
-struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
-		struct drm_plane *plane, int id, int ovlp_id,
-		enum mdp4_dma dma_id)
-{
-	struct drm_crtc *crtc = NULL;
-	struct mdp4_crtc *mdp4_crtc;
-
-	mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL);
-	if (!mdp4_crtc)
-		return ERR_PTR(-ENOMEM);
-
-	crtc = &mdp4_crtc->base;
-
-	mdp4_crtc->id = id;
-
-	mdp4_crtc->ovlp = ovlp_id;
-	mdp4_crtc->dma = dma_id;
-
-	mdp4_crtc->vblank.irqmask = dma2irq(mdp4_crtc->dma);
-	mdp4_crtc->vblank.irq = mdp4_crtc_vblank_irq;
-
-	mdp4_crtc->err.irqmask = dma2err(mdp4_crtc->dma);
-	mdp4_crtc->err.irq = mdp4_crtc_err_irq;
-
-	snprintf(mdp4_crtc->name, sizeof(mdp4_crtc->name), "%s:%d",
-			dma_names[dma_id], ovlp_id);
-
-	spin_lock_init(&mdp4_crtc->cursor.lock);
-
-	drm_flip_work_init(&mdp4_crtc->unref_cursor_work,
-			"unref cursor", unref_cursor_worker);
-
-	drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs,
-				  NULL);
-	drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
-	plane->crtc = crtc;
-
-	return crtc;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c
deleted file mode 100644
index 6a1ebdace391..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dsi_encoder.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
- * Copyright (c) 2014, Inforce Computing. All rights reserved.
- *
- * Author: Vinay Simha <vinaysimha@inforcecomputing.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "mdp4_kms.h"
-
-struct mdp4_dsi_encoder {
-	struct drm_encoder base;
-	struct drm_panel *panel;
-	bool enabled;
-};
-#define to_mdp4_dsi_encoder(x) container_of(x, struct mdp4_dsi_encoder, base)
-
-static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
-{
-	struct msm_drm_private *priv = encoder->dev->dev_private;
-	return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
-
-	drm_encoder_cleanup(encoder);
-	kfree(mdp4_dsi_encoder);
-}
-
-static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
-	.destroy = mdp4_dsi_encoder_destroy,
-};
-
-static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode,
-				      struct drm_display_mode *adjusted_mode)
-{
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	uint32_t dsi_hsync_skew, vsync_period, vsync_len, ctrl_pol;
-	uint32_t display_v_start, display_v_end;
-	uint32_t hsync_start_x, hsync_end_x;
-
-	mode = adjusted_mode;
-
-	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-
-	ctrl_pol = 0;
-	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-		ctrl_pol |= MDP4_DSI_CTRL_POLARITY_HSYNC_LOW;
-	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-		ctrl_pol |= MDP4_DSI_CTRL_POLARITY_VSYNC_LOW;
-	/* probably need to get DATA_EN polarity from panel.. */
-
-	dsi_hsync_skew = 0;  /* get this from panel? */
-
-	hsync_start_x = (mode->htotal - mode->hsync_start);
-	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
-
-	vsync_period = mode->vtotal * mode->htotal;
-	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
-	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dsi_hsync_skew;
-	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dsi_hsync_skew - 1;
-
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_CTRL,
-			MDP4_DSI_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
-			MDP4_DSI_HSYNC_CTRL_PERIOD(mode->htotal));
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_PERIOD, vsync_period);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_LEN, vsync_len);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_HCTRL,
-			MDP4_DSI_DISPLAY_HCTRL_START(hsync_start_x) |
-			MDP4_DSI_DISPLAY_HCTRL_END(hsync_end_x));
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VSTART, display_v_start);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VEND, display_v_end);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_CTRL_POLARITY, ctrl_pol);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_UNDERFLOW_CLR,
-			MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY |
-			MDP4_DSI_UNDERFLOW_CLR_COLOR(0xff));
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_HCTL,
-			MDP4_DSI_ACTIVE_HCTL_START(0) |
-			MDP4_DSI_ACTIVE_HCTL_END(0));
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_SKEW, dsi_hsync_skew);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_BORDER_CLR, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VSTART, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VEND, 0);
-}
-
-static void mdp4_dsi_encoder_disable(struct drm_encoder *encoder)
-{
-	struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-
-	if (!mdp4_dsi_encoder->enabled)
-		return;
-
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
-
-	/*
-	 * Wait for a vsync so we know the ENABLE=0 latched before
-	 * the (connector) source of the vsync's gets disabled,
-	 * otherwise we end up in a funny state if we re-enable
-	 * before the disable latches, which results that some of
-	 * the settings changes for the new modeset (like new
-	 * scanout buffer) don't latch properly..
-	 */
-	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
-
-	mdp4_dsi_encoder->enabled = false;
-}
-
-static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder)
-{
-	struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-
-	if (mdp4_dsi_encoder->enabled)
-		return;
-
-	 mdp4_crtc_set_config(encoder->crtc,
-			MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
-			MDP4_DMA_CONFIG_DEFLKR_EN |
-			MDP4_DMA_CONFIG_DITHER_EN |
-			MDP4_DMA_CONFIG_R_BPC(BPC8) |
-			MDP4_DMA_CONFIG_G_BPC(BPC8) |
-			MDP4_DMA_CONFIG_B_BPC(BPC8) |
-			MDP4_DMA_CONFIG_PACK(0x21));
-
-	mdp4_crtc_set_intf(encoder->crtc, INTF_DSI_VIDEO, 0);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 1);
-
-	mdp4_dsi_encoder->enabled = true;
-}
-
-static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = {
-	.mode_set = mdp4_dsi_encoder_mode_set,
-	.disable = mdp4_dsi_encoder_disable,
-	.enable = mdp4_dsi_encoder_enable,
-};
-
-/* initialize encoder */
-struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
-{
-	struct drm_encoder *encoder = NULL;
-	struct mdp4_dsi_encoder *mdp4_dsi_encoder;
-	int ret;
-
-	mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL);
-	if (!mdp4_dsi_encoder) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	encoder = &mdp4_dsi_encoder->base;
-
-	drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs,
-			 DRM_MODE_ENCODER_DSI, NULL);
-	drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs);
-
-	return encoder;
-
-fail:
-	if (encoder)
-		mdp4_dsi_encoder_destroy(encoder);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
deleted file mode 100644
index ba8e587f734b..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "mdp4_kms.h"
-
-struct mdp4_dtv_encoder {
-	struct drm_encoder base;
-	struct clk *hdmi_clk;
-	struct clk *mdp_clk;
-	unsigned long int pixclock;
-	bool enabled;
-	uint32_t bsc;
-};
-#define to_mdp4_dtv_encoder(x) container_of(x, struct mdp4_dtv_encoder, base)
-
-static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
-{
-	struct msm_drm_private *priv = encoder->dev->dev_private;
-	return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
-#include <mach/board.h>
-/* not ironically named at all.. no, really.. */
-static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder)
-{
-	struct drm_device *dev = mdp4_dtv_encoder->base.dev;
-	struct lcdc_platform_data *dtv_pdata = mdp4_find_pdata("dtv.0");
-
-	if (!dtv_pdata) {
-		dev_err(dev->dev, "could not find dtv pdata\n");
-		return;
-	}
-
-	if (dtv_pdata->bus_scale_table) {
-		mdp4_dtv_encoder->bsc = msm_bus_scale_register_client(
-				dtv_pdata->bus_scale_table);
-		DBG("bus scale client: %08x", mdp4_dtv_encoder->bsc);
-		DBG("lcdc_power_save: %p", dtv_pdata->lcdc_power_save);
-		if (dtv_pdata->lcdc_power_save)
-			dtv_pdata->lcdc_power_save(1);
-	}
-}
-
-static void bs_fini(struct mdp4_dtv_encoder *mdp4_dtv_encoder)
-{
-	if (mdp4_dtv_encoder->bsc) {
-		msm_bus_scale_unregister_client(mdp4_dtv_encoder->bsc);
-		mdp4_dtv_encoder->bsc = 0;
-	}
-}
-
-static void bs_set(struct mdp4_dtv_encoder *mdp4_dtv_encoder, int idx)
-{
-	if (mdp4_dtv_encoder->bsc) {
-		DBG("set bus scaling: %d", idx);
-		msm_bus_scale_client_update_request(mdp4_dtv_encoder->bsc, idx);
-	}
-}
-#else
-static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder) {}
-static void bs_fini(struct mdp4_dtv_encoder *mdp4_dtv_encoder) {}
-static void bs_set(struct mdp4_dtv_encoder *mdp4_dtv_encoder, int idx) {}
-#endif
-
-static void mdp4_dtv_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	bs_fini(mdp4_dtv_encoder);
-	drm_encoder_cleanup(encoder);
-	kfree(mdp4_dtv_encoder);
-}
-
-static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = {
-	.destroy = mdp4_dtv_encoder_destroy,
-};
-
-static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
-		struct drm_display_mode *mode,
-		struct drm_display_mode *adjusted_mode)
-{
-	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
-	uint32_t display_v_start, display_v_end;
-	uint32_t hsync_start_x, hsync_end_x;
-
-	mode = adjusted_mode;
-
-	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-
-	mdp4_dtv_encoder->pixclock = mode->clock * 1000;
-
-	DBG("pixclock=%lu", mdp4_dtv_encoder->pixclock);
-
-	ctrl_pol = 0;
-	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-		ctrl_pol |= MDP4_DTV_CTRL_POLARITY_HSYNC_LOW;
-	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-		ctrl_pol |= MDP4_DTV_CTRL_POLARITY_VSYNC_LOW;
-	/* probably need to get DATA_EN polarity from panel.. */
-
-	dtv_hsync_skew = 0;  /* get this from panel? */
-
-	hsync_start_x = (mode->htotal - mode->hsync_start);
-	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
-
-	vsync_period = mode->vtotal * mode->htotal;
-	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
-	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
-	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
-
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_HSYNC_CTRL,
-			MDP4_DTV_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
-			MDP4_DTV_HSYNC_CTRL_PERIOD(mode->htotal));
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_VSYNC_PERIOD, vsync_period);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_VSYNC_LEN, vsync_len);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_HCTRL,
-			MDP4_DTV_DISPLAY_HCTRL_START(hsync_start_x) |
-			MDP4_DTV_DISPLAY_HCTRL_END(hsync_end_x));
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_VSTART, display_v_start);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_DISPLAY_VEND, display_v_end);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_BORDER_CLR, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_UNDERFLOW_CLR,
-			MDP4_DTV_UNDERFLOW_CLR_ENABLE_RECOVERY |
-			MDP4_DTV_UNDERFLOW_CLR_COLOR(0xff));
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_HSYNC_SKEW, dtv_hsync_skew);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_CTRL_POLARITY, ctrl_pol);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_HCTL,
-			MDP4_DTV_ACTIVE_HCTL_START(0) |
-			MDP4_DTV_ACTIVE_HCTL_END(0));
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
-}
-
-static void mdp4_dtv_encoder_disable(struct drm_encoder *encoder)
-{
-	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-
-	if (WARN_ON(!mdp4_dtv_encoder->enabled))
-		return;
-
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
-
-	/*
-	 * Wait for a vsync so we know the ENABLE=0 latched before
-	 * the (connector) source of the vsync's gets disabled,
-	 * otherwise we end up in a funny state if we re-enable
-	 * before the disable latches, which results that some of
-	 * the settings changes for the new modeset (like new
-	 * scanout buffer) don't latch properly..
-	 */
-	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC);
-
-	clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
-	clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
-
-	bs_set(mdp4_dtv_encoder, 0);
-
-	mdp4_dtv_encoder->enabled = false;
-}
-
-static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder)
-{
-	struct drm_device *dev = encoder->dev;
-	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	unsigned long pc = mdp4_dtv_encoder->pixclock;
-	int ret;
-
-	if (WARN_ON(mdp4_dtv_encoder->enabled))
-		return;
-
-	mdp4_crtc_set_config(encoder->crtc,
-			MDP4_DMA_CONFIG_R_BPC(BPC8) |
-			MDP4_DMA_CONFIG_G_BPC(BPC8) |
-			MDP4_DMA_CONFIG_B_BPC(BPC8) |
-			MDP4_DMA_CONFIG_PACK(0x21));
-	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1);
-
-	bs_set(mdp4_dtv_encoder, 1);
-
-	DBG("setting mdp_clk=%lu", pc);
-
-	ret = clk_set_rate(mdp4_dtv_encoder->mdp_clk, pc);
-	if (ret)
-		dev_err(dev->dev, "failed to set mdp_clk to %lu: %d\n",
-			pc, ret);
-
-	ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
-	if (ret)
-		dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
-
-	ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
-	if (ret)
-		dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1);
-
-	mdp4_dtv_encoder->enabled = true;
-}
-
-static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = {
-	.mode_set = mdp4_dtv_encoder_mode_set,
-	.enable = mdp4_dtv_encoder_enable,
-	.disable = mdp4_dtv_encoder_disable,
-};
-
-long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
-{
-	struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
-	return clk_round_rate(mdp4_dtv_encoder->mdp_clk, rate);
-}
-
-/* initialize encoder */
-struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev)
-{
-	struct drm_encoder *encoder = NULL;
-	struct mdp4_dtv_encoder *mdp4_dtv_encoder;
-	int ret;
-
-	mdp4_dtv_encoder = kzalloc(sizeof(*mdp4_dtv_encoder), GFP_KERNEL);
-	if (!mdp4_dtv_encoder) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	encoder = &mdp4_dtv_encoder->base;
-
-	drm_encoder_init(dev, encoder, &mdp4_dtv_encoder_funcs,
-			 DRM_MODE_ENCODER_TMDS, NULL);
-	drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs);
-
-	mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk");
-	if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) {
-		dev_err(dev->dev, "failed to get hdmi_clk\n");
-		ret = PTR_ERR(mdp4_dtv_encoder->hdmi_clk);
-		goto fail;
-	}
-
-	mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "tv_clk");
-	if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) {
-		dev_err(dev->dev, "failed to get tv_clk\n");
-		ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk);
-		goto fail;
-	}
-
-	bs_init(mdp4_dtv_encoder);
-
-	return encoder;
-
-fail:
-	if (encoder)
-		mdp4_dtv_encoder_destroy(encoder);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
deleted file mode 100644
index b764d7f10312..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_print.h>
-
-#include "msm_drv.h"
-#include "mdp4_kms.h"
-
-void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
-		uint32_t old_irqmask)
-{
-	mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_CLEAR,
-		irqmask ^ (irqmask & old_irqmask));
-	mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask);
-}
-
-static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp4_kms *mdp4_kms = container_of(irq, struct mdp4_kms, error_handler);
-	static DEFINE_RATELIMIT_STATE(rs, 5*HZ, 1);
-	extern bool dumpstate;
-
-	DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
-
-	if (dumpstate && __ratelimit(&rs)) {
-		struct drm_printer p = drm_info_printer(mdp4_kms->dev->dev);
-		drm_state_dump(mdp4_kms->dev, &p);
-	}
-}
-
-void mdp4_irq_preinstall(struct msm_kms *kms)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	mdp4_enable(mdp4_kms);
-	mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
-	mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
-	mdp4_disable(mdp4_kms);
-}
-
-int mdp4_irq_postinstall(struct msm_kms *kms)
-{
-	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
-	struct mdp_irq *error_handler = &mdp4_kms->error_handler;
-
-	error_handler->irq = mdp4_irq_error_handler;
-	error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN |
-			MDP4_IRQ_EXTERNAL_INTF_UDERRUN;
-
-	mdp_irq_register(mdp_kms, error_handler);
-
-	return 0;
-}
-
-void mdp4_irq_uninstall(struct msm_kms *kms)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	mdp4_enable(mdp4_kms);
-	mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
-	mdp4_disable(mdp4_kms);
-}
-
-irqreturn_t mdp4_irq(struct msm_kms *kms)
-{
-	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
-	struct drm_device *dev = mdp4_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	unsigned int id;
-	uint32_t status, enable;
-
-	enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE);
-	status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS) & enable;
-	mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status);
-
-	VERB("status=%08x", status);
-
-	mdp_dispatch_irqs(mdp_kms, status);
-
-	for (id = 0; id < priv->num_crtcs; id++)
-		if (status & mdp4_crtc_vblank(priv->crtcs[id]))
-			drm_handle_vblank(dev, id);
-
-	return IRQ_HANDLED;
-}
-
-int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-
-	mdp4_enable(mdp4_kms);
-	mdp_update_vblank_mask(to_mdp_kms(kms),
-			mdp4_crtc_vblank(crtc), true);
-	mdp4_disable(mdp4_kms);
-
-	return 0;
-}
-
-void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-
-	mdp4_enable(mdp4_kms);
-	mdp_update_vblank_mask(to_mdp_kms(kms),
-			mdp4_crtc_vblank(crtc), false);
-	mdp4_disable(mdp4_kms);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
deleted file mode 100644
index f7f087419ed8..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "msm_drv.h"
-#include "msm_gem.h"
-#include "msm_mmu.h"
-#include "mdp4_kms.h"
-
-static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev);
-
-static int mdp4_hw_init(struct msm_kms *kms)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	struct drm_device *dev = mdp4_kms->dev;
-	uint32_t version, major, minor, dmap_cfg, vg_cfg;
-	unsigned long clk;
-	int ret = 0;
-
-	pm_runtime_get_sync(dev->dev);
-
-	mdp4_enable(mdp4_kms);
-	version = mdp4_read(mdp4_kms, REG_MDP4_VERSION);
-	mdp4_disable(mdp4_kms);
-
-	major = FIELD(version, MDP4_VERSION_MAJOR);
-	minor = FIELD(version, MDP4_VERSION_MINOR);
-
-	DBG("found MDP4 version v%d.%d", major, minor);
-
-	if (major != 4) {
-		dev_err(dev->dev, "unexpected MDP version: v%d.%d\n",
-				major, minor);
-		ret = -ENXIO;
-		goto out;
-	}
-
-	mdp4_kms->rev = minor;
-
-	if (mdp4_kms->rev > 1) {
-		mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER0, 0x0707ffff);
-		mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER1, 0x03073f3f);
-	}
-
-	mdp4_write(mdp4_kms, REG_MDP4_PORTMAP_MODE, 0x3);
-
-	/* max read pending cmd config, 3 pending requests: */
-	mdp4_write(mdp4_kms, REG_MDP4_READ_CNFG, 0x02222);
-
-	clk = clk_get_rate(mdp4_kms->clk);
-
-	if ((mdp4_kms->rev >= 1) || (clk >= 90000000)) {
-		dmap_cfg = 0x47;     /* 16 bytes-burst x 8 req */
-		vg_cfg = 0x47;       /* 16 bytes-burs x 8 req */
-	} else {
-		dmap_cfg = 0x27;     /* 8 bytes-burst x 8 req */
-		vg_cfg = 0x43;       /* 16 bytes-burst x 4 req */
-	}
-
-	DBG("fetch config: dmap=%02x, vg=%02x", dmap_cfg, vg_cfg);
-
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_P), dmap_cfg);
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_FETCH_CONFIG(DMA_E), dmap_cfg);
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG1), vg_cfg);
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(VG2), vg_cfg);
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB1), vg_cfg);
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_FETCH_CONFIG(RGB2), vg_cfg);
-
-	if (mdp4_kms->rev >= 2)
-		mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1);
-	mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0);
-
-	/* disable CSC matrix / YUV by default: */
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG2), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_P_OP_MODE, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DMA_S_OP_MODE, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(1), 0);
-	mdp4_write(mdp4_kms, REG_MDP4_OVLP_CSC_CONFIG(2), 0);
-
-	if (mdp4_kms->rev > 1)
-		mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1);
-
-	dev->mode_config.allow_fb_modifiers = true;
-
-out:
-	pm_runtime_put_sync(dev->dev);
-
-	return ret;
-}
-
-static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	int i;
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *crtc_state;
-
-	mdp4_enable(mdp4_kms);
-
-	/* see 119ecb7fd */
-	for_each_new_crtc_in_state(state, crtc, crtc_state, i)
-		drm_crtc_vblank_get(crtc);
-}
-
-static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	int i;
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *crtc_state;
-
-	/* see 119ecb7fd */
-	for_each_new_crtc_in_state(state, crtc, crtc_state, i)
-		drm_crtc_vblank_put(crtc);
-
-	mdp4_disable(mdp4_kms);
-}
-
-static void mdp4_wait_for_crtc_commit_done(struct msm_kms *kms,
-						struct drm_crtc *crtc)
-{
-	mdp4_crtc_wait_for_commit_done(crtc);
-}
-
-static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
-		struct drm_encoder *encoder)
-{
-	/* if we had >1 encoder, we'd need something more clever: */
-	switch (encoder->encoder_type) {
-	case DRM_MODE_ENCODER_TMDS:
-		return mdp4_dtv_round_pixclk(encoder, rate);
-	case DRM_MODE_ENCODER_LVDS:
-	case DRM_MODE_ENCODER_DSI:
-	default:
-		return rate;
-	}
-}
-
-static const char * const iommu_ports[] = {
-	"mdp_port0_cb0", "mdp_port1_cb0",
-};
-
-static void mdp4_destroy(struct msm_kms *kms)
-{
-	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-	struct device *dev = mdp4_kms->dev->dev;
-	struct msm_gem_address_space *aspace = kms->aspace;
-
-	if (mdp4_kms->blank_cursor_iova)
-		msm_gem_put_iova(mdp4_kms->blank_cursor_bo, kms->aspace);
-	drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo);
-
-	if (aspace) {
-		aspace->mmu->funcs->detach(aspace->mmu,
-				iommu_ports, ARRAY_SIZE(iommu_ports));
-		msm_gem_address_space_put(aspace);
-	}
-
-	if (mdp4_kms->rpm_enabled)
-		pm_runtime_disable(dev);
-
-	kfree(mdp4_kms);
-}
-
-static const struct mdp_kms_funcs kms_funcs = {
-	.base = {
-		.hw_init         = mdp4_hw_init,
-		.irq_preinstall  = mdp4_irq_preinstall,
-		.irq_postinstall = mdp4_irq_postinstall,
-		.irq_uninstall   = mdp4_irq_uninstall,
-		.irq             = mdp4_irq,
-		.enable_vblank   = mdp4_enable_vblank,
-		.disable_vblank  = mdp4_disable_vblank,
-		.prepare_commit  = mdp4_prepare_commit,
-		.complete_commit = mdp4_complete_commit,
-		.wait_for_crtc_commit_done = mdp4_wait_for_crtc_commit_done,
-		.get_format      = mdp_get_format,
-		.round_pixclk    = mdp4_round_pixclk,
-		.destroy         = mdp4_destroy,
-	},
-	.set_irqmask         = mdp4_set_irqmask,
-};
-
-int mdp4_disable(struct mdp4_kms *mdp4_kms)
-{
-	DBG("");
-
-	clk_disable_unprepare(mdp4_kms->clk);
-	if (mdp4_kms->pclk)
-		clk_disable_unprepare(mdp4_kms->pclk);
-	clk_disable_unprepare(mdp4_kms->lut_clk);
-	if (mdp4_kms->axi_clk)
-		clk_disable_unprepare(mdp4_kms->axi_clk);
-
-	return 0;
-}
-
-int mdp4_enable(struct mdp4_kms *mdp4_kms)
-{
-	DBG("");
-
-	clk_prepare_enable(mdp4_kms->clk);
-	if (mdp4_kms->pclk)
-		clk_prepare_enable(mdp4_kms->pclk);
-	clk_prepare_enable(mdp4_kms->lut_clk);
-	if (mdp4_kms->axi_clk)
-		clk_prepare_enable(mdp4_kms->axi_clk);
-
-	return 0;
-}
-
-
-static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
-				  int intf_type)
-{
-	struct drm_device *dev = mdp4_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	struct drm_encoder *encoder;
-	struct drm_connector *connector;
-	struct device_node *panel_node;
-	int dsi_id;
-	int ret;
-
-	switch (intf_type) {
-	case DRM_MODE_ENCODER_LVDS:
-		/*
-		 * bail out early if there is no panel node (no need to
-		 * initialize LCDC encoder and LVDS connector)
-		 */
-		panel_node = of_graph_get_remote_node(dev->dev->of_node, 0, 0);
-		if (!panel_node)
-			return 0;
-
-		encoder = mdp4_lcdc_encoder_init(dev, panel_node);
-		if (IS_ERR(encoder)) {
-			dev_err(dev->dev, "failed to construct LCDC encoder\n");
-			return PTR_ERR(encoder);
-		}
-
-		/* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
-		encoder->possible_crtcs = 1 << DMA_P;
-
-		connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
-		if (IS_ERR(connector)) {
-			dev_err(dev->dev, "failed to initialize LVDS connector\n");
-			return PTR_ERR(connector);
-		}
-
-		priv->encoders[priv->num_encoders++] = encoder;
-		priv->connectors[priv->num_connectors++] = connector;
-
-		break;
-	case DRM_MODE_ENCODER_TMDS:
-		encoder = mdp4_dtv_encoder_init(dev);
-		if (IS_ERR(encoder)) {
-			dev_err(dev->dev, "failed to construct DTV encoder\n");
-			return PTR_ERR(encoder);
-		}
-
-		/* DTV can be hooked to DMA_E: */
-		encoder->possible_crtcs = 1 << 1;
-
-		if (priv->hdmi) {
-			/* Construct bridge/connector for HDMI: */
-			ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);
-			if (ret) {
-				dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-				return ret;
-			}
-		}
-
-		priv->encoders[priv->num_encoders++] = encoder;
-
-		break;
-	case DRM_MODE_ENCODER_DSI:
-		/* only DSI1 supported for now */
-		dsi_id = 0;
-
-		if (!priv->dsi[dsi_id])
-			break;
-
-		encoder = mdp4_dsi_encoder_init(dev);
-		if (IS_ERR(encoder)) {
-			ret = PTR_ERR(encoder);
-			dev_err(dev->dev,
-				"failed to construct DSI encoder: %d\n", ret);
-			return ret;
-		}
-
-		/* TODO: Add DMA_S later? */
-		encoder->possible_crtcs = 1 << DMA_P;
-		priv->encoders[priv->num_encoders++] = encoder;
-
-		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
-		if (ret) {
-			dev_err(dev->dev, "failed to initialize DSI: %d\n",
-				ret);
-			return ret;
-		}
-
-		break;
-	default:
-		dev_err(dev->dev, "Invalid or unsupported interface\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int modeset_init(struct mdp4_kms *mdp4_kms)
-{
-	struct drm_device *dev = mdp4_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	struct drm_plane *plane;
-	struct drm_crtc *crtc;
-	int i, ret;
-	static const enum mdp4_pipe rgb_planes[] = {
-		RGB1, RGB2,
-	};
-	static const enum mdp4_pipe vg_planes[] = {
-		VG1, VG2,
-	};
-	static const enum mdp4_dma mdp4_crtcs[] = {
-		DMA_P, DMA_E,
-	};
-	static const char * const mdp4_crtc_names[] = {
-		"DMA_P", "DMA_E",
-	};
-	static const int mdp4_intfs[] = {
-		DRM_MODE_ENCODER_LVDS,
-		DRM_MODE_ENCODER_DSI,
-		DRM_MODE_ENCODER_TMDS,
-	};
-
-	/* construct non-private planes: */
-	for (i = 0; i < ARRAY_SIZE(vg_planes); i++) {
-		plane = mdp4_plane_init(dev, vg_planes[i], false);
-		if (IS_ERR(plane)) {
-			dev_err(dev->dev,
-				"failed to construct plane for VG%d\n", i + 1);
-			ret = PTR_ERR(plane);
-			goto fail;
-		}
-		priv->planes[priv->num_planes++] = plane;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(mdp4_crtcs); i++) {
-		plane = mdp4_plane_init(dev, rgb_planes[i], true);
-		if (IS_ERR(plane)) {
-			dev_err(dev->dev,
-				"failed to construct plane for RGB%d\n", i + 1);
-			ret = PTR_ERR(plane);
-			goto fail;
-		}
-
-		crtc  = mdp4_crtc_init(dev, plane, priv->num_crtcs, i,
-				mdp4_crtcs[i]);
-		if (IS_ERR(crtc)) {
-			dev_err(dev->dev, "failed to construct crtc for %s\n",
-				mdp4_crtc_names[i]);
-			ret = PTR_ERR(crtc);
-			goto fail;
-		}
-
-		priv->crtcs[priv->num_crtcs++] = crtc;
-	}
-
-	/*
-	 * we currently set up two relatively fixed paths:
-	 *
-	 * LCDC/LVDS path: RGB1 -> DMA_P -> LCDC -> LVDS
-	 *			or
-	 * DSI path: RGB1 -> DMA_P -> DSI1 -> DSI Panel
-	 *
-	 * DTV/HDMI path: RGB2 -> DMA_E -> DTV -> HDMI
-	 */
-
-	for (i = 0; i < ARRAY_SIZE(mdp4_intfs); i++) {
-		ret = mdp4_modeset_init_intf(mdp4_kms, mdp4_intfs[i]);
-		if (ret) {
-			dev_err(dev->dev, "failed to initialize intf: %d, %d\n",
-				i, ret);
-			goto fail;
-		}
-	}
-
-	return 0;
-
-fail:
-	return ret;
-}
-
-struct msm_kms *mdp4_kms_init(struct drm_device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev->dev);
-	struct mdp4_platform_config *config = mdp4_get_config(pdev);
-	struct mdp4_kms *mdp4_kms;
-	struct msm_kms *kms = NULL;
-	struct msm_gem_address_space *aspace;
-	int irq, ret;
-
-	mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
-	if (!mdp4_kms) {
-		dev_err(dev->dev, "failed to allocate kms\n");
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	mdp_kms_init(&mdp4_kms->base, &kms_funcs);
-
-	kms = &mdp4_kms->base.base;
-
-	mdp4_kms->dev = dev;
-
-	mdp4_kms->mmio = msm_ioremap(pdev, NULL, "MDP4");
-	if (IS_ERR(mdp4_kms->mmio)) {
-		ret = PTR_ERR(mdp4_kms->mmio);
-		goto fail;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		ret = irq;
-		dev_err(dev->dev, "failed to get irq: %d\n", ret);
-		goto fail;
-	}
-
-	kms->irq = irq;
-
-	/* NOTE: driver for this regulator still missing upstream.. use
-	 * _get_exclusive() and ignore the error if it does not exist
-	 * (and hope that the bootloader left it on for us)
-	 */
-	mdp4_kms->vdd = devm_regulator_get_exclusive(&pdev->dev, "vdd");
-	if (IS_ERR(mdp4_kms->vdd))
-		mdp4_kms->vdd = NULL;
-
-	if (mdp4_kms->vdd) {
-		ret = regulator_enable(mdp4_kms->vdd);
-		if (ret) {
-			dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret);
-			goto fail;
-		}
-	}
-
-	mdp4_kms->clk = devm_clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(mdp4_kms->clk)) {
-		dev_err(dev->dev, "failed to get core_clk\n");
-		ret = PTR_ERR(mdp4_kms->clk);
-		goto fail;
-	}
-
-	mdp4_kms->pclk = devm_clk_get(&pdev->dev, "iface_clk");
-	if (IS_ERR(mdp4_kms->pclk))
-		mdp4_kms->pclk = NULL;
-
-	// XXX if (rev >= MDP_REV_42) { ???
-	mdp4_kms->lut_clk = devm_clk_get(&pdev->dev, "lut_clk");
-	if (IS_ERR(mdp4_kms->lut_clk)) {
-		dev_err(dev->dev, "failed to get lut_clk\n");
-		ret = PTR_ERR(mdp4_kms->lut_clk);
-		goto fail;
-	}
-
-	mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
-	if (IS_ERR(mdp4_kms->axi_clk)) {
-		dev_err(dev->dev, "failed to get axi_clk\n");
-		ret = PTR_ERR(mdp4_kms->axi_clk);
-		goto fail;
-	}
-
-	clk_set_rate(mdp4_kms->clk, config->max_clk);
-	clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
-
-	pm_runtime_enable(dev->dev);
-	mdp4_kms->rpm_enabled = true;
-
-	/* make sure things are off before attaching iommu (bootloader could
-	 * have left things on, in which case we'll start getting faults if
-	 * we don't disable):
-	 */
-	mdp4_enable(mdp4_kms);
-	mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
-	mdp4_disable(mdp4_kms);
-	mdelay(16);
-
-	if (config->iommu) {
-		aspace = msm_gem_address_space_create(&pdev->dev,
-				config->iommu, "mdp4");
-		if (IS_ERR(aspace)) {
-			ret = PTR_ERR(aspace);
-			goto fail;
-		}
-
-		kms->aspace = aspace;
-
-		ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
-				ARRAY_SIZE(iommu_ports));
-		if (ret)
-			goto fail;
-	} else {
-		dev_info(dev->dev, "no iommu, fallback to phys "
-				"contig buffers for scanout\n");
-		aspace = NULL;
-	}
-
-	ret = modeset_init(mdp4_kms);
-	if (ret) {
-		dev_err(dev->dev, "modeset_init failed: %d\n", ret);
-		goto fail;
-	}
-
-	mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC);
-	if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
-		ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
-		dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
-		mdp4_kms->blank_cursor_bo = NULL;
-		goto fail;
-	}
-
-	ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, kms->aspace,
-			&mdp4_kms->blank_cursor_iova);
-	if (ret) {
-		dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
-		goto fail;
-	}
-
-	dev->mode_config.min_width = 0;
-	dev->mode_config.min_height = 0;
-	dev->mode_config.max_width = 2048;
-	dev->mode_config.max_height = 2048;
-
-	return kms;
-
-fail:
-	if (kms)
-		mdp4_destroy(kms);
-	return ERR_PTR(ret);
-}
-
-static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
-{
-	static struct mdp4_platform_config config = {};
-
-	/* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
-	config.max_clk = 266667000;
-	config.iommu = iommu_domain_alloc(&platform_bus_type);
-	if (config.iommu) {
-		config.iommu->geometry.aperture_start = 0x1000;
-		config.iommu->geometry.aperture_end = 0xffffffff;
-	}
-
-	return &config;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
deleted file mode 100644
index a1b3e31e959e..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MDP4_KMS_H__
-#define __MDP4_KMS_H__
-
-#include <drm/drm_panel.h>
-
-#include "msm_drv.h"
-#include "msm_kms.h"
-#include "mdp/mdp_kms.h"
-#include "mdp4.xml.h"
-
-struct device_node;
-
-struct mdp4_kms {
-	struct mdp_kms base;
-
-	struct drm_device *dev;
-
-	int rev;
-
-	void __iomem *mmio;
-
-	struct regulator *vdd;
-
-	struct clk *clk;
-	struct clk *pclk;
-	struct clk *lut_clk;
-	struct clk *axi_clk;
-
-	struct mdp_irq error_handler;
-
-	bool rpm_enabled;
-
-	/* empty/blank cursor bo to use when cursor is "disabled" */
-	struct drm_gem_object *blank_cursor_bo;
-	uint64_t blank_cursor_iova;
-};
-#define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base)
-
-/* platform config data (ie. from DT, or pdata) */
-struct mdp4_platform_config {
-	struct iommu_domain *iommu;
-	uint32_t max_clk;
-};
-
-static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data)
-{
-	msm_writel(data, mdp4_kms->mmio + reg);
-}
-
-static inline u32 mdp4_read(struct mdp4_kms *mdp4_kms, u32 reg)
-{
-	return msm_readl(mdp4_kms->mmio + reg);
-}
-
-static inline uint32_t pipe2flush(enum mdp4_pipe pipe)
-{
-	switch (pipe) {
-	case VG1:      return MDP4_OVERLAY_FLUSH_VG1;
-	case VG2:      return MDP4_OVERLAY_FLUSH_VG2;
-	case RGB1:     return MDP4_OVERLAY_FLUSH_RGB1;
-	case RGB2:     return MDP4_OVERLAY_FLUSH_RGB2;
-	default:       return 0;
-	}
-}
-
-static inline uint32_t ovlp2flush(int ovlp)
-{
-	switch (ovlp) {
-	case 0:        return MDP4_OVERLAY_FLUSH_OVLP0;
-	case 1:        return MDP4_OVERLAY_FLUSH_OVLP1;
-	default:       return 0;
-	}
-}
-
-static inline uint32_t dma2irq(enum mdp4_dma dma)
-{
-	switch (dma) {
-	case DMA_P:    return MDP4_IRQ_DMA_P_DONE;
-	case DMA_S:    return MDP4_IRQ_DMA_S_DONE;
-	case DMA_E:    return MDP4_IRQ_DMA_E_DONE;
-	default:       return 0;
-	}
-}
-
-static inline uint32_t dma2err(enum mdp4_dma dma)
-{
-	switch (dma) {
-	case DMA_P:    return MDP4_IRQ_PRIMARY_INTF_UDERRUN;
-	case DMA_S:    return 0;  // ???
-	case DMA_E:    return MDP4_IRQ_EXTERNAL_INTF_UDERRUN;
-	default:       return 0;
-	}
-}
-
-static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
-		enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage)
-{
-	switch (pipe) {
-	case VG1:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
-		break;
-	case VG2:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
-		break;
-	case RGB1:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
-		break;
-	case RGB2:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
-		break;
-	case RGB3:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
-		break;
-	case VG3:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
-		break;
-	case VG4:
-		mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK |
-				MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
-		mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
-			COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
-		break;
-	default:
-		WARN(1, "invalid pipe");
-		break;
-	}
-
-	return mixer_cfg;
-}
-
-int mdp4_disable(struct mdp4_kms *mdp4_kms);
-int mdp4_enable(struct mdp4_kms *mdp4_kms);
-
-void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
-		uint32_t old_irqmask);
-void mdp4_irq_preinstall(struct msm_kms *kms);
-int mdp4_irq_postinstall(struct msm_kms *kms);
-void mdp4_irq_uninstall(struct msm_kms *kms);
-irqreturn_t mdp4_irq(struct msm_kms *kms);
-int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
-void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
-
-static inline uint32_t mdp4_pipe_caps(enum mdp4_pipe pipe)
-{
-	switch (pipe) {
-	case VG1:
-	case VG2:
-	case VG3:
-	case VG4:
-		return MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
-	case RGB1:
-	case RGB2:
-	case RGB3:
-		return MDP_PIPE_CAP_SCALE;
-	default:
-		return 0;
-	}
-}
-
-enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane);
-struct drm_plane *mdp4_plane_init(struct drm_device *dev,
-		enum mdp4_pipe pipe_id, bool private_plane);
-
-uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
-void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
-void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
-void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc);
-struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
-		struct drm_plane *plane, int id, int ovlp_id,
-		enum mdp4_dma dma_id);
-
-long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
-struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
-
-long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
-struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
-		struct device_node *panel_node);
-
-struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
-		struct device_node *panel_node, struct drm_encoder *encoder);
-
-#ifdef CONFIG_DRM_MSM_DSI
-struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev);
-#else
-static inline struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
-{
-	return ERR_PTR(-ENODEV);
-}
-#endif
-
-#ifdef CONFIG_COMMON_CLK
-struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
-#else
-static inline struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
-{
-	return ERR_PTR(-ENODEV);
-}
-#endif
-
-#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
-/* bus scaling data is associated with extra pointless platform devices,
- * "dtv", etc.. this is a bit of a hack, but we need a way for encoders
- * to find their pdata to make the bus-scaling stuff work.
- */
-static inline void *mdp4_find_pdata(const char *devname)
-{
-	struct device *dev;
-	dev = bus_find_device_by_name(&platform_bus_type, NULL, devname);
-	return dev ? dev->platform_data : NULL;
-}
-#endif
-
-#endif /* __MDP4_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
deleted file mode 100644
index 4a645926edb7..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2014 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- * Author: Vinay Simha <vinaysimha@inforcecomputing.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "mdp4_kms.h"
-
-struct mdp4_lcdc_encoder {
-	struct drm_encoder base;
-	struct device_node *panel_node;
-	struct drm_panel *panel;
-	struct clk *lcdc_clk;
-	unsigned long int pixclock;
-	struct regulator *regs[3];
-	bool enabled;
-	uint32_t bsc;
-};
-#define to_mdp4_lcdc_encoder(x) container_of(x, struct mdp4_lcdc_encoder, base)
-
-static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
-{
-	struct msm_drm_private *priv = encoder->dev->dev_private;
-	return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
-#include <mach/board.h>
-static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
-{
-	struct drm_device *dev = mdp4_lcdc_encoder->base.dev;
-	struct lcdc_platform_data *lcdc_pdata = mdp4_find_pdata("lvds.0");
-
-	if (!lcdc_pdata) {
-		dev_err(dev->dev, "could not find lvds pdata\n");
-		return;
-	}
-
-	if (lcdc_pdata->bus_scale_table) {
-		mdp4_lcdc_encoder->bsc = msm_bus_scale_register_client(
-				lcdc_pdata->bus_scale_table);
-		DBG("lvds : bus scale client: %08x", mdp4_lcdc_encoder->bsc);
-	}
-}
-
-static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
-{
-	if (mdp4_lcdc_encoder->bsc) {
-		msm_bus_scale_unregister_client(mdp4_lcdc_encoder->bsc);
-		mdp4_lcdc_encoder->bsc = 0;
-	}
-}
-
-static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx)
-{
-	if (mdp4_lcdc_encoder->bsc) {
-		DBG("set bus scaling: %d", idx);
-		msm_bus_scale_client_update_request(mdp4_lcdc_encoder->bsc, idx);
-	}
-}
-#else
-static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
-static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
-static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx) {}
-#endif
-
-static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
-			to_mdp4_lcdc_encoder(encoder);
-	bs_fini(mdp4_lcdc_encoder);
-	drm_encoder_cleanup(encoder);
-	kfree(mdp4_lcdc_encoder);
-}
-
-static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = {
-	.destroy = mdp4_lcdc_encoder_destroy,
-};
-
-/* this should probably be a helper: */
-static struct drm_connector *get_connector(struct drm_encoder *encoder)
-{
-	struct drm_device *dev = encoder->dev;
-	struct drm_connector *connector;
-
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-		if (connector->encoder == encoder)
-			return connector;
-
-	return NULL;
-}
-
-static void setup_phy(struct drm_encoder *encoder)
-{
-	struct drm_device *dev = encoder->dev;
-	struct drm_connector *connector = get_connector(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	uint32_t lvds_intf = 0, lvds_phy_cfg0 = 0;
-	int bpp, nchan, swap;
-
-	if (!connector)
-		return;
-
-	bpp = 3 * connector->display_info.bpc;
-
-	if (!bpp)
-		bpp = 18;
-
-	/* TODO, these should come from panel somehow: */
-	nchan = 1;
-	swap = 0;
-
-	switch (bpp) {
-	case 24:
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x08) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x05) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x04) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x03));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x02) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x01) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x00));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x11) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x10) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0d) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0c));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0b) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0a) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x09));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x15));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x14) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x13) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x12));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(3),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1b) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x17) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x16) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0f));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(3),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0e) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x07) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x06));
-		if (nchan == 2) {
-			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
-		} else {
-			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
-		}
-		break;
-
-	case 18:
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x0a) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x07) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x06) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x05));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x04) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x03) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x02));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x13) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x12) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0f) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0e));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0d) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0c) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x0b));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
-				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x17));
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x16) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x15) |
-				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x14));
-		if (nchan == 2) {
-			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
-		} else {
-			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
-					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
-		}
-		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT;
-		break;
-
-	default:
-		dev_err(dev->dev, "unknown bpp: %d\n", bpp);
-		return;
-	}
-
-	switch (nchan) {
-	case 1:
-		lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0;
-		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN |
-				MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL;
-		break;
-	case 2:
-		lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0 |
-				MDP4_LVDS_PHY_CFG0_CHANNEL1;
-		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN |
-				MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN;
-		break;
-	default:
-		dev_err(dev->dev, "unknown # of channels: %d\n", nchan);
-		return;
-	}
-
-	if (swap)
-		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP;
-
-	lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_ENABLE;
-
-	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_INTF_CTL, lvds_intf);
-	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG2, 0x30);
-
-	mb();
-	udelay(1);
-	lvds_phy_cfg0 |= MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE;
-	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
-}
-
-static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
-		struct drm_display_mode *mode,
-		struct drm_display_mode *adjusted_mode)
-{
-	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
-			to_mdp4_lcdc_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	uint32_t lcdc_hsync_skew, vsync_period, vsync_len, ctrl_pol;
-	uint32_t display_v_start, display_v_end;
-	uint32_t hsync_start_x, hsync_end_x;
-
-	mode = adjusted_mode;
-
-	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-
-	mdp4_lcdc_encoder->pixclock = mode->clock * 1000;
-
-	DBG("pixclock=%lu", mdp4_lcdc_encoder->pixclock);
-
-	ctrl_pol = 0;
-	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-		ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW;
-	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-		ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW;
-	/* probably need to get DATA_EN polarity from panel.. */
-
-	lcdc_hsync_skew = 0;  /* get this from panel? */
-
-	hsync_start_x = (mode->htotal - mode->hsync_start);
-	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
-
-	vsync_period = mode->vtotal * mode->htotal;
-	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
-	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + lcdc_hsync_skew;
-	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + lcdc_hsync_skew - 1;
-
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_CTRL,
-			MDP4_LCDC_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
-			MDP4_LCDC_HSYNC_CTRL_PERIOD(mode->htotal));
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_PERIOD, vsync_period);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_LEN, vsync_len);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_HCTRL,
-			MDP4_LCDC_DISPLAY_HCTRL_START(hsync_start_x) |
-			MDP4_LCDC_DISPLAY_HCTRL_END(hsync_end_x));
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VSTART, display_v_start);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VEND, display_v_end);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_BORDER_CLR, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_UNDERFLOW_CLR,
-			MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY |
-			MDP4_LCDC_UNDERFLOW_CLR_COLOR(0xff));
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_SKEW, lcdc_hsync_skew);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_CTRL_POLARITY, ctrl_pol);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_HCTL,
-			MDP4_LCDC_ACTIVE_HCTL_START(0) |
-			MDP4_LCDC_ACTIVE_HCTL_END(0));
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VSTART, 0);
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
-}
-
-static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
-{
-	struct drm_device *dev = encoder->dev;
-	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
-			to_mdp4_lcdc_encoder(encoder);
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	struct drm_panel *panel;
-	int i, ret;
-
-	if (WARN_ON(!mdp4_lcdc_encoder->enabled))
-		return;
-
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
-
-	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
-	if (panel) {
-		drm_panel_disable(panel);
-		drm_panel_unprepare(panel);
-	}
-
-	/*
-	 * Wait for a vsync so we know the ENABLE=0 latched before
-	 * the (connector) source of the vsync's gets disabled,
-	 * otherwise we end up in a funny state if we re-enable
-	 * before the disable latches, which results that some of
-	 * the settings changes for the new modeset (like new
-	 * scanout buffer) don't latch properly..
-	 */
-	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
-
-	clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
-
-	for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
-		ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
-		if (ret)
-			dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
-	}
-
-	bs_set(mdp4_lcdc_encoder, 0);
-
-	mdp4_lcdc_encoder->enabled = false;
-}
-
-static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
-{
-	struct drm_device *dev = encoder->dev;
-	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
-			to_mdp4_lcdc_encoder(encoder);
-	unsigned long pc = mdp4_lcdc_encoder->pixclock;
-	struct mdp4_kms *mdp4_kms = get_kms(encoder);
-	struct drm_panel *panel;
-	int i, ret;
-
-	if (WARN_ON(mdp4_lcdc_encoder->enabled))
-		return;
-
-	/* TODO: hard-coded for 18bpp: */
-	mdp4_crtc_set_config(encoder->crtc,
-			MDP4_DMA_CONFIG_R_BPC(BPC6) |
-			MDP4_DMA_CONFIG_G_BPC(BPC6) |
-			MDP4_DMA_CONFIG_B_BPC(BPC6) |
-			MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
-			MDP4_DMA_CONFIG_PACK(0x21) |
-			MDP4_DMA_CONFIG_DEFLKR_EN |
-			MDP4_DMA_CONFIG_DITHER_EN);
-	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
-
-	bs_set(mdp4_lcdc_encoder, 1);
-
-	for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
-		ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
-		if (ret)
-			dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
-	}
-
-	DBG("setting lcdc_clk=%lu", pc);
-	ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
-	if (ret)
-		dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
-	ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
-	if (ret)
-		dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
-
-	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
-	if (panel) {
-		drm_panel_prepare(panel);
-		drm_panel_enable(panel);
-	}
-
-	setup_phy(encoder);
-
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
-
-	mdp4_lcdc_encoder->enabled = true;
-}
-
-static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
-	.mode_set = mdp4_lcdc_encoder_mode_set,
-	.disable = mdp4_lcdc_encoder_disable,
-	.enable = mdp4_lcdc_encoder_enable,
-};
-
-long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
-{
-	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
-			to_mdp4_lcdc_encoder(encoder);
-	return clk_round_rate(mdp4_lcdc_encoder->lcdc_clk, rate);
-}
-
-/* initialize encoder */
-struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
-		struct device_node *panel_node)
-{
-	struct drm_encoder *encoder = NULL;
-	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
-	struct regulator *reg;
-	int ret;
-
-	mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL);
-	if (!mdp4_lcdc_encoder) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	mdp4_lcdc_encoder->panel_node = panel_node;
-
-	encoder = &mdp4_lcdc_encoder->base;
-
-	drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs,
-			 DRM_MODE_ENCODER_LVDS, NULL);
-	drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
-
-	/* TODO: do we need different pll in other cases? */
-	mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev);
-	if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
-		dev_err(dev->dev, "failed to get lvds_clk\n");
-		ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk);
-		goto fail;
-	}
-
-	/* TODO: different regulators in other cases? */
-	reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v");
-	if (IS_ERR(reg)) {
-		ret = PTR_ERR(reg);
-		dev_err(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
-		goto fail;
-	}
-	mdp4_lcdc_encoder->regs[0] = reg;
-
-	reg = devm_regulator_get(dev->dev, "lvds-pll-vdda");
-	if (IS_ERR(reg)) {
-		ret = PTR_ERR(reg);
-		dev_err(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
-		goto fail;
-	}
-	mdp4_lcdc_encoder->regs[1] = reg;
-
-	reg = devm_regulator_get(dev->dev, "lvds-vdda");
-	if (IS_ERR(reg)) {
-		ret = PTR_ERR(reg);
-		dev_err(dev->dev, "failed to get lvds-vdda: %d\n", ret);
-		goto fail;
-	}
-	mdp4_lcdc_encoder->regs[2] = reg;
-
-	bs_init(mdp4_lcdc_encoder);
-
-	return encoder;
-
-fail:
-	if (encoder)
-		mdp4_lcdc_encoder_destroy(encoder);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
deleted file mode 100644
index e3b1c86b7aae..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2014 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- * Author: Vinay Simha <vinaysimha@inforcecomputing.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/gpio.h>
-
-#include "mdp4_kms.h"
-
-struct mdp4_lvds_connector {
-	struct drm_connector base;
-	struct drm_encoder *encoder;
-	struct device_node *panel_node;
-	struct drm_panel *panel;
-};
-#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
-
-static enum drm_connector_status mdp4_lvds_connector_detect(
-		struct drm_connector *connector, bool force)
-{
-	struct mdp4_lvds_connector *mdp4_lvds_connector =
-			to_mdp4_lvds_connector(connector);
-
-	if (!mdp4_lvds_connector->panel)
-		mdp4_lvds_connector->panel =
-			of_drm_find_panel(mdp4_lvds_connector->panel_node);
-
-	return mdp4_lvds_connector->panel ?
-			connector_status_connected :
-			connector_status_disconnected;
-}
-
-static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
-{
-	struct mdp4_lvds_connector *mdp4_lvds_connector =
-			to_mdp4_lvds_connector(connector);
-
-	drm_connector_cleanup(connector);
-
-	kfree(mdp4_lvds_connector);
-}
-
-static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
-{
-	struct mdp4_lvds_connector *mdp4_lvds_connector =
-			to_mdp4_lvds_connector(connector);
-	struct drm_panel *panel = mdp4_lvds_connector->panel;
-	int ret = 0;
-
-	if (panel) {
-		drm_panel_attach(panel, connector);
-
-		ret = panel->funcs->get_modes(panel);
-
-		drm_panel_detach(panel);
-	}
-
-	return ret;
-}
-
-static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
-				 struct drm_display_mode *mode)
-{
-	struct mdp4_lvds_connector *mdp4_lvds_connector =
-			to_mdp4_lvds_connector(connector);
-	struct drm_encoder *encoder = mdp4_lvds_connector->encoder;
-	long actual, requested;
-
-	requested = 1000 * mode->clock;
-	actual = mdp4_lcdc_round_pixclk(encoder, requested);
-
-	DBG("requested=%ld, actual=%ld", requested, actual);
-
-	if (actual != requested)
-		return MODE_CLOCK_RANGE;
-
-	return MODE_OK;
-}
-
-static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
-	.detect = mdp4_lvds_connector_detect,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = mdp4_lvds_connector_destroy,
-	.reset = drm_atomic_helper_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
-	.get_modes = mdp4_lvds_connector_get_modes,
-	.mode_valid = mdp4_lvds_connector_mode_valid,
-};
-
-/* initialize connector */
-struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
-		struct device_node *panel_node, struct drm_encoder *encoder)
-{
-	struct drm_connector *connector = NULL;
-	struct mdp4_lvds_connector *mdp4_lvds_connector;
-
-	mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL);
-	if (!mdp4_lvds_connector)
-		return ERR_PTR(-ENOMEM);
-
-	mdp4_lvds_connector->encoder = encoder;
-	mdp4_lvds_connector->panel_node = panel_node;
-
-	connector = &mdp4_lvds_connector->base;
-
-	drm_connector_init(dev, connector, &mdp4_lvds_connector_funcs,
-			DRM_MODE_CONNECTOR_LVDS);
-	drm_connector_helper_add(connector, &mdp4_lvds_connector_helper_funcs);
-
-	connector->polled = 0;
-
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-
-	drm_mode_connector_attach_encoder(connector, encoder);
-
-	return connector;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c
deleted file mode 100644
index ce4245971673..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_pll.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2014 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-
-#include "mdp4_kms.h"
-
-struct mdp4_lvds_pll {
-	struct clk_hw pll_hw;
-	struct drm_device *dev;
-	unsigned long pixclk;
-};
-#define to_mdp4_lvds_pll(x) container_of(x, struct mdp4_lvds_pll, pll_hw)
-
-static struct mdp4_kms *get_kms(struct mdp4_lvds_pll *lvds_pll)
-{
-	struct msm_drm_private *priv = lvds_pll->dev->dev_private;
-	return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-struct pll_rate {
-	unsigned long rate;
-	struct {
-		uint32_t val;
-		uint32_t reg;
-	} conf[32];
-};
-
-/* NOTE: keep sorted highest freq to lowest: */
-static const struct pll_rate freqtbl[] = {
-	{ 72000000, {
-		{ 0x8f, REG_MDP4_LVDS_PHY_PLL_CTRL_1 },
-		{ 0x30, REG_MDP4_LVDS_PHY_PLL_CTRL_2 },
-		{ 0xc6, REG_MDP4_LVDS_PHY_PLL_CTRL_3 },
-		{ 0x10, REG_MDP4_LVDS_PHY_PLL_CTRL_5 },
-		{ 0x07, REG_MDP4_LVDS_PHY_PLL_CTRL_6 },
-		{ 0x62, REG_MDP4_LVDS_PHY_PLL_CTRL_7 },
-		{ 0x41, REG_MDP4_LVDS_PHY_PLL_CTRL_8 },
-		{ 0x0d, REG_MDP4_LVDS_PHY_PLL_CTRL_9 },
-		{ 0, 0 } }
-	},
-};
-
-static const struct pll_rate *find_rate(unsigned long rate)
-{
-	int i;
-	for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
-		if (rate > freqtbl[i].rate)
-			return &freqtbl[i-1];
-	return &freqtbl[i-1];
-}
-
-static int mpd4_lvds_pll_enable(struct clk_hw *hw)
-{
-	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
-	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
-	const struct pll_rate *pll_rate = find_rate(lvds_pll->pixclk);
-	int i;
-
-	DBG("pixclk=%lu (%lu)", lvds_pll->pixclk, pll_rate->rate);
-
-	if (WARN_ON(!pll_rate))
-		return -EINVAL;
-
-	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_PHY_RESET, 0x33);
-
-	for (i = 0; pll_rate->conf[i].reg; i++)
-		mdp4_write(mdp4_kms, pll_rate->conf[i].reg, pll_rate->conf[i].val);
-
-	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x01);
-
-	/* Wait until LVDS PLL is locked and ready */
-	while (!mdp4_read(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_LOCKED))
-		cpu_relax();
-
-	return 0;
-}
-
-static void mpd4_lvds_pll_disable(struct clk_hw *hw)
-{
-	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
-	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
-
-	DBG("");
-
-	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, 0x0);
-	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
-}
-
-static unsigned long mpd4_lvds_pll_recalc_rate(struct clk_hw *hw,
-				unsigned long parent_rate)
-{
-	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
-	return lvds_pll->pixclk;
-}
-
-static long mpd4_lvds_pll_round_rate(struct clk_hw *hw, unsigned long rate,
-		unsigned long *parent_rate)
-{
-	const struct pll_rate *pll_rate = find_rate(rate);
-	return pll_rate->rate;
-}
-
-static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
-		unsigned long parent_rate)
-{
-	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
-	lvds_pll->pixclk = rate;
-	return 0;
-}
-
-
-static const struct clk_ops mpd4_lvds_pll_ops = {
-	.enable = mpd4_lvds_pll_enable,
-	.disable = mpd4_lvds_pll_disable,
-	.recalc_rate = mpd4_lvds_pll_recalc_rate,
-	.round_rate = mpd4_lvds_pll_round_rate,
-	.set_rate = mpd4_lvds_pll_set_rate,
-};
-
-static const char *mpd4_lvds_pll_parents[] = {
-	"pxo",
-};
-
-static struct clk_init_data pll_init = {
-	.name = "mpd4_lvds_pll",
-	.ops = &mpd4_lvds_pll_ops,
-	.parent_names = mpd4_lvds_pll_parents,
-	.num_parents = ARRAY_SIZE(mpd4_lvds_pll_parents),
-};
-
-struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
-{
-	struct mdp4_lvds_pll *lvds_pll;
-	struct clk *clk;
-	int ret;
-
-	lvds_pll = devm_kzalloc(dev->dev, sizeof(*lvds_pll), GFP_KERNEL);
-	if (!lvds_pll) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	lvds_pll->dev = dev;
-
-	lvds_pll->pll_hw.init = &pll_init;
-	clk = devm_clk_register(dev->dev, &lvds_pll->pll_hw);
-	if (IS_ERR(clk)) {
-		ret = PTR_ERR(clk);
-		goto fail;
-	}
-
-	return clk;
-
-fail:
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
deleted file mode 100644
index 7a1ad3af08e3..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "mdp4_kms.h"
-
-#define DOWN_SCALE_MAX	8
-#define UP_SCALE_MAX	8
-
-struct mdp4_plane {
-	struct drm_plane base;
-	const char *name;
-
-	enum mdp4_pipe pipe;
-
-	uint32_t caps;
-	uint32_t nformats;
-	uint32_t formats[32];
-
-	bool enabled;
-};
-#define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base)
-
-/* MDP format helper functions */
-static inline
-enum mdp4_frame_format mdp4_get_frame_format(struct drm_framebuffer *fb)
-{
-	bool is_tile = false;
-
-	if (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
-		is_tile = true;
-
-	if (fb->format->format == DRM_FORMAT_NV12 && is_tile)
-		return FRAME_TILE_YCBCR_420;
-
-	return FRAME_LINEAR;
-}
-
-static void mdp4_plane_set_scanout(struct drm_plane *plane,
-		struct drm_framebuffer *fb);
-static int mdp4_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h);
-
-static struct mdp4_kms *get_kms(struct drm_plane *plane)
-{
-	struct msm_drm_private *priv = plane->dev->dev_private;
-	return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-static void mdp4_plane_destroy(struct drm_plane *plane)
-{
-	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-
-	drm_plane_helper_disable(plane);
-	drm_plane_cleanup(plane);
-
-	kfree(mdp4_plane);
-}
-
-/* helper to install properties which are common to planes and crtcs */
-static void mdp4_plane_install_properties(struct drm_plane *plane,
-		struct drm_mode_object *obj)
-{
-	// XXX
-}
-
-static int mdp4_plane_set_property(struct drm_plane *plane,
-		struct drm_property *property, uint64_t val)
-{
-	// XXX
-	return -EINVAL;
-}
-
-static const struct drm_plane_funcs mdp4_plane_funcs = {
-		.update_plane = drm_atomic_helper_update_plane,
-		.disable_plane = drm_atomic_helper_disable_plane,
-		.destroy = mdp4_plane_destroy,
-		.set_property = mdp4_plane_set_property,
-		.reset = drm_atomic_helper_plane_reset,
-		.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-		.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
-
-static int mdp4_plane_prepare_fb(struct drm_plane *plane,
-				 struct drm_plane_state *new_state)
-{
-	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-	struct mdp4_kms *mdp4_kms = get_kms(plane);
-	struct msm_kms *kms = &mdp4_kms->base.base;
-	struct drm_framebuffer *fb = new_state->fb;
-
-	if (!fb)
-		return 0;
-
-	DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id);
-	return msm_framebuffer_prepare(fb, kms->aspace);
-}
-
-static void mdp4_plane_cleanup_fb(struct drm_plane *plane,
-				  struct drm_plane_state *old_state)
-{
-	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-	struct mdp4_kms *mdp4_kms = get_kms(plane);
-	struct msm_kms *kms = &mdp4_kms->base.base;
-	struct drm_framebuffer *fb = old_state->fb;
-
-	if (!fb)
-		return;
-
-	DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id);
-	msm_framebuffer_cleanup(fb, kms->aspace);
-}
-
-
-static int mdp4_plane_atomic_check(struct drm_plane *plane,
-		struct drm_plane_state *state)
-{
-	return 0;
-}
-
-static void mdp4_plane_atomic_update(struct drm_plane *plane,
-				     struct drm_plane_state *old_state)
-{
-	struct drm_plane_state *state = plane->state;
-	int ret;
-
-	ret = mdp4_plane_mode_set(plane,
-			state->crtc, state->fb,
-			state->crtc_x, state->crtc_y,
-			state->crtc_w, state->crtc_h,
-			state->src_x,  state->src_y,
-			state->src_w, state->src_h);
-	/* atomic_check should have ensured that this doesn't fail */
-	WARN_ON(ret < 0);
-}
-
-static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs = {
-		.prepare_fb = mdp4_plane_prepare_fb,
-		.cleanup_fb = mdp4_plane_cleanup_fb,
-		.atomic_check = mdp4_plane_atomic_check,
-		.atomic_update = mdp4_plane_atomic_update,
-};
-
-static void mdp4_plane_set_scanout(struct drm_plane *plane,
-		struct drm_framebuffer *fb)
-{
-	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-	struct mdp4_kms *mdp4_kms = get_kms(plane);
-	struct msm_kms *kms = &mdp4_kms->base.base;
-	enum mdp4_pipe pipe = mdp4_plane->pipe;
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe),
-			MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
-			MDP4_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_B(pipe),
-			MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
-			MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 0));
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 1));
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 2));
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 3));
-
-	plane->fb = fb;
-}
-
-static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms,
-		enum mdp4_pipe pipe, struct csc_cfg *csc)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(csc->matrix); i++) {
-		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_MV(pipe, i),
-				csc->matrix[i]);
-	}
-
-	for (i = 0; i < ARRAY_SIZE(csc->post_bias) ; i++) {
-		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_BV(pipe, i),
-				csc->pre_bias[i]);
-
-		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_BV(pipe, i),
-				csc->post_bias[i]);
-	}
-
-	for (i = 0; i < ARRAY_SIZE(csc->post_clamp) ; i++) {
-		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_LV(pipe, i),
-				csc->pre_clamp[i]);
-
-		mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_LV(pipe, i),
-				csc->post_clamp[i]);
-	}
-}
-
-#define MDP4_VG_PHASE_STEP_DEFAULT	0x20000000
-
-static int mdp4_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h)
-{
-	struct drm_device *dev = plane->dev;
-	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-	struct mdp4_kms *mdp4_kms = get_kms(plane);
-	enum mdp4_pipe pipe = mdp4_plane->pipe;
-	const struct mdp_format *format;
-	uint32_t op_mode = 0;
-	uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
-	uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
-	enum mdp4_frame_format frame_type;
-
-	if (!(crtc && fb)) {
-		DBG("%s: disabled!", mdp4_plane->name);
-		return 0;
-	}
-
-	frame_type = mdp4_get_frame_format(fb);
-
-	/* src values are in Q16 fixed point, convert to integer: */
-	src_x = src_x >> 16;
-	src_y = src_y >> 16;
-	src_w = src_w >> 16;
-	src_h = src_h >> 16;
-
-	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name,
-			fb->base.id, src_x, src_y, src_w, src_h,
-			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
-
-	format = to_mdp_format(msm_framebuffer_format(fb));
-
-	if (src_w > (crtc_w * DOWN_SCALE_MAX)) {
-		dev_err(dev->dev, "Width down scaling exceeds limits!\n");
-		return -ERANGE;
-	}
-
-	if (src_h > (crtc_h * DOWN_SCALE_MAX)) {
-		dev_err(dev->dev, "Height down scaling exceeds limits!\n");
-		return -ERANGE;
-	}
-
-	if (crtc_w > (src_w * UP_SCALE_MAX)) {
-		dev_err(dev->dev, "Width up scaling exceeds limits!\n");
-		return -ERANGE;
-	}
-
-	if (crtc_h > (src_h * UP_SCALE_MAX)) {
-		dev_err(dev->dev, "Height up scaling exceeds limits!\n");
-		return -ERANGE;
-	}
-
-	if (src_w != crtc_w) {
-		uint32_t sel_unit = SCALE_FIR;
-		op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN;
-
-		if (MDP_FORMAT_IS_YUV(format)) {
-			if (crtc_w > src_w)
-				sel_unit = SCALE_PIXEL_RPT;
-			else if (crtc_w <= (src_w / 4))
-				sel_unit = SCALE_MN_PHASE;
-
-			op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit);
-			phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT,
-					src_w, crtc_w);
-		}
-	}
-
-	if (src_h != crtc_h) {
-		uint32_t sel_unit = SCALE_FIR;
-		op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN;
-
-		if (MDP_FORMAT_IS_YUV(format)) {
-
-			if (crtc_h > src_h)
-				sel_unit = SCALE_PIXEL_RPT;
-			else if (crtc_h <= (src_h / 4))
-				sel_unit = SCALE_MN_PHASE;
-
-			op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit);
-			phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT,
-					src_h, crtc_h);
-		}
-	}
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe),
-			MDP4_PIPE_SRC_SIZE_WIDTH(src_w) |
-			MDP4_PIPE_SRC_SIZE_HEIGHT(src_h));
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe),
-			MDP4_PIPE_SRC_XY_X(src_x) |
-			MDP4_PIPE_SRC_XY_Y(src_y));
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe),
-			MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) |
-			MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h));
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe),
-			MDP4_PIPE_DST_XY_X(crtc_x) |
-			MDP4_PIPE_DST_XY_Y(crtc_y));
-
-	mdp4_plane_set_scanout(plane, fb);
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe),
-			MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
-			MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
-			MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
-			MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
-			COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
-			MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
-			MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
-			MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) |
-			MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) |
-			MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type) |
-			COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT));
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe),
-			MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
-			MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
-			MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
-			MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
-
-	if (MDP_FORMAT_IS_YUV(format)) {
-		struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB);
-
-		op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR;
-		op_mode |= MDP4_PIPE_OP_MODE_CSC_EN;
-		mdp4_write_csc_config(mdp4_kms, pipe, csc);
-	}
-
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode);
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
-	mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
-
-	if (frame_type != FRAME_LINEAR)
-		mdp4_write(mdp4_kms, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe),
-				MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w) |
-				MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h));
-
-	return 0;
-}
-
-static const char *pipe_names[] = {
-		"VG1", "VG2",
-		"RGB1", "RGB2", "RGB3",
-		"VG3", "VG4",
-};
-
-enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane)
-{
-	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-	return mdp4_plane->pipe;
-}
-
-/* initialize plane */
-struct drm_plane *mdp4_plane_init(struct drm_device *dev,
-		enum mdp4_pipe pipe_id, bool private_plane)
-{
-	struct drm_plane *plane = NULL;
-	struct mdp4_plane *mdp4_plane;
-	int ret;
-	enum drm_plane_type type;
-
-	mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL);
-	if (!mdp4_plane) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	plane = &mdp4_plane->base;
-
-	mdp4_plane->pipe = pipe_id;
-	mdp4_plane->name = pipe_names[pipe_id];
-	mdp4_plane->caps = mdp4_pipe_caps(pipe_id);
-
-	mdp4_plane->nformats = mdp_get_formats(mdp4_plane->formats,
-			ARRAY_SIZE(mdp4_plane->formats),
-			!pipe_supports_yuv(mdp4_plane->caps));
-
-	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
-	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
-				 mdp4_plane->formats, mdp4_plane->nformats,
-				 NULL, type, NULL);
-	if (ret)
-		goto fail;
-
-	drm_plane_helper_add(plane, &mdp4_plane_helper_funcs);
-
-	mdp4_plane_install_properties(plane, &plane->base);
-
-	return plane;
-
-fail:
-	if (plane)
-		mdp4_plane_destroy(plane);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
deleted file mode 100644
index d9c10e02ee41..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
+++ /dev/null
@@ -1,1968 +0,0 @@
-#ifndef MDP5_XML
-#define MDP5_XML
-
-/* Autogenerated file, DO NOT EDIT manually!
-
-This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://github.com/freedreno/envytools/
-git clone https://github.com/freedreno/envytools.git
-
-The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
-
-Copyright (C) 2013-2017 by the following authors:
-- Rob Clark <robdclark@gmail.com> (robclark)
-- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice (including the
-next paragraph) shall be included in all copies or substantial
-portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-
-enum mdp5_intf_type {
-	INTF_DISABLED = 0,
-	INTF_DSI = 1,
-	INTF_HDMI = 3,
-	INTF_LCDC = 5,
-	INTF_eDP = 9,
-	INTF_VIRTUAL = 100,
-	INTF_WB = 101,
-};
-
-enum mdp5_intfnum {
-	NO_INTF = 0,
-	INTF0 = 1,
-	INTF1 = 2,
-	INTF2 = 3,
-	INTF3 = 4,
-};
-
-enum mdp5_pipe {
-	SSPP_NONE = 0,
-	SSPP_VIG0 = 1,
-	SSPP_VIG1 = 2,
-	SSPP_VIG2 = 3,
-	SSPP_RGB0 = 4,
-	SSPP_RGB1 = 5,
-	SSPP_RGB2 = 6,
-	SSPP_DMA0 = 7,
-	SSPP_DMA1 = 8,
-	SSPP_VIG3 = 9,
-	SSPP_RGB3 = 10,
-	SSPP_CURSOR0 = 11,
-	SSPP_CURSOR1 = 12,
-};
-
-enum mdp5_ctl_mode {
-	MODE_NONE = 0,
-	MODE_WB_0_BLOCK = 1,
-	MODE_WB_1_BLOCK = 2,
-	MODE_WB_0_LINE = 3,
-	MODE_WB_1_LINE = 4,
-	MODE_WB_2_LINE = 5,
-};
-
-enum mdp5_pack_3d {
-	PACK_3D_FRAME_INT = 0,
-	PACK_3D_H_ROW_INT = 1,
-	PACK_3D_V_ROW_INT = 2,
-	PACK_3D_COL_INT = 3,
-};
-
-enum mdp5_scale_filter {
-	SCALE_FILTER_NEAREST = 0,
-	SCALE_FILTER_BIL = 1,
-	SCALE_FILTER_PCMN = 2,
-	SCALE_FILTER_CA = 3,
-};
-
-enum mdp5_pipe_bwc {
-	BWC_LOSSLESS = 0,
-	BWC_Q_HIGH = 1,
-	BWC_Q_MED = 2,
-};
-
-enum mdp5_cursor_format {
-	CURSOR_FMT_ARGB8888 = 0,
-	CURSOR_FMT_ARGB1555 = 2,
-	CURSOR_FMT_ARGB4444 = 4,
-};
-
-enum mdp5_cursor_alpha {
-	CURSOR_ALPHA_CONST = 0,
-	CURSOR_ALPHA_PER_PIXEL = 2,
-};
-
-enum mdp5_igc_type {
-	IGC_VIG = 0,
-	IGC_RGB = 1,
-	IGC_DMA = 2,
-	IGC_DSPP = 3,
-};
-
-enum mdp5_data_format {
-	DATA_FORMAT_RGB = 0,
-	DATA_FORMAT_YUV = 1,
-};
-
-enum mdp5_block_size {
-	BLOCK_SIZE_64 = 0,
-	BLOCK_SIZE_128 = 1,
-};
-
-enum mdp5_rotate_mode {
-	ROTATE_0 = 0,
-	ROTATE_90 = 1,
-};
-
-enum mdp5_chroma_downsample_method {
-	DS_MTHD_NO_PIXEL_DROP = 0,
-	DS_MTHD_PIXEL_DROP = 1,
-};
-
-#define MDP5_IRQ_WB_0_DONE					0x00000001
-#define MDP5_IRQ_WB_1_DONE					0x00000002
-#define MDP5_IRQ_WB_2_DONE					0x00000010
-#define MDP5_IRQ_PING_PONG_0_DONE				0x00000100
-#define MDP5_IRQ_PING_PONG_1_DONE				0x00000200
-#define MDP5_IRQ_PING_PONG_2_DONE				0x00000400
-#define MDP5_IRQ_PING_PONG_3_DONE				0x00000800
-#define MDP5_IRQ_PING_PONG_0_RD_PTR				0x00001000
-#define MDP5_IRQ_PING_PONG_1_RD_PTR				0x00002000
-#define MDP5_IRQ_PING_PONG_2_RD_PTR				0x00004000
-#define MDP5_IRQ_PING_PONG_3_RD_PTR				0x00008000
-#define MDP5_IRQ_PING_PONG_0_WR_PTR				0x00010000
-#define MDP5_IRQ_PING_PONG_1_WR_PTR				0x00020000
-#define MDP5_IRQ_PING_PONG_2_WR_PTR				0x00040000
-#define MDP5_IRQ_PING_PONG_3_WR_PTR				0x00080000
-#define MDP5_IRQ_PING_PONG_0_AUTO_REF				0x00100000
-#define MDP5_IRQ_PING_PONG_1_AUTO_REF				0x00200000
-#define MDP5_IRQ_PING_PONG_2_AUTO_REF				0x00400000
-#define MDP5_IRQ_PING_PONG_3_AUTO_REF				0x00800000
-#define MDP5_IRQ_INTF0_UNDER_RUN				0x01000000
-#define MDP5_IRQ_INTF0_VSYNC					0x02000000
-#define MDP5_IRQ_INTF1_UNDER_RUN				0x04000000
-#define MDP5_IRQ_INTF1_VSYNC					0x08000000
-#define MDP5_IRQ_INTF2_UNDER_RUN				0x10000000
-#define MDP5_IRQ_INTF2_VSYNC					0x20000000
-#define MDP5_IRQ_INTF3_UNDER_RUN				0x40000000
-#define MDP5_IRQ_INTF3_VSYNC					0x80000000
-#define REG_MDSS_HW_VERSION					0x00000000
-#define MDSS_HW_VERSION_STEP__MASK				0x0000ffff
-#define MDSS_HW_VERSION_STEP__SHIFT				0
-static inline uint32_t MDSS_HW_VERSION_STEP(uint32_t val)
-{
-	return ((val) << MDSS_HW_VERSION_STEP__SHIFT) & MDSS_HW_VERSION_STEP__MASK;
-}
-#define MDSS_HW_VERSION_MINOR__MASK				0x0fff0000
-#define MDSS_HW_VERSION_MINOR__SHIFT				16
-static inline uint32_t MDSS_HW_VERSION_MINOR(uint32_t val)
-{
-	return ((val) << MDSS_HW_VERSION_MINOR__SHIFT) & MDSS_HW_VERSION_MINOR__MASK;
-}
-#define MDSS_HW_VERSION_MAJOR__MASK				0xf0000000
-#define MDSS_HW_VERSION_MAJOR__SHIFT				28
-static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val)
-{
-	return ((val) << MDSS_HW_VERSION_MAJOR__SHIFT) & MDSS_HW_VERSION_MAJOR__MASK;
-}
-
-#define REG_MDSS_HW_INTR_STATUS					0x00000010
-#define MDSS_HW_INTR_STATUS_INTR_MDP				0x00000001
-#define MDSS_HW_INTR_STATUS_INTR_DSI0				0x00000010
-#define MDSS_HW_INTR_STATUS_INTR_DSI1				0x00000020
-#define MDSS_HW_INTR_STATUS_INTR_HDMI				0x00000100
-#define MDSS_HW_INTR_STATUS_INTR_EDP				0x00001000
-
-#define REG_MDP5_HW_VERSION					0x00000000
-#define MDP5_HW_VERSION_STEP__MASK				0x0000ffff
-#define MDP5_HW_VERSION_STEP__SHIFT				0
-static inline uint32_t MDP5_HW_VERSION_STEP(uint32_t val)
-{
-	return ((val) << MDP5_HW_VERSION_STEP__SHIFT) & MDP5_HW_VERSION_STEP__MASK;
-}
-#define MDP5_HW_VERSION_MINOR__MASK				0x0fff0000
-#define MDP5_HW_VERSION_MINOR__SHIFT				16
-static inline uint32_t MDP5_HW_VERSION_MINOR(uint32_t val)
-{
-	return ((val) << MDP5_HW_VERSION_MINOR__SHIFT) & MDP5_HW_VERSION_MINOR__MASK;
-}
-#define MDP5_HW_VERSION_MAJOR__MASK				0xf0000000
-#define MDP5_HW_VERSION_MAJOR__SHIFT				28
-static inline uint32_t MDP5_HW_VERSION_MAJOR(uint32_t val)
-{
-	return ((val) << MDP5_HW_VERSION_MAJOR__SHIFT) & MDP5_HW_VERSION_MAJOR__MASK;
-}
-
-#define REG_MDP5_DISP_INTF_SEL					0x00000004
-#define MDP5_DISP_INTF_SEL_INTF0__MASK				0x000000ff
-#define MDP5_DISP_INTF_SEL_INTF0__SHIFT				0
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val)
-{
-	return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK;
-}
-#define MDP5_DISP_INTF_SEL_INTF1__MASK				0x0000ff00
-#define MDP5_DISP_INTF_SEL_INTF1__SHIFT				8
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val)
-{
-	return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK;
-}
-#define MDP5_DISP_INTF_SEL_INTF2__MASK				0x00ff0000
-#define MDP5_DISP_INTF_SEL_INTF2__SHIFT				16
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val)
-{
-	return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK;
-}
-#define MDP5_DISP_INTF_SEL_INTF3__MASK				0xff000000
-#define MDP5_DISP_INTF_SEL_INTF3__SHIFT				24
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val)
-{
-	return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK;
-}
-
-#define REG_MDP5_INTR_EN					0x00000010
-
-#define REG_MDP5_INTR_STATUS					0x00000014
-
-#define REG_MDP5_INTR_CLEAR					0x00000018
-
-#define REG_MDP5_HIST_INTR_EN					0x0000001c
-
-#define REG_MDP5_HIST_INTR_STATUS				0x00000020
-
-#define REG_MDP5_HIST_INTR_CLEAR				0x00000024
-
-#define REG_MDP5_SPARE_0					0x00000028
-#define MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN			0x00000001
-
-static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000080 + 0x4*i0; }
-
-static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000080 + 0x4*i0; }
-#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK			0x000000ff
-#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT			0
-static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(uint32_t val)
-{
-	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
-}
-#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK			0x0000ff00
-#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT			8
-static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(uint32_t val)
-{
-	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
-}
-#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK			0x00ff0000
-#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT			16
-static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(uint32_t val)
-{
-	return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
-}
-
-static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000130 + 0x4*i0; }
-
-static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000130 + 0x4*i0; }
-#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK			0x000000ff
-#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT			0
-static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(uint32_t val)
-{
-	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK;
-}
-#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK			0x0000ff00
-#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT			8
-static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(uint32_t val)
-{
-	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK;
-}
-#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK			0x00ff0000
-#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT			16
-static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(uint32_t val)
-{
-	return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK;
-}
-
-static inline uint32_t __offset_IGC(enum mdp5_igc_type idx)
-{
-	switch (idx) {
-		case IGC_VIG: return 0x00000200;
-		case IGC_RGB: return 0x00000210;
-		case IGC_DMA: return 0x00000220;
-		case IGC_DSPP: return 0x00000300;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); }
-
-static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
-#define MDP5_IGC_LUT_REG_VAL__MASK				0x00000fff
-#define MDP5_IGC_LUT_REG_VAL__SHIFT				0
-static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val)
-{
-	return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK;
-}
-#define MDP5_IGC_LUT_REG_INDEX_UPDATE				0x02000000
-#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0				0x10000000
-#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1				0x20000000
-#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2				0x40000000
-
-#define REG_MDP5_SPLIT_DPL_EN					0x000002f4
-
-#define REG_MDP5_SPLIT_DPL_UPPER				0x000002f8
-#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL			0x00000002
-#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN		0x00000004
-#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX			0x00000010
-#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX			0x00000100
-
-#define REG_MDP5_SPLIT_DPL_LOWER				0x000003f0
-#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL			0x00000002
-#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN		0x00000004
-#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC			0x00000010
-#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC			0x00000100
-
-static inline uint32_t __offset_CTL(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return (mdp5_cfg->ctl.base[0]);
-		case 1: return (mdp5_cfg->ctl.base[1]);
-		case 2: return (mdp5_cfg->ctl.base[2]);
-		case 3: return (mdp5_cfg->ctl.base[3]);
-		case 4: return (mdp5_cfg->ctl.base[4]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_CTL(uint32_t i0) { return 0x00000000 + __offset_CTL(i0); }
-
-static inline uint32_t __offset_LAYER(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return 0x00000000;
-		case 1: return 0x00000004;
-		case 2: return 0x00000008;
-		case 3: return 0x0000000c;
-		case 4: return 0x00000010;
-		case 5: return 0x00000024;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER(i1); }
-
-static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER(i1); }
-#define MDP5_CTL_LAYER_REG_VIG0__MASK				0x00000007
-#define MDP5_CTL_LAYER_REG_VIG0__SHIFT				0
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_VIG0__SHIFT) & MDP5_CTL_LAYER_REG_VIG0__MASK;
-}
-#define MDP5_CTL_LAYER_REG_VIG1__MASK				0x00000038
-#define MDP5_CTL_LAYER_REG_VIG1__SHIFT				3
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_VIG1__SHIFT) & MDP5_CTL_LAYER_REG_VIG1__MASK;
-}
-#define MDP5_CTL_LAYER_REG_VIG2__MASK				0x000001c0
-#define MDP5_CTL_LAYER_REG_VIG2__SHIFT				6
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_VIG2__SHIFT) & MDP5_CTL_LAYER_REG_VIG2__MASK;
-}
-#define MDP5_CTL_LAYER_REG_RGB0__MASK				0x00000e00
-#define MDP5_CTL_LAYER_REG_RGB0__SHIFT				9
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_RGB0__SHIFT) & MDP5_CTL_LAYER_REG_RGB0__MASK;
-}
-#define MDP5_CTL_LAYER_REG_RGB1__MASK				0x00007000
-#define MDP5_CTL_LAYER_REG_RGB1__SHIFT				12
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_RGB1__SHIFT) & MDP5_CTL_LAYER_REG_RGB1__MASK;
-}
-#define MDP5_CTL_LAYER_REG_RGB2__MASK				0x00038000
-#define MDP5_CTL_LAYER_REG_RGB2__SHIFT				15
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_RGB2__SHIFT) & MDP5_CTL_LAYER_REG_RGB2__MASK;
-}
-#define MDP5_CTL_LAYER_REG_DMA0__MASK				0x001c0000
-#define MDP5_CTL_LAYER_REG_DMA0__SHIFT				18
-static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_DMA0__SHIFT) & MDP5_CTL_LAYER_REG_DMA0__MASK;
-}
-#define MDP5_CTL_LAYER_REG_DMA1__MASK				0x00e00000
-#define MDP5_CTL_LAYER_REG_DMA1__SHIFT				21
-static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK;
-}
-#define MDP5_CTL_LAYER_REG_BORDER_COLOR				0x01000000
-#define MDP5_CTL_LAYER_REG_CURSOR_OUT				0x02000000
-#define MDP5_CTL_LAYER_REG_VIG3__MASK				0x1c000000
-#define MDP5_CTL_LAYER_REG_VIG3__SHIFT				26
-static inline uint32_t MDP5_CTL_LAYER_REG_VIG3(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_VIG3__SHIFT) & MDP5_CTL_LAYER_REG_VIG3__MASK;
-}
-#define MDP5_CTL_LAYER_REG_RGB3__MASK				0xe0000000
-#define MDP5_CTL_LAYER_REG_RGB3__SHIFT				29
-static inline uint32_t MDP5_CTL_LAYER_REG_RGB3(uint32_t val)
-{
-	return ((val) << MDP5_CTL_LAYER_REG_RGB3__SHIFT) & MDP5_CTL_LAYER_REG_RGB3__MASK;
-}
-
-static inline uint32_t REG_MDP5_CTL_OP(uint32_t i0) { return 0x00000014 + __offset_CTL(i0); }
-#define MDP5_CTL_OP_MODE__MASK					0x0000000f
-#define MDP5_CTL_OP_MODE__SHIFT					0
-static inline uint32_t MDP5_CTL_OP_MODE(enum mdp5_ctl_mode val)
-{
-	return ((val) << MDP5_CTL_OP_MODE__SHIFT) & MDP5_CTL_OP_MODE__MASK;
-}
-#define MDP5_CTL_OP_INTF_NUM__MASK				0x00000070
-#define MDP5_CTL_OP_INTF_NUM__SHIFT				4
-static inline uint32_t MDP5_CTL_OP_INTF_NUM(enum mdp5_intfnum val)
-{
-	return ((val) << MDP5_CTL_OP_INTF_NUM__SHIFT) & MDP5_CTL_OP_INTF_NUM__MASK;
-}
-#define MDP5_CTL_OP_CMD_MODE					0x00020000
-#define MDP5_CTL_OP_PACK_3D_ENABLE				0x00080000
-#define MDP5_CTL_OP_PACK_3D__MASK				0x00300000
-#define MDP5_CTL_OP_PACK_3D__SHIFT				20
-static inline uint32_t MDP5_CTL_OP_PACK_3D(enum mdp5_pack_3d val)
-{
-	return ((val) << MDP5_CTL_OP_PACK_3D__SHIFT) & MDP5_CTL_OP_PACK_3D__MASK;
-}
-
-static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000018 + __offset_CTL(i0); }
-#define MDP5_CTL_FLUSH_VIG0					0x00000001
-#define MDP5_CTL_FLUSH_VIG1					0x00000002
-#define MDP5_CTL_FLUSH_VIG2					0x00000004
-#define MDP5_CTL_FLUSH_RGB0					0x00000008
-#define MDP5_CTL_FLUSH_RGB1					0x00000010
-#define MDP5_CTL_FLUSH_RGB2					0x00000020
-#define MDP5_CTL_FLUSH_LM0					0x00000040
-#define MDP5_CTL_FLUSH_LM1					0x00000080
-#define MDP5_CTL_FLUSH_LM2					0x00000100
-#define MDP5_CTL_FLUSH_LM3					0x00000200
-#define MDP5_CTL_FLUSH_LM4					0x00000400
-#define MDP5_CTL_FLUSH_DMA0					0x00000800
-#define MDP5_CTL_FLUSH_DMA1					0x00001000
-#define MDP5_CTL_FLUSH_DSPP0					0x00002000
-#define MDP5_CTL_FLUSH_DSPP1					0x00004000
-#define MDP5_CTL_FLUSH_DSPP2					0x00008000
-#define MDP5_CTL_FLUSH_WB					0x00010000
-#define MDP5_CTL_FLUSH_CTL					0x00020000
-#define MDP5_CTL_FLUSH_VIG3					0x00040000
-#define MDP5_CTL_FLUSH_RGB3					0x00080000
-#define MDP5_CTL_FLUSH_LM5					0x00100000
-#define MDP5_CTL_FLUSH_DSPP3					0x00200000
-#define MDP5_CTL_FLUSH_CURSOR_0					0x00400000
-#define MDP5_CTL_FLUSH_CURSOR_1					0x00800000
-#define MDP5_CTL_FLUSH_CHROMADOWN_0				0x04000000
-#define MDP5_CTL_FLUSH_TIMING_3					0x10000000
-#define MDP5_CTL_FLUSH_TIMING_2					0x20000000
-#define MDP5_CTL_FLUSH_TIMING_1					0x40000000
-#define MDP5_CTL_FLUSH_TIMING_0					0x80000000
-
-static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __offset_CTL(i0); }
-
-static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000020 + __offset_CTL(i0); }
-
-static inline uint32_t __offset_LAYER_EXT(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return 0x00000040;
-		case 1: return 0x00000044;
-		case 2: return 0x00000048;
-		case 3: return 0x0000004c;
-		case 4: return 0x00000050;
-		case 5: return 0x00000054;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_CTL_LAYER_EXT(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
-
-static inline uint32_t REG_MDP5_CTL_LAYER_EXT_REG(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_CTL(i0) + __offset_LAYER_EXT(i1); }
-#define MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3			0x00000001
-#define MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3			0x00000004
-#define MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3			0x00000010
-#define MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3			0x00000040
-#define MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3			0x00000100
-#define MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3			0x00000400
-#define MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3			0x00001000
-#define MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3			0x00004000
-#define MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3			0x00010000
-#define MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3			0x00040000
-#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK			0x00f00000
-#define MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT			20
-static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR0(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR0__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR0__MASK;
-}
-#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK			0x3c000000
-#define MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT			26
-static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR1(enum mdp_mixer_stage_id val)
-{
-	return ((val) << MDP5_CTL_LAYER_EXT_REG_CURSOR1__SHIFT) & MDP5_CTL_LAYER_EXT_REG_CURSOR1__MASK;
-}
-
-static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
-{
-	switch (idx) {
-		case SSPP_NONE: return (INVALID_IDX(idx));
-		case SSPP_VIG0: return (mdp5_cfg->pipe_vig.base[0]);
-		case SSPP_VIG1: return (mdp5_cfg->pipe_vig.base[1]);
-		case SSPP_VIG2: return (mdp5_cfg->pipe_vig.base[2]);
-		case SSPP_RGB0: return (mdp5_cfg->pipe_rgb.base[0]);
-		case SSPP_RGB1: return (mdp5_cfg->pipe_rgb.base[1]);
-		case SSPP_RGB2: return (mdp5_cfg->pipe_rgb.base[2]);
-		case SSPP_DMA0: return (mdp5_cfg->pipe_dma.base[0]);
-		case SSPP_DMA1: return (mdp5_cfg->pipe_dma.base[1]);
-		case SSPP_VIG3: return (mdp5_cfg->pipe_vig.base[3]);
-		case SSPP_RGB3: return (mdp5_cfg->pipe_rgb.base[3]);
-		case SSPP_CURSOR0: return (mdp5_cfg->pipe_cursor.base[0]);
-		case SSPP_CURSOR1: return (mdp5_cfg->pipe_cursor.base[1]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_OP_MODE(enum mdp5_pipe i0) { return 0x00000200 + __offset_PIPE(i0); }
-#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK		0x00080000
-#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT		19
-static inline uint32_t MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(enum mdp5_data_format val)
-{
-	return ((val) << MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK;
-}
-#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK		0x00040000
-#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT		18
-static inline uint32_t MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(enum mdp5_data_format val)
-{
-	return ((val) << MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK;
-}
-#define MDP5_PIPE_OP_MODE_CSC_1_EN				0x00020000
-
-static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000002c4 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000002f0 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00000300 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(enum mdp5_pipe i0) { return 0x00000320 + __offset_PIPE(i0); }
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK		0x00001fff
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK;
-}
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK		0x1fff0000
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT		16
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(enum mdp5_pipe i0) { return 0x00000324 + __offset_PIPE(i0); }
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK		0x00001fff
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK;
-}
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK		0x1fff0000
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT		16
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(enum mdp5_pipe i0) { return 0x00000328 + __offset_PIPE(i0); }
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK		0x00001fff
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK;
-}
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK		0x1fff0000
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT		16
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(enum mdp5_pipe i0) { return 0x0000032c + __offset_PIPE(i0); }
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK		0x00001fff
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK;
-}
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK		0x1fff0000
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT		16
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(enum mdp5_pipe i0) { return 0x00000330 + __offset_PIPE(i0); }
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK		0x00001fff
-#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; }
-#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK		0x000000ff
-#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK;
-}
-#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK			0x0000ff00
-#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT		8
-static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; }
-#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK		0x000000ff
-#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK;
-}
-#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK		0x0000ff00
-#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT		8
-static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; }
-#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK		0x000001ff
-#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; }
-#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK		0x000001ff
-#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT		0
-static inline uint32_t MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT			16
-static inline uint32_t MDP5_PIPE_SRC_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_SIZE_HEIGHT__MASK;
-}
-#define MDP5_PIPE_SRC_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP5_PIPE_SRC_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC_IMG_SIZE(enum mdp5_pipe i0) { return 0x00000004 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK			0xffff0000
-#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT			16
-static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK;
-}
-#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK			0x0000ffff
-#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT			0
-static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC_XY(enum mdp5_pipe i0) { return 0x00000008 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_XY_Y__MASK				0xffff0000
-#define MDP5_PIPE_SRC_XY_Y__SHIFT				16
-static inline uint32_t MDP5_PIPE_SRC_XY_Y(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_XY_Y__SHIFT) & MDP5_PIPE_SRC_XY_Y__MASK;
-}
-#define MDP5_PIPE_SRC_XY_X__MASK				0x0000ffff
-#define MDP5_PIPE_SRC_XY_X__SHIFT				0
-static inline uint32_t MDP5_PIPE_SRC_XY_X(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_XY_X__SHIFT) & MDP5_PIPE_SRC_XY_X__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_OUT_SIZE(enum mdp5_pipe i0) { return 0x0000000c + __offset_PIPE(i0); }
-#define MDP5_PIPE_OUT_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT			16
-static inline uint32_t MDP5_PIPE_OUT_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_OUT_SIZE_HEIGHT__MASK;
-}
-#define MDP5_PIPE_OUT_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP5_PIPE_OUT_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT) & MDP5_PIPE_OUT_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_OUT_XY(enum mdp5_pipe i0) { return 0x00000010 + __offset_PIPE(i0); }
-#define MDP5_PIPE_OUT_XY_Y__MASK				0xffff0000
-#define MDP5_PIPE_OUT_XY_Y__SHIFT				16
-static inline uint32_t MDP5_PIPE_OUT_XY_Y(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_OUT_XY_Y__SHIFT) & MDP5_PIPE_OUT_XY_Y__MASK;
-}
-#define MDP5_PIPE_OUT_XY_X__MASK				0x0000ffff
-#define MDP5_PIPE_OUT_XY_X__SHIFT				0
-static inline uint32_t MDP5_PIPE_OUT_XY_X(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_OUT_XY_X__SHIFT) & MDP5_PIPE_OUT_XY_X__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC0_ADDR(enum mdp5_pipe i0) { return 0x00000014 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SRC1_ADDR(enum mdp5_pipe i0) { return 0x00000018 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SRC2_ADDR(enum mdp5_pipe i0) { return 0x0000001c + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SRC3_ADDR(enum mdp5_pipe i0) { return 0x00000020 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_A(enum mdp5_pipe i0) { return 0x00000024 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_STRIDE_A_P0__MASK				0x0000ffff
-#define MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT			0
-static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P0(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P0__MASK;
-}
-#define MDP5_PIPE_SRC_STRIDE_A_P1__MASK				0xffff0000
-#define MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT			16
-static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P1(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P1__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_B(enum mdp5_pipe i0) { return 0x00000028 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_STRIDE_B_P2__MASK				0x0000ffff
-#define MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT			0
-static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P2(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P2__MASK;
-}
-#define MDP5_PIPE_SRC_STRIDE_B_P3__MASK				0xffff0000
-#define MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT			16
-static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P3(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P3__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_STILE_FRAME_SIZE(enum mdp5_pipe i0) { return 0x0000002c + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SRC_FORMAT(enum mdp5_pipe i0) { return 0x00000030 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_FORMAT_G_BPC__MASK			0x00000003
-#define MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT			0
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_G_BPC__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_B_BPC__MASK			0x0000000c
-#define MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT			2
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_B_BPC__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_R_BPC__MASK			0x00000030
-#define MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT			4
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_R_BPC__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_A_BPC__MASK			0x000000c0
-#define MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT			6
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_A_BPC__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE			0x00000100
-#define MDP5_PIPE_SRC_FORMAT_CPP__MASK				0x00000600
-#define MDP5_PIPE_SRC_FORMAT_CPP__SHIFT				9
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_CPP(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CPP__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_ROT90				0x00000800
-#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK			0x00003000
-#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT		12
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000
-#define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000
-#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK			0x00180000
-#define MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT			19
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(enum mdp_fetch_type val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__SHIFT) & MDP5_PIPE_SRC_FORMAT_FETCH_TYPE__MASK;
-}
-#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK			0x01800000
-#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT			23
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val)
-{
-	return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC_UNPACK(enum mdp5_pipe i0) { return 0x00000034 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_UNPACK_ELEM0__MASK			0x000000ff
-#define MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT			0
-static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM0(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM0__MASK;
-}
-#define MDP5_PIPE_SRC_UNPACK_ELEM1__MASK			0x0000ff00
-#define MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT			8
-static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM1(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM1__MASK;
-}
-#define MDP5_PIPE_SRC_UNPACK_ELEM2__MASK			0x00ff0000
-#define MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT			16
-static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM2(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM2__MASK;
-}
-#define MDP5_PIPE_SRC_UNPACK_ELEM3__MASK			0xff000000
-#define MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT			24
-static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM3__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SRC_OP_MODE(enum mdp5_pipe i0) { return 0x00000038 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SRC_OP_MODE_BWC_EN				0x00000001
-#define MDP5_PIPE_SRC_OP_MODE_BWC__MASK				0x00000006
-#define MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT			1
-static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val)
-{
-	return ((val) << MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT) & MDP5_PIPE_SRC_OP_MODE_BWC__MASK;
-}
-#define MDP5_PIPE_SRC_OP_MODE_FLIP_LR				0x00002000
-#define MDP5_PIPE_SRC_OP_MODE_FLIP_UD				0x00004000
-#define MDP5_PIPE_SRC_OP_MODE_IGC_EN				0x00010000
-#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_0				0x00020000
-#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1				0x00040000
-#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE			0x00400000
-#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD			0x00800000
-#define MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE		0x80000000
-
-static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000003c + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_FETCH_CONFIG(enum mdp5_pipe i0) { return 0x00000048 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_VC1_RANGE(enum mdp5_pipe i0) { return 0x0000004c + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(enum mdp5_pipe i0) { return 0x00000050 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(enum mdp5_pipe i0) { return 0x00000054 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(enum mdp5_pipe i0) { return 0x00000058 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(enum mdp5_pipe i0) { return 0x00000070 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC0_ADDR(enum mdp5_pipe i0) { return 0x000000a4 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC1_ADDR(enum mdp5_pipe i0) { return 0x000000a8 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC2_ADDR(enum mdp5_pipe i0) { return 0x000000ac + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC3_ADDR(enum mdp5_pipe i0) { return 0x000000b0 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_DECIMATION(enum mdp5_pipe i0) { return 0x000000b4 + __offset_PIPE(i0); }
-#define MDP5_PIPE_DECIMATION_VERT__MASK				0x000000ff
-#define MDP5_PIPE_DECIMATION_VERT__SHIFT			0
-static inline uint32_t MDP5_PIPE_DECIMATION_VERT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_DECIMATION_VERT__SHIFT) & MDP5_PIPE_DECIMATION_VERT__MASK;
-}
-#define MDP5_PIPE_DECIMATION_HORZ__MASK				0x0000ff00
-#define MDP5_PIPE_DECIMATION_HORZ__SHIFT			8
-static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK;
-}
-
-static inline uint32_t __offset_SW_PIX_EXT(enum mdp_component_type idx)
-{
-	switch (idx) {
-		case COMP_0: return 0x00000100;
-		case COMP_1_2: return 0x00000110;
-		case COMP_3: return 0x00000120;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
-
-static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_LR(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
-#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK			0x000000ff
-#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT			0
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK			0x0000ff00
-#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT			8
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(int32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK			0x00ff0000
-#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT		16
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK			0xff000000
-#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT		24
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(int32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_TB(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000004 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
-#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK			0x000000ff
-#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT			0
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK			0x0000ff00
-#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT			8
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(int32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK		0x00ff0000
-#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT		16
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK		0xff000000
-#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT		24
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(int32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000008 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); }
-#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK	0x0000ffff
-#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT	0
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK;
-}
-#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK	0xffff0000
-#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT	16
-static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(uint32_t val)
-{
-	return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00000204 + __offset_PIPE(i0); }
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN			0x00000001
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN			0x00000002
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK	0x00000300
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT	8
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(enum mdp5_scale_filter val)
-{
-	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0__MASK;
-}
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK	0x00000c00
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT	10
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(enum mdp5_scale_filter val)
-{
-	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0__MASK;
-}
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK	0x00003000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT	12
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(enum mdp5_scale_filter val)
-{
-	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2__MASK;
-}
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK	0x0000c000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT	14
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(enum mdp5_scale_filter val)
-{
-	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2__MASK;
-}
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK	0x00030000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT	16
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(enum mdp5_scale_filter val)
-{
-	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3__MASK;
-}
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK	0x000c0000
-#define MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT	18
-static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(enum mdp5_scale_filter val)
-{
-	return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3__MASK;
-}
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000210 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00000214 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000218 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x0000021c + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00000220 + __offset_PIPE(i0); }
-
-static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00000224 + __offset_PIPE(i0); }
-
-static inline uint32_t __offset_LM(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return (mdp5_cfg->lm.base[0]);
-		case 1: return (mdp5_cfg->lm.base[1]);
-		case 2: return (mdp5_cfg->lm.base[2]);
-		case 3: return (mdp5_cfg->lm.base[3]);
-		case 4: return (mdp5_cfg->lm.base[4]);
-		case 5: return (mdp5_cfg->lm.base[5]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_LM(uint32_t i0) { return 0x00000000 + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_COLOR_OUT(uint32_t i0) { return 0x00000000 + __offset_LM(i0); }
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA			0x00000002
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA			0x00000004
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA			0x00000008
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA			0x00000010
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE4_FG_ALPHA			0x00000020
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE5_FG_ALPHA			0x00000040
-#define MDP5_LM_BLEND_COLOR_OUT_STAGE6_FG_ALPHA			0x00000080
-#define MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT		0x80000000
-
-static inline uint32_t REG_MDP5_LM_OUT_SIZE(uint32_t i0) { return 0x00000004 + __offset_LM(i0); }
-#define MDP5_LM_OUT_SIZE_HEIGHT__MASK				0xffff0000
-#define MDP5_LM_OUT_SIZE_HEIGHT__SHIFT				16
-static inline uint32_t MDP5_LM_OUT_SIZE_HEIGHT(uint32_t val)
-{
-	return ((val) << MDP5_LM_OUT_SIZE_HEIGHT__SHIFT) & MDP5_LM_OUT_SIZE_HEIGHT__MASK;
-}
-#define MDP5_LM_OUT_SIZE_WIDTH__MASK				0x0000ffff
-#define MDP5_LM_OUT_SIZE_WIDTH__SHIFT				0
-static inline uint32_t MDP5_LM_OUT_SIZE_WIDTH(uint32_t val)
-{
-	return ((val) << MDP5_LM_OUT_SIZE_WIDTH__SHIFT) & MDP5_LM_OUT_SIZE_WIDTH__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x00000008 + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00000010 + __offset_LM(i0); }
-
-static inline uint32_t __offset_BLEND(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return 0x00000020;
-		case 1: return 0x00000050;
-		case 2: return 0x00000080;
-		case 3: return 0x000000b0;
-		case 4: return 0x00000230;
-		case 5: return 0x00000260;
-		case 6: return 0x00000290;
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_LM(i0) + __offset_BLEND(i1); }
-#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK			0x00000003
-#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT			0
-static inline uint32_t MDP5_LM_BLEND_OP_MODE_FG_ALPHA(enum mdp_alpha_type val)
-{
-	return ((val) << MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK;
-}
-#define MDP5_LM_BLEND_OP_MODE_FG_INV_ALPHA			0x00000004
-#define MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA			0x00000008
-#define MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA			0x00000010
-#define MDP5_LM_BLEND_OP_MODE_FG_TRANSP_EN			0x00000020
-#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK			0x00000300
-#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT			8
-static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val)
-{
-	return ((val) << MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK;
-}
-#define MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA			0x00000400
-#define MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA			0x00000800
-#define MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA			0x00001000
-#define MDP5_LM_BLEND_OP_MODE_BG_TRANSP_EN			0x00002000
-
-static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000004 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00000008 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000000c + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000010 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000014 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000018 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000001c + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00000020 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00000024 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000028 + __offset_LM(i0) + __offset_BLEND(i1); }
-
-static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000000e0 + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK			0x0000ffff
-#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT			0
-static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_W(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK;
-}
-#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK			0xffff0000
-#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT			16
-static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_H(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000000e4 + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_SIZE_ROI_W__MASK				0x0000ffff
-#define MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT			0
-static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_W(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_W__MASK;
-}
-#define MDP5_LM_CURSOR_SIZE_ROI_H__MASK				0xffff0000
-#define MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT			16
-static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_H(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_H__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000000e8 + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_XY_SRC_X__MASK				0x0000ffff
-#define MDP5_LM_CURSOR_XY_SRC_X__SHIFT				0
-static inline uint32_t MDP5_LM_CURSOR_XY_SRC_X(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_XY_SRC_X__SHIFT) & MDP5_LM_CURSOR_XY_SRC_X__MASK;
-}
-#define MDP5_LM_CURSOR_XY_SRC_Y__MASK				0xffff0000
-#define MDP5_LM_CURSOR_XY_SRC_Y__SHIFT				16
-static inline uint32_t MDP5_LM_CURSOR_XY_SRC_Y(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_XY_SRC_Y__SHIFT) & MDP5_LM_CURSOR_XY_SRC_Y__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000000dc + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_STRIDE_STRIDE__MASK			0x0000ffff
-#define MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT			0
-static inline uint32_t MDP5_LM_CURSOR_STRIDE_STRIDE(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT) & MDP5_LM_CURSOR_STRIDE_STRIDE__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000000ec + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_FORMAT_FORMAT__MASK			0x00000007
-#define MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT			0
-static inline uint32_t MDP5_LM_CURSOR_FORMAT_FORMAT(enum mdp5_cursor_format val)
-{
-	return ((val) << MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT) & MDP5_LM_CURSOR_FORMAT_FORMAT__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000000f0 + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000000f4 + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_START_XY_X_START__MASK			0x0000ffff
-#define MDP5_LM_CURSOR_START_XY_X_START__SHIFT			0
-static inline uint32_t MDP5_LM_CURSOR_START_XY_X_START(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_START_XY_X_START__SHIFT) & MDP5_LM_CURSOR_START_XY_X_START__MASK;
-}
-#define MDP5_LM_CURSOR_START_XY_Y_START__MASK			0xffff0000
-#define MDP5_LM_CURSOR_START_XY_Y_START__SHIFT			16
-static inline uint32_t MDP5_LM_CURSOR_START_XY_Y_START(uint32_t val)
-{
-	return ((val) << MDP5_LM_CURSOR_START_XY_Y_START__SHIFT) & MDP5_LM_CURSOR_START_XY_Y_START__MASK;
-}
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000000f8 + __offset_LM(i0); }
-#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN			0x00000001
-#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK	0x00000006
-#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT	1
-static inline uint32_t MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(enum mdp5_cursor_alpha val)
-{
-	return ((val) << MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT) & MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK;
-}
-#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN		0x00000008
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000000fc + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW0(uint32_t i0) { return 0x00000100 + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW1(uint32_t i0) { return 0x00000104 + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH0(uint32_t i0) { return 0x00000108 + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH1(uint32_t i0) { return 0x0000010c + __offset_LM(i0); }
-
-static inline uint32_t REG_MDP5_LM_GC_LUT_BASE(uint32_t i0) { return 0x00000110 + __offset_LM(i0); }
-
-static inline uint32_t __offset_DSPP(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return (mdp5_cfg->dspp.base[0]);
-		case 1: return (mdp5_cfg->dspp.base[1]);
-		case 2: return (mdp5_cfg->dspp.base[2]);
-		case 3: return (mdp5_cfg->dspp.base[3]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_DSPP(uint32_t i0) { return 0x00000000 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_OP_MODE(uint32_t i0) { return 0x00000000 + __offset_DSPP(i0); }
-#define MDP5_DSPP_OP_MODE_IGC_LUT_EN				0x00000001
-#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK			0x0000000e
-#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT			1
-static inline uint32_t MDP5_DSPP_OP_MODE_IGC_TBL_IDX(uint32_t val)
-{
-	return ((val) << MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT) & MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK;
-}
-#define MDP5_DSPP_OP_MODE_PCC_EN				0x00000010
-#define MDP5_DSPP_OP_MODE_DITHER_EN				0x00000100
-#define MDP5_DSPP_OP_MODE_HIST_EN				0x00010000
-#define MDP5_DSPP_OP_MODE_AUTO_CLEAR				0x00020000
-#define MDP5_DSPP_OP_MODE_HIST_LUT_EN				0x00080000
-#define MDP5_DSPP_OP_MODE_PA_EN					0x00100000
-#define MDP5_DSPP_OP_MODE_GAMUT_EN				0x00800000
-#define MDP5_DSPP_OP_MODE_GAMUT_ORDER				0x01000000
-
-static inline uint32_t REG_MDP5_DSPP_PCC_BASE(uint32_t i0) { return 0x00000030 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_DITHER_DEPTH(uint32_t i0) { return 0x00000150 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_HIST_CTL_BASE(uint32_t i0) { return 0x00000210 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_HIST_LUT_BASE(uint32_t i0) { return 0x00000230 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_HIST_LUT_SWAP(uint32_t i0) { return 0x00000234 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_PA_BASE(uint32_t i0) { return 0x00000238 + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000002dc + __offset_DSPP(i0); }
-
-static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000002b0 + __offset_DSPP(i0); }
-
-static inline uint32_t __offset_PP(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return (mdp5_cfg->pp.base[0]);
-		case 1: return (mdp5_cfg->pp.base[1]);
-		case 2: return (mdp5_cfg->pp.base[2]);
-		case 3: return (mdp5_cfg->pp.base[3]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_PP(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_TEAR_CHECK_EN(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_VSYNC(uint32_t i0) { return 0x00000004 + __offset_PP(i0); }
-#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK			0x0007ffff
-#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT			0
-static inline uint32_t MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT) & MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK;
-}
-#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN			0x00080000
-#define MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN				0x00100000
-
-static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_HEIGHT(uint32_t i0) { return 0x00000008 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_SYNC_WRCOUNT(uint32_t i0) { return 0x0000000c + __offset_PP(i0); }
-#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK			0x0000ffff
-#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT			0
-static inline uint32_t MDP5_PP_SYNC_WRCOUNT_LINE_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK;
-}
-#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK			0xffff0000
-#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT			16
-static inline uint32_t MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK;
-}
-
-static inline uint32_t REG_MDP5_PP_VSYNC_INIT_VAL(uint32_t i0) { return 0x00000010 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_INT_COUNT_VAL(uint32_t i0) { return 0x00000014 + __offset_PP(i0); }
-#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK			0x0000ffff
-#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT			0
-static inline uint32_t MDP5_PP_INT_COUNT_VAL_LINE_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK;
-}
-#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK			0xffff0000
-#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT		16
-static inline uint32_t MDP5_PP_INT_COUNT_VAL_FRAME_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK;
-}
-
-static inline uint32_t REG_MDP5_PP_SYNC_THRESH(uint32_t i0) { return 0x00000018 + __offset_PP(i0); }
-#define MDP5_PP_SYNC_THRESH_START__MASK				0x0000ffff
-#define MDP5_PP_SYNC_THRESH_START__SHIFT			0
-static inline uint32_t MDP5_PP_SYNC_THRESH_START(uint32_t val)
-{
-	return ((val) << MDP5_PP_SYNC_THRESH_START__SHIFT) & MDP5_PP_SYNC_THRESH_START__MASK;
-}
-#define MDP5_PP_SYNC_THRESH_CONTINUE__MASK			0xffff0000
-#define MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT			16
-static inline uint32_t MDP5_PP_SYNC_THRESH_CONTINUE(uint32_t val)
-{
-	return ((val) << MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT) & MDP5_PP_SYNC_THRESH_CONTINUE__MASK;
-}
-
-static inline uint32_t REG_MDP5_PP_START_POS(uint32_t i0) { return 0x0000001c + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_RD_PTR_IRQ(uint32_t i0) { return 0x00000020 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_WR_PTR_IRQ(uint32_t i0) { return 0x00000024 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_OUT_LINE_COUNT(uint32_t i0) { return 0x00000028 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_PP_LINE_COUNT(uint32_t i0) { return 0x0000002c + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_AUTOREFRESH_CONFIG(uint32_t i0) { return 0x00000030 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_FBC_MODE(uint32_t i0) { return 0x00000034 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x00000038 + __offset_PP(i0); }
-
-static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); }
-
-static inline uint32_t __offset_WB(uint32_t idx)
-{
-	switch (idx) {
-#if 0  /* TEMPORARY until patch that adds wb.base[] is merged */
-		case 0: return (mdp5_cfg->wb.base[0]);
-		case 1: return (mdp5_cfg->wb.base[1]);
-		case 2: return (mdp5_cfg->wb.base[2]);
-		case 3: return (mdp5_cfg->wb.base[3]);
-		case 4: return (mdp5_cfg->wb.base[4]);
-#endif
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_WB(uint32_t i0) { return 0x00000000 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DST_FORMAT(uint32_t i0) { return 0x00000000 + __offset_WB(i0); }
-#define MDP5_WB_DST_FORMAT_DSTC0_OUT__MASK			0x00000003
-#define MDP5_WB_DST_FORMAT_DSTC0_OUT__SHIFT			0
-static inline uint32_t MDP5_WB_DST_FORMAT_DSTC0_OUT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DSTC0_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC0_OUT__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DSTC1_OUT__MASK			0x0000000c
-#define MDP5_WB_DST_FORMAT_DSTC1_OUT__SHIFT			2
-static inline uint32_t MDP5_WB_DST_FORMAT_DSTC1_OUT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DSTC1_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC1_OUT__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DSTC2_OUT__MASK			0x00000030
-#define MDP5_WB_DST_FORMAT_DSTC2_OUT__SHIFT			4
-static inline uint32_t MDP5_WB_DST_FORMAT_DSTC2_OUT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DSTC2_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC2_OUT__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DSTC3_OUT__MASK			0x000000c0
-#define MDP5_WB_DST_FORMAT_DSTC3_OUT__SHIFT			6
-static inline uint32_t MDP5_WB_DST_FORMAT_DSTC3_OUT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DSTC3_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC3_OUT__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DSTC3_EN				0x00000100
-#define MDP5_WB_DST_FORMAT_DST_BPP__MASK			0x00000600
-#define MDP5_WB_DST_FORMAT_DST_BPP__SHIFT			9
-static inline uint32_t MDP5_WB_DST_FORMAT_DST_BPP(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DST_BPP__SHIFT) & MDP5_WB_DST_FORMAT_DST_BPP__MASK;
-}
-#define MDP5_WB_DST_FORMAT_PACK_COUNT__MASK			0x00003000
-#define MDP5_WB_DST_FORMAT_PACK_COUNT__SHIFT			12
-static inline uint32_t MDP5_WB_DST_FORMAT_PACK_COUNT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_PACK_COUNT__SHIFT) & MDP5_WB_DST_FORMAT_PACK_COUNT__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DST_ALPHA_X				0x00004000
-#define MDP5_WB_DST_FORMAT_PACK_TIGHT				0x00020000
-#define MDP5_WB_DST_FORMAT_PACK_ALIGN_MSB			0x00040000
-#define MDP5_WB_DST_FORMAT_WRITE_PLANES__MASK			0x00180000
-#define MDP5_WB_DST_FORMAT_WRITE_PLANES__SHIFT			19
-static inline uint32_t MDP5_WB_DST_FORMAT_WRITE_PLANES(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_WRITE_PLANES__SHIFT) & MDP5_WB_DST_FORMAT_WRITE_PLANES__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DST_DITHER_EN			0x00400000
-#define MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__MASK		0x03800000
-#define MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__SHIFT		23
-static inline uint32_t MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__SHIFT) & MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__MASK;
-}
-#define MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__MASK		0x3c000000
-#define MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__SHIFT		26
-static inline uint32_t MDP5_WB_DST_FORMAT_DST_CHROMA_SITE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__SHIFT) & MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__MASK;
-}
-#define MDP5_WB_DST_FORMAT_FRAME_FORMAT__MASK			0xc0000000
-#define MDP5_WB_DST_FORMAT_FRAME_FORMAT__SHIFT			30
-static inline uint32_t MDP5_WB_DST_FORMAT_FRAME_FORMAT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_FORMAT_FRAME_FORMAT__SHIFT) & MDP5_WB_DST_FORMAT_FRAME_FORMAT__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_DST_OP_MODE(uint32_t i0) { return 0x00000004 + __offset_WB(i0); }
-#define MDP5_WB_DST_OP_MODE_BWC_ENC_EN				0x00000001
-#define MDP5_WB_DST_OP_MODE_BWC_ENC_OP__MASK			0x00000006
-#define MDP5_WB_DST_OP_MODE_BWC_ENC_OP__SHIFT			1
-static inline uint32_t MDP5_WB_DST_OP_MODE_BWC_ENC_OP(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_BWC_ENC_OP__SHIFT) & MDP5_WB_DST_OP_MODE_BWC_ENC_OP__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_BLOCK_SIZE__MASK			0x00000010
-#define MDP5_WB_DST_OP_MODE_BLOCK_SIZE__SHIFT			4
-static inline uint32_t MDP5_WB_DST_OP_MODE_BLOCK_SIZE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_BLOCK_SIZE__SHIFT) & MDP5_WB_DST_OP_MODE_BLOCK_SIZE__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_ROT_MODE__MASK			0x00000020
-#define MDP5_WB_DST_OP_MODE_ROT_MODE__SHIFT			5
-static inline uint32_t MDP5_WB_DST_OP_MODE_ROT_MODE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_ROT_MODE__SHIFT) & MDP5_WB_DST_OP_MODE_ROT_MODE__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_ROT_EN				0x00000040
-#define MDP5_WB_DST_OP_MODE_CSC_EN				0x00000100
-#define MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__MASK		0x00000200
-#define MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT		9
-static inline uint32_t MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__MASK		0x00000400
-#define MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT		10
-static inline uint32_t MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_EN		0x00000800
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__MASK	0x00001000
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__SHIFT	12
-static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__MASK	0x00002000
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__SHIFT	13
-static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__MASK;
-}
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__MASK	0x00004000
-#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__SHIFT	14
-static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_DST_PACK_PATTERN(uint32_t i0) { return 0x00000008 + __offset_WB(i0); }
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT0__MASK			0x00000003
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT0__SHIFT		0
-static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT0(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT0__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT0__MASK;
-}
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT1__MASK			0x00000300
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT1__SHIFT		8
-static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT1(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT1__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT1__MASK;
-}
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT2__MASK			0x00030000
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT2__SHIFT		16
-static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT2(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT2__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT2__MASK;
-}
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT3__MASK			0x03000000
-#define MDP5_WB_DST_PACK_PATTERN_ELEMENT3__SHIFT		24
-static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT3(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT3__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT3__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_DST0_ADDR(uint32_t i0) { return 0x0000000c + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DST1_ADDR(uint32_t i0) { return 0x00000010 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DST2_ADDR(uint32_t i0) { return 0x00000014 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DST3_ADDR(uint32_t i0) { return 0x00000018 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DST_YSTRIDE0(uint32_t i0) { return 0x0000001c + __offset_WB(i0); }
-#define MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__MASK			0x0000ffff
-#define MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__SHIFT		0
-static inline uint32_t MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__MASK;
-}
-#define MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__MASK			0xffff0000
-#define MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__SHIFT		16
-static inline uint32_t MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_DST_YSTRIDE1(uint32_t i0) { return 0x00000020 + __offset_WB(i0); }
-#define MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__MASK			0x0000ffff
-#define MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__SHIFT		0
-static inline uint32_t MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__MASK;
-}
-#define MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__MASK			0xffff0000
-#define MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__SHIFT		16
-static inline uint32_t MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE(uint32_t val)
-{
-	return ((val) << MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_DST_DITHER_BITDEPTH(uint32_t i0) { return 0x00000024 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW0(uint32_t i0) { return 0x00000030 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW1(uint32_t i0) { return 0x00000034 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW2(uint32_t i0) { return 0x00000038 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW3(uint32_t i0) { return 0x0000003c + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_DST_WRITE_CONFIG(uint32_t i0) { return 0x00000048 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_ROTATION_DNSCALER(uint32_t i0) { return 0x00000050 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_X_0_3(uint32_t i0) { return 0x00000060 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_X_1_2(uint32_t i0) { return 0x00000064 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_Y_0_3(uint32_t i0) { return 0x00000068 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_Y_1_2(uint32_t i0) { return 0x0000006c + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_OUT_SIZE(uint32_t i0) { return 0x00000074 + __offset_WB(i0); }
-#define MDP5_WB_OUT_SIZE_DST_W__MASK				0x0000ffff
-#define MDP5_WB_OUT_SIZE_DST_W__SHIFT				0
-static inline uint32_t MDP5_WB_OUT_SIZE_DST_W(uint32_t val)
-{
-	return ((val) << MDP5_WB_OUT_SIZE_DST_W__SHIFT) & MDP5_WB_OUT_SIZE_DST_W__MASK;
-}
-#define MDP5_WB_OUT_SIZE_DST_H__MASK				0xffff0000
-#define MDP5_WB_OUT_SIZE_DST_H__SHIFT				16
-static inline uint32_t MDP5_WB_OUT_SIZE_DST_H(uint32_t val)
-{
-	return ((val) << MDP5_WB_OUT_SIZE_DST_H__SHIFT) & MDP5_WB_OUT_SIZE_DST_H__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_ALPHA_X_VALUE(uint32_t i0) { return 0x00000078 + __offset_WB(i0); }
-
-static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_0(uint32_t i0) { return 0x00000260 + __offset_WB(i0); }
-#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__MASK		0x00001fff
-#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__MASK;
-}
-#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__MASK		0x1fff0000
-#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__SHIFT		16
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_1(uint32_t i0) { return 0x00000264 + __offset_WB(i0); }
-#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__MASK		0x00001fff
-#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__MASK;
-}
-#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__MASK		0x1fff0000
-#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__SHIFT		16
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_2(uint32_t i0) { return 0x00000268 + __offset_WB(i0); }
-#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__MASK		0x00001fff
-#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__MASK;
-}
-#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__MASK		0x1fff0000
-#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__SHIFT		16
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_3(uint32_t i0) { return 0x0000026c + __offset_WB(i0); }
-#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__MASK		0x00001fff
-#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__MASK;
-}
-#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__MASK		0x1fff0000
-#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__SHIFT		16
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_4(uint32_t i0) { return 0x00000270 + __offset_WB(i0); }
-#define MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__MASK		0x00001fff
-#define MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_PRECLAMP(uint32_t i0, uint32_t i1) { return 0x00000274 + __offset_WB(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_PRECLAMP_REG(uint32_t i0, uint32_t i1) { return 0x00000274 + __offset_WB(i0) + 0x4*i1; }
-#define MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__MASK		0x000000ff
-#define MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__SHIFT) & MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__MASK;
-}
-#define MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__MASK			0x0000ff00
-#define MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__SHIFT		8
-static inline uint32_t MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__SHIFT) & MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTCLAMP(uint32_t i0, uint32_t i1) { return 0x00000280 + __offset_WB(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTCLAMP_REG(uint32_t i0, uint32_t i1) { return 0x00000280 + __offset_WB(i0) + 0x4*i1; }
-#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__MASK		0x000000ff
-#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__SHIFT) & MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__MASK;
-}
-#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__MASK		0x0000ff00
-#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__SHIFT		8
-static inline uint32_t MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__SHIFT) & MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_PREBIAS(uint32_t i0, uint32_t i1) { return 0x0000028c + __offset_WB(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_PREBIAS_REG(uint32_t i0, uint32_t i1) { return 0x0000028c + __offset_WB(i0) + 0x4*i1; }
-#define MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__MASK		0x000001ff
-#define MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__SHIFT) & MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__MASK;
-}
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTBIAS(uint32_t i0, uint32_t i1) { return 0x00000298 + __offset_WB(i0) + 0x4*i1; }
-
-static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTBIAS_REG(uint32_t i0, uint32_t i1) { return 0x00000298 + __offset_WB(i0) + 0x4*i1; }
-#define MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__MASK		0x000001ff
-#define MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__SHIFT		0
-static inline uint32_t MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE(uint32_t val)
-{
-	return ((val) << MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__SHIFT) & MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__MASK;
-}
-
-static inline uint32_t __offset_INTF(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return (mdp5_cfg->intf.base[0]);
-		case 1: return (mdp5_cfg->intf.base[1]);
-		case 2: return (mdp5_cfg->intf.base[2]);
-		case 3: return (mdp5_cfg->intf.base[3]);
-		case 4: return (mdp5_cfg->intf.base[4]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_INTF(uint32_t i0) { return 0x00000000 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TIMING_ENGINE_EN(uint32_t i0) { return 0x00000000 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_CONFIG(uint32_t i0) { return 0x00000004 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_HSYNC_CTL(uint32_t i0) { return 0x00000008 + __offset_INTF(i0); }
-#define MDP5_INTF_HSYNC_CTL_PULSEW__MASK			0x0000ffff
-#define MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT			0
-static inline uint32_t MDP5_INTF_HSYNC_CTL_PULSEW(uint32_t val)
-{
-	return ((val) << MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT) & MDP5_INTF_HSYNC_CTL_PULSEW__MASK;
-}
-#define MDP5_INTF_HSYNC_CTL_PERIOD__MASK			0xffff0000
-#define MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT			16
-static inline uint32_t MDP5_INTF_HSYNC_CTL_PERIOD(uint32_t val)
-{
-	return ((val) << MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT) & MDP5_INTF_HSYNC_CTL_PERIOD__MASK;
-}
-
-static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F0(uint32_t i0) { return 0x0000000c + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F1(uint32_t i0) { return 0x00000010 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F0(uint32_t i0) { return 0x00000014 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F1(uint32_t i0) { return 0x00000018 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F0(uint32_t i0) { return 0x0000001c + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F1(uint32_t i0) { return 0x00000020 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F0(uint32_t i0) { return 0x00000024 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F1(uint32_t i0) { return 0x00000028 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F0(uint32_t i0) { return 0x0000002c + __offset_INTF(i0); }
-#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK			0x7fffffff
-#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT			0
-static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F0_VAL(uint32_t val)
-{
-	return ((val) << MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK;
-}
-#define MDP5_INTF_ACTIVE_VSTART_F0_ACTIVE_V_ENABLE		0x80000000
-
-static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F1(uint32_t i0) { return 0x00000030 + __offset_INTF(i0); }
-#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK			0x7fffffff
-#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT			0
-static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F1_VAL(uint32_t val)
-{
-	return ((val) << MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK;
-}
-
-static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F0(uint32_t i0) { return 0x00000034 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F1(uint32_t i0) { return 0x00000038 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DISPLAY_HCTL(uint32_t i0) { return 0x0000003c + __offset_INTF(i0); }
-#define MDP5_INTF_DISPLAY_HCTL_START__MASK			0x0000ffff
-#define MDP5_INTF_DISPLAY_HCTL_START__SHIFT			0
-static inline uint32_t MDP5_INTF_DISPLAY_HCTL_START(uint32_t val)
-{
-	return ((val) << MDP5_INTF_DISPLAY_HCTL_START__SHIFT) & MDP5_INTF_DISPLAY_HCTL_START__MASK;
-}
-#define MDP5_INTF_DISPLAY_HCTL_END__MASK			0xffff0000
-#define MDP5_INTF_DISPLAY_HCTL_END__SHIFT			16
-static inline uint32_t MDP5_INTF_DISPLAY_HCTL_END(uint32_t val)
-{
-	return ((val) << MDP5_INTF_DISPLAY_HCTL_END__SHIFT) & MDP5_INTF_DISPLAY_HCTL_END__MASK;
-}
-
-static inline uint32_t REG_MDP5_INTF_ACTIVE_HCTL(uint32_t i0) { return 0x00000040 + __offset_INTF(i0); }
-#define MDP5_INTF_ACTIVE_HCTL_START__MASK			0x00007fff
-#define MDP5_INTF_ACTIVE_HCTL_START__SHIFT			0
-static inline uint32_t MDP5_INTF_ACTIVE_HCTL_START(uint32_t val)
-{
-	return ((val) << MDP5_INTF_ACTIVE_HCTL_START__SHIFT) & MDP5_INTF_ACTIVE_HCTL_START__MASK;
-}
-#define MDP5_INTF_ACTIVE_HCTL_END__MASK				0x7fff0000
-#define MDP5_INTF_ACTIVE_HCTL_END__SHIFT			16
-static inline uint32_t MDP5_INTF_ACTIVE_HCTL_END(uint32_t val)
-{
-	return ((val) << MDP5_INTF_ACTIVE_HCTL_END__SHIFT) & MDP5_INTF_ACTIVE_HCTL_END__MASK;
-}
-#define MDP5_INTF_ACTIVE_HCTL_ACTIVE_H_ENABLE			0x80000000
-
-static inline uint32_t REG_MDP5_INTF_BORDER_COLOR(uint32_t i0) { return 0x00000044 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_UNDERFLOW_COLOR(uint32_t i0) { return 0x00000048 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_HSYNC_SKEW(uint32_t i0) { return 0x0000004c + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_POLARITY_CTL(uint32_t i0) { return 0x00000050 + __offset_INTF(i0); }
-#define MDP5_INTF_POLARITY_CTL_HSYNC_LOW			0x00000001
-#define MDP5_INTF_POLARITY_CTL_VSYNC_LOW			0x00000002
-#define MDP5_INTF_POLARITY_CTL_DATA_EN_LOW			0x00000004
-
-static inline uint32_t REG_MDP5_INTF_TEST_CTL(uint32_t i0) { return 0x00000054 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TP_COLOR0(uint32_t i0) { return 0x00000058 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TP_COLOR1(uint32_t i0) { return 0x0000005c + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DSI_CMD_MODE_TRIGGER_EN(uint32_t i0) { return 0x00000084 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_PANEL_FORMAT(uint32_t i0) { return 0x00000090 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_FRAME_LINE_COUNT_EN(uint32_t i0) { return 0x000000a8 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_FRAME_COUNT(uint32_t i0) { return 0x000000ac + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_LINE_COUNT(uint32_t i0) { return 0x000000b0 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DEFLICKER_CONFIG(uint32_t i0) { return 0x000000f0 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DEFLICKER_STRNG_COEFF(uint32_t i0) { return 0x000000f4 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_DEFLICKER_WEAK_COEFF(uint32_t i0) { return 0x000000f8 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_ENABLE(uint32_t i0) { return 0x00000100 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_MAIN_CONTROL(uint32_t i0) { return 0x00000104 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_VIDEO_CONFIG(uint32_t i0) { return 0x00000108 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_COMPONENT_LIMITS(uint32_t i0) { return 0x0000010c + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_RECTANGLE(uint32_t i0) { return 0x00000110 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_INITIAL_VALUE(uint32_t i0) { return 0x00000114 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_BLK_WHITE_PATTERN_FRAME(uint32_t i0) { return 0x00000118 + __offset_INTF(i0); }
-
-static inline uint32_t REG_MDP5_INTF_TPG_RGB_MAPPING(uint32_t i0) { return 0x0000011c + __offset_INTF(i0); }
-
-static inline uint32_t __offset_AD(uint32_t idx)
-{
-	switch (idx) {
-		case 0: return (mdp5_cfg->ad.base[0]);
-		case 1: return (mdp5_cfg->ad.base[1]);
-		default: return INVALID_IDX(idx);
-	}
-}
-static inline uint32_t REG_MDP5_AD(uint32_t i0) { return 0x00000000 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_BYPASS(uint32_t i0) { return 0x00000000 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CTRL_0(uint32_t i0) { return 0x00000004 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CTRL_1(uint32_t i0) { return 0x00000008 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_FRAME_SIZE(uint32_t i0) { return 0x0000000c + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CON_CTRL_0(uint32_t i0) { return 0x00000010 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CON_CTRL_1(uint32_t i0) { return 0x00000014 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_STR_MAN(uint32_t i0) { return 0x00000018 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_VAR(uint32_t i0) { return 0x0000001c + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_DITH(uint32_t i0) { return 0x00000020 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_DITH_CTRL(uint32_t i0) { return 0x00000024 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_AMP_LIM(uint32_t i0) { return 0x00000028 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_SLOPE(uint32_t i0) { return 0x0000002c + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_BW_LVL(uint32_t i0) { return 0x00000030 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_LOGO_POS(uint32_t i0) { return 0x00000034 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_LUT_FI(uint32_t i0) { return 0x00000038 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_LUT_CC(uint32_t i0) { return 0x0000007c + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_STR_LIM(uint32_t i0) { return 0x000000c8 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CALIB_AB(uint32_t i0) { return 0x000000cc + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CALIB_CD(uint32_t i0) { return 0x000000d0 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_MODE_SEL(uint32_t i0) { return 0x000000d4 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_TFILT_CTRL(uint32_t i0) { return 0x000000d8 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_BL_MINMAX(uint32_t i0) { return 0x000000dc + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_BL(uint32_t i0) { return 0x000000e0 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_BL_MAX(uint32_t i0) { return 0x000000e8 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_AL(uint32_t i0) { return 0x000000ec + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_AL_MIN(uint32_t i0) { return 0x000000f0 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_AL_FILT(uint32_t i0) { return 0x000000f4 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CFG_BUF(uint32_t i0) { return 0x000000f8 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_LUT_AL(uint32_t i0) { return 0x00000100 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_TARG_STR(uint32_t i0) { return 0x00000144 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_START_CALC(uint32_t i0) { return 0x00000148 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_STR_OUT(uint32_t i0) { return 0x0000014c + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_BL_OUT(uint32_t i0) { return 0x00000154 + __offset_AD(i0); }
-
-static inline uint32_t REG_MDP5_AD_CALC_DONE(uint32_t i0) { return 0x00000158 + __offset_AD(i0); }
-
-
-#endif /* MDP5_XML */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
deleted file mode 100644
index 824067d2d427..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include "mdp5_kms.h"
-#include "mdp5_cfg.h"
-
-struct mdp5_cfg_handler {
-	int revision;
-	struct mdp5_cfg config;
-};
-
-/* mdp5_cfg must be exposed (used in mdp5.xml.h) */
-const struct mdp5_cfg_hw *mdp5_cfg = NULL;
-
-const struct mdp5_cfg_hw msm8x74v1_config = {
-	.name = "msm8x74v1",
-	.mdp = {
-		.count = 1,
-		.caps = MDP_CAP_SMP |
-			0,
-	},
-	.smp = {
-		.mmb_count = 22,
-		.mmb_size = 4096,
-		.clients = {
-			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
-			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
-			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
-		},
-	},
-	.ctl = {
-		.count = 5,
-		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
-		.flush_hw_mask = 0x0003ffff,
-	},
-	.pipe_vig = {
-		.count = 3,
-		.base = { 0x01100, 0x01500, 0x01900 },
-		.caps = MDP_PIPE_CAP_HFLIP |
-			MDP_PIPE_CAP_VFLIP |
-			MDP_PIPE_CAP_SCALE |
-			MDP_PIPE_CAP_CSC   |
-			0,
-	},
-	.pipe_rgb = {
-		.count = 3,
-		.base = { 0x01d00, 0x02100, 0x02500 },
-		.caps = MDP_PIPE_CAP_HFLIP |
-			MDP_PIPE_CAP_VFLIP |
-			MDP_PIPE_CAP_SCALE |
-			0,
-	},
-	.pipe_dma = {
-		.count = 2,
-		.base = { 0x02900, 0x02d00 },
-		.caps = MDP_PIPE_CAP_HFLIP |
-			MDP_PIPE_CAP_VFLIP |
-			0,
-	},
-	.lm = {
-		.count = 5,
-		.base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 },
-		.instances = {
-				{ .id = 0, .pp = 0, .dspp = 0,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 1, .pp = 1, .dspp = 1,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 2, .pp = 2, .dspp = 2,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 3, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB },
-				{ .id = 4, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB },
-			     },
-		.nb_stages = 5,
-		.max_width = 2048,
-		.max_height = 0xFFFF,
-	},
-	.dspp = {
-		.count = 3,
-		.base = { 0x04500, 0x04900, 0x04d00 },
-	},
-	.pp = {
-		.count = 3,
-		.base = { 0x21a00, 0x21b00, 0x21c00 },
-	},
-	.intf = {
-		.base = { 0x21000, 0x21200, 0x21400, 0x21600 },
-		.connect = {
-			[0] = INTF_eDP,
-			[1] = INTF_DSI,
-			[2] = INTF_DSI,
-			[3] = INTF_HDMI,
-		},
-	},
-	.max_clk = 200000000,
-};
-
-const struct mdp5_cfg_hw msm8x74v2_config = {
-	.name = "msm8x74",
-	.mdp = {
-		.count = 1,
-		.caps = MDP_CAP_SMP |
-			0,
-	},
-	.smp = {
-		.mmb_count = 22,
-		.mmb_size = 4096,
-		.clients = {
-			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
-			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
-			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
-		},
-	},
-	.ctl = {
-		.count = 5,
-		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
-		.flush_hw_mask = 0x0003ffff,
-	},
-	.pipe_vig = {
-		.count = 3,
-		.base = { 0x01100, 0x01500, 0x01900 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
-				MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_rgb = {
-		.count = 3,
-		.base = { 0x01d00, 0x02100, 0x02500 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_dma = {
-		.count = 2,
-		.base = { 0x02900, 0x02d00 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
-	},
-	.lm = {
-		.count = 5,
-		.base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 },
-		.instances = {
-				{ .id = 0, .pp = 0, .dspp = 0,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 1, .pp = 1, .dspp = 1,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 2, .pp = 2, .dspp = 2,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 3, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 4, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-			     },
-		.nb_stages = 5,
-		.max_width = 2048,
-		.max_height = 0xFFFF,
-	},
-	.dspp = {
-		.count = 3,
-		.base = { 0x04500, 0x04900, 0x04d00 },
-	},
-	.ad = {
-		.count = 2,
-		.base = { 0x13000, 0x13200 },
-	},
-	.pp = {
-		.count = 3,
-		.base = { 0x12c00, 0x12d00, 0x12e00 },
-	},
-	.intf = {
-		.base = { 0x12400, 0x12600, 0x12800, 0x12a00 },
-		.connect = {
-			[0] = INTF_eDP,
-			[1] = INTF_DSI,
-			[2] = INTF_DSI,
-			[3] = INTF_HDMI,
-		},
-	},
-	.max_clk = 200000000,
-};
-
-const struct mdp5_cfg_hw apq8084_config = {
-	.name = "apq8084",
-	.mdp = {
-		.count = 1,
-		.caps = MDP_CAP_SMP |
-			MDP_CAP_SRC_SPLIT |
-			0,
-	},
-	.smp = {
-		.mmb_count = 44,
-		.mmb_size = 8192,
-		.clients = {
-			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
-			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
-			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
-			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
-			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
-		},
-		.reserved_state[0] = GENMASK(7, 0),	/* first 8 MMBs */
-		.reserved = {
-			/* Two SMP blocks are statically tied to RGB pipes: */
-			[16] = 2, [17] = 2, [18] = 2, [22] = 2,
-		},
-	},
-	.ctl = {
-		.count = 5,
-		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
-		.flush_hw_mask = 0x003fffff,
-	},
-	.pipe_vig = {
-		.count = 4,
-		.base = { 0x01100, 0x01500, 0x01900, 0x01d00 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
-				MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_rgb = {
-		.count = 4,
-		.base = { 0x02100, 0x02500, 0x02900, 0x02d00 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_dma = {
-		.count = 2,
-		.base = { 0x03100, 0x03500 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
-	},
-	.lm = {
-		.count = 6,
-		.base = { 0x03900, 0x03d00, 0x04100, 0x04500, 0x04900, 0x04d00 },
-		.instances = {
-				{ .id = 0, .pp = 0, .dspp = 0,
-				  .caps = MDP_LM_CAP_DISPLAY |
-					  MDP_LM_CAP_PAIR, },
-				{ .id = 1, .pp = 1, .dspp = 1,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 2, .pp = 2, .dspp = 2,
-				  .caps = MDP_LM_CAP_DISPLAY |
-					  MDP_LM_CAP_PAIR, },
-				{ .id = 3, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 4, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 5, .pp = 3, .dspp = 3,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-			     },
-		.nb_stages = 5,
-		.max_width = 2048,
-		.max_height = 0xFFFF,
-	},
-	.dspp = {
-		.count = 4,
-		.base = { 0x05100, 0x05500, 0x05900, 0x05d00 },
-
-	},
-	.ad = {
-		.count = 3,
-		.base = { 0x13400, 0x13600, 0x13800 },
-	},
-	.pp = {
-		.count = 4,
-		.base = { 0x12e00, 0x12f00, 0x13000, 0x13100 },
-	},
-	.intf = {
-		.base = { 0x12400, 0x12600, 0x12800, 0x12a00, 0x12c00 },
-		.connect = {
-			[0] = INTF_eDP,
-			[1] = INTF_DSI,
-			[2] = INTF_DSI,
-			[3] = INTF_HDMI,
-		},
-	},
-	.max_clk = 320000000,
-};
-
-const struct mdp5_cfg_hw msm8x16_config = {
-	.name = "msm8x16",
-	.mdp = {
-		.count = 1,
-		.base = { 0x0 },
-		.caps = MDP_CAP_SMP |
-			0,
-	},
-	.smp = {
-		.mmb_count = 8,
-		.mmb_size = 8192,
-		.clients = {
-			[SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
-			[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
-		},
-	},
-	.ctl = {
-		.count = 5,
-		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
-		.flush_hw_mask = 0x4003ffff,
-	},
-	.pipe_vig = {
-		.count = 1,
-		.base = { 0x04000 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
-				MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_rgb = {
-		.count = 2,
-		.base = { 0x14000, 0x16000 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_dma = {
-		.count = 1,
-		.base = { 0x24000 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
-	},
-	.lm = {
-		.count = 2, /* LM0 and LM3 */
-		.base = { 0x44000, 0x47000 },
-		.instances = {
-				{ .id = 0, .pp = 0, .dspp = 0,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 3, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB },
-			     },
-		.nb_stages = 8,
-		.max_width = 2048,
-		.max_height = 0xFFFF,
-	},
-	.dspp = {
-		.count = 1,
-		.base = { 0x54000 },
-
-	},
-	.intf = {
-		.base = { 0x00000, 0x6a800 },
-		.connect = {
-			[0] = INTF_DISABLED,
-			[1] = INTF_DSI,
-		},
-	},
-	.max_clk = 320000000,
-};
-
-const struct mdp5_cfg_hw msm8x94_config = {
-	.name = "msm8x94",
-	.mdp = {
-		.count = 1,
-		.caps = MDP_CAP_SMP |
-			MDP_CAP_SRC_SPLIT |
-			0,
-	},
-	.smp = {
-		.mmb_count = 44,
-		.mmb_size = 8192,
-		.clients = {
-			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
-			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
-			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
-			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
-			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
-		},
-		.reserved_state[0] = GENMASK(23, 0),	/* first 24 MMBs */
-		.reserved = {
-			 [1] = 1,  [4] = 1,  [7] = 1, [19] = 1,
-			[16] = 5, [17] = 5, [18] = 5, [22] = 5,
-		},
-	},
-	.ctl = {
-		.count = 5,
-		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
-		.flush_hw_mask = 0xf0ffffff,
-	},
-	.pipe_vig = {
-		.count = 4,
-		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
-				MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_rgb = {
-		.count = 4,
-		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
-	},
-	.pipe_dma = {
-		.count = 2,
-		.base = { 0x24000, 0x26000 },
-		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
-	},
-	.lm = {
-		.count = 6,
-		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
-		.instances = {
-				{ .id = 0, .pp = 0, .dspp = 0,
-				  .caps = MDP_LM_CAP_DISPLAY |
-					  MDP_LM_CAP_PAIR, },
-				{ .id = 1, .pp = 1, .dspp = 1,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 2, .pp = 2, .dspp = 2,
-				  .caps = MDP_LM_CAP_DISPLAY |
-					  MDP_LM_CAP_PAIR, },
-				{ .id = 3, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 4, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 5, .pp = 3, .dspp = 3,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-			     },
-		.nb_stages = 8,
-		.max_width = 2048,
-		.max_height = 0xFFFF,
-	},
-	.dspp = {
-		.count = 4,
-		.base = { 0x54000, 0x56000, 0x58000, 0x5a000 },
-
-	},
-	.ad = {
-		.count = 3,
-		.base = { 0x78000, 0x78800, 0x79000 },
-	},
-	.pp = {
-		.count = 4,
-		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
-	},
-	.intf = {
-		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
-		.connect = {
-			[0] = INTF_DISABLED,
-			[1] = INTF_DSI,
-			[2] = INTF_DSI,
-			[3] = INTF_HDMI,
-		},
-	},
-	.max_clk = 400000000,
-};
-
-const struct mdp5_cfg_hw msm8x96_config = {
-	.name = "msm8x96",
-	.mdp = {
-		.count = 1,
-		.caps = MDP_CAP_DSC |
-			MDP_CAP_CDM |
-			MDP_CAP_SRC_SPLIT |
-			0,
-	},
-	.ctl = {
-		.count = 5,
-		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
-		.flush_hw_mask = 0xf4ffffff,
-	},
-	.pipe_vig = {
-		.count = 4,
-		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
-		.caps = MDP_PIPE_CAP_HFLIP	|
-			MDP_PIPE_CAP_VFLIP	|
-			MDP_PIPE_CAP_SCALE	|
-			MDP_PIPE_CAP_CSC	|
-			MDP_PIPE_CAP_DECIMATION	|
-			MDP_PIPE_CAP_SW_PIX_EXT	|
-			0,
-	},
-	.pipe_rgb = {
-		.count = 4,
-		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
-		.caps = MDP_PIPE_CAP_HFLIP	|
-			MDP_PIPE_CAP_VFLIP	|
-			MDP_PIPE_CAP_SCALE	|
-			MDP_PIPE_CAP_DECIMATION	|
-			MDP_PIPE_CAP_SW_PIX_EXT	|
-			0,
-	},
-	.pipe_dma = {
-		.count = 2,
-		.base = { 0x24000, 0x26000 },
-		.caps = MDP_PIPE_CAP_HFLIP	|
-			MDP_PIPE_CAP_VFLIP	|
-			MDP_PIPE_CAP_SW_PIX_EXT	|
-			0,
-	},
-	.pipe_cursor = {
-		.count = 2,
-		.base = { 0x34000, 0x36000 },
-		.caps = MDP_PIPE_CAP_HFLIP	|
-			MDP_PIPE_CAP_VFLIP	|
-			MDP_PIPE_CAP_SW_PIX_EXT	|
-			MDP_PIPE_CAP_CURSOR	|
-			0,
-	},
-
-	.lm = {
-		.count = 6,
-		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
-		.instances = {
-				{ .id = 0, .pp = 0, .dspp = 0,
-				  .caps = MDP_LM_CAP_DISPLAY |
-					  MDP_LM_CAP_PAIR, },
-				{ .id = 1, .pp = 1, .dspp = 1,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-				{ .id = 2, .pp = 2, .dspp = -1,
-				  .caps = MDP_LM_CAP_DISPLAY |
-					  MDP_LM_CAP_PAIR, },
-				{ .id = 3, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 4, .pp = -1, .dspp = -1,
-				  .caps = MDP_LM_CAP_WB, },
-				{ .id = 5, .pp = 3, .dspp = -1,
-				  .caps = MDP_LM_CAP_DISPLAY, },
-			     },
-		.nb_stages = 8,
-		.max_width = 2560,
-		.max_height = 0xFFFF,
-	},
-	.dspp = {
-		.count = 2,
-		.base = { 0x54000, 0x56000 },
-	},
-	.ad = {
-		.count = 3,
-		.base = { 0x78000, 0x78800, 0x79000 },
-	},
-	.pp = {
-		.count = 4,
-		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
-	},
-	.cdm = {
-		.count = 1,
-		.base = { 0x79200 },
-	},
-	.dsc = {
-		.count = 2,
-		.base = { 0x80000, 0x80400 },
-	},
-	.intf = {
-		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
-		.connect = {
-			[0] = INTF_DISABLED,
-			[1] = INTF_DSI,
-			[2] = INTF_DSI,
-			[3] = INTF_HDMI,
-		},
-	},
-	.max_clk = 412500000,
-};
-
-static const struct mdp5_cfg_handler cfg_handlers[] = {
-	{ .revision = 0, .config = { .hw = &msm8x74v1_config } },
-	{ .revision = 2, .config = { .hw = &msm8x74v2_config } },
-	{ .revision = 3, .config = { .hw = &apq8084_config } },
-	{ .revision = 6, .config = { .hw = &msm8x16_config } },
-	{ .revision = 9, .config = { .hw = &msm8x94_config } },
-	{ .revision = 7, .config = { .hw = &msm8x96_config } },
-};
-
-static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
-
-const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
-{
-	return cfg_handler->config.hw;
-}
-
-struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler)
-{
-	return &cfg_handler->config;
-}
-
-int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler)
-{
-	return cfg_handler->revision;
-}
-
-void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler)
-{
-	kfree(cfg_handler);
-}
-
-struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
-		uint32_t major, uint32_t minor)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	struct platform_device *pdev = to_platform_device(dev->dev);
-	struct mdp5_cfg_handler *cfg_handler;
-	struct mdp5_cfg_platform *pconfig;
-	int i, ret = 0;
-
-	cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
-	if (unlikely(!cfg_handler)) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	if (major != 1) {
-		dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n",
-				major, minor);
-		ret = -ENXIO;
-		goto fail;
-	}
-
-	/* only after mdp5_cfg global pointer's init can we access the hw */
-	for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
-		if (cfg_handlers[i].revision != minor)
-			continue;
-		mdp5_cfg = cfg_handlers[i].config.hw;
-
-		break;
-	}
-	if (unlikely(!mdp5_cfg)) {
-		dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
-				major, minor);
-		ret = -ENXIO;
-		goto fail;
-	}
-
-	cfg_handler->revision = minor;
-	cfg_handler->config.hw = mdp5_cfg;
-
-	pconfig = mdp5_get_config(pdev);
-	memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig));
-
-	DBG("MDP5: %s hw config selected", mdp5_cfg->name);
-
-	return cfg_handler;
-
-fail:
-	if (cfg_handler)
-		mdp5_cfg_destroy(cfg_handler);
-
-	return NULL;
-}
-
-static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
-{
-	static struct mdp5_cfg_platform config = {};
-
-	config.iommu = iommu_domain_alloc(&platform_bus_type);
-	if (config.iommu) {
-		config.iommu->geometry.aperture_start = 0x1000;
-		config.iommu->geometry.aperture_end = 0xffffffff;
-	}
-
-	return &config;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
deleted file mode 100644
index 75910d0f2f4c..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MDP5_CFG_H__
-#define __MDP5_CFG_H__
-
-#include "msm_drv.h"
-
-/*
- * mdp5_cfg
- *
- * This module configures the dynamic offsets used by mdp5.xml.h
- * (initialized in mdp5_cfg.c)
- */
-extern const struct mdp5_cfg_hw *mdp5_cfg;
-
-#define MAX_CTL			8
-#define MAX_BASES		8
-#define MAX_SMP_BLOCKS		44
-#define MAX_CLIENTS		32
-
-typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS);
-
-#define MDP5_SUB_BLOCK_DEFINITION \
-	unsigned int count; \
-	uint32_t base[MAX_BASES]
-
-struct mdp5_sub_block {
-	MDP5_SUB_BLOCK_DEFINITION;
-};
-
-struct mdp5_lm_instance {
-	int id;
-	int pp;
-	int dspp;
-	uint32_t caps;
-};
-
-struct mdp5_lm_block {
-	MDP5_SUB_BLOCK_DEFINITION;
-	struct mdp5_lm_instance instances[MAX_BASES];
-	uint32_t nb_stages;		/* number of stages per blender */
-	uint32_t max_width;		/* Maximum output resolution */
-	uint32_t max_height;
-};
-
-struct mdp5_pipe_block {
-	MDP5_SUB_BLOCK_DEFINITION;
-	uint32_t caps;			/* pipe capabilities */
-};
-
-struct mdp5_ctl_block {
-	MDP5_SUB_BLOCK_DEFINITION;
-	uint32_t flush_hw_mask;		/* FLUSH register's hardware mask */
-};
-
-struct mdp5_smp_block {
-	int mmb_count;			/* number of SMP MMBs */
-	int mmb_size;			/* MMB: size in bytes */
-	uint32_t clients[MAX_CLIENTS];	/* SMP port allocation /pipe */
-	mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */
-	uint8_t reserved[MAX_CLIENTS];	/* # of MMBs allocated per client */
-};
-
-struct mdp5_mdp_block {
-	MDP5_SUB_BLOCK_DEFINITION;
-	uint32_t caps;			/* MDP capabilities: MDP_CAP_xxx bits */
-};
-
-#define MDP5_INTF_NUM_MAX	5
-
-struct mdp5_intf_block {
-	uint32_t base[MAX_BASES];
-	u32 connect[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
-};
-
-struct mdp5_cfg_hw {
-	char  *name;
-
-	struct mdp5_mdp_block mdp;
-	struct mdp5_smp_block smp;
-	struct mdp5_ctl_block ctl;
-	struct mdp5_pipe_block pipe_vig;
-	struct mdp5_pipe_block pipe_rgb;
-	struct mdp5_pipe_block pipe_dma;
-	struct mdp5_pipe_block pipe_cursor;
-	struct mdp5_lm_block  lm;
-	struct mdp5_sub_block dspp;
-	struct mdp5_sub_block ad;
-	struct mdp5_sub_block pp;
-	struct mdp5_sub_block dsc;
-	struct mdp5_sub_block cdm;
-	struct mdp5_intf_block intf;
-
-	uint32_t max_clk;
-};
-
-/* platform config data (ie. from DT, or pdata) */
-struct mdp5_cfg_platform {
-	struct iommu_domain *iommu;
-};
-
-struct mdp5_cfg {
-	const struct mdp5_cfg_hw *hw;
-	struct mdp5_cfg_platform platform;
-};
-
-struct mdp5_kms;
-struct mdp5_cfg_handler;
-
-const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hnd);
-struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd);
-int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd);
-
-#define mdp5_cfg_intf_is_virtual(intf_type) ({	\
-	typeof(intf_type) __val = (intf_type);	\
-	(__val) >= INTF_VIRTUAL ? true : false; })
-
-struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
-		uint32_t major, uint32_t minor);
-void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd);
-
-#endif /* __MDP5_CFG_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
deleted file mode 100644
index 1abc7f5c345c..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "mdp5_kms.h"
-
-static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
-{
-	struct msm_drm_private *priv = encoder->dev->dev_private;
-	return to_mdp5_kms(to_mdp_kms(priv->kms));
-}
-
-#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
-#include <mach/board.h>
-#include <linux/msm-bus.h>
-#include <linux/msm-bus-board.h>
-
-static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx)
-{
-	if (mdp5_cmd_enc->bsc) {
-		DBG("set bus scaling: %d", idx);
-		/* HACK: scaling down, and then immediately back up
-		 * seems to leave things broken (underflow).. so
-		 * never disable:
-		 */
-		idx = 1;
-		msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx);
-	}
-}
-#else
-static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx) {}
-#endif
-
-#define VSYNC_CLK_RATE 19200000
-static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
-				    struct drm_display_mode *mode)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	struct device *dev = encoder->dev->dev;
-	u32 total_lines_x100, vclks_line, cfg;
-	long vsync_clk_speed;
-	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
-	int pp_id = mixer->pp;
-
-	if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
-		dev_err(dev, "vsync_clk is not initialized\n");
-		return -EINVAL;
-	}
-
-	total_lines_x100 = mode->vtotal * mode->vrefresh;
-	if (!total_lines_x100) {
-		dev_err(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
-				__func__, mode->vtotal, mode->vrefresh);
-		return -EINVAL;
-	}
-
-	vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
-	if (vsync_clk_speed <= 0) {
-		dev_err(dev, "vsync_clk round rate failed %ld\n",
-							vsync_clk_speed);
-		return -EINVAL;
-	}
-	vclks_line = vsync_clk_speed * 100 / total_lines_x100;
-
-	cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
-		| MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
-	cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
-
-	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
-	mdp5_write(mdp5_kms,
-		REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
-	mdp5_write(mdp5_kms,
-		REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
-	mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
-	mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
-	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
-			MDP5_PP_SYNC_THRESH_START(4) |
-			MDP5_PP_SYNC_THRESH_CONTINUE(4));
-
-	return 0;
-}
-
-static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
-	int pp_id = mixer->pp;
-	int ret;
-
-	ret = clk_set_rate(mdp5_kms->vsync_clk,
-		clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
-	if (ret) {
-		dev_err(encoder->dev->dev,
-			"vsync_clk clk_set_rate failed, %d\n", ret);
-		return ret;
-	}
-	ret = clk_prepare_enable(mdp5_kms->vsync_clk);
-	if (ret) {
-		dev_err(encoder->dev->dev,
-			"vsync_clk clk_prepare_enable failed, %d\n", ret);
-		return ret;
-	}
-
-	mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
-
-	return 0;
-}
-
-static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
-	int pp_id = mixer->pp;
-
-	mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
-	clk_disable_unprepare(mdp5_kms->vsync_clk);
-}
-
-void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
-			       struct drm_display_mode *mode,
-			       struct drm_display_mode *adjusted_mode)
-{
-	mode = adjusted_mode;
-
-	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-	pingpong_tearcheck_setup(encoder, mode);
-	mdp5_crtc_set_pipeline(encoder->crtc);
-}
-
-void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
-	struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
-	struct mdp5_interface *intf = mdp5_cmd_enc->intf;
-	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
-
-	if (WARN_ON(!mdp5_cmd_enc->enabled))
-		return;
-
-	pingpong_tearcheck_disable(encoder);
-
-	mdp5_ctl_set_encoder_state(ctl, pipeline, false);
-	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
-
-	bs_set(mdp5_cmd_enc, 0);
-
-	mdp5_cmd_enc->enabled = false;
-}
-
-void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
-	struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
-	struct mdp5_interface *intf = mdp5_cmd_enc->intf;
-	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
-
-	if (WARN_ON(mdp5_cmd_enc->enabled))
-		return;
-
-	bs_set(mdp5_cmd_enc, 1);
-	if (pingpong_tearcheck_enable(encoder))
-		return;
-
-	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
-
-	mdp5_ctl_set_encoder_state(ctl, pipeline, true);
-
-	mdp5_cmd_enc->enabled = true;
-}
-
-int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
-				       struct drm_encoder *slave_encoder)
-{
-	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms;
-	struct device *dev;
-	int intf_num;
-	u32 data = 0;
-
-	if (!encoder || !slave_encoder)
-		return -EINVAL;
-
-	mdp5_kms = get_kms(encoder);
-	intf_num = mdp5_cmd_enc->intf->num;
-
-	/* Switch slave encoder's trigger MUX, to use the master's
-	 * start signal for the slave encoder
-	 */
-	if (intf_num == 1)
-		data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
-	else if (intf_num == 2)
-		data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
-	else
-		return -EINVAL;
-
-	/* Smart Panel, Sync mode */
-	data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
-
-	dev = &mdp5_kms->pdev->dev;
-
-	/* Make sure clocks are on when connectors calling this function. */
-	pm_runtime_get_sync(dev);
-	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
-
-	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
-		   MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
-	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
-	pm_runtime_put_sync(dev);
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
deleted file mode 100644
index e414850dbbda..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ /dev/null
@@ -1,1194 +0,0 @@
-/*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/sort.h>
-#include <drm/drm_mode.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_flip_work.h>
-
-#include "mdp5_kms.h"
-
-#define CURSOR_WIDTH	64
-#define CURSOR_HEIGHT	64
-
-struct mdp5_crtc {
-	struct drm_crtc base;
-	int id;
-	bool enabled;
-
-	spinlock_t lm_lock;     /* protect REG_MDP5_LM_* registers */
-
-	/* if there is a pending flip, these will be non-null: */
-	struct drm_pending_vblank_event *event;
-
-	/* Bits have been flushed at the last commit,
-	 * used to decide if a vsync has happened since last commit.
-	 */
-	u32 flushed_mask;
-
-#define PENDING_CURSOR 0x1
-#define PENDING_FLIP   0x2
-	atomic_t pending;
-
-	/* for unref'ing cursor bo's after scanout completes: */
-	struct drm_flip_work unref_cursor_work;
-
-	struct mdp_irq vblank;
-	struct mdp_irq err;
-	struct mdp_irq pp_done;
-
-	struct completion pp_completion;
-
-	bool lm_cursor_enabled;
-
-	struct {
-		/* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
-		spinlock_t lock;
-
-		/* current cursor being scanned out: */
-		struct drm_gem_object *scanout_bo;
-		uint64_t iova;
-		uint32_t width, height;
-		uint32_t x, y;
-	} cursor;
-};
-#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
-
-static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc);
-
-static struct mdp5_kms *get_kms(struct drm_crtc *crtc)
-{
-	struct msm_drm_private *priv = crtc->dev->dev_private;
-	return to_mdp5_kms(to_mdp_kms(priv->kms));
-}
-
-static void request_pending(struct drm_crtc *crtc, uint32_t pending)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-
-	atomic_or(pending, &mdp5_crtc->pending);
-	mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
-}
-
-static void request_pp_done_pending(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	reinit_completion(&mdp5_crtc->pp_completion);
-}
-
-static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
-	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
-
-	DBG("%s: flush=%08x", crtc->name, flush_mask);
-	return mdp5_ctl_commit(ctl, pipeline, flush_mask);
-}
-
-/*
- * flush updates, to make sure hw is updated to new scanout fb,
- * so that we can safely queue unref to current fb (ie. next
- * vblank we know hw is done w/ previous scanout_fb).
- */
-static u32 crtc_flush_all(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_hw_mixer *mixer, *r_mixer;
-	struct drm_plane *plane;
-	uint32_t flush_mask = 0;
-
-	/* this should not happen: */
-	if (WARN_ON(!mdp5_cstate->ctl))
-		return 0;
-
-	drm_atomic_crtc_for_each_plane(plane, crtc) {
-		if (!plane->state->visible)
-			continue;
-		flush_mask |= mdp5_plane_get_flush(plane);
-	}
-
-	mixer = mdp5_cstate->pipeline.mixer;
-	flush_mask |= mdp_ctl_flush_mask_lm(mixer->lm);
-
-	r_mixer = mdp5_cstate->pipeline.r_mixer;
-	if (r_mixer)
-		flush_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
-
-	return crtc_flush(crtc, flush_mask);
-}
-
-/* if file!=NULL, this is preclose potential cancel-flip path */
-static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
-	struct drm_device *dev = crtc->dev;
-	struct drm_pending_vblank_event *event;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-	event = mdp5_crtc->event;
-	if (event) {
-		mdp5_crtc->event = NULL;
-		DBG("%s: send event: %p", crtc->name, event);
-		drm_crtc_send_vblank_event(crtc, event);
-	}
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-
-	if (ctl && !crtc->state->enable) {
-		/* set STAGE_UNUSED for all layers */
-		mdp5_ctl_blend(ctl, pipeline, NULL, NULL, 0, 0);
-		/* XXX: What to do here? */
-		/* mdp5_crtc->ctl = NULL; */
-	}
-}
-
-static void unref_cursor_worker(struct drm_flip_work *work, void *val)
-{
-	struct mdp5_crtc *mdp5_crtc =
-		container_of(work, struct mdp5_crtc, unref_cursor_work);
-	struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base);
-	struct msm_kms *kms = &mdp5_kms->base.base;
-
-	msm_gem_put_iova(val, kms->aspace);
-	drm_gem_object_unreference_unlocked(val);
-}
-
-static void mdp5_crtc_destroy(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-
-	drm_crtc_cleanup(crtc);
-	drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work);
-
-	kfree(mdp5_crtc);
-}
-
-static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage)
-{
-	switch (stage) {
-	case STAGE0: return MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA;
-	case STAGE1: return MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA;
-	case STAGE2: return MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA;
-	case STAGE3: return MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA;
-	case STAGE4: return MDP5_LM_BLEND_COLOR_OUT_STAGE4_FG_ALPHA;
-	case STAGE5: return MDP5_LM_BLEND_COLOR_OUT_STAGE5_FG_ALPHA;
-	case STAGE6: return MDP5_LM_BLEND_COLOR_OUT_STAGE6_FG_ALPHA;
-	default:
-		return 0;
-	}
-}
-
-/*
- * left/right pipe offsets for the stage array used in blend_setup()
- */
-#define PIPE_LEFT	0
-#define PIPE_RIGHT	1
-
-/*
- * blend_setup() - blend all the planes of a CRTC
- *
- * If no base layer is available, border will be enabled as the base layer.
- * Otherwise all layers will be blended based on their stage calculated
- * in mdp5_crtc_atomic_check.
- */
-static void blend_setup(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct drm_plane *plane;
-	const struct mdp5_cfg_hw *hw_cfg;
-	struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL};
-	const struct mdp_format *format;
-	struct mdp5_hw_mixer *mixer = pipeline->mixer;
-	uint32_t lm = mixer->lm;
-	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
-	uint32_t r_lm = r_mixer ? r_mixer->lm : 0;
-	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
-	uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
-	unsigned long flags;
-	enum mdp5_pipe stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { { SSPP_NONE } };
-	enum mdp5_pipe r_stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { { SSPP_NONE } };
-	int i, plane_cnt = 0;
-	bool bg_alpha_enabled = false;
-	u32 mixer_op_mode = 0;
-	u32 val;
-#define blender(stage)	((stage) - STAGE0)
-
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-
-	spin_lock_irqsave(&mdp5_crtc->lm_lock, flags);
-
-	/* ctl could be released already when we are shutting down: */
-	/* XXX: Can this happen now? */
-	if (!ctl)
-		goto out;
-
-	/* Collect all plane information */
-	drm_atomic_crtc_for_each_plane(plane, crtc) {
-		enum mdp5_pipe right_pipe;
-
-		if (!plane->state->visible)
-			continue;
-
-		pstate = to_mdp5_plane_state(plane->state);
-		pstates[pstate->stage] = pstate;
-		stage[pstate->stage][PIPE_LEFT] = mdp5_plane_pipe(plane);
-		/*
-		 * if we have a right mixer, stage the same pipe as we
-		 * have on the left mixer
-		 */
-		if (r_mixer)
-			r_stage[pstate->stage][PIPE_LEFT] =
-						mdp5_plane_pipe(plane);
-		/*
-		 * if we have a right pipe (i.e, the plane comprises of 2
-		 * hwpipes, then stage the right pipe on the right side of both
-		 * the layer mixers
-		 */
-		right_pipe = mdp5_plane_right_pipe(plane);
-		if (right_pipe) {
-			stage[pstate->stage][PIPE_RIGHT] = right_pipe;
-			r_stage[pstate->stage][PIPE_RIGHT] = right_pipe;
-		}
-
-		plane_cnt++;
-	}
-
-	if (!pstates[STAGE_BASE]) {
-		ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
-		DBG("Border Color is enabled");
-	} else if (plane_cnt) {
-		format = to_mdp_format(msm_framebuffer_format(pstates[STAGE_BASE]->base.fb));
-
-		if (format->alpha_enable)
-			bg_alpha_enabled = true;
-	}
-
-	/* The reset for blending */
-	for (i = STAGE0; i <= STAGE_MAX; i++) {
-		if (!pstates[i])
-			continue;
-
-		format = to_mdp_format(
-			msm_framebuffer_format(pstates[i]->base.fb));
-		plane = pstates[i]->base.plane;
-		blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
-			MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST);
-		fg_alpha = pstates[i]->alpha;
-		bg_alpha = 0xFF - pstates[i]->alpha;
-
-		if (!format->alpha_enable && bg_alpha_enabled)
-			mixer_op_mode = 0;
-		else
-			mixer_op_mode |= mdp5_lm_use_fg_alpha_mask(i);
-
-		DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha);
-
-		if (format->alpha_enable && pstates[i]->premultiplied) {
-			blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
-				MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
-			if (fg_alpha != 0xff) {
-				bg_alpha = fg_alpha;
-				blend_op |=
-					MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
-					MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
-			} else {
-				blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
-			}
-		} else if (format->alpha_enable) {
-			blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_PIXEL) |
-				MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
-			if (fg_alpha != 0xff) {
-				bg_alpha = fg_alpha;
-				blend_op |=
-				       MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA |
-				       MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA |
-				       MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
-				       MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
-			} else {
-				blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
-			}
-		}
-
-		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(lm,
-				blender(i)), blend_op);
-		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
-				blender(i)), fg_alpha);
-		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
-				blender(i)), bg_alpha);
-		if (r_mixer) {
-			mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(r_lm,
-					blender(i)), blend_op);
-			mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(r_lm,
-					blender(i)), fg_alpha);
-			mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(r_lm,
-					blender(i)), bg_alpha);
-		}
-	}
-
-	val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm));
-	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm),
-		   val | mixer_op_mode);
-	if (r_mixer) {
-		val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm));
-		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm),
-			   val | mixer_op_mode);
-	}
-
-	mdp5_ctl_blend(ctl, pipeline, stage, r_stage, plane_cnt,
-		       ctl_blend_flags);
-out:
-	spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
-}
-
-static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct mdp5_hw_mixer *mixer = mdp5_cstate->pipeline.mixer;
-	struct mdp5_hw_mixer *r_mixer = mdp5_cstate->pipeline.r_mixer;
-	uint32_t lm = mixer->lm;
-	u32 mixer_width, val;
-	unsigned long flags;
-	struct drm_display_mode *mode;
-
-	if (WARN_ON(!crtc->state))
-		return;
-
-	mode = &crtc->state->adjusted_mode;
-
-	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			crtc->name, mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-
-	mixer_width = mode->hdisplay;
-	if (r_mixer)
-		mixer_width /= 2;
-
-	spin_lock_irqsave(&mdp5_crtc->lm_lock, flags);
-	mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(lm),
-			MDP5_LM_OUT_SIZE_WIDTH(mixer_width) |
-			MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
-
-	/* Assign mixer to LEFT side in source split mode */
-	val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm));
-	val &= ~MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT;
-	mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm), val);
-
-	if (r_mixer) {
-		u32 r_lm = r_mixer->lm;
-
-		mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(r_lm),
-			   MDP5_LM_OUT_SIZE_WIDTH(mixer_width) |
-			   MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
-
-		/* Assign mixer to RIGHT side in source split mode */
-		val = mdp5_read(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm));
-		val |= MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT;
-		mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm), val);
-	}
-
-	spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
-}
-
-static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc,
-				     struct drm_crtc_state *old_state)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	DBG("%s", crtc->name);
-
-	if (WARN_ON(!mdp5_crtc->enabled))
-		return;
-
-	/* Disable/save vblank irq handling before power is disabled */
-	drm_crtc_vblank_off(crtc);
-
-	if (mdp5_cstate->cmd_mode)
-		mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done);
-
-	mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
-	pm_runtime_put_sync(dev);
-
-	mdp5_crtc->enabled = false;
-}
-
-static void mdp5_crtc_atomic_enable(struct drm_crtc *crtc,
-				    struct drm_crtc_state *old_state)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	DBG("%s", crtc->name);
-
-	if (WARN_ON(mdp5_crtc->enabled))
-		return;
-
-	pm_runtime_get_sync(dev);
-
-	if (mdp5_crtc->lm_cursor_enabled) {
-		/*
-		 * Restore LM cursor state, as it might have been lost
-		 * with suspend:
-		 */
-		if (mdp5_crtc->cursor.iova) {
-			unsigned long flags;
-
-			spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
-			mdp5_crtc_restore_cursor(crtc);
-			spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
-
-			mdp5_ctl_set_cursor(mdp5_cstate->ctl,
-					    &mdp5_cstate->pipeline, 0, true);
-		} else {
-			mdp5_ctl_set_cursor(mdp5_cstate->ctl,
-					    &mdp5_cstate->pipeline, 0, false);
-		}
-	}
-
-	/* Restore vblank irq handling after power is enabled */
-	drm_crtc_vblank_on(crtc);
-
-	mdp5_crtc_mode_set_nofb(crtc);
-
-	mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
-
-	if (mdp5_cstate->cmd_mode)
-		mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->pp_done);
-
-	mdp5_crtc->enabled = true;
-}
-
-int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
-			     struct drm_crtc_state *new_crtc_state,
-			     bool need_right_mixer)
-{
-	struct mdp5_crtc_state *mdp5_cstate =
-			to_mdp5_crtc_state(new_crtc_state);
-	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
-	struct mdp5_interface *intf;
-	bool new_mixer = false;
-
-	new_mixer = !pipeline->mixer;
-
-	if ((need_right_mixer && !pipeline->r_mixer) ||
-	    (!need_right_mixer && pipeline->r_mixer))
-		new_mixer = true;
-
-	if (new_mixer) {
-		struct mdp5_hw_mixer *old_mixer = pipeline->mixer;
-		struct mdp5_hw_mixer *old_r_mixer = pipeline->r_mixer;
-		u32 caps;
-		int ret;
-
-		caps = MDP_LM_CAP_DISPLAY;
-		if (need_right_mixer)
-			caps |= MDP_LM_CAP_PAIR;
-
-		ret = mdp5_mixer_assign(new_crtc_state->state, crtc, caps,
-					&pipeline->mixer, need_right_mixer ?
-					&pipeline->r_mixer : NULL);
-		if (ret)
-			return ret;
-
-		mdp5_mixer_release(new_crtc_state->state, old_mixer);
-		if (old_r_mixer) {
-			mdp5_mixer_release(new_crtc_state->state, old_r_mixer);
-			if (!need_right_mixer)
-				pipeline->r_mixer = NULL;
-		}
-	}
-
-	/*
-	 * these should have been already set up in the encoder's atomic
-	 * check (called by drm_atomic_helper_check_modeset)
-	 */
-	intf = pipeline->intf;
-
-	mdp5_cstate->err_irqmask = intf2err(intf->num);
-	mdp5_cstate->vblank_irqmask = intf2vblank(pipeline->mixer, intf);
-
-	if ((intf->type == INTF_DSI) &&
-	    (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
-		mdp5_cstate->pp_done_irqmask = lm2ppdone(pipeline->mixer);
-		mdp5_cstate->cmd_mode = true;
-	} else {
-		mdp5_cstate->pp_done_irqmask = 0;
-		mdp5_cstate->cmd_mode = false;
-	}
-
-	return 0;
-}
-
-struct plane_state {
-	struct drm_plane *plane;
-	struct mdp5_plane_state *state;
-};
-
-static int pstate_cmp(const void *a, const void *b)
-{
-	struct plane_state *pa = (struct plane_state *)a;
-	struct plane_state *pb = (struct plane_state *)b;
-	return pa->state->zpos - pb->state->zpos;
-}
-
-/* is there a helper for this? */
-static bool is_fullscreen(struct drm_crtc_state *cstate,
-		struct drm_plane_state *pstate)
-{
-	return (pstate->crtc_x <= 0) && (pstate->crtc_y <= 0) &&
-		((pstate->crtc_x + pstate->crtc_w) >= cstate->mode.hdisplay) &&
-		((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay);
-}
-
-static enum mdp_mixer_stage_id get_start_stage(struct drm_crtc *crtc,
-					struct drm_crtc_state *new_crtc_state,
-					struct drm_plane_state *bpstate)
-{
-	struct mdp5_crtc_state *mdp5_cstate =
-			to_mdp5_crtc_state(new_crtc_state);
-
-	/*
-	 * if we're in source split mode, it's mandatory to have
-	 * border out on the base stage
-	 */
-	if (mdp5_cstate->pipeline.r_mixer)
-		return STAGE0;
-
-	/* if the bottom-most layer is not fullscreen, we need to use
-	 * it for solid-color:
-	 */
-	if (!is_fullscreen(new_crtc_state, bpstate))
-		return STAGE0;
-
-	return STAGE_BASE;
-}
-
-static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
-		struct drm_crtc_state *state)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct drm_plane *plane;
-	struct drm_device *dev = crtc->dev;
-	struct plane_state pstates[STAGE_MAX + 1];
-	const struct mdp5_cfg_hw *hw_cfg;
-	const struct drm_plane_state *pstate;
-	const struct drm_display_mode *mode = &state->adjusted_mode;
-	bool cursor_plane = false;
-	bool need_right_mixer = false;
-	int cnt = 0, i;
-	int ret;
-	enum mdp_mixer_stage_id start;
-
-	DBG("%s: check", crtc->name);
-
-	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
-		if (!pstate->visible)
-			continue;
-
-		pstates[cnt].plane = plane;
-		pstates[cnt].state = to_mdp5_plane_state(pstate);
-
-		/*
-		 * if any plane on this crtc uses 2 hwpipes, then we need
-		 * the crtc to have a right hwmixer.
-		 */
-		if (pstates[cnt].state->r_hwpipe)
-			need_right_mixer = true;
-		cnt++;
-
-		if (plane->type == DRM_PLANE_TYPE_CURSOR)
-			cursor_plane = true;
-	}
-
-	/* bail out early if there aren't any planes */
-	if (!cnt)
-		return 0;
-
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-
-	/*
-	 * we need a right hwmixer if the mode's width is greater than a single
-	 * LM's max width
-	 */
-	if (mode->hdisplay > hw_cfg->lm.max_width)
-		need_right_mixer = true;
-
-	ret = mdp5_crtc_setup_pipeline(crtc, state, need_right_mixer);
-	if (ret) {
-		dev_err(dev->dev, "couldn't assign mixers %d\n", ret);
-		return ret;
-	}
-
-	/* assign a stage based on sorted zpos property */
-	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
-
-	/* trigger a warning if cursor isn't the highest zorder */
-	WARN_ON(cursor_plane &&
-		(pstates[cnt - 1].plane->type != DRM_PLANE_TYPE_CURSOR));
-
-	start = get_start_stage(crtc, state, &pstates[0].state->base);
-
-	/* verify that there are not too many planes attached to crtc
-	 * and that we don't have conflicting mixer stages:
-	 */
-	if ((cnt + start - 1) >= hw_cfg->lm.nb_stages) {
-		dev_err(dev->dev, "too many planes! cnt=%d, start stage=%d\n",
-			cnt, start);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < cnt; i++) {
-		if (cursor_plane && (i == (cnt - 1)))
-			pstates[i].state->stage = hw_cfg->lm.nb_stages;
-		else
-			pstates[i].state->stage = start + i;
-		DBG("%s: assign pipe %s on stage=%d", crtc->name,
-				pstates[i].plane->name,
-				pstates[i].state->stage);
-	}
-
-	return 0;
-}
-
-static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
-{
-	DBG("%s: begin", crtc->name);
-}
-
-static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc,
-				   struct drm_crtc_state *old_crtc_state)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct drm_device *dev = crtc->dev;
-	unsigned long flags;
-
-	DBG("%s: event: %p", crtc->name, crtc->state->event);
-
-	WARN_ON(mdp5_crtc->event);
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-	mdp5_crtc->event = crtc->state->event;
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-
-	/*
-	 * If no CTL has been allocated in mdp5_crtc_atomic_check(),
-	 * it means we are trying to flush a CRTC whose state is disabled:
-	 * nothing else needs to be done.
-	 */
-	/* XXX: Can this happen now ? */
-	if (unlikely(!mdp5_cstate->ctl))
-		return;
-
-	blend_setup(crtc);
-
-	/* PP_DONE irq is only used by command mode for now.
-	 * It is better to request pending before FLUSH and START trigger
-	 * to make sure no pp_done irq missed.
-	 * This is safe because no pp_done will happen before SW trigger
-	 * in command mode.
-	 */
-	if (mdp5_cstate->cmd_mode)
-		request_pp_done_pending(crtc);
-
-	mdp5_crtc->flushed_mask = crtc_flush_all(crtc);
-
-	/* XXX are we leaking out state here? */
-	mdp5_crtc->vblank.irqmask = mdp5_cstate->vblank_irqmask;
-	mdp5_crtc->err.irqmask = mdp5_cstate->err_irqmask;
-	mdp5_crtc->pp_done.irqmask = mdp5_cstate->pp_done_irqmask;
-
-	request_pending(crtc, PENDING_FLIP);
-}
-
-static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	uint32_t xres = crtc->mode.hdisplay;
-	uint32_t yres = crtc->mode.vdisplay;
-
-	/*
-	 * Cursor Region Of Interest (ROI) is a plane read from cursor
-	 * buffer to render. The ROI region is determined by the visibility of
-	 * the cursor point. In the default Cursor image the cursor point will
-	 * be at the top left of the cursor image, unless it is specified
-	 * otherwise using hotspot feature.
-	 *
-	 * If the cursor point reaches the right (xres - x < cursor.width) or
-	 * bottom (yres - y < cursor.height) boundary of the screen, then ROI
-	 * width and ROI height need to be evaluated to crop the cursor image
-	 * accordingly.
-	 * (xres-x) will be new cursor width when x > (xres - cursor.width)
-	 * (yres-y) will be new cursor height when y > (yres - cursor.height)
-	 */
-	*roi_w = min(mdp5_crtc->cursor.width, xres -
-			mdp5_crtc->cursor.x);
-	*roi_h = min(mdp5_crtc->cursor.height, yres -
-			mdp5_crtc->cursor.y);
-}
-
-static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	const enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
-	uint32_t blendcfg, stride;
-	uint32_t x, y, width, height;
-	uint32_t roi_w, roi_h;
-	int lm;
-
-	assert_spin_locked(&mdp5_crtc->cursor.lock);
-
-	lm = mdp5_cstate->pipeline.mixer->lm;
-
-	x = mdp5_crtc->cursor.x;
-	y = mdp5_crtc->cursor.y;
-	width = mdp5_crtc->cursor.width;
-	height = mdp5_crtc->cursor.height;
-
-	stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0);
-
-	get_roi(crtc, &roi_w, &roi_h);
-
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
-			MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm),
-			MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
-			MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
-			MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
-			MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(lm),
-			MDP5_LM_CURSOR_START_XY_Y_START(y) |
-			MDP5_LM_CURSOR_START_XY_X_START(x));
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm),
-			mdp5_crtc->cursor.iova);
-
-	blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
-	blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
-	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
-}
-
-static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
-		struct drm_file *file, uint32_t handle,
-		uint32_t width, uint32_t height)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
-	struct drm_device *dev = crtc->dev;
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct platform_device *pdev = mdp5_kms->pdev;
-	struct msm_kms *kms = &mdp5_kms->base.base;
-	struct drm_gem_object *cursor_bo, *old_bo = NULL;
-	struct mdp5_ctl *ctl;
-	int ret;
-	uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
-	bool cursor_enable = true;
-	unsigned long flags;
-
-	if (!mdp5_crtc->lm_cursor_enabled) {
-		dev_warn(dev->dev,
-			 "cursor_set is deprecated with cursor planes\n");
-		return -EINVAL;
-	}
-
-	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
-		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
-		return -EINVAL;
-	}
-
-	ctl = mdp5_cstate->ctl;
-	if (!ctl)
-		return -EINVAL;
-
-	/* don't support LM cursors when we we have source split enabled */
-	if (mdp5_cstate->pipeline.r_mixer)
-		return -EINVAL;
-
-	if (!handle) {
-		DBG("Cursor off");
-		cursor_enable = false;
-		mdp5_crtc->cursor.iova = 0;
-		pm_runtime_get_sync(&pdev->dev);
-		goto set_cursor;
-	}
-
-	cursor_bo = drm_gem_object_lookup(file, handle);
-	if (!cursor_bo)
-		return -ENOENT;
-
-	ret = msm_gem_get_iova(cursor_bo, kms->aspace,
-			&mdp5_crtc->cursor.iova);
-	if (ret)
-		return -EINVAL;
-
-	pm_runtime_get_sync(&pdev->dev);
-
-	spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
-	old_bo = mdp5_crtc->cursor.scanout_bo;
-
-	mdp5_crtc->cursor.scanout_bo = cursor_bo;
-	mdp5_crtc->cursor.width = width;
-	mdp5_crtc->cursor.height = height;
-
-	mdp5_crtc_restore_cursor(crtc);
-
-	spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
-
-set_cursor:
-	ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable);
-	if (ret) {
-		dev_err(dev->dev, "failed to %sable cursor: %d\n",
-				cursor_enable ? "en" : "dis", ret);
-		goto end;
-	}
-
-	crtc_flush(crtc, flush_mask);
-
-end:
-	pm_runtime_put_sync(&pdev->dev);
-	if (old_bo) {
-		drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
-		/* enable vblank to complete cursor work: */
-		request_pending(crtc, PENDING_CURSOR);
-	}
-	return ret;
-}
-
-static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
-	struct drm_device *dev = crtc->dev;
-	uint32_t roi_w;
-	uint32_t roi_h;
-	unsigned long flags;
-
-	if (!mdp5_crtc->lm_cursor_enabled) {
-		dev_warn(dev->dev,
-			 "cursor_move is deprecated with cursor planes\n");
-		return -EINVAL;
-	}
-
-	/* don't support LM cursors when we we have source split enabled */
-	if (mdp5_cstate->pipeline.r_mixer)
-		return -EINVAL;
-
-	/* In case the CRTC is disabled, just drop the cursor update */
-	if (unlikely(!crtc->state->enable))
-		return 0;
-
-	mdp5_crtc->cursor.x = x = max(x, 0);
-	mdp5_crtc->cursor.y = y = max(y, 0);
-
-	get_roi(crtc, &roi_w, &roi_h);
-
-	pm_runtime_get_sync(&mdp5_kms->pdev->dev);
-
-	spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
-	mdp5_crtc_restore_cursor(crtc);
-	spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
-
-	crtc_flush(crtc, flush_mask);
-
-	pm_runtime_put_sync(&mdp5_kms->pdev->dev);
-
-	return 0;
-}
-
-static void
-mdp5_crtc_atomic_print_state(struct drm_printer *p,
-			     const struct drm_crtc_state *state)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state);
-	struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
-	struct mdp5_kms *mdp5_kms = get_kms(state->crtc);
-
-	if (WARN_ON(!pipeline))
-		return;
-
-	drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ?
-			pipeline->mixer->name : "(null)");
-
-	if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
-		drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ?
-			   pipeline->r_mixer->name : "(null)");
-}
-
-static void mdp5_crtc_reset(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate;
-
-	if (crtc->state) {
-		__drm_atomic_helper_crtc_destroy_state(crtc->state);
-		kfree(to_mdp5_crtc_state(crtc->state));
-	}
-
-	mdp5_cstate = kzalloc(sizeof(*mdp5_cstate), GFP_KERNEL);
-
-	if (mdp5_cstate) {
-		mdp5_cstate->base.crtc = crtc;
-		crtc->state = &mdp5_cstate->base;
-	}
-}
-
-static struct drm_crtc_state *
-mdp5_crtc_duplicate_state(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate;
-
-	if (WARN_ON(!crtc->state))
-		return NULL;
-
-	mdp5_cstate = kmemdup(to_mdp5_crtc_state(crtc->state),
-			      sizeof(*mdp5_cstate), GFP_KERNEL);
-	if (!mdp5_cstate)
-		return NULL;
-
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &mdp5_cstate->base);
-
-	return &mdp5_cstate->base;
-}
-
-static void mdp5_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state);
-
-	__drm_atomic_helper_crtc_destroy_state(state);
-
-	kfree(mdp5_cstate);
-}
-
-static const struct drm_crtc_funcs mdp5_crtc_funcs = {
-	.set_config = drm_atomic_helper_set_config,
-	.destroy = mdp5_crtc_destroy,
-	.page_flip = drm_atomic_helper_page_flip,
-	.reset = mdp5_crtc_reset,
-	.atomic_duplicate_state = mdp5_crtc_duplicate_state,
-	.atomic_destroy_state = mdp5_crtc_destroy_state,
-	.cursor_set = mdp5_crtc_cursor_set,
-	.cursor_move = mdp5_crtc_cursor_move,
-	.atomic_print_state = mdp5_crtc_atomic_print_state,
-};
-
-static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
-	.mode_set_nofb = mdp5_crtc_mode_set_nofb,
-	.atomic_check = mdp5_crtc_atomic_check,
-	.atomic_begin = mdp5_crtc_atomic_begin,
-	.atomic_flush = mdp5_crtc_atomic_flush,
-	.atomic_enable = mdp5_crtc_atomic_enable,
-	.atomic_disable = mdp5_crtc_atomic_disable,
-};
-
-static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
-	struct drm_crtc *crtc = &mdp5_crtc->base;
-	struct msm_drm_private *priv = crtc->dev->dev_private;
-	unsigned pending;
-
-	mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);
-
-	pending = atomic_xchg(&mdp5_crtc->pending, 0);
-
-	if (pending & PENDING_FLIP) {
-		complete_flip(crtc, NULL);
-	}
-
-	if (pending & PENDING_CURSOR)
-		drm_flip_work_commit(&mdp5_crtc->unref_cursor_work, priv->wq);
-}
-
-static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, err);
-
-	DBG("%s: error: %08x", mdp5_crtc->base.name, irqstatus);
-}
-
-static void mdp5_crtc_pp_done_irq(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc,
-								pp_done);
-
-	complete(&mdp5_crtc->pp_completion);
-}
-
-static void mdp5_crtc_wait_for_pp_done(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	int ret;
-
-	ret = wait_for_completion_timeout(&mdp5_crtc->pp_completion,
-						msecs_to_jiffies(50));
-	if (ret == 0)
-		dev_warn(dev->dev, "pp done time out, lm=%d\n",
-			 mdp5_cstate->pipeline.mixer->lm);
-}
-
-static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_ctl *ctl = mdp5_cstate->ctl;
-	int ret;
-
-	/* Should not call this function if crtc is disabled. */
-	if (!ctl)
-		return;
-
-	ret = drm_crtc_vblank_get(crtc);
-	if (ret)
-		return;
-
-	ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue,
-		((mdp5_ctl_get_commit_status(ctl) &
-		mdp5_crtc->flushed_mask) == 0),
-		msecs_to_jiffies(50));
-	if (ret <= 0)
-		dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp5_crtc->id);
-
-	mdp5_crtc->flushed_mask = 0;
-
-	drm_crtc_vblank_put(crtc);
-}
-
-uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	return mdp5_crtc->vblank.irqmask;
-}
-
-void mdp5_crtc_set_pipeline(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-
-	/* should this be done elsewhere ? */
-	mdp_irq_update(&mdp5_kms->base);
-
-	mdp5_ctl_set_pipeline(mdp5_cstate->ctl, &mdp5_cstate->pipeline);
-}
-
-struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-
-	return mdp5_cstate->ctl;
-}
-
-struct mdp5_hw_mixer *mdp5_crtc_get_mixer(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate;
-
-	if (WARN_ON(!crtc))
-		return ERR_PTR(-EINVAL);
-
-	mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-
-	return WARN_ON(!mdp5_cstate->pipeline.mixer) ?
-		ERR_PTR(-EINVAL) : mdp5_cstate->pipeline.mixer;
-}
-
-struct mdp5_pipeline *mdp5_crtc_get_pipeline(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate;
-
-	if (WARN_ON(!crtc))
-		return ERR_PTR(-EINVAL);
-
-	mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-
-	return &mdp5_cstate->pipeline;
-}
-
-void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
-{
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
-
-	if (mdp5_cstate->cmd_mode)
-		mdp5_crtc_wait_for_pp_done(crtc);
-	else
-		mdp5_crtc_wait_for_flush_done(crtc);
-}
-
-/* initialize crtc */
-struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
-				struct drm_plane *plane,
-				struct drm_plane *cursor_plane, int id)
-{
-	struct drm_crtc *crtc = NULL;
-	struct mdp5_crtc *mdp5_crtc;
-
-	mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL);
-	if (!mdp5_crtc)
-		return ERR_PTR(-ENOMEM);
-
-	crtc = &mdp5_crtc->base;
-
-	mdp5_crtc->id = id;
-
-	spin_lock_init(&mdp5_crtc->lm_lock);
-	spin_lock_init(&mdp5_crtc->cursor.lock);
-	init_completion(&mdp5_crtc->pp_completion);
-
-	mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
-	mdp5_crtc->err.irq = mdp5_crtc_err_irq;
-	mdp5_crtc->pp_done.irq = mdp5_crtc_pp_done_irq;
-
-	mdp5_crtc->lm_cursor_enabled = cursor_plane ? false : true;
-
-	drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane,
-				  &mdp5_crtc_funcs, NULL);
-
-	drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
-			"unref cursor", unref_cursor_worker);
-
-	drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
-	plane->crtc = crtc;
-
-	return crtc;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
deleted file mode 100644
index 439e0a300e25..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
+++ /dev/null
@@ -1,779 +0,0 @@
-/*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include "mdp5_kms.h"
-#include "mdp5_ctl.h"
-
-/*
- * CTL - MDP Control Pool Manager
- *
- * Controls are shared between all display interfaces.
- *
- * They are intended to be used for data path configuration.
- * The top level register programming describes the complete data path for
- * a specific data path ID - REG_MDP5_CTL_*(<id>, ...)
- *
- * Hardware capabilities determine the number of concurrent data paths
- *
- * In certain use cases (high-resolution dual pipe), one single CTL can be
- * shared across multiple CRTCs.
- */
-
-#define CTL_STAT_BUSY		0x1
-#define CTL_STAT_BOOKED	0x2
-
-struct mdp5_ctl {
-	struct mdp5_ctl_manager *ctlm;
-
-	u32 id;
-
-	/* CTL status bitmask */
-	u32 status;
-
-	bool encoder_enabled;
-	uint32_t start_mask;
-
-	/* REG_MDP5_CTL_*(<id>) registers access info + lock: */
-	spinlock_t hw_lock;
-	u32 reg_offset;
-
-	/* when do CTL registers need to be flushed? (mask of trigger bits) */
-	u32 pending_ctl_trigger;
-
-	bool cursor_on;
-
-	/* True if the current CTL has FLUSH bits pending for single FLUSH. */
-	bool flush_pending;
-
-	struct mdp5_ctl *pair; /* Paired CTL to be flushed together */
-};
-
-struct mdp5_ctl_manager {
-	struct drm_device *dev;
-
-	/* number of CTL / Layer Mixers in this hw config: */
-	u32 nlm;
-	u32 nctl;
-
-	/* to filter out non-present bits in the current hardware config */
-	u32 flush_hw_mask;
-
-	/* status for single FLUSH */
-	bool single_flush_supported;
-	u32 single_flush_pending_mask;
-
-	/* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
-	spinlock_t pool_lock;
-	struct mdp5_ctl ctls[MAX_CTL];
-};
-
-static inline
-struct mdp5_kms *get_kms(struct mdp5_ctl_manager *ctl_mgr)
-{
-	struct msm_drm_private *priv = ctl_mgr->dev->dev_private;
-
-	return to_mdp5_kms(to_mdp_kms(priv->kms));
-}
-
-static inline
-void ctl_write(struct mdp5_ctl *ctl, u32 reg, u32 data)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
-
-	(void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
-	mdp5_write(mdp5_kms, reg, data);
-}
-
-static inline
-u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
-
-	(void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
-	return mdp5_read(mdp5_kms, reg);
-}
-
-static void set_display_intf(struct mdp5_kms *mdp5_kms,
-		struct mdp5_interface *intf)
-{
-	unsigned long flags;
-	u32 intf_sel;
-
-	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-	intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
-
-	switch (intf->num) {
-	case 0:
-		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
-		intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf->type);
-		break;
-	case 1:
-		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
-		intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf->type);
-		break;
-	case 2:
-		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
-		intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf->type);
-		break;
-	case 3:
-		intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
-		intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf->type);
-		break;
-	default:
-		BUG();
-		break;
-	}
-
-	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
-	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
-}
-
-static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
-{
-	unsigned long flags;
-	struct mdp5_interface *intf = pipeline->intf;
-	u32 ctl_op = 0;
-
-	if (!mdp5_cfg_intf_is_virtual(intf->type))
-		ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
-
-	switch (intf->type) {
-	case INTF_DSI:
-		if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
-			ctl_op |= MDP5_CTL_OP_CMD_MODE;
-		break;
-
-	case INTF_WB:
-		if (intf->mode == MDP5_INTF_WB_MODE_LINE)
-			ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
-		break;
-
-	default:
-		break;
-	}
-
-	if (pipeline->r_mixer)
-		ctl_op |= MDP5_CTL_OP_PACK_3D_ENABLE |
-			  MDP5_CTL_OP_PACK_3D(1);
-
-	spin_lock_irqsave(&ctl->hw_lock, flags);
-	ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
-	spin_unlock_irqrestore(&ctl->hw_lock, flags);
-}
-
-int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
-{
-	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-	struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
-	struct mdp5_interface *intf = pipeline->intf;
-	struct mdp5_hw_mixer *mixer = pipeline->mixer;
-	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
-
-	ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) |
-			  mdp_ctl_flush_mask_encoder(intf);
-	if (r_mixer)
-		ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
-
-	/* Virtual interfaces need not set a display intf (e.g.: Writeback) */
-	if (!mdp5_cfg_intf_is_virtual(intf->type))
-		set_display_intf(mdp5_kms, intf);
-
-	set_ctl_op(ctl, pipeline);
-
-	return 0;
-}
-
-static bool start_signal_needed(struct mdp5_ctl *ctl,
-				struct mdp5_pipeline *pipeline)
-{
-	struct mdp5_interface *intf = pipeline->intf;
-
-	if (!ctl->encoder_enabled || ctl->start_mask != 0)
-		return false;
-
-	switch (intf->type) {
-	case INTF_WB:
-		return true;
-	case INTF_DSI:
-		return intf->mode == MDP5_INTF_DSI_MODE_COMMAND;
-	default:
-		return false;
-	}
-}
-
-/*
- * send_start_signal() - Overlay Processor Start Signal
- *
- * For a given control operation (display pipeline), a START signal needs to be
- * executed in order to kick off operation and activate all layers.
- * e.g.: DSI command mode, Writeback
- */
-static void send_start_signal(struct mdp5_ctl *ctl)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ctl->hw_lock, flags);
-	ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1);
-	spin_unlock_irqrestore(&ctl->hw_lock, flags);
-}
-
-static void refill_start_mask(struct mdp5_ctl *ctl,
-			      struct mdp5_pipeline *pipeline)
-{
-	struct mdp5_interface *intf = pipeline->intf;
-	struct mdp5_hw_mixer *mixer = pipeline->mixer;
-	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
-
-	ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm);
-	if (r_mixer)
-		ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
-
-	/*
-	 * Writeback encoder needs to program & flush
-	 * address registers for each page flip..
-	 */
-	if (intf->type == INTF_WB)
-		ctl->start_mask |= mdp_ctl_flush_mask_encoder(intf);
-}
-
-/**
- * mdp5_ctl_set_encoder_state() - set the encoder state
- *
- * @enable: true, when encoder is ready for data streaming; false, otherwise.
- *
- * Note:
- * This encoder state is needed to trigger START signal (data path kickoff).
- */
-int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl,
-			       struct mdp5_pipeline *pipeline,
-			       bool enabled)
-{
-	struct mdp5_interface *intf = pipeline->intf;
-
-	if (WARN_ON(!ctl))
-		return -EINVAL;
-
-	ctl->encoder_enabled = enabled;
-	DBG("intf_%d: %s", intf->num, enabled ? "on" : "off");
-
-	if (start_signal_needed(ctl, pipeline)) {
-		send_start_signal(ctl);
-		refill_start_mask(ctl, pipeline);
-	}
-
-	return 0;
-}
-
-/*
- * Note:
- * CTL registers need to be flushed after calling this function
- * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
- */
-int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-			int cursor_id, bool enable)
-{
-	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-	unsigned long flags;
-	u32 blend_cfg;
-	struct mdp5_hw_mixer *mixer = pipeline->mixer;
-
-	if (unlikely(WARN_ON(!mixer))) {
-		dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM",
-			ctl->id);
-		return -EINVAL;
-	}
-
-	if (pipeline->r_mixer) {
-		dev_err(ctl_mgr->dev->dev, "unsupported configuration");
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&ctl->hw_lock, flags);
-
-	blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm));
-
-	if (enable)
-		blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
-	else
-		blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
-
-	ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
-	ctl->cursor_on = enable;
-
-	spin_unlock_irqrestore(&ctl->hw_lock, flags);
-
-	ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
-
-	return 0;
-}
-
-static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
-		enum mdp_mixer_stage_id stage)
-{
-	switch (pipe) {
-	case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
-	case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
-	case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
-	case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
-	case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
-	case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
-	case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
-	case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
-	case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
-	case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
-	case SSPP_CURSOR0:
-	case SSPP_CURSOR1:
-	default:	return 0;
-	}
-}
-
-static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
-		enum mdp_mixer_stage_id stage)
-{
-	if (stage < STAGE6 && (pipe != SSPP_CURSOR0 && pipe != SSPP_CURSOR1))
-		return 0;
-
-	switch (pipe) {
-	case SSPP_VIG0: return MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3;
-	case SSPP_VIG1: return MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3;
-	case SSPP_VIG2: return MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3;
-	case SSPP_RGB0: return MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3;
-	case SSPP_RGB1: return MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3;
-	case SSPP_RGB2: return MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3;
-	case SSPP_DMA0: return MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3;
-	case SSPP_DMA1: return MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3;
-	case SSPP_VIG3: return MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3;
-	case SSPP_RGB3: return MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3;
-	case SSPP_CURSOR0: return MDP5_CTL_LAYER_EXT_REG_CURSOR0(stage);
-	case SSPP_CURSOR1: return MDP5_CTL_LAYER_EXT_REG_CURSOR1(stage);
-	default:	return 0;
-	}
-}
-
-static void mdp5_ctl_reset_blend_regs(struct mdp5_ctl *ctl)
-{
-	unsigned long flags;
-	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-	int i;
-
-	spin_lock_irqsave(&ctl->hw_lock, flags);
-
-	for (i = 0; i < ctl_mgr->nlm; i++) {
-		ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, i), 0x0);
-		ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, i), 0x0);
-	}
-
-	spin_unlock_irqrestore(&ctl->hw_lock, flags);
-}
-
-#define PIPE_LEFT	0
-#define PIPE_RIGHT	1
-int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-		   enum mdp5_pipe stage[][MAX_PIPE_STAGE],
-		   enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
-		   u32 stage_cnt, u32 ctl_blend_op_flags)
-{
-	struct mdp5_hw_mixer *mixer = pipeline->mixer;
-	struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
-	unsigned long flags;
-	u32 blend_cfg = 0, blend_ext_cfg = 0;
-	u32 r_blend_cfg = 0, r_blend_ext_cfg = 0;
-	int i, start_stage;
-
-	mdp5_ctl_reset_blend_regs(ctl);
-
-	if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
-		start_stage = STAGE0;
-		blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
-		if (r_mixer)
-			r_blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
-	} else {
-		start_stage = STAGE_BASE;
-	}
-
-	for (i = start_stage; stage_cnt && i <= STAGE_MAX; i++) {
-		blend_cfg |=
-			mdp_ctl_blend_mask(stage[i][PIPE_LEFT], i) |
-			mdp_ctl_blend_mask(stage[i][PIPE_RIGHT], i);
-		blend_ext_cfg |=
-			mdp_ctl_blend_ext_mask(stage[i][PIPE_LEFT], i) |
-			mdp_ctl_blend_ext_mask(stage[i][PIPE_RIGHT], i);
-		if (r_mixer) {
-			r_blend_cfg |=
-				mdp_ctl_blend_mask(r_stage[i][PIPE_LEFT], i) |
-				mdp_ctl_blend_mask(r_stage[i][PIPE_RIGHT], i);
-			r_blend_ext_cfg |=
-			     mdp_ctl_blend_ext_mask(r_stage[i][PIPE_LEFT], i) |
-			     mdp_ctl_blend_ext_mask(r_stage[i][PIPE_RIGHT], i);
-		}
-	}
-
-	spin_lock_irqsave(&ctl->hw_lock, flags);
-	if (ctl->cursor_on)
-		blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
-
-	ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
-	ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, mixer->lm),
-		  blend_ext_cfg);
-	if (r_mixer) {
-		ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, r_mixer->lm),
-			  r_blend_cfg);
-		ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, r_mixer->lm),
-			  r_blend_ext_cfg);
-	}
-	spin_unlock_irqrestore(&ctl->hw_lock, flags);
-
-	ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(mixer->lm);
-	if (r_mixer)
-		ctl->pending_ctl_trigger |= mdp_ctl_flush_mask_lm(r_mixer->lm);
-
-	DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", mixer->lm,
-		blend_cfg, blend_ext_cfg);
-	if (r_mixer)
-		DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x",
-		    r_mixer->lm, r_blend_cfg, r_blend_ext_cfg);
-
-	return 0;
-}
-
-u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf)
-{
-	if (intf->type == INTF_WB)
-		return MDP5_CTL_FLUSH_WB;
-
-	switch (intf->num) {
-	case 0: return MDP5_CTL_FLUSH_TIMING_0;
-	case 1: return MDP5_CTL_FLUSH_TIMING_1;
-	case 2: return MDP5_CTL_FLUSH_TIMING_2;
-	case 3: return MDP5_CTL_FLUSH_TIMING_3;
-	default: return 0;
-	}
-}
-
-u32 mdp_ctl_flush_mask_cursor(int cursor_id)
-{
-	switch (cursor_id) {
-	case 0: return MDP5_CTL_FLUSH_CURSOR_0;
-	case 1: return MDP5_CTL_FLUSH_CURSOR_1;
-	default: return 0;
-	}
-}
-
-u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
-{
-	switch (pipe) {
-	case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
-	case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
-	case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
-	case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
-	case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
-	case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
-	case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
-	case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
-	case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
-	case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
-	case SSPP_CURSOR0: return MDP5_CTL_FLUSH_CURSOR_0;
-	case SSPP_CURSOR1: return MDP5_CTL_FLUSH_CURSOR_1;
-	default:        return 0;
-	}
-}
-
-u32 mdp_ctl_flush_mask_lm(int lm)
-{
-	switch (lm) {
-	case 0:  return MDP5_CTL_FLUSH_LM0;
-	case 1:  return MDP5_CTL_FLUSH_LM1;
-	case 2:  return MDP5_CTL_FLUSH_LM2;
-	case 5:  return MDP5_CTL_FLUSH_LM5;
-	default: return 0;
-	}
-}
-
-static u32 fix_sw_flush(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-			u32 flush_mask)
-{
-	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-	u32 sw_mask = 0;
-#define BIT_NEEDS_SW_FIX(bit) \
-	(!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit))
-
-	/* for some targets, cursor bit is the same as LM bit */
-	if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0))
-		sw_mask |= mdp_ctl_flush_mask_lm(pipeline->mixer->lm);
-
-	return sw_mask;
-}
-
-static void fix_for_single_flush(struct mdp5_ctl *ctl, u32 *flush_mask,
-		u32 *flush_id)
-{
-	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-
-	if (ctl->pair) {
-		DBG("CTL %d FLUSH pending mask %x", ctl->id, *flush_mask);
-		ctl->flush_pending = true;
-		ctl_mgr->single_flush_pending_mask |= (*flush_mask);
-		*flush_mask = 0;
-
-		if (ctl->pair->flush_pending) {
-			*flush_id = min_t(u32, ctl->id, ctl->pair->id);
-			*flush_mask = ctl_mgr->single_flush_pending_mask;
-
-			ctl->flush_pending = false;
-			ctl->pair->flush_pending = false;
-			ctl_mgr->single_flush_pending_mask = 0;
-
-			DBG("Single FLUSH mask %x,ID %d", *flush_mask,
-				*flush_id);
-		}
-	}
-}
-
-/**
- * mdp5_ctl_commit() - Register Flush
- *
- * The flush register is used to indicate several registers are all
- * programmed, and are safe to update to the back copy of the double
- * buffered registers.
- *
- * Some registers FLUSH bits are shared when the hardware does not have
- * dedicated bits for them; handling these is the job of fix_sw_flush().
- *
- * CTL registers need to be flushed in some circumstances; if that is the
- * case, some trigger bits will be present in both flush mask and
- * ctl->pending_ctl_trigger.
- *
- * Return H/W flushed bit mask.
- */
-u32 mdp5_ctl_commit(struct mdp5_ctl *ctl,
-		    struct mdp5_pipeline *pipeline,
-		    u32 flush_mask)
-{
-	struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
-	unsigned long flags;
-	u32 flush_id = ctl->id;
-	u32 curr_ctl_flush_mask;
-
-	ctl->start_mask &= ~flush_mask;
-
-	VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask,
-			ctl->start_mask, ctl->pending_ctl_trigger);
-
-	if (ctl->pending_ctl_trigger & flush_mask) {
-		flush_mask |= MDP5_CTL_FLUSH_CTL;
-		ctl->pending_ctl_trigger = 0;
-	}
-
-	flush_mask |= fix_sw_flush(ctl, pipeline, flush_mask);
-
-	flush_mask &= ctl_mgr->flush_hw_mask;
-
-	curr_ctl_flush_mask = flush_mask;
-
-	fix_for_single_flush(ctl, &flush_mask, &flush_id);
-
-	if (flush_mask) {
-		spin_lock_irqsave(&ctl->hw_lock, flags);
-		ctl_write(ctl, REG_MDP5_CTL_FLUSH(flush_id), flush_mask);
-		spin_unlock_irqrestore(&ctl->hw_lock, flags);
-	}
-
-	if (start_signal_needed(ctl, pipeline)) {
-		send_start_signal(ctl);
-		refill_start_mask(ctl, pipeline);
-	}
-
-	return curr_ctl_flush_mask;
-}
-
-u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl)
-{
-	return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id));
-}
-
-int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
-{
-	return WARN_ON(!ctl) ? -EINVAL : ctl->id;
-}
-
-/*
- * mdp5_ctl_pair() - Associate 2 booked CTLs for single FLUSH
- */
-int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable)
-{
-	struct mdp5_ctl_manager *ctl_mgr = ctlx->ctlm;
-	struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
-
-	/* do nothing silently if hw doesn't support */
-	if (!ctl_mgr->single_flush_supported)
-		return 0;
-
-	if (!enable) {
-		ctlx->pair = NULL;
-		ctly->pair = NULL;
-		mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, 0);
-		return 0;
-	} else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) {
-		dev_err(ctl_mgr->dev->dev, "CTLs already paired\n");
-		return -EINVAL;
-	} else if (!(ctlx->status & ctly->status & CTL_STAT_BOOKED)) {
-		dev_err(ctl_mgr->dev->dev, "Only pair booked CTLs\n");
-		return -EINVAL;
-	}
-
-	ctlx->pair = ctly;
-	ctly->pair = ctlx;
-
-	mdp5_write(mdp5_kms, REG_MDP5_SPARE_0,
-		   MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
-
-	return 0;
-}
-
-/*
- * mdp5_ctl_request() - CTL allocation
- *
- * Try to return booked CTL for @intf_num is 1 or 2, unbooked for other INTFs.
- * If no CTL is available in preferred category, allocate from the other one.
- *
- * @return fail if no CTL is available.
- */
-struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
-		int intf_num)
-{
-	struct mdp5_ctl *ctl = NULL;
-	const u32 checkm = CTL_STAT_BUSY | CTL_STAT_BOOKED;
-	u32 match = ((intf_num == 1) || (intf_num == 2)) ? CTL_STAT_BOOKED : 0;
-	unsigned long flags;
-	int c;
-
-	spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
-
-	/* search the preferred */
-	for (c = 0; c < ctl_mgr->nctl; c++)
-		if ((ctl_mgr->ctls[c].status & checkm) == match)
-			goto found;
-
-	dev_warn(ctl_mgr->dev->dev,
-		"fall back to the other CTL category for INTF %d!\n", intf_num);
-
-	match ^= CTL_STAT_BOOKED;
-	for (c = 0; c < ctl_mgr->nctl; c++)
-		if ((ctl_mgr->ctls[c].status & checkm) == match)
-			goto found;
-
-	dev_err(ctl_mgr->dev->dev, "No more CTL available!");
-	goto unlock;
-
-found:
-	ctl = &ctl_mgr->ctls[c];
-	ctl->status |= CTL_STAT_BUSY;
-	ctl->pending_ctl_trigger = 0;
-	DBG("CTL %d allocated", ctl->id);
-
-unlock:
-	spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
-	return ctl;
-}
-
-void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctl_mgr)
-{
-	unsigned long flags;
-	int c;
-
-	for (c = 0; c < ctl_mgr->nctl; c++) {
-		struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
-
-		spin_lock_irqsave(&ctl->hw_lock, flags);
-		ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), 0);
-		spin_unlock_irqrestore(&ctl->hw_lock, flags);
-	}
-}
-
-void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr)
-{
-	kfree(ctl_mgr);
-}
-
-struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
-		void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd)
-{
-	struct mdp5_ctl_manager *ctl_mgr;
-	const struct mdp5_cfg_hw *hw_cfg = mdp5_cfg_get_hw_config(cfg_hnd);
-	int rev = mdp5_cfg_get_hw_rev(cfg_hnd);
-	const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
-	unsigned long flags;
-	int c, ret;
-
-	ctl_mgr = kzalloc(sizeof(*ctl_mgr), GFP_KERNEL);
-	if (!ctl_mgr) {
-		dev_err(dev->dev, "failed to allocate CTL manager\n");
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	if (unlikely(WARN_ON(ctl_cfg->count > MAX_CTL))) {
-		dev_err(dev->dev, "Increase static pool size to at least %d\n",
-				ctl_cfg->count);
-		ret = -ENOSPC;
-		goto fail;
-	}
-
-	/* initialize the CTL manager: */
-	ctl_mgr->dev = dev;
-	ctl_mgr->nlm = hw_cfg->lm.count;
-	ctl_mgr->nctl = ctl_cfg->count;
-	ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask;
-	spin_lock_init(&ctl_mgr->pool_lock);
-
-	/* initialize each CTL of the pool: */
-	spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
-	for (c = 0; c < ctl_mgr->nctl; c++) {
-		struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
-
-		if (WARN_ON(!ctl_cfg->base[c])) {
-			dev_err(dev->dev, "CTL_%d: base is null!\n", c);
-			ret = -EINVAL;
-			spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
-			goto fail;
-		}
-		ctl->ctlm = ctl_mgr;
-		ctl->id = c;
-		ctl->reg_offset = ctl_cfg->base[c];
-		ctl->status = 0;
-		spin_lock_init(&ctl->hw_lock);
-	}
-
-	/*
-	 * In Dual DSI case, CTL0 and CTL1 are always assigned to two DSI
-	 * interfaces to support single FLUSH feature (Flush CTL0 and CTL1 when
-	 * only write into CTL0's FLUSH register) to keep two DSI pipes in sync.
-	 * Single FLUSH is supported from hw rev v3.0.
-	 */
-	if (rev >= 3) {
-		ctl_mgr->single_flush_supported = true;
-		/* Reserve CTL0/1 for INTF1/2 */
-		ctl_mgr->ctls[0].status |= CTL_STAT_BOOKED;
-		ctl_mgr->ctls[1].status |= CTL_STAT_BOOKED;
-	}
-	spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
-	DBG("Pool of %d CTLs created.", ctl_mgr->nctl);
-
-	return ctl_mgr;
-
-fail:
-	if (ctl_mgr)
-		mdp5_ctlm_destroy(ctl_mgr);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
deleted file mode 100644
index b63120388dc6..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MDP5_CTL_H__
-#define __MDP5_CTL_H__
-
-#include "msm_drv.h"
-
-/*
- * CTL Manager prototypes:
- * mdp5_ctlm_init() returns a ctlm (CTL Manager) handler,
- * which is then used to call the other mdp5_ctlm_*(ctlm, ...) functions.
- */
-struct mdp5_ctl_manager;
-struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
-		void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd);
-void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm);
-void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
-
-/*
- * CTL prototypes:
- * mdp5_ctl_request(ctlm, ...) returns a ctl (CTL resource) handler,
- * which is then used to call the other mdp5_ctl_*(ctl, ...) functions.
- */
-struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, int intf_num);
-
-int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl);
-
-struct mdp5_interface;
-struct mdp5_pipeline;
-int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *p);
-int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, struct mdp5_pipeline *p,
-			       bool enabled);
-
-int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-			int cursor_id, bool enable);
-int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
-
-#define MAX_PIPE_STAGE		2
-
-/*
- * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
- *
- * @stage: array to contain the pipe num for each stage
- * @stage_cnt: valid stage number in stage array
- * @ctl_blend_op_flags: blender operation mode flags
- *
- * Note:
- * CTL registers need to be flushed after calling this function
- * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
- */
-#define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT	BIT(0)
-int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-		   enum mdp5_pipe stage[][MAX_PIPE_STAGE],
-		   enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
-		   u32 stage_cnt, u32 ctl_blend_op_flags);
-
-/**
- * mdp_ctl_flush_mask...() - Register FLUSH masks
- *
- * These masks are used to specify which block(s) need to be flushed
- * through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask).
- */
-u32 mdp_ctl_flush_mask_lm(int lm);
-u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe);
-u32 mdp_ctl_flush_mask_cursor(int cursor_id);
-u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
-
-/* @flush_mask: see CTL flush masks definitions below */
-u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
-		    u32 flush_mask);
-u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl);
-
-
-
-#endif /* __MDP5_CTL_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
deleted file mode 100644
index 36ad3cbe5f79..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "mdp5_kms.h"
-
-static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
-{
-	struct msm_drm_private *priv = encoder->dev->dev_private;
-	return to_mdp5_kms(to_mdp_kms(priv->kms));
-}
-
-#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
-#include <mach/board.h>
-#include <mach/msm_bus.h>
-#include <mach/msm_bus_board.h>
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
-	{						\
-		.src = MSM_BUS_MASTER_MDP_PORT0,	\
-		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
-		.ab = (ab_val),				\
-		.ib = (ib_val),				\
-	}
-
-static struct msm_bus_vectors mdp_bus_vectors[] = {
-	MDP_BUS_VECTOR_ENTRY(0, 0),
-	MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
-};
-static struct msm_bus_paths mdp_bus_usecases[] = { {
-		.num_paths = 1,
-		.vectors = &mdp_bus_vectors[0],
-}, {
-		.num_paths = 1,
-		.vectors = &mdp_bus_vectors[1],
-} };
-static struct msm_bus_scale_pdata mdp_bus_scale_table = {
-	.usecase = mdp_bus_usecases,
-	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
-	.name = "mdss_mdp",
-};
-
-static void bs_init(struct mdp5_encoder *mdp5_encoder)
-{
-	mdp5_encoder->bsc = msm_bus_scale_register_client(
-			&mdp_bus_scale_table);
-	DBG("bus scale client: %08x", mdp5_encoder->bsc);
-}
-
-static void bs_fini(struct mdp5_encoder *mdp5_encoder)
-{
-	if (mdp5_encoder->bsc) {
-		msm_bus_scale_unregister_client(mdp5_encoder->bsc);
-		mdp5_encoder->bsc = 0;
-	}
-}
-
-static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx)
-{
-	if (mdp5_encoder->bsc) {
-		DBG("set bus scaling: %d", idx);
-		/* HACK: scaling down, and then immediately back up
-		 * seems to leave things broken (underflow).. so
-		 * never disable:
-		 */
-		idx = 1;
-		msm_bus_scale_client_update_request(mdp5_encoder->bsc, idx);
-	}
-}
-#else
-static void bs_init(struct mdp5_encoder *mdp5_encoder) {}
-static void bs_fini(struct mdp5_encoder *mdp5_encoder) {}
-static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) {}
-#endif
-
-static void mdp5_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	bs_fini(mdp5_encoder);
-	drm_encoder_cleanup(encoder);
-	kfree(mdp5_encoder);
-}
-
-static const struct drm_encoder_funcs mdp5_encoder_funcs = {
-	.destroy = mdp5_encoder_destroy,
-};
-
-static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder,
-				      struct drm_display_mode *mode,
-				      struct drm_display_mode *adjusted_mode)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	struct drm_device *dev = encoder->dev;
-	struct drm_connector *connector;
-	int intf = mdp5_encoder->intf->num;
-	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
-	uint32_t display_v_start, display_v_end;
-	uint32_t hsync_start_x, hsync_end_x;
-	uint32_t format = 0x2100;
-	unsigned long flags;
-
-	mode = adjusted_mode;
-
-	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-			mode->base.id, mode->name,
-			mode->vrefresh, mode->clock,
-			mode->hdisplay, mode->hsync_start,
-			mode->hsync_end, mode->htotal,
-			mode->vdisplay, mode->vsync_start,
-			mode->vsync_end, mode->vtotal,
-			mode->type, mode->flags);
-
-	ctrl_pol = 0;
-
-	/* DSI controller cannot handle active-low sync signals. */
-	if (mdp5_encoder->intf->type != INTF_DSI) {
-		if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-			ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW;
-		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-			ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW;
-	}
-	/* probably need to get DATA_EN polarity from panel.. */
-
-	dtv_hsync_skew = 0;  /* get this from panel? */
-
-	/* Get color format from panel, default is 8bpc */
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			switch (connector->display_info.bpc) {
-			case 4:
-				format |= 0;
-				break;
-			case 5:
-				format |= 0x15;
-				break;
-			case 6:
-				format |= 0x2A;
-				break;
-			case 8:
-			default:
-				format |= 0x3F;
-				break;
-			}
-			break;
-		}
-	}
-
-	hsync_start_x = (mode->htotal - mode->hsync_start);
-	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
-
-	vsync_period = mode->vtotal * mode->htotal;
-	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
-	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
-	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
-
-	/*
-	 * For edp only:
-	 * DISPLAY_V_START = (VBP * HCYCLE) + HBP
-	 * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
-	 */
-	if (mdp5_encoder->intf->type == INTF_eDP) {
-		display_v_start += mode->htotal - mode->hsync_start;
-		display_v_end -= mode->hsync_start - mode->hdisplay;
-	}
-
-	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf),
-			MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) |
-			MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal));
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_PERIOD_F0(intf), vsync_period);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_LEN_F0(intf), vsync_len);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_HCTL(intf),
-			MDP5_INTF_DISPLAY_HCTL_START(hsync_start_x) |
-			MDP5_INTF_DISPLAY_HCTL_END(hsync_end_x));
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VSTART_F0(intf), display_v_start);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VEND_F0(intf), display_v_end);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_BORDER_COLOR(intf), 0);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_UNDERFLOW_COLOR(intf), 0xff);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_SKEW(intf), dtv_hsync_skew);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_POLARITY_CTL(intf), ctrl_pol);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_HCTL(intf),
-			MDP5_INTF_ACTIVE_HCTL_START(0) |
-			MDP5_INTF_ACTIVE_HCTL_END(0));
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VSTART_F0(intf), 0);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
-
-	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
-
-	mdp5_crtc_set_pipeline(encoder->crtc);
-}
-
-static void mdp5_vid_encoder_disable(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
-	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
-	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-	int intfn = mdp5_encoder->intf->num;
-	unsigned long flags;
-
-	if (WARN_ON(!mdp5_encoder->enabled))
-		return;
-
-	mdp5_ctl_set_encoder_state(ctl, pipeline, false);
-
-	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
-	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
-	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
-
-	/*
-	 * Wait for a vsync so we know the ENABLE=0 latched before
-	 * the (connector) source of the vsync's gets disabled,
-	 * otherwise we end up in a funny state if we re-enable
-	 * before the disable latches, which results that some of
-	 * the settings changes for the new modeset (like new
-	 * scanout buffer) don't latch properly..
-	 */
-	mdp_irq_wait(&mdp5_kms->base, intf2vblank(mixer, intf));
-
-	bs_set(mdp5_encoder, 0);
-
-	mdp5_encoder->enabled = false;
-}
-
-static void mdp5_vid_encoder_enable(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
-	int intfn = intf->num;
-	unsigned long flags;
-
-	if (WARN_ON(mdp5_encoder->enabled))
-		return;
-
-	bs_set(mdp5_encoder, 1);
-	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
-	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
-	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
-
-	mdp5_ctl_set_encoder_state(ctl, pipeline, true);
-
-	mdp5_encoder->enabled = true;
-}
-
-static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
-				  struct drm_display_mode *mode,
-				  struct drm_display_mode *adjusted_mode)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-
-	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
-		mdp5_cmd_encoder_mode_set(encoder, mode, adjusted_mode);
-	else
-		mdp5_vid_encoder_mode_set(encoder, mode, adjusted_mode);
-}
-
-static void mdp5_encoder_disable(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-
-	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
-		mdp5_cmd_encoder_disable(encoder);
-	else
-		mdp5_vid_encoder_disable(encoder);
-}
-
-static void mdp5_encoder_enable(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-	/* this isn't right I think */
-	struct drm_crtc_state *cstate = encoder->crtc->state;
-
-	mdp5_encoder_mode_set(encoder, &cstate->mode, &cstate->adjusted_mode);
-
-	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
-		mdp5_cmd_encoder_enable(encoder);
-	else
-		mdp5_vid_encoder_enable(encoder);
-}
-
-static int mdp5_encoder_atomic_check(struct drm_encoder *encoder,
-				     struct drm_crtc_state *crtc_state,
-				     struct drm_connector_state *conn_state)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc_state);
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
-
-	mdp5_cstate->ctl = ctl;
-	mdp5_cstate->pipeline.intf = intf;
-
-	return 0;
-}
-
-static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
-	.disable = mdp5_encoder_disable,
-	.enable = mdp5_encoder_enable,
-	.atomic_check = mdp5_encoder_atomic_check,
-};
-
-int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	int intf = mdp5_encoder->intf->num;
-
-	return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
-}
-
-u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	int intf = mdp5_encoder->intf->num;
-
-	return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
-}
-
-int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
-				       struct drm_encoder *slave_encoder)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
-	struct mdp5_kms *mdp5_kms;
-	struct device *dev;
-	int intf_num;
-	u32 data = 0;
-
-	if (!encoder || !slave_encoder)
-		return -EINVAL;
-
-	mdp5_kms = get_kms(encoder);
-	intf_num = mdp5_encoder->intf->num;
-
-	/* Switch slave encoder's TimingGen Sync mode,
-	 * to use the master's enable signal for the slave encoder.
-	 */
-	if (intf_num == 1)
-		data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC;
-	else if (intf_num == 2)
-		data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC;
-	else
-		return -EINVAL;
-
-	dev = &mdp5_kms->pdev->dev;
-	/* Make sure clocks are on when connectors calling this function. */
-	pm_runtime_get_sync(dev);
-
-	/* Dumb Panel, Sync mode */
-	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
-	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
-	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
-
-	mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);
-
-	pm_runtime_put_sync(dev);
-
-	return 0;
-}
-
-void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_interface *intf = mdp5_encoder->intf;
-
-	/* TODO: Expand this to set writeback modes too */
-	if (cmd_mode) {
-		WARN_ON(intf->type != INTF_DSI);
-		intf->mode = MDP5_INTF_DSI_MODE_COMMAND;
-	} else {
-		if (intf->type == INTF_DSI)
-			intf->mode = MDP5_INTF_DSI_MODE_VIDEO;
-		else
-			intf->mode = MDP5_INTF_MODE_NONE;
-	}
-}
-
-/* initialize encoder */
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
-				      struct mdp5_interface *intf,
-				      struct mdp5_ctl *ctl)
-{
-	struct drm_encoder *encoder = NULL;
-	struct mdp5_encoder *mdp5_encoder;
-	int enc_type = (intf->type == INTF_DSI) ?
-		DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS;
-	int ret;
-
-	mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
-	if (!mdp5_encoder) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	encoder = &mdp5_encoder->base;
-	mdp5_encoder->ctl = ctl;
-	mdp5_encoder->intf = intf;
-
-	spin_lock_init(&mdp5_encoder->intf_lock);
-
-	drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type, NULL);
-
-	drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
-
-	bs_init(mdp5_encoder);
-
-	return encoder;
-
-fail:
-	if (encoder)
-		mdp5_encoder_destroy(encoder);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
deleted file mode 100644
index 280e368bc9bb..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/irq.h>
-
-#include <drm/drm_print.h>
-
-#include "msm_drv.h"
-#include "mdp5_kms.h"
-
-void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
-		uint32_t old_irqmask)
-{
-	mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_CLEAR,
-		   irqmask ^ (irqmask & old_irqmask));
-	mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask);
-}
-
-static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp5_kms *mdp5_kms = container_of(irq, struct mdp5_kms, error_handler);
-	static DEFINE_RATELIMIT_STATE(rs, 5*HZ, 1);
-	extern bool dumpstate;
-
-	DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
-
-	if (dumpstate && __ratelimit(&rs)) {
-		struct drm_printer p = drm_info_printer(mdp5_kms->dev->dev);
-		drm_state_dump(mdp5_kms->dev, &p);
-		if (mdp5_kms->smp)
-			mdp5_smp_dump(mdp5_kms->smp, &p);
-	}
-}
-
-void mdp5_irq_preinstall(struct msm_kms *kms)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	pm_runtime_get_sync(dev);
-	mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
-	mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
-	pm_runtime_put_sync(dev);
-}
-
-int mdp5_irq_postinstall(struct msm_kms *kms)
-{
-	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
-	struct device *dev = &mdp5_kms->pdev->dev;
-	struct mdp_irq *error_handler = &mdp5_kms->error_handler;
-
-	error_handler->irq = mdp5_irq_error_handler;
-	error_handler->irqmask = MDP5_IRQ_INTF0_UNDER_RUN |
-			MDP5_IRQ_INTF1_UNDER_RUN |
-			MDP5_IRQ_INTF2_UNDER_RUN |
-			MDP5_IRQ_INTF3_UNDER_RUN;
-
-	pm_runtime_get_sync(dev);
-	mdp_irq_register(mdp_kms, error_handler);
-	pm_runtime_put_sync(dev);
-
-	return 0;
-}
-
-void mdp5_irq_uninstall(struct msm_kms *kms)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	pm_runtime_get_sync(dev);
-	mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
-	pm_runtime_put_sync(dev);
-}
-
-irqreturn_t mdp5_irq(struct msm_kms *kms)
-{
-	struct mdp_kms *mdp_kms = to_mdp_kms(kms);
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
-	struct drm_device *dev = mdp5_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	unsigned int id;
-	uint32_t status, enable;
-
-	enable = mdp5_read(mdp5_kms, REG_MDP5_INTR_EN);
-	status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS) & enable;
-	mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status);
-
-	VERB("status=%08x", status);
-
-	mdp_dispatch_irqs(mdp_kms, status);
-
-	for (id = 0; id < priv->num_crtcs; id++)
-		if (status & mdp5_crtc_vblank(priv->crtcs[id]))
-			drm_handle_vblank(dev, id);
-
-	return IRQ_HANDLED;
-}
-
-int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	pm_runtime_get_sync(dev);
-	mdp_update_vblank_mask(to_mdp_kms(kms),
-			mdp5_crtc_vblank(crtc), true);
-	pm_runtime_put_sync(dev);
-
-	return 0;
-}
-
-void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	pm_runtime_get_sync(dev);
-	mdp_update_vblank_mask(to_mdp_kms(kms),
-			mdp5_crtc_vblank(crtc), false);
-	pm_runtime_put_sync(dev);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
deleted file mode 100644
index 3e9bba4d6624..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ /dev/null
@@ -1,1067 +0,0 @@
-/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/of_irq.h>
-
-#include "msm_drv.h"
-#include "msm_gem.h"
-#include "msm_mmu.h"
-#include "mdp5_kms.h"
-
-static const char *iommu_ports[] = {
-		"mdp_0",
-};
-
-static int mdp5_hw_init(struct msm_kms *kms)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-	unsigned long flags;
-
-	pm_runtime_get_sync(dev);
-
-	/* Magic unknown register writes:
-	 *
-	 *    W VBIF:0x004 00000001      (mdss_mdp.c:839)
-	 *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839)
-	 *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839)
-	 *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839)
-	 *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839)
-	 *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839)
-	 *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839)
-	 *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839)
-	 *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839)
-	 *
-	 * Downstream fbdev driver gets these register offsets/values
-	 * from DT.. not really sure what these registers are or if
-	 * different values for different boards/SoC's, etc.  I guess
-	 * they are the golden registers.
-	 *
-	 * Not setting these does not seem to cause any problem.  But
-	 * we may be getting lucky with the bootloader initializing
-	 * them for us.  OTOH, if we can always count on the bootloader
-	 * setting the golden registers, then perhaps we don't need to
-	 * care.
-	 */
-
-	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
-	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
-
-	mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
-
-	pm_runtime_put_sync(dev);
-
-	return 0;
-}
-
-struct mdp5_state *mdp5_get_state(struct drm_atomic_state *s)
-{
-	struct msm_drm_private *priv = s->dev->dev_private;
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
-	struct msm_kms_state *state = to_kms_state(s);
-	struct mdp5_state *new_state;
-	int ret;
-
-	if (state->state)
-		return state->state;
-
-	ret = drm_modeset_lock(&mdp5_kms->state_lock, s->acquire_ctx);
-	if (ret)
-		return ERR_PTR(ret);
-
-	new_state = kmalloc(sizeof(*mdp5_kms->state), GFP_KERNEL);
-	if (!new_state)
-		return ERR_PTR(-ENOMEM);
-
-	/* Copy state: */
-	new_state->hwpipe = mdp5_kms->state->hwpipe;
-	new_state->hwmixer = mdp5_kms->state->hwmixer;
-	if (mdp5_kms->smp)
-		new_state->smp = mdp5_kms->state->smp;
-
-	state->state = new_state;
-
-	return new_state;
-}
-
-static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	swap(to_kms_state(state)->state, mdp5_kms->state);
-}
-
-static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	pm_runtime_get_sync(dev);
-
-	if (mdp5_kms->smp)
-		mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
-}
-
-static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct device *dev = &mdp5_kms->pdev->dev;
-
-	if (mdp5_kms->smp)
-		mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
-
-	pm_runtime_put_sync(dev);
-}
-
-static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms,
-						struct drm_crtc *crtc)
-{
-	mdp5_crtc_wait_for_commit_done(crtc);
-}
-
-static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
-		struct drm_encoder *encoder)
-{
-	return rate;
-}
-
-static int mdp5_set_split_display(struct msm_kms *kms,
-		struct drm_encoder *encoder,
-		struct drm_encoder *slave_encoder,
-		bool is_cmd_mode)
-{
-	if (is_cmd_mode)
-		return mdp5_cmd_encoder_set_split_display(encoder,
-							slave_encoder);
-	else
-		return mdp5_vid_encoder_set_split_display(encoder,
-							  slave_encoder);
-}
-
-static void mdp5_set_encoder_mode(struct msm_kms *kms,
-				  struct drm_encoder *encoder,
-				  bool cmd_mode)
-{
-	mdp5_encoder_set_intf_mode(encoder, cmd_mode);
-}
-
-static void mdp5_kms_destroy(struct msm_kms *kms)
-{
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct msm_gem_address_space *aspace = kms->aspace;
-	int i;
-
-	for (i = 0; i < mdp5_kms->num_hwmixers; i++)
-		mdp5_mixer_destroy(mdp5_kms->hwmixers[i]);
-
-	for (i = 0; i < mdp5_kms->num_hwpipes; i++)
-		mdp5_pipe_destroy(mdp5_kms->hwpipes[i]);
-
-	if (aspace) {
-		aspace->mmu->funcs->detach(aspace->mmu,
-				iommu_ports, ARRAY_SIZE(iommu_ports));
-		msm_gem_address_space_put(aspace);
-	}
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int smp_show(struct seq_file *m, void *arg)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
-	struct drm_printer p = drm_seq_file_printer(m);
-
-	if (!mdp5_kms->smp) {
-		drm_printf(&p, "no SMP pool\n");
-		return 0;
-	}
-
-	mdp5_smp_dump(mdp5_kms->smp, &p);
-
-	return 0;
-}
-
-static struct drm_info_list mdp5_debugfs_list[] = {
-		{"smp", smp_show },
-};
-
-static int mdp5_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)
-{
-	struct drm_device *dev = minor->dev;
-	int ret;
-
-	ret = drm_debugfs_create_files(mdp5_debugfs_list,
-			ARRAY_SIZE(mdp5_debugfs_list),
-			minor->debugfs_root, minor);
-
-	if (ret) {
-		dev_err(dev->dev, "could not install mdp5_debugfs_list\n");
-		return ret;
-	}
-
-	return 0;
-}
-#endif
-
-static const struct mdp_kms_funcs kms_funcs = {
-	.base = {
-		.hw_init         = mdp5_hw_init,
-		.irq_preinstall  = mdp5_irq_preinstall,
-		.irq_postinstall = mdp5_irq_postinstall,
-		.irq_uninstall   = mdp5_irq_uninstall,
-		.irq             = mdp5_irq,
-		.enable_vblank   = mdp5_enable_vblank,
-		.disable_vblank  = mdp5_disable_vblank,
-		.swap_state      = mdp5_swap_state,
-		.prepare_commit  = mdp5_prepare_commit,
-		.complete_commit = mdp5_complete_commit,
-		.wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done,
-		.get_format      = mdp_get_format,
-		.round_pixclk    = mdp5_round_pixclk,
-		.set_split_display = mdp5_set_split_display,
-		.set_encoder_mode = mdp5_set_encoder_mode,
-		.destroy         = mdp5_kms_destroy,
-#ifdef CONFIG_DEBUG_FS
-		.debugfs_init    = mdp5_kms_debugfs_init,
-#endif
-	},
-	.set_irqmask         = mdp5_set_irqmask,
-};
-
-int mdp5_disable(struct mdp5_kms *mdp5_kms)
-{
-	DBG("");
-
-	mdp5_kms->enable_count--;
-	WARN_ON(mdp5_kms->enable_count < 0);
-
-	clk_disable_unprepare(mdp5_kms->ahb_clk);
-	clk_disable_unprepare(mdp5_kms->axi_clk);
-	clk_disable_unprepare(mdp5_kms->core_clk);
-	if (mdp5_kms->lut_clk)
-		clk_disable_unprepare(mdp5_kms->lut_clk);
-
-	return 0;
-}
-
-int mdp5_enable(struct mdp5_kms *mdp5_kms)
-{
-	DBG("");
-
-	mdp5_kms->enable_count++;
-
-	clk_prepare_enable(mdp5_kms->ahb_clk);
-	clk_prepare_enable(mdp5_kms->axi_clk);
-	clk_prepare_enable(mdp5_kms->core_clk);
-	if (mdp5_kms->lut_clk)
-		clk_prepare_enable(mdp5_kms->lut_clk);
-
-	return 0;
-}
-
-static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
-					     struct mdp5_interface *intf,
-					     struct mdp5_ctl *ctl)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	struct drm_encoder *encoder;
-
-	encoder = mdp5_encoder_init(dev, intf, ctl);
-	if (IS_ERR(encoder)) {
-		dev_err(dev->dev, "failed to construct encoder\n");
-		return encoder;
-	}
-
-	priv->encoders[priv->num_encoders++] = encoder;
-
-	return encoder;
-}
-
-static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
-{
-	const enum mdp5_intf_type *intfs = hw_cfg->intf.connect;
-	const int intf_cnt = ARRAY_SIZE(hw_cfg->intf.connect);
-	int id = 0, i;
-
-	for (i = 0; i < intf_cnt; i++) {
-		if (intfs[i] == INTF_DSI) {
-			if (intf_num == i)
-				return id;
-
-			id++;
-		}
-	}
-
-	return -EINVAL;
-}
-
-static int modeset_init_intf(struct mdp5_kms *mdp5_kms,
-			     struct mdp5_interface *intf)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;
-	struct mdp5_ctl *ctl;
-	struct drm_encoder *encoder;
-	int ret = 0;
-
-	switch (intf->type) {
-	case INTF_eDP:
-		if (!priv->edp)
-			break;
-
-		ctl = mdp5_ctlm_request(ctlm, intf->num);
-		if (!ctl) {
-			ret = -EINVAL;
-			break;
-		}
-
-		encoder = construct_encoder(mdp5_kms, intf, ctl);
-		if (IS_ERR(encoder)) {
-			ret = PTR_ERR(encoder);
-			break;
-		}
-
-		ret = msm_edp_modeset_init(priv->edp, dev, encoder);
-		break;
-	case INTF_HDMI:
-		if (!priv->hdmi)
-			break;
-
-		ctl = mdp5_ctlm_request(ctlm, intf->num);
-		if (!ctl) {
-			ret = -EINVAL;
-			break;
-		}
-
-		encoder = construct_encoder(mdp5_kms, intf, ctl);
-		if (IS_ERR(encoder)) {
-			ret = PTR_ERR(encoder);
-			break;
-		}
-
-		ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);
-		break;
-	case INTF_DSI:
-	{
-		const struct mdp5_cfg_hw *hw_cfg =
-					mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-		int dsi_id = get_dsi_id_from_intf(hw_cfg, intf->num);
-
-		if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
-			dev_err(dev->dev, "failed to find dsi from intf %d\n",
-				intf->num);
-			ret = -EINVAL;
-			break;
-		}
-
-		if (!priv->dsi[dsi_id])
-			break;
-
-		ctl = mdp5_ctlm_request(ctlm, intf->num);
-		if (!ctl) {
-			ret = -EINVAL;
-			break;
-		}
-
-		encoder = construct_encoder(mdp5_kms, intf, ctl);
-		if (IS_ERR(encoder)) {
-			ret = PTR_ERR(encoder);
-			break;
-		}
-
-		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
-		break;
-	}
-	default:
-		dev_err(dev->dev, "unknown intf: %d\n", intf->type);
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static int modeset_init(struct mdp5_kms *mdp5_kms)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	struct msm_drm_private *priv = dev->dev_private;
-	const struct mdp5_cfg_hw *hw_cfg;
-	unsigned int num_crtcs;
-	int i, ret, pi = 0, ci = 0;
-	struct drm_plane *primary[MAX_BASES] = { NULL };
-	struct drm_plane *cursor[MAX_BASES] = { NULL };
-
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-
-	/*
-	 * Construct encoders and modeset initialize connector devices
-	 * for each external display interface.
-	 */
-	for (i = 0; i < mdp5_kms->num_intfs; i++) {
-		ret = modeset_init_intf(mdp5_kms, mdp5_kms->intfs[i]);
-		if (ret)
-			goto fail;
-	}
-
-	/*
-	 * We should ideally have less number of encoders (set up by parsing
-	 * the MDP5 interfaces) than the number of layer mixers present in HW,
-	 * but let's be safe here anyway
-	 */
-	num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers);
-
-	/*
-	 * Construct planes equaling the number of hw pipes, and CRTCs for the
-	 * N encoders set up by the driver. The first N planes become primary
-	 * planes for the CRTCs, with the remainder as overlay planes:
-	 */
-	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
-		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
-		struct drm_plane *plane;
-		enum drm_plane_type type;
-
-		if (i < num_crtcs)
-			type = DRM_PLANE_TYPE_PRIMARY;
-		else if (hwpipe->caps & MDP_PIPE_CAP_CURSOR)
-			type = DRM_PLANE_TYPE_CURSOR;
-		else
-			type = DRM_PLANE_TYPE_OVERLAY;
-
-		plane = mdp5_plane_init(dev, type);
-		if (IS_ERR(plane)) {
-			ret = PTR_ERR(plane);
-			dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
-			goto fail;
-		}
-		priv->planes[priv->num_planes++] = plane;
-
-		if (type == DRM_PLANE_TYPE_PRIMARY)
-			primary[pi++] = plane;
-		if (type == DRM_PLANE_TYPE_CURSOR)
-			cursor[ci++] = plane;
-	}
-
-	for (i = 0; i < num_crtcs; i++) {
-		struct drm_crtc *crtc;
-
-		crtc  = mdp5_crtc_init(dev, primary[i], cursor[i], i);
-		if (IS_ERR(crtc)) {
-			ret = PTR_ERR(crtc);
-			dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
-			goto fail;
-		}
-		priv->crtcs[priv->num_crtcs++] = crtc;
-	}
-
-	/*
-	 * Now that we know the number of crtcs we've created, set the possible
-	 * crtcs for the encoders
-	 */
-	for (i = 0; i < priv->num_encoders; i++) {
-		struct drm_encoder *encoder = priv->encoders[i];
-
-		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
-	}
-
-	return 0;
-
-fail:
-	return ret;
-}
-
-static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,
-				 u32 *major, u32 *minor)
-{
-	struct device *dev = &mdp5_kms->pdev->dev;
-	u32 version;
-
-	pm_runtime_get_sync(dev);
-	version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION);
-	pm_runtime_put_sync(dev);
-
-	*major = FIELD(version, MDP5_HW_VERSION_MAJOR);
-	*minor = FIELD(version, MDP5_HW_VERSION_MINOR);
-
-	dev_info(dev, "MDP5 version v%d.%d", *major, *minor);
-}
-
-static int get_clk(struct platform_device *pdev, struct clk **clkp,
-		const char *name, bool mandatory)
-{
-	struct device *dev = &pdev->dev;
-	struct clk *clk = msm_clk_get(pdev, name);
-	if (IS_ERR(clk) && mandatory) {
-		dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
-		return PTR_ERR(clk);
-	}
-	if (IS_ERR(clk))
-		DBG("skipping %s", name);
-	else
-		*clkp = clk;
-
-	return 0;
-}
-
-static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_encoder *encoder;
-
-	drm_for_each_encoder(encoder, dev)
-		if (encoder->crtc == crtc)
-			return encoder;
-
-	return NULL;
-}
-
-static bool mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
-				bool in_vblank_irq, int *vpos, int *hpos,
-				ktime_t *stime, ktime_t *etime,
-				const struct drm_display_mode *mode)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	struct drm_crtc *crtc;
-	struct drm_encoder *encoder;
-	int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
-
-	crtc = priv->crtcs[pipe];
-	if (!crtc) {
-		DRM_ERROR("Invalid crtc %d\n", pipe);
-		return false;
-	}
-
-	encoder = get_encoder_from_crtc(crtc);
-	if (!encoder) {
-		DRM_ERROR("no encoder found for crtc %d\n", pipe);
-		return false;
-	}
-
-	vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
-	vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
-
-	/*
-	 * the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
-	 * the end of VFP. Translate the porch values relative to the line
-	 * counter positions.
-	 */
-
-	vactive_start = vsw + vbp + 1;
-
-	vactive_end = vactive_start + mode->crtc_vdisplay;
-
-	/* last scan line before VSYNC */
-	vfp_end = mode->crtc_vtotal;
-
-	if (stime)
-		*stime = ktime_get();
-
-	line = mdp5_encoder_get_linecount(encoder);
-
-	if (line < vactive_start) {
-		line -= vactive_start;
-	} else if (line > vactive_end) {
-		line = line - vfp_end - vactive_start;
-	} else {
-		line -= vactive_start;
-	}
-
-	*vpos = line;
-	*hpos = 0;
-
-	if (etime)
-		*etime = ktime_get();
-
-	return true;
-}
-
-static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	struct drm_crtc *crtc;
-	struct drm_encoder *encoder;
-
-	if (pipe >= priv->num_crtcs)
-		return 0;
-
-	crtc = priv->crtcs[pipe];
-	if (!crtc)
-		return 0;
-
-	encoder = get_encoder_from_crtc(crtc);
-	if (!encoder)
-		return 0;
-
-	return mdp5_encoder_get_framecount(encoder);
-}
-
-struct msm_kms *mdp5_kms_init(struct drm_device *dev)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	struct platform_device *pdev;
-	struct mdp5_kms *mdp5_kms;
-	struct mdp5_cfg *config;
-	struct msm_kms *kms;
-	struct msm_gem_address_space *aspace;
-	int irq, i, ret;
-
-	/* priv->kms would have been populated by the MDP5 driver */
-	kms = priv->kms;
-	if (!kms)
-		return NULL;
-
-	mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-
-	mdp_kms_init(&mdp5_kms->base, &kms_funcs);
-
-	pdev = mdp5_kms->pdev;
-
-	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
-	if (irq < 0) {
-		ret = irq;
-		dev_err(&pdev->dev, "failed to get irq: %d\n", ret);
-		goto fail;
-	}
-
-	kms->irq = irq;
-
-	config = mdp5_cfg_get_config(mdp5_kms->cfg);
-
-	/* make sure things are off before attaching iommu (bootloader could
-	 * have left things on, in which case we'll start getting faults if
-	 * we don't disable):
-	 */
-	pm_runtime_get_sync(&pdev->dev);
-	for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
-		if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
-		    !config->hw->intf.base[i])
-			continue;
-		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
-
-		mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
-	}
-	mdelay(16);
-
-	if (config->platform.iommu) {
-		aspace = msm_gem_address_space_create(&pdev->dev,
-				config->platform.iommu, "mdp5");
-		if (IS_ERR(aspace)) {
-			ret = PTR_ERR(aspace);
-			goto fail;
-		}
-
-		kms->aspace = aspace;
-
-		ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
-				ARRAY_SIZE(iommu_ports));
-		if (ret) {
-			dev_err(&pdev->dev, "failed to attach iommu: %d\n",
-				ret);
-			goto fail;
-		}
-	} else {
-		dev_info(&pdev->dev,
-			 "no iommu, fallback to phys contig buffers for scanout\n");
-		aspace = NULL;;
-	}
-
-	pm_runtime_put_sync(&pdev->dev);
-
-	ret = modeset_init(mdp5_kms);
-	if (ret) {
-		dev_err(&pdev->dev, "modeset_init failed: %d\n", ret);
-		goto fail;
-	}
-
-	dev->mode_config.min_width = 0;
-	dev->mode_config.min_height = 0;
-	dev->mode_config.max_width = 0xffff;
-	dev->mode_config.max_height = 0xffff;
-
-	dev->driver->get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos;
-	dev->driver->get_scanout_position = mdp5_get_scanoutpos;
-	dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
-	dev->max_vblank_count = 0xffffffff;
-	dev->vblank_disable_immediate = true;
-
-	return kms;
-fail:
-	if (kms)
-		mdp5_kms_destroy(kms);
-	return ERR_PTR(ret);
-}
-
-static void mdp5_destroy(struct platform_device *pdev)
-{
-	struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
-	int i;
-
-	if (mdp5_kms->ctlm)
-		mdp5_ctlm_destroy(mdp5_kms->ctlm);
-	if (mdp5_kms->smp)
-		mdp5_smp_destroy(mdp5_kms->smp);
-	if (mdp5_kms->cfg)
-		mdp5_cfg_destroy(mdp5_kms->cfg);
-
-	for (i = 0; i < mdp5_kms->num_intfs; i++)
-		kfree(mdp5_kms->intfs[i]);
-
-	if (mdp5_kms->rpm_enabled)
-		pm_runtime_disable(&pdev->dev);
-
-	kfree(mdp5_kms->state);
-}
-
-static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt,
-		const enum mdp5_pipe *pipes, const uint32_t *offsets,
-		uint32_t caps)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	int i, ret;
-
-	for (i = 0; i < cnt; i++) {
-		struct mdp5_hw_pipe *hwpipe;
-
-		hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps);
-		if (IS_ERR(hwpipe)) {
-			ret = PTR_ERR(hwpipe);
-			dev_err(dev->dev, "failed to construct pipe for %s (%d)\n",
-					pipe2name(pipes[i]), ret);
-			return ret;
-		}
-		hwpipe->idx = mdp5_kms->num_hwpipes;
-		mdp5_kms->hwpipes[mdp5_kms->num_hwpipes++] = hwpipe;
-	}
-
-	return 0;
-}
-
-static int hwpipe_init(struct mdp5_kms *mdp5_kms)
-{
-	static const enum mdp5_pipe rgb_planes[] = {
-			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
-	};
-	static const enum mdp5_pipe vig_planes[] = {
-			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
-	};
-	static const enum mdp5_pipe dma_planes[] = {
-			SSPP_DMA0, SSPP_DMA1,
-	};
-	static const enum mdp5_pipe cursor_planes[] = {
-			SSPP_CURSOR0, SSPP_CURSOR1,
-	};
-	const struct mdp5_cfg_hw *hw_cfg;
-	int ret;
-
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-
-	/* Construct RGB pipes: */
-	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_rgb.count, rgb_planes,
-			hw_cfg->pipe_rgb.base, hw_cfg->pipe_rgb.caps);
-	if (ret)
-		return ret;
-
-	/* Construct video (VIG) pipes: */
-	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_vig.count, vig_planes,
-			hw_cfg->pipe_vig.base, hw_cfg->pipe_vig.caps);
-	if (ret)
-		return ret;
-
-	/* Construct DMA pipes: */
-	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_dma.count, dma_planes,
-			hw_cfg->pipe_dma.base, hw_cfg->pipe_dma.caps);
-	if (ret)
-		return ret;
-
-	/* Construct cursor pipes: */
-	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_cursor.count,
-			cursor_planes, hw_cfg->pipe_cursor.base,
-			hw_cfg->pipe_cursor.caps);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int hwmixer_init(struct mdp5_kms *mdp5_kms)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	const struct mdp5_cfg_hw *hw_cfg;
-	int i, ret;
-
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-
-	for (i = 0; i < hw_cfg->lm.count; i++) {
-		struct mdp5_hw_mixer *mixer;
-
-		mixer = mdp5_mixer_init(&hw_cfg->lm.instances[i]);
-		if (IS_ERR(mixer)) {
-			ret = PTR_ERR(mixer);
-			dev_err(dev->dev, "failed to construct LM%d (%d)\n",
-				i, ret);
-			return ret;
-		}
-
-		mixer->idx = mdp5_kms->num_hwmixers;
-		mdp5_kms->hwmixers[mdp5_kms->num_hwmixers++] = mixer;
-	}
-
-	return 0;
-}
-
-static int interface_init(struct mdp5_kms *mdp5_kms)
-{
-	struct drm_device *dev = mdp5_kms->dev;
-	const struct mdp5_cfg_hw *hw_cfg;
-	const enum mdp5_intf_type *intf_types;
-	int i;
-
-	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
-	intf_types = hw_cfg->intf.connect;
-
-	for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
-		struct mdp5_interface *intf;
-
-		if (intf_types[i] == INTF_DISABLED)
-			continue;
-
-		intf = kzalloc(sizeof(*intf), GFP_KERNEL);
-		if (!intf) {
-			dev_err(dev->dev, "failed to construct INTF%d\n", i);
-			return -ENOMEM;
-		}
-
-		intf->num = i;
-		intf->type = intf_types[i];
-		intf->mode = MDP5_INTF_MODE_NONE;
-		intf->idx = mdp5_kms->num_intfs;
-		mdp5_kms->intfs[mdp5_kms->num_intfs++] = intf;
-	}
-
-	return 0;
-}
-
-static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	struct mdp5_kms *mdp5_kms;
-	struct mdp5_cfg *config;
-	u32 major, minor;
-	int ret;
-
-	mdp5_kms = devm_kzalloc(&pdev->dev, sizeof(*mdp5_kms), GFP_KERNEL);
-	if (!mdp5_kms) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	platform_set_drvdata(pdev, mdp5_kms);
-
-	spin_lock_init(&mdp5_kms->resource_lock);
-
-	mdp5_kms->dev = dev;
-	mdp5_kms->pdev = pdev;
-
-	drm_modeset_lock_init(&mdp5_kms->state_lock);
-	mdp5_kms->state = kzalloc(sizeof(*mdp5_kms->state), GFP_KERNEL);
-	if (!mdp5_kms->state) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
-	if (IS_ERR(mdp5_kms->mmio)) {
-		ret = PTR_ERR(mdp5_kms->mmio);
-		goto fail;
-	}
-
-	/* mandatory clocks: */
-	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus", true);
-	if (ret)
-		goto fail;
-	ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface", true);
-	if (ret)
-		goto fail;
-	ret = get_clk(pdev, &mdp5_kms->core_clk, "core", true);
-	if (ret)
-		goto fail;
-	ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync", true);
-	if (ret)
-		goto fail;
-
-	/* optional clocks: */
-	get_clk(pdev, &mdp5_kms->lut_clk, "lut", false);
-
-	/* we need to set a default rate before enabling.  Set a safe
-	 * rate first, then figure out hw revision, and then set a
-	 * more optimal rate:
-	 */
-	clk_set_rate(mdp5_kms->core_clk, 200000000);
-
-	pm_runtime_enable(&pdev->dev);
-	mdp5_kms->rpm_enabled = true;
-
-	read_mdp_hw_revision(mdp5_kms, &major, &minor);
-
-	mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor);
-	if (IS_ERR(mdp5_kms->cfg)) {
-		ret = PTR_ERR(mdp5_kms->cfg);
-		mdp5_kms->cfg = NULL;
-		goto fail;
-	}
-
-	config = mdp5_cfg_get_config(mdp5_kms->cfg);
-	mdp5_kms->caps = config->hw->mdp.caps;
-
-	/* TODO: compute core clock rate at runtime */
-	clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk);
-
-	/*
-	 * Some chipsets have a Shared Memory Pool (SMP), while others
-	 * have dedicated latency buffering per source pipe instead;
-	 * this section initializes the SMP:
-	 */
-	if (mdp5_kms->caps & MDP_CAP_SMP) {
-		mdp5_kms->smp = mdp5_smp_init(mdp5_kms, &config->hw->smp);
-		if (IS_ERR(mdp5_kms->smp)) {
-			ret = PTR_ERR(mdp5_kms->smp);
-			mdp5_kms->smp = NULL;
-			goto fail;
-		}
-	}
-
-	mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg);
-	if (IS_ERR(mdp5_kms->ctlm)) {
-		ret = PTR_ERR(mdp5_kms->ctlm);
-		mdp5_kms->ctlm = NULL;
-		goto fail;
-	}
-
-	ret = hwpipe_init(mdp5_kms);
-	if (ret)
-		goto fail;
-
-	ret = hwmixer_init(mdp5_kms);
-	if (ret)
-		goto fail;
-
-	ret = interface_init(mdp5_kms);
-	if (ret)
-		goto fail;
-
-	/* set uninit-ed kms */
-	priv->kms = &mdp5_kms->base.base;
-
-	return 0;
-fail:
-	mdp5_destroy(pdev);
-	return ret;
-}
-
-static int mdp5_bind(struct device *dev, struct device *master, void *data)
-{
-	struct drm_device *ddev = dev_get_drvdata(master);
-	struct platform_device *pdev = to_platform_device(dev);
-
-	DBG("");
-
-	return mdp5_init(pdev, ddev);
-}
-
-static void mdp5_unbind(struct device *dev, struct device *master,
-			void *data)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-
-	mdp5_destroy(pdev);
-}
-
-static const struct component_ops mdp5_ops = {
-	.bind   = mdp5_bind,
-	.unbind = mdp5_unbind,
-};
-
-static int mdp5_dev_probe(struct platform_device *pdev)
-{
-	DBG("");
-	return component_add(&pdev->dev, &mdp5_ops);
-}
-
-static int mdp5_dev_remove(struct platform_device *pdev)
-{
-	DBG("");
-	component_del(&pdev->dev, &mdp5_ops);
-	return 0;
-}
-
-static __maybe_unused int mdp5_runtime_suspend(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
-
-	DBG("");
-
-	return mdp5_disable(mdp5_kms);
-}
-
-static __maybe_unused int mdp5_runtime_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
-
-	DBG("");
-
-	return mdp5_enable(mdp5_kms);
-}
-
-static const struct dev_pm_ops mdp5_pm_ops = {
-	SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL)
-};
-
-static const struct of_device_id mdp5_dt_match[] = {
-	{ .compatible = "qcom,mdp5", },
-	/* to support downstream DT files */
-	{ .compatible = "qcom,mdss_mdp", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, mdp5_dt_match);
-
-static struct platform_driver mdp5_driver = {
-	.probe = mdp5_dev_probe,
-	.remove = mdp5_dev_remove,
-	.driver = {
-		.name = "msm_mdp",
-		.of_match_table = mdp5_dt_match,
-		.pm = &mdp5_pm_ops,
-	},
-};
-
-void __init msm_mdp_register(void)
-{
-	DBG("");
-	platform_driver_register(&mdp5_driver);
-}
-
-void __exit msm_mdp_unregister(void)
-{
-	DBG("");
-	platform_driver_unregister(&mdp5_driver);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
deleted file mode 100644
index 9b3fe01089d1..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MDP5_KMS_H__
-#define __MDP5_KMS_H__
-
-#include "msm_drv.h"
-#include "msm_kms.h"
-#include "mdp/mdp_kms.h"
-#include "mdp5_cfg.h"	/* must be included before mdp5.xml.h */
-#include "mdp5.xml.h"
-#include "mdp5_pipe.h"
-#include "mdp5_mixer.h"
-#include "mdp5_ctl.h"
-#include "mdp5_smp.h"
-
-struct mdp5_state;
-
-struct mdp5_kms {
-	struct mdp_kms base;
-
-	struct drm_device *dev;
-
-	struct platform_device *pdev;
-
-	unsigned num_hwpipes;
-	struct mdp5_hw_pipe *hwpipes[SSPP_MAX];
-
-	unsigned num_hwmixers;
-	struct mdp5_hw_mixer *hwmixers[8];
-
-	unsigned num_intfs;
-	struct mdp5_interface *intfs[5];
-
-	struct mdp5_cfg_handler *cfg;
-	uint32_t caps;	/* MDP capabilities (MDP_CAP_XXX bits) */
-
-	/**
-	 * Global atomic state.  Do not access directly, use mdp5_get_state()
-	 */
-	struct mdp5_state *state;
-	struct drm_modeset_lock state_lock;
-
-	struct mdp5_smp *smp;
-	struct mdp5_ctl_manager *ctlm;
-
-	/* io/register spaces: */
-	void __iomem *mmio;
-
-	struct clk *axi_clk;
-	struct clk *ahb_clk;
-	struct clk *core_clk;
-	struct clk *lut_clk;
-	struct clk *vsync_clk;
-
-	/*
-	 * lock to protect access to global resources: ie., following register:
-	 *	- REG_MDP5_DISP_INTF_SEL
-	 */
-	spinlock_t resource_lock;
-
-	bool rpm_enabled;
-
-	struct mdp_irq error_handler;
-
-	int enable_count;
-};
-#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)
-
-/* Global atomic state for tracking resources that are shared across
- * multiple kms objects (planes/crtcs/etc).
- *
- * For atomic updates which require modifying global state,
- */
-struct mdp5_state {
-	struct mdp5_hw_pipe_state hwpipe;
-	struct mdp5_hw_mixer_state hwmixer;
-	struct mdp5_smp_state smp;
-};
-
-struct mdp5_state *__must_check
-mdp5_get_state(struct drm_atomic_state *s);
-
-/* Atomic plane state.  Subclasses the base drm_plane_state in order to
- * track assigned hwpipe and hw specific state.
- */
-struct mdp5_plane_state {
-	struct drm_plane_state base;
-
-	struct mdp5_hw_pipe *hwpipe;
-	struct mdp5_hw_pipe *r_hwpipe;	/* right hwpipe */
-
-	/* aligned with property */
-	uint8_t premultiplied;
-	uint8_t zpos;
-	uint8_t alpha;
-
-	/* assigned by crtc blender */
-	enum mdp_mixer_stage_id stage;
-};
-#define to_mdp5_plane_state(x) \
-		container_of(x, struct mdp5_plane_state, base)
-
-struct mdp5_pipeline {
-	struct mdp5_interface *intf;
-	struct mdp5_hw_mixer *mixer;
-	struct mdp5_hw_mixer *r_mixer;	/* right mixer */
-};
-
-struct mdp5_crtc_state {
-	struct drm_crtc_state base;
-
-	struct mdp5_ctl *ctl;
-	struct mdp5_pipeline pipeline;
-
-	/* these are derivatives of intf/mixer state in mdp5_pipeline */
-	u32 vblank_irqmask;
-	u32 err_irqmask;
-	u32 pp_done_irqmask;
-
-	bool cmd_mode;
-};
-#define to_mdp5_crtc_state(x) \
-		container_of(x, struct mdp5_crtc_state, base)
-
-enum mdp5_intf_mode {
-	MDP5_INTF_MODE_NONE = 0,
-
-	/* Modes used for DSI interface (INTF_DSI type): */
-	MDP5_INTF_DSI_MODE_VIDEO,
-	MDP5_INTF_DSI_MODE_COMMAND,
-
-	/* Modes used for WB interface (INTF_WB type):  */
-	MDP5_INTF_WB_MODE_BLOCK,
-	MDP5_INTF_WB_MODE_LINE,
-};
-
-struct mdp5_interface {
-	int idx;
-	int num; /* display interface number */
-	enum mdp5_intf_type type;
-	enum mdp5_intf_mode mode;
-};
-
-struct mdp5_encoder {
-	struct drm_encoder base;
-	spinlock_t intf_lock;	/* protect REG_MDP5_INTF_* registers */
-	bool enabled;
-	uint32_t bsc;
-
-	struct mdp5_interface *intf;
-	struct mdp5_ctl *ctl;
-};
-#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
-
-static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
-{
-	WARN_ON(mdp5_kms->enable_count <= 0);
-	msm_writel(data, mdp5_kms->mmio + reg);
-}
-
-static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg)
-{
-	WARN_ON(mdp5_kms->enable_count <= 0);
-	return msm_readl(mdp5_kms->mmio + reg);
-}
-
-static inline const char *stage2name(enum mdp_mixer_stage_id stage)
-{
-	static const char *names[] = {
-#define NAME(n) [n] = #n
-		NAME(STAGE_UNUSED), NAME(STAGE_BASE),
-		NAME(STAGE0), NAME(STAGE1), NAME(STAGE2),
-		NAME(STAGE3), NAME(STAGE4), NAME(STAGE6),
-#undef NAME
-	};
-	return names[stage];
-}
-
-static inline const char *pipe2name(enum mdp5_pipe pipe)
-{
-	static const char *names[] = {
-#define NAME(n) [SSPP_ ## n] = #n
-		NAME(VIG0), NAME(VIG1), NAME(VIG2),
-		NAME(RGB0), NAME(RGB1), NAME(RGB2),
-		NAME(DMA0), NAME(DMA1),
-		NAME(VIG3), NAME(RGB3),
-		NAME(CURSOR0), NAME(CURSOR1),
-#undef NAME
-	};
-	return names[pipe];
-}
-
-static inline int pipe2nclients(enum mdp5_pipe pipe)
-{
-	switch (pipe) {
-	case SSPP_RGB0:
-	case SSPP_RGB1:
-	case SSPP_RGB2:
-	case SSPP_RGB3:
-		return 1;
-	default:
-		return 3;
-	}
-}
-
-static inline uint32_t intf2err(int intf_num)
-{
-	switch (intf_num) {
-	case 0:  return MDP5_IRQ_INTF0_UNDER_RUN;
-	case 1:  return MDP5_IRQ_INTF1_UNDER_RUN;
-	case 2:  return MDP5_IRQ_INTF2_UNDER_RUN;
-	case 3:  return MDP5_IRQ_INTF3_UNDER_RUN;
-	default: return 0;
-	}
-}
-
-static inline uint32_t intf2vblank(struct mdp5_hw_mixer *mixer,
-				   struct mdp5_interface *intf)
-{
-	/*
-	 * In case of DSI Command Mode, the Ping Pong's read pointer IRQ
-	 * acts as a Vblank signal. The Ping Pong buffer used is bound to
-	 * layer mixer.
-	 */
-
-	if ((intf->type == INTF_DSI) &&
-			(intf->mode == MDP5_INTF_DSI_MODE_COMMAND))
-		return MDP5_IRQ_PING_PONG_0_RD_PTR << mixer->pp;
-
-	if (intf->type == INTF_WB)
-		return MDP5_IRQ_WB_2_DONE;
-
-	switch (intf->num) {
-	case 0:  return MDP5_IRQ_INTF0_VSYNC;
-	case 1:  return MDP5_IRQ_INTF1_VSYNC;
-	case 2:  return MDP5_IRQ_INTF2_VSYNC;
-	case 3:  return MDP5_IRQ_INTF3_VSYNC;
-	default: return 0;
-	}
-}
-
-static inline uint32_t lm2ppdone(struct mdp5_hw_mixer *mixer)
-{
-	return MDP5_IRQ_PING_PONG_0_DONE << mixer->pp;
-}
-
-void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
-		uint32_t old_irqmask);
-void mdp5_irq_preinstall(struct msm_kms *kms);
-int mdp5_irq_postinstall(struct msm_kms *kms);
-void mdp5_irq_uninstall(struct msm_kms *kms);
-irqreturn_t mdp5_irq(struct msm_kms *kms);
-int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
-void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
-int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
-void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
-
-uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
-enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
-enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane);
-struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-				  enum drm_plane_type type);
-
-struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc);
-uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
-
-struct mdp5_hw_mixer *mdp5_crtc_get_mixer(struct drm_crtc *crtc);
-struct mdp5_pipeline *mdp5_crtc_get_pipeline(struct drm_crtc *crtc);
-void mdp5_crtc_set_pipeline(struct drm_crtc *crtc);
-void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc);
-struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
-				struct drm_plane *plane,
-				struct drm_plane *cursor_plane, int id);
-
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
-		struct mdp5_interface *intf, struct mdp5_ctl *ctl);
-int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
-				       struct drm_encoder *slave_encoder);
-void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode);
-int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
-u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
-
-#ifdef CONFIG_DRM_MSM_DSI
-void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
-			       struct drm_display_mode *mode,
-			       struct drm_display_mode *adjusted_mode);
-void mdp5_cmd_encoder_disable(struct drm_encoder *encoder);
-void mdp5_cmd_encoder_enable(struct drm_encoder *encoder);
-int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
-				       struct drm_encoder *slave_encoder);
-#else
-static inline void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
-					     struct drm_display_mode *mode,
-					     struct drm_display_mode *adjusted_mode)
-{
-}
-static inline void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
-{
-}
-static inline void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
-{
-}
-static inline int mdp5_cmd_encoder_set_split_display(
-	struct drm_encoder *encoder, struct drm_encoder *slave_encoder)
-{
-	return -EINVAL;
-}
-#endif
-
-#endif /* __MDP5_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c
deleted file mode 100644
index f2a0db7a8a03..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/irqdomain.h>
-#include <linux/irq.h>
-
-#include "msm_drv.h"
-#include "mdp5_kms.h"
-
-/*
- * If needed, this can become more specific: something like struct mdp5_mdss,
- * which contains a 'struct msm_mdss base' member.
- */
-struct msm_mdss {
-	struct drm_device *dev;
-
-	void __iomem *mmio, *vbif;
-
-	struct regulator *vdd;
-
-	struct clk *ahb_clk;
-	struct clk *axi_clk;
-	struct clk *vsync_clk;
-
-	struct {
-		volatile unsigned long enabled_mask;
-		struct irq_domain *domain;
-	} irqcontroller;
-};
-
-static inline void mdss_write(struct msm_mdss *mdss, u32 reg, u32 data)
-{
-	msm_writel(data, mdss->mmio + reg);
-}
-
-static inline u32 mdss_read(struct msm_mdss *mdss, u32 reg)
-{
-	return msm_readl(mdss->mmio + reg);
-}
-
-static irqreturn_t mdss_irq(int irq, void *arg)
-{
-	struct msm_mdss *mdss = arg;
-	u32 intr;
-
-	intr = mdss_read(mdss, REG_MDSS_HW_INTR_STATUS);
-
-	VERB("intr=%08x", intr);
-
-	while (intr) {
-		irq_hw_number_t hwirq = fls(intr) - 1;
-
-		generic_handle_irq(irq_find_mapping(
-				mdss->irqcontroller.domain, hwirq));
-		intr &= ~(1 << hwirq);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/*
- * interrupt-controller implementation, so sub-blocks (MDP/HDMI/eDP/DSI/etc)
- * can register to get their irq's delivered
- */
-
-#define VALID_IRQS  (MDSS_HW_INTR_STATUS_INTR_MDP | \
-		MDSS_HW_INTR_STATUS_INTR_DSI0 | \
-		MDSS_HW_INTR_STATUS_INTR_DSI1 | \
-		MDSS_HW_INTR_STATUS_INTR_HDMI | \
-		MDSS_HW_INTR_STATUS_INTR_EDP)
-
-static void mdss_hw_mask_irq(struct irq_data *irqd)
-{
-	struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd);
-
-	smp_mb__before_atomic();
-	clear_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask);
-	smp_mb__after_atomic();
-}
-
-static void mdss_hw_unmask_irq(struct irq_data *irqd)
-{
-	struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd);
-
-	smp_mb__before_atomic();
-	set_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask);
-	smp_mb__after_atomic();
-}
-
-static struct irq_chip mdss_hw_irq_chip = {
-	.name		= "mdss",
-	.irq_mask	= mdss_hw_mask_irq,
-	.irq_unmask	= mdss_hw_unmask_irq,
-};
-
-static int mdss_hw_irqdomain_map(struct irq_domain *d, unsigned int irq,
-				 irq_hw_number_t hwirq)
-{
-	struct msm_mdss *mdss = d->host_data;
-
-	if (!(VALID_IRQS & (1 << hwirq)))
-		return -EPERM;
-
-	irq_set_chip_and_handler(irq, &mdss_hw_irq_chip, handle_level_irq);
-	irq_set_chip_data(irq, mdss);
-
-	return 0;
-}
-
-static const struct irq_domain_ops mdss_hw_irqdomain_ops = {
-	.map = mdss_hw_irqdomain_map,
-	.xlate = irq_domain_xlate_onecell,
-};
-
-
-static int mdss_irq_domain_init(struct msm_mdss *mdss)
-{
-	struct device *dev = mdss->dev->dev;
-	struct irq_domain *d;
-
-	d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops,
-				  mdss);
-	if (!d) {
-		dev_err(dev, "mdss irq domain add failed\n");
-		return -ENXIO;
-	}
-
-	mdss->irqcontroller.enabled_mask = 0;
-	mdss->irqcontroller.domain = d;
-
-	return 0;
-}
-
-int msm_mdss_enable(struct msm_mdss *mdss)
-{
-	DBG("");
-
-	clk_prepare_enable(mdss->ahb_clk);
-	if (mdss->axi_clk)
-		clk_prepare_enable(mdss->axi_clk);
-	if (mdss->vsync_clk)
-		clk_prepare_enable(mdss->vsync_clk);
-
-	return 0;
-}
-
-int msm_mdss_disable(struct msm_mdss *mdss)
-{
-	DBG("");
-
-	if (mdss->vsync_clk)
-		clk_disable_unprepare(mdss->vsync_clk);
-	if (mdss->axi_clk)
-		clk_disable_unprepare(mdss->axi_clk);
-	clk_disable_unprepare(mdss->ahb_clk);
-
-	return 0;
-}
-
-static int msm_mdss_get_clocks(struct msm_mdss *mdss)
-{
-	struct platform_device *pdev = to_platform_device(mdss->dev->dev);
-
-	mdss->ahb_clk = msm_clk_get(pdev, "iface");
-	if (IS_ERR(mdss->ahb_clk))
-		mdss->ahb_clk = NULL;
-
-	mdss->axi_clk = msm_clk_get(pdev, "bus");
-	if (IS_ERR(mdss->axi_clk))
-		mdss->axi_clk = NULL;
-
-	mdss->vsync_clk = msm_clk_get(pdev, "vsync");
-	if (IS_ERR(mdss->vsync_clk))
-		mdss->vsync_clk = NULL;
-
-	return 0;
-}
-
-void msm_mdss_destroy(struct drm_device *dev)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	struct msm_mdss *mdss = priv->mdss;
-
-	if (!mdss)
-		return;
-
-	irq_domain_remove(mdss->irqcontroller.domain);
-	mdss->irqcontroller.domain = NULL;
-
-	regulator_disable(mdss->vdd);
-
-	pm_runtime_disable(dev->dev);
-}
-
-int msm_mdss_init(struct drm_device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev->dev);
-	struct msm_drm_private *priv = dev->dev_private;
-	struct msm_mdss *mdss;
-	int ret;
-
-	DBG("");
-
-	if (!of_device_is_compatible(dev->dev->of_node, "qcom,mdss"))
-		return 0;
-
-	mdss = devm_kzalloc(dev->dev, sizeof(*mdss), GFP_KERNEL);
-	if (!mdss) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	mdss->dev = dev;
-
-	mdss->mmio = msm_ioremap(pdev, "mdss_phys", "MDSS");
-	if (IS_ERR(mdss->mmio)) {
-		ret = PTR_ERR(mdss->mmio);
-		goto fail;
-	}
-
-	mdss->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF");
-	if (IS_ERR(mdss->vbif)) {
-		ret = PTR_ERR(mdss->vbif);
-		goto fail;
-	}
-
-	ret = msm_mdss_get_clocks(mdss);
-	if (ret) {
-		dev_err(dev->dev, "failed to get clocks: %d\n", ret);
-		goto fail;
-	}
-
-	/* Regulator to enable GDSCs in downstream kernels */
-	mdss->vdd = devm_regulator_get(dev->dev, "vdd");
-	if (IS_ERR(mdss->vdd)) {
-		ret = PTR_ERR(mdss->vdd);
-		goto fail;
-	}
-
-	ret = regulator_enable(mdss->vdd);
-	if (ret) {
-		dev_err(dev->dev, "failed to enable regulator vdd: %d\n",
-			ret);
-		goto fail;
-	}
-
-	ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0),
-			       mdss_irq, 0, "mdss_isr", mdss);
-	if (ret) {
-		dev_err(dev->dev, "failed to init irq: %d\n", ret);
-		goto fail_irq;
-	}
-
-	ret = mdss_irq_domain_init(mdss);
-	if (ret) {
-		dev_err(dev->dev, "failed to init sub-block irqs: %d\n", ret);
-		goto fail_irq;
-	}
-
-	priv->mdss = mdss;
-
-	pm_runtime_enable(dev->dev);
-
-	return 0;
-fail_irq:
-	regulator_disable(mdss->vdd);
-fail:
-	return ret;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c
deleted file mode 100644
index 8a00991f03c7..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "mdp5_kms.h"
-
-/*
- * As of now, there are only 2 combinations possible for source split:
- *
- * Left | Right
- * -----|------
- *  LM0 | LM1
- *  LM2 | LM5
- *
- */
-static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 };
-
-static int get_right_pair_idx(struct mdp5_kms *mdp5_kms, int lm)
-{
-	int i;
-	int pair_lm;
-
-	pair_lm = lm_right_pair[lm];
-	if (pair_lm < 0)
-		return -EINVAL;
-
-	for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
-		struct mdp5_hw_mixer *mixer = mdp5_kms->hwmixers[i];
-
-		if (mixer->lm == pair_lm)
-			return mixer->idx;
-	}
-
-	return -1;
-}
-
-int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,
-		      uint32_t caps, struct mdp5_hw_mixer **mixer,
-		      struct mdp5_hw_mixer **r_mixer)
-{
-	struct msm_drm_private *priv = s->dev->dev_private;
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
-	struct mdp5_state *state = mdp5_get_state(s);
-	struct mdp5_hw_mixer_state *new_state;
-	int i;
-
-	if (IS_ERR(state))
-		return PTR_ERR(state);
-
-	new_state = &state->hwmixer;
-
-	for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
-		struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i];
-
-		/*
-		 * skip if already in-use by a different CRTC. If there is a
-		 * mixer already assigned to this CRTC, it means this call is
-		 * a request to get an additional right mixer. Assume that the
-		 * existing mixer is the 'left' one, and try to see if we can
-		 * get its corresponding 'right' pair.
-		 */
-		if (new_state->hwmixer_to_crtc[cur->idx] &&
-		    new_state->hwmixer_to_crtc[cur->idx] != crtc)
-			continue;
-
-		/* skip if doesn't support some required caps: */
-		if (caps & ~cur->caps)
-			continue;
-
-		if (r_mixer) {
-			int pair_idx;
-
-			pair_idx = get_right_pair_idx(mdp5_kms, cur->lm);
-			if (pair_idx < 0)
-				return -EINVAL;
-
-			if (new_state->hwmixer_to_crtc[pair_idx])
-				continue;
-
-			*r_mixer = mdp5_kms->hwmixers[pair_idx];
-		}
-
-		/*
-		 * prefer a pair-able LM over an unpairable one. We can
-		 * switch the CRTC from Normal mode to Source Split mode
-		 * without requiring a full modeset if we had already
-		 * assigned this CRTC a pair-able LM.
-		 *
-		 * TODO: There will be assignment sequences which would
-		 * result in the CRTC requiring a full modeset, even
-		 * if we have the LM resources to prevent it. For a platform
-		 * with a few displays, we don't run out of pair-able LMs
-		 * so easily. For now, ignore the possibility of requiring
-		 * a full modeset.
-		 */
-		if (!(*mixer) || cur->caps & MDP_LM_CAP_PAIR)
-			*mixer = cur;
-	}
-
-	if (!(*mixer))
-		return -ENOMEM;
-
-	if (r_mixer && !(*r_mixer))
-		return -ENOMEM;
-
-	DBG("assigning Layer Mixer %d to crtc %s", (*mixer)->lm, crtc->name);
-
-	new_state->hwmixer_to_crtc[(*mixer)->idx] = crtc;
-	if (r_mixer) {
-		DBG("assigning Right Layer Mixer %d to crtc %s", (*r_mixer)->lm,
-		    crtc->name);
-		new_state->hwmixer_to_crtc[(*r_mixer)->idx] = crtc;
-	}
-
-	return 0;
-}
-
-void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)
-{
-	struct mdp5_state *state = mdp5_get_state(s);
-	struct mdp5_hw_mixer_state *new_state = &state->hwmixer;
-
-	if (!mixer)
-		return;
-
-	if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx]))
-		return;
-
-	DBG("%s: release from crtc %s", mixer->name,
-	    new_state->hwmixer_to_crtc[mixer->idx]->name);
-
-	new_state->hwmixer_to_crtc[mixer->idx] = NULL;
-}
-
-void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer)
-{
-	kfree(mixer);
-}
-
-static const char * const mixer_names[] = {
-	"LM0", "LM1", "LM2", "LM3", "LM4", "LM5",
-};
-
-struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm)
-{
-	struct mdp5_hw_mixer *mixer;
-
-	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
-	if (!mixer)
-		return ERR_PTR(-ENOMEM);
-
-	mixer->name = mixer_names[lm->id];
-	mixer->lm = lm->id;
-	mixer->caps = lm->caps;
-	mixer->pp = lm->pp;
-	mixer->dspp = lm->dspp;
-	mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id);
-
-	return mixer;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h
deleted file mode 100644
index 9be94f567fbd..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MDP5_LM_H__
-#define __MDP5_LM_H__
-
-/* represents a hw Layer Mixer, one (or more) is dynamically assigned to a crtc */
-struct mdp5_hw_mixer {
-	int idx;
-
-	const char *name;
-
-	int lm;			/* the LM instance # */
-	uint32_t caps;
-	int pp;
-	int dspp;
-
-	uint32_t flush_mask;      /* used to commit LM registers */
-};
-
-/* global atomic state of assignment between CRTCs and Layer Mixers: */
-struct mdp5_hw_mixer_state {
-	struct drm_crtc *hwmixer_to_crtc[8];
-};
-
-struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm);
-void mdp5_mixer_destroy(struct mdp5_hw_mixer *lm);
-int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,
-		      uint32_t caps, struct mdp5_hw_mixer **mixer,
-		      struct mdp5_hw_mixer **r_mixer);
-void mdp5_mixer_release(struct drm_atomic_state *s,
-			struct mdp5_hw_mixer *mixer);
-
-#endif /* __MDP5_LM_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
deleted file mode 100644
index ff52c49095f9..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2016 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "mdp5_kms.h"
-
-int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane,
-		     uint32_t caps, uint32_t blkcfg,
-		     struct mdp5_hw_pipe **hwpipe,
-		     struct mdp5_hw_pipe **r_hwpipe)
-{
-	struct msm_drm_private *priv = s->dev->dev_private;
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
-	struct mdp5_state *state;
-	struct mdp5_hw_pipe_state *old_state, *new_state;
-	int i, j;
-
-	state = mdp5_get_state(s);
-	if (IS_ERR(state))
-		return PTR_ERR(state);
-
-	/* grab old_state after mdp5_get_state(), since now we hold lock: */
-	old_state = &mdp5_kms->state->hwpipe;
-	new_state = &state->hwpipe;
-
-	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
-		struct mdp5_hw_pipe *cur = mdp5_kms->hwpipes[i];
-
-		/* skip if already in-use.. check both new and old state,
-		 * since we cannot immediately re-use a pipe that is
-		 * released in the current update in some cases:
-		 *  (1) mdp5 can have SMP (non-double-buffered)
-		 *  (2) hw pipe previously assigned to different CRTC
-		 *      (vblanks might not be aligned)
-		 */
-		if (new_state->hwpipe_to_plane[cur->idx] ||
-				old_state->hwpipe_to_plane[cur->idx])
-			continue;
-
-		/* skip if doesn't support some required caps: */
-		if (caps & ~cur->caps)
-			continue;
-
-		/*
-		 * don't assign a cursor pipe to a plane that isn't going to
-		 * be used as a cursor
-		 */
-		if (cur->caps & MDP_PIPE_CAP_CURSOR &&
-				plane->type != DRM_PLANE_TYPE_CURSOR)
-			continue;
-
-		/* possible candidate, take the one with the
-		 * fewest unneeded caps bits set:
-		 */
-		if (!(*hwpipe) || (hweight_long(cur->caps & ~caps) <
-				   hweight_long((*hwpipe)->caps & ~caps))) {
-			bool r_found = false;
-
-			if (r_hwpipe) {
-				for (j = i + 1; j < mdp5_kms->num_hwpipes;
-				     j++) {
-					struct mdp5_hw_pipe *r_cur =
-							mdp5_kms->hwpipes[j];
-
-					/* reject different types of hwpipes */
-					if (r_cur->caps != cur->caps)
-						continue;
-
-					/* respect priority, eg. VIG0 > VIG1 */
-					if (cur->pipe > r_cur->pipe)
-						continue;
-
-					*r_hwpipe = r_cur;
-					r_found = true;
-					break;
-				}
-			}
-
-			if (!r_hwpipe || r_found)
-				*hwpipe = cur;
-		}
-	}
-
-	if (!(*hwpipe))
-		return -ENOMEM;
-
-	if (r_hwpipe && !(*r_hwpipe))
-		return -ENOMEM;
-
-	if (mdp5_kms->smp) {
-		int ret;
-
-		/* We don't support SMP and 2 hwpipes/plane together */
-		WARN_ON(r_hwpipe);
-
-		DBG("%s: alloc SMP blocks", (*hwpipe)->name);
-		ret = mdp5_smp_assign(mdp5_kms->smp, &state->smp,
-				(*hwpipe)->pipe, blkcfg);
-		if (ret)
-			return -ENOMEM;
-
-		(*hwpipe)->blkcfg = blkcfg;
-	}
-
-	DBG("%s: assign to plane %s for caps %x",
-			(*hwpipe)->name, plane->name, caps);
-	new_state->hwpipe_to_plane[(*hwpipe)->idx] = plane;
-
-	if (r_hwpipe) {
-		DBG("%s: assign to right of plane %s for caps %x",
-		    (*r_hwpipe)->name, plane->name, caps);
-		new_state->hwpipe_to_plane[(*r_hwpipe)->idx] = plane;
-	}
-
-	return 0;
-}
-
-void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
-{
-	struct msm_drm_private *priv = s->dev->dev_private;
-	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
-	struct mdp5_state *state = mdp5_get_state(s);
-	struct mdp5_hw_pipe_state *new_state = &state->hwpipe;
-
-	if (!hwpipe)
-		return;
-
-	if (WARN_ON(!new_state->hwpipe_to_plane[hwpipe->idx]))
-		return;
-
-	DBG("%s: release from plane %s", hwpipe->name,
-		new_state->hwpipe_to_plane[hwpipe->idx]->name);
-
-	if (mdp5_kms->smp) {
-		DBG("%s: free SMP blocks", hwpipe->name);
-		mdp5_smp_release(mdp5_kms->smp, &state->smp, hwpipe->pipe);
-	}
-
-	new_state->hwpipe_to_plane[hwpipe->idx] = NULL;
-}
-
-void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe)
-{
-	kfree(hwpipe);
-}
-
-struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
-		uint32_t reg_offset, uint32_t caps)
-{
-	struct mdp5_hw_pipe *hwpipe;
-
-	hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL);
-	if (!hwpipe)
-		return ERR_PTR(-ENOMEM);
-
-	hwpipe->name = pipe2name(pipe);
-	hwpipe->pipe = pipe;
-	hwpipe->reg_offset = reg_offset;
-	hwpipe->caps = caps;
-	hwpipe->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
-
-	return hwpipe;
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
deleted file mode 100644
index bb2b0ac7aa2b..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MDP5_PIPE_H__
-#define __MDP5_PIPE_H__
-
-/* TODO: Add SSPP_MAX in mdp5.xml.h */
-#define SSPP_MAX	(SSPP_CURSOR1 + 1)
-
-/* represents a hw pipe, which is dynamically assigned to a plane */
-struct mdp5_hw_pipe {
-	int idx;
-
-	const char *name;
-	enum mdp5_pipe pipe;
-
-	uint32_t reg_offset;
-	uint32_t caps;
-
-	uint32_t flush_mask;      /* used to commit pipe registers */
-
-	/* number of smp blocks per plane, ie:
-	 *   nblks_y | (nblks_u << 8) | (nblks_v << 16)
-	 */
-	uint32_t blkcfg;
-};
-
-/* global atomic state of assignment between pipes and planes: */
-struct mdp5_hw_pipe_state {
-	struct drm_plane *hwpipe_to_plane[SSPP_MAX];
-};
-
-int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane,
-		     uint32_t caps, uint32_t blkcfg,
-		     struct mdp5_hw_pipe **hwpipe,
-		     struct mdp5_hw_pipe **r_hwpipe);
-void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe);
-
-struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
-		uint32_t reg_offset, uint32_t caps);
-void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe);
-
-#endif /* __MDP5_PIPE_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
deleted file mode 100644
index 29678876fc09..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ /dev/null
@@ -1,1137 +0,0 @@
-/*
- * Copyright (C) 2014-2015 The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <drm/drm_print.h>
-#include "mdp5_kms.h"
-
-struct mdp5_plane {
-	struct drm_plane base;
-
-	uint32_t nformats;
-	uint32_t formats[32];
-};
-#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
-
-static int mdp5_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		struct drm_rect *src, struct drm_rect *dest);
-
-static struct mdp5_kms *get_kms(struct drm_plane *plane)
-{
-	struct msm_drm_private *priv = plane->dev->dev_private;
-	return to_mdp5_kms(to_mdp_kms(priv->kms));
-}
-
-static bool plane_enabled(struct drm_plane_state *state)
-{
-	return state->visible;
-}
-
-static void mdp5_plane_destroy(struct drm_plane *plane)
-{
-	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-
-	drm_plane_helper_disable(plane);
-	drm_plane_cleanup(plane);
-
-	kfree(mdp5_plane);
-}
-
-static void mdp5_plane_install_rotation_property(struct drm_device *dev,
-		struct drm_plane *plane)
-{
-	drm_plane_create_rotation_property(plane,
-					   DRM_MODE_ROTATE_0,
-					   DRM_MODE_ROTATE_0 |
-					   DRM_MODE_ROTATE_180 |
-					   DRM_MODE_REFLECT_X |
-					   DRM_MODE_REFLECT_Y);
-}
-
-/* helper to install properties which are common to planes and crtcs */
-static void mdp5_plane_install_properties(struct drm_plane *plane,
-		struct drm_mode_object *obj)
-{
-	struct drm_device *dev = plane->dev;
-	struct msm_drm_private *dev_priv = dev->dev_private;
-	struct drm_property *prop;
-
-#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
-		prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
-		if (!prop) { \
-			prop = drm_property_##fnc(dev, 0, #name, \
-				##__VA_ARGS__); \
-			if (!prop) { \
-				dev_warn(dev->dev, \
-					"Create property %s failed\n", \
-					#name); \
-				return; \
-			} \
-			dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
-		} \
-		drm_object_attach_property(&plane->base, prop, init_val); \
-	} while (0)
-
-#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
-		INSTALL_PROPERTY(name, NAME, init_val, \
-				create_range, min, max)
-
-#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
-		INSTALL_PROPERTY(name, NAME, init_val, \
-				create_enum, name##_prop_enum_list, \
-				ARRAY_SIZE(name##_prop_enum_list))
-
-	INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
-
-	mdp5_plane_install_rotation_property(dev, plane);
-
-#undef INSTALL_RANGE_PROPERTY
-#undef INSTALL_ENUM_PROPERTY
-#undef INSTALL_PROPERTY
-}
-
-static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
-		struct drm_plane_state *state, struct drm_property *property,
-		uint64_t val)
-{
-	struct drm_device *dev = plane->dev;
-	struct mdp5_plane_state *pstate;
-	struct msm_drm_private *dev_priv = dev->dev_private;
-	int ret = 0;
-
-	pstate = to_mdp5_plane_state(state);
-
-#define SET_PROPERTY(name, NAME, type) do { \
-		if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
-			pstate->name = (type)val; \
-			DBG("Set property %s %d", #name, (type)val); \
-			goto done; \
-		} \
-	} while (0)
-
-	SET_PROPERTY(zpos, ZPOS, uint8_t);
-
-	dev_err(dev->dev, "Invalid property\n");
-	ret = -EINVAL;
-done:
-	return ret;
-#undef SET_PROPERTY
-}
-
-static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
-		const struct drm_plane_state *state,
-		struct drm_property *property, uint64_t *val)
-{
-	struct drm_device *dev = plane->dev;
-	struct mdp5_plane_state *pstate;
-	struct msm_drm_private *dev_priv = dev->dev_private;
-	int ret = 0;
-
-	pstate = to_mdp5_plane_state(state);
-
-#define GET_PROPERTY(name, NAME, type) do { \
-		if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
-			*val = pstate->name; \
-			DBG("Get property %s %lld", #name, *val); \
-			goto done; \
-		} \
-	} while (0)
-
-	GET_PROPERTY(zpos, ZPOS, uint8_t);
-
-	dev_err(dev->dev, "Invalid property\n");
-	ret = -EINVAL;
-done:
-	return ret;
-#undef SET_PROPERTY
-}
-
-static void
-mdp5_plane_atomic_print_state(struct drm_printer *p,
-		const struct drm_plane_state *state)
-{
-	struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
-	struct mdp5_kms *mdp5_kms = get_kms(state->plane);
-
-	drm_printf(p, "\thwpipe=%s\n", pstate->hwpipe ?
-			pstate->hwpipe->name : "(null)");
-	if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
-		drm_printf(p, "\tright-hwpipe=%s\n",
-			   pstate->r_hwpipe ? pstate->r_hwpipe->name :
-					      "(null)");
-	drm_printf(p, "\tpremultiplied=%u\n", pstate->premultiplied);
-	drm_printf(p, "\tzpos=%u\n", pstate->zpos);
-	drm_printf(p, "\talpha=%u\n", pstate->alpha);
-	drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage));
-}
-
-static void mdp5_plane_reset(struct drm_plane *plane)
-{
-	struct mdp5_plane_state *mdp5_state;
-
-	if (plane->state && plane->state->fb)
-		drm_framebuffer_unreference(plane->state->fb);
-
-	kfree(to_mdp5_plane_state(plane->state));
-	mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
-
-	/* assign default blend parameters */
-	mdp5_state->alpha = 255;
-	mdp5_state->premultiplied = 0;
-
-	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
-		mdp5_state->zpos = STAGE_BASE;
-	else
-		mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
-
-	mdp5_state->base.plane = plane;
-
-	plane->state = &mdp5_state->base;
-}
-
-static struct drm_plane_state *
-mdp5_plane_duplicate_state(struct drm_plane *plane)
-{
-	struct mdp5_plane_state *mdp5_state;
-
-	if (WARN_ON(!plane->state))
-		return NULL;
-
-	mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
-			sizeof(*mdp5_state), GFP_KERNEL);
-	if (!mdp5_state)
-		return NULL;
-
-	__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
-
-	return &mdp5_state->base;
-}
-
-static void mdp5_plane_destroy_state(struct drm_plane *plane,
-		struct drm_plane_state *state)
-{
-	struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
-
-	if (state->fb)
-		drm_framebuffer_unreference(state->fb);
-
-	kfree(pstate);
-}
-
-static const struct drm_plane_funcs mdp5_plane_funcs = {
-		.update_plane = drm_atomic_helper_update_plane,
-		.disable_plane = drm_atomic_helper_disable_plane,
-		.destroy = mdp5_plane_destroy,
-		.atomic_set_property = mdp5_plane_atomic_set_property,
-		.atomic_get_property = mdp5_plane_atomic_get_property,
-		.reset = mdp5_plane_reset,
-		.atomic_duplicate_state = mdp5_plane_duplicate_state,
-		.atomic_destroy_state = mdp5_plane_destroy_state,
-		.atomic_print_state = mdp5_plane_atomic_print_state,
-};
-
-static int mdp5_plane_prepare_fb(struct drm_plane *plane,
-				 struct drm_plane_state *new_state)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	struct msm_kms *kms = &mdp5_kms->base.base;
-	struct drm_framebuffer *fb = new_state->fb;
-
-	if (!new_state->fb)
-		return 0;
-
-	DBG("%s: prepare: FB[%u]", plane->name, fb->base.id);
-	return msm_framebuffer_prepare(fb, kms->aspace);
-}
-
-static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
-				  struct drm_plane_state *old_state)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	struct msm_kms *kms = &mdp5_kms->base.base;
-	struct drm_framebuffer *fb = old_state->fb;
-
-	if (!fb)
-		return;
-
-	DBG("%s: cleanup: FB[%u]", plane->name, fb->base.id);
-	msm_framebuffer_cleanup(fb, kms->aspace);
-}
-
-#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
-static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
-					      struct drm_plane_state *state)
-{
-	struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
-	struct drm_plane *plane = state->plane;
-	struct drm_plane_state *old_state = plane->state;
-	struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg);
-	bool new_hwpipe = false;
-	bool need_right_hwpipe = false;
-	uint32_t max_width, max_height;
-	bool out_of_bounds = false;
-	uint32_t caps = 0;
-	struct drm_rect clip;
-	int min_scale, max_scale;
-	int ret;
-
-	DBG("%s: check (%d -> %d)", plane->name,
-			plane_enabled(old_state), plane_enabled(state));
-
-	max_width = config->hw->lm.max_width << 16;
-	max_height = config->hw->lm.max_height << 16;
-
-	/* Make sure source dimensions are within bounds. */
-	if (state->src_h > max_height)
-		out_of_bounds = true;
-
-	if (state->src_w > max_width) {
-		/* If source split is supported, we can go up to 2x
-		 * the max LM width, but we'd need to stage another
-		 * hwpipe to the right LM. So, the drm_plane would
-		 * consist of 2 hwpipes.
-		 */
-		if (config->hw->mdp.caps & MDP_CAP_SRC_SPLIT &&
-		    (state->src_w <= 2 * max_width))
-			need_right_hwpipe = true;
-		else
-			out_of_bounds = true;
-	}
-
-	if (out_of_bounds) {
-		struct drm_rect src = drm_plane_state_src(state);
-		DBG("Invalid source size "DRM_RECT_FP_FMT,
-				DRM_RECT_FP_ARG(&src));
-		return -ERANGE;
-	}
-
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
-	min_scale = FRAC_16_16(1, 8);
-	max_scale = FRAC_16_16(8, 1);
-
-	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
-						  min_scale, max_scale,
-						  true, true);
-	if (ret)
-		return ret;
-
-	if (plane_enabled(state)) {
-		unsigned int rotation;
-		const struct mdp_format *format;
-		struct mdp5_kms *mdp5_kms = get_kms(plane);
-		uint32_t blkcfg = 0;
-
-		format = to_mdp_format(msm_framebuffer_format(state->fb));
-		if (MDP_FORMAT_IS_YUV(format))
-			caps |= MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
-
-		if (((state->src_w >> 16) != state->crtc_w) ||
-				((state->src_h >> 16) != state->crtc_h))
-			caps |= MDP_PIPE_CAP_SCALE;
-
-		rotation = drm_rotation_simplify(state->rotation,
-						 DRM_MODE_ROTATE_0 |
-						 DRM_MODE_REFLECT_X |
-						 DRM_MODE_REFLECT_Y);
-
-		if (rotation & DRM_MODE_REFLECT_X)
-			caps |= MDP_PIPE_CAP_HFLIP;
-
-		if (rotation & DRM_MODE_REFLECT_Y)
-			caps |= MDP_PIPE_CAP_VFLIP;
-
-		if (plane->type == DRM_PLANE_TYPE_CURSOR)
-			caps |= MDP_PIPE_CAP_CURSOR;
-
-		/* (re)allocate hw pipe if we don't have one or caps-mismatch: */
-		if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
-			new_hwpipe = true;
-
-		/*
-		 * (re)allocte hw pipe if we're either requesting for 2 hw pipes
-		 * or we're switching from 2 hw pipes to 1 hw pipe because the
-		 * new src_w can be supported by 1 hw pipe itself.
-		 */
-		if ((need_right_hwpipe && !mdp5_state->r_hwpipe) ||
-		    (!need_right_hwpipe && mdp5_state->r_hwpipe))
-			new_hwpipe = true;
-
-		if (mdp5_kms->smp) {
-			const struct mdp_format *format =
-				to_mdp_format(msm_framebuffer_format(state->fb));
-
-			blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format,
-					state->src_w >> 16, false);
-
-			if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg))
-				new_hwpipe = true;
-		}
-
-		/* (re)assign hwpipe if needed, otherwise keep old one: */
-		if (new_hwpipe) {
-			/* TODO maybe we want to re-assign hwpipe sometimes
-			 * in cases when we no-longer need some caps to make
-			 * it available for other planes?
-			 */
-			struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe;
-			struct mdp5_hw_pipe *old_right_hwpipe =
-							  mdp5_state->r_hwpipe;
-			struct mdp5_hw_pipe *new_hwpipe = NULL;
-			struct mdp5_hw_pipe *new_right_hwpipe = NULL;
-
-			ret = mdp5_pipe_assign(state->state, plane, caps,
-					       blkcfg, &new_hwpipe,
-					       need_right_hwpipe ?
-					       &new_right_hwpipe : NULL);
-			if (ret) {
-				DBG("%s: failed to assign hwpipe(s)!",
-				    plane->name);
-				return ret;
-			}
-
-			mdp5_state->hwpipe = new_hwpipe;
-			if (need_right_hwpipe)
-				mdp5_state->r_hwpipe = new_right_hwpipe;
-			else
-				/*
-				 * set it to NULL so that the driver knows we
-				 * don't have a right hwpipe when committing a
-				 * new state
-				 */
-				mdp5_state->r_hwpipe = NULL;
-
-
-			mdp5_pipe_release(state->state, old_hwpipe);
-			mdp5_pipe_release(state->state, old_right_hwpipe);
-		}
-	} else {
-		mdp5_pipe_release(state->state, mdp5_state->hwpipe);
-		mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
-		mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL;
-	}
-
-	return 0;
-}
-
-static int mdp5_plane_atomic_check(struct drm_plane *plane,
-				   struct drm_plane_state *state)
-{
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *crtc_state;
-
-	crtc = state->crtc ? state->crtc : plane->state->crtc;
-	if (!crtc)
-		return 0;
-
-	crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
-	if (WARN_ON(!crtc_state))
-		return -EINVAL;
-
-	return mdp5_plane_atomic_check_with_state(crtc_state, state);
-}
-
-static void mdp5_plane_atomic_update(struct drm_plane *plane,
-				     struct drm_plane_state *old_state)
-{
-	struct drm_plane_state *state = plane->state;
-
-	DBG("%s: update", plane->name);
-
-	if (plane_enabled(state)) {
-		int ret;
-
-		ret = mdp5_plane_mode_set(plane,
-				state->crtc, state->fb,
-				&state->src, &state->dst);
-		/* atomic_check should have ensured that this doesn't fail */
-		WARN_ON(ret < 0);
-	}
-}
-
-static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
-					 struct drm_plane_state *state)
-{
-	struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
-	struct drm_crtc_state *crtc_state;
-	struct drm_rect clip;
-	int min_scale, max_scale;
-	int ret;
-
-	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
-							state->crtc);
-	if (WARN_ON(!crtc_state))
-		return -EINVAL;
-
-	if (!crtc_state->active)
-		return -EINVAL;
-
-	mdp5_state = to_mdp5_plane_state(state);
-
-	/* don't use fast path if we don't have a hwpipe allocated yet */
-	if (!mdp5_state->hwpipe)
-		return -EINVAL;
-
-	/* only allow changing of position(crtc x/y or src x/y) in fast path */
-	if (plane->state->crtc != state->crtc ||
-	    plane->state->src_w != state->src_w ||
-	    plane->state->src_h != state->src_h ||
-	    plane->state->crtc_w != state->crtc_w ||
-	    plane->state->crtc_h != state->crtc_h ||
-	    !plane->state->fb ||
-	    plane->state->fb != state->fb)
-		return -EINVAL;
-
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
-	min_scale = FRAC_16_16(1, 8);
-	max_scale = FRAC_16_16(8, 1);
-
-	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
-						  min_scale, max_scale,
-						  true, true);
-	if (ret)
-		return ret;
-
-	/*
-	 * if the visibility of the plane changes (i.e, if the cursor is
-	 * clipped out completely, we can't take the async path because
-	 * we need to stage/unstage the plane from the Layer Mixer(s). We
-	 * also assign/unassign the hwpipe(s) tied to the plane. We avoid
-	 * taking the fast path for both these reasons.
-	 */
-	if (state->visible != plane->state->visible)
-		return -EINVAL;
-
-	return 0;
-}
-
-static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
-					   struct drm_plane_state *new_state)
-{
-	plane->state->src_x = new_state->src_x;
-	plane->state->src_y = new_state->src_y;
-	plane->state->crtc_x = new_state->crtc_x;
-	plane->state->crtc_y = new_state->crtc_y;
-
-	if (plane_enabled(new_state)) {
-		struct mdp5_ctl *ctl;
-		struct mdp5_pipeline *pipeline =
-					mdp5_crtc_get_pipeline(plane->crtc);
-		int ret;
-
-		ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb,
-				&new_state->src, &new_state->dst);
-		WARN_ON(ret < 0);
-
-		ctl = mdp5_crtc_get_ctl(new_state->crtc);
-
-		mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane));
-	}
-
-	*to_mdp5_plane_state(plane->state) =
-		*to_mdp5_plane_state(new_state);
-}
-
-static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
-		.prepare_fb = mdp5_plane_prepare_fb,
-		.cleanup_fb = mdp5_plane_cleanup_fb,
-		.atomic_check = mdp5_plane_atomic_check,
-		.atomic_update = mdp5_plane_atomic_update,
-		.atomic_async_check = mdp5_plane_atomic_async_check,
-		.atomic_async_update = mdp5_plane_atomic_async_update,
-};
-
-static void set_scanout_locked(struct mdp5_kms *mdp5_kms,
-			       enum mdp5_pipe pipe,
-			       struct drm_framebuffer *fb)
-{
-	struct msm_kms *kms = &mdp5_kms->base.base;
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
-			MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
-			MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
-			MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
-			MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 0));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 1));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 2));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
-			msm_framebuffer_iova(fb, kms->aspace, 3));
-}
-
-/* Note: mdp5_plane->pipe_lock must be locked */
-static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
-{
-	uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
-			 ~MDP5_PIPE_OP_MODE_CSC_1_EN;
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
-}
-
-/* Note: mdp5_plane->pipe_lock must be locked */
-static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
-		struct csc_cfg *csc)
-{
-	uint32_t  i, mode = 0; /* RGB, no CSC */
-	uint32_t *matrix;
-
-	if (unlikely(!csc))
-		return;
-
-	if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
-		mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
-	if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
-		mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
-	mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
-
-	matrix = csc->matrix;
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
-			MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
-
-	for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
-		uint32_t *pre_clamp = csc->pre_clamp;
-		uint32_t *post_clamp = csc->post_clamp;
-
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
-			MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
-			MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
-
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
-			MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
-			MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
-
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
-			MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
-
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
-			MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
-	}
-}
-
-#define PHASE_STEP_SHIFT	21
-#define DOWN_SCALE_RATIO_MAX	32	/* 2^(26-21) */
-
-static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
-{
-	uint32_t unit;
-
-	if (src == 0 || dst == 0)
-		return -EINVAL;
-
-	/*
-	 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
-	 * where 2^21 represents the unity "1" in fixed-point hardware design.
-	 * This leaves 5 bits for the integer part (downscale case):
-	 *	-> maximum downscale ratio = 0b1_1111 = 31
-	 */
-	if (src > (dst * DOWN_SCALE_RATIO_MAX))
-		return -EOVERFLOW;
-
-	unit = 1 << PHASE_STEP_SHIFT;
-	*out_phase = mult_frac(unit, src, dst);
-
-	return 0;
-}
-
-static int calc_scalex_steps(struct drm_plane *plane,
-		uint32_t pixel_format, uint32_t src, uint32_t dest,
-		uint32_t phasex_steps[COMP_MAX])
-{
-	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	struct device *dev = mdp5_kms->dev->dev;
-	uint32_t phasex_step;
-	unsigned int hsub;
-	int ret;
-
-	ret = calc_phase_step(src, dest, &phasex_step);
-	if (ret) {
-		dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
-		return ret;
-	}
-
-	hsub = drm_format_horz_chroma_subsampling(pixel_format);
-
-	phasex_steps[COMP_0]   = phasex_step;
-	phasex_steps[COMP_3]   = phasex_step;
-	phasex_steps[COMP_1_2] = phasex_step / hsub;
-
-	return 0;
-}
-
-static int calc_scaley_steps(struct drm_plane *plane,
-		uint32_t pixel_format, uint32_t src, uint32_t dest,
-		uint32_t phasey_steps[COMP_MAX])
-{
-	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	struct device *dev = mdp5_kms->dev->dev;
-	uint32_t phasey_step;
-	unsigned int vsub;
-	int ret;
-
-	ret = calc_phase_step(src, dest, &phasey_step);
-	if (ret) {
-		dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
-		return ret;
-	}
-
-	vsub = drm_format_vert_chroma_subsampling(pixel_format);
-
-	phasey_steps[COMP_0]   = phasey_step;
-	phasey_steps[COMP_3]   = phasey_step;
-	phasey_steps[COMP_1_2] = phasey_step / vsub;
-
-	return 0;
-}
-
-static uint32_t get_scale_config(const struct mdp_format *format,
-		uint32_t src, uint32_t dst, bool horz)
-{
-	bool scaling = format->is_yuv ? true : (src != dst);
-	uint32_t sub, pix_fmt = format->base.pixel_format;
-	uint32_t ya_filter, uv_filter;
-	bool yuv = format->is_yuv;
-
-	if (!scaling)
-		return 0;
-
-	if (yuv) {
-		sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) :
-			     drm_format_vert_chroma_subsampling(pix_fmt);
-		uv_filter = ((src / sub) <= dst) ?
-				   SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
-	}
-	ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
-
-	if (horz)
-		return  MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
-			MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) |
-			COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter));
-	else
-		return  MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
-			MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) |
-			COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter));
-}
-
-static void calc_pixel_ext(const struct mdp_format *format,
-		uint32_t src, uint32_t dst, uint32_t phase_step[2],
-		int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX],
-		bool horz)
-{
-	bool scaling = format->is_yuv ? true : (src != dst);
-	int i;
-
-	/*
-	 * Note:
-	 * We assume here that:
-	 *     1. PCMN filter is used for downscale
-	 *     2. bilinear filter is used for upscale
-	 *     3. we are in a single pipe configuration
-	 */
-
-	for (i = 0; i < COMP_MAX; i++) {
-		pix_ext_edge1[i] = 0;
-		pix_ext_edge2[i] = scaling ? 1 : 0;
-	}
-}
-
-static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
-	const struct mdp_format *format,
-	uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX],
-	uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX])
-{
-	uint32_t pix_fmt = format->base.pixel_format;
-	uint32_t lr, tb, req;
-	int i;
-
-	for (i = 0; i < COMP_MAX; i++) {
-		uint32_t roi_w = src_w;
-		uint32_t roi_h = src_h;
-
-		if (format->is_yuv && i == COMP_1_2) {
-			roi_w /= drm_format_horz_chroma_subsampling(pix_fmt);
-			roi_h /= drm_format_vert_chroma_subsampling(pix_fmt);
-		}
-
-		lr  = (pe_left[i] >= 0) ?
-			MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) :
-			MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]);
-
-		lr |= (pe_right[i] >= 0) ?
-			MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) :
-			MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]);
-
-		tb  = (pe_top[i] >= 0) ?
-			MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) :
-			MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]);
-
-		tb |= (pe_bottom[i] >= 0) ?
-			MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) :
-			MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]);
-
-		req  = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w +
-				pe_left[i] + pe_right[i]);
-
-		req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h +
-				pe_top[i] + pe_bottom[i]);
-
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req);
-
-		DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i,
-			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT),
-			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT),
-			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF),
-			FIELD(lr,  MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF),
-			FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT));
-
-		DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i,
-			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT),
-			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT),
-			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF),
-			FIELD(tb,  MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF),
-			FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM));
-	}
-}
-
-struct pixel_ext {
-	int left[COMP_MAX];
-	int right[COMP_MAX];
-	int top[COMP_MAX];
-	int bottom[COMP_MAX];
-};
-
-struct phase_step {
-	u32 x[COMP_MAX];
-	u32 y[COMP_MAX];
-};
-
-static void mdp5_hwpipe_mode_set(struct mdp5_kms *mdp5_kms,
-				 struct mdp5_hw_pipe *hwpipe,
-				 struct drm_framebuffer *fb,
-				 struct phase_step *step,
-				 struct pixel_ext *pe,
-				 u32 scale_config, u32 hdecm, u32 vdecm,
-				 bool hflip, bool vflip,
-				 int crtc_x, int crtc_y,
-				 unsigned int crtc_w, unsigned int crtc_h,
-				 u32 src_img_w, u32 src_img_h,
-				 u32 src_x, u32 src_y,
-				 u32 src_w, u32 src_h)
-{
-	enum mdp5_pipe pipe = hwpipe->pipe;
-	bool has_pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT;
-	const struct mdp_format *format =
-			to_mdp_format(msm_framebuffer_format(fb));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
-			MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_img_w) |
-			MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_img_h));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
-			MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
-			MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
-			MDP5_PIPE_SRC_XY_X(src_x) |
-			MDP5_PIPE_SRC_XY_Y(src_y));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
-			MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
-			MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
-			MDP5_PIPE_OUT_XY_X(crtc_x) |
-			MDP5_PIPE_OUT_XY_Y(crtc_y));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
-			MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
-			MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
-			MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
-			MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
-			COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
-			MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
-			MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
-			COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
-			MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
-			MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
-			MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
-			MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
-			MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
-			MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
-
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
-			(hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
-			(vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
-			COND(has_pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) |
-			MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
-
-	/* not using secure mode: */
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
-
-	if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT)
-		mdp5_write_pixel_ext(mdp5_kms, pipe, format,
-				src_w, pe->left, pe->right,
-				src_h, pe->top, pe->bottom);
-
-	if (hwpipe->caps & MDP_PIPE_CAP_SCALE) {
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
-				step->x[COMP_0]);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
-				step->y[COMP_0]);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
-				step->x[COMP_1_2]);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
-				step->y[COMP_1_2]);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
-				MDP5_PIPE_DECIMATION_VERT(vdecm) |
-				MDP5_PIPE_DECIMATION_HORZ(hdecm));
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe),
-			   scale_config);
-	}
-
-	if (hwpipe->caps & MDP_PIPE_CAP_CSC) {
-		if (MDP_FORMAT_IS_YUV(format))
-			csc_enable(mdp5_kms, pipe,
-					mdp_get_default_csc_cfg(CSC_YUV2RGB));
-		else
-			csc_disable(mdp5_kms, pipe);
-	}
-
-	set_scanout_locked(mdp5_kms, pipe, fb);
-}
-
-static int mdp5_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		struct drm_rect *src, struct drm_rect *dest)
-{
-	struct drm_plane_state *pstate = plane->state;
-	struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe;
-	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	enum mdp5_pipe pipe = hwpipe->pipe;
-	struct mdp5_hw_pipe *right_hwpipe;
-	const struct mdp_format *format;
-	uint32_t nplanes, config = 0;
-	struct phase_step step = { { 0 } };
-	struct pixel_ext pe = { { 0 } };
-	uint32_t hdecm = 0, vdecm = 0;
-	uint32_t pix_format;
-	unsigned int rotation;
-	bool vflip, hflip;
-	int crtc_x, crtc_y;
-	unsigned int crtc_w, crtc_h;
-	uint32_t src_x, src_y;
-	uint32_t src_w, src_h;
-	uint32_t src_img_w, src_img_h;
-	int ret;
-
-	nplanes = fb->format->num_planes;
-
-	/* bad formats should already be rejected: */
-	if (WARN_ON(nplanes > pipe2nclients(pipe)))
-		return -EINVAL;
-
-	format = to_mdp_format(msm_framebuffer_format(fb));
-	pix_format = format->base.pixel_format;
-
-	src_x = src->x1;
-	src_y = src->y1;
-	src_w = drm_rect_width(src);
-	src_h = drm_rect_height(src);
-
-	crtc_x = dest->x1;
-	crtc_y = dest->y1;
-	crtc_w = drm_rect_width(dest);
-	crtc_h = drm_rect_height(dest);
-
-	/* src values are in Q16 fixed point, convert to integer: */
-	src_x = src_x >> 16;
-	src_y = src_y >> 16;
-	src_w = src_w >> 16;
-	src_h = src_h >> 16;
-
-	src_img_w = min(fb->width, src_w);
-	src_img_h = min(fb->height, src_h);
-
-	DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", plane->name,
-			fb->base.id, src_x, src_y, src_w, src_h,
-			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
-
-	right_hwpipe = to_mdp5_plane_state(pstate)->r_hwpipe;
-	if (right_hwpipe) {
-		/*
-		 * if the plane comprises of 2 hw pipes, assume that the width
-		 * is split equally across them. The only parameters that varies
-		 * between the 2 pipes are src_x and crtc_x
-		 */
-		crtc_w /= 2;
-		src_w /= 2;
-		src_img_w /= 2;
-	}
-
-	ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, step.x);
-	if (ret)
-		return ret;
-
-	ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, step.y);
-	if (ret)
-		return ret;
-
-	if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
-		calc_pixel_ext(format, src_w, crtc_w, step.x,
-			       pe.left, pe.right, true);
-		calc_pixel_ext(format, src_h, crtc_h, step.y,
-			       pe.top, pe.bottom, false);
-	}
-
-	/* TODO calc hdecm, vdecm */
-
-	/* SCALE is used to both scale and up-sample chroma components */
-	config |= get_scale_config(format, src_w, crtc_w, true);
-	config |= get_scale_config(format, src_h, crtc_h, false);
-	DBG("scale config = %x", config);
-
-	rotation = drm_rotation_simplify(pstate->rotation,
-					 DRM_MODE_ROTATE_0 |
-					 DRM_MODE_REFLECT_X |
-					 DRM_MODE_REFLECT_Y);
-	hflip = !!(rotation & DRM_MODE_REFLECT_X);
-	vflip = !!(rotation & DRM_MODE_REFLECT_Y);
-
-	mdp5_hwpipe_mode_set(mdp5_kms, hwpipe, fb, &step, &pe,
-			     config, hdecm, vdecm, hflip, vflip,
-			     crtc_x, crtc_y, crtc_w, crtc_h,
-			     src_img_w, src_img_h,
-			     src_x, src_y, src_w, src_h);
-	if (right_hwpipe)
-		mdp5_hwpipe_mode_set(mdp5_kms, right_hwpipe, fb, &step, &pe,
-				     config, hdecm, vdecm, hflip, vflip,
-				     crtc_x + crtc_w, crtc_y, crtc_w, crtc_h,
-				     src_img_w, src_img_h,
-				     src_x + src_w, src_y, src_w, src_h);
-
-	plane->fb = fb;
-
-	return ret;
-}
-
-/*
- * Use this func and the one below only after the atomic state has been
- * successfully swapped
- */
-enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
-{
-	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
-
-	if (WARN_ON(!pstate->hwpipe))
-		return SSPP_NONE;
-
-	return pstate->hwpipe->pipe;
-}
-
-enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane)
-{
-	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
-
-	if (!pstate->r_hwpipe)
-		return SSPP_NONE;
-
-	return pstate->r_hwpipe->pipe;
-}
-
-uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
-{
-	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
-	u32 mask;
-
-	if (WARN_ON(!pstate->hwpipe))
-		return 0;
-
-	mask = pstate->hwpipe->flush_mask;
-
-	if (pstate->r_hwpipe)
-		mask |= pstate->r_hwpipe->flush_mask;
-
-	return mask;
-}
-
-/* initialize plane */
-struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-				  enum drm_plane_type type)
-{
-	struct drm_plane *plane = NULL;
-	struct mdp5_plane *mdp5_plane;
-	int ret;
-
-	mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
-	if (!mdp5_plane) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	plane = &mdp5_plane->base;
-
-	mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
-		ARRAY_SIZE(mdp5_plane->formats), false);
-
-	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
-			mdp5_plane->formats, mdp5_plane->nformats,
-			NULL, type, NULL);
-	if (ret)
-		goto fail;
-
-	drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
-
-	mdp5_plane_install_properties(plane, &plane->base);
-
-	return plane;
-
-fail:
-	if (plane)
-		mdp5_plane_destroy(plane);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
deleted file mode 100644
index ae4983d9d0a5..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "mdp5_kms.h"
-#include "mdp5_smp.h"
-
-
-struct mdp5_smp {
-	struct drm_device *dev;
-
-	uint8_t reserved[MAX_CLIENTS]; /* fixed MMBs allocation per client */
-
-	int blk_cnt;
-	int blk_size;
-
-	/* register cache */
-	u32 alloc_w[22];
-	u32 alloc_r[22];
-	u32 pipe_reqprio_fifo_wm0[SSPP_MAX];
-	u32 pipe_reqprio_fifo_wm1[SSPP_MAX];
-	u32 pipe_reqprio_fifo_wm2[SSPP_MAX];
-};
-
-static inline
-struct mdp5_kms *get_kms(struct mdp5_smp *smp)
-{
-	struct msm_drm_private *priv = smp->dev->dev_private;
-
-	return to_mdp5_kms(to_mdp_kms(priv->kms));
-}
-
-static inline u32 pipe2client(enum mdp5_pipe pipe, int plane)
-{
-#define CID_UNUSED	0
-
-	if (WARN_ON(plane >= pipe2nclients(pipe)))
-		return CID_UNUSED;
-
-	/*
-	 * Note on SMP clients:
-	 * For ViG pipes, fetch Y/Cr/Cb-components clients are always
-	 * consecutive, and in that order.
-	 *
-	 * e.g.:
-	 * if mdp5_cfg->smp.clients[SSPP_VIG0] = N,
-	 *	Y  plane's client ID is N
-	 *	Cr plane's client ID is N + 1
-	 *	Cb plane's client ID is N + 2
-	 */
-
-	return mdp5_cfg->smp.clients[pipe] + plane;
-}
-
-/* allocate blocks for the specified request: */
-static int smp_request_block(struct mdp5_smp *smp,
-		struct mdp5_smp_state *state,
-		u32 cid, int nblks)
-{
-	void *cs = state->client_state[cid];
-	int i, avail, cnt = smp->blk_cnt;
-	uint8_t reserved;
-
-	/* we shouldn't be requesting blocks for an in-use client: */
-	WARN_ON(bitmap_weight(cs, cnt) > 0);
-
-	reserved = smp->reserved[cid];
-
-	if (reserved) {
-		nblks = max(0, nblks - reserved);
-		DBG("%d MMBs allocated (%d reserved)", nblks, reserved);
-	}
-
-	avail = cnt - bitmap_weight(state->state, cnt);
-	if (nblks > avail) {
-		dev_err(smp->dev->dev, "out of blks (req=%d > avail=%d)\n",
-				nblks, avail);
-		return -ENOSPC;
-	}
-
-	for (i = 0; i < nblks; i++) {
-		int blk = find_first_zero_bit(state->state, cnt);
-		set_bit(blk, cs);
-		set_bit(blk, state->state);
-	}
-
-	return 0;
-}
-
-static void set_fifo_thresholds(struct mdp5_smp *smp,
-		enum mdp5_pipe pipe, int nblks)
-{
-	u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE);
-	u32 val;
-
-	/* 1/4 of SMP pool that is being fetched */
-	val = (nblks * smp_entries_per_blk) / 4;
-
-	smp->pipe_reqprio_fifo_wm0[pipe] = val * 1;
-	smp->pipe_reqprio_fifo_wm1[pipe] = val * 2;
-	smp->pipe_reqprio_fifo_wm2[pipe] = val * 3;
-}
-
-/*
- * NOTE: looks like if horizontal decimation is used (if we supported that)
- * then the width used to calculate SMP block requirements is the post-
- * decimated width.  Ie. SMP buffering sits downstream of decimation (which
- * presumably happens during the dma from scanout buffer).
- */
-uint32_t mdp5_smp_calculate(struct mdp5_smp *smp,
-		const struct mdp_format *format,
-		u32 width, bool hdecim)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(smp);
-	int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg);
-	int i, hsub, nplanes, nlines;
-	u32 fmt = format->base.pixel_format;
-	uint32_t blkcfg = 0;
-
-	nplanes = drm_format_num_planes(fmt);
-	hsub = drm_format_horz_chroma_subsampling(fmt);
-
-	/* different if BWC (compressed framebuffer?) enabled: */
-	nlines = 2;
-
-	/* Newer MDPs have split/packing logic, which fetches sub-sampled
-	 * U and V components (splits them from Y if necessary) and packs
-	 * them together, writes to SMP using a single client.
-	 */
-	if ((rev > 0) && (format->chroma_sample > CHROMA_FULL)) {
-		fmt = DRM_FORMAT_NV24;
-		nplanes = 2;
-
-		/* if decimation is enabled, HW decimates less on the
-		 * sub sampled chroma components
-		 */
-		if (hdecim && (hsub > 1))
-			hsub = 1;
-	}
-
-	for (i = 0; i < nplanes; i++) {
-		int n, fetch_stride, cpp;
-
-		cpp = drm_format_plane_cpp(fmt, i);
-		fetch_stride = width * cpp / (i ? hsub : 1);
-
-		n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size);
-
-		/* for hw rev v1.00 */
-		if (rev == 0)
-			n = roundup_pow_of_two(n);
-
-		blkcfg |= (n << (8 * i));
-	}
-
-	return blkcfg;
-}
-
-int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state,
-		enum mdp5_pipe pipe, uint32_t blkcfg)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(smp);
-	struct drm_device *dev = mdp5_kms->dev;
-	int i, ret;
-
-	for (i = 0; i < pipe2nclients(pipe); i++) {
-		u32 cid = pipe2client(pipe, i);
-		int n = blkcfg & 0xff;
-
-		if (!n)
-			continue;
-
-		DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n);
-		ret = smp_request_block(smp, state, cid, n);
-		if (ret) {
-			dev_err(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
-					n, ret);
-			return ret;
-		}
-
-		blkcfg >>= 8;
-	}
-
-	state->assigned |= (1 << pipe);
-
-	return 0;
-}
-
-/* Release SMP blocks for all clients of the pipe */
-void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state,
-		enum mdp5_pipe pipe)
-{
-	int i;
-	int cnt = smp->blk_cnt;
-
-	for (i = 0; i < pipe2nclients(pipe); i++) {
-		u32 cid = pipe2client(pipe, i);
-		void *cs = state->client_state[cid];
-
-		/* update global state: */
-		bitmap_andnot(state->state, state->state, cs, cnt);
-
-		/* clear client's state */
-		bitmap_zero(cs, cnt);
-	}
-
-	state->released |= (1 << pipe);
-}
-
-/* NOTE: SMP_ALLOC_* regs are *not* double buffered, so release has to
- * happen after scanout completes.
- */
-static unsigned update_smp_state(struct mdp5_smp *smp,
-		u32 cid, mdp5_smp_state_t *assigned)
-{
-	int cnt = smp->blk_cnt;
-	unsigned nblks = 0;
-	u32 blk, val;
-
-	for_each_set_bit(blk, *assigned, cnt) {
-		int idx = blk / 3;
-		int fld = blk % 3;
-
-		val = smp->alloc_w[idx];
-
-		switch (fld) {
-		case 0:
-			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
-			val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
-			break;
-		case 1:
-			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
-			val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid);
-			break;
-		case 2:
-			val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
-			val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid);
-			break;
-		}
-
-		smp->alloc_w[idx] = val;
-		smp->alloc_r[idx] = val;
-
-		nblks++;
-	}
-
-	return nblks;
-}
-
-static void write_smp_alloc_regs(struct mdp5_smp *smp)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(smp);
-	int i, num_regs;
-
-	num_regs = smp->blk_cnt / 3 + 1;
-
-	for (i = 0; i < num_regs; i++) {
-		mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(i),
-			   smp->alloc_w[i]);
-		mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(i),
-			   smp->alloc_r[i]);
-	}
-}
-
-static void write_smp_fifo_regs(struct mdp5_smp *smp)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(smp);
-	int i;
-
-	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
-		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
-		enum mdp5_pipe pipe = hwpipe->pipe;
-
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe),
-			   smp->pipe_reqprio_fifo_wm0[pipe]);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe),
-			   smp->pipe_reqprio_fifo_wm1[pipe]);
-		mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe),
-			   smp->pipe_reqprio_fifo_wm2[pipe]);
-	}
-}
-
-void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
-{
-	enum mdp5_pipe pipe;
-
-	for_each_set_bit(pipe, &state->assigned, sizeof(state->assigned) * 8) {
-		unsigned i, nblks = 0;
-
-		for (i = 0; i < pipe2nclients(pipe); i++) {
-			u32 cid = pipe2client(pipe, i);
-			void *cs = state->client_state[cid];
-
-			nblks += update_smp_state(smp, cid, cs);
-
-			DBG("assign %s:%u, %u blks",
-				pipe2name(pipe), i, nblks);
-		}
-
-		set_fifo_thresholds(smp, pipe, nblks);
-	}
-
-	write_smp_alloc_regs(smp);
-	write_smp_fifo_regs(smp);
-
-	state->assigned = 0;
-}
-
-void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state)
-{
-	enum mdp5_pipe pipe;
-
-	for_each_set_bit(pipe, &state->released, sizeof(state->released) * 8) {
-		DBG("release %s", pipe2name(pipe));
-		set_fifo_thresholds(smp, pipe, 0);
-	}
-
-	write_smp_fifo_regs(smp);
-
-	state->released = 0;
-}
-
-void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p)
-{
-	struct mdp5_kms *mdp5_kms = get_kms(smp);
-	struct mdp5_hw_pipe_state *hwpstate;
-	struct mdp5_smp_state *state;
-	int total = 0, i, j;
-
-	drm_printf(p, "name\tinuse\tplane\n");
-	drm_printf(p, "----\t-----\t-----\n");
-
-	if (drm_can_sleep())
-		drm_modeset_lock(&mdp5_kms->state_lock, NULL);
-
-	/* grab these *after* we hold the state_lock */
-	hwpstate = &mdp5_kms->state->hwpipe;
-	state = &mdp5_kms->state->smp;
-
-	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
-		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
-		struct drm_plane *plane = hwpstate->hwpipe_to_plane[hwpipe->idx];
-		enum mdp5_pipe pipe = hwpipe->pipe;
-		for (j = 0; j < pipe2nclients(pipe); j++) {
-			u32 cid = pipe2client(pipe, j);
-			void *cs = state->client_state[cid];
-			int inuse = bitmap_weight(cs, smp->blk_cnt);
-
-			drm_printf(p, "%s:%d\t%d\t%s\n",
-				pipe2name(pipe), j, inuse,
-				plane ? plane->name : NULL);
-
-			total += inuse;
-		}
-	}
-
-	drm_printf(p, "TOTAL:\t%d\t(of %d)\n", total, smp->blk_cnt);
-	drm_printf(p, "AVAIL:\t%d\n", smp->blk_cnt -
-			bitmap_weight(state->state, smp->blk_cnt));
-
-	if (drm_can_sleep())
-		drm_modeset_unlock(&mdp5_kms->state_lock);
-}
-
-void mdp5_smp_destroy(struct mdp5_smp *smp)
-{
-	kfree(smp);
-}
-
-struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg)
-{
-	struct mdp5_smp_state *state = &mdp5_kms->state->smp;
-	struct mdp5_smp *smp = NULL;
-	int ret;
-
-	smp = kzalloc(sizeof(*smp), GFP_KERNEL);
-	if (unlikely(!smp)) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	smp->dev = mdp5_kms->dev;
-	smp->blk_cnt = cfg->mmb_count;
-	smp->blk_size = cfg->mmb_size;
-
-	/* statically tied MMBs cannot be re-allocated: */
-	bitmap_copy(state->state, cfg->reserved_state, smp->blk_cnt);
-	memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved));
-
-	return smp;
-fail:
-	if (smp)
-		mdp5_smp_destroy(smp);
-
-	return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
deleted file mode 100644
index b41d0448fbe8..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MDP5_SMP_H__
-#define __MDP5_SMP_H__
-
-#include <drm/drm_print.h>
-
-#include "msm_drv.h"
-
-/*
- * SMP - Shared Memory Pool:
- *
- * SMP blocks are shared between all the clients, where each plane in
- * a scanout buffer is a SMP client.  Ie. scanout of 3 plane I420 on
- * pipe VIG0 => 3 clients: VIG0_Y, VIG0_CB, VIG0_CR.
- *
- * Based on the size of the attached scanout buffer, a certain # of
- * blocks must be allocated to that client out of the shared pool.
- *
- * In some hw, some blocks are statically allocated for certain pipes
- * and CANNOT be re-allocated (eg: MMB0 and MMB1 both tied to RGB0).
- *
- *
- * Atomic SMP State:
- *
- * On atomic updates that modify SMP configuration, the state is cloned
- * (copied) and modified.  For test-only, or in cases where atomic
- * update fails (or if we hit ww_mutex deadlock/backoff condition) the
- * new state is simply thrown away.
- *
- * Because the SMP registers are not double buffered, updates are a
- * two step process:
- *
- * 1) in _prepare_commit() we configure things (via read-modify-write)
- *    for the newly assigned pipes, so we don't take away blocks
- *    assigned to pipes that are still scanning out
- * 2) in _complete_commit(), after vblank/etc, we clear things for the
- *    released clients, since at that point old pipes are no longer
- *    scanning out.
- */
-struct mdp5_smp_state {
-	/* global state of what blocks are in use: */
-	mdp5_smp_state_t state;
-
-	/* per client state of what blocks they are using: */
-	mdp5_smp_state_t client_state[MAX_CLIENTS];
-
-	/* assigned pipes (hw updated at _prepare_commit()): */
-	unsigned long assigned;
-
-	/* released pipes (hw updated at _complete_commit()): */
-	unsigned long released;
-};
-
-struct mdp5_kms;
-struct mdp5_smp;
-
-/*
- * SMP module prototypes:
- * mdp5_smp_init() returns a SMP @handler,
- * which is then used to call the other mdp5_smp_*(handler, ...) functions.
- */
-
-struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms,
-		const struct mdp5_smp_block *cfg);
-void  mdp5_smp_destroy(struct mdp5_smp *smp);
-
-void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p);
-
-uint32_t mdp5_smp_calculate(struct mdp5_smp *smp,
-		const struct mdp_format *format,
-		u32 width, bool hdecim);
-
-int mdp5_smp_assign(struct mdp5_smp *smp, struct mdp5_smp_state *state,
-		enum mdp5_pipe pipe, uint32_t blkcfg);
-void mdp5_smp_release(struct mdp5_smp *smp, struct mdp5_smp_state *state,
-		enum mdp5_pipe pipe);
-
-void mdp5_smp_prepare_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state);
-void mdp5_smp_complete_commit(struct mdp5_smp *smp, struct mdp5_smp_state *state);
-
-#endif /* __MDP5_SMP_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
deleted file mode 100644
index 1494c407be44..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef MDP_COMMON_XML
-#define MDP_COMMON_XML
-
-/* Autogenerated file, DO NOT EDIT manually!
-
-This file was generated by the rules-ng-ng headergen tool in this git repository:
-http://github.com/freedreno/envytools/
-git clone https://github.com/freedreno/envytools.git
-
-The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1572 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20915 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2849 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  37411 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  33004 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    602 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2017-05-17 13:21:27)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  41799 bytes, from 2017-06-16 12:32:42)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (  10416 bytes, from 2017-05-17 13:21:27)
-
-Copyright (C) 2013-2017 by the following authors:
-- Rob Clark <robdclark@gmail.com> (robclark)
-- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice (including the
-next paragraph) shall be included in all copies or substantial
-portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-
-enum mdp_chroma_samp_type {
-	CHROMA_FULL = 0,
-	CHROMA_H2V1 = 1,
-	CHROMA_H1V2 = 2,
-	CHROMA_420 = 3,
-};
-
-enum mdp_fetch_type {
-	MDP_PLANE_INTERLEAVED = 0,
-	MDP_PLANE_PLANAR = 1,
-	MDP_PLANE_PSEUDO_PLANAR = 2,
-};
-
-enum mdp_mixer_stage_id {
-	STAGE_UNUSED = 0,
-	STAGE_BASE = 1,
-	STAGE0 = 2,
-	STAGE1 = 3,
-	STAGE2 = 4,
-	STAGE3 = 5,
-	STAGE4 = 6,
-	STAGE5 = 7,
-	STAGE6 = 8,
-	STAGE_MAX = 8,
-};
-
-enum mdp_alpha_type {
-	FG_CONST = 0,
-	BG_CONST = 1,
-	FG_PIXEL = 2,
-	BG_PIXEL = 3,
-};
-
-enum mdp_component_type {
-	COMP_0 = 0,
-	COMP_1_2 = 1,
-	COMP_3 = 2,
-	COMP_MAX = 3,
-};
-
-enum mdp_bpc {
-	BPC1 = 0,
-	BPC5 = 1,
-	BPC6 = 2,
-	BPC8 = 3,
-};
-
-enum mdp_bpc_alpha {
-	BPC1A = 0,
-	BPC4A = 1,
-	BPC6A = 2,
-	BPC8A = 3,
-};
-
-
-#endif /* MDP_COMMON_XML */
diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c
deleted file mode 100644
index b4a8aa4490ee..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp_format.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "msm_drv.h"
-#include "mdp_kms.h"
-
-static struct csc_cfg csc_convert[CSC_MAX] = {
-	[CSC_RGB2RGB] = {
-		.type = CSC_RGB2RGB,
-		.matrix = {
-			0x0200, 0x0000, 0x0000,
-			0x0000, 0x0200, 0x0000,
-			0x0000, 0x0000, 0x0200
-		},
-		.pre_bias =	{ 0x0, 0x0, 0x0 },
-		.post_bias =	{ 0x0, 0x0, 0x0 },
-		.pre_clamp =	{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff },
-		.post_clamp =	{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff },
-	},
-	[CSC_YUV2RGB] = {
-		.type = CSC_YUV2RGB,
-		.matrix = {
-			0x0254, 0x0000, 0x0331,
-			0x0254, 0xff37, 0xfe60,
-			0x0254, 0x0409, 0x0000
-		},
-		.pre_bias =	{ 0xfff0, 0xff80, 0xff80 },
-		.post_bias =	{ 0x00, 0x00, 0x00 },
-		.pre_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
-		.post_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
-	},
-	[CSC_RGB2YUV] = {
-		.type = CSC_RGB2YUV,
-		.matrix = {
-			0x0083, 0x0102, 0x0032,
-			0x1fb5, 0x1f6c, 0x00e1,
-			0x00e1, 0x1f45, 0x1fdc
-		},
-		.pre_bias =	{ 0x00, 0x00, 0x00 },
-		.post_bias =	{ 0x10, 0x80, 0x80 },
-		.pre_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
-		.post_clamp =	{ 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0 },
-	},
-	[CSC_YUV2YUV] = {
-		.type = CSC_YUV2YUV,
-		.matrix = {
-			0x0200, 0x0000, 0x0000,
-			0x0000, 0x0200, 0x0000,
-			0x0000, 0x0000, 0x0200
-		},
-		.pre_bias =	{ 0x00, 0x00, 0x00 },
-		.post_bias =	{ 0x00, 0x00, 0x00 },
-		.pre_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
-		.post_clamp =	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
-	},
-};
-
-#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs, yuv) { \
-		.base = { .pixel_format = DRM_FORMAT_ ## name }, \
-		.bpc_a = BPC ## a ## A,                          \
-		.bpc_r = BPC ## r,                               \
-		.bpc_g = BPC ## g,                               \
-		.bpc_b = BPC ## b,                               \
-		.unpack = { e0, e1, e2, e3 },                    \
-		.alpha_enable = alpha,                           \
-		.unpack_tight = tight,                           \
-		.cpp = c,                                        \
-		.unpack_count = cnt,                             \
-		.fetch_type = fp,                                \
-		.chroma_sample = cs,                             \
-		.is_yuv = yuv,                                   \
-}
-
-#define BPC0A 0
-
-/*
- * Note: Keep RGB formats 1st, followed by YUV formats to avoid breaking
- * mdp_get_rgb_formats()'s implementation.
- */
-static const struct mdp_format formats[] = {
-	/*  name      a  r  g  b   e0 e1 e2 e3  alpha   tight  cpp cnt ... */
-	FMT(ARGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  true,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(ABGR8888, 8, 8, 8, 8,  2, 0, 1, 3,  true,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(RGBA8888, 8, 8, 8, 8,  3, 1, 0, 2,  true,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(BGRA8888, 8, 8, 8, 8,  3, 2, 0, 1,  true,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(XBGR8888, 8, 8, 8, 8,  2, 0, 1, 3,  false,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(RGBX8888, 8, 8, 8, 8,  3, 1, 0, 2,  false,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(BGRX8888, 8, 8, 8, 8,  3, 2, 0, 1,  false,   true,  4,  4,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(RGB565,   0, 5, 6, 5,  1, 0, 2, 0,  false,  true,  2,  3,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-	FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3,
-			MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
-
-	/* --- RGB formats above / YUV formats below this line --- */
-
-	/* 2 plane YUV */
-	FMT(NV12,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
-			MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
-	FMT(NV21,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
-			MDP_PLANE_PSEUDO_PLANAR, CHROMA_420, true),
-	FMT(NV16,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
-			MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
-	FMT(NV61,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
-			MDP_PLANE_PSEUDO_PLANAR, CHROMA_H2V1, true),
-	/* 1 plane YUV */
-	FMT(VYUY,     0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  2, 4,
-			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
-	FMT(UYVY,     0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  2, 4,
-			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
-	FMT(YUYV,     0, 8, 8, 8,  0, 1, 0, 2,  false,  true,  2, 4,
-			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
-	FMT(YVYU,     0, 8, 8, 8,  0, 2, 0, 1,  false,  true,  2, 4,
-			MDP_PLANE_INTERLEAVED, CHROMA_H2V1, true),
-	/* 3 plane YUV */
-	FMT(YUV420,   0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  1, 1,
-			MDP_PLANE_PLANAR, CHROMA_420, true),
-	FMT(YVU420,   0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  1, 1,
-			MDP_PLANE_PLANAR, CHROMA_420, true),
-};
-
-/*
- * Note:
- * @rgb_only must be set to true, when requesting
- * supported formats for RGB pipes.
- */
-uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats,
-		bool rgb_only)
-{
-	uint32_t i;
-	for (i = 0; i < ARRAY_SIZE(formats); i++) {
-		const struct mdp_format *f = &formats[i];
-
-		if (i == max_formats)
-			break;
-
-		if (rgb_only && MDP_FORMAT_IS_YUV(f))
-			break;
-
-		pixel_formats[i] = f->base.pixel_format;
-	}
-
-	return i;
-}
-
-const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(formats); i++) {
-		const struct mdp_format *f = &formats[i];
-		if (f->base.pixel_format == format)
-			return &f->base;
-	}
-	return NULL;
-}
-
-struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type)
-{
-	if (unlikely(WARN_ON(type >= CSC_MAX)))
-		return NULL;
-
-	return &csc_convert[type];
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c
deleted file mode 100644
index 64287304054d..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp_kms.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "msm_drv.h"
-#include "mdp_kms.h"
-
-
-struct mdp_irq_wait {
-	struct mdp_irq irq;
-	int count;
-};
-
-static DECLARE_WAIT_QUEUE_HEAD(wait_event);
-
-static DEFINE_SPINLOCK(list_lock);
-
-static void update_irq(struct mdp_kms *mdp_kms)
-{
-	struct mdp_irq *irq;
-	uint32_t irqmask = mdp_kms->vblank_mask;
-
-	assert_spin_locked(&list_lock);
-
-	list_for_each_entry(irq, &mdp_kms->irq_list, node)
-		irqmask |= irq->irqmask;
-
-	mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask);
-	mdp_kms->cur_irq_mask = irqmask;
-}
-
-/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder
- * link changes, this must be called to figure out the new global irqmask
- */
-void mdp_irq_update(struct mdp_kms *mdp_kms)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&list_lock, flags);
-	update_irq(mdp_kms);
-	spin_unlock_irqrestore(&list_lock, flags);
-}
-
-void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status)
-{
-	struct mdp_irq *handler, *n;
-	unsigned long flags;
-
-	spin_lock_irqsave(&list_lock, flags);
-	mdp_kms->in_irq = true;
-	list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) {
-		if (handler->irqmask & status) {
-			spin_unlock_irqrestore(&list_lock, flags);
-			handler->irq(handler, handler->irqmask & status);
-			spin_lock_irqsave(&list_lock, flags);
-		}
-	}
-	mdp_kms->in_irq = false;
-	update_irq(mdp_kms);
-	spin_unlock_irqrestore(&list_lock, flags);
-
-}
-
-void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&list_lock, flags);
-	if (enable)
-		mdp_kms->vblank_mask |= mask;
-	else
-		mdp_kms->vblank_mask &= ~mask;
-	update_irq(mdp_kms);
-	spin_unlock_irqrestore(&list_lock, flags);
-}
-
-static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus)
-{
-	struct mdp_irq_wait *wait =
-			container_of(irq, struct mdp_irq_wait, irq);
-	wait->count--;
-	wake_up_all(&wait_event);
-}
-
-void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask)
-{
-	struct mdp_irq_wait wait = {
-		.irq = {
-			.irq = wait_irq,
-			.irqmask = irqmask,
-		},
-		.count = 1,
-	};
-	mdp_irq_register(mdp_kms, &wait.irq);
-	wait_event_timeout(wait_event, (wait.count <= 0),
-			msecs_to_jiffies(100));
-	mdp_irq_unregister(mdp_kms, &wait.irq);
-}
-
-void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
-{
-	unsigned long flags;
-	bool needs_update = false;
-
-	spin_lock_irqsave(&list_lock, flags);
-
-	if (!irq->registered) {
-		irq->registered = true;
-		list_add(&irq->node, &mdp_kms->irq_list);
-		needs_update = !mdp_kms->in_irq;
-	}
-
-	spin_unlock_irqrestore(&list_lock, flags);
-
-	if (needs_update)
-		mdp_irq_update(mdp_kms);
-}
-
-void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
-{
-	unsigned long flags;
-	bool needs_update = false;
-
-	spin_lock_irqsave(&list_lock, flags);
-
-	if (irq->registered) {
-		irq->registered = false;
-		list_del(&irq->node);
-		needs_update = !mdp_kms->in_irq;
-	}
-
-	spin_unlock_irqrestore(&list_lock, flags);
-
-	if (needs_update)
-		mdp_irq_update(mdp_kms);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h
deleted file mode 100644
index 1185487e7e5e..000000000000
--- a/drivers/gpu/drm/msm/mdp/mdp_kms.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MDP_KMS_H__
-#define __MDP_KMS_H__
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-
-#include "msm_drv.h"
-#include "msm_kms.h"
-#include "mdp_common.xml.h"
-
-struct mdp_kms;
-
-struct mdp_kms_funcs {
-	struct msm_kms_funcs base;
-	void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask,
-		uint32_t old_irqmask);
-};
-
-struct mdp_kms {
-	struct msm_kms base;
-
-	const struct mdp_kms_funcs *funcs;
-
-	/* irq handling: */
-	bool in_irq;
-	struct list_head irq_list;    /* list of mdp4_irq */
-	uint32_t vblank_mask;         /* irq bits set for userspace vblank */
-	uint32_t cur_irq_mask;        /* current irq mask */
-};
-#define to_mdp_kms(x) container_of(x, struct mdp_kms, base)
-
-static inline void mdp_kms_init(struct mdp_kms *mdp_kms,
-		const struct mdp_kms_funcs *funcs)
-{
-	mdp_kms->funcs = funcs;
-	INIT_LIST_HEAD(&mdp_kms->irq_list);
-	msm_kms_init(&mdp_kms->base, &funcs->base);
-}
-
-/*
- * irq helpers:
- */
-
-/* For transiently registering for different MDP irqs that various parts
- * of the KMS code need during setup/configuration.  These are not
- * necessarily the same as what drm_vblank_get/put() are requesting, and
- * the hysteresis in drm_vblank_put() is not necessarily desirable for
- * internal housekeeping related irq usage.
- */
-struct mdp_irq {
-	struct list_head node;
-	uint32_t irqmask;
-	bool registered;
-	void (*irq)(struct mdp_irq *irq, uint32_t irqstatus);
-};
-
-void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status);
-void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable);
-void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask);
-void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
-void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
-void mdp_irq_update(struct mdp_kms *mdp_kms);
-
-/*
- * pixel format helpers:
- */
-
-struct mdp_format {
-	struct msm_format base;
-	enum mdp_bpc bpc_r, bpc_g, bpc_b;
-	enum mdp_bpc_alpha bpc_a;
-	uint8_t unpack[4];
-	bool alpha_enable, unpack_tight;
-	uint8_t cpp, unpack_count;
-	enum mdp_fetch_type fetch_type;
-	enum mdp_chroma_samp_type chroma_sample;
-	bool is_yuv;
-};
-#define to_mdp_format(x) container_of(x, struct mdp_format, base)
-#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->is_yuv)
-
-uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only);
-const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
-
-/* MDP capabilities */
-#define MDP_CAP_SMP		BIT(0)	/* Shared Memory Pool                 */
-#define MDP_CAP_DSC		BIT(1)	/* VESA Display Stream Compression    */
-#define MDP_CAP_CDM		BIT(2)	/* Chroma Down Module (HDMI 2.0 YUV)  */
-#define MDP_CAP_SRC_SPLIT	BIT(3)	/* Source Split of SSPPs */
-
-/* MDP pipe capabilities */
-#define MDP_PIPE_CAP_HFLIP			BIT(0)
-#define MDP_PIPE_CAP_VFLIP			BIT(1)
-#define MDP_PIPE_CAP_SCALE			BIT(2)
-#define MDP_PIPE_CAP_CSC			BIT(3)
-#define MDP_PIPE_CAP_DECIMATION			BIT(4)
-#define MDP_PIPE_CAP_SW_PIX_EXT			BIT(5)
-#define MDP_PIPE_CAP_CURSOR			BIT(6)
-
-/* MDP layer mixer caps */
-#define MDP_LM_CAP_DISPLAY			BIT(0)
-#define MDP_LM_CAP_WB				BIT(1)
-#define MDP_LM_CAP_PAIR				BIT(2)
-
-static inline bool pipe_supports_yuv(uint32_t pipe_caps)
-{
-	return (pipe_caps & MDP_PIPE_CAP_SCALE) &&
-		(pipe_caps & MDP_PIPE_CAP_CSC);
-}
-
-enum csc_type {
-	CSC_RGB2RGB = 0,
-	CSC_YUV2RGB,
-	CSC_RGB2YUV,
-	CSC_YUV2YUV,
-	CSC_MAX
-};
-
-struct csc_cfg {
-	enum csc_type type;
-	uint32_t matrix[9];
-	uint32_t pre_bias[3];
-	uint32_t post_bias[3];
-	uint32_t pre_clamp[6];
-	uint32_t post_clamp[6];
-};
-
-struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type);
-
-#endif /* __MDP_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
index 1855182c76ce..ba74cb4f94df 100644
--- a/drivers/gpu/drm/msm/msm_debugfs.c
+++ b/drivers/gpu/drm/msm/msm_debugfs.c
@@ -161,8 +161,11 @@ int msm_debugfs_init(struct drm_minor *minor)
 		return ret;
 	}
 
-	if (priv->kms->funcs->debugfs_init)
+	if (priv->kms->funcs->debugfs_init) {
 		ret = priv->kms->funcs->debugfs_init(priv->kms, minor);
+		if (ret)
+			return ret;
+	}
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index d90ef1d78a1b..65d3b0bb7c86 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -393,6 +393,14 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 
 	drm_mode_config_init(ddev);
 
+	ret = msm_init_vram(ddev);
+	if (ret) {
+		msm_mdss_destroy(ddev);
+		kfree(priv);
+		drm_dev_unref(ddev);
+		return ret;
+	}
+
 	/* Bind all our sub-components: */
 	ret = component_bind_all(dev, ddev);
 	if (ret) {
@@ -402,10 +410,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
 		return ret;
 	}
 
-	ret = msm_init_vram(ddev);
-	if (ret)
-		goto fail;
-
 	msm_gem_shrinker_init(ddev);
 
 	switch (get_mdp_ver(pdev)) {
@@ -660,7 +664,7 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
 
 	ret = msm_gem_cpu_prep(obj, args->op, &timeout);
 
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 	return ret;
 }
@@ -678,7 +682,7 @@ static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
 
 	ret = msm_gem_cpu_fini(obj);
 
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 	return ret;
 }
@@ -718,7 +722,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
 		args->offset = msm_gem_mmap_offset(obj);
 	}
 
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 	return ret;
 }
@@ -783,7 +787,7 @@ static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data,
 		ret = 0;
 	}
 
-	drm_gem_object_unreference(obj);
+	drm_gem_object_put(obj);
 
 unlock:
 	mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 0a653dd2e618..48ed5b9a8580 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -51,7 +51,6 @@ struct msm_rd_state;
 struct msm_perf_state;
 struct msm_gem_submit;
 struct msm_fence_context;
-struct msm_fence_cb;
 struct msm_gem_address_space;
 struct msm_gem_vma;
 
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index fc175e724ad6..0e0c87252ab0 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -53,7 +53,7 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb)
 	for (i = 0; i < n; i++) {
 		struct drm_gem_object *bo = msm_fb->planes[i];
 
-		drm_gem_object_unreference_unlocked(bo);
+		drm_gem_object_put_unlocked(bo);
 	}
 
 	kfree(msm_fb);
@@ -160,7 +160,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
 
 out_unref:
 	for (i = 0; i < n; i++)
-		drm_gem_object_unreference_unlocked(bos[i]);
+		drm_gem_object_put_unlocked(bos[i]);
 	return ERR_PTR(ret);
 }
 
@@ -274,7 +274,7 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format
 		/* note: if fb creation failed, we can't rely on fb destroy
 		 * to unref the bo:
 		 */
-		drm_gem_object_unreference_unlocked(bo);
+		drm_gem_object_put_unlocked(bo);
 		return ERR_CAST(fb);
 	}
 
diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h
index 1aa6a4c6530c..b9fe059091f2 100644
--- a/drivers/gpu/drm/msm/msm_fence.h
+++ b/drivers/gpu/drm/msm/msm_fence.h
@@ -37,8 +37,6 @@ void msm_fence_context_free(struct msm_fence_context *fctx);
 
 int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence,
 		ktime_t *timeout, bool interruptible);
-int msm_queue_fence_cb(struct msm_fence_context *fctx,
-		struct msm_fence_cb *cb, uint32_t fence);
 void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence);
 
 struct dma_fence * msm_fence_alloc(struct msm_fence_context *fctx);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 07376de9ff4c..95196479f651 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -470,7 +470,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
 
 	*offset = msm_gem_mmap_offset(obj);
 
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 fail:
 	return ret;
@@ -798,6 +798,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
 }
 #endif
 
+/* don't call directly!  Use drm_gem_object_put() and friends */
 void msm_gem_free_object(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
@@ -854,7 +855,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
 	ret = drm_gem_handle_create(file, obj, handle);
 
 	/* drop reference from allocate - handle holds it now */
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 
 	return ret;
 }
@@ -974,7 +975,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
 	return obj;
 
 fail:
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 	return ERR_PTR(ret);
 }
 
@@ -1034,7 +1035,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
 	return obj;
 
 fail:
-	drm_gem_object_unreference_unlocked(obj);
+	drm_gem_object_put_unlocked(obj);
 	return ERR_PTR(ret);
 }
 
@@ -1052,7 +1053,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
 	if (iova) {
 		ret = msm_gem_get_iova(obj, aspace, iova);
 		if (ret) {
-			drm_gem_object_unreference(obj);
+			drm_gem_object_put(obj);
 			return ERR_PTR(ret);
 		}
 	}
@@ -1060,7 +1061,7 @@ static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size,
 	vaddr = msm_gem_get_vaddr(obj);
 	if (IS_ERR(vaddr)) {
 		msm_gem_put_iova(obj, aspace);
-		drm_gem_object_unreference(obj);
+		drm_gem_object_put(obj);
 		return ERR_CAST(vaddr);
 	}
 
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 9320e184b48d..c5d9bd3e47a8 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -146,6 +146,7 @@ struct msm_gem_submit {
 	struct msm_gpu_submitqueue *queue;
 	struct pid *pid;    /* submitting process */
 	bool valid;         /* true if no cmdstream patching needed */
+	bool in_rb;         /* "sudo" mode, copy cmds into RB */
 	struct msm_ringbuffer *ring;
 	unsigned int nr_cmds;
 	unsigned int nr_bos;
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index b8dc8f96caf2..7bd83e0afa97 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -430,6 +430,12 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 	if (MSM_PIPE_FLAGS(args->flags) & ~MSM_SUBMIT_FLAGS)
 		return -EINVAL;
 
+	if (args->flags & MSM_SUBMIT_SUDO) {
+		if (!IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) ||
+		    !capable(CAP_SYS_RAWIO))
+			return -EINVAL;
+	}
+
 	queue = msm_submitqueue_get(ctx, args->queueid);
 	if (!queue)
 		return -ENOENT;
@@ -471,6 +477,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 		goto out_unlock;
 	}
 
+	if (args->flags & MSM_SUBMIT_SUDO)
+		submit->in_rb = true;
+
 	ret = submit_lookup_objects(submit, args, file);
 	if (ret)
 		goto out;
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index d34e331554f3..ffbec224551b 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -96,6 +96,8 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
 		const char *name)
 {
 	struct msm_gem_address_space *aspace;
+	u64 size = domain->geometry.aperture_end -
+		domain->geometry.aperture_start;
 
 	aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
 	if (!aspace)
@@ -106,7 +108,7 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
 	aspace->mmu = msm_iommu_new(dev, domain);
 
 	drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT),
-			(domain->geometry.aperture_end >> PAGE_SHIFT) - 1);
+		size >> PAGE_SHIFT);
 
 	kref_init(&aspace->kref);
 
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index bd376f9e18a7..1c09acfb4028 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -552,7 +552,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
 		/* move to inactive: */
 		msm_gem_move_to_inactive(&msm_obj->base);
 		msm_gem_put_iova(&msm_obj->base, gpu->aspace);
-		drm_gem_object_unreference(&msm_obj->base);
+		drm_gem_object_put(&msm_obj->base);
 	}
 
 	pm_runtime_mark_last_busy(&gpu->pdev->dev);
@@ -634,7 +634,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 		WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu));
 
 		/* submit takes a reference to the bo and iova until retired: */
-		drm_gem_object_reference(&msm_obj->base);
+		drm_gem_object_get(&msm_obj->base);
 		msm_gem_get_iova(&msm_obj->base,
 				submit->gpu->aspace, &iova);
 
@@ -682,8 +682,10 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu)
 
 	gpu->grp_clks = devm_kcalloc(dev, sizeof(struct clk *), gpu->nr_clocks,
 		GFP_KERNEL);
-	if (!gpu->grp_clks)
+	if (!gpu->grp_clks) {
+		gpu->nr_clocks = 0;
 		return -ENOMEM;
+	}
 
 	of_property_for_each_string(dev->of_node, "clock-names", prop, name) {
 		gpu->grp_clks[i] = get_clock(dev, name);
@@ -865,7 +867,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 	if (gpu->memptrs_bo) {
 		msm_gem_put_vaddr(gpu->memptrs_bo);
 		msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace);
-		drm_gem_object_unreference_unlocked(gpu->memptrs_bo);
+		drm_gem_object_put_unlocked(gpu->memptrs_bo);
 	}
 
 	platform_set_drvdata(pdev, NULL);
@@ -888,7 +890,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
 	if (gpu->memptrs_bo) {
 		msm_gem_put_vaddr(gpu->memptrs_bo);
 		msm_gem_put_iova(gpu->memptrs_bo, gpu->aspace);
-		drm_gem_object_unreference_unlocked(gpu->memptrs_bo);
+		drm_gem_object_put_unlocked(gpu->memptrs_bo);
 	}
 
 	if (!IS_ERR_OR_NULL(gpu->aspace)) {
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index fccfccd303af..b8241179175a 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -65,6 +65,8 @@ struct msm_gpu_funcs {
 #ifdef CONFIG_DEBUG_FS
 	/* show GPU status in debugfs: */
 	void (*show)(struct msm_gpu *gpu, struct seq_file *m);
+	/* for generation specific debugfs: */
+	int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor);
 #endif
 	int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value);
 };
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index 6ca98da35f63..6f5295b3f2f6 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -76,7 +76,7 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
 	if (ring->bo) {
 		msm_gem_put_iova(ring->bo, ring->gpu->aspace);
 		msm_gem_put_vaddr(ring->bo);
-		drm_gem_object_unreference_unlocked(ring->bo);
+		drm_gem_object_put_unlocked(ring->bo);
 	}
 	kfree(ring);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 69d6e61a01ec..6ed9cb053dfa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
 		nv_connector->edid = NULL;
 	}
 
-	ret = pm_runtime_get_sync(connector->dev->dev);
-	if (ret < 0 && ret != -EACCES)
-		return conn_status;
+	/* Outputs are only polled while runtime active, so acquiring a
+	 * runtime PM ref here is unnecessary (and would deadlock upon
+	 * runtime suspend because it waits for polling to finish).
+	 */
+	if (!drm_kms_helper_is_poll_worker()) {
+		ret = pm_runtime_get_sync(connector->dev->dev);
+		if (ret < 0 && ret != -EACCES)
+			return conn_status;
+	}
 
 	nv_encoder = nouveau_connector_ddc_detect(connector);
 	if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
@@ -647,8 +653,10 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
 
  out:
 
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return conn_status;
 }
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index dd8d4352ed99..1f55b3d80a56 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -232,8 +232,6 @@ struct nv50_wndw_atom {
 	struct drm_plane_state state;
 	u8 interval;
 
-	struct drm_rect clip;
-
 	struct {
 		u32  handle;
 		u16  offset:12;
@@ -848,10 +846,6 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw,
 	int ret;
 
 	NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name);
-	asyw->clip.x1 = 0;
-	asyw->clip.y1 = 0;
-	asyw->clip.x2 = asyh->state.mode.hdisplay;
-	asyw->clip.y2 = asyh->state.mode.vdisplay;
 
 	asyw->image.w = fb->base.width;
 	asyw->image.h = fb->base.height;
@@ -1149,10 +1143,15 @@ static int
 nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
 		  struct nv50_head_atom *asyh)
 {
+	struct drm_rect clip = {};
 	int ret;
 
+	if (asyh->state.enable)
+		drm_mode_get_hv_timing(&asyh->state.mode,
+				       &clip.x2, &clip.y2);
+
 	ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
-						  &asyw->clip,
+						  &clip,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  true, true);
@@ -1436,13 +1435,18 @@ nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
 		  struct nv50_head_atom *asyh)
 {
 	const struct drm_framebuffer *fb = asyw->state.fb;
+	struct drm_rect clip = {};
 	int ret;
 
 	if (!fb->format->depth)
 		return -EINVAL;
 
+	if (asyh->state.enable)
+		drm_mode_get_hv_timing(&asyh->state.mode,
+				       &clip.x2, &clip.y2);
+
 	ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
-						  &asyw->clip,
+						  &clip,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  DRM_PLANE_HELPER_NO_SCALING,
 						  false, true);
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 6ba4031f3919..988048ebcc22 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -7,6 +7,16 @@ config DRM_PANEL
 menu "Display Panels"
 	depends on DRM && DRM_PANEL
 
+config DRM_PANEL_ARM_VERSATILE
+	tristate "ARM Versatile panel driver"
+	depends on OF
+	depends on MFD_SYSCON
+	select VIDEOMODE_HELPERS
+	help
+	  This driver supports the ARM Versatile panels connected to ARM
+	  reference designs. The panel is detected using special registers
+	  in the Versatile family syscon registers.
+
 config DRM_PANEL_LVDS
 	tristate "Generic LVDS panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 6d251ebc568c..3d2a88d0e965 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c
new file mode 100644
index 000000000000..3930b4925b15
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-arm-versatile.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Panel driver for the ARM Versatile family reference designs from
+ * ARM Limited.
+ *
+ * Author:
+ * Linus Walleij <linus.wallei@linaro.org>
+ *
+ * On the Versatile AB, these panels come mounted on daughterboards
+ * named "IB1" or "IB2" (Interface Board 1 & 2 respectively.) They
+ * are documented in ARM DUI 0225D Appendix C and D. These daughter
+ * boards support TFT display panels.
+ *
+ * - The IB1 is a passive board where the display connector defines a
+ *   few wires for encoding the display type for autodetection,
+ *   suitable display settings can then be looked up from this setting.
+ *   The magic bits can be read out from the system controller.
+ *
+ * - The IB2 is a more complex board intended for GSM phone development
+ *   with some logic and a control register, which needs to be accessed
+ *   and the board display needs to be turned on explicitly.
+ *
+ * On the Versatile PB, a special CLCD adaptor board is available
+ * supporting the same displays as the Versatile AB, plus one more
+ * Epson QCIF display.
+ *
+ */
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+/*
+ * This configuration register in the Versatile and RealView
+ * family is uniformly present but appears more and more
+ * unutilized starting with the RealView series.
+ */
+#define SYS_CLCD			0x50
+
+/* The Versatile can detect the connected panel type */
+#define SYS_CLCD_CLCDID_MASK		(BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12))
+#define SYS_CLCD_ID_SANYO_3_8		(0x00 << 8)
+#define SYS_CLCD_ID_SHARP_8_4		(0x01 << 8)
+#define SYS_CLCD_ID_EPSON_2_2		(0x02 << 8)
+#define SYS_CLCD_ID_SANYO_2_5		(0x07 << 8)
+#define SYS_CLCD_ID_VGA			(0x1f << 8)
+
+/* IB2 control register for the Versatile daughterboard */
+#define IB2_CTRL			0x00
+#define IB2_CTRL_LCD_SD			BIT(1) /* 1 = shut down LCD */
+#define IB2_CTRL_LCD_BL_ON		BIT(0)
+#define IB2_CTRL_LCD_MASK		(BIT(0)|BIT(1))
+
+/**
+ * struct versatile_panel_type - lookup struct for the supported panels
+ */
+struct versatile_panel_type {
+	/**
+	 * @name: the name of this panel
+	 */
+	const char *name;
+	/**
+	 * @magic: the magic value from the detection register
+	 */
+	u32 magic;
+	/**
+	 * @mode: the DRM display mode for this panel
+	 */
+	struct drm_display_mode mode;
+	/**
+	 * @bus_flags: the DRM bus flags for this panel e.g. inverted clock
+	 */
+	u32 bus_flags;
+	/**
+	 * @width_mm: the panel width in mm
+	 */
+	u32 width_mm;
+	/**
+	 * @height_mm: the panel height in mm
+	 */
+	u32 height_mm;
+	/**
+	 * @ib2: the panel may be connected on an IB2 daughterboard
+	 */
+	bool ib2;
+};
+
+/**
+ * struct versatile_panel - state container for the Versatile panels
+ */
+struct versatile_panel {
+	/**
+	 * @dev: the container device
+	 */
+	struct device *dev;
+	/**
+	 * @panel: the DRM panel instance for this device
+	 */
+	struct drm_panel panel;
+	/**
+	 * @panel_type: the Versatile panel type as detected
+	 */
+	const struct versatile_panel_type *panel_type;
+	/**
+	 * @map: map to the parent syscon where the main register reside
+	 */
+	struct regmap *map;
+	/**
+	 * @ib2_map: map to the IB2 syscon, if applicable
+	 */
+	struct regmap *ib2_map;
+};
+
+static const struct versatile_panel_type versatile_panels[] = {
+	/*
+	 * Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT
+	 * found on the Versatile AB IB1 connector or the Versatile
+	 * PB adaptor board connector.
+	 */
+	{
+		.name = "Sanyo TM38QV67A02A",
+		.magic = SYS_CLCD_ID_SANYO_3_8,
+		.width_mm = 79,
+		.height_mm = 54,
+		.mode = {
+			.clock = 10000000,
+			.hdisplay = 320,
+			.hsync_start = 320 + 6,
+			.hsync_end = 320 + 6 + 6,
+			.htotal = 320 + 6 + 6 + 6,
+			.vdisplay = 240,
+			.vsync_start = 240 + 5,
+			.vsync_end = 240 + 5 + 6,
+			.vtotal = 240 + 5 + 6 + 5,
+			.vrefresh = 116,
+			.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+		},
+	},
+	/*
+	 * Sharp LQ084V1DG21 640x480 VGA Color TFT module
+	 * found on the Versatile AB IB1 connector or the Versatile
+	 * PB adaptor board connector.
+	 */
+	{
+		.name = "Sharp LQ084V1DG21",
+		.magic = SYS_CLCD_ID_SHARP_8_4,
+		.width_mm = 171,
+		.height_mm = 130,
+		.mode = {
+			.clock = 25000000,
+			.hdisplay = 640,
+			.hsync_start = 640 + 24,
+			.hsync_end = 640 + 24 + 96,
+			.htotal = 640 + 24 + 96 + 24,
+			.vdisplay = 480,
+			.vsync_start = 480 + 11,
+			.vsync_end = 480 + 11 + 2,
+			.vtotal = 480 + 11 + 2 + 32,
+			.vrefresh = 60,
+			.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+		},
+	},
+	/*
+	 * Epson L2F50113T00 - 2.2 inch QCIF 176x220 Color TFT
+	 * found on the Versatile PB adaptor board connector.
+	 */
+	{
+		.name = "Epson L2F50113T00",
+		.magic = SYS_CLCD_ID_EPSON_2_2,
+		.width_mm = 34,
+		.height_mm = 45,
+		.mode = {
+			.clock = 625000000,
+			.hdisplay = 176,
+			.hsync_start = 176 + 2,
+			.hsync_end = 176 + 2 + 3,
+			.htotal = 176 + 2 + 3 + 3,
+			.vdisplay = 220,
+			.vsync_start = 220 + 0,
+			.vsync_end = 220 + 0 + 2,
+			.vtotal = 220 + 0 + 2 + 1,
+			.vrefresh = 390,
+			.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+		},
+		.bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE,
+	},
+	/*
+	 * Sanyo ALR252RGT 240x320 portrait display found on the
+	 * Versatile AB IB2 daughterboard for GSM prototyping.
+	 */
+	{
+		.name = "Sanyo ALR252RGT",
+		.magic = SYS_CLCD_ID_SANYO_2_5,
+		.width_mm = 37,
+		.height_mm = 50,
+		.mode = {
+			.clock = 5400000,
+			.hdisplay = 240,
+			.hsync_start = 240 + 10,
+			.hsync_end = 240 + 10 + 10,
+			.htotal = 240 + 10 + 10 + 20,
+			.vdisplay = 320,
+			.vsync_start = 320 + 2,
+			.vsync_end = 320 + 2 + 2,
+			.vtotal = 320 + 2 + 2 + 2,
+			.vrefresh = 116,
+			.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+		},
+		.bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE,
+		.ib2 = true,
+	},
+};
+
+static inline struct versatile_panel *
+to_versatile_panel(struct drm_panel *panel)
+{
+	return container_of(panel, struct versatile_panel, panel);
+}
+
+static int versatile_panel_disable(struct drm_panel *panel)
+{
+	struct versatile_panel *vpanel = to_versatile_panel(panel);
+
+	/* If we're on an IB2 daughterboard, turn off display */
+	if (vpanel->ib2_map) {
+		dev_dbg(vpanel->dev, "disable IB2 display\n");
+		regmap_update_bits(vpanel->ib2_map,
+				   IB2_CTRL,
+				   IB2_CTRL_LCD_MASK,
+				   IB2_CTRL_LCD_SD);
+	}
+
+	return 0;
+}
+
+static int versatile_panel_enable(struct drm_panel *panel)
+{
+	struct versatile_panel *vpanel = to_versatile_panel(panel);
+
+	/* If we're on an IB2 daughterboard, turn on display */
+	if (vpanel->ib2_map) {
+		dev_dbg(vpanel->dev, "enable IB2 display\n");
+		regmap_update_bits(vpanel->ib2_map,
+				   IB2_CTRL,
+				   IB2_CTRL_LCD_MASK,
+				   IB2_CTRL_LCD_BL_ON);
+	}
+
+	return 0;
+}
+
+static int versatile_panel_get_modes(struct drm_panel *panel)
+{
+	struct drm_connector *connector = panel->connector;
+	struct versatile_panel *vpanel = to_versatile_panel(panel);
+	struct drm_display_mode *mode;
+
+	strncpy(connector->display_info.name, vpanel->panel_type->name,
+		DRM_DISPLAY_INFO_LEN);
+	connector->display_info.width_mm = vpanel->panel_type->width_mm;
+	connector->display_info.height_mm = vpanel->panel_type->height_mm;
+	connector->display_info.bus_flags = vpanel->panel_type->bus_flags;
+
+	mode = drm_mode_duplicate(panel->drm, &vpanel->panel_type->mode);
+	drm_mode_set_name(mode);
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+	mode->width_mm = vpanel->panel_type->width_mm;
+	mode->height_mm = vpanel->panel_type->height_mm;
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_panel_funcs versatile_panel_drm_funcs = {
+	.disable = versatile_panel_disable,
+	.enable = versatile_panel_enable,
+	.get_modes = versatile_panel_get_modes,
+};
+
+static int versatile_panel_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct versatile_panel *vpanel;
+	struct device *parent;
+	struct regmap *map;
+	int ret;
+	u32 val;
+	int i;
+
+	parent = dev->parent;
+	if (!parent) {
+		dev_err(dev, "no parent for versatile panel\n");
+		return -ENODEV;
+	}
+	map = syscon_node_to_regmap(parent->of_node);
+	if (IS_ERR(map)) {
+		dev_err(dev, "no regmap for versatile panel parent\n");
+		return PTR_ERR(map);
+	}
+
+	vpanel = devm_kzalloc(dev, sizeof(*vpanel), GFP_KERNEL);
+	if (!vpanel)
+		return -ENOMEM;
+
+	ret = regmap_read(map, SYS_CLCD, &val);
+	if (ret) {
+		dev_err(dev, "cannot access syscon regs\n");
+		return ret;
+	}
+
+	val &= SYS_CLCD_CLCDID_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) {
+		const struct versatile_panel_type *pt;
+
+		pt = &versatile_panels[i];
+		if (pt->magic == val) {
+			vpanel->panel_type = pt;
+			break;
+		}
+	}
+
+	/* No panel detected or VGA, let's leave this show */
+	if (i == ARRAY_SIZE(versatile_panels)) {
+		dev_info(dev, "no panel detected\n");
+		return -ENODEV;
+	}
+
+	dev_info(dev, "detected: %s\n", vpanel->panel_type->name);
+	vpanel->dev = dev;
+	vpanel->map = map;
+
+	/* Check if the panel is mounted on an IB2 daughterboard */
+	if (vpanel->panel_type->ib2) {
+		vpanel->ib2_map = syscon_regmap_lookup_by_compatible(
+			"arm,versatile-ib2-syscon");
+		if (IS_ERR(vpanel->ib2_map))
+			vpanel->ib2_map = NULL;
+		else
+			dev_info(dev, "panel mounted on IB2 daughterboard\n");
+	}
+
+	drm_panel_init(&vpanel->panel);
+	vpanel->panel.dev = dev;
+	vpanel->panel.funcs = &versatile_panel_drm_funcs;
+
+	return drm_panel_add(&vpanel->panel);
+}
+
+static const struct of_device_id versatile_panel_match[] = {
+	{ .compatible = "arm,versatile-tft-panel", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, versatile_panel_match);
+
+static struct platform_driver versatile_panel_driver = {
+	.probe		= versatile_panel_probe,
+	.driver		= {
+		.name	= "versatile-tft-panel",
+		.of_match_table = versatile_panel_match,
+	},
+};
+module_platform_driver(versatile_panel_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("ARM Versatile panel driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
index 7f915f706fa6..74a806121f80 100644
--- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
+++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
@@ -59,34 +59,28 @@ static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
 
 static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
 {
-	struct mipi_dsi_device *dsi = wuxga_nt->dsi;
-	int ret;
-
-	ret = mipi_dsi_turn_on_peripheral(dsi);
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	return mipi_dsi_turn_on_peripheral(wuxga_nt->dsi);
 }
 
 static int wuxga_nt_panel_disable(struct drm_panel *panel)
 {
 	struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
+	int mipi_ret, bl_ret = 0;
 
 	if (!wuxga_nt->enabled)
 		return 0;
 
-	mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
+	mipi_ret = mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
 
 	if (wuxga_nt->backlight) {
 		wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN;
 		wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK;
-		backlight_update_status(wuxga_nt->backlight);
+		bl_ret = backlight_update_status(wuxga_nt->backlight);
 	}
 
 	wuxga_nt->enabled = false;
 
-	return 0;
+	return mipi_ret ? mipi_ret : bl_ret;
 }
 
 static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig
index e5e2abd66491..82cb3e60ddc8 100644
--- a/drivers/gpu/drm/pl111/Kconfig
+++ b/drivers/gpu/drm/pl111/Kconfig
@@ -8,6 +8,7 @@ config DRM_PL111
 	select DRM_GEM_CMA_HELPER
 	select DRM_BRIDGE
 	select DRM_PANEL_BRIDGE
+	select DRM_DUMB_VGA_DAC
 	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
 	help
 	  Choose this option for DRM support for the PL111 CLCD controller.
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c
index 06c4bf756b69..d75923896609 100644
--- a/drivers/gpu/drm/pl111/pl111_display.c
+++ b/drivers/gpu/drm/pl111/pl111_display.c
@@ -94,6 +94,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 	const struct drm_display_mode *mode = &cstate->mode;
 	struct drm_framebuffer *fb = plane->state->fb;
 	struct drm_connector *connector = priv->connector;
+	struct drm_bridge *bridge = priv->bridge;
 	u32 cntl;
 	u32 ppl, hsw, hfp, hbp;
 	u32 lpp, vsw, vfp, vbp;
@@ -137,17 +138,46 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 	tim2 = readl(priv->regs + CLCD_TIM2);
 	tim2 &= (TIM2_BCD | TIM2_PCD_LO_MASK | TIM2_PCD_HI_MASK);
 
+	if (priv->variant->broken_clockdivider)
+		tim2 |= TIM2_BCD;
+
 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
 		tim2 |= TIM2_IHS;
 
 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
 		tim2 |= TIM2_IVS;
 
-	if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW)
-		tim2 |= TIM2_IOE;
+	if (connector) {
+		if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW)
+			tim2 |= TIM2_IOE;
 
-	if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
-		tim2 |= TIM2_IPC;
+		if (connector->display_info.bus_flags &
+		    DRM_BUS_FLAG_PIXDATA_NEGEDGE)
+			tim2 |= TIM2_IPC;
+	}
+
+	if (bridge) {
+		const struct drm_bridge_timings *btimings = bridge->timings;
+
+		/*
+		 * Here is when things get really fun. Sometimes the bridge
+		 * timings are such that the signal out from PL11x is not
+		 * stable before the receiving bridge (such as a dumb VGA DAC
+		 * or similar) samples it. If that happens, we compensate by
+		 * the only method we have: output the data on the opposite
+		 * edge of the clock so it is for sure stable when it gets
+		 * sampled.
+		 *
+		 * The PL111 manual does not contain proper timining diagrams
+		 * or data for these details, but we know from experiments
+		 * that the setup time is more than 3000 picoseconds (3 ns).
+		 * If we have a bridge that requires the signal to be stable
+		 * earlier than 3000 ps before the clock pulse, we have to
+		 * output the data on the opposite edge to avoid flicker.
+		 */
+		if (btimings && btimings->setup_time_ps >= 3000)
+			tim2 ^= TIM2_IPC;
+	}
 
 	tim2 |= cpl << 16;
 	writel(tim2, priv->regs + CLCD_TIM2);
@@ -172,10 +202,17 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 		cntl |= CNTL_LCDBPP24 | CNTL_BGR;
 		break;
 	case DRM_FORMAT_BGR565:
-		cntl |= CNTL_LCDBPP16_565;
+		if (priv->variant->is_pl110)
+			cntl |= CNTL_LCDBPP16;
+		else
+			cntl |= CNTL_LCDBPP16_565;
 		break;
 	case DRM_FORMAT_RGB565:
-		cntl |= CNTL_LCDBPP16_565 | CNTL_BGR;
+		if (priv->variant->is_pl110)
+			cntl |= CNTL_LCDBPP16;
+		else
+			cntl |= CNTL_LCDBPP16_565;
+		cntl |= CNTL_BGR;
 		break;
 	case DRM_FORMAT_ABGR1555:
 	case DRM_FORMAT_XBGR1555:
@@ -199,6 +236,10 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 		break;
 	}
 
+	/* The PL110 in Integrator/Versatile does the BGR routing externally */
+	if (priv->variant->external_bgr)
+		cntl &= ~CNTL_BGR;
+
 	/* Power sequence: first enable and chill */
 	writel(cntl, priv->regs + priv->ctrl);
 
@@ -215,7 +256,8 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 	cntl |= CNTL_LCDPWR;
 	writel(cntl, priv->regs + priv->ctrl);
 
-	drm_crtc_vblank_on(crtc);
+	if (!priv->variant->broken_vblank)
+		drm_crtc_vblank_on(crtc);
 }
 
 void pl111_display_disable(struct drm_simple_display_pipe *pipe)
@@ -225,7 +267,8 @@ void pl111_display_disable(struct drm_simple_display_pipe *pipe)
 	struct pl111_drm_dev_private *priv = drm->dev_private;
 	u32 cntl;
 
-	drm_crtc_vblank_off(crtc);
+	if (!priv->variant->broken_vblank)
+		drm_crtc_vblank_off(crtc);
 
 	/* Power Down */
 	cntl = readl(priv->regs + priv->ctrl);
@@ -417,6 +460,11 @@ pl111_init_clock_divider(struct drm_device *drm)
 		dev_err(drm->dev, "CLCD: unable to get clcdclk.\n");
 		return PTR_ERR(parent);
 	}
+	/* If the clock divider is broken, use the parent directly */
+	if (priv->variant->broken_clockdivider) {
+		priv->clk = parent;
+		return 0;
+	}
 	parent_name = __clk_get_name(parent);
 
 	spin_lock_init(&priv->tim2_lock);
diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h
index 07fa2cdb364a..6d0e450e51b1 100644
--- a/drivers/gpu/drm/pl111/pl111_drm.h
+++ b/drivers/gpu/drm/pl111/pl111_drm.h
@@ -36,12 +36,20 @@ struct drm_minor;
  * struct pl111_variant_data - encodes IP differences
  * @name: the name of this variant
  * @is_pl110: this is the early PL110 variant
+ * @external_bgr: this is the Versatile Pl110 variant with external
+ *	BGR/RGB routing
+ * @broken_clockdivider: the clock divider is broken and we need to
+ *	use the supplied clock directly
+ * @broken_vblank: the vblank IRQ is broken on this variant
  * @formats: array of supported pixel formats on this variant
  * @nformats: the length of the array of supported pixel formats
  */
 struct pl111_variant_data {
 	const char *name;
 	bool is_pl110;
+	bool external_bgr;
+	bool broken_clockdivider;
+	bool broken_vblank;
 	const u32 *formats;
 	unsigned int nformats;
 };
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index acb738c69873..1231905150d0 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -58,6 +58,8 @@
 #include <linux/dma-buf.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
@@ -85,9 +87,13 @@ static int pl111_modeset_init(struct drm_device *dev)
 {
 	struct drm_mode_config *mode_config;
 	struct pl111_drm_dev_private *priv = dev->dev_private;
-	struct drm_panel *panel;
-	struct drm_bridge *bridge;
+	struct device_node *np = dev->dev->of_node;
+	struct device_node *remote;
+	struct drm_panel *panel = NULL;
+	struct drm_bridge *bridge = NULL;
+	bool defer = false;
 	int ret = 0;
+	int i;
 
 	drm_mode_config_init(dev);
 	mode_config = &dev->mode_config;
@@ -97,10 +103,54 @@ static int pl111_modeset_init(struct drm_device *dev)
 	mode_config->min_height = 1;
 	mode_config->max_height = 768;
 
-	ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
-					  0, 0, &panel, &bridge);
-	if (ret && ret != -ENODEV)
-		return ret;
+	i = 0;
+	for_each_endpoint_of_node(np, remote) {
+		struct drm_panel *tmp_panel;
+		struct drm_bridge *tmp_bridge;
+
+		dev_dbg(dev->dev, "checking endpoint %d\n", i);
+
+		ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
+						  0, i,
+						  &tmp_panel,
+						  &tmp_bridge);
+		if (ret) {
+			if (ret == -EPROBE_DEFER) {
+				/*
+				 * Something deferred, but that is often just
+				 * another way of saying -ENODEV, but let's
+				 * cast a vote for later deferral.
+				 */
+				defer = true;
+			} else if (ret != -ENODEV) {
+				/* Continue, maybe something else is working */
+				dev_err(dev->dev,
+					"endpoint %d returns %d\n", i, ret);
+			}
+		}
+
+		if (tmp_panel) {
+			dev_info(dev->dev,
+				 "found panel on endpoint %d\n", i);
+			panel = tmp_panel;
+		}
+		if (tmp_bridge) {
+			dev_info(dev->dev,
+				 "found bridge on endpoint %d\n", i);
+			bridge = tmp_bridge;
+		}
+
+		i++;
+	}
+
+	/*
+	 * If we can't find neither panel nor bridge on any of the
+	 * endpoints, and any of them retured -EPROBE_DEFER, then
+	 * let's defer this driver too.
+	 */
+	if ((!panel && !bridge) && defer)
+		return -EPROBE_DEFER;
+
 	if (panel) {
 		bridge = drm_panel_bridge_add(panel,
 					      DRM_MODE_CONNECTOR_Unknown);
@@ -108,11 +158,17 @@ static int pl111_modeset_init(struct drm_device *dev)
 			ret = PTR_ERR(bridge);
 			goto out_config;
 		}
-		/*
-		 * TODO: when we are using a different bridge than a panel
-		 * (such as a dumb VGA connector) we need to devise a different
-		 * method to get the connector out of the bridge.
-		 */
+	} else if (bridge) {
+		dev_info(dev->dev, "Using non-panel bridge\n");
+	} else {
+		dev_err(dev->dev, "No bridge, exiting\n");
+		return -ENODEV;
+	}
+
+	priv->bridge = bridge;
+	if (panel) {
+		priv->panel = panel;
+		priv->connector = panel->connector;
 	}
 
 	ret = pl111_display_init(dev);
@@ -126,14 +182,12 @@ static int pl111_modeset_init(struct drm_device *dev)
 	if (ret)
 		return ret;
 
-	priv->bridge = bridge;
-	priv->panel = panel;
-	priv->connector = panel->connector;
-
-	ret = drm_vblank_init(dev, 1);
-	if (ret != 0) {
-		dev_err(dev->dev, "Failed to init vblank\n");
-		goto out_bridge;
+	if (!priv->variant->broken_vblank) {
+		ret = drm_vblank_init(dev, 1);
+		if (ret != 0) {
+			dev_err(dev->dev, "Failed to init vblank\n");
+			goto out_bridge;
+		}
 	}
 
 	drm_mode_config_reset(dev);
@@ -170,10 +224,6 @@ static struct drm_driver pl111_drm_driver = {
 	.dumb_create = drm_gem_cma_dumb_create,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_vm_ops = &drm_gem_cma_vm_ops,
-
-	.enable_vblank = pl111_enable_vblank,
-	.disable_vblank = pl111_disable_vblank,
-
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_prime_import = drm_gem_prime_import,
@@ -191,7 +241,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
 {
 	struct device *dev = &amba_dev->dev;
 	struct pl111_drm_dev_private *priv;
-	struct pl111_variant_data *variant = id->data;
+	const struct pl111_variant_data *variant = id->data;
 	struct drm_device *drm;
 	int ret;
 
@@ -199,6 +249,11 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
 	if (!priv)
 		return -ENOMEM;
 
+	if (!variant->broken_vblank) {
+		pl111_drm_driver.enable_vblank = pl111_enable_vblank;
+		pl111_drm_driver.disable_vblank = pl111_disable_vblank;
+	}
+
 	drm = drm_dev_alloc(&pl111_drm_driver, dev);
 	if (IS_ERR(drm))
 		return PTR_ERR(drm);
@@ -207,27 +262,10 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
 	drm->dev_private = priv;
 	priv->variant = variant;
 
-	/*
-	 * The PL110 and PL111 variants have two registers
-	 * swapped: interrupt enable and control. For this reason
-	 * we use offsets that we can change per variant.
-	 */
+	/* The two variants swap this register */
 	if (variant->is_pl110) {
-		/*
-		 * The ARM Versatile boards are even more special:
-		 * their PrimeCell ID say they are PL110 but the
-		 * control and interrupt enable registers are anyway
-		 * swapped to the PL111 order so they are not following
-		 * the PL110 datasheet.
-		 */
-		if (of_machine_is_compatible("arm,versatile-ab") ||
-		    of_machine_is_compatible("arm,versatile-pb")) {
-			priv->ienb = CLCD_PL111_IENB;
-			priv->ctrl = CLCD_PL111_CNTL;
-		} else {
-			priv->ienb = CLCD_PL110_IENB;
-			priv->ctrl = CLCD_PL110_CNTL;
-		}
+		priv->ienb = CLCD_PL110_IENB;
+		priv->ctrl = CLCD_PL110_CNTL;
 	} else {
 		priv->ienb = CLCD_PL111_IENB;
 		priv->ctrl = CLCD_PL111_CNTL;
@@ -239,6 +277,11 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
 		return PTR_ERR(priv->regs);
 	}
 
+	/* This may override some variant settings */
+	ret = pl111_versatile_init(dev, priv);
+	if (ret)
+		goto dev_unref;
+
 	/* turn off interrupts before requesting the irq */
 	writel(0, priv->regs + priv->ienb);
 
@@ -249,10 +292,6 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
 		return ret;
 	}
 
-	ret = pl111_versatile_init(dev, priv);
-	if (ret)
-		goto dev_unref;
-
 	ret = pl111_modeset_init(drm);
 	if (ret != 0)
 		goto dev_unref;
@@ -284,8 +323,7 @@ static int pl111_amba_remove(struct amba_device *amba_dev)
 }
 
 /*
- * This variant exist in early versions like the ARM Integrator
- * and this version lacks the 565 and 444 pixel formats.
+ * This early variant lacks the 565 and 444 pixel formats.
  */
 static const u32 pl110_pixel_formats[] = {
 	DRM_FORMAT_ABGR8888,
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c
index 97d4af6925a3..05a4b89e0934 100644
--- a/drivers/gpu/drm/pl111/pl111_versatile.c
+++ b/drivers/gpu/drm/pl111/pl111_versatile.c
@@ -1,3 +1,4 @@
+#include <linux/amba/clcd-regs.h>
 #include <linux/device.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
@@ -64,10 +65,8 @@ static const struct of_device_id versatile_clcd_of_match[] = {
 #define INTEGRATOR_CLCD_LCDBIASEN	BIT(8)
 #define INTEGRATOR_CLCD_LCDBIASUP	BIT(9)
 #define INTEGRATOR_CLCD_LCDBIASDN	BIT(10)
-/* Bits 11,12,13 controls the LCD type */
-#define INTEGRATOR_CLCD_LCDMUX_MASK	(BIT(11)|BIT(12)|BIT(13))
+/* Bits 11,12,13 controls the LCD or VGA bridge type */
 #define INTEGRATOR_CLCD_LCDMUX_LCD24	BIT(11)
-#define INTEGRATOR_CLCD_LCDMUX_VGA565	BIT(12)
 #define INTEGRATOR_CLCD_LCDMUX_SHARP	(BIT(11)|BIT(12))
 #define INTEGRATOR_CLCD_LCDMUX_VGA555	BIT(13)
 #define INTEGRATOR_CLCD_LCDMUX_VGA24	(BIT(11)|BIT(12)|BIT(13))
@@ -82,16 +81,7 @@ static const struct of_device_id versatile_clcd_of_match[] = {
 /* 0 = 24bit VGA, 1 = 18bit VGA */
 #define INTEGRATOR_CLCD_LCD_N24BITEN	BIT(19)
 
-#define INTEGRATOR_CLCD_MASK		(INTEGRATOR_CLCD_LCDBIASEN | \
-					 INTEGRATOR_CLCD_LCDBIASUP | \
-					 INTEGRATOR_CLCD_LCDBIASDN | \
-					 INTEGRATOR_CLCD_LCDMUX_MASK | \
-					 INTEGRATOR_CLCD_LCD0_EN | \
-					 INTEGRATOR_CLCD_LCD1_EN | \
-					 INTEGRATOR_CLCD_LCD_STATIC1 | \
-					 INTEGRATOR_CLCD_LCD_STATIC2 | \
-					 INTEGRATOR_CLCD_LCD_STATIC | \
-					 INTEGRATOR_CLCD_LCD_N24BITEN)
+#define INTEGRATOR_CLCD_MASK		GENMASK(19, 8)
 
 static void pl111_integrator_enable(struct drm_device *drm, u32 format)
 {
@@ -106,11 +96,8 @@ static void pl111_integrator_enable(struct drm_device *drm, u32 format)
 	switch (format) {
 	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_XRGB8888:
-		break;
-	case DRM_FORMAT_BGR565:
-	case DRM_FORMAT_RGB565:
-		/* truecolor RGB565 */
-		val |= INTEGRATOR_CLCD_LCDMUX_VGA565;
+		/* 24bit formats */
+		val |= INTEGRATOR_CLCD_LCDMUX_VGA24;
 		break;
 	case DRM_FORMAT_XBGR1555:
 	case DRM_FORMAT_XRGB1555:
@@ -217,6 +204,57 @@ static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format)
 			   SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
 }
 
+/* PL110 pixel formats for Integrator, vanilla PL110 */
+static const u32 pl110_integrator_pixel_formats[] = {
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB1555,
+};
+
+/* Extended PL110 pixel formats for Integrator and Versatile */
+static const u32 pl110_versatile_pixel_formats[] = {
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_BGR565, /* Uses external PLD */
+	DRM_FORMAT_RGB565, /* Uses external PLD */
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XRGB1555,
+};
+
+/*
+ * The Integrator variant is a PL110 with a bunch of broken, or not
+ * yet implemented features
+ */
+static const struct pl111_variant_data pl110_integrator = {
+	.name = "PL110 Integrator",
+	.is_pl110 = true,
+	.broken_clockdivider = true,
+	.broken_vblank = true,
+	.formats = pl110_integrator_pixel_formats,
+	.nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
+};
+
+/*
+ * This is the in-between PL110 variant found in the ARM Versatile,
+ * supporting RGB565/BGR565
+ */
+static const struct pl111_variant_data pl110_versatile = {
+	.name = "PL110 Versatile",
+	.is_pl110 = true,
+	.external_bgr = true,
+	.formats = pl110_versatile_pixel_formats,
+	.nformats = ARRAY_SIZE(pl110_versatile_pixel_formats),
+};
+
 int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
 {
 	const struct of_device_id *clcd_id;
@@ -241,14 +279,24 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
 	switch (versatile_clcd_type) {
 	case INTEGRATOR_CLCD_CM:
 		versatile_syscon_map = map;
+		priv->variant = &pl110_integrator;
 		priv->variant_display_enable = pl111_integrator_enable;
 		dev_info(dev, "set up callbacks for Integrator PL110\n");
 		break;
 	case VERSATILE_CLCD:
 		versatile_syscon_map = map;
+		/* This can do RGB565 with external PLD */
+		priv->variant = &pl110_versatile;
 		priv->variant_display_enable = pl111_versatile_enable;
 		priv->variant_display_disable = pl111_versatile_disable;
-		dev_info(dev, "set up callbacks for Versatile PL110+\n");
+		/*
+		 * The Versatile has a variant halfway between PL110
+		 * and PL111 where these two registers have already been
+		 * swapped.
+		 */
+		priv->ienb = CLCD_PL111_IENB;
+		priv->ctrl = CLCD_PL111_CNTL;
+		dev_info(dev, "set up callbacks for Versatile PL110\n");
 		break;
 	case REALVIEW_CLCD_EB:
 	case REALVIEW_CLCD_PB1176:
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index d34887873dea..4a2eb409aacc 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2387,6 +2387,7 @@ struct radeon_device {
 	struct radeon_dummy_page	dummy_page;
 	bool				shutdown;
 	bool				need_dma32;
+	bool				need_swiotlb;
 	bool				accel_working;
 	bool				fastfb_working; /* IGP feature*/
 	bool				needs_reset, in_reset;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 5012f5e47a1e..2e2ca3c6b47d 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -899,9 +899,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	if (encoder) {
 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -924,8 +926,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
 	/* check acpi lid status ??? */
 
 	radeon_connector_update_scratch_regs(connector, ret);
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
+
 	return ret;
 }
 
@@ -1039,9 +1045,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status ret = connector_status_disconnected;
 	int r;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	encoder = radeon_best_single_encoder(connector);
 	if (!encoder)
@@ -1108,8 +1116,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
 	radeon_connector_update_scratch_regs(connector, ret);
 
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1173,9 +1183,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force)
 	if (!radeon_connector->dac_load_detect)
 		return ret;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	encoder = radeon_best_single_encoder(connector);
 	if (!encoder)
@@ -1187,8 +1199,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force)
 	if (ret == connector_status_connected)
 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
 	radeon_connector_update_scratch_regs(connector, ret);
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
+
 	return ret;
 }
 
@@ -1251,9 +1267,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status ret = connector_status_disconnected;
 	bool dret = false, broken_edid = false;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	if (radeon_connector->detected_hpd_without_ddc) {
 		force = true;
@@ -1436,8 +1454,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
 	}
 
 exit:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
@@ -1688,9 +1708,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
 	if (radeon_dig_connector->is_mst)
 		return connector_status_disconnected;
 
-	r = pm_runtime_get_sync(connector->dev->dev);
-	if (r < 0)
-		return connector_status_disconnected;
+	if (!drm_kms_helper_is_poll_worker()) {
+		r = pm_runtime_get_sync(connector->dev->dev);
+		if (r < 0)
+			return connector_status_disconnected;
+	}
 
 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
 		ret = connector->status;
@@ -1777,8 +1799,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
 	}
 
 out:
-	pm_runtime_mark_last_busy(connector->dev->dev);
-	pm_runtime_put_autosuspend(connector->dev->dev);
+	if (!drm_kms_helper_is_poll_worker()) {
+		pm_runtime_mark_last_busy(connector->dev->dev);
+		pm_runtime_put_autosuspend(connector->dev->dev);
+	}
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 8d3e3d2e0090..7f40c6f7c4dd 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_cache.h>
 #include <drm/radeon_drm.h>
 #include <linux/pm_runtime.h>
 #include <linux/vgaarb.h>
@@ -1378,6 +1379,7 @@ int radeon_device_init(struct radeon_device *rdev,
 		pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32));
 		pr_warn("radeon: No coherent DMA available\n");
 	}
+	rdev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits);
 
 	/* Registers mapping */
 	/* TODO: block userspace mapping of io register */
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index dfda5e0ed166..26129b2b082d 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -570,7 +570,7 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc,
 		base &= ~7;
 	}
 	work->base = base;
-	work->target_vblank = target - drm_crtc_vblank_count(crtc) +
+	work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
 		dev->driver->get_vblank_counter(dev, work->crtc_id);
 
 	/* We borrow the event spin lock for protecting flip_work */
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index a0a839bc39bf..c1e3862a48a4 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -756,7 +756,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm,
 #endif
 
 #ifdef CONFIG_SWIOTLB
-	if (swiotlb_nr_tbl()) {
+	if (rdev->need_swiotlb && swiotlb_nr_tbl()) {
 		return ttm_dma_populate(&gtt->ttm, rdev->dev, ctx);
 	}
 #endif
@@ -788,7 +788,7 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
 #endif
 
 #ifdef CONFIG_SWIOTLB
-	if (swiotlb_nr_tbl()) {
+	if (rdev->need_swiotlb && swiotlb_nr_tbl()) {
 		ttm_dma_unpopulate(&gtt->ttm, rdev->dev);
 		return;
 	}
@@ -1155,7 +1155,7 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
 	count = ARRAY_SIZE(radeon_ttm_debugfs_list);
 
 #ifdef CONFIG_SWIOTLB
-	if (!swiotlb_nr_tbl())
+	if (!(rdev->need_swiotlb && swiotlb_nr_tbl()))
 		--count;
 #endif
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 4a3d16cf3ed6..5687a94d4cb1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -572,7 +572,7 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane,
 {
 	struct drm_device *dev = plane->dev;
 	struct drm_crtc_state *crtc_state;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 	int ret;
 
 	if (!state->crtc) {
@@ -589,10 +589,9 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane,
 	if (IS_ERR(crtc_state))
 		return PTR_ERR(crtc_state);
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->mode.hdisplay;
-	clip.y2 = crtc_state->mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						  DRM_PLANE_HELPER_NO_SCALING,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index ba7505292b78..7715853ef90a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -253,17 +253,6 @@ static bool is_yuv_support(uint32_t format)
 	}
 }
 
-static bool is_alpha_support(uint32_t format)
-{
-	switch (format) {
-	case DRM_FORMAT_ARGB8888:
-	case DRM_FORMAT_ABGR8888:
-		return true;
-	default:
-		return false;
-	}
-}
-
 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
 				  uint32_t dst, bool is_horizontal,
 				  int vsu_mode, int *vskiplines)
@@ -641,7 +630,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 	struct vop_win *vop_win = to_vop_win(plane);
 	const struct vop_win_data *win = vop_win->data;
 	int ret;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 	int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
 					DRM_PLANE_HELPER_NO_SCALING;
 	int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
@@ -654,10 +643,9 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 	if (WARN_ON(!crtc_state))
 		return -EINVAL;
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						  min_scale, max_scale,
@@ -790,7 +778,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	rb_swap = has_rb_swapped(fb->format->format);
 	VOP_WIN_SET(vop, win, rb_swap, rb_swap);
 
-	if (is_alpha_support(fb->format->format)) {
+	if (fb->format->has_alpha) {
 		VOP_WIN_SET(vop, win, dst_alpha_ctl,
 			    DST_FACTOR_M0(ALPHA_SRC_INVERSE));
 		val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) |
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index 8fe954c27fba..8bc7e8418b8d 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -31,6 +31,24 @@ static const struct drm_mode_config_funcs drv_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
+static int stm_gem_cma_dumb_create(struct drm_file *file,
+				   struct drm_device *dev,
+				   struct drm_mode_create_dumb *args)
+{
+#ifdef CONFIG_MMU
+	unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+	/*
+	 * in order to optimize data transfer, pitch is aligned on
+	 * 128 bytes, height is aligned on 4 bytes
+	 */
+	args->pitch = roundup(min_pitch, 128);
+	args->height = roundup(args->height, 4);
+#endif
+
+	return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
 DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
 
 static struct drm_driver drv_driver = {
@@ -44,7 +62,7 @@ static struct drm_driver drv_driver = {
 	.minor = 0,
 	.patchlevel = 0,
 	.fops = &drv_driver_fops,
-	.dumb_create = drm_gem_cma_dumb_create,
+	.dumb_create = stm_gem_cma_dumb_create,
 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
index fd02506274da..a514b593f37c 100644
--- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
@@ -14,7 +14,14 @@
 #include <drm/bridge/dw_mipi_dsi.h>
 #include <video/mipi_display.h>
 
-/* DSI wrapper register & bit definitions */
+#define HWVER_130			0x31333000	/* IP version 1.30 */
+#define HWVER_131			0x31333100	/* IP version 1.31 */
+
+/* DSI digital registers & bit definitions */
+#define DSI_VERSION			0x00
+#define VERSION				GENMASK(31, 8)
+
+/* DSI wrapper registers & bit definitions */
 /* Note: registers are named as in the Reference Manual */
 #define DSI_WCFGR	0x0400		/* Wrapper ConFiGuration Reg */
 #define WCFGR_DSIM	BIT(0)		/* DSI Mode */
@@ -65,6 +72,10 @@ enum dsi_color {
 struct dw_mipi_dsi_stm {
 	void __iomem *base;
 	struct clk *pllref_clk;
+	struct dw_mipi_dsi *dsi;
+	u32 hw_version;
+	int lane_min_kbps;
+	int lane_max_kbps;
 };
 
 static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val)
@@ -121,7 +132,8 @@ static int dsi_pll_get_clkout_khz(int clkin_khz, int idf, int ndiv, int odf)
 	return DIV_ROUND_CLOSEST(clkin_khz * ndiv, divisor);
 }
 
-static int dsi_pll_get_params(int clkin_khz, int clkout_khz,
+static int dsi_pll_get_params(struct dw_mipi_dsi_stm *dsi,
+			      int clkin_khz, int clkout_khz,
 			      int *idf, int *ndiv, int *odf)
 {
 	int i, o, n, n_min, n_max;
@@ -131,8 +143,8 @@ static int dsi_pll_get_params(int clkin_khz, int clkout_khz,
 	if (clkin_khz <= 0 || clkout_khz <= 0)
 		return -EINVAL;
 
-	fvco_min = LANE_MIN_KBPS * 2 * ODF_MAX;
-	fvco_max = LANE_MAX_KBPS * 2 * ODF_MIN;
+	fvco_min = dsi->lane_min_kbps * 2 * ODF_MAX;
+	fvco_max = dsi->lane_max_kbps * 2 * ODF_MIN;
 
 	best_delta = 1000000; /* big started value (1000000khz) */
 
@@ -212,6 +224,15 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
 	int ret, bpp;
 	u32 val;
 
+	/* Update lane capabilities according to hw version */
+	dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
+	dsi->lane_min_kbps = LANE_MIN_KBPS;
+	dsi->lane_max_kbps = LANE_MAX_KBPS;
+	if (dsi->hw_version == HWVER_131) {
+		dsi->lane_min_kbps *= 2;
+		dsi->lane_max_kbps *= 2;
+	}
+
 	pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000);
 
 	/* Compute requested pll out */
@@ -219,12 +240,12 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
 	pll_out_khz = mode->clock * bpp / lanes;
 	/* Add 20% to pll out to be higher than pixel bw (burst mode only) */
 	pll_out_khz = (pll_out_khz * 12) / 10;
-	if (pll_out_khz > LANE_MAX_KBPS) {
-		pll_out_khz = LANE_MAX_KBPS;
+	if (pll_out_khz > dsi->lane_max_kbps) {
+		pll_out_khz = dsi->lane_max_kbps;
 		DRM_WARN("Warning max phy mbps is used\n");
 	}
-	if (pll_out_khz < LANE_MIN_KBPS) {
-		pll_out_khz = LANE_MIN_KBPS;
+	if (pll_out_khz < dsi->lane_min_kbps) {
+		pll_out_khz = dsi->lane_min_kbps;
 		DRM_WARN("Warning min phy mbps is used\n");
 	}
 
@@ -232,7 +253,8 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
 	idf = 0;
 	ndiv = 0;
 	odf = 0;
-	ret = dsi_pll_get_params(pll_in_khz, pll_out_khz, &idf, &ndiv, &odf);
+	ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz,
+				 &idf, &ndiv, &odf);
 	if (ret)
 		DRM_WARN("Warning dsi_pll_get_params(): bad params\n");
 
@@ -312,21 +334,24 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
 	dw_mipi_dsi_stm_plat_data.base = dsi->base;
 	dw_mipi_dsi_stm_plat_data.priv_data = dsi;
 
-	ret = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data);
-	if (ret) {
+	platform_set_drvdata(pdev, dsi);
+
+	dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data);
+	if (IS_ERR(dsi->dsi)) {
 		DRM_ERROR("Failed to initialize mipi dsi host\n");
 		clk_disable_unprepare(dsi->pllref_clk);
+		return PTR_ERR(dsi->dsi);
 	}
 
-	return ret;
+	return 0;
 }
 
 static int dw_mipi_dsi_stm_remove(struct platform_device *pdev)
 {
-	struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data;
+	struct dw_mipi_dsi_stm *dsi = platform_get_drvdata(pdev);
 
 	clk_disable_unprepare(dsi->pllref_clk);
-	dw_mipi_dsi_remove(pdev);
+	dw_mipi_dsi_remove(dsi->dsi);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 6dc5d4ec4e17..1a3277e483d5 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -175,6 +175,8 @@
 
 #define LXCFBLNR_CFBLN	GENMASK(10, 0)	/* Color Frame Buffer Line Number */
 
+#define CLUT_SIZE	256
+
 #define CONSTA_MAX	0xFF		/* CONSTant Alpha MAX= 1.0 */
 #define BF1_PAXCA	0x600		/* Pixel Alpha x Constant Alpha */
 #define BF1_CA		0x400		/* Constant Alpha */
@@ -326,6 +328,26 @@ static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf)
 	}
 }
 
+static inline u32 get_pixelformat_without_alpha(u32 drm)
+{
+	switch (drm) {
+	case DRM_FORMAT_ARGB4444:
+		return DRM_FORMAT_XRGB4444;
+	case DRM_FORMAT_RGBA4444:
+		return DRM_FORMAT_RGBX4444;
+	case DRM_FORMAT_ARGB1555:
+		return DRM_FORMAT_XRGB1555;
+	case DRM_FORMAT_RGBA5551:
+		return DRM_FORMAT_RGBX5551;
+	case DRM_FORMAT_ARGB8888:
+		return DRM_FORMAT_XRGB8888;
+	case DRM_FORMAT_RGBA8888:
+		return DRM_FORMAT_RGBX8888;
+	default:
+		return 0;
+	}
+}
+
 static irqreturn_t ltdc_irq_thread(int irq, void *arg)
 {
 	struct drm_device *ddev = arg;
@@ -363,6 +385,28 @@ static irqreturn_t ltdc_irq(int irq, void *arg)
  * DRM_CRTC
  */
 
+static void ltdc_crtc_update_clut(struct drm_crtc *crtc)
+{
+	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
+	struct drm_color_lut *lut;
+	u32 val;
+	int i;
+
+	if (!crtc || !crtc->state)
+		return;
+
+	if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
+		return;
+
+	lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
+
+	for (i = 0; i < CLUT_SIZE; i++, lut++) {
+		val = ((lut->red << 8) & 0xff0000) | (lut->green & 0xff00) |
+			(lut->blue >> 8) | (i << 24);
+		reg_write(ldev->regs, LTDC_L1CLUTWR, val);
+	}
+}
+
 static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
@@ -404,12 +448,35 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc,
 	reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR);
 }
 
+static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
+	int rate = mode->clock * 1000;
+
+	/*
+	 * TODO clk_round_rate() does not work yet. When ready, it can
+	 * be used instead of clk_set_rate() then clk_get_rate().
+	 */
+
+	clk_disable(ldev->pixel_clk);
+	if (clk_set_rate(ldev->pixel_clk, rate) < 0) {
+		DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate);
+		return false;
+	}
+	clk_enable(ldev->pixel_clk);
+
+	adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000;
+
+	return true;
+}
+
 static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
 	struct ltdc_device *ldev = crtc_to_ltdc(crtc);
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 	struct videomode vm;
-	int rate = mode->clock * 1000;
 	u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h;
 	u32 total_width, total_height;
 	u32 val;
@@ -432,15 +499,6 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
 	total_width = accum_act_w + vm.hfront_porch;
 	total_height = accum_act_h + vm.vfront_porch;
 
-	clk_disable(ldev->pixel_clk);
-
-	if (clk_set_rate(ldev->pixel_clk, rate) < 0) {
-		DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate);
-		return;
-	}
-
-	clk_enable(ldev->pixel_clk);
-
 	/* Configures the HS, VS, DE and PC polarities. Default Active Low */
 	val = 0;
 
@@ -486,6 +544,8 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
 
 	DRM_DEBUG_ATOMIC("\n");
 
+	ltdc_crtc_update_clut(crtc);
+
 	/* Commit shadow registers = update planes at next vblank */
 	reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR);
 
@@ -502,6 +562,7 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
+	.mode_fixup = ltdc_crtc_mode_fixup,
 	.mode_set_nofb = ltdc_crtc_mode_set_nofb,
 	.atomic_flush = ltdc_crtc_atomic_flush,
 	.atomic_enable = ltdc_crtc_atomic_enable,
@@ -533,6 +594,7 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
 	.reset = drm_atomic_helper_crtc_reset,
 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.gamma_set = drm_atomic_helper_legacy_gamma_set,
 };
 
 /*
@@ -638,6 +700,14 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
 
 	/* Specifies the blending factors */
 	val = BF1_PAXCA | BF2_1PAXCA;
+	if (!fb->format->has_alpha)
+		val = BF1_CA | BF2_1CA;
+
+	/* Manage hw-specific capabilities */
+	if (ldev->caps.non_alpha_only_l1 &&
+	    plane->type != DRM_PLANE_TYPE_PRIMARY)
+		val = BF1_PAXCA | BF2_1PAXCA;
+
 	reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs,
 			LXBFCR_BF2 | LXBFCR_BF1, val);
 
@@ -705,8 +775,8 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
 	struct device *dev = ddev->dev;
 	struct drm_plane *plane;
 	unsigned int i, nb_fmt = 0;
-	u32 formats[NB_PF];
-	u32 drm_fmt;
+	u32 formats[NB_PF * 2];
+	u32 drm_fmt, drm_fmt_no_alpha;
 	int ret;
 
 	/* Get supported pixel formats */
@@ -715,6 +785,18 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
 		if (!drm_fmt)
 			continue;
 		formats[nb_fmt++] = drm_fmt;
+
+		/* Add the no-alpha related format if any & supported */
+		drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt);
+		if (!drm_fmt_no_alpha)
+			continue;
+
+		/* Manage hw-specific capabilities */
+		if (ldev->caps.non_alpha_only_l1 &&
+		    type != DRM_PLANE_TYPE_PRIMARY)
+			continue;
+
+		formats[nb_fmt++] = drm_fmt_no_alpha;
 	}
 
 	plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
@@ -765,6 +847,9 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
 
 	drm_crtc_helper_add(crtc, &ltdc_crtc_helper_funcs);
 
+	drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE);
+	drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE);
+
 	DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id);
 
 	/* Add planes. Note : the first layer is used by primary plane */
@@ -839,10 +924,19 @@ static int ltdc_get_caps(struct drm_device *ddev)
 	case HWVER_10300:
 		ldev->caps.reg_ofs = REG_OFS_NONE;
 		ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0;
+		/*
+		 * Hw older versions support non-alpha color formats derived
+		 * from native alpha color formats only on the primary layer.
+		 * For instance, RG16 native format without alpha works fine
+		 * on 2nd layer but XR24 (derived color format from AR24)
+		 * does not work on 2nd layer.
+		 */
+		ldev->caps.non_alpha_only_l1 = true;
 		break;
 	case HWVER_20101:
 		ldev->caps.reg_ofs = REG_OFS_4;
 		ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1;
+		ldev->caps.non_alpha_only_l1 = false;
 		break;
 	default:
 		return -ENODEV;
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index edd1c0a446d1..edb268129c54 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -17,6 +17,7 @@ struct ltdc_caps {
 	u32 reg_ofs;		/* register offset for applicable regs */
 	u32 bus_width;		/* bus width (32 or 64 bits) */
 	const u32 *pix_fmt_hw;	/* supported pixel formats */
+	bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */
 };
 
 struct ltdc_device {
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 2b37a6abbb1d..582607c0c488 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 sun4i-backend-y			+= sun4i_backend.o sun4i_layer.o
+sun4i-frontend-y		+= sun4i_frontend.o
 
 sun4i-drm-y			+= sun4i_drv.o
 sun4i-drm-y			+= sun4i_framebuffer.o
@@ -24,6 +25,6 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 
-obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o sun4i-frontend.o
 obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
 obj-$(CONFIG_DRM_SUN8I_MIXER)	+= sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 847eecbe4d14..245b189fc4d8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -11,6 +11,7 @@
  */
 
 #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>
@@ -26,6 +27,7 @@
 
 #include "sun4i_backend.h"
 #include "sun4i_drv.h"
+#include "sun4i_frontend.h"
 #include "sun4i_layer.h"
 #include "sunxi_engine.h"
 
@@ -93,7 +95,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
 					     u32 format, u32 *mode)
 {
-	if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
+	if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
 	    (format == DRM_FORMAT_ARGB8888))
 		format = DRM_FORMAT_XRGB8888;
 
@@ -141,7 +143,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 				     int layer, struct drm_plane *plane)
 {
 	struct drm_plane_state *state = plane->state;
-	struct drm_framebuffer *fb = state->fb;
 
 	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
 
@@ -153,12 +154,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 						   state->crtc_h));
 	}
 
-	/* Set the line width */
-	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
-	regmap_write(backend->engine.regs,
-		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
-		     fb->pitches[0] * 8);
-
 	/* Set height and width */
 	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
 			 state->crtc_w, state->crtc_h);
@@ -210,6 +205,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 	return 0;
 }
 
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+					int layer, uint32_t fmt)
+{
+	u32 val;
+	int ret;
+
+	ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid format\n");
+		return ret;
+	}
+
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG0(layer),
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
+
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG1(layer),
+			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
+
+	return 0;
+}
+
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane)
 {
@@ -218,6 +237,12 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	u32 lo_paddr, hi_paddr;
 	dma_addr_t paddr;
 
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
+	regmap_write(backend->engine.regs,
+		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
+		     fb->pitches[0] * 8);
+
 	/* Get the start of the displayed memory */
 	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
 	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
@@ -246,6 +271,176 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	return 0;
 }
 
+int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,
+				    struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	unsigned int priority = state->normalized_zpos;
+
+	DRM_DEBUG_DRIVER("Setting layer %d's priority to %d\n", layer, priority);
+
+	regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK,
+			   SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(priority));
+
+	return 0;
+}
+
+static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
+{
+	u16 src_h = state->src_h >> 16;
+	u16 src_w = state->src_w >> 16;
+
+	DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
+			 src_w, src_h, state->crtc_w, state->crtc_h);
+
+	if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
+		return true;
+
+	return false;
+}
+
+static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
+	struct sun4i_backend *backend = layer->backend;
+
+	if (IS_ERR(backend->frontend))
+		return false;
+
+	return sun4i_backend_plane_uses_scaler(state);
+}
+
+static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
+				       struct drm_crtc_state *old_state)
+{
+	u32 val;
+
+	WARN_ON(regmap_read_poll_timeout(engine->regs,
+					 SUN4I_BACKEND_REGBUFFCTL_REG,
+					 val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL),
+					 100, 50000));
+}
+
+static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
+				      struct drm_crtc_state *crtc_state)
+{
+	struct drm_atomic_state *state = crtc_state->state;
+	struct drm_device *drm = state->dev;
+	struct drm_plane *plane;
+	unsigned int num_planes = 0;
+	unsigned int num_alpha_planes = 0;
+	unsigned int num_frontend_planes = 0;
+
+	DRM_DEBUG_DRIVER("Starting checking our planes\n");
+
+	if (!crtc_state->planes_changed)
+		return 0;
+
+	drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
+		struct drm_plane_state *plane_state =
+			drm_atomic_get_plane_state(state, plane);
+		struct sun4i_layer_state *layer_state =
+			state_to_sun4i_layer_state(plane_state);
+		struct drm_framebuffer *fb = plane_state->fb;
+		struct drm_format_name_buf format_name;
+
+		if (sun4i_backend_plane_uses_frontend(plane_state)) {
+			DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
+					 plane->index);
+
+			layer_state->uses_frontend = true;
+			num_frontend_planes++;
+		} else {
+			layer_state->uses_frontend = false;
+		}
+
+		DRM_DEBUG_DRIVER("Plane FB format is %s\n",
+				 drm_get_format_name(fb->format->format,
+						     &format_name));
+		if (fb->format->has_alpha)
+			num_alpha_planes++;
+
+		num_planes++;
+	}
+
+	/*
+	 * The hardware is a bit unusual here.
+	 *
+	 * Even though it supports 4 layers, it does the composition
+	 * in two separate steps.
+	 *
+	 * The first one is assigning a layer to one of its two
+	 * pipes. If more that 1 layer is assigned to the same pipe,
+	 * and if pixels overlaps, the pipe will take the pixel from
+	 * the layer with the highest priority.
+	 *
+	 * The second step is the actual alpha blending, that takes
+	 * the two pipes as input, and uses the eventual alpha
+	 * component to do the transparency between the two.
+	 *
+	 * This two steps scenario makes us unable to guarantee a
+	 * robust alpha blending between the 4 layers in all
+	 * situations, since this means that we need to have one layer
+	 * with alpha at the lowest position of our two pipes.
+	 *
+	 * However, we cannot even do that, since the hardware has a
+	 * bug where the lowest plane of the lowest pipe (pipe 0,
+	 * priority 0), if it has any alpha, will discard the pixel
+	 * entirely and just display the pixels in the background
+	 * color (black by default).
+	 *
+	 * This means that we effectively have only three valid
+	 * configurations with alpha, all of them with the alpha being
+	 * on pipe1 with the lowest position, which can be 1, 2 or 3
+	 * depending on the number of planes and their zpos.
+	 */
+	if (num_alpha_planes > SUN4I_BACKEND_NUM_ALPHA_LAYERS) {
+		DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n");
+		return -EINVAL;
+	}
+
+	if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
+		DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n",
+			 num_planes, num_alpha_planes, num_frontend_planes);
+
+	return 0;
+}
+
+static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
+{
+	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (!frontend)
+		return;
+
+	/*
+	 * In a teardown scenario with the frontend involved, we have
+	 * to keep the frontend enabled until the next vblank, and
+	 * only then disable it.
+	 *
+	 * This is due to the fact that the backend will not take into
+	 * account the new configuration (with the plane that used to
+	 * be fed by the frontend now disabled) until we write to the
+	 * commit bit and the hardware fetches the new configuration
+	 * during the next vblank.
+	 *
+	 * So we keep the frontend around in order to prevent any
+	 * visual artifacts.
+	 */
+	spin_lock(&backend->frontend_lock);
+	if (backend->frontend_teardown) {
+		sun4i_frontend_exit(frontend);
+		backend->frontend_teardown = false;
+	}
+	spin_unlock(&backend->frontend_lock);
+};
+
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 	int ret;
@@ -330,11 +525,43 @@ static int sun4i_backend_of_get_id(struct device_node *node)
 	return ret;
 }
 
+/* TODO: This needs to take multiple pipelines into account */
+static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
+							  struct device_node *node)
+{
+	struct device_node *port, *ep, *remote;
+	struct sun4i_frontend *frontend;
+
+	port = of_graph_get_port_by_id(node, 0);
+	if (!port)
+		return ERR_PTR(-EINVAL);
+
+	for_each_available_child_of_node(port, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote)
+			continue;
+
+		/* does this node match any registered engines? */
+		list_for_each_entry(frontend, &drv->frontend_list, list) {
+			if (remote == frontend->node) {
+				of_node_put(remote);
+				of_node_put(port);
+				return frontend;
+			}
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
 static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.atomic_begin			= sun4i_backend_atomic_begin,
+	.atomic_check			= sun4i_backend_atomic_check,
 	.commit				= sun4i_backend_commit,
 	.layers_init			= sun4i_layers_init,
 	.apply_color_correction		= sun4i_backend_apply_color_correction,
 	.disable_color_correction	= sun4i_backend_disable_color_correction,
+	.vblank_quirk			= sun4i_backend_vblank_quirk,
 };
 
 static struct regmap_config sun4i_backend_regmap_config = {
@@ -360,6 +587,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (!backend)
 		return -ENOMEM;
 	dev_set_drvdata(dev, backend);
+	spin_lock_init(&backend->frontend_lock);
 
 	backend->engine.node = dev->of_node;
 	backend->engine.ops = &sun4i_backend_engine_ops;
@@ -367,6 +595,10 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (backend->engine.id < 0)
 		return backend->engine.id;
 
+	backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
+	if (IS_ERR(backend->frontend))
+		dev_warn(dev, "Couldn't find matching frontend, frontend features disabled\n");
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(dev, res);
 	if (IS_ERR(regs))
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index ac3cc029f5cd..52e77591186a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -72,6 +72,7 @@
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
 #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN		BIT(1)
 
 #define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
 #define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
@@ -111,7 +112,9 @@
 #define SUN4I_BACKEND_SPRALPHACTL_REG		0x90c
 #define SUN4I_BACKEND_IYUVCTL_REG		0x920
 #define SUN4I_BACKEND_IYUVADD_REG(c)		(0x930 + (0x4 * (c)))
-#define SUN4I_BACKEND_IYUVLINEWITDTH_REG(c)	(0x940 + (0x4 * (c)))
+
+#define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c)	(0x940 + (0x4 * (c)))
+
 #define SUN4I_BACKEND_YGCOEF_REG(c)		(0x950 + (0x4 * (c)))
 #define SUN4I_BACKEND_YGCONS_REG		0x95c
 #define SUN4I_BACKEND_URCOEF_REG(c)		(0x960 + (0x4 * (c)))
@@ -143,8 +146,13 @@
 #define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
 #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
 
+#define SUN4I_BACKEND_NUM_LAYERS		4
+#define SUN4I_BACKEND_NUM_ALPHA_LAYERS		1
+#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS	1
+
 struct sun4i_backend {
 	struct sunxi_engine	engine;
+	struct sun4i_frontend	*frontend;
 
 	struct reset_control	*reset;
 
@@ -154,6 +162,10 @@ struct sun4i_backend {
 
 	struct clk		*sat_clk;
 	struct reset_control	*sat_reset;
+
+	/* Protects against races in the frontend teardown */
+	spinlock_t		frontend_lock;
+	bool			frontend_teardown;
 };
 
 static inline struct sun4i_backend *
@@ -170,5 +182,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 				       int layer, struct drm_plane *plane);
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane);
+int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
+					int layer, uint32_t in_fmt);
+int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend,
+				    int layer, struct drm_plane *plane);
 
 #endif /* _SUN4I_BACKEND_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 5decae0069d0..3b2d11b675e8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -25,6 +25,7 @@
 
 #include <video/videomode.h>
 
+#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sunxi_engine.h"
@@ -46,11 +47,25 @@ static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
 	return NULL;
 }
 
+static int sun4i_crtc_atomic_check(struct drm_crtc *crtc,
+				    struct drm_crtc_state *state)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sunxi_engine *engine = scrtc->engine;
+	int ret = 0;
+
+	if (engine && engine->ops && engine->ops->atomic_check)
+		ret = engine->ops->atomic_check(engine, state);
+
+	return ret;
+}
+
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned long flags;
 
 	if (crtc->state->event) {
@@ -60,7 +75,10 @@ static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 		scrtc->event = crtc->state->event;
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 		crtc->state->event = NULL;
-	 }
+	}
+
+	if (engine->ops->atomic_begin)
+		engine->ops->atomic_begin(engine, old_state);
 }
 
 static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
@@ -125,6 +143,7 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
 }
 
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+	.atomic_check	= sun4i_crtc_atomic_check,
 	.atomic_begin	= sun4i_crtc_atomic_begin,
 	.atomic_flush	= sun4i_crtc_atomic_flush,
 	.atomic_enable	= sun4i_crtc_atomic_enable,
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 4570da0227b4..3957c2ff6870 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -23,6 +23,7 @@
 #include <drm/drm_of.h>
 
 #include "sun4i_drv.h"
+#include "sun4i_frontend.h"
 #include "sun4i_framebuffer.h"
 #include "sun4i_tcon.h"
 
@@ -91,6 +92,7 @@ static int sun4i_drv_bind(struct device *dev)
 		goto free_drm;
 	}
 	drm->dev_private = drv;
+	INIT_LIST_HEAD(&drv->frontend_list);
 	INIT_LIST_HEAD(&drv->engine_list);
 	INIT_LIST_HEAD(&drv->tcon_list);
 
@@ -177,6 +179,14 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node)
 		of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");
 }
 
+static bool sun4i_drv_node_is_supported_frontend(struct device_node *node)
+{
+	if (IS_ENABLED(CONFIG_DRM_SUN4I_BACKEND))
+		return !!of_match_node(sun4i_frontend_of_table, node);
+
+	return false;
+}
+
 static bool sun4i_drv_node_is_tcon(struct device_node *node)
 {
 	return !!of_match_node(sun4i_tcon_of_table, node);
@@ -225,9 +235,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	int count = 0;
 
 	/*
-	 * We don't support the frontend for now, so we will never
-	 * have a device bound. Just skip over it, but we still want
-	 * the rest our pipeline to be added.
+	 * The frontend has been disabled in some of our old device
+	 * trees. If we find a node that is the frontend and is
+	 * disabled, we should just follow through and parse its
+	 * child, but without adding it to the component list.
+	 * Otherwise, we obviously want to add it to the list.
 	 */
 	if (!sun4i_drv_node_is_frontend(node) &&
 	    !of_device_is_available(node))
@@ -240,7 +252,14 @@ static int sun4i_drv_add_endpoints(struct device *dev,
 	if (sun4i_drv_node_is_connector(node))
 		return 0;
 
-	if (!sun4i_drv_node_is_frontend(node)) {
+	/*
+	 * If the device is either just a regular device, or an
+	 * enabled frontend supported by the driver, we add it to our
+	 * component list.
+	 */
+	if (!sun4i_drv_node_is_frontend(node) ||
+	    (sun4i_drv_node_is_supported_frontend(node) &&
+	     of_device_is_available(node))) {
 		/* Add current component */
 		DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
 		drm_of_component_match_add(dev, match, compare_of, node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index 2825f140da54..5750b8ce8b31 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -19,6 +19,7 @@
 
 struct sun4i_drv {
 	struct list_head	engine_list;
+	struct list_head	frontend_list;
 	struct list_head	tcon_list;
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 38a36c0dfa2f..5f29850ef8ac 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -10,6 +10,7 @@
  * the License, or (at your option) any later version.
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
@@ -19,13 +20,33 @@
 #include "sun4i_drv.h"
 #include "sun4i_framebuffer.h"
 
+static int sun4i_de_atomic_check(struct drm_device *dev,
+				 struct drm_atomic_state *state)
+{
+	int ret;
+
+	ret = drm_atomic_helper_check_modeset(dev, state);
+	if (ret)
+		return ret;
+
+	ret = drm_atomic_normalize_zpos(dev, state);
+	if (ret)
+		return ret;
+
+	return drm_atomic_helper_check_planes(dev, state);
+}
+
 static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
 	.output_poll_changed	= drm_fb_helper_output_poll_changed,
-	.atomic_check		= drm_atomic_helper_check,
+	.atomic_check		= sun4i_de_atomic_check,
 	.atomic_commit		= drm_atomic_helper_commit,
 	.fb_create		= drm_gem_fb_create,
 };
 
+static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
+	.atomic_commit_tail	= drm_atomic_helper_commit_tail_rpm,
+};
+
 int sun4i_framebuffer_init(struct drm_device *drm)
 {
 	drm_mode_config_reset(drm);
@@ -34,6 +55,7 @@ int sun4i_framebuffer_init(struct drm_device *drm)
 	drm->mode_config.max_height = 8192;
 
 	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
+	drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
 
 	return drm_fb_cma_fbdev_init(drm, 32, 0);
 }
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
new file mode 100644
index 000000000000..ddf6cfa6dd23
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_frontend.h"
+
+static const u32 sun4i_frontend_vert_coef[32] = {
+	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+	0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+	0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+	0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+	0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+};
+
+static const u32 sun4i_frontend_horz_coef[64] = {
+	0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
+	0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
+	0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
+	0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
+	0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
+	0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
+	0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
+	0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
+	0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
+	0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
+	0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
+	0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
+	0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
+	0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
+	0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
+	0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
+};
+
+static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
+			     sun4i_frontend_horz_coef[2 * i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
+			     sun4i_frontend_horz_coef[2 * i + 1]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+		regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
+			     sun4i_frontend_vert_coef[i]);
+	}
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			   SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL,
+			   SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL);
+}
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend)
+{
+	return pm_runtime_get_sync(frontend->dev);
+}
+EXPORT_SYMBOL(sun4i_frontend_init);
+
+void sun4i_frontend_exit(struct sun4i_frontend *frontend)
+{
+	pm_runtime_put(frontend->dev);
+}
+EXPORT_SYMBOL(sun4i_frontend_exit);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	dma_addr_t paddr;
+
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
+		     fb->pitches[0]);
+
+	/* Set the physical address of the buffer in memory */
+	paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
+	paddr -= PHYS_OFFSET;
+	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_buffer);
+
+static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_ARGB8888:
+		*val = 5;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
+{
+	switch (fmt) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		*val = 2;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	u32 out_fmt_val;
+	u32 in_fmt_val;
+	int ret;
+
+	ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
+						     &in_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid input format\n");
+		return ret;
+	}
+
+	ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid output format\n");
+		return ret;
+	}
+
+	/*
+	 * I have no idea what this does exactly, but it seems to be
+	 * related to the scaler FIR filter phase parameters.
+	 */
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
+		     SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) |
+		     SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) |
+		     SUN4I_FRONTEND_INPUT_FMT_PS(1));
+
+	/*
+	 * TODO: It look like the A31 and A80 at least will need the
+	 * bit 7 (ALPHA_EN) enabled when using a format with alpha (so
+	 * ARGB8888).
+	 */
+	regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
+		     SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val));
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_update_formats);
+
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+
+	/* Set height and width */
+	DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
+			 state->crtc_w, state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
+		     SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
+					   state->src_w >> 16));
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
+		     SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
+		     state->src_w / state->crtc_w);
+
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+	regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
+		     state->src_h / state->crtc_h);
+
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
+			  SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
+}
+EXPORT_SYMBOL(sun4i_frontend_update_coord);
+
+int sun4i_frontend_enable(struct sun4i_frontend *frontend)
+{
+	regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START,
+			  SUN4I_FRONTEND_FRM_CTRL_FRM_START);
+
+	return 0;
+}
+EXPORT_SYMBOL(sun4i_frontend_enable);
+
+static struct regmap_config sun4i_frontend_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x0a14,
+};
+
+static int sun4i_frontend_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sun4i_frontend *frontend;
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct resource *res;
+	void __iomem *regs;
+
+	frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
+	if (!frontend)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, frontend);
+	frontend->dev = dev;
+	frontend->node = dev->of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	frontend->regs = devm_regmap_init_mmio(dev, regs,
+					       &sun4i_frontend_regmap_config);
+	if (IS_ERR(frontend->regs)) {
+		dev_err(dev, "Couldn't create the frontend regmap\n");
+		return PTR_ERR(frontend->regs);
+	}
+
+	frontend->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(frontend->reset)) {
+		dev_err(dev, "Couldn't get our reset line\n");
+		return PTR_ERR(frontend->reset);
+	}
+
+	frontend->bus_clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(frontend->bus_clk)) {
+		dev_err(dev, "Couldn't get our bus clock\n");
+		return PTR_ERR(frontend->bus_clk);
+	}
+
+	frontend->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(frontend->mod_clk)) {
+		dev_err(dev, "Couldn't get our mod clock\n");
+		return PTR_ERR(frontend->mod_clk);
+	}
+
+	frontend->ram_clk = devm_clk_get(dev, "ram");
+	if (IS_ERR(frontend->ram_clk)) {
+		dev_err(dev, "Couldn't get our ram clock\n");
+		return PTR_ERR(frontend->ram_clk);
+	}
+
+	list_add_tail(&frontend->list, &drv->frontend_list);
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static void sun4i_frontend_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	list_del(&frontend->list);
+	pm_runtime_force_suspend(dev);
+}
+
+static const struct component_ops sun4i_frontend_ops = {
+	.bind	= sun4i_frontend_bind,
+	.unbind	= sun4i_frontend_unbind,
+};
+
+static int sun4i_frontend_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_frontend_ops);
+}
+
+static int sun4i_frontend_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_frontend_ops);
+
+	return 0;
+}
+
+static int sun4i_frontend_runtime_resume(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+	int ret;
+
+	clk_set_rate(frontend->mod_clk, 300000000);
+
+	clk_prepare_enable(frontend->bus_clk);
+	clk_prepare_enable(frontend->mod_clk);
+	clk_prepare_enable(frontend->ram_clk);
+
+	ret = reset_control_reset(frontend->reset);
+	if (ret) {
+		dev_err(dev, "Couldn't reset our device\n");
+		return ret;
+	}
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
+			   SUN4I_FRONTEND_EN_EN,
+			   SUN4I_FRONTEND_EN_EN);
+
+	regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN,
+			   SUN4I_FRONTEND_BYPASS_CSC_EN);
+
+	sun4i_frontend_scaler_init(frontend);
+
+	return 0;
+}
+
+static int sun4i_frontend_runtime_suspend(struct device *dev)
+{
+	struct sun4i_frontend *frontend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(frontend->ram_clk);
+	clk_disable_unprepare(frontend->mod_clk);
+	clk_disable_unprepare(frontend->bus_clk);
+
+	reset_control_assert(frontend->reset);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sun4i_frontend_pm_ops = {
+	.runtime_resume		= sun4i_frontend_runtime_resume,
+	.runtime_suspend	= sun4i_frontend_runtime_suspend,
+};
+
+const struct of_device_id sun4i_frontend_of_table[] = {
+	{ .compatible = "allwinner,sun8i-a33-display-frontend" },
+	{ }
+};
+EXPORT_SYMBOL(sun4i_frontend_of_table);
+MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
+
+static struct platform_driver sun4i_frontend_driver = {
+	.probe		= sun4i_frontend_probe,
+	.remove		= sun4i_frontend_remove,
+	.driver		= {
+		.name		= "sun4i-frontend",
+		.of_match_table	= sun4i_frontend_of_table,
+		.pm		= &sun4i_frontend_pm_ops,
+	},
+};
+module_platform_driver(sun4i_frontend_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
new file mode 100644
index 000000000000..02661ce81f3e
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ */
+
+#ifndef _SUN4I_FRONTEND_H_
+#define _SUN4I_FRONTEND_H_
+
+#include <linux/list.h>
+
+#define SUN4I_FRONTEND_EN_REG			0x000
+#define SUN4I_FRONTEND_EN_EN				BIT(0)
+
+#define SUN4I_FRONTEND_FRM_CTRL_REG		0x004
+#define SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL	BIT(23)
+#define SUN4I_FRONTEND_FRM_CTRL_FRM_START		BIT(16)
+#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY		BIT(1)
+#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY			BIT(0)
+
+#define SUN4I_FRONTEND_BYPASS_REG		0x008
+#define SUN4I_FRONTEND_BYPASS_CSC_EN			BIT(1)
+
+#define SUN4I_FRONTEND_BUF_ADDR0_REG		0x020
+
+#define SUN4I_FRONTEND_LINESTRD0_REG		0x040
+
+#define SUN4I_FRONTEND_INPUT_FMT_REG		0x04c
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod)		((mod) << 8)
+#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt)		((fmt) << 4)
+#define SUN4I_FRONTEND_INPUT_FMT_PS(ps)			(ps)
+
+#define SUN4I_FRONTEND_OUTPUT_FMT_REG		0x05c
+#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt)		(fmt)
+
+#define SUN4I_FRONTEND_CH0_INSIZE_REG		0x100
+#define SUN4I_FRONTEND_INSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_OUTSIZE_REG		0x104
+#define SUN4I_FRONTEND_OUTSIZE(h, w)			((((h) - 1) << 16) | (((w) - 1)))
+
+#define SUN4I_FRONTEND_CH0_HORZFACT_REG		0x108
+#define SUN4I_FRONTEND_HORZFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_VERTFACT_REG		0x10c
+#define SUN4I_FRONTEND_VERTFACT(i, f)			(((i) << 16) | (f))
+
+#define SUN4I_FRONTEND_CH0_HORZPHASE_REG	0x110
+#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG	0x114
+#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG	0x118
+
+#define SUN4I_FRONTEND_CH1_INSIZE_REG		0x200
+#define SUN4I_FRONTEND_CH1_OUTSIZE_REG		0x204
+#define SUN4I_FRONTEND_CH1_HORZFACT_REG		0x208
+#define SUN4I_FRONTEND_CH1_VERTFACT_REG		0x20c
+
+#define SUN4I_FRONTEND_CH1_HORZPHASE_REG	0x210
+#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG	0x214
+#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG	0x218
+
+#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i)	(0x400 + i * 4)
+#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i)	(0x480 + i * 4)
+#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i)	(0x500 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i)	(0x600 + i * 4)
+#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i)	(0x680 + i * 4)
+#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i)	(0x700 + i * 4)
+
+struct clk;
+struct device_node;
+struct drm_plane;
+struct regmap;
+struct reset_control;
+
+struct sun4i_frontend {
+	struct list_head	list;
+	struct device		*dev;
+	struct device_node	*node;
+
+	struct clk		*bus_clk;
+	struct clk		*mod_clk;
+	struct clk		*ram_clk;
+	struct regmap		*regs;
+	struct reset_control	*reset;
+};
+
+extern const struct of_device_id sun4i_frontend_of_table[];
+
+int sun4i_frontend_init(struct sun4i_frontend *frontend);
+void sun4i_frontend_exit(struct sun4i_frontend *frontend);
+int sun4i_frontend_enable(struct sun4i_frontend *frontend);
+
+void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane);
+void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
+				 struct drm_plane *plane);
+int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
+				  struct drm_plane *plane, uint32_t out_fmt);
+
+#endif /* _SUN4I_FRONTEND_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..19be798e4fac 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -15,34 +15,107 @@
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
+#include "sun4i_frontend.h"
 #include "sun4i_layer.h"
 #include "sunxi_engine.h"
 
 struct sun4i_plane_desc {
-	       enum drm_plane_type     type;
-	       u8                      pipe;
-	       const uint32_t          *formats;
-	       uint32_t                nformats;
+	enum drm_plane_type     type;
+	u8                      pipe;
+	const uint32_t          *formats;
+	uint32_t                nformats;
 };
 
+static void sun4i_backend_layer_reset(struct drm_plane *plane)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
+	struct sun4i_layer_state *state;
+
+	if (plane->state) {
+		state = state_to_sun4i_layer_state(plane->state);
+
+		__drm_atomic_helper_plane_destroy_state(&state->state);
+
+		kfree(state);
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		plane->state = &state->state;
+		plane->state->plane = plane;
+		plane->state->zpos = layer->id;
+	}
+}
+
+static struct drm_plane_state *
+sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
+{
+	struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
+	struct sun4i_layer_state *copy;
+
+	copy = kzalloc(sizeof(*copy), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
+	copy->uses_frontend = orig->uses_frontend;
+
+	return &copy->state;
+}
+
+static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
+					      struct drm_plane_state *state)
+{
+	struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+
+	kfree(s_state);
+}
+
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
+	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
 	struct sun4i_backend *backend = layer->backend;
 
 	sun4i_backend_layer_enable(backend, layer->id, false);
+
+	if (layer_state->uses_frontend) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&backend->frontend_lock, flags);
+		backend->frontend_teardown = true;
+		spin_unlock_irqrestore(&backend->frontend_lock, flags);
+	}
 }
 
 static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
 					      struct drm_plane_state *old_state)
 {
+	struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
 	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
 	struct sun4i_backend *backend = layer->backend;
+	struct sun4i_frontend *frontend = backend->frontend;
+
+	if (layer_state->uses_frontend) {
+		sun4i_frontend_init(frontend);
+		sun4i_frontend_update_coord(frontend, plane);
+		sun4i_frontend_update_buffer(frontend, plane);
+		sun4i_frontend_update_formats(frontend, plane,
+					      DRM_FORMAT_ARGB8888);
+		sun4i_backend_update_layer_frontend(backend, layer->id,
+						    DRM_FORMAT_ARGB8888);
+		sun4i_frontend_enable(frontend);
+	} else {
+		sun4i_backend_update_layer_formats(backend, layer->id, plane);
+		sun4i_backend_update_layer_buffer(backend, layer->id, plane);
+	}
 
 	sun4i_backend_update_layer_coord(backend, layer->id, plane);
-	sun4i_backend_update_layer_formats(backend, layer->id, plane);
-	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
+	sun4i_backend_update_layer_zpos(backend, layer->id, plane);
 	sun4i_backend_layer_enable(backend, layer->id, true);
 }
 
@@ -52,11 +125,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
 };
 
 static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
-	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
-	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state	= sun4i_backend_layer_destroy_state,
+	.atomic_duplicate_state	= sun4i_backend_layer_duplicate_state,
 	.destroy		= drm_plane_cleanup,
 	.disable_plane		= drm_atomic_helper_disable_plane,
-	.reset			= drm_atomic_helper_plane_reset,
+	.reset			= sun4i_backend_layer_reset,
 	.update_plane		= drm_atomic_helper_update_plane,
 };
 
@@ -128,32 +201,12 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
 	int i;
 
-	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
+	/* We need to have a sentinel at the need, hence the overallocation */
+	planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1,
 			      sizeof(*planes), GFP_KERNEL);
 	if (!planes)
 		return ERR_PTR(-ENOMEM);
 
-	/*
-	 * The hardware is a bit unusual here.
-	 *
-	 * Even though it supports 4 layers, it does the composition
-	 * in two separate steps.
-	 *
-	 * The first one is assigning a layer to one of its two
-	 * pipes. If more that 1 layer is assigned to the same pipe,
-	 * and if pixels overlaps, the pipe will take the pixel from
-	 * the layer with the highest priority.
-	 *
-	 * The second step is the actual alpha blending, that takes
-	 * the two pipes as input, and uses the eventual alpha
-	 * component to do the transparency between the two.
-	 *
-	 * This two steps scenario makes us unable to guarantee a
-	 * robust alpha blending between the 4 layers in all
-	 * situations. So we just expose two layers, one per pipe. On
-	 * SoCs that support it, sprites could fill the need for more
-	 * layers.
-	 */
 	for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
 		const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
 		struct sun4i_layer *layer;
@@ -165,6 +218,8 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 			return ERR_CAST(layer);
 		};
 
+		drm_plane_create_zpos_immutable_property(&layer->plane, i);
+
 		DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
 				 i ? "overlay" : "primary", plane->pipe);
 		regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 4e84f438b346..75b4868ba87c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -22,12 +22,23 @@ struct sun4i_layer {
 	int			id;
 };
 
+struct sun4i_layer_state {
+	struct drm_plane_state	state;
+	bool			uses_frontend;
+};
+
 static inline struct sun4i_layer *
 plane_to_sun4i_layer(struct drm_plane *plane)
 {
 	return container_of(plane, struct sun4i_layer, plane);
 }
 
+static inline struct sun4i_layer_state *
+state_to_sun4i_layer_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct sun4i_layer_state, state);
+}
+
 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 				     struct sunxi_engine *engine);
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 3c15cf24b503..4b7340ee6290 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -540,6 +540,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 	struct sun4i_tcon *tcon = private;
 	struct drm_device *drm = tcon->drm;
 	struct sun4i_crtc *scrtc = tcon->crtc;
+	struct sunxi_engine *engine = scrtc->engine;
 	unsigned int status;
 
 	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -557,6 +558,9 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 			   SUN4I_TCON_GINT0_VBLANK_INT(1),
 			   0);
 
+	if (engine->ops->vblank_quirk)
+		engine->ops->vblank_quirk(engine);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 28d7c48d50fe..2f0ccd50b54d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -211,7 +211,7 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
 	struct drm_crtc *crtc = state->crtc;
 	struct drm_crtc_state *crtc_state;
 	int min_scale, max_scale;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 
 	if (!crtc)
 		return 0;
@@ -220,10 +220,9 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
 	if (WARN_ON(!crtc_state))
 		return -EINVAL;
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	min_scale = DRM_PLANE_HELPER_NO_SCALING;
 	max_scale = DRM_PLANE_HELPER_NO_SCALING;
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 40c3b303068a..eb3bf2d7291a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -239,7 +239,7 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
 	struct drm_crtc *crtc = state->crtc;
 	struct drm_crtc_state *crtc_state;
 	int min_scale, max_scale;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 
 	if (!crtc)
 		return 0;
@@ -248,10 +248,9 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
 	if (WARN_ON(!crtc_state))
 		return -EINVAL;
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	min_scale = DRM_PLANE_HELPER_NO_SCALING;
 	max_scale = DRM_PLANE_HELPER_NO_SCALING;
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index 4cb70ae65c79..d317ea04b8aa 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -12,16 +12,106 @@
 
 struct drm_plane;
 struct drm_device;
+struct drm_crtc_state;
 
 struct sunxi_engine;
 
+/**
+ * struct sunxi_engine_ops - helper operations for sunXi engines
+ *
+ * These hooks are used by the common part of the DRM driver to
+ * implement the proper behaviour.
+ */
 struct sunxi_engine_ops {
+	/**
+	 * @atomic_begin:
+	 *
+	 * This callback allows to prepare our engine for an atomic
+	 * update. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_begin callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 */
+	void (*atomic_begin)(struct sunxi_engine *engine,
+			     struct drm_crtc_state *old_state);
+
+	/**
+	 * @atomic_check:
+	 *
+	 * This callback allows to validate plane-update related CRTC
+	 * constraints specific to engines. This is mirroring the
+	 * &drm_crtc_helper_funcs.atomic_check callback, so any
+	 * documentation there applies.
+	 *
+	 * This function is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * 0 on success or a negative error code.
+	 */
+	int (*atomic_check)(struct sunxi_engine *engine,
+			    struct drm_crtc_state *state);
+
+	/**
+	 * @commit:
+	 *
+	 * This callback will trigger the hardware switch to commit
+	 * the new configuration that has been setup during the next
+	 * vblank period.
+	 *
+	 * This function is optional.
+	 */
 	void (*commit)(struct sunxi_engine *engine);
+
+	/**
+	 * @layers_init:
+	 *
+	 * This callback is used to allocate, initialize and register
+	 * the layers supported by that engine.
+	 *
+	 * This function is mandatory.
+	 *
+	 * RETURNS:
+	 *
+	 * The array of struct drm_plane backing the layers, or an
+	 * error pointer on failure.
+	 */
 	struct drm_plane **(*layers_init)(struct drm_device *drm,
 					  struct sunxi_engine *engine);
 
+	/**
+	 * @apply_color_correction:
+	 *
+	 * This callback will enable the color correction in the
+	 * engine. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
 	void (*apply_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @disable_color_correction:
+	 *
+	 * This callback will stop the color correction in the
+	 * engine. This is useful only for the composite output.
+	 *
+	 * This function is optional.
+	 */
 	void (*disable_color_correction)(struct sunxi_engine *engine);
+
+	/**
+	 * @vblank_quirk:
+	 *
+	 * This callback is used to implement engine-specific
+	 * behaviour part of the VBLANK event. It is run with all the
+	 * constraints of an interrupt (can't sleep, all local
+	 * interrupts disabled) and therefore should be as fast as
+	 * possible.
+	 *
+	 * This function is optional.
+	 */
+	void (*vblank_quirk)(struct sunxi_engine *engine);
 };
 
 /**
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index b8403ed48285..49df2db2ad46 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1359,7 +1359,7 @@ static u32 tegra_dc_get_vblank_counter(struct drm_crtc *crtc)
 		return host1x_syncpt_read(dc->syncpt);
 
 	/* fallback to software emulated VBLANK counter */
-	return drm_crtc_vblank_count(&dc->base);
+	return (u32)drm_crtc_vblank_count(&dc->base);
 }
 
 static int tegra_dc_enable_vblank(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c
index 36a06a993698..7267a01e6f08 100644
--- a/drivers/gpu/drm/tegra/plane.c
+++ b/drivers/gpu/drm/tegra/plane.c
@@ -82,7 +82,7 @@ int tegra_plane_state_add(struct tegra_plane *plane,
 {
 	struct drm_crtc_state *crtc_state;
 	struct tegra_dc_state *tegra;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 	int err;
 
 	/* Propagate errors from allocation or locking failures. */
@@ -90,10 +90,9 @@ int tegra_plane_state_add(struct tegra_plane *plane,
 	if (IS_ERR(crtc_state))
 		return PTR_ERR(crtc_state);
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->mode.hdisplay;
-	clip.y2 = crtc_state->mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	/* Check plane state for visibility and calculate clipping bounds */
 	err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
index f41fc506ff87..11ae950b0fc9 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
@@ -15,7 +15,7 @@
 
 struct tinydrm_connector {
 	struct drm_connector base;
-	const struct drm_display_mode *mode;
+	struct drm_display_mode mode;
 };
 
 static inline struct tinydrm_connector *
@@ -29,7 +29,7 @@ static int tinydrm_connector_get_modes(struct drm_connector *connector)
 	struct tinydrm_connector *tconn = to_tinydrm_connector(connector);
 	struct drm_display_mode *mode;
 
-	mode = drm_mode_duplicate(connector->dev, tconn->mode);
+	mode = drm_mode_duplicate(connector->dev, &tconn->mode);
 	if (!mode) {
 		DRM_ERROR("Failed to duplicate mode\n");
 		return 0;
@@ -92,7 +92,7 @@ tinydrm_connector_create(struct drm_device *drm,
 	if (!tconn)
 		return ERR_PTR(-ENOMEM);
 
-	tconn->mode = mode;
+	drm_mode_copy(&tconn->mode, mode);
 	connector = &tconn->base;
 
 	drm_connector_helper_add(connector, &tinydrm_connector_hfuncs);
@@ -199,35 +199,27 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
 			  unsigned int rotation)
 {
 	struct drm_device *drm = tdev->drm;
-	struct drm_display_mode *mode_copy;
+	struct drm_display_mode mode_copy;
 	struct drm_connector *connector;
 	int ret;
 
-	mode_copy = devm_kmalloc(drm->dev, sizeof(*mode_copy), GFP_KERNEL);
-	if (!mode_copy)
-		return -ENOMEM;
-
-	*mode_copy = *mode;
-	ret = tinydrm_rotate_mode(mode_copy, rotation);
+	drm_mode_copy(&mode_copy, mode);
+	ret = tinydrm_rotate_mode(&mode_copy, rotation);
 	if (ret) {
 		DRM_ERROR("Illegal rotation value %u\n", rotation);
 		return -EINVAL;
 	}
 
-	drm->mode_config.min_width = mode_copy->hdisplay;
-	drm->mode_config.max_width = mode_copy->hdisplay;
-	drm->mode_config.min_height = mode_copy->vdisplay;
-	drm->mode_config.max_height = mode_copy->vdisplay;
+	drm->mode_config.min_width = mode_copy.hdisplay;
+	drm->mode_config.max_width = mode_copy.hdisplay;
+	drm->mode_config.min_height = mode_copy.vdisplay;
+	drm->mode_config.max_height = mode_copy.vdisplay;
 
-	connector = tinydrm_connector_create(drm, mode_copy, connector_type);
+	connector = tinydrm_connector_create(drm, &mode_copy, connector_type);
 	if (IS_ERR(connector))
 		return PTR_ERR(connector);
 
-	ret = drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
-					   format_count, NULL, connector);
-	if (ret)
-		return ret;
-
-	return 0;
+	return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
+					    format_count, NULL, connector);
 }
 EXPORT_SYMBOL(tinydrm_display_pipe_init);
diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c
index c0cf49849302..a0759502b81a 100644
--- a/drivers/gpu/drm/tinydrm/ili9225.c
+++ b/drivers/gpu/drm/tinydrm/ili9225.c
@@ -180,7 +180,6 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
 {
 	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
 	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
-	struct drm_framebuffer *fb = pipe->plane.fb;
 	struct device *dev = tdev->drm->dev;
 	int ret;
 	u8 am_id;
@@ -269,10 +268,7 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017);
 
-	mipi->enabled = true;
-
-	if (fb)
-		fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
+	mipi_dbi_enable_flush(mipi);
 }
 
 static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe)
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c
index 674d407640be..79cb5af5abac 100644
--- a/drivers/gpu/drm/tinydrm/mi0283qt.c
+++ b/drivers/gpu/drm/tinydrm/mi0283qt.c
@@ -9,47 +9,59 @@
  * (at your option) any later version.
  */
 
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_modeset_helper.h>
-#include <drm/tinydrm/ili9341.h>
-#include <drm/tinydrm/mipi-dbi.h>
-#include <drm/tinydrm/tinydrm-helpers.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/property.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
+
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/tinydrm/mipi-dbi.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
 #include <video/mipi_display.h>
 
-static int mi0283qt_init(struct mipi_dbi *mipi)
+#define ILI9341_FRMCTR1		0xb1
+#define ILI9341_DISCTRL		0xb6
+#define ILI9341_ETMOD		0xb7
+
+#define ILI9341_PWCTRL1		0xc0
+#define ILI9341_PWCTRL2		0xc1
+#define ILI9341_VMCTRL1		0xc5
+#define ILI9341_VMCTRL2		0xc7
+#define ILI9341_PWCTRLA		0xcb
+#define ILI9341_PWCTRLB		0xcf
+
+#define ILI9341_PGAMCTRL	0xe0
+#define ILI9341_NGAMCTRL	0xe1
+#define ILI9341_DTCTRLA		0xe8
+#define ILI9341_DTCTRLB		0xea
+#define ILI9341_PWRSEQ		0xed
+
+#define ILI9341_EN3GAM		0xf2
+#define ILI9341_PUMPCTRL	0xf7
+
+#define ILI9341_MADCTL_BGR	BIT(3)
+#define ILI9341_MADCTL_MV	BIT(5)
+#define ILI9341_MADCTL_MX	BIT(6)
+#define ILI9341_MADCTL_MY	BIT(7)
+
+static void mi0283qt_enable(struct drm_simple_display_pipe *pipe,
+			    struct drm_crtc_state *crtc_state)
 {
-	struct tinydrm_device *tdev = &mipi->tinydrm;
-	struct device *dev = tdev->drm->dev;
+	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
 	u8 addr_mode;
 	int ret;
 
 	DRM_DEBUG_KMS("\n");
 
-	ret = regulator_enable(mipi->regulator);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Failed to enable regulator %d\n", ret);
-		return ret;
-	}
-
-	/* Avoid flicker by skipping setup if the bootloader has done it */
-	if (mipi_dbi_display_is_on(mipi))
-		return 0;
-
-	mipi_dbi_hw_reset(mipi);
-	ret = mipi_dbi_command(mipi, MIPI_DCS_SOFT_RESET);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Error sending command %d\n", ret);
-		regulator_disable(mipi->regulator);
-		return ret;
-	}
-
-	msleep(20);
+	ret = mipi_dbi_poweron_conditional_reset(mipi);
+	if (ret < 0)
+		return;
+	if (ret == 1)
+		goto out_enable;
 
 	mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_OFF);
 
@@ -68,7 +80,7 @@ static int mi0283qt_init(struct mipi_dbi *mipi)
 	mipi_dbi_command(mipi, ILI9341_VMCTRL2, 0xbe);
 
 	/* Memory Access Control */
-	mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
+	mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
 
 	switch (mipi->rotation) {
 	default:
@@ -112,19 +124,12 @@ static int mi0283qt_init(struct mipi_dbi *mipi)
 	mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
 	msleep(100);
 
-	return 0;
-}
-
-static void mi0283qt_fini(void *data)
-{
-	struct mipi_dbi *mipi = data;
-
-	DRM_DEBUG_KMS("\n");
-	regulator_disable(mipi->regulator);
+out_enable:
+	mipi_dbi_enable_flush(mipi);
 }
 
 static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = {
-	.enable = mipi_dbi_pipe_enable,
+	.enable = mi0283qt_enable,
 	.disable = mipi_dbi_pipe_disable,
 	.update = tinydrm_display_pipe_update,
 	.prepare_fb = tinydrm_display_pipe_prepare_fb,
@@ -205,17 +210,6 @@ static int mi0283qt_probe(struct spi_device *spi)
 	if (ret)
 		return ret;
 
-	ret = mi0283qt_init(mipi);
-	if (ret)
-		return ret;
-
-	/* use devres to fini after drm unregister (drv->remove is before) */
-	ret = devm_add_action(dev, mi0283qt_fini, mipi);
-	if (ret) {
-		mi0283qt_fini(mipi);
-		return ret;
-	}
-
 	spi_set_drvdata(spi, mipi);
 
 	return devm_tinydrm_register(&mipi->tinydrm);
@@ -231,25 +225,13 @@ static void mi0283qt_shutdown(struct spi_device *spi)
 static int __maybe_unused mi0283qt_pm_suspend(struct device *dev)
 {
 	struct mipi_dbi *mipi = dev_get_drvdata(dev);
-	int ret;
 
-	ret = drm_mode_config_helper_suspend(mipi->tinydrm.drm);
-	if (ret)
-		return ret;
-
-	mi0283qt_fini(mipi);
-
-	return 0;
+	return drm_mode_config_helper_suspend(mipi->tinydrm.drm);
 }
 
 static int __maybe_unused mi0283qt_pm_resume(struct device *dev)
 {
 	struct mipi_dbi *mipi = dev_get_drvdata(dev);
-	int ret;
-
-	ret = mi0283qt_init(mipi);
-	if (ret)
-		return ret;
 
 	drm_mode_config_helper_resume(mipi->tinydrm.drm);
 
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c
index aa6b6ce56891..75dd65c57e74 100644
--- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
+++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
@@ -271,21 +271,16 @@ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
 };
 
 /**
- * mipi_dbi_pipe_enable - MIPI DBI pipe enable helper
- * @pipe: Display pipe
- * @crtc_state: CRTC state
+ * mipi_dbi_enable_flush - MIPI DBI enable helper
+ * @mipi: MIPI DBI structure
  *
- * This function enables backlight. Drivers can use this as their
+ * This function sets &mipi_dbi->enabled, flushes the whole framebuffer and
+ * enables the backlight. Drivers can use this in their
  * &drm_simple_display_pipe_funcs->enable callback.
  */
-void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe,
-			  struct drm_crtc_state *crtc_state)
+void mipi_dbi_enable_flush(struct mipi_dbi *mipi)
 {
-	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
-	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
-	struct drm_framebuffer *fb = pipe->plane.fb;
-
-	DRM_DEBUG_KMS("\n");
+	struct drm_framebuffer *fb = mipi->tinydrm.pipe.plane.fb;
 
 	mipi->enabled = true;
 	if (fb)
@@ -293,7 +288,7 @@ void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	tinydrm_enable_backlight(mipi->backlight);
 }
-EXPORT_SYMBOL(mipi_dbi_pipe_enable);
+EXPORT_SYMBOL(mipi_dbi_enable_flush);
 
 static void mipi_dbi_blank(struct mipi_dbi *mipi)
 {
@@ -316,8 +311,8 @@ static void mipi_dbi_blank(struct mipi_dbi *mipi)
  * mipi_dbi_pipe_disable - MIPI DBI pipe disable helper
  * @pipe: Display pipe
  *
- * This function disables backlight if present or if not the
- * display memory is blanked. Drivers can use this as their
+ * This function disables backlight if present, if not the display memory is
+ * blanked. The regulator is disabled if in use. Drivers can use this as their
  * &drm_simple_display_pipe_funcs->disable callback.
  */
 void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
@@ -333,6 +328,9 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
 		tinydrm_disable_backlight(mipi->backlight);
 	else
 		mipi_dbi_blank(mipi);
+
+	if (mipi->regulator)
+		regulator_disable(mipi->regulator);
 }
 EXPORT_SYMBOL(mipi_dbi_pipe_disable);
 
@@ -416,7 +414,7 @@ void mipi_dbi_hw_reset(struct mipi_dbi *mipi)
 		return;
 
 	gpiod_set_value_cansleep(mipi->reset, 0);
-	msleep(20);
+	usleep_range(20, 1000);
 	gpiod_set_value_cansleep(mipi->reset, 1);
 	msleep(120);
 }
@@ -443,6 +441,7 @@ bool mipi_dbi_display_is_on(struct mipi_dbi *mipi)
 
 	val &= ~DCS_POWER_MODE_RESERVED_MASK;
 
+	/* The poweron/reset value is 08h DCS_POWER_MODE_DISPLAY_NORMAL_MODE */
 	if (val != (DCS_POWER_MODE_DISPLAY |
 	    DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE))
 		return false;
@@ -453,6 +452,78 @@ bool mipi_dbi_display_is_on(struct mipi_dbi *mipi)
 }
 EXPORT_SYMBOL(mipi_dbi_display_is_on);
 
+static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi *mipi, bool cond)
+{
+	struct device *dev = mipi->tinydrm.drm->dev;
+	int ret;
+
+	if (mipi->regulator) {
+		ret = regulator_enable(mipi->regulator);
+		if (ret) {
+			DRM_DEV_ERROR(dev, "Failed to enable regulator (%d)\n", ret);
+			return ret;
+		}
+	}
+
+	if (cond && mipi_dbi_display_is_on(mipi))
+		return 1;
+
+	mipi_dbi_hw_reset(mipi);
+	ret = mipi_dbi_command(mipi, MIPI_DCS_SOFT_RESET);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to send reset command (%d)\n", ret);
+		if (mipi->regulator)
+			regulator_disable(mipi->regulator);
+		return ret;
+	}
+
+	/*
+	 * If we did a hw reset, we know the controller is in Sleep mode and
+	 * per MIPI DSC spec should wait 5ms after soft reset. If we didn't,
+	 * we assume worst case and wait 120ms.
+	 */
+	if (mipi->reset)
+		usleep_range(5000, 20000);
+	else
+		msleep(120);
+
+	return 0;
+}
+
+/**
+ * mipi_dbi_poweron_reset - MIPI DBI poweron and reset
+ * @mipi: MIPI DBI structure
+ *
+ * This function enables the regulator if used and does a hardware and software
+ * reset.
+ *
+ * Returns:
+ * Zero on success, or a negative error code.
+ */
+int mipi_dbi_poweron_reset(struct mipi_dbi *mipi)
+{
+	return mipi_dbi_poweron_reset_conditional(mipi, false);
+}
+EXPORT_SYMBOL(mipi_dbi_poweron_reset);
+
+/**
+ * mipi_dbi_poweron_conditional_reset - MIPI DBI poweron and conditional reset
+ * @mipi: MIPI DBI structure
+ *
+ * This function enables the regulator if used and if the display is off, it
+ * does a hardware and software reset. If mipi_dbi_display_is_on() determines
+ * that the display is on, no reset is performed.
+ *
+ * Returns:
+ * Zero if the controller was reset, 1 if the display was already on, or a
+ * negative error code.
+ */
+int mipi_dbi_poweron_conditional_reset(struct mipi_dbi *mipi)
+{
+	return mipi_dbi_poweron_reset_conditional(mipi, true);
+}
+EXPORT_SYMBOL(mipi_dbi_poweron_conditional_reset);
+
 #if IS_ENABLED(CONFIG_SPI)
 
 /**
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c
index 5aebfceb740e..a6396ef9cc4a 100644
--- a/drivers/gpu/drm/tinydrm/st7586.c
+++ b/drivers/gpu/drm/tinydrm/st7586.c
@@ -179,20 +179,16 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
 {
 	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
 	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
-	struct drm_framebuffer *fb = pipe->plane.fb;
-	struct device *dev = tdev->drm->dev;
 	int ret;
 	u8 addr_mode;
 
 	DRM_DEBUG_KMS("\n");
 
-	mipi_dbi_hw_reset(mipi);
-	ret = mipi_dbi_command(mipi, ST7586_AUTO_READ_CTRL, 0x9f);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Error sending command %d\n", ret);
+	ret = mipi_dbi_poweron_reset(mipi);
+	if (ret)
 		return;
-	}
 
+	mipi_dbi_command(mipi, ST7586_AUTO_READ_CTRL, 0x9f);
 	mipi_dbi_command(mipi, ST7586_OTP_RW_CTRL, 0x00);
 
 	msleep(10);
@@ -241,10 +237,7 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
 
-	mipi->enabled = true;
-
-	if (fb)
-		fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
+	mipi_dbi_enable_flush(mipi);
 }
 
 static void st7586_pipe_disable(struct drm_simple_display_pipe *pipe)
diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c
index 98ff447f40b4..08b4fb18edb6 100644
--- a/drivers/gpu/drm/tinydrm/st7735r.c
+++ b/drivers/gpu/drm/tinydrm/st7735r.c
@@ -40,19 +40,14 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe,
 {
 	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
 	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
-	struct device *dev = tdev->drm->dev;
 	int ret;
 	u8 addr_mode;
 
 	DRM_DEBUG_KMS("\n");
 
-	mipi_dbi_hw_reset(mipi);
-
-	ret = mipi_dbi_command(mipi, MIPI_DCS_SOFT_RESET);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Error sending command %d\n", ret);
+	ret = mipi_dbi_poweron_reset(mipi);
+	if (ret)
 		return;
-	}
 
 	msleep(150);
 
@@ -102,7 +97,7 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	msleep(20);
 
-	mipi_dbi_pipe_enable(pipe, crtc_state);
+	mipi_dbi_enable_flush(mipi);
 }
 
 static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = {
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index f5500df51686..4a3a868235f8 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -15,6 +15,7 @@ vc4-y := \
 	vc4_vec.o \
 	vc4_hvs.o \
 	vc4_irq.o \
+	vc4_perfmon.o \
 	vc4_plane.o \
 	vc4_render_cl.o \
 	vc4_trace_points.o \
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index ceb385fd69c5..94b99c90425a 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -101,6 +101,7 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data,
 	case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:
 	case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:
 	case DRM_VC4_PARAM_SUPPORTS_MADVISE:
+	case DRM_VC4_PARAM_SUPPORTS_PERFMON:
 		args->value = true;
 		break;
 	default:
@@ -111,6 +112,26 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
+static int vc4_open(struct drm_device *dev, struct drm_file *file)
+{
+	struct vc4_file *vc4file;
+
+	vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL);
+	if (!vc4file)
+		return -ENOMEM;
+
+	vc4_perfmon_open_file(vc4file);
+	file->driver_priv = vc4file;
+	return 0;
+}
+
+static void vc4_close(struct drm_device *dev, struct drm_file *file)
+{
+	struct vc4_file *vc4file = file->driver_priv;
+
+	vc4_perfmon_close_file(vc4file);
+}
+
 static const struct vm_operations_struct vc4_vm_ops = {
 	.fault = vc4_fault,
 	.open = drm_gem_vm_open,
@@ -143,6 +164,9 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(VC4_GEM_MADVISE, vc4_gem_madvise_ioctl, DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(VC4_PERFMON_CREATE, vc4_perfmon_create_ioctl, DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(VC4_PERFMON_DESTROY, vc4_perfmon_destroy_ioctl, DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
 };
 
 static struct drm_driver vc4_drm_driver = {
@@ -153,6 +177,8 @@ static struct drm_driver vc4_drm_driver = {
 			    DRIVER_RENDER |
 			    DRIVER_PRIME),
 	.lastclose = drm_fb_helper_lastclose,
+	.open = vc4_open,
+	.postclose = vc4_close,
 	.irq_handler = vc4_irq,
 	.irq_preinstall = vc4_irq_preinstall,
 	.irq_postinstall = vc4_irq_postinstall,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 3af22936d9b3..fefa1664a9f5 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -11,6 +11,8 @@
 #include <drm/drm_encoder.h>
 #include <drm/drm_gem_cma_helper.h>
 
+#include "uapi/drm/vc4_drm.h"
+
 /* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
  * this.
  */
@@ -29,6 +31,36 @@ enum vc4_kernel_bo_type {
 	VC4_BO_TYPE_COUNT
 };
 
+/* Performance monitor object. The perform lifetime is controlled by userspace
+ * using perfmon related ioctls. A perfmon can be attached to a submit_cl
+ * request, and when this is the case, HW perf counters will be activated just
+ * before the submit_cl is submitted to the GPU and disabled when the job is
+ * done. This way, only events related to a specific job will be counted.
+ */
+struct vc4_perfmon {
+	/* Tracks the number of users of the perfmon, when this counter reaches
+	 * zero the perfmon is destroyed.
+	 */
+	refcount_t refcnt;
+
+	/* Number of counters activated in this perfmon instance
+	 * (should be less than DRM_VC4_MAX_PERF_COUNTERS).
+	 */
+	u8 ncounters;
+
+	/* Events counted by the HW perf counters. */
+	u8 events[DRM_VC4_MAX_PERF_COUNTERS];
+
+	/* Storage for counter values. Counters are incremented by the HW
+	 * perf counter values every time the perfmon is attached to a GPU job.
+	 * This way, perfmon users don't have to retrieve the results after
+	 * each job if they want to track events covering several submissions.
+	 * Note that counter values can't be reset, but you can fake a reset by
+	 * destroying the perfmon and creating a new one.
+	 */
+	u64 counters[0];
+};
+
 struct vc4_dev {
 	struct drm_device *dev;
 
@@ -121,6 +153,11 @@ struct vc4_dev {
 	wait_queue_head_t job_wait_queue;
 	struct work_struct job_done_work;
 
+	/* Used to track the active perfmon if any. Access to this field is
+	 * protected by job_lock.
+	 */
+	struct vc4_perfmon *active_perfmon;
+
 	/* List of struct vc4_seqno_cb for callbacks to be made from a
 	 * workqueue when the given seqno is passed.
 	 */
@@ -406,6 +443,21 @@ struct vc4_exec_info {
 	void *uniforms_v;
 	uint32_t uniforms_p;
 	uint32_t uniforms_size;
+
+	/* Pointer to a performance monitor object if the user requested it,
+	 * NULL otherwise.
+	 */
+	struct vc4_perfmon *perfmon;
+};
+
+/* Per-open file private data. Any driver-specific resource that has to be
+ * released when the DRM file is closed should be placed here.
+ */
+struct vc4_file {
+	struct {
+		struct idr idr;
+		struct mutex lock;
+	} perfmon;
 };
 
 static inline struct vc4_exec_info *
@@ -646,3 +698,19 @@ bool vc4_check_tex_size(struct vc4_exec_info *exec,
 /* vc4_validate_shader.c */
 struct vc4_validated_shader_info *
 vc4_validate_shader(struct drm_gem_cma_object *shader_obj);
+
+/* vc4_perfmon.c */
+void vc4_perfmon_get(struct vc4_perfmon *perfmon);
+void vc4_perfmon_put(struct vc4_perfmon *perfmon);
+void vc4_perfmon_start(struct vc4_dev *vc4, struct vc4_perfmon *perfmon);
+void vc4_perfmon_stop(struct vc4_dev *vc4, struct vc4_perfmon *perfmon,
+		      bool capture);
+struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id);
+void vc4_perfmon_open_file(struct vc4_file *vc4file);
+void vc4_perfmon_close_file(struct vc4_file *vc4file);
+int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
+			     struct drm_file *file_priv);
+int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
+			      struct drm_file *file_priv);
+int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index c94cce96544c..2107b0daf8ef 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -467,14 +467,30 @@ vc4_submit_next_bin_job(struct drm_device *dev)
 
 	vc4_flush_caches(dev);
 
+	/* Only start the perfmon if it was not already started by a previous
+	 * job.
+	 */
+	if (exec->perfmon && vc4->active_perfmon != exec->perfmon)
+		vc4_perfmon_start(vc4, exec->perfmon);
+
 	/* Either put the job in the binner if it uses the binner, or
 	 * immediately move it to the to-be-rendered queue.
 	 */
 	if (exec->ct0ca != exec->ct0ea) {
 		submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
 	} else {
+		struct vc4_exec_info *next;
+
 		vc4_move_job_to_render(dev, exec);
-		goto again;
+		next = vc4_first_bin_job(vc4);
+
+		/* We can't start the next bin job if the previous job had a
+		 * different perfmon instance attached to it. The same goes
+		 * if one of them had a perfmon attached to it and the other
+		 * one doesn't.
+		 */
+		if (next && next->perfmon == exec->perfmon)
+			goto again;
 	}
 }
 
@@ -642,6 +658,7 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
 		 struct ww_acquire_ctx *acquire_ctx)
 {
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
+	struct vc4_exec_info *renderjob;
 	uint64_t seqno;
 	unsigned long irqflags;
 	struct vc4_fence *fence;
@@ -667,11 +684,14 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
 
 	list_add_tail(&exec->head, &vc4->bin_job_list);
 
-	/* If no job was executing, kick ours off.  Otherwise, it'll
-	 * get started when the previous job's flush done interrupt
-	 * occurs.
+	/* If no bin job was executing and if the render job (if any) has the
+	 * same perfmon as our job attached to it (or if both jobs don't have
+	 * perfmon activated), then kick ours off.  Otherwise, it'll get
+	 * started when the previous job's flush/render done interrupt occurs.
 	 */
-	if (vc4_first_bin_job(vc4) == exec) {
+	renderjob = vc4_first_render_job(vc4);
+	if (vc4_first_bin_job(vc4) == exec &&
+	    (!renderjob || renderjob->perfmon == exec->perfmon)) {
 		vc4_submit_next_bin_job(dev);
 		vc4_queue_hangcheck(dev);
 	}
@@ -936,6 +956,9 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
 	vc4->bin_alloc_used &= ~exec->bin_slots;
 	spin_unlock_irqrestore(&vc4->job_lock, irqflags);
 
+	/* Release the reference we had on the perf monitor. */
+	vc4_perfmon_put(exec->perfmon);
+
 	mutex_lock(&vc4->power_lock);
 	if (--vc4->power_refcount == 0) {
 		pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev);
@@ -1088,6 +1111,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
 		    struct drm_file *file_priv)
 {
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
+	struct vc4_file *vc4file = file_priv->driver_priv;
 	struct drm_vc4_submit_cl *args = data;
 	struct vc4_exec_info *exec;
 	struct ww_acquire_ctx acquire_ctx;
@@ -1101,6 +1125,11 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
 		return -EINVAL;
 	}
 
+	if (args->pad2 != 0) {
+		DRM_DEBUG("->pad2 must be set to zero\n");
+		return -EINVAL;
+	}
+
 	exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
 	if (!exec) {
 		DRM_ERROR("malloc failure on exec struct\n");
@@ -1126,6 +1155,15 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
 	if (ret)
 		goto fail;
 
+	if (args->perfmonid) {
+		exec->perfmon = vc4_perfmon_find(vc4file,
+						 args->perfmonid);
+		if (!exec->perfmon) {
+			ret = -ENOENT;
+			goto fail;
+		}
+	}
+
 	if (exec->args->bin_cl_size != 0) {
 		ret = vc4_get_bcl(dev, exec);
 		if (ret)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 984501e3f0b0..b92c6603c7a2 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -995,15 +995,17 @@ static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = {
 	{ "TX", NULL, "Playback" },
 };
 
-static const struct snd_soc_codec_driver vc4_hdmi_audio_codec_drv = {
-	.component_driver = {
-		.controls = vc4_hdmi_audio_controls,
-		.num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls),
-		.dapm_widgets = vc4_hdmi_audio_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets),
-		.dapm_routes = vc4_hdmi_audio_routes,
-		.num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes),
-	},
+static const struct snd_soc_component_driver vc4_hdmi_audio_component_drv = {
+	.controls		= vc4_hdmi_audio_controls,
+	.num_controls		= ARRAY_SIZE(vc4_hdmi_audio_controls),
+	.dapm_widgets		= vc4_hdmi_audio_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(vc4_hdmi_audio_widgets),
+	.dapm_routes		= vc4_hdmi_audio_routes,
+	.num_dapm_routes	= ARRAY_SIZE(vc4_hdmi_audio_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = {
@@ -1101,11 +1103,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
 		return ret;
 	}
 
-	/* register codec and codec dai */
-	ret = snd_soc_register_codec(dev, &vc4_hdmi_audio_codec_drv,
+	/* register component and codec dai */
+	ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_component_drv,
 				     &vc4_hdmi_audio_codec_dai_drv, 1);
 	if (ret) {
-		dev_err(dev, "Could not register codec: %d\n", ret);
+		dev_err(dev, "Could not register component: %d\n", ret);
 		return ret;
 	}
 
@@ -1130,29 +1132,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
 	 */
 	snd_soc_card_set_drvdata(card, hdmi);
 	ret = devm_snd_soc_register_card(dev, card);
-	if (ret) {
+	if (ret)
 		dev_err(dev, "Could not register sound card: %d\n", ret);
-		goto unregister_codec;
-	}
-
-	return 0;
-
-unregister_codec:
-	snd_soc_unregister_codec(dev);
 
 	return ret;
-}
-
-static void vc4_hdmi_audio_cleanup(struct vc4_hdmi *hdmi)
-{
-	struct device *dev = &hdmi->pdev->dev;
 
-	/*
-	 * If drvdata is not set this means the audio card was not
-	 * registered, just skip codec unregistration in this case.
-	 */
-	if (dev_get_drvdata(dev))
-		snd_soc_unregister_codec(dev);
 }
 
 #ifdef CONFIG_DRM_VC4_HDMI_CEC
@@ -1480,7 +1464,6 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
 	struct vc4_dev *vc4 = drm->dev_private;
 	struct vc4_hdmi *hdmi = vc4->hdmi;
 
-	vc4_hdmi_audio_cleanup(hdmi);
 	cec_unregister_adapter(hdmi->cec_adap);
 	vc4_hdmi_connector_destroy(hdmi->connector);
 	vc4_hdmi_encoder_destroy(hdmi->encoder);
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 3dd62d75f531..4cd2ccfe15f4 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -104,13 +104,20 @@ static void
 vc4_irq_finish_bin_job(struct drm_device *dev)
 {
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
-	struct vc4_exec_info *exec = vc4_first_bin_job(vc4);
+	struct vc4_exec_info *next, *exec = vc4_first_bin_job(vc4);
 
 	if (!exec)
 		return;
 
 	vc4_move_job_to_render(dev, exec);
-	vc4_submit_next_bin_job(dev);
+	next = vc4_first_bin_job(vc4);
+
+	/* Only submit the next job in the bin list if it matches the perfmon
+	 * attached to the one that just finished (or if both jobs don't have
+	 * perfmon attached to them).
+	 */
+	if (next && next->perfmon == exec->perfmon)
+		vc4_submit_next_bin_job(dev);
 }
 
 static void
@@ -122,6 +129,10 @@ vc4_cancel_bin_job(struct drm_device *dev)
 	if (!exec)
 		return;
 
+	/* Stop the perfmon so that the next bin job can be started. */
+	if (exec->perfmon)
+		vc4_perfmon_stop(vc4, exec->perfmon, false);
+
 	list_move_tail(&exec->head, &vc4->bin_job_list);
 	vc4_submit_next_bin_job(dev);
 }
@@ -131,18 +142,41 @@ vc4_irq_finish_render_job(struct drm_device *dev)
 {
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
 	struct vc4_exec_info *exec = vc4_first_render_job(vc4);
+	struct vc4_exec_info *nextbin, *nextrender;
 
 	if (!exec)
 		return;
 
 	vc4->finished_seqno++;
 	list_move_tail(&exec->head, &vc4->job_done_list);
+
+	nextbin = vc4_first_bin_job(vc4);
+	nextrender = vc4_first_render_job(vc4);
+
+	/* Only stop the perfmon if following jobs in the queue don't expect it
+	 * to be enabled.
+	 */
+	if (exec->perfmon && !nextrender &&
+	    (!nextbin || nextbin->perfmon != exec->perfmon))
+		vc4_perfmon_stop(vc4, exec->perfmon, true);
+
+	/* If there's a render job waiting, start it. If this is not the case
+	 * we may have to unblock the binner if it's been stalled because of
+	 * perfmon (this can be checked by comparing the perfmon attached to
+	 * the finished renderjob to the one attached to the next bin job: if
+	 * they don't match, this means the binner is stalled and should be
+	 * restarted).
+	 */
+	if (nextrender)
+		vc4_submit_next_render_job(dev);
+	else if (nextbin && nextbin->perfmon != exec->perfmon)
+		vc4_submit_next_bin_job(dev);
+
 	if (exec->fence) {
 		dma_fence_signal_locked(exec->fence);
 		dma_fence_put(exec->fence);
 		exec->fence = NULL;
 	}
-	vc4_submit_next_render_job(dev);
 
 	wake_up_all(&vc4->job_wait_queue);
 	schedule_work(&vc4->job_done_work);
diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c
new file mode 100644
index 000000000000..437e7a27f21d
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_perfmon.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Broadcom
+ */
+
+/**
+ * DOC: VC4 V3D performance monitor module
+ *
+ * The V3D block provides 16 hardware counters which can count various events.
+ */
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+#define VC4_PERFMONID_MIN	1
+#define VC4_PERFMONID_MAX	U32_MAX
+
+void vc4_perfmon_get(struct vc4_perfmon *perfmon)
+{
+	if (perfmon)
+		refcount_inc(&perfmon->refcnt);
+}
+
+void vc4_perfmon_put(struct vc4_perfmon *perfmon)
+{
+	if (perfmon && refcount_dec_and_test(&perfmon->refcnt))
+		kfree(perfmon);
+}
+
+void vc4_perfmon_start(struct vc4_dev *vc4, struct vc4_perfmon *perfmon)
+{
+	unsigned int i;
+	u32 mask;
+
+	if (WARN_ON_ONCE(!perfmon || vc4->active_perfmon))
+		return;
+
+	for (i = 0; i < perfmon->ncounters; i++)
+		V3D_WRITE(V3D_PCTRS(i), perfmon->events[i]);
+
+	mask = GENMASK(perfmon->ncounters - 1, 0);
+	V3D_WRITE(V3D_PCTRC, mask);
+	V3D_WRITE(V3D_PCTRE, V3D_PCTRE_EN | mask);
+	vc4->active_perfmon = perfmon;
+}
+
+void vc4_perfmon_stop(struct vc4_dev *vc4, struct vc4_perfmon *perfmon,
+		      bool capture)
+{
+	unsigned int i;
+
+	if (WARN_ON_ONCE(!vc4->active_perfmon ||
+			 perfmon != vc4->active_perfmon))
+		return;
+
+	if (capture) {
+		for (i = 0; i < perfmon->ncounters; i++)
+			perfmon->counters[i] += V3D_READ(V3D_PCTR(i));
+	}
+
+	V3D_WRITE(V3D_PCTRE, 0);
+	vc4->active_perfmon = NULL;
+}
+
+struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id)
+{
+	struct vc4_perfmon *perfmon;
+
+	mutex_lock(&vc4file->perfmon.lock);
+	perfmon = idr_find(&vc4file->perfmon.idr, id);
+	vc4_perfmon_get(perfmon);
+	mutex_unlock(&vc4file->perfmon.lock);
+
+	return perfmon;
+}
+
+void vc4_perfmon_open_file(struct vc4_file *vc4file)
+{
+	mutex_init(&vc4file->perfmon.lock);
+	idr_init(&vc4file->perfmon.idr);
+}
+
+static int vc4_perfmon_idr_del(int id, void *elem, void *data)
+{
+	struct vc4_perfmon *perfmon = elem;
+
+	vc4_perfmon_put(perfmon);
+
+	return 0;
+}
+
+void vc4_perfmon_close_file(struct vc4_file *vc4file)
+{
+	mutex_lock(&vc4file->perfmon.lock);
+	idr_for_each(&vc4file->perfmon.idr, vc4_perfmon_idr_del, NULL);
+	idr_destroy(&vc4file->perfmon.idr);
+	mutex_unlock(&vc4file->perfmon.lock);
+}
+
+int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
+			     struct drm_file *file_priv)
+{
+	struct vc4_file *vc4file = file_priv->driver_priv;
+	struct drm_vc4_perfmon_create *req = data;
+	struct vc4_perfmon *perfmon;
+	unsigned int i;
+	int ret;
+
+	/* Number of monitored counters cannot exceed HW limits. */
+	if (req->ncounters > DRM_VC4_MAX_PERF_COUNTERS ||
+	    !req->ncounters)
+		return -EINVAL;
+
+	/* Make sure all events are valid. */
+	for (i = 0; i < req->ncounters; i++) {
+		if (req->events[i] >= VC4_PERFCNT_NUM_EVENTS)
+			return -EINVAL;
+	}
+
+	perfmon = kzalloc(sizeof(*perfmon) + (req->ncounters * sizeof(u64)),
+			  GFP_KERNEL);
+	if (!perfmon)
+		return -ENOMEM;
+
+	for (i = 0; i < req->ncounters; i++)
+		perfmon->events[i] = req->events[i];
+
+	perfmon->ncounters = req->ncounters;
+
+	refcount_set(&perfmon->refcnt, 1);
+
+	mutex_lock(&vc4file->perfmon.lock);
+	ret = idr_alloc(&vc4file->perfmon.idr, perfmon, VC4_PERFMONID_MIN,
+			VC4_PERFMONID_MAX, GFP_KERNEL);
+	mutex_unlock(&vc4file->perfmon.lock);
+
+	if (ret < 0) {
+		kfree(perfmon);
+		return ret;
+	}
+
+	req->id = ret;
+	return 0;
+}
+
+int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
+			      struct drm_file *file_priv)
+{
+	struct vc4_file *vc4file = file_priv->driver_priv;
+	struct drm_vc4_perfmon_destroy *req = data;
+	struct vc4_perfmon *perfmon;
+
+	mutex_lock(&vc4file->perfmon.lock);
+	perfmon = idr_remove(&vc4file->perfmon.idr, req->id);
+	mutex_unlock(&vc4file->perfmon.lock);
+
+	if (!perfmon)
+		return -EINVAL;
+
+	vc4_perfmon_put(perfmon);
+	return 0;
+}
+
+int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv)
+{
+	struct vc4_file *vc4file = file_priv->driver_priv;
+	struct drm_vc4_perfmon_get_values *req = data;
+	struct vc4_perfmon *perfmon;
+	int ret;
+
+	mutex_lock(&vc4file->perfmon.lock);
+	perfmon = idr_find(&vc4file->perfmon.idr, req->id);
+	vc4_perfmon_get(perfmon);
+	mutex_unlock(&vc4file->perfmon.lock);
+
+	if (!perfmon)
+		return -EINVAL;
+
+	if (copy_to_user(u64_to_user_ptr(req->values_ptr), perfmon->counters,
+			 perfmon->ncounters * sizeof(u64)))
+		ret = -EFAULT;
+	else
+		ret = 0;
+
+	vc4_perfmon_put(perfmon);
+	return ret;
+}
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 515f97997624..61ad955645a5 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -85,47 +85,46 @@ static const struct hvs_format {
 	u32 drm; /* DRM_FORMAT_* */
 	u32 hvs; /* HVS_FORMAT_* */
 	u32 pixel_order;
-	bool has_alpha;
 } hvs_formats[] = {
 	{
 		.drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
-		.pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_ABGR,
 	},
 	{
 		.drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
-		.pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
+		.pixel_order = HVS_PIXEL_ORDER_ABGR,
 	},
 	{
 		.drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
-		.pixel_order = HVS_PIXEL_ORDER_ARGB, .has_alpha = true,
+		.pixel_order = HVS_PIXEL_ORDER_ARGB,
 	},
 	{
 		.drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
-		.pixel_order = HVS_PIXEL_ORDER_ARGB, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_ARGB,
 	},
 	{
 		.drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
-		.pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_XRGB,
 	},
 	{
 		.drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
-		.pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_XBGR,
 	},
 	{
 		.drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
-		.pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
+		.pixel_order = HVS_PIXEL_ORDER_ABGR,
 	},
 	{
 		.drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
-		.pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_ABGR,
 	},
 	{
 		.drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888,
-		.pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_XRGB,
 	},
 	{
 		.drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888,
-		.pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
+		.pixel_order = HVS_PIXEL_ORDER_XBGR,
 	},
 	{
 		.drm = DRM_FORMAT_YUV422,
@@ -622,7 +621,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
 	/* Position Word 2: Source Image Size, Alpha Mode */
 	vc4_state->pos2_offset = vc4_state->dlist_count;
 	vc4_dlist_write(vc4_state,
-			VC4_SET_FIELD(format->has_alpha ?
+			VC4_SET_FIELD(fb->format->has_alpha ?
 				      SCALER_POS2_ALPHA_MODE_PIPELINE :
 				      SCALER_POS2_ALPHA_MODE_FIXED,
 				      SCALER_POS2_ALPHA_MODE) |
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 55677bd50f66..b9749cb24063 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -122,38 +122,9 @@
 #define V3D_VPMBASE  0x00504
 #define V3D_PCTRC    0x00670
 #define V3D_PCTRE    0x00674
-#define V3D_PCTR0    0x00680
-#define V3D_PCTRS0   0x00684
-#define V3D_PCTR1    0x00688
-#define V3D_PCTRS1   0x0068c
-#define V3D_PCTR2    0x00690
-#define V3D_PCTRS2   0x00694
-#define V3D_PCTR3    0x00698
-#define V3D_PCTRS3   0x0069c
-#define V3D_PCTR4    0x006a0
-#define V3D_PCTRS4   0x006a4
-#define V3D_PCTR5    0x006a8
-#define V3D_PCTRS5   0x006ac
-#define V3D_PCTR6    0x006b0
-#define V3D_PCTRS6   0x006b4
-#define V3D_PCTR7    0x006b8
-#define V3D_PCTRS7   0x006bc
-#define V3D_PCTR8    0x006c0
-#define V3D_PCTRS8   0x006c4
-#define V3D_PCTR9    0x006c8
-#define V3D_PCTRS9   0x006cc
-#define V3D_PCTR10   0x006d0
-#define V3D_PCTRS10  0x006d4
-#define V3D_PCTR11   0x006d8
-#define V3D_PCTRS11  0x006dc
-#define V3D_PCTR12   0x006e0
-#define V3D_PCTRS12  0x006e4
-#define V3D_PCTR13   0x006e8
-#define V3D_PCTRS13  0x006ec
-#define V3D_PCTR14   0x006f0
-#define V3D_PCTRS14  0x006f4
-#define V3D_PCTR15   0x006f8
-#define V3D_PCTRS15  0x006fc
+# define V3D_PCTRE_EN	BIT(31)
+#define V3D_PCTR(x)  (0x00680 + ((x) * 8))
+#define V3D_PCTRS(x) (0x00684 + ((x) * 8))
 #define V3D_DBGE     0x00f00
 #define V3D_FDBGO    0x00f04
 #define V3D_FDBGB    0x00f08
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 493f392b3a0a..bfc2fa73d2ae 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -68,38 +68,38 @@ static const struct {
 	REGDEF(V3D_VPMBASE),
 	REGDEF(V3D_PCTRC),
 	REGDEF(V3D_PCTRE),
-	REGDEF(V3D_PCTR0),
-	REGDEF(V3D_PCTRS0),
-	REGDEF(V3D_PCTR1),
-	REGDEF(V3D_PCTRS1),
-	REGDEF(V3D_PCTR2),
-	REGDEF(V3D_PCTRS2),
-	REGDEF(V3D_PCTR3),
-	REGDEF(V3D_PCTRS3),
-	REGDEF(V3D_PCTR4),
-	REGDEF(V3D_PCTRS4),
-	REGDEF(V3D_PCTR5),
-	REGDEF(V3D_PCTRS5),
-	REGDEF(V3D_PCTR6),
-	REGDEF(V3D_PCTRS6),
-	REGDEF(V3D_PCTR7),
-	REGDEF(V3D_PCTRS7),
-	REGDEF(V3D_PCTR8),
-	REGDEF(V3D_PCTRS8),
-	REGDEF(V3D_PCTR9),
-	REGDEF(V3D_PCTRS9),
-	REGDEF(V3D_PCTR10),
-	REGDEF(V3D_PCTRS10),
-	REGDEF(V3D_PCTR11),
-	REGDEF(V3D_PCTRS11),
-	REGDEF(V3D_PCTR12),
-	REGDEF(V3D_PCTRS12),
-	REGDEF(V3D_PCTR13),
-	REGDEF(V3D_PCTRS13),
-	REGDEF(V3D_PCTR14),
-	REGDEF(V3D_PCTRS14),
-	REGDEF(V3D_PCTR15),
-	REGDEF(V3D_PCTRS15),
+	REGDEF(V3D_PCTR(0)),
+	REGDEF(V3D_PCTRS(0)),
+	REGDEF(V3D_PCTR(1)),
+	REGDEF(V3D_PCTRS(1)),
+	REGDEF(V3D_PCTR(2)),
+	REGDEF(V3D_PCTRS(2)),
+	REGDEF(V3D_PCTR(3)),
+	REGDEF(V3D_PCTRS(3)),
+	REGDEF(V3D_PCTR(4)),
+	REGDEF(V3D_PCTRS(4)),
+	REGDEF(V3D_PCTR(5)),
+	REGDEF(V3D_PCTRS(5)),
+	REGDEF(V3D_PCTR(6)),
+	REGDEF(V3D_PCTRS(6)),
+	REGDEF(V3D_PCTR(7)),
+	REGDEF(V3D_PCTRS(7)),
+	REGDEF(V3D_PCTR(8)),
+	REGDEF(V3D_PCTRS(8)),
+	REGDEF(V3D_PCTR(9)),
+	REGDEF(V3D_PCTRS(9)),
+	REGDEF(V3D_PCTR(10)),
+	REGDEF(V3D_PCTRS(10)),
+	REGDEF(V3D_PCTR(11)),
+	REGDEF(V3D_PCTRS(11)),
+	REGDEF(V3D_PCTR(12)),
+	REGDEF(V3D_PCTRS(12)),
+	REGDEF(V3D_PCTR(13)),
+	REGDEF(V3D_PCTRS(13)),
+	REGDEF(V3D_PCTR(14)),
+	REGDEF(V3D_PCTRS(14)),
+	REGDEF(V3D_PCTR(15)),
+	REGDEF(V3D_PCTRS(15)),
 	REGDEF(V3D_DBGE),
 	REGDEF(V3D_FDBGO),
 	REGDEF(V3D_FDBGB),
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index 5720a0d4ac0a..355569a9b5cb 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -518,6 +518,8 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
 
 	ret = wait_event_timeout(vgdev->resp_wq,
 				 atomic_read(&cache_ent->is_valid), 5 * HZ);
+	if (!ret)
+		return -EBUSY;
 
 	ptr = cache_ent->caps_cache;
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index ead61015cd79..1107d6d03506 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -449,10 +449,9 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
 	if (state->crtc)
 		crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
 
-	if (crtc_state && crtc_state->enable) {
-		clip.x2 = crtc_state->adjusted_mode.hdisplay;
-		clip.y2 = crtc_state->adjusted_mode.vdisplay;
-	}
+	if (crtc_state && crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
 						  DRM_PLANE_HELPER_NO_SCALING,
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
index 68fd2e2dc78a..8e1f34274e24 100644
--- a/drivers/gpu/drm/zte/zx_plane.c
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -55,7 +55,7 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane,
 	struct drm_framebuffer *fb = plane_state->fb;
 	struct drm_crtc *crtc = plane_state->crtc;
 	struct drm_crtc_state *crtc_state;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 	int min_scale = FRAC_16_16(1, 8);
 	int max_scale = FRAC_16_16(8, 1);
 
@@ -75,10 +75,9 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane,
 	if (!plane_state->crtc)
 		return -EINVAL;
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
 						   &clip, min_scale, max_scale,
@@ -292,7 +291,7 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane,
 	struct drm_framebuffer *fb = plane_state->fb;
 	struct drm_crtc *crtc = plane_state->crtc;
 	struct drm_crtc_state *crtc_state;
-	struct drm_rect clip;
+	struct drm_rect clip = {};
 
 	if (!crtc || !fb)
 		return 0;
@@ -310,10 +309,9 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane,
 	if (!plane_state->crtc)
 		return -EINVAL;
 
-	clip.x1 = 0;
-	clip.y1 = 0;
-	clip.x2 = crtc_state->adjusted_mode.hdisplay;
-	clip.y2 = crtc_state->adjusted_mode.vdisplay;
+	if (crtc_state->enable)
+		drm_mode_get_hv_timing(&crtc_state->mode,
+				       &clip.x2, &clip.y2);
 
 	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
 						   &clip,
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 658fa2d3e40c..48685cddbad1 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc)
 {
 	struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
-	const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
+	static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
 
 	chained_irq_enter(chip, desc);
 
@@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc)
 {
 	struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
-	const int int_reg[] = { 4, 5, 8, 9};
+	static const int int_reg[] = { 4, 5, 8, 9};
 
 	chained_irq_enter(chip, desc);
 
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index bb9c087e6c0d..ef32377b91c0 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -788,6 +788,7 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
 	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_GREY:
 		offset = image->rect.left + image->rect.top * pix->bytesperline;
 		break;
 	case V4L2_PIX_FMT_SBGGR16:
diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c
index f1cec3d70498..0f70e8847540 100644
--- a/drivers/gpu/ipu-v3/ipu-pre.c
+++ b/drivers/gpu/ipu-v3/ipu-pre.c
@@ -129,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
 		if (pre_node == pre->dev->of_node) {
 			mutex_unlock(&ipu_pre_list_mutex);
 			device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE);
+			of_node_put(pre_node);
 			return pre;
 		}
 	}
 	mutex_unlock(&ipu_pre_list_mutex);
 
+	of_node_put(pre_node);
+
 	return NULL;
 }
 
diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c
index 067365c733c6..97b99500153d 100644
--- a/drivers/gpu/ipu-v3/ipu-prg.c
+++ b/drivers/gpu/ipu-v3/ipu-prg.c
@@ -102,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
 			mutex_unlock(&ipu_prg_list_mutex);
 			device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
 			prg->id = ipu_id;
+			of_node_put(prg_node);
 			return prg;
 		}
 	}
 	mutex_unlock(&ipu_prg_list_mutex);
 
+	of_node_put(prg_node);
+
 	return NULL;
 }
 
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 19c499f5623d..276c50e3bf45 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -274,6 +274,14 @@ config HID_EMS_FF
 	Currently the following devices are known to be supported:
 	 - Trio Linker Plus II
 
+config HID_ELAN
+	tristate "ELAN USB Touchpad Support"
+	depends on LEDS_CLASS && USB_HID
+	---help---
+	Say Y to enable support for the USB ELAN touchpad
+	Currently the following devices are known to be supported:
+	 - HP Pavilion X2 10-p0XX.
+
 config HID_ELECOM
 	tristate "ELECOM HID devices"
 	depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index eb13b9e92d85..713601c7bfa6 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_HID_CP2112)	+= hid-cp2112.o
 obj-$(CONFIG_HID_CYPRESS)	+= hid-cypress.o
 obj-$(CONFIG_HID_DRAGONRISE)	+= hid-dr.o
 obj-$(CONFIG_HID_EMS_FF)	+= hid-emsff.o
+obj-$(CONFIG_HID_ELAN)		+= hid-elan.o
 obj-$(CONFIG_HID_ELECOM)	+= hid-elecom.o
 obj-$(CONFIG_HID_ELO)		+= hid-elo.o
 obj-$(CONFIG_HID_EZKEY)		+= hid-ezkey.o
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 88b9703318e4..d92f8aa2876b 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -570,7 +570,9 @@ static int asus_input_mapping(struct hid_device *hdev,
 static int asus_start_multitouch(struct hid_device *hdev)
 {
 	int ret;
-	const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 };
+	static const unsigned char buf[] = {
+		FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00
+	};
 	unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
 
 	if (!dmabuf) {
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c2560aae5542..4fc08c38bc0e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1365,7 +1365,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
 	 * of implement() working on 8 byte chunks
 	 */
 
-	int len = hid_report_len(report) + 7;
+	u32 len = hid_report_len(report) + 7;
 
 	return kmalloc(len, flags);
 }
@@ -1430,7 +1430,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report,
 {
 	char *buf;
 	int ret;
-	int len;
+	u32 len;
 
 	buf = hid_alloc_report_buf(report, GFP_KERNEL);
 	if (!buf)
@@ -1456,14 +1456,14 @@ void __hid_request(struct hid_device *hid, struct hid_report *report,
 }
 EXPORT_SYMBOL_GPL(__hid_request);
 
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 		int interrupt)
 {
 	struct hid_report_enum *report_enum = hid->report_enum + type;
 	struct hid_report *report;
 	struct hid_driver *hdrv;
 	unsigned int a;
-	int rsize, csize = size;
+	u32 rsize, csize = size;
 	u8 *cdata = data;
 	int ret = 0;
 
@@ -1521,7 +1521,7 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event);
  *
  * This is data entry for lower layers.
  */
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt)
 {
 	struct hid_report_enum *report_enum;
 	struct hid_driver *hdrv;
diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c
index 9ba5d98a1180..ec9e060ec46c 100644
--- a/drivers/hid/hid-corsair.c
+++ b/drivers/hid/hid-corsair.c
@@ -2,11 +2,14 @@
  * HID driver for Corsair devices
  *
  * Supported devices:
+ *  - Vengeance K70 Keyboard
+ *  - K70 RAPIDFIRE Keyboard
  *  - Vengeance K90 Keyboard
  *  - Scimitar PRO RGB Gaming Mouse
  *
  * Copyright (c) 2015 Clement Vuchener
  * Copyright (c) 2017 Oscar Campos
+ * Copyright (c) 2017 Aaron Bottegal
  */
 
 /*
@@ -673,7 +676,7 @@ static int corsair_input_mapping(struct hid_device *dev,
 }
 
 /*
- * The report descriptor of Corsair Scimitar RGB Pro gaming mouse is
+ * The report descriptor of some of the Corsair gaming mice is
  * non parseable as they define two consecutive Logical Minimum for
  * the Usage Page (Consumer) in rdescs bytes 75 and 77 being 77 0x16
  * that should be obviousy 0x26 for Logical Magimum of 16 bits. This
@@ -681,7 +684,8 @@ static int corsair_input_mapping(struct hid_device *dev,
  * Minimum being larger than Logical Maximum.
  *
  * This driver fixes the report descriptor for:
- * - USB ID b1c:1b3e, sold as Scimitar RGB Pro Gaming mouse
+ * - USB ID 1b1c:1b34, sold as GLAIVE RGB Gaming mouse
+ * - USB ID 1b1c:1b3e, sold as Scimitar RGB Pro Gaming mouse
  */
 
 static __u8 *corsair_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -691,13 +695,14 @@ static __u8 *corsair_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
 	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
 		/*
-		 * Corsair Scimitar RGB Pro report descriptor is broken and
-		 * defines two different Logical Minimum for the Consumer
-		 * Application. The byte 77 should be a 0x26 defining a 16
-		 * bits integer for the Logical Maximum but it is a 0x16
+		 * Corsair GLAIVE RGB and Scimitar RGB Pro report descriptor is
+		 * broken and defines two different Logical Minimum for the
+		 * Consumer Application. The byte 77 should be a 0x26 defining
+		 * a 16 bits integer for the Logical Maximum but it is a 0x16
 		 * instead (Logical Minimum)
 		 */
 		switch (hdev->product) {
+		case USB_DEVICE_ID_CORSAIR_GLAIVE_RGB:
 		case USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB:
 			if (*rsize >= 172 && rdesc[75] == 0x15 && rdesc[77] == 0x16
 			&& rdesc[78] == 0xff && rdesc[79] == 0x0f) {
@@ -715,8 +720,15 @@ static const struct hid_device_id corsair_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90),
 		.driver_data = CORSAIR_USE_K90_MACRO |
 			       CORSAIR_USE_K90_BACKLIGHT },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR,
+            USB_DEVICE_ID_CORSAIR_GLAIVE_RGB) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR,
             USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) },
+	/*
+	 * Vengeance K70 and K70 RAPIDFIRE share product IDs.
+	 */
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR,
+            USB_DEVICE_ID_CORSAIR_K70R) },
 	{}
 };
 
diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c
new file mode 100644
index 000000000000..803a725785cf
--- /dev/null
+++ b/drivers/hid/hid-elan.c
@@ -0,0 +1,421 @@
+/*
+ * HID Driver for ELAN Touchpad
+ *
+ * Currently only supports touchpad found on HP Pavilion X2 10
+ *
+ * Copyright (c) 2016 Alexandrov Stanislav <neko@nya.ai>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+#include <linux/input/mt.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define ELAN_SINGLE_FINGER	0x81
+#define ELAN_MT_FIRST_FINGER	0x82
+#define ELAN_MT_SECOND_FINGER	0x83
+#define ELAN_INPUT_REPORT_SIZE	8
+
+#define ELAN_MUTE_LED_REPORT	0xBC
+#define ELAN_LED_REPORT_SIZE	8
+
+struct elan_touchpad_settings {
+	u8 max_fingers;
+	u16 max_x;
+	u16 max_y;
+	u8 max_area_x;
+	u8 max_area_y;
+	u8 max_w;
+	int usb_bInterfaceNumber;
+};
+
+struct elan_drvdata {
+	struct input_dev *input;
+	u8 prev_report[ELAN_INPUT_REPORT_SIZE];
+	struct led_classdev mute_led;
+	u8 mute_led_state;
+	struct elan_touchpad_settings *settings;
+};
+
+static int is_not_elan_touchpad(struct hid_device *hdev)
+{
+	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	return (intf->altsetting->desc.bInterfaceNumber != drvdata->settings->usb_bInterfaceNumber);
+}
+
+static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+			      struct hid_field *field, struct hid_usage *usage,
+			      unsigned long **bit, int *max)
+{
+	if (is_not_elan_touchpad(hdev))
+		return 0;
+
+	if (field->report->id == ELAN_SINGLE_FINGER ||
+	    field->report->id == ELAN_MT_FIRST_FINGER ||
+	    field->report->id == ELAN_MT_SECOND_FINGER)
+		return -1;
+
+	return 0;
+}
+
+static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
+{
+	int ret;
+	struct input_dev *input;
+	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (is_not_elan_touchpad(hdev))
+		return 0;
+
+	input = devm_input_allocate_device(&hdev->dev);
+	if (!input)
+		return -ENOMEM;
+
+	input->name = "Elan Touchpad";
+	input->phys = hdev->phys;
+	input->uniq = hdev->uniq;
+	input->id.bustype = hdev->bus;
+	input->id.vendor  = hdev->vendor;
+	input->id.product = hdev->product;
+	input->id.version = hdev->version;
+	input->dev.parent = &hdev->dev;
+
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0,
+			     drvdata->settings->max_x, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
+			     drvdata->settings->max_y, 0, 0);
+	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
+			     drvdata->settings->max_fingers, 0, 0);
+	input_set_abs_params(input, ABS_TOOL_WIDTH, 0,
+			     drvdata->settings->max_w, 0, 0);
+
+	__set_bit(BTN_LEFT, input->keybit);
+	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+	ret = input_mt_init_slots(input, drvdata->settings->max_fingers,
+				  INPUT_MT_POINTER);
+	if (ret) {
+		hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
+		return ret;
+	}
+
+	ret = input_register_device(input);
+	if (ret) {
+		hid_err(hdev, "Failed to register elan input device: %d\n",
+			ret);
+		input_free_device(input);
+		return ret;
+	}
+
+	drvdata->input = input;
+
+	return 0;
+}
+
+static void elan_report_mt_slot(struct elan_drvdata *drvdata, u8 *data,
+				unsigned int slot_num)
+{
+	struct input_dev *input = drvdata->input;
+	int x, y, w;
+
+	bool active = !!data;
+
+	input_mt_slot(input, slot_num);
+	input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
+	if (active) {
+		x = ((data[0] & 0xF0) << 4) | data[1];
+		y = drvdata->settings->max_y -
+		    (((data[0] & 0x07) << 8) | data[2]);
+		w = data[4];
+
+		input_report_abs(input, ABS_MT_POSITION_X, x);
+		input_report_abs(input, ABS_MT_POSITION_Y, y);
+		input_report_abs(input, ABS_TOOL_WIDTH, w);
+	}
+}
+
+static void elan_report_input(struct elan_drvdata *drvdata, u8 *data)
+{
+	int i;
+	struct input_dev *input = drvdata->input;
+
+	/*
+	 * There is 3 types of reports: for single touch,
+	 * for multitouch - first finger and for multitouch - second finger
+	 *
+	 * packet structure for ELAN_SINGLE_FINGER and ELAN_MT_FIRST_FINGER:
+	 *
+	 * byte 1: 1   0   0   0   0   0   0   1  // 0x81 or 0x82
+	 * byte 2: 0   0   0   0   0   0   0   0  // looks like unused
+	 * byte 3: f5  f4  f3  f2  f1  0   0   L
+	 * byte 4: x12 x11 x10 x9  0?  y11 y10 y9
+	 * byte 5: x8  x7  x6  x5  x4  x3  x2  x1
+	 * byte 6: y8  y7  y6  y5  y4  y3  y2  y1
+	 * byte 7: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
+	 * byte 8: w8  w7  w6  w5  w4  w3  w2  w1
+	 *
+	 * packet structure for ELAN_MT_SECOND_FINGER:
+	 *
+	 * byte 1: 1   0   0   0   0   0   1   1  // 0x83
+	 * byte 2: x12 x11 x10 x9  0   y11 y10 y9
+	 * byte 3: x8  x7  x6  x5  x4  x3  x2  x1
+	 * byte 4: y8  y7  y6  y5  y4  y3  y2  y1
+	 * byte 5: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
+	 * byte 6: w8  w7  w6  w5  w4  w3  w2  w1
+	 * byte 7: 0   0   0   0   0   0   0   0
+	 * byte 8: 0   0   0   0   0   0   0   0
+	 *
+	 * f5-f1: finger touch bits
+	 * L: clickpad button
+	 * sy / sx: not sure yet, but this looks like rectangular
+	 * area for finger
+	 * w: looks like finger width
+	 */
+
+	if (data[0] == ELAN_SINGLE_FINGER) {
+		for (i = 0; i < drvdata->settings->max_fingers; i++) {
+			if (data[2] & BIT(i + 3))
+				elan_report_mt_slot(drvdata, data + 3, i);
+			else
+				elan_report_mt_slot(drvdata, NULL, i);
+		}
+		input_report_key(input, BTN_LEFT, data[2] & 0x01);
+	}
+	/*
+	 * When touched with two fingers Elan touchpad will emit two HID reports
+	 * first is ELAN_MT_FIRST_FINGER and second is ELAN_MT_SECOND_FINGER
+	 * we will save ELAN_MT_FIRST_FINGER report and wait for
+	 * ELAN_MT_SECOND_FINGER to finish multitouch
+	 */
+	if (data[0] == ELAN_MT_FIRST_FINGER) {
+		memcpy(drvdata->prev_report, data,
+		       sizeof(drvdata->prev_report));
+		return;
+	}
+
+	if (data[0] == ELAN_MT_SECOND_FINGER) {
+		int first = 0;
+		u8 *prev_report = drvdata->prev_report;
+
+		if (prev_report[0] != ELAN_MT_FIRST_FINGER)
+			return;
+
+		for (i = 0; i < drvdata->settings->max_fingers; i++) {
+			if (prev_report[2] & BIT(i + 3)) {
+				if (!first) {
+					first = 1;
+					elan_report_mt_slot(drvdata, prev_report + 3, i);
+				} else {
+					elan_report_mt_slot(drvdata, data + 1, i);
+				}
+			} else {
+				elan_report_mt_slot(drvdata, NULL, i);
+			}
+		}
+		input_report_key(input, BTN_LEFT, prev_report[2] & 0x01);
+	}
+
+	input_mt_sync_frame(input);
+	input_sync(input);
+}
+
+static int elan_raw_event(struct hid_device *hdev,
+			  struct hid_report *report, u8 *data, int size)
+{
+	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	if (is_not_elan_touchpad(hdev))
+		return 0;
+
+	if (data[0] == ELAN_SINGLE_FINGER ||
+	    data[0] == ELAN_MT_FIRST_FINGER ||
+	    data[0] == ELAN_MT_SECOND_FINGER) {
+		if (size == ELAN_INPUT_REPORT_SIZE) {
+			elan_report_input(drvdata, data);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int elan_start_multitouch(struct hid_device *hdev)
+{
+	int ret;
+
+	/*
+	 * This byte sequence will enable multitouch mode and disable
+	 * mouse emulation
+	 */
+	const unsigned char buf[] = { 0x0D, 0x00, 0x03, 0x21, 0x00 };
+	unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
+
+	if (!dmabuf)
+		return -ENOMEM;
+
+	ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
+				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+	kfree(dmabuf);
+
+	if (ret != sizeof(buf)) {
+		hid_err(hdev, "Failed to start multitouch: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static enum led_brightness elan_mute_led_get_brigtness(struct led_classdev *led_cdev)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hdev = to_hid_device(dev);
+	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	return drvdata->mute_led_state;
+}
+
+static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev,
+				       enum led_brightness value)
+{
+	int ret;
+	u8 led_state;
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hdev = to_hid_device(dev);
+	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
+
+	unsigned char *dmabuf = kzalloc(ELAN_LED_REPORT_SIZE, GFP_KERNEL);
+
+	if (!dmabuf)
+		return -ENOMEM;
+
+	led_state = !!value;
+
+	dmabuf[0] = ELAN_MUTE_LED_REPORT;
+	dmabuf[1] = 0x02;
+	dmabuf[2] = led_state;
+
+	ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, ELAN_LED_REPORT_SIZE,
+				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+	kfree(dmabuf);
+
+	if (ret != ELAN_LED_REPORT_SIZE) {
+		hid_err(hdev, "Failed to set mute led brightness: %d\n", ret);
+		return ret;
+	}
+
+	drvdata->mute_led_state = led_state;
+	return 0;
+}
+
+static int elan_init_mute_led(struct hid_device *hdev)
+{
+	struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
+	struct led_classdev *mute_led = &drvdata->mute_led;
+
+	mute_led->name = "elan:red:mute";
+	mute_led->brightness_get = elan_mute_led_get_brigtness;
+	mute_led->brightness_set_blocking = elan_mute_led_set_brigtness;
+	mute_led->max_brightness = LED_ON;
+	mute_led->dev = &hdev->dev;
+
+	return devm_led_classdev_register(&hdev->dev, mute_led);
+}
+
+static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int ret;
+	struct elan_drvdata *drvdata;
+
+	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
+
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->settings = (struct elan_touchpad_settings *)id->driver_data;
+	hid_set_drvdata(hdev, drvdata);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "Hid Parse failed\n");
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "Hid hw start failed\n");
+		return ret;
+	}
+
+	if (is_not_elan_touchpad(hdev))
+		return 0;
+
+	if (!drvdata->input) {
+		hid_err(hdev, "Input device is not registred\n");
+		ret = -ENAVAIL;
+		goto err;
+	}
+
+	ret = elan_start_multitouch(hdev);
+	if (ret)
+		goto err;
+
+	ret = elan_init_mute_led(hdev);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	hid_hw_stop(hdev);
+	return ret;
+}
+
+static void elan_remove(struct hid_device *hdev)
+{
+	hid_hw_stop(hdev);
+}
+
+static const struct elan_touchpad_settings hp_x2_10_touchpad_data = {
+	.max_fingers = 5,
+	.max_x = 2930,
+	.max_y = 1250,
+	.max_area_x = 15,
+	.max_area_y = 15,
+	.max_w = 255,
+	.usb_bInterfaceNumber = 1,
+};
+
+static const struct hid_device_id elan_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER),
+		(kernel_ulong_t)&hp_x2_10_touchpad_data},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(hid, elan_devices);
+
+static struct hid_driver elan_driver = {
+	.name = "elan",
+	.id_table = elan_devices,
+	.input_mapping = elan_input_mapping,
+	.input_configured = elan_input_configured,
+	.raw_event = elan_raw_event,
+	.probe = elan_probe,
+	.remove = elan_remove,
+};
+
+module_hid_driver(elan_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexandrov Stanislav");
+MODULE_DESCRIPTION("Driver for HID ELAN Touchpads");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 43ddcdfbd0da..db76acc6dab3 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -291,6 +291,7 @@
 #define USB_DEVICE_ID_CORSAIR_K70RGB    0x1b13
 #define USB_DEVICE_ID_CORSAIR_STRAFE    0x1b15
 #define USB_DEVICE_ID_CORSAIR_K65RGB    0x1b17
+#define USB_DEVICE_ID_CORSAIR_GLAIVE_RGB        0x1b34
 #define USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE  0x1b38
 #define USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE  0x1b39
 #define USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB  0x1b3e
@@ -368,6 +369,7 @@
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001	0xa001
 
 #define USB_VENDOR_ID_ELAN		0x04f3
+#define USB_DEVICE_ID_HP_X2_10_COVER	0x0755
 
 #define USB_VENDOR_ID_ELECOM		0x056e
 #define USB_DEVICE_ID_ELECOM_BM084	0x0061
@@ -645,6 +647,9 @@
 #define USB_DEVICE_ID_LD_MICROCASSYTIME		0x1033
 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE	0x1035
 #define USB_DEVICE_ID_LD_MICROCASSYPH		0x1038
+#define USB_DEVICE_ID_LD_POWERANALYSERCASSY	0x1040
+#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY	0x1042
+#define USB_DEVICE_ID_LD_MACHINETESTCASSY	0x1043
 #define USB_DEVICE_ID_LD_JWM		0x1080
 #define USB_DEVICE_ID_LD_DMMP		0x1081
 #define USB_DEVICE_ID_LD_UMIP		0x1090
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 04d01b57d94c..d86398755b0d 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1368,7 +1368,8 @@ static void hidinput_led_worker(struct work_struct *work)
 					      led_work);
 	struct hid_field *field;
 	struct hid_report *report;
-	int len, ret;
+	int ret;
+	u32 len;
 	__u8 *buf;
 
 	field = hidinput_get_led_field(hid);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 3b4739bde05d..2e1736ba2444 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -370,7 +370,8 @@ static const struct attribute_group mt_attribute_group = {
 static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
-	int ret, size = hid_report_len(report);
+	int ret;
+	u32 size = hid_report_len(report);
 	u8 *buf;
 
 	/*
@@ -1183,7 +1184,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
 	struct hid_report_enum *re;
 	struct mt_class *cls = &td->mtclass;
 	char *buf;
-	int report_len;
+	u32 report_len;
 
 	if (td->inputmode < 0)
 		return;
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 5f6035a5ce36..45c701ca78a1 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -62,6 +62,7 @@ static const struct hid_device_id hid_quirks[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70R), HID_QUIRK_NO_INIT_REPORTS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_M65RGB), HID_QUIRK_NO_INIT_REPORTS },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51), HID_QUIRK_NOGET },
@@ -317,6 +318,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #endif
 #if IS_ENABLED(CONFIG_HID_CORSAIR)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) },
 #endif
 #if IS_ENABLED(CONFIG_HID_CP2112)
@@ -333,6 +335,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
 #endif
+#if IS_ENABLED(CONFIG_HID_ELAN)
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER) },
+#endif
 #if IS_ENABLED(CONFIG_HID_ELECOM)
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRED) },
@@ -809,6 +814,9 @@ static const struct hid_device_id hid_ignore_list[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index c6c05df3e8d2..9c9362149641 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -89,8 +89,8 @@ struct rmi_data {
 	u8 *writeReport;
 	u8 *readReport;
 
-	int input_report_size;
-	int output_report_size;
+	u32 input_report_size;
+	u32 output_report_size;
 
 	unsigned long flags;
 
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 7230243b94d3..97689e98e53f 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -144,10 +144,10 @@ struct i2c_hid {
 						   * register of the HID
 						   * descriptor. */
 	unsigned int		bufsize;	/* i2c buffer size */
-	char			*inbuf;		/* Input buffer */
-	char			*rawbuf;	/* Raw Input buffer */
-	char			*cmdbuf;	/* Command buffer */
-	char			*argsbuf;	/* Command arguments buffer */
+	u8			*inbuf;		/* Input buffer */
+	u8			*rawbuf;	/* Raw Input buffer */
+	u8			*cmdbuf;	/* Command buffer */
+	u8			*argsbuf;	/* Command arguments buffer */
 
 	unsigned long		flags;		/* device flags */
 	unsigned long		quirks;		/* Various quirks */
@@ -455,7 +455,8 @@ static int i2c_hid_hwreset(struct i2c_client *client)
 
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
-	int ret, ret_size;
+	int ret;
+	u32 ret_size;
 	int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
 
 	if (size > ihid->bufsize)
@@ -480,7 +481,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
 		return;
 	}
 
-	if (ret_size > size) {
+	if ((ret_size > size) || (ret_size <= 2)) {
 		dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
 			__func__, size, ret_size);
 		return;
@@ -891,10 +892,10 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
 
 static void i2c_hid_acpi_fix_up_power(struct device *dev)
 {
-	acpi_handle handle = ACPI_HANDLE(dev);
 	struct acpi_device *adev;
 
-	if (handle && acpi_bus_get_device(handle, &adev) == 0)
+	adev = ACPI_COMPANION(dev);
+	if (adev)
 		acpi_device_fix_up_power(adev);
 }
 
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 4e0e7baf8513..3c5507313606 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -496,12 +496,12 @@ static int uhid_dev_create2(struct uhid_device *uhid,
 		goto err_free;
 	}
 
-	len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1;
-	strncpy(hid->name, ev->u.create2.name, len);
-	len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1;
-	strncpy(hid->phys, ev->u.create2.phys, len);
-	len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1;
-	strncpy(hid->uniq, ev->u.create2.uniq, len);
+	len = min(sizeof(hid->name), sizeof(ev->u.create2.name));
+	strlcpy(hid->name, ev->u.create2.name, len);
+	len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys));
+	strlcpy(hid->phys, ev->u.create2.phys, len);
+	len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq));
+	strlcpy(hid->uniq, ev->u.create2.uniq, len);
 
 	hid->ll_driver = &uhid_hid_driver;
 	hid->bus = ev->u.create2.bus;
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 409543160af7..b54ef1ffcbec 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -219,7 +219,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
 	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
 	u8 *data;
 	int ret;
-	int n;
+	u32 n;
 
 	switch (equivalent_usage) {
 	case HID_DG_CONTACTMAX:
@@ -519,7 +519,7 @@ static int wacom_set_device_mode(struct hid_device *hdev,
 	u8 *rep_data;
 	struct hid_report *r;
 	struct hid_report_enum *re;
-	int length;
+	u32 length;
 	int error = -ENOMEM, limit = 0;
 
 	if (wacom_wac->mode_report < 0)
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
index 190e7b39ce32..2c7ba70921f5 100644
--- a/drivers/hwmon/sht21.c
+++ b/drivers/hwmon/sht21.c
@@ -16,8 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
  *
- * Data sheet available (5/2010) at
- * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
+ * Data sheet available at http://www.sensirion.com/file/datasheet_sht21
  */
 
 #include <linux/module.h>
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index c4560d84dfae..25bb178f6074 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -305,16 +305,21 @@ void nldev_exit(void);
 static inline struct ib_qp *_ib_create_qp(struct ib_device *dev,
 					  struct ib_pd *pd,
 					  struct ib_qp_init_attr *attr,
-					  struct ib_udata *udata)
+					  struct ib_udata *udata,
+					  struct ib_uobject *uobj)
 {
 	struct ib_qp *qp;
 
+	if (!dev->create_qp)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	qp = dev->create_qp(pd, attr, udata);
 	if (IS_ERR(qp))
 		return qp;
 
 	qp->device = dev;
 	qp->pd = pd;
+	qp->uobject = uobj;
 	/*
 	 * We don't track XRC QPs for now, because they don't have PD
 	 * and more importantly they are created internaly by driver,
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index 85b5ee4defa4..d8eead5d106d 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -141,7 +141,12 @@ static struct ib_uobject *alloc_uobj(struct ib_ucontext *context,
 	 */
 	uobj->context = context;
 	uobj->type = type;
-	atomic_set(&uobj->usecnt, 0);
+	/*
+	 * Allocated objects start out as write locked to deny any other
+	 * syscalls from accessing them until they are committed. See
+	 * rdma_alloc_commit_uobject
+	 */
+	atomic_set(&uobj->usecnt, -1);
 	kref_init(&uobj->ref);
 
 	return uobj;
@@ -196,7 +201,15 @@ static struct ib_uobject *lookup_get_idr_uobject(const struct uverbs_obj_type *t
 		goto free;
 	}
 
-	uverbs_uobject_get(uobj);
+	/*
+	 * The idr_find is guaranteed to return a pointer to something that
+	 * isn't freed yet, or NULL, as the free after idr_remove goes through
+	 * kfree_rcu(). However the object may still have been released and
+	 * kfree() could be called at any time.
+	 */
+	if (!kref_get_unless_zero(&uobj->ref))
+		uobj = ERR_PTR(-ENOENT);
+
 free:
 	rcu_read_unlock();
 	return uobj;
@@ -399,13 +412,13 @@ static int __must_check remove_commit_fd_uobject(struct ib_uobject *uobj,
 	return ret;
 }
 
-static void lockdep_check(struct ib_uobject *uobj, bool exclusive)
+static void assert_uverbs_usecnt(struct ib_uobject *uobj, bool exclusive)
 {
 #ifdef CONFIG_LOCKDEP
 	if (exclusive)
-		WARN_ON(atomic_read(&uobj->usecnt) > 0);
+		WARN_ON(atomic_read(&uobj->usecnt) != -1);
 	else
-		WARN_ON(atomic_read(&uobj->usecnt) == -1);
+		WARN_ON(atomic_read(&uobj->usecnt) <= 0);
 #endif
 }
 
@@ -444,7 +457,7 @@ int __must_check rdma_remove_commit_uobject(struct ib_uobject *uobj)
 		WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n");
 		return 0;
 	}
-	lockdep_check(uobj, true);
+	assert_uverbs_usecnt(uobj, true);
 	ret = _rdma_remove_commit_uobject(uobj, RDMA_REMOVE_DESTROY);
 
 	up_read(&ucontext->cleanup_rwsem);
@@ -474,16 +487,17 @@ int rdma_explicit_destroy(struct ib_uobject *uobject)
 		WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n");
 		return 0;
 	}
-	lockdep_check(uobject, true);
+	assert_uverbs_usecnt(uobject, true);
 	ret = uobject->type->type_class->remove_commit(uobject,
 						       RDMA_REMOVE_DESTROY);
 	if (ret)
-		return ret;
+		goto out;
 
 	uobject->type = &null_obj_type;
 
+out:
 	up_read(&ucontext->cleanup_rwsem);
-	return 0;
+	return ret;
 }
 
 static void alloc_commit_idr_uobject(struct ib_uobject *uobj)
@@ -527,6 +541,10 @@ int rdma_alloc_commit_uobject(struct ib_uobject *uobj)
 		return ret;
 	}
 
+	/* matches atomic_set(-1) in alloc_uobj */
+	assert_uverbs_usecnt(uobj, true);
+	atomic_set(&uobj->usecnt, 0);
+
 	uobj->type->type_class->alloc_commit(uobj);
 	up_read(&uobj->context->cleanup_rwsem);
 
@@ -561,7 +579,7 @@ static void lookup_put_fd_uobject(struct ib_uobject *uobj, bool exclusive)
 
 void rdma_lookup_put_uobject(struct ib_uobject *uobj, bool exclusive)
 {
-	lockdep_check(uobj, exclusive);
+	assert_uverbs_usecnt(uobj, exclusive);
 	uobj->type->type_class->lookup_put(uobj, exclusive);
 	/*
 	 * In order to unlock an object, either decrease its usecnt for
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index 857637bf46da..3dbc4e4cca41 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -7,7 +7,6 @@
 #include <rdma/restrack.h>
 #include <linux/mutex.h>
 #include <linux/sched/task.h>
-#include <linux/uaccess.h>
 #include <linux/pid_namespace.h>
 
 void rdma_restrack_init(struct rdma_restrack_root *res)
@@ -63,7 +62,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 {
 	enum rdma_restrack_type type = res->type;
 	struct ib_device *dev;
-	struct ib_xrcd *xrcd;
 	struct ib_pd *pd;
 	struct ib_cq *cq;
 	struct ib_qp *qp;
@@ -81,10 +79,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 		qp = container_of(res, struct ib_qp, res);
 		dev = qp->device;
 		break;
-	case RDMA_RESTRACK_XRCD:
-		xrcd = container_of(res, struct ib_xrcd, res);
-		dev = xrcd->device;
-		break;
 	default:
 		WARN_ONCE(true, "Wrong resource tracking type %u\n", type);
 		return NULL;
@@ -93,6 +87,21 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 	return dev;
 }
 
+static bool res_is_user(struct rdma_restrack_entry *res)
+{
+	switch (res->type) {
+	case RDMA_RESTRACK_PD:
+		return container_of(res, struct ib_pd, res)->uobject;
+	case RDMA_RESTRACK_CQ:
+		return container_of(res, struct ib_cq, res)->uobject;
+	case RDMA_RESTRACK_QP:
+		return container_of(res, struct ib_qp, res)->uobject;
+	default:
+		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
+		return false;
+	}
+}
+
 void rdma_restrack_add(struct rdma_restrack_entry *res)
 {
 	struct ib_device *dev = res_to_dev(res);
@@ -100,7 +109,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res)
 	if (!dev)
 		return;
 
-	if (!uaccess_kernel()) {
+	if (res_is_user(res)) {
 		get_task_struct(current);
 		res->task = current;
 		res->kern_name = NULL;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 256934d1f64f..25a0e0e083b3 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -562,9 +562,10 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
 	if (f.file)
 		fdput(f);
 
+	mutex_unlock(&file->device->xrcd_tree_mutex);
+
 	uobj_alloc_commit(&obj->uobject);
 
-	mutex_unlock(&file->device->xrcd_tree_mutex);
 	return in_len;
 
 err_copy:
@@ -603,10 +604,8 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
 
 	uobj  = uobj_get_write(uobj_get_type(xrcd), cmd.xrcd_handle,
 			       file->ucontext);
-	if (IS_ERR(uobj)) {
-		mutex_unlock(&file->device->xrcd_tree_mutex);
+	if (IS_ERR(uobj))
 		return PTR_ERR(uobj);
-	}
 
 	ret = uobj_remove_commit(uobj);
 	return ret ?: in_len;
@@ -979,6 +978,9 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	struct ib_uverbs_ex_create_cq_resp resp;
 	struct ib_cq_init_attr attr = {};
 
+	if (!ib_dev->create_cq)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	if (cmd->comp_vector >= file->device->num_comp_vectors)
 		return ERR_PTR(-EINVAL);
 
@@ -1030,14 +1032,14 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
 	resp.response_length = offsetof(typeof(resp), response_length) +
 		sizeof(resp.response_length);
 
+	cq->res.type = RDMA_RESTRACK_CQ;
+	rdma_restrack_add(&cq->res);
+
 	ret = cb(file, obj, &resp, ucore, context);
 	if (ret)
 		goto err_cb;
 
 	uobj_alloc_commit(&obj->uobject);
-	cq->res.type = RDMA_RESTRACK_CQ;
-	rdma_restrack_add(&cq->res);
-
 	return obj;
 
 err_cb:
@@ -1518,7 +1520,8 @@ static int create_qp(struct ib_uverbs_file *file,
 	if (cmd->qp_type == IB_QPT_XRC_TGT)
 		qp = ib_create_qp(pd, &attr);
 	else
-		qp = _ib_create_qp(device, pd, &attr, uhw);
+		qp = _ib_create_qp(device, pd, &attr, uhw,
+				   &obj->uevent.uobject);
 
 	if (IS_ERR(qp)) {
 		ret = PTR_ERR(qp);
@@ -1551,7 +1554,6 @@ static int create_qp(struct ib_uverbs_file *file,
 		if (ind_tbl)
 			atomic_inc(&ind_tbl->usecnt);
 	}
-	qp->uobject = &obj->uevent.uobject;
 
 	obj->uevent.uobject.object = qp;
 
@@ -1971,8 +1973,15 @@ static int modify_qp(struct ib_uverbs_file *file,
 		goto release_qp;
 	}
 
+	if ((cmd->base.attr_mask & IB_QP_AV) &&
+	    !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) {
+		ret = -EINVAL;
+		goto release_qp;
+	}
+
 	if ((cmd->base.attr_mask & IB_QP_ALT_PATH) &&
-	    !rdma_is_port_valid(qp->device, cmd->base.alt_port_num)) {
+	    (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) ||
+	    !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) {
 		ret = -EINVAL;
 		goto release_qp;
 	}
@@ -2941,6 +2950,11 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
 		wq_init_attr.create_flags = cmd.create_flags;
 	obj->uevent.events_reported = 0;
 	INIT_LIST_HEAD(&obj->uevent.event_list);
+
+	if (!pd->device->create_wq) {
+		err = -EOPNOTSUPP;
+		goto err_put_cq;
+	}
 	wq = pd->device->create_wq(pd, &wq_init_attr, uhw);
 	if (IS_ERR(wq)) {
 		err = PTR_ERR(wq);
@@ -3084,7 +3098,12 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file,
 		wq_attr.flags = cmd.flags;
 		wq_attr.flags_mask = cmd.flags_mask;
 	}
+	if (!wq->device->modify_wq) {
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
 	ret = wq->device->modify_wq(wq, &wq_attr, cmd.attr_mask, uhw);
+out:
 	uobj_put_obj_read(wq);
 	return ret;
 }
@@ -3181,6 +3200,11 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 
 	init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size;
 	init_attr.ind_tbl = wqs;
+
+	if (!ib_dev->create_rwq_ind_table) {
+		err = -EOPNOTSUPP;
+		goto err_uobj;
+	}
 	rwq_ind_tbl = ib_dev->create_rwq_ind_table(ib_dev, &init_attr, uhw);
 
 	if (IS_ERR(rwq_ind_tbl)) {
@@ -3770,6 +3794,9 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
 	struct ib_device_attr attr = {0};
 	int err;
 
+	if (!ib_dev->query_device)
+		return -EOPNOTSUPP;
+
 	if (ucore->inlen < sizeof(cmd))
 		return -EINVAL;
 
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index d96dc1d17be1..339b85145044 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -59,6 +59,9 @@ static int uverbs_process_attr(struct ib_device *ibdev,
 			return 0;
 	}
 
+	if (test_bit(attr_id, attr_bundle_h->valid_bitmap))
+		return -EINVAL;
+
 	spec = &attr_spec_bucket->attrs[attr_id];
 	e = &elements[attr_id];
 	e->uattr = uattr_ptr;
diff --git a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c
index 062485f9300d..62e1eb1d2a28 100644
--- a/drivers/infiniband/core/uverbs_ioctl_merge.c
+++ b/drivers/infiniband/core/uverbs_ioctl_merge.c
@@ -114,6 +114,7 @@ static size_t get_elements_above_id(const void **iters,
 	short min = SHRT_MAX;
 	const void *elem;
 	int i, j, last_stored = -1;
+	unsigned int equal_min = 0;
 
 	for_each_element(elem, i, j, elements, num_elements, num_offset,
 			 data_offset) {
@@ -136,6 +137,10 @@ static size_t get_elements_above_id(const void **iters,
 		 */
 		iters[last_stored == i ? num_iters - 1 : num_iters++] = elem;
 		last_stored = i;
+		if (min == GET_ID(id))
+			equal_min++;
+		else
+			equal_min = 1;
 		min = GET_ID(id);
 	}
 
@@ -146,15 +151,10 @@ static size_t get_elements_above_id(const void **iters,
 	 * Therefore, we need to clean the beginning of the array to make sure
 	 * all ids of final elements are equal to min.
 	 */
-	for (i = num_iters - 1; i >= 0 &&
-	     GET_ID(*(u16 *)(iters[i] + id_offset)) == min; i--)
-		;
-
-	num_iters -= i + 1;
-	memmove(iters, iters + i + 1, sizeof(*iters) * num_iters);
+	memmove(iters, iters + num_iters - equal_min, sizeof(*iters) * equal_min);
 
 	*min_id = min;
-	return num_iters;
+	return equal_min;
 }
 
 #define find_max_element_entry_id(num_elements, elements, num_objects_fld, \
@@ -322,7 +322,7 @@ static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_me
 		hash = kzalloc(sizeof(*hash) +
 			       ALIGN(sizeof(*hash->attrs) * (attr_max_bucket + 1),
 				     sizeof(long)) +
-			       BITS_TO_LONGS(attr_max_bucket) * sizeof(long),
+			       BITS_TO_LONGS(attr_max_bucket + 1) * sizeof(long),
 			       GFP_KERNEL);
 		if (!hash) {
 			res = -ENOMEM;
@@ -509,7 +509,7 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_
 			 * first handler which != NULL. This also defines the
 			 * set of flags used for this handler.
 			 */
-			for (i = num_object_defs - 1;
+			for (i = num_method_defs - 1;
 			     i >= 0 && !method_defs[i]->handler; i--)
 				;
 			hash->methods[min_id++] = method;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 395a3b091229..b1ca223aa380 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -650,12 +650,21 @@ static int verify_command_mask(struct ib_device *ib_dev, __u32 command)
 	return -1;
 }
 
+static bool verify_command_idx(u32 command, bool extended)
+{
+	if (extended)
+		return command < ARRAY_SIZE(uverbs_ex_cmd_table);
+
+	return command < ARRAY_SIZE(uverbs_cmd_table);
+}
+
 static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
 			     size_t count, loff_t *pos)
 {
 	struct ib_uverbs_file *file = filp->private_data;
 	struct ib_device *ib_dev;
 	struct ib_uverbs_cmd_hdr hdr;
+	bool extended_command;
 	__u32 command;
 	__u32 flags;
 	int srcu_key;
@@ -688,6 +697,15 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
 	}
 
 	command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK;
+	flags = (hdr.command &
+		 IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT;
+
+	extended_command = flags & IB_USER_VERBS_CMD_FLAG_EXTENDED;
+	if (!verify_command_idx(command, extended_command)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	if (verify_command_mask(ib_dev, command)) {
 		ret = -EOPNOTSUPP;
 		goto out;
@@ -699,12 +717,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
 		goto out;
 	}
 
-	flags = (hdr.command &
-		 IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT;
-
 	if (!flags) {
-		if (command >= ARRAY_SIZE(uverbs_cmd_table) ||
-		    !uverbs_cmd_table[command]) {
+		if (!uverbs_cmd_table[command]) {
 			ret = -EINVAL;
 			goto out;
 		}
@@ -725,8 +739,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
 		struct ib_udata uhw;
 		size_t written_count = count;
 
-		if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) ||
-		    !uverbs_ex_cmd_table[command]) {
+		if (!uverbs_ex_cmd_table[command]) {
 			ret = -ENOSYS;
 			goto out;
 		}
@@ -942,6 +955,7 @@ static const struct file_operations uverbs_fops = {
 	.llseek	 = no_llseek,
 #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS)
 	.unlocked_ioctl = ib_uverbs_ioctl,
+	.compat_ioctl = ib_uverbs_ioctl,
 #endif
 };
 
@@ -954,6 +968,7 @@ static const struct file_operations uverbs_mmap_fops = {
 	.llseek	 = no_llseek,
 #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS)
 	.unlocked_ioctl = ib_uverbs_ioctl,
+	.compat_ioctl = ib_uverbs_ioctl,
 #endif
 };
 
diff --git a/drivers/infiniband/core/uverbs_std_types.c b/drivers/infiniband/core/uverbs_std_types.c
index cab0ac3556eb..df1360e6774f 100644
--- a/drivers/infiniband/core/uverbs_std_types.c
+++ b/drivers/infiniband/core/uverbs_std_types.c
@@ -234,15 +234,18 @@ static void create_udata(struct uverbs_attr_bundle *ctx,
 		uverbs_attr_get(ctx, UVERBS_UHW_OUT);
 
 	if (!IS_ERR(uhw_in)) {
-		udata->inbuf = uhw_in->ptr_attr.ptr;
 		udata->inlen = uhw_in->ptr_attr.len;
+		if (uverbs_attr_ptr_is_inline(uhw_in))
+			udata->inbuf = &uhw_in->uattr->data;
+		else
+			udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data);
 	} else {
 		udata->inbuf = NULL;
 		udata->inlen = 0;
 	}
 
 	if (!IS_ERR(uhw_out)) {
-		udata->outbuf = uhw_out->ptr_attr.ptr;
+		udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data);
 		udata->outlen = uhw_out->ptr_attr.len;
 	} else {
 		udata->outbuf = NULL;
@@ -323,7 +326,8 @@ static int uverbs_create_cq_handler(struct ib_device *ib_dev,
 	cq->res.type = RDMA_RESTRACK_CQ;
 	rdma_restrack_add(&cq->res);
 
-	ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe);
+	ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe,
+			     sizeof(cq->cqe));
 	if (ret)
 		goto err_cq;
 
@@ -375,7 +379,7 @@ static int uverbs_destroy_cq_handler(struct ib_device *ib_dev,
 	resp.comp_events_reported  = obj->comp_events_reported;
 	resp.async_events_reported = obj->async_events_reported;
 
-	return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp);
+	return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp, sizeof(resp));
 }
 
 static DECLARE_UVERBS_METHOD(
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 16ebc6372c31..93025d2009b8 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -887,7 +887,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
 	if (qp_init_attr->cap.max_rdma_ctxs)
 		rdma_rw_init_qp(device, qp_init_attr);
 
-	qp = _ib_create_qp(device, pd, qp_init_attr, NULL);
+	qp = _ib_create_qp(device, pd, qp_init_attr, NULL, NULL);
 	if (IS_ERR(qp))
 		return qp;
 
@@ -898,7 +898,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
 	}
 
 	qp->real_qp    = qp;
-	qp->uobject    = NULL;
 	qp->qp_type    = qp_init_attr->qp_type;
 	qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl;
 
diff --git a/drivers/infiniband/hw/cxgb3/Kconfig b/drivers/infiniband/hw/cxgb3/Kconfig
index 431be733fbbe..a7b77cb3d5d5 100644
--- a/drivers/infiniband/hw/cxgb3/Kconfig
+++ b/drivers/infiniband/hw/cxgb3/Kconfig
@@ -16,12 +16,3 @@ config INFINIBAND_CXGB3
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called iw_cxgb3.
-
-config INFINIBAND_CXGB3_DEBUG
-	bool "Verbose debugging output"
-	depends on INFINIBAND_CXGB3
-	default n
-	---help---
-	  This option causes the Chelsio RDMA driver to produce copious
-	  amounts of debug messages.  Select this if you are developing
-	  the driver or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile
index 2c66d35d19bd..66fe0917aba0 100644
--- a/drivers/infiniband/hw/cxgb3/Makefile
+++ b/drivers/infiniband/hw/cxgb3/Makefile
@@ -5,5 +5,3 @@ obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
 
 iw_cxgb3-y :=  iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
 	       iwch_provider.o iwch.o cxio_hal.o cxio_resource.o
-
-ccflags-$(CONFIG_INFINIBAND_CXGB3_DEBUG) += -DDEBUG
diff --git a/drivers/infiniband/hw/cxgb3/cxio_dbg.c b/drivers/infiniband/hw/cxgb3/cxio_dbg.c
deleted file mode 100644
index 97dbe728520a..000000000000
--- a/drivers/infiniband/hw/cxgb3/cxio_dbg.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifdef DEBUG
-#include <linux/types.h>
-#include <linux/slab.h>
-#include "common.h"
-#include "cxgb3_ioctl.h"
-#include "cxio_hal.h"
-#include "cxio_wr.h"
-
-void cxio_dump_tpt(struct cxio_rdev *rdev, u32 stag)
-{
-	struct ch_mem_range *m;
-	u64 *data;
-	int rc;
-	int size = 32;
-
-	m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
-	if (!m)
-		return;
-
-	m->mem_id = MEM_PMRX;
-	m->addr = (stag>>8) * 32 + rdev->rnic_info.tpt_base;
-	m->len = size;
-	pr_debug("%s TPT addr 0x%x len %d\n", __func__, m->addr, m->len);
-	rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
-	if (rc) {
-		pr_debug("%s toectl returned error %d\n", __func__, rc);
-		kfree(m);
-		return;
-	}
-
-	data = (u64 *)m->buf;
-	while (size > 0) {
-		pr_debug("TPT %08x: %016llx\n",
-			 m->addr, (unsigned long long)*data);
-		size -= 8;
-		data++;
-		m->addr += 8;
-	}
-	kfree(m);
-}
-
-void cxio_dump_pbl(struct cxio_rdev *rdev, u32 pbl_addr, uint len, u8 shift)
-{
-	struct ch_mem_range *m;
-	u64 *data;
-	int rc;
-	int size, npages;
-
-	shift += 12;
-	npages = (len + (1ULL << shift) - 1) >> shift;
-	size = npages * sizeof(u64);
-
-	m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
-	if (!m)
-		return;
-
-	m->mem_id = MEM_PMRX;
-	m->addr = pbl_addr;
-	m->len = size;
-	pr_debug("%s PBL addr 0x%x len %d depth %d\n",
-		 __func__, m->addr, m->len, npages);
-	rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
-	if (rc) {
-		pr_debug("%s toectl returned error %d\n", __func__, rc);
-		kfree(m);
-		return;
-	}
-
-	data = (u64 *)m->buf;
-	while (size > 0) {
-		pr_debug("PBL %08x: %016llx\n",
-			 m->addr, (unsigned long long)*data);
-		size -= 8;
-		data++;
-		m->addr += 8;
-	}
-	kfree(m);
-}
-
-void cxio_dump_wqe(union t3_wr *wqe)
-{
-	__be64 *data = (__be64 *)wqe;
-	uint size = (uint)(be64_to_cpu(*data) & 0xff);
-
-	if (size == 0)
-		size = 8;
-	while (size > 0) {
-		pr_debug("WQE %p: %016llx\n",
-			 data, (unsigned long long)be64_to_cpu(*data));
-		size--;
-		data++;
-	}
-}
-
-void cxio_dump_wce(struct t3_cqe *wce)
-{
-	__be64 *data = (__be64 *)wce;
-	int size = sizeof(*wce);
-
-	while (size > 0) {
-		pr_debug("WCE %p: %016llx\n",
-			 data, (unsigned long long)be64_to_cpu(*data));
-		size -= 8;
-		data++;
-	}
-}
-
-void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents)
-{
-	struct ch_mem_range *m;
-	int size = nents * 64;
-	u64 *data;
-	int rc;
-
-	m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
-	if (!m)
-		return;
-
-	m->mem_id = MEM_PMRX;
-	m->addr = ((hwtid)<<10) + rdev->rnic_info.rqt_base;
-	m->len = size;
-	pr_debug("%s RQT addr 0x%x len %d\n", __func__, m->addr, m->len);
-	rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
-	if (rc) {
-		pr_debug("%s toectl returned error %d\n", __func__, rc);
-		kfree(m);
-		return;
-	}
-
-	data = (u64 *)m->buf;
-	while (size > 0) {
-		pr_debug("RQT %08x: %016llx\n",
-			 m->addr, (unsigned long long)*data);
-		size -= 8;
-		data++;
-		m->addr += 8;
-	}
-	kfree(m);
-}
-
-void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid)
-{
-	struct ch_mem_range *m;
-	int size = TCB_SIZE;
-	u32 *data;
-	int rc;
-
-	m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
-	if (!m)
-		return;
-
-	m->mem_id = MEM_CM;
-	m->addr = hwtid * size;
-	m->len = size;
-	pr_debug("%s TCB %d len %d\n", __func__, m->addr, m->len);
-	rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
-	if (rc) {
-		pr_debug("%s toectl returned error %d\n", __func__, rc);
-		kfree(m);
-		return;
-	}
-
-	data = (u32 *)m->buf;
-	while (size > 0) {
-		printk("%2u: %08x %08x %08x %08x %08x %08x %08x %08x\n",
-			m->addr,
-			*(data+2), *(data+3), *(data),*(data+1),
-			*(data+6), *(data+7), *(data+4), *(data+5));
-		size -= 32;
-		data += 8;
-		m->addr += 32;
-	}
-	kfree(m);
-}
-#endif
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index 7e70c5492262..c64e50b5a548 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -202,13 +202,4 @@ int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb);
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#ifdef DEBUG
-void cxio_dump_tpt(struct cxio_rdev *rev, u32 stag);
-void cxio_dump_pbl(struct cxio_rdev *rev, u32 pbl_addr, uint len, u8 shift);
-void cxio_dump_wqe(union t3_wr *wqe);
-void cxio_dump_wce(struct t3_cqe *wce);
-void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents);
-void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid);
-#endif
-
 #endif
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cq.c b/drivers/infiniband/hw/cxgb3/iwch_cq.c
index dd5348e48806..0a8542c20804 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cq.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cq.c
@@ -200,9 +200,6 @@ int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
 
 	spin_lock_irqsave(&chp->lock, flags);
 	for (npolled = 0; npolled < num_entries; ++npolled) {
-#ifdef DEBUG
-		int i=0;
-#endif
 
 		/*
 		 * Because T3 can post CQEs that are _not_ associated
@@ -211,9 +208,6 @@ int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
 		 */
 		do {
 			err = iwch_poll_cq_one(rhp, chp, wc + npolled);
-#ifdef DEBUG
-			BUG_ON(++i > 1000);
-#endif
 		} while (err == -EAGAIN);
 		if (err <= 0)
 			break;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
index da13bd7c3ca9..47e1b6ac1e1a 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -1687,13 +1687,13 @@ static int hns_roce_v1_post_mbox(struct hns_roce_dev *hr_dev, u64 in_param,
 	roce_set_field(val, ROCEE_MB6_ROCEE_MB_TOKEN_M,
 		       ROCEE_MB6_ROCEE_MB_TOKEN_S, token);
 
-	__raw_writeq(cpu_to_le64(in_param), hcr + 0);
-	__raw_writeq(cpu_to_le64(out_param), hcr + 2);
-	__raw_writel(cpu_to_le32(in_modifier), hcr + 4);
+	writeq(in_param, hcr + 0);
+	writeq(out_param, hcr + 2);
+	writel(in_modifier, hcr + 4);
 	/* Memory barrier */
 	wmb();
 
-	__raw_writel(cpu_to_le32(val), hcr + 5);
+	writel(val, hcr + 5);
 
 	mmiowb();
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index db2ff352d75f..016bca1923ec 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -509,7 +509,7 @@ static int hns_roce_v2_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 	spin_lock_irqsave(&hr_qp->rq.lock, flags);
 	ind = hr_qp->rq.head & (hr_qp->rq.wqe_cnt - 1);
 
-	if (hr_qp->state == IB_QPS_RESET || hr_qp->state == IB_QPS_ERR) {
+	if (hr_qp->state == IB_QPS_RESET) {
 		spin_unlock_irqrestore(&hr_qp->rq.lock, flags);
 		*bad_wr = wr;
 		return -EINVAL;
@@ -1228,14 +1228,14 @@ static int hns_roce_v2_post_mbox(struct hns_roce_dev *hr_dev, u64 in_param,
 	roce_set_field(val1, HNS_ROCE_VF_MB5_TOKEN_MASK,
 		       HNS_ROCE_VF_MB5_TOKEN_SHIFT, token);
 
-	__raw_writeq(cpu_to_le64(in_param), hcr + 0);
-	__raw_writeq(cpu_to_le64(out_param), hcr + 2);
+	writeq(in_param, hcr + 0);
+	writeq(out_param, hcr + 2);
 
 	/* Memory barrier */
 	wmb();
 
-	__raw_writel(cpu_to_le32(val0), hcr + 4);
-	__raw_writel(cpu_to_le32(val1), hcr + 5);
+	writel(val0, hcr + 4);
+	writel(val1, hcr + 5);
 
 	mmiowb();
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index eb9a69fc7bec..8255bb9021b0 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -100,6 +100,7 @@ static int hns_roce_del_gid(struct ib_device *device, u8 port_num,
 			    unsigned int index, void **context)
 {
 	struct hns_roce_dev *hr_dev = to_hr_dev(device);
+	struct ib_gid_attr zattr = { };
 	union ib_gid zgid = { {0} };
 	u8 port = port_num - 1;
 	unsigned long flags;
@@ -110,7 +111,7 @@ static int hns_roce_del_gid(struct ib_device *device, u8 port_num,
 
 	spin_lock_irqsave(&hr_dev->iboe.lock, flags);
 
-	ret = hr_dev->hw->set_gid(hr_dev, port, index, &zgid, NULL);
+	ret = hr_dev->hw->set_gid(hr_dev, port, index, &zgid, &zattr);
 
 	spin_unlock_irqrestore(&hr_dev->iboe.lock, flags);
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index da86a8117bd5..f7256d88d38f 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -933,7 +933,7 @@ int hns_roce_ib_umem_write_mtt(struct hns_roce_dev *hr_dev,
 		ret = hns_roce_write_mtt(hr_dev, mtt, n, i, pages);
 
 out:
-	free_page((unsigned long) pages);
+	free_pages((unsigned long) pages, order);
 	return ret;
 }
 
diff --git a/drivers/infiniband/hw/usnic/usnic_transport.c b/drivers/infiniband/hw/usnic/usnic_transport.c
index de318389a301..67de94343cb4 100644
--- a/drivers/infiniband/hw/usnic/usnic_transport.c
+++ b/drivers/infiniband/hw/usnic/usnic_transport.c
@@ -174,14 +174,13 @@ void usnic_transport_put_socket(struct socket *sock)
 int usnic_transport_sock_get_addr(struct socket *sock, int *proto,
 					uint32_t *addr, uint16_t *port)
 {
-	int len;
 	int err;
 	struct sockaddr_in sock_addr;
 
 	err = sock->ops->getname(sock,
 				(struct sockaddr *)&sock_addr,
-				&len, 0);
-	if (err)
+				0);
+	if (err < 0)
 		return err;
 
 	if (sock_addr.sin_family != AF_INET)
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
index faa9478c14a6..f95b97646c25 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
@@ -114,6 +114,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
 	union pvrdma_cmd_resp rsp;
 	struct pvrdma_cmd_create_cq *cmd = &req.create_cq;
 	struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp;
+	struct pvrdma_create_cq_resp cq_resp = {0};
 	struct pvrdma_create_cq ucmd;
 
 	BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64);
@@ -197,6 +198,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
 
 	cq->ibcq.cqe = resp->cqe;
 	cq->cq_handle = resp->cq_handle;
+	cq_resp.cqn = resp->cq_handle;
 	spin_lock_irqsave(&dev->cq_tbl_lock, flags);
 	dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq;
 	spin_unlock_irqrestore(&dev->cq_tbl_lock, flags);
@@ -205,7 +207,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
 		cq->uar = &(to_vucontext(context)->uar);
 
 		/* Copy udata back. */
-		if (ib_copy_to_udata(udata, &cq->cq_handle, sizeof(__u32))) {
+		if (ib_copy_to_udata(udata, &cq_resp, sizeof(cq_resp))) {
 			dev_warn(&dev->pdev->dev,
 				 "failed to copy back udata\n");
 			pvrdma_destroy_cq(&cq->ibcq);
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c
index 5acebb1ef631..af235967a9c2 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c
@@ -113,6 +113,7 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd,
 	union pvrdma_cmd_resp rsp;
 	struct pvrdma_cmd_create_srq *cmd = &req.create_srq;
 	struct pvrdma_cmd_create_srq_resp *resp = &rsp.create_srq_resp;
+	struct pvrdma_create_srq_resp srq_resp = {0};
 	struct pvrdma_create_srq ucmd;
 	unsigned long flags;
 	int ret;
@@ -204,12 +205,13 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd,
 	}
 
 	srq->srq_handle = resp->srqn;
+	srq_resp.srqn = resp->srqn;
 	spin_lock_irqsave(&dev->srq_tbl_lock, flags);
 	dev->srq_tbl[srq->srq_handle % dev->dsr->caps.max_srq] = srq;
 	spin_unlock_irqrestore(&dev->srq_tbl_lock, flags);
 
 	/* Copy udata back. */
-	if (ib_copy_to_udata(udata, &srq->srq_handle, sizeof(__u32))) {
+	if (ib_copy_to_udata(udata, &srq_resp, sizeof(srq_resp))) {
 		dev_warn(&dev->pdev->dev, "failed to copy back udata\n");
 		pvrdma_destroy_srq(&srq->ibsrq);
 		return ERR_PTR(-EINVAL);
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
index 16b96616ef7e..a51463cd2f37 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
@@ -447,6 +447,7 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev,
 	union pvrdma_cmd_resp rsp;
 	struct pvrdma_cmd_create_pd *cmd = &req.create_pd;
 	struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp;
+	struct pvrdma_alloc_pd_resp pd_resp = {0};
 	int ret;
 	void *ptr;
 
@@ -475,9 +476,10 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev,
 	pd->privileged = !context;
 	pd->pd_handle = resp->pd_handle;
 	pd->pdn = resp->pd_handle;
+	pd_resp.pdn = resp->pd_handle;
 
 	if (context) {
-		if (ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) {
+		if (ib_copy_to_udata(udata, &pd_resp, sizeof(pd_resp))) {
 			dev_warn(&dev->pdev->dev,
 				 "failed to copy back protection domain\n");
 			pvrdma_dealloc_pd(&pd->ibpd);
diff --git a/drivers/infiniband/sw/rxe/rxe_av.c b/drivers/infiniband/sw/rxe/rxe_av.c
index 7522d1af3ae2..7f1ae364088a 100644
--- a/drivers/infiniband/sw/rxe/rxe_av.c
+++ b/drivers/infiniband/sw/rxe/rxe_av.c
@@ -74,8 +74,9 @@ void rxe_av_fill_ip_info(struct rxe_av *av,
 			struct ib_gid_attr *sgid_attr,
 			union ib_gid *sgid)
 {
-	rdma_gid2ip(&av->sgid_addr._sockaddr, sgid);
-	rdma_gid2ip(&av->dgid_addr._sockaddr, &rdma_ah_read_grh(attr)->dgid);
+	rdma_gid2ip((struct sockaddr *)&av->sgid_addr, sgid);
+	rdma_gid2ip((struct sockaddr *)&av->dgid_addr,
+		    &rdma_ah_read_grh(attr)->dgid);
 	av->network_type = ib_gid_to_network_type(sgid_attr->gid_type, sgid);
 }
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index 11f74cbe6660..ea302b054601 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -281,8 +281,6 @@ void ipoib_delete_debug_files(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = ipoib_priv(dev);
 
-	WARN_ONCE(!priv->mcg_dentry, "null mcg debug file\n");
-	WARN_ONCE(!priv->path_dentry, "null path debug file\n");
 	debugfs_remove(priv->mcg_dentry);
 	debugfs_remove(priv->path_dentry);
 	priv->mcg_dentry = priv->path_dentry = NULL;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index b48843833d69..241c0e72dce3 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -3871,12 +3871,10 @@ static ssize_t srp_create_target(struct device *dev,
 				      num_online_nodes());
 		const int ch_end = ((node_idx + 1) * target->ch_count /
 				    num_online_nodes());
-		const int cv_start = (node_idx * ibdev->num_comp_vectors /
-				      num_online_nodes() + target->comp_vector)
-				     % ibdev->num_comp_vectors;
-		const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors /
-				    num_online_nodes() + target->comp_vector)
-				   % ibdev->num_comp_vectors;
+		const int cv_start = node_idx * ibdev->num_comp_vectors /
+				     num_online_nodes();
+		const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors /
+				   num_online_nodes();
 		int cpu_idx = 0;
 
 		for_each_online_cpu(cpu) {
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 1f316d66e6f7..41614c185918 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -218,8 +218,10 @@ static void matrix_keypad_stop(struct input_dev *dev)
 {
 	struct matrix_keypad *keypad = input_get_drvdata(dev);
 
+	spin_lock_irq(&keypad->lock);
 	keypad->stopped = true;
-	mb();
+	spin_unlock_irq(&keypad->lock);
+
 	flush_work(&keypad->work.work);
 	/*
 	 * matrix_keypad_scan() will leave IRQs enabled;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 3d2e23a0ae39..dcb8e0cfaa1a 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1228,32 +1228,39 @@ static void set_abs_position_params(struct input_dev *dev,
 	input_abs_set_res(dev, y_code, info->y_res);
 }
 
-static void set_input_params(struct psmouse *psmouse,
-			     struct synaptics_data *priv)
+static int set_input_params(struct psmouse *psmouse,
+			    struct synaptics_data *priv)
 {
 	struct input_dev *dev = psmouse->dev;
 	struct synaptics_device_info *info = &priv->info;
 	int i;
+	int error;
+
+	/* Reset default psmouse capabilities */
+	__clear_bit(EV_REL, dev->evbit);
+	bitmap_zero(dev->relbit, REL_CNT);
+	bitmap_zero(dev->keybit, KEY_CNT);
 
 	/* Things that apply to both modes */
 	__set_bit(INPUT_PROP_POINTER, dev->propbit);
-	__set_bit(EV_KEY, dev->evbit);
-	__set_bit(BTN_LEFT, dev->keybit);
-	__set_bit(BTN_RIGHT, dev->keybit);
 
-	if (SYN_CAP_MIDDLE_BUTTON(info->capabilities))
-		__set_bit(BTN_MIDDLE, dev->keybit);
+	input_set_capability(dev, EV_KEY, BTN_LEFT);
+
+	/* Clickpads report only left button */
+	if (!SYN_CAP_CLICKPAD(info->ext_cap_0c)) {
+		input_set_capability(dev, EV_KEY, BTN_RIGHT);
+		if (SYN_CAP_MIDDLE_BUTTON(info->capabilities))
+			input_set_capability(dev, EV_KEY, BTN_MIDDLE);
+	}
 
 	if (!priv->absolute_mode) {
 		/* Relative mode */
-		__set_bit(EV_REL, dev->evbit);
-		__set_bit(REL_X, dev->relbit);
-		__set_bit(REL_Y, dev->relbit);
-		return;
+		input_set_capability(dev, EV_REL, REL_X);
+		input_set_capability(dev, EV_REL, REL_Y);
+		return 0;
 	}
 
 	/* Absolute mode */
-	__set_bit(EV_ABS, dev->evbit);
 	set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y);
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
@@ -1265,11 +1272,15 @@ static void set_input_params(struct psmouse *psmouse,
 					ABS_MT_POSITION_X, ABS_MT_POSITION_Y);
 		/* Image sensors can report per-contact pressure */
 		input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
-		input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK);
+
+		error = input_mt_init_slots(dev, 2,
+					    INPUT_MT_POINTER | INPUT_MT_TRACK);
+		if (error)
+			return error;
 
 		/* Image sensors can signal 4 and 5 finger clicks */
-		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
-		__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_QUADTAP);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_QUINTTAP);
 	} else if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) {
 		set_abs_position_params(dev, info,
 					ABS_MT_POSITION_X, ABS_MT_POSITION_Y);
@@ -1277,10 +1288,13 @@ static void set_input_params(struct psmouse *psmouse,
 		 * Profile sensor in CR-48 tracks contacts reasonably well,
 		 * other non-image sensors with AGM use semi-mt.
 		 */
-		input_mt_init_slots(dev, 2,
-				    INPUT_MT_POINTER |
-				    (cr48_profile_sensor ?
-					INPUT_MT_TRACK : INPUT_MT_SEMI_MT));
+		error = input_mt_init_slots(dev, 2,
+					    INPUT_MT_POINTER |
+					     (cr48_profile_sensor ?
+					      INPUT_MT_TRACK :
+					      INPUT_MT_SEMI_MT));
+		if (error)
+			return error;
 
 		/*
 		 * For semi-mt devices we send ABS_X/Y ourselves instead of
@@ -1296,37 +1310,32 @@ static void set_input_params(struct psmouse *psmouse,
 	if (SYN_CAP_PALMDETECT(info->capabilities))
 		input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
 
-	__set_bit(BTN_TOUCH, dev->keybit);
-	__set_bit(BTN_TOOL_FINGER, dev->keybit);
+	input_set_capability(dev, EV_KEY, BTN_TOUCH);
+	input_set_capability(dev, EV_KEY, BTN_TOOL_FINGER);
 
 	if (synaptics_has_multifinger(priv)) {
-		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
-		__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_DOUBLETAP);
+		input_set_capability(dev, EV_KEY, BTN_TOOL_TRIPLETAP);
 	}
 
 	if (SYN_CAP_FOUR_BUTTON(info->capabilities) ||
 	    SYN_CAP_MIDDLE_BUTTON(info->capabilities)) {
-		__set_bit(BTN_FORWARD, dev->keybit);
-		__set_bit(BTN_BACK, dev->keybit);
+		input_set_capability(dev, EV_KEY, BTN_FORWARD);
+		input_set_capability(dev, EV_KEY, BTN_BACK);
 	}
 
 	if (!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10))
 		for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(info->ext_cap); i++)
-			__set_bit(BTN_0 + i, dev->keybit);
-
-	__clear_bit(EV_REL, dev->evbit);
-	__clear_bit(REL_X, dev->relbit);
-	__clear_bit(REL_Y, dev->relbit);
+			input_set_capability(dev, EV_KEY, BTN_0 + i);
 
 	if (SYN_CAP_CLICKPAD(info->ext_cap_0c)) {
 		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
 		if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
 		    !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10))
 			__set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
-		/* Clickpads report only left button */
-		__clear_bit(BTN_RIGHT, dev->keybit);
-		__clear_bit(BTN_MIDDLE, dev->keybit);
 	}
+
+	return 0;
 }
 
 static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
@@ -1564,7 +1573,12 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
 		     info->capabilities, info->ext_cap, info->ext_cap_0c,
 		     info->ext_cap_10, info->board_id, info->firmware_id);
 
-	set_input_params(psmouse, priv);
+	err = set_input_params(psmouse, priv);
+	if (err) {
+		psmouse_err(psmouse,
+			    "failed to set up capabilities: %d\n", err);
+		goto init_fail;
+	}
 
 	/*
 	 * Encode touchpad model so that it can be used to set
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index db4f6bb502e3..a5ab774da4cc 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -1,11 +1,8 @@
-/*
- * Copyright (C) 2012 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+// Melfas MMS114/MMS152 touchscreen device driver
+//
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+// Author: Joonyoung Shim <jy0922.shim@samsung.com>
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -624,4 +621,4 @@ module_i2c_driver(mms114_driver);
 /* Module information */
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
 MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index f16f8358c70a..894843a7ec7b 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -38,6 +38,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-sg.h>
 
@@ -81,7 +82,10 @@ struct sur40_blob {
 
 	__le32 area;       /* size in pixels/pressure (?) */
 
-	u8 padding[32];
+	u8 padding[24];
+
+	__le32 tag_id;     /* valid when type == 0x04 (SUR40_TAG) */
+	__le32 unknown;
 
 } __packed;
 
@@ -146,6 +150,40 @@ struct sur40_image_header {
 #define SUR40_TOUCH	0x02
 #define SUR40_TAG	0x04
 
+/* video controls */
+#define SUR40_BRIGHTNESS_MAX 0xff
+#define SUR40_BRIGHTNESS_MIN 0x00
+#define SUR40_BRIGHTNESS_DEF 0xff
+
+#define SUR40_CONTRAST_MAX 0x0f
+#define SUR40_CONTRAST_MIN 0x00
+#define SUR40_CONTRAST_DEF 0x0a
+
+#define SUR40_GAIN_MAX 0x09
+#define SUR40_GAIN_MIN 0x00
+#define SUR40_GAIN_DEF 0x08
+
+#define SUR40_BACKLIGHT_MAX 0x01
+#define SUR40_BACKLIGHT_MIN 0x00
+#define SUR40_BACKLIGHT_DEF 0x01
+
+#define sur40_str(s) #s
+#define SUR40_PARAM_RANGE(lo, hi) " (range " sur40_str(lo) "-" sur40_str(hi) ")"
+
+/* module parameters */
+static uint brightness = SUR40_BRIGHTNESS_DEF;
+module_param(brightness, uint, 0644);
+MODULE_PARM_DESC(brightness, "set initial brightness"
+	SUR40_PARAM_RANGE(SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX));
+static uint contrast = SUR40_CONTRAST_DEF;
+module_param(contrast, uint, 0644);
+MODULE_PARM_DESC(contrast, "set initial contrast"
+	SUR40_PARAM_RANGE(SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX));
+static uint gain = SUR40_GAIN_DEF;
+module_param(gain, uint, 0644);
+MODULE_PARM_DESC(gain, "set initial gain"
+	SUR40_PARAM_RANGE(SUR40_GAIN_MIN, SUR40_GAIN_MAX));
+
 static const struct v4l2_pix_format sur40_pix_format[] = {
 	{
 		.pixelformat = V4L2_TCH_FMT_TU08,
@@ -178,6 +216,7 @@ struct sur40_state {
 	struct video_device vdev;
 	struct mutex lock;
 	struct v4l2_pix_format pix_fmt;
+	struct v4l2_ctrl_handler hdl;
 
 	struct vb2_queue queue;
 	struct list_head buf_list;
@@ -187,6 +226,7 @@ struct sur40_state {
 	struct sur40_data *bulk_in_buffer;
 	size_t bulk_in_size;
 	u8 bulk_in_epaddr;
+	u8 vsvideo;
 
 	char phys[64];
 };
@@ -200,6 +240,11 @@ struct sur40_buffer {
 static const struct video_device sur40_video_device;
 static const struct vb2_queue sur40_queue;
 static void sur40_process_video(struct sur40_state *sur40);
+static int sur40_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops sur40_ctrl_ops = {
+	.s_ctrl = sur40_s_ctrl,
+};
 
 /*
  * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT
@@ -220,6 +265,81 @@ static int sur40_command(struct sur40_state *dev,
 			       0x00, index, buffer, size, 1000);
 }
 
+/* poke a byte in the panel register space */
+static int sur40_poke(struct sur40_state *dev, u8 offset, u8 value)
+{
+	int result;
+	u8 index = 0x96; // 0xae for permanent write
+
+	result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+		SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0x32, index, NULL, 0, 1000);
+	if (result < 0)
+		goto error;
+	msleep(5);
+
+	result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+		SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0x72, offset, NULL, 0, 1000);
+	if (result < 0)
+		goto error;
+	msleep(5);
+
+	result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+		SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0xb2, value, NULL, 0, 1000);
+	if (result < 0)
+		goto error;
+	msleep(5);
+
+error:
+	return result;
+}
+
+static int sur40_set_preprocessor(struct sur40_state *dev, u8 value)
+{
+	u8 setting_07[2] = { 0x01, 0x00 };
+	u8 setting_17[2] = { 0x85, 0x80 };
+	int result;
+
+	if (value > 1)
+		return -ERANGE;
+
+	result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+		SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0x07, setting_07[value], NULL, 0, 1000);
+	if (result < 0)
+		goto error;
+	msleep(5);
+
+	result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+		SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0x17, setting_17[value], NULL, 0, 1000);
+	if (result < 0)
+		goto error;
+	msleep(5);
+
+error:
+	return result;
+}
+
+static void sur40_set_vsvideo(struct sur40_state *handle, u8 value)
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		sur40_poke(handle, 0x1c+i, value);
+	handle->vsvideo = value;
+}
+
+static void sur40_set_irlevel(struct sur40_state *handle, u8 value)
+{
+	int i;
+
+	for (i = 0; i < 8; i++)
+		sur40_poke(handle, 0x08+(2*i), value);
+}
+
 /* Initialization routine, called from sur40_open */
 static int sur40_init(struct sur40_state *dev)
 {
@@ -631,6 +751,36 @@ static int sur40_probe(struct usb_interface *interface,
 	sur40->vdev.queue = &sur40->queue;
 	video_set_drvdata(&sur40->vdev, sur40);
 
+	/* initialize the control handler for 4 controls */
+	v4l2_ctrl_handler_init(&sur40->hdl, 4);
+	sur40->v4l2.ctrl_handler = &sur40->hdl;
+	sur40->vsvideo = (SUR40_CONTRAST_DEF << 4) | SUR40_GAIN_DEF;
+
+	v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_BRIGHTNESS,
+	  SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX, 1, clamp(brightness,
+	  (uint)SUR40_BRIGHTNESS_MIN, (uint)SUR40_BRIGHTNESS_MAX));
+
+	v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_CONTRAST,
+	  SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX, 1, clamp(contrast,
+	  (uint)SUR40_CONTRAST_MIN, (uint)SUR40_CONTRAST_MAX));
+
+	v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_GAIN,
+	  SUR40_GAIN_MIN, SUR40_GAIN_MAX, 1, clamp(gain,
+	  (uint)SUR40_GAIN_MIN, (uint)SUR40_GAIN_MAX));
+
+	v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops,
+	  V4L2_CID_BACKLIGHT_COMPENSATION, SUR40_BACKLIGHT_MIN,
+	  SUR40_BACKLIGHT_MAX, 1, SUR40_BACKLIGHT_DEF);
+
+	v4l2_ctrl_handler_setup(&sur40->hdl);
+
+	if (sur40->hdl.error) {
+		dev_err(&interface->dev,
+			"Unable to register video controls.");
+		v4l2_ctrl_handler_free(&sur40->hdl);
+		goto err_unreg_v4l2;
+	}
+
 	error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1);
 	if (error) {
 		dev_err(&interface->dev,
@@ -663,6 +813,7 @@ static void sur40_disconnect(struct usb_interface *interface)
 {
 	struct sur40_state *sur40 = usb_get_intfdata(interface);
 
+	v4l2_ctrl_handler_free(&sur40->hdl);
 	video_unregister_device(&sur40->vdev);
 	v4l2_device_unregister(&sur40->v4l2);
 
@@ -856,6 +1007,31 @@ static int sur40_vidioc_g_fmt(struct file *file, void *priv,
 	return 0;
 }
 
+static int sur40_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct sur40_state *sur40  = container_of(ctrl->handler,
+	  struct sur40_state, hdl);
+	u8 value = sur40->vsvideo;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		sur40_set_irlevel(sur40, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		value = (value & 0x0f) | (ctrl->val << 4);
+		sur40_set_vsvideo(sur40, value);
+		break;
+	case V4L2_CID_GAIN:
+		value = (value & 0xf0) | (ctrl->val);
+		sur40_set_vsvideo(sur40, value);
+		break;
+	case V4L2_CID_BACKLIGHT_COMPENSATION:
+		sur40_set_preprocessor(sur40, ctrl->val);
+		break;
+	}
+	return 0;
+}
+
 static int sur40_ioctl_parm(struct file *file, void *priv,
 			    struct v4l2_streamparm *p)
 {
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 74788fdeb773..5f5a4e9f2038 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -1056,9 +1056,9 @@ static int iommu_queue_command_sync(struct amd_iommu *iommu,
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&iommu->lock, flags);
+	raw_spin_lock_irqsave(&iommu->lock, flags);
 	ret = __iommu_queue_command_sync(iommu, cmd, sync);
-	spin_unlock_irqrestore(&iommu->lock, flags);
+	raw_spin_unlock_irqrestore(&iommu->lock, flags);
 
 	return ret;
 }
@@ -1084,7 +1084,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
 
 	build_completion_wait(&cmd, (u64)&iommu->cmd_sem);
 
-	spin_lock_irqsave(&iommu->lock, flags);
+	raw_spin_lock_irqsave(&iommu->lock, flags);
 
 	iommu->cmd_sem = 0;
 
@@ -1095,7 +1095,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
 	ret = wait_on_sem(&iommu->cmd_sem);
 
 out_unlock:
-	spin_unlock_irqrestore(&iommu->lock, flags);
+	raw_spin_unlock_irqrestore(&iommu->lock, flags);
 
 	return ret;
 }
@@ -3050,7 +3050,7 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
 	size_t unmap_size;
 
 	if (domain->mode == PAGE_MODE_NONE)
-		return -EINVAL;
+		return 0;
 
 	mutex_lock(&domain->api_lock);
 	unmap_size = iommu_unmap_page(domain, iova, page_size);
@@ -3595,7 +3595,22 @@ static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
 	amd_iommu_dev_table[devid].data[2] = dte;
 }
 
-static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic)
+static struct irq_remap_table *get_irq_table(u16 devid)
+{
+	struct irq_remap_table *table;
+
+	if (WARN_ONCE(!amd_iommu_rlookup_table[devid],
+		      "%s: no iommu for devid %x\n", __func__, devid))
+		return NULL;
+
+	table = irq_lookup_table[devid];
+	if (WARN_ONCE(!table, "%s: no table for devid %x\n", __func__, devid))
+		return NULL;
+
+	return table;
+}
+
+static struct irq_remap_table *alloc_irq_table(u16 devid, bool ioapic)
 {
 	struct irq_remap_table *table = NULL;
 	struct amd_iommu *iommu;
@@ -3627,7 +3642,7 @@ static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic)
 		goto out_unlock;
 
 	/* Initialize table spin-lock */
-	spin_lock_init(&table->lock);
+	raw_spin_lock_init(&table->lock);
 
 	if (ioapic)
 		/* Keep the first 32 indexes free for IOAPIC interrupts */
@@ -3682,14 +3697,14 @@ static int alloc_irq_index(u16 devid, int count, bool align)
 	if (!iommu)
 		return -ENODEV;
 
-	table = get_irq_table(devid, false);
+	table = alloc_irq_table(devid, false);
 	if (!table)
 		return -ENODEV;
 
 	if (align)
 		alignment = roundup_pow_of_two(count);
 
-	spin_lock_irqsave(&table->lock, flags);
+	raw_spin_lock_irqsave(&table->lock, flags);
 
 	/* Scan table for free entries */
 	for (index = ALIGN(table->min_index, alignment), c = 0;
@@ -3716,7 +3731,7 @@ static int alloc_irq_index(u16 devid, int count, bool align)
 	index = -ENOSPC;
 
 out:
-	spin_unlock_irqrestore(&table->lock, flags);
+	raw_spin_unlock_irqrestore(&table->lock, flags);
 
 	return index;
 }
@@ -3733,11 +3748,11 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
 	if (iommu == NULL)
 		return -EINVAL;
 
-	table = get_irq_table(devid, false);
+	table = get_irq_table(devid);
 	if (!table)
 		return -ENOMEM;
 
-	spin_lock_irqsave(&table->lock, flags);
+	raw_spin_lock_irqsave(&table->lock, flags);
 
 	entry = (struct irte_ga *)table->table;
 	entry = &entry[index];
@@ -3748,7 +3763,7 @@ static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
 	if (data)
 		data->ref = entry;
 
-	spin_unlock_irqrestore(&table->lock, flags);
+	raw_spin_unlock_irqrestore(&table->lock, flags);
 
 	iommu_flush_irt(iommu, devid);
 	iommu_completion_wait(iommu);
@@ -3766,13 +3781,13 @@ static int modify_irte(u16 devid, int index, union irte *irte)
 	if (iommu == NULL)
 		return -EINVAL;
 
-	table = get_irq_table(devid, false);
+	table = get_irq_table(devid);
 	if (!table)
 		return -ENOMEM;
 
-	spin_lock_irqsave(&table->lock, flags);
+	raw_spin_lock_irqsave(&table->lock, flags);
 	table->table[index] = irte->val;
-	spin_unlock_irqrestore(&table->lock, flags);
+	raw_spin_unlock_irqrestore(&table->lock, flags);
 
 	iommu_flush_irt(iommu, devid);
 	iommu_completion_wait(iommu);
@@ -3790,13 +3805,13 @@ static void free_irte(u16 devid, int index)
 	if (iommu == NULL)
 		return;
 
-	table = get_irq_table(devid, false);
+	table = get_irq_table(devid);
 	if (!table)
 		return;
 
-	spin_lock_irqsave(&table->lock, flags);
+	raw_spin_lock_irqsave(&table->lock, flags);
 	iommu->irte_ops->clear_allocated(table, index);
-	spin_unlock_irqrestore(&table->lock, flags);
+	raw_spin_unlock_irqrestore(&table->lock, flags);
 
 	iommu_flush_irt(iommu, devid);
 	iommu_completion_wait(iommu);
@@ -3877,10 +3892,8 @@ static void irte_ga_set_affinity(void *entry, u16 devid, u16 index,
 				 u8 vector, u32 dest_apicid)
 {
 	struct irte_ga *irte = (struct irte_ga *) entry;
-	struct iommu_dev_data *dev_data = search_dev_data(devid);
 
-	if (!dev_data || !dev_data->use_vapic ||
-	    !irte->lo.fields_remap.guest_mode) {
+	if (!irte->lo.fields_remap.guest_mode) {
 		irte->hi.fields.vector = vector;
 		irte->lo.fields_remap.destination = dest_apicid;
 		modify_irte_ga(devid, index, irte, NULL);
@@ -4110,7 +4123,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
 		return ret;
 
 	if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
-		if (get_irq_table(devid, true))
+		if (alloc_irq_table(devid, true))
 			index = info->ioapic_pin;
 		else
 			ret = -ENOMEM;
@@ -4393,11 +4406,11 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data)
 	if (!iommu)
 		return -ENODEV;
 
-	irt = get_irq_table(devid, false);
+	irt = get_irq_table(devid);
 	if (!irt)
 		return -ENODEV;
 
-	spin_lock_irqsave(&irt->lock, flags);
+	raw_spin_lock_irqsave(&irt->lock, flags);
 
 	if (ref->lo.fields_vapic.guest_mode) {
 		if (cpu >= 0)
@@ -4406,7 +4419,7 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data)
 		barrier();
 	}
 
-	spin_unlock_irqrestore(&irt->lock, flags);
+	raw_spin_unlock_irqrestore(&irt->lock, flags);
 
 	iommu_flush_irt(iommu, devid);
 	iommu_completion_wait(iommu);
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 4e4a615bf13f..904c575d1677 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1474,7 +1474,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
 {
 	int ret;
 
-	spin_lock_init(&iommu->lock);
+	raw_spin_lock_init(&iommu->lock);
 
 	/* Add IOMMU to internal data structures */
 	list_add_tail(&iommu->list, &amd_iommu_list);
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 6a877ebd058b..da886b0095aa 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -408,7 +408,7 @@ extern bool amd_iommu_iotlb_sup;
 #define IRQ_TABLE_ALIGNMENT	128
 
 struct irq_remap_table {
-	spinlock_t lock;
+	raw_spinlock_t lock;
 	unsigned min_index;
 	u32 *table;
 };
@@ -490,7 +490,7 @@ struct amd_iommu {
 	int index;
 
 	/* locks the accesses to the hardware */
-	spinlock_t lock;
+	raw_spinlock_t lock;
 
 	/* Pointer to PCI device of this IOMMU */
 	struct pci_dev *dev;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 25914d36c5ac..f05f3cf90756 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -19,6 +19,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi_iort.h>
 #include <linux/device.h>
 #include <linux/dma-iommu.h>
 #include <linux/gfp.h>
@@ -167,13 +168,18 @@ EXPORT_SYMBOL(iommu_put_dma_cookie);
  *
  * IOMMU drivers can use this to implement their .get_resv_regions callback
  * for general non-IOMMU-specific reservations. Currently, this covers host
- * bridge windows for PCI devices.
+ * bridge windows for PCI devices and GICv3 ITS region reservation on ACPI
+ * based ARM platforms that may require HW MSI reservation.
  */
 void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
 {
 	struct pci_host_bridge *bridge;
 	struct resource_entry *window;
 
+	if (!is_of_node(dev->iommu_fwspec->iommu_fwnode) &&
+		iort_iommu_msi_get_resv_regions(dev, list) < 0)
+		return;
+
 	if (!dev_is_pci(dev))
 		return;
 
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 9a7ffd13c7f0..accf58388bdb 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -806,7 +806,7 @@ int __init dmar_dev_scope_init(void)
 	return dmar_dev_scope_status;
 }
 
-void dmar_register_bus_notifier(void)
+void __init dmar_register_bus_notifier(void)
 {
 	bus_register_notifier(&pci_bus_type, &dmar_pci_bus_nb);
 }
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 2138102ef611..210715f08cf6 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1238,17 +1238,6 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *iommu_domain,
 	return phys;
 }
 
-static struct iommu_group *get_device_iommu_group(struct device *dev)
-{
-	struct iommu_group *group;
-
-	group = iommu_group_get(dev);
-	if (!group)
-		group = iommu_group_alloc();
-
-	return group;
-}
-
 static int exynos_iommu_add_device(struct device *dev)
 {
 	struct exynos_iommu_owner *owner = dev->archdata.iommu;
@@ -1344,7 +1333,7 @@ static const struct iommu_ops exynos_iommu_ops = {
 	.unmap = exynos_iommu_unmap,
 	.map_sg = default_iommu_map_sg,
 	.iova_to_phys = exynos_iommu_iova_to_phys,
-	.device_group = get_device_iommu_group,
+	.device_group = generic_device_group,
 	.add_device = exynos_iommu_add_device,
 	.remove_device = exynos_iommu_remove_device,
 	.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c
index 2ca08dc9331c..10e4a3d11c02 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -357,8 +357,8 @@ static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl)
 	return false;
 }
 
-static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *, unsigned long,
-			   size_t, int, arm_v7s_iopte *);
+static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *, unsigned long,
+			      size_t, int, arm_v7s_iopte *);
 
 static int arm_v7s_init_pte(struct arm_v7s_io_pgtable *data,
 			    unsigned long iova, phys_addr_t paddr, int prot,
@@ -541,9 +541,10 @@ static arm_v7s_iopte arm_v7s_split_cont(struct arm_v7s_io_pgtable *data,
 	return pte;
 }
 
-static int arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
-				   unsigned long iova, size_t size,
-				   arm_v7s_iopte blk_pte, arm_v7s_iopte *ptep)
+static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
+				      unsigned long iova, size_t size,
+				      arm_v7s_iopte blk_pte,
+				      arm_v7s_iopte *ptep)
 {
 	struct io_pgtable_cfg *cfg = &data->iop.cfg;
 	arm_v7s_iopte pte, *tablep;
@@ -584,9 +585,9 @@ static int arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
 	return size;
 }
 
-static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
-			    unsigned long iova, size_t size, int lvl,
-			    arm_v7s_iopte *ptep)
+static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
+			      unsigned long iova, size_t size, int lvl,
+			      arm_v7s_iopte *ptep)
 {
 	arm_v7s_iopte pte[ARM_V7S_CONT_PAGES];
 	struct io_pgtable *iop = &data->iop;
@@ -656,8 +657,8 @@ static int __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
 	return __arm_v7s_unmap(data, iova, size, lvl + 1, ptep);
 }
 
-static int arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova,
-			 size_t size)
+static size_t arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova,
+			    size_t size)
 {
 	struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops);
 
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 51e5c43caed1..8faaaa04d7a7 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -268,9 +268,9 @@ static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte,
 		__arm_lpae_sync_pte(ptep, cfg);
 }
 
-static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
-			    unsigned long iova, size_t size, int lvl,
-			    arm_lpae_iopte *ptep);
+static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
+			       unsigned long iova, size_t size, int lvl,
+			       arm_lpae_iopte *ptep);
 
 static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
 				phys_addr_t paddr, arm_lpae_iopte prot,
@@ -506,10 +506,10 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop)
 	kfree(data);
 }
 
-static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
-				    unsigned long iova, size_t size,
-				    arm_lpae_iopte blk_pte, int lvl,
-				    arm_lpae_iopte *ptep)
+static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
+				       unsigned long iova, size_t size,
+				       arm_lpae_iopte blk_pte, int lvl,
+				       arm_lpae_iopte *ptep)
 {
 	struct io_pgtable_cfg *cfg = &data->iop.cfg;
 	arm_lpae_iopte pte, *tablep;
@@ -560,9 +560,9 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
 	return size;
 }
 
-static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
-			    unsigned long iova, size_t size, int lvl,
-			    arm_lpae_iopte *ptep)
+static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
+			       unsigned long iova, size_t size, int lvl,
+			       arm_lpae_iopte *ptep)
 {
 	arm_lpae_iopte pte;
 	struct io_pgtable *iop = &data->iop;
@@ -606,8 +606,8 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
 	return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep);
 }
 
-static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
-			  size_t size)
+static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
+			     size_t size)
 {
 	struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
 	arm_lpae_iopte *ptep = data->pgd;
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index cd2e1eafffe6..2df79093cad9 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -119,8 +119,8 @@ struct io_pgtable_cfg {
 struct io_pgtable_ops {
 	int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
 		   phys_addr_t paddr, size_t size, int prot);
-	int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
-		     size_t size);
+	size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
+			size_t size);
 	phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
 				    unsigned long iova);
 };
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 69fef991c651..d2aa23202bb9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1573,10 +1573,10 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 
 	if (unlikely(ops->unmap == NULL ||
 		     domain->pgsize_bitmap == 0UL))
-		return -ENODEV;
+		return 0;
 
 	if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING)))
-		return -EINVAL;
+		return 0;
 
 	/* find out the minimum page size supported */
 	min_pagesz = 1 << __ffs(domain->pgsize_bitmap);
@@ -1589,7 +1589,7 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
 	if (!IS_ALIGNED(iova | size, min_pagesz)) {
 		pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
 		       iova, size, min_pagesz);
-		return -EINVAL;
+		return 0;
 	}
 
 	pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size);
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 49721b4e1975..496deee3ae3a 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -27,7 +27,7 @@ int disable_irq_post = 0;
 static int disable_irq_remap;
 static struct irq_remap_ops *remap_ops;
 
-static void irq_remapping_disable_io_apic(void)
+static void irq_remapping_restore_boot_irq_mode(void)
 {
 	/*
 	 * With interrupt-remapping, for now we will use virtual wire A
@@ -42,7 +42,7 @@ static void irq_remapping_disable_io_apic(void)
 
 static void __init irq_remapping_modify_x86_ops(void)
 {
-	x86_io_apic_ops.disable		= irq_remapping_disable_io_apic;
+	x86_apic_ops.restore = irq_remapping_restore_boot_irq_mode;
 }
 
 static __init int setup_nointremap(char *str)
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 542930cd183d..1b1b77594897 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -418,20 +418,12 @@ static int mtk_iommu_create_mapping(struct device *dev,
 		m4udev->archdata.iommu = mtk_mapping;
 	}
 
-	ret = arm_iommu_attach_device(dev, mtk_mapping);
-	if (ret)
-		goto err_release_mapping;
-
 	return 0;
-
-err_release_mapping:
-	arm_iommu_release_mapping(mtk_mapping);
-	m4udev->archdata.iommu = NULL;
-	return ret;
 }
 
 static int mtk_iommu_add_device(struct device *dev)
 {
+	struct dma_iommu_mapping *mtk_mapping;
 	struct of_phandle_args iommu_spec;
 	struct of_phandle_iterator it;
 	struct mtk_iommu_data *data;
@@ -452,15 +444,30 @@ static int mtk_iommu_add_device(struct device *dev)
 	if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops)
 		return -ENODEV; /* Not a iommu client device */
 
-	data = dev->iommu_fwspec->iommu_priv;
-	iommu_device_link(&data->iommu, dev);
-
-	group = iommu_group_get_for_dev(dev);
+	/*
+	 * This is a short-term bodge because the ARM DMA code doesn't
+	 * understand multi-device groups, but we have to call into it
+	 * successfully (and not just rely on a normal IOMMU API attach
+	 * here) in order to set the correct DMA API ops on @dev.
+	 */
+	group = iommu_group_alloc();
 	if (IS_ERR(group))
 		return PTR_ERR(group);
 
+	err = iommu_group_add_device(group, dev);
 	iommu_group_put(group);
-	return 0;
+	if (err)
+		return err;
+
+	data = dev->iommu_fwspec->iommu_priv;
+	mtk_mapping = data->dev->archdata.iommu;
+	err = arm_iommu_attach_device(dev, mtk_mapping);
+	if (err) {
+		iommu_group_remove_device(dev);
+		return err;
+	}
+
+	return iommu_device_link(&data->iommu, dev);;
 }
 
 static void mtk_iommu_remove_device(struct device *dev)
@@ -477,24 +484,6 @@ static void mtk_iommu_remove_device(struct device *dev)
 	iommu_fwspec_free(dev);
 }
 
-static struct iommu_group *mtk_iommu_device_group(struct device *dev)
-{
-	struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv;
-
-	if (!data)
-		return ERR_PTR(-ENODEV);
-
-	/* All the client devices are in the same m4u iommu-group */
-	if (!data->m4u_group) {
-		data->m4u_group = iommu_group_alloc();
-		if (IS_ERR(data->m4u_group))
-			dev_err(dev, "Failed to allocate M4U IOMMU group\n");
-	} else {
-		iommu_group_ref_get(data->m4u_group);
-	}
-	return data->m4u_group;
-}
-
 static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
 {
 	u32 regval;
@@ -547,7 +536,6 @@ static struct iommu_ops mtk_iommu_ops = {
 	.iova_to_phys	= mtk_iommu_iova_to_phys,
 	.add_device	= mtk_iommu_add_device,
 	.remove_device	= mtk_iommu_remove_device,
-	.device_group	= mtk_iommu_device_group,
 	.pgsize_bitmap	= ~0UL << MT2701_IOMMU_PAGE_SHIFT,
 };
 
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 1d3056f53747..d01f3cab3d45 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3452,7 +3452,8 @@ static int __init gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
 		return -ENOMEM;
 	}
 
-	err = iort_register_domain_token(its_entry->translation_id, dom_handle);
+	err = iort_register_domain_token(its_entry->translation_id, res.start,
+					 dom_handle);
 	if (err) {
 		pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n",
 		       &res.start, its_entry->translation_id);
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index c5603d1a07d6..1f8f489b4167 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -560,7 +560,7 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 
 static int
 data_sock_getname(struct socket *sock, struct sockaddr *addr,
-		  int *addr_len, int peer)
+		  int peer)
 {
 	struct sockaddr_mISDN	*maddr = (struct sockaddr_mISDN *) addr;
 	struct sock		*sk = sock->sk;
@@ -570,14 +570,13 @@ data_sock_getname(struct socket *sock, struct sockaddr *addr,
 
 	lock_sock(sk);
 
-	*addr_len = sizeof(*maddr);
 	maddr->family = AF_ISDN;
 	maddr->dev = _pms(sk)->dev->id;
 	maddr->channel = _pms(sk)->ch.nr;
 	maddr->sapi = _pms(sk)->ch.addr & 0xff;
 	maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff;
 	release_sock(sk);
-	return 0;
+	return sizeof(*maddr);
 }
 
 static const struct proto_ops data_sock_ops = {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 3e763d2a0cb3..2c896c0e69e1 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -69,7 +69,7 @@ config LEDS_APU
 	  module will be called leds-apu.
 
 config LEDS_AS3645A
-	tristate "AS3645A LED flash controller support"
+	tristate "AS3645A and LM3555 LED flash controllers support"
 	depends on I2C && LEDS_CLASS_FLASH
 	depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
 	help
@@ -521,7 +521,7 @@ config LEDS_MC13783
 	depends on LEDS_CLASS
 	depends on MFD_MC13XXX
 	help
-	  This option enable support for on-chip LED drivers found
+	  This option enables support for on-chip LED drivers found
 	  on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC.
 
 config LEDS_NS2
@@ -544,7 +544,7 @@ config LEDS_NETXBIG
 	depends on MACH_KIRKWOOD
 	default y
 	help
-	  This option enable support for LEDs found on the LaCie 2Big
+	  This option enables support for LEDs found on the LaCie 2Big
 	  and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
 	  controlled through a GPIO extension bus.
 
@@ -594,12 +594,12 @@ config LEDS_MAX8997
 	  MAXIM MAX8997 PMIC.
 
 config LEDS_LM355x
-	tristate "LED support for LM355x Chips, LM3554 and LM3556"
+	tristate "LED support for LM3554 and LM3556 chips"
 	depends on LEDS_CLASS && I2C
 	select REGMAP_I2C
 	help
-	  This option enables support for LEDs connected to LM355x.
-	  LM355x includes Torch, Flash and Indicator functions.
+	  This option enables support for LEDs connected to LM3554
+	  and LM3556. It includes Torch, Flash and Indicator functions.
 
 config LEDS_OT200
 	tristate "LED support for the Bachmann OT200"
@@ -674,7 +674,7 @@ config LEDS_SYSCON
 	depends on MFD_SYSCON
 	depends on OF
 	help
-	  This option enabled support for the LEDs on syscon type
+	  This option enables support for the LEDs on syscon type
 	  devices. This will only work with device tree enabled
 	  devices.
 
@@ -688,11 +688,20 @@ config LEDS_PM8058
 
 config LEDS_MLXCPLD
 	tristate "LED support for the Mellanox boards"
-	depends on X86_64 && DMI
+	depends on X86 && DMI
+	depends on LEDS_CLASS
+	help
+	  This option enables support for the LEDs on the Mellanox
+	  boards. Say Y to enable these.
+
+config LEDS_MLXREG
+	tristate "LED support for the Mellanox switches management control"
 	depends on LEDS_CLASS
 	help
-	  This option enabled support for the LEDs on the Mellanox
-	  boards. Say Y to enabled these.
+	  This option enables support for the LEDs on the Mellanox Ethernet and
+	  InfiniBand switches. The driver can be activated by the platform device
+	  device add call. Say Y to enable these. To compile this driver as a
+	  module, choose 'M' here: the module will be called leds-mlxreg.
 
 config LEDS_USER
 	tristate "Userspace LED support"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 987884a5b9a5..91eca81cae82 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_LEDS_IS31FL319X)		+= leds-is31fl319x.o
 obj-$(CONFIG_LEDS_IS31FL32XX)		+= leds-is31fl32xx.o
 obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
 obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
+obj-$(CONFIG_LEDS_MLXREG)		+= leds-mlxreg.o
 obj-$(CONFIG_LEDS_NIC78BX)		+= leds-nic78bx.o
 obj-$(CONFIG_LEDS_MT6323)		+= leds-mt6323.o
 obj-$(CONFIG_LEDS_LM3692X)		+= leds-lm3692x.o
diff --git a/drivers/leds/leds-apu.c b/drivers/leds/leds-apu.c
index 74820aab9497..311e98b1823f 100644
--- a/drivers/leds/leds-apu.c
+++ b/drivers/leds/leds-apu.c
@@ -110,6 +110,7 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "APU")
 		}
 	},
+	/* PC Engines APU2 with "Legacy" bios < 4.0.8 */
 	{
 		.ident = "apu2",
 		.matches = {
@@ -117,6 +118,22 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_BOARD_NAME, "APU2")
 		}
 	},
+	/* PC Engines APU2 with "Legacy" bios >= 4.0.8 */
+	{
+		.ident = "apu2",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
+			DMI_MATCH(DMI_BOARD_NAME, "apu2")
+		}
+	},
+	/* PC Engines APU2 with "Mainline" bios */
+	{
+		.ident = "apu2",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
+			DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2")
+		}
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table);
@@ -211,7 +228,9 @@ static int __init apu_led_probe(struct platform_device *pdev)
 		apu_led->platform = APU1_LED_PLATFORM;
 		apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile);
 		apu_led->iosize = APU1_IOSIZE;
-	} else if (dmi_match(DMI_BOARD_NAME, "APU2")) {
+	} else if (dmi_match(DMI_BOARD_NAME, "APU2") ||
+		   dmi_match(DMI_BOARD_NAME, "apu2") ||
+		   dmi_match(DMI_BOARD_NAME, "PC Engines apu2")) {
 		apu_led->profile = apu2_led_profile;
 		apu_led->platform = APU2_LED_PLATFORM;
 		apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile);
@@ -237,7 +256,10 @@ static int __init apu_led_init(void)
 		pr_err("No PC Engines board detected\n");
 		return -ENODEV;
 	}
-	if (!(dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "APU2"))) {
+	if (!(dmi_match(DMI_PRODUCT_NAME, "APU") ||
+	      dmi_match(DMI_PRODUCT_NAME, "APU2") ||
+	      dmi_match(DMI_PRODUCT_NAME, "apu2") ||
+	      dmi_match(DMI_PRODUCT_NAME, "PC Engines apu2"))) {
 		pr_err("Unknown PC Engines board: %s\n",
 				dmi_get_system_info(DMI_PRODUCT_NAME));
 		return -ENODEV;
diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c
new file mode 100644
index 000000000000..1ee48cb21df9
--- /dev/null
+++ b/drivers/leds/leds-mlxreg.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+//
+// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
+// Copyright (c) 2018 Vadim Pasternak <vadimp@mellanox.com>
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* Codes for LEDs. */
+#define MLXREG_LED_OFFSET_BLINK_3HZ	0x01 /* Offset from solid: 3Hz blink */
+#define MLXREG_LED_OFFSET_BLINK_6HZ	0x02 /* Offset from solid: 6Hz blink */
+#define MLXREG_LED_IS_OFF		0x00 /* Off */
+#define MLXREG_LED_RED_SOLID		0x05 /* Solid red */
+#define MLXREG_LED_GREEN_SOLID		0x0D /* Solid green */
+#define MLXREG_LED_AMBER_SOLID		0x09 /* Solid amber */
+#define MLXREG_LED_BLINK_3HZ		167 /* ~167 msec off/on - HW support */
+#define MLXREG_LED_BLINK_6HZ		83 /* ~83 msec off/on - HW support */
+
+/**
+ * struct mlxreg_led_data - led control data:
+ *
+ * @data: led configuration data;
+ * @led_classdev: led class data;
+ * @base_color: base led color (other colors have constant offset from base);
+ * @led_data: led data;
+ * @data_parent: pointer to private device control data of parent;
+ */
+struct mlxreg_led_data {
+	struct mlxreg_core_data *data;
+	struct led_classdev led_cdev;
+	u8 base_color;
+	void *data_parent;
+	char led_cdev_name[MLXREG_CORE_LABEL_MAX_SIZE];
+};
+
+#define cdev_to_priv(c) container_of(c, struct mlxreg_led_data, led_cdev)
+
+/**
+ * struct mlxreg_led_priv_data - platform private data:
+ *
+ * @pdev: platform device;
+ * @pdata: platform data;
+ * @access_lock: mutex for attribute IO access;
+ */
+struct mlxreg_led_priv_data {
+	struct platform_device *pdev;
+	struct mlxreg_core_platform_data *pdata;
+	struct mutex access_lock; /* protect IO operations */
+};
+
+static int
+mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset)
+{
+	struct mlxreg_led_priv_data *priv = led_data->data_parent;
+	struct mlxreg_core_platform_data *led_pdata = priv->pdata;
+	struct mlxreg_core_data *data = led_data->data;
+	u32 regval;
+	u32 nib;
+	int ret;
+
+	/*
+	 * Each LED is controlled through low or high nibble of the relevant
+	 * register byte. Register offset is specified by off parameter.
+	 * Parameter vset provides color code: 0x0 for off, 0x5 for solid red,
+	 * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink
+	 * green.
+	 * Parameter mask specifies which nibble is used for specific LED: mask
+	 * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f -
+	 * higher nibble (bits from 4 to 7).
+	 */
+	mutex_lock(&priv->access_lock);
+
+	ret = regmap_read(led_pdata->regmap, data->reg, &regval);
+	if (ret)
+		goto access_error;
+
+	nib = (ror32(data->mask, data->bit) == 0xf0) ? rol32(vset, data->bit) :
+	      rol32(vset, data->bit + 4);
+	regval = (regval & data->mask) | nib;
+
+	ret = regmap_write(led_pdata->regmap, data->reg, regval);
+
+access_error:
+	mutex_unlock(&priv->access_lock);
+
+	return ret;
+}
+
+static enum led_brightness
+mlxreg_led_get_hw(struct mlxreg_led_data *led_data)
+{
+	struct mlxreg_led_priv_data *priv = led_data->data_parent;
+	struct mlxreg_core_platform_data *led_pdata = priv->pdata;
+	struct mlxreg_core_data *data = led_data->data;
+	u32 regval;
+	int err;
+
+	/*
+	 * Each LED is controlled through low or high nibble of the relevant
+	 * register byte. Register offset is specified by off parameter.
+	 * Parameter vset provides color code: 0x0 for off, 0x5 for solid red,
+	 * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink
+	 * green.
+	 * Parameter mask specifies which nibble is used for specific LED: mask
+	 * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f -
+	 * higher nibble (bits from 4 to 7).
+	 */
+	err = regmap_read(led_pdata->regmap, data->reg, &regval);
+	if (err < 0) {
+		dev_warn(led_data->led_cdev.dev, "Failed to get current brightness, error: %d\n",
+			 err);
+		/* Assume the LED is OFF */
+		return LED_OFF;
+	}
+
+	regval = regval & ~data->mask;
+	regval = (ror32(data->mask, data->bit) == 0xf0) ? ror32(regval,
+		 data->bit) : ror32(regval, data->bit + 4);
+	if (regval >= led_data->base_color &&
+	    regval <= (led_data->base_color + MLXREG_LED_OFFSET_BLINK_6HZ))
+		return LED_FULL;
+
+	return LED_OFF;
+}
+
+static int
+mlxreg_led_brightness_set(struct led_classdev *cled, enum led_brightness value)
+{
+	struct mlxreg_led_data *led_data = cdev_to_priv(cled);
+
+	if (value)
+		return mlxreg_led_store_hw(led_data, led_data->base_color);
+	else
+		return mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF);
+}
+
+static enum led_brightness
+mlxreg_led_brightness_get(struct led_classdev *cled)
+{
+	struct mlxreg_led_data *led_data = cdev_to_priv(cled);
+
+	return mlxreg_led_get_hw(led_data);
+}
+
+static int
+mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on,
+		     unsigned long *delay_off)
+{
+	struct mlxreg_led_data *led_data = cdev_to_priv(cled);
+	int err;
+
+	/*
+	 * HW supports two types of blinking: full (6Hz) and half (3Hz).
+	 * For delay on/off zero LED is setting to solid color. For others
+	 * combination blinking is to be controlled by the software timer.
+	 */
+	if (!(*delay_on == 0 && *delay_off == 0) &&
+	    !(*delay_on == MLXREG_LED_BLINK_3HZ &&
+	      *delay_off == MLXREG_LED_BLINK_3HZ) &&
+	    !(*delay_on == MLXREG_LED_BLINK_6HZ &&
+	      *delay_off == MLXREG_LED_BLINK_6HZ))
+		return -EINVAL;
+
+	if (*delay_on == MLXREG_LED_BLINK_6HZ)
+		err = mlxreg_led_store_hw(led_data, led_data->base_color +
+					  MLXREG_LED_OFFSET_BLINK_6HZ);
+	else if (*delay_on == MLXREG_LED_BLINK_3HZ)
+		err = mlxreg_led_store_hw(led_data, led_data->base_color +
+					  MLXREG_LED_OFFSET_BLINK_3HZ);
+	else
+		err = mlxreg_led_store_hw(led_data, led_data->base_color);
+
+	return err;
+}
+
+static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
+{
+	struct mlxreg_core_platform_data *led_pdata = priv->pdata;
+	struct mlxreg_core_data *data = led_pdata->data;
+	struct mlxreg_led_data *led_data;
+	struct led_classdev *led_cdev;
+	enum led_brightness brightness;
+	int i;
+	int err;
+
+	for (i = 0; i < led_pdata->counter; i++, data++) {
+		led_data = devm_kzalloc(&priv->pdev->dev, sizeof(*led_data),
+					GFP_KERNEL);
+		if (!led_data)
+			return -ENOMEM;
+
+		led_cdev = &led_data->led_cdev;
+		led_data->data_parent = priv;
+		if (strstr(data->label, "red") ||
+		    strstr(data->label, "orange")) {
+			brightness = LED_OFF;
+			led_data->base_color = MLXREG_LED_RED_SOLID;
+		} else if (strstr(data->label, "amber")) {
+			brightness = LED_OFF;
+			led_data->base_color = MLXREG_LED_AMBER_SOLID;
+		} else {
+			brightness = LED_OFF;
+			led_data->base_color = MLXREG_LED_GREEN_SOLID;
+		}
+		sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg",
+			data->label);
+		led_cdev->name = led_data->led_cdev_name;
+		led_cdev->brightness = brightness;
+		led_cdev->max_brightness = LED_ON;
+		led_cdev->brightness_set_blocking =
+						mlxreg_led_brightness_set;
+		led_cdev->brightness_get = mlxreg_led_brightness_get;
+		led_cdev->blink_set = mlxreg_led_blink_set;
+		led_cdev->flags = LED_CORE_SUSPENDRESUME;
+		led_data->data = data;
+		err = devm_led_classdev_register(&priv->pdev->dev, led_cdev);
+		if (err)
+			return err;
+
+		if (led_cdev->brightness)
+			mlxreg_led_brightness_set(led_cdev,
+						  led_cdev->brightness);
+		dev_info(led_cdev->dev, "label: %s, mask: 0x%02x, offset:0x%02x\n",
+			 data->label, data->mask, data->reg);
+	}
+
+	return 0;
+}
+
+static int mlxreg_led_probe(struct platform_device *pdev)
+{
+	struct mlxreg_core_platform_data *led_pdata;
+	struct mlxreg_led_priv_data *priv;
+
+	led_pdata = dev_get_platdata(&pdev->dev);
+	if (!led_pdata) {
+		dev_err(&pdev->dev, "Failed to get platform data.\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->access_lock);
+	priv->pdev = pdev;
+	priv->pdata = led_pdata;
+
+	return mlxreg_led_config(priv);
+}
+
+static int mlxreg_led_remove(struct platform_device *pdev)
+{
+	struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev);
+
+	mutex_destroy(&priv->access_lock);
+
+	return 0;
+}
+
+static struct platform_driver mlxreg_led_driver = {
+	.driver = {
+	    .name = "leds-mlxreg",
+	},
+	.probe = mlxreg_led_probe,
+	.remove = mlxreg_led_remove,
+};
+
+module_platform_driver(mlxreg_led_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox LED regmap driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:leds-mlxreg");
diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c
index e40065bdbfc8..0a7e99d62c69 100644
--- a/drivers/md/md-multipath.c
+++ b/drivers/md/md-multipath.c
@@ -157,7 +157,7 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev)
 		seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
 	}
 	rcu_read_unlock();
-	seq_printf (seq, "]");
+	seq_putc(seq, ']');
 }
 
 static int multipath_congested(struct mddev *mddev, int bits)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index bc67ab6844f0..ba152dddaaa3 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -801,6 +801,9 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
 	struct bio *bio;
 	int ff = 0;
 
+	if (!page)
+		return;
+
 	if (test_bit(Faulty, &rdev->flags))
 		return;
 
@@ -5452,6 +5455,7 @@ int md_run(struct mddev *mddev)
 	 * the only valid external interface is through the md
 	 * device.
 	 */
+	mddev->has_superblocks = false;
 	rdev_for_each(rdev, mddev) {
 		if (test_bit(Faulty, &rdev->flags))
 			continue;
@@ -5465,6 +5469,9 @@ int md_run(struct mddev *mddev)
 				set_disk_ro(mddev->gendisk, 1);
 		}
 
+		if (rdev->sb_page)
+			mddev->has_superblocks = true;
+
 		/* perform some consistency tests on the device.
 		 * We don't want the data to overlap the metadata,
 		 * Internal Bitmap issues have been handled elsewhere.
@@ -5497,8 +5504,10 @@ int md_run(struct mddev *mddev)
 	}
 	if (mddev->sync_set == NULL) {
 		mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
-		if (!mddev->sync_set)
-			return -ENOMEM;
+		if (!mddev->sync_set) {
+			err = -ENOMEM;
+			goto abort;
+		}
 	}
 
 	spin_lock(&pers_lock);
@@ -5511,7 +5520,8 @@ int md_run(struct mddev *mddev)
 		else
 			pr_warn("md: personality for level %s is not loaded!\n",
 				mddev->clevel);
-		return -EINVAL;
+		err = -EINVAL;
+		goto abort;
 	}
 	spin_unlock(&pers_lock);
 	if (mddev->level != pers->level) {
@@ -5524,7 +5534,8 @@ int md_run(struct mddev *mddev)
 	    pers->start_reshape == NULL) {
 		/* This personality cannot handle reshaping... */
 		module_put(pers->owner);
-		return -EINVAL;
+		err = -EINVAL;
+		goto abort;
 	}
 
 	if (pers->sync_request) {
@@ -5593,7 +5604,7 @@ int md_run(struct mddev *mddev)
 		mddev->private = NULL;
 		module_put(pers->owner);
 		bitmap_destroy(mddev);
-		return err;
+		goto abort;
 	}
 	if (mddev->queue) {
 		bool nonrot = true;
@@ -5655,6 +5666,18 @@ int md_run(struct mddev *mddev)
 	sysfs_notify_dirent_safe(mddev->sysfs_action);
 	sysfs_notify(&mddev->kobj, NULL, "degraded");
 	return 0;
+
+abort:
+	if (mddev->bio_set) {
+		bioset_free(mddev->bio_set);
+		mddev->bio_set = NULL;
+	}
+	if (mddev->sync_set) {
+		bioset_free(mddev->sync_set);
+		mddev->sync_set = NULL;
+	}
+
+	return err;
 }
 EXPORT_SYMBOL_GPL(md_run);
 
@@ -8049,6 +8072,7 @@ EXPORT_SYMBOL(md_done_sync);
 bool md_write_start(struct mddev *mddev, struct bio *bi)
 {
 	int did_change = 0;
+
 	if (bio_data_dir(bi) != WRITE)
 		return true;
 
@@ -8081,6 +8105,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi)
 	rcu_read_unlock();
 	if (did_change)
 		sysfs_notify_dirent_safe(mddev->sysfs_state);
+	if (!mddev->has_superblocks)
+		return true;
 	wait_event(mddev->sb_wait,
 		   !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) ||
 		   mddev->suspended);
@@ -8569,6 +8595,10 @@ static int remove_and_add_spares(struct mddev *mddev,
 	int removed = 0;
 	bool remove_some = false;
 
+	if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+		/* Mustn't remove devices when resync thread is running */
+		return 0;
+
 	rdev_for_each(rdev, mddev) {
 		if ((this == NULL || rdev == this) &&
 		    rdev->raid_disk >= 0 &&
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 58cd20a5e85e..fbc925cce810 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -468,6 +468,8 @@ struct mddev {
 	void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
 	struct md_cluster_info		*cluster_info;
 	unsigned int			good_device_nr;	/* good device num within cluster raid */
+
+	bool	has_superblocks:1;
 };
 
 enum recovery_flags {
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index b2eae332e1a2..f978eddc7a21 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1108,7 +1108,7 @@ static void alloc_behind_master_bio(struct r1bio *r1_bio,
 
 	bio_copy_data(behind_bio, bio);
 skip_copy:
-	r1_bio->behind_master_bio = behind_bio;;
+	r1_bio->behind_master_bio = behind_bio;
 	set_bit(R1BIO_BehindIO, &r1_bio->state);
 
 	return;
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index c7294e7557e0..eb84bc68e2fd 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -26,6 +26,18 @@
 #define BARRIER_BUCKETS_NR_BITS		(PAGE_SHIFT - ilog2(sizeof(atomic_t)))
 #define BARRIER_BUCKETS_NR		(1<<BARRIER_BUCKETS_NR_BITS)
 
+/* Note: raid1_info.rdev can be set to NULL asynchronously by raid1_remove_disk.
+ * There are three safe ways to access raid1_info.rdev.
+ * 1/ when holding mddev->reconfig_mutex
+ * 2/ when resync/recovery is known to be happening - i.e. in code that is
+ *    called as part of performing resync/recovery.
+ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
+ *    and if it is non-NULL, increment rdev->nr_pending before dropping the
+ *    RCU lock.
+ * When .rdev is set to NULL, the nr_pending count checked again and if it has
+ * been incremented, the pointer is put back in .rdev.
+ */
+
 struct raid1_info {
 	struct md_rdev	*rdev;
 	sector_t	head_position;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 99c9207899a7..9e9441fde8b3 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -141,7 +141,7 @@ static void r10bio_pool_free(void *r10_bio, void *data)
 #define RESYNC_WINDOW (1024*1024)
 /* maximum number of concurrent requests, memory permitting */
 #define RESYNC_DEPTH (32*1024*1024/RESYNC_BLOCK_SIZE)
-#define CLUSTER_RESYNC_WINDOW (16 * RESYNC_WINDOW)
+#define CLUSTER_RESYNC_WINDOW (32 * RESYNC_WINDOW)
 #define CLUSTER_RESYNC_WINDOW_SECTORS (CLUSTER_RESYNC_WINDOW >> 9)
 
 /*
@@ -2655,7 +2655,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
 		for (m = 0; m < conf->copies; m++) {
 			int dev = r10_bio->devs[m].devnum;
 			rdev = conf->mirrors[dev].rdev;
-			if (r10_bio->devs[m].bio == NULL)
+			if (r10_bio->devs[m].bio == NULL ||
+				r10_bio->devs[m].bio->bi_end_io == NULL)
 				continue;
 			if (!r10_bio->devs[m].bio->bi_status) {
 				rdev_clear_badblocks(
@@ -2670,7 +2671,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
 					md_error(conf->mddev, rdev);
 			}
 			rdev = conf->mirrors[dev].replacement;
-			if (r10_bio->devs[m].repl_bio == NULL)
+			if (r10_bio->devs[m].repl_bio == NULL ||
+				r10_bio->devs[m].repl_bio->bi_end_io == NULL)
 				continue;
 
 			if (!r10_bio->devs[m].repl_bio->bi_status) {
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index db2ac22ac1b4..e2e8840de9bf 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -2,6 +2,19 @@
 #ifndef _RAID10_H
 #define _RAID10_H
 
+/* Note: raid10_info.rdev can be set to NULL asynchronously by
+ * raid10_remove_disk.
+ * There are three safe ways to access raid10_info.rdev.
+ * 1/ when holding mddev->reconfig_mutex
+ * 2/ when resync/recovery/reshape is known to be happening - i.e. in code
+ *    that is called as part of performing resync/recovery/reshape.
+ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
+ *    and if it is non-NULL, increment rdev->nr_pending before dropping the
+ *    RCU lock.
+ * When .rdev is set to NULL, the nr_pending count checked again and if it has
+ * been incremented, the pointer is put back in .rdev.
+ */
+
 struct raid10_info {
 	struct md_rdev	*rdev, *replacement;
 	sector_t	head_position;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 50d01144b805..36e050678f5a 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6764,9 +6764,7 @@ static void free_conf(struct r5conf *conf)
 
 	log_exit(conf);
 
-	if (conf->shrinker.nr_deferred)
-		unregister_shrinker(&conf->shrinker);
-
+	unregister_shrinker(&conf->shrinker);
 	free_thread_groups(conf);
 	shrink_stripes(conf);
 	raid5_free_percpu(conf);
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 2e6123825095..3f8da26032ac 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -450,6 +450,18 @@ enum {
  * HANDLE gets cleared if stripe_handle leaves nothing locked.
  */
 
+/* Note: disk_info.rdev can be set to NULL asynchronously by raid5_remove_disk.
+ * There are three safe ways to access disk_info.rdev.
+ * 1/ when holding mddev->reconfig_mutex
+ * 2/ when resync/recovery/reshape is known to be happening - i.e. in code that
+ *    is called as part of performing resync/recovery/reshape.
+ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
+ *    and if it is non-NULL, increment rdev->nr_pending before dropping the RCU
+ *    lock.
+ * When .rdev is set to NULL, the nr_pending count checked again and if
+ * it has been incremented, the pointer is put back in .rdev.
+ */
+
 struct disk_info {
 	struct md_rdev	*rdev, *replacement;
 	struct page	*extra_page; /* extra page to use in prexor */
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 2b1e540587d6..768f7d70b55c 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index 492db12b8c4d..10b67fc40318 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * cec-api.c - HDMI Consumer Electronics Control framework - API
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index a9f9525db9ae..e47ea22b3c23 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * cec-core.c - HDMI Consumer Electronics Control framework - Core
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c
index 38e3fec6152b..ec72ac1c0b91 100644
--- a/drivers/media/cec/cec-edid.c
+++ b/drivers/media/cec/cec-edid.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c
index 08b619d0ea1e..16dffa06c913 100644
--- a/drivers/media/cec/cec-notifier.c
+++ b/drivers/media/cec/cec-notifier.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * cec-notifier.c - notify CEC drivers of physical address changes
  *
  * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
  * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/export.h>
diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h
index 7d0def199762..cf41c4236efd 100644
--- a/drivers/media/cec/cec-pin-priv.h
+++ b/drivers/media/cec/cec-pin-priv.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * cec-pin-priv.h - internal cec-pin header
  *
  * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef LINUX_CEC_PIN_PRIV_H
diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c
index b48dfe844118..8e834b9f72c6 100644
--- a/drivers/media/cec/cec-pin.c
+++ b/drivers/media/cec/cec-pin.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/delay.h>
diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h
index daf597643af8..804e38f849c7 100644
--- a/drivers/media/cec/cec-priv.h
+++ b/drivers/media/cec/cec-priv.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * cec-priv.h - HDMI Consumer Electronics Control internal header
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _CEC_PRIV_H
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
index 43180204fab2..3a3dc23c560c 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * v4l2-tpg-colors.c - A table that converts colors to various colorspaces
  *
@@ -20,19 +21,6 @@
  * in order to preserve precision.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/videodev2.h>
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 2b3d4ac4dfd4..d248d1fb9d1d 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * v4l2-tpg-core.c - Test Pattern Generator
  *
@@ -5,19 +6,6 @@
  * vivi.c source for the copyright information of those functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index a056d6cdaaaa..91ff06088572 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Analog Devices AD9389B/AD9889B video encoder driver
  *
  * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 /*
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 2817bafc67bf..d23505a411ee 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Analog Devices ADV7511 HDMI Transmitter Device Driver
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 1544920ec52d..b2caaff945ab 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * adv7604 - Analog Devices ADV7604 video decoder driver
  *
  * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 /*
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 136aa80a834b..fddac32e5051 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * adv7842 - Analog Devices ADV7842 video decoder driver
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 /*
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 2b8181469b93..393bbbbbaad7 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * tc358743 - Toshiba HDMI to CSI-2 bridge
  *
  * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
  * reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 /*
diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h
index 227b46471793..2495878dc358 100644
--- a/drivers/media/i2c/tc358743_regs.h
+++ b/drivers/media/i2c/tc358743_regs.h
@@ -1,22 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks
  *
  * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
  * reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 /*
diff --git a/drivers/media/pci/cobalt/Makefile b/drivers/media/pci/cobalt/Makefile
index b328955abbd2..29eddff2f35f 100644
--- a/drivers/media/pci/cobalt/Makefile
+++ b/drivers/media/pci/cobalt/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
 cobalt-objs    := cobalt-driver.o cobalt-irq.o cobalt-v4l2.o \
 		  cobalt-i2c.o cobalt-omnitek.o cobalt-flash.o cobalt-cpld.o \
 		  cobalt-alsa-main.o cobalt-alsa-pcm.o
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c
index 720e3ad93a9e..e5022b620856 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-main.c
+++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  ALSA interface to cobalt PCM capture streams
  *
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/init.h>
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
index b69b258d39b9..f6a7df13cd04 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
+++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  ALSA PCM device for the
  *  ALSA interface to cobalt PCM capture streams
  *
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/init.h>
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h
index 513fb1f71794..0e2e9c63a23e 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h
+++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h
@@ -1,22 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  ALSA PCM device for the
  *  ALSA interface to cobalt PCM capture streams
  *
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc);
diff --git a/drivers/media/pci/cobalt/cobalt-alsa.h b/drivers/media/pci/cobalt/cobalt-alsa.h
index 08db699ced37..bb7f156ad3e7 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa.h
+++ b/drivers/media/pci/cobalt/cobalt-alsa.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  ALSA interface to cobalt PCM capture streams
  *
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 struct snd_card;
diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c
index bfcecef659e3..3d8026483ac3 100644
--- a/drivers/media/pci/cobalt/cobalt-cpld.c
+++ b/drivers/media/pci/cobalt/cobalt-cpld.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  Cobalt CPLD functions
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/delay.h>
diff --git a/drivers/media/pci/cobalt/cobalt-cpld.h b/drivers/media/pci/cobalt/cobalt-cpld.h
index 0fc88fd5fa7b..8c880ed14cda 100644
--- a/drivers/media/pci/cobalt/cobalt-cpld.h
+++ b/drivers/media/pci/cobalt/cobalt-cpld.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Cobalt CPLD functions
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef COBALT_CPLD_H
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
index 3f16cf3f6d74..c8b1a6206c65 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  cobalt driver initialization and card probing
  *
@@ -5,19 +6,6 @@
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/delay.h>
diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h
index 00f773ec359a..429bee4ef79c 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.h
+++ b/drivers/media/pci/cobalt/cobalt-driver.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  cobalt driver internal defines and structures
  *
@@ -5,19 +6,6 @@
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef COBALT_DRIVER_H
diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c
index 04dcaf9198d2..ef96e0f956d2 100644
--- a/drivers/media/pci/cobalt/cobalt-flash.c
+++ b/drivers/media/pci/cobalt/cobalt-flash.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  Cobalt NOR flash functions
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/mtd/mtd.h>
diff --git a/drivers/media/pci/cobalt/cobalt-flash.h b/drivers/media/pci/cobalt/cobalt-flash.h
index 8077daea51cd..605ce3d37ca3 100644
--- a/drivers/media/pci/cobalt/cobalt-flash.h
+++ b/drivers/media/pci/cobalt/cobalt-flash.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Cobalt NOR flash functions
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef COBALT_FLASH_H
diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c
index 1a5c55673ea8..c374dae78bf7 100644
--- a/drivers/media/pci/cobalt/cobalt-i2c.c
+++ b/drivers/media/pci/cobalt/cobalt-i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  cobalt I2C functions
  *
@@ -5,19 +6,6 @@
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include "cobalt-driver.h"
diff --git a/drivers/media/pci/cobalt/cobalt-i2c.h b/drivers/media/pci/cobalt/cobalt-i2c.h
index a4c1cfaacf95..7a9057c8bff6 100644
--- a/drivers/media/pci/cobalt/cobalt-i2c.h
+++ b/drivers/media/pci/cobalt/cobalt-i2c.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  cobalt I2C functions
  *
@@ -5,19 +6,6 @@
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 /* init + register i2c algo-bit adapter */
diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c
index b190d4f81c6e..04783e78cc12 100644
--- a/drivers/media/pci/cobalt/cobalt-irq.c
+++ b/drivers/media/pci/cobalt/cobalt-irq.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  cobalt interrupt handling
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <media/i2c/adv7604.h>
diff --git a/drivers/media/pci/cobalt/cobalt-irq.h b/drivers/media/pci/cobalt/cobalt-irq.h
index 5119484a24d9..0b4078ce6555 100644
--- a/drivers/media/pci/cobalt/cobalt-irq.h
+++ b/drivers/media/pci/cobalt/cobalt-irq.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  cobalt interrupt handling
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/interrupt.h>
diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c
index a28a8482c1d4..4c137453e679 100644
--- a/drivers/media/pci/cobalt/cobalt-omnitek.c
+++ b/drivers/media/pci/cobalt/cobalt-omnitek.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  Omnitek Scatter-Gather DMA Controller
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/string.h>
diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.h b/drivers/media/pci/cobalt/cobalt-omnitek.h
index e5c6d032c6f2..129c5fccbe39 100644
--- a/drivers/media/pci/cobalt/cobalt-omnitek.h
+++ b/drivers/media/pci/cobalt/cobalt-omnitek.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Omnitek Scatter-Gather DMA Controller
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef COBALT_OMNITEK_H
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index def4a3b37084..e2a4c705d353 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  cobalt V4L2 API
  *
@@ -5,19 +6,6 @@
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #include <linux/dma-mapping.h>
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.h b/drivers/media/pci/cobalt/cobalt-v4l2.h
index 62be553cd8e2..dc43974b2d86 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.h
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  cobalt V4L2 API
  *
  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 int cobalt_nodes_register(struct cobalt *cobalt);
diff --git a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h
index 9bc9ef1fd3a8..4c6ad1cee87e 100644
--- a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h
index a480529f561e..6cc1ad7d98c9 100644
--- a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00235_FDMA_PACKER_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h
index 602419e589d3..f0c6fe304247 100644
--- a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00389_CVI_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h
index 95471c995067..27f05aca632f 100644
--- a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00460_EVCNT_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h
index 384a3e156301..8a5bf008750a 100644
--- a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00473_FREEWHEEL_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h
index 2a029026bf82..18bd4fcd2db8 100644
--- a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h
index bdef2df5d689..86da49033cd8 100644
--- a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
  *  All rights reserved.
- *
- *  This program is free software; you may 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.
- *
- *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- *  SOFTWARE.
  */
 
 #ifndef M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H
diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c
index 5debdf08fbe7..f1f28cf5c751 100644
--- a/drivers/media/platform/cec-gpio/cec-gpio.c
+++ b/drivers/media/platform/cec-gpio/cec-gpio.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 521d4b36c090..c4a577848dd7 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -76,7 +76,7 @@ int venus_boot(struct device *dev, const char *fwname)
 	}
 
 	ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys,
-			    mem_size);
+			    mem_size, NULL);
 
 	release_firmware(mdt);
 
diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c
index a4603d573c34..bd1bbbeedec3 100644
--- a/drivers/media/platform/sti/delta/delta-ipc.c
+++ b/drivers/media/platform/sti/delta/delta-ipc.c
@@ -175,8 +175,8 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name,
 	msg.ipc_buf_size = ipc_buf_size;
 	msg.ipc_buf_paddr = ctx->ipc_buf->paddr;
 
-	memcpy(msg.name, name, sizeof(msg.name));
-	msg.name[sizeof(msg.name) - 1] = 0;
+	memset(msg.name, 0, sizeof(msg.name));
+	strcpy(msg.name, name);
 
 	msg.param_size = param->size;
 	memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c
index b55d278d38a7..619bd8435b7f 100644
--- a/drivers/media/platform/vivid/vivid-cec.c
+++ b/drivers/media/platform/vivid/vivid-cec.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-cec.c - A Virtual Video Test Driver, cec emulation
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <media/cec.h>
diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h
index 3926b1422777..7524ed48a914 100644
--- a/drivers/media/platform/vivid/vivid-cec.h
+++ b/drivers/media/platform/vivid/vivid-cec.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-cec.h - A Virtual Video Test Driver, cec emulation
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifdef CONFIG_VIDEO_VIVID_CEC
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 9f036c5f51b0..82ec216f2ad8 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-core.c - A Virtual Video Test Driver, core initialization
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index c90e4a0ab94e..477c80a4d44c 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-core.h - core datastructures
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_CORE_H_
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 3f9d354827af..4b6b5d715031 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-ctrls.c - control support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h
index 9bcca9d56359..6fad5f5d0054 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.h
+++ b/drivers/media/platform/vivid/vivid-ctrls.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-ctrls.h - control support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_CTRLS_H_
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 6ca71aabb576..3fdb280c36ca 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-kthread-cap.h - video/vbi capture thread support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h
index 5b92fc9a0d04..0f43015306d6 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.h
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-kthread-cap.h - video/vbi capture thread support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_KTHREAD_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
index 98eed5889bc1..9981e7548019 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.c
+++ b/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-kthread-out.h - video/vbi output thread support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h
index 2bf04a17b05d..d5bcf44bbaca 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.h
+++ b/drivers/media/platform/vivid/vivid-kthread-out.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-kthread-out.h - video/vbi output thread support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_KTHREAD_OUT_H_
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
index bdc380b14e0c..bbbc1b6938a5 100644
--- a/drivers/media/platform/vivid/vivid-osd.c
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-osd.c - osd support for testing overlays.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h
index 57c9daa5940a..f9ac1af25dd3 100644
--- a/drivers/media/platform/vivid/vivid-osd.h
+++ b/drivers/media/platform/vivid/vivid-osd.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-osd.h - output overlay support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_OSD_H_
diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c
index 78c1e920670a..7c8efe38ff5b 100644
--- a/drivers/media/platform/vivid/vivid-radio-common.c
+++ b/drivers/media/platform/vivid/vivid-radio-common.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-radio-common.c - common radio rx/tx support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h
index 92fe589141b7..30a9900e5b2b 100644
--- a/drivers/media/platform/vivid/vivid-radio-common.h
+++ b/drivers/media/platform/vivid/vivid-radio-common.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-radio-common.h - common radio rx/tx support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_RADIO_COMMON_H_
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c
index f834f7df8cf9..acbfea2cce76 100644
--- a/drivers/media/platform/vivid/vivid-radio-rx.c
+++ b/drivers/media/platform/vivid/vivid-radio-rx.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-radio-rx.c - radio receiver support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h
index 2b33edb60942..c9c7849f6f99 100644
--- a/drivers/media/platform/vivid/vivid-radio-rx.h
+++ b/drivers/media/platform/vivid/vivid-radio-rx.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-radio-rx.h - radio receiver support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_RADIO_RX_H_
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
index 308b13f85dc0..1a3749ba5e7e 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.c
+++ b/drivers/media/platform/vivid/vivid-radio-tx.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-radio-tx.c - radio transmitter support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h
index 3c3343d70cbc..c2bf1e7e634a 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.h
+++ b/drivers/media/platform/vivid/vivid-radio-tx.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-radio-tx.h - radio transmitter support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_RADIO_TX_H_
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c
index 996e35e28d37..39ca9a56448c 100644
--- a/drivers/media/platform/vivid/vivid-rds-gen.c
+++ b/drivers/media/platform/vivid/vivid-rds-gen.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-rds-gen.c - rds (radio data system) generator support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h
index e55e3b22b7ca..35ac5742302b 100644
--- a/drivers/media/platform/vivid/vivid-rds-gen.h
+++ b/drivers/media/platform/vivid/vivid-rds-gen.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-rds-gen.h - rds (radio data system) generator support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_RDS_GEN_H_
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index ebd7b9c4dd83..cfb7cb4d37a8 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-sdr-cap.c - software defined radio support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h
index 43014b2733db..813c9248e5a7 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.h
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-sdr-cap.h - software defined radio support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_SDR_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
index d66ef95dd2b5..92a852955173 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.c
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-vbi-cap.c - vbi capture support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h
index 2d8ea0bac743..91d2de01381c 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.h
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-vbi-cap.h - vbi capture support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_VBI_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c
index 02c79d7cedab..acc98445a1fa 100644
--- a/drivers/media/platform/vivid/vivid-vbi-gen.c
+++ b/drivers/media/platform/vivid/vivid-vbi-gen.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-vbi-gen.c - vbi generator support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h
index 8444abe905ea..2657a7f5571c 100644
--- a/drivers/media/platform/vivid/vivid-vbi-gen.h
+++ b/drivers/media/platform/vivid/vivid-vbi-gen.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-vbi-gen.h - vbi generator support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_VBI_GEN_H_
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
index d2989195cf03..69486c130a7e 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.c
+++ b/drivers/media/platform/vivid/vivid-vbi-out.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-vbi-out.c - vbi output support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h
index 6555ba9d2860..76584940cdaf 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.h
+++ b/drivers/media/platform/vivid/vivid-vbi-out.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-vbi-out.h - vbi output support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_VBI_OUT_H_
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 0fbbcde19f0d..808967c7b0ab 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-vid-cap.c - video capture support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h
index 94079815dbc2..47d8b48820df 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.h
+++ b/drivers/media/platform/vivid/vivid-vid-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-vid-cap.h - video capture support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_VID_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index a651527d80db..cc67f403a808 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-vid-common.c - common video support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h
index 4b6175eab8a2..29b6c0b40a1b 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.h
+++ b/drivers/media/platform/vivid/vivid-vid-common.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-vid-common.h - common video support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_VID_COMMON_H_
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 0b1b6218ede8..51fec66d8d45 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * vivid-vid-out.c - video output support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h
index dfa84db184ed..e87aacf843c5 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.h
+++ b/drivers/media/platform/vivid/vivid-vid-out.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * vivid-vid-out.h - video output support functions.
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _VIVID_VID_OUT_H_
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 70a2c86774ce..9a5079d64c4a 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index a115db24667b..05c66701a899 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
  * All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 /* kernel includes */
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index f14ead5954e0..447f82c1f65a 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -28,14 +28,12 @@ config LIRC
 menuconfig RC_DECODERS
 	bool "Remote controller decoders"
 	depends on RC_CORE
-	default y
 
 if RC_DECODERS
 config IR_NEC_DECODER
 	tristate "Enable IR raw decoder for the NEC protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have IR with NEC protocol, and
@@ -45,7 +43,6 @@ config IR_RC5_DECODER
 	tristate "Enable IR raw decoder for the RC-5 protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have IR with RC-5 protocol, and
@@ -55,7 +52,6 @@ config IR_RC6_DECODER
 	tristate "Enable IR raw decoder for the RC6 protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have an infrared remote control which
@@ -65,7 +61,6 @@ config IR_JVC_DECODER
 	tristate "Enable IR raw decoder for the JVC protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have an infrared remote control which
@@ -75,7 +70,6 @@ config IR_SONY_DECODER
 	tristate "Enable IR raw decoder for the Sony protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have an infrared remote control which
@@ -84,7 +78,6 @@ config IR_SONY_DECODER
 config IR_SANYO_DECODER
 	tristate "Enable IR raw decoder for the Sanyo protocol"
 	depends on RC_CORE
-	default y
 
 	---help---
 	   Enable this option if you have an infrared remote control which
@@ -94,7 +87,6 @@ config IR_SANYO_DECODER
 config IR_SHARP_DECODER
 	tristate "Enable IR raw decoder for the Sharp protocol"
 	depends on RC_CORE
-	default y
 
 	---help---
 	   Enable this option if you have an infrared remote control which
@@ -105,7 +97,6 @@ config IR_MCE_KBD_DECODER
 	tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have a Microsoft Remote Keyboard for
@@ -116,7 +107,6 @@ config IR_XMP_DECODER
 	tristate "Enable IR raw decoder for the XMP protocol"
 	depends on RC_CORE
 	select BITREVERSE
-	default y
 
 	---help---
 	   Enable this option if you have IR with XMP protocol, and
@@ -446,7 +436,6 @@ config IR_SERIAL
 
 config IR_SERIAL_TRANSMITTER
 	bool "Serial Port Transmitter"
-	default y
 	depends on IR_SERIAL
 	---help---
 	   Serial Port Transmitter support
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index 0ce11c41dfae..700ab4c563d0 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -71,9 +71,10 @@ struct hix5hd2_ir_priv {
 	unsigned long		rate;
 };
 
-static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
+static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
 {
 	u32 val;
+	int ret = 0;
 
 	if (dev->regmap) {
 		regmap_read(dev->regmap, IR_CLK, &val);
@@ -87,10 +88,11 @@ static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
 		regmap_write(dev->regmap, IR_CLK, val);
 	} else {
 		if (on)
-			clk_prepare_enable(dev->clock);
+			ret = clk_prepare_enable(dev->clock);
 		else
 			clk_disable_unprepare(dev->clock);
 	}
+	return ret;
 }
 
 static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
@@ -127,9 +129,18 @@ static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
 static int hix5hd2_ir_open(struct rc_dev *rdev)
 {
 	struct hix5hd2_ir_priv *priv = rdev->priv;
+	int ret;
+
+	ret = hix5hd2_ir_enable(priv, true);
+	if (ret)
+		return ret;
 
-	hix5hd2_ir_enable(priv, true);
-	return hix5hd2_ir_config(priv);
+	ret = hix5hd2_ir_config(priv);
+	if (ret) {
+		hix5hd2_ir_enable(priv, false);
+		return ret;
+	}
+	return 0;
 }
 
 static void hix5hd2_ir_close(struct rc_dev *rdev)
@@ -239,7 +250,9 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
 		ret = PTR_ERR(priv->clock);
 		goto err;
 	}
-	clk_prepare_enable(priv->clock);
+	ret = clk_prepare_enable(priv->clock);
+	if (ret)
+		goto err;
 	priv->rate = clk_get_rate(priv->clock);
 
 	rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
@@ -309,9 +322,17 @@ static int hix5hd2_ir_suspend(struct device *dev)
 static int hix5hd2_ir_resume(struct device *dev)
 {
 	struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+	int ret;
 
-	hix5hd2_ir_enable(priv, true);
-	clk_prepare_enable(priv->clock);
+	ret = hix5hd2_ir_enable(priv, true);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(priv->clock);
+	if (ret) {
+		hix5hd2_ir_enable(priv, false);
+		return ret;
+	}
 
 	writel_relaxed(0x01, priv->base + IR_ENABLE);
 	writel_relaxed(0x00, priv->base + IR_INTM);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index c03c776cfa54..8cb68ae43282 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -56,8 +56,8 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
 		goto out;
 
-	IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 again:
 	switch (data->state) {
@@ -136,15 +136,15 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			u32 scancode;
 			scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
 				   (bitrev8((data->bits >> 0) & 0xff) << 0);
-			IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
+			dev_dbg(&dev->dev, "JVC scancode 0x%04x\n", scancode);
 			rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle);
 			data->first = false;
 			data->old_bits = data->bits;
 		} else if (data->bits == data->old_bits) {
-			IR_dprintk(1, "JVC repeat\n");
+			dev_dbg(&dev->dev, "JVC repeat\n");
 			rc_repeat(dev);
 		} else {
-			IR_dprintk(1, "JVC invalid repeat msg\n");
+			dev_dbg(&dev->dev, "JVC invalid repeat msg\n");
 			break;
 		}
 
@@ -164,8 +164,8 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 out:
-	IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 2c3df02e05ff..c110984ca671 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -117,19 +117,19 @@ static unsigned char kbd_keycodes[256] = {
 
 static void mce_kbd_rx_timeout(struct timer_list *t)
 {
-	struct mce_kbd_dec *mce_kbd = from_timer(mce_kbd, t, rx_timeout);
-	int i;
+	struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout);
 	unsigned char maskcode;
+	int i;
 
-	IR_dprintk(2, "timer callback clearing all keys\n");
+	dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n");
 
 	for (i = 0; i < 7; i++) {
 		maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
-		input_report_key(mce_kbd->idev, maskcode, 0);
+		input_report_key(raw->mce_kbd.idev, maskcode, 0);
 	}
 
 	for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
-		input_report_key(mce_kbd->idev, kbd_keycodes[i], 0);
+		input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0);
 }
 
 static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
@@ -144,16 +144,16 @@ static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
 	}
 }
 
-static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
-					     u32 scancode)
+static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode)
 {
+	struct mce_kbd_dec *data = &dev->raw->mce_kbd;
 	u8 keydata   = (scancode >> 8) & 0xff;
 	u8 shiftmask = scancode & 0xff;
 	unsigned char keycode, maskcode;
 	int i, keystate;
 
-	IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
-		   keydata, shiftmask);
+	dev_dbg(&dev->dev, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
+		keydata, shiftmask);
 
 	for (i = 0; i < 7; i++) {
 		maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
@@ -161,20 +161,21 @@ static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
 			keystate = 1;
 		else
 			keystate = 0;
-		input_report_key(idev, maskcode, keystate);
+		input_report_key(data->idev, maskcode, keystate);
 	}
 
 	if (keydata) {
 		keycode = kbd_keycodes[keydata];
-		input_report_key(idev, keycode, 1);
+		input_report_key(data->idev, keycode, 1);
 	} else {
 		for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
-			input_report_key(idev, kbd_keycodes[i], 0);
+			input_report_key(data->idev, kbd_keycodes[i], 0);
 	}
 }
 
-static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
+static void ir_mce_kbd_process_mouse_data(struct rc_dev *dev, u32 scancode)
 {
+	struct mce_kbd_dec *data = &dev->raw->mce_kbd;
 	/* raw mouse coordinates */
 	u8 xdata = (scancode >> 7) & 0x7f;
 	u8 ydata = (scancode >> 14) & 0x7f;
@@ -193,14 +194,14 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
 	else
 		y = ydata;
 
-	IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n",
-		   x, y, left ? "L" : "", right ? "R" : "");
+	dev_dbg(&dev->dev, "mouse: x = %d, y = %d, btns = %s%s\n",
+		x, y, left ? "L" : "", right ? "R" : "");
 
-	input_report_rel(idev, REL_X, x);
-	input_report_rel(idev, REL_Y, y);
+	input_report_rel(data->idev, REL_X, x);
+	input_report_rel(data->idev, REL_Y, y);
 
-	input_report_key(idev, BTN_LEFT, left);
-	input_report_key(idev, BTN_RIGHT, right);
+	input_report_key(data->idev, BTN_LEFT, left);
+	input_report_key(data->idev, BTN_RIGHT, right);
 }
 
 /**
@@ -227,8 +228,8 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		goto out;
 
 again:
-	IR_dprintk(2, "started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "started at state %i (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
 		return 0;
@@ -280,7 +281,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			data->wanted_bits = MCIR2_MOUSE_NBITS;
 			break;
 		default:
-			IR_dprintk(1, "not keyboard or mouse data\n");
+			dev_dbg(&dev->dev, "not keyboard or mouse data\n");
 			goto out;
 		}
 
@@ -319,25 +320,26 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		switch (data->wanted_bits) {
 		case MCIR2_KEYBOARD_NBITS:
 			scancode = data->body & 0xffff;
-			IR_dprintk(1, "keyboard data 0x%08x\n", data->body);
+			dev_dbg(&dev->dev, "keyboard data 0x%08x\n",
+				data->body);
 			if (dev->timeout)
 				delay = usecs_to_jiffies(dev->timeout / 1000);
 			else
 				delay = msecs_to_jiffies(100);
 			mod_timer(&data->rx_timeout, jiffies + delay);
 			/* Pass data to keyboard buffer parser */
-			ir_mce_kbd_process_keyboard_data(data->idev, scancode);
+			ir_mce_kbd_process_keyboard_data(dev, scancode);
 			lsc.rc_proto = RC_PROTO_MCIR2_KBD;
 			break;
 		case MCIR2_MOUSE_NBITS:
 			scancode = data->body & 0x1fffff;
-			IR_dprintk(1, "mouse data 0x%06x\n", scancode);
+			dev_dbg(&dev->dev, "mouse data 0x%06x\n", scancode);
 			/* Pass data to mouse buffer parser */
-			ir_mce_kbd_process_mouse_data(data->idev, scancode);
+			ir_mce_kbd_process_mouse_data(dev, scancode);
 			lsc.rc_proto = RC_PROTO_MCIR2_MSE;
 			break;
 		default:
-			IR_dprintk(1, "not keyboard or mouse data\n");
+			dev_dbg(&dev->dev, "not keyboard or mouse data\n");
 			goto out;
 		}
 
@@ -350,8 +352,8 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 out:
-	IR_dprintk(1, "failed at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "failed at state %i (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	input_sync(data->idev);
 	return -EINVAL;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 31d7bafe7bda..21647b809e6f 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -49,8 +49,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 	}
 
-	IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "NEC decode started at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	switch (data->state) {
 
@@ -99,13 +99,11 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			break;
 
 		if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
-			geq_margin(ev.duration,
-			NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
-				IR_dprintk(1, "Repeat last key\n");
-				rc_repeat(dev);
-				data->state = STATE_INACTIVE;
-				return 0;
-
+		    geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
+			dev_dbg(&dev->dev, "Repeat last key\n");
+			rc_repeat(dev);
+			data->state = STATE_INACTIVE;
+			return 0;
 		} else if (data->count > NECX_REPEAT_BITS)
 			data->necx_repeat = false;
 
@@ -164,8 +162,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 	}
 
-	IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "NEC decode failed at count %d state %d (%uus %s)\n",
+		data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 11a28f8772da..74d3b859c3a2 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -54,8 +54,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		goto out;
 
 again:
-	IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
 		return 0;
@@ -157,8 +157,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		} else
 			break;
 
-		IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
-			   scancode, protocol, toggle);
+		dev_dbg(&dev->dev, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
+			scancode, protocol, toggle);
 
 		rc_keydown(dev, protocol, scancode, toggle);
 		data->state = STATE_INACTIVE;
@@ -166,8 +166,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 out:
-	IR_dprintk(1, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
-		   data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
+		data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 55bb19bbd4e9..8314da32453f 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -100,8 +100,8 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		goto out;
 
 again:
-	IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "RC6 decode started at state %i (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
 		return 0;
@@ -170,7 +170,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			break;
 
 		if (!(data->header & RC6_STARTBIT_MASK)) {
-			IR_dprintk(1, "RC6 invalid start bit\n");
+			dev_dbg(&dev->dev, "RC6 invalid start bit\n");
 			break;
 		}
 
@@ -187,7 +187,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			data->wanted_bits = RC6_6A_NBITS;
 			break;
 		default:
-			IR_dprintk(1, "RC6 unknown mode\n");
+			dev_dbg(&dev->dev, "RC6 unknown mode\n");
 			goto out;
 		}
 		goto again;
@@ -230,13 +230,13 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			scancode = data->body;
 			toggle = data->toggle;
 			protocol = RC_PROTO_RC6_0;
-			IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
-				   scancode, toggle);
+			dev_dbg(&dev->dev, "RC6(0) scancode 0x%04x (toggle: %u)\n",
+				scancode, toggle);
 			break;
 
 		case RC6_MODE_6A:
 			if (data->count > CHAR_BIT * sizeof data->body) {
-				IR_dprintk(1, "RC6 too many (%u) data bits\n",
+				dev_dbg(&dev->dev, "RC6 too many (%u) data bits\n",
 					data->count);
 				goto out;
 			}
@@ -262,15 +262,15 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 				}
 				break;
 			default:
-				IR_dprintk(1, "RC6(6A) unsupported length\n");
+				dev_dbg(&dev->dev, "RC6(6A) unsupported length\n");
 				goto out;
 			}
 
-			IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
-				   protocol, scancode, toggle);
+			dev_dbg(&dev->dev, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
+				protocol, scancode, toggle);
 			break;
 		default:
-			IR_dprintk(1, "RC6 unknown mode\n");
+			dev_dbg(&dev->dev, "RC6 unknown mode\n");
 			goto out;
 		}
 
@@ -280,8 +280,8 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	}
 
 out:
-	IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "RC6 decode failed at state %i (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index ded39cdfc6ef..4efe6db5376a 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -52,14 +52,14 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 	if (!is_timing_event(ev)) {
 		if (ev.reset) {
-			IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
+			dev_dbg(&dev->dev, "SANYO event reset received. reset to state 0\n");
 			data->state = STATE_INACTIVE;
 		}
 		return 0;
 	}
 
-	IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "SANYO decode started at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	switch (data->state) {
 
@@ -102,7 +102,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
 		if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
 			rc_repeat(dev);
-			IR_dprintk(1, "SANYO repeat last key\n");
+			dev_dbg(&dev->dev, "SANYO repeat last key\n");
 			data->state = STATE_INACTIVE;
 			return 0;
 		}
@@ -144,21 +144,21 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		not_command = bitrev8((data->bits >>  0) & 0xff);
 
 		if ((command ^ not_command) != 0xff) {
-			IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n",
-				   data->bits);
+			dev_dbg(&dev->dev, "SANYO checksum error: received 0x%08llx\n",
+				data->bits);
 			data->state = STATE_INACTIVE;
 			return 0;
 		}
 
 		scancode = address << 8 | command;
-		IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
+		dev_dbg(&dev->dev, "SANYO scancode: 0x%06x\n", scancode);
 		rc_keydown(dev, RC_PROTO_SANYO, scancode, 0);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "SANYO decode failed at count %d state %d (%uus %s)\n",
+		data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index df296991906c..6a38c50566a4 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -54,8 +54,8 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 	}
 
-	IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "Sharp decode started at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	switch (data->state) {
 
@@ -149,9 +149,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		msg = (data->bits >> 15) & 0x7fff;
 		echo = data->bits & 0x7fff;
 		if ((msg ^ echo) != 0x3ff) {
-			IR_dprintk(1,
-				   "Sharp checksum error: received 0x%04x, 0x%04x\n",
-				   msg, echo);
+			dev_dbg(&dev->dev,
+				"Sharp checksum error: received 0x%04x, 0x%04x\n",
+				msg, echo);
 			break;
 		}
 
@@ -159,16 +159,15 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		command = bitrev8((msg >> 2) & 0xff);
 
 		scancode = address << 8 | command;
-		IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
+		dev_dbg(&dev->dev, "Sharp scancode 0x%04x\n", scancode);
 
 		rc_keydown(dev, RC_PROTO_SHARP, scancode, 0);
 		data->state = STATE_INACTIVE;
 		return 0;
 	}
 
-	IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration),
-		   TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "Sharp decode failed at count %d state %d (%uus %s)\n",
+		data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index e4bcff21c025..6764ec9de646 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -55,8 +55,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
 		goto out;
 
-	IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	switch (data->state) {
 
@@ -148,19 +148,21 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			protocol = RC_PROTO_SONY20;
 			break;
 		default:
-			IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
+			dev_dbg(&dev->dev, "Sony invalid bitcount %u\n",
+				data->count);
 			goto out;
 		}
 
 		scancode = device << 16 | subdevice << 8 | function;
-		IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
+		dev_dbg(&dev->dev, "Sony(%u) scancode 0x%05x\n", data->count,
+			scancode);
 		rc_keydown(dev, protocol, scancode, 0);
 		goto finish_state_machine;
 	}
 
 out:
-	IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
-		   data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n",
+		data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
index a32a84ae2d0b..7163d5ce2e64 100644
--- a/drivers/media/rc/ir-spi.c
+++ b/drivers/media/rc/ir-spi.c
@@ -15,21 +15,11 @@
 
 #define IR_SPI_DRIVER_NAME		"ir-spi"
 
-/* pulse value for different duty cycles */
-#define IR_SPI_PULSE_DC_50		0xff00
-#define IR_SPI_PULSE_DC_60		0xfc00
-#define IR_SPI_PULSE_DC_70		0xf800
-#define IR_SPI_PULSE_DC_75		0xf000
-#define IR_SPI_PULSE_DC_80		0xc000
-#define IR_SPI_PULSE_DC_90		0x8000
-
 #define IR_SPI_DEFAULT_FREQUENCY	38000
-#define IR_SPI_BIT_PER_WORD		    8
 #define IR_SPI_MAX_BUFSIZE		 4096
 
 struct ir_spi_data {
 	u32 freq;
-	u8 duty_cycle;
 	bool negated;
 
 	u16 tx_buf[IR_SPI_MAX_BUFSIZE];
@@ -105,19 +95,9 @@ static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier)
 static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
 {
 	struct ir_spi_data *idata = dev->priv;
+	int bits = (duty_cycle * 15) / 100;
 
-	if (duty_cycle >= 90)
-		idata->pulse = IR_SPI_PULSE_DC_90;
-	else if (duty_cycle >= 80)
-		idata->pulse = IR_SPI_PULSE_DC_80;
-	else if (duty_cycle >= 75)
-		idata->pulse = IR_SPI_PULSE_DC_75;
-	else if (duty_cycle >= 70)
-		idata->pulse = IR_SPI_PULSE_DC_70;
-	else if (duty_cycle >= 60)
-		idata->pulse = IR_SPI_PULSE_DC_60;
-	else
-		idata->pulse = IR_SPI_PULSE_DC_50;
+	idata->pulse = GENMASK(bits, 0);
 
 	if (idata->negated) {
 		idata->pulse = ~idata->pulse;
diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c
index 712bc6d76e92..58b47af1a763 100644
--- a/drivers/media/rc/ir-xmp-decoder.c
+++ b/drivers/media/rc/ir-xmp-decoder.c
@@ -49,8 +49,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		return 0;
 	}
 
-	IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n",
-		   data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "XMP decode started at state %d %d (%uus %s)\n",
+		data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
 
 	switch (data->state) {
 
@@ -85,7 +85,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			u32 scancode;
 
 			if (data->count != 16) {
-				IR_dprintk(2, "received TRAILER period at index %d: %u\n",
+				dev_dbg(&dev->dev, "received TRAILER period at index %d: %u\n",
 					data->count, ev.duration);
 				data->state = STATE_INACTIVE;
 				return -EINVAL;
@@ -99,7 +99,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			 */
 			divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000;
 			if (divider < 50) {
-				IR_dprintk(2, "divider to small %d.\n", divider);
+				dev_dbg(&dev->dev, "divider to small %d.\n",
+					divider);
 				data->state = STATE_INACTIVE;
 				return -EINVAL;
 			}
@@ -113,7 +114,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 				n[12] + n[13] + n[14] + n[15]) % 16;
 
 			if (sum1 != 15 || sum2 != 15) {
-				IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n",
+				dev_dbg(&dev->dev, "checksum errors sum1=0x%X sum2=0x%X\n",
 					sum1, sum2);
 				data->state = STATE_INACTIVE;
 				return -EINVAL;
@@ -127,24 +128,24 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			obc1 = n[12] << 4 | n[13];
 			obc2 = n[14] << 4 | n[15];
 			if (subaddr != subaddr2) {
-				IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n",
+				dev_dbg(&dev->dev, "subaddress nibbles mismatch 0x%02X != 0x%02X\n",
 					subaddr, subaddr2);
 				data->state = STATE_INACTIVE;
 				return -EINVAL;
 			}
 			if (oem != 0x44)
-				IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n",
+				dev_dbg(&dev->dev, "Warning: OEM nibbles 0x%02X. Expected 0x44\n",
 					oem);
 
 			scancode = addr << 24 | subaddr << 16 |
 				   obc1 << 8 | obc2;
-			IR_dprintk(1, "XMP scancode 0x%06x\n", scancode);
+			dev_dbg(&dev->dev, "XMP scancode 0x%06x\n", scancode);
 
 			if (toggle == 0) {
 				rc_keydown(dev, RC_PROTO_XMP, scancode, 0);
 			} else {
 				rc_repeat(dev);
-				IR_dprintk(1, "Repeat last key\n");
+				dev_dbg(&dev->dev, "Repeat last key\n");
 			}
 			data->state = STATE_INACTIVE;
 
@@ -153,7 +154,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		} else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) {
 			/* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */
 			if (data->count == 16) {
-				IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n",
+				dev_dbg(&dev->dev, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n",
 					data->count, ev.duration);
 				/*
 				 * TODO: for now go back to half frame position
@@ -164,7 +165,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			}
 
 			else if (data->count != 8)
-				IR_dprintk(2, "received half frame pulse at index %d: %u\n",
+				dev_dbg(&dev->dev, "received half frame pulse at index %d: %u\n",
 					data->count, ev.duration);
 			data->state = STATE_LEADER_PULSE;
 
@@ -173,7 +174,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		} else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) {
 			/* store nibble raw data, decode after trailer */
 			if (data->count == 16) {
-				IR_dprintk(2, "to many pulses (%d) ignoring: %u\n",
+				dev_dbg(&dev->dev, "to many pulses (%d) ignoring: %u\n",
 					data->count, ev.duration);
 				data->state = STATE_INACTIVE;
 				return -EINVAL;
@@ -189,8 +190,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		break;
 	}
 
-	IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n",
-		   data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+	dev_dbg(&dev->dev, "XMP decode failed at count %d state %d (%uus %s)\n",
+		data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
 	data->state = STATE_INACTIVE;
 	return -EINVAL;
 }
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index cc863044c880..da3b5c095a59 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -60,12 +60,12 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 		 * space with the maximum time value.
 		 */
 		sample = LIRC_SPACE(LIRC_VALUE_MASK);
-		IR_dprintk(2, "delivering reset sync space to lirc_dev\n");
+		dev_dbg(&dev->dev, "delivering reset sync space to lirc_dev\n");
 
 	/* Carrier reports */
 	} else if (ev.carrier_report) {
 		sample = LIRC_FREQUENCY(ev.carrier);
-		IR_dprintk(2, "carrier report (freq: %d)\n", sample);
+		dev_dbg(&dev->dev, "carrier report (freq: %d)\n", sample);
 
 	/* Packet end */
 	} else if (ev.timeout) {
@@ -77,7 +77,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 		dev->gap_duration = ev.duration;
 
 		sample = LIRC_TIMEOUT(ev.duration / 1000);
-		IR_dprintk(2, "timeout report (duration: %d)\n", sample);
+		dev_dbg(&dev->dev, "timeout report (duration: %d)\n", sample);
 
 	/* Normal sample */
 	} else {
@@ -100,8 +100,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 
 		sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
 					LIRC_SPACE(ev.duration / 1000);
-		IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
-			   TO_US(ev.duration), TO_STR(ev.pulse));
+		dev_dbg(&dev->dev, "delivering %uus %s to lirc_dev\n",
+			TO_US(ev.duration), TO_STR(ev.pulse));
 	}
 
 	spin_lock_irqsave(&dev->lirc_fh_lock, flags);
@@ -249,8 +249,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 		goto out_unlock;
 	}
 
-	start = ktime_get();
-
 	if (!dev->tx_ir) {
 		ret = -EINVAL;
 		goto out_unlock;
@@ -343,6 +341,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 		duration += txbuf[i];
 	}
 
+	start = ktime_get();
+
 	ret = dev->tx_ir(dev, txbuf, count);
 	if (ret < 0)
 		goto out_kfree;
@@ -570,7 +570,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd,
 				ret = -EINVAL;
 			else if (dev->s_timeout)
 				ret = dev->s_timeout(dev, tmp);
-			else if (!ret)
+			else
 				dev->timeout = tmp;
 		}
 		break;
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 458e9eb2d6a9..d09a06e1c17f 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -292,11 +292,4 @@ static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
 static inline void ir_lirc_unregister(struct rc_dev *dev) { }
 #endif
 
-/*
- * Decoder initialization code
- *
- * Those load logic are called during ir-core init, and automatically
- * loads the compiled decoders for their usage with IR raw events
- */
-
 #endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 18504870b9f0..2790a0d268fd 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -65,8 +65,8 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
 	if (!dev->raw)
 		return -EINVAL;
 
-	IR_dprintk(2, "sample: (%05dus %s)\n",
-		   TO_US(ev->duration), TO_STR(ev->pulse));
+	dev_dbg(&dev->dev, "sample: (%05dus %s)\n",
+		TO_US(ev->duration), TO_STR(ev->pulse));
 
 	if (!kfifo_put(&dev->raw->kfifo, *ev)) {
 		dev_err(&dev->dev, "IR event FIFO is full!\n");
@@ -168,7 +168,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
 	if (!dev->raw)
 		return;
 
-	IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
+	dev_dbg(&dev->dev, "%s idle mode\n", idle ? "enter" : "leave");
 
 	if (idle) {
 		dev->raw->this_ev.timeout = true;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 1db8d38fed7c..4a952108ba1e 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -156,6 +156,7 @@ static struct rc_map_list empty_map = {
 
 /**
  * ir_create_table() - initializes a scancode table
+ * @dev:	the rc_dev device
  * @rc_map:	the rc_map to initialize
  * @name:	name to assign to the table
  * @rc_proto:	ir type to assign to the new table
@@ -166,7 +167,7 @@ static struct rc_map_list empty_map = {
  *
  * return:	zero on success or a negative error code
  */
-static int ir_create_table(struct rc_map *rc_map,
+static int ir_create_table(struct rc_dev *dev, struct rc_map *rc_map,
 			   const char *name, u64 rc_proto, size_t size)
 {
 	rc_map->name = kstrdup(name, GFP_KERNEL);
@@ -182,8 +183,8 @@ static int ir_create_table(struct rc_map *rc_map,
 		return -ENOMEM;
 	}
 
-	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
-		   rc_map->size, rc_map->alloc);
+	dev_dbg(&dev->dev, "Allocated space for %u keycode entries (%u bytes)\n",
+		rc_map->size, rc_map->alloc);
 	return 0;
 }
 
@@ -205,6 +206,7 @@ static void ir_free_table(struct rc_map *rc_map)
 
 /**
  * ir_resize_table() - resizes a scancode table if necessary
+ * @dev:	the rc_dev device
  * @rc_map:	the rc_map to resize
  * @gfp_flags:	gfp flags to use when allocating memory
  *
@@ -213,7 +215,8 @@ static void ir_free_table(struct rc_map *rc_map)
  *
  * return:	zero on success or a negative error code
  */
-static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
+static int ir_resize_table(struct rc_dev *dev, struct rc_map *rc_map,
+			   gfp_t gfp_flags)
 {
 	unsigned int oldalloc = rc_map->alloc;
 	unsigned int newalloc = oldalloc;
@@ -226,23 +229,21 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
 			return -ENOMEM;
 
 		newalloc *= 2;
-		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+		dev_dbg(&dev->dev, "Growing table to %u bytes\n", newalloc);
 	}
 
 	if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
 		/* Less than 1/3 of entries in use -> shrink keytable */
 		newalloc /= 2;
-		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+		dev_dbg(&dev->dev, "Shrinking table to %u bytes\n", newalloc);
 	}
 
 	if (newalloc == oldalloc)
 		return 0;
 
 	newscan = kmalloc(newalloc, gfp_flags);
-	if (!newscan) {
-		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+	if (!newscan)
 		return -ENOMEM;
-	}
 
 	memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
 	rc_map->scan = newscan;
@@ -275,16 +276,16 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
 
 	/* Did the user wish to remove the mapping? */
 	if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
-		IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
-			   index, rc_map->scan[index].scancode);
+		dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n",
+			index, rc_map->scan[index].scancode);
 		rc_map->len--;
 		memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
 			(rc_map->len - index) * sizeof(struct rc_map_table));
 	} else {
-		IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
-			   index,
-			   old_keycode == KEY_RESERVED ? "New" : "Replacing",
-			   rc_map->scan[index].scancode, new_keycode);
+		dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n",
+			index,
+			old_keycode == KEY_RESERVED ? "New" : "Replacing",
+			rc_map->scan[index].scancode, new_keycode);
 		rc_map->scan[index].keycode = new_keycode;
 		__set_bit(new_keycode, dev->input_dev->keybit);
 	}
@@ -301,7 +302,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
 		}
 
 		/* Possibly shrink the keytable, failure is not a problem */
-		ir_resize_table(rc_map, GFP_ATOMIC);
+		ir_resize_table(dev, rc_map, GFP_ATOMIC);
 	}
 
 	return old_keycode;
@@ -352,7 +353,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
 
 	/* No previous mapping found, we might need to grow the table */
 	if (rc_map->size == rc_map->len) {
-		if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
+		if (!resize || ir_resize_table(dev, rc_map, GFP_ATOMIC))
 			return -1U;
 	}
 
@@ -431,8 +432,8 @@ static int ir_setkeytable(struct rc_dev *dev,
 	unsigned int i, index;
 	int rc;
 
-	rc = ir_create_table(rc_map, from->name,
-			     from->rc_proto, from->size);
+	rc = ir_create_table(dev, rc_map, from->name, from->rc_proto,
+			     from->size);
 	if (rc)
 		return rc;
 
@@ -576,8 +577,8 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
 	spin_unlock_irqrestore(&rc_map->lock, flags);
 
 	if (keycode != KEY_RESERVED)
-		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
-			   dev->device_name, scancode, keycode);
+		dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n",
+			dev->device_name, scancode, keycode);
 
 	return keycode;
 }
@@ -596,7 +597,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync)
 	if (!dev->keypressed)
 		return;
 
-	IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
+	dev_dbg(&dev->dev, "keyup key 0x%04x\n", dev->last_keycode);
 	del_timer(&dev->timer_repeat);
 	input_report_key(dev->input_dev, dev->last_keycode, 0);
 	led_trigger_event(led_feedback, LED_OFF);
@@ -751,8 +752,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
 		/* Register a keypress */
 		dev->keypressed = true;
 
-		IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
-			   dev->device_name, keycode, protocol, scancode);
+		dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
+			dev->device_name, keycode, protocol, scancode);
 		input_report_key(dev->input_dev, keycode, 1);
 
 		led_trigger_event(led_feedback, LED_FULL);
@@ -1056,8 +1057,8 @@ static ssize_t show_protocols(struct device *device,
 
 	mutex_unlock(&dev->lock);
 
-	IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
-		   __func__, (long long)allowed, (long long)enabled);
+	dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
+		__func__, (long long)allowed, (long long)enabled);
 
 	for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
 		if (allowed & enabled & proto_names[i].type)
@@ -1083,6 +1084,7 @@ static ssize_t show_protocols(struct device *device,
 
 /**
  * parse_protocol_change() - parses a protocol change request
+ * @dev:	rc_dev device
  * @protocols:	pointer to the bitmask of current protocols
  * @buf:	pointer to the buffer with a list of changes
  *
@@ -1092,7 +1094,8 @@ static ssize_t show_protocols(struct device *device,
  * Writing "none" will disable all protocols.
  * Returns the number of changes performed or a negative error code.
  */
-static int parse_protocol_change(u64 *protocols, const char *buf)
+static int parse_protocol_change(struct rc_dev *dev, u64 *protocols,
+				 const char *buf)
 {
 	const char *tmp;
 	unsigned count = 0;
@@ -1128,7 +1131,8 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
 			if (!strcasecmp(tmp, "lirc"))
 				mask = 0;
 			else {
-				IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+				dev_dbg(&dev->dev, "Unknown protocol: '%s'\n",
+					tmp);
 				return -EINVAL;
 			}
 		}
@@ -1144,7 +1148,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
 	}
 
 	if (!count) {
-		IR_dprintk(1, "Protocol not specified\n");
+		dev_dbg(&dev->dev, "Protocol not specified\n");
 		return -EINVAL;
 	}
 
@@ -1217,12 +1221,12 @@ static ssize_t store_protocols(struct device *device,
 	u64 old_protocols, new_protocols;
 	ssize_t rc;
 
-	IR_dprintk(1, "Normal protocol change requested\n");
+	dev_dbg(&dev->dev, "Normal protocol change requested\n");
 	current_protocols = &dev->enabled_protocols;
 	filter = &dev->scancode_filter;
 
 	if (!dev->change_protocol) {
-		IR_dprintk(1, "Protocol switching not supported\n");
+		dev_dbg(&dev->dev, "Protocol switching not supported\n");
 		return -EINVAL;
 	}
 
@@ -1230,14 +1234,14 @@ static ssize_t store_protocols(struct device *device,
 
 	old_protocols = *current_protocols;
 	new_protocols = old_protocols;
-	rc = parse_protocol_change(&new_protocols, buf);
+	rc = parse_protocol_change(dev, &new_protocols, buf);
 	if (rc < 0)
 		goto out;
 
 	rc = dev->change_protocol(dev, &new_protocols);
 	if (rc < 0) {
-		IR_dprintk(1, "Error setting protocols to 0x%llx\n",
-			   (long long)new_protocols);
+		dev_dbg(&dev->dev, "Error setting protocols to 0x%llx\n",
+			(long long)new_protocols);
 		goto out;
 	}
 
@@ -1246,8 +1250,8 @@ static ssize_t store_protocols(struct device *device,
 
 	if (new_protocols != old_protocols) {
 		*current_protocols = new_protocols;
-		IR_dprintk(1, "Protocols changed to 0x%llx\n",
-			   (long long)new_protocols);
+		dev_dbg(&dev->dev, "Protocols changed to 0x%llx\n",
+			(long long)new_protocols);
 	}
 
 	/*
@@ -1435,8 +1439,8 @@ static ssize_t show_wakeup_protocols(struct device *device,
 
 	mutex_unlock(&dev->lock);
 
-	IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n",
-		   __func__, (long long)allowed, enabled);
+	dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - %d\n",
+		__func__, (long long)allowed, enabled);
 
 	for (i = 0; i < ARRAY_SIZE(protocols); i++) {
 		if (allowed & (1ULL << i)) {
@@ -1511,7 +1515,7 @@ static ssize_t store_wakeup_protocols(struct device *device,
 
 	if (dev->wakeup_protocol != protocol) {
 		dev->wakeup_protocol = protocol;
-		IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol);
+		dev_dbg(&dev->dev, "Wakeup protocol changed to %d\n", protocol);
 
 		if (protocol == RC_PROTO_RC6_MCE)
 			dev->scancode_wakeup_filter.data = 0x800f0000;
@@ -1874,9 +1878,8 @@ int rc_register_device(struct rc_dev *dev)
 
 	dev->registered = true;
 
-	IR_dprintk(1, "Registered rc%u (driver: %s)\n",
-		   dev->minor,
-		   dev->driver_name ? dev->driver_name : "unknown");
+	dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor,
+		dev->driver_name ? dev->driver_name : "unknown");
 
 	return 0;
 
@@ -1994,9 +1997,5 @@ static void __exit rc_core_exit(void)
 subsys_initcall(rc_core_init);
 module_exit(rc_core_exit);
 
-int rc_core_debug;    /* ir_debug level (0,1,2) */
-EXPORT_SYMBOL_GPL(rc_core_debug);
-module_param_named(debug, rc_core_debug, int, 0644);
-
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index e2ee5f00c445..d98c4ad7a9c3 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * v4l2-dv-timings - dv-timings helper functions
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 #include <linux/module.h>
diff --git a/drivers/memory/samsung/Kconfig b/drivers/memory/samsung/Kconfig
index 9de12222061c..79ce7ea58903 100644
--- a/drivers/memory/samsung/Kconfig
+++ b/drivers/memory/samsung/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
 config SAMSUNG_MC
 	bool "Samsung Exynos Memory Controller support" if COMPILE_TEST
 	help
diff --git a/drivers/memory/samsung/Makefile b/drivers/memory/samsung/Makefile
index 9c554d5522ad..00587be66211 100644
--- a/drivers/memory/samsung/Makefile
+++ b/drivers/memory/samsung/Makefile
@@ -1 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_EXYNOS_SROM)	+= exynos-srom.o
diff --git a/drivers/memory/samsung/exynos-srom.c b/drivers/memory/samsung/exynos-srom.c
index bf827a666694..7edd7fb540f2 100644
--- a/drivers/memory/samsung/exynos-srom.c
+++ b/drivers/memory/samsung/exynos-srom.c
@@ -1,14 +1,10 @@
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
- *	      http://www.samsung.com/
- *
- * EXYNOS - SROM Controller support
- * Author: Pankaj Dubey <pankaj.dubey@samsung.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2015 Samsung Electronics Co., Ltd.
+//	      http://www.samsung.com/
+//
+// EXYNOS - SROM Controller support
+// Author: Pankaj Dubey <pankaj.dubey@samsung.com>
 
 #include <linux/io.h>
 #include <linux/init.h>
diff --git a/drivers/memory/samsung/exynos-srom.h b/drivers/memory/samsung/exynos-srom.h
index 34660c6a57a9..da612797f522 100644
--- a/drivers/memory/samsung/exynos-srom.h
+++ b/drivers/memory/samsung/exynos-srom.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * Exynos SROMC register definitions
- *
- * 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 __EXYNOS_SROM_H
 #define __EXYNOS_SROM_H __FILE__
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 8d12017b9893..4470630dd545 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -2687,6 +2687,8 @@ mptctl_hp_targetinfo(unsigned long arg)
 				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
+	if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
+		return -EINVAL;
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
 	    ioc->name));
 
diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c
index 66d9e1baeae5..fbde2516c04f 100644
--- a/drivers/misc/eeprom/digsy_mtc_eeprom.c
+++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c
@@ -7,9 +7,18 @@
  * 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.
+ *
+ * FIXME: this driver is used on a device-tree probed platform: it
+ * should be defined as a bit-banged SPI device and probed from the device
+ * tree and not like this with static grabbing of a few numbered GPIO
+ * lines at random.
+ *
+ * Add proper SPI and EEPROM in arch/powerpc/boot/dts/digsy_mtc.dts
+ * and delete this driver.
  */
 
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
@@ -42,9 +51,6 @@ struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = {
 };
 
 static struct spi_gpio_platform_data eeprom_spi_gpio_data = {
-	.sck		= GPIO_EEPROM_CLK,
-	.mosi		= GPIO_EEPROM_DI,
-	.miso		= GPIO_EEPROM_DO,
 	.num_chipselect	= 1,
 };
 
@@ -56,6 +62,21 @@ static struct platform_device digsy_mtc_eeprom = {
 	},
 };
 
+static struct gpiod_lookup_table eeprom_spi_gpiod_table = {
+	.dev_id         = "spi_gpio",
+	.table          = {
+		GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CLK,
+			    "sck", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DI,
+			    "mosi", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_DO,
+			    "miso", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CS,
+			    "cs", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = {
 	{
 		.modalias		= "93xx46",
@@ -63,7 +84,6 @@ static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = {
 		.bus_num		= EE_SPI_BUS_NUM,
 		.chip_select		= 0,
 		.mode			= SPI_MODE_0,
-		.controller_data	= (void *)GPIO_EEPROM_CS,
 		.platform_data		= &digsy_mtc_eeprom_data,
 	},
 };
@@ -78,6 +98,7 @@ static int __init digsy_mtc_eeprom_devices_init(void)
 		pr_err("can't request gpio %d\n", GPIO_EEPROM_OE);
 		return ret;
 	}
+	gpiod_add_lookup_table(&eeprom_spi_gpiod_table);
 	spi_register_board_info(digsy_mtc_eeprom_info,
 				ARRAY_SIZE(digsy_mtc_eeprom_info));
 	return platform_device_register(&digsy_mtc_eeprom);
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 24108bfad889..6193270e7b3d 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -400,10 +400,14 @@ static void skip_back_repeat_test(char *arg)
 	int go_back = simple_strtol(arg, NULL, 10);
 
 	repeat_test--;
-	if (repeat_test <= 0)
+	if (repeat_test <= 0) {
 		ts.idx++;
-	else
+	} else {
+		if (repeat_test % 100 == 0)
+			v1printk("kgdbts:RUN ... %d remaining\n", repeat_test);
+
 		ts.idx -= go_back;
+	}
 	fill_get_buf(ts.tst[ts.idx].get);
 }
 
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 3e5eabdae8d9..772d02922529 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -548,12 +548,6 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
 		goto out;
 	}
 
-	if (bus->dev_state == MEI_DEV_POWER_DOWN) {
-		dev_dbg(bus->dev, "Device is powering down, don't bother with disconnection\n");
-		err = 0;
-		goto out;
-	}
-
 	err = mei_cl_disconnect(cl);
 	if (err < 0)
 		dev_err(bus->dev, "Could not disconnect from the ME client\n");
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index be64969d986a..7e60c1817c31 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -945,6 +945,12 @@ int mei_cl_disconnect(struct mei_cl *cl)
 		return 0;
 	}
 
+	if (dev->dev_state == MEI_DEV_POWER_DOWN) {
+		cl_dbg(dev, cl, "Device is powering down, don't bother with disconnection\n");
+		mei_cl_set_disconnected(cl);
+		return 0;
+	}
+
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
 		pm_runtime_put_noidle(dev->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c0ba6d8823b7..e01910dd964b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2369,7 +2369,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
 		return card->pref_erase;
 
 	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
-	if (mmc_can_trim(card)) {
+	if (max_discard && mmc_can_trim(card)) {
 		max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
 		if (max_trim < max_discard)
 			max_discard = max_trim;
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 7c03cfead6f9..a04f31fea72f 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -71,11 +71,11 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
 };
 
 static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
-	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
-			  TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY |
-			  TMIO_MMC_MIN_RCAR2,
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
+			  TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
 			  MMC_CAP_CMD23,
+	.capabilities2	= MMC_CAP2_NO_WRITE_PROTECT,
 	.bus_shift	= 2,
 	.scc_offset	= 0x1000,
 	.taps		= rcar_gen3_scc_taps,
@@ -145,7 +145,6 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
 	u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
 	enum dma_data_direction dir;
 	int ret;
-	u32 irq_mask;
 
 	/* This DMAC cannot handle if sg_len is not 1 */
 	WARN_ON(host->sg_len > 1);
@@ -157,11 +156,9 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
 	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);
@@ -170,9 +167,6 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
 
 	renesas_sdhi_internal_dmac_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 */
 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
 					    dtran_mode);
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index 82d757c480b2..4bb46c489d71 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -40,9 +40,9 @@ static const struct renesas_sdhi_of_data of_rz_compatible = {
 };
 
 static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
-	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
-			  TMIO_MMC_CLK_ACTUAL,
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL,
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+	.capabilities2	= MMC_CAP2_NO_WRITE_PROTECT,
 };
 
 /* Definitions for sampling clocks */
@@ -58,11 +58,11 @@ static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = {
 };
 
 static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
-	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
-			  TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY |
-			  TMIO_MMC_MIN_RCAR2,
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
+			  TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
 			  MMC_CAP_CMD23,
+	.capabilities2	= MMC_CAP2_NO_WRITE_PROTECT,
 	.dma_buswidth	= DMA_SLAVE_BUSWIDTH_4_BYTES,
 	.dma_rx_offset	= 0x2000,
 	.scc_offset	= 0x0300,
@@ -79,11 +79,11 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
 };
 
 static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
-	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
-			  TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY |
-			  TMIO_MMC_MIN_RCAR2,
+	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
+			  TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
 			  MMC_CAP_CMD23,
+	.capabilities2	= MMC_CAP2_NO_WRITE_PROTECT,
 	.bus_shift	= 2,
 	.scc_offset	= 0x1000,
 	.taps		= rcar_gen3_scc_taps,
@@ -205,8 +205,6 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
 		return;
 	}
 
-	tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY);
-
 	/* The only sg element can be unaligned, use our bounce buffer then */
 	if (!aligned) {
 		sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
@@ -280,8 +278,6 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
 		return;
 	}
 
-	tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ);
-
 	/* The only sg element can be unaligned, use our bounce buffer then */
 	if (!aligned) {
 		unsigned long flags;
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index 61666d269771..0ef741bc515d 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -214,6 +214,7 @@ static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
 		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
 		  SDHCI_QUIRK_MISSING_CAPS |
 		  SDHCI_QUIRK_NO_HISPD_BIT,
+	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 	.ops = &sdhci_iproc_32only_ops,
 };
 
diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 628bfe9a3d17..1456abd5eeb9 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -25,17 +25,32 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "sdhci-pltfm.h"
 
 #define SDHCI_OMAP_CON		0x12c
 #define CON_DW8			BIT(5)
 #define CON_DMA_MASTER		BIT(20)
+#define CON_DDR			BIT(19)
+#define CON_CLKEXTFREE		BIT(16)
+#define CON_PADEN		BIT(15)
 #define CON_INIT		BIT(1)
 #define CON_OD			BIT(0)
 
+#define SDHCI_OMAP_DLL		0x0134
+#define DLL_SWT			BIT(20)
+#define DLL_FORCE_SR_C_SHIFT	13
+#define DLL_FORCE_SR_C_MASK	(0x7f << DLL_FORCE_SR_C_SHIFT)
+#define DLL_FORCE_VALUE		BIT(12)
+#define DLL_CALIB		BIT(1)
+
 #define SDHCI_OMAP_CMD		0x20c
 
+#define SDHCI_OMAP_PSTATE	0x0224
+#define PSTATE_DLEV_DAT0	BIT(20)
+#define PSTATE_DATI		BIT(1)
+
 #define SDHCI_OMAP_HCTL		0x228
 #define HCTL_SDBP		BIT(8)
 #define HCTL_SDVS_SHIFT		9
@@ -56,12 +71,16 @@
 
 #define SDHCI_OMAP_AC12		0x23c
 #define AC12_V1V8_SIGEN		BIT(19)
+#define AC12_SCLK_SEL		BIT(23)
 
 #define SDHCI_OMAP_CAPA		0x240
 #define CAPA_VS33		BIT(24)
 #define CAPA_VS30		BIT(25)
 #define CAPA_VS18		BIT(26)
 
+#define SDHCI_OMAP_CAPA2	0x0244
+#define CAPA2_TSDR50		BIT(13)
+
 #define SDHCI_OMAP_TIMEOUT	1		/* 1 msec */
 
 #define SYSCTL_CLKD_MAX		0x3FF
@@ -70,8 +89,14 @@
 #define IOV_3V0			3000000		/* 300000 uV */
 #define IOV_3V3			3300000		/* 330000 uV */
 
+#define MAX_PHASE_DELAY		0x7C
+
+/* sdhci-omap controller flags */
+#define SDHCI_OMAP_REQUIRE_IODELAY	BIT(0)
+
 struct sdhci_omap_data {
 	u32 offset;
+	u8 flags;
 };
 
 struct sdhci_omap_host {
@@ -82,8 +107,16 @@ struct sdhci_omap_host {
 	struct sdhci_host	*host;
 	u8			bus_mode;
 	u8			power_mode;
+	u8			timing;
+	u8			flags;
+
+	struct pinctrl		*pinctrl;
+	struct pinctrl_state	**pinctrl_state;
 };
 
+static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host);
+static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host);
+
 static inline u32 sdhci_omap_readl(struct sdhci_omap_host *host,
 				   unsigned int offset)
 {
@@ -191,6 +224,178 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
 	}
 }
 
+static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
+				      int count)
+{
+	int i;
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_FORCE_VALUE;
+	reg &= ~DLL_FORCE_SR_C_MASK;
+	reg |= (count << DLL_FORCE_SR_C_SHIFT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	reg |= DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+	for (i = 0; i < 1000; i++) {
+		reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+		if (reg & DLL_CALIB)
+			break;
+	}
+	reg &= ~DLL_CALIB;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host)
+{
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	reg &= ~AC12_SCLK_SEL;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg);
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg &= ~(DLL_FORCE_VALUE | DLL_SWT);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+}
+
+static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+	struct device *dev = omap_host->dev;
+	struct mmc_ios *ios = &mmc->ios;
+	u32 start_window = 0, max_window = 0;
+	u8 cur_match, prev_match = 0;
+	u32 length = 0, max_len = 0;
+	u32 ier = host->ier;
+	u32 phase_delay = 0;
+	int ret = 0;
+	u32 reg;
+
+	pltfm_host = sdhci_priv(host);
+	omap_host = sdhci_pltfm_priv(pltfm_host);
+	dev = omap_host->dev;
+
+	/* clock tuning is not needed for upto 52MHz */
+	if (ios->clock <= 52000000)
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2);
+	if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
+		return 0;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
+	reg |= DLL_SWT;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
+
+	/*
+	 * OMAP5/DRA74X/DRA72x Errata i802:
+	 * DCRC error interrupts (MMCHS_STAT[21] DCRC=0x1) can occur
+	 * during the tuning procedure. So disable it during the
+	 * tuning procedure.
+	 */
+	ier &= ~SDHCI_INT_DATA_CRC;
+	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+
+	while (phase_delay <= MAX_PHASE_DELAY) {
+		sdhci_omap_set_dll(omap_host, phase_delay);
+
+		cur_match = !mmc_send_tuning(mmc, opcode, NULL);
+		if (cur_match) {
+			if (prev_match) {
+				length++;
+			} else {
+				start_window = phase_delay;
+				length = 1;
+			}
+		}
+
+		if (length > max_len) {
+			max_window = start_window;
+			max_len = length;
+		}
+
+		prev_match = cur_match;
+		phase_delay += 4;
+	}
+
+	if (!max_len) {
+		dev_err(dev, "Unable to find match\n");
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	if (!(reg & AC12_SCLK_SEL)) {
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	phase_delay = max_window + 4 * (max_len >> 1);
+	sdhci_omap_set_dll(omap_host, phase_delay);
+
+	goto ret;
+
+tuning_error:
+	dev_err(dev, "Tuning failed\n");
+	sdhci_omap_disable_tuning(omap_host);
+
+ret:
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+	return ret;
+}
+
+static int sdhci_omap_card_busy(struct mmc_host *mmc)
+{
+	u32 reg, ac12;
+	int ret = false;
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_omap_host *omap_host;
+	u32 ier = host->ier;
+
+	pltfm_host = sdhci_priv(host);
+	omap_host = sdhci_pltfm_priv(pltfm_host);
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+	ac12 = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
+	reg &= ~CON_CLKEXTFREE;
+	if (ac12 & AC12_V1V8_SIGEN)
+		reg |= CON_CLKEXTFREE;
+	reg |= CON_PADEN;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+	disable_irq(host->irq);
+	ier |= SDHCI_INT_CARD_INT;
+	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+
+	/*
+	 * Delay is required for PSTATE to correctly reflect
+	 * DLEV/CLEV values after PADEN is set.
+	 */
+	usleep_range(50, 100);
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_PSTATE);
+	if ((reg & PSTATE_DATI) || !(reg & PSTATE_DLEV_DAT0))
+		ret = true;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+	reg &= ~(CON_CLKEXTFREE | CON_PADEN);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+	enable_irq(host->irq);
+
+	return ret;
+}
+
 static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc,
 						  struct mmc_ios *ios)
 {
@@ -244,6 +449,39 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc,
 	return 0;
 }
 
+static void sdhci_omap_set_timing(struct sdhci_omap_host *omap_host, u8 timing)
+{
+	int ret;
+	struct pinctrl_state *pinctrl_state;
+	struct device *dev = omap_host->dev;
+
+	if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY))
+		return;
+
+	if (omap_host->timing == timing)
+		return;
+
+	sdhci_omap_stop_clock(omap_host);
+
+	pinctrl_state = omap_host->pinctrl_state[timing];
+	ret = pinctrl_select_state(omap_host->pinctrl, pinctrl_state);
+	if (ret) {
+		dev_err(dev, "failed to select pinctrl state\n");
+		return;
+	}
+
+	sdhci_omap_start_clock(omap_host);
+	omap_host->timing = timing;
+}
+
+static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host,
+				      u8 power_mode)
+{
+	if (omap_host->bus_mode == MMC_POWER_OFF)
+		sdhci_omap_disable_tuning(omap_host);
+	omap_host->power_mode = power_mode;
+}
+
 static void sdhci_omap_set_bus_mode(struct sdhci_omap_host *omap_host,
 				    unsigned int mode)
 {
@@ -272,7 +510,9 @@ static void sdhci_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	omap_host = sdhci_pltfm_priv(pltfm_host);
 
 	sdhci_omap_set_bus_mode(omap_host, ios->bus_mode);
+	sdhci_omap_set_timing(omap_host, ios->timing);
 	sdhci_set_ios(mmc, ios);
+	sdhci_omap_set_power_mode(omap_host, ios->power_mode);
 }
 
 static u16 sdhci_omap_calc_divisor(struct sdhci_pltfm_host *host,
@@ -401,8 +641,26 @@ static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode)
 	sdhci_omap_writel(omap_host, SDHCI_OMAP_STAT, INT_CC_EN);
 
 	enable_irq(host->irq);
+}
 
-	omap_host->power_mode = power_mode;
+static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host,
+					 unsigned int timing)
+{
+	u32 reg;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+
+	sdhci_omap_stop_clock(omap_host);
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+	if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52)
+		reg |= CON_DDR;
+	else
+		reg &= ~CON_DDR;
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+	sdhci_set_uhs_signaling(host, timing);
+	sdhci_omap_start_clock(omap_host);
 }
 
 static struct sdhci_ops sdhci_omap_ops = {
@@ -414,7 +672,7 @@ static struct sdhci_ops sdhci_omap_ops = {
 	.set_bus_width = sdhci_omap_set_bus_width,
 	.platform_send_init_74_clocks = sdhci_omap_init_74_clocks,
 	.reset = sdhci_reset,
-	.set_uhs_signaling = sdhci_set_uhs_signaling,
+	.set_uhs_signaling = sdhci_omap_set_uhs_signaling,
 };
 
 static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host)
@@ -453,14 +711,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = {
 		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
 		  SDHCI_QUIRK_NO_HISPD_BIT |
 		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
-	.quirks2 = SDHCI_QUIRK2_NO_1_8_V |
-		   SDHCI_QUIRK2_ACMD23_BROKEN |
+	.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN |
+		   SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
 		   SDHCI_QUIRK2_RSP_136_HAS_CRC,
 	.ops = &sdhci_omap_ops,
 };
 
 static const struct sdhci_omap_data dra7_data = {
 	.offset = 0x200,
+	.flags	= SDHCI_OMAP_REQUIRE_IODELAY,
 };
 
 static const struct of_device_id omap_sdhci_match[] = {
@@ -469,6 +728,108 @@ static const struct of_device_id omap_sdhci_match[] = {
 };
 MODULE_DEVICE_TABLE(of, omap_sdhci_match);
 
+static struct pinctrl_state
+*sdhci_omap_iodelay_pinctrl_state(struct sdhci_omap_host *omap_host, char *mode,
+				  u32 *caps, u32 capmask)
+{
+	struct device *dev = omap_host->dev;
+	struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV);
+
+	if (!(*caps & capmask))
+		goto ret;
+
+	pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
+	if (IS_ERR(pinctrl_state)) {
+		dev_err(dev, "no pinctrl state for %s mode", mode);
+		*caps &= ~capmask;
+	}
+
+ret:
+	return pinctrl_state;
+}
+
+static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
+						   *omap_host)
+{
+	struct device *dev = omap_host->dev;
+	struct sdhci_host *host = omap_host->host;
+	struct mmc_host *mmc = host->mmc;
+	u32 *caps = &mmc->caps;
+	u32 *caps2 = &mmc->caps2;
+	struct pinctrl_state *state;
+	struct pinctrl_state **pinctrl_state;
+
+	if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY))
+		return 0;
+
+	pinctrl_state = devm_kzalloc(dev, sizeof(*pinctrl_state) *
+				     (MMC_TIMING_MMC_HS200 + 1), GFP_KERNEL);
+	if (!pinctrl_state)
+		return -ENOMEM;
+
+	omap_host->pinctrl = devm_pinctrl_get(omap_host->dev);
+	if (IS_ERR(omap_host->pinctrl)) {
+		dev_err(dev, "Cannot get pinctrl\n");
+		return PTR_ERR(omap_host->pinctrl);
+	}
+
+	state = pinctrl_lookup_state(omap_host->pinctrl, "default");
+	if (IS_ERR(state)) {
+		dev_err(dev, "no pinctrl state for default mode\n");
+		return PTR_ERR(state);
+	}
+	pinctrl_state[MMC_TIMING_LEGACY] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr104", caps,
+						 MMC_CAP_UHS_SDR104);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_UHS_SDR104] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr50", caps,
+						 MMC_CAP_UHS_DDR50);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_UHS_DDR50] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr50", caps,
+						 MMC_CAP_UHS_SDR50);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_UHS_SDR50] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr25", caps,
+						 MMC_CAP_UHS_SDR25);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_UHS_SDR25] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr12", caps,
+						 MMC_CAP_UHS_SDR12);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_UHS_SDR12] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps,
+						 MMC_CAP_1_8V_DDR);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_MMC_DDR52] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps,
+						 MMC_CAP_SD_HIGHSPEED);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_SD_HS] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps,
+						 MMC_CAP_MMC_HIGHSPEED);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_MMC_HS] = state;
+
+	state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs200_1_8v", caps2,
+						 MMC_CAP2_HS200_1_8V_SDR);
+	if (!IS_ERR(state))
+		pinctrl_state[MMC_TIMING_MMC_HS200] = state;
+
+	omap_host->pinctrl_state = pinctrl_state;
+
+	return 0;
+}
+
 static int sdhci_omap_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -504,6 +865,9 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	omap_host->host = host;
 	omap_host->base = host->ioaddr;
 	omap_host->dev = dev;
+	omap_host->power_mode = MMC_POWER_UNDEFINED;
+	omap_host->timing = MMC_TIMING_LEGACY;
+	omap_host->flags = data->flags;
 	host->ioaddr += offset;
 
 	mmc = host->mmc;
@@ -552,10 +916,16 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 		goto err_put_sync;
 	}
 
+	ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
+	if (ret)
+		goto err_put_sync;
+
 	host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
 	host->mmc_host_ops.start_signal_voltage_switch =
 					sdhci_omap_start_signal_voltage_switch;
 	host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
+	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
+	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
 
 	sdhci_read_caps(host);
 	host->caps |= SDHCI_CAN_DO_ADMA2;
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 7bb00c68a756..4c2a1f8ddbf3 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -7,13 +7,6 @@
  * 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.
- *
- *
- * TODO
- *  1. DMA
- *  2. Power management
- *  3. Handle MMC errors better
- *
  */
 
 /*
@@ -67,7 +60,6 @@
 #include <linux/module.h>
 
 #define DRIVER_NAME	"sh_mmcif"
-#define DRIVER_VERSION	"2010-04-28"
 
 /* CE_CMD_SET */
 #define CMD_MASK		0x3f000000
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 33494241245a..0e8e46e906b2 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -350,8 +350,6 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host,
 			c |= TRANSFER_READ;
 	}
 
-	if (!host->native_hotplug)
-		irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
 	tmio_mmc_enable_mmc_irqs(host, irq_mask);
 
 	/* Fire off the command */
@@ -623,15 +621,21 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat)
 	 */
 	if (host->data && (!cmd->error || cmd->error == -EILSEQ)) {
 		if (host->data->flags & MMC_DATA_READ) {
-			if (host->force_pio || !host->chan_rx)
+			if (host->force_pio || !host->chan_rx) {
 				tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
-			else
+			} else {
+				tmio_mmc_disable_mmc_irqs(host,
+							  TMIO_MASK_READOP);
 				tasklet_schedule(&host->dma_issue);
+			}
 		} else {
-			if (host->force_pio || !host->chan_tx)
+			if (host->force_pio || !host->chan_tx) {
 				tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
-			else
+			} else {
+				tmio_mmc_disable_mmc_irqs(host,
+							  TMIO_MASK_WRITEOP);
 				tasklet_schedule(&host->dma_issue);
+			}
 		}
 	} else {
 		schedule_work(&host->done);
@@ -1061,10 +1065,17 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
 {
 	struct tmio_mmc_host *host = mmc_priv(mmc);
-	struct tmio_mmc_data *pdata = host->pdata;
 
-	return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
-		 (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
+	return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) &
+		 TMIO_STAT_WRPROTECT);
+}
+
+static int tmio_mmc_get_cd(struct mmc_host *mmc)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+
+	return !!(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) &
+		  TMIO_STAT_SIGSTATE);
 }
 
 static int tmio_multi_io_quirk(struct mmc_card *card,
@@ -1082,7 +1093,7 @@ static const struct mmc_host_ops tmio_mmc_ops = {
 	.request	= tmio_mmc_request,
 	.set_ios	= tmio_mmc_set_ios,
 	.get_ro         = tmio_mmc_get_ro,
-	.get_cd		= mmc_gpio_get_cd,
+	.get_cd		= tmio_mmc_get_cd,
 	.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
 	.multi_io_quirk	= tmio_multi_io_quirk,
 	.hw_reset	= tmio_mmc_hw_reset,
@@ -1114,15 +1125,20 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
 }
 
 static void tmio_mmc_of_parse(struct platform_device *pdev,
-			      struct tmio_mmc_data *pdata)
+			      struct mmc_host *mmc)
 {
 	const struct device_node *np = pdev->dev.of_node;
 
 	if (!np)
 		return;
 
+	/*
+	 * DEPRECATED:
+	 * For new platforms, please use "disable-wp" instead of
+	 * "toshiba,mmc-wrprotect-disable"
+	 */
 	if (of_get_property(np, "toshiba,mmc-wrprotect-disable", NULL))
-		pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE;
+		mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
 }
 
 struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev,
@@ -1157,7 +1173,7 @@ struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev,
 		goto free;
 	}
 
-	tmio_mmc_of_parse(pdev, pdata);
+	tmio_mmc_of_parse(pdev, mmc);
 
 	platform_set_drvdata(pdev, host);
 
@@ -1230,6 +1246,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
 	if (mmc_can_gpio_ro(mmc))
 		_host->ops.get_ro = mmc_gpio_get_ro;
 
+	if (mmc_can_gpio_cd(mmc))
+		_host->ops.get_ro = mmc_gpio_get_cd;
+
 	_host->native_hotplug = !(mmc_can_gpio_cd(mmc) ||
 				  mmc->caps & MMC_CAP_NEEDS_POLL ||
 				  !mmc_card_is_removable(mmc));
@@ -1260,16 +1279,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
 	_host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK);
 	tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
 
-	/* Unmask the IRQs we want to know about */
-	if (!_host->chan_rx)
-		irq_mask |= TMIO_MASK_READOP;
-	if (!_host->chan_tx)
-		irq_mask |= TMIO_MASK_WRITEOP;
-	if (!_host->native_hotplug)
-		irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
-
 	_host->sdcard_irq_mask &= ~irq_mask;
 
+	if (_host->native_hotplug)
+		tmio_mmc_enable_mmc_irqs(_host,
+				TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+
 	spin_lock_init(&_host->lock);
 	mutex_init(&_host->ios_lock);
 
@@ -1367,6 +1382,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
 	if (host->clk_cache)
 		tmio_mmc_set_clock(host, host->clk_cache);
 
+	if (host->native_hotplug)
+		tmio_mmc_enable_mmc_irqs(host,
+				TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+
 	tmio_mmc_enable_dma(host, true);
 
 	if (tmio_mmc_can_retune(host) && host->select_tuning(host))
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 28553c840d32..a1c94526fb88 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -641,29 +641,6 @@ int del_mtd_device(struct mtd_info *mtd)
 	return ret;
 }
 
-static int mtd_add_device_partitions(struct mtd_info *mtd,
-				     struct mtd_partitions *parts)
-{
-	const struct mtd_partition *real_parts = parts->parts;
-	int nbparts = parts->nr_parts;
-	int ret;
-
-	if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
-		ret = add_mtd_device(mtd);
-		if (ret)
-			return ret;
-	}
-
-	if (nbparts > 0) {
-		ret = add_mtd_partitions(mtd, real_parts, nbparts);
-		if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
-			del_mtd_device(mtd);
-		return ret;
-	}
-
-	return 0;
-}
-
 /*
  * Set a few defaults based on the parent devices, if not provided by the
  * driver
@@ -714,29 +691,31 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 			      const struct mtd_partition *parts,
 			      int nr_parts)
 {
-	struct mtd_partitions parsed;
+	struct mtd_partitions parsed = { };
 	int ret;
 
 	mtd_set_dev_defaults(mtd);
 
-	memset(&parsed, 0, sizeof(parsed));
+	if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
+		ret = add_mtd_device(mtd);
+		if (ret)
+			return ret;
+	}
 
+	/* Prefer parsed partitions over driver-provided fallback */
 	ret = parse_mtd_partitions(mtd, types, &parsed, parser_data);
-	if ((ret < 0 || parsed.nr_parts == 0) && parts && nr_parts) {
-		/* Fall back to driver-provided partitions */
-		parsed = (struct mtd_partitions){
-			.parts		= parts,
-			.nr_parts	= nr_parts,
-		};
-	} else if (ret < 0) {
-		/* Didn't come up with parsed OR fallback partitions */
-		pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
-			ret);
-		/* Don't abort on errors; we can still use unpartitioned MTD */
-		memset(&parsed, 0, sizeof(parsed));
+	if (!ret && parsed.nr_parts) {
+		parts = parsed.parts;
+		nr_parts = parsed.nr_parts;
 	}
 
-	ret = mtd_add_device_partitions(mtd, &parsed);
+	if (nr_parts)
+		ret = add_mtd_partitions(mtd, parts, nr_parts);
+	else if (!device_is_registered(&mtd->dev))
+		ret = add_mtd_device(mtd);
+	else
+		ret = 0;
+
 	if (ret)
 		goto out;
 
@@ -758,6 +737,9 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 out:
 	/* Cleanup any parsed partitions */
 	mtd_part_parser_cleanup(&parsed);
+	if (ret && device_is_registered(&mtd->dev))
+		del_mtd_device(mtd);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(mtd_device_parse_register);
@@ -971,10 +953,14 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
  */
 int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
+	if (!mtd->erasesize || !mtd->_erase)
+		return -ENOTSUPP;
+
 	if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
 		return -EINVAL;
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
+
 	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 	if (!instr->len) {
 		instr->state = MTD_ERASE_DONE;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 736ac887303c..1c1a1f487e20 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,580 +1,4 @@
-config MTD_NAND_ECC
+config MTD_NAND_CORE
 	tristate
 
-config MTD_NAND_ECC_SMC
-	bool "NAND ECC Smart Media byte order"
-	depends on MTD_NAND_ECC
-	default n
-	help
-	  Software ECC according to the Smart Media Specification.
-	  The original Linux implementation had byte 0 and 1 swapped.
-
-
-menuconfig MTD_NAND
-	tristate "NAND Device Support"
-	depends on MTD
-	select MTD_NAND_ECC
-	help
-	  This enables support for accessing all type of NAND flash
-	  devices. For further information see
-	  <http://www.linux-mtd.infradead.org/doc/nand.html>.
-
-if MTD_NAND
-
-config MTD_NAND_BCH
-	tristate
-	select BCH
-	depends on MTD_NAND_ECC_BCH
-	default MTD_NAND
-
-config MTD_NAND_ECC_BCH
-	bool "Support software BCH ECC"
-	default n
-	help
-	  This enables support for software BCH error correction. Binary BCH
-	  codes are more powerful and cpu intensive than traditional Hamming
-	  ECC codes. They are used with NAND devices requiring more than 1 bit
-	  of error correction.
-
-config MTD_SM_COMMON
-	tristate
-	default n
-
-config MTD_NAND_DENALI
-	tristate
-
-config MTD_NAND_DENALI_PCI
-        tristate "Support Denali NAND controller on Intel Moorestown"
-	select MTD_NAND_DENALI
-	depends on HAS_DMA && PCI
-        help
-          Enable the driver for NAND flash on Intel Moorestown, using the
-          Denali NAND controller core.
-
-config MTD_NAND_DENALI_DT
-	tristate "Support Denali NAND controller as a DT device"
-	select MTD_NAND_DENALI
-	depends on HAS_DMA && HAVE_CLK && OF
-	help
-	  Enable the driver for NAND flash on platforms using a Denali NAND
-	  controller as a DT device.
-
-config MTD_NAND_GPIO
-	tristate "GPIO assisted NAND Flash driver"
-	depends on GPIOLIB || COMPILE_TEST
-	depends on HAS_IOMEM
-	help
-	  This enables a NAND flash driver where control signals are
-	  connected to GPIO pins, and commands and data are communicated
-	  via a memory mapped interface.
-
-config MTD_NAND_AMS_DELTA
-	tristate "NAND Flash device on Amstrad E3"
-	depends on MACH_AMS_DELTA
-	default y
-	help
-	  Support for NAND flash on Amstrad E3 (Delta).
-
-config MTD_NAND_OMAP2
-	tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
-	depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
-	help
-          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
-	  and Keystone platforms.
-
-config MTD_NAND_OMAP_BCH
-	depends on MTD_NAND_OMAP2
-	bool "Support hardware based BCH error correction"
-	default n
-	select BCH
-	help
-	  This config enables the ELM hardware engine, which can be used to
-	  locate and correct errors when using BCH ECC scheme. This offloads
-	  the cpu from doing ECC error searching and correction. However some
-	  legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
-	  so this is optional for them.
-
-config MTD_NAND_OMAP_BCH_BUILD
-	def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
-
-config MTD_NAND_RICOH
-	tristate "Ricoh xD card reader"
-	default n
-	depends on PCI
-	select MTD_SM_COMMON
-	help
-	  Enable support for Ricoh R5C852 xD card reader
-	  You also need to enable ether
-	  NAND SSFDC (SmartMedia) read only translation layer' or new
-	  expermental, readwrite
-	  'SmartMedia/xD new translation layer'
-
-config MTD_NAND_AU1550
-	tristate "Au1550/1200 NAND support"
-	depends on MIPS_ALCHEMY
-	help
-	  This enables the driver for the NAND flash controller on the
-	  AMD/Alchemy 1550 SOC.
-
-config MTD_NAND_BF5XX
-	tristate "Blackfin on-chip NAND Flash Controller driver"
-	depends on BF54x || BF52x
-	help
-	  This enables the Blackfin on-chip NAND flash controller
-
-	  No board specific support is done by this driver, each board
-	  must advertise a platform_device for the driver to attach.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called bf5xx-nand.
-
-config MTD_NAND_BF5XX_HWECC
-	bool "BF5XX NAND Hardware ECC"
-	default y
-	depends on MTD_NAND_BF5XX
-	help
-	  Enable the use of the BF5XX's internal ECC generator when
-	  using NAND.
-
-config MTD_NAND_BF5XX_BOOTROM_ECC
-	bool "Use Blackfin BootROM ECC Layout"
-	default n
-	depends on MTD_NAND_BF5XX_HWECC
-	help
-	  If you wish to modify NAND pages and allow the Blackfin on-chip
-	  BootROM to boot from them, say Y here.  This is only necessary
-	  if you are booting U-Boot out of NAND and you wish to update
-	  U-Boot from Linux' userspace.  Otherwise, you should say N here.
-
-	  If unsure, say N.
-
-config MTD_NAND_S3C2410
-	tristate "NAND Flash support for Samsung S3C SoCs"
-	depends on ARCH_S3C24XX || ARCH_S3C64XX
-	help
-	  This enables the NAND flash controller on the S3C24xx and S3C64xx
-	  SoCs
-
-	  No board specific support is done by this driver, each board
-	  must advertise a platform_device for the driver to attach.
-
-config MTD_NAND_S3C2410_DEBUG
-	bool "Samsung S3C NAND driver debug"
-	depends on MTD_NAND_S3C2410
-	help
-	  Enable debugging of the S3C NAND driver
-
-config MTD_NAND_NDFC
-	tristate "NDFC NanD Flash Controller"
-	depends on 4xx
-	select MTD_NAND_ECC_SMC
-	help
-	 NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
-
-config MTD_NAND_S3C2410_CLKSTOP
-	bool "Samsung S3C NAND IDLE clock stop"
-	depends on MTD_NAND_S3C2410
-	default n
-	help
-	  Stop the clock to the NAND controller when there is no chip
-	  selected to save power. This will mean there is a small delay
-	  when the is NAND chip selected or released, but will save
-	  approximately 5mA of power when there is nothing happening.
-
-config MTD_NAND_TANGO
-	tristate "NAND Flash support for Tango chips"
-	depends on ARCH_TANGO || COMPILE_TEST
-	depends on HAS_DMA
-	help
-	  Enables the NAND Flash controller on Tango chips.
-
-config MTD_NAND_DISKONCHIP
-	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
-	depends on HAS_IOMEM
-	select REED_SOLOMON
-	select REED_SOLOMON_DEC16
-	help
-	  This is a reimplementation of M-Systems DiskOnChip 2000,
-	  Millennium and Millennium Plus as a standard NAND device driver,
-	  as opposed to the earlier self-contained MTD device drivers.
-	  This should enable, among other things, proper JFFS2 operation on
-	  these devices.
-
-config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        bool "Advanced detection options for DiskOnChip"
-        depends on MTD_NAND_DISKONCHIP
-        help
-          This option allows you to specify nonstandard address at which to
-          probe for a DiskOnChip, or to change the detection options.  You
-          are unlikely to need any of this unless you are using LinuxBIOS.
-          Say 'N'.
-
-config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
-        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        depends on MTD_NAND_DISKONCHIP
-        default "0"
-        ---help---
-        By default, the probe for DiskOnChip devices will look for a
-        DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-        This option allows you to specify a single address at which to probe
-        for the device, which is useful if you have other devices in that
-        range which get upset when they are probed.
-
-        (Note that on PowerPC, the normal probe will only check at
-        0xE4000000.)
-
-        Normally, you should leave this set to zero, to allow the probe at
-        the normal addresses.
-
-config MTD_NAND_DISKONCHIP_PROBE_HIGH
-        bool "Probe high addresses"
-        depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        help
-          By default, the probe for DiskOnChip devices will look for a
-          DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-          This option changes to make it probe between 0xFFFC8000 and
-          0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-          useful to you.  Say 'N'.
-
-config MTD_NAND_DISKONCHIP_BBTWRITE
-	bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
-	depends on MTD_NAND_DISKONCHIP
-	help
-	  On DiskOnChip devices shipped with the INFTL filesystem (Millennium
-	  and 2000 TSOP/Alon), Linux reserves some space at the end of the
-	  device for the Bad Block Table (BBT).  If you have existing INFTL
-	  data on your device (created by non-Linux tools such as M-Systems'
-	  DOS drivers), your data might overlap the area Linux wants to use for
-	  the BBT.  If this is a concern for you, leave this option disabled and
-	  Linux will not write BBT data into this area.
-	  The downside of leaving this option disabled is that if bad blocks
-	  are detected by Linux, they will not be recorded in the BBT, which
-	  could cause future problems.
-	  Once you enable this option, new filesystems (INFTL or others, created
-	  in Linux or other operating systems) will not use the reserved area.
-	  The only reason not to enable this option is to prevent damage to
-	  preexisting filesystems.
-	  Even if you leave this disabled, you can enable BBT writes at module
-	  load time (assuming you build diskonchip as a module) with the module
-	  parameter "inftl_bbt_write=1".
-
-config MTD_NAND_DOCG4
-	tristate "Support for DiskOnChip G4"
-	depends on HAS_IOMEM
-	select BCH
-	select BITREVERSE
-	help
-	  Support for diskonchip G4 nand flash, found in various smartphones and
-	  PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
-	  Portege G900, Asus P526, and O2 XDA Zinc.
-
-	  With this driver you will be able to use UBI and create a ubifs on the
-	  device, so you may wish to consider enabling UBI and UBIFS as well.
-
-	  These devices ship with the Mys/Sandisk SAFTL formatting, for which
-	  there is currently no mtd parser, so you may want to use command line
-	  partitioning to segregate write-protected blocks. On the Treo680, the
-	  first five erase blocks (256KiB each) are write-protected, followed
-	  by the block containing the saftl partition table.  This is probably
-	  typical.
-
-config MTD_NAND_SHARPSL
-	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
-	depends on ARCH_PXA
-
-config MTD_NAND_CAFE
-	tristate "NAND support for OLPC CAFÉ chip"
-	depends on PCI
-	select REED_SOLOMON
-	select REED_SOLOMON_DEC16
-	help
-	  Use NAND flash attached to the CAFÉ chip designed for the OLPC
-	  laptop.
-
-config MTD_NAND_CS553X
-	tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
-	depends on X86_32
-	depends on !UML && HAS_IOMEM
-	help
-	  The CS553x companion chips for the AMD Geode processor
-	  include NAND flash controllers with built-in hardware ECC
-	  capabilities; enabling this option will allow you to use
-	  these. The driver will check the MSRs to verify that the
-	  controller is enabled for NAND, and currently requires that
-	  the controller be in MMIO mode.
-
-	  If you say "m", the module will be called cs553x_nand.
-
-config MTD_NAND_ATMEL
-	tristate "Support for NAND Flash / SmartMedia on AT91"
-	depends on ARCH_AT91
-	select MFD_ATMEL_SMC
-	help
-	  Enables support for NAND Flash / Smart Media Card interface
-	  on Atmel AT91 processors.
-
-config MTD_NAND_PXA3xx
-	tristate "NAND support on PXA3xx and Armada 370/XP"
-	depends on !MTD_NAND_MARVELL
-	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU
-	help
-
-	  This enables the driver for the NAND flash device found on
-	  PXA3xx processors (NFCv1) and also on 32-bit Armada
-	  platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada
-	  platforms (7K, 8K) (NFCv2).
-
-config MTD_NAND_MARVELL
-	tristate "NAND controller support on Marvell boards"
-	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
-		   COMPILE_TEST
-	depends on HAS_IOMEM && HAS_DMA
-	help
-	  This enables the NAND flash controller driver for Marvell boards,
-	  including:
-	  - PXA3xx processors (NFCv1)
-	  - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
-	  - 64-bit Aramda platforms (7k, 8k) (NFCv2)
-
-config MTD_NAND_SLC_LPC32XX
-	tristate "NXP LPC32xx SLC Controller"
-	depends on ARCH_LPC32XX
-	help
-	  Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
-	  chips) NAND controller. This is the default for the PHYTEC 3250
-	  reference board which contains a NAND256R3A2CZA6 chip.
-
-	  Please check the actual NAND chip connected and its support
-	  by the SLC NAND controller.
-
-config MTD_NAND_MLC_LPC32XX
-	tristate "NXP LPC32xx MLC Controller"
-	depends on ARCH_LPC32XX
-	help
-	  Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
-	  controller. This is the default for the WORK92105 controller
-	  board.
-
-	  Please check the actual NAND chip connected and its support
-	  by the MLC NAND controller.
-
-config MTD_NAND_CM_X270
-	tristate "Support for NAND Flash on CM-X270 modules"
-	depends on MACH_ARMCORE
-
-config MTD_NAND_PASEMI
-	tristate "NAND support for PA Semi PWRficient"
-	depends on PPC_PASEMI
-	help
-	  Enables support for NAND Flash interface on PA Semi PWRficient
-	  based boards
-
-config MTD_NAND_TMIO
-	tristate "NAND Flash device on Toshiba Mobile IO Controller"
-	depends on MFD_TMIO
-	help
-	  Support for NAND flash connected to a Toshiba Mobile IO
-	  Controller in some PDAs, including the Sharp SL6000x.
-
-config MTD_NAND_NANDSIM
-	tristate "Support for NAND Flash Simulator"
-	help
-	  The simulator may simulate various NAND flash chips for the
-	  MTD nand layer.
-
-config MTD_NAND_GPMI_NAND
-        tristate "GPMI NAND Flash Controller driver"
-        depends on MTD_NAND && MXS_DMA
-        help
-	 Enables NAND Flash support for IMX23, IMX28 or IMX6.
-	 The GPMI controller is very powerful, with the help of BCH
-	 module, it can do the hardware ECC. The GPMI supports several
-	 NAND flashs at the same time.
-
-config MTD_NAND_BRCMNAND
-	tristate "Broadcom STB NAND controller"
-	depends on ARM || ARM64 || MIPS
-	help
-	  Enables the Broadcom NAND controller driver. The controller was
-	  originally designed for Set-Top Box but is used on various BCM7xxx,
-	  BCM3xxx, BCM63xxx, iProc/Cygnus and more.
-
-config MTD_NAND_BCM47XXNFLASH
-	tristate "Support for NAND flash on BCM4706 BCMA bus"
-	depends on BCMA_NFLASH
-	help
-	  BCMA bus can have various flash memories attached, they are
-	  registered by bcma as platform devices. This enables driver for
-	  NAND flash memories. For now only BCM4706 is supported.
-
-config MTD_NAND_PLATFORM
-	tristate "Support for generic platform NAND driver"
-	depends on HAS_IOMEM
-	help
-	  This implements a generic NAND driver for on-SOC platform
-	  devices. You will need to provide platform-specific functions
-	  via platform_data.
-
-config MTD_NAND_ORION
-	tristate "NAND Flash support for Marvell Orion SoC"
-	depends on PLAT_ORION
-	help
-	  This enables the NAND flash controller on Orion machines.
-
-	  No board specific support is done by this driver, each board
-	  must advertise a platform_device for the driver to attach.
-
-config MTD_NAND_OXNAS
-	tristate "NAND Flash support for Oxford Semiconductor SoC"
-	depends on ARCH_OXNAS || COMPILE_TEST
-	depends on HAS_IOMEM
-	help
-	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
-
-config MTD_NAND_FSL_ELBC
-	tristate "NAND support for Freescale eLBC controllers"
-	depends on FSL_SOC
-	select FSL_LBC
-	help
-	  Various Freescale chips, including the 8313, include a NAND Flash
-	  Controller Module with built-in hardware ECC capabilities.
-	  Enabling this option will enable you to use this to control
-	  external NAND devices.
-
-config MTD_NAND_FSL_IFC
-	tristate "NAND support for Freescale IFC controller"
-	depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
-	select FSL_IFC
-	select MEMORY
-	help
-	  Various Freescale chips e.g P1010, include a NAND Flash machine
-	  with built-in hardware ECC capabilities.
-	  Enabling this option will enable you to use this to control
-	  external NAND devices.
-
-config MTD_NAND_FSL_UPM
-	tristate "Support for NAND on Freescale UPM"
-	depends on PPC_83xx || PPC_85xx
-	select FSL_LBC
-	help
-	  Enables support for NAND Flash chips wired onto Freescale PowerPC
-	  processor localbus with User-Programmable Machine support.
-
-config MTD_NAND_MPC5121_NFC
-	tristate "MPC5121 built-in NAND Flash Controller support"
-	depends on PPC_MPC512x
-	help
-	  This enables the driver for the NAND flash controller on the
-	  MPC5121 SoC.
-
-config MTD_NAND_VF610_NFC
-	tristate "Support for Freescale NFC for VF610/MPC5125"
-	depends on (SOC_VF610 || COMPILE_TEST)
-	depends on HAS_IOMEM
-	help
-	  Enables support for NAND Flash Controller on some Freescale
-	  processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
-	  The driver supports a maximum 2k page size. With 2k pages and
-	  64 bytes or more of OOB, hardware ECC with up to 32-bit error
-	  correction is supported. Hardware ECC is only enabled through
-	  device tree.
-
-config MTD_NAND_MXC
-	tristate "MXC NAND support"
-	depends on ARCH_MXC
-	help
-	  This enables the driver for the NAND flash controller on the
-	  MXC processors.
-
-config MTD_NAND_SH_FLCTL
-	tristate "Support for NAND on Renesas SuperH FLCTL"
-	depends on SUPERH || COMPILE_TEST
-	depends on HAS_IOMEM
-	depends on HAS_DMA
-	help
-	  Several Renesas SuperH CPU has FLCTL. This option enables support
-	  for NAND Flash using FLCTL.
-
-config MTD_NAND_DAVINCI
-        tristate "Support NAND on DaVinci/Keystone SoC"
-        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
-        help
-	  Enable the driver for NAND flash chips on Texas Instruments
-	  DaVinci/Keystone processors.
-
-config MTD_NAND_TXX9NDFMC
-	tristate "NAND Flash support for TXx9 SoC"
-	depends on SOC_TX4938 || SOC_TX4939
-	help
-	  This enables the NAND flash controller on the TXx9 SoCs.
-
-config MTD_NAND_SOCRATES
-	tristate "Support for NAND on Socrates board"
-	depends on SOCRATES
-	help
-	  Enables support for NAND Flash chips wired onto Socrates board.
-
-config MTD_NAND_NUC900
-	tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
-	depends on ARCH_W90X900
-	help
-	  This enables the driver for the NAND Flash on evaluation board based
-	  on w90p910 / NUC9xx.
-
-config MTD_NAND_JZ4740
-	tristate "Support for JZ4740 SoC NAND controller"
-	depends on MACH_JZ4740
-	help
-		Enables support for NAND Flash on JZ4740 SoC based boards.
-
-config MTD_NAND_JZ4780
-	tristate "Support for NAND on JZ4780 SoC"
-	depends on MACH_JZ4780 && JZ4780_NEMC
-	help
-	  Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
-	  based boards, using the BCH controller for hardware error correction.
-
-config MTD_NAND_FSMC
-	tristate "Support for NAND on ST Micros FSMC"
-	depends on OF
-	depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
-	help
-	  Enables support for NAND Flash chips on the ST Microelectronics
-	  Flexible Static Memory Controller (FSMC)
-
-config MTD_NAND_XWAY
-	bool "Support for NAND on Lantiq XWAY SoC"
-	depends on LANTIQ && SOC_TYPE_XWAY
-	help
-	  Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
-	  to the External Bus Unit (EBU).
-
-config MTD_NAND_SUNXI
-	tristate "Support for NAND on Allwinner SoCs"
-	depends on ARCH_SUNXI
-	help
-	  Enables support for NAND Flash chips on Allwinner SoCs.
-
-config MTD_NAND_HISI504
-	tristate "Support for NAND controller on Hisilicon SoC Hip04"
-	depends on ARCH_HISI || COMPILE_TEST
-	depends on HAS_DMA
-	help
-	  Enables support for NAND controller on Hisilicon SoC Hip04.
-
-config MTD_NAND_QCOM
-	tristate "Support for NAND on QCOM SoCs"
-	depends on ARCH_QCOM
-	help
-	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
-	  controller. This controller is found on IPQ806x SoC.
-
-config MTD_NAND_MTK
-	tristate "Support for NAND controller on MTK SoCs"
-	depends on ARCH_MEDIATEK || COMPILE_TEST
-	depends on HAS_DMA
-	help
-	  Enables support for NAND controller on MTK SoCs.
-	  This controller is found on mt27xx, mt81xx, mt65xx SoCs.
-
-endif # MTD_NAND
+source "drivers/mtd/nand/raw/Kconfig"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 921634ba400c..a72d3cb0f325 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,71 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
-#
-# linux/drivers/nand/Makefile
-#
 
-obj-$(CONFIG_MTD_NAND)			+= nand.o
-obj-$(CONFIG_MTD_NAND_ECC)		+= nand_ecc.o
-obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
-obj-$(CONFIG_MTD_SM_COMMON) 		+= sm_common.o
+nandcore-objs := core.o bbt.o
+obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
 
-obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
-obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
-obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o
-obj-$(CONFIG_MTD_NAND_DENALI_PCI)	+= denali_pci.o
-obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
-obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
-obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
-obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
-obj-$(CONFIG_MTD_NAND_TANGO)		+= tango_nand.o
-obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
-obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
-obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
-obj-$(CONFIG_MTD_NAND_FSMC)		+= fsmc_nand.o
-obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
-obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nandsim.o
-obj-$(CONFIG_MTD_NAND_CS553X)		+= cs553x_nand.o
-obj-$(CONFIG_MTD_NAND_NDFC)		+= ndfc.o
-obj-$(CONFIG_MTD_NAND_ATMEL)		+= atmel/
-obj-$(CONFIG_MTD_NAND_GPIO)		+= gpio.o
-omap2_nand-objs := omap2.o
-obj-$(CONFIG_MTD_NAND_OMAP2) 		+= omap2_nand.o
-obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)	+= omap_elm.o
-obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
-obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
-obj-$(CONFIG_MTD_NAND_MARVELL)		+= marvell_nand.o
-obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
-obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
-obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
-obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
-obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
-obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
-obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
-obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
-obj-$(CONFIG_MTD_NAND_SLC_LPC32XX)      += lpc32xx_slc.o
-obj-$(CONFIG_MTD_NAND_MLC_LPC32XX)      += lpc32xx_mlc.o
-obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
-obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
-obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
-obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
-obj-$(CONFIG_MTD_NAND_NUC900)		+= nuc900_nand.o
-obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o
-obj-$(CONFIG_MTD_NAND_VF610_NFC)	+= vf610_nfc.o
-obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o
-obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
-obj-$(CONFIG_MTD_NAND_JZ4780)		+= jz4780_nand.o jz4780_bch.o
-obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
-obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
-obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
-obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
-obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
-obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
-obj-$(CONFIG_MTD_NAND_MTK)		+= mtk_ecc.o mtk_nand.o
-
-nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
-nand-objs += nand_amd.o
-nand-objs += nand_hynix.o
-nand-objs += nand_macronix.o
-nand-objs += nand_micron.o
-nand-objs += nand_samsung.o
-nand-objs += nand_toshiba.o
+obj-y	+= raw/
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
deleted file mode 100644
index d60ada45c549..000000000000
--- a/drivers/mtd/nand/ams-delta.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- *  drivers/mtd/nand/ams-delta.c
- *
- *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
- *
- *  Derived from drivers/mtd/toto.c
- *  Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
- *  Partially stolen from drivers/mtd/nand/plat_nand.c
- *
- * 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.
- *
- *  Overview:
- *   This is a device driver for the NAND flash device found on the
- *   Amstrad E3 (Delta).
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/gpio-omap.h>
-
-#include <asm/io.h>
-#include <asm/sizes.h>
-
-#include <mach/board-ams-delta.h>
-
-#include <mach/hardware.h>
-
-/*
- * MTD structure for E3 (Delta)
- */
-static struct mtd_info *ams_delta_mtd = NULL;
-
-/*
- * Define partitions for flash devices
- */
-
-static const struct mtd_partition partition_info[] = {
-	{ .name		= "Kernel",
-	  .offset	= 0,
-	  .size		= 3 * SZ_1M + SZ_512K },
-	{ .name		= "u-boot",
-	  .offset	= 3 * SZ_1M + SZ_512K,
-	  .size		= SZ_256K },
-	{ .name		= "u-boot params",
-	  .offset	= 3 * SZ_1M + SZ_512K + SZ_256K,
-	  .size		= SZ_256K },
-	{ .name		= "Amstrad LDR",
-	  .offset	= 4 * SZ_1M,
-	  .size		= SZ_256K },
-	{ .name		= "File system",
-	  .offset	= 4 * SZ_1M + 1 * SZ_256K,
-	  .size		= 27 * SZ_1M },
-	{ .name		= "PBL reserved",
-	  .offset	= 32 * SZ_1M - 3 * SZ_256K,
-	  .size		=  3 * SZ_256K },
-};
-
-static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
-
-	writew(0, io_base + OMAP_MPUIO_IO_CNTL);
-	writew(byte, this->IO_ADDR_W);
-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
-	ndelay(40);
-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
-}
-
-static u_char ams_delta_read_byte(struct mtd_info *mtd)
-{
-	u_char res;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
-
-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
-	ndelay(40);
-	writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
-	res = readw(this->IO_ADDR_R);
-	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
-
-	return res;
-}
-
-static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
-				int len)
-{
-	int i;
-
-	for (i=0; i<len; i++)
-		ams_delta_write_byte(mtd, buf[i]);
-}
-
-static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	int i;
-
-	for (i=0; i<len; i++)
-		buf[i] = ams_delta_read_byte(mtd);
-}
-
-/*
- * Command control function
- *
- * ctrl:
- * NAND_NCE: bit 0 -> bit 2
- * NAND_CLE: bit 1 -> bit 7
- * NAND_ALE: bit 2 -> bit 6
- */
-static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
-				unsigned int ctrl)
-{
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
-				(ctrl & NAND_NCE) == 0);
-		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
-				(ctrl & NAND_CLE) != 0);
-		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
-				(ctrl & NAND_ALE) != 0);
-	}
-
-	if (cmd != NAND_CMD_NONE)
-		ams_delta_write_byte(mtd, cmd);
-}
-
-static int ams_delta_nand_ready(struct mtd_info *mtd)
-{
-	return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
-}
-
-static const struct gpio _mandatory_gpio[] = {
-	{
-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NCE,
-		.flags	= GPIOF_OUT_INIT_HIGH,
-		.label	= "nand_nce",
-	},
-	{
-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NRE,
-		.flags	= GPIOF_OUT_INIT_HIGH,
-		.label	= "nand_nre",
-	},
-	{
-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWP,
-		.flags	= GPIOF_OUT_INIT_HIGH,
-		.label	= "nand_nwp",
-	},
-	{
-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWE,
-		.flags	= GPIOF_OUT_INIT_HIGH,
-		.label	= "nand_nwe",
-	},
-	{
-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_ALE,
-		.flags	= GPIOF_OUT_INIT_LOW,
-		.label	= "nand_ale",
-	},
-	{
-		.gpio	= AMS_DELTA_GPIO_PIN_NAND_CLE,
-		.flags	= GPIOF_OUT_INIT_LOW,
-		.label	= "nand_cle",
-	},
-};
-
-/*
- * Main initialization routine
- */
-static int ams_delta_init(struct platform_device *pdev)
-{
-	struct nand_chip *this;
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	void __iomem *io_base;
-	int err = 0;
-
-	if (!res)
-		return -ENXIO;
-
-	/* Allocate memory for MTD device structure and private data */
-	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
-	if (!this) {
-		printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
-		err = -ENOMEM;
-		goto out;
-	}
-
-	ams_delta_mtd = nand_to_mtd(this);
-	ams_delta_mtd->owner = THIS_MODULE;
-
-	/*
-	 * Don't try to request the memory region from here,
-	 * it should have been already requested from the
-	 * gpio-omap driver and requesting it again would fail.
-	 */
-
-	io_base = ioremap(res->start, resource_size(res));
-	if (io_base == NULL) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		err = -EIO;
-		goto out_free;
-	}
-
-	nand_set_controller_data(this, (void *)io_base);
-
-	/* Set address of NAND IO lines */
-	this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
-	this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
-	this->read_byte = ams_delta_read_byte;
-	this->write_buf = ams_delta_write_buf;
-	this->read_buf = ams_delta_read_buf;
-	this->cmd_ctrl = ams_delta_hwcontrol;
-	if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
-		this->dev_ready = ams_delta_nand_ready;
-	} else {
-		this->dev_ready = NULL;
-		printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
-	}
-	/* 25 us command delay time */
-	this->chip_delay = 30;
-	this->ecc.mode = NAND_ECC_SOFT;
-	this->ecc.algo = NAND_ECC_HAMMING;
-
-	platform_set_drvdata(pdev, io_base);
-
-	/* Set chip enabled, but  */
-	err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-	if (err)
-		goto out_gpio;
-
-	/* Scan to find existence of the device */
-	err = nand_scan(ams_delta_mtd, 1);
-	if (err)
-		goto out_mtd;
-
-	/* Register the partitions */
-	mtd_device_register(ams_delta_mtd, partition_info,
-			    ARRAY_SIZE(partition_info));
-
-	goto out;
-
- out_mtd:
-	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-out_gpio:
-	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
-	iounmap(io_base);
-out_free:
-	kfree(this);
- out:
-	return err;
-}
-
-/*
- * Clean up routine
- */
-static int ams_delta_cleanup(struct platform_device *pdev)
-{
-	void __iomem *io_base = platform_get_drvdata(pdev);
-
-	/* Release resources, unregister device */
-	nand_release(ams_delta_mtd);
-
-	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
-	iounmap(io_base);
-
-	/* Free the MTD device structure */
-	kfree(mtd_to_nand(ams_delta_mtd));
-
-	return 0;
-}
-
-static struct platform_driver ams_delta_nand_driver = {
-	.probe		= ams_delta_init,
-	.remove		= ams_delta_cleanup,
-	.driver		= {
-		.name	= "ams-delta-nand",
-	},
-};
-
-module_platform_driver(ams_delta_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
-MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
diff --git a/drivers/mtd/nand/atmel/Makefile b/drivers/mtd/nand/atmel/Makefile
deleted file mode 100644
index 288db4f38a8f..000000000000
--- a/drivers/mtd/nand/atmel/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-$(CONFIG_MTD_NAND_ATMEL)	+= atmel-nand-controller.o atmel-pmecc.o
-
-atmel-nand-controller-objs	:= nand-controller.o
-atmel-pmecc-objs		:= pmecc.o
diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c
deleted file mode 100644
index b2f00b398490..000000000000
--- a/drivers/mtd/nand/atmel/nand-controller.c
+++ /dev/null
@@ -1,2565 +0,0 @@
-/*
- * Copyright 2017 ATMEL
- * Copyright 2017 Free Electrons
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * Derived from the atmel_nand.c driver which contained the following
- * copyrights:
- *
- *   Copyright 2003 Rick Bronson
- *
- *   Derived from drivers/mtd/nand/autcpu12.c
- *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
- *
- *   Derived from drivers/mtd/spia.c
- *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
- *
- *
- *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
- *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
- *
- *   Derived from Das U-Boot source code
- *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
- *	Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
- *
- *   Add Programmable Multibit ECC support for various AT91 SoC
- *	Copyright 2012 ATMEL, Hong Xu
- *
- *   Add Nand Flash Controller support for SAMA5 SoC
- *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
- *
- * A few words about the naming convention in this file. This convention
- * applies to structure and function names.
- *
- * Prefixes:
- *
- * - atmel_nand_: all generic structures/functions
- * - atmel_smc_nand_: all structures/functions specific to the SMC interface
- *		      (at91sam9 and avr32 SoCs)
- * - atmel_hsmc_nand_: all structures/functions specific to the HSMC interface
- *		       (sama5 SoCs and later)
- * - atmel_nfc_: all structures/functions used to manipulate the NFC sub-block
- *		 that is available in the HSMC block
- * - <soc>_nand_: all SoC specific structures/functions
- */
-
-#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/genalloc.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/atmel-matrix.h>
-#include <linux/mfd/syscon/atmel-smc.h>
-#include <linux/module.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/iopoll.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-
-#include "pmecc.h"
-
-#define ATMEL_HSMC_NFC_CFG			0x0
-#define ATMEL_HSMC_NFC_CFG_SPARESIZE(x)		(((x) / 4) << 24)
-#define ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK	GENMASK(30, 24)
-#define ATMEL_HSMC_NFC_CFG_DTO(cyc, mul)	(((cyc) << 16) | ((mul) << 20))
-#define ATMEL_HSMC_NFC_CFG_DTO_MAX		GENMASK(22, 16)
-#define ATMEL_HSMC_NFC_CFG_RBEDGE		BIT(13)
-#define ATMEL_HSMC_NFC_CFG_FALLING_EDGE		BIT(12)
-#define ATMEL_HSMC_NFC_CFG_RSPARE		BIT(9)
-#define ATMEL_HSMC_NFC_CFG_WSPARE		BIT(8)
-#define ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK	GENMASK(2, 0)
-#define ATMEL_HSMC_NFC_CFG_PAGESIZE(x)		(fls((x) / 512) - 1)
-
-#define ATMEL_HSMC_NFC_CTRL			0x4
-#define ATMEL_HSMC_NFC_CTRL_EN			BIT(0)
-#define ATMEL_HSMC_NFC_CTRL_DIS			BIT(1)
-
-#define ATMEL_HSMC_NFC_SR			0x8
-#define ATMEL_HSMC_NFC_IER			0xc
-#define ATMEL_HSMC_NFC_IDR			0x10
-#define ATMEL_HSMC_NFC_IMR			0x14
-#define ATMEL_HSMC_NFC_SR_ENABLED		BIT(1)
-#define ATMEL_HSMC_NFC_SR_RB_RISE		BIT(4)
-#define ATMEL_HSMC_NFC_SR_RB_FALL		BIT(5)
-#define ATMEL_HSMC_NFC_SR_BUSY			BIT(8)
-#define ATMEL_HSMC_NFC_SR_WR			BIT(11)
-#define ATMEL_HSMC_NFC_SR_CSID			GENMASK(14, 12)
-#define ATMEL_HSMC_NFC_SR_XFRDONE		BIT(16)
-#define ATMEL_HSMC_NFC_SR_CMDDONE		BIT(17)
-#define ATMEL_HSMC_NFC_SR_DTOE			BIT(20)
-#define ATMEL_HSMC_NFC_SR_UNDEF			BIT(21)
-#define ATMEL_HSMC_NFC_SR_AWB			BIT(22)
-#define ATMEL_HSMC_NFC_SR_NFCASE		BIT(23)
-#define ATMEL_HSMC_NFC_SR_ERRORS		(ATMEL_HSMC_NFC_SR_DTOE | \
-						 ATMEL_HSMC_NFC_SR_UNDEF | \
-						 ATMEL_HSMC_NFC_SR_AWB | \
-						 ATMEL_HSMC_NFC_SR_NFCASE)
-#define ATMEL_HSMC_NFC_SR_RBEDGE(x)		BIT((x) + 24)
-
-#define ATMEL_HSMC_NFC_ADDR			0x18
-#define ATMEL_HSMC_NFC_BANK			0x1c
-
-#define ATMEL_NFC_MAX_RB_ID			7
-
-#define ATMEL_NFC_SRAM_SIZE			0x2400
-
-#define ATMEL_NFC_CMD(pos, cmd)			((cmd) << (((pos) * 8) + 2))
-#define ATMEL_NFC_VCMD2				BIT(18)
-#define ATMEL_NFC_ACYCLE(naddrs)		((naddrs) << 19)
-#define ATMEL_NFC_CSID(cs)			((cs) << 22)
-#define ATMEL_NFC_DATAEN			BIT(25)
-#define ATMEL_NFC_NFCWR				BIT(26)
-
-#define ATMEL_NFC_MAX_ADDR_CYCLES		5
-
-#define ATMEL_NAND_ALE_OFFSET			BIT(21)
-#define ATMEL_NAND_CLE_OFFSET			BIT(22)
-
-#define DEFAULT_TIMEOUT_MS			1000
-#define MIN_DMA_LEN				128
-
-enum atmel_nand_rb_type {
-	ATMEL_NAND_NO_RB,
-	ATMEL_NAND_NATIVE_RB,
-	ATMEL_NAND_GPIO_RB,
-};
-
-struct atmel_nand_rb {
-	enum atmel_nand_rb_type type;
-	union {
-		struct gpio_desc *gpio;
-		int id;
-	};
-};
-
-struct atmel_nand_cs {
-	int id;
-	struct atmel_nand_rb rb;
-	struct gpio_desc *csgpio;
-	struct {
-		void __iomem *virt;
-		dma_addr_t dma;
-	} io;
-
-	struct atmel_smc_cs_conf smcconf;
-};
-
-struct atmel_nand {
-	struct list_head node;
-	struct device *dev;
-	struct nand_chip base;
-	struct atmel_nand_cs *activecs;
-	struct atmel_pmecc_user *pmecc;
-	struct gpio_desc *cdgpio;
-	int numcs;
-	struct atmel_nand_cs cs[];
-};
-
-static inline struct atmel_nand *to_atmel_nand(struct nand_chip *chip)
-{
-	return container_of(chip, struct atmel_nand, base);
-}
-
-enum atmel_nfc_data_xfer {
-	ATMEL_NFC_NO_DATA,
-	ATMEL_NFC_READ_DATA,
-	ATMEL_NFC_WRITE_DATA,
-};
-
-struct atmel_nfc_op {
-	u8 cs;
-	u8 ncmds;
-	u8 cmds[2];
-	u8 naddrs;
-	u8 addrs[5];
-	enum atmel_nfc_data_xfer data;
-	u32 wait;
-	u32 errors;
-};
-
-struct atmel_nand_controller;
-struct atmel_nand_controller_caps;
-
-struct atmel_nand_controller_ops {
-	int (*probe)(struct platform_device *pdev,
-		     const struct atmel_nand_controller_caps *caps);
-	int (*remove)(struct atmel_nand_controller *nc);
-	void (*nand_init)(struct atmel_nand_controller *nc,
-			  struct atmel_nand *nand);
-	int (*ecc_init)(struct atmel_nand *nand);
-	int (*setup_data_interface)(struct atmel_nand *nand, int csline,
-				    const struct nand_data_interface *conf);
-};
-
-struct atmel_nand_controller_caps {
-	bool has_dma;
-	bool legacy_of_bindings;
-	u32 ale_offs;
-	u32 cle_offs;
-	const struct atmel_nand_controller_ops *ops;
-};
-
-struct atmel_nand_controller {
-	struct nand_hw_control base;
-	const struct atmel_nand_controller_caps *caps;
-	struct device *dev;
-	struct regmap *smc;
-	struct dma_chan *dmac;
-	struct atmel_pmecc *pmecc;
-	struct list_head chips;
-	struct clk *mck;
-};
-
-static inline struct atmel_nand_controller *
-to_nand_controller(struct nand_hw_control *ctl)
-{
-	return container_of(ctl, struct atmel_nand_controller, base);
-}
-
-struct atmel_smc_nand_controller {
-	struct atmel_nand_controller base;
-	struct regmap *matrix;
-	unsigned int ebi_csa_offs;
-};
-
-static inline struct atmel_smc_nand_controller *
-to_smc_nand_controller(struct nand_hw_control *ctl)
-{
-	return container_of(to_nand_controller(ctl),
-			    struct atmel_smc_nand_controller, base);
-}
-
-struct atmel_hsmc_nand_controller {
-	struct atmel_nand_controller base;
-	struct {
-		struct gen_pool *pool;
-		void __iomem *virt;
-		dma_addr_t dma;
-	} sram;
-	const struct atmel_hsmc_reg_layout *hsmc_layout;
-	struct regmap *io;
-	struct atmel_nfc_op op;
-	struct completion complete;
-	int irq;
-
-	/* Only used when instantiating from legacy DT bindings. */
-	struct clk *clk;
-};
-
-static inline struct atmel_hsmc_nand_controller *
-to_hsmc_nand_controller(struct nand_hw_control *ctl)
-{
-	return container_of(to_nand_controller(ctl),
-			    struct atmel_hsmc_nand_controller, base);
-}
-
-static bool atmel_nfc_op_done(struct atmel_nfc_op *op, u32 status)
-{
-	op->errors |= status & ATMEL_HSMC_NFC_SR_ERRORS;
-	op->wait ^= status & op->wait;
-
-	return !op->wait || op->errors;
-}
-
-static irqreturn_t atmel_nfc_interrupt(int irq, void *data)
-{
-	struct atmel_hsmc_nand_controller *nc = data;
-	u32 sr, rcvd;
-	bool done;
-
-	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &sr);
-
-	rcvd = sr & (nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
-	done = atmel_nfc_op_done(&nc->op, sr);
-
-	if (rcvd)
-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, rcvd);
-
-	if (done)
-		complete(&nc->complete);
-
-	return rcvd ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static int atmel_nfc_wait(struct atmel_hsmc_nand_controller *nc, bool poll,
-			  unsigned int timeout_ms)
-{
-	int ret;
-
-	if (!timeout_ms)
-		timeout_ms = DEFAULT_TIMEOUT_MS;
-
-	if (poll) {
-		u32 status;
-
-		ret = regmap_read_poll_timeout(nc->base.smc,
-					       ATMEL_HSMC_NFC_SR, status,
-					       atmel_nfc_op_done(&nc->op,
-								 status),
-					       0, timeout_ms * 1000);
-	} else {
-		init_completion(&nc->complete);
-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IER,
-			     nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
-		ret = wait_for_completion_timeout(&nc->complete,
-						msecs_to_jiffies(timeout_ms));
-		if (!ret)
-			ret = -ETIMEDOUT;
-		else
-			ret = 0;
-
-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
-	}
-
-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_DTOE) {
-		dev_err(nc->base.dev, "Waiting NAND R/B Timeout\n");
-		ret = -ETIMEDOUT;
-	}
-
-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_UNDEF) {
-		dev_err(nc->base.dev, "Access to an undefined area\n");
-		ret = -EIO;
-	}
-
-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_AWB) {
-		dev_err(nc->base.dev, "Access while busy\n");
-		ret = -EIO;
-	}
-
-	if (nc->op.errors & ATMEL_HSMC_NFC_SR_NFCASE) {
-		dev_err(nc->base.dev, "Wrong access size\n");
-		ret = -EIO;
-	}
-
-	return ret;
-}
-
-static void atmel_nand_dma_transfer_finished(void *data)
-{
-	struct completion *finished = data;
-
-	complete(finished);
-}
-
-static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
-				   void *buf, dma_addr_t dev_dma, size_t len,
-				   enum dma_data_direction dir)
-{
-	DECLARE_COMPLETION_ONSTACK(finished);
-	dma_addr_t src_dma, dst_dma, buf_dma;
-	struct dma_async_tx_descriptor *tx;
-	dma_cookie_t cookie;
-
-	buf_dma = dma_map_single(nc->dev, buf, len, dir);
-	if (dma_mapping_error(nc->dev, dev_dma)) {
-		dev_err(nc->dev,
-			"Failed to prepare a buffer for DMA access\n");
-		goto err;
-	}
-
-	if (dir == DMA_FROM_DEVICE) {
-		src_dma = dev_dma;
-		dst_dma = buf_dma;
-	} else {
-		src_dma = buf_dma;
-		dst_dma = dev_dma;
-	}
-
-	tx = dmaengine_prep_dma_memcpy(nc->dmac, dst_dma, src_dma, len,
-				       DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
-	if (!tx) {
-		dev_err(nc->dev, "Failed to prepare DMA memcpy\n");
-		goto err_unmap;
-	}
-
-	tx->callback = atmel_nand_dma_transfer_finished;
-	tx->callback_param = &finished;
-
-	cookie = dmaengine_submit(tx);
-	if (dma_submit_error(cookie)) {
-		dev_err(nc->dev, "Failed to do DMA tx_submit\n");
-		goto err_unmap;
-	}
-
-	dma_async_issue_pending(nc->dmac);
-	wait_for_completion(&finished);
-
-	return 0;
-
-err_unmap:
-	dma_unmap_single(nc->dev, buf_dma, len, dir);
-
-err:
-	dev_dbg(nc->dev, "Fall back to CPU I/O\n");
-
-	return -EIO;
-}
-
-static u8 atmel_nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-
-	return ioread8(nand->activecs->io.virt);
-}
-
-static u16 atmel_nand_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-
-	return ioread16(nand->activecs->io.virt);
-}
-
-static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-
-	if (chip->options & NAND_BUSWIDTH_16)
-		iowrite16(byte | (byte << 8), nand->activecs->io.virt);
-	else
-		iowrite8(byte, nand->activecs->io.virt);
-}
-
-static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_nand_controller *nc;
-
-	nc = to_nand_controller(chip->controller);
-
-	/*
-	 * If the controller supports DMA, the buffer address is DMA-able and
-	 * len is long enough to make DMA transfers profitable, let's trigger
-	 * a DMA transfer. If it fails, fallback to PIO mode.
-	 */
-	if (nc->dmac && virt_addr_valid(buf) &&
-	    len >= MIN_DMA_LEN &&
-	    !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len,
-				     DMA_FROM_DEVICE))
-		return;
-
-	if (chip->options & NAND_BUSWIDTH_16)
-		ioread16_rep(nand->activecs->io.virt, buf, len / 2);
-	else
-		ioread8_rep(nand->activecs->io.virt, buf, len);
-}
-
-static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_nand_controller *nc;
-
-	nc = to_nand_controller(chip->controller);
-
-	/*
-	 * If the controller supports DMA, the buffer address is DMA-able and
-	 * len is long enough to make DMA transfers profitable, let's trigger
-	 * a DMA transfer. If it fails, fallback to PIO mode.
-	 */
-	if (nc->dmac && virt_addr_valid(buf) &&
-	    len >= MIN_DMA_LEN &&
-	    !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma,
-				     len, DMA_TO_DEVICE))
-		return;
-
-	if (chip->options & NAND_BUSWIDTH_16)
-		iowrite16_rep(nand->activecs->io.virt, buf, len / 2);
-	else
-		iowrite8_rep(nand->activecs->io.virt, buf, len);
-}
-
-static int atmel_nand_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-
-	return gpiod_get_value(nand->activecs->rb.gpio);
-}
-
-static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-
-	if (cs < 0 || cs >= nand->numcs) {
-		nand->activecs = NULL;
-		chip->dev_ready = NULL;
-		return;
-	}
-
-	nand->activecs = &nand->cs[cs];
-
-	if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
-		chip->dev_ready = atmel_nand_dev_ready;
-}
-
-static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_hsmc_nand_controller *nc;
-	u32 status;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status);
-
-	return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
-}
-
-static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_hsmc_nand_controller *nc;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	atmel_nand_select_chip(mtd, cs);
-
-	if (!nand->activecs) {
-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
-			     ATMEL_HSMC_NFC_CTRL_DIS);
-		return;
-	}
-
-	if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
-		chip->dev_ready = atmel_hsmc_nand_dev_ready;
-
-	regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
-			   ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
-			   ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK |
-			   ATMEL_HSMC_NFC_CFG_RSPARE |
-			   ATMEL_HSMC_NFC_CFG_WSPARE,
-			   ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
-			   ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
-			   ATMEL_HSMC_NFC_CFG_RSPARE);
-	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
-		     ATMEL_HSMC_NFC_CTRL_EN);
-}
-
-static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
-{
-	u8 *addrs = nc->op.addrs;
-	unsigned int op = 0;
-	u32 addr, val;
-	int i, ret;
-
-	nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
-
-	for (i = 0; i < nc->op.ncmds; i++)
-		op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
-
-	if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
-		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
-
-	op |= ATMEL_NFC_CSID(nc->op.cs) |
-	      ATMEL_NFC_ACYCLE(nc->op.naddrs);
-
-	if (nc->op.ncmds > 1)
-		op |= ATMEL_NFC_VCMD2;
-
-	addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
-	       (addrs[3] << 24);
-
-	if (nc->op.data != ATMEL_NFC_NO_DATA) {
-		op |= ATMEL_NFC_DATAEN;
-		nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
-
-		if (nc->op.data == ATMEL_NFC_WRITE_DATA)
-			op |= ATMEL_NFC_NFCWR;
-	}
-
-	/* Clear all flags. */
-	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
-
-	/* Send the command. */
-	regmap_write(nc->io, op, addr);
-
-	ret = atmel_nfc_wait(nc, poll, 0);
-	if (ret)
-		dev_err(nc->base.dev,
-			"Failed to send NAND command (err = %d)!",
-			ret);
-
-	/* Reset the op state. */
-	memset(&nc->op, 0, sizeof(nc->op));
-
-	return ret;
-}
-
-static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
-				     unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_hsmc_nand_controller *nc;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	if (ctrl & NAND_ALE) {
-		if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
-			return;
-
-		nc->op.addrs[nc->op.naddrs++] = dat;
-	} else if (ctrl & NAND_CLE) {
-		if (nc->op.ncmds > 1)
-			return;
-
-		nc->op.cmds[nc->op.ncmds++] = dat;
-	}
-
-	if (dat == NAND_CMD_NONE) {
-		nc->op.cs = nand->activecs->id;
-		atmel_nfc_exec_op(nc, true);
-	}
-}
-
-static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-				unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_nand_controller *nc;
-
-	nc = to_nand_controller(chip->controller);
-
-	if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) {
-		if (ctrl & NAND_NCE)
-			gpiod_set_value(nand->activecs->csgpio, 0);
-		else
-			gpiod_set_value(nand->activecs->csgpio, 1);
-	}
-
-	if (ctrl & NAND_ALE)
-		writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs);
-	else if (ctrl & NAND_CLE)
-		writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs);
-}
-
-static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
-				   bool oob_required)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_hsmc_nand_controller *nc;
-	int ret = -EIO;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	if (nc->base.dmac)
-		ret = atmel_nand_dma_transfer(&nc->base, (void *)buf,
-					      nc->sram.dma, mtd->writesize,
-					      DMA_TO_DEVICE);
-
-	/* Falling back to CPU copy. */
-	if (ret)
-		memcpy_toio(nc->sram.virt, buf, mtd->writesize);
-
-	if (oob_required)
-		memcpy_toio(nc->sram.virt + mtd->writesize, chip->oob_poi,
-			    mtd->oobsize);
-}
-
-static void atmel_nfc_copy_from_sram(struct nand_chip *chip, u8 *buf,
-				     bool oob_required)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_hsmc_nand_controller *nc;
-	int ret = -EIO;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	if (nc->base.dmac)
-		ret = atmel_nand_dma_transfer(&nc->base, buf, nc->sram.dma,
-					      mtd->writesize, DMA_FROM_DEVICE);
-
-	/* Falling back to CPU copy. */
-	if (ret)
-		memcpy_fromio(buf, nc->sram.virt, mtd->writesize);
-
-	if (oob_required)
-		memcpy_fromio(chip->oob_poi, nc->sram.virt + mtd->writesize,
-			      mtd->oobsize);
-}
-
-static void atmel_nfc_set_op_addr(struct nand_chip *chip, int page, int column)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_hsmc_nand_controller *nc;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	if (column >= 0) {
-		nc->op.addrs[nc->op.naddrs++] = column;
-
-		/*
-		 * 2 address cycles for the column offset on large page NANDs.
-		 */
-		if (mtd->writesize > 512)
-			nc->op.addrs[nc->op.naddrs++] = column >> 8;
-	}
-
-	if (page >= 0) {
-		nc->op.addrs[nc->op.naddrs++] = page;
-		nc->op.addrs[nc->op.naddrs++] = page >> 8;
-
-		if (chip->options & NAND_ROW_ADDR_3)
-			nc->op.addrs[nc->op.naddrs++] = page >> 16;
-	}
-}
-
-static int atmel_nand_pmecc_enable(struct nand_chip *chip, int op, bool raw)
-{
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_nand_controller *nc;
-	int ret;
-
-	nc = to_nand_controller(chip->controller);
-
-	if (raw)
-		return 0;
-
-	ret = atmel_pmecc_enable(nand->pmecc, op);
-	if (ret)
-		dev_err(nc->dev,
-			"Failed to enable ECC engine (err = %d)\n", ret);
-
-	return ret;
-}
-
-static void atmel_nand_pmecc_disable(struct nand_chip *chip, bool raw)
-{
-	struct atmel_nand *nand = to_atmel_nand(chip);
-
-	if (!raw)
-		atmel_pmecc_disable(nand->pmecc);
-}
-
-static int atmel_nand_pmecc_generate_eccbytes(struct nand_chip *chip, bool raw)
-{
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand_controller *nc;
-	struct mtd_oob_region oobregion;
-	void *eccbuf;
-	int ret, i;
-
-	nc = to_nand_controller(chip->controller);
-
-	if (raw)
-		return 0;
-
-	ret = atmel_pmecc_wait_rdy(nand->pmecc);
-	if (ret) {
-		dev_err(nc->dev,
-			"Failed to transfer NAND page data (err = %d)\n",
-			ret);
-		return ret;
-	}
-
-	mtd_ooblayout_ecc(mtd, 0, &oobregion);
-	eccbuf = chip->oob_poi + oobregion.offset;
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		atmel_pmecc_get_generated_eccbytes(nand->pmecc, i,
-						   eccbuf);
-		eccbuf += chip->ecc.bytes;
-	}
-
-	return 0;
-}
-
-static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf,
-					 bool raw)
-{
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand_controller *nc;
-	struct mtd_oob_region oobregion;
-	int ret, i, max_bitflips = 0;
-	void *databuf, *eccbuf;
-
-	nc = to_nand_controller(chip->controller);
-
-	if (raw)
-		return 0;
-
-	ret = atmel_pmecc_wait_rdy(nand->pmecc);
-	if (ret) {
-		dev_err(nc->dev,
-			"Failed to read NAND page data (err = %d)\n",
-			ret);
-		return ret;
-	}
-
-	mtd_ooblayout_ecc(mtd, 0, &oobregion);
-	eccbuf = chip->oob_poi + oobregion.offset;
-	databuf = buf;
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		ret = atmel_pmecc_correct_sector(nand->pmecc, i, databuf,
-						 eccbuf);
-		if (ret < 0 && !atmel_pmecc_correct_erased_chunks(nand->pmecc))
-			ret = nand_check_erased_ecc_chunk(databuf,
-							  chip->ecc.size,
-							  eccbuf,
-							  chip->ecc.bytes,
-							  NULL, 0,
-							  chip->ecc.strength);
-
-		if (ret >= 0)
-			max_bitflips = max(ret, max_bitflips);
-		else
-			mtd->ecc_stats.failed++;
-
-		databuf += chip->ecc.size;
-		eccbuf += chip->ecc.bytes;
-	}
-
-	return max_bitflips;
-}
-
-static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
-				     bool oob_required, int page, bool raw)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	int ret;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
-	if (ret)
-		return ret;
-
-	atmel_nand_write_buf(mtd, buf, mtd->writesize);
-
-	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
-	if (ret) {
-		atmel_pmecc_disable(nand->pmecc);
-		return ret;
-	}
-
-	atmel_nand_pmecc_disable(chip, raw);
-
-	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
-				       struct nand_chip *chip, const u8 *buf,
-				       int oob_required, int page)
-{
-	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
-}
-
-static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
-					   struct nand_chip *chip,
-					   const u8 *buf, int oob_required,
-					   int page)
-{
-	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, true);
-}
-
-static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
-				    bool oob_required, int page, bool raw)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
-	if (ret)
-		return ret;
-
-	atmel_nand_read_buf(mtd, buf, mtd->writesize);
-	atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
-
-	atmel_nand_pmecc_disable(chip, raw);
-
-	return ret;
-}
-
-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
-				      struct nand_chip *chip, u8 *buf,
-				      int oob_required, int page)
-{
-	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
-}
-
-static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
-					  struct nand_chip *chip, u8 *buf,
-					  int oob_required, int page)
-{
-	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
-}
-
-static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
-					  const u8 *buf, bool oob_required,
-					  int page, bool raw)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_hsmc_nand_controller *nc;
-	int ret, status;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	atmel_nfc_copy_to_sram(chip, buf, false);
-
-	nc->op.cmds[0] = NAND_CMD_SEQIN;
-	nc->op.ncmds = 1;
-	atmel_nfc_set_op_addr(chip, page, 0x0);
-	nc->op.cs = nand->activecs->id;
-	nc->op.data = ATMEL_NFC_WRITE_DATA;
-
-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
-	if (ret)
-		return ret;
-
-	ret = atmel_nfc_exec_op(nc, false);
-	if (ret) {
-		atmel_nand_pmecc_disable(chip, raw);
-		dev_err(nc->base.dev,
-			"Failed to transfer NAND page data (err = %d)\n",
-			ret);
-		return ret;
-	}
-
-	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
-
-	atmel_nand_pmecc_disable(chip, raw);
-
-	if (ret)
-		return ret;
-
-	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	nc->op.cmds[0] = NAND_CMD_PAGEPROG;
-	nc->op.ncmds = 1;
-	nc->op.cs = nand->activecs->id;
-	ret = atmel_nfc_exec_op(nc, false);
-	if (ret)
-		dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
-			ret);
-
-	status = chip->waitfunc(mtd, chip);
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
-
-	return ret;
-}
-
-static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
-					    struct nand_chip *chip,
-					    const u8 *buf, int oob_required,
-					    int page)
-{
-	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
-					      false);
-}
-
-static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
-						struct nand_chip *chip,
-						const u8 *buf,
-						int oob_required, int page)
-{
-	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
-					      true);
-}
-
-static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
-					 bool oob_required, int page,
-					 bool raw)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_hsmc_nand_controller *nc;
-	int ret;
-
-	nc = to_hsmc_nand_controller(chip->controller);
-
-	/*
-	 * Optimized read page accessors only work when the NAND R/B pin is
-	 * connected to a native SoC R/B pin. If that's not the case, fallback
-	 * to the non-optimized one.
-	 */
-	if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
-		nand_read_page_op(chip, page, 0, NULL, 0);
-
-		return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
-						raw);
-	}
-
-	nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0;
-
-	if (mtd->writesize > 512)
-		nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READSTART;
-
-	atmel_nfc_set_op_addr(chip, page, 0x0);
-	nc->op.cs = nand->activecs->id;
-	nc->op.data = ATMEL_NFC_READ_DATA;
-
-	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
-	if (ret)
-		return ret;
-
-	ret = atmel_nfc_exec_op(nc, false);
-	if (ret) {
-		atmel_nand_pmecc_disable(chip, raw);
-		dev_err(nc->base.dev,
-			"Failed to load NAND page data (err = %d)\n",
-			ret);
-		return ret;
-	}
-
-	atmel_nfc_copy_from_sram(chip, buf, true);
-
-	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
-
-	atmel_nand_pmecc_disable(chip, raw);
-
-	return ret;
-}
-
-static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
-					   struct nand_chip *chip, u8 *buf,
-					   int oob_required, int page)
-{
-	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
-					     false);
-}
-
-static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
-					       struct nand_chip *chip,
-					       u8 *buf, int oob_required,
-					       int page)
-{
-	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
-					     true);
-}
-
-static int atmel_nand_pmecc_init(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_nand_controller *nc;
-	struct atmel_pmecc_user_req req;
-
-	nc = to_nand_controller(chip->controller);
-
-	if (!nc->pmecc) {
-		dev_err(nc->dev, "HW ECC not supported\n");
-		return -ENOTSUPP;
-	}
-
-	if (nc->caps->legacy_of_bindings) {
-		u32 val;
-
-		if (!of_property_read_u32(nc->dev->of_node, "atmel,pmecc-cap",
-					  &val))
-			chip->ecc.strength = val;
-
-		if (!of_property_read_u32(nc->dev->of_node,
-					  "atmel,pmecc-sector-size",
-					  &val))
-			chip->ecc.size = val;
-	}
-
-	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
-		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
-	else if (chip->ecc.strength)
-		req.ecc.strength = chip->ecc.strength;
-	else if (chip->ecc_strength_ds)
-		req.ecc.strength = chip->ecc_strength_ds;
-	else
-		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
-
-	if (chip->ecc.size)
-		req.ecc.sectorsize = chip->ecc.size;
-	else if (chip->ecc_step_ds)
-		req.ecc.sectorsize = chip->ecc_step_ds;
-	else
-		req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
-
-	req.pagesize = mtd->writesize;
-	req.oobsize = mtd->oobsize;
-
-	if (mtd->writesize <= 512) {
-		req.ecc.bytes = 4;
-		req.ecc.ooboffset = 0;
-	} else {
-		req.ecc.bytes = mtd->oobsize - 2;
-		req.ecc.ooboffset = ATMEL_PMECC_OOBOFFSET_AUTO;
-	}
-
-	nand->pmecc = atmel_pmecc_create_user(nc->pmecc, &req);
-	if (IS_ERR(nand->pmecc))
-		return PTR_ERR(nand->pmecc);
-
-	chip->ecc.algo = NAND_ECC_BCH;
-	chip->ecc.size = req.ecc.sectorsize;
-	chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors;
-	chip->ecc.strength = req.ecc.strength;
-
-	chip->options |= NAND_NO_SUBPAGE_WRITE;
-
-	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-
-	return 0;
-}
-
-static int atmel_nand_ecc_init(struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	struct atmel_nand_controller *nc;
-	int ret;
-
-	nc = to_nand_controller(chip->controller);
-
-	switch (chip->ecc.mode) {
-	case NAND_ECC_NONE:
-	case NAND_ECC_SOFT:
-		/*
-		 * Nothing to do, the core will initialize everything for us.
-		 */
-		break;
-
-	case NAND_ECC_HW:
-		ret = atmel_nand_pmecc_init(chip);
-		if (ret)
-			return ret;
-
-		chip->ecc.read_page = atmel_nand_pmecc_read_page;
-		chip->ecc.write_page = atmel_nand_pmecc_write_page;
-		chip->ecc.read_page_raw = atmel_nand_pmecc_read_page_raw;
-		chip->ecc.write_page_raw = atmel_nand_pmecc_write_page_raw;
-		break;
-
-	default:
-		/* Other modes are not supported. */
-		dev_err(nc->dev, "Unsupported ECC mode: %d\n",
-			chip->ecc.mode);
-		return -ENOTSUPP;
-	}
-
-	return 0;
-}
-
-static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	int ret;
-
-	ret = atmel_nand_ecc_init(nand);
-	if (ret)
-		return ret;
-
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return 0;
-
-	/* Adjust the ECC operations for the HSMC IP. */
-	chip->ecc.read_page = atmel_hsmc_nand_pmecc_read_page;
-	chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page;
-	chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw;
-	chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw;
-
-	return 0;
-}
-
-static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
-					const struct nand_data_interface *conf,
-					struct atmel_smc_cs_conf *smcconf)
-{
-	u32 ncycles, totalcycles, timeps, mckperiodps;
-	struct atmel_nand_controller *nc;
-	int ret;
-
-	nc = to_nand_controller(nand->base.controller);
-
-	/* DDR interface not supported. */
-	if (conf->type != NAND_SDR_IFACE)
-		return -ENOTSUPP;
-
-	/*
-	 * tRC < 30ns implies EDO mode. This controller does not support this
-	 * mode.
-	 */
-	if (conf->timings.sdr.tRC_min < 30000)
-		return -ENOTSUPP;
-
-	atmel_smc_cs_conf_init(smcconf);
-
-	mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
-	mckperiodps *= 1000;
-
-	/*
-	 * Set write pulse timing. This one is easy to extract:
-	 *
-	 * NWE_PULSE = tWP
-	 */
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
-	totalcycles = ncycles;
-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/*
-	 * The write setup timing depends on the operation done on the NAND.
-	 * All operations goes through the same data bus, but the operation
-	 * type depends on the address we are writing to (ALE/CLE address
-	 * lines).
-	 * Since we have no way to differentiate the different operations at
-	 * the SMC level, we must consider the worst case (the biggest setup
-	 * time among all operation types):
-	 *
-	 * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
-	 */
-	timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
-		      conf->timings.sdr.tALS_min);
-	timeps = max(timeps, conf->timings.sdr.tDS_min);
-	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
-	ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
-	totalcycles += ncycles;
-	ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/*
-	 * As for the write setup timing, the write hold timing depends on the
-	 * operation done on the NAND:
-	 *
-	 * NWE_HOLD = max(tCLH, tCH, tALH, tDH, tWH)
-	 */
-	timeps = max3(conf->timings.sdr.tCLH_min, conf->timings.sdr.tCH_min,
-		      conf->timings.sdr.tALH_min);
-	timeps = max3(timeps, conf->timings.sdr.tDH_min,
-		      conf->timings.sdr.tWH_min);
-	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
-	totalcycles += ncycles;
-
-	/*
-	 * The write cycle timing is directly matching tWC, but is also
-	 * dependent on the other timings on the setup and hold timings we
-	 * calculated earlier, which gives:
-	 *
-	 * NWE_CYCLE = max(tWC, NWE_SETUP + NWE_PULSE + NWE_HOLD)
-	 */
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWC_min, mckperiodps);
-	ncycles = max(totalcycles, ncycles);
-	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NWE_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/*
-	 * We don't want the CS line to be toggled between each byte/word
-	 * transfer to the NAND. The only way to guarantee that is to have the
-	 * NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
-	 *
-	 * NCS_WR_PULSE = NWE_CYCLE
-	 */
-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_WR_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/*
-	 * As for the write setup timing, the read hold timing depends on the
-	 * operation done on the NAND:
-	 *
-	 * NRD_HOLD = max(tREH, tRHOH)
-	 */
-	timeps = max(conf->timings.sdr.tREH_min, conf->timings.sdr.tRHOH_min);
-	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
-	totalcycles = ncycles;
-
-	/*
-	 * TDF = tRHZ - NRD_HOLD
-	 */
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRHZ_max, mckperiodps);
-	ncycles -= totalcycles;
-
-	/*
-	 * In ONFI 4.0 specs, tRHZ has been increased to support EDO NANDs and
-	 * we might end up with a config that does not fit in the TDF field.
-	 * Just take the max value in this case and hope that the NAND is more
-	 * tolerant than advertised.
-	 */
-	if (ncycles > ATMEL_SMC_MODE_TDF_MAX)
-		ncycles = ATMEL_SMC_MODE_TDF_MAX;
-	else if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
-		ncycles = ATMEL_SMC_MODE_TDF_MIN;
-
-	smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles) |
-			 ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
-
-	/*
-	 * Read pulse timing directly matches tRP:
-	 *
-	 * NRD_PULSE = tRP
-	 */
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
-	totalcycles += ncycles;
-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/*
-	 * The write cycle timing is directly matching tWC, but is also
-	 * dependent on the setup and hold timings we calculated earlier,
-	 * which gives:
-	 *
-	 * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
-	 *
-	 * NRD_SETUP is always 0.
-	 */
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
-	ncycles = max(totalcycles, ncycles);
-	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NRD_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/*
-	 * We don't want the CS line to be toggled between each byte/word
-	 * transfer from the NAND. The only way to guarantee that is to have
-	 * the NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
-	 *
-	 * NCS_RD_PULSE = NRD_CYCLE
-	 */
-	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_RD_SHIFT,
-					  ncycles);
-	if (ret)
-		return ret;
-
-	/* Txxx timings are directly matching tXXX ones. */
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tCLR_min, mckperiodps);
-	ret = atmel_smc_cs_conf_set_timing(smcconf,
-					   ATMEL_HSMC_TIMINGS_TCLR_SHIFT,
-					   ncycles);
-	if (ret)
-		return ret;
-
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tADL_min, mckperiodps);
-	ret = atmel_smc_cs_conf_set_timing(smcconf,
-					   ATMEL_HSMC_TIMINGS_TADL_SHIFT,
-					   ncycles);
-	/*
-	 * Version 4 of the ONFI spec mandates that tADL be at least 400
-	 * nanoseconds, but, depending on the master clock rate, 400 ns may not
-	 * fit in the tADL field of the SMC reg. We need to relax the check and
-	 * accept the -ERANGE return code.
-	 *
-	 * Note that previous versions of the ONFI spec had a lower tADL_min
-	 * (100 or 200 ns). It's not clear why this timing constraint got
-	 * increased but it seems most NANDs are fine with values lower than
-	 * 400ns, so we should be safe.
-	 */
-	if (ret && ret != -ERANGE)
-		return ret;
-
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tAR_min, mckperiodps);
-	ret = atmel_smc_cs_conf_set_timing(smcconf,
-					   ATMEL_HSMC_TIMINGS_TAR_SHIFT,
-					   ncycles);
-	if (ret)
-		return ret;
-
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRR_min, mckperiodps);
-	ret = atmel_smc_cs_conf_set_timing(smcconf,
-					   ATMEL_HSMC_TIMINGS_TRR_SHIFT,
-					   ncycles);
-	if (ret)
-		return ret;
-
-	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWB_max, mckperiodps);
-	ret = atmel_smc_cs_conf_set_timing(smcconf,
-					   ATMEL_HSMC_TIMINGS_TWB_SHIFT,
-					   ncycles);
-	if (ret)
-		return ret;
-
-	/* Attach the CS line to the NFC logic. */
-	smcconf->timings |= ATMEL_HSMC_TIMINGS_NFSEL;
-
-	/* Set the appropriate data bus width. */
-	if (nand->base.options & NAND_BUSWIDTH_16)
-		smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
-
-	/* Operate in NRD/NWE READ/WRITEMODE. */
-	smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD |
-			 ATMEL_SMC_MODE_WRITEMODE_NWE;
-
-	return 0;
-}
-
-static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
-					int csline,
-					const struct nand_data_interface *conf)
-{
-	struct atmel_nand_controller *nc;
-	struct atmel_smc_cs_conf smcconf;
-	struct atmel_nand_cs *cs;
-	int ret;
-
-	nc = to_nand_controller(nand->base.controller);
-
-	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
-	if (ret)
-		return ret;
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	cs = &nand->cs[csline];
-	cs->smcconf = smcconf;
-	atmel_smc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
-
-	return 0;
-}
-
-static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
-					int csline,
-					const struct nand_data_interface *conf)
-{
-	struct atmel_hsmc_nand_controller *nc;
-	struct atmel_smc_cs_conf smcconf;
-	struct atmel_nand_cs *cs;
-	int ret;
-
-	nc = to_hsmc_nand_controller(nand->base.controller);
-
-	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
-	if (ret)
-		return ret;
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	cs = &nand->cs[csline];
-	cs->smcconf = smcconf;
-
-	if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
-		cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
-
-	atmel_hsmc_cs_conf_apply(nc->base.smc, nc->hsmc_layout, cs->id,
-				 &cs->smcconf);
-
-	return 0;
-}
-
-static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
-					const struct nand_data_interface *conf)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct atmel_nand *nand = to_atmel_nand(chip);
-	struct atmel_nand_controller *nc;
-
-	nc = to_nand_controller(nand->base.controller);
-
-	if (csline >= nand->numcs ||
-	    (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
-		return -EINVAL;
-
-	return nc->caps->ops->setup_data_interface(nand, csline, conf);
-}
-
-static void atmel_nand_init(struct atmel_nand_controller *nc,
-			    struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	mtd->dev.parent = nc->dev;
-	nand->base.controller = &nc->base;
-
-	chip->cmd_ctrl = atmel_nand_cmd_ctrl;
-	chip->read_byte = atmel_nand_read_byte;
-	chip->read_word = atmel_nand_read_word;
-	chip->write_byte = atmel_nand_write_byte;
-	chip->read_buf = atmel_nand_read_buf;
-	chip->write_buf = atmel_nand_write_buf;
-	chip->select_chip = atmel_nand_select_chip;
-
-	if (nc->mck && nc->caps->ops->setup_data_interface)
-		chip->setup_data_interface = atmel_nand_setup_data_interface;
-
-	/* Some NANDs require a longer delay than the default one (20us). */
-	chip->chip_delay = 40;
-
-	/*
-	 * Use a bounce buffer when the buffer passed by the MTD user is not
-	 * suitable for DMA.
-	 */
-	if (nc->dmac)
-		chip->options |= NAND_USE_BOUNCE_BUFFER;
-
-	/* Default to HW ECC if pmecc is available. */
-	if (nc->pmecc)
-		chip->ecc.mode = NAND_ECC_HW;
-}
-
-static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
-				struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	struct atmel_smc_nand_controller *smc_nc;
-	int i;
-
-	atmel_nand_init(nc, nand);
-
-	smc_nc = to_smc_nand_controller(chip->controller);
-	if (!smc_nc->matrix)
-		return;
-
-	/* Attach the CS to the NAND Flash logic. */
-	for (i = 0; i < nand->numcs; i++)
-		regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs,
-				   BIT(nand->cs[i].id), BIT(nand->cs[i].id));
-}
-
-static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
-				 struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-
-	atmel_nand_init(nc, nand);
-
-	/* Overload some methods for the HSMC controller. */
-	chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
-	chip->select_chip = atmel_hsmc_nand_select_chip;
-}
-
-static int atmel_nand_detect(struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand_controller *nc;
-	int ret;
-
-	nc = to_nand_controller(chip->controller);
-
-	ret = nand_scan_ident(mtd, nand->numcs, NULL);
-	if (ret)
-		dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
-
-	return ret;
-}
-
-static int atmel_nand_unregister(struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-
-	ret = mtd_device_unregister(mtd);
-	if (ret)
-		return ret;
-
-	nand_cleanup(chip);
-	list_del(&nand->node);
-
-	return 0;
-}
-
-static int atmel_nand_register(struct atmel_nand *nand)
-{
-	struct nand_chip *chip = &nand->base;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct atmel_nand_controller *nc;
-	int ret;
-
-	nc = to_nand_controller(chip->controller);
-
-	if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
-		/*
-		 * We keep the MTD name unchanged to avoid breaking platforms
-		 * where the MTD cmdline parser is used and the bootloader
-		 * has not been updated to use the new naming scheme.
-		 */
-		mtd->name = "atmel_nand";
-	} else if (!mtd->name) {
-		/*
-		 * If the new bindings are used and the bootloader has not been
-		 * updated to pass a new mtdparts parameter on the cmdline, you
-		 * should define the following property in your nand node:
-		 *
-		 *	label = "atmel_nand";
-		 *
-		 * This way, mtd->name will be set by the core when
-		 * nand_set_flash_node() is called.
-		 */
-		mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
-					   "%s:nand.%d", dev_name(nc->dev),
-					   nand->cs[0].id);
-		if (!mtd->name) {
-			dev_err(nc->dev, "Failed to allocate mtd->name\n");
-			return -ENOMEM;
-		}
-	}
-
-	ret = nand_scan_tail(mtd);
-	if (ret) {
-		dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret) {
-		dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
-		nand_cleanup(chip);
-		return ret;
-	}
-
-	list_add_tail(&nand->node, &nc->chips);
-
-	return 0;
-}
-
-static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
-					    struct device_node *np,
-					    int reg_cells)
-{
-	struct atmel_nand *nand;
-	struct gpio_desc *gpio;
-	int numcs, ret, i;
-
-	numcs = of_property_count_elems_of_size(np, "reg",
-						reg_cells * sizeof(u32));
-	if (numcs < 1) {
-		dev_err(nc->dev, "Missing or invalid reg property\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	nand = devm_kzalloc(nc->dev,
-			    sizeof(*nand) + (numcs * sizeof(*nand->cs)),
-			    GFP_KERNEL);
-	if (!nand) {
-		dev_err(nc->dev, "Failed to allocate NAND object\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	nand->numcs = numcs;
-
-	gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0,
-						      &np->fwnode, GPIOD_IN,
-						      "nand-det");
-	if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
-		dev_err(nc->dev,
-			"Failed to get detect gpio (err = %ld)\n",
-			PTR_ERR(gpio));
-		return ERR_CAST(gpio);
-	}
-
-	if (!IS_ERR(gpio))
-		nand->cdgpio = gpio;
-
-	for (i = 0; i < numcs; i++) {
-		struct resource res;
-		u32 val;
-
-		ret = of_address_to_resource(np, 0, &res);
-		if (ret) {
-			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
-				ret);
-			return ERR_PTR(ret);
-		}
-
-		ret = of_property_read_u32_index(np, "reg", i * reg_cells,
-						 &val);
-		if (ret) {
-			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
-				ret);
-			return ERR_PTR(ret);
-		}
-
-		nand->cs[i].id = val;
-
-		nand->cs[i].io.dma = res.start;
-		nand->cs[i].io.virt = devm_ioremap_resource(nc->dev, &res);
-		if (IS_ERR(nand->cs[i].io.virt))
-			return ERR_CAST(nand->cs[i].io.virt);
-
-		if (!of_property_read_u32(np, "atmel,rb", &val)) {
-			if (val > ATMEL_NFC_MAX_RB_ID)
-				return ERR_PTR(-EINVAL);
-
-			nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB;
-			nand->cs[i].rb.id = val;
-		} else {
-			gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev,
-							"rb", i, &np->fwnode,
-							GPIOD_IN, "nand-rb");
-			if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
-				dev_err(nc->dev,
-					"Failed to get R/B gpio (err = %ld)\n",
-					PTR_ERR(gpio));
-				return ERR_CAST(gpio);
-			}
-
-			if (!IS_ERR(gpio)) {
-				nand->cs[i].rb.type = ATMEL_NAND_GPIO_RB;
-				nand->cs[i].rb.gpio = gpio;
-			}
-		}
-
-		gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs",
-							      i, &np->fwnode,
-							      GPIOD_OUT_HIGH,
-							      "nand-cs");
-		if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
-			dev_err(nc->dev,
-				"Failed to get CS gpio (err = %ld)\n",
-				PTR_ERR(gpio));
-			return ERR_CAST(gpio);
-		}
-
-		if (!IS_ERR(gpio))
-			nand->cs[i].csgpio = gpio;
-	}
-
-	nand_set_flash_node(&nand->base, np);
-
-	return nand;
-}
-
-static int
-atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
-			       struct atmel_nand *nand)
-{
-	int ret;
-
-	/* No card inserted, skip this NAND. */
-	if (nand->cdgpio && gpiod_get_value(nand->cdgpio)) {
-		dev_info(nc->dev, "No SmartMedia card inserted.\n");
-		return 0;
-	}
-
-	nc->caps->ops->nand_init(nc, nand);
-
-	ret = atmel_nand_detect(nand);
-	if (ret)
-		return ret;
-
-	ret = nc->caps->ops->ecc_init(nand);
-	if (ret)
-		return ret;
-
-	return atmel_nand_register(nand);
-}
-
-static int
-atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
-{
-	struct atmel_nand *nand, *tmp;
-	int ret;
-
-	list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
-		ret = atmel_nand_unregister(nand);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int
-atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc)
-{
-	struct device *dev = nc->dev;
-	struct platform_device *pdev = to_platform_device(dev);
-	struct atmel_nand *nand;
-	struct gpio_desc *gpio;
-	struct resource *res;
-
-	/*
-	 * Legacy bindings only allow connecting a single NAND with a unique CS
-	 * line to the controller.
-	 */
-	nand = devm_kzalloc(nc->dev, sizeof(*nand) + sizeof(*nand->cs),
-			    GFP_KERNEL);
-	if (!nand)
-		return -ENOMEM;
-
-	nand->numcs = 1;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nand->cs[0].io.virt = devm_ioremap_resource(dev, res);
-	if (IS_ERR(nand->cs[0].io.virt))
-		return PTR_ERR(nand->cs[0].io.virt);
-
-	nand->cs[0].io.dma = res->start;
-
-	/*
-	 * The old driver was hardcoding the CS id to 3 for all sama5
-	 * controllers. Since this id is only meaningful for the sama5
-	 * controller we can safely assign this id to 3 no matter the
-	 * controller.
-	 * If one wants to connect a NAND to a different CS line, he will
-	 * have to use the new bindings.
-	 */
-	nand->cs[0].id = 3;
-
-	/* R/B GPIO. */
-	gpio = devm_gpiod_get_index_optional(dev, NULL, 0,  GPIOD_IN);
-	if (IS_ERR(gpio)) {
-		dev_err(dev, "Failed to get R/B gpio (err = %ld)\n",
-			PTR_ERR(gpio));
-		return PTR_ERR(gpio);
-	}
-
-	if (gpio) {
-		nand->cs[0].rb.type = ATMEL_NAND_GPIO_RB;
-		nand->cs[0].rb.gpio = gpio;
-	}
-
-	/* CS GPIO. */
-	gpio = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_HIGH);
-	if (IS_ERR(gpio)) {
-		dev_err(dev, "Failed to get CS gpio (err = %ld)\n",
-			PTR_ERR(gpio));
-		return PTR_ERR(gpio);
-	}
-
-	nand->cs[0].csgpio = gpio;
-
-	/* Card detect GPIO. */
-	gpio = devm_gpiod_get_index_optional(nc->dev, NULL, 2, GPIOD_IN);
-	if (IS_ERR(gpio)) {
-		dev_err(dev,
-			"Failed to get detect gpio (err = %ld)\n",
-			PTR_ERR(gpio));
-		return PTR_ERR(gpio);
-	}
-
-	nand->cdgpio = gpio;
-
-	nand_set_flash_node(&nand->base, nc->dev->of_node);
-
-	return atmel_nand_controller_add_nand(nc, nand);
-}
-
-static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc)
-{
-	struct device_node *np, *nand_np;
-	struct device *dev = nc->dev;
-	int ret, reg_cells;
-	u32 val;
-
-	/* We do not retrieve the SMC syscon when parsing old DTs. */
-	if (nc->caps->legacy_of_bindings)
-		return atmel_nand_controller_legacy_add_nands(nc);
-
-	np = dev->of_node;
-
-	ret = of_property_read_u32(np, "#address-cells", &val);
-	if (ret) {
-		dev_err(dev, "missing #address-cells property\n");
-		return ret;
-	}
-
-	reg_cells = val;
-
-	ret = of_property_read_u32(np, "#size-cells", &val);
-	if (ret) {
-		dev_err(dev, "missing #address-cells property\n");
-		return ret;
-	}
-
-	reg_cells += val;
-
-	for_each_child_of_node(np, nand_np) {
-		struct atmel_nand *nand;
-
-		nand = atmel_nand_create(nc, nand_np, reg_cells);
-		if (IS_ERR(nand)) {
-			ret = PTR_ERR(nand);
-			goto err;
-		}
-
-		ret = atmel_nand_controller_add_nand(nc, nand);
-		if (ret)
-			goto err;
-	}
-
-	return 0;
-
-err:
-	atmel_nand_controller_remove_nands(nc);
-
-	return ret;
-}
-
-static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc)
-{
-	if (nc->dmac)
-		dma_release_channel(nc->dmac);
-
-	clk_put(nc->mck);
-}
-
-static const struct of_device_id atmel_matrix_of_ids[] = {
-	{
-		.compatible = "atmel,at91sam9260-matrix",
-		.data = (void *)AT91SAM9260_MATRIX_EBICSA,
-	},
-	{
-		.compatible = "atmel,at91sam9261-matrix",
-		.data = (void *)AT91SAM9261_MATRIX_EBICSA,
-	},
-	{
-		.compatible = "atmel,at91sam9263-matrix",
-		.data = (void *)AT91SAM9263_MATRIX_EBI0CSA,
-	},
-	{
-		.compatible = "atmel,at91sam9rl-matrix",
-		.data = (void *)AT91SAM9RL_MATRIX_EBICSA,
-	},
-	{
-		.compatible = "atmel,at91sam9g45-matrix",
-		.data = (void *)AT91SAM9G45_MATRIX_EBICSA,
-	},
-	{
-		.compatible = "atmel,at91sam9n12-matrix",
-		.data = (void *)AT91SAM9N12_MATRIX_EBICSA,
-	},
-	{
-		.compatible = "atmel,at91sam9x5-matrix",
-		.data = (void *)AT91SAM9X5_MATRIX_EBICSA,
-	},
-	{ /* sentinel */ },
-};
-
-static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
-				struct platform_device *pdev,
-				const struct atmel_nand_controller_caps *caps)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	int ret;
-
-	nand_hw_control_init(&nc->base);
-	INIT_LIST_HEAD(&nc->chips);
-	nc->dev = dev;
-	nc->caps = caps;
-
-	platform_set_drvdata(pdev, nc);
-
-	nc->pmecc = devm_atmel_pmecc_get(dev);
-	if (IS_ERR(nc->pmecc)) {
-		ret = PTR_ERR(nc->pmecc);
-		if (ret != -EPROBE_DEFER)
-			dev_err(dev, "Could not get PMECC object (err = %d)\n",
-				ret);
-		return ret;
-	}
-
-	if (nc->caps->has_dma) {
-		dma_cap_mask_t mask;
-
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_MEMCPY, mask);
-
-		nc->dmac = dma_request_channel(mask, NULL, NULL);
-		if (!nc->dmac)
-			dev_err(nc->dev, "Failed to request DMA channel\n");
-	}
-
-	/* We do not retrieve the SMC syscon when parsing old DTs. */
-	if (nc->caps->legacy_of_bindings)
-		return 0;
-
-	nc->mck = of_clk_get(dev->parent->of_node, 0);
-	if (IS_ERR(nc->mck)) {
-		dev_err(dev, "Failed to retrieve MCK clk\n");
-		return PTR_ERR(nc->mck);
-	}
-
-	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
-	if (!np) {
-		dev_err(dev, "Missing or invalid atmel,smc property\n");
-		return -EINVAL;
-	}
-
-	nc->smc = syscon_node_to_regmap(np);
-	of_node_put(np);
-	if (IS_ERR(nc->smc)) {
-		ret = PTR_ERR(nc->smc);
-		dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int
-atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
-{
-	struct device *dev = nc->base.dev;
-	const struct of_device_id *match;
-	struct device_node *np;
-	int ret;
-
-	/* We do not retrieve the matrix syscon when parsing old DTs. */
-	if (nc->base.caps->legacy_of_bindings)
-		return 0;
-
-	np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0);
-	if (!np)
-		return 0;
-
-	match = of_match_node(atmel_matrix_of_ids, np);
-	if (!match) {
-		of_node_put(np);
-		return 0;
-	}
-
-	nc->matrix = syscon_node_to_regmap(np);
-	of_node_put(np);
-	if (IS_ERR(nc->matrix)) {
-		ret = PTR_ERR(nc->matrix);
-		dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret);
-		return ret;
-	}
-
-	nc->ebi_csa_offs = (unsigned int)match->data;
-
-	/*
-	 * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
-	 * add 4 to ->ebi_csa_offs.
-	 */
-	if (of_device_is_compatible(dev->parent->of_node,
-				    "atmel,at91sam9263-ebi1"))
-		nc->ebi_csa_offs += 4;
-
-	return 0;
-}
-
-static int
-atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
-{
-	struct regmap_config regmap_conf = {
-		.reg_bits = 32,
-		.val_bits = 32,
-		.reg_stride = 4,
-	};
-
-	struct device *dev = nc->base.dev;
-	struct device_node *nand_np, *nfc_np;
-	void __iomem *iomem;
-	struct resource res;
-	int ret;
-
-	nand_np = dev->of_node;
-	nfc_np = of_find_compatible_node(dev->of_node, NULL,
-					 "atmel,sama5d3-nfc");
-
-	nc->clk = of_clk_get(nfc_np, 0);
-	if (IS_ERR(nc->clk)) {
-		ret = PTR_ERR(nc->clk);
-		dev_err(dev, "Failed to retrieve HSMC clock (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	ret = clk_prepare_enable(nc->clk);
-	if (ret) {
-		dev_err(dev, "Failed to enable the HSMC clock (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	nc->irq = of_irq_get(nand_np, 0);
-	if (nc->irq <= 0) {
-		ret = nc->irq ?: -ENXIO;
-		if (ret != -EPROBE_DEFER)
-			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
-				ret);
-		goto out;
-	}
-
-	ret = of_address_to_resource(nfc_np, 0, &res);
-	if (ret) {
-		dev_err(dev, "Invalid or missing NFC IO resource (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	iomem = devm_ioremap_resource(dev, &res);
-	if (IS_ERR(iomem)) {
-		ret = PTR_ERR(iomem);
-		goto out;
-	}
-
-	regmap_conf.name = "nfc-io";
-	regmap_conf.max_register = resource_size(&res) - 4;
-	nc->io = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
-	if (IS_ERR(nc->io)) {
-		ret = PTR_ERR(nc->io);
-		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	ret = of_address_to_resource(nfc_np, 1, &res);
-	if (ret) {
-		dev_err(dev, "Invalid or missing HSMC resource (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	iomem = devm_ioremap_resource(dev, &res);
-	if (IS_ERR(iomem)) {
-		ret = PTR_ERR(iomem);
-		goto out;
-	}
-
-	regmap_conf.name = "smc";
-	regmap_conf.max_register = resource_size(&res) - 4;
-	nc->base.smc = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
-	if (IS_ERR(nc->base.smc)) {
-		ret = PTR_ERR(nc->base.smc);
-		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	ret = of_address_to_resource(nfc_np, 2, &res);
-	if (ret) {
-		dev_err(dev, "Invalid or missing SRAM resource (err = %d)\n",
-			ret);
-		goto out;
-	}
-
-	nc->sram.virt = devm_ioremap_resource(dev, &res);
-	if (IS_ERR(nc->sram.virt)) {
-		ret = PTR_ERR(nc->sram.virt);
-		goto out;
-	}
-
-	nc->sram.dma = res.start;
-
-out:
-	of_node_put(nfc_np);
-
-	return ret;
-}
-
-static int
-atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
-{
-	struct device *dev = nc->base.dev;
-	struct device_node *np;
-	int ret;
-
-	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
-	if (!np) {
-		dev_err(dev, "Missing or invalid atmel,smc property\n");
-		return -EINVAL;
-	}
-
-	nc->hsmc_layout = atmel_hsmc_get_reg_layout(np);
-
-	nc->irq = of_irq_get(np, 0);
-	of_node_put(np);
-	if (nc->irq <= 0) {
-		ret = nc->irq ?: -ENXIO;
-		if (ret != -EPROBE_DEFER)
-			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
-				ret);
-		return ret;
-	}
-
-	np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0);
-	if (!np) {
-		dev_err(dev, "Missing or invalid atmel,nfc-io property\n");
-		return -EINVAL;
-	}
-
-	nc->io = syscon_node_to_regmap(np);
-	of_node_put(np);
-	if (IS_ERR(nc->io)) {
-		ret = PTR_ERR(nc->io);
-		dev_err(dev, "Could not get NFC IO regmap (err = %d)\n", ret);
-		return ret;
-	}
-
-	nc->sram.pool = of_gen_pool_get(nc->base.dev->of_node,
-					 "atmel,nfc-sram", 0);
-	if (!nc->sram.pool) {
-		dev_err(nc->base.dev, "Missing SRAM\n");
-		return -ENOMEM;
-	}
-
-	nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
-					    ATMEL_NFC_SRAM_SIZE,
-					    &nc->sram.dma);
-	if (!nc->sram.virt) {
-		dev_err(nc->base.dev,
-			"Could not allocate memory from the NFC SRAM pool\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static int
-atmel_hsmc_nand_controller_remove(struct atmel_nand_controller *nc)
-{
-	struct atmel_hsmc_nand_controller *hsmc_nc;
-	int ret;
-
-	ret = atmel_nand_controller_remove_nands(nc);
-	if (ret)
-		return ret;
-
-	hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base);
-	if (hsmc_nc->sram.pool)
-		gen_pool_free(hsmc_nc->sram.pool,
-			      (unsigned long)hsmc_nc->sram.virt,
-			      ATMEL_NFC_SRAM_SIZE);
-
-	if (hsmc_nc->clk) {
-		clk_disable_unprepare(hsmc_nc->clk);
-		clk_put(hsmc_nc->clk);
-	}
-
-	atmel_nand_controller_cleanup(nc);
-
-	return 0;
-}
-
-static int atmel_hsmc_nand_controller_probe(struct platform_device *pdev,
-				const struct atmel_nand_controller_caps *caps)
-{
-	struct device *dev = &pdev->dev;
-	struct atmel_hsmc_nand_controller *nc;
-	int ret;
-
-	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
-	if (!nc)
-		return -ENOMEM;
-
-	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
-	if (ret)
-		return ret;
-
-	if (caps->legacy_of_bindings)
-		ret = atmel_hsmc_nand_controller_legacy_init(nc);
-	else
-		ret = atmel_hsmc_nand_controller_init(nc);
-
-	if (ret)
-		return ret;
-
-	/* Make sure all irqs are masked before registering our IRQ handler. */
-	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
-	ret = devm_request_irq(dev, nc->irq, atmel_nfc_interrupt,
-			       IRQF_SHARED, "nfc", nc);
-	if (ret) {
-		dev_err(dev,
-			"Could not get register NFC interrupt handler (err = %d)\n",
-			ret);
-		goto err;
-	}
-
-	/* Initial NFC configuration. */
-	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG,
-		     ATMEL_HSMC_NFC_CFG_DTO_MAX);
-
-	ret = atmel_nand_controller_add_nands(&nc->base);
-	if (ret)
-		goto err;
-
-	return 0;
-
-err:
-	atmel_hsmc_nand_controller_remove(&nc->base);
-
-	return ret;
-}
-
-static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
-	.probe = atmel_hsmc_nand_controller_probe,
-	.remove = atmel_hsmc_nand_controller_remove,
-	.ecc_init = atmel_hsmc_nand_ecc_init,
-	.nand_init = atmel_hsmc_nand_init,
-	.setup_data_interface = atmel_hsmc_nand_setup_data_interface,
-};
-
-static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
-	.has_dma = true,
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &atmel_hsmc_nc_ops,
-};
-
-/* Only used to parse old bindings. */
-static const struct atmel_nand_controller_caps atmel_sama5_nand_caps = {
-	.has_dma = true,
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &atmel_hsmc_nc_ops,
-	.legacy_of_bindings = true,
-};
-
-static int atmel_smc_nand_controller_probe(struct platform_device *pdev,
-				const struct atmel_nand_controller_caps *caps)
-{
-	struct device *dev = &pdev->dev;
-	struct atmel_smc_nand_controller *nc;
-	int ret;
-
-	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
-	if (!nc)
-		return -ENOMEM;
-
-	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
-	if (ret)
-		return ret;
-
-	ret = atmel_smc_nand_controller_init(nc);
-	if (ret)
-		return ret;
-
-	return atmel_nand_controller_add_nands(&nc->base);
-}
-
-static int
-atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
-{
-	int ret;
-
-	ret = atmel_nand_controller_remove_nands(nc);
-	if (ret)
-		return ret;
-
-	atmel_nand_controller_cleanup(nc);
-
-	return 0;
-}
-
-/*
- * The SMC reg layout of at91rm9200 is completely different which prevents us
- * from re-using atmel_smc_nand_setup_data_interface() for the
- * ->setup_data_interface() hook.
- * At this point, there's no support for the at91rm9200 SMC IP, so we leave
- * ->setup_data_interface() unassigned.
- */
-static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
-	.probe = atmel_smc_nand_controller_probe,
-	.remove = atmel_smc_nand_controller_remove,
-	.ecc_init = atmel_nand_ecc_init,
-	.nand_init = atmel_smc_nand_init,
-};
-
-static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &at91rm9200_nc_ops,
-};
-
-static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
-	.probe = atmel_smc_nand_controller_probe,
-	.remove = atmel_smc_nand_controller_remove,
-	.ecc_init = atmel_nand_ecc_init,
-	.nand_init = atmel_smc_nand_init,
-	.setup_data_interface = atmel_smc_nand_setup_data_interface,
-};
-
-static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &atmel_smc_nc_ops,
-};
-
-static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = {
-	.ale_offs = BIT(22),
-	.cle_offs = BIT(21),
-	.ops = &atmel_smc_nc_ops,
-};
-
-static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
-	.has_dma = true,
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &atmel_smc_nc_ops,
-};
-
-/* Only used to parse old bindings. */
-static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &atmel_smc_nc_ops,
-	.legacy_of_bindings = true,
-};
-
-static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
-	.ale_offs = BIT(22),
-	.cle_offs = BIT(21),
-	.ops = &atmel_smc_nc_ops,
-	.legacy_of_bindings = true,
-};
-
-static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
-	.has_dma = true,
-	.ale_offs = BIT(21),
-	.cle_offs = BIT(22),
-	.ops = &atmel_smc_nc_ops,
-	.legacy_of_bindings = true,
-};
-
-static const struct of_device_id atmel_nand_controller_of_ids[] = {
-	{
-		.compatible = "atmel,at91rm9200-nand-controller",
-		.data = &atmel_rm9200_nc_caps,
-	},
-	{
-		.compatible = "atmel,at91sam9260-nand-controller",
-		.data = &atmel_sam9260_nc_caps,
-	},
-	{
-		.compatible = "atmel,at91sam9261-nand-controller",
-		.data = &atmel_sam9261_nc_caps,
-	},
-	{
-		.compatible = "atmel,at91sam9g45-nand-controller",
-		.data = &atmel_sam9g45_nc_caps,
-	},
-	{
-		.compatible = "atmel,sama5d3-nand-controller",
-		.data = &atmel_sama5_nc_caps,
-	},
-	/* Support for old/deprecated bindings: */
-	{
-		.compatible = "atmel,at91rm9200-nand",
-		.data = &atmel_rm9200_nand_caps,
-	},
-	{
-		.compatible = "atmel,sama5d4-nand",
-		.data = &atmel_rm9200_nand_caps,
-	},
-	{
-		.compatible = "atmel,sama5d2-nand",
-		.data = &atmel_rm9200_nand_caps,
-	},
-	{ /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, atmel_nand_controller_of_ids);
-
-static int atmel_nand_controller_probe(struct platform_device *pdev)
-{
-	const struct atmel_nand_controller_caps *caps;
-
-	if (pdev->id_entry)
-		caps = (void *)pdev->id_entry->driver_data;
-	else
-		caps = of_device_get_match_data(&pdev->dev);
-
-	if (!caps) {
-		dev_err(&pdev->dev, "Could not retrieve NFC caps\n");
-		return -EINVAL;
-	}
-
-	if (caps->legacy_of_bindings) {
-		u32 ale_offs = 21;
-
-		/*
-		 * If we are parsing legacy DT props and the DT contains a
-		 * valid NFC node, forward the request to the sama5 logic.
-		 */
-		if (of_find_compatible_node(pdev->dev.of_node, NULL,
-					    "atmel,sama5d3-nfc"))
-			caps = &atmel_sama5_nand_caps;
-
-		/*
-		 * Even if the compatible says we are dealing with an
-		 * at91rm9200 controller, the atmel,nand-has-dma specify that
-		 * this controller supports DMA, which means we are in fact
-		 * dealing with an at91sam9g45+ controller.
-		 */
-		if (!caps->has_dma &&
-		    of_property_read_bool(pdev->dev.of_node,
-					  "atmel,nand-has-dma"))
-			caps = &atmel_sam9g45_nand_caps;
-
-		/*
-		 * All SoCs except the at91sam9261 are assigning ALE to A21 and
-		 * CLE to A22. If atmel,nand-addr-offset != 21 this means we're
-		 * actually dealing with an at91sam9261 controller.
-		 */
-		of_property_read_u32(pdev->dev.of_node,
-				     "atmel,nand-addr-offset", &ale_offs);
-		if (ale_offs != 21)
-			caps = &atmel_sam9261_nand_caps;
-	}
-
-	return caps->ops->probe(pdev, caps);
-}
-
-static int atmel_nand_controller_remove(struct platform_device *pdev)
-{
-	struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
-
-	return nc->caps->ops->remove(nc);
-}
-
-static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
-{
-	struct atmel_nand_controller *nc = dev_get_drvdata(dev);
-	struct atmel_nand *nand;
-
-	if (nc->pmecc)
-		atmel_pmecc_reset(nc->pmecc);
-
-	list_for_each_entry(nand, &nc->chips, node) {
-		int i;
-
-		for (i = 0; i < nand->numcs; i++)
-			nand_reset(&nand->base, i);
-	}
-
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(atmel_nand_controller_pm_ops, NULL,
-			 atmel_nand_controller_resume);
-
-static struct platform_driver atmel_nand_controller_driver = {
-	.driver = {
-		.name = "atmel-nand-controller",
-		.of_match_table = of_match_ptr(atmel_nand_controller_of_ids),
-		.pm = &atmel_nand_controller_pm_ops,
-	},
-	.probe = atmel_nand_controller_probe,
-	.remove = atmel_nand_controller_remove,
-};
-module_platform_driver(atmel_nand_controller_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
-MODULE_DESCRIPTION("NAND Flash Controller driver for Atmel SoCs");
-MODULE_ALIAS("platform:atmel-nand-controller");
diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/atmel/pmecc.c
deleted file mode 100644
index fcbe4fd6e684..000000000000
--- a/drivers/mtd/nand/atmel/pmecc.c
+++ /dev/null
@@ -1,1012 +0,0 @@
-/*
- * Copyright 2017 ATMEL
- * Copyright 2017 Free Electrons
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * Derived from the atmel_nand.c driver which contained the following
- * copyrights:
- *
- *   Copyright 2003 Rick Bronson
- *
- *   Derived from drivers/mtd/nand/autcpu12.c
- *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
- *
- *   Derived from drivers/mtd/spia.c
- *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
- *
- *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
- *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
- *
- *   Derived from Das U-Boot source code
- *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
- *      Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
- *
- *   Add Programmable Multibit ECC support for various AT91 SoC
- *	Copyright 2012 ATMEL, Hong Xu
- *
- *   Add Nand Flash Controller support for SAMA5 SoC
- *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
- *
- * The PMECC is an hardware assisted BCH engine, which means part of the
- * ECC algorithm is left to the software. The hardware/software repartition
- * is explained in the "PMECC Controller Functional Description" chapter in
- * Atmel datasheets, and some of the functions in this file are directly
- * implementing the algorithms described in the "Software Implementation"
- * sub-section.
- *
- * TODO: it seems that the software BCH implementation in lib/bch.c is already
- * providing some of the logic we are implementing here. It would be smart
- * to expose the needed lib/bch.c helpers/functions and re-use them here.
- */
-
-#include <linux/genalloc.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "pmecc.h"
-
-/* Galois field dimension */
-#define PMECC_GF_DIMENSION_13			13
-#define PMECC_GF_DIMENSION_14			14
-
-/* Primitive Polynomial used by PMECC */
-#define PMECC_GF_13_PRIMITIVE_POLY		0x201b
-#define PMECC_GF_14_PRIMITIVE_POLY		0x4443
-
-#define PMECC_LOOKUP_TABLE_SIZE_512		0x2000
-#define PMECC_LOOKUP_TABLE_SIZE_1024		0x4000
-
-/* Time out value for reading PMECC status register */
-#define PMECC_MAX_TIMEOUT_MS			100
-
-/* PMECC Register Definitions */
-#define ATMEL_PMECC_CFG				0x0
-#define PMECC_CFG_BCH_STRENGTH(x)		(x)
-#define PMECC_CFG_BCH_STRENGTH_MASK		GENMASK(2, 0)
-#define PMECC_CFG_SECTOR512			(0 << 4)
-#define PMECC_CFG_SECTOR1024			(1 << 4)
-#define PMECC_CFG_NSECTORS(x)			((fls(x) - 1) << 8)
-#define PMECC_CFG_READ_OP			(0 << 12)
-#define PMECC_CFG_WRITE_OP			(1 << 12)
-#define PMECC_CFG_SPARE_ENABLE			BIT(16)
-#define PMECC_CFG_AUTO_ENABLE			BIT(20)
-
-#define ATMEL_PMECC_SAREA			0x4
-#define ATMEL_PMECC_SADDR			0x8
-#define ATMEL_PMECC_EADDR			0xc
-
-#define ATMEL_PMECC_CLK				0x10
-#define PMECC_CLK_133MHZ			(2 << 0)
-
-#define ATMEL_PMECC_CTRL			0x14
-#define PMECC_CTRL_RST				BIT(0)
-#define PMECC_CTRL_DATA				BIT(1)
-#define PMECC_CTRL_USER				BIT(2)
-#define PMECC_CTRL_ENABLE			BIT(4)
-#define PMECC_CTRL_DISABLE			BIT(5)
-
-#define ATMEL_PMECC_SR				0x18
-#define PMECC_SR_BUSY				BIT(0)
-#define PMECC_SR_ENABLE				BIT(4)
-
-#define ATMEL_PMECC_IER				0x1c
-#define ATMEL_PMECC_IDR				0x20
-#define ATMEL_PMECC_IMR				0x24
-#define ATMEL_PMECC_ISR				0x28
-#define PMECC_ERROR_INT				BIT(0)
-
-#define ATMEL_PMECC_ECC(sector, n)		\
-	((((sector) + 1) * 0x40) + (n))
-
-#define ATMEL_PMECC_REM(sector, n)		\
-	((((sector) + 1) * 0x40) + ((n) * 4) + 0x200)
-
-/* PMERRLOC Register Definitions */
-#define ATMEL_PMERRLOC_ELCFG			0x0
-#define PMERRLOC_ELCFG_SECTOR_512		(0 << 0)
-#define PMERRLOC_ELCFG_SECTOR_1024		(1 << 0)
-#define PMERRLOC_ELCFG_NUM_ERRORS(n)		((n) << 16)
-
-#define ATMEL_PMERRLOC_ELPRIM			0x4
-#define ATMEL_PMERRLOC_ELEN			0x8
-#define ATMEL_PMERRLOC_ELDIS			0xc
-#define PMERRLOC_DISABLE			BIT(0)
-
-#define ATMEL_PMERRLOC_ELSR			0x10
-#define PMERRLOC_ELSR_BUSY			BIT(0)
-
-#define ATMEL_PMERRLOC_ELIER			0x14
-#define ATMEL_PMERRLOC_ELIDR			0x18
-#define ATMEL_PMERRLOC_ELIMR			0x1c
-#define ATMEL_PMERRLOC_ELISR			0x20
-#define PMERRLOC_ERR_NUM_MASK			GENMASK(12, 8)
-#define PMERRLOC_CALC_DONE			BIT(0)
-
-#define ATMEL_PMERRLOC_SIGMA(x)			(((x) * 0x4) + 0x28)
-
-#define ATMEL_PMERRLOC_EL(offs, x)		(((x) * 0x4) + (offs))
-
-struct atmel_pmecc_gf_tables {
-	u16 *alpha_to;
-	u16 *index_of;
-};
-
-struct atmel_pmecc_caps {
-	const int *strengths;
-	int nstrengths;
-	int el_offset;
-	bool correct_erased_chunks;
-};
-
-struct atmel_pmecc {
-	struct device *dev;
-	const struct atmel_pmecc_caps *caps;
-
-	struct {
-		void __iomem *base;
-		void __iomem *errloc;
-	} regs;
-
-	struct mutex lock;
-};
-
-struct atmel_pmecc_user_conf_cache {
-	u32 cfg;
-	u32 sarea;
-	u32 saddr;
-	u32 eaddr;
-};
-
-struct atmel_pmecc_user {
-	struct atmel_pmecc_user_conf_cache cache;
-	struct atmel_pmecc *pmecc;
-	const struct atmel_pmecc_gf_tables *gf_tables;
-	int eccbytes;
-	s16 *partial_syn;
-	s16 *si;
-	s16 *lmu;
-	s16 *smu;
-	s32 *mu;
-	s32 *dmu;
-	s32 *delta;
-	u32 isr;
-};
-
-static DEFINE_MUTEX(pmecc_gf_tables_lock);
-static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_512;
-static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_1024;
-
-static inline int deg(unsigned int poly)
-{
-	/* polynomial degree is the most-significant bit index */
-	return fls(poly) - 1;
-}
-
-static int atmel_pmecc_build_gf_tables(int mm, unsigned int poly,
-				       struct atmel_pmecc_gf_tables *gf_tables)
-{
-	unsigned int i, x = 1;
-	const unsigned int k = BIT(deg(poly));
-	unsigned int nn = BIT(mm) - 1;
-
-	/* primitive polynomial must be of degree m */
-	if (k != (1u << mm))
-		return -EINVAL;
-
-	for (i = 0; i < nn; i++) {
-		gf_tables->alpha_to[i] = x;
-		gf_tables->index_of[x] = i;
-		if (i && (x == 1))
-			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
-			return -EINVAL;
-		x <<= 1;
-		if (x & k)
-			x ^= poly;
-	}
-	gf_tables->alpha_to[nn] = 1;
-	gf_tables->index_of[0] = 0;
-
-	return 0;
-}
-
-static const struct atmel_pmecc_gf_tables *
-atmel_pmecc_create_gf_tables(const struct atmel_pmecc_user_req *req)
-{
-	struct atmel_pmecc_gf_tables *gf_tables;
-	unsigned int poly, degree, table_size;
-	int ret;
-
-	if (req->ecc.sectorsize == 512) {
-		degree = PMECC_GF_DIMENSION_13;
-		poly = PMECC_GF_13_PRIMITIVE_POLY;
-		table_size = PMECC_LOOKUP_TABLE_SIZE_512;
-	} else {
-		degree = PMECC_GF_DIMENSION_14;
-		poly = PMECC_GF_14_PRIMITIVE_POLY;
-		table_size = PMECC_LOOKUP_TABLE_SIZE_1024;
-	}
-
-	gf_tables = kzalloc(sizeof(*gf_tables) +
-			    (2 * table_size * sizeof(u16)),
-			    GFP_KERNEL);
-	if (!gf_tables)
-		return ERR_PTR(-ENOMEM);
-
-	gf_tables->alpha_to = (void *)(gf_tables + 1);
-	gf_tables->index_of = gf_tables->alpha_to + table_size;
-
-	ret = atmel_pmecc_build_gf_tables(degree, poly, gf_tables);
-	if (ret) {
-		kfree(gf_tables);
-		return ERR_PTR(ret);
-	}
-
-	return gf_tables;
-}
-
-static const struct atmel_pmecc_gf_tables *
-atmel_pmecc_get_gf_tables(const struct atmel_pmecc_user_req *req)
-{
-	const struct atmel_pmecc_gf_tables **gf_tables, *ret;
-
-	mutex_lock(&pmecc_gf_tables_lock);
-	if (req->ecc.sectorsize == 512)
-		gf_tables = &pmecc_gf_tables_512;
-	else
-		gf_tables = &pmecc_gf_tables_1024;
-
-	ret = *gf_tables;
-
-	if (!ret) {
-		ret = atmel_pmecc_create_gf_tables(req);
-		if (!IS_ERR(ret))
-			*gf_tables = ret;
-	}
-	mutex_unlock(&pmecc_gf_tables_lock);
-
-	return ret;
-}
-
-static int atmel_pmecc_prepare_user_req(struct atmel_pmecc *pmecc,
-					struct atmel_pmecc_user_req *req)
-{
-	int i, max_eccbytes, eccbytes = 0, eccstrength = 0;
-
-	if (req->pagesize <= 0 || req->oobsize <= 0 || req->ecc.bytes <= 0)
-		return -EINVAL;
-
-	if (req->ecc.ooboffset >= 0 &&
-	    req->ecc.ooboffset + req->ecc.bytes > req->oobsize)
-		return -EINVAL;
-
-	if (req->ecc.sectorsize == ATMEL_PMECC_SECTOR_SIZE_AUTO) {
-		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
-			return -EINVAL;
-
-		if (req->pagesize > 512)
-			req->ecc.sectorsize = 1024;
-		else
-			req->ecc.sectorsize = 512;
-	}
-
-	if (req->ecc.sectorsize != 512 && req->ecc.sectorsize != 1024)
-		return -EINVAL;
-
-	if (req->pagesize % req->ecc.sectorsize)
-		return -EINVAL;
-
-	req->ecc.nsectors = req->pagesize / req->ecc.sectorsize;
-
-	max_eccbytes = req->ecc.bytes;
-
-	for (i = 0; i < pmecc->caps->nstrengths; i++) {
-		int nbytes, strength = pmecc->caps->strengths[i];
-
-		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH &&
-		    strength < req->ecc.strength)
-			continue;
-
-		nbytes = DIV_ROUND_UP(strength * fls(8 * req->ecc.sectorsize),
-				      8);
-		nbytes *= req->ecc.nsectors;
-
-		if (nbytes > max_eccbytes)
-			break;
-
-		eccstrength = strength;
-		eccbytes = nbytes;
-
-		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
-			break;
-	}
-
-	if (!eccstrength)
-		return -EINVAL;
-
-	req->ecc.bytes = eccbytes;
-	req->ecc.strength = eccstrength;
-
-	if (req->ecc.ooboffset < 0)
-		req->ecc.ooboffset = req->oobsize - eccbytes;
-
-	return 0;
-}
-
-struct atmel_pmecc_user *
-atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
-			struct atmel_pmecc_user_req *req)
-{
-	struct atmel_pmecc_user *user;
-	const struct atmel_pmecc_gf_tables *gf_tables;
-	int strength, size, ret;
-
-	ret = atmel_pmecc_prepare_user_req(pmecc, req);
-	if (ret)
-		return ERR_PTR(ret);
-
-	size = sizeof(*user);
-	size = ALIGN(size, sizeof(u16));
-	/* Reserve space for partial_syn, si and smu */
-	size += ((2 * req->ecc.strength) + 1) * sizeof(u16) *
-		(2 + req->ecc.strength + 2);
-	/* Reserve space for lmu. */
-	size += (req->ecc.strength + 1) * sizeof(u16);
-	/* Reserve space for mu, dmu and delta. */
-	size = ALIGN(size, sizeof(s32));
-	size += (req->ecc.strength + 1) * sizeof(s32) * 3;
-
-	user = kzalloc(size, GFP_KERNEL);
-	if (!user)
-		return ERR_PTR(-ENOMEM);
-
-	user->pmecc = pmecc;
-
-	user->partial_syn = (s16 *)PTR_ALIGN(user + 1, sizeof(u16));
-	user->si = user->partial_syn + ((2 * req->ecc.strength) + 1);
-	user->lmu = user->si + ((2 * req->ecc.strength) + 1);
-	user->smu = user->lmu + (req->ecc.strength + 1);
-	user->mu = (s32 *)PTR_ALIGN(user->smu +
-				    (((2 * req->ecc.strength) + 1) *
-				     (req->ecc.strength + 2)),
-				    sizeof(s32));
-	user->dmu = user->mu + req->ecc.strength + 1;
-	user->delta = user->dmu + req->ecc.strength + 1;
-
-	gf_tables = atmel_pmecc_get_gf_tables(req);
-	if (IS_ERR(gf_tables)) {
-		kfree(user);
-		return ERR_CAST(gf_tables);
-	}
-
-	user->gf_tables = gf_tables;
-
-	user->eccbytes = req->ecc.bytes / req->ecc.nsectors;
-
-	for (strength = 0; strength < pmecc->caps->nstrengths; strength++) {
-		if (pmecc->caps->strengths[strength] == req->ecc.strength)
-			break;
-	}
-
-	user->cache.cfg = PMECC_CFG_BCH_STRENGTH(strength) |
-			  PMECC_CFG_NSECTORS(req->ecc.nsectors);
-
-	if (req->ecc.sectorsize == 1024)
-		user->cache.cfg |= PMECC_CFG_SECTOR1024;
-
-	user->cache.sarea = req->oobsize - 1;
-	user->cache.saddr = req->ecc.ooboffset;
-	user->cache.eaddr = req->ecc.ooboffset + req->ecc.bytes - 1;
-
-	return user;
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_create_user);
-
-void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user)
-{
-	kfree(user);
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user);
-
-static int get_strength(struct atmel_pmecc_user *user)
-{
-	const int *strengths = user->pmecc->caps->strengths;
-
-	return strengths[user->cache.cfg & PMECC_CFG_BCH_STRENGTH_MASK];
-}
-
-static int get_sectorsize(struct atmel_pmecc_user *user)
-{
-	return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512;
-}
-
-static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector)
-{
-	int strength = get_strength(user);
-	u32 value;
-	int i;
-
-	/* Fill odd syndromes */
-	for (i = 0; i < strength; i++) {
-		value = readl_relaxed(user->pmecc->regs.base +
-				      ATMEL_PMECC_REM(sector, i / 2));
-		if (i & 1)
-			value >>= 16;
-
-		user->partial_syn[(2 * i) + 1] = value;
-	}
-}
-
-static void atmel_pmecc_substitute(struct atmel_pmecc_user *user)
-{
-	int degree = get_sectorsize(user) == 512 ? 13 : 14;
-	int cw_len = BIT(degree) - 1;
-	int strength = get_strength(user);
-	s16 *alpha_to = user->gf_tables->alpha_to;
-	s16 *index_of = user->gf_tables->index_of;
-	s16 *partial_syn = user->partial_syn;
-	s16 *si;
-	int i, j;
-
-	/*
-	 * si[] is a table that holds the current syndrome value,
-	 * an element of that table belongs to the field
-	 */
-	si = user->si;
-
-	memset(&si[1], 0, sizeof(s16) * ((2 * strength) - 1));
-
-	/* Computation 2t syndromes based on S(x) */
-	/* Odd syndromes */
-	for (i = 1; i < 2 * strength; i += 2) {
-		for (j = 0; j < degree; j++) {
-			if (partial_syn[i] & BIT(j))
-				si[i] = alpha_to[i * j] ^ si[i];
-		}
-	}
-	/* Even syndrome = (Odd syndrome) ** 2 */
-	for (i = 2, j = 1; j <= strength; i = ++j << 1) {
-		if (si[j] == 0) {
-			si[i] = 0;
-		} else {
-			s16 tmp;
-
-			tmp = index_of[si[j]];
-			tmp = (tmp * 2) % cw_len;
-			si[i] = alpha_to[tmp];
-		}
-	}
-}
-
-static void atmel_pmecc_get_sigma(struct atmel_pmecc_user *user)
-{
-	s16 *lmu = user->lmu;
-	s16 *si = user->si;
-	s32 *mu = user->mu;
-	s32 *dmu = user->dmu;
-	s32 *delta = user->delta;
-	int degree = get_sectorsize(user) == 512 ? 13 : 14;
-	int cw_len = BIT(degree) - 1;
-	int strength = get_strength(user);
-	int num = 2 * strength + 1;
-	s16 *index_of = user->gf_tables->index_of;
-	s16 *alpha_to = user->gf_tables->alpha_to;
-	int i, j, k;
-	u32 dmu_0_count, tmp;
-	s16 *smu = user->smu;
-
-	/* index of largest delta */
-	int ro;
-	int largest;
-	int diff;
-
-	dmu_0_count = 0;
-
-	/* First Row */
-
-	/* Mu */
-	mu[0] = -1;
-
-	memset(smu, 0, sizeof(s16) * num);
-	smu[0] = 1;
-
-	/* discrepancy set to 1 */
-	dmu[0] = 1;
-	/* polynom order set to 0 */
-	lmu[0] = 0;
-	delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
-
-	/* Second Row */
-
-	/* Mu */
-	mu[1] = 0;
-	/* Sigma(x) set to 1 */
-	memset(&smu[num], 0, sizeof(s16) * num);
-	smu[num] = 1;
-
-	/* discrepancy set to S1 */
-	dmu[1] = si[1];
-
-	/* polynom order set to 0 */
-	lmu[1] = 0;
-
-	delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
-
-	/* Init the Sigma(x) last row */
-	memset(&smu[(strength + 1) * num], 0, sizeof(s16) * num);
-
-	for (i = 1; i <= strength; i++) {
-		mu[i + 1] = i << 1;
-		/* Begin Computing Sigma (Mu+1) and L(mu) */
-		/* check if discrepancy is set to 0 */
-		if (dmu[i] == 0) {
-			dmu_0_count++;
-
-			tmp = ((strength - (lmu[i] >> 1) - 1) / 2);
-			if ((strength - (lmu[i] >> 1) - 1) & 0x1)
-				tmp += 2;
-			else
-				tmp += 1;
-
-			if (dmu_0_count == tmp) {
-				for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
-					smu[(strength + 1) * num + j] =
-							smu[i * num + j];
-
-				lmu[strength + 1] = lmu[i];
-				return;
-			}
-
-			/* copy polynom */
-			for (j = 0; j <= lmu[i] >> 1; j++)
-				smu[(i + 1) * num + j] = smu[i * num + j];
-
-			/* copy previous polynom order to the next */
-			lmu[i + 1] = lmu[i];
-		} else {
-			ro = 0;
-			largest = -1;
-			/* find largest delta with dmu != 0 */
-			for (j = 0; j < i; j++) {
-				if ((dmu[j]) && (delta[j] > largest)) {
-					largest = delta[j];
-					ro = j;
-				}
-			}
-
-			/* compute difference */
-			diff = (mu[i] - mu[ro]);
-
-			/* Compute degree of the new smu polynomial */
-			if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
-				lmu[i + 1] = lmu[i];
-			else
-				lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
-
-			/* Init smu[i+1] with 0 */
-			for (k = 0; k < num; k++)
-				smu[(i + 1) * num + k] = 0;
-
-			/* Compute smu[i+1] */
-			for (k = 0; k <= lmu[ro] >> 1; k++) {
-				s16 a, b, c;
-
-				if (!(smu[ro * num + k] && dmu[i]))
-					continue;
-
-				a = index_of[dmu[i]];
-				b = index_of[dmu[ro]];
-				c = index_of[smu[ro * num + k]];
-				tmp = a + (cw_len - b) + c;
-				a = alpha_to[tmp % cw_len];
-				smu[(i + 1) * num + (k + diff)] = a;
-			}
-
-			for (k = 0; k <= lmu[i] >> 1; k++)
-				smu[(i + 1) * num + k] ^= smu[i * num + k];
-		}
-
-		/* End Computing Sigma (Mu+1) and L(mu) */
-		/* In either case compute delta */
-		delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
-
-		/* Do not compute discrepancy for the last iteration */
-		if (i >= strength)
-			continue;
-
-		for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
-			tmp = 2 * (i - 1);
-			if (k == 0) {
-				dmu[i + 1] = si[tmp + 3];
-			} else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
-				s16 a, b, c;
-
-				a = index_of[smu[(i + 1) * num + k]];
-				b = si[2 * (i - 1) + 3 - k];
-				c = index_of[b];
-				tmp = a + c;
-				tmp %= cw_len;
-				dmu[i + 1] = alpha_to[tmp] ^ dmu[i + 1];
-			}
-		}
-	}
-}
-
-static int atmel_pmecc_err_location(struct atmel_pmecc_user *user)
-{
-	int sector_size = get_sectorsize(user);
-	int degree = sector_size == 512 ? 13 : 14;
-	struct atmel_pmecc *pmecc = user->pmecc;
-	int strength = get_strength(user);
-	int ret, roots_nbr, i, err_nbr = 0;
-	int num = (2 * strength) + 1;
-	s16 *smu = user->smu;
-	u32 val;
-
-	writel(PMERRLOC_DISABLE, pmecc->regs.errloc + ATMEL_PMERRLOC_ELDIS);
-
-	for (i = 0; i <= user->lmu[strength + 1] >> 1; i++) {
-		writel_relaxed(smu[(strength + 1) * num + i],
-			       pmecc->regs.errloc + ATMEL_PMERRLOC_SIGMA(i));
-		err_nbr++;
-	}
-
-	val = (err_nbr - 1) << 16;
-	if (sector_size == 1024)
-		val |= 1;
-
-	writel(val, pmecc->regs.errloc + ATMEL_PMERRLOC_ELCFG);
-	writel((sector_size * 8) + (degree * strength),
-	       pmecc->regs.errloc + ATMEL_PMERRLOC_ELEN);
-
-	ret = readl_relaxed_poll_timeout(pmecc->regs.errloc +
-					 ATMEL_PMERRLOC_ELISR,
-					 val, val & PMERRLOC_CALC_DONE, 0,
-					 PMECC_MAX_TIMEOUT_MS * 1000);
-	if (ret) {
-		dev_err(pmecc->dev,
-			"PMECC: Timeout to calculate error location.\n");
-		return ret;
-	}
-
-	roots_nbr = (val & PMERRLOC_ERR_NUM_MASK) >> 8;
-	/* Number of roots == degree of smu hence <= cap */
-	if (roots_nbr == user->lmu[strength + 1] >> 1)
-		return err_nbr - 1;
-
-	/*
-	 * Number of roots does not match the degree of smu
-	 * unable to correct error.
-	 */
-	return -EBADMSG;
-}
-
-int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
-			       void *data, void *ecc)
-{
-	struct atmel_pmecc *pmecc = user->pmecc;
-	int sectorsize = get_sectorsize(user);
-	int eccbytes = user->eccbytes;
-	int i, nerrors;
-
-	if (!(user->isr & BIT(sector)))
-		return 0;
-
-	atmel_pmecc_gen_syndrome(user, sector);
-	atmel_pmecc_substitute(user);
-	atmel_pmecc_get_sigma(user);
-
-	nerrors = atmel_pmecc_err_location(user);
-	if (nerrors < 0)
-		return nerrors;
-
-	for (i = 0; i < nerrors; i++) {
-		const char *area;
-		int byte, bit;
-		u32 errpos;
-		u8 *ptr;
-
-		errpos = readl_relaxed(pmecc->regs.errloc +
-				ATMEL_PMERRLOC_EL(pmecc->caps->el_offset, i));
-		errpos--;
-
-		byte = errpos / 8;
-		bit = errpos % 8;
-
-		if (byte < sectorsize) {
-			ptr = data + byte;
-			area = "data";
-		} else if (byte < sectorsize + eccbytes) {
-			ptr = ecc + byte - sectorsize;
-			area = "ECC";
-		} else {
-			dev_dbg(pmecc->dev,
-				"Invalid errpos value (%d, max is %d)\n",
-				errpos, (sectorsize + eccbytes) * 8);
-			return -EINVAL;
-		}
-
-		dev_dbg(pmecc->dev,
-			"Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n",
-			area, byte, *ptr, (unsigned int)(*ptr ^ BIT(bit)));
-
-		*ptr ^= BIT(bit);
-	}
-
-	return nerrors;
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_correct_sector);
-
-bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user)
-{
-	return user->pmecc->caps->correct_erased_chunks;
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_correct_erased_chunks);
-
-void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
-					int sector, void *ecc)
-{
-	struct atmel_pmecc *pmecc = user->pmecc;
-	u8 *ptr = ecc;
-	int i;
-
-	for (i = 0; i < user->eccbytes; i++)
-		ptr[i] = readb_relaxed(pmecc->regs.base +
-				       ATMEL_PMECC_ECC(sector, i));
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_get_generated_eccbytes);
-
-void atmel_pmecc_reset(struct atmel_pmecc *pmecc)
-{
-	writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
-	writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_reset);
-
-int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op)
-{
-	struct atmel_pmecc *pmecc = user->pmecc;
-	u32 cfg;
-
-	if (op != NAND_ECC_READ && op != NAND_ECC_WRITE) {
-		dev_err(pmecc->dev, "Bad ECC operation!");
-		return -EINVAL;
-	}
-
-	mutex_lock(&user->pmecc->lock);
-
-	cfg = user->cache.cfg;
-	if (op == NAND_ECC_WRITE)
-		cfg |= PMECC_CFG_WRITE_OP;
-	else
-		cfg |= PMECC_CFG_AUTO_ENABLE;
-
-	writel(cfg, pmecc->regs.base + ATMEL_PMECC_CFG);
-	writel(user->cache.sarea, pmecc->regs.base + ATMEL_PMECC_SAREA);
-	writel(user->cache.saddr, pmecc->regs.base + ATMEL_PMECC_SADDR);
-	writel(user->cache.eaddr, pmecc->regs.base + ATMEL_PMECC_EADDR);
-
-	writel(PMECC_CTRL_ENABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
-	writel(PMECC_CTRL_DATA, pmecc->regs.base + ATMEL_PMECC_CTRL);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_enable);
-
-void atmel_pmecc_disable(struct atmel_pmecc_user *user)
-{
-	atmel_pmecc_reset(user->pmecc);
-	mutex_unlock(&user->pmecc->lock);
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_disable);
-
-int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user)
-{
-	struct atmel_pmecc *pmecc = user->pmecc;
-	u32 status;
-	int ret;
-
-	ret = readl_relaxed_poll_timeout(pmecc->regs.base +
-					 ATMEL_PMECC_SR,
-					 status, !(status & PMECC_SR_BUSY), 0,
-					 PMECC_MAX_TIMEOUT_MS * 1000);
-	if (ret) {
-		dev_err(pmecc->dev,
-			"Timeout while waiting for PMECC ready.\n");
-		return ret;
-	}
-
-	user->isr = readl_relaxed(pmecc->regs.base + ATMEL_PMECC_ISR);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(atmel_pmecc_wait_rdy);
-
-static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev,
-					const struct atmel_pmecc_caps *caps,
-					int pmecc_res_idx, int errloc_res_idx)
-{
-	struct device *dev = &pdev->dev;
-	struct atmel_pmecc *pmecc;
-	struct resource *res;
-
-	pmecc = devm_kzalloc(dev, sizeof(*pmecc), GFP_KERNEL);
-	if (!pmecc)
-		return ERR_PTR(-ENOMEM);
-
-	pmecc->caps = caps;
-	pmecc->dev = dev;
-	mutex_init(&pmecc->lock);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, pmecc_res_idx);
-	pmecc->regs.base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(pmecc->regs.base))
-		return ERR_CAST(pmecc->regs.base);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, errloc_res_idx);
-	pmecc->regs.errloc = devm_ioremap_resource(dev, res);
-	if (IS_ERR(pmecc->regs.errloc))
-		return ERR_CAST(pmecc->regs.errloc);
-
-	/* Disable all interrupts before registering the PMECC handler. */
-	writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR);
-	atmel_pmecc_reset(pmecc);
-
-	return pmecc;
-}
-
-static void devm_atmel_pmecc_put(struct device *dev, void *res)
-{
-	struct atmel_pmecc **pmecc = res;
-
-	put_device((*pmecc)->dev);
-}
-
-static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
-						   struct device_node *np)
-{
-	struct platform_device *pdev;
-	struct atmel_pmecc *pmecc, **ptr;
-
-	pdev = of_find_device_by_node(np);
-	if (!pdev || !platform_get_drvdata(pdev))
-		return ERR_PTR(-EPROBE_DEFER);
-
-	ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
-	if (!ptr)
-		return ERR_PTR(-ENOMEM);
-
-	get_device(&pdev->dev);
-	pmecc = platform_get_drvdata(pdev);
-
-	*ptr = pmecc;
-
-	devres_add(userdev, ptr);
-
-	return pmecc;
-}
-
-static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
-
-static struct atmel_pmecc_caps at91sam9g45_caps = {
-	.strengths = atmel_pmecc_strengths,
-	.nstrengths = 5,
-	.el_offset = 0x8c,
-};
-
-static struct atmel_pmecc_caps sama5d4_caps = {
-	.strengths = atmel_pmecc_strengths,
-	.nstrengths = 5,
-	.el_offset = 0x8c,
-	.correct_erased_chunks = true,
-};
-
-static struct atmel_pmecc_caps sama5d2_caps = {
-	.strengths = atmel_pmecc_strengths,
-	.nstrengths = 6,
-	.el_offset = 0xac,
-	.correct_erased_chunks = true,
-};
-
-static const struct of_device_id atmel_pmecc_legacy_match[] = {
-	{ .compatible = "atmel,sama5d4-nand", &sama5d4_caps },
-	{ .compatible = "atmel,sama5d2-nand", &sama5d2_caps },
-	{ /* sentinel */ }
-};
-
-struct atmel_pmecc *devm_atmel_pmecc_get(struct device *userdev)
-{
-	struct atmel_pmecc *pmecc;
-	struct device_node *np;
-
-	if (!userdev)
-		return ERR_PTR(-EINVAL);
-
-	if (!userdev->of_node)
-		return NULL;
-
-	np = of_parse_phandle(userdev->of_node, "ecc-engine", 0);
-	if (np) {
-		pmecc = atmel_pmecc_get_by_node(userdev, np);
-		of_node_put(np);
-	} else {
-		/*
-		 * Support old DT bindings: in this case the PMECC iomem
-		 * resources are directly defined in the user pdev at position
-		 * 1 and 2. Extract all relevant information from there.
-		 */
-		struct platform_device *pdev = to_platform_device(userdev);
-		const struct atmel_pmecc_caps *caps;
-		const struct of_device_id *match;
-
-		/* No PMECC engine available. */
-		if (!of_property_read_bool(userdev->of_node,
-					   "atmel,has-pmecc"))
-			return NULL;
-
-		caps = &at91sam9g45_caps;
-
-		/* Find the caps associated to the NAND dev node. */
-		match = of_match_node(atmel_pmecc_legacy_match,
-				      userdev->of_node);
-		if (match && match->data)
-			caps = match->data;
-
-		pmecc = atmel_pmecc_create(pdev, caps, 1, 2);
-	}
-
-	return pmecc;
-}
-EXPORT_SYMBOL(devm_atmel_pmecc_get);
-
-static const struct of_device_id atmel_pmecc_match[] = {
-	{ .compatible = "atmel,at91sam9g45-pmecc", &at91sam9g45_caps },
-	{ .compatible = "atmel,sama5d4-pmecc", &sama5d4_caps },
-	{ .compatible = "atmel,sama5d2-pmecc", &sama5d2_caps },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, atmel_pmecc_match);
-
-static int atmel_pmecc_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	const struct atmel_pmecc_caps *caps;
-	struct atmel_pmecc *pmecc;
-
-	caps = of_device_get_match_data(&pdev->dev);
-	if (!caps) {
-		dev_err(dev, "Invalid caps\n");
-		return -EINVAL;
-	}
-
-	pmecc = atmel_pmecc_create(pdev, caps, 0, 1);
-	if (IS_ERR(pmecc))
-		return PTR_ERR(pmecc);
-
-	platform_set_drvdata(pdev, pmecc);
-
-	return 0;
-}
-
-static struct platform_driver atmel_pmecc_driver = {
-	.driver = {
-		.name = "atmel-pmecc",
-		.of_match_table = of_match_ptr(atmel_pmecc_match),
-	},
-	.probe = atmel_pmecc_probe,
-};
-module_platform_driver(atmel_pmecc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
-MODULE_DESCRIPTION("PMECC engine driver");
-MODULE_ALIAS("platform:atmel_pmecc");
diff --git a/drivers/mtd/nand/atmel/pmecc.h b/drivers/mtd/nand/atmel/pmecc.h
deleted file mode 100644
index 817e0dd9fd15..000000000000
--- a/drivers/mtd/nand/atmel/pmecc.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * © Copyright 2016 ATMEL
- * © Copyright 2016 Free Electrons
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * Derived from the atmel_nand.c driver which contained the following
- * copyrights:
- *
- *    Copyright © 2003 Rick Bronson
- *
- *    Derived from drivers/mtd/nand/autcpu12.c
- *        Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
- *
- *    Derived from drivers/mtd/spia.c
- *        Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
- *
- *
- *    Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
- *        Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
- *
- *        Derived from Das U-Boot source code
- *              (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
- *        © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
- *
- *    Add Programmable Multibit ECC support for various AT91 SoC
- *        © Copyright 2012 ATMEL, Hong Xu
- *
- *    Add Nand Flash Controller support for SAMA5 SoC
- *        © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
- *
- */
-
-#ifndef ATMEL_PMECC_H
-#define ATMEL_PMECC_H
-
-#define ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH	0
-#define ATMEL_PMECC_SECTOR_SIZE_AUTO		0
-#define ATMEL_PMECC_OOBOFFSET_AUTO		-1
-
-struct atmel_pmecc_user_req {
-	int pagesize;
-	int oobsize;
-	struct {
-		int strength;
-		int bytes;
-		int sectorsize;
-		int nsectors;
-		int ooboffset;
-	} ecc;
-};
-
-struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev);
-
-struct atmel_pmecc_user *
-atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
-			struct atmel_pmecc_user_req *req);
-void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user);
-
-void atmel_pmecc_reset(struct atmel_pmecc *pmecc);
-int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op);
-void atmel_pmecc_disable(struct atmel_pmecc_user *user);
-int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user);
-int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
-			       void *data, void *ecc);
-bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user);
-void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
-					int sector, void *ecc);
-
-#endif /* ATMEL_PMECC_H */
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
deleted file mode 100644
index 8ab827edf94e..000000000000
--- a/drivers/mtd/nand/au1550nd.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- *  drivers/mtd/nand/au1550nd.c
- *
- *  Copyright (C) 2004 Embedded Edge, LLC
- *
- * 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/slab.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/platform_device.h>
-#include <asm/io.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1550nd.h>
-
-
-struct au1550nd_ctx {
-	struct nand_chip chip;
-
-	int cs;
-	void __iomem *base;
-	void (*write_byte)(struct mtd_info *, u_char);
-};
-
-/**
- * au_read_byte -  read one byte from the chip
- * @mtd:	MTD device structure
- *
- * read function for 8bit buswidth
- */
-static u_char au_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	u_char ret = readb(this->IO_ADDR_R);
-	wmb(); /* drain writebuffer */
-	return ret;
-}
-
-/**
- * au_write_byte -  write one byte to the chip
- * @mtd:	MTD device structure
- * @byte:	pointer to data byte to write
- *
- * write function for 8it buswidth
- */
-static void au_write_byte(struct mtd_info *mtd, u_char byte)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	writeb(byte, this->IO_ADDR_W);
-	wmb(); /* drain writebuffer */
-}
-
-/**
- * au_read_byte16 -  read one byte endianness aware from the chip
- * @mtd:	MTD device structure
- *
- * read function for 16bit buswidth with endianness conversion
- */
-static u_char au_read_byte16(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
-	wmb(); /* drain writebuffer */
-	return ret;
-}
-
-/**
- * au_write_byte16 -  write one byte endianness aware to the chip
- * @mtd:	MTD device structure
- * @byte:	pointer to data byte to write
- *
- * write function for 16bit buswidth with endianness conversion
- */
-static void au_write_byte16(struct mtd_info *mtd, u_char byte)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
-	wmb(); /* drain writebuffer */
-}
-
-/**
- * au_read_word -  read one word from the chip
- * @mtd:	MTD device structure
- *
- * read function for 16bit buswidth without endianness conversion
- */
-static u16 au_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	u16 ret = readw(this->IO_ADDR_R);
-	wmb(); /* drain writebuffer */
-	return ret;
-}
-
-/**
- * au_write_buf -  write buffer to chip
- * @mtd:	MTD device structure
- * @buf:	data buffer
- * @len:	number of bytes to write
- *
- * write function for 8bit buswidth
- */
-static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	for (i = 0; i < len; i++) {
-		writeb(buf[i], this->IO_ADDR_W);
-		wmb(); /* drain writebuffer */
-	}
-}
-
-/**
- * au_read_buf -  read chip data into buffer
- * @mtd:	MTD device structure
- * @buf:	buffer to store date
- * @len:	number of bytes to read
- *
- * read function for 8bit buswidth
- */
-static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	for (i = 0; i < len; i++) {
-		buf[i] = readb(this->IO_ADDR_R);
-		wmb(); /* drain writebuffer */
-	}
-}
-
-/**
- * au_write_buf16 -  write buffer to chip
- * @mtd:	MTD device structure
- * @buf:	data buffer
- * @len:	number of bytes to write
- *
- * write function for 16bit buswidth
- */
-static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	u16 *p = (u16 *) buf;
-	len >>= 1;
-
-	for (i = 0; i < len; i++) {
-		writew(p[i], this->IO_ADDR_W);
-		wmb(); /* drain writebuffer */
-	}
-
-}
-
-/**
- * au_read_buf16 -  read chip data into buffer
- * @mtd:	MTD device structure
- * @buf:	buffer to store date
- * @len:	number of bytes to read
- *
- * read function for 16bit buswidth
- */
-static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	u16 *p = (u16 *) buf;
-	len >>= 1;
-
-	for (i = 0; i < len; i++) {
-		p[i] = readw(this->IO_ADDR_R);
-		wmb(); /* drain writebuffer */
-	}
-}
-
-/* Select the chip by setting nCE to low */
-#define NAND_CTL_SETNCE		1
-/* Deselect the chip by setting nCE to high */
-#define NAND_CTL_CLRNCE		2
-/* Select the command latch by setting CLE to high */
-#define NAND_CTL_SETCLE		3
-/* Deselect the command latch by setting CLE to low */
-#define NAND_CTL_CLRCLE		4
-/* Select the address latch by setting ALE to high */
-#define NAND_CTL_SETALE		5
-/* Deselect the address latch by setting ALE to low */
-#define NAND_CTL_CLRALE		6
-
-static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
-						chip);
-
-	switch (cmd) {
-
-	case NAND_CTL_SETCLE:
-		this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
-		break;
-
-	case NAND_CTL_CLRCLE:
-		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
-		break;
-
-	case NAND_CTL_SETALE:
-		this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
-		break;
-
-	case NAND_CTL_CLRALE:
-		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
-		/* FIXME: Nobody knows why this is necessary,
-		 * but it works only that way */
-		udelay(1);
-		break;
-
-	case NAND_CTL_SETNCE:
-		/* assert (force assert) chip enable */
-		alchemy_wrsmem((1 << (4 + ctx->cs)), AU1000_MEM_STNDCTL);
-		break;
-
-	case NAND_CTL_CLRNCE:
-		/* deassert chip enable */
-		alchemy_wrsmem(0, AU1000_MEM_STNDCTL);
-		break;
-	}
-
-	this->IO_ADDR_R = this->IO_ADDR_W;
-
-	wmb(); /* Drain the writebuffer */
-}
-
-int au1550_device_ready(struct mtd_info *mtd)
-{
-	return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
-}
-
-/**
- * au1550_select_chip - control -CE line
- *	Forbid driving -CE manually permitting the NAND controller to do this.
- *	Keeping -CE asserted during the whole sector reads interferes with the
- *	NOR flash and PCMCIA drivers as it causes contention on the static bus.
- *	We only have to hold -CE low for the NAND read commands since the flash
- *	chip needs it to be asserted during chip not ready time but the NAND
- *	controller keeps it released.
- *
- * @mtd:	MTD device structure
- * @chip:	chipnumber to select, -1 for deselect
- */
-static void au1550_select_chip(struct mtd_info *mtd, int chip)
-{
-}
-
-/**
- * au1550_command - Send command to NAND device
- * @mtd:	MTD device structure
- * @command:	the command to be sent
- * @column:	the column address for this command, -1 if none
- * @page_addr:	the page address for this command, -1 if none
- */
-static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
-						chip);
-	int ce_override = 0, i;
-	unsigned long flags = 0;
-
-	/* Begin command latch cycle */
-	au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
-	/*
-	 * Write out the command to the device.
-	 */
-	if (command == NAND_CMD_SEQIN) {
-		int readcmd;
-
-		if (column >= mtd->writesize) {
-			/* OOB area */
-			column -= mtd->writesize;
-			readcmd = NAND_CMD_READOOB;
-		} else if (column < 256) {
-			/* First 256 bytes --> READ0 */
-			readcmd = NAND_CMD_READ0;
-		} else {
-			column -= 256;
-			readcmd = NAND_CMD_READ1;
-		}
-		ctx->write_byte(mtd, readcmd);
-	}
-	ctx->write_byte(mtd, command);
-
-	/* Set ALE and clear CLE to start address cycle */
-	au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
-
-	if (column != -1 || page_addr != -1) {
-		au1550_hwcontrol(mtd, NAND_CTL_SETALE);
-
-		/* Serially input address */
-		if (column != -1) {
-			/* Adjust columns for 16 bit buswidth */
-			if (this->options & NAND_BUSWIDTH_16 &&
-					!nand_opcode_8bits(command))
-				column >>= 1;
-			ctx->write_byte(mtd, column);
-		}
-		if (page_addr != -1) {
-			ctx->write_byte(mtd, (u8)(page_addr & 0xff));
-
-			if (command == NAND_CMD_READ0 ||
-			    command == NAND_CMD_READ1 ||
-			    command == NAND_CMD_READOOB) {
-				/*
-				 * NAND controller will release -CE after
-				 * the last address byte is written, so we'll
-				 * have to forcibly assert it. No interrupts
-				 * are allowed while we do this as we don't
-				 * want the NOR flash or PCMCIA drivers to
-				 * steal our precious bytes of data...
-				 */
-				ce_override = 1;
-				local_irq_save(flags);
-				au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
-			}
-
-			ctx->write_byte(mtd, (u8)(page_addr >> 8));
-
-			if (this->options & NAND_ROW_ADDR_3)
-				ctx->write_byte(mtd,
-						((page_addr >> 16) & 0x0f));
-		}
-		/* Latch in address */
-		au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
-	}
-
-	/*
-	 * Program and erase have their own busy handlers.
-	 * Status and sequential in need no delay.
-	 */
-	switch (command) {
-
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_STATUS:
-		return;
-
-	case NAND_CMD_RESET:
-		break;
-
-	case NAND_CMD_READ0:
-	case NAND_CMD_READ1:
-	case NAND_CMD_READOOB:
-		/* Check if we're really driving -CE low (just in case) */
-		if (unlikely(!ce_override))
-			break;
-
-		/* Apply a short delay always to ensure that we do wait tWB. */
-		ndelay(100);
-		/* Wait for a chip to become ready... */
-		for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
-			udelay(1);
-
-		/* Release -CE and re-enable interrupts. */
-		au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
-		local_irq_restore(flags);
-		return;
-	}
-	/* Apply this short delay always to ensure that we do wait tWB. */
-	ndelay(100);
-
-	while(!this->dev_ready(mtd));
-}
-
-static int find_nand_cs(unsigned long nand_base)
-{
-	void __iomem *base =
-			(void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
-	unsigned long addr, staddr, start, mask, end;
-	int i;
-
-	for (i = 0; i < 4; i++) {
-		addr = 0x1000 + (i * 0x10);			/* CSx */
-		staddr = __raw_readl(base + addr + 0x08);	/* STADDRx */
-		/* figure out the decoded range of this CS */
-		start = (staddr << 4) & 0xfffc0000;
-		mask = (staddr << 18) & 0xfffc0000;
-		end = (start | (start - 1)) & ~(start ^ mask);
-		if ((nand_base >= start) && (nand_base < end))
-			return i;
-	}
-
-	return -ENODEV;
-}
-
-static int au1550nd_probe(struct platform_device *pdev)
-{
-	struct au1550nd_platdata *pd;
-	struct au1550nd_ctx *ctx;
-	struct nand_chip *this;
-	struct mtd_info *mtd;
-	struct resource *r;
-	int ret, cs;
-
-	pd = dev_get_platdata(&pdev->dev);
-	if (!pd) {
-		dev_err(&pdev->dev, "missing platform data\n");
-		return -ENODEV;
-	}
-
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		dev_err(&pdev->dev, "no NAND memory resource\n");
-		ret = -ENODEV;
-		goto out1;
-	}
-	if (request_mem_region(r->start, resource_size(r), "au1550-nand")) {
-		dev_err(&pdev->dev, "cannot claim NAND memory area\n");
-		ret = -ENOMEM;
-		goto out1;
-	}
-
-	ctx->base = ioremap_nocache(r->start, 0x1000);
-	if (!ctx->base) {
-		dev_err(&pdev->dev, "cannot remap NAND memory area\n");
-		ret = -ENODEV;
-		goto out2;
-	}
-
-	this = &ctx->chip;
-	mtd = nand_to_mtd(this);
-	mtd->dev.parent = &pdev->dev;
-
-	/* figure out which CS# r->start belongs to */
-	cs = find_nand_cs(r->start);
-	if (cs < 0) {
-		dev_err(&pdev->dev, "cannot detect NAND chipselect\n");
-		ret = -ENODEV;
-		goto out3;
-	}
-	ctx->cs = cs;
-
-	this->dev_ready = au1550_device_ready;
-	this->select_chip = au1550_select_chip;
-	this->cmdfunc = au1550_command;
-
-	/* 30 us command delay time */
-	this->chip_delay = 30;
-	this->ecc.mode = NAND_ECC_SOFT;
-	this->ecc.algo = NAND_ECC_HAMMING;
-
-	if (pd->devwidth)
-		this->options |= NAND_BUSWIDTH_16;
-
-	this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
-	ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
-	this->read_word = au_read_word;
-	this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
-	this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
-
-	ret = nand_scan(mtd, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
-		goto out3;
-	}
-
-	mtd_device_register(mtd, pd->parts, pd->num_parts);
-
-	platform_set_drvdata(pdev, ctx);
-
-	return 0;
-
-out3:
-	iounmap(ctx->base);
-out2:
-	release_mem_region(r->start, resource_size(r));
-out1:
-	kfree(ctx);
-	return ret;
-}
-
-static int au1550nd_remove(struct platform_device *pdev)
-{
-	struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
-	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-	nand_release(nand_to_mtd(&ctx->chip));
-	iounmap(ctx->base);
-	release_mem_region(r->start, 0x1000);
-	kfree(ctx);
-	return 0;
-}
-
-static struct platform_driver au1550nd_driver = {
-	.driver = {
-		.name	= "au1550-nand",
-	},
-	.probe		= au1550nd_probe,
-	.remove		= au1550nd_remove,
-};
-
-module_platform_driver(au1550nd_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");
diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
new file mode 100644
index 000000000000..56cde38b92c0
--- /dev/null
+++ b/drivers/mtd/nand/bbt.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 Free Electrons
+ *
+ * Authors:
+ *	Boris Brezillon <boris.brezillon@free-electrons.com>
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#define pr_fmt(fmt)	"nand-bbt: " fmt
+
+#include <linux/mtd/nand.h>
+#include <linux/slab.h>
+
+/**
+ * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
+ * @nand: NAND device
+ *
+ * Initialize the in-memory BBT.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_bbt_init(struct nand_device *nand)
+{
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned int nblocks = nanddev_neraseblocks(nand);
+	unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
+					   BITS_PER_LONG);
+
+	nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
+	if (!nand->bbt.cache)
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_init);
+
+/**
+ * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table)
+ * @nand: NAND device
+ *
+ * Undoes what has been done in nanddev_bbt_init()
+ */
+void nanddev_bbt_cleanup(struct nand_device *nand)
+{
+	kfree(nand->bbt.cache);
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
+
+/**
+ * nanddev_bbt_update() - Update a BBT
+ * @nand: nand device
+ *
+ * Update the BBT. Currently a NOP function since on-flash bbt is not yet
+ * supported.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_bbt_update(struct nand_device *nand)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_update);
+
+/**
+ * nanddev_bbt_get_block_status() - Return the status of an eraseblock
+ * @nand: nand device
+ * @entry: the BBT entry
+ *
+ * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry
+ *	   is bigger than the BBT size.
+ */
+int nanddev_bbt_get_block_status(const struct nand_device *nand,
+				 unsigned int entry)
+{
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned long *pos = nand->bbt.cache +
+			     ((entry * bits_per_block) / BITS_PER_LONG);
+	unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
+	unsigned long status;
+
+	if (entry >= nanddev_neraseblocks(nand))
+		return -ERANGE;
+
+	status = pos[0] >> offs;
+	if (bits_per_block + offs > BITS_PER_LONG)
+		status |= pos[1] << (BITS_PER_LONG - offs);
+
+	return status & GENMASK(bits_per_block - 1, 0);
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
+
+/**
+ * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the
+ *				    in-memory BBT
+ * @nand: nand device
+ * @entry: the BBT entry to update
+ * @status: the new status
+ *
+ * Update an entry of the in-memory BBT. If you want to push the updated BBT
+ * the NAND you should call nanddev_bbt_update().
+ *
+ * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT
+ *	   size.
+ */
+int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
+				 enum nand_bbt_block_status status)
+{
+	unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
+	unsigned long *pos = nand->bbt.cache +
+			     ((entry * bits_per_block) / BITS_PER_LONG);
+	unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
+	unsigned long val = status & GENMASK(bits_per_block - 1, 0);
+
+	if (entry >= nanddev_neraseblocks(nand))
+		return -ERANGE;
+
+	pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
+	pos[0] |= val << offs;
+
+	if (bits_per_block + offs > BITS_PER_LONG) {
+		unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
+
+		pos[1] &= ~GENMASK(rbits - 1, 0);
+		pos[1] |= val >> rbits;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);
diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile
deleted file mode 100644
index f05b119e134b..000000000000
--- a/drivers/mtd/nand/bcm47xxnflash/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-bcm47xxnflash-y				+= main.o
-bcm47xxnflash-y				+= ops_bcm4706.o
-
-obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash.o
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
deleted file mode 100644
index 201b9baa52a0..000000000000
--- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __BCM47XXNFLASH_H
-#define __BCM47XXNFLASH_H
-
-#ifndef pr_fmt
-#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
-#endif
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-
-struct bcm47xxnflash {
-	struct bcma_drv_cc *cc;
-
-	struct nand_chip nand_chip;
-
-	unsigned curr_command;
-	int curr_page_addr;
-	int curr_column;
-
-	u8 id_data[8];
-};
-
-int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
-
-#endif /* BCM47XXNFLASH */
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c
deleted file mode 100644
index fb31429b70a9..000000000000
--- a/drivers/mtd/nand/bcm47xxnflash/main.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * BCM47XX NAND flash driver
- *
- * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.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 "bcm47xxnflash.h"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/bcma/bcma.h>
-
-MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rafał Miłecki");
-
-static const char *probes[] = { "bcm47xxpart", NULL };
-
-static int bcm47xxnflash_probe(struct platform_device *pdev)
-{
-	struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
-	struct bcm47xxnflash *b47n;
-	struct mtd_info *mtd;
-	int err = 0;
-
-	b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
-	if (!b47n)
-		return -ENOMEM;
-
-	nand_set_controller_data(&b47n->nand_chip, b47n);
-	mtd = nand_to_mtd(&b47n->nand_chip);
-	mtd->dev.parent = &pdev->dev;
-	b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
-
-	if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
-		err = bcm47xxnflash_ops_bcm4706_init(b47n);
-	} else {
-		pr_err("Device not supported\n");
-		err = -ENOTSUPP;
-	}
-	if (err) {
-		pr_err("Initialization failed: %d\n", err);
-		return err;
-	}
-
-	platform_set_drvdata(pdev, b47n);
-
-	err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
-	if (err) {
-		pr_err("Failed to register MTD device: %d\n", err);
-		return err;
-	}
-
-	return 0;
-}
-
-static int bcm47xxnflash_remove(struct platform_device *pdev)
-{
-	struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
-
-	nand_release(nand_to_mtd(&nflash->nand_chip));
-
-	return 0;
-}
-
-static struct platform_driver bcm47xxnflash_driver = {
-	.probe	= bcm47xxnflash_probe,
-	.remove = bcm47xxnflash_remove,
-	.driver = {
-		.name = "bcma_nflash",
-	},
-};
-
-module_platform_driver(bcm47xxnflash_driver);
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
deleted file mode 100644
index 54bac5b73f0a..000000000000
--- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * BCM47XX NAND flash driver
- *
- * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.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 "bcm47xxnflash.h"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/bcma/bcma.h>
-
-/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
- * shown ~1000 retries as maxiumum. */
-#define NFLASH_READY_RETRIES		10000
-
-#define NFLASH_SECTOR_SIZE		512
-
-#define NCTL_CMD0			0x00010000
-#define NCTL_COL			0x00020000	/* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
-#define NCTL_ROW			0x00040000	/* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
-#define NCTL_CMD1W			0x00080000
-#define NCTL_READ			0x00100000
-#define NCTL_WRITE			0x00200000
-#define NCTL_SPECADDR			0x01000000
-#define NCTL_READY			0x04000000
-#define NCTL_ERR			0x08000000
-#define NCTL_CSA			0x40000000
-#define NCTL_START			0x80000000
-
-/**************************************************
- * Various helpers
- **************************************************/
-
-static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
-{
-	return ((ns * 1000 * clock) / 1000000) + 1;
-}
-
-static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
-{
-	int i = 0;
-
-	bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
-	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
-		if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
-			i = 0;
-			break;
-		}
-	}
-	if (i) {
-		pr_err("NFLASH control command not ready!\n");
-		return -EBUSY;
-	}
-	return 0;
-}
-
-static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
-{
-	int i;
-
-	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
-		if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
-			if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
-			    BCMA_CC_NFLASH_CTL_ERR) {
-				pr_err("Error on polling\n");
-				return -EBUSY;
-			} else {
-				return 0;
-			}
-		}
-	}
-
-	pr_err("Polling timeout!\n");
-	return -EBUSY;
-}
-
-/**************************************************
- * R/W
- **************************************************/
-
-static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
-					   int len)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-
-	u32 ctlcode;
-	u32 *dest = (u32 *)buf;
-	int i;
-	int toread;
-
-	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
-	/* Don't validate column using nand_chip->page_shift, it may be bigger
-	 * when accessing OOB */
-
-	while (len) {
-		/* We can read maximum of 0x200 bytes at once */
-		toread = min(len, 0x200);
-
-		/* Set page and column */
-		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
-				b47n->curr_column);
-		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
-				b47n->curr_page_addr);
-
-		/* Prepare to read */
-		ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
-			  NCTL_CMD0;
-		ctlcode |= NAND_CMD_READSTART << 8;
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
-			return;
-		if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
-			return;
-
-		/* Eventually read some data :) */
-		for (i = 0; i < toread; i += 4, dest++) {
-			ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
-			if (i == toread - 4) /* Last read goes without that */
-				ctlcode &= ~NCTL_CSA;
-			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
-							      ctlcode))
-				return;
-			*dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
-		}
-
-		b47n->curr_column += toread;
-		len -= toread;
-	}
-}
-
-static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
-					    const uint8_t *buf, int len)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-	struct bcma_drv_cc *cc = b47n->cc;
-
-	u32 ctlcode;
-	const u32 *data = (u32 *)buf;
-	int i;
-
-	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
-	/* Don't validate column using nand_chip->page_shift, it may be bigger
-	 * when accessing OOB */
-
-	for (i = 0; i < len; i += 4, data++) {
-		bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
-
-		ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
-		if (i == len - 4) /* Last read goes without that */
-			ctlcode &= ~NCTL_CSA;
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
-			pr_err("%s ctl_cmd didn't work!\n", __func__);
-			return;
-		}
-	}
-
-	b47n->curr_column += len;
-}
-
-/**************************************************
- * NAND chip ops
- **************************************************/
-
-static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
-					       unsigned int ctrl)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-	u32 code = 0;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (cmd & NAND_CTRL_CLE)
-		code = cmd | NCTL_CMD0;
-
-	/* nCS is not needed for reset command */
-	if (cmd != NAND_CMD_RESET)
-		code |= NCTL_CSA;
-
-	bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
-}
-
-/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
-static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
-						  int chip)
-{
-	return;
-}
-
-static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-
-	return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
-}
-
-/*
- * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
- * For example, reading chip id is performed in a non-standard way.
- * Setting column and page is also handled differently, we use a special
- * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
- * standard commands would be much more complicated.
- */
-static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
-					      unsigned command, int column,
-					      int page_addr)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-	struct bcma_drv_cc *cc = b47n->cc;
-	u32 ctlcode;
-	int i;
-
-	if (column != -1)
-		b47n->curr_column = column;
-	if (page_addr != -1)
-		b47n->curr_page_addr = page_addr;
-
-	switch (command) {
-	case NAND_CMD_RESET:
-		nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
-
-		ndelay(100);
-		nand_wait_ready(mtd);
-		break;
-	case NAND_CMD_READID:
-		ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
-		ctlcode |= NAND_CMD_READID;
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
-			pr_err("READID error\n");
-			break;
-		}
-
-		/*
-		 * Reading is specific, last one has to go without NCTL_CSA
-		 * bit. We don't know how many reads NAND subsystem is going
-		 * to perform, so cache everything.
-		 */
-		for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
-			ctlcode = NCTL_CSA | NCTL_READ;
-			if (i == ARRAY_SIZE(b47n->id_data) - 1)
-				ctlcode &= ~NCTL_CSA;
-			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
-							      ctlcode)) {
-				pr_err("READID error\n");
-				break;
-			}
-			b47n->id_data[i] =
-				bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
-				& 0xFF;
-		}
-
-		break;
-	case NAND_CMD_STATUS:
-		ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
-			pr_err("STATUS command error\n");
-		break;
-	case NAND_CMD_READ0:
-		break;
-	case NAND_CMD_READOOB:
-		if (page_addr != -1)
-			b47n->curr_column += mtd->writesize;
-		break;
-	case NAND_CMD_ERASE1:
-		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
-				b47n->curr_page_addr);
-		ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
-			  NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
-			pr_err("ERASE1 failed\n");
-		break;
-	case NAND_CMD_ERASE2:
-		break;
-	case NAND_CMD_SEQIN:
-		/* Set page and column */
-		bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
-				b47n->curr_column);
-		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
-				b47n->curr_page_addr);
-
-		/* Prepare to write */
-		ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
-		ctlcode |= NAND_CMD_SEQIN;
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
-			pr_err("SEQIN failed\n");
-		break;
-	case NAND_CMD_PAGEPROG:
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
-							  NAND_CMD_PAGEPROG))
-			pr_err("PAGEPROG failed\n");
-		if (bcm47xxnflash_ops_bcm4706_poll(cc))
-			pr_err("PAGEPROG not ready\n");
-		break;
-	default:
-		pr_err("Command 0x%X unsupported\n", command);
-		break;
-	}
-	b47n->curr_command = command;
-}
-
-static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-	struct bcma_drv_cc *cc = b47n->cc;
-	u32 tmp = 0;
-
-	switch (b47n->curr_command) {
-	case NAND_CMD_READID:
-		if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
-			pr_err("Requested invalid id_data: %d\n",
-			       b47n->curr_column);
-			return 0;
-		}
-		return b47n->id_data[b47n->curr_column++];
-	case NAND_CMD_STATUS:
-		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
-			return 0;
-		return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
-	case NAND_CMD_READOOB:
-		bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
-		return tmp & 0xFF;
-	}
-
-	pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
-	return 0;
-}
-
-static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
-					       uint8_t *buf, int len)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-
-	switch (b47n->curr_command) {
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-		bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
-		return;
-	}
-
-	pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
-}
-
-static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
-						const uint8_t *buf, int len)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
-
-	switch (b47n->curr_command) {
-	case NAND_CMD_SEQIN:
-		bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
-		return;
-	}
-
-	pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
-}
-
-/**************************************************
- * Init
- **************************************************/
-
-int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
-{
-	struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
-	int err;
-	u32 freq;
-	u16 clock;
-	u8 w0, w1, w2, w3, w4;
-
-	unsigned long chipsize; /* MiB */
-	u8 tbits, col_bits, col_size, row_bits, row_bsize;
-	u32 val;
-
-	b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
-	nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
-	nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
-	b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
-	b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
-	b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
-	b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
-	b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
-	b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
-
-	nand_chip->chip_delay = 50;
-	b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
-	b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
-
-	/* Enable NAND flash access */
-	bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
-		      BCMA_CC_4706_FLASHSCFG_NF1);
-
-	/* Configure wait counters */
-	if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
-		/* 400 MHz */
-		freq = 400000000 / 4;
-	} else {
-		freq = bcma_chipco_pll_read(b47n->cc, 4);
-		freq = (freq & 0xFFF) >> 3;
-		/* Fixed reference clock 25 MHz and m = 2 */
-		freq = (freq * 25000000 / 2) / 4;
-	}
-	clock = freq / 1000000;
-	w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
-	w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
-	w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
-	w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
-	w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
-	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
-			(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
-
-	/* Scan NAND */
-	err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
-	if (err) {
-		pr_err("Could not scan NAND flash: %d\n", err);
-		goto exit;
-	}
-
-	/* Configure FLASH */
-	chipsize = b47n->nand_chip.chipsize >> 20;
-	tbits = ffs(chipsize); /* find first bit set */
-	if (!tbits || tbits != fls(chipsize)) {
-		pr_err("Invalid flash size: 0x%lX\n", chipsize);
-		err = -ENOTSUPP;
-		goto exit;
-	}
-	tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
-
-	col_bits = b47n->nand_chip.page_shift + 1;
-	col_size = (col_bits + 7) / 8;
-
-	row_bits = tbits - col_bits + 1;
-	row_bsize = (row_bits + 7) / 8;
-
-	val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
-	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
-
-exit:
-	if (err)
-		bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
-			       ~BCMA_CC_4706_FLASHSCFG_NF1);
-	return err;
-}
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
deleted file mode 100644
index 87bbd177b3e5..000000000000
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ /dev/null
@@ -1,862 +0,0 @@
-/* linux/drivers/mtd/nand/bf5xx_nand.c
- *
- * Copyright 2006-2008 Analog Devices Inc.
- *	http://blackfin.uclinux.org/
- *	Bryan Wu <bryan.wu@analog.com>
- *
- * Blackfin BF5xx on-chip NAND flash controller driver
- *
- * Derived from drivers/mtd/nand/s3c2410.c
- * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
- *
- * Derived from drivers/mtd/nand/cafe.c
- * Copyright © 2006 Red Hat, Inc.
- * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
- *
- * Changelog:
- *	12-Jun-2007  Bryan Wu:  Initial version
- *	18-Jul-2007  Bryan Wu:
- *		- ECC_HW and ECC_SW supported
- *		- DMA supported in ECC_HW
- *		- YAFFS tested as rootfs in both ECC_HW and ECC_SW
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/blackfin.h>
-#include <asm/dma.h>
-#include <asm/cacheflush.h>
-#include <asm/nand.h>
-#include <asm/portmux.h>
-
-#define DRV_NAME	"bf5xx-nand"
-#define DRV_VERSION	"1.2"
-#define DRV_AUTHOR	"Bryan Wu <bryan.wu@analog.com>"
-#define DRV_DESC	"BF5xx on-chip NAND FLash Controller Driver"
-
-/* NFC_STAT Masks */
-#define NBUSY       0x01  /* Not Busy */
-#define WB_FULL     0x02  /* Write Buffer Full */
-#define PG_WR_STAT  0x04  /* Page Write Pending */
-#define PG_RD_STAT  0x08  /* Page Read Pending */
-#define WB_EMPTY    0x10  /* Write Buffer Empty */
-
-/* NFC_IRQSTAT Masks */
-#define NBUSYIRQ    0x01  /* Not Busy IRQ */
-#define WB_OVF      0x02  /* Write Buffer Overflow */
-#define WB_EDGE     0x04  /* Write Buffer Edge Detect */
-#define RD_RDY      0x08  /* Read Data Ready */
-#define WR_DONE     0x10  /* Page Write Done */
-
-/* NFC_RST Masks */
-#define ECC_RST     0x01  /* ECC (and NFC counters) Reset */
-
-/* NFC_PGCTL Masks */
-#define PG_RD_START 0x01  /* Page Read Start */
-#define PG_WR_START 0x02  /* Page Write Start */
-
-#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
-static int hardware_ecc = 1;
-#else
-static int hardware_ecc;
-#endif
-
-static const unsigned short bfin_nfc_pin_req[] =
-	{P_NAND_CE,
-	 P_NAND_RB,
-	 P_NAND_D0,
-	 P_NAND_D1,
-	 P_NAND_D2,
-	 P_NAND_D3,
-	 P_NAND_D4,
-	 P_NAND_D5,
-	 P_NAND_D6,
-	 P_NAND_D7,
-	 P_NAND_WE,
-	 P_NAND_RE,
-	 P_NAND_CLE,
-	 P_NAND_ALE,
-	 0};
-
-#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
-static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	if (section > 7)
-		return -ERANGE;
-
-	oobregion->offset = section * 8;
-	oobregion->length = 3;
-
-	return 0;
-}
-
-static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	if (section > 7)
-		return -ERANGE;
-
-	oobregion->offset = (section * 8) + 3;
-	oobregion->length = 5;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
-	.ecc = bootrom_ooblayout_ecc,
-	.free = bootrom_ooblayout_free,
-};
-#endif
-
-/*
- * Data structures for bf5xx nand flash controller driver
- */
-
-/* bf5xx nand info */
-struct bf5xx_nand_info {
-	/* mtd info */
-	struct nand_hw_control		controller;
-	struct nand_chip		chip;
-
-	/* platform info */
-	struct bf5xx_nand_platform	*platform;
-
-	/* device info */
-	struct device			*device;
-
-	/* DMA stuff */
-	struct completion		dma_completion;
-};
-
-/*
- * Conversion functions
- */
-static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
-			    chip);
-}
-
-static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
-{
-	return platform_get_drvdata(pdev);
-}
-
-static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
-{
-	return dev_get_platdata(&pdev->dev);
-}
-
-/*
- * struct nand_chip interface function pointers
- */
-
-/*
- * bf5xx_nand_hwcontrol
- *
- * Issue command and address cycles to the chip
- */
-static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigned int ctrl)
-{
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	while (bfin_read_NFC_STAT() & WB_FULL)
-		cpu_relax();
-
-	if (ctrl & NAND_CLE)
-		bfin_write_NFC_CMD(cmd);
-	else if (ctrl & NAND_ALE)
-		bfin_write_NFC_ADDR(cmd);
-	SSYNC();
-}
-
-/*
- * bf5xx_nand_devready()
- *
- * returns 0 if the nand is busy, 1 if it is ready
- */
-static int bf5xx_nand_devready(struct mtd_info *mtd)
-{
-	unsigned short val = bfin_read_NFC_STAT();
-
-	if ((val & NBUSY) == NBUSY)
-		return 1;
-	else
-		return 0;
-}
-
-/*
- * ECC functions
- * These allow the bf5xx to use the controller's ECC
- * generator block to ECC the data as it passes through
- */
-
-/*
- * ECC error correction function
- */
-static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
-					u_char *read_ecc, u_char *calc_ecc)
-{
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	u32 syndrome[5];
-	u32 calced, stored;
-	int i;
-	unsigned short failing_bit, failing_byte;
-	u_char data;
-
-	calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
-	stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
-
-	syndrome[0] = (calced ^ stored);
-
-	/*
-	 * syndrome 0: all zero
-	 * No error in data
-	 * No action
-	 */
-	if (!syndrome[0] || !calced || !stored)
-		return 0;
-
-	/*
-	 * sysdrome 0: only one bit is one
-	 * ECC data was incorrect
-	 * No action
-	 */
-	if (hweight32(syndrome[0]) == 1) {
-		dev_err(info->device, "ECC data was incorrect!\n");
-		return -EBADMSG;
-	}
-
-	syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
-	syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
-	syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
-	syndrome[4] = syndrome[2] ^ syndrome[3];
-
-	for (i = 0; i < 5; i++)
-		dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
-
-	dev_info(info->device,
-		"calced[0x%08x], stored[0x%08x]\n",
-		calced, stored);
-
-	/*
-	 * sysdrome 0: exactly 11 bits are one, each parity
-	 * and parity' pair is 1 & 0 or 0 & 1.
-	 * 1-bit correctable error
-	 * Correct the error
-	 */
-	if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
-		dev_info(info->device,
-			"1-bit correctable error, correct it.\n");
-		dev_info(info->device,
-			"syndrome[1] 0x%08x\n", syndrome[1]);
-
-		failing_bit = syndrome[1] & 0x7;
-		failing_byte = syndrome[1] >> 0x3;
-		data = *(dat + failing_byte);
-		data = data ^ (0x1 << failing_bit);
-		*(dat + failing_byte) = data;
-
-		return 1;
-	}
-
-	/*
-	 * sysdrome 0: random data
-	 * More than 1-bit error, non-correctable error
-	 * Discard data, mark bad block
-	 */
-	dev_err(info->device,
-		"More than 1-bit error, non-correctable error.\n");
-	dev_err(info->device,
-		"Please discard data, mark bad block\n");
-
-	return -EBADMSG;
-}
-
-static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
-					u_char *read_ecc, u_char *calc_ecc)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret, bitflips = 0;
-
-	ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
-	if (ret < 0)
-		return ret;
-
-	bitflips = ret;
-
-	/* If ecc size is 512, correct second 256 bytes */
-	if (chip->ecc.size == 512) {
-		dat += 256;
-		read_ecc += 3;
-		calc_ecc += 3;
-		ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
-		if (ret < 0)
-			return ret;
-
-		bitflips += ret;
-	}
-
-	return bitflips;
-}
-
-static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	return;
-}
-
-static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
-		const u_char *dat, u_char *ecc_code)
-{
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u16 ecc0, ecc1;
-	u32 code[2];
-	u8 *p;
-
-	/* first 3 bytes ECC code for 256 page size */
-	ecc0 = bfin_read_NFC_ECC0();
-	ecc1 = bfin_read_NFC_ECC1();
-
-	code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
-
-	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
-
-	p = (u8 *) code;
-	memcpy(ecc_code, p, 3);
-
-	/* second 3 bytes ECC code for 512 ecc size */
-	if (chip->ecc.size == 512) {
-		ecc0 = bfin_read_NFC_ECC2();
-		ecc1 = bfin_read_NFC_ECC3();
-		code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
-
-		/* second 3 bytes in ecc_code for second 256
-		 * bytes of 512 page size
-		 */
-		p = (u8 *) (code + 1);
-		memcpy((ecc_code + 3), p, 3);
-		dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
-	}
-
-	return 0;
-}
-
-/*
- * PIO mode for buffer writing and reading
- */
-static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	int i;
-	unsigned short val;
-
-	/*
-	 * Data reads are requested by first writing to NFC_DATA_RD
-	 * and then reading back from NFC_READ.
-	 */
-	for (i = 0; i < len; i++) {
-		while (bfin_read_NFC_STAT() & WB_FULL)
-			cpu_relax();
-
-		/* Contents do not matter */
-		bfin_write_NFC_DATA_RD(0x0000);
-		SSYNC();
-
-		while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
-			cpu_relax();
-
-		buf[i] = bfin_read_NFC_READ();
-
-		val = bfin_read_NFC_IRQSTAT();
-		val |= RD_RDY;
-		bfin_write_NFC_IRQSTAT(val);
-		SSYNC();
-	}
-}
-
-static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
-{
-	uint8_t val;
-
-	bf5xx_nand_read_buf(mtd, &val, 1);
-
-	return val;
-}
-
-static void bf5xx_nand_write_buf(struct mtd_info *mtd,
-				const uint8_t *buf, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++) {
-		while (bfin_read_NFC_STAT() & WB_FULL)
-			cpu_relax();
-
-		bfin_write_NFC_DATA_WR(buf[i]);
-		SSYNC();
-	}
-}
-
-static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	int i;
-	u16 *p = (u16 *) buf;
-	len >>= 1;
-
-	/*
-	 * Data reads are requested by first writing to NFC_DATA_RD
-	 * and then reading back from NFC_READ.
-	 */
-	bfin_write_NFC_DATA_RD(0x5555);
-
-	SSYNC();
-
-	for (i = 0; i < len; i++)
-		p[i] = bfin_read_NFC_READ();
-}
-
-static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
-				const uint8_t *buf, int len)
-{
-	int i;
-	u16 *p = (u16 *) buf;
-	len >>= 1;
-
-	for (i = 0; i < len; i++)
-		bfin_write_NFC_DATA_WR(p[i]);
-
-	SSYNC();
-}
-
-/*
- * DMA functions for buffer writing and reading
- */
-static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
-{
-	struct bf5xx_nand_info *info = dev_id;
-
-	clear_dma_irqstat(CH_NFC);
-	disable_dma(CH_NFC);
-	complete(&info->dma_completion);
-
-	return IRQ_HANDLED;
-}
-
-static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
-				uint8_t *buf, int is_read)
-{
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	unsigned short val;
-
-	dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
-			mtd, buf, is_read);
-
-	/*
-	 * Before starting a dma transfer, be sure to invalidate/flush
-	 * the cache over the address range of your DMA buffer to
-	 * prevent cache coherency problems. Otherwise very subtle bugs
-	 * can be introduced to your driver.
-	 */
-	if (is_read)
-		invalidate_dcache_range((unsigned int)buf,
-				(unsigned int)(buf + chip->ecc.size));
-	else
-		flush_dcache_range((unsigned int)buf,
-				(unsigned int)(buf + chip->ecc.size));
-
-	/*
-	 * This register must be written before each page is
-	 * transferred to generate the correct ECC register
-	 * values.
-	 */
-	bfin_write_NFC_RST(ECC_RST);
-	SSYNC();
-	while (bfin_read_NFC_RST() & ECC_RST)
-		cpu_relax();
-
-	disable_dma(CH_NFC);
-	clear_dma_irqstat(CH_NFC);
-
-	/* setup DMA register with Blackfin DMA API */
-	set_dma_config(CH_NFC, 0x0);
-	set_dma_start_addr(CH_NFC, (unsigned long) buf);
-
-	/* The DMAs have different size on BF52x and BF54x */
-#ifdef CONFIG_BF52x
-	set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
-	set_dma_x_modify(CH_NFC, 2);
-	val = DI_EN | WDSIZE_16;
-#endif
-
-#ifdef CONFIG_BF54x
-	set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
-	set_dma_x_modify(CH_NFC, 4);
-	val = DI_EN | WDSIZE_32;
-#endif
-	/* setup write or read operation */
-	if (is_read)
-		val |= WNR;
-	set_dma_config(CH_NFC, val);
-	enable_dma(CH_NFC);
-
-	/* Start PAGE read/write operation */
-	if (is_read)
-		bfin_write_NFC_PGCTL(PG_RD_START);
-	else
-		bfin_write_NFC_PGCTL(PG_WR_START);
-	wait_for_completion(&info->dma_completion);
-}
-
-static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
-					uint8_t *buf, int len)
-{
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
-
-	if (len == chip->ecc.size)
-		bf5xx_nand_dma_rw(mtd, buf, 1);
-	else
-		bf5xx_nand_read_buf(mtd, buf, len);
-}
-
-static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
-				const uint8_t *buf, int len)
-{
-	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
-
-	if (len == chip->ecc.size)
-		bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
-	else
-		bf5xx_nand_write_buf(mtd, buf, len);
-}
-
-static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-		uint8_t *buf, int oob_required, int page)
-{
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
-	bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return 0;
-}
-
-static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
-		struct nand_chip *chip,	const uint8_t *buf, int oob_required,
-		int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-/*
- * System initialization functions
- */
-static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
-{
-	int ret;
-
-	/* Do not use dma */
-	if (!hardware_ecc)
-		return 0;
-
-	init_completion(&info->dma_completion);
-
-	/* Request NFC DMA channel */
-	ret = request_dma(CH_NFC, "BF5XX NFC driver");
-	if (ret < 0) {
-		dev_err(info->device, " unable to get DMA channel\n");
-		return ret;
-	}
-
-#ifdef CONFIG_BF54x
-	/* Setup DMAC1 channel mux for NFC which shared with SDH */
-	bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
-	SSYNC();
-#endif
-
-	set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
-
-	/* Turn off the DMA channel first */
-	disable_dma(CH_NFC);
-	return 0;
-}
-
-static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
-{
-	/* Free NFC DMA channel */
-	if (hardware_ecc)
-		free_dma(CH_NFC);
-}
-
-/*
- * BF5XX NFC hardware initialization
- *  - pin mux setup
- *  - clear interrupt status
- */
-static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
-{
-	int err = 0;
-	unsigned short val;
-	struct bf5xx_nand_platform *plat = info->platform;
-
-	/* setup NFC_CTL register */
-	dev_info(info->device,
-		"data_width=%d, wr_dly=%d, rd_dly=%d\n",
-		(plat->data_width ? 16 : 8),
-		plat->wr_dly, plat->rd_dly);
-
-	val = (1 << NFC_PG_SIZE_OFFSET) |
-		(plat->data_width << NFC_NWIDTH_OFFSET) |
-		(plat->rd_dly << NFC_RDDLY_OFFSET) |
-		(plat->wr_dly << NFC_WRDLY_OFFSET);
-	dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
-
-	bfin_write_NFC_CTL(val);
-	SSYNC();
-
-	/* clear interrupt status */
-	bfin_write_NFC_IRQMASK(0x0);
-	SSYNC();
-	val = bfin_read_NFC_IRQSTAT();
-	bfin_write_NFC_IRQSTAT(val);
-	SSYNC();
-
-	/* DMA initialization  */
-	if (bf5xx_nand_dma_init(info))
-		err = -ENXIO;
-
-	return err;
-}
-
-/*
- * Device management interface
- */
-static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
-{
-	struct mtd_info *mtd = nand_to_mtd(&info->chip);
-	struct mtd_partition *parts = info->platform->partitions;
-	int nr = info->platform->nr_partitions;
-
-	return mtd_device_register(mtd, parts, nr);
-}
-
-static int bf5xx_nand_remove(struct platform_device *pdev)
-{
-	struct bf5xx_nand_info *info = to_nand_info(pdev);
-
-	/* first thing we need to do is release all our mtds
-	 * and their partitions, then go through freeing the
-	 * resources used
-	 */
-	nand_release(nand_to_mtd(&info->chip));
-
-	peripheral_free_list(bfin_nfc_pin_req);
-	bf5xx_nand_dma_remove(info);
-
-	return 0;
-}
-
-static int bf5xx_nand_scan(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		return ret;
-
-	if (hardware_ecc) {
-		/*
-		 * for nand with page size > 512B, think it as several sections with 512B
-		 */
-		if (likely(mtd->writesize >= 512)) {
-			chip->ecc.size = 512;
-			chip->ecc.bytes = 6;
-			chip->ecc.strength = 2;
-		} else {
-			chip->ecc.size = 256;
-			chip->ecc.bytes = 3;
-			chip->ecc.strength = 1;
-			bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
-			SSYNC();
-		}
-	}
-
-	return	nand_scan_tail(mtd);
-}
-
-/*
- * bf5xx_nand_probe
- *
- * called by device layer when it finds a device matching
- * one our driver can handled. This code checks to see if
- * it can allocate all necessary resources then calls the
- * nand layer to look for devices
- */
-static int bf5xx_nand_probe(struct platform_device *pdev)
-{
-	struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
-	struct bf5xx_nand_info *info = NULL;
-	struct nand_chip *chip = NULL;
-	struct mtd_info *mtd = NULL;
-	int err = 0;
-
-	dev_dbg(&pdev->dev, "(%p)\n", pdev);
-
-	if (!plat) {
-		dev_err(&pdev->dev, "no platform specific information\n");
-		return -EINVAL;
-	}
-
-	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
-		dev_err(&pdev->dev, "requesting Peripherals failed\n");
-		return -EFAULT;
-	}
-
-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-	if (info == NULL) {
-		err = -ENOMEM;
-		goto out_err;
-	}
-
-	platform_set_drvdata(pdev, info);
-
-	nand_hw_control_init(&info->controller);
-
-	info->device     = &pdev->dev;
-	info->platform   = plat;
-
-	/* initialise chip data struct */
-	chip = &info->chip;
-	mtd = nand_to_mtd(&info->chip);
-
-	if (plat->data_width)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
-
-	chip->read_buf = (plat->data_width) ?
-		bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
-	chip->write_buf = (plat->data_width) ?
-		bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
-
-	chip->read_byte    = bf5xx_nand_read_byte;
-
-	chip->cmd_ctrl     = bf5xx_nand_hwcontrol;
-	chip->dev_ready    = bf5xx_nand_devready;
-
-	nand_set_controller_data(chip, mtd);
-	chip->controller   = &info->controller;
-
-	chip->IO_ADDR_R    = (void __iomem *) NFC_READ;
-	chip->IO_ADDR_W    = (void __iomem *) NFC_DATA_WR;
-
-	chip->chip_delay   = 0;
-
-	/* initialise mtd info data struct */
-	mtd->dev.parent = &pdev->dev;
-
-	/* initialise the hardware */
-	err = bf5xx_nand_hw_init(info);
-	if (err)
-		goto out_err;
-
-	/* setup hardware ECC data struct */
-	if (hardware_ecc) {
-#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
-		mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
-#endif
-		chip->read_buf      = bf5xx_nand_dma_read_buf;
-		chip->write_buf     = bf5xx_nand_dma_write_buf;
-		chip->ecc.calculate = bf5xx_nand_calculate_ecc;
-		chip->ecc.correct   = bf5xx_nand_correct_data;
-		chip->ecc.mode	    = NAND_ECC_HW;
-		chip->ecc.hwctl	    = bf5xx_nand_enable_hwecc;
-		chip->ecc.read_page_raw = bf5xx_nand_read_page_raw;
-		chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
-	} else {
-		chip->ecc.mode	    = NAND_ECC_SOFT;
-		chip->ecc.algo	= NAND_ECC_HAMMING;
-	}
-
-	/* scan hardware nand chip and setup mtd info data struct */
-	if (bf5xx_nand_scan(mtd)) {
-		err = -ENXIO;
-		goto out_err_nand_scan;
-	}
-
-#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
-	chip->badblockpos = 63;
-#endif
-
-	/* add NAND partition */
-	bf5xx_nand_add_partition(info);
-
-	dev_dbg(&pdev->dev, "initialised ok\n");
-	return 0;
-
-out_err_nand_scan:
-	bf5xx_nand_dma_remove(info);
-out_err:
-	peripheral_free_list(bfin_nfc_pin_req);
-
-	return err;
-}
-
-/* driver device registration */
-static struct platform_driver bf5xx_nand_driver = {
-	.probe		= bf5xx_nand_probe,
-	.remove		= bf5xx_nand_remove,
-	.driver		= {
-		.name	= DRV_NAME,
-	},
-};
-
-module_platform_driver(bf5xx_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR(DRV_AUTHOR);
-MODULE_DESCRIPTION(DRV_DESC);
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/mtd/nand/brcmnand/Makefile b/drivers/mtd/nand/brcmnand/Makefile
deleted file mode 100644
index 195b845e48b8..000000000000
--- a/drivers/mtd/nand/brcmnand/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# link order matters; don't link the more generic brcmstb_nand.o before the
-# more specific iproc_nand.o, for instance
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= iproc_nand.o
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm63138_nand.o
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm6368_nand.o
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmstb_nand.o
-obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand.o
diff --git a/drivers/mtd/nand/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/brcmnand/bcm63138_nand.c
deleted file mode 100644
index 59444b3a697d..000000000000
--- a/drivers/mtd/nand/brcmnand/bcm63138_nand.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright © 2015 Broadcom 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/device.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "brcmnand.h"
-
-struct bcm63138_nand_soc {
-	struct brcmnand_soc soc;
-	void __iomem *base;
-};
-
-#define BCM63138_NAND_INT_STATUS		0x00
-#define BCM63138_NAND_INT_EN			0x04
-
-enum {
-	BCM63138_CTLRDY		= BIT(4),
-};
-
-static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
-{
-	struct bcm63138_nand_soc *priv =
-			container_of(soc, struct bcm63138_nand_soc, soc);
-	void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
-	u32 val = brcmnand_readl(mmio);
-
-	if (val & BCM63138_CTLRDY) {
-		brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
-		return true;
-	}
-
-	return false;
-}
-
-static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
-{
-	struct bcm63138_nand_soc *priv =
-			container_of(soc, struct bcm63138_nand_soc, soc);
-	void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
-	u32 val = brcmnand_readl(mmio);
-
-	if (en)
-		val |= BCM63138_CTLRDY;
-	else
-		val &= ~BCM63138_CTLRDY;
-
-	brcmnand_writel(val, mmio);
-}
-
-static int bcm63138_nand_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct bcm63138_nand_soc *priv;
-	struct brcmnand_soc *soc;
-	struct resource *res;
-
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-	soc = &priv->soc;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
-	priv->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(priv->base))
-		return PTR_ERR(priv->base);
-
-	soc->ctlrdy_ack = bcm63138_nand_intc_ack;
-	soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
-
-	return brcmnand_probe(pdev, soc);
-}
-
-static const struct of_device_id bcm63138_nand_of_match[] = {
-	{ .compatible = "brcm,nand-bcm63138" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
-
-static struct platform_driver bcm63138_nand_driver = {
-	.probe			= bcm63138_nand_probe,
-	.remove			= brcmnand_remove,
-	.driver = {
-		.name		= "bcm63138_nand",
-		.pm		= &brcmnand_pm_ops,
-		.of_match_table	= bcm63138_nand_of_match,
-	}
-};
-module_platform_driver(bcm63138_nand_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Brian Norris");
-MODULE_DESCRIPTION("NAND driver for BCM63138");
diff --git a/drivers/mtd/nand/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/brcmnand/bcm6368_nand.c
deleted file mode 100644
index 34c91b0e1e69..000000000000
--- a/drivers/mtd/nand/brcmnand/bcm6368_nand.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2015 Simon Arlott
- *
- * 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.
- *
- * Derived from bcm63138_nand.c:
- * Copyright © 2015 Broadcom Corporation
- *
- * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
- * Copyright 2000-2010 Broadcom Corporation
- *
- * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c:
- * Copyright 2000-2010 Broadcom Corporation
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "brcmnand.h"
-
-struct bcm6368_nand_soc {
-	struct brcmnand_soc soc;
-	void __iomem *base;
-};
-
-#define BCM6368_NAND_INT		0x00
-#define  BCM6368_NAND_STATUS_SHIFT	0
-#define  BCM6368_NAND_STATUS_MASK	(0xfff << BCM6368_NAND_STATUS_SHIFT)
-#define  BCM6368_NAND_ENABLE_SHIFT	16
-#define  BCM6368_NAND_ENABLE_MASK	(0xffff << BCM6368_NAND_ENABLE_SHIFT)
-#define BCM6368_NAND_BASE_ADDR0	0x04
-#define BCM6368_NAND_BASE_ADDR1	0x0c
-
-enum {
-	BCM6368_NP_READ		= BIT(0),
-	BCM6368_BLOCK_ERASE	= BIT(1),
-	BCM6368_COPY_BACK	= BIT(2),
-	BCM6368_PAGE_PGM	= BIT(3),
-	BCM6368_CTRL_READY	= BIT(4),
-	BCM6368_DEV_RBPIN	= BIT(5),
-	BCM6368_ECC_ERR_UNC	= BIT(6),
-	BCM6368_ECC_ERR_CORR	= BIT(7),
-};
-
-static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
-{
-	struct bcm6368_nand_soc *priv =
-			container_of(soc, struct bcm6368_nand_soc, soc);
-	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
-	u32 val = brcmnand_readl(mmio);
-
-	if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
-		/* Ack interrupt */
-		val &= ~BCM6368_NAND_STATUS_MASK;
-		val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
-		brcmnand_writel(val, mmio);
-		return true;
-	}
-
-	return false;
-}
-
-static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
-{
-	struct bcm6368_nand_soc *priv =
-			container_of(soc, struct bcm6368_nand_soc, soc);
-	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
-	u32 val = brcmnand_readl(mmio);
-
-	/* Don't ack any interrupts */
-	val &= ~BCM6368_NAND_STATUS_MASK;
-
-	if (en)
-		val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
-	else
-		val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
-
-	brcmnand_writel(val, mmio);
-}
-
-static int bcm6368_nand_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct bcm6368_nand_soc *priv;
-	struct brcmnand_soc *soc;
-	struct resource *res;
-
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-	soc = &priv->soc;
-
-	res = platform_get_resource_byname(pdev,
-		IORESOURCE_MEM, "nand-int-base");
-	priv->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(priv->base))
-		return PTR_ERR(priv->base);
-
-	soc->ctlrdy_ack = bcm6368_nand_intc_ack;
-	soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
-
-	/* Disable and ack all interrupts  */
-	brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
-	brcmnand_writel(BCM6368_NAND_STATUS_MASK,
-			priv->base + BCM6368_NAND_INT);
-
-	return brcmnand_probe(pdev, soc);
-}
-
-static const struct of_device_id bcm6368_nand_of_match[] = {
-	{ .compatible = "brcm,nand-bcm6368" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
-
-static struct platform_driver bcm6368_nand_driver = {
-	.probe			= bcm6368_nand_probe,
-	.remove			= brcmnand_remove,
-	.driver = {
-		.name		= "bcm6368_nand",
-		.pm		= &brcmnand_pm_ops,
-		.of_match_table	= bcm6368_nand_of_match,
-	}
-};
-module_platform_driver(bcm6368_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Arlott");
-MODULE_DESCRIPTION("NAND driver for BCM6368");
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
deleted file mode 100644
index c28fd2bc1a84..000000000000
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ /dev/null
@@ -1,2620 +0,0 @@
-/*
- * Copyright © 2010-2015 Broadcom 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/clk.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/bug.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/mm.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/log2.h>
-
-#include "brcmnand.h"
-
-/*
- * This flag controls if WP stays on between erase/write commands to mitigate
- * flash corruption due to power glitches. Values:
- * 0: NAND_WP is not used or not available
- * 1: NAND_WP is set by default, cleared for erase/write operations
- * 2: NAND_WP is always cleared
- */
-static int wp_on = 1;
-module_param(wp_on, int, 0444);
-
-/***********************************************************************
- * Definitions
- ***********************************************************************/
-
-#define DRV_NAME			"brcmnand"
-
-#define CMD_NULL			0x00
-#define CMD_PAGE_READ			0x01
-#define CMD_SPARE_AREA_READ		0x02
-#define CMD_STATUS_READ			0x03
-#define CMD_PROGRAM_PAGE		0x04
-#define CMD_PROGRAM_SPARE_AREA		0x05
-#define CMD_COPY_BACK			0x06
-#define CMD_DEVICE_ID_READ		0x07
-#define CMD_BLOCK_ERASE			0x08
-#define CMD_FLASH_RESET			0x09
-#define CMD_BLOCKS_LOCK			0x0a
-#define CMD_BLOCKS_LOCK_DOWN		0x0b
-#define CMD_BLOCKS_UNLOCK		0x0c
-#define CMD_READ_BLOCKS_LOCK_STATUS	0x0d
-#define CMD_PARAMETER_READ		0x0e
-#define CMD_PARAMETER_CHANGE_COL	0x0f
-#define CMD_LOW_LEVEL_OP		0x10
-
-struct brcm_nand_dma_desc {
-	u32 next_desc;
-	u32 next_desc_ext;
-	u32 cmd_irq;
-	u32 dram_addr;
-	u32 dram_addr_ext;
-	u32 tfr_len;
-	u32 total_len;
-	u32 flash_addr;
-	u32 flash_addr_ext;
-	u32 cs;
-	u32 pad2[5];
-	u32 status_valid;
-} __packed;
-
-/* Bitfields for brcm_nand_dma_desc::status_valid */
-#define FLASH_DMA_ECC_ERROR	(1 << 8)
-#define FLASH_DMA_CORR_ERROR	(1 << 9)
-
-/* 512B flash cache in the NAND controller HW */
-#define FC_SHIFT		9U
-#define FC_BYTES		512U
-#define FC_WORDS		(FC_BYTES >> 2)
-
-#define BRCMNAND_MIN_PAGESIZE	512
-#define BRCMNAND_MIN_BLOCKSIZE	(8 * 1024)
-#define BRCMNAND_MIN_DEVSIZE	(4ULL * 1024 * 1024)
-
-#define NAND_CTRL_RDY			(INTFC_CTLR_READY | INTFC_FLASH_READY)
-#define NAND_POLL_STATUS_TIMEOUT_MS	100
-
-/* Controller feature flags */
-enum {
-	BRCMNAND_HAS_1K_SECTORS			= BIT(0),
-	BRCMNAND_HAS_PREFETCH			= BIT(1),
-	BRCMNAND_HAS_CACHE_MODE			= BIT(2),
-	BRCMNAND_HAS_WP				= BIT(3),
-};
-
-struct brcmnand_controller {
-	struct device		*dev;
-	struct nand_hw_control	controller;
-	void __iomem		*nand_base;
-	void __iomem		*nand_fc; /* flash cache */
-	void __iomem		*flash_dma_base;
-	unsigned int		irq;
-	unsigned int		dma_irq;
-	int			nand_version;
-
-	/* Some SoCs provide custom interrupt status register(s) */
-	struct brcmnand_soc	*soc;
-
-	/* Some SoCs have a gateable clock for the controller */
-	struct clk		*clk;
-
-	int			cmd_pending;
-	bool			dma_pending;
-	struct completion	done;
-	struct completion	dma_done;
-
-	/* List of NAND hosts (one for each chip-select) */
-	struct list_head host_list;
-
-	struct brcm_nand_dma_desc *dma_desc;
-	dma_addr_t		dma_pa;
-
-	/* in-memory cache of the FLASH_CACHE, used only for some commands */
-	u8			flash_cache[FC_BYTES];
-
-	/* Controller revision details */
-	const u16		*reg_offsets;
-	unsigned int		reg_spacing; /* between CS1, CS2, ... regs */
-	const u8		*cs_offsets; /* within each chip-select */
-	const u8		*cs0_offsets; /* within CS0, if different */
-	unsigned int		max_block_size;
-	const unsigned int	*block_sizes;
-	unsigned int		max_page_size;
-	const unsigned int	*page_sizes;
-	unsigned int		max_oob;
-	u32			features;
-
-	/* for low-power standby/resume only */
-	u32			nand_cs_nand_select;
-	u32			nand_cs_nand_xor;
-	u32			corr_stat_threshold;
-	u32			flash_dma_mode;
-};
-
-struct brcmnand_cfg {
-	u64			device_size;
-	unsigned int		block_size;
-	unsigned int		page_size;
-	unsigned int		spare_area_size;
-	unsigned int		device_width;
-	unsigned int		col_adr_bytes;
-	unsigned int		blk_adr_bytes;
-	unsigned int		ful_adr_bytes;
-	unsigned int		sector_size_1k;
-	unsigned int		ecc_level;
-	/* use for low-power standby/resume only */
-	u32			acc_control;
-	u32			config;
-	u32			config_ext;
-	u32			timing_1;
-	u32			timing_2;
-};
-
-struct brcmnand_host {
-	struct list_head	node;
-
-	struct nand_chip	chip;
-	struct platform_device	*pdev;
-	int			cs;
-
-	unsigned int		last_cmd;
-	unsigned int		last_byte;
-	u64			last_addr;
-	struct brcmnand_cfg	hwcfg;
-	struct brcmnand_controller *ctrl;
-};
-
-enum brcmnand_reg {
-	BRCMNAND_CMD_START = 0,
-	BRCMNAND_CMD_EXT_ADDRESS,
-	BRCMNAND_CMD_ADDRESS,
-	BRCMNAND_INTFC_STATUS,
-	BRCMNAND_CS_SELECT,
-	BRCMNAND_CS_XOR,
-	BRCMNAND_LL_OP,
-	BRCMNAND_CS0_BASE,
-	BRCMNAND_CS1_BASE,		/* CS1 regs, if non-contiguous */
-	BRCMNAND_CORR_THRESHOLD,
-	BRCMNAND_CORR_THRESHOLD_EXT,
-	BRCMNAND_UNCORR_COUNT,
-	BRCMNAND_CORR_COUNT,
-	BRCMNAND_CORR_EXT_ADDR,
-	BRCMNAND_CORR_ADDR,
-	BRCMNAND_UNCORR_EXT_ADDR,
-	BRCMNAND_UNCORR_ADDR,
-	BRCMNAND_SEMAPHORE,
-	BRCMNAND_ID,
-	BRCMNAND_ID_EXT,
-	BRCMNAND_LL_RDATA,
-	BRCMNAND_OOB_READ_BASE,
-	BRCMNAND_OOB_READ_10_BASE,	/* offset 0x10, if non-contiguous */
-	BRCMNAND_OOB_WRITE_BASE,
-	BRCMNAND_OOB_WRITE_10_BASE,	/* offset 0x10, if non-contiguous */
-	BRCMNAND_FC_BASE,
-};
-
-/* BRCMNAND v4.0 */
-static const u16 brcmnand_regs_v40[] = {
-	[BRCMNAND_CMD_START]		=  0x04,
-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-	[BRCMNAND_INTFC_STATUS]		=  0x6c,
-	[BRCMNAND_CS_SELECT]		=  0x14,
-	[BRCMNAND_CS_XOR]		=  0x18,
-	[BRCMNAND_LL_OP]		= 0x178,
-	[BRCMNAND_CS0_BASE]		=  0x40,
-	[BRCMNAND_CS1_BASE]		=  0xd0,
-	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
-	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
-	[BRCMNAND_UNCORR_COUNT]		=     0,
-	[BRCMNAND_CORR_COUNT]		=     0,
-	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
-	[BRCMNAND_CORR_ADDR]		=  0x74,
-	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
-	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
-	[BRCMNAND_SEMAPHORE]		=  0x58,
-	[BRCMNAND_ID]			=  0x60,
-	[BRCMNAND_ID_EXT]		=  0x64,
-	[BRCMNAND_LL_RDATA]		= 0x17c,
-	[BRCMNAND_OOB_READ_BASE]	=  0x20,
-	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
-	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-	[BRCMNAND_FC_BASE]		= 0x200,
-};
-
-/* BRCMNAND v5.0 */
-static const u16 brcmnand_regs_v50[] = {
-	[BRCMNAND_CMD_START]		=  0x04,
-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-	[BRCMNAND_INTFC_STATUS]		=  0x6c,
-	[BRCMNAND_CS_SELECT]		=  0x14,
-	[BRCMNAND_CS_XOR]		=  0x18,
-	[BRCMNAND_LL_OP]		= 0x178,
-	[BRCMNAND_CS0_BASE]		=  0x40,
-	[BRCMNAND_CS1_BASE]		=  0xd0,
-	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
-	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
-	[BRCMNAND_UNCORR_COUNT]		=     0,
-	[BRCMNAND_CORR_COUNT]		=     0,
-	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
-	[BRCMNAND_CORR_ADDR]		=  0x74,
-	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
-	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
-	[BRCMNAND_SEMAPHORE]		=  0x58,
-	[BRCMNAND_ID]			=  0x60,
-	[BRCMNAND_ID_EXT]		=  0x64,
-	[BRCMNAND_LL_RDATA]		= 0x17c,
-	[BRCMNAND_OOB_READ_BASE]	=  0x20,
-	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
-	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
-	[BRCMNAND_OOB_WRITE_10_BASE]	= 0x140,
-	[BRCMNAND_FC_BASE]		= 0x200,
-};
-
-/* BRCMNAND v6.0 - v7.1 */
-static const u16 brcmnand_regs_v60[] = {
-	[BRCMNAND_CMD_START]		=  0x04,
-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-	[BRCMNAND_INTFC_STATUS]		=  0x14,
-	[BRCMNAND_CS_SELECT]		=  0x18,
-	[BRCMNAND_CS_XOR]		=  0x1c,
-	[BRCMNAND_LL_OP]		=  0x20,
-	[BRCMNAND_CS0_BASE]		=  0x50,
-	[BRCMNAND_CS1_BASE]		=     0,
-	[BRCMNAND_CORR_THRESHOLD]	=  0xc0,
-	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xc4,
-	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
-	[BRCMNAND_CORR_COUNT]		= 0x100,
-	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
-	[BRCMNAND_CORR_ADDR]		= 0x110,
-	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
-	[BRCMNAND_UNCORR_ADDR]		= 0x118,
-	[BRCMNAND_SEMAPHORE]		= 0x150,
-	[BRCMNAND_ID]			= 0x194,
-	[BRCMNAND_ID_EXT]		= 0x198,
-	[BRCMNAND_LL_RDATA]		= 0x19c,
-	[BRCMNAND_OOB_READ_BASE]	= 0x200,
-	[BRCMNAND_OOB_READ_10_BASE]	=     0,
-	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-	[BRCMNAND_FC_BASE]		= 0x400,
-};
-
-/* BRCMNAND v7.1 */
-static const u16 brcmnand_regs_v71[] = {
-	[BRCMNAND_CMD_START]		=  0x04,
-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-	[BRCMNAND_INTFC_STATUS]		=  0x14,
-	[BRCMNAND_CS_SELECT]		=  0x18,
-	[BRCMNAND_CS_XOR]		=  0x1c,
-	[BRCMNAND_LL_OP]		=  0x20,
-	[BRCMNAND_CS0_BASE]		=  0x50,
-	[BRCMNAND_CS1_BASE]		=     0,
-	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
-	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
-	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
-	[BRCMNAND_CORR_COUNT]		= 0x100,
-	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
-	[BRCMNAND_CORR_ADDR]		= 0x110,
-	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
-	[BRCMNAND_UNCORR_ADDR]		= 0x118,
-	[BRCMNAND_SEMAPHORE]		= 0x150,
-	[BRCMNAND_ID]			= 0x194,
-	[BRCMNAND_ID_EXT]		= 0x198,
-	[BRCMNAND_LL_RDATA]		= 0x19c,
-	[BRCMNAND_OOB_READ_BASE]	= 0x200,
-	[BRCMNAND_OOB_READ_10_BASE]	=     0,
-	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-	[BRCMNAND_FC_BASE]		= 0x400,
-};
-
-/* BRCMNAND v7.2 */
-static const u16 brcmnand_regs_v72[] = {
-	[BRCMNAND_CMD_START]		=  0x04,
-	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
-	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
-	[BRCMNAND_INTFC_STATUS]		=  0x14,
-	[BRCMNAND_CS_SELECT]		=  0x18,
-	[BRCMNAND_CS_XOR]		=  0x1c,
-	[BRCMNAND_LL_OP]		=  0x20,
-	[BRCMNAND_CS0_BASE]		=  0x50,
-	[BRCMNAND_CS1_BASE]		=     0,
-	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
-	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
-	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
-	[BRCMNAND_CORR_COUNT]		= 0x100,
-	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
-	[BRCMNAND_CORR_ADDR]		= 0x110,
-	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
-	[BRCMNAND_UNCORR_ADDR]		= 0x118,
-	[BRCMNAND_SEMAPHORE]		= 0x150,
-	[BRCMNAND_ID]			= 0x194,
-	[BRCMNAND_ID_EXT]		= 0x198,
-	[BRCMNAND_LL_RDATA]		= 0x19c,
-	[BRCMNAND_OOB_READ_BASE]	= 0x200,
-	[BRCMNAND_OOB_READ_10_BASE]	=     0,
-	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
-	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
-	[BRCMNAND_FC_BASE]		= 0x600,
-};
-
-enum brcmnand_cs_reg {
-	BRCMNAND_CS_CFG_EXT = 0,
-	BRCMNAND_CS_CFG,
-	BRCMNAND_CS_ACC_CONTROL,
-	BRCMNAND_CS_TIMING1,
-	BRCMNAND_CS_TIMING2,
-};
-
-/* Per chip-select offsets for v7.1 */
-static const u8 brcmnand_cs_offsets_v71[] = {
-	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
-	[BRCMNAND_CS_CFG_EXT]		= 0x04,
-	[BRCMNAND_CS_CFG]		= 0x08,
-	[BRCMNAND_CS_TIMING1]		= 0x0c,
-	[BRCMNAND_CS_TIMING2]		= 0x10,
-};
-
-/* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
-static const u8 brcmnand_cs_offsets[] = {
-	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
-	[BRCMNAND_CS_CFG_EXT]		= 0x04,
-	[BRCMNAND_CS_CFG]		= 0x04,
-	[BRCMNAND_CS_TIMING1]		= 0x08,
-	[BRCMNAND_CS_TIMING2]		= 0x0c,
-};
-
-/* Per chip-select offset for <= v5.0 on CS0 only */
-static const u8 brcmnand_cs_offsets_cs0[] = {
-	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
-	[BRCMNAND_CS_CFG_EXT]		= 0x08,
-	[BRCMNAND_CS_CFG]		= 0x08,
-	[BRCMNAND_CS_TIMING1]		= 0x10,
-	[BRCMNAND_CS_TIMING2]		= 0x14,
-};
-
-/*
- * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
- * one config register, but once the bitfields overflowed, newer controllers
- * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
- */
-enum {
-	CFG_BLK_ADR_BYTES_SHIFT		= 8,
-	CFG_COL_ADR_BYTES_SHIFT		= 12,
-	CFG_FUL_ADR_BYTES_SHIFT		= 16,
-	CFG_BUS_WIDTH_SHIFT		= 23,
-	CFG_BUS_WIDTH			= BIT(CFG_BUS_WIDTH_SHIFT),
-	CFG_DEVICE_SIZE_SHIFT		= 24,
-
-	/* Only for pre-v7.1 (with no CFG_EXT register) */
-	CFG_PAGE_SIZE_SHIFT		= 20,
-	CFG_BLK_SIZE_SHIFT		= 28,
-
-	/* Only for v7.1+ (with CFG_EXT register) */
-	CFG_EXT_PAGE_SIZE_SHIFT		= 0,
-	CFG_EXT_BLK_SIZE_SHIFT		= 4,
-};
-
-/* BRCMNAND_INTFC_STATUS */
-enum {
-	INTFC_FLASH_STATUS		= GENMASK(7, 0),
-
-	INTFC_ERASED			= BIT(27),
-	INTFC_OOB_VALID			= BIT(28),
-	INTFC_CACHE_VALID		= BIT(29),
-	INTFC_FLASH_READY		= BIT(30),
-	INTFC_CTLR_READY		= BIT(31),
-};
-
-static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
-{
-	return brcmnand_readl(ctrl->nand_base + offs);
-}
-
-static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
-				 u32 val)
-{
-	brcmnand_writel(val, ctrl->nand_base + offs);
-}
-
-static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
-{
-	static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
-	static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
-	static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
-
-	ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
-
-	/* Only support v4.0+? */
-	if (ctrl->nand_version < 0x0400) {
-		dev_err(ctrl->dev, "version %#x not supported\n",
-			ctrl->nand_version);
-		return -ENODEV;
-	}
-
-	/* Register offsets */
-	if (ctrl->nand_version >= 0x0702)
-		ctrl->reg_offsets = brcmnand_regs_v72;
-	else if (ctrl->nand_version >= 0x0701)
-		ctrl->reg_offsets = brcmnand_regs_v71;
-	else if (ctrl->nand_version >= 0x0600)
-		ctrl->reg_offsets = brcmnand_regs_v60;
-	else if (ctrl->nand_version >= 0x0500)
-		ctrl->reg_offsets = brcmnand_regs_v50;
-	else if (ctrl->nand_version >= 0x0400)
-		ctrl->reg_offsets = brcmnand_regs_v40;
-
-	/* Chip-select stride */
-	if (ctrl->nand_version >= 0x0701)
-		ctrl->reg_spacing = 0x14;
-	else
-		ctrl->reg_spacing = 0x10;
-
-	/* Per chip-select registers */
-	if (ctrl->nand_version >= 0x0701) {
-		ctrl->cs_offsets = brcmnand_cs_offsets_v71;
-	} else {
-		ctrl->cs_offsets = brcmnand_cs_offsets;
-
-		/* v5.0 and earlier has a different CS0 offset layout */
-		if (ctrl->nand_version <= 0x0500)
-			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
-	}
-
-	/* Page / block sizes */
-	if (ctrl->nand_version >= 0x0701) {
-		/* >= v7.1 use nice power-of-2 values! */
-		ctrl->max_page_size = 16 * 1024;
-		ctrl->max_block_size = 2 * 1024 * 1024;
-	} else {
-		ctrl->page_sizes = page_sizes;
-		if (ctrl->nand_version >= 0x0600)
-			ctrl->block_sizes = block_sizes_v6;
-		else
-			ctrl->block_sizes = block_sizes_v4;
-
-		if (ctrl->nand_version < 0x0400) {
-			ctrl->max_page_size = 4096;
-			ctrl->max_block_size = 512 * 1024;
-		}
-	}
-
-	/* Maximum spare area sector size (per 512B) */
-	if (ctrl->nand_version >= 0x0702)
-		ctrl->max_oob = 128;
-	else if (ctrl->nand_version >= 0x0600)
-		ctrl->max_oob = 64;
-	else if (ctrl->nand_version >= 0x0500)
-		ctrl->max_oob = 32;
-	else
-		ctrl->max_oob = 16;
-
-	/* v6.0 and newer (except v6.1) have prefetch support */
-	if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
-		ctrl->features |= BRCMNAND_HAS_PREFETCH;
-
-	/*
-	 * v6.x has cache mode, but it's implemented differently. Ignore it for
-	 * now.
-	 */
-	if (ctrl->nand_version >= 0x0700)
-		ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
-
-	if (ctrl->nand_version >= 0x0500)
-		ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
-
-	if (ctrl->nand_version >= 0x0700)
-		ctrl->features |= BRCMNAND_HAS_WP;
-	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
-		ctrl->features |= BRCMNAND_HAS_WP;
-
-	return 0;
-}
-
-static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
-		enum brcmnand_reg reg)
-{
-	u16 offs = ctrl->reg_offsets[reg];
-
-	if (offs)
-		return nand_readreg(ctrl, offs);
-	else
-		return 0;
-}
-
-static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
-				      enum brcmnand_reg reg, u32 val)
-{
-	u16 offs = ctrl->reg_offsets[reg];
-
-	if (offs)
-		nand_writereg(ctrl, offs, val);
-}
-
-static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
-				    enum brcmnand_reg reg, u32 mask, unsigned
-				    int shift, u32 val)
-{
-	u32 tmp = brcmnand_read_reg(ctrl, reg);
-
-	tmp &= ~mask;
-	tmp |= val << shift;
-	brcmnand_write_reg(ctrl, reg, tmp);
-}
-
-static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
-{
-	return __raw_readl(ctrl->nand_fc + word * 4);
-}
-
-static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
-				     int word, u32 val)
-{
-	__raw_writel(val, ctrl->nand_fc + word * 4);
-}
-
-static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
-				     enum brcmnand_cs_reg reg)
-{
-	u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
-	u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
-	u8 cs_offs;
-
-	if (cs == 0 && ctrl->cs0_offsets)
-		cs_offs = ctrl->cs0_offsets[reg];
-	else
-		cs_offs = ctrl->cs_offsets[reg];
-
-	if (cs && offs_cs1)
-		return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
-
-	return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
-}
-
-static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
-{
-	if (ctrl->nand_version < 0x0600)
-		return 1;
-	return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
-}
-
-static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	unsigned int shift = 0, bits;
-	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
-	int cs = host->cs;
-
-	if (ctrl->nand_version >= 0x0702)
-		bits = 7;
-	else if (ctrl->nand_version >= 0x0600)
-		bits = 6;
-	else if (ctrl->nand_version >= 0x0500)
-		bits = 5;
-	else
-		bits = 4;
-
-	if (ctrl->nand_version >= 0x0702) {
-		if (cs >= 4)
-			reg = BRCMNAND_CORR_THRESHOLD_EXT;
-		shift = (cs % 4) * bits;
-	} else if (ctrl->nand_version >= 0x0600) {
-		if (cs >= 5)
-			reg = BRCMNAND_CORR_THRESHOLD_EXT;
-		shift = (cs % 5) * bits;
-	}
-	brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
-}
-
-static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
-{
-	if (ctrl->nand_version < 0x0602)
-		return 24;
-	return 0;
-}
-
-/***********************************************************************
- * NAND ACC CONTROL bitfield
- *
- * Some bits have remained constant throughout hardware revision, while
- * others have shifted around.
- ***********************************************************************/
-
-/* Constant for all versions (where supported) */
-enum {
-	/* See BRCMNAND_HAS_CACHE_MODE */
-	ACC_CONTROL_CACHE_MODE				= BIT(22),
-
-	/* See BRCMNAND_HAS_PREFETCH */
-	ACC_CONTROL_PREFETCH				= BIT(23),
-
-	ACC_CONTROL_PAGE_HIT				= BIT(24),
-	ACC_CONTROL_WR_PREEMPT				= BIT(25),
-	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
-	ACC_CONTROL_RD_ERASED				= BIT(27),
-	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
-	ACC_CONTROL_WR_ECC				= BIT(30),
-	ACC_CONTROL_RD_ECC				= BIT(31),
-};
-
-static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
-{
-	if (ctrl->nand_version >= 0x0702)
-		return GENMASK(7, 0);
-	else if (ctrl->nand_version >= 0x0600)
-		return GENMASK(6, 0);
-	else
-		return GENMASK(5, 0);
-}
-
-#define NAND_ACC_CONTROL_ECC_SHIFT	16
-#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
-
-static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
-{
-	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
-
-	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
-
-	/* v7.2 includes additional ECC levels */
-	if (ctrl->nand_version >= 0x0702)
-		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
-
-	return mask;
-}
-
-static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
-	u32 acc_control = nand_readreg(ctrl, offs);
-	u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
-
-	if (en) {
-		acc_control |= ecc_flags; /* enable RD/WR ECC */
-		acc_control |= host->hwcfg.ecc_level
-			       << NAND_ACC_CONTROL_ECC_SHIFT;
-	} else {
-		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
-		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
-	}
-
-	nand_writereg(ctrl, offs, acc_control);
-}
-
-static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
-{
-	if (ctrl->nand_version >= 0x0702)
-		return 9;
-	else if (ctrl->nand_version >= 0x0600)
-		return 7;
-	else if (ctrl->nand_version >= 0x0500)
-		return 6;
-	else
-		return -1;
-}
-
-static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	int shift = brcmnand_sector_1k_shift(ctrl);
-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-						  BRCMNAND_CS_ACC_CONTROL);
-
-	if (shift < 0)
-		return 0;
-
-	return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
-}
-
-static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	int shift = brcmnand_sector_1k_shift(ctrl);
-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-						  BRCMNAND_CS_ACC_CONTROL);
-	u32 tmp;
-
-	if (shift < 0)
-		return;
-
-	tmp = nand_readreg(ctrl, acc_control_offs);
-	tmp &= ~(1 << shift);
-	tmp |= (!!val) << shift;
-	nand_writereg(ctrl, acc_control_offs, tmp);
-}
-
-/***********************************************************************
- * CS_NAND_SELECT
- ***********************************************************************/
-
-enum {
-	CS_SELECT_NAND_WP			= BIT(29),
-	CS_SELECT_AUTO_DEVICE_ID_CFG		= BIT(30),
-};
-
-static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
-				    u32 mask, u32 expected_val,
-				    unsigned long timeout_ms)
-{
-	unsigned long limit;
-	u32 val;
-
-	if (!timeout_ms)
-		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
-
-	limit = jiffies + msecs_to_jiffies(timeout_ms);
-	do {
-		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
-		if ((val & mask) == expected_val)
-			return 0;
-
-		cpu_relax();
-	} while (time_after(limit, jiffies));
-
-	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
-		 expected_val, val & mask);
-
-	return -ETIMEDOUT;
-}
-
-static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
-{
-	u32 val = en ? CS_SELECT_NAND_WP : 0;
-
-	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
-}
-
-/***********************************************************************
- * Flash DMA
- ***********************************************************************/
-
-enum flash_dma_reg {
-	FLASH_DMA_REVISION		= 0x00,
-	FLASH_DMA_FIRST_DESC		= 0x04,
-	FLASH_DMA_FIRST_DESC_EXT	= 0x08,
-	FLASH_DMA_CTRL			= 0x0c,
-	FLASH_DMA_MODE			= 0x10,
-	FLASH_DMA_STATUS		= 0x14,
-	FLASH_DMA_INTERRUPT_DESC	= 0x18,
-	FLASH_DMA_INTERRUPT_DESC_EXT	= 0x1c,
-	FLASH_DMA_ERROR_STATUS		= 0x20,
-	FLASH_DMA_CURRENT_DESC		= 0x24,
-	FLASH_DMA_CURRENT_DESC_EXT	= 0x28,
-};
-
-static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
-{
-	return ctrl->flash_dma_base;
-}
-
-static inline bool flash_dma_buf_ok(const void *buf)
-{
-	return buf && !is_vmalloc_addr(buf) &&
-		likely(IS_ALIGNED((uintptr_t)buf, 4));
-}
-
-static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
-				    u32 val)
-{
-	brcmnand_writel(val, ctrl->flash_dma_base + offs);
-}
-
-static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
-{
-	return brcmnand_readl(ctrl->flash_dma_base + offs);
-}
-
-/* Low-level operation types: command, address, write, or read */
-enum brcmnand_llop_type {
-	LL_OP_CMD,
-	LL_OP_ADDR,
-	LL_OP_WR,
-	LL_OP_RD,
-};
-
-/***********************************************************************
- * Internal support functions
- ***********************************************************************/
-
-static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
-				  struct brcmnand_cfg *cfg)
-{
-	if (ctrl->nand_version <= 0x0701)
-		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
-			cfg->ecc_level == 15;
-	else
-		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
-			cfg->ecc_level == 15) ||
-			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
-}
-
-/*
- * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
- * the layout/configuration.
- * Returns -ERRCODE on failure.
- */
-static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
-					  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_cfg *cfg = &host->hwcfg;
-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-
-	if (section >= sectors)
-		return -ERANGE;
-
-	oobregion->offset = (section * sas) + 6;
-	oobregion->length = 3;
-
-	return 0;
-}
-
-static int brcmnand_hamming_ooblayout_free(struct mtd_info *mtd, int section,
-					   struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_cfg *cfg = &host->hwcfg;
-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-
-	if (section >= sectors * 2)
-		return -ERANGE;
-
-	oobregion->offset = (section / 2) * sas;
-
-	if (section & 1) {
-		oobregion->offset += 9;
-		oobregion->length = 7;
-	} else {
-		oobregion->length = 6;
-
-		/* First sector of each page may have BBI */
-		if (!section) {
-			/*
-			 * Small-page NAND use byte 6 for BBI while large-page
-			 * NAND use byte 0.
-			 */
-			if (cfg->page_size > 512)
-				oobregion->offset++;
-			oobregion->length--;
-		}
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
-	.ecc = brcmnand_hamming_ooblayout_ecc,
-	.free = brcmnand_hamming_ooblayout_free,
-};
-
-static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
-				      struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_cfg *cfg = &host->hwcfg;
-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-
-	if (section >= sectors)
-		return -ERANGE;
-
-	oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
-	oobregion->length = chip->ecc.bytes;
-
-	return 0;
-}
-
-static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
-					  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_cfg *cfg = &host->hwcfg;
-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
-
-	if (section >= sectors)
-		return -ERANGE;
-
-	if (sas <= chip->ecc.bytes)
-		return 0;
-
-	oobregion->offset = section * sas;
-	oobregion->length = sas - chip->ecc.bytes;
-
-	if (!section) {
-		oobregion->offset++;
-		oobregion->length--;
-	}
-
-	return 0;
-}
-
-static int brcmnand_bch_ooblayout_free_sp(struct mtd_info *mtd, int section,
-					  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_cfg *cfg = &host->hwcfg;
-	int sas = cfg->spare_area_size << cfg->sector_size_1k;
-
-	if (section > 1 || sas - chip->ecc.bytes < 6 ||
-	    (section && sas - chip->ecc.bytes == 6))
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->offset = 0;
-		oobregion->length = 5;
-	} else {
-		oobregion->offset = 6;
-		oobregion->length = sas - chip->ecc.bytes - 6;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
-	.ecc = brcmnand_bch_ooblayout_ecc,
-	.free = brcmnand_bch_ooblayout_free_lp,
-};
-
-static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
-	.ecc = brcmnand_bch_ooblayout_ecc,
-	.free = brcmnand_bch_ooblayout_free_sp,
-};
-
-static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
-{
-	struct brcmnand_cfg *p = &host->hwcfg;
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-	struct nand_ecc_ctrl *ecc = &host->chip.ecc;
-	unsigned int ecc_level = p->ecc_level;
-	int sas = p->spare_area_size << p->sector_size_1k;
-	int sectors = p->page_size / (512 << p->sector_size_1k);
-
-	if (p->sector_size_1k)
-		ecc_level <<= 1;
-
-	if (is_hamming_ecc(host->ctrl, p)) {
-		ecc->bytes = 3 * sectors;
-		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
-		return 0;
-	}
-
-	/*
-	 * CONTROLLER_VERSION:
-	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
-	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
-	 * But we will just be conservative.
-	 */
-	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
-	if (p->page_size == 512)
-		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
-	else
-		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
-
-	if (ecc->bytes >= sas) {
-		dev_err(&host->pdev->dev,
-			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
-			ecc->bytes, sas);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void brcmnand_wp(struct mtd_info *mtd, int wp)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-
-	if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
-		static int old_wp = -1;
-		int ret;
-
-		if (old_wp != wp) {
-			dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
-			old_wp = wp;
-		}
-
-		/*
-		 * make sure ctrl/flash ready before and after
-		 * changing state of #WP pin
-		 */
-		ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
-					       NAND_STATUS_READY,
-					       NAND_CTRL_RDY |
-					       NAND_STATUS_READY, 0);
-		if (ret)
-			return;
-
-		brcmnand_set_wp(ctrl, wp);
-		nand_status_op(chip, NULL);
-		/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
-		ret = bcmnand_ctrl_poll_status(ctrl,
-					       NAND_CTRL_RDY |
-					       NAND_STATUS_READY |
-					       NAND_STATUS_WP,
-					       NAND_CTRL_RDY |
-					       NAND_STATUS_READY |
-					       (wp ? 0 : NAND_STATUS_WP), 0);
-
-		if (ret)
-			dev_err_ratelimited(&host->pdev->dev,
-					    "nand #WP expected %s\n",
-					    wp ? "on" : "off");
-	}
-}
-
-/* Helper functions for reading and writing OOB registers */
-static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
-{
-	u16 offset0, offset10, reg_offs;
-
-	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
-	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
-
-	if (offs >= ctrl->max_oob)
-		return 0x77;
-
-	if (offs >= 16 && offset10)
-		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
-	else
-		reg_offs = offset0 + (offs & ~0x03);
-
-	return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
-}
-
-static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
-				 u32 data)
-{
-	u16 offset0, offset10, reg_offs;
-
-	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
-	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
-
-	if (offs >= ctrl->max_oob)
-		return;
-
-	if (offs >= 16 && offset10)
-		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
-	else
-		reg_offs = offset0 + (offs & ~0x03);
-
-	nand_writereg(ctrl, reg_offs, data);
-}
-
-/*
- * read_oob_from_regs - read data from OOB registers
- * @ctrl: NAND controller
- * @i: sub-page sector index
- * @oob: buffer to read to
- * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
- * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
- */
-static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
-			      int sas, int sector_1k)
-{
-	int tbytes = sas << sector_1k;
-	int j;
-
-	/* Adjust OOB values for 1K sector size */
-	if (sector_1k && (i & 0x01))
-		tbytes = max(0, tbytes - (int)ctrl->max_oob);
-	tbytes = min_t(int, tbytes, ctrl->max_oob);
-
-	for (j = 0; j < tbytes; j++)
-		oob[j] = oob_reg_read(ctrl, j);
-	return tbytes;
-}
-
-/*
- * write_oob_to_regs - write data to OOB registers
- * @i: sub-page sector index
- * @oob: buffer to write from
- * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
- * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
- */
-static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
-			     const u8 *oob, int sas, int sector_1k)
-{
-	int tbytes = sas << sector_1k;
-	int j;
-
-	/* Adjust OOB values for 1K sector size */
-	if (sector_1k && (i & 0x01))
-		tbytes = max(0, tbytes - (int)ctrl->max_oob);
-	tbytes = min_t(int, tbytes, ctrl->max_oob);
-
-	for (j = 0; j < tbytes; j += 4)
-		oob_reg_write(ctrl, j,
-				(oob[j + 0] << 24) |
-				(oob[j + 1] << 16) |
-				(oob[j + 2] <<  8) |
-				(oob[j + 3] <<  0));
-	return tbytes;
-}
-
-static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
-{
-	struct brcmnand_controller *ctrl = data;
-
-	/* Discard all NAND_CTLRDY interrupts during DMA */
-	if (ctrl->dma_pending)
-		return IRQ_HANDLED;
-
-	complete(&ctrl->done);
-	return IRQ_HANDLED;
-}
-
-/* Handle SoC-specific interrupt hardware */
-static irqreturn_t brcmnand_irq(int irq, void *data)
-{
-	struct brcmnand_controller *ctrl = data;
-
-	if (ctrl->soc->ctlrdy_ack(ctrl->soc))
-		return brcmnand_ctlrdy_irq(irq, data);
-
-	return IRQ_NONE;
-}
-
-static irqreturn_t brcmnand_dma_irq(int irq, void *data)
-{
-	struct brcmnand_controller *ctrl = data;
-
-	complete(&ctrl->dma_done);
-
-	return IRQ_HANDLED;
-}
-
-static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	int ret;
-
-	dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
-		brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
-	BUG_ON(ctrl->cmd_pending != 0);
-	ctrl->cmd_pending = cmd;
-
-	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
-	WARN_ON(ret);
-
-	mb(); /* flush previous writes */
-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
-			   cmd << brcmnand_cmd_shift(ctrl));
-}
-
-/***********************************************************************
- * NAND MTD API: read/program/erase
- ***********************************************************************/
-
-static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
-	unsigned int ctrl)
-{
-	/* intentionally left blank */
-}
-
-static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-	unsigned long timeo = msecs_to_jiffies(100);
-
-	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
-	if (ctrl->cmd_pending &&
-			wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
-		u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
-					>> brcmnand_cmd_shift(ctrl);
-
-		dev_err_ratelimited(ctrl->dev,
-			"timeout waiting for command %#02x\n", cmd);
-		dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
-			brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
-	}
-	ctrl->cmd_pending = 0;
-	return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
-				 INTFC_FLASH_STATUS;
-}
-
-enum {
-	LLOP_RE				= BIT(16),
-	LLOP_WE				= BIT(17),
-	LLOP_ALE			= BIT(18),
-	LLOP_CLE			= BIT(19),
-	LLOP_RETURN_IDLE		= BIT(31),
-
-	LLOP_DATA_MASK			= GENMASK(15, 0),
-};
-
-static int brcmnand_low_level_op(struct brcmnand_host *host,
-				 enum brcmnand_llop_type type, u32 data,
-				 bool last_op)
-{
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-	struct nand_chip *chip = &host->chip;
-	struct brcmnand_controller *ctrl = host->ctrl;
-	u32 tmp;
-
-	tmp = data & LLOP_DATA_MASK;
-	switch (type) {
-	case LL_OP_CMD:
-		tmp |= LLOP_WE | LLOP_CLE;
-		break;
-	case LL_OP_ADDR:
-		/* WE | ALE */
-		tmp |= LLOP_WE | LLOP_ALE;
-		break;
-	case LL_OP_WR:
-		/* WE */
-		tmp |= LLOP_WE;
-		break;
-	case LL_OP_RD:
-		/* RE */
-		tmp |= LLOP_RE;
-		break;
-	}
-	if (last_op)
-		/* RETURN_IDLE */
-		tmp |= LLOP_RETURN_IDLE;
-
-	dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
-
-	brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
-	(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
-
-	brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
-	return brcmnand_waitfunc(mtd, chip);
-}
-
-static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
-			     int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-	u64 addr = (u64)page_addr << chip->page_shift;
-	int native_cmd = 0;
-
-	if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
-			command == NAND_CMD_RNDOUT)
-		addr = (u64)column;
-	/* Avoid propagating a negative, don't-care address */
-	else if (page_addr < 0)
-		addr = 0;
-
-	dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
-		(unsigned long long)addr);
-
-	host->last_cmd = command;
-	host->last_byte = 0;
-	host->last_addr = addr;
-
-	switch (command) {
-	case NAND_CMD_RESET:
-		native_cmd = CMD_FLASH_RESET;
-		break;
-	case NAND_CMD_STATUS:
-		native_cmd = CMD_STATUS_READ;
-		break;
-	case NAND_CMD_READID:
-		native_cmd = CMD_DEVICE_ID_READ;
-		break;
-	case NAND_CMD_READOOB:
-		native_cmd = CMD_SPARE_AREA_READ;
-		break;
-	case NAND_CMD_ERASE1:
-		native_cmd = CMD_BLOCK_ERASE;
-		brcmnand_wp(mtd, 0);
-		break;
-	case NAND_CMD_PARAM:
-		native_cmd = CMD_PARAMETER_READ;
-		break;
-	case NAND_CMD_SET_FEATURES:
-	case NAND_CMD_GET_FEATURES:
-		brcmnand_low_level_op(host, LL_OP_CMD, command, false);
-		brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
-		break;
-	case NAND_CMD_RNDOUT:
-		native_cmd = CMD_PARAMETER_CHANGE_COL;
-		addr &= ~((u64)(FC_BYTES - 1));
-		/*
-		 * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
-		 * NB: hwcfg.sector_size_1k may not be initialized yet
-		 */
-		if (brcmnand_get_sector_size_1k(host)) {
-			host->hwcfg.sector_size_1k =
-				brcmnand_get_sector_size_1k(host);
-			brcmnand_set_sector_size_1k(host, 0);
-		}
-		break;
-	}
-
-	if (!native_cmd)
-		return;
-
-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-		(host->cs << 16) | ((addr >> 32) & 0xffff));
-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-
-	brcmnand_send_cmd(host, native_cmd);
-	brcmnand_waitfunc(mtd, chip);
-
-	if (native_cmd == CMD_PARAMETER_READ ||
-			native_cmd == CMD_PARAMETER_CHANGE_COL) {
-		/* Copy flash cache word-wise */
-		u32 *flash_cache = (u32 *)ctrl->flash_cache;
-		int i;
-
-		brcmnand_soc_data_bus_prepare(ctrl->soc, true);
-
-		/*
-		 * Must cache the FLASH_CACHE now, since changes in
-		 * SECTOR_SIZE_1K may invalidate it
-		 */
-		for (i = 0; i < FC_WORDS; i++)
-			/*
-			 * Flash cache is big endian for parameter pages, at
-			 * least on STB SoCs
-			 */
-			flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
-
-		brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
-
-		/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
-		if (host->hwcfg.sector_size_1k)
-			brcmnand_set_sector_size_1k(host,
-						    host->hwcfg.sector_size_1k);
-	}
-
-	/* Re-enable protection is necessary only after erase */
-	if (command == NAND_CMD_ERASE1)
-		brcmnand_wp(mtd, 1);
-}
-
-static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-	uint8_t ret = 0;
-	int addr, offs;
-
-	switch (host->last_cmd) {
-	case NAND_CMD_READID:
-		if (host->last_byte < 4)
-			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
-				(24 - (host->last_byte << 3));
-		else if (host->last_byte < 8)
-			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
-				(56 - (host->last_byte << 3));
-		break;
-
-	case NAND_CMD_READOOB:
-		ret = oob_reg_read(ctrl, host->last_byte);
-		break;
-
-	case NAND_CMD_STATUS:
-		ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
-					INTFC_FLASH_STATUS;
-		if (wp_on) /* hide WP status */
-			ret |= NAND_STATUS_WP;
-		break;
-
-	case NAND_CMD_PARAM:
-	case NAND_CMD_RNDOUT:
-		addr = host->last_addr + host->last_byte;
-		offs = addr & (FC_BYTES - 1);
-
-		/* At FC_BYTES boundary, switch to next column */
-		if (host->last_byte > 0 && offs == 0)
-			nand_change_read_column_op(chip, addr, NULL, 0, false);
-
-		ret = ctrl->flash_cache[offs];
-		break;
-	case NAND_CMD_GET_FEATURES:
-		if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
-			ret = 0;
-		} else {
-			bool last = host->last_byte ==
-				ONFI_SUBFEATURE_PARAM_LEN - 1;
-			brcmnand_low_level_op(host, LL_OP_RD, 0, last);
-			ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
-		}
-	}
-
-	dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
-	host->last_byte++;
-
-	return ret;
-}
-
-static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++, buf++)
-		*buf = brcmnand_read_byte(mtd);
-}
-
-static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-				   int len)
-{
-	int i;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-
-	switch (host->last_cmd) {
-	case NAND_CMD_SET_FEATURES:
-		for (i = 0; i < len; i++)
-			brcmnand_low_level_op(host, LL_OP_WR, buf[i],
-						  (i + 1) == len);
-		break;
-	default:
-		BUG();
-		break;
-	}
-}
-
-/**
- * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
- * following ahead of time:
- *  - Is this descriptor the beginning or end of a linked list?
- *  - What is the (DMA) address of the next descriptor in the linked list?
- */
-static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
-				  struct brcm_nand_dma_desc *desc, u64 addr,
-				  dma_addr_t buf, u32 len, u8 dma_cmd,
-				  bool begin, bool end,
-				  dma_addr_t next_desc)
-{
-	memset(desc, 0, sizeof(*desc));
-	/* Descriptors are written in native byte order (wordwise) */
-	desc->next_desc = lower_32_bits(next_desc);
-	desc->next_desc_ext = upper_32_bits(next_desc);
-	desc->cmd_irq = (dma_cmd << 24) |
-		(end ? (0x03 << 8) : 0) | /* IRQ | STOP */
-		(!!begin) | ((!!end) << 1); /* head, tail */
-#ifdef CONFIG_CPU_BIG_ENDIAN
-	desc->cmd_irq |= 0x01 << 12;
-#endif
-	desc->dram_addr = lower_32_bits(buf);
-	desc->dram_addr_ext = upper_32_bits(buf);
-	desc->tfr_len = len;
-	desc->total_len = len;
-	desc->flash_addr = lower_32_bits(addr);
-	desc->flash_addr_ext = upper_32_bits(addr);
-	desc->cs = host->cs;
-	desc->status_valid = 0x01;
-	return 0;
-}
-
-/**
- * Kick the FLASH_DMA engine, with a given DMA descriptor
- */
-static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	unsigned long timeo = msecs_to_jiffies(100);
-
-	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
-	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
-	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
-	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
-
-	/* Start FLASH_DMA engine */
-	ctrl->dma_pending = true;
-	mb(); /* flush previous writes */
-	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
-
-	if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
-		dev_err(ctrl->dev,
-				"timeout waiting for DMA; status %#x, error status %#x\n",
-				flash_dma_readl(ctrl, FLASH_DMA_STATUS),
-				flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
-	}
-	ctrl->dma_pending = false;
-	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
-}
-
-static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
-			      u32 len, u8 dma_cmd)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	dma_addr_t buf_pa;
-	int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
-	buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
-	if (dma_mapping_error(ctrl->dev, buf_pa)) {
-		dev_err(ctrl->dev, "unable to map buffer for DMA\n");
-		return -ENOMEM;
-	}
-
-	brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
-				   dma_cmd, true, true, 0);
-
-	brcmnand_dma_run(host, ctrl->dma_pa);
-
-	dma_unmap_single(ctrl->dev, buf_pa, len, dir);
-
-	if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
-		return -EBADMSG;
-	else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
-		return -EUCLEAN;
-
-	return 0;
-}
-
-/*
- * Assumes proper CS is already set
- */
-static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
-				u64 addr, unsigned int trans, u32 *buf,
-				u8 *oob, u64 *err_addr)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-	int i, j, ret = 0;
-
-	/* Clear error addresses */
-	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
-	brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
-	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
-	brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
-
-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-			(host->cs << 16) | ((addr >> 32) & 0xffff));
-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-
-	for (i = 0; i < trans; i++, addr += FC_BYTES) {
-		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
-				   lower_32_bits(addr));
-		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
-		brcmnand_send_cmd(host, CMD_PAGE_READ);
-		brcmnand_waitfunc(mtd, chip);
-
-		if (likely(buf)) {
-			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
-
-			for (j = 0; j < FC_WORDS; j++, buf++)
-				*buf = brcmnand_read_fc(ctrl, j);
-
-			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
-		}
-
-		if (oob)
-			oob += read_oob_from_regs(ctrl, i, oob,
-					mtd->oobsize / trans,
-					host->hwcfg.sector_size_1k);
-
-		if (!ret) {
-			*err_addr = brcmnand_read_reg(ctrl,
-					BRCMNAND_UNCORR_ADDR) |
-				((u64)(brcmnand_read_reg(ctrl,
-						BRCMNAND_UNCORR_EXT_ADDR)
-					& 0xffff) << 32);
-			if (*err_addr)
-				ret = -EBADMSG;
-		}
-
-		if (!ret) {
-			*err_addr = brcmnand_read_reg(ctrl,
-					BRCMNAND_CORR_ADDR) |
-				((u64)(brcmnand_read_reg(ctrl,
-						BRCMNAND_CORR_EXT_ADDR)
-					& 0xffff) << 32);
-			if (*err_addr)
-				ret = -EUCLEAN;
-		}
-	}
-
-	return ret;
-}
-
-/*
- * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
- * error
- *
- * Because the HW ECC signals an ECC error if an erase paged has even a single
- * bitflip, we must check each ECC error to see if it is actually an erased
- * page with bitflips, not a truly corrupted page.
- *
- * On a real error, return a negative error code (-EBADMSG for ECC error), and
- * buf will contain raw data.
- * Otherwise, buf gets filled with 0xffs and return the maximum number of
- * bitflips-per-ECC-sector to the caller.
- *
- */
-static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
-		  struct nand_chip *chip, void *buf, u64 addr)
-{
-	int i, sas;
-	void *oob = chip->oob_poi;
-	int bitflips = 0;
-	int page = addr >> chip->page_shift;
-	int ret;
-
-	if (!buf) {
-		buf = chip->data_buf;
-		/* Invalidate page cache */
-		chip->pagebuf = -1;
-	}
-
-	sas = mtd->oobsize / chip->ecc.steps;
-
-	/* read without ecc for verification */
-	ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
-		ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
-						  oob, sas, NULL, 0,
-						  chip->ecc.strength);
-		if (ret < 0)
-			return ret;
-
-		bitflips = max(bitflips, ret);
-	}
-
-	return bitflips;
-}
-
-static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
-			 u64 addr, unsigned int trans, u32 *buf, u8 *oob)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-	u64 err_addr = 0;
-	int err;
-	bool retry = true;
-
-	dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
-
-try_dmaread:
-	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
-
-	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
-		err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
-					     CMD_PAGE_READ);
-		if (err) {
-			if (mtd_is_bitflip_or_eccerr(err))
-				err_addr = addr;
-			else
-				return -EIO;
-		}
-	} else {
-		if (oob)
-			memset(oob, 0x99, mtd->oobsize);
-
-		err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
-					       oob, &err_addr);
-	}
-
-	if (mtd_is_eccerr(err)) {
-		/*
-		 * On controller version and 7.0, 7.1 , DMA read after a
-		 * prior PIO read that reported uncorrectable error,
-		 * the DMA engine captures this error following DMA read
-		 * cleared only on subsequent DMA read, so just retry once
-		 * to clear a possible false error reported for current DMA
-		 * read
-		 */
-		if ((ctrl->nand_version == 0x0700) ||
-		    (ctrl->nand_version == 0x0701)) {
-			if (retry) {
-				retry = false;
-				goto try_dmaread;
-			}
-		}
-
-		/*
-		 * Controller version 7.2 has hw encoder to detect erased page
-		 * bitflips, apply sw verification for older controllers only
-		 */
-		if (ctrl->nand_version < 0x0702) {
-			err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
-							      addr);
-			/* erased page bitflips corrected */
-			if (err >= 0)
-				return err;
-		}
-
-		dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
-			(unsigned long long)err_addr);
-		mtd->ecc_stats.failed++;
-		/* NAND layer expects zero on ECC errors */
-		return 0;
-	}
-
-	if (mtd_is_bitflip(err)) {
-		unsigned int corrected = brcmnand_count_corrected(ctrl);
-
-		dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
-			(unsigned long long)err_addr);
-		mtd->ecc_stats.corrected += corrected;
-		/* Always exceed the software-imposed threshold */
-		return max(mtd->bitflip_threshold, corrected);
-	}
-
-	return 0;
-}
-
-static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			      uint8_t *buf, int oob_required, int page)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	return brcmnand_read(mtd, chip, host->last_addr,
-			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
-}
-
-static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				  uint8_t *buf, int oob_required, int page)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
-	int ret;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	brcmnand_set_ecc_enabled(host, 0);
-	ret = brcmnand_read(mtd, chip, host->last_addr,
-			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
-	brcmnand_set_ecc_enabled(host, 1);
-	return ret;
-}
-
-static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			     int page)
-{
-	return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
-			mtd->writesize >> FC_SHIFT,
-			NULL, (u8 *)chip->oob_poi);
-}
-
-static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				 int page)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-
-	brcmnand_set_ecc_enabled(host, 0);
-	brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
-		mtd->writesize >> FC_SHIFT,
-		NULL, (u8 *)chip->oob_poi);
-	brcmnand_set_ecc_enabled(host, 1);
-	return 0;
-}
-
-static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
-			  u64 addr, const u32 *buf, u8 *oob)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	struct brcmnand_controller *ctrl = host->ctrl;
-	unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
-	int status, ret = 0;
-
-	dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
-
-	if (unlikely((unsigned long)buf & 0x03)) {
-		dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
-		buf = (u32 *)((unsigned long)buf & ~0x03);
-	}
-
-	brcmnand_wp(mtd, 0);
-
-	for (i = 0; i < ctrl->max_oob; i += 4)
-		oob_reg_write(ctrl, i, 0xffffffff);
-
-	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
-		if (brcmnand_dma_trans(host, addr, (u32 *)buf,
-					mtd->writesize, CMD_PROGRAM_PAGE))
-			ret = -EIO;
-		goto out;
-	}
-
-	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
-			(host->cs << 16) | ((addr >> 32) & 0xffff));
-	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
-
-	for (i = 0; i < trans; i++, addr += FC_BYTES) {
-		/* full address MUST be set before populating FC */
-		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
-				   lower_32_bits(addr));
-		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
-
-		if (buf) {
-			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
-
-			for (j = 0; j < FC_WORDS; j++, buf++)
-				brcmnand_write_fc(ctrl, j, *buf);
-
-			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
-		} else if (oob) {
-			for (j = 0; j < FC_WORDS; j++)
-				brcmnand_write_fc(ctrl, j, 0xffffffff);
-		}
-
-		if (oob) {
-			oob += write_oob_to_regs(ctrl, i, oob,
-					mtd->oobsize / trans,
-					host->hwcfg.sector_size_1k);
-		}
-
-		/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
-		brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
-		status = brcmnand_waitfunc(mtd, chip);
-
-		if (status & NAND_STATUS_FAIL) {
-			dev_info(ctrl->dev, "program failed at %llx\n",
-				(unsigned long long)addr);
-			ret = -EIO;
-			goto out;
-		}
-	}
-out:
-	brcmnand_wp(mtd, 1);
-	return ret;
-}
-
-static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-			       const uint8_t *buf, int oob_required, int page)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	void *oob = oob_required ? chip->oob_poi : NULL;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int brcmnand_write_page_raw(struct mtd_info *mtd,
-				   struct nand_chip *chip, const uint8_t *buf,
-				   int oob_required, int page)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	void *oob = oob_required ? chip->oob_poi : NULL;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	brcmnand_set_ecc_enabled(host, 0);
-	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
-	brcmnand_set_ecc_enabled(host, 1);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-				  int page)
-{
-	return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
-				  NULL, chip->oob_poi);
-}
-
-static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				  int page)
-{
-	struct brcmnand_host *host = nand_get_controller_data(chip);
-	int ret;
-
-	brcmnand_set_ecc_enabled(host, 0);
-	ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
-				 (u8 *)chip->oob_poi);
-	brcmnand_set_ecc_enabled(host, 1);
-
-	return ret;
-}
-
-/***********************************************************************
- * Per-CS setup (1 NAND device)
- ***********************************************************************/
-
-static int brcmnand_set_cfg(struct brcmnand_host *host,
-			    struct brcmnand_cfg *cfg)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	struct nand_chip *chip = &host->chip;
-	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
-	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
-			BRCMNAND_CS_CFG_EXT);
-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-			BRCMNAND_CS_ACC_CONTROL);
-	u8 block_size = 0, page_size = 0, device_size = 0;
-	u32 tmp;
-
-	if (ctrl->block_sizes) {
-		int i, found;
-
-		for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
-			if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
-				block_size = i;
-				found = 1;
-			}
-		if (!found) {
-			dev_warn(ctrl->dev, "invalid block size %u\n",
-					cfg->block_size);
-			return -EINVAL;
-		}
-	} else {
-		block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
-	}
-
-	if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
-				cfg->block_size > ctrl->max_block_size)) {
-		dev_warn(ctrl->dev, "invalid block size %u\n",
-				cfg->block_size);
-		block_size = 0;
-	}
-
-	if (ctrl->page_sizes) {
-		int i, found;
-
-		for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
-			if (ctrl->page_sizes[i] == cfg->page_size) {
-				page_size = i;
-				found = 1;
-			}
-		if (!found) {
-			dev_warn(ctrl->dev, "invalid page size %u\n",
-					cfg->page_size);
-			return -EINVAL;
-		}
-	} else {
-		page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
-	}
-
-	if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
-				cfg->page_size > ctrl->max_page_size)) {
-		dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
-		return -EINVAL;
-	}
-
-	if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
-		dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
-			(unsigned long long)cfg->device_size);
-		return -EINVAL;
-	}
-	device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
-
-	tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
-		(cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
-		(cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
-		(!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
-		(device_size << CFG_DEVICE_SIZE_SHIFT);
-	if (cfg_offs == cfg_ext_offs) {
-		tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
-		       (block_size << CFG_BLK_SIZE_SHIFT);
-		nand_writereg(ctrl, cfg_offs, tmp);
-	} else {
-		nand_writereg(ctrl, cfg_offs, tmp);
-		tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
-		      (block_size << CFG_EXT_BLK_SIZE_SHIFT);
-		nand_writereg(ctrl, cfg_ext_offs, tmp);
-	}
-
-	tmp = nand_readreg(ctrl, acc_control_offs);
-	tmp &= ~brcmnand_ecc_level_mask(ctrl);
-	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
-	tmp &= ~brcmnand_spare_area_mask(ctrl);
-	tmp |= cfg->spare_area_size;
-	nand_writereg(ctrl, acc_control_offs, tmp);
-
-	brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
-
-	/* threshold = ceil(BCH-level * 0.75) */
-	brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
-
-	return 0;
-}
-
-static void brcmnand_print_cfg(struct brcmnand_host *host,
-			       char *buf, struct brcmnand_cfg *cfg)
-{
-	buf += sprintf(buf,
-		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
-		(unsigned long long)cfg->device_size >> 20,
-		cfg->block_size >> 10,
-		cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
-		cfg->page_size >= 1024 ? "KiB" : "B",
-		cfg->spare_area_size, cfg->device_width);
-
-	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
-	if (is_hamming_ecc(host->ctrl, cfg))
-		sprintf(buf, ", Hamming ECC");
-	else if (cfg->sector_size_1k)
-		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
-	else
-		sprintf(buf, ", BCH-%u", cfg->ecc_level);
-}
-
-/*
- * Minimum number of bytes to address a page. Calculated as:
- *     roundup(log2(size / page-size) / 8)
- *
- * NB: the following does not "round up" for non-power-of-2 'size'; but this is
- *     OK because many other things will break if 'size' is irregular...
- */
-static inline int get_blk_adr_bytes(u64 size, u32 writesize)
-{
-	return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
-}
-
-static int brcmnand_setup_dev(struct brcmnand_host *host)
-{
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-	struct nand_chip *chip = &host->chip;
-	struct brcmnand_controller *ctrl = host->ctrl;
-	struct brcmnand_cfg *cfg = &host->hwcfg;
-	char msg[128];
-	u32 offs, tmp, oob_sector;
-	int ret;
-
-	memset(cfg, 0, sizeof(*cfg));
-
-	ret = of_property_read_u32(nand_get_flash_node(chip),
-				   "brcm,nand-oob-sector-size",
-				   &oob_sector);
-	if (ret) {
-		/* Use detected size */
-		cfg->spare_area_size = mtd->oobsize /
-					(mtd->writesize >> FC_SHIFT);
-	} else {
-		cfg->spare_area_size = oob_sector;
-	}
-	if (cfg->spare_area_size > ctrl->max_oob)
-		cfg->spare_area_size = ctrl->max_oob;
-	/*
-	 * Set oobsize to be consistent with controller's spare_area_size, as
-	 * the rest is inaccessible.
-	 */
-	mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
-
-	cfg->device_size = mtd->size;
-	cfg->block_size = mtd->erasesize;
-	cfg->page_size = mtd->writesize;
-	cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
-	cfg->col_adr_bytes = 2;
-	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
-
-	if (chip->ecc.mode != NAND_ECC_HW) {
-		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
-			chip->ecc.mode);
-		return -EINVAL;
-	}
-
-	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
-		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
-			/* Default to Hamming for 1-bit ECC, if unspecified */
-			chip->ecc.algo = NAND_ECC_HAMMING;
-		else
-			/* Otherwise, BCH */
-			chip->ecc.algo = NAND_ECC_BCH;
-	}
-
-	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
-						   chip->ecc.size != 512)) {
-		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
-			chip->ecc.strength, chip->ecc.size);
-		return -EINVAL;
-	}
-
-	switch (chip->ecc.size) {
-	case 512:
-		if (chip->ecc.algo == NAND_ECC_HAMMING)
-			cfg->ecc_level = 15;
-		else
-			cfg->ecc_level = chip->ecc.strength;
-		cfg->sector_size_1k = 0;
-		break;
-	case 1024:
-		if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
-			dev_err(ctrl->dev, "1KB sectors not supported\n");
-			return -EINVAL;
-		}
-		if (chip->ecc.strength & 0x1) {
-			dev_err(ctrl->dev,
-				"odd ECC not supported with 1KB sectors\n");
-			return -EINVAL;
-		}
-
-		cfg->ecc_level = chip->ecc.strength >> 1;
-		cfg->sector_size_1k = 1;
-		break;
-	default:
-		dev_err(ctrl->dev, "unsupported ECC size: %d\n",
-			chip->ecc.size);
-		return -EINVAL;
-	}
-
-	cfg->ful_adr_bytes = cfg->blk_adr_bytes;
-	if (mtd->writesize > 512)
-		cfg->ful_adr_bytes += cfg->col_adr_bytes;
-	else
-		cfg->ful_adr_bytes += 1;
-
-	ret = brcmnand_set_cfg(host, cfg);
-	if (ret)
-		return ret;
-
-	brcmnand_set_ecc_enabled(host, 1);
-
-	brcmnand_print_cfg(host, msg, cfg);
-	dev_info(ctrl->dev, "detected %s\n", msg);
-
-	/* Configure ACC_CONTROL */
-	offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
-	tmp = nand_readreg(ctrl, offs);
-	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
-	tmp &= ~ACC_CONTROL_RD_ERASED;
-
-	/* We need to turn on Read from erased paged protected by ECC */
-	if (ctrl->nand_version >= 0x0702)
-		tmp |= ACC_CONTROL_RD_ERASED;
-	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
-	if (ctrl->features & BRCMNAND_HAS_PREFETCH)
-		tmp &= ~ACC_CONTROL_PREFETCH;
-
-	nand_writereg(ctrl, offs, tmp);
-
-	return 0;
-}
-
-static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	struct platform_device *pdev = host->pdev;
-	struct mtd_info *mtd;
-	struct nand_chip *chip;
-	int ret;
-	u16 cfg_offs;
-
-	ret = of_property_read_u32(dn, "reg", &host->cs);
-	if (ret) {
-		dev_err(&pdev->dev, "can't get chip-select\n");
-		return -ENXIO;
-	}
-
-	mtd = nand_to_mtd(&host->chip);
-	chip = &host->chip;
-
-	nand_set_flash_node(chip, dn);
-	nand_set_controller_data(chip, host);
-	mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
-				   host->cs);
-	if (!mtd->name)
-		return -ENOMEM;
-
-	mtd->owner = THIS_MODULE;
-	mtd->dev.parent = &pdev->dev;
-
-	chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
-	chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
-
-	chip->cmd_ctrl = brcmnand_cmd_ctrl;
-	chip->cmdfunc = brcmnand_cmdfunc;
-	chip->waitfunc = brcmnand_waitfunc;
-	chip->read_byte = brcmnand_read_byte;
-	chip->read_buf = brcmnand_read_buf;
-	chip->write_buf = brcmnand_write_buf;
-
-	chip->ecc.mode = NAND_ECC_HW;
-	chip->ecc.read_page = brcmnand_read_page;
-	chip->ecc.write_page = brcmnand_write_page;
-	chip->ecc.read_page_raw = brcmnand_read_page_raw;
-	chip->ecc.write_page_raw = brcmnand_write_page_raw;
-	chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
-	chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
-	chip->ecc.read_oob = brcmnand_read_oob;
-	chip->ecc.write_oob = brcmnand_write_oob;
-
-	chip->controller = &ctrl->controller;
-
-	/*
-	 * The bootloader might have configured 16bit mode but
-	 * NAND READID command only works in 8bit mode. We force
-	 * 8bit mode here to ensure that NAND READID commands works.
-	 */
-	cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
-	nand_writereg(ctrl, cfg_offs,
-		      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		return ret;
-
-	chip->options |= NAND_NO_SUBPAGE_WRITE;
-	/*
-	 * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
-	 * to/from, and have nand_base pass us a bounce buffer instead, as
-	 * needed.
-	 */
-	chip->options |= NAND_USE_BOUNCE_BUFFER;
-
-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
-		chip->bbt_options |= NAND_BBT_NO_OOB;
-
-	if (brcmnand_setup_dev(host))
-		return -ENXIO;
-
-	chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
-	/* only use our internal HW threshold */
-	mtd->bitflip_threshold = 1;
-
-	ret = brcmstb_choose_ecc_layout(host);
-	if (ret)
-		return ret;
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		return ret;
-
-	return mtd_device_register(mtd, NULL, 0);
-}
-
-static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
-					    int restore)
-{
-	struct brcmnand_controller *ctrl = host->ctrl;
-	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
-	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
-			BRCMNAND_CS_CFG_EXT);
-	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
-			BRCMNAND_CS_ACC_CONTROL);
-	u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
-	u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
-
-	if (restore) {
-		nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
-		if (cfg_offs != cfg_ext_offs)
-			nand_writereg(ctrl, cfg_ext_offs,
-				      host->hwcfg.config_ext);
-		nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
-		nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
-		nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
-	} else {
-		host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
-		if (cfg_offs != cfg_ext_offs)
-			host->hwcfg.config_ext =
-				nand_readreg(ctrl, cfg_ext_offs);
-		host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
-		host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
-		host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
-	}
-}
-
-static int brcmnand_suspend(struct device *dev)
-{
-	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
-	struct brcmnand_host *host;
-
-	list_for_each_entry(host, &ctrl->host_list, node)
-		brcmnand_save_restore_cs_config(host, 0);
-
-	ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
-	ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
-	ctrl->corr_stat_threshold =
-		brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
-
-	if (has_flash_dma(ctrl))
-		ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
-
-	return 0;
-}
-
-static int brcmnand_resume(struct device *dev)
-{
-	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
-	struct brcmnand_host *host;
-
-	if (has_flash_dma(ctrl)) {
-		flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
-		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
-	}
-
-	brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
-	brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
-	brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
-			ctrl->corr_stat_threshold);
-	if (ctrl->soc) {
-		/* Clear/re-enable interrupt */
-		ctrl->soc->ctlrdy_ack(ctrl->soc);
-		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
-	}
-
-	list_for_each_entry(host, &ctrl->host_list, node) {
-		struct nand_chip *chip = &host->chip;
-
-		brcmnand_save_restore_cs_config(host, 1);
-
-		/* Reset the chip, required by some chips after power-up */
-		nand_reset_op(chip);
-	}
-
-	return 0;
-}
-
-const struct dev_pm_ops brcmnand_pm_ops = {
-	.suspend		= brcmnand_suspend,
-	.resume			= brcmnand_resume,
-};
-EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
-
-static const struct of_device_id brcmnand_of_match[] = {
-	{ .compatible = "brcm,brcmnand-v4.0" },
-	{ .compatible = "brcm,brcmnand-v5.0" },
-	{ .compatible = "brcm,brcmnand-v6.0" },
-	{ .compatible = "brcm,brcmnand-v6.1" },
-	{ .compatible = "brcm,brcmnand-v6.2" },
-	{ .compatible = "brcm,brcmnand-v7.0" },
-	{ .compatible = "brcm,brcmnand-v7.1" },
-	{ .compatible = "brcm,brcmnand-v7.2" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, brcmnand_of_match);
-
-/***********************************************************************
- * Platform driver setup (per controller)
- ***********************************************************************/
-
-int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *dn = dev->of_node, *child;
-	struct brcmnand_controller *ctrl;
-	struct resource *res;
-	int ret;
-
-	/* We only support device-tree instantiation */
-	if (!dn)
-		return -ENODEV;
-
-	if (!of_match_node(brcmnand_of_match, dn))
-		return -ENODEV;
-
-	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
-	if (!ctrl)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, ctrl);
-	ctrl->dev = dev;
-
-	init_completion(&ctrl->done);
-	init_completion(&ctrl->dma_done);
-	nand_hw_control_init(&ctrl->controller);
-	INIT_LIST_HEAD(&ctrl->host_list);
-
-	/* NAND register range */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	ctrl->nand_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(ctrl->nand_base))
-		return PTR_ERR(ctrl->nand_base);
-
-	/* Enable clock before using NAND registers */
-	ctrl->clk = devm_clk_get(dev, "nand");
-	if (!IS_ERR(ctrl->clk)) {
-		ret = clk_prepare_enable(ctrl->clk);
-		if (ret)
-			return ret;
-	} else {
-		ret = PTR_ERR(ctrl->clk);
-		if (ret == -EPROBE_DEFER)
-			return ret;
-
-		ctrl->clk = NULL;
-	}
-
-	/* Initialize NAND revision */
-	ret = brcmnand_revision_init(ctrl);
-	if (ret)
-		goto err;
-
-	/*
-	 * Most chips have this cache at a fixed offset within 'nand' block.
-	 * Some must specify this region separately.
-	 */
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
-	if (res) {
-		ctrl->nand_fc = devm_ioremap_resource(dev, res);
-		if (IS_ERR(ctrl->nand_fc)) {
-			ret = PTR_ERR(ctrl->nand_fc);
-			goto err;
-		}
-	} else {
-		ctrl->nand_fc = ctrl->nand_base +
-				ctrl->reg_offsets[BRCMNAND_FC_BASE];
-	}
-
-	/* FLASH_DMA */
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
-	if (res) {
-		ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
-		if (IS_ERR(ctrl->flash_dma_base)) {
-			ret = PTR_ERR(ctrl->flash_dma_base);
-			goto err;
-		}
-
-		flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
-		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
-
-		/* Allocate descriptor(s) */
-		ctrl->dma_desc = dmam_alloc_coherent(dev,
-						     sizeof(*ctrl->dma_desc),
-						     &ctrl->dma_pa, GFP_KERNEL);
-		if (!ctrl->dma_desc) {
-			ret = -ENOMEM;
-			goto err;
-		}
-
-		ctrl->dma_irq = platform_get_irq(pdev, 1);
-		if ((int)ctrl->dma_irq < 0) {
-			dev_err(dev, "missing FLASH_DMA IRQ\n");
-			ret = -ENODEV;
-			goto err;
-		}
-
-		ret = devm_request_irq(dev, ctrl->dma_irq,
-				brcmnand_dma_irq, 0, DRV_NAME,
-				ctrl);
-		if (ret < 0) {
-			dev_err(dev, "can't allocate IRQ %d: error %d\n",
-					ctrl->dma_irq, ret);
-			goto err;
-		}
-
-		dev_info(dev, "enabling FLASH_DMA\n");
-	}
-
-	/* Disable automatic device ID config, direct addressing */
-	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
-			 CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
-	/* Disable XOR addressing */
-	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
-
-	if (ctrl->features & BRCMNAND_HAS_WP) {
-		/* Permanently disable write protection */
-		if (wp_on == 2)
-			brcmnand_set_wp(ctrl, false);
-	} else {
-		wp_on = 0;
-	}
-
-	/* IRQ */
-	ctrl->irq = platform_get_irq(pdev, 0);
-	if ((int)ctrl->irq < 0) {
-		dev_err(dev, "no IRQ defined\n");
-		ret = -ENODEV;
-		goto err;
-	}
-
-	/*
-	 * Some SoCs integrate this controller (e.g., its interrupt bits) in
-	 * interesting ways
-	 */
-	if (soc) {
-		ctrl->soc = soc;
-
-		ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
-				       DRV_NAME, ctrl);
-
-		/* Enable interrupt */
-		ctrl->soc->ctlrdy_ack(ctrl->soc);
-		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
-	} else {
-		/* Use standard interrupt infrastructure */
-		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
-				       DRV_NAME, ctrl);
-	}
-	if (ret < 0) {
-		dev_err(dev, "can't allocate IRQ %d: error %d\n",
-			ctrl->irq, ret);
-		goto err;
-	}
-
-	for_each_available_child_of_node(dn, child) {
-		if (of_device_is_compatible(child, "brcm,nandcs")) {
-			struct brcmnand_host *host;
-
-			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-			if (!host) {
-				of_node_put(child);
-				ret = -ENOMEM;
-				goto err;
-			}
-			host->pdev = pdev;
-			host->ctrl = ctrl;
-
-			ret = brcmnand_init_cs(host, child);
-			if (ret) {
-				devm_kfree(dev, host);
-				continue; /* Try all chip-selects */
-			}
-
-			list_add_tail(&host->node, &ctrl->host_list);
-		}
-	}
-
-	/* No chip-selects could initialize properly */
-	if (list_empty(&ctrl->host_list)) {
-		ret = -ENODEV;
-		goto err;
-	}
-
-	return 0;
-
-err:
-	clk_disable_unprepare(ctrl->clk);
-	return ret;
-
-}
-EXPORT_SYMBOL_GPL(brcmnand_probe);
-
-int brcmnand_remove(struct platform_device *pdev)
-{
-	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
-	struct brcmnand_host *host;
-
-	list_for_each_entry(host, &ctrl->host_list, node)
-		nand_release(nand_to_mtd(&host->chip));
-
-	clk_disable_unprepare(ctrl->clk);
-
-	dev_set_drvdata(&pdev->dev, NULL);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(brcmnand_remove);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Kevin Cernekee");
-MODULE_AUTHOR("Brian Norris");
-MODULE_DESCRIPTION("NAND driver for Broadcom chips");
-MODULE_ALIAS("platform:brcmnand");
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h
deleted file mode 100644
index 5c44cd4aba87..000000000000
--- a/drivers/mtd/nand/brcmnand/brcmnand.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright © 2015 Broadcom 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.
- */
-
-#ifndef __BRCMNAND_H__
-#define __BRCMNAND_H__
-
-#include <linux/types.h>
-#include <linux/io.h>
-
-struct platform_device;
-struct dev_pm_ops;
-
-struct brcmnand_soc {
-	bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
-	void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
-	void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
-				 bool is_param);
-};
-
-static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
-						 bool is_param)
-{
-	if (soc && soc->prepare_data_bus)
-		soc->prepare_data_bus(soc, true, is_param);
-}
-
-static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
-						   bool is_param)
-{
-	if (soc && soc->prepare_data_bus)
-		soc->prepare_data_bus(soc, false, is_param);
-}
-
-static inline u32 brcmnand_readl(void __iomem *addr)
-{
-	/*
-	 * MIPS endianness is configured by boot strap, which also reverses all
-	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
-	 * endian I/O).
-	 *
-	 * Other architectures (e.g., ARM) either do not support big endian, or
-	 * else leave I/O in little endian mode.
-	 */
-	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
-		return __raw_readl(addr);
-	else
-		return readl_relaxed(addr);
-}
-
-static inline void brcmnand_writel(u32 val, void __iomem *addr)
-{
-	/* See brcmnand_readl() comments */
-	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
-		__raw_writel(val, addr);
-	else
-		writel_relaxed(val, addr);
-}
-
-int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
-int brcmnand_remove(struct platform_device *pdev);
-
-extern const struct dev_pm_ops brcmnand_pm_ops;
-
-#endif /* __BRCMNAND_H__ */
diff --git a/drivers/mtd/nand/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/brcmnand/brcmstb_nand.c
deleted file mode 100644
index 5c271077ac87..000000000000
--- a/drivers/mtd/nand/brcmnand/brcmstb_nand.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright © 2015 Broadcom 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/device.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "brcmnand.h"
-
-static const struct of_device_id brcmstb_nand_of_match[] = {
-	{ .compatible = "brcm,brcmnand" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, brcmstb_nand_of_match);
-
-static int brcmstb_nand_probe(struct platform_device *pdev)
-{
-	return brcmnand_probe(pdev, NULL);
-}
-
-static struct platform_driver brcmstb_nand_driver = {
-	.probe			= brcmstb_nand_probe,
-	.remove			= brcmnand_remove,
-	.driver = {
-		.name		= "brcmstb_nand",
-		.pm		= &brcmnand_pm_ops,
-		.of_match_table = brcmstb_nand_of_match,
-	}
-};
-module_platform_driver(brcmstb_nand_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Brian Norris");
-MODULE_DESCRIPTION("NAND driver for Broadcom STB chips");
diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/brcmnand/iproc_nand.c
deleted file mode 100644
index 4c6ae113664d..000000000000
--- a/drivers/mtd/nand/brcmnand/iproc_nand.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright © 2015 Broadcom 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/device.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "brcmnand.h"
-
-struct iproc_nand_soc {
-	struct brcmnand_soc soc;
-
-	void __iomem *idm_base;
-	void __iomem *ext_base;
-	spinlock_t idm_lock;
-};
-
-#define IPROC_NAND_CTLR_READY_OFFSET       0x10
-#define IPROC_NAND_CTLR_READY              BIT(0)
-
-#define IPROC_NAND_IO_CTRL_OFFSET          0x00
-#define IPROC_NAND_APB_LE_MODE             BIT(24)
-#define IPROC_NAND_INT_CTRL_READ_ENABLE    BIT(6)
-
-static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
-{
-	struct iproc_nand_soc *priv =
-			container_of(soc, struct iproc_nand_soc, soc);
-	void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
-	u32 val = brcmnand_readl(mmio);
-
-	if (val & IPROC_NAND_CTLR_READY) {
-		brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
-		return true;
-	}
-
-	return false;
-}
-
-static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
-{
-	struct iproc_nand_soc *priv =
-			container_of(soc, struct iproc_nand_soc, soc);
-	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
-	u32 val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->idm_lock, flags);
-
-	val = brcmnand_readl(mmio);
-
-	if (en)
-		val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
-	else
-		val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
-
-	brcmnand_writel(val, mmio);
-
-	spin_unlock_irqrestore(&priv->idm_lock, flags);
-}
-
-static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
-				  bool is_param)
-{
-	struct iproc_nand_soc *priv =
-			container_of(soc, struct iproc_nand_soc, soc);
-	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
-	u32 val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->idm_lock, flags);
-
-	val = brcmnand_readl(mmio);
-
-	/*
-	 * In the case of BE or when dealing with NAND data, alway configure
-	 * the APB bus to LE mode before accessing the FIFO and back to BE mode
-	 * after the access is done
-	 */
-	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
-		if (prepare)
-			val |= IPROC_NAND_APB_LE_MODE;
-		else
-			val &= ~IPROC_NAND_APB_LE_MODE;
-	} else { /* when in LE accessing the parameter page, keep APB in BE */
-		val &= ~IPROC_NAND_APB_LE_MODE;
-	}
-
-	brcmnand_writel(val, mmio);
-
-	spin_unlock_irqrestore(&priv->idm_lock, flags);
-}
-
-static int iproc_nand_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct iproc_nand_soc *priv;
-	struct brcmnand_soc *soc;
-	struct resource *res;
-
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-	soc = &priv->soc;
-
-	spin_lock_init(&priv->idm_lock);
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
-	priv->idm_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(priv->idm_base))
-		return PTR_ERR(priv->idm_base);
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
-	priv->ext_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(priv->ext_base))
-		return PTR_ERR(priv->ext_base);
-
-	soc->ctlrdy_ack = iproc_nand_intc_ack;
-	soc->ctlrdy_set_enabled = iproc_nand_intc_set;
-	soc->prepare_data_bus = iproc_nand_apb_access;
-
-	return brcmnand_probe(pdev, soc);
-}
-
-static const struct of_device_id iproc_nand_of_match[] = {
-	{ .compatible = "brcm,nand-iproc" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
-
-static struct platform_driver iproc_nand_driver = {
-	.probe			= iproc_nand_probe,
-	.remove			= brcmnand_remove,
-	.driver = {
-		.name		= "iproc_nand",
-		.pm		= &brcmnand_pm_ops,
-		.of_match_table	= iproc_nand_of_match,
-	}
-};
-module_platform_driver(iproc_nand_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Brian Norris");
-MODULE_AUTHOR("Ray Jui");
-MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
deleted file mode 100644
index 567ff972d5fc..000000000000
--- a/drivers/mtd/nand/cafe_nand.c
+++ /dev/null
@@ -1,871 +0,0 @@
-/*
- * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
- *
- * The data sheet for this device can be found at:
- *    http://wiki.laptop.org/go/Datasheets 
- *
- * Copyright © 2006 Red Hat, Inc.
- * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
- */
-
-#define DEBUG
-
-#include <linux/device.h>
-#undef DEBUG
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/rslib.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <asm/io.h>
-
-#define CAFE_NAND_CTRL1		0x00
-#define CAFE_NAND_CTRL2		0x04
-#define CAFE_NAND_CTRL3		0x08
-#define CAFE_NAND_STATUS	0x0c
-#define CAFE_NAND_IRQ		0x10
-#define CAFE_NAND_IRQ_MASK	0x14
-#define CAFE_NAND_DATA_LEN	0x18
-#define CAFE_NAND_ADDR1		0x1c
-#define CAFE_NAND_ADDR2		0x20
-#define CAFE_NAND_TIMING1	0x24
-#define CAFE_NAND_TIMING2	0x28
-#define CAFE_NAND_TIMING3	0x2c
-#define CAFE_NAND_NONMEM	0x30
-#define CAFE_NAND_ECC_RESULT	0x3C
-#define CAFE_NAND_DMA_CTRL	0x40
-#define CAFE_NAND_DMA_ADDR0	0x44
-#define CAFE_NAND_DMA_ADDR1	0x48
-#define CAFE_NAND_ECC_SYN01	0x50
-#define CAFE_NAND_ECC_SYN23	0x54
-#define CAFE_NAND_ECC_SYN45	0x58
-#define CAFE_NAND_ECC_SYN67	0x5c
-#define CAFE_NAND_READ_DATA	0x1000
-#define CAFE_NAND_WRITE_DATA	0x2000
-
-#define CAFE_GLOBAL_CTRL	0x3004
-#define CAFE_GLOBAL_IRQ		0x3008
-#define CAFE_GLOBAL_IRQ_MASK	0x300c
-#define CAFE_NAND_RESET		0x3034
-
-/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
-#define CTRL1_CHIPSELECT	(1<<19)
-
-struct cafe_priv {
-	struct nand_chip nand;
-	struct pci_dev *pdev;
-	void __iomem *mmio;
-	struct rs_control *rs;
-	uint32_t ctl1;
-	uint32_t ctl2;
-	int datalen;
-	int nr_data;
-	int data_pos;
-	int page_addr;
-	dma_addr_t dmaaddr;
-	unsigned char *dmabuf;
-};
-
-static int usedma = 1;
-module_param(usedma, int, 0644);
-
-static int skipbbt = 0;
-module_param(skipbbt, int, 0644);
-
-static int debug = 0;
-module_param(debug, int, 0644);
-
-static int regdebug = 0;
-module_param(regdebug, int, 0644);
-
-static int checkecc = 1;
-module_param(checkecc, int, 0644);
-
-static unsigned int numtimings;
-static int timing[3];
-module_param_array(timing, int, &numtimings, 0644);
-
-static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-
-/* Hrm. Why isn't this already conditional on something in the struct device? */
-#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
-
-/* Make it easier to switch to PIO if we need to */
-#define cafe_readl(cafe, addr)			readl((cafe)->mmio + CAFE_##addr)
-#define cafe_writel(cafe, datum, addr)		writel(datum, (cafe)->mmio + CAFE_##addr)
-
-static int cafe_device_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-	int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
-	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
-
-	cafe_writel(cafe, irqs, NAND_IRQ);
-
-	cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
-		result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
-		cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
-
-	return result;
-}
-
-
-static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-
-	if (usedma)
-		memcpy(cafe->dmabuf + cafe->datalen, buf, len);
-	else
-		memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
-
-	cafe->datalen += len;
-
-	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
-		len, cafe->datalen);
-}
-
-static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-
-	if (usedma)
-		memcpy(buf, cafe->dmabuf + cafe->datalen, len);
-	else
-		memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
-
-	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
-		  len, cafe->datalen);
-	cafe->datalen += len;
-}
-
-static uint8_t cafe_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-	uint8_t d;
-
-	cafe_read_buf(mtd, &d, 1);
-	cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
-
-	return d;
-}
-
-static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
-			      int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-	int adrbytes = 0;
-	uint32_t ctl1;
-	uint32_t doneint = 0x80000000;
-
-	cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
-		command, column, page_addr);
-
-	if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
-		/* Second half of a command we already calculated */
-		cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
-		ctl1 = cafe->ctl1;
-		cafe->ctl2 &= ~(1<<30);
-		cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
-			  cafe->ctl1, cafe->nr_data);
-		goto do_command;
-	}
-	/* Reset ECC engine */
-	cafe_writel(cafe, 0, NAND_CTRL2);
-
-	/* Emulate NAND_CMD_READOOB on large-page chips */
-	if (mtd->writesize > 512 &&
-	    command == NAND_CMD_READOOB) {
-		column += mtd->writesize;
-		command = NAND_CMD_READ0;
-	}
-
-	/* FIXME: Do we need to send read command before sending data
-	   for small-page chips, to position the buffer correctly? */
-
-	if (column != -1) {
-		cafe_writel(cafe, column, NAND_ADDR1);
-		adrbytes = 2;
-		if (page_addr != -1)
-			goto write_adr2;
-	} else if (page_addr != -1) {
-		cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
-		page_addr >>= 16;
-	write_adr2:
-		cafe_writel(cafe, page_addr, NAND_ADDR2);
-		adrbytes += 2;
-		if (mtd->size > mtd->writesize << 16)
-			adrbytes++;
-	}
-
-	cafe->data_pos = cafe->datalen = 0;
-
-	/* Set command valid bit, mask in the chip select bit  */
-	ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
-
-	/* Set RD or WR bits as appropriate */
-	if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
-		ctl1 |= (1<<26); /* rd */
-		/* Always 5 bytes, for now */
-		cafe->datalen = 4;
-		/* And one address cycle -- even for STATUS, since the controller doesn't work without */
-		adrbytes = 1;
-	} else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
-		   command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
-		ctl1 |= 1<<26; /* rd */
-		/* For now, assume just read to end of page */
-		cafe->datalen = mtd->writesize + mtd->oobsize - column;
-	} else if (command == NAND_CMD_SEQIN)
-		ctl1 |= 1<<25; /* wr */
-
-	/* Set number of address bytes */
-	if (adrbytes)
-		ctl1 |= ((adrbytes-1)|8) << 27;
-
-	if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
-		/* Ignore the first command of a pair; the hardware
-		   deals with them both at once, later */
-		cafe->ctl1 = ctl1;
-		cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
-			  cafe->ctl1, cafe->datalen);
-		return;
-	}
-	/* RNDOUT and READ0 commands need a following byte */
-	if (command == NAND_CMD_RNDOUT)
-		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
-	else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
-		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
-
- do_command:
-	cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
-		cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
-
-	/* NB: The datasheet lies -- we really should be subtracting 1 here */
-	cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
-	cafe_writel(cafe, 0x90000000, NAND_IRQ);
-	if (usedma && (ctl1 & (3<<25))) {
-		uint32_t dmactl = 0xc0000000 + cafe->datalen;
-		/* If WR or RD bits set, set up DMA */
-		if (ctl1 & (1<<26)) {
-			/* It's a read */
-			dmactl |= (1<<29);
-			/* ... so it's done when the DMA is done, not just
-			   the command. */
-			doneint = 0x10000000;
-		}
-		cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
-	}
-	cafe->datalen = 0;
-
-	if (unlikely(regdebug)) {
-		int i;
-		printk("About to write command %08x to register 0\n", ctl1);
-		for (i=4; i< 0x5c; i+=4)
-			printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
-	}
-
-	cafe_writel(cafe, ctl1, NAND_CTRL1);
-	/* Apply this short delay always to ensure that we do wait tWB in
-	 * any case on any machine. */
-	ndelay(100);
-
-	if (1) {
-		int c;
-		uint32_t irqs;
-
-		for (c = 500000; c != 0; c--) {
-			irqs = cafe_readl(cafe, NAND_IRQ);
-			if (irqs & doneint)
-				break;
-			udelay(1);
-			if (!(c % 100000))
-				cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
-			cpu_relax();
-		}
-		cafe_writel(cafe, doneint, NAND_IRQ);
-		cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
-			     command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
-	}
-
-	WARN_ON(cafe->ctl2 & (1<<30));
-
-	switch (command) {
-
-	case NAND_CMD_CACHEDPROG:
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_RNDIN:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_RNDOUT:
-		cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
-		return;
-	}
-	nand_wait_ready(mtd);
-	cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
-}
-
-static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-
-	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
-
-	/* Mask the appropriate bit into the stored value of ctl1
-	   which will be used by cafe_nand_cmdfunc() */
-	if (chipnr)
-		cafe->ctl1 |= CTRL1_CHIPSELECT;
-	else
-		cafe->ctl1 &= ~CTRL1_CHIPSELECT;
-}
-
-static irqreturn_t cafe_nand_interrupt(int irq, void *id)
-{
-	struct mtd_info *mtd = id;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
-	cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
-	if (!irqs)
-		return IRQ_NONE;
-
-	cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
-	return IRQ_HANDLED;
-}
-
-static void cafe_nand_bug(struct mtd_info *mtd)
-{
-	BUG();
-}
-
-static int cafe_nand_write_oob(struct mtd_info *mtd,
-			       struct nand_chip *chip, int page)
-{
-	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
-				 mtd->oobsize);
-}
-
-/* Don't use -- use nand_read_oob_std for now */
-static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			      int page)
-{
-	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-}
-/**
- * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
- * @mtd:	mtd info structure
- * @chip:	nand chip info structure
- * @buf:	buffer to store read data
- * @oob_required:	caller expects OOB data read to chip->oob_poi
- *
- * The hw generator calculates the error syndrome automatically. Therefore
- * we need a special oob layout and handling.
- */
-static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			       uint8_t *buf, int oob_required, int page)
-{
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-	unsigned int max_bitflips = 0;
-
-	cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
-		     cafe_readl(cafe, NAND_ECC_RESULT),
-		     cafe_readl(cafe, NAND_ECC_SYN01));
-
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
-		unsigned short syn[8], pat[4];
-		int pos[4];
-		u8 *oob = chip->oob_poi;
-		int i, n;
-
-		for (i=0; i<8; i+=2) {
-			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
-			syn[i] = cafe->rs->index_of[tmp & 0xfff];
-			syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
-		}
-
-		n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
-		                pat);
-
-		for (i = 0; i < n; i++) {
-			int p = pos[i];
-
-			/* The 12-bit symbols are mapped to bytes here */
-
-			if (p > 1374) {
-				/* out of range */
-				n = -1374;
-			} else if (p == 0) {
-				/* high four bits do not correspond to data */
-				if (pat[i] > 0xff)
-					n = -2048;
-				else
-					buf[0] ^= pat[i];
-			} else if (p == 1365) {
-				buf[2047] ^= pat[i] >> 4;
-				oob[0] ^= pat[i] << 4;
-			} else if (p > 1365) {
-				if ((p & 1) == 1) {
-					oob[3*p/2 - 2048] ^= pat[i] >> 4;
-					oob[3*p/2 - 2047] ^= pat[i] << 4;
-				} else {
-					oob[3*p/2 - 2049] ^= pat[i] >> 8;
-					oob[3*p/2 - 2048] ^= pat[i];
-				}
-			} else if ((p & 1) == 1) {
-				buf[3*p/2] ^= pat[i] >> 4;
-				buf[3*p/2 + 1] ^= pat[i] << 4;
-			} else {
-				buf[3*p/2 - 1] ^= pat[i] >> 8;
-				buf[3*p/2] ^= pat[i];
-			}
-		}
-
-		if (n < 0) {
-			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
-				cafe_readl(cafe, NAND_ADDR2) * 2048);
-			for (i = 0; i < 0x5c; i += 4)
-				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
-			mtd->ecc_stats.failed++;
-		} else {
-			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
-			mtd->ecc_stats.corrected += n;
-			max_bitflips = max_t(unsigned int, max_bitflips, n);
-		}
-	}
-
-	return max_bitflips;
-}
-
-static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
-			      struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 0;
-	oobregion->length = chip->ecc.total;
-
-	return 0;
-}
-
-static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
-			       struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = chip->ecc.total;
-	oobregion->length = mtd->oobsize - chip->ecc.total;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
-	.ecc = cafe_ooblayout_ecc,
-	.free = cafe_ooblayout_free,
-};
-
-/* Ick. The BBT code really ought to be able to work this bit out
-   for itself from the above, at least for the 2KiB case */
-static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
-static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
-
-static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
-static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
-
-
-static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	14,
-	.len = 4,
-	.veroffs = 18,
-	.maxblocks = 4,
-	.pattern = cafe_bbt_pattern_2048
-};
-
-static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	14,
-	.len = 4,
-	.veroffs = 18,
-	.maxblocks = 4,
-	.pattern = cafe_mirror_pattern_2048
-};
-
-static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	14,
-	.len = 1,
-	.veroffs = 15,
-	.maxblocks = 4,
-	.pattern = cafe_bbt_pattern_512
-};
-
-static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	14,
-	.len = 1,
-	.veroffs = 15,
-	.maxblocks = 4,
-	.pattern = cafe_mirror_pattern_512
-};
-
-
-static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
-					  struct nand_chip *chip,
-					  const uint8_t *buf, int oob_required,
-					  int page)
-{
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	/* Set up ECC autogeneration */
-	cafe->ctl2 |= (1<<30);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
-{
-	return 0;
-}
-
-/* F_2[X]/(X**6+X+1)  */
-static unsigned short gf64_mul(u8 a, u8 b)
-{
-	u8 c;
-	unsigned int i;
-
-	c = 0;
-	for (i = 0; i < 6; i++) {
-		if (a & 1)
-			c ^= b;
-		a >>= 1;
-		b <<= 1;
-		if ((b & 0x40) != 0)
-			b ^= 0x43;
-	}
-
-	return c;
-}
-
-/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
-static u16 gf4096_mul(u16 a, u16 b)
-{
-	u8 ah, al, bh, bl, ch, cl;
-
-	ah = a >> 6;
-	al = a & 0x3f;
-	bh = b >> 6;
-	bl = b & 0x3f;
-
-	ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
-	cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
-
-	return (ch << 6) ^ cl;
-}
-
-static int cafe_mul(int x)
-{
-	if (x == 0)
-		return 1;
-	return gf4096_mul(x, 0xe01);
-}
-
-static int cafe_nand_probe(struct pci_dev *pdev,
-				     const struct pci_device_id *ent)
-{
-	struct mtd_info *mtd;
-	struct cafe_priv *cafe;
-	uint32_t ctrl;
-	int err = 0;
-	int old_dma;
-
-	/* Very old versions shared the same PCI ident for all three
-	   functions on the chip. Verify the class too... */
-	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
-		return -ENODEV;
-
-	err = pci_enable_device(pdev);
-	if (err)
-		return err;
-
-	pci_set_master(pdev);
-
-	cafe = kzalloc(sizeof(*cafe), GFP_KERNEL);
-	if (!cafe)
-		return  -ENOMEM;
-
-	mtd = nand_to_mtd(&cafe->nand);
-	mtd->dev.parent = &pdev->dev;
-	nand_set_controller_data(&cafe->nand, cafe);
-
-	cafe->pdev = pdev;
-	cafe->mmio = pci_iomap(pdev, 0, 0);
-	if (!cafe->mmio) {
-		dev_warn(&pdev->dev, "failed to iomap\n");
-		err = -ENOMEM;
-		goto out_free_mtd;
-	}
-
-	cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
-	if (!cafe->rs) {
-		err = -ENOMEM;
-		goto out_ior;
-	}
-
-	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
-	cafe->nand.dev_ready = cafe_device_ready;
-	cafe->nand.read_byte = cafe_read_byte;
-	cafe->nand.read_buf = cafe_read_buf;
-	cafe->nand.write_buf = cafe_write_buf;
-	cafe->nand.select_chip = cafe_select_chip;
-	cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
-	cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
-
-	cafe->nand.chip_delay = 0;
-
-	/* Enable the following for a flash based bad block table */
-	cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
-
-	if (skipbbt) {
-		cafe->nand.options |= NAND_SKIP_BBTSCAN;
-		cafe->nand.block_bad = cafe_nand_block_bad;
-	}
-
-	if (numtimings && numtimings != 3) {
-		dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
-	}
-
-	if (numtimings == 3) {
-		cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
-			     timing[0], timing[1], timing[2]);
-	} else {
-		timing[0] = cafe_readl(cafe, NAND_TIMING1);
-		timing[1] = cafe_readl(cafe, NAND_TIMING2);
-		timing[2] = cafe_readl(cafe, NAND_TIMING3);
-
-		if (timing[0] | timing[1] | timing[2]) {
-			cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
-				     timing[0], timing[1], timing[2]);
-		} else {
-			dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
-			timing[0] = timing[1] = timing[2] = 0xffffffff;
-		}
-	}
-
-	/* Start off by resetting the NAND controller completely */
-	cafe_writel(cafe, 1, NAND_RESET);
-	cafe_writel(cafe, 0, NAND_RESET);
-
-	cafe_writel(cafe, timing[0], NAND_TIMING1);
-	cafe_writel(cafe, timing[1], NAND_TIMING2);
-	cafe_writel(cafe, timing[2], NAND_TIMING3);
-
-	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
-	err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
-			  "CAFE NAND", mtd);
-	if (err) {
-		dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
-		goto out_ior;
-	}
-
-	/* Disable master reset, enable NAND clock */
-	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
-	ctrl &= 0xffffeff0;
-	ctrl |= 0x00007000;
-	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
-	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
-	cafe_writel(cafe, 0, NAND_DMA_CTRL);
-
-	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
-	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
-
-	/* Enable NAND IRQ in global IRQ mask register */
-	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
-	cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
-		cafe_readl(cafe, GLOBAL_CTRL),
-		cafe_readl(cafe, GLOBAL_IRQ_MASK));
-
-	/* Do not use the DMA for the nand_scan_ident() */
-	old_dma = usedma;
-	usedma = 0;
-
-	/* Scan to find existence of the device */
-	err = nand_scan_ident(mtd, 2, NULL);
-	if (err)
-		goto out_irq;
-
-	cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
-					  &cafe->dmaaddr, GFP_KERNEL);
-	if (!cafe->dmabuf) {
-		err = -ENOMEM;
-		goto out_irq;
-	}
-
-	/* Set up DMA address */
-	cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
-	cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
-
-	cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
-		cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
-
-	/* Restore the DMA flag */
-	usedma = old_dma;
-
-	cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
-	if (mtd->writesize == 2048)
-		cafe->ctl2 |= 1<<29; /* 2KiB page size */
-
-	/* Set up ECC according to the type of chip we found */
-	mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
-	if (mtd->writesize == 2048) {
-		cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
-		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
-	} else if (mtd->writesize == 512) {
-		cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
-		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
-	} else {
-		printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
-		       mtd->writesize);
-		goto out_free_dma;
-	}
-	cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
-	cafe->nand.ecc.size = mtd->writesize;
-	cafe->nand.ecc.bytes = 14;
-	cafe->nand.ecc.strength = 4;
-	cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
-	cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
-	cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
-	cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
-	cafe->nand.ecc.write_oob = cafe_nand_write_oob;
-	cafe->nand.ecc.read_page = cafe_nand_read_page;
-	cafe->nand.ecc.read_oob = cafe_nand_read_oob;
-
-	err = nand_scan_tail(mtd);
-	if (err)
-		goto out_free_dma;
-
-	pci_set_drvdata(pdev, mtd);
-
-	mtd->name = "cafe_nand";
-	mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
-
-	goto out;
-
- out_free_dma:
-	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
- out_irq:
-	/* Disable NAND IRQ in global IRQ mask register */
-	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
-	free_irq(pdev->irq, mtd);
- out_ior:
-	pci_iounmap(pdev, cafe->mmio);
- out_free_mtd:
-	kfree(cafe);
- out:
-	return err;
-}
-
-static void cafe_nand_remove(struct pci_dev *pdev)
-{
-	struct mtd_info *mtd = pci_get_drvdata(pdev);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-
-	/* Disable NAND IRQ in global IRQ mask register */
-	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
-	free_irq(pdev->irq, mtd);
-	nand_release(mtd);
-	free_rs(cafe->rs);
-	pci_iounmap(pdev, cafe->mmio);
-	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
-	kfree(cafe);
-}
-
-static const struct pci_device_id cafe_nand_tbl[] = {
-	{ PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
-	  PCI_ANY_ID, PCI_ANY_ID },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
-
-static int cafe_nand_resume(struct pci_dev *pdev)
-{
-	uint32_t ctrl;
-	struct mtd_info *mtd = pci_get_drvdata(pdev);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct cafe_priv *cafe = nand_get_controller_data(chip);
-
-       /* Start off by resetting the NAND controller completely */
-	cafe_writel(cafe, 1, NAND_RESET);
-	cafe_writel(cafe, 0, NAND_RESET);
-	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
-
-	/* Restore timing configuration */
-	cafe_writel(cafe, timing[0], NAND_TIMING1);
-	cafe_writel(cafe, timing[1], NAND_TIMING2);
-	cafe_writel(cafe, timing[2], NAND_TIMING3);
-
-        /* Disable master reset, enable NAND clock */
-	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
-	ctrl &= 0xffffeff0;
-	ctrl |= 0x00007000;
-	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
-	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
-	cafe_writel(cafe, 0, NAND_DMA_CTRL);
-	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
-	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
-
-	/* Set up DMA address */
-	cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
-	if (sizeof(cafe->dmaaddr) > 4)
-	/* Shift in two parts to shut the compiler up */
-		cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
-	else
-		cafe_writel(cafe, 0, NAND_DMA_ADDR1);
-
-	/* Enable NAND IRQ in global IRQ mask register */
-	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
-	return 0;
-}
-
-static struct pci_driver cafe_nand_pci_driver = {
-	.name = "CAFÉ NAND",
-	.id_table = cafe_nand_tbl,
-	.probe = cafe_nand_probe,
-	.remove = cafe_nand_remove,
-	.resume = cafe_nand_resume,
-};
-
-module_pci_driver(cafe_nand_pci_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
deleted file mode 100644
index b01c9804590e..000000000000
--- a/drivers/mtd/nand/cmx270_nand.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- *  linux/drivers/mtd/nand/cmx270-nand.c
- *
- *  Copyright (C) 2006 Compulab, Ltd.
- *  Mike Rapoport <mike@compulab.co.il>
- *
- *  Derived from drivers/mtd/nand/h1910.c
- *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
- *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.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.
- *
- *  Overview:
- *   This is a device driver for the NAND flash device found on the
- *   CM-X270 board.
- */
-
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <mach/pxa2xx-regs.h>
-
-#define GPIO_NAND_CS	(11)
-#define GPIO_NAND_RB	(89)
-
-/* MTD structure for CM-X270 board */
-static struct mtd_info *cmx270_nand_mtd;
-
-/* remaped IO address of the device */
-static void __iomem *cmx270_nand_io;
-
-/*
- * Define static partitions for flash device
- */
-static const struct mtd_partition partition_info[] = {
-	[0] = {
-		.name	= "cmx270-0",
-		.offset	= 0,
-		.size	= MTDPART_SIZ_FULL
-	}
-};
-#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
-
-static u_char cmx270_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	return (readl(this->IO_ADDR_R) >> 16);
-}
-
-static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	for (i=0; i<len; i++)
-		writel((*buf++ << 16), this->IO_ADDR_W);
-}
-
-static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	for (i=0; i<len; i++)
-		*buf++ = readl(this->IO_ADDR_R) >> 16;
-}
-
-static inline void nand_cs_on(void)
-{
-	gpio_set_value(GPIO_NAND_CS, 0);
-}
-
-static void nand_cs_off(void)
-{
-	dsb();
-
-	gpio_set_value(GPIO_NAND_CS, 1);
-}
-
-/*
- *	hardware specific access to control-lines
- */
-static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
-			     unsigned int ctrl)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
-
-	dsb();
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		if ( ctrl & NAND_ALE )
-			nandaddr |=  (1 << 3);
-		else
-			nandaddr &= ~(1 << 3);
-		if ( ctrl & NAND_CLE )
-			nandaddr |=  (1 << 2);
-		else
-			nandaddr &= ~(1 << 2);
-		if ( ctrl & NAND_NCE )
-			nand_cs_on();
-		else
-			nand_cs_off();
-	}
-
-	dsb();
-	this->IO_ADDR_W = (void __iomem*)nandaddr;
-	if (dat != NAND_CMD_NONE)
-		writel((dat << 16), this->IO_ADDR_W);
-
-	dsb();
-}
-
-/*
- *	read device ready pin
- */
-static int cmx270_device_ready(struct mtd_info *mtd)
-{
-	dsb();
-
-	return (gpio_get_value(GPIO_NAND_RB));
-}
-
-/*
- * Main initialization routine
- */
-static int __init cmx270_init(void)
-{
-	struct nand_chip *this;
-	int ret;
-
-	if (!(machine_is_armcore() && cpu_is_pxa27x()))
-		return -ENODEV;
-
-	ret = gpio_request(GPIO_NAND_CS, "NAND CS");
-	if (ret) {
-		pr_warn("CM-X270: failed to request NAND CS gpio\n");
-		return ret;
-	}
-
-	gpio_direction_output(GPIO_NAND_CS, 1);
-
-	ret = gpio_request(GPIO_NAND_RB, "NAND R/B");
-	if (ret) {
-		pr_warn("CM-X270: failed to request NAND R/B gpio\n");
-		goto err_gpio_request;
-	}
-
-	gpio_direction_input(GPIO_NAND_RB);
-
-	/* Allocate memory for MTD device structure and private data */
-	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
-	if (!this) {
-		ret = -ENOMEM;
-		goto err_kzalloc;
-	}
-
-	cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
-	if (!cmx270_nand_io) {
-		pr_debug("Unable to ioremap NAND device\n");
-		ret = -EINVAL;
-		goto err_ioremap;
-	}
-
-	cmx270_nand_mtd = nand_to_mtd(this);
-
-	/* Link the private data with the MTD structure */
-	cmx270_nand_mtd->owner = THIS_MODULE;
-
-	/* insert callbacks */
-	this->IO_ADDR_R = cmx270_nand_io;
-	this->IO_ADDR_W = cmx270_nand_io;
-	this->cmd_ctrl = cmx270_hwcontrol;
-	this->dev_ready = cmx270_device_ready;
-
-	/* 15 us command delay time */
-	this->chip_delay = 20;
-	this->ecc.mode = NAND_ECC_SOFT;
-	this->ecc.algo = NAND_ECC_HAMMING;
-
-	/* read/write functions */
-	this->read_byte = cmx270_read_byte;
-	this->read_buf = cmx270_read_buf;
-	this->write_buf = cmx270_write_buf;
-
-	/* Scan to find existence of the device */
-	ret = nand_scan(cmx270_nand_mtd, 1);
-	if (ret) {
-		pr_notice("No NAND device\n");
-		goto err_scan;
-	}
-
-	/* Register the partitions */
-	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
-					partition_info, NUM_PARTITIONS);
-	if (ret)
-		goto err_scan;
-
-	/* Return happy */
-	return 0;
-
-err_scan:
-	iounmap(cmx270_nand_io);
-err_ioremap:
-	kfree(this);
-err_kzalloc:
-	gpio_free(GPIO_NAND_RB);
-err_gpio_request:
-	gpio_free(GPIO_NAND_CS);
-
-	return ret;
-
-}
-module_init(cmx270_init);
-
-/*
- * Clean up routine
- */
-static void __exit cmx270_cleanup(void)
-{
-	/* Release resources, unregister device */
-	nand_release(cmx270_nand_mtd);
-
-	gpio_free(GPIO_NAND_RB);
-	gpio_free(GPIO_NAND_CS);
-
-	iounmap(cmx270_nand_io);
-
-	kfree(mtd_to_nand(cmx270_nand_mtd));
-}
-module_exit(cmx270_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
-MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
new file mode 100644
index 000000000000..f237a688f8e9
--- /dev/null
+++ b/drivers/mtd/nand/core.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 Free Electrons
+ *
+ * Authors:
+ *	Boris Brezillon <boris.brezillon@free-electrons.com>
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#define pr_fmt(fmt)	"nand: " fmt
+
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+
+/**
+ * nanddev_isbad() - Check if a block is bad
+ * @nand: NAND device
+ * @pos: position pointing to the block we want to check
+ *
+ * Return: true if the block is bad, false otherwise.
+ */
+bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+	if (nanddev_bbt_is_initialized(nand)) {
+		unsigned int entry;
+		int status;
+
+		entry = nanddev_bbt_pos_to_entry(nand, pos);
+		status = nanddev_bbt_get_block_status(nand, entry);
+		/* Lazy block status retrieval */
+		if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) {
+			if (nand->ops->isbad(nand, pos))
+				status = NAND_BBT_BLOCK_FACTORY_BAD;
+			else
+				status = NAND_BBT_BLOCK_GOOD;
+
+			nanddev_bbt_set_block_status(nand, entry, status);
+		}
+
+		if (status == NAND_BBT_BLOCK_WORN ||
+		    status == NAND_BBT_BLOCK_FACTORY_BAD)
+			return true;
+
+		return false;
+	}
+
+	return nand->ops->isbad(nand, pos);
+}
+EXPORT_SYMBOL_GPL(nanddev_isbad);
+
+/**
+ * nanddev_markbad() - Mark a block as bad
+ * @nand: NAND device
+ * @block: block to mark bad
+ *
+ * Mark a block bad. This function is updating the BBT if available and
+ * calls the low-level markbad hook (nand->ops->markbad()).
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	unsigned int entry;
+	int ret = 0;
+
+	if (nanddev_isbad(nand, pos))
+		return 0;
+
+	ret = nand->ops->markbad(nand, pos);
+	if (ret)
+		pr_warn("failed to write BBM to block @%llx (err = %d)\n",
+			nanddev_pos_to_offs(nand, pos), ret);
+
+	if (!nanddev_bbt_is_initialized(nand))
+		goto out;
+
+	entry = nanddev_bbt_pos_to_entry(nand, pos);
+	ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN);
+	if (ret)
+		goto out;
+
+	ret = nanddev_bbt_update(nand);
+
+out:
+	if (!ret)
+		mtd->ecc_stats.badblocks++;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nanddev_markbad);
+
+/**
+ * nanddev_isreserved() - Check whether an eraseblock is reserved or not
+ * @nand: NAND device
+ * @pos: NAND position to test
+ *
+ * Checks whether the eraseblock pointed by @pos is reserved or not.
+ *
+ * Return: true if the eraseblock is reserved, false otherwise.
+ */
+bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos)
+{
+	unsigned int entry;
+	int status;
+
+	if (!nanddev_bbt_is_initialized(nand))
+		return false;
+
+	/* Return info from the table */
+	entry = nanddev_bbt_pos_to_entry(nand, pos);
+	status = nanddev_bbt_get_block_status(nand, entry);
+	return status == NAND_BBT_BLOCK_RESERVED;
+}
+EXPORT_SYMBOL_GPL(nanddev_isreserved);
+
+/**
+ * nanddev_erase() - Erase a NAND portion
+ * @nand: NAND device
+ * @block: eraseblock to erase
+ *
+ * Erases @block if it's not bad.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
+{
+	if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
+		pr_warn("attempt to erase a bad/reserved block @%llx\n",
+			nanddev_pos_to_offs(nand, pos));
+		return -EIO;
+	}
+
+	return nand->ops->erase(nand, pos);
+}
+EXPORT_SYMBOL_GPL(nanddev_erase);
+
+/**
+ * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
+ * @mtd: MTD device
+ * @einfo: erase request
+ *
+ * This is a simple mtd->_erase() implementation iterating over all blocks
+ * concerned by @einfo and calling nand->ops->erase() on each of them.
+ *
+ * Note that mtd->_erase should not be directly assigned to this helper,
+ * because there's no locking here. NAND specialized layers should instead
+ * implement there own wrapper around nanddev_mtd_erase() taking the
+ * appropriate lock before calling nanddev_mtd_erase().
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
+{
+	struct nand_device *nand = mtd_to_nanddev(mtd);
+	struct nand_pos pos, last;
+	int ret;
+
+	nanddev_offs_to_pos(nand, einfo->addr, &pos);
+	nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
+	while (nanddev_pos_cmp(&pos, &last) <= 0) {
+		ret = nanddev_erase(nand, &pos);
+		if (ret) {
+			einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
+			einfo->state = MTD_ERASE_FAILED;
+
+			return ret;
+		}
+
+		nanddev_pos_next_eraseblock(nand, &pos);
+	}
+
+	einfo->state = MTD_ERASE_DONE;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
+
+/**
+ * nanddev_init() - Initialize a NAND device
+ * @nand: NAND device
+ * @memorg: NAND memory organization descriptor
+ * @ops: NAND device operations
+ *
+ * Initializes a NAND device object. Consistency checks are done on @memorg and
+ * @ops. Also takes care of initializing the BBT.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
+		 struct module *owner)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct nand_memory_organization *memorg = nanddev_get_memorg(nand);
+
+	if (!nand || !ops)
+		return -EINVAL;
+
+	if (!ops->erase || !ops->markbad || !ops->isbad)
+		return -EINVAL;
+
+	if (!memorg->bits_per_cell || !memorg->pagesize ||
+	    !memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun ||
+	    !memorg->planes_per_lun || !memorg->luns_per_target ||
+	    !memorg->ntargets)
+		return -EINVAL;
+
+	nand->rowconv.eraseblock_addr_shift =
+					fls(memorg->pages_per_eraseblock - 1);
+	nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) +
+				       nand->rowconv.eraseblock_addr_shift;
+
+	nand->ops = ops;
+
+	mtd->type = memorg->bits_per_cell == 1 ?
+		    MTD_NANDFLASH : MTD_MLCNANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
+	mtd->writesize = memorg->pagesize;
+	mtd->writebufsize = memorg->pagesize;
+	mtd->oobsize = memorg->oobsize;
+	mtd->size = nanddev_size(nand);
+	mtd->owner = owner;
+
+	return nanddev_bbt_init(nand);
+}
+EXPORT_SYMBOL_GPL(nanddev_init);
+
+/**
+ * nanddev_cleanup() - Release resources allocated in nanddev_init()
+ * @nand: NAND device
+ *
+ * Basically undoes what has been done in nanddev_init().
+ */
+void nanddev_cleanup(struct nand_device *nand)
+{
+	if (nanddev_bbt_is_initialized(nand))
+		nanddev_bbt_cleanup(nand);
+}
+EXPORT_SYMBOL_GPL(nanddev_cleanup);
+
+MODULE_DESCRIPTION("Generic NAND framework");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
deleted file mode 100644
index d48877540f14..000000000000
--- a/drivers/mtd/nand/cs553x_nand.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * drivers/mtd/nand/cs553x_nand.c
- *
- * (C) 2005, 2006 Red Hat Inc.
- *
- * Author: David Woodhouse <dwmw2@infradead.org>
- *	   Tom Sylla <tom.sylla@amd.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.
- *
- *  Overview:
- *   This is a device driver for the NAND flash controller found on
- *   the AMD CS5535/CS5536 companion chipsets for the Geode processor.
- *   mtd-id for command line partitioning is cs553x_nand_cs[0-3]
- *   where 0-3 reflects the chip select for NAND.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/msr.h>
-#include <asm/io.h>
-
-#define NR_CS553X_CONTROLLERS	4
-
-#define MSR_DIVIL_GLD_CAP	0x51400000	/* DIVIL capabilitiies */
-#define CAP_CS5535		0x2df000ULL
-#define CAP_CS5536		0x5df500ULL
-
-/* NAND Timing MSRs */
-#define MSR_NANDF_DATA		0x5140001b	/* NAND Flash Data Timing MSR */
-#define MSR_NANDF_CTL		0x5140001c	/* NAND Flash Control Timing */
-#define MSR_NANDF_RSVD		0x5140001d	/* Reserved */
-
-/* NAND BAR MSRs */
-#define MSR_DIVIL_LBAR_FLSH0	0x51400010	/* Flash Chip Select 0 */
-#define MSR_DIVIL_LBAR_FLSH1	0x51400011	/* Flash Chip Select 1 */
-#define MSR_DIVIL_LBAR_FLSH2	0x51400012	/* Flash Chip Select 2 */
-#define MSR_DIVIL_LBAR_FLSH3	0x51400013	/* Flash Chip Select 3 */
-	/* Each made up of... */
-#define FLSH_LBAR_EN		(1ULL<<32)
-#define FLSH_NOR_NAND		(1ULL<<33)	/* 1 for NAND */
-#define FLSH_MEM_IO		(1ULL<<34)	/* 1 for MMIO */
-	/* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */
-	/* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */
-
-/* Pin function selection MSR (IDE vs. flash on the IDE pins) */
-#define MSR_DIVIL_BALL_OPTS	0x51400015
-#define PIN_OPT_IDE		(1<<0)	/* 0 for flash, 1 for IDE */
-
-/* Registers within the NAND flash controller BAR -- memory mapped */
-#define MM_NAND_DATA		0x00	/* 0 to 0x7ff, in fact */
-#define MM_NAND_CTL		0x800	/* Any even address 0x800-0x80e */
-#define MM_NAND_IO		0x801	/* Any odd address 0x801-0x80f */
-#define MM_NAND_STS		0x810
-#define MM_NAND_ECC_LSB		0x811
-#define MM_NAND_ECC_MSB		0x812
-#define MM_NAND_ECC_COL		0x813
-#define MM_NAND_LAC		0x814
-#define MM_NAND_ECC_CTL		0x815
-
-/* Registers within the NAND flash controller BAR -- I/O mapped */
-#define IO_NAND_DATA		0x00	/* 0 to 3, in fact */
-#define IO_NAND_CTL		0x04
-#define IO_NAND_IO		0x05
-#define IO_NAND_STS		0x06
-#define IO_NAND_ECC_CTL		0x08
-#define IO_NAND_ECC_LSB		0x09
-#define IO_NAND_ECC_MSB		0x0a
-#define IO_NAND_ECC_COL		0x0b
-#define IO_NAND_LAC		0x0c
-
-#define CS_NAND_CTL_DIST_EN	(1<<4)	/* Enable NAND Distract interrupt */
-#define CS_NAND_CTL_RDY_INT_MASK	(1<<3)	/* Enable RDY/BUSY# interrupt */
-#define CS_NAND_CTL_ALE		(1<<2)
-#define CS_NAND_CTL_CLE		(1<<1)
-#define CS_NAND_CTL_CE		(1<<0)	/* Keep low; 1 to reset */
-
-#define CS_NAND_STS_FLASH_RDY	(1<<3)
-#define CS_NAND_CTLR_BUSY	(1<<2)
-#define CS_NAND_CMD_COMP	(1<<1)
-#define CS_NAND_DIST_ST		(1<<0)
-
-#define CS_NAND_ECC_PARITY	(1<<2)
-#define CS_NAND_ECC_CLRECC	(1<<1)
-#define CS_NAND_ECC_ENECC	(1<<0)
-
-static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	while (unlikely(len > 0x800)) {
-		memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
-		buf += 0x800;
-		len -= 0x800;
-	}
-	memcpy_fromio(buf, this->IO_ADDR_R, len);
-}
-
-static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	while (unlikely(len > 0x800)) {
-		memcpy_toio(this->IO_ADDR_R, buf, 0x800);
-		buf += 0x800;
-		len -= 0x800;
-	}
-	memcpy_toio(this->IO_ADDR_R, buf, len);
-}
-
-static unsigned char cs553x_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	return readb(this->IO_ADDR_R);
-}
-
-static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int i = 100000;
-
-	while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
-		udelay(1);
-		i--;
-	}
-	writeb(byte, this->IO_ADDR_W + 0x801);
-}
-
-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
-			     unsigned int ctrl)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	void __iomem *mmio_base = this->IO_ADDR_R;
-	if (ctrl & NAND_CTRL_CHANGE) {
-		unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
-		writeb(ctl, mmio_base + MM_NAND_CTL);
-	}
-	if (cmd != NAND_CMD_NONE)
-		cs553x_write_byte(mtd, cmd);
-}
-
-static int cs553x_device_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	void __iomem *mmio_base = this->IO_ADDR_R;
-	unsigned char foo = readb(mmio_base + MM_NAND_STS);
-
-	return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
-}
-
-static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	void __iomem *mmio_base = this->IO_ADDR_R;
-
-	writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
-}
-
-static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-{
-	uint32_t ecc;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	void __iomem *mmio_base = this->IO_ADDR_R;
-
-	ecc = readl(mmio_base + MM_NAND_STS);
-
-	ecc_code[1] = ecc >> 8;
-	ecc_code[0] = ecc >> 16;
-	ecc_code[2] = ecc >> 24;
-	return 0;
-}
-
-static struct mtd_info *cs553x_mtd[4];
-
-static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
-{
-	int err = 0;
-	struct nand_chip *this;
-	struct mtd_info *new_mtd;
-
-	printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr);
-
-	if (!mmio) {
-		printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n");
-		return -ENXIO;
-	}
-
-	/* Allocate memory for MTD device structure and private data */
-	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
-	if (!this) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	new_mtd = nand_to_mtd(this);
-
-	/* Link the private data with the MTD structure */
-	new_mtd->owner = THIS_MODULE;
-
-	/* map physical address */
-	this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
-	if (!this->IO_ADDR_R) {
-		printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr);
-		err = -EIO;
-		goto out_mtd;
-	}
-
-	this->cmd_ctrl = cs553x_hwcontrol;
-	this->dev_ready = cs553x_device_ready;
-	this->read_byte = cs553x_read_byte;
-	this->read_buf = cs553x_read_buf;
-	this->write_buf = cs553x_write_buf;
-
-	this->chip_delay = 0;
-
-	this->ecc.mode = NAND_ECC_HW;
-	this->ecc.size = 256;
-	this->ecc.bytes = 3;
-	this->ecc.hwctl  = cs_enable_hwecc;
-	this->ecc.calculate = cs_calculate_ecc;
-	this->ecc.correct  = nand_correct_data;
-	this->ecc.strength = 1;
-
-	/* Enable the following for a flash based bad block table */
-	this->bbt_options = NAND_BBT_USE_FLASH;
-
-	new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
-	if (!new_mtd->name) {
-		err = -ENOMEM;
-		goto out_ior;
-	}
-
-	/* Scan to find existence of the device */
-	err = nand_scan(new_mtd, 1);
-	if (err)
-		goto out_free;
-
-	cs553x_mtd[cs] = new_mtd;
-	goto out;
-
-out_free:
-	kfree(new_mtd->name);
-out_ior:
-	iounmap(this->IO_ADDR_R);
-out_mtd:
-	kfree(this);
-out:
-	return err;
-}
-
-static int is_geode(void)
-{
-	/* These are the CPUs which will have a CS553[56] companion chip */
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-	    boot_cpu_data.x86 == 5 &&
-	    boot_cpu_data.x86_model == 10)
-		return 1; /* Geode LX */
-
-	if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
-	     boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
-	    boot_cpu_data.x86 == 5 &&
-	    boot_cpu_data.x86_model == 5)
-		return 1; /* Geode GX (née GX2) */
-
-	return 0;
-}
-
-static int __init cs553x_init(void)
-{
-	int err = -ENXIO;
-	int i;
-	uint64_t val;
-
-	/* If the CPU isn't a Geode GX or LX, abort */
-	if (!is_geode())
-		return -ENXIO;
-
-	/* If it doesn't have the CS553[56], abort */
-	rdmsrl(MSR_DIVIL_GLD_CAP, val);
-	val &= ~0xFFULL;
-	if (val != CAP_CS5535 && val != CAP_CS5536)
-		return -ENXIO;
-
-	/* If it doesn't have the NAND controller enabled, abort */
-	rdmsrl(MSR_DIVIL_BALL_OPTS, val);
-	if (val & PIN_OPT_IDE) {
-		printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
-		return -ENXIO;
-	}
-
-	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
-		rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);
-
-		if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))
-			err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
-	}
-
-	/* Register all devices together here. This means we can easily hack it to
-	   do mtdconcat etc. if we want to. */
-	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
-		if (cs553x_mtd[i]) {
-			/* If any devices registered, return success. Else the last error. */
-			mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
-						  NULL, 0);
-			err = 0;
-		}
-	}
-
-	return err;
-}
-
-module_init(cs553x_init);
-
-static void __exit cs553x_cleanup(void)
-{
-	int i;
-
-	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
-		struct mtd_info *mtd = cs553x_mtd[i];
-		struct nand_chip *this;
-		void __iomem *mmio_base;
-
-		if (!mtd)
-			continue;
-
-		this = mtd_to_nand(mtd);
-		mmio_base = this->IO_ADDR_R;
-
-		/* Release resources, unregister device */
-		nand_release(mtd);
-		kfree(mtd->name);
-		cs553x_mtd[i] = NULL;
-
-		/* unmap physical address */
-		iounmap(mmio_base);
-
-		/* Free the MTD device structure */
-		kfree(this);
-	}
-}
-
-module_exit(cs553x_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
deleted file mode 100644
index ccc8c43abcff..000000000000
--- a/drivers/mtd/nand/davinci_nand.c
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * davinci_nand.c - NAND Flash Driver for DaVinci family chips
- *
- * Copyright © 2006 Texas Instruments.
- *
- * Port to 2.6.23 Copyright © 2008 by:
- *   Sander Huijsen <Shuijsen@optelecom-nkf.com>
- *   Troy Kisky <troy.kisky@boundarydevices.com>
- *   Dirk Behme <Dirk.Behme@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-
-#include <linux/platform_data/mtd-davinci.h>
-#include <linux/platform_data/mtd-davinci-aemif.h>
-
-/*
- * This is a device driver for the NAND flash controller found on the
- * various DaVinci family chips.  It handles up to four SoC chipselects,
- * and some flavors of secondary chipselect (e.g. based on A12) as used
- * with multichip packages.
- *
- * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC
- * available on chips like the DM355 and OMAP-L137 and needed with the
- * more error-prone MLC NAND chips.
- *
- * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY
- * outputs in a "wire-AND" configuration, with no per-chip signals.
- */
-struct davinci_nand_info {
-	struct nand_chip	chip;
-
-	struct device		*dev;
-	struct clk		*clk;
-
-	bool			is_readmode;
-
-	void __iomem		*base;
-	void __iomem		*vaddr;
-
-	uint32_t		ioaddr;
-	uint32_t		current_cs;
-
-	uint32_t		mask_chipsel;
-	uint32_t		mask_ale;
-	uint32_t		mask_cle;
-
-	uint32_t		core_chipsel;
-
-	struct davinci_aemif_timing	*timing;
-};
-
-static DEFINE_SPINLOCK(davinci_nand_lock);
-static bool ecc4_busy;
-
-static inline struct davinci_nand_info *to_davinci_nand(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct davinci_nand_info, chip);
-}
-
-static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
-		int offset)
-{
-	return __raw_readl(info->base + offset);
-}
-
-static inline void davinci_nand_writel(struct davinci_nand_info *info,
-		int offset, unsigned long value)
-{
-	__raw_writel(value, info->base + offset);
-}
-
-/*----------------------------------------------------------------------*/
-
-/*
- * Access to hardware control lines:  ALE, CLE, secondary chipselect.
- */
-
-static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigned int ctrl)
-{
-	struct davinci_nand_info	*info = to_davinci_nand(mtd);
-	uint32_t			addr = info->current_cs;
-	struct nand_chip		*nand = mtd_to_nand(mtd);
-
-	/* Did the control lines change? */
-	if (ctrl & NAND_CTRL_CHANGE) {
-		if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE)
-			addr |= info->mask_cle;
-		else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
-			addr |= info->mask_ale;
-
-		nand->IO_ADDR_W = (void __iomem __force *)addr;
-	}
-
-	if (cmd != NAND_CMD_NONE)
-		iowrite8(cmd, nand->IO_ADDR_W);
-}
-
-static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct davinci_nand_info	*info = to_davinci_nand(mtd);
-	uint32_t			addr = info->ioaddr;
-
-	/* maybe kick in a second chipselect */
-	if (chip > 0)
-		addr |= info->mask_chipsel;
-	info->current_cs = addr;
-
-	info->chip.IO_ADDR_W = (void __iomem __force *)addr;
-	info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
-}
-
-/*----------------------------------------------------------------------*/
-
-/*
- * 1-bit hardware ECC ... context maintained for each core chipselect
- */
-
-static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
-{
-	struct davinci_nand_info *info = to_davinci_nand(mtd);
-
-	return davinci_nand_readl(info, NANDF1ECC_OFFSET
-			+ 4 * info->core_chipsel);
-}
-
-static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
-{
-	struct davinci_nand_info *info;
-	uint32_t nandcfr;
-	unsigned long flags;
-
-	info = to_davinci_nand(mtd);
-
-	/* Reset ECC hardware */
-	nand_davinci_readecc_1bit(mtd);
-
-	spin_lock_irqsave(&davinci_nand_lock, flags);
-
-	/* Restart ECC hardware */
-	nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET);
-	nandcfr |= BIT(8 + info->core_chipsel);
-	davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr);
-
-	spin_unlock_irqrestore(&davinci_nand_lock, flags);
-}
-
-/*
- * Read hardware ECC value and pack into three bytes
- */
-static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
-				      const u_char *dat, u_char *ecc_code)
-{
-	unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
-	unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
-
-	/* invert so that erased block ecc is correct */
-	ecc24 = ~ecc24;
-	ecc_code[0] = (u_char)(ecc24);
-	ecc_code[1] = (u_char)(ecc24 >> 8);
-	ecc_code[2] = (u_char)(ecc24 >> 16);
-
-	return 0;
-}
-
-static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
-				     u_char *read_ecc, u_char *calc_ecc)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
-					  (read_ecc[2] << 16);
-	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
-					  (calc_ecc[2] << 16);
-	uint32_t diff = eccCalc ^ eccNand;
-
-	if (diff) {
-		if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
-			/* Correctable error */
-			if ((diff >> (12 + 3)) < chip->ecc.size) {
-				dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
-				return 1;
-			} else {
-				return -EBADMSG;
-			}
-		} else if (!(diff & (diff - 1))) {
-			/* Single bit ECC error in the ECC itself,
-			 * nothing to fix */
-			return 1;
-		} else {
-			/* Uncorrectable error */
-			return -EBADMSG;
-		}
-
-	}
-	return 0;
-}
-
-/*----------------------------------------------------------------------*/
-
-/*
- * 4-bit hardware ECC ... context maintained over entire AEMIF
- *
- * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME
- * since that forces use of a problematic "infix OOB" layout.
- * Among other things, it trashes manufacturer bad block markers.
- * Also, and specific to this hardware, it ECC-protects the "prepad"
- * in the OOB ... while having ECC protection for parts of OOB would
- * seem useful, the current MTD stack sometimes wants to update the
- * OOB without recomputing ECC.
- */
-
-static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
-{
-	struct davinci_nand_info *info = to_davinci_nand(mtd);
-	unsigned long flags;
-	u32 val;
-
-	/* Reset ECC hardware */
-	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
-
-	spin_lock_irqsave(&davinci_nand_lock, flags);
-
-	/* Start 4-bit ECC calculation for read/write */
-	val = davinci_nand_readl(info, NANDFCR_OFFSET);
-	val &= ~(0x03 << 4);
-	val |= (info->core_chipsel << 4) | BIT(12);
-	davinci_nand_writel(info, NANDFCR_OFFSET, val);
-
-	info->is_readmode = (mode == NAND_ECC_READ);
-
-	spin_unlock_irqrestore(&davinci_nand_lock, flags);
-}
-
-/* Read raw ECC code after writing to NAND. */
-static void
-nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
-{
-	const u32 mask = 0x03ff03ff;
-
-	code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask;
-	code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask;
-	code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask;
-	code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask;
-}
-
-/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
-static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
-		const u_char *dat, u_char *ecc_code)
-{
-	struct davinci_nand_info *info = to_davinci_nand(mtd);
-	u32 raw_ecc[4], *p;
-	unsigned i;
-
-	/* After a read, terminate ECC calculation by a dummy read
-	 * of some 4-bit ECC register.  ECC covers everything that
-	 * was read; correct() just uses the hardware state, so
-	 * ecc_code is not needed.
-	 */
-	if (info->is_readmode) {
-		davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
-		return 0;
-	}
-
-	/* Pack eight raw 10-bit ecc values into ten bytes, making
-	 * two passes which each convert four values (in upper and
-	 * lower halves of two 32-bit words) into five bytes.  The
-	 * ROM boot loader uses this same packing scheme.
-	 */
-	nand_davinci_readecc_4bit(info, raw_ecc);
-	for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
-		*ecc_code++ =   p[0]        & 0xff;
-		*ecc_code++ = ((p[0] >>  8) & 0x03) | ((p[0] >> 14) & 0xfc);
-		*ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] <<  4) & 0xf0);
-		*ecc_code++ = ((p[1] >>  4) & 0x3f) | ((p[1] >> 10) & 0xc0);
-		*ecc_code++ =  (p[1] >> 18) & 0xff;
-	}
-
-	return 0;
-}
-
-/* Correct up to 4 bits in data we just read, using state left in the
- * hardware plus the ecc_code computed when it was first written.
- */
-static int nand_davinci_correct_4bit(struct mtd_info *mtd,
-		u_char *data, u_char *ecc_code, u_char *null)
-{
-	int i;
-	struct davinci_nand_info *info = to_davinci_nand(mtd);
-	unsigned short ecc10[8];
-	unsigned short *ecc16;
-	u32 syndrome[4];
-	u32 ecc_state;
-	unsigned num_errors, corrected;
-	unsigned long timeo;
-
-	/* Unpack ten bytes into eight 10 bit values.  We know we're
-	 * little-endian, and use type punning for less shifting/masking.
-	 */
-	if (WARN_ON(0x01 & (unsigned) ecc_code))
-		return -EINVAL;
-	ecc16 = (unsigned short *)ecc_code;
-
-	ecc10[0] =  (ecc16[0] >>  0) & 0x3ff;
-	ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0);
-	ecc10[2] =  (ecc16[1] >>  4) & 0x3ff;
-	ecc10[3] = ((ecc16[1] >> 14) & 0x3)  | ((ecc16[2] << 2) & 0x3fc);
-	ecc10[4] =  (ecc16[2] >>  8)         | ((ecc16[3] << 8) & 0x300);
-	ecc10[5] =  (ecc16[3] >>  2) & 0x3ff;
-	ecc10[6] = ((ecc16[3] >> 12) & 0xf)  | ((ecc16[4] << 4) & 0x3f0);
-	ecc10[7] =  (ecc16[4] >>  6) & 0x3ff;
-
-	/* Tell ECC controller about the expected ECC codes. */
-	for (i = 7; i >= 0; i--)
-		davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]);
-
-	/* Allow time for syndrome calculation ... then read it.
-	 * A syndrome of all zeroes 0 means no detected errors.
-	 */
-	davinci_nand_readl(info, NANDFSR_OFFSET);
-	nand_davinci_readecc_4bit(info, syndrome);
-	if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
-		return 0;
-
-	/*
-	 * Clear any previous address calculation by doing a dummy read of an
-	 * error address register.
-	 */
-	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
-
-	/* Start address calculation, and wait for it to complete.
-	 * We _could_ start reading more data while this is working,
-	 * to speed up the overall page read.
-	 */
-	davinci_nand_writel(info, NANDFCR_OFFSET,
-			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
-
-	/*
-	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
-	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
-	 * begin trying to poll for the state, you may fall right out of your
-	 * loop without any of the correction calculations having taken place.
-	 * The recommendation from the hardware team is to initially delay as
-	 * long as ECC_STATE reads less than 4. After that, ECC HW has entered
-	 * correction state.
-	 */
-	timeo = jiffies + usecs_to_jiffies(100);
-	do {
-		ecc_state = (davinci_nand_readl(info,
-				NANDFSR_OFFSET) >> 8) & 0x0f;
-		cpu_relax();
-	} while ((ecc_state < 4) && time_before(jiffies, timeo));
-
-	for (;;) {
-		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
-
-		switch ((fsr >> 8) & 0x0f) {
-		case 0:		/* no error, should not happen */
-			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
-			return 0;
-		case 1:		/* five or more errors detected */
-			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
-			return -EBADMSG;
-		case 2:		/* error addresses computed */
-		case 3:
-			num_errors = 1 + ((fsr >> 16) & 0x03);
-			goto correct;
-		default:	/* still working on it */
-			cpu_relax();
-			continue;
-		}
-	}
-
-correct:
-	/* correct each error */
-	for (i = 0, corrected = 0; i < num_errors; i++) {
-		int error_address, error_value;
-
-		if (i > 1) {
-			error_address = davinci_nand_readl(info,
-						NAND_ERR_ADD2_OFFSET);
-			error_value = davinci_nand_readl(info,
-						NAND_ERR_ERRVAL2_OFFSET);
-		} else {
-			error_address = davinci_nand_readl(info,
-						NAND_ERR_ADD1_OFFSET);
-			error_value = davinci_nand_readl(info,
-						NAND_ERR_ERRVAL1_OFFSET);
-		}
-
-		if (i & 1) {
-			error_address >>= 16;
-			error_value >>= 16;
-		}
-		error_address &= 0x3ff;
-		error_address = (512 + 7) - error_address;
-
-		if (error_address < 512) {
-			data[error_address] ^= error_value;
-			corrected++;
-		}
-	}
-
-	return corrected;
-}
-
-/*----------------------------------------------------------------------*/
-
-/*
- * NOTE:  NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's
- * how these chips are normally wired.  This translates to both 8 and 16
- * bit busses using ALE == BIT(3) in byte addresses, and CLE == BIT(4).
- *
- * For now we assume that configuration, or any other one which ignores
- * the two LSBs for NAND access ... so we can issue 32-bit reads/writes
- * and have that transparently morphed into multiple NAND operations.
- */
-static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
-		ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
-	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
-		ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
-	else
-		ioread8_rep(chip->IO_ADDR_R, buf, len);
-}
-
-static void nand_davinci_write_buf(struct mtd_info *mtd,
-		const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
-		iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
-	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
-		iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
-	else
-		iowrite8_rep(chip->IO_ADDR_R, buf, len);
-}
-
-/*
- * Check hardware register for wait status. Returns 1 if device is ready,
- * 0 if it is still busy.
- */
-static int nand_davinci_dev_ready(struct mtd_info *mtd)
-{
-	struct davinci_nand_info *info = to_davinci_nand(mtd);
-
-	return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
-}
-
-/*----------------------------------------------------------------------*/
-
-/* An ECC layout for using 4-bit ECC with small-page flash, storing
- * ten ECC bytes plus the manufacturer's bad block marker byte, and
- * and not overlapping the default BBT markers.
- */
-static int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
-				      struct mtd_oob_region *oobregion)
-{
-	if (section > 2)
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->offset = 0;
-		oobregion->length = 5;
-	} else if (section == 1) {
-		oobregion->offset = 6;
-		oobregion->length = 2;
-	} else {
-		oobregion->offset = 13;
-		oobregion->length = 3;
-	}
-
-	return 0;
-}
-
-static int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
-				       struct mtd_oob_region *oobregion)
-{
-	if (section > 1)
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->offset = 8;
-		oobregion->length = 5;
-	} else {
-		oobregion->offset = 16;
-		oobregion->length = mtd->oobsize - 16;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
-	.ecc = hwecc4_ooblayout_small_ecc,
-	.free = hwecc4_ooblayout_small_free,
-};
-
-#if defined(CONFIG_OF)
-static const struct of_device_id davinci_nand_of_match[] = {
-	{.compatible = "ti,davinci-nand", },
-	{.compatible = "ti,keystone-nand", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
-
-static struct davinci_nand_pdata
-	*nand_davinci_get_pdata(struct platform_device *pdev)
-{
-	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
-		struct davinci_nand_pdata *pdata;
-		const char *mode;
-		u32 prop;
-
-		pdata =  devm_kzalloc(&pdev->dev,
-				sizeof(struct davinci_nand_pdata),
-				GFP_KERNEL);
-		pdev->dev.platform_data = pdata;
-		if (!pdata)
-			return ERR_PTR(-ENOMEM);
-		if (!of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-chipselect", &prop))
-			pdev->id = prop;
-		else
-			return ERR_PTR(-EINVAL);
-
-		if (!of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-mask-ale", &prop))
-			pdata->mask_ale = prop;
-		if (!of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-mask-cle", &prop))
-			pdata->mask_cle = prop;
-		if (!of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-mask-chipsel", &prop))
-			pdata->mask_chipsel = prop;
-		if (!of_property_read_string(pdev->dev.of_node,
-			"ti,davinci-ecc-mode", &mode)) {
-			if (!strncmp("none", mode, 4))
-				pdata->ecc_mode = NAND_ECC_NONE;
-			if (!strncmp("soft", mode, 4))
-				pdata->ecc_mode = NAND_ECC_SOFT;
-			if (!strncmp("hw", mode, 2))
-				pdata->ecc_mode = NAND_ECC_HW;
-		}
-		if (!of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-ecc-bits", &prop))
-			pdata->ecc_bits = prop;
-
-		if (!of_property_read_u32(pdev->dev.of_node,
-			"ti,davinci-nand-buswidth", &prop) && prop == 16)
-			pdata->options |= NAND_BUSWIDTH_16;
-
-		if (of_property_read_bool(pdev->dev.of_node,
-			"ti,davinci-nand-use-bbt"))
-			pdata->bbt_options = NAND_BBT_USE_FLASH;
-
-		/*
-		 * Since kernel v4.8, this driver has been fixed to enable
-		 * use of 4-bit hardware ECC with subpages and verified on
-		 * TI's keystone EVMs (K2L, K2HK and K2E).
-		 * However, in the interest of not breaking systems using
-		 * existing UBI partitions, sub-page writes are not being
-		 * (re)enabled. If you want to use subpage writes on Keystone
-		 * platforms (i.e. do not have any existing UBI partitions),
-		 * then use "ti,davinci-nand" as the compatible in your
-		 * device-tree file.
-		 */
-		if (of_device_is_compatible(pdev->dev.of_node,
-					    "ti,keystone-nand")) {
-			pdata->options |= NAND_NO_SUBPAGE_WRITE;
-		}
-	}
-
-	return dev_get_platdata(&pdev->dev);
-}
-#else
-static struct davinci_nand_pdata
-	*nand_davinci_get_pdata(struct platform_device *pdev)
-{
-	return dev_get_platdata(&pdev->dev);
-}
-#endif
-
-static int nand_davinci_probe(struct platform_device *pdev)
-{
-	struct davinci_nand_pdata	*pdata;
-	struct davinci_nand_info	*info;
-	struct resource			*res1;
-	struct resource			*res2;
-	void __iomem			*vaddr;
-	void __iomem			*base;
-	int				ret;
-	uint32_t			val;
-	struct mtd_info			*mtd;
-
-	pdata = nand_davinci_get_pdata(pdev);
-	if (IS_ERR(pdata))
-		return PTR_ERR(pdata);
-
-	/* insist on board-specific configuration */
-	if (!pdata)
-		return -ENODEV;
-
-	/* which external chipselect will we be managing? */
-	if (pdev->id < 0 || pdev->id > 3)
-		return -ENODEV;
-
-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	platform_set_drvdata(pdev, info);
-
-	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res1 || !res2) {
-		dev_err(&pdev->dev, "resource missing\n");
-		return -EINVAL;
-	}
-
-	vaddr = devm_ioremap_resource(&pdev->dev, res1);
-	if (IS_ERR(vaddr))
-		return PTR_ERR(vaddr);
-
-	/*
-	 * This registers range is used to setup NAND settings. In case with
-	 * TI AEMIF driver, the same memory address range is requested already
-	 * by AEMIF, so we cannot request it twice, just ioremap.
-	 * The AEMIF and NAND drivers not use the same registers in this range.
-	 */
-	base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
-	if (!base) {
-		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
-		return -EADDRNOTAVAIL;
-	}
-
-	info->dev		= &pdev->dev;
-	info->base		= base;
-	info->vaddr		= vaddr;
-
-	mtd			= nand_to_mtd(&info->chip);
-	mtd->dev.parent		= &pdev->dev;
-	nand_set_flash_node(&info->chip, pdev->dev.of_node);
-
-	info->chip.IO_ADDR_R	= vaddr;
-	info->chip.IO_ADDR_W	= vaddr;
-	info->chip.chip_delay	= 0;
-	info->chip.select_chip	= nand_davinci_select_chip;
-
-	/* options such as NAND_BBT_USE_FLASH */
-	info->chip.bbt_options	= pdata->bbt_options;
-	/* options such as 16-bit widths */
-	info->chip.options	= pdata->options;
-	info->chip.bbt_td	= pdata->bbt_td;
-	info->chip.bbt_md	= pdata->bbt_md;
-	info->timing		= pdata->timing;
-
-	info->ioaddr		= (uint32_t __force) vaddr;
-
-	info->current_cs	= info->ioaddr;
-	info->core_chipsel	= pdev->id;
-	info->mask_chipsel	= pdata->mask_chipsel;
-
-	/* use nandboot-capable ALE/CLE masks by default */
-	info->mask_ale		= pdata->mask_ale ? : MASK_ALE;
-	info->mask_cle		= pdata->mask_cle ? : MASK_CLE;
-
-	/* Set address of hardware control function */
-	info->chip.cmd_ctrl	= nand_davinci_hwcontrol;
-	info->chip.dev_ready	= nand_davinci_dev_ready;
-
-	/* Speed up buffer I/O */
-	info->chip.read_buf     = nand_davinci_read_buf;
-	info->chip.write_buf    = nand_davinci_write_buf;
-
-	/* Use board-specific ECC config */
-	info->chip.ecc.mode	= pdata->ecc_mode;
-
-	ret = -EINVAL;
-
-	info->clk = devm_clk_get(&pdev->dev, "aemif");
-	if (IS_ERR(info->clk)) {
-		ret = PTR_ERR(info->clk);
-		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
-		return ret;
-	}
-
-	ret = clk_prepare_enable(info->clk);
-	if (ret < 0) {
-		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
-			ret);
-		goto err_clk_enable;
-	}
-
-	spin_lock_irq(&davinci_nand_lock);
-
-	/* put CSxNAND into NAND mode */
-	val = davinci_nand_readl(info, NANDFCR_OFFSET);
-	val |= BIT(info->core_chipsel);
-	davinci_nand_writel(info, NANDFCR_OFFSET, val);
-
-	spin_unlock_irq(&davinci_nand_lock);
-
-	/* Scan to find existence of the device(s) */
-	ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
-	if (ret < 0) {
-		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
-		goto err;
-	}
-
-	switch (info->chip.ecc.mode) {
-	case NAND_ECC_NONE:
-		pdata->ecc_bits = 0;
-		break;
-	case NAND_ECC_SOFT:
-		pdata->ecc_bits = 0;
-		/*
-		 * This driver expects Hamming based ECC when ecc_mode is set
-		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
-		 * avoid adding an extra ->ecc_algo field to
-		 * davinci_nand_pdata.
-		 */
-		info->chip.ecc.algo = NAND_ECC_HAMMING;
-		break;
-	case NAND_ECC_HW:
-		if (pdata->ecc_bits == 4) {
-			/* No sanity checks:  CPUs must support this,
-			 * and the chips may not use NAND_BUSWIDTH_16.
-			 */
-
-			/* No sharing 4-bit hardware between chipselects yet */
-			spin_lock_irq(&davinci_nand_lock);
-			if (ecc4_busy)
-				ret = -EBUSY;
-			else
-				ecc4_busy = true;
-			spin_unlock_irq(&davinci_nand_lock);
-
-			if (ret == -EBUSY)
-				return ret;
-
-			info->chip.ecc.calculate = nand_davinci_calculate_4bit;
-			info->chip.ecc.correct = nand_davinci_correct_4bit;
-			info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
-			info->chip.ecc.bytes = 10;
-			info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
-			info->chip.ecc.algo = NAND_ECC_BCH;
-		} else {
-			/* 1bit ecc hamming */
-			info->chip.ecc.calculate = nand_davinci_calculate_1bit;
-			info->chip.ecc.correct = nand_davinci_correct_1bit;
-			info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
-			info->chip.ecc.bytes = 3;
-			info->chip.ecc.algo = NAND_ECC_HAMMING;
-		}
-		info->chip.ecc.size = 512;
-		info->chip.ecc.strength = pdata->ecc_bits;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* Update ECC layout if needed ... for 1-bit HW ECC, the default
-	 * is OK, but it allocates 6 bytes when only 3 are needed (for
-	 * each 512 bytes).  For the 4-bit HW ECC, that default is not
-	 * usable:  10 bytes are needed, not 6.
-	 */
-	if (pdata->ecc_bits == 4) {
-		int	chunks = mtd->writesize / 512;
-
-		if (!chunks || mtd->oobsize < 16) {
-			dev_dbg(&pdev->dev, "too small\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		/* For small page chips, preserve the manufacturer's
-		 * badblock marking data ... and make sure a flash BBT
-		 * table marker fits in the free bytes.
-		 */
-		if (chunks == 1) {
-			mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
-		} else if (chunks == 4 || chunks == 8) {
-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-			info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
-		} else {
-			ret = -EIO;
-			goto err;
-		}
-	}
-
-	ret = nand_scan_tail(mtd);
-	if (ret < 0)
-		goto err;
-
-	if (pdata->parts)
-		ret = mtd_device_parse_register(mtd, NULL, NULL,
-					pdata->parts, pdata->nr_parts);
-	else
-		ret = mtd_device_register(mtd, NULL, 0);
-	if (ret < 0)
-		goto err;
-
-	val = davinci_nand_readl(info, NRCSR_OFFSET);
-	dev_info(&pdev->dev, "controller rev. %d.%d\n",
-	       (val >> 8) & 0xff, val & 0xff);
-
-	return 0;
-
-err:
-	clk_disable_unprepare(info->clk);
-
-err_clk_enable:
-	spin_lock_irq(&davinci_nand_lock);
-	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
-		ecc4_busy = false;
-	spin_unlock_irq(&davinci_nand_lock);
-	return ret;
-}
-
-static int nand_davinci_remove(struct platform_device *pdev)
-{
-	struct davinci_nand_info *info = platform_get_drvdata(pdev);
-
-	spin_lock_irq(&davinci_nand_lock);
-	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
-		ecc4_busy = false;
-	spin_unlock_irq(&davinci_nand_lock);
-
-	nand_release(nand_to_mtd(&info->chip));
-
-	clk_disable_unprepare(info->clk);
-
-	return 0;
-}
-
-static struct platform_driver nand_davinci_driver = {
-	.probe		= nand_davinci_probe,
-	.remove		= nand_davinci_remove,
-	.driver		= {
-		.name	= "davinci_nand",
-		.of_match_table = of_match_ptr(davinci_nand_of_match),
-	},
-};
-MODULE_ALIAS("platform:davinci_nand");
-
-module_platform_driver(nand_davinci_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("Davinci NAND flash driver");
-
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
deleted file mode 100644
index 313c7f50621b..000000000000
--- a/drivers/mtd/nand/denali.c
+++ /dev/null
@@ -1,1408 +0,0 @@
-/*
- * NAND Flash Controller Device Driver
- * Copyright © 2009-2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/bitfield.h>
-#include <linux/completion.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#include "denali.h"
-
-MODULE_LICENSE("GPL");
-
-#define DENALI_NAND_NAME    "denali-nand"
-
-/* for Indexed Addressing */
-#define DENALI_INDEXED_CTRL	0x00
-#define DENALI_INDEXED_DATA	0x10
-
-#define DENALI_MAP00		(0 << 26)	/* direct access to buffer */
-#define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
-#define DENALI_MAP10		(2 << 26)	/* high-level control plane */
-#define DENALI_MAP11		(3 << 26)	/* direct controller access */
-
-/* MAP11 access cycle type */
-#define DENALI_MAP11_CMD	((DENALI_MAP11) | 0)	/* command cycle */
-#define DENALI_MAP11_ADDR	((DENALI_MAP11) | 1)	/* address cycle */
-#define DENALI_MAP11_DATA	((DENALI_MAP11) | 2)	/* data cycle */
-
-/* MAP10 commands */
-#define DENALI_ERASE		0x01
-
-#define DENALI_BANK(denali)	((denali)->active_bank << 24)
-
-#define DENALI_INVALID_BANK	-1
-#define DENALI_NR_BANKS		4
-
-/*
- * The bus interface clock, clk_x, is phase aligned with the core clock.  The
- * clk_x is an integral multiple N of the core clk.  The value N is configured
- * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
- * to the largest value to make it work with any possible configuration.
- */
-#define DENALI_CLK_X_MULT	6
-
-static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
-}
-
-/*
- * Direct Addressing - the slave address forms the control information (command
- * type, bank, block, and page address).  The slave data is the actual data to
- * be transferred.  This mode requires 28 bits of address region allocated.
- */
-static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr)
-{
-	return ioread32(denali->host + addr);
-}
-
-static void denali_direct_write(struct denali_nand_info *denali, u32 addr,
-				u32 data)
-{
-	iowrite32(data, denali->host + addr);
-}
-
-/*
- * Indexed Addressing - address translation module intervenes in passing the
- * control information.  This mode reduces the required address range.  The
- * control information and transferred data are latched by the registers in
- * the translation module.
- */
-static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr)
-{
-	iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
-	return ioread32(denali->host + DENALI_INDEXED_DATA);
-}
-
-static void denali_indexed_write(struct denali_nand_info *denali, u32 addr,
-				 u32 data)
-{
-	iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
-	iowrite32(data, denali->host + DENALI_INDEXED_DATA);
-}
-
-/*
- * Use the configuration feature register to determine the maximum number of
- * banks that the hardware supports.
- */
-static void denali_detect_max_banks(struct denali_nand_info *denali)
-{
-	uint32_t features = ioread32(denali->reg + FEATURES);
-
-	denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features);
-
-	/* the encoding changed from rev 5.0 to 5.1 */
-	if (denali->revision < 0x0501)
-		denali->max_banks <<= 1;
-}
-
-static void denali_enable_irq(struct denali_nand_info *denali)
-{
-	int i;
-
-	for (i = 0; i < DENALI_NR_BANKS; i++)
-		iowrite32(U32_MAX, denali->reg + INTR_EN(i));
-	iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
-}
-
-static void denali_disable_irq(struct denali_nand_info *denali)
-{
-	int i;
-
-	for (i = 0; i < DENALI_NR_BANKS; i++)
-		iowrite32(0, denali->reg + INTR_EN(i));
-	iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
-}
-
-static void denali_clear_irq(struct denali_nand_info *denali,
-			     int bank, uint32_t irq_status)
-{
-	/* write one to clear bits */
-	iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
-}
-
-static void denali_clear_irq_all(struct denali_nand_info *denali)
-{
-	int i;
-
-	for (i = 0; i < DENALI_NR_BANKS; i++)
-		denali_clear_irq(denali, i, U32_MAX);
-}
-
-static irqreturn_t denali_isr(int irq, void *dev_id)
-{
-	struct denali_nand_info *denali = dev_id;
-	irqreturn_t ret = IRQ_NONE;
-	uint32_t irq_status;
-	int i;
-
-	spin_lock(&denali->irq_lock);
-
-	for (i = 0; i < DENALI_NR_BANKS; i++) {
-		irq_status = ioread32(denali->reg + INTR_STATUS(i));
-		if (irq_status)
-			ret = IRQ_HANDLED;
-
-		denali_clear_irq(denali, i, irq_status);
-
-		if (i != denali->active_bank)
-			continue;
-
-		denali->irq_status |= irq_status;
-
-		if (denali->irq_status & denali->irq_mask)
-			complete(&denali->complete);
-	}
-
-	spin_unlock(&denali->irq_lock);
-
-	return ret;
-}
-
-static void denali_reset_irq(struct denali_nand_info *denali)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&denali->irq_lock, flags);
-	denali->irq_status = 0;
-	denali->irq_mask = 0;
-	spin_unlock_irqrestore(&denali->irq_lock, flags);
-}
-
-static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
-				    uint32_t irq_mask)
-{
-	unsigned long time_left, flags;
-	uint32_t irq_status;
-
-	spin_lock_irqsave(&denali->irq_lock, flags);
-
-	irq_status = denali->irq_status;
-
-	if (irq_mask & irq_status) {
-		/* return immediately if the IRQ has already happened. */
-		spin_unlock_irqrestore(&denali->irq_lock, flags);
-		return irq_status;
-	}
-
-	denali->irq_mask = irq_mask;
-	reinit_completion(&denali->complete);
-	spin_unlock_irqrestore(&denali->irq_lock, flags);
-
-	time_left = wait_for_completion_timeout(&denali->complete,
-						msecs_to_jiffies(1000));
-	if (!time_left) {
-		dev_err(denali->dev, "timeout while waiting for irq 0x%x\n",
-			irq_mask);
-		return 0;
-	}
-
-	return denali->irq_status;
-}
-
-static uint32_t denali_check_irq(struct denali_nand_info *denali)
-{
-	unsigned long flags;
-	uint32_t irq_status;
-
-	spin_lock_irqsave(&denali->irq_lock, flags);
-	irq_status = denali->irq_status;
-	spin_unlock_irqrestore(&denali->irq_lock, flags);
-
-	return irq_status;
-}
-
-static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-	int i;
-
-	for (i = 0; i < len; i++)
-		buf[i] = denali->host_read(denali, addr);
-}
-
-static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-	int i;
-
-	for (i = 0; i < len; i++)
-		denali->host_write(denali, addr, buf[i]);
-}
-
-static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-	uint16_t *buf16 = (uint16_t *)buf;
-	int i;
-
-	for (i = 0; i < len / 2; i++)
-		buf16[i] = denali->host_read(denali, addr);
-}
-
-static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
-			       int len)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
-	const uint16_t *buf16 = (const uint16_t *)buf;
-	int i;
-
-	for (i = 0; i < len / 2; i++)
-		denali->host_write(denali, addr, buf16[i]);
-}
-
-static uint8_t denali_read_byte(struct mtd_info *mtd)
-{
-	uint8_t byte;
-
-	denali_read_buf(mtd, &byte, 1);
-
-	return byte;
-}
-
-static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
-	denali_write_buf(mtd, &byte, 1);
-}
-
-static uint16_t denali_read_word(struct mtd_info *mtd)
-{
-	uint16_t word;
-
-	denali_read_buf16(mtd, (uint8_t *)&word, 2);
-
-	return word;
-}
-
-static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t type;
-
-	if (ctrl & NAND_CLE)
-		type = DENALI_MAP11_CMD;
-	else if (ctrl & NAND_ALE)
-		type = DENALI_MAP11_ADDR;
-	else
-		return;
-
-	/*
-	 * Some commands are followed by chip->dev_ready or chip->waitfunc.
-	 * irq_status must be cleared here to catch the R/B# interrupt later.
-	 */
-	if (ctrl & NAND_CTRL_CHANGE)
-		denali_reset_irq(denali);
-
-	denali->host_write(denali, DENALI_BANK(denali) | type, dat);
-}
-
-static int denali_dev_ready(struct mtd_info *mtd)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-
-	return !!(denali_check_irq(denali) & INTR__INT_ACT);
-}
-
-static int denali_check_erased_page(struct mtd_info *mtd,
-				    struct nand_chip *chip, uint8_t *buf,
-				    unsigned long uncor_ecc_flags,
-				    unsigned int max_bitflips)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes;
-	int ecc_steps = chip->ecc.steps;
-	int ecc_size = chip->ecc.size;
-	int ecc_bytes = chip->ecc.bytes;
-	int i, stat;
-
-	for (i = 0; i < ecc_steps; i++) {
-		if (!(uncor_ecc_flags & BIT(i)))
-			continue;
-
-		stat = nand_check_erased_ecc_chunk(buf, ecc_size,
-						  ecc_code, ecc_bytes,
-						  NULL, 0,
-						  chip->ecc.strength);
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-
-		buf += ecc_size;
-		ecc_code += ecc_bytes;
-	}
-
-	return max_bitflips;
-}
-
-static int denali_hw_ecc_fixup(struct mtd_info *mtd,
-			       struct denali_nand_info *denali,
-			       unsigned long *uncor_ecc_flags)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int bank = denali->active_bank;
-	uint32_t ecc_cor;
-	unsigned int max_bitflips;
-
-	ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
-	ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
-
-	if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
-		/*
-		 * This flag is set when uncorrectable error occurs at least in
-		 * one ECC sector.  We can not know "how many sectors", or
-		 * "which sector(s)".  We need erase-page check for all sectors.
-		 */
-		*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
-		return 0;
-	}
-
-	max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor);
-
-	/*
-	 * The register holds the maximum of per-sector corrected bitflips.
-	 * This is suitable for the return value of the ->read_page() callback.
-	 * Unfortunately, we can not know the total number of corrected bits in
-	 * the page.  Increase the stats by max_bitflips. (compromised solution)
-	 */
-	mtd->ecc_stats.corrected += max_bitflips;
-
-	return max_bitflips;
-}
-
-static int denali_sw_ecc_fixup(struct mtd_info *mtd,
-			       struct denali_nand_info *denali,
-			       unsigned long *uncor_ecc_flags, uint8_t *buf)
-{
-	unsigned int ecc_size = denali->nand.ecc.size;
-	unsigned int bitflips = 0;
-	unsigned int max_bitflips = 0;
-	uint32_t err_addr, err_cor_info;
-	unsigned int err_byte, err_sector, err_device;
-	uint8_t err_cor_value;
-	unsigned int prev_sector = 0;
-	uint32_t irq_status;
-
-	denali_reset_irq(denali);
-
-	do {
-		err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS);
-		err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr);
-		err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr);
-
-		err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO);
-		err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE,
-					  err_cor_info);
-		err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE,
-				       err_cor_info);
-
-		/* reset the bitflip counter when crossing ECC sector */
-		if (err_sector != prev_sector)
-			bitflips = 0;
-
-		if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) {
-			/*
-			 * Check later if this is a real ECC error, or
-			 * an erased sector.
-			 */
-			*uncor_ecc_flags |= BIT(err_sector);
-		} else if (err_byte < ecc_size) {
-			/*
-			 * If err_byte is larger than ecc_size, means error
-			 * happened in OOB, so we ignore it. It's no need for
-			 * us to correct it err_device is represented the NAND
-			 * error bits are happened in if there are more than
-			 * one NAND connected.
-			 */
-			int offset;
-			unsigned int flips_in_byte;
-
-			offset = (err_sector * ecc_size + err_byte) *
-					denali->devs_per_cs + err_device;
-
-			/* correct the ECC error */
-			flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
-			buf[offset] ^= err_cor_value;
-			mtd->ecc_stats.corrected += flips_in_byte;
-			bitflips += flips_in_byte;
-
-			max_bitflips = max(max_bitflips, bitflips);
-		}
-
-		prev_sector = err_sector;
-	} while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR));
-
-	/*
-	 * Once handle all ECC errors, controller will trigger an
-	 * ECC_TRANSACTION_DONE interrupt.
-	 */
-	irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE);
-	if (!(irq_status & INTR__ECC_TRANSACTION_DONE))
-		return -EIO;
-
-	return max_bitflips;
-}
-
-static void denali_setup_dma64(struct denali_nand_info *denali,
-			       dma_addr_t dma_addr, int page, int write)
-{
-	uint32_t mode;
-	const int page_count = 1;
-
-	mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
-
-	/* DMA is a three step process */
-
-	/*
-	 * 1. setup transfer type, interrupt when complete,
-	 *    burst len = 64 bytes, the number of pages
-	 */
-	denali->host_write(denali, mode,
-			   0x01002000 | (64 << 16) | (write << 8) | page_count);
-
-	/* 2. set memory low address */
-	denali->host_write(denali, mode, lower_32_bits(dma_addr));
-
-	/* 3. set memory high address */
-	denali->host_write(denali, mode, upper_32_bits(dma_addr));
-}
-
-static void denali_setup_dma32(struct denali_nand_info *denali,
-			       dma_addr_t dma_addr, int page, int write)
-{
-	uint32_t mode;
-	const int page_count = 1;
-
-	mode = DENALI_MAP10 | DENALI_BANK(denali);
-
-	/* DMA is a four step process */
-
-	/* 1. setup transfer type and # of pages */
-	denali->host_write(denali, mode | page,
-			   0x2000 | (write << 8) | page_count);
-
-	/* 2. set memory high address bits 23:8 */
-	denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
-
-	/* 3. set memory low address bits 23:8 */
-	denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300);
-
-	/* 4. interrupt when complete, burst len = 64 bytes */
-	denali->host_write(denali, mode | 0x14000, 0x2400);
-}
-
-static int denali_pio_read(struct denali_nand_info *denali, void *buf,
-			   size_t size, int page, int raw)
-{
-	u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
-	uint32_t *buf32 = (uint32_t *)buf;
-	uint32_t irq_status, ecc_err_mask;
-	int i;
-
-	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
-		ecc_err_mask = INTR__ECC_UNCOR_ERR;
-	else
-		ecc_err_mask = INTR__ECC_ERR;
-
-	denali_reset_irq(denali);
-
-	for (i = 0; i < size / 4; i++)
-		*buf32++ = denali->host_read(denali, addr);
-
-	irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
-	if (!(irq_status & INTR__PAGE_XFER_INC))
-		return -EIO;
-
-	if (irq_status & INTR__ERASED_PAGE)
-		memset(buf, 0xff, size);
-
-	return irq_status & ecc_err_mask ? -EBADMSG : 0;
-}
-
-static int denali_pio_write(struct denali_nand_info *denali,
-			    const void *buf, size_t size, int page, int raw)
-{
-	u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
-	const uint32_t *buf32 = (uint32_t *)buf;
-	uint32_t irq_status;
-	int i;
-
-	denali_reset_irq(denali);
-
-	for (i = 0; i < size / 4; i++)
-		denali->host_write(denali, addr, *buf32++);
-
-	irq_status = denali_wait_for_irq(denali,
-				INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
-	if (!(irq_status & INTR__PROGRAM_COMP))
-		return -EIO;
-
-	return 0;
-}
-
-static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
-			   size_t size, int page, int raw, int write)
-{
-	if (write)
-		return denali_pio_write(denali, buf, size, page, raw);
-	else
-		return denali_pio_read(denali, buf, size, page, raw);
-}
-
-static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
-			   size_t size, int page, int raw, int write)
-{
-	dma_addr_t dma_addr;
-	uint32_t irq_mask, irq_status, ecc_err_mask;
-	enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-	int ret = 0;
-
-	dma_addr = dma_map_single(denali->dev, buf, size, dir);
-	if (dma_mapping_error(denali->dev, dma_addr)) {
-		dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
-		return denali_pio_xfer(denali, buf, size, page, raw, write);
-	}
-
-	if (write) {
-		/*
-		 * INTR__PROGRAM_COMP is never asserted for the DMA transfer.
-		 * We can use INTR__DMA_CMD_COMP instead.  This flag is asserted
-		 * when the page program is completed.
-		 */
-		irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
-		ecc_err_mask = 0;
-	} else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) {
-		irq_mask = INTR__DMA_CMD_COMP;
-		ecc_err_mask = INTR__ECC_UNCOR_ERR;
-	} else {
-		irq_mask = INTR__DMA_CMD_COMP;
-		ecc_err_mask = INTR__ECC_ERR;
-	}
-
-	iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
-
-	denali_reset_irq(denali);
-	denali->setup_dma(denali, dma_addr, page, write);
-
-	irq_status = denali_wait_for_irq(denali, irq_mask);
-	if (!(irq_status & INTR__DMA_CMD_COMP))
-		ret = -EIO;
-	else if (irq_status & ecc_err_mask)
-		ret = -EBADMSG;
-
-	iowrite32(0, denali->reg + DMA_ENABLE);
-
-	dma_unmap_single(denali->dev, dma_addr, size, dir);
-
-	if (irq_status & INTR__ERASED_PAGE)
-		memset(buf, 0xff, size);
-
-	return ret;
-}
-
-static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
-			    size_t size, int page, int raw, int write)
-{
-	iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE);
-	iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0,
-		  denali->reg + TRANSFER_SPARE_REG);
-
-	if (denali->dma_avail)
-		return denali_dma_xfer(denali, buf, size, page, raw, write);
-	else
-		return denali_pio_xfer(denali, buf, size, page, raw, write);
-}
-
-static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
-			    int page, int write)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	int writesize = mtd->writesize;
-	int oobsize = mtd->oobsize;
-	uint8_t *bufpoi = chip->oob_poi;
-	int ecc_steps = chip->ecc.steps;
-	int ecc_size = chip->ecc.size;
-	int ecc_bytes = chip->ecc.bytes;
-	int oob_skip = denali->oob_skip_bytes;
-	size_t size = writesize + oobsize;
-	int i, pos, len;
-
-	/* BBM at the beginning of the OOB area */
-	if (write)
-		nand_prog_page_begin_op(chip, page, writesize, bufpoi,
-					oob_skip);
-	else
-		nand_read_page_op(chip, page, writesize, bufpoi, oob_skip);
-	bufpoi += oob_skip;
-
-	/* OOB ECC */
-	for (i = 0; i < ecc_steps; i++) {
-		pos = ecc_size + i * (ecc_size + ecc_bytes);
-		len = ecc_bytes;
-
-		if (pos >= writesize)
-			pos += oob_skip;
-		else if (pos + len > writesize)
-			len = writesize - pos;
-
-		if (write)
-			nand_change_write_column_op(chip, pos, bufpoi, len,
-						    false);
-		else
-			nand_change_read_column_op(chip, pos, bufpoi, len,
-						   false);
-		bufpoi += len;
-		if (len < ecc_bytes) {
-			len = ecc_bytes - len;
-			if (write)
-				nand_change_write_column_op(chip, writesize +
-							    oob_skip, bufpoi,
-							    len, false);
-			else
-				nand_change_read_column_op(chip, writesize +
-							   oob_skip, bufpoi,
-							   len, false);
-			bufpoi += len;
-		}
-	}
-
-	/* OOB free */
-	len = oobsize - (bufpoi - chip->oob_poi);
-	if (write)
-		nand_change_write_column_op(chip, size - len, bufpoi, len,
-					    false);
-	else
-		nand_change_read_column_op(chip, size - len, bufpoi, len,
-					   false);
-}
-
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	int writesize = mtd->writesize;
-	int oobsize = mtd->oobsize;
-	int ecc_steps = chip->ecc.steps;
-	int ecc_size = chip->ecc.size;
-	int ecc_bytes = chip->ecc.bytes;
-	void *tmp_buf = denali->buf;
-	int oob_skip = denali->oob_skip_bytes;
-	size_t size = writesize + oobsize;
-	int ret, i, pos, len;
-
-	ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0);
-	if (ret)
-		return ret;
-
-	/* Arrange the buffer for syndrome payload/ecc layout */
-	if (buf) {
-		for (i = 0; i < ecc_steps; i++) {
-			pos = i * (ecc_size + ecc_bytes);
-			len = ecc_size;
-
-			if (pos >= writesize)
-				pos += oob_skip;
-			else if (pos + len > writesize)
-				len = writesize - pos;
-
-			memcpy(buf, tmp_buf + pos, len);
-			buf += len;
-			if (len < ecc_size) {
-				len = ecc_size - len;
-				memcpy(buf, tmp_buf + writesize + oob_skip,
-				       len);
-				buf += len;
-			}
-		}
-	}
-
-	if (oob_required) {
-		uint8_t *oob = chip->oob_poi;
-
-		/* BBM at the beginning of the OOB area */
-		memcpy(oob, tmp_buf + writesize, oob_skip);
-		oob += oob_skip;
-
-		/* OOB ECC */
-		for (i = 0; i < ecc_steps; i++) {
-			pos = ecc_size + i * (ecc_size + ecc_bytes);
-			len = ecc_bytes;
-
-			if (pos >= writesize)
-				pos += oob_skip;
-			else if (pos + len > writesize)
-				len = writesize - pos;
-
-			memcpy(oob, tmp_buf + pos, len);
-			oob += len;
-			if (len < ecc_bytes) {
-				len = ecc_bytes - len;
-				memcpy(oob, tmp_buf + writesize + oob_skip,
-				       len);
-				oob += len;
-			}
-		}
-
-		/* OOB free */
-		len = oobsize - (oob - chip->oob_poi);
-		memcpy(oob, tmp_buf + size - len, len);
-	}
-
-	return 0;
-}
-
-static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			   int page)
-{
-	denali_oob_xfer(mtd, chip, page, 0);
-
-	return 0;
-}
-
-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			    int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-
-	denali_reset_irq(denali);
-
-	denali_oob_xfer(mtd, chip, page, 1);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			    uint8_t *buf, int oob_required, int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	unsigned long uncor_ecc_flags = 0;
-	int stat = 0;
-	int ret;
-
-	ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
-	if (ret && ret != -EBADMSG)
-		return ret;
-
-	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
-		stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
-	else if (ret == -EBADMSG)
-		stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
-
-	if (stat < 0)
-		return stat;
-
-	if (uncor_ecc_flags) {
-		ret = denali_read_oob(mtd, chip, page);
-		if (ret)
-			return ret;
-
-		stat = denali_check_erased_page(mtd, chip, buf,
-						uncor_ecc_flags, stat);
-	}
-
-	return stat;
-}
-
-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				 const uint8_t *buf, int oob_required, int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	int writesize = mtd->writesize;
-	int oobsize = mtd->oobsize;
-	int ecc_steps = chip->ecc.steps;
-	int ecc_size = chip->ecc.size;
-	int ecc_bytes = chip->ecc.bytes;
-	void *tmp_buf = denali->buf;
-	int oob_skip = denali->oob_skip_bytes;
-	size_t size = writesize + oobsize;
-	int i, pos, len;
-
-	/*
-	 * Fill the buffer with 0xff first except the full page transfer.
-	 * This simplifies the logic.
-	 */
-	if (!buf || !oob_required)
-		memset(tmp_buf, 0xff, size);
-
-	/* Arrange the buffer for syndrome payload/ecc layout */
-	if (buf) {
-		for (i = 0; i < ecc_steps; i++) {
-			pos = i * (ecc_size + ecc_bytes);
-			len = ecc_size;
-
-			if (pos >= writesize)
-				pos += oob_skip;
-			else if (pos + len > writesize)
-				len = writesize - pos;
-
-			memcpy(tmp_buf + pos, buf, len);
-			buf += len;
-			if (len < ecc_size) {
-				len = ecc_size - len;
-				memcpy(tmp_buf + writesize + oob_skip, buf,
-				       len);
-				buf += len;
-			}
-		}
-	}
-
-	if (oob_required) {
-		const uint8_t *oob = chip->oob_poi;
-
-		/* BBM at the beginning of the OOB area */
-		memcpy(tmp_buf + writesize, oob, oob_skip);
-		oob += oob_skip;
-
-		/* OOB ECC */
-		for (i = 0; i < ecc_steps; i++) {
-			pos = ecc_size + i * (ecc_size + ecc_bytes);
-			len = ecc_bytes;
-
-			if (pos >= writesize)
-				pos += oob_skip;
-			else if (pos + len > writesize)
-				len = writesize - pos;
-
-			memcpy(tmp_buf + pos, oob, len);
-			oob += len;
-			if (len < ecc_bytes) {
-				len = ecc_bytes - len;
-				memcpy(tmp_buf + writesize + oob_skip, oob,
-				       len);
-				oob += len;
-			}
-		}
-
-		/* OOB free */
-		len = oobsize - (oob - chip->oob_poi);
-		memcpy(tmp_buf + size - len, oob, len);
-	}
-
-	return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
-}
-
-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-			     const uint8_t *buf, int oob_required, int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-
-	return denali_data_xfer(denali, (void *)buf, mtd->writesize,
-				page, 0, 1);
-}
-
-static void denali_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-
-	denali->active_bank = chip;
-}
-
-static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t irq_status;
-
-	/* R/B# pin transitioned from low to high? */
-	irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
-
-	return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
-}
-
-static int denali_erase(struct mtd_info *mtd, int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t irq_status;
-
-	denali_reset_irq(denali);
-
-	denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
-			   DENALI_ERASE);
-
-	/* wait for erase to complete or failure to occur */
-	irq_status = denali_wait_for_irq(denali,
-					 INTR__ERASE_COMP | INTR__ERASE_FAIL);
-
-	return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
-}
-
-static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
-				       const struct nand_data_interface *conf)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	const struct nand_sdr_timings *timings;
-	unsigned long t_clk;
-	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
-	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
-	int addr_2_data_mask;
-	uint32_t tmp;
-
-	timings = nand_get_sdr_timings(conf);
-	if (IS_ERR(timings))
-		return PTR_ERR(timings);
-
-	/* clk_x period in picoseconds */
-	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
-	if (!t_clk)
-		return -EINVAL;
-
-	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	/* tREA -> ACC_CLKS */
-	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
-	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
-
-	tmp = ioread32(denali->reg + ACC_CLKS);
-	tmp &= ~ACC_CLKS__VALUE;
-	tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks);
-	iowrite32(tmp, denali->reg + ACC_CLKS);
-
-	/* tRWH -> RE_2_WE */
-	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
-	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
-
-	tmp = ioread32(denali->reg + RE_2_WE);
-	tmp &= ~RE_2_WE__VALUE;
-	tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we);
-	iowrite32(tmp, denali->reg + RE_2_WE);
-
-	/* tRHZ -> RE_2_RE */
-	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
-	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
-
-	tmp = ioread32(denali->reg + RE_2_RE);
-	tmp &= ~RE_2_RE__VALUE;
-	tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re);
-	iowrite32(tmp, denali->reg + RE_2_RE);
-
-	/*
-	 * tCCS, tWHR -> WE_2_RE
-	 *
-	 * With WE_2_RE properly set, the Denali controller automatically takes
-	 * care of the delay; the driver need not set NAND_WAIT_TCCS.
-	 */
-	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
-			       t_clk);
-	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
-
-	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
-	tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
-	tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re);
-	iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
-
-	/* tADL -> ADDR_2_DATA */
-
-	/* for older versions, ADDR_2_DATA is only 6 bit wide */
-	addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
-	if (denali->revision < 0x0501)
-		addr_2_data_mask >>= 1;
-
-	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
-	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
-
-	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
-	tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
-	tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data);
-	iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
-
-	/* tREH, tWH -> RDWR_EN_HI_CNT */
-	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
-				  t_clk);
-	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
-
-	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
-	tmp &= ~RDWR_EN_HI_CNT__VALUE;
-	tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi);
-	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
-
-	/* tRP, tWP -> RDWR_EN_LO_CNT */
-	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
-				  t_clk);
-	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
-				     t_clk);
-	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
-	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
-	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
-
-	tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
-	tmp &= ~RDWR_EN_LO_CNT__VALUE;
-	tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo);
-	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
-
-	/* tCS, tCEA -> CS_SETUP_CNT */
-	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
-			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
-			0);
-	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
-
-	tmp = ioread32(denali->reg + CS_SETUP_CNT);
-	tmp &= ~CS_SETUP_CNT__VALUE;
-	tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup);
-	iowrite32(tmp, denali->reg + CS_SETUP_CNT);
-
-	return 0;
-}
-
-static void denali_reset_banks(struct denali_nand_info *denali)
-{
-	u32 irq_status;
-	int i;
-
-	for (i = 0; i < denali->max_banks; i++) {
-		denali->active_bank = i;
-
-		denali_reset_irq(denali);
-
-		iowrite32(DEVICE_RESET__BANK(i),
-			  denali->reg + DEVICE_RESET);
-
-		irq_status = denali_wait_for_irq(denali,
-			INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
-		if (!(irq_status & INTR__INT_ACT))
-			break;
-	}
-
-	dev_dbg(denali->dev, "%d chips connected\n", i);
-	denali->max_banks = i;
-}
-
-static void denali_hw_init(struct denali_nand_info *denali)
-{
-	/*
-	 * The REVISION register may not be reliable.  Platforms are allowed to
-	 * override it.
-	 */
-	if (!denali->revision)
-		denali->revision = swab16(ioread32(denali->reg + REVISION));
-
-	/*
-	 * tell driver how many bit controller will skip before
-	 * writing ECC code in OOB, this register may be already
-	 * set by firmware. So we read this value out.
-	 * if this value is 0, just let it be.
-	 */
-	denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
-	denali_detect_max_banks(denali);
-	iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
-	iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
-
-	iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
-}
-
-int denali_calc_ecc_bytes(int step_size, int strength)
-{
-	/* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
-	return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
-}
-EXPORT_SYMBOL(denali_calc_ecc_bytes);
-
-static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
-			    struct denali_nand_info *denali)
-{
-	int oobavail = mtd->oobsize - denali->oob_skip_bytes;
-	int ret;
-
-	/*
-	 * If .size and .strength are already set (usually by DT),
-	 * check if they are supported by this controller.
-	 */
-	if (chip->ecc.size && chip->ecc.strength)
-		return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
-
-	/*
-	 * We want .size and .strength closest to the chip's requirement
-	 * unless NAND_ECC_MAXIMIZE is requested.
-	 */
-	if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
-		ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
-		if (!ret)
-			return 0;
-	}
-
-	/* Max ECC strength is the last thing we can do */
-	return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
-}
-
-static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
-				struct mtd_oob_region *oobregion)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = denali->oob_skip_bytes;
-	oobregion->length = chip->ecc.total;
-
-	return 0;
-}
-
-static int denali_ooblayout_free(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
-	oobregion->length = mtd->oobsize - oobregion->offset;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
-	.ecc = denali_ooblayout_ecc,
-	.free = denali_ooblayout_free,
-};
-
-static int denali_multidev_fixup(struct denali_nand_info *denali)
-{
-	struct nand_chip *chip = &denali->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	/*
-	 * Support for multi device:
-	 * When the IP configuration is x16 capable and two x8 chips are
-	 * connected in parallel, DEVICES_CONNECTED should be set to 2.
-	 * In this case, the core framework knows nothing about this fact,
-	 * so we should tell it the _logical_ pagesize and anything necessary.
-	 */
-	denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED);
-
-	/*
-	 * On some SoCs, DEVICES_CONNECTED is not auto-detected.
-	 * For those, DEVICES_CONNECTED is left to 0.  Set 1 if it is the case.
-	 */
-	if (denali->devs_per_cs == 0) {
-		denali->devs_per_cs = 1;
-		iowrite32(1, denali->reg + DEVICES_CONNECTED);
-	}
-
-	if (denali->devs_per_cs == 1)
-		return 0;
-
-	if (denali->devs_per_cs != 2) {
-		dev_err(denali->dev, "unsupported number of devices %d\n",
-			denali->devs_per_cs);
-		return -EINVAL;
-	}
-
-	/* 2 chips in parallel */
-	mtd->size <<= 1;
-	mtd->erasesize <<= 1;
-	mtd->writesize <<= 1;
-	mtd->oobsize <<= 1;
-	chip->chipsize <<= 1;
-	chip->page_shift += 1;
-	chip->phys_erase_shift += 1;
-	chip->bbt_erase_shift += 1;
-	chip->chip_shift += 1;
-	chip->pagemask <<= 1;
-	chip->ecc.size <<= 1;
-	chip->ecc.bytes <<= 1;
-	chip->ecc.strength <<= 1;
-	denali->oob_skip_bytes <<= 1;
-
-	return 0;
-}
-
-int denali_init(struct denali_nand_info *denali)
-{
-	struct nand_chip *chip = &denali->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u32 features = ioread32(denali->reg + FEATURES);
-	int ret;
-
-	mtd->dev.parent = denali->dev;
-	denali_hw_init(denali);
-
-	init_completion(&denali->complete);
-	spin_lock_init(&denali->irq_lock);
-
-	denali_clear_irq_all(denali);
-
-	ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
-			       IRQF_SHARED, DENALI_NAND_NAME, denali);
-	if (ret) {
-		dev_err(denali->dev, "Unable to request IRQ\n");
-		return ret;
-	}
-
-	denali_enable_irq(denali);
-	denali_reset_banks(denali);
-
-	denali->active_bank = DENALI_INVALID_BANK;
-
-	nand_set_flash_node(chip, denali->dev->of_node);
-	/* Fallback to the default name if DT did not give "label" property */
-	if (!mtd->name)
-		mtd->name = "denali-nand";
-
-	chip->select_chip = denali_select_chip;
-	chip->read_byte = denali_read_byte;
-	chip->write_byte = denali_write_byte;
-	chip->read_word = denali_read_word;
-	chip->cmd_ctrl = denali_cmd_ctrl;
-	chip->dev_ready = denali_dev_ready;
-	chip->waitfunc = denali_waitfunc;
-
-	if (features & FEATURES__INDEX_ADDR) {
-		denali->host_read = denali_indexed_read;
-		denali->host_write = denali_indexed_write;
-	} else {
-		denali->host_read = denali_direct_read;
-		denali->host_write = denali_direct_write;
-	}
-
-	/* clk rate info is needed for setup_data_interface */
-	if (denali->clk_x_rate)
-		chip->setup_data_interface = denali_setup_data_interface;
-
-	ret = nand_scan_ident(mtd, denali->max_banks, NULL);
-	if (ret)
-		goto disable_irq;
-
-	if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
-		denali->dma_avail = 1;
-
-	if (denali->dma_avail) {
-		int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
-
-		ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
-		if (ret) {
-			dev_info(denali->dev,
-				 "Failed to set DMA mask. Disabling DMA.\n");
-			denali->dma_avail = 0;
-		}
-	}
-
-	if (denali->dma_avail) {
-		chip->options |= NAND_USE_BOUNCE_BUFFER;
-		chip->buf_align = 16;
-		if (denali->caps & DENALI_CAP_DMA_64BIT)
-			denali->setup_dma = denali_setup_dma64;
-		else
-			denali->setup_dma = denali_setup_dma32;
-	}
-
-	chip->bbt_options |= NAND_BBT_USE_FLASH;
-	chip->bbt_options |= NAND_BBT_NO_OOB;
-	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
-	chip->options |= NAND_NO_SUBPAGE_WRITE;
-
-	ret = denali_ecc_setup(mtd, chip, denali);
-	if (ret) {
-		dev_err(denali->dev, "Failed to setup ECC settings.\n");
-		goto disable_irq;
-	}
-
-	dev_dbg(denali->dev,
-		"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
-		chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
-
-	iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
-		  FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
-		  denali->reg + ECC_CORRECTION);
-	iowrite32(mtd->erasesize / mtd->writesize,
-		  denali->reg + PAGES_PER_BLOCK);
-	iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
-		  denali->reg + DEVICE_WIDTH);
-	iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG,
-		  denali->reg + TWO_ROW_ADDR_CYCLES);
-	iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
-	iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
-
-	iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
-	iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
-	/* chip->ecc.steps is set by nand_scan_tail(); not available here */
-	iowrite32(mtd->writesize / chip->ecc.size,
-		  denali->reg + CFG_NUM_DATA_BLOCKS);
-
-	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
-
-	if (chip->options & NAND_BUSWIDTH_16) {
-		chip->read_buf = denali_read_buf16;
-		chip->write_buf = denali_write_buf16;
-	} else {
-		chip->read_buf = denali_read_buf;
-		chip->write_buf = denali_write_buf;
-	}
-	chip->ecc.read_page = denali_read_page;
-	chip->ecc.read_page_raw = denali_read_page_raw;
-	chip->ecc.write_page = denali_write_page;
-	chip->ecc.write_page_raw = denali_write_page_raw;
-	chip->ecc.read_oob = denali_read_oob;
-	chip->ecc.write_oob = denali_write_oob;
-	chip->erase = denali_erase;
-
-	ret = denali_multidev_fixup(denali);
-	if (ret)
-		goto disable_irq;
-
-	/*
-	 * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
-	 * use devm_kmalloc() because the memory allocated by devm_ does not
-	 * guarantee DMA-safe alignment.
-	 */
-	denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
-	if (!denali->buf) {
-		ret = -ENOMEM;
-		goto disable_irq;
-	}
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		goto free_buf;
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret) {
-		dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
-		goto free_buf;
-	}
-	return 0;
-
-free_buf:
-	kfree(denali->buf);
-disable_irq:
-	denali_disable_irq(denali);
-
-	return ret;
-}
-EXPORT_SYMBOL(denali_init);
-
-void denali_remove(struct denali_nand_info *denali)
-{
-	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
-
-	nand_release(mtd);
-	kfree(denali->buf);
-	denali_disable_irq(denali);
-}
-EXPORT_SYMBOL(denali_remove);
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
deleted file mode 100644
index 9ad33d237378..000000000000
--- a/drivers/mtd/nand/denali.h
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * NAND Flash Controller Device Driver
- * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#ifndef __DENALI_H__
-#define __DENALI_H__
-
-#include <linux/bitops.h>
-#include <linux/completion.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/spinlock_types.h>
-#include <linux/types.h>
-
-#define DEVICE_RESET				0x0
-#define     DEVICE_RESET__BANK(bank)			BIT(bank)
-
-#define TRANSFER_SPARE_REG			0x10
-#define     TRANSFER_SPARE_REG__FLAG			BIT(0)
-
-#define LOAD_WAIT_CNT				0x20
-#define     LOAD_WAIT_CNT__VALUE			GENMASK(15, 0)
-
-#define PROGRAM_WAIT_CNT			0x30
-#define     PROGRAM_WAIT_CNT__VALUE			GENMASK(15, 0)
-
-#define ERASE_WAIT_CNT				0x40
-#define     ERASE_WAIT_CNT__VALUE			GENMASK(15, 0)
-
-#define INT_MON_CYCCNT				0x50
-#define     INT_MON_CYCCNT__VALUE			GENMASK(15, 0)
-
-#define RB_PIN_ENABLED				0x60
-#define     RB_PIN_ENABLED__BANK(bank)			BIT(bank)
-
-#define MULTIPLANE_OPERATION			0x70
-#define     MULTIPLANE_OPERATION__FLAG			BIT(0)
-
-#define MULTIPLANE_READ_ENABLE			0x80
-#define     MULTIPLANE_READ_ENABLE__FLAG		BIT(0)
-
-#define COPYBACK_DISABLE			0x90
-#define     COPYBACK_DISABLE__FLAG			BIT(0)
-
-#define CACHE_WRITE_ENABLE			0xa0
-#define     CACHE_WRITE_ENABLE__FLAG			BIT(0)
-
-#define CACHE_READ_ENABLE			0xb0
-#define     CACHE_READ_ENABLE__FLAG			BIT(0)
-
-#define PREFETCH_MODE				0xc0
-#define     PREFETCH_MODE__PREFETCH_EN			BIT(0)
-#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH	GENMASK(15, 4)
-
-#define CHIP_ENABLE_DONT_CARE			0xd0
-#define     CHIP_EN_DONT_CARE__FLAG			BIT(0)
-
-#define ECC_ENABLE				0xe0
-#define     ECC_ENABLE__FLAG				BIT(0)
-
-#define GLOBAL_INT_ENABLE			0xf0
-#define     GLOBAL_INT_EN_FLAG				BIT(0)
-
-#define TWHR2_AND_WE_2_RE			0x100
-#define     TWHR2_AND_WE_2_RE__WE_2_RE			GENMASK(5, 0)
-#define     TWHR2_AND_WE_2_RE__TWHR2			GENMASK(13, 8)
-
-#define TCWAW_AND_ADDR_2_DATA			0x110
-/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
-#define     TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA		GENMASK(6, 0)
-#define     TCWAW_AND_ADDR_2_DATA__TCWAW		GENMASK(13, 8)
-
-#define RE_2_WE					0x120
-#define     RE_2_WE__VALUE				GENMASK(5, 0)
-
-#define ACC_CLKS				0x130
-#define     ACC_CLKS__VALUE				GENMASK(3, 0)
-
-#define NUMBER_OF_PLANES			0x140
-#define     NUMBER_OF_PLANES__VALUE			GENMASK(2, 0)
-
-#define PAGES_PER_BLOCK				0x150
-#define     PAGES_PER_BLOCK__VALUE			GENMASK(15, 0)
-
-#define DEVICE_WIDTH				0x160
-#define     DEVICE_WIDTH__VALUE				GENMASK(1, 0)
-
-#define DEVICE_MAIN_AREA_SIZE			0x170
-#define     DEVICE_MAIN_AREA_SIZE__VALUE		GENMASK(15, 0)
-
-#define DEVICE_SPARE_AREA_SIZE			0x180
-#define     DEVICE_SPARE_AREA_SIZE__VALUE		GENMASK(15, 0)
-
-#define TWO_ROW_ADDR_CYCLES			0x190
-#define     TWO_ROW_ADDR_CYCLES__FLAG			BIT(0)
-
-#define MULTIPLANE_ADDR_RESTRICT		0x1a0
-#define     MULTIPLANE_ADDR_RESTRICT__FLAG		BIT(0)
-
-#define ECC_CORRECTION				0x1b0
-#define     ECC_CORRECTION__VALUE			GENMASK(4, 0)
-#define     ECC_CORRECTION__ERASE_THRESHOLD		GENMASK(31, 16)
-
-#define READ_MODE				0x1c0
-#define     READ_MODE__VALUE				GENMASK(3, 0)
-
-#define WRITE_MODE				0x1d0
-#define     WRITE_MODE__VALUE				GENMASK(3, 0)
-
-#define COPYBACK_MODE				0x1e0
-#define     COPYBACK_MODE__VALUE			GENMASK(3, 0)
-
-#define RDWR_EN_LO_CNT				0x1f0
-#define     RDWR_EN_LO_CNT__VALUE			GENMASK(4, 0)
-
-#define RDWR_EN_HI_CNT				0x200
-#define     RDWR_EN_HI_CNT__VALUE			GENMASK(4, 0)
-
-#define MAX_RD_DELAY				0x210
-#define     MAX_RD_DELAY__VALUE				GENMASK(3, 0)
-
-#define CS_SETUP_CNT				0x220
-#define     CS_SETUP_CNT__VALUE				GENMASK(4, 0)
-#define     CS_SETUP_CNT__TWB				GENMASK(17, 12)
-
-#define SPARE_AREA_SKIP_BYTES			0x230
-#define     SPARE_AREA_SKIP_BYTES__VALUE		GENMASK(5, 0)
-
-#define SPARE_AREA_MARKER			0x240
-#define     SPARE_AREA_MARKER__VALUE			GENMASK(15, 0)
-
-#define DEVICES_CONNECTED			0x250
-#define     DEVICES_CONNECTED__VALUE			GENMASK(2, 0)
-
-#define DIE_MASK				0x260
-#define     DIE_MASK__VALUE				GENMASK(7, 0)
-
-#define FIRST_BLOCK_OF_NEXT_PLANE		0x270
-#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE		GENMASK(15, 0)
-
-#define WRITE_PROTECT				0x280
-#define     WRITE_PROTECT__FLAG				BIT(0)
-
-#define RE_2_RE					0x290
-#define     RE_2_RE__VALUE				GENMASK(5, 0)
-
-#define MANUFACTURER_ID				0x300
-#define     MANUFACTURER_ID__VALUE			GENMASK(7, 0)
-
-#define DEVICE_ID				0x310
-#define     DEVICE_ID__VALUE				GENMASK(7, 0)
-
-#define DEVICE_PARAM_0				0x320
-#define     DEVICE_PARAM_0__VALUE			GENMASK(7, 0)
-
-#define DEVICE_PARAM_1				0x330
-#define     DEVICE_PARAM_1__VALUE			GENMASK(7, 0)
-
-#define DEVICE_PARAM_2				0x340
-#define     DEVICE_PARAM_2__VALUE			GENMASK(7, 0)
-
-#define LOGICAL_PAGE_DATA_SIZE			0x350
-#define     LOGICAL_PAGE_DATA_SIZE__VALUE		GENMASK(15, 0)
-
-#define LOGICAL_PAGE_SPARE_SIZE			0x360
-#define     LOGICAL_PAGE_SPARE_SIZE__VALUE		GENMASK(15, 0)
-
-#define REVISION				0x370
-#define     REVISION__VALUE				GENMASK(15, 0)
-
-#define ONFI_DEVICE_FEATURES			0x380
-#define     ONFI_DEVICE_FEATURES__VALUE			GENMASK(5, 0)
-
-#define ONFI_OPTIONAL_COMMANDS			0x390
-#define     ONFI_OPTIONAL_COMMANDS__VALUE		GENMASK(5, 0)
-
-#define ONFI_TIMING_MODE			0x3a0
-#define     ONFI_TIMING_MODE__VALUE			GENMASK(5, 0)
-
-#define ONFI_PGM_CACHE_TIMING_MODE		0x3b0
-#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE		GENMASK(5, 0)
-
-#define ONFI_DEVICE_NO_OF_LUNS			0x3c0
-#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS		GENMASK(7, 0)
-#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE		BIT(8)
-
-#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L	0x3d0
-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE	GENMASK(15, 0)
-
-#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U	0x3e0
-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE	GENMASK(15, 0)
-
-#define FEATURES				0x3f0
-#define     FEATURES__N_BANKS				GENMASK(1, 0)
-#define     FEATURES__ECC_MAX_ERR			GENMASK(5, 2)
-#define     FEATURES__DMA				BIT(6)
-#define     FEATURES__CMD_DMA				BIT(7)
-#define     FEATURES__PARTITION				BIT(8)
-#define     FEATURES__XDMA_SIDEBAND			BIT(9)
-#define     FEATURES__GPREG				BIT(10)
-#define     FEATURES__INDEX_ADDR			BIT(11)
-
-#define TRANSFER_MODE				0x400
-#define     TRANSFER_MODE__VALUE			GENMASK(1, 0)
-
-#define INTR_STATUS(bank)			(0x410 + (bank) * 0x50)
-#define INTR_EN(bank)				(0x420 + (bank) * 0x50)
-/* bit[1:0] is used differently depending on IP version */
-#define     INTR__ECC_UNCOR_ERR				BIT(0)	/* new IP */
-#define     INTR__ECC_TRANSACTION_DONE			BIT(0)	/* old IP */
-#define     INTR__ECC_ERR				BIT(1)	/* old IP */
-#define     INTR__DMA_CMD_COMP				BIT(2)
-#define     INTR__TIME_OUT				BIT(3)
-#define     INTR__PROGRAM_FAIL				BIT(4)
-#define     INTR__ERASE_FAIL				BIT(5)
-#define     INTR__LOAD_COMP				BIT(6)
-#define     INTR__PROGRAM_COMP				BIT(7)
-#define     INTR__ERASE_COMP				BIT(8)
-#define     INTR__PIPE_CPYBCK_CMD_COMP			BIT(9)
-#define     INTR__LOCKED_BLK				BIT(10)
-#define     INTR__UNSUP_CMD				BIT(11)
-#define     INTR__INT_ACT				BIT(12)
-#define     INTR__RST_COMP				BIT(13)
-#define     INTR__PIPE_CMD_ERR				BIT(14)
-#define     INTR__PAGE_XFER_INC				BIT(15)
-#define     INTR__ERASED_PAGE				BIT(16)
-
-#define PAGE_CNT(bank)				(0x430 + (bank) * 0x50)
-#define ERR_PAGE_ADDR(bank)			(0x440 + (bank) * 0x50)
-#define ERR_BLOCK_ADDR(bank)			(0x450 + (bank) * 0x50)
-
-#define ECC_THRESHOLD				0x600
-#define     ECC_THRESHOLD__VALUE			GENMASK(9, 0)
-
-#define ECC_ERROR_BLOCK_ADDRESS			0x610
-#define     ECC_ERROR_BLOCK_ADDRESS__VALUE		GENMASK(15, 0)
-
-#define ECC_ERROR_PAGE_ADDRESS			0x620
-#define     ECC_ERROR_PAGE_ADDRESS__VALUE		GENMASK(11, 0)
-#define     ECC_ERROR_PAGE_ADDRESS__BANK		GENMASK(15, 12)
-
-#define ECC_ERROR_ADDRESS			0x630
-#define     ECC_ERROR_ADDRESS__OFFSET			GENMASK(11, 0)
-#define     ECC_ERROR_ADDRESS__SECTOR			GENMASK(15, 12)
-
-#define ERR_CORRECTION_INFO			0x640
-#define     ERR_CORRECTION_INFO__BYTE			GENMASK(7, 0)
-#define     ERR_CORRECTION_INFO__DEVICE			GENMASK(11, 8)
-#define     ERR_CORRECTION_INFO__UNCOR			BIT(14)
-#define     ERR_CORRECTION_INFO__LAST_ERR		BIT(15)
-
-#define ECC_COR_INFO(bank)			(0x650 + (bank) / 2 * 0x10)
-#define     ECC_COR_INFO__SHIFT(bank)			((bank) % 2 * 8)
-#define     ECC_COR_INFO__MAX_ERRORS			GENMASK(6, 0)
-#define     ECC_COR_INFO__UNCOR_ERR			BIT(7)
-
-#define CFG_DATA_BLOCK_SIZE			0x6b0
-
-#define CFG_LAST_DATA_BLOCK_SIZE		0x6c0
-
-#define CFG_NUM_DATA_BLOCKS			0x6d0
-
-#define CFG_META_DATA_SIZE			0x6e0
-
-#define DMA_ENABLE				0x700
-#define     DMA_ENABLE__FLAG				BIT(0)
-
-#define IGNORE_ECC_DONE				0x710
-#define     IGNORE_ECC_DONE__FLAG			BIT(0)
-
-#define DMA_INTR				0x720
-#define DMA_INTR_EN				0x730
-#define     DMA_INTR__TARGET_ERROR			BIT(0)
-#define     DMA_INTR__DESC_COMP_CHANNEL0		BIT(1)
-#define     DMA_INTR__DESC_COMP_CHANNEL1		BIT(2)
-#define     DMA_INTR__DESC_COMP_CHANNEL2		BIT(3)
-#define     DMA_INTR__DESC_COMP_CHANNEL3		BIT(4)
-#define     DMA_INTR__MEMCOPY_DESC_COMP			BIT(5)
-
-#define TARGET_ERR_ADDR_LO			0x740
-#define     TARGET_ERR_ADDR_LO__VALUE			GENMASK(15, 0)
-
-#define TARGET_ERR_ADDR_HI			0x750
-#define     TARGET_ERR_ADDR_HI__VALUE			GENMASK(15, 0)
-
-#define CHNL_ACTIVE				0x760
-#define     CHNL_ACTIVE__CHANNEL0			BIT(0)
-#define     CHNL_ACTIVE__CHANNEL1			BIT(1)
-#define     CHNL_ACTIVE__CHANNEL2			BIT(2)
-#define     CHNL_ACTIVE__CHANNEL3			BIT(3)
-
-struct denali_nand_info {
-	struct nand_chip nand;
-	unsigned long clk_x_rate;	/* bus interface clock rate */
-	int active_bank;		/* currently selected bank */
-	struct device *dev;
-	void __iomem *reg;		/* Register Interface */
-	void __iomem *host;		/* Host Data/Command Interface */
-	struct completion complete;
-	spinlock_t irq_lock;		/* protect irq_mask and irq_status */
-	u32 irq_mask;			/* interrupts we are waiting for */
-	u32 irq_status;			/* interrupts that have happened */
-	int irq;
-	void *buf;			/* for syndrome layout conversion */
-	dma_addr_t dma_addr;
-	int dma_avail;			/* can support DMA? */
-	int devs_per_cs;		/* devices connected in parallel */
-	int oob_skip_bytes;		/* number of bytes reserved for BBM */
-	int max_banks;
-	unsigned int revision;		/* IP revision */
-	unsigned int caps;		/* IP capability (or quirk) */
-	const struct nand_ecc_caps *ecc_caps;
-	u32 (*host_read)(struct denali_nand_info *denali, u32 addr);
-	void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data);
-	void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr,
-			  int page, int write);
-};
-
-#define DENALI_CAP_HW_ECC_FIXUP			BIT(0)
-#define DENALI_CAP_DMA_64BIT			BIT(1)
-
-int denali_calc_ecc_bytes(int step_size, int strength);
-int denali_init(struct denali_nand_info *denali);
-void denali_remove(struct denali_nand_info *denali);
-
-#endif /* __DENALI_H__ */
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
deleted file mode 100644
index cfd33e6ca77f..000000000000
--- a/drivers/mtd/nand/denali_dt.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * NAND Flash Controller Device Driver for DT
- *
- * Copyright © 2011, Picochip.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-
-#include "denali.h"
-
-struct denali_dt {
-	struct denali_nand_info	denali;
-	struct clk		*clk;
-};
-
-struct denali_dt_data {
-	unsigned int revision;
-	unsigned int caps;
-	const struct nand_ecc_caps *ecc_caps;
-};
-
-NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
-		     512, 8, 15);
-static const struct denali_dt_data denali_socfpga_data = {
-	.caps = DENALI_CAP_HW_ECC_FIXUP,
-	.ecc_caps = &denali_socfpga_ecc_caps,
-};
-
-NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
-		     1024, 8, 16, 24);
-static const struct denali_dt_data denali_uniphier_v5a_data = {
-	.caps = DENALI_CAP_HW_ECC_FIXUP |
-		DENALI_CAP_DMA_64BIT,
-	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
-};
-
-NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
-		     1024, 8, 16);
-static const struct denali_dt_data denali_uniphier_v5b_data = {
-	.revision = 0x0501,
-	.caps = DENALI_CAP_HW_ECC_FIXUP |
-		DENALI_CAP_DMA_64BIT,
-	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
-};
-
-static const struct of_device_id denali_nand_dt_ids[] = {
-	{
-		.compatible = "altr,socfpga-denali-nand",
-		.data = &denali_socfpga_data,
-	},
-	{
-		.compatible = "socionext,uniphier-denali-nand-v5a",
-		.data = &denali_uniphier_v5a_data,
-	},
-	{
-		.compatible = "socionext,uniphier-denali-nand-v5b",
-		.data = &denali_uniphier_v5b_data,
-	},
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
-
-static int denali_dt_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct denali_dt *dt;
-	const struct denali_dt_data *data;
-	struct denali_nand_info *denali;
-	int ret;
-
-	dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
-	if (!dt)
-		return -ENOMEM;
-	denali = &dt->denali;
-
-	data = of_device_get_match_data(&pdev->dev);
-	if (data) {
-		denali->revision = data->revision;
-		denali->caps = data->caps;
-		denali->ecc_caps = data->ecc_caps;
-	}
-
-	denali->dev = &pdev->dev;
-	denali->irq = platform_get_irq(pdev, 0);
-	if (denali->irq < 0) {
-		dev_err(&pdev->dev, "no irq defined\n");
-		return denali->irq;
-	}
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
-	denali->reg = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(denali->reg))
-		return PTR_ERR(denali->reg);
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-	denali->host = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(denali->host))
-		return PTR_ERR(denali->host);
-
-	dt->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(dt->clk)) {
-		dev_err(&pdev->dev, "no clk available\n");
-		return PTR_ERR(dt->clk);
-	}
-	ret = clk_prepare_enable(dt->clk);
-	if (ret)
-		return ret;
-
-	denali->clk_x_rate = clk_get_rate(dt->clk);
-
-	ret = denali_init(denali);
-	if (ret)
-		goto out_disable_clk;
-
-	platform_set_drvdata(pdev, dt);
-	return 0;
-
-out_disable_clk:
-	clk_disable_unprepare(dt->clk);
-
-	return ret;
-}
-
-static int denali_dt_remove(struct platform_device *pdev)
-{
-	struct denali_dt *dt = platform_get_drvdata(pdev);
-
-	denali_remove(&dt->denali);
-	clk_disable_unprepare(dt->clk);
-
-	return 0;
-}
-
-static struct platform_driver denali_dt_driver = {
-	.probe		= denali_dt_probe,
-	.remove		= denali_dt_remove,
-	.driver		= {
-		.name	= "denali-nand-dt",
-		.of_match_table	= denali_nand_dt_ids,
-	},
-};
-module_platform_driver(denali_dt_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jamie Iles");
-MODULE_DESCRIPTION("DT driver for Denali NAND controller");
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
deleted file mode 100644
index 49cb3e1f8bd0..000000000000
--- a/drivers/mtd/nand/denali_pci.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * NAND Flash Controller Device Driver
- * Copyright © 2009-2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- */
-
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include "denali.h"
-
-#define DENALI_NAND_NAME    "denali-nand-pci"
-
-#define INTEL_CE4100	1
-#define INTEL_MRST	2
-
-/* List of platforms this NAND controller has be integrated into */
-static const struct pci_device_id denali_pci_ids[] = {
-	{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
-	{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
-	{ /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE(pci, denali_pci_ids);
-
-NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
-
-static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int ret;
-	resource_size_t csr_base, mem_base;
-	unsigned long csr_len, mem_len;
-	struct denali_nand_info *denali;
-
-	denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL);
-	if (!denali)
-		return -ENOMEM;
-
-	ret = pcim_enable_device(dev);
-	if (ret) {
-		dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n");
-		return ret;
-	}
-
-	if (id->driver_data == INTEL_CE4100) {
-		mem_base = pci_resource_start(dev, 0);
-		mem_len = pci_resource_len(dev, 1);
-		csr_base = pci_resource_start(dev, 1);
-		csr_len = pci_resource_len(dev, 1);
-	} else {
-		csr_base = pci_resource_start(dev, 0);
-		csr_len = pci_resource_len(dev, 0);
-		mem_base = pci_resource_start(dev, 1);
-		mem_len = pci_resource_len(dev, 1);
-		if (!mem_len) {
-			mem_base = csr_base + csr_len;
-			mem_len = csr_len;
-		}
-	}
-
-	pci_set_master(dev);
-	denali->dev = &dev->dev;
-	denali->irq = dev->irq;
-	denali->ecc_caps = &denali_pci_ecc_caps;
-	denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
-	denali->clk_x_rate = 200000000;		/* 200 MHz */
-
-	ret = pci_request_regions(dev, DENALI_NAND_NAME);
-	if (ret) {
-		dev_err(&dev->dev, "Spectra: Unable to request memory regions\n");
-		return ret;
-	}
-
-	denali->reg = ioremap_nocache(csr_base, csr_len);
-	if (!denali->reg) {
-		dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
-		return -ENOMEM;
-	}
-
-	denali->host = ioremap_nocache(mem_base, mem_len);
-	if (!denali->host) {
-		dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
-		ret = -ENOMEM;
-		goto failed_remap_reg;
-	}
-
-	ret = denali_init(denali);
-	if (ret)
-		goto failed_remap_mem;
-
-	pci_set_drvdata(dev, denali);
-
-	return 0;
-
-failed_remap_mem:
-	iounmap(denali->host);
-failed_remap_reg:
-	iounmap(denali->reg);
-	return ret;
-}
-
-static void denali_pci_remove(struct pci_dev *dev)
-{
-	struct denali_nand_info *denali = pci_get_drvdata(dev);
-
-	denali_remove(denali);
-	iounmap(denali->reg);
-	iounmap(denali->host);
-}
-
-static struct pci_driver denali_pci_driver = {
-	.name = DENALI_NAND_NAME,
-	.id_table = denali_pci_ids,
-	.probe = denali_pci_probe,
-	.remove = denali_pci_remove,
-};
-module_pci_driver(denali_pci_driver);
-
-MODULE_DESCRIPTION("PCI driver for Denali NAND controller");
-MODULE_AUTHOR("Intel Corporation and its suppliers");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
deleted file mode 100644
index 6bc93ea66f50..000000000000
--- a/drivers/mtd/nand/diskonchip.c
+++ /dev/null
@@ -1,1711 +0,0 @@
-/*
- * drivers/mtd/nand/diskonchip.c
- *
- * (C) 2003 Red Hat, Inc.
- * (C) 2004 Dan Brown <dan_brown@ieee.org>
- * (C) 2004 Kalev Lember <kalev@smartlink.ee>
- *
- * Author: David Woodhouse <dwmw2@infradead.org>
- * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
- * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
- *
- * Error correction code lifted from the old docecc code
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
- * Copyright (C) 2000 Netgem S.A.
- * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
- *
- * Interface to generic NAND code for M-Systems DiskOnChip devices
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/rslib.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/doc2000.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/inftl.h>
-#include <linux/module.h>
-
-/* Where to look for the devices? */
-#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
-#endif
-
-static unsigned long doc_locations[] __initdata = {
-#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
-	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
-	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
-	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
-	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
-	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
-#else
-	0xc8000, 0xca000, 0xcc000, 0xce000,
-	0xd0000, 0xd2000, 0xd4000, 0xd6000,
-	0xd8000, 0xda000, 0xdc000, 0xde000,
-	0xe0000, 0xe2000, 0xe4000, 0xe6000,
-	0xe8000, 0xea000, 0xec000, 0xee000,
-#endif
-#endif
-	0xffffffff };
-
-static struct mtd_info *doclist = NULL;
-
-struct doc_priv {
-	void __iomem *virtadr;
-	unsigned long physadr;
-	u_char ChipID;
-	u_char CDSNControl;
-	int chips_per_floor;	/* The number of chips detected on each floor */
-	int curfloor;
-	int curchip;
-	int mh0_page;
-	int mh1_page;
-	struct mtd_info *nextdoc;
-
-	/* Handle the last stage of initialization (BBT scan, partitioning) */
-	int (*late_init)(struct mtd_info *mtd);
-};
-
-/* This is the ecc value computed by the HW ecc generator upon writing an empty
-   page, one with all 0xff for data. */
-static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
-
-#define INFTL_BBT_RESERVED_BLOCKS 4
-
-#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
-#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
-#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
-
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
-			      unsigned int bitmask);
-static void doc200x_select_chip(struct mtd_info *mtd, int chip);
-
-static int debug = 0;
-module_param(debug, int, 0);
-
-static int try_dword = 1;
-module_param(try_dword, int, 0);
-
-static int no_ecc_failures = 0;
-module_param(no_ecc_failures, int, 0);
-
-static int no_autopart = 0;
-module_param(no_autopart, int, 0);
-
-static int show_firmware_partition = 0;
-module_param(show_firmware_partition, int, 0);
-
-#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
-static int inftl_bbt_write = 1;
-#else
-static int inftl_bbt_write = 0;
-#endif
-module_param(inftl_bbt_write, int, 0);
-
-static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
-module_param(doc_config_location, ulong, 0);
-MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
-
-/* Sector size for HW ECC */
-#define SECTOR_SIZE 512
-/* The sector bytes are packed into NB_DATA 10 bit words */
-#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
-/* Number of roots */
-#define NROOTS 4
-/* First consective root */
-#define FCR 510
-/* Number of symbols */
-#define NN 1023
-
-/* the Reed Solomon control structure */
-static struct rs_control *rs_decoder;
-
-/*
- * The HW decoder in the DoC ASIC's provides us a error syndrome,
- * which we must convert to a standard syndrome usable by the generic
- * Reed-Solomon library code.
- *
- * Fabrice Bellard figured this out in the old docecc code. I added
- * some comments, improved a minor bit and converted it to make use
- * of the generic Reed-Solomon library. tglx
- */
-static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
-{
-	int i, j, nerr, errpos[8];
-	uint8_t parity;
-	uint16_t ds[4], s[5], tmp, errval[8], syn[4];
-
-	memset(syn, 0, sizeof(syn));
-	/* Convert the ecc bytes into words */
-	ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
-	ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
-	ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
-	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
-	parity = ecc[1];
-
-	/* Initialize the syndrome buffer */
-	for (i = 0; i < NROOTS; i++)
-		s[i] = ds[0];
-	/*
-	 *  Evaluate
-	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
-	 *  where x = alpha^(FCR + i)
-	 */
-	for (j = 1; j < NROOTS; j++) {
-		if (ds[j] == 0)
-			continue;
-		tmp = rs->index_of[ds[j]];
-		for (i = 0; i < NROOTS; i++)
-			s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
-	}
-
-	/* Calc syn[i] = s[i] / alpha^(v + i) */
-	for (i = 0; i < NROOTS; i++) {
-		if (s[i])
-			syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
-	}
-	/* Call the decoder library */
-	nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
-
-	/* Incorrectable errors ? */
-	if (nerr < 0)
-		return nerr;
-
-	/*
-	 * Correct the errors. The bitpositions are a bit of magic,
-	 * but they are given by the design of the de/encoder circuit
-	 * in the DoC ASIC's.
-	 */
-	for (i = 0; i < nerr; i++) {
-		int index, bitpos, pos = 1015 - errpos[i];
-		uint8_t val;
-		if (pos >= NB_DATA && pos < 1019)
-			continue;
-		if (pos < NB_DATA) {
-			/* extract bit position (MSB first) */
-			pos = 10 * (NB_DATA - 1 - pos) - 6;
-			/* now correct the following 10 bits. At most two bytes
-			   can be modified since pos is even */
-			index = (pos >> 3) ^ 1;
-			bitpos = pos & 7;
-			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
-				val = (uint8_t) (errval[i] >> (2 + bitpos));
-				parity ^= val;
-				if (index < SECTOR_SIZE)
-					data[index] ^= val;
-			}
-			index = ((pos >> 3) + 1) ^ 1;
-			bitpos = (bitpos + 10) & 7;
-			if (bitpos == 0)
-				bitpos = 8;
-			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
-				val = (uint8_t) (errval[i] << (8 - bitpos));
-				parity ^= val;
-				if (index < SECTOR_SIZE)
-					data[index] ^= val;
-			}
-		}
-	}
-	/* If the parity is wrong, no rescue possible */
-	return parity ? -EBADMSG : nerr;
-}
-
-static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
-{
-	volatile char dummy;
-	int i;
-
-	for (i = 0; i < cycles; i++) {
-		if (DoC_is_Millennium(doc))
-			dummy = ReadDOC(doc->virtadr, NOP);
-		else if (DoC_is_MillenniumPlus(doc))
-			dummy = ReadDOC(doc->virtadr, Mplus_NOP);
-		else
-			dummy = ReadDOC(doc->virtadr, DOCStatus);
-	}
-
-}
-
-#define CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
-
-/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
-static int _DoC_WaitReady(struct doc_priv *doc)
-{
-	void __iomem *docptr = doc->virtadr;
-	unsigned long timeo = jiffies + (HZ * 10);
-
-	if (debug)
-		printk("_DoC_WaitReady...\n");
-	/* Out-of-line routine to wait for chip response */
-	if (DoC_is_MillenniumPlus(doc)) {
-		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
-			if (time_after(jiffies, timeo)) {
-				printk("_DoC_WaitReady timed out.\n");
-				return -EIO;
-			}
-			udelay(1);
-			cond_resched();
-		}
-	} else {
-		while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-			if (time_after(jiffies, timeo)) {
-				printk("_DoC_WaitReady timed out.\n");
-				return -EIO;
-			}
-			udelay(1);
-			cond_resched();
-		}
-	}
-
-	return 0;
-}
-
-static inline int DoC_WaitReady(struct doc_priv *doc)
-{
-	void __iomem *docptr = doc->virtadr;
-	int ret = 0;
-
-	if (DoC_is_MillenniumPlus(doc)) {
-		DoC_Delay(doc, 4);
-
-		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
-			/* Call the out-of-line routine to wait */
-			ret = _DoC_WaitReady(doc);
-	} else {
-		DoC_Delay(doc, 4);
-
-		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
-			/* Call the out-of-line routine to wait */
-			ret = _DoC_WaitReady(doc);
-		DoC_Delay(doc, 2);
-	}
-
-	if (debug)
-		printk("DoC_WaitReady OK\n");
-	return ret;
-}
-
-static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	if (debug)
-		printk("write_byte %02x\n", datum);
-	WriteDOC(datum, docptr, CDSNSlowIO);
-	WriteDOC(datum, docptr, 2k_CDSN_IO);
-}
-
-static u_char doc2000_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	u_char ret;
-
-	ReadDOC(docptr, CDSNSlowIO);
-	DoC_Delay(doc, 2);
-	ret = ReadDOC(docptr, 2k_CDSN_IO);
-	if (debug)
-		printk("read_byte returns %02x\n", ret);
-	return ret;
-}
-
-static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-	if (debug)
-		printk("writebuf of %d bytes: ", len);
-	for (i = 0; i < len; i++) {
-		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
-		if (debug && i < 16)
-			printk("%02x ", buf[i]);
-	}
-	if (debug)
-		printk("\n");
-}
-
-static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	if (debug)
-		printk("readbuf of %d bytes: ", len);
-
-	for (i = 0; i < len; i++) {
-		buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
-	}
-}
-
-static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	if (debug)
-		printk("readbuf_dword of %d bytes: ", len);
-
-	if (unlikely((((unsigned long)buf) | len) & 3)) {
-		for (i = 0; i < len; i++) {
-			*(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
-		}
-	} else {
-		for (i = 0; i < len; i += 4) {
-			*(uint32_t *) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
-		}
-	}
-}
-
-static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	uint16_t ret;
-
-	doc200x_select_chip(mtd, nr);
-	doc200x_hwcontrol(mtd, NAND_CMD_READID,
-			  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-	doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
-	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-	/* We can't use dev_ready here, but at least we wait for the
-	 * command to complete
-	 */
-	udelay(50);
-
-	ret = this->read_byte(mtd) << 8;
-	ret |= this->read_byte(mtd);
-
-	if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
-		/* First chip probe. See if we get same results by 32-bit access */
-		union {
-			uint32_t dword;
-			uint8_t byte[4];
-		} ident;
-		void __iomem *docptr = doc->virtadr;
-
-		doc200x_hwcontrol(mtd, NAND_CMD_READID,
-				  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-		doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
-		doc200x_hwcontrol(mtd, NAND_CMD_NONE,
-				  NAND_NCE | NAND_CTRL_CHANGE);
-
-		udelay(50);
-
-		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
-		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
-			printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
-			this->read_buf = &doc2000_readbuf_dword;
-		}
-	}
-
-	return ret;
-}
-
-static void __init doc2000_count_chips(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	uint16_t mfrid;
-	int i;
-
-	/* Max 4 chips per floor on DiskOnChip 2000 */
-	doc->chips_per_floor = 4;
-
-	/* Find out what the first chip is */
-	mfrid = doc200x_ident_chip(mtd, 0);
-
-	/* Find how many chips in each floor. */
-	for (i = 1; i < 4; i++) {
-		if (doc200x_ident_chip(mtd, i) != mfrid)
-			break;
-	}
-	doc->chips_per_floor = i;
-	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
-}
-
-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
-{
-	struct doc_priv *doc = nand_get_controller_data(this);
-
-	int status;
-
-	DoC_WaitReady(doc);
-	nand_status_op(this, NULL);
-	DoC_WaitReady(doc);
-	status = (int)this->read_byte(mtd);
-
-	return status;
-}
-
-static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	WriteDOC(datum, docptr, CDSNSlowIO);
-	WriteDOC(datum, docptr, Mil_CDSN_IO);
-	WriteDOC(datum, docptr, WritePipeTerm);
-}
-
-static u_char doc2001_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	//ReadDOC(docptr, CDSNSlowIO);
-	/* 11.4.5 -- delay twice to allow extended length cycle */
-	DoC_Delay(doc, 2);
-	ReadDOC(docptr, ReadPipeInit);
-	//return ReadDOC(docptr, Mil_CDSN_IO);
-	return ReadDOC(docptr, LastDataRead);
-}
-
-static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	for (i = 0; i < len; i++)
-		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
-	/* Terminate write pipeline */
-	WriteDOC(0x00, docptr, WritePipeTerm);
-}
-
-static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	/* Start read pipeline */
-	ReadDOC(docptr, ReadPipeInit);
-
-	for (i = 0; i < len - 1; i++)
-		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
-
-	/* Terminate read pipeline */
-	buf[i] = ReadDOC(docptr, LastDataRead);
-}
-
-static u_char doc2001plus_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	u_char ret;
-
-	ReadDOC(docptr, Mplus_ReadPipeInit);
-	ReadDOC(docptr, Mplus_ReadPipeInit);
-	ret = ReadDOC(docptr, Mplus_LastDataRead);
-	if (debug)
-		printk("read_byte returns %02x\n", ret);
-	return ret;
-}
-
-static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	if (debug)
-		printk("writebuf of %d bytes: ", len);
-	for (i = 0; i < len; i++) {
-		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
-		if (debug && i < 16)
-			printk("%02x ", buf[i]);
-	}
-	if (debug)
-		printk("\n");
-}
-
-static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	if (debug)
-		printk("readbuf of %d bytes: ", len);
-
-	/* Start read pipeline */
-	ReadDOC(docptr, Mplus_ReadPipeInit);
-	ReadDOC(docptr, Mplus_ReadPipeInit);
-
-	for (i = 0; i < len - 2; i++) {
-		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
-		if (debug && i < 16)
-			printk("%02x ", buf[i]);
-	}
-
-	/* Terminate read pipeline */
-	buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
-	if (debug && i < 16)
-		printk("%02x ", buf[len - 2]);
-	buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
-	if (debug && i < 16)
-		printk("%02x ", buf[len - 1]);
-	if (debug)
-		printk("\n");
-}
-
-static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int floor = 0;
-
-	if (debug)
-		printk("select chip (%d)\n", chip);
-
-	if (chip == -1) {
-		/* Disable flash internally */
-		WriteDOC(0, docptr, Mplus_FlashSelect);
-		return;
-	}
-
-	floor = chip / doc->chips_per_floor;
-	chip -= (floor * doc->chips_per_floor);
-
-	/* Assert ChipEnable and deassert WriteProtect */
-	WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
-	nand_reset_op(this);
-
-	doc->curchip = chip;
-	doc->curfloor = floor;
-}
-
-static void doc200x_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int floor = 0;
-
-	if (debug)
-		printk("select chip (%d)\n", chip);
-
-	if (chip == -1)
-		return;
-
-	floor = chip / doc->chips_per_floor;
-	chip -= (floor * doc->chips_per_floor);
-
-	/* 11.4.4 -- deassert CE before changing chip */
-	doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
-
-	WriteDOC(floor, docptr, FloorSelect);
-	WriteDOC(chip, docptr, CDSNDeviceSelect);
-
-	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-	doc->curchip = chip;
-	doc->curfloor = floor;
-}
-
-#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
-
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
-			      unsigned int ctrl)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		doc->CDSNControl &= ~CDSN_CTRL_MSK;
-		doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
-		if (debug)
-			printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
-		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
-		/* 11.4.3 -- 4 NOPs after CSDNControl write */
-		DoC_Delay(doc, 4);
-	}
-	if (cmd != NAND_CMD_NONE) {
-		if (DoC_is_2000(doc))
-			doc2000_write_byte(mtd, cmd);
-		else
-			doc2001_write_byte(mtd, cmd);
-	}
-}
-
-static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	/*
-	 * Must terminate write pipeline before sending any commands
-	 * to the device.
-	 */
-	if (command == NAND_CMD_PAGEPROG) {
-		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-	}
-
-	/*
-	 * Write out the command to the device.
-	 */
-	if (command == NAND_CMD_SEQIN) {
-		int readcmd;
-
-		if (column >= mtd->writesize) {
-			/* OOB area */
-			column -= mtd->writesize;
-			readcmd = NAND_CMD_READOOB;
-		} else if (column < 256) {
-			/* First 256 bytes --> READ0 */
-			readcmd = NAND_CMD_READ0;
-		} else {
-			column -= 256;
-			readcmd = NAND_CMD_READ1;
-		}
-		WriteDOC(readcmd, docptr, Mplus_FlashCmd);
-	}
-	WriteDOC(command, docptr, Mplus_FlashCmd);
-	WriteDOC(0, docptr, Mplus_WritePipeTerm);
-	WriteDOC(0, docptr, Mplus_WritePipeTerm);
-
-	if (column != -1 || page_addr != -1) {
-		/* Serially input address */
-		if (column != -1) {
-			/* Adjust columns for 16 bit buswidth */
-			if (this->options & NAND_BUSWIDTH_16 &&
-					!nand_opcode_8bits(command))
-				column >>= 1;
-			WriteDOC(column, docptr, Mplus_FlashAddress);
-		}
-		if (page_addr != -1) {
-			WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress);
-			WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
-			if (this->options & NAND_ROW_ADDR_3) {
-				WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
-				printk("high density\n");
-			}
-		}
-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-		/* deassert ALE */
-		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
-		    command == NAND_CMD_READOOB || command == NAND_CMD_READID)
-			WriteDOC(0, docptr, Mplus_FlashControl);
-	}
-
-	/*
-	 * program and erase have their own busy handlers
-	 * status and sequential in needs no delay
-	 */
-	switch (command) {
-
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_STATUS:
-		return;
-
-	case NAND_CMD_RESET:
-		if (this->dev_ready)
-			break;
-		udelay(this->chip_delay);
-		WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-		while (!(this->read_byte(mtd) & 0x40)) ;
-		return;
-
-		/* This applies to read commands */
-	default:
-		/*
-		 * If we don't have access to the busy pin, we apply the given
-		 * command delay
-		 */
-		if (!this->dev_ready) {
-			udelay(this->chip_delay);
-			return;
-		}
-	}
-
-	/* Apply this short delay always to ensure that we do wait tWB in
-	 * any case on any machine. */
-	ndelay(100);
-	/* wait until command is processed */
-	while (!this->dev_ready(mtd)) ;
-}
-
-static int doc200x_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	if (DoC_is_MillenniumPlus(doc)) {
-		/* 11.4.2 -- must NOP four times before checking FR/B# */
-		DoC_Delay(doc, 4);
-		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
-			if (debug)
-				printk("not ready\n");
-			return 0;
-		}
-		if (debug)
-			printk("was ready\n");
-		return 1;
-	} else {
-		/* 11.4.2 -- must NOP four times before checking FR/B# */
-		DoC_Delay(doc, 4);
-		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-			if (debug)
-				printk("not ready\n");
-			return 0;
-		}
-		/* 11.4.2 -- Must NOP twice if it's ready */
-		DoC_Delay(doc, 2);
-		if (debug)
-			printk("was ready\n");
-		return 1;
-	}
-}
-
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
-{
-	/* This is our last resort if we couldn't find or create a BBT.  Just
-	   pretend all blocks are good. */
-	return 0;
-}
-
-static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	/* Prime the ECC engine */
-	switch (mode) {
-	case NAND_ECC_READ:
-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
-		break;
-	case NAND_ECC_WRITE:
-		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-		break;
-	}
-}
-
-static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-
-	/* Prime the ECC engine */
-	switch (mode) {
-	case NAND_ECC_READ:
-		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
-		break;
-	case NAND_ECC_WRITE:
-		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
-		break;
-	}
-}
-
-/* This code is only called on write */
-static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-	int emptymatch = 1;
-
-	/* flush the pipeline */
-	if (DoC_is_2000(doc)) {
-		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
-		WriteDOC(0, docptr, 2k_CDSN_IO);
-		WriteDOC(0, docptr, 2k_CDSN_IO);
-		WriteDOC(0, docptr, 2k_CDSN_IO);
-		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
-	} else if (DoC_is_MillenniumPlus(doc)) {
-		WriteDOC(0, docptr, Mplus_NOP);
-		WriteDOC(0, docptr, Mplus_NOP);
-		WriteDOC(0, docptr, Mplus_NOP);
-	} else {
-		WriteDOC(0, docptr, NOP);
-		WriteDOC(0, docptr, NOP);
-		WriteDOC(0, docptr, NOP);
-	}
-
-	for (i = 0; i < 6; i++) {
-		if (DoC_is_MillenniumPlus(doc))
-			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
-		else
-			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
-		if (ecc_code[i] != empty_write_ecc[i])
-			emptymatch = 0;
-	}
-	if (DoC_is_MillenniumPlus(doc))
-		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
-	else
-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-#if 0
-	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
-	if (emptymatch) {
-		/* Note: this somewhat expensive test should not be triggered
-		   often.  It could be optimized away by examining the data in
-		   the writebuf routine, and remembering the result. */
-		for (i = 0; i < 512; i++) {
-			if (dat[i] == 0xff)
-				continue;
-			emptymatch = 0;
-			break;
-		}
-	}
-	/* If emptymatch still =1, we do have an all-0xff data buffer.
-	   Return all-0xff ecc value instead of the computed one, so
-	   it'll look just like a freshly-erased page. */
-	if (emptymatch)
-		memset(ecc_code, 0xff, 6);
-#endif
-	return 0;
-}
-
-static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
-				u_char *read_ecc, u_char *isnull)
-{
-	int i, ret = 0;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	void __iomem *docptr = doc->virtadr;
-	uint8_t calc_ecc[6];
-	volatile u_char dummy;
-
-	/* flush the pipeline */
-	if (DoC_is_2000(doc)) {
-		dummy = ReadDOC(docptr, 2k_ECCStatus);
-		dummy = ReadDOC(docptr, 2k_ECCStatus);
-		dummy = ReadDOC(docptr, 2k_ECCStatus);
-	} else if (DoC_is_MillenniumPlus(doc)) {
-		dummy = ReadDOC(docptr, Mplus_ECCConf);
-		dummy = ReadDOC(docptr, Mplus_ECCConf);
-		dummy = ReadDOC(docptr, Mplus_ECCConf);
-	} else {
-		dummy = ReadDOC(docptr, ECCConf);
-		dummy = ReadDOC(docptr, ECCConf);
-		dummy = ReadDOC(docptr, ECCConf);
-	}
-
-	/* Error occurred ? */
-	if (dummy & 0x80) {
-		for (i = 0; i < 6; i++) {
-			if (DoC_is_MillenniumPlus(doc))
-				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
-			else
-				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
-		}
-
-		ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
-		if (ret > 0)
-			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
-	}
-	if (DoC_is_MillenniumPlus(doc))
-		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
-	else
-		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-	if (no_ecc_failures && mtd_is_eccerr(ret)) {
-		printk(KERN_ERR "suppressing ECC failure\n");
-		ret = 0;
-	}
-	return ret;
-}
-
-//u_char mydatabuf[528];
-
-static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 0;
-	oobregion->length = 6;
-
-	return 0;
-}
-
-static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	if (section > 1)
-		return -ERANGE;
-
-	/*
-	 * The strange out-of-order free bytes definition is a (possibly
-	 * unneeded) attempt to retain compatibility.  It used to read:
-	 *	.oobfree = { {8, 8} }
-	 * Since that leaves two bytes unusable, it was changed.  But the
-	 * following scheme might affect existing jffs2 installs by moving the
-	 * cleanmarker:
-	 *	.oobfree = { {6, 10} }
-	 * jffs2 seems to handle the above gracefully, but the current scheme
-	 * seems safer. The only problem with it is that any code retrieving
-	 * free bytes position must be able to handle out-of-order segments.
-	 */
-	if (!section) {
-		oobregion->offset = 8;
-		oobregion->length = 8;
-	} else {
-		oobregion->offset = 6;
-		oobregion->length = 2;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
-	.ecc = doc200x_ooblayout_ecc,
-	.free = doc200x_ooblayout_free,
-};
-
-/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
-   On successful return, buf will contain a copy of the media header for
-   further processing.  id is the string to scan for, and will presumably be
-   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
-   header.  The page #s of the found media headers are placed in mh0_page and
-   mh1_page in the DOC private structure. */
-static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	unsigned offs;
-	int ret;
-	size_t retlen;
-
-	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
-		ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
-		if (retlen != mtd->writesize)
-			continue;
-		if (ret) {
-			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
-		}
-		if (memcmp(buf, id, 6))
-			continue;
-		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
-		if (doc->mh0_page == -1) {
-			doc->mh0_page = offs >> this->page_shift;
-			if (!findmirror)
-				return 1;
-			continue;
-		}
-		doc->mh1_page = offs >> this->page_shift;
-		return 2;
-	}
-	if (doc->mh0_page == -1) {
-		printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
-		return 0;
-	}
-	/* Only one mediaheader was found.  We want buf to contain a
-	   mediaheader on return, so we'll have to re-read the one we found. */
-	offs = doc->mh0_page << this->page_shift;
-	ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
-	if (retlen != mtd->writesize) {
-		/* Insanity.  Give up. */
-		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
-		return 0;
-	}
-	return 1;
-}
-
-static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	int ret = 0;
-	u_char *buf;
-	struct NFTLMediaHeader *mh;
-	const unsigned psize = 1 << this->page_shift;
-	int numparts = 0;
-	unsigned blocks, maxblocks;
-	int offs, numheaders;
-
-	buf = kmalloc(mtd->writesize, GFP_KERNEL);
-	if (!buf) {
-		return 0;
-	}
-	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
-		goto out;
-	mh = (struct NFTLMediaHeader *)buf;
-
-	le16_to_cpus(&mh->NumEraseUnits);
-	le16_to_cpus(&mh->FirstPhysicalEUN);
-	le32_to_cpus(&mh->FormattedSize);
-
-	printk(KERN_INFO "    DataOrgID        = %s\n"
-			 "    NumEraseUnits    = %d\n"
-			 "    FirstPhysicalEUN = %d\n"
-			 "    FormattedSize    = %d\n"
-			 "    UnitSizeFactor   = %d\n",
-		mh->DataOrgID, mh->NumEraseUnits,
-		mh->FirstPhysicalEUN, mh->FormattedSize,
-		mh->UnitSizeFactor);
-
-	blocks = mtd->size >> this->phys_erase_shift;
-	maxblocks = min(32768U, mtd->erasesize - psize);
-
-	if (mh->UnitSizeFactor == 0x00) {
-		/* Auto-determine UnitSizeFactor.  The constraints are:
-		   - There can be at most 32768 virtual blocks.
-		   - There can be at most (virtual block size - page size)
-		   virtual blocks (because MediaHeader+BBT must fit in 1).
-		 */
-		mh->UnitSizeFactor = 0xff;
-		while (blocks > maxblocks) {
-			blocks >>= 1;
-			maxblocks = min(32768U, (maxblocks << 1) + psize);
-			mh->UnitSizeFactor--;
-		}
-		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
-	}
-
-	/* NOTE: The lines below modify internal variables of the NAND and MTD
-	   layers; variables with have already been configured by nand_scan.
-	   Unfortunately, we didn't know before this point what these values
-	   should be.  Thus, this code is somewhat dependent on the exact
-	   implementation of the NAND layer.  */
-	if (mh->UnitSizeFactor != 0xff) {
-		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
-		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
-		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
-		blocks = mtd->size >> this->bbt_erase_shift;
-		maxblocks = min(32768U, mtd->erasesize - psize);
-	}
-
-	if (blocks > maxblocks) {
-		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
-		goto out;
-	}
-
-	/* Skip past the media headers. */
-	offs = max(doc->mh0_page, doc->mh1_page);
-	offs <<= this->page_shift;
-	offs += mtd->erasesize;
-
-	if (show_firmware_partition == 1) {
-		parts[0].name = " DiskOnChip Firmware / Media Header partition";
-		parts[0].offset = 0;
-		parts[0].size = offs;
-		numparts = 1;
-	}
-
-	parts[numparts].name = " DiskOnChip BDTL partition";
-	parts[numparts].offset = offs;
-	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
-
-	offs += parts[numparts].size;
-	numparts++;
-
-	if (offs < mtd->size) {
-		parts[numparts].name = " DiskOnChip Remainder partition";
-		parts[numparts].offset = offs;
-		parts[numparts].size = mtd->size - offs;
-		numparts++;
-	}
-
-	ret = numparts;
- out:
-	kfree(buf);
-	return ret;
-}
-
-/* This is a stripped-down copy of the code in inftlmount.c */
-static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	int ret = 0;
-	u_char *buf;
-	struct INFTLMediaHeader *mh;
-	struct INFTLPartition *ip;
-	int numparts = 0;
-	int blocks;
-	int vshift, lastvunit = 0;
-	int i;
-	int end = mtd->size;
-
-	if (inftl_bbt_write)
-		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
-
-	buf = kmalloc(mtd->writesize, GFP_KERNEL);
-	if (!buf) {
-		return 0;
-	}
-
-	if (!find_media_headers(mtd, buf, "BNAND", 0))
-		goto out;
-	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
-	mh = (struct INFTLMediaHeader *)buf;
-
-	le32_to_cpus(&mh->NoOfBootImageBlocks);
-	le32_to_cpus(&mh->NoOfBinaryPartitions);
-	le32_to_cpus(&mh->NoOfBDTLPartitions);
-	le32_to_cpus(&mh->BlockMultiplierBits);
-	le32_to_cpus(&mh->FormatFlags);
-	le32_to_cpus(&mh->PercentUsed);
-
-	printk(KERN_INFO "    bootRecordID          = %s\n"
-			 "    NoOfBootImageBlocks   = %d\n"
-			 "    NoOfBinaryPartitions  = %d\n"
-			 "    NoOfBDTLPartitions    = %d\n"
-			 "    BlockMultiplerBits    = %d\n"
-			 "    FormatFlgs            = %d\n"
-			 "    OsakVersion           = %d.%d.%d.%d\n"
-			 "    PercentUsed           = %d\n",
-		mh->bootRecordID, mh->NoOfBootImageBlocks,
-		mh->NoOfBinaryPartitions,
-		mh->NoOfBDTLPartitions,
-		mh->BlockMultiplierBits, mh->FormatFlags,
-		((unsigned char *) &mh->OsakVersion)[0] & 0xf,
-		((unsigned char *) &mh->OsakVersion)[1] & 0xf,
-		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
-		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
-		mh->PercentUsed);
-
-	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
-
-	blocks = mtd->size >> vshift;
-	if (blocks > 32768) {
-		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
-		goto out;
-	}
-
-	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
-	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
-		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
-		goto out;
-	}
-
-	/* Scan the partitions */
-	for (i = 0; (i < 4); i++) {
-		ip = &(mh->Partitions[i]);
-		le32_to_cpus(&ip->virtualUnits);
-		le32_to_cpus(&ip->firstUnit);
-		le32_to_cpus(&ip->lastUnit);
-		le32_to_cpus(&ip->flags);
-		le32_to_cpus(&ip->spareUnits);
-		le32_to_cpus(&ip->Reserved0);
-
-		printk(KERN_INFO	"    PARTITION[%d] ->\n"
-			"        virtualUnits    = %d\n"
-			"        firstUnit       = %d\n"
-			"        lastUnit        = %d\n"
-			"        flags           = 0x%x\n"
-			"        spareUnits      = %d\n",
-			i, ip->virtualUnits, ip->firstUnit,
-			ip->lastUnit, ip->flags,
-			ip->spareUnits);
-
-		if ((show_firmware_partition == 1) &&
-		    (i == 0) && (ip->firstUnit > 0)) {
-			parts[0].name = " DiskOnChip IPL / Media Header partition";
-			parts[0].offset = 0;
-			parts[0].size = mtd->erasesize * ip->firstUnit;
-			numparts = 1;
-		}
-
-		if (ip->flags & INFTL_BINARY)
-			parts[numparts].name = " DiskOnChip BDK partition";
-		else
-			parts[numparts].name = " DiskOnChip BDTL partition";
-		parts[numparts].offset = ip->firstUnit << vshift;
-		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
-		numparts++;
-		if (ip->lastUnit > lastvunit)
-			lastvunit = ip->lastUnit;
-		if (ip->flags & INFTL_LAST)
-			break;
-	}
-	lastvunit++;
-	if ((lastvunit << vshift) < end) {
-		parts[numparts].name = " DiskOnChip Remainder partition";
-		parts[numparts].offset = lastvunit << vshift;
-		parts[numparts].size = end - parts[numparts].offset;
-		numparts++;
-	}
-	ret = numparts;
- out:
-	kfree(buf);
-	return ret;
-}
-
-static int __init nftl_scan_bbt(struct mtd_info *mtd)
-{
-	int ret, numparts;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	struct mtd_partition parts[2];
-
-	memset((char *)parts, 0, sizeof(parts));
-	/* On NFTL, we have to find the media headers before we can read the
-	   BBTs, since they're stored in the media header eraseblocks. */
-	numparts = nftl_partscan(mtd, parts);
-	if (!numparts)
-		return -EIO;
-	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
-				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
-				NAND_BBT_VERSION;
-	this->bbt_td->veroffs = 7;
-	this->bbt_td->pages[0] = doc->mh0_page + 1;
-	if (doc->mh1_page != -1) {
-		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
-					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
-					NAND_BBT_VERSION;
-		this->bbt_md->veroffs = 7;
-		this->bbt_md->pages[0] = doc->mh1_page + 1;
-	} else {
-		this->bbt_md = NULL;
-	}
-
-	ret = this->scan_bbt(mtd);
-	if (ret)
-		return ret;
-
-	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
-}
-
-static int __init inftl_scan_bbt(struct mtd_info *mtd)
-{
-	int ret, numparts;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-	struct mtd_partition parts[5];
-
-	if (this->numchips > doc->chips_per_floor) {
-		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
-		return -EIO;
-	}
-
-	if (DoC_is_MillenniumPlus(doc)) {
-		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
-		if (inftl_bbt_write)
-			this->bbt_td->options |= NAND_BBT_WRITE;
-		this->bbt_td->pages[0] = 2;
-		this->bbt_md = NULL;
-	} else {
-		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
-		if (inftl_bbt_write)
-			this->bbt_td->options |= NAND_BBT_WRITE;
-		this->bbt_td->offs = 8;
-		this->bbt_td->len = 8;
-		this->bbt_td->veroffs = 7;
-		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
-		this->bbt_td->reserved_block_code = 0x01;
-		this->bbt_td->pattern = "MSYS_BBT";
-
-		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
-		if (inftl_bbt_write)
-			this->bbt_md->options |= NAND_BBT_WRITE;
-		this->bbt_md->offs = 8;
-		this->bbt_md->len = 8;
-		this->bbt_md->veroffs = 7;
-		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
-		this->bbt_md->reserved_block_code = 0x01;
-		this->bbt_md->pattern = "TBB_SYSM";
-	}
-
-	ret = this->scan_bbt(mtd);
-	if (ret)
-		return ret;
-
-	memset((char *)parts, 0, sizeof(parts));
-	numparts = inftl_partscan(mtd, parts);
-	/* At least for now, require the INFTL Media Header.  We could probably
-	   do without it for non-INFTL use, since all it gives us is
-	   autopartitioning, but I want to give it more thought. */
-	if (!numparts)
-		return -EIO;
-	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
-}
-
-static inline int __init doc2000_init(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-
-	this->read_byte = doc2000_read_byte;
-	this->write_buf = doc2000_writebuf;
-	this->read_buf = doc2000_readbuf;
-	doc->late_init = nftl_scan_bbt;
-
-	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
-	doc2000_count_chips(mtd);
-	mtd->name = "DiskOnChip 2000 (NFTL Model)";
-	return (4 * doc->chips_per_floor);
-}
-
-static inline int __init doc2001_init(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-
-	this->read_byte = doc2001_read_byte;
-	this->write_buf = doc2001_writebuf;
-	this->read_buf = doc2001_readbuf;
-
-	ReadDOC(doc->virtadr, ChipID);
-	ReadDOC(doc->virtadr, ChipID);
-	ReadDOC(doc->virtadr, ChipID);
-	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
-		/* It's not a Millennium; it's one of the newer
-		   DiskOnChip 2000 units with a similar ASIC.
-		   Treat it like a Millennium, except that it
-		   can have multiple chips. */
-		doc2000_count_chips(mtd);
-		mtd->name = "DiskOnChip 2000 (INFTL Model)";
-		doc->late_init = inftl_scan_bbt;
-		return (4 * doc->chips_per_floor);
-	} else {
-		/* Bog-standard Millennium */
-		doc->chips_per_floor = 1;
-		mtd->name = "DiskOnChip Millennium";
-		doc->late_init = nftl_scan_bbt;
-		return 1;
-	}
-}
-
-static inline int __init doc2001plus_init(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct doc_priv *doc = nand_get_controller_data(this);
-
-	this->read_byte = doc2001plus_read_byte;
-	this->write_buf = doc2001plus_writebuf;
-	this->read_buf = doc2001plus_readbuf;
-	doc->late_init = inftl_scan_bbt;
-	this->cmd_ctrl = NULL;
-	this->select_chip = doc2001plus_select_chip;
-	this->cmdfunc = doc2001plus_command;
-	this->ecc.hwctl = doc2001plus_enable_hwecc;
-
-	doc->chips_per_floor = 1;
-	mtd->name = "DiskOnChip Millennium Plus";
-
-	return 1;
-}
-
-static int __init doc_probe(unsigned long physadr)
-{
-	unsigned char ChipID;
-	struct mtd_info *mtd;
-	struct nand_chip *nand;
-	struct doc_priv *doc;
-	void __iomem *virtadr;
-	unsigned char save_control;
-	unsigned char tmp, tmpb, tmpc;
-	int reg, len, numchips;
-	int ret = 0;
-
-	if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
-		return -EBUSY;
-	virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
-	if (!virtadr) {
-		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
-		ret = -EIO;
-		goto error_ioremap;
-	}
-
-	/* It's not possible to cleanly detect the DiskOnChip - the
-	 * bootup procedure will put the device into reset mode, and
-	 * it's not possible to talk to it without actually writing
-	 * to the DOCControl register. So we store the current contents
-	 * of the DOCControl register's location, in case we later decide
-	 * that it's not a DiskOnChip, and want to put it back how we
-	 * found it.
-	 */
-	save_control = ReadDOC(virtadr, DOCControl);
-
-	/* Reset the DiskOnChip ASIC */
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
-
-	/* Enable the DiskOnChip ASIC */
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
-	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
-
-	ChipID = ReadDOC(virtadr, ChipID);
-
-	switch (ChipID) {
-	case DOC_ChipID_Doc2k:
-		reg = DoC_2k_ECCStatus;
-		break;
-	case DOC_ChipID_DocMil:
-		reg = DoC_ECCConf;
-		break;
-	case DOC_ChipID_DocMilPlus16:
-	case DOC_ChipID_DocMilPlus32:
-	case 0:
-		/* Possible Millennium Plus, need to do more checks */
-		/* Possibly release from power down mode */
-		for (tmp = 0; (tmp < 4); tmp++)
-			ReadDOC(virtadr, Mplus_Power);
-
-		/* Reset the Millennium Plus ASIC */
-		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
-		WriteDOC(tmp, virtadr, Mplus_DOCControl);
-		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
-
-		mdelay(1);
-		/* Enable the Millennium Plus ASIC */
-		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
-		WriteDOC(tmp, virtadr, Mplus_DOCControl);
-		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
-		mdelay(1);
-
-		ChipID = ReadDOC(virtadr, ChipID);
-
-		switch (ChipID) {
-		case DOC_ChipID_DocMilPlus16:
-			reg = DoC_Mplus_Toggle;
-			break;
-		case DOC_ChipID_DocMilPlus32:
-			printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
-		default:
-			ret = -ENODEV;
-			goto notfound;
-		}
-		break;
-
-	default:
-		ret = -ENODEV;
-		goto notfound;
-	}
-	/* Check the TOGGLE bit in the ECC register */
-	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
-	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
-	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
-	if ((tmp == tmpb) || (tmp != tmpc)) {
-		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
-		ret = -ENODEV;
-		goto notfound;
-	}
-
-	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
-		unsigned char oldval;
-		unsigned char newval;
-		nand = mtd_to_nand(mtd);
-		doc = nand_get_controller_data(nand);
-		/* Use the alias resolution register to determine if this is
-		   in fact the same DOC aliased to a new address.  If writes
-		   to one chip's alias resolution register change the value on
-		   the other chip, they're the same chip. */
-		if (ChipID == DOC_ChipID_DocMilPlus16) {
-			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
-			newval = ReadDOC(virtadr, Mplus_AliasResolution);
-		} else {
-			oldval = ReadDOC(doc->virtadr, AliasResolution);
-			newval = ReadDOC(virtadr, AliasResolution);
-		}
-		if (oldval != newval)
-			continue;
-		if (ChipID == DOC_ChipID_DocMilPlus16) {
-			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
-			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
-			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it
-		} else {
-			WriteDOC(~newval, virtadr, AliasResolution);
-			oldval = ReadDOC(doc->virtadr, AliasResolution);
-			WriteDOC(newval, virtadr, AliasResolution);	// restore it
-		}
-		newval = ~newval;
-		if (oldval == newval) {
-			printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
-			goto notfound;
-		}
-	}
-
-	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
-
-	len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
-	      (2 * sizeof(struct nand_bbt_descr));
-	nand = kzalloc(len, GFP_KERNEL);
-	if (!nand) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
-	mtd			= nand_to_mtd(nand);
-	doc			= (struct doc_priv *) (nand + 1);
-	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);
-	nand->bbt_md		= nand->bbt_td + 1;
-
-	mtd->owner		= THIS_MODULE;
-	mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
-
-	nand_set_controller_data(nand, doc);
-	nand->select_chip	= doc200x_select_chip;
-	nand->cmd_ctrl		= doc200x_hwcontrol;
-	nand->dev_ready		= doc200x_dev_ready;
-	nand->waitfunc		= doc200x_wait;
-	nand->block_bad		= doc200x_block_bad;
-	nand->ecc.hwctl		= doc200x_enable_hwecc;
-	nand->ecc.calculate	= doc200x_calculate_ecc;
-	nand->ecc.correct	= doc200x_correct_data;
-
-	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;
-	nand->ecc.size		= 512;
-	nand->ecc.bytes		= 6;
-	nand->ecc.strength	= 2;
-	nand->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
-	nand->bbt_options	= NAND_BBT_USE_FLASH;
-	/* Skip the automatic BBT scan so we can run it manually */
-	nand->options		|= NAND_SKIP_BBTSCAN;
-
-	doc->physadr		= physadr;
-	doc->virtadr		= virtadr;
-	doc->ChipID		= ChipID;
-	doc->curfloor		= -1;
-	doc->curchip		= -1;
-	doc->mh0_page		= -1;
-	doc->mh1_page		= -1;
-	doc->nextdoc		= doclist;
-
-	if (ChipID == DOC_ChipID_Doc2k)
-		numchips = doc2000_init(mtd);
-	else if (ChipID == DOC_ChipID_DocMilPlus16)
-		numchips = doc2001plus_init(mtd);
-	else
-		numchips = doc2001_init(mtd);
-
-	if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
-		/* DBB note: i believe nand_release is necessary here, as
-		   buffers may have been allocated in nand_base.  Check with
-		   Thomas. FIX ME! */
-		/* nand_release will call mtd_device_unregister, but we
-		   haven't yet added it.  This is handled without incident by
-		   mtd_device_unregister, as far as I can tell. */
-		nand_release(mtd);
-		kfree(nand);
-		goto fail;
-	}
-
-	/* Success! */
-	doclist = mtd;
-	return 0;
-
- notfound:
-	/* Put back the contents of the DOCControl register, in case it's not
-	   actually a DiskOnChip.  */
-	WriteDOC(save_control, virtadr, DOCControl);
- fail:
-	iounmap(virtadr);
-
-error_ioremap:
-	release_mem_region(physadr, DOC_IOREMAP_LEN);
-
-	return ret;
-}
-
-static void release_nanddoc(void)
-{
-	struct mtd_info *mtd, *nextmtd;
-	struct nand_chip *nand;
-	struct doc_priv *doc;
-
-	for (mtd = doclist; mtd; mtd = nextmtd) {
-		nand = mtd_to_nand(mtd);
-		doc = nand_get_controller_data(nand);
-
-		nextmtd = doc->nextdoc;
-		nand_release(mtd);
-		iounmap(doc->virtadr);
-		release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
-		kfree(nand);
-	}
-}
-
-static int __init init_nanddoc(void)
-{
-	int i, ret = 0;
-
-	/* We could create the decoder on demand, if memory is a concern.
-	 * This way we have it handy, if an error happens
-	 *
-	 * Symbolsize is 10 (bits)
-	 * Primitve polynomial is x^10+x^3+1
-	 * first consecutive root is 510
-	 * primitve element to generate roots = 1
-	 * generator polinomial degree = 4
-	 */
-	rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
-	if (!rs_decoder) {
-		printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
-		return -ENOMEM;
-	}
-
-	if (doc_config_location) {
-		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
-		ret = doc_probe(doc_config_location);
-		if (ret < 0)
-			goto outerr;
-	} else {
-		for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
-			doc_probe(doc_locations[i]);
-		}
-	}
-	/* No banner message any more. Print a message if no DiskOnChip
-	   found, so the user knows we at least tried. */
-	if (!doclist) {
-		printk(KERN_INFO "No valid DiskOnChip devices found\n");
-		ret = -ENODEV;
-		goto outerr;
-	}
-	return 0;
- outerr:
-	free_rs(rs_decoder);
-	return ret;
-}
-
-static void __exit cleanup_nanddoc(void)
-{
-	/* Cleanup the nand/DoC resources */
-	release_nanddoc();
-
-	/* Free the reed solomon resources */
-	if (rs_decoder) {
-		free_rs(rs_decoder);
-	}
-}
-
-module_init(init_nanddoc);
-module_exit(cleanup_nanddoc);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
deleted file mode 100644
index 72f1327c4430..000000000000
--- a/drivers/mtd/nand/docg4.c
+++ /dev/null
@@ -1,1421 +0,0 @@
-/*
- *  Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
- *
- * mtd nand driver for M-Systems DiskOnChip G4
- *
- * 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.
- *
- * Tested on the Palm Treo 680.  The G4 is also present on Toshiba Portege, Asus
- * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
- * Should work on these as well.  Let me know!
- *
- * TODO:
- *
- *  Mechanism for management of password-protected areas
- *
- *  Hamming ecc when reading oob only
- *
- *  According to the M-Sys documentation, this device is also available in a
- *  "dual-die" configuration having a 256MB capacity, but no mechanism for
- *  detecting this variant is documented.  Currently this driver assumes 128MB
- *  capacity.
- *
- *  Support for multiple cascaded devices ("floors").  Not sure which gadgets
- *  contain multiple G4s in a cascaded configuration, if any.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/bch.h>
-#include <linux/bitrev.h>
-#include <linux/jiffies.h>
-
-/*
- * In "reliable mode" consecutive 2k pages are used in parallel (in some
- * fashion) to store the same data.  The data can be read back from the
- * even-numbered pages in the normal manner; odd-numbered pages will appear to
- * contain junk.  Systems that boot from the docg4 typically write the secondary
- * program loader (SPL) code in this mode.  The SPL is loaded by the initial
- * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
- * to the reset vector address).  This module parameter enables you to use this
- * driver to write the SPL.  When in this mode, no more than 2k of data can be
- * written at a time, because the addresses do not increment in the normal
- * manner, and the starting offset must be within an even-numbered 2k region;
- * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
- * 0x1a00, ...  Reliable mode is a special case and should not be used unless
- * you know what you're doing.
- */
-static bool reliable_mode;
-module_param(reliable_mode, bool, 0);
-MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
-
-/*
- * You'll want to ignore badblocks if you're reading a partition that contains
- * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
- * it does not use mtd nand's method for marking bad blocks (using oob area).
- * This will also skip the check of the "page written" flag.
- */
-static bool ignore_badblocks;
-module_param(ignore_badblocks, bool, 0);
-MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
-
-struct docg4_priv {
-	struct mtd_info	*mtd;
-	struct device *dev;
-	void __iomem *virtadr;
-	int status;
-	struct {
-		unsigned int command;
-		int column;
-		int page;
-	} last_command;
-	uint8_t oob_buf[16];
-	uint8_t ecc_buf[7];
-	int oob_page;
-	struct bch_control *bch;
-};
-
-/*
- * Defines prefixed with DOCG4 are unique to the diskonchip G4.  All others are
- * shared with other diskonchip devices (P3, G3 at least).
- *
- * Functions with names prefixed with docg4_ are mtd / nand interface functions
- * (though they may also be called internally).  All others are internal.
- */
-
-#define DOC_IOSPACE_DATA		0x0800
-
-/* register offsets */
-#define DOC_CHIPID			0x1000
-#define DOC_DEVICESELECT		0x100a
-#define DOC_ASICMODE			0x100c
-#define DOC_DATAEND			0x101e
-#define DOC_NOP				0x103e
-
-#define DOC_FLASHSEQUENCE		0x1032
-#define DOC_FLASHCOMMAND		0x1034
-#define DOC_FLASHADDRESS		0x1036
-#define DOC_FLASHCONTROL		0x1038
-#define DOC_ECCCONF0			0x1040
-#define DOC_ECCCONF1			0x1042
-#define DOC_HAMMINGPARITY		0x1046
-#define DOC_BCH_SYNDROM(idx)		(0x1048 + idx)
-
-#define DOC_ASICMODECONFIRM		0x1072
-#define DOC_CHIPID_INV			0x1074
-#define DOC_POWERMODE			0x107c
-
-#define DOCG4_MYSTERY_REG		0x1050
-
-/* apparently used only to write oob bytes 6 and 7 */
-#define DOCG4_OOB_6_7			0x1052
-
-/* DOC_FLASHSEQUENCE register commands */
-#define DOC_SEQ_RESET			0x00
-#define DOCG4_SEQ_PAGE_READ		0x03
-#define DOCG4_SEQ_FLUSH			0x29
-#define DOCG4_SEQ_PAGEWRITE		0x16
-#define DOCG4_SEQ_PAGEPROG		0x1e
-#define DOCG4_SEQ_BLOCKERASE		0x24
-#define DOCG4_SEQ_SETMODE		0x45
-
-/* DOC_FLASHCOMMAND register commands */
-#define DOCG4_CMD_PAGE_READ             0x00
-#define DOC_CMD_ERASECYCLE2		0xd0
-#define DOCG4_CMD_FLUSH                 0x70
-#define DOCG4_CMD_READ2                 0x30
-#define DOC_CMD_PROG_BLOCK_ADDR		0x60
-#define DOCG4_CMD_PAGEWRITE		0x80
-#define DOC_CMD_PROG_CYCLE2		0x10
-#define DOCG4_CMD_FAST_MODE		0xa3 /* functionality guessed */
-#define DOC_CMD_RELIABLE_MODE		0x22
-#define DOC_CMD_RESET			0xff
-
-/* DOC_POWERMODE register bits */
-#define DOC_POWERDOWN_READY		0x80
-
-/* DOC_FLASHCONTROL register bits */
-#define DOC_CTRL_CE			0x10
-#define DOC_CTRL_UNKNOWN		0x40
-#define DOC_CTRL_FLASHREADY		0x01
-
-/* DOC_ECCCONF0 register bits */
-#define DOC_ECCCONF0_READ_MODE		0x8000
-#define DOC_ECCCONF0_UNKNOWN		0x2000
-#define DOC_ECCCONF0_ECC_ENABLE	        0x1000
-#define DOC_ECCCONF0_DATA_BYTES_MASK	0x07ff
-
-/* DOC_ECCCONF1 register bits */
-#define DOC_ECCCONF1_BCH_SYNDROM_ERR	0x80
-#define DOC_ECCCONF1_ECC_ENABLE         0x07
-#define DOC_ECCCONF1_PAGE_IS_WRITTEN	0x20
-
-/* DOC_ASICMODE register bits */
-#define DOC_ASICMODE_RESET		0x00
-#define DOC_ASICMODE_NORMAL		0x01
-#define DOC_ASICMODE_POWERDOWN		0x02
-#define DOC_ASICMODE_MDWREN		0x04
-#define DOC_ASICMODE_BDETCT_RESET	0x08
-#define DOC_ASICMODE_RSTIN_RESET	0x10
-#define DOC_ASICMODE_RAM_WE		0x20
-
-/* good status values read after read/write/erase operations */
-#define DOCG4_PROGSTATUS_GOOD          0x51
-#define DOCG4_PROGSTATUS_GOOD_2        0xe0
-
-/*
- * On read operations (page and oob-only), the first byte read from I/O reg is a
- * status.  On error, it reads 0x73; otherwise, it reads either 0x71 (first read
- * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
- */
-#define DOCG4_READ_ERROR           0x02 /* bit 1 indicates read error */
-
-/* anatomy of the device */
-#define DOCG4_CHIP_SIZE        0x8000000
-#define DOCG4_PAGE_SIZE        0x200
-#define DOCG4_PAGES_PER_BLOCK  0x200
-#define DOCG4_BLOCK_SIZE       (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
-#define DOCG4_NUMBLOCKS        (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
-#define DOCG4_OOB_SIZE         0x10
-#define DOCG4_CHIP_SHIFT       27    /* log_2(DOCG4_CHIP_SIZE) */
-#define DOCG4_PAGE_SHIFT       9     /* log_2(DOCG4_PAGE_SIZE) */
-#define DOCG4_ERASE_SHIFT      18    /* log_2(DOCG4_BLOCK_SIZE) */
-
-/* all but the last byte is included in ecc calculation */
-#define DOCG4_BCH_SIZE         (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
-
-#define DOCG4_USERDATA_LEN     520 /* 512 byte page plus 8 oob avail to user */
-
-/* expected values from the ID registers */
-#define DOCG4_IDREG1_VALUE     0x0400
-#define DOCG4_IDREG2_VALUE     0xfbff
-
-/* primitive polynomial used to build the Galois field used by hw ecc gen */
-#define DOCG4_PRIMITIVE_POLY   0x4443
-
-#define DOCG4_M                14  /* Galois field is of order 2^14 */
-#define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
-
-#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
-#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
-
-/*
- * Bytes 0, 1 are used as badblock marker.
- * Bytes 2 - 6 are available to the user.
- * Byte 7 is hamming ecc for first 7 oob bytes only.
- * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
- * Byte 15 (the last) is used by the driver as a "page written" flag.
- */
-static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
-			       struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 7;
-	oobregion->length = 9;
-
-	return 0;
-}
-
-static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
-				struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 2;
-	oobregion->length = 5;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
-	.ecc = docg4_ooblayout_ecc,
-	.free = docg4_ooblayout_free,
-};
-
-/*
- * The device has a nop register which M-Sys claims is for the purpose of
- * inserting precise delays.  But beware; at least some operations fail if the
- * nop writes are replaced with a generic delay!
- */
-static inline void write_nop(void __iomem *docptr)
-{
-	writew(0, docptr + DOC_NOP);
-}
-
-static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	int i;
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	uint16_t *p = (uint16_t *) buf;
-	len >>= 1;
-
-	for (i = 0; i < len; i++)
-		p[i] = readw(nand->IO_ADDR_R);
-}
-
-static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	int i;
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	uint16_t *p = (uint16_t *) buf;
-	len >>= 1;
-
-	for (i = 0; i < len; i++)
-		writew(p[i], nand->IO_ADDR_W);
-}
-
-static int poll_status(struct docg4_priv *doc)
-{
-	/*
-	 * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
-	 * register.  Operations known to take a long time (e.g., block erase)
-	 * should sleep for a while before calling this.
-	 */
-
-	uint16_t flash_status;
-	unsigned long timeo;
-	void __iomem *docptr = doc->virtadr;
-
-	dev_dbg(doc->dev, "%s...\n", __func__);
-
-	/* hardware quirk requires reading twice initially */
-	flash_status = readw(docptr + DOC_FLASHCONTROL);
-
-	timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
-	do {
-		cpu_relax();
-		flash_status = readb(docptr + DOC_FLASHCONTROL);
-	} while (!(flash_status & DOC_CTRL_FLASHREADY) &&
-		 time_before(jiffies, timeo));
-
-	if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
-		dev_err(doc->dev, "%s: timed out!\n", __func__);
-		return NAND_STATUS_FAIL;
-	}
-
-	return 0;
-}
-
-
-static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
-{
-
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	int status = NAND_STATUS_WP;       /* inverse logic?? */
-	dev_dbg(doc->dev, "%s...\n", __func__);
-
-	/* report any previously unreported error */
-	if (doc->status) {
-		status |= doc->status;
-		doc->status = 0;
-		return status;
-	}
-
-	status |= poll_status(doc);
-	return status;
-}
-
-static void docg4_select_chip(struct mtd_info *mtd, int chip)
-{
-	/*
-	 * Select among multiple cascaded chips ("floors").  Multiple floors are
-	 * not yet supported, so the only valid non-negative value is 0.
-	 */
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-
-	dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
-
-	if (chip < 0)
-		return;		/* deselected */
-
-	if (chip > 0)
-		dev_warn(doc->dev, "multiple floors currently unsupported\n");
-
-	writew(0, docptr + DOC_DEVICESELECT);
-}
-
-static void reset(struct mtd_info *mtd)
-{
-	/* full device reset */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-
-	writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
-	       docptr + DOC_ASICMODE);
-	writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
-	       docptr + DOC_ASICMODECONFIRM);
-	write_nop(docptr);
-
-	writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
-	       docptr + DOC_ASICMODE);
-	writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
-	       docptr + DOC_ASICMODECONFIRM);
-
-	writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
-
-	poll_status(doc);
-}
-
-static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
-{
-	/* read the 7 hw-generated ecc bytes */
-
-	int i;
-	for (i = 0; i < 7; i++) { /* hw quirk; read twice */
-		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
-		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
-	}
-}
-
-static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
-{
-	/*
-	 * Called after a page read when hardware reports bitflips.
-	 * Up to four bitflips can be corrected.
-	 */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	int i, numerrs, errpos[4];
-	const uint8_t blank_read_hwecc[8] = {
-		0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
-
-	read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
-
-	/* check if read error is due to a blank page */
-	if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
-		return 0;	/* yes */
-
-	/* skip additional check of "written flag" if ignore_badblocks */
-	if (ignore_badblocks == false) {
-
-		/*
-		 * If the hw ecc bytes are not those of a blank page, there's
-		 * still a chance that the page is blank, but was read with
-		 * errors.  Check the "written flag" in last oob byte, which
-		 * is set to zero when a page is written.  If more than half
-		 * the bits are set, assume a blank page.  Unfortunately, the
-		 * bit flips(s) are not reported in stats.
-		 */
-
-		if (nand->oob_poi[15]) {
-			int bit, numsetbits = 0;
-			unsigned long written_flag = nand->oob_poi[15];
-			for_each_set_bit(bit, &written_flag, 8)
-				numsetbits++;
-			if (numsetbits > 4) { /* assume blank */
-				dev_warn(doc->dev,
-					 "error(s) in blank page "
-					 "at offset %08x\n",
-					 page * DOCG4_PAGE_SIZE);
-				return 0;
-			}
-		}
-	}
-
-	/*
-	 * The hardware ecc unit produces oob_ecc ^ calc_ecc.  The kernel's bch
-	 * algorithm is used to decode this.  However the hw operates on page
-	 * data in a bit order that is the reverse of that of the bch alg,
-	 * requiring that the bits be reversed on the result.  Thanks to Ivan
-	 * Djelic for his analysis!
-	 */
-	for (i = 0; i < 7; i++)
-		doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
-
-	numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
-			     doc->ecc_buf, NULL, errpos);
-
-	if (numerrs == -EBADMSG) {
-		dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
-			 page * DOCG4_PAGE_SIZE);
-		return -EBADMSG;
-	}
-
-	BUG_ON(numerrs < 0);	/* -EINVAL, or anything other than -EBADMSG */
-
-	/* undo last step in BCH alg (modulo mirroring not needed) */
-	for (i = 0; i < numerrs; i++)
-		errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
-
-	/* fix the errors */
-	for (i = 0; i < numerrs; i++) {
-
-		/* ignore if error within oob ecc bytes */
-		if (errpos[i] > DOCG4_USERDATA_LEN * 8)
-			continue;
-
-		/* if error within oob area preceeding ecc bytes... */
-		if (errpos[i] > DOCG4_PAGE_SIZE * 8)
-			change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
-				   (unsigned long *)nand->oob_poi);
-
-		else    /* error in page data */
-			change_bit(errpos[i], (unsigned long *)buf);
-	}
-
-	dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
-		   numerrs, page * DOCG4_PAGE_SIZE);
-
-	return numerrs;
-}
-
-static uint8_t docg4_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-
-	dev_dbg(doc->dev, "%s\n", __func__);
-
-	if (doc->last_command.command == NAND_CMD_STATUS) {
-		int status;
-
-		/*
-		 * Previous nand command was status request, so nand
-		 * infrastructure code expects to read the status here.  If an
-		 * error occurred in a previous operation, report it.
-		 */
-		doc->last_command.command = 0;
-
-		if (doc->status) {
-			status = doc->status;
-			doc->status = 0;
-		}
-
-		/* why is NAND_STATUS_WP inverse logic?? */
-		else
-			status = NAND_STATUS_WP | NAND_STATUS_READY;
-
-		return status;
-	}
-
-	dev_warn(doc->dev, "unexpected call to read_byte()\n");
-
-	return 0;
-}
-
-static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
-{
-	/* write the four address bytes packed in docg4_addr to the device */
-
-	void __iomem *docptr = doc->virtadr;
-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-	docg4_addr >>= 8;
-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-	docg4_addr >>= 8;
-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-	docg4_addr >>= 8;
-	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-}
-
-static int read_progstatus(struct docg4_priv *doc)
-{
-	/*
-	 * This apparently checks the status of programming.  Done after an
-	 * erasure, and after page data is written.  On error, the status is
-	 * saved, to be later retrieved by the nand infrastructure code.
-	 */
-	void __iomem *docptr = doc->virtadr;
-
-	/* status is read from the I/O reg */
-	uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
-	uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
-	uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
-
-	dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
-	      __func__, status1, status2, status3);
-
-	if (status1 != DOCG4_PROGSTATUS_GOOD
-	    || status2 != DOCG4_PROGSTATUS_GOOD_2
-	    || status3 != DOCG4_PROGSTATUS_GOOD_2) {
-		doc->status = NAND_STATUS_FAIL;
-		dev_warn(doc->dev, "read_progstatus failed: "
-			 "%02x, %02x, %02x\n", status1, status2, status3);
-		return -EIO;
-	}
-	return 0;
-}
-
-static int pageprog(struct mtd_info *mtd)
-{
-	/*
-	 * Final step in writing a page.  Writes the contents of its
-	 * internal buffer out to the flash array, or some such.
-	 */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	int retval = 0;
-
-	dev_dbg(doc->dev, "docg4: %s\n", __func__);
-
-	writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
-	writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	/* Just busy-wait; usleep_range() slows things down noticeably. */
-	poll_status(doc);
-
-	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
-	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
-	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	retval = read_progstatus(doc);
-	writew(0, docptr + DOC_DATAEND);
-	write_nop(docptr);
-	poll_status(doc);
-	write_nop(docptr);
-
-	return retval;
-}
-
-static void sequence_reset(struct mtd_info *mtd)
-{
-	/* common starting sequence for all operations */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-
-	writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
-	writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
-	writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-	write_nop(docptr);
-	poll_status(doc);
-	write_nop(docptr);
-}
-
-static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
-	/* first step in reading a page */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-
-	dev_dbg(doc->dev,
-	      "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
-
-	sequence_reset(mtd);
-
-	writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
-	writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-
-	write_addr(doc, docg4_addr);
-
-	write_nop(docptr);
-	writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	poll_status(doc);
-}
-
-static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
-	/* first step in writing a page */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-
-	dev_dbg(doc->dev,
-	      "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
-	sequence_reset(mtd);
-
-	if (unlikely(reliable_mode)) {
-		writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
-		writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
-		writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
-		write_nop(docptr);
-	}
-
-	writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
-	writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-	write_addr(doc, docg4_addr);
-	write_nop(docptr);
-	write_nop(docptr);
-	poll_status(doc);
-}
-
-static uint32_t mtd_to_docg4_address(int page, int column)
-{
-	/*
-	 * Convert mtd address to format used by the device, 32 bit packed.
-	 *
-	 * Some notes on G4 addressing... The M-Sys documentation on this device
-	 * claims that pages are 2K in length, and indeed, the format of the
-	 * address used by the device reflects that.  But within each page are
-	 * four 512 byte "sub-pages", each with its own oob data that is
-	 * read/written immediately after the 512 bytes of page data.  This oob
-	 * data contains the ecc bytes for the preceeding 512 bytes.
-	 *
-	 * Rather than tell the mtd nand infrastructure that page size is 2k,
-	 * with four sub-pages each, we engage in a little subterfuge and tell
-	 * the infrastructure code that pages are 512 bytes in size.  This is
-	 * done because during the course of reverse-engineering the device, I
-	 * never observed an instance where an entire 2K "page" was read or
-	 * written as a unit.  Each "sub-page" is always addressed individually,
-	 * its data read/written, and ecc handled before the next "sub-page" is
-	 * addressed.
-	 *
-	 * This requires us to convert addresses passed by the mtd nand
-	 * infrastructure code to those used by the device.
-	 *
-	 * The address that is written to the device consists of four bytes: the
-	 * first two are the 2k page number, and the second is the index into
-	 * the page.  The index is in terms of 16-bit half-words and includes
-	 * the preceeding oob data, so e.g., the index into the second
-	 * "sub-page" is 0x108, and the full device address of the start of mtd
-	 * page 0x201 is 0x00800108.
-	 */
-	int g4_page = page / 4;	                      /* device's 2K page */
-	int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
-	return (g4_page << 16) | g4_index;	      /* pack */
-}
-
-static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
-			  int page_addr)
-{
-	/* handle standard nand commands */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
-
-	dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
-	      __func__, command, page_addr, column);
-
-	/*
-	 * Save the command and its arguments.  This enables emulation of
-	 * standard flash devices, and also some optimizations.
-	 */
-	doc->last_command.command = command;
-	doc->last_command.column = column;
-	doc->last_command.page = page_addr;
-
-	switch (command) {
-
-	case NAND_CMD_RESET:
-		reset(mtd);
-		break;
-
-	case NAND_CMD_READ0:
-		read_page_prologue(mtd, g4_addr);
-		break;
-
-	case NAND_CMD_STATUS:
-		/* next call to read_byte() will expect a status */
-		break;
-
-	case NAND_CMD_SEQIN:
-		if (unlikely(reliable_mode)) {
-			uint16_t g4_page = g4_addr >> 16;
-
-			/* writes to odd-numbered 2k pages are invalid */
-			if (g4_page & 0x01)
-				dev_warn(doc->dev,
-					 "invalid reliable mode address\n");
-		}
-
-		write_page_prologue(mtd, g4_addr);
-
-		/* hack for deferred write of oob bytes */
-		if (doc->oob_page == page_addr)
-			memcpy(nand->oob_poi, doc->oob_buf, 16);
-		break;
-
-	case NAND_CMD_PAGEPROG:
-		pageprog(mtd);
-		break;
-
-	/* we don't expect these, based on review of nand_base.c */
-	case NAND_CMD_READOOB:
-	case NAND_CMD_READID:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-		dev_warn(doc->dev, "docg4_command: "
-			 "unexpected nand command 0x%x\n", command);
-		break;
-
-	}
-}
-
-static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
-		     uint8_t *buf, int page, bool use_ecc)
-{
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	uint16_t status, edc_err, *buf16;
-	int bits_corrected = 0;
-
-	dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
-
-	nand_read_page_op(nand, page, 0, NULL, 0);
-
-	writew(DOC_ECCCONF0_READ_MODE |
-	       DOC_ECCCONF0_ECC_ENABLE |
-	       DOC_ECCCONF0_UNKNOWN |
-	       DOCG4_BCH_SIZE,
-	       docptr + DOC_ECCCONF0);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	/* the 1st byte from the I/O reg is a status; the rest is page data */
-	status = readw(docptr + DOC_IOSPACE_DATA);
-	if (status & DOCG4_READ_ERROR) {
-		dev_err(doc->dev,
-			"docg4_read_page: bad status: 0x%02x\n", status);
-		writew(0, docptr + DOC_DATAEND);
-		return -EIO;
-	}
-
-	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
-	docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
-
-	/* this device always reads oob after page data */
-	/* first 14 oob bytes read from I/O reg */
-	docg4_read_buf(mtd, nand->oob_poi, 14);
-
-	/* last 2 read from another reg */
-	buf16 = (uint16_t *)(nand->oob_poi + 14);
-	*buf16 = readw(docptr + DOCG4_MYSTERY_REG);
-
-	write_nop(docptr);
-
-	if (likely(use_ecc == true)) {
-
-		/* read the register that tells us if bitflip(s) detected  */
-		edc_err = readw(docptr + DOC_ECCCONF1);
-		edc_err = readw(docptr + DOC_ECCCONF1);
-		dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
-
-		/* If bitflips are reported, attempt to correct with ecc */
-		if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
-			bits_corrected = correct_data(mtd, buf, page);
-			if (bits_corrected == -EBADMSG)
-				mtd->ecc_stats.failed++;
-			else
-				mtd->ecc_stats.corrected += bits_corrected;
-		}
-	}
-
-	writew(0, docptr + DOC_DATAEND);
-	if (bits_corrected == -EBADMSG)	  /* uncorrectable errors */
-		return 0;
-	return bits_corrected;
-}
-
-
-static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
-			       uint8_t *buf, int oob_required, int page)
-{
-	return read_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
-			   uint8_t *buf, int oob_required, int page)
-{
-	return read_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
-			  int page)
-{
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	uint16_t status;
-
-	dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
-
-	nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
-
-	writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	/* the 1st byte from the I/O reg is a status; the rest is oob data */
-	status = readw(docptr + DOC_IOSPACE_DATA);
-	if (status & DOCG4_READ_ERROR) {
-		dev_warn(doc->dev,
-			 "docg4_read_oob failed: status = 0x%02x\n", status);
-		return -EIO;
-	}
-
-	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
-	docg4_read_buf(mtd, nand->oob_poi, 16);
-
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	writew(0, docptr + DOC_DATAEND);
-	write_nop(docptr);
-
-	return 0;
-}
-
-static int docg4_erase_block(struct mtd_info *mtd, int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	uint16_t g4_page;
-	int status;
-
-	dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
-
-	sequence_reset(mtd);
-
-	writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
-	writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-
-	/* only 2 bytes of address are written to specify erase block */
-	g4_page = (uint16_t)(page / 4);  /* to g4's 2k page addressing */
-	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
-	g4_page >>= 8;
-	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
-	write_nop(docptr);
-
-	/* start the erasure */
-	writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	usleep_range(500, 1000); /* erasure is long; take a snooze */
-	poll_status(doc);
-	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
-	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
-	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-	write_nop(docptr);
-
-	read_progstatus(doc);
-
-	writew(0, docptr + DOC_DATAEND);
-	write_nop(docptr);
-	poll_status(doc);
-	write_nop(docptr);
-
-	status = nand->waitfunc(mtd, nand);
-	if (status < 0)
-		return status;
-
-	return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
-		      const uint8_t *buf, int page, bool use_ecc)
-{
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	uint8_t ecc_buf[8];
-
-	dev_dbg(doc->dev, "%s...\n", __func__);
-
-	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
-
-	writew(DOC_ECCCONF0_ECC_ENABLE |
-	       DOC_ECCCONF0_UNKNOWN |
-	       DOCG4_BCH_SIZE,
-	       docptr + DOC_ECCCONF0);
-	write_nop(docptr);
-
-	/* write the page data */
-	docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
-
-	/* oob bytes 0 through 5 are written to I/O reg */
-	docg4_write_buf16(mtd, nand->oob_poi, 6);
-
-	/* oob byte 6 written to a separate reg */
-	writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
-
-	write_nop(docptr);
-	write_nop(docptr);
-
-	/* write hw-generated ecc bytes to oob */
-	if (likely(use_ecc == true)) {
-		/* oob byte 7 is hamming code */
-		uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
-		hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
-		writew(hamming, docptr + DOCG4_OOB_6_7);
-		write_nop(docptr);
-
-		/* read the 7 bch bytes from ecc regs */
-		read_hw_ecc(docptr, ecc_buf);
-		ecc_buf[7] = 0;         /* clear the "page written" flag */
-	}
-
-	/* write user-supplied bytes to oob */
-	else {
-		writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
-		write_nop(docptr);
-		memcpy(ecc_buf, &nand->oob_poi[8], 8);
-	}
-
-	docg4_write_buf16(mtd, ecc_buf, 8);
-	write_nop(docptr);
-	write_nop(docptr);
-	writew(0, docptr + DOC_DATAEND);
-	write_nop(docptr);
-
-	return nand_prog_page_end_op(nand);
-}
-
-static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
-				const uint8_t *buf, int oob_required, int page)
-{
-	return write_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
-			     const uint8_t *buf, int oob_required, int page)
-{
-	return write_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
-			   int page)
-{
-	/*
-	 * Writing oob-only is not really supported, because MLC nand must write
-	 * oob bytes at the same time as page data.  Nonetheless, we save the
-	 * oob buffer contents here, and then write it along with the page data
-	 * if the same page is subsequently written.  This allows user space
-	 * utilities that write the oob data prior to the page data to work
-	 * (e.g., nandwrite).  The disdvantage is that, if the intention was to
-	 * write oob only, the operation is quietly ignored.  Also, oob can get
-	 * corrupted if two concurrent processes are running nandwrite.
-	 */
-
-	/* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	doc->oob_page = page;
-	memcpy(doc->oob_buf, nand->oob_poi, 16);
-	return 0;
-}
-
-static int __init read_factory_bbt(struct mtd_info *mtd)
-{
-	/*
-	 * The device contains a read-only factory bad block table.  Read it and
-	 * update the memory-based bbt accordingly.
-	 */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
-	uint8_t *buf;
-	int i, block;
-	__u32 eccfailed_stats = mtd->ecc_stats.failed;
-
-	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
-	if (buf == NULL)
-		return -ENOMEM;
-
-	read_page_prologue(mtd, g4_addr);
-	docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
-
-	/*
-	 * If no memory-based bbt was created, exit.  This will happen if module
-	 * parameter ignore_badblocks is set.  Then why even call this function?
-	 * For an unknown reason, block erase always fails if it's the first
-	 * operation after device power-up.  The above read ensures it never is.
-	 * Ugly, I know.
-	 */
-	if (nand->bbt == NULL)  /* no memory-based bbt */
-		goto exit;
-
-	if (mtd->ecc_stats.failed > eccfailed_stats) {
-		/*
-		 * Whoops, an ecc failure ocurred reading the factory bbt.
-		 * It is stored redundantly, so we get another chance.
-		 */
-		eccfailed_stats = mtd->ecc_stats.failed;
-		docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
-		if (mtd->ecc_stats.failed > eccfailed_stats) {
-			dev_warn(doc->dev,
-				 "The factory bbt could not be read!\n");
-			goto exit;
-		}
-	}
-
-	/*
-	 * Parse factory bbt and update memory-based bbt.  Factory bbt format is
-	 * simple: one bit per block, block numbers increase left to right (msb
-	 * to lsb).  Bit clear means bad block.
-	 */
-	for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
-		int bitnum;
-		unsigned long bits = ~buf[i];
-		for_each_set_bit(bitnum, &bits, 8) {
-			int badblock = block + 7 - bitnum;
-			nand->bbt[badblock / 4] |=
-				0x03 << ((badblock % 4) * 2);
-			mtd->ecc_stats.badblocks++;
-			dev_notice(doc->dev, "factory-marked bad block: %d\n",
-				   badblock);
-		}
-	}
- exit:
-	kfree(buf);
-	return 0;
-}
-
-static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	/*
-	 * Mark a block as bad.  Bad blocks are marked in the oob area of the
-	 * first page of the block.  The default scan_bbt() in the nand
-	 * infrastructure code works fine for building the memory-based bbt
-	 * during initialization, as does the nand infrastructure function that
-	 * checks if a block is bad by reading the bbt.  This function replaces
-	 * the nand default because writes to oob-only are not supported.
-	 */
-
-	int ret, i;
-	uint8_t *buf;
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	struct nand_bbt_descr *bbtd = nand->badblock_pattern;
-	int page = (int)(ofs >> nand->page_shift);
-	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
-
-	dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
-
-	if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
-		dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
-			 __func__, ofs);
-
-	/* allocate blank buffer for page data */
-	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
-	if (buf == NULL)
-		return -ENOMEM;
-
-	/* write bit-wise negation of pattern to oob buffer */
-	memset(nand->oob_poi, 0xff, mtd->oobsize);
-	for (i = 0; i < bbtd->len; i++)
-		nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
-
-	/* write first page of block */
-	write_page_prologue(mtd, g4_addr);
-	docg4_write_page(mtd, nand, buf, 1, page);
-	ret = pageprog(mtd);
-
-	kfree(buf);
-
-	return ret;
-}
-
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
-{
-	/* only called when module_param ignore_badblocks is set */
-	return 0;
-}
-
-static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	/*
-	 * Put the device into "deep power-down" mode.  Note that CE# must be
-	 * deasserted for this to take effect.  The xscale, e.g., can be
-	 * configured to float this signal when the processor enters power-down,
-	 * and a suitable pull-up ensures its deassertion.
-	 */
-
-	int i;
-	uint8_t pwr_down;
-	struct docg4_priv *doc = platform_get_drvdata(pdev);
-	void __iomem *docptr = doc->virtadr;
-
-	dev_dbg(doc->dev, "%s...\n", __func__);
-
-	/* poll the register that tells us we're ready to go to sleep */
-	for (i = 0; i < 10; i++) {
-		pwr_down = readb(docptr + DOC_POWERMODE);
-		if (pwr_down & DOC_POWERDOWN_READY)
-			break;
-		usleep_range(1000, 4000);
-	}
-
-	if (pwr_down & DOC_POWERDOWN_READY) {
-		dev_err(doc->dev, "suspend failed; "
-			"timeout polling DOC_POWERDOWN_READY\n");
-		return -EIO;
-	}
-
-	writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
-	       docptr + DOC_ASICMODE);
-	writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
-	       docptr + DOC_ASICMODECONFIRM);
-
-	write_nop(docptr);
-
-	return 0;
-}
-
-static int docg4_resume(struct platform_device *pdev)
-{
-
-	/*
-	 * Exit power-down.  Twelve consecutive reads of the address below
-	 * accomplishes this, assuming CE# has been asserted.
-	 */
-
-	struct docg4_priv *doc = platform_get_drvdata(pdev);
-	void __iomem *docptr = doc->virtadr;
-	int i;
-
-	dev_dbg(doc->dev, "%s...\n", __func__);
-
-	for (i = 0; i < 12; i++)
-		readb(docptr + 0x1fff);
-
-	return 0;
-}
-
-static void __init init_mtd_structs(struct mtd_info *mtd)
-{
-	/* initialize mtd and nand data structures */
-
-	/*
-	 * Note that some of the following initializations are not usually
-	 * required within a nand driver because they are performed by the nand
-	 * infrastructure code as part of nand_scan().  In this case they need
-	 * to be initialized here because we skip call to nand_scan_ident() (the
-	 * first half of nand_scan()).  The call to nand_scan_ident() is skipped
-	 * because for this device the chip id is not read in the manner of a
-	 * standard nand device.  Unfortunately, nand_scan_ident() does other
-	 * things as well, such as call nand_set_defaults().
-	 */
-
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-
-	mtd->size = DOCG4_CHIP_SIZE;
-	mtd->name = "Msys_Diskonchip_G4";
-	mtd->writesize = DOCG4_PAGE_SIZE;
-	mtd->erasesize = DOCG4_BLOCK_SIZE;
-	mtd->oobsize = DOCG4_OOB_SIZE;
-	mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
-	nand->chipsize = DOCG4_CHIP_SIZE;
-	nand->chip_shift = DOCG4_CHIP_SHIFT;
-	nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
-	nand->chip_delay = 20;
-	nand->page_shift = DOCG4_PAGE_SHIFT;
-	nand->pagemask = 0x3ffff;
-	nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
-	nand->badblockbits = 8;
-	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
-	nand->ecc.size = DOCG4_PAGE_SIZE;
-	nand->ecc.prepad = 8;
-	nand->ecc.bytes	= 8;
-	nand->ecc.strength = DOCG4_T;
-	nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
-	nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
-	nand->controller = &nand->hwcontrol;
-	nand_hw_control_init(nand->controller);
-
-	/* methods */
-	nand->cmdfunc = docg4_command;
-	nand->waitfunc = docg4_wait;
-	nand->select_chip = docg4_select_chip;
-	nand->read_byte = docg4_read_byte;
-	nand->block_markbad = docg4_block_markbad;
-	nand->read_buf = docg4_read_buf;
-	nand->write_buf = docg4_write_buf16;
-	nand->erase = docg4_erase_block;
-	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
-	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
-	nand->ecc.read_page = docg4_read_page;
-	nand->ecc.write_page = docg4_write_page;
-	nand->ecc.read_page_raw = docg4_read_page_raw;
-	nand->ecc.write_page_raw = docg4_write_page_raw;
-	nand->ecc.read_oob = docg4_read_oob;
-	nand->ecc.write_oob = docg4_write_oob;
-
-	/*
-	 * The way the nand infrastructure code is written, a memory-based bbt
-	 * is not created if NAND_SKIP_BBTSCAN is set.  With no memory bbt,
-	 * nand->block_bad() is used.  So when ignoring bad blocks, we skip the
-	 * scan and define a dummy block_bad() which always returns 0.
-	 */
-	if (ignore_badblocks) {
-		nand->options |= NAND_SKIP_BBTSCAN;
-		nand->block_bad	= docg4_block_neverbad;
-	}
-
-}
-
-static int __init read_id_reg(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct docg4_priv *doc = nand_get_controller_data(nand);
-	void __iomem *docptr = doc->virtadr;
-	uint16_t id1, id2;
-
-	/* check for presence of g4 chip by reading id registers */
-	id1 = readw(docptr + DOC_CHIPID);
-	id1 = readw(docptr + DOCG4_MYSTERY_REG);
-	id2 = readw(docptr + DOC_CHIPID_INV);
-	id2 = readw(docptr + DOCG4_MYSTERY_REG);
-
-	if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
-		dev_info(doc->dev,
-			 "NAND device: 128MiB Diskonchip G4 detected\n");
-		return 0;
-	}
-
-	return -ENODEV;
-}
-
-static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
-
-static int __init probe_docg4(struct platform_device *pdev)
-{
-	struct mtd_info *mtd;
-	struct nand_chip *nand;
-	void __iomem *virtadr;
-	struct docg4_priv *doc;
-	int len, retval;
-	struct resource *r;
-	struct device *dev = &pdev->dev;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		dev_err(dev, "no io memory resource defined!\n");
-		return -ENODEV;
-	}
-
-	virtadr = ioremap(r->start, resource_size(r));
-	if (!virtadr) {
-		dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
-		return -EIO;
-	}
-
-	len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
-	nand = kzalloc(len, GFP_KERNEL);
-	if (nand == NULL) {
-		retval = -ENOMEM;
-		goto fail_unmap;
-	}
-
-	mtd = nand_to_mtd(nand);
-	doc = (struct docg4_priv *) (nand + 1);
-	nand_set_controller_data(nand, doc);
-	mtd->dev.parent = &pdev->dev;
-	doc->virtadr = virtadr;
-	doc->dev = dev;
-
-	init_mtd_structs(mtd);
-
-	/* initialize kernel bch algorithm */
-	doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
-	if (doc->bch == NULL) {
-		retval = -EINVAL;
-		goto fail;
-	}
-
-	platform_set_drvdata(pdev, doc);
-
-	reset(mtd);
-	retval = read_id_reg(mtd);
-	if (retval == -ENODEV) {
-		dev_warn(dev, "No diskonchip G4 device found.\n");
-		goto fail;
-	}
-
-	retval = nand_scan_tail(mtd);
-	if (retval)
-		goto fail;
-
-	retval = read_factory_bbt(mtd);
-	if (retval)
-		goto fail;
-
-	retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
-	if (retval)
-		goto fail;
-
-	doc->mtd = mtd;
-	return 0;
-
-fail:
-	nand_release(mtd); /* deletes partitions and mtd devices */
-	free_bch(doc->bch);
-	kfree(nand);
-
-fail_unmap:
-	iounmap(virtadr);
-
-	return retval;
-}
-
-static int __exit cleanup_docg4(struct platform_device *pdev)
-{
-	struct docg4_priv *doc = platform_get_drvdata(pdev);
-	nand_release(doc->mtd);
-	free_bch(doc->bch);
-	kfree(mtd_to_nand(doc->mtd));
-	iounmap(doc->virtadr);
-	return 0;
-}
-
-static struct platform_driver docg4_driver = {
-	.driver		= {
-		.name	= "docg4",
-	},
-	.suspend	= docg4_suspend,
-	.resume		= docg4_resume,
-	.remove		= __exit_p(cleanup_docg4),
-};
-
-module_platform_driver_probe(docg4_driver, probe_docg4);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mike Dunn");
-MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
deleted file mode 100644
index 8b6dcd739ecb..000000000000
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/* Freescale Enhanced Local Bus Controller NAND driver
- *
- * Copyright © 2006-2007, 2010 Freescale Semiconductor
- *
- * Authors: Nick Spence <nick.spence@freescale.com>,
- *          Scott Wood <scottwood@freescale.com>
- *          Jack Lan <jack.lan@freescale.com>
- *          Roy Zang <tie-fei.zang@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/fsl_lbc.h>
-
-#define MAX_BANKS 8
-#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
-#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
-
-/* mtd information per set */
-
-struct fsl_elbc_mtd {
-	struct nand_chip chip;
-	struct fsl_lbc_ctrl *ctrl;
-
-	struct device *dev;
-	int bank;               /* Chip select bank number           */
-	u8 __iomem *vbase;      /* Chip select base virtual address  */
-	int page_size;          /* NAND page size (0=512, 1=2048)    */
-	unsigned int fmr;       /* FCM Flash Mode Register value     */
-};
-
-/* Freescale eLBC FCM controller information */
-
-struct fsl_elbc_fcm_ctrl {
-	struct nand_hw_control controller;
-	struct fsl_elbc_mtd *chips[MAX_BANKS];
-
-	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
-	unsigned int page;       /* Last page written to / read from      */
-	unsigned int read_bytes; /* Number of bytes read during command   */
-	unsigned int column;     /* Saved column from SEQIN               */
-	unsigned int index;      /* Pointer to next byte to 'read'        */
-	unsigned int status;     /* status read from LTESR after last op  */
-	unsigned int mdr;        /* UPM/FCM Data Register value           */
-	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
-	unsigned int oob;        /* Non zero if operating on OOB data     */
-	unsigned int counter;	 /* counter for the initializations	  */
-	unsigned int max_bitflips;  /* Saved during READ0 cmd		  */
-};
-
-/* These map to the positions used by the FCM hardware ECC generator */
-
-static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (16 * section) + 6;
-	if (priv->fmr & FMR_ECCM)
-		oobregion->offset += 2;
-
-	oobregion->length = chip->ecc.bytes;
-
-	return 0;
-}
-
-static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
-				   struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-
-	if (section > chip->ecc.steps)
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->offset = 0;
-		if (mtd->writesize > 512)
-			oobregion->offset++;
-		oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
-	} else {
-		oobregion->offset = (16 * section) -
-				    ((priv->fmr & FMR_ECCM) ? 5 : 7);
-		if (section < chip->ecc.steps)
-			oobregion->length = 13;
-		else
-			oobregion->length = mtd->oobsize - oobregion->offset;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
-	.ecc = fsl_elbc_ooblayout_ecc,
-	.free = fsl_elbc_ooblayout_free,
-};
-
-/*
- * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
- * interfere with ECC positions, that's why we implement our own descriptors.
- * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
- */
-static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
-static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
-		   NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	11,
-	.len = 4,
-	.veroffs = 15,
-	.maxblocks = 4,
-	.pattern = bbt_pattern,
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
-		   NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	11,
-	.len = 4,
-	.veroffs = 15,
-	.maxblocks = 4,
-	.pattern = mirror_pattern,
-};
-
-/*=================================*/
-
-/*
- * Set up the FCM hardware block and page address fields, and the fcm
- * structure addr field to point to the correct FCM buffer in memory
- */
-static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
-	int buf_num;
-
-	elbc_fcm_ctrl->page = page_addr;
-
-	if (priv->page_size) {
-		/*
-		 * large page size chip : FPAR[PI] save the lowest 6 bits,
-		 *                        FBAR[BLK] save the other bits.
-		 */
-		out_be32(&lbc->fbar, page_addr >> 6);
-		out_be32(&lbc->fpar,
-		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
-		         (oob ? FPAR_LP_MS : 0) | column);
-		buf_num = (page_addr & 1) << 2;
-	} else {
-		/*
-		 * small page size chip : FPAR[PI] save the lowest 5 bits,
-		 *                        FBAR[BLK] save the other bits.
-		 */
-		out_be32(&lbc->fbar, page_addr >> 5);
-		out_be32(&lbc->fpar,
-		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
-		         (oob ? FPAR_SP_MS : 0) | column);
-		buf_num = page_addr & 7;
-	}
-
-	elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
-	elbc_fcm_ctrl->index = column;
-
-	/* for OOB data point to the second half of the buffer */
-	if (oob)
-		elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
-
-	dev_vdbg(priv->dev, "set_addr: bank=%d, "
-			    "elbc_fcm_ctrl->addr=0x%p (0x%p), "
-	                    "index %x, pes %d ps %d\n",
-		 buf_num, elbc_fcm_ctrl->addr, priv->vbase,
-		 elbc_fcm_ctrl->index,
-	         chip->phys_erase_shift, chip->page_shift);
-}
-
-/*
- * execute FCM command and wait for it to complete
- */
-static int fsl_elbc_run_command(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-
-	/* Setup the FMR[OP] to execute without write protection */
-	out_be32(&lbc->fmr, priv->fmr | 3);
-	if (elbc_fcm_ctrl->use_mdr)
-		out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
-
-	dev_vdbg(priv->dev,
-	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
-	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
-	dev_vdbg(priv->dev,
-	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
-	         "fbcr=%08x bank=%d\n",
-	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
-	         in_be32(&lbc->fbcr), priv->bank);
-
-	ctrl->irq_status = 0;
-	/* execute special operation */
-	out_be32(&lbc->lsor, priv->bank);
-
-	/* wait for FCM complete flag or timeout */
-	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
-	                   FCM_TIMEOUT_MSECS * HZ/1000);
-	elbc_fcm_ctrl->status = ctrl->irq_status;
-	/* store mdr value in case it was needed */
-	if (elbc_fcm_ctrl->use_mdr)
-		elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
-
-	elbc_fcm_ctrl->use_mdr = 0;
-
-	if (elbc_fcm_ctrl->status != LTESR_CC) {
-		dev_info(priv->dev,
-		         "command failed: fir %x fcr %x status %x mdr %x\n",
-		         in_be32(&lbc->fir), in_be32(&lbc->fcr),
-			 elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
-		return -EIO;
-	}
-
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return 0;
-
-	elbc_fcm_ctrl->max_bitflips = 0;
-
-	if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
-		uint32_t lteccr = in_be32(&lbc->lteccr);
-		/*
-		 * if command was a full page read and the ELBC
-		 * has the LTECCR register, then bits 12-15 (ppc order) of
-		 * LTECCR indicates which 512 byte sub-pages had fixed errors.
-		 * bits 28-31 are uncorrectable errors, marked elsewhere.
-		 * for small page nand only 1 bit is used.
-		 * if the ELBC doesn't have the lteccr register it reads 0
-		 * FIXME: 4 bits can be corrected on NANDs with 2k pages, so
-		 * count the number of sub-pages with bitflips and update
-		 * ecc_stats.corrected accordingly.
-		 */
-		if (lteccr & 0x000F000F)
-			out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
-		if (lteccr & 0x000F0000) {
-			mtd->ecc_stats.corrected++;
-			elbc_fcm_ctrl->max_bitflips = 1;
-		}
-	}
-
-	return 0;
-}
-
-static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
-{
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-
-	if (priv->page_size) {
-		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
-		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
-		         (FIR_OP_CM1 << FIR_OP3_SHIFT) |
-		         (FIR_OP_RBW << FIR_OP4_SHIFT));
-
-		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
-		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
-	} else {
-		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
-		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
-		         (FIR_OP_RBW << FIR_OP3_SHIFT));
-
-		if (oob)
-			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
-		else
-			out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
-	}
-}
-
-/* cmdfunc send commands to the FCM */
-static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
-                             int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-
-	elbc_fcm_ctrl->use_mdr = 0;
-
-	/* clear the read buffer */
-	elbc_fcm_ctrl->read_bytes = 0;
-	if (command != NAND_CMD_PAGEPROG)
-		elbc_fcm_ctrl->index = 0;
-
-	switch (command) {
-	/* READ0 and READ1 read the entire buffer to use hardware ECC. */
-	case NAND_CMD_READ1:
-		column += 256;
-
-	/* fall-through */
-	case NAND_CMD_READ0:
-		dev_dbg(priv->dev,
-		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
-		        " 0x%x, column: 0x%x.\n", page_addr, column);
-
-
-		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
-		set_addr(mtd, 0, page_addr, 0);
-
-		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
-		elbc_fcm_ctrl->index += column;
-
-		fsl_elbc_do_read(chip, 0);
-		fsl_elbc_run_command(mtd);
-		return;
-
-	/* READOOB reads only the OOB because no ECC is performed. */
-	case NAND_CMD_READOOB:
-		dev_vdbg(priv->dev,
-		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
-			 " 0x%x, column: 0x%x.\n", page_addr, column);
-
-		out_be32(&lbc->fbcr, mtd->oobsize - column);
-		set_addr(mtd, column, page_addr, 1);
-
-		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
-
-		fsl_elbc_do_read(chip, 1);
-		fsl_elbc_run_command(mtd);
-		return;
-
-	case NAND_CMD_READID:
-	case NAND_CMD_PARAM:
-		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD %x\n", command);
-
-		out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
-		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
-		out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);
-		/*
-		 * although currently it's 8 bytes for READID, we always read
-		 * the maximum 256 bytes(for PARAM)
-		 */
-		out_be32(&lbc->fbcr, 256);
-		elbc_fcm_ctrl->read_bytes = 256;
-		elbc_fcm_ctrl->use_mdr = 1;
-		elbc_fcm_ctrl->mdr = column;
-		set_addr(mtd, 0, 0, 0);
-		fsl_elbc_run_command(mtd);
-		return;
-
-	/* ERASE1 stores the block and page address */
-	case NAND_CMD_ERASE1:
-		dev_vdbg(priv->dev,
-		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
-		         "page_addr: 0x%x.\n", page_addr);
-		set_addr(mtd, 0, page_addr, 0);
-		return;
-
-	/* ERASE2 uses the block and page address from ERASE1 */
-	case NAND_CMD_ERASE2:
-		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
-
-		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
-		         (FIR_OP_CM2 << FIR_OP2_SHIFT) |
-		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
-		         (FIR_OP_RS  << FIR_OP4_SHIFT));
-
-		out_be32(&lbc->fcr,
-		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
-		         (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
-		         (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
-
-		out_be32(&lbc->fbcr, 0);
-		elbc_fcm_ctrl->read_bytes = 0;
-		elbc_fcm_ctrl->use_mdr = 1;
-
-		fsl_elbc_run_command(mtd);
-		return;
-
-	/* SEQIN sets up the addr buffer and all registers except the length */
-	case NAND_CMD_SEQIN: {
-		__be32 fcr;
-		dev_vdbg(priv->dev,
-			 "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
-		         "page_addr: 0x%x, column: 0x%x.\n",
-		         page_addr, column);
-
-		elbc_fcm_ctrl->column = column;
-		elbc_fcm_ctrl->use_mdr = 1;
-
-		if (column >= mtd->writesize) {
-			/* OOB area */
-			column -= mtd->writesize;
-			elbc_fcm_ctrl->oob = 1;
-		} else {
-			WARN_ON(column != 0);
-			elbc_fcm_ctrl->oob = 0;
-		}
-
-		fcr = (NAND_CMD_STATUS   << FCR_CMD1_SHIFT) |
-		      (NAND_CMD_SEQIN    << FCR_CMD2_SHIFT) |
-		      (NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
-
-		if (priv->page_size) {
-			out_be32(&lbc->fir,
-			         (FIR_OP_CM2 << FIR_OP0_SHIFT) |
-			         (FIR_OP_CA  << FIR_OP1_SHIFT) |
-			         (FIR_OP_PA  << FIR_OP2_SHIFT) |
-			         (FIR_OP_WB  << FIR_OP3_SHIFT) |
-			         (FIR_OP_CM3 << FIR_OP4_SHIFT) |
-			         (FIR_OP_CW1 << FIR_OP5_SHIFT) |
-			         (FIR_OP_RS  << FIR_OP6_SHIFT));
-		} else {
-			out_be32(&lbc->fir,
-			         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
-			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
-			         (FIR_OP_PA  << FIR_OP3_SHIFT) |
-			         (FIR_OP_WB  << FIR_OP4_SHIFT) |
-			         (FIR_OP_CM3 << FIR_OP5_SHIFT) |
-			         (FIR_OP_CW1 << FIR_OP6_SHIFT) |
-			         (FIR_OP_RS  << FIR_OP7_SHIFT));
-
-			if (elbc_fcm_ctrl->oob)
-				/* OOB area --> READOOB */
-				fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
-			else
-				/* First 256 bytes --> READ0 */
-				fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
-		}
-
-		out_be32(&lbc->fcr, fcr);
-		set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
-		return;
-	}
-
-	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
-	case NAND_CMD_PAGEPROG: {
-		dev_vdbg(priv->dev,
-		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
-			 "writing %d bytes.\n", elbc_fcm_ctrl->index);
-
-		/* if the write did not start at 0 or is not a full page
-		 * then set the exact length, otherwise use a full page
-		 * write so the HW generates the ECC.
-		 */
-		if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
-		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
-			out_be32(&lbc->fbcr,
-				elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
-		else
-			out_be32(&lbc->fbcr, 0);
-
-		fsl_elbc_run_command(mtd);
-		return;
-	}
-
-	/* CMD_STATUS must read the status byte while CEB is active */
-	/* Note - it does not wait for the ready line */
-	case NAND_CMD_STATUS:
-		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_RBW << FIR_OP1_SHIFT));
-		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
-		out_be32(&lbc->fbcr, 1);
-		set_addr(mtd, 0, 0, 0);
-		elbc_fcm_ctrl->read_bytes = 1;
-
-		fsl_elbc_run_command(mtd);
-
-		/* The chip always seems to report that it is
-		 * write-protected, even when it is not.
-		 */
-		setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
-		return;
-
-	/* RESET without waiting for the ready line */
-	case NAND_CMD_RESET:
-		dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
-		out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
-		out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
-		fsl_elbc_run_command(mtd);
-		return;
-
-	default:
-		dev_err(priv->dev,
-		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
-		        command);
-	}
-}
-
-static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
-{
-	/* The hardware does not seem to support multiple
-	 * chips per bank.
-	 */
-}
-
-/*
- * Write buf to the FCM Controller Data Buffer
- */
-static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
-	unsigned int bufsize = mtd->writesize + mtd->oobsize;
-
-	if (len <= 0) {
-		dev_err(priv->dev, "write_buf of %d bytes", len);
-		elbc_fcm_ctrl->status = 0;
-		return;
-	}
-
-	if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
-		dev_err(priv->dev,
-		        "write_buf beyond end of buffer "
-		        "(%d requested, %u available)\n",
-			len, bufsize - elbc_fcm_ctrl->index);
-		len = bufsize - elbc_fcm_ctrl->index;
-	}
-
-	memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
-	/*
-	 * This is workaround for the weird elbc hangs during nand write,
-	 * Scott Wood says: "...perhaps difference in how long it takes a
-	 * write to make it through the localbus compared to a write to IMMR
-	 * is causing problems, and sync isn't helping for some reason."
-	 * Reading back the last byte helps though.
-	 */
-	in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
-
-	elbc_fcm_ctrl->index += len;
-}
-
-/*
- * read a byte from either the FCM hardware buffer if it has any data left
- * otherwise issue a command to read a single byte.
- */
-static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
-
-	/* If there are still bytes in the FCM, then use the next byte. */
-	if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
-		return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
-
-	dev_err(priv->dev, "read_byte beyond end of buffer\n");
-	return ERR_BYTE;
-}
-
-/*
- * Read from the FCM Controller Data Buffer
- */
-static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
-	int avail;
-
-	if (len < 0)
-		return;
-
-	avail = min((unsigned int)len,
-			elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
-	memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
-	elbc_fcm_ctrl->index += avail;
-
-	if (len > avail)
-		dev_err(priv->dev,
-		        "read_buf beyond end of buffer "
-		        "(%d requested, %d available)\n",
-		        len, avail);
-}
-
-/* This function is called after Program and Erase Operations to
- * check for success or failure.
- */
-static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
-
-	if (elbc_fcm_ctrl->status != LTESR_CC)
-		return NAND_STATUS_FAIL;
-
-	/* The chip always seems to report that it is
-	 * write-protected, even when it is not.
-	 */
-	return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
-}
-
-static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-	unsigned int al;
-
-	/* calculate FMR Address Length field */
-	al = 0;
-	if (chip->pagemask & 0xffff0000)
-		al++;
-	if (chip->pagemask & 0xff000000)
-		al++;
-
-	priv->fmr |= al << FMR_AL_SHIFT;
-
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
-	        chip->numchips);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
-	        chip->chipsize);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
-	        chip->pagemask);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
-	        chip->chip_delay);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
-	        chip->badblockpos);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
-	        chip->chip_shift);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
-	        chip->page_shift);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
-	        chip->phys_erase_shift);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
-	        chip->ecc.mode);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
-	        chip->ecc.steps);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
-	        chip->ecc.bytes);
-	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
-	        chip->ecc.total);
-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
-		mtd->ooblayout);
-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
-	        mtd->erasesize);
-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
-	        mtd->writesize);
-	dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
-	        mtd->oobsize);
-
-	/* adjust Option Register and ECC to match Flash page size */
-	if (mtd->writesize == 512) {
-		priv->page_size = 0;
-		clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
-	} else if (mtd->writesize == 2048) {
-		priv->page_size = 1;
-		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
-	} else {
-		dev_err(priv->dev,
-		        "fsl_elbc_init: page size %d is not supported\n",
-		        mtd->writesize);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			      uint8_t *buf, int oob_required, int page)
-{
-	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
-
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	if (oob_required)
-		fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
-		mtd->ecc_stats.failed++;
-
-	return elbc_fcm_ctrl->max_bitflips;
-}
-
-/* ECC will be calculated automatically, and errors will be detected in
- * waitfunc.
- */
-static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-				const uint8_t *buf, int oob_required, int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-/* ECC will be calculated automatically, and errors will be detected in
- * waitfunc.
- */
-static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-				uint32_t offset, uint32_t data_len,
-				const uint8_t *buf, int oob_required, int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
-	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-	return nand_prog_page_end_op(chip);
-}
-
-static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
-{
-	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
-	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
-	struct nand_chip *chip = &priv->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
-
-	/* Fill in fsl_elbc_mtd structure */
-	mtd->dev.parent = priv->dev;
-	nand_set_flash_node(chip, priv->dev->of_node);
-
-	/* set timeout to maximum */
-	priv->fmr = 15 << FMR_CWTO_SHIFT;
-	if (in_be32(&lbc->bank[priv->bank].or) & OR_FCM_PGS)
-		priv->fmr |= FMR_ECCM;
-
-	/* fill in nand_chip structure */
-	/* set up function call table */
-	chip->read_byte = fsl_elbc_read_byte;
-	chip->write_buf = fsl_elbc_write_buf;
-	chip->read_buf = fsl_elbc_read_buf;
-	chip->select_chip = fsl_elbc_select_chip;
-	chip->cmdfunc = fsl_elbc_cmdfunc;
-	chip->waitfunc = fsl_elbc_wait;
-	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
-	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
-
-	chip->bbt_td = &bbt_main_descr;
-	chip->bbt_md = &bbt_mirror_descr;
-
-	/* set up nand options */
-	chip->bbt_options = NAND_BBT_USE_FLASH;
-
-	chip->controller = &elbc_fcm_ctrl->controller;
-	nand_set_controller_data(chip, priv);
-
-	chip->ecc.read_page = fsl_elbc_read_page;
-	chip->ecc.write_page = fsl_elbc_write_page;
-	chip->ecc.write_subpage = fsl_elbc_write_subpage;
-
-	/* If CS Base Register selects full hardware ECC then use it */
-	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
-	    BR_DECC_CHK_GEN) {
-		chip->ecc.mode = NAND_ECC_HW;
-		mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
-		chip->ecc.size = 512;
-		chip->ecc.bytes = 3;
-		chip->ecc.strength = 1;
-	} else {
-		/* otherwise fall back to default software ECC */
-		chip->ecc.mode = NAND_ECC_SOFT;
-		chip->ecc.algo = NAND_ECC_HAMMING;
-	}
-
-	return 0;
-}
-
-static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
-{
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
-
-	nand_release(mtd);
-
-	kfree(mtd->name);
-
-	if (priv->vbase)
-		iounmap(priv->vbase);
-
-	elbc_fcm_ctrl->chips[priv->bank] = NULL;
-	kfree(priv);
-	return 0;
-}
-
-static DEFINE_MUTEX(fsl_elbc_nand_mutex);
-
-static int fsl_elbc_nand_probe(struct platform_device *pdev)
-{
-	struct fsl_lbc_regs __iomem *lbc;
-	struct fsl_elbc_mtd *priv;
-	struct resource res;
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
-	static const char *part_probe_types[]
-		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
-	int ret;
-	int bank;
-	struct device *dev;
-	struct device_node *node = pdev->dev.of_node;
-	struct mtd_info *mtd;
-
-	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
-		return -ENODEV;
-	lbc = fsl_lbc_ctrl_dev->regs;
-	dev = fsl_lbc_ctrl_dev->dev;
-
-	/* get, allocate and map the memory resource */
-	ret = of_address_to_resource(node, 0, &res);
-	if (ret) {
-		dev_err(dev, "failed to get resource\n");
-		return ret;
-	}
-
-	/* find which chip select it is connected to */
-	for (bank = 0; bank < MAX_BANKS; bank++)
-		if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
-		    (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
-		    (in_be32(&lbc->bank[bank].br) &
-		     in_be32(&lbc->bank[bank].or) & BR_BA)
-		     == fsl_lbc_addr(res.start))
-			break;
-
-	if (bank >= MAX_BANKS) {
-		dev_err(dev, "address did not match any chip selects\n");
-		return -ENODEV;
-	}
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	mutex_lock(&fsl_elbc_nand_mutex);
-	if (!fsl_lbc_ctrl_dev->nand) {
-		elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
-		if (!elbc_fcm_ctrl) {
-			mutex_unlock(&fsl_elbc_nand_mutex);
-			ret = -ENOMEM;
-			goto err;
-		}
-		elbc_fcm_ctrl->counter++;
-
-		nand_hw_control_init(&elbc_fcm_ctrl->controller);
-		fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
-	} else {
-		elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
-	}
-	mutex_unlock(&fsl_elbc_nand_mutex);
-
-	elbc_fcm_ctrl->chips[bank] = priv;
-	priv->bank = bank;
-	priv->ctrl = fsl_lbc_ctrl_dev;
-	priv->dev = &pdev->dev;
-	dev_set_drvdata(priv->dev, priv);
-
-	priv->vbase = ioremap(res.start, resource_size(&res));
-	if (!priv->vbase) {
-		dev_err(dev, "failed to map chip region\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	mtd = nand_to_mtd(&priv->chip);
-	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
-	if (!nand_to_mtd(&priv->chip)->name) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	ret = fsl_elbc_chip_init(priv);
-	if (ret)
-		goto err;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		goto err;
-
-	ret = fsl_elbc_chip_init_tail(mtd);
-	if (ret)
-		goto err;
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		goto err;
-
-	/* First look for RedBoot table or partitions on the command
-	 * line, these take precedence over device tree information */
-	mtd_device_parse_register(mtd, part_probe_types, NULL,
-				  NULL, 0);
-
-	printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
-	       (unsigned long long)res.start, priv->bank);
-	return 0;
-
-err:
-	fsl_elbc_chip_remove(priv);
-	return ret;
-}
-
-static int fsl_elbc_nand_remove(struct platform_device *pdev)
-{
-	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
-	struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
-
-	fsl_elbc_chip_remove(priv);
-
-	mutex_lock(&fsl_elbc_nand_mutex);
-	elbc_fcm_ctrl->counter--;
-	if (!elbc_fcm_ctrl->counter) {
-		fsl_lbc_ctrl_dev->nand = NULL;
-		kfree(elbc_fcm_ctrl);
-	}
-	mutex_unlock(&fsl_elbc_nand_mutex);
-
-	return 0;
-
-}
-
-static const struct of_device_id fsl_elbc_nand_match[] = {
-	{ .compatible = "fsl,elbc-fcm-nand", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
-
-static struct platform_driver fsl_elbc_nand_driver = {
-	.driver = {
-		.name = "fsl,elbc-fcm-nand",
-		.of_match_table = fsl_elbc_nand_match,
-	},
-	.probe = fsl_elbc_nand_probe,
-	.remove = fsl_elbc_nand_remove,
-};
-
-module_platform_driver(fsl_elbc_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Freescale");
-MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
deleted file mode 100644
index 4872a7ba6503..000000000000
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ /dev/null
@@ -1,1117 +0,0 @@
-/*
- * Freescale Integrated Flash Controller NAND driver
- *
- * Copyright 2011-2012 Freescale Semiconductor, Inc
- *
- * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/of_address.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/fsl_ifc.h>
-
-#define ERR_BYTE		0xFF /* Value returned for read
-					bytes when read failed	*/
-#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
-					for IFC NAND Machine	*/
-
-struct fsl_ifc_ctrl;
-
-/* mtd information per set */
-struct fsl_ifc_mtd {
-	struct nand_chip chip;
-	struct fsl_ifc_ctrl *ctrl;
-
-	struct device *dev;
-	int bank;		/* Chip select bank number		*/
-	unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
-	u8 __iomem *vbase;      /* Chip select base virtual address	*/
-};
-
-/* overview of the fsl ifc controller */
-struct fsl_ifc_nand_ctrl {
-	struct nand_hw_control controller;
-	struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
-
-	void __iomem *addr;	/* Address of assigned IFC buffer	*/
-	unsigned int page;	/* Last page written to / read from	*/
-	unsigned int read_bytes;/* Number of bytes read during command	*/
-	unsigned int column;	/* Saved column from SEQIN		*/
-	unsigned int index;	/* Pointer to next byte to 'read'	*/
-	unsigned int oob;	/* Non zero if operating on OOB data	*/
-	unsigned int eccread;	/* Non zero for a full-page ECC read	*/
-	unsigned int counter;	/* counter for the initializations	*/
-	unsigned int max_bitflips;  /* Saved during READ0 cmd		*/
-};
-
-static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
-
-/*
- * Generic flash bbt descriptors
- */
-static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
-static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
-		   NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	2, /* 0 on 8-bit small page */
-	.len = 4,
-	.veroffs = 6,
-	.maxblocks = 4,
-	.pattern = bbt_pattern,
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
-		   NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	2, /* 0 on 8-bit small page */
-	.len = 4,
-	.veroffs = 6,
-	.maxblocks = 4,
-	.pattern = mirror_pattern,
-};
-
-static int fsl_ifc_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 8;
-	oobregion->length = chip->ecc.total;
-
-	return 0;
-}
-
-static int fsl_ifc_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section > 1)
-		return -ERANGE;
-
-	if (mtd->writesize == 512 &&
-	    !(chip->options & NAND_BUSWIDTH_16)) {
-		if (!section) {
-			oobregion->offset = 0;
-			oobregion->length = 5;
-		} else {
-			oobregion->offset = 6;
-			oobregion->length = 2;
-		}
-
-		return 0;
-	}
-
-	if (!section) {
-		oobregion->offset = 2;
-		oobregion->length = 6;
-	} else {
-		oobregion->offset = chip->ecc.total + 8;
-		oobregion->length = mtd->oobsize - oobregion->offset;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
-	.ecc = fsl_ifc_ooblayout_ecc,
-	.free = fsl_ifc_ooblayout_free,
-};
-
-/*
- * Set up the IFC hardware block and page address fields, and the ifc nand
- * structure addr field to point to the correct IFC buffer in memory
- */
-static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
-	int buf_num;
-
-	ifc_nand_ctrl->page = page_addr;
-	/* Program ROW0/COL0 */
-	ifc_out32(page_addr, &ifc->ifc_nand.row0);
-	ifc_out32((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0);
-
-	buf_num = page_addr & priv->bufnum_mask;
-
-	ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
-	ifc_nand_ctrl->index = column;
-
-	/* for OOB data point to the second half of the buffer */
-	if (oob)
-		ifc_nand_ctrl->index += mtd->writesize;
-}
-
-/* returns nonzero if entire page is blank */
-static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
-			  u32 *eccstat, unsigned int bufnum)
-{
-	u32 reg = eccstat[bufnum / 4];
-	int errors;
-
-	errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
-
-	return errors;
-}
-
-/*
- * execute IFC NAND command and wait for it to complete
- */
-static void fsl_ifc_run_command(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
-	u32 eccstat[4];
-	int i;
-
-	/* set the chip select for NAND Transaction */
-	ifc_out32(priv->bank << IFC_NAND_CSEL_SHIFT,
-		  &ifc->ifc_nand.nand_csel);
-
-	dev_vdbg(priv->dev,
-			"%s: fir0=%08x fcr0=%08x\n",
-			__func__,
-			ifc_in32(&ifc->ifc_nand.nand_fir0),
-			ifc_in32(&ifc->ifc_nand.nand_fcr0));
-
-	ctrl->nand_stat = 0;
-
-	/* start read/write seq */
-	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
-
-	/* wait for command complete flag or timeout */
-	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
-			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
-
-	/* ctrl->nand_stat will be updated from IRQ context */
-	if (!ctrl->nand_stat)
-		dev_err(priv->dev, "Controller is not responding\n");
-	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
-		dev_err(priv->dev, "NAND Flash Timeout Error\n");
-	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
-		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
-
-	nctrl->max_bitflips = 0;
-
-	if (nctrl->eccread) {
-		int errors;
-		int bufnum = nctrl->page & priv->bufnum_mask;
-		int sector = bufnum * chip->ecc.steps;
-		int sector_end = sector + chip->ecc.steps - 1;
-		__be32 *eccstat_regs;
-
-		if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
-			eccstat_regs = ifc->ifc_nand.v2_nand_eccstat;
-		else
-			eccstat_regs = ifc->ifc_nand.v1_nand_eccstat;
-
-		for (i = sector / 4; i <= sector_end / 4; i++)
-			eccstat[i] = ifc_in32(&eccstat_regs[i]);
-
-		for (i = sector; i <= sector_end; i++) {
-			errors = check_read_ecc(mtd, ctrl, eccstat, i);
-
-			if (errors == 15) {
-				/*
-				 * Uncorrectable error.
-				 * We'll check for blank pages later.
-				 *
-				 * We disable ECCER reporting due to...
-				 * erratum IFC-A002770 -- so report it now if we
-				 * see an uncorrectable error in ECCSTAT.
-				 */
-				ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
-				continue;
-			}
-
-			mtd->ecc_stats.corrected += errors;
-			nctrl->max_bitflips = max_t(unsigned int,
-						    nctrl->max_bitflips,
-						    errors);
-		}
-
-		nctrl->eccread = 0;
-	}
-}
-
-static void fsl_ifc_do_read(struct nand_chip *chip,
-			    int oob,
-			    struct mtd_info *mtd)
-{
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
-
-	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
-	if (mtd->writesize > 512) {
-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
-			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
-			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT),
-			  &ifc->ifc_nand.nand_fir0);
-		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
-
-		ifc_out32((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
-			  (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT),
-			  &ifc->ifc_nand.nand_fcr0);
-	} else {
-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-			  (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
-			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT),
-			  &ifc->ifc_nand.nand_fir0);
-		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
-
-		if (oob)
-			ifc_out32(NAND_CMD_READOOB <<
-				  IFC_NAND_FCR0_CMD0_SHIFT,
-				  &ifc->ifc_nand.nand_fcr0);
-		else
-			ifc_out32(NAND_CMD_READ0 <<
-				  IFC_NAND_FCR0_CMD0_SHIFT,
-				  &ifc->ifc_nand.nand_fcr0);
-	}
-}
-
-/* cmdfunc send commands to the IFC NAND Machine */
-static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
-			     int column, int page_addr) {
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
-
-	/* clear the read buffer */
-	ifc_nand_ctrl->read_bytes = 0;
-	if (command != NAND_CMD_PAGEPROG)
-		ifc_nand_ctrl->index = 0;
-
-	switch (command) {
-	/* READ0 read the entire buffer to use hardware ECC. */
-	case NAND_CMD_READ0:
-		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
-		set_addr(mtd, 0, page_addr, 0);
-
-		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
-		ifc_nand_ctrl->index += column;
-
-		if (chip->ecc.mode == NAND_ECC_HW)
-			ifc_nand_ctrl->eccread = 1;
-
-		fsl_ifc_do_read(chip, 0, mtd);
-		fsl_ifc_run_command(mtd);
-		return;
-
-	/* READOOB reads only the OOB because no ECC is performed. */
-	case NAND_CMD_READOOB:
-		ifc_out32(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr);
-		set_addr(mtd, column, page_addr, 1);
-
-		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
-
-		fsl_ifc_do_read(chip, 1, mtd);
-		fsl_ifc_run_command(mtd);
-
-		return;
-
-	case NAND_CMD_READID:
-	case NAND_CMD_PARAM: {
-		int timing = IFC_FIR_OP_RB;
-		if (command == NAND_CMD_PARAM)
-			timing = IFC_FIR_OP_RBCD;
-
-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-			  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
-			  (timing << IFC_NAND_FIR0_OP2_SHIFT),
-			  &ifc->ifc_nand.nand_fir0);
-		ifc_out32(command << IFC_NAND_FCR0_CMD0_SHIFT,
-			  &ifc->ifc_nand.nand_fcr0);
-		ifc_out32(column, &ifc->ifc_nand.row3);
-
-		/*
-		 * although currently it's 8 bytes for READID, we always read
-		 * the maximum 256 bytes(for PARAM)
-		 */
-		ifc_out32(256, &ifc->ifc_nand.nand_fbcr);
-		ifc_nand_ctrl->read_bytes = 256;
-
-		set_addr(mtd, 0, 0, 0);
-		fsl_ifc_run_command(mtd);
-		return;
-	}
-
-	/* ERASE1 stores the block and page address */
-	case NAND_CMD_ERASE1:
-		set_addr(mtd, 0, page_addr, 0);
-		return;
-
-	/* ERASE2 uses the block and page address from ERASE1 */
-	case NAND_CMD_ERASE2:
-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT),
-			  &ifc->ifc_nand.nand_fir0);
-
-		ifc_out32((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
-			  (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT),
-			  &ifc->ifc_nand.nand_fcr0);
-
-		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
-		ifc_nand_ctrl->read_bytes = 0;
-		fsl_ifc_run_command(mtd);
-		return;
-
-	/* SEQIN sets up the addr buffer and all registers except the length */
-	case NAND_CMD_SEQIN: {
-		u32 nand_fcr0;
-		ifc_nand_ctrl->column = column;
-		ifc_nand_ctrl->oob = 0;
-
-		if (mtd->writesize > 512) {
-			nand_fcr0 =
-				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
-				(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
-				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
-
-			ifc_out32(
-				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
-				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
-				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT),
-				&ifc->ifc_nand.nand_fir0);
-			ifc_out32(
-				(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
-				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP6_SHIFT) |
-				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT),
-				&ifc->ifc_nand.nand_fir1);
-		} else {
-			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
-					IFC_NAND_FCR0_CMD1_SHIFT) |
-				    (NAND_CMD_SEQIN <<
-					IFC_NAND_FCR0_CMD2_SHIFT) |
-				    (NAND_CMD_STATUS <<
-					IFC_NAND_FCR0_CMD3_SHIFT));
-
-			ifc_out32(
-				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
-				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
-				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
-				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT),
-				&ifc->ifc_nand.nand_fir0);
-			ifc_out32(
-				(IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
-				(IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
-				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP7_SHIFT) |
-				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT),
-				&ifc->ifc_nand.nand_fir1);
-
-			if (column >= mtd->writesize)
-				nand_fcr0 |=
-				NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
-			else
-				nand_fcr0 |=
-				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
-		}
-
-		if (column >= mtd->writesize) {
-			/* OOB area --> READOOB */
-			column -= mtd->writesize;
-			ifc_nand_ctrl->oob = 1;
-		}
-		ifc_out32(nand_fcr0, &ifc->ifc_nand.nand_fcr0);
-		set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
-		return;
-	}
-
-	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
-	case NAND_CMD_PAGEPROG: {
-		if (ifc_nand_ctrl->oob) {
-			ifc_out32(ifc_nand_ctrl->index -
-				  ifc_nand_ctrl->column,
-				  &ifc->ifc_nand.nand_fbcr);
-		} else {
-			ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
-		}
-
-		fsl_ifc_run_command(mtd);
-		return;
-	}
-
-	case NAND_CMD_STATUS: {
-		void __iomem *addr;
-
-		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-			  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT),
-			  &ifc->ifc_nand.nand_fir0);
-		ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
-			  &ifc->ifc_nand.nand_fcr0);
-		ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
-		set_addr(mtd, 0, 0, 0);
-		ifc_nand_ctrl->read_bytes = 1;
-
-		fsl_ifc_run_command(mtd);
-
-		/*
-		 * The chip always seems to report that it is
-		 * write-protected, even when it is not.
-		 */
-		addr = ifc_nand_ctrl->addr;
-		if (chip->options & NAND_BUSWIDTH_16)
-			ifc_out16(ifc_in16(addr) | (NAND_STATUS_WP), addr);
-		else
-			ifc_out8(ifc_in8(addr) | (NAND_STATUS_WP), addr);
-		return;
-	}
-
-	case NAND_CMD_RESET:
-		ifc_out32(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT,
-			  &ifc->ifc_nand.nand_fir0);
-		ifc_out32(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT,
-			  &ifc->ifc_nand.nand_fcr0);
-		fsl_ifc_run_command(mtd);
-		return;
-
-	default:
-		dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
-					__func__, command);
-	}
-}
-
-static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
-{
-	/* The hardware does not seem to support multiple
-	 * chips per bank.
-	 */
-}
-
-/*
- * Write buf to the IFC NAND Controller Data Buffer
- */
-static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	unsigned int bufsize = mtd->writesize + mtd->oobsize;
-
-	if (len <= 0) {
-		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
-		return;
-	}
-
-	if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
-		dev_err(priv->dev,
-			"%s: beyond end of buffer (%d requested, %u available)\n",
-			__func__, len, bufsize - ifc_nand_ctrl->index);
-		len = bufsize - ifc_nand_ctrl->index;
-	}
-
-	memcpy_toio(ifc_nand_ctrl->addr + ifc_nand_ctrl->index, buf, len);
-	ifc_nand_ctrl->index += len;
-}
-
-/*
- * Read a byte from either the IFC hardware buffer
- * read function for 8-bit buswidth
- */
-static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	unsigned int offset;
-
-	/*
-	 * If there are still bytes in the IFC buffer, then use the
-	 * next byte.
-	 */
-	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
-		offset = ifc_nand_ctrl->index++;
-		return ifc_in8(ifc_nand_ctrl->addr + offset);
-	}
-
-	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
-	return ERR_BYTE;
-}
-
-/*
- * Read two bytes from the IFC hardware buffer
- * read function for 16-bit buswith
- */
-static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	uint16_t data;
-
-	/*
-	 * If there are still bytes in the IFC buffer, then use the
-	 * next byte.
-	 */
-	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
-		data = ifc_in16(ifc_nand_ctrl->addr + ifc_nand_ctrl->index);
-		ifc_nand_ctrl->index += 2;
-		return (uint8_t) data;
-	}
-
-	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
-	return ERR_BYTE;
-}
-
-/*
- * Read from the IFC Controller Data Buffer
- */
-static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	int avail;
-
-	if (len < 0) {
-		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
-		return;
-	}
-
-	avail = min((unsigned int)len,
-			ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
-	memcpy_fromio(buf, ifc_nand_ctrl->addr + ifc_nand_ctrl->index, avail);
-	ifc_nand_ctrl->index += avail;
-
-	if (len > avail)
-		dev_err(priv->dev,
-			"%s: beyond end of buffer (%d requested, %d available)\n",
-			__func__, len, avail);
-}
-
-/*
- * This function is called after Program and Erase Operations to
- * check for success or failure.
- */
-static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
-	u32 nand_fsr;
-
-	/* Use READ_STATUS command, but wait for the device to be ready */
-	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-		  (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT),
-		  &ifc->ifc_nand.nand_fir0);
-	ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
-		  &ifc->ifc_nand.nand_fcr0);
-	ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
-	set_addr(mtd, 0, 0, 0);
-	ifc_nand_ctrl->read_bytes = 1;
-
-	fsl_ifc_run_command(mtd);
-
-	nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
-
-	/*
-	 * The chip always seems to report that it is
-	 * write-protected, even when it is not.
-	 */
-	return nand_fsr | NAND_STATUS_WP;
-}
-
-/*
- * The controller does not check for bitflips in erased pages,
- * therefore software must check instead.
- */
-static int check_erased_page(struct nand_chip *chip, u8 *buf)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 *ecc = chip->oob_poi;
-	const int ecc_size = chip->ecc.bytes;
-	const int pkt_size = chip->ecc.size;
-	int i, res, bitflips = 0;
-	struct mtd_oob_region oobregion = { };
-
-	mtd_ooblayout_ecc(mtd, 0, &oobregion);
-	ecc += oobregion.offset;
-
-	for (i = 0; i < chip->ecc.steps; ++i) {
-		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
-						  NULL, 0,
-						  chip->ecc.strength);
-		if (res < 0)
-			mtd->ecc_stats.failed++;
-		else
-			mtd->ecc_stats.corrected += res;
-
-		bitflips = max(res, bitflips);
-		buf += pkt_size;
-		ecc += ecc_size;
-	}
-
-	return bitflips;
-}
-
-static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			     uint8_t *buf, int oob_required, int page)
-{
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
-
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	if (oob_required)
-		fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
-		if (!oob_required)
-			fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-		return check_erased_page(chip, buf);
-	}
-
-	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
-		mtd->ecc_stats.failed++;
-
-	return nctrl->max_bitflips;
-}
-
-/* ECC will be calculated automatically, and errors will be detected in
- * waitfunc.
- */
-static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-			       const uint8_t *buf, int oob_required, int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
-
-	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
-							chip->numchips);
-	dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
-							chip->chipsize);
-	dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
-							chip->pagemask);
-	dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
-							chip->chip_delay);
-	dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
-							chip->badblockpos);
-	dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
-							chip->chip_shift);
-	dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
-							chip->page_shift);
-	dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
-							chip->phys_erase_shift);
-	dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
-							chip->ecc.mode);
-	dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
-							chip->ecc.steps);
-	dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
-							chip->ecc.bytes);
-	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
-							chip->ecc.total);
-	dev_dbg(priv->dev, "%s: mtd->ooblayout = %p\n", __func__,
-							mtd->ooblayout);
-	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
-	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
-	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
-							mtd->erasesize);
-	dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
-							mtd->writesize);
-	dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
-							mtd->oobsize);
-
-	return 0;
-}
-
-static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
-{
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
-	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
-	uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
-	uint32_t cs = priv->bank;
-
-	/* Save CSOR and CSOR_ext */
-	csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
-	csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
-
-	/* chage PageSize 8K and SpareSize 1K*/
-	csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
-	ifc_out32(csor_8k, &ifc_global->csor_cs[cs].csor);
-	ifc_out32(0x0000400, &ifc_global->csor_cs[cs].csor_ext);
-
-	/* READID */
-	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-		    (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
-		    (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
-		    &ifc_runtime->ifc_nand.nand_fir0);
-	ifc_out32(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT,
-		    &ifc_runtime->ifc_nand.nand_fcr0);
-	ifc_out32(0x0, &ifc_runtime->ifc_nand.row3);
-
-	ifc_out32(0x0, &ifc_runtime->ifc_nand.nand_fbcr);
-
-	/* Program ROW0/COL0 */
-	ifc_out32(0x0, &ifc_runtime->ifc_nand.row0);
-	ifc_out32(0x0, &ifc_runtime->ifc_nand.col0);
-
-	/* set the chip select for NAND Transaction */
-	ifc_out32(cs << IFC_NAND_CSEL_SHIFT,
-		&ifc_runtime->ifc_nand.nand_csel);
-
-	/* start read seq */
-	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT,
-		&ifc_runtime->ifc_nand.nandseq_strt);
-
-	/* wait for command complete flag or timeout */
-	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
-			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
-
-	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
-		printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
-
-	/* Restore CSOR and CSOR_ext */
-	ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
-	ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
-}
-
-static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
-{
-	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
-	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
-	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
-	struct nand_chip *chip = &priv->chip;
-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
-	u32 csor;
-
-	/* Fill in fsl_ifc_mtd structure */
-	mtd->dev.parent = priv->dev;
-	nand_set_flash_node(chip, priv->dev->of_node);
-
-	/* fill in nand_chip structure */
-	/* set up function call table */
-	if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
-		& CSPR_PORT_SIZE_16)
-		chip->read_byte = fsl_ifc_read_byte16;
-	else
-		chip->read_byte = fsl_ifc_read_byte;
-
-	chip->write_buf = fsl_ifc_write_buf;
-	chip->read_buf = fsl_ifc_read_buf;
-	chip->select_chip = fsl_ifc_select_chip;
-	chip->cmdfunc = fsl_ifc_cmdfunc;
-	chip->waitfunc = fsl_ifc_wait;
-	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
-	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
-
-	chip->bbt_td = &bbt_main_descr;
-	chip->bbt_md = &bbt_mirror_descr;
-
-	ifc_out32(0x0, &ifc_runtime->ifc_nand.ncfgr);
-
-	/* set up nand options */
-	chip->bbt_options = NAND_BBT_USE_FLASH;
-	chip->options = NAND_NO_SUBPAGE_WRITE;
-
-	if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
-		& CSPR_PORT_SIZE_16) {
-		chip->read_byte = fsl_ifc_read_byte16;
-		chip->options |= NAND_BUSWIDTH_16;
-	} else {
-		chip->read_byte = fsl_ifc_read_byte;
-	}
-
-	chip->controller = &ifc_nand_ctrl->controller;
-	nand_set_controller_data(chip, priv);
-
-	chip->ecc.read_page = fsl_ifc_read_page;
-	chip->ecc.write_page = fsl_ifc_write_page;
-
-	csor = ifc_in32(&ifc_global->csor_cs[priv->bank].csor);
-
-	switch (csor & CSOR_NAND_PGS_MASK) {
-	case CSOR_NAND_PGS_512:
-		if (!(chip->options & NAND_BUSWIDTH_16)) {
-			/* Avoid conflict with bad block marker */
-			bbt_main_descr.offs = 0;
-			bbt_mirror_descr.offs = 0;
-		}
-
-		priv->bufnum_mask = 15;
-		break;
-
-	case CSOR_NAND_PGS_2K:
-		priv->bufnum_mask = 3;
-		break;
-
-	case CSOR_NAND_PGS_4K:
-		priv->bufnum_mask = 1;
-		break;
-
-	case CSOR_NAND_PGS_8K:
-		priv->bufnum_mask = 0;
-		break;
-
-	default:
-		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
-		return -ENODEV;
-	}
-
-	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
-	if (csor & CSOR_NAND_ECC_DEC_EN) {
-		chip->ecc.mode = NAND_ECC_HW;
-		mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
-
-		/* Hardware generates ECC per 512 Bytes */
-		chip->ecc.size = 512;
-		if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) {
-			chip->ecc.bytes = 8;
-			chip->ecc.strength = 4;
-		} else {
-			chip->ecc.bytes = 16;
-			chip->ecc.strength = 8;
-		}
-	} else {
-		chip->ecc.mode = NAND_ECC_SOFT;
-		chip->ecc.algo = NAND_ECC_HAMMING;
-	}
-
-	if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
-		fsl_ifc_sram_init(priv);
-
-	/*
-	 * As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
-	 * versions which had 8KB. Hence bufnum mask needs to be updated.
-	 */
-	if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
-		priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
-
-	return 0;
-}
-
-static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
-{
-	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
-
-	nand_release(mtd);
-
-	kfree(mtd->name);
-
-	if (priv->vbase)
-		iounmap(priv->vbase);
-
-	ifc_nand_ctrl->chips[priv->bank] = NULL;
-
-	return 0;
-}
-
-static int match_bank(struct fsl_ifc_global __iomem *ifc_global, int bank,
-		      phys_addr_t addr)
-{
-	u32 cspr = ifc_in32(&ifc_global->cspr_cs[bank].cspr);
-
-	if (!(cspr & CSPR_V))
-		return 0;
-	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
-		return 0;
-
-	return (cspr & CSPR_BA) == convert_ifc_address(addr);
-}
-
-static DEFINE_MUTEX(fsl_ifc_nand_mutex);
-
-static int fsl_ifc_nand_probe(struct platform_device *dev)
-{
-	struct fsl_ifc_runtime __iomem *ifc;
-	struct fsl_ifc_mtd *priv;
-	struct resource res;
-	static const char *part_probe_types[]
-		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
-	int ret;
-	int bank;
-	struct device_node *node = dev->dev.of_node;
-	struct mtd_info *mtd;
-
-	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->rregs)
-		return -ENODEV;
-	ifc = fsl_ifc_ctrl_dev->rregs;
-
-	/* get, allocate and map the memory resource */
-	ret = of_address_to_resource(node, 0, &res);
-	if (ret) {
-		dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
-		return ret;
-	}
-
-	/* find which chip select it is connected to */
-	for (bank = 0; bank < fsl_ifc_ctrl_dev->banks; bank++) {
-		if (match_bank(fsl_ifc_ctrl_dev->gregs, bank, res.start))
-			break;
-	}
-
-	if (bank >= fsl_ifc_ctrl_dev->banks) {
-		dev_err(&dev->dev, "%s: address did not match any chip selects\n",
-			__func__);
-		return -ENODEV;
-	}
-
-	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	mutex_lock(&fsl_ifc_nand_mutex);
-	if (!fsl_ifc_ctrl_dev->nand) {
-		ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
-		if (!ifc_nand_ctrl) {
-			mutex_unlock(&fsl_ifc_nand_mutex);
-			return -ENOMEM;
-		}
-
-		ifc_nand_ctrl->read_bytes = 0;
-		ifc_nand_ctrl->index = 0;
-		ifc_nand_ctrl->addr = NULL;
-		fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
-
-		nand_hw_control_init(&ifc_nand_ctrl->controller);
-	} else {
-		ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
-	}
-	mutex_unlock(&fsl_ifc_nand_mutex);
-
-	ifc_nand_ctrl->chips[bank] = priv;
-	priv->bank = bank;
-	priv->ctrl = fsl_ifc_ctrl_dev;
-	priv->dev = &dev->dev;
-
-	priv->vbase = ioremap(res.start, resource_size(&res));
-	if (!priv->vbase) {
-		dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	dev_set_drvdata(priv->dev, priv);
-
-	ifc_out32(IFC_NAND_EVTER_EN_OPC_EN |
-		  IFC_NAND_EVTER_EN_FTOER_EN |
-		  IFC_NAND_EVTER_EN_WPER_EN,
-		  &ifc->ifc_nand.nand_evter_en);
-
-	/* enable NAND Machine Interrupts */
-	ifc_out32(IFC_NAND_EVTER_INTR_OPCIR_EN |
-		  IFC_NAND_EVTER_INTR_FTOERIR_EN |
-		  IFC_NAND_EVTER_INTR_WPERIR_EN,
-		  &ifc->ifc_nand.nand_evter_intr_en);
-
-	mtd = nand_to_mtd(&priv->chip);
-	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
-	if (!mtd->name) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	ret = fsl_ifc_chip_init(priv);
-	if (ret)
-		goto err;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		goto err;
-
-	ret = fsl_ifc_chip_init_tail(mtd);
-	if (ret)
-		goto err;
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		goto err;
-
-	/* First look for RedBoot table or partitions on the command
-	 * line, these take precedence over device tree information */
-	mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0);
-
-	dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
-		 (unsigned long long)res.start, priv->bank);
-	return 0;
-
-err:
-	fsl_ifc_chip_remove(priv);
-	return ret;
-}
-
-static int fsl_ifc_nand_remove(struct platform_device *dev)
-{
-	struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
-
-	fsl_ifc_chip_remove(priv);
-
-	mutex_lock(&fsl_ifc_nand_mutex);
-	ifc_nand_ctrl->counter--;
-	if (!ifc_nand_ctrl->counter) {
-		fsl_ifc_ctrl_dev->nand = NULL;
-		kfree(ifc_nand_ctrl);
-	}
-	mutex_unlock(&fsl_ifc_nand_mutex);
-
-	return 0;
-}
-
-static const struct of_device_id fsl_ifc_nand_match[] = {
-	{
-		.compatible = "fsl,ifc-nand",
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match);
-
-static struct platform_driver fsl_ifc_nand_driver = {
-	.driver = {
-		.name	= "fsl,ifc-nand",
-		.of_match_table = fsl_ifc_nand_match,
-	},
-	.probe       = fsl_ifc_nand_probe,
-	.remove      = fsl_ifc_nand_remove,
-};
-
-module_platform_driver(fsl_ifc_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Freescale");
-MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
deleted file mode 100644
index a88e2cf66e0f..000000000000
--- a/drivers/mtd/nand/fsl_upm.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Freescale UPM NAND driver.
- *
- * Copyright © 2007-2008  MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/mtd.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <asm/fsl_lbc.h>
-
-#define FSL_UPM_WAIT_RUN_PATTERN  0x1
-#define FSL_UPM_WAIT_WRITE_BYTE   0x2
-#define FSL_UPM_WAIT_WRITE_BUFFER 0x4
-
-struct fsl_upm_nand {
-	struct device *dev;
-	struct nand_chip chip;
-	int last_ctrl;
-	struct mtd_partition *parts;
-	struct fsl_upm upm;
-	uint8_t upm_addr_offset;
-	uint8_t upm_cmd_offset;
-	void __iomem *io_base;
-	int rnb_gpio[NAND_MAX_CHIPS];
-	uint32_t mchip_offsets[NAND_MAX_CHIPS];
-	uint32_t mchip_count;
-	uint32_t mchip_number;
-	int chip_delay;
-	uint32_t wait_flags;
-};
-
-static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
-{
-	return container_of(mtd_to_nand(mtdinfo), struct fsl_upm_nand,
-			    chip);
-}
-
-static int fun_chip_ready(struct mtd_info *mtd)
-{
-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
-
-	if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
-		return 1;
-
-	dev_vdbg(fun->dev, "busy\n");
-	return 0;
-}
-
-static void fun_wait_rnb(struct fsl_upm_nand *fun)
-{
-	if (fun->rnb_gpio[fun->mchip_number] >= 0) {
-		struct mtd_info *mtd = nand_to_mtd(&fun->chip);
-		int cnt = 1000000;
-
-		while (--cnt && !fun_chip_ready(mtd))
-			cpu_relax();
-		if (!cnt)
-			dev_err(fun->dev, "tired waiting for RNB\n");
-	} else {
-		ndelay(100);
-	}
-}
-
-static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
-	u32 mar;
-
-	if (!(ctrl & fun->last_ctrl)) {
-		fsl_upm_end_pattern(&fun->upm);
-
-		if (cmd == NAND_CMD_NONE)
-			return;
-
-		fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
-	}
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		if (ctrl & NAND_ALE)
-			fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
-		else if (ctrl & NAND_CLE)
-			fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
-	}
-
-	mar = (cmd << (32 - fun->upm.width)) |
-		fun->mchip_offsets[fun->mchip_number];
-	fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
-
-	if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
-		fun_wait_rnb(fun);
-}
-
-static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
-
-	if (mchip_nr == -1) {
-		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
-	} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
-		fun->mchip_number = mchip_nr;
-		chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
-		chip->IO_ADDR_W = chip->IO_ADDR_R;
-	} else {
-		BUG();
-	}
-}
-
-static uint8_t fun_read_byte(struct mtd_info *mtd)
-{
-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
-
-	return in_8(fun->chip.IO_ADDR_R);
-}
-
-static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
-	int i;
-
-	for (i = 0; i < len; i++)
-		buf[i] = in_8(fun->chip.IO_ADDR_R);
-}
-
-static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
-	int i;
-
-	for (i = 0; i < len; i++) {
-		out_8(fun->chip.IO_ADDR_W, buf[i]);
-		if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
-			fun_wait_rnb(fun);
-	}
-	if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER)
-		fun_wait_rnb(fun);
-}
-
-static int fun_chip_init(struct fsl_upm_nand *fun,
-			 const struct device_node *upm_np,
-			 const struct resource *io_res)
-{
-	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
-	int ret;
-	struct device_node *flash_np;
-
-	fun->chip.IO_ADDR_R = fun->io_base;
-	fun->chip.IO_ADDR_W = fun->io_base;
-	fun->chip.cmd_ctrl = fun_cmd_ctrl;
-	fun->chip.chip_delay = fun->chip_delay;
-	fun->chip.read_byte = fun_read_byte;
-	fun->chip.read_buf = fun_read_buf;
-	fun->chip.write_buf = fun_write_buf;
-	fun->chip.ecc.mode = NAND_ECC_SOFT;
-	fun->chip.ecc.algo = NAND_ECC_HAMMING;
-	if (fun->mchip_count > 1)
-		fun->chip.select_chip = fun_select_chip;
-
-	if (fun->rnb_gpio[0] >= 0)
-		fun->chip.dev_ready = fun_chip_ready;
-
-	mtd->dev.parent = fun->dev;
-
-	flash_np = of_get_next_child(upm_np, NULL);
-	if (!flash_np)
-		return -ENODEV;
-
-	nand_set_flash_node(&fun->chip, flash_np);
-	mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
-			      flash_np->name);
-	if (!mtd->name) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	ret = nand_scan(mtd, fun->mchip_count);
-	if (ret)
-		goto err;
-
-	ret = mtd_device_register(mtd, NULL, 0);
-err:
-	of_node_put(flash_np);
-	if (ret)
-		kfree(mtd->name);
-	return ret;
-}
-
-static int fun_probe(struct platform_device *ofdev)
-{
-	struct fsl_upm_nand *fun;
-	struct resource io_res;
-	const __be32 *prop;
-	int rnb_gpio;
-	int ret;
-	int size;
-	int i;
-
-	fun = kzalloc(sizeof(*fun), GFP_KERNEL);
-	if (!fun)
-		return -ENOMEM;
-
-	ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res);
-	if (ret) {
-		dev_err(&ofdev->dev, "can't get IO base\n");
-		goto err1;
-	}
-
-	ret = fsl_upm_find(io_res.start, &fun->upm);
-	if (ret) {
-		dev_err(&ofdev->dev, "can't find UPM\n");
-		goto err1;
-	}
-
-	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset",
-			       &size);
-	if (!prop || size != sizeof(uint32_t)) {
-		dev_err(&ofdev->dev, "can't get UPM address offset\n");
-		ret = -EINVAL;
-		goto err1;
-	}
-	fun->upm_addr_offset = *prop;
-
-	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size);
-	if (!prop || size != sizeof(uint32_t)) {
-		dev_err(&ofdev->dev, "can't get UPM command offset\n");
-		ret = -EINVAL;
-		goto err1;
-	}
-	fun->upm_cmd_offset = *prop;
-
-	prop = of_get_property(ofdev->dev.of_node,
-			       "fsl,upm-addr-line-cs-offsets", &size);
-	if (prop && (size / sizeof(uint32_t)) > 0) {
-		fun->mchip_count = size / sizeof(uint32_t);
-		if (fun->mchip_count >= NAND_MAX_CHIPS) {
-			dev_err(&ofdev->dev, "too much multiple chips\n");
-			goto err1;
-		}
-		for (i = 0; i < fun->mchip_count; i++)
-			fun->mchip_offsets[i] = be32_to_cpu(prop[i]);
-	} else {
-		fun->mchip_count = 1;
-	}
-
-	for (i = 0; i < fun->mchip_count; i++) {
-		fun->rnb_gpio[i] = -1;
-		rnb_gpio = of_get_gpio(ofdev->dev.of_node, i);
-		if (rnb_gpio >= 0) {
-			ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
-			if (ret) {
-				dev_err(&ofdev->dev,
-					"can't request RNB gpio #%d\n", i);
-				goto err2;
-			}
-			gpio_direction_input(rnb_gpio);
-			fun->rnb_gpio[i] = rnb_gpio;
-		} else if (rnb_gpio == -EINVAL) {
-			dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i);
-			goto err2;
-		}
-	}
-
-	prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
-	if (prop)
-		fun->chip_delay = be32_to_cpup(prop);
-	else
-		fun->chip_delay = 50;
-
-	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
-	if (prop && size == sizeof(uint32_t))
-		fun->wait_flags = be32_to_cpup(prop);
-	else
-		fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN |
-				  FSL_UPM_WAIT_WRITE_BYTE;
-
-	fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
-					    resource_size(&io_res));
-	if (!fun->io_base) {
-		ret = -ENOMEM;
-		goto err2;
-	}
-
-	fun->dev = &ofdev->dev;
-	fun->last_ctrl = NAND_CLE;
-
-	ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res);
-	if (ret)
-		goto err2;
-
-	dev_set_drvdata(&ofdev->dev, fun);
-
-	return 0;
-err2:
-	for (i = 0; i < fun->mchip_count; i++) {
-		if (fun->rnb_gpio[i] < 0)
-			break;
-		gpio_free(fun->rnb_gpio[i]);
-	}
-err1:
-	kfree(fun);
-
-	return ret;
-}
-
-static int fun_remove(struct platform_device *ofdev)
-{
-	struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
-	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
-	int i;
-
-	nand_release(mtd);
-	kfree(mtd->name);
-
-	for (i = 0; i < fun->mchip_count; i++) {
-		if (fun->rnb_gpio[i] < 0)
-			break;
-		gpio_free(fun->rnb_gpio[i]);
-	}
-
-	kfree(fun);
-
-	return 0;
-}
-
-static const struct of_device_id of_fun_match[] = {
-	{ .compatible = "fsl,upm-nand" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, of_fun_match);
-
-static struct platform_driver of_fun_driver = {
-	.driver = {
-		.name = "fsl,upm-nand",
-		.of_match_table = of_fun_match,
-	},
-	.probe		= fun_probe,
-	.remove		= fun_remove,
-};
-
-module_platform_driver(of_fun_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
-MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
-		   "LocalBus User-Programmable Machine");
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
deleted file mode 100644
index f49ed46fa770..000000000000
--- a/drivers/mtd/nand/fsmc_nand.c
+++ /dev/null
@@ -1,1175 +0,0 @@
-/*
- * drivers/mtd/nand/fsmc_nand.c
- *
- * ST Microelectronics
- * Flexible Static Memory Controller (FSMC)
- * Driver for NAND portions
- *
- * Copyright © 2010 ST Microelectronics
- * Vipin Kumar <vipin.kumar@st.com>
- * Ashish Priyadarshi
- *
- * Based on drivers/mtd/nand/nomadik_nand.c
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-direction.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/resource.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/amba/bus.h>
-#include <mtd/mtd-abi.h>
-
-/* fsmc controller registers for NOR flash */
-#define CTRL			0x0
-	/* ctrl register definitions */
-	#define BANK_ENABLE		(1 << 0)
-	#define MUXED			(1 << 1)
-	#define NOR_DEV			(2 << 2)
-	#define WIDTH_8			(0 << 4)
-	#define WIDTH_16		(1 << 4)
-	#define RSTPWRDWN		(1 << 6)
-	#define WPROT			(1 << 7)
-	#define WRT_ENABLE		(1 << 12)
-	#define WAIT_ENB		(1 << 13)
-
-#define CTRL_TIM		0x4
-	/* ctrl_tim register definitions */
-
-#define FSMC_NOR_BANK_SZ	0x8
-#define FSMC_NOR_REG_SIZE	0x40
-
-#define FSMC_NOR_REG(base, bank, reg)		(base + \
-						FSMC_NOR_BANK_SZ * (bank) + \
-						reg)
-
-/* fsmc controller registers for NAND flash */
-#define PC			0x00
-	/* pc register definitions */
-	#define FSMC_RESET		(1 << 0)
-	#define FSMC_WAITON		(1 << 1)
-	#define FSMC_ENABLE		(1 << 2)
-	#define FSMC_DEVTYPE_NAND	(1 << 3)
-	#define FSMC_DEVWID_8		(0 << 4)
-	#define FSMC_DEVWID_16		(1 << 4)
-	#define FSMC_ECCEN		(1 << 6)
-	#define FSMC_ECCPLEN_512	(0 << 7)
-	#define FSMC_ECCPLEN_256	(1 << 7)
-	#define FSMC_TCLR_1		(1)
-	#define FSMC_TCLR_SHIFT		(9)
-	#define FSMC_TCLR_MASK		(0xF)
-	#define FSMC_TAR_1		(1)
-	#define FSMC_TAR_SHIFT		(13)
-	#define FSMC_TAR_MASK		(0xF)
-#define STS			0x04
-	/* sts register definitions */
-	#define FSMC_CODE_RDY		(1 << 15)
-#define COMM			0x08
-	/* comm register definitions */
-	#define FSMC_TSET_0		0
-	#define FSMC_TSET_SHIFT		0
-	#define FSMC_TSET_MASK		0xFF
-	#define FSMC_TWAIT_6		6
-	#define FSMC_TWAIT_SHIFT	8
-	#define FSMC_TWAIT_MASK		0xFF
-	#define FSMC_THOLD_4		4
-	#define FSMC_THOLD_SHIFT	16
-	#define FSMC_THOLD_MASK		0xFF
-	#define FSMC_THIZ_1		1
-	#define FSMC_THIZ_SHIFT		24
-	#define FSMC_THIZ_MASK		0xFF
-#define ATTRIB			0x0C
-#define IOATA			0x10
-#define ECC1			0x14
-#define ECC2			0x18
-#define ECC3			0x1C
-#define FSMC_NAND_BANK_SZ	0x20
-
-#define FSMC_NAND_REG(base, bank, reg)		(base + FSMC_NOR_REG_SIZE + \
-						(FSMC_NAND_BANK_SZ * (bank)) + \
-						reg)
-
-#define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
-
-struct fsmc_nand_timings {
-	uint8_t tclr;
-	uint8_t tar;
-	uint8_t thiz;
-	uint8_t thold;
-	uint8_t twait;
-	uint8_t tset;
-};
-
-enum access_mode {
-	USE_DMA_ACCESS = 1,
-	USE_WORD_ACCESS,
-};
-
-/**
- * struct fsmc_nand_data - structure for FSMC NAND device state
- *
- * @pid:		Part ID on the AMBA PrimeCell format
- * @mtd:		MTD info for a NAND flash.
- * @nand:		Chip related info for a NAND flash.
- * @partitions:		Partition info for a NAND Flash.
- * @nr_partitions:	Total number of partition of a NAND flash.
- *
- * @bank:		Bank number for probed device.
- * @clk:		Clock structure for FSMC.
- *
- * @read_dma_chan:	DMA channel for read access
- * @write_dma_chan:	DMA channel for write access to NAND
- * @dma_access_complete: Completion structure
- *
- * @data_pa:		NAND Physical port for Data.
- * @data_va:		NAND port for Data.
- * @cmd_va:		NAND port for Command.
- * @addr_va:		NAND port for Address.
- * @regs_va:		FSMC regs base address.
- */
-struct fsmc_nand_data {
-	u32			pid;
-	struct nand_chip	nand;
-
-	unsigned int		bank;
-	struct device		*dev;
-	enum access_mode	mode;
-	struct clk		*clk;
-
-	/* DMA related objects */
-	struct dma_chan		*read_dma_chan;
-	struct dma_chan		*write_dma_chan;
-	struct completion	dma_access_complete;
-
-	struct fsmc_nand_timings *dev_timings;
-
-	dma_addr_t		data_pa;
-	void __iomem		*data_va;
-	void __iomem		*cmd_va;
-	void __iomem		*addr_va;
-	void __iomem		*regs_va;
-};
-
-static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
-				   struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 2;
-	oobregion->length = 3;
-
-	return 0;
-}
-
-static int fsmc_ecc1_ooblayout_free(struct mtd_info *mtd, int section,
-				    struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 8;
-
-	if (section < chip->ecc.steps - 1)
-		oobregion->length = 8;
-	else
-		oobregion->length = mtd->oobsize - oobregion->offset;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
-	.ecc = fsmc_ecc1_ooblayout_ecc,
-	.free = fsmc_ecc1_ooblayout_free,
-};
-
-/*
- * ECC placement definitions in oobfree type format.
- * There are 13 bytes of ecc for every 512 byte block and it has to be read
- * consecutively and immediately after the 512 byte data block for hardware to
- * generate the error bit offsets in 512 byte data.
- */
-static int fsmc_ecc4_ooblayout_ecc(struct mtd_info *mtd, int section,
-				   struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->length = chip->ecc.bytes;
-
-	if (!section && mtd->writesize <= 512)
-		oobregion->offset = 0;
-	else
-		oobregion->offset = (section * 16) + 2;
-
-	return 0;
-}
-
-static int fsmc_ecc4_ooblayout_free(struct mtd_info *mtd, int section,
-				    struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 15;
-
-	if (section < chip->ecc.steps - 1)
-		oobregion->length = 3;
-	else
-		oobregion->length = mtd->oobsize - oobregion->offset;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
-	.ecc = fsmc_ecc4_ooblayout_ecc,
-	.free = fsmc_ecc4_ooblayout_free,
-};
-
-static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
-}
-
-/*
- * fsmc_cmd_ctrl - For facilitaing Hardware access
- * This routine allows hardware specific access to control-lines(ALE,CLE)
- */
-static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-	void __iomem *regs = host->regs_va;
-	unsigned int bank = host->bank;
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		u32 pc;
-
-		if (ctrl & NAND_CLE) {
-			this->IO_ADDR_R = host->cmd_va;
-			this->IO_ADDR_W = host->cmd_va;
-		} else if (ctrl & NAND_ALE) {
-			this->IO_ADDR_R = host->addr_va;
-			this->IO_ADDR_W = host->addr_va;
-		} else {
-			this->IO_ADDR_R = host->data_va;
-			this->IO_ADDR_W = host->data_va;
-		}
-
-		pc = readl(FSMC_NAND_REG(regs, bank, PC));
-		if (ctrl & NAND_NCE)
-			pc |= FSMC_ENABLE;
-		else
-			pc &= ~FSMC_ENABLE;
-		writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
-	}
-
-	mb();
-
-	if (cmd != NAND_CMD_NONE)
-		writeb_relaxed(cmd, this->IO_ADDR_W);
-}
-
-/*
- * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine
- *
- * This routine initializes timing parameters related to NAND memory access in
- * FSMC registers
- */
-static void fsmc_nand_setup(struct fsmc_nand_data *host,
-			    struct fsmc_nand_timings *tims)
-{
-	uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
-	uint32_t tclr, tar, thiz, thold, twait, tset;
-	unsigned int bank = host->bank;
-	void __iomem *regs = host->regs_va;
-
-	tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
-	tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
-	thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT;
-	thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT;
-	twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
-	tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
-
-	if (host->nand.options & NAND_BUSWIDTH_16)
-		writel_relaxed(value | FSMC_DEVWID_16,
-				FSMC_NAND_REG(regs, bank, PC));
-	else
-		writel_relaxed(value | FSMC_DEVWID_8,
-				FSMC_NAND_REG(regs, bank, PC));
-
-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
-			FSMC_NAND_REG(regs, bank, PC));
-	writel_relaxed(thiz | thold | twait | tset,
-			FSMC_NAND_REG(regs, bank, COMM));
-	writel_relaxed(thiz | thold | twait | tset,
-			FSMC_NAND_REG(regs, bank, ATTRIB));
-}
-
-static int fsmc_calc_timings(struct fsmc_nand_data *host,
-			     const struct nand_sdr_timings *sdrt,
-			     struct fsmc_nand_timings *tims)
-{
-	unsigned long hclk = clk_get_rate(host->clk);
-	unsigned long hclkn = NSEC_PER_SEC / hclk;
-	uint32_t thiz, thold, twait, tset;
-
-	if (sdrt->tRC_min < 30000)
-		return -EOPNOTSUPP;
-
-	tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
-	if (tims->tar > FSMC_TAR_MASK)
-		tims->tar = FSMC_TAR_MASK;
-	tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
-	if (tims->tclr > FSMC_TCLR_MASK)
-		tims->tclr = FSMC_TCLR_MASK;
-
-	thiz = sdrt->tCS_min - sdrt->tWP_min;
-	tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
-
-	thold = sdrt->tDH_min;
-	if (thold < sdrt->tCH_min)
-		thold = sdrt->tCH_min;
-	if (thold < sdrt->tCLH_min)
-		thold = sdrt->tCLH_min;
-	if (thold < sdrt->tWH_min)
-		thold = sdrt->tWH_min;
-	if (thold < sdrt->tALH_min)
-		thold = sdrt->tALH_min;
-	if (thold < sdrt->tREH_min)
-		thold = sdrt->tREH_min;
-	tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
-	if (tims->thold == 0)
-		tims->thold = 1;
-	else if (tims->thold > FSMC_THOLD_MASK)
-		tims->thold = FSMC_THOLD_MASK;
-
-	twait = max(sdrt->tRP_min, sdrt->tWP_min);
-	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
-	if (tims->twait == 0)
-		tims->twait = 1;
-	else if (tims->twait > FSMC_TWAIT_MASK)
-		tims->twait = FSMC_TWAIT_MASK;
-
-	tset = max(sdrt->tCS_min - sdrt->tWP_min,
-		   sdrt->tCEA_max - sdrt->tREA_max);
-	tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
-	if (tims->tset == 0)
-		tims->tset = 1;
-	else if (tims->tset > FSMC_TSET_MASK)
-		tims->tset = FSMC_TSET_MASK;
-
-	return 0;
-}
-
-static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
-				     const struct nand_data_interface *conf)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct fsmc_nand_data *host = nand_get_controller_data(nand);
-	struct fsmc_nand_timings tims;
-	const struct nand_sdr_timings *sdrt;
-	int ret;
-
-	sdrt = nand_get_sdr_timings(conf);
-	if (IS_ERR(sdrt))
-		return PTR_ERR(sdrt);
-
-	ret = fsmc_calc_timings(host, sdrt, &tims);
-	if (ret)
-		return ret;
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	fsmc_nand_setup(host, &tims);
-
-	return 0;
-}
-
-/*
- * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
- */
-static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-	void __iomem *regs = host->regs_va;
-	uint32_t bank = host->bank;
-
-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
-			FSMC_NAND_REG(regs, bank, PC));
-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
-			FSMC_NAND_REG(regs, bank, PC));
-	writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
-			FSMC_NAND_REG(regs, bank, PC));
-}
-
-/*
- * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by
- * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
- * max of 8-bits)
- */
-static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
-				uint8_t *ecc)
-{
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-	void __iomem *regs = host->regs_va;
-	uint32_t bank = host->bank;
-	uint32_t ecc_tmp;
-	unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
-
-	do {
-		if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
-			break;
-		else
-			cond_resched();
-	} while (!time_after_eq(jiffies, deadline));
-
-	if (time_after_eq(jiffies, deadline)) {
-		dev_err(host->dev, "calculate ecc timed out\n");
-		return -ETIMEDOUT;
-	}
-
-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
-	ecc[0] = (uint8_t) (ecc_tmp >> 0);
-	ecc[1] = (uint8_t) (ecc_tmp >> 8);
-	ecc[2] = (uint8_t) (ecc_tmp >> 16);
-	ecc[3] = (uint8_t) (ecc_tmp >> 24);
-
-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
-	ecc[4] = (uint8_t) (ecc_tmp >> 0);
-	ecc[5] = (uint8_t) (ecc_tmp >> 8);
-	ecc[6] = (uint8_t) (ecc_tmp >> 16);
-	ecc[7] = (uint8_t) (ecc_tmp >> 24);
-
-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
-	ecc[8] = (uint8_t) (ecc_tmp >> 0);
-	ecc[9] = (uint8_t) (ecc_tmp >> 8);
-	ecc[10] = (uint8_t) (ecc_tmp >> 16);
-	ecc[11] = (uint8_t) (ecc_tmp >> 24);
-
-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
-	ecc[12] = (uint8_t) (ecc_tmp >> 16);
-
-	return 0;
-}
-
-/*
- * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by
- * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
- * max of 1-bit)
- */
-static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
-				uint8_t *ecc)
-{
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-	void __iomem *regs = host->regs_va;
-	uint32_t bank = host->bank;
-	uint32_t ecc_tmp;
-
-	ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
-	ecc[0] = (uint8_t) (ecc_tmp >> 0);
-	ecc[1] = (uint8_t) (ecc_tmp >> 8);
-	ecc[2] = (uint8_t) (ecc_tmp >> 16);
-
-	return 0;
-}
-
-/* Count the number of 0's in buff upto a max of max_bits */
-static int count_written_bits(uint8_t *buff, int size, int max_bits)
-{
-	int k, written_bits = 0;
-
-	for (k = 0; k < size; k++) {
-		written_bits += hweight8(~buff[k]);
-		if (written_bits > max_bits)
-			break;
-	}
-
-	return written_bits;
-}
-
-static void dma_complete(void *param)
-{
-	struct fsmc_nand_data *host = param;
-
-	complete(&host->dma_access_complete);
-}
-
-static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
-		enum dma_data_direction direction)
-{
-	struct dma_chan *chan;
-	struct dma_device *dma_dev;
-	struct dma_async_tx_descriptor *tx;
-	dma_addr_t dma_dst, dma_src, dma_addr;
-	dma_cookie_t cookie;
-	unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-	int ret;
-	unsigned long time_left;
-
-	if (direction == DMA_TO_DEVICE)
-		chan = host->write_dma_chan;
-	else if (direction == DMA_FROM_DEVICE)
-		chan = host->read_dma_chan;
-	else
-		return -EINVAL;
-
-	dma_dev = chan->device;
-	dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction);
-
-	if (direction == DMA_TO_DEVICE) {
-		dma_src = dma_addr;
-		dma_dst = host->data_pa;
-	} else {
-		dma_src = host->data_pa;
-		dma_dst = dma_addr;
-	}
-
-	tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
-			len, flags);
-	if (!tx) {
-		dev_err(host->dev, "device_prep_dma_memcpy error\n");
-		ret = -EIO;
-		goto unmap_dma;
-	}
-
-	tx->callback = dma_complete;
-	tx->callback_param = host;
-	cookie = tx->tx_submit(tx);
-
-	ret = dma_submit_error(cookie);
-	if (ret) {
-		dev_err(host->dev, "dma_submit_error %d\n", cookie);
-		goto unmap_dma;
-	}
-
-	dma_async_issue_pending(chan);
-
-	time_left =
-	wait_for_completion_timeout(&host->dma_access_complete,
-				msecs_to_jiffies(3000));
-	if (time_left == 0) {
-		dmaengine_terminate_all(chan);
-		dev_err(host->dev, "wait_for_completion_timeout\n");
-		ret = -ETIMEDOUT;
-		goto unmap_dma;
-	}
-
-	ret = 0;
-
-unmap_dma:
-	dma_unmap_single(dma_dev->dev, dma_addr, len, direction);
-
-	return ret;
-}
-
-/*
- * fsmc_write_buf - write buffer to chip
- * @mtd:	MTD device structure
- * @buf:	data buffer
- * @len:	number of bytes to write
- */
-static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	int i;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
-			IS_ALIGNED(len, sizeof(uint32_t))) {
-		uint32_t *p = (uint32_t *)buf;
-		len = len >> 2;
-		for (i = 0; i < len; i++)
-			writel_relaxed(p[i], chip->IO_ADDR_W);
-	} else {
-		for (i = 0; i < len; i++)
-			writeb_relaxed(buf[i], chip->IO_ADDR_W);
-	}
-}
-
-/*
- * fsmc_read_buf - read chip data into buffer
- * @mtd:	MTD device structure
- * @buf:	buffer to store date
- * @len:	number of bytes to read
- */
-static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	int i;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
-			IS_ALIGNED(len, sizeof(uint32_t))) {
-		uint32_t *p = (uint32_t *)buf;
-		len = len >> 2;
-		for (i = 0; i < len; i++)
-			p[i] = readl_relaxed(chip->IO_ADDR_R);
-	} else {
-		for (i = 0; i < len; i++)
-			buf[i] = readb_relaxed(chip->IO_ADDR_R);
-	}
-}
-
-/*
- * fsmc_read_buf_dma - read chip data into buffer
- * @mtd:	MTD device structure
- * @buf:	buffer to store date
- * @len:	number of bytes to read
- */
-static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
-
-	dma_xfer(host, buf, len, DMA_FROM_DEVICE);
-}
-
-/*
- * fsmc_write_buf_dma - write buffer to chip
- * @mtd:	MTD device structure
- * @buf:	data buffer
- * @len:	number of bytes to write
- */
-static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
-		int len)
-{
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-
-	dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
-}
-
-/*
- * fsmc_read_page_hwecc
- * @mtd:	mtd info structure
- * @chip:	nand chip info structure
- * @buf:	buffer to store read data
- * @oob_required:	caller expects OOB data read to chip->oob_poi
- * @page:	page number to read
- *
- * This routine is needed for fsmc version 8 as reading from NAND chip has to be
- * performed in a strict sequence as follows:
- * data(512 byte) -> ecc(13 byte)
- * After this read, fsmc hardware generates and reports error data bits(up to a
- * max of 8 bits)
- */
-static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-				 uint8_t *buf, int oob_required, int page)
-{
-	int i, j, s, stat, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *p = buf;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	uint8_t *ecc_code = chip->ecc.code_buf;
-	int off, len, group = 0;
-	/*
-	 * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we
-	 * end up reading 14 bytes (7 words) from oob. The local array is
-	 * to maintain word alignment
-	 */
-	uint16_t ecc_oob[7];
-	uint8_t *oob = (uint8_t *)&ecc_oob[0];
-	unsigned int max_bitflips = 0;
-
-	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
-		nand_read_page_op(chip, page, s * eccsize, NULL, 0);
-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-		chip->read_buf(mtd, p, eccsize);
-
-		for (j = 0; j < eccbytes;) {
-			struct mtd_oob_region oobregion;
-			int ret;
-
-			ret = mtd_ooblayout_ecc(mtd, group++, &oobregion);
-			if (ret)
-				return ret;
-
-			off = oobregion.offset;
-			len = oobregion.length;
-
-			/*
-			 * length is intentionally kept a higher multiple of 2
-			 * to read at least 13 bytes even in case of 16 bit NAND
-			 * devices
-			 */
-			if (chip->options & NAND_BUSWIDTH_16)
-				len = roundup(len, 2);
-
-			nand_read_oob_op(chip, page, off, oob + j, len);
-			j += len;
-		}
-
-		memcpy(&ecc_code[i], oob, chip->ecc.bytes);
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-	}
-
-	return max_bitflips;
-}
-
-/*
- * fsmc_bch8_correct_data
- * @mtd:	mtd info structure
- * @dat:	buffer of read data
- * @read_ecc:	ecc read from device spare area
- * @calc_ecc:	ecc calculated from read data
- *
- * calc_ecc is a 104 bit information containing maximum of 8 error
- * offset informations of 13 bits each in 512 bytes of read data.
- */
-static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
-			     uint8_t *read_ecc, uint8_t *calc_ecc)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
-	void __iomem *regs = host->regs_va;
-	unsigned int bank = host->bank;
-	uint32_t err_idx[8];
-	uint32_t num_err, i;
-	uint32_t ecc1, ecc2, ecc3, ecc4;
-
-	num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
-
-	/* no bit flipping */
-	if (likely(num_err == 0))
-		return 0;
-
-	/* too many errors */
-	if (unlikely(num_err > 8)) {
-		/*
-		 * This is a temporary erase check. A newly erased page read
-		 * would result in an ecc error because the oob data is also
-		 * erased to FF and the calculated ecc for an FF data is not
-		 * FF..FF.
-		 * This is a workaround to skip performing correction in case
-		 * data is FF..FF
-		 *
-		 * Logic:
-		 * For every page, each bit written as 0 is counted until these
-		 * number of bits are greater than 8 (the maximum correction
-		 * capability of FSMC for each 512 + 13 bytes)
-		 */
-
-		int bits_ecc = count_written_bits(read_ecc, chip->ecc.bytes, 8);
-		int bits_data = count_written_bits(dat, chip->ecc.size, 8);
-
-		if ((bits_ecc + bits_data) <= 8) {
-			if (bits_data)
-				memset(dat, 0xff, chip->ecc.size);
-			return bits_data;
-		}
-
-		return -EBADMSG;
-	}
-
-	/*
-	 * ------------------- calc_ecc[] bit wise -----------|--13 bits--|
-	 * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--|
-	 *
-	 * calc_ecc is a 104 bit information containing maximum of 8 error
-	 * offset informations of 13 bits each. calc_ecc is copied into a
-	 * uint64_t array and error offset indexes are populated in err_idx
-	 * array
-	 */
-	ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
-	ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
-	ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
-	ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
-
-	err_idx[0] = (ecc1 >> 0) & 0x1FFF;
-	err_idx[1] = (ecc1 >> 13) & 0x1FFF;
-	err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F);
-	err_idx[3] = (ecc2 >> 7) & 0x1FFF;
-	err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF);
-	err_idx[5] = (ecc3 >> 1) & 0x1FFF;
-	err_idx[6] = (ecc3 >> 14) & 0x1FFF;
-	err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F);
-
-	i = 0;
-	while (num_err--) {
-		change_bit(0, (unsigned long *)&err_idx[i]);
-		change_bit(1, (unsigned long *)&err_idx[i]);
-
-		if (err_idx[i] < chip->ecc.size * 8) {
-			change_bit(err_idx[i], (unsigned long *)dat);
-			i++;
-		}
-	}
-	return i;
-}
-
-static bool filter(struct dma_chan *chan, void *slave)
-{
-	chan->private = slave;
-	return true;
-}
-
-static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
-				     struct fsmc_nand_data *host,
-				     struct nand_chip *nand)
-{
-	struct device_node *np = pdev->dev.of_node;
-	u32 val;
-	int ret;
-
-	nand->options = 0;
-
-	if (!of_property_read_u32(np, "bank-width", &val)) {
-		if (val == 2) {
-			nand->options |= NAND_BUSWIDTH_16;
-		} else if (val != 1) {
-			dev_err(&pdev->dev, "invalid bank-width %u\n", val);
-			return -EINVAL;
-		}
-	}
-
-	if (of_get_property(np, "nand-skip-bbtscan", NULL))
-		nand->options |= NAND_SKIP_BBTSCAN;
-
-	host->dev_timings = devm_kzalloc(&pdev->dev,
-				sizeof(*host->dev_timings), GFP_KERNEL);
-	if (!host->dev_timings)
-		return -ENOMEM;
-	ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
-						sizeof(*host->dev_timings));
-	if (ret)
-		host->dev_timings = NULL;
-
-	/* Set default NAND bank to 0 */
-	host->bank = 0;
-	if (!of_property_read_u32(np, "bank", &val)) {
-		if (val > 3) {
-			dev_err(&pdev->dev, "invalid bank %u\n", val);
-			return -EINVAL;
-		}
-		host->bank = val;
-	}
-	return 0;
-}
-
-/*
- * fsmc_nand_probe - Probe function
- * @pdev:       platform device structure
- */
-static int __init fsmc_nand_probe(struct platform_device *pdev)
-{
-	struct fsmc_nand_data *host;
-	struct mtd_info *mtd;
-	struct nand_chip *nand;
-	struct resource *res;
-	dma_cap_mask_t mask;
-	int ret = 0;
-	u32 pid;
-	int i;
-
-	/* Allocate memory for the device structure (and zero it) */
-	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	nand = &host->nand;
-
-	ret = fsmc_nand_probe_config_dt(pdev, host, nand);
-	if (ret)
-		return ret;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-	host->data_va = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(host->data_va))
-		return PTR_ERR(host->data_va);
-
-	host->data_pa = (dma_addr_t)res->start;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
-	host->addr_va = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(host->addr_va))
-		return PTR_ERR(host->addr_va);
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
-	host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(host->cmd_va))
-		return PTR_ERR(host->cmd_va);
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
-	host->regs_va = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(host->regs_va))
-		return PTR_ERR(host->regs_va);
-
-	host->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(host->clk)) {
-		dev_err(&pdev->dev, "failed to fetch block clock\n");
-		return PTR_ERR(host->clk);
-	}
-
-	ret = clk_prepare_enable(host->clk);
-	if (ret)
-		return ret;
-
-	/*
-	 * This device ID is actually a common AMBA ID as used on the
-	 * AMBA PrimeCell bus. However it is not a PrimeCell.
-	 */
-	for (pid = 0, i = 0; i < 4; i++)
-		pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
-	host->pid = pid;
-	dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
-		 "revision %02x, config %02x\n",
-		 AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
-		 AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
-
-	host->dev = &pdev->dev;
-
-	if (host->mode == USE_DMA_ACCESS)
-		init_completion(&host->dma_access_complete);
-
-	/* Link all private pointers */
-	mtd = nand_to_mtd(&host->nand);
-	nand_set_controller_data(nand, host);
-	nand_set_flash_node(nand, pdev->dev.of_node);
-
-	mtd->dev.parent = &pdev->dev;
-	nand->IO_ADDR_R = host->data_va;
-	nand->IO_ADDR_W = host->data_va;
-	nand->cmd_ctrl = fsmc_cmd_ctrl;
-	nand->chip_delay = 30;
-
-	/*
-	 * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
-	 * can overwrite this value if the DT provides a different value.
-	 */
-	nand->ecc.mode = NAND_ECC_HW;
-	nand->ecc.hwctl = fsmc_enable_hwecc;
-	nand->ecc.size = 512;
-	nand->badblockbits = 7;
-
-	switch (host->mode) {
-	case USE_DMA_ACCESS:
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_MEMCPY, mask);
-		host->read_dma_chan = dma_request_channel(mask, filter, NULL);
-		if (!host->read_dma_chan) {
-			dev_err(&pdev->dev, "Unable to get read dma channel\n");
-			goto err_req_read_chnl;
-		}
-		host->write_dma_chan = dma_request_channel(mask, filter, NULL);
-		if (!host->write_dma_chan) {
-			dev_err(&pdev->dev, "Unable to get write dma channel\n");
-			goto err_req_write_chnl;
-		}
-		nand->read_buf = fsmc_read_buf_dma;
-		nand->write_buf = fsmc_write_buf_dma;
-		break;
-
-	default:
-	case USE_WORD_ACCESS:
-		nand->read_buf = fsmc_read_buf;
-		nand->write_buf = fsmc_write_buf;
-		break;
-	}
-
-	if (host->dev_timings)
-		fsmc_nand_setup(host, host->dev_timings);
-	else
-		nand->setup_data_interface = fsmc_setup_data_interface;
-
-	if (AMBA_REV_BITS(host->pid) >= 8) {
-		nand->ecc.read_page = fsmc_read_page_hwecc;
-		nand->ecc.calculate = fsmc_read_hwecc_ecc4;
-		nand->ecc.correct = fsmc_bch8_correct_data;
-		nand->ecc.bytes = 13;
-		nand->ecc.strength = 8;
-	}
-
-	/*
-	 * Scan to find existence of the device
-	 */
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret) {
-		dev_err(&pdev->dev, "No NAND Device found!\n");
-		goto err_scan_ident;
-	}
-
-	if (AMBA_REV_BITS(host->pid) >= 8) {
-		switch (mtd->oobsize) {
-		case 16:
-		case 64:
-		case 128:
-		case 224:
-		case 256:
-			break;
-		default:
-			dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
-				 mtd->oobsize);
-			ret = -EINVAL;
-			goto err_probe;
-		}
-
-		mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
-	} else {
-		switch (nand->ecc.mode) {
-		case NAND_ECC_HW:
-			dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
-			nand->ecc.calculate = fsmc_read_hwecc_ecc1;
-			nand->ecc.correct = nand_correct_data;
-			nand->ecc.bytes = 3;
-			nand->ecc.strength = 1;
-			break;
-
-		case NAND_ECC_SOFT:
-			if (nand->ecc.algo == NAND_ECC_BCH) {
-				dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
-				break;
-			}
-
-		case NAND_ECC_ON_DIE:
-			break;
-
-		default:
-			dev_err(&pdev->dev, "Unsupported ECC mode!\n");
-			goto err_probe;
-		}
-
-		/*
-		 * Don't set layout for BCH4 SW ECC. This will be
-		 * generated later in nand_bch_init() later.
-		 */
-		if (nand->ecc.mode == NAND_ECC_HW) {
-			switch (mtd->oobsize) {
-			case 16:
-			case 64:
-			case 128:
-				mtd_set_ooblayout(mtd,
-						  &fsmc_ecc1_ooblayout_ops);
-				break;
-			default:
-				dev_warn(&pdev->dev,
-					 "No oob scheme defined for oobsize %d\n",
-					 mtd->oobsize);
-				ret = -EINVAL;
-				goto err_probe;
-			}
-		}
-	}
-
-	/* Second stage of scan to fill MTD data-structures */
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		goto err_probe;
-
-	mtd->name = "nand";
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret)
-		goto err_probe;
-
-	platform_set_drvdata(pdev, host);
-	dev_info(&pdev->dev, "FSMC NAND driver registration successful\n");
-	return 0;
-
-err_probe:
-err_scan_ident:
-	if (host->mode == USE_DMA_ACCESS)
-		dma_release_channel(host->write_dma_chan);
-err_req_write_chnl:
-	if (host->mode == USE_DMA_ACCESS)
-		dma_release_channel(host->read_dma_chan);
-err_req_read_chnl:
-	clk_disable_unprepare(host->clk);
-	return ret;
-}
-
-/*
- * Clean up routine
- */
-static int fsmc_nand_remove(struct platform_device *pdev)
-{
-	struct fsmc_nand_data *host = platform_get_drvdata(pdev);
-
-	if (host) {
-		nand_release(nand_to_mtd(&host->nand));
-
-		if (host->mode == USE_DMA_ACCESS) {
-			dma_release_channel(host->write_dma_chan);
-			dma_release_channel(host->read_dma_chan);
-		}
-		clk_disable_unprepare(host->clk);
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int fsmc_nand_suspend(struct device *dev)
-{
-	struct fsmc_nand_data *host = dev_get_drvdata(dev);
-	if (host)
-		clk_disable_unprepare(host->clk);
-	return 0;
-}
-
-static int fsmc_nand_resume(struct device *dev)
-{
-	struct fsmc_nand_data *host = dev_get_drvdata(dev);
-	if (host) {
-		clk_prepare_enable(host->clk);
-		if (host->dev_timings)
-			fsmc_nand_setup(host, host->dev_timings);
-	}
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
-
-static const struct of_device_id fsmc_nand_id_table[] = {
-	{ .compatible = "st,spear600-fsmc-nand" },
-	{ .compatible = "stericsson,fsmc-nand" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
-
-static struct platform_driver fsmc_nand_driver = {
-	.remove = fsmc_nand_remove,
-	.driver = {
-		.name = "fsmc-nand",
-		.of_match_table = fsmc_nand_id_table,
-		.pm = &fsmc_nand_pm_ops,
-	},
-};
-
-module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi");
-MODULE_DESCRIPTION("NAND driver for SPEAr Platforms");
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c
deleted file mode 100644
index a8bde6665c24..000000000000
--- a/drivers/mtd/nand/gpio.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * drivers/mtd/nand/gpio.c
- *
- * Updated, and converted to generic GPIO based driver by Russell King.
- *
- * Written by Ben Dooks <ben@simtec.co.uk>
- *   Based on 2.4 version by Mark Whittaker
- *
- * © 2004 Simtec Electronics
- *
- * Device driver for NAND flash that uses a memory mapped interface to
- * read/write the NAND commands and data, and GPIO pins for control signals
- * (the DT binding refers to this as "GPIO assisted NAND flash")
- *
- * 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/kernel.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand-gpio.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-struct gpiomtd {
-	void __iomem		*io_sync;
-	struct nand_chip	nand_chip;
-	struct gpio_nand_platdata plat;
-	struct gpio_desc *nce; /* Optional chip enable */
-	struct gpio_desc *cle;
-	struct gpio_desc *ale;
-	struct gpio_desc *rdy;
-	struct gpio_desc *nwp; /* Optional write protection */
-};
-
-static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip);
-}
-
-
-#ifdef CONFIG_ARM
-/* gpio_nand_dosync()
- *
- * Make sure the GPIO state changes occur in-order with writes to NAND
- * memory region.
- * Needed on PXA due to bus-reordering within the SoC itself (see section on
- * I/O ordering in PXA manual (section 2.3, p35)
- */
-static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
-{
-	unsigned long tmp;
-
-	if (gpiomtd->io_sync) {
-		/*
-		 * Linux memory barriers don't cater for what's required here.
-		 * What's required is what's here - a read from a separate
-		 * region with a dependency on that read.
-		 */
-		tmp = readl(gpiomtd->io_sync);
-		asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp));
-	}
-}
-#else
-static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
-#endif
-
-static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
-
-	gpio_nand_dosync(gpiomtd);
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		if (gpiomtd->nce)
-			gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE));
-		gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE));
-		gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE));
-		gpio_nand_dosync(gpiomtd);
-	}
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
-	gpio_nand_dosync(gpiomtd);
-}
-
-static int gpio_nand_devready(struct mtd_info *mtd)
-{
-	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
-
-	return gpiod_get_value(gpiomtd->rdy);
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id gpio_nand_id_table[] = {
-	{ .compatible = "gpio-control-nand" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
-
-static int gpio_nand_get_config_of(const struct device *dev,
-				   struct gpio_nand_platdata *plat)
-{
-	u32 val;
-
-	if (!dev->of_node)
-		return -ENODEV;
-
-	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
-		if (val == 2) {
-			plat->options |= NAND_BUSWIDTH_16;
-		} else if (val != 1) {
-			dev_err(dev, "invalid bank-width %u\n", val);
-			return -EINVAL;
-		}
-	}
-
-	if (!of_property_read_u32(dev->of_node, "chip-delay", &val))
-		plat->chip_delay = val;
-
-	return 0;
-}
-
-static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
-{
-	struct resource *r;
-	u64 addr;
-
-	if (of_property_read_u64(pdev->dev.of_node,
-				       "gpio-control-nand,io-sync-reg", &addr))
-		return NULL;
-
-	r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
-	if (!r)
-		return NULL;
-
-	r->start = addr;
-	r->end = r->start + 0x3;
-	r->flags = IORESOURCE_MEM;
-
-	return r;
-}
-#else /* CONFIG_OF */
-static inline int gpio_nand_get_config_of(const struct device *dev,
-					  struct gpio_nand_platdata *plat)
-{
-	return -ENOSYS;
-}
-
-static inline struct resource *
-gpio_nand_get_io_sync_of(struct platform_device *pdev)
-{
-	return NULL;
-}
-#endif /* CONFIG_OF */
-
-static inline int gpio_nand_get_config(const struct device *dev,
-				       struct gpio_nand_platdata *plat)
-{
-	int ret = gpio_nand_get_config_of(dev, plat);
-
-	if (!ret)
-		return ret;
-
-	if (dev_get_platdata(dev)) {
-		memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static inline struct resource *
-gpio_nand_get_io_sync(struct platform_device *pdev)
-{
-	struct resource *r = gpio_nand_get_io_sync_of(pdev);
-
-	if (r)
-		return r;
-
-	return platform_get_resource(pdev, IORESOURCE_MEM, 1);
-}
-
-static int gpio_nand_remove(struct platform_device *pdev)
-{
-	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
-
-	nand_release(nand_to_mtd(&gpiomtd->nand_chip));
-
-	/* Enable write protection and disable the chip */
-	if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
-		gpiod_set_value(gpiomtd->nwp, 0);
-	if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
-		gpiod_set_value(gpiomtd->nce, 0);
-
-	return 0;
-}
-
-static int gpio_nand_probe(struct platform_device *pdev)
-{
-	struct gpiomtd *gpiomtd;
-	struct nand_chip *chip;
-	struct mtd_info *mtd;
-	struct resource *res;
-	struct device *dev = &pdev->dev;
-	int ret = 0;
-
-	if (!dev->of_node && !dev_get_platdata(dev))
-		return -EINVAL;
-
-	gpiomtd = devm_kzalloc(dev, sizeof(*gpiomtd), GFP_KERNEL);
-	if (!gpiomtd)
-		return -ENOMEM;
-
-	chip = &gpiomtd->nand_chip;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
-	if (IS_ERR(chip->IO_ADDR_R))
-		return PTR_ERR(chip->IO_ADDR_R);
-
-	res = gpio_nand_get_io_sync(pdev);
-	if (res) {
-		gpiomtd->io_sync = devm_ioremap_resource(dev, res);
-		if (IS_ERR(gpiomtd->io_sync))
-			return PTR_ERR(gpiomtd->io_sync);
-	}
-
-	ret = gpio_nand_get_config(dev, &gpiomtd->plat);
-	if (ret)
-		return ret;
-
-	/* Just enable the chip */
-	gpiomtd->nce = devm_gpiod_get_optional(dev, "nce", GPIOD_OUT_HIGH);
-	if (IS_ERR(gpiomtd->nce))
-		return PTR_ERR(gpiomtd->nce);
-
-	/* We disable write protection once we know probe() will succeed */
-	gpiomtd->nwp = devm_gpiod_get_optional(dev, "nwp", GPIOD_OUT_LOW);
-	if (IS_ERR(gpiomtd->nwp)) {
-		ret = PTR_ERR(gpiomtd->nwp);
-		goto out_ce;
-	}
-
-	gpiomtd->ale = devm_gpiod_get(dev, "ale", GPIOD_OUT_LOW);
-	if (IS_ERR(gpiomtd->ale)) {
-		ret = PTR_ERR(gpiomtd->ale);
-		goto out_ce;
-	}
-
-	gpiomtd->cle = devm_gpiod_get(dev, "cle", GPIOD_OUT_LOW);
-	if (IS_ERR(gpiomtd->cle)) {
-		ret = PTR_ERR(gpiomtd->cle);
-		goto out_ce;
-	}
-
-	gpiomtd->rdy = devm_gpiod_get_optional(dev, "rdy", GPIOD_IN);
-	if (IS_ERR(gpiomtd->rdy)) {
-		ret = PTR_ERR(gpiomtd->rdy);
-		goto out_ce;
-	}
-	/* Using RDY pin */
-	if (gpiomtd->rdy)
-		chip->dev_ready = gpio_nand_devready;
-
-	nand_set_flash_node(chip, pdev->dev.of_node);
-	chip->IO_ADDR_W		= chip->IO_ADDR_R;
-	chip->ecc.mode		= NAND_ECC_SOFT;
-	chip->ecc.algo		= NAND_ECC_HAMMING;
-	chip->options		= gpiomtd->plat.options;
-	chip->chip_delay	= gpiomtd->plat.chip_delay;
-	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;
-
-	mtd			= nand_to_mtd(chip);
-	mtd->dev.parent		= dev;
-
-	platform_set_drvdata(pdev, gpiomtd);
-
-	/* Disable write protection, if wired up */
-	if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
-		gpiod_direction_output(gpiomtd->nwp, 1);
-
-	ret = nand_scan(mtd, 1);
-	if (ret)
-		goto err_wp;
-
-	if (gpiomtd->plat.adjust_parts)
-		gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
-
-	ret = mtd_device_register(mtd, gpiomtd->plat.parts,
-				  gpiomtd->plat.num_parts);
-	if (!ret)
-		return 0;
-
-err_wp:
-	if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
-		gpiod_set_value(gpiomtd->nwp, 0);
-out_ce:
-	if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
-		gpiod_set_value(gpiomtd->nce, 0);
-
-	return ret;
-}
-
-static struct platform_driver gpio_nand_driver = {
-	.probe		= gpio_nand_probe,
-	.remove		= gpio_nand_remove,
-	.driver		= {
-		.name	= "gpio-nand",
-		.of_match_table = of_match_ptr(gpio_nand_id_table),
-	},
-};
-
-module_platform_driver(gpio_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("GPIO NAND Driver");
diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/gpmi-nand/Makefile
deleted file mode 100644
index 3a462487c35e..000000000000
--- a/drivers/mtd/nand/gpmi-nand/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o
-gpmi_nand-objs += gpmi-nand.o
-gpmi_nand-objs += gpmi-lib.o
diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h
deleted file mode 100644
index 05bb91f2f4c4..000000000000
--- a/drivers/mtd/nand/gpmi-nand/bch-regs.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
- * Copyright 2008 Embedded Alley Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef __GPMI_NAND_BCH_REGS_H
-#define __GPMI_NAND_BCH_REGS_H
-
-#define HW_BCH_CTRL				0x00000000
-#define HW_BCH_CTRL_SET				0x00000004
-#define HW_BCH_CTRL_CLR				0x00000008
-#define HW_BCH_CTRL_TOG				0x0000000c
-
-#define BM_BCH_CTRL_COMPLETE_IRQ_EN		(1 << 8)
-#define BM_BCH_CTRL_COMPLETE_IRQ		(1 << 0)
-
-#define HW_BCH_STATUS0				0x00000010
-#define HW_BCH_MODE				0x00000020
-#define HW_BCH_ENCODEPTR			0x00000030
-#define HW_BCH_DATAPTR				0x00000040
-#define HW_BCH_METAPTR				0x00000050
-#define HW_BCH_LAYOUTSELECT			0x00000070
-
-#define HW_BCH_FLASH0LAYOUT0			0x00000080
-
-#define BP_BCH_FLASH0LAYOUT0_NBLOCKS		24
-#define BM_BCH_FLASH0LAYOUT0_NBLOCKS	(0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS)
-#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v)		\
-	(((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS)
-
-#define BP_BCH_FLASH0LAYOUT0_META_SIZE		16
-#define BM_BCH_FLASH0LAYOUT0_META_SIZE	(0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE)
-#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v)	\
-	(((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\
-					 & BM_BCH_FLASH0LAYOUT0_META_SIZE)
-
-#define BP_BCH_FLASH0LAYOUT0_ECC0		12
-#define BM_BCH_FLASH0LAYOUT0_ECC0	(0xf << BP_BCH_FLASH0LAYOUT0_ECC0)
-#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0		11
-#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)
-#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x)				\
-	(GPMI_IS_MX6(x)					\
-		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)	\
-			& MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0)	\
-		: (((v) << BP_BCH_FLASH0LAYOUT0_ECC0)		\
-			& BM_BCH_FLASH0LAYOUT0_ECC0)		\
-	)
-
-#define MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14	10
-#define MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14			\
-				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)
-#define BF_BCH_FLASH0LAYOUT0_GF(v, x)				\
-	((GPMI_IS_MX6(x) && ((v) == 14))			\
-		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)	\
-			& MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14)	\
-		: 0						\
-	)
-
-#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE		0
-#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE		\
-			(0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
-#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE	\
-			(0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
-#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x)				\
-	(GPMI_IS_MX6(x)						\
-		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)	\
-		: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)		\
-	)
-
-#define HW_BCH_FLASH0LAYOUT1			0x00000090
-
-#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE		16
-#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE		\
-			(0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE)
-#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v)	\
-	(((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \
-					 & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
-
-#define BP_BCH_FLASH0LAYOUT1_ECCN		12
-#define BM_BCH_FLASH0LAYOUT1_ECCN	(0xf << BP_BCH_FLASH0LAYOUT1_ECCN)
-#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN		11
-#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)
-#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x)				\
-	(GPMI_IS_MX6(x)					\
-		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)	\
-			& MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN)	\
-		: (((v) << BP_BCH_FLASH0LAYOUT1_ECCN)		\
-			& BM_BCH_FLASH0LAYOUT1_ECCN)		\
-	)
-
-#define MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14	10
-#define MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14			\
-				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)
-#define BF_BCH_FLASH0LAYOUT1_GF(v, x)				\
-	((GPMI_IS_MX6(x) && ((v) == 14))			\
-		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)	\
-			& MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14)	\
-		: 0						\
-	)
-
-#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE		0
-#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE		\
-			(0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
-#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE	\
-			(0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
-#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x)				\
-	(GPMI_IS_MX6(x)						\
-		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)	\
-		: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)		\
-	)
-
-#define HW_BCH_VERSION				0x00000160
-#endif
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
deleted file mode 100644
index 97787246af41..000000000000
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ /dev/null
@@ -1,1510 +0,0 @@
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-
-#include "gpmi-nand.h"
-#include "gpmi-regs.h"
-#include "bch-regs.h"
-
-static struct timing_threshold timing_default_threshold = {
-	.max_data_setup_cycles       = (BM_GPMI_TIMING0_DATA_SETUP >>
-						BP_GPMI_TIMING0_DATA_SETUP),
-	.internal_data_setup_in_ns   = 0,
-	.max_sample_delay_factor     = (BM_GPMI_CTRL1_RDN_DELAY >>
-						BP_GPMI_CTRL1_RDN_DELAY),
-	.max_dll_clock_period_in_ns  = 32,
-	.max_dll_delay_in_ns         = 16,
-};
-
-#define MXS_SET_ADDR		0x4
-#define MXS_CLR_ADDR		0x8
-/*
- * Clear the bit and poll it cleared.  This is usually called with
- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
- * (bit 30).
- */
-static int clear_poll_bit(void __iomem *addr, u32 mask)
-{
-	int timeout = 0x400;
-
-	/* clear the bit */
-	writel(mask, addr + MXS_CLR_ADDR);
-
-	/*
-	 * SFTRST needs 3 GPMI clocks to settle, the reference manual
-	 * recommends to wait 1us.
-	 */
-	udelay(1);
-
-	/* poll the bit becoming clear */
-	while ((readl(addr) & mask) && --timeout)
-		/* nothing */;
-
-	return !timeout;
-}
-
-#define MODULE_CLKGATE		(1 << 30)
-#define MODULE_SFTRST		(1 << 31)
-/*
- * The current mxs_reset_block() will do two things:
- *  [1] enable the module.
- *  [2] reset the module.
- *
- * In most of the cases, it's ok.
- * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
- * If you try to soft reset the BCH block, it becomes unusable until
- * the next hard reset. This case occurs in the NAND boot mode. When the board
- * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
- * So If the driver tries to reset the BCH again, the BCH will not work anymore.
- * You will see a DMA timeout in this case. The bug has been fixed
- * in the following chips, such as MX28.
- *
- * To avoid this bug, just add a new parameter `just_enable` for
- * the mxs_reset_block(), and rewrite it here.
- */
-static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
-{
-	int ret;
-	int timeout = 0x400;
-
-	/* clear and poll SFTRST */
-	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
-	if (unlikely(ret))
-		goto error;
-
-	/* clear CLKGATE */
-	writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
-
-	if (!just_enable) {
-		/* set SFTRST to reset the block */
-		writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
-		udelay(1);
-
-		/* poll CLKGATE becoming set */
-		while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
-			/* nothing */;
-		if (unlikely(!timeout))
-			goto error;
-	}
-
-	/* clear and poll SFTRST */
-	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
-	if (unlikely(ret))
-		goto error;
-
-	/* clear and poll CLKGATE */
-	ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
-	if (unlikely(ret))
-		goto error;
-
-	return 0;
-
-error:
-	pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
-	return -ETIMEDOUT;
-}
-
-static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
-{
-	struct clk *clk;
-	int ret;
-	int i;
-
-	for (i = 0; i < GPMI_CLK_MAX; i++) {
-		clk = this->resources.clock[i];
-		if (!clk)
-			break;
-
-		if (v) {
-			ret = clk_prepare_enable(clk);
-			if (ret)
-				goto err_clk;
-		} else {
-			clk_disable_unprepare(clk);
-		}
-	}
-	return 0;
-
-err_clk:
-	for (; i > 0; i--)
-		clk_disable_unprepare(this->resources.clock[i - 1]);
-	return ret;
-}
-
-#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
-#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
-
-int gpmi_init(struct gpmi_nand_data *this)
-{
-	struct resources *r = &this->resources;
-	int ret;
-
-	ret = gpmi_enable_clk(this);
-	if (ret)
-		return ret;
-	ret = gpmi_reset_block(r->gpmi_regs, false);
-	if (ret)
-		goto err_out;
-
-	/*
-	 * Reset BCH here, too. We got failures otherwise :(
-	 * See later BCH reset for explanation of MX23 handling
-	 */
-	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
-	if (ret)
-		goto err_out;
-
-
-	/* Choose NAND mode. */
-	writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
-
-	/* Set the IRQ polarity. */
-	writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
-				r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	/* Disable Write-Protection. */
-	writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	/* Select BCH ECC. */
-	writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	/*
-	 * Decouple the chip select from dma channel. We use dma0 for all
-	 * the chips.
-	 */
-	writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	gpmi_disable_clk(this);
-	return 0;
-err_out:
-	gpmi_disable_clk(this);
-	return ret;
-}
-
-/* This function is very useful. It is called only when the bug occur. */
-void gpmi_dump_info(struct gpmi_nand_data *this)
-{
-	struct resources *r = &this->resources;
-	struct bch_geometry *geo = &this->bch_geometry;
-	u32 reg;
-	int i;
-
-	dev_err(this->dev, "Show GPMI registers :\n");
-	for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
-		reg = readl(r->gpmi_regs + i * 0x10);
-		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
-	}
-
-	/* start to print out the BCH info */
-	dev_err(this->dev, "Show BCH registers :\n");
-	for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
-		reg = readl(r->bch_regs + i * 0x10);
-		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
-	}
-	dev_err(this->dev, "BCH Geometry :\n"
-		"GF length              : %u\n"
-		"ECC Strength           : %u\n"
-		"Page Size in Bytes     : %u\n"
-		"Metadata Size in Bytes : %u\n"
-		"ECC Chunk Size in Bytes: %u\n"
-		"ECC Chunk Count        : %u\n"
-		"Payload Size in Bytes  : %u\n"
-		"Auxiliary Size in Bytes: %u\n"
-		"Auxiliary Status Offset: %u\n"
-		"Block Mark Byte Offset : %u\n"
-		"Block Mark Bit Offset  : %u\n",
-		geo->gf_len,
-		geo->ecc_strength,
-		geo->page_size,
-		geo->metadata_size,
-		geo->ecc_chunk_size,
-		geo->ecc_chunk_count,
-		geo->payload_size,
-		geo->auxiliary_size,
-		geo->auxiliary_status_offset,
-		geo->block_mark_byte_offset,
-		geo->block_mark_bit_offset);
-}
-
-/* Configures the geometry for BCH.  */
-int bch_set_geometry(struct gpmi_nand_data *this)
-{
-	struct resources *r = &this->resources;
-	struct bch_geometry *bch_geo = &this->bch_geometry;
-	unsigned int block_count;
-	unsigned int block_size;
-	unsigned int metadata_size;
-	unsigned int ecc_strength;
-	unsigned int page_size;
-	unsigned int gf_len;
-	int ret;
-
-	if (common_nfc_set_geometry(this))
-		return !0;
-
-	block_count   = bch_geo->ecc_chunk_count - 1;
-	block_size    = bch_geo->ecc_chunk_size;
-	metadata_size = bch_geo->metadata_size;
-	ecc_strength  = bch_geo->ecc_strength >> 1;
-	page_size     = bch_geo->page_size;
-	gf_len        = bch_geo->gf_len;
-
-	ret = gpmi_enable_clk(this);
-	if (ret)
-		return ret;
-
-	/*
-	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
-	* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
-	* On the other hand, the MX28 needs the reset, because one case has been
-	* seen where the BCH produced ECC errors constantly after 10000
-	* consecutive reboots. The latter case has not been seen on the MX23
-	* yet, still we don't know if it could happen there as well.
-	*/
-	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
-	if (ret)
-		goto err_out;
-
-	/* Configure layout 0. */
-	writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
-			| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
-			| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
-			| BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
-			| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
-			r->bch_regs + HW_BCH_FLASH0LAYOUT0);
-
-	writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
-			| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
-			| BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
-			| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
-			r->bch_regs + HW_BCH_FLASH0LAYOUT1);
-
-	/* Set *all* chip selects to use layout 0. */
-	writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
-
-	/* Enable interrupts. */
-	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
-				r->bch_regs + HW_BCH_CTRL_SET);
-
-	gpmi_disable_clk(this);
-	return 0;
-err_out:
-	gpmi_disable_clk(this);
-	return ret;
-}
-
-/* Converts time in nanoseconds to cycles. */
-static unsigned int ns_to_cycles(unsigned int time,
-			unsigned int period, unsigned int min)
-{
-	unsigned int k;
-
-	k = (time + period - 1) / period;
-	return max(k, min);
-}
-
-#define DEF_MIN_PROP_DELAY	5
-#define DEF_MAX_PROP_DELAY	9
-/* Apply timing to current hardware conditions. */
-static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
-					struct gpmi_nfc_hardware_timing *hw)
-{
-	struct timing_threshold *nfc = &timing_default_threshold;
-	struct resources *r = &this->resources;
-	struct nand_chip *nand = &this->nand;
-	struct nand_timing target = this->timing;
-	bool improved_timing_is_available;
-	unsigned long clock_frequency_in_hz;
-	unsigned int clock_period_in_ns;
-	bool dll_use_half_periods;
-	unsigned int dll_delay_shift;
-	unsigned int max_sample_delay_in_ns;
-	unsigned int address_setup_in_cycles;
-	unsigned int data_setup_in_ns;
-	unsigned int data_setup_in_cycles;
-	unsigned int data_hold_in_cycles;
-	int ideal_sample_delay_in_ns;
-	unsigned int sample_delay_factor;
-	int tEYE;
-	unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
-	unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
-
-	/*
-	 * If there are multiple chips, we need to relax the timings to allow
-	 * for signal distortion due to higher capacitance.
-	 */
-	if (nand->numchips > 2) {
-		target.data_setup_in_ns    += 10;
-		target.data_hold_in_ns     += 10;
-		target.address_setup_in_ns += 10;
-	} else if (nand->numchips > 1) {
-		target.data_setup_in_ns    += 5;
-		target.data_hold_in_ns     += 5;
-		target.address_setup_in_ns += 5;
-	}
-
-	/* Check if improved timing information is available. */
-	improved_timing_is_available =
-		(target.tREA_in_ns  >= 0) &&
-		(target.tRLOH_in_ns >= 0) &&
-		(target.tRHOH_in_ns >= 0);
-
-	/* Inspect the clock. */
-	nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
-	clock_frequency_in_hz = nfc->clock_frequency_in_hz;
-	clock_period_in_ns    = NSEC_PER_SEC / clock_frequency_in_hz;
-
-	/*
-	 * The NFC quantizes setup and hold parameters in terms of clock cycles.
-	 * Here, we quantize the setup and hold timing parameters to the
-	 * next-highest clock period to make sure we apply at least the
-	 * specified times.
-	 *
-	 * For data setup and data hold, the hardware interprets a value of zero
-	 * as the largest possible delay. This is not what's intended by a zero
-	 * in the input parameter, so we impose a minimum of one cycle.
-	 */
-	data_setup_in_cycles    = ns_to_cycles(target.data_setup_in_ns,
-							clock_period_in_ns, 1);
-	data_hold_in_cycles     = ns_to_cycles(target.data_hold_in_ns,
-							clock_period_in_ns, 1);
-	address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns,
-							clock_period_in_ns, 0);
-
-	/*
-	 * The clock's period affects the sample delay in a number of ways:
-	 *
-	 * (1) The NFC HAL tells us the maximum clock period the sample delay
-	 *     DLL can tolerate. If the clock period is greater than half that
-	 *     maximum, we must configure the DLL to be driven by half periods.
-	 *
-	 * (2) We need to convert from an ideal sample delay, in ns, to a
-	 *     "sample delay factor," which the NFC uses. This factor depends on
-	 *     whether we're driving the DLL with full or half periods.
-	 *     Paraphrasing the reference manual:
-	 *
-	 *         AD = SDF x 0.125 x RP
-	 *
-	 * where:
-	 *
-	 *     AD   is the applied delay, in ns.
-	 *     SDF  is the sample delay factor, which is dimensionless.
-	 *     RP   is the reference period, in ns, which is a full clock period
-	 *          if the DLL is being driven by full periods, or half that if
-	 *          the DLL is being driven by half periods.
-	 *
-	 * Let's re-arrange this in a way that's more useful to us:
-	 *
-	 *                        8
-	 *         SDF  =  AD x ----
-	 *                       RP
-	 *
-	 * The reference period is either the clock period or half that, so this
-	 * is:
-	 *
-	 *                        8       AD x DDF
-	 *         SDF  =  AD x -----  =  --------
-	 *                      f x P        P
-	 *
-	 * where:
-	 *
-	 *       f  is 1 or 1/2, depending on how we're driving the DLL.
-	 *       P  is the clock period.
-	 *     DDF  is the DLL Delay Factor, a dimensionless value that
-	 *          incorporates all the constants in the conversion.
-	 *
-	 * DDF will be either 8 or 16, both of which are powers of two. We can
-	 * reduce the cost of this conversion by using bit shifts instead of
-	 * multiplication or division. Thus:
-	 *
-	 *                 AD << DDS
-	 *         SDF  =  ---------
-	 *                     P
-	 *
-	 *     or
-	 *
-	 *         AD  =  (SDF >> DDS) x P
-	 *
-	 * where:
-	 *
-	 *     DDS  is the DLL Delay Shift, the logarithm to base 2 of the DDF.
-	 */
-	if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) {
-		dll_use_half_periods = true;
-		dll_delay_shift      = 3 + 1;
-	} else {
-		dll_use_half_periods = false;
-		dll_delay_shift      = 3;
-	}
-
-	/*
-	 * Compute the maximum sample delay the NFC allows, under current
-	 * conditions. If the clock is running too slowly, no sample delay is
-	 * possible.
-	 */
-	if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns)
-		max_sample_delay_in_ns = 0;
-	else {
-		/*
-		 * Compute the delay implied by the largest sample delay factor
-		 * the NFC allows.
-		 */
-		max_sample_delay_in_ns =
-			(nfc->max_sample_delay_factor * clock_period_in_ns) >>
-								dll_delay_shift;
-
-		/*
-		 * Check if the implied sample delay larger than the NFC
-		 * actually allows.
-		 */
-		if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns)
-			max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
-	}
-
-	/*
-	 * Check if improved timing information is available. If not, we have to
-	 * use a less-sophisticated algorithm.
-	 */
-	if (!improved_timing_is_available) {
-		/*
-		 * Fold the read setup time required by the NFC into the ideal
-		 * sample delay.
-		 */
-		ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns +
-						nfc->internal_data_setup_in_ns;
-
-		/*
-		 * The ideal sample delay may be greater than the maximum
-		 * allowed by the NFC. If so, we can trade off sample delay time
-		 * for more data setup time.
-		 *
-		 * In each iteration of the following loop, we add a cycle to
-		 * the data setup time and subtract a corresponding amount from
-		 * the sample delay until we've satisified the constraints or
-		 * can't do any better.
-		 */
-		while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
-
-			data_setup_in_cycles++;
-			ideal_sample_delay_in_ns -= clock_period_in_ns;
-
-			if (ideal_sample_delay_in_ns < 0)
-				ideal_sample_delay_in_ns = 0;
-
-		}
-
-		/*
-		 * Compute the sample delay factor that corresponds most closely
-		 * to the ideal sample delay. If the result is too large for the
-		 * NFC, use the maximum value.
-		 *
-		 * Notice that we use the ns_to_cycles function to compute the
-		 * sample delay factor. We do this because the form of the
-		 * computation is the same as that for calculating cycles.
-		 */
-		sample_delay_factor =
-			ns_to_cycles(
-				ideal_sample_delay_in_ns << dll_delay_shift,
-							clock_period_in_ns, 0);
-
-		if (sample_delay_factor > nfc->max_sample_delay_factor)
-			sample_delay_factor = nfc->max_sample_delay_factor;
-
-		/* Skip to the part where we return our results. */
-		goto return_results;
-	}
-
-	/*
-	 * If control arrives here, we have more detailed timing information,
-	 * so we can use a better algorithm.
-	 */
-
-	/*
-	 * Fold the read setup time required by the NFC into the maximum
-	 * propagation delay.
-	 */
-	max_prop_delay_in_ns += nfc->internal_data_setup_in_ns;
-
-	/*
-	 * Earlier, we computed the number of clock cycles required to satisfy
-	 * the data setup time. Now, we need to know the actual nanoseconds.
-	 */
-	data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles;
-
-	/*
-	 * Compute tEYE, the width of the data eye when reading from the NAND
-	 * Flash. The eye width is fundamentally determined by the data setup
-	 * time, perturbed by propagation delays and some characteristics of the
-	 * NAND Flash device.
-	 *
-	 * start of the eye = max_prop_delay + tREA
-	 * end of the eye   = min_prop_delay + tRHOH + data_setup
-	 */
-	tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns +
-							(int)data_setup_in_ns;
-
-	tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns;
-
-	/*
-	 * The eye must be open. If it's not, we can try to open it by
-	 * increasing its main forcer, the data setup time.
-	 *
-	 * In each iteration of the following loop, we increase the data setup
-	 * time by a single clock cycle. We do this until either the eye is
-	 * open or we run into NFC limits.
-	 */
-	while ((tEYE <= 0) &&
-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
-		/* Give a cycle to data setup. */
-		data_setup_in_cycles++;
-		/* Synchronize the data setup time with the cycles. */
-		data_setup_in_ns += clock_period_in_ns;
-		/* Adjust tEYE accordingly. */
-		tEYE += clock_period_in_ns;
-	}
-
-	/*
-	 * When control arrives here, the eye is open. The ideal time to sample
-	 * the data is in the center of the eye:
-	 *
-	 *     end of the eye + start of the eye
-	 *     ---------------------------------  -  data_setup
-	 *                    2
-	 *
-	 * After some algebra, this simplifies to the code immediately below.
-	 */
-	ideal_sample_delay_in_ns =
-		((int)max_prop_delay_in_ns +
-			(int)target.tREA_in_ns +
-				(int)min_prop_delay_in_ns +
-					(int)target.tRHOH_in_ns -
-						(int)data_setup_in_ns) >> 1;
-
-	/*
-	 * The following figure illustrates some aspects of a NAND Flash read:
-	 *
-	 *
-	 *           __                   _____________________________________
-	 * RDN         \_________________/
-	 *
-	 *                                         <---- tEYE ----->
-	 *                                        /-----------------\
-	 * Read Data ----------------------------<                   >---------
-	 *                                        \-----------------/
-	 *             ^                 ^                 ^              ^
-	 *             |                 |                 |              |
-	 *             |<--Data Setup -->|<--Delay Time -->|              |
-	 *             |                 |                 |              |
-	 *             |                 |                                |
-	 *             |                 |<--   Quantized Delay Time   -->|
-	 *             |                 |                                |
-	 *
-	 *
-	 * We have some issues we must now address:
-	 *
-	 * (1) The *ideal* sample delay time must not be negative. If it is, we
-	 *     jam it to zero.
-	 *
-	 * (2) The *ideal* sample delay time must not be greater than that
-	 *     allowed by the NFC. If it is, we can increase the data setup
-	 *     time, which will reduce the delay between the end of the data
-	 *     setup and the center of the eye. It will also make the eye
-	 *     larger, which might help with the next issue...
-	 *
-	 * (3) The *quantized* sample delay time must not fall either before the
-	 *     eye opens or after it closes (the latter is the problem
-	 *     illustrated in the above figure).
-	 */
-
-	/* Jam a negative ideal sample delay to zero. */
-	if (ideal_sample_delay_in_ns < 0)
-		ideal_sample_delay_in_ns = 0;
-
-	/*
-	 * Extend the data setup as needed to reduce the ideal sample delay
-	 * below the maximum permitted by the NFC.
-	 */
-	while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
-
-		/* Give a cycle to data setup. */
-		data_setup_in_cycles++;
-		/* Synchronize the data setup time with the cycles. */
-		data_setup_in_ns += clock_period_in_ns;
-		/* Adjust tEYE accordingly. */
-		tEYE += clock_period_in_ns;
-
-		/*
-		 * Decrease the ideal sample delay by one half cycle, to keep it
-		 * in the middle of the eye.
-		 */
-		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
-
-		/* Jam a negative ideal sample delay to zero. */
-		if (ideal_sample_delay_in_ns < 0)
-			ideal_sample_delay_in_ns = 0;
-	}
-
-	/*
-	 * Compute the sample delay factor that corresponds to the ideal sample
-	 * delay. If the result is too large, then use the maximum allowed
-	 * value.
-	 *
-	 * Notice that we use the ns_to_cycles function to compute the sample
-	 * delay factor. We do this because the form of the computation is the
-	 * same as that for calculating cycles.
-	 */
-	sample_delay_factor =
-		ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift,
-							clock_period_in_ns, 0);
-
-	if (sample_delay_factor > nfc->max_sample_delay_factor)
-		sample_delay_factor = nfc->max_sample_delay_factor;
-
-	/*
-	 * These macros conveniently encapsulate a computation we'll use to
-	 * continuously evaluate whether or not the data sample delay is inside
-	 * the eye.
-	 */
-	#define IDEAL_DELAY  ((int) ideal_sample_delay_in_ns)
-
-	#define QUANTIZED_DELAY  \
-		((int) ((sample_delay_factor * clock_period_in_ns) >> \
-							dll_delay_shift))
-
-	#define DELAY_ERROR  (abs(QUANTIZED_DELAY - IDEAL_DELAY))
-
-	#define SAMPLE_IS_NOT_WITHIN_THE_EYE  (DELAY_ERROR > (tEYE >> 1))
-
-	/*
-	 * While the quantized sample time falls outside the eye, reduce the
-	 * sample delay or extend the data setup to move the sampling point back
-	 * toward the eye. Do not allow the number of data setup cycles to
-	 * exceed the maximum allowed by the NFC.
-	 */
-	while (SAMPLE_IS_NOT_WITHIN_THE_EYE &&
-			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
-		/*
-		 * If control arrives here, the quantized sample delay falls
-		 * outside the eye. Check if it's before the eye opens, or after
-		 * the eye closes.
-		 */
-		if (QUANTIZED_DELAY > IDEAL_DELAY) {
-			/*
-			 * If control arrives here, the quantized sample delay
-			 * falls after the eye closes. Decrease the quantized
-			 * delay time and then go back to re-evaluate.
-			 */
-			if (sample_delay_factor != 0)
-				sample_delay_factor--;
-			continue;
-		}
-
-		/*
-		 * If control arrives here, the quantized sample delay falls
-		 * before the eye opens. Shift the sample point by increasing
-		 * data setup time. This will also make the eye larger.
-		 */
-
-		/* Give a cycle to data setup. */
-		data_setup_in_cycles++;
-		/* Synchronize the data setup time with the cycles. */
-		data_setup_in_ns += clock_period_in_ns;
-		/* Adjust tEYE accordingly. */
-		tEYE += clock_period_in_ns;
-
-		/*
-		 * Decrease the ideal sample delay by one half cycle, to keep it
-		 * in the middle of the eye.
-		 */
-		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
-
-		/* ...and one less period for the delay time. */
-		ideal_sample_delay_in_ns -= clock_period_in_ns;
-
-		/* Jam a negative ideal sample delay to zero. */
-		if (ideal_sample_delay_in_ns < 0)
-			ideal_sample_delay_in_ns = 0;
-
-		/*
-		 * We have a new ideal sample delay, so re-compute the quantized
-		 * delay.
-		 */
-		sample_delay_factor =
-			ns_to_cycles(
-				ideal_sample_delay_in_ns << dll_delay_shift,
-							clock_period_in_ns, 0);
-
-		if (sample_delay_factor > nfc->max_sample_delay_factor)
-			sample_delay_factor = nfc->max_sample_delay_factor;
-	}
-
-	/* Control arrives here when we're ready to return our results. */
-return_results:
-	hw->data_setup_in_cycles    = data_setup_in_cycles;
-	hw->data_hold_in_cycles     = data_hold_in_cycles;
-	hw->address_setup_in_cycles = address_setup_in_cycles;
-	hw->use_half_periods        = dll_use_half_periods;
-	hw->sample_delay_factor     = sample_delay_factor;
-	hw->device_busy_timeout     = GPMI_DEFAULT_BUSY_TIMEOUT;
-	hw->wrn_dly_sel             = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
-
-	/* Return success. */
-	return 0;
-}
-
-/*
- * <1> Firstly, we should know what's the GPMI-clock means.
- *     The GPMI-clock is the internal clock in the gpmi nand controller.
- *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
- *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
- *
- * <2> Secondly, we should know what's the frequency on the nand chip pins.
- *     The frequency on the nand chip pins is derived from the GPMI-clock.
- *     We can get it from the following equation:
- *
- *         F = G / (DS + DH)
- *
- *         F  : the frequency on the nand chip pins.
- *         G  : the GPMI clock, such as 100MHz.
- *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
- *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
- *
- * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
- *     the nand EDO(extended Data Out) timing could be applied.
- *     The GPMI implements a feedback read strobe to sample the read data.
- *     The feedback read strobe can be delayed to support the nand EDO timing
- *     where the read strobe may deasserts before the read data is valid, and
- *     read data is valid for some time after read strobe.
- *
- *     The following figure illustrates some aspects of a NAND Flash read:
- *
- *                   |<---tREA---->|
- *                   |             |
- *                   |         |   |
- *                   |<--tRP-->|   |
- *                   |         |   |
- *                  __          ___|__________________________________
- *     RDN            \________/   |
- *                                 |
- *                                 /---------\
- *     Read Data    --------------<           >---------
- *                                 \---------/
- *                                |     |
- *                                |<-D->|
- *     FeedbackRDN  ________             ____________
- *                          \___________/
- *
- *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
- *
- *
- * <4> Now, we begin to describe how to compute the right RDN_DELAY.
- *
- *  4.1) From the aspect of the nand chip pins:
- *        Delay = (tREA + C - tRP)               {1}
- *
- *        tREA : the maximum read access time. From the ONFI nand standards,
- *               we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4.
- *               Please check it in : www.onfi.org
- *        C    : a constant for adjust the delay. default is 4.
- *        tRP  : the read pulse width.
- *               Specified by the HW_GPMI_TIMING0:DATA_SETUP:
- *                    tRP = (GPMI-clock-period) * DATA_SETUP
- *
- *  4.2) From the aspect of the GPMI nand controller:
- *         Delay = RDN_DELAY * 0.125 * RP        {2}
- *
- *         RP   : the DLL reference period.
- *            if (GPMI-clock-period > DLL_THRETHOLD)
- *                   RP = GPMI-clock-period / 2;
- *            else
- *                   RP = GPMI-clock-period;
- *
- *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
- *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
- *            is 16ns, but in mx6q, we use 12ns.
- *
- *  4.3) since {1} equals {2}, we get:
- *
- *                    (tREA + 4 - tRP) * 8
- *         RDN_DELAY = ---------------------     {3}
- *                           RP
- *
- *  4.4) We only support the fastest asynchronous mode of ONFI nand.
- *       For some ONFI nand, the mode 4 is the fastest mode;
- *       while for some ONFI nand, the mode 5 is the fastest mode.
- *       So we only support the mode 4 and mode 5. It is no need to
- *       support other modes.
- */
-static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
-			struct gpmi_nfc_hardware_timing *hw)
-{
-	struct resources *r = &this->resources;
-	unsigned long rate = clk_get_rate(r->clock[0]);
-	int mode = this->timing_mode;
-	int dll_threshold = this->devdata->max_chain_delay;
-	unsigned long delay;
-	unsigned long clk_period;
-	int t_rea;
-	int c = 4;
-	int t_rp;
-	int rp;
-
-	/*
-	 * [1] for GPMI_HW_GPMI_TIMING0:
-	 *     The async mode requires 40MHz for mode 4, 50MHz for mode 5.
-	 *     The GPMI can support 100MHz at most. So if we want to
-	 *     get the 40MHz or 50MHz, we have to set DS=1, DH=1.
-	 *     Set the ADDRESS_SETUP to 0 in mode 4.
-	 */
-	hw->data_setup_in_cycles = 1;
-	hw->data_hold_in_cycles = 1;
-	hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
-
-	/* [2] for GPMI_HW_GPMI_TIMING1 */
-	hw->device_busy_timeout = 0x9000;
-
-	/* [3] for GPMI_HW_GPMI_CTRL1 */
-	hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
-
-	/*
-	 * Enlarge 10 times for the numerator and denominator in {3}.
-	 * This make us to get more accurate result.
-	 */
-	clk_period = NSEC_PER_SEC / (rate / 10);
-	dll_threshold *= 10;
-	t_rea = ((mode == 5) ? 16 : 20) * 10;
-	c *= 10;
-
-	t_rp = clk_period * 1; /* DATA_SETUP is 1 */
-
-	if (clk_period > dll_threshold) {
-		hw->use_half_periods = 1;
-		rp = clk_period / 2;
-	} else {
-		hw->use_half_periods = 0;
-		rp = clk_period;
-	}
-
-	/*
-	 * Multiply the numerator with 10, we could do a round off:
-	 *      7.8 round up to 8; 7.4 round down to 7.
-	 */
-	delay  = (((t_rea + c - t_rp) * 8) * 10) / rp;
-	delay = (delay + 5) / 10;
-
-	hw->sample_delay_factor = delay;
-}
-
-static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
-{
-	struct resources  *r = &this->resources;
-	struct nand_chip *nand = &this->nand;
-	struct mtd_info	 *mtd = nand_to_mtd(nand);
-	uint8_t *feature;
-	unsigned long rate;
-	int ret;
-
-	feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
-	if (!feature)
-		return -ENOMEM;
-
-	nand->select_chip(mtd, 0);
-
-	/* [1] send SET FEATURE command to NAND */
-	feature[0] = mode;
-	ret = nand->onfi_set_features(mtd, nand,
-				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
-	if (ret)
-		goto err_out;
-
-	/* [2] send GET FEATURE command to double-check the timing mode */
-	memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
-	ret = nand->onfi_get_features(mtd, nand,
-				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
-	if (ret || feature[0] != mode)
-		goto err_out;
-
-	nand->select_chip(mtd, -1);
-
-	/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
-	rate = (mode == 5) ? 100000000 : 80000000;
-	clk_set_rate(r->clock[0], rate);
-
-	/* Let the gpmi_begin() re-compute the timing again. */
-	this->flags &= ~GPMI_TIMING_INIT_OK;
-
-	this->flags |= GPMI_ASYNC_EDO_ENABLED;
-	this->timing_mode = mode;
-	kfree(feature);
-	dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
-	return 0;
-
-err_out:
-	nand->select_chip(mtd, -1);
-	kfree(feature);
-	dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
-	return -EINVAL;
-}
-
-int gpmi_extra_init(struct gpmi_nand_data *this)
-{
-	struct nand_chip *chip = &this->nand;
-
-	/* Enable the asynchronous EDO feature. */
-	if (GPMI_IS_MX6(this) && chip->onfi_version) {
-		int mode = onfi_get_async_timing_mode(chip);
-
-		/* We only support the timing mode 4 and mode 5. */
-		if (mode & ONFI_TIMING_MODE_5)
-			mode = 5;
-		else if (mode & ONFI_TIMING_MODE_4)
-			mode = 4;
-		else
-			return 0;
-
-		return enable_edo_mode(this, mode);
-	}
-	return 0;
-}
-
-/* Begin the I/O */
-void gpmi_begin(struct gpmi_nand_data *this)
-{
-	struct resources *r = &this->resources;
-	void __iomem *gpmi_regs = r->gpmi_regs;
-	unsigned int   clock_period_in_ns;
-	uint32_t       reg;
-	unsigned int   dll_wait_time_in_us;
-	struct gpmi_nfc_hardware_timing  hw;
-	int ret;
-
-	/* Enable the clock. */
-	ret = gpmi_enable_clk(this);
-	if (ret) {
-		dev_err(this->dev, "We failed in enable the clk\n");
-		goto err_out;
-	}
-
-	/* Only initialize the timing once */
-	if (this->flags & GPMI_TIMING_INIT_OK)
-		return;
-	this->flags |= GPMI_TIMING_INIT_OK;
-
-	if (this->flags & GPMI_ASYNC_EDO_ENABLED)
-		gpmi_compute_edo_timing(this, &hw);
-	else
-		gpmi_nfc_compute_hardware_timing(this, &hw);
-
-	/* [1] Set HW_GPMI_TIMING0 */
-	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
-		BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         |
-		BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
-
-	writel(reg, gpmi_regs + HW_GPMI_TIMING0);
-
-	/* [2] Set HW_GPMI_TIMING1 */
-	writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
-		gpmi_regs + HW_GPMI_TIMING1);
-
-	/* [3] The following code is to set the HW_GPMI_CTRL1. */
-
-	/* Set the WRN_DLY_SEL */
-	writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
-	writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
-					gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	/* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
-	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
-
-	/* Clear out the DLL control fields. */
-	reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD;
-	writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
-
-	/* If no sample delay is called for, return immediately. */
-	if (!hw.sample_delay_factor)
-		return;
-
-	/* Set RDN_DELAY or HALF_PERIOD. */
-	reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
-		| BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
-
-	writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	/* At last, we enable the DLL. */
-	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET);
-
-	/*
-	 * After we enable the GPMI DLL, we have to wait 64 clock cycles before
-	 * we can use the GPMI. Calculate the amount of time we need to wait,
-	 * in microseconds.
-	 */
-	clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
-	dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
-
-	if (!dll_wait_time_in_us)
-		dll_wait_time_in_us = 1;
-
-	/* Wait for the DLL to settle. */
-	udelay(dll_wait_time_in_us);
-
-err_out:
-	return;
-}
-
-void gpmi_end(struct gpmi_nand_data *this)
-{
-	gpmi_disable_clk(this);
-}
-
-/* Clears a BCH interrupt. */
-void gpmi_clear_bch(struct gpmi_nand_data *this)
-{
-	struct resources *r = &this->resources;
-	writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
-}
-
-/* Returns the Ready/Busy status of the given chip. */
-int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
-{
-	struct resources *r = &this->resources;
-	uint32_t mask = 0;
-	uint32_t reg = 0;
-
-	if (GPMI_IS_MX23(this)) {
-		mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
-		reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
-	} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
-		/*
-		 * In the imx6, all the ready/busy pins are bound
-		 * together. So we only need to check chip 0.
-		 */
-		if (GPMI_IS_MX6(this))
-			chip = 0;
-
-		/* MX28 shares the same R/B register as MX6Q. */
-		mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
-		reg = readl(r->gpmi_regs + HW_GPMI_STAT);
-	} else
-		dev_err(this->dev, "unknown arch.\n");
-	return reg & mask;
-}
-
-static inline void set_dma_type(struct gpmi_nand_data *this,
-					enum dma_ops_type type)
-{
-	this->last_dma_type = this->dma_type;
-	this->dma_type = type;
-}
-
-int gpmi_send_command(struct gpmi_nand_data *this)
-{
-	struct dma_chan *channel = get_dma_chan(this);
-	struct dma_async_tx_descriptor *desc;
-	struct scatterlist *sgl;
-	int chip = this->current_chip;
-	u32 pio[3];
-
-	/* [1] send out the PIO words */
-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
-		| BM_GPMI_CTRL0_ADDRESS_INCREMENT
-		| BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
-	pio[1] = pio[2] = 0;
-	desc = dmaengine_prep_slave_sg(channel,
-					(struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-	if (!desc)
-		return -EINVAL;
-
-	/* [2] send out the COMMAND + ADDRESS string stored in @buffer */
-	sgl = &this->cmd_sgl;
-
-	sg_init_one(sgl, this->cmd_buffer, this->command_length);
-	dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
-	desc = dmaengine_prep_slave_sg(channel,
-				sgl, 1, DMA_MEM_TO_DEV,
-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc)
-		return -EINVAL;
-
-	/* [3] submit the DMA */
-	set_dma_type(this, DMA_FOR_COMMAND);
-	return start_dma_without_bch_irq(this, desc);
-}
-
-int gpmi_send_data(struct gpmi_nand_data *this)
-{
-	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *channel = get_dma_chan(this);
-	int chip = this->current_chip;
-	uint32_t command_mode;
-	uint32_t address;
-	u32 pio[2];
-
-	/* [1] PIO */
-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(address)
-		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
-	pio[1] = 0;
-	desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-	if (!desc)
-		return -EINVAL;
-
-	/* [2] send DMA request */
-	prepare_data_dma(this, DMA_TO_DEVICE);
-	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
-					1, DMA_MEM_TO_DEV,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc)
-		return -EINVAL;
-
-	/* [3] submit the DMA */
-	set_dma_type(this, DMA_FOR_WRITE_DATA);
-	return start_dma_without_bch_irq(this, desc);
-}
-
-int gpmi_read_data(struct gpmi_nand_data *this)
-{
-	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *channel = get_dma_chan(this);
-	int chip = this->current_chip;
-	u32 pio[2];
-
-	/* [1] : send PIO */
-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
-		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
-	pio[1] = 0;
-	desc = dmaengine_prep_slave_sg(channel,
-					(struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-	if (!desc)
-		return -EINVAL;
-
-	/* [2] : send DMA request */
-	prepare_data_dma(this, DMA_FROM_DEVICE);
-	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
-					1, DMA_DEV_TO_MEM,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc)
-		return -EINVAL;
-
-	/* [3] : submit the DMA */
-	set_dma_type(this, DMA_FOR_READ_DATA);
-	return start_dma_without_bch_irq(this, desc);
-}
-
-int gpmi_send_page(struct gpmi_nand_data *this,
-			dma_addr_t payload, dma_addr_t auxiliary)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-	uint32_t command_mode;
-	uint32_t address;
-	uint32_t ecc_command;
-	uint32_t buffer_mask;
-	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *channel = get_dma_chan(this);
-	int chip = this->current_chip;
-	u32 pio[6];
-
-	/* A DMA descriptor that does an ECC page read. */
-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
-	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
-				BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
-
-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(address)
-		| BF_GPMI_CTRL0_XFER_COUNT(0);
-	pio[1] = 0;
-	pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
-		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
-		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
-	pio[3] = geo->page_size;
-	pio[4] = payload;
-	pio[5] = auxiliary;
-
-	desc = dmaengine_prep_slave_sg(channel,
-					(struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE,
-					DMA_CTRL_ACK);
-	if (!desc)
-		return -EINVAL;
-
-	set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
-	return start_dma_with_bch_irq(this, desc);
-}
-
-int gpmi_read_page(struct gpmi_nand_data *this,
-				dma_addr_t payload, dma_addr_t auxiliary)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-	uint32_t command_mode;
-	uint32_t address;
-	uint32_t ecc_command;
-	uint32_t buffer_mask;
-	struct dma_async_tx_descriptor *desc;
-	struct dma_chan *channel = get_dma_chan(this);
-	int chip = this->current_chip;
-	u32 pio[6];
-
-	/* [1] Wait for the chip to report ready. */
-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
-	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(address)
-		| BF_GPMI_CTRL0_XFER_COUNT(0);
-	pio[1] = 0;
-	desc = dmaengine_prep_slave_sg(channel,
-				(struct scatterlist *)pio, 2,
-				DMA_TRANS_NONE, 0);
-	if (!desc)
-		return -EINVAL;
-
-	/* [2] Enable the BCH block and read. */
-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
-	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
-			| BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
-
-	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(address)
-		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
-
-	pio[1] = 0;
-	pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC
-		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
-		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
-	pio[3] = geo->page_size;
-	pio[4] = payload;
-	pio[5] = auxiliary;
-	desc = dmaengine_prep_slave_sg(channel,
-					(struct scatterlist *)pio,
-					ARRAY_SIZE(pio), DMA_TRANS_NONE,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc)
-		return -EINVAL;
-
-	/* [3] Disable the BCH block */
-	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
-	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
-
-	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
-		| BM_GPMI_CTRL0_WORD_LENGTH
-		| BF_GPMI_CTRL0_CS(chip, this)
-		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
-		| BF_GPMI_CTRL0_ADDRESS(address)
-		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
-	pio[1] = 0;
-	pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
-	desc = dmaengine_prep_slave_sg(channel,
-				(struct scatterlist *)pio, 3,
-				DMA_TRANS_NONE,
-				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc)
-		return -EINVAL;
-
-	/* [4] submit the DMA */
-	set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
-	return start_dma_with_bch_irq(this, desc);
-}
-
-/**
- * gpmi_copy_bits - copy bits from one memory region to another
- * @dst: destination buffer
- * @dst_bit_off: bit offset we're starting to write at
- * @src: source buffer
- * @src_bit_off: bit offset we're starting to read from
- * @nbits: number of bits to copy
- *
- * This functions copies bits from one memory region to another, and is used by
- * the GPMI driver to copy ECC sections which are not guaranteed to be byte
- * aligned.
- *
- * src and dst should not overlap.
- *
- */
-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
-		    const u8 *src, size_t src_bit_off,
-		    size_t nbits)
-{
-	size_t i;
-	size_t nbytes;
-	u32 src_buffer = 0;
-	size_t bits_in_src_buffer = 0;
-
-	if (!nbits)
-		return;
-
-	/*
-	 * Move src and dst pointers to the closest byte pointer and store bit
-	 * offsets within a byte.
-	 */
-	src += src_bit_off / 8;
-	src_bit_off %= 8;
-
-	dst += dst_bit_off / 8;
-	dst_bit_off %= 8;
-
-	/*
-	 * Initialize the src_buffer value with bits available in the first
-	 * byte of data so that we end up with a byte aligned src pointer.
-	 */
-	if (src_bit_off) {
-		src_buffer = src[0] >> src_bit_off;
-		if (nbits >= (8 - src_bit_off)) {
-			bits_in_src_buffer += 8 - src_bit_off;
-		} else {
-			src_buffer &= GENMASK(nbits - 1, 0);
-			bits_in_src_buffer += nbits;
-		}
-		nbits -= bits_in_src_buffer;
-		src++;
-	}
-
-	/* Calculate the number of bytes that can be copied from src to dst. */
-	nbytes = nbits / 8;
-
-	/* Try to align dst to a byte boundary. */
-	if (dst_bit_off) {
-		if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
-			src_buffer |= src[0] << bits_in_src_buffer;
-			bits_in_src_buffer += 8;
-			src++;
-			nbytes--;
-		}
-
-		if (bits_in_src_buffer >= (8 - dst_bit_off)) {
-			dst[0] &= GENMASK(dst_bit_off - 1, 0);
-			dst[0] |= src_buffer << dst_bit_off;
-			src_buffer >>= (8 - dst_bit_off);
-			bits_in_src_buffer -= (8 - dst_bit_off);
-			dst_bit_off = 0;
-			dst++;
-			if (bits_in_src_buffer > 7) {
-				bits_in_src_buffer -= 8;
-				dst[0] = src_buffer;
-				dst++;
-				src_buffer >>= 8;
-			}
-		}
-	}
-
-	if (!bits_in_src_buffer && !dst_bit_off) {
-		/*
-		 * Both src and dst pointers are byte aligned, thus we can
-		 * just use the optimized memcpy function.
-		 */
-		if (nbytes)
-			memcpy(dst, src, nbytes);
-	} else {
-		/*
-		 * src buffer is not byte aligned, hence we have to copy each
-		 * src byte to the src_buffer variable before extracting a byte
-		 * to store in dst.
-		 */
-		for (i = 0; i < nbytes; i++) {
-			src_buffer |= src[i] << bits_in_src_buffer;
-			dst[i] = src_buffer;
-			src_buffer >>= 8;
-		}
-	}
-	/* Update dst and src pointers */
-	dst += nbytes;
-	src += nbytes;
-
-	/*
-	 * nbits is the number of remaining bits. It should not exceed 8 as
-	 * we've already copied as much bytes as possible.
-	 */
-	nbits %= 8;
-
-	/*
-	 * If there's no more bits to copy to the destination and src buffer
-	 * was already byte aligned, then we're done.
-	 */
-	if (!nbits && !bits_in_src_buffer)
-		return;
-
-	/* Copy the remaining bits to src_buffer */
-	if (nbits)
-		src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
-			      bits_in_src_buffer;
-	bits_in_src_buffer += nbits;
-
-	/*
-	 * In case there were not enough bits to get a byte aligned dst buffer
-	 * prepare the src_buffer variable to match the dst organization (shift
-	 * src_buffer by dst_bit_off and retrieve the least significant bits
-	 * from dst).
-	 */
-	if (dst_bit_off)
-		src_buffer = (src_buffer << dst_bit_off) |
-			     (*dst & GENMASK(dst_bit_off - 1, 0));
-	bits_in_src_buffer += dst_bit_off;
-
-	/*
-	 * Keep most significant bits from dst if we end up with an unaligned
-	 * number of bits.
-	 */
-	nbytes = bits_in_src_buffer / 8;
-	if (bits_in_src_buffer % 8) {
-		src_buffer |= (dst[nbytes] &
-			       GENMASK(7, bits_in_src_buffer % 8)) <<
-			      (nbytes * 8);
-		nbytes++;
-	}
-
-	/* Copy the remaining bytes to dst */
-	for (i = 0; i < nbytes; i++) {
-		dst[i] = src_buffer;
-		src_buffer >>= 8;
-	}
-}
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
deleted file mode 100644
index 61fdd733492f..000000000000
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ /dev/null
@@ -1,2182 +0,0 @@
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/sched/task_stack.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include "gpmi-nand.h"
-#include "bch-regs.h"
-
-/* Resource names for the GPMI NAND driver. */
-#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
-#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
-#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
-
-/* add our owner bbt descriptor */
-static uint8_t scan_ff_pattern[] = { 0xff };
-static struct nand_bbt_descr gpmi_bbt_descr = {
-	.options	= 0,
-	.offs		= 0,
-	.len		= 1,
-	.pattern	= scan_ff_pattern
-};
-
-/*
- * We may change the layout if we can get the ECC info from the datasheet,
- * else we will use all the (page + OOB).
- */
-static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
-			      struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	struct bch_geometry *geo = &this->bch_geometry;
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 0;
-	oobregion->length = geo->page_size - mtd->writesize;
-
-	return 0;
-}
-
-static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
-			       struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	struct bch_geometry *geo = &this->bch_geometry;
-
-	if (section)
-		return -ERANGE;
-
-	/* The available oob size we have. */
-	if (geo->page_size < mtd->writesize + mtd->oobsize) {
-		oobregion->offset = geo->page_size - mtd->writesize;
-		oobregion->length = mtd->oobsize - oobregion->offset;
-	}
-
-	return 0;
-}
-
-static const char * const gpmi_clks_for_mx2x[] = {
-	"gpmi_io",
-};
-
-static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
-	.ecc = gpmi_ooblayout_ecc,
-	.free = gpmi_ooblayout_free,
-};
-
-static const struct gpmi_devdata gpmi_devdata_imx23 = {
-	.type = IS_MX23,
-	.bch_max_ecc_strength = 20,
-	.max_chain_delay = 16,
-	.clks = gpmi_clks_for_mx2x,
-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
-};
-
-static const struct gpmi_devdata gpmi_devdata_imx28 = {
-	.type = IS_MX28,
-	.bch_max_ecc_strength = 20,
-	.max_chain_delay = 16,
-	.clks = gpmi_clks_for_mx2x,
-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
-};
-
-static const char * const gpmi_clks_for_mx6[] = {
-	"gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
-};
-
-static const struct gpmi_devdata gpmi_devdata_imx6q = {
-	.type = IS_MX6Q,
-	.bch_max_ecc_strength = 40,
-	.max_chain_delay = 12,
-	.clks = gpmi_clks_for_mx6,
-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
-};
-
-static const struct gpmi_devdata gpmi_devdata_imx6sx = {
-	.type = IS_MX6SX,
-	.bch_max_ecc_strength = 62,
-	.max_chain_delay = 12,
-	.clks = gpmi_clks_for_mx6,
-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
-};
-
-static const char * const gpmi_clks_for_mx7d[] = {
-	"gpmi_io", "gpmi_bch_apb",
-};
-
-static const struct gpmi_devdata gpmi_devdata_imx7d = {
-	.type = IS_MX7D,
-	.bch_max_ecc_strength = 62,
-	.max_chain_delay = 12,
-	.clks = gpmi_clks_for_mx7d,
-	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
-};
-
-static irqreturn_t bch_irq(int irq, void *cookie)
-{
-	struct gpmi_nand_data *this = cookie;
-
-	gpmi_clear_bch(this);
-	complete(&this->bch_done);
-	return IRQ_HANDLED;
-}
-
-/*
- *  Calculate the ECC strength by hand:
- *	E : The ECC strength.
- *	G : the length of Galois Field.
- *	N : The chunk count of per page.
- *	O : the oobsize of the NAND chip.
- *	M : the metasize of per page.
- *
- *	The formula is :
- *		E * G * N
- *	      ------------ <= (O - M)
- *                  8
- *
- *      So, we get E by:
- *                    (O - M) * 8
- *              E <= -------------
- *                       G * N
- */
-static inline int get_ecc_strength(struct gpmi_nand_data *this)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-	struct mtd_info	*mtd = nand_to_mtd(&this->nand);
-	int ecc_strength;
-
-	ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
-			/ (geo->gf_len * geo->ecc_chunk_count);
-
-	/* We need the minor even number. */
-	return round_down(ecc_strength, 2);
-}
-
-static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-
-	/* Do the sanity check. */
-	if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
-		/* The mx23/mx28 only support the GF13. */
-		if (geo->gf_len == 14)
-			return false;
-	}
-	return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
-}
-
-/*
- * If we can get the ECC information from the nand chip, we do not
- * need to calculate them ourselves.
- *
- * We may have available oob space in this case.
- */
-static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int block_mark_bit_offset;
-
-	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
-		return -EINVAL;
-
-	switch (chip->ecc_step_ds) {
-	case SZ_512:
-		geo->gf_len = 13;
-		break;
-	case SZ_1K:
-		geo->gf_len = 14;
-		break;
-	default:
-		dev_err(this->dev,
-			"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
-			chip->ecc_strength_ds, chip->ecc_step_ds);
-		return -EINVAL;
-	}
-	geo->ecc_chunk_size = chip->ecc_step_ds;
-	geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
-	if (!gpmi_check_ecc(this))
-		return -EINVAL;
-
-	/* Keep the C >= O */
-	if (geo->ecc_chunk_size < mtd->oobsize) {
-		dev_err(this->dev,
-			"unsupported nand chip. ecc size: %d, oob size : %d\n",
-			chip->ecc_step_ds, mtd->oobsize);
-		return -EINVAL;
-	}
-
-	/* The default value, see comment in the legacy_set_geometry(). */
-	geo->metadata_size = 10;
-
-	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
-
-	/*
-	 * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
-	 *
-	 *    |                          P                            |
-	 *    |<----------------------------------------------------->|
-	 *    |                                                       |
-	 *    |                                        (Block Mark)   |
-	 *    |                      P'                      |      | |     |
-	 *    |<-------------------------------------------->|  D   | |  O' |
-	 *    |                                              |<---->| |<--->|
-	 *    V                                              V      V V     V
-	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
-	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|     |
-	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
-	 *                                                   ^              ^
-	 *                                                   |      O       |
-	 *                                                   |<------------>|
-	 *                                                   |              |
-	 *
-	 *	P : the page size for BCH module.
-	 *	E : The ECC strength.
-	 *	G : the length of Galois Field.
-	 *	N : The chunk count of per page.
-	 *	M : the metasize of per page.
-	 *	C : the ecc chunk size, aka the "data" above.
-	 *	P': the nand chip's page size.
-	 *	O : the nand chip's oob size.
-	 *	O': the free oob.
-	 *
-	 *	The formula for P is :
-	 *
-	 *	            E * G * N
-	 *	       P = ------------ + P' + M
-	 *                      8
-	 *
-	 * The position of block mark moves forward in the ECC-based view
-	 * of page, and the delta is:
-	 *
-	 *                   E * G * (N - 1)
-	 *             D = (---------------- + M)
-	 *                          8
-	 *
-	 * Please see the comment in legacy_set_geometry().
-	 * With the condition C >= O , we still can get same result.
-	 * So the bit position of the physical block mark within the ECC-based
-	 * view of the page is :
-	 *             (P' - D) * 8
-	 */
-	geo->page_size = mtd->writesize + geo->metadata_size +
-		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
-
-	geo->payload_size = mtd->writesize;
-
-	geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
-	geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
-				+ ALIGN(geo->ecc_chunk_count, 4);
-
-	if (!this->swap_block_mark)
-		return 0;
-
-	/* For bit swap. */
-	block_mark_bit_offset = mtd->writesize * 8 -
-		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
-				+ geo->metadata_size * 8);
-
-	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
-	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
-	return 0;
-}
-
-static int legacy_set_geometry(struct gpmi_nand_data *this)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-	struct mtd_info *mtd = nand_to_mtd(&this->nand);
-	unsigned int metadata_size;
-	unsigned int status_size;
-	unsigned int block_mark_bit_offset;
-
-	/*
-	 * The size of the metadata can be changed, though we set it to 10
-	 * bytes now. But it can't be too large, because we have to save
-	 * enough space for BCH.
-	 */
-	geo->metadata_size = 10;
-
-	/* The default for the length of Galois Field. */
-	geo->gf_len = 13;
-
-	/* The default for chunk size. */
-	geo->ecc_chunk_size = 512;
-	while (geo->ecc_chunk_size < mtd->oobsize) {
-		geo->ecc_chunk_size *= 2; /* keep C >= O */
-		geo->gf_len = 14;
-	}
-
-	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
-
-	/* We use the same ECC strength for all chunks. */
-	geo->ecc_strength = get_ecc_strength(this);
-	if (!gpmi_check_ecc(this)) {
-		dev_err(this->dev,
-			"ecc strength: %d cannot be supported by the controller (%d)\n"
-			"try to use minimum ecc strength that NAND chip required\n",
-			geo->ecc_strength,
-			this->devdata->bch_max_ecc_strength);
-		return -EINVAL;
-	}
-
-	geo->page_size = mtd->writesize + geo->metadata_size +
-		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
-	geo->payload_size = mtd->writesize;
-
-	/*
-	 * The auxiliary buffer contains the metadata and the ECC status. The
-	 * metadata is padded to the nearest 32-bit boundary. The ECC status
-	 * contains one byte for every ECC chunk, and is also padded to the
-	 * nearest 32-bit boundary.
-	 */
-	metadata_size = ALIGN(geo->metadata_size, 4);
-	status_size   = ALIGN(geo->ecc_chunk_count, 4);
-
-	geo->auxiliary_size = metadata_size + status_size;
-	geo->auxiliary_status_offset = metadata_size;
-
-	if (!this->swap_block_mark)
-		return 0;
-
-	/*
-	 * We need to compute the byte and bit offsets of
-	 * the physical block mark within the ECC-based view of the page.
-	 *
-	 * NAND chip with 2K page shows below:
-	 *                                             (Block Mark)
-	 *                                                   |      |
-	 *                                                   |  D   |
-	 *                                                   |<---->|
-	 *                                                   V      V
-	 *    +---+----------+-+----------+-+----------+-+----------+-+
-	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|
-	 *    +---+----------+-+----------+-+----------+-+----------+-+
-	 *
-	 * The position of block mark moves forward in the ECC-based view
-	 * of page, and the delta is:
-	 *
-	 *                   E * G * (N - 1)
-	 *             D = (---------------- + M)
-	 *                          8
-	 *
-	 * With the formula to compute the ECC strength, and the condition
-	 *       : C >= O         (C is the ecc chunk size)
-	 *
-	 * It's easy to deduce to the following result:
-	 *
-	 *         E * G       (O - M)      C - M         C - M
-	 *      ----------- <= ------- <=  --------  <  ---------
-	 *           8            N           N          (N - 1)
-	 *
-	 *  So, we get:
-	 *
-	 *                   E * G * (N - 1)
-	 *             D = (---------------- + M) < C
-	 *                          8
-	 *
-	 *  The above inequality means the position of block mark
-	 *  within the ECC-based view of the page is still in the data chunk,
-	 *  and it's NOT in the ECC bits of the chunk.
-	 *
-	 *  Use the following to compute the bit position of the
-	 *  physical block mark within the ECC-based view of the page:
-	 *          (page_size - D) * 8
-	 *
-	 *  --Huang Shijie
-	 */
-	block_mark_bit_offset = mtd->writesize * 8 -
-		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
-				+ geo->metadata_size * 8);
-
-	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
-	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
-	return 0;
-}
-
-int common_nfc_set_geometry(struct gpmi_nand_data *this)
-{
-	if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
-				|| legacy_set_geometry(this))
-		return set_geometry_by_ecc_info(this);
-
-	return 0;
-}
-
-struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
-{
-	/* We use the DMA channel 0 to access all the nand chips. */
-	return this->dma_chans[0];
-}
-
-/* Can we use the upper's buffer directly for DMA? */
-void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
-{
-	struct scatterlist *sgl = &this->data_sgl;
-	int ret;
-
-	/* first try to map the upper buffer directly */
-	if (virt_addr_valid(this->upper_buf) &&
-		!object_is_on_stack(this->upper_buf)) {
-		sg_init_one(sgl, this->upper_buf, this->upper_len);
-		ret = dma_map_sg(this->dev, sgl, 1, dr);
-		if (ret == 0)
-			goto map_fail;
-
-		this->direct_dma_map_ok = true;
-		return;
-	}
-
-map_fail:
-	/* We have to use our own DMA buffer. */
-	sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
-
-	if (dr == DMA_TO_DEVICE)
-		memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
-
-	dma_map_sg(this->dev, sgl, 1, dr);
-
-	this->direct_dma_map_ok = false;
-}
-
-/* This will be called after the DMA operation is finished. */
-static void dma_irq_callback(void *param)
-{
-	struct gpmi_nand_data *this = param;
-	struct completion *dma_c = &this->dma_done;
-
-	switch (this->dma_type) {
-	case DMA_FOR_COMMAND:
-		dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
-		break;
-
-	case DMA_FOR_READ_DATA:
-		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE);
-		if (this->direct_dma_map_ok == false)
-			memcpy(this->upper_buf, this->data_buffer_dma,
-				this->upper_len);
-		break;
-
-	case DMA_FOR_WRITE_DATA:
-		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE);
-		break;
-
-	case DMA_FOR_READ_ECC_PAGE:
-	case DMA_FOR_WRITE_ECC_PAGE:
-		/* We have to wait the BCH interrupt to finish. */
-		break;
-
-	default:
-		dev_err(this->dev, "in wrong DMA operation.\n");
-	}
-
-	complete(dma_c);
-}
-
-int start_dma_without_bch_irq(struct gpmi_nand_data *this,
-				struct dma_async_tx_descriptor *desc)
-{
-	struct completion *dma_c = &this->dma_done;
-	unsigned long timeout;
-
-	init_completion(dma_c);
-
-	desc->callback		= dma_irq_callback;
-	desc->callback_param	= this;
-	dmaengine_submit(desc);
-	dma_async_issue_pending(get_dma_chan(this));
-
-	/* Wait for the interrupt from the DMA block. */
-	timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
-	if (!timeout) {
-		dev_err(this->dev, "DMA timeout, last DMA :%d\n",
-			this->last_dma_type);
-		gpmi_dump_info(this);
-		return -ETIMEDOUT;
-	}
-	return 0;
-}
-
-/*
- * This function is used in BCH reading or BCH writing pages.
- * It will wait for the BCH interrupt as long as ONE second.
- * Actually, we must wait for two interrupts :
- *	[1] firstly the DMA interrupt and
- *	[2] secondly the BCH interrupt.
- */
-int start_dma_with_bch_irq(struct gpmi_nand_data *this,
-			struct dma_async_tx_descriptor *desc)
-{
-	struct completion *bch_c = &this->bch_done;
-	unsigned long timeout;
-
-	/* Prepare to receive an interrupt from the BCH block. */
-	init_completion(bch_c);
-
-	/* start the DMA */
-	start_dma_without_bch_irq(this, desc);
-
-	/* Wait for the interrupt from the BCH block. */
-	timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
-	if (!timeout) {
-		dev_err(this->dev, "BCH timeout, last DMA :%d\n",
-			this->last_dma_type);
-		gpmi_dump_info(this);
-		return -ETIMEDOUT;
-	}
-	return 0;
-}
-
-static int acquire_register_block(struct gpmi_nand_data *this,
-				  const char *res_name)
-{
-	struct platform_device *pdev = this->pdev;
-	struct resources *res = &this->resources;
-	struct resource *r;
-	void __iomem *p;
-
-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
-	p = devm_ioremap_resource(&pdev->dev, r);
-	if (IS_ERR(p))
-		return PTR_ERR(p);
-
-	if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
-		res->gpmi_regs = p;
-	else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
-		res->bch_regs = p;
-	else
-		dev_err(this->dev, "unknown resource name : %s\n", res_name);
-
-	return 0;
-}
-
-static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
-{
-	struct platform_device *pdev = this->pdev;
-	const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
-	struct resource *r;
-	int err;
-
-	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
-	if (!r) {
-		dev_err(this->dev, "Can't get resource for %s\n", res_name);
-		return -ENODEV;
-	}
-
-	err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
-	if (err)
-		dev_err(this->dev, "error requesting BCH IRQ\n");
-
-	return err;
-}
-
-static void release_dma_channels(struct gpmi_nand_data *this)
-{
-	unsigned int i;
-	for (i = 0; i < DMA_CHANS; i++)
-		if (this->dma_chans[i]) {
-			dma_release_channel(this->dma_chans[i]);
-			this->dma_chans[i] = NULL;
-		}
-}
-
-static int acquire_dma_channels(struct gpmi_nand_data *this)
-{
-	struct platform_device *pdev = this->pdev;
-	struct dma_chan *dma_chan;
-
-	/* request dma channel */
-	dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
-	if (!dma_chan) {
-		dev_err(this->dev, "Failed to request DMA channel.\n");
-		goto acquire_err;
-	}
-
-	this->dma_chans[0] = dma_chan;
-	return 0;
-
-acquire_err:
-	release_dma_channels(this);
-	return -EINVAL;
-}
-
-static int gpmi_get_clks(struct gpmi_nand_data *this)
-{
-	struct resources *r = &this->resources;
-	struct clk *clk;
-	int err, i;
-
-	for (i = 0; i < this->devdata->clks_count; i++) {
-		clk = devm_clk_get(this->dev, this->devdata->clks[i]);
-		if (IS_ERR(clk)) {
-			err = PTR_ERR(clk);
-			goto err_clock;
-		}
-
-		r->clock[i] = clk;
-	}
-
-	if (GPMI_IS_MX6(this))
-		/*
-		 * Set the default value for the gpmi clock.
-		 *
-		 * If you want to use the ONFI nand which is in the
-		 * Synchronous Mode, you should change the clock as you need.
-		 */
-		clk_set_rate(r->clock[0], 22000000);
-
-	return 0;
-
-err_clock:
-	dev_dbg(this->dev, "failed in finding the clocks.\n");
-	return err;
-}
-
-static int acquire_resources(struct gpmi_nand_data *this)
-{
-	int ret;
-
-	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
-	if (ret)
-		goto exit_regs;
-
-	ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME);
-	if (ret)
-		goto exit_regs;
-
-	ret = acquire_bch_irq(this, bch_irq);
-	if (ret)
-		goto exit_regs;
-
-	ret = acquire_dma_channels(this);
-	if (ret)
-		goto exit_regs;
-
-	ret = gpmi_get_clks(this);
-	if (ret)
-		goto exit_clock;
-	return 0;
-
-exit_clock:
-	release_dma_channels(this);
-exit_regs:
-	return ret;
-}
-
-static void release_resources(struct gpmi_nand_data *this)
-{
-	release_dma_channels(this);
-}
-
-static int init_hardware(struct gpmi_nand_data *this)
-{
-	int ret;
-
-	/*
-	 * This structure contains the "safe" GPMI timing that should succeed
-	 * with any NAND Flash device
-	 * (although, with less-than-optimal performance).
-	 */
-	struct nand_timing  safe_timing = {
-		.data_setup_in_ns        = 80,
-		.data_hold_in_ns         = 60,
-		.address_setup_in_ns     = 25,
-		.gpmi_sample_delay_in_ns =  6,
-		.tREA_in_ns              = -1,
-		.tRLOH_in_ns             = -1,
-		.tRHOH_in_ns             = -1,
-	};
-
-	/* Initialize the hardwares. */
-	ret = gpmi_init(this);
-	if (ret)
-		return ret;
-
-	this->timing = safe_timing;
-	return 0;
-}
-
-static int read_page_prepare(struct gpmi_nand_data *this,
-			void *destination, unsigned length,
-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-			void **use_virt, dma_addr_t *use_phys)
-{
-	struct device *dev = this->dev;
-
-	if (virt_addr_valid(destination)) {
-		dma_addr_t dest_phys;
-
-		dest_phys = dma_map_single(dev, destination,
-						length, DMA_FROM_DEVICE);
-		if (dma_mapping_error(dev, dest_phys)) {
-			if (alt_size < length) {
-				dev_err(dev, "Alternate buffer is too small\n");
-				return -ENOMEM;
-			}
-			goto map_failed;
-		}
-		*use_virt = destination;
-		*use_phys = dest_phys;
-		this->direct_dma_map_ok = true;
-		return 0;
-	}
-
-map_failed:
-	*use_virt = alt_virt;
-	*use_phys = alt_phys;
-	this->direct_dma_map_ok = false;
-	return 0;
-}
-
-static inline void read_page_end(struct gpmi_nand_data *this,
-			void *destination, unsigned length,
-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-			void *used_virt, dma_addr_t used_phys)
-{
-	if (this->direct_dma_map_ok)
-		dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE);
-}
-
-static inline void read_page_swap_end(struct gpmi_nand_data *this,
-			void *destination, unsigned length,
-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-			void *used_virt, dma_addr_t used_phys)
-{
-	if (!this->direct_dma_map_ok)
-		memcpy(destination, alt_virt, length);
-}
-
-static int send_page_prepare(struct gpmi_nand_data *this,
-			const void *source, unsigned length,
-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-			const void **use_virt, dma_addr_t *use_phys)
-{
-	struct device *dev = this->dev;
-
-	if (virt_addr_valid(source)) {
-		dma_addr_t source_phys;
-
-		source_phys = dma_map_single(dev, (void *)source, length,
-						DMA_TO_DEVICE);
-		if (dma_mapping_error(dev, source_phys)) {
-			if (alt_size < length) {
-				dev_err(dev, "Alternate buffer is too small\n");
-				return -ENOMEM;
-			}
-			goto map_failed;
-		}
-		*use_virt = source;
-		*use_phys = source_phys;
-		return 0;
-	}
-map_failed:
-	/*
-	 * Copy the content of the source buffer into the alternate
-	 * buffer and set up the return values accordingly.
-	 */
-	memcpy(alt_virt, source, length);
-
-	*use_virt = alt_virt;
-	*use_phys = alt_phys;
-	return 0;
-}
-
-static void send_page_end(struct gpmi_nand_data *this,
-			const void *source, unsigned length,
-			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
-			const void *used_virt, dma_addr_t used_phys)
-{
-	struct device *dev = this->dev;
-	if (used_virt == source)
-		dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
-}
-
-static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
-{
-	struct device *dev = this->dev;
-
-	if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt))
-		dma_free_coherent(dev, this->page_buffer_size,
-					this->page_buffer_virt,
-					this->page_buffer_phys);
-	kfree(this->cmd_buffer);
-	kfree(this->data_buffer_dma);
-	kfree(this->raw_buffer);
-
-	this->cmd_buffer	= NULL;
-	this->data_buffer_dma	= NULL;
-	this->raw_buffer	= NULL;
-	this->page_buffer_virt	= NULL;
-	this->page_buffer_size	=  0;
-}
-
-/* Allocate the DMA buffers */
-static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
-{
-	struct bch_geometry *geo = &this->bch_geometry;
-	struct device *dev = this->dev;
-	struct mtd_info *mtd = nand_to_mtd(&this->nand);
-
-	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
-	this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
-	if (this->cmd_buffer == NULL)
-		goto error_alloc;
-
-	/*
-	 * [2] Allocate a read/write data buffer.
-	 *     The gpmi_alloc_dma_buffer can be called twice.
-	 *     We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
-	 *     is called before the nand_scan_ident; and we allocate a buffer
-	 *     of the real NAND page size when the gpmi_alloc_dma_buffer is
-	 *     called after the nand_scan_ident.
-	 */
-	this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
-					GFP_DMA | GFP_KERNEL);
-	if (this->data_buffer_dma == NULL)
-		goto error_alloc;
-
-	/*
-	 * [3] Allocate the page buffer.
-	 *
-	 * Both the payload buffer and the auxiliary buffer must appear on
-	 * 32-bit boundaries. We presume the size of the payload buffer is a
-	 * power of two and is much larger than four, which guarantees the
-	 * auxiliary buffer will appear on a 32-bit boundary.
-	 */
-	this->page_buffer_size = geo->payload_size + geo->auxiliary_size;
-	this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size,
-					&this->page_buffer_phys, GFP_DMA);
-	if (!this->page_buffer_virt)
-		goto error_alloc;
-
-	this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
-	if (!this->raw_buffer)
-		goto error_alloc;
-
-	/* Slice up the page buffer. */
-	this->payload_virt = this->page_buffer_virt;
-	this->payload_phys = this->page_buffer_phys;
-	this->auxiliary_virt = this->payload_virt + geo->payload_size;
-	this->auxiliary_phys = this->payload_phys + geo->payload_size;
-	return 0;
-
-error_alloc:
-	gpmi_free_dma_buffer(this);
-	return -ENOMEM;
-}
-
-static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	int ret;
-
-	/*
-	 * Every operation begins with a command byte and a series of zero or
-	 * more address bytes. These are distinguished by either the Address
-	 * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
-	 * asserted. When MTD is ready to execute the command, it will deassert
-	 * both latch enables.
-	 *
-	 * Rather than run a separate DMA operation for every single byte, we
-	 * queue them up and run a single DMA operation for the entire series
-	 * of command and data bytes. NAND_CMD_NONE means the END of the queue.
-	 */
-	if ((ctrl & (NAND_ALE | NAND_CLE))) {
-		if (data != NAND_CMD_NONE)
-			this->cmd_buffer[this->command_length++] = data;
-		return;
-	}
-
-	if (!this->command_length)
-		return;
-
-	ret = gpmi_send_command(this);
-	if (ret)
-		dev_err(this->dev, "Chip: %u, Error %d\n",
-			this->current_chip, ret);
-
-	this->command_length = 0;
-}
-
-static int gpmi_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-	return gpmi_is_ready(this, this->current_chip);
-}
-
-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-	if ((this->current_chip < 0) && (chipnr >= 0))
-		gpmi_begin(this);
-	else if ((this->current_chip >= 0) && (chipnr < 0))
-		gpmi_end(this);
-
-	this->current_chip = chipnr;
-}
-
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-	dev_dbg(this->dev, "len is %d\n", len);
-	this->upper_buf	= buf;
-	this->upper_len	= len;
-
-	gpmi_read_data(this);
-}
-
-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-	dev_dbg(this->dev, "len is %d\n", len);
-	this->upper_buf	= (uint8_t *)buf;
-	this->upper_len	= len;
-
-	gpmi_send_data(this);
-}
-
-static uint8_t gpmi_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	uint8_t *buf = this->data_buffer_dma;
-
-	gpmi_read_buf(mtd, buf, 1);
-	return buf[0];
-}
-
-/*
- * Handles block mark swapping.
- * It can be called in swapping the block mark, or swapping it back,
- * because the the operations are the same.
- */
-static void block_mark_swapping(struct gpmi_nand_data *this,
-				void *payload, void *auxiliary)
-{
-	struct bch_geometry *nfc_geo = &this->bch_geometry;
-	unsigned char *p;
-	unsigned char *a;
-	unsigned int  bit;
-	unsigned char mask;
-	unsigned char from_data;
-	unsigned char from_oob;
-
-	if (!this->swap_block_mark)
-		return;
-
-	/*
-	 * If control arrives here, we're swapping. Make some convenience
-	 * variables.
-	 */
-	bit = nfc_geo->block_mark_bit_offset;
-	p   = payload + nfc_geo->block_mark_byte_offset;
-	a   = auxiliary;
-
-	/*
-	 * Get the byte from the data area that overlays the block mark. Since
-	 * the ECC engine applies its own view to the bits in the page, the
-	 * physical block mark won't (in general) appear on a byte boundary in
-	 * the data.
-	 */
-	from_data = (p[0] >> bit) | (p[1] << (8 - bit));
-
-	/* Get the byte from the OOB. */
-	from_oob = a[0];
-
-	/* Swap them. */
-	a[0] = from_data;
-
-	mask = (0x1 << bit) - 1;
-	p[0] = (p[0] & mask) | (from_oob << bit);
-
-	mask = ~0 << bit;
-	p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
-}
-
-static int gpmi_ecc_read_page_data(struct nand_chip *chip,
-				   uint8_t *buf, int oob_required,
-				   int page)
-{
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	struct bch_geometry *nfc_geo = &this->bch_geometry;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	void          *payload_virt;
-	dma_addr_t    payload_phys;
-	void          *auxiliary_virt;
-	dma_addr_t    auxiliary_phys;
-	unsigned int  i;
-	unsigned char *status;
-	unsigned int  max_bitflips = 0;
-	int           ret;
-
-	dev_dbg(this->dev, "page number is : %d\n", page);
-	ret = read_page_prepare(this, buf, nfc_geo->payload_size,
-					this->payload_virt, this->payload_phys,
-					nfc_geo->payload_size,
-					&payload_virt, &payload_phys);
-	if (ret) {
-		dev_err(this->dev, "Inadequate DMA buffer\n");
-		ret = -ENOMEM;
-		return ret;
-	}
-	auxiliary_virt = this->auxiliary_virt;
-	auxiliary_phys = this->auxiliary_phys;
-
-	/* go! */
-	ret = gpmi_read_page(this, payload_phys, auxiliary_phys);
-	read_page_end(this, buf, nfc_geo->payload_size,
-			this->payload_virt, this->payload_phys,
-			nfc_geo->payload_size,
-			payload_virt, payload_phys);
-	if (ret) {
-		dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
-		return ret;
-	}
-
-	/* Loop over status bytes, accumulating ECC status. */
-	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
-
-	read_page_swap_end(this, buf, nfc_geo->payload_size,
-			   this->payload_virt, this->payload_phys,
-			   nfc_geo->payload_size,
-			   payload_virt, payload_phys);
-
-	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
-		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
-			continue;
-
-		if (*status == STATUS_UNCORRECTABLE) {
-			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
-			u8 *eccbuf = this->raw_buffer;
-			int offset, bitoffset;
-			int eccbytes;
-			int flips;
-
-			/* Read ECC bytes into our internal raw_buffer */
-			offset = nfc_geo->metadata_size * 8;
-			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
-			offset -= eccbits;
-			bitoffset = offset % 8;
-			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
-			offset /= 8;
-			eccbytes -= offset;
-			nand_change_read_column_op(chip, offset, eccbuf,
-						   eccbytes, false);
-
-			/*
-			 * ECC data are not byte aligned and we may have
-			 * in-band data in the first and last byte of
-			 * eccbuf. Set non-eccbits to one so that
-			 * nand_check_erased_ecc_chunk() does not count them
-			 * as bitflips.
-			 */
-			if (bitoffset)
-				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
-
-			bitoffset = (bitoffset + eccbits) % 8;
-			if (bitoffset)
-				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
-
-			/*
-			 * The ECC hardware has an uncorrectable ECC status
-			 * code in case we have bitflips in an erased page. As
-			 * nothing was written into this subpage the ECC is
-			 * obviously wrong and we can not trust it. We assume
-			 * at this point that we are reading an erased page and
-			 * try to correct the bitflips in buffer up to
-			 * ecc_strength bitflips. If this is a page with random
-			 * data, we exceed this number of bitflips and have a
-			 * ECC failure. Otherwise we use the corrected buffer.
-			 */
-			if (i == 0) {
-				/* The first block includes metadata */
-				flips = nand_check_erased_ecc_chunk(
-						buf + i * nfc_geo->ecc_chunk_size,
-						nfc_geo->ecc_chunk_size,
-						eccbuf, eccbytes,
-						auxiliary_virt,
-						nfc_geo->metadata_size,
-						nfc_geo->ecc_strength);
-			} else {
-				flips = nand_check_erased_ecc_chunk(
-						buf + i * nfc_geo->ecc_chunk_size,
-						nfc_geo->ecc_chunk_size,
-						eccbuf, eccbytes,
-						NULL, 0,
-						nfc_geo->ecc_strength);
-			}
-
-			if (flips > 0) {
-				max_bitflips = max_t(unsigned int, max_bitflips,
-						     flips);
-				mtd->ecc_stats.corrected += flips;
-				continue;
-			}
-
-			mtd->ecc_stats.failed++;
-			continue;
-		}
-
-		mtd->ecc_stats.corrected += *status;
-		max_bitflips = max_t(unsigned int, max_bitflips, *status);
-	}
-
-	/* handle the block mark swapping */
-	block_mark_swapping(this, buf, auxiliary_virt);
-
-	if (oob_required) {
-		/*
-		 * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
-		 * for details about our policy for delivering the OOB.
-		 *
-		 * We fill the caller's buffer with set bits, and then copy the
-		 * block mark to th caller's buffer. Note that, if block mark
-		 * swapping was necessary, it has already been done, so we can
-		 * rely on the first byte of the auxiliary buffer to contain
-		 * the block mark.
-		 */
-		memset(chip->oob_poi, ~0, mtd->oobsize);
-		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
-	}
-
-	return max_bitflips;
-}
-
-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			      uint8_t *buf, int oob_required, int page)
-{
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	return gpmi_ecc_read_page_data(chip, buf, oob_required, page);
-}
-
-/* Fake a virtual small page for the subpage read */
-static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-			uint32_t offs, uint32_t len, uint8_t *buf, int page)
-{
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	void __iomem *bch_regs = this->resources.bch_regs;
-	struct bch_geometry old_geo = this->bch_geometry;
-	struct bch_geometry *geo = &this->bch_geometry;
-	int size = chip->ecc.size; /* ECC chunk size */
-	int meta, n, page_size;
-	u32 r1_old, r2_old, r1_new, r2_new;
-	unsigned int max_bitflips;
-	int first, last, marker_pos;
-	int ecc_parity_size;
-	int col = 0;
-	int old_swap_block_mark = this->swap_block_mark;
-
-	/* The size of ECC parity */
-	ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
-
-	/* Align it with the chunk size */
-	first = offs / size;
-	last = (offs + len - 1) / size;
-
-	if (this->swap_block_mark) {
-		/*
-		 * Find the chunk which contains the Block Marker.
-		 * If this chunk is in the range of [first, last],
-		 * we have to read out the whole page.
-		 * Why? since we had swapped the data at the position of Block
-		 * Marker to the metadata which is bound with the chunk 0.
-		 */
-		marker_pos = geo->block_mark_byte_offset / size;
-		if (last >= marker_pos && first <= marker_pos) {
-			dev_dbg(this->dev,
-				"page:%d, first:%d, last:%d, marker at:%d\n",
-				page, first, last, marker_pos);
-			return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
-		}
-	}
-
-	meta = geo->metadata_size;
-	if (first) {
-		col = meta + (size + ecc_parity_size) * first;
-		meta = 0;
-		buf = buf + first * size;
-	}
-
-	nand_read_page_op(chip, page, col, NULL, 0);
-
-	/* Save the old environment */
-	r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
-	r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
-
-	/* change the BCH registers and bch_geometry{} */
-	n = last - first + 1;
-	page_size = meta + (size + ecc_parity_size) * n;
-
-	r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
-			BM_BCH_FLASH0LAYOUT0_META_SIZE);
-	r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
-			| BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
-	writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
-
-	r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
-	r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
-	writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
-
-	geo->ecc_chunk_count = n;
-	geo->payload_size = n * size;
-	geo->page_size = page_size;
-	geo->auxiliary_status_offset = ALIGN(meta, 4);
-
-	dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
-		page, offs, len, col, first, n, page_size);
-
-	/* Read the subpage now */
-	this->swap_block_mark = false;
-	max_bitflips = gpmi_ecc_read_page_data(chip, buf, 0, page);
-
-	/* Restore */
-	writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
-	writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
-	this->bch_geometry = old_geo;
-	this->swap_block_mark = old_swap_block_mark;
-
-	return max_bitflips;
-}
-
-static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-				const uint8_t *buf, int oob_required, int page)
-{
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	struct bch_geometry *nfc_geo = &this->bch_geometry;
-	const void *payload_virt;
-	dma_addr_t payload_phys;
-	const void *auxiliary_virt;
-	dma_addr_t auxiliary_phys;
-	int        ret;
-
-	dev_dbg(this->dev, "ecc write page.\n");
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	if (this->swap_block_mark) {
-		/*
-		 * If control arrives here, we're doing block mark swapping.
-		 * Since we can't modify the caller's buffers, we must copy them
-		 * into our own.
-		 */
-		memcpy(this->payload_virt, buf, mtd->writesize);
-		payload_virt = this->payload_virt;
-		payload_phys = this->payload_phys;
-
-		memcpy(this->auxiliary_virt, chip->oob_poi,
-				nfc_geo->auxiliary_size);
-		auxiliary_virt = this->auxiliary_virt;
-		auxiliary_phys = this->auxiliary_phys;
-
-		/* Handle block mark swapping. */
-		block_mark_swapping(this,
-				(void *)payload_virt, (void *)auxiliary_virt);
-	} else {
-		/*
-		 * If control arrives here, we're not doing block mark swapping,
-		 * so we can to try and use the caller's buffers.
-		 */
-		ret = send_page_prepare(this,
-				buf, mtd->writesize,
-				this->payload_virt, this->payload_phys,
-				nfc_geo->payload_size,
-				&payload_virt, &payload_phys);
-		if (ret) {
-			dev_err(this->dev, "Inadequate payload DMA buffer\n");
-			return 0;
-		}
-
-		ret = send_page_prepare(this,
-				chip->oob_poi, mtd->oobsize,
-				this->auxiliary_virt, this->auxiliary_phys,
-				nfc_geo->auxiliary_size,
-				&auxiliary_virt, &auxiliary_phys);
-		if (ret) {
-			dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
-			goto exit_auxiliary;
-		}
-	}
-
-	/* Ask the NFC. */
-	ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
-	if (ret)
-		dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
-
-	if (!this->swap_block_mark) {
-		send_page_end(this, chip->oob_poi, mtd->oobsize,
-				this->auxiliary_virt, this->auxiliary_phys,
-				nfc_geo->auxiliary_size,
-				auxiliary_virt, auxiliary_phys);
-exit_auxiliary:
-		send_page_end(this, buf, mtd->writesize,
-				this->payload_virt, this->payload_phys,
-				nfc_geo->payload_size,
-				payload_virt, payload_phys);
-	}
-
-	if (ret)
-		return ret;
-
-	return nand_prog_page_end_op(chip);
-}
-
-/*
- * There are several places in this driver where we have to handle the OOB and
- * block marks. This is the function where things are the most complicated, so
- * this is where we try to explain it all. All the other places refer back to
- * here.
- *
- * These are the rules, in order of decreasing importance:
- *
- * 1) Nothing the caller does can be allowed to imperil the block mark.
- *
- * 2) In read operations, the first byte of the OOB we return must reflect the
- *    true state of the block mark, no matter where that block mark appears in
- *    the physical page.
- *
- * 3) ECC-based read operations return an OOB full of set bits (since we never
- *    allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads
- *    return).
- *
- * 4) "Raw" read operations return a direct view of the physical bytes in the
- *    page, using the conventional definition of which bytes are data and which
- *    are OOB. This gives the caller a way to see the actual, physical bytes
- *    in the page, without the distortions applied by our ECC engine.
- *
- *
- * What we do for this specific read operation depends on two questions:
- *
- * 1) Are we doing a "raw" read, or an ECC-based read?
- *
- * 2) Are we using block mark swapping or transcription?
- *
- * There are four cases, illustrated by the following Karnaugh map:
- *
- *                    |           Raw           |         ECC-based       |
- *       -------------+-------------------------+-------------------------+
- *                    | Read the conventional   |                         |
- *                    | OOB at the end of the   |                         |
- *       Swapping     | page and return it. It  |                         |
- *                    | contains exactly what   |                         |
- *                    | we want.                | Read the block mark and |
- *       -------------+-------------------------+ return it in a buffer   |
- *                    | Read the conventional   | full of set bits.       |
- *                    | OOB at the end of the   |                         |
- *                    | page and also the block |                         |
- *       Transcribing | mark in the metadata.   |                         |
- *                    | Copy the block mark     |                         |
- *                    | into the first byte of  |                         |
- *                    | the OOB.                |                         |
- *       -------------+-------------------------+-------------------------+
- *
- * Note that we break rule #4 in the Transcribing/Raw case because we're not
- * giving an accurate view of the actual, physical bytes in the page (we're
- * overwriting the block mark). That's OK because it's more important to follow
- * rule #2.
- *
- * It turns out that knowing whether we want an "ECC-based" or "raw" read is not
- * easy. When reading a page, for example, the NAND Flash MTD code calls our
- * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
- * ECC-based or raw view of the page is implicit in which function it calls
- * (there is a similar pair of ECC-based/raw functions for writing).
- */
-static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-				int page)
-{
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-
-	dev_dbg(this->dev, "page number is %d\n", page);
-	/* clear the OOB buffer */
-	memset(chip->oob_poi, ~0, mtd->oobsize);
-
-	/* Read out the conventional OOB. */
-	nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	/*
-	 * Now, we want to make sure the block mark is correct. In the
-	 * non-transcribing case (!GPMI_IS_MX23()), we already have it.
-	 * Otherwise, we need to explicitly read it.
-	 */
-	if (GPMI_IS_MX23(this)) {
-		/* Read the block mark into the first byte of the OOB buffer. */
-		nand_read_page_op(chip, page, 0, NULL, 0);
-		chip->oob_poi[0] = chip->read_byte(mtd);
-	}
-
-	return 0;
-}
-
-static int
-gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
-{
-	struct mtd_oob_region of = { };
-
-	/* Do we have available oob area? */
-	mtd_ooblayout_free(mtd, 0, &of);
-	if (!of.length)
-		return -EPERM;
-
-	if (!nand_is_slc(chip))
-		return -EPERM;
-
-	return nand_prog_page_op(chip, page, mtd->writesize + of.offset,
-				 chip->oob_poi + of.offset, of.length);
-}
-
-/*
- * This function reads a NAND page without involving the ECC engine (no HW
- * ECC correction).
- * The tricky part in the GPMI/BCH controller is that it stores ECC bits
- * inline (interleaved with payload DATA), and do not align data chunk on
- * byte boundaries.
- * We thus need to take care moving the payload data and ECC bits stored in the
- * page into the provided buffers, which is why we're using gpmi_copy_bits.
- *
- * See set_geometry_by_ecc_info inline comments to have a full description
- * of the layout used by the GPMI controller.
- */
-static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
-				  struct nand_chip *chip, uint8_t *buf,
-				  int oob_required, int page)
-{
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	struct bch_geometry *nfc_geo = &this->bch_geometry;
-	int eccsize = nfc_geo->ecc_chunk_size;
-	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
-	u8 *tmp_buf = this->raw_buffer;
-	size_t src_bit_off;
-	size_t oob_bit_off;
-	size_t oob_byte_off;
-	uint8_t *oob = chip->oob_poi;
-	int step;
-
-	nand_read_page_op(chip, page, 0, tmp_buf,
-			  mtd->writesize + mtd->oobsize);
-
-	/*
-	 * If required, swap the bad block marker and the data stored in the
-	 * metadata section, so that we don't wrongly consider a block as bad.
-	 *
-	 * See the layout description for a detailed explanation on why this
-	 * is needed.
-	 */
-	if (this->swap_block_mark)
-		swap(tmp_buf[0], tmp_buf[mtd->writesize]);
-
-	/*
-	 * Copy the metadata section into the oob buffer (this section is
-	 * guaranteed to be aligned on a byte boundary).
-	 */
-	if (oob_required)
-		memcpy(oob, tmp_buf, nfc_geo->metadata_size);
-
-	oob_bit_off = nfc_geo->metadata_size * 8;
-	src_bit_off = oob_bit_off;
-
-	/* Extract interleaved payload data and ECC bits */
-	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
-		if (buf)
-			gpmi_copy_bits(buf, step * eccsize * 8,
-				       tmp_buf, src_bit_off,
-				       eccsize * 8);
-		src_bit_off += eccsize * 8;
-
-		/* Align last ECC block to align a byte boundary */
-		if (step == nfc_geo->ecc_chunk_count - 1 &&
-		    (oob_bit_off + eccbits) % 8)
-			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
-
-		if (oob_required)
-			gpmi_copy_bits(oob, oob_bit_off,
-				       tmp_buf, src_bit_off,
-				       eccbits);
-
-		src_bit_off += eccbits;
-		oob_bit_off += eccbits;
-	}
-
-	if (oob_required) {
-		oob_byte_off = oob_bit_off / 8;
-
-		if (oob_byte_off < mtd->oobsize)
-			memcpy(oob + oob_byte_off,
-			       tmp_buf + mtd->writesize + oob_byte_off,
-			       mtd->oobsize - oob_byte_off);
-	}
-
-	return 0;
-}
-
-/*
- * This function writes a NAND page without involving the ECC engine (no HW
- * ECC generation).
- * The tricky part in the GPMI/BCH controller is that it stores ECC bits
- * inline (interleaved with payload DATA), and do not align data chunk on
- * byte boundaries.
- * We thus need to take care moving the OOB area at the right place in the
- * final page, which is why we're using gpmi_copy_bits.
- *
- * See set_geometry_by_ecc_info inline comments to have a full description
- * of the layout used by the GPMI controller.
- */
-static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
-				   struct nand_chip *chip,
-				   const uint8_t *buf,
-				   int oob_required, int page)
-{
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	struct bch_geometry *nfc_geo = &this->bch_geometry;
-	int eccsize = nfc_geo->ecc_chunk_size;
-	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
-	u8 *tmp_buf = this->raw_buffer;
-	uint8_t *oob = chip->oob_poi;
-	size_t dst_bit_off;
-	size_t oob_bit_off;
-	size_t oob_byte_off;
-	int step;
-
-	/*
-	 * Initialize all bits to 1 in case we don't have a buffer for the
-	 * payload or oob data in order to leave unspecified bits of data
-	 * to their initial state.
-	 */
-	if (!buf || !oob_required)
-		memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize);
-
-	/*
-	 * First copy the metadata section (stored in oob buffer) at the
-	 * beginning of the page, as imposed by the GPMI layout.
-	 */
-	memcpy(tmp_buf, oob, nfc_geo->metadata_size);
-	oob_bit_off = nfc_geo->metadata_size * 8;
-	dst_bit_off = oob_bit_off;
-
-	/* Interleave payload data and ECC bits */
-	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
-		if (buf)
-			gpmi_copy_bits(tmp_buf, dst_bit_off,
-				       buf, step * eccsize * 8, eccsize * 8);
-		dst_bit_off += eccsize * 8;
-
-		/* Align last ECC block to align a byte boundary */
-		if (step == nfc_geo->ecc_chunk_count - 1 &&
-		    (oob_bit_off + eccbits) % 8)
-			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
-
-		if (oob_required)
-			gpmi_copy_bits(tmp_buf, dst_bit_off,
-				       oob, oob_bit_off, eccbits);
-
-		dst_bit_off += eccbits;
-		oob_bit_off += eccbits;
-	}
-
-	oob_byte_off = oob_bit_off / 8;
-
-	if (oob_required && oob_byte_off < mtd->oobsize)
-		memcpy(tmp_buf + mtd->writesize + oob_byte_off,
-		       oob + oob_byte_off, mtd->oobsize - oob_byte_off);
-
-	/*
-	 * If required, swap the bad block marker and the first byte of the
-	 * metadata section, so that we don't modify the bad block marker.
-	 *
-	 * See the layout description for a detailed explanation on why this
-	 * is needed.
-	 */
-	if (this->swap_block_mark)
-		swap(tmp_buf[0], tmp_buf[mtd->writesize]);
-
-	return nand_prog_page_op(chip, page, 0, tmp_buf,
-				 mtd->writesize + mtd->oobsize);
-}
-
-static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				 int page)
-{
-	return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
-}
-
-static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				 int page)
-{
-	return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
-}
-
-static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct gpmi_nand_data *this = nand_get_controller_data(chip);
-	int ret = 0;
-	uint8_t *block_mark;
-	int column, page, chipnr;
-
-	chipnr = (int)(ofs >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
-	column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
-
-	/* Write the block mark. */
-	block_mark = this->data_buffer_dma;
-	block_mark[0] = 0; /* bad block marker */
-
-	/* Shift to get page */
-	page = (int)(ofs >> chip->page_shift);
-
-	ret = nand_prog_page_op(chip, page, column, block_mark, 1);
-
-	chip->select_chip(mtd, -1);
-
-	return ret;
-}
-
-static int nand_boot_set_geometry(struct gpmi_nand_data *this)
-{
-	struct boot_rom_geometry *geometry = &this->rom_geometry;
-
-	/*
-	 * Set the boot block stride size.
-	 *
-	 * In principle, we should be reading this from the OTP bits, since
-	 * that's where the ROM is going to get it. In fact, we don't have any
-	 * way to read the OTP bits, so we go with the default and hope for the
-	 * best.
-	 */
-	geometry->stride_size_in_pages = 64;
-
-	/*
-	 * Set the search area stride exponent.
-	 *
-	 * In principle, we should be reading this from the OTP bits, since
-	 * that's where the ROM is going to get it. In fact, we don't have any
-	 * way to read the OTP bits, so we go with the default and hope for the
-	 * best.
-	 */
-	geometry->search_area_stride_exponent = 2;
-	return 0;
-}
-
-static const char  *fingerprint = "STMP";
-static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
-{
-	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
-	struct device *dev = this->dev;
-	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int search_area_size_in_strides;
-	unsigned int stride;
-	unsigned int page;
-	uint8_t *buffer = chip->data_buf;
-	int saved_chip_number;
-	int found_an_ncb_fingerprint = false;
-
-	/* Compute the number of strides in a search area. */
-	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
-
-	saved_chip_number = this->current_chip;
-	chip->select_chip(mtd, 0);
-
-	/*
-	 * Loop through the first search area, looking for the NCB fingerprint.
-	 */
-	dev_dbg(dev, "Scanning for an NCB fingerprint...\n");
-
-	for (stride = 0; stride < search_area_size_in_strides; stride++) {
-		/* Compute the page addresses. */
-		page = stride * rom_geo->stride_size_in_pages;
-
-		dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page);
-
-		/*
-		 * Read the NCB fingerprint. The fingerprint is four bytes long
-		 * and starts in the 12th byte of the page.
-		 */
-		nand_read_page_op(chip, page, 12, NULL, 0);
-		chip->read_buf(mtd, buffer, strlen(fingerprint));
-
-		/* Look for the fingerprint. */
-		if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
-			found_an_ncb_fingerprint = true;
-			break;
-		}
-
-	}
-
-	chip->select_chip(mtd, saved_chip_number);
-
-	if (found_an_ncb_fingerprint)
-		dev_dbg(dev, "\tFound a fingerprint\n");
-	else
-		dev_dbg(dev, "\tNo fingerprint found\n");
-	return found_an_ncb_fingerprint;
-}
-
-/* Writes a transcription stamp. */
-static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
-{
-	struct device *dev = this->dev;
-	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
-	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int block_size_in_pages;
-	unsigned int search_area_size_in_strides;
-	unsigned int search_area_size_in_pages;
-	unsigned int search_area_size_in_blocks;
-	unsigned int block;
-	unsigned int stride;
-	unsigned int page;
-	uint8_t      *buffer = chip->data_buf;
-	int saved_chip_number;
-	int status;
-
-	/* Compute the search area geometry. */
-	block_size_in_pages = mtd->erasesize / mtd->writesize;
-	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
-	search_area_size_in_pages = search_area_size_in_strides *
-					rom_geo->stride_size_in_pages;
-	search_area_size_in_blocks =
-		  (search_area_size_in_pages + (block_size_in_pages - 1)) /
-				    block_size_in_pages;
-
-	dev_dbg(dev, "Search Area Geometry :\n");
-	dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks);
-	dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides);
-	dev_dbg(dev, "\tin Pages  : %u\n", search_area_size_in_pages);
-
-	/* Select chip 0. */
-	saved_chip_number = this->current_chip;
-	chip->select_chip(mtd, 0);
-
-	/* Loop over blocks in the first search area, erasing them. */
-	dev_dbg(dev, "Erasing the search area...\n");
-
-	for (block = 0; block < search_area_size_in_blocks; block++) {
-		/* Erase this block. */
-		dev_dbg(dev, "\tErasing block 0x%x\n", block);
-		status = nand_erase_op(chip, block);
-		if (status)
-			dev_err(dev, "[%s] Erase failed.\n", __func__);
-	}
-
-	/* Write the NCB fingerprint into the page buffer. */
-	memset(buffer, ~0, mtd->writesize);
-	memcpy(buffer + 12, fingerprint, strlen(fingerprint));
-
-	/* Loop through the first search area, writing NCB fingerprints. */
-	dev_dbg(dev, "Writing NCB fingerprints...\n");
-	for (stride = 0; stride < search_area_size_in_strides; stride++) {
-		/* Compute the page addresses. */
-		page = stride * rom_geo->stride_size_in_pages;
-
-		/* Write the first page of the current stride. */
-		dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
-
-		status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
-		if (status)
-			dev_err(dev, "[%s] Write failed.\n", __func__);
-	}
-
-	/* Deselect chip 0. */
-	chip->select_chip(mtd, saved_chip_number);
-	return 0;
-}
-
-static int mx23_boot_init(struct gpmi_nand_data  *this)
-{
-	struct device *dev = this->dev;
-	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int block_count;
-	unsigned int block;
-	int     chipnr;
-	int     page;
-	loff_t  byte;
-	uint8_t block_mark;
-	int     ret = 0;
-
-	/*
-	 * If control arrives here, we can't use block mark swapping, which
-	 * means we're forced to use transcription. First, scan for the
-	 * transcription stamp. If we find it, then we don't have to do
-	 * anything -- the block marks are already transcribed.
-	 */
-	if (mx23_check_transcription_stamp(this))
-		return 0;
-
-	/*
-	 * If control arrives here, we couldn't find a transcription stamp, so
-	 * so we presume the block marks are in the conventional location.
-	 */
-	dev_dbg(dev, "Transcribing bad block marks...\n");
-
-	/* Compute the number of blocks in the entire medium. */
-	block_count = chip->chipsize >> chip->phys_erase_shift;
-
-	/*
-	 * Loop over all the blocks in the medium, transcribing block marks as
-	 * we go.
-	 */
-	for (block = 0; block < block_count; block++) {
-		/*
-		 * Compute the chip, page and byte addresses for this block's
-		 * conventional mark.
-		 */
-		chipnr = block >> (chip->chip_shift - chip->phys_erase_shift);
-		page = block << (chip->phys_erase_shift - chip->page_shift);
-		byte = block <<  chip->phys_erase_shift;
-
-		/* Send the command to read the conventional block mark. */
-		chip->select_chip(mtd, chipnr);
-		nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
-		block_mark = chip->read_byte(mtd);
-		chip->select_chip(mtd, -1);
-
-		/*
-		 * Check if the block is marked bad. If so, we need to mark it
-		 * again, but this time the result will be a mark in the
-		 * location where we transcribe block marks.
-		 */
-		if (block_mark != 0xff) {
-			dev_dbg(dev, "Transcribing mark in block %u\n", block);
-			ret = chip->block_markbad(mtd, byte);
-			if (ret)
-				dev_err(dev,
-					"Failed to mark block bad with ret %d\n",
-					ret);
-		}
-	}
-
-	/* Write the stamp that indicates we've transcribed the block marks. */
-	mx23_write_transcription_stamp(this);
-	return 0;
-}
-
-static int nand_boot_init(struct gpmi_nand_data  *this)
-{
-	nand_boot_set_geometry(this);
-
-	/* This is ROM arch-specific initilization before the BBT scanning. */
-	if (GPMI_IS_MX23(this))
-		return mx23_boot_init(this);
-	return 0;
-}
-
-static int gpmi_set_geometry(struct gpmi_nand_data *this)
-{
-	int ret;
-
-	/* Free the temporary DMA memory for reading ID. */
-	gpmi_free_dma_buffer(this);
-
-	/* Set up the NFC geometry which is used by BCH. */
-	ret = bch_set_geometry(this);
-	if (ret) {
-		dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
-		return ret;
-	}
-
-	/* Alloc the new DMA buffers according to the pagesize and oobsize */
-	return gpmi_alloc_dma_buffer(this);
-}
-
-static int gpmi_init_last(struct gpmi_nand_data *this)
-{
-	struct nand_chip *chip = &this->nand;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	struct bch_geometry *bch_geo = &this->bch_geometry;
-	int ret;
-
-	/* Set up the medium geometry */
-	ret = gpmi_set_geometry(this);
-	if (ret)
-		return ret;
-
-	/* Init the nand_ecc_ctrl{} */
-	ecc->read_page	= gpmi_ecc_read_page;
-	ecc->write_page	= gpmi_ecc_write_page;
-	ecc->read_oob	= gpmi_ecc_read_oob;
-	ecc->write_oob	= gpmi_ecc_write_oob;
-	ecc->read_page_raw = gpmi_ecc_read_page_raw;
-	ecc->write_page_raw = gpmi_ecc_write_page_raw;
-	ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
-	ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
-	ecc->mode	= NAND_ECC_HW;
-	ecc->size	= bch_geo->ecc_chunk_size;
-	ecc->strength	= bch_geo->ecc_strength;
-	mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
-
-	/*
-	 * We only enable the subpage read when:
-	 *  (1) the chip is imx6, and
-	 *  (2) the size of the ECC parity is byte aligned.
-	 */
-	if (GPMI_IS_MX6(this) &&
-		((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
-		ecc->read_subpage = gpmi_ecc_read_subpage;
-		chip->options |= NAND_SUBPAGE_READ;
-	}
-
-	/*
-	 * Can we enable the extra features? such as EDO or Sync mode.
-	 *
-	 * We do not check the return value now. That's means if we fail in
-	 * enable the extra features, we still can run in the normal way.
-	 */
-	gpmi_extra_init(this);
-
-	return 0;
-}
-
-static int gpmi_nand_init(struct gpmi_nand_data *this)
-{
-	struct nand_chip *chip = &this->nand;
-	struct mtd_info  *mtd = nand_to_mtd(chip);
-	int ret;
-
-	/* init current chip */
-	this->current_chip	= -1;
-
-	/* init the MTD data structures */
-	mtd->name		= "gpmi-nand";
-	mtd->dev.parent		= this->dev;
-
-	/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
-	nand_set_controller_data(chip, this);
-	nand_set_flash_node(chip, this->pdev->dev.of_node);
-	chip->select_chip	= gpmi_select_chip;
-	chip->cmd_ctrl		= gpmi_cmd_ctrl;
-	chip->dev_ready		= gpmi_dev_ready;
-	chip->read_byte		= gpmi_read_byte;
-	chip->read_buf		= gpmi_read_buf;
-	chip->write_buf		= gpmi_write_buf;
-	chip->badblock_pattern	= &gpmi_bbt_descr;
-	chip->block_markbad	= gpmi_block_markbad;
-	chip->options		|= NAND_NO_SUBPAGE_WRITE;
-
-	/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
-	this->swap_block_mark = !GPMI_IS_MX23(this);
-
-	/*
-	 * Allocate a temporary DMA buffer for reading ID in the
-	 * nand_scan_ident().
-	 */
-	this->bch_geometry.payload_size = 1024;
-	this->bch_geometry.auxiliary_size = 128;
-	ret = gpmi_alloc_dma_buffer(this);
-	if (ret)
-		goto err_out;
-
-	ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
-	if (ret)
-		goto err_out;
-
-	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-		chip->bbt_options |= NAND_BBT_NO_OOB;
-
-		if (of_property_read_bool(this->dev->of_node,
-						"fsl,no-blockmark-swap"))
-			this->swap_block_mark = false;
-	}
-	dev_dbg(this->dev, "Blockmark swapping %sabled\n",
-		this->swap_block_mark ? "en" : "dis");
-
-	ret = gpmi_init_last(this);
-	if (ret)
-		goto err_out;
-
-	chip->options |= NAND_SKIP_BBTSCAN;
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		goto err_out;
-
-	ret = nand_boot_init(this);
-	if (ret)
-		goto err_nand_cleanup;
-	ret = chip->scan_bbt(mtd);
-	if (ret)
-		goto err_nand_cleanup;
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret)
-		goto err_nand_cleanup;
-	return 0;
-
-err_nand_cleanup:
-	nand_cleanup(chip);
-err_out:
-	gpmi_free_dma_buffer(this);
-	return ret;
-}
-
-static const struct of_device_id gpmi_nand_id_table[] = {
-	{
-		.compatible = "fsl,imx23-gpmi-nand",
-		.data = &gpmi_devdata_imx23,
-	}, {
-		.compatible = "fsl,imx28-gpmi-nand",
-		.data = &gpmi_devdata_imx28,
-	}, {
-		.compatible = "fsl,imx6q-gpmi-nand",
-		.data = &gpmi_devdata_imx6q,
-	}, {
-		.compatible = "fsl,imx6sx-gpmi-nand",
-		.data = &gpmi_devdata_imx6sx,
-	}, {
-		.compatible = "fsl,imx7d-gpmi-nand",
-		.data = &gpmi_devdata_imx7d,
-	}, {}
-};
-MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
-
-static int gpmi_nand_probe(struct platform_device *pdev)
-{
-	struct gpmi_nand_data *this;
-	const struct of_device_id *of_id;
-	int ret;
-
-	this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
-	if (!this)
-		return -ENOMEM;
-
-	of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
-	if (of_id) {
-		this->devdata = of_id->data;
-	} else {
-		dev_err(&pdev->dev, "Failed to find the right device id.\n");
-		return -ENODEV;
-	}
-
-	platform_set_drvdata(pdev, this);
-	this->pdev  = pdev;
-	this->dev   = &pdev->dev;
-
-	ret = acquire_resources(this);
-	if (ret)
-		goto exit_acquire_resources;
-
-	ret = init_hardware(this);
-	if (ret)
-		goto exit_nfc_init;
-
-	ret = gpmi_nand_init(this);
-	if (ret)
-		goto exit_nfc_init;
-
-	dev_info(this->dev, "driver registered.\n");
-
-	return 0;
-
-exit_nfc_init:
-	release_resources(this);
-exit_acquire_resources:
-
-	return ret;
-}
-
-static int gpmi_nand_remove(struct platform_device *pdev)
-{
-	struct gpmi_nand_data *this = platform_get_drvdata(pdev);
-
-	nand_release(nand_to_mtd(&this->nand));
-	gpmi_free_dma_buffer(this);
-	release_resources(this);
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int gpmi_pm_suspend(struct device *dev)
-{
-	struct gpmi_nand_data *this = dev_get_drvdata(dev);
-
-	release_dma_channels(this);
-	return 0;
-}
-
-static int gpmi_pm_resume(struct device *dev)
-{
-	struct gpmi_nand_data *this = dev_get_drvdata(dev);
-	int ret;
-
-	ret = acquire_dma_channels(this);
-	if (ret < 0)
-		return ret;
-
-	/* re-init the GPMI registers */
-	this->flags &= ~GPMI_TIMING_INIT_OK;
-	ret = gpmi_init(this);
-	if (ret) {
-		dev_err(this->dev, "Error setting GPMI : %d\n", ret);
-		return ret;
-	}
-
-	/* re-init the BCH registers */
-	ret = bch_set_geometry(this);
-	if (ret) {
-		dev_err(this->dev, "Error setting BCH : %d\n", ret);
-		return ret;
-	}
-
-	/* re-init others */
-	gpmi_extra_init(this);
-
-	return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct dev_pm_ops gpmi_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
-};
-
-static struct platform_driver gpmi_nand_driver = {
-	.driver = {
-		.name = "gpmi-nand",
-		.pm = &gpmi_pm_ops,
-		.of_match_table = gpmi_nand_id_table,
-	},
-	.probe   = gpmi_nand_probe,
-	.remove  = gpmi_nand_remove,
-};
-module_platform_driver(gpmi_nand_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
deleted file mode 100644
index 06c1f993912c..000000000000
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
-#define __DRIVERS_MTD_NAND_GPMI_NAND_H
-
-#include <linux/mtd/rawnand.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-
-#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
-struct resources {
-	void __iomem  *gpmi_regs;
-	void __iomem  *bch_regs;
-	unsigned int  dma_low_channel;
-	unsigned int  dma_high_channel;
-	struct clk    *clock[GPMI_CLK_MAX];
-};
-
-/**
- * struct bch_geometry - BCH geometry description.
- * @gf_len:                   The length of Galois Field. (e.g., 13 or 14)
- * @ecc_strength:             A number that describes the strength of the ECC
- *                            algorithm.
- * @page_size:                The size, in bytes, of a physical page, including
- *                            both data and OOB.
- * @metadata_size:            The size, in bytes, of the metadata.
- * @ecc_chunk_size:           The size, in bytes, of a single ECC chunk. Note
- *                            the first chunk in the page includes both data and
- *                            metadata, so it's a bit larger than this value.
- * @ecc_chunk_count:          The number of ECC chunks in the page,
- * @payload_size:             The size, in bytes, of the payload buffer.
- * @auxiliary_size:           The size, in bytes, of the auxiliary buffer.
- * @auxiliary_status_offset:  The offset into the auxiliary buffer at which
- *                            the ECC status appears.
- * @block_mark_byte_offset:   The byte offset in the ECC-based page view at
- *                            which the underlying physical block mark appears.
- * @block_mark_bit_offset:    The bit offset into the ECC-based page view at
- *                            which the underlying physical block mark appears.
- */
-struct bch_geometry {
-	unsigned int  gf_len;
-	unsigned int  ecc_strength;
-	unsigned int  page_size;
-	unsigned int  metadata_size;
-	unsigned int  ecc_chunk_size;
-	unsigned int  ecc_chunk_count;
-	unsigned int  payload_size;
-	unsigned int  auxiliary_size;
-	unsigned int  auxiliary_status_offset;
-	unsigned int  block_mark_byte_offset;
-	unsigned int  block_mark_bit_offset;
-};
-
-/**
- * struct boot_rom_geometry - Boot ROM geometry description.
- * @stride_size_in_pages:        The size of a boot block stride, in pages.
- * @search_area_stride_exponent: The logarithm to base 2 of the size of a
- *                               search area in boot block strides.
- */
-struct boot_rom_geometry {
-	unsigned int  stride_size_in_pages;
-	unsigned int  search_area_stride_exponent;
-};
-
-/* DMA operations types */
-enum dma_ops_type {
-	DMA_FOR_COMMAND = 1,
-	DMA_FOR_READ_DATA,
-	DMA_FOR_WRITE_DATA,
-	DMA_FOR_READ_ECC_PAGE,
-	DMA_FOR_WRITE_ECC_PAGE
-};
-
-/**
- * struct nand_timing - Fundamental timing attributes for NAND.
- * @data_setup_in_ns:         The data setup time, in nanoseconds. Usually the
- *                            maximum of tDS and tWP. A negative value
- *                            indicates this characteristic isn't known.
- * @data_hold_in_ns:          The data hold time, in nanoseconds. Usually the
- *                            maximum of tDH, tWH and tREH. A negative value
- *                            indicates this characteristic isn't known.
- * @address_setup_in_ns:      The address setup time, in nanoseconds. Usually
- *                            the maximum of tCLS, tCS and tALS. A negative
- *                            value indicates this characteristic isn't known.
- * @gpmi_sample_delay_in_ns:  A GPMI-specific timing parameter. A negative value
- *                            indicates this characteristic isn't known.
- * @tREA_in_ns:               tREA, in nanoseconds, from the data sheet. A
- *                            negative value indicates this characteristic isn't
- *                            known.
- * @tRLOH_in_ns:              tRLOH, in nanoseconds, from the data sheet. A
- *                            negative value indicates this characteristic isn't
- *                            known.
- * @tRHOH_in_ns:              tRHOH, in nanoseconds, from the data sheet. A
- *                            negative value indicates this characteristic isn't
- *                            known.
- */
-struct nand_timing {
-	int8_t  data_setup_in_ns;
-	int8_t  data_hold_in_ns;
-	int8_t  address_setup_in_ns;
-	int8_t  gpmi_sample_delay_in_ns;
-	int8_t  tREA_in_ns;
-	int8_t  tRLOH_in_ns;
-	int8_t  tRHOH_in_ns;
-};
-
-enum gpmi_type {
-	IS_MX23,
-	IS_MX28,
-	IS_MX6Q,
-	IS_MX6SX,
-	IS_MX7D,
-};
-
-struct gpmi_devdata {
-	enum gpmi_type type;
-	int bch_max_ecc_strength;
-	int max_chain_delay; /* See the async EDO mode */
-	const char * const *clks;
-	const int clks_count;
-};
-
-struct gpmi_nand_data {
-	/* flags */
-#define GPMI_ASYNC_EDO_ENABLED	(1 << 0)
-#define GPMI_TIMING_INIT_OK	(1 << 1)
-	int			flags;
-	const struct gpmi_devdata *devdata;
-
-	/* System Interface */
-	struct device		*dev;
-	struct platform_device	*pdev;
-
-	/* Resources */
-	struct resources	resources;
-
-	/* Flash Hardware */
-	struct nand_timing	timing;
-	int			timing_mode;
-
-	/* BCH */
-	struct bch_geometry	bch_geometry;
-	struct completion	bch_done;
-
-	/* NAND Boot issue */
-	bool			swap_block_mark;
-	struct boot_rom_geometry rom_geometry;
-
-	/* MTD / NAND */
-	struct nand_chip	nand;
-
-	/* General-use Variables */
-	int			current_chip;
-	unsigned int		command_length;
-
-	/* passed from upper layer */
-	uint8_t			*upper_buf;
-	int			upper_len;
-
-	/* for DMA operations */
-	bool			direct_dma_map_ok;
-
-	struct scatterlist	cmd_sgl;
-	char			*cmd_buffer;
-
-	struct scatterlist	data_sgl;
-	char			*data_buffer_dma;
-
-	void			*page_buffer_virt;
-	dma_addr_t		page_buffer_phys;
-	unsigned int		page_buffer_size;
-
-	void			*payload_virt;
-	dma_addr_t		payload_phys;
-
-	void			*auxiliary_virt;
-	dma_addr_t		auxiliary_phys;
-
-	void			*raw_buffer;
-
-	/* DMA channels */
-#define DMA_CHANS		8
-	struct dma_chan		*dma_chans[DMA_CHANS];
-	enum dma_ops_type	last_dma_type;
-	enum dma_ops_type	dma_type;
-	struct completion	dma_done;
-
-	/* private */
-	void			*private;
-};
-
-/**
- * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
- * @data_setup_in_cycles:      The data setup time, in cycles.
- * @data_hold_in_cycles:       The data hold time, in cycles.
- * @address_setup_in_cycles:   The address setup time, in cycles.
- * @device_busy_timeout:       The timeout waiting for NAND Ready/Busy,
- *                             this value is the number of cycles multiplied
- *                             by 4096.
- * @use_half_periods:          Indicates the clock is running slowly, so the
- *                             NFC DLL should use half-periods.
- * @sample_delay_factor:       The sample delay factor.
- * @wrn_dly_sel:               The delay on the GPMI write strobe.
- */
-struct gpmi_nfc_hardware_timing {
-	/* for HW_GPMI_TIMING0 */
-	uint8_t  data_setup_in_cycles;
-	uint8_t  data_hold_in_cycles;
-	uint8_t  address_setup_in_cycles;
-
-	/* for HW_GPMI_TIMING1 */
-	uint16_t device_busy_timeout;
-#define GPMI_DEFAULT_BUSY_TIMEOUT	0x500 /* default busy timeout value.*/
-
-	/* for HW_GPMI_CTRL1 */
-	bool     use_half_periods;
-	uint8_t  sample_delay_factor;
-	uint8_t  wrn_dly_sel;
-};
-
-/**
- * struct timing_threshold - Timing threshold
- * @max_data_setup_cycles:       The maximum number of data setup cycles that
- *                               can be expressed in the hardware.
- * @internal_data_setup_in_ns:   The time, in ns, that the NFC hardware requires
- *                               for data read internal setup. In the Reference
- *                               Manual, see the chapter "High-Speed NAND
- *                               Timing" for more details.
- * @max_sample_delay_factor:     The maximum sample delay factor that can be
- *                               expressed in the hardware.
- * @max_dll_clock_period_in_ns:  The maximum period of the GPMI clock that the
- *                               sample delay DLL hardware can possibly work
- *                               with (the DLL is unusable with longer periods).
- *                               If the full-cycle period is greater than HALF
- *                               this value, the DLL must be configured to use
- *                               half-periods.
- * @max_dll_delay_in_ns:         The maximum amount of delay, in ns, that the
- *                               DLL can implement.
- * @clock_frequency_in_hz:       The clock frequency, in Hz, during the current
- *                               I/O transaction. If no I/O transaction is in
- *                               progress, this is the clock frequency during
- *                               the most recent I/O transaction.
- */
-struct timing_threshold {
-	const unsigned int      max_chip_count;
-	const unsigned int      max_data_setup_cycles;
-	const unsigned int      internal_data_setup_in_ns;
-	const unsigned int      max_sample_delay_factor;
-	const unsigned int      max_dll_clock_period_in_ns;
-	const unsigned int      max_dll_delay_in_ns;
-	unsigned long           clock_frequency_in_hz;
-
-};
-
-/* Common Services */
-int common_nfc_set_geometry(struct gpmi_nand_data *);
-struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
-void prepare_data_dma(struct gpmi_nand_data *,
-		      enum dma_data_direction dr);
-int start_dma_without_bch_irq(struct gpmi_nand_data *,
-			      struct dma_async_tx_descriptor *);
-int start_dma_with_bch_irq(struct gpmi_nand_data *,
-			   struct dma_async_tx_descriptor *);
-
-/* GPMI-NAND helper function library */
-int gpmi_init(struct gpmi_nand_data *);
-int gpmi_extra_init(struct gpmi_nand_data *);
-void gpmi_clear_bch(struct gpmi_nand_data *);
-void gpmi_dump_info(struct gpmi_nand_data *);
-int bch_set_geometry(struct gpmi_nand_data *);
-int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
-int gpmi_send_command(struct gpmi_nand_data *);
-void gpmi_begin(struct gpmi_nand_data *);
-void gpmi_end(struct gpmi_nand_data *);
-int gpmi_read_data(struct gpmi_nand_data *);
-int gpmi_send_data(struct gpmi_nand_data *);
-int gpmi_send_page(struct gpmi_nand_data *,
-		   dma_addr_t payload, dma_addr_t auxiliary);
-int gpmi_read_page(struct gpmi_nand_data *,
-		   dma_addr_t payload, dma_addr_t auxiliary);
-
-void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
-		    const u8 *src, size_t src_bit_off,
-		    size_t nbits);
-
-/* BCH : Status Block Completion Codes */
-#define STATUS_GOOD		0x00
-#define STATUS_ERASED		0xff
-#define STATUS_UNCORRECTABLE	0xfe
-
-/* Use the devdata to distinguish different Archs. */
-#define GPMI_IS_MX23(x)		((x)->devdata->type == IS_MX23)
-#define GPMI_IS_MX28(x)		((x)->devdata->type == IS_MX28)
-#define GPMI_IS_MX6Q(x)		((x)->devdata->type == IS_MX6Q)
-#define GPMI_IS_MX6SX(x)	((x)->devdata->type == IS_MX6SX)
-#define GPMI_IS_MX7D(x)		((x)->devdata->type == IS_MX7D)
-
-#define GPMI_IS_MX6(x)		(GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
-				 GPMI_IS_MX7D(x))
-#endif
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
deleted file mode 100644
index 82114cdc8330..000000000000
--- a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Freescale GPMI NAND Flash Driver
- *
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
- * Copyright 2008 Embedded Alley Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef __GPMI_NAND_GPMI_REGS_H
-#define __GPMI_NAND_GPMI_REGS_H
-
-#define HW_GPMI_CTRL0					0x00000000
-#define HW_GPMI_CTRL0_SET				0x00000004
-#define HW_GPMI_CTRL0_CLR				0x00000008
-#define HW_GPMI_CTRL0_TOG				0x0000000c
-
-#define BP_GPMI_CTRL0_COMMAND_MODE			24
-#define BM_GPMI_CTRL0_COMMAND_MODE	(3 << BP_GPMI_CTRL0_COMMAND_MODE)
-#define BF_GPMI_CTRL0_COMMAND_MODE(v)	\
-	(((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE)
-#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE		0x0
-#define BV_GPMI_CTRL0_COMMAND_MODE__READ		0x1
-#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE	0x2
-#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY	0x3
-
-#define BM_GPMI_CTRL0_WORD_LENGTH			(1 << 23)
-#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT		0x0
-#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT		0x1
-
-/*
- *  Difference in LOCK_CS between imx23 and imx28 :
- *  This bit may impact the _POWER_ consumption. So some chips
- *  do not set it.
- */
-#define MX23_BP_GPMI_CTRL0_LOCK_CS			22
-#define MX28_BP_GPMI_CTRL0_LOCK_CS			27
-#define LOCK_CS_ENABLE					0x1
-#define BF_GPMI_CTRL0_LOCK_CS(v, x)			0x0
-
-/* Difference in CS between imx23 and imx28 */
-#define BP_GPMI_CTRL0_CS				20
-#define MX23_BM_GPMI_CTRL0_CS		(3 << BP_GPMI_CTRL0_CS)
-#define MX28_BM_GPMI_CTRL0_CS		(7 << BP_GPMI_CTRL0_CS)
-#define BF_GPMI_CTRL0_CS(v, x)		(((v) << BP_GPMI_CTRL0_CS) & \
-						(GPMI_IS_MX23((x)) \
-						? MX23_BM_GPMI_CTRL0_CS	\
-						: MX28_BM_GPMI_CTRL0_CS))
-
-#define BP_GPMI_CTRL0_ADDRESS				17
-#define BM_GPMI_CTRL0_ADDRESS		(3 << BP_GPMI_CTRL0_ADDRESS)
-#define BF_GPMI_CTRL0_ADDRESS(v)	\
-		(((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS)
-#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA		0x0
-#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE			0x1
-#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE			0x2
-
-#define BM_GPMI_CTRL0_ADDRESS_INCREMENT			(1 << 16)
-#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED	0x0
-#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED	0x1
-
-#define BP_GPMI_CTRL0_XFER_COUNT			0
-#define BM_GPMI_CTRL0_XFER_COUNT	(0xffff << BP_GPMI_CTRL0_XFER_COUNT)
-#define BF_GPMI_CTRL0_XFER_COUNT(v)	\
-		(((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT)
-
-#define HW_GPMI_COMPARE					0x00000010
-
-#define HW_GPMI_ECCCTRL					0x00000020
-#define HW_GPMI_ECCCTRL_SET				0x00000024
-#define HW_GPMI_ECCCTRL_CLR				0x00000028
-#define HW_GPMI_ECCCTRL_TOG				0x0000002c
-
-#define BP_GPMI_ECCCTRL_ECC_CMD				13
-#define BM_GPMI_ECCCTRL_ECC_CMD		(3 << BP_GPMI_ECCCTRL_ECC_CMD)
-#define BF_GPMI_ECCCTRL_ECC_CMD(v)	\
-		(((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD)
-#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE		0x0
-#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE		0x1
-
-#define BM_GPMI_ECCCTRL_ENABLE_ECC			(1 << 12)
-#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE		0x1
-#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE		0x0
-
-#define BP_GPMI_ECCCTRL_BUFFER_MASK			0
-#define BM_GPMI_ECCCTRL_BUFFER_MASK	(0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK)
-#define BF_GPMI_ECCCTRL_BUFFER_MASK(v)	\
-	(((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK)
-#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY	0x100
-#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE		0x1FF
-
-#define HW_GPMI_ECCCOUNT				0x00000030
-#define HW_GPMI_PAYLOAD					0x00000040
-#define HW_GPMI_AUXILIARY				0x00000050
-#define HW_GPMI_CTRL1					0x00000060
-#define HW_GPMI_CTRL1_SET				0x00000064
-#define HW_GPMI_CTRL1_CLR				0x00000068
-#define HW_GPMI_CTRL1_TOG				0x0000006c
-
-#define BP_GPMI_CTRL1_DECOUPLE_CS			24
-#define BM_GPMI_CTRL1_DECOUPLE_CS	(1 << BP_GPMI_CTRL1_DECOUPLE_CS)
-
-#define BP_GPMI_CTRL1_WRN_DLY_SEL			22
-#define BM_GPMI_CTRL1_WRN_DLY_SEL	(0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
-#define BF_GPMI_CTRL1_WRN_DLY_SEL(v)  \
-	(((v) << BP_GPMI_CTRL1_WRN_DLY_SEL) & BM_GPMI_CTRL1_WRN_DLY_SEL)
-#define BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS		0x0
-#define BV_GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS		0x1
-#define BV_GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS		0x2
-#define BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY		0x3
-
-#define BM_GPMI_CTRL1_BCH_MODE				(1 << 18)
-
-#define BP_GPMI_CTRL1_DLL_ENABLE			17
-#define BM_GPMI_CTRL1_DLL_ENABLE	(1 << BP_GPMI_CTRL1_DLL_ENABLE)
-
-#define BP_GPMI_CTRL1_HALF_PERIOD			16
-#define BM_GPMI_CTRL1_HALF_PERIOD	(1 << BP_GPMI_CTRL1_HALF_PERIOD)
-
-#define BP_GPMI_CTRL1_RDN_DELAY				12
-#define BM_GPMI_CTRL1_RDN_DELAY		(0xf << BP_GPMI_CTRL1_RDN_DELAY)
-#define BF_GPMI_CTRL1_RDN_DELAY(v)	\
-		(((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY)
-
-#define BM_GPMI_CTRL1_DEV_RESET				(1 << 3)
-#define BV_GPMI_CTRL1_DEV_RESET__ENABLED		0x0
-#define BV_GPMI_CTRL1_DEV_RESET__DISABLED		0x1
-
-#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY		(1 << 2)
-#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW	0x0
-#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH	0x1
-
-#define BM_GPMI_CTRL1_CAMERA_MODE			(1 << 1)
-#define BV_GPMI_CTRL1_GPMI_MODE__NAND			0x0
-#define BV_GPMI_CTRL1_GPMI_MODE__ATA			0x1
-
-#define BM_GPMI_CTRL1_GPMI_MODE				(1 << 0)
-
-#define HW_GPMI_TIMING0					0x00000070
-
-#define BP_GPMI_TIMING0_ADDRESS_SETUP			16
-#define BM_GPMI_TIMING0_ADDRESS_SETUP	(0xff << BP_GPMI_TIMING0_ADDRESS_SETUP)
-#define BF_GPMI_TIMING0_ADDRESS_SETUP(v)	\
-	(((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP)
-
-#define BP_GPMI_TIMING0_DATA_HOLD			8
-#define BM_GPMI_TIMING0_DATA_HOLD	(0xff << BP_GPMI_TIMING0_DATA_HOLD)
-#define BF_GPMI_TIMING0_DATA_HOLD(v)		\
-	(((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD)
-
-#define BP_GPMI_TIMING0_DATA_SETUP			0
-#define BM_GPMI_TIMING0_DATA_SETUP	(0xff << BP_GPMI_TIMING0_DATA_SETUP)
-#define BF_GPMI_TIMING0_DATA_SETUP(v)		\
-	(((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP)
-
-#define HW_GPMI_TIMING1					0x00000080
-#define BP_GPMI_TIMING1_BUSY_TIMEOUT			16
-#define BM_GPMI_TIMING1_BUSY_TIMEOUT	(0xffff << BP_GPMI_TIMING1_BUSY_TIMEOUT)
-#define BF_GPMI_TIMING1_BUSY_TIMEOUT(v)		\
-	(((v) << BP_GPMI_TIMING1_BUSY_TIMEOUT) & BM_GPMI_TIMING1_BUSY_TIMEOUT)
-
-#define HW_GPMI_TIMING2					0x00000090
-#define HW_GPMI_DATA					0x000000a0
-
-/* MX28 uses this to detect READY. */
-#define HW_GPMI_STAT					0x000000b0
-#define MX28_BP_GPMI_STAT_READY_BUSY			24
-#define MX28_BM_GPMI_STAT_READY_BUSY	(0xff << MX28_BP_GPMI_STAT_READY_BUSY)
-#define MX28_BF_GPMI_STAT_READY_BUSY(v)		\
-	(((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY)
-
-/* MX23 uses this to detect READY. */
-#define HW_GPMI_DEBUG					0x000000c0
-#define MX23_BP_GPMI_DEBUG_READY0			28
-#define MX23_BM_GPMI_DEBUG_READY0	(1 << MX23_BP_GPMI_DEBUG_READY0)
-#endif
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
deleted file mode 100644
index cb862793ab6d..000000000000
--- a/drivers/mtd/nand/hisi504_nand.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- * Hisilicon NAND Flash controller driver
- *
- * Copyright © 2012-2014 HiSilicon Technologies Co., Ltd.
- *              http://www.hisilicon.com
- *
- * Author: Zhou Wang <wangzhou.bry@gmail.com>
- * The initial developer of the original code is Zhiyong Cai
- * <caizhiyong@huawei.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/of.h>
-#include <linux/mtd/mtd.h>
-#include <linux/sizes.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/partitions.h>
-
-#define HINFC504_MAX_CHIP                               (4)
-#define HINFC504_W_LATCH                                (5)
-#define HINFC504_R_LATCH                                (7)
-#define HINFC504_RW_LATCH                               (3)
-
-#define HINFC504_NFC_TIMEOUT				(2 * HZ)
-#define HINFC504_NFC_PM_TIMEOUT				(1 * HZ)
-#define HINFC504_NFC_DMA_TIMEOUT			(5 * HZ)
-#define HINFC504_CHIP_DELAY				(25)
-
-#define HINFC504_REG_BASE_ADDRESS_LEN			(0x100)
-#define HINFC504_BUFFER_BASE_ADDRESS_LEN		(2048 + 128)
-
-#define HINFC504_ADDR_CYCLE_MASK			0x4
-
-#define HINFC504_CON					0x00
-#define HINFC504_CON_OP_MODE_NORMAL			BIT(0)
-#define HINFC504_CON_PAGEISZE_SHIFT			(1)
-#define HINFC504_CON_PAGESIZE_MASK			(0x07)
-#define HINFC504_CON_BUS_WIDTH				BIT(4)
-#define HINFC504_CON_READY_BUSY_SEL			BIT(8)
-#define HINFC504_CON_ECCTYPE_SHIFT			(9)
-#define HINFC504_CON_ECCTYPE_MASK			(0x07)
-
-#define HINFC504_PWIDTH					0x04
-#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
-	((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
-
-#define HINFC504_CMD					0x0C
-#define HINFC504_ADDRL					0x10
-#define HINFC504_ADDRH					0x14
-#define HINFC504_DATA_NUM				0x18
-
-#define HINFC504_OP					0x1C
-#define HINFC504_OP_READ_DATA_EN			BIT(1)
-#define HINFC504_OP_WAIT_READY_EN			BIT(2)
-#define HINFC504_OP_CMD2_EN				BIT(3)
-#define HINFC504_OP_WRITE_DATA_EN			BIT(4)
-#define HINFC504_OP_ADDR_EN				BIT(5)
-#define HINFC504_OP_CMD1_EN				BIT(6)
-#define HINFC504_OP_NF_CS_SHIFT                         (7)
-#define HINFC504_OP_NF_CS_MASK				(3)
-#define HINFC504_OP_ADDR_CYCLE_SHIFT			(9)
-#define HINFC504_OP_ADDR_CYCLE_MASK			(7)
-
-#define HINFC504_STATUS                                 0x20
-#define HINFC504_READY					BIT(0)
-
-#define HINFC504_INTEN					0x24
-#define HINFC504_INTEN_DMA				BIT(9)
-#define HINFC504_INTEN_UE				BIT(6)
-#define HINFC504_INTEN_CE				BIT(5)
-
-#define HINFC504_INTS					0x28
-#define HINFC504_INTS_DMA				BIT(9)
-#define HINFC504_INTS_UE				BIT(6)
-#define HINFC504_INTS_CE				BIT(5)
-
-#define HINFC504_INTCLR                                 0x2C
-#define HINFC504_INTCLR_DMA				BIT(9)
-#define HINFC504_INTCLR_UE				BIT(6)
-#define HINFC504_INTCLR_CE				BIT(5)
-
-#define HINFC504_ECC_STATUS                             0x5C
-#define HINFC504_ECC_16_BIT_SHIFT                       12
-
-#define HINFC504_DMA_CTRL				0x60
-#define HINFC504_DMA_CTRL_DMA_START			BIT(0)
-#define HINFC504_DMA_CTRL_WE				BIT(1)
-#define HINFC504_DMA_CTRL_DATA_AREA_EN			BIT(2)
-#define HINFC504_DMA_CTRL_OOB_AREA_EN			BIT(3)
-#define HINFC504_DMA_CTRL_BURST4_EN			BIT(4)
-#define HINFC504_DMA_CTRL_BURST8_EN			BIT(5)
-#define HINFC504_DMA_CTRL_BURST16_EN			BIT(6)
-#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT		(7)
-#define HINFC504_DMA_CTRL_ADDR_NUM_MASK                 (1)
-#define HINFC504_DMA_CTRL_CS_SHIFT			(8)
-#define HINFC504_DMA_CTRL_CS_MASK			(0x03)
-
-#define HINFC504_DMA_ADDR_DATA				0x64
-#define HINFC504_DMA_ADDR_OOB				0x68
-
-#define HINFC504_DMA_LEN				0x6C
-#define HINFC504_DMA_LEN_OOB_SHIFT			(16)
-#define HINFC504_DMA_LEN_OOB_MASK			(0xFFF)
-
-#define HINFC504_DMA_PARA				0x70
-#define HINFC504_DMA_PARA_DATA_RW_EN			BIT(0)
-#define HINFC504_DMA_PARA_OOB_RW_EN			BIT(1)
-#define HINFC504_DMA_PARA_DATA_EDC_EN			BIT(2)
-#define HINFC504_DMA_PARA_OOB_EDC_EN			BIT(3)
-#define HINFC504_DMA_PARA_DATA_ECC_EN			BIT(4)
-#define HINFC504_DMA_PARA_OOB_ECC_EN			BIT(5)
-
-#define HINFC_VERSION                                   0x74
-#define HINFC504_LOG_READ_ADDR				0x7C
-#define HINFC504_LOG_READ_LEN				0x80
-
-#define HINFC504_NANDINFO_LEN				0x10
-
-struct hinfc_host {
-	struct nand_chip	chip;
-	struct device		*dev;
-	void __iomem		*iobase;
-	void __iomem		*mmio;
-	struct completion       cmd_complete;
-	unsigned int		offset;
-	unsigned int		command;
-	int			chipselect;
-	unsigned int		addr_cycle;
-	u32                     addr_value[2];
-	u32                     cache_addr_value[2];
-	char			*buffer;
-	dma_addr_t		dma_buffer;
-	dma_addr_t		dma_oob;
-	int			version;
-	unsigned int            irq_status; /* interrupt status */
-};
-
-static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
-{
-	return readl(host->iobase + reg);
-}
-
-static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
-			       unsigned int reg)
-{
-	writel(value, host->iobase + reg);
-}
-
-static void wait_controller_finished(struct hinfc_host *host)
-{
-	unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
-	int val;
-
-	while (time_before(jiffies, timeout)) {
-		val = hinfc_read(host, HINFC504_STATUS);
-		if (host->command == NAND_CMD_ERASE2) {
-			/* nfc is ready */
-			while (!(val & HINFC504_READY))	{
-				usleep_range(500, 1000);
-				val = hinfc_read(host, HINFC504_STATUS);
-			}
-			return;
-		}
-
-		if (val & HINFC504_READY)
-			return;
-	}
-
-	/* wait cmd timeout */
-	dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
-}
-
-static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
-{
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info	*mtd = nand_to_mtd(chip);
-	unsigned long val;
-	int ret;
-
-	hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
-	hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
-
-	if (chip->ecc.mode == NAND_ECC_NONE) {
-		hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
-			<< HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
-
-		hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
-			| HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
-	} else {
-		if (host->command == NAND_CMD_READOOB)
-			hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
-			| HINFC504_DMA_PARA_OOB_EDC_EN
-			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
-		else
-			hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
-			| HINFC504_DMA_PARA_OOB_RW_EN
-			| HINFC504_DMA_PARA_DATA_EDC_EN
-			| HINFC504_DMA_PARA_OOB_EDC_EN
-			| HINFC504_DMA_PARA_DATA_ECC_EN
-			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
-
-	}
-
-	val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
-		| HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
-		| HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
-		| ((host->addr_cycle == 4 ? 1 : 0)
-			<< HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
-		| ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
-			<< HINFC504_DMA_CTRL_CS_SHIFT));
-
-	if (todev)
-		val |= HINFC504_DMA_CTRL_WE;
-
-	init_completion(&host->cmd_complete);
-
-	hinfc_write(host, val, HINFC504_DMA_CTRL);
-	ret = wait_for_completion_timeout(&host->cmd_complete,
-			HINFC504_NFC_DMA_TIMEOUT);
-
-	if (!ret) {
-		dev_err(host->dev, "DMA operation(irq) timeout!\n");
-		/* sanity check */
-		val = hinfc_read(host, HINFC504_DMA_CTRL);
-		if (!(val & HINFC504_DMA_CTRL_DMA_START))
-			dev_err(host->dev, "DMA is already done but without irq ACK!\n");
-		else
-			dev_err(host->dev, "DMA is really timeout!\n");
-	}
-}
-
-static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
-{
-	host->addr_value[0] &= 0xffff0000;
-
-	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
-	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
-	hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
-		    HINFC504_CMD);
-
-	hisi_nfc_dma_transfer(host, 1);
-
-	return 0;
-}
-
-static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
-{
-	struct mtd_info	*mtd = nand_to_mtd(&host->chip);
-
-	if ((host->addr_value[0] == host->cache_addr_value[0]) &&
-	    (host->addr_value[1] == host->cache_addr_value[1]))
-		return 0;
-
-	host->addr_value[0] &= 0xffff0000;
-
-	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
-	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
-	hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
-		    HINFC504_CMD);
-
-	hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
-	hinfc_write(host, mtd->writesize + mtd->oobsize,
-		    HINFC504_LOG_READ_LEN);
-
-	hisi_nfc_dma_transfer(host, 0);
-
-	host->cache_addr_value[0] = host->addr_value[0];
-	host->cache_addr_value[1] = host->addr_value[1];
-
-	return 0;
-}
-
-static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
-{
-	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
-	hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
-		    HINFC504_CMD);
-
-	hinfc_write(host, HINFC504_OP_WAIT_READY_EN
-		| HINFC504_OP_CMD2_EN
-		| HINFC504_OP_CMD1_EN
-		| HINFC504_OP_ADDR_EN
-		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
-			<< HINFC504_OP_NF_CS_SHIFT)
-		| ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
-			<< HINFC504_OP_ADDR_CYCLE_SHIFT),
-		HINFC504_OP);
-
-	wait_controller_finished(host);
-
-	return 0;
-}
-
-static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
-{
-	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
-	hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
-	hinfc_write(host, 0, HINFC504_ADDRL);
-
-	hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
-		| HINFC504_OP_READ_DATA_EN
-		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
-			<< HINFC504_OP_NF_CS_SHIFT)
-		| 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
-
-	wait_controller_finished(host);
-
-	return 0;
-}
-
-static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
-{
-	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
-	hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
-	hinfc_write(host, HINFC504_OP_CMD1_EN
-		| HINFC504_OP_READ_DATA_EN
-		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
-			<< HINFC504_OP_NF_CS_SHIFT),
-		HINFC504_OP);
-
-	wait_controller_finished(host);
-
-	return 0;
-}
-
-static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
-{
-	hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
-
-	hinfc_write(host, HINFC504_OP_CMD1_EN
-		| ((chipselect & HINFC504_OP_NF_CS_MASK)
-			<< HINFC504_OP_NF_CS_SHIFT)
-		| HINFC504_OP_WAIT_READY_EN,
-		HINFC504_OP);
-
-	wait_controller_finished(host);
-
-	return 0;
-}
-
-static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-
-	if (chipselect < 0)
-		return;
-
-	host->chipselect = chipselect;
-}
-
-static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-
-	if (host->command == NAND_CMD_STATUS)
-		return *(uint8_t *)(host->mmio);
-
-	host->offset++;
-
-	if (host->command == NAND_CMD_READID)
-		return *(uint8_t *)(host->mmio + host->offset - 1);
-
-	return *(uint8_t *)(host->buffer + host->offset - 1);
-}
-
-static u16 hisi_nfc_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-
-	host->offset += 2;
-	return *(u16 *)(host->buffer + host->offset - 2);
-}
-
-static void
-hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-
-	memcpy(host->buffer + host->offset, buf, len);
-	host->offset += len;
-}
-
-static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-
-	memcpy(buf, host->buffer + host->offset, len);
-	host->offset += len;
-}
-
-static void set_addr(struct mtd_info *mtd, int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-	unsigned int command = host->command;
-
-	host->addr_cycle    = 0;
-	host->addr_value[0] = 0;
-	host->addr_value[1] = 0;
-
-	/* Serially input address */
-	if (column != -1) {
-		/* Adjust columns for 16 bit buswidth */
-		if (chip->options & NAND_BUSWIDTH_16 &&
-				!nand_opcode_8bits(command))
-			column >>= 1;
-
-		host->addr_value[0] = column & 0xffff;
-		host->addr_cycle    = 2;
-	}
-	if (page_addr != -1) {
-		host->addr_value[0] |= (page_addr & 0xffff)
-			<< (host->addr_cycle * 8);
-		host->addr_cycle    += 2;
-		if (chip->options & NAND_ROW_ADDR_3) {
-			host->addr_cycle += 1;
-			if (host->command == NAND_CMD_ERASE1)
-				host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
-			else
-				host->addr_value[1] |= ((page_addr >> 16) & 0xff);
-		}
-	}
-}
-
-static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
-		int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hinfc_host *host = nand_get_controller_data(chip);
-	int is_cache_invalid = 1;
-	unsigned int flag = 0;
-
-	host->command =  command;
-
-	switch (command) {
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-		if (command == NAND_CMD_READ0)
-			host->offset = column;
-		else
-			host->offset = column + mtd->writesize;
-
-		is_cache_invalid = 0;
-		set_addr(mtd, column, page_addr);
-		hisi_nfc_send_cmd_readstart(host);
-		break;
-
-	case NAND_CMD_SEQIN:
-		host->offset = column;
-		set_addr(mtd, column, page_addr);
-		break;
-
-	case NAND_CMD_ERASE1:
-		set_addr(mtd, column, page_addr);
-		break;
-
-	case NAND_CMD_PAGEPROG:
-		hisi_nfc_send_cmd_pageprog(host);
-		break;
-
-	case NAND_CMD_ERASE2:
-		hisi_nfc_send_cmd_erase(host);
-		break;
-
-	case NAND_CMD_READID:
-		host->offset = column;
-		memset(host->mmio, 0, 0x10);
-		hisi_nfc_send_cmd_readid(host);
-		break;
-
-	case NAND_CMD_STATUS:
-		flag = hinfc_read(host, HINFC504_CON);
-		if (chip->ecc.mode == NAND_ECC_HW)
-			hinfc_write(host,
-				    flag & ~(HINFC504_CON_ECCTYPE_MASK <<
-				    HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
-
-		host->offset = 0;
-		memset(host->mmio, 0, 0x10);
-		hisi_nfc_send_cmd_status(host);
-		hinfc_write(host, flag, HINFC504_CON);
-		break;
-
-	case NAND_CMD_RESET:
-		hisi_nfc_send_cmd_reset(host, host->chipselect);
-		break;
-
-	default:
-		dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
-			command, column, page_addr);
-	}
-
-	if (is_cache_invalid) {
-		host->cache_addr_value[0] = ~0;
-		host->cache_addr_value[1] = ~0;
-	}
-}
-
-static irqreturn_t hinfc_irq_handle(int irq, void *devid)
-{
-	struct hinfc_host *host = devid;
-	unsigned int flag;
-
-	flag = hinfc_read(host, HINFC504_INTS);
-	/* store interrupts state */
-	host->irq_status |= flag;
-
-	if (flag & HINFC504_INTS_DMA) {
-		hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
-		complete(&host->cmd_complete);
-	} else if (flag & HINFC504_INTS_CE) {
-		hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
-	} else if (flag & HINFC504_INTS_UE) {
-		hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
-	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
-{
-	struct hinfc_host *host = nand_get_controller_data(chip);
-	int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
-	int stat_1, stat_2;
-
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	/* errors which can not be corrected by ECC */
-	if (host->irq_status & HINFC504_INTS_UE) {
-		mtd->ecc_stats.failed++;
-	} else if (host->irq_status & HINFC504_INTS_CE) {
-		/* TODO: need add other ECC modes! */
-		switch (chip->ecc.strength) {
-		case 16:
-			status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >>
-					HINFC504_ECC_16_BIT_SHIFT & 0x0fff;
-			stat_2 = status_ecc & 0x3f;
-			stat_1 = status_ecc >> 6 & 0x3f;
-			stat = stat_1 + stat_2;
-			stat_max = max_t(int, stat_1, stat_2);
-		}
-		mtd->ecc_stats.corrected += stat;
-		max_bitflips = max_t(int, max_bitflips, stat_max);
-	}
-	host->irq_status = 0;
-
-	return max_bitflips;
-}
-
-static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-				int page)
-{
-	struct hinfc_host *host = nand_get_controller_data(chip);
-
-	nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-
-	if (host->irq_status & HINFC504_INTS_UE) {
-		host->irq_status = 0;
-		return -EBADMSG;
-	}
-
-	host->irq_status = 0;
-	return 0;
-}
-
-static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
-		struct nand_chip *chip, const uint8_t *buf, int oob_required,
-		int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	if (oob_required)
-		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static void hisi_nfc_host_init(struct hinfc_host *host)
-{
-	struct nand_chip *chip = &host->chip;
-	unsigned int flag = 0;
-
-	host->version = hinfc_read(host, HINFC_VERSION);
-	host->addr_cycle		= 0;
-	host->addr_value[0]		= 0;
-	host->addr_value[1]		= 0;
-	host->cache_addr_value[0]	= ~0;
-	host->cache_addr_value[1]	= ~0;
-	host->chipselect		= 0;
-
-	/* default page size: 2K, ecc_none. need modify */
-	flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
-		| ((0x001 & HINFC504_CON_PAGESIZE_MASK)
-			<< HINFC504_CON_PAGEISZE_SHIFT)
-		| ((0x0 & HINFC504_CON_ECCTYPE_MASK)
-			<< HINFC504_CON_ECCTYPE_SHIFT)
-		| ((chip->options & NAND_BUSWIDTH_16) ?
-			HINFC504_CON_BUS_WIDTH : 0);
-	hinfc_write(host, flag, HINFC504_CON);
-
-	memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
-
-	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
-		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
-
-	/* enable DMA irq */
-	hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
-}
-
-static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section,
-			      struct mtd_oob_region *oobregion)
-{
-	/* FIXME: add ECC bytes position */
-	return -ENOTSUPP;
-}
-
-static int hisi_ooblayout_free(struct mtd_info *mtd, int section,
-			       struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 2;
-	oobregion->length = 6;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
-	.ecc = hisi_ooblayout_ecc,
-	.free = hisi_ooblayout_free,
-};
-
-static int hisi_nfc_ecc_probe(struct hinfc_host *host)
-{
-	unsigned int flag;
-	int size, strength, ecc_bits;
-	struct device *dev = host->dev;
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	size = chip->ecc.size;
-	strength = chip->ecc.strength;
-	if (size != 1024) {
-		dev_err(dev, "error ecc size: %d\n", size);
-		return -EINVAL;
-	}
-
-	if ((size == 1024) && ((strength != 8) && (strength != 16) &&
-				(strength != 24) && (strength != 40))) {
-		dev_err(dev, "ecc size and strength do not match\n");
-		return -EINVAL;
-	}
-
-	chip->ecc.size = size;
-	chip->ecc.strength = strength;
-
-	chip->ecc.read_page = hisi_nand_read_page_hwecc;
-	chip->ecc.read_oob = hisi_nand_read_oob;
-	chip->ecc.write_page = hisi_nand_write_page_hwecc;
-
-	switch (chip->ecc.strength) {
-	case 16:
-		ecc_bits = 6;
-		if (mtd->writesize == 2048)
-			mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);
-
-		/* TODO: add more page size support */
-		break;
-
-	/* TODO: add more ecc strength support */
-	default:
-		dev_err(dev, "not support strength: %d\n", chip->ecc.strength);
-		return -EINVAL;
-	}
-
-	flag = hinfc_read(host, HINFC504_CON);
-	/* add ecc type configure */
-	flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK)
-						<< HINFC504_CON_ECCTYPE_SHIFT);
-	hinfc_write(host, flag, HINFC504_CON);
-
-	/* enable ecc irq */
-	flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
-	hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
-		    HINFC504_INTEN);
-
-	return 0;
-}
-
-static int hisi_nfc_probe(struct platform_device *pdev)
-{
-	int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
-	struct device *dev = &pdev->dev;
-	struct hinfc_host *host;
-	struct nand_chip  *chip;
-	struct mtd_info   *mtd;
-	struct resource	  *res;
-	struct device_node *np = dev->of_node;
-
-	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-	host->dev = dev;
-
-	platform_set_drvdata(pdev, host);
-	chip = &host->chip;
-	mtd  = nand_to_mtd(chip);
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "no IRQ resource defined\n");
-		ret = -ENXIO;
-		goto err_res;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	host->iobase = devm_ioremap_resource(dev, res);
-	if (IS_ERR(host->iobase)) {
-		ret = PTR_ERR(host->iobase);
-		goto err_res;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	host->mmio = devm_ioremap_resource(dev, res);
-	if (IS_ERR(host->mmio)) {
-		ret = PTR_ERR(host->mmio);
-		dev_err(dev, "devm_ioremap_resource[1] fail\n");
-		goto err_res;
-	}
-
-	mtd->name		= "hisi_nand";
-	mtd->dev.parent         = &pdev->dev;
-
-	nand_set_controller_data(chip, host);
-	nand_set_flash_node(chip, np);
-	chip->cmdfunc		= hisi_nfc_cmdfunc;
-	chip->select_chip	= hisi_nfc_select_chip;
-	chip->read_byte		= hisi_nfc_read_byte;
-	chip->read_word		= hisi_nfc_read_word;
-	chip->write_buf		= hisi_nfc_write_buf;
-	chip->read_buf		= hisi_nfc_read_buf;
-	chip->chip_delay	= HINFC504_CHIP_DELAY;
-	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
-	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
-
-	hisi_nfc_host_init(host);
-
-	ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);
-	if (ret) {
-		dev_err(dev, "failed to request IRQ\n");
-		goto err_res;
-	}
-
-	ret = nand_scan_ident(mtd, max_chips, NULL);
-	if (ret)
-		goto err_res;
-
-	host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
-		&host->dma_buffer, GFP_KERNEL);
-	if (!host->buffer) {
-		ret = -ENOMEM;
-		goto err_res;
-	}
-
-	host->dma_oob = host->dma_buffer + mtd->writesize;
-	memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
-
-	flag = hinfc_read(host, HINFC504_CON);
-	flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
-	switch (mtd->writesize) {
-	case 2048:
-		flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
-	/*
-	 * TODO: add more pagesize support,
-	 * default pagesize has been set in hisi_nfc_host_init
-	 */
-	default:
-		dev_err(dev, "NON-2KB page size nand flash\n");
-		ret = -EINVAL;
-		goto err_res;
-	}
-	hinfc_write(host, flag, HINFC504_CON);
-
-	if (chip->ecc.mode == NAND_ECC_HW)
-		hisi_nfc_ecc_probe(host);
-
-	ret = nand_scan_tail(mtd);
-	if (ret) {
-		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
-		goto err_res;
-	}
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret) {
-		dev_err(dev, "Err MTD partition=%d\n", ret);
-		goto err_mtd;
-	}
-
-	return 0;
-
-err_mtd:
-	nand_release(mtd);
-err_res:
-	return ret;
-}
-
-static int hisi_nfc_remove(struct platform_device *pdev)
-{
-	struct hinfc_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-
-	nand_release(mtd);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int hisi_nfc_suspend(struct device *dev)
-{
-	struct hinfc_host *host = dev_get_drvdata(dev);
-	unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT;
-
-	while (time_before(jiffies, timeout)) {
-		if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) &&
-		    (hinfc_read(host, HINFC504_DMA_CTRL) &
-		     HINFC504_DMA_CTRL_DMA_START)) {
-			cond_resched();
-			return 0;
-		}
-	}
-
-	dev_err(host->dev, "nand controller suspend timeout.\n");
-
-	return -EAGAIN;
-}
-
-static int hisi_nfc_resume(struct device *dev)
-{
-	int cs;
-	struct hinfc_host *host = dev_get_drvdata(dev);
-	struct nand_chip *chip = &host->chip;
-
-	for (cs = 0; cs < chip->numchips; cs++)
-		hisi_nfc_send_cmd_reset(host, cs);
-	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
-		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
-
-	return 0;
-}
-#endif
-static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
-
-static const struct of_device_id nfc_id_table[] = {
-	{ .compatible = "hisilicon,504-nfc" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, nfc_id_table);
-
-static struct platform_driver hisi_nfc_driver = {
-	.driver = {
-		.name  = "hisi_nand",
-		.of_match_table = nfc_id_table,
-		.pm = &hisi_nfc_pm_ops,
-	},
-	.probe		= hisi_nfc_probe,
-	.remove		= hisi_nfc_remove,
-};
-
-module_platform_driver(hisi_nfc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Zhou Wang");
-MODULE_AUTHOR("Zhiyong Cai");
-MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
deleted file mode 100644
index 613b00a9604b..000000000000
--- a/drivers/mtd/nand/jz4740_nand.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 SoC NAND controller driver
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/gpio.h>
-
-#include <asm/mach-jz4740/jz4740_nand.h>
-
-#define JZ_REG_NAND_CTRL	0x50
-#define JZ_REG_NAND_ECC_CTRL	0x100
-#define JZ_REG_NAND_DATA	0x104
-#define JZ_REG_NAND_PAR0	0x108
-#define JZ_REG_NAND_PAR1	0x10C
-#define JZ_REG_NAND_PAR2	0x110
-#define JZ_REG_NAND_IRQ_STAT	0x114
-#define JZ_REG_NAND_IRQ_CTRL	0x118
-#define JZ_REG_NAND_ERR(x)	(0x11C + ((x) << 2))
-
-#define JZ_NAND_ECC_CTRL_PAR_READY	BIT(4)
-#define JZ_NAND_ECC_CTRL_ENCODING	BIT(3)
-#define JZ_NAND_ECC_CTRL_RS		BIT(2)
-#define JZ_NAND_ECC_CTRL_RESET		BIT(1)
-#define JZ_NAND_ECC_CTRL_ENABLE		BIT(0)
-
-#define JZ_NAND_STATUS_ERR_COUNT	(BIT(31) | BIT(30) | BIT(29))
-#define JZ_NAND_STATUS_PAD_FINISH	BIT(4)
-#define JZ_NAND_STATUS_DEC_FINISH	BIT(3)
-#define JZ_NAND_STATUS_ENC_FINISH	BIT(2)
-#define JZ_NAND_STATUS_UNCOR_ERROR	BIT(1)
-#define JZ_NAND_STATUS_ERROR		BIT(0)
-
-#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
-#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
-#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
-
-#define JZ_NAND_MEM_CMD_OFFSET 0x08000
-#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
-
-struct jz_nand {
-	struct nand_chip chip;
-	void __iomem *base;
-	struct resource *mem;
-
-	unsigned char banks[JZ_NAND_NUM_BANKS];
-	void __iomem *bank_base[JZ_NAND_NUM_BANKS];
-	struct resource *bank_mem[JZ_NAND_NUM_BANKS];
-
-	int selected_bank;
-
-	struct gpio_desc *busy_gpio;
-	bool is_reading;
-};
-
-static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
-}
-
-static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	uint32_t ctrl;
-	int banknr;
-
-	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
-	ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
-
-	if (chipnr == -1) {
-		banknr = -1;
-	} else {
-		banknr = nand->banks[chipnr] - 1;
-		chip->IO_ADDR_R = nand->bank_base[banknr];
-		chip->IO_ADDR_W = nand->bank_base[banknr];
-	}
-	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-
-	nand->selected_bank = banknr;
-}
-
-static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
-{
-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	uint32_t reg;
-	void __iomem *bank_base = nand->bank_base[nand->selected_bank];
-
-	BUG_ON(nand->selected_bank < 0);
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
-		if (ctrl & NAND_ALE)
-			bank_base += JZ_NAND_MEM_ADDR_OFFSET;
-		else if (ctrl & NAND_CLE)
-			bank_base += JZ_NAND_MEM_CMD_OFFSET;
-		chip->IO_ADDR_W = bank_base;
-
-		reg = readl(nand->base + JZ_REG_NAND_CTRL);
-		if (ctrl & NAND_NCE)
-			reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
-		else
-			reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
-		writel(reg, nand->base + JZ_REG_NAND_CTRL);
-	}
-	if (dat != NAND_CMD_NONE)
-		writeb(dat, chip->IO_ADDR_W);
-}
-
-static int jz_nand_dev_ready(struct mtd_info *mtd)
-{
-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	return gpiod_get_value_cansleep(nand->busy_gpio);
-}
-
-static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
-{
-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	uint32_t reg;
-
-	writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-
-	reg |= JZ_NAND_ECC_CTRL_RESET;
-	reg |= JZ_NAND_ECC_CTRL_ENABLE;
-	reg |= JZ_NAND_ECC_CTRL_RS;
-
-	switch (mode) {
-	case NAND_ECC_READ:
-		reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
-		nand->is_reading = true;
-		break;
-	case NAND_ECC_WRITE:
-		reg |= JZ_NAND_ECC_CTRL_ENCODING;
-		nand->is_reading = false;
-		break;
-	default:
-		break;
-	}
-
-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-}
-
-static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
-	uint8_t *ecc_code)
-{
-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	uint32_t reg, status;
-	int i;
-	unsigned int timeout = 1000;
-	static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
-						0x8b, 0xff, 0xb7, 0x6f};
-
-	if (nand->is_reading)
-		return 0;
-
-	do {
-		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
-	} while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
-
-	if (timeout == 0)
-	    return -1;
-
-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-
-	for (i = 0; i < 9; ++i)
-		ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
-
-	/* If the written data is completly 0xff, we also want to write 0xff as
-	 * ecc, otherwise we will get in trouble when doing subpage writes. */
-	if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
-		memset(ecc_code, 0xff, 9);
-
-	return 0;
-}
-
-static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
-{
-	int offset = index & 0x7;
-	uint16_t data;
-
-	index += (index >> 3);
-
-	data = dat[index];
-	data |= dat[index+1] << 8;
-
-	mask ^= (data >> offset) & 0x1ff;
-	data &= ~(0x1ff << offset);
-	data |= (mask << offset);
-
-	dat[index] = data & 0xff;
-	dat[index+1] = (data >> 8) & 0xff;
-}
-
-static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
-	uint8_t *read_ecc, uint8_t *calc_ecc)
-{
-	struct jz_nand *nand = mtd_to_jz_nand(mtd);
-	int i, error_count, index;
-	uint32_t reg, status, error;
-	unsigned int timeout = 1000;
-
-	for (i = 0; i < 9; ++i)
-		writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
-
-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-	reg |= JZ_NAND_ECC_CTRL_PAR_READY;
-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-
-	do {
-		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
-	} while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
-
-	if (timeout == 0)
-		return -ETIMEDOUT;
-
-	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
-	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
-	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
-
-	if (status & JZ_NAND_STATUS_ERROR) {
-		if (status & JZ_NAND_STATUS_UNCOR_ERROR)
-			return -EBADMSG;
-
-		error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
-
-		for (i = 0; i < error_count; ++i) {
-			error = readl(nand->base + JZ_REG_NAND_ERR(i));
-			index = ((error >> 16) & 0x1ff) - 1;
-			if (index >= 0 && index < 512)
-				jz_nand_correct_data(dat, index, error & 0x1ff);
-		}
-
-		return error_count;
-	}
-
-	return 0;
-}
-
-static int jz_nand_ioremap_resource(struct platform_device *pdev,
-	const char *name, struct resource **res, void *__iomem *base)
-{
-	int ret;
-
-	*res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-	if (!*res) {
-		dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
-		ret = -ENXIO;
-		goto err;
-	}
-
-	*res = request_mem_region((*res)->start, resource_size(*res),
-				pdev->name);
-	if (!*res) {
-		dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
-		ret = -EBUSY;
-		goto err;
-	}
-
-	*base = ioremap((*res)->start, resource_size(*res));
-	if (!*base) {
-		dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
-		ret = -EBUSY;
-		goto err_release_mem;
-	}
-
-	return 0;
-
-err_release_mem:
-	release_mem_region((*res)->start, resource_size(*res));
-err:
-	*res = NULL;
-	*base = NULL;
-	return ret;
-}
-
-static inline void jz_nand_iounmap_resource(struct resource *res,
-					    void __iomem *base)
-{
-	iounmap(base);
-	release_mem_region(res->start, resource_size(res));
-}
-
-static int jz_nand_detect_bank(struct platform_device *pdev,
-			       struct jz_nand *nand, unsigned char bank,
-			       size_t chipnr, uint8_t *nand_maf_id,
-			       uint8_t *nand_dev_id)
-{
-	int ret;
-	char res_name[6];
-	uint32_t ctrl;
-	struct nand_chip *chip = &nand->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 id[2];
-
-	/* Request I/O resource. */
-	sprintf(res_name, "bank%d", bank);
-	ret = jz_nand_ioremap_resource(pdev, res_name,
-					&nand->bank_mem[bank - 1],
-					&nand->bank_base[bank - 1]);
-	if (ret)
-		return ret;
-
-	/* Enable chip in bank. */
-	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
-	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
-	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-
-	if (chipnr == 0) {
-		/* Detect first chip. */
-		ret = nand_scan_ident(mtd, 1, NULL);
-		if (ret)
-			goto notfound_id;
-
-		/* Retrieve the IDs from the first chip. */
-		chip->select_chip(mtd, 0);
-		nand_reset_op(chip);
-		nand_readid_op(chip, 0, id, sizeof(id));
-		*nand_maf_id = id[0];
-		*nand_dev_id = id[1];
-	} else {
-		/* Detect additional chip. */
-		chip->select_chip(mtd, chipnr);
-		nand_reset_op(chip);
-		nand_readid_op(chip, 0, id, sizeof(id));
-		if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
-			ret = -ENODEV;
-			goto notfound_id;
-		}
-
-		/* Update size of the MTD. */
-		chip->numchips++;
-		mtd->size += chip->chipsize;
-	}
-
-	dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
-	return 0;
-
-notfound_id:
-	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
-	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
-	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
-				 nand->bank_base[bank - 1]);
-	return ret;
-}
-
-static int jz_nand_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct jz_nand *nand;
-	struct nand_chip *chip;
-	struct mtd_info *mtd;
-	struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	size_t chipnr, bank_idx;
-	uint8_t nand_maf_id = 0, nand_dev_id = 0;
-
-	nand = kzalloc(sizeof(*nand), GFP_KERNEL);
-	if (!nand)
-		return -ENOMEM;
-
-	ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
-	if (ret)
-		goto err_free;
-
-	nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
-	if (IS_ERR(nand->busy_gpio)) {
-		ret = PTR_ERR(nand->busy_gpio);
-		dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
-		    ret);
-		goto err_iounmap_mmio;
-	}
-
-	chip		= &nand->chip;
-	mtd		= nand_to_mtd(chip);
-	mtd->dev.parent = &pdev->dev;
-	mtd->name	= "jz4740-nand";
-
-	chip->ecc.hwctl		= jz_nand_hwctl;
-	chip->ecc.calculate	= jz_nand_calculate_ecc_rs;
-	chip->ecc.correct	= jz_nand_correct_ecc_rs;
-	chip->ecc.mode		= NAND_ECC_HW_OOB_FIRST;
-	chip->ecc.size		= 512;
-	chip->ecc.bytes		= 9;
-	chip->ecc.strength	= 4;
-	chip->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
-
-	chip->chip_delay = 50;
-	chip->cmd_ctrl = jz_nand_cmd_ctrl;
-	chip->select_chip = jz_nand_select_chip;
-
-	if (nand->busy_gpio)
-		chip->dev_ready = jz_nand_dev_ready;
-
-	platform_set_drvdata(pdev, nand);
-
-	/* We are going to autodetect NAND chips in the banks specified in the
-	 * platform data. Although nand_scan_ident() can detect multiple chips,
-	 * it requires those chips to be numbered consecuitively, which is not
-	 * always the case for external memory banks. And a fixed chip-to-bank
-	 * mapping is not practical either, since for example Dingoo units
-	 * produced at different times have NAND chips in different banks.
-	 */
-	chipnr = 0;
-	for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
-		unsigned char bank;
-
-		/* If there is no platform data, look for NAND in bank 1,
-		 * which is the most likely bank since it is the only one
-		 * that can be booted from.
-		 */
-		bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
-		if (bank == 0)
-			break;
-		if (bank > JZ_NAND_NUM_BANKS) {
-			dev_warn(&pdev->dev,
-				"Skipping non-existing bank: %d\n", bank);
-			continue;
-		}
-		/* The detection routine will directly or indirectly call
-		 * jz_nand_select_chip(), so nand->banks has to contain the
-		 * bank we're checking.
-		 */
-		nand->banks[chipnr] = bank;
-		if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
-					&nand_maf_id, &nand_dev_id) == 0)
-			chipnr++;
-		else
-			nand->banks[chipnr] = 0;
-	}
-	if (chipnr == 0) {
-		dev_err(&pdev->dev, "No NAND chips found\n");
-		goto err_iounmap_mmio;
-	}
-
-	if (pdata && pdata->ident_callback) {
-		pdata->ident_callback(pdev, mtd, &pdata->partitions,
-					&pdata->num_partitions);
-	}
-
-	ret = nand_scan_tail(mtd);
-	if (ret) {
-		dev_err(&pdev->dev,  "Failed to scan NAND\n");
-		goto err_unclaim_banks;
-	}
-
-	ret = mtd_device_parse_register(mtd, NULL, NULL,
-					pdata ? pdata->partitions : NULL,
-					pdata ? pdata->num_partitions : 0);
-
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to add mtd device\n");
-		goto err_nand_release;
-	}
-
-	dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
-
-	return 0;
-
-err_nand_release:
-	nand_release(mtd);
-err_unclaim_banks:
-	while (chipnr--) {
-		unsigned char bank = nand->banks[chipnr];
-		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
-					 nand->bank_base[bank - 1]);
-	}
-	writel(0, nand->base + JZ_REG_NAND_CTRL);
-err_iounmap_mmio:
-	jz_nand_iounmap_resource(nand->mem, nand->base);
-err_free:
-	kfree(nand);
-	return ret;
-}
-
-static int jz_nand_remove(struct platform_device *pdev)
-{
-	struct jz_nand *nand = platform_get_drvdata(pdev);
-	size_t i;
-
-	nand_release(nand_to_mtd(&nand->chip));
-
-	/* Deassert and disable all chips */
-	writel(0, nand->base + JZ_REG_NAND_CTRL);
-
-	for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
-		unsigned char bank = nand->banks[i];
-		if (bank != 0) {
-			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
-						 nand->bank_base[bank - 1]);
-		}
-	}
-
-	jz_nand_iounmap_resource(nand->mem, nand->base);
-
-	kfree(nand);
-
-	return 0;
-}
-
-static struct platform_driver jz_nand_driver = {
-	.probe = jz_nand_probe,
-	.remove = jz_nand_remove,
-	.driver = {
-		.name = "jz4740-nand",
-	},
-};
-
-module_platform_driver(jz_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
-MODULE_ALIAS("platform:jz4740-nand");
diff --git a/drivers/mtd/nand/jz4780_bch.c b/drivers/mtd/nand/jz4780_bch.c
deleted file mode 100644
index 731c6051d91e..000000000000
--- a/drivers/mtd/nand/jz4780_bch.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * JZ4780 BCH controller
- *
- * Copyright (c) 2015 Imagination Technologies
- * Author: Alex Smith <alex.smith@imgtec.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/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include "jz4780_bch.h"
-
-#define BCH_BHCR			0x0
-#define BCH_BHCCR			0x8
-#define BCH_BHCNT			0xc
-#define BCH_BHDR			0x10
-#define BCH_BHPAR0			0x14
-#define BCH_BHERR0			0x84
-#define BCH_BHINT			0x184
-#define BCH_BHINTES			0x188
-#define BCH_BHINTEC			0x18c
-#define BCH_BHINTE			0x190
-
-#define BCH_BHCR_BSEL_SHIFT		4
-#define BCH_BHCR_BSEL_MASK		(0x7f << BCH_BHCR_BSEL_SHIFT)
-#define BCH_BHCR_ENCE			BIT(2)
-#define BCH_BHCR_INIT			BIT(1)
-#define BCH_BHCR_BCHE			BIT(0)
-
-#define BCH_BHCNT_PARITYSIZE_SHIFT	16
-#define BCH_BHCNT_PARITYSIZE_MASK	(0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
-#define BCH_BHCNT_BLOCKSIZE_SHIFT	0
-#define BCH_BHCNT_BLOCKSIZE_MASK	(0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
-
-#define BCH_BHERR_MASK_SHIFT		16
-#define BCH_BHERR_MASK_MASK		(0xffff << BCH_BHERR_MASK_SHIFT)
-#define BCH_BHERR_INDEX_SHIFT		0
-#define BCH_BHERR_INDEX_MASK		(0x7ff << BCH_BHERR_INDEX_SHIFT)
-
-#define BCH_BHINT_ERRC_SHIFT		24
-#define BCH_BHINT_ERRC_MASK		(0x7f << BCH_BHINT_ERRC_SHIFT)
-#define BCH_BHINT_TERRC_SHIFT		16
-#define BCH_BHINT_TERRC_MASK		(0x7f << BCH_BHINT_TERRC_SHIFT)
-#define BCH_BHINT_DECF			BIT(3)
-#define BCH_BHINT_ENCF			BIT(2)
-#define BCH_BHINT_UNCOR			BIT(1)
-#define BCH_BHINT_ERR			BIT(0)
-
-#define BCH_CLK_RATE			(200 * 1000 * 1000)
-
-/* Timeout for BCH calculation/correction. */
-#define BCH_TIMEOUT_US			100000
-
-struct jz4780_bch {
-	struct device *dev;
-	void __iomem *base;
-	struct clk *clk;
-	struct mutex lock;
-};
-
-static void jz4780_bch_init(struct jz4780_bch *bch,
-			    struct jz4780_bch_params *params, bool encode)
-{
-	u32 reg;
-
-	/* Clear interrupt status. */
-	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
-
-	/* Set up BCH count register. */
-	reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
-	reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
-	writel(reg, bch->base + BCH_BHCNT);
-
-	/* Initialise and enable BCH. */
-	reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
-	reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
-	if (encode)
-		reg |= BCH_BHCR_ENCE;
-	writel(reg, bch->base + BCH_BHCR);
-}
-
-static void jz4780_bch_disable(struct jz4780_bch *bch)
-{
-	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
-	writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
-}
-
-static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
-				  size_t size)
-{
-	size_t size32 = size / sizeof(u32);
-	size_t size8 = size % sizeof(u32);
-	const u32 *src32;
-	const u8 *src8;
-
-	src32 = (const u32 *)buf;
-	while (size32--)
-		writel(*src32++, bch->base + BCH_BHDR);
-
-	src8 = (const u8 *)src32;
-	while (size8--)
-		writeb(*src8++, bch->base + BCH_BHDR);
-}
-
-static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
-				   size_t size)
-{
-	size_t size32 = size / sizeof(u32);
-	size_t size8 = size % sizeof(u32);
-	u32 *dest32;
-	u8 *dest8;
-	u32 val, offset = 0;
-
-	dest32 = (u32 *)buf;
-	while (size32--) {
-		*dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
-		offset += sizeof(u32);
-	}
-
-	dest8 = (u8 *)dest32;
-	val = readl(bch->base + BCH_BHPAR0 + offset);
-	switch (size8) {
-	case 3:
-		dest8[2] = (val >> 16) & 0xff;
-	case 2:
-		dest8[1] = (val >> 8) & 0xff;
-	case 1:
-		dest8[0] = val & 0xff;
-		break;
-	}
-}
-
-static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
-				     u32 *status)
-{
-	u32 reg;
-	int ret;
-
-	/*
-	 * While we could use interrupts here and sleep until the operation
-	 * completes, the controller works fairly quickly (usually a few
-	 * microseconds) and so the overhead of sleeping until we get an
-	 * interrupt quite noticeably decreases performance.
-	 */
-	ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
-				 (reg & irq) == irq, 0, BCH_TIMEOUT_US);
-	if (ret)
-		return false;
-
-	if (status)
-		*status = reg;
-
-	writel(reg, bch->base + BCH_BHINT);
-	return true;
-}
-
-/**
- * jz4780_bch_calculate() - calculate ECC for a data buffer
- * @bch: BCH device.
- * @params: BCH parameters.
- * @buf: input buffer with raw data.
- * @ecc_code: output buffer with ECC.
- *
- * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
- * controller.
- */
-int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
-			 const u8 *buf, u8 *ecc_code)
-{
-	int ret = 0;
-
-	mutex_lock(&bch->lock);
-	jz4780_bch_init(bch, params, true);
-	jz4780_bch_write_data(bch, buf, params->size);
-
-	if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
-		jz4780_bch_read_parity(bch, ecc_code, params->bytes);
-	} else {
-		dev_err(bch->dev, "timed out while calculating ECC\n");
-		ret = -ETIMEDOUT;
-	}
-
-	jz4780_bch_disable(bch);
-	mutex_unlock(&bch->lock);
-	return ret;
-}
-EXPORT_SYMBOL(jz4780_bch_calculate);
-
-/**
- * jz4780_bch_correct() - detect and correct bit errors
- * @bch: BCH device.
- * @params: BCH parameters.
- * @buf: raw data read from the chip.
- * @ecc_code: ECC read from the chip.
- *
- * Given the raw data and the ECC read from the NAND device, detects and
- * corrects errors in the data.
- *
- * Return: the number of bit errors corrected, -EBADMSG if there are too many
- * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
- */
-int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
-		       u8 *buf, u8 *ecc_code)
-{
-	u32 reg, mask, index;
-	int i, ret, count;
-
-	mutex_lock(&bch->lock);
-
-	jz4780_bch_init(bch, params, false);
-	jz4780_bch_write_data(bch, buf, params->size);
-	jz4780_bch_write_data(bch, ecc_code, params->bytes);
-
-	if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
-		dev_err(bch->dev, "timed out while correcting data\n");
-		ret = -ETIMEDOUT;
-		goto out;
-	}
-
-	if (reg & BCH_BHINT_UNCOR) {
-		dev_warn(bch->dev, "uncorrectable ECC error\n");
-		ret = -EBADMSG;
-		goto out;
-	}
-
-	/* Correct any detected errors. */
-	if (reg & BCH_BHINT_ERR) {
-		count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
-		ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
-
-		for (i = 0; i < count; i++) {
-			reg = readl(bch->base + BCH_BHERR0 + (i * 4));
-			mask = (reg & BCH_BHERR_MASK_MASK) >>
-						BCH_BHERR_MASK_SHIFT;
-			index = (reg & BCH_BHERR_INDEX_MASK) >>
-						BCH_BHERR_INDEX_SHIFT;
-			buf[(index * 2) + 0] ^= mask;
-			buf[(index * 2) + 1] ^= mask >> 8;
-		}
-	} else {
-		ret = 0;
-	}
-
-out:
-	jz4780_bch_disable(bch);
-	mutex_unlock(&bch->lock);
-	return ret;
-}
-EXPORT_SYMBOL(jz4780_bch_correct);
-
-/**
- * jz4780_bch_get() - get the BCH controller device
- * @np: BCH device tree node.
- *
- * Gets the BCH controller device from the specified device tree node. The
- * device must be released with jz4780_bch_release() when it is no longer being
- * used.
- *
- * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
- * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
- */
-static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
-{
-	struct platform_device *pdev;
-	struct jz4780_bch *bch;
-
-	pdev = of_find_device_by_node(np);
-	if (!pdev || !platform_get_drvdata(pdev))
-		return ERR_PTR(-EPROBE_DEFER);
-
-	get_device(&pdev->dev);
-
-	bch = platform_get_drvdata(pdev);
-	clk_prepare_enable(bch->clk);
-
-	return bch;
-}
-
-/**
- * of_jz4780_bch_get() - get the BCH controller from a DT node
- * @of_node: the node that contains a bch-controller property.
- *
- * Get the bch-controller property from the given device tree
- * node and pass it to jz4780_bch_get to do the work.
- *
- * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
- * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
- */
-struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
-{
-	struct jz4780_bch *bch = NULL;
-	struct device_node *np;
-
-	np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
-
-	if (np) {
-		bch = jz4780_bch_get(np);
-		of_node_put(np);
-	}
-	return bch;
-}
-EXPORT_SYMBOL(of_jz4780_bch_get);
-
-/**
- * jz4780_bch_release() - release the BCH controller device
- * @bch: BCH device.
- */
-void jz4780_bch_release(struct jz4780_bch *bch)
-{
-	clk_disable_unprepare(bch->clk);
-	put_device(bch->dev);
-}
-EXPORT_SYMBOL(jz4780_bch_release);
-
-static int jz4780_bch_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct jz4780_bch *bch;
-	struct resource *res;
-
-	bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
-	if (!bch)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	bch->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(bch->base))
-		return PTR_ERR(bch->base);
-
-	jz4780_bch_disable(bch);
-
-	bch->clk = devm_clk_get(dev, NULL);
-	if (IS_ERR(bch->clk)) {
-		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk));
-		return PTR_ERR(bch->clk);
-	}
-
-	clk_set_rate(bch->clk, BCH_CLK_RATE);
-
-	mutex_init(&bch->lock);
-
-	bch->dev = dev;
-	platform_set_drvdata(pdev, bch);
-
-	return 0;
-}
-
-static const struct of_device_id jz4780_bch_dt_match[] = {
-	{ .compatible = "ingenic,jz4780-bch" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
-
-static struct platform_driver jz4780_bch_driver = {
-	.probe		= jz4780_bch_probe,
-	.driver	= {
-		.name	= "jz4780-bch",
-		.of_match_table = of_match_ptr(jz4780_bch_dt_match),
-	},
-};
-module_platform_driver(jz4780_bch_driver);
-
-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
-MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/jz4780_bch.h b/drivers/mtd/nand/jz4780_bch.h
deleted file mode 100644
index bf4718088a3a..000000000000
--- a/drivers/mtd/nand/jz4780_bch.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * JZ4780 BCH controller
- *
- * Copyright (c) 2015 Imagination Technologies
- * Author: Alex Smith <alex.smith@imgtec.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.
- */
-
-#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__
-#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
-
-#include <linux/types.h>
-
-struct device;
-struct device_node;
-struct jz4780_bch;
-
-/**
- * struct jz4780_bch_params - BCH parameters
- * @size: data bytes per ECC step.
- * @bytes: ECC bytes per step.
- * @strength: number of correctable bits per ECC step.
- */
-struct jz4780_bch_params {
-	int size;
-	int bytes;
-	int strength;
-};
-
-int jz4780_bch_calculate(struct jz4780_bch *bch,
-				struct jz4780_bch_params *params,
-				const u8 *buf, u8 *ecc_code);
-int jz4780_bch_correct(struct jz4780_bch *bch,
-			      struct jz4780_bch_params *params, u8 *buf,
-			      u8 *ecc_code);
-
-void jz4780_bch_release(struct jz4780_bch *bch);
-struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
-
-#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c
deleted file mode 100644
index e69f6ae4c539..000000000000
--- a/drivers/mtd/nand/jz4780_nand.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * JZ4780 NAND driver
- *
- * Copyright (c) 2015 Imagination Technologies
- * Author: Alex Smith <alex.smith@imgtec.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/delay.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/gpio/consumer.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/jz4780-nemc.h>
-
-#include "jz4780_bch.h"
-
-#define DRV_NAME	"jz4780-nand"
-
-#define OFFSET_DATA	0x00000000
-#define OFFSET_CMD	0x00400000
-#define OFFSET_ADDR	0x00800000
-
-/* Command delay when there is no R/B pin. */
-#define RB_DELAY_US	100
-
-struct jz4780_nand_cs {
-	unsigned int bank;
-	void __iomem *base;
-};
-
-struct jz4780_nand_controller {
-	struct device *dev;
-	struct jz4780_bch *bch;
-	struct nand_hw_control controller;
-	unsigned int num_banks;
-	struct list_head chips;
-	int selected;
-	struct jz4780_nand_cs cs[];
-};
-
-struct jz4780_nand_chip {
-	struct nand_chip chip;
-	struct list_head chip_list;
-
-	struct gpio_desc *busy_gpio;
-	struct gpio_desc *wp_gpio;
-	unsigned int reading: 1;
-};
-
-static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
-}
-
-static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
-{
-	return container_of(ctrl, struct jz4780_nand_controller, controller);
-}
-
-static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-	struct jz4780_nand_cs *cs;
-
-	/* Ensure the currently selected chip is deasserted. */
-	if (chipnr == -1 && nfc->selected >= 0) {
-		cs = &nfc->cs[nfc->selected];
-		jz4780_nemc_assert(nfc->dev, cs->bank, false);
-	}
-
-	nfc->selected = chipnr;
-}
-
-static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-				 unsigned int ctrl)
-{
-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-	struct jz4780_nand_cs *cs;
-
-	if (WARN_ON(nfc->selected < 0))
-		return;
-
-	cs = &nfc->cs[nfc->selected];
-
-	jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_ALE)
-		writeb(cmd, cs->base + OFFSET_ADDR);
-	else if (ctrl & NAND_CLE)
-		writeb(cmd, cs->base + OFFSET_CMD);
-}
-
-static int jz4780_nand_dev_ready(struct mtd_info *mtd)
-{
-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
-
-	return !gpiod_get_value_cansleep(nand->busy_gpio);
-}
-
-static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
-{
-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
-
-	nand->reading = (mode == NAND_ECC_READ);
-}
-
-static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
-				     u8 *ecc_code)
-{
-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-	struct jz4780_bch_params params;
-
-	/*
-	 * Don't need to generate the ECC when reading, BCH does it for us as
-	 * part of decoding/correction.
-	 */
-	if (nand->reading)
-		return 0;
-
-	params.size = nand->chip.ecc.size;
-	params.bytes = nand->chip.ecc.bytes;
-	params.strength = nand->chip.ecc.strength;
-
-	return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
-}
-
-static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
-				   u8 *read_ecc, u8 *calc_ecc)
-{
-	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
-	struct jz4780_bch_params params;
-
-	params.size = nand->chip.ecc.size;
-	params.bytes = nand->chip.ecc.bytes;
-	params.strength = nand->chip.ecc.strength;
-
-	return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
-}
-
-static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
-{
-	struct nand_chip *chip = &nand->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
-	int eccbytes;
-
-	chip->ecc.bytes = fls((1 + 8) * chip->ecc.size)	*
-				(chip->ecc.strength / 8);
-
-	switch (chip->ecc.mode) {
-	case NAND_ECC_HW:
-		if (!nfc->bch) {
-			dev_err(dev, "HW BCH selected, but BCH controller not found\n");
-			return -ENODEV;
-		}
-
-		chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
-		chip->ecc.calculate = jz4780_nand_ecc_calculate;
-		chip->ecc.correct = jz4780_nand_ecc_correct;
-		/* fall through */
-	case NAND_ECC_SOFT:
-		dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
-			(nfc->bch) ? "hardware BCH" : "software ECC",
-			chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
-		break;
-	case NAND_ECC_NONE:
-		dev_info(dev, "not using ECC\n");
-		break;
-	default:
-		dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
-		return -EINVAL;
-	}
-
-	/* The NAND core will generate the ECC layout for SW ECC */
-	if (chip->ecc.mode != NAND_ECC_HW)
-		return 0;
-
-	/* Generate ECC layout. ECC codes are right aligned in the OOB area. */
-	eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
-
-	if (eccbytes > mtd->oobsize - 2) {
-		dev_err(dev,
-			"invalid ECC config: required %d ECC bytes, but only %d are available",
-			eccbytes, mtd->oobsize - 2);
-		return -EINVAL;
-	}
-
-	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-
-	return 0;
-}
-
-static int jz4780_nand_init_chip(struct platform_device *pdev,
-				struct jz4780_nand_controller *nfc,
-				struct device_node *np,
-				unsigned int chipnr)
-{
-	struct device *dev = &pdev->dev;
-	struct jz4780_nand_chip *nand;
-	struct jz4780_nand_cs *cs;
-	struct resource *res;
-	struct nand_chip *chip;
-	struct mtd_info *mtd;
-	const __be32 *reg;
-	int ret = 0;
-
-	cs = &nfc->cs[chipnr];
-
-	reg = of_get_property(np, "reg", NULL);
-	if (!reg)
-		return -EINVAL;
-
-	cs->bank = be32_to_cpu(*reg);
-
-	jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
-	cs->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(cs->base))
-		return PTR_ERR(cs->base);
-
-	nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
-	if (!nand)
-		return -ENOMEM;
-
-	nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
-
-	if (IS_ERR(nand->busy_gpio)) {
-		ret = PTR_ERR(nand->busy_gpio);
-		dev_err(dev, "failed to request busy GPIO: %d\n", ret);
-		return ret;
-	} else if (nand->busy_gpio) {
-		nand->chip.dev_ready = jz4780_nand_dev_ready;
-	}
-
-	nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
-
-	if (IS_ERR(nand->wp_gpio)) {
-		ret = PTR_ERR(nand->wp_gpio);
-		dev_err(dev, "failed to request WP GPIO: %d\n", ret);
-		return ret;
-	}
-
-	chip = &nand->chip;
-	mtd = nand_to_mtd(chip);
-	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
-				   cs->bank);
-	if (!mtd->name)
-		return -ENOMEM;
-	mtd->dev.parent = dev;
-
-	chip->IO_ADDR_R = cs->base + OFFSET_DATA;
-	chip->IO_ADDR_W = cs->base + OFFSET_DATA;
-	chip->chip_delay = RB_DELAY_US;
-	chip->options = NAND_NO_SUBPAGE_WRITE;
-	chip->select_chip = jz4780_nand_select_chip;
-	chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
-	chip->ecc.mode = NAND_ECC_HW;
-	chip->controller = &nfc->controller;
-	nand_set_flash_node(chip, np);
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		return ret;
-
-	ret = jz4780_nand_init_ecc(nand, dev);
-	if (ret)
-		return ret;
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		return ret;
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret) {
-		nand_release(mtd);
-		return ret;
-	}
-
-	list_add_tail(&nand->chip_list, &nfc->chips);
-
-	return 0;
-}
-
-static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
-{
-	struct jz4780_nand_chip *chip;
-
-	while (!list_empty(&nfc->chips)) {
-		chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
-		nand_release(nand_to_mtd(&chip->chip));
-		list_del(&chip->chip_list);
-	}
-}
-
-static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc,
-				  struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np;
-	int i = 0;
-	int ret;
-	int num_chips = of_get_child_count(dev->of_node);
-
-	if (num_chips > nfc->num_banks) {
-		dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks);
-		return -EINVAL;
-	}
-
-	for_each_child_of_node(dev->of_node, np) {
-		ret = jz4780_nand_init_chip(pdev, nfc, np, i);
-		if (ret) {
-			jz4780_nand_cleanup_chips(nfc);
-			return ret;
-		}
-
-		i++;
-	}
-
-	return 0;
-}
-
-static int jz4780_nand_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	unsigned int num_banks;
-	struct jz4780_nand_controller *nfc;
-	int ret;
-
-	num_banks = jz4780_nemc_num_banks(dev);
-	if (num_banks == 0) {
-		dev_err(dev, "no banks found\n");
-		return -ENODEV;
-	}
-
-	nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
-	if (!nfc)
-		return -ENOMEM;
-
-	/*
-	 * Check for BCH HW before we call nand_scan_ident, to prevent us from
-	 * having to call it again if the BCH driver returns -EPROBE_DEFER.
-	 */
-	nfc->bch = of_jz4780_bch_get(dev->of_node);
-	if (IS_ERR(nfc->bch))
-		return PTR_ERR(nfc->bch);
-
-	nfc->dev = dev;
-	nfc->num_banks = num_banks;
-
-	nand_hw_control_init(&nfc->controller);
-	INIT_LIST_HEAD(&nfc->chips);
-
-	ret = jz4780_nand_init_chips(nfc, pdev);
-	if (ret) {
-		if (nfc->bch)
-			jz4780_bch_release(nfc->bch);
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, nfc);
-	return 0;
-}
-
-static int jz4780_nand_remove(struct platform_device *pdev)
-{
-	struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev);
-
-	if (nfc->bch)
-		jz4780_bch_release(nfc->bch);
-
-	jz4780_nand_cleanup_chips(nfc);
-
-	return 0;
-}
-
-static const struct of_device_id jz4780_nand_dt_match[] = {
-	{ .compatible = "ingenic,jz4780-nand" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match);
-
-static struct platform_driver jz4780_nand_driver = {
-	.probe		= jz4780_nand_probe,
-	.remove		= jz4780_nand_remove,
-	.driver	= {
-		.name	= DRV_NAME,
-		.of_match_table = of_match_ptr(jz4780_nand_dt_match),
-	},
-};
-module_platform_driver(jz4780_nand_driver);
-
-MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
-MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
deleted file mode 100644
index e357948a7505..000000000000
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * Driver for NAND MLC Controller in LPC32xx
- *
- * Author: Roland Stigge <stigge@antcom.de>
- *
- * Copyright © 2011 WORK Microwave GmbH
- * Copyright © 2011, 2012 Roland Stigge
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * NAND Flash Controller Operation:
- * - Read: Auto Decode
- * - Write: Auto Encode
- * - Tested Page Sizes: 2048, 4096
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/mtd/lpc32xx_mlc.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/mtd/nand_ecc.h>
-
-#define DRV_NAME "lpc32xx_mlc"
-
-/**********************************************************************
-* MLC NAND controller register offsets
-**********************************************************************/
-
-#define MLC_BUFF(x)			(x + 0x00000)
-#define MLC_DATA(x)			(x + 0x08000)
-#define MLC_CMD(x)			(x + 0x10000)
-#define MLC_ADDR(x)			(x + 0x10004)
-#define MLC_ECC_ENC_REG(x)		(x + 0x10008)
-#define MLC_ECC_DEC_REG(x)		(x + 0x1000C)
-#define MLC_ECC_AUTO_ENC_REG(x)		(x + 0x10010)
-#define MLC_ECC_AUTO_DEC_REG(x)		(x + 0x10014)
-#define MLC_RPR(x)			(x + 0x10018)
-#define MLC_WPR(x)			(x + 0x1001C)
-#define MLC_RUBP(x)			(x + 0x10020)
-#define MLC_ROBP(x)			(x + 0x10024)
-#define MLC_SW_WP_ADD_LOW(x)		(x + 0x10028)
-#define MLC_SW_WP_ADD_HIG(x)		(x + 0x1002C)
-#define MLC_ICR(x)			(x + 0x10030)
-#define MLC_TIME_REG(x)			(x + 0x10034)
-#define MLC_IRQ_MR(x)			(x + 0x10038)
-#define MLC_IRQ_SR(x)			(x + 0x1003C)
-#define MLC_LOCK_PR(x)			(x + 0x10044)
-#define MLC_ISR(x)			(x + 0x10048)
-#define MLC_CEH(x)			(x + 0x1004C)
-
-/**********************************************************************
-* MLC_CMD bit definitions
-**********************************************************************/
-#define MLCCMD_RESET			0xFF
-
-/**********************************************************************
-* MLC_ICR bit definitions
-**********************************************************************/
-#define MLCICR_WPROT			(1 << 3)
-#define MLCICR_LARGEBLOCK		(1 << 2)
-#define MLCICR_LONGADDR			(1 << 1)
-#define MLCICR_16BIT			(1 << 0)  /* unsupported by LPC32x0! */
-
-/**********************************************************************
-* MLC_TIME_REG bit definitions
-**********************************************************************/
-#define MLCTIMEREG_TCEA_DELAY(n)	(((n) & 0x03) << 24)
-#define MLCTIMEREG_BUSY_DELAY(n)	(((n) & 0x1F) << 19)
-#define MLCTIMEREG_NAND_TA(n)		(((n) & 0x07) << 16)
-#define MLCTIMEREG_RD_HIGH(n)		(((n) & 0x0F) << 12)
-#define MLCTIMEREG_RD_LOW(n)		(((n) & 0x0F) << 8)
-#define MLCTIMEREG_WR_HIGH(n)		(((n) & 0x0F) << 4)
-#define MLCTIMEREG_WR_LOW(n)		(((n) & 0x0F) << 0)
-
-/**********************************************************************
-* MLC_IRQ_MR and MLC_IRQ_SR bit definitions
-**********************************************************************/
-#define MLCIRQ_NAND_READY		(1 << 5)
-#define MLCIRQ_CONTROLLER_READY		(1 << 4)
-#define MLCIRQ_DECODE_FAILURE		(1 << 3)
-#define MLCIRQ_DECODE_ERROR		(1 << 2)
-#define MLCIRQ_ECC_READY		(1 << 1)
-#define MLCIRQ_WRPROT_FAULT		(1 << 0)
-
-/**********************************************************************
-* MLC_LOCK_PR bit definitions
-**********************************************************************/
-#define MLCLOCKPR_MAGIC			0xA25E
-
-/**********************************************************************
-* MLC_ISR bit definitions
-**********************************************************************/
-#define MLCISR_DECODER_FAILURE		(1 << 6)
-#define MLCISR_ERRORS			((1 << 4) | (1 << 5))
-#define MLCISR_ERRORS_DETECTED		(1 << 3)
-#define MLCISR_ECC_READY		(1 << 2)
-#define MLCISR_CONTROLLER_READY		(1 << 1)
-#define MLCISR_NAND_READY		(1 << 0)
-
-/**********************************************************************
-* MLC_CEH bit definitions
-**********************************************************************/
-#define MLCCEH_NORMAL			(1 << 0)
-
-struct lpc32xx_nand_cfg_mlc {
-	uint32_t tcea_delay;
-	uint32_t busy_delay;
-	uint32_t nand_ta;
-	uint32_t rd_high;
-	uint32_t rd_low;
-	uint32_t wr_high;
-	uint32_t wr_low;
-	int wp_gpio;
-	struct mtd_partition *parts;
-	unsigned num_parts;
-};
-
-static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-
-	if (section >= nand_chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = ((section + 1) * 16) - nand_chip->ecc.bytes;
-	oobregion->length = nand_chip->ecc.bytes;
-
-	return 0;
-}
-
-static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-
-	if (section >= nand_chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = 16 * section;
-	oobregion->length = 16 - nand_chip->ecc.bytes;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
-	.ecc = lpc32xx_ooblayout_ecc,
-	.free = lpc32xx_ooblayout_free,
-};
-
-static struct nand_bbt_descr lpc32xx_nand_bbt = {
-	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
-		   NAND_BBT_WRITE,
-	.pages = { 524224, 0, 0, 0, 0, 0, 0, 0 },
-};
-
-static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
-	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
-		   NAND_BBT_WRITE,
-	.pages = { 524160, 0, 0, 0, 0, 0, 0, 0 },
-};
-
-struct lpc32xx_nand_host {
-	struct nand_chip	nand_chip;
-	struct lpc32xx_mlc_platform_data *pdata;
-	struct clk		*clk;
-	void __iomem		*io_base;
-	int			irq;
-	struct lpc32xx_nand_cfg_mlc	*ncfg;
-	struct completion       comp_nand;
-	struct completion       comp_controller;
-	uint32_t llptr;
-	/*
-	 * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer
-	 */
-	dma_addr_t		oob_buf_phy;
-	/*
-	 * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer
-	 */
-	uint8_t			*oob_buf;
-	/* Physical address of DMA base address */
-	dma_addr_t		io_base_phy;
-
-	struct completion	comp_dma;
-	struct dma_chan		*dma_chan;
-	struct dma_slave_config	dma_slave_config;
-	struct scatterlist	sgl;
-	uint8_t			*dma_buf;
-	uint8_t			*dummy_buf;
-	int			mlcsubpages; /* number of 512bytes-subpages */
-};
-
-/*
- * Activate/Deactivate DMA Operation:
- *
- * Using the PL080 DMA Controller for transferring the 512 byte subpages
- * instead of doing readl() / writel() in a loop slows it down significantly.
- * Measurements via getnstimeofday() upon 512 byte subpage reads reveal:
- *
- * - readl() of 128 x 32 bits in a loop: ~20us
- * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us
- * - DMA read of 512 bytes (32 bit, no bursts): ~100us
- *
- * This applies to the transfer itself. In the DMA case: only the
- * wait_for_completion() (DMA setup _not_ included).
- *
- * Note that the 512 bytes subpage transfer is done directly from/to a
- * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a
- * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND
- * controller transferring data between its internal buffer to/from the NAND
- * chip.)
- *
- * Therefore, using the PL080 DMA is disabled by default, for now.
- *
- */
-static int use_dma;
-
-static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
-{
-	uint32_t clkrate, tmp;
-
-	/* Reset MLC controller */
-	writel(MLCCMD_RESET, MLC_CMD(host->io_base));
-	udelay(1000);
-
-	/* Get base clock for MLC block */
-	clkrate = clk_get_rate(host->clk);
-	if (clkrate == 0)
-		clkrate = 104000000;
-
-	/* Unlock MLC_ICR
-	 * (among others, will be locked again automatically) */
-	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
-
-	/* Configure MLC Controller: Large Block, 5 Byte Address */
-	tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR;
-	writel(tmp, MLC_ICR(host->io_base));
-
-	/* Unlock MLC_TIME_REG
-	 * (among others, will be locked again automatically) */
-	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
-
-	/* Compute clock setup values, see LPC and NAND manual */
-	tmp = 0;
-	tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1);
-	tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1);
-	tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1);
-	tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1);
-	tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low);
-	tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1);
-	tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low);
-	writel(tmp, MLC_TIME_REG(host->io_base));
-
-	/* Enable IRQ for CONTROLLER_READY and NAND_READY */
-	writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY,
-			MLC_IRQ_MR(host->io_base));
-
-	/* Normal nCE operation: nCE controlled by controller */
-	writel(MLCCEH_NORMAL, MLC_CEH(host->io_base));
-}
-
-/*
- * Hardware specific access to control lines
- */
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-				  unsigned int ctrl)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
-
-	if (cmd != NAND_CMD_NONE) {
-		if (ctrl & NAND_CLE)
-			writel(cmd, MLC_CMD(host->io_base));
-		else
-			writel(cmd, MLC_ADDR(host->io_base));
-	}
-}
-
-/*
- * Read Device Ready (NAND device _and_ controller ready)
- */
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
-
-	if ((readb(MLC_ISR(host->io_base)) &
-	     (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
-	    (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY))
-		return  1;
-
-	return 0;
-}
-
-static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
-{
-	uint8_t sr;
-
-	/* Clear interrupt flag by reading status */
-	sr = readb(MLC_IRQ_SR(host->io_base));
-	if (sr & MLCIRQ_NAND_READY)
-		complete(&host->comp_nand);
-	if (sr & MLCIRQ_CONTROLLER_READY)
-		complete(&host->comp_controller);
-
-	return IRQ_HANDLED;
-}
-
-static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
-		goto exit;
-
-	wait_for_completion(&host->comp_nand);
-
-	while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) {
-		/* Seems to be delayed sometimes by controller */
-		dev_dbg(&mtd->dev, "Warning: NAND not ready.\n");
-		cpu_relax();
-	}
-
-exit:
-	return NAND_STATUS_READY;
-}
-
-static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
-				       struct nand_chip *chip)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
-		goto exit;
-
-	wait_for_completion(&host->comp_controller);
-
-	while (!(readb(MLC_ISR(host->io_base)) &
-		 MLCISR_CONTROLLER_READY)) {
-		dev_dbg(&mtd->dev, "Warning: Controller not ready.\n");
-		cpu_relax();
-	}
-
-exit:
-	return NAND_STATUS_READY;
-}
-
-static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	lpc32xx_waitfunc_nand(mtd, chip);
-	lpc32xx_waitfunc_controller(mtd, chip);
-
-	return NAND_STATUS_READY;
-}
-
-/*
- * Enable NAND write protect
- */
-static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
-{
-	if (gpio_is_valid(host->ncfg->wp_gpio))
-		gpio_set_value(host->ncfg->wp_gpio, 0);
-}
-
-/*
- * Disable NAND write protect
- */
-static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
-{
-	if (gpio_is_valid(host->ncfg->wp_gpio))
-		gpio_set_value(host->ncfg->wp_gpio, 1);
-}
-
-static void lpc32xx_dma_complete_func(void *completion)
-{
-	complete(completion);
-}
-
-static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len,
-			    enum dma_transfer_direction dir)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	struct dma_async_tx_descriptor *desc;
-	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-	int res;
-
-	sg_init_one(&host->sgl, mem, len);
-
-	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
-			 DMA_BIDIRECTIONAL);
-	if (res != 1) {
-		dev_err(mtd->dev.parent, "Failed to map sg list\n");
-		return -ENXIO;
-	}
-	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
-				       flags);
-	if (!desc) {
-		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
-		goto out1;
-	}
-
-	init_completion(&host->comp_dma);
-	desc->callback = lpc32xx_dma_complete_func;
-	desc->callback_param = &host->comp_dma;
-
-	dmaengine_submit(desc);
-	dma_async_issue_pending(host->dma_chan);
-
-	wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
-
-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
-		     DMA_BIDIRECTIONAL);
-	return 0;
-out1:
-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
-		     DMA_BIDIRECTIONAL);
-	return -ENXIO;
-}
-
-static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			     uint8_t *buf, int oob_required, int page)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	int i, j;
-	uint8_t *oobbuf = chip->oob_poi;
-	uint32_t mlc_isr;
-	int res;
-	uint8_t *dma_buf;
-	bool dma_mapped;
-
-	if ((void *)buf <= high_memory) {
-		dma_buf = buf;
-		dma_mapped = true;
-	} else {
-		dma_buf = host->dma_buf;
-		dma_mapped = false;
-	}
-
-	/* Writing Command and Address */
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	/* For all sub-pages */
-	for (i = 0; i < host->mlcsubpages; i++) {
-		/* Start Auto Decode Command */
-		writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
-
-		/* Wait for Controller Ready */
-		lpc32xx_waitfunc_controller(mtd, chip);
-
-		/* Check ECC Error status */
-		mlc_isr = readl(MLC_ISR(host->io_base));
-		if (mlc_isr & MLCISR_DECODER_FAILURE) {
-			mtd->ecc_stats.failed++;
-			dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__);
-		} else if (mlc_isr & MLCISR_ERRORS_DETECTED) {
-			mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1;
-		}
-
-		/* Read 512 + 16 Bytes */
-		if (use_dma) {
-			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
-					       DMA_DEV_TO_MEM);
-			if (res)
-				return res;
-		} else {
-			for (j = 0; j < (512 >> 2); j++) {
-				*((uint32_t *)(buf)) =
-					readl(MLC_BUFF(host->io_base));
-				buf += 4;
-			}
-		}
-		for (j = 0; j < (16 >> 2); j++) {
-			*((uint32_t *)(oobbuf)) =
-				readl(MLC_BUFF(host->io_base));
-			oobbuf += 4;
-		}
-	}
-
-	if (use_dma && !dma_mapped)
-		memcpy(buf, dma_buf, mtd->writesize);
-
-	return 0;
-}
-
-static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
-				       struct nand_chip *chip,
-				       const uint8_t *buf, int oob_required,
-				       int page)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	const uint8_t *oobbuf = chip->oob_poi;
-	uint8_t *dma_buf = (uint8_t *)buf;
-	int res;
-	int i, j;
-
-	if (use_dma && (void *)buf >= high_memory) {
-		dma_buf = host->dma_buf;
-		memcpy(dma_buf, buf, mtd->writesize);
-	}
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	for (i = 0; i < host->mlcsubpages; i++) {
-		/* Start Encode */
-		writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
-
-		/* Write 512 + 6 Bytes to Buffer */
-		if (use_dma) {
-			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
-					       DMA_MEM_TO_DEV);
-			if (res)
-				return res;
-		} else {
-			for (j = 0; j < (512 >> 2); j++) {
-				writel(*((uint32_t *)(buf)),
-				       MLC_BUFF(host->io_base));
-				buf += 4;
-			}
-		}
-		writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base));
-		oobbuf += 4;
-		writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base));
-		oobbuf += 12;
-
-		/* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */
-		writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
-
-		/* Wait for Controller Ready */
-		lpc32xx_waitfunc_controller(mtd, chip);
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			    int page)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	/* Read whole page - necessary with MLC controller! */
-	lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
-
-	return 0;
-}
-
-static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			      int page)
-{
-	/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
-	return 0;
-}
-
-/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
-static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
-{
-	/* Always enabled! */
-}
-
-static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
-{
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
-	dma_cap_mask_t mask;
-
-	if (!host->pdata || !host->pdata->dma_filter) {
-		dev_err(mtd->dev.parent, "no DMA platform data\n");
-		return -ENOENT;
-	}
-
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
-					     "nand-mlc");
-	if (!host->dma_chan) {
-		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
-		return -EBUSY;
-	}
-
-	/*
-	 * Set direction to a sensible value even if the dmaengine driver
-	 * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x
-	 * driver criticizes it as "alien transfer direction".
-	 */
-	host->dma_slave_config.direction = DMA_DEV_TO_MEM;
-	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	host->dma_slave_config.src_maxburst = 128;
-	host->dma_slave_config.dst_maxburst = 128;
-	/* DMA controller does flow control: */
-	host->dma_slave_config.device_fc = false;
-	host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy);
-	host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy);
-	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
-		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
-		goto out1;
-	}
-
-	return 0;
-out1:
-	dma_release_channel(host->dma_chan);
-	return -ENXIO;
-}
-
-static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
-{
-	struct lpc32xx_nand_cfg_mlc *ncfg;
-	struct device_node *np = dev->of_node;
-
-	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
-	if (!ncfg)
-		return NULL;
-
-	of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
-	of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
-	of_property_read_u32(np, "nxp,nand-ta", &ncfg->nand_ta);
-	of_property_read_u32(np, "nxp,rd-high", &ncfg->rd_high);
-	of_property_read_u32(np, "nxp,rd-low", &ncfg->rd_low);
-	of_property_read_u32(np, "nxp,wr-high", &ncfg->wr_high);
-	of_property_read_u32(np, "nxp,wr-low", &ncfg->wr_low);
-
-	if (!ncfg->tcea_delay || !ncfg->busy_delay || !ncfg->nand_ta ||
-	    !ncfg->rd_high || !ncfg->rd_low || !ncfg->wr_high ||
-	    !ncfg->wr_low) {
-		dev_err(dev, "chip parameters not specified correctly\n");
-		return NULL;
-	}
-
-	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
-
-	return ncfg;
-}
-
-/*
- * Probe for NAND controller
- */
-static int lpc32xx_nand_probe(struct platform_device *pdev)
-{
-	struct lpc32xx_nand_host *host;
-	struct mtd_info *mtd;
-	struct nand_chip *nand_chip;
-	struct resource *rc;
-	int res;
-
-	/* Allocate memory for the device structure (and zero it) */
-	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
-	if (IS_ERR(host->io_base))
-		return PTR_ERR(host->io_base);
-	
-	host->io_base_phy = rc->start;
-
-	nand_chip = &host->nand_chip;
-	mtd = nand_to_mtd(nand_chip);
-	if (pdev->dev.of_node)
-		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
-	if (!host->ncfg) {
-		dev_err(&pdev->dev,
-			"Missing or bad NAND config from device tree\n");
-		return -ENOENT;
-	}
-	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
-		return -EPROBE_DEFER;
-	if (gpio_is_valid(host->ncfg->wp_gpio) &&
-			gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
-		dev_err(&pdev->dev, "GPIO not available\n");
-		return -EBUSY;
-	}
-	lpc32xx_wp_disable(host);
-
-	host->pdata = dev_get_platdata(&pdev->dev);
-
-	/* link the private data structures */
-	nand_set_controller_data(nand_chip, host);
-	nand_set_flash_node(nand_chip, pdev->dev.of_node);
-	mtd->dev.parent = &pdev->dev;
-
-	/* Get NAND clock */
-	host->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(host->clk)) {
-		dev_err(&pdev->dev, "Clock initialization failure\n");
-		res = -ENOENT;
-		goto err_exit1;
-	}
-	res = clk_prepare_enable(host->clk);
-	if (res)
-		goto err_put_clk;
-
-	nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
-	nand_chip->dev_ready = lpc32xx_nand_device_ready;
-	nand_chip->chip_delay = 25; /* us */
-	nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
-	nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
-
-	/* Init NAND controller */
-	lpc32xx_nand_setup(host);
-
-	platform_set_drvdata(pdev, host);
-
-	/* Initialize function pointers */
-	nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
-	nand_chip->ecc.read_page_raw = lpc32xx_read_page;
-	nand_chip->ecc.read_page = lpc32xx_read_page;
-	nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel;
-	nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel;
-	nand_chip->ecc.write_oob = lpc32xx_write_oob;
-	nand_chip->ecc.read_oob = lpc32xx_read_oob;
-	nand_chip->ecc.strength = 4;
-	nand_chip->ecc.bytes = 10;
-	nand_chip->waitfunc = lpc32xx_waitfunc;
-
-	nand_chip->options = NAND_NO_SUBPAGE_WRITE;
-	nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
-	nand_chip->bbt_td = &lpc32xx_nand_bbt;
-	nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
-
-	if (use_dma) {
-		res = lpc32xx_dma_setup(host);
-		if (res) {
-			res = -EIO;
-			goto err_exit2;
-		}
-	}
-
-	/*
-	 * Scan to find existance of the device and
-	 * Get the type of NAND device SMALL block or LARGE block
-	 */
-	res = nand_scan_ident(mtd, 1, NULL);
-	if (res)
-		goto err_exit3;
-
-	host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
-	if (!host->dma_buf) {
-		res = -ENOMEM;
-		goto err_exit3;
-	}
-
-	host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
-	if (!host->dummy_buf) {
-		res = -ENOMEM;
-		goto err_exit3;
-	}
-
-	nand_chip->ecc.mode = NAND_ECC_HW;
-	nand_chip->ecc.size = 512;
-	mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
-	host->mlcsubpages = mtd->writesize / 512;
-
-	/* initially clear interrupt status */
-	readb(MLC_IRQ_SR(host->io_base));
-
-	init_completion(&host->comp_nand);
-	init_completion(&host->comp_controller);
-
-	host->irq = platform_get_irq(pdev, 0);
-	if (host->irq < 0) {
-		dev_err(&pdev->dev, "failed to get platform irq\n");
-		res = -EINVAL;
-		goto err_exit3;
-	}
-
-	if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
-			IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
-		dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
-		res = -ENXIO;
-		goto err_exit3;
-	}
-
-	/*
-	 * Fills out all the uninitialized function pointers with the defaults
-	 * And scans for a bad block table if appropriate.
-	 */
-	res = nand_scan_tail(mtd);
-	if (res)
-		goto err_exit4;
-
-	mtd->name = DRV_NAME;
-
-	res = mtd_device_register(mtd, host->ncfg->parts,
-				  host->ncfg->num_parts);
-	if (!res)
-		return res;
-
-	nand_release(mtd);
-
-err_exit4:
-	free_irq(host->irq, host);
-err_exit3:
-	if (use_dma)
-		dma_release_channel(host->dma_chan);
-err_exit2:
-	clk_disable_unprepare(host->clk);
-err_put_clk:
-	clk_put(host->clk);
-err_exit1:
-	lpc32xx_wp_enable(host);
-	gpio_free(host->ncfg->wp_gpio);
-
-	return res;
-}
-
-/*
- * Remove NAND device
- */
-static int lpc32xx_nand_remove(struct platform_device *pdev)
-{
-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
-
-	nand_release(mtd);
-	free_irq(host->irq, host);
-	if (use_dma)
-		dma_release_channel(host->dma_chan);
-
-	clk_disable_unprepare(host->clk);
-	clk_put(host->clk);
-
-	lpc32xx_wp_enable(host);
-	gpio_free(host->ncfg->wp_gpio);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int lpc32xx_nand_resume(struct platform_device *pdev)
-{
-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-	int ret;
-
-	/* Re-enable NAND clock */
-	ret = clk_prepare_enable(host->clk);
-	if (ret)
-		return ret;
-
-	/* Fresh init of NAND controller */
-	lpc32xx_nand_setup(host);
-
-	/* Disable write protect */
-	lpc32xx_wp_disable(host);
-
-	return 0;
-}
-
-static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
-{
-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-
-	/* Enable write protect for safety */
-	lpc32xx_wp_enable(host);
-
-	/* Disable clock */
-	clk_disable_unprepare(host->clk);
-	return 0;
-}
-
-#else
-#define lpc32xx_nand_resume NULL
-#define lpc32xx_nand_suspend NULL
-#endif
-
-static const struct of_device_id lpc32xx_nand_match[] = {
-	{ .compatible = "nxp,lpc3220-mlc" },
-	{ /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
-
-static struct platform_driver lpc32xx_nand_driver = {
-	.probe		= lpc32xx_nand_probe,
-	.remove		= lpc32xx_nand_remove,
-	.resume		= lpc32xx_nand_resume,
-	.suspend	= lpc32xx_nand_suspend,
-	.driver		= {
-		.name	= DRV_NAME,
-		.of_match_table = lpc32xx_nand_match,
-	},
-};
-
-module_platform_driver(lpc32xx_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
-MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller");
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
deleted file mode 100644
index 5f7cc6da0a7f..000000000000
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * NXP LPC32XX NAND SLC driver
- *
- * Authors:
- *    Kevin Wells <kevin.wells@nxp.com>
- *    Roland Stigge <stigge@antcom.de>
- *
- * Copyright © 2011 NXP Semiconductors
- * Copyright © 2012 Roland Stigge
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/mtd/lpc32xx_slc.h>
-
-#define LPC32XX_MODNAME		"lpc32xx-nand"
-
-/**********************************************************************
-* SLC NAND controller register offsets
-**********************************************************************/
-
-#define SLC_DATA(x)		(x + 0x000)
-#define SLC_ADDR(x)		(x + 0x004)
-#define SLC_CMD(x)		(x + 0x008)
-#define SLC_STOP(x)		(x + 0x00C)
-#define SLC_CTRL(x)		(x + 0x010)
-#define SLC_CFG(x)		(x + 0x014)
-#define SLC_STAT(x)		(x + 0x018)
-#define SLC_INT_STAT(x)		(x + 0x01C)
-#define SLC_IEN(x)		(x + 0x020)
-#define SLC_ISR(x)		(x + 0x024)
-#define SLC_ICR(x)		(x + 0x028)
-#define SLC_TAC(x)		(x + 0x02C)
-#define SLC_TC(x)		(x + 0x030)
-#define SLC_ECC(x)		(x + 0x034)
-#define SLC_DMA_DATA(x)		(x + 0x038)
-
-/**********************************************************************
-* slc_ctrl register definitions
-**********************************************************************/
-#define SLCCTRL_SW_RESET	(1 << 2) /* Reset the NAND controller bit */
-#define SLCCTRL_ECC_CLEAR	(1 << 1) /* Reset ECC bit */
-#define SLCCTRL_DMA_START	(1 << 0) /* Start DMA channel bit */
-
-/**********************************************************************
-* slc_cfg register definitions
-**********************************************************************/
-#define SLCCFG_CE_LOW		(1 << 5) /* Force CE low bit */
-#define SLCCFG_DMA_ECC		(1 << 4) /* Enable DMA ECC bit */
-#define SLCCFG_ECC_EN		(1 << 3) /* ECC enable bit */
-#define SLCCFG_DMA_BURST	(1 << 2) /* DMA burst bit */
-#define SLCCFG_DMA_DIR		(1 << 1) /* DMA write(0)/read(1) bit */
-#define SLCCFG_WIDTH		(1 << 0) /* External device width, 0=8bit */
-
-/**********************************************************************
-* slc_stat register definitions
-**********************************************************************/
-#define SLCSTAT_DMA_FIFO	(1 << 2) /* DMA FIFO has data bit */
-#define SLCSTAT_SLC_FIFO	(1 << 1) /* SLC FIFO has data bit */
-#define SLCSTAT_NAND_READY	(1 << 0) /* NAND device is ready bit */
-
-/**********************************************************************
-* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
-**********************************************************************/
-#define SLCSTAT_INT_TC		(1 << 1) /* Transfer count bit */
-#define SLCSTAT_INT_RDY_EN	(1 << 0) /* Ready interrupt bit */
-
-/**********************************************************************
-* slc_tac register definitions
-**********************************************************************/
-/* Computation of clock cycles on basis of controller and device clock rates */
-#define SLCTAC_CLOCKS(c, n, s)	(min_t(u32, DIV_ROUND_UP(c, n) - 1, 0xF) << s)
-
-/* Clock setting for RDY write sample wait time in 2*n clocks */
-#define SLCTAC_WDR(n)		(((n) & 0xF) << 28)
-/* Write pulse width in clock cycles, 1 to 16 clocks */
-#define SLCTAC_WWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 24))
-/* Write hold time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_WHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 20))
-/* Write setup time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_WSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 16))
-/* Clock setting for RDY read sample wait time in 2*n clocks */
-#define SLCTAC_RDR(n)		(((n) & 0xF) << 12)
-/* Read pulse width in clock cycles, 1 to 16 clocks */
-#define SLCTAC_RWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 8))
-/* Read hold time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_RHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 4))
-/* Read setup time of control and data signals, 1 to 16 clocks */
-#define SLCTAC_RSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 0))
-
-/**********************************************************************
-* slc_ecc register definitions
-**********************************************************************/
-/* ECC line party fetch macro */
-#define SLCECC_TO_LINEPAR(n)	(((n) >> 6) & 0x7FFF)
-#define SLCECC_TO_COLPAR(n)	((n) & 0x3F)
-
-/*
- * DMA requires storage space for the DMA local buffer and the hardware ECC
- * storage area. The DMA local buffer is only used if DMA mapping fails
- * during runtime.
- */
-#define LPC32XX_DMA_DATA_SIZE		4096
-#define LPC32XX_ECC_SAVE_SIZE		((4096 / 256) * 4)
-
-/* Number of bytes used for ECC stored in NAND per 256 bytes */
-#define LPC32XX_SLC_DEV_ECC_BYTES	3
-
-/*
- * If the NAND base clock frequency can't be fetched, this frequency will be
- * used instead as the base. This rate is used to setup the timing registers
- * used for NAND accesses.
- */
-#define LPC32XX_DEF_BUS_RATE		133250000
-
-/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
-#define LPC32XX_DMA_TIMEOUT		100
-
-/*
- * NAND ECC Layout for small page NAND devices
- * Note: For large and huge page devices, the default layouts are used
- */
-static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->length = 6;
-	oobregion->offset = 10;
-
-	return 0;
-}
-
-static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	if (section > 1)
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->offset = 0;
-		oobregion->length = 4;
-	} else {
-		oobregion->offset = 6;
-		oobregion->length = 4;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
-	.ecc = lpc32xx_ooblayout_ecc,
-	.free = lpc32xx_ooblayout_free,
-};
-
-static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
-static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
-
-/*
- * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
- * Note: Large page devices used the default layout
- */
-static struct nand_bbt_descr bbt_smallpage_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	0,
-	.len = 4,
-	.veroffs = 6,
-	.maxblocks = 4,
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	0,
-	.len = 4,
-	.veroffs = 6,
-	.maxblocks = 4,
-	.pattern = mirror_pattern
-};
-
-/*
- * NAND platform configuration structure
- */
-struct lpc32xx_nand_cfg_slc {
-	uint32_t wdr_clks;
-	uint32_t wwidth;
-	uint32_t whold;
-	uint32_t wsetup;
-	uint32_t rdr_clks;
-	uint32_t rwidth;
-	uint32_t rhold;
-	uint32_t rsetup;
-	int wp_gpio;
-	struct mtd_partition *parts;
-	unsigned num_parts;
-};
-
-struct lpc32xx_nand_host {
-	struct nand_chip	nand_chip;
-	struct lpc32xx_slc_platform_data *pdata;
-	struct clk		*clk;
-	void __iomem		*io_base;
-	struct lpc32xx_nand_cfg_slc *ncfg;
-
-	struct completion	comp;
-	struct dma_chan		*dma_chan;
-	uint32_t		dma_buf_len;
-	struct dma_slave_config	dma_slave_config;
-	struct scatterlist	sgl;
-
-	/*
-	 * DMA and CPU addresses of ECC work area and data buffer
-	 */
-	uint32_t		*ecc_buf;
-	uint8_t			*data_buf;
-	dma_addr_t		io_base_dma;
-};
-
-static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
-{
-	uint32_t clkrate, tmp;
-
-	/* Reset SLC controller */
-	writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
-	udelay(1000);
-
-	/* Basic setup */
-	writel(0, SLC_CFG(host->io_base));
-	writel(0, SLC_IEN(host->io_base));
-	writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
-		SLC_ICR(host->io_base));
-
-	/* Get base clock for SLC block */
-	clkrate = clk_get_rate(host->clk);
-	if (clkrate == 0)
-		clkrate = LPC32XX_DEF_BUS_RATE;
-
-	/* Compute clock setup values */
-	tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
-		SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) |
-		SLCTAC_WHOLD(clkrate, host->ncfg->whold) |
-		SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) |
-		SLCTAC_RDR(host->ncfg->rdr_clks) |
-		SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) |
-		SLCTAC_RHOLD(clkrate, host->ncfg->rhold) |
-		SLCTAC_RSETUP(clkrate, host->ncfg->rsetup);
-	writel(tmp, SLC_TAC(host->io_base));
-}
-
-/*
- * Hardware specific access to control lines
- */
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-	unsigned int ctrl)
-{
-	uint32_t tmp;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	/* Does CE state need to be changed? */
-	tmp = readl(SLC_CFG(host->io_base));
-	if (ctrl & NAND_NCE)
-		tmp |= SLCCFG_CE_LOW;
-	else
-		tmp &= ~SLCCFG_CE_LOW;
-	writel(tmp, SLC_CFG(host->io_base));
-
-	if (cmd != NAND_CMD_NONE) {
-		if (ctrl & NAND_CLE)
-			writel(cmd, SLC_CMD(host->io_base));
-		else
-			writel(cmd, SLC_ADDR(host->io_base));
-	}
-}
-
-/*
- * Read the Device Ready pin
- */
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	int rdy = 0;
-
-	if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
-		rdy = 1;
-
-	return rdy;
-}
-
-/*
- * Enable NAND write protect
- */
-static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
-{
-	if (gpio_is_valid(host->ncfg->wp_gpio))
-		gpio_set_value(host->ncfg->wp_gpio, 0);
-}
-
-/*
- * Disable NAND write protect
- */
-static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
-{
-	if (gpio_is_valid(host->ncfg->wp_gpio))
-		gpio_set_value(host->ncfg->wp_gpio, 1);
-}
-
-/*
- * Prepares SLC for transfers with H/W ECC enabled
- */
-static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
-{
-	/* Hardware ECC is enabled automatically in hardware as needed */
-}
-
-/*
- * Calculates the ECC for the data
- */
-static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
-				      const unsigned char *buf,
-				      unsigned char *code)
-{
-	/*
-	 * ECC is calculated automatically in hardware during syndrome read
-	 * and write operations, so it doesn't need to be calculated here.
-	 */
-	return 0;
-}
-
-/*
- * Read a single byte from NAND device
- */
-static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	return (uint8_t)readl(SLC_DATA(host->io_base));
-}
-
-/*
- * Simple device read without ECC
- */
-static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	/* Direct device read with no ECC */
-	while (len-- > 0)
-		*buf++ = (uint8_t)readl(SLC_DATA(host->io_base));
-}
-
-/*
- * Simple device write without ECC
- */
-static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-
-	/* Direct device write with no ECC */
-	while (len-- > 0)
-		writel((uint32_t)*buf++, SLC_DATA(host->io_base));
-}
-
-/*
- * Read the OOB data from the device without ECC using FIFO method
- */
-static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
-					  struct nand_chip *chip, int page)
-{
-	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-}
-
-/*
- * Write the OOB data to the device without ECC using FIFO method
- */
-static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
-	struct nand_chip *chip, int page)
-{
-	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
-				 mtd->oobsize);
-}
-
-/*
- * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
- */
-static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count)
-{
-	int i;
-
-	for (i = 0; i < (count * 3); i += 3) {
-		uint32_t ce = ecc[i / 3];
-		ce = ~(ce << 2) & 0xFFFFFF;
-		spare[i + 2] = (uint8_t)(ce & 0xFF);
-		ce >>= 8;
-		spare[i + 1] = (uint8_t)(ce & 0xFF);
-		ce >>= 8;
-		spare[i] = (uint8_t)(ce & 0xFF);
-	}
-}
-
-static void lpc32xx_dma_complete_func(void *completion)
-{
-	complete(completion);
-}
-
-static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
-			    void *mem, int len, enum dma_transfer_direction dir)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	struct dma_async_tx_descriptor *desc;
-	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-	int res;
-
-	host->dma_slave_config.direction = dir;
-	host->dma_slave_config.src_addr = dma;
-	host->dma_slave_config.dst_addr = dma;
-	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	host->dma_slave_config.src_maxburst = 4;
-	host->dma_slave_config.dst_maxburst = 4;
-	/* DMA controller does flow control: */
-	host->dma_slave_config.device_fc = false;
-	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
-		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
-		return -ENXIO;
-	}
-
-	sg_init_one(&host->sgl, mem, len);
-
-	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
-			 DMA_BIDIRECTIONAL);
-	if (res != 1) {
-		dev_err(mtd->dev.parent, "Failed to map sg list\n");
-		return -ENXIO;
-	}
-	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
-				       flags);
-	if (!desc) {
-		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
-		goto out1;
-	}
-
-	init_completion(&host->comp);
-	desc->callback = lpc32xx_dma_complete_func;
-	desc->callback_param = &host->comp;
-
-	dmaengine_submit(desc);
-	dma_async_issue_pending(host->dma_chan);
-
-	wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
-
-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
-		     DMA_BIDIRECTIONAL);
-
-	return 0;
-out1:
-	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
-		     DMA_BIDIRECTIONAL);
-	return -ENXIO;
-}
-
-/*
- * DMA read/write transfers with ECC support
- */
-static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
-			int read)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	int i, status = 0;
-	unsigned long timeout;
-	int res;
-	enum dma_transfer_direction dir =
-		read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
-	uint8_t *dma_buf;
-	bool dma_mapped;
-
-	if ((void *)buf <= high_memory) {
-		dma_buf = buf;
-		dma_mapped = true;
-	} else {
-		dma_buf = host->data_buf;
-		dma_mapped = false;
-		if (!read)
-			memcpy(host->data_buf, buf, mtd->writesize);
-	}
-
-	if (read) {
-		writel(readl(SLC_CFG(host->io_base)) |
-		       SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
-		       SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
-	} else {
-		writel((readl(SLC_CFG(host->io_base)) |
-			SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
-		       ~SLCCFG_DMA_DIR,
-			SLC_CFG(host->io_base));
-	}
-
-	/* Clear initial ECC */
-	writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
-
-	/* Transfer size is data area only */
-	writel(mtd->writesize, SLC_TC(host->io_base));
-
-	/* Start transfer in the NAND controller */
-	writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
-	       SLC_CTRL(host->io_base));
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		/* Data */
-		res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
-				       dma_buf + i * chip->ecc.size,
-				       mtd->writesize / chip->ecc.steps, dir);
-		if (res)
-			return res;
-
-		/* Always _read_ ECC */
-		if (i == chip->ecc.steps - 1)
-			break;
-		if (!read) /* ECC availability delayed on write */
-			udelay(10);
-		res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
-				       &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
-		if (res)
-			return res;
-	}
-
-	/*
-	 * According to NXP, the DMA can be finished here, but the NAND
-	 * controller may still have buffered data. After porting to using the
-	 * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
-	 * appears to be always true, according to tests. Keeping the check for
-	 * safety reasons for now.
-	 */
-	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
-		dev_warn(mtd->dev.parent, "FIFO not empty!\n");
-		timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
-		while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
-		       time_before(jiffies, timeout))
-			cpu_relax();
-		if (!time_before(jiffies, timeout)) {
-			dev_err(mtd->dev.parent, "FIFO held data too long\n");
-			status = -EIO;
-		}
-	}
-
-	/* Read last calculated ECC value */
-	if (!read)
-		udelay(10);
-	host->ecc_buf[chip->ecc.steps - 1] =
-		readl(SLC_ECC(host->io_base));
-
-	/* Flush DMA */
-	dmaengine_terminate_all(host->dma_chan);
-
-	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
-	    readl(SLC_TC(host->io_base))) {
-		/* Something is left in the FIFO, something is wrong */
-		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
-		status = -EIO;
-	}
-
-	/* Stop DMA & HW ECC */
-	writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
-	       SLC_CTRL(host->io_base));
-	writel(readl(SLC_CFG(host->io_base)) &
-	       ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
-		 SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
-
-	if (!dma_mapped && read)
-		memcpy(buf, host->data_buf, mtd->writesize);
-
-	return status;
-}
-
-/*
- * Read the data and OOB data from the device, use ECC correction with the
- * data, disable ECC for the OOB data
- */
-static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
-					   struct nand_chip *chip, uint8_t *buf,
-					   int oob_required, int page)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	struct mtd_oob_region oobregion = { };
-	int stat, i, status, error;
-	uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
-
-	/* Issue read command */
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	/* Read data and oob, calculate ECC */
-	status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
-
-	/* Get OOB data */
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	/* Convert to stored ECC format */
-	lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
-
-	/* Pointer to ECC data retrieved from NAND spare area */
-	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
-	if (error)
-		return error;
-
-	oobecc = chip->oob_poi + oobregion.offset;
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		stat = chip->ecc.correct(mtd, buf, oobecc,
-					 &tmpecc[i * chip->ecc.bytes]);
-		if (stat < 0)
-			mtd->ecc_stats.failed++;
-		else
-			mtd->ecc_stats.corrected += stat;
-
-		buf += chip->ecc.size;
-		oobecc += chip->ecc.bytes;
-	}
-
-	return status;
-}
-
-/*
- * Read the data and OOB data from the device, no ECC correction with the
- * data or OOB data
- */
-static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
-					       struct nand_chip *chip,
-					       uint8_t *buf, int oob_required,
-					       int page)
-{
-	/* Issue read command */
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	/* Raw reads can just use the FIFO interface */
-	chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return 0;
-}
-
-/*
- * Write the data and OOB data to the device, use ECC with the data,
- * disable ECC for the OOB data
- */
-static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
-					    struct nand_chip *chip,
-					    const uint8_t *buf,
-					    int oob_required, int page)
-{
-	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
-	struct mtd_oob_region oobregion = { };
-	uint8_t *pb;
-	int error;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	/* Write data, calculate ECC on outbound data */
-	error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
-	if (error)
-		return error;
-
-	/*
-	 * The calculated ECC needs some manual work done to it before
-	 * committing it to NAND. Process the calculated ECC and place
-	 * the resultant values directly into the OOB buffer. */
-	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
-	if (error)
-		return error;
-
-	pb = chip->oob_poi + oobregion.offset;
-	lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
-
-	/* Write ECC data to device */
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-/*
- * Write the data and OOB data to the device, no ECC correction with the
- * data or OOB data
- */
-static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
-						struct nand_chip *chip,
-						const uint8_t *buf,
-						int oob_required, int page)
-{
-	/* Raw writes can just use the FIFO interface */
-	nand_prog_page_begin_op(chip, page, 0, buf,
-				chip->ecc.size * chip->ecc.steps);
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
-{
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
-	dma_cap_mask_t mask;
-
-	if (!host->pdata || !host->pdata->dma_filter) {
-		dev_err(mtd->dev.parent, "no DMA platform data\n");
-		return -ENOENT;
-	}
-
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
-					     "nand-slc");
-	if (!host->dma_chan) {
-		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
-{
-	struct lpc32xx_nand_cfg_slc *ncfg;
-	struct device_node *np = dev->of_node;
-
-	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
-	if (!ncfg)
-		return NULL;
-
-	of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
-	of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
-	of_property_read_u32(np, "nxp,whold", &ncfg->whold);
-	of_property_read_u32(np, "nxp,wsetup", &ncfg->wsetup);
-	of_property_read_u32(np, "nxp,rdr-clks", &ncfg->rdr_clks);
-	of_property_read_u32(np, "nxp,rwidth", &ncfg->rwidth);
-	of_property_read_u32(np, "nxp,rhold", &ncfg->rhold);
-	of_property_read_u32(np, "nxp,rsetup", &ncfg->rsetup);
-
-	if (!ncfg->wdr_clks || !ncfg->wwidth || !ncfg->whold ||
-	    !ncfg->wsetup || !ncfg->rdr_clks || !ncfg->rwidth ||
-	    !ncfg->rhold || !ncfg->rsetup) {
-		dev_err(dev, "chip parameters not specified correctly\n");
-		return NULL;
-	}
-
-	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
-
-	return ncfg;
-}
-
-/*
- * Probe for NAND controller
- */
-static int lpc32xx_nand_probe(struct platform_device *pdev)
-{
-	struct lpc32xx_nand_host *host;
-	struct mtd_info *mtd;
-	struct nand_chip *chip;
-	struct resource *rc;
-	int res;
-
-	/* Allocate memory for the device structure (and zero it) */
-	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
-	if (IS_ERR(host->io_base))
-		return PTR_ERR(host->io_base);
-
-	host->io_base_dma = rc->start;
-	if (pdev->dev.of_node)
-		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
-	if (!host->ncfg) {
-		dev_err(&pdev->dev,
-			"Missing or bad NAND config from device tree\n");
-		return -ENOENT;
-	}
-	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
-		return -EPROBE_DEFER;
-	if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
-			host->ncfg->wp_gpio, "NAND WP")) {
-		dev_err(&pdev->dev, "GPIO not available\n");
-		return -EBUSY;
-	}
-	lpc32xx_wp_disable(host);
-
-	host->pdata = dev_get_platdata(&pdev->dev);
-
-	chip = &host->nand_chip;
-	mtd = nand_to_mtd(chip);
-	nand_set_controller_data(chip, host);
-	nand_set_flash_node(chip, pdev->dev.of_node);
-	mtd->owner = THIS_MODULE;
-	mtd->dev.parent = &pdev->dev;
-
-	/* Get NAND clock */
-	host->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(host->clk)) {
-		dev_err(&pdev->dev, "Clock failure\n");
-		res = -ENOENT;
-		goto err_exit1;
-	}
-	res = clk_prepare_enable(host->clk);
-	if (res)
-		goto err_exit1;
-
-	/* Set NAND IO addresses and command/ready functions */
-	chip->IO_ADDR_R = SLC_DATA(host->io_base);
-	chip->IO_ADDR_W = SLC_DATA(host->io_base);
-	chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
-	chip->dev_ready = lpc32xx_nand_device_ready;
-	chip->chip_delay = 20; /* 20us command delay time */
-
-	/* Init NAND controller */
-	lpc32xx_nand_setup(host);
-
-	platform_set_drvdata(pdev, host);
-
-	/* NAND callbacks for LPC32xx SLC hardware */
-	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
-	chip->read_byte = lpc32xx_nand_read_byte;
-	chip->read_buf = lpc32xx_nand_read_buf;
-	chip->write_buf = lpc32xx_nand_write_buf;
-	chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
-	chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
-	chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
-	chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
-	chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
-	chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
-	chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
-	chip->ecc.correct = nand_correct_data;
-	chip->ecc.strength = 1;
-	chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
-
-	/*
-	 * Allocate a large enough buffer for a single huge page plus
-	 * extra space for the spare area and ECC storage area
-	 */
-	host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
-	host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
-				      GFP_KERNEL);
-	if (host->data_buf == NULL) {
-		res = -ENOMEM;
-		goto err_exit2;
-	}
-
-	res = lpc32xx_nand_dma_setup(host);
-	if (res) {
-		res = -EIO;
-		goto err_exit2;
-	}
-
-	/* Find NAND device */
-	res = nand_scan_ident(mtd, 1, NULL);
-	if (res)
-		goto err_exit3;
-
-	/* OOB and ECC CPU and DMA work areas */
-	host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
-
-	/*
-	 * Small page FLASH has a unique OOB layout, but large and huge
-	 * page FLASH use the standard layout. Small page FLASH uses a
-	 * custom BBT marker layout.
-	 */
-	if (mtd->writesize <= 512)
-		mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
-
-	/* These sizes remain the same regardless of page size */
-	chip->ecc.size = 256;
-	chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
-	chip->ecc.prepad = chip->ecc.postpad = 0;
-
-	/*
-	 * Use a custom BBT marker setup for small page FLASH that
-	 * won't interfere with the ECC layout. Large and huge page
-	 * FLASH use the standard layout.
-	 */
-	if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
-	    mtd->writesize <= 512) {
-		chip->bbt_td = &bbt_smallpage_main_descr;
-		chip->bbt_md = &bbt_smallpage_mirror_descr;
-	}
-
-	/*
-	 * Fills out all the uninitialized function pointers with the defaults
-	 */
-	res = nand_scan_tail(mtd);
-	if (res)
-		goto err_exit3;
-
-	mtd->name = "nxp_lpc3220_slc";
-	res = mtd_device_register(mtd, host->ncfg->parts,
-				  host->ncfg->num_parts);
-	if (!res)
-		return res;
-
-	nand_release(mtd);
-
-err_exit3:
-	dma_release_channel(host->dma_chan);
-err_exit2:
-	clk_disable_unprepare(host->clk);
-err_exit1:
-	lpc32xx_wp_enable(host);
-
-	return res;
-}
-
-/*
- * Remove NAND device.
- */
-static int lpc32xx_nand_remove(struct platform_device *pdev)
-{
-	uint32_t tmp;
-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
-
-	nand_release(mtd);
-	dma_release_channel(host->dma_chan);
-
-	/* Force CE high */
-	tmp = readl(SLC_CTRL(host->io_base));
-	tmp &= ~SLCCFG_CE_LOW;
-	writel(tmp, SLC_CTRL(host->io_base));
-
-	clk_disable_unprepare(host->clk);
-	lpc32xx_wp_enable(host);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int lpc32xx_nand_resume(struct platform_device *pdev)
-{
-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-	int ret;
-
-	/* Re-enable NAND clock */
-	ret = clk_prepare_enable(host->clk);
-	if (ret)
-		return ret;
-
-	/* Fresh init of NAND controller */
-	lpc32xx_nand_setup(host);
-
-	/* Disable write protect */
-	lpc32xx_wp_disable(host);
-
-	return 0;
-}
-
-static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
-{
-	uint32_t tmp;
-	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-
-	/* Force CE high */
-	tmp = readl(SLC_CTRL(host->io_base));
-	tmp &= ~SLCCFG_CE_LOW;
-	writel(tmp, SLC_CTRL(host->io_base));
-
-	/* Enable write protect for safety */
-	lpc32xx_wp_enable(host);
-
-	/* Disable clock */
-	clk_disable_unprepare(host->clk);
-
-	return 0;
-}
-
-#else
-#define lpc32xx_nand_resume NULL
-#define lpc32xx_nand_suspend NULL
-#endif
-
-static const struct of_device_id lpc32xx_nand_match[] = {
-	{ .compatible = "nxp,lpc3220-slc" },
-	{ /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
-
-static struct platform_driver lpc32xx_nand_driver = {
-	.probe		= lpc32xx_nand_probe,
-	.remove		= lpc32xx_nand_remove,
-	.resume		= lpc32xx_nand_resume,
-	.suspend	= lpc32xx_nand_suspend,
-	.driver		= {
-		.name	= LPC32XX_MODNAME,
-		.of_match_table = lpc32xx_nand_match,
-	},
-};
-
-module_platform_driver(lpc32xx_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
-MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
diff --git a/drivers/mtd/nand/marvell_nand.c b/drivers/mtd/nand/marvell_nand.c
deleted file mode 100644
index 2196f2a233d6..000000000000
--- a/drivers/mtd/nand/marvell_nand.c
+++ /dev/null
@@ -1,2896 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Marvell NAND flash controller driver
- *
- * Copyright (C) 2017 Marvell
- * Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
- *
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/of_platform.h>
-#include <linux/iopoll.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-#include <asm/unaligned.h>
-
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
-#include <linux/platform_data/mtd-nand-pxa3xx.h>
-
-/* Data FIFO granularity, FIFO reads/writes must be a multiple of this length */
-#define FIFO_DEPTH		8
-#define FIFO_REP(x)		(x / sizeof(u32))
-#define BCH_SEQ_READS		(32 / FIFO_DEPTH)
-/* NFC does not support transfers of larger chunks at a time */
-#define MAX_CHUNK_SIZE		2112
-/* NFCv1 cannot read more that 7 bytes of ID */
-#define NFCV1_READID_LEN	7
-/* Polling is done at a pace of POLL_PERIOD us until POLL_TIMEOUT is reached */
-#define POLL_PERIOD		0
-#define POLL_TIMEOUT		100000
-/* Interrupt maximum wait period in ms */
-#define IRQ_TIMEOUT		1000
-/* Latency in clock cycles between SoC pins and NFC logic */
-#define MIN_RD_DEL_CNT		3
-/* Maximum number of contiguous address cycles */
-#define MAX_ADDRESS_CYC_NFCV1	5
-#define MAX_ADDRESS_CYC_NFCV2	7
-/* System control registers/bits to enable the NAND controller on some SoCs */
-#define GENCONF_SOC_DEVICE_MUX	0x208
-#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
-#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20)
-#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21)
-#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25)
-#define GENCONF_CLK_GATING_CTRL	0x220
-#define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2)
-#define GENCONF_ND_CLK_CTRL	0x700
-#define GENCONF_ND_CLK_CTRL_EN	BIT(0)
-
-/* NAND controller data flash control register */
-#define NDCR			0x00
-#define NDCR_ALL_INT		GENMASK(11, 0)
-#define NDCR_CS1_CMDDM		BIT(7)
-#define NDCR_CS0_CMDDM		BIT(8)
-#define NDCR_RDYM		BIT(11)
-#define NDCR_ND_ARB_EN		BIT(12)
-#define NDCR_RA_START		BIT(15)
-#define NDCR_RD_ID_CNT(x)	(min_t(unsigned int, x, 0x7) << 16)
-#define NDCR_PAGE_SZ(x)		(x >= 2048 ? BIT(24) : 0)
-#define NDCR_DWIDTH_M		BIT(26)
-#define NDCR_DWIDTH_C		BIT(27)
-#define NDCR_ND_RUN		BIT(28)
-#define NDCR_DMA_EN		BIT(29)
-#define NDCR_ECC_EN		BIT(30)
-#define NDCR_SPARE_EN		BIT(31)
-#define NDCR_GENERIC_FIELDS_MASK (~(NDCR_RA_START | NDCR_PAGE_SZ(2048) | \
-				    NDCR_DWIDTH_M | NDCR_DWIDTH_C))
-
-/* NAND interface timing parameter 0 register */
-#define NDTR0			0x04
-#define NDTR0_TRP(x)		((min_t(unsigned int, x, 0xF) & 0x7) << 0)
-#define NDTR0_TRH(x)		(min_t(unsigned int, x, 0x7) << 3)
-#define NDTR0_ETRP(x)		((min_t(unsigned int, x, 0xF) & 0x8) << 3)
-#define NDTR0_SEL_NRE_EDGE	BIT(7)
-#define NDTR0_TWP(x)		(min_t(unsigned int, x, 0x7) << 8)
-#define NDTR0_TWH(x)		(min_t(unsigned int, x, 0x7) << 11)
-#define NDTR0_TCS(x)		(min_t(unsigned int, x, 0x7) << 16)
-#define NDTR0_TCH(x)		(min_t(unsigned int, x, 0x7) << 19)
-#define NDTR0_RD_CNT_DEL(x)	(min_t(unsigned int, x, 0xF) << 22)
-#define NDTR0_SELCNTR		BIT(26)
-#define NDTR0_TADL(x)		(min_t(unsigned int, x, 0x1F) << 27)
-
-/* NAND interface timing parameter 1 register */
-#define NDTR1			0x0C
-#define NDTR1_TAR(x)		(min_t(unsigned int, x, 0xF) << 0)
-#define NDTR1_TWHR(x)		(min_t(unsigned int, x, 0xF) << 4)
-#define NDTR1_TRHW(x)		(min_t(unsigned int, x / 16, 0x3) << 8)
-#define NDTR1_PRESCALE		BIT(14)
-#define NDTR1_WAIT_MODE		BIT(15)
-#define NDTR1_TR(x)		(min_t(unsigned int, x, 0xFFFF) << 16)
-
-/* NAND controller status register */
-#define NDSR			0x14
-#define NDSR_WRCMDREQ		BIT(0)
-#define NDSR_RDDREQ		BIT(1)
-#define NDSR_WRDREQ		BIT(2)
-#define NDSR_CORERR		BIT(3)
-#define NDSR_UNCERR		BIT(4)
-#define NDSR_CMDD(cs)		BIT(8 - cs)
-#define NDSR_RDY(rb)		BIT(11 + rb)
-#define NDSR_ERRCNT(x)		((x >> 16) & 0x1F)
-
-/* NAND ECC control register */
-#define NDECCCTRL		0x28
-#define NDECCCTRL_BCH_EN	BIT(0)
-
-/* NAND controller data buffer register */
-#define NDDB			0x40
-
-/* NAND controller command buffer 0 register */
-#define NDCB0			0x48
-#define NDCB0_CMD1(x)		((x & 0xFF) << 0)
-#define NDCB0_CMD2(x)		((x & 0xFF) << 8)
-#define NDCB0_ADDR_CYC(x)	((x & 0x7) << 16)
-#define NDCB0_ADDR_GET_NUM_CYC(x) (((x) >> 16) & 0x7)
-#define NDCB0_DBC		BIT(19)
-#define NDCB0_CMD_TYPE(x)	((x & 0x7) << 21)
-#define NDCB0_CSEL		BIT(24)
-#define NDCB0_RDY_BYP		BIT(27)
-#define NDCB0_LEN_OVRD		BIT(28)
-#define NDCB0_CMD_XTYPE(x)	((x & 0x7) << 29)
-
-/* NAND controller command buffer 1 register */
-#define NDCB1			0x4C
-#define NDCB1_COLS(x)		((x & 0xFFFF) << 0)
-#define NDCB1_ADDRS_PAGE(x)	(x << 16)
-
-/* NAND controller command buffer 2 register */
-#define NDCB2			0x50
-#define NDCB2_ADDR5_PAGE(x)	(((x >> 16) & 0xFF) << 0)
-#define NDCB2_ADDR5_CYC(x)	((x & 0xFF) << 0)
-
-/* NAND controller command buffer 3 register */
-#define NDCB3			0x54
-#define NDCB3_ADDR6_CYC(x)	((x & 0xFF) << 16)
-#define NDCB3_ADDR7_CYC(x)	((x & 0xFF) << 24)
-
-/* NAND controller command buffer 0 register 'type' and 'xtype' fields */
-#define TYPE_READ		0
-#define TYPE_WRITE		1
-#define TYPE_ERASE		2
-#define TYPE_READ_ID		3
-#define TYPE_STATUS		4
-#define TYPE_RESET		5
-#define TYPE_NAKED_CMD		6
-#define TYPE_NAKED_ADDR		7
-#define TYPE_MASK		7
-#define XTYPE_MONOLITHIC_RW	0
-#define XTYPE_LAST_NAKED_RW	1
-#define XTYPE_FINAL_COMMAND	3
-#define XTYPE_READ		4
-#define XTYPE_WRITE_DISPATCH	4
-#define XTYPE_NAKED_RW		5
-#define XTYPE_COMMAND_DISPATCH	6
-#define XTYPE_MASK		7
-
-/**
- * Marvell ECC engine works differently than the others, in order to limit the
- * size of the IP, hardware engineers chose to set a fixed strength at 16 bits
- * per subpage, and depending on a the desired strength needed by the NAND chip,
- * a particular layout mixing data/spare/ecc is defined, with a possible last
- * chunk smaller that the others.
- *
- * @writesize:		Full page size on which the layout applies
- * @chunk:		Desired ECC chunk size on which the layout applies
- * @strength:		Desired ECC strength (per chunk size bytes) on which the
- *			layout applies
- * @nchunks:		Total number of chunks
- * @full_chunk_cnt:	Number of full-sized chunks, which is the number of
- *			repetitions of the pattern:
- *			(data_bytes + spare_bytes + ecc_bytes).
- * @data_bytes:		Number of data bytes per chunk
- * @spare_bytes:	Number of spare bytes per chunk
- * @ecc_bytes:		Number of ecc bytes per chunk
- * @last_data_bytes:	Number of data bytes in the last chunk
- * @last_spare_bytes:	Number of spare bytes in the last chunk
- * @last_ecc_bytes:	Number of ecc bytes in the last chunk
- */
-struct marvell_hw_ecc_layout {
-	/* Constraints */
-	int writesize;
-	int chunk;
-	int strength;
-	/* Corresponding layout */
-	int nchunks;
-	int full_chunk_cnt;
-	int data_bytes;
-	int spare_bytes;
-	int ecc_bytes;
-	int last_data_bytes;
-	int last_spare_bytes;
-	int last_ecc_bytes;
-};
-
-#define MARVELL_LAYOUT(ws, dc, ds, nc, fcc, db, sb, eb, ldb, lsb, leb)	\
-	{								\
-		.writesize = ws,					\
-		.chunk = dc,						\
-		.strength = ds,						\
-		.nchunks = nc,						\
-		.full_chunk_cnt = fcc,					\
-		.data_bytes = db,					\
-		.spare_bytes = sb,					\
-		.ecc_bytes = eb,					\
-		.last_data_bytes = ldb,					\
-		.last_spare_bytes = lsb,				\
-		.last_ecc_bytes = leb,					\
-	}
-
-/* Layouts explained in AN-379_Marvell_SoC_NFC_ECC */
-static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
-	MARVELL_LAYOUT(  512,   512,  1,  1,  1,  512,  8,  8,  0,  0,  0),
-	MARVELL_LAYOUT( 2048,   512,  1,  1,  1, 2048, 40, 24,  0,  0,  0),
-	MARVELL_LAYOUT( 2048,   512,  4,  1,  1, 2048, 32, 30,  0,  0,  0),
-	MARVELL_LAYOUT( 4096,   512,  4,  2,  2, 2048, 32, 30,  0,  0,  0),
-	MARVELL_LAYOUT( 4096,   512,  8,  5,  4, 1024,  0, 30,  0, 64, 30),
-};
-
-/**
- * The Nand Flash Controller has up to 4 CE and 2 RB pins. The CE selection
- * is made by a field in NDCB0 register, and in another field in NDCB2 register.
- * The datasheet describes the logic with an error: ADDR5 field is once
- * declared at the beginning of NDCB2, and another time at its end. Because the
- * ADDR5 field of NDCB2 may be used by other bytes, it would be more logical
- * to use the last bit of this field instead of the first ones.
- *
- * @cs:			Wanted CE lane.
- * @ndcb0_csel:		Value of the NDCB0 register with or without the flag
- *			selecting the wanted CE lane. This is set once when
- *			the Device Tree is probed.
- * @rb:			Ready/Busy pin for the flash chip
- */
-struct marvell_nand_chip_sel {
-	unsigned int cs;
-	u32 ndcb0_csel;
-	unsigned int rb;
-};
-
-/**
- * NAND chip structure: stores NAND chip device related information
- *
- * @chip:		Base NAND chip structure
- * @node:		Used to store NAND chips into a list
- * @layout		NAND layout when using hardware ECC
- * @ndcr:		Controller register value for this NAND chip
- * @ndtr0:		Timing registers 0 value for this NAND chip
- * @ndtr1:		Timing registers 1 value for this NAND chip
- * @selected_die:	Current active CS
- * @nsels:		Number of CS lines required by the NAND chip
- * @sels:		Array of CS lines descriptions
- */
-struct marvell_nand_chip {
-	struct nand_chip chip;
-	struct list_head node;
-	const struct marvell_hw_ecc_layout *layout;
-	u32 ndcr;
-	u32 ndtr0;
-	u32 ndtr1;
-	int addr_cyc;
-	int selected_die;
-	unsigned int nsels;
-	struct marvell_nand_chip_sel sels[0];
-};
-
-static inline struct marvell_nand_chip *to_marvell_nand(struct nand_chip *chip)
-{
-	return container_of(chip, struct marvell_nand_chip, chip);
-}
-
-static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
-							*nand)
-{
-	return &nand->sels[nand->selected_die];
-}
-
-/**
- * NAND controller capabilities for distinction between compatible strings
- *
- * @max_cs_nb:		Number of Chip Select lines available
- * @max_rb_nb:		Number of Ready/Busy lines available
- * @need_system_controller: Indicates if the SoC needs to have access to the
- *                      system controller (ie. to enable the NAND controller)
- * @legacy_of_bindings:	Indicates if DT parsing must be done using the old
- *			fashion way
- * @is_nfcv2:		NFCv2 has numerous enhancements compared to NFCv1, ie.
- *			BCH error detection and correction algorithm,
- *			NDCB3 register has been added
- * @use_dma:		Use dma for data transfers
- */
-struct marvell_nfc_caps {
-	unsigned int max_cs_nb;
-	unsigned int max_rb_nb;
-	bool need_system_controller;
-	bool legacy_of_bindings;
-	bool is_nfcv2;
-	bool use_dma;
-};
-
-/**
- * NAND controller structure: stores Marvell NAND controller information
- *
- * @controller:		Base controller structure
- * @dev:		Parent device (used to print error messages)
- * @regs:		NAND controller registers
- * @ecc_clk:		ECC block clock, two times the NAND controller clock
- * @complete:		Completion object to wait for NAND controller events
- * @assigned_cs:	Bitmask describing already assigned CS lines
- * @chips:		List containing all the NAND chips attached to
- *			this NAND controller
- * @caps:		NAND controller capabilities for each compatible string
- * @dma_chan:		DMA channel (NFCv1 only)
- * @dma_buf:		32-bit aligned buffer for DMA transfers (NFCv1 only)
- */
-struct marvell_nfc {
-	struct nand_hw_control controller;
-	struct device *dev;
-	void __iomem *regs;
-	struct clk *ecc_clk;
-	struct completion complete;
-	unsigned long assigned_cs;
-	struct list_head chips;
-	struct nand_chip *selected_chip;
-	const struct marvell_nfc_caps *caps;
-
-	/* DMA (NFCv1 only) */
-	bool use_dma;
-	struct dma_chan *dma_chan;
-	u8 *dma_buf;
-};
-
-static inline struct marvell_nfc *to_marvell_nfc(struct nand_hw_control *ctrl)
-{
-	return container_of(ctrl, struct marvell_nfc, controller);
-}
-
-/**
- * NAND controller timings expressed in NAND Controller clock cycles
- *
- * @tRP:		ND_nRE pulse width
- * @tRH:		ND_nRE high duration
- * @tWP:		ND_nWE pulse time
- * @tWH:		ND_nWE high duration
- * @tCS:		Enable signal setup time
- * @tCH:		Enable signal hold time
- * @tADL:		Address to write data delay
- * @tAR:		ND_ALE low to ND_nRE low delay
- * @tWHR:		ND_nWE high to ND_nRE low for status read
- * @tRHW:		ND_nRE high duration, read to write delay
- * @tR:			ND_nWE high to ND_nRE low for read
- */
-struct marvell_nfc_timings {
-	/* NDTR0 fields */
-	unsigned int tRP;
-	unsigned int tRH;
-	unsigned int tWP;
-	unsigned int tWH;
-	unsigned int tCS;
-	unsigned int tCH;
-	unsigned int tADL;
-	/* NDTR1 fields */
-	unsigned int tAR;
-	unsigned int tWHR;
-	unsigned int tRHW;
-	unsigned int tR;
-};
-
-/**
- * Derives a duration in numbers of clock cycles.
- *
- * @ps: Duration in pico-seconds
- * @period_ns:  Clock period in nano-seconds
- *
- * Convert the duration in nano-seconds, then divide by the period and
- * return the number of clock periods.
- */
-#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP(ps / 1000, period_ns))
-
-/**
- * NAND driver structure filled during the parsing of the ->exec_op() subop
- * subset of instructions.
- *
- * @ndcb:		Array of values written to NDCBx registers
- * @cle_ale_delay_ns:	Optional delay after the last CMD or ADDR cycle
- * @rdy_timeout_ms:	Timeout for waits on Ready/Busy pin
- * @rdy_delay_ns:	Optional delay after waiting for the RB pin
- * @data_delay_ns:	Optional delay after the data xfer
- * @data_instr_idx:	Index of the data instruction in the subop
- * @data_instr:		Pointer to the data instruction in the subop
- */
-struct marvell_nfc_op {
-	u32 ndcb[4];
-	unsigned int cle_ale_delay_ns;
-	unsigned int rdy_timeout_ms;
-	unsigned int rdy_delay_ns;
-	unsigned int data_delay_ns;
-	unsigned int data_instr_idx;
-	const struct nand_op_instr *data_instr;
-};
-
-/*
- * Internal helper to conditionnally apply a delay (from the above structure,
- * most of the time).
- */
-static void cond_delay(unsigned int ns)
-{
-	if (!ns)
-		return;
-
-	if (ns < 10000)
-		ndelay(ns);
-	else
-		udelay(DIV_ROUND_UP(ns, 1000));
-}
-
-/*
- * The controller has many flags that could generate interrupts, most of them
- * are disabled and polling is used. For the very slow signals, using interrupts
- * may relax the CPU charge.
- */
-static void marvell_nfc_disable_int(struct marvell_nfc *nfc, u32 int_mask)
-{
-	u32 reg;
-
-	/* Writing 1 disables the interrupt */
-	reg = readl_relaxed(nfc->regs + NDCR);
-	writel_relaxed(reg | int_mask, nfc->regs + NDCR);
-}
-
-static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask)
-{
-	u32 reg;
-
-	/* Writing 0 enables the interrupt */
-	reg = readl_relaxed(nfc->regs + NDCR);
-	writel_relaxed(reg & ~int_mask, nfc->regs + NDCR);
-}
-
-static void marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
-{
-	writel_relaxed(int_mask, nfc->regs + NDSR);
-}
-
-static void marvell_nfc_force_byte_access(struct nand_chip *chip,
-					  bool force_8bit)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 ndcr;
-
-	/*
-	 * Callers of this function do not verify if the NAND is using a 16-bit
-	 * an 8-bit bus for normal operations, so we need to take care of that
-	 * here by leaving the configuration unchanged if the NAND does not have
-	 * the NAND_BUSWIDTH_16 flag set.
-	 */
-	if (!(chip->options & NAND_BUSWIDTH_16))
-		return;
-
-	ndcr = readl_relaxed(nfc->regs + NDCR);
-
-	if (force_8bit)
-		ndcr &= ~(NDCR_DWIDTH_M | NDCR_DWIDTH_C);
-	else
-		ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
-
-	writel_relaxed(ndcr, nfc->regs + NDCR);
-}
-
-static int marvell_nfc_wait_ndrun(struct nand_chip *chip)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 val;
-	int ret;
-
-	/*
-	 * The command is being processed, wait for the ND_RUN bit to be
-	 * cleared by the NFC. If not, we must clear it by hand.
-	 */
-	ret = readl_relaxed_poll_timeout(nfc->regs + NDCR, val,
-					 (val & NDCR_ND_RUN) == 0,
-					 POLL_PERIOD, POLL_TIMEOUT);
-	if (ret) {
-		dev_err(nfc->dev, "Timeout on NAND controller run mode\n");
-		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
-			       nfc->regs + NDCR);
-		return ret;
-	}
-
-	return 0;
-}
-
-/*
- * Any time a command has to be sent to the controller, the following sequence
- * has to be followed:
- * - call marvell_nfc_prepare_cmd()
- *      -> activate the ND_RUN bit that will kind of 'start a job'
- *      -> wait the signal indicating the NFC is waiting for a command
- * - send the command (cmd and address cycles)
- * - enventually send or receive the data
- * - call marvell_nfc_end_cmd() with the corresponding flag
- *      -> wait the flag to be triggered or cancel the job with a timeout
- *
- * The following helpers are here to factorize the code a bit so that
- * specialized functions responsible for executing the actual NAND
- * operations do not have to replicate the same code blocks.
- */
-static int marvell_nfc_prepare_cmd(struct nand_chip *chip)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 ndcr, val;
-	int ret;
-
-	/* Poll ND_RUN and clear NDSR before issuing any command */
-	ret = marvell_nfc_wait_ndrun(chip);
-	if (ret) {
-		dev_err(nfc->dev, "Last operation did not succeed\n");
-		return ret;
-	}
-
-	ndcr = readl_relaxed(nfc->regs + NDCR);
-	writel_relaxed(readl(nfc->regs + NDSR), nfc->regs + NDSR);
-
-	/* Assert ND_RUN bit and wait the NFC to be ready */
-	writel_relaxed(ndcr | NDCR_ND_RUN, nfc->regs + NDCR);
-	ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
-					 val & NDSR_WRCMDREQ,
-					 POLL_PERIOD, POLL_TIMEOUT);
-	if (ret) {
-		dev_err(nfc->dev, "Timeout on WRCMDRE\n");
-		return -ETIMEDOUT;
-	}
-
-	/* Command may be written, clear WRCMDREQ status bit */
-	writel_relaxed(NDSR_WRCMDREQ, nfc->regs + NDSR);
-
-	return 0;
-}
-
-static void marvell_nfc_send_cmd(struct nand_chip *chip,
-				 struct marvell_nfc_op *nfc_op)
-{
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-
-	dev_dbg(nfc->dev, "\nNDCR:  0x%08x\n"
-		"NDCB0: 0x%08x\nNDCB1: 0x%08x\nNDCB2: 0x%08x\nNDCB3: 0x%08x\n",
-		(u32)readl_relaxed(nfc->regs + NDCR), nfc_op->ndcb[0],
-		nfc_op->ndcb[1], nfc_op->ndcb[2], nfc_op->ndcb[3]);
-
-	writel_relaxed(to_nand_sel(marvell_nand)->ndcb0_csel | nfc_op->ndcb[0],
-		       nfc->regs + NDCB0);
-	writel_relaxed(nfc_op->ndcb[1], nfc->regs + NDCB0);
-	writel(nfc_op->ndcb[2], nfc->regs + NDCB0);
-
-	/*
-	 * Write NDCB0 four times only if LEN_OVRD is set or if ADDR6 or ADDR7
-	 * fields are used (only available on NFCv2).
-	 */
-	if (nfc_op->ndcb[0] & NDCB0_LEN_OVRD ||
-	    NDCB0_ADDR_GET_NUM_CYC(nfc_op->ndcb[0]) >= 6) {
-		if (!WARN_ON_ONCE(!nfc->caps->is_nfcv2))
-			writel(nfc_op->ndcb[3], nfc->regs + NDCB0);
-	}
-}
-
-static int marvell_nfc_end_cmd(struct nand_chip *chip, int flag,
-			       const char *label)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 val;
-	int ret;
-
-	ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
-					 val & flag,
-					 POLL_PERIOD, POLL_TIMEOUT);
-
-	if (ret) {
-		dev_err(nfc->dev, "Timeout on %s (NDSR: 0x%08x)\n",
-			label, val);
-		if (nfc->dma_chan)
-			dmaengine_terminate_all(nfc->dma_chan);
-		return ret;
-	}
-
-	/*
-	 * DMA function uses this helper to poll on CMDD bits without wanting
-	 * them to be cleared.
-	 */
-	if (nfc->use_dma && (readl_relaxed(nfc->regs + NDCR) & NDCR_DMA_EN))
-		return 0;
-
-	writel_relaxed(flag, nfc->regs + NDSR);
-
-	return 0;
-}
-
-static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
-{
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	int cs_flag = NDSR_CMDD(to_nand_sel(marvell_nand)->ndcb0_csel);
-
-	return marvell_nfc_end_cmd(chip, cs_flag, "CMDD");
-}
-
-static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	int ret;
-
-	/* Timeout is expressed in ms */
-	if (!timeout_ms)
-		timeout_ms = IRQ_TIMEOUT;
-
-	init_completion(&nfc->complete);
-
-	marvell_nfc_enable_int(nfc, NDCR_RDYM);
-	ret = wait_for_completion_timeout(&nfc->complete,
-					  msecs_to_jiffies(timeout_ms));
-	marvell_nfc_disable_int(nfc, NDCR_RDYM);
-	marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
-	if (!ret) {
-		dev_err(nfc->dev, "Timeout waiting for RB signal\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 ndcr_generic;
-
-	if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die)
-		return;
-
-	if (die_nr < 0 || die_nr >= marvell_nand->nsels) {
-		nfc->selected_chip = NULL;
-		marvell_nand->selected_die = -1;
-		return;
-	}
-
-	/*
-	 * Do not change the timing registers when using the DT property
-	 * marvell,nand-keep-config; in that case ->ndtr0 and ->ndtr1 from the
-	 * marvell_nand structure are supposedly empty.
-	 */
-	writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
-	writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
-
-	/*
-	 * Reset the NDCR register to a clean state for this particular chip,
-	 * also clear ND_RUN bit.
-	 */
-	ndcr_generic = readl_relaxed(nfc->regs + NDCR) &
-		       NDCR_GENERIC_FIELDS_MASK & ~NDCR_ND_RUN;
-	writel_relaxed(ndcr_generic | marvell_nand->ndcr, nfc->regs + NDCR);
-
-	/* Also reset the interrupt status register */
-	marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
-
-	nfc->selected_chip = chip;
-	marvell_nand->selected_die = die_nr;
-}
-
-static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
-{
-	struct marvell_nfc *nfc = dev_id;
-	u32 st = readl_relaxed(nfc->regs + NDSR);
-	u32 ien = (~readl_relaxed(nfc->regs + NDCR)) & NDCR_ALL_INT;
-
-	/*
-	 * RDY interrupt mask is one bit in NDCR while there are two status
-	 * bit in NDSR (RDY[cs0/cs2] and RDY[cs1/cs3]).
-	 */
-	if (st & NDSR_RDY(1))
-		st |= NDSR_RDY(0);
-
-	if (!(st & ien))
-		return IRQ_NONE;
-
-	marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
-
-	if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
-		complete(&nfc->complete);
-
-	return IRQ_HANDLED;
-}
-
-/* HW ECC related functions */
-static void marvell_nfc_enable_hw_ecc(struct nand_chip *chip)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
-
-	if (!(ndcr & NDCR_ECC_EN)) {
-		writel_relaxed(ndcr | NDCR_ECC_EN, nfc->regs + NDCR);
-
-		/*
-		 * When enabling BCH, set threshold to 0 to always know the
-		 * number of corrected bitflips.
-		 */
-		if (chip->ecc.algo == NAND_ECC_BCH)
-			writel_relaxed(NDECCCTRL_BCH_EN, nfc->regs + NDECCCTRL);
-	}
-}
-
-static void marvell_nfc_disable_hw_ecc(struct nand_chip *chip)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
-
-	if (ndcr & NDCR_ECC_EN) {
-		writel_relaxed(ndcr & ~NDCR_ECC_EN, nfc->regs + NDCR);
-		if (chip->ecc.algo == NAND_ECC_BCH)
-			writel_relaxed(0, nfc->regs + NDECCCTRL);
-	}
-}
-
-/* DMA related helpers */
-static void marvell_nfc_enable_dma(struct marvell_nfc *nfc)
-{
-	u32 reg;
-
-	reg = readl_relaxed(nfc->regs + NDCR);
-	writel_relaxed(reg | NDCR_DMA_EN, nfc->regs + NDCR);
-}
-
-static void marvell_nfc_disable_dma(struct marvell_nfc *nfc)
-{
-	u32 reg;
-
-	reg = readl_relaxed(nfc->regs + NDCR);
-	writel_relaxed(reg & ~NDCR_DMA_EN, nfc->regs + NDCR);
-}
-
-/* Read/write PIO/DMA accessors */
-static int marvell_nfc_xfer_data_dma(struct marvell_nfc *nfc,
-				     enum dma_data_direction direction,
-				     unsigned int len)
-{
-	unsigned int dma_len = min_t(int, ALIGN(len, 32), MAX_CHUNK_SIZE);
-	struct dma_async_tx_descriptor *tx;
-	struct scatterlist sg;
-	dma_cookie_t cookie;
-	int ret;
-
-	marvell_nfc_enable_dma(nfc);
-	/* Prepare the DMA transfer */
-	sg_init_one(&sg, nfc->dma_buf, dma_len);
-	dma_map_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
-	tx = dmaengine_prep_slave_sg(nfc->dma_chan, &sg, 1,
-				     direction == DMA_FROM_DEVICE ?
-				     DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
-				     DMA_PREP_INTERRUPT);
-	if (!tx) {
-		dev_err(nfc->dev, "Could not prepare DMA S/G list\n");
-		return -ENXIO;
-	}
-
-	/* Do the task and wait for it to finish */
-	cookie = dmaengine_submit(tx);
-	ret = dma_submit_error(cookie);
-	if (ret)
-		return -EIO;
-
-	dma_async_issue_pending(nfc->dma_chan);
-	ret = marvell_nfc_wait_cmdd(nfc->selected_chip);
-	dma_unmap_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
-	marvell_nfc_disable_dma(nfc);
-	if (ret) {
-		dev_err(nfc->dev, "Timeout waiting for DMA (status: %d)\n",
-			dmaengine_tx_status(nfc->dma_chan, cookie, NULL));
-		dmaengine_terminate_all(nfc->dma_chan);
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static int marvell_nfc_xfer_data_in_pio(struct marvell_nfc *nfc, u8 *in,
-					unsigned int len)
-{
-	unsigned int last_len = len % FIFO_DEPTH;
-	unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
-	int i;
-
-	for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
-		ioread32_rep(nfc->regs + NDDB, in + i, FIFO_REP(FIFO_DEPTH));
-
-	if (last_len) {
-		u8 tmp_buf[FIFO_DEPTH];
-
-		ioread32_rep(nfc->regs + NDDB, tmp_buf, FIFO_REP(FIFO_DEPTH));
-		memcpy(in + last_full_offset, tmp_buf, last_len);
-	}
-
-	return 0;
-}
-
-static int marvell_nfc_xfer_data_out_pio(struct marvell_nfc *nfc, const u8 *out,
-					 unsigned int len)
-{
-	unsigned int last_len = len % FIFO_DEPTH;
-	unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
-	int i;
-
-	for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
-		iowrite32_rep(nfc->regs + NDDB, out + i, FIFO_REP(FIFO_DEPTH));
-
-	if (last_len) {
-		u8 tmp_buf[FIFO_DEPTH];
-
-		memcpy(tmp_buf, out + last_full_offset, last_len);
-		iowrite32_rep(nfc->regs + NDDB, tmp_buf, FIFO_REP(FIFO_DEPTH));
-	}
-
-	return 0;
-}
-
-static void marvell_nfc_check_empty_chunk(struct nand_chip *chip,
-					  u8 *data, int data_len,
-					  u8 *spare, int spare_len,
-					  u8 *ecc, int ecc_len,
-					  unsigned int *max_bitflips)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int bf;
-
-	/*
-	 * Blank pages (all 0xFF) that have not been written may be recognized
-	 * as bad if bitflips occur, so whenever an uncorrectable error occurs,
-	 * check if the entire page (with ECC bytes) is actually blank or not.
-	 */
-	if (!data)
-		data_len = 0;
-	if (!spare)
-		spare_len = 0;
-	if (!ecc)
-		ecc_len = 0;
-
-	bf = nand_check_erased_ecc_chunk(data, data_len, ecc, ecc_len,
-					 spare, spare_len, chip->ecc.strength);
-	if (bf < 0) {
-		mtd->ecc_stats.failed++;
-		return;
-	}
-
-	/* Update the stats and max_bitflips */
-	mtd->ecc_stats.corrected += bf;
-	*max_bitflips = max_t(unsigned int, *max_bitflips, bf);
-}
-
-/*
- * Check a chunk is correct or not according to hardware ECC engine.
- * mtd->ecc_stats.corrected is updated, as well as max_bitflips, however
- * mtd->ecc_stats.failure is not, the function will instead return a non-zero
- * value indicating that a check on the emptyness of the subpage must be
- * performed before declaring the subpage corrupted.
- */
-static int marvell_nfc_hw_ecc_correct(struct nand_chip *chip,
-				      unsigned int *max_bitflips)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	int bf = 0;
-	u32 ndsr;
-
-	ndsr = readl_relaxed(nfc->regs + NDSR);
-
-	/* Check uncorrectable error flag */
-	if (ndsr & NDSR_UNCERR) {
-		writel_relaxed(ndsr, nfc->regs + NDSR);
-
-		/*
-		 * Do not increment ->ecc_stats.failed now, instead, return a
-		 * non-zero value to indicate that this chunk was apparently
-		 * bad, and it should be check to see if it empty or not. If
-		 * the chunk (with ECC bytes) is not declared empty, the calling
-		 * function must increment the failure count.
-		 */
-		return -EBADMSG;
-	}
-
-	/* Check correctable error flag */
-	if (ndsr & NDSR_CORERR) {
-		writel_relaxed(ndsr, nfc->regs + NDSR);
-
-		if (chip->ecc.algo == NAND_ECC_BCH)
-			bf = NDSR_ERRCNT(ndsr);
-		else
-			bf = 1;
-	}
-
-	/* Update the stats and max_bitflips */
-	mtd->ecc_stats.corrected += bf;
-	*max_bitflips = max_t(unsigned int, *max_bitflips, bf);
-
-	return 0;
-}
-
-/* Hamming read helpers */
-static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
-					       u8 *data_buf, u8 *oob_buf,
-					       bool raw, int page)
-{
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	struct marvell_nfc_op nfc_op = {
-		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
-			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
-			   NDCB0_DBC |
-			   NDCB0_CMD1(NAND_CMD_READ0) |
-			   NDCB0_CMD2(NAND_CMD_READSTART),
-		.ndcb[1] = NDCB1_ADDRS_PAGE(page),
-		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
-	};
-	unsigned int oob_bytes = lt->spare_bytes + (raw ? lt->ecc_bytes : 0);
-	int ret;
-
-	/* NFCv2 needs more information about the operation being executed */
-	if (nfc->caps->is_nfcv2)
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
-				  "RDDREQ while draining FIFO (data/oob)");
-	if (ret)
-		return ret;
-
-	/*
-	 * Read the page then the OOB area. Unlike what is shown in current
-	 * documentation, spare bytes are protected by the ECC engine, and must
-	 * be at the beginning of the OOB area or running this driver on legacy
-	 * systems will prevent the discovery of the BBM/BBT.
-	 */
-	if (nfc->use_dma) {
-		marvell_nfc_xfer_data_dma(nfc, DMA_FROM_DEVICE,
-					  lt->data_bytes + oob_bytes);
-		memcpy(data_buf, nfc->dma_buf, lt->data_bytes);
-		memcpy(oob_buf, nfc->dma_buf + lt->data_bytes, oob_bytes);
-	} else {
-		marvell_nfc_xfer_data_in_pio(nfc, data_buf, lt->data_bytes);
-		marvell_nfc_xfer_data_in_pio(nfc, oob_buf, oob_bytes);
-	}
-
-	ret = marvell_nfc_wait_cmdd(chip);
-
-	return ret;
-}
-
-static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
-						struct nand_chip *chip, u8 *buf,
-						int oob_required, int page)
-{
-	return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
-						   true, page);
-}
-
-static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
-					    struct nand_chip *chip,
-					    u8 *buf, int oob_required,
-					    int page)
-{
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
-	int max_bitflips = 0, ret;
-	u8 *raw_buf;
-
-	marvell_nfc_enable_hw_ecc(chip);
-	marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, false,
-					    page);
-	ret = marvell_nfc_hw_ecc_correct(chip, &max_bitflips);
-	marvell_nfc_disable_hw_ecc(chip);
-
-	if (!ret)
-		return max_bitflips;
-
-	/*
-	 * When ECC failures are detected, check if the full page has been
-	 * written or not. Ignore the failure if it is actually empty.
-	 */
-	raw_buf = kmalloc(full_sz, GFP_KERNEL);
-	if (!raw_buf)
-		return -ENOMEM;
-
-	marvell_nfc_hw_ecc_hmg_do_read_page(chip, raw_buf, raw_buf +
-					    lt->data_bytes, true, page);
-	marvell_nfc_check_empty_chunk(chip, raw_buf, full_sz, NULL, 0, NULL, 0,
-				      &max_bitflips);
-	kfree(raw_buf);
-
-	return max_bitflips;
-}
-
-/*
- * Spare area in Hamming layouts is not protected by the ECC engine (even if
- * it appears before the ECC bytes when reading), the ->read_oob_raw() function
- * also stands for ->read_oob().
- */
-static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
-					       struct nand_chip *chip, int page)
-{
-	/* Invalidate page cache */
-	chip->pagebuf = -1;
-
-	return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf,
-						   chip->oob_poi, true, page);
-}
-
-/* Hamming write helpers */
-static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
-						const u8 *data_buf,
-						const u8 *oob_buf, bool raw,
-						int page)
-{
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	struct marvell_nfc_op nfc_op = {
-		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) |
-			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
-			   NDCB0_CMD1(NAND_CMD_SEQIN) |
-			   NDCB0_CMD2(NAND_CMD_PAGEPROG) |
-			   NDCB0_DBC,
-		.ndcb[1] = NDCB1_ADDRS_PAGE(page),
-		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
-	};
-	unsigned int oob_bytes = lt->spare_bytes + (raw ? lt->ecc_bytes : 0);
-	int ret;
-
-	/* NFCv2 needs more information about the operation being executed */
-	if (nfc->caps->is_nfcv2)
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
-				  "WRDREQ while loading FIFO (data)");
-	if (ret)
-		return ret;
-
-	/* Write the page then the OOB area */
-	if (nfc->use_dma) {
-		memcpy(nfc->dma_buf, data_buf, lt->data_bytes);
-		memcpy(nfc->dma_buf + lt->data_bytes, oob_buf, oob_bytes);
-		marvell_nfc_xfer_data_dma(nfc, DMA_TO_DEVICE, lt->data_bytes +
-					  lt->ecc_bytes + lt->spare_bytes);
-	} else {
-		marvell_nfc_xfer_data_out_pio(nfc, data_buf, lt->data_bytes);
-		marvell_nfc_xfer_data_out_pio(nfc, oob_buf, oob_bytes);
-	}
-
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	ret = marvell_nfc_wait_op(chip,
-				  chip->data_interface.timings.sdr.tPROG_max);
-	return ret;
-}
-
-static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
-						 struct nand_chip *chip,
-						 const u8 *buf,
-						 int oob_required, int page)
-{
-	return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
-						    true, page);
-}
-
-static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
-					     struct nand_chip *chip,
-					     const u8 *buf,
-					     int oob_required, int page)
-{
-	int ret;
-
-	marvell_nfc_enable_hw_ecc(chip);
-	ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
-						   false, page);
-	marvell_nfc_disable_hw_ecc(chip);
-
-	return ret;
-}
-
-/*
- * Spare area in Hamming layouts is not protected by the ECC engine (even if
- * it appears before the ECC bytes when reading), the ->write_oob_raw() function
- * also stands for ->write_oob().
- */
-static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
-						struct nand_chip *chip,
-						int page)
-{
-	/* Invalidate page cache */
-	chip->pagebuf = -1;
-
-	memset(chip->data_buf, 0xFF, mtd->writesize);
-
-	return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf,
-						    chip->oob_poi, true, page);
-}
-
-/* BCH read helpers */
-static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
-						struct nand_chip *chip, u8 *buf,
-						int oob_required, int page)
-{
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	u8 *oob = chip->oob_poi;
-	int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
-	int ecc_offset = (lt->full_chunk_cnt * lt->spare_bytes) +
-		lt->last_spare_bytes;
-	int data_len = lt->data_bytes;
-	int spare_len = lt->spare_bytes;
-	int ecc_len = lt->ecc_bytes;
-	int chunk;
-
-	if (oob_required)
-		memset(chip->oob_poi, 0xFF, mtd->oobsize);
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	for (chunk = 0; chunk < lt->nchunks; chunk++) {
-		/* Update last chunk length */
-		if (chunk >= lt->full_chunk_cnt) {
-			data_len = lt->last_data_bytes;
-			spare_len = lt->last_spare_bytes;
-			ecc_len = lt->last_ecc_bytes;
-		}
-
-		/* Read data bytes*/
-		nand_change_read_column_op(chip, chunk * chunk_size,
-					   buf + (lt->data_bytes * chunk),
-					   data_len, false);
-
-		/* Read spare bytes */
-		nand_read_data_op(chip, oob + (lt->spare_bytes * chunk),
-				  spare_len, false);
-
-		/* Read ECC bytes */
-		nand_read_data_op(chip, oob + ecc_offset +
-				  (ALIGN(lt->ecc_bytes, 32) * chunk),
-				  ecc_len, false);
-	}
-
-	return 0;
-}
-
-static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
-					      u8 *data, unsigned int data_len,
-					      u8 *spare, unsigned int spare_len,
-					      int page)
-{
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	int i, ret;
-	struct marvell_nfc_op nfc_op = {
-		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
-			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
-			   NDCB0_LEN_OVRD,
-		.ndcb[1] = NDCB1_ADDRS_PAGE(page),
-		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
-		.ndcb[3] = data_len + spare_len,
-	};
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return;
-
-	if (chunk == 0)
-		nfc_op.ndcb[0] |= NDCB0_DBC |
-				  NDCB0_CMD1(NAND_CMD_READ0) |
-				  NDCB0_CMD2(NAND_CMD_READSTART);
-
-	/*
-	 * Trigger the naked read operation only on the last chunk.
-	 * Otherwise, use monolithic read.
-	 */
-	if (lt->nchunks == 1 || (chunk < lt->nchunks - 1))
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
-	else
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-
-	/*
-	 * According to the datasheet, when reading from NDDB
-	 * with BCH enabled, after each 32 bytes reads, we
-	 * have to make sure that the NDSR.RDDREQ bit is set.
-	 *
-	 * Drain the FIFO, 8 32-bit reads at a time, and skip
-	 * the polling on the last read.
-	 *
-	 * Length is a multiple of 32 bytes, hence it is a multiple of 8 too.
-	 */
-	for (i = 0; i < data_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
-		marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
-				    "RDDREQ while draining FIFO (data)");
-		marvell_nfc_xfer_data_in_pio(nfc, data,
-					     FIFO_DEPTH * BCH_SEQ_READS);
-		data += FIFO_DEPTH * BCH_SEQ_READS;
-	}
-
-	for (i = 0; i < spare_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
-		marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
-				    "RDDREQ while draining FIFO (OOB)");
-		marvell_nfc_xfer_data_in_pio(nfc, spare,
-					     FIFO_DEPTH * BCH_SEQ_READS);
-		spare += FIFO_DEPTH * BCH_SEQ_READS;
-	}
-}
-
-static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
-					    struct nand_chip *chip,
-					    u8 *buf, int oob_required,
-					    int page)
-{
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
-	u8 *data = buf, *spare = chip->oob_poi, *ecc;
-	int max_bitflips = 0;
-	u32 failure_mask = 0;
-	int chunk, ecc_offset_in_page, ret;
-
-	/*
-	 * With BCH, OOB is not fully used (and thus not read entirely), not
-	 * expected bytes could show up at the end of the OOB buffer if not
-	 * explicitly erased.
-	 */
-	if (oob_required)
-		memset(chip->oob_poi, 0xFF, mtd->oobsize);
-
-	marvell_nfc_enable_hw_ecc(chip);
-
-	for (chunk = 0; chunk < lt->nchunks; chunk++) {
-		/* Update length for the last chunk */
-		if (chunk >= lt->full_chunk_cnt) {
-			data_len = lt->last_data_bytes;
-			spare_len = lt->last_spare_bytes;
-		}
-
-		/* Read the chunk and detect number of bitflips */
-		marvell_nfc_hw_ecc_bch_read_chunk(chip, chunk, data, data_len,
-						  spare, spare_len, page);
-		ret = marvell_nfc_hw_ecc_correct(chip, &max_bitflips);
-		if (ret)
-			failure_mask |= BIT(chunk);
-
-		data += data_len;
-		spare += spare_len;
-	}
-
-	marvell_nfc_disable_hw_ecc(chip);
-
-	if (!failure_mask)
-		return max_bitflips;
-
-	/*
-	 * Please note that dumping the ECC bytes during a normal read with OOB
-	 * area would add a significant overhead as ECC bytes are "consumed" by
-	 * the controller in normal mode and must be re-read in raw mode. To
-	 * avoid dropping the performances, we prefer not to include them. The
-	 * user should re-read the page in raw mode if ECC bytes are required.
-	 *
-	 * However, for any subpage read error reported by ->correct(), the ECC
-	 * bytes must be read in raw mode and the full subpage must be checked
-	 * to see if it is entirely empty of if there was an actual error.
-	 */
-	for (chunk = 0; chunk < lt->nchunks; chunk++) {
-		/* No failure reported for this chunk, move to the next one */
-		if (!(failure_mask & BIT(chunk)))
-			continue;
-
-		/* Derive ECC bytes positions (in page/buffer) and length */
-		ecc = chip->oob_poi +
-			(lt->full_chunk_cnt * lt->spare_bytes) +
-			lt->last_spare_bytes +
-			(chunk * ALIGN(lt->ecc_bytes, 32));
-		ecc_offset_in_page =
-			(chunk * (lt->data_bytes + lt->spare_bytes +
-				  lt->ecc_bytes)) +
-			(chunk < lt->full_chunk_cnt ?
-			 lt->data_bytes + lt->spare_bytes :
-			 lt->last_data_bytes + lt->last_spare_bytes);
-		ecc_len = chunk < lt->full_chunk_cnt ?
-			lt->ecc_bytes : lt->last_ecc_bytes;
-
-		/* Do the actual raw read of the ECC bytes */
-		nand_change_read_column_op(chip, ecc_offset_in_page,
-					   ecc, ecc_len, false);
-
-		/* Derive data/spare bytes positions (in buffer) and length */
-		data = buf + (chunk * lt->data_bytes);
-		data_len = chunk < lt->full_chunk_cnt ?
-			lt->data_bytes : lt->last_data_bytes;
-		spare = chip->oob_poi + (chunk * (lt->spare_bytes +
-						  lt->ecc_bytes));
-		spare_len = chunk < lt->full_chunk_cnt ?
-			lt->spare_bytes : lt->last_spare_bytes;
-
-		/* Check the entire chunk (data + spare + ecc) for emptyness */
-		marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
-					      spare_len, ecc, ecc_len,
-					      &max_bitflips);
-	}
-
-	return max_bitflips;
-}
-
-static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
-					       struct nand_chip *chip, int page)
-{
-	/* Invalidate page cache */
-	chip->pagebuf = -1;
-
-	return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
-}
-
-static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
-					   struct nand_chip *chip, int page)
-{
-	/* Invalidate page cache */
-	chip->pagebuf = -1;
-
-	return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
-}
-
-/* BCH write helpers */
-static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
-						 struct nand_chip *chip,
-						 const u8 *buf,
-						 int oob_required, int page)
-{
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	int full_chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
-	int data_len = lt->data_bytes;
-	int spare_len = lt->spare_bytes;
-	int ecc_len = lt->ecc_bytes;
-	int spare_offset = 0;
-	int ecc_offset = (lt->full_chunk_cnt * lt->spare_bytes) +
-		lt->last_spare_bytes;
-	int chunk;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	for (chunk = 0; chunk < lt->nchunks; chunk++) {
-		if (chunk >= lt->full_chunk_cnt) {
-			data_len = lt->last_data_bytes;
-			spare_len = lt->last_spare_bytes;
-			ecc_len = lt->last_ecc_bytes;
-		}
-
-		/* Point to the column of the next chunk */
-		nand_change_write_column_op(chip, chunk * full_chunk_size,
-					    NULL, 0, false);
-
-		/* Write the data */
-		nand_write_data_op(chip, buf + (chunk * lt->data_bytes),
-				   data_len, false);
-
-		if (!oob_required)
-			continue;
-
-		/* Write the spare bytes */
-		if (spare_len)
-			nand_write_data_op(chip, chip->oob_poi + spare_offset,
-					   spare_len, false);
-
-		/* Write the ECC bytes */
-		if (ecc_len)
-			nand_write_data_op(chip, chip->oob_poi + ecc_offset,
-					   ecc_len, false);
-
-		spare_offset += spare_len;
-		ecc_offset += ALIGN(ecc_len, 32);
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int
-marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
-				   const u8 *data, unsigned int data_len,
-				   const u8 *spare, unsigned int spare_len,
-				   int page)
-{
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	int ret;
-	struct marvell_nfc_op nfc_op = {
-		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) | NDCB0_LEN_OVRD,
-		.ndcb[3] = data_len + spare_len,
-	};
-
-	/*
-	 * First operation dispatches the CMD_SEQIN command, issue the address
-	 * cycles and asks for the first chunk of data.
-	 * All operations in the middle (if any) will issue a naked write and
-	 * also ask for data.
-	 * Last operation (if any) asks for the last chunk of data through a
-	 * last naked write.
-	 */
-	if (chunk == 0) {
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_WRITE_DISPATCH) |
-				  NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
-				  NDCB0_CMD1(NAND_CMD_SEQIN);
-		nfc_op.ndcb[1] |= NDCB1_ADDRS_PAGE(page);
-		nfc_op.ndcb[2] |= NDCB2_ADDR5_PAGE(page);
-	} else if (chunk < lt->nchunks - 1) {
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_NAKED_RW);
-	} else {
-		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
-	}
-
-	/* Always dispatch the PAGEPROG command on the last chunk */
-	if (chunk == lt->nchunks - 1)
-		nfc_op.ndcb[0] |= NDCB0_CMD2(NAND_CMD_PAGEPROG) | NDCB0_DBC;
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
-				  "WRDREQ while loading FIFO (data)");
-	if (ret)
-		return ret;
-
-	/* Transfer the contents */
-	iowrite32_rep(nfc->regs + NDDB, data, FIFO_REP(data_len));
-	iowrite32_rep(nfc->regs + NDDB, spare, FIFO_REP(spare_len));
-
-	return 0;
-}
-
-static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
-					     struct nand_chip *chip,
-					     const u8 *buf,
-					     int oob_required, int page)
-{
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-	const u8 *data = buf;
-	const u8 *spare = chip->oob_poi;
-	int data_len = lt->data_bytes;
-	int spare_len = lt->spare_bytes;
-	int chunk, ret;
-
-	/* Spare data will be written anyway, so clear it to avoid garbage */
-	if (!oob_required)
-		memset(chip->oob_poi, 0xFF, mtd->oobsize);
-
-	marvell_nfc_enable_hw_ecc(chip);
-
-	for (chunk = 0; chunk < lt->nchunks; chunk++) {
-		if (chunk >= lt->full_chunk_cnt) {
-			data_len = lt->last_data_bytes;
-			spare_len = lt->last_spare_bytes;
-		}
-
-		marvell_nfc_hw_ecc_bch_write_chunk(chip, chunk, data, data_len,
-						   spare, spare_len, page);
-		data += data_len;
-		spare += spare_len;
-
-		/*
-		 * Waiting only for CMDD or PAGED is not enough, ECC are
-		 * partially written. No flag is set once the operation is
-		 * really finished but the ND_RUN bit is cleared, so wait for it
-		 * before stepping into the next command.
-		 */
-		marvell_nfc_wait_ndrun(chip);
-	}
-
-	ret = marvell_nfc_wait_op(chip,
-				  chip->data_interface.timings.sdr.tPROG_max);
-
-	marvell_nfc_disable_hw_ecc(chip);
-
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
-						struct nand_chip *chip,
-						int page)
-{
-	/* Invalidate page cache */
-	chip->pagebuf = -1;
-
-	memset(chip->data_buf, 0xFF, mtd->writesize);
-
-	return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
-}
-
-static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
-					    struct nand_chip *chip, int page)
-{
-	/* Invalidate page cache */
-	chip->pagebuf = -1;
-
-	memset(chip->data_buf, 0xFF, mtd->writesize);
-
-	return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
-}
-
-/* NAND framework ->exec_op() hooks and related helpers */
-static void marvell_nfc_parse_instructions(struct nand_chip *chip,
-					   const struct nand_subop *subop,
-					   struct marvell_nfc_op *nfc_op)
-{
-	const struct nand_op_instr *instr = NULL;
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	bool first_cmd = true;
-	unsigned int op_id;
-	int i;
-
-	/* Reset the input structure as most of its fields will be OR'ed */
-	memset(nfc_op, 0, sizeof(struct marvell_nfc_op));
-
-	for (op_id = 0; op_id < subop->ninstrs; op_id++) {
-		unsigned int offset, naddrs;
-		const u8 *addrs;
-		int len = nand_subop_get_data_len(subop, op_id);
-
-		instr = &subop->instrs[op_id];
-
-		switch (instr->type) {
-		case NAND_OP_CMD_INSTR:
-			if (first_cmd)
-				nfc_op->ndcb[0] |=
-					NDCB0_CMD1(instr->ctx.cmd.opcode);
-			else
-				nfc_op->ndcb[0] |=
-					NDCB0_CMD2(instr->ctx.cmd.opcode) |
-					NDCB0_DBC;
-
-			nfc_op->cle_ale_delay_ns = instr->delay_ns;
-			first_cmd = false;
-			break;
-
-		case NAND_OP_ADDR_INSTR:
-			offset = nand_subop_get_addr_start_off(subop, op_id);
-			naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
-			addrs = &instr->ctx.addr.addrs[offset];
-
-			nfc_op->ndcb[0] |= NDCB0_ADDR_CYC(naddrs);
-
-			for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
-				nfc_op->ndcb[1] |= addrs[i] << (8 * i);
-
-			if (naddrs >= 5)
-				nfc_op->ndcb[2] |= NDCB2_ADDR5_CYC(addrs[4]);
-			if (naddrs >= 6)
-				nfc_op->ndcb[3] |= NDCB3_ADDR6_CYC(addrs[5]);
-			if (naddrs == 7)
-				nfc_op->ndcb[3] |= NDCB3_ADDR7_CYC(addrs[6]);
-
-			nfc_op->cle_ale_delay_ns = instr->delay_ns;
-			break;
-
-		case NAND_OP_DATA_IN_INSTR:
-			nfc_op->data_instr = instr;
-			nfc_op->data_instr_idx = op_id;
-			nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ);
-			if (nfc->caps->is_nfcv2) {
-				nfc_op->ndcb[0] |=
-					NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
-					NDCB0_LEN_OVRD;
-				nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
-			}
-			nfc_op->data_delay_ns = instr->delay_ns;
-			break;
-
-		case NAND_OP_DATA_OUT_INSTR:
-			nfc_op->data_instr = instr;
-			nfc_op->data_instr_idx = op_id;
-			nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE);
-			if (nfc->caps->is_nfcv2) {
-				nfc_op->ndcb[0] |=
-					NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
-					NDCB0_LEN_OVRD;
-				nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
-			}
-			nfc_op->data_delay_ns = instr->delay_ns;
-			break;
-
-		case NAND_OP_WAITRDY_INSTR:
-			nfc_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms;
-			nfc_op->rdy_delay_ns = instr->delay_ns;
-			break;
-		}
-	}
-}
-
-static int marvell_nfc_xfer_data_pio(struct nand_chip *chip,
-				     const struct nand_subop *subop,
-				     struct marvell_nfc_op *nfc_op)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	const struct nand_op_instr *instr = nfc_op->data_instr;
-	unsigned int op_id = nfc_op->data_instr_idx;
-	unsigned int len = nand_subop_get_data_len(subop, op_id);
-	unsigned int offset = nand_subop_get_data_start_off(subop, op_id);
-	bool reading = (instr->type == NAND_OP_DATA_IN_INSTR);
-	int ret;
-
-	if (instr->ctx.data.force_8bit)
-		marvell_nfc_force_byte_access(chip, true);
-
-	if (reading) {
-		u8 *in = instr->ctx.data.buf.in + offset;
-
-		ret = marvell_nfc_xfer_data_in_pio(nfc, in, len);
-	} else {
-		const u8 *out = instr->ctx.data.buf.out + offset;
-
-		ret = marvell_nfc_xfer_data_out_pio(nfc, out, len);
-	}
-
-	if (instr->ctx.data.force_8bit)
-		marvell_nfc_force_byte_access(chip, false);
-
-	return ret;
-}
-
-static int marvell_nfc_monolithic_access_exec(struct nand_chip *chip,
-					      const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	bool reading;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-	reading = (nfc_op.data_instr->type == NAND_OP_DATA_IN_INSTR);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
-				  "RDDREQ/WRDREQ while draining raw data");
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.cle_ale_delay_ns);
-
-	if (reading) {
-		if (nfc_op.rdy_timeout_ms) {
-			ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-			if (ret)
-				return ret;
-		}
-
-		cond_delay(nfc_op.rdy_delay_ns);
-	}
-
-	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.data_delay_ns);
-
-	if (!reading) {
-		if (nfc_op.rdy_timeout_ms) {
-			ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-			if (ret)
-				return ret;
-		}
-
-		cond_delay(nfc_op.rdy_delay_ns);
-	}
-
-	/*
-	 * NDCR ND_RUN bit should be cleared automatically at the end of each
-	 * operation but experience shows that the behavior is buggy when it
-	 * comes to writes (with LEN_OVRD). Clear it by hand in this case.
-	 */
-	if (!reading) {
-		struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-
-		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
-			       nfc->regs + NDCR);
-	}
-
-	return 0;
-}
-
-static int marvell_nfc_naked_access_exec(struct nand_chip *chip,
-					 const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-
-	/*
-	 * Naked access are different in that they need to be flagged as naked
-	 * by the controller. Reset the controller registers fields that inform
-	 * on the type and refill them according to the ongoing operation.
-	 */
-	nfc_op.ndcb[0] &= ~(NDCB0_CMD_TYPE(TYPE_MASK) |
-			    NDCB0_CMD_XTYPE(XTYPE_MASK));
-	switch (subop->instrs[0].type) {
-	case NAND_OP_CMD_INSTR:
-		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_CMD);
-		break;
-	case NAND_OP_ADDR_INSTR:
-		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_ADDR);
-		break;
-	case NAND_OP_DATA_IN_INSTR:
-		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ) |
-				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
-		break;
-	case NAND_OP_DATA_OUT_INSTR:
-		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE) |
-				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
-		break;
-	default:
-		/* This should never happen */
-		break;
-	}
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-
-	if (!nfc_op.data_instr) {
-		ret = marvell_nfc_wait_cmdd(chip);
-		cond_delay(nfc_op.cle_ale_delay_ns);
-		return ret;
-	}
-
-	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
-				  "RDDREQ/WRDREQ while draining raw data");
-	if (ret)
-		return ret;
-
-	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	/*
-	 * NDCR ND_RUN bit should be cleared automatically at the end of each
-	 * operation but experience shows that the behavior is buggy when it
-	 * comes to writes (with LEN_OVRD). Clear it by hand in this case.
-	 */
-	if (subop->instrs[0].type == NAND_OP_DATA_OUT_INSTR) {
-		struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-
-		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
-			       nfc->regs + NDCR);
-	}
-
-	return 0;
-}
-
-static int marvell_nfc_naked_waitrdy_exec(struct nand_chip *chip,
-					  const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-
-	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-	cond_delay(nfc_op.rdy_delay_ns);
-
-	return ret;
-}
-
-static int marvell_nfc_read_id_type_exec(struct nand_chip *chip,
-					 const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-	nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
-	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ_ID);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
-				  "RDDREQ while reading ID");
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.cle_ale_delay_ns);
-
-	if (nfc_op.rdy_timeout_ms) {
-		ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-		if (ret)
-			return ret;
-	}
-
-	cond_delay(nfc_op.rdy_delay_ns);
-
-	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.data_delay_ns);
-
-	return 0;
-}
-
-static int marvell_nfc_read_status_exec(struct nand_chip *chip,
-					const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-	nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
-	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_STATUS);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
-				  "RDDREQ while reading status");
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.cle_ale_delay_ns);
-
-	if (nfc_op.rdy_timeout_ms) {
-		ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-		if (ret)
-			return ret;
-	}
-
-	cond_delay(nfc_op.rdy_delay_ns);
-
-	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.data_delay_ns);
-
-	return 0;
-}
-
-static int marvell_nfc_reset_cmd_type_exec(struct nand_chip *chip,
-					   const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_RESET);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.cle_ale_delay_ns);
-
-	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.rdy_delay_ns);
-
-	return 0;
-}
-
-static int marvell_nfc_erase_cmd_type_exec(struct nand_chip *chip,
-					   const struct nand_subop *subop)
-{
-	struct marvell_nfc_op nfc_op;
-	int ret;
-
-	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
-	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_ERASE);
-
-	ret = marvell_nfc_prepare_cmd(chip);
-	if (ret)
-		return ret;
-
-	marvell_nfc_send_cmd(chip, &nfc_op);
-	ret = marvell_nfc_wait_cmdd(chip);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.cle_ale_delay_ns);
-
-	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
-	if (ret)
-		return ret;
-
-	cond_delay(nfc_op.rdy_delay_ns);
-
-	return 0;
-}
-
-static const struct nand_op_parser marvell_nfcv2_op_parser = NAND_OP_PARSER(
-	/* Monolithic reads/writes */
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_monolithic_access_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC_NFCV2),
-		NAND_OP_PARSER_PAT_CMD_ELEM(true),
-		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
-		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_monolithic_access_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2),
-		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE),
-		NAND_OP_PARSER_PAT_CMD_ELEM(true),
-		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
-	/* Naked commands */
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_naked_access_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_naked_access_exec,
-		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_naked_access_exec,
-		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_naked_access_exec,
-		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_naked_waitrdy_exec,
-		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
-	);
-
-static const struct nand_op_parser marvell_nfcv1_op_parser = NAND_OP_PARSER(
-	/* Naked commands not supported, use a function for each pattern */
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_read_id_type_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
-		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_erase_cmd_type_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_read_status_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_reset_cmd_type_exec,
-		NAND_OP_PARSER_PAT_CMD_ELEM(false),
-		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
-	NAND_OP_PARSER_PATTERN(
-		marvell_nfc_naked_waitrdy_exec,
-		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
-	);
-
-static int marvell_nfc_exec_op(struct nand_chip *chip,
-			       const struct nand_operation *op,
-			       bool check_only)
-{
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-
-	if (nfc->caps->is_nfcv2)
-		return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser,
-					      op, check_only);
-	else
-		return nand_op_parser_exec_op(chip, &marvell_nfcv1_op_parser,
-					      op, check_only);
-}
-
-/*
- * Layouts were broken in old pxa3xx_nand driver, these are supposed to be
- * usable.
- */
-static int marvell_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
-				      struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->length = (lt->full_chunk_cnt * lt->ecc_bytes) +
-			    lt->last_ecc_bytes;
-	oobregion->offset = mtd->oobsize - oobregion->length;
-
-	return 0;
-}
-
-static int marvell_nand_ooblayout_free(struct mtd_info *mtd, int section,
-				       struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-
-	if (section)
-		return -ERANGE;
-
-	/*
-	 * Bootrom looks in bytes 0 & 5 for bad blocks for the
-	 * 4KB page / 4bit BCH combination.
-	 */
-	if (mtd->writesize == SZ_4K && lt->data_bytes == SZ_2K)
-		oobregion->offset = 6;
-	else
-		oobregion->offset = 2;
-
-	oobregion->length = (lt->full_chunk_cnt * lt->spare_bytes) +
-			    lt->last_spare_bytes - oobregion->offset;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops marvell_nand_ooblayout_ops = {
-	.ecc = marvell_nand_ooblayout_ecc,
-	.free = marvell_nand_ooblayout_free,
-};
-
-static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
-					 struct nand_ecc_ctrl *ecc)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	const struct marvell_hw_ecc_layout *l;
-	int i;
-
-	if (!nfc->caps->is_nfcv2 &&
-	    (mtd->writesize + mtd->oobsize > MAX_CHUNK_SIZE)) {
-		dev_err(nfc->dev,
-			"NFCv1: writesize (%d) cannot be bigger than a chunk (%d)\n",
-			mtd->writesize, MAX_CHUNK_SIZE - mtd->oobsize);
-		return -ENOTSUPP;
-	}
-
-	to_marvell_nand(chip)->layout = NULL;
-	for (i = 0; i < ARRAY_SIZE(marvell_nfc_layouts); i++) {
-		l = &marvell_nfc_layouts[i];
-		if (mtd->writesize == l->writesize &&
-		    ecc->size == l->chunk && ecc->strength == l->strength) {
-			to_marvell_nand(chip)->layout = l;
-			break;
-		}
-	}
-
-	if (!to_marvell_nand(chip)->layout ||
-	    (!nfc->caps->is_nfcv2 && ecc->strength > 1)) {
-		dev_err(nfc->dev,
-			"ECC strength %d at page size %d is not supported\n",
-			ecc->strength, mtd->writesize);
-		return -ENOTSUPP;
-	}
-
-	mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
-	ecc->steps = l->nchunks;
-	ecc->size = l->data_bytes;
-
-	if (ecc->strength == 1) {
-		chip->ecc.algo = NAND_ECC_HAMMING;
-		ecc->read_page_raw = marvell_nfc_hw_ecc_hmg_read_page_raw;
-		ecc->read_page = marvell_nfc_hw_ecc_hmg_read_page;
-		ecc->read_oob_raw = marvell_nfc_hw_ecc_hmg_read_oob_raw;
-		ecc->read_oob = ecc->read_oob_raw;
-		ecc->write_page_raw = marvell_nfc_hw_ecc_hmg_write_page_raw;
-		ecc->write_page = marvell_nfc_hw_ecc_hmg_write_page;
-		ecc->write_oob_raw = marvell_nfc_hw_ecc_hmg_write_oob_raw;
-		ecc->write_oob = ecc->write_oob_raw;
-	} else {
-		chip->ecc.algo = NAND_ECC_BCH;
-		ecc->strength = 16;
-		ecc->read_page_raw = marvell_nfc_hw_ecc_bch_read_page_raw;
-		ecc->read_page = marvell_nfc_hw_ecc_bch_read_page;
-		ecc->read_oob_raw = marvell_nfc_hw_ecc_bch_read_oob_raw;
-		ecc->read_oob = marvell_nfc_hw_ecc_bch_read_oob;
-		ecc->write_page_raw = marvell_nfc_hw_ecc_bch_write_page_raw;
-		ecc->write_page = marvell_nfc_hw_ecc_bch_write_page;
-		ecc->write_oob_raw = marvell_nfc_hw_ecc_bch_write_oob_raw;
-		ecc->write_oob = marvell_nfc_hw_ecc_bch_write_oob;
-	}
-
-	return 0;
-}
-
-static int marvell_nand_ecc_init(struct mtd_info *mtd,
-				 struct nand_ecc_ctrl *ecc)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	int ret;
-
-	if (ecc->mode != NAND_ECC_NONE && (!ecc->size || !ecc->strength)) {
-		if (chip->ecc_step_ds && chip->ecc_strength_ds) {
-			ecc->size = chip->ecc_step_ds;
-			ecc->strength = chip->ecc_strength_ds;
-		} else {
-			dev_info(nfc->dev,
-				 "No minimum ECC strength, using 1b/512B\n");
-			ecc->size = 512;
-			ecc->strength = 1;
-		}
-	}
-
-	switch (ecc->mode) {
-	case NAND_ECC_HW:
-		ret = marvell_nand_hw_ecc_ctrl_init(mtd, ecc);
-		if (ret)
-			return ret;
-		break;
-	case NAND_ECC_NONE:
-	case NAND_ECC_SOFT:
-		if (!nfc->caps->is_nfcv2 && mtd->writesize != SZ_512 &&
-		    mtd->writesize != SZ_2K) {
-			dev_err(nfc->dev, "NFCv1 cannot write %d bytes pages\n",
-				mtd->writesize);
-			return -EINVAL;
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
-static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
-		   NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	8,
-	.len = 6,
-	.veroffs = 14,
-	.maxblocks = 8,	/* Last 8 blocks in each chip */
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
-		   NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	8,
-	.len = 6,
-	.veroffs = 14,
-	.maxblocks = 8,	/* Last 8 blocks in each chip */
-	.pattern = bbt_mirror_pattern
-};
-
-static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
-					    const struct nand_data_interface
-					    *conf)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
-	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
-	unsigned int period_ns = 1000000000 / clk_get_rate(nfc->ecc_clk) * 2;
-	const struct nand_sdr_timings *sdr;
-	struct marvell_nfc_timings nfc_tmg;
-	int read_delay;
-
-	sdr = nand_get_sdr_timings(conf);
-	if (IS_ERR(sdr))
-		return PTR_ERR(sdr);
-
-	/*
-	 * SDR timings are given in pico-seconds while NFC timings must be
-	 * expressed in NAND controller clock cycles, which is half of the
-	 * frequency of the accessible ECC clock retrieved by clk_get_rate().
-	 * This is not written anywhere in the datasheet but was observed
-	 * with an oscilloscope.
-	 *
-	 * NFC datasheet gives equations from which thoses calculations
-	 * are derived, they tend to be slightly more restrictives than the
-	 * given core timings and may improve the overall speed.
-	 */
-	nfc_tmg.tRP = TO_CYCLES(DIV_ROUND_UP(sdr->tRC_min, 2), period_ns) - 1;
-	nfc_tmg.tRH = nfc_tmg.tRP;
-	nfc_tmg.tWP = TO_CYCLES(DIV_ROUND_UP(sdr->tWC_min, 2), period_ns) - 1;
-	nfc_tmg.tWH = nfc_tmg.tWP;
-	nfc_tmg.tCS = TO_CYCLES(sdr->tCS_min, period_ns);
-	nfc_tmg.tCH = TO_CYCLES(sdr->tCH_min, period_ns) - 1;
-	nfc_tmg.tADL = TO_CYCLES(sdr->tADL_min, period_ns);
-	/*
-	 * Read delay is the time of propagation from SoC pins to NFC internal
-	 * logic. With non-EDO timings, this is MIN_RD_DEL_CNT clock cycles. In
-	 * EDO mode, an additional delay of tRH must be taken into account so
-	 * the data is sampled on the falling edge instead of the rising edge.
-	 */
-	read_delay = sdr->tRC_min >= 30000 ?
-		MIN_RD_DEL_CNT : MIN_RD_DEL_CNT + nfc_tmg.tRH;
-
-	nfc_tmg.tAR = TO_CYCLES(sdr->tAR_min, period_ns);
-	/*
-	 * tWHR and tRHW are supposed to be read to write delays (and vice
-	 * versa) but in some cases, ie. when doing a change column, they must
-	 * be greater than that to be sure tCCS delay is respected.
-	 */
-	nfc_tmg.tWHR = TO_CYCLES(max_t(int, sdr->tWHR_min, sdr->tCCS_min),
-				 period_ns) - 2,
-	nfc_tmg.tRHW = TO_CYCLES(max_t(int, sdr->tRHW_min, sdr->tCCS_min),
-				 period_ns);
-
-	/* Use WAIT_MODE (wait for RB line) instead of only relying on delays */
-	nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns);
-
-	if (chipnr < 0)
-		return 0;
-
-	marvell_nand->ndtr0 =
-		NDTR0_TRP(nfc_tmg.tRP) |
-		NDTR0_TRH(nfc_tmg.tRH) |
-		NDTR0_ETRP(nfc_tmg.tRP) |
-		NDTR0_TWP(nfc_tmg.tWP) |
-		NDTR0_TWH(nfc_tmg.tWH) |
-		NDTR0_TCS(nfc_tmg.tCS) |
-		NDTR0_TCH(nfc_tmg.tCH) |
-		NDTR0_RD_CNT_DEL(read_delay) |
-		NDTR0_SELCNTR |
-		NDTR0_TADL(nfc_tmg.tADL);
-
-	marvell_nand->ndtr1 =
-		NDTR1_TAR(nfc_tmg.tAR) |
-		NDTR1_TWHR(nfc_tmg.tWHR) |
-		NDTR1_TRHW(nfc_tmg.tRHW) |
-		NDTR1_WAIT_MODE |
-		NDTR1_TR(nfc_tmg.tR);
-
-	return 0;
-}
-
-static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
-				  struct device_node *np)
-{
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(dev);
-	struct marvell_nand_chip *marvell_nand;
-	struct mtd_info *mtd;
-	struct nand_chip *chip;
-	int nsels, ret, i;
-	u32 cs, rb;
-
-	/*
-	 * The legacy "num-cs" property indicates the number of CS on the only
-	 * chip connected to the controller (legacy bindings does not support
-	 * more than one chip). CS are only incremented one by one while the RB
-	 * pin is always the #0.
-	 *
-	 * When not using legacy bindings, a couple of "reg" and "nand-rb"
-	 * properties must be filled. For each chip, expressed as a subnode,
-	 * "reg" points to the CS lines and "nand-rb" to the RB line.
-	 */
-	if (pdata) {
-		nsels = 1;
-	} else if (nfc->caps->legacy_of_bindings &&
-		   !of_get_property(np, "num-cs", &nsels)) {
-		dev_err(dev, "missing num-cs property\n");
-		return -EINVAL;
-	} else if (!of_get_property(np, "reg", &nsels)) {
-		dev_err(dev, "missing reg property\n");
-		return -EINVAL;
-	}
-
-	if (!pdata)
-		nsels /= sizeof(u32);
-	if (!nsels) {
-		dev_err(dev, "invalid reg property size\n");
-		return -EINVAL;
-	}
-
-	/* Alloc the nand chip structure */
-	marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) +
-				    (nsels *
-				     sizeof(struct marvell_nand_chip_sel)),
-				    GFP_KERNEL);
-	if (!marvell_nand) {
-		dev_err(dev, "could not allocate chip structure\n");
-		return -ENOMEM;
-	}
-
-	marvell_nand->nsels = nsels;
-	marvell_nand->selected_die = -1;
-
-	for (i = 0; i < nsels; i++) {
-		if (pdata || nfc->caps->legacy_of_bindings) {
-			/*
-			 * Legacy bindings use the CS lines in natural
-			 * order (0, 1, ...)
-			 */
-			cs = i;
-		} else {
-			/* Retrieve CS id */
-			ret = of_property_read_u32_index(np, "reg", i, &cs);
-			if (ret) {
-				dev_err(dev, "could not retrieve reg property: %d\n",
-					ret);
-				return ret;
-			}
-		}
-
-		if (cs >= nfc->caps->max_cs_nb) {
-			dev_err(dev, "invalid reg value: %u (max CS = %d)\n",
-				cs, nfc->caps->max_cs_nb);
-			return -EINVAL;
-		}
-
-		if (test_and_set_bit(cs, &nfc->assigned_cs)) {
-			dev_err(dev, "CS %d already assigned\n", cs);
-			return -EINVAL;
-		}
-
-		/*
-		 * The cs variable represents the chip select id, which must be
-		 * converted in bit fields for NDCB0 and NDCB2 to select the
-		 * right chip. Unfortunately, due to a lack of information on
-		 * the subject and incoherent documentation, the user should not
-		 * use CS1 and CS3 at all as asserting them is not supported in
-		 * a reliable way (due to multiplexing inside ADDR5 field).
-		 */
-		marvell_nand->sels[i].cs = cs;
-		switch (cs) {
-		case 0:
-		case 2:
-			marvell_nand->sels[i].ndcb0_csel = 0;
-			break;
-		case 1:
-		case 3:
-			marvell_nand->sels[i].ndcb0_csel = NDCB0_CSEL;
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		/* Retrieve RB id */
-		if (pdata || nfc->caps->legacy_of_bindings) {
-			/* Legacy bindings always use RB #0 */
-			rb = 0;
-		} else {
-			ret = of_property_read_u32_index(np, "nand-rb", i,
-							 &rb);
-			if (ret) {
-				dev_err(dev,
-					"could not retrieve RB property: %d\n",
-					ret);
-				return ret;
-			}
-		}
-
-		if (rb >= nfc->caps->max_rb_nb) {
-			dev_err(dev, "invalid reg value: %u (max RB = %d)\n",
-				rb, nfc->caps->max_rb_nb);
-			return -EINVAL;
-		}
-
-		marvell_nand->sels[i].rb = rb;
-	}
-
-	chip = &marvell_nand->chip;
-	chip->controller = &nfc->controller;
-	nand_set_flash_node(chip, np);
-
-	chip->exec_op = marvell_nfc_exec_op;
-	chip->select_chip = marvell_nfc_select_chip;
-	if (nfc->caps->is_nfcv2 &&
-	    !of_property_read_bool(np, "marvell,nand-keep-config"))
-		chip->setup_data_interface = marvell_nfc_setup_data_interface;
-
-	mtd = nand_to_mtd(chip);
-	mtd->dev.parent = dev;
-
-	/*
-	 * Default to HW ECC engine mode. If the nand-ecc-mode property is given
-	 * in the DT node, this entry will be overwritten in nand_scan_ident().
-	 */
-	chip->ecc.mode = NAND_ECC_HW;
-
-	/*
-	 * Save a reference value for timing registers before
-	 * ->setup_data_interface() is called.
-	 */
-	marvell_nand->ndtr0 = readl_relaxed(nfc->regs + NDTR0);
-	marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);
-
-	chip->options |= NAND_BUSWIDTH_AUTO;
-	ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
-	if (ret) {
-		dev_err(dev, "could not identify the nand chip\n");
-		return ret;
-	}
-
-	if (pdata && pdata->flash_bbt)
-		chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-		/*
-		 * We'll use a bad block table stored in-flash and don't
-		 * allow writing the bad block marker to the flash.
-		 */
-		chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
-		chip->bbt_td = &bbt_main_descr;
-		chip->bbt_md = &bbt_mirror_descr;
-	}
-
-	/* Save the chip-specific fields of NDCR */
-	marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
-	if (chip->options & NAND_BUSWIDTH_16)
-		marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
-
-	/*
-	 * On small page NANDs, only one cycle is needed to pass the
-	 * column address.
-	 */
-	if (mtd->writesize <= 512) {
-		marvell_nand->addr_cyc = 1;
-	} else {
-		marvell_nand->addr_cyc = 2;
-		marvell_nand->ndcr |= NDCR_RA_START;
-	}
-
-	/*
-	 * Now add the number of cycles needed to pass the row
-	 * address.
-	 *
-	 * Addressing a chip using CS 2 or 3 should also need the third row
-	 * cycle but due to inconsistance in the documentation and lack of
-	 * hardware to test this situation, this case is not supported.
-	 */
-	if (chip->options & NAND_ROW_ADDR_3)
-		marvell_nand->addr_cyc += 3;
-	else
-		marvell_nand->addr_cyc += 2;
-
-	if (pdata) {
-		chip->ecc.size = pdata->ecc_step_size;
-		chip->ecc.strength = pdata->ecc_strength;
-	}
-
-	ret = marvell_nand_ecc_init(mtd, &chip->ecc);
-	if (ret) {
-		dev_err(dev, "ECC init failed: %d\n", ret);
-		return ret;
-	}
-
-	if (chip->ecc.mode == NAND_ECC_HW) {
-		/*
-		 * Subpage write not available with hardware ECC, prohibit also
-		 * subpage read as in userspace subpage access would still be
-		 * allowed and subpage write, if used, would lead to numerous
-		 * uncorrectable ECC errors.
-		 */
-		chip->options |= NAND_NO_SUBPAGE_WRITE;
-	}
-
-	if (pdata || nfc->caps->legacy_of_bindings) {
-		/*
-		 * We keep the MTD name unchanged to avoid breaking platforms
-		 * where the MTD cmdline parser is used and the bootloader
-		 * has not been updated to use the new naming scheme.
-		 */
-		mtd->name = "pxa3xx_nand-0";
-	} else if (!mtd->name) {
-		/*
-		 * If the new bindings are used and the bootloader has not been
-		 * updated to pass a new mtdparts parameter on the cmdline, you
-		 * should define the following property in your NAND node, ie:
-		 *
-		 *	label = "main-storage";
-		 *
-		 * This way, mtd->name will be set by the core when
-		 * nand_set_flash_node() is called.
-		 */
-		mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
-					   "%s:nand.%d", dev_name(nfc->dev),
-					   marvell_nand->sels[0].cs);
-		if (!mtd->name) {
-			dev_err(nfc->dev, "Failed to allocate mtd->name\n");
-			return -ENOMEM;
-		}
-	}
-
-	ret = nand_scan_tail(mtd);
-	if (ret) {
-		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
-		return ret;
-	}
-
-	if (pdata)
-		/* Legacy bindings support only one chip */
-		ret = mtd_device_register(mtd, pdata->parts[0],
-					  pdata->nr_parts[0]);
-	else
-		ret = mtd_device_register(mtd, NULL, 0);
-	if (ret) {
-		dev_err(dev, "failed to register mtd device: %d\n", ret);
-		nand_release(mtd);
-		return ret;
-	}
-
-	list_add_tail(&marvell_nand->node, &nfc->chips);
-
-	return 0;
-}
-
-static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
-{
-	struct device_node *np = dev->of_node;
-	struct device_node *nand_np;
-	int max_cs = nfc->caps->max_cs_nb;
-	int nchips;
-	int ret;
-
-	if (!np)
-		nchips = 1;
-	else
-		nchips = of_get_child_count(np);
-
-	if (nchips > max_cs) {
-		dev_err(dev, "too many NAND chips: %d (max = %d CS)\n", nchips,
-			max_cs);
-		return -EINVAL;
-	}
-
-	/*
-	 * Legacy bindings do not use child nodes to exhibit NAND chip
-	 * properties and layout. Instead, NAND properties are mixed with the
-	 * controller ones, and partitions are defined as direct subnodes of the
-	 * NAND controller node.
-	 */
-	if (nfc->caps->legacy_of_bindings) {
-		ret = marvell_nand_chip_init(dev, nfc, np);
-		return ret;
-	}
-
-	for_each_child_of_node(np, nand_np) {
-		ret = marvell_nand_chip_init(dev, nfc, nand_np);
-		if (ret) {
-			of_node_put(nand_np);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
-{
-	struct marvell_nand_chip *entry, *temp;
-
-	list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
-		nand_release(nand_to_mtd(&entry->chip));
-		list_del(&entry->node);
-	}
-}
-
-static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
-{
-	struct platform_device *pdev = container_of(nfc->dev,
-						    struct platform_device,
-						    dev);
-	struct dma_slave_config config = {};
-	struct resource *r;
-	dma_cap_mask_t mask;
-	struct pxad_param param;
-	int ret;
-
-	if (!IS_ENABLED(CONFIG_PXA_DMA)) {
-		dev_warn(nfc->dev,
-			 "DMA not enabled in configuration\n");
-		return -ENOTSUPP;
-	}
-
-	ret = dma_set_mask_and_coherent(nfc->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!r) {
-		dev_err(nfc->dev, "No resource defined for data DMA\n");
-		return -ENXIO;
-	}
-
-	param.drcmr = r->start;
-	param.prio = PXAD_PRIO_LOWEST;
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	nfc->dma_chan =
-		dma_request_slave_channel_compat(mask, pxad_filter_fn,
-						 &param, nfc->dev,
-						 "data");
-	if (!nfc->dma_chan) {
-		dev_err(nfc->dev,
-			"Unable to request data DMA channel\n");
-		return -ENODEV;
-	}
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r)
-		return -ENXIO;
-
-	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.src_addr = r->start + NDDB;
-	config.dst_addr = r->start + NDDB;
-	config.src_maxburst = 32;
-	config.dst_maxburst = 32;
-	ret = dmaengine_slave_config(nfc->dma_chan, &config);
-	if (ret < 0) {
-		dev_err(nfc->dev, "Failed to configure DMA channel\n");
-		return ret;
-	}
-
-	/*
-	 * DMA must act on length multiple of 32 and this length may be
-	 * bigger than the destination buffer. Use this buffer instead
-	 * for DMA transfers and then copy the desired amount of data to
-	 * the provided buffer.
-	 */
-	nfc->dma_buf = kmalloc(MAX_CHUNK_SIZE, GFP_KERNEL | GFP_DMA);
-	if (!nfc->dma_buf)
-		return -ENOMEM;
-
-	nfc->use_dma = true;
-
-	return 0;
-}
-
-static int marvell_nfc_init(struct marvell_nfc *nfc)
-{
-	struct device_node *np = nfc->dev->of_node;
-
-	/*
-	 * Some SoCs like A7k/A8k need to enable manually the NAND
-	 * controller, gated clocks and reset bits to avoid being bootloader
-	 * dependent. This is done through the use of the System Functions
-	 * registers.
-	 */
-	if (nfc->caps->need_system_controller) {
-		struct regmap *sysctrl_base =
-			syscon_regmap_lookup_by_phandle(np,
-							"marvell,system-controller");
-		u32 reg;
-
-		if (IS_ERR(sysctrl_base))
-			return PTR_ERR(sysctrl_base);
-
-		reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
-		      GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
-		      GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
-		      GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
-		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
-
-		regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
-		reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
-		regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
-
-		regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
-		reg |= GENCONF_ND_CLK_CTRL_EN;
-		regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
-	}
-
-	/* Configure the DMA if appropriate */
-	if (!nfc->caps->is_nfcv2)
-		marvell_nfc_init_dma(nfc);
-
-	/*
-	 * ECC operations and interruptions are only enabled when specifically
-	 * needed. ECC shall not be activated in the early stages (fails probe).
-	 * Arbiter flag, even if marked as "reserved", must be set (empirical).
-	 * SPARE_EN bit must always be set or ECC bytes will not be at the same
-	 * offset in the read page and this will fail the protection.
-	 */
-	writel_relaxed(NDCR_ALL_INT | NDCR_ND_ARB_EN | NDCR_SPARE_EN |
-		       NDCR_RD_ID_CNT(NFCV1_READID_LEN), nfc->regs + NDCR);
-	writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
-	writel_relaxed(0, nfc->regs + NDECCCTRL);
-
-	return 0;
-}
-
-static int marvell_nfc_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct resource *r;
-	struct marvell_nfc *nfc;
-	int ret;
-	int irq;
-
-	nfc = devm_kzalloc(&pdev->dev, sizeof(struct marvell_nfc),
-			   GFP_KERNEL);
-	if (!nfc)
-		return -ENOMEM;
-
-	nfc->dev = dev;
-	nand_hw_control_init(&nfc->controller);
-	INIT_LIST_HEAD(&nfc->chips);
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nfc->regs = devm_ioremap_resource(dev, r);
-	if (IS_ERR(nfc->regs))
-		return PTR_ERR(nfc->regs);
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "failed to retrieve irq\n");
-		return irq;
-	}
-
-	nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(nfc->ecc_clk))
-		return PTR_ERR(nfc->ecc_clk);
-
-	ret = clk_prepare_enable(nfc->ecc_clk);
-	if (ret)
-		return ret;
-
-	marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
-	marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
-	ret = devm_request_irq(dev, irq, marvell_nfc_isr,
-			       0, "marvell-nfc", nfc);
-	if (ret)
-		goto unprepare_clk;
-
-	/* Get NAND controller capabilities */
-	if (pdev->id_entry)
-		nfc->caps = (void *)pdev->id_entry->driver_data;
-	else
-		nfc->caps = of_device_get_match_data(&pdev->dev);
-
-	if (!nfc->caps) {
-		dev_err(dev, "Could not retrieve NFC caps\n");
-		ret = -EINVAL;
-		goto unprepare_clk;
-	}
-
-	/* Init the controller and then probe the chips */
-	ret = marvell_nfc_init(nfc);
-	if (ret)
-		goto unprepare_clk;
-
-	platform_set_drvdata(pdev, nfc);
-
-	ret = marvell_nand_chips_init(dev, nfc);
-	if (ret)
-		goto unprepare_clk;
-
-	return 0;
-
-unprepare_clk:
-	clk_disable_unprepare(nfc->ecc_clk);
-
-	return ret;
-}
-
-static int marvell_nfc_remove(struct platform_device *pdev)
-{
-	struct marvell_nfc *nfc = platform_get_drvdata(pdev);
-
-	marvell_nand_chips_cleanup(nfc);
-
-	if (nfc->use_dma) {
-		dmaengine_terminate_all(nfc->dma_chan);
-		dma_release_channel(nfc->dma_chan);
-	}
-
-	clk_disable_unprepare(nfc->ecc_clk);
-
-	return 0;
-}
-
-static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
-	.max_cs_nb = 4,
-	.max_rb_nb = 2,
-	.need_system_controller = true,
-	.is_nfcv2 = true,
-};
-
-static const struct marvell_nfc_caps marvell_armada370_nfc_caps = {
-	.max_cs_nb = 4,
-	.max_rb_nb = 2,
-	.is_nfcv2 = true,
-};
-
-static const struct marvell_nfc_caps marvell_pxa3xx_nfc_caps = {
-	.max_cs_nb = 2,
-	.max_rb_nb = 1,
-	.use_dma = true,
-};
-
-static const struct marvell_nfc_caps marvell_armada_8k_nfc_legacy_caps = {
-	.max_cs_nb = 4,
-	.max_rb_nb = 2,
-	.need_system_controller = true,
-	.legacy_of_bindings = true,
-	.is_nfcv2 = true,
-};
-
-static const struct marvell_nfc_caps marvell_armada370_nfc_legacy_caps = {
-	.max_cs_nb = 4,
-	.max_rb_nb = 2,
-	.legacy_of_bindings = true,
-	.is_nfcv2 = true,
-};
-
-static const struct marvell_nfc_caps marvell_pxa3xx_nfc_legacy_caps = {
-	.max_cs_nb = 2,
-	.max_rb_nb = 1,
-	.legacy_of_bindings = true,
-	.use_dma = true,
-};
-
-static const struct platform_device_id marvell_nfc_platform_ids[] = {
-	{
-		.name = "pxa3xx-nand",
-		.driver_data = (kernel_ulong_t)&marvell_pxa3xx_nfc_legacy_caps,
-	},
-	{ /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(platform, marvell_nfc_platform_ids);
-
-static const struct of_device_id marvell_nfc_of_ids[] = {
-	{
-		.compatible = "marvell,armada-8k-nand-controller",
-		.data = &marvell_armada_8k_nfc_caps,
-	},
-	{
-		.compatible = "marvell,armada370-nand-controller",
-		.data = &marvell_armada370_nfc_caps,
-	},
-	{
-		.compatible = "marvell,pxa3xx-nand-controller",
-		.data = &marvell_pxa3xx_nfc_caps,
-	},
-	/* Support for old/deprecated bindings: */
-	{
-		.compatible = "marvell,armada-8k-nand",
-		.data = &marvell_armada_8k_nfc_legacy_caps,
-	},
-	{
-		.compatible = "marvell,armada370-nand",
-		.data = &marvell_armada370_nfc_legacy_caps,
-	},
-	{
-		.compatible = "marvell,pxa3xx-nand",
-		.data = &marvell_pxa3xx_nfc_legacy_caps,
-	},
-	{ /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, marvell_nfc_of_ids);
-
-static struct platform_driver marvell_nfc_driver = {
-	.driver	= {
-		.name		= "marvell-nfc",
-		.of_match_table = marvell_nfc_of_ids,
-	},
-	.id_table = marvell_nfc_platform_ids,
-	.probe = marvell_nfc_probe,
-	.remove	= marvell_nfc_remove,
-};
-module_platform_driver(marvell_nfc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Marvell NAND controller driver");
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
deleted file mode 100644
index b6b97cc9fba6..000000000000
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
- * Copyright 2004-2008 Freescale Semiconductor, Inc.
- * Copyright 2009 Semihalf.
- *
- * Approved as OSADL project by a majority of OSADL members and funded
- * by OSADL membership fees in 2009;  for details see www.osadl.org.
- *
- * Based on original driver from Freescale Semiconductor
- * written by John Rigby <jrigby@freescale.com> on basis
- * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
- * Piotr Ziecik <kosmo@semihalf.com>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/gfp.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-
-#include <asm/mpc5121.h>
-
-/* Addresses for NFC MAIN RAM BUFFER areas */
-#define NFC_MAIN_AREA(n)	((n) *  0x200)
-
-/* Addresses for NFC SPARE BUFFER areas */
-#define NFC_SPARE_BUFFERS	8
-#define NFC_SPARE_LEN		0x40
-#define NFC_SPARE_AREA(n)	(0x1000 + ((n) * NFC_SPARE_LEN))
-
-/* MPC5121 NFC registers */
-#define NFC_BUF_ADDR		0x1E04
-#define NFC_FLASH_ADDR		0x1E06
-#define NFC_FLASH_CMD		0x1E08
-#define NFC_CONFIG		0x1E0A
-#define NFC_ECC_STATUS1		0x1E0C
-#define NFC_ECC_STATUS2		0x1E0E
-#define NFC_SPAS		0x1E10
-#define NFC_WRPROT		0x1E12
-#define NFC_NF_WRPRST		0x1E18
-#define NFC_CONFIG1		0x1E1A
-#define NFC_CONFIG2		0x1E1C
-#define NFC_UNLOCKSTART_BLK0	0x1E20
-#define NFC_UNLOCKEND_BLK0	0x1E22
-#define NFC_UNLOCKSTART_BLK1	0x1E24
-#define NFC_UNLOCKEND_BLK1	0x1E26
-#define NFC_UNLOCKSTART_BLK2	0x1E28
-#define NFC_UNLOCKEND_BLK2	0x1E2A
-#define NFC_UNLOCKSTART_BLK3	0x1E2C
-#define NFC_UNLOCKEND_BLK3	0x1E2E
-
-/* Bit Definitions: NFC_BUF_ADDR */
-#define NFC_RBA_MASK		(7 << 0)
-#define NFC_ACTIVE_CS_SHIFT	5
-#define NFC_ACTIVE_CS_MASK	(3 << NFC_ACTIVE_CS_SHIFT)
-
-/* Bit Definitions: NFC_CONFIG */
-#define NFC_BLS_UNLOCKED	(1 << 1)
-
-/* Bit Definitions: NFC_CONFIG1 */
-#define NFC_ECC_4BIT		(1 << 0)
-#define NFC_FULL_PAGE_DMA	(1 << 1)
-#define NFC_SPARE_ONLY		(1 << 2)
-#define NFC_ECC_ENABLE		(1 << 3)
-#define NFC_INT_MASK		(1 << 4)
-#define NFC_BIG_ENDIAN		(1 << 5)
-#define NFC_RESET		(1 << 6)
-#define NFC_CE			(1 << 7)
-#define NFC_ONE_CYCLE		(1 << 8)
-#define NFC_PPB_32		(0 << 9)
-#define NFC_PPB_64		(1 << 9)
-#define NFC_PPB_128		(2 << 9)
-#define NFC_PPB_256		(3 << 9)
-#define NFC_PPB_MASK		(3 << 9)
-#define NFC_FULL_PAGE_INT	(1 << 11)
-
-/* Bit Definitions: NFC_CONFIG2 */
-#define NFC_COMMAND		(1 << 0)
-#define NFC_ADDRESS		(1 << 1)
-#define NFC_INPUT		(1 << 2)
-#define NFC_OUTPUT		(1 << 3)
-#define NFC_ID			(1 << 4)
-#define NFC_STATUS		(1 << 5)
-#define NFC_CMD_FAIL		(1 << 15)
-#define NFC_INT			(1 << 15)
-
-/* Bit Definitions: NFC_WRPROT */
-#define NFC_WPC_LOCK_TIGHT	(1 << 0)
-#define NFC_WPC_LOCK		(1 << 1)
-#define NFC_WPC_UNLOCK		(1 << 2)
-
-#define	DRV_NAME		"mpc5121_nfc"
-
-/* Timeouts */
-#define NFC_RESET_TIMEOUT	1000		/* 1 ms */
-#define NFC_TIMEOUT		(HZ / 10)	/* 1/10 s */
-
-struct mpc5121_nfc_prv {
-	struct nand_chip	chip;
-	int			irq;
-	void __iomem		*regs;
-	struct clk		*clk;
-	wait_queue_head_t	irq_waitq;
-	uint			column;
-	int			spareonly;
-	void __iomem		*csreg;
-	struct device		*dev;
-};
-
-static void mpc5121_nfc_done(struct mtd_info *mtd);
-
-/* Read NFC register */
-static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-
-	return in_be16(prv->regs + reg);
-}
-
-/* Write NFC register */
-static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-
-	out_be16(prv->regs + reg, val);
-}
-
-/* Set bits in NFC register */
-static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
-{
-	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
-}
-
-/* Clear bits in NFC register */
-static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
-{
-	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
-}
-
-/* Invoke address cycle */
-static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
-{
-	nfc_write(mtd, NFC_FLASH_ADDR, addr);
-	nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
-	mpc5121_nfc_done(mtd);
-}
-
-/* Invoke command cycle */
-static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
-{
-	nfc_write(mtd, NFC_FLASH_CMD, cmd);
-	nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
-	mpc5121_nfc_done(mtd);
-}
-
-/* Send data from NFC buffers to NAND flash */
-static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
-{
-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
-	nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
-	mpc5121_nfc_done(mtd);
-}
-
-/* Receive data from NAND flash */
-static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
-{
-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
-	nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
-	mpc5121_nfc_done(mtd);
-}
-
-/* Receive ID from NAND flash */
-static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
-{
-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
-	nfc_write(mtd, NFC_CONFIG2, NFC_ID);
-	mpc5121_nfc_done(mtd);
-}
-
-/* Receive status from NAND flash */
-static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
-{
-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
-	nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
-	mpc5121_nfc_done(mtd);
-}
-
-/* NFC interrupt handler */
-static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
-{
-	struct mtd_info *mtd = data;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-
-	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
-	wake_up(&prv->irq_waitq);
-
-	return IRQ_HANDLED;
-}
-
-/* Wait for operation complete */
-static void mpc5121_nfc_done(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-	int rv;
-
-	if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
-		nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
-		rv = wait_event_timeout(prv->irq_waitq,
-			(nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
-
-		if (!rv)
-			dev_warn(prv->dev,
-				"Timeout while waiting for interrupt.\n");
-	}
-
-	nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
-}
-
-/* Do address cycle(s) */
-static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u32 pagemask = chip->pagemask;
-
-	if (column != -1) {
-		mpc5121_nfc_send_addr(mtd, column);
-		if (mtd->writesize > 512)
-			mpc5121_nfc_send_addr(mtd, column >> 8);
-	}
-
-	if (page != -1) {
-		do {
-			mpc5121_nfc_send_addr(mtd, page & 0xFF);
-			page >>= 8;
-			pagemask >>= 8;
-		} while (pagemask);
-	}
-}
-
-/* Control chip select signals */
-static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
-{
-	if (chip < 0) {
-		nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
-		return;
-	}
-
-	nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
-	nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
-							NFC_ACTIVE_CS_MASK);
-	nfc_set(mtd, NFC_CONFIG1, NFC_CE);
-}
-
-/* Init external chip select logic on ADS5121 board */
-static int ads5121_chipselect_init(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-	struct device_node *dn;
-
-	dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
-	if (dn) {
-		prv->csreg = of_iomap(dn, 0);
-		of_node_put(dn);
-		if (!prv->csreg)
-			return -ENOMEM;
-
-		/* CPLD Register 9 controls NAND /CE Lines */
-		prv->csreg += 9;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-/* Control chips select signal on ADS5121 board */
-static void ads5121_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
-	u8 v;
-
-	v = in_8(prv->csreg);
-	v |= 0x0F;
-
-	if (chip >= 0) {
-		mpc5121_nfc_select_chip(mtd, 0);
-		v &= ~(1 << chip);
-	} else
-		mpc5121_nfc_select_chip(mtd, -1);
-
-	out_8(prv->csreg, v);
-}
-
-/* Read NAND Ready/Busy signal */
-static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
-{
-	/*
-	 * NFC handles ready/busy signal internally. Therefore, this function
-	 * always returns status as ready.
-	 */
-	return 1;
-}
-
-/* Write command to NAND flash */
-static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
-							int column, int page)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-
-	prv->column = (column >= 0) ? column : 0;
-	prv->spareonly = 0;
-
-	switch (command) {
-	case NAND_CMD_PAGEPROG:
-		mpc5121_nfc_send_prog_page(mtd);
-		break;
-	/*
-	 * NFC does not support sub-page reads and writes,
-	 * so emulate them using full page transfers.
-	 */
-	case NAND_CMD_READ0:
-		column = 0;
-		break;
-
-	case NAND_CMD_READ1:
-		prv->column += 256;
-		command = NAND_CMD_READ0;
-		column = 0;
-		break;
-
-	case NAND_CMD_READOOB:
-		prv->spareonly = 1;
-		command = NAND_CMD_READ0;
-		column = 0;
-		break;
-
-	case NAND_CMD_SEQIN:
-		mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
-		column = 0;
-		break;
-
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_READID:
-	case NAND_CMD_STATUS:
-		break;
-
-	default:
-		return;
-	}
-
-	mpc5121_nfc_send_cmd(mtd, command);
-	mpc5121_nfc_addr_cycle(mtd, column, page);
-
-	switch (command) {
-	case NAND_CMD_READ0:
-		if (mtd->writesize > 512)
-			mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
-		mpc5121_nfc_send_read_page(mtd);
-		break;
-
-	case NAND_CMD_READID:
-		mpc5121_nfc_send_read_id(mtd);
-		break;
-
-	case NAND_CMD_STATUS:
-		mpc5121_nfc_send_read_status(mtd);
-		if (chip->options & NAND_BUSWIDTH_16)
-			prv->column = 1;
-		else
-			prv->column = 0;
-		break;
-	}
-}
-
-/* Copy data from/to NFC spare buffers. */
-static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
-						u8 *buffer, uint size, int wr)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
-	uint o, s, sbsize, blksize;
-
-	/*
-	 * NAND spare area is available through NFC spare buffers.
-	 * The NFC divides spare area into (page_size / 512) chunks.
-	 * Each chunk is placed into separate spare memory area, using
-	 * first (spare_size / num_of_chunks) bytes of the buffer.
-	 *
-	 * For NAND device in which the spare area is not divided fully
-	 * by the number of chunks, number of used bytes in each spare
-	 * buffer is rounded down to the nearest even number of bytes,
-	 * and all remaining bytes are added to the last used spare area.
-	 *
-	 * For more information read section 26.6.10 of MPC5121e
-	 * Microcontroller Reference Manual, Rev. 3.
-	 */
-
-	/* Calculate number of valid bytes in each spare buffer */
-	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
-
-	while (size) {
-		/* Calculate spare buffer number */
-		s = offset / sbsize;
-		if (s > NFC_SPARE_BUFFERS - 1)
-			s = NFC_SPARE_BUFFERS - 1;
-
-		/*
-		 * Calculate offset to requested data block in selected spare
-		 * buffer and its size.
-		 */
-		o = offset - (s * sbsize);
-		blksize = min(sbsize - o, size);
-
-		if (wr)
-			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
-							buffer, blksize);
-		else
-			memcpy_fromio(buffer,
-				prv->regs + NFC_SPARE_AREA(s) + o, blksize);
-
-		buffer += blksize;
-		offset += blksize;
-		size -= blksize;
-	};
-}
-
-/* Copy data from/to NFC main and spare buffers */
-static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
-									int wr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-	uint c = prv->column;
-	uint l;
-
-	/* Handle spare area access */
-	if (prv->spareonly || c >= mtd->writesize) {
-		/* Calculate offset from beginning of spare area */
-		if (c >= mtd->writesize)
-			c -= mtd->writesize;
-
-		prv->column += len;
-		mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
-		return;
-	}
-
-	/*
-	 * Handle main area access - limit copy length to prevent
-	 * crossing main/spare boundary.
-	 */
-	l = min((uint)len, mtd->writesize - c);
-	prv->column += l;
-
-	if (wr)
-		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
-	else
-		memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
-
-	/* Handle crossing main/spare boundary */
-	if (l != len) {
-		buf += l;
-		len -= l;
-		mpc5121_nfc_buf_copy(mtd, buf, len, wr);
-	}
-}
-
-/* Read data from NFC buffers */
-static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	mpc5121_nfc_buf_copy(mtd, buf, len, 0);
-}
-
-/* Write data to NFC buffers */
-static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
-						const u_char *buf, int len)
-{
-	mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
-}
-
-/* Read byte from NFC buffers */
-static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
-{
-	u8 tmp;
-
-	mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
-
-	return tmp;
-}
-
-/* Read word from NFC buffers */
-static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
-{
-	u16 tmp;
-
-	mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
-
-	return tmp;
-}
-
-/*
- * Read NFC configuration from Reset Config Word
- *
- * NFC is configured during reset in basis of information stored
- * in Reset Config Word. There is no other way to set NAND block
- * size, spare size and bus width.
- */
-static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-	struct mpc512x_reset_module *rm;
-	struct device_node *rmnode;
-	uint rcw_pagesize = 0;
-	uint rcw_sparesize = 0;
-	uint rcw_width;
-	uint rcwh;
-	uint romloc, ps;
-	int ret = 0;
-
-	rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
-	if (!rmnode) {
-		dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' "
-					"node in device tree!\n");
-		return -ENODEV;
-	}
-
-	rm = of_iomap(rmnode, 0);
-	if (!rm) {
-		dev_err(prv->dev, "Error mapping reset module node!\n");
-		ret = -EBUSY;
-		goto out;
-	}
-
-	rcwh = in_be32(&rm->rcwhr);
-
-	/* Bit 6: NFC bus width */
-	rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
-
-	/* Bit 7: NFC Page/Spare size */
-	ps = (rcwh >> 7) & 0x1;
-
-	/* Bits [22:21]: ROM Location */
-	romloc = (rcwh >> 21) & 0x3;
-
-	/* Decode RCW bits */
-	switch ((ps << 2) | romloc) {
-	case 0x00:
-	case 0x01:
-		rcw_pagesize = 512;
-		rcw_sparesize = 16;
-		break;
-	case 0x02:
-	case 0x03:
-		rcw_pagesize = 4096;
-		rcw_sparesize = 128;
-		break;
-	case 0x04:
-	case 0x05:
-		rcw_pagesize = 2048;
-		rcw_sparesize = 64;
-		break;
-	case 0x06:
-	case 0x07:
-		rcw_pagesize = 4096;
-		rcw_sparesize = 218;
-		break;
-	}
-
-	mtd->writesize = rcw_pagesize;
-	mtd->oobsize = rcw_sparesize;
-	if (rcw_width == 2)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	dev_notice(prv->dev, "Configured for "
-				"%u-bit NAND, page size %u "
-				"with %u spare.\n",
-				rcw_width * 8, rcw_pagesize,
-				rcw_sparesize);
-	iounmap(rm);
-out:
-	of_node_put(rmnode);
-	return ret;
-}
-
-/* Free driver resources */
-static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
-
-	if (prv->clk)
-		clk_disable_unprepare(prv->clk);
-
-	if (prv->csreg)
-		iounmap(prv->csreg);
-}
-
-static int mpc5121_nfc_probe(struct platform_device *op)
-{
-	struct device_node *dn = op->dev.of_node;
-	struct clk *clk;
-	struct device *dev = &op->dev;
-	struct mpc5121_nfc_prv *prv;
-	struct resource res;
-	struct mtd_info *mtd;
-	struct nand_chip *chip;
-	unsigned long regs_paddr, regs_size;
-	const __be32 *chips_no;
-	int resettime = 0;
-	int retval = 0;
-	int rev, len;
-
-	/*
-	 * Check SoC revision. This driver supports only NFC
-	 * in MPC5121 revision 2 and MPC5123 revision 3.
-	 */
-	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
-	if ((rev != 2) && (rev != 3)) {
-		dev_err(dev, "SoC revision %u is not supported!\n", rev);
-		return -ENXIO;
-	}
-
-	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
-	if (!prv)
-		return -ENOMEM;
-
-	chip = &prv->chip;
-	mtd = nand_to_mtd(chip);
-
-	mtd->dev.parent = dev;
-	nand_set_controller_data(chip, prv);
-	nand_set_flash_node(chip, dn);
-	prv->dev = dev;
-
-	/* Read NFC configuration from Reset Config Word */
-	retval = mpc5121_nfc_read_hw_config(mtd);
-	if (retval) {
-		dev_err(dev, "Unable to read NFC config!\n");
-		return retval;
-	}
-
-	prv->irq = irq_of_parse_and_map(dn, 0);
-	if (prv->irq == NO_IRQ) {
-		dev_err(dev, "Error mapping IRQ!\n");
-		return -EINVAL;
-	}
-
-	retval = of_address_to_resource(dn, 0, &res);
-	if (retval) {
-		dev_err(dev, "Error parsing memory region!\n");
-		return retval;
-	}
-
-	chips_no = of_get_property(dn, "chips", &len);
-	if (!chips_no || len != sizeof(*chips_no)) {
-		dev_err(dev, "Invalid/missing 'chips' property!\n");
-		return -EINVAL;
-	}
-
-	regs_paddr = res.start;
-	regs_size = resource_size(&res);
-
-	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
-		dev_err(dev, "Error requesting memory region!\n");
-		return -EBUSY;
-	}
-
-	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
-	if (!prv->regs) {
-		dev_err(dev, "Error mapping memory region!\n");
-		return -ENOMEM;
-	}
-
-	mtd->name = "MPC5121 NAND";
-	chip->dev_ready = mpc5121_nfc_dev_ready;
-	chip->cmdfunc = mpc5121_nfc_command;
-	chip->read_byte = mpc5121_nfc_read_byte;
-	chip->read_word = mpc5121_nfc_read_word;
-	chip->read_buf = mpc5121_nfc_read_buf;
-	chip->write_buf = mpc5121_nfc_write_buf;
-	chip->select_chip = mpc5121_nfc_select_chip;
-	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
-	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
-	chip->bbt_options = NAND_BBT_USE_FLASH;
-	chip->ecc.mode = NAND_ECC_SOFT;
-	chip->ecc.algo = NAND_ECC_HAMMING;
-
-	/* Support external chip-select logic on ADS5121 board */
-	if (of_machine_is_compatible("fsl,mpc5121ads")) {
-		retval = ads5121_chipselect_init(mtd);
-		if (retval) {
-			dev_err(dev, "Chipselect init error!\n");
-			return retval;
-		}
-
-		chip->select_chip = ads5121_select_chip;
-	}
-
-	/* Enable NFC clock */
-	clk = devm_clk_get(dev, "ipg");
-	if (IS_ERR(clk)) {
-		dev_err(dev, "Unable to acquire NFC clock!\n");
-		retval = PTR_ERR(clk);
-		goto error;
-	}
-	retval = clk_prepare_enable(clk);
-	if (retval) {
-		dev_err(dev, "Unable to enable NFC clock!\n");
-		goto error;
-	}
-	prv->clk = clk;
-
-	/* Reset NAND Flash controller */
-	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
-	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
-		if (resettime++ >= NFC_RESET_TIMEOUT) {
-			dev_err(dev, "Timeout while resetting NFC!\n");
-			retval = -EINVAL;
-			goto error;
-		}
-
-		udelay(1);
-	}
-
-	/* Enable write to NFC memory */
-	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
-
-	/* Enable write to all NAND pages */
-	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
-	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
-	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
-
-	/*
-	 * Setup NFC:
-	 *	- Big Endian transfers,
-	 *	- Interrupt after full page read/write.
-	 */
-	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
-							NFC_FULL_PAGE_INT);
-
-	/* Set spare area size */
-	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
-
-	init_waitqueue_head(&prv->irq_waitq);
-	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
-									mtd);
-	if (retval) {
-		dev_err(dev, "Error requesting IRQ!\n");
-		goto error;
-	}
-
-	/* Detect NAND chips */
-	retval = nand_scan(mtd, be32_to_cpup(chips_no));
-	if (retval) {
-		dev_err(dev, "NAND Flash not found !\n");
-		goto error;
-	}
-
-	/* Set erase block size */
-	switch (mtd->erasesize / mtd->writesize) {
-	case 32:
-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
-		break;
-
-	case 64:
-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
-		break;
-
-	case 128:
-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
-		break;
-
-	case 256:
-		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
-		break;
-
-	default:
-		dev_err(dev, "Unsupported NAND flash!\n");
-		retval = -ENXIO;
-		goto error;
-	}
-
-	dev_set_drvdata(dev, mtd);
-
-	/* Register device in MTD */
-	retval = mtd_device_register(mtd, NULL, 0);
-	if (retval) {
-		dev_err(dev, "Error adding MTD device!\n");
-		goto error;
-	}
-
-	return 0;
-error:
-	mpc5121_nfc_free(dev, mtd);
-	return retval;
-}
-
-static int mpc5121_nfc_remove(struct platform_device *op)
-{
-	struct device *dev = &op->dev;
-	struct mtd_info *mtd = dev_get_drvdata(dev);
-
-	nand_release(mtd);
-	mpc5121_nfc_free(dev, mtd);
-
-	return 0;
-}
-
-static const struct of_device_id mpc5121_nfc_match[] = {
-	{ .compatible = "fsl,mpc5121-nfc", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
-
-static struct platform_driver mpc5121_nfc_driver = {
-	.probe		= mpc5121_nfc_probe,
-	.remove		= mpc5121_nfc_remove,
-	.driver		= {
-		.name = DRV_NAME,
-		.of_match_table = mpc5121_nfc_match,
-	},
-};
-
-module_platform_driver(mpc5121_nfc_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
deleted file mode 100644
index 40d86a861a70..000000000000
--- a/drivers/mtd/nand/mtk_ecc.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * MTK ECC controller driver.
- * Copyright (C) 2016  MediaTek Inc.
- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
- *
- * 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/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/iopoll.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/mutex.h>
-
-#include "mtk_ecc.h"
-
-#define ECC_IDLE_MASK		BIT(0)
-#define ECC_IRQ_EN		BIT(0)
-#define ECC_PG_IRQ_SEL		BIT(1)
-#define ECC_OP_ENABLE		(1)
-#define ECC_OP_DISABLE		(0)
-
-#define ECC_ENCCON		(0x00)
-#define ECC_ENCCNFG		(0x04)
-#define		ECC_MS_SHIFT		(16)
-#define ECC_ENCDIADDR		(0x08)
-#define ECC_ENCIDLE		(0x0C)
-#define ECC_DECCON		(0x100)
-#define ECC_DECCNFG		(0x104)
-#define		DEC_EMPTY_EN		BIT(31)
-#define		DEC_CNFG_CORRECT	(0x3 << 12)
-#define ECC_DECIDLE		(0x10C)
-#define ECC_DECENUM0		(0x114)
-
-#define ECC_TIMEOUT		(500000)
-
-#define ECC_IDLE_REG(op)	((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
-#define ECC_CTL_REG(op)		((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
-
-struct mtk_ecc_caps {
-	u32 err_mask;
-	const u8 *ecc_strength;
-	const u32 *ecc_regs;
-	u8 num_ecc_strength;
-	u8 ecc_mode_shift;
-	u32 parity_bits;
-	int pg_irq_sel;
-};
-
-struct mtk_ecc {
-	struct device *dev;
-	const struct mtk_ecc_caps *caps;
-	void __iomem *regs;
-	struct clk *clk;
-
-	struct completion done;
-	struct mutex lock;
-	u32 sectors;
-
-	u8 *eccdata;
-};
-
-/* ecc strength that each IP supports */
-static const u8 ecc_strength_mt2701[] = {
-	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
-	40, 44, 48, 52, 56, 60
-};
-
-static const u8 ecc_strength_mt2712[] = {
-	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
-	40, 44, 48, 52, 56, 60, 68, 72, 80
-};
-
-static const u8 ecc_strength_mt7622[] = {
-	4, 6, 8, 10, 12, 14, 16
-};
-
-enum mtk_ecc_regs {
-	ECC_ENCPAR00,
-	ECC_ENCIRQ_EN,
-	ECC_ENCIRQ_STA,
-	ECC_DECDONE,
-	ECC_DECIRQ_EN,
-	ECC_DECIRQ_STA,
-};
-
-static int mt2701_ecc_regs[] = {
-	[ECC_ENCPAR00] =        0x10,
-	[ECC_ENCIRQ_EN] =       0x80,
-	[ECC_ENCIRQ_STA] =      0x84,
-	[ECC_DECDONE] =         0x124,
-	[ECC_DECIRQ_EN] =       0x200,
-	[ECC_DECIRQ_STA] =      0x204,
-};
-
-static int mt2712_ecc_regs[] = {
-	[ECC_ENCPAR00] =        0x300,
-	[ECC_ENCIRQ_EN] =       0x80,
-	[ECC_ENCIRQ_STA] =      0x84,
-	[ECC_DECDONE] =         0x124,
-	[ECC_DECIRQ_EN] =       0x200,
-	[ECC_DECIRQ_STA] =      0x204,
-};
-
-static int mt7622_ecc_regs[] = {
-	[ECC_ENCPAR00] =        0x10,
-	[ECC_ENCIRQ_EN] =       0x30,
-	[ECC_ENCIRQ_STA] =      0x34,
-	[ECC_DECDONE] =         0x11c,
-	[ECC_DECIRQ_EN] =       0x140,
-	[ECC_DECIRQ_STA] =      0x144,
-};
-
-static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
-				     enum mtk_ecc_operation op)
-{
-	struct device *dev = ecc->dev;
-	u32 val;
-	int ret;
-
-	ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(op), val,
-					val & ECC_IDLE_MASK,
-					10, ECC_TIMEOUT);
-	if (ret)
-		dev_warn(dev, "%s NOT idle\n",
-			 op == ECC_ENCODE ? "encoder" : "decoder");
-}
-
-static irqreturn_t mtk_ecc_irq(int irq, void *id)
-{
-	struct mtk_ecc *ecc = id;
-	u32 dec, enc;
-
-	dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA])
-		    & ECC_IRQ_EN;
-	if (dec) {
-		dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
-		if (dec & ecc->sectors) {
-			/*
-			 * Clear decode IRQ status once again to ensure that
-			 * there will be no extra IRQ.
-			 */
-			readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA]);
-			ecc->sectors = 0;
-			complete(&ecc->done);
-		} else {
-			return IRQ_HANDLED;
-		}
-	} else {
-		enc = readl(ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_STA])
-		      & ECC_IRQ_EN;
-		if (enc)
-			complete(&ecc->done);
-		else
-			return IRQ_NONE;
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
-{
-	u32 ecc_bit, dec_sz, enc_sz;
-	u32 reg, i;
-
-	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
-		if (ecc->caps->ecc_strength[i] == config->strength)
-			break;
-	}
-
-	if (i == ecc->caps->num_ecc_strength) {
-		dev_err(ecc->dev, "invalid ecc strength %d\n",
-			config->strength);
-		return -EINVAL;
-	}
-
-	ecc_bit = i;
-
-	if (config->op == ECC_ENCODE) {
-		/* configure ECC encoder (in bits) */
-		enc_sz = config->len << 3;
-
-		reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
-		reg |= (enc_sz << ECC_MS_SHIFT);
-		writel(reg, ecc->regs + ECC_ENCCNFG);
-
-		if (config->mode != ECC_NFI_MODE)
-			writel(lower_32_bits(config->addr),
-			       ecc->regs + ECC_ENCDIADDR);
-
-	} else {
-		/* configure ECC decoder (in bits) */
-		dec_sz = (config->len << 3) +
-			 config->strength * ecc->caps->parity_bits;
-
-		reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
-		reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
-		reg |= DEC_EMPTY_EN;
-		writel(reg, ecc->regs + ECC_DECCNFG);
-
-		if (config->sectors)
-			ecc->sectors = 1 << (config->sectors - 1);
-	}
-
-	return 0;
-}
-
-void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
-		       int sectors)
-{
-	u32 offset, i, err;
-	u32 bitflips = 0;
-
-	stats->corrected = 0;
-	stats->failed = 0;
-
-	for (i = 0; i < sectors; i++) {
-		offset = (i >> 2) << 2;
-		err = readl(ecc->regs + ECC_DECENUM0 + offset);
-		err = err >> ((i % 4) * 8);
-		err &= ecc->caps->err_mask;
-		if (err == ecc->caps->err_mask) {
-			/* uncorrectable errors */
-			stats->failed++;
-			continue;
-		}
-
-		stats->corrected += err;
-		bitflips = max_t(u32, bitflips, err);
-	}
-
-	stats->bitflips = bitflips;
-}
-EXPORT_SYMBOL(mtk_ecc_get_stats);
-
-void mtk_ecc_release(struct mtk_ecc *ecc)
-{
-	clk_disable_unprepare(ecc->clk);
-	put_device(ecc->dev);
-}
-EXPORT_SYMBOL(mtk_ecc_release);
-
-static void mtk_ecc_hw_init(struct mtk_ecc *ecc)
-{
-	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
-	writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
-
-	mtk_ecc_wait_idle(ecc, ECC_DECODE);
-	writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
-}
-
-static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
-{
-	struct platform_device *pdev;
-	struct mtk_ecc *ecc;
-
-	pdev = of_find_device_by_node(np);
-	if (!pdev || !platform_get_drvdata(pdev))
-		return ERR_PTR(-EPROBE_DEFER);
-
-	get_device(&pdev->dev);
-	ecc = platform_get_drvdata(pdev);
-	clk_prepare_enable(ecc->clk);
-	mtk_ecc_hw_init(ecc);
-
-	return ecc;
-}
-
-struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
-{
-	struct mtk_ecc *ecc = NULL;
-	struct device_node *np;
-
-	np = of_parse_phandle(of_node, "ecc-engine", 0);
-	if (np) {
-		ecc = mtk_ecc_get(np);
-		of_node_put(np);
-	}
-
-	return ecc;
-}
-EXPORT_SYMBOL(of_mtk_ecc_get);
-
-int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
-{
-	enum mtk_ecc_operation op = config->op;
-	u16 reg_val;
-	int ret;
-
-	ret = mutex_lock_interruptible(&ecc->lock);
-	if (ret) {
-		dev_err(ecc->dev, "interrupted when attempting to lock\n");
-		return ret;
-	}
-
-	mtk_ecc_wait_idle(ecc, op);
-
-	ret = mtk_ecc_config(ecc, config);
-	if (ret) {
-		mutex_unlock(&ecc->lock);
-		return ret;
-	}
-
-	if (config->mode != ECC_NFI_MODE || op != ECC_ENCODE) {
-		init_completion(&ecc->done);
-		reg_val = ECC_IRQ_EN;
-		/*
-		 * For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it
-		 * means this chip can only generate one ecc irq during page
-		 * read / write. If is 0, generate one ecc irq each ecc step.
-		 */
-		if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
-			reg_val |= ECC_PG_IRQ_SEL;
-		if (op == ECC_ENCODE)
-			writew(reg_val, ecc->regs +
-			       ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
-		else
-			writew(reg_val, ecc->regs +
-			       ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
-	}
-
-	writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
-
-	return 0;
-}
-EXPORT_SYMBOL(mtk_ecc_enable);
-
-void mtk_ecc_disable(struct mtk_ecc *ecc)
-{
-	enum mtk_ecc_operation op = ECC_ENCODE;
-
-	/* find out the running operation */
-	if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
-		op = ECC_DECODE;
-
-	/* disable it */
-	mtk_ecc_wait_idle(ecc, op);
-	if (op == ECC_DECODE) {
-		/*
-		 * Clear decode IRQ status in case there is a timeout to wait
-		 * decode IRQ.
-		 */
-		readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
-		writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
-	} else {
-		writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
-	}
-
-	writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
-
-	mutex_unlock(&ecc->lock);
-}
-EXPORT_SYMBOL(mtk_ecc_disable);
-
-int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op)
-{
-	int ret;
-
-	ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
-	if (!ret) {
-		dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
-			(op == ECC_ENCODE) ? "encoder" : "decoder");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(mtk_ecc_wait_done);
-
-int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
-		   u8 *data, u32 bytes)
-{
-	dma_addr_t addr;
-	u32 len;
-	int ret;
-
-	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
-	ret = dma_mapping_error(ecc->dev, addr);
-	if (ret) {
-		dev_err(ecc->dev, "dma mapping error\n");
-		return -EINVAL;
-	}
-
-	config->op = ECC_ENCODE;
-	config->addr = addr;
-	ret = mtk_ecc_enable(ecc, config);
-	if (ret) {
-		dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
-		return ret;
-	}
-
-	ret = mtk_ecc_wait_done(ecc, ECC_ENCODE);
-	if (ret)
-		goto timeout;
-
-	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
-
-	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
-	len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
-
-	/* write the parity bytes generated by the ECC back to temp buffer */
-	__ioread32_copy(ecc->eccdata,
-			ecc->regs + ecc->caps->ecc_regs[ECC_ENCPAR00],
-			round_up(len, 4));
-
-	/* copy into possibly unaligned OOB region with actual length */
-	memcpy(data + bytes, ecc->eccdata, len);
-timeout:
-
-	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
-	mtk_ecc_disable(ecc);
-
-	return ret;
-}
-EXPORT_SYMBOL(mtk_ecc_encode);
-
-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
-{
-	const u8 *ecc_strength = ecc->caps->ecc_strength;
-	int i;
-
-	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
-		if (*p <= ecc_strength[i]) {
-			if (!i)
-				*p = ecc_strength[i];
-			else if (*p != ecc_strength[i])
-				*p = ecc_strength[i - 1];
-			return;
-		}
-	}
-
-	*p = ecc_strength[ecc->caps->num_ecc_strength - 1];
-}
-EXPORT_SYMBOL(mtk_ecc_adjust_strength);
-
-unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
-{
-	return ecc->caps->parity_bits;
-}
-EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
-
-static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
-	.err_mask = 0x3f,
-	.ecc_strength = ecc_strength_mt2701,
-	.ecc_regs = mt2701_ecc_regs,
-	.num_ecc_strength = 20,
-	.ecc_mode_shift = 5,
-	.parity_bits = 14,
-	.pg_irq_sel = 0,
-};
-
-static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
-	.err_mask = 0x7f,
-	.ecc_strength = ecc_strength_mt2712,
-	.ecc_regs = mt2712_ecc_regs,
-	.num_ecc_strength = 23,
-	.ecc_mode_shift = 5,
-	.parity_bits = 14,
-	.pg_irq_sel = 1,
-};
-
-static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
-	.err_mask = 0x3f,
-	.ecc_strength = ecc_strength_mt7622,
-	.ecc_regs = mt7622_ecc_regs,
-	.num_ecc_strength = 7,
-	.ecc_mode_shift = 4,
-	.parity_bits = 13,
-	.pg_irq_sel = 0,
-};
-
-static const struct of_device_id mtk_ecc_dt_match[] = {
-	{
-		.compatible = "mediatek,mt2701-ecc",
-		.data = &mtk_ecc_caps_mt2701,
-	}, {
-		.compatible = "mediatek,mt2712-ecc",
-		.data = &mtk_ecc_caps_mt2712,
-	}, {
-		.compatible = "mediatek,mt7622-ecc",
-		.data = &mtk_ecc_caps_mt7622,
-	},
-	{},
-};
-
-static int mtk_ecc_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct mtk_ecc *ecc;
-	struct resource *res;
-	const struct of_device_id *of_ecc_id = NULL;
-	u32 max_eccdata_size;
-	int irq, ret;
-
-	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
-	if (!ecc)
-		return -ENOMEM;
-
-	of_ecc_id = of_match_device(mtk_ecc_dt_match, &pdev->dev);
-	if (!of_ecc_id)
-		return -ENODEV;
-
-	ecc->caps = of_ecc_id->data;
-
-	max_eccdata_size = ecc->caps->num_ecc_strength - 1;
-	max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
-	max_eccdata_size = (max_eccdata_size * ecc->caps->parity_bits + 7) >> 3;
-	max_eccdata_size = round_up(max_eccdata_size, 4);
-	ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
-	if (!ecc->eccdata)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	ecc->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(ecc->regs)) {
-		dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
-		return PTR_ERR(ecc->regs);
-	}
-
-	ecc->clk = devm_clk_get(dev, NULL);
-	if (IS_ERR(ecc->clk)) {
-		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
-		return PTR_ERR(ecc->clk);
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "failed to get irq: %d\n", irq);
-		return irq;
-	}
-
-	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
-	if (ret) {
-		dev_err(dev, "failed to set DMA mask\n");
-		return ret;
-	}
-
-	ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
-	if (ret) {
-		dev_err(dev, "failed to request irq\n");
-		return -EINVAL;
-	}
-
-	ecc->dev = dev;
-	mutex_init(&ecc->lock);
-	platform_set_drvdata(pdev, ecc);
-	dev_info(dev, "probed\n");
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int mtk_ecc_suspend(struct device *dev)
-{
-	struct mtk_ecc *ecc = dev_get_drvdata(dev);
-
-	clk_disable_unprepare(ecc->clk);
-
-	return 0;
-}
-
-static int mtk_ecc_resume(struct device *dev)
-{
-	struct mtk_ecc *ecc = dev_get_drvdata(dev);
-	int ret;
-
-	ret = clk_prepare_enable(ecc->clk);
-	if (ret) {
-		dev_err(dev, "failed to enable clk\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
-#endif
-
-MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
-
-static struct platform_driver mtk_ecc_driver = {
-	.probe  = mtk_ecc_probe,
-	.driver = {
-		.name  = "mtk-ecc",
-		.of_match_table = of_match_ptr(mtk_ecc_dt_match),
-#ifdef CONFIG_PM_SLEEP
-		.pm = &mtk_ecc_pm_ops,
-#endif
-	},
-};
-
-module_platform_driver(mtk_ecc_driver);
-
-MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
-MODULE_DESCRIPTION("MTK Nand ECC Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/mtk_ecc.h b/drivers/mtd/nand/mtk_ecc.h
deleted file mode 100644
index a455df080952..000000000000
--- a/drivers/mtd/nand/mtk_ecc.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * MTK SDG1 ECC controller
- *
- * Copyright (c) 2016 Mediatek
- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
- * 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 __DRIVERS_MTD_NAND_MTK_ECC_H__
-#define __DRIVERS_MTD_NAND_MTK_ECC_H__
-
-#include <linux/types.h>
-
-enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
-enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
-
-struct device_node;
-struct mtk_ecc;
-
-struct mtk_ecc_stats {
-	u32 corrected;
-	u32 bitflips;
-	u32 failed;
-};
-
-struct mtk_ecc_config {
-	enum mtk_ecc_operation op;
-	enum mtk_ecc_mode mode;
-	dma_addr_t addr;
-	u32 strength;
-	u32 sectors;
-	u32 len;
-};
-
-int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
-void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
-int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
-int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
-void mtk_ecc_disable(struct mtk_ecc *);
-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
-unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
-
-struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
-void mtk_ecc_release(struct mtk_ecc *);
-
-#endif
diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c
deleted file mode 100644
index 6977da3a26aa..000000000000
--- a/drivers/mtd/nand/mtk_nand.c
+++ /dev/null
@@ -1,1599 +0,0 @@
-/*
- * MTK NAND Flash controller driver.
- * Copyright (C) 2016 MediaTek Inc.
- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
- *
- * 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/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/mtd.h>
-#include <linux/module.h>
-#include <linux/iopoll.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include "mtk_ecc.h"
-
-/* NAND controller register definition */
-#define NFI_CNFG		(0x00)
-#define		CNFG_AHB		BIT(0)
-#define		CNFG_READ_EN		BIT(1)
-#define		CNFG_DMA_BURST_EN	BIT(2)
-#define		CNFG_BYTE_RW		BIT(6)
-#define		CNFG_HW_ECC_EN		BIT(8)
-#define		CNFG_AUTO_FMT_EN	BIT(9)
-#define		CNFG_OP_CUST		(6 << 12)
-#define NFI_PAGEFMT		(0x04)
-#define		PAGEFMT_FDM_ECC_SHIFT	(12)
-#define		PAGEFMT_FDM_SHIFT	(8)
-#define		PAGEFMT_SEC_SEL_512	BIT(2)
-#define		PAGEFMT_512_2K		(0)
-#define		PAGEFMT_2K_4K		(1)
-#define		PAGEFMT_4K_8K		(2)
-#define		PAGEFMT_8K_16K		(3)
-/* NFI control */
-#define NFI_CON			(0x08)
-#define		CON_FIFO_FLUSH		BIT(0)
-#define		CON_NFI_RST		BIT(1)
-#define		CON_BRD			BIT(8)  /* burst  read */
-#define		CON_BWR			BIT(9)	/* burst  write */
-#define		CON_SEC_SHIFT		(12)
-/* Timming control register */
-#define NFI_ACCCON		(0x0C)
-#define NFI_INTR_EN		(0x10)
-#define		INTR_AHB_DONE_EN	BIT(6)
-#define NFI_INTR_STA		(0x14)
-#define NFI_CMD			(0x20)
-#define NFI_ADDRNOB		(0x30)
-#define NFI_COLADDR		(0x34)
-#define NFI_ROWADDR		(0x38)
-#define NFI_STRDATA		(0x40)
-#define		STAR_EN			(1)
-#define		STAR_DE			(0)
-#define NFI_CNRNB		(0x44)
-#define NFI_DATAW		(0x50)
-#define NFI_DATAR		(0x54)
-#define NFI_PIO_DIRDY		(0x58)
-#define		PIO_DI_RDY		(0x01)
-#define NFI_STA			(0x60)
-#define		STA_CMD			BIT(0)
-#define		STA_ADDR		BIT(1)
-#define		STA_BUSY		BIT(8)
-#define		STA_EMP_PAGE		BIT(12)
-#define		NFI_FSM_CUSTDATA	(0xe << 16)
-#define		NFI_FSM_MASK		(0xf << 16)
-#define NFI_ADDRCNTR		(0x70)
-#define		CNTR_MASK		GENMASK(16, 12)
-#define		ADDRCNTR_SEC_SHIFT	(12)
-#define		ADDRCNTR_SEC(val) \
-		(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
-#define NFI_STRADDR		(0x80)
-#define NFI_BYTELEN		(0x84)
-#define NFI_CSEL		(0x90)
-#define NFI_FDML(x)		(0xA0 + (x) * sizeof(u32) * 2)
-#define NFI_FDMM(x)		(0xA4 + (x) * sizeof(u32) * 2)
-#define NFI_FDM_MAX_SIZE	(8)
-#define NFI_FDM_MIN_SIZE	(1)
-#define NFI_MASTER_STA		(0x224)
-#define		MASTER_STA_MASK		(0x0FFF)
-#define NFI_EMPTY_THRESH	(0x23C)
-
-#define MTK_NAME		"mtk-nand"
-#define KB(x)			((x) * 1024UL)
-#define MB(x)			(KB(x) * 1024UL)
-
-#define MTK_TIMEOUT		(500000)
-#define MTK_RESET_TIMEOUT	(1000000)
-#define MTK_NAND_MAX_NSELS	(2)
-#define MTK_NFC_MIN_SPARE	(16)
-#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
-	((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
-	(tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
-
-struct mtk_nfc_caps {
-	const u8 *spare_size;
-	u8 num_spare_size;
-	u8 pageformat_spare_shift;
-	u8 nfi_clk_div;
-	u8 max_sector;
-	u32 max_sector_size;
-};
-
-struct mtk_nfc_bad_mark_ctl {
-	void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
-	u32 sec;
-	u32 pos;
-};
-
-/*
- * FDM: region used to store free OOB data
- */
-struct mtk_nfc_fdm {
-	u32 reg_size;
-	u32 ecc_size;
-};
-
-struct mtk_nfc_nand_chip {
-	struct list_head node;
-	struct nand_chip nand;
-
-	struct mtk_nfc_bad_mark_ctl bad_mark;
-	struct mtk_nfc_fdm fdm;
-	u32 spare_per_sector;
-
-	int nsels;
-	u8 sels[0];
-	/* nothing after this field */
-};
-
-struct mtk_nfc_clk {
-	struct clk *nfi_clk;
-	struct clk *pad_clk;
-};
-
-struct mtk_nfc {
-	struct nand_hw_control controller;
-	struct mtk_ecc_config ecc_cfg;
-	struct mtk_nfc_clk clk;
-	struct mtk_ecc *ecc;
-
-	struct device *dev;
-	const struct mtk_nfc_caps *caps;
-	void __iomem *regs;
-
-	struct completion done;
-	struct list_head chips;
-
-	u8 *buffer;
-};
-
-/*
- * supported spare size of each IP.
- * order should be the same with the spare size bitfiled defination of
- * register NFI_PAGEFMT.
- */
-static const u8 spare_size_mt2701[] = {
-	16, 26, 27, 28, 32, 36, 40, 44,	48, 49, 50, 51, 52, 62, 63, 64
-};
-
-static const u8 spare_size_mt2712[] = {
-	16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
-	74
-};
-
-static const u8 spare_size_mt7622[] = {
-	16, 26, 27, 28
-};
-
-static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
-{
-	return container_of(nand, struct mtk_nfc_nand_chip, nand);
-}
-
-static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i)
-{
-	return (u8 *)p + i * chip->ecc.size;
-}
-
-static inline u8 *oob_ptr(struct nand_chip *chip, int i)
-{
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	u8 *poi;
-
-	/* map the sector's FDM data to free oob:
-	 * the beginning of the oob area stores the FDM data of bad mark sectors
-	 */
-
-	if (i < mtk_nand->bad_mark.sec)
-		poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
-	else if (i == mtk_nand->bad_mark.sec)
-		poi = chip->oob_poi;
-	else
-		poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
-
-	return poi;
-}
-
-static inline int mtk_data_len(struct nand_chip *chip)
-{
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-
-	return chip->ecc.size + mtk_nand->spare_per_sector;
-}
-
-static inline u8 *mtk_data_ptr(struct nand_chip *chip,  int i)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-
-	return nfc->buffer + i * mtk_data_len(chip);
-}
-
-static inline u8 *mtk_oob_ptr(struct nand_chip *chip, int i)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-
-	return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
-}
-
-static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
-{
-	writel(val, nfc->regs + reg);
-}
-
-static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
-{
-	writew(val, nfc->regs + reg);
-}
-
-static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
-{
-	writeb(val, nfc->regs + reg);
-}
-
-static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
-{
-	return readl_relaxed(nfc->regs + reg);
-}
-
-static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
-{
-	return readw_relaxed(nfc->regs + reg);
-}
-
-static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
-{
-	return readb_relaxed(nfc->regs + reg);
-}
-
-static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
-{
-	struct device *dev = nfc->dev;
-	u32 val;
-	int ret;
-
-	/* reset all registers and force the NFI master to terminate */
-	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
-
-	/* wait for the master to finish the last transaction */
-	ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
-				 !(val & MASTER_STA_MASK), 50,
-				 MTK_RESET_TIMEOUT);
-	if (ret)
-		dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
-			 NFI_MASTER_STA, val);
-
-	/* ensure any status register affected by the NFI master is reset */
-	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
-	nfi_writew(nfc, STAR_DE, NFI_STRDATA);
-}
-
-static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
-{
-	struct device *dev = nfc->dev;
-	u32 val;
-	int ret;
-
-	nfi_writel(nfc, command, NFI_CMD);
-
-	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
-					!(val & STA_CMD), 10,  MTK_TIMEOUT);
-	if (ret) {
-		dev_warn(dev, "nfi core timed out entering command mode\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
-{
-	struct device *dev = nfc->dev;
-	u32 val;
-	int ret;
-
-	nfi_writel(nfc, addr, NFI_COLADDR);
-	nfi_writel(nfc, 0, NFI_ROWADDR);
-	nfi_writew(nfc, 1, NFI_ADDRNOB);
-
-	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
-					!(val & STA_ADDR), 10, MTK_TIMEOUT);
-	if (ret) {
-		dev_warn(dev, "nfi core timed out entering address mode\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	u32 fmt, spare, i;
-
-	if (!mtd->writesize)
-		return 0;
-
-	spare = mtk_nand->spare_per_sector;
-
-	switch (mtd->writesize) {
-	case 512:
-		fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
-		break;
-	case KB(2):
-		if (chip->ecc.size == 512)
-			fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
-		else
-			fmt = PAGEFMT_512_2K;
-		break;
-	case KB(4):
-		if (chip->ecc.size == 512)
-			fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
-		else
-			fmt = PAGEFMT_2K_4K;
-		break;
-	case KB(8):
-		if (chip->ecc.size == 512)
-			fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
-		else
-			fmt = PAGEFMT_4K_8K;
-		break;
-	case KB(16):
-		fmt = PAGEFMT_8K_16K;
-		break;
-	default:
-		dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
-		return -EINVAL;
-	}
-
-	/*
-	 * the hardware will double the value for this eccsize, so we need to
-	 * halve it
-	 */
-	if (chip->ecc.size == 1024)
-		spare >>= 1;
-
-	for (i = 0; i < nfc->caps->num_spare_size; i++) {
-		if (nfc->caps->spare_size[i] == spare)
-			break;
-	}
-
-	if (i == nfc->caps->num_spare_size) {
-		dev_err(nfc->dev, "invalid spare size %d\n", spare);
-		return -EINVAL;
-	}
-
-	fmt |= i << nfc->caps->pageformat_spare_shift;
-
-	fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
-	fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
-	nfi_writel(nfc, fmt, NFI_PAGEFMT);
-
-	nfc->ecc_cfg.strength = chip->ecc.strength;
-	nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
-
-	return 0;
-}
-
-static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
-
-	if (chip < 0)
-		return;
-
-	mtk_nfc_hw_runtime_config(mtd);
-
-	nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
-}
-
-static int mtk_nfc_dev_ready(struct mtd_info *mtd)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
-
-	if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
-		return 0;
-
-	return 1;
-}
-
-static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
-
-	if (ctrl & NAND_ALE) {
-		mtk_nfc_send_address(nfc, dat);
-	} else if (ctrl & NAND_CLE) {
-		mtk_nfc_hw_reset(nfc);
-
-		nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
-		mtk_nfc_send_command(nfc, dat);
-	}
-}
-
-static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
-{
-	int rc;
-	u8 val;
-
-	rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
-				       val & PIO_DI_RDY, 10, MTK_TIMEOUT);
-	if (rc < 0)
-		dev_err(nfc->dev, "data not ready\n");
-}
-
-static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	u32 reg;
-
-	/* after each byte read, the NFI_STA reg is reset by the hardware */
-	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
-	if (reg != NFI_FSM_CUSTDATA) {
-		reg = nfi_readw(nfc, NFI_CNFG);
-		reg |= CNFG_BYTE_RW | CNFG_READ_EN;
-		nfi_writew(nfc, reg, NFI_CNFG);
-
-		/*
-		 * set to max sector to allow the HW to continue reading over
-		 * unaligned accesses
-		 */
-		reg = (nfc->caps->max_sector << CON_SEC_SHIFT) | CON_BRD;
-		nfi_writel(nfc, reg, NFI_CON);
-
-		/* trigger to fetch data */
-		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
-	}
-
-	mtk_nfc_wait_ioready(nfc);
-
-	return nfi_readb(nfc, NFI_DATAR);
-}
-
-static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		buf[i] = mtk_nfc_read_byte(mtd);
-}
-
-static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
-	u32 reg;
-
-	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
-
-	if (reg != NFI_FSM_CUSTDATA) {
-		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
-		nfi_writew(nfc, reg, NFI_CNFG);
-
-		reg = nfc->caps->max_sector << CON_SEC_SHIFT | CON_BWR;
-		nfi_writel(nfc, reg, NFI_CON);
-
-		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
-	}
-
-	mtk_nfc_wait_ioready(nfc);
-	nfi_writeb(nfc, byte, NFI_DATAW);
-}
-
-static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		mtk_nfc_write_byte(mtd, buf[i]);
-}
-
-static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
-					const struct nand_data_interface *conf)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
-	const struct nand_sdr_timings *timings;
-	u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
-
-	timings = nand_get_sdr_timings(conf);
-	if (IS_ERR(timings))
-		return -ENOTSUPP;
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	rate = clk_get_rate(nfc->clk.nfi_clk);
-	/* There is a frequency divider in some IPs */
-	rate /= nfc->caps->nfi_clk_div;
-
-	/* turn clock rate into KHZ */
-	rate /= 1000;
-
-	tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
-	tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
-	tpoecs &= 0xf;
-
-	tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
-	tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
-	tprecs &= 0x3f;
-
-	/* sdr interface has no tCR which means CE# low to RE# low */
-	tc2r = 0;
-
-	tw2r = timings->tWHR_min / 1000;
-	tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
-	tw2r = DIV_ROUND_UP(tw2r - 1, 2);
-	tw2r &= 0xf;
-
-	twh = max(timings->tREH_min, timings->tWH_min) / 1000;
-	twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
-	twh &= 0xf;
-
-	twst = timings->tWP_min / 1000;
-	twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
-	twst &= 0xf;
-
-	trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
-	trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
-	trlt &= 0xf;
-
-	/*
-	 * ACCON: access timing control register
-	 * -------------------------------------
-	 * 31:28: tpoecs, minimum required time for CS post pulling down after
-	 *        accessing the device
-	 * 27:22: tprecs, minimum required time for CS pre pulling down before
-	 *        accessing the device
-	 * 21:16: tc2r, minimum required time from NCEB low to NREB low
-	 * 15:12: tw2r, minimum required time from NWEB high to NREB low.
-	 * 11:08: twh, write enable hold time
-	 * 07:04: twst, write wait states
-	 * 03:00: trlt, read wait states
-	 */
-	trlt = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
-	nfi_writel(nfc, trlt, NFI_ACCCON);
-
-	return 0;
-}
-
-static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	int size = chip->ecc.size + mtk_nand->fdm.reg_size;
-
-	nfc->ecc_cfg.mode = ECC_DMA_MODE;
-	nfc->ecc_cfg.op = ECC_ENCODE;
-
-	return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size);
-}
-
-static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, u8 *b, int c)
-{
-	/* nop */
-}
-
-static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
-	u32 bad_pos = nand->bad_mark.pos;
-
-	if (raw)
-		bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
-	else
-		bad_pos += nand->bad_mark.sec * chip->ecc.size;
-
-	swap(chip->oob_poi[0], buf[bad_pos]);
-}
-
-static int mtk_nfc_format_subpage(struct mtd_info *mtd, u32 offset,
-				  u32 len, const u8 *buf)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
-	u32 start, end;
-	int i, ret;
-
-	start = offset / chip->ecc.size;
-	end = DIV_ROUND_UP(offset + len, chip->ecc.size);
-
-	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
-	for (i = 0; i < chip->ecc.steps; i++) {
-		memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
-		       chip->ecc.size);
-
-		if (start > i || i >= end)
-			continue;
-
-		if (i == mtk_nand->bad_mark.sec)
-			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
-
-		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
-
-		/* program the CRC back to the OOB */
-		ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static void mtk_nfc_format_page(struct mtd_info *mtd, const u8 *buf)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
-	u32 i;
-
-	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
-	for (i = 0; i < chip->ecc.steps; i++) {
-		if (buf)
-			memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
-			       chip->ecc.size);
-
-		if (i == mtk_nand->bad_mark.sec)
-			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
-
-		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
-	}
-}
-
-static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
-				    u32 sectors)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
-	u32 vall, valm;
-	u8 *oobptr;
-	int i, j;
-
-	for (i = 0; i < sectors; i++) {
-		oobptr = oob_ptr(chip, start + i);
-		vall = nfi_readl(nfc, NFI_FDML(i));
-		valm = nfi_readl(nfc, NFI_FDMM(i));
-
-		for (j = 0; j < fdm->reg_size; j++)
-			oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
-	}
-}
-
-static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
-	u32 vall, valm;
-	u8 *oobptr;
-	int i, j;
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		oobptr = oob_ptr(chip, i);
-		vall = 0;
-		valm = 0;
-		for (j = 0; j < 8; j++) {
-			if (j < 4)
-				vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
-						<< (j * 8);
-			else
-				valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
-						<< ((j - 4) * 8);
-		}
-		nfi_writel(nfc, vall, NFI_FDML(i));
-		nfi_writel(nfc, valm, NFI_FDMM(i));
-	}
-}
-
-static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-				 const u8 *buf, int page, int len)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct device *dev = nfc->dev;
-	dma_addr_t addr;
-	u32 reg;
-	int ret;
-
-	addr = dma_map_single(dev, (void *)buf, len, DMA_TO_DEVICE);
-	ret = dma_mapping_error(nfc->dev, addr);
-	if (ret) {
-		dev_err(nfc->dev, "dma mapping error\n");
-		return -EINVAL;
-	}
-
-	reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
-	nfi_writew(nfc, reg, NFI_CNFG);
-
-	nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
-	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
-	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
-
-	init_completion(&nfc->done);
-
-	reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
-	nfi_writel(nfc, reg, NFI_CON);
-	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
-
-	ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
-	if (!ret) {
-		dev_err(dev, "program ahb done timeout\n");
-		nfi_writew(nfc, 0, NFI_INTR_EN);
-		ret = -ETIMEDOUT;
-		goto timeout;
-	}
-
-	ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
-					ADDRCNTR_SEC(reg) >= chip->ecc.steps,
-					10, MTK_TIMEOUT);
-	if (ret)
-		dev_err(dev, "hwecc write timeout\n");
-
-timeout:
-
-	dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
-	nfi_writel(nfc, 0, NFI_CON);
-
-	return ret;
-}
-
-static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-			      const u8 *buf, int page, int raw)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	size_t len;
-	const u8 *bufpoi;
-	u32 reg;
-	int ret;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	if (!raw) {
-		/* OOB => FDM: from register,  ECC: from HW */
-		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
-		nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
-
-		nfc->ecc_cfg.op = ECC_ENCODE;
-		nfc->ecc_cfg.mode = ECC_NFI_MODE;
-		ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
-		if (ret) {
-			/* clear NFI config */
-			reg = nfi_readw(nfc, NFI_CNFG);
-			reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
-			nfi_writew(nfc, reg, NFI_CNFG);
-
-			return ret;
-		}
-
-		memcpy(nfc->buffer, buf, mtd->writesize);
-		mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
-		bufpoi = nfc->buffer;
-
-		/* write OOB into the FDM registers (OOB area in MTK NAND) */
-		mtk_nfc_write_fdm(chip);
-	} else {
-		bufpoi = buf;
-	}
-
-	len = mtd->writesize + (raw ? mtd->oobsize : 0);
-	ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
-
-	if (!raw)
-		mtk_ecc_disable(nfc->ecc);
-
-	if (ret)
-		return ret;
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
-				    struct nand_chip *chip, const u8 *buf,
-				    int oob_on, int page)
-{
-	return mtk_nfc_write_page(mtd, chip, buf, page, 0);
-}
-
-static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				  const u8 *buf, int oob_on, int pg)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-
-	mtk_nfc_format_page(mtd, buf);
-	return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
-}
-
-static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
-				       struct nand_chip *chip, u32 offset,
-				       u32 data_len, const u8 *buf,
-				       int oob_on, int page)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	int ret;
-
-	ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
-	if (ret < 0)
-		return ret;
-
-	/* use the data in the private buffer (now with FDM and CRC) */
-	return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
-}
-
-static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-				 int page)
-{
-	return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
-}
-
-static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_ecc_stats stats;
-	int rc, i;
-
-	rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
-	if (rc) {
-		memset(buf, 0xff, sectors * chip->ecc.size);
-		for (i = 0; i < sectors; i++)
-			memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
-		return 0;
-	}
-
-	mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
-	mtd->ecc_stats.corrected += stats.corrected;
-	mtd->ecc_stats.failed += stats.failed;
-
-	return stats.bitflips;
-}
-
-static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-				u32 data_offs, u32 readlen,
-				u8 *bufpoi, int page, int raw)
-{
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	u32 spare = mtk_nand->spare_per_sector;
-	u32 column, sectors, start, end, reg;
-	dma_addr_t addr;
-	int bitflips;
-	size_t len;
-	u8 *buf;
-	int rc;
-
-	start = data_offs / chip->ecc.size;
-	end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
-
-	sectors = end - start;
-	column = start * (chip->ecc.size + spare);
-
-	len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
-	buf = bufpoi + start * chip->ecc.size;
-
-	nand_read_page_op(chip, page, column, NULL, 0);
-
-	addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
-	rc = dma_mapping_error(nfc->dev, addr);
-	if (rc) {
-		dev_err(nfc->dev, "dma mapping error\n");
-
-		return -EINVAL;
-	}
-
-	reg = nfi_readw(nfc, NFI_CNFG);
-	reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
-	if (!raw) {
-		reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
-		nfi_writew(nfc, reg, NFI_CNFG);
-
-		nfc->ecc_cfg.mode = ECC_NFI_MODE;
-		nfc->ecc_cfg.sectors = sectors;
-		nfc->ecc_cfg.op = ECC_DECODE;
-		rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
-		if (rc) {
-			dev_err(nfc->dev, "ecc enable\n");
-			/* clear NFI_CNFG */
-			reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
-				CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
-			nfi_writew(nfc, reg, NFI_CNFG);
-			dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
-
-			return rc;
-		}
-	} else {
-		nfi_writew(nfc, reg, NFI_CNFG);
-	}
-
-	nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
-	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
-	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
-
-	init_completion(&nfc->done);
-	reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
-	nfi_writel(nfc, reg, NFI_CON);
-	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
-
-	rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
-	if (!rc)
-		dev_warn(nfc->dev, "read ahb/dma done timeout\n");
-
-	rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
-				       ADDRCNTR_SEC(reg) >= sectors, 10,
-				       MTK_TIMEOUT);
-	if (rc < 0) {
-		dev_err(nfc->dev, "subpage done timeout\n");
-		bitflips = -EIO;
-	} else {
-		bitflips = 0;
-		if (!raw) {
-			rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
-			bitflips = rc < 0 ? -ETIMEDOUT :
-				mtk_nfc_update_ecc_stats(mtd, buf, sectors);
-			mtk_nfc_read_fdm(chip, start, sectors);
-		}
-	}
-
-	dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
-
-	if (raw)
-		goto done;
-
-	mtk_ecc_disable(nfc->ecc);
-
-	if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
-		mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
-done:
-	nfi_writel(nfc, 0, NFI_CON);
-
-	return bitflips;
-}
-
-static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
-				      struct nand_chip *chip, u32 off,
-				      u32 len, u8 *p, int pg)
-{
-	return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
-}
-
-static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
-				   struct nand_chip *chip, u8 *p,
-				   int oob_on, int pg)
-{
-	return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
-}
-
-static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				 u8 *buf, int oob_on, int page)
-{
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc *nfc = nand_get_controller_data(chip);
-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
-	int i, ret;
-
-	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
-	ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
-				   page, 1);
-	if (ret < 0)
-		return ret;
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
-
-		if (i == mtk_nand->bad_mark.sec)
-			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
-
-		if (buf)
-			memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
-			       chip->ecc.size);
-	}
-
-	return ret;
-}
-
-static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-				int page)
-{
-	return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
-}
-
-static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
-{
-	/*
-	 * CNRNB: nand ready/busy register
-	 * -------------------------------
-	 * 7:4: timeout register for polling the NAND busy/ready signal
-	 * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
-	 */
-	nfi_writew(nfc, 0xf1, NFI_CNRNB);
-	nfi_writel(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
-
-	mtk_nfc_hw_reset(nfc);
-
-	nfi_readl(nfc, NFI_INTR_STA);
-	nfi_writel(nfc, 0, NFI_INTR_EN);
-}
-
-static irqreturn_t mtk_nfc_irq(int irq, void *id)
-{
-	struct mtk_nfc *nfc = id;
-	u16 sta, ien;
-
-	sta = nfi_readw(nfc, NFI_INTR_STA);
-	ien = nfi_readw(nfc, NFI_INTR_EN);
-
-	if (!(sta & ien))
-		return IRQ_NONE;
-
-	nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
-	complete(&nfc->done);
-
-	return IRQ_HANDLED;
-}
-
-static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
-{
-	int ret;
-
-	ret = clk_prepare_enable(clk->nfi_clk);
-	if (ret) {
-		dev_err(dev, "failed to enable nfi clk\n");
-		return ret;
-	}
-
-	ret = clk_prepare_enable(clk->pad_clk);
-	if (ret) {
-		dev_err(dev, "failed to enable pad clk\n");
-		clk_disable_unprepare(clk->nfi_clk);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
-{
-	clk_disable_unprepare(clk->nfi_clk);
-	clk_disable_unprepare(clk->pad_clk);
-}
-
-static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oob_region)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
-	u32 eccsteps;
-
-	eccsteps = mtd->writesize / chip->ecc.size;
-
-	if (section >= eccsteps)
-		return -ERANGE;
-
-	oob_region->length = fdm->reg_size - fdm->ecc_size;
-	oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
-
-	return 0;
-}
-
-static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oob_region)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
-	u32 eccsteps;
-
-	if (section)
-		return -ERANGE;
-
-	eccsteps = mtd->writesize / chip->ecc.size;
-	oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
-	oob_region->length = mtd->oobsize - oob_region->offset;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
-	.free = mtk_nfc_ooblayout_free,
-	.ecc = mtk_nfc_ooblayout_ecc,
-};
-
-static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
-	u32 ecc_bytes;
-
-	ecc_bytes = DIV_ROUND_UP(nand->ecc.strength *
-				 mtk_ecc_get_parity_bits(nfc->ecc), 8);
-
-	fdm->reg_size = chip->spare_per_sector - ecc_bytes;
-	if (fdm->reg_size > NFI_FDM_MAX_SIZE)
-		fdm->reg_size = NFI_FDM_MAX_SIZE;
-
-	/* bad block mark storage */
-	fdm->ecc_size = 1;
-}
-
-static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
-				     struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-
-	if (mtd->writesize == 512) {
-		bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
-	} else {
-		bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
-		bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
-		bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
-	}
-}
-
-static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
-	const u8 *spare = nfc->caps->spare_size;
-	u32 eccsteps, i, closest_spare = 0;
-
-	eccsteps = mtd->writesize / nand->ecc.size;
-	*sps = mtd->oobsize / eccsteps;
-
-	if (nand->ecc.size == 1024)
-		*sps >>= 1;
-
-	if (*sps < MTK_NFC_MIN_SPARE)
-		return -EINVAL;
-
-	for (i = 0; i < nfc->caps->num_spare_size; i++) {
-		if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
-			closest_spare = i;
-			if (*sps == spare[i])
-				break;
-		}
-	}
-
-	*sps = spare[closest_spare];
-
-	if (nand->ecc.size == 1024)
-		*sps <<= 1;
-
-	return 0;
-}
-
-static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct mtk_nfc *nfc = nand_get_controller_data(nand);
-	u32 spare;
-	int free, ret;
-
-	/* support only ecc hw mode */
-	if (nand->ecc.mode != NAND_ECC_HW) {
-		dev_err(dev, "ecc.mode not supported\n");
-		return -EINVAL;
-	}
-
-	/* if optional dt settings not present */
-	if (!nand->ecc.size || !nand->ecc.strength) {
-		/* use datasheet requirements */
-		nand->ecc.strength = nand->ecc_strength_ds;
-		nand->ecc.size = nand->ecc_step_ds;
-
-		/*
-		 * align eccstrength and eccsize
-		 * this controller only supports 512 and 1024 sizes
-		 */
-		if (nand->ecc.size < 1024) {
-			if (mtd->writesize > 512 &&
-			    nfc->caps->max_sector_size > 512) {
-				nand->ecc.size = 1024;
-				nand->ecc.strength <<= 1;
-			} else {
-				nand->ecc.size = 512;
-			}
-		} else {
-			nand->ecc.size = 1024;
-		}
-
-		ret = mtk_nfc_set_spare_per_sector(&spare, mtd);
-		if (ret)
-			return ret;
-
-		/* calculate oob bytes except ecc parity data */
-		free = (nand->ecc.strength * mtk_ecc_get_parity_bits(nfc->ecc)
-			+ 7) >> 3;
-		free = spare - free;
-
-		/*
-		 * enhance ecc strength if oob left is bigger than max FDM size
-		 * or reduce ecc strength if oob size is not enough for ecc
-		 * parity data.
-		 */
-		if (free > NFI_FDM_MAX_SIZE) {
-			spare -= NFI_FDM_MAX_SIZE;
-			nand->ecc.strength = (spare << 3) /
-					     mtk_ecc_get_parity_bits(nfc->ecc);
-		} else if (free < 0) {
-			spare -= NFI_FDM_MIN_SIZE;
-			nand->ecc.strength = (spare << 3) /
-					     mtk_ecc_get_parity_bits(nfc->ecc);
-		}
-	}
-
-	mtk_ecc_adjust_strength(nfc->ecc, &nand->ecc.strength);
-
-	dev_info(dev, "eccsize %d eccstrength %d\n",
-		 nand->ecc.size, nand->ecc.strength);
-
-	return 0;
-}
-
-static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
-				  struct device_node *np)
-{
-	struct mtk_nfc_nand_chip *chip;
-	struct nand_chip *nand;
-	struct mtd_info *mtd;
-	int nsels, len;
-	u32 tmp;
-	int ret;
-	int i;
-
-	if (!of_get_property(np, "reg", &nsels))
-		return -ENODEV;
-
-	nsels /= sizeof(u32);
-	if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
-		dev_err(dev, "invalid reg property size %d\n", nsels);
-		return -EINVAL;
-	}
-
-	chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
-			    GFP_KERNEL);
-	if (!chip)
-		return -ENOMEM;
-
-	chip->nsels = nsels;
-	for (i = 0; i < nsels; i++) {
-		ret = of_property_read_u32_index(np, "reg", i, &tmp);
-		if (ret) {
-			dev_err(dev, "reg property failure : %d\n", ret);
-			return ret;
-		}
-		chip->sels[i] = tmp;
-	}
-
-	nand = &chip->nand;
-	nand->controller = &nfc->controller;
-
-	nand_set_flash_node(nand, np);
-	nand_set_controller_data(nand, nfc);
-
-	nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
-	nand->dev_ready = mtk_nfc_dev_ready;
-	nand->select_chip = mtk_nfc_select_chip;
-	nand->write_byte = mtk_nfc_write_byte;
-	nand->write_buf = mtk_nfc_write_buf;
-	nand->read_byte = mtk_nfc_read_byte;
-	nand->read_buf = mtk_nfc_read_buf;
-	nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
-	nand->setup_data_interface = mtk_nfc_setup_data_interface;
-
-	/* set default mode in case dt entry is missing */
-	nand->ecc.mode = NAND_ECC_HW;
-
-	nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
-	nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
-	nand->ecc.write_page = mtk_nfc_write_page_hwecc;
-	nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
-	nand->ecc.write_oob = mtk_nfc_write_oob_std;
-
-	nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
-	nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
-	nand->ecc.read_page = mtk_nfc_read_page_hwecc;
-	nand->ecc.read_oob_raw = mtk_nfc_read_oob_std;
-	nand->ecc.read_oob = mtk_nfc_read_oob_std;
-
-	mtd = nand_to_mtd(nand);
-	mtd->owner = THIS_MODULE;
-	mtd->dev.parent = dev;
-	mtd->name = MTK_NAME;
-	mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
-
-	mtk_nfc_hw_init(nfc);
-
-	ret = nand_scan_ident(mtd, nsels, NULL);
-	if (ret)
-		return ret;
-
-	/* store bbt magic in page, cause OOB is not protected */
-	if (nand->bbt_options & NAND_BBT_USE_FLASH)
-		nand->bbt_options |= NAND_BBT_NO_OOB;
-
-	ret = mtk_nfc_ecc_init(dev, mtd);
-	if (ret)
-		return -EINVAL;
-
-	if (nand->options & NAND_BUSWIDTH_16) {
-		dev_err(dev, "16bits buswidth not supported");
-		return -EINVAL;
-	}
-
-	ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
-	if (ret)
-		return ret;
-
-	mtk_nfc_set_fdm(&chip->fdm, mtd);
-	mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
-
-	len = mtd->writesize + mtd->oobsize;
-	nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
-	if (!nfc->buffer)
-		return  -ENOMEM;
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		return ret;
-
-	ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
-	if (ret) {
-		dev_err(dev, "mtd parse partition error\n");
-		nand_release(mtd);
-		return ret;
-	}
-
-	list_add_tail(&chip->node, &nfc->chips);
-
-	return 0;
-}
-
-static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
-{
-	struct device_node *np = dev->of_node;
-	struct device_node *nand_np;
-	int ret;
-
-	for_each_child_of_node(np, nand_np) {
-		ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
-		if (ret) {
-			of_node_put(nand_np);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
-	.spare_size = spare_size_mt2701,
-	.num_spare_size = 16,
-	.pageformat_spare_shift = 4,
-	.nfi_clk_div = 1,
-	.max_sector = 16,
-	.max_sector_size = 1024,
-};
-
-static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
-	.spare_size = spare_size_mt2712,
-	.num_spare_size = 19,
-	.pageformat_spare_shift = 16,
-	.nfi_clk_div = 2,
-	.max_sector = 16,
-	.max_sector_size = 1024,
-};
-
-static const struct mtk_nfc_caps mtk_nfc_caps_mt7622 = {
-	.spare_size = spare_size_mt7622,
-	.num_spare_size = 4,
-	.pageformat_spare_shift = 4,
-	.nfi_clk_div = 1,
-	.max_sector = 8,
-	.max_sector_size = 512,
-};
-
-static const struct of_device_id mtk_nfc_id_table[] = {
-	{
-		.compatible = "mediatek,mt2701-nfc",
-		.data = &mtk_nfc_caps_mt2701,
-	}, {
-		.compatible = "mediatek,mt2712-nfc",
-		.data = &mtk_nfc_caps_mt2712,
-	}, {
-		.compatible = "mediatek,mt7622-nfc",
-		.data = &mtk_nfc_caps_mt7622,
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
-
-static int mtk_nfc_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	struct mtk_nfc *nfc;
-	struct resource *res;
-	const struct of_device_id *of_nfc_id = NULL;
-	int ret, irq;
-
-	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
-	if (!nfc)
-		return -ENOMEM;
-
-	spin_lock_init(&nfc->controller.lock);
-	init_waitqueue_head(&nfc->controller.wq);
-	INIT_LIST_HEAD(&nfc->chips);
-
-	/* probe defer if not ready */
-	nfc->ecc = of_mtk_ecc_get(np);
-	if (IS_ERR(nfc->ecc))
-		return PTR_ERR(nfc->ecc);
-	else if (!nfc->ecc)
-		return -ENODEV;
-
-	nfc->dev = dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nfc->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(nfc->regs)) {
-		ret = PTR_ERR(nfc->regs);
-		goto release_ecc;
-	}
-
-	nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
-	if (IS_ERR(nfc->clk.nfi_clk)) {
-		dev_err(dev, "no clk\n");
-		ret = PTR_ERR(nfc->clk.nfi_clk);
-		goto release_ecc;
-	}
-
-	nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
-	if (IS_ERR(nfc->clk.pad_clk)) {
-		dev_err(dev, "no pad clk\n");
-		ret = PTR_ERR(nfc->clk.pad_clk);
-		goto release_ecc;
-	}
-
-	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
-	if (ret)
-		goto release_ecc;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "no nfi irq resource\n");
-		ret = -EINVAL;
-		goto clk_disable;
-	}
-
-	ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
-	if (ret) {
-		dev_err(dev, "failed to request nfi irq\n");
-		goto clk_disable;
-	}
-
-	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
-	if (ret) {
-		dev_err(dev, "failed to set dma mask\n");
-		goto clk_disable;
-	}
-
-	of_nfc_id = of_match_device(mtk_nfc_id_table, &pdev->dev);
-	if (!of_nfc_id) {
-		ret = -ENODEV;
-		goto clk_disable;
-	}
-
-	nfc->caps = of_nfc_id->data;
-
-	platform_set_drvdata(pdev, nfc);
-
-	ret = mtk_nfc_nand_chips_init(dev, nfc);
-	if (ret) {
-		dev_err(dev, "failed to init nand chips\n");
-		goto clk_disable;
-	}
-
-	return 0;
-
-clk_disable:
-	mtk_nfc_disable_clk(&nfc->clk);
-
-release_ecc:
-	mtk_ecc_release(nfc->ecc);
-
-	return ret;
-}
-
-static int mtk_nfc_remove(struct platform_device *pdev)
-{
-	struct mtk_nfc *nfc = platform_get_drvdata(pdev);
-	struct mtk_nfc_nand_chip *chip;
-
-	while (!list_empty(&nfc->chips)) {
-		chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
-					node);
-		nand_release(nand_to_mtd(&chip->nand));
-		list_del(&chip->node);
-	}
-
-	mtk_ecc_release(nfc->ecc);
-	mtk_nfc_disable_clk(&nfc->clk);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int mtk_nfc_suspend(struct device *dev)
-{
-	struct mtk_nfc *nfc = dev_get_drvdata(dev);
-
-	mtk_nfc_disable_clk(&nfc->clk);
-
-	return 0;
-}
-
-static int mtk_nfc_resume(struct device *dev)
-{
-	struct mtk_nfc *nfc = dev_get_drvdata(dev);
-	struct mtk_nfc_nand_chip *chip;
-	struct nand_chip *nand;
-	int ret;
-	u32 i;
-
-	udelay(200);
-
-	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
-	if (ret)
-		return ret;
-
-	/* reset NAND chip if VCC was powered off */
-	list_for_each_entry(chip, &nfc->chips, node) {
-		nand = &chip->nand;
-		for (i = 0; i < chip->nsels; i++)
-			nand_reset(nand, i);
-	}
-
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
-#endif
-
-static struct platform_driver mtk_nfc_driver = {
-	.probe  = mtk_nfc_probe,
-	.remove = mtk_nfc_remove,
-	.driver = {
-		.name  = MTK_NAME,
-		.of_match_table = mtk_nfc_id_table,
-#ifdef CONFIG_PM_SLEEP
-		.pm = &mtk_nfc_pm_ops,
-#endif
-	},
-};
-
-module_platform_driver(mtk_nfc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
-MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
deleted file mode 100644
index f3be0b2a8869..000000000000
--- a/drivers/mtd/nand/mxc_nand.c
+++ /dev/null
@@ -1,1853 +0,0 @@
-/*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/completion.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include <asm/mach/flash.h>
-#include <linux/platform_data/mtd-mxc_nand.h>
-
-#define DRIVER_NAME "mxc_nand"
-
-/* Addresses for NFC registers */
-#define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
-#define NFC_V1_V2_BUF_ADDR		(host->regs + 0x04)
-#define NFC_V1_V2_FLASH_ADDR		(host->regs + 0x06)
-#define NFC_V1_V2_FLASH_CMD		(host->regs + 0x08)
-#define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
-#define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
-#define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
-#define NFC_V1_V2_RSLTSPARE_AREA	(host->regs + 0x10)
-#define NFC_V1_V2_WRPROT		(host->regs + 0x12)
-#define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
-#define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
-#define NFC_V21_UNLOCKSTART_BLKADDR0	(host->regs + 0x20)
-#define NFC_V21_UNLOCKSTART_BLKADDR1	(host->regs + 0x24)
-#define NFC_V21_UNLOCKSTART_BLKADDR2	(host->regs + 0x28)
-#define NFC_V21_UNLOCKSTART_BLKADDR3	(host->regs + 0x2c)
-#define NFC_V21_UNLOCKEND_BLKADDR0	(host->regs + 0x22)
-#define NFC_V21_UNLOCKEND_BLKADDR1	(host->regs + 0x26)
-#define NFC_V21_UNLOCKEND_BLKADDR2	(host->regs + 0x2a)
-#define NFC_V21_UNLOCKEND_BLKADDR3	(host->regs + 0x2e)
-#define NFC_V1_V2_NF_WRPRST		(host->regs + 0x18)
-#define NFC_V1_V2_CONFIG1		(host->regs + 0x1a)
-#define NFC_V1_V2_CONFIG2		(host->regs + 0x1c)
-
-#define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
-#define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
-#define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
-#define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
-#define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
-#define NFC_V1_V2_CONFIG1_RST		(1 << 6)
-#define NFC_V1_V2_CONFIG1_CE		(1 << 7)
-#define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
-#define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
-#define NFC_V2_CONFIG1_FP_INT		(1 << 11)
-
-#define NFC_V1_V2_CONFIG2_INT		(1 << 15)
-
-/*
- * Operation modes for the NFC. Valid for v1, v2 and v3
- * type controllers.
- */
-#define NFC_CMD				(1 << 0)
-#define NFC_ADDR			(1 << 1)
-#define NFC_INPUT			(1 << 2)
-#define NFC_OUTPUT			(1 << 3)
-#define NFC_ID				(1 << 4)
-#define NFC_STATUS			(1 << 5)
-
-#define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
-#define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
-
-#define NFC_V3_CONFIG1			(host->regs_axi + 0x34)
-#define NFC_V3_CONFIG1_SP_EN		(1 << 0)
-#define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7 ) << 4)
-
-#define NFC_V3_ECC_STATUS_RESULT	(host->regs_axi + 0x38)
-
-#define NFC_V3_LAUNCH			(host->regs_axi + 0x40)
-
-#define NFC_V3_WRPROT			(host->regs_ip + 0x0)
-#define NFC_V3_WRPROT_LOCK_TIGHT	(1 << 0)
-#define NFC_V3_WRPROT_LOCK		(1 << 1)
-#define NFC_V3_WRPROT_UNLOCK		(1 << 2)
-#define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
-
-#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0   (host->regs_ip + 0x04)
-
-#define NFC_V3_CONFIG2			(host->regs_ip + 0x24)
-#define NFC_V3_CONFIG2_PS_512			(0 << 0)
-#define NFC_V3_CONFIG2_PS_2048			(1 << 0)
-#define NFC_V3_CONFIG2_PS_4096			(2 << 0)
-#define NFC_V3_CONFIG2_ONE_CYCLE		(1 << 2)
-#define NFC_V3_CONFIG2_ECC_EN			(1 << 3)
-#define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
-#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
-#define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
-#define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
-#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
-#define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
-#define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
-#define NFC_V3_CONFIG2_SPAS(x)			(((x) & 0xff) << 16)
-
-#define NFC_V3_CONFIG3				(host->regs_ip + 0x28)
-#define NFC_V3_CONFIG3_ADD_OP(x)		(((x) & 0x3) << 0)
-#define NFC_V3_CONFIG3_FW8			(1 << 3)
-#define NFC_V3_CONFIG3_SBB(x)			(((x) & 0x7) << 8)
-#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x)	(((x) & 0x7) << 12)
-#define NFC_V3_CONFIG3_RBB_MODE			(1 << 15)
-#define NFC_V3_CONFIG3_NO_SDMA			(1 << 20)
-
-#define NFC_V3_IPC			(host->regs_ip + 0x2C)
-#define NFC_V3_IPC_CREQ			(1 << 0)
-#define NFC_V3_IPC_INT			(1 << 31)
-
-#define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
-
-struct mxc_nand_host;
-
-struct mxc_nand_devtype_data {
-	void (*preset)(struct mtd_info *);
-	void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
-	void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
-	void (*send_page)(struct mtd_info *, unsigned int);
-	void (*send_read_id)(struct mxc_nand_host *);
-	uint16_t (*get_dev_status)(struct mxc_nand_host *);
-	int (*check_int)(struct mxc_nand_host *);
-	void (*irq_control)(struct mxc_nand_host *, int);
-	u32 (*get_ecc_status)(struct mxc_nand_host *);
-	const struct mtd_ooblayout_ops *ooblayout;
-	void (*select_chip)(struct mtd_info *mtd, int chip);
-	int (*correct_data)(struct mtd_info *mtd, u_char *dat,
-			u_char *read_ecc, u_char *calc_ecc);
-	int (*setup_data_interface)(struct mtd_info *mtd, int csline,
-				    const struct nand_data_interface *conf);
-
-	/*
-	 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
-	 * (CONFIG1:INT_MSK is set). To handle this the driver uses
-	 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
-	 */
-	int irqpending_quirk;
-	int needs_ip;
-
-	size_t regs_offset;
-	size_t spare0_offset;
-	size_t axi_offset;
-
-	int spare_len;
-	int eccbytes;
-	int eccsize;
-	int ppb_shift;
-};
-
-struct mxc_nand_host {
-	struct nand_chip	nand;
-	struct device		*dev;
-
-	void __iomem		*spare0;
-	void __iomem		*main_area0;
-
-	void __iomem		*base;
-	void __iomem		*regs;
-	void __iomem		*regs_axi;
-	void __iomem		*regs_ip;
-	int			status_request;
-	struct clk		*clk;
-	int			clk_act;
-	int			irq;
-	int			eccsize;
-	int			used_oobsize;
-	int			active_cs;
-
-	struct completion	op_completion;
-
-	uint8_t			*data_buf;
-	unsigned int		buf_start;
-
-	const struct mxc_nand_devtype_data *devtype_data;
-	struct mxc_nand_platform_data pdata;
-};
-
-static const char * const part_probes[] = {
-	"cmdlinepart", "RedBoot", "ofpart", NULL };
-
-static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
-{
-	int i;
-	u32 *t = trg;
-	const __iomem u32 *s = src;
-
-	for (i = 0; i < (size >> 2); i++)
-		*t++ = __raw_readl(s++);
-}
-
-static void memcpy16_fromio(void *trg, const void __iomem  *src, size_t size)
-{
-	int i;
-	u16 *t = trg;
-	const __iomem u16 *s = src;
-
-	/* We assume that src (IO) is always 32bit aligned */
-	if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
-		memcpy32_fromio(trg, src, size);
-		return;
-	}
-
-	for (i = 0; i < (size >> 1); i++)
-		*t++ = __raw_readw(s++);
-}
-
-static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
-{
-	/* __iowrite32_copy use 32bit size values so divide by 4 */
-	__iowrite32_copy(trg, src, size / 4);
-}
-
-static void memcpy16_toio(void __iomem *trg, const void *src, int size)
-{
-	int i;
-	__iomem u16 *t = trg;
-	const u16 *s = src;
-
-	/* We assume that trg (IO) is always 32bit aligned */
-	if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
-		memcpy32_toio(trg, src, size);
-		return;
-	}
-
-	for (i = 0; i < (size >> 1); i++)
-		__raw_writew(*s++, t++);
-}
-
-static int check_int_v3(struct mxc_nand_host *host)
-{
-	uint32_t tmp;
-
-	tmp = readl(NFC_V3_IPC);
-	if (!(tmp & NFC_V3_IPC_INT))
-		return 0;
-
-	tmp &= ~NFC_V3_IPC_INT;
-	writel(tmp, NFC_V3_IPC);
-
-	return 1;
-}
-
-static int check_int_v1_v2(struct mxc_nand_host *host)
-{
-	uint32_t tmp;
-
-	tmp = readw(NFC_V1_V2_CONFIG2);
-	if (!(tmp & NFC_V1_V2_CONFIG2_INT))
-		return 0;
-
-	if (!host->devtype_data->irqpending_quirk)
-		writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
-
-	return 1;
-}
-
-static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
-{
-	uint16_t tmp;
-
-	tmp = readw(NFC_V1_V2_CONFIG1);
-
-	if (activate)
-		tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
-	else
-		tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
-
-	writew(tmp, NFC_V1_V2_CONFIG1);
-}
-
-static void irq_control_v3(struct mxc_nand_host *host, int activate)
-{
-	uint32_t tmp;
-
-	tmp = readl(NFC_V3_CONFIG2);
-
-	if (activate)
-		tmp &= ~NFC_V3_CONFIG2_INT_MSK;
-	else
-		tmp |= NFC_V3_CONFIG2_INT_MSK;
-
-	writel(tmp, NFC_V3_CONFIG2);
-}
-
-static void irq_control(struct mxc_nand_host *host, int activate)
-{
-	if (host->devtype_data->irqpending_quirk) {
-		if (activate)
-			enable_irq(host->irq);
-		else
-			disable_irq_nosync(host->irq);
-	} else {
-		host->devtype_data->irq_control(host, activate);
-	}
-}
-
-static u32 get_ecc_status_v1(struct mxc_nand_host *host)
-{
-	return readw(NFC_V1_V2_ECC_STATUS_RESULT);
-}
-
-static u32 get_ecc_status_v2(struct mxc_nand_host *host)
-{
-	return readl(NFC_V1_V2_ECC_STATUS_RESULT);
-}
-
-static u32 get_ecc_status_v3(struct mxc_nand_host *host)
-{
-	return readl(NFC_V3_ECC_STATUS_RESULT);
-}
-
-static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
-{
-	struct mxc_nand_host *host = dev_id;
-
-	if (!host->devtype_data->check_int(host))
-		return IRQ_NONE;
-
-	irq_control(host, 0);
-
-	complete(&host->op_completion);
-
-	return IRQ_HANDLED;
-}
-
-/* This function polls the NANDFC to wait for the basic operation to
- * complete by checking the INT bit of config2 register.
- */
-static int wait_op_done(struct mxc_nand_host *host, int useirq)
-{
-	int ret = 0;
-
-	/*
-	 * If operation is already complete, don't bother to setup an irq or a
-	 * loop.
-	 */
-	if (host->devtype_data->check_int(host))
-		return 0;
-
-	if (useirq) {
-		unsigned long timeout;
-
-		reinit_completion(&host->op_completion);
-
-		irq_control(host, 1);
-
-		timeout = wait_for_completion_timeout(&host->op_completion, HZ);
-		if (!timeout && !host->devtype_data->check_int(host)) {
-			dev_dbg(host->dev, "timeout waiting for irq\n");
-			ret = -ETIMEDOUT;
-		}
-	} else {
-		int max_retries = 8000;
-		int done;
-
-		do {
-			udelay(1);
-
-			done = host->devtype_data->check_int(host);
-			if (done)
-				break;
-
-		} while (--max_retries);
-
-		if (!done) {
-			dev_dbg(host->dev, "timeout polling for completion\n");
-			ret = -ETIMEDOUT;
-		}
-	}
-
-	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
-
-	return ret;
-}
-
-static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
-{
-	/* fill command */
-	writel(cmd, NFC_V3_FLASH_CMD);
-
-	/* send out command */
-	writel(NFC_CMD, NFC_V3_LAUNCH);
-
-	/* Wait for operation to complete */
-	wait_op_done(host, useirq);
-}
-
-/* This function issues the specified command to the NAND device and
- * waits for completion. */
-static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
-{
-	dev_dbg(host->dev, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
-
-	writew(cmd, NFC_V1_V2_FLASH_CMD);
-	writew(NFC_CMD, NFC_V1_V2_CONFIG2);
-
-	if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
-		int max_retries = 100;
-		/* Reset completion is indicated by NFC_CONFIG2 */
-		/* being set to 0 */
-		while (max_retries-- > 0) {
-			if (readw(NFC_V1_V2_CONFIG2) == 0) {
-				break;
-			}
-			udelay(1);
-		}
-		if (max_retries < 0)
-			dev_dbg(host->dev, "%s: RESET failed\n", __func__);
-	} else {
-		/* Wait for operation to complete */
-		wait_op_done(host, useirq);
-	}
-}
-
-static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
-{
-	/* fill address */
-	writel(addr, NFC_V3_FLASH_ADDR0);
-
-	/* send out address */
-	writel(NFC_ADDR, NFC_V3_LAUNCH);
-
-	wait_op_done(host, 0);
-}
-
-/* This function sends an address (or partial address) to the
- * NAND device. The address is used to select the source/destination for
- * a NAND command. */
-static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
-{
-	dev_dbg(host->dev, "send_addr(host, 0x%x %d)\n", addr, islast);
-
-	writew(addr, NFC_V1_V2_FLASH_ADDR);
-	writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
-
-	/* Wait for operation to complete */
-	wait_op_done(host, islast);
-}
-
-static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	uint32_t tmp;
-
-	tmp = readl(NFC_V3_CONFIG1);
-	tmp &= ~(7 << 4);
-	writel(tmp, NFC_V3_CONFIG1);
-
-	/* transfer data from NFC ram to nand */
-	writel(ops, NFC_V3_LAUNCH);
-
-	wait_op_done(host, false);
-}
-
-static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-
-	/* NANDFC buffer 0 is used for page read/write */
-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
-
-	writew(ops, NFC_V1_V2_CONFIG2);
-
-	/* Wait for operation to complete */
-	wait_op_done(host, true);
-}
-
-static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	int bufs, i;
-
-	if (mtd->writesize > 512)
-		bufs = 4;
-	else
-		bufs = 1;
-
-	for (i = 0; i < bufs; i++) {
-
-		/* NANDFC buffer 0 is used for page read/write */
-		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
-
-		writew(ops, NFC_V1_V2_CONFIG2);
-
-		/* Wait for operation to complete */
-		wait_op_done(host, true);
-	}
-}
-
-static void send_read_id_v3(struct mxc_nand_host *host)
-{
-	/* Read ID into main buffer */
-	writel(NFC_ID, NFC_V3_LAUNCH);
-
-	wait_op_done(host, true);
-
-	memcpy32_fromio(host->data_buf, host->main_area0, 16);
-}
-
-/* Request the NANDFC to perform a read of the NAND device ID. */
-static void send_read_id_v1_v2(struct mxc_nand_host *host)
-{
-	/* NANDFC buffer 0 is used for device ID output */
-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
-
-	writew(NFC_ID, NFC_V1_V2_CONFIG2);
-
-	/* Wait for operation to complete */
-	wait_op_done(host, true);
-
-	memcpy32_fromio(host->data_buf, host->main_area0, 16);
-}
-
-static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
-{
-	writew(NFC_STATUS, NFC_V3_LAUNCH);
-	wait_op_done(host, true);
-
-	return readl(NFC_V3_CONFIG1) >> 16;
-}
-
-/* This function requests the NANDFC to perform a read of the
- * NAND device status and returns the current status. */
-static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
-{
-	void __iomem *main_buf = host->main_area0;
-	uint32_t store;
-	uint16_t ret;
-
-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
-
-	/*
-	 * The device status is stored in main_area0. To
-	 * prevent corruption of the buffer save the value
-	 * and restore it afterwards.
-	 */
-	store = readl(main_buf);
-
-	writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
-	wait_op_done(host, true);
-
-	ret = readw(main_buf);
-
-	writel(store, main_buf);
-
-	return ret;
-}
-
-/* This functions is used by upper layer to checks if device is ready */
-static int mxc_nand_dev_ready(struct mtd_info *mtd)
-{
-	/*
-	 * NFC handles R/B internally. Therefore, this function
-	 * always returns status as ready.
-	 */
-	return 1;
-}
-
-static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	/*
-	 * If HW ECC is enabled, we turn it on during init. There is
-	 * no need to enable again here.
-	 */
-}
-
-static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
-				 u_char *read_ecc, u_char *calc_ecc)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-
-	/*
-	 * 1-Bit errors are automatically corrected in HW.  No need for
-	 * additional correction.  2-Bit errors cannot be corrected by
-	 * HW ECC, so we need to return failure
-	 */
-	uint16_t ecc_status = get_ecc_status_v1(host);
-
-	if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
-		dev_dbg(host->dev, "HWECC uncorrectable 2-bit ECC error\n");
-		return -EBADMSG;
-	}
-
-	return 0;
-}
-
-static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
-				 u_char *read_ecc, u_char *calc_ecc)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	u32 ecc_stat, err;
-	int no_subpages = 1;
-	int ret = 0;
-	u8 ecc_bit_mask, err_limit;
-
-	ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
-	err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
-
-	no_subpages = mtd->writesize >> 9;
-
-	ecc_stat = host->devtype_data->get_ecc_status(host);
-
-	do {
-		err = ecc_stat & ecc_bit_mask;
-		if (err > err_limit) {
-			dev_dbg(host->dev, "UnCorrectable RS-ECC Error\n");
-			return -EBADMSG;
-		} else {
-			ret += err;
-		}
-		ecc_stat >>= 4;
-	} while (--no_subpages);
-
-	dev_dbg(host->dev, "%d Symbol Correctable RS-ECC Error\n", ret);
-
-	return ret;
-}
-
-static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-				  u_char *ecc_code)
-{
-	return 0;
-}
-
-static u_char mxc_nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	uint8_t ret;
-
-	/* Check for status request */
-	if (host->status_request)
-		return host->devtype_data->get_dev_status(host) & 0xFF;
-
-	if (nand_chip->options & NAND_BUSWIDTH_16) {
-		/* only take the lower byte of each word */
-		ret = *(uint16_t *)(host->data_buf + host->buf_start);
-
-		host->buf_start += 2;
-	} else {
-		ret = *(uint8_t *)(host->data_buf + host->buf_start);
-		host->buf_start++;
-	}
-
-	dev_dbg(host->dev, "%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
-	return ret;
-}
-
-static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	uint16_t ret;
-
-	ret = *(uint16_t *)(host->data_buf + host->buf_start);
-	host->buf_start += 2;
-
-	return ret;
-}
-
-/* Write data of length len to buffer buf. The data to be
- * written on NAND Flash is first copied to RAMbuffer. After the Data Input
- * Operation by the NFC, the data is written to NAND Flash */
-static void mxc_nand_write_buf(struct mtd_info *mtd,
-				const u_char *buf, int len)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	u16 col = host->buf_start;
-	int n = mtd->oobsize + mtd->writesize - col;
-
-	n = min(n, len);
-
-	memcpy(host->data_buf + col, buf, n);
-
-	host->buf_start += n;
-}
-
-/* Read the data buffer from the NAND Flash. To read the data from NAND
- * Flash first the data output cycle is initiated by the NFC, which copies
- * the data to RAMbuffer. This data of length len is then copied to buffer buf.
- */
-static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	u16 col = host->buf_start;
-	int n = mtd->oobsize + mtd->writesize - col;
-
-	n = min(n, len);
-
-	memcpy(buf, host->data_buf + col, n);
-
-	host->buf_start += n;
-}
-
-/* This function is used by upper layer for select and
- * deselect of the NAND chip */
-static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-
-	if (chip == -1) {
-		/* Disable the NFC clock */
-		if (host->clk_act) {
-			clk_disable_unprepare(host->clk);
-			host->clk_act = 0;
-		}
-		return;
-	}
-
-	if (!host->clk_act) {
-		/* Enable the NFC clock */
-		clk_prepare_enable(host->clk);
-		host->clk_act = 1;
-	}
-}
-
-static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-
-	if (chip == -1) {
-		/* Disable the NFC clock */
-		if (host->clk_act) {
-			clk_disable_unprepare(host->clk);
-			host->clk_act = 0;
-		}
-		return;
-	}
-
-	if (!host->clk_act) {
-		/* Enable the NFC clock */
-		clk_prepare_enable(host->clk);
-		host->clk_act = 1;
-	}
-
-	host->active_cs = chip;
-	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
-}
-
-/*
- * The controller splits a page into data chunks of 512 bytes + partial oob.
- * There are writesize / 512 such chunks, the size of the partial oob parts is
- * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
- * contains additionally the byte lost by rounding (if any).
- * This function handles the needed shuffling between host->data_buf (which
- * holds a page in natural order, i.e. writesize bytes data + oobsize bytes
- * spare) and the NFC buffer.
- */
-static void copy_spare(struct mtd_info *mtd, bool bfrom)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(this);
-	u16 i, oob_chunk_size;
-	u16 num_chunks = mtd->writesize / 512;
-
-	u8 *d = host->data_buf + mtd->writesize;
-	u8 __iomem *s = host->spare0;
-	u16 sparebuf_size = host->devtype_data->spare_len;
-
-	/* size of oob chunk for all but possibly the last one */
-	oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
-
-	if (bfrom) {
-		for (i = 0; i < num_chunks - 1; i++)
-			memcpy16_fromio(d + i * oob_chunk_size,
-					s + i * sparebuf_size,
-					oob_chunk_size);
-
-		/* the last chunk */
-		memcpy16_fromio(d + i * oob_chunk_size,
-				s + i * sparebuf_size,
-				host->used_oobsize - i * oob_chunk_size);
-	} else {
-		for (i = 0; i < num_chunks - 1; i++)
-			memcpy16_toio(&s[i * sparebuf_size],
-				      &d[i * oob_chunk_size],
-				      oob_chunk_size);
-
-		/* the last chunk */
-		memcpy16_toio(&s[i * sparebuf_size],
-			      &d[i * oob_chunk_size],
-			      host->used_oobsize - i * oob_chunk_size);
-	}
-}
-
-/*
- * MXC NANDFC can only perform full page+spare or spare-only read/write.  When
- * the upper layers perform a read/write buf operation, the saved column address
- * is used to index into the full page. So usually this function is called with
- * column == 0 (unless no column cycle is needed indicated by column == -1)
- */
-static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-
-	/* Write out column address, if necessary */
-	if (column != -1) {
-		host->devtype_data->send_addr(host, column & 0xff,
-					      page_addr == -1);
-		if (mtd->writesize > 512)
-			/* another col addr cycle for 2k page */
-			host->devtype_data->send_addr(host,
-						      (column >> 8) & 0xff,
-						      false);
-	}
-
-	/* Write out page address, if necessary */
-	if (page_addr != -1) {
-		/* paddr_0 - p_addr_7 */
-		host->devtype_data->send_addr(host, (page_addr & 0xff), false);
-
-		if (mtd->writesize > 512) {
-			if (mtd->size >= 0x10000000) {
-				/* paddr_8 - paddr_15 */
-				host->devtype_data->send_addr(host,
-						(page_addr >> 8) & 0xff,
-						false);
-				host->devtype_data->send_addr(host,
-						(page_addr >> 16) & 0xff,
-						true);
-			} else
-				/* paddr_8 - paddr_15 */
-				host->devtype_data->send_addr(host,
-						(page_addr >> 8) & 0xff, true);
-		} else {
-			if (nand_chip->options & NAND_ROW_ADDR_3) {
-				/* paddr_8 - paddr_15 */
-				host->devtype_data->send_addr(host,
-						(page_addr >> 8) & 0xff,
-						false);
-				host->devtype_data->send_addr(host,
-						(page_addr >> 16) & 0xff,
-						true);
-			} else
-				/* paddr_8 - paddr_15 */
-				host->devtype_data->send_addr(host,
-						(page_addr >> 8) & 0xff, true);
-		}
-	}
-}
-
-#define MXC_V1_ECCBYTES		5
-
-static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
-				struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-
-	if (section >= nand_chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 6;
-	oobregion->length = MXC_V1_ECCBYTES;
-
-	return 0;
-}
-
-static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-
-	if (section > nand_chip->ecc.steps)
-		return -ERANGE;
-
-	if (!section) {
-		if (mtd->writesize <= 512) {
-			oobregion->offset = 0;
-			oobregion->length = 5;
-		} else {
-			oobregion->offset = 2;
-			oobregion->length = 4;
-		}
-	} else {
-		oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
-		if (section < nand_chip->ecc.steps)
-			oobregion->length = (section * 16) + 6 -
-					    oobregion->offset;
-		else
-			oobregion->length = mtd->oobsize - oobregion->offset;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
-	.ecc = mxc_v1_ooblayout_ecc,
-	.free = mxc_v1_ooblayout_free,
-};
-
-static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
-				struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
-
-	if (section >= nand_chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (section * stepsize) + 7;
-	oobregion->length = nand_chip->ecc.bytes;
-
-	return 0;
-}
-
-static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
-
-	if (section >= nand_chip->ecc.steps)
-		return -ERANGE;
-
-	if (!section) {
-		if (mtd->writesize <= 512) {
-			oobregion->offset = 0;
-			oobregion->length = 5;
-		} else {
-			oobregion->offset = 2;
-			oobregion->length = 4;
-		}
-	} else {
-		oobregion->offset = section * stepsize;
-		oobregion->length = 7;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
-	.ecc = mxc_v2_ooblayout_ecc,
-	.free = mxc_v2_ooblayout_free,
-};
-
-/*
- * v2 and v3 type controllers can do 4bit or 8bit ecc depending
- * on how much oob the nand chip has. For 8bit ecc we need at least
- * 26 bytes of oob data per 512 byte block.
- */
-static int get_eccsize(struct mtd_info *mtd)
-{
-	int oobbytes_per_512 = 0;
-
-	oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
-
-	if (oobbytes_per_512 < 26)
-		return 4;
-	else
-		return 8;
-}
-
-static void preset_v1(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	uint16_t config1 = 0;
-
-	if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
-		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
-
-	if (!host->devtype_data->irqpending_quirk)
-		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
-
-	host->eccsize = 1;
-
-	writew(config1, NFC_V1_V2_CONFIG1);
-	/* preset operation */
-
-	/* Unlock the internal RAM Buffer */
-	writew(0x2, NFC_V1_V2_CONFIG);
-
-	/* Blocks to be unlocked */
-	writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
-	writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
-
-	/* Unlock Block Command for given address range */
-	writew(0x4, NFC_V1_V2_WRPROT);
-}
-
-static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
-					const struct nand_data_interface *conf)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	int tRC_min_ns, tRC_ps, ret;
-	unsigned long rate, rate_round;
-	const struct nand_sdr_timings *timings;
-	u16 config1;
-
-	timings = nand_get_sdr_timings(conf);
-	if (IS_ERR(timings))
-		return -ENOTSUPP;
-
-	config1 = readw(NFC_V1_V2_CONFIG1);
-
-	tRC_min_ns = timings->tRC_min / 1000;
-	rate = 1000000000 / tRC_min_ns;
-
-	/*
-	 * For tRC < 30ns we have to use EDO mode. In this case the controller
-	 * does one access per clock cycle. Otherwise the controller does one
-	 * access in two clock cycles, thus we have to double the rate to the
-	 * controller.
-	 */
-	if (tRC_min_ns < 30) {
-		rate_round = clk_round_rate(host->clk, rate);
-		config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
-		tRC_ps = 1000000000 / (rate_round / 1000);
-	} else {
-		rate *= 2;
-		rate_round = clk_round_rate(host->clk, rate);
-		config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
-		tRC_ps = 1000000000 / (rate_round / 1000 / 2);
-	}
-
-	/*
-	 * The timing values compared against are from the i.MX25 Automotive
-	 * datasheet, Table 50. NFC Timing Parameters
-	 */
-	if (timings->tCLS_min > tRC_ps - 1000 ||
-	    timings->tCLH_min > tRC_ps - 2000 ||
-	    timings->tCS_min > tRC_ps - 1000 ||
-	    timings->tCH_min > tRC_ps - 2000 ||
-	    timings->tWP_min > tRC_ps - 1500 ||
-	    timings->tALS_min > tRC_ps ||
-	    timings->tALH_min > tRC_ps - 3000 ||
-	    timings->tDS_min > tRC_ps ||
-	    timings->tDH_min > tRC_ps - 5000 ||
-	    timings->tWC_min > 2 * tRC_ps ||
-	    timings->tWH_min > tRC_ps - 2500 ||
-	    timings->tRR_min > 6 * tRC_ps ||
-	    timings->tRP_min > 3 * tRC_ps / 2 ||
-	    timings->tRC_min > 2 * tRC_ps ||
-	    timings->tREH_min > (tRC_ps / 2) - 2500) {
-		dev_dbg(host->dev, "Timing out of bounds\n");
-		return -EINVAL;
-	}
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	ret = clk_set_rate(host->clk, rate);
-	if (ret)
-		return ret;
-
-	writew(config1, NFC_V1_V2_CONFIG1);
-
-	dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
-		config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
-		"normal");
-
-	return 0;
-}
-
-static void preset_v2(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	uint16_t config1 = 0;
-
-	config1 |= NFC_V2_CONFIG1_FP_INT;
-
-	if (!host->devtype_data->irqpending_quirk)
-		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
-
-	if (mtd->writesize) {
-		uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
-
-		if (nand_chip->ecc.mode == NAND_ECC_HW)
-			config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
-
-		host->eccsize = get_eccsize(mtd);
-		if (host->eccsize == 4)
-			config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
-
-		config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
-	} else {
-		host->eccsize = 1;
-	}
-
-	writew(config1, NFC_V1_V2_CONFIG1);
-	/* preset operation */
-
-	/* Unlock the internal RAM Buffer */
-	writew(0x2, NFC_V1_V2_CONFIG);
-
-	/* Blocks to be unlocked */
-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
-	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
-	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
-
-	/* Unlock Block Command for given address range */
-	writew(0x4, NFC_V1_V2_WRPROT);
-}
-
-static void preset_v3(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(chip);
-	uint32_t config2, config3;
-	int i, addr_phases;
-
-	writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
-	writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
-
-	/* Unlock the internal RAM Buffer */
-	writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
-			NFC_V3_WRPROT);
-
-	/* Blocks to be unlocked */
-	for (i = 0; i < NAND_MAX_CHIPS; i++)
-		writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
-
-	writel(0, NFC_V3_IPC);
-
-	config2 = NFC_V3_CONFIG2_ONE_CYCLE |
-		NFC_V3_CONFIG2_2CMD_PHASES |
-		NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
-		NFC_V3_CONFIG2_ST_CMD(0x70) |
-		NFC_V3_CONFIG2_INT_MSK |
-		NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
-
-	addr_phases = fls(chip->pagemask) >> 3;
-
-	if (mtd->writesize == 2048) {
-		config2 |= NFC_V3_CONFIG2_PS_2048;
-		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
-	} else if (mtd->writesize == 4096) {
-		config2 |= NFC_V3_CONFIG2_PS_4096;
-		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
-	} else {
-		config2 |= NFC_V3_CONFIG2_PS_512;
-		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
-	}
-
-	if (mtd->writesize) {
-		if (chip->ecc.mode == NAND_ECC_HW)
-			config2 |= NFC_V3_CONFIG2_ECC_EN;
-
-		config2 |= NFC_V3_CONFIG2_PPB(
-				ffs(mtd->erasesize / mtd->writesize) - 6,
-				host->devtype_data->ppb_shift);
-		host->eccsize = get_eccsize(mtd);
-		if (host->eccsize == 8)
-			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
-	}
-
-	writel(config2, NFC_V3_CONFIG2);
-
-	config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
-			NFC_V3_CONFIG3_NO_SDMA |
-			NFC_V3_CONFIG3_RBB_MODE |
-			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
-			NFC_V3_CONFIG3_ADD_OP(0);
-
-	if (!(chip->options & NAND_BUSWIDTH_16))
-		config3 |= NFC_V3_CONFIG3_FW8;
-
-	writel(config3, NFC_V3_CONFIG3);
-
-	writel(0, NFC_V3_DELAY_LINE);
-}
-
-/* Used by the upper layer to write command to NAND Flash for
- * different operations to be carried out on NAND Flash */
-static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
-				int column, int page_addr)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-
-	dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
-	      command, column, page_addr);
-
-	/* Reset command state information */
-	host->status_request = false;
-
-	/* Command pre-processing step */
-	switch (command) {
-	case NAND_CMD_RESET:
-		host->devtype_data->preset(mtd);
-		host->devtype_data->send_cmd(host, command, false);
-		break;
-
-	case NAND_CMD_STATUS:
-		host->buf_start = 0;
-		host->status_request = true;
-
-		host->devtype_data->send_cmd(host, command, true);
-		WARN_ONCE(column != -1 || page_addr != -1,
-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
-			  command, column, page_addr);
-		mxc_do_addr_cycle(mtd, column, page_addr);
-		break;
-
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-		if (command == NAND_CMD_READ0)
-			host->buf_start = column;
-		else
-			host->buf_start = column + mtd->writesize;
-
-		command = NAND_CMD_READ0; /* only READ0 is valid */
-
-		host->devtype_data->send_cmd(host, command, false);
-		WARN_ONCE(column < 0,
-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
-			  command, column, page_addr);
-		mxc_do_addr_cycle(mtd, 0, page_addr);
-
-		if (mtd->writesize > 512)
-			host->devtype_data->send_cmd(host,
-					NAND_CMD_READSTART, true);
-
-		host->devtype_data->send_page(mtd, NFC_OUTPUT);
-
-		memcpy32_fromio(host->data_buf, host->main_area0,
-				mtd->writesize);
-		copy_spare(mtd, true);
-		break;
-
-	case NAND_CMD_SEQIN:
-		if (column >= mtd->writesize)
-			/* call ourself to read a page */
-			mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
-
-		host->buf_start = column;
-
-		host->devtype_data->send_cmd(host, command, false);
-		WARN_ONCE(column < -1,
-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
-			  command, column, page_addr);
-		mxc_do_addr_cycle(mtd, 0, page_addr);
-		break;
-
-	case NAND_CMD_PAGEPROG:
-		memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
-		copy_spare(mtd, false);
-		host->devtype_data->send_page(mtd, NFC_INPUT);
-		host->devtype_data->send_cmd(host, command, true);
-		WARN_ONCE(column != -1 || page_addr != -1,
-			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
-			  command, column, page_addr);
-		mxc_do_addr_cycle(mtd, column, page_addr);
-		break;
-
-	case NAND_CMD_READID:
-		host->devtype_data->send_cmd(host, command, true);
-		mxc_do_addr_cycle(mtd, column, page_addr);
-		host->devtype_data->send_read_id(host);
-		host->buf_start = 0;
-		break;
-
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-		host->devtype_data->send_cmd(host, command, false);
-		WARN_ONCE(column != -1,
-			  "Unexpected column value (cmd=%u, col=%d)\n",
-			  command, column);
-		mxc_do_addr_cycle(mtd, column, page_addr);
-
-		break;
-	case NAND_CMD_PARAM:
-		host->devtype_data->send_cmd(host, command, false);
-		mxc_do_addr_cycle(mtd, column, page_addr);
-		host->devtype_data->send_page(mtd, NFC_OUTPUT);
-		memcpy32_fromio(host->data_buf, host->main_area0, 512);
-		host->buf_start = 0;
-		break;
-	default:
-		WARN_ONCE(1, "Unimplemented command (cmd=%u)\n",
-			  command);
-		break;
-	}
-}
-
-static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
-				      struct nand_chip *chip, int addr,
-				      u8 *subfeature_param)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	int i;
-
-	if (!chip->onfi_version ||
-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
-		return -EINVAL;
-
-	host->buf_start = 0;
-
-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-		chip->write_byte(mtd, subfeature_param[i]);
-
-	memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
-	host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
-	mxc_do_addr_cycle(mtd, addr, -1);
-	host->devtype_data->send_page(mtd, NFC_INPUT);
-
-	return 0;
-}
-
-static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
-				      struct nand_chip *chip, int addr,
-				      u8 *subfeature_param)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-	int i;
-
-	if (!chip->onfi_version ||
-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
-		return -EINVAL;
-
-	host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
-	mxc_do_addr_cycle(mtd, addr, -1);
-	host->devtype_data->send_page(mtd, NFC_OUTPUT);
-	memcpy32_fromio(host->data_buf, host->main_area0, 512);
-	host->buf_start = 0;
-
-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-		*subfeature_param++ = chip->read_byte(mtd);
-
-	return 0;
-}
-
-/*
- * The generic flash bbt decriptors overlap with our ecc
- * hardware, so define some i.MX specific ones.
- */
-static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
-static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs = 0,
-	.len = 4,
-	.veroffs = 4,
-	.maxblocks = 4,
-	.pattern = bbt_pattern,
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs = 0,
-	.len = 4,
-	.veroffs = 4,
-	.maxblocks = 4,
-	.pattern = mirror_pattern,
-};
-
-/* v1 + irqpending_quirk: i.MX21 */
-static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
-	.preset = preset_v1,
-	.send_cmd = send_cmd_v1_v2,
-	.send_addr = send_addr_v1_v2,
-	.send_page = send_page_v1,
-	.send_read_id = send_read_id_v1_v2,
-	.get_dev_status = get_dev_status_v1_v2,
-	.check_int = check_int_v1_v2,
-	.irq_control = irq_control_v1_v2,
-	.get_ecc_status = get_ecc_status_v1,
-	.ooblayout = &mxc_v1_ooblayout_ops,
-	.select_chip = mxc_nand_select_chip_v1_v3,
-	.correct_data = mxc_nand_correct_data_v1,
-	.irqpending_quirk = 1,
-	.needs_ip = 0,
-	.regs_offset = 0xe00,
-	.spare0_offset = 0x800,
-	.spare_len = 16,
-	.eccbytes = 3,
-	.eccsize = 1,
-};
-
-/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
-static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
-	.preset = preset_v1,
-	.send_cmd = send_cmd_v1_v2,
-	.send_addr = send_addr_v1_v2,
-	.send_page = send_page_v1,
-	.send_read_id = send_read_id_v1_v2,
-	.get_dev_status = get_dev_status_v1_v2,
-	.check_int = check_int_v1_v2,
-	.irq_control = irq_control_v1_v2,
-	.get_ecc_status = get_ecc_status_v1,
-	.ooblayout = &mxc_v1_ooblayout_ops,
-	.select_chip = mxc_nand_select_chip_v1_v3,
-	.correct_data = mxc_nand_correct_data_v1,
-	.irqpending_quirk = 0,
-	.needs_ip = 0,
-	.regs_offset = 0xe00,
-	.spare0_offset = 0x800,
-	.axi_offset = 0,
-	.spare_len = 16,
-	.eccbytes = 3,
-	.eccsize = 1,
-};
-
-/* v21: i.MX25, i.MX35 */
-static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
-	.preset = preset_v2,
-	.send_cmd = send_cmd_v1_v2,
-	.send_addr = send_addr_v1_v2,
-	.send_page = send_page_v2,
-	.send_read_id = send_read_id_v1_v2,
-	.get_dev_status = get_dev_status_v1_v2,
-	.check_int = check_int_v1_v2,
-	.irq_control = irq_control_v1_v2,
-	.get_ecc_status = get_ecc_status_v2,
-	.ooblayout = &mxc_v2_ooblayout_ops,
-	.select_chip = mxc_nand_select_chip_v2,
-	.correct_data = mxc_nand_correct_data_v2_v3,
-	.setup_data_interface = mxc_nand_v2_setup_data_interface,
-	.irqpending_quirk = 0,
-	.needs_ip = 0,
-	.regs_offset = 0x1e00,
-	.spare0_offset = 0x1000,
-	.axi_offset = 0,
-	.spare_len = 64,
-	.eccbytes = 9,
-	.eccsize = 0,
-};
-
-/* v3.2a: i.MX51 */
-static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
-	.preset = preset_v3,
-	.send_cmd = send_cmd_v3,
-	.send_addr = send_addr_v3,
-	.send_page = send_page_v3,
-	.send_read_id = send_read_id_v3,
-	.get_dev_status = get_dev_status_v3,
-	.check_int = check_int_v3,
-	.irq_control = irq_control_v3,
-	.get_ecc_status = get_ecc_status_v3,
-	.ooblayout = &mxc_v2_ooblayout_ops,
-	.select_chip = mxc_nand_select_chip_v1_v3,
-	.correct_data = mxc_nand_correct_data_v2_v3,
-	.irqpending_quirk = 0,
-	.needs_ip = 1,
-	.regs_offset = 0,
-	.spare0_offset = 0x1000,
-	.axi_offset = 0x1e00,
-	.spare_len = 64,
-	.eccbytes = 0,
-	.eccsize = 0,
-	.ppb_shift = 7,
-};
-
-/* v3.2b: i.MX53 */
-static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
-	.preset = preset_v3,
-	.send_cmd = send_cmd_v3,
-	.send_addr = send_addr_v3,
-	.send_page = send_page_v3,
-	.send_read_id = send_read_id_v3,
-	.get_dev_status = get_dev_status_v3,
-	.check_int = check_int_v3,
-	.irq_control = irq_control_v3,
-	.get_ecc_status = get_ecc_status_v3,
-	.ooblayout = &mxc_v2_ooblayout_ops,
-	.select_chip = mxc_nand_select_chip_v1_v3,
-	.correct_data = mxc_nand_correct_data_v2_v3,
-	.irqpending_quirk = 0,
-	.needs_ip = 1,
-	.regs_offset = 0,
-	.spare0_offset = 0x1000,
-	.axi_offset = 0x1e00,
-	.spare_len = 64,
-	.eccbytes = 0,
-	.eccsize = 0,
-	.ppb_shift = 8,
-};
-
-static inline int is_imx21_nfc(struct mxc_nand_host *host)
-{
-	return host->devtype_data == &imx21_nand_devtype_data;
-}
-
-static inline int is_imx27_nfc(struct mxc_nand_host *host)
-{
-	return host->devtype_data == &imx27_nand_devtype_data;
-}
-
-static inline int is_imx25_nfc(struct mxc_nand_host *host)
-{
-	return host->devtype_data == &imx25_nand_devtype_data;
-}
-
-static inline int is_imx51_nfc(struct mxc_nand_host *host)
-{
-	return host->devtype_data == &imx51_nand_devtype_data;
-}
-
-static inline int is_imx53_nfc(struct mxc_nand_host *host)
-{
-	return host->devtype_data == &imx53_nand_devtype_data;
-}
-
-static const struct platform_device_id mxcnd_devtype[] = {
-	{
-		.name = "imx21-nand",
-		.driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
-	}, {
-		.name = "imx27-nand",
-		.driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
-	}, {
-		.name = "imx25-nand",
-		.driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
-	}, {
-		.name = "imx51-nand",
-		.driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
-	}, {
-		.name = "imx53-nand",
-		.driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
-	}, {
-		/* sentinel */
-	}
-};
-MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
-
-#ifdef CONFIG_OF
-static const struct of_device_id mxcnd_dt_ids[] = {
-	{
-		.compatible = "fsl,imx21-nand",
-		.data = &imx21_nand_devtype_data,
-	}, {
-		.compatible = "fsl,imx27-nand",
-		.data = &imx27_nand_devtype_data,
-	}, {
-		.compatible = "fsl,imx25-nand",
-		.data = &imx25_nand_devtype_data,
-	}, {
-		.compatible = "fsl,imx51-nand",
-		.data = &imx51_nand_devtype_data,
-	}, {
-		.compatible = "fsl,imx53-nand",
-		.data = &imx53_nand_devtype_data,
-	},
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
-
-static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
-{
-	struct device_node *np = host->dev->of_node;
-	const struct of_device_id *of_id =
-		of_match_device(mxcnd_dt_ids, host->dev);
-
-	if (!np)
-		return 1;
-
-	host->devtype_data = of_id->data;
-
-	return 0;
-}
-#else
-static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
-{
-	return 1;
-}
-#endif
-
-static int mxcnd_probe(struct platform_device *pdev)
-{
-	struct nand_chip *this;
-	struct mtd_info *mtd;
-	struct mxc_nand_host *host;
-	struct resource *res;
-	int err = 0;
-
-	/* Allocate memory for MTD device structure and private data */
-	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
-			GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	/* allocate a temporary buffer for the nand_scan_ident() */
-	host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
-	if (!host->data_buf)
-		return -ENOMEM;
-
-	host->dev = &pdev->dev;
-	/* structures must be linked */
-	this = &host->nand;
-	mtd = nand_to_mtd(this);
-	mtd->dev.parent = &pdev->dev;
-	mtd->name = DRIVER_NAME;
-
-	/* 50 us command delay time */
-	this->chip_delay = 5;
-
-	nand_set_controller_data(this, host);
-	nand_set_flash_node(this, pdev->dev.of_node),
-	this->dev_ready = mxc_nand_dev_ready;
-	this->cmdfunc = mxc_nand_command;
-	this->read_byte = mxc_nand_read_byte;
-	this->read_word = mxc_nand_read_word;
-	this->write_buf = mxc_nand_write_buf;
-	this->read_buf = mxc_nand_read_buf;
-	this->onfi_set_features = mxc_nand_onfi_set_features;
-	this->onfi_get_features = mxc_nand_onfi_get_features;
-
-	host->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(host->clk))
-		return PTR_ERR(host->clk);
-
-	err = mxcnd_probe_dt(host);
-	if (err > 0) {
-		struct mxc_nand_platform_data *pdata =
-					dev_get_platdata(&pdev->dev);
-		if (pdata) {
-			host->pdata = *pdata;
-			host->devtype_data = (struct mxc_nand_devtype_data *)
-						pdev->id_entry->driver_data;
-		} else {
-			err = -ENODEV;
-		}
-	}
-	if (err < 0)
-		return err;
-
-	this->setup_data_interface = host->devtype_data->setup_data_interface;
-
-	if (host->devtype_data->needs_ip) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
-		if (IS_ERR(host->regs_ip))
-			return PTR_ERR(host->regs_ip);
-
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	} else {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	}
-
-	host->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(host->base))
-		return PTR_ERR(host->base);
-
-	host->main_area0 = host->base;
-
-	if (host->devtype_data->regs_offset)
-		host->regs = host->base + host->devtype_data->regs_offset;
-	host->spare0 = host->base + host->devtype_data->spare0_offset;
-	if (host->devtype_data->axi_offset)
-		host->regs_axi = host->base + host->devtype_data->axi_offset;
-
-	this->ecc.bytes = host->devtype_data->eccbytes;
-	host->eccsize = host->devtype_data->eccsize;
-
-	this->select_chip = host->devtype_data->select_chip;
-	this->ecc.size = 512;
-	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
-
-	if (host->pdata.hw_ecc) {
-		this->ecc.mode = NAND_ECC_HW;
-	} else {
-		this->ecc.mode = NAND_ECC_SOFT;
-		this->ecc.algo = NAND_ECC_HAMMING;
-	}
-
-	/* NAND bus width determines access functions used by upper layer */
-	if (host->pdata.width == 2)
-		this->options |= NAND_BUSWIDTH_16;
-
-	/* update flash based bbt */
-	if (host->pdata.flash_bbt)
-		this->bbt_options |= NAND_BBT_USE_FLASH;
-
-	init_completion(&host->op_completion);
-
-	host->irq = platform_get_irq(pdev, 0);
-	if (host->irq < 0)
-		return host->irq;
-
-	/*
-	 * Use host->devtype_data->irq_control() here instead of irq_control()
-	 * because we must not disable_irq_nosync without having requested the
-	 * irq.
-	 */
-	host->devtype_data->irq_control(host, 0);
-
-	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
-			0, DRIVER_NAME, host);
-	if (err)
-		return err;
-
-	err = clk_prepare_enable(host->clk);
-	if (err)
-		return err;
-	host->clk_act = 1;
-
-	/*
-	 * Now that we "own" the interrupt make sure the interrupt mask bit is
-	 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
-	 * on this machine.
-	 */
-	if (host->devtype_data->irqpending_quirk) {
-		disable_irq_nosync(host->irq);
-		host->devtype_data->irq_control(host, 1);
-	}
-
-	/* first scan to find the device and get the page size */
-	err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
-	if (err)
-		goto escan;
-
-	switch (this->ecc.mode) {
-	case NAND_ECC_HW:
-		this->ecc.calculate = mxc_nand_calculate_ecc;
-		this->ecc.hwctl = mxc_nand_enable_hwecc;
-		this->ecc.correct = host->devtype_data->correct_data;
-		break;
-
-	case NAND_ECC_SOFT:
-		break;
-
-	default:
-		err = -EINVAL;
-		goto escan;
-	}
-
-	if (this->bbt_options & NAND_BBT_USE_FLASH) {
-		this->bbt_td = &bbt_main_descr;
-		this->bbt_md = &bbt_mirror_descr;
-	}
-
-	/* allocate the right size buffer now */
-	devm_kfree(&pdev->dev, (void *)host->data_buf);
-	host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
-					GFP_KERNEL);
-	if (!host->data_buf) {
-		err = -ENOMEM;
-		goto escan;
-	}
-
-	/* Call preset again, with correct writesize this time */
-	host->devtype_data->preset(mtd);
-
-	if (!this->ecc.bytes) {
-		if (host->eccsize == 8)
-			this->ecc.bytes = 18;
-		else if (host->eccsize == 4)
-			this->ecc.bytes = 9;
-	}
-
-	/*
-	 * Experimentation shows that i.MX NFC can only handle up to 218 oob
-	 * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
-	 * into copying invalid data to/from the spare IO buffer, as this
-	 * might cause ECC data corruption when doing sub-page write to a
-	 * partially written page.
-	 */
-	host->used_oobsize = min(mtd->oobsize, 218U);
-
-	if (this->ecc.mode == NAND_ECC_HW) {
-		if (is_imx21_nfc(host) || is_imx27_nfc(host))
-			this->ecc.strength = 1;
-		else
-			this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
-	}
-
-	/* second phase scan */
-	err = nand_scan_tail(mtd);
-	if (err)
-		goto escan;
-
-	/* Register the partitions */
-	mtd_device_parse_register(mtd, part_probes,
-			NULL,
-			host->pdata.parts,
-			host->pdata.nr_parts);
-
-	platform_set_drvdata(pdev, host);
-
-	return 0;
-
-escan:
-	if (host->clk_act)
-		clk_disable_unprepare(host->clk);
-
-	return err;
-}
-
-static int mxcnd_remove(struct platform_device *pdev)
-{
-	struct mxc_nand_host *host = platform_get_drvdata(pdev);
-
-	nand_release(nand_to_mtd(&host->nand));
-	if (host->clk_act)
-		clk_disable_unprepare(host->clk);
-
-	return 0;
-}
-
-static struct platform_driver mxcnd_driver = {
-	.driver = {
-		   .name = DRIVER_NAME,
-		   .of_match_table = of_match_ptr(mxcnd_dt_ids),
-	},
-	.id_table = mxcnd_devtype,
-	.probe = mxcnd_probe,
-	.remove = mxcnd_remove,
-};
-module_platform_driver(mxcnd_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("MXC NAND MTD driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/nand_amd.c b/drivers/mtd/nand/nand_amd.c
deleted file mode 100644
index 22f060f38123..000000000000
--- a/drivers/mtd/nand/nand_amd.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 Free Electrons
- * Copyright (C) 2017 NextThing Co
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mtd/rawnand.h>
-
-static void amd_nand_decode_id(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	nand_decode_ext_id(chip);
-
-	/*
-	 * Check for Spansion/AMD ID + repeating 5th, 6th byte since
-	 * some Spansion chips have erasesize that conflicts with size
-	 * listed in nand_ids table.
-	 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
-	 */
-	if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
-	    chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
-	    mtd->writesize == 512) {
-		mtd->erasesize = 128 * 1024;
-		mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
-	}
-}
-
-static int amd_nand_init(struct nand_chip *chip)
-{
-	if (nand_is_slc(chip))
-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
-	return 0;
-}
-
-const struct nand_manufacturer_ops amd_nand_manuf_ops = {
-	.detect = amd_nand_decode_id,
-	.init = amd_nand_init,
-};
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
deleted file mode 100644
index e70ca16a5118..000000000000
--- a/drivers/mtd/nand/nand_base.c
+++ /dev/null
@@ -1,6582 +0,0 @@
-/*
- *  Overview:
- *   This is the generic MTD driver for NAND flash devices. It should be
- *   capable of working with almost all NAND chips currently available.
- *
- *	Additional technical information is available on
- *	http://www.linux-mtd.infradead.org/doc/nand.html
- *
- *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *		  2002-2006 Thomas Gleixner (tglx@linutronix.de)
- *
- *  Credits:
- *	David Woodhouse for adding multichip support
- *
- *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the
- *	rework for 2K page size chips
- *
- *  TODO:
- *	Enable cached programming for 2k page size chips
- *	Check, if mtd->ecctype should be set to MTD_ECC_HW
- *	if we have HW ECC support.
- *	BBT table is not serialized, has to be fixed
- *
- * 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.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/nmi.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/nand_bch.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/io.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of.h>
-
-static int nand_get_device(struct mtd_info *mtd, int new_state);
-
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
-			     struct mtd_oob_ops *ops);
-
-/* Define default oob placement schemes for large and small page devices */
-static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (section > 1)
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->offset = 0;
-		if (mtd->oobsize == 16)
-			oobregion->length = 4;
-		else
-			oobregion->length = 3;
-	} else {
-		if (mtd->oobsize == 8)
-			return -ERANGE;
-
-		oobregion->offset = 6;
-		oobregion->length = ecc->total - 4;
-	}
-
-	return 0;
-}
-
-static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	if (section > 1)
-		return -ERANGE;
-
-	if (mtd->oobsize == 16) {
-		if (section)
-			return -ERANGE;
-
-		oobregion->length = 8;
-		oobregion->offset = 8;
-	} else {
-		oobregion->length = 2;
-		if (!section)
-			oobregion->offset = 3;
-		else
-			oobregion->offset = 6;
-	}
-
-	return 0;
-}
-
-const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
-	.ecc = nand_ooblayout_ecc_sp,
-	.free = nand_ooblayout_free_sp,
-};
-EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
-
-static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (section || !ecc->total)
-		return -ERANGE;
-
-	oobregion->length = ecc->total;
-	oobregion->offset = mtd->oobsize - oobregion->length;
-
-	return 0;
-}
-
-static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->length = mtd->oobsize - ecc->total - 2;
-	oobregion->offset = 2;
-
-	return 0;
-}
-
-const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
-	.ecc = nand_ooblayout_ecc_lp,
-	.free = nand_ooblayout_free_lp,
-};
-EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
-
-/*
- * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
- * are placed at a fixed offset.
- */
-static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
-					 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (section)
-		return -ERANGE;
-
-	switch (mtd->oobsize) {
-	case 64:
-		oobregion->offset = 40;
-		break;
-	case 128:
-		oobregion->offset = 80;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	oobregion->length = ecc->total;
-	if (oobregion->offset + oobregion->length > mtd->oobsize)
-		return -ERANGE;
-
-	return 0;
-}
-
-static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
-					  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ecc_offset = 0;
-
-	if (section < 0 || section > 1)
-		return -ERANGE;
-
-	switch (mtd->oobsize) {
-	case 64:
-		ecc_offset = 40;
-		break;
-	case 128:
-		ecc_offset = 80;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (section == 0) {
-		oobregion->offset = 2;
-		oobregion->length = ecc_offset - 2;
-	} else {
-		oobregion->offset = ecc_offset + ecc->total;
-		oobregion->length = mtd->oobsize - oobregion->offset;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
-	.ecc = nand_ooblayout_ecc_lp_hamming,
-	.free = nand_ooblayout_free_lp_hamming,
-};
-
-static int check_offs_len(struct mtd_info *mtd,
-					loff_t ofs, uint64_t len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret = 0;
-
-	/* Start address must align on block boundary */
-	if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
-		pr_debug("%s: unaligned address\n", __func__);
-		ret = -EINVAL;
-	}
-
-	/* Length must align on block boundary */
-	if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
-		pr_debug("%s: length not block aligned\n", __func__);
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-/**
- * nand_release_device - [GENERIC] release chip
- * @mtd: MTD device structure
- *
- * Release chip lock and wake up anyone waiting on the device.
- */
-static void nand_release_device(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	/* Release the controller and the chip */
-	spin_lock(&chip->controller->lock);
-	chip->controller->active = NULL;
-	chip->state = FL_READY;
-	wake_up(&chip->controller->wq);
-	spin_unlock(&chip->controller->lock);
-}
-
-/**
- * nand_read_byte - [DEFAULT] read one byte from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 8bit buswidth
- */
-static uint8_t nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	return readb(chip->IO_ADDR_R);
-}
-
-/**
- * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth with endianness conversion.
- *
- */
-static uint8_t nand_read_byte16(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
-}
-
-/**
- * nand_read_word - [DEFAULT] read one word from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth without endianness conversion.
- */
-static u16 nand_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	return readw(chip->IO_ADDR_R);
-}
-
-/**
- * nand_select_chip - [DEFAULT] control CE line
- * @mtd: MTD device structure
- * @chipnr: chipnumber to select, -1 for deselect
- *
- * Default select function for 1 chip devices.
- */
-static void nand_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	switch (chipnr) {
-	case -1:
-		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
-		break;
-	case 0:
-		break;
-
-	default:
-		BUG();
-	}
-}
-
-/**
- * nand_write_byte - [DEFAULT] write single byte to chip
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0]
- */
-static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	chip->write_buf(mtd, &byte, 1);
-}
-
-/**
- * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
- */
-static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	uint16_t word = byte;
-
-	/*
-	 * It's not entirely clear what should happen to I/O[15:8] when writing
-	 * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
-	 *
-	 *    When the host supports a 16-bit bus width, only data is
-	 *    transferred at the 16-bit width. All address and command line
-	 *    transfers shall use only the lower 8-bits of the data bus. During
-	 *    command transfers, the host may place any value on the upper
-	 *    8-bits of the data bus. During address transfers, the host shall
-	 *    set the upper 8-bits of the data bus to 00h.
-	 *
-	 * One user of the write_byte callback is nand_onfi_set_features. The
-	 * four parameters are specified to be written to I/O[7:0], but this is
-	 * neither an address nor a command transfer. Let's assume a 0 on the
-	 * upper I/O lines is OK.
-	 */
-	chip->write_buf(mtd, (uint8_t *)&word, 2);
-}
-
-/**
- * nand_write_buf - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 8bit buswidth.
- */
-static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	iowrite8_rep(chip->IO_ADDR_W, buf, len);
-}
-
-/**
- * nand_read_buf - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 8bit buswidth.
- */
-static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	ioread8_rep(chip->IO_ADDR_R, buf, len);
-}
-
-/**
- * nand_write_buf16 - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 16bit buswidth.
- */
-static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u16 *p = (u16 *) buf;
-
-	iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
-}
-
-/**
- * nand_read_buf16 - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 16bit buswidth.
- */
-static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u16 *p = (u16 *) buf;
-
-	ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
-}
-
-/**
- * nand_block_bad - [DEFAULT] Read bad block marker from the chip
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * Check, if the block is bad.
- */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
-{
-	int page, page_end, res;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u8 bad;
-
-	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-		ofs += mtd->erasesize - mtd->writesize;
-
-	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-	page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
-
-	for (; page < page_end; page++) {
-		res = chip->ecc.read_oob(mtd, chip, page);
-		if (res)
-			return res;
-
-		bad = chip->oob_poi[chip->badblockpos];
-
-		if (likely(chip->badblockbits == 8))
-			res = bad != 0xFF;
-		else
-			res = hweight8(bad) < chip->badblockbits;
-		if (res)
-			return res;
-	}
-
-	return 0;
-}
-
-/**
- * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * This is the default implementation, which can be overridden by a hardware
- * specific driver. It provides the details for writing a bad block marker to a
- * block.
- */
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtd_oob_ops ops;
-	uint8_t buf[2] = { 0, 0 };
-	int ret = 0, res, i = 0;
-
-	memset(&ops, 0, sizeof(ops));
-	ops.oobbuf = buf;
-	ops.ooboffs = chip->badblockpos;
-	if (chip->options & NAND_BUSWIDTH_16) {
-		ops.ooboffs &= ~0x01;
-		ops.len = ops.ooblen = 2;
-	} else {
-		ops.len = ops.ooblen = 1;
-	}
-	ops.mode = MTD_OPS_PLACE_OOB;
-
-	/* Write to first/last page(s) if necessary */
-	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-		ofs += mtd->erasesize - mtd->writesize;
-	do {
-		res = nand_do_write_oob(mtd, ofs, &ops);
-		if (!ret)
-			ret = res;
-
-		i++;
-		ofs += mtd->writesize;
-	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-
-	return ret;
-}
-
-/**
- * nand_block_markbad_lowlevel - mark a block bad
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * This function performs the generic NAND bad block marking steps (i.e., bad
- * block table(s) and/or marker(s)). We only allow the hardware driver to
- * specify how to write bad block markers to OOB (chip->block_markbad).
- *
- * We try operations in the following order:
- *
- *  (1) erase the affected block, to allow OOB marker to be written cleanly
- *  (2) write bad block marker to OOB area of affected block (unless flag
- *      NAND_BBT_NO_OOB_BBM is present)
- *  (3) update the BBT
- *
- * Note that we retain the first error encountered in (2) or (3), finish the
- * procedures, and dump the error in the end.
-*/
-static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int res, ret = 0;
-
-	if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
-		struct erase_info einfo;
-
-		/* Attempt erase before marking OOB */
-		memset(&einfo, 0, sizeof(einfo));
-		einfo.mtd = mtd;
-		einfo.addr = ofs;
-		einfo.len = 1ULL << chip->phys_erase_shift;
-		nand_erase_nand(mtd, &einfo, 0);
-
-		/* Write bad block marker to OOB */
-		nand_get_device(mtd, FL_WRITING);
-		ret = chip->block_markbad(mtd, ofs);
-		nand_release_device(mtd);
-	}
-
-	/* Mark block bad in BBT */
-	if (chip->bbt) {
-		res = nand_markbad_bbt(mtd, ofs);
-		if (!ret)
-			ret = res;
-	}
-
-	if (!ret)
-		mtd->ecc_stats.badblocks++;
-
-	return ret;
-}
-
-/**
- * nand_check_wp - [GENERIC] check if the chip is write protected
- * @mtd: MTD device structure
- *
- * Check, if the device is write protected. The function expects, that the
- * device is already selected.
- */
-static int nand_check_wp(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u8 status;
-	int ret;
-
-	/* Broken xD cards report WP despite being writable */
-	if (chip->options & NAND_BROKEN_XD)
-		return 0;
-
-	/* Check the WP bit */
-	ret = nand_status_op(chip, &status);
-	if (ret)
-		return ret;
-
-	return status & NAND_STATUS_WP ? 0 : 1;
-}
-
-/**
- * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * Check if the block is marked as reserved.
- */
-static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (!chip->bbt)
-		return 0;
-	/* Return info from the table */
-	return nand_isreserved_bbt(mtd, ofs);
-}
-
-/**
- * nand_block_checkbad - [GENERIC] Check if a block is marked bad
- * @mtd: MTD device structure
- * @ofs: offset from device start
- * @allowbbt: 1, if its allowed to access the bbt area
- *
- * Check, if the block is bad. Either by reading the bad block table or
- * calling of the scan function.
- */
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs);
-
-	/* Return info from the table */
-	return nand_isbad_bbt(mtd, ofs, allowbbt);
-}
-
-/**
- * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout
- *
- * Helper function for nand_wait_ready used when needing to wait in interrupt
- * context.
- */
-static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int i;
-
-	/* Wait for the device to get ready */
-	for (i = 0; i < timeo; i++) {
-		if (chip->dev_ready(mtd))
-			break;
-		touch_softlockup_watchdog();
-		mdelay(1);
-	}
-}
-
-/**
- * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- *
- * Wait for the ready pin after a command, and warn if a timeout occurs.
- */
-void nand_wait_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	unsigned long timeo = 400;
-
-	if (in_interrupt() || oops_in_progress)
-		return panic_nand_wait_ready(mtd, timeo);
-
-	/* Wait until command is processed or timeout occurs */
-	timeo = jiffies + msecs_to_jiffies(timeo);
-	do {
-		if (chip->dev_ready(mtd))
-			return;
-		cond_resched();
-	} while (time_before(jiffies, timeo));
-
-	if (!chip->dev_ready(mtd))
-		pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
-}
-EXPORT_SYMBOL_GPL(nand_wait_ready);
-
-/**
- * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout in ms
- *
- * Wait for status ready (i.e. command done) or timeout.
- */
-static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
-{
-	register struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	timeo = jiffies + msecs_to_jiffies(timeo);
-	do {
-		u8 status;
-
-		ret = nand_read_data_op(chip, &status, sizeof(status), true);
-		if (ret)
-			return;
-
-		if (status & NAND_STATUS_READY)
-			break;
-		touch_softlockup_watchdog();
-	} while (time_before(jiffies, timeo));
-};
-
-/**
- * nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1
- * @chip: NAND chip structure
- * @timeout_ms: Timeout in ms
- *
- * Poll the STATUS register using ->exec_op() until the RDY bit becomes 1.
- * If that does not happen whitin the specified timeout, -ETIMEDOUT is
- * returned.
- *
- * This helper is intended to be used when the controller does not have access
- * to the NAND R/B pin.
- *
- * Be aware that calling this helper from an ->exec_op() implementation means
- * ->exec_op() must be re-entrant.
- *
- * Return 0 if the NAND chip is ready, a negative error otherwise.
- */
-int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
-{
-	u8 status = 0;
-	int ret;
-
-	if (!chip->exec_op)
-		return -ENOTSUPP;
-
-	ret = nand_status_op(chip, NULL);
-	if (ret)
-		return ret;
-
-	timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
-	do {
-		ret = nand_read_data_op(chip, &status, sizeof(status), true);
-		if (ret)
-			break;
-
-		if (status & NAND_STATUS_READY)
-			break;
-
-		/*
-		 * Typical lowest execution time for a tR on most NANDs is 10us,
-		 * use this as polling delay before doing something smarter (ie.
-		 * deriving a delay from the timeout value, timeout_ms/ratio).
-		 */
-		udelay(10);
-	} while	(time_before(jiffies, timeout_ms));
-
-	/*
-	 * We have to exit READ_STATUS mode in order to read real data on the
-	 * bus in case the WAITRDY instruction is preceding a DATA_IN
-	 * instruction.
-	 */
-	nand_exit_status_op(chip);
-
-	if (ret)
-		return ret;
-
-	return status & NAND_STATUS_READY ? 0 : -ETIMEDOUT;
-};
-EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
-
-/**
- * nand_command - [DEFAULT] Send command to NAND device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This function is used for small page devices
- * (512 Bytes per page).
- */
-static void nand_command(struct mtd_info *mtd, unsigned int command,
-			 int column, int page_addr)
-{
-	register struct nand_chip *chip = mtd_to_nand(mtd);
-	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
-
-	/* Write out the command to the device */
-	if (command == NAND_CMD_SEQIN) {
-		int readcmd;
-
-		if (column >= mtd->writesize) {
-			/* OOB area */
-			column -= mtd->writesize;
-			readcmd = NAND_CMD_READOOB;
-		} else if (column < 256) {
-			/* First 256 bytes --> READ0 */
-			readcmd = NAND_CMD_READ0;
-		} else {
-			column -= 256;
-			readcmd = NAND_CMD_READ1;
-		}
-		chip->cmd_ctrl(mtd, readcmd, ctrl);
-		ctrl &= ~NAND_CTRL_CHANGE;
-	}
-	if (command != NAND_CMD_NONE)
-		chip->cmd_ctrl(mtd, command, ctrl);
-
-	/* Address cycle, when necessary */
-	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
-	/* Serially input address */
-	if (column != -1) {
-		/* Adjust columns for 16 bit buswidth */
-		if (chip->options & NAND_BUSWIDTH_16 &&
-				!nand_opcode_8bits(command))
-			column >>= 1;
-		chip->cmd_ctrl(mtd, column, ctrl);
-		ctrl &= ~NAND_CTRL_CHANGE;
-	}
-	if (page_addr != -1) {
-		chip->cmd_ctrl(mtd, page_addr, ctrl);
-		ctrl &= ~NAND_CTRL_CHANGE;
-		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
-		if (chip->options & NAND_ROW_ADDR_3)
-			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
-	}
-	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-	/*
-	 * Program and erase have their own busy handlers status and sequential
-	 * in needs no delay
-	 */
-	switch (command) {
-
-	case NAND_CMD_NONE:
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_READID:
-	case NAND_CMD_SET_FEATURES:
-		return;
-
-	case NAND_CMD_RESET:
-		if (chip->dev_ready)
-			break;
-		udelay(chip->chip_delay);
-		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
-			       NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-		chip->cmd_ctrl(mtd,
-			       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
-		nand_wait_status_ready(mtd, 250);
-		return;
-
-		/* This applies to read commands */
-	case NAND_CMD_READ0:
-		/*
-		 * READ0 is sometimes used to exit GET STATUS mode. When this
-		 * is the case no address cycles are requested, and we can use
-		 * this information to detect that we should not wait for the
-		 * device to be ready.
-		 */
-		if (column == -1 && page_addr == -1)
-			return;
-
-	default:
-		/*
-		 * If we don't have access to the busy pin, we apply the given
-		 * command delay
-		 */
-		if (!chip->dev_ready) {
-			udelay(chip->chip_delay);
-			return;
-		}
-	}
-	/*
-	 * Apply this short delay always to ensure that we do wait tWB in
-	 * any case on any machine.
-	 */
-	ndelay(100);
-
-	nand_wait_ready(mtd);
-}
-
-static void nand_ccs_delay(struct nand_chip *chip)
-{
-	/*
-	 * The controller already takes care of waiting for tCCS when the RNDIN
-	 * or RNDOUT command is sent, return directly.
-	 */
-	if (!(chip->options & NAND_WAIT_TCCS))
-		return;
-
-	/*
-	 * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
-	 * (which should be safe for all NANDs).
-	 */
-	if (chip->setup_data_interface)
-		ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
-	else
-		ndelay(500);
-}
-
-/**
- * nand_command_lp - [DEFAULT] Send command to NAND large page device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This is the version for the new large page
- * devices. We don't have the separate regions as we have in the small page
- * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
- */
-static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
-			    int column, int page_addr)
-{
-	register struct nand_chip *chip = mtd_to_nand(mtd);
-
-	/* Emulate NAND_CMD_READOOB */
-	if (command == NAND_CMD_READOOB) {
-		column += mtd->writesize;
-		command = NAND_CMD_READ0;
-	}
-
-	/* Command latch cycle */
-	if (command != NAND_CMD_NONE)
-		chip->cmd_ctrl(mtd, command,
-			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-
-	if (column != -1 || page_addr != -1) {
-		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
-
-		/* Serially input address */
-		if (column != -1) {
-			/* Adjust columns for 16 bit buswidth */
-			if (chip->options & NAND_BUSWIDTH_16 &&
-					!nand_opcode_8bits(command))
-				column >>= 1;
-			chip->cmd_ctrl(mtd, column, ctrl);
-			ctrl &= ~NAND_CTRL_CHANGE;
-
-			/* Only output a single addr cycle for 8bits opcodes. */
-			if (!nand_opcode_8bits(command))
-				chip->cmd_ctrl(mtd, column >> 8, ctrl);
-		}
-		if (page_addr != -1) {
-			chip->cmd_ctrl(mtd, page_addr, ctrl);
-			chip->cmd_ctrl(mtd, page_addr >> 8,
-				       NAND_NCE | NAND_ALE);
-			if (chip->options & NAND_ROW_ADDR_3)
-				chip->cmd_ctrl(mtd, page_addr >> 16,
-					       NAND_NCE | NAND_ALE);
-		}
-	}
-	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-	/*
-	 * Program and erase have their own busy handlers status, sequential
-	 * in and status need no delay.
-	 */
-	switch (command) {
-
-	case NAND_CMD_NONE:
-	case NAND_CMD_CACHEDPROG:
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_READID:
-	case NAND_CMD_SET_FEATURES:
-		return;
-
-	case NAND_CMD_RNDIN:
-		nand_ccs_delay(chip);
-		return;
-
-	case NAND_CMD_RESET:
-		if (chip->dev_ready)
-			break;
-		udelay(chip->chip_delay);
-		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
-			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
-			       NAND_NCE | NAND_CTRL_CHANGE);
-		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
-		nand_wait_status_ready(mtd, 250);
-		return;
-
-	case NAND_CMD_RNDOUT:
-		/* No ready / busy check necessary */
-		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
-			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
-			       NAND_NCE | NAND_CTRL_CHANGE);
-
-		nand_ccs_delay(chip);
-		return;
-
-	case NAND_CMD_READ0:
-		/*
-		 * READ0 is sometimes used to exit GET STATUS mode. When this
-		 * is the case no address cycles are requested, and we can use
-		 * this information to detect that READSTART should not be
-		 * issued.
-		 */
-		if (column == -1 && page_addr == -1)
-			return;
-
-		chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
-			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
-			       NAND_NCE | NAND_CTRL_CHANGE);
-
-		/* This applies to read commands */
-	default:
-		/*
-		 * If we don't have access to the busy pin, we apply the given
-		 * command delay.
-		 */
-		if (!chip->dev_ready) {
-			udelay(chip->chip_delay);
-			return;
-		}
-	}
-
-	/*
-	 * Apply this short delay always to ensure that we do wait tWB in
-	 * any case on any machine.
-	 */
-	ndelay(100);
-
-	nand_wait_ready(mtd);
-}
-
-/**
- * panic_nand_get_device - [GENERIC] Get chip for selected access
- * @chip: the nand chip descriptor
- * @mtd: MTD device structure
- * @new_state: the state which is requested
- *
- * Used when in panic, no locks are taken.
- */
-static void panic_nand_get_device(struct nand_chip *chip,
-		      struct mtd_info *mtd, int new_state)
-{
-	/* Hardware controller shared among independent devices */
-	chip->controller->active = chip;
-	chip->state = new_state;
-}
-
-/**
- * nand_get_device - [GENERIC] Get chip for selected access
- * @mtd: MTD device structure
- * @new_state: the state which is requested
- *
- * Get the device and lock it for exclusive access
- */
-static int
-nand_get_device(struct mtd_info *mtd, int new_state)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	spinlock_t *lock = &chip->controller->lock;
-	wait_queue_head_t *wq = &chip->controller->wq;
-	DECLARE_WAITQUEUE(wait, current);
-retry:
-	spin_lock(lock);
-
-	/* Hardware controller shared among independent devices */
-	if (!chip->controller->active)
-		chip->controller->active = chip;
-
-	if (chip->controller->active == chip && chip->state == FL_READY) {
-		chip->state = new_state;
-		spin_unlock(lock);
-		return 0;
-	}
-	if (new_state == FL_PM_SUSPENDED) {
-		if (chip->controller->active->state == FL_PM_SUSPENDED) {
-			chip->state = FL_PM_SUSPENDED;
-			spin_unlock(lock);
-			return 0;
-		}
-	}
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(wq, &wait);
-	spin_unlock(lock);
-	schedule();
-	remove_wait_queue(wq, &wait);
-	goto retry;
-}
-
-/**
- * panic_nand_wait - [GENERIC] wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND chip structure
- * @timeo: timeout
- *
- * Wait for command done. This is a helper function for nand_wait used when
- * we are in interrupt context. May happen when in panic and trying to write
- * an oops through mtdoops.
- */
-static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
-			    unsigned long timeo)
-{
-	int i;
-	for (i = 0; i < timeo; i++) {
-		if (chip->dev_ready) {
-			if (chip->dev_ready(mtd))
-				break;
-		} else {
-			int ret;
-			u8 status;
-
-			ret = nand_read_data_op(chip, &status, sizeof(status),
-						true);
-			if (ret)
-				return;
-
-			if (status & NAND_STATUS_READY)
-				break;
-		}
-		mdelay(1);
-	}
-}
-
-/**
- * nand_wait - [DEFAULT] wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND chip structure
- *
- * Wait for command done. This applies to erase and program only.
- */
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-
-	unsigned long timeo = 400;
-	u8 status;
-	int ret;
-
-	/*
-	 * Apply this short delay always to ensure that we do wait tWB in any
-	 * case on any machine.
-	 */
-	ndelay(100);
-
-	ret = nand_status_op(chip, NULL);
-	if (ret)
-		return ret;
-
-	if (in_interrupt() || oops_in_progress)
-		panic_nand_wait(mtd, chip, timeo);
-	else {
-		timeo = jiffies + msecs_to_jiffies(timeo);
-		do {
-			if (chip->dev_ready) {
-				if (chip->dev_ready(mtd))
-					break;
-			} else {
-				ret = nand_read_data_op(chip, &status,
-							sizeof(status), true);
-				if (ret)
-					return ret;
-
-				if (status & NAND_STATUS_READY)
-					break;
-			}
-			cond_resched();
-		} while (time_before(jiffies, timeo));
-	}
-
-	ret = nand_read_data_op(chip, &status, sizeof(status), true);
-	if (ret)
-		return ret;
-
-	/* This can happen if in case of timeout or buggy dev_ready */
-	WARN_ON(!(status & NAND_STATUS_READY));
-	return status;
-}
-
-/**
- * nand_reset_data_interface - Reset data interface and timings
- * @chip: The NAND chip
- * @chipnr: Internal die id
- *
- * Reset the Data interface and timings to ONFI mode 0.
- *
- * Returns 0 for success or negative error code otherwise.
- */
-static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-
-	if (!chip->setup_data_interface)
-		return 0;
-
-	/*
-	 * The ONFI specification says:
-	 * "
-	 * To transition from NV-DDR or NV-DDR2 to the SDR data
-	 * interface, the host shall use the Reset (FFh) command
-	 * using SDR timing mode 0. A device in any timing mode is
-	 * required to recognize Reset (FFh) command issued in SDR
-	 * timing mode 0.
-	 * "
-	 *
-	 * Configure the data interface in SDR mode and set the
-	 * timings to timing mode 0.
-	 */
-
-	onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
-	ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
-	if (ret)
-		pr_err("Failed to configure data interface to SDR timing mode 0\n");
-
-	return ret;
-}
-
-/**
- * nand_setup_data_interface - Setup the best data interface and timings
- * @chip: The NAND chip
- * @chipnr: Internal die id
- *
- * Find and configure the best data interface and NAND timings supported by
- * the chip and the driver.
- * First tries to retrieve supported timing modes from ONFI information,
- * and if the NAND chip does not support ONFI, relies on the
- * ->onfi_timing_mode_default specified in the nand_ids table.
- *
- * Returns 0 for success or negative error code otherwise.
- */
-static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-
-	if (!chip->setup_data_interface)
-		return 0;
-
-	/*
-	 * Ensure the timing mode has been changed on the chip side
-	 * before changing timings on the controller side.
-	 */
-	if (chip->onfi_version &&
-	    (le16_to_cpu(chip->onfi_params.opt_cmd) &
-	     ONFI_OPT_CMD_SET_GET_FEATURES)) {
-		u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
-			chip->onfi_timing_mode_default,
-		};
-
-		ret = chip->onfi_set_features(mtd, chip,
-				ONFI_FEATURE_ADDR_TIMING_MODE,
-				tmode_param);
-		if (ret)
-			goto err;
-	}
-
-	ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
-err:
-	return ret;
-}
-
-/**
- * nand_init_data_interface - find the best data interface and timings
- * @chip: The NAND chip
- *
- * Find the best data interface and NAND timings supported by the chip
- * and the driver.
- * First tries to retrieve supported timing modes from ONFI information,
- * and if the NAND chip does not support ONFI, relies on the
- * ->onfi_timing_mode_default specified in the nand_ids table. After this
- * function nand_chip->data_interface is initialized with the best timing mode
- * available.
- *
- * Returns 0 for success or negative error code otherwise.
- */
-static int nand_init_data_interface(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int modes, mode, ret;
-
-	if (!chip->setup_data_interface)
-		return 0;
-
-	/*
-	 * First try to identify the best timings from ONFI parameters and
-	 * if the NAND does not support ONFI, fallback to the default ONFI
-	 * timing mode.
-	 */
-	modes = onfi_get_async_timing_mode(chip);
-	if (modes == ONFI_TIMING_MODE_UNKNOWN) {
-		if (!chip->onfi_timing_mode_default)
-			return 0;
-
-		modes = GENMASK(chip->onfi_timing_mode_default, 0);
-	}
-
-
-	for (mode = fls(modes) - 1; mode >= 0; mode--) {
-		ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
-		if (ret)
-			continue;
-
-		/*
-		 * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
-		 * controller supports the requested timings.
-		 */
-		ret = chip->setup_data_interface(mtd,
-						 NAND_DATA_IFACE_CHECK_ONLY,
-						 &chip->data_interface);
-		if (!ret) {
-			chip->onfi_timing_mode_default = mode;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * nand_fill_column_cycles - fill the column cycles of an address
- * @chip: The NAND chip
- * @addrs: Array of address cycles to fill
- * @offset_in_page: The offset in the page
- *
- * Fills the first or the first two bytes of the @addrs field depending
- * on the NAND bus width and the page size.
- *
- * Returns the number of cycles needed to encode the column, or a negative
- * error code in case one of the arguments is invalid.
- */
-static int nand_fill_column_cycles(struct nand_chip *chip, u8 *addrs,
-				   unsigned int offset_in_page)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	/* Make sure the offset is less than the actual page size. */
-	if (offset_in_page > mtd->writesize + mtd->oobsize)
-		return -EINVAL;
-
-	/*
-	 * On small page NANDs, there's a dedicated command to access the OOB
-	 * area, and the column address is relative to the start of the OOB
-	 * area, not the start of the page. Asjust the address accordingly.
-	 */
-	if (mtd->writesize <= 512 && offset_in_page >= mtd->writesize)
-		offset_in_page -= mtd->writesize;
-
-	/*
-	 * The offset in page is expressed in bytes, if the NAND bus is 16-bit
-	 * wide, then it must be divided by 2.
-	 */
-	if (chip->options & NAND_BUSWIDTH_16) {
-		if (WARN_ON(offset_in_page % 2))
-			return -EINVAL;
-
-		offset_in_page /= 2;
-	}
-
-	addrs[0] = offset_in_page;
-
-	/*
-	 * Small page NANDs use 1 cycle for the columns, while large page NANDs
-	 * need 2
-	 */
-	if (mtd->writesize <= 512)
-		return 1;
-
-	addrs[1] = offset_in_page >> 8;
-
-	return 2;
-}
-
-static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
-				     unsigned int offset_in_page, void *buf,
-				     unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const struct nand_sdr_timings *sdr =
-		nand_get_sdr_timings(&chip->data_interface);
-	u8 addrs[4];
-	struct nand_op_instr instrs[] = {
-		NAND_OP_CMD(NAND_CMD_READ0, 0),
-		NAND_OP_ADDR(3, addrs, PSEC_TO_NSEC(sdr->tWB_max)),
-		NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
-				 PSEC_TO_NSEC(sdr->tRR_min)),
-		NAND_OP_DATA_IN(len, buf, 0),
-	};
-	struct nand_operation op = NAND_OPERATION(instrs);
-	int ret;
-
-	/* Drop the DATA_IN instruction if len is set to 0. */
-	if (!len)
-		op.ninstrs--;
-
-	if (offset_in_page >= mtd->writesize)
-		instrs[0].ctx.cmd.opcode = NAND_CMD_READOOB;
-	else if (offset_in_page >= 256 &&
-		 !(chip->options & NAND_BUSWIDTH_16))
-		instrs[0].ctx.cmd.opcode = NAND_CMD_READ1;
-
-	ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
-	if (ret < 0)
-		return ret;
-
-	addrs[1] = page;
-	addrs[2] = page >> 8;
-
-	if (chip->options & NAND_ROW_ADDR_3) {
-		addrs[3] = page >> 16;
-		instrs[1].ctx.addr.naddrs++;
-	}
-
-	return nand_exec_op(chip, &op);
-}
-
-static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
-				     unsigned int offset_in_page, void *buf,
-				     unsigned int len)
-{
-	const struct nand_sdr_timings *sdr =
-		nand_get_sdr_timings(&chip->data_interface);
-	u8 addrs[5];
-	struct nand_op_instr instrs[] = {
-		NAND_OP_CMD(NAND_CMD_READ0, 0),
-		NAND_OP_ADDR(4, addrs, 0),
-		NAND_OP_CMD(NAND_CMD_READSTART, PSEC_TO_NSEC(sdr->tWB_max)),
-		NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
-				 PSEC_TO_NSEC(sdr->tRR_min)),
-		NAND_OP_DATA_IN(len, buf, 0),
-	};
-	struct nand_operation op = NAND_OPERATION(instrs);
-	int ret;
-
-	/* Drop the DATA_IN instruction if len is set to 0. */
-	if (!len)
-		op.ninstrs--;
-
-	ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
-	if (ret < 0)
-		return ret;
-
-	addrs[2] = page;
-	addrs[3] = page >> 8;
-
-	if (chip->options & NAND_ROW_ADDR_3) {
-		addrs[4] = page >> 16;
-		instrs[1].ctx.addr.naddrs++;
-	}
-
-	return nand_exec_op(chip, &op);
-}
-
-/**
- * nand_read_page_op - Do a READ PAGE operation
- * @chip: The NAND chip
- * @page: page to read
- * @offset_in_page: offset within the page
- * @buf: buffer used to store the data
- * @len: length of the buffer
- *
- * This function issues a READ PAGE operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_read_page_op(struct nand_chip *chip, unsigned int page,
-		      unsigned int offset_in_page, void *buf, unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-		return -EINVAL;
-
-	if (chip->exec_op) {
-		if (mtd->writesize > 512)
-			return nand_lp_exec_read_page_op(chip, page,
-							 offset_in_page, buf,
-							 len);
-
-		return nand_sp_exec_read_page_op(chip, page, offset_in_page,
-						 buf, len);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
-	if (len)
-		chip->read_buf(mtd, buf, len);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_read_page_op);
-
-/**
- * nand_read_param_page_op - Do a READ PARAMETER PAGE operation
- * @chip: The NAND chip
- * @page: parameter page to read
- * @buf: buffer used to store the data
- * @len: length of the buffer
- *
- * This function issues a READ PARAMETER PAGE operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
-				   unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int i;
-	u8 *p = buf;
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_PARAM, 0),
-			NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)),
-			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
-					 PSEC_TO_NSEC(sdr->tRR_min)),
-			NAND_OP_8BIT_DATA_IN(len, buf, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		/* Drop the DATA_IN instruction if len is set to 0. */
-		if (!len)
-			op.ninstrs--;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
-	for (i = 0; i < len; i++)
-		p[i] = chip->read_byte(mtd);
-
-	return 0;
-}
-
-/**
- * nand_change_read_column_op - Do a CHANGE READ COLUMN operation
- * @chip: The NAND chip
- * @offset_in_page: offset within the page
- * @buf: buffer used to store the data
- * @len: length of the buffer
- * @force_8bit: force 8-bit bus access
- *
- * This function issues a CHANGE READ COLUMN operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_change_read_column_op(struct nand_chip *chip,
-			       unsigned int offset_in_page, void *buf,
-			       unsigned int len, bool force_8bit)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-		return -EINVAL;
-
-	/* Small page NANDs do not support column change. */
-	if (mtd->writesize <= 512)
-		return -ENOTSUPP;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		u8 addrs[2] = {};
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_RNDOUT, 0),
-			NAND_OP_ADDR(2, addrs, 0),
-			NAND_OP_CMD(NAND_CMD_RNDOUTSTART,
-				    PSEC_TO_NSEC(sdr->tCCS_min)),
-			NAND_OP_DATA_IN(len, buf, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-		int ret;
-
-		ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
-		if (ret < 0)
-			return ret;
-
-		/* Drop the DATA_IN instruction if len is set to 0. */
-		if (!len)
-			op.ninstrs--;
-
-		instrs[3].ctx.data.force_8bit = force_8bit;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
-	if (len)
-		chip->read_buf(mtd, buf, len);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_change_read_column_op);
-
-/**
- * nand_read_oob_op - Do a READ OOB operation
- * @chip: The NAND chip
- * @page: page to read
- * @offset_in_oob: offset within the OOB area
- * @buf: buffer used to store the data
- * @len: length of the buffer
- *
- * This function issues a READ OOB operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
-		     unsigned int offset_in_oob, void *buf, unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (offset_in_oob + len > mtd->oobsize)
-		return -EINVAL;
-
-	if (chip->exec_op)
-		return nand_read_page_op(chip, page,
-					 mtd->writesize + offset_in_oob,
-					 buf, len);
-
-	chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
-	if (len)
-		chip->read_buf(mtd, buf, len);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_read_oob_op);
-
-static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
-				  unsigned int offset_in_page, const void *buf,
-				  unsigned int len, bool prog)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const struct nand_sdr_timings *sdr =
-		nand_get_sdr_timings(&chip->data_interface);
-	u8 addrs[5] = {};
-	struct nand_op_instr instrs[] = {
-		/*
-		 * The first instruction will be dropped if we're dealing
-		 * with a large page NAND and adjusted if we're dealing
-		 * with a small page NAND and the page offset is > 255.
-		 */
-		NAND_OP_CMD(NAND_CMD_READ0, 0),
-		NAND_OP_CMD(NAND_CMD_SEQIN, 0),
-		NAND_OP_ADDR(0, addrs, PSEC_TO_NSEC(sdr->tADL_min)),
-		NAND_OP_DATA_OUT(len, buf, 0),
-		NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)),
-		NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
-	};
-	struct nand_operation op = NAND_OPERATION(instrs);
-	int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
-	int ret;
-	u8 status;
-
-	if (naddrs < 0)
-		return naddrs;
-
-	addrs[naddrs++] = page;
-	addrs[naddrs++] = page >> 8;
-	if (chip->options & NAND_ROW_ADDR_3)
-		addrs[naddrs++] = page >> 16;
-
-	instrs[2].ctx.addr.naddrs = naddrs;
-
-	/* Drop the last two instructions if we're not programming the page. */
-	if (!prog) {
-		op.ninstrs -= 2;
-		/* Also drop the DATA_OUT instruction if empty. */
-		if (!len)
-			op.ninstrs--;
-	}
-
-	if (mtd->writesize <= 512) {
-		/*
-		 * Small pages need some more tweaking: we have to adjust the
-		 * first instruction depending on the page offset we're trying
-		 * to access.
-		 */
-		if (offset_in_page >= mtd->writesize)
-			instrs[0].ctx.cmd.opcode = NAND_CMD_READOOB;
-		else if (offset_in_page >= 256 &&
-			 !(chip->options & NAND_BUSWIDTH_16))
-			instrs[0].ctx.cmd.opcode = NAND_CMD_READ1;
-	} else {
-		/*
-		 * Drop the first command if we're dealing with a large page
-		 * NAND.
-		 */
-		op.instrs++;
-		op.ninstrs--;
-	}
-
-	ret = nand_exec_op(chip, &op);
-	if (!prog || ret)
-		return ret;
-
-	ret = nand_status_op(chip, &status);
-	if (ret)
-		return ret;
-
-	return status;
-}
-
-/**
- * nand_prog_page_begin_op - starts a PROG PAGE operation
- * @chip: The NAND chip
- * @page: page to write
- * @offset_in_page: offset within the page
- * @buf: buffer containing the data to write to the page
- * @len: length of the buffer
- *
- * This function issues the first half of a PROG PAGE operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
-			    unsigned int offset_in_page, const void *buf,
-			    unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-		return -EINVAL;
-
-	if (chip->exec_op)
-		return nand_exec_prog_page_op(chip, page, offset_in_page, buf,
-					      len, false);
-
-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
-
-	if (buf)
-		chip->write_buf(mtd, buf, len);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
-
-/**
- * nand_prog_page_end_op - ends a PROG PAGE operation
- * @chip: The NAND chip
- *
- * This function issues the second half of a PROG PAGE operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_prog_page_end_op(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-	u8 status;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_PAGEPROG,
-				    PSEC_TO_NSEC(sdr->tWB_max)),
-			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		ret = nand_exec_op(chip, &op);
-		if (ret)
-			return ret;
-
-		ret = nand_status_op(chip, &status);
-		if (ret)
-			return ret;
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-		ret = chip->waitfunc(mtd, chip);
-		if (ret < 0)
-			return ret;
-
-		status = ret;
-	}
-
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_prog_page_end_op);
-
-/**
- * nand_prog_page_op - Do a full PROG PAGE operation
- * @chip: The NAND chip
- * @page: page to write
- * @offset_in_page: offset within the page
- * @buf: buffer containing the data to write to the page
- * @len: length of the buffer
- *
- * This function issues a full PROG PAGE operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
-		      unsigned int offset_in_page, const void *buf,
-		      unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int status;
-
-	if (!len || !buf)
-		return -EINVAL;
-
-	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-		return -EINVAL;
-
-	if (chip->exec_op) {
-		status = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
-						len, true);
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
-		chip->write_buf(mtd, buf, len);
-		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-		status = chip->waitfunc(mtd, chip);
-	}
-
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_prog_page_op);
-
-/**
- * nand_change_write_column_op - Do a CHANGE WRITE COLUMN operation
- * @chip: The NAND chip
- * @offset_in_page: offset within the page
- * @buf: buffer containing the data to send to the NAND
- * @len: length of the buffer
- * @force_8bit: force 8-bit bus access
- *
- * This function issues a CHANGE WRITE COLUMN operation.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_change_write_column_op(struct nand_chip *chip,
-				unsigned int offset_in_page,
-				const void *buf, unsigned int len,
-				bool force_8bit)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
-		return -EINVAL;
-
-	/* Small page NANDs do not support column change. */
-	if (mtd->writesize <= 512)
-		return -ENOTSUPP;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		u8 addrs[2];
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_RNDIN, 0),
-			NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)),
-			NAND_OP_DATA_OUT(len, buf, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-		int ret;
-
-		ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
-		if (ret < 0)
-			return ret;
-
-		instrs[2].ctx.data.force_8bit = force_8bit;
-
-		/* Drop the DATA_OUT instruction if len is set to 0. */
-		if (!len)
-			op.ninstrs--;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
-	if (len)
-		chip->write_buf(mtd, buf, len);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_change_write_column_op);
-
-/**
- * nand_readid_op - Do a READID operation
- * @chip: The NAND chip
- * @addr: address cycle to pass after the READID command
- * @buf: buffer used to store the ID
- * @len: length of the buffer
- *
- * This function sends a READID command and reads back the ID returned by the
- * NAND.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
-		   unsigned int len)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int i;
-	u8 *id = buf;
-
-	if (len && !buf)
-		return -EINVAL;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_READID, 0),
-			NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)),
-			NAND_OP_8BIT_DATA_IN(len, buf, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		/* Drop the DATA_IN instruction if len is set to 0. */
-		if (!len)
-			op.ninstrs--;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
-
-	for (i = 0; i < len; i++)
-		id[i] = chip->read_byte(mtd);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_readid_op);
-
-/**
- * nand_status_op - Do a STATUS operation
- * @chip: The NAND chip
- * @status: out variable to store the NAND status
- *
- * This function sends a STATUS command and reads back the status returned by
- * the NAND.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_status_op(struct nand_chip *chip, u8 *status)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_STATUS,
-				    PSEC_TO_NSEC(sdr->tADL_min)),
-			NAND_OP_8BIT_DATA_IN(1, status, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		if (!status)
-			op.ninstrs--;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-	if (status)
-		*status = chip->read_byte(mtd);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_status_op);
-
-/**
- * nand_exit_status_op - Exit a STATUS operation
- * @chip: The NAND chip
- *
- * This function sends a READ0 command to cancel the effect of the STATUS
- * command to avoid reading only the status until a new read command is sent.
- *
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_exit_status_op(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (chip->exec_op) {
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_READ0, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_exit_status_op);
-
-/**
- * nand_erase_op - Do an erase operation
- * @chip: The NAND chip
- * @eraseblock: block to erase
- *
- * This function sends an ERASE command and waits for the NAND to be ready
- * before returning.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	unsigned int page = eraseblock <<
-			    (chip->phys_erase_shift - chip->page_shift);
-	int ret;
-	u8 status;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		u8 addrs[3] = {	page, page >> 8, page >> 16 };
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_ERASE1, 0),
-			NAND_OP_ADDR(2, addrs, 0),
-			NAND_OP_CMD(NAND_CMD_ERASE2,
-				    PSEC_TO_MSEC(sdr->tWB_max)),
-			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		if (chip->options & NAND_ROW_ADDR_3)
-			instrs[1].ctx.addr.naddrs++;
-
-		ret = nand_exec_op(chip, &op);
-		if (ret)
-			return ret;
-
-		ret = nand_status_op(chip, &status);
-		if (ret)
-			return ret;
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
-		chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
-
-		ret = chip->waitfunc(mtd, chip);
-		if (ret < 0)
-			return ret;
-
-		status = ret;
-	}
-
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_erase_op);
-
-/**
- * nand_set_features_op - Do a SET FEATURES operation
- * @chip: The NAND chip
- * @feature: feature id
- * @data: 4 bytes of data
- *
- * This function sends a SET FEATURES command and waits for the NAND to be
- * ready before returning.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-static int nand_set_features_op(struct nand_chip *chip, u8 feature,
-				const void *data)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const u8 *params = data;
-	int i, ret;
-	u8 status;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0),
-			NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)),
-			NAND_OP_8BIT_DATA_OUT(ONFI_SUBFEATURE_PARAM_LEN, data,
-					      PSEC_TO_NSEC(sdr->tWB_max)),
-			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		ret = nand_exec_op(chip, &op);
-		if (ret)
-			return ret;
-
-		ret = nand_status_op(chip, &status);
-		if (ret)
-			return ret;
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
-		for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-			chip->write_byte(mtd, params[i]);
-
-		ret = chip->waitfunc(mtd, chip);
-		if (ret < 0)
-			return ret;
-
-		status = ret;
-	}
-
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
-
-	return 0;
-}
-
-/**
- * nand_get_features_op - Do a GET FEATURES operation
- * @chip: The NAND chip
- * @feature: feature id
- * @data: 4 bytes of data
- *
- * This function sends a GET FEATURES command and waits for the NAND to be
- * ready before returning.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-static int nand_get_features_op(struct nand_chip *chip, u8 feature,
-				void *data)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 *params = data;
-	int i;
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0),
-			NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)),
-			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max),
-					 PSEC_TO_NSEC(sdr->tRR_min)),
-			NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN,
-					     data, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
-	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-		params[i] = chip->read_byte(mtd);
-
-	return 0;
-}
-
-/**
- * nand_reset_op - Do a reset operation
- * @chip: The NAND chip
- *
- * This function sends a RESET command and waits for the NAND to be ready
- * before returning.
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_reset_op(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (chip->exec_op) {
-		const struct nand_sdr_timings *sdr =
-			nand_get_sdr_timings(&chip->data_interface);
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)),
-			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_reset_op);
-
-/**
- * nand_read_data_op - Read data from the NAND
- * @chip: The NAND chip
- * @buf: buffer used to store the data
- * @len: length of the buffer
- * @force_8bit: force 8-bit bus access
- *
- * This function does a raw data read on the bus. Usually used after launching
- * another NAND operation like nand_read_page_op().
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
-		      bool force_8bit)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (!len || !buf)
-		return -EINVAL;
-
-	if (chip->exec_op) {
-		struct nand_op_instr instrs[] = {
-			NAND_OP_DATA_IN(len, buf, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		instrs[0].ctx.data.force_8bit = force_8bit;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	if (force_8bit) {
-		u8 *p = buf;
-		unsigned int i;
-
-		for (i = 0; i < len; i++)
-			p[i] = chip->read_byte(mtd);
-	} else {
-		chip->read_buf(mtd, buf, len);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_read_data_op);
-
-/**
- * nand_write_data_op - Write data from the NAND
- * @chip: The NAND chip
- * @buf: buffer containing the data to send on the bus
- * @len: length of the buffer
- * @force_8bit: force 8-bit bus access
- *
- * This function does a raw data write on the bus. Usually used after launching
- * another NAND operation like nand_write_page_begin_op().
- * This function does not select/unselect the CS line.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_write_data_op(struct nand_chip *chip, const void *buf,
-		       unsigned int len, bool force_8bit)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (!len || !buf)
-		return -EINVAL;
-
-	if (chip->exec_op) {
-		struct nand_op_instr instrs[] = {
-			NAND_OP_DATA_OUT(len, buf, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		instrs[0].ctx.data.force_8bit = force_8bit;
-
-		return nand_exec_op(chip, &op);
-	}
-
-	if (force_8bit) {
-		const u8 *p = buf;
-		unsigned int i;
-
-		for (i = 0; i < len; i++)
-			chip->write_byte(mtd, p[i]);
-	} else {
-		chip->write_buf(mtd, buf, len);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_write_data_op);
-
-/**
- * struct nand_op_parser_ctx - Context used by the parser
- * @instrs: array of all the instructions that must be addressed
- * @ninstrs: length of the @instrs array
- * @subop: Sub-operation to be passed to the NAND controller
- *
- * This structure is used by the core to split NAND operations into
- * sub-operations that can be handled by the NAND controller.
- */
-struct nand_op_parser_ctx {
-	const struct nand_op_instr *instrs;
-	unsigned int ninstrs;
-	struct nand_subop subop;
-};
-
-/**
- * nand_op_parser_must_split_instr - Checks if an instruction must be split
- * @pat: the parser pattern element that matches @instr
- * @instr: pointer to the instruction to check
- * @start_offset: this is an in/out parameter. If @instr has already been
- *		  split, then @start_offset is the offset from which to start
- *		  (either an address cycle or an offset in the data buffer).
- *		  Conversely, if the function returns true (ie. instr must be
- *		  split), this parameter is updated to point to the first
- *		  data/address cycle that has not been taken care of.
- *
- * Some NAND controllers are limited and cannot send X address cycles with a
- * unique operation, or cannot read/write more than Y bytes at the same time.
- * In this case, split the instruction that does not fit in a single
- * controller-operation into two or more chunks.
- *
- * Returns true if the instruction must be split, false otherwise.
- * The @start_offset parameter is also updated to the offset at which the next
- * bundle of instruction must start (if an address or a data instruction).
- */
-static bool
-nand_op_parser_must_split_instr(const struct nand_op_parser_pattern_elem *pat,
-				const struct nand_op_instr *instr,
-				unsigned int *start_offset)
-{
-	switch (pat->type) {
-	case NAND_OP_ADDR_INSTR:
-		if (!pat->ctx.addr.maxcycles)
-			break;
-
-		if (instr->ctx.addr.naddrs - *start_offset >
-		    pat->ctx.addr.maxcycles) {
-			*start_offset += pat->ctx.addr.maxcycles;
-			return true;
-		}
-		break;
-
-	case NAND_OP_DATA_IN_INSTR:
-	case NAND_OP_DATA_OUT_INSTR:
-		if (!pat->ctx.data.maxlen)
-			break;
-
-		if (instr->ctx.data.len - *start_offset >
-		    pat->ctx.data.maxlen) {
-			*start_offset += pat->ctx.data.maxlen;
-			return true;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	return false;
-}
-
-/**
- * nand_op_parser_match_pat - Checks if a pattern matches the instructions
- *			      remaining in the parser context
- * @pat: the pattern to test
- * @ctx: the parser context structure to match with the pattern @pat
- *
- * Check if @pat matches the set or a sub-set of instructions remaining in @ctx.
- * Returns true if this is the case, false ortherwise. When true is returned,
- * @ctx->subop is updated with the set of instructions to be passed to the
- * controller driver.
- */
-static bool
-nand_op_parser_match_pat(const struct nand_op_parser_pattern *pat,
-			 struct nand_op_parser_ctx *ctx)
-{
-	unsigned int instr_offset = ctx->subop.first_instr_start_off;
-	const struct nand_op_instr *end = ctx->instrs + ctx->ninstrs;
-	const struct nand_op_instr *instr = ctx->subop.instrs;
-	unsigned int i, ninstrs;
-
-	for (i = 0, ninstrs = 0; i < pat->nelems && instr < end; i++) {
-		/*
-		 * The pattern instruction does not match the operation
-		 * instruction. If the instruction is marked optional in the
-		 * pattern definition, we skip the pattern element and continue
-		 * to the next one. If the element is mandatory, there's no
-		 * match and we can return false directly.
-		 */
-		if (instr->type != pat->elems[i].type) {
-			if (!pat->elems[i].optional)
-				return false;
-
-			continue;
-		}
-
-		/*
-		 * Now check the pattern element constraints. If the pattern is
-		 * not able to handle the whole instruction in a single step,
-		 * we have to split it.
-		 * The last_instr_end_off value comes back updated to point to
-		 * the position where we have to split the instruction (the
-		 * start of the next subop chunk).
-		 */
-		if (nand_op_parser_must_split_instr(&pat->elems[i], instr,
-						    &instr_offset)) {
-			ninstrs++;
-			i++;
-			break;
-		}
-
-		instr++;
-		ninstrs++;
-		instr_offset = 0;
-	}
-
-	/*
-	 * This can happen if all instructions of a pattern are optional.
-	 * Still, if there's not at least one instruction handled by this
-	 * pattern, this is not a match, and we should try the next one (if
-	 * any).
-	 */
-	if (!ninstrs)
-		return false;
-
-	/*
-	 * We had a match on the pattern head, but the pattern may be longer
-	 * than the instructions we're asked to execute. We need to make sure
-	 * there's no mandatory elements in the pattern tail.
-	 */
-	for (; i < pat->nelems; i++) {
-		if (!pat->elems[i].optional)
-			return false;
-	}
-
-	/*
-	 * We have a match: update the subop structure accordingly and return
-	 * true.
-	 */
-	ctx->subop.ninstrs = ninstrs;
-	ctx->subop.last_instr_end_off = instr_offset;
-
-	return true;
-}
-
-#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
-static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
-{
-	const struct nand_op_instr *instr;
-	char *prefix = "      ";
-	unsigned int i;
-
-	pr_debug("executing subop:\n");
-
-	for (i = 0; i < ctx->ninstrs; i++) {
-		instr = &ctx->instrs[i];
-
-		if (instr == &ctx->subop.instrs[0])
-			prefix = "    ->";
-
-		switch (instr->type) {
-		case NAND_OP_CMD_INSTR:
-			pr_debug("%sCMD      [0x%02x]\n", prefix,
-				 instr->ctx.cmd.opcode);
-			break;
-		case NAND_OP_ADDR_INSTR:
-			pr_debug("%sADDR     [%d cyc: %*ph]\n", prefix,
-				 instr->ctx.addr.naddrs,
-				 instr->ctx.addr.naddrs < 64 ?
-				 instr->ctx.addr.naddrs : 64,
-				 instr->ctx.addr.addrs);
-			break;
-		case NAND_OP_DATA_IN_INSTR:
-			pr_debug("%sDATA_IN  [%d B%s]\n", prefix,
-				 instr->ctx.data.len,
-				 instr->ctx.data.force_8bit ?
-				 ", force 8-bit" : "");
-			break;
-		case NAND_OP_DATA_OUT_INSTR:
-			pr_debug("%sDATA_OUT [%d B%s]\n", prefix,
-				 instr->ctx.data.len,
-				 instr->ctx.data.force_8bit ?
-				 ", force 8-bit" : "");
-			break;
-		case NAND_OP_WAITRDY_INSTR:
-			pr_debug("%sWAITRDY  [max %d ms]\n", prefix,
-				 instr->ctx.waitrdy.timeout_ms);
-			break;
-		}
-
-		if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1])
-			prefix = "      ";
-	}
-}
-#else
-static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
-{
-	/* NOP */
-}
-#endif
-
-/**
- * nand_op_parser_exec_op - exec_op parser
- * @chip: the NAND chip
- * @parser: patterns description provided by the controller driver
- * @op: the NAND operation to address
- * @check_only: when true, the function only checks if @op can be handled but
- *		does not execute the operation
- *
- * Helper function designed to ease integration of NAND controller drivers that
- * only support a limited set of instruction sequences. The supported sequences
- * are described in @parser, and the framework takes care of splitting @op into
- * multiple sub-operations (if required) and pass them back to the ->exec()
- * callback of the matching pattern if @check_only is set to false.
- *
- * NAND controller drivers should call this function from their own ->exec_op()
- * implementation.
- *
- * Returns 0 on success, a negative error code otherwise. A failure can be
- * caused by an unsupported operation (none of the supported patterns is able
- * to handle the requested operation), or an error returned by one of the
- * matching pattern->exec() hook.
- */
-int nand_op_parser_exec_op(struct nand_chip *chip,
-			   const struct nand_op_parser *parser,
-			   const struct nand_operation *op, bool check_only)
-{
-	struct nand_op_parser_ctx ctx = {
-		.subop.instrs = op->instrs,
-		.instrs = op->instrs,
-		.ninstrs = op->ninstrs,
-	};
-	unsigned int i;
-
-	while (ctx.subop.instrs < op->instrs + op->ninstrs) {
-		int ret;
-
-		for (i = 0; i < parser->npatterns; i++) {
-			const struct nand_op_parser_pattern *pattern;
-
-			pattern = &parser->patterns[i];
-			if (!nand_op_parser_match_pat(pattern, &ctx))
-				continue;
-
-			nand_op_parser_trace(&ctx);
-
-			if (check_only)
-				break;
-
-			ret = pattern->exec(chip, &ctx.subop);
-			if (ret)
-				return ret;
-
-			break;
-		}
-
-		if (i == parser->npatterns) {
-			pr_debug("->exec_op() parser: pattern not found!\n");
-			return -ENOTSUPP;
-		}
-
-		/*
-		 * Update the context structure by pointing to the start of the
-		 * next subop.
-		 */
-		ctx.subop.instrs = ctx.subop.instrs + ctx.subop.ninstrs;
-		if (ctx.subop.last_instr_end_off)
-			ctx.subop.instrs -= 1;
-
-		ctx.subop.first_instr_start_off = ctx.subop.last_instr_end_off;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_op_parser_exec_op);
-
-static bool nand_instr_is_data(const struct nand_op_instr *instr)
-{
-	return instr && (instr->type == NAND_OP_DATA_IN_INSTR ||
-			 instr->type == NAND_OP_DATA_OUT_INSTR);
-}
-
-static bool nand_subop_instr_is_valid(const struct nand_subop *subop,
-				      unsigned int instr_idx)
-{
-	return subop && instr_idx < subop->ninstrs;
-}
-
-static int nand_subop_get_start_off(const struct nand_subop *subop,
-				    unsigned int instr_idx)
-{
-	if (instr_idx)
-		return 0;
-
-	return subop->first_instr_start_off;
-}
-
-/**
- * nand_subop_get_addr_start_off - Get the start offset in an address array
- * @subop: The entire sub-operation
- * @instr_idx: Index of the instruction inside the sub-operation
- *
- * During driver development, one could be tempted to directly use the
- * ->addr.addrs field of address instructions. This is wrong as address
- * instructions might be split.
- *
- * Given an address instruction, returns the offset of the first cycle to issue.
- */
-int nand_subop_get_addr_start_off(const struct nand_subop *subop,
-				  unsigned int instr_idx)
-{
-	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-	    subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
-		return -EINVAL;
-
-	return nand_subop_get_start_off(subop, instr_idx);
-}
-EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off);
-
-/**
- * nand_subop_get_num_addr_cyc - Get the remaining address cycles to assert
- * @subop: The entire sub-operation
- * @instr_idx: Index of the instruction inside the sub-operation
- *
- * During driver development, one could be tempted to directly use the
- * ->addr->naddrs field of a data instruction. This is wrong as instructions
- * might be split.
- *
- * Given an address instruction, returns the number of address cycle to issue.
- */
-int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
-				unsigned int instr_idx)
-{
-	int start_off, end_off;
-
-	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-	    subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
-		return -EINVAL;
-
-	start_off = nand_subop_get_addr_start_off(subop, instr_idx);
-
-	if (instr_idx == subop->ninstrs - 1 &&
-	    subop->last_instr_end_off)
-		end_off = subop->last_instr_end_off;
-	else
-		end_off = subop->instrs[instr_idx].ctx.addr.naddrs;
-
-	return end_off - start_off;
-}
-EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc);
-
-/**
- * nand_subop_get_data_start_off - Get the start offset in a data array
- * @subop: The entire sub-operation
- * @instr_idx: Index of the instruction inside the sub-operation
- *
- * During driver development, one could be tempted to directly use the
- * ->data->buf.{in,out} field of data instructions. This is wrong as data
- * instructions might be split.
- *
- * Given a data instruction, returns the offset to start from.
- */
-int nand_subop_get_data_start_off(const struct nand_subop *subop,
-				  unsigned int instr_idx)
-{
-	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-	    !nand_instr_is_data(&subop->instrs[instr_idx]))
-		return -EINVAL;
-
-	return nand_subop_get_start_off(subop, instr_idx);
-}
-EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off);
-
-/**
- * nand_subop_get_data_len - Get the number of bytes to retrieve
- * @subop: The entire sub-operation
- * @instr_idx: Index of the instruction inside the sub-operation
- *
- * During driver development, one could be tempted to directly use the
- * ->data->len field of a data instruction. This is wrong as data instructions
- * might be split.
- *
- * Returns the length of the chunk of data to send/receive.
- */
-int nand_subop_get_data_len(const struct nand_subop *subop,
-			    unsigned int instr_idx)
-{
-	int start_off = 0, end_off;
-
-	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-	    !nand_instr_is_data(&subop->instrs[instr_idx]))
-		return -EINVAL;
-
-	start_off = nand_subop_get_data_start_off(subop, instr_idx);
-
-	if (instr_idx == subop->ninstrs - 1 &&
-	    subop->last_instr_end_off)
-		end_off = subop->last_instr_end_off;
-	else
-		end_off = subop->instrs[instr_idx].ctx.data.len;
-
-	return end_off - start_off;
-}
-EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
-
-/**
- * nand_reset - Reset and initialize a NAND device
- * @chip: The NAND chip
- * @chipnr: Internal die id
- *
- * Save the timings data structure, then apply SDR timings mode 0 (see
- * nand_reset_data_interface for details), do the reset operation, and
- * apply back the previous timings.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int nand_reset(struct nand_chip *chip, int chipnr)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_data_interface saved_data_intf = chip->data_interface;
-	int ret;
-
-	ret = nand_reset_data_interface(chip, chipnr);
-	if (ret)
-		return ret;
-
-	/*
-	 * The CS line has to be released before we can apply the new NAND
-	 * interface settings, hence this weird ->select_chip() dance.
-	 */
-	chip->select_chip(mtd, chipnr);
-	ret = nand_reset_op(chip);
-	chip->select_chip(mtd, -1);
-	if (ret)
-		return ret;
-
-	chip->select_chip(mtd, chipnr);
-	chip->data_interface = saved_data_intf;
-	ret = nand_setup_data_interface(chip, chipnr);
-	chip->select_chip(mtd, -1);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_reset);
-
-/**
- * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
- * @buf: buffer to test
- * @len: buffer length
- * @bitflips_threshold: maximum number of bitflips
- *
- * Check if a buffer contains only 0xff, which means the underlying region
- * has been erased and is ready to be programmed.
- * The bitflips_threshold specify the maximum number of bitflips before
- * considering the region is not erased.
- * Note: The logic of this function has been extracted from the memweight
- * implementation, except that nand_check_erased_buf function exit before
- * testing the whole buffer if the number of bitflips exceed the
- * bitflips_threshold value.
- *
- * Returns a positive number of bitflips less than or equal to
- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
- * threshold.
- */
-static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
-{
-	const unsigned char *bitmap = buf;
-	int bitflips = 0;
-	int weight;
-
-	for (; len && ((uintptr_t)bitmap) % sizeof(long);
-	     len--, bitmap++) {
-		weight = hweight8(*bitmap);
-		bitflips += BITS_PER_BYTE - weight;
-		if (unlikely(bitflips > bitflips_threshold))
-			return -EBADMSG;
-	}
-
-	for (; len >= sizeof(long);
-	     len -= sizeof(long), bitmap += sizeof(long)) {
-		unsigned long d = *((unsigned long *)bitmap);
-		if (d == ~0UL)
-			continue;
-		weight = hweight_long(d);
-		bitflips += BITS_PER_LONG - weight;
-		if (unlikely(bitflips > bitflips_threshold))
-			return -EBADMSG;
-	}
-
-	for (; len > 0; len--, bitmap++) {
-		weight = hweight8(*bitmap);
-		bitflips += BITS_PER_BYTE - weight;
-		if (unlikely(bitflips > bitflips_threshold))
-			return -EBADMSG;
-	}
-
-	return bitflips;
-}
-
-/**
- * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
- *				 0xff data
- * @data: data buffer to test
- * @datalen: data length
- * @ecc: ECC buffer
- * @ecclen: ECC length
- * @extraoob: extra OOB buffer
- * @extraooblen: extra OOB length
- * @bitflips_threshold: maximum number of bitflips
- *
- * Check if a data buffer and its associated ECC and OOB data contains only
- * 0xff pattern, which means the underlying region has been erased and is
- * ready to be programmed.
- * The bitflips_threshold specify the maximum number of bitflips before
- * considering the region as not erased.
- *
- * Note:
- * 1/ ECC algorithms are working on pre-defined block sizes which are usually
- *    different from the NAND page size. When fixing bitflips, ECC engines will
- *    report the number of errors per chunk, and the NAND core infrastructure
- *    expect you to return the maximum number of bitflips for the whole page.
- *    This is why you should always use this function on a single chunk and
- *    not on the whole page. After checking each chunk you should update your
- *    max_bitflips value accordingly.
- * 2/ When checking for bitflips in erased pages you should not only check
- *    the payload data but also their associated ECC data, because a user might
- *    have programmed almost all bits to 1 but a few. In this case, we
- *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
- *    this case.
- * 3/ The extraoob argument is optional, and should be used if some of your OOB
- *    data are protected by the ECC engine.
- *    It could also be used if you support subpages and want to attach some
- *    extra OOB data to an ECC chunk.
- *
- * Returns a positive number of bitflips less than or equal to
- * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
- * threshold. In case of success, the passed buffers are filled with 0xff.
- */
-int nand_check_erased_ecc_chunk(void *data, int datalen,
-				void *ecc, int ecclen,
-				void *extraoob, int extraooblen,
-				int bitflips_threshold)
-{
-	int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
-
-	data_bitflips = nand_check_erased_buf(data, datalen,
-					      bitflips_threshold);
-	if (data_bitflips < 0)
-		return data_bitflips;
-
-	bitflips_threshold -= data_bitflips;
-
-	ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
-	if (ecc_bitflips < 0)
-		return ecc_bitflips;
-
-	bitflips_threshold -= ecc_bitflips;
-
-	extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
-						  bitflips_threshold);
-	if (extraoob_bitflips < 0)
-		return extraoob_bitflips;
-
-	if (data_bitflips)
-		memset(data, 0xff, datalen);
-
-	if (ecc_bitflips)
-		memset(ecc, 0xff, ecclen);
-
-	if (extraoob_bitflips)
-		memset(extraoob, 0xff, extraooblen);
-
-	return data_bitflips + ecc_bitflips + extraoob_bitflips;
-}
-EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
-
-/**
- * nand_read_page_raw - [INTERN] read raw page data without ecc
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- *
- * Not for syndrome calculating ECC controllers, which use a special oob layout.
- */
-int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-		       uint8_t *buf, int oob_required, int page)
-{
-	int ret;
-
-	ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	if (ret)
-		return ret;
-
-	if (oob_required) {
-		ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
-					false);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(nand_read_page_raw);
-
-/**
- * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- *
- * We need a special oob layout and handling even when OOB isn't used.
- */
-static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
-				       struct nand_chip *chip, uint8_t *buf,
-				       int oob_required, int page)
-{
-	int eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	uint8_t *oob = chip->oob_poi;
-	int steps, size, ret;
-
-	ret = nand_read_page_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (steps = chip->ecc.steps; steps > 0; steps--) {
-		ret = nand_read_data_op(chip, buf, eccsize, false);
-		if (ret)
-			return ret;
-
-		buf += eccsize;
-
-		if (chip->ecc.prepad) {
-			ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
-						false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.prepad;
-		}
-
-		ret = nand_read_data_op(chip, oob, eccbytes, false);
-		if (ret)
-			return ret;
-
-		oob += eccbytes;
-
-		if (chip->ecc.postpad) {
-			ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
-						false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.postpad;
-		}
-	}
-
-	size = mtd->oobsize - (oob - chip->oob_poi);
-	if (size) {
-		ret = nand_read_data_op(chip, oob, size, false);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-/**
- * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- */
-static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	int i, eccsize = chip->ecc.size, ret;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *p = buf;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	uint8_t *ecc_code = chip->ecc.code_buf;
-	unsigned int max_bitflips = 0;
-
-	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	eccsteps = chip->ecc.steps;
-	p = buf;
-
-	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		int stat;
-
-		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-	}
-	return max_bitflips;
-}
-
-/**
- * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @data_offs: offset of requested data within the page
- * @readlen: data length
- * @bufpoi: buffer to store read data
- * @page: page number to read
- */
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
-			int page)
-{
-	int start_step, end_step, num_steps, ret;
-	uint8_t *p;
-	int data_col_addr, i, gaps = 0;
-	int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
-	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
-	int index, section = 0;
-	unsigned int max_bitflips = 0;
-	struct mtd_oob_region oobregion = { };
-
-	/* Column address within the page aligned to ECC size (256bytes) */
-	start_step = data_offs / chip->ecc.size;
-	end_step = (data_offs + readlen - 1) / chip->ecc.size;
-	num_steps = end_step - start_step + 1;
-	index = start_step * chip->ecc.bytes;
-
-	/* Data size aligned to ECC ecc.size */
-	datafrag_len = num_steps * chip->ecc.size;
-	eccfrag_len = num_steps * chip->ecc.bytes;
-
-	data_col_addr = start_step * chip->ecc.size;
-	/* If we read not a page aligned data */
-	p = bufpoi + data_col_addr;
-	ret = nand_read_page_op(chip, page, data_col_addr, p, datafrag_len);
-	if (ret)
-		return ret;
-
-	/* Calculate ECC */
-	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
-		chip->ecc.calculate(mtd, p, &chip->ecc.calc_buf[i]);
-
-	/*
-	 * The performance is faster if we position offsets according to
-	 * ecc.pos. Let's make sure that there are no gaps in ECC positions.
-	 */
-	ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
-	if (ret)
-		return ret;
-
-	if (oobregion.length < eccfrag_len)
-		gaps = 1;
-
-	if (gaps) {
-		ret = nand_change_read_column_op(chip, mtd->writesize,
-						 chip->oob_poi, mtd->oobsize,
-						 false);
-		if (ret)
-			return ret;
-	} else {
-		/*
-		 * Send the command to read the particular ECC bytes take care
-		 * about buswidth alignment in read_buf.
-		 */
-		aligned_pos = oobregion.offset & ~(busw - 1);
-		aligned_len = eccfrag_len;
-		if (oobregion.offset & (busw - 1))
-			aligned_len++;
-		if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
-		    (busw - 1))
-			aligned_len++;
-
-		ret = nand_change_read_column_op(chip,
-						 mtd->writesize + aligned_pos,
-						 &chip->oob_poi[aligned_pos],
-						 aligned_len, false);
-		if (ret)
-			return ret;
-	}
-
-	ret = mtd_ooblayout_get_eccbytes(mtd, chip->ecc.code_buf,
-					 chip->oob_poi, index, eccfrag_len);
-	if (ret)
-		return ret;
-
-	p = bufpoi + data_col_addr;
-	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
-		int stat;
-
-		stat = chip->ecc.correct(mtd, p, &chip->ecc.code_buf[i],
-					 &chip->ecc.calc_buf[i]);
-		if (stat == -EBADMSG &&
-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
-			/* check for empty pages with bitflips */
-			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
-						&chip->ecc.code_buf[i],
-						chip->ecc.bytes,
-						NULL, 0,
-						chip->ecc.strength);
-		}
-
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-	}
-	return max_bitflips;
-}
-
-/**
- * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- *
- * Not for syndrome calculating ECC controllers which need a special oob layout.
- */
-static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	int i, eccsize = chip->ecc.size, ret;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *p = buf;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	uint8_t *ecc_code = chip->ecc.code_buf;
-	unsigned int max_bitflips = 0;
-
-	ret = nand_read_page_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-
-		ret = nand_read_data_op(chip, p, eccsize, false);
-		if (ret)
-			return ret;
-
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-	}
-
-	ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
-	if (ret)
-		return ret;
-
-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	eccsteps = chip->ecc.steps;
-	p = buf;
-
-	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		int stat;
-
-		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-		if (stat == -EBADMSG &&
-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
-			/* check for empty pages with bitflips */
-			stat = nand_check_erased_ecc_chunk(p, eccsize,
-						&ecc_code[i], eccbytes,
-						NULL, 0,
-						chip->ecc.strength);
-		}
-
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-	}
-	return max_bitflips;
-}
-
-/**
- * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- *
- * Hardware ECC for large page chips, require OOB to be read first. For this
- * ECC mode, the write_page method is re-used from ECC_HW. These methods
- * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
- * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
- * the data area, by overwriting the NAND manufacturer bad block markings.
- */
-static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
-	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
-{
-	int i, eccsize = chip->ecc.size, ret;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *p = buf;
-	uint8_t *ecc_code = chip->ecc.code_buf;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	unsigned int max_bitflips = 0;
-
-	/* Read the OOB area first */
-	ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-	if (ret)
-		return ret;
-
-	ret = nand_read_page_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		int stat;
-
-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-
-		ret = nand_read_data_op(chip, p, eccsize, false);
-		if (ret)
-			return ret;
-
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
-		if (stat == -EBADMSG &&
-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
-			/* check for empty pages with bitflips */
-			stat = nand_check_erased_ecc_chunk(p, eccsize,
-						&ecc_code[i], eccbytes,
-						NULL, 0,
-						chip->ecc.strength);
-		}
-
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-	}
-	return max_bitflips;
-}
-
-/**
- * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- * @oob_required: caller requires OOB data read to chip->oob_poi
- * @page: page number to read
- *
- * The hw generator calculates the error syndrome automatically. Therefore we
- * need a special oob layout and handling.
- */
-static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-				   uint8_t *buf, int oob_required, int page)
-{
-	int ret, i, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
-	uint8_t *p = buf;
-	uint8_t *oob = chip->oob_poi;
-	unsigned int max_bitflips = 0;
-
-	ret = nand_read_page_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		int stat;
-
-		chip->ecc.hwctl(mtd, NAND_ECC_READ);
-
-		ret = nand_read_data_op(chip, p, eccsize, false);
-		if (ret)
-			return ret;
-
-		if (chip->ecc.prepad) {
-			ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
-						false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.prepad;
-		}
-
-		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
-
-		ret = nand_read_data_op(chip, oob, eccbytes, false);
-		if (ret)
-			return ret;
-
-		stat = chip->ecc.correct(mtd, p, oob, NULL);
-
-		oob += eccbytes;
-
-		if (chip->ecc.postpad) {
-			ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
-						false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.postpad;
-		}
-
-		if (stat == -EBADMSG &&
-		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
-			/* check for empty pages with bitflips */
-			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
-							   oob - eccpadbytes,
-							   eccpadbytes,
-							   NULL, 0,
-							   chip->ecc.strength);
-		}
-
-		if (stat < 0) {
-			mtd->ecc_stats.failed++;
-		} else {
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max_t(unsigned int, max_bitflips, stat);
-		}
-	}
-
-	/* Calculate remaining oob bytes */
-	i = mtd->oobsize - (oob - chip->oob_poi);
-	if (i) {
-		ret = nand_read_data_op(chip, oob, i, false);
-		if (ret)
-			return ret;
-	}
-
-	return max_bitflips;
-}
-
-/**
- * nand_transfer_oob - [INTERN] Transfer oob to client buffer
- * @mtd: mtd info structure
- * @oob: oob destination address
- * @ops: oob ops structure
- * @len: size of oob to transfer
- */
-static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
-				  struct mtd_oob_ops *ops, size_t len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	switch (ops->mode) {
-
-	case MTD_OPS_PLACE_OOB:
-	case MTD_OPS_RAW:
-		memcpy(oob, chip->oob_poi + ops->ooboffs, len);
-		return oob + len;
-
-	case MTD_OPS_AUTO_OOB:
-		ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
-						  ops->ooboffs, len);
-		BUG_ON(ret);
-		return oob + len;
-
-	default:
-		BUG();
-	}
-	return NULL;
-}
-
-/**
- * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
- * @mtd: MTD device structure
- * @retry_mode: the retry mode to use
- *
- * Some vendors supply a special command to shift the Vt threshold, to be used
- * when there are too many bitflips in a page (i.e., ECC error). After setting
- * a new threshold, the host should retry reading the page.
- */
-static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	pr_debug("setting READ RETRY mode %d\n", retry_mode);
-
-	if (retry_mode >= chip->read_retries)
-		return -EINVAL;
-
-	if (!chip->setup_read_retry)
-		return -EOPNOTSUPP;
-
-	return chip->setup_read_retry(mtd, retry_mode);
-}
-
-/**
- * nand_do_read_ops - [INTERN] Read data with ECC
- * @mtd: MTD device structure
- * @from: offset to read from
- * @ops: oob ops structure
- *
- * Internal function. Called with chip held.
- */
-static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
-			    struct mtd_oob_ops *ops)
-{
-	int chipnr, page, realpage, col, bytes, aligned, oob_required;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret = 0;
-	uint32_t readlen = ops->len;
-	uint32_t oobreadlen = ops->ooblen;
-	uint32_t max_oobsize = mtd_oobavail(mtd, ops);
-
-	uint8_t *bufpoi, *oob, *buf;
-	int use_bufpoi;
-	unsigned int max_bitflips = 0;
-	int retry_mode = 0;
-	bool ecc_fail = false;
-
-	chipnr = (int)(from >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
-	realpage = (int)(from >> chip->page_shift);
-	page = realpage & chip->pagemask;
-
-	col = (int)(from & (mtd->writesize - 1));
-
-	buf = ops->datbuf;
-	oob = ops->oobbuf;
-	oob_required = oob ? 1 : 0;
-
-	while (1) {
-		unsigned int ecc_failures = mtd->ecc_stats.failed;
-
-		bytes = min(mtd->writesize - col, readlen);
-		aligned = (bytes == mtd->writesize);
-
-		if (!aligned)
-			use_bufpoi = 1;
-		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
-			use_bufpoi = !virt_addr_valid(buf) ||
-				     !IS_ALIGNED((unsigned long)buf,
-						 chip->buf_align);
-		else
-			use_bufpoi = 0;
-
-		/* Is the current page in the buffer? */
-		if (realpage != chip->pagebuf || oob) {
-			bufpoi = use_bufpoi ? chip->data_buf : buf;
-
-			if (use_bufpoi && aligned)
-				pr_debug("%s: using read bounce buffer for buf@%p\n",
-						 __func__, buf);
-
-read_retry:
-			/*
-			 * Now read the page into the buffer.  Absent an error,
-			 * the read methods return max bitflips per ecc step.
-			 */
-			if (unlikely(ops->mode == MTD_OPS_RAW))
-				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
-							      oob_required,
-							      page);
-			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
-				 !oob)
-				ret = chip->ecc.read_subpage(mtd, chip,
-							col, bytes, bufpoi,
-							page);
-			else
-				ret = chip->ecc.read_page(mtd, chip, bufpoi,
-							  oob_required, page);
-			if (ret < 0) {
-				if (use_bufpoi)
-					/* Invalidate page cache */
-					chip->pagebuf = -1;
-				break;
-			}
-
-			/* Transfer not aligned data */
-			if (use_bufpoi) {
-				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
-				    !(mtd->ecc_stats.failed - ecc_failures) &&
-				    (ops->mode != MTD_OPS_RAW)) {
-					chip->pagebuf = realpage;
-					chip->pagebuf_bitflips = ret;
-				} else {
-					/* Invalidate page cache */
-					chip->pagebuf = -1;
-				}
-				memcpy(buf, chip->data_buf + col, bytes);
-			}
-
-			if (unlikely(oob)) {
-				int toread = min(oobreadlen, max_oobsize);
-
-				if (toread) {
-					oob = nand_transfer_oob(mtd,
-						oob, ops, toread);
-					oobreadlen -= toread;
-				}
-			}
-
-			if (chip->options & NAND_NEED_READRDY) {
-				/* Apply delay or wait for ready/busy pin */
-				if (!chip->dev_ready)
-					udelay(chip->chip_delay);
-				else
-					nand_wait_ready(mtd);
-			}
-
-			if (mtd->ecc_stats.failed - ecc_failures) {
-				if (retry_mode + 1 < chip->read_retries) {
-					retry_mode++;
-					ret = nand_setup_read_retry(mtd,
-							retry_mode);
-					if (ret < 0)
-						break;
-
-					/* Reset failures; retry */
-					mtd->ecc_stats.failed = ecc_failures;
-					goto read_retry;
-				} else {
-					/* No more retry modes; real failure */
-					ecc_fail = true;
-				}
-			}
-
-			buf += bytes;
-			max_bitflips = max_t(unsigned int, max_bitflips, ret);
-		} else {
-			memcpy(buf, chip->data_buf + col, bytes);
-			buf += bytes;
-			max_bitflips = max_t(unsigned int, max_bitflips,
-					     chip->pagebuf_bitflips);
-		}
-
-		readlen -= bytes;
-
-		/* Reset to retry mode 0 */
-		if (retry_mode) {
-			ret = nand_setup_read_retry(mtd, 0);
-			if (ret < 0)
-				break;
-			retry_mode = 0;
-		}
-
-		if (!readlen)
-			break;
-
-		/* For subsequent reads align to page boundary */
-		col = 0;
-		/* Increment page address */
-		realpage++;
-
-		page = realpage & chip->pagemask;
-		/* Check, if we cross a chip boundary */
-		if (!page) {
-			chipnr++;
-			chip->select_chip(mtd, -1);
-			chip->select_chip(mtd, chipnr);
-		}
-	}
-	chip->select_chip(mtd, -1);
-
-	ops->retlen = ops->len - (size_t) readlen;
-	if (oob)
-		ops->oobretlen = ops->ooblen - oobreadlen;
-
-	if (ret < 0)
-		return ret;
-
-	if (ecc_fail)
-		return -EBADMSG;
-
-	return max_bitflips;
-}
-
-/**
- * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to read
- */
-int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
-{
-	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-}
-EXPORT_SYMBOL(nand_read_oob_std);
-
-/**
- * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
- *			    with syndromes
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to read
- */
-int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-			   int page)
-{
-	int length = mtd->oobsize;
-	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
-	int eccsize = chip->ecc.size;
-	uint8_t *bufpoi = chip->oob_poi;
-	int i, toread, sndrnd = 0, pos, ret;
-
-	ret = nand_read_page_op(chip, page, chip->ecc.size, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < chip->ecc.steps; i++) {
-		if (sndrnd) {
-			int ret;
-
-			pos = eccsize + i * (eccsize + chunk);
-			if (mtd->writesize > 512)
-				ret = nand_change_read_column_op(chip, pos,
-								 NULL, 0,
-								 false);
-			else
-				ret = nand_read_page_op(chip, page, pos, NULL,
-							0);
-
-			if (ret)
-				return ret;
-		} else
-			sndrnd = 1;
-		toread = min_t(int, length, chunk);
-
-		ret = nand_read_data_op(chip, bufpoi, toread, false);
-		if (ret)
-			return ret;
-
-		bufpoi += toread;
-		length -= toread;
-	}
-	if (length > 0) {
-		ret = nand_read_data_op(chip, bufpoi, length, false);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(nand_read_oob_syndrome);
-
-/**
- * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to write
- */
-int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
-{
-	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
-				 mtd->oobsize);
-}
-EXPORT_SYMBOL(nand_write_oob_std);
-
-/**
- * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
- *			     with syndrome - only for large page flash
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to write
- */
-int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-			    int page)
-{
-	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
-	int eccsize = chip->ecc.size, length = mtd->oobsize;
-	int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
-	const uint8_t *bufpoi = chip->oob_poi;
-
-	/*
-	 * data-ecc-data-ecc ... ecc-oob
-	 * or
-	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob
-	 */
-	if (!chip->ecc.prepad && !chip->ecc.postpad) {
-		pos = steps * (eccsize + chunk);
-		steps = 0;
-	} else
-		pos = eccsize;
-
-	ret = nand_prog_page_begin_op(chip, page, pos, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < steps; i++) {
-		if (sndcmd) {
-			if (mtd->writesize <= 512) {
-				uint32_t fill = 0xFFFFFFFF;
-
-				len = eccsize;
-				while (len > 0) {
-					int num = min_t(int, len, 4);
-
-					ret = nand_write_data_op(chip, &fill,
-								 num, false);
-					if (ret)
-						return ret;
-
-					len -= num;
-				}
-			} else {
-				pos = eccsize + i * (eccsize + chunk);
-				ret = nand_change_write_column_op(chip, pos,
-								  NULL, 0,
-								  false);
-				if (ret)
-					return ret;
-			}
-		} else
-			sndcmd = 1;
-		len = min_t(int, length, chunk);
-
-		ret = nand_write_data_op(chip, bufpoi, len, false);
-		if (ret)
-			return ret;
-
-		bufpoi += len;
-		length -= len;
-	}
-	if (length > 0) {
-		ret = nand_write_data_op(chip, bufpoi, length, false);
-		if (ret)
-			return ret;
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-EXPORT_SYMBOL(nand_write_oob_syndrome);
-
-/**
- * nand_do_read_oob - [INTERN] NAND read out-of-band
- * @mtd: MTD device structure
- * @from: offset to read from
- * @ops: oob operations description structure
- *
- * NAND read out-of-band data from the spare area.
- */
-static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
-			    struct mtd_oob_ops *ops)
-{
-	unsigned int max_bitflips = 0;
-	int page, realpage, chipnr;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct mtd_ecc_stats stats;
-	int readlen = ops->ooblen;
-	int len;
-	uint8_t *buf = ops->oobbuf;
-	int ret = 0;
-
-	pr_debug("%s: from = 0x%08Lx, len = %i\n",
-			__func__, (unsigned long long)from, readlen);
-
-	stats = mtd->ecc_stats;
-
-	len = mtd_oobavail(mtd, ops);
-
-	chipnr = (int)(from >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
-	/* Shift to get page */
-	realpage = (int)(from >> chip->page_shift);
-	page = realpage & chip->pagemask;
-
-	while (1) {
-		if (ops->mode == MTD_OPS_RAW)
-			ret = chip->ecc.read_oob_raw(mtd, chip, page);
-		else
-			ret = chip->ecc.read_oob(mtd, chip, page);
-
-		if (ret < 0)
-			break;
-
-		len = min(len, readlen);
-		buf = nand_transfer_oob(mtd, buf, ops, len);
-
-		if (chip->options & NAND_NEED_READRDY) {
-			/* Apply delay or wait for ready/busy pin */
-			if (!chip->dev_ready)
-				udelay(chip->chip_delay);
-			else
-				nand_wait_ready(mtd);
-		}
-
-		max_bitflips = max_t(unsigned int, max_bitflips, ret);
-
-		readlen -= len;
-		if (!readlen)
-			break;
-
-		/* Increment page address */
-		realpage++;
-
-		page = realpage & chip->pagemask;
-		/* Check, if we cross a chip boundary */
-		if (!page) {
-			chipnr++;
-			chip->select_chip(mtd, -1);
-			chip->select_chip(mtd, chipnr);
-		}
-	}
-	chip->select_chip(mtd, -1);
-
-	ops->oobretlen = ops->ooblen - readlen;
-
-	if (ret < 0)
-		return ret;
-
-	if (mtd->ecc_stats.failed - stats.failed)
-		return -EBADMSG;
-
-	return max_bitflips;
-}
-
-/**
- * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
- * @mtd: MTD device structure
- * @from: offset to read from
- * @ops: oob operation description structure
- *
- * NAND read data and/or out-of-band data.
- */
-static int nand_read_oob(struct mtd_info *mtd, loff_t from,
-			 struct mtd_oob_ops *ops)
-{
-	int ret;
-
-	ops->retlen = 0;
-
-	if (ops->mode != MTD_OPS_PLACE_OOB &&
-	    ops->mode != MTD_OPS_AUTO_OOB &&
-	    ops->mode != MTD_OPS_RAW)
-		return -ENOTSUPP;
-
-	nand_get_device(mtd, FL_READING);
-
-	if (!ops->datbuf)
-		ret = nand_do_read_oob(mtd, from, ops);
-	else
-		ret = nand_do_read_ops(mtd, from, ops);
-
-	nand_release_device(mtd);
-	return ret;
-}
-
-
-/**
- * nand_write_page_raw - [INTERN] raw page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- *
- * Not for syndrome calculating ECC controllers, which use a special oob layout.
- */
-int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-			const uint8_t *buf, int oob_required, int page)
-{
-	int ret;
-
-	ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	if (ret)
-		return ret;
-
-	if (oob_required) {
-		ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize,
-					 false);
-		if (ret)
-			return ret;
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-EXPORT_SYMBOL(nand_write_page_raw);
-
-/**
- * nand_write_page_raw_syndrome - [INTERN] raw page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- *
- * We need a special oob layout and handling even when ECC isn't checked.
- */
-static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
-					struct nand_chip *chip,
-					const uint8_t *buf, int oob_required,
-					int page)
-{
-	int eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	uint8_t *oob = chip->oob_poi;
-	int steps, size, ret;
-
-	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (steps = chip->ecc.steps; steps > 0; steps--) {
-		ret = nand_write_data_op(chip, buf, eccsize, false);
-		if (ret)
-			return ret;
-
-		buf += eccsize;
-
-		if (chip->ecc.prepad) {
-			ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
-						 false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.prepad;
-		}
-
-		ret = nand_write_data_op(chip, oob, eccbytes, false);
-		if (ret)
-			return ret;
-
-		oob += eccbytes;
-
-		if (chip->ecc.postpad) {
-			ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
-						 false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.postpad;
-		}
-	}
-
-	size = mtd->oobsize - (oob - chip->oob_poi);
-	if (size) {
-		ret = nand_write_data_op(chip, oob, size, false);
-		if (ret)
-			return ret;
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-/**
- * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- */
-static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-				 const uint8_t *buf, int oob_required,
-				 int page)
-{
-	int i, eccsize = chip->ecc.size, ret;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	const uint8_t *p = buf;
-
-	/* Software ECC calculation */
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
-}
-
-/**
- * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- */
-static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-				  const uint8_t *buf, int oob_required,
-				  int page)
-{
-	int i, eccsize = chip->ecc.size, ret;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	const uint8_t *p = buf;
-
-	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-
-		ret = nand_write_data_op(chip, p, eccsize, false);
-		if (ret)
-			return ret;
-
-		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-	}
-
-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
-	if (ret)
-		return ret;
-
-	return nand_prog_page_end_op(chip);
-}
-
-
-/**
- * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
- * @mtd:	mtd info structure
- * @chip:	nand chip info structure
- * @offset:	column address of subpage within the page
- * @data_len:	data length
- * @buf:	data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- */
-static int nand_write_subpage_hwecc(struct mtd_info *mtd,
-				struct nand_chip *chip, uint32_t offset,
-				uint32_t data_len, const uint8_t *buf,
-				int oob_required, int page)
-{
-	uint8_t *oob_buf  = chip->oob_poi;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	int ecc_size      = chip->ecc.size;
-	int ecc_bytes     = chip->ecc.bytes;
-	int ecc_steps     = chip->ecc.steps;
-	uint32_t start_step = offset / ecc_size;
-	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
-	int oob_bytes       = mtd->oobsize / ecc_steps;
-	int step, ret;
-
-	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (step = 0; step < ecc_steps; step++) {
-		/* configure controller for WRITE access */
-		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-
-		/* write data (untouched subpages already masked by 0xFF) */
-		ret = nand_write_data_op(chip, buf, ecc_size, false);
-		if (ret)
-			return ret;
-
-		/* mask ECC of un-touched subpages by padding 0xFF */
-		if ((step < start_step) || (step > end_step))
-			memset(ecc_calc, 0xff, ecc_bytes);
-		else
-			chip->ecc.calculate(mtd, buf, ecc_calc);
-
-		/* mask OOB of un-touched subpages by padding 0xFF */
-		/* if oob_required, preserve OOB metadata of written subpage */
-		if (!oob_required || (step < start_step) || (step > end_step))
-			memset(oob_buf, 0xff, oob_bytes);
-
-		buf += ecc_size;
-		ecc_calc += ecc_bytes;
-		oob_buf  += oob_bytes;
-	}
-
-	/* copy calculated ECC for whole page to chip->buffer->oob */
-	/* this include masked-value(0xFF) for unwritten subpages */
-	ecc_calc = chip->ecc.calc_buf;
-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	/* write OOB buffer to NAND device */
-	ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
-	if (ret)
-		return ret;
-
-	return nand_prog_page_end_op(chip);
-}
-
-
-/**
- * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- *
- * The hw generator calculates the error syndrome automatically. Therefore we
- * need a special oob layout and handling.
- */
-static int nand_write_page_syndrome(struct mtd_info *mtd,
-				    struct nand_chip *chip,
-				    const uint8_t *buf, int oob_required,
-				    int page)
-{
-	int i, eccsize = chip->ecc.size;
-	int eccbytes = chip->ecc.bytes;
-	int eccsteps = chip->ecc.steps;
-	const uint8_t *p = buf;
-	uint8_t *oob = chip->oob_poi;
-	int ret;
-
-	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	if (ret)
-		return ret;
-
-	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-
-		ret = nand_write_data_op(chip, p, eccsize, false);
-		if (ret)
-			return ret;
-
-		if (chip->ecc.prepad) {
-			ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
-						 false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.prepad;
-		}
-
-		chip->ecc.calculate(mtd, p, oob);
-
-		ret = nand_write_data_op(chip, oob, eccbytes, false);
-		if (ret)
-			return ret;
-
-		oob += eccbytes;
-
-		if (chip->ecc.postpad) {
-			ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
-						 false);
-			if (ret)
-				return ret;
-
-			oob += chip->ecc.postpad;
-		}
-	}
-
-	/* Calculate remaining oob bytes */
-	i = mtd->oobsize - (oob - chip->oob_poi);
-	if (i) {
-		ret = nand_write_data_op(chip, oob, i, false);
-		if (ret)
-			return ret;
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-
-/**
- * nand_write_page - write one page
- * @mtd: MTD device structure
- * @chip: NAND chip descriptor
- * @offset: address offset within the page
- * @data_len: length of actual data to be written
- * @buf: the data to write
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- * @raw: use _raw version of write_page
- */
-static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-		uint32_t offset, int data_len, const uint8_t *buf,
-		int oob_required, int page, int raw)
-{
-	int status, subpage;
-
-	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
-		chip->ecc.write_subpage)
-		subpage = offset || (data_len < mtd->writesize);
-	else
-		subpage = 0;
-
-	if (unlikely(raw))
-		status = chip->ecc.write_page_raw(mtd, chip, buf,
-						  oob_required, page);
-	else if (subpage)
-		status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
-						 buf, oob_required, page);
-	else
-		status = chip->ecc.write_page(mtd, chip, buf, oob_required,
-					      page);
-
-	if (status < 0)
-		return status;
-
-	return 0;
-}
-
-/**
- * nand_fill_oob - [INTERN] Transfer client buffer to oob
- * @mtd: MTD device structure
- * @oob: oob data buffer
- * @len: oob data write length
- * @ops: oob ops structure
- */
-static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
-			      struct mtd_oob_ops *ops)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	/*
-	 * Initialise to all 0xFF, to avoid the possibility of left over OOB
-	 * data from a previous OOB read.
-	 */
-	memset(chip->oob_poi, 0xff, mtd->oobsize);
-
-	switch (ops->mode) {
-
-	case MTD_OPS_PLACE_OOB:
-	case MTD_OPS_RAW:
-		memcpy(chip->oob_poi + ops->ooboffs, oob, len);
-		return oob + len;
-
-	case MTD_OPS_AUTO_OOB:
-		ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
-						  ops->ooboffs, len);
-		BUG_ON(ret);
-		return oob + len;
-
-	default:
-		BUG();
-	}
-	return NULL;
-}
-
-#define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0)
-
-/**
- * nand_do_write_ops - [INTERN] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operations description structure
- *
- * NAND write with ECC.
- */
-static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
-			     struct mtd_oob_ops *ops)
-{
-	int chipnr, realpage, page, column;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	uint32_t writelen = ops->len;
-
-	uint32_t oobwritelen = ops->ooblen;
-	uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
-
-	uint8_t *oob = ops->oobbuf;
-	uint8_t *buf = ops->datbuf;
-	int ret;
-	int oob_required = oob ? 1 : 0;
-
-	ops->retlen = 0;
-	if (!writelen)
-		return 0;
-
-	/* Reject writes, which are not page aligned */
-	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
-		pr_notice("%s: attempt to write non page aligned data\n",
-			   __func__);
-		return -EINVAL;
-	}
-
-	column = to & (mtd->writesize - 1);
-
-	chipnr = (int)(to >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
-	/* Check, if it is write protected */
-	if (nand_check_wp(mtd)) {
-		ret = -EIO;
-		goto err_out;
-	}
-
-	realpage = (int)(to >> chip->page_shift);
-	page = realpage & chip->pagemask;
-
-	/* Invalidate the page cache, when we write to the cached page */
-	if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
-	    ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
-		chip->pagebuf = -1;
-
-	/* Don't allow multipage oob writes with offset */
-	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
-		ret = -EINVAL;
-		goto err_out;
-	}
-
-	while (1) {
-		int bytes = mtd->writesize;
-		uint8_t *wbuf = buf;
-		int use_bufpoi;
-		int part_pagewr = (column || writelen < mtd->writesize);
-
-		if (part_pagewr)
-			use_bufpoi = 1;
-		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
-			use_bufpoi = !virt_addr_valid(buf) ||
-				     !IS_ALIGNED((unsigned long)buf,
-						 chip->buf_align);
-		else
-			use_bufpoi = 0;
-
-		/* Partial page write?, or need to use bounce buffer */
-		if (use_bufpoi) {
-			pr_debug("%s: using write bounce buffer for buf@%p\n",
-					 __func__, buf);
-			if (part_pagewr)
-				bytes = min_t(int, bytes - column, writelen);
-			chip->pagebuf = -1;
-			memset(chip->data_buf, 0xff, mtd->writesize);
-			memcpy(&chip->data_buf[column], buf, bytes);
-			wbuf = chip->data_buf;
-		}
-
-		if (unlikely(oob)) {
-			size_t len = min(oobwritelen, oobmaxlen);
-			oob = nand_fill_oob(mtd, oob, len, ops);
-			oobwritelen -= len;
-		} else {
-			/* We still need to erase leftover OOB data */
-			memset(chip->oob_poi, 0xff, mtd->oobsize);
-		}
-
-		ret = nand_write_page(mtd, chip, column, bytes, wbuf,
-				      oob_required, page,
-				      (ops->mode == MTD_OPS_RAW));
-		if (ret)
-			break;
-
-		writelen -= bytes;
-		if (!writelen)
-			break;
-
-		column = 0;
-		buf += bytes;
-		realpage++;
-
-		page = realpage & chip->pagemask;
-		/* Check, if we cross a chip boundary */
-		if (!page) {
-			chipnr++;
-			chip->select_chip(mtd, -1);
-			chip->select_chip(mtd, chipnr);
-		}
-	}
-
-	ops->retlen = ops->len - writelen;
-	if (unlikely(oob))
-		ops->oobretlen = ops->ooblen;
-
-err_out:
-	chip->select_chip(mtd, -1);
-	return ret;
-}
-
-/**
- * panic_nand_write - [MTD Interface] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- * @len: number of bytes to write
- * @retlen: pointer to variable to store the number of written bytes
- * @buf: the data to write
- *
- * NAND write with ECC. Used when performing writes in interrupt context, this
- * may for example be called by mtdoops when writing an oops while in panic.
- */
-static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
-			    size_t *retlen, const uint8_t *buf)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int chipnr = (int)(to >> chip->chip_shift);
-	struct mtd_oob_ops ops;
-	int ret;
-
-	/* Grab the device */
-	panic_nand_get_device(chip, mtd, FL_WRITING);
-
-	chip->select_chip(mtd, chipnr);
-
-	/* Wait for the device to get ready */
-	panic_nand_wait(mtd, chip, 400);
-
-	memset(&ops, 0, sizeof(ops));
-	ops.len = len;
-	ops.datbuf = (uint8_t *)buf;
-	ops.mode = MTD_OPS_PLACE_OOB;
-
-	ret = nand_do_write_ops(mtd, to, &ops);
-
-	*retlen = ops.retlen;
-	return ret;
-}
-
-/**
- * nand_do_write_oob - [MTD Interface] NAND write out-of-band
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operation description structure
- *
- * NAND write out-of-band.
- */
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
-			     struct mtd_oob_ops *ops)
-{
-	int chipnr, page, status, len;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	pr_debug("%s: to = 0x%08x, len = %i\n",
-			 __func__, (unsigned int)to, (int)ops->ooblen);
-
-	len = mtd_oobavail(mtd, ops);
-
-	/* Do not allow write past end of page */
-	if ((ops->ooboffs + ops->ooblen) > len) {
-		pr_debug("%s: attempt to write past end of page\n",
-				__func__);
-		return -EINVAL;
-	}
-
-	chipnr = (int)(to >> chip->chip_shift);
-
-	/*
-	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
-	 * of my DiskOnChip 2000 test units) will clear the whole data page too
-	 * if we don't do this. I have no clue why, but I seem to have 'fixed'
-	 * it in the doc2000 driver in August 1999.  dwmw2.
-	 */
-	nand_reset(chip, chipnr);
-
-	chip->select_chip(mtd, chipnr);
-
-	/* Shift to get page */
-	page = (int)(to >> chip->page_shift);
-
-	/* Check, if it is write protected */
-	if (nand_check_wp(mtd)) {
-		chip->select_chip(mtd, -1);
-		return -EROFS;
-	}
-
-	/* Invalidate the page cache, if we write to the cached page */
-	if (page == chip->pagebuf)
-		chip->pagebuf = -1;
-
-	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
-
-	if (ops->mode == MTD_OPS_RAW)
-		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
-	else
-		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
-
-	chip->select_chip(mtd, -1);
-
-	if (status)
-		return status;
-
-	ops->oobretlen = ops->ooblen;
-
-	return 0;
-}
-
-/**
- * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operation description structure
- */
-static int nand_write_oob(struct mtd_info *mtd, loff_t to,
-			  struct mtd_oob_ops *ops)
-{
-	int ret = -ENOTSUPP;
-
-	ops->retlen = 0;
-
-	nand_get_device(mtd, FL_WRITING);
-
-	switch (ops->mode) {
-	case MTD_OPS_PLACE_OOB:
-	case MTD_OPS_AUTO_OOB:
-	case MTD_OPS_RAW:
-		break;
-
-	default:
-		goto out;
-	}
-
-	if (!ops->datbuf)
-		ret = nand_do_write_oob(mtd, to, ops);
-	else
-		ret = nand_do_write_ops(mtd, to, ops);
-
-out:
-	nand_release_device(mtd);
-	return ret;
-}
-
-/**
- * single_erase - [GENERIC] NAND standard block erase command function
- * @mtd: MTD device structure
- * @page: the page address of the block which will be erased
- *
- * Standard erase command for NAND chips. Returns NAND status.
- */
-static int single_erase(struct mtd_info *mtd, int page)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	unsigned int eraseblock;
-
-	/* Send commands to erase a block */
-	eraseblock = page >> (chip->phys_erase_shift - chip->page_shift);
-
-	return nand_erase_op(chip, eraseblock);
-}
-
-/**
- * nand_erase - [MTD Interface] erase block(s)
- * @mtd: MTD device structure
- * @instr: erase instruction
- *
- * Erase one ore more blocks.
- */
-static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	return nand_erase_nand(mtd, instr, 0);
-}
-
-/**
- * nand_erase_nand - [INTERN] erase block(s)
- * @mtd: MTD device structure
- * @instr: erase instruction
- * @allowbbt: allow erasing the bbt area
- *
- * Erase one ore more blocks.
- */
-int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
-		    int allowbbt)
-{
-	int page, status, pages_per_block, ret, chipnr;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	loff_t len;
-
-	pr_debug("%s: start = 0x%012llx, len = %llu\n",
-			__func__, (unsigned long long)instr->addr,
-			(unsigned long long)instr->len);
-
-	if (check_offs_len(mtd, instr->addr, instr->len))
-		return -EINVAL;
-
-	/* Grab the lock and see if the device is available */
-	nand_get_device(mtd, FL_ERASING);
-
-	/* Shift to get first page */
-	page = (int)(instr->addr >> chip->page_shift);
-	chipnr = (int)(instr->addr >> chip->chip_shift);
-
-	/* Calculate pages in each block */
-	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
-
-	/* Select the NAND device */
-	chip->select_chip(mtd, chipnr);
-
-	/* Check, if it is write protected */
-	if (nand_check_wp(mtd)) {
-		pr_debug("%s: device is write protected!\n",
-				__func__);
-		instr->state = MTD_ERASE_FAILED;
-		goto erase_exit;
-	}
-
-	/* Loop through the pages */
-	len = instr->len;
-
-	instr->state = MTD_ERASING;
-
-	while (len) {
-		/* Check if we have a bad block, we do not erase bad blocks! */
-		if (nand_block_checkbad(mtd, ((loff_t) page) <<
-					chip->page_shift, allowbbt)) {
-			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
-				    __func__, page);
-			instr->state = MTD_ERASE_FAILED;
-			goto erase_exit;
-		}
-
-		/*
-		 * Invalidate the page cache, if we erase the block which
-		 * contains the current cached page.
-		 */
-		if (page <= chip->pagebuf && chip->pagebuf <
-		    (page + pages_per_block))
-			chip->pagebuf = -1;
-
-		status = chip->erase(mtd, page & chip->pagemask);
-
-		/* See if block erase succeeded */
-		if (status) {
-			pr_debug("%s: failed erase, page 0x%08x\n",
-					__func__, page);
-			instr->state = MTD_ERASE_FAILED;
-			instr->fail_addr =
-				((loff_t)page << chip->page_shift);
-			goto erase_exit;
-		}
-
-		/* Increment page address and decrement length */
-		len -= (1ULL << chip->phys_erase_shift);
-		page += pages_per_block;
-
-		/* Check, if we cross a chip boundary */
-		if (len && !(page & chip->pagemask)) {
-			chipnr++;
-			chip->select_chip(mtd, -1);
-			chip->select_chip(mtd, chipnr);
-		}
-	}
-	instr->state = MTD_ERASE_DONE;
-
-erase_exit:
-
-	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-
-	/* Deselect and wake up anyone waiting on the device */
-	chip->select_chip(mtd, -1);
-	nand_release_device(mtd);
-
-	/* Do call back function */
-	if (!ret)
-		mtd_erase_callback(instr);
-
-	/* Return more or less happy */
-	return ret;
-}
-
-/**
- * nand_sync - [MTD Interface] sync
- * @mtd: MTD device structure
- *
- * Sync is actually a wait for chip ready function.
- */
-static void nand_sync(struct mtd_info *mtd)
-{
-	pr_debug("%s: called\n", __func__);
-
-	/* Grab the lock and see if the device is available */
-	nand_get_device(mtd, FL_SYNCING);
-	/* Release it and go back */
-	nand_release_device(mtd);
-}
-
-/**
- * nand_block_isbad - [MTD Interface] Check if block at offset is bad
- * @mtd: MTD device structure
- * @offs: offset relative to mtd start
- */
-static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int chipnr = (int)(offs >> chip->chip_shift);
-	int ret;
-
-	/* Select the NAND device */
-	nand_get_device(mtd, FL_READING);
-	chip->select_chip(mtd, chipnr);
-
-	ret = nand_block_checkbad(mtd, offs, 0);
-
-	chip->select_chip(mtd, -1);
-	nand_release_device(mtd);
-
-	return ret;
-}
-
-/**
- * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
- * @mtd: MTD device structure
- * @ofs: offset relative to mtd start
- */
-static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	int ret;
-
-	ret = nand_block_isbad(mtd, ofs);
-	if (ret) {
-		/* If it was bad already, return success and do nothing */
-		if (ret > 0)
-			return 0;
-		return ret;
-	}
-
-	return nand_block_markbad_lowlevel(mtd, ofs);
-}
-
-/**
- * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
- * @mtd: MTD device structure
- * @ofs: offset relative to mtd start
- * @len: length of mtd
- */
-static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u32 part_start_block;
-	u32 part_end_block;
-	u32 part_start_die;
-	u32 part_end_die;
-
-	/*
-	 * max_bb_per_die and blocks_per_die used to determine
-	 * the maximum bad block count.
-	 */
-	if (!chip->max_bb_per_die || !chip->blocks_per_die)
-		return -ENOTSUPP;
-
-	/* Get the start and end of the partition in erase blocks. */
-	part_start_block = mtd_div_by_eb(ofs, mtd);
-	part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
-
-	/* Get the start and end LUNs of the partition. */
-	part_start_die = part_start_block / chip->blocks_per_die;
-	part_end_die = part_end_block / chip->blocks_per_die;
-
-	/*
-	 * Look up the bad blocks per unit and multiply by the number of units
-	 * that the partition spans.
-	 */
-	return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
-}
-
-/**
- * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
-			int addr, uint8_t *subfeature_param)
-{
-	if (!chip->onfi_version ||
-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
-		return -EINVAL;
-
-	return nand_set_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
-			int addr, uint8_t *subfeature_param)
-{
-	if (!chip->onfi_version ||
-	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
-	      & ONFI_OPT_CMD_SET_GET_FEATURES))
-		return -EINVAL;
-
-	return nand_get_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_onfi_get_set_features_notsupp - set/get features stub returning
- *					-ENOTSUPP
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- *
- * Should be used by NAND controller drivers that do not support the SET/GET
- * FEATURES operations.
- */
-int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
-				       struct nand_chip *chip, int addr,
-				       u8 *subfeature_param)
-{
-	return -ENOTSUPP;
-}
-EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
-
-/**
- * nand_suspend - [MTD Interface] Suspend the NAND flash
- * @mtd: MTD device structure
- */
-static int nand_suspend(struct mtd_info *mtd)
-{
-	return nand_get_device(mtd, FL_PM_SUSPENDED);
-}
-
-/**
- * nand_resume - [MTD Interface] Resume the NAND flash
- * @mtd: MTD device structure
- */
-static void nand_resume(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (chip->state == FL_PM_SUSPENDED)
-		nand_release_device(mtd);
-	else
-		pr_err("%s called for a chip which is not in suspended state\n",
-			__func__);
-}
-
-/**
- * nand_shutdown - [MTD Interface] Finish the current NAND operation and
- *                 prevent further operations
- * @mtd: MTD device structure
- */
-static void nand_shutdown(struct mtd_info *mtd)
-{
-	nand_get_device(mtd, FL_PM_SUSPENDED);
-}
-
-/* Set default functions */
-static void nand_set_defaults(struct nand_chip *chip)
-{
-	unsigned int busw = chip->options & NAND_BUSWIDTH_16;
-
-	/* check for proper chip_delay setup, set 20us if not */
-	if (!chip->chip_delay)
-		chip->chip_delay = 20;
-
-	/* check, if a user supplied command function given */
-	if (!chip->cmdfunc && !chip->exec_op)
-		chip->cmdfunc = nand_command;
-
-	/* check, if a user supplied wait function given */
-	if (chip->waitfunc == NULL)
-		chip->waitfunc = nand_wait;
-
-	if (!chip->select_chip)
-		chip->select_chip = nand_select_chip;
-
-	/* set for ONFI nand */
-	if (!chip->onfi_set_features)
-		chip->onfi_set_features = nand_onfi_set_features;
-	if (!chip->onfi_get_features)
-		chip->onfi_get_features = nand_onfi_get_features;
-
-	/* If called twice, pointers that depend on busw may need to be reset */
-	if (!chip->read_byte || chip->read_byte == nand_read_byte)
-		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
-	if (!chip->read_word)
-		chip->read_word = nand_read_word;
-	if (!chip->block_bad)
-		chip->block_bad = nand_block_bad;
-	if (!chip->block_markbad)
-		chip->block_markbad = nand_default_block_markbad;
-	if (!chip->write_buf || chip->write_buf == nand_write_buf)
-		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-	if (!chip->write_byte || chip->write_byte == nand_write_byte)
-		chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
-	if (!chip->read_buf || chip->read_buf == nand_read_buf)
-		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-	if (!chip->scan_bbt)
-		chip->scan_bbt = nand_default_bbt;
-
-	if (!chip->controller) {
-		chip->controller = &chip->hwcontrol;
-		nand_hw_control_init(chip->controller);
-	}
-
-	if (!chip->buf_align)
-		chip->buf_align = 1;
-}
-
-/* Sanitize ONFI strings so we can safely print them */
-static void sanitize_string(uint8_t *s, size_t len)
-{
-	ssize_t i;
-
-	/* Null terminate */
-	s[len - 1] = 0;
-
-	/* Remove non printable chars */
-	for (i = 0; i < len - 1; i++) {
-		if (s[i] < ' ' || s[i] > 127)
-			s[i] = '?';
-	}
-
-	/* Remove trailing spaces */
-	strim(s);
-}
-
-static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
-{
-	int i;
-	while (len--) {
-		crc ^= *p++ << 8;
-		for (i = 0; i < 8; i++)
-			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
-	}
-
-	return crc;
-}
-
-/* Parse the Extended Parameter Page. */
-static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
-					    struct nand_onfi_params *p)
-{
-	struct onfi_ext_param_page *ep;
-	struct onfi_ext_section *s;
-	struct onfi_ext_ecc_info *ecc;
-	uint8_t *cursor;
-	int ret;
-	int len;
-	int i;
-
-	len = le16_to_cpu(p->ext_param_page_length) * 16;
-	ep = kmalloc(len, GFP_KERNEL);
-	if (!ep)
-		return -ENOMEM;
-
-	/* Send our own NAND_CMD_PARAM. */
-	ret = nand_read_param_page_op(chip, 0, NULL, 0);
-	if (ret)
-		goto ext_out;
-
-	/* Use the Change Read Column command to skip the ONFI param pages. */
-	ret = nand_change_read_column_op(chip,
-					 sizeof(*p) * p->num_of_param_pages,
-					 ep, len, true);
-	if (ret)
-		goto ext_out;
-
-	ret = -EINVAL;
-	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
-		!= le16_to_cpu(ep->crc))) {
-		pr_debug("fail in the CRC.\n");
-		goto ext_out;
-	}
-
-	/*
-	 * Check the signature.
-	 * Do not strictly follow the ONFI spec, maybe changed in future.
-	 */
-	if (strncmp(ep->sig, "EPPS", 4)) {
-		pr_debug("The signature is invalid.\n");
-		goto ext_out;
-	}
-
-	/* find the ECC section. */
-	cursor = (uint8_t *)(ep + 1);
-	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
-		s = ep->sections + i;
-		if (s->type == ONFI_SECTION_TYPE_2)
-			break;
-		cursor += s->length * 16;
-	}
-	if (i == ONFI_EXT_SECTION_MAX) {
-		pr_debug("We can not find the ECC section.\n");
-		goto ext_out;
-	}
-
-	/* get the info we want. */
-	ecc = (struct onfi_ext_ecc_info *)cursor;
-
-	if (!ecc->codeword_size) {
-		pr_debug("Invalid codeword size\n");
-		goto ext_out;
-	}
-
-	chip->ecc_strength_ds = ecc->ecc_bits;
-	chip->ecc_step_ds = 1 << ecc->codeword_size;
-	ret = 0;
-
-ext_out:
-	kfree(ep);
-	return ret;
-}
-
-/*
- * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_onfi(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_onfi_params *p = &chip->onfi_params;
-	char id[4];
-	int i, ret, val;
-
-	/* Try ONFI for unknown chip or LP */
-	ret = nand_readid_op(chip, 0x20, id, sizeof(id));
-	if (ret || strncmp(id, "ONFI", 4))
-		return 0;
-
-	ret = nand_read_param_page_op(chip, 0, NULL, 0);
-	if (ret)
-		return 0;
-
-	for (i = 0; i < 3; i++) {
-		ret = nand_read_data_op(chip, p, sizeof(*p), true);
-		if (ret)
-			return 0;
-
-		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
-				le16_to_cpu(p->crc)) {
-			break;
-		}
-	}
-
-	if (i == 3) {
-		pr_err("Could not find valid ONFI parameter page; aborting\n");
-		return 0;
-	}
-
-	/* Check version */
-	val = le16_to_cpu(p->revision);
-	if (val & (1 << 5))
-		chip->onfi_version = 23;
-	else if (val & (1 << 4))
-		chip->onfi_version = 22;
-	else if (val & (1 << 3))
-		chip->onfi_version = 21;
-	else if (val & (1 << 2))
-		chip->onfi_version = 20;
-	else if (val & (1 << 1))
-		chip->onfi_version = 10;
-
-	if (!chip->onfi_version) {
-		pr_info("unsupported ONFI version: %d\n", val);
-		return 0;
-	}
-
-	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
-	sanitize_string(p->model, sizeof(p->model));
-	if (!mtd->name)
-		mtd->name = p->model;
-
-	mtd->writesize = le32_to_cpu(p->byte_per_page);
-
-	/*
-	 * pages_per_block and blocks_per_lun may not be a power-of-2 size
-	 * (don't ask me who thought of this...). MTD assumes that these
-	 * dimensions will be power-of-2, so just truncate the remaining area.
-	 */
-	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
-	mtd->erasesize *= mtd->writesize;
-
-	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
-	/* See erasesize comment */
-	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
-	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-	chip->bits_per_cell = p->bits_per_cell;
-
-	chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
-	chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
-
-	if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	if (p->ecc_bits != 0xff) {
-		chip->ecc_strength_ds = p->ecc_bits;
-		chip->ecc_step_ds = 512;
-	} else if (chip->onfi_version >= 21 &&
-		(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
-
-		/*
-		 * The nand_flash_detect_ext_param_page() uses the
-		 * Change Read Column command which maybe not supported
-		 * by the chip->cmdfunc. So try to update the chip->cmdfunc
-		 * now. We do not replace user supplied command function.
-		 */
-		if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
-			chip->cmdfunc = nand_command_lp;
-
-		/* The Extended Parameter Page is supported since ONFI 2.1. */
-		if (nand_flash_detect_ext_param_page(chip, p))
-			pr_warn("Failed to detect ONFI extended param page\n");
-	} else {
-		pr_warn("Could not retrieve ONFI ECC requirements\n");
-	}
-
-	return 1;
-}
-
-/*
- * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_jedec(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_jedec_params *p = &chip->jedec_params;
-	struct jedec_ecc_info *ecc;
-	char id[5];
-	int i, val, ret;
-
-	/* Try JEDEC for unknown chip or LP */
-	ret = nand_readid_op(chip, 0x40, id, sizeof(id));
-	if (ret || strncmp(id, "JEDEC", sizeof(id)))
-		return 0;
-
-	ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
-	if (ret)
-		return 0;
-
-	for (i = 0; i < 3; i++) {
-		ret = nand_read_data_op(chip, p, sizeof(*p), true);
-		if (ret)
-			return 0;
-
-		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
-				le16_to_cpu(p->crc))
-			break;
-	}
-
-	if (i == 3) {
-		pr_err("Could not find valid JEDEC parameter page; aborting\n");
-		return 0;
-	}
-
-	/* Check version */
-	val = le16_to_cpu(p->revision);
-	if (val & (1 << 2))
-		chip->jedec_version = 10;
-	else if (val & (1 << 1))
-		chip->jedec_version = 1; /* vendor specific version */
-
-	if (!chip->jedec_version) {
-		pr_info("unsupported JEDEC version: %d\n", val);
-		return 0;
-	}
-
-	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
-	sanitize_string(p->model, sizeof(p->model));
-	if (!mtd->name)
-		mtd->name = p->model;
-
-	mtd->writesize = le32_to_cpu(p->byte_per_page);
-
-	/* Please reference to the comment for nand_flash_detect_onfi. */
-	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
-	mtd->erasesize *= mtd->writesize;
-
-	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
-	/* Please reference to the comment for nand_flash_detect_onfi. */
-	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
-	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-	chip->bits_per_cell = p->bits_per_cell;
-
-	if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	/* ECC info */
-	ecc = &p->ecc_info[0];
-
-	if (ecc->codeword_size >= 9) {
-		chip->ecc_strength_ds = ecc->ecc_bits;
-		chip->ecc_step_ds = 1 << ecc->codeword_size;
-	} else {
-		pr_warn("Invalid codeword size\n");
-	}
-
-	return 1;
-}
-
-/*
- * nand_id_has_period - Check if an ID string has a given wraparound period
- * @id_data: the ID string
- * @arrlen: the length of the @id_data array
- * @period: the period of repitition
- *
- * Check if an ID string is repeated within a given sequence of bytes at
- * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
- * period of 3). This is a helper function for nand_id_len(). Returns non-zero
- * if the repetition has a period of @period; otherwise, returns zero.
- */
-static int nand_id_has_period(u8 *id_data, int arrlen, int period)
-{
-	int i, j;
-	for (i = 0; i < period; i++)
-		for (j = i + period; j < arrlen; j += period)
-			if (id_data[i] != id_data[j])
-				return 0;
-	return 1;
-}
-
-/*
- * nand_id_len - Get the length of an ID string returned by CMD_READID
- * @id_data: the ID string
- * @arrlen: the length of the @id_data array
-
- * Returns the length of the ID string, according to known wraparound/trailing
- * zero patterns. If no pattern exists, returns the length of the array.
- */
-static int nand_id_len(u8 *id_data, int arrlen)
-{
-	int last_nonzero, period;
-
-	/* Find last non-zero byte */
-	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
-		if (id_data[last_nonzero])
-			break;
-
-	/* All zeros */
-	if (last_nonzero < 0)
-		return 0;
-
-	/* Calculate wraparound period */
-	for (period = 1; period < arrlen; period++)
-		if (nand_id_has_period(id_data, arrlen, period))
-			break;
-
-	/* There's a repeated pattern */
-	if (period < arrlen)
-		return period;
-
-	/* There are trailing zeros */
-	if (last_nonzero < arrlen - 1)
-		return last_nonzero + 1;
-
-	/* No pattern detected */
-	return arrlen;
-}
-
-/* Extract the bits of per cell from the 3rd byte of the extended ID */
-static int nand_get_bits_per_cell(u8 cellinfo)
-{
-	int bits;
-
-	bits = cellinfo & NAND_CI_CELLTYPE_MSK;
-	bits >>= NAND_CI_CELLTYPE_SHIFT;
-	return bits + 1;
-}
-
-/*
- * Many new NAND share similar device ID codes, which represent the size of the
- * chip. The rest of the parameters must be decoded according to generic or
- * manufacturer-specific "extended ID" decoding patterns.
- */
-void nand_decode_ext_id(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int extid;
-	u8 *id_data = chip->id.data;
-	/* The 3rd id byte holds MLC / multichip data */
-	chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
-	/* The 4th id byte is the important one */
-	extid = id_data[3];
-
-	/* Calc pagesize */
-	mtd->writesize = 1024 << (extid & 0x03);
-	extid >>= 2;
-	/* Calc oobsize */
-	mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
-	extid >>= 2;
-	/* Calc blocksize. Blocksize is multiples of 64KiB */
-	mtd->erasesize = (64 * 1024) << (extid & 0x03);
-	extid >>= 2;
-	/* Get buswidth information */
-	if (extid & 0x1)
-		chip->options |= NAND_BUSWIDTH_16;
-}
-EXPORT_SYMBOL_GPL(nand_decode_ext_id);
-
-/*
- * Old devices have chip data hardcoded in the device ID table. nand_decode_id
- * decodes a matching ID table entry and assigns the MTD size parameters for
- * the chip.
- */
-static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	mtd->erasesize = type->erasesize;
-	mtd->writesize = type->pagesize;
-	mtd->oobsize = mtd->writesize / 32;
-
-	/* All legacy ID NAND are small-page, SLC */
-	chip->bits_per_cell = 1;
-}
-
-/*
- * Set the bad block marker/indicator (BBM/BBI) patterns according to some
- * heuristic patterns using various detected parameters (e.g., manufacturer,
- * page size, cell-type information).
- */
-static void nand_decode_bbm_options(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	/* Set the bad block position */
-	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
-		chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
-	else
-		chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
-}
-
-static inline bool is_full_id_nand(struct nand_flash_dev *type)
-{
-	return type->id_len;
-}
-
-static bool find_full_id_nand(struct nand_chip *chip,
-			      struct nand_flash_dev *type)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 *id_data = chip->id.data;
-
-	if (!strncmp(type->id, id_data, type->id_len)) {
-		mtd->writesize = type->pagesize;
-		mtd->erasesize = type->erasesize;
-		mtd->oobsize = type->oobsize;
-
-		chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
-		chip->chipsize = (uint64_t)type->chipsize << 20;
-		chip->options |= type->options;
-		chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
-		chip->ecc_step_ds = NAND_ECC_STEP(type);
-		chip->onfi_timing_mode_default =
-					type->onfi_timing_mode_default;
-
-		if (!mtd->name)
-			mtd->name = type->name;
-
-		return true;
-	}
-	return false;
-}
-
-/*
- * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
- * compliant and does not have a full-id or legacy-id entry in the nand_ids
- * table.
- */
-static void nand_manufacturer_detect(struct nand_chip *chip)
-{
-	/*
-	 * Try manufacturer detection if available and use
-	 * nand_decode_ext_id() otherwise.
-	 */
-	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
-	    chip->manufacturer.desc->ops->detect) {
-		/* The 3rd id byte holds MLC / multichip data */
-		chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
-		chip->manufacturer.desc->ops->detect(chip);
-	} else {
-		nand_decode_ext_id(chip);
-	}
-}
-
-/*
- * Manufacturer initialization. This function is called for all NANDs including
- * ONFI and JEDEC compliant ones.
- * Manufacturer drivers should put all their specific initialization code in
- * their ->init() hook.
- */
-static int nand_manufacturer_init(struct nand_chip *chip)
-{
-	if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
-	    !chip->manufacturer.desc->ops->init)
-		return 0;
-
-	return chip->manufacturer.desc->ops->init(chip);
-}
-
-/*
- * Manufacturer cleanup. This function is called for all NANDs including
- * ONFI and JEDEC compliant ones.
- * Manufacturer drivers should put all their specific cleanup code in their
- * ->cleanup() hook.
- */
-static void nand_manufacturer_cleanup(struct nand_chip *chip)
-{
-	/* Release manufacturer private data */
-	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
-	    chip->manufacturer.desc->ops->cleanup)
-		chip->manufacturer.desc->ops->cleanup(chip);
-}
-
-/*
- * Get the flash and manufacturer id and lookup if the type is supported.
- */
-static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
-{
-	const struct nand_manufacturer *manufacturer;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int busw, ret;
-	u8 *id_data = chip->id.data;
-	u8 maf_id, dev_id;
-
-	/*
-	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
-	 * after power-up.
-	 */
-	ret = nand_reset(chip, 0);
-	if (ret)
-		return ret;
-
-	/* Select the device */
-	chip->select_chip(mtd, 0);
-
-	/* Send the command for reading device ID */
-	ret = nand_readid_op(chip, 0, id_data, 2);
-	if (ret)
-		return ret;
-
-	/* Read manufacturer and device IDs */
-	maf_id = id_data[0];
-	dev_id = id_data[1];
-
-	/*
-	 * Try again to make sure, as some systems the bus-hold or other
-	 * interface concerns can cause random data which looks like a
-	 * possibly credible NAND flash to appear. If the two results do
-	 * not match, ignore the device completely.
-	 */
-
-	/* Read entire ID string */
-	ret = nand_readid_op(chip, 0, id_data, sizeof(chip->id.data));
-	if (ret)
-		return ret;
-
-	if (id_data[0] != maf_id || id_data[1] != dev_id) {
-		pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
-			maf_id, dev_id, id_data[0], id_data[1]);
-		return -ENODEV;
-	}
-
-	chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
-
-	/* Try to identify manufacturer */
-	manufacturer = nand_get_manufacturer(maf_id);
-	chip->manufacturer.desc = manufacturer;
-
-	if (!type)
-		type = nand_flash_ids;
-
-	/*
-	 * Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
-	 * override it.
-	 * This is required to make sure initial NAND bus width set by the
-	 * NAND controller driver is coherent with the real NAND bus width
-	 * (extracted by auto-detection code).
-	 */
-	busw = chip->options & NAND_BUSWIDTH_16;
-
-	/*
-	 * The flag is only set (never cleared), reset it to its default value
-	 * before starting auto-detection.
-	 */
-	chip->options &= ~NAND_BUSWIDTH_16;
-
-	for (; type->name != NULL; type++) {
-		if (is_full_id_nand(type)) {
-			if (find_full_id_nand(chip, type))
-				goto ident_done;
-		} else if (dev_id == type->dev_id) {
-			break;
-		}
-	}
-
-	chip->onfi_version = 0;
-	if (!type->name || !type->pagesize) {
-		/* Check if the chip is ONFI compliant */
-		if (nand_flash_detect_onfi(chip))
-			goto ident_done;
-
-		/* Check if the chip is JEDEC compliant */
-		if (nand_flash_detect_jedec(chip))
-			goto ident_done;
-	}
-
-	if (!type->name)
-		return -ENODEV;
-
-	if (!mtd->name)
-		mtd->name = type->name;
-
-	chip->chipsize = (uint64_t)type->chipsize << 20;
-
-	if (!type->pagesize)
-		nand_manufacturer_detect(chip);
-	else
-		nand_decode_id(chip, type);
-
-	/* Get chip options */
-	chip->options |= type->options;
-
-ident_done:
-
-	if (chip->options & NAND_BUSWIDTH_AUTO) {
-		WARN_ON(busw & NAND_BUSWIDTH_16);
-		nand_set_defaults(chip);
-	} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
-		/*
-		 * Check, if buswidth is correct. Hardware drivers should set
-		 * chip correct!
-		 */
-		pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
-			maf_id, dev_id);
-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
-			mtd->name);
-		pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
-			(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
-		return -EINVAL;
-	}
-
-	nand_decode_bbm_options(chip);
-
-	/* Calculate the address shift from the page size */
-	chip->page_shift = ffs(mtd->writesize) - 1;
-	/* Convert chipsize to number of pages per chip -1 */
-	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
-
-	chip->bbt_erase_shift = chip->phys_erase_shift =
-		ffs(mtd->erasesize) - 1;
-	if (chip->chipsize & 0xffffffff)
-		chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
-	else {
-		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
-		chip->chip_shift += 32 - 1;
-	}
-
-	if (chip->chip_shift - chip->page_shift > 16)
-		chip->options |= NAND_ROW_ADDR_3;
-
-	chip->badblockbits = 8;
-	chip->erase = single_erase;
-
-	/* Do not replace user supplied command function! */
-	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
-		chip->cmdfunc = nand_command_lp;
-
-	pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
-		maf_id, dev_id);
-
-	if (chip->onfi_version)
-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
-			chip->onfi_params.model);
-	else if (chip->jedec_version)
-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
-			chip->jedec_params.model);
-	else
-		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
-			type->name);
-
-	pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
-		(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
-		mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
-	return 0;
-}
-
-static const char * const nand_ecc_modes[] = {
-	[NAND_ECC_NONE]		= "none",
-	[NAND_ECC_SOFT]		= "soft",
-	[NAND_ECC_HW]		= "hw",
-	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
-	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
-	[NAND_ECC_ON_DIE]	= "on-die",
-};
-
-static int of_get_nand_ecc_mode(struct device_node *np)
-{
-	const char *pm;
-	int err, i;
-
-	err = of_property_read_string(np, "nand-ecc-mode", &pm);
-	if (err < 0)
-		return err;
-
-	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
-		if (!strcasecmp(pm, nand_ecc_modes[i]))
-			return i;
-
-	/*
-	 * For backward compatibility we support few obsoleted values that don't
-	 * have their mappings into nand_ecc_modes_t anymore (they were merged
-	 * with other enums).
-	 */
-	if (!strcasecmp(pm, "soft_bch"))
-		return NAND_ECC_SOFT;
-
-	return -ENODEV;
-}
-
-static const char * const nand_ecc_algos[] = {
-	[NAND_ECC_HAMMING]	= "hamming",
-	[NAND_ECC_BCH]		= "bch",
-};
-
-static int of_get_nand_ecc_algo(struct device_node *np)
-{
-	const char *pm;
-	int err, i;
-
-	err = of_property_read_string(np, "nand-ecc-algo", &pm);
-	if (!err) {
-		for (i = NAND_ECC_HAMMING; i < ARRAY_SIZE(nand_ecc_algos); i++)
-			if (!strcasecmp(pm, nand_ecc_algos[i]))
-				return i;
-		return -ENODEV;
-	}
-
-	/*
-	 * For backward compatibility we also read "nand-ecc-mode" checking
-	 * for some obsoleted values that were specifying ECC algorithm.
-	 */
-	err = of_property_read_string(np, "nand-ecc-mode", &pm);
-	if (err < 0)
-		return err;
-
-	if (!strcasecmp(pm, "soft"))
-		return NAND_ECC_HAMMING;
-	else if (!strcasecmp(pm, "soft_bch"))
-		return NAND_ECC_BCH;
-
-	return -ENODEV;
-}
-
-static int of_get_nand_ecc_step_size(struct device_node *np)
-{
-	int ret;
-	u32 val;
-
-	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
-	return ret ? ret : val;
-}
-
-static int of_get_nand_ecc_strength(struct device_node *np)
-{
-	int ret;
-	u32 val;
-
-	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
-	return ret ? ret : val;
-}
-
-static int of_get_nand_bus_width(struct device_node *np)
-{
-	u32 val;
-
-	if (of_property_read_u32(np, "nand-bus-width", &val))
-		return 8;
-
-	switch (val) {
-	case 8:
-	case 16:
-		return val;
-	default:
-		return -EIO;
-	}
-}
-
-static bool of_get_nand_on_flash_bbt(struct device_node *np)
-{
-	return of_property_read_bool(np, "nand-on-flash-bbt");
-}
-
-static int nand_dt_init(struct nand_chip *chip)
-{
-	struct device_node *dn = nand_get_flash_node(chip);
-	int ecc_mode, ecc_algo, ecc_strength, ecc_step;
-
-	if (!dn)
-		return 0;
-
-	if (of_get_nand_bus_width(dn) == 16)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	if (of_get_nand_on_flash_bbt(dn))
-		chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-	ecc_mode = of_get_nand_ecc_mode(dn);
-	ecc_algo = of_get_nand_ecc_algo(dn);
-	ecc_strength = of_get_nand_ecc_strength(dn);
-	ecc_step = of_get_nand_ecc_step_size(dn);
-
-	if (ecc_mode >= 0)
-		chip->ecc.mode = ecc_mode;
-
-	if (ecc_algo >= 0)
-		chip->ecc.algo = ecc_algo;
-
-	if (ecc_strength >= 0)
-		chip->ecc.strength = ecc_strength;
-
-	if (ecc_step > 0)
-		chip->ecc.size = ecc_step;
-
-	if (of_property_read_bool(dn, "nand-ecc-maximize"))
-		chip->ecc.options |= NAND_ECC_MAXIMIZE;
-
-	return 0;
-}
-
-/**
- * nand_scan_ident - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: number of chips to scan for
- * @table: alternative NAND ID table
- *
- * This is the first phase of the normal nand_scan() function. It reads the
- * flash ID and sets up MTD fields accordingly.
- *
- */
-int nand_scan_ident(struct mtd_info *mtd, int maxchips,
-		    struct nand_flash_dev *table)
-{
-	int i, nand_maf_id, nand_dev_id;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	/* Enforce the right timings for reset/detection */
-	onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
-
-	ret = nand_dt_init(chip);
-	if (ret)
-		return ret;
-
-	if (!mtd->name && mtd->dev.parent)
-		mtd->name = dev_name(mtd->dev.parent);
-
-	/*
-	 * ->cmdfunc() is legacy and will only be used if ->exec_op() is not
-	 * populated.
-	 */
-	if (!chip->exec_op) {
-		/*
-		 * Default functions assigned for ->cmdfunc() and
-		 * ->select_chip() both expect ->cmd_ctrl() to be populated.
-		 */
-		if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
-			pr_err("->cmd_ctrl() should be provided\n");
-			return -EINVAL;
-		}
-	}
-
-	/* Set the default functions */
-	nand_set_defaults(chip);
-
-	/* Read the flash type */
-	ret = nand_detect(chip, table);
-	if (ret) {
-		if (!(chip->options & NAND_SCAN_SILENT_NODEV))
-			pr_warn("No NAND device found\n");
-		chip->select_chip(mtd, -1);
-		return ret;
-	}
-
-	nand_maf_id = chip->id.data[0];
-	nand_dev_id = chip->id.data[1];
-
-	chip->select_chip(mtd, -1);
-
-	/* Check for a chip array */
-	for (i = 1; i < maxchips; i++) {
-		u8 id[2];
-
-		/* See comment in nand_get_flash_type for reset */
-		nand_reset(chip, i);
-
-		chip->select_chip(mtd, i);
-		/* Send the command for reading device ID */
-		nand_readid_op(chip, 0, id, sizeof(id));
-		/* Read manufacturer and device IDs */
-		if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
-			chip->select_chip(mtd, -1);
-			break;
-		}
-		chip->select_chip(mtd, -1);
-	}
-	if (i > 1)
-		pr_info("%d chips detected\n", i);
-
-	/* Store the number of chips and calc total size for mtd */
-	chip->numchips = i;
-	mtd->size = i * chip->chipsize;
-
-	return 0;
-}
-EXPORT_SYMBOL(nand_scan_ident);
-
-static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
-		return -EINVAL;
-
-	switch (ecc->algo) {
-	case NAND_ECC_HAMMING:
-		ecc->calculate = nand_calculate_ecc;
-		ecc->correct = nand_correct_data;
-		ecc->read_page = nand_read_page_swecc;
-		ecc->read_subpage = nand_read_subpage;
-		ecc->write_page = nand_write_page_swecc;
-		ecc->read_page_raw = nand_read_page_raw;
-		ecc->write_page_raw = nand_write_page_raw;
-		ecc->read_oob = nand_read_oob_std;
-		ecc->write_oob = nand_write_oob_std;
-		if (!ecc->size)
-			ecc->size = 256;
-		ecc->bytes = 3;
-		ecc->strength = 1;
-		return 0;
-	case NAND_ECC_BCH:
-		if (!mtd_nand_has_bch()) {
-			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
-			return -EINVAL;
-		}
-		ecc->calculate = nand_bch_calculate_ecc;
-		ecc->correct = nand_bch_correct_data;
-		ecc->read_page = nand_read_page_swecc;
-		ecc->read_subpage = nand_read_subpage;
-		ecc->write_page = nand_write_page_swecc;
-		ecc->read_page_raw = nand_read_page_raw;
-		ecc->write_page_raw = nand_write_page_raw;
-		ecc->read_oob = nand_read_oob_std;
-		ecc->write_oob = nand_write_oob_std;
-
-		/*
-		* Board driver should supply ecc.size and ecc.strength
-		* values to select how many bits are correctable.
-		* Otherwise, default to 4 bits for large page devices.
-		*/
-		if (!ecc->size && (mtd->oobsize >= 64)) {
-			ecc->size = 512;
-			ecc->strength = 4;
-		}
-
-		/*
-		 * if no ecc placement scheme was provided pickup the default
-		 * large page one.
-		 */
-		if (!mtd->ooblayout) {
-			/* handle large page devices only */
-			if (mtd->oobsize < 64) {
-				WARN(1, "OOB layout is required when using software BCH on small pages\n");
-				return -EINVAL;
-			}
-
-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-
-		}
-
-		/*
-		 * We can only maximize ECC config when the default layout is
-		 * used, otherwise we don't know how many bytes can really be
-		 * used.
-		 */
-		if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
-		    ecc->options & NAND_ECC_MAXIMIZE) {
-			int steps, bytes;
-
-			/* Always prefer 1k blocks over 512bytes ones */
-			ecc->size = 1024;
-			steps = mtd->writesize / ecc->size;
-
-			/* Reserve 2 bytes for the BBM */
-			bytes = (mtd->oobsize - 2) / steps;
-			ecc->strength = bytes * 8 / fls(8 * ecc->size);
-		}
-
-		/* See nand_bch_init() for details. */
-		ecc->bytes = 0;
-		ecc->priv = nand_bch_init(mtd);
-		if (!ecc->priv) {
-			WARN(1, "BCH ECC initialization failed!\n");
-			return -EINVAL;
-		}
-		return 0;
-	default:
-		WARN(1, "Unsupported ECC algorithm!\n");
-		return -EINVAL;
-	}
-}
-
-/**
- * nand_check_ecc_caps - check the sanity of preset ECC settings
- * @chip: nand chip info structure
- * @caps: ECC caps info structure
- * @oobavail: OOB size that the ECC engine can use
- *
- * When ECC step size and strength are already set, check if they are supported
- * by the controller and the calculated ECC bytes fit within the chip's OOB.
- * On success, the calculated ECC bytes is set.
- */
-int nand_check_ecc_caps(struct nand_chip *chip,
-			const struct nand_ecc_caps *caps, int oobavail)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const struct nand_ecc_step_info *stepinfo;
-	int preset_step = chip->ecc.size;
-	int preset_strength = chip->ecc.strength;
-	int nsteps, ecc_bytes;
-	int i, j;
-
-	if (WARN_ON(oobavail < 0))
-		return -EINVAL;
-
-	if (!preset_step || !preset_strength)
-		return -ENODATA;
-
-	nsteps = mtd->writesize / preset_step;
-
-	for (i = 0; i < caps->nstepinfos; i++) {
-		stepinfo = &caps->stepinfos[i];
-
-		if (stepinfo->stepsize != preset_step)
-			continue;
-
-		for (j = 0; j < stepinfo->nstrengths; j++) {
-			if (stepinfo->strengths[j] != preset_strength)
-				continue;
-
-			ecc_bytes = caps->calc_ecc_bytes(preset_step,
-							 preset_strength);
-			if (WARN_ON_ONCE(ecc_bytes < 0))
-				return ecc_bytes;
-
-			if (ecc_bytes * nsteps > oobavail) {
-				pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
-				       preset_step, preset_strength);
-				return -ENOSPC;
-			}
-
-			chip->ecc.bytes = ecc_bytes;
-
-			return 0;
-		}
-	}
-
-	pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
-	       preset_step, preset_strength);
-
-	return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
-
-/**
- * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
- * @chip: nand chip info structure
- * @caps: ECC engine caps info structure
- * @oobavail: OOB size that the ECC engine can use
- *
- * If a chip's ECC requirement is provided, try to meet it with the least
- * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
- * On success, the chosen ECC settings are set.
- */
-int nand_match_ecc_req(struct nand_chip *chip,
-		       const struct nand_ecc_caps *caps, int oobavail)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const struct nand_ecc_step_info *stepinfo;
-	int req_step = chip->ecc_step_ds;
-	int req_strength = chip->ecc_strength_ds;
-	int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
-	int best_step, best_strength, best_ecc_bytes;
-	int best_ecc_bytes_total = INT_MAX;
-	int i, j;
-
-	if (WARN_ON(oobavail < 0))
-		return -EINVAL;
-
-	/* No information provided by the NAND chip */
-	if (!req_step || !req_strength)
-		return -ENOTSUPP;
-
-	/* number of correctable bits the chip requires in a page */
-	req_corr = mtd->writesize / req_step * req_strength;
-
-	for (i = 0; i < caps->nstepinfos; i++) {
-		stepinfo = &caps->stepinfos[i];
-		step_size = stepinfo->stepsize;
-
-		for (j = 0; j < stepinfo->nstrengths; j++) {
-			strength = stepinfo->strengths[j];
-
-			/*
-			 * If both step size and strength are smaller than the
-			 * chip's requirement, it is not easy to compare the
-			 * resulted reliability.
-			 */
-			if (step_size < req_step && strength < req_strength)
-				continue;
-
-			if (mtd->writesize % step_size)
-				continue;
-
-			nsteps = mtd->writesize / step_size;
-
-			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
-			if (WARN_ON_ONCE(ecc_bytes < 0))
-				continue;
-			ecc_bytes_total = ecc_bytes * nsteps;
-
-			if (ecc_bytes_total > oobavail ||
-			    strength * nsteps < req_corr)
-				continue;
-
-			/*
-			 * We assume the best is to meet the chip's requrement
-			 * with the least number of ECC bytes.
-			 */
-			if (ecc_bytes_total < best_ecc_bytes_total) {
-				best_ecc_bytes_total = ecc_bytes_total;
-				best_step = step_size;
-				best_strength = strength;
-				best_ecc_bytes = ecc_bytes;
-			}
-		}
-	}
-
-	if (best_ecc_bytes_total == INT_MAX)
-		return -ENOTSUPP;
-
-	chip->ecc.size = best_step;
-	chip->ecc.strength = best_strength;
-	chip->ecc.bytes = best_ecc_bytes;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_match_ecc_req);
-
-/**
- * nand_maximize_ecc - choose the max ECC strength available
- * @chip: nand chip info structure
- * @caps: ECC engine caps info structure
- * @oobavail: OOB size that the ECC engine can use
- *
- * Choose the max ECC strength that is supported on the controller, and can fit
- * within the chip's OOB.  On success, the chosen ECC settings are set.
- */
-int nand_maximize_ecc(struct nand_chip *chip,
-		      const struct nand_ecc_caps *caps, int oobavail)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const struct nand_ecc_step_info *stepinfo;
-	int step_size, strength, nsteps, ecc_bytes, corr;
-	int best_corr = 0;
-	int best_step = 0;
-	int best_strength, best_ecc_bytes;
-	int i, j;
-
-	if (WARN_ON(oobavail < 0))
-		return -EINVAL;
-
-	for (i = 0; i < caps->nstepinfos; i++) {
-		stepinfo = &caps->stepinfos[i];
-		step_size = stepinfo->stepsize;
-
-		/* If chip->ecc.size is already set, respect it */
-		if (chip->ecc.size && step_size != chip->ecc.size)
-			continue;
-
-		for (j = 0; j < stepinfo->nstrengths; j++) {
-			strength = stepinfo->strengths[j];
-
-			if (mtd->writesize % step_size)
-				continue;
-
-			nsteps = mtd->writesize / step_size;
-
-			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
-			if (WARN_ON_ONCE(ecc_bytes < 0))
-				continue;
-
-			if (ecc_bytes * nsteps > oobavail)
-				continue;
-
-			corr = strength * nsteps;
-
-			/*
-			 * If the number of correctable bits is the same,
-			 * bigger step_size has more reliability.
-			 */
-			if (corr > best_corr ||
-			    (corr == best_corr && step_size > best_step)) {
-				best_corr = corr;
-				best_step = step_size;
-				best_strength = strength;
-				best_ecc_bytes = ecc_bytes;
-			}
-		}
-	}
-
-	if (!best_corr)
-		return -ENOTSUPP;
-
-	chip->ecc.size = best_step;
-	chip->ecc.strength = best_strength;
-	chip->ecc.bytes = best_ecc_bytes;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nand_maximize_ecc);
-
-/*
- * Check if the chip configuration meet the datasheet requirements.
-
- * If our configuration corrects A bits per B bytes and the minimum
- * required correction level is X bits per Y bytes, then we must ensure
- * both of the following are true:
- *
- * (1) A / B >= X / Y
- * (2) A >= X
- *
- * Requirement (1) ensures we can correct for the required bitflip density.
- * Requirement (2) ensures we can correct even when all bitflips are clumped
- * in the same sector.
- */
-static bool nand_ecc_strength_good(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int corr, ds_corr;
-
-	if (ecc->size == 0 || chip->ecc_step_ds == 0)
-		/* Not enough information */
-		return true;
-
-	/*
-	 * We get the number of corrected bits per page to compare
-	 * the correction density.
-	 */
-	corr = (mtd->writesize * ecc->strength) / ecc->size;
-	ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds;
-
-	return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
-}
-
-/**
- * nand_scan_tail - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- *
- * This is the second phase of the normal nand_scan() function. It fills out
- * all the uninitialized function pointers with the defaults and scans for a
- * bad block table if appropriate.
- */
-int nand_scan_tail(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ret, i;
-
-	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
-	if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
-		   !(chip->bbt_options & NAND_BBT_USE_FLASH))) {
-		return -EINVAL;
-	}
-
-	chip->data_buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
-	if (!chip->data_buf)
-		return -ENOMEM;
-
-	/*
-	 * FIXME: some NAND manufacturer drivers expect the first die to be
-	 * selected when manufacturer->init() is called. They should be fixed
-	 * to explictly select the relevant die when interacting with the NAND
-	 * chip.
-	 */
-	chip->select_chip(mtd, 0);
-	ret = nand_manufacturer_init(chip);
-	chip->select_chip(mtd, -1);
-	if (ret)
-		goto err_free_buf;
-
-	/* Set the internal oob buffer location, just after the page data */
-	chip->oob_poi = chip->data_buf + mtd->writesize;
-
-	/*
-	 * If no default placement scheme is given, select an appropriate one.
-	 */
-	if (!mtd->ooblayout &&
-	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
-		switch (mtd->oobsize) {
-		case 8:
-		case 16:
-			mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
-			break;
-		case 64:
-		case 128:
-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
-			break;
-		default:
-			/*
-			 * Expose the whole OOB area to users if ECC_NONE
-			 * is passed. We could do that for all kind of
-			 * ->oobsize, but we must keep the old large/small
-			 * page with ECC layout when ->oobsize <= 128 for
-			 * compatibility reasons.
-			 */
-			if (ecc->mode == NAND_ECC_NONE) {
-				mtd_set_ooblayout(mtd,
-						&nand_ooblayout_lp_ops);
-				break;
-			}
-
-			WARN(1, "No oob scheme defined for oobsize %d\n",
-				mtd->oobsize);
-			ret = -EINVAL;
-			goto err_nand_manuf_cleanup;
-		}
-	}
-
-	/*
-	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
-	 * selected and we have 256 byte pagesize fallback to software ECC
-	 */
-
-	switch (ecc->mode) {
-	case NAND_ECC_HW_OOB_FIRST:
-		/* Similar to NAND_ECC_HW, but a separate read_page handle */
-		if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
-			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
-			ret = -EINVAL;
-			goto err_nand_manuf_cleanup;
-		}
-		if (!ecc->read_page)
-			ecc->read_page = nand_read_page_hwecc_oob_first;
-
-	case NAND_ECC_HW:
-		/* Use standard hwecc read page function? */
-		if (!ecc->read_page)
-			ecc->read_page = nand_read_page_hwecc;
-		if (!ecc->write_page)
-			ecc->write_page = nand_write_page_hwecc;
-		if (!ecc->read_page_raw)
-			ecc->read_page_raw = nand_read_page_raw;
-		if (!ecc->write_page_raw)
-			ecc->write_page_raw = nand_write_page_raw;
-		if (!ecc->read_oob)
-			ecc->read_oob = nand_read_oob_std;
-		if (!ecc->write_oob)
-			ecc->write_oob = nand_write_oob_std;
-		if (!ecc->read_subpage)
-			ecc->read_subpage = nand_read_subpage;
-		if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
-			ecc->write_subpage = nand_write_subpage_hwecc;
-
-	case NAND_ECC_HW_SYNDROME:
-		if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
-		    (!ecc->read_page ||
-		     ecc->read_page == nand_read_page_hwecc ||
-		     !ecc->write_page ||
-		     ecc->write_page == nand_write_page_hwecc)) {
-			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
-			ret = -EINVAL;
-			goto err_nand_manuf_cleanup;
-		}
-		/* Use standard syndrome read/write page function? */
-		if (!ecc->read_page)
-			ecc->read_page = nand_read_page_syndrome;
-		if (!ecc->write_page)
-			ecc->write_page = nand_write_page_syndrome;
-		if (!ecc->read_page_raw)
-			ecc->read_page_raw = nand_read_page_raw_syndrome;
-		if (!ecc->write_page_raw)
-			ecc->write_page_raw = nand_write_page_raw_syndrome;
-		if (!ecc->read_oob)
-			ecc->read_oob = nand_read_oob_syndrome;
-		if (!ecc->write_oob)
-			ecc->write_oob = nand_write_oob_syndrome;
-
-		if (mtd->writesize >= ecc->size) {
-			if (!ecc->strength) {
-				WARN(1, "Driver must set ecc.strength when using hardware ECC\n");
-				ret = -EINVAL;
-				goto err_nand_manuf_cleanup;
-			}
-			break;
-		}
-		pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
-			ecc->size, mtd->writesize);
-		ecc->mode = NAND_ECC_SOFT;
-		ecc->algo = NAND_ECC_HAMMING;
-
-	case NAND_ECC_SOFT:
-		ret = nand_set_ecc_soft_ops(mtd);
-		if (ret) {
-			ret = -EINVAL;
-			goto err_nand_manuf_cleanup;
-		}
-		break;
-
-	case NAND_ECC_ON_DIE:
-		if (!ecc->read_page || !ecc->write_page) {
-			WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
-			ret = -EINVAL;
-			goto err_nand_manuf_cleanup;
-		}
-		if (!ecc->read_oob)
-			ecc->read_oob = nand_read_oob_std;
-		if (!ecc->write_oob)
-			ecc->write_oob = nand_write_oob_std;
-		break;
-
-	case NAND_ECC_NONE:
-		pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
-		ecc->read_page = nand_read_page_raw;
-		ecc->write_page = nand_write_page_raw;
-		ecc->read_oob = nand_read_oob_std;
-		ecc->read_page_raw = nand_read_page_raw;
-		ecc->write_page_raw = nand_write_page_raw;
-		ecc->write_oob = nand_write_oob_std;
-		ecc->size = mtd->writesize;
-		ecc->bytes = 0;
-		ecc->strength = 0;
-		break;
-
-	default:
-		WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode);
-		ret = -EINVAL;
-		goto err_nand_manuf_cleanup;
-	}
-
-	if (ecc->correct || ecc->calculate) {
-		ecc->calc_buf = kmalloc(mtd->oobsize, GFP_KERNEL);
-		ecc->code_buf = kmalloc(mtd->oobsize, GFP_KERNEL);
-		if (!ecc->calc_buf || !ecc->code_buf) {
-			ret = -ENOMEM;
-			goto err_nand_manuf_cleanup;
-		}
-	}
-
-	/* For many systems, the standard OOB write also works for raw */
-	if (!ecc->read_oob_raw)
-		ecc->read_oob_raw = ecc->read_oob;
-	if (!ecc->write_oob_raw)
-		ecc->write_oob_raw = ecc->write_oob;
-
-	/* propagate ecc info to mtd_info */
-	mtd->ecc_strength = ecc->strength;
-	mtd->ecc_step_size = ecc->size;
-
-	/*
-	 * Set the number of read / write steps for one page depending on ECC
-	 * mode.
-	 */
-	ecc->steps = mtd->writesize / ecc->size;
-	if (ecc->steps * ecc->size != mtd->writesize) {
-		WARN(1, "Invalid ECC parameters\n");
-		ret = -EINVAL;
-		goto err_nand_manuf_cleanup;
-	}
-	ecc->total = ecc->steps * ecc->bytes;
-	if (ecc->total > mtd->oobsize) {
-		WARN(1, "Total number of ECC bytes exceeded oobsize\n");
-		ret = -EINVAL;
-		goto err_nand_manuf_cleanup;
-	}
-
-	/*
-	 * The number of bytes available for a client to place data into
-	 * the out of band area.
-	 */
-	ret = mtd_ooblayout_count_freebytes(mtd);
-	if (ret < 0)
-		ret = 0;
-
-	mtd->oobavail = ret;
-
-	/* ECC sanity check: warn if it's too weak */
-	if (!nand_ecc_strength_good(mtd))
-		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
-			mtd->name);
-
-	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
-	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
-		switch (ecc->steps) {
-		case 2:
-			mtd->subpage_sft = 1;
-			break;
-		case 4:
-		case 8:
-		case 16:
-			mtd->subpage_sft = 2;
-			break;
-		}
-	}
-	chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
-
-	/* Initialize state */
-	chip->state = FL_READY;
-
-	/* Invalidate the pagebuffer reference */
-	chip->pagebuf = -1;
-
-	/* Large page NAND with SOFT_ECC should support subpage reads */
-	switch (ecc->mode) {
-	case NAND_ECC_SOFT:
-		if (chip->page_shift > 9)
-			chip->options |= NAND_SUBPAGE_READ;
-		break;
-
-	default:
-		break;
-	}
-
-	/* Fill in remaining MTD driver data */
-	mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
-	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
-						MTD_CAP_NANDFLASH;
-	mtd->_erase = nand_erase;
-	mtd->_point = NULL;
-	mtd->_unpoint = NULL;
-	mtd->_panic_write = panic_nand_write;
-	mtd->_read_oob = nand_read_oob;
-	mtd->_write_oob = nand_write_oob;
-	mtd->_sync = nand_sync;
-	mtd->_lock = NULL;
-	mtd->_unlock = NULL;
-	mtd->_suspend = nand_suspend;
-	mtd->_resume = nand_resume;
-	mtd->_reboot = nand_shutdown;
-	mtd->_block_isreserved = nand_block_isreserved;
-	mtd->_block_isbad = nand_block_isbad;
-	mtd->_block_markbad = nand_block_markbad;
-	mtd->_max_bad_blocks = nand_max_bad_blocks;
-	mtd->writebufsize = mtd->writesize;
-
-	/*
-	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
-	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
-	 * properly set.
-	 */
-	if (!mtd->bitflip_threshold)
-		mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
-
-	/* Initialize the ->data_interface field. */
-	ret = nand_init_data_interface(chip);
-	if (ret)
-		goto err_nand_manuf_cleanup;
-
-	/* Enter fastest possible mode on all dies. */
-	for (i = 0; i < chip->numchips; i++) {
-		chip->select_chip(mtd, i);
-		ret = nand_setup_data_interface(chip, i);
-		chip->select_chip(mtd, -1);
-
-		if (ret)
-			goto err_nand_manuf_cleanup;
-	}
-
-	/* Check, if we should skip the bad block table scan */
-	if (chip->options & NAND_SKIP_BBTSCAN)
-		return 0;
-
-	/* Build bad block table */
-	ret = chip->scan_bbt(mtd);
-	if (ret)
-		goto err_nand_manuf_cleanup;
-
-	return 0;
-
-
-err_nand_manuf_cleanup:
-	nand_manufacturer_cleanup(chip);
-
-err_free_buf:
-	kfree(chip->data_buf);
-	kfree(ecc->code_buf);
-	kfree(ecc->calc_buf);
-
-	return ret;
-}
-EXPORT_SYMBOL(nand_scan_tail);
-
-/*
- * is_module_text_address() isn't exported, and it's mostly a pointless
- * test if this is a module _anyway_ -- they'd have to try _really_ hard
- * to call us from in-kernel code if the core NAND support is modular.
- */
-#ifdef MODULE
-#define caller_is_module() (1)
-#else
-#define caller_is_module() \
-	is_module_text_address((unsigned long)__builtin_return_address(0))
-#endif
-
-/**
- * nand_scan - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: number of chips to scan for
- *
- * This fills out all the uninitialized function pointers with the defaults.
- * The flash ID is read and the mtd/chip structures are filled with the
- * appropriate values.
- */
-int nand_scan(struct mtd_info *mtd, int maxchips)
-{
-	int ret;
-
-	ret = nand_scan_ident(mtd, maxchips, NULL);
-	if (!ret)
-		ret = nand_scan_tail(mtd);
-	return ret;
-}
-EXPORT_SYMBOL(nand_scan);
-
-/**
- * nand_cleanup - [NAND Interface] Free resources held by the NAND device
- * @chip: NAND chip object
- */
-void nand_cleanup(struct nand_chip *chip)
-{
-	if (chip->ecc.mode == NAND_ECC_SOFT &&
-	    chip->ecc.algo == NAND_ECC_BCH)
-		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
-
-	/* Free bad block table memory */
-	kfree(chip->bbt);
-	kfree(chip->data_buf);
-	kfree(chip->ecc.code_buf);
-	kfree(chip->ecc.calc_buf);
-
-	/* Free bad block descriptor memory */
-	if (chip->badblock_pattern && chip->badblock_pattern->options
-			& NAND_BBT_DYNAMICSTRUCT)
-		kfree(chip->badblock_pattern);
-
-	/* Free manufacturer priv data. */
-	nand_manufacturer_cleanup(chip);
-}
-EXPORT_SYMBOL_GPL(nand_cleanup);
-
-/**
- * nand_release - [NAND Interface] Unregister the MTD device and free resources
- *		  held by the NAND device
- * @mtd: MTD device structure
- */
-void nand_release(struct mtd_info *mtd)
-{
-	mtd_device_unregister(mtd);
-	nand_cleanup(mtd_to_nand(mtd));
-}
-EXPORT_SYMBOL_GPL(nand_release);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
-MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Generic NAND flash driver code");
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
deleted file mode 100644
index 36092850be2c..000000000000
--- a/drivers/mtd/nand/nand_bbt.c
+++ /dev/null
@@ -1,1452 +0,0 @@
-/*
- *  Overview:
- *   Bad block table support for the NAND driver
- *
- *  Copyright © 2004 Thomas Gleixner (tglx@linutronix.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.
- *
- * Description:
- *
- * When nand_scan_bbt is called, then it tries to find the bad block table
- * depending on the options in the BBT descriptor(s). If no flash based BBT
- * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
- * marked good / bad blocks. This information is used to create a memory BBT.
- * Once a new bad block is discovered then the "factory" information is updated
- * on the device.
- * If a flash based BBT is specified then the function first tries to find the
- * BBT on flash. If a BBT is found then the contents are read and the memory
- * based BBT is created. If a mirrored BBT is selected then the mirror is
- * searched too and the versions are compared. If the mirror has a greater
- * version number, then the mirror BBT is used to build the memory based BBT.
- * If the tables are not versioned, then we "or" the bad block information.
- * If one of the BBTs is out of date or does not exist it is (re)created.
- * If no BBT exists at all then the device is scanned for factory marked
- * good / bad blocks and the bad block tables are created.
- *
- * For manufacturer created BBTs like the one found on M-SYS DOC devices
- * the BBT is searched and read but never created
- *
- * The auto generated bad block table is located in the last good blocks
- * of the device. The table is mirrored, so it can be updated eventually.
- * The table is marked in the OOB area with an ident pattern and a version
- * number which indicates which of both tables is more up to date. If the NAND
- * controller needs the complete OOB area for the ECC information then the
- * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
- * course): it moves the ident pattern and the version byte into the data area
- * and the OOB area will remain untouched.
- *
- * The table uses 2 bits per block
- * 11b:		block is good
- * 00b:		block is factory marked bad
- * 01b, 10b:	block is marked bad due to wear
- *
- * The memory bad block table uses the following scheme:
- * 00b:		block is good
- * 01b:		block is marked bad due to wear
- * 10b:		block is reserved (to protect the bbt area)
- * 11b:		block is factory marked bad
- *
- * Multichip devices like DOC store the bad block info per floor.
- *
- * Following assumptions are made:
- * - bbts start at a page boundary, if autolocated on a block boundary
- * - the space necessary for a bbt in FLASH does not exceed a block boundary
- *
- */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/bbm.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/vmalloc.h>
-#include <linux/export.h>
-#include <linux/string.h>
-
-#define BBT_BLOCK_GOOD		0x00
-#define BBT_BLOCK_WORN		0x01
-#define BBT_BLOCK_RESERVED	0x02
-#define BBT_BLOCK_FACTORY_BAD	0x03
-
-#define BBT_ENTRY_MASK		0x03
-#define BBT_ENTRY_SHIFT		2
-
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
-
-static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
-{
-	uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
-	entry >>= (block & BBT_ENTRY_MASK) * 2;
-	return entry & BBT_ENTRY_MASK;
-}
-
-static inline void bbt_mark_entry(struct nand_chip *chip, int block,
-		uint8_t mark)
-{
-	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
-	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
-}
-
-static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
-{
-	if (memcmp(buf, td->pattern, td->len))
-		return -1;
-	return 0;
-}
-
-/**
- * check_pattern - [GENERIC] check if a pattern is in the buffer
- * @buf: the buffer to search
- * @len: the length of buffer to search
- * @paglen: the pagelength
- * @td: search pattern descriptor
- *
- * Check for a pattern at the given place. Used to search bad block tables and
- * good / bad block identifiers.
- */
-static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
-{
-	if (td->options & NAND_BBT_NO_OOB)
-		return check_pattern_no_oob(buf, td);
-
-	/* Compare the pattern */
-	if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
-		return -1;
-
-	return 0;
-}
-
-/**
- * check_short_pattern - [GENERIC] check if a pattern is in the buffer
- * @buf: the buffer to search
- * @td:	search pattern descriptor
- *
- * Check for a pattern at the given place. Used to search bad block tables and
- * good / bad block identifiers. Same as check_pattern, but no optional empty
- * check.
- */
-static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
-{
-	/* Compare the pattern */
-	if (memcmp(buf + td->offs, td->pattern, td->len))
-		return -1;
-	return 0;
-}
-
-/**
- * add_marker_len - compute the length of the marker in data area
- * @td: BBT descriptor used for computation
- *
- * The length will be 0 if the marker is located in OOB area.
- */
-static u32 add_marker_len(struct nand_bbt_descr *td)
-{
-	u32 len;
-
-	if (!(td->options & NAND_BBT_NO_OOB))
-		return 0;
-
-	len = td->len;
-	if (td->options & NAND_BBT_VERSION)
-		len++;
-	return len;
-}
-
-/**
- * read_bbt - [GENERIC] Read the bad block table starting from page
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @page: the starting page
- * @num: the number of bbt descriptors to read
- * @td: the bbt describtion table
- * @offs: block number offset in the table
- *
- * Read the bad block table starting from page.
- */
-static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
-		struct nand_bbt_descr *td, int offs)
-{
-	int res, ret = 0, i, j, act = 0;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	size_t retlen, len, totlen;
-	loff_t from;
-	int bits = td->options & NAND_BBT_NRBITS_MSK;
-	uint8_t msk = (uint8_t)((1 << bits) - 1);
-	u32 marker_len;
-	int reserved_block_code = td->reserved_block_code;
-
-	totlen = (num * bits) >> 3;
-	marker_len = add_marker_len(td);
-	from = ((loff_t)page) << this->page_shift;
-
-	while (totlen) {
-		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
-		if (marker_len) {
-			/*
-			 * In case the BBT marker is not in the OOB area it
-			 * will be just in the first page.
-			 */
-			len -= marker_len;
-			from += marker_len;
-			marker_len = 0;
-		}
-		res = mtd_read(mtd, from, len, &retlen, buf);
-		if (res < 0) {
-			if (mtd_is_eccerr(res)) {
-				pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
-					from & ~mtd->writesize);
-				return res;
-			} else if (mtd_is_bitflip(res)) {
-				pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
-					from & ~mtd->writesize);
-				ret = res;
-			} else {
-				pr_info("nand_bbt: error reading BBT\n");
-				return res;
-			}
-		}
-
-		/* Analyse data */
-		for (i = 0; i < len; i++) {
-			uint8_t dat = buf[i];
-			for (j = 0; j < 8; j += bits, act++) {
-				uint8_t tmp = (dat >> j) & msk;
-				if (tmp == msk)
-					continue;
-				if (reserved_block_code && (tmp == reserved_block_code)) {
-					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
-						 (loff_t)(offs + act) <<
-						 this->bbt_erase_shift);
-					bbt_mark_entry(this, offs + act,
-							BBT_BLOCK_RESERVED);
-					mtd->ecc_stats.bbtblocks++;
-					continue;
-				}
-				/*
-				 * Leave it for now, if it's matured we can
-				 * move this message to pr_debug.
-				 */
-				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
-					 (loff_t)(offs + act) <<
-					 this->bbt_erase_shift);
-				/* Factory marked bad or worn out? */
-				if (tmp == 0)
-					bbt_mark_entry(this, offs + act,
-							BBT_BLOCK_FACTORY_BAD);
-				else
-					bbt_mark_entry(this, offs + act,
-							BBT_BLOCK_WORN);
-				mtd->ecc_stats.badblocks++;
-			}
-		}
-		totlen -= len;
-		from += len;
-	}
-	return ret;
-}
-
-/**
- * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @td: descriptor for the bad block table
- * @chip: read the table for a specific chip, -1 read all chips; applies only if
- *        NAND_BBT_PERCHIP option is set
- *
- * Read the bad block table for all chips starting at a given page. We assume
- * that the bbt bits are in consecutive order.
- */
-static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int res = 0, i;
-
-	if (td->options & NAND_BBT_PERCHIP) {
-		int offs = 0;
-		for (i = 0; i < this->numchips; i++) {
-			if (chip == -1 || chip == i)
-				res = read_bbt(mtd, buf, td->pages[i],
-					this->chipsize >> this->bbt_erase_shift,
-					td, offs);
-			if (res)
-				return res;
-			offs += this->chipsize >> this->bbt_erase_shift;
-		}
-	} else {
-		res = read_bbt(mtd, buf, td->pages[0],
-				mtd->size >> this->bbt_erase_shift, td, 0);
-		if (res)
-			return res;
-	}
-	return 0;
-}
-
-/* BBT marker is in the first page, no OOB */
-static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-			 struct nand_bbt_descr *td)
-{
-	size_t retlen;
-	size_t len;
-
-	len = td->len;
-	if (td->options & NAND_BBT_VERSION)
-		len++;
-
-	return mtd_read(mtd, offs, len, &retlen, buf);
-}
-
-/**
- * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @offs: offset at which to scan
- * @len: length of data region to read
- *
- * Scan read data from data+OOB. May traverse multiple pages, interleaving
- * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
- * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
- */
-static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-			 size_t len)
-{
-	struct mtd_oob_ops ops;
-	int res, ret = 0;
-
-	ops.mode = MTD_OPS_PLACE_OOB;
-	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
-
-	while (len > 0) {
-		ops.datbuf = buf;
-		ops.len = min(len, (size_t)mtd->writesize);
-		ops.oobbuf = buf + ops.len;
-
-		res = mtd_read_oob(mtd, offs, &ops);
-		if (res) {
-			if (!mtd_is_bitflip_or_eccerr(res))
-				return res;
-			else if (mtd_is_eccerr(res) || !ret)
-				ret = res;
-		}
-
-		buf += mtd->oobsize + mtd->writesize;
-		len -= mtd->writesize;
-		offs += mtd->writesize;
-	}
-	return ret;
-}
-
-static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
-			 size_t len, struct nand_bbt_descr *td)
-{
-	if (td->options & NAND_BBT_NO_OOB)
-		return scan_read_data(mtd, buf, offs, td);
-	else
-		return scan_read_oob(mtd, buf, offs, len);
-}
-
-/* Scan write data with oob to flash */
-static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
-			  uint8_t *buf, uint8_t *oob)
-{
-	struct mtd_oob_ops ops;
-
-	ops.mode = MTD_OPS_PLACE_OOB;
-	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
-	ops.datbuf = buf;
-	ops.oobbuf = oob;
-	ops.len = len;
-
-	return mtd_write_oob(mtd, offs, &ops);
-}
-
-static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
-{
-	u32 ver_offs = td->veroffs;
-
-	if (!(td->options & NAND_BBT_NO_OOB))
-		ver_offs += mtd->writesize;
-	return ver_offs;
-}
-
-/**
- * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @td: descriptor for the bad block table
- * @md:	descriptor for the bad block table mirror
- *
- * Read the bad block table(s) for all chips starting at a given page. We
- * assume that the bbt bits are in consecutive order.
- */
-static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
-			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	/* Read the primary version, if available */
-	if (td->options & NAND_BBT_VERSION) {
-		scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
-			      mtd->writesize, td);
-		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
-		pr_info("Bad block table at page %d, version 0x%02X\n",
-			 td->pages[0], td->version[0]);
-	}
-
-	/* Read the mirror version, if available */
-	if (md && (md->options & NAND_BBT_VERSION)) {
-		scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
-			      mtd->writesize, md);
-		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
-		pr_info("Bad block table at page %d, version 0x%02X\n",
-			 md->pages[0], md->version[0]);
-	}
-}
-
-/* Scan a given block partially */
-static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
-			   loff_t offs, uint8_t *buf, int numpages)
-{
-	struct mtd_oob_ops ops;
-	int j, ret;
-
-	ops.ooblen = mtd->oobsize;
-	ops.oobbuf = buf;
-	ops.ooboffs = 0;
-	ops.datbuf = NULL;
-	ops.mode = MTD_OPS_PLACE_OOB;
-
-	for (j = 0; j < numpages; j++) {
-		/*
-		 * Read the full oob until read_oob is fixed to handle single
-		 * byte reads for 16 bit buswidth.
-		 */
-		ret = mtd_read_oob(mtd, offs, &ops);
-		/* Ignore ECC errors when checking for BBM */
-		if (ret && !mtd_is_bitflip_or_eccerr(ret))
-			return ret;
-
-		if (check_short_pattern(buf, bd))
-			return 1;
-
-		offs += mtd->writesize;
-	}
-	return 0;
-}
-
-/**
- * create_bbt - [GENERIC] Create a bad block table by scanning the device
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @bd: descriptor for the good/bad block search pattern
- * @chip: create the table for a specific chip, -1 read all chips; applies only
- *        if NAND_BBT_PERCHIP option is set
- *
- * Create a bad block table by scanning the device for the given good/bad block
- * identify pattern.
- */
-static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
-	struct nand_bbt_descr *bd, int chip)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int i, numblocks, numpages;
-	int startblock;
-	loff_t from;
-
-	pr_info("Scanning device for bad blocks\n");
-
-	if (bd->options & NAND_BBT_SCAN2NDPAGE)
-		numpages = 2;
-	else
-		numpages = 1;
-
-	if (chip == -1) {
-		numblocks = mtd->size >> this->bbt_erase_shift;
-		startblock = 0;
-		from = 0;
-	} else {
-		if (chip >= this->numchips) {
-			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
-			       chip + 1, this->numchips);
-			return -EINVAL;
-		}
-		numblocks = this->chipsize >> this->bbt_erase_shift;
-		startblock = chip * numblocks;
-		numblocks += startblock;
-		from = (loff_t)startblock << this->bbt_erase_shift;
-	}
-
-	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
-		from += mtd->erasesize - (mtd->writesize * numpages);
-
-	for (i = startblock; i < numblocks; i++) {
-		int ret;
-
-		BUG_ON(bd->options & NAND_BBT_NO_OOB);
-
-		ret = scan_block_fast(mtd, bd, from, buf, numpages);
-		if (ret < 0)
-			return ret;
-
-		if (ret) {
-			bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
-			pr_warn("Bad eraseblock %d at 0x%012llx\n",
-				i, (unsigned long long)from);
-			mtd->ecc_stats.badblocks++;
-		}
-
-		from += (1 << this->bbt_erase_shift);
-	}
-	return 0;
-}
-
-/**
- * search_bbt - [GENERIC] scan the device for a specific bad block table
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @td: descriptor for the bad block table
- *
- * Read the bad block table by searching for a given ident pattern. Search is
- * preformed either from the beginning up or from the end of the device
- * downwards. The search starts always at the start of a block. If the option
- * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
- * the bad block information of this chip. This is necessary to provide support
- * for certain DOC devices.
- *
- * The bbt ident pattern resides in the oob area of the first page in a block.
- */
-static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int i, chips;
-	int startblock, block, dir;
-	int scanlen = mtd->writesize + mtd->oobsize;
-	int bbtblocks;
-	int blocktopage = this->bbt_erase_shift - this->page_shift;
-
-	/* Search direction top -> down? */
-	if (td->options & NAND_BBT_LASTBLOCK) {
-		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
-		dir = -1;
-	} else {
-		startblock = 0;
-		dir = 1;
-	}
-
-	/* Do we have a bbt per chip? */
-	if (td->options & NAND_BBT_PERCHIP) {
-		chips = this->numchips;
-		bbtblocks = this->chipsize >> this->bbt_erase_shift;
-		startblock &= bbtblocks - 1;
-	} else {
-		chips = 1;
-		bbtblocks = mtd->size >> this->bbt_erase_shift;
-	}
-
-	for (i = 0; i < chips; i++) {
-		/* Reset version information */
-		td->version[i] = 0;
-		td->pages[i] = -1;
-		/* Scan the maximum number of blocks */
-		for (block = 0; block < td->maxblocks; block++) {
-
-			int actblock = startblock + dir * block;
-			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
-
-			/* Read first page */
-			scan_read(mtd, buf, offs, mtd->writesize, td);
-			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
-				td->pages[i] = actblock << blocktopage;
-				if (td->options & NAND_BBT_VERSION) {
-					offs = bbt_get_ver_offs(mtd, td);
-					td->version[i] = buf[offs];
-				}
-				break;
-			}
-		}
-		startblock += this->chipsize >> this->bbt_erase_shift;
-	}
-	/* Check, if we found a bbt for each requested chip */
-	for (i = 0; i < chips; i++) {
-		if (td->pages[i] == -1)
-			pr_warn("Bad block table not found for chip %d\n", i);
-		else
-			pr_info("Bad block table found at page %d, version 0x%02X\n",
-				td->pages[i], td->version[i]);
-	}
-	return 0;
-}
-
-/**
- * search_read_bbts - [GENERIC] scan the device for bad block table(s)
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @td: descriptor for the bad block table
- * @md: descriptor for the bad block table mirror
- *
- * Search and read the bad block table(s).
- */
-static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
-			     struct nand_bbt_descr *td,
-			     struct nand_bbt_descr *md)
-{
-	/* Search the primary table */
-	search_bbt(mtd, buf, td);
-
-	/* Search the mirror table */
-	if (md)
-		search_bbt(mtd, buf, md);
-}
-
-/**
- * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
- * @this: the NAND device
- * @td: the BBT description
- * @md: the mirror BBT descriptor
- * @chip: the CHIP selector
- *
- * This functions returns a positive block number pointing a valid eraseblock
- * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
- * all blocks are already used of marked bad. If td->pages[chip] was already
- * pointing to a valid block we re-use it, otherwise we search for the next
- * valid one.
- */
-static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
-			 struct nand_bbt_descr *md, int chip)
-{
-	int startblock, dir, page, numblocks, i;
-
-	/*
-	 * There was already a version of the table, reuse the page. This
-	 * applies for absolute placement too, as we have the page number in
-	 * td->pages.
-	 */
-	if (td->pages[chip] != -1)
-		return td->pages[chip] >>
-				(this->bbt_erase_shift - this->page_shift);
-
-	numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
-	if (!(td->options & NAND_BBT_PERCHIP))
-		numblocks *= this->numchips;
-
-	/*
-	 * Automatic placement of the bad block table. Search direction
-	 * top -> down?
-	 */
-	if (td->options & NAND_BBT_LASTBLOCK) {
-		startblock = numblocks * (chip + 1) - 1;
-		dir = -1;
-	} else {
-		startblock = chip * numblocks;
-		dir = 1;
-	}
-
-	for (i = 0; i < td->maxblocks; i++) {
-		int block = startblock + dir * i;
-
-		/* Check, if the block is bad */
-		switch (bbt_get_entry(this, block)) {
-		case BBT_BLOCK_WORN:
-		case BBT_BLOCK_FACTORY_BAD:
-			continue;
-		}
-
-		page = block << (this->bbt_erase_shift - this->page_shift);
-
-		/* Check, if the block is used by the mirror table */
-		if (!md || md->pages[chip] != page)
-			return block;
-	}
-
-	return -ENOSPC;
-}
-
-/**
- * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
- * @this: the NAND device
- * @td: the BBT description
- * @chip: the CHIP selector
- * @block: the BBT block to mark
- *
- * Blocks reserved for BBT can become bad. This functions is an helper to mark
- * such blocks as bad. It takes care of updating the in-memory BBT, marking the
- * block as bad using a bad block marker and invalidating the associated
- * td->pages[] entry.
- */
-static void mark_bbt_block_bad(struct nand_chip *this,
-			       struct nand_bbt_descr *td,
-			       int chip, int block)
-{
-	struct mtd_info *mtd = nand_to_mtd(this);
-	loff_t to;
-	int res;
-
-	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
-
-	to = (loff_t)block << this->bbt_erase_shift;
-	res = this->block_markbad(mtd, to);
-	if (res)
-		pr_warn("nand_bbt: error %d while marking block %d bad\n",
-			res, block);
-
-	td->pages[chip] = -1;
-}
-
-/**
- * write_bbt - [GENERIC] (Re)write the bad block table
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @td: descriptor for the bad block table
- * @md: descriptor for the bad block table mirror
- * @chipsel: selector for a specific chip, -1 for all
- *
- * (Re)write the bad block table.
- */
-static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
-		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
-		     int chipsel)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct erase_info einfo;
-	int i, res, chip = 0;
-	int bits, page, offs, numblocks, sft, sftmsk;
-	int nrchips, pageoffs, ooboffs;
-	uint8_t msk[4];
-	uint8_t rcode = td->reserved_block_code;
-	size_t retlen, len = 0;
-	loff_t to;
-	struct mtd_oob_ops ops;
-
-	ops.ooblen = mtd->oobsize;
-	ops.ooboffs = 0;
-	ops.datbuf = NULL;
-	ops.mode = MTD_OPS_PLACE_OOB;
-
-	if (!rcode)
-		rcode = 0xff;
-	/* Write bad block table per chip rather than per device? */
-	if (td->options & NAND_BBT_PERCHIP) {
-		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
-		/* Full device write or specific chip? */
-		if (chipsel == -1) {
-			nrchips = this->numchips;
-		} else {
-			nrchips = chipsel + 1;
-			chip = chipsel;
-		}
-	} else {
-		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
-		nrchips = 1;
-	}
-
-	/* Loop through the chips */
-	while (chip < nrchips) {
-		int block;
-
-		block = get_bbt_block(this, td, md, chip);
-		if (block < 0) {
-			pr_err("No space left to write bad block table\n");
-			res = block;
-			goto outerr;
-		}
-
-		/*
-		 * get_bbt_block() returns a block number, shift the value to
-		 * get a page number.
-		 */
-		page = block << (this->bbt_erase_shift - this->page_shift);
-
-		/* Set up shift count and masks for the flash table */
-		bits = td->options & NAND_BBT_NRBITS_MSK;
-		msk[2] = ~rcode;
-		switch (bits) {
-		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
-			msk[3] = 0x01;
-			break;
-		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
-			msk[3] = 0x03;
-			break;
-		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
-			msk[3] = 0x0f;
-			break;
-		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
-			msk[3] = 0xff;
-			break;
-		default: return -EINVAL;
-		}
-
-		to = ((loff_t)page) << this->page_shift;
-
-		/* Must we save the block contents? */
-		if (td->options & NAND_BBT_SAVECONTENT) {
-			/* Make it block aligned */
-			to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
-			len = 1 << this->bbt_erase_shift;
-			res = mtd_read(mtd, to, len, &retlen, buf);
-			if (res < 0) {
-				if (retlen != len) {
-					pr_info("nand_bbt: error reading block for writing the bad block table\n");
-					return res;
-				}
-				pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n");
-			}
-			/* Read oob data */
-			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
-			ops.oobbuf = &buf[len];
-			res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
-			if (res < 0 || ops.oobretlen != ops.ooblen)
-				goto outerr;
-
-			/* Calc the byte offset in the buffer */
-			pageoffs = page - (int)(to >> this->page_shift);
-			offs = pageoffs << this->page_shift;
-			/* Preset the bbt area with 0xff */
-			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
-			ooboffs = len + (pageoffs * mtd->oobsize);
-
-		} else if (td->options & NAND_BBT_NO_OOB) {
-			ooboffs = 0;
-			offs = td->len;
-			/* The version byte */
-			if (td->options & NAND_BBT_VERSION)
-				offs++;
-			/* Calc length */
-			len = (size_t)(numblocks >> sft);
-			len += offs;
-			/* Make it page aligned! */
-			len = ALIGN(len, mtd->writesize);
-			/* Preset the buffer with 0xff */
-			memset(buf, 0xff, len);
-			/* Pattern is located at the begin of first page */
-			memcpy(buf, td->pattern, td->len);
-		} else {
-			/* Calc length */
-			len = (size_t)(numblocks >> sft);
-			/* Make it page aligned! */
-			len = ALIGN(len, mtd->writesize);
-			/* Preset the buffer with 0xff */
-			memset(buf, 0xff, len +
-			       (len >> this->page_shift)* mtd->oobsize);
-			offs = 0;
-			ooboffs = len;
-			/* Pattern is located in oob area of first page */
-			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
-		}
-
-		if (td->options & NAND_BBT_VERSION)
-			buf[ooboffs + td->veroffs] = td->version[chip];
-
-		/* Walk through the memory table */
-		for (i = 0; i < numblocks; i++) {
-			uint8_t dat;
-			int sftcnt = (i << (3 - sft)) & sftmsk;
-			dat = bbt_get_entry(this, chip * numblocks + i);
-			/* Do not store the reserved bbt blocks! */
-			buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
-		}
-
-		memset(&einfo, 0, sizeof(einfo));
-		einfo.mtd = mtd;
-		einfo.addr = to;
-		einfo.len = 1 << this->bbt_erase_shift;
-		res = nand_erase_nand(mtd, &einfo, 1);
-		if (res < 0) {
-			pr_warn("nand_bbt: error while erasing BBT block %d\n",
-				res);
-			mark_bbt_block_bad(this, td, chip, block);
-			continue;
-		}
-
-		res = scan_write_bbt(mtd, to, len, buf,
-				td->options & NAND_BBT_NO_OOB ? NULL :
-				&buf[len]);
-		if (res < 0) {
-			pr_warn("nand_bbt: error while writing BBT block %d\n",
-				res);
-			mark_bbt_block_bad(this, td, chip, block);
-			continue;
-		}
-
-		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
-			 (unsigned long long)to, td->version[chip]);
-
-		/* Mark it as used */
-		td->pages[chip++] = page;
-	}
-	return 0;
-
- outerr:
-	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
-	return res;
-}
-
-/**
- * nand_memory_bbt - [GENERIC] create a memory based bad block table
- * @mtd: MTD device structure
- * @bd: descriptor for the good/bad block search pattern
- *
- * The function creates a memory based bbt by scanning the device for
- * manufacturer / software marked good / bad blocks.
- */
-static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-
-	return create_bbt(mtd, this->data_buf, bd, -1);
-}
-
-/**
- * check_create - [GENERIC] create and write bbt(s) if necessary
- * @mtd: MTD device structure
- * @buf: temporary buffer
- * @bd: descriptor for the good/bad block search pattern
- *
- * The function checks the results of the previous call to read_bbt and creates
- * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
- * for the chip/device. Update is necessary if one of the tables is missing or
- * the version nr. of one table is less than the other.
- */
-static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
-{
-	int i, chips, writeops, create, chipsel, res, res2;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct nand_bbt_descr *td = this->bbt_td;
-	struct nand_bbt_descr *md = this->bbt_md;
-	struct nand_bbt_descr *rd, *rd2;
-
-	/* Do we have a bbt per chip? */
-	if (td->options & NAND_BBT_PERCHIP)
-		chips = this->numchips;
-	else
-		chips = 1;
-
-	for (i = 0; i < chips; i++) {
-		writeops = 0;
-		create = 0;
-		rd = NULL;
-		rd2 = NULL;
-		res = res2 = 0;
-		/* Per chip or per device? */
-		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
-		/* Mirrored table available? */
-		if (md) {
-			if (td->pages[i] == -1 && md->pages[i] == -1) {
-				create = 1;
-				writeops = 0x03;
-			} else if (td->pages[i] == -1) {
-				rd = md;
-				writeops = 0x01;
-			} else if (md->pages[i] == -1) {
-				rd = td;
-				writeops = 0x02;
-			} else if (td->version[i] == md->version[i]) {
-				rd = td;
-				if (!(td->options & NAND_BBT_VERSION))
-					rd2 = md;
-			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
-				rd = td;
-				writeops = 0x02;
-			} else {
-				rd = md;
-				writeops = 0x01;
-			}
-		} else {
-			if (td->pages[i] == -1) {
-				create = 1;
-				writeops = 0x01;
-			} else {
-				rd = td;
-			}
-		}
-
-		if (create) {
-			/* Create the bad block table by scanning the device? */
-			if (!(td->options & NAND_BBT_CREATE))
-				continue;
-
-			/* Create the table in memory by scanning the chip(s) */
-			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
-				create_bbt(mtd, buf, bd, chipsel);
-
-			td->version[i] = 1;
-			if (md)
-				md->version[i] = 1;
-		}
-
-		/* Read back first? */
-		if (rd) {
-			res = read_abs_bbt(mtd, buf, rd, chipsel);
-			if (mtd_is_eccerr(res)) {
-				/* Mark table as invalid */
-				rd->pages[i] = -1;
-				rd->version[i] = 0;
-				i--;
-				continue;
-			}
-		}
-		/* If they weren't versioned, read both */
-		if (rd2) {
-			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
-			if (mtd_is_eccerr(res2)) {
-				/* Mark table as invalid */
-				rd2->pages[i] = -1;
-				rd2->version[i] = 0;
-				i--;
-				continue;
-			}
-		}
-
-		/* Scrub the flash table(s)? */
-		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
-			writeops = 0x03;
-
-		/* Update version numbers before writing */
-		if (md) {
-			td->version[i] = max(td->version[i], md->version[i]);
-			md->version[i] = td->version[i];
-		}
-
-		/* Write the bad block table to the device? */
-		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-			res = write_bbt(mtd, buf, td, md, chipsel);
-			if (res < 0)
-				return res;
-		}
-
-		/* Write the mirror bad block table to the device? */
-		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-			res = write_bbt(mtd, buf, md, td, chipsel);
-			if (res < 0)
-				return res;
-		}
-	}
-	return 0;
-}
-
-/**
- * mark_bbt_regions - [GENERIC] mark the bad block table regions
- * @mtd: MTD device structure
- * @td: bad block table descriptor
- *
- * The bad block table regions are marked as "bad" to prevent accidental
- * erasures / writes. The regions are identified by the mark 0x02.
- */
-static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int i, j, chips, block, nrblocks, update;
-	uint8_t oldval;
-
-	/* Do we have a bbt per chip? */
-	if (td->options & NAND_BBT_PERCHIP) {
-		chips = this->numchips;
-		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
-	} else {
-		chips = 1;
-		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
-	}
-
-	for (i = 0; i < chips; i++) {
-		if ((td->options & NAND_BBT_ABSPAGE) ||
-		    !(td->options & NAND_BBT_WRITE)) {
-			if (td->pages[i] == -1)
-				continue;
-			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
-			oldval = bbt_get_entry(this, block);
-			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
-			if ((oldval != BBT_BLOCK_RESERVED) &&
-					td->reserved_block_code)
-				nand_update_bbt(mtd, (loff_t)block <<
-						this->bbt_erase_shift);
-			continue;
-		}
-		update = 0;
-		if (td->options & NAND_BBT_LASTBLOCK)
-			block = ((i + 1) * nrblocks) - td->maxblocks;
-		else
-			block = i * nrblocks;
-		for (j = 0; j < td->maxblocks; j++) {
-			oldval = bbt_get_entry(this, block);
-			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
-			if (oldval != BBT_BLOCK_RESERVED)
-				update = 1;
-			block++;
-		}
-		/*
-		 * If we want reserved blocks to be recorded to flash, and some
-		 * new ones have been marked, then we need to update the stored
-		 * bbts.  This should only happen once.
-		 */
-		if (update && td->reserved_block_code)
-			nand_update_bbt(mtd, (loff_t)(block - 1) <<
-					this->bbt_erase_shift);
-	}
-}
-
-/**
- * verify_bbt_descr - verify the bad block description
- * @mtd: MTD device structure
- * @bd: the table to verify
- *
- * This functions performs a few sanity checks on the bad block description
- * table.
- */
-static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	u32 pattern_len;
-	u32 bits;
-	u32 table_size;
-
-	if (!bd)
-		return;
-
-	pattern_len = bd->len;
-	bits = bd->options & NAND_BBT_NRBITS_MSK;
-
-	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
-			!(this->bbt_options & NAND_BBT_USE_FLASH));
-	BUG_ON(!bits);
-
-	if (bd->options & NAND_BBT_VERSION)
-		pattern_len++;
-
-	if (bd->options & NAND_BBT_NO_OOB) {
-		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
-		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
-		BUG_ON(bd->offs);
-		if (bd->options & NAND_BBT_VERSION)
-			BUG_ON(bd->veroffs != bd->len);
-		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
-	}
-
-	if (bd->options & NAND_BBT_PERCHIP)
-		table_size = this->chipsize >> this->bbt_erase_shift;
-	else
-		table_size = mtd->size >> this->bbt_erase_shift;
-	table_size >>= 3;
-	table_size *= bits;
-	if (bd->options & NAND_BBT_NO_OOB)
-		table_size += pattern_len;
-	BUG_ON(table_size > (1 << this->bbt_erase_shift));
-}
-
-/**
- * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
- * @mtd: MTD device structure
- * @bd: descriptor for the good/bad block search pattern
- *
- * The function checks, if a bad block table(s) is/are already available. If
- * not it scans the device for manufacturer marked good / bad blocks and writes
- * the bad block table(s) to the selected place.
- *
- * The bad block table memory is allocated here. It must be freed by calling
- * the nand_free_bbt function.
- */
-static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int len, res;
-	uint8_t *buf;
-	struct nand_bbt_descr *td = this->bbt_td;
-	struct nand_bbt_descr *md = this->bbt_md;
-
-	len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
-	/*
-	 * Allocate memory (2bit per block) and clear the memory bad block
-	 * table.
-	 */
-	this->bbt = kzalloc(len, GFP_KERNEL);
-	if (!this->bbt)
-		return -ENOMEM;
-
-	/*
-	 * If no primary table decriptor is given, scan the device to build a
-	 * memory based bad block table.
-	 */
-	if (!td) {
-		if ((res = nand_memory_bbt(mtd, bd))) {
-			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
-			goto err;
-		}
-		return 0;
-	}
-	verify_bbt_descr(mtd, td);
-	verify_bbt_descr(mtd, md);
-
-	/* Allocate a temporary buffer for one eraseblock incl. oob */
-	len = (1 << this->bbt_erase_shift);
-	len += (len >> this->page_shift) * mtd->oobsize;
-	buf = vmalloc(len);
-	if (!buf) {
-		res = -ENOMEM;
-		goto err;
-	}
-
-	/* Is the bbt at a given page? */
-	if (td->options & NAND_BBT_ABSPAGE) {
-		read_abs_bbts(mtd, buf, td, md);
-	} else {
-		/* Search the bad block table using a pattern in oob */
-		search_read_bbts(mtd, buf, td, md);
-	}
-
-	res = check_create(mtd, buf, bd);
-	if (res)
-		goto err;
-
-	/* Prevent the bbt regions from erasing / writing */
-	mark_bbt_region(mtd, td);
-	if (md)
-		mark_bbt_region(mtd, md);
-
-	vfree(buf);
-	return 0;
-
-err:
-	kfree(this->bbt);
-	this->bbt = NULL;
-	return res;
-}
-
-/**
- * nand_update_bbt - update bad block table(s)
- * @mtd: MTD device structure
- * @offs: the offset of the newly marked block
- *
- * The function updates the bad block table(s).
- */
-static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int len, res = 0;
-	int chip, chipsel;
-	uint8_t *buf;
-	struct nand_bbt_descr *td = this->bbt_td;
-	struct nand_bbt_descr *md = this->bbt_md;
-
-	if (!this->bbt || !td)
-		return -EINVAL;
-
-	/* Allocate a temporary buffer for one eraseblock incl. oob */
-	len = (1 << this->bbt_erase_shift);
-	len += (len >> this->page_shift) * mtd->oobsize;
-	buf = kmalloc(len, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/* Do we have a bbt per chip? */
-	if (td->options & NAND_BBT_PERCHIP) {
-		chip = (int)(offs >> this->chip_shift);
-		chipsel = chip;
-	} else {
-		chip = 0;
-		chipsel = -1;
-	}
-
-	td->version[chip]++;
-	if (md)
-		md->version[chip]++;
-
-	/* Write the bad block table to the device? */
-	if (td->options & NAND_BBT_WRITE) {
-		res = write_bbt(mtd, buf, td, md, chipsel);
-		if (res < 0)
-			goto out;
-	}
-	/* Write the mirror bad block table to the device? */
-	if (md && (md->options & NAND_BBT_WRITE)) {
-		res = write_bbt(mtd, buf, md, td, chipsel);
-	}
-
- out:
-	kfree(buf);
-	return res;
-}
-
-/*
- * Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks.
- */
-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-
-/* Generic flash bbt descriptors */
-static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	8,
-	.len = 4,
-	.veroffs = 12,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-	.offs =	8,
-	.len = 4,
-	.veroffs = 12,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = mirror_pattern
-};
-
-static struct nand_bbt_descr bbt_main_no_oob_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
-		| NAND_BBT_NO_OOB,
-	.len = 4,
-	.veroffs = 4,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
-		| NAND_BBT_NO_OOB,
-	.len = 4,
-	.veroffs = 4,
-	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
-	.pattern = mirror_pattern
-};
-
-#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
-/**
- * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
- * @this: NAND chip to create descriptor for
- *
- * This function allocates and initializes a nand_bbt_descr for BBM detection
- * based on the properties of @this. The new descriptor is stored in
- * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
- * passed to this function.
- */
-static int nand_create_badblock_pattern(struct nand_chip *this)
-{
-	struct nand_bbt_descr *bd;
-	if (this->badblock_pattern) {
-		pr_warn("Bad block pattern already allocated; not replacing\n");
-		return -EINVAL;
-	}
-	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
-	if (!bd)
-		return -ENOMEM;
-	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
-	bd->offs = this->badblockpos;
-	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
-	bd->pattern = scan_ff_pattern;
-	bd->options |= NAND_BBT_DYNAMICSTRUCT;
-	this->badblock_pattern = bd;
-	return 0;
-}
-
-/**
- * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
- * @mtd: MTD device structure
- *
- * This function selects the default bad block table support for the device and
- * calls the nand_scan_bbt function.
- */
-int nand_default_bbt(struct mtd_info *mtd)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int ret;
-
-	/* Is a flash based bad block table requested? */
-	if (this->bbt_options & NAND_BBT_USE_FLASH) {
-		/* Use the default pattern descriptors */
-		if (!this->bbt_td) {
-			if (this->bbt_options & NAND_BBT_NO_OOB) {
-				this->bbt_td = &bbt_main_no_oob_descr;
-				this->bbt_md = &bbt_mirror_no_oob_descr;
-			} else {
-				this->bbt_td = &bbt_main_descr;
-				this->bbt_md = &bbt_mirror_descr;
-			}
-		}
-	} else {
-		this->bbt_td = NULL;
-		this->bbt_md = NULL;
-	}
-
-	if (!this->badblock_pattern) {
-		ret = nand_create_badblock_pattern(this);
-		if (ret)
-			return ret;
-	}
-
-	return nand_scan_bbt(mtd, this->badblock_pattern);
-}
-
-/**
- * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
- * @mtd: MTD device structure
- * @offs: offset in the device
- */
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int block;
-
-	block = (int)(offs >> this->bbt_erase_shift);
-	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
-}
-
-/**
- * nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd: MTD device structure
- * @offs: offset in the device
- * @allowbbt: allow access to bad block table region
- */
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int block, res;
-
-	block = (int)(offs >> this->bbt_erase_shift);
-	res = bbt_get_entry(this, block);
-
-	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
-		 (unsigned int)offs, block, res);
-
-	switch (res) {
-	case BBT_BLOCK_GOOD:
-		return 0;
-	case BBT_BLOCK_WORN:
-		return 1;
-	case BBT_BLOCK_RESERVED:
-		return allowbbt ? 0 : 1;
-	}
-	return 1;
-}
-
-/**
- * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
- * @mtd: MTD device structure
- * @offs: offset of the bad block
- */
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	int block, ret = 0;
-
-	block = (int)(offs >> this->bbt_erase_shift);
-
-	/* Mark bad block in memory */
-	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
-
-	/* Update flash-based bad block table */
-	if (this->bbt_options & NAND_BBT_USE_FLASH)
-		ret = nand_update_bbt(mtd, offs);
-
-	return ret;
-}
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
deleted file mode 100644
index 505441c9373b..000000000000
--- a/drivers/mtd/nand/nand_bch.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * This file provides ECC correction for more than 1 bit per block of data,
- * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
- *
- * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
- *
- * This file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 or (at your option) any
- * later version.
- *
- * This file is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this file; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_bch.h>
-#include <linux/bch.h>
-
-/**
- * struct nand_bch_control - private NAND BCH control structure
- * @bch:       BCH control structure
- * @errloc:    error location array
- * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
- */
-struct nand_bch_control {
-	struct bch_control   *bch;
-	unsigned int         *errloc;
-	unsigned char        *eccmask;
-};
-
-/**
- * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
- * @mtd:	MTD block structure
- * @buf:	input buffer with raw data
- * @code:	output buffer with ECC
- */
-int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
-			   unsigned char *code)
-{
-	const struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_bch_control *nbc = chip->ecc.priv;
-	unsigned int i;
-
-	memset(code, 0, chip->ecc.bytes);
-	encode_bch(nbc->bch, buf, chip->ecc.size, code);
-
-	/* apply mask so that an erased page is a valid codeword */
-	for (i = 0; i < chip->ecc.bytes; i++)
-		code[i] ^= nbc->eccmask[i];
-
-	return 0;
-}
-EXPORT_SYMBOL(nand_bch_calculate_ecc);
-
-/**
- * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd:	MTD block structure
- * @buf:	raw data read from the chip
- * @read_ecc:	ECC from the chip
- * @calc_ecc:	the ECC calculated from raw data
- *
- * Detect and correct bit errors for a data byte block
- */
-int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
-			  unsigned char *read_ecc, unsigned char *calc_ecc)
-{
-	const struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_bch_control *nbc = chip->ecc.priv;
-	unsigned int *errloc = nbc->errloc;
-	int i, count;
-
-	count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
-			   NULL, errloc);
-	if (count > 0) {
-		for (i = 0; i < count; i++) {
-			if (errloc[i] < (chip->ecc.size*8))
-				/* error is located in data, correct it */
-				buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
-			/* else error in ecc, no action needed */
-
-			pr_debug("%s: corrected bitflip %u\n", __func__,
-					errloc[i]);
-		}
-	} else if (count < 0) {
-		printk(KERN_ERR "ecc unrecoverable error\n");
-		count = -EBADMSG;
-	}
-	return count;
-}
-EXPORT_SYMBOL(nand_bch_correct_data);
-
-/**
- * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
- * @mtd:	MTD block structure
- *
- * Returns:
- *  a pointer to a new NAND BCH control structure, or NULL upon failure
- *
- * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
- * are used to compute BCH parameters m (Galois field order) and t (error
- * correction capability). @eccbytes should be equal to the number of bytes
- * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
- *
- * Example: to configure 4 bit correction per 512 bytes, you should pass
- * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
- * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits)
- */
-struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	unsigned int m, t, eccsteps, i;
-	struct nand_bch_control *nbc = NULL;
-	unsigned char *erased_page;
-	unsigned int eccsize = nand->ecc.size;
-	unsigned int eccbytes = nand->ecc.bytes;
-	unsigned int eccstrength = nand->ecc.strength;
-
-	if (!eccbytes && eccstrength) {
-		eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
-		nand->ecc.bytes = eccbytes;
-	}
-
-	if (!eccsize || !eccbytes) {
-		printk(KERN_WARNING "ecc parameters not supplied\n");
-		goto fail;
-	}
-
-	m = fls(1+8*eccsize);
-	t = (eccbytes*8)/m;
-
-	nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
-	if (!nbc)
-		goto fail;
-
-	nbc->bch = init_bch(m, t, 0);
-	if (!nbc->bch)
-		goto fail;
-
-	/* verify that eccbytes has the expected value */
-	if (nbc->bch->ecc_bytes != eccbytes) {
-		printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
-		       eccbytes, nbc->bch->ecc_bytes);
-		goto fail;
-	}
-
-	eccsteps = mtd->writesize/eccsize;
-
-	/* Check that we have an oob layout description. */
-	if (!mtd->ooblayout) {
-		pr_warn("missing oob scheme");
-		goto fail;
-	}
-
-	/* sanity checks */
-	if (8*(eccsize+eccbytes) >= (1 << m)) {
-		printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
-		goto fail;
-	}
-
-	/*
-	 * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(),
-	 * which is called by mtd_ooblayout_count_eccbytes().
-	 * Make sure they are properly initialized before calling
-	 * mtd_ooblayout_count_eccbytes().
-	 * FIXME: we should probably rework the sequencing in nand_scan_tail()
-	 * to avoid setting those fields twice.
-	 */
-	nand->ecc.steps = eccsteps;
-	nand->ecc.total = eccsteps * eccbytes;
-	if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
-		printk(KERN_WARNING "invalid ecc layout\n");
-		goto fail;
-	}
-
-	nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
-	nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
-	if (!nbc->eccmask || !nbc->errloc)
-		goto fail;
-	/*
-	 * compute and store the inverted ecc of an erased ecc block
-	 */
-	erased_page = kmalloc(eccsize, GFP_KERNEL);
-	if (!erased_page)
-		goto fail;
-
-	memset(erased_page, 0xff, eccsize);
-	memset(nbc->eccmask, 0, eccbytes);
-	encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
-	kfree(erased_page);
-
-	for (i = 0; i < eccbytes; i++)
-		nbc->eccmask[i] ^= 0xff;
-
-	if (!eccstrength)
-		nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
-
-	return nbc;
-fail:
-	nand_bch_free(nbc);
-	return NULL;
-}
-EXPORT_SYMBOL(nand_bch_init);
-
-/**
- * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
- * @nbc:	NAND BCH control structure
- */
-void nand_bch_free(struct nand_bch_control *nbc)
-{
-	if (nbc) {
-		free_bch(nbc->bch);
-		kfree(nbc->errloc);
-		kfree(nbc->eccmask);
-		kfree(nbc);
-	}
-}
-EXPORT_SYMBOL(nand_bch_free);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
-MODULE_DESCRIPTION("NAND software BCH ECC support");
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
deleted file mode 100644
index 7613a0388044..000000000000
--- a/drivers/mtd/nand/nand_ecc.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * This file contains an ECC algorithm that detects and corrects 1 bit
- * errors in a 256 byte block of data.
- *
- * drivers/mtd/nand/nand_ecc.c
- *
- * Copyright © 2008 Koninklijke Philips Electronics NV.
- *                  Author: Frans Meulenbroeks
- *
- * Completely replaces the previous ECC implementation which was written by:
- *   Steven J. Hill (sjhill@realitydiluted.com)
- *   Thomas Gleixner (tglx@linutronix.de)
- *
- * Information on how this algorithm works and how it was developed
- * can be found in Documentation/mtd/nand_ecc.txt
- *
- * This file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 or (at your option) any
- * later version.
- *
- * This file is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this file; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- */
-
-/*
- * The STANDALONE macro is useful when running the code outside the kernel
- * e.g. when running the code in a testbed or a benchmark program.
- * When STANDALONE is used, the module related macros are commented out
- * as well as the linux include files.
- * Instead a private definition of mtd_info is given to satisfy the compiler
- * (the code does not use mtd_info, so the code does not care)
- */
-#ifndef STANDALONE
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <asm/byteorder.h>
-#else
-#include <stdint.h>
-struct mtd_info;
-#define EXPORT_SYMBOL(x)  /* x */
-
-#define MODULE_LICENSE(x)	/* x */
-#define MODULE_AUTHOR(x)	/* x */
-#define MODULE_DESCRIPTION(x)	/* x */
-
-#define pr_err printf
-#endif
-
-/*
- * invparity is a 256 byte table that contains the odd parity
- * for each byte. So if the number of bits in a byte is even,
- * the array element is 1, and when the number of bits is odd
- * the array eleemnt is 0.
- */
-static const char invparity[256] = {
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
-};
-
-/*
- * bitsperbyte contains the number of bits per byte
- * this is only used for testing and repairing parity
- * (a precalculated value slightly improves performance)
- */
-static const char bitsperbyte[256] = {
-	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
-};
-
-/*
- * addressbits is a lookup table to filter out the bits from the xor-ed
- * ECC data that identify the faulty location.
- * this is only used for repairing parity
- * see the comments in nand_correct_data for more details
- */
-static const char addressbits[256] = {
-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
-	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
-};
-
-/**
- * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
- *			 block
- * @buf:	input buffer with raw data
- * @eccsize:	data bytes per ECC step (256 or 512)
- * @code:	output buffer with ECC
- */
-void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
-		       unsigned char *code)
-{
-	int i;
-	const uint32_t *bp = (uint32_t *)buf;
-	/* 256 or 512 bytes/ecc  */
-	const uint32_t eccsize_mult = eccsize >> 8;
-	uint32_t cur;		/* current value in buffer */
-	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
-	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
-	uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
-	uint32_t uninitialized_var(rp17);	/* to make compiler happy */
-	uint32_t par;		/* the cumulative parity for all data */
-	uint32_t tmppar;	/* the cumulative parity for this iteration;
-				   for rp12, rp14 and rp16 at the end of the
-				   loop */
-
-	par = 0;
-	rp4 = 0;
-	rp6 = 0;
-	rp8 = 0;
-	rp10 = 0;
-	rp12 = 0;
-	rp14 = 0;
-	rp16 = 0;
-
-	/*
-	 * The loop is unrolled a number of times;
-	 * This avoids if statements to decide on which rp value to update
-	 * Also we process the data by longwords.
-	 * Note: passing unaligned data might give a performance penalty.
-	 * It is assumed that the buffers are aligned.
-	 * tmppar is the cumulative sum of this iteration.
-	 * needed for calculating rp12, rp14, rp16 and par
-	 * also used as a performance improvement for rp6, rp8 and rp10
-	 */
-	for (i = 0; i < eccsize_mult << 2; i++) {
-		cur = *bp++;
-		tmppar = cur;
-		rp4 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp6 ^= tmppar;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp8 ^= tmppar;
-
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		rp6 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp6 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp10 ^= tmppar;
-
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		rp6 ^= cur;
-		rp8 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp6 ^= cur;
-		rp8 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		rp8 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp8 ^= cur;
-
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		rp6 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp6 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-		rp4 ^= cur;
-		cur = *bp++;
-		tmppar ^= cur;
-
-		par ^= tmppar;
-		if ((i & 0x1) == 0)
-			rp12 ^= tmppar;
-		if ((i & 0x2) == 0)
-			rp14 ^= tmppar;
-		if (eccsize_mult == 2 && (i & 0x4) == 0)
-			rp16 ^= tmppar;
-	}
-
-	/*
-	 * handle the fact that we use longword operations
-	 * we'll bring rp4..rp14..rp16 back to single byte entities by
-	 * shifting and xoring first fold the upper and lower 16 bits,
-	 * then the upper and lower 8 bits.
-	 */
-	rp4 ^= (rp4 >> 16);
-	rp4 ^= (rp4 >> 8);
-	rp4 &= 0xff;
-	rp6 ^= (rp6 >> 16);
-	rp6 ^= (rp6 >> 8);
-	rp6 &= 0xff;
-	rp8 ^= (rp8 >> 16);
-	rp8 ^= (rp8 >> 8);
-	rp8 &= 0xff;
-	rp10 ^= (rp10 >> 16);
-	rp10 ^= (rp10 >> 8);
-	rp10 &= 0xff;
-	rp12 ^= (rp12 >> 16);
-	rp12 ^= (rp12 >> 8);
-	rp12 &= 0xff;
-	rp14 ^= (rp14 >> 16);
-	rp14 ^= (rp14 >> 8);
-	rp14 &= 0xff;
-	if (eccsize_mult == 2) {
-		rp16 ^= (rp16 >> 16);
-		rp16 ^= (rp16 >> 8);
-		rp16 &= 0xff;
-	}
-
-	/*
-	 * we also need to calculate the row parity for rp0..rp3
-	 * This is present in par, because par is now
-	 * rp3 rp3 rp2 rp2 in little endian and
-	 * rp2 rp2 rp3 rp3 in big endian
-	 * as well as
-	 * rp1 rp0 rp1 rp0 in little endian and
-	 * rp0 rp1 rp0 rp1 in big endian
-	 * First calculate rp2 and rp3
-	 */
-#ifdef __BIG_ENDIAN
-	rp2 = (par >> 16);
-	rp2 ^= (rp2 >> 8);
-	rp2 &= 0xff;
-	rp3 = par & 0xffff;
-	rp3 ^= (rp3 >> 8);
-	rp3 &= 0xff;
-#else
-	rp3 = (par >> 16);
-	rp3 ^= (rp3 >> 8);
-	rp3 &= 0xff;
-	rp2 = par & 0xffff;
-	rp2 ^= (rp2 >> 8);
-	rp2 &= 0xff;
-#endif
-
-	/* reduce par to 16 bits then calculate rp1 and rp0 */
-	par ^= (par >> 16);
-#ifdef __BIG_ENDIAN
-	rp0 = (par >> 8) & 0xff;
-	rp1 = (par & 0xff);
-#else
-	rp1 = (par >> 8) & 0xff;
-	rp0 = (par & 0xff);
-#endif
-
-	/* finally reduce par to 8 bits */
-	par ^= (par >> 8);
-	par &= 0xff;
-
-	/*
-	 * and calculate rp5..rp15..rp17
-	 * note that par = rp4 ^ rp5 and due to the commutative property
-	 * of the ^ operator we can say:
-	 * rp5 = (par ^ rp4);
-	 * The & 0xff seems superfluous, but benchmarking learned that
-	 * leaving it out gives slightly worse results. No idea why, probably
-	 * it has to do with the way the pipeline in pentium is organized.
-	 */
-	rp5 = (par ^ rp4) & 0xff;
-	rp7 = (par ^ rp6) & 0xff;
-	rp9 = (par ^ rp8) & 0xff;
-	rp11 = (par ^ rp10) & 0xff;
-	rp13 = (par ^ rp12) & 0xff;
-	rp15 = (par ^ rp14) & 0xff;
-	if (eccsize_mult == 2)
-		rp17 = (par ^ rp16) & 0xff;
-
-	/*
-	 * Finally calculate the ECC bits.
-	 * Again here it might seem that there are performance optimisations
-	 * possible, but benchmarks showed that on the system this is developed
-	 * the code below is the fastest
-	 */
-#ifdef CONFIG_MTD_NAND_ECC_SMC
-	code[0] =
-	    (invparity[rp7] << 7) |
-	    (invparity[rp6] << 6) |
-	    (invparity[rp5] << 5) |
-	    (invparity[rp4] << 4) |
-	    (invparity[rp3] << 3) |
-	    (invparity[rp2] << 2) |
-	    (invparity[rp1] << 1) |
-	    (invparity[rp0]);
-	code[1] =
-	    (invparity[rp15] << 7) |
-	    (invparity[rp14] << 6) |
-	    (invparity[rp13] << 5) |
-	    (invparity[rp12] << 4) |
-	    (invparity[rp11] << 3) |
-	    (invparity[rp10] << 2) |
-	    (invparity[rp9] << 1)  |
-	    (invparity[rp8]);
-#else
-	code[1] =
-	    (invparity[rp7] << 7) |
-	    (invparity[rp6] << 6) |
-	    (invparity[rp5] << 5) |
-	    (invparity[rp4] << 4) |
-	    (invparity[rp3] << 3) |
-	    (invparity[rp2] << 2) |
-	    (invparity[rp1] << 1) |
-	    (invparity[rp0]);
-	code[0] =
-	    (invparity[rp15] << 7) |
-	    (invparity[rp14] << 6) |
-	    (invparity[rp13] << 5) |
-	    (invparity[rp12] << 4) |
-	    (invparity[rp11] << 3) |
-	    (invparity[rp10] << 2) |
-	    (invparity[rp9] << 1)  |
-	    (invparity[rp8]);
-#endif
-	if (eccsize_mult == 1)
-		code[2] =
-		    (invparity[par & 0xf0] << 7) |
-		    (invparity[par & 0x0f] << 6) |
-		    (invparity[par & 0xcc] << 5) |
-		    (invparity[par & 0x33] << 4) |
-		    (invparity[par & 0xaa] << 3) |
-		    (invparity[par & 0x55] << 2) |
-		    3;
-	else
-		code[2] =
-		    (invparity[par & 0xf0] << 7) |
-		    (invparity[par & 0x0f] << 6) |
-		    (invparity[par & 0xcc] << 5) |
-		    (invparity[par & 0x33] << 4) |
-		    (invparity[par & 0xaa] << 3) |
-		    (invparity[par & 0x55] << 2) |
-		    (invparity[rp17] << 1) |
-		    (invparity[rp16] << 0);
-}
-EXPORT_SYMBOL(__nand_calculate_ecc);
-
-/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
- *			 block
- * @mtd:	MTD block structure
- * @buf:	input buffer with raw data
- * @code:	output buffer with ECC
- */
-int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
-		       unsigned char *code)
-{
-	__nand_calculate_ecc(buf,
-			mtd_to_nand(mtd)->ecc.size, code);
-
-	return 0;
-}
-EXPORT_SYMBOL(nand_calculate_ecc);
-
-/**
- * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @buf:	raw data read from the chip
- * @read_ecc:	ECC from the chip
- * @calc_ecc:	the ECC calculated from raw data
- * @eccsize:	data bytes per ECC step (256 or 512)
- *
- * Detect and correct a 1 bit error for eccsize byte block
- */
-int __nand_correct_data(unsigned char *buf,
-			unsigned char *read_ecc, unsigned char *calc_ecc,
-			unsigned int eccsize)
-{
-	unsigned char b0, b1, b2, bit_addr;
-	unsigned int byte_addr;
-	/* 256 or 512 bytes/ecc  */
-	const uint32_t eccsize_mult = eccsize >> 8;
-
-	/*
-	 * b0 to b2 indicate which bit is faulty (if any)
-	 * we might need the xor result  more than once,
-	 * so keep them in a local var
-	*/
-#ifdef CONFIG_MTD_NAND_ECC_SMC
-	b0 = read_ecc[0] ^ calc_ecc[0];
-	b1 = read_ecc[1] ^ calc_ecc[1];
-#else
-	b0 = read_ecc[1] ^ calc_ecc[1];
-	b1 = read_ecc[0] ^ calc_ecc[0];
-#endif
-	b2 = read_ecc[2] ^ calc_ecc[2];
-
-	/* check if there are any bitfaults */
-
-	/* repeated if statements are slightly more efficient than switch ... */
-	/* ordered in order of likelihood */
-
-	if ((b0 | b1 | b2) == 0)
-		return 0;	/* no error */
-
-	if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
-	    (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
-	    ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
-	     (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
-	/* single bit error */
-		/*
-		 * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
-		 * byte, cp 5/3/1 indicate the faulty bit.
-		 * A lookup table (called addressbits) is used to filter
-		 * the bits from the byte they are in.
-		 * A marginal optimisation is possible by having three
-		 * different lookup tables.
-		 * One as we have now (for b0), one for b2
-		 * (that would avoid the >> 1), and one for b1 (with all values
-		 * << 4). However it was felt that introducing two more tables
-		 * hardly justify the gain.
-		 *
-		 * The b2 shift is there to get rid of the lowest two bits.
-		 * We could also do addressbits[b2] >> 1 but for the
-		 * performance it does not make any difference
-		 */
-		if (eccsize_mult == 1)
-			byte_addr = (addressbits[b1] << 4) + addressbits[b0];
-		else
-			byte_addr = (addressbits[b2 & 0x3] << 8) +
-				    (addressbits[b1] << 4) + addressbits[b0];
-		bit_addr = addressbits[b2 >> 2];
-		/* flip the bit */
-		buf[byte_addr] ^= (1 << bit_addr);
-		return 1;
-
-	}
-	/* count nr of bits; use table lookup, faster than calculating it */
-	if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
-		return 1;	/* error in ECC data; no action needed */
-
-	pr_err("%s: uncorrectable ECC error\n", __func__);
-	return -EBADMSG;
-}
-EXPORT_SYMBOL(__nand_correct_data);
-
-/**
- * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd:	MTD block structure
- * @buf:	raw data read from the chip
- * @read_ecc:	ECC from the chip
- * @calc_ecc:	the ECC calculated from raw data
- *
- * Detect and correct a 1 bit error for 256/512 byte block
- */
-int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
-		      unsigned char *read_ecc, unsigned char *calc_ecc)
-{
-	return __nand_correct_data(buf, read_ecc, calc_ecc,
-				   mtd_to_nand(mtd)->ecc.size);
-}
-EXPORT_SYMBOL(nand_correct_data);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
-MODULE_DESCRIPTION("Generic NAND ECC support");
diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c
deleted file mode 100644
index d542908a0ebb..000000000000
--- a/drivers/mtd/nand/nand_hynix.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- * Copyright (C) 2017 Free Electrons
- * Copyright (C) 2017 NextThing Co
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mtd/rawnand.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-
-#define NAND_HYNIX_CMD_SET_PARAMS	0x36
-#define NAND_HYNIX_CMD_APPLY_PARAMS	0x16
-
-#define NAND_HYNIX_1XNM_RR_REPEAT	8
-
-/**
- * struct hynix_read_retry - read-retry data
- * @nregs: number of register to set when applying a new read-retry mode
- * @regs: register offsets (NAND chip dependent)
- * @values: array of values to set in registers. The array size is equal to
- *	    (nregs * nmodes)
- */
-struct hynix_read_retry {
-	int nregs;
-	const u8 *regs;
-	u8 values[0];
-};
-
-/**
- * struct hynix_nand - private Hynix NAND struct
- * @nand_technology: manufacturing process expressed in picometer
- * @read_retry: read-retry information
- */
-struct hynix_nand {
-	const struct hynix_read_retry *read_retry;
-};
-
-/**
- * struct hynix_read_retry_otp - structure describing how the read-retry OTP
- *				 area
- * @nregs: number of hynix private registers to set before reading the reading
- *	   the OTP area
- * @regs: registers that should be configured
- * @values: values that should be set in regs
- * @page: the address to pass to the READ_PAGE command. Depends on the NAND
- *	  chip
- * @size: size of the read-retry OTP section
- */
-struct hynix_read_retry_otp {
-	int nregs;
-	const u8 *regs;
-	const u8 *values;
-	int page;
-	int size;
-};
-
-static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
-{
-	u8 jedecid[5] = { };
-	int ret;
-
-	ret = nand_readid_op(chip, 0x40, jedecid, sizeof(jedecid));
-	if (ret)
-		return false;
-
-	return !strncmp("JEDEC", jedecid, sizeof(jedecid));
-}
-
-static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (chip->exec_op) {
-		struct nand_op_instr instrs[] = {
-			NAND_OP_CMD(cmd, 0),
-		};
-		struct nand_operation op = NAND_OPERATION(instrs);
-
-		return nand_exec_op(chip, &op);
-	}
-
-	chip->cmdfunc(mtd, cmd, -1, -1);
-
-	return 0;
-}
-
-static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u16 column = ((u16)addr << 8) | addr;
-
-	chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
-	chip->write_byte(mtd, val);
-
-	return 0;
-}
-
-static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
-	const u8 *values;
-	int i, ret;
-
-	values = hynix->read_retry->values +
-		 (retry_mode * hynix->read_retry->nregs);
-
-	/* Enter 'Set Hynix Parameters' mode */
-	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
-	if (ret)
-		return ret;
-
-	/*
-	 * Configure the NAND in the requested read-retry mode.
-	 * This is done by setting pre-defined values in internal NAND
-	 * registers.
-	 *
-	 * The set of registers is NAND specific, and the values are either
-	 * predefined or extracted from an OTP area on the NAND (values are
-	 * probably tweaked at production in this case).
-	 */
-	for (i = 0; i < hynix->read_retry->nregs; i++) {
-		ret = hynix_nand_reg_write_op(chip, hynix->read_retry->regs[i],
-					      values[i]);
-		if (ret)
-			return ret;
-	}
-
-	/* Apply the new settings. */
-	return hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
-}
-
-/**
- * hynix_get_majority - get the value that is occurring the most in a given
- *			set of values
- * @in: the array of values to test
- * @repeat: the size of the in array
- * @out: pointer used to store the output value
- *
- * This function implements the 'majority check' logic that is supposed to
- * overcome the unreliability of MLC NANDs when reading the OTP area storing
- * the read-retry parameters.
- *
- * It's based on a pretty simple assumption: if we repeat the same value
- * several times and then take the one that is occurring the most, we should
- * find the correct value.
- * Let's hope this dummy algorithm prevents us from losing the read-retry
- * parameters.
- */
-static int hynix_get_majority(const u8 *in, int repeat, u8 *out)
-{
-	int i, j, half = repeat / 2;
-
-	/*
-	 * We only test the first half of the in array because we must ensure
-	 * that the value is at least occurring repeat / 2 times.
-	 *
-	 * This loop is suboptimal since we may count the occurrences of the
-	 * same value several time, but we are doing that on small sets, which
-	 * makes it acceptable.
-	 */
-	for (i = 0; i < half; i++) {
-		int cnt = 0;
-		u8 val = in[i];
-
-		/* Count all values that are matching the one at index i. */
-		for (j = i + 1; j < repeat; j++) {
-			if (in[j] == val)
-				cnt++;
-		}
-
-		/* We found a value occurring more than repeat / 2. */
-		if (cnt > half) {
-			*out = val;
-			return 0;
-		}
-	}
-
-	return -EIO;
-}
-
-static int hynix_read_rr_otp(struct nand_chip *chip,
-			     const struct hynix_read_retry_otp *info,
-			     void *buf)
-{
-	int i, ret;
-
-	ret = nand_reset_op(chip);
-	if (ret)
-		return ret;
-
-	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < info->nregs; i++) {
-		ret = hynix_nand_reg_write_op(chip, info->regs[i],
-					      info->values[i]);
-		if (ret)
-			return ret;
-	}
-
-	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
-	if (ret)
-		return ret;
-
-	/* Sequence to enter OTP mode? */
-	ret = hynix_nand_cmd_op(chip, 0x17);
-	if (ret)
-		return ret;
-
-	ret = hynix_nand_cmd_op(chip, 0x4);
-	if (ret)
-		return ret;
-
-	ret = hynix_nand_cmd_op(chip, 0x19);
-	if (ret)
-		return ret;
-
-	/* Now read the page */
-	ret = nand_read_page_op(chip, info->page, 0, buf, info->size);
-	if (ret)
-		return ret;
-
-	/* Put everything back to normal */
-	ret = nand_reset_op(chip);
-	if (ret)
-		return ret;
-
-	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
-	if (ret)
-		return ret;
-
-	ret = hynix_nand_reg_write_op(chip, 0x38, 0);
-	if (ret)
-		return ret;
-
-	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
-	if (ret)
-		return ret;
-
-	return nand_read_page_op(chip, 0, 0, NULL, 0);
-}
-
-#define NAND_HYNIX_1XNM_RR_COUNT_OFFS				0
-#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS			8
-#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv)		\
-	(16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize)))
-
-static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs,
-				   int mode, int reg, bool inv, u8 *val)
-{
-	u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT];
-	int val_offs = (mode * nregs) + reg;
-	int set_size = nmodes * nregs;
-	int i, ret;
-
-	for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) {
-		int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv);
-
-		tmp[i] = buf[val_offs + set_offs];
-	}
-
-	ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val);
-	if (ret)
-		return ret;
-
-	if (inv)
-		*val = ~*val;
-
-	return 0;
-}
-
-static u8 hynix_1xnm_mlc_read_retry_regs[] = {
-	0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
-};
-
-static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
-				  const struct hynix_read_retry_otp *info)
-{
-	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
-	struct hynix_read_retry *rr = NULL;
-	int ret, i, j;
-	u8 nregs, nmodes;
-	u8 *buf;
-
-	buf = kmalloc(info->size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	ret = hynix_read_rr_otp(chip, info, buf);
-	if (ret)
-		goto out;
-
-	ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT,
-				 &nmodes);
-	if (ret)
-		goto out;
-
-	ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT,
-				 NAND_HYNIX_1XNM_RR_REPEAT,
-				 &nregs);
-	if (ret)
-		goto out;
-
-	rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL);
-	if (!rr) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	for (i = 0; i < nmodes; i++) {
-		for (j = 0; j < nregs; j++) {
-			u8 *val = rr->values + (i * nregs);
-
-			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
-						      false, val);
-			if (!ret)
-				continue;
-
-			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
-						      true, val);
-			if (ret)
-				goto out;
-		}
-	}
-
-	rr->nregs = nregs;
-	rr->regs = hynix_1xnm_mlc_read_retry_regs;
-	hynix->read_retry = rr;
-	chip->setup_read_retry = hynix_nand_setup_read_retry;
-	chip->read_retries = nmodes;
-
-out:
-	kfree(buf);
-
-	if (ret)
-		kfree(rr);
-
-	return ret;
-}
-
-static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 };
-static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 };
-
-static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = {
-	{
-		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
-		.regs = hynix_mlc_1xnm_rr_otp_regs,
-		.values = hynix_mlc_1xnm_rr_otp_values,
-		.page = 0x21f,
-		.size = 784
-	},
-	{
-		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
-		.regs = hynix_mlc_1xnm_rr_otp_regs,
-		.values = hynix_mlc_1xnm_rr_otp_values,
-		.page = 0x200,
-		.size = 528,
-	},
-};
-
-static int hynix_nand_rr_init(struct nand_chip *chip)
-{
-	int i, ret = 0;
-	bool valid_jedecid;
-
-	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
-
-	/*
-	 * We only support read-retry for 1xnm NANDs, and those NANDs all
-	 * expose a valid JEDEC ID.
-	 */
-	if (valid_jedecid) {
-		u8 nand_tech = chip->id.data[5] >> 4;
-
-		/* 1xnm technology */
-		if (nand_tech == 4) {
-			for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps);
-			     i++) {
-				/*
-				 * FIXME: Hynix recommend to copy the
-				 * read-retry OTP area into a normal page.
-				 */
-				ret = hynix_mlc_1xnm_rr_init(chip,
-						hynix_mlc_1xnm_rr_otps);
-				if (!ret)
-					break;
-			}
-		}
-	}
-
-	if (ret)
-		pr_warn("failed to initialize read-retry infrastructure");
-
-	return 0;
-}
-
-static void hynix_nand_extract_oobsize(struct nand_chip *chip,
-				       bool valid_jedecid)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 oobsize;
-
-	oobsize = ((chip->id.data[3] >> 2) & 0x3) |
-		  ((chip->id.data[3] >> 4) & 0x4);
-
-	if (valid_jedecid) {
-		switch (oobsize) {
-		case 0:
-			mtd->oobsize = 2048;
-			break;
-		case 1:
-			mtd->oobsize = 1664;
-			break;
-		case 2:
-			mtd->oobsize = 1024;
-			break;
-		case 3:
-			mtd->oobsize = 640;
-			break;
-		default:
-			/*
-			 * We should never reach this case, but if that
-			 * happens, this probably means Hynix decided to use
-			 * a different extended ID format, and we should find
-			 * a way to support it.
-			 */
-			WARN(1, "Invalid OOB size");
-			break;
-		}
-	} else {
-		switch (oobsize) {
-		case 0:
-			mtd->oobsize = 128;
-			break;
-		case 1:
-			mtd->oobsize = 224;
-			break;
-		case 2:
-			mtd->oobsize = 448;
-			break;
-		case 3:
-			mtd->oobsize = 64;
-			break;
-		case 4:
-			mtd->oobsize = 32;
-			break;
-		case 5:
-			mtd->oobsize = 16;
-			break;
-		case 6:
-			mtd->oobsize = 640;
-			break;
-		default:
-			/*
-			 * We should never reach this case, but if that
-			 * happens, this probably means Hynix decided to use
-			 * a different extended ID format, and we should find
-			 * a way to support it.
-			 */
-			WARN(1, "Invalid OOB size");
-			break;
-		}
-	}
-}
-
-static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
-						bool valid_jedecid)
-{
-	u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
-
-	if (valid_jedecid) {
-		/* Reference: H27UCG8T2E datasheet */
-		chip->ecc_step_ds = 1024;
-
-		switch (ecc_level) {
-		case 0:
-			chip->ecc_step_ds = 0;
-			chip->ecc_strength_ds = 0;
-			break;
-		case 1:
-			chip->ecc_strength_ds = 4;
-			break;
-		case 2:
-			chip->ecc_strength_ds = 24;
-			break;
-		case 3:
-			chip->ecc_strength_ds = 32;
-			break;
-		case 4:
-			chip->ecc_strength_ds = 40;
-			break;
-		case 5:
-			chip->ecc_strength_ds = 50;
-			break;
-		case 6:
-			chip->ecc_strength_ds = 60;
-			break;
-		default:
-			/*
-			 * We should never reach this case, but if that
-			 * happens, this probably means Hynix decided to use
-			 * a different extended ID format, and we should find
-			 * a way to support it.
-			 */
-			WARN(1, "Invalid ECC requirements");
-		}
-	} else {
-		/*
-		 * The ECC requirements field meaning depends on the
-		 * NAND technology.
-		 */
-		u8 nand_tech = chip->id.data[5] & 0x7;
-
-		if (nand_tech < 3) {
-			/* > 26nm, reference: H27UBG8T2A datasheet */
-			if (ecc_level < 5) {
-				chip->ecc_step_ds = 512;
-				chip->ecc_strength_ds = 1 << ecc_level;
-			} else if (ecc_level < 7) {
-				if (ecc_level == 5)
-					chip->ecc_step_ds = 2048;
-				else
-					chip->ecc_step_ds = 1024;
-				chip->ecc_strength_ds = 24;
-			} else {
-				/*
-				 * We should never reach this case, but if that
-				 * happens, this probably means Hynix decided
-				 * to use a different extended ID format, and
-				 * we should find a way to support it.
-				 */
-				WARN(1, "Invalid ECC requirements");
-			}
-		} else {
-			/* <= 26nm, reference: H27UBG8T2B datasheet */
-			if (!ecc_level) {
-				chip->ecc_step_ds = 0;
-				chip->ecc_strength_ds = 0;
-			} else if (ecc_level < 5) {
-				chip->ecc_step_ds = 512;
-				chip->ecc_strength_ds = 1 << (ecc_level - 1);
-			} else {
-				chip->ecc_step_ds = 1024;
-				chip->ecc_strength_ds = 24 +
-							(8 * (ecc_level - 5));
-			}
-		}
-	}
-}
-
-static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
-						       bool valid_jedecid)
-{
-	u8 nand_tech;
-
-	/* We need scrambling on all TLC NANDs*/
-	if (chip->bits_per_cell > 2)
-		chip->options |= NAND_NEED_SCRAMBLING;
-
-	/* And on MLC NANDs with sub-3xnm process */
-	if (valid_jedecid) {
-		nand_tech = chip->id.data[5] >> 4;
-
-		/* < 3xnm */
-		if (nand_tech > 0)
-			chip->options |= NAND_NEED_SCRAMBLING;
-	} else {
-		nand_tech = chip->id.data[5] & 0x7;
-
-		/* < 32nm */
-		if (nand_tech > 2)
-			chip->options |= NAND_NEED_SCRAMBLING;
-	}
-}
-
-static void hynix_nand_decode_id(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	bool valid_jedecid;
-	u8 tmp;
-
-	/*
-	 * Exclude all SLC NANDs from this advanced detection scheme.
-	 * According to the ranges defined in several datasheets, it might
-	 * appear that even SLC NANDs could fall in this extended ID scheme.
-	 * If that the case rework the test to let SLC NANDs go through the
-	 * detection process.
-	 */
-	if (chip->id.len < 6 || nand_is_slc(chip)) {
-		nand_decode_ext_id(chip);
-		return;
-	}
-
-	/* Extract pagesize */
-	mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
-
-	tmp = (chip->id.data[3] >> 4) & 0x3;
-	/*
-	 * When bit7 is set that means we start counting at 1MiB, otherwise
-	 * we start counting at 128KiB and shift this value the content of
-	 * ID[3][4:5].
-	 * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
-	 * this case the erasesize is set to 768KiB.
-	 */
-	if (chip->id.data[3] & 0x80)
-		mtd->erasesize = SZ_1M << tmp;
-	else if (tmp == 3)
-		mtd->erasesize = SZ_512K + SZ_256K;
-	else
-		mtd->erasesize = SZ_128K << tmp;
-
-	/*
-	 * Modern Toggle DDR NANDs have a valid JEDECID even though they are
-	 * not exposing a valid JEDEC parameter table.
-	 * These NANDs use a different NAND ID scheme.
-	 */
-	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
-
-	hynix_nand_extract_oobsize(chip, valid_jedecid);
-	hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
-	hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
-}
-
-static void hynix_nand_cleanup(struct nand_chip *chip)
-{
-	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
-
-	if (!hynix)
-		return;
-
-	kfree(hynix->read_retry);
-	kfree(hynix);
-	nand_set_manufacturer_data(chip, NULL);
-}
-
-static int hynix_nand_init(struct nand_chip *chip)
-{
-	struct hynix_nand *hynix;
-	int ret;
-
-	if (!nand_is_slc(chip))
-		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
-	else
-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
-	hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
-	if (!hynix)
-		return -ENOMEM;
-
-	nand_set_manufacturer_data(chip, hynix);
-
-	ret = hynix_nand_rr_init(chip);
-	if (ret)
-		hynix_nand_cleanup(chip);
-
-	return ret;
-}
-
-const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
-	.detect = hynix_nand_decode_id,
-	.init = hynix_nand_init,
-	.cleanup = hynix_nand_cleanup,
-};
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
deleted file mode 100644
index 5423c3bb388e..000000000000
--- a/drivers/mtd/nand/nand_ids.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.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/mtd/rawnand.h>
-#include <linux/sizes.h>
-
-#define LP_OPTIONS 0
-#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
-
-#define SP_OPTIONS NAND_NEED_READRDY
-#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
-
-/*
- * The chip ID list:
- *    name, device ID, page size, chip size in MiB, eraseblock size, options
- *
- * If page size and eraseblock size are 0, the sizes are taken from the
- * extended chip ID.
- */
-struct nand_flash_dev nand_flash_ids[] = {
-	/*
-	 * Some incompatible NAND chips share device ID's and so must be
-	 * listed by full ID. We list them first so that we can easily identify
-	 * the most specific match.
-	 */
-	{"TC58NVG0S3E 1G 3.3V 8-bit",
-		{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
-		  SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
-		  2 },
-	{"TC58NVG2S0F 4G 3.3V 8-bit",
-		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
-		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
-	{"TC58NVG2S0H 4G 3.3V 8-bit",
-		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
-		  SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
-	{"TC58NVG3S0F 8G 3.3V 8-bit",
-		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
-		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
-	{"TC58NVG5D2 32G 3.3V 8-bit",
-		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
-		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
-	{"TC58NVG6D2 64G 3.3V 8-bit",
-		{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
-		  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
-	{"SDTNRGAMA 64G 3.3V 8-bit",
-		{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
-		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
-	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
-		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
-		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
-		  NAND_ECC_INFO(40, SZ_1K), 4 },
-
-	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS),
-
-	LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit",  0x33, 16, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit",  0x73, 16, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16),
-	LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16),
-
-	LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit",  0x35, 32, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit",  0x75, 32, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16),
-	LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16),
-
-	LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit",  0x36, 64, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit",  0x76, 64, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16),
-	LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16),
-
-	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x78, 128, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x39, 128, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit",  0x79, 128, SZ_16K, SP_OPTIONS),
-	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16),
-	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16),
-	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16),
-	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16),
-
-	LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS),
-
-	/*
-	 * These are the new chips with large page size. Their page size and
-	 * eraseblock size are determined from the extended ID bytes.
-	 */
-
-	/* 512 Megabit */
-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA2,  64, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA0,  64, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF2,  64, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xD0,  64, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF0,  64, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2,  64, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0,  64, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2,  64, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0,  64, LP_OPTIONS16),
-
-	/* 1 Gigabit */
-	EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit",  0xA1, 128, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xF1, 128, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xD1, 128, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16),
-
-	/* 2 Gigabit */
-	EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit",  0xAA, 256, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit",  0xDA, 256, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16),
-
-	/* 4 Gigabit */
-	EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit",  0xAC, 512, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit",  0xDC, 512, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16),
-
-	/* 8 Gigabit */
-	EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit",  0xA3, 1024, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit",  0xD3, 1024, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16),
-
-	/* 16 Gigabit */
-	EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit",  0xA5, 2048, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit",  0xD5, 2048, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16),
-
-	/* 32 Gigabit */
-	EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit",  0xA7, 4096, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit",  0xD7, 4096, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16),
-
-	/* 64 Gigabit */
-	EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit",  0xAE, 8192, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit",  0xDE, 8192, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16),
-
-	/* 128 Gigabit */
-	EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit",  0x1A, 16384, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit",  0x3A, 16384, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16),
-
-	/* 256 Gigabit */
-	EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit",  0x1C, 32768, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit",  0x3C, 32768, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16),
-
-	/* 512 Gigabit */
-	EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit",  0x1E, 65536, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit",  0x3E, 65536, LP_OPTIONS),
-	EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16),
-	EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16),
-
-	{NULL}
-};
-
-/* Manufacturer IDs */
-static const struct nand_manufacturer nand_manufacturers[] = {
-	{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
-	{NAND_MFR_ESMT, "ESMT"},
-	{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
-	{NAND_MFR_FUJITSU, "Fujitsu"},
-	{NAND_MFR_NATIONAL, "National"},
-	{NAND_MFR_RENESAS, "Renesas"},
-	{NAND_MFR_STMICRO, "ST Micro"},
-	{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
-	{NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
-	{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
-	{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
-	{NAND_MFR_EON, "Eon"},
-	{NAND_MFR_SANDISK, "SanDisk"},
-	{NAND_MFR_INTEL, "Intel"},
-	{NAND_MFR_ATO, "ATO"},
-	{NAND_MFR_WINBOND, "Winbond"},
-};
-
-/**
- * nand_get_manufacturer - Get manufacturer information from the manufacturer
- *			   ID
- * @id: manufacturer ID
- *
- * Returns a pointer a nand_manufacturer object if the manufacturer is defined
- * in the NAND manufacturers database, NULL otherwise.
- */
-const struct nand_manufacturer *nand_get_manufacturer(u8 id)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
-		if (nand_manufacturers[i].id == id)
-			return &nand_manufacturers[i];
-
-	return NULL;
-}
diff --git a/drivers/mtd/nand/nand_macronix.c b/drivers/mtd/nand/nand_macronix.c
deleted file mode 100644
index d290ff2a6d2f..000000000000
--- a/drivers/mtd/nand/nand_macronix.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 Free Electrons
- * Copyright (C) 2017 NextThing Co
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mtd/rawnand.h>
-
-static int macronix_nand_init(struct nand_chip *chip)
-{
-	if (nand_is_slc(chip))
-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
-	return 0;
-}
-
-const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
-	.init = macronix_nand_init,
-};
diff --git a/drivers/mtd/nand/nand_micron.c b/drivers/mtd/nand/nand_micron.c
deleted file mode 100644
index 02e109ae73f1..000000000000
--- a/drivers/mtd/nand/nand_micron.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2017 Free Electrons
- * Copyright (C) 2017 NextThing Co
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mtd/rawnand.h>
-
-/*
- * Special Micron status bit that indicates when the block has been
- * corrected by on-die ECC and should be rewritten
- */
-#define NAND_STATUS_WRITE_RECOMMENDED	BIT(3)
-
-struct nand_onfi_vendor_micron {
-	u8 two_plane_read;
-	u8 read_cache;
-	u8 read_unique_id;
-	u8 dq_imped;
-	u8 dq_imped_num_settings;
-	u8 dq_imped_feat_addr;
-	u8 rb_pulldown_strength;
-	u8 rb_pulldown_strength_feat_addr;
-	u8 rb_pulldown_strength_num_settings;
-	u8 otp_mode;
-	u8 otp_page_start;
-	u8 otp_data_prot_addr;
-	u8 otp_num_pages;
-	u8 otp_feat_addr;
-	u8 read_retry_options;
-	u8 reserved[72];
-	u8 param_revision;
-} __packed;
-
-static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
-
-	return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
-				       feature);
-}
-
-/*
- * Configure chip properties from Micron vendor-specific ONFI table
- */
-static int micron_nand_onfi_init(struct nand_chip *chip)
-{
-	struct nand_onfi_params *p = &chip->onfi_params;
-	struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
-
-	if (!chip->onfi_version)
-		return 0;
-
-	if (le16_to_cpu(p->vendor_revision) < 1)
-		return 0;
-
-	chip->read_retries = micron->read_retry_options;
-	chip->setup_read_retry = micron_nand_setup_read_retry;
-
-	return 0;
-}
-
-static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
-					    struct mtd_oob_region *oobregion)
-{
-	if (section >= 4)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 8;
-	oobregion->length = 8;
-
-	return 0;
-}
-
-static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
-					     struct mtd_oob_region *oobregion)
-{
-	if (section >= 4)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 2;
-	oobregion->length = 6;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
-	.ecc = micron_nand_on_die_ooblayout_ecc,
-	.free = micron_nand_on_die_ooblayout_free,
-};
-
-static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
-{
-	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
-
-	if (enable)
-		feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
-
-	return chip->onfi_set_features(nand_to_mtd(chip), chip,
-				       ONFI_FEATURE_ON_DIE_ECC, feature);
-}
-
-static int
-micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-				 uint8_t *buf, int oob_required,
-				 int page)
-{
-	u8 status;
-	int ret, max_bitflips = 0;
-
-	ret = micron_nand_on_die_ecc_setup(chip, true);
-	if (ret)
-		return ret;
-
-	ret = nand_read_page_op(chip, page, 0, NULL, 0);
-	if (ret)
-		goto out;
-
-	ret = nand_status_op(chip, &status);
-	if (ret)
-		goto out;
-
-	ret = nand_exit_status_op(chip);
-	if (ret)
-		goto out;
-
-	if (status & NAND_STATUS_FAIL)
-		mtd->ecc_stats.failed++;
-
-	/*
-	 * The internal ECC doesn't tell us the number of bitflips
-	 * that have been corrected, but tells us if it recommends to
-	 * rewrite the block. If it's the case, then we pretend we had
-	 * a number of bitflips equal to the ECC strength, which will
-	 * hint the NAND core to rewrite the block.
-	 */
-	else if (status & NAND_STATUS_WRITE_RECOMMENDED)
-		max_bitflips = chip->ecc.strength;
-
-	ret = nand_read_data_op(chip, buf, mtd->writesize, false);
-	if (!ret && oob_required)
-		ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
-					false);
-
-out:
-	micron_nand_on_die_ecc_setup(chip, false);
-
-	return ret ? ret : max_bitflips;
-}
-
-static int
-micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-				  const uint8_t *buf, int oob_required,
-				  int page)
-{
-	int ret;
-
-	ret = micron_nand_on_die_ecc_setup(chip, true);
-	if (ret)
-		return ret;
-
-	ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
-	micron_nand_on_die_ecc_setup(chip, false);
-
-	return ret;
-}
-
-enum {
-	/* The NAND flash doesn't support on-die ECC */
-	MICRON_ON_DIE_UNSUPPORTED,
-
-	/*
-	 * The NAND flash supports on-die ECC and it can be
-	 * enabled/disabled by a set features command.
-	 */
-	MICRON_ON_DIE_SUPPORTED,
-
-	/*
-	 * The NAND flash supports on-die ECC, and it cannot be
-	 * disabled.
-	 */
-	MICRON_ON_DIE_MANDATORY,
-};
-
-/*
- * Try to detect if the NAND support on-die ECC. To do this, we enable
- * the feature, and read back if it has been enabled as expected. We
- * also check if it can be disabled, because some Micron NANDs do not
- * allow disabling the on-die ECC and we don't support such NANDs for
- * now.
- *
- * This function also has the side effect of disabling on-die ECC if
- * it had been left enabled by the firmware/bootloader.
- */
-static int micron_supports_on_die_ecc(struct nand_chip *chip)
-{
-	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
-	int ret;
-
-	if (chip->onfi_version == 0)
-		return MICRON_ON_DIE_UNSUPPORTED;
-
-	if (chip->bits_per_cell != 1)
-		return MICRON_ON_DIE_UNSUPPORTED;
-
-	ret = micron_nand_on_die_ecc_setup(chip, true);
-	if (ret)
-		return MICRON_ON_DIE_UNSUPPORTED;
-
-	chip->onfi_get_features(nand_to_mtd(chip), chip,
-				ONFI_FEATURE_ON_DIE_ECC, feature);
-	if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
-		return MICRON_ON_DIE_UNSUPPORTED;
-
-	ret = micron_nand_on_die_ecc_setup(chip, false);
-	if (ret)
-		return MICRON_ON_DIE_UNSUPPORTED;
-
-	chip->onfi_get_features(nand_to_mtd(chip), chip,
-				ONFI_FEATURE_ON_DIE_ECC, feature);
-	if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
-		return MICRON_ON_DIE_MANDATORY;
-
-	/*
-	 * Some Micron NANDs have an on-die ECC of 4/512, some other
-	 * 8/512. We only support the former.
-	 */
-	if (chip->onfi_params.ecc_bits != 4)
-		return MICRON_ON_DIE_UNSUPPORTED;
-
-	return MICRON_ON_DIE_SUPPORTED;
-}
-
-static int micron_nand_init(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ondie;
-	int ret;
-
-	ret = micron_nand_onfi_init(chip);
-	if (ret)
-		return ret;
-
-	if (mtd->writesize == 2048)
-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
-	ondie = micron_supports_on_die_ecc(chip);
-
-	if (ondie == MICRON_ON_DIE_MANDATORY) {
-		pr_err("On-die ECC forcefully enabled, not supported\n");
-		return -EINVAL;
-	}
-
-	if (chip->ecc.mode == NAND_ECC_ON_DIE) {
-		if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
-			pr_err("On-die ECC selected but not supported\n");
-			return -EINVAL;
-		}
-
-		chip->ecc.bytes = 8;
-		chip->ecc.size = 512;
-		chip->ecc.strength = 4;
-		chip->ecc.algo = NAND_ECC_BCH;
-		chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
-		chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
-		chip->ecc.read_page_raw = nand_read_page_raw;
-		chip->ecc.write_page_raw = nand_write_page_raw;
-
-		mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
-	}
-
-	return 0;
-}
-
-const struct nand_manufacturer_ops micron_nand_manuf_ops = {
-	.init = micron_nand_init,
-};
diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/nand_samsung.c
deleted file mode 100644
index ef022f62f74c..000000000000
--- a/drivers/mtd/nand/nand_samsung.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2017 Free Electrons
- * Copyright (C) 2017 NextThing Co
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mtd/rawnand.h>
-
-static void samsung_nand_decode_id(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
-	if (chip->id.len == 6 && !nand_is_slc(chip) &&
-	    chip->id.data[5] != 0x00) {
-		u8 extid = chip->id.data[3];
-
-		/* Get pagesize */
-		mtd->writesize = 2048 << (extid & 0x03);
-
-		extid >>= 2;
-
-		/* Get oobsize */
-		switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
-		case 1:
-			mtd->oobsize = 128;
-			break;
-		case 2:
-			mtd->oobsize = 218;
-			break;
-		case 3:
-			mtd->oobsize = 400;
-			break;
-		case 4:
-			mtd->oobsize = 436;
-			break;
-		case 5:
-			mtd->oobsize = 512;
-			break;
-		case 6:
-			mtd->oobsize = 640;
-			break;
-		default:
-			/*
-			 * We should never reach this case, but if that
-			 * happens, this probably means Samsung decided to use
-			 * a different extended ID format, and we should find
-			 * a way to support it.
-			 */
-			WARN(1, "Invalid OOB size value");
-			break;
-		}
-
-		/* Get blocksize */
-		extid >>= 2;
-		mtd->erasesize = (128 * 1024) <<
-				 (((extid >> 1) & 0x04) | (extid & 0x03));
-
-		/* Extract ECC requirements from 5th id byte*/
-		extid = (chip->id.data[4] >> 4) & 0x07;
-		if (extid < 5) {
-			chip->ecc_step_ds = 512;
-			chip->ecc_strength_ds = 1 << extid;
-		} else {
-			chip->ecc_step_ds = 1024;
-			switch (extid) {
-			case 5:
-				chip->ecc_strength_ds = 24;
-				break;
-			case 6:
-				chip->ecc_strength_ds = 40;
-				break;
-			case 7:
-				chip->ecc_strength_ds = 60;
-				break;
-			default:
-				WARN(1, "Could not decode ECC info");
-				chip->ecc_step_ds = 0;
-			}
-		}
-	} else {
-		nand_decode_ext_id(chip);
-
-		if (nand_is_slc(chip)) {
-			switch (chip->id.data[1]) {
-			/* K9F4G08U0D-S[I|C]B0(T00) */
-			case 0xDC:
-				chip->ecc_step_ds = 512;
-				chip->ecc_strength_ds = 1;
-				break;
-
-			/* K9F1G08U0E 21nm chips do not support subpage write */
-			case 0xF1:
-				if (chip->id.len > 4 &&
-				    (chip->id.data[4] & GENMASK(1, 0)) == 0x1)
-					chip->options |= NAND_NO_SUBPAGE_WRITE;
-				break;
-			default:
-				break;
-			}
-		}
-	}
-}
-
-static int samsung_nand_init(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	if (mtd->writesize > 512)
-		chip->options |= NAND_SAMSUNG_LP_OPTIONS;
-
-	if (!nand_is_slc(chip))
-		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
-	else
-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
-	return 0;
-}
-
-const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
-	.detect = samsung_nand_decode_id,
-	.init = samsung_nand_init,
-};
diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
deleted file mode 100644
index 9400d039ddbd..000000000000
--- a/drivers/mtd/nand/nand_timings.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- *  Copyright (C) 2014 Free Electrons
- *
- *  Author: Boris BREZILLON <boris.brezillon@free-electrons.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/kernel.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/mtd/rawnand.h>
-
-static const struct nand_data_interface onfi_sdr_timings[] = {
-	/* Mode 0 */
-	{
-		.type = NAND_SDR_IFACE,
-		.timings.sdr = {
-			.tCCS_min = 500000,
-			.tR_max = 200000000,
-			.tADL_min = 400000,
-			.tALH_min = 20000,
-			.tALS_min = 50000,
-			.tAR_min = 25000,
-			.tCEA_max = 100000,
-			.tCEH_min = 20000,
-			.tCH_min = 20000,
-			.tCHZ_max = 100000,
-			.tCLH_min = 20000,
-			.tCLR_min = 20000,
-			.tCLS_min = 50000,
-			.tCOH_min = 0,
-			.tCS_min = 70000,
-			.tDH_min = 20000,
-			.tDS_min = 40000,
-			.tFEAT_max = 1000000,
-			.tIR_min = 10000,
-			.tITC_max = 1000000,
-			.tRC_min = 100000,
-			.tREA_max = 40000,
-			.tREH_min = 30000,
-			.tRHOH_min = 0,
-			.tRHW_min = 200000,
-			.tRHZ_max = 200000,
-			.tRLOH_min = 0,
-			.tRP_min = 50000,
-			.tRR_min = 40000,
-			.tRST_max = 250000000000ULL,
-			.tWB_max = 200000,
-			.tWC_min = 100000,
-			.tWH_min = 30000,
-			.tWHR_min = 120000,
-			.tWP_min = 50000,
-			.tWW_min = 100000,
-		},
-	},
-	/* Mode 1 */
-	{
-		.type = NAND_SDR_IFACE,
-		.timings.sdr = {
-			.tCCS_min = 500000,
-			.tR_max = 200000000,
-			.tADL_min = 400000,
-			.tALH_min = 10000,
-			.tALS_min = 25000,
-			.tAR_min = 10000,
-			.tCEA_max = 45000,
-			.tCEH_min = 20000,
-			.tCH_min = 10000,
-			.tCHZ_max = 50000,
-			.tCLH_min = 10000,
-			.tCLR_min = 10000,
-			.tCLS_min = 25000,
-			.tCOH_min = 15000,
-			.tCS_min = 35000,
-			.tDH_min = 10000,
-			.tDS_min = 20000,
-			.tFEAT_max = 1000000,
-			.tIR_min = 0,
-			.tITC_max = 1000000,
-			.tRC_min = 50000,
-			.tREA_max = 30000,
-			.tREH_min = 15000,
-			.tRHOH_min = 15000,
-			.tRHW_min = 100000,
-			.tRHZ_max = 100000,
-			.tRLOH_min = 0,
-			.tRP_min = 25000,
-			.tRR_min = 20000,
-			.tRST_max = 500000000,
-			.tWB_max = 100000,
-			.tWC_min = 45000,
-			.tWH_min = 15000,
-			.tWHR_min = 80000,
-			.tWP_min = 25000,
-			.tWW_min = 100000,
-		},
-	},
-	/* Mode 2 */
-	{
-		.type = NAND_SDR_IFACE,
-		.timings.sdr = {
-			.tCCS_min = 500000,
-			.tR_max = 200000000,
-			.tADL_min = 400000,
-			.tALH_min = 10000,
-			.tALS_min = 15000,
-			.tAR_min = 10000,
-			.tCEA_max = 30000,
-			.tCEH_min = 20000,
-			.tCH_min = 10000,
-			.tCHZ_max = 50000,
-			.tCLH_min = 10000,
-			.tCLR_min = 10000,
-			.tCLS_min = 15000,
-			.tCOH_min = 15000,
-			.tCS_min = 25000,
-			.tDH_min = 5000,
-			.tDS_min = 15000,
-			.tFEAT_max = 1000000,
-			.tIR_min = 0,
-			.tITC_max = 1000000,
-			.tRC_min = 35000,
-			.tREA_max = 25000,
-			.tREH_min = 15000,
-			.tRHOH_min = 15000,
-			.tRHW_min = 100000,
-			.tRHZ_max = 100000,
-			.tRLOH_min = 0,
-			.tRR_min = 20000,
-			.tRST_max = 500000000,
-			.tWB_max = 100000,
-			.tRP_min = 17000,
-			.tWC_min = 35000,
-			.tWH_min = 15000,
-			.tWHR_min = 80000,
-			.tWP_min = 17000,
-			.tWW_min = 100000,
-		},
-	},
-	/* Mode 3 */
-	{
-		.type = NAND_SDR_IFACE,
-		.timings.sdr = {
-			.tCCS_min = 500000,
-			.tR_max = 200000000,
-			.tADL_min = 400000,
-			.tALH_min = 5000,
-			.tALS_min = 10000,
-			.tAR_min = 10000,
-			.tCEA_max = 25000,
-			.tCEH_min = 20000,
-			.tCH_min = 5000,
-			.tCHZ_max = 50000,
-			.tCLH_min = 5000,
-			.tCLR_min = 10000,
-			.tCLS_min = 10000,
-			.tCOH_min = 15000,
-			.tCS_min = 25000,
-			.tDH_min = 5000,
-			.tDS_min = 10000,
-			.tFEAT_max = 1000000,
-			.tIR_min = 0,
-			.tITC_max = 1000000,
-			.tRC_min = 30000,
-			.tREA_max = 20000,
-			.tREH_min = 10000,
-			.tRHOH_min = 15000,
-			.tRHW_min = 100000,
-			.tRHZ_max = 100000,
-			.tRLOH_min = 0,
-			.tRP_min = 15000,
-			.tRR_min = 20000,
-			.tRST_max = 500000000,
-			.tWB_max = 100000,
-			.tWC_min = 30000,
-			.tWH_min = 10000,
-			.tWHR_min = 80000,
-			.tWP_min = 15000,
-			.tWW_min = 100000,
-		},
-	},
-	/* Mode 4 */
-	{
-		.type = NAND_SDR_IFACE,
-		.timings.sdr = {
-			.tCCS_min = 500000,
-			.tR_max = 200000000,
-			.tADL_min = 400000,
-			.tALH_min = 5000,
-			.tALS_min = 10000,
-			.tAR_min = 10000,
-			.tCEA_max = 25000,
-			.tCEH_min = 20000,
-			.tCH_min = 5000,
-			.tCHZ_max = 30000,
-			.tCLH_min = 5000,
-			.tCLR_min = 10000,
-			.tCLS_min = 10000,
-			.tCOH_min = 15000,
-			.tCS_min = 20000,
-			.tDH_min = 5000,
-			.tDS_min = 10000,
-			.tFEAT_max = 1000000,
-			.tIR_min = 0,
-			.tITC_max = 1000000,
-			.tRC_min = 25000,
-			.tREA_max = 20000,
-			.tREH_min = 10000,
-			.tRHOH_min = 15000,
-			.tRHW_min = 100000,
-			.tRHZ_max = 100000,
-			.tRLOH_min = 5000,
-			.tRP_min = 12000,
-			.tRR_min = 20000,
-			.tRST_max = 500000000,
-			.tWB_max = 100000,
-			.tWC_min = 25000,
-			.tWH_min = 10000,
-			.tWHR_min = 80000,
-			.tWP_min = 12000,
-			.tWW_min = 100000,
-		},
-	},
-	/* Mode 5 */
-	{
-		.type = NAND_SDR_IFACE,
-		.timings.sdr = {
-			.tCCS_min = 500000,
-			.tR_max = 200000000,
-			.tADL_min = 400000,
-			.tALH_min = 5000,
-			.tALS_min = 10000,
-			.tAR_min = 10000,
-			.tCEA_max = 25000,
-			.tCEH_min = 20000,
-			.tCH_min = 5000,
-			.tCHZ_max = 30000,
-			.tCLH_min = 5000,
-			.tCLR_min = 10000,
-			.tCLS_min = 10000,
-			.tCOH_min = 15000,
-			.tCS_min = 15000,
-			.tDH_min = 5000,
-			.tDS_min = 7000,
-			.tFEAT_max = 1000000,
-			.tIR_min = 0,
-			.tITC_max = 1000000,
-			.tRC_min = 20000,
-			.tREA_max = 16000,
-			.tREH_min = 7000,
-			.tRHOH_min = 15000,
-			.tRHW_min = 100000,
-			.tRHZ_max = 100000,
-			.tRLOH_min = 5000,
-			.tRP_min = 10000,
-			.tRR_min = 20000,
-			.tRST_max = 500000000,
-			.tWB_max = 100000,
-			.tWC_min = 20000,
-			.tWH_min = 7000,
-			.tWHR_min = 80000,
-			.tWP_min = 10000,
-			.tWW_min = 100000,
-		},
-	},
-};
-
-/**
- * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
- * timings according to the given ONFI timing mode
- * @mode: ONFI timing mode
- */
-const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
-{
-	if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
-		return ERR_PTR(-EINVAL);
-
-	return &onfi_sdr_timings[mode].timings.sdr;
-}
-EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
-
-/**
- * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
- * given ONFI mode
- * @mode: The ONFI timing mode
- */
-int onfi_fill_data_interface(struct nand_chip *chip,
-			     enum nand_data_interface_type type,
-			     int timing_mode)
-{
-	struct nand_data_interface *iface = &chip->data_interface;
-
-	if (type != NAND_SDR_IFACE)
-		return -EINVAL;
-
-	if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
-		return -EINVAL;
-
-	*iface = onfi_sdr_timings[timing_mode];
-
-	/*
-	 * Initialize timings that cannot be deduced from timing mode:
-	 * tR, tPROG, tCCS, ...
-	 * These information are part of the ONFI parameter page.
-	 */
-	if (chip->onfi_version) {
-		struct nand_onfi_params *params = &chip->onfi_params;
-		struct nand_sdr_timings *timings = &iface->timings.sdr;
-
-		/* microseconds -> picoseconds */
-		timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog);
-		timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers);
-		timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r);
-
-		/* nanoseconds -> picoseconds */
-		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(onfi_fill_data_interface);
diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/nand_toshiba.c
deleted file mode 100644
index 57df857074e6..000000000000
--- a/drivers/mtd/nand/nand_toshiba.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 Free Electrons
- * Copyright (C) 2017 NextThing Co
- *
- * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mtd/rawnand.h>
-
-static void toshiba_nand_decode_id(struct nand_chip *chip)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	nand_decode_ext_id(chip);
-
-	/*
-	 * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
-	 * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
-	 * follows:
-	 * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
-	 *                         110b -> 24nm
-	 * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
-	 */
-	if (chip->id.len >= 6 && nand_is_slc(chip) &&
-	    (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
-	    !(chip->id.data[4] & 0x80) /* !BENAND */)
-		mtd->oobsize = 32 * mtd->writesize >> 9;
-}
-
-static int toshiba_nand_init(struct nand_chip *chip)
-{
-	if (nand_is_slc(chip))
-		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
-
-	return 0;
-}
-
-const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
-	.detect = toshiba_nand_decode_id,
-	.init = toshiba_nand_init,
-};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
deleted file mode 100644
index 44322a363ba5..000000000000
--- a/drivers/mtd/nand/nandsim.c
+++ /dev/null
@@ -1,2392 +0,0 @@
-/*
- * NAND flash simulator.
- *
- * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
- *
- * Copyright (C) 2004 Nokia Corporation
- *
- * Note: NS means "NAND Simulator".
- * Note: Input means input TO flash chip, output means output FROM chip.
- *
- * 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, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/vmalloc.h>
-#include <linux/math64.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_bch.h>
-#include <linux/mtd/partitions.h>
-#include <linux/delay.h>
-#include <linux/list.h>
-#include <linux/random.h>
-#include <linux/sched.h>
-#include <linux/sched/mm.h>
-#include <linux/fs.h>
-#include <linux/pagemap.h>
-#include <linux/seq_file.h>
-#include <linux/debugfs.h>
-
-/* Default simulator parameters values */
-#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
-    !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
-    !defined(CONFIG_NANDSIM_THIRD_ID_BYTE)  || \
-    !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
-#define CONFIG_NANDSIM_FIRST_ID_BYTE  0x98
-#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x39
-#define CONFIG_NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
-#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
-#endif
-
-#ifndef CONFIG_NANDSIM_ACCESS_DELAY
-#define CONFIG_NANDSIM_ACCESS_DELAY 25
-#endif
-#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
-#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
-#endif
-#ifndef CONFIG_NANDSIM_ERASE_DELAY
-#define CONFIG_NANDSIM_ERASE_DELAY 2
-#endif
-#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
-#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
-#endif
-#ifndef CONFIG_NANDSIM_INPUT_CYCLE
-#define CONFIG_NANDSIM_INPUT_CYCLE  50
-#endif
-#ifndef CONFIG_NANDSIM_BUS_WIDTH
-#define CONFIG_NANDSIM_BUS_WIDTH  8
-#endif
-#ifndef CONFIG_NANDSIM_DO_DELAYS
-#define CONFIG_NANDSIM_DO_DELAYS  0
-#endif
-#ifndef CONFIG_NANDSIM_LOG
-#define CONFIG_NANDSIM_LOG        0
-#endif
-#ifndef CONFIG_NANDSIM_DBG
-#define CONFIG_NANDSIM_DBG        0
-#endif
-#ifndef CONFIG_NANDSIM_MAX_PARTS
-#define CONFIG_NANDSIM_MAX_PARTS  32
-#endif
-
-static uint access_delay   = CONFIG_NANDSIM_ACCESS_DELAY;
-static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
-static uint erase_delay    = CONFIG_NANDSIM_ERASE_DELAY;
-static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
-static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
-static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
-static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
-static uint log            = CONFIG_NANDSIM_LOG;
-static uint dbg            = CONFIG_NANDSIM_DBG;
-static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
-static unsigned int parts_num;
-static char *badblocks = NULL;
-static char *weakblocks = NULL;
-static char *weakpages = NULL;
-static unsigned int bitflips = 0;
-static char *gravepages = NULL;
-static unsigned int overridesize = 0;
-static char *cache_file = NULL;
-static unsigned int bbt;
-static unsigned int bch;
-static u_char id_bytes[8] = {
-	[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
-	[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
-	[2] = CONFIG_NANDSIM_THIRD_ID_BYTE,
-	[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
-	[4 ... 7] = 0xFF,
-};
-
-module_param_array(id_bytes, byte, NULL, 0400);
-module_param_named(first_id_byte, id_bytes[0], byte, 0400);
-module_param_named(second_id_byte, id_bytes[1], byte, 0400);
-module_param_named(third_id_byte, id_bytes[2], byte, 0400);
-module_param_named(fourth_id_byte, id_bytes[3], byte, 0400);
-module_param(access_delay,   uint, 0400);
-module_param(programm_delay, uint, 0400);
-module_param(erase_delay,    uint, 0400);
-module_param(output_cycle,   uint, 0400);
-module_param(input_cycle,    uint, 0400);
-module_param(bus_width,      uint, 0400);
-module_param(do_delays,      uint, 0400);
-module_param(log,            uint, 0400);
-module_param(dbg,            uint, 0400);
-module_param_array(parts, ulong, &parts_num, 0400);
-module_param(badblocks,      charp, 0400);
-module_param(weakblocks,     charp, 0400);
-module_param(weakpages,      charp, 0400);
-module_param(bitflips,       uint, 0400);
-module_param(gravepages,     charp, 0400);
-module_param(overridesize,   uint, 0400);
-module_param(cache_file,     charp, 0400);
-module_param(bbt,	     uint, 0400);
-module_param(bch,	     uint, 0400);
-
-MODULE_PARM_DESC(id_bytes,       "The ID bytes returned by NAND Flash 'read ID' command");
-MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
-MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID) (obsolete)");
-MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command (obsolete)");
-MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command (obsolete)");
-MODULE_PARM_DESC(access_delay,   "Initial page access delay (microseconds)");
-MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
-MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");
-MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanoseconds)");
-MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanoseconds)");
-MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
-MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
-MODULE_PARM_DESC(log,            "Perform logging if not zero");
-MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
-MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
-/* Page and erase block positions for the following parameters are independent of any partitions */
-MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
-MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
-				 " separated by commas e.g. 113:2 means eb 113"
-				 " can be erased only twice before failing");
-MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"
-				 " separated by commas e.g. 1401:2 means page 1401"
-				 " can be written only twice before failing");
-MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");
-MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
-				 " separated by commas e.g. 1401:2 means page 1401"
-				 " can be read only twice before failing");
-MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
-				 "The size is specified in erase blocks and as the exponent of a power of two"
-				 " e.g. 5 means a size of 32 erase blocks");
-MODULE_PARM_DESC(cache_file,     "File to use to cache nand pages instead of memory");
-MODULE_PARM_DESC(bbt,		 "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
-MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
-				 "be correctable in 512-byte blocks");
-
-/* The largest possible page size */
-#define NS_LARGEST_PAGE_SIZE	4096
-
-/* The prefix for simulator output */
-#define NS_OUTPUT_PREFIX "[nandsim]"
-
-/* Simulator's output macros (logging, debugging, warning, error) */
-#define NS_LOG(args...) \
-	do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
-#define NS_DBG(args...) \
-	do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
-#define NS_WARN(args...) \
-	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
-#define NS_ERR(args...) \
-	do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
-#define NS_INFO(args...) \
-	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
-
-/* Busy-wait delay macros (microseconds, milliseconds) */
-#define NS_UDELAY(us) \
-        do { if (do_delays) udelay(us); } while(0)
-#define NS_MDELAY(us) \
-        do { if (do_delays) mdelay(us); } while(0)
-
-/* Is the nandsim structure initialized ? */
-#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
-
-/* Good operation completion status */
-#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
-
-/* Operation failed completion status */
-#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
-
-/* Calculate the page offset in flash RAM image by (row, column) address */
-#define NS_RAW_OFFSET(ns) \
-	(((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
-
-/* Calculate the OOB offset in flash RAM image by (row, column) address */
-#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
-
-/* After a command is input, the simulator goes to one of the following states */
-#define STATE_CMD_READ0        0x00000001 /* read data from the beginning of page */
-#define STATE_CMD_READ1        0x00000002 /* read data from the second half of page */
-#define STATE_CMD_READSTART    0x00000003 /* read data second command (large page devices) */
-#define STATE_CMD_PAGEPROG     0x00000004 /* start page program */
-#define STATE_CMD_READOOB      0x00000005 /* read OOB area */
-#define STATE_CMD_ERASE1       0x00000006 /* sector erase first command */
-#define STATE_CMD_STATUS       0x00000007 /* read status */
-#define STATE_CMD_SEQIN        0x00000009 /* sequential data input */
-#define STATE_CMD_READID       0x0000000A /* read ID */
-#define STATE_CMD_ERASE2       0x0000000B /* sector erase second command */
-#define STATE_CMD_RESET        0x0000000C /* reset */
-#define STATE_CMD_RNDOUT       0x0000000D /* random output command */
-#define STATE_CMD_RNDOUTSTART  0x0000000E /* random output start command */
-#define STATE_CMD_MASK         0x0000000F /* command states mask */
-
-/* After an address is input, the simulator goes to one of these states */
-#define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */
-#define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */
-#define STATE_ADDR_COLUMN      0x00000030 /* column address was accepted */
-#define STATE_ADDR_ZERO        0x00000040 /* one byte zero address was accepted */
-#define STATE_ADDR_MASK        0x00000070 /* address states mask */
-
-/* During data input/output the simulator is in these states */
-#define STATE_DATAIN           0x00000100 /* waiting for data input */
-#define STATE_DATAIN_MASK      0x00000100 /* data input states mask */
-
-#define STATE_DATAOUT          0x00001000 /* waiting for page data output */
-#define STATE_DATAOUT_ID       0x00002000 /* waiting for ID bytes output */
-#define STATE_DATAOUT_STATUS   0x00003000 /* waiting for status output */
-#define STATE_DATAOUT_MASK     0x00007000 /* data output states mask */
-
-/* Previous operation is done, ready to accept new requests */
-#define STATE_READY            0x00000000
-
-/* This state is used to mark that the next state isn't known yet */
-#define STATE_UNKNOWN          0x10000000
-
-/* Simulator's actions bit masks */
-#define ACTION_CPY       0x00100000 /* copy page/OOB to the internal buffer */
-#define ACTION_PRGPAGE   0x00200000 /* program the internal buffer to flash */
-#define ACTION_SECERASE  0x00300000 /* erase sector */
-#define ACTION_ZEROOFF   0x00400000 /* don't add any offset to address */
-#define ACTION_HALFOFF   0x00500000 /* add to address half of page */
-#define ACTION_OOBOFF    0x00600000 /* add to address OOB offset */
-#define ACTION_MASK      0x00700000 /* action mask */
-
-#define NS_OPER_NUM      13 /* Number of operations supported by the simulator */
-#define NS_OPER_STATES   6  /* Maximum number of states in operation */
-
-#define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */
-#define OPT_PAGE512      0x00000002 /* 512-byte  page chips */
-#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */
-#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
-#define OPT_PAGE4096     0x00000080 /* 4096-byte page chips */
-#define OPT_LARGEPAGE    (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
-#define OPT_SMALLPAGE    (OPT_PAGE512) /* 512-byte page chips */
-
-/* Remove action bits from state */
-#define NS_STATE(x) ((x) & ~ACTION_MASK)
-
-/*
- * Maximum previous states which need to be saved. Currently saving is
- * only needed for page program operation with preceded read command
- * (which is only valid for 512-byte pages).
- */
-#define NS_MAX_PREVSTATES 1
-
-/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
-#define NS_MAX_HELD_PAGES 16
-
-/*
- * A union to represent flash memory contents and flash buffer.
- */
-union ns_mem {
-	u_char *byte;    /* for byte access */
-	uint16_t *word;  /* for 16-bit word access */
-};
-
-/*
- * The structure which describes all the internal simulator data.
- */
-struct nandsim {
-	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
-	unsigned int nbparts;
-
-	uint busw;              /* flash chip bus width (8 or 16) */
-	u_char ids[8];          /* chip's ID bytes */
-	uint32_t options;       /* chip's characteristic bits */
-	uint32_t state;         /* current chip state */
-	uint32_t nxstate;       /* next expected state */
-
-	uint32_t *op;           /* current operation, NULL operations isn't known yet  */
-	uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
-	uint16_t npstates;      /* number of previous states saved */
-	uint16_t stateidx;      /* current state index */
-
-	/* The simulated NAND flash pages array */
-	union ns_mem *pages;
-
-	/* Slab allocator for nand pages */
-	struct kmem_cache *nand_pages_slab;
-
-	/* Internal buffer of page + OOB size bytes */
-	union ns_mem buf;
-
-	/* NAND flash "geometry" */
-	struct {
-		uint64_t totsz;     /* total flash size, bytes */
-		uint32_t secsz;     /* flash sector (erase block) size, bytes */
-		uint pgsz;          /* NAND flash page size, bytes */
-		uint oobsz;         /* page OOB area size, bytes */
-		uint64_t totszoob;  /* total flash size including OOB, bytes */
-		uint pgszoob;       /* page size including OOB , bytes*/
-		uint secszoob;      /* sector size including OOB, bytes */
-		uint pgnum;         /* total number of pages */
-		uint pgsec;         /* number of pages per sector */
-		uint secshift;      /* bits number in sector size */
-		uint pgshift;       /* bits number in page size */
-		uint pgaddrbytes;   /* bytes per page address */
-		uint secaddrbytes;  /* bytes per sector address */
-		uint idbytes;       /* the number ID bytes that this chip outputs */
-	} geom;
-
-	/* NAND flash internal registers */
-	struct {
-		unsigned command; /* the command register */
-		u_char   status;  /* the status register */
-		uint     row;     /* the page number */
-		uint     column;  /* the offset within page */
-		uint     count;   /* internal counter */
-		uint     num;     /* number of bytes which must be processed */
-		uint     off;     /* fixed page offset */
-	} regs;
-
-	/* NAND flash lines state */
-        struct {
-                int ce;  /* chip Enable */
-                int cle; /* command Latch Enable */
-                int ale; /* address Latch Enable */
-                int wp;  /* write Protect */
-        } lines;
-
-	/* Fields needed when using a cache file */
-	struct file *cfile; /* Open file */
-	unsigned long *pages_written; /* Which pages have been written */
-	void *file_buf;
-	struct page *held_pages[NS_MAX_HELD_PAGES];
-	int held_cnt;
-};
-
-/*
- * Operations array. To perform any operation the simulator must pass
- * through the correspondent states chain.
- */
-static struct nandsim_operations {
-	uint32_t reqopts;  /* options which are required to perform the operation */
-	uint32_t states[NS_OPER_STATES]; /* operation's states */
-} ops[NS_OPER_NUM] = {
-	/* Read page + OOB from the beginning */
-	{OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,
-			STATE_DATAOUT, STATE_READY}},
-	/* Read page + OOB from the second half */
-	{OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,
-			STATE_DATAOUT, STATE_READY}},
-	/* Read OOB */
-	{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
-			STATE_DATAOUT, STATE_READY}},
-	/* Program page starting from the beginning */
-	{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
-			STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-	/* Program page starting from the beginning */
-	{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
-			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-	/* Program page starting from the second half */
-	{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
-			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-	/* Program OOB */
-	{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
-			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
-	/* Erase sector */
-	{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
-	/* Read status */
-	{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
-	/* Read ID */
-	{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
-	/* Large page devices read page */
-	{OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY,
-			       STATE_DATAOUT, STATE_READY}},
-	/* Large page devices random page read */
-	{OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY,
-			       STATE_DATAOUT, STATE_READY}},
-};
-
-struct weak_block {
-	struct list_head list;
-	unsigned int erase_block_no;
-	unsigned int max_erases;
-	unsigned int erases_done;
-};
-
-static LIST_HEAD(weak_blocks);
-
-struct weak_page {
-	struct list_head list;
-	unsigned int page_no;
-	unsigned int max_writes;
-	unsigned int writes_done;
-};
-
-static LIST_HEAD(weak_pages);
-
-struct grave_page {
-	struct list_head list;
-	unsigned int page_no;
-	unsigned int max_reads;
-	unsigned int reads_done;
-};
-
-static LIST_HEAD(grave_pages);
-
-static unsigned long *erase_block_wear = NULL;
-static unsigned int wear_eb_count = 0;
-static unsigned long total_wear = 0;
-
-/* MTD structure for NAND controller */
-static struct mtd_info *nsmtd;
-
-static int nandsim_debugfs_show(struct seq_file *m, void *private)
-{
-	unsigned long wmin = -1, wmax = 0, avg;
-	unsigned long deciles[10], decile_max[10], tot = 0;
-	unsigned int i;
-
-	/* Calc wear stats */
-	for (i = 0; i < wear_eb_count; ++i) {
-		unsigned long wear = erase_block_wear[i];
-		if (wear < wmin)
-			wmin = wear;
-		if (wear > wmax)
-			wmax = wear;
-		tot += wear;
-	}
-
-	for (i = 0; i < 9; ++i) {
-		deciles[i] = 0;
-		decile_max[i] = (wmax * (i + 1) + 5) / 10;
-	}
-	deciles[9] = 0;
-	decile_max[9] = wmax;
-	for (i = 0; i < wear_eb_count; ++i) {
-		int d;
-		unsigned long wear = erase_block_wear[i];
-		for (d = 0; d < 10; ++d)
-			if (wear <= decile_max[d]) {
-				deciles[d] += 1;
-				break;
-			}
-	}
-	avg = tot / wear_eb_count;
-
-	/* Output wear report */
-	seq_printf(m, "Total numbers of erases:  %lu\n", tot);
-	seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
-	seq_printf(m, "Average number of erases: %lu\n", avg);
-	seq_printf(m, "Maximum number of erases: %lu\n", wmax);
-	seq_printf(m, "Minimum number of erases: %lu\n", wmin);
-	for (i = 0; i < 10; ++i) {
-		unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
-		if (from > decile_max[i])
-			continue;
-		seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
-			from,
-			decile_max[i],
-			deciles[i]);
-	}
-
-	return 0;
-}
-
-static int nandsim_debugfs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, nandsim_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations dfs_fops = {
-	.open		= nandsim_debugfs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-/**
- * nandsim_debugfs_create - initialize debugfs
- * @dev: nandsim device description object
- *
- * This function creates all debugfs files for UBI device @ubi. Returns zero in
- * case of success and a negative error code in case of failure.
- */
-static int nandsim_debugfs_create(struct nandsim *dev)
-{
-	struct dentry *root = nsmtd->dbg.dfs_dir;
-	struct dentry *dent;
-
-	/*
-	 * Just skip debugfs initialization when the debugfs directory is
-	 * missing.
-	 */
-	if (IS_ERR_OR_NULL(root)) {
-		if (IS_ENABLED(CONFIG_DEBUG_FS) &&
-		    !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
-			NS_WARN("CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n");
-		return 0;
-	}
-
-	dent = debugfs_create_file("nandsim_wear_report", S_IRUSR,
-				   root, dev, &dfs_fops);
-	if (IS_ERR_OR_NULL(dent)) {
-		NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * Allocate array of page pointers, create slab allocation for an array
- * and initialize the array by NULL pointers.
- *
- * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
- */
-static int __init alloc_device(struct nandsim *ns)
-{
-	struct file *cfile;
-	int i, err;
-
-	if (cache_file) {
-		cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
-		if (IS_ERR(cfile))
-			return PTR_ERR(cfile);
-		if (!(cfile->f_mode & FMODE_CAN_READ)) {
-			NS_ERR("alloc_device: cache file not readable\n");
-			err = -EINVAL;
-			goto err_close;
-		}
-		if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
-			NS_ERR("alloc_device: cache file not writeable\n");
-			err = -EINVAL;
-			goto err_close;
-		}
-		ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
-					    sizeof(unsigned long));
-		if (!ns->pages_written) {
-			NS_ERR("alloc_device: unable to allocate pages written array\n");
-			err = -ENOMEM;
-			goto err_close;
-		}
-		ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
-		if (!ns->file_buf) {
-			NS_ERR("alloc_device: unable to allocate file buf\n");
-			err = -ENOMEM;
-			goto err_free;
-		}
-		ns->cfile = cfile;
-		return 0;
-	}
-
-	ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
-	if (!ns->pages) {
-		NS_ERR("alloc_device: unable to allocate page array\n");
-		return -ENOMEM;
-	}
-	for (i = 0; i < ns->geom.pgnum; i++) {
-		ns->pages[i].byte = NULL;
-	}
-	ns->nand_pages_slab = kmem_cache_create("nandsim",
-						ns->geom.pgszoob, 0, 0, NULL);
-	if (!ns->nand_pages_slab) {
-		NS_ERR("cache_create: unable to create kmem_cache\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-
-err_free:
-	vfree(ns->pages_written);
-err_close:
-	filp_close(cfile, NULL);
-	return err;
-}
-
-/*
- * Free any allocated pages, and free the array of page pointers.
- */
-static void free_device(struct nandsim *ns)
-{
-	int i;
-
-	if (ns->cfile) {
-		kfree(ns->file_buf);
-		vfree(ns->pages_written);
-		filp_close(ns->cfile, NULL);
-		return;
-	}
-
-	if (ns->pages) {
-		for (i = 0; i < ns->geom.pgnum; i++) {
-			if (ns->pages[i].byte)
-				kmem_cache_free(ns->nand_pages_slab,
-						ns->pages[i].byte);
-		}
-		kmem_cache_destroy(ns->nand_pages_slab);
-		vfree(ns->pages);
-	}
-}
-
-static char __init *get_partition_name(int i)
-{
-	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
-}
-
-/*
- * Initialize the nandsim structure.
- *
- * RETURNS: 0 if success, -ERRNO if failure.
- */
-static int __init init_nandsim(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nandsim   *ns   = nand_get_controller_data(chip);
-	int i, ret = 0;
-	uint64_t remains;
-	uint64_t next_offset;
-
-	if (NS_IS_INITIALIZED(ns)) {
-		NS_ERR("init_nandsim: nandsim is already initialized\n");
-		return -EIO;
-	}
-
-	/* Force mtd to not do delays */
-	chip->chip_delay = 0;
-
-	/* Initialize the NAND flash parameters */
-	ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
-	ns->geom.totsz    = mtd->size;
-	ns->geom.pgsz     = mtd->writesize;
-	ns->geom.oobsz    = mtd->oobsize;
-	ns->geom.secsz    = mtd->erasesize;
-	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
-	ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
-	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
-	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
-	ns->geom.pgshift  = chip->page_shift;
-	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
-	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
-	ns->options = 0;
-
-	if (ns->geom.pgsz == 512) {
-		ns->options |= OPT_PAGE512;
-		if (ns->busw == 8)
-			ns->options |= OPT_PAGE512_8BIT;
-	} else if (ns->geom.pgsz == 2048) {
-		ns->options |= OPT_PAGE2048;
-	} else if (ns->geom.pgsz == 4096) {
-		ns->options |= OPT_PAGE4096;
-	} else {
-		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
-		return -EIO;
-	}
-
-	if (ns->options & OPT_SMALLPAGE) {
-		if (ns->geom.totsz <= (32 << 20)) {
-			ns->geom.pgaddrbytes  = 3;
-			ns->geom.secaddrbytes = 2;
-		} else {
-			ns->geom.pgaddrbytes  = 4;
-			ns->geom.secaddrbytes = 3;
-		}
-	} else {
-		if (ns->geom.totsz <= (128 << 20)) {
-			ns->geom.pgaddrbytes  = 4;
-			ns->geom.secaddrbytes = 2;
-		} else {
-			ns->geom.pgaddrbytes  = 5;
-			ns->geom.secaddrbytes = 3;
-		}
-	}
-
-	/* Fill the partition_info structure */
-	if (parts_num > ARRAY_SIZE(ns->partitions)) {
-		NS_ERR("too many partitions.\n");
-		return -EINVAL;
-	}
-	remains = ns->geom.totsz;
-	next_offset = 0;
-	for (i = 0; i < parts_num; ++i) {
-		uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
-
-		if (!part_sz || part_sz > remains) {
-			NS_ERR("bad partition size.\n");
-			return -EINVAL;
-		}
-		ns->partitions[i].name   = get_partition_name(i);
-		if (!ns->partitions[i].name) {
-			NS_ERR("unable to allocate memory.\n");
-			return -ENOMEM;
-		}
-		ns->partitions[i].offset = next_offset;
-		ns->partitions[i].size   = part_sz;
-		next_offset += ns->partitions[i].size;
-		remains -= ns->partitions[i].size;
-	}
-	ns->nbparts = parts_num;
-	if (remains) {
-		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
-			NS_ERR("too many partitions.\n");
-			return -EINVAL;
-		}
-		ns->partitions[i].name   = get_partition_name(i);
-		if (!ns->partitions[i].name) {
-			NS_ERR("unable to allocate memory.\n");
-			return -ENOMEM;
-		}
-		ns->partitions[i].offset = next_offset;
-		ns->partitions[i].size   = remains;
-		ns->nbparts += 1;
-	}
-
-	if (ns->busw == 16)
-		NS_WARN("16-bit flashes support wasn't tested\n");
-
-	printk("flash size: %llu MiB\n",
-			(unsigned long long)ns->geom.totsz >> 20);
-	printk("page size: %u bytes\n",         ns->geom.pgsz);
-	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
-	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
-	printk("pages number: %u\n",            ns->geom.pgnum);
-	printk("pages per sector: %u\n",        ns->geom.pgsec);
-	printk("bus width: %u\n",               ns->busw);
-	printk("bits in sector size: %u\n",     ns->geom.secshift);
-	printk("bits in page size: %u\n",       ns->geom.pgshift);
-	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
-	printk("flash size with OOB: %llu KiB\n",
-			(unsigned long long)ns->geom.totszoob >> 10);
-	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
-	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
-	printk("options: %#x\n",                ns->options);
-
-	if ((ret = alloc_device(ns)) != 0)
-		return ret;
-
-	/* Allocate / initialize the internal buffer */
-	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
-	if (!ns->buf.byte) {
-		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
-			ns->geom.pgszoob);
-		return -ENOMEM;
-	}
-	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
-
-	return 0;
-}
-
-/*
- * Free the nandsim structure.
- */
-static void free_nandsim(struct nandsim *ns)
-{
-	kfree(ns->buf.byte);
-	free_device(ns);
-
-	return;
-}
-
-static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
-{
-	char *w;
-	int zero_ok;
-	unsigned int erase_block_no;
-	loff_t offset;
-
-	if (!badblocks)
-		return 0;
-	w = badblocks;
-	do {
-		zero_ok = (*w == '0' ? 1 : 0);
-		erase_block_no = simple_strtoul(w, &w, 0);
-		if (!zero_ok && !erase_block_no) {
-			NS_ERR("invalid badblocks.\n");
-			return -EINVAL;
-		}
-		offset = (loff_t)erase_block_no * ns->geom.secsz;
-		if (mtd_block_markbad(mtd, offset)) {
-			NS_ERR("invalid badblocks.\n");
-			return -EINVAL;
-		}
-		if (*w == ',')
-			w += 1;
-	} while (*w);
-	return 0;
-}
-
-static int parse_weakblocks(void)
-{
-	char *w;
-	int zero_ok;
-	unsigned int erase_block_no;
-	unsigned int max_erases;
-	struct weak_block *wb;
-
-	if (!weakblocks)
-		return 0;
-	w = weakblocks;
-	do {
-		zero_ok = (*w == '0' ? 1 : 0);
-		erase_block_no = simple_strtoul(w, &w, 0);
-		if (!zero_ok && !erase_block_no) {
-			NS_ERR("invalid weakblocks.\n");
-			return -EINVAL;
-		}
-		max_erases = 3;
-		if (*w == ':') {
-			w += 1;
-			max_erases = simple_strtoul(w, &w, 0);
-		}
-		if (*w == ',')
-			w += 1;
-		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
-		if (!wb) {
-			NS_ERR("unable to allocate memory.\n");
-			return -ENOMEM;
-		}
-		wb->erase_block_no = erase_block_no;
-		wb->max_erases = max_erases;
-		list_add(&wb->list, &weak_blocks);
-	} while (*w);
-	return 0;
-}
-
-static int erase_error(unsigned int erase_block_no)
-{
-	struct weak_block *wb;
-
-	list_for_each_entry(wb, &weak_blocks, list)
-		if (wb->erase_block_no == erase_block_no) {
-			if (wb->erases_done >= wb->max_erases)
-				return 1;
-			wb->erases_done += 1;
-			return 0;
-		}
-	return 0;
-}
-
-static int parse_weakpages(void)
-{
-	char *w;
-	int zero_ok;
-	unsigned int page_no;
-	unsigned int max_writes;
-	struct weak_page *wp;
-
-	if (!weakpages)
-		return 0;
-	w = weakpages;
-	do {
-		zero_ok = (*w == '0' ? 1 : 0);
-		page_no = simple_strtoul(w, &w, 0);
-		if (!zero_ok && !page_no) {
-			NS_ERR("invalid weakpages.\n");
-			return -EINVAL;
-		}
-		max_writes = 3;
-		if (*w == ':') {
-			w += 1;
-			max_writes = simple_strtoul(w, &w, 0);
-		}
-		if (*w == ',')
-			w += 1;
-		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
-		if (!wp) {
-			NS_ERR("unable to allocate memory.\n");
-			return -ENOMEM;
-		}
-		wp->page_no = page_no;
-		wp->max_writes = max_writes;
-		list_add(&wp->list, &weak_pages);
-	} while (*w);
-	return 0;
-}
-
-static int write_error(unsigned int page_no)
-{
-	struct weak_page *wp;
-
-	list_for_each_entry(wp, &weak_pages, list)
-		if (wp->page_no == page_no) {
-			if (wp->writes_done >= wp->max_writes)
-				return 1;
-			wp->writes_done += 1;
-			return 0;
-		}
-	return 0;
-}
-
-static int parse_gravepages(void)
-{
-	char *g;
-	int zero_ok;
-	unsigned int page_no;
-	unsigned int max_reads;
-	struct grave_page *gp;
-
-	if (!gravepages)
-		return 0;
-	g = gravepages;
-	do {
-		zero_ok = (*g == '0' ? 1 : 0);
-		page_no = simple_strtoul(g, &g, 0);
-		if (!zero_ok && !page_no) {
-			NS_ERR("invalid gravepagess.\n");
-			return -EINVAL;
-		}
-		max_reads = 3;
-		if (*g == ':') {
-			g += 1;
-			max_reads = simple_strtoul(g, &g, 0);
-		}
-		if (*g == ',')
-			g += 1;
-		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
-		if (!gp) {
-			NS_ERR("unable to allocate memory.\n");
-			return -ENOMEM;
-		}
-		gp->page_no = page_no;
-		gp->max_reads = max_reads;
-		list_add(&gp->list, &grave_pages);
-	} while (*g);
-	return 0;
-}
-
-static int read_error(unsigned int page_no)
-{
-	struct grave_page *gp;
-
-	list_for_each_entry(gp, &grave_pages, list)
-		if (gp->page_no == page_no) {
-			if (gp->reads_done >= gp->max_reads)
-				return 1;
-			gp->reads_done += 1;
-			return 0;
-		}
-	return 0;
-}
-
-static void free_lists(void)
-{
-	struct list_head *pos, *n;
-	list_for_each_safe(pos, n, &weak_blocks) {
-		list_del(pos);
-		kfree(list_entry(pos, struct weak_block, list));
-	}
-	list_for_each_safe(pos, n, &weak_pages) {
-		list_del(pos);
-		kfree(list_entry(pos, struct weak_page, list));
-	}
-	list_for_each_safe(pos, n, &grave_pages) {
-		list_del(pos);
-		kfree(list_entry(pos, struct grave_page, list));
-	}
-	kfree(erase_block_wear);
-}
-
-static int setup_wear_reporting(struct mtd_info *mtd)
-{
-	size_t mem;
-
-	wear_eb_count = div_u64(mtd->size, mtd->erasesize);
-	mem = wear_eb_count * sizeof(unsigned long);
-	if (mem / sizeof(unsigned long) != wear_eb_count) {
-		NS_ERR("Too many erase blocks for wear reporting\n");
-		return -ENOMEM;
-	}
-	erase_block_wear = kzalloc(mem, GFP_KERNEL);
-	if (!erase_block_wear) {
-		NS_ERR("Too many erase blocks for wear reporting\n");
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-static void update_wear(unsigned int erase_block_no)
-{
-	if (!erase_block_wear)
-		return;
-	total_wear += 1;
-	/*
-	 * TODO: Notify this through a debugfs entry,
-	 * instead of showing an error message.
-	 */
-	if (total_wear == 0)
-		NS_ERR("Erase counter total overflow\n");
-	erase_block_wear[erase_block_no] += 1;
-	if (erase_block_wear[erase_block_no] == 0)
-		NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
-}
-
-/*
- * Returns the string representation of 'state' state.
- */
-static char *get_state_name(uint32_t state)
-{
-	switch (NS_STATE(state)) {
-		case STATE_CMD_READ0:
-			return "STATE_CMD_READ0";
-		case STATE_CMD_READ1:
-			return "STATE_CMD_READ1";
-		case STATE_CMD_PAGEPROG:
-			return "STATE_CMD_PAGEPROG";
-		case STATE_CMD_READOOB:
-			return "STATE_CMD_READOOB";
-		case STATE_CMD_READSTART:
-			return "STATE_CMD_READSTART";
-		case STATE_CMD_ERASE1:
-			return "STATE_CMD_ERASE1";
-		case STATE_CMD_STATUS:
-			return "STATE_CMD_STATUS";
-		case STATE_CMD_SEQIN:
-			return "STATE_CMD_SEQIN";
-		case STATE_CMD_READID:
-			return "STATE_CMD_READID";
-		case STATE_CMD_ERASE2:
-			return "STATE_CMD_ERASE2";
-		case STATE_CMD_RESET:
-			return "STATE_CMD_RESET";
-		case STATE_CMD_RNDOUT:
-			return "STATE_CMD_RNDOUT";
-		case STATE_CMD_RNDOUTSTART:
-			return "STATE_CMD_RNDOUTSTART";
-		case STATE_ADDR_PAGE:
-			return "STATE_ADDR_PAGE";
-		case STATE_ADDR_SEC:
-			return "STATE_ADDR_SEC";
-		case STATE_ADDR_ZERO:
-			return "STATE_ADDR_ZERO";
-		case STATE_ADDR_COLUMN:
-			return "STATE_ADDR_COLUMN";
-		case STATE_DATAIN:
-			return "STATE_DATAIN";
-		case STATE_DATAOUT:
-			return "STATE_DATAOUT";
-		case STATE_DATAOUT_ID:
-			return "STATE_DATAOUT_ID";
-		case STATE_DATAOUT_STATUS:
-			return "STATE_DATAOUT_STATUS";
-		case STATE_READY:
-			return "STATE_READY";
-		case STATE_UNKNOWN:
-			return "STATE_UNKNOWN";
-	}
-
-	NS_ERR("get_state_name: unknown state, BUG\n");
-	return NULL;
-}
-
-/*
- * Check if command is valid.
- *
- * RETURNS: 1 if wrong command, 0 if right.
- */
-static int check_command(int cmd)
-{
-	switch (cmd) {
-
-	case NAND_CMD_READ0:
-	case NAND_CMD_READ1:
-	case NAND_CMD_READSTART:
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_READOOB:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_READID:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_RESET:
-	case NAND_CMD_RNDOUT:
-	case NAND_CMD_RNDOUTSTART:
-		return 0;
-
-	default:
-		return 1;
-	}
-}
-
-/*
- * Returns state after command is accepted by command number.
- */
-static uint32_t get_state_by_command(unsigned command)
-{
-	switch (command) {
-		case NAND_CMD_READ0:
-			return STATE_CMD_READ0;
-		case NAND_CMD_READ1:
-			return STATE_CMD_READ1;
-		case NAND_CMD_PAGEPROG:
-			return STATE_CMD_PAGEPROG;
-		case NAND_CMD_READSTART:
-			return STATE_CMD_READSTART;
-		case NAND_CMD_READOOB:
-			return STATE_CMD_READOOB;
-		case NAND_CMD_ERASE1:
-			return STATE_CMD_ERASE1;
-		case NAND_CMD_STATUS:
-			return STATE_CMD_STATUS;
-		case NAND_CMD_SEQIN:
-			return STATE_CMD_SEQIN;
-		case NAND_CMD_READID:
-			return STATE_CMD_READID;
-		case NAND_CMD_ERASE2:
-			return STATE_CMD_ERASE2;
-		case NAND_CMD_RESET:
-			return STATE_CMD_RESET;
-		case NAND_CMD_RNDOUT:
-			return STATE_CMD_RNDOUT;
-		case NAND_CMD_RNDOUTSTART:
-			return STATE_CMD_RNDOUTSTART;
-	}
-
-	NS_ERR("get_state_by_command: unknown command, BUG\n");
-	return 0;
-}
-
-/*
- * Move an address byte to the correspondent internal register.
- */
-static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
-{
-	uint byte = (uint)bt;
-
-	if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
-		ns->regs.column |= (byte << 8 * ns->regs.count);
-	else {
-		ns->regs.row |= (byte << 8 * (ns->regs.count -
-						ns->geom.pgaddrbytes +
-						ns->geom.secaddrbytes));
-	}
-
-	return;
-}
-
-/*
- * Switch to STATE_READY state.
- */
-static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
-{
-	NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
-
-	ns->state       = STATE_READY;
-	ns->nxstate     = STATE_UNKNOWN;
-	ns->op          = NULL;
-	ns->npstates    = 0;
-	ns->stateidx    = 0;
-	ns->regs.num    = 0;
-	ns->regs.count  = 0;
-	ns->regs.off    = 0;
-	ns->regs.row    = 0;
-	ns->regs.column = 0;
-	ns->regs.status = status;
-}
-
-/*
- * If the operation isn't known yet, try to find it in the global array
- * of supported operations.
- *
- * Operation can be unknown because of the following.
- *   1. New command was accepted and this is the first call to find the
- *      correspondent states chain. In this case ns->npstates = 0;
- *   2. There are several operations which begin with the same command(s)
- *      (for example program from the second half and read from the
- *      second half operations both begin with the READ1 command). In this
- *      case the ns->pstates[] array contains previous states.
- *
- * Thus, the function tries to find operation containing the following
- * states (if the 'flag' parameter is 0):
- *    ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
- *
- * If (one and only one) matching operation is found, it is accepted (
- * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
- * zeroed).
- *
- * If there are several matches, the current state is pushed to the
- * ns->pstates.
- *
- * The operation can be unknown only while commands are input to the chip.
- * As soon as address command is accepted, the operation must be known.
- * In such situation the function is called with 'flag' != 0, and the
- * operation is searched using the following pattern:
- *     ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
- *
- * It is supposed that this pattern must either match one operation or
- * none. There can't be ambiguity in that case.
- *
- * If no matches found, the function does the following:
- *   1. if there are saved states present, try to ignore them and search
- *      again only using the last command. If nothing was found, switch
- *      to the STATE_READY state.
- *   2. if there are no saved states, switch to the STATE_READY state.
- *
- * RETURNS: -2 - no matched operations found.
- *          -1 - several matches.
- *           0 - operation is found.
- */
-static int find_operation(struct nandsim *ns, uint32_t flag)
-{
-	int opsfound = 0;
-	int i, j, idx = 0;
-
-	for (i = 0; i < NS_OPER_NUM; i++) {
-
-		int found = 1;
-
-		if (!(ns->options & ops[i].reqopts))
-			/* Ignore operations we can't perform */
-			continue;
-
-		if (flag) {
-			if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
-				continue;
-		} else {
-			if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates]))
-				continue;
-		}
-
-		for (j = 0; j < ns->npstates; j++)
-			if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
-				&& (ns->options & ops[idx].reqopts)) {
-				found = 0;
-				break;
-			}
-
-		if (found) {
-			idx = i;
-			opsfound += 1;
-		}
-	}
-
-	if (opsfound == 1) {
-		/* Exact match */
-		ns->op = &ops[idx].states[0];
-		if (flag) {
-			/*
-			 * In this case the find_operation function was
-			 * called when address has just began input. But it isn't
-			 * yet fully input and the current state must
-			 * not be one of STATE_ADDR_*, but the STATE_ADDR_*
-			 * state must be the next state (ns->nxstate).
-			 */
-			ns->stateidx = ns->npstates - 1;
-		} else {
-			ns->stateidx = ns->npstates;
-		}
-		ns->npstates = 0;
-		ns->state = ns->op[ns->stateidx];
-		ns->nxstate = ns->op[ns->stateidx + 1];
-		NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
-				idx, get_state_name(ns->state), get_state_name(ns->nxstate));
-		return 0;
-	}
-
-	if (opsfound == 0) {
-		/* Nothing was found. Try to ignore previous commands (if any) and search again */
-		if (ns->npstates != 0) {
-			NS_DBG("find_operation: no operation found, try again with state %s\n",
-					get_state_name(ns->state));
-			ns->npstates = 0;
-			return find_operation(ns, 0);
-
-		}
-		NS_DBG("find_operation: no operations found\n");
-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-		return -2;
-	}
-
-	if (flag) {
-		/* This shouldn't happen */
-		NS_DBG("find_operation: BUG, operation must be known if address is input\n");
-		return -2;
-	}
-
-	NS_DBG("find_operation: there is still ambiguity\n");
-
-	ns->pstates[ns->npstates++] = ns->state;
-
-	return -1;
-}
-
-static void put_pages(struct nandsim *ns)
-{
-	int i;
-
-	for (i = 0; i < ns->held_cnt; i++)
-		put_page(ns->held_pages[i]);
-}
-
-/* Get page cache pages in advance to provide NOFS memory allocation */
-static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
-{
-	pgoff_t index, start_index, end_index;
-	struct page *page;
-	struct address_space *mapping = file->f_mapping;
-
-	start_index = pos >> PAGE_SHIFT;
-	end_index = (pos + count - 1) >> PAGE_SHIFT;
-	if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
-		return -EINVAL;
-	ns->held_cnt = 0;
-	for (index = start_index; index <= end_index; index++) {
-		page = find_get_page(mapping, index);
-		if (page == NULL) {
-			page = find_or_create_page(mapping, index, GFP_NOFS);
-			if (page == NULL) {
-				write_inode_now(mapping->host, 1);
-				page = find_or_create_page(mapping, index, GFP_NOFS);
-			}
-			if (page == NULL) {
-				put_pages(ns);
-				return -ENOMEM;
-			}
-			unlock_page(page);
-		}
-		ns->held_pages[ns->held_cnt++] = page;
-	}
-	return 0;
-}
-
-static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
-{
-	ssize_t tx;
-	int err;
-	unsigned int noreclaim_flag;
-
-	err = get_pages(ns, file, count, pos);
-	if (err)
-		return err;
-	noreclaim_flag = memalloc_noreclaim_save();
-	tx = kernel_read(file, buf, count, &pos);
-	memalloc_noreclaim_restore(noreclaim_flag);
-	put_pages(ns);
-	return tx;
-}
-
-static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
-{
-	ssize_t tx;
-	int err;
-	unsigned int noreclaim_flag;
-
-	err = get_pages(ns, file, count, pos);
-	if (err)
-		return err;
-	noreclaim_flag = memalloc_noreclaim_save();
-	tx = kernel_write(file, buf, count, &pos);
-	memalloc_noreclaim_restore(noreclaim_flag);
-	put_pages(ns);
-	return tx;
-}
-
-/*
- * Returns a pointer to the current page.
- */
-static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
-{
-	return &(ns->pages[ns->regs.row]);
-}
-
-/*
- * Retuns a pointer to the current byte, within the current page.
- */
-static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
-{
-	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
-}
-
-static int do_read_error(struct nandsim *ns, int num)
-{
-	unsigned int page_no = ns->regs.row;
-
-	if (read_error(page_no)) {
-		prandom_bytes(ns->buf.byte, num);
-		NS_WARN("simulating read error in page %u\n", page_no);
-		return 1;
-	}
-	return 0;
-}
-
-static void do_bit_flips(struct nandsim *ns, int num)
-{
-	if (bitflips && prandom_u32() < (1 << 22)) {
-		int flips = 1;
-		if (bitflips > 1)
-			flips = (prandom_u32() % (int) bitflips) + 1;
-		while (flips--) {
-			int pos = prandom_u32() % (num * 8);
-			ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
-			NS_WARN("read_page: flipping bit %d in page %d "
-				"reading from %d ecc: corrected=%u failed=%u\n",
-				pos, ns->regs.row, ns->regs.column + ns->regs.off,
-				nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
-		}
-	}
-}
-
-/*
- * Fill the NAND buffer with data read from the specified page.
- */
-static void read_page(struct nandsim *ns, int num)
-{
-	union ns_mem *mypage;
-
-	if (ns->cfile) {
-		if (!test_bit(ns->regs.row, ns->pages_written)) {
-			NS_DBG("read_page: page %d not written\n", ns->regs.row);
-			memset(ns->buf.byte, 0xFF, num);
-		} else {
-			loff_t pos;
-			ssize_t tx;
-
-			NS_DBG("read_page: page %d written, reading from %d\n",
-				ns->regs.row, ns->regs.column + ns->regs.off);
-			if (do_read_error(ns, num))
-				return;
-			pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
-			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
-			if (tx != num) {
-				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return;
-			}
-			do_bit_flips(ns, num);
-		}
-		return;
-	}
-
-	mypage = NS_GET_PAGE(ns);
-	if (mypage->byte == NULL) {
-		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
-		memset(ns->buf.byte, 0xFF, num);
-	} else {
-		NS_DBG("read_page: page %d allocated, reading from %d\n",
-			ns->regs.row, ns->regs.column + ns->regs.off);
-		if (do_read_error(ns, num))
-			return;
-		memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
-		do_bit_flips(ns, num);
-	}
-}
-
-/*
- * Erase all pages in the specified sector.
- */
-static void erase_sector(struct nandsim *ns)
-{
-	union ns_mem *mypage;
-	int i;
-
-	if (ns->cfile) {
-		for (i = 0; i < ns->geom.pgsec; i++)
-			if (__test_and_clear_bit(ns->regs.row + i,
-						 ns->pages_written)) {
-				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
-			}
-		return;
-	}
-
-	mypage = NS_GET_PAGE(ns);
-	for (i = 0; i < ns->geom.pgsec; i++) {
-		if (mypage->byte != NULL) {
-			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
-			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
-			mypage->byte = NULL;
-		}
-		mypage++;
-	}
-}
-
-/*
- * Program the specified page with the contents from the NAND buffer.
- */
-static int prog_page(struct nandsim *ns, int num)
-{
-	int i;
-	union ns_mem *mypage;
-	u_char *pg_off;
-
-	if (ns->cfile) {
-		loff_t off;
-		ssize_t tx;
-		int all;
-
-		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
-		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
-		off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
-		if (!test_bit(ns->regs.row, ns->pages_written)) {
-			all = 1;
-			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
-		} else {
-			all = 0;
-			tx = read_file(ns, ns->cfile, pg_off, num, off);
-			if (tx != num) {
-				NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return -1;
-			}
-		}
-		for (i = 0; i < num; i++)
-			pg_off[i] &= ns->buf.byte[i];
-		if (all) {
-			loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
-			tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
-			if (tx != ns->geom.pgszoob) {
-				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return -1;
-			}
-			__set_bit(ns->regs.row, ns->pages_written);
-		} else {
-			tx = write_file(ns, ns->cfile, pg_off, num, off);
-			if (tx != num) {
-				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return -1;
-			}
-		}
-		return 0;
-	}
-
-	mypage = NS_GET_PAGE(ns);
-	if (mypage->byte == NULL) {
-		NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
-		/*
-		 * We allocate memory with GFP_NOFS because a flash FS may
-		 * utilize this. If it is holding an FS lock, then gets here,
-		 * then kernel memory alloc runs writeback which goes to the FS
-		 * again and deadlocks. This was seen in practice.
-		 */
-		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
-		if (mypage->byte == NULL) {
-			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
-			return -1;
-		}
-		memset(mypage->byte, 0xFF, ns->geom.pgszoob);
-	}
-
-	pg_off = NS_PAGE_BYTE_OFF(ns);
-	for (i = 0; i < num; i++)
-		pg_off[i] &= ns->buf.byte[i];
-
-	return 0;
-}
-
-/*
- * If state has any action bit, perform this action.
- *
- * RETURNS: 0 if success, -1 if error.
- */
-static int do_state_action(struct nandsim *ns, uint32_t action)
-{
-	int num;
-	int busdiv = ns->busw == 8 ? 1 : 2;
-	unsigned int erase_block_no, page_no;
-
-	action &= ACTION_MASK;
-
-	/* Check that page address input is correct */
-	if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
-		NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
-		return -1;
-	}
-
-	switch (action) {
-
-	case ACTION_CPY:
-		/*
-		 * Copy page data to the internal buffer.
-		 */
-
-		/* Column shouldn't be very large */
-		if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
-			NS_ERR("do_state_action: column number is too large\n");
-			break;
-		}
-		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-		read_page(ns, num);
-
-		NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
-			num, NS_RAW_OFFSET(ns) + ns->regs.off);
-
-		if (ns->regs.off == 0)
-			NS_LOG("read page %d\n", ns->regs.row);
-		else if (ns->regs.off < ns->geom.pgsz)
-			NS_LOG("read page %d (second half)\n", ns->regs.row);
-		else
-			NS_LOG("read OOB of page %d\n", ns->regs.row);
-
-		NS_UDELAY(access_delay);
-		NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
-
-		break;
-
-	case ACTION_SECERASE:
-		/*
-		 * Erase sector.
-		 */
-
-		if (ns->lines.wp) {
-			NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
-			return -1;
-		}
-
-		if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
-			|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
-			NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
-			return -1;
-		}
-
-		ns->regs.row = (ns->regs.row <<
-				8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
-		ns->regs.column = 0;
-
-		erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
-
-		NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
-				ns->regs.row, NS_RAW_OFFSET(ns));
-		NS_LOG("erase sector %u\n", erase_block_no);
-
-		erase_sector(ns);
-
-		NS_MDELAY(erase_delay);
-
-		if (erase_block_wear)
-			update_wear(erase_block_no);
-
-		if (erase_error(erase_block_no)) {
-			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
-			return -1;
-		}
-
-		break;
-
-	case ACTION_PRGPAGE:
-		/*
-		 * Program page - move internal buffer data to the page.
-		 */
-
-		if (ns->lines.wp) {
-			NS_WARN("do_state_action: device is write-protected, programm\n");
-			return -1;
-		}
-
-		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-		if (num != ns->regs.count) {
-			NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
-					ns->regs.count, num);
-			return -1;
-		}
-
-		if (prog_page(ns, num) == -1)
-			return -1;
-
-		page_no = ns->regs.row;
-
-		NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
-			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
-		NS_LOG("programm page %d\n", ns->regs.row);
-
-		NS_UDELAY(programm_delay);
-		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
-
-		if (write_error(page_no)) {
-			NS_WARN("simulating write failure in page %u\n", page_no);
-			return -1;
-		}
-
-		break;
-
-	case ACTION_ZEROOFF:
-		NS_DBG("do_state_action: set internal offset to 0\n");
-		ns->regs.off = 0;
-		break;
-
-	case ACTION_HALFOFF:
-		if (!(ns->options & OPT_PAGE512_8BIT)) {
-			NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
-				"byte page size 8x chips\n");
-			return -1;
-		}
-		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
-		ns->regs.off = ns->geom.pgsz/2;
-		break;
-
-	case ACTION_OOBOFF:
-		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
-		ns->regs.off = ns->geom.pgsz;
-		break;
-
-	default:
-		NS_DBG("do_state_action: BUG! unknown action\n");
-	}
-
-	return 0;
-}
-
-/*
- * Switch simulator's state.
- */
-static void switch_state(struct nandsim *ns)
-{
-	if (ns->op) {
-		/*
-		 * The current operation have already been identified.
-		 * Just follow the states chain.
-		 */
-
-		ns->stateidx += 1;
-		ns->state = ns->nxstate;
-		ns->nxstate = ns->op[ns->stateidx + 1];
-
-		NS_DBG("switch_state: operation is known, switch to the next state, "
-			"state: %s, nxstate: %s\n",
-			get_state_name(ns->state), get_state_name(ns->nxstate));
-
-		/* See, whether we need to do some action */
-		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-			return;
-		}
-
-	} else {
-		/*
-		 * We don't yet know which operation we perform.
-		 * Try to identify it.
-		 */
-
-		/*
-		 *  The only event causing the switch_state function to
-		 *  be called with yet unknown operation is new command.
-		 */
-		ns->state = get_state_by_command(ns->regs.command);
-
-		NS_DBG("switch_state: operation is unknown, try to find it\n");
-
-		if (find_operation(ns, 0) != 0)
-			return;
-
-		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-			return;
-		}
-	}
-
-	/* For 16x devices column means the page offset in words */
-	if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
-		NS_DBG("switch_state: double the column number for 16x device\n");
-		ns->regs.column <<= 1;
-	}
-
-	if (NS_STATE(ns->nxstate) == STATE_READY) {
-		/*
-		 * The current state is the last. Return to STATE_READY
-		 */
-
-		u_char status = NS_STATUS_OK(ns);
-
-		/* In case of data states, see if all bytes were input/output */
-		if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
-			&& ns->regs.count != ns->regs.num) {
-			NS_WARN("switch_state: not all bytes were processed, %d left\n",
-					ns->regs.num - ns->regs.count);
-			status = NS_STATUS_FAILED(ns);
-		}
-
-		NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
-
-		switch_to_ready_state(ns, status);
-
-		return;
-	} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
-		/*
-		 * If the next state is data input/output, switch to it now
-		 */
-
-		ns->state      = ns->nxstate;
-		ns->nxstate    = ns->op[++ns->stateidx + 1];
-		ns->regs.num   = ns->regs.count = 0;
-
-		NS_DBG("switch_state: the next state is data I/O, switch, "
-			"state: %s, nxstate: %s\n",
-			get_state_name(ns->state), get_state_name(ns->nxstate));
-
-		/*
-		 * Set the internal register to the count of bytes which
-		 * are expected to be input or output
-		 */
-		switch (NS_STATE(ns->state)) {
-			case STATE_DATAIN:
-			case STATE_DATAOUT:
-				ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-				break;
-
-			case STATE_DATAOUT_ID:
-				ns->regs.num = ns->geom.idbytes;
-				break;
-
-			case STATE_DATAOUT_STATUS:
-				ns->regs.count = ns->regs.num = 0;
-				break;
-
-			default:
-				NS_ERR("switch_state: BUG! unknown data state\n");
-		}
-
-	} else if (ns->nxstate & STATE_ADDR_MASK) {
-		/*
-		 * If the next state is address input, set the internal
-		 * register to the number of expected address bytes
-		 */
-
-		ns->regs.count = 0;
-
-		switch (NS_STATE(ns->nxstate)) {
-			case STATE_ADDR_PAGE:
-				ns->regs.num = ns->geom.pgaddrbytes;
-
-				break;
-			case STATE_ADDR_SEC:
-				ns->regs.num = ns->geom.secaddrbytes;
-				break;
-
-			case STATE_ADDR_ZERO:
-				ns->regs.num = 1;
-				break;
-
-			case STATE_ADDR_COLUMN:
-				/* Column address is always 2 bytes */
-				ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes;
-				break;
-
-			default:
-				NS_ERR("switch_state: BUG! unknown address state\n");
-		}
-	} else {
-		/*
-		 * Just reset internal counters.
-		 */
-
-		ns->regs.num = 0;
-		ns->regs.count = 0;
-	}
-}
-
-static u_char ns_nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nandsim *ns = nand_get_controller_data(chip);
-	u_char outb = 0x00;
-
-	/* Sanity and correctness checks */
-	if (!ns->lines.ce) {
-		NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
-		return outb;
-	}
-	if (ns->lines.ale || ns->lines.cle) {
-		NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
-		return outb;
-	}
-	if (!(ns->state & STATE_DATAOUT_MASK)) {
-		NS_WARN("read_byte: unexpected data output cycle, state is %s "
-			"return %#x\n", get_state_name(ns->state), (uint)outb);
-		return outb;
-	}
-
-	/* Status register may be read as many times as it is wanted */
-	if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
-		NS_DBG("read_byte: return %#x status\n", ns->regs.status);
-		return ns->regs.status;
-	}
-
-	/* Check if there is any data in the internal buffer which may be read */
-	if (ns->regs.count == ns->regs.num) {
-		NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
-		return outb;
-	}
-
-	switch (NS_STATE(ns->state)) {
-		case STATE_DATAOUT:
-			if (ns->busw == 8) {
-				outb = ns->buf.byte[ns->regs.count];
-				ns->regs.count += 1;
-			} else {
-				outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
-				ns->regs.count += 2;
-			}
-			break;
-		case STATE_DATAOUT_ID:
-			NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
-			outb = ns->ids[ns->regs.count];
-			ns->regs.count += 1;
-			break;
-		default:
-			BUG();
-	}
-
-	if (ns->regs.count == ns->regs.num) {
-		NS_DBG("read_byte: all bytes were read\n");
-
-		if (NS_STATE(ns->nxstate) == STATE_READY)
-			switch_state(ns);
-	}
-
-	return outb;
-}
-
-static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nandsim *ns = nand_get_controller_data(chip);
-
-	/* Sanity and correctness checks */
-	if (!ns->lines.ce) {
-		NS_ERR("write_byte: chip is disabled, ignore write\n");
-		return;
-	}
-	if (ns->lines.ale && ns->lines.cle) {
-		NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
-		return;
-	}
-
-	if (ns->lines.cle == 1) {
-		/*
-		 * The byte written is a command.
-		 */
-
-		if (byte == NAND_CMD_RESET) {
-			NS_LOG("reset chip\n");
-			switch_to_ready_state(ns, NS_STATUS_OK(ns));
-			return;
-		}
-
-		/* Check that the command byte is correct */
-		if (check_command(byte)) {
-			NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
-			return;
-		}
-
-		if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
-			|| NS_STATE(ns->state) == STATE_DATAOUT) {
-			int row = ns->regs.row;
-
-			switch_state(ns);
-			if (byte == NAND_CMD_RNDOUT)
-				ns->regs.row = row;
-		}
-
-		/* Check if chip is expecting command */
-		if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
-			/* Do not warn if only 2 id bytes are read */
-			if (!(ns->regs.command == NAND_CMD_READID &&
-			    NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
-				/*
-				 * We are in situation when something else (not command)
-				 * was expected but command was input. In this case ignore
-				 * previous command(s)/state(s) and accept the last one.
-				 */
-				NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
-					"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
-			}
-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-		}
-
-		NS_DBG("command byte corresponding to %s state accepted\n",
-			get_state_name(get_state_by_command(byte)));
-		ns->regs.command = byte;
-		switch_state(ns);
-
-	} else if (ns->lines.ale == 1) {
-		/*
-		 * The byte written is an address.
-		 */
-
-		if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
-
-			NS_DBG("write_byte: operation isn't known yet, identify it\n");
-
-			if (find_operation(ns, 1) < 0)
-				return;
-
-			if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
-				switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-				return;
-			}
-
-			ns->regs.count = 0;
-			switch (NS_STATE(ns->nxstate)) {
-				case STATE_ADDR_PAGE:
-					ns->regs.num = ns->geom.pgaddrbytes;
-					break;
-				case STATE_ADDR_SEC:
-					ns->regs.num = ns->geom.secaddrbytes;
-					break;
-				case STATE_ADDR_ZERO:
-					ns->regs.num = 1;
-					break;
-				default:
-					BUG();
-			}
-		}
-
-		/* Check that chip is expecting address */
-		if (!(ns->nxstate & STATE_ADDR_MASK)) {
-			NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
-				"switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-			return;
-		}
-
-		/* Check if this is expected byte */
-		if (ns->regs.count == ns->regs.num) {
-			NS_ERR("write_byte: no more address bytes expected\n");
-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-			return;
-		}
-
-		accept_addr_byte(ns, byte);
-
-		ns->regs.count += 1;
-
-		NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
-				(uint)byte, ns->regs.count, ns->regs.num);
-
-		if (ns->regs.count == ns->regs.num) {
-			NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
-			switch_state(ns);
-		}
-
-	} else {
-		/*
-		 * The byte written is an input data.
-		 */
-
-		/* Check that chip is expecting data input */
-		if (!(ns->state & STATE_DATAIN_MASK)) {
-			NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
-				"switch to %s\n", (uint)byte,
-				get_state_name(ns->state), get_state_name(STATE_READY));
-			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-			return;
-		}
-
-		/* Check if this is expected byte */
-		if (ns->regs.count == ns->regs.num) {
-			NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
-					ns->regs.num);
-			return;
-		}
-
-		if (ns->busw == 8) {
-			ns->buf.byte[ns->regs.count] = byte;
-			ns->regs.count += 1;
-		} else {
-			ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
-			ns->regs.count += 2;
-		}
-	}
-
-	return;
-}
-
-static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nandsim *ns = nand_get_controller_data(chip);
-
-	ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
-	ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
-	ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
-
-	if (cmd != NAND_CMD_NONE)
-		ns_nand_write_byte(mtd, cmd);
-}
-
-static int ns_device_ready(struct mtd_info *mtd)
-{
-	NS_DBG("device_ready\n");
-	return 1;
-}
-
-static uint16_t ns_nand_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	NS_DBG("read_word\n");
-
-	return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
-}
-
-static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nandsim *ns = nand_get_controller_data(chip);
-
-	/* Check that chip is expecting data input */
-	if (!(ns->state & STATE_DATAIN_MASK)) {
-		NS_ERR("write_buf: data input isn't expected, state is %s, "
-			"switch to STATE_READY\n", get_state_name(ns->state));
-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-		return;
-	}
-
-	/* Check if these are expected bytes */
-	if (ns->regs.count + len > ns->regs.num) {
-		NS_ERR("write_buf: too many input bytes\n");
-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-		return;
-	}
-
-	memcpy(ns->buf.byte + ns->regs.count, buf, len);
-	ns->regs.count += len;
-
-	if (ns->regs.count == ns->regs.num) {
-		NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
-	}
-}
-
-static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nandsim *ns = nand_get_controller_data(chip);
-
-	/* Sanity and correctness checks */
-	if (!ns->lines.ce) {
-		NS_ERR("read_buf: chip is disabled\n");
-		return;
-	}
-	if (ns->lines.ale || ns->lines.cle) {
-		NS_ERR("read_buf: ALE or CLE pin is high\n");
-		return;
-	}
-	if (!(ns->state & STATE_DATAOUT_MASK)) {
-		NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
-			get_state_name(ns->state));
-		return;
-	}
-
-	if (NS_STATE(ns->state) != STATE_DATAOUT) {
-		int i;
-
-		for (i = 0; i < len; i++)
-			buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
-
-		return;
-	}
-
-	/* Check if these are expected bytes */
-	if (ns->regs.count + len > ns->regs.num) {
-		NS_ERR("read_buf: too many bytes to read\n");
-		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
-		return;
-	}
-
-	memcpy(buf, ns->buf.byte + ns->regs.count, len);
-	ns->regs.count += len;
-
-	if (ns->regs.count == ns->regs.num) {
-		if (NS_STATE(ns->nxstate) == STATE_READY)
-			switch_state(ns);
-	}
-
-	return;
-}
-
-/*
- * Module initialization function
- */
-static int __init ns_init_module(void)
-{
-	struct nand_chip *chip;
-	struct nandsim *nand;
-	int retval = -ENOMEM, i;
-
-	if (bus_width != 8 && bus_width != 16) {
-		NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
-		return -EINVAL;
-	}
-
-	/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
-	chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
-		       GFP_KERNEL);
-	if (!chip) {
-		NS_ERR("unable to allocate core structures.\n");
-		return -ENOMEM;
-	}
-	nsmtd       = nand_to_mtd(chip);
-	nand        = (struct nandsim *)(chip + 1);
-	nand_set_controller_data(chip, (void *)nand);
-
-	/*
-	 * Register simulator's callbacks.
-	 */
-	chip->cmd_ctrl	 = ns_hwcontrol;
-	chip->read_byte  = ns_nand_read_byte;
-	chip->dev_ready  = ns_device_ready;
-	chip->write_buf  = ns_nand_write_buf;
-	chip->read_buf   = ns_nand_read_buf;
-	chip->read_word  = ns_nand_read_word;
-	chip->ecc.mode   = NAND_ECC_SOFT;
-	chip->ecc.algo   = NAND_ECC_HAMMING;
-	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
-	/* and 'badblocks' parameters to work */
-	chip->options   |= NAND_SKIP_BBTSCAN;
-
-	switch (bbt) {
-	case 2:
-		 chip->bbt_options |= NAND_BBT_NO_OOB;
-	case 1:
-		 chip->bbt_options |= NAND_BBT_USE_FLASH;
-	case 0:
-		break;
-	default:
-		NS_ERR("bbt has to be 0..2\n");
-		retval = -EINVAL;
-		goto error;
-	}
-	/*
-	 * Perform minimum nandsim structure initialization to handle
-	 * the initial ID read command correctly
-	 */
-	if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
-		nand->geom.idbytes = 8;
-	else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
-		nand->geom.idbytes = 6;
-	else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
-		nand->geom.idbytes = 4;
-	else
-		nand->geom.idbytes = 2;
-	nand->regs.status = NS_STATUS_OK(nand);
-	nand->nxstate = STATE_UNKNOWN;
-	nand->options |= OPT_PAGE512; /* temporary value */
-	memcpy(nand->ids, id_bytes, sizeof(nand->ids));
-	if (bus_width == 16) {
-		nand->busw = 16;
-		chip->options |= NAND_BUSWIDTH_16;
-	}
-
-	nsmtd->owner = THIS_MODULE;
-
-	if ((retval = parse_weakblocks()) != 0)
-		goto error;
-
-	if ((retval = parse_weakpages()) != 0)
-		goto error;
-
-	if ((retval = parse_gravepages()) != 0)
-		goto error;
-
-	retval = nand_scan_ident(nsmtd, 1, NULL);
-	if (retval) {
-		NS_ERR("cannot scan NAND Simulator device\n");
-		goto error;
-	}
-
-	if (bch) {
-		unsigned int eccsteps, eccbytes;
-		if (!mtd_nand_has_bch()) {
-			NS_ERR("BCH ECC support is disabled\n");
-			retval = -EINVAL;
-			goto error;
-		}
-		/* use 512-byte ecc blocks */
-		eccsteps = nsmtd->writesize/512;
-		eccbytes = (bch*13+7)/8;
-		/* do not bother supporting small page devices */
-		if ((nsmtd->oobsize < 64) || !eccsteps) {
-			NS_ERR("bch not available on small page devices\n");
-			retval = -EINVAL;
-			goto error;
-		}
-		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
-			NS_ERR("invalid bch value %u\n", bch);
-			retval = -EINVAL;
-			goto error;
-		}
-		chip->ecc.mode = NAND_ECC_SOFT;
-		chip->ecc.algo = NAND_ECC_BCH;
-		chip->ecc.size = 512;
-		chip->ecc.strength = bch;
-		chip->ecc.bytes = eccbytes;
-		NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
-	}
-
-	retval = nand_scan_tail(nsmtd);
-	if (retval) {
-		NS_ERR("can't register NAND Simulator\n");
-		goto error;
-	}
-
-	if (overridesize) {
-		uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
-		if (new_size >> overridesize != nsmtd->erasesize) {
-			NS_ERR("overridesize is too big\n");
-			retval = -EINVAL;
-			goto err_exit;
-		}
-		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
-		nsmtd->size = new_size;
-		chip->chipsize = new_size;
-		chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
-		chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
-	}
-
-	if ((retval = setup_wear_reporting(nsmtd)) != 0)
-		goto err_exit;
-
-	if ((retval = init_nandsim(nsmtd)) != 0)
-		goto err_exit;
-
-	if ((retval = chip->scan_bbt(nsmtd)) != 0)
-		goto err_exit;
-
-	if ((retval = parse_badblocks(nand, nsmtd)) != 0)
-		goto err_exit;
-
-	/* Register NAND partitions */
-	retval = mtd_device_register(nsmtd, &nand->partitions[0],
-				     nand->nbparts);
-	if (retval != 0)
-		goto err_exit;
-
-	if ((retval = nandsim_debugfs_create(nand)) != 0)
-		goto err_exit;
-
-        return 0;
-
-err_exit:
-	free_nandsim(nand);
-	nand_release(nsmtd);
-	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
-		kfree(nand->partitions[i].name);
-error:
-	kfree(chip);
-	free_lists();
-
-	return retval;
-}
-
-module_init(ns_init_module);
-
-/*
- * Module clean-up function
- */
-static void __exit ns_cleanup_module(void)
-{
-	struct nand_chip *chip = mtd_to_nand(nsmtd);
-	struct nandsim *ns = nand_get_controller_data(chip);
-	int i;
-
-	free_nandsim(ns);    /* Free nandsim private resources */
-	nand_release(nsmtd); /* Unregister driver */
-	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
-		kfree(ns->partitions[i].name);
-	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
-	free_lists();
-}
-
-module_exit(ns_cleanup_module);
-
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Artem B. Bityuckiy");
-MODULE_DESCRIPTION ("The NAND flash simulator");
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
deleted file mode 100644
index d8a806894937..000000000000
--- a/drivers/mtd/nand/ndfc.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- *  Overview:
- *   Platform independent driver for NDFC (NanD Flash Controller)
- *   integrated into EP440 cores
- *
- *   Ported to an OF platform driver by Sean MacLennan
- *
- *   The NDFC supports multiple chips, but this driver only supports a
- *   single chip since I do not have access to any boards with
- *   multiple chips.
- *
- *  Author: Thomas Gleixner
- *
- *  Copyright 2006 IBM
- *  Copyright 2008 PIKA Technologies
- *    Sean MacLennan <smaclennan@pikatech.com>
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/ndfc.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <asm/io.h>
-
-#define NDFC_MAX_CS    4
-
-struct ndfc_controller {
-	struct platform_device *ofdev;
-	void __iomem *ndfcbase;
-	struct nand_chip chip;
-	int chip_select;
-	struct nand_hw_control ndfc_control;
-};
-
-static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
-
-static void ndfc_select_chip(struct mtd_info *mtd, int chip)
-{
-	uint32_t ccr;
-	struct nand_chip *nchip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
-
-	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
-	if (chip >= 0) {
-		ccr &= ~NDFC_CCR_BS_MASK;
-		ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
-	} else
-		ccr |= NDFC_CCR_RESET_CE;
-	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
-}
-
-static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
-	else
-		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
-}
-
-static int ndfc_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
-
-	return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
-}
-
-static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	uint32_t ccr;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
-
-	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
-	ccr |= NDFC_CCR_RESET_ECC;
-	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
-	wmb();
-}
-
-static int ndfc_calculate_ecc(struct mtd_info *mtd,
-			      const u_char *dat, u_char *ecc_code)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
-	uint32_t ecc;
-	uint8_t *p = (uint8_t *)&ecc;
-
-	wmb();
-	ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
-	/* The NDFC uses Smart Media (SMC) bytes order */
-	ecc_code[0] = p[1];
-	ecc_code[1] = p[2];
-	ecc_code[2] = p[3];
-
-	return 0;
-}
-
-/*
- * Speedups for buffer read/write/verify
- *
- * NDFC allows 32bit read/write of data. So we can speed up the buffer
- * functions. No further checking, as nand_base will always read/write
- * page aligned.
- */
-static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
-	uint32_t *p = (uint32_t *) buf;
-
-	for(;len > 0; len -= 4)
-		*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
-}
-
-static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
-	uint32_t *p = (uint32_t *) buf;
-
-	for(;len > 0; len -= 4)
-		out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
-}
-
-/*
- * Initialize chip structure
- */
-static int ndfc_chip_init(struct ndfc_controller *ndfc,
-			  struct device_node *node)
-{
-	struct device_node *flash_np;
-	struct nand_chip *chip = &ndfc->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-
-	chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
-	chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
-	chip->cmd_ctrl = ndfc_hwcontrol;
-	chip->dev_ready = ndfc_ready;
-	chip->select_chip = ndfc_select_chip;
-	chip->chip_delay = 50;
-	chip->controller = &ndfc->ndfc_control;
-	chip->read_buf = ndfc_read_buf;
-	chip->write_buf = ndfc_write_buf;
-	chip->ecc.correct = nand_correct_data;
-	chip->ecc.hwctl = ndfc_enable_hwecc;
-	chip->ecc.calculate = ndfc_calculate_ecc;
-	chip->ecc.mode = NAND_ECC_HW;
-	chip->ecc.size = 256;
-	chip->ecc.bytes = 3;
-	chip->ecc.strength = 1;
-	nand_set_controller_data(chip, ndfc);
-
-	mtd->dev.parent = &ndfc->ofdev->dev;
-
-	flash_np = of_get_next_child(node, NULL);
-	if (!flash_np)
-		return -ENODEV;
-	nand_set_flash_node(chip, flash_np);
-
-	mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
-			      flash_np->name);
-	if (!mtd->name) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	ret = nand_scan(mtd, 1);
-	if (ret)
-		goto err;
-
-	ret = mtd_device_register(mtd, NULL, 0);
-
-err:
-	of_node_put(flash_np);
-	if (ret)
-		kfree(mtd->name);
-	return ret;
-}
-
-static int ndfc_probe(struct platform_device *ofdev)
-{
-	struct ndfc_controller *ndfc;
-	const __be32 *reg;
-	u32 ccr;
-	u32 cs;
-	int err, len;
-
-	/* Read the reg property to get the chip select */
-	reg = of_get_property(ofdev->dev.of_node, "reg", &len);
-	if (reg == NULL || len != 12) {
-		dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
-		return -ENOENT;
-	}
-
-	cs = be32_to_cpu(reg[0]);
-	if (cs >= NDFC_MAX_CS) {
-		dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs);
-		return -EINVAL;
-	}
-
-	ndfc = &ndfc_ctrl[cs];
-	ndfc->chip_select = cs;
-
-	nand_hw_control_init(&ndfc->ndfc_control);
-	ndfc->ofdev = ofdev;
-	dev_set_drvdata(&ofdev->dev, ndfc);
-
-	ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
-	if (!ndfc->ndfcbase) {
-		dev_err(&ofdev->dev, "failed to get memory\n");
-		return -EIO;
-	}
-
-	ccr = NDFC_CCR_BS(ndfc->chip_select);
-
-	/* It is ok if ccr does not exist - just default to 0 */
-	reg = of_get_property(ofdev->dev.of_node, "ccr", NULL);
-	if (reg)
-		ccr |= be32_to_cpup(reg);
-
-	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
-
-	/* Set the bank settings if given */
-	reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL);
-	if (reg) {
-		int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
-		out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg));
-	}
-
-	err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
-	if (err) {
-		iounmap(ndfc->ndfcbase);
-		return err;
-	}
-
-	return 0;
-}
-
-static int ndfc_remove(struct platform_device *ofdev)
-{
-	struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
-	struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
-
-	nand_release(mtd);
-	kfree(mtd->name);
-
-	return 0;
-}
-
-static const struct of_device_id ndfc_match[] = {
-	{ .compatible = "ibm,ndfc", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, ndfc_match);
-
-static struct platform_driver ndfc_driver = {
-	.driver = {
-		.name = "ndfc",
-		.of_match_table = ndfc_match,
-	},
-	.probe = ndfc_probe,
-	.remove = ndfc_remove,
-};
-
-module_platform_driver(ndfc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("OF Platform driver for NDFC");
diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c
deleted file mode 100644
index af5b32c9a791..000000000000
--- a/drivers/mtd/nand/nuc900_nand.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright © 2009 Nuvoton technology corporation.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation;version 2 of the License.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#define REG_FMICSR   	0x00
-#define REG_SMCSR    	0xa0
-#define REG_SMISR    	0xac
-#define REG_SMCMD    	0xb0
-#define REG_SMADDR   	0xb4
-#define REG_SMDATA   	0xb8
-
-#define RESET_FMI	0x01
-#define NAND_EN		0x08
-#define READYBUSY	(0x01 << 18)
-
-#define SWRST		0x01
-#define PSIZE		(0x01 << 3)
-#define DMARWEN		(0x03 << 1)
-#define BUSWID		(0x01 << 4)
-#define ECC4EN		(0x01 << 5)
-#define WP		(0x01 << 24)
-#define NANDCS		(0x01 << 25)
-#define ENDADDR		(0x01 << 31)
-
-#define read_data_reg(dev)		\
-	__raw_readl((dev)->reg + REG_SMDATA)
-
-#define write_data_reg(dev, val)	\
-	__raw_writel((val), (dev)->reg + REG_SMDATA)
-
-#define write_cmd_reg(dev, val)		\
-	__raw_writel((val), (dev)->reg + REG_SMCMD)
-
-#define write_addr_reg(dev, val)	\
-	__raw_writel((val), (dev)->reg + REG_SMADDR)
-
-struct nuc900_nand {
-	struct nand_chip chip;
-	void __iomem *reg;
-	struct clk *clk;
-	spinlock_t lock;
-};
-
-static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
-}
-
-static const struct mtd_partition partitions[] = {
-	{
-	 .name = "NAND FS 0",
-	 .offset = 0,
-	 .size = 8 * 1024 * 1024
-	},
-	{
-	 .name = "NAND FS 1",
-	 .offset = MTDPART_OFS_APPEND,
-	 .size = MTDPART_SIZ_FULL
-	}
-};
-
-static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
-{
-	unsigned char ret;
-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
-
-	ret = (unsigned char)read_data_reg(nand);
-
-	return ret;
-}
-
-static void nuc900_nand_read_buf(struct mtd_info *mtd,
-				 unsigned char *buf, int len)
-{
-	int i;
-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
-
-	for (i = 0; i < len; i++)
-		buf[i] = (unsigned char)read_data_reg(nand);
-}
-
-static void nuc900_nand_write_buf(struct mtd_info *mtd,
-				  const unsigned char *buf, int len)
-{
-	int i;
-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
-
-	for (i = 0; i < len; i++)
-		write_data_reg(nand, buf[i]);
-}
-
-static int nuc900_check_rb(struct nuc900_nand *nand)
-{
-	unsigned int val;
-	spin_lock(&nand->lock);
-	val = __raw_readl(nand->reg + REG_SMISR);
-	val &= READYBUSY;
-	spin_unlock(&nand->lock);
-
-	return val;
-}
-
-static int nuc900_nand_devready(struct mtd_info *mtd)
-{
-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
-	int ready;
-
-	ready = (nuc900_check_rb(nand)) ? 1 : 0;
-	return ready;
-}
-
-static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
-				   int column, int page_addr)
-{
-	register struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
-
-	if (command == NAND_CMD_READOOB) {
-		column += mtd->writesize;
-		command = NAND_CMD_READ0;
-	}
-
-	write_cmd_reg(nand, command & 0xff);
-
-	if (column != -1 || page_addr != -1) {
-
-		if (column != -1) {
-			if (chip->options & NAND_BUSWIDTH_16 &&
-					!nand_opcode_8bits(command))
-				column >>= 1;
-			write_addr_reg(nand, column);
-			write_addr_reg(nand, column >> 8 | ENDADDR);
-		}
-		if (page_addr != -1) {
-			write_addr_reg(nand, page_addr);
-
-			if (chip->options & NAND_ROW_ADDR_3) {
-				write_addr_reg(nand, page_addr >> 8);
-				write_addr_reg(nand, page_addr >> 16 | ENDADDR);
-			} else {
-				write_addr_reg(nand, page_addr >> 8 | ENDADDR);
-			}
-		}
-	}
-
-	switch (command) {
-	case NAND_CMD_CACHEDPROG:
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-	case NAND_CMD_ERASE2:
-	case NAND_CMD_SEQIN:
-	case NAND_CMD_RNDIN:
-	case NAND_CMD_STATUS:
-		return;
-
-	case NAND_CMD_RESET:
-		if (chip->dev_ready)
-			break;
-		udelay(chip->chip_delay);
-
-		write_cmd_reg(nand, NAND_CMD_STATUS);
-		write_cmd_reg(nand, command);
-
-		while (!nuc900_check_rb(nand))
-			;
-
-		return;
-
-	case NAND_CMD_RNDOUT:
-		write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
-		return;
-
-	case NAND_CMD_READ0:
-
-		write_cmd_reg(nand, NAND_CMD_READSTART);
-	default:
-
-		if (!chip->dev_ready) {
-			udelay(chip->chip_delay);
-			return;
-		}
-	}
-
-	/* Apply this short delay always to ensure that we do wait tWB in
-	 * any case on any machine. */
-	ndelay(100);
-
-	while (!chip->dev_ready(mtd))
-		;
-}
-
-
-static void nuc900_nand_enable(struct nuc900_nand *nand)
-{
-	unsigned int val;
-	spin_lock(&nand->lock);
-	__raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
-
-	val = __raw_readl(nand->reg + REG_FMICSR);
-
-	if (!(val & NAND_EN))
-		__raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
-
-	val = __raw_readl(nand->reg + REG_SMCSR);
-
-	val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
-	val |= WP;
-
-	__raw_writel(val, nand->reg + REG_SMCSR);
-
-	spin_unlock(&nand->lock);
-}
-
-static int nuc900_nand_probe(struct platform_device *pdev)
-{
-	struct nuc900_nand *nuc900_nand;
-	struct nand_chip *chip;
-	struct mtd_info *mtd;
-	struct resource *res;
-
-	nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
-				   GFP_KERNEL);
-	if (!nuc900_nand)
-		return -ENOMEM;
-	chip = &(nuc900_nand->chip);
-	mtd = nand_to_mtd(chip);
-
-	mtd->dev.parent		= &pdev->dev;
-	spin_lock_init(&nuc900_nand->lock);
-
-	nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(nuc900_nand->clk))
-		return -ENOENT;
-	clk_enable(nuc900_nand->clk);
-
-	chip->cmdfunc		= nuc900_nand_command_lp;
-	chip->dev_ready		= nuc900_nand_devready;
-	chip->read_byte		= nuc900_nand_read_byte;
-	chip->write_buf		= nuc900_nand_write_buf;
-	chip->read_buf		= nuc900_nand_read_buf;
-	chip->chip_delay	= 50;
-	chip->options		= 0;
-	chip->ecc.mode		= NAND_ECC_SOFT;
-	chip->ecc.algo		= NAND_ECC_HAMMING;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(nuc900_nand->reg))
-		return PTR_ERR(nuc900_nand->reg);
-
-	nuc900_nand_enable(nuc900_nand);
-
-	if (nand_scan(mtd, 1))
-		return -ENXIO;
-
-	mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
-
-	platform_set_drvdata(pdev, nuc900_nand);
-
-	return 0;
-}
-
-static int nuc900_nand_remove(struct platform_device *pdev)
-{
-	struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
-
-	nand_release(nand_to_mtd(&nuc900_nand->chip));
-	clk_disable(nuc900_nand->clk);
-
-	return 0;
-}
-
-static struct platform_driver nuc900_nand_driver = {
-	.probe		= nuc900_nand_probe,
-	.remove		= nuc900_nand_remove,
-	.driver		= {
-		.name	= "nuc900-fmi",
-	},
-};
-
-module_platform_driver(nuc900_nand_driver);
-
-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
-MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nuc900-fmi");
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
deleted file mode 100644
index 8cdf7d3d8fa7..000000000000
--- a/drivers/mtd/nand/omap2.c
+++ /dev/null
@@ -1,2316 +0,0 @@
-/*
- * Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
- * Copyright © 2004 Micron Technology Inc.
- * Copyright © 2004 David Brownell
- *
- * 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/platform_device.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/omap-dma.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include <linux/mtd/nand_bch.h>
-#include <linux/platform_data/elm.h>
-
-#include <linux/omap-gpmc.h>
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#define	DRIVER_NAME	"omap2-nand"
-#define	OMAP_NAND_TIMEOUT_MS	5000
-
-#define NAND_Ecc_P1e		(1 << 0)
-#define NAND_Ecc_P2e		(1 << 1)
-#define NAND_Ecc_P4e		(1 << 2)
-#define NAND_Ecc_P8e		(1 << 3)
-#define NAND_Ecc_P16e		(1 << 4)
-#define NAND_Ecc_P32e		(1 << 5)
-#define NAND_Ecc_P64e		(1 << 6)
-#define NAND_Ecc_P128e		(1 << 7)
-#define NAND_Ecc_P256e		(1 << 8)
-#define NAND_Ecc_P512e		(1 << 9)
-#define NAND_Ecc_P1024e		(1 << 10)
-#define NAND_Ecc_P2048e		(1 << 11)
-
-#define NAND_Ecc_P1o		(1 << 16)
-#define NAND_Ecc_P2o		(1 << 17)
-#define NAND_Ecc_P4o		(1 << 18)
-#define NAND_Ecc_P8o		(1 << 19)
-#define NAND_Ecc_P16o		(1 << 20)
-#define NAND_Ecc_P32o		(1 << 21)
-#define NAND_Ecc_P64o		(1 << 22)
-#define NAND_Ecc_P128o		(1 << 23)
-#define NAND_Ecc_P256o		(1 << 24)
-#define NAND_Ecc_P512o		(1 << 25)
-#define NAND_Ecc_P1024o		(1 << 26)
-#define NAND_Ecc_P2048o		(1 << 27)
-
-#define TF(value)	(value ? 1 : 0)
-
-#define P2048e(a)	(TF(a & NAND_Ecc_P2048e)	<< 0)
-#define P2048o(a)	(TF(a & NAND_Ecc_P2048o)	<< 1)
-#define P1e(a)		(TF(a & NAND_Ecc_P1e)		<< 2)
-#define P1o(a)		(TF(a & NAND_Ecc_P1o)		<< 3)
-#define P2e(a)		(TF(a & NAND_Ecc_P2e)		<< 4)
-#define P2o(a)		(TF(a & NAND_Ecc_P2o)		<< 5)
-#define P4e(a)		(TF(a & NAND_Ecc_P4e)		<< 6)
-#define P4o(a)		(TF(a & NAND_Ecc_P4o)		<< 7)
-
-#define P8e(a)		(TF(a & NAND_Ecc_P8e)		<< 0)
-#define P8o(a)		(TF(a & NAND_Ecc_P8o)		<< 1)
-#define P16e(a)		(TF(a & NAND_Ecc_P16e)		<< 2)
-#define P16o(a)		(TF(a & NAND_Ecc_P16o)		<< 3)
-#define P32e(a)		(TF(a & NAND_Ecc_P32e)		<< 4)
-#define P32o(a)		(TF(a & NAND_Ecc_P32o)		<< 5)
-#define P64e(a)		(TF(a & NAND_Ecc_P64e)		<< 6)
-#define P64o(a)		(TF(a & NAND_Ecc_P64o)		<< 7)
-
-#define P128e(a)	(TF(a & NAND_Ecc_P128e)		<< 0)
-#define P128o(a)	(TF(a & NAND_Ecc_P128o)		<< 1)
-#define P256e(a)	(TF(a & NAND_Ecc_P256e)		<< 2)
-#define P256o(a)	(TF(a & NAND_Ecc_P256o)		<< 3)
-#define P512e(a)	(TF(a & NAND_Ecc_P512e)		<< 4)
-#define P512o(a)	(TF(a & NAND_Ecc_P512o)		<< 5)
-#define P1024e(a)	(TF(a & NAND_Ecc_P1024e)	<< 6)
-#define P1024o(a)	(TF(a & NAND_Ecc_P1024o)	<< 7)
-
-#define P8e_s(a)	(TF(a & NAND_Ecc_P8e)		<< 0)
-#define P8o_s(a)	(TF(a & NAND_Ecc_P8o)		<< 1)
-#define P16e_s(a)	(TF(a & NAND_Ecc_P16e)		<< 2)
-#define P16o_s(a)	(TF(a & NAND_Ecc_P16o)		<< 3)
-#define P1e_s(a)	(TF(a & NAND_Ecc_P1e)		<< 4)
-#define P1o_s(a)	(TF(a & NAND_Ecc_P1o)		<< 5)
-#define P2e_s(a)	(TF(a & NAND_Ecc_P2e)		<< 6)
-#define P2o_s(a)	(TF(a & NAND_Ecc_P2o)		<< 7)
-
-#define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
-#define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
-
-#define	PREFETCH_CONFIG1_CS_SHIFT	24
-#define	ECC_CONFIG_CS_SHIFT		1
-#define	CS_MASK				0x7
-#define	ENABLE_PREFETCH			(0x1 << 7)
-#define	DMA_MPU_MODE_SHIFT		2
-#define	ECCSIZE0_SHIFT			12
-#define	ECCSIZE1_SHIFT			22
-#define	ECC1RESULTSIZE			0x1
-#define	ECCCLEAR			0x100
-#define	ECC1				0x1
-#define	PREFETCH_FIFOTHRESHOLD_MAX	0x40
-#define	PREFETCH_FIFOTHRESHOLD(val)	((val) << 8)
-#define	PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
-#define	PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
-#define	STATUS_BUFF_EMPTY		0x00000001
-
-#define SECTOR_BYTES		512
-/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
-#define BCH4_BIT_PAD		4
-
-/* GPMC ecc engine settings for read */
-#define BCH_WRAPMODE_1		1	/* BCH wrap mode 1 */
-#define BCH8R_ECC_SIZE0		0x1a	/* ecc_size0 = 26 */
-#define BCH8R_ECC_SIZE1		0x2	/* ecc_size1 = 2 */
-#define BCH4R_ECC_SIZE0		0xd	/* ecc_size0 = 13 */
-#define BCH4R_ECC_SIZE1		0x3	/* ecc_size1 = 3 */
-
-/* GPMC ecc engine settings for write */
-#define BCH_WRAPMODE_6		6	/* BCH wrap mode 6 */
-#define BCH_ECC_SIZE0		0x0	/* ecc_size0 = 0, no oob protection */
-#define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
-
-#define BADBLOCK_MARKER_LENGTH		2
-
-static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
-				0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
-				0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93,
-				0x07, 0x0e};
-static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
-	0xac, 0x6b, 0xff, 0x99, 0x7b};
-static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
-
-/* Shared among all NAND instances to synchronize access to the ECC Engine */
-static struct nand_hw_control omap_gpmc_controller = {
-	.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
-	.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
-};
-
-struct omap_nand_info {
-	struct nand_chip		nand;
-	struct platform_device		*pdev;
-
-	int				gpmc_cs;
-	bool				dev_ready;
-	enum nand_io			xfer_type;
-	int				devsize;
-	enum omap_ecc			ecc_opt;
-	struct device_node		*elm_of_node;
-
-	unsigned long			phys_base;
-	struct completion		comp;
-	struct dma_chan			*dma;
-	int				gpmc_irq_fifo;
-	int				gpmc_irq_count;
-	enum {
-		OMAP_NAND_IO_READ = 0,	/* read */
-		OMAP_NAND_IO_WRITE,	/* write */
-	} iomode;
-	u_char				*buf;
-	int					buf_len;
-	/* Interface to GPMC */
-	struct gpmc_nand_regs		reg;
-	struct gpmc_nand_ops		*ops;
-	bool				flash_bbt;
-	/* fields specific for BCHx_HW ECC scheme */
-	struct device			*elm_dev;
-	/* NAND ready gpio */
-	struct gpio_desc		*ready_gpiod;
-};
-
-static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct omap_nand_info, nand);
-}
-
-/**
- * omap_prefetch_enable - configures and starts prefetch transfer
- * @cs: cs (chip select) number
- * @fifo_th: fifo threshold to be used for read/ write
- * @dma_mode: dma mode enable (1) or disable (0)
- * @u32_count: number of bytes to be transferred
- * @is_write: prefetch read(0) or write post(1) mode
- */
-static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
-	unsigned int u32_count, int is_write, struct omap_nand_info *info)
-{
-	u32 val;
-
-	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
-		return -1;
-
-	if (readl(info->reg.gpmc_prefetch_control))
-		return -EBUSY;
-
-	/* Set the amount of bytes to be prefetched */
-	writel(u32_count, info->reg.gpmc_prefetch_config2);
-
-	/* Set dma/mpu mode, the prefetch read / post write and
-	 * enable the engine. Set which cs is has requested for.
-	 */
-	val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
-		PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
-		(dma_mode << DMA_MPU_MODE_SHIFT) | (is_write & 0x1));
-	writel(val, info->reg.gpmc_prefetch_config1);
-
-	/*  Start the prefetch engine */
-	writel(0x1, info->reg.gpmc_prefetch_control);
-
-	return 0;
-}
-
-/**
- * omap_prefetch_reset - disables and stops the prefetch engine
- */
-static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
-{
-	u32 config1;
-
-	/* check if the same module/cs is trying to reset */
-	config1 = readl(info->reg.gpmc_prefetch_config1);
-	if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
-		return -EINVAL;
-
-	/* Stop the PFPW engine */
-	writel(0x0, info->reg.gpmc_prefetch_control);
-
-	/* Reset/disable the PFPW engine */
-	writel(0x0, info->reg.gpmc_prefetch_config1);
-
-	return 0;
-}
-
-/**
- * omap_hwcontrol - hardware specific access to control-lines
- * @mtd: MTD device structure
- * @cmd: command to device
- * @ctrl:
- * NAND_NCE: bit 0 -> don't care
- * NAND_CLE: bit 1 -> Command Latch
- * NAND_ALE: bit 2 -> Address Latch
- *
- * NOTE: boards may use different bits for these!!
- */
-static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-
-	if (cmd != NAND_CMD_NONE) {
-		if (ctrl & NAND_CLE)
-			writeb(cmd, info->reg.gpmc_nand_command);
-
-		else if (ctrl & NAND_ALE)
-			writeb(cmd, info->reg.gpmc_nand_address);
-
-		else /* NAND_NCE */
-			writeb(cmd, info->reg.gpmc_nand_data);
-	}
-}
-
-/**
- * omap_read_buf8 - read data from NAND controller into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- */
-static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-
-	ioread8_rep(nand->IO_ADDR_R, buf, len);
-}
-
-/**
- * omap_write_buf8 - write buffer to NAND controller
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- */
-static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	u_char *p = (u_char *)buf;
-	bool status;
-
-	while (len--) {
-		iowrite8(*p++, info->nand.IO_ADDR_W);
-		/* wait until buffer is available for write */
-		do {
-			status = info->ops->nand_writebuffer_empty();
-		} while (!status);
-	}
-}
-
-/**
- * omap_read_buf16 - read data from NAND controller into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- */
-static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-
-	ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
-}
-
-/**
- * omap_write_buf16 - write buffer to NAND controller
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- */
-static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	u16 *p = (u16 *) buf;
-	bool status;
-	/* FIXME try bursts of writesw() or DMA ... */
-	len >>= 1;
-
-	while (len--) {
-		iowrite16(*p++, info->nand.IO_ADDR_W);
-		/* wait until buffer is available for write */
-		do {
-			status = info->ops->nand_writebuffer_empty();
-		} while (!status);
-	}
-}
-
-/**
- * omap_read_buf_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- */
-static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	uint32_t r_count = 0;
-	int ret = 0;
-	u32 *p = (u32 *)buf;
-
-	/* take care of subpage reads */
-	if (len % 4) {
-		if (info->nand.options & NAND_BUSWIDTH_16)
-			omap_read_buf16(mtd, buf, len % 4);
-		else
-			omap_read_buf8(mtd, buf, len % 4);
-		p = (u32 *) (buf + len % 4);
-		len -= len % 4;
-	}
-
-	/* configure and start prefetch transfer */
-	ret = omap_prefetch_enable(info->gpmc_cs,
-			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
-	if (ret) {
-		/* PFPW engine is busy, use cpu copy method */
-		if (info->nand.options & NAND_BUSWIDTH_16)
-			omap_read_buf16(mtd, (u_char *)p, len);
-		else
-			omap_read_buf8(mtd, (u_char *)p, len);
-	} else {
-		do {
-			r_count = readl(info->reg.gpmc_prefetch_status);
-			r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
-			r_count = r_count >> 2;
-			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
-			p += r_count;
-			len -= r_count << 2;
-		} while (len);
-		/* disable and stop the PFPW engine */
-		omap_prefetch_reset(info->gpmc_cs, info);
-	}
-}
-
-/**
- * omap_write_buf_pref - write buffer to NAND controller
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- */
-static void omap_write_buf_pref(struct mtd_info *mtd,
-					const u_char *buf, int len)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	uint32_t w_count = 0;
-	int i = 0, ret = 0;
-	u16 *p = (u16 *)buf;
-	unsigned long tim, limit;
-	u32 val;
-
-	/* take care of subpage writes */
-	if (len % 2 != 0) {
-		writeb(*buf, info->nand.IO_ADDR_W);
-		p = (u16 *)(buf + 1);
-		len--;
-	}
-
-	/*  configure and start prefetch transfer */
-	ret = omap_prefetch_enable(info->gpmc_cs,
-			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
-	if (ret) {
-		/* PFPW engine is busy, use cpu copy method */
-		if (info->nand.options & NAND_BUSWIDTH_16)
-			omap_write_buf16(mtd, (u_char *)p, len);
-		else
-			omap_write_buf8(mtd, (u_char *)p, len);
-	} else {
-		while (len) {
-			w_count = readl(info->reg.gpmc_prefetch_status);
-			w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
-			w_count = w_count >> 1;
-			for (i = 0; (i < w_count) && len; i++, len -= 2)
-				iowrite16(*p++, info->nand.IO_ADDR_W);
-		}
-		/* wait for data to flushed-out before reset the prefetch */
-		tim = 0;
-		limit = (loops_per_jiffy *
-					msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
-		do {
-			cpu_relax();
-			val = readl(info->reg.gpmc_prefetch_status);
-			val = PREFETCH_STATUS_COUNT(val);
-		} while (val && (tim++ < limit));
-
-		/* disable and stop the PFPW engine */
-		omap_prefetch_reset(info->gpmc_cs, info);
-	}
-}
-
-/*
- * omap_nand_dma_callback: callback on the completion of dma transfer
- * @data: pointer to completion data structure
- */
-static void omap_nand_dma_callback(void *data)
-{
-	complete((struct completion *) data);
-}
-
-/*
- * omap_nand_dma_transfer: configure and start dma transfer
- * @mtd: MTD device structure
- * @addr: virtual address in RAM of source/destination
- * @len: number of data bytes to be transferred
- * @is_write: flag for read/write operation
- */
-static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
-					unsigned int len, int is_write)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	struct dma_async_tx_descriptor *tx;
-	enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
-							DMA_FROM_DEVICE;
-	struct scatterlist sg;
-	unsigned long tim, limit;
-	unsigned n;
-	int ret;
-	u32 val;
-
-	if (!virt_addr_valid(addr))
-		goto out_copy;
-
-	sg_init_one(&sg, addr, len);
-	n = dma_map_sg(info->dma->device->dev, &sg, 1, dir);
-	if (n == 0) {
-		dev_err(&info->pdev->dev,
-			"Couldn't DMA map a %d byte buffer\n", len);
-		goto out_copy;
-	}
-
-	tx = dmaengine_prep_slave_sg(info->dma, &sg, n,
-		is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
-		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!tx)
-		goto out_copy_unmap;
-
-	tx->callback = omap_nand_dma_callback;
-	tx->callback_param = &info->comp;
-	dmaengine_submit(tx);
-
-	init_completion(&info->comp);
-
-	/* setup and start DMA using dma_addr */
-	dma_async_issue_pending(info->dma);
-
-	/*  configure and start prefetch transfer */
-	ret = omap_prefetch_enable(info->gpmc_cs,
-		PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
-	if (ret)
-		/* PFPW engine is busy, use cpu copy method */
-		goto out_copy_unmap;
-
-	wait_for_completion(&info->comp);
-	tim = 0;
-	limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
-
-	do {
-		cpu_relax();
-		val = readl(info->reg.gpmc_prefetch_status);
-		val = PREFETCH_STATUS_COUNT(val);
-	} while (val && (tim++ < limit));
-
-	/* disable and stop the PFPW engine */
-	omap_prefetch_reset(info->gpmc_cs, info);
-
-	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
-	return 0;
-
-out_copy_unmap:
-	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
-out_copy:
-	if (info->nand.options & NAND_BUSWIDTH_16)
-		is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
-			: omap_write_buf16(mtd, (u_char *) addr, len);
-	else
-		is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
-			: omap_write_buf8(mtd, (u_char *) addr, len);
-	return 0;
-}
-
-/**
- * omap_read_buf_dma_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- */
-static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
-{
-	if (len <= mtd->oobsize)
-		omap_read_buf_pref(mtd, buf, len);
-	else
-		/* start transfer in DMA mode */
-		omap_nand_dma_transfer(mtd, buf, len, 0x0);
-}
-
-/**
- * omap_write_buf_dma_pref - write buffer to NAND controller
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- */
-static void omap_write_buf_dma_pref(struct mtd_info *mtd,
-					const u_char *buf, int len)
-{
-	if (len <= mtd->oobsize)
-		omap_write_buf_pref(mtd, buf, len);
-	else
-		/* start transfer in DMA mode */
-		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
-}
-
-/*
- * omap_nand_irq - GPMC irq handler
- * @this_irq: gpmc irq number
- * @dev: omap_nand_info structure pointer is passed here
- */
-static irqreturn_t omap_nand_irq(int this_irq, void *dev)
-{
-	struct omap_nand_info *info = (struct omap_nand_info *) dev;
-	u32 bytes;
-
-	bytes = readl(info->reg.gpmc_prefetch_status);
-	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
-	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
-	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
-		if (this_irq == info->gpmc_irq_count)
-			goto done;
-
-		if (info->buf_len && (info->buf_len < bytes))
-			bytes = info->buf_len;
-		else if (!info->buf_len)
-			bytes = 0;
-		iowrite32_rep(info->nand.IO_ADDR_W,
-						(u32 *)info->buf, bytes >> 2);
-		info->buf = info->buf + bytes;
-		info->buf_len -= bytes;
-
-	} else {
-		ioread32_rep(info->nand.IO_ADDR_R,
-						(u32 *)info->buf, bytes >> 2);
-		info->buf = info->buf + bytes;
-
-		if (this_irq == info->gpmc_irq_count)
-			goto done;
-	}
-
-	return IRQ_HANDLED;
-
-done:
-	complete(&info->comp);
-
-	disable_irq_nosync(info->gpmc_irq_fifo);
-	disable_irq_nosync(info->gpmc_irq_count);
-
-	return IRQ_HANDLED;
-}
-
-/*
- * omap_read_buf_irq_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- */
-static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	int ret = 0;
-
-	if (len <= mtd->oobsize) {
-		omap_read_buf_pref(mtd, buf, len);
-		return;
-	}
-
-	info->iomode = OMAP_NAND_IO_READ;
-	info->buf = buf;
-	init_completion(&info->comp);
-
-	/*  configure and start prefetch transfer */
-	ret = omap_prefetch_enable(info->gpmc_cs,
-			PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
-	if (ret)
-		/* PFPW engine is busy, use cpu copy method */
-		goto out_copy;
-
-	info->buf_len = len;
-
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
-
-	/* waiting for read to complete */
-	wait_for_completion(&info->comp);
-
-	/* disable and stop the PFPW engine */
-	omap_prefetch_reset(info->gpmc_cs, info);
-	return;
-
-out_copy:
-	if (info->nand.options & NAND_BUSWIDTH_16)
-		omap_read_buf16(mtd, buf, len);
-	else
-		omap_read_buf8(mtd, buf, len);
-}
-
-/*
- * omap_write_buf_irq_pref - write buffer to NAND controller
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- */
-static void omap_write_buf_irq_pref(struct mtd_info *mtd,
-					const u_char *buf, int len)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	int ret = 0;
-	unsigned long tim, limit;
-	u32 val;
-
-	if (len <= mtd->oobsize) {
-		omap_write_buf_pref(mtd, buf, len);
-		return;
-	}
-
-	info->iomode = OMAP_NAND_IO_WRITE;
-	info->buf = (u_char *) buf;
-	init_completion(&info->comp);
-
-	/* configure and start prefetch transfer : size=24 */
-	ret = omap_prefetch_enable(info->gpmc_cs,
-		(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
-	if (ret)
-		/* PFPW engine is busy, use cpu copy method */
-		goto out_copy;
-
-	info->buf_len = len;
-
-	enable_irq(info->gpmc_irq_count);
-	enable_irq(info->gpmc_irq_fifo);
-
-	/* waiting for write to complete */
-	wait_for_completion(&info->comp);
-
-	/* wait for data to flushed-out before reset the prefetch */
-	tim = 0;
-	limit = (loops_per_jiffy *  msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
-	do {
-		val = readl(info->reg.gpmc_prefetch_status);
-		val = PREFETCH_STATUS_COUNT(val);
-		cpu_relax();
-	} while (val && (tim++ < limit));
-
-	/* disable and stop the PFPW engine */
-	omap_prefetch_reset(info->gpmc_cs, info);
-	return;
-
-out_copy:
-	if (info->nand.options & NAND_BUSWIDTH_16)
-		omap_write_buf16(mtd, buf, len);
-	else
-		omap_write_buf8(mtd, buf, len);
-}
-
-/**
- * gen_true_ecc - This function will generate true ECC value
- * @ecc_buf: buffer to store ecc code
- *
- * This generated true ECC value can be used when correcting
- * data read from NAND flash memory core
- */
-static void gen_true_ecc(u8 *ecc_buf)
-{
-	u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) |
-		((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
-
-	ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) |
-			P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
-	ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) |
-			P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
-	ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) |
-			P1e(tmp) | P2048o(tmp) | P2048e(tmp));
-}
-
-/**
- * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data
- * @ecc_data1:  ecc code from nand spare area
- * @ecc_data2:  ecc code from hardware register obtained from hardware ecc
- * @page_data:  page data
- *
- * This function compares two ECC's and indicates if there is an error.
- * If the error can be corrected it will be corrected to the buffer.
- * If there is no error, %0 is returned. If there is an error but it
- * was corrected, %1 is returned. Otherwise, %-1 is returned.
- */
-static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
-			    u8 *ecc_data2,	/* read from register */
-			    u8 *page_data)
-{
-	uint	i;
-	u8	tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
-	u8	comp0_bit[8], comp1_bit[8], comp2_bit[8];
-	u8	ecc_bit[24];
-	u8	ecc_sum = 0;
-	u8	find_bit = 0;
-	uint	find_byte = 0;
-	int	isEccFF;
-
-	isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
-
-	gen_true_ecc(ecc_data1);
-	gen_true_ecc(ecc_data2);
-
-	for (i = 0; i <= 2; i++) {
-		*(ecc_data1 + i) = ~(*(ecc_data1 + i));
-		*(ecc_data2 + i) = ~(*(ecc_data2 + i));
-	}
-
-	for (i = 0; i < 8; i++) {
-		tmp0_bit[i]     = *ecc_data1 % 2;
-		*ecc_data1	= *ecc_data1 / 2;
-	}
-
-	for (i = 0; i < 8; i++) {
-		tmp1_bit[i]	 = *(ecc_data1 + 1) % 2;
-		*(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
-	}
-
-	for (i = 0; i < 8; i++) {
-		tmp2_bit[i]	 = *(ecc_data1 + 2) % 2;
-		*(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
-	}
-
-	for (i = 0; i < 8; i++) {
-		comp0_bit[i]     = *ecc_data2 % 2;
-		*ecc_data2       = *ecc_data2 / 2;
-	}
-
-	for (i = 0; i < 8; i++) {
-		comp1_bit[i]     = *(ecc_data2 + 1) % 2;
-		*(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
-	}
-
-	for (i = 0; i < 8; i++) {
-		comp2_bit[i]     = *(ecc_data2 + 2) % 2;
-		*(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
-	}
-
-	for (i = 0; i < 6; i++)
-		ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
-
-	for (i = 0; i < 8; i++)
-		ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
-
-	for (i = 0; i < 8; i++)
-		ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
-
-	ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
-	ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
-
-	for (i = 0; i < 24; i++)
-		ecc_sum += ecc_bit[i];
-
-	switch (ecc_sum) {
-	case 0:
-		/* Not reached because this function is not called if
-		 *  ECC values are equal
-		 */
-		return 0;
-
-	case 1:
-		/* Uncorrectable error */
-		pr_debug("ECC UNCORRECTED_ERROR 1\n");
-		return -EBADMSG;
-
-	case 11:
-		/* UN-Correctable error */
-		pr_debug("ECC UNCORRECTED_ERROR B\n");
-		return -EBADMSG;
-
-	case 12:
-		/* Correctable error */
-		find_byte = (ecc_bit[23] << 8) +
-			    (ecc_bit[21] << 7) +
-			    (ecc_bit[19] << 6) +
-			    (ecc_bit[17] << 5) +
-			    (ecc_bit[15] << 4) +
-			    (ecc_bit[13] << 3) +
-			    (ecc_bit[11] << 2) +
-			    (ecc_bit[9]  << 1) +
-			    ecc_bit[7];
-
-		find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
-
-		pr_debug("Correcting single bit ECC error at offset: "
-				"%d, bit: %d\n", find_byte, find_bit);
-
-		page_data[find_byte] ^= (1 << find_bit);
-
-		return 1;
-	default:
-		if (isEccFF) {
-			if (ecc_data2[0] == 0 &&
-			    ecc_data2[1] == 0 &&
-			    ecc_data2[2] == 0)
-				return 0;
-		}
-		pr_debug("UNCORRECTED_ERROR default\n");
-		return -EBADMSG;
-	}
-}
-
-/**
- * omap_correct_data - Compares the ECC read with HW generated ECC
- * @mtd: MTD device structure
- * @dat: page data
- * @read_ecc: ecc read from nand flash
- * @calc_ecc: ecc read from HW ECC registers
- *
- * Compares the ecc read from nand spare area with ECC registers values
- * and if ECC's mismatched, it will call 'omap_compare_ecc' for error
- * detection and correction. If there are no errors, %0 is returned. If
- * there were errors and all of the errors were corrected, the number of
- * corrected errors is returned. If uncorrectable errors exist, %-1 is
- * returned.
- */
-static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
-				u_char *read_ecc, u_char *calc_ecc)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	int blockCnt = 0, i = 0, ret = 0;
-	int stat = 0;
-
-	/* Ex NAND_ECC_HW12_2048 */
-	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
-			(info->nand.ecc.size  == 2048))
-		blockCnt = 4;
-	else
-		blockCnt = 1;
-
-	for (i = 0; i < blockCnt; i++) {
-		if (memcmp(read_ecc, calc_ecc, 3) != 0) {
-			ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
-			if (ret < 0)
-				return ret;
-			/* keep track of the number of corrected errors */
-			stat += ret;
-		}
-		read_ecc += 3;
-		calc_ecc += 3;
-		dat      += 512;
-	}
-	return stat;
-}
-
-/**
- * omap_calcuate_ecc - Generate non-inverted ECC bytes.
- * @mtd: MTD device structure
- * @dat: The pointer to data on which ecc is computed
- * @ecc_code: The ecc_code buffer
- *
- * Using noninverted ECC can be considered ugly since writing a blank
- * page ie. padding will clear the ECC bytes. This is no problem as long
- * nobody is trying to write data on the seemingly unused page. Reading
- * an erased page will produce an ECC mismatch between generated and read
- * ECC bytes that has to be dealt with separately.
- */
-static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-				u_char *ecc_code)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	u32 val;
-
-	val = readl(info->reg.gpmc_ecc_config);
-	if (((val >> ECC_CONFIG_CS_SHIFT) & CS_MASK) != info->gpmc_cs)
-		return -EINVAL;
-
-	/* read ecc result */
-	val = readl(info->reg.gpmc_ecc1_result);
-	*ecc_code++ = val;          /* P128e, ..., P1e */
-	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
-	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
-	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
-
-	return 0;
-}
-
-/**
- * omap_enable_hwecc - This function enables the hardware ecc functionality
- * @mtd: MTD device structure
- * @mode: Read/Write mode
- */
-static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-	u32 val;
-
-	/* clear ecc and enable bits */
-	val = ECCCLEAR | ECC1;
-	writel(val, info->reg.gpmc_ecc_control);
-
-	/* program ecc and result sizes */
-	val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
-			 ECC1RESULTSIZE);
-	writel(val, info->reg.gpmc_ecc_size_config);
-
-	switch (mode) {
-	case NAND_ECC_READ:
-	case NAND_ECC_WRITE:
-		writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
-		break;
-	case NAND_ECC_READSYN:
-		writel(ECCCLEAR, info->reg.gpmc_ecc_control);
-		break;
-	default:
-		dev_info(&info->pdev->dev,
-			"error: unrecognized Mode[%d]!\n", mode);
-		break;
-	}
-
-	/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
-	val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
-	writel(val, info->reg.gpmc_ecc_config);
-}
-
-/**
- * omap_wait - wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND Chip structure
- *
- * Wait function is called during Program and erase operations and
- * the way it is called from MTD layer, we should wait till the NAND
- * chip is ready after the programming/erase operation has completed.
- *
- * Erase can take up to 400ms and program up to 20ms according to
- * general NAND and SmartMedia specs
- */
-static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	unsigned long timeo = jiffies;
-	int status, state = this->state;
-
-	if (state == FL_ERASING)
-		timeo += msecs_to_jiffies(400);
-	else
-		timeo += msecs_to_jiffies(20);
-
-	writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
-	while (time_before(jiffies, timeo)) {
-		status = readb(info->reg.gpmc_nand_data);
-		if (status & NAND_STATUS_READY)
-			break;
-		cond_resched();
-	}
-
-	status = readb(info->reg.gpmc_nand_data);
-	return status;
-}
-
-/**
- * omap_dev_ready - checks the NAND Ready GPIO line
- * @mtd: MTD device structure
- *
- * Returns true if ready and false if busy.
- */
-static int omap_dev_ready(struct mtd_info *mtd)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-
-	return gpiod_get_value(info->ready_gpiod);
-}
-
-/**
- * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
- * @mtd: MTD device structure
- * @mode: Read/Write mode
- *
- * When using BCH with SW correction (i.e. no ELM), sector size is set
- * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
- * for both reading and writing with:
- * eccsize0 = 0  (no additional protected byte in spare area)
- * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
- */
-static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
-{
-	unsigned int bch_type;
-	unsigned int dev_width, nsectors;
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	enum omap_ecc ecc_opt = info->ecc_opt;
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	u32 val, wr_mode;
-	unsigned int ecc_size1, ecc_size0;
-
-	/* GPMC configurations for calculating ECC */
-	switch (ecc_opt) {
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-		bch_type = 0;
-		nsectors = 1;
-		wr_mode	  = BCH_WRAPMODE_6;
-		ecc_size0 = BCH_ECC_SIZE0;
-		ecc_size1 = BCH_ECC_SIZE1;
-		break;
-	case OMAP_ECC_BCH4_CODE_HW:
-		bch_type = 0;
-		nsectors = chip->ecc.steps;
-		if (mode == NAND_ECC_READ) {
-			wr_mode	  = BCH_WRAPMODE_1;
-			ecc_size0 = BCH4R_ECC_SIZE0;
-			ecc_size1 = BCH4R_ECC_SIZE1;
-		} else {
-			wr_mode   = BCH_WRAPMODE_6;
-			ecc_size0 = BCH_ECC_SIZE0;
-			ecc_size1 = BCH_ECC_SIZE1;
-		}
-		break;
-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
-		bch_type = 1;
-		nsectors = 1;
-		wr_mode	  = BCH_WRAPMODE_6;
-		ecc_size0 = BCH_ECC_SIZE0;
-		ecc_size1 = BCH_ECC_SIZE1;
-		break;
-	case OMAP_ECC_BCH8_CODE_HW:
-		bch_type = 1;
-		nsectors = chip->ecc.steps;
-		if (mode == NAND_ECC_READ) {
-			wr_mode	  = BCH_WRAPMODE_1;
-			ecc_size0 = BCH8R_ECC_SIZE0;
-			ecc_size1 = BCH8R_ECC_SIZE1;
-		} else {
-			wr_mode   = BCH_WRAPMODE_6;
-			ecc_size0 = BCH_ECC_SIZE0;
-			ecc_size1 = BCH_ECC_SIZE1;
-		}
-		break;
-	case OMAP_ECC_BCH16_CODE_HW:
-		bch_type = 0x2;
-		nsectors = chip->ecc.steps;
-		if (mode == NAND_ECC_READ) {
-			wr_mode	  = 0x01;
-			ecc_size0 = 52; /* ECC bits in nibbles per sector */
-			ecc_size1 = 0;  /* non-ECC bits in nibbles per sector */
-		} else {
-			wr_mode	  = 0x01;
-			ecc_size0 = 0;  /* extra bits in nibbles per sector */
-			ecc_size1 = 52; /* OOB bits in nibbles per sector */
-		}
-		break;
-	default:
-		return;
-	}
-
-	writel(ECC1, info->reg.gpmc_ecc_control);
-
-	/* Configure ecc size for BCH */
-	val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT);
-	writel(val, info->reg.gpmc_ecc_size_config);
-
-	dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-
-	/* BCH configuration */
-	val = ((1                        << 16) | /* enable BCH */
-	       (bch_type		 << 12) | /* BCH4/BCH8/BCH16 */
-	       (wr_mode                  <<  8) | /* wrap mode */
-	       (dev_width                <<  7) | /* bus width */
-	       (((nsectors-1) & 0x7)     <<  4) | /* number of sectors */
-	       (info->gpmc_cs            <<  1) | /* ECC CS */
-	       (0x1));                            /* enable ECC */
-
-	writel(val, info->reg.gpmc_ecc_config);
-
-	/* Clear ecc and enable bits */
-	writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
-}
-
-static u8  bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f};
-static u8  bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
-				0x97, 0x79, 0xe5, 0x24, 0xb5};
-
-/**
- * _omap_calculate_ecc_bch - Generate ECC bytes for one sector
- * @mtd:	MTD device structure
- * @dat:	The pointer to data on which ecc is computed
- * @ecc_code:	The ecc_code buffer
- * @i:		The sector number (for a multi sector page)
- *
- * Support calculating of BCH4/8/16 ECC vectors for one sector
- * within a page. Sector number is in @i.
- */
-static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
-				   const u_char *dat, u_char *ecc_calc, int i)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	int eccbytes	= info->nand.ecc.bytes;
-	struct gpmc_nand_regs	*gpmc_regs = &info->reg;
-	u8 *ecc_code;
-	unsigned long bch_val1, bch_val2, bch_val3, bch_val4;
-	u32 val;
-	int j;
-
-	ecc_code = ecc_calc;
-	switch (info->ecc_opt) {
-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
-	case OMAP_ECC_BCH8_CODE_HW:
-		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
-		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
-		bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]);
-		bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]);
-		*ecc_code++ = (bch_val4 & 0xFF);
-		*ecc_code++ = ((bch_val3 >> 24) & 0xFF);
-		*ecc_code++ = ((bch_val3 >> 16) & 0xFF);
-		*ecc_code++ = ((bch_val3 >> 8) & 0xFF);
-		*ecc_code++ = (bch_val3 & 0xFF);
-		*ecc_code++ = ((bch_val2 >> 24) & 0xFF);
-		*ecc_code++ = ((bch_val2 >> 16) & 0xFF);
-		*ecc_code++ = ((bch_val2 >> 8) & 0xFF);
-		*ecc_code++ = (bch_val2 & 0xFF);
-		*ecc_code++ = ((bch_val1 >> 24) & 0xFF);
-		*ecc_code++ = ((bch_val1 >> 16) & 0xFF);
-		*ecc_code++ = ((bch_val1 >> 8) & 0xFF);
-		*ecc_code++ = (bch_val1 & 0xFF);
-		break;
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-	case OMAP_ECC_BCH4_CODE_HW:
-		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
-		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
-		*ecc_code++ = ((bch_val2 >> 12) & 0xFF);
-		*ecc_code++ = ((bch_val2 >> 4) & 0xFF);
-		*ecc_code++ = ((bch_val2 & 0xF) << 4) |
-			((bch_val1 >> 28) & 0xF);
-		*ecc_code++ = ((bch_val1 >> 20) & 0xFF);
-		*ecc_code++ = ((bch_val1 >> 12) & 0xFF);
-		*ecc_code++ = ((bch_val1 >> 4) & 0xFF);
-		*ecc_code++ = ((bch_val1 & 0xF) << 4);
-		break;
-	case OMAP_ECC_BCH16_CODE_HW:
-		val = readl(gpmc_regs->gpmc_bch_result6[i]);
-		ecc_code[0]  = ((val >>  8) & 0xFF);
-		ecc_code[1]  = ((val >>  0) & 0xFF);
-		val = readl(gpmc_regs->gpmc_bch_result5[i]);
-		ecc_code[2]  = ((val >> 24) & 0xFF);
-		ecc_code[3]  = ((val >> 16) & 0xFF);
-		ecc_code[4]  = ((val >>  8) & 0xFF);
-		ecc_code[5]  = ((val >>  0) & 0xFF);
-		val = readl(gpmc_regs->gpmc_bch_result4[i]);
-		ecc_code[6]  = ((val >> 24) & 0xFF);
-		ecc_code[7]  = ((val >> 16) & 0xFF);
-		ecc_code[8]  = ((val >>  8) & 0xFF);
-		ecc_code[9]  = ((val >>  0) & 0xFF);
-		val = readl(gpmc_regs->gpmc_bch_result3[i]);
-		ecc_code[10] = ((val >> 24) & 0xFF);
-		ecc_code[11] = ((val >> 16) & 0xFF);
-		ecc_code[12] = ((val >>  8) & 0xFF);
-		ecc_code[13] = ((val >>  0) & 0xFF);
-		val = readl(gpmc_regs->gpmc_bch_result2[i]);
-		ecc_code[14] = ((val >> 24) & 0xFF);
-		ecc_code[15] = ((val >> 16) & 0xFF);
-		ecc_code[16] = ((val >>  8) & 0xFF);
-		ecc_code[17] = ((val >>  0) & 0xFF);
-		val = readl(gpmc_regs->gpmc_bch_result1[i]);
-		ecc_code[18] = ((val >> 24) & 0xFF);
-		ecc_code[19] = ((val >> 16) & 0xFF);
-		ecc_code[20] = ((val >>  8) & 0xFF);
-		ecc_code[21] = ((val >>  0) & 0xFF);
-		val = readl(gpmc_regs->gpmc_bch_result0[i]);
-		ecc_code[22] = ((val >> 24) & 0xFF);
-		ecc_code[23] = ((val >> 16) & 0xFF);
-		ecc_code[24] = ((val >>  8) & 0xFF);
-		ecc_code[25] = ((val >>  0) & 0xFF);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* ECC scheme specific syndrome customizations */
-	switch (info->ecc_opt) {
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-		/* Add constant polynomial to remainder, so that
-		 * ECC of blank pages results in 0x0 on reading back
-		 */
-		for (j = 0; j < eccbytes; j++)
-			ecc_calc[j] ^= bch4_polynomial[j];
-		break;
-	case OMAP_ECC_BCH4_CODE_HW:
-		/* Set  8th ECC byte as 0x0 for ROM compatibility */
-		ecc_calc[eccbytes - 1] = 0x0;
-		break;
-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
-		/* Add constant polynomial to remainder, so that
-		 * ECC of blank pages results in 0x0 on reading back
-		 */
-		for (j = 0; j < eccbytes; j++)
-			ecc_calc[j] ^= bch8_polynomial[j];
-		break;
-	case OMAP_ECC_BCH8_CODE_HW:
-		/* Set 14th ECC byte as 0x0 for ROM compatibility */
-		ecc_calc[eccbytes - 1] = 0x0;
-		break;
-	case OMAP_ECC_BCH16_CODE_HW:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/**
- * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
- * @mtd:	MTD device structure
- * @dat:	The pointer to data on which ecc is computed
- * @ecc_code:	The ecc_code buffer
- *
- * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
- * when SW based correction is required as ECC is required for one sector
- * at a time.
- */
-static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
-				     const u_char *dat, u_char *ecc_calc)
-{
-	return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
-}
-
-/**
- * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
- * @mtd:	MTD device structure
- * @dat:	The pointer to data on which ecc is computed
- * @ecc_code:	The ecc_code buffer
- *
- * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
- */
-static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
-					const u_char *dat, u_char *ecc_calc)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	int eccbytes = info->nand.ecc.bytes;
-	unsigned long nsectors;
-	int i, ret;
-
-	nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
-	for (i = 0; i < nsectors; i++) {
-		ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
-		if (ret)
-			return ret;
-
-		ecc_calc += eccbytes;
-	}
-
-	return 0;
-}
-
-/**
- * erased_sector_bitflips - count bit flips
- * @data:	data sector buffer
- * @oob:	oob buffer
- * @info:	omap_nand_info
- *
- * Check the bit flips in erased page falls below correctable level.
- * If falls below, report the page as erased with correctable bit
- * flip, else report as uncorrectable page.
- */
-static int erased_sector_bitflips(u_char *data, u_char *oob,
-		struct omap_nand_info *info)
-{
-	int flip_bits = 0, i;
-
-	for (i = 0; i < info->nand.ecc.size; i++) {
-		flip_bits += hweight8(~data[i]);
-		if (flip_bits > info->nand.ecc.strength)
-			return 0;
-	}
-
-	for (i = 0; i < info->nand.ecc.bytes - 1; i++) {
-		flip_bits += hweight8(~oob[i]);
-		if (flip_bits > info->nand.ecc.strength)
-			return 0;
-	}
-
-	/*
-	 * Bit flips falls in correctable level.
-	 * Fill data area with 0xFF
-	 */
-	if (flip_bits) {
-		memset(data, 0xFF, info->nand.ecc.size);
-		memset(oob, 0xFF, info->nand.ecc.bytes);
-	}
-
-	return flip_bits;
-}
-
-/**
- * omap_elm_correct_data - corrects page data area in case error reported
- * @mtd:	MTD device structure
- * @data:	page data
- * @read_ecc:	ecc read from nand flash
- * @calc_ecc:	ecc read from HW ECC registers
- *
- * Calculated ecc vector reported as zero in case of non-error pages.
- * In case of non-zero ecc vector, first filter out erased-pages, and
- * then process data via ELM to detect bit-flips.
- */
-static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
-				u_char *read_ecc, u_char *calc_ecc)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	struct nand_ecc_ctrl *ecc = &info->nand.ecc;
-	int eccsteps = info->nand.ecc.steps;
-	int i , j, stat = 0;
-	int eccflag, actual_eccbytes;
-	struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
-	u_char *ecc_vec = calc_ecc;
-	u_char *spare_ecc = read_ecc;
-	u_char *erased_ecc_vec;
-	u_char *buf;
-	int bitflip_count;
-	bool is_error_reported = false;
-	u32 bit_pos, byte_pos, error_max, pos;
-	int err;
-
-	switch (info->ecc_opt) {
-	case OMAP_ECC_BCH4_CODE_HW:
-		/* omit  7th ECC byte reserved for ROM code compatibility */
-		actual_eccbytes = ecc->bytes - 1;
-		erased_ecc_vec = bch4_vector;
-		break;
-	case OMAP_ECC_BCH8_CODE_HW:
-		/* omit 14th ECC byte reserved for ROM code compatibility */
-		actual_eccbytes = ecc->bytes - 1;
-		erased_ecc_vec = bch8_vector;
-		break;
-	case OMAP_ECC_BCH16_CODE_HW:
-		actual_eccbytes = ecc->bytes;
-		erased_ecc_vec = bch16_vector;
-		break;
-	default:
-		dev_err(&info->pdev->dev, "invalid driver configuration\n");
-		return -EINVAL;
-	}
-
-	/* Initialize elm error vector to zero */
-	memset(err_vec, 0, sizeof(err_vec));
-
-	for (i = 0; i < eccsteps ; i++) {
-		eccflag = 0;	/* initialize eccflag */
-
-		/*
-		 * Check any error reported,
-		 * In case of error, non zero ecc reported.
-		 */
-		for (j = 0; j < actual_eccbytes; j++) {
-			if (calc_ecc[j] != 0) {
-				eccflag = 1; /* non zero ecc, error present */
-				break;
-			}
-		}
-
-		if (eccflag == 1) {
-			if (memcmp(calc_ecc, erased_ecc_vec,
-						actual_eccbytes) == 0) {
-				/*
-				 * calc_ecc[] matches pattern for ECC(all 0xff)
-				 * so this is definitely an erased-page
-				 */
-			} else {
-				buf = &data[info->nand.ecc.size * i];
-				/*
-				 * count number of 0-bits in read_buf.
-				 * This check can be removed once a similar
-				 * check is introduced in generic NAND driver
-				 */
-				bitflip_count = erased_sector_bitflips(
-						buf, read_ecc, info);
-				if (bitflip_count) {
-					/*
-					 * number of 0-bits within ECC limits
-					 * So this may be an erased-page
-					 */
-					stat += bitflip_count;
-				} else {
-					/*
-					 * Too many 0-bits. It may be a
-					 * - programmed-page, OR
-					 * - erased-page with many bit-flips
-					 * So this page requires check by ELM
-					 */
-					err_vec[i].error_reported = true;
-					is_error_reported = true;
-				}
-			}
-		}
-
-		/* Update the ecc vector */
-		calc_ecc += ecc->bytes;
-		read_ecc += ecc->bytes;
-	}
-
-	/* Check if any error reported */
-	if (!is_error_reported)
-		return stat;
-
-	/* Decode BCH error using ELM module */
-	elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec);
-
-	err = 0;
-	for (i = 0; i < eccsteps; i++) {
-		if (err_vec[i].error_uncorrectable) {
-			dev_err(&info->pdev->dev,
-				"uncorrectable bit-flips found\n");
-			err = -EBADMSG;
-		} else if (err_vec[i].error_reported) {
-			for (j = 0; j < err_vec[i].error_count; j++) {
-				switch (info->ecc_opt) {
-				case OMAP_ECC_BCH4_CODE_HW:
-					/* Add 4 bits to take care of padding */
-					pos = err_vec[i].error_loc[j] +
-						BCH4_BIT_PAD;
-					break;
-				case OMAP_ECC_BCH8_CODE_HW:
-				case OMAP_ECC_BCH16_CODE_HW:
-					pos = err_vec[i].error_loc[j];
-					break;
-				default:
-					return -EINVAL;
-				}
-				error_max = (ecc->size + actual_eccbytes) * 8;
-				/* Calculate bit position of error */
-				bit_pos = pos % 8;
-
-				/* Calculate byte position of error */
-				byte_pos = (error_max - pos - 1) / 8;
-
-				if (pos < error_max) {
-					if (byte_pos < 512) {
-						pr_debug("bitflip@dat[%d]=%x\n",
-						     byte_pos, data[byte_pos]);
-						data[byte_pos] ^= 1 << bit_pos;
-					} else {
-						pr_debug("bitflip@oob[%d]=%x\n",
-							(byte_pos - 512),
-						     spare_ecc[byte_pos - 512]);
-						spare_ecc[byte_pos - 512] ^=
-							1 << bit_pos;
-					}
-				} else {
-					dev_err(&info->pdev->dev,
-						"invalid bit-flip @ %d:%d\n",
-						byte_pos, bit_pos);
-					err = -EBADMSG;
-				}
-			}
-		}
-
-		/* Update number of correctable errors */
-		stat += err_vec[i].error_count;
-
-		/* Update page data with sector size */
-		data += ecc->size;
-		spare_ecc += ecc->bytes;
-	}
-
-	return (err) ? err : stat;
-}
-
-/**
- * omap_write_page_bch - BCH ecc based write page function for entire page
- * @mtd:		mtd info structure
- * @chip:		nand chip info structure
- * @buf:		data buffer
- * @oob_required:	must write chip->oob_poi to OOB
- * @page:		page
- *
- * Custom write page method evolved to support multi sector writing in one shot
- */
-static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
-			       const uint8_t *buf, int oob_required, int page)
-{
-	int ret;
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	/* Enable GPMC ecc engine */
-	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-
-	/* Write data */
-	chip->write_buf(mtd, buf, mtd->writesize);
-
-	/* Update ecc vector from GPMC result registers */
-	omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
-
-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	/* Write ecc vector to OOB area */
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-/**
- * omap_write_subpage_bch - BCH hardware ECC based subpage write
- * @mtd:	mtd info structure
- * @chip:	nand chip info structure
- * @offset:	column address of subpage within the page
- * @data_len:	data length
- * @buf:	data buffer
- * @oob_required: must write chip->oob_poi to OOB
- * @page: page number to write
- *
- * OMAP optimized subpage write method.
- */
-static int omap_write_subpage_bch(struct mtd_info *mtd,
-				  struct nand_chip *chip, u32 offset,
-				  u32 data_len, const u8 *buf,
-				  int oob_required, int page)
-{
-	u8 *ecc_calc = chip->ecc.calc_buf;
-	int ecc_size      = chip->ecc.size;
-	int ecc_bytes     = chip->ecc.bytes;
-	int ecc_steps     = chip->ecc.steps;
-	u32 start_step = offset / ecc_size;
-	u32 end_step   = (offset + data_len - 1) / ecc_size;
-	int step, ret = 0;
-
-	/*
-	 * Write entire page at one go as it would be optimal
-	 * as ECC is calculated by hardware.
-	 * ECC is calculated for all subpages but we choose
-	 * only what we want.
-	 */
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	/* Enable GPMC ECC engine */
-	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-
-	/* Write data */
-	chip->write_buf(mtd, buf, mtd->writesize);
-
-	for (step = 0; step < ecc_steps; step++) {
-		/* mask ECC of un-touched subpages by padding 0xFF */
-		if (step < start_step || step > end_step)
-			memset(ecc_calc, 0xff, ecc_bytes);
-		else
-			ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step);
-
-		if (ret)
-			return ret;
-
-		buf += ecc_size;
-		ecc_calc += ecc_bytes;
-	}
-
-	/* copy calculated ECC for whole page to chip->buffer->oob */
-	/* this include masked-value(0xFF) for unwritten subpages */
-	ecc_calc = chip->ecc.calc_buf;
-	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	/* write OOB buffer to NAND device */
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-/**
- * omap_read_page_bch - BCH ecc based page read function for entire page
- * @mtd:		mtd info structure
- * @chip:		nand chip info structure
- * @buf:		buffer to store read data
- * @oob_required:	caller requires OOB data read to chip->oob_poi
- * @page:		page number to read
- *
- * For BCH ecc scheme, GPMC used for syndrome calculation and ELM module
- * used for error correction.
- * Custom method evolved to support ELM error correction & multi sector
- * reading. On reading page data area is read along with OOB data with
- * ecc engine enabled. ecc vector updated after read of OOB data.
- * For non error pages ecc vector reported as zero.
- */
-static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	uint8_t *ecc_calc = chip->ecc.calc_buf;
-	uint8_t *ecc_code = chip->ecc.code_buf;
-	int stat, ret;
-	unsigned int max_bitflips = 0;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	/* Enable GPMC ecc engine */
-	chip->ecc.hwctl(mtd, NAND_ECC_READ);
-
-	/* Read data */
-	chip->read_buf(mtd, buf, mtd->writesize);
-
-	/* Read oob bytes */
-	nand_change_read_column_op(chip,
-				   mtd->writesize + BADBLOCK_MARKER_LENGTH,
-				   chip->oob_poi + BADBLOCK_MARKER_LENGTH,
-				   chip->ecc.total, false);
-
-	/* Calculate ecc bytes */
-	omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
-
-	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
-					 chip->ecc.total);
-	if (ret)
-		return ret;
-
-	stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
-
-	if (stat < 0) {
-		mtd->ecc_stats.failed++;
-	} else {
-		mtd->ecc_stats.corrected += stat;
-		max_bitflips = max_t(unsigned int, max_bitflips, stat);
-	}
-
-	return max_bitflips;
-}
-
-/**
- * is_elm_present - checks for presence of ELM module by scanning DT nodes
- * @omap_nand_info: NAND device structure containing platform data
- */
-static bool is_elm_present(struct omap_nand_info *info,
-			   struct device_node *elm_node)
-{
-	struct platform_device *pdev;
-
-	/* check whether elm-id is passed via DT */
-	if (!elm_node) {
-		dev_err(&info->pdev->dev, "ELM devicetree node not found\n");
-		return false;
-	}
-	pdev = of_find_device_by_node(elm_node);
-	/* check whether ELM device is registered */
-	if (!pdev) {
-		dev_err(&info->pdev->dev, "ELM device not found\n");
-		return false;
-	}
-	/* ELM module available, now configure it */
-	info->elm_dev = &pdev->dev;
-	return true;
-}
-
-static bool omap2_nand_ecc_check(struct omap_nand_info *info)
-{
-	bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm;
-
-	switch (info->ecc_opt) {
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
-		ecc_needs_omap_bch = false;
-		ecc_needs_bch = true;
-		ecc_needs_elm = false;
-		break;
-	case OMAP_ECC_BCH4_CODE_HW:
-	case OMAP_ECC_BCH8_CODE_HW:
-	case OMAP_ECC_BCH16_CODE_HW:
-		ecc_needs_omap_bch = true;
-		ecc_needs_bch = false;
-		ecc_needs_elm = true;
-		break;
-	default:
-		ecc_needs_omap_bch = false;
-		ecc_needs_bch = false;
-		ecc_needs_elm = false;
-		break;
-	}
-
-	if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
-		dev_err(&info->pdev->dev,
-			"CONFIG_MTD_NAND_ECC_BCH not enabled\n");
-		return false;
-	}
-	if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
-		dev_err(&info->pdev->dev,
-			"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
-		return false;
-	}
-	if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
-		dev_err(&info->pdev->dev, "ELM not available\n");
-		return false;
-	}
-
-	return true;
-}
-
-static const char * const nand_xfer_types[] = {
-	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
-	[NAND_OMAP_POLLED] = "polled",
-	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
-	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
-};
-
-static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
-{
-	struct device_node *child = dev->of_node;
-	int i;
-	const char *s;
-	u32 cs;
-
-	if (of_property_read_u32(child, "reg", &cs) < 0) {
-		dev_err(dev, "reg not found in DT\n");
-		return -EINVAL;
-	}
-
-	info->gpmc_cs = cs;
-
-	/* detect availability of ELM module. Won't be present pre-OMAP4 */
-	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
-	if (!info->elm_of_node) {
-		info->elm_of_node = of_parse_phandle(child, "elm_id", 0);
-		if (!info->elm_of_node)
-			dev_dbg(dev, "ti,elm-id not in DT\n");
-	}
-
-	/* select ecc-scheme for NAND */
-	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
-		dev_err(dev, "ti,nand-ecc-opt not found\n");
-		return -EINVAL;
-	}
-
-	if (!strcmp(s, "sw")) {
-		info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
-	} else if (!strcmp(s, "ham1") ||
-		   !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
-		info->ecc_opt =	OMAP_ECC_HAM1_CODE_HW;
-	} else if (!strcmp(s, "bch4")) {
-		if (info->elm_of_node)
-			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
-		else
-			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
-	} else if (!strcmp(s, "bch8")) {
-		if (info->elm_of_node)
-			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
-		else
-			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
-	} else if (!strcmp(s, "bch16")) {
-		info->ecc_opt =	OMAP_ECC_BCH16_CODE_HW;
-	} else {
-		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
-		return -EINVAL;
-	}
-
-	/* select data transfer mode */
-	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
-		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
-			if (!strcasecmp(s, nand_xfer_types[i])) {
-				info->xfer_type = i;
-				return 0;
-			}
-		}
-
-		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
-			      struct mtd_oob_region *oobregion)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	struct nand_chip *chip = &info->nand;
-	int off = BADBLOCK_MARKER_LENGTH;
-
-	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
-	    !(chip->options & NAND_BUSWIDTH_16))
-		off = 1;
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = off;
-	oobregion->length = chip->ecc.total;
-
-	return 0;
-}
-
-static int omap_ooblayout_free(struct mtd_info *mtd, int section,
-			       struct mtd_oob_region *oobregion)
-{
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	struct nand_chip *chip = &info->nand;
-	int off = BADBLOCK_MARKER_LENGTH;
-
-	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
-	    !(chip->options & NAND_BUSWIDTH_16))
-		off = 1;
-
-	if (section)
-		return -ERANGE;
-
-	off += chip->ecc.total;
-	if (off >= mtd->oobsize)
-		return -ERANGE;
-
-	oobregion->offset = off;
-	oobregion->length = mtd->oobsize - off;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
-	.ecc = omap_ooblayout_ecc,
-	.free = omap_ooblayout_free,
-};
-
-static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int off = BADBLOCK_MARKER_LENGTH;
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	/*
-	 * When SW correction is employed, one OMAP specific marker byte is
-	 * reserved after each ECC step.
-	 */
-	oobregion->offset = off + (section * (chip->ecc.bytes + 1));
-	oobregion->length = chip->ecc.bytes;
-
-	return 0;
-}
-
-static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int off = BADBLOCK_MARKER_LENGTH;
-
-	if (section)
-		return -ERANGE;
-
-	/*
-	 * When SW correction is employed, one OMAP specific marker byte is
-	 * reserved after each ECC step.
-	 */
-	off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
-	if (off >= mtd->oobsize)
-		return -ERANGE;
-
-	oobregion->offset = off;
-	oobregion->length = mtd->oobsize - off;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
-	.ecc = omap_sw_ooblayout_ecc,
-	.free = omap_sw_ooblayout_free,
-};
-
-static int omap_nand_probe(struct platform_device *pdev)
-{
-	struct omap_nand_info		*info;
-	struct mtd_info			*mtd;
-	struct nand_chip		*nand_chip;
-	int				err;
-	dma_cap_mask_t			mask;
-	struct resource			*res;
-	struct device			*dev = &pdev->dev;
-	int				min_oobbytes = BADBLOCK_MARKER_LENGTH;
-	int				oobbytes_per_step;
-
-	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
-				GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	info->pdev = pdev;
-
-	err = omap_get_dt_info(dev, info);
-	if (err)
-		return err;
-
-	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
-	if (!info->ops) {
-		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
-		return -ENODEV;
-	}
-
-	nand_chip		= &info->nand;
-	mtd			= nand_to_mtd(nand_chip);
-	mtd->dev.parent		= &pdev->dev;
-	nand_chip->ecc.priv	= NULL;
-	nand_set_flash_node(nand_chip, dev->of_node);
-
-	if (!mtd->name) {
-		mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
-					   "omap2-nand.%d", info->gpmc_cs);
-		if (!mtd->name) {
-			dev_err(&pdev->dev, "Failed to set MTD name\n");
-			return -ENOMEM;
-		}
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(nand_chip->IO_ADDR_R))
-		return PTR_ERR(nand_chip->IO_ADDR_R);
-
-	info->phys_base = res->start;
-
-	nand_chip->controller = &omap_gpmc_controller;
-
-	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
-	nand_chip->cmd_ctrl  = omap_hwcontrol;
-
-	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
-						    GPIOD_IN);
-	if (IS_ERR(info->ready_gpiod)) {
-		dev_err(dev, "failed to get ready gpio\n");
-		return PTR_ERR(info->ready_gpiod);
-	}
-
-	/*
-	 * If RDY/BSY line is connected to OMAP then use the omap ready
-	 * function and the generic nand_wait function which reads the status
-	 * register after monitoring the RDY/BSY line. Otherwise use a standard
-	 * chip delay which is slightly more than tR (AC Timing) of the NAND
-	 * device and read status register until you get a failure or success
-	 */
-	if (info->ready_gpiod) {
-		nand_chip->dev_ready = omap_dev_ready;
-		nand_chip->chip_delay = 0;
-	} else {
-		nand_chip->waitfunc = omap_wait;
-		nand_chip->chip_delay = 50;
-	}
-
-	if (info->flash_bbt)
-		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-	/* scan NAND device connected to chip controller */
-	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
-	err = nand_scan_ident(mtd, 1, NULL);
-	if (err) {
-		dev_err(&info->pdev->dev,
-			"scan failed, may be bus-width mismatch\n");
-		goto return_error;
-	}
-
-	if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
-		nand_chip->bbt_options |= NAND_BBT_NO_OOB;
-	else
-		nand_chip->options |= NAND_SKIP_BBTSCAN;
-
-	/* re-populate low-level callbacks based on xfer modes */
-	switch (info->xfer_type) {
-	case NAND_OMAP_PREFETCH_POLLED:
-		nand_chip->read_buf   = omap_read_buf_pref;
-		nand_chip->write_buf  = omap_write_buf_pref;
-		break;
-
-	case NAND_OMAP_POLLED:
-		/* Use nand_base defaults for {read,write}_buf */
-		break;
-
-	case NAND_OMAP_PREFETCH_DMA:
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_SLAVE, mask);
-		info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
-
-		if (IS_ERR(info->dma)) {
-			dev_err(&pdev->dev, "DMA engine request failed\n");
-			err = PTR_ERR(info->dma);
-			goto return_error;
-		} else {
-			struct dma_slave_config cfg;
-
-			memset(&cfg, 0, sizeof(cfg));
-			cfg.src_addr = info->phys_base;
-			cfg.dst_addr = info->phys_base;
-			cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-			cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-			cfg.src_maxburst = 16;
-			cfg.dst_maxburst = 16;
-			err = dmaengine_slave_config(info->dma, &cfg);
-			if (err) {
-				dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
-					err);
-				goto return_error;
-			}
-			nand_chip->read_buf   = omap_read_buf_dma_pref;
-			nand_chip->write_buf  = omap_write_buf_dma_pref;
-		}
-		break;
-
-	case NAND_OMAP_PREFETCH_IRQ:
-		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
-		if (info->gpmc_irq_fifo <= 0) {
-			dev_err(&pdev->dev, "error getting fifo irq\n");
-			err = -ENODEV;
-			goto return_error;
-		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-fifo", info);
-		if (err) {
-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_fifo, err);
-			info->gpmc_irq_fifo = 0;
-			goto return_error;
-		}
-
-		info->gpmc_irq_count = platform_get_irq(pdev, 1);
-		if (info->gpmc_irq_count <= 0) {
-			dev_err(&pdev->dev, "error getting count irq\n");
-			err = -ENODEV;
-			goto return_error;
-		}
-		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
-					omap_nand_irq, IRQF_SHARED,
-					"gpmc-nand-count", info);
-		if (err) {
-			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
-						info->gpmc_irq_count, err);
-			info->gpmc_irq_count = 0;
-			goto return_error;
-		}
-
-		nand_chip->read_buf  = omap_read_buf_irq_pref;
-		nand_chip->write_buf = omap_write_buf_irq_pref;
-
-		break;
-
-	default:
-		dev_err(&pdev->dev,
-			"xfer_type(%d) not supported!\n", info->xfer_type);
-		err = -EINVAL;
-		goto return_error;
-	}
-
-	if (!omap2_nand_ecc_check(info)) {
-		err = -EINVAL;
-		goto return_error;
-	}
-
-	/*
-	 * Bail out earlier to let NAND_ECC_SOFT code create its own
-	 * ooblayout instead of using ours.
-	 */
-	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
-		nand_chip->ecc.mode = NAND_ECC_SOFT;
-		nand_chip->ecc.algo = NAND_ECC_HAMMING;
-		goto scan_tail;
-	}
-
-	/* populate MTD interface based on ECC scheme */
-	switch (info->ecc_opt) {
-	case OMAP_ECC_HAM1_CODE_HW:
-		pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
-		nand_chip->ecc.mode             = NAND_ECC_HW;
-		nand_chip->ecc.bytes            = 3;
-		nand_chip->ecc.size             = 512;
-		nand_chip->ecc.strength         = 1;
-		nand_chip->ecc.calculate        = omap_calculate_ecc;
-		nand_chip->ecc.hwctl            = omap_enable_hwecc;
-		nand_chip->ecc.correct          = omap_correct_data;
-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-		oobbytes_per_step		= nand_chip->ecc.bytes;
-
-		if (!(nand_chip->options & NAND_BUSWIDTH_16))
-			min_oobbytes		= 1;
-
-		break;
-
-	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
-		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
-		nand_chip->ecc.mode		= NAND_ECC_HW;
-		nand_chip->ecc.size		= 512;
-		nand_chip->ecc.bytes		= 7;
-		nand_chip->ecc.strength		= 4;
-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
-		nand_chip->ecc.correct		= nand_bch_correct_data;
-		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
-		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
-		/* Reserve one byte for the OMAP marker */
-		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
-		/* software bch library is used for locating errors */
-		nand_chip->ecc.priv		= nand_bch_init(mtd);
-		if (!nand_chip->ecc.priv) {
-			dev_err(&info->pdev->dev, "unable to use BCH library\n");
-			err = -EINVAL;
-			goto return_error;
-		}
-		break;
-
-	case OMAP_ECC_BCH4_CODE_HW:
-		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
-		nand_chip->ecc.mode		= NAND_ECC_HW;
-		nand_chip->ecc.size		= 512;
-		/* 14th bit is kept reserved for ROM-code compatibility */
-		nand_chip->ecc.bytes		= 7 + 1;
-		nand_chip->ecc.strength		= 4;
-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
-		nand_chip->ecc.correct		= omap_elm_correct_data;
-		nand_chip->ecc.read_page	= omap_read_page_bch;
-		nand_chip->ecc.write_page	= omap_write_page_bch;
-		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-		oobbytes_per_step		= nand_chip->ecc.bytes;
-
-		err = elm_config(info->elm_dev, BCH4_ECC,
-				 mtd->writesize / nand_chip->ecc.size,
-				 nand_chip->ecc.size, nand_chip->ecc.bytes);
-		if (err < 0)
-			goto return_error;
-		break;
-
-	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
-		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
-		nand_chip->ecc.mode		= NAND_ECC_HW;
-		nand_chip->ecc.size		= 512;
-		nand_chip->ecc.bytes		= 13;
-		nand_chip->ecc.strength		= 8;
-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
-		nand_chip->ecc.correct		= nand_bch_correct_data;
-		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
-		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
-		/* Reserve one byte for the OMAP marker */
-		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
-		/* software bch library is used for locating errors */
-		nand_chip->ecc.priv		= nand_bch_init(mtd);
-		if (!nand_chip->ecc.priv) {
-			dev_err(&info->pdev->dev, "unable to use BCH library\n");
-			err = -EINVAL;
-			goto return_error;
-		}
-		break;
-
-	case OMAP_ECC_BCH8_CODE_HW:
-		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
-		nand_chip->ecc.mode		= NAND_ECC_HW;
-		nand_chip->ecc.size		= 512;
-		/* 14th bit is kept reserved for ROM-code compatibility */
-		nand_chip->ecc.bytes		= 13 + 1;
-		nand_chip->ecc.strength		= 8;
-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
-		nand_chip->ecc.correct		= omap_elm_correct_data;
-		nand_chip->ecc.read_page	= omap_read_page_bch;
-		nand_chip->ecc.write_page	= omap_write_page_bch;
-		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-		oobbytes_per_step		= nand_chip->ecc.bytes;
-
-		err = elm_config(info->elm_dev, BCH8_ECC,
-				 mtd->writesize / nand_chip->ecc.size,
-				 nand_chip->ecc.size, nand_chip->ecc.bytes);
-		if (err < 0)
-			goto return_error;
-
-		break;
-
-	case OMAP_ECC_BCH16_CODE_HW:
-		pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
-		nand_chip->ecc.mode		= NAND_ECC_HW;
-		nand_chip->ecc.size		= 512;
-		nand_chip->ecc.bytes		= 26;
-		nand_chip->ecc.strength		= 16;
-		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
-		nand_chip->ecc.correct		= omap_elm_correct_data;
-		nand_chip->ecc.read_page	= omap_read_page_bch;
-		nand_chip->ecc.write_page	= omap_write_page_bch;
-		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
-		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
-		oobbytes_per_step		= nand_chip->ecc.bytes;
-
-		err = elm_config(info->elm_dev, BCH16_ECC,
-				 mtd->writesize / nand_chip->ecc.size,
-				 nand_chip->ecc.size, nand_chip->ecc.bytes);
-		if (err < 0)
-			goto return_error;
-
-		break;
-	default:
-		dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
-		err = -EINVAL;
-		goto return_error;
-	}
-
-	/* check if NAND device's OOB is enough to store ECC signatures */
-	min_oobbytes += (oobbytes_per_step *
-			 (mtd->writesize / nand_chip->ecc.size));
-	if (mtd->oobsize < min_oobbytes) {
-		dev_err(&info->pdev->dev,
-			"not enough OOB bytes required = %d, available=%d\n",
-			min_oobbytes, mtd->oobsize);
-		err = -EINVAL;
-		goto return_error;
-	}
-
-scan_tail:
-	/* second phase scan */
-	err = nand_scan_tail(mtd);
-	if (err)
-		goto return_error;
-
-	err = mtd_device_register(mtd, NULL, 0);
-	if (err)
-		goto return_error;
-
-	platform_set_drvdata(pdev, mtd);
-
-	return 0;
-
-return_error:
-	if (!IS_ERR_OR_NULL(info->dma))
-		dma_release_channel(info->dma);
-	if (nand_chip->ecc.priv) {
-		nand_bch_free(nand_chip->ecc.priv);
-		nand_chip->ecc.priv = NULL;
-	}
-	return err;
-}
-
-static int omap_nand_remove(struct platform_device *pdev)
-{
-	struct mtd_info *mtd = platform_get_drvdata(pdev);
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct omap_nand_info *info = mtd_to_omap(mtd);
-	if (nand_chip->ecc.priv) {
-		nand_bch_free(nand_chip->ecc.priv);
-		nand_chip->ecc.priv = NULL;
-	}
-	if (info->dma)
-		dma_release_channel(info->dma);
-	nand_release(mtd);
-	return 0;
-}
-
-static const struct of_device_id omap_nand_ids[] = {
-	{ .compatible = "ti,omap2-nand", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, omap_nand_ids);
-
-static struct platform_driver omap_nand_driver = {
-	.probe		= omap_nand_probe,
-	.remove		= omap_nand_remove,
-	.driver		= {
-		.name	= DRIVER_NAME,
-		.of_match_table = of_match_ptr(omap_nand_ids),
-	},
-};
-
-module_platform_driver(omap_nand_driver);
-
-MODULE_ALIAS("platform:" DRIVER_NAME);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c
deleted file mode 100644
index a3f32f939cc1..000000000000
--- a/drivers/mtd/nand/omap_elm.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Error Location Module
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#define DRIVER_NAME	"omap-elm"
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/sched.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_data/elm.h>
-
-#define ELM_SYSCONFIG			0x010
-#define ELM_IRQSTATUS			0x018
-#define ELM_IRQENABLE			0x01c
-#define ELM_LOCATION_CONFIG		0x020
-#define ELM_PAGE_CTRL			0x080
-#define ELM_SYNDROME_FRAGMENT_0		0x400
-#define ELM_SYNDROME_FRAGMENT_1		0x404
-#define ELM_SYNDROME_FRAGMENT_2		0x408
-#define ELM_SYNDROME_FRAGMENT_3		0x40c
-#define ELM_SYNDROME_FRAGMENT_4		0x410
-#define ELM_SYNDROME_FRAGMENT_5		0x414
-#define ELM_SYNDROME_FRAGMENT_6		0x418
-#define ELM_LOCATION_STATUS		0x800
-#define ELM_ERROR_LOCATION_0		0x880
-
-/* ELM Interrupt Status Register */
-#define INTR_STATUS_PAGE_VALID		BIT(8)
-
-/* ELM Interrupt Enable Register */
-#define INTR_EN_PAGE_MASK		BIT(8)
-
-/* ELM Location Configuration Register */
-#define ECC_BCH_LEVEL_MASK		0x3
-
-/* ELM syndrome */
-#define ELM_SYNDROME_VALID		BIT(16)
-
-/* ELM_LOCATION_STATUS Register */
-#define ECC_CORRECTABLE_MASK		BIT(8)
-#define ECC_NB_ERRORS_MASK		0x1f
-
-/* ELM_ERROR_LOCATION_0-15 Registers */
-#define ECC_ERROR_LOCATION_MASK		0x1fff
-
-#define ELM_ECC_SIZE			0x7ff
-
-#define SYNDROME_FRAGMENT_REG_SIZE	0x40
-#define ERROR_LOCATION_SIZE		0x100
-
-struct elm_registers {
-	u32 elm_irqenable;
-	u32 elm_sysconfig;
-	u32 elm_location_config;
-	u32 elm_page_ctrl;
-	u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
-	u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
-	u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
-	u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
-	u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
-	u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
-	u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
-};
-
-struct elm_info {
-	struct device *dev;
-	void __iomem *elm_base;
-	struct completion elm_completion;
-	struct list_head list;
-	enum bch_ecc bch_type;
-	struct elm_registers elm_regs;
-	int ecc_steps;
-	int ecc_syndrome_size;
-};
-
-static LIST_HEAD(elm_devices);
-
-static void elm_write_reg(struct elm_info *info, int offset, u32 val)
-{
-	writel(val, info->elm_base + offset);
-}
-
-static u32 elm_read_reg(struct elm_info *info, int offset)
-{
-	return readl(info->elm_base + offset);
-}
-
-/**
- * elm_config - Configure ELM module
- * @dev:	ELM device
- * @bch_type:	Type of BCH ecc
- */
-int elm_config(struct device *dev, enum bch_ecc bch_type,
-	int ecc_steps, int ecc_step_size, int ecc_syndrome_size)
-{
-	u32 reg_val;
-	struct elm_info *info = dev_get_drvdata(dev);
-
-	if (!info) {
-		dev_err(dev, "Unable to configure elm - device not probed?\n");
-		return -EPROBE_DEFER;
-	}
-	/* ELM cannot detect ECC errors for chunks > 1KB */
-	if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) {
-		dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size);
-		return -EINVAL;
-	}
-	/* ELM support 8 error syndrome process */
-	if (ecc_steps > ERROR_VECTOR_MAX) {
-		dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
-		return -EINVAL;
-	}
-
-	reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
-	elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
-	info->bch_type		= bch_type;
-	info->ecc_steps		= ecc_steps;
-	info->ecc_syndrome_size	= ecc_syndrome_size;
-
-	return 0;
-}
-EXPORT_SYMBOL(elm_config);
-
-/**
- * elm_configure_page_mode - Enable/Disable page mode
- * @info:	elm info
- * @index:	index number of syndrome fragment vector
- * @enable:	enable/disable flag for page mode
- *
- * Enable page mode for syndrome fragment index
- */
-static void elm_configure_page_mode(struct elm_info *info, int index,
-		bool enable)
-{
-	u32 reg_val;
-
-	reg_val = elm_read_reg(info, ELM_PAGE_CTRL);
-	if (enable)
-		reg_val |= BIT(index);	/* enable page mode */
-	else
-		reg_val &= ~BIT(index);	/* disable page mode */
-
-	elm_write_reg(info, ELM_PAGE_CTRL, reg_val);
-}
-
-/**
- * elm_load_syndrome - Load ELM syndrome reg
- * @info:	elm info
- * @err_vec:	elm error vectors
- * @ecc:	buffer with calculated ecc
- *
- * Load syndrome fragment registers with calculated ecc in reverse order.
- */
-static void elm_load_syndrome(struct elm_info *info,
-		struct elm_errorvec *err_vec, u8 *ecc)
-{
-	int i, offset;
-	u32 val;
-
-	for (i = 0; i < info->ecc_steps; i++) {
-
-		/* Check error reported */
-		if (err_vec[i].error_reported) {
-			elm_configure_page_mode(info, i, true);
-			offset = ELM_SYNDROME_FRAGMENT_0 +
-				SYNDROME_FRAGMENT_REG_SIZE * i;
-			switch (info->bch_type) {
-			case BCH8_ECC:
-				/* syndrome fragment 0 = ecc[9-12B] */
-				val = cpu_to_be32(*(u32 *) &ecc[9]);
-				elm_write_reg(info, offset, val);
-
-				/* syndrome fragment 1 = ecc[5-8B] */
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[5]);
-				elm_write_reg(info, offset, val);
-
-				/* syndrome fragment 2 = ecc[1-4B] */
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[1]);
-				elm_write_reg(info, offset, val);
-
-				/* syndrome fragment 3 = ecc[0B] */
-				offset += 4;
-				val = ecc[0];
-				elm_write_reg(info, offset, val);
-				break;
-			case BCH4_ECC:
-				/* syndrome fragment 0 = ecc[20-52b] bits */
-				val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
-					((ecc[2] & 0xf) << 28);
-				elm_write_reg(info, offset, val);
-
-				/* syndrome fragment 1 = ecc[0-20b] bits */
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
-				elm_write_reg(info, offset, val);
-				break;
-			case BCH16_ECC:
-				val = cpu_to_be32(*(u32 *) &ecc[22]);
-				elm_write_reg(info, offset, val);
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[18]);
-				elm_write_reg(info, offset, val);
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[14]);
-				elm_write_reg(info, offset, val);
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[10]);
-				elm_write_reg(info, offset, val);
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[6]);
-				elm_write_reg(info, offset, val);
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[2]);
-				elm_write_reg(info, offset, val);
-				offset += 4;
-				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16;
-				elm_write_reg(info, offset, val);
-				break;
-			default:
-				pr_err("invalid config bch_type\n");
-			}
-		}
-
-		/* Update ecc pointer with ecc byte size */
-		ecc += info->ecc_syndrome_size;
-	}
-}
-
-/**
- * elm_start_processing - start elm syndrome processing
- * @info:	elm info
- * @err_vec:	elm error vectors
- *
- * Set syndrome valid bit for syndrome fragment registers for which
- * elm syndrome fragment registers are loaded. This enables elm module
- * to start processing syndrome vectors.
- */
-static void elm_start_processing(struct elm_info *info,
-		struct elm_errorvec *err_vec)
-{
-	int i, offset;
-	u32 reg_val;
-
-	/*
-	 * Set syndrome vector valid, so that ELM module
-	 * will process it for vectors error is reported
-	 */
-	for (i = 0; i < info->ecc_steps; i++) {
-		if (err_vec[i].error_reported) {
-			offset = ELM_SYNDROME_FRAGMENT_6 +
-				SYNDROME_FRAGMENT_REG_SIZE * i;
-			reg_val = elm_read_reg(info, offset);
-			reg_val |= ELM_SYNDROME_VALID;
-			elm_write_reg(info, offset, reg_val);
-		}
-	}
-}
-
-/**
- * elm_error_correction - locate correctable error position
- * @info:	elm info
- * @err_vec:	elm error vectors
- *
- * On completion of processing by elm module, error location status
- * register updated with correctable/uncorrectable error information.
- * In case of correctable errors, number of errors located from
- * elm location status register & read the positions from
- * elm error location register.
- */
-static void elm_error_correction(struct elm_info *info,
-		struct elm_errorvec *err_vec)
-{
-	int i, j, errors = 0;
-	int offset;
-	u32 reg_val;
-
-	for (i = 0; i < info->ecc_steps; i++) {
-
-		/* Check error reported */
-		if (err_vec[i].error_reported) {
-			offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i;
-			reg_val = elm_read_reg(info, offset);
-
-			/* Check correctable error or not */
-			if (reg_val & ECC_CORRECTABLE_MASK) {
-				offset = ELM_ERROR_LOCATION_0 +
-					ERROR_LOCATION_SIZE * i;
-
-				/* Read count of correctable errors */
-				err_vec[i].error_count = reg_val &
-					ECC_NB_ERRORS_MASK;
-
-				/* Update the error locations in error vector */
-				for (j = 0; j < err_vec[i].error_count; j++) {
-
-					reg_val = elm_read_reg(info, offset);
-					err_vec[i].error_loc[j] = reg_val &
-						ECC_ERROR_LOCATION_MASK;
-
-					/* Update error location register */
-					offset += 4;
-				}
-
-				errors += err_vec[i].error_count;
-			} else {
-				err_vec[i].error_uncorrectable = true;
-			}
-
-			/* Clearing interrupts for processed error vectors */
-			elm_write_reg(info, ELM_IRQSTATUS, BIT(i));
-
-			/* Disable page mode */
-			elm_configure_page_mode(info, i, false);
-		}
-	}
-}
-
-/**
- * elm_decode_bch_error_page - Locate error position
- * @dev:	device pointer
- * @ecc_calc:	calculated ECC bytes from GPMC
- * @err_vec:	elm error vectors
- *
- * Called with one or more error reported vectors & vectors with
- * error reported is updated in err_vec[].error_reported
- */
-void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
-		struct elm_errorvec *err_vec)
-{
-	struct elm_info *info = dev_get_drvdata(dev);
-	u32 reg_val;
-
-	/* Enable page mode interrupt */
-	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
-	elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID);
-	elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK);
-
-	/* Load valid ecc byte to syndrome fragment register */
-	elm_load_syndrome(info, err_vec, ecc_calc);
-
-	/* Enable syndrome processing for which syndrome fragment is updated */
-	elm_start_processing(info, err_vec);
-
-	/* Wait for ELM module to finish locating error correction */
-	wait_for_completion(&info->elm_completion);
-
-	/* Disable page mode interrupt */
-	reg_val = elm_read_reg(info, ELM_IRQENABLE);
-	elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK);
-	elm_error_correction(info, err_vec);
-}
-EXPORT_SYMBOL(elm_decode_bch_error_page);
-
-static irqreturn_t elm_isr(int this_irq, void *dev_id)
-{
-	u32 reg_val;
-	struct elm_info *info = dev_id;
-
-	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
-
-	/* All error vectors processed */
-	if (reg_val & INTR_STATUS_PAGE_VALID) {
-		elm_write_reg(info, ELM_IRQSTATUS,
-				reg_val & INTR_STATUS_PAGE_VALID);
-		complete(&info->elm_completion);
-		return IRQ_HANDLED;
-	}
-
-	return IRQ_NONE;
-}
-
-static int elm_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct resource *res, *irq;
-	struct elm_info *info;
-
-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	info->dev = &pdev->dev;
-
-	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "no irq resource defined\n");
-		return -ENODEV;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	info->elm_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(info->elm_base))
-		return PTR_ERR(info->elm_base);
-
-	ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
-			pdev->name, info);
-	if (ret) {
-		dev_err(&pdev->dev, "failure requesting %pr\n", irq);
-		return ret;
-	}
-
-	pm_runtime_enable(&pdev->dev);
-	if (pm_runtime_get_sync(&pdev->dev) < 0) {
-		ret = -EINVAL;
-		pm_runtime_disable(&pdev->dev);
-		dev_err(&pdev->dev, "can't enable clock\n");
-		return ret;
-	}
-
-	init_completion(&info->elm_completion);
-	INIT_LIST_HEAD(&info->list);
-	list_add(&info->list, &elm_devices);
-	platform_set_drvdata(pdev, info);
-	return ret;
-}
-
-static int elm_remove(struct platform_device *pdev)
-{
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-/**
- * elm_context_save
- * saves ELM configurations to preserve them across Hardware powered-down
- */
-static int elm_context_save(struct elm_info *info)
-{
-	struct elm_registers *regs = &info->elm_regs;
-	enum bch_ecc bch_type = info->bch_type;
-	u32 offset = 0, i;
-
-	regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
-	regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
-	regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
-	regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
-	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
-		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
-		switch (bch_type) {
-		case BCH16_ECC:
-			regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_6 + offset);
-			regs->elm_syndrome_fragment_5[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_5 + offset);
-			regs->elm_syndrome_fragment_4[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_4 + offset);
-		case BCH8_ECC:
-			regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_3 + offset);
-			regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_2 + offset);
-		case BCH4_ECC:
-			regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_1 + offset);
-			regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_0 + offset);
-			break;
-		default:
-			return -EINVAL;
-		}
-		/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
-		 * to be saved for all BCH schemes*/
-		regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
-					ELM_SYNDROME_FRAGMENT_6 + offset);
-	}
-	return 0;
-}
-
-/**
- * elm_context_restore
- * writes configurations saved duing power-down back into ELM registers
- */
-static int elm_context_restore(struct elm_info *info)
-{
-	struct elm_registers *regs = &info->elm_regs;
-	enum bch_ecc bch_type = info->bch_type;
-	u32 offset = 0, i;
-
-	elm_write_reg(info, ELM_IRQENABLE,	 regs->elm_irqenable);
-	elm_write_reg(info, ELM_SYSCONFIG,	 regs->elm_sysconfig);
-	elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
-	elm_write_reg(info, ELM_PAGE_CTRL,	 regs->elm_page_ctrl);
-	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
-		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
-		switch (bch_type) {
-		case BCH16_ECC:
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
-					regs->elm_syndrome_fragment_6[i]);
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset,
-					regs->elm_syndrome_fragment_5[i]);
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset,
-					regs->elm_syndrome_fragment_4[i]);
-		case BCH8_ECC:
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
-					regs->elm_syndrome_fragment_3[i]);
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
-					regs->elm_syndrome_fragment_2[i]);
-		case BCH4_ECC:
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
-					regs->elm_syndrome_fragment_1[i]);
-			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
-					regs->elm_syndrome_fragment_0[i]);
-			break;
-		default:
-			return -EINVAL;
-		}
-		/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
-		elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
-					regs->elm_syndrome_fragment_6[i] &
-							 ELM_SYNDROME_VALID);
-	}
-	return 0;
-}
-
-static int elm_suspend(struct device *dev)
-{
-	struct elm_info *info = dev_get_drvdata(dev);
-	elm_context_save(info);
-	pm_runtime_put_sync(dev);
-	return 0;
-}
-
-static int elm_resume(struct device *dev)
-{
-	struct elm_info *info = dev_get_drvdata(dev);
-	pm_runtime_get_sync(dev);
-	elm_context_restore(info);
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
-
-#ifdef CONFIG_OF
-static const struct of_device_id elm_of_match[] = {
-	{ .compatible = "ti,am3352-elm" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, elm_of_match);
-#endif
-
-static struct platform_driver elm_driver = {
-	.driver	= {
-		.name	= DRIVER_NAME,
-		.of_match_table = of_match_ptr(elm_of_match),
-		.pm	= &elm_pm_ops,
-	},
-	.probe	= elm_probe,
-	.remove	= elm_remove,
-};
-
-module_platform_driver(elm_driver);
-
-MODULE_DESCRIPTION("ELM driver for BCH error correction");
-MODULE_AUTHOR("Texas Instruments");
-MODULE_ALIAS("platform:" DRIVER_NAME);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
deleted file mode 100644
index 5a5aa1f07d07..000000000000
--- a/drivers/mtd/nand/orion_nand.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * drivers/mtd/nand/orion_nand.c
- *
- * NAND support for Marvell Orion SoC platforms
- *
- * Tzachi Perelstein <tzachi@marvell.com>
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <asm/sizes.h>
-#include <linux/platform_data/mtd-orion_nand.h>
-
-struct orion_nand_info {
-	struct nand_chip chip;
-	struct clk *clk;
-};
-
-static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	struct nand_chip *nc = mtd_to_nand(mtd);
-	struct orion_nand_data *board = nand_get_controller_data(nc);
-	u32 offs;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		offs = (1 << board->cle);
-	else if (ctrl & NAND_ALE)
-		offs = (1 << board->ale);
-	else
-		return;
-
-	if (nc->options & NAND_BUSWIDTH_16)
-		offs <<= 1;
-
-	writeb(cmd, nc->IO_ADDR_W + offs);
-}
-
-static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	void __iomem *io_base = chip->IO_ADDR_R;
-#if __LINUX_ARM_ARCH__ >= 5
-	uint64_t *buf64;
-#endif
-	int i = 0;
-
-	while (len && (unsigned long)buf & 7) {
-		*buf++ = readb(io_base);
-		len--;
-	}
-#if __LINUX_ARM_ARCH__ >= 5
-	buf64 = (uint64_t *)buf;
-	while (i < len/8) {
-		/*
-		 * Since GCC has no proper constraint (PR 43518)
-		 * force x variable to r2/r3 registers as ldrd instruction
-		 * requires first register to be even.
-		 */
-		register uint64_t x asm ("r2");
-
-		asm volatile ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base));
-		buf64[i++] = x;
-	}
-	i *= 8;
-#else
-	readsl(io_base, buf, len/4);
-	i = len / 4 * 4;
-#endif
-	while (i < len)
-		buf[i++] = readb(io_base);
-}
-
-static int __init orion_nand_probe(struct platform_device *pdev)
-{
-	struct orion_nand_info *info;
-	struct mtd_info *mtd;
-	struct nand_chip *nc;
-	struct orion_nand_data *board;
-	struct resource *res;
-	void __iomem *io_base;
-	int ret = 0;
-	u32 val = 0;
-
-	info = devm_kzalloc(&pdev->dev,
-			sizeof(struct orion_nand_info),
-			GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-	nc = &info->chip;
-	mtd = nand_to_mtd(nc);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	io_base = devm_ioremap_resource(&pdev->dev, res);
-
-	if (IS_ERR(io_base))
-		return PTR_ERR(io_base);
-
-	if (pdev->dev.of_node) {
-		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
-					GFP_KERNEL);
-		if (!board)
-			return -ENOMEM;
-		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
-			board->cle = (u8)val;
-		else
-			board->cle = 0;
-		if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
-			board->ale = (u8)val;
-		else
-			board->ale = 1;
-		if (!of_property_read_u32(pdev->dev.of_node,
-						"bank-width", &val))
-			board->width = (u8)val * 8;
-		else
-			board->width = 8;
-		if (!of_property_read_u32(pdev->dev.of_node,
-						"chip-delay", &val))
-			board->chip_delay = (u8)val;
-	} else {
-		board = dev_get_platdata(&pdev->dev);
-	}
-
-	mtd->dev.parent = &pdev->dev;
-
-	nand_set_controller_data(nc, board);
-	nand_set_flash_node(nc, pdev->dev.of_node);
-	nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
-	nc->cmd_ctrl = orion_nand_cmd_ctrl;
-	nc->read_buf = orion_nand_read_buf;
-	nc->ecc.mode = NAND_ECC_SOFT;
-	nc->ecc.algo = NAND_ECC_HAMMING;
-
-	if (board->chip_delay)
-		nc->chip_delay = board->chip_delay;
-
-	WARN(board->width > 16,
-		"%d bit bus width out of range",
-		board->width);
-
-	if (board->width == 16)
-		nc->options |= NAND_BUSWIDTH_16;
-
-	if (board->dev_ready)
-		nc->dev_ready = board->dev_ready;
-
-	platform_set_drvdata(pdev, info);
-
-	/* Not all platforms can gate the clock, so it is not
-	   an error if the clock does not exists. */
-	info->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(info->clk)) {
-		ret = PTR_ERR(info->clk);
-		if (ret == -ENOENT) {
-			info->clk = NULL;
-		} else {
-			dev_err(&pdev->dev, "failed to get clock!\n");
-			return ret;
-		}
-	}
-
-	ret = clk_prepare_enable(info->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to prepare clock!\n");
-		return ret;
-	}
-
-	ret = nand_scan(mtd, 1);
-	if (ret)
-		goto no_dev;
-
-	mtd->name = "orion_nand";
-	ret = mtd_device_register(mtd, board->parts, board->nr_parts);
-	if (ret) {
-		nand_release(mtd);
-		goto no_dev;
-	}
-
-	return 0;
-
-no_dev:
-	clk_disable_unprepare(info->clk);
-	return ret;
-}
-
-static int orion_nand_remove(struct platform_device *pdev)
-{
-	struct orion_nand_info *info = platform_get_drvdata(pdev);
-	struct nand_chip *chip = &info->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	nand_release(mtd);
-
-	clk_disable_unprepare(info->clk);
-
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id orion_nand_of_match_table[] = {
-	{ .compatible = "marvell,orion-nand", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
-#endif
-
-static struct platform_driver orion_nand_driver = {
-	.remove		= orion_nand_remove,
-	.driver		= {
-		.name	= "orion_nand",
-		.of_match_table = of_match_ptr(orion_nand_of_match_table),
-	},
-};
-
-module_platform_driver_probe(orion_nand_driver, orion_nand_probe);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Tzachi Perelstein");
-MODULE_DESCRIPTION("NAND glue for Orion platforms");
-MODULE_ALIAS("platform:orion_nand");
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
deleted file mode 100644
index d649d5944826..000000000000
--- a/drivers/mtd/nand/oxnas_nand.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Oxford Semiconductor OXNAS NAND driver
-
- * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
- * Heavily based on plat_nand.c :
- * Author: Vitaly Wool <vitalywool@gmail.com>
- * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
- * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
- *
- * 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/err.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/reset.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of.h>
-
-/* Nand commands */
-#define OXNAS_NAND_CMD_ALE		BIT(18)
-#define OXNAS_NAND_CMD_CLE		BIT(19)
-
-#define OXNAS_NAND_MAX_CHIPS	1
-
-struct oxnas_nand_ctrl {
-	struct nand_hw_control base;
-	void __iomem *io_base;
-	struct clk *clk;
-	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
-};
-
-static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
-
-	return readb(oxnas->io_base);
-}
-
-static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
-
-	ioread8_rep(oxnas->io_base, buf, len);
-}
-
-static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
-
-	iowrite8_rep(oxnas->io_base, buf, len);
-}
-
-/* Single CS command control */
-static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-				unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
-
-	if (ctrl & NAND_CLE)
-		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
-	else if (ctrl & NAND_ALE)
-		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
-}
-
-/*
- * Probe for the NAND device.
- */
-static int oxnas_nand_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct device_node *nand_np;
-	struct oxnas_nand_ctrl *oxnas;
-	struct nand_chip *chip;
-	struct mtd_info *mtd;
-	struct resource *res;
-	int nchips = 0;
-	int count = 0;
-	int err = 0;
-
-	/* Allocate memory for the device structure (and zero it) */
-	oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas),
-			     GFP_KERNEL);
-	if (!oxnas)
-		return -ENOMEM;
-
-	nand_hw_control_init(&oxnas->base);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(oxnas->io_base))
-		return PTR_ERR(oxnas->io_base);
-
-	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(oxnas->clk))
-		oxnas->clk = NULL;
-
-	/* Only a single chip node is supported */
-	count = of_get_child_count(np);
-	if (count > 1)
-		return -EINVAL;
-
-	err = clk_prepare_enable(oxnas->clk);
-	if (err)
-		return err;
-
-	device_reset_optional(&pdev->dev);
-
-	for_each_child_of_node(np, nand_np) {
-		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
-				    GFP_KERNEL);
-		if (!chip) {
-			err = -ENOMEM;
-			goto err_clk_unprepare;
-		}
-
-		chip->controller = &oxnas->base;
-
-		nand_set_flash_node(chip, nand_np);
-		nand_set_controller_data(chip, oxnas);
-
-		mtd = nand_to_mtd(chip);
-		mtd->dev.parent = &pdev->dev;
-		mtd->priv = chip;
-
-		chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
-		chip->read_buf = oxnas_nand_read_buf;
-		chip->read_byte = oxnas_nand_read_byte;
-		chip->write_buf = oxnas_nand_write_buf;
-		chip->chip_delay = 30;
-
-		/* Scan to find existence of the device */
-		err = nand_scan(mtd, 1);
-		if (err)
-			goto err_clk_unprepare;
-
-		err = mtd_device_register(mtd, NULL, 0);
-		if (err) {
-			nand_release(mtd);
-			goto err_clk_unprepare;
-		}
-
-		oxnas->chips[nchips] = chip;
-		++nchips;
-	}
-
-	/* Exit if no chips found */
-	if (!nchips) {
-		err = -ENODEV;
-		goto err_clk_unprepare;
-	}
-
-	platform_set_drvdata(pdev, oxnas);
-
-	return 0;
-
-err_clk_unprepare:
-	clk_disable_unprepare(oxnas->clk);
-	return err;
-}
-
-static int oxnas_nand_remove(struct platform_device *pdev)
-{
-	struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
-
-	if (oxnas->chips[0])
-		nand_release(nand_to_mtd(oxnas->chips[0]));
-
-	clk_disable_unprepare(oxnas->clk);
-
-	return 0;
-}
-
-static const struct of_device_id oxnas_nand_match[] = {
-	{ .compatible = "oxsemi,ox820-nand" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, oxnas_nand_match);
-
-static struct platform_driver oxnas_nand_driver = {
-	.probe	= oxnas_nand_probe,
-	.remove	= oxnas_nand_remove,
-	.driver	= {
-		.name		= "oxnas_nand",
-		.of_match_table = oxnas_nand_match,
-	},
-};
-
-module_platform_driver(oxnas_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
-MODULE_DESCRIPTION("Oxnas NAND driver");
-MODULE_ALIAS("platform:oxnas_nand");
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
deleted file mode 100644
index a47a7e4bd25a..000000000000
--- a/drivers/mtd/nand/pasemi_nand.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2006-2007 PA Semi, Inc
- *
- * Author: Egor Martovetsky <egor@pasemi.com>
- * Maintained by: Olof Johansson <olof@lixom.net>
- *
- * Driver for the PWRficient onchip NAND flash interface
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#undef DEBUG
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
-
-#include <asm/io.h>
-
-#define LBICTRL_LPCCTL_NR		0x00004000
-#define CLE_PIN_CTL			15
-#define ALE_PIN_CTL			14
-
-static unsigned int lpcctl;
-static struct mtd_info *pasemi_nand_mtd;
-static const char driver_name[] = "pasemi-nand";
-
-static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	while (len > 0x800) {
-		memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
-		buf += 0x800;
-		len -= 0x800;
-	}
-	memcpy_fromio(buf, chip->IO_ADDR_R, len);
-}
-
-static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	while (len > 0x800) {
-		memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
-		buf += 0x800;
-		len -= 0x800;
-	}
-	memcpy_toio(chip->IO_ADDR_R, buf, len);
-}
-
-static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
-			     unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
-	else
-		out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
-
-	/* Push out posted writes */
-	eieio();
-	inl(lpcctl);
-}
-
-int pasemi_device_ready(struct mtd_info *mtd)
-{
-	return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
-}
-
-static int pasemi_nand_probe(struct platform_device *ofdev)
-{
-	struct device *dev = &ofdev->dev;
-	struct pci_dev *pdev;
-	struct device_node *np = dev->of_node;
-	struct resource res;
-	struct nand_chip *chip;
-	int err = 0;
-
-	err = of_address_to_resource(np, 0, &res);
-
-	if (err)
-		return -EINVAL;
-
-	/* We only support one device at the moment */
-	if (pasemi_nand_mtd)
-		return -ENODEV;
-
-	dev_dbg(dev, "pasemi_nand at %pR\n", &res);
-
-	/* Allocate memory for MTD device structure and private data */
-	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
-	if (!chip) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	pasemi_nand_mtd = nand_to_mtd(chip);
-
-	/* Link the private data with the MTD structure */
-	pasemi_nand_mtd->dev.parent = dev;
-
-	chip->IO_ADDR_R = of_iomap(np, 0);
-	chip->IO_ADDR_W = chip->IO_ADDR_R;
-
-	if (!chip->IO_ADDR_R) {
-		err = -EIO;
-		goto out_mtd;
-	}
-
-	pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL);
-	if (!pdev) {
-		err = -ENODEV;
-		goto out_ior;
-	}
-
-	lpcctl = pci_resource_start(pdev, 0);
-	pci_dev_put(pdev);
-
-	if (!request_region(lpcctl, 4, driver_name)) {
-		err = -EBUSY;
-		goto out_ior;
-	}
-
-	chip->cmd_ctrl = pasemi_hwcontrol;
-	chip->dev_ready = pasemi_device_ready;
-	chip->read_buf = pasemi_read_buf;
-	chip->write_buf = pasemi_write_buf;
-	chip->chip_delay = 0;
-	chip->ecc.mode = NAND_ECC_SOFT;
-	chip->ecc.algo = NAND_ECC_HAMMING;
-
-	/* Enable the following for a flash based bad block table */
-	chip->bbt_options = NAND_BBT_USE_FLASH;
-
-	/* Scan to find existence of the device */
-	err = nand_scan(pasemi_nand_mtd, 1);
-	if (err)
-		goto out_lpc;
-
-	if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
-		dev_err(dev, "Unable to register MTD device\n");
-		err = -ENODEV;
-		goto out_lpc;
-	}
-
-	dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
-		 lpcctl);
-
-	return 0;
-
- out_lpc:
-	release_region(lpcctl, 4);
- out_ior:
-	iounmap(chip->IO_ADDR_R);
- out_mtd:
-	kfree(chip);
- out:
-	return err;
-}
-
-static int pasemi_nand_remove(struct platform_device *ofdev)
-{
-	struct nand_chip *chip;
-
-	if (!pasemi_nand_mtd)
-		return 0;
-
-	chip = mtd_to_nand(pasemi_nand_mtd);
-
-	/* Release resources, unregister device */
-	nand_release(pasemi_nand_mtd);
-
-	release_region(lpcctl, 4);
-
-	iounmap(chip->IO_ADDR_R);
-
-	/* Free the MTD device structure */
-	kfree(chip);
-
-	pasemi_nand_mtd = NULL;
-
-	return 0;
-}
-
-static const struct of_device_id pasemi_nand_match[] =
-{
-	{
-		.compatible   = "pasemi,localbus-nand",
-	},
-	{},
-};
-
-MODULE_DEVICE_TABLE(of, pasemi_nand_match);
-
-static struct platform_driver pasemi_nand_driver =
-{
-	.driver = {
-		.name = driver_name,
-		.of_match_table = pasemi_nand_match,
-	},
-	.probe		= pasemi_nand_probe,
-	.remove		= pasemi_nand_remove,
-};
-
-module_platform_driver(pasemi_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
-MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient");
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
deleted file mode 100644
index 925a1323604d..000000000000
--- a/drivers/mtd/nand/plat_nand.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Generic NAND driver
- *
- * Author: Vitaly Wool <vitalywool@gmail.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/err.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-struct plat_nand_data {
-	struct nand_chip	chip;
-	void __iomem		*io_base;
-};
-
-/*
- * Probe for the NAND device.
- */
-static int plat_nand_probe(struct platform_device *pdev)
-{
-	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
-	struct plat_nand_data *data;
-	struct mtd_info *mtd;
-	struct resource *res;
-	const char **part_types;
-	int err = 0;
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "platform_nand_data is missing\n");
-		return -EINVAL;
-	}
-
-	if (pdata->chip.nr_chips < 1) {
-		dev_err(&pdev->dev, "invalid number of chips specified\n");
-		return -EINVAL;
-	}
-
-	/* Allocate memory for the device structure (and zero it) */
-	data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
-			    GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	data->io_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(data->io_base))
-		return PTR_ERR(data->io_base);
-
-	nand_set_flash_node(&data->chip, pdev->dev.of_node);
-	mtd = nand_to_mtd(&data->chip);
-	mtd->dev.parent = &pdev->dev;
-
-	data->chip.IO_ADDR_R = data->io_base;
-	data->chip.IO_ADDR_W = data->io_base;
-	data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
-	data->chip.dev_ready = pdata->ctrl.dev_ready;
-	data->chip.select_chip = pdata->ctrl.select_chip;
-	data->chip.write_buf = pdata->ctrl.write_buf;
-	data->chip.read_buf = pdata->ctrl.read_buf;
-	data->chip.read_byte = pdata->ctrl.read_byte;
-	data->chip.chip_delay = pdata->chip.chip_delay;
-	data->chip.options |= pdata->chip.options;
-	data->chip.bbt_options |= pdata->chip.bbt_options;
-
-	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
-	data->chip.ecc.mode = NAND_ECC_SOFT;
-	data->chip.ecc.algo = NAND_ECC_HAMMING;
-
-	platform_set_drvdata(pdev, data);
-
-	/* Handle any platform specific setup */
-	if (pdata->ctrl.probe) {
-		err = pdata->ctrl.probe(pdev);
-		if (err)
-			goto out;
-	}
-
-	/* Scan to find existence of the device */
-	err = nand_scan(mtd, pdata->chip.nr_chips);
-	if (err)
-		goto out;
-
-	part_types = pdata->chip.part_probe_types;
-
-	err = mtd_device_parse_register(mtd, part_types, NULL,
-					pdata->chip.partitions,
-					pdata->chip.nr_partitions);
-
-	if (!err)
-		return err;
-
-	nand_release(mtd);
-out:
-	if (pdata->ctrl.remove)
-		pdata->ctrl.remove(pdev);
-	return err;
-}
-
-/*
- * Remove a NAND device.
- */
-static int plat_nand_remove(struct platform_device *pdev)
-{
-	struct plat_nand_data *data = platform_get_drvdata(pdev);
-	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
-
-	nand_release(nand_to_mtd(&data->chip));
-	if (pdata->ctrl.remove)
-		pdata->ctrl.remove(pdev);
-
-	return 0;
-}
-
-static const struct of_device_id plat_nand_match[] = {
-	{ .compatible = "gen_nand" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, plat_nand_match);
-
-static struct platform_driver plat_nand_driver = {
-	.probe	= plat_nand_probe,
-	.remove	= plat_nand_remove,
-	.driver	= {
-		.name		= "gen_nand",
-		.of_match_table = plat_nand_match,
-	},
-};
-
-module_platform_driver(plat_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Vitaly Wool");
-MODULE_DESCRIPTION("Simple generic NAND driver");
-MODULE_ALIAS("platform:gen_nand");
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
deleted file mode 100644
index d1979c7dbe7e..000000000000
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ /dev/null
@@ -1,2105 +0,0 @@
-/*
- * drivers/mtd/nand/pxa3xx_nand.c
- *
- * Copyright © 2005 Intel Corporation
- * Copyright © 2006 Marvell International Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_data/mtd-nand-pxa3xx.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-
-#define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
-#define NAND_STOP_DELAY		msecs_to_jiffies(40)
-#define PAGE_CHUNK_SIZE		(2048)
-
-/*
- * Define a buffer size for the initial command that detects the flash device:
- * STATUS, READID and PARAM.
- * ONFI param page is 256 bytes, and there are three redundant copies
- * to be read. JEDEC param page is 512 bytes, and there are also three
- * redundant copies to be read.
- * Hence this buffer should be at least 512 x 3. Let's pick 2048.
- */
-#define INIT_BUFFER_SIZE	2048
-
-/* System control register and bit to enable NAND on some SoCs */
-#define GENCONF_SOC_DEVICE_MUX	0x208
-#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
-
-/* registers and bit definitions */
-#define NDCR		(0x00) /* Control register */
-#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
-#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
-#define NDSR		(0x14) /* Status Register */
-#define NDPCR		(0x18) /* Page Count Register */
-#define NDBDR0		(0x1C) /* Bad Block Register 0 */
-#define NDBDR1		(0x20) /* Bad Block Register 1 */
-#define NDECCCTRL	(0x28) /* ECC control */
-#define NDDB		(0x40) /* Data Buffer */
-#define NDCB0		(0x48) /* Command Buffer0 */
-#define NDCB1		(0x4C) /* Command Buffer1 */
-#define NDCB2		(0x50) /* Command Buffer2 */
-
-#define NDCR_SPARE_EN		(0x1 << 31)
-#define NDCR_ECC_EN		(0x1 << 30)
-#define NDCR_DMA_EN		(0x1 << 29)
-#define NDCR_ND_RUN		(0x1 << 28)
-#define NDCR_DWIDTH_C		(0x1 << 27)
-#define NDCR_DWIDTH_M		(0x1 << 26)
-#define NDCR_PAGE_SZ		(0x1 << 24)
-#define NDCR_NCSX		(0x1 << 23)
-#define NDCR_ND_MODE		(0x3 << 21)
-#define NDCR_NAND_MODE   	(0x0)
-#define NDCR_CLR_PG_CNT		(0x1 << 20)
-#define NFCV1_NDCR_ARB_CNTL	(0x1 << 19)
-#define NFCV2_NDCR_STOP_ON_UNCOR	(0x1 << 19)
-#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
-#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
-
-#define NDCR_RA_START		(0x1 << 15)
-#define NDCR_PG_PER_BLK		(0x1 << 14)
-#define NDCR_ND_ARB_EN		(0x1 << 12)
-#define NDCR_INT_MASK           (0xFFF)
-
-#define NDSR_MASK		(0xfff)
-#define NDSR_ERR_CNT_OFF	(16)
-#define NDSR_ERR_CNT_MASK       (0x1f)
-#define NDSR_ERR_CNT(sr)	((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
-#define NDSR_RDY                (0x1 << 12)
-#define NDSR_FLASH_RDY          (0x1 << 11)
-#define NDSR_CS0_PAGED		(0x1 << 10)
-#define NDSR_CS1_PAGED		(0x1 << 9)
-#define NDSR_CS0_CMDD		(0x1 << 8)
-#define NDSR_CS1_CMDD		(0x1 << 7)
-#define NDSR_CS0_BBD		(0x1 << 6)
-#define NDSR_CS1_BBD		(0x1 << 5)
-#define NDSR_UNCORERR		(0x1 << 4)
-#define NDSR_CORERR		(0x1 << 3)
-#define NDSR_WRDREQ		(0x1 << 2)
-#define NDSR_RDDREQ		(0x1 << 1)
-#define NDSR_WRCMDREQ		(0x1)
-
-#define NDCB0_LEN_OVRD		(0x1 << 28)
-#define NDCB0_ST_ROW_EN         (0x1 << 26)
-#define NDCB0_AUTO_RS		(0x1 << 25)
-#define NDCB0_CSEL		(0x1 << 24)
-#define NDCB0_EXT_CMD_TYPE_MASK	(0x7 << 29)
-#define NDCB0_EXT_CMD_TYPE(x)	(((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
-#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
-#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
-#define NDCB0_NC		(0x1 << 20)
-#define NDCB0_DBC		(0x1 << 19)
-#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
-#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
-#define NDCB0_CMD2_MASK		(0xff << 8)
-#define NDCB0_CMD1_MASK		(0xff)
-#define NDCB0_ADDR_CYC_SHIFT	(16)
-
-#define EXT_CMD_TYPE_DISPATCH	6 /* Command dispatch */
-#define EXT_CMD_TYPE_NAKED_RW	5 /* Naked read or Naked write */
-#define EXT_CMD_TYPE_READ	4 /* Read */
-#define EXT_CMD_TYPE_DISP_WR	4 /* Command dispatch with write */
-#define EXT_CMD_TYPE_FINAL	3 /* Final command */
-#define EXT_CMD_TYPE_LAST_RW	1 /* Last naked read/write */
-#define EXT_CMD_TYPE_MONO	0 /* Monolithic read/write */
-
-/*
- * This should be large enough to read 'ONFI' and 'JEDEC'.
- * Let's use 7 bytes, which is the maximum ID count supported
- * by the controller (see NDCR_RD_ID_CNT_MASK).
- */
-#define READ_ID_BYTES		7
-
-/* macros for registers read/write */
-#define nand_writel(info, off, val)					\
-	do {								\
-		dev_vdbg(&info->pdev->dev,				\
-			 "%s():%d nand_writel(0x%x, 0x%04x)\n",		\
-			 __func__, __LINE__, (val), (off));		\
-		writel_relaxed((val), (info)->mmio_base + (off));	\
-	} while (0)
-
-#define nand_readl(info, off)						\
-	({								\
-		unsigned int _v;					\
-		_v = readl_relaxed((info)->mmio_base + (off));		\
-		dev_vdbg(&info->pdev->dev,				\
-			 "%s():%d nand_readl(0x%04x) = 0x%x\n",		\
-			 __func__, __LINE__, (off), _v);		\
-		_v;							\
-	})
-
-/* error code and state */
-enum {
-	ERR_NONE	= 0,
-	ERR_DMABUSERR	= -1,
-	ERR_SENDCMD	= -2,
-	ERR_UNCORERR	= -3,
-	ERR_BBERR	= -4,
-	ERR_CORERR	= -5,
-};
-
-enum {
-	STATE_IDLE = 0,
-	STATE_PREPARED,
-	STATE_CMD_HANDLE,
-	STATE_DMA_READING,
-	STATE_DMA_WRITING,
-	STATE_DMA_DONE,
-	STATE_PIO_READING,
-	STATE_PIO_WRITING,
-	STATE_CMD_DONE,
-	STATE_READY,
-};
-
-enum pxa3xx_nand_variant {
-	PXA3XX_NAND_VARIANT_PXA,
-	PXA3XX_NAND_VARIANT_ARMADA370,
-	PXA3XX_NAND_VARIANT_ARMADA_8K,
-};
-
-struct pxa3xx_nand_host {
-	struct nand_chip	chip;
-	void			*info_data;
-
-	/* page size of attached chip */
-	int			use_ecc;
-	int			cs;
-
-	/* calculated from pxa3xx_nand_flash data */
-	unsigned int		col_addr_cycles;
-	unsigned int		row_addr_cycles;
-};
-
-struct pxa3xx_nand_info {
-	struct nand_hw_control	controller;
-	struct platform_device	 *pdev;
-
-	struct clk		*clk;
-	void __iomem		*mmio_base;
-	unsigned long		mmio_phys;
-	struct completion	cmd_complete, dev_ready;
-
-	unsigned int 		buf_start;
-	unsigned int		buf_count;
-	unsigned int		buf_size;
-	unsigned int		data_buff_pos;
-	unsigned int		oob_buff_pos;
-
-	/* DMA information */
-	struct scatterlist	sg;
-	enum dma_data_direction	dma_dir;
-	struct dma_chan		*dma_chan;
-	dma_cookie_t		dma_cookie;
-	int			drcmr_dat;
-
-	unsigned char		*data_buff;
-	unsigned char		*oob_buff;
-	dma_addr_t 		data_buff_phys;
-	int 			data_dma_ch;
-
-	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
-	unsigned int		state;
-
-	/*
-	 * This driver supports NFCv1 (as found in PXA SoC)
-	 * and NFCv2 (as found in Armada 370/XP SoC).
-	 */
-	enum pxa3xx_nand_variant variant;
-
-	int			cs;
-	int			use_ecc;	/* use HW ECC ? */
-	int			ecc_bch;	/* using BCH ECC? */
-	int			use_dma;	/* use DMA ? */
-	int			use_spare;	/* use spare ? */
-	int			need_wait;
-
-	/* Amount of real data per full chunk */
-	unsigned int		chunk_size;
-
-	/* Amount of spare data per full chunk */
-	unsigned int		spare_size;
-
-	/* Number of full chunks (i.e chunk_size + spare_size) */
-	unsigned int            nfullchunks;
-
-	/*
-	 * Total number of chunks. If equal to nfullchunks, then there
-	 * are only full chunks. Otherwise, there is one last chunk of
-	 * size (last_chunk_size + last_spare_size)
-	 */
-	unsigned int            ntotalchunks;
-
-	/* Amount of real data in the last chunk */
-	unsigned int		last_chunk_size;
-
-	/* Amount of spare data in the last chunk */
-	unsigned int		last_spare_size;
-
-	unsigned int		ecc_size;
-	unsigned int		ecc_err_cnt;
-	unsigned int		max_bitflips;
-	int 			retcode;
-
-	/*
-	 * Variables only valid during command
-	 * execution. step_chunk_size and step_spare_size is the
-	 * amount of real data and spare data in the current
-	 * chunk. cur_chunk is the current chunk being
-	 * read/programmed.
-	 */
-	unsigned int		step_chunk_size;
-	unsigned int		step_spare_size;
-	unsigned int            cur_chunk;
-
-	/* cached register value */
-	uint32_t		reg_ndcr;
-	uint32_t		ndtr0cs0;
-	uint32_t		ndtr1cs0;
-
-	/* generated NDCBx register values */
-	uint32_t		ndcb0;
-	uint32_t		ndcb1;
-	uint32_t		ndcb2;
-	uint32_t		ndcb3;
-};
-
-static bool use_dma = 1;
-module_param(use_dma, bool, 0444);
-MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
-
-struct pxa3xx_nand_timing {
-	unsigned int	tCH;  /* Enable signal hold time */
-	unsigned int	tCS;  /* Enable signal setup time */
-	unsigned int	tWH;  /* ND_nWE high duration */
-	unsigned int	tWP;  /* ND_nWE pulse time */
-	unsigned int	tRH;  /* ND_nRE high duration */
-	unsigned int	tRP;  /* ND_nRE pulse width */
-	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
-	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
-	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
-};
-
-struct pxa3xx_nand_flash {
-	uint32_t	chip_id;
-	unsigned int	flash_width;	/* Width of Flash memory (DWIDTH_M) */
-	unsigned int	dfc_width;	/* Width of flash controller(DWIDTH_C) */
-	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
-};
-
-static struct pxa3xx_nand_timing timing[] = {
-	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
-	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
-	{ 10, 25, 15,  25, 15,  30, 25000,  60, 10, },
-	{ 10, 35, 15,  25, 15,  25, 25000,  60, 10, },
-};
-
-static struct pxa3xx_nand_flash builtin_flash_types[] = {
-	{ 0x46ec, 16, 16, &timing[1] },
-	{ 0xdaec,  8,  8, &timing[1] },
-	{ 0xd7ec,  8,  8, &timing[1] },
-	{ 0xa12c,  8,  8, &timing[2] },
-	{ 0xb12c, 16, 16, &timing[2] },
-	{ 0xdc2c,  8,  8, &timing[2] },
-	{ 0xcc2c, 16, 16, &timing[2] },
-	{ 0xba20, 16, 16, &timing[3] },
-};
-
-static int pxa3xx_ooblayout_ecc(struct mtd_info *mtd, int section,
-				struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	int nchunks = mtd->writesize / info->chunk_size;
-
-	if (section >= nchunks)
-		return -ERANGE;
-
-	oobregion->offset = ((info->ecc_size + info->spare_size) * section) +
-			    info->spare_size;
-	oobregion->length = info->ecc_size;
-
-	return 0;
-}
-
-static int pxa3xx_ooblayout_free(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	int nchunks = mtd->writesize / info->chunk_size;
-
-	if (section >= nchunks)
-		return -ERANGE;
-
-	if (!info->spare_size)
-		return 0;
-
-	oobregion->offset = section * (info->ecc_size + info->spare_size);
-	oobregion->length = info->spare_size;
-	if (!section) {
-		/*
-		 * Bootrom looks in bytes 0 & 5 for bad blocks for the
-		 * 4KB page / 4bit BCH combination.
-		 */
-		if (mtd->writesize == 4096 && info->chunk_size == 2048) {
-			oobregion->offset += 6;
-			oobregion->length -= 6;
-		} else {
-			oobregion->offset += 2;
-			oobregion->length -= 2;
-		}
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops pxa3xx_ooblayout_ops = {
-	.ecc = pxa3xx_ooblayout_ecc,
-	.free = pxa3xx_ooblayout_free,
-};
-
-static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
-static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
-
-static struct nand_bbt_descr bbt_main_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	8,
-	.len = 6,
-	.veroffs = 14,
-	.maxblocks = 8,		/* Last 8 blocks in each chip */
-	.pattern = bbt_pattern
-};
-
-static struct nand_bbt_descr bbt_mirror_descr = {
-	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION,
-	.offs =	8,
-	.len = 6,
-	.veroffs = 14,
-	.maxblocks = 8,		/* Last 8 blocks in each chip */
-	.pattern = bbt_mirror_pattern
-};
-
-#define NDTR0_tCH(c)	(min((c), 7) << 19)
-#define NDTR0_tCS(c)	(min((c), 7) << 16)
-#define NDTR0_tWH(c)	(min((c), 7) << 11)
-#define NDTR0_tWP(c)	(min((c), 7) << 8)
-#define NDTR0_tRH(c)	(min((c), 7) << 3)
-#define NDTR0_tRP(c)	(min((c), 7) << 0)
-
-#define NDTR1_tR(c)	(min((c), 65535) << 16)
-#define NDTR1_tWHR(c)	(min((c), 15) << 4)
-#define NDTR1_tAR(c)	(min((c), 15) << 0)
-
-/* convert nano-seconds to nand flash controller clock cycles */
-#define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000)
-
-static const struct of_device_id pxa3xx_nand_dt_ids[] = {
-	{
-		.compatible = "marvell,pxa3xx-nand",
-		.data       = (void *)PXA3XX_NAND_VARIANT_PXA,
-	},
-	{
-		.compatible = "marvell,armada370-nand",
-		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
-	},
-	{
-		.compatible = "marvell,armada-8k-nand",
-		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA_8K,
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
-
-static enum pxa3xx_nand_variant
-pxa3xx_nand_get_variant(struct platform_device *pdev)
-{
-	const struct of_device_id *of_id =
-			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
-	if (!of_id)
-		return PXA3XX_NAND_VARIANT_PXA;
-	return (enum pxa3xx_nand_variant)of_id->data;
-}
-
-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
-				   const struct pxa3xx_nand_timing *t)
-{
-	struct pxa3xx_nand_info *info = host->info_data;
-	unsigned long nand_clk = clk_get_rate(info->clk);
-	uint32_t ndtr0, ndtr1;
-
-	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
-		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
-		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
-		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
-		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
-		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
-
-	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
-		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
-		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
-
-	info->ndtr0cs0 = ndtr0;
-	info->ndtr1cs0 = ndtr1;
-	nand_writel(info, NDTR0CS0, ndtr0);
-	nand_writel(info, NDTR1CS0, ndtr1);
-}
-
-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
-				       const struct nand_sdr_timings *t)
-{
-	struct pxa3xx_nand_info *info = host->info_data;
-	struct nand_chip *chip = &host->chip;
-	unsigned long nand_clk = clk_get_rate(info->clk);
-	uint32_t ndtr0, ndtr1;
-
-	u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
-	u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000);
-	u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
-	u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000);
-	u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
-	u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000);
-	u32 tR = chip->chip_delay * 1000;
-	u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
-	u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
-
-	/* fallback to a default value if tR = 0 */
-	if (!tR)
-		tR = 20000;
-
-	ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) |
-		NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) |
-		NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) |
-		NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) |
-		NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) |
-		NDTR0_tRP(ns2cycle(tRP_min, nand_clk));
-
-	ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) |
-		NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) |
-		NDTR1_tAR(ns2cycle(tAR_min, nand_clk));
-
-	info->ndtr0cs0 = ndtr0;
-	info->ndtr1cs0 = ndtr1;
-	nand_writel(info, NDTR0CS0, ndtr0);
-	nand_writel(info, NDTR1CS0, ndtr1);
-}
-
-static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
-					   unsigned int *flash_width,
-					   unsigned int *dfc_width)
-{
-	struct nand_chip *chip = &host->chip;
-	struct pxa3xx_nand_info *info = host->info_data;
-	const struct pxa3xx_nand_flash *f = NULL;
-	int i, id, ntypes;
-	u8 idbuf[2];
-
-	ntypes = ARRAY_SIZE(builtin_flash_types);
-
-	nand_readid_op(chip, 0, idbuf, sizeof(idbuf));
-	id = idbuf[0] | (idbuf[1] << 8);
-
-	for (i = 0; i < ntypes; i++) {
-		f = &builtin_flash_types[i];
-
-		if (f->chip_id == id)
-			break;
-	}
-
-	if (i == ntypes) {
-		dev_err(&info->pdev->dev, "Error: timings not found\n");
-		return -EINVAL;
-	}
-
-	pxa3xx_nand_set_timing(host, f->timing);
-
-	*flash_width = f->flash_width;
-	*dfc_width = f->dfc_width;
-
-	return 0;
-}
-
-static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host,
-					 int mode)
-{
-	const struct nand_sdr_timings *timings;
-
-	mode = fls(mode) - 1;
-	if (mode < 0)
-		mode = 0;
-
-	timings = onfi_async_timing_mode_to_sdr_timings(mode);
-	if (IS_ERR(timings))
-		return PTR_ERR(timings);
-
-	pxa3xx_nand_set_sdr_timing(host, timings);
-
-	return 0;
-}
-
-static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
-{
-	struct nand_chip *chip = &host->chip;
-	struct pxa3xx_nand_info *info = host->info_data;
-	unsigned int flash_width = 0, dfc_width = 0;
-	int mode, err;
-
-	mode = onfi_get_async_timing_mode(chip);
-	if (mode == ONFI_TIMING_MODE_UNKNOWN) {
-		err = pxa3xx_nand_init_timings_compat(host, &flash_width,
-						      &dfc_width);
-		if (err)
-			return err;
-
-		if (flash_width == 16) {
-			info->reg_ndcr |= NDCR_DWIDTH_M;
-			chip->options |= NAND_BUSWIDTH_16;
-		}
-
-		info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0;
-	} else {
-		err = pxa3xx_nand_init_timings_onfi(host, mode);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-/**
- * NOTE: it is a must to set ND_RUN firstly, then write
- * command buffer, otherwise, it does not work.
- * We enable all the interrupt at the same time, and
- * let pxa3xx_nand_irq to handle all logic.
- */
-static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
-{
-	uint32_t ndcr;
-
-	ndcr = info->reg_ndcr;
-
-	if (info->use_ecc) {
-		ndcr |= NDCR_ECC_EN;
-		if (info->ecc_bch)
-			nand_writel(info, NDECCCTRL, 0x1);
-	} else {
-		ndcr &= ~NDCR_ECC_EN;
-		if (info->ecc_bch)
-			nand_writel(info, NDECCCTRL, 0x0);
-	}
-
-	if (info->use_dma)
-		ndcr |= NDCR_DMA_EN;
-	else
-		ndcr &= ~NDCR_DMA_EN;
-
-	if (info->use_spare)
-		ndcr |= NDCR_SPARE_EN;
-	else
-		ndcr &= ~NDCR_SPARE_EN;
-
-	ndcr |= NDCR_ND_RUN;
-
-	/* clear status bits and run */
-	nand_writel(info, NDSR, NDSR_MASK);
-	nand_writel(info, NDCR, 0);
-	nand_writel(info, NDCR, ndcr);
-}
-
-static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
-{
-	uint32_t ndcr;
-	int timeout = NAND_STOP_DELAY;
-
-	/* wait RUN bit in NDCR become 0 */
-	ndcr = nand_readl(info, NDCR);
-	while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) {
-		ndcr = nand_readl(info, NDCR);
-		udelay(1);
-	}
-
-	if (timeout <= 0) {
-		ndcr &= ~NDCR_ND_RUN;
-		nand_writel(info, NDCR, ndcr);
-	}
-	if (info->dma_chan)
-		dmaengine_terminate_all(info->dma_chan);
-
-	/* clear status bits */
-	nand_writel(info, NDSR, NDSR_MASK);
-}
-
-static void __maybe_unused
-enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
-{
-	uint32_t ndcr;
-
-	ndcr = nand_readl(info, NDCR);
-	nand_writel(info, NDCR, ndcr & ~int_mask);
-}
-
-static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
-{
-	uint32_t ndcr;
-
-	ndcr = nand_readl(info, NDCR);
-	nand_writel(info, NDCR, ndcr | int_mask);
-}
-
-static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
-{
-	if (info->ecc_bch) {
-		u32 val;
-		int ret;
-
-		/*
-		 * According to the datasheet, when reading from NDDB
-		 * with BCH enabled, after each 32 bytes reads, we
-		 * have to make sure that the NDSR.RDDREQ bit is set.
-		 *
-		 * Drain the FIFO 8 32 bits reads at a time, and skip
-		 * the polling on the last read.
-		 */
-		while (len > 8) {
-			ioread32_rep(info->mmio_base + NDDB, data, 8);
-
-			ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
-							 val & NDSR_RDDREQ, 1000, 5000);
-			if (ret) {
-				dev_err(&info->pdev->dev,
-					"Timeout on RDDREQ while draining the FIFO\n");
-				return;
-			}
-
-			data += 32;
-			len -= 8;
-		}
-	}
-
-	ioread32_rep(info->mmio_base + NDDB, data, len);
-}
-
-static void handle_data_pio(struct pxa3xx_nand_info *info)
-{
-	switch (info->state) {
-	case STATE_PIO_WRITING:
-		if (info->step_chunk_size)
-			writesl(info->mmio_base + NDDB,
-				info->data_buff + info->data_buff_pos,
-				DIV_ROUND_UP(info->step_chunk_size, 4));
-
-		if (info->step_spare_size)
-			writesl(info->mmio_base + NDDB,
-				info->oob_buff + info->oob_buff_pos,
-				DIV_ROUND_UP(info->step_spare_size, 4));
-		break;
-	case STATE_PIO_READING:
-		if (info->step_chunk_size)
-			drain_fifo(info,
-				   info->data_buff + info->data_buff_pos,
-				   DIV_ROUND_UP(info->step_chunk_size, 4));
-
-		if (info->step_spare_size)
-			drain_fifo(info,
-				   info->oob_buff + info->oob_buff_pos,
-				   DIV_ROUND_UP(info->step_spare_size, 4));
-		break;
-	default:
-		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
-				info->state);
-		BUG();
-	}
-
-	/* Update buffer pointers for multi-page read/write */
-	info->data_buff_pos += info->step_chunk_size;
-	info->oob_buff_pos += info->step_spare_size;
-}
-
-static void pxa3xx_nand_data_dma_irq(void *data)
-{
-	struct pxa3xx_nand_info *info = data;
-	struct dma_tx_state state;
-	enum dma_status status;
-
-	status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
-	if (likely(status == DMA_COMPLETE)) {
-		info->state = STATE_DMA_DONE;
-	} else {
-		dev_err(&info->pdev->dev, "DMA error on data channel\n");
-		info->retcode = ERR_DMABUSERR;
-	}
-	dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
-
-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
-	enable_int(info, NDCR_INT_MASK);
-}
-
-static void start_data_dma(struct pxa3xx_nand_info *info)
-{
-	enum dma_transfer_direction direction;
-	struct dma_async_tx_descriptor *tx;
-
-	switch (info->state) {
-	case STATE_DMA_WRITING:
-		info->dma_dir = DMA_TO_DEVICE;
-		direction = DMA_MEM_TO_DEV;
-		break;
-	case STATE_DMA_READING:
-		info->dma_dir = DMA_FROM_DEVICE;
-		direction = DMA_DEV_TO_MEM;
-		break;
-	default:
-		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
-				info->state);
-		BUG();
-	}
-	info->sg.length = info->chunk_size;
-	if (info->use_spare)
-		info->sg.length += info->spare_size + info->ecc_size;
-	dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
-
-	tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
-				     DMA_PREP_INTERRUPT);
-	if (!tx) {
-		dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
-		return;
-	}
-	tx->callback = pxa3xx_nand_data_dma_irq;
-	tx->callback_param = info;
-	info->dma_cookie = dmaengine_submit(tx);
-	dma_async_issue_pending(info->dma_chan);
-	dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
-		__func__, direction, info->dma_cookie, info->sg.length);
-}
-
-static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
-{
-	struct pxa3xx_nand_info *info = data;
-
-	handle_data_pio(info);
-
-	info->state = STATE_CMD_DONE;
-	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
-{
-	struct pxa3xx_nand_info *info = devid;
-	unsigned int status, is_completed = 0, is_ready = 0;
-	unsigned int ready, cmd_done;
-	irqreturn_t ret = IRQ_HANDLED;
-
-	if (info->cs == 0) {
-		ready           = NDSR_FLASH_RDY;
-		cmd_done        = NDSR_CS0_CMDD;
-	} else {
-		ready           = NDSR_RDY;
-		cmd_done        = NDSR_CS1_CMDD;
-	}
-
-	status = nand_readl(info, NDSR);
-
-	if (status & NDSR_UNCORERR)
-		info->retcode = ERR_UNCORERR;
-	if (status & NDSR_CORERR) {
-		info->retcode = ERR_CORERR;
-		if ((info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		     info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) &&
-		    info->ecc_bch)
-			info->ecc_err_cnt = NDSR_ERR_CNT(status);
-		else
-			info->ecc_err_cnt = 1;
-
-		/*
-		 * Each chunk composing a page is corrected independently,
-		 * and we need to store maximum number of corrected bitflips
-		 * to return it to the MTD layer in ecc.read_page().
-		 */
-		info->max_bitflips = max_t(unsigned int,
-					   info->max_bitflips,
-					   info->ecc_err_cnt);
-	}
-	if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
-		/* whether use dma to transfer data */
-		if (info->use_dma) {
-			disable_int(info, NDCR_INT_MASK);
-			info->state = (status & NDSR_RDDREQ) ?
-				      STATE_DMA_READING : STATE_DMA_WRITING;
-			start_data_dma(info);
-			goto NORMAL_IRQ_EXIT;
-		} else {
-			info->state = (status & NDSR_RDDREQ) ?
-				      STATE_PIO_READING : STATE_PIO_WRITING;
-			ret = IRQ_WAKE_THREAD;
-			goto NORMAL_IRQ_EXIT;
-		}
-	}
-	if (status & cmd_done) {
-		info->state = STATE_CMD_DONE;
-		is_completed = 1;
-	}
-	if (status & ready) {
-		info->state = STATE_READY;
-		is_ready = 1;
-	}
-
-	/*
-	 * Clear all status bit before issuing the next command, which
-	 * can and will alter the status bits and will deserve a new
-	 * interrupt on its own. This lets the controller exit the IRQ
-	 */
-	nand_writel(info, NDSR, status);
-
-	if (status & NDSR_WRCMDREQ) {
-		status &= ~NDSR_WRCMDREQ;
-		info->state = STATE_CMD_HANDLE;
-
-		/*
-		 * Command buffer registers NDCB{0-2} (and optionally NDCB3)
-		 * must be loaded by writing directly either 12 or 16
-		 * bytes directly to NDCB0, four bytes at a time.
-		 *
-		 * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
-		 * but each NDCBx register can be read.
-		 */
-		nand_writel(info, NDCB0, info->ndcb0);
-		nand_writel(info, NDCB0, info->ndcb1);
-		nand_writel(info, NDCB0, info->ndcb2);
-
-		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
-			nand_writel(info, NDCB0, info->ndcb3);
-	}
-
-	if (is_completed)
-		complete(&info->cmd_complete);
-	if (is_ready)
-		complete(&info->dev_ready);
-NORMAL_IRQ_EXIT:
-	return ret;
-}
-
-static inline int is_buf_blank(uint8_t *buf, size_t len)
-{
-	for (; len > 0; len--)
-		if (*buf++ != 0xff)
-			return 0;
-	return 1;
-}
-
-static void set_command_address(struct pxa3xx_nand_info *info,
-		unsigned int page_size, uint16_t column, int page_addr)
-{
-	/* small page addr setting */
-	if (page_size < PAGE_CHUNK_SIZE) {
-		info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
-				| (column & 0xFF);
-
-		info->ndcb2 = 0;
-	} else {
-		info->ndcb1 = ((page_addr & 0xFFFF) << 16)
-				| (column & 0xFFFF);
-
-		if (page_addr & 0xFF0000)
-			info->ndcb2 = (page_addr & 0xFF0000) >> 16;
-		else
-			info->ndcb2 = 0;
-	}
-}
-
-static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
-{
-	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-
-	/* reset data and oob column point to handle data */
-	info->buf_start		= 0;
-	info->buf_count		= 0;
-	info->data_buff_pos	= 0;
-	info->oob_buff_pos	= 0;
-	info->step_chunk_size   = 0;
-	info->step_spare_size   = 0;
-	info->cur_chunk         = 0;
-	info->use_ecc		= 0;
-	info->use_spare		= 1;
-	info->retcode		= ERR_NONE;
-	info->ecc_err_cnt	= 0;
-	info->ndcb3		= 0;
-	info->need_wait		= 0;
-
-	switch (command) {
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-	case NAND_CMD_PAGEPROG:
-		info->use_ecc = 1;
-		break;
-	case NAND_CMD_PARAM:
-		info->use_spare = 0;
-		break;
-	default:
-		info->ndcb1 = 0;
-		info->ndcb2 = 0;
-		break;
-	}
-
-	/*
-	 * If we are about to issue a read command, or about to set
-	 * the write address, then clean the data buffer.
-	 */
-	if (command == NAND_CMD_READ0 ||
-	    command == NAND_CMD_READOOB ||
-	    command == NAND_CMD_SEQIN) {
-
-		info->buf_count = mtd->writesize + mtd->oobsize;
-		memset(info->data_buff, 0xFF, info->buf_count);
-	}
-
-}
-
-static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
-		int ext_cmd_type, uint16_t column, int page_addr)
-{
-	int addr_cycle, exec_cmd;
-	struct pxa3xx_nand_host *host;
-	struct mtd_info *mtd;
-
-	host = info->host[info->cs];
-	mtd = nand_to_mtd(&host->chip);
-	addr_cycle = 0;
-	exec_cmd = 1;
-
-	if (info->cs != 0)
-		info->ndcb0 = NDCB0_CSEL;
-	else
-		info->ndcb0 = 0;
-
-	if (command == NAND_CMD_SEQIN)
-		exec_cmd = 0;
-
-	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
-				    + host->col_addr_cycles);
-
-	switch (command) {
-	case NAND_CMD_READOOB:
-	case NAND_CMD_READ0:
-		info->buf_start = column;
-		info->ndcb0 |= NDCB0_CMD_TYPE(0)
-				| addr_cycle
-				| NAND_CMD_READ0;
-
-		if (command == NAND_CMD_READOOB)
-			info->buf_start += mtd->writesize;
-
-		if (info->cur_chunk < info->nfullchunks) {
-			info->step_chunk_size = info->chunk_size;
-			info->step_spare_size = info->spare_size;
-		} else {
-			info->step_chunk_size = info->last_chunk_size;
-			info->step_spare_size = info->last_spare_size;
-		}
-
-		/*
-		 * Multiple page read needs an 'extended command type' field,
-		 * which is either naked-read or last-read according to the
-		 * state.
-		 */
-		if (mtd->writesize == PAGE_CHUNK_SIZE) {
-			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
-		} else if (mtd->writesize > PAGE_CHUNK_SIZE) {
-			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
-					| NDCB0_LEN_OVRD
-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-			info->ndcb3 = info->step_chunk_size +
-				info->step_spare_size;
-		}
-
-		set_command_address(info, mtd->writesize, column, page_addr);
-		break;
-
-	case NAND_CMD_SEQIN:
-
-		info->buf_start = column;
-		set_command_address(info, mtd->writesize, 0, page_addr);
-
-		/*
-		 * Multiple page programming needs to execute the initial
-		 * SEQIN command that sets the page address.
-		 */
-		if (mtd->writesize > PAGE_CHUNK_SIZE) {
-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-				| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
-				| addr_cycle
-				| command;
-			exec_cmd = 1;
-		}
-		break;
-
-	case NAND_CMD_PAGEPROG:
-		if (is_buf_blank(info->data_buff,
-					(mtd->writesize + mtd->oobsize))) {
-			exec_cmd = 0;
-			break;
-		}
-
-		if (info->cur_chunk < info->nfullchunks) {
-			info->step_chunk_size = info->chunk_size;
-			info->step_spare_size = info->spare_size;
-		} else {
-			info->step_chunk_size = info->last_chunk_size;
-			info->step_spare_size = info->last_spare_size;
-		}
-
-		/* Second command setting for large pages */
-		if (mtd->writesize > PAGE_CHUNK_SIZE) {
-			/*
-			 * Multiple page write uses the 'extended command'
-			 * field. This can be used to issue a command dispatch
-			 * or a naked-write depending on the current stage.
-			 */
-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-					| NDCB0_LEN_OVRD
-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-			info->ndcb3 = info->step_chunk_size +
-				      info->step_spare_size;
-
-			/*
-			 * This is the command dispatch that completes a chunked
-			 * page program operation.
-			 */
-			if (info->cur_chunk == info->ntotalchunks) {
-				info->ndcb0 = NDCB0_CMD_TYPE(0x1)
-					| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
-					| command;
-				info->ndcb1 = 0;
-				info->ndcb2 = 0;
-				info->ndcb3 = 0;
-			}
-		} else {
-			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-					| NDCB0_AUTO_RS
-					| NDCB0_ST_ROW_EN
-					| NDCB0_DBC
-					| (NAND_CMD_PAGEPROG << 8)
-					| NAND_CMD_SEQIN
-					| addr_cycle;
-		}
-		break;
-
-	case NAND_CMD_PARAM:
-		info->buf_count = INIT_BUFFER_SIZE;
-		info->ndcb0 |= NDCB0_CMD_TYPE(0)
-				| NDCB0_ADDR_CYC(1)
-				| NDCB0_LEN_OVRD
-				| command;
-		info->ndcb1 = (column & 0xFF);
-		info->ndcb3 = INIT_BUFFER_SIZE;
-		info->step_chunk_size = INIT_BUFFER_SIZE;
-		break;
-
-	case NAND_CMD_READID:
-		info->buf_count = READ_ID_BYTES;
-		info->ndcb0 |= NDCB0_CMD_TYPE(3)
-				| NDCB0_ADDR_CYC(1)
-				| command;
-		info->ndcb1 = (column & 0xFF);
-
-		info->step_chunk_size = 8;
-		break;
-	case NAND_CMD_STATUS:
-		info->buf_count = 1;
-		info->ndcb0 |= NDCB0_CMD_TYPE(4)
-				| NDCB0_ADDR_CYC(1)
-				| command;
-
-		info->step_chunk_size = 8;
-		break;
-
-	case NAND_CMD_ERASE1:
-		info->ndcb0 |= NDCB0_CMD_TYPE(2)
-				| NDCB0_AUTO_RS
-				| NDCB0_ADDR_CYC(3)
-				| NDCB0_DBC
-				| (NAND_CMD_ERASE2 << 8)
-				| NAND_CMD_ERASE1;
-		info->ndcb1 = page_addr;
-		info->ndcb2 = 0;
-
-		break;
-	case NAND_CMD_RESET:
-		info->ndcb0 |= NDCB0_CMD_TYPE(5)
-				| command;
-
-		break;
-
-	case NAND_CMD_ERASE2:
-		exec_cmd = 0;
-		break;
-
-	default:
-		exec_cmd = 0;
-		dev_err(&info->pdev->dev, "non-supported command %x\n",
-				command);
-		break;
-	}
-
-	return exec_cmd;
-}
-
-static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
-			 int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	int exec_cmd;
-
-	/*
-	 * if this is a x16 device ,then convert the input
-	 * "byte" address into a "word" address appropriate
-	 * for indexing a word-oriented device
-	 */
-	if (info->reg_ndcr & NDCR_DWIDTH_M)
-		column /= 2;
-
-	/*
-	 * There may be different NAND chip hooked to
-	 * different chip select, so check whether
-	 * chip select has been changed, if yes, reset the timing
-	 */
-	if (info->cs != host->cs) {
-		info->cs = host->cs;
-		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
-		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
-	}
-
-	prepare_start_command(info, command);
-
-	info->state = STATE_PREPARED;
-	exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
-
-	if (exec_cmd) {
-		init_completion(&info->cmd_complete);
-		init_completion(&info->dev_ready);
-		info->need_wait = 1;
-		pxa3xx_nand_start(info);
-
-		if (!wait_for_completion_timeout(&info->cmd_complete,
-		    CHIP_DELAY_TIMEOUT)) {
-			dev_err(&info->pdev->dev, "Wait time out!!!\n");
-			/* Stop State Machine for next command cycle */
-			pxa3xx_nand_stop(info);
-		}
-	}
-	info->state = STATE_IDLE;
-}
-
-static void nand_cmdfunc_extended(struct mtd_info *mtd,
-				  const unsigned command,
-				  int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	int exec_cmd, ext_cmd_type;
-
-	/*
-	 * if this is a x16 device then convert the input
-	 * "byte" address into a "word" address appropriate
-	 * for indexing a word-oriented device
-	 */
-	if (info->reg_ndcr & NDCR_DWIDTH_M)
-		column /= 2;
-
-	/*
-	 * There may be different NAND chip hooked to
-	 * different chip select, so check whether
-	 * chip select has been changed, if yes, reset the timing
-	 */
-	if (info->cs != host->cs) {
-		info->cs = host->cs;
-		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
-		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
-	}
-
-	/* Select the extended command for the first command */
-	switch (command) {
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-		ext_cmd_type = EXT_CMD_TYPE_MONO;
-		break;
-	case NAND_CMD_SEQIN:
-		ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
-		break;
-	case NAND_CMD_PAGEPROG:
-		ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
-		break;
-	default:
-		ext_cmd_type = 0;
-		break;
-	}
-
-	prepare_start_command(info, command);
-
-	/*
-	 * Prepare the "is ready" completion before starting a command
-	 * transaction sequence. If the command is not executed the
-	 * completion will be completed, see below.
-	 *
-	 * We can do that inside the loop because the command variable
-	 * is invariant and thus so is the exec_cmd.
-	 */
-	info->need_wait = 1;
-	init_completion(&info->dev_ready);
-	do {
-		info->state = STATE_PREPARED;
-
-		exec_cmd = prepare_set_command(info, command, ext_cmd_type,
-					       column, page_addr);
-		if (!exec_cmd) {
-			info->need_wait = 0;
-			complete(&info->dev_ready);
-			break;
-		}
-
-		init_completion(&info->cmd_complete);
-		pxa3xx_nand_start(info);
-
-		if (!wait_for_completion_timeout(&info->cmd_complete,
-		    CHIP_DELAY_TIMEOUT)) {
-			dev_err(&info->pdev->dev, "Wait time out!!!\n");
-			/* Stop State Machine for next command cycle */
-			pxa3xx_nand_stop(info);
-			break;
-		}
-
-		/* Only a few commands need several steps */
-		if (command != NAND_CMD_PAGEPROG &&
-		    command != NAND_CMD_READ0    &&
-		    command != NAND_CMD_READOOB)
-			break;
-
-		info->cur_chunk++;
-
-		/* Check if the sequence is complete */
-		if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
-			break;
-
-		/*
-		 * After a splitted program command sequence has issued
-		 * the command dispatch, the command sequence is complete.
-		 */
-		if (info->cur_chunk == (info->ntotalchunks + 1) &&
-		    command == NAND_CMD_PAGEPROG &&
-		    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
-			break;
-
-		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
-			/* Last read: issue a 'last naked read' */
-			if (info->cur_chunk == info->ntotalchunks - 1)
-				ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
-			else
-				ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
-
-		/*
-		 * If a splitted program command has no more data to transfer,
-		 * the command dispatch must be issued to complete.
-		 */
-		} else if (command == NAND_CMD_PAGEPROG &&
-			   info->cur_chunk == info->ntotalchunks) {
-				ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
-		}
-	} while (1);
-
-	info->state = STATE_IDLE;
-}
-
-static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
-		struct nand_chip *chip, const uint8_t *buf, int oob_required,
-		int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
-		struct nand_chip *chip, uint8_t *buf, int oob_required,
-		int page)
-{
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	if (info->retcode == ERR_CORERR && info->use_ecc) {
-		mtd->ecc_stats.corrected += info->ecc_err_cnt;
-
-	} else if (info->retcode == ERR_UNCORERR) {
-		/*
-		 * for blank page (all 0xff), HW will calculate its ECC as
-		 * 0, which is different from the ECC information within
-		 * OOB, ignore such uncorrectable errors
-		 */
-		if (is_buf_blank(buf, mtd->writesize))
-			info->retcode = ERR_NONE;
-		else
-			mtd->ecc_stats.failed++;
-	}
-
-	return info->max_bitflips;
-}
-
-static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	char retval = 0xFF;
-
-	if (info->buf_start < info->buf_count)
-		/* Has just send a new command? */
-		retval = info->data_buff[info->buf_start++];
-
-	return retval;
-}
-
-static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	u16 retval = 0xFFFF;
-
-	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
-		retval = *((u16 *)(info->data_buff+info->buf_start));
-		info->buf_start += 2;
-	}
-	return retval;
-}
-
-static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
-
-	memcpy(buf, info->data_buff + info->buf_start, real_len);
-	info->buf_start += real_len;
-}
-
-static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
-		const uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
-
-	memcpy(info->data_buff + info->buf_start, buf, real_len);
-	info->buf_start += real_len;
-}
-
-static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
-{
-	return;
-}
-
-static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-
-	if (info->need_wait) {
-		info->need_wait = 0;
-		if (!wait_for_completion_timeout(&info->dev_ready,
-		    CHIP_DELAY_TIMEOUT)) {
-			dev_err(&info->pdev->dev, "Ready time out!!!\n");
-			return NAND_STATUS_FAIL;
-		}
-	}
-
-	/* pxa3xx_nand_send_command has waited for command complete */
-	if (this->state == FL_WRITING || this->state == FL_ERASING) {
-		if (info->retcode == ERR_NONE)
-			return 0;
-		else
-			return NAND_STATUS_FAIL;
-	}
-
-	return NAND_STATUS_READY;
-}
-
-static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
-{
-	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	const struct nand_sdr_timings *timings;
-
-	/* Configure default flash values */
-	info->chunk_size = PAGE_CHUNK_SIZE;
-	info->reg_ndcr = 0x0; /* enable all interrupts */
-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
-	info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
-	info->reg_ndcr |= NDCR_SPARE_EN;
-
-	/* use the common timing to make a try */
-	timings = onfi_async_timing_mode_to_sdr_timings(0);
-	if (IS_ERR(timings))
-		return PTR_ERR(timings);
-
-	pxa3xx_nand_set_sdr_timing(host, timings);
-	return 0;
-}
-
-static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info)
-{
-	struct pxa3xx_nand_host *host = info->host[info->cs];
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
-	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
-	info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
-}
-
-static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
-{
-	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	uint32_t ndcr = nand_readl(info, NDCR);
-
-	/* Set an initial chunk size */
-	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
-	info->reg_ndcr = ndcr &
-		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
-	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
-	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
-	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
-}
-
-static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
-{
-	struct platform_device *pdev = info->pdev;
-	struct dma_slave_config	config;
-	dma_cap_mask_t mask;
-	struct pxad_param param;
-	int ret;
-
-	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-	if (info->data_buff == NULL)
-		return -ENOMEM;
-	if (use_dma == 0)
-		return 0;
-
-	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	sg_init_one(&info->sg, info->data_buff, info->buf_size);
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-	param.prio = PXAD_PRIO_LOWEST;
-	param.drcmr = info->drcmr_dat;
-	info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
-							  &param, &pdev->dev,
-							  "data");
-	if (!info->dma_chan) {
-		dev_err(&pdev->dev, "unable to request data dma channel\n");
-		return -ENODEV;
-	}
-
-	memset(&config, 0, sizeof(config));
-	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.src_addr = info->mmio_phys + NDDB;
-	config.dst_addr = info->mmio_phys + NDDB;
-	config.src_maxburst = 32;
-	config.dst_maxburst = 32;
-	ret = dmaengine_slave_config(info->dma_chan, &config);
-	if (ret < 0) {
-		dev_err(&info->pdev->dev,
-			"dma channel configuration failed: %d\n",
-			ret);
-		return ret;
-	}
-
-	/*
-	 * Now that DMA buffers are allocated we turn on
-	 * DMA proper for I/O operations.
-	 */
-	info->use_dma = 1;
-	return 0;
-}
-
-static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
-{
-	if (info->use_dma) {
-		dmaengine_terminate_all(info->dma_chan);
-		dma_release_channel(info->dma_chan);
-	}
-	kfree(info->data_buff);
-}
-
-static int pxa_ecc_init(struct pxa3xx_nand_info *info,
-			struct mtd_info *mtd,
-			int strength, int ecc_stepsize, int page_size)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
-		info->nfullchunks = 1;
-		info->ntotalchunks = 1;
-		info->chunk_size = 2048;
-		info->spare_size = 40;
-		info->ecc_size = 24;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = 512;
-		ecc->strength = 1;
-
-	} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
-		info->nfullchunks = 1;
-		info->ntotalchunks = 1;
-		info->chunk_size = 512;
-		info->spare_size = 8;
-		info->ecc_size = 8;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = 512;
-		ecc->strength = 1;
-
-	/*
-	 * Required ECC: 4-bit correction per 512 bytes
-	 * Select: 16-bit correction per 2048 bytes
-	 */
-	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
-		info->ecc_bch = 1;
-		info->nfullchunks = 1;
-		info->ntotalchunks = 1;
-		info->chunk_size = 2048;
-		info->spare_size = 32;
-		info->ecc_size = 32;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = info->chunk_size;
-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
-		ecc->strength = 16;
-
-	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
-		info->ecc_bch = 1;
-		info->nfullchunks = 2;
-		info->ntotalchunks = 2;
-		info->chunk_size = 2048;
-		info->spare_size = 32;
-		info->ecc_size = 32;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = info->chunk_size;
-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
-		ecc->strength = 16;
-
-	/*
-	 * Required ECC: 8-bit correction per 512 bytes
-	 * Select: 16-bit correction per 1024 bytes
-	 */
-	} else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
-		info->ecc_bch = 1;
-		info->nfullchunks = 4;
-		info->ntotalchunks = 5;
-		info->chunk_size = 1024;
-		info->spare_size = 0;
-		info->last_chunk_size = 0;
-		info->last_spare_size = 64;
-		info->ecc_size = 32;
-		ecc->mode = NAND_ECC_HW;
-		ecc->size = info->chunk_size;
-		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
-		ecc->strength = 16;
-	} else {
-		dev_err(&info->pdev->dev,
-			"ECC strength %d at page size %d is not supported\n",
-			strength, page_size);
-		return -ENODEV;
-	}
-
-	dev_info(&info->pdev->dev, "ECC strength %d, ECC step size %d\n",
-		 ecc->strength, ecc->size);
-	return 0;
-}
-
-static int pxa3xx_nand_scan(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
-	struct pxa3xx_nand_info *info = host->info_data;
-	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	int ret;
-	uint16_t ecc_strength, ecc_step;
-
-	if (pdata->keep_config) {
-		pxa3xx_nand_detect_config(info);
-	} else {
-		ret = pxa3xx_nand_config_ident(info);
-		if (ret)
-			return ret;
-	}
-
-	if (info->reg_ndcr & NDCR_DWIDTH_M)
-		chip->options |= NAND_BUSWIDTH_16;
-
-	/* Device detection must be done with ECC disabled */
-	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-	    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
-		nand_writel(info, NDECCCTRL, 0x0);
-
-	if (pdata->flash_bbt)
-		chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-	chip->ecc.strength = pdata->ecc_strength;
-	chip->ecc.size = pdata->ecc_step_size;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		return ret;
-
-	if (!pdata->keep_config) {
-		ret = pxa3xx_nand_init(host);
-		if (ret) {
-			dev_err(&info->pdev->dev, "Failed to init nand: %d\n",
-				ret);
-			return ret;
-		}
-	}
-
-	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-		/*
-		 * We'll use a bad block table stored in-flash and don't
-		 * allow writing the bad block marker to the flash.
-		 */
-		chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
-		chip->bbt_td = &bbt_main_descr;
-		chip->bbt_md = &bbt_mirror_descr;
-	}
-
-	/*
-	 * If the page size is bigger than the FIFO size, let's check
-	 * we are given the right variant and then switch to the extended
-	 * (aka splitted) command handling,
-	 */
-	if (mtd->writesize > PAGE_CHUNK_SIZE) {
-		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) {
-			chip->cmdfunc = nand_cmdfunc_extended;
-		} else {
-			dev_err(&info->pdev->dev,
-				"unsupported page size on this variant\n");
-			return -ENODEV;
-		}
-	}
-
-	ecc_strength = chip->ecc.strength;
-	ecc_step = chip->ecc.size;
-	if (!ecc_strength || !ecc_step) {
-		ecc_strength = chip->ecc_strength_ds;
-		ecc_step = chip->ecc_step_ds;
-	}
-
-	/* Set default ECC strength requirements on non-ONFI devices */
-	if (ecc_strength < 1 && ecc_step < 1) {
-		ecc_strength = 1;
-		ecc_step = 512;
-	}
-
-	ret = pxa_ecc_init(info, mtd, ecc_strength,
-			   ecc_step, mtd->writesize);
-	if (ret)
-		return ret;
-
-	/* calculate addressing information */
-	if (mtd->writesize >= 2048)
-		host->col_addr_cycles = 2;
-	else
-		host->col_addr_cycles = 1;
-
-	/* release the initial buffer */
-	kfree(info->data_buff);
-
-	/* allocate the real data + oob buffer */
-	info->buf_size = mtd->writesize + mtd->oobsize;
-	ret = pxa3xx_nand_init_buff(info);
-	if (ret)
-		return ret;
-	info->oob_buff = info->data_buff + mtd->writesize;
-
-	if ((mtd->size >> chip->page_shift) > 65536)
-		host->row_addr_cycles = 3;
-	else
-		host->row_addr_cycles = 2;
-
-	if (!pdata->keep_config)
-		pxa3xx_nand_config_tail(info);
-
-	return nand_scan_tail(mtd);
-}
-
-static int alloc_nand_resource(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct pxa3xx_nand_platform_data *pdata;
-	struct pxa3xx_nand_info *info;
-	struct pxa3xx_nand_host *host;
-	struct nand_chip *chip = NULL;
-	struct mtd_info *mtd;
-	struct resource *r;
-	int ret, irq, cs;
-
-	pdata = dev_get_platdata(&pdev->dev);
-	if (pdata->num_cs <= 0) {
-		dev_err(&pdev->dev, "invalid number of chip selects\n");
-		return -ENODEV;
-	}
-
-	info = devm_kzalloc(&pdev->dev,
-			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
-			    GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	info->pdev = pdev;
-	info->variant = pxa3xx_nand_get_variant(pdev);
-	for (cs = 0; cs < pdata->num_cs; cs++) {
-		host = (void *)&info[1] + sizeof(*host) * cs;
-		chip = &host->chip;
-		nand_set_controller_data(chip, host);
-		mtd = nand_to_mtd(chip);
-		info->host[cs] = host;
-		host->cs = cs;
-		host->info_data = info;
-		mtd->dev.parent = &pdev->dev;
-		/* FIXME: all chips use the same device tree partitions */
-		nand_set_flash_node(chip, np);
-
-		nand_set_controller_data(chip, host);
-		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc;
-		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc;
-		chip->controller        = &info->controller;
-		chip->waitfunc		= pxa3xx_nand_waitfunc;
-		chip->select_chip	= pxa3xx_nand_select_chip;
-		chip->read_word		= pxa3xx_nand_read_word;
-		chip->read_byte		= pxa3xx_nand_read_byte;
-		chip->read_buf		= pxa3xx_nand_read_buf;
-		chip->write_buf		= pxa3xx_nand_write_buf;
-		chip->options		|= NAND_NO_SUBPAGE_WRITE;
-		chip->cmdfunc		= nand_cmdfunc;
-		chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
-		chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
-	}
-
-	nand_hw_control_init(chip->controller);
-	info->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(info->clk)) {
-		ret = PTR_ERR(info->clk);
-		dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
-		return ret;
-	}
-	ret = clk_prepare_enable(info->clk);
-	if (ret < 0)
-		return ret;
-
-	if (!np && use_dma) {
-		r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-		if (r == NULL) {
-			dev_err(&pdev->dev,
-				"no resource defined for data DMA\n");
-			ret = -ENXIO;
-			goto fail_disable_clk;
-		}
-		info->drcmr_dat = r->start;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "no IRQ resource defined\n");
-		ret = -ENXIO;
-		goto fail_disable_clk;
-	}
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
-	if (IS_ERR(info->mmio_base)) {
-		ret = PTR_ERR(info->mmio_base);
-		dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
-		goto fail_disable_clk;
-	}
-	info->mmio_phys = r->start;
-
-	/* Allocate a buffer to allow flash detection */
-	info->buf_size = INIT_BUFFER_SIZE;
-	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-	if (info->data_buff == NULL) {
-		ret = -ENOMEM;
-		goto fail_disable_clk;
-	}
-
-	/* initialize all interrupts to be disabled */
-	disable_int(info, NDSR_MASK);
-
-	ret = request_threaded_irq(irq, pxa3xx_nand_irq,
-				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
-				   pdev->name, info);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
-		goto fail_free_buf;
-	}
-
-	platform_set_drvdata(pdev, info);
-
-	return 0;
-
-fail_free_buf:
-	free_irq(irq, info);
-	kfree(info->data_buff);
-fail_disable_clk:
-	clk_disable_unprepare(info->clk);
-	return ret;
-}
-
-static int pxa3xx_nand_remove(struct platform_device *pdev)
-{
-	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
-	struct pxa3xx_nand_platform_data *pdata;
-	int irq, cs;
-
-	if (!info)
-		return 0;
-
-	pdata = dev_get_platdata(&pdev->dev);
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq >= 0)
-		free_irq(irq, info);
-	pxa3xx_nand_free_buff(info);
-
-	/*
-	 * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
-	 * In order to prevent a lockup of the system bus, the DFI bus
-	 * arbitration is granted to SMC upon driver removal. This is done by
-	 * setting the x_ARB_CNTL bit, which also prevents the NAND to have
-	 * access to the bus anymore.
-	 */
-	nand_writel(info, NDCR,
-		    (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
-		    NFCV1_NDCR_ARB_CNTL);
-	clk_disable_unprepare(info->clk);
-
-	for (cs = 0; cs < pdata->num_cs; cs++)
-		nand_release(nand_to_mtd(&info->host[cs]->chip));
-	return 0;
-}
-
-static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
-{
-	struct pxa3xx_nand_platform_data *pdata;
-	struct device_node *np = pdev->dev.of_node;
-	const struct of_device_id *of_id =
-			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
-
-	if (!of_id)
-		return 0;
-
-	/*
-	 * Some SoCs like A7k/A8k need to enable manually the NAND
-	 * controller to avoid being bootloader dependent. This is done
-	 * through the use of a single bit in the System Functions registers.
-	 */
-	if (pxa3xx_nand_get_variant(pdev) == PXA3XX_NAND_VARIANT_ARMADA_8K) {
-		struct regmap *sysctrl_base = syscon_regmap_lookup_by_phandle(
-			pdev->dev.of_node, "marvell,system-controller");
-		u32 reg;
-
-		if (IS_ERR(sysctrl_base))
-			return PTR_ERR(sysctrl_base);
-
-		regmap_read(sysctrl_base, GENCONF_SOC_DEVICE_MUX, &reg);
-		reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN;
-		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
-	}
-
-	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return -ENOMEM;
-
-	if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
-		pdata->enable_arbiter = 1;
-	if (of_get_property(np, "marvell,nand-keep-config", NULL))
-		pdata->keep_config = 1;
-	of_property_read_u32(np, "num-cs", &pdata->num_cs);
-
-	pdev->dev.platform_data = pdata;
-
-	return 0;
-}
-
-static int pxa3xx_nand_probe(struct platform_device *pdev)
-{
-	struct pxa3xx_nand_platform_data *pdata;
-	struct pxa3xx_nand_info *info;
-	int ret, cs, probe_success, dma_available;
-
-	dma_available = IS_ENABLED(CONFIG_ARM) &&
-		(IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
-	if (use_dma && !dma_available) {
-		use_dma = 0;
-		dev_warn(&pdev->dev,
-			 "This platform can't do DMA on this device\n");
-	}
-
-	ret = pxa3xx_nand_probe_dt(pdev);
-	if (ret)
-		return ret;
-
-	pdata = dev_get_platdata(&pdev->dev);
-	if (!pdata) {
-		dev_err(&pdev->dev, "no platform data defined\n");
-		return -ENODEV;
-	}
-
-	ret = alloc_nand_resource(pdev);
-	if (ret)
-		return ret;
-
-	info = platform_get_drvdata(pdev);
-	probe_success = 0;
-	for (cs = 0; cs < pdata->num_cs; cs++) {
-		struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
-
-		/*
-		 * The mtd name matches the one used in 'mtdparts' kernel
-		 * parameter. This name cannot be changed or otherwise
-		 * user's mtd partitions configuration would get broken.
-		 */
-		mtd->name = "pxa3xx_nand-0";
-		info->cs = cs;
-		ret = pxa3xx_nand_scan(mtd);
-		if (ret) {
-			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
-				cs);
-			continue;
-		}
-
-		ret = mtd_device_register(mtd, pdata->parts[cs],
-					  pdata->nr_parts[cs]);
-		if (!ret)
-			probe_success = 1;
-	}
-
-	if (!probe_success) {
-		pxa3xx_nand_remove(pdev);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pxa3xx_nand_suspend(struct device *dev)
-{
-	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
-
-	if (info->state) {
-		dev_err(dev, "driver busy, state = %d\n", info->state);
-		return -EAGAIN;
-	}
-
-	clk_disable(info->clk);
-	return 0;
-}
-
-static int pxa3xx_nand_resume(struct device *dev)
-{
-	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
-	int ret;
-
-	ret = clk_enable(info->clk);
-	if (ret < 0)
-		return ret;
-
-	/* We don't want to handle interrupt without calling mtd routine */
-	disable_int(info, NDCR_INT_MASK);
-
-	/*
-	 * Directly set the chip select to a invalid value,
-	 * then the driver would reset the timing according
-	 * to current chip select at the beginning of cmdfunc
-	 */
-	info->cs = 0xff;
-
-	/*
-	 * As the spec says, the NDSR would be updated to 0x1800 when
-	 * doing the nand_clk disable/enable.
-	 * To prevent it damaging state machine of the driver, clear
-	 * all status before resume
-	 */
-	nand_writel(info, NDSR, NDSR_MASK);
-
-	return 0;
-}
-#else
-#define pxa3xx_nand_suspend	NULL
-#define pxa3xx_nand_resume	NULL
-#endif
-
-static const struct dev_pm_ops pxa3xx_nand_pm_ops = {
-	.suspend	= pxa3xx_nand_suspend,
-	.resume		= pxa3xx_nand_resume,
-};
-
-static struct platform_driver pxa3xx_nand_driver = {
-	.driver = {
-		.name	= "pxa3xx-nand",
-		.of_match_table = pxa3xx_nand_dt_ids,
-		.pm	= &pxa3xx_nand_pm_ops,
-	},
-	.probe		= pxa3xx_nand_probe,
-	.remove		= pxa3xx_nand_remove,
-};
-
-module_platform_driver(pxa3xx_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("PXA3xx NAND controller driver");
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
deleted file mode 100644
index 563b759ffca6..000000000000
--- a/drivers/mtd/nand/qcom_nandc.c
+++ /dev/null
@@ -1,2921 +0,0 @@
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/clk.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/module.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/delay.h>
-#include <linux/dma/qcom_bam_dma.h>
-#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
-
-/* NANDc reg offsets */
-#define	NAND_FLASH_CMD			0x00
-#define	NAND_ADDR0			0x04
-#define	NAND_ADDR1			0x08
-#define	NAND_FLASH_CHIP_SELECT		0x0c
-#define	NAND_EXEC_CMD			0x10
-#define	NAND_FLASH_STATUS		0x14
-#define	NAND_BUFFER_STATUS		0x18
-#define	NAND_DEV0_CFG0			0x20
-#define	NAND_DEV0_CFG1			0x24
-#define	NAND_DEV0_ECC_CFG		0x28
-#define	NAND_DEV1_ECC_CFG		0x2c
-#define	NAND_DEV1_CFG0			0x30
-#define	NAND_DEV1_CFG1			0x34
-#define	NAND_READ_ID			0x40
-#define	NAND_READ_STATUS		0x44
-#define	NAND_DEV_CMD0			0xa0
-#define	NAND_DEV_CMD1			0xa4
-#define	NAND_DEV_CMD2			0xa8
-#define	NAND_DEV_CMD_VLD		0xac
-#define	SFLASHC_BURST_CFG		0xe0
-#define	NAND_ERASED_CW_DETECT_CFG	0xe8
-#define	NAND_ERASED_CW_DETECT_STATUS	0xec
-#define	NAND_EBI2_ECC_BUF_CFG		0xf0
-#define	FLASH_BUF_ACC			0x100
-
-#define	NAND_CTRL			0xf00
-#define	NAND_VERSION			0xf08
-#define	NAND_READ_LOCATION_0		0xf20
-#define	NAND_READ_LOCATION_1		0xf24
-#define	NAND_READ_LOCATION_2		0xf28
-#define	NAND_READ_LOCATION_3		0xf2c
-
-/* dummy register offsets, used by write_reg_dma */
-#define	NAND_DEV_CMD1_RESTORE		0xdead
-#define	NAND_DEV_CMD_VLD_RESTORE	0xbeef
-
-/* NAND_FLASH_CMD bits */
-#define	PAGE_ACC			BIT(4)
-#define	LAST_PAGE			BIT(5)
-
-/* NAND_FLASH_CHIP_SELECT bits */
-#define	NAND_DEV_SEL			0
-#define	DM_EN				BIT(2)
-
-/* NAND_FLASH_STATUS bits */
-#define	FS_OP_ERR			BIT(4)
-#define	FS_READY_BSY_N			BIT(5)
-#define	FS_MPU_ERR			BIT(8)
-#define	FS_DEVICE_STS_ERR		BIT(16)
-#define	FS_DEVICE_WP			BIT(23)
-
-/* NAND_BUFFER_STATUS bits */
-#define	BS_UNCORRECTABLE_BIT		BIT(8)
-#define	BS_CORRECTABLE_ERR_MSK		0x1f
-
-/* NAND_DEVn_CFG0 bits */
-#define	DISABLE_STATUS_AFTER_WRITE	4
-#define	CW_PER_PAGE			6
-#define	UD_SIZE_BYTES			9
-#define	ECC_PARITY_SIZE_BYTES_RS	19
-#define	SPARE_SIZE_BYTES		23
-#define	NUM_ADDR_CYCLES			27
-#define	STATUS_BFR_READ			30
-#define	SET_RD_MODE_AFTER_STATUS	31
-
-/* NAND_DEVn_CFG0 bits */
-#define	DEV0_CFG1_ECC_DISABLE		0
-#define	WIDE_FLASH			1
-#define	NAND_RECOVERY_CYCLES		2
-#define	CS_ACTIVE_BSY			5
-#define	BAD_BLOCK_BYTE_NUM		6
-#define	BAD_BLOCK_IN_SPARE_AREA		16
-#define	WR_RD_BSY_GAP			17
-#define	ENABLE_BCH_ECC			27
-
-/* NAND_DEV0_ECC_CFG bits */
-#define	ECC_CFG_ECC_DISABLE		0
-#define	ECC_SW_RESET			1
-#define	ECC_MODE			4
-#define	ECC_PARITY_SIZE_BYTES_BCH	8
-#define	ECC_NUM_DATA_BYTES		16
-#define	ECC_FORCE_CLK_OPEN		30
-
-/* NAND_DEV_CMD1 bits */
-#define	READ_ADDR			0
-
-/* NAND_DEV_CMD_VLD bits */
-#define	READ_START_VLD			BIT(0)
-#define	READ_STOP_VLD			BIT(1)
-#define	WRITE_START_VLD			BIT(2)
-#define	ERASE_START_VLD			BIT(3)
-#define	SEQ_READ_START_VLD		BIT(4)
-
-/* NAND_EBI2_ECC_BUF_CFG bits */
-#define	NUM_STEPS			0
-
-/* NAND_ERASED_CW_DETECT_CFG bits */
-#define	ERASED_CW_ECC_MASK		1
-#define	AUTO_DETECT_RES			0
-#define	MASK_ECC			(1 << ERASED_CW_ECC_MASK)
-#define	RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
-#define	ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
-#define	CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
-#define	SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
-
-/* NAND_ERASED_CW_DETECT_STATUS bits */
-#define	PAGE_ALL_ERASED			BIT(7)
-#define	CODEWORD_ALL_ERASED		BIT(6)
-#define	PAGE_ERASED			BIT(5)
-#define	CODEWORD_ERASED			BIT(4)
-#define	ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
-#define	ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
-
-/* NAND_READ_LOCATION_n bits */
-#define READ_LOCATION_OFFSET		0
-#define READ_LOCATION_SIZE		16
-#define READ_LOCATION_LAST		31
-
-/* Version Mask */
-#define	NAND_VERSION_MAJOR_MASK		0xf0000000
-#define	NAND_VERSION_MAJOR_SHIFT	28
-#define	NAND_VERSION_MINOR_MASK		0x0fff0000
-#define	NAND_VERSION_MINOR_SHIFT	16
-
-/* NAND OP_CMDs */
-#define	PAGE_READ			0x2
-#define	PAGE_READ_WITH_ECC		0x3
-#define	PAGE_READ_WITH_ECC_SPARE	0x4
-#define	PROGRAM_PAGE			0x6
-#define	PAGE_PROGRAM_WITH_ECC		0x7
-#define	PROGRAM_PAGE_SPARE		0x9
-#define	BLOCK_ERASE			0xa
-#define	FETCH_ID			0xb
-#define	RESET_DEVICE			0xd
-
-/* Default Value for NAND_DEV_CMD_VLD */
-#define NAND_DEV_CMD_VLD_VAL		(READ_START_VLD | WRITE_START_VLD | \
-					 ERASE_START_VLD | SEQ_READ_START_VLD)
-
-/* NAND_CTRL bits */
-#define	BAM_MODE_EN			BIT(0)
-
-/*
- * the NAND controller performs reads/writes with ECC in 516 byte chunks.
- * the driver calls the chunks 'step' or 'codeword' interchangeably
- */
-#define	NANDC_STEP_SIZE			512
-
-/*
- * the largest page size we support is 8K, this will have 16 steps/codewords
- * of 512 bytes each
- */
-#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)
-
-/* we read at most 3 registers per codeword scan */
-#define	MAX_REG_RD			(3 * MAX_NUM_STEPS)
-
-/* ECC modes supported by the controller */
-#define	ECC_NONE	BIT(0)
-#define	ECC_RS_4BIT	BIT(1)
-#define	ECC_BCH_4BIT	BIT(2)
-#define	ECC_BCH_8BIT	BIT(3)
-
-#define nandc_set_read_loc(nandc, reg, offset, size, is_last)	\
-nandc_set_reg(nandc, NAND_READ_LOCATION_##reg,			\
-	      ((offset) << READ_LOCATION_OFFSET) |		\
-	      ((size) << READ_LOCATION_SIZE) |			\
-	      ((is_last) << READ_LOCATION_LAST))
-
-/*
- * Returns the actual register address for all NAND_DEV_ registers
- * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
- */
-#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
-
-/* Returns the NAND register physical address */
-#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
-
-/* Returns the dma address for reg read buffer */
-#define reg_buf_dma_addr(chip, vaddr) \
-	((chip)->reg_read_dma + \
-	((uint8_t *)(vaddr) - (uint8_t *)(chip)->reg_read_buf))
-
-#define QPIC_PER_CW_CMD_ELEMENTS	32
-#define QPIC_PER_CW_CMD_SGL		32
-#define QPIC_PER_CW_DATA_SGL		8
-
-/*
- * Flags used in DMA descriptor preparation helper functions
- * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
- */
-/* Don't set the EOT in current tx BAM sgl */
-#define NAND_BAM_NO_EOT			BIT(0)
-/* Set the NWD flag in current BAM sgl */
-#define NAND_BAM_NWD			BIT(1)
-/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
-#define NAND_BAM_NEXT_SGL		BIT(2)
-/*
- * Erased codeword status is being used two times in single transfer so this
- * flag will determine the current value of erased codeword status register
- */
-#define NAND_ERASED_CW_SET		BIT(4)
-
-/*
- * This data type corresponds to the BAM transaction which will be used for all
- * NAND transfers.
- * @bam_ce - the array of BAM command elements
- * @cmd_sgl - sgl for NAND BAM command pipe
- * @data_sgl - sgl for NAND BAM consumer/producer pipe
- * @bam_ce_pos - the index in bam_ce which is available for next sgl
- * @bam_ce_start - the index in bam_ce which marks the start position ce
- *		   for current sgl. It will be used for size calculation
- *		   for current sgl
- * @cmd_sgl_pos - current index in command sgl.
- * @cmd_sgl_start - start index in command sgl.
- * @tx_sgl_pos - current index in data sgl for tx.
- * @tx_sgl_start - start index in data sgl for tx.
- * @rx_sgl_pos - current index in data sgl for rx.
- * @rx_sgl_start - start index in data sgl for rx.
- */
-struct bam_transaction {
-	struct bam_cmd_element *bam_ce;
-	struct scatterlist *cmd_sgl;
-	struct scatterlist *data_sgl;
-	u32 bam_ce_pos;
-	u32 bam_ce_start;
-	u32 cmd_sgl_pos;
-	u32 cmd_sgl_start;
-	u32 tx_sgl_pos;
-	u32 tx_sgl_start;
-	u32 rx_sgl_pos;
-	u32 rx_sgl_start;
-};
-
-/*
- * This data type corresponds to the nand dma descriptor
- * @list - list for desc_info
- * @dir - DMA transfer direction
- * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
- *	      ADM
- * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
- * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
- * @dma_desc - low level DMA engine descriptor
- */
-struct desc_info {
-	struct list_head node;
-
-	enum dma_data_direction dir;
-	union {
-		struct scatterlist adm_sgl;
-		struct {
-			struct scatterlist *bam_sgl;
-			int sgl_cnt;
-		};
-	};
-	struct dma_async_tx_descriptor *dma_desc;
-};
-
-/*
- * holds the current register values that we want to write. acts as a contiguous
- * chunk of memory which we use to write the controller registers through DMA.
- */
-struct nandc_regs {
-	__le32 cmd;
-	__le32 addr0;
-	__le32 addr1;
-	__le32 chip_sel;
-	__le32 exec;
-
-	__le32 cfg0;
-	__le32 cfg1;
-	__le32 ecc_bch_cfg;
-
-	__le32 clrflashstatus;
-	__le32 clrreadstatus;
-
-	__le32 cmd1;
-	__le32 vld;
-
-	__le32 orig_cmd1;
-	__le32 orig_vld;
-
-	__le32 ecc_buf_cfg;
-	__le32 read_location0;
-	__le32 read_location1;
-	__le32 read_location2;
-	__le32 read_location3;
-
-	__le32 erased_cw_detect_cfg_clr;
-	__le32 erased_cw_detect_cfg_set;
-};
-
-/*
- * NAND controller data struct
- *
- * @controller:			base controller structure
- * @host_list:			list containing all the chips attached to the
- *				controller
- * @dev:			parent device
- * @base:			MMIO base
- * @base_phys:			physical base address of controller registers
- * @base_dma:			dma base address of controller registers
- * @core_clk:			controller clock
- * @aon_clk:			another controller clock
- *
- * @chan:			dma channel
- * @cmd_crci:			ADM DMA CRCI for command flow control
- * @data_crci:			ADM DMA CRCI for data flow control
- * @desc_list:			DMA descriptor list (list of desc_infos)
- *
- * @data_buffer:		our local DMA buffer for page read/writes,
- *				used when we can't use the buffer provided
- *				by upper layers directly
- * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
- * @reg_read_buf:		local buffer for reading back registers via DMA
- * @reg_read_dma:		contains dma address for register read buffer
- * @reg_read_pos:		marker for data read in reg_read_buf
- *
- * @regs:			a contiguous chunk of memory for DMA register
- *				writes. contains the register values to be
- *				written to controller
- * @cmd1/vld:			some fixed controller register values
- * @props:			properties of current NAND controller,
- *				initialized via DT match data
- * @max_cwperpage:		maximum QPIC codewords required. calculated
- *				from all connected NAND devices pagesize
- */
-struct qcom_nand_controller {
-	struct nand_hw_control controller;
-	struct list_head host_list;
-
-	struct device *dev;
-
-	void __iomem *base;
-	phys_addr_t base_phys;
-	dma_addr_t base_dma;
-
-	struct clk *core_clk;
-	struct clk *aon_clk;
-
-	union {
-		/* will be used only by QPIC for BAM DMA */
-		struct {
-			struct dma_chan *tx_chan;
-			struct dma_chan *rx_chan;
-			struct dma_chan *cmd_chan;
-		};
-
-		/* will be used only by EBI2 for ADM DMA */
-		struct {
-			struct dma_chan *chan;
-			unsigned int cmd_crci;
-			unsigned int data_crci;
-		};
-	};
-
-	struct list_head desc_list;
-	struct bam_transaction *bam_txn;
-
-	u8		*data_buffer;
-	int		buf_size;
-	int		buf_count;
-	int		buf_start;
-	unsigned int	max_cwperpage;
-
-	__le32 *reg_read_buf;
-	dma_addr_t reg_read_dma;
-	int reg_read_pos;
-
-	struct nandc_regs *regs;
-
-	u32 cmd1, vld;
-	const struct qcom_nandc_props *props;
-};
-
-/*
- * NAND chip structure
- *
- * @chip:			base NAND chip structure
- * @node:			list node to add itself to host_list in
- *				qcom_nand_controller
- *
- * @cs:				chip select value for this chip
- * @cw_size:			the number of bytes in a single step/codeword
- *				of a page, consisting of all data, ecc, spare
- *				and reserved bytes
- * @cw_data:			the number of bytes within a codeword protected
- *				by ECC
- * @use_ecc:			request the controller to use ECC for the
- *				upcoming read/write
- * @bch_enabled:		flag to tell whether BCH ECC mode is used
- * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
- *				chip
- * @status:			value to be returned if NAND_CMD_STATUS command
- *				is executed
- * @last_command:		keeps track of last command on this chip. used
- *				for reading correct status
- *
- * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
- *				ecc/non-ecc mode for the current nand flash
- *				device
- */
-struct qcom_nand_host {
-	struct nand_chip chip;
-	struct list_head node;
-
-	int cs;
-	int cw_size;
-	int cw_data;
-	bool use_ecc;
-	bool bch_enabled;
-	int ecc_bytes_hw;
-	int spare_bytes;
-	int bbm_size;
-	u8 status;
-	int last_command;
-
-	u32 cfg0, cfg1;
-	u32 cfg0_raw, cfg1_raw;
-	u32 ecc_buf_cfg;
-	u32 ecc_bch_cfg;
-	u32 clrflashstatus;
-	u32 clrreadstatus;
-};
-
-/*
- * This data type corresponds to the NAND controller properties which varies
- * among different NAND controllers.
- * @ecc_modes - ecc mode for NAND
- * @is_bam - whether NAND controller is using BAM
- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
- */
-struct qcom_nandc_props {
-	u32 ecc_modes;
-	bool is_bam;
-	u32 dev_cmd_reg_start;
-};
-
-/* Frees the BAM transaction memory */
-static void free_bam_transaction(struct qcom_nand_controller *nandc)
-{
-	struct bam_transaction *bam_txn = nandc->bam_txn;
-
-	devm_kfree(nandc->dev, bam_txn);
-}
-
-/* Allocates and Initializes the BAM transaction */
-static struct bam_transaction *
-alloc_bam_transaction(struct qcom_nand_controller *nandc)
-{
-	struct bam_transaction *bam_txn;
-	size_t bam_txn_size;
-	unsigned int num_cw = nandc->max_cwperpage;
-	void *bam_txn_buf;
-
-	bam_txn_size =
-		sizeof(*bam_txn) + num_cw *
-		((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
-		(sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
-		(sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
-
-	bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
-	if (!bam_txn_buf)
-		return NULL;
-
-	bam_txn = bam_txn_buf;
-	bam_txn_buf += sizeof(*bam_txn);
-
-	bam_txn->bam_ce = bam_txn_buf;
-	bam_txn_buf +=
-		sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
-
-	bam_txn->cmd_sgl = bam_txn_buf;
-	bam_txn_buf +=
-		sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
-
-	bam_txn->data_sgl = bam_txn_buf;
-
-	return bam_txn;
-}
-
-/* Clears the BAM transaction indexes */
-static void clear_bam_transaction(struct qcom_nand_controller *nandc)
-{
-	struct bam_transaction *bam_txn = nandc->bam_txn;
-
-	if (!nandc->props->is_bam)
-		return;
-
-	bam_txn->bam_ce_pos = 0;
-	bam_txn->bam_ce_start = 0;
-	bam_txn->cmd_sgl_pos = 0;
-	bam_txn->cmd_sgl_start = 0;
-	bam_txn->tx_sgl_pos = 0;
-	bam_txn->tx_sgl_start = 0;
-	bam_txn->rx_sgl_pos = 0;
-	bam_txn->rx_sgl_start = 0;
-
-	sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
-		      QPIC_PER_CW_CMD_SGL);
-	sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
-		      QPIC_PER_CW_DATA_SGL);
-}
-
-static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
-{
-	return container_of(chip, struct qcom_nand_host, chip);
-}
-
-static inline struct qcom_nand_controller *
-get_qcom_nand_controller(struct nand_chip *chip)
-{
-	return container_of(chip->controller, struct qcom_nand_controller,
-			    controller);
-}
-
-static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
-{
-	return ioread32(nandc->base + offset);
-}
-
-static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
-			       u32 val)
-{
-	iowrite32(val, nandc->base + offset);
-}
-
-static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
-					  bool is_cpu)
-{
-	if (!nandc->props->is_bam)
-		return;
-
-	if (is_cpu)
-		dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
-					MAX_REG_RD *
-					sizeof(*nandc->reg_read_buf),
-					DMA_FROM_DEVICE);
-	else
-		dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
-					   MAX_REG_RD *
-					   sizeof(*nandc->reg_read_buf),
-					   DMA_FROM_DEVICE);
-}
-
-static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
-{
-	switch (offset) {
-	case NAND_FLASH_CMD:
-		return &regs->cmd;
-	case NAND_ADDR0:
-		return &regs->addr0;
-	case NAND_ADDR1:
-		return &regs->addr1;
-	case NAND_FLASH_CHIP_SELECT:
-		return &regs->chip_sel;
-	case NAND_EXEC_CMD:
-		return &regs->exec;
-	case NAND_FLASH_STATUS:
-		return &regs->clrflashstatus;
-	case NAND_DEV0_CFG0:
-		return &regs->cfg0;
-	case NAND_DEV0_CFG1:
-		return &regs->cfg1;
-	case NAND_DEV0_ECC_CFG:
-		return &regs->ecc_bch_cfg;
-	case NAND_READ_STATUS:
-		return &regs->clrreadstatus;
-	case NAND_DEV_CMD1:
-		return &regs->cmd1;
-	case NAND_DEV_CMD1_RESTORE:
-		return &regs->orig_cmd1;
-	case NAND_DEV_CMD_VLD:
-		return &regs->vld;
-	case NAND_DEV_CMD_VLD_RESTORE:
-		return &regs->orig_vld;
-	case NAND_EBI2_ECC_BUF_CFG:
-		return &regs->ecc_buf_cfg;
-	case NAND_READ_LOCATION_0:
-		return &regs->read_location0;
-	case NAND_READ_LOCATION_1:
-		return &regs->read_location1;
-	case NAND_READ_LOCATION_2:
-		return &regs->read_location2;
-	case NAND_READ_LOCATION_3:
-		return &regs->read_location3;
-	default:
-		return NULL;
-	}
-}
-
-static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset,
-			  u32 val)
-{
-	struct nandc_regs *regs = nandc->regs;
-	__le32 *reg;
-
-	reg = offset_to_nandc_reg(regs, offset);
-
-	if (reg)
-		*reg = cpu_to_le32(val);
-}
-
-/* helper to configure address register values */
-static void set_address(struct qcom_nand_host *host, u16 column, int page)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	if (chip->options & NAND_BUSWIDTH_16)
-		column >>= 1;
-
-	nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column);
-	nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff);
-}
-
-/*
- * update_rw_regs:	set up read/write register values, these will be
- *			written to the NAND controller registers via DMA
- *
- * @num_cw:		number of steps for the read/write operation
- * @read:		read or write operation
- */
-static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	u32 cmd, cfg0, cfg1, ecc_bch_cfg;
-
-	if (read) {
-		if (host->use_ecc)
-			cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
-		else
-			cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
-	} else {
-			cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
-	}
-
-	if (host->use_ecc) {
-		cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
-				(num_cw - 1) << CW_PER_PAGE;
-
-		cfg1 = host->cfg1;
-		ecc_bch_cfg = host->ecc_bch_cfg;
-	} else {
-		cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-				(num_cw - 1) << CW_PER_PAGE;
-
-		cfg1 = host->cfg1_raw;
-		ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-	}
-
-	nandc_set_reg(nandc, NAND_FLASH_CMD, cmd);
-	nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0);
-	nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1);
-	nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
-	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
-	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
-	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
-
-	if (read)
-		nandc_set_read_loc(nandc, 0, 0, host->use_ecc ?
-				   host->cw_data : host->cw_size, 1);
-}
-
-/*
- * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
- * for BAM. This descriptor will be added in the NAND DMA descriptor queue
- * which will be submitted to DMA engine.
- */
-static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
-				  struct dma_chan *chan,
-				  unsigned long flags)
-{
-	struct desc_info *desc;
-	struct scatterlist *sgl;
-	unsigned int sgl_cnt;
-	int ret;
-	struct bam_transaction *bam_txn = nandc->bam_txn;
-	enum dma_transfer_direction dir_eng;
-	struct dma_async_tx_descriptor *dma_desc;
-
-	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
-	if (chan == nandc->cmd_chan) {
-		sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
-		sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
-		bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
-		dir_eng = DMA_MEM_TO_DEV;
-		desc->dir = DMA_TO_DEVICE;
-	} else if (chan == nandc->tx_chan) {
-		sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
-		sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
-		bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
-		dir_eng = DMA_MEM_TO_DEV;
-		desc->dir = DMA_TO_DEVICE;
-	} else {
-		sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
-		sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
-		bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
-		dir_eng = DMA_DEV_TO_MEM;
-		desc->dir = DMA_FROM_DEVICE;
-	}
-
-	sg_mark_end(sgl + sgl_cnt - 1);
-	ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-	if (ret == 0) {
-		dev_err(nandc->dev, "failure in mapping desc\n");
-		kfree(desc);
-		return -ENOMEM;
-	}
-
-	desc->sgl_cnt = sgl_cnt;
-	desc->bam_sgl = sgl;
-
-	dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
-					   flags);
-
-	if (!dma_desc) {
-		dev_err(nandc->dev, "failure in prep desc\n");
-		dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
-		kfree(desc);
-		return -EINVAL;
-	}
-
-	desc->dma_desc = dma_desc;
-
-	list_add_tail(&desc->node, &nandc->desc_list);
-
-	return 0;
-}
-
-/*
- * Prepares the command descriptor for BAM DMA which will be used for NAND
- * register reads and writes. The command descriptor requires the command
- * to be formed in command element type so this function uses the command
- * element from bam transaction ce array and fills the same with required
- * data. A single SGL can contain multiple command elements so
- * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
- * after the current command element.
- */
-static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
-				 int reg_off, const void *vaddr,
-				 int size, unsigned int flags)
-{
-	int bam_ce_size;
-	int i, ret;
-	struct bam_cmd_element *bam_ce_buffer;
-	struct bam_transaction *bam_txn = nandc->bam_txn;
-
-	bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
-
-	/* fill the command desc */
-	for (i = 0; i < size; i++) {
-		if (read)
-			bam_prep_ce(&bam_ce_buffer[i],
-				    nandc_reg_phys(nandc, reg_off + 4 * i),
-				    BAM_READ_COMMAND,
-				    reg_buf_dma_addr(nandc,
-						     (__le32 *)vaddr + i));
-		else
-			bam_prep_ce_le32(&bam_ce_buffer[i],
-					 nandc_reg_phys(nandc, reg_off + 4 * i),
-					 BAM_WRITE_COMMAND,
-					 *((__le32 *)vaddr + i));
-	}
-
-	bam_txn->bam_ce_pos += size;
-
-	/* use the separate sgl after this command */
-	if (flags & NAND_BAM_NEXT_SGL) {
-		bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
-		bam_ce_size = (bam_txn->bam_ce_pos -
-				bam_txn->bam_ce_start) *
-				sizeof(struct bam_cmd_element);
-		sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
-			   bam_ce_buffer, bam_ce_size);
-		bam_txn->cmd_sgl_pos++;
-		bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
-
-		if (flags & NAND_BAM_NWD) {
-			ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-						     DMA_PREP_FENCE |
-						     DMA_PREP_CMD);
-			if (ret)
-				return ret;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * Prepares the data descriptor for BAM DMA which will be used for NAND
- * data reads and writes.
- */
-static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
-				  const void *vaddr,
-				  int size, unsigned int flags)
-{
-	int ret;
-	struct bam_transaction *bam_txn = nandc->bam_txn;
-
-	if (read) {
-		sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
-			   vaddr, size);
-		bam_txn->rx_sgl_pos++;
-	} else {
-		sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
-			   vaddr, size);
-		bam_txn->tx_sgl_pos++;
-
-		/*
-		 * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
-		 * is not set, form the DMA descriptor
-		 */
-		if (!(flags & NAND_BAM_NO_EOT)) {
-			ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
-						     DMA_PREP_INTERRUPT);
-			if (ret)
-				return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
-			     int reg_off, const void *vaddr, int size,
-			     bool flow_control)
-{
-	struct desc_info *desc;
-	struct dma_async_tx_descriptor *dma_desc;
-	struct scatterlist *sgl;
-	struct dma_slave_config slave_conf;
-	enum dma_transfer_direction dir_eng;
-	int ret;
-
-	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return -ENOMEM;
-
-	sgl = &desc->adm_sgl;
-
-	sg_init_one(sgl, vaddr, size);
-
-	if (read) {
-		dir_eng = DMA_DEV_TO_MEM;
-		desc->dir = DMA_FROM_DEVICE;
-	} else {
-		dir_eng = DMA_MEM_TO_DEV;
-		desc->dir = DMA_TO_DEVICE;
-	}
-
-	ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
-	if (ret == 0) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	memset(&slave_conf, 0x00, sizeof(slave_conf));
-
-	slave_conf.device_fc = flow_control;
-	if (read) {
-		slave_conf.src_maxburst = 16;
-		slave_conf.src_addr = nandc->base_dma + reg_off;
-		slave_conf.slave_id = nandc->data_crci;
-	} else {
-		slave_conf.dst_maxburst = 16;
-		slave_conf.dst_addr = nandc->base_dma + reg_off;
-		slave_conf.slave_id = nandc->cmd_crci;
-	}
-
-	ret = dmaengine_slave_config(nandc->chan, &slave_conf);
-	if (ret) {
-		dev_err(nandc->dev, "failed to configure dma channel\n");
-		goto err;
-	}
-
-	dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
-	if (!dma_desc) {
-		dev_err(nandc->dev, "failed to prepare desc\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	desc->dma_desc = dma_desc;
-
-	list_add_tail(&desc->node, &nandc->desc_list);
-
-	return 0;
-err:
-	kfree(desc);
-
-	return ret;
-}
-
-/*
- * read_reg_dma:	prepares a descriptor to read a given number of
- *			contiguous registers to the reg_read_buf pointer
- *
- * @first:		offset of the first register in the contiguous block
- * @num_regs:		number of registers to read
- * @flags:		flags to control DMA descriptor preparation
- */
-static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
-			int num_regs, unsigned int flags)
-{
-	bool flow_control = false;
-	void *vaddr;
-
-	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-	nandc->reg_read_pos += num_regs;
-
-	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
-		first = dev_cmd_reg_addr(nandc, first);
-
-	if (nandc->props->is_bam)
-		return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
-					     num_regs, flags);
-
-	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-		flow_control = true;
-
-	return prep_adm_dma_desc(nandc, true, first, vaddr,
-				 num_regs * sizeof(u32), flow_control);
-}
-
-/*
- * write_reg_dma:	prepares a descriptor to write a given number of
- *			contiguous registers
- *
- * @first:		offset of the first register in the contiguous block
- * @num_regs:		number of registers to write
- * @flags:		flags to control DMA descriptor preparation
- */
-static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
-			 int num_regs, unsigned int flags)
-{
-	bool flow_control = false;
-	struct nandc_regs *regs = nandc->regs;
-	void *vaddr;
-
-	vaddr = offset_to_nandc_reg(regs, first);
-
-	if (first == NAND_ERASED_CW_DETECT_CFG) {
-		if (flags & NAND_ERASED_CW_SET)
-			vaddr = &regs->erased_cw_detect_cfg_set;
-		else
-			vaddr = &regs->erased_cw_detect_cfg_clr;
-	}
-
-	if (first == NAND_EXEC_CMD)
-		flags |= NAND_BAM_NWD;
-
-	if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
-		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
-
-	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
-		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
-
-	if (nandc->props->is_bam)
-		return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
-					     num_regs, flags);
-
-	if (first == NAND_FLASH_CMD)
-		flow_control = true;
-
-	return prep_adm_dma_desc(nandc, false, first, vaddr,
-				 num_regs * sizeof(u32), flow_control);
-}
-
-/*
- * read_data_dma:	prepares a DMA descriptor to transfer data from the
- *			controller's internal buffer to the buffer 'vaddr'
- *
- * @reg_off:		offset within the controller's data buffer
- * @vaddr:		virtual address of the buffer we want to write to
- * @size:		DMA transaction size in bytes
- * @flags:		flags to control DMA descriptor preparation
- */
-static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-			 const u8 *vaddr, int size, unsigned int flags)
-{
-	if (nandc->props->is_bam)
-		return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
-
-	return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
-}
-
-/*
- * write_data_dma:	prepares a DMA descriptor to transfer data from
- *			'vaddr' to the controller's internal buffer
- *
- * @reg_off:		offset within the controller's data buffer
- * @vaddr:		virtual address of the buffer we want to read from
- * @size:		DMA transaction size in bytes
- * @flags:		flags to control DMA descriptor preparation
- */
-static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
-			  const u8 *vaddr, int size, unsigned int flags)
-{
-	if (nandc->props->is_bam)
-		return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
-
-	return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
-}
-
-/*
- * Helper to prepare DMA descriptors for configuring registers
- * before reading a NAND page.
- */
-static void config_nand_page_read(struct qcom_nand_controller *nandc)
-{
-	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
-	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
-	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
-		      NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
-}
-
-/*
- * Helper to prepare DMA descriptors for configuring registers
- * before reading each codeword in NAND page.
- */
-static void config_nand_cw_read(struct qcom_nand_controller *nandc)
-{
-	if (nandc->props->is_bam)
-		write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
-			      NAND_BAM_NEXT_SGL);
-
-	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
-	read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
-		     NAND_BAM_NEXT_SGL);
-}
-
-/*
- * Helper to prepare dma descriptors to configure registers needed for reading a
- * single codeword in page
- */
-static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
-{
-	config_nand_page_read(nandc);
-	config_nand_cw_read(nandc);
-}
-
-/*
- * Helper to prepare DMA descriptors used to configure registers needed for
- * before writing a NAND page.
- */
-static void config_nand_page_write(struct qcom_nand_controller *nandc)
-{
-	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
-	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
-	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
-		      NAND_BAM_NEXT_SGL);
-}
-
-/*
- * Helper to prepare DMA descriptors for configuring registers
- * before writing each codeword in NAND page.
- */
-static void config_nand_cw_write(struct qcom_nand_controller *nandc)
-{
-	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
-	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
-}
-
-/*
- * the following functions are used within chip->cmdfunc() to perform different
- * NAND_CMD_* commands
- */
-
-/* sets up descriptors for NAND_CMD_PARAM */
-static int nandc_param(struct qcom_nand_host *host)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	/*
-	 * NAND_CMD_PARAM is called before we know much about the FLASH chip
-	 * in use. we configure the controller to perform a raw read of 512
-	 * bytes to read onfi params
-	 */
-	nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
-	nandc_set_reg(nandc, NAND_ADDR0, 0);
-	nandc_set_reg(nandc, NAND_ADDR1, 0);
-	nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
-					| 512 << UD_SIZE_BYTES
-					| 5 << NUM_ADDR_CYCLES
-					| 0 << SPARE_SIZE_BYTES);
-	nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
-					| 0 << CS_ACTIVE_BSY
-					| 17 << BAD_BLOCK_BYTE_NUM
-					| 1 << BAD_BLOCK_IN_SPARE_AREA
-					| 2 << WR_RD_BSY_GAP
-					| 0 << WIDE_FLASH
-					| 1 << DEV0_CFG1_ECC_DISABLE);
-	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
-
-	/* configure CMD1 and VLD for ONFI param probing */
-	nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
-		      (nandc->vld & ~READ_START_VLD));
-	nandc_set_reg(nandc, NAND_DEV_CMD1,
-		      (nandc->cmd1 & ~(0xFF << READ_ADDR))
-		      | NAND_CMD_PARAM << READ_ADDR);
-
-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
-
-	nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
-	nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
-	nandc_set_read_loc(nandc, 0, 0, 512, 1);
-
-	write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
-	write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
-
-	nandc->buf_count = 512;
-	memset(nandc->data_buffer, 0xff, nandc->buf_count);
-
-	config_nand_single_cw_page_read(nandc);
-
-	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
-		      nandc->buf_count, 0);
-
-	/* restore CMD1 and VLD regs */
-	write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
-	write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
-
-	return 0;
-}
-
-/* sets up descriptors for NAND_CMD_ERASE1 */
-static int erase_block(struct qcom_nand_host *host, int page_addr)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	nandc_set_reg(nandc, NAND_FLASH_CMD,
-		      BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
-	nandc_set_reg(nandc, NAND_ADDR0, page_addr);
-	nandc_set_reg(nandc, NAND_ADDR1, 0);
-	nandc_set_reg(nandc, NAND_DEV0_CFG0,
-		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
-	nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw);
-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
-	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
-	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
-
-	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
-	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-	return 0;
-}
-
-/* sets up descriptors for NAND_CMD_READID */
-static int read_id(struct qcom_nand_host *host, int column)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	if (column == -1)
-		return 0;
-
-	nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID);
-	nandc_set_reg(nandc, NAND_ADDR0, column);
-	nandc_set_reg(nandc, NAND_ADDR1, 0);
-	nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT,
-		      nandc->props->is_bam ? 0 : DM_EN);
-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
-
-	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
-
-	return 0;
-}
-
-/* sets up descriptors for NAND_CMD_RESET */
-static int reset(struct qcom_nand_host *host)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE);
-	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
-
-	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-	return 0;
-}
-
-/* helpers to submit/free our list of dma descriptors */
-static int submit_descs(struct qcom_nand_controller *nandc)
-{
-	struct desc_info *desc;
-	dma_cookie_t cookie = 0;
-	struct bam_transaction *bam_txn = nandc->bam_txn;
-	int r;
-
-	if (nandc->props->is_bam) {
-		if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
-			r = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
-			if (r)
-				return r;
-		}
-
-		if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
-			r = prepare_bam_async_desc(nandc, nandc->tx_chan,
-						   DMA_PREP_INTERRUPT);
-			if (r)
-				return r;
-		}
-
-		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-			r = prepare_bam_async_desc(nandc, nandc->cmd_chan,
-						   DMA_PREP_CMD);
-			if (r)
-				return r;
-		}
-	}
-
-	list_for_each_entry(desc, &nandc->desc_list, node)
-		cookie = dmaengine_submit(desc->dma_desc);
-
-	if (nandc->props->is_bam) {
-		dma_async_issue_pending(nandc->tx_chan);
-		dma_async_issue_pending(nandc->rx_chan);
-
-		if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE)
-			return -ETIMEDOUT;
-	} else {
-		if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
-			return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static void free_descs(struct qcom_nand_controller *nandc)
-{
-	struct desc_info *desc, *n;
-
-	list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
-		list_del(&desc->node);
-
-		if (nandc->props->is_bam)
-			dma_unmap_sg(nandc->dev, desc->bam_sgl,
-				     desc->sgl_cnt, desc->dir);
-		else
-			dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
-				     desc->dir);
-
-		kfree(desc);
-	}
-}
-
-/* reset the register read buffer for next NAND operation */
-static void clear_read_regs(struct qcom_nand_controller *nandc)
-{
-	nandc->reg_read_pos = 0;
-	nandc_read_buffer_sync(nandc, false);
-}
-
-static void pre_command(struct qcom_nand_host *host, int command)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	nandc->buf_count = 0;
-	nandc->buf_start = 0;
-	host->use_ecc = false;
-	host->last_command = command;
-
-	clear_read_regs(nandc);
-
-	if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
-	    command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
-		clear_bam_transaction(nandc);
-}
-
-/*
- * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
- * privately maintained status byte, this status byte can be read after
- * NAND_CMD_STATUS is called
- */
-static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int num_cw;
-	int i;
-
-	num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
-	nandc_read_buffer_sync(nandc, true);
-
-	for (i = 0; i < num_cw; i++) {
-		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-
-		if (flash_status & FS_MPU_ERR)
-			host->status &= ~NAND_STATUS_WP;
-
-		if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
-						 (flash_status &
-						  FS_DEVICE_STS_ERR)))
-			host->status |= NAND_STATUS_FAIL;
-	}
-}
-
-static void post_command(struct qcom_nand_host *host, int command)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	switch (command) {
-	case NAND_CMD_READID:
-		nandc_read_buffer_sync(nandc, true);
-		memcpy(nandc->data_buffer, nandc->reg_read_buf,
-		       nandc->buf_count);
-		break;
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_ERASE1:
-		parse_erase_write_errors(host, command);
-		break;
-	default:
-		break;
-	}
-}
-
-/*
- * Implements chip->cmdfunc. It's  only used for a limited set of commands.
- * The rest of the commands wouldn't be called by upper layers. For example,
- * NAND_CMD_READOOB would never be called because we have our own versions
- * of read_oob ops for nand_ecc_ctrl.
- */
-static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
-			       int column, int page_addr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	bool wait = false;
-	int ret = 0;
-
-	pre_command(host, command);
-
-	switch (command) {
-	case NAND_CMD_RESET:
-		ret = reset(host);
-		wait = true;
-		break;
-
-	case NAND_CMD_READID:
-		nandc->buf_count = 4;
-		ret = read_id(host, column);
-		wait = true;
-		break;
-
-	case NAND_CMD_PARAM:
-		ret = nandc_param(host);
-		wait = true;
-		break;
-
-	case NAND_CMD_ERASE1:
-		ret = erase_block(host, page_addr);
-		wait = true;
-		break;
-
-	case NAND_CMD_READ0:
-		/* we read the entire page for now */
-		WARN_ON(column != 0);
-
-		host->use_ecc = true;
-		set_address(host, 0, page_addr);
-		update_rw_regs(host, ecc->steps, true);
-		break;
-
-	case NAND_CMD_SEQIN:
-		WARN_ON(column != 0);
-		set_address(host, 0, page_addr);
-		break;
-
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_NONE:
-	default:
-		break;
-	}
-
-	if (ret) {
-		dev_err(nandc->dev, "failure executing command %d\n",
-			command);
-		free_descs(nandc);
-		return;
-	}
-
-	if (wait) {
-		ret = submit_descs(nandc);
-		if (ret)
-			dev_err(nandc->dev,
-				"failure submitting descs for command %d\n",
-				command);
-	}
-
-	free_descs(nandc);
-
-	post_command(host, command);
-}
-
-/*
- * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
- * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
- *
- * when using RS ECC, the HW reports the same erros when reading an erased CW,
- * but it notifies that it is an erased CW by placing special characters at
- * certain offsets in the buffer.
- *
- * verify if the page is erased or not, and fix up the page for RS ECC by
- * replacing the special characters with 0xff.
- */
-static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
-{
-	u8 empty1, empty2;
-
-	/*
-	 * an erased page flags an error in NAND_FLASH_STATUS, check if the page
-	 * is erased by looking for 0x54s at offsets 3 and 175 from the
-	 * beginning of each codeword
-	 */
-
-	empty1 = data_buf[3];
-	empty2 = data_buf[175];
-
-	/*
-	 * if the erased codework markers, if they exist override them with
-	 * 0xffs
-	 */
-	if ((empty1 == 0x54 && empty2 == 0xff) ||
-	    (empty1 == 0xff && empty2 == 0x54)) {
-		data_buf[3] = 0xff;
-		data_buf[175] = 0xff;
-	}
-
-	/*
-	 * check if the entire chunk contains 0xffs or not. if it doesn't, then
-	 * restore the original values at the special offsets
-	 */
-	if (memchr_inv(data_buf, 0xff, data_len)) {
-		data_buf[3] = empty1;
-		data_buf[175] = empty2;
-
-		return false;
-	}
-
-	return true;
-}
-
-struct read_stats {
-	__le32 flash;
-	__le32 buffer;
-	__le32 erased_cw;
-};
-
-/*
- * reads back status registers set by the controller to notify page read
- * errors. this is equivalent to what 'ecc->correct()' would do.
- */
-static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
-			     u8 *oob_buf)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	unsigned int max_bitflips = 0;
-	struct read_stats *buf;
-	int i;
-
-	buf = (struct read_stats *)nandc->reg_read_buf;
-	nandc_read_buffer_sync(nandc, true);
-
-	for (i = 0; i < ecc->steps; i++, buf++) {
-		u32 flash, buffer, erased_cw;
-		int data_len, oob_len;
-
-		if (i == (ecc->steps - 1)) {
-			data_len = ecc->size - ((ecc->steps - 1) << 2);
-			oob_len = ecc->steps << 2;
-		} else {
-			data_len = host->cw_data;
-			oob_len = 0;
-		}
-
-		flash = le32_to_cpu(buf->flash);
-		buffer = le32_to_cpu(buf->buffer);
-		erased_cw = le32_to_cpu(buf->erased_cw);
-
-		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
-			bool erased;
-
-			/* ignore erased codeword errors */
-			if (host->bch_enabled) {
-				erased = (erased_cw & ERASED_CW) == ERASED_CW ?
-					 true : false;
-			} else {
-				erased = erased_chunk_check_and_fixup(data_buf,
-								      data_len);
-			}
-
-			if (erased) {
-				data_buf += data_len;
-				if (oob_buf)
-					oob_buf += oob_len + ecc->bytes;
-				continue;
-			}
-
-			if (buffer & BS_UNCORRECTABLE_BIT) {
-				int ret, ecclen, extraooblen;
-				void *eccbuf;
-
-				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
-				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
-				extraooblen = oob_buf ? oob_len : 0;
-
-				/*
-				 * make sure it isn't an erased page reported
-				 * as not-erased by HW because of a few bitflips
-				 */
-				ret = nand_check_erased_ecc_chunk(data_buf,
-					data_len, eccbuf, ecclen, oob_buf,
-					extraooblen, ecc->strength);
-				if (ret < 0) {
-					mtd->ecc_stats.failed++;
-				} else {
-					mtd->ecc_stats.corrected += ret;
-					max_bitflips =
-						max_t(unsigned int, max_bitflips, ret);
-				}
-			}
-		} else {
-			unsigned int stat;
-
-			stat = buffer & BS_CORRECTABLE_ERR_MSK;
-			mtd->ecc_stats.corrected += stat;
-			max_bitflips = max(max_bitflips, stat);
-		}
-
-		data_buf += data_len;
-		if (oob_buf)
-			oob_buf += oob_len + ecc->bytes;
-	}
-
-	return max_bitflips;
-}
-
-/*
- * helper to perform the actual page read operation, used by ecc->read_page(),
- * ecc->read_oob()
- */
-static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
-			 u8 *oob_buf)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int i, ret;
-
-	config_nand_page_read(nandc);
-
-	/* queue cmd descs for each codeword */
-	for (i = 0; i < ecc->steps; i++) {
-		int data_size, oob_size;
-
-		if (i == (ecc->steps - 1)) {
-			data_size = ecc->size - ((ecc->steps - 1) << 2);
-			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
-				   host->spare_bytes;
-		} else {
-			data_size = host->cw_data;
-			oob_size = host->ecc_bytes_hw + host->spare_bytes;
-		}
-
-		if (nandc->props->is_bam) {
-			if (data_buf && oob_buf) {
-				nandc_set_read_loc(nandc, 0, 0, data_size, 0);
-				nandc_set_read_loc(nandc, 1, data_size,
-						   oob_size, 1);
-			} else if (data_buf) {
-				nandc_set_read_loc(nandc, 0, 0, data_size, 1);
-			} else {
-				nandc_set_read_loc(nandc, 0, data_size,
-						   oob_size, 1);
-			}
-		}
-
-		config_nand_cw_read(nandc);
-
-		if (data_buf)
-			read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
-				      data_size, 0);
-
-		/*
-		 * when ecc is enabled, the controller doesn't read the real
-		 * or dummy bad block markers in each chunk. To maintain a
-		 * consistent layout across RAW and ECC reads, we just
-		 * leave the real/dummy BBM offsets empty (i.e, filled with
-		 * 0xffs)
-		 */
-		if (oob_buf) {
-			int j;
-
-			for (j = 0; j < host->bbm_size; j++)
-				*oob_buf++ = 0xff;
-
-			read_data_dma(nandc, FLASH_BUF_ACC + data_size,
-				      oob_buf, oob_size, 0);
-		}
-
-		if (data_buf)
-			data_buf += data_size;
-		if (oob_buf)
-			oob_buf += oob_size;
-	}
-
-	ret = submit_descs(nandc);
-	if (ret)
-		dev_err(nandc->dev, "failure to read page/oob\n");
-
-	free_descs(nandc);
-
-	return ret;
-}
-
-/*
- * a helper that copies the last step/codeword of a page (containing free oob)
- * into our local buffer
- */
-static int copy_last_cw(struct qcom_nand_host *host, int page)
-{
-	struct nand_chip *chip = &host->chip;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int size;
-	int ret;
-
-	clear_read_regs(nandc);
-
-	size = host->use_ecc ? host->cw_data : host->cw_size;
-
-	/* prepare a clean read buffer */
-	memset(nandc->data_buffer, 0xff, size);
-
-	set_address(host, host->cw_size * (ecc->steps - 1), page);
-	update_rw_regs(host, 1, true);
-
-	config_nand_single_cw_page_read(nandc);
-
-	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
-
-	ret = submit_descs(nandc);
-	if (ret)
-		dev_err(nandc->dev, "failed to copy last codeword\n");
-
-	free_descs(nandc);
-
-	return ret;
-}
-
-/* implements ecc->read_page() */
-static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	u8 *data_buf, *oob_buf = NULL;
-	int ret;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-	data_buf = buf;
-	oob_buf = oob_required ? chip->oob_poi : NULL;
-
-	clear_bam_transaction(nandc);
-	ret = read_page_ecc(host, data_buf, oob_buf);
-	if (ret) {
-		dev_err(nandc->dev, "failure to read page\n");
-		return ret;
-	}
-
-	return parse_read_errors(host, data_buf, oob_buf);
-}
-
-/* implements ecc->read_page_raw() */
-static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
-				    struct nand_chip *chip, uint8_t *buf,
-				    int oob_required, int page)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	u8 *data_buf, *oob_buf;
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int i, ret;
-	int read_loc;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-	data_buf = buf;
-	oob_buf = chip->oob_poi;
-
-	host->use_ecc = false;
-
-	clear_bam_transaction(nandc);
-	update_rw_regs(host, ecc->steps, true);
-	config_nand_page_read(nandc);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_size1, data_size2, oob_size1, oob_size2;
-		int reg_off = FLASH_BUF_ACC;
-
-		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
-		oob_size1 = host->bbm_size;
-
-		if (i == (ecc->steps - 1)) {
-			data_size2 = ecc->size - data_size1 -
-				     ((ecc->steps - 1) << 2);
-			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
-				    host->spare_bytes;
-		} else {
-			data_size2 = host->cw_data - data_size1;
-			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
-		}
-
-		if (nandc->props->is_bam) {
-			read_loc = 0;
-			nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
-			read_loc += data_size1;
-
-			nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
-			read_loc += oob_size1;
-
-			nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
-			read_loc += data_size2;
-
-			nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
-		}
-
-		config_nand_cw_read(nandc);
-
-		read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
-		reg_off += data_size1;
-		data_buf += data_size1;
-
-		read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
-		reg_off += oob_size1;
-		oob_buf += oob_size1;
-
-		read_data_dma(nandc, reg_off, data_buf, data_size2, 0);
-		reg_off += data_size2;
-		data_buf += data_size2;
-
-		read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
-		oob_buf += oob_size2;
-	}
-
-	ret = submit_descs(nandc);
-	if (ret)
-		dev_err(nandc->dev, "failure to read raw page\n");
-
-	free_descs(nandc);
-
-	return 0;
-}
-
-/* implements ecc->read_oob() */
-static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			       int page)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ret;
-
-	clear_read_regs(nandc);
-	clear_bam_transaction(nandc);
-
-	host->use_ecc = true;
-	set_address(host, 0, page);
-	update_rw_regs(host, ecc->steps, true);
-
-	ret = read_page_ecc(host, NULL, chip->oob_poi);
-	if (ret)
-		dev_err(nandc->dev, "failure to read oob\n");
-
-	return ret;
-}
-
-/* implements ecc->write_page() */
-static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-				 const uint8_t *buf, int oob_required, int page)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	u8 *data_buf, *oob_buf;
-	int i, ret;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	clear_read_regs(nandc);
-	clear_bam_transaction(nandc);
-
-	data_buf = (u8 *)buf;
-	oob_buf = chip->oob_poi;
-
-	host->use_ecc = true;
-	update_rw_regs(host, ecc->steps, false);
-	config_nand_page_write(nandc);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_size, oob_size;
-
-		if (i == (ecc->steps - 1)) {
-			data_size = ecc->size - ((ecc->steps - 1) << 2);
-			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
-				   host->spare_bytes;
-		} else {
-			data_size = host->cw_data;
-			oob_size = ecc->bytes;
-		}
-
-
-		write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
-			       i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
-
-		/*
-		 * when ECC is enabled, we don't really need to write anything
-		 * to oob for the first n - 1 codewords since these oob regions
-		 * just contain ECC bytes that's written by the controller
-		 * itself. For the last codeword, we skip the bbm positions and
-		 * write to the free oob area.
-		 */
-		if (i == (ecc->steps - 1)) {
-			oob_buf += host->bbm_size;
-
-			write_data_dma(nandc, FLASH_BUF_ACC + data_size,
-				       oob_buf, oob_size, 0);
-		}
-
-		config_nand_cw_write(nandc);
-
-		data_buf += data_size;
-		oob_buf += oob_size;
-	}
-
-	ret = submit_descs(nandc);
-	if (ret)
-		dev_err(nandc->dev, "failure to write page\n");
-
-	free_descs(nandc);
-
-	if (!ret)
-		ret = nand_prog_page_end_op(chip);
-
-	return ret;
-}
-
-/* implements ecc->write_page_raw() */
-static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
-				     struct nand_chip *chip, const uint8_t *buf,
-				     int oob_required, int page)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	u8 *data_buf, *oob_buf;
-	int i, ret;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	clear_read_regs(nandc);
-	clear_bam_transaction(nandc);
-
-	data_buf = (u8 *)buf;
-	oob_buf = chip->oob_poi;
-
-	host->use_ecc = false;
-	update_rw_regs(host, ecc->steps, false);
-	config_nand_page_write(nandc);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_size1, data_size2, oob_size1, oob_size2;
-		int reg_off = FLASH_BUF_ACC;
-
-		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
-		oob_size1 = host->bbm_size;
-
-		if (i == (ecc->steps - 1)) {
-			data_size2 = ecc->size - data_size1 -
-				     ((ecc->steps - 1) << 2);
-			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
-				    host->spare_bytes;
-		} else {
-			data_size2 = host->cw_data - data_size1;
-			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
-		}
-
-		write_data_dma(nandc, reg_off, data_buf, data_size1,
-			       NAND_BAM_NO_EOT);
-		reg_off += data_size1;
-		data_buf += data_size1;
-
-		write_data_dma(nandc, reg_off, oob_buf, oob_size1,
-			       NAND_BAM_NO_EOT);
-		reg_off += oob_size1;
-		oob_buf += oob_size1;
-
-		write_data_dma(nandc, reg_off, data_buf, data_size2,
-			       NAND_BAM_NO_EOT);
-		reg_off += data_size2;
-		data_buf += data_size2;
-
-		write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
-		oob_buf += oob_size2;
-
-		config_nand_cw_write(nandc);
-	}
-
-	ret = submit_descs(nandc);
-	if (ret)
-		dev_err(nandc->dev, "failure to write raw page\n");
-
-	free_descs(nandc);
-
-	if (!ret)
-		ret = nand_prog_page_end_op(chip);
-
-	return ret;
-}
-
-/*
- * implements ecc->write_oob()
- *
- * the NAND controller cannot write only data or only oob within a codeword,
- * since ecc is calculated for the combined codeword. we first copy the
- * entire contents for the last codeword(data + oob), replace the old oob
- * with the new one in chip->oob_poi, and then write the entire codeword.
- * this read-copy-write operation results in a slight performance loss.
- */
-static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-				int page)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	u8 *oob = chip->oob_poi;
-	int data_size, oob_size;
-	int ret;
-
-	host->use_ecc = true;
-
-	clear_bam_transaction(nandc);
-	ret = copy_last_cw(host, page);
-	if (ret)
-		return ret;
-
-	clear_read_regs(nandc);
-	clear_bam_transaction(nandc);
-
-	/* calculate the data and oob size for the last codeword/step */
-	data_size = ecc->size - ((ecc->steps - 1) << 2);
-	oob_size = mtd->oobavail;
-
-	/* override new oob content to last codeword */
-	mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
-				    0, mtd->oobavail);
-
-	set_address(host, host->cw_size * (ecc->steps - 1), page);
-	update_rw_regs(host, 1, false);
-
-	config_nand_page_write(nandc);
-	write_data_dma(nandc, FLASH_BUF_ACC,
-		       nandc->data_buffer, data_size + oob_size, 0);
-	config_nand_cw_write(nandc);
-
-	ret = submit_descs(nandc);
-
-	free_descs(nandc);
-
-	if (ret) {
-		dev_err(nandc->dev, "failure to write oob\n");
-		return -EIO;
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int page, ret, bbpos, bad = 0;
-	u32 flash_status;
-
-	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-
-	/*
-	 * configure registers for a raw sub page read, the address is set to
-	 * the beginning of the last codeword, we don't care about reading ecc
-	 * portion of oob. we just want the first few bytes from this codeword
-	 * that contains the BBM
-	 */
-	host->use_ecc = false;
-
-	clear_bam_transaction(nandc);
-	ret = copy_last_cw(host, page);
-	if (ret)
-		goto err;
-
-	flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
-
-	if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
-		dev_warn(nandc->dev, "error when trying to read BBM\n");
-		goto err;
-	}
-
-	bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
-
-	bad = nandc->data_buffer[bbpos] != 0xff;
-
-	if (chip->options & NAND_BUSWIDTH_16)
-		bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
-err:
-	return bad;
-}
-
-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int page, ret;
-
-	clear_read_regs(nandc);
-	clear_bam_transaction(nandc);
-
-	/*
-	 * to mark the BBM as bad, we flash the entire last codeword with 0s.
-	 * we don't care about the rest of the content in the codeword since
-	 * we aren't going to use this block again
-	 */
-	memset(nandc->data_buffer, 0x00, host->cw_size);
-
-	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-
-	/* prepare write */
-	host->use_ecc = false;
-	set_address(host, host->cw_size * (ecc->steps - 1), page);
-	update_rw_regs(host, 1, false);
-
-	config_nand_page_write(nandc);
-	write_data_dma(nandc, FLASH_BUF_ACC,
-		       nandc->data_buffer, host->cw_size, 0);
-	config_nand_cw_write(nandc);
-
-	ret = submit_descs(nandc);
-
-	free_descs(nandc);
-
-	if (ret) {
-		dev_err(nandc->dev, "failure to update BBM\n");
-		return -EIO;
-	}
-
-	return nand_prog_page_end_op(chip);
-}
-
-/*
- * the three functions below implement chip->read_byte(), chip->read_buf()
- * and chip->write_buf() respectively. these aren't used for
- * reading/writing page data, they are used for smaller data like reading
- * id, status etc
- */
-static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	u8 *buf = nandc->data_buffer;
-	u8 ret = 0x0;
-
-	if (host->last_command == NAND_CMD_STATUS) {
-		ret = host->status;
-
-		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
-
-		return ret;
-	}
-
-	if (nandc->buf_start < nandc->buf_count)
-		ret = buf[nandc->buf_start++];
-
-	return ret;
-}
-
-static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
-
-	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
-	nandc->buf_start += real_len;
-}
-
-static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-				 int len)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
-
-	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
-
-	nandc->buf_start += real_len;
-}
-
-/* we support only one external chip for now */
-static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	if (chipnr <= 0)
-		return;
-
-	dev_warn(nandc->dev, "invalid chip select\n");
-}
-
-/*
- * NAND controller page layout info
- *
- * Layout with ECC enabled:
- *
- * |----------------------|  |---------------------------------|
- * |           xx.......yy|  |             *********xx.......yy|
- * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
- * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
- * |           xx.......yy|  |             *********xx.......yy|
- * |----------------------|  |---------------------------------|
- *     codeword 1,2..n-1                  codeword n
- *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
- *
- * n = Number of codewords in the page
- * . = ECC bytes
- * * = Spare/free bytes
- * x = Unused byte(s)
- * y = Reserved byte(s)
- *
- * 2K page: n = 4, spare = 16 bytes
- * 4K page: n = 8, spare = 32 bytes
- * 8K page: n = 16, spare = 64 bytes
- *
- * the qcom nand controller operates at a sub page/codeword level. each
- * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
- * the number of ECC bytes vary based on the ECC strength and the bus width.
- *
- * the first n - 1 codewords contains 516 bytes of user data, the remaining
- * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
- * both user data and spare(oobavail) bytes that sum up to 516 bytes.
- *
- * When we access a page with ECC enabled, the reserved bytes(s) are not
- * accessible at all. When reading, we fill up these unreadable positions
- * with 0xffs. When writing, the controller skips writing the inaccessible
- * bytes.
- *
- * Layout with ECC disabled:
- *
- * |------------------------------|  |---------------------------------------|
- * |         yy          xx.......|  |         bb          *********xx.......|
- * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
- * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
- * |         yy          xx.......|  |         bb          *********xx.......|
- * |------------------------------|  |---------------------------------------|
- *         codeword 1,2..n-1                        codeword n
- *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
- *
- * n = Number of codewords in the page
- * . = ECC bytes
- * * = Spare/free bytes
- * x = Unused byte(s)
- * y = Dummy Bad Bock byte(s)
- * b = Real Bad Block byte(s)
- * size1/size2 = function of codeword size and 'n'
- *
- * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
- * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
- * Block Markers. In the last codeword, this position contains the real BBM
- *
- * In order to have a consistent layout between RAW and ECC modes, we assume
- * the following OOB layout arrangement:
- *
- * |-----------|  |--------------------|
- * |yyxx.......|  |bb*********xx.......|
- * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
- * |yyxx.......|  |bb*********xx.......|
- * |yyxx.......|  |bb*********xx.......|
- * |-----------|  |--------------------|
- *  first n - 1       nth OOB region
- *  OOB regions
- *
- * n = Number of codewords in the page
- * . = ECC bytes
- * * = FREE OOB bytes
- * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
- * x = Unused byte(s)
- * b = Real bad block byte(s) (inaccessible when ECC enabled)
- *
- * This layout is read as is when ECC is disabled. When ECC is enabled, the
- * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
- * and assumed as 0xffs when we read a page/oob. The ECC, unused and
- * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
- * the sum of the three).
- */
-static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
-				   struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (section > 1)
-		return -ERANGE;
-
-	if (!section) {
-		oobregion->length = (ecc->bytes * (ecc->steps - 1)) +
-				    host->bbm_size;
-		oobregion->offset = 0;
-	} else {
-		oobregion->length = host->ecc_bytes_hw + host->spare_bytes;
-		oobregion->offset = mtd->oobsize - oobregion->length;
-	}
-
-	return 0;
-}
-
-static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section,
-				     struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->length = ecc->steps * 4;
-	oobregion->offset = ((ecc->steps - 1) * ecc->bytes) + host->bbm_size;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
-	.ecc = qcom_nand_ooblayout_ecc,
-	.free = qcom_nand_ooblayout_free,
-};
-
-static int qcom_nand_host_setup(struct qcom_nand_host *host)
-{
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int cwperpage, bad_block_byte;
-	bool wide_bus;
-	int ecc_mode = 1;
-
-	/*
-	 * the controller requires each step consists of 512 bytes of data.
-	 * bail out if DT has populated a wrong step size.
-	 */
-	if (ecc->size != NANDC_STEP_SIZE) {
-		dev_err(nandc->dev, "invalid ecc size\n");
-		return -EINVAL;
-	}
-
-	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
-
-	if (ecc->strength >= 8) {
-		/* 8 bit ECC defaults to BCH ECC on all platforms */
-		host->bch_enabled = true;
-		ecc_mode = 1;
-
-		if (wide_bus) {
-			host->ecc_bytes_hw = 14;
-			host->spare_bytes = 0;
-			host->bbm_size = 2;
-		} else {
-			host->ecc_bytes_hw = 13;
-			host->spare_bytes = 2;
-			host->bbm_size = 1;
-		}
-	} else {
-		/*
-		 * if the controller supports BCH for 4 bit ECC, the controller
-		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
-		 * always 10 bytes
-		 */
-		if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
-			/* BCH */
-			host->bch_enabled = true;
-			ecc_mode = 0;
-
-			if (wide_bus) {
-				host->ecc_bytes_hw = 8;
-				host->spare_bytes = 2;
-				host->bbm_size = 2;
-			} else {
-				host->ecc_bytes_hw = 7;
-				host->spare_bytes = 4;
-				host->bbm_size = 1;
-			}
-		} else {
-			/* RS */
-			host->ecc_bytes_hw = 10;
-
-			if (wide_bus) {
-				host->spare_bytes = 0;
-				host->bbm_size = 2;
-			} else {
-				host->spare_bytes = 1;
-				host->bbm_size = 1;
-			}
-		}
-	}
-
-	/*
-	 * we consider ecc->bytes as the sum of all the non-data content in a
-	 * step. It gives us a clean representation of the oob area (even if
-	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
-	 * ECC and 12 bytes for 4 bit ECC
-	 */
-	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
-
-	ecc->read_page		= qcom_nandc_read_page;
-	ecc->read_page_raw	= qcom_nandc_read_page_raw;
-	ecc->read_oob		= qcom_nandc_read_oob;
-	ecc->write_page		= qcom_nandc_write_page;
-	ecc->write_page_raw	= qcom_nandc_write_page_raw;
-	ecc->write_oob		= qcom_nandc_write_oob;
-
-	ecc->mode = NAND_ECC_HW;
-
-	mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
-
-	cwperpage = mtd->writesize / ecc->size;
-	nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
-				     cwperpage);
-
-	/*
-	 * DATA_UD_BYTES varies based on whether the read/write command protects
-	 * spare data with ECC too. We protect spare data by default, so we set
-	 * it to main + spare data, which are 512 and 4 bytes respectively.
-	 */
-	host->cw_data = 516;
-
-	/*
-	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
-	 * for 8 bit ECC
-	 */
-	host->cw_size = host->cw_data + ecc->bytes;
-
-	if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
-		dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
-		return -EINVAL;
-	}
-
-	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
-
-	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
-				| host->cw_data << UD_SIZE_BYTES
-				| 0 << DISABLE_STATUS_AFTER_WRITE
-				| 5 << NUM_ADDR_CYCLES
-				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
-				| 0 << STATUS_BFR_READ
-				| 1 << SET_RD_MODE_AFTER_STATUS
-				| host->spare_bytes << SPARE_SIZE_BYTES;
-
-	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
-				| 0 <<  CS_ACTIVE_BSY
-				| bad_block_byte << BAD_BLOCK_BYTE_NUM
-				| 0 << BAD_BLOCK_IN_SPARE_AREA
-				| 2 << WR_RD_BSY_GAP
-				| wide_bus << WIDE_FLASH
-				| host->bch_enabled << ENABLE_BCH_ECC;
-
-	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
-				| host->cw_size << UD_SIZE_BYTES
-				| 5 << NUM_ADDR_CYCLES
-				| 0 << SPARE_SIZE_BYTES;
-
-	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
-				| 0 << CS_ACTIVE_BSY
-				| 17 << BAD_BLOCK_BYTE_NUM
-				| 1 << BAD_BLOCK_IN_SPARE_AREA
-				| 2 << WR_RD_BSY_GAP
-				| wide_bus << WIDE_FLASH
-				| 1 << DEV0_CFG1_ECC_DISABLE;
-
-	host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
-				| 0 << ECC_SW_RESET
-				| host->cw_data << ECC_NUM_DATA_BYTES
-				| 1 << ECC_FORCE_CLK_OPEN
-				| ecc_mode << ECC_MODE
-				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
-
-	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
-
-	host->clrflashstatus = FS_READY_BSY_N;
-	host->clrreadstatus = 0xc0;
-	nandc->regs->erased_cw_detect_cfg_clr =
-		cpu_to_le32(CLR_ERASED_PAGE_DET);
-	nandc->regs->erased_cw_detect_cfg_set =
-		cpu_to_le32(SET_ERASED_PAGE_DET);
-
-	dev_dbg(nandc->dev,
-		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
-		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
-		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
-		cwperpage);
-
-	return 0;
-}
-
-static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
-{
-	int ret;
-
-	ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
-	if (ret) {
-		dev_err(nandc->dev, "failed to set DMA mask\n");
-		return ret;
-	}
-
-	/*
-	 * we use the internal buffer for reading ONFI params, reading small
-	 * data like ID and status, and preforming read-copy-write operations
-	 * when writing to a codeword partially. 532 is the maximum possible
-	 * size of a codeword for our nand controller
-	 */
-	nandc->buf_size = 532;
-
-	nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size,
-					GFP_KERNEL);
-	if (!nandc->data_buffer)
-		return -ENOMEM;
-
-	nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs),
-					GFP_KERNEL);
-	if (!nandc->regs)
-		return -ENOMEM;
-
-	nandc->reg_read_buf = devm_kzalloc(nandc->dev,
-				MAX_REG_RD * sizeof(*nandc->reg_read_buf),
-				GFP_KERNEL);
-	if (!nandc->reg_read_buf)
-		return -ENOMEM;
-
-	if (nandc->props->is_bam) {
-		nandc->reg_read_dma =
-			dma_map_single(nandc->dev, nandc->reg_read_buf,
-				       MAX_REG_RD *
-				       sizeof(*nandc->reg_read_buf),
-				       DMA_FROM_DEVICE);
-		if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
-			dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
-			return -EIO;
-		}
-
-		nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
-		if (!nandc->tx_chan) {
-			dev_err(nandc->dev, "failed to request tx channel\n");
-			return -ENODEV;
-		}
-
-		nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
-		if (!nandc->rx_chan) {
-			dev_err(nandc->dev, "failed to request rx channel\n");
-			return -ENODEV;
-		}
-
-		nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
-		if (!nandc->cmd_chan) {
-			dev_err(nandc->dev, "failed to request cmd channel\n");
-			return -ENODEV;
-		}
-
-		/*
-		 * Initially allocate BAM transaction to read ONFI param page.
-		 * After detecting all the devices, this BAM transaction will
-		 * be freed and the next BAM tranasction will be allocated with
-		 * maximum codeword size
-		 */
-		nandc->max_cwperpage = 1;
-		nandc->bam_txn = alloc_bam_transaction(nandc);
-		if (!nandc->bam_txn) {
-			dev_err(nandc->dev,
-				"failed to allocate bam transaction\n");
-			return -ENOMEM;
-		}
-	} else {
-		nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
-		if (!nandc->chan) {
-			dev_err(nandc->dev,
-				"failed to request slave channel\n");
-			return -ENODEV;
-		}
-	}
-
-	INIT_LIST_HEAD(&nandc->desc_list);
-	INIT_LIST_HEAD(&nandc->host_list);
-
-	nand_hw_control_init(&nandc->controller);
-
-	return 0;
-}
-
-static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
-{
-	if (nandc->props->is_bam) {
-		if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
-			dma_unmap_single(nandc->dev, nandc->reg_read_dma,
-					 MAX_REG_RD *
-					 sizeof(*nandc->reg_read_buf),
-					 DMA_FROM_DEVICE);
-
-		if (nandc->tx_chan)
-			dma_release_channel(nandc->tx_chan);
-
-		if (nandc->rx_chan)
-			dma_release_channel(nandc->rx_chan);
-
-		if (nandc->cmd_chan)
-			dma_release_channel(nandc->cmd_chan);
-	} else {
-		if (nandc->chan)
-			dma_release_channel(nandc->chan);
-	}
-}
-
-/* one time setup of a few nand controller registers */
-static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
-{
-	u32 nand_ctrl;
-
-	/* kill onenand */
-	nandc_write(nandc, SFLASHC_BURST_CFG, 0);
-	nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
-		    NAND_DEV_CMD_VLD_VAL);
-
-	/* enable ADM or BAM DMA */
-	if (nandc->props->is_bam) {
-		nand_ctrl = nandc_read(nandc, NAND_CTRL);
-		nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
-	} else {
-		nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
-	}
-
-	/* save the original values of these registers */
-	nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
-	nandc->vld = NAND_DEV_CMD_VLD_VAL;
-
-	return 0;
-}
-
-static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
-			       struct qcom_nand_host *host,
-			       struct device_node *dn)
-{
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct device *dev = nandc->dev;
-	int ret;
-
-	ret = of_property_read_u32(dn, "reg", &host->cs);
-	if (ret) {
-		dev_err(dev, "can't get chip-select\n");
-		return -ENXIO;
-	}
-
-	nand_set_flash_node(chip, dn);
-	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
-	if (!mtd->name)
-		return -ENOMEM;
-
-	mtd->owner = THIS_MODULE;
-	mtd->dev.parent = dev;
-
-	chip->cmdfunc		= qcom_nandc_command;
-	chip->select_chip	= qcom_nandc_select_chip;
-	chip->read_byte		= qcom_nandc_read_byte;
-	chip->read_buf		= qcom_nandc_read_buf;
-	chip->write_buf		= qcom_nandc_write_buf;
-	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
-	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
-
-	/*
-	 * the bad block marker is readable only when we read the last codeword
-	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
-	 * helpers don't allow us to read BB from a nand chip with ECC
-	 * disabled (MTD_OPS_PLACE_OOB is set by default). use the block_bad
-	 * and block_markbad helpers until we permanently switch to using
-	 * MTD_OPS_RAW for all drivers (with the help of badblockbits)
-	 */
-	chip->block_bad		= qcom_nandc_block_bad;
-	chip->block_markbad	= qcom_nandc_block_markbad;
-
-	chip->controller = &nandc->controller;
-	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
-			 NAND_SKIP_BBTSCAN;
-
-	/* set up initial status value */
-	host->status = NAND_STATUS_READY | NAND_STATUS_WP;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (ret)
-		return ret;
-
-	ret = qcom_nand_host_setup(host);
-
-	return ret;
-}
-
-static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
-				  struct qcom_nand_host *host,
-				  struct device_node *dn)
-{
-	struct nand_chip *chip = &host->chip;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	int ret;
-
-	ret = nand_scan_tail(mtd);
-	if (ret)
-		return ret;
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret)
-		nand_cleanup(mtd_to_nand(mtd));
-
-	return ret;
-}
-
-static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
-{
-	struct device *dev = nandc->dev;
-	struct device_node *dn = dev->of_node, *child;
-	struct qcom_nand_host *host, *tmp;
-	int ret;
-
-	for_each_available_child_of_node(dn, child) {
-		host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
-		if (!host) {
-			of_node_put(child);
-			return -ENOMEM;
-		}
-
-		ret = qcom_nand_host_init(nandc, host, child);
-		if (ret) {
-			devm_kfree(dev, host);
-			continue;
-		}
-
-		list_add_tail(&host->node, &nandc->host_list);
-	}
-
-	if (list_empty(&nandc->host_list))
-		return -ENODEV;
-
-	if (nandc->props->is_bam) {
-		free_bam_transaction(nandc);
-		nandc->bam_txn = alloc_bam_transaction(nandc);
-		if (!nandc->bam_txn) {
-			dev_err(nandc->dev,
-				"failed to allocate bam transaction\n");
-			return -ENOMEM;
-		}
-	}
-
-	list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
-		ret = qcom_nand_mtd_register(nandc, host, child);
-		if (ret) {
-			list_del(&host->node);
-			devm_kfree(dev, host);
-		}
-	}
-
-	if (list_empty(&nandc->host_list))
-		return -ENODEV;
-
-	return 0;
-}
-
-/* parse custom DT properties here */
-static int qcom_nandc_parse_dt(struct platform_device *pdev)
-{
-	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
-	struct device_node *np = nandc->dev->of_node;
-	int ret;
-
-	if (!nandc->props->is_bam) {
-		ret = of_property_read_u32(np, "qcom,cmd-crci",
-					   &nandc->cmd_crci);
-		if (ret) {
-			dev_err(nandc->dev, "command CRCI unspecified\n");
-			return ret;
-		}
-
-		ret = of_property_read_u32(np, "qcom,data-crci",
-					   &nandc->data_crci);
-		if (ret) {
-			dev_err(nandc->dev, "data CRCI unspecified\n");
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int qcom_nandc_probe(struct platform_device *pdev)
-{
-	struct qcom_nand_controller *nandc;
-	const void *dev_data;
-	struct device *dev = &pdev->dev;
-	struct resource *res;
-	int ret;
-
-	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
-	if (!nandc)
-		return -ENOMEM;
-
-	platform_set_drvdata(pdev, nandc);
-	nandc->dev = dev;
-
-	dev_data = of_device_get_match_data(dev);
-	if (!dev_data) {
-		dev_err(&pdev->dev, "failed to get device data\n");
-		return -ENODEV;
-	}
-
-	nandc->props = dev_data;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nandc->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(nandc->base))
-		return PTR_ERR(nandc->base);
-
-	nandc->base_phys = res->start;
-	nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
-
-	nandc->core_clk = devm_clk_get(dev, "core");
-	if (IS_ERR(nandc->core_clk))
-		return PTR_ERR(nandc->core_clk);
-
-	nandc->aon_clk = devm_clk_get(dev, "aon");
-	if (IS_ERR(nandc->aon_clk))
-		return PTR_ERR(nandc->aon_clk);
-
-	ret = qcom_nandc_parse_dt(pdev);
-	if (ret)
-		return ret;
-
-	ret = qcom_nandc_alloc(nandc);
-	if (ret)
-		goto err_core_clk;
-
-	ret = clk_prepare_enable(nandc->core_clk);
-	if (ret)
-		goto err_core_clk;
-
-	ret = clk_prepare_enable(nandc->aon_clk);
-	if (ret)
-		goto err_aon_clk;
-
-	ret = qcom_nandc_setup(nandc);
-	if (ret)
-		goto err_setup;
-
-	ret = qcom_probe_nand_devices(nandc);
-	if (ret)
-		goto err_setup;
-
-	return 0;
-
-err_setup:
-	clk_disable_unprepare(nandc->aon_clk);
-err_aon_clk:
-	clk_disable_unprepare(nandc->core_clk);
-err_core_clk:
-	qcom_nandc_unalloc(nandc);
-
-	return ret;
-}
-
-static int qcom_nandc_remove(struct platform_device *pdev)
-{
-	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
-	struct qcom_nand_host *host;
-
-	list_for_each_entry(host, &nandc->host_list, node)
-		nand_release(nand_to_mtd(&host->chip));
-
-	qcom_nandc_unalloc(nandc);
-
-	clk_disable_unprepare(nandc->aon_clk);
-	clk_disable_unprepare(nandc->core_clk);
-
-	return 0;
-}
-
-static const struct qcom_nandc_props ipq806x_nandc_props = {
-	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
-	.is_bam = false,
-	.dev_cmd_reg_start = 0x0,
-};
-
-static const struct qcom_nandc_props ipq4019_nandc_props = {
-	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-	.is_bam = true,
-	.dev_cmd_reg_start = 0x0,
-};
-
-static const struct qcom_nandc_props ipq8074_nandc_props = {
-	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
-	.is_bam = true,
-	.dev_cmd_reg_start = 0x7000,
-};
-
-/*
- * data will hold a struct pointer containing more differences once we support
- * more controller variants
- */
-static const struct of_device_id qcom_nandc_of_match[] = {
-	{
-		.compatible = "qcom,ipq806x-nand",
-		.data = &ipq806x_nandc_props,
-	},
-	{
-		.compatible = "qcom,ipq4019-nand",
-		.data = &ipq4019_nandc_props,
-	},
-	{
-		.compatible = "qcom,ipq8074-nand",
-		.data = &ipq8074_nandc_props,
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
-
-static struct platform_driver qcom_nandc_driver = {
-	.driver = {
-		.name = "qcom-nandc",
-		.of_match_table = qcom_nandc_of_match,
-	},
-	.probe   = qcom_nandc_probe,
-	.remove  = qcom_nandc_remove,
-};
-module_platform_driver(qcom_nandc_driver);
-
-MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
-MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c
deleted file mode 100644
index 595635b9e9de..000000000000
--- a/drivers/mtd/nand/r852.c
+++ /dev/null
@@ -1,1079 +0,0 @@
-/*
- * Copyright © 2009 - Maxim Levitsky
- * driver for Ricoh xD readers
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <linux/sched.h>
-#include "sm_common.h"
-#include "r852.h"
-
-
-static bool r852_enable_dma = 1;
-module_param(r852_enable_dma, bool, S_IRUGO);
-MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)");
-
-static int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level (0-2)");
-
-/* read register */
-static inline uint8_t r852_read_reg(struct r852_device *dev, int address)
-{
-	uint8_t reg = readb(dev->mmio + address);
-	return reg;
-}
-
-/* write register */
-static inline void r852_write_reg(struct r852_device *dev,
-						int address, uint8_t value)
-{
-	writeb(value, dev->mmio + address);
-	mmiowb();
-}
-
-
-/* read dword sized register */
-static inline uint32_t r852_read_reg_dword(struct r852_device *dev, int address)
-{
-	uint32_t reg = le32_to_cpu(readl(dev->mmio + address));
-	return reg;
-}
-
-/* write dword sized register */
-static inline void r852_write_reg_dword(struct r852_device *dev,
-							int address, uint32_t value)
-{
-	writel(cpu_to_le32(value), dev->mmio + address);
-	mmiowb();
-}
-
-/* returns pointer to our private structure */
-static inline struct r852_device *r852_get_dev(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	return nand_get_controller_data(chip);
-}
-
-
-/* check if controller supports dma */
-static void r852_dma_test(struct r852_device *dev)
-{
-	dev->dma_usable = (r852_read_reg(dev, R852_DMA_CAP) &
-		(R852_DMA1 | R852_DMA2)) == (R852_DMA1 | R852_DMA2);
-
-	if (!dev->dma_usable)
-		message("Non dma capable device detected, dma disabled");
-
-	if (!r852_enable_dma) {
-		message("disabling dma on user request");
-		dev->dma_usable = 0;
-	}
-}
-
-/*
- * Enable dma. Enables ether first or second stage of the DMA,
- * Expects dev->dma_dir and dev->dma_state be set
- */
-static void r852_dma_enable(struct r852_device *dev)
-{
-	uint8_t dma_reg, dma_irq_reg;
-
-	/* Set up dma settings */
-	dma_reg = r852_read_reg_dword(dev, R852_DMA_SETTINGS);
-	dma_reg &= ~(R852_DMA_READ | R852_DMA_INTERNAL | R852_DMA_MEMORY);
-
-	if (dev->dma_dir)
-		dma_reg |= R852_DMA_READ;
-
-	if (dev->dma_state == DMA_INTERNAL) {
-		dma_reg |= R852_DMA_INTERNAL;
-		/* Precaution to make sure HW doesn't write */
-			/* to random kernel memory */
-		r852_write_reg_dword(dev, R852_DMA_ADDR,
-			cpu_to_le32(dev->phys_bounce_buffer));
-	} else {
-		dma_reg |= R852_DMA_MEMORY;
-		r852_write_reg_dword(dev, R852_DMA_ADDR,
-			cpu_to_le32(dev->phys_dma_addr));
-	}
-
-	/* Precaution: make sure write reached the device */
-	r852_read_reg_dword(dev, R852_DMA_ADDR);
-
-	r852_write_reg_dword(dev, R852_DMA_SETTINGS, dma_reg);
-
-	/* Set dma irq */
-	dma_irq_reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
-	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
-		dma_irq_reg |
-		R852_DMA_IRQ_INTERNAL |
-		R852_DMA_IRQ_ERROR |
-		R852_DMA_IRQ_MEMORY);
-}
-
-/*
- * Disable dma, called from the interrupt handler, which specifies
- * success of the operation via 'error' argument
- */
-static void r852_dma_done(struct r852_device *dev, int error)
-{
-	WARN_ON(dev->dma_stage == 0);
-
-	r852_write_reg_dword(dev, R852_DMA_IRQ_STA,
-			r852_read_reg_dword(dev, R852_DMA_IRQ_STA));
-
-	r852_write_reg_dword(dev, R852_DMA_SETTINGS, 0);
-	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, 0);
-
-	/* Precaution to make sure HW doesn't write to random kernel memory */
-	r852_write_reg_dword(dev, R852_DMA_ADDR,
-		cpu_to_le32(dev->phys_bounce_buffer));
-	r852_read_reg_dword(dev, R852_DMA_ADDR);
-
-	dev->dma_error = error;
-	dev->dma_stage = 0;
-
-	if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer)
-		pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN,
-			dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-}
-
-/*
- * Wait, till dma is done, which includes both phases of it
- */
-static int r852_dma_wait(struct r852_device *dev)
-{
-	long timeout = wait_for_completion_timeout(&dev->dma_done,
-				msecs_to_jiffies(1000));
-	if (!timeout) {
-		dbg("timeout waiting for DMA interrupt");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-/*
- * Read/Write one page using dma. Only pages can be read (512 bytes)
-*/
-static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
-{
-	int bounce = 0;
-	unsigned long flags;
-	int error;
-
-	dev->dma_error = 0;
-
-	/* Set dma direction */
-	dev->dma_dir = do_read;
-	dev->dma_stage = 1;
-	reinit_completion(&dev->dma_done);
-
-	dbg_verbose("doing dma %s ", do_read ? "read" : "write");
-
-	/* Set initial dma state: for reading first fill on board buffer,
-	  from device, for writes first fill the buffer  from memory*/
-	dev->dma_state = do_read ? DMA_INTERNAL : DMA_MEMORY;
-
-	/* if incoming buffer is not page aligned, we should do bounce */
-	if ((unsigned long)buf & (R852_DMA_LEN-1))
-		bounce = 1;
-
-	if (!bounce) {
-		dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf,
-			R852_DMA_LEN,
-			(do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
-
-		if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr))
-			bounce = 1;
-	}
-
-	if (bounce) {
-		dbg_verbose("dma: using bounce buffer");
-		dev->phys_dma_addr = dev->phys_bounce_buffer;
-		if (!do_read)
-			memcpy(dev->bounce_buffer, buf, R852_DMA_LEN);
-	}
-
-	/* Enable DMA */
-	spin_lock_irqsave(&dev->irqlock, flags);
-	r852_dma_enable(dev);
-	spin_unlock_irqrestore(&dev->irqlock, flags);
-
-	/* Wait till complete */
-	error = r852_dma_wait(dev);
-
-	if (error) {
-		r852_dma_done(dev, error);
-		return;
-	}
-
-	if (do_read && bounce)
-		memcpy((void *)buf, dev->bounce_buffer, R852_DMA_LEN);
-}
-
-/*
- * Program data lines of the nand chip to send data to it
- */
-static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-	uint32_t reg;
-
-	/* Don't allow any access to hardware if we suspect card removal */
-	if (dev->card_unstable)
-		return;
-
-	/* Special case for whole sector read */
-	if (len == R852_DMA_LEN && dev->dma_usable) {
-		r852_do_dma(dev, (uint8_t *)buf, 0);
-		return;
-	}
-
-	/* write DWORD chinks - faster */
-	while (len >= 4) {
-		reg = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-		r852_write_reg_dword(dev, R852_DATALINE, reg);
-		buf += 4;
-		len -= 4;
-
-	}
-
-	/* write rest */
-	while (len > 0) {
-		r852_write_reg(dev, R852_DATALINE, *buf++);
-		len--;
-	}
-}
-
-/*
- * Read data lines of the nand chip to retrieve data
- */
-static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-	uint32_t reg;
-
-	if (dev->card_unstable) {
-		/* since we can't signal error here, at least, return
-			predictable buffer */
-		memset(buf, 0, len);
-		return;
-	}
-
-	/* special case for whole sector read */
-	if (len == R852_DMA_LEN && dev->dma_usable) {
-		r852_do_dma(dev, buf, 1);
-		return;
-	}
-
-	/* read in dword sized chunks */
-	while (len >= 4) {
-
-		reg = r852_read_reg_dword(dev, R852_DATALINE);
-		*buf++ = reg & 0xFF;
-		*buf++ = (reg >> 8) & 0xFF;
-		*buf++ = (reg >> 16) & 0xFF;
-		*buf++ = (reg >> 24) & 0xFF;
-		len -= 4;
-	}
-
-	/* read the reset by bytes */
-	while (len--)
-		*buf++ = r852_read_reg(dev, R852_DATALINE);
-}
-
-/*
- * Read one byte from nand chip
- */
-static uint8_t r852_read_byte(struct mtd_info *mtd)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-
-	/* Same problem as in r852_read_buf.... */
-	if (dev->card_unstable)
-		return 0;
-
-	return r852_read_reg(dev, R852_DATALINE);
-}
-
-/*
- * Control several chip lines & send commands
- */
-static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-
-	if (dev->card_unstable)
-		return;
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-
-		dev->ctlreg &= ~(R852_CTL_DATA | R852_CTL_COMMAND |
-				 R852_CTL_ON | R852_CTL_CARDENABLE);
-
-		if (ctrl & NAND_ALE)
-			dev->ctlreg |= R852_CTL_DATA;
-
-		if (ctrl & NAND_CLE)
-			dev->ctlreg |= R852_CTL_COMMAND;
-
-		if (ctrl & NAND_NCE)
-			dev->ctlreg |= (R852_CTL_CARDENABLE | R852_CTL_ON);
-		else
-			dev->ctlreg &= ~R852_CTL_WRITE;
-
-		/* when write is stareted, enable write access */
-		if (dat == NAND_CMD_ERASE1)
-			dev->ctlreg |= R852_CTL_WRITE;
-
-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
-	}
-
-	 /* HACK: NAND_CMD_SEQIN is called without NAND_CTRL_CHANGE, but we need
-		to set write mode */
-	if (dat == NAND_CMD_SEQIN && (dev->ctlreg & R852_CTL_COMMAND)) {
-		dev->ctlreg |= R852_CTL_WRITE;
-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
-	}
-
-	if (dat != NAND_CMD_NONE)
-		r852_write_reg(dev, R852_DATALINE, dat);
-}
-
-/*
- * Wait till card is ready.
- * based on nand_wait, but returns errors on DMA error
- */
-static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct r852_device *dev = nand_get_controller_data(chip);
-
-	unsigned long timeout;
-	u8 status;
-
-	timeout = jiffies + (chip->state == FL_ERASING ?
-		msecs_to_jiffies(400) : msecs_to_jiffies(20));
-
-	while (time_before(jiffies, timeout))
-		if (chip->dev_ready(mtd))
-			break;
-
-	nand_status_op(chip, &status);
-
-	/* Unfortunelly, no way to send detailed error status... */
-	if (dev->dma_error) {
-		status |= NAND_STATUS_FAIL;
-		dev->dma_error = 0;
-	}
-	return status;
-}
-
-/*
- * Check if card is ready
- */
-
-static int r852_ready(struct mtd_info *mtd)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-	return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
-}
-
-
-/*
- * Set ECC engine mode
-*/
-
-static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-
-	if (dev->card_unstable)
-		return;
-
-	switch (mode) {
-	case NAND_ECC_READ:
-	case NAND_ECC_WRITE:
-		/* enable ecc generation/check*/
-		dev->ctlreg |= R852_CTL_ECC_ENABLE;
-
-		/* flush ecc buffer */
-		r852_write_reg(dev, R852_CTL,
-			dev->ctlreg | R852_CTL_ECC_ACCESS);
-
-		r852_read_reg_dword(dev, R852_DATALINE);
-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
-		return;
-
-	case NAND_ECC_READSYN:
-		/* disable ecc generation */
-		dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
-		r852_write_reg(dev, R852_CTL, dev->ctlreg);
-	}
-}
-
-/*
- * Calculate ECC, only used for writes
- */
-
-static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
-							uint8_t *ecc_code)
-{
-	struct r852_device *dev = r852_get_dev(mtd);
-	struct sm_oob *oob = (struct sm_oob *)ecc_code;
-	uint32_t ecc1, ecc2;
-
-	if (dev->card_unstable)
-		return 0;
-
-	dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
-	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
-
-	ecc1 = r852_read_reg_dword(dev, R852_DATALINE);
-	ecc2 = r852_read_reg_dword(dev, R852_DATALINE);
-
-	oob->ecc1[0] = (ecc1) & 0xFF;
-	oob->ecc1[1] = (ecc1 >> 8) & 0xFF;
-	oob->ecc1[2] = (ecc1 >> 16) & 0xFF;
-
-	oob->ecc2[0] = (ecc2) & 0xFF;
-	oob->ecc2[1] = (ecc2 >> 8) & 0xFF;
-	oob->ecc2[2] = (ecc2 >> 16) & 0xFF;
-
-	r852_write_reg(dev, R852_CTL, dev->ctlreg);
-	return 0;
-}
-
-/*
- * Correct the data using ECC, hw did almost everything for us
- */
-
-static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
-				uint8_t *read_ecc, uint8_t *calc_ecc)
-{
-	uint32_t ecc_reg;
-	uint8_t ecc_status, err_byte;
-	int i, error = 0;
-
-	struct r852_device *dev = r852_get_dev(mtd);
-
-	if (dev->card_unstable)
-		return 0;
-
-	if (dev->dma_error) {
-		dev->dma_error = 0;
-		return -EIO;
-	}
-
-	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
-	ecc_reg = r852_read_reg_dword(dev, R852_DATALINE);
-	r852_write_reg(dev, R852_CTL, dev->ctlreg);
-
-	for (i = 0 ; i <= 1 ; i++) {
-
-		ecc_status = (ecc_reg >> 8) & 0xFF;
-
-		/* ecc uncorrectable error */
-		if (ecc_status & R852_ECC_FAIL) {
-			dbg("ecc: unrecoverable error, in half %d", i);
-			error = -EBADMSG;
-			goto exit;
-		}
-
-		/* correctable error */
-		if (ecc_status & R852_ECC_CORRECTABLE) {
-
-			err_byte = ecc_reg & 0xFF;
-			dbg("ecc: recoverable error, "
-				"in half %d, byte %d, bit %d", i,
-				err_byte, ecc_status & R852_ECC_ERR_BIT_MSK);
-
-			dat[err_byte] ^=
-				1 << (ecc_status & R852_ECC_ERR_BIT_MSK);
-			error++;
-		}
-
-		dat += 256;
-		ecc_reg >>= 16;
-	}
-exit:
-	return error;
-}
-
-/*
- * This is copy of nand_read_oob_std
- * nand_read_oob_syndrome assumes we can send column address - we can't
- */
-static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			     int page)
-{
-	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
-}
-
-/*
- * Start the nand engine
- */
-
-static void r852_engine_enable(struct r852_device *dev)
-{
-	if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
-		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
-		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
-	} else {
-		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
-		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
-	}
-	msleep(300);
-	r852_write_reg(dev, R852_CTL, 0);
-}
-
-
-/*
- * Stop the nand engine
- */
-
-static void r852_engine_disable(struct r852_device *dev)
-{
-	r852_write_reg_dword(dev, R852_HW, 0);
-	r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
-}
-
-/*
- * Test if card is present
- */
-
-static void r852_card_update_present(struct r852_device *dev)
-{
-	unsigned long flags;
-	uint8_t reg;
-
-	spin_lock_irqsave(&dev->irqlock, flags);
-	reg = r852_read_reg(dev, R852_CARD_STA);
-	dev->card_detected = !!(reg & R852_CARD_STA_PRESENT);
-	spin_unlock_irqrestore(&dev->irqlock, flags);
-}
-
-/*
- * Update card detection IRQ state according to current card state
- * which is read in r852_card_update_present
- */
-static void r852_update_card_detect(struct r852_device *dev)
-{
-	int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
-	dev->card_unstable = 0;
-
-	card_detect_reg &= ~(R852_CARD_IRQ_REMOVE | R852_CARD_IRQ_INSERT);
-	card_detect_reg |= R852_CARD_IRQ_GENABLE;
-
-	card_detect_reg |= dev->card_detected ?
-		R852_CARD_IRQ_REMOVE : R852_CARD_IRQ_INSERT;
-
-	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
-}
-
-static ssize_t r852_media_type_show(struct device *sys_dev,
-			struct device_attribute *attr, char *buf)
-{
-	struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
-	struct r852_device *dev = r852_get_dev(mtd);
-	char *data = dev->sm ? "smartmedia" : "xd";
-
-	strcpy(buf, data);
-	return strlen(data);
-}
-
-static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
-
-
-/* Detect properties of card in slot */
-static void r852_update_media_status(struct r852_device *dev)
-{
-	uint8_t reg;
-	unsigned long flags;
-	int readonly;
-
-	spin_lock_irqsave(&dev->irqlock, flags);
-	if (!dev->card_detected) {
-		message("card removed");
-		spin_unlock_irqrestore(&dev->irqlock, flags);
-		return ;
-	}
-
-	readonly  = r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_RO;
-	reg = r852_read_reg(dev, R852_DMA_CAP);
-	dev->sm = (reg & (R852_DMA1 | R852_DMA2)) && (reg & R852_SMBIT);
-
-	message("detected %s %s card in slot",
-		dev->sm ? "SmartMedia" : "xD",
-		readonly ? "readonly" : "writeable");
-
-	dev->readonly = readonly;
-	spin_unlock_irqrestore(&dev->irqlock, flags);
-}
-
-/*
- * Register the nand device
- * Called when the card is detected
- */
-static int r852_register_nand_device(struct r852_device *dev)
-{
-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
-
-	WARN_ON(dev->card_registred);
-
-	mtd->dev.parent = &dev->pci_dev->dev;
-
-	if (dev->readonly)
-		dev->chip->options |= NAND_ROM;
-
-	r852_engine_enable(dev);
-
-	if (sm_register_device(mtd, dev->sm))
-		goto error1;
-
-	if (device_create_file(&mtd->dev, &dev_attr_media_type)) {
-		message("can't create media type sysfs attribute");
-		goto error3;
-	}
-
-	dev->card_registred = 1;
-	return 0;
-error3:
-	nand_release(mtd);
-error1:
-	/* Force card redetect */
-	dev->card_detected = 0;
-	return -1;
-}
-
-/*
- * Unregister the card
- */
-
-static void r852_unregister_nand_device(struct r852_device *dev)
-{
-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
-
-	if (!dev->card_registred)
-		return;
-
-	device_remove_file(&mtd->dev, &dev_attr_media_type);
-	nand_release(mtd);
-	r852_engine_disable(dev);
-	dev->card_registred = 0;
-}
-
-/* Card state updater */
-static void r852_card_detect_work(struct work_struct *work)
-{
-	struct r852_device *dev =
-		container_of(work, struct r852_device, card_detect_work.work);
-
-	r852_card_update_present(dev);
-	r852_update_card_detect(dev);
-	dev->card_unstable = 0;
-
-	/* False alarm */
-	if (dev->card_detected == dev->card_registred)
-		goto exit;
-
-	/* Read media properties */
-	r852_update_media_status(dev);
-
-	/* Register the card */
-	if (dev->card_detected)
-		r852_register_nand_device(dev);
-	else
-		r852_unregister_nand_device(dev);
-exit:
-	r852_update_card_detect(dev);
-}
-
-/* Ack + disable IRQ generation */
-static void r852_disable_irqs(struct r852_device *dev)
-{
-	uint8_t reg;
-	reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
-	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, reg & ~R852_CARD_IRQ_MASK);
-
-	reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
-	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
-					reg & ~R852_DMA_IRQ_MASK);
-
-	r852_write_reg(dev, R852_CARD_IRQ_STA, R852_CARD_IRQ_MASK);
-	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, R852_DMA_IRQ_MASK);
-}
-
-/* Interrupt handler */
-static irqreturn_t r852_irq(int irq, void *data)
-{
-	struct r852_device *dev = (struct r852_device *)data;
-
-	uint8_t card_status, dma_status;
-	unsigned long flags;
-	irqreturn_t ret = IRQ_NONE;
-
-	spin_lock_irqsave(&dev->irqlock, flags);
-
-	/* handle card detection interrupts first */
-	card_status = r852_read_reg(dev, R852_CARD_IRQ_STA);
-	r852_write_reg(dev, R852_CARD_IRQ_STA, card_status);
-
-	if (card_status & (R852_CARD_IRQ_INSERT|R852_CARD_IRQ_REMOVE)) {
-
-		ret = IRQ_HANDLED;
-		dev->card_detected = !!(card_status & R852_CARD_IRQ_INSERT);
-
-		/* we shouldn't receive any interrupts if we wait for card
-			to settle */
-		WARN_ON(dev->card_unstable);
-
-		/* disable irqs while card is unstable */
-		/* this will timeout DMA if active, but better that garbage */
-		r852_disable_irqs(dev);
-
-		if (dev->card_unstable)
-			goto out;
-
-		/* let, card state to settle a bit, and then do the work */
-		dev->card_unstable = 1;
-		queue_delayed_work(dev->card_workqueue,
-			&dev->card_detect_work, msecs_to_jiffies(100));
-		goto out;
-	}
-
-
-	/* Handle dma interrupts */
-	dma_status = r852_read_reg_dword(dev, R852_DMA_IRQ_STA);
-	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, dma_status);
-
-	if (dma_status & R852_DMA_IRQ_MASK) {
-
-		ret = IRQ_HANDLED;
-
-		if (dma_status & R852_DMA_IRQ_ERROR) {
-			dbg("received dma error IRQ");
-			r852_dma_done(dev, -EIO);
-			complete(&dev->dma_done);
-			goto out;
-		}
-
-		/* received DMA interrupt out of nowhere? */
-		WARN_ON_ONCE(dev->dma_stage == 0);
-
-		if (dev->dma_stage == 0)
-			goto out;
-
-		/* done device access */
-		if (dev->dma_state == DMA_INTERNAL &&
-				(dma_status & R852_DMA_IRQ_INTERNAL)) {
-
-			dev->dma_state = DMA_MEMORY;
-			dev->dma_stage++;
-		}
-
-		/* done memory DMA */
-		if (dev->dma_state == DMA_MEMORY &&
-				(dma_status & R852_DMA_IRQ_MEMORY)) {
-			dev->dma_state = DMA_INTERNAL;
-			dev->dma_stage++;
-		}
-
-		/* Enable 2nd half of dma dance */
-		if (dev->dma_stage == 2)
-			r852_dma_enable(dev);
-
-		/* Operation done */
-		if (dev->dma_stage == 3) {
-			r852_dma_done(dev, 0);
-			complete(&dev->dma_done);
-		}
-		goto out;
-	}
-
-	/* Handle unknown interrupts */
-	if (dma_status)
-		dbg("bad dma IRQ status = %x", dma_status);
-
-	if (card_status & ~R852_CARD_STA_CD)
-		dbg("strange card status = %x", card_status);
-
-out:
-	spin_unlock_irqrestore(&dev->irqlock, flags);
-	return ret;
-}
-
-static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
-{
-	int error;
-	struct nand_chip *chip;
-	struct r852_device *dev;
-
-	/* pci initialization */
-	error = pci_enable_device(pci_dev);
-
-	if (error)
-		goto error1;
-
-	pci_set_master(pci_dev);
-
-	error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
-	if (error)
-		goto error2;
-
-	error = pci_request_regions(pci_dev, DRV_NAME);
-
-	if (error)
-		goto error3;
-
-	error = -ENOMEM;
-
-	/* init nand chip, but register it only on card insert */
-	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
-
-	if (!chip)
-		goto error4;
-
-	/* commands */
-	chip->cmd_ctrl = r852_cmdctl;
-	chip->waitfunc = r852_wait;
-	chip->dev_ready = r852_ready;
-
-	/* I/O */
-	chip->read_byte = r852_read_byte;
-	chip->read_buf = r852_read_buf;
-	chip->write_buf = r852_write_buf;
-
-	/* ecc */
-	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
-	chip->ecc.size = R852_DMA_LEN;
-	chip->ecc.bytes = SM_OOB_SIZE;
-	chip->ecc.strength = 2;
-	chip->ecc.hwctl = r852_ecc_hwctl;
-	chip->ecc.calculate = r852_ecc_calculate;
-	chip->ecc.correct = r852_ecc_correct;
-
-	/* TODO: hack */
-	chip->ecc.read_oob = r852_read_oob;
-
-	/* init our device structure */
-	dev = kzalloc(sizeof(struct r852_device), GFP_KERNEL);
-
-	if (!dev)
-		goto error5;
-
-	nand_set_controller_data(chip, dev);
-	dev->chip = chip;
-	dev->pci_dev = pci_dev;
-	pci_set_drvdata(pci_dev, dev);
-
-	dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN,
-		&dev->phys_bounce_buffer);
-
-	if (!dev->bounce_buffer)
-		goto error6;
-
-
-	error = -ENODEV;
-	dev->mmio = pci_ioremap_bar(pci_dev, 0);
-
-	if (!dev->mmio)
-		goto error7;
-
-	error = -ENOMEM;
-	dev->tmp_buffer = kzalloc(SM_SECTOR_SIZE, GFP_KERNEL);
-
-	if (!dev->tmp_buffer)
-		goto error8;
-
-	init_completion(&dev->dma_done);
-
-	dev->card_workqueue = create_freezable_workqueue(DRV_NAME);
-
-	if (!dev->card_workqueue)
-		goto error9;
-
-	INIT_DELAYED_WORK(&dev->card_detect_work, r852_card_detect_work);
-
-	/* shutdown everything - precation */
-	r852_engine_disable(dev);
-	r852_disable_irqs(dev);
-
-	r852_dma_test(dev);
-
-	dev->irq = pci_dev->irq;
-	spin_lock_init(&dev->irqlock);
-
-	dev->card_detected = 0;
-	r852_card_update_present(dev);
-
-	/*register irq handler*/
-	error = -ENODEV;
-	if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED,
-			  DRV_NAME, dev))
-		goto error10;
-
-	/* kick initial present test */
-	queue_delayed_work(dev->card_workqueue,
-		&dev->card_detect_work, 0);
-
-
-	printk(KERN_NOTICE DRV_NAME ": driver loaded successfully\n");
-	return 0;
-
-error10:
-	destroy_workqueue(dev->card_workqueue);
-error9:
-	kfree(dev->tmp_buffer);
-error8:
-	pci_iounmap(pci_dev, dev->mmio);
-error7:
-	pci_free_consistent(pci_dev, R852_DMA_LEN,
-		dev->bounce_buffer, dev->phys_bounce_buffer);
-error6:
-	kfree(dev);
-error5:
-	kfree(chip);
-error4:
-	pci_release_regions(pci_dev);
-error3:
-error2:
-	pci_disable_device(pci_dev);
-error1:
-	return error;
-}
-
-static void r852_remove(struct pci_dev *pci_dev)
-{
-	struct r852_device *dev = pci_get_drvdata(pci_dev);
-
-	/* Stop detect workqueue -
-		we are going to unregister the device anyway*/
-	cancel_delayed_work_sync(&dev->card_detect_work);
-	destroy_workqueue(dev->card_workqueue);
-
-	/* Unregister the device, this might make more IO */
-	r852_unregister_nand_device(dev);
-
-	/* Stop interrupts */
-	r852_disable_irqs(dev);
-	free_irq(dev->irq, dev);
-
-	/* Cleanup */
-	kfree(dev->tmp_buffer);
-	pci_iounmap(pci_dev, dev->mmio);
-	pci_free_consistent(pci_dev, R852_DMA_LEN,
-		dev->bounce_buffer, dev->phys_bounce_buffer);
-
-	kfree(dev->chip);
-	kfree(dev);
-
-	/* Shutdown the PCI device */
-	pci_release_regions(pci_dev);
-	pci_disable_device(pci_dev);
-}
-
-static void r852_shutdown(struct pci_dev *pci_dev)
-{
-	struct r852_device *dev = pci_get_drvdata(pci_dev);
-
-	cancel_delayed_work_sync(&dev->card_detect_work);
-	r852_disable_irqs(dev);
-	synchronize_irq(dev->irq);
-	pci_disable_device(pci_dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int r852_suspend(struct device *device)
-{
-	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
-
-	if (dev->ctlreg & R852_CTL_CARDENABLE)
-		return -EBUSY;
-
-	/* First make sure the detect work is gone */
-	cancel_delayed_work_sync(&dev->card_detect_work);
-
-	/* Turn off the interrupts and stop the device */
-	r852_disable_irqs(dev);
-	r852_engine_disable(dev);
-
-	/* If card was pulled off just during the suspend, which is very
-		unlikely, we will remove it on resume, it too late now
-		anyway... */
-	dev->card_unstable = 0;
-	return 0;
-}
-
-static int r852_resume(struct device *device)
-{
-	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
-	struct mtd_info *mtd = nand_to_mtd(dev->chip);
-
-	r852_disable_irqs(dev);
-	r852_card_update_present(dev);
-	r852_engine_disable(dev);
-
-
-	/* If card status changed, just do the work */
-	if (dev->card_detected != dev->card_registred) {
-		dbg("card was %s during low power state",
-			dev->card_detected ? "added" : "removed");
-
-		queue_delayed_work(dev->card_workqueue,
-		&dev->card_detect_work, msecs_to_jiffies(1000));
-		return 0;
-	}
-
-	/* Otherwise, initialize the card */
-	if (dev->card_registred) {
-		r852_engine_enable(dev);
-		dev->chip->select_chip(mtd, 0);
-		nand_reset_op(dev->chip);
-		dev->chip->select_chip(mtd, -1);
-	}
-
-	/* Program card detection IRQ */
-	r852_update_card_detect(dev);
-	return 0;
-}
-#endif
-
-static const struct pci_device_id r852_pci_id_tbl[] = {
-
-	{ PCI_VDEVICE(RICOH, 0x0852), },
-	{ },
-};
-
-MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl);
-
-static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume);
-
-static struct pci_driver r852_pci_driver = {
-	.name		= DRV_NAME,
-	.id_table	= r852_pci_id_tbl,
-	.probe		= r852_probe,
-	.remove		= r852_remove,
-	.shutdown	= r852_shutdown,
-	.driver.pm	= &r852_pm_ops,
-};
-
-module_pci_driver(r852_pci_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
-MODULE_DESCRIPTION("Ricoh 85xx xD/smartmedia card reader driver");
diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h
deleted file mode 100644
index 8713c57f6207..000000000000
--- a/drivers/mtd/nand/r852.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright © 2009 - Maxim Levitsky
- * driver for Ricoh xD readers
- *
- * 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/pci.h>
-#include <linux/completion.h>
-#include <linux/workqueue.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/spinlock.h>
-
-
-/* nand interface + ecc
-   byte write/read does one cycle on nand data lines.
-   dword write/read does 4 cycles
-   if R852_CTL_ECC_ACCESS is set in R852_CTL, then dword read reads
-   results of ecc correction, if DMA read was done before.
-   If write was done two dword reads read generated ecc checksums
-*/
-#define	R852_DATALINE		0x00
-
-/* control register */
-#define R852_CTL		0x04
-#define R852_CTL_COMMAND 	0x01	/* send command (#CLE)*/
-#define R852_CTL_DATA		0x02	/* read/write data (#ALE)*/
-#define R852_CTL_ON		0x04	/* only seem to controls the hd led, */
-					/* but has to be set on start...*/
-#define R852_CTL_RESET		0x08	/* unknown, set only on start once*/
-#define R852_CTL_CARDENABLE	0x10	/* probably (#CE) - always set*/
-#define R852_CTL_ECC_ENABLE	0x20	/* enable ecc engine */
-#define R852_CTL_ECC_ACCESS	0x40	/* read/write ecc via reg #0*/
-#define R852_CTL_WRITE		0x80	/* set when performing writes (#WP) */
-
-/* card detection status */
-#define R852_CARD_STA		0x05
-
-#define R852_CARD_STA_CD	0x01	/* state of #CD line, same as 0x04 */
-#define R852_CARD_STA_RO	0x02	/* card is readonly */
-#define R852_CARD_STA_PRESENT	0x04	/* card is present (#CD) */
-#define R852_CARD_STA_ABSENT	0x08	/* card is absent */
-#define R852_CARD_STA_BUSY	0x80	/* card is busy - (#R/B) */
-
-/* card detection irq status & enable*/
-#define R852_CARD_IRQ_STA	0x06	/* IRQ status */
-#define R852_CARD_IRQ_ENABLE	0x07	/* IRQ enable */
-
-#define R852_CARD_IRQ_CD	0x01	/* fire when #CD lights, same as 0x04*/
-#define R852_CARD_IRQ_REMOVE	0x04	/* detect card removal */
-#define R852_CARD_IRQ_INSERT	0x08	/* detect card insert */
-#define R852_CARD_IRQ_UNK1	0x10	/* unknown */
-#define R852_CARD_IRQ_GENABLE	0x80	/* general enable */
-#define R852_CARD_IRQ_MASK	0x1D
-
-
-
-/* hardware enable */
-#define R852_HW			0x08
-#define R852_HW_ENABLED		0x01	/* hw enabled */
-#define R852_HW_UNKNOWN		0x80
-
-
-/* dma capabilities */
-#define R852_DMA_CAP		0x09
-#define R852_SMBIT		0x20	/* if set with bit #6 or bit #7, then */
-					/* hw is smartmedia */
-#define R852_DMA1		0x40	/* if set w/bit #7, dma is supported */
-#define R852_DMA2		0x80	/* if set w/bit #6, dma is supported */
-
-
-/* physical DMA address - 32 bit value*/
-#define R852_DMA_ADDR		0x0C
-
-
-/* dma settings */
-#define R852_DMA_SETTINGS	0x10
-#define R852_DMA_MEMORY		0x01	/* (memory <-> internal hw buffer) */
-#define R852_DMA_READ		0x02	/* 0 = write, 1 = read */
-#define R852_DMA_INTERNAL	0x04	/* (internal hw buffer <-> card) */
-
-/* dma IRQ status */
-#define R852_DMA_IRQ_STA		0x14
-
-/* dma IRQ enable */
-#define R852_DMA_IRQ_ENABLE	0x18
-
-#define R852_DMA_IRQ_MEMORY	0x01	/* (memory <-> internal hw buffer) */
-#define R852_DMA_IRQ_ERROR	0x02	/* error did happen */
-#define R852_DMA_IRQ_INTERNAL	0x04	/* (internal hw buffer <-> card) */
-#define R852_DMA_IRQ_MASK	0x07	/* mask of all IRQ bits */
-
-
-/* ECC syndrome format - read from reg #0 will return two copies of these for
-   each half of the page.
-   first byte is error byte location, and second, bit location + flags */
-#define R852_ECC_ERR_BIT_MSK	0x07	/* error bit location */
-#define R852_ECC_CORRECT		0x10	/* no errors - (guessed) */
-#define R852_ECC_CORRECTABLE	0x20	/* correctable error exist */
-#define R852_ECC_FAIL		0x40	/* non correctable error detected */
-
-#define R852_DMA_LEN		512
-
-#define DMA_INTERNAL	0
-#define DMA_MEMORY	1
-
-struct r852_device {
-	void __iomem *mmio;		/* mmio */
-	struct nand_chip *chip;		/* nand chip backpointer */
-	struct pci_dev *pci_dev;	/* pci backpointer */
-
-	/* dma area */
-	dma_addr_t phys_dma_addr;	/* bus address of buffer*/
-	struct completion dma_done;	/* data transfer done */
-
-	dma_addr_t phys_bounce_buffer;	/* bus address of bounce buffer */
-	uint8_t *bounce_buffer;		/* virtual address of bounce buffer */
-
-	int dma_dir;			/* 1 = read, 0 = write */
-	int dma_stage;			/* 0 - idle, 1 - first step,
-					   2 - second step */
-
-	int dma_state;			/* 0 = internal, 1 = memory */
-	int dma_error;			/* dma errors */
-	int dma_usable;			/* is it possible to use dma */
-
-	/* card status area */
-	struct delayed_work card_detect_work;
-	struct workqueue_struct *card_workqueue;
-	int card_registred;		/* card registered with mtd */
-	int card_detected;		/* card detected in slot */
-	int card_unstable;		/* whenever the card is inserted,
-					   is not known yet */
-	int readonly;			/* card is readonly */
-	int sm;				/* Is card smartmedia */
-
-	/* interrupt handling */
-	spinlock_t irqlock;		/* IRQ protecting lock */
-	int irq;			/* irq num */
-	/* misc */
-	void *tmp_buffer;		/* temporary buffer */
-	uint8_t ctlreg;			/* cached contents of control reg */
-};
-
-#define DRV_NAME "r852"
-
-
-#define dbg(format, ...) \
-	if (debug) \
-		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
-
-#define dbg_verbose(format, ...) \
-	if (debug > 1) \
-		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
-
-
-#define message(format, ...) \
-	printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
new file mode 100644
index 000000000000..736ac887303c
--- /dev/null
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -0,0 +1,580 @@
+config MTD_NAND_ECC
+	tristate
+
+config MTD_NAND_ECC_SMC
+	bool "NAND ECC Smart Media byte order"
+	depends on MTD_NAND_ECC
+	default n
+	help
+	  Software ECC according to the Smart Media Specification.
+	  The original Linux implementation had byte 0 and 1 swapped.
+
+
+menuconfig MTD_NAND
+	tristate "NAND Device Support"
+	depends on MTD
+	select MTD_NAND_ECC
+	help
+	  This enables support for accessing all type of NAND flash
+	  devices. For further information see
+	  <http://www.linux-mtd.infradead.org/doc/nand.html>.
+
+if MTD_NAND
+
+config MTD_NAND_BCH
+	tristate
+	select BCH
+	depends on MTD_NAND_ECC_BCH
+	default MTD_NAND
+
+config MTD_NAND_ECC_BCH
+	bool "Support software BCH ECC"
+	default n
+	help
+	  This enables support for software BCH error correction. Binary BCH
+	  codes are more powerful and cpu intensive than traditional Hamming
+	  ECC codes. They are used with NAND devices requiring more than 1 bit
+	  of error correction.
+
+config MTD_SM_COMMON
+	tristate
+	default n
+
+config MTD_NAND_DENALI
+	tristate
+
+config MTD_NAND_DENALI_PCI
+        tristate "Support Denali NAND controller on Intel Moorestown"
+	select MTD_NAND_DENALI
+	depends on HAS_DMA && PCI
+        help
+          Enable the driver for NAND flash on Intel Moorestown, using the
+          Denali NAND controller core.
+
+config MTD_NAND_DENALI_DT
+	tristate "Support Denali NAND controller as a DT device"
+	select MTD_NAND_DENALI
+	depends on HAS_DMA && HAVE_CLK && OF
+	help
+	  Enable the driver for NAND flash on platforms using a Denali NAND
+	  controller as a DT device.
+
+config MTD_NAND_GPIO
+	tristate "GPIO assisted NAND Flash driver"
+	depends on GPIOLIB || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  This enables a NAND flash driver where control signals are
+	  connected to GPIO pins, and commands and data are communicated
+	  via a memory mapped interface.
+
+config MTD_NAND_AMS_DELTA
+	tristate "NAND Flash device on Amstrad E3"
+	depends on MACH_AMS_DELTA
+	default y
+	help
+	  Support for NAND flash on Amstrad E3 (Delta).
+
+config MTD_NAND_OMAP2
+	tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
+	depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
+	help
+          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
+	  and Keystone platforms.
+
+config MTD_NAND_OMAP_BCH
+	depends on MTD_NAND_OMAP2
+	bool "Support hardware based BCH error correction"
+	default n
+	select BCH
+	help
+	  This config enables the ELM hardware engine, which can be used to
+	  locate and correct errors when using BCH ECC scheme. This offloads
+	  the cpu from doing ECC error searching and correction. However some
+	  legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
+	  so this is optional for them.
+
+config MTD_NAND_OMAP_BCH_BUILD
+	def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
+
+config MTD_NAND_RICOH
+	tristate "Ricoh xD card reader"
+	default n
+	depends on PCI
+	select MTD_SM_COMMON
+	help
+	  Enable support for Ricoh R5C852 xD card reader
+	  You also need to enable ether
+	  NAND SSFDC (SmartMedia) read only translation layer' or new
+	  expermental, readwrite
+	  'SmartMedia/xD new translation layer'
+
+config MTD_NAND_AU1550
+	tristate "Au1550/1200 NAND support"
+	depends on MIPS_ALCHEMY
+	help
+	  This enables the driver for the NAND flash controller on the
+	  AMD/Alchemy 1550 SOC.
+
+config MTD_NAND_BF5XX
+	tristate "Blackfin on-chip NAND Flash Controller driver"
+	depends on BF54x || BF52x
+	help
+	  This enables the Blackfin on-chip NAND flash controller
+
+	  No board specific support is done by this driver, each board
+	  must advertise a platform_device for the driver to attach.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called bf5xx-nand.
+
+config MTD_NAND_BF5XX_HWECC
+	bool "BF5XX NAND Hardware ECC"
+	default y
+	depends on MTD_NAND_BF5XX
+	help
+	  Enable the use of the BF5XX's internal ECC generator when
+	  using NAND.
+
+config MTD_NAND_BF5XX_BOOTROM_ECC
+	bool "Use Blackfin BootROM ECC Layout"
+	default n
+	depends on MTD_NAND_BF5XX_HWECC
+	help
+	  If you wish to modify NAND pages and allow the Blackfin on-chip
+	  BootROM to boot from them, say Y here.  This is only necessary
+	  if you are booting U-Boot out of NAND and you wish to update
+	  U-Boot from Linux' userspace.  Otherwise, you should say N here.
+
+	  If unsure, say N.
+
+config MTD_NAND_S3C2410
+	tristate "NAND Flash support for Samsung S3C SoCs"
+	depends on ARCH_S3C24XX || ARCH_S3C64XX
+	help
+	  This enables the NAND flash controller on the S3C24xx and S3C64xx
+	  SoCs
+
+	  No board specific support is done by this driver, each board
+	  must advertise a platform_device for the driver to attach.
+
+config MTD_NAND_S3C2410_DEBUG
+	bool "Samsung S3C NAND driver debug"
+	depends on MTD_NAND_S3C2410
+	help
+	  Enable debugging of the S3C NAND driver
+
+config MTD_NAND_NDFC
+	tristate "NDFC NanD Flash Controller"
+	depends on 4xx
+	select MTD_NAND_ECC_SMC
+	help
+	 NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
+
+config MTD_NAND_S3C2410_CLKSTOP
+	bool "Samsung S3C NAND IDLE clock stop"
+	depends on MTD_NAND_S3C2410
+	default n
+	help
+	  Stop the clock to the NAND controller when there is no chip
+	  selected to save power. This will mean there is a small delay
+	  when the is NAND chip selected or released, but will save
+	  approximately 5mA of power when there is nothing happening.
+
+config MTD_NAND_TANGO
+	tristate "NAND Flash support for Tango chips"
+	depends on ARCH_TANGO || COMPILE_TEST
+	depends on HAS_DMA
+	help
+	  Enables the NAND Flash controller on Tango chips.
+
+config MTD_NAND_DISKONCHIP
+	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
+	depends on HAS_IOMEM
+	select REED_SOLOMON
+	select REED_SOLOMON_DEC16
+	help
+	  This is a reimplementation of M-Systems DiskOnChip 2000,
+	  Millennium and Millennium Plus as a standard NAND device driver,
+	  as opposed to the earlier self-contained MTD device drivers.
+	  This should enable, among other things, proper JFFS2 operation on
+	  these devices.
+
+config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+        bool "Advanced detection options for DiskOnChip"
+        depends on MTD_NAND_DISKONCHIP
+        help
+          This option allows you to specify nonstandard address at which to
+          probe for a DiskOnChip, or to change the detection options.  You
+          are unlikely to need any of this unless you are using LinuxBIOS.
+          Say 'N'.
+
+config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+        depends on MTD_NAND_DISKONCHIP
+        default "0"
+        ---help---
+        By default, the probe for DiskOnChip devices will look for a
+        DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+        This option allows you to specify a single address at which to probe
+        for the device, which is useful if you have other devices in that
+        range which get upset when they are probed.
+
+        (Note that on PowerPC, the normal probe will only check at
+        0xE4000000.)
+
+        Normally, you should leave this set to zero, to allow the probe at
+        the normal addresses.
+
+config MTD_NAND_DISKONCHIP_PROBE_HIGH
+        bool "Probe high addresses"
+        depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+        help
+          By default, the probe for DiskOnChip devices will look for a
+          DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
+          This option changes to make it probe between 0xFFFC8000 and
+          0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
+          useful to you.  Say 'N'.
+
+config MTD_NAND_DISKONCHIP_BBTWRITE
+	bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
+	depends on MTD_NAND_DISKONCHIP
+	help
+	  On DiskOnChip devices shipped with the INFTL filesystem (Millennium
+	  and 2000 TSOP/Alon), Linux reserves some space at the end of the
+	  device for the Bad Block Table (BBT).  If you have existing INFTL
+	  data on your device (created by non-Linux tools such as M-Systems'
+	  DOS drivers), your data might overlap the area Linux wants to use for
+	  the BBT.  If this is a concern for you, leave this option disabled and
+	  Linux will not write BBT data into this area.
+	  The downside of leaving this option disabled is that if bad blocks
+	  are detected by Linux, they will not be recorded in the BBT, which
+	  could cause future problems.
+	  Once you enable this option, new filesystems (INFTL or others, created
+	  in Linux or other operating systems) will not use the reserved area.
+	  The only reason not to enable this option is to prevent damage to
+	  preexisting filesystems.
+	  Even if you leave this disabled, you can enable BBT writes at module
+	  load time (assuming you build diskonchip as a module) with the module
+	  parameter "inftl_bbt_write=1".
+
+config MTD_NAND_DOCG4
+	tristate "Support for DiskOnChip G4"
+	depends on HAS_IOMEM
+	select BCH
+	select BITREVERSE
+	help
+	  Support for diskonchip G4 nand flash, found in various smartphones and
+	  PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
+	  Portege G900, Asus P526, and O2 XDA Zinc.
+
+	  With this driver you will be able to use UBI and create a ubifs on the
+	  device, so you may wish to consider enabling UBI and UBIFS as well.
+
+	  These devices ship with the Mys/Sandisk SAFTL formatting, for which
+	  there is currently no mtd parser, so you may want to use command line
+	  partitioning to segregate write-protected blocks. On the Treo680, the
+	  first five erase blocks (256KiB each) are write-protected, followed
+	  by the block containing the saftl partition table.  This is probably
+	  typical.
+
+config MTD_NAND_SHARPSL
+	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+	depends on ARCH_PXA
+
+config MTD_NAND_CAFE
+	tristate "NAND support for OLPC CAFÉ chip"
+	depends on PCI
+	select REED_SOLOMON
+	select REED_SOLOMON_DEC16
+	help
+	  Use NAND flash attached to the CAFÉ chip designed for the OLPC
+	  laptop.
+
+config MTD_NAND_CS553X
+	tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
+	depends on X86_32
+	depends on !UML && HAS_IOMEM
+	help
+	  The CS553x companion chips for the AMD Geode processor
+	  include NAND flash controllers with built-in hardware ECC
+	  capabilities; enabling this option will allow you to use
+	  these. The driver will check the MSRs to verify that the
+	  controller is enabled for NAND, and currently requires that
+	  the controller be in MMIO mode.
+
+	  If you say "m", the module will be called cs553x_nand.
+
+config MTD_NAND_ATMEL
+	tristate "Support for NAND Flash / SmartMedia on AT91"
+	depends on ARCH_AT91
+	select MFD_ATMEL_SMC
+	help
+	  Enables support for NAND Flash / Smart Media Card interface
+	  on Atmel AT91 processors.
+
+config MTD_NAND_PXA3xx
+	tristate "NAND support on PXA3xx and Armada 370/XP"
+	depends on !MTD_NAND_MARVELL
+	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU
+	help
+
+	  This enables the driver for the NAND flash device found on
+	  PXA3xx processors (NFCv1) and also on 32-bit Armada
+	  platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada
+	  platforms (7K, 8K) (NFCv2).
+
+config MTD_NAND_MARVELL
+	tristate "NAND controller support on Marvell boards"
+	depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
+		   COMPILE_TEST
+	depends on HAS_IOMEM && HAS_DMA
+	help
+	  This enables the NAND flash controller driver for Marvell boards,
+	  including:
+	  - PXA3xx processors (NFCv1)
+	  - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
+	  - 64-bit Aramda platforms (7k, 8k) (NFCv2)
+
+config MTD_NAND_SLC_LPC32XX
+	tristate "NXP LPC32xx SLC Controller"
+	depends on ARCH_LPC32XX
+	help
+	  Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
+	  chips) NAND controller. This is the default for the PHYTEC 3250
+	  reference board which contains a NAND256R3A2CZA6 chip.
+
+	  Please check the actual NAND chip connected and its support
+	  by the SLC NAND controller.
+
+config MTD_NAND_MLC_LPC32XX
+	tristate "NXP LPC32xx MLC Controller"
+	depends on ARCH_LPC32XX
+	help
+	  Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
+	  controller. This is the default for the WORK92105 controller
+	  board.
+
+	  Please check the actual NAND chip connected and its support
+	  by the MLC NAND controller.
+
+config MTD_NAND_CM_X270
+	tristate "Support for NAND Flash on CM-X270 modules"
+	depends on MACH_ARMCORE
+
+config MTD_NAND_PASEMI
+	tristate "NAND support for PA Semi PWRficient"
+	depends on PPC_PASEMI
+	help
+	  Enables support for NAND Flash interface on PA Semi PWRficient
+	  based boards
+
+config MTD_NAND_TMIO
+	tristate "NAND Flash device on Toshiba Mobile IO Controller"
+	depends on MFD_TMIO
+	help
+	  Support for NAND flash connected to a Toshiba Mobile IO
+	  Controller in some PDAs, including the Sharp SL6000x.
+
+config MTD_NAND_NANDSIM
+	tristate "Support for NAND Flash Simulator"
+	help
+	  The simulator may simulate various NAND flash chips for the
+	  MTD nand layer.
+
+config MTD_NAND_GPMI_NAND
+        tristate "GPMI NAND Flash Controller driver"
+        depends on MTD_NAND && MXS_DMA
+        help
+	 Enables NAND Flash support for IMX23, IMX28 or IMX6.
+	 The GPMI controller is very powerful, with the help of BCH
+	 module, it can do the hardware ECC. The GPMI supports several
+	 NAND flashs at the same time.
+
+config MTD_NAND_BRCMNAND
+	tristate "Broadcom STB NAND controller"
+	depends on ARM || ARM64 || MIPS
+	help
+	  Enables the Broadcom NAND controller driver. The controller was
+	  originally designed for Set-Top Box but is used on various BCM7xxx,
+	  BCM3xxx, BCM63xxx, iProc/Cygnus and more.
+
+config MTD_NAND_BCM47XXNFLASH
+	tristate "Support for NAND flash on BCM4706 BCMA bus"
+	depends on BCMA_NFLASH
+	help
+	  BCMA bus can have various flash memories attached, they are
+	  registered by bcma as platform devices. This enables driver for
+	  NAND flash memories. For now only BCM4706 is supported.
+
+config MTD_NAND_PLATFORM
+	tristate "Support for generic platform NAND driver"
+	depends on HAS_IOMEM
+	help
+	  This implements a generic NAND driver for on-SOC platform
+	  devices. You will need to provide platform-specific functions
+	  via platform_data.
+
+config MTD_NAND_ORION
+	tristate "NAND Flash support for Marvell Orion SoC"
+	depends on PLAT_ORION
+	help
+	  This enables the NAND flash controller on Orion machines.
+
+	  No board specific support is done by this driver, each board
+	  must advertise a platform_device for the driver to attach.
+
+config MTD_NAND_OXNAS
+	tristate "NAND Flash support for Oxford Semiconductor SoC"
+	depends on ARCH_OXNAS || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
+config MTD_NAND_FSL_ELBC
+	tristate "NAND support for Freescale eLBC controllers"
+	depends on FSL_SOC
+	select FSL_LBC
+	help
+	  Various Freescale chips, including the 8313, include a NAND Flash
+	  Controller Module with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
+config MTD_NAND_FSL_IFC
+	tristate "NAND support for Freescale IFC controller"
+	depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
+	select FSL_IFC
+	select MEMORY
+	help
+	  Various Freescale chips e.g P1010, include a NAND Flash machine
+	  with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
+config MTD_NAND_FSL_UPM
+	tristate "Support for NAND on Freescale UPM"
+	depends on PPC_83xx || PPC_85xx
+	select FSL_LBC
+	help
+	  Enables support for NAND Flash chips wired onto Freescale PowerPC
+	  processor localbus with User-Programmable Machine support.
+
+config MTD_NAND_MPC5121_NFC
+	tristate "MPC5121 built-in NAND Flash Controller support"
+	depends on PPC_MPC512x
+	help
+	  This enables the driver for the NAND flash controller on the
+	  MPC5121 SoC.
+
+config MTD_NAND_VF610_NFC
+	tristate "Support for Freescale NFC for VF610/MPC5125"
+	depends on (SOC_VF610 || COMPILE_TEST)
+	depends on HAS_IOMEM
+	help
+	  Enables support for NAND Flash Controller on some Freescale
+	  processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
+	  The driver supports a maximum 2k page size. With 2k pages and
+	  64 bytes or more of OOB, hardware ECC with up to 32-bit error
+	  correction is supported. Hardware ECC is only enabled through
+	  device tree.
+
+config MTD_NAND_MXC
+	tristate "MXC NAND support"
+	depends on ARCH_MXC
+	help
+	  This enables the driver for the NAND flash controller on the
+	  MXC processors.
+
+config MTD_NAND_SH_FLCTL
+	tristate "Support for NAND on Renesas SuperH FLCTL"
+	depends on SUPERH || COMPILE_TEST
+	depends on HAS_IOMEM
+	depends on HAS_DMA
+	help
+	  Several Renesas SuperH CPU has FLCTL. This option enables support
+	  for NAND Flash using FLCTL.
+
+config MTD_NAND_DAVINCI
+        tristate "Support NAND on DaVinci/Keystone SoC"
+        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
+        help
+	  Enable the driver for NAND flash chips on Texas Instruments
+	  DaVinci/Keystone processors.
+
+config MTD_NAND_TXX9NDFMC
+	tristate "NAND Flash support for TXx9 SoC"
+	depends on SOC_TX4938 || SOC_TX4939
+	help
+	  This enables the NAND flash controller on the TXx9 SoCs.
+
+config MTD_NAND_SOCRATES
+	tristate "Support for NAND on Socrates board"
+	depends on SOCRATES
+	help
+	  Enables support for NAND Flash chips wired onto Socrates board.
+
+config MTD_NAND_NUC900
+	tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
+	depends on ARCH_W90X900
+	help
+	  This enables the driver for the NAND Flash on evaluation board based
+	  on w90p910 / NUC9xx.
+
+config MTD_NAND_JZ4740
+	tristate "Support for JZ4740 SoC NAND controller"
+	depends on MACH_JZ4740
+	help
+		Enables support for NAND Flash on JZ4740 SoC based boards.
+
+config MTD_NAND_JZ4780
+	tristate "Support for NAND on JZ4780 SoC"
+	depends on MACH_JZ4780 && JZ4780_NEMC
+	help
+	  Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
+	  based boards, using the BCH controller for hardware error correction.
+
+config MTD_NAND_FSMC
+	tristate "Support for NAND on ST Micros FSMC"
+	depends on OF
+	depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
+	help
+	  Enables support for NAND Flash chips on the ST Microelectronics
+	  Flexible Static Memory Controller (FSMC)
+
+config MTD_NAND_XWAY
+	bool "Support for NAND on Lantiq XWAY SoC"
+	depends on LANTIQ && SOC_TYPE_XWAY
+	help
+	  Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
+	  to the External Bus Unit (EBU).
+
+config MTD_NAND_SUNXI
+	tristate "Support for NAND on Allwinner SoCs"
+	depends on ARCH_SUNXI
+	help
+	  Enables support for NAND Flash chips on Allwinner SoCs.
+
+config MTD_NAND_HISI504
+	tristate "Support for NAND controller on Hisilicon SoC Hip04"
+	depends on ARCH_HISI || COMPILE_TEST
+	depends on HAS_DMA
+	help
+	  Enables support for NAND controller on Hisilicon SoC Hip04.
+
+config MTD_NAND_QCOM
+	tristate "Support for NAND on QCOM SoCs"
+	depends on ARCH_QCOM
+	help
+	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+	  controller. This controller is found on IPQ806x SoC.
+
+config MTD_NAND_MTK
+	tristate "Support for NAND controller on MTK SoCs"
+	depends on ARCH_MEDIATEK || COMPILE_TEST
+	depends on HAS_DMA
+	help
+	  Enables support for NAND controller on MTK SoCs.
+	  This controller is found on mt27xx, mt81xx, mt65xx SoCs.
+
+endif # MTD_NAND
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
new file mode 100644
index 000000000000..4e0982476267
--- /dev/null
+++ b/drivers/mtd/nand/raw/Makefile
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_MTD_NAND)			+= nand.o
+obj-$(CONFIG_MTD_NAND_ECC)		+= nand_ecc.o
+obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
+obj-$(CONFIG_MTD_SM_COMMON) 		+= sm_common.o
+
+obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
+obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
+obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o
+obj-$(CONFIG_MTD_NAND_DENALI_PCI)	+= denali_pci.o
+obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
+obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
+obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
+obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO)		+= tango_nand.o
+obj-$(CONFIG_MTD_NAND_DAVINCI)		+= davinci_nand.o
+obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
+obj-$(CONFIG_MTD_NAND_DOCG4)		+= docg4.o
+obj-$(CONFIG_MTD_NAND_FSMC)		+= fsmc_nand.o
+obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
+obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nandsim.o
+obj-$(CONFIG_MTD_NAND_CS553X)		+= cs553x_nand.o
+obj-$(CONFIG_MTD_NAND_NDFC)		+= ndfc.o
+obj-$(CONFIG_MTD_NAND_ATMEL)		+= atmel/
+obj-$(CONFIG_MTD_NAND_GPIO)		+= gpio.o
+omap2_nand-objs := omap2.o
+obj-$(CONFIG_MTD_NAND_OMAP2) 		+= omap2_nand.o
+obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD)	+= omap_elm.o
+obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
+obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
+obj-$(CONFIG_MTD_NAND_MARVELL)		+= marvell_nand.o
+obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
+obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
+obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
+obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS)		+= oxnas_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
+obj-$(CONFIG_MTD_NAND_SLC_LPC32XX)      += lpc32xx_slc.o
+obj-$(CONFIG_MTD_NAND_MLC_LPC32XX)      += lpc32xx_mlc.o
+obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
+obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
+obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
+obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
+obj-$(CONFIG_MTD_NAND_NUC900)		+= nuc900_nand.o
+obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o
+obj-$(CONFIG_MTD_NAND_VF610_NFC)	+= vf610_nfc.o
+obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o
+obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
+obj-$(CONFIG_MTD_NAND_JZ4780)		+= jz4780_nand.o jz4780_bch.o
+obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
+obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash/
+obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_nand.o
+obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
+obj-$(CONFIG_MTD_NAND_MTK)		+= mtk_ecc.o mtk_nand.o
+
+nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
+nand-objs += nand_amd.o
+nand-objs += nand_hynix.o
+nand-objs += nand_macronix.o
+nand-objs += nand_micron.o
+nand-objs += nand_samsung.o
+nand-objs += nand_toshiba.o
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
new file mode 100644
index 000000000000..35f80523e52e
--- /dev/null
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -0,0 +1,291 @@
+/*
+ *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ *  Derived from drivers/mtd/nand/toto.c (removed in v2.6.28)
+ *    Copyright (c) 2003 Texas Instruments
+ *    Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
+ *
+ *  Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *  Partially stolen from plat_nand.c
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   Amstrad E3 (Delta).
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/gpio-omap.h>
+
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <mach/board-ams-delta.h>
+
+#include <mach/hardware.h>
+
+/*
+ * MTD structure for E3 (Delta)
+ */
+static struct mtd_info *ams_delta_mtd = NULL;
+
+/*
+ * Define partitions for flash devices
+ */
+
+static const struct mtd_partition partition_info[] = {
+	{ .name		= "Kernel",
+	  .offset	= 0,
+	  .size		= 3 * SZ_1M + SZ_512K },
+	{ .name		= "u-boot",
+	  .offset	= 3 * SZ_1M + SZ_512K,
+	  .size		= SZ_256K },
+	{ .name		= "u-boot params",
+	  .offset	= 3 * SZ_1M + SZ_512K + SZ_256K,
+	  .size		= SZ_256K },
+	{ .name		= "Amstrad LDR",
+	  .offset	= 4 * SZ_1M,
+	  .size		= SZ_256K },
+	{ .name		= "File system",
+	  .offset	= 4 * SZ_1M + 1 * SZ_256K,
+	  .size		= 27 * SZ_1M },
+	{ .name		= "PBL reserved",
+	  .offset	= 32 * SZ_1M - 3 * SZ_256K,
+	  .size		=  3 * SZ_256K },
+};
+
+static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
+
+	writew(0, io_base + OMAP_MPUIO_IO_CNTL);
+	writew(byte, this->IO_ADDR_W);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
+	ndelay(40);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
+}
+
+static u_char ams_delta_read_byte(struct mtd_info *mtd)
+{
+	u_char res;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
+
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
+	ndelay(40);
+	writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
+	res = readw(this->IO_ADDR_R);
+	gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
+
+	return res;
+}
+
+static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
+				int len)
+{
+	int i;
+
+	for (i=0; i<len; i++)
+		ams_delta_write_byte(mtd, buf[i]);
+}
+
+static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+
+	for (i=0; i<len; i++)
+		buf[i] = ams_delta_read_byte(mtd);
+}
+
+/*
+ * Command control function
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 -> bit 2
+ * NAND_CLE: bit 1 -> bit 7
+ * NAND_ALE: bit 2 -> bit 6
+ */
+static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
+				(ctrl & NAND_NCE) == 0);
+		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
+				(ctrl & NAND_CLE) != 0);
+		gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
+				(ctrl & NAND_ALE) != 0);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		ams_delta_write_byte(mtd, cmd);
+}
+
+static int ams_delta_nand_ready(struct mtd_info *mtd)
+{
+	return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
+}
+
+static const struct gpio _mandatory_gpio[] = {
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NCE,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nce",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NRE,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nre",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWP,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nwp",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_NWE,
+		.flags	= GPIOF_OUT_INIT_HIGH,
+		.label	= "nand_nwe",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_ALE,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "nand_ale",
+	},
+	{
+		.gpio	= AMS_DELTA_GPIO_PIN_NAND_CLE,
+		.flags	= GPIOF_OUT_INIT_LOW,
+		.label	= "nand_cle",
+	},
+};
+
+/*
+ * Main initialization routine
+ */
+static int ams_delta_init(struct platform_device *pdev)
+{
+	struct nand_chip *this;
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	void __iomem *io_base;
+	int err = 0;
+
+	if (!res)
+		return -ENXIO;
+
+	/* Allocate memory for MTD device structure and private data */
+	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+	if (!this) {
+		printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	ams_delta_mtd = nand_to_mtd(this);
+	ams_delta_mtd->owner = THIS_MODULE;
+
+	/*
+	 * Don't try to request the memory region from here,
+	 * it should have been already requested from the
+	 * gpio-omap driver and requesting it again would fail.
+	 */
+
+	io_base = ioremap(res->start, resource_size(res));
+	if (io_base == NULL) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		err = -EIO;
+		goto out_free;
+	}
+
+	nand_set_controller_data(this, (void *)io_base);
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
+	this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
+	this->read_byte = ams_delta_read_byte;
+	this->write_buf = ams_delta_write_buf;
+	this->read_buf = ams_delta_read_buf;
+	this->cmd_ctrl = ams_delta_hwcontrol;
+	if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
+		this->dev_ready = ams_delta_nand_ready;
+	} else {
+		this->dev_ready = NULL;
+		printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
+	}
+	/* 25 us command delay time */
+	this->chip_delay = 30;
+	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
+
+	platform_set_drvdata(pdev, io_base);
+
+	/* Set chip enabled, but  */
+	err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+	if (err)
+		goto out_gpio;
+
+	/* Scan to find existence of the device */
+	err = nand_scan(ams_delta_mtd, 1);
+	if (err)
+		goto out_mtd;
+
+	/* Register the partitions */
+	mtd_device_register(ams_delta_mtd, partition_info,
+			    ARRAY_SIZE(partition_info));
+
+	goto out;
+
+ out_mtd:
+	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+out_gpio:
+	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
+	iounmap(io_base);
+out_free:
+	kfree(this);
+ out:
+	return err;
+}
+
+/*
+ * Clean up routine
+ */
+static int ams_delta_cleanup(struct platform_device *pdev)
+{
+	void __iomem *io_base = platform_get_drvdata(pdev);
+
+	/* Release resources, unregister device */
+	nand_release(ams_delta_mtd);
+
+	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
+	iounmap(io_base);
+
+	/* Free the MTD device structure */
+	kfree(mtd_to_nand(ams_delta_mtd));
+
+	return 0;
+}
+
+static struct platform_driver ams_delta_nand_driver = {
+	.probe		= ams_delta_init,
+	.remove		= ams_delta_cleanup,
+	.driver		= {
+		.name	= "ams-delta-nand",
+	},
+};
+
+module_platform_driver(ams_delta_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
+MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
diff --git a/drivers/mtd/nand/raw/atmel/Makefile b/drivers/mtd/nand/raw/atmel/Makefile
new file mode 100644
index 000000000000..288db4f38a8f
--- /dev/null
+++ b/drivers/mtd/nand/raw/atmel/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_MTD_NAND_ATMEL)	+= atmel-nand-controller.o atmel-pmecc.o
+
+atmel-nand-controller-objs	:= nand-controller.o
+atmel-pmecc-objs		:= pmecc.o
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
new file mode 100644
index 000000000000..12f6753d47ae
--- /dev/null
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -0,0 +1,2565 @@
+/*
+ * Copyright 2017 ATMEL
+ * Copyright 2017 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * Derived from the atmel_nand.c driver which contained the following
+ * copyrights:
+ *
+ *   Copyright 2003 Rick Bronson
+ *
+ *   Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
+ *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ *   Derived from drivers/mtd/spia.c (removed in v3.8)
+ *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ *
+ *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+ *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
+ *
+ *   Derived from Das U-Boot source code
+ *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ *	Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
+ *   Add Programmable Multibit ECC support for various AT91 SoC
+ *	Copyright 2012 ATMEL, Hong Xu
+ *
+ *   Add Nand Flash Controller support for SAMA5 SoC
+ *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
+ *
+ * A few words about the naming convention in this file. This convention
+ * applies to structure and function names.
+ *
+ * Prefixes:
+ *
+ * - atmel_nand_: all generic structures/functions
+ * - atmel_smc_nand_: all structures/functions specific to the SMC interface
+ *		      (at91sam9 and avr32 SoCs)
+ * - atmel_hsmc_nand_: all structures/functions specific to the HSMC interface
+ *		       (sama5 SoCs and later)
+ * - atmel_nfc_: all structures/functions used to manipulate the NFC sub-block
+ *		 that is available in the HSMC block
+ * - <soc>_nand_: all SoC specific structures/functions
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/genalloc.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/atmel-matrix.h>
+#include <linux/mfd/syscon/atmel-smc.h>
+#include <linux/module.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/iopoll.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "pmecc.h"
+
+#define ATMEL_HSMC_NFC_CFG			0x0
+#define ATMEL_HSMC_NFC_CFG_SPARESIZE(x)		(((x) / 4) << 24)
+#define ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK	GENMASK(30, 24)
+#define ATMEL_HSMC_NFC_CFG_DTO(cyc, mul)	(((cyc) << 16) | ((mul) << 20))
+#define ATMEL_HSMC_NFC_CFG_DTO_MAX		GENMASK(22, 16)
+#define ATMEL_HSMC_NFC_CFG_RBEDGE		BIT(13)
+#define ATMEL_HSMC_NFC_CFG_FALLING_EDGE		BIT(12)
+#define ATMEL_HSMC_NFC_CFG_RSPARE		BIT(9)
+#define ATMEL_HSMC_NFC_CFG_WSPARE		BIT(8)
+#define ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK	GENMASK(2, 0)
+#define ATMEL_HSMC_NFC_CFG_PAGESIZE(x)		(fls((x) / 512) - 1)
+
+#define ATMEL_HSMC_NFC_CTRL			0x4
+#define ATMEL_HSMC_NFC_CTRL_EN			BIT(0)
+#define ATMEL_HSMC_NFC_CTRL_DIS			BIT(1)
+
+#define ATMEL_HSMC_NFC_SR			0x8
+#define ATMEL_HSMC_NFC_IER			0xc
+#define ATMEL_HSMC_NFC_IDR			0x10
+#define ATMEL_HSMC_NFC_IMR			0x14
+#define ATMEL_HSMC_NFC_SR_ENABLED		BIT(1)
+#define ATMEL_HSMC_NFC_SR_RB_RISE		BIT(4)
+#define ATMEL_HSMC_NFC_SR_RB_FALL		BIT(5)
+#define ATMEL_HSMC_NFC_SR_BUSY			BIT(8)
+#define ATMEL_HSMC_NFC_SR_WR			BIT(11)
+#define ATMEL_HSMC_NFC_SR_CSID			GENMASK(14, 12)
+#define ATMEL_HSMC_NFC_SR_XFRDONE		BIT(16)
+#define ATMEL_HSMC_NFC_SR_CMDDONE		BIT(17)
+#define ATMEL_HSMC_NFC_SR_DTOE			BIT(20)
+#define ATMEL_HSMC_NFC_SR_UNDEF			BIT(21)
+#define ATMEL_HSMC_NFC_SR_AWB			BIT(22)
+#define ATMEL_HSMC_NFC_SR_NFCASE		BIT(23)
+#define ATMEL_HSMC_NFC_SR_ERRORS		(ATMEL_HSMC_NFC_SR_DTOE | \
+						 ATMEL_HSMC_NFC_SR_UNDEF | \
+						 ATMEL_HSMC_NFC_SR_AWB | \
+						 ATMEL_HSMC_NFC_SR_NFCASE)
+#define ATMEL_HSMC_NFC_SR_RBEDGE(x)		BIT((x) + 24)
+
+#define ATMEL_HSMC_NFC_ADDR			0x18
+#define ATMEL_HSMC_NFC_BANK			0x1c
+
+#define ATMEL_NFC_MAX_RB_ID			7
+
+#define ATMEL_NFC_SRAM_SIZE			0x2400
+
+#define ATMEL_NFC_CMD(pos, cmd)			((cmd) << (((pos) * 8) + 2))
+#define ATMEL_NFC_VCMD2				BIT(18)
+#define ATMEL_NFC_ACYCLE(naddrs)		((naddrs) << 19)
+#define ATMEL_NFC_CSID(cs)			((cs) << 22)
+#define ATMEL_NFC_DATAEN			BIT(25)
+#define ATMEL_NFC_NFCWR				BIT(26)
+
+#define ATMEL_NFC_MAX_ADDR_CYCLES		5
+
+#define ATMEL_NAND_ALE_OFFSET			BIT(21)
+#define ATMEL_NAND_CLE_OFFSET			BIT(22)
+
+#define DEFAULT_TIMEOUT_MS			1000
+#define MIN_DMA_LEN				128
+
+enum atmel_nand_rb_type {
+	ATMEL_NAND_NO_RB,
+	ATMEL_NAND_NATIVE_RB,
+	ATMEL_NAND_GPIO_RB,
+};
+
+struct atmel_nand_rb {
+	enum atmel_nand_rb_type type;
+	union {
+		struct gpio_desc *gpio;
+		int id;
+	};
+};
+
+struct atmel_nand_cs {
+	int id;
+	struct atmel_nand_rb rb;
+	struct gpio_desc *csgpio;
+	struct {
+		void __iomem *virt;
+		dma_addr_t dma;
+	} io;
+
+	struct atmel_smc_cs_conf smcconf;
+};
+
+struct atmel_nand {
+	struct list_head node;
+	struct device *dev;
+	struct nand_chip base;
+	struct atmel_nand_cs *activecs;
+	struct atmel_pmecc_user *pmecc;
+	struct gpio_desc *cdgpio;
+	int numcs;
+	struct atmel_nand_cs cs[];
+};
+
+static inline struct atmel_nand *to_atmel_nand(struct nand_chip *chip)
+{
+	return container_of(chip, struct atmel_nand, base);
+}
+
+enum atmel_nfc_data_xfer {
+	ATMEL_NFC_NO_DATA,
+	ATMEL_NFC_READ_DATA,
+	ATMEL_NFC_WRITE_DATA,
+};
+
+struct atmel_nfc_op {
+	u8 cs;
+	u8 ncmds;
+	u8 cmds[2];
+	u8 naddrs;
+	u8 addrs[5];
+	enum atmel_nfc_data_xfer data;
+	u32 wait;
+	u32 errors;
+};
+
+struct atmel_nand_controller;
+struct atmel_nand_controller_caps;
+
+struct atmel_nand_controller_ops {
+	int (*probe)(struct platform_device *pdev,
+		     const struct atmel_nand_controller_caps *caps);
+	int (*remove)(struct atmel_nand_controller *nc);
+	void (*nand_init)(struct atmel_nand_controller *nc,
+			  struct atmel_nand *nand);
+	int (*ecc_init)(struct atmel_nand *nand);
+	int (*setup_data_interface)(struct atmel_nand *nand, int csline,
+				    const struct nand_data_interface *conf);
+};
+
+struct atmel_nand_controller_caps {
+	bool has_dma;
+	bool legacy_of_bindings;
+	u32 ale_offs;
+	u32 cle_offs;
+	const struct atmel_nand_controller_ops *ops;
+};
+
+struct atmel_nand_controller {
+	struct nand_hw_control base;
+	const struct atmel_nand_controller_caps *caps;
+	struct device *dev;
+	struct regmap *smc;
+	struct dma_chan *dmac;
+	struct atmel_pmecc *pmecc;
+	struct list_head chips;
+	struct clk *mck;
+};
+
+static inline struct atmel_nand_controller *
+to_nand_controller(struct nand_hw_control *ctl)
+{
+	return container_of(ctl, struct atmel_nand_controller, base);
+}
+
+struct atmel_smc_nand_controller {
+	struct atmel_nand_controller base;
+	struct regmap *matrix;
+	unsigned int ebi_csa_offs;
+};
+
+static inline struct atmel_smc_nand_controller *
+to_smc_nand_controller(struct nand_hw_control *ctl)
+{
+	return container_of(to_nand_controller(ctl),
+			    struct atmel_smc_nand_controller, base);
+}
+
+struct atmel_hsmc_nand_controller {
+	struct atmel_nand_controller base;
+	struct {
+		struct gen_pool *pool;
+		void __iomem *virt;
+		dma_addr_t dma;
+	} sram;
+	const struct atmel_hsmc_reg_layout *hsmc_layout;
+	struct regmap *io;
+	struct atmel_nfc_op op;
+	struct completion complete;
+	int irq;
+
+	/* Only used when instantiating from legacy DT bindings. */
+	struct clk *clk;
+};
+
+static inline struct atmel_hsmc_nand_controller *
+to_hsmc_nand_controller(struct nand_hw_control *ctl)
+{
+	return container_of(to_nand_controller(ctl),
+			    struct atmel_hsmc_nand_controller, base);
+}
+
+static bool atmel_nfc_op_done(struct atmel_nfc_op *op, u32 status)
+{
+	op->errors |= status & ATMEL_HSMC_NFC_SR_ERRORS;
+	op->wait ^= status & op->wait;
+
+	return !op->wait || op->errors;
+}
+
+static irqreturn_t atmel_nfc_interrupt(int irq, void *data)
+{
+	struct atmel_hsmc_nand_controller *nc = data;
+	u32 sr, rcvd;
+	bool done;
+
+	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &sr);
+
+	rcvd = sr & (nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
+	done = atmel_nfc_op_done(&nc->op, sr);
+
+	if (rcvd)
+		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, rcvd);
+
+	if (done)
+		complete(&nc->complete);
+
+	return rcvd ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int atmel_nfc_wait(struct atmel_hsmc_nand_controller *nc, bool poll,
+			  unsigned int timeout_ms)
+{
+	int ret;
+
+	if (!timeout_ms)
+		timeout_ms = DEFAULT_TIMEOUT_MS;
+
+	if (poll) {
+		u32 status;
+
+		ret = regmap_read_poll_timeout(nc->base.smc,
+					       ATMEL_HSMC_NFC_SR, status,
+					       atmel_nfc_op_done(&nc->op,
+								 status),
+					       0, timeout_ms * 1000);
+	} else {
+		init_completion(&nc->complete);
+		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IER,
+			     nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
+		ret = wait_for_completion_timeout(&nc->complete,
+						msecs_to_jiffies(timeout_ms));
+		if (!ret)
+			ret = -ETIMEDOUT;
+		else
+			ret = 0;
+
+		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
+	}
+
+	if (nc->op.errors & ATMEL_HSMC_NFC_SR_DTOE) {
+		dev_err(nc->base.dev, "Waiting NAND R/B Timeout\n");
+		ret = -ETIMEDOUT;
+	}
+
+	if (nc->op.errors & ATMEL_HSMC_NFC_SR_UNDEF) {
+		dev_err(nc->base.dev, "Access to an undefined area\n");
+		ret = -EIO;
+	}
+
+	if (nc->op.errors & ATMEL_HSMC_NFC_SR_AWB) {
+		dev_err(nc->base.dev, "Access while busy\n");
+		ret = -EIO;
+	}
+
+	if (nc->op.errors & ATMEL_HSMC_NFC_SR_NFCASE) {
+		dev_err(nc->base.dev, "Wrong access size\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static void atmel_nand_dma_transfer_finished(void *data)
+{
+	struct completion *finished = data;
+
+	complete(finished);
+}
+
+static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
+				   void *buf, dma_addr_t dev_dma, size_t len,
+				   enum dma_data_direction dir)
+{
+	DECLARE_COMPLETION_ONSTACK(finished);
+	dma_addr_t src_dma, dst_dma, buf_dma;
+	struct dma_async_tx_descriptor *tx;
+	dma_cookie_t cookie;
+
+	buf_dma = dma_map_single(nc->dev, buf, len, dir);
+	if (dma_mapping_error(nc->dev, dev_dma)) {
+		dev_err(nc->dev,
+			"Failed to prepare a buffer for DMA access\n");
+		goto err;
+	}
+
+	if (dir == DMA_FROM_DEVICE) {
+		src_dma = dev_dma;
+		dst_dma = buf_dma;
+	} else {
+		src_dma = buf_dma;
+		dst_dma = dev_dma;
+	}
+
+	tx = dmaengine_prep_dma_memcpy(nc->dmac, dst_dma, src_dma, len,
+				       DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	if (!tx) {
+		dev_err(nc->dev, "Failed to prepare DMA memcpy\n");
+		goto err_unmap;
+	}
+
+	tx->callback = atmel_nand_dma_transfer_finished;
+	tx->callback_param = &finished;
+
+	cookie = dmaengine_submit(tx);
+	if (dma_submit_error(cookie)) {
+		dev_err(nc->dev, "Failed to do DMA tx_submit\n");
+		goto err_unmap;
+	}
+
+	dma_async_issue_pending(nc->dmac);
+	wait_for_completion(&finished);
+
+	return 0;
+
+err_unmap:
+	dma_unmap_single(nc->dev, buf_dma, len, dir);
+
+err:
+	dev_dbg(nc->dev, "Fall back to CPU I/O\n");
+
+	return -EIO;
+}
+
+static u8 atmel_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+
+	return ioread8(nand->activecs->io.virt);
+}
+
+static u16 atmel_nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+
+	return ioread16(nand->activecs->io.virt);
+}
+
+static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		iowrite16(byte | (byte << 8), nand->activecs->io.virt);
+	else
+		iowrite8(byte, nand->activecs->io.virt);
+}
+
+static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_nand_controller *nc;
+
+	nc = to_nand_controller(chip->controller);
+
+	/*
+	 * If the controller supports DMA, the buffer address is DMA-able and
+	 * len is long enough to make DMA transfers profitable, let's trigger
+	 * a DMA transfer. If it fails, fallback to PIO mode.
+	 */
+	if (nc->dmac && virt_addr_valid(buf) &&
+	    len >= MIN_DMA_LEN &&
+	    !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len,
+				     DMA_FROM_DEVICE))
+		return;
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		ioread16_rep(nand->activecs->io.virt, buf, len / 2);
+	else
+		ioread8_rep(nand->activecs->io.virt, buf, len);
+}
+
+static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_nand_controller *nc;
+
+	nc = to_nand_controller(chip->controller);
+
+	/*
+	 * If the controller supports DMA, the buffer address is DMA-able and
+	 * len is long enough to make DMA transfers profitable, let's trigger
+	 * a DMA transfer. If it fails, fallback to PIO mode.
+	 */
+	if (nc->dmac && virt_addr_valid(buf) &&
+	    len >= MIN_DMA_LEN &&
+	    !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma,
+				     len, DMA_TO_DEVICE))
+		return;
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		iowrite16_rep(nand->activecs->io.virt, buf, len / 2);
+	else
+		iowrite8_rep(nand->activecs->io.virt, buf, len);
+}
+
+static int atmel_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+
+	return gpiod_get_value(nand->activecs->rb.gpio);
+}
+
+static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+
+	if (cs < 0 || cs >= nand->numcs) {
+		nand->activecs = NULL;
+		chip->dev_ready = NULL;
+		return;
+	}
+
+	nand->activecs = &nand->cs[cs];
+
+	if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
+		chip->dev_ready = atmel_nand_dev_ready;
+}
+
+static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_hsmc_nand_controller *nc;
+	u32 status;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status);
+
+	return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
+}
+
+static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_hsmc_nand_controller *nc;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	atmel_nand_select_chip(mtd, cs);
+
+	if (!nand->activecs) {
+		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
+			     ATMEL_HSMC_NFC_CTRL_DIS);
+		return;
+	}
+
+	if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
+		chip->dev_ready = atmel_hsmc_nand_dev_ready;
+
+	regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
+			   ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
+			   ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK |
+			   ATMEL_HSMC_NFC_CFG_RSPARE |
+			   ATMEL_HSMC_NFC_CFG_WSPARE,
+			   ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
+			   ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
+			   ATMEL_HSMC_NFC_CFG_RSPARE);
+	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
+		     ATMEL_HSMC_NFC_CTRL_EN);
+}
+
+static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
+{
+	u8 *addrs = nc->op.addrs;
+	unsigned int op = 0;
+	u32 addr, val;
+	int i, ret;
+
+	nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
+
+	for (i = 0; i < nc->op.ncmds; i++)
+		op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
+
+	if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
+		regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
+
+	op |= ATMEL_NFC_CSID(nc->op.cs) |
+	      ATMEL_NFC_ACYCLE(nc->op.naddrs);
+
+	if (nc->op.ncmds > 1)
+		op |= ATMEL_NFC_VCMD2;
+
+	addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
+	       (addrs[3] << 24);
+
+	if (nc->op.data != ATMEL_NFC_NO_DATA) {
+		op |= ATMEL_NFC_DATAEN;
+		nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
+
+		if (nc->op.data == ATMEL_NFC_WRITE_DATA)
+			op |= ATMEL_NFC_NFCWR;
+	}
+
+	/* Clear all flags. */
+	regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
+
+	/* Send the command. */
+	regmap_write(nc->io, op, addr);
+
+	ret = atmel_nfc_wait(nc, poll, 0);
+	if (ret)
+		dev_err(nc->base.dev,
+			"Failed to send NAND command (err = %d)!",
+			ret);
+
+	/* Reset the op state. */
+	memset(&nc->op, 0, sizeof(nc->op));
+
+	return ret;
+}
+
+static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
+				     unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_hsmc_nand_controller *nc;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	if (ctrl & NAND_ALE) {
+		if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
+			return;
+
+		nc->op.addrs[nc->op.naddrs++] = dat;
+	} else if (ctrl & NAND_CLE) {
+		if (nc->op.ncmds > 1)
+			return;
+
+		nc->op.cmds[nc->op.ncmds++] = dat;
+	}
+
+	if (dat == NAND_CMD_NONE) {
+		nc->op.cs = nand->activecs->id;
+		atmel_nfc_exec_op(nc, true);
+	}
+}
+
+static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_nand_controller *nc;
+
+	nc = to_nand_controller(chip->controller);
+
+	if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) {
+		if (ctrl & NAND_NCE)
+			gpiod_set_value(nand->activecs->csgpio, 0);
+		else
+			gpiod_set_value(nand->activecs->csgpio, 1);
+	}
+
+	if (ctrl & NAND_ALE)
+		writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs);
+	else if (ctrl & NAND_CLE)
+		writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs);
+}
+
+static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
+				   bool oob_required)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_hsmc_nand_controller *nc;
+	int ret = -EIO;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	if (nc->base.dmac)
+		ret = atmel_nand_dma_transfer(&nc->base, (void *)buf,
+					      nc->sram.dma, mtd->writesize,
+					      DMA_TO_DEVICE);
+
+	/* Falling back to CPU copy. */
+	if (ret)
+		memcpy_toio(nc->sram.virt, buf, mtd->writesize);
+
+	if (oob_required)
+		memcpy_toio(nc->sram.virt + mtd->writesize, chip->oob_poi,
+			    mtd->oobsize);
+}
+
+static void atmel_nfc_copy_from_sram(struct nand_chip *chip, u8 *buf,
+				     bool oob_required)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_hsmc_nand_controller *nc;
+	int ret = -EIO;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	if (nc->base.dmac)
+		ret = atmel_nand_dma_transfer(&nc->base, buf, nc->sram.dma,
+					      mtd->writesize, DMA_FROM_DEVICE);
+
+	/* Falling back to CPU copy. */
+	if (ret)
+		memcpy_fromio(buf, nc->sram.virt, mtd->writesize);
+
+	if (oob_required)
+		memcpy_fromio(chip->oob_poi, nc->sram.virt + mtd->writesize,
+			      mtd->oobsize);
+}
+
+static void atmel_nfc_set_op_addr(struct nand_chip *chip, int page, int column)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_hsmc_nand_controller *nc;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	if (column >= 0) {
+		nc->op.addrs[nc->op.naddrs++] = column;
+
+		/*
+		 * 2 address cycles for the column offset on large page NANDs.
+		 */
+		if (mtd->writesize > 512)
+			nc->op.addrs[nc->op.naddrs++] = column >> 8;
+	}
+
+	if (page >= 0) {
+		nc->op.addrs[nc->op.naddrs++] = page;
+		nc->op.addrs[nc->op.naddrs++] = page >> 8;
+
+		if (chip->options & NAND_ROW_ADDR_3)
+			nc->op.addrs[nc->op.naddrs++] = page >> 16;
+	}
+}
+
+static int atmel_nand_pmecc_enable(struct nand_chip *chip, int op, bool raw)
+{
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_nand_controller *nc;
+	int ret;
+
+	nc = to_nand_controller(chip->controller);
+
+	if (raw)
+		return 0;
+
+	ret = atmel_pmecc_enable(nand->pmecc, op);
+	if (ret)
+		dev_err(nc->dev,
+			"Failed to enable ECC engine (err = %d)\n", ret);
+
+	return ret;
+}
+
+static void atmel_nand_pmecc_disable(struct nand_chip *chip, bool raw)
+{
+	struct atmel_nand *nand = to_atmel_nand(chip);
+
+	if (!raw)
+		atmel_pmecc_disable(nand->pmecc);
+}
+
+static int atmel_nand_pmecc_generate_eccbytes(struct nand_chip *chip, bool raw)
+{
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand_controller *nc;
+	struct mtd_oob_region oobregion;
+	void *eccbuf;
+	int ret, i;
+
+	nc = to_nand_controller(chip->controller);
+
+	if (raw)
+		return 0;
+
+	ret = atmel_pmecc_wait_rdy(nand->pmecc);
+	if (ret) {
+		dev_err(nc->dev,
+			"Failed to transfer NAND page data (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	eccbuf = chip->oob_poi + oobregion.offset;
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		atmel_pmecc_get_generated_eccbytes(nand->pmecc, i,
+						   eccbuf);
+		eccbuf += chip->ecc.bytes;
+	}
+
+	return 0;
+}
+
+static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf,
+					 bool raw)
+{
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand_controller *nc;
+	struct mtd_oob_region oobregion;
+	int ret, i, max_bitflips = 0;
+	void *databuf, *eccbuf;
+
+	nc = to_nand_controller(chip->controller);
+
+	if (raw)
+		return 0;
+
+	ret = atmel_pmecc_wait_rdy(nand->pmecc);
+	if (ret) {
+		dev_err(nc->dev,
+			"Failed to read NAND page data (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	eccbuf = chip->oob_poi + oobregion.offset;
+	databuf = buf;
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		ret = atmel_pmecc_correct_sector(nand->pmecc, i, databuf,
+						 eccbuf);
+		if (ret < 0 && !atmel_pmecc_correct_erased_chunks(nand->pmecc))
+			ret = nand_check_erased_ecc_chunk(databuf,
+							  chip->ecc.size,
+							  eccbuf,
+							  chip->ecc.bytes,
+							  NULL, 0,
+							  chip->ecc.strength);
+
+		if (ret >= 0)
+			max_bitflips = max(ret, max_bitflips);
+		else
+			mtd->ecc_stats.failed++;
+
+		databuf += chip->ecc.size;
+		eccbuf += chip->ecc.bytes;
+	}
+
+	return max_bitflips;
+}
+
+static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
+				     bool oob_required, int page, bool raw)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	int ret;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
+	if (ret)
+		return ret;
+
+	atmel_nand_write_buf(mtd, buf, mtd->writesize);
+
+	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
+	if (ret) {
+		atmel_pmecc_disable(nand->pmecc);
+		return ret;
+	}
+
+	atmel_nand_pmecc_disable(chip, raw);
+
+	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+				       struct nand_chip *chip, const u8 *buf,
+				       int oob_required, int page)
+{
+	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
+}
+
+static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
+					   struct nand_chip *chip,
+					   const u8 *buf, int oob_required,
+					   int page)
+{
+	return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, true);
+}
+
+static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
+				    bool oob_required, int page, bool raw)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
+	if (ret)
+		return ret;
+
+	atmel_nand_read_buf(mtd, buf, mtd->writesize);
+	atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
+
+	atmel_nand_pmecc_disable(chip, raw);
+
+	return ret;
+}
+
+static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+				      struct nand_chip *chip, u8 *buf,
+				      int oob_required, int page)
+{
+	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
+}
+
+static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
+					  struct nand_chip *chip, u8 *buf,
+					  int oob_required, int page)
+{
+	return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
+}
+
+static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
+					  const u8 *buf, bool oob_required,
+					  int page, bool raw)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_hsmc_nand_controller *nc;
+	int ret, status;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	atmel_nfc_copy_to_sram(chip, buf, false);
+
+	nc->op.cmds[0] = NAND_CMD_SEQIN;
+	nc->op.ncmds = 1;
+	atmel_nfc_set_op_addr(chip, page, 0x0);
+	nc->op.cs = nand->activecs->id;
+	nc->op.data = ATMEL_NFC_WRITE_DATA;
+
+	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
+	if (ret)
+		return ret;
+
+	ret = atmel_nfc_exec_op(nc, false);
+	if (ret) {
+		atmel_nand_pmecc_disable(chip, raw);
+		dev_err(nc->base.dev,
+			"Failed to transfer NAND page data (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
+
+	atmel_nand_pmecc_disable(chip, raw);
+
+	if (ret)
+		return ret;
+
+	atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	nc->op.cmds[0] = NAND_CMD_PAGEPROG;
+	nc->op.ncmds = 1;
+	nc->op.cs = nand->activecs->id;
+	ret = atmel_nfc_exec_op(nc, false);
+	if (ret)
+		dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
+			ret);
+
+	status = chip->waitfunc(mtd, chip);
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return ret;
+}
+
+static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    const u8 *buf, int oob_required,
+					    int page)
+{
+	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
+					      false);
+}
+
+static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
+						struct nand_chip *chip,
+						const u8 *buf,
+						int oob_required, int page)
+{
+	return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
+					      true);
+}
+
+static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
+					 bool oob_required, int page,
+					 bool raw)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_hsmc_nand_controller *nc;
+	int ret;
+
+	nc = to_hsmc_nand_controller(chip->controller);
+
+	/*
+	 * Optimized read page accessors only work when the NAND R/B pin is
+	 * connected to a native SoC R/B pin. If that's not the case, fallback
+	 * to the non-optimized one.
+	 */
+	if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
+		nand_read_page_op(chip, page, 0, NULL, 0);
+
+		return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
+						raw);
+	}
+
+	nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0;
+
+	if (mtd->writesize > 512)
+		nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READSTART;
+
+	atmel_nfc_set_op_addr(chip, page, 0x0);
+	nc->op.cs = nand->activecs->id;
+	nc->op.data = ATMEL_NFC_READ_DATA;
+
+	ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
+	if (ret)
+		return ret;
+
+	ret = atmel_nfc_exec_op(nc, false);
+	if (ret) {
+		atmel_nand_pmecc_disable(chip, raw);
+		dev_err(nc->base.dev,
+			"Failed to load NAND page data (err = %d)\n",
+			ret);
+		return ret;
+	}
+
+	atmel_nfc_copy_from_sram(chip, buf, true);
+
+	ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
+
+	atmel_nand_pmecc_disable(chip, raw);
+
+	return ret;
+}
+
+static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
+					   struct nand_chip *chip, u8 *buf,
+					   int oob_required, int page)
+{
+	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
+					     false);
+}
+
+static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
+					       struct nand_chip *chip,
+					       u8 *buf, int oob_required,
+					       int page)
+{
+	return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
+					     true);
+}
+
+static int atmel_nand_pmecc_init(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_nand_controller *nc;
+	struct atmel_pmecc_user_req req;
+
+	nc = to_nand_controller(chip->controller);
+
+	if (!nc->pmecc) {
+		dev_err(nc->dev, "HW ECC not supported\n");
+		return -ENOTSUPP;
+	}
+
+	if (nc->caps->legacy_of_bindings) {
+		u32 val;
+
+		if (!of_property_read_u32(nc->dev->of_node, "atmel,pmecc-cap",
+					  &val))
+			chip->ecc.strength = val;
+
+		if (!of_property_read_u32(nc->dev->of_node,
+					  "atmel,pmecc-sector-size",
+					  &val))
+			chip->ecc.size = val;
+	}
+
+	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
+	else if (chip->ecc.strength)
+		req.ecc.strength = chip->ecc.strength;
+	else if (chip->ecc_strength_ds)
+		req.ecc.strength = chip->ecc_strength_ds;
+	else
+		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
+
+	if (chip->ecc.size)
+		req.ecc.sectorsize = chip->ecc.size;
+	else if (chip->ecc_step_ds)
+		req.ecc.sectorsize = chip->ecc_step_ds;
+	else
+		req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
+
+	req.pagesize = mtd->writesize;
+	req.oobsize = mtd->oobsize;
+
+	if (mtd->writesize <= 512) {
+		req.ecc.bytes = 4;
+		req.ecc.ooboffset = 0;
+	} else {
+		req.ecc.bytes = mtd->oobsize - 2;
+		req.ecc.ooboffset = ATMEL_PMECC_OOBOFFSET_AUTO;
+	}
+
+	nand->pmecc = atmel_pmecc_create_user(nc->pmecc, &req);
+	if (IS_ERR(nand->pmecc))
+		return PTR_ERR(nand->pmecc);
+
+	chip->ecc.algo = NAND_ECC_BCH;
+	chip->ecc.size = req.ecc.sectorsize;
+	chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors;
+	chip->ecc.strength = req.ecc.strength;
+
+	chip->options |= NAND_NO_SUBPAGE_WRITE;
+
+	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+
+	return 0;
+}
+
+static int atmel_nand_ecc_init(struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	struct atmel_nand_controller *nc;
+	int ret;
+
+	nc = to_nand_controller(chip->controller);
+
+	switch (chip->ecc.mode) {
+	case NAND_ECC_NONE:
+	case NAND_ECC_SOFT:
+		/*
+		 * Nothing to do, the core will initialize everything for us.
+		 */
+		break;
+
+	case NAND_ECC_HW:
+		ret = atmel_nand_pmecc_init(chip);
+		if (ret)
+			return ret;
+
+		chip->ecc.read_page = atmel_nand_pmecc_read_page;
+		chip->ecc.write_page = atmel_nand_pmecc_write_page;
+		chip->ecc.read_page_raw = atmel_nand_pmecc_read_page_raw;
+		chip->ecc.write_page_raw = atmel_nand_pmecc_write_page_raw;
+		break;
+
+	default:
+		/* Other modes are not supported. */
+		dev_err(nc->dev, "Unsupported ECC mode: %d\n",
+			chip->ecc.mode);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	int ret;
+
+	ret = atmel_nand_ecc_init(nand);
+	if (ret)
+		return ret;
+
+	if (chip->ecc.mode != NAND_ECC_HW)
+		return 0;
+
+	/* Adjust the ECC operations for the HSMC IP. */
+	chip->ecc.read_page = atmel_hsmc_nand_pmecc_read_page;
+	chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page;
+	chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw;
+	chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw;
+
+	return 0;
+}
+
+static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
+					const struct nand_data_interface *conf,
+					struct atmel_smc_cs_conf *smcconf)
+{
+	u32 ncycles, totalcycles, timeps, mckperiodps;
+	struct atmel_nand_controller *nc;
+	int ret;
+
+	nc = to_nand_controller(nand->base.controller);
+
+	/* DDR interface not supported. */
+	if (conf->type != NAND_SDR_IFACE)
+		return -ENOTSUPP;
+
+	/*
+	 * tRC < 30ns implies EDO mode. This controller does not support this
+	 * mode.
+	 */
+	if (conf->timings.sdr.tRC_min < 30000)
+		return -ENOTSUPP;
+
+	atmel_smc_cs_conf_init(smcconf);
+
+	mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
+	mckperiodps *= 1000;
+
+	/*
+	 * Set write pulse timing. This one is easy to extract:
+	 *
+	 * NWE_PULSE = tWP
+	 */
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
+	totalcycles = ncycles;
+	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/*
+	 * The write setup timing depends on the operation done on the NAND.
+	 * All operations goes through the same data bus, but the operation
+	 * type depends on the address we are writing to (ALE/CLE address
+	 * lines).
+	 * Since we have no way to differentiate the different operations at
+	 * the SMC level, we must consider the worst case (the biggest setup
+	 * time among all operation types):
+	 *
+	 * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
+	 */
+	timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
+		      conf->timings.sdr.tALS_min);
+	timeps = max(timeps, conf->timings.sdr.tDS_min);
+	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+	ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
+	totalcycles += ncycles;
+	ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/*
+	 * As for the write setup timing, the write hold timing depends on the
+	 * operation done on the NAND:
+	 *
+	 * NWE_HOLD = max(tCLH, tCH, tALH, tDH, tWH)
+	 */
+	timeps = max3(conf->timings.sdr.tCLH_min, conf->timings.sdr.tCH_min,
+		      conf->timings.sdr.tALH_min);
+	timeps = max3(timeps, conf->timings.sdr.tDH_min,
+		      conf->timings.sdr.tWH_min);
+	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+	totalcycles += ncycles;
+
+	/*
+	 * The write cycle timing is directly matching tWC, but is also
+	 * dependent on the other timings on the setup and hold timings we
+	 * calculated earlier, which gives:
+	 *
+	 * NWE_CYCLE = max(tWC, NWE_SETUP + NWE_PULSE + NWE_HOLD)
+	 */
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWC_min, mckperiodps);
+	ncycles = max(totalcycles, ncycles);
+	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NWE_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/*
+	 * We don't want the CS line to be toggled between each byte/word
+	 * transfer to the NAND. The only way to guarantee that is to have the
+	 * NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
+	 *
+	 * NCS_WR_PULSE = NWE_CYCLE
+	 */
+	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_WR_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/*
+	 * As for the write setup timing, the read hold timing depends on the
+	 * operation done on the NAND:
+	 *
+	 * NRD_HOLD = max(tREH, tRHOH)
+	 */
+	timeps = max(conf->timings.sdr.tREH_min, conf->timings.sdr.tRHOH_min);
+	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+	totalcycles = ncycles;
+
+	/*
+	 * TDF = tRHZ - NRD_HOLD
+	 */
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRHZ_max, mckperiodps);
+	ncycles -= totalcycles;
+
+	/*
+	 * In ONFI 4.0 specs, tRHZ has been increased to support EDO NANDs and
+	 * we might end up with a config that does not fit in the TDF field.
+	 * Just take the max value in this case and hope that the NAND is more
+	 * tolerant than advertised.
+	 */
+	if (ncycles > ATMEL_SMC_MODE_TDF_MAX)
+		ncycles = ATMEL_SMC_MODE_TDF_MAX;
+	else if (ncycles < ATMEL_SMC_MODE_TDF_MIN)
+		ncycles = ATMEL_SMC_MODE_TDF_MIN;
+
+	smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles) |
+			 ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
+
+	/*
+	 * Read pulse timing directly matches tRP:
+	 *
+	 * NRD_PULSE = tRP
+	 */
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps);
+	totalcycles += ncycles;
+	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/*
+	 * The write cycle timing is directly matching tWC, but is also
+	 * dependent on the setup and hold timings we calculated earlier,
+	 * which gives:
+	 *
+	 * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
+	 *
+	 * NRD_SETUP is always 0.
+	 */
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
+	ncycles = max(totalcycles, ncycles);
+	ret = atmel_smc_cs_conf_set_cycle(smcconf, ATMEL_SMC_NRD_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/*
+	 * We don't want the CS line to be toggled between each byte/word
+	 * transfer from the NAND. The only way to guarantee that is to have
+	 * the NCS_{WR,RD}_{SETUP,HOLD} timings set to 0, which in turn means:
+	 *
+	 * NCS_RD_PULSE = NRD_CYCLE
+	 */
+	ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NCS_RD_SHIFT,
+					  ncycles);
+	if (ret)
+		return ret;
+
+	/* Txxx timings are directly matching tXXX ones. */
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tCLR_min, mckperiodps);
+	ret = atmel_smc_cs_conf_set_timing(smcconf,
+					   ATMEL_HSMC_TIMINGS_TCLR_SHIFT,
+					   ncycles);
+	if (ret)
+		return ret;
+
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tADL_min, mckperiodps);
+	ret = atmel_smc_cs_conf_set_timing(smcconf,
+					   ATMEL_HSMC_TIMINGS_TADL_SHIFT,
+					   ncycles);
+	/*
+	 * Version 4 of the ONFI spec mandates that tADL be at least 400
+	 * nanoseconds, but, depending on the master clock rate, 400 ns may not
+	 * fit in the tADL field of the SMC reg. We need to relax the check and
+	 * accept the -ERANGE return code.
+	 *
+	 * Note that previous versions of the ONFI spec had a lower tADL_min
+	 * (100 or 200 ns). It's not clear why this timing constraint got
+	 * increased but it seems most NANDs are fine with values lower than
+	 * 400ns, so we should be safe.
+	 */
+	if (ret && ret != -ERANGE)
+		return ret;
+
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tAR_min, mckperiodps);
+	ret = atmel_smc_cs_conf_set_timing(smcconf,
+					   ATMEL_HSMC_TIMINGS_TAR_SHIFT,
+					   ncycles);
+	if (ret)
+		return ret;
+
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRR_min, mckperiodps);
+	ret = atmel_smc_cs_conf_set_timing(smcconf,
+					   ATMEL_HSMC_TIMINGS_TRR_SHIFT,
+					   ncycles);
+	if (ret)
+		return ret;
+
+	ncycles = DIV_ROUND_UP(conf->timings.sdr.tWB_max, mckperiodps);
+	ret = atmel_smc_cs_conf_set_timing(smcconf,
+					   ATMEL_HSMC_TIMINGS_TWB_SHIFT,
+					   ncycles);
+	if (ret)
+		return ret;
+
+	/* Attach the CS line to the NFC logic. */
+	smcconf->timings |= ATMEL_HSMC_TIMINGS_NFSEL;
+
+	/* Set the appropriate data bus width. */
+	if (nand->base.options & NAND_BUSWIDTH_16)
+		smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
+
+	/* Operate in NRD/NWE READ/WRITEMODE. */
+	smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD |
+			 ATMEL_SMC_MODE_WRITEMODE_NWE;
+
+	return 0;
+}
+
+static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
+					int csline,
+					const struct nand_data_interface *conf)
+{
+	struct atmel_nand_controller *nc;
+	struct atmel_smc_cs_conf smcconf;
+	struct atmel_nand_cs *cs;
+	int ret;
+
+	nc = to_nand_controller(nand->base.controller);
+
+	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
+	if (ret)
+		return ret;
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	cs = &nand->cs[csline];
+	cs->smcconf = smcconf;
+	atmel_smc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
+
+	return 0;
+}
+
+static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
+					int csline,
+					const struct nand_data_interface *conf)
+{
+	struct atmel_hsmc_nand_controller *nc;
+	struct atmel_smc_cs_conf smcconf;
+	struct atmel_nand_cs *cs;
+	int ret;
+
+	nc = to_hsmc_nand_controller(nand->base.controller);
+
+	ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
+	if (ret)
+		return ret;
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	cs = &nand->cs[csline];
+	cs->smcconf = smcconf;
+
+	if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
+		cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
+
+	atmel_hsmc_cs_conf_apply(nc->base.smc, nc->hsmc_layout, cs->id,
+				 &cs->smcconf);
+
+	return 0;
+}
+
+static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+					const struct nand_data_interface *conf)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct atmel_nand *nand = to_atmel_nand(chip);
+	struct atmel_nand_controller *nc;
+
+	nc = to_nand_controller(nand->base.controller);
+
+	if (csline >= nand->numcs ||
+	    (csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
+		return -EINVAL;
+
+	return nc->caps->ops->setup_data_interface(nand, csline, conf);
+}
+
+static void atmel_nand_init(struct atmel_nand_controller *nc,
+			    struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	mtd->dev.parent = nc->dev;
+	nand->base.controller = &nc->base;
+
+	chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+	chip->read_byte = atmel_nand_read_byte;
+	chip->read_word = atmel_nand_read_word;
+	chip->write_byte = atmel_nand_write_byte;
+	chip->read_buf = atmel_nand_read_buf;
+	chip->write_buf = atmel_nand_write_buf;
+	chip->select_chip = atmel_nand_select_chip;
+
+	if (nc->mck && nc->caps->ops->setup_data_interface)
+		chip->setup_data_interface = atmel_nand_setup_data_interface;
+
+	/* Some NANDs require a longer delay than the default one (20us). */
+	chip->chip_delay = 40;
+
+	/*
+	 * Use a bounce buffer when the buffer passed by the MTD user is not
+	 * suitable for DMA.
+	 */
+	if (nc->dmac)
+		chip->options |= NAND_USE_BOUNCE_BUFFER;
+
+	/* Default to HW ECC if pmecc is available. */
+	if (nc->pmecc)
+		chip->ecc.mode = NAND_ECC_HW;
+}
+
+static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
+				struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	struct atmel_smc_nand_controller *smc_nc;
+	int i;
+
+	atmel_nand_init(nc, nand);
+
+	smc_nc = to_smc_nand_controller(chip->controller);
+	if (!smc_nc->matrix)
+		return;
+
+	/* Attach the CS to the NAND Flash logic. */
+	for (i = 0; i < nand->numcs; i++)
+		regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs,
+				   BIT(nand->cs[i].id), BIT(nand->cs[i].id));
+}
+
+static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
+				 struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+
+	atmel_nand_init(nc, nand);
+
+	/* Overload some methods for the HSMC controller. */
+	chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
+	chip->select_chip = atmel_hsmc_nand_select_chip;
+}
+
+static int atmel_nand_detect(struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand_controller *nc;
+	int ret;
+
+	nc = to_nand_controller(chip->controller);
+
+	ret = nand_scan_ident(mtd, nand->numcs, NULL);
+	if (ret)
+		dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
+
+	return ret;
+}
+
+static int atmel_nand_unregister(struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	ret = mtd_device_unregister(mtd);
+	if (ret)
+		return ret;
+
+	nand_cleanup(chip);
+	list_del(&nand->node);
+
+	return 0;
+}
+
+static int atmel_nand_register(struct atmel_nand *nand)
+{
+	struct nand_chip *chip = &nand->base;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct atmel_nand_controller *nc;
+	int ret;
+
+	nc = to_nand_controller(chip->controller);
+
+	if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
+		/*
+		 * We keep the MTD name unchanged to avoid breaking platforms
+		 * where the MTD cmdline parser is used and the bootloader
+		 * has not been updated to use the new naming scheme.
+		 */
+		mtd->name = "atmel_nand";
+	} else if (!mtd->name) {
+		/*
+		 * If the new bindings are used and the bootloader has not been
+		 * updated to pass a new mtdparts parameter on the cmdline, you
+		 * should define the following property in your nand node:
+		 *
+		 *	label = "atmel_nand";
+		 *
+		 * This way, mtd->name will be set by the core when
+		 * nand_set_flash_node() is called.
+		 */
+		mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
+					   "%s:nand.%d", dev_name(nc->dev),
+					   nand->cs[0].id);
+		if (!mtd->name) {
+			dev_err(nc->dev, "Failed to allocate mtd->name\n");
+			return -ENOMEM;
+		}
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
+		nand_cleanup(chip);
+		return ret;
+	}
+
+	list_add_tail(&nand->node, &nc->chips);
+
+	return 0;
+}
+
+static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
+					    struct device_node *np,
+					    int reg_cells)
+{
+	struct atmel_nand *nand;
+	struct gpio_desc *gpio;
+	int numcs, ret, i;
+
+	numcs = of_property_count_elems_of_size(np, "reg",
+						reg_cells * sizeof(u32));
+	if (numcs < 1) {
+		dev_err(nc->dev, "Missing or invalid reg property\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	nand = devm_kzalloc(nc->dev,
+			    sizeof(*nand) + (numcs * sizeof(*nand->cs)),
+			    GFP_KERNEL);
+	if (!nand) {
+		dev_err(nc->dev, "Failed to allocate NAND object\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	nand->numcs = numcs;
+
+	gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0,
+						      &np->fwnode, GPIOD_IN,
+						      "nand-det");
+	if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
+		dev_err(nc->dev,
+			"Failed to get detect gpio (err = %ld)\n",
+			PTR_ERR(gpio));
+		return ERR_CAST(gpio);
+	}
+
+	if (!IS_ERR(gpio))
+		nand->cdgpio = gpio;
+
+	for (i = 0; i < numcs; i++) {
+		struct resource res;
+		u32 val;
+
+		ret = of_address_to_resource(np, 0, &res);
+		if (ret) {
+			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
+				ret);
+			return ERR_PTR(ret);
+		}
+
+		ret = of_property_read_u32_index(np, "reg", i * reg_cells,
+						 &val);
+		if (ret) {
+			dev_err(nc->dev, "Invalid reg property (err = %d)\n",
+				ret);
+			return ERR_PTR(ret);
+		}
+
+		nand->cs[i].id = val;
+
+		nand->cs[i].io.dma = res.start;
+		nand->cs[i].io.virt = devm_ioremap_resource(nc->dev, &res);
+		if (IS_ERR(nand->cs[i].io.virt))
+			return ERR_CAST(nand->cs[i].io.virt);
+
+		if (!of_property_read_u32(np, "atmel,rb", &val)) {
+			if (val > ATMEL_NFC_MAX_RB_ID)
+				return ERR_PTR(-EINVAL);
+
+			nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB;
+			nand->cs[i].rb.id = val;
+		} else {
+			gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev,
+							"rb", i, &np->fwnode,
+							GPIOD_IN, "nand-rb");
+			if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
+				dev_err(nc->dev,
+					"Failed to get R/B gpio (err = %ld)\n",
+					PTR_ERR(gpio));
+				return ERR_CAST(gpio);
+			}
+
+			if (!IS_ERR(gpio)) {
+				nand->cs[i].rb.type = ATMEL_NAND_GPIO_RB;
+				nand->cs[i].rb.gpio = gpio;
+			}
+		}
+
+		gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs",
+							      i, &np->fwnode,
+							      GPIOD_OUT_HIGH,
+							      "nand-cs");
+		if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
+			dev_err(nc->dev,
+				"Failed to get CS gpio (err = %ld)\n",
+				PTR_ERR(gpio));
+			return ERR_CAST(gpio);
+		}
+
+		if (!IS_ERR(gpio))
+			nand->cs[i].csgpio = gpio;
+	}
+
+	nand_set_flash_node(&nand->base, np);
+
+	return nand;
+}
+
+static int
+atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
+			       struct atmel_nand *nand)
+{
+	int ret;
+
+	/* No card inserted, skip this NAND. */
+	if (nand->cdgpio && gpiod_get_value(nand->cdgpio)) {
+		dev_info(nc->dev, "No SmartMedia card inserted.\n");
+		return 0;
+	}
+
+	nc->caps->ops->nand_init(nc, nand);
+
+	ret = atmel_nand_detect(nand);
+	if (ret)
+		return ret;
+
+	ret = nc->caps->ops->ecc_init(nand);
+	if (ret)
+		return ret;
+
+	return atmel_nand_register(nand);
+}
+
+static int
+atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
+{
+	struct atmel_nand *nand, *tmp;
+	int ret;
+
+	list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
+		ret = atmel_nand_unregister(nand);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc)
+{
+	struct device *dev = nc->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct atmel_nand *nand;
+	struct gpio_desc *gpio;
+	struct resource *res;
+
+	/*
+	 * Legacy bindings only allow connecting a single NAND with a unique CS
+	 * line to the controller.
+	 */
+	nand = devm_kzalloc(nc->dev, sizeof(*nand) + sizeof(*nand->cs),
+			    GFP_KERNEL);
+	if (!nand)
+		return -ENOMEM;
+
+	nand->numcs = 1;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nand->cs[0].io.virt = devm_ioremap_resource(dev, res);
+	if (IS_ERR(nand->cs[0].io.virt))
+		return PTR_ERR(nand->cs[0].io.virt);
+
+	nand->cs[0].io.dma = res->start;
+
+	/*
+	 * The old driver was hardcoding the CS id to 3 for all sama5
+	 * controllers. Since this id is only meaningful for the sama5
+	 * controller we can safely assign this id to 3 no matter the
+	 * controller.
+	 * If one wants to connect a NAND to a different CS line, he will
+	 * have to use the new bindings.
+	 */
+	nand->cs[0].id = 3;
+
+	/* R/B GPIO. */
+	gpio = devm_gpiod_get_index_optional(dev, NULL, 0,  GPIOD_IN);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "Failed to get R/B gpio (err = %ld)\n",
+			PTR_ERR(gpio));
+		return PTR_ERR(gpio);
+	}
+
+	if (gpio) {
+		nand->cs[0].rb.type = ATMEL_NAND_GPIO_RB;
+		nand->cs[0].rb.gpio = gpio;
+	}
+
+	/* CS GPIO. */
+	gpio = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_HIGH);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "Failed to get CS gpio (err = %ld)\n",
+			PTR_ERR(gpio));
+		return PTR_ERR(gpio);
+	}
+
+	nand->cs[0].csgpio = gpio;
+
+	/* Card detect GPIO. */
+	gpio = devm_gpiod_get_index_optional(nc->dev, NULL, 2, GPIOD_IN);
+	if (IS_ERR(gpio)) {
+		dev_err(dev,
+			"Failed to get detect gpio (err = %ld)\n",
+			PTR_ERR(gpio));
+		return PTR_ERR(gpio);
+	}
+
+	nand->cdgpio = gpio;
+
+	nand_set_flash_node(&nand->base, nc->dev->of_node);
+
+	return atmel_nand_controller_add_nand(nc, nand);
+}
+
+static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc)
+{
+	struct device_node *np, *nand_np;
+	struct device *dev = nc->dev;
+	int ret, reg_cells;
+	u32 val;
+
+	/* We do not retrieve the SMC syscon when parsing old DTs. */
+	if (nc->caps->legacy_of_bindings)
+		return atmel_nand_controller_legacy_add_nands(nc);
+
+	np = dev->of_node;
+
+	ret = of_property_read_u32(np, "#address-cells", &val);
+	if (ret) {
+		dev_err(dev, "missing #address-cells property\n");
+		return ret;
+	}
+
+	reg_cells = val;
+
+	ret = of_property_read_u32(np, "#size-cells", &val);
+	if (ret) {
+		dev_err(dev, "missing #address-cells property\n");
+		return ret;
+	}
+
+	reg_cells += val;
+
+	for_each_child_of_node(np, nand_np) {
+		struct atmel_nand *nand;
+
+		nand = atmel_nand_create(nc, nand_np, reg_cells);
+		if (IS_ERR(nand)) {
+			ret = PTR_ERR(nand);
+			goto err;
+		}
+
+		ret = atmel_nand_controller_add_nand(nc, nand);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	atmel_nand_controller_remove_nands(nc);
+
+	return ret;
+}
+
+static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc)
+{
+	if (nc->dmac)
+		dma_release_channel(nc->dmac);
+
+	clk_put(nc->mck);
+}
+
+static const struct of_device_id atmel_matrix_of_ids[] = {
+	{
+		.compatible = "atmel,at91sam9260-matrix",
+		.data = (void *)AT91SAM9260_MATRIX_EBICSA,
+	},
+	{
+		.compatible = "atmel,at91sam9261-matrix",
+		.data = (void *)AT91SAM9261_MATRIX_EBICSA,
+	},
+	{
+		.compatible = "atmel,at91sam9263-matrix",
+		.data = (void *)AT91SAM9263_MATRIX_EBI0CSA,
+	},
+	{
+		.compatible = "atmel,at91sam9rl-matrix",
+		.data = (void *)AT91SAM9RL_MATRIX_EBICSA,
+	},
+	{
+		.compatible = "atmel,at91sam9g45-matrix",
+		.data = (void *)AT91SAM9G45_MATRIX_EBICSA,
+	},
+	{
+		.compatible = "atmel,at91sam9n12-matrix",
+		.data = (void *)AT91SAM9N12_MATRIX_EBICSA,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-matrix",
+		.data = (void *)AT91SAM9X5_MATRIX_EBICSA,
+	},
+	{ /* sentinel */ },
+};
+
+static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
+				struct platform_device *pdev,
+				const struct atmel_nand_controller_caps *caps)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	int ret;
+
+	nand_hw_control_init(&nc->base);
+	INIT_LIST_HEAD(&nc->chips);
+	nc->dev = dev;
+	nc->caps = caps;
+
+	platform_set_drvdata(pdev, nc);
+
+	nc->pmecc = devm_atmel_pmecc_get(dev);
+	if (IS_ERR(nc->pmecc)) {
+		ret = PTR_ERR(nc->pmecc);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Could not get PMECC object (err = %d)\n",
+				ret);
+		return ret;
+	}
+
+	if (nc->caps->has_dma) {
+		dma_cap_mask_t mask;
+
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_MEMCPY, mask);
+
+		nc->dmac = dma_request_channel(mask, NULL, NULL);
+		if (!nc->dmac)
+			dev_err(nc->dev, "Failed to request DMA channel\n");
+	}
+
+	/* We do not retrieve the SMC syscon when parsing old DTs. */
+	if (nc->caps->legacy_of_bindings)
+		return 0;
+
+	nc->mck = of_clk_get(dev->parent->of_node, 0);
+	if (IS_ERR(nc->mck)) {
+		dev_err(dev, "Failed to retrieve MCK clk\n");
+		return PTR_ERR(nc->mck);
+	}
+
+	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
+	if (!np) {
+		dev_err(dev, "Missing or invalid atmel,smc property\n");
+		return -EINVAL;
+	}
+
+	nc->smc = syscon_node_to_regmap(np);
+	of_node_put(np);
+	if (IS_ERR(nc->smc)) {
+		ret = PTR_ERR(nc->smc);
+		dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int
+atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
+{
+	struct device *dev = nc->base.dev;
+	const struct of_device_id *match;
+	struct device_node *np;
+	int ret;
+
+	/* We do not retrieve the matrix syscon when parsing old DTs. */
+	if (nc->base.caps->legacy_of_bindings)
+		return 0;
+
+	np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0);
+	if (!np)
+		return 0;
+
+	match = of_match_node(atmel_matrix_of_ids, np);
+	if (!match) {
+		of_node_put(np);
+		return 0;
+	}
+
+	nc->matrix = syscon_node_to_regmap(np);
+	of_node_put(np);
+	if (IS_ERR(nc->matrix)) {
+		ret = PTR_ERR(nc->matrix);
+		dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret);
+		return ret;
+	}
+
+	nc->ebi_csa_offs = (unsigned int)match->data;
+
+	/*
+	 * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
+	 * add 4 to ->ebi_csa_offs.
+	 */
+	if (of_device_is_compatible(dev->parent->of_node,
+				    "atmel,at91sam9263-ebi1"))
+		nc->ebi_csa_offs += 4;
+
+	return 0;
+}
+
+static int
+atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
+{
+	struct regmap_config regmap_conf = {
+		.reg_bits = 32,
+		.val_bits = 32,
+		.reg_stride = 4,
+	};
+
+	struct device *dev = nc->base.dev;
+	struct device_node *nand_np, *nfc_np;
+	void __iomem *iomem;
+	struct resource res;
+	int ret;
+
+	nand_np = dev->of_node;
+	nfc_np = of_find_compatible_node(dev->of_node, NULL,
+					 "atmel,sama5d3-nfc");
+
+	nc->clk = of_clk_get(nfc_np, 0);
+	if (IS_ERR(nc->clk)) {
+		ret = PTR_ERR(nc->clk);
+		dev_err(dev, "Failed to retrieve HSMC clock (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	ret = clk_prepare_enable(nc->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable the HSMC clock (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	nc->irq = of_irq_get(nand_np, 0);
+	if (nc->irq <= 0) {
+		ret = nc->irq ?: -ENXIO;
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
+				ret);
+		goto out;
+	}
+
+	ret = of_address_to_resource(nfc_np, 0, &res);
+	if (ret) {
+		dev_err(dev, "Invalid or missing NFC IO resource (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	iomem = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(iomem)) {
+		ret = PTR_ERR(iomem);
+		goto out;
+	}
+
+	regmap_conf.name = "nfc-io";
+	regmap_conf.max_register = resource_size(&res) - 4;
+	nc->io = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
+	if (IS_ERR(nc->io)) {
+		ret = PTR_ERR(nc->io);
+		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	ret = of_address_to_resource(nfc_np, 1, &res);
+	if (ret) {
+		dev_err(dev, "Invalid or missing HSMC resource (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	iomem = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(iomem)) {
+		ret = PTR_ERR(iomem);
+		goto out;
+	}
+
+	regmap_conf.name = "smc";
+	regmap_conf.max_register = resource_size(&res) - 4;
+	nc->base.smc = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
+	if (IS_ERR(nc->base.smc)) {
+		ret = PTR_ERR(nc->base.smc);
+		dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	ret = of_address_to_resource(nfc_np, 2, &res);
+	if (ret) {
+		dev_err(dev, "Invalid or missing SRAM resource (err = %d)\n",
+			ret);
+		goto out;
+	}
+
+	nc->sram.virt = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(nc->sram.virt)) {
+		ret = PTR_ERR(nc->sram.virt);
+		goto out;
+	}
+
+	nc->sram.dma = res.start;
+
+out:
+	of_node_put(nfc_np);
+
+	return ret;
+}
+
+static int
+atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
+{
+	struct device *dev = nc->base.dev;
+	struct device_node *np;
+	int ret;
+
+	np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
+	if (!np) {
+		dev_err(dev, "Missing or invalid atmel,smc property\n");
+		return -EINVAL;
+	}
+
+	nc->hsmc_layout = atmel_hsmc_get_reg_layout(np);
+
+	nc->irq = of_irq_get(np, 0);
+	of_node_put(np);
+	if (nc->irq <= 0) {
+		ret = nc->irq ?: -ENXIO;
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get IRQ number (err = %d)\n",
+				ret);
+		return ret;
+	}
+
+	np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0);
+	if (!np) {
+		dev_err(dev, "Missing or invalid atmel,nfc-io property\n");
+		return -EINVAL;
+	}
+
+	nc->io = syscon_node_to_regmap(np);
+	of_node_put(np);
+	if (IS_ERR(nc->io)) {
+		ret = PTR_ERR(nc->io);
+		dev_err(dev, "Could not get NFC IO regmap (err = %d)\n", ret);
+		return ret;
+	}
+
+	nc->sram.pool = of_gen_pool_get(nc->base.dev->of_node,
+					 "atmel,nfc-sram", 0);
+	if (!nc->sram.pool) {
+		dev_err(nc->base.dev, "Missing SRAM\n");
+		return -ENOMEM;
+	}
+
+	nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
+					    ATMEL_NFC_SRAM_SIZE,
+					    &nc->sram.dma);
+	if (!nc->sram.virt) {
+		dev_err(nc->base.dev,
+			"Could not allocate memory from the NFC SRAM pool\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int
+atmel_hsmc_nand_controller_remove(struct atmel_nand_controller *nc)
+{
+	struct atmel_hsmc_nand_controller *hsmc_nc;
+	int ret;
+
+	ret = atmel_nand_controller_remove_nands(nc);
+	if (ret)
+		return ret;
+
+	hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base);
+	if (hsmc_nc->sram.pool)
+		gen_pool_free(hsmc_nc->sram.pool,
+			      (unsigned long)hsmc_nc->sram.virt,
+			      ATMEL_NFC_SRAM_SIZE);
+
+	if (hsmc_nc->clk) {
+		clk_disable_unprepare(hsmc_nc->clk);
+		clk_put(hsmc_nc->clk);
+	}
+
+	atmel_nand_controller_cleanup(nc);
+
+	return 0;
+}
+
+static int atmel_hsmc_nand_controller_probe(struct platform_device *pdev,
+				const struct atmel_nand_controller_caps *caps)
+{
+	struct device *dev = &pdev->dev;
+	struct atmel_hsmc_nand_controller *nc;
+	int ret;
+
+	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
+	if (!nc)
+		return -ENOMEM;
+
+	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
+	if (ret)
+		return ret;
+
+	if (caps->legacy_of_bindings)
+		ret = atmel_hsmc_nand_controller_legacy_init(nc);
+	else
+		ret = atmel_hsmc_nand_controller_init(nc);
+
+	if (ret)
+		return ret;
+
+	/* Make sure all irqs are masked before registering our IRQ handler. */
+	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
+	ret = devm_request_irq(dev, nc->irq, atmel_nfc_interrupt,
+			       IRQF_SHARED, "nfc", nc);
+	if (ret) {
+		dev_err(dev,
+			"Could not get register NFC interrupt handler (err = %d)\n",
+			ret);
+		goto err;
+	}
+
+	/* Initial NFC configuration. */
+	regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG,
+		     ATMEL_HSMC_NFC_CFG_DTO_MAX);
+
+	ret = atmel_nand_controller_add_nands(&nc->base);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	atmel_hsmc_nand_controller_remove(&nc->base);
+
+	return ret;
+}
+
+static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
+	.probe = atmel_hsmc_nand_controller_probe,
+	.remove = atmel_hsmc_nand_controller_remove,
+	.ecc_init = atmel_hsmc_nand_ecc_init,
+	.nand_init = atmel_hsmc_nand_init,
+	.setup_data_interface = atmel_hsmc_nand_setup_data_interface,
+};
+
+static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
+	.has_dma = true,
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &atmel_hsmc_nc_ops,
+};
+
+/* Only used to parse old bindings. */
+static const struct atmel_nand_controller_caps atmel_sama5_nand_caps = {
+	.has_dma = true,
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &atmel_hsmc_nc_ops,
+	.legacy_of_bindings = true,
+};
+
+static int atmel_smc_nand_controller_probe(struct platform_device *pdev,
+				const struct atmel_nand_controller_caps *caps)
+{
+	struct device *dev = &pdev->dev;
+	struct atmel_smc_nand_controller *nc;
+	int ret;
+
+	nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
+	if (!nc)
+		return -ENOMEM;
+
+	ret = atmel_nand_controller_init(&nc->base, pdev, caps);
+	if (ret)
+		return ret;
+
+	ret = atmel_smc_nand_controller_init(nc);
+	if (ret)
+		return ret;
+
+	return atmel_nand_controller_add_nands(&nc->base);
+}
+
+static int
+atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
+{
+	int ret;
+
+	ret = atmel_nand_controller_remove_nands(nc);
+	if (ret)
+		return ret;
+
+	atmel_nand_controller_cleanup(nc);
+
+	return 0;
+}
+
+/*
+ * The SMC reg layout of at91rm9200 is completely different which prevents us
+ * from re-using atmel_smc_nand_setup_data_interface() for the
+ * ->setup_data_interface() hook.
+ * At this point, there's no support for the at91rm9200 SMC IP, so we leave
+ * ->setup_data_interface() unassigned.
+ */
+static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
+	.probe = atmel_smc_nand_controller_probe,
+	.remove = atmel_smc_nand_controller_remove,
+	.ecc_init = atmel_nand_ecc_init,
+	.nand_init = atmel_smc_nand_init,
+};
+
+static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &at91rm9200_nc_ops,
+};
+
+static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
+	.probe = atmel_smc_nand_controller_probe,
+	.remove = atmel_smc_nand_controller_remove,
+	.ecc_init = atmel_nand_ecc_init,
+	.nand_init = atmel_smc_nand_init,
+	.setup_data_interface = atmel_smc_nand_setup_data_interface,
+};
+
+static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &atmel_smc_nc_ops,
+};
+
+static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = {
+	.ale_offs = BIT(22),
+	.cle_offs = BIT(21),
+	.ops = &atmel_smc_nc_ops,
+};
+
+static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
+	.has_dma = true,
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &atmel_smc_nc_ops,
+};
+
+/* Only used to parse old bindings. */
+static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &atmel_smc_nc_ops,
+	.legacy_of_bindings = true,
+};
+
+static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
+	.ale_offs = BIT(22),
+	.cle_offs = BIT(21),
+	.ops = &atmel_smc_nc_ops,
+	.legacy_of_bindings = true,
+};
+
+static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
+	.has_dma = true,
+	.ale_offs = BIT(21),
+	.cle_offs = BIT(22),
+	.ops = &atmel_smc_nc_ops,
+	.legacy_of_bindings = true,
+};
+
+static const struct of_device_id atmel_nand_controller_of_ids[] = {
+	{
+		.compatible = "atmel,at91rm9200-nand-controller",
+		.data = &atmel_rm9200_nc_caps,
+	},
+	{
+		.compatible = "atmel,at91sam9260-nand-controller",
+		.data = &atmel_sam9260_nc_caps,
+	},
+	{
+		.compatible = "atmel,at91sam9261-nand-controller",
+		.data = &atmel_sam9261_nc_caps,
+	},
+	{
+		.compatible = "atmel,at91sam9g45-nand-controller",
+		.data = &atmel_sam9g45_nc_caps,
+	},
+	{
+		.compatible = "atmel,sama5d3-nand-controller",
+		.data = &atmel_sama5_nc_caps,
+	},
+	/* Support for old/deprecated bindings: */
+	{
+		.compatible = "atmel,at91rm9200-nand",
+		.data = &atmel_rm9200_nand_caps,
+	},
+	{
+		.compatible = "atmel,sama5d4-nand",
+		.data = &atmel_rm9200_nand_caps,
+	},
+	{
+		.compatible = "atmel,sama5d2-nand",
+		.data = &atmel_rm9200_nand_caps,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, atmel_nand_controller_of_ids);
+
+static int atmel_nand_controller_probe(struct platform_device *pdev)
+{
+	const struct atmel_nand_controller_caps *caps;
+
+	if (pdev->id_entry)
+		caps = (void *)pdev->id_entry->driver_data;
+	else
+		caps = of_device_get_match_data(&pdev->dev);
+
+	if (!caps) {
+		dev_err(&pdev->dev, "Could not retrieve NFC caps\n");
+		return -EINVAL;
+	}
+
+	if (caps->legacy_of_bindings) {
+		u32 ale_offs = 21;
+
+		/*
+		 * If we are parsing legacy DT props and the DT contains a
+		 * valid NFC node, forward the request to the sama5 logic.
+		 */
+		if (of_find_compatible_node(pdev->dev.of_node, NULL,
+					    "atmel,sama5d3-nfc"))
+			caps = &atmel_sama5_nand_caps;
+
+		/*
+		 * Even if the compatible says we are dealing with an
+		 * at91rm9200 controller, the atmel,nand-has-dma specify that
+		 * this controller supports DMA, which means we are in fact
+		 * dealing with an at91sam9g45+ controller.
+		 */
+		if (!caps->has_dma &&
+		    of_property_read_bool(pdev->dev.of_node,
+					  "atmel,nand-has-dma"))
+			caps = &atmel_sam9g45_nand_caps;
+
+		/*
+		 * All SoCs except the at91sam9261 are assigning ALE to A21 and
+		 * CLE to A22. If atmel,nand-addr-offset != 21 this means we're
+		 * actually dealing with an at91sam9261 controller.
+		 */
+		of_property_read_u32(pdev->dev.of_node,
+				     "atmel,nand-addr-offset", &ale_offs);
+		if (ale_offs != 21)
+			caps = &atmel_sam9261_nand_caps;
+	}
+
+	return caps->ops->probe(pdev, caps);
+}
+
+static int atmel_nand_controller_remove(struct platform_device *pdev)
+{
+	struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
+
+	return nc->caps->ops->remove(nc);
+}
+
+static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
+{
+	struct atmel_nand_controller *nc = dev_get_drvdata(dev);
+	struct atmel_nand *nand;
+
+	if (nc->pmecc)
+		atmel_pmecc_reset(nc->pmecc);
+
+	list_for_each_entry(nand, &nc->chips, node) {
+		int i;
+
+		for (i = 0; i < nand->numcs; i++)
+			nand_reset(&nand->base, i);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(atmel_nand_controller_pm_ops, NULL,
+			 atmel_nand_controller_resume);
+
+static struct platform_driver atmel_nand_controller_driver = {
+	.driver = {
+		.name = "atmel-nand-controller",
+		.of_match_table = of_match_ptr(atmel_nand_controller_of_ids),
+		.pm = &atmel_nand_controller_pm_ops,
+	},
+	.probe = atmel_nand_controller_probe,
+	.remove = atmel_nand_controller_remove,
+};
+module_platform_driver(atmel_nand_controller_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("NAND Flash Controller driver for Atmel SoCs");
+MODULE_ALIAS("platform:atmel-nand-controller");
diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c
new file mode 100644
index 000000000000..9de29c9afb0c
--- /dev/null
+++ b/drivers/mtd/nand/raw/atmel/pmecc.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright 2017 ATMEL
+ * Copyright 2017 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * Derived from the atmel_nand.c driver which contained the following
+ * copyrights:
+ *
+ *   Copyright 2003 Rick Bronson
+ *
+ *   Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
+ *	Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ *   Derived from drivers/mtd/spia.c (removed in v3.8)
+ *	Copyright 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ *   Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+ *	Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
+ *
+ *   Derived from Das U-Boot source code
+ *	(u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ *      Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
+ *   Add Programmable Multibit ECC support for various AT91 SoC
+ *	Copyright 2012 ATMEL, Hong Xu
+ *
+ *   Add Nand Flash Controller support for SAMA5 SoC
+ *	Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
+ *
+ * The PMECC is an hardware assisted BCH engine, which means part of the
+ * ECC algorithm is left to the software. The hardware/software repartition
+ * is explained in the "PMECC Controller Functional Description" chapter in
+ * Atmel datasheets, and some of the functions in this file are directly
+ * implementing the algorithms described in the "Software Implementation"
+ * sub-section.
+ *
+ * TODO: it seems that the software BCH implementation in lib/bch.c is already
+ * providing some of the logic we are implementing here. It would be smart
+ * to expose the needed lib/bch.c helpers/functions and re-use them here.
+ */
+
+#include <linux/genalloc.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pmecc.h"
+
+/* Galois field dimension */
+#define PMECC_GF_DIMENSION_13			13
+#define PMECC_GF_DIMENSION_14			14
+
+/* Primitive Polynomial used by PMECC */
+#define PMECC_GF_13_PRIMITIVE_POLY		0x201b
+#define PMECC_GF_14_PRIMITIVE_POLY		0x4443
+
+#define PMECC_LOOKUP_TABLE_SIZE_512		0x2000
+#define PMECC_LOOKUP_TABLE_SIZE_1024		0x4000
+
+/* Time out value for reading PMECC status register */
+#define PMECC_MAX_TIMEOUT_MS			100
+
+/* PMECC Register Definitions */
+#define ATMEL_PMECC_CFG				0x0
+#define PMECC_CFG_BCH_STRENGTH(x)		(x)
+#define PMECC_CFG_BCH_STRENGTH_MASK		GENMASK(2, 0)
+#define PMECC_CFG_SECTOR512			(0 << 4)
+#define PMECC_CFG_SECTOR1024			(1 << 4)
+#define PMECC_CFG_NSECTORS(x)			((fls(x) - 1) << 8)
+#define PMECC_CFG_READ_OP			(0 << 12)
+#define PMECC_CFG_WRITE_OP			(1 << 12)
+#define PMECC_CFG_SPARE_ENABLE			BIT(16)
+#define PMECC_CFG_AUTO_ENABLE			BIT(20)
+
+#define ATMEL_PMECC_SAREA			0x4
+#define ATMEL_PMECC_SADDR			0x8
+#define ATMEL_PMECC_EADDR			0xc
+
+#define ATMEL_PMECC_CLK				0x10
+#define PMECC_CLK_133MHZ			(2 << 0)
+
+#define ATMEL_PMECC_CTRL			0x14
+#define PMECC_CTRL_RST				BIT(0)
+#define PMECC_CTRL_DATA				BIT(1)
+#define PMECC_CTRL_USER				BIT(2)
+#define PMECC_CTRL_ENABLE			BIT(4)
+#define PMECC_CTRL_DISABLE			BIT(5)
+
+#define ATMEL_PMECC_SR				0x18
+#define PMECC_SR_BUSY				BIT(0)
+#define PMECC_SR_ENABLE				BIT(4)
+
+#define ATMEL_PMECC_IER				0x1c
+#define ATMEL_PMECC_IDR				0x20
+#define ATMEL_PMECC_IMR				0x24
+#define ATMEL_PMECC_ISR				0x28
+#define PMECC_ERROR_INT				BIT(0)
+
+#define ATMEL_PMECC_ECC(sector, n)		\
+	((((sector) + 1) * 0x40) + (n))
+
+#define ATMEL_PMECC_REM(sector, n)		\
+	((((sector) + 1) * 0x40) + ((n) * 4) + 0x200)
+
+/* PMERRLOC Register Definitions */
+#define ATMEL_PMERRLOC_ELCFG			0x0
+#define PMERRLOC_ELCFG_SECTOR_512		(0 << 0)
+#define PMERRLOC_ELCFG_SECTOR_1024		(1 << 0)
+#define PMERRLOC_ELCFG_NUM_ERRORS(n)		((n) << 16)
+
+#define ATMEL_PMERRLOC_ELPRIM			0x4
+#define ATMEL_PMERRLOC_ELEN			0x8
+#define ATMEL_PMERRLOC_ELDIS			0xc
+#define PMERRLOC_DISABLE			BIT(0)
+
+#define ATMEL_PMERRLOC_ELSR			0x10
+#define PMERRLOC_ELSR_BUSY			BIT(0)
+
+#define ATMEL_PMERRLOC_ELIER			0x14
+#define ATMEL_PMERRLOC_ELIDR			0x18
+#define ATMEL_PMERRLOC_ELIMR			0x1c
+#define ATMEL_PMERRLOC_ELISR			0x20
+#define PMERRLOC_ERR_NUM_MASK			GENMASK(12, 8)
+#define PMERRLOC_CALC_DONE			BIT(0)
+
+#define ATMEL_PMERRLOC_SIGMA(x)			(((x) * 0x4) + 0x28)
+
+#define ATMEL_PMERRLOC_EL(offs, x)		(((x) * 0x4) + (offs))
+
+struct atmel_pmecc_gf_tables {
+	u16 *alpha_to;
+	u16 *index_of;
+};
+
+struct atmel_pmecc_caps {
+	const int *strengths;
+	int nstrengths;
+	int el_offset;
+	bool correct_erased_chunks;
+};
+
+struct atmel_pmecc {
+	struct device *dev;
+	const struct atmel_pmecc_caps *caps;
+
+	struct {
+		void __iomem *base;
+		void __iomem *errloc;
+	} regs;
+
+	struct mutex lock;
+};
+
+struct atmel_pmecc_user_conf_cache {
+	u32 cfg;
+	u32 sarea;
+	u32 saddr;
+	u32 eaddr;
+};
+
+struct atmel_pmecc_user {
+	struct atmel_pmecc_user_conf_cache cache;
+	struct atmel_pmecc *pmecc;
+	const struct atmel_pmecc_gf_tables *gf_tables;
+	int eccbytes;
+	s16 *partial_syn;
+	s16 *si;
+	s16 *lmu;
+	s16 *smu;
+	s32 *mu;
+	s32 *dmu;
+	s32 *delta;
+	u32 isr;
+};
+
+static DEFINE_MUTEX(pmecc_gf_tables_lock);
+static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_512;
+static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_1024;
+
+static inline int deg(unsigned int poly)
+{
+	/* polynomial degree is the most-significant bit index */
+	return fls(poly) - 1;
+}
+
+static int atmel_pmecc_build_gf_tables(int mm, unsigned int poly,
+				       struct atmel_pmecc_gf_tables *gf_tables)
+{
+	unsigned int i, x = 1;
+	const unsigned int k = BIT(deg(poly));
+	unsigned int nn = BIT(mm) - 1;
+
+	/* primitive polynomial must be of degree m */
+	if (k != (1u << mm))
+		return -EINVAL;
+
+	for (i = 0; i < nn; i++) {
+		gf_tables->alpha_to[i] = x;
+		gf_tables->index_of[x] = i;
+		if (i && (x == 1))
+			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
+			return -EINVAL;
+		x <<= 1;
+		if (x & k)
+			x ^= poly;
+	}
+	gf_tables->alpha_to[nn] = 1;
+	gf_tables->index_of[0] = 0;
+
+	return 0;
+}
+
+static const struct atmel_pmecc_gf_tables *
+atmel_pmecc_create_gf_tables(const struct atmel_pmecc_user_req *req)
+{
+	struct atmel_pmecc_gf_tables *gf_tables;
+	unsigned int poly, degree, table_size;
+	int ret;
+
+	if (req->ecc.sectorsize == 512) {
+		degree = PMECC_GF_DIMENSION_13;
+		poly = PMECC_GF_13_PRIMITIVE_POLY;
+		table_size = PMECC_LOOKUP_TABLE_SIZE_512;
+	} else {
+		degree = PMECC_GF_DIMENSION_14;
+		poly = PMECC_GF_14_PRIMITIVE_POLY;
+		table_size = PMECC_LOOKUP_TABLE_SIZE_1024;
+	}
+
+	gf_tables = kzalloc(sizeof(*gf_tables) +
+			    (2 * table_size * sizeof(u16)),
+			    GFP_KERNEL);
+	if (!gf_tables)
+		return ERR_PTR(-ENOMEM);
+
+	gf_tables->alpha_to = (void *)(gf_tables + 1);
+	gf_tables->index_of = gf_tables->alpha_to + table_size;
+
+	ret = atmel_pmecc_build_gf_tables(degree, poly, gf_tables);
+	if (ret) {
+		kfree(gf_tables);
+		return ERR_PTR(ret);
+	}
+
+	return gf_tables;
+}
+
+static const struct atmel_pmecc_gf_tables *
+atmel_pmecc_get_gf_tables(const struct atmel_pmecc_user_req *req)
+{
+	const struct atmel_pmecc_gf_tables **gf_tables, *ret;
+
+	mutex_lock(&pmecc_gf_tables_lock);
+	if (req->ecc.sectorsize == 512)
+		gf_tables = &pmecc_gf_tables_512;
+	else
+		gf_tables = &pmecc_gf_tables_1024;
+
+	ret = *gf_tables;
+
+	if (!ret) {
+		ret = atmel_pmecc_create_gf_tables(req);
+		if (!IS_ERR(ret))
+			*gf_tables = ret;
+	}
+	mutex_unlock(&pmecc_gf_tables_lock);
+
+	return ret;
+}
+
+static int atmel_pmecc_prepare_user_req(struct atmel_pmecc *pmecc,
+					struct atmel_pmecc_user_req *req)
+{
+	int i, max_eccbytes, eccbytes = 0, eccstrength = 0;
+
+	if (req->pagesize <= 0 || req->oobsize <= 0 || req->ecc.bytes <= 0)
+		return -EINVAL;
+
+	if (req->ecc.ooboffset >= 0 &&
+	    req->ecc.ooboffset + req->ecc.bytes > req->oobsize)
+		return -EINVAL;
+
+	if (req->ecc.sectorsize == ATMEL_PMECC_SECTOR_SIZE_AUTO) {
+		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
+			return -EINVAL;
+
+		if (req->pagesize > 512)
+			req->ecc.sectorsize = 1024;
+		else
+			req->ecc.sectorsize = 512;
+	}
+
+	if (req->ecc.sectorsize != 512 && req->ecc.sectorsize != 1024)
+		return -EINVAL;
+
+	if (req->pagesize % req->ecc.sectorsize)
+		return -EINVAL;
+
+	req->ecc.nsectors = req->pagesize / req->ecc.sectorsize;
+
+	max_eccbytes = req->ecc.bytes;
+
+	for (i = 0; i < pmecc->caps->nstrengths; i++) {
+		int nbytes, strength = pmecc->caps->strengths[i];
+
+		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH &&
+		    strength < req->ecc.strength)
+			continue;
+
+		nbytes = DIV_ROUND_UP(strength * fls(8 * req->ecc.sectorsize),
+				      8);
+		nbytes *= req->ecc.nsectors;
+
+		if (nbytes > max_eccbytes)
+			break;
+
+		eccstrength = strength;
+		eccbytes = nbytes;
+
+		if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
+			break;
+	}
+
+	if (!eccstrength)
+		return -EINVAL;
+
+	req->ecc.bytes = eccbytes;
+	req->ecc.strength = eccstrength;
+
+	if (req->ecc.ooboffset < 0)
+		req->ecc.ooboffset = req->oobsize - eccbytes;
+
+	return 0;
+}
+
+struct atmel_pmecc_user *
+atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
+			struct atmel_pmecc_user_req *req)
+{
+	struct atmel_pmecc_user *user;
+	const struct atmel_pmecc_gf_tables *gf_tables;
+	int strength, size, ret;
+
+	ret = atmel_pmecc_prepare_user_req(pmecc, req);
+	if (ret)
+		return ERR_PTR(ret);
+
+	size = sizeof(*user);
+	size = ALIGN(size, sizeof(u16));
+	/* Reserve space for partial_syn, si and smu */
+	size += ((2 * req->ecc.strength) + 1) * sizeof(u16) *
+		(2 + req->ecc.strength + 2);
+	/* Reserve space for lmu. */
+	size += (req->ecc.strength + 1) * sizeof(u16);
+	/* Reserve space for mu, dmu and delta. */
+	size = ALIGN(size, sizeof(s32));
+	size += (req->ecc.strength + 1) * sizeof(s32) * 3;
+
+	user = kzalloc(size, GFP_KERNEL);
+	if (!user)
+		return ERR_PTR(-ENOMEM);
+
+	user->pmecc = pmecc;
+
+	user->partial_syn = (s16 *)PTR_ALIGN(user + 1, sizeof(u16));
+	user->si = user->partial_syn + ((2 * req->ecc.strength) + 1);
+	user->lmu = user->si + ((2 * req->ecc.strength) + 1);
+	user->smu = user->lmu + (req->ecc.strength + 1);
+	user->mu = (s32 *)PTR_ALIGN(user->smu +
+				    (((2 * req->ecc.strength) + 1) *
+				     (req->ecc.strength + 2)),
+				    sizeof(s32));
+	user->dmu = user->mu + req->ecc.strength + 1;
+	user->delta = user->dmu + req->ecc.strength + 1;
+
+	gf_tables = atmel_pmecc_get_gf_tables(req);
+	if (IS_ERR(gf_tables)) {
+		kfree(user);
+		return ERR_CAST(gf_tables);
+	}
+
+	user->gf_tables = gf_tables;
+
+	user->eccbytes = req->ecc.bytes / req->ecc.nsectors;
+
+	for (strength = 0; strength < pmecc->caps->nstrengths; strength++) {
+		if (pmecc->caps->strengths[strength] == req->ecc.strength)
+			break;
+	}
+
+	user->cache.cfg = PMECC_CFG_BCH_STRENGTH(strength) |
+			  PMECC_CFG_NSECTORS(req->ecc.nsectors);
+
+	if (req->ecc.sectorsize == 1024)
+		user->cache.cfg |= PMECC_CFG_SECTOR1024;
+
+	user->cache.sarea = req->oobsize - 1;
+	user->cache.saddr = req->ecc.ooboffset;
+	user->cache.eaddr = req->ecc.ooboffset + req->ecc.bytes - 1;
+
+	return user;
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_create_user);
+
+void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user)
+{
+	kfree(user);
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user);
+
+static int get_strength(struct atmel_pmecc_user *user)
+{
+	const int *strengths = user->pmecc->caps->strengths;
+
+	return strengths[user->cache.cfg & PMECC_CFG_BCH_STRENGTH_MASK];
+}
+
+static int get_sectorsize(struct atmel_pmecc_user *user)
+{
+	return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512;
+}
+
+static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector)
+{
+	int strength = get_strength(user);
+	u32 value;
+	int i;
+
+	/* Fill odd syndromes */
+	for (i = 0; i < strength; i++) {
+		value = readl_relaxed(user->pmecc->regs.base +
+				      ATMEL_PMECC_REM(sector, i / 2));
+		if (i & 1)
+			value >>= 16;
+
+		user->partial_syn[(2 * i) + 1] = value;
+	}
+}
+
+static void atmel_pmecc_substitute(struct atmel_pmecc_user *user)
+{
+	int degree = get_sectorsize(user) == 512 ? 13 : 14;
+	int cw_len = BIT(degree) - 1;
+	int strength = get_strength(user);
+	s16 *alpha_to = user->gf_tables->alpha_to;
+	s16 *index_of = user->gf_tables->index_of;
+	s16 *partial_syn = user->partial_syn;
+	s16 *si;
+	int i, j;
+
+	/*
+	 * si[] is a table that holds the current syndrome value,
+	 * an element of that table belongs to the field
+	 */
+	si = user->si;
+
+	memset(&si[1], 0, sizeof(s16) * ((2 * strength) - 1));
+
+	/* Computation 2t syndromes based on S(x) */
+	/* Odd syndromes */
+	for (i = 1; i < 2 * strength; i += 2) {
+		for (j = 0; j < degree; j++) {
+			if (partial_syn[i] & BIT(j))
+				si[i] = alpha_to[i * j] ^ si[i];
+		}
+	}
+	/* Even syndrome = (Odd syndrome) ** 2 */
+	for (i = 2, j = 1; j <= strength; i = ++j << 1) {
+		if (si[j] == 0) {
+			si[i] = 0;
+		} else {
+			s16 tmp;
+
+			tmp = index_of[si[j]];
+			tmp = (tmp * 2) % cw_len;
+			si[i] = alpha_to[tmp];
+		}
+	}
+}
+
+static void atmel_pmecc_get_sigma(struct atmel_pmecc_user *user)
+{
+	s16 *lmu = user->lmu;
+	s16 *si = user->si;
+	s32 *mu = user->mu;
+	s32 *dmu = user->dmu;
+	s32 *delta = user->delta;
+	int degree = get_sectorsize(user) == 512 ? 13 : 14;
+	int cw_len = BIT(degree) - 1;
+	int strength = get_strength(user);
+	int num = 2 * strength + 1;
+	s16 *index_of = user->gf_tables->index_of;
+	s16 *alpha_to = user->gf_tables->alpha_to;
+	int i, j, k;
+	u32 dmu_0_count, tmp;
+	s16 *smu = user->smu;
+
+	/* index of largest delta */
+	int ro;
+	int largest;
+	int diff;
+
+	dmu_0_count = 0;
+
+	/* First Row */
+
+	/* Mu */
+	mu[0] = -1;
+
+	memset(smu, 0, sizeof(s16) * num);
+	smu[0] = 1;
+
+	/* discrepancy set to 1 */
+	dmu[0] = 1;
+	/* polynom order set to 0 */
+	lmu[0] = 0;
+	delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
+
+	/* Second Row */
+
+	/* Mu */
+	mu[1] = 0;
+	/* Sigma(x) set to 1 */
+	memset(&smu[num], 0, sizeof(s16) * num);
+	smu[num] = 1;
+
+	/* discrepancy set to S1 */
+	dmu[1] = si[1];
+
+	/* polynom order set to 0 */
+	lmu[1] = 0;
+
+	delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
+
+	/* Init the Sigma(x) last row */
+	memset(&smu[(strength + 1) * num], 0, sizeof(s16) * num);
+
+	for (i = 1; i <= strength; i++) {
+		mu[i + 1] = i << 1;
+		/* Begin Computing Sigma (Mu+1) and L(mu) */
+		/* check if discrepancy is set to 0 */
+		if (dmu[i] == 0) {
+			dmu_0_count++;
+
+			tmp = ((strength - (lmu[i] >> 1) - 1) / 2);
+			if ((strength - (lmu[i] >> 1) - 1) & 0x1)
+				tmp += 2;
+			else
+				tmp += 1;
+
+			if (dmu_0_count == tmp) {
+				for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
+					smu[(strength + 1) * num + j] =
+							smu[i * num + j];
+
+				lmu[strength + 1] = lmu[i];
+				return;
+			}
+
+			/* copy polynom */
+			for (j = 0; j <= lmu[i] >> 1; j++)
+				smu[(i + 1) * num + j] = smu[i * num + j];
+
+			/* copy previous polynom order to the next */
+			lmu[i + 1] = lmu[i];
+		} else {
+			ro = 0;
+			largest = -1;
+			/* find largest delta with dmu != 0 */
+			for (j = 0; j < i; j++) {
+				if ((dmu[j]) && (delta[j] > largest)) {
+					largest = delta[j];
+					ro = j;
+				}
+			}
+
+			/* compute difference */
+			diff = (mu[i] - mu[ro]);
+
+			/* Compute degree of the new smu polynomial */
+			if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
+				lmu[i + 1] = lmu[i];
+			else
+				lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
+
+			/* Init smu[i+1] with 0 */
+			for (k = 0; k < num; k++)
+				smu[(i + 1) * num + k] = 0;
+
+			/* Compute smu[i+1] */
+			for (k = 0; k <= lmu[ro] >> 1; k++) {
+				s16 a, b, c;
+
+				if (!(smu[ro * num + k] && dmu[i]))
+					continue;
+
+				a = index_of[dmu[i]];
+				b = index_of[dmu[ro]];
+				c = index_of[smu[ro * num + k]];
+				tmp = a + (cw_len - b) + c;
+				a = alpha_to[tmp % cw_len];
+				smu[(i + 1) * num + (k + diff)] = a;
+			}
+
+			for (k = 0; k <= lmu[i] >> 1; k++)
+				smu[(i + 1) * num + k] ^= smu[i * num + k];
+		}
+
+		/* End Computing Sigma (Mu+1) and L(mu) */
+		/* In either case compute delta */
+		delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
+
+		/* Do not compute discrepancy for the last iteration */
+		if (i >= strength)
+			continue;
+
+		for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
+			tmp = 2 * (i - 1);
+			if (k == 0) {
+				dmu[i + 1] = si[tmp + 3];
+			} else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
+				s16 a, b, c;
+
+				a = index_of[smu[(i + 1) * num + k]];
+				b = si[2 * (i - 1) + 3 - k];
+				c = index_of[b];
+				tmp = a + c;
+				tmp %= cw_len;
+				dmu[i + 1] = alpha_to[tmp] ^ dmu[i + 1];
+			}
+		}
+	}
+}
+
+static int atmel_pmecc_err_location(struct atmel_pmecc_user *user)
+{
+	int sector_size = get_sectorsize(user);
+	int degree = sector_size == 512 ? 13 : 14;
+	struct atmel_pmecc *pmecc = user->pmecc;
+	int strength = get_strength(user);
+	int ret, roots_nbr, i, err_nbr = 0;
+	int num = (2 * strength) + 1;
+	s16 *smu = user->smu;
+	u32 val;
+
+	writel(PMERRLOC_DISABLE, pmecc->regs.errloc + ATMEL_PMERRLOC_ELDIS);
+
+	for (i = 0; i <= user->lmu[strength + 1] >> 1; i++) {
+		writel_relaxed(smu[(strength + 1) * num + i],
+			       pmecc->regs.errloc + ATMEL_PMERRLOC_SIGMA(i));
+		err_nbr++;
+	}
+
+	val = (err_nbr - 1) << 16;
+	if (sector_size == 1024)
+		val |= 1;
+
+	writel(val, pmecc->regs.errloc + ATMEL_PMERRLOC_ELCFG);
+	writel((sector_size * 8) + (degree * strength),
+	       pmecc->regs.errloc + ATMEL_PMERRLOC_ELEN);
+
+	ret = readl_relaxed_poll_timeout(pmecc->regs.errloc +
+					 ATMEL_PMERRLOC_ELISR,
+					 val, val & PMERRLOC_CALC_DONE, 0,
+					 PMECC_MAX_TIMEOUT_MS * 1000);
+	if (ret) {
+		dev_err(pmecc->dev,
+			"PMECC: Timeout to calculate error location.\n");
+		return ret;
+	}
+
+	roots_nbr = (val & PMERRLOC_ERR_NUM_MASK) >> 8;
+	/* Number of roots == degree of smu hence <= cap */
+	if (roots_nbr == user->lmu[strength + 1] >> 1)
+		return err_nbr - 1;
+
+	/*
+	 * Number of roots does not match the degree of smu
+	 * unable to correct error.
+	 */
+	return -EBADMSG;
+}
+
+int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
+			       void *data, void *ecc)
+{
+	struct atmel_pmecc *pmecc = user->pmecc;
+	int sectorsize = get_sectorsize(user);
+	int eccbytes = user->eccbytes;
+	int i, nerrors;
+
+	if (!(user->isr & BIT(sector)))
+		return 0;
+
+	atmel_pmecc_gen_syndrome(user, sector);
+	atmel_pmecc_substitute(user);
+	atmel_pmecc_get_sigma(user);
+
+	nerrors = atmel_pmecc_err_location(user);
+	if (nerrors < 0)
+		return nerrors;
+
+	for (i = 0; i < nerrors; i++) {
+		const char *area;
+		int byte, bit;
+		u32 errpos;
+		u8 *ptr;
+
+		errpos = readl_relaxed(pmecc->regs.errloc +
+				ATMEL_PMERRLOC_EL(pmecc->caps->el_offset, i));
+		errpos--;
+
+		byte = errpos / 8;
+		bit = errpos % 8;
+
+		if (byte < sectorsize) {
+			ptr = data + byte;
+			area = "data";
+		} else if (byte < sectorsize + eccbytes) {
+			ptr = ecc + byte - sectorsize;
+			area = "ECC";
+		} else {
+			dev_dbg(pmecc->dev,
+				"Invalid errpos value (%d, max is %d)\n",
+				errpos, (sectorsize + eccbytes) * 8);
+			return -EINVAL;
+		}
+
+		dev_dbg(pmecc->dev,
+			"Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n",
+			area, byte, *ptr, (unsigned int)(*ptr ^ BIT(bit)));
+
+		*ptr ^= BIT(bit);
+	}
+
+	return nerrors;
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_correct_sector);
+
+bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user)
+{
+	return user->pmecc->caps->correct_erased_chunks;
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_correct_erased_chunks);
+
+void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
+					int sector, void *ecc)
+{
+	struct atmel_pmecc *pmecc = user->pmecc;
+	u8 *ptr = ecc;
+	int i;
+
+	for (i = 0; i < user->eccbytes; i++)
+		ptr[i] = readb_relaxed(pmecc->regs.base +
+				       ATMEL_PMECC_ECC(sector, i));
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_get_generated_eccbytes);
+
+void atmel_pmecc_reset(struct atmel_pmecc *pmecc)
+{
+	writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
+	writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_reset);
+
+int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op)
+{
+	struct atmel_pmecc *pmecc = user->pmecc;
+	u32 cfg;
+
+	if (op != NAND_ECC_READ && op != NAND_ECC_WRITE) {
+		dev_err(pmecc->dev, "Bad ECC operation!");
+		return -EINVAL;
+	}
+
+	mutex_lock(&user->pmecc->lock);
+
+	cfg = user->cache.cfg;
+	if (op == NAND_ECC_WRITE)
+		cfg |= PMECC_CFG_WRITE_OP;
+	else
+		cfg |= PMECC_CFG_AUTO_ENABLE;
+
+	writel(cfg, pmecc->regs.base + ATMEL_PMECC_CFG);
+	writel(user->cache.sarea, pmecc->regs.base + ATMEL_PMECC_SAREA);
+	writel(user->cache.saddr, pmecc->regs.base + ATMEL_PMECC_SADDR);
+	writel(user->cache.eaddr, pmecc->regs.base + ATMEL_PMECC_EADDR);
+
+	writel(PMECC_CTRL_ENABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
+	writel(PMECC_CTRL_DATA, pmecc->regs.base + ATMEL_PMECC_CTRL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_enable);
+
+void atmel_pmecc_disable(struct atmel_pmecc_user *user)
+{
+	atmel_pmecc_reset(user->pmecc);
+	mutex_unlock(&user->pmecc->lock);
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_disable);
+
+int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user)
+{
+	struct atmel_pmecc *pmecc = user->pmecc;
+	u32 status;
+	int ret;
+
+	ret = readl_relaxed_poll_timeout(pmecc->regs.base +
+					 ATMEL_PMECC_SR,
+					 status, !(status & PMECC_SR_BUSY), 0,
+					 PMECC_MAX_TIMEOUT_MS * 1000);
+	if (ret) {
+		dev_err(pmecc->dev,
+			"Timeout while waiting for PMECC ready.\n");
+		return ret;
+	}
+
+	user->isr = readl_relaxed(pmecc->regs.base + ATMEL_PMECC_ISR);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(atmel_pmecc_wait_rdy);
+
+static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev,
+					const struct atmel_pmecc_caps *caps,
+					int pmecc_res_idx, int errloc_res_idx)
+{
+	struct device *dev = &pdev->dev;
+	struct atmel_pmecc *pmecc;
+	struct resource *res;
+
+	pmecc = devm_kzalloc(dev, sizeof(*pmecc), GFP_KERNEL);
+	if (!pmecc)
+		return ERR_PTR(-ENOMEM);
+
+	pmecc->caps = caps;
+	pmecc->dev = dev;
+	mutex_init(&pmecc->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, pmecc_res_idx);
+	pmecc->regs.base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(pmecc->regs.base))
+		return ERR_CAST(pmecc->regs.base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, errloc_res_idx);
+	pmecc->regs.errloc = devm_ioremap_resource(dev, res);
+	if (IS_ERR(pmecc->regs.errloc))
+		return ERR_CAST(pmecc->regs.errloc);
+
+	/* Disable all interrupts before registering the PMECC handler. */
+	writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR);
+	atmel_pmecc_reset(pmecc);
+
+	return pmecc;
+}
+
+static void devm_atmel_pmecc_put(struct device *dev, void *res)
+{
+	struct atmel_pmecc **pmecc = res;
+
+	put_device((*pmecc)->dev);
+}
+
+static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
+						   struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct atmel_pmecc *pmecc, **ptr;
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev || !platform_get_drvdata(pdev))
+		return ERR_PTR(-EPROBE_DEFER);
+
+	ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	get_device(&pdev->dev);
+	pmecc = platform_get_drvdata(pdev);
+
+	*ptr = pmecc;
+
+	devres_add(userdev, ptr);
+
+	return pmecc;
+}
+
+static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
+
+static struct atmel_pmecc_caps at91sam9g45_caps = {
+	.strengths = atmel_pmecc_strengths,
+	.nstrengths = 5,
+	.el_offset = 0x8c,
+};
+
+static struct atmel_pmecc_caps sama5d4_caps = {
+	.strengths = atmel_pmecc_strengths,
+	.nstrengths = 5,
+	.el_offset = 0x8c,
+	.correct_erased_chunks = true,
+};
+
+static struct atmel_pmecc_caps sama5d2_caps = {
+	.strengths = atmel_pmecc_strengths,
+	.nstrengths = 6,
+	.el_offset = 0xac,
+	.correct_erased_chunks = true,
+};
+
+static const struct of_device_id atmel_pmecc_legacy_match[] = {
+	{ .compatible = "atmel,sama5d4-nand", &sama5d4_caps },
+	{ .compatible = "atmel,sama5d2-nand", &sama5d2_caps },
+	{ /* sentinel */ }
+};
+
+struct atmel_pmecc *devm_atmel_pmecc_get(struct device *userdev)
+{
+	struct atmel_pmecc *pmecc;
+	struct device_node *np;
+
+	if (!userdev)
+		return ERR_PTR(-EINVAL);
+
+	if (!userdev->of_node)
+		return NULL;
+
+	np = of_parse_phandle(userdev->of_node, "ecc-engine", 0);
+	if (np) {
+		pmecc = atmel_pmecc_get_by_node(userdev, np);
+		of_node_put(np);
+	} else {
+		/*
+		 * Support old DT bindings: in this case the PMECC iomem
+		 * resources are directly defined in the user pdev at position
+		 * 1 and 2. Extract all relevant information from there.
+		 */
+		struct platform_device *pdev = to_platform_device(userdev);
+		const struct atmel_pmecc_caps *caps;
+		const struct of_device_id *match;
+
+		/* No PMECC engine available. */
+		if (!of_property_read_bool(userdev->of_node,
+					   "atmel,has-pmecc"))
+			return NULL;
+
+		caps = &at91sam9g45_caps;
+
+		/* Find the caps associated to the NAND dev node. */
+		match = of_match_node(atmel_pmecc_legacy_match,
+				      userdev->of_node);
+		if (match && match->data)
+			caps = match->data;
+
+		pmecc = atmel_pmecc_create(pdev, caps, 1, 2);
+	}
+
+	return pmecc;
+}
+EXPORT_SYMBOL(devm_atmel_pmecc_get);
+
+static const struct of_device_id atmel_pmecc_match[] = {
+	{ .compatible = "atmel,at91sam9g45-pmecc", &at91sam9g45_caps },
+	{ .compatible = "atmel,sama5d4-pmecc", &sama5d4_caps },
+	{ .compatible = "atmel,sama5d2-pmecc", &sama5d2_caps },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, atmel_pmecc_match);
+
+static int atmel_pmecc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct atmel_pmecc_caps *caps;
+	struct atmel_pmecc *pmecc;
+
+	caps = of_device_get_match_data(&pdev->dev);
+	if (!caps) {
+		dev_err(dev, "Invalid caps\n");
+		return -EINVAL;
+	}
+
+	pmecc = atmel_pmecc_create(pdev, caps, 0, 1);
+	if (IS_ERR(pmecc))
+		return PTR_ERR(pmecc);
+
+	platform_set_drvdata(pdev, pmecc);
+
+	return 0;
+}
+
+static struct platform_driver atmel_pmecc_driver = {
+	.driver = {
+		.name = "atmel-pmecc",
+		.of_match_table = of_match_ptr(atmel_pmecc_match),
+	},
+	.probe = atmel_pmecc_probe,
+};
+module_platform_driver(atmel_pmecc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("PMECC engine driver");
+MODULE_ALIAS("platform:atmel_pmecc");
diff --git a/drivers/mtd/nand/raw/atmel/pmecc.h b/drivers/mtd/nand/raw/atmel/pmecc.h
new file mode 100644
index 000000000000..808f1be0d6ad
--- /dev/null
+++ b/drivers/mtd/nand/raw/atmel/pmecc.h
@@ -0,0 +1,74 @@
+/*
+ * © Copyright 2016 ATMEL
+ * © Copyright 2016 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * Derived from the atmel_nand.c driver which contained the following
+ * copyrights:
+ *
+ *    Copyright © 2003 Rick Bronson
+ *
+ *    Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
+ *        Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ *    Derived from drivers/mtd/spia.c (removed in v3.8)
+ *        Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ *
+ *    Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+ *        Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
+ *
+ *        Derived from Das U-Boot source code
+ *              (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ *        © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
+ *    Add Programmable Multibit ECC support for various AT91 SoC
+ *        © Copyright 2012 ATMEL, Hong Xu
+ *
+ *    Add Nand Flash Controller support for SAMA5 SoC
+ *        © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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.
+ *
+ */
+
+#ifndef ATMEL_PMECC_H
+#define ATMEL_PMECC_H
+
+#define ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH	0
+#define ATMEL_PMECC_SECTOR_SIZE_AUTO		0
+#define ATMEL_PMECC_OOBOFFSET_AUTO		-1
+
+struct atmel_pmecc_user_req {
+	int pagesize;
+	int oobsize;
+	struct {
+		int strength;
+		int bytes;
+		int sectorsize;
+		int nsectors;
+		int ooboffset;
+	} ecc;
+};
+
+struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev);
+
+struct atmel_pmecc_user *
+atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
+			struct atmel_pmecc_user_req *req);
+void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user);
+
+void atmel_pmecc_reset(struct atmel_pmecc *pmecc);
+int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op);
+void atmel_pmecc_disable(struct atmel_pmecc_user *user);
+int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user);
+int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
+			       void *data, void *ecc);
+bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user);
+void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
+					int sector, void *ecc);
+
+#endif /* ATMEL_PMECC_H */
diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
new file mode 100644
index 000000000000..df0ef1f1e2f5
--- /dev/null
+++ b/drivers/mtd/nand/raw/au1550nd.c
@@ -0,0 +1,515 @@
+/*
+ *  Copyright (C) 2004 Embedded Edge, LLC
+ *
+ * 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/slab.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1550nd.h>
+
+
+struct au1550nd_ctx {
+	struct nand_chip chip;
+
+	int cs;
+	void __iomem *base;
+	void (*write_byte)(struct mtd_info *, u_char);
+};
+
+/**
+ * au_read_byte -  read one byte from the chip
+ * @mtd:	MTD device structure
+ *
+ * read function for 8bit buswidth
+ */
+static u_char au_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	u_char ret = readb(this->IO_ADDR_R);
+	wmb(); /* drain writebuffer */
+	return ret;
+}
+
+/**
+ * au_write_byte -  write one byte to the chip
+ * @mtd:	MTD device structure
+ * @byte:	pointer to data byte to write
+ *
+ * write function for 8it buswidth
+ */
+static void au_write_byte(struct mtd_info *mtd, u_char byte)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	writeb(byte, this->IO_ADDR_W);
+	wmb(); /* drain writebuffer */
+}
+
+/**
+ * au_read_byte16 -  read one byte endianness aware from the chip
+ * @mtd:	MTD device structure
+ *
+ * read function for 16bit buswidth with endianness conversion
+ */
+static u_char au_read_byte16(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
+	wmb(); /* drain writebuffer */
+	return ret;
+}
+
+/**
+ * au_write_byte16 -  write one byte endianness aware to the chip
+ * @mtd:	MTD device structure
+ * @byte:	pointer to data byte to write
+ *
+ * write function for 16bit buswidth with endianness conversion
+ */
+static void au_write_byte16(struct mtd_info *mtd, u_char byte)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+	wmb(); /* drain writebuffer */
+}
+
+/**
+ * au_read_word -  read one word from the chip
+ * @mtd:	MTD device structure
+ *
+ * read function for 16bit buswidth without endianness conversion
+ */
+static u16 au_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	u16 ret = readw(this->IO_ADDR_R);
+	wmb(); /* drain writebuffer */
+	return ret;
+}
+
+/**
+ * au_write_buf -  write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ *
+ * write function for 8bit buswidth
+ */
+static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	for (i = 0; i < len; i++) {
+		writeb(buf[i], this->IO_ADDR_W);
+		wmb(); /* drain writebuffer */
+	}
+}
+
+/**
+ * au_read_buf -  read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ *
+ * read function for 8bit buswidth
+ */
+static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	for (i = 0; i < len; i++) {
+		buf[i] = readb(this->IO_ADDR_R);
+		wmb(); /* drain writebuffer */
+	}
+}
+
+/**
+ * au_write_buf16 -  write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ *
+ * write function for 16bit buswidth
+ */
+static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++) {
+		writew(p[i], this->IO_ADDR_W);
+		wmb(); /* drain writebuffer */
+	}
+
+}
+
+/**
+ * au_read_buf16 -  read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ *
+ * read function for 16bit buswidth
+ */
+static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++) {
+		p[i] = readw(this->IO_ADDR_R);
+		wmb(); /* drain writebuffer */
+	}
+}
+
+/* Select the chip by setting nCE to low */
+#define NAND_CTL_SETNCE		1
+/* Deselect the chip by setting nCE to high */
+#define NAND_CTL_CLRNCE		2
+/* Select the command latch by setting CLE to high */
+#define NAND_CTL_SETCLE		3
+/* Deselect the command latch by setting CLE to low */
+#define NAND_CTL_CLRCLE		4
+/* Select the address latch by setting ALE to high */
+#define NAND_CTL_SETALE		5
+/* Deselect the address latch by setting ALE to low */
+#define NAND_CTL_CLRALE		6
+
+static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
+						chip);
+
+	switch (cmd) {
+
+	case NAND_CTL_SETCLE:
+		this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
+		break;
+
+	case NAND_CTL_CLRCLE:
+		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+		break;
+
+	case NAND_CTL_SETALE:
+		this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
+		break;
+
+	case NAND_CTL_CLRALE:
+		this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+		/* FIXME: Nobody knows why this is necessary,
+		 * but it works only that way */
+		udelay(1);
+		break;
+
+	case NAND_CTL_SETNCE:
+		/* assert (force assert) chip enable */
+		alchemy_wrsmem((1 << (4 + ctx->cs)), AU1000_MEM_STNDCTL);
+		break;
+
+	case NAND_CTL_CLRNCE:
+		/* deassert chip enable */
+		alchemy_wrsmem(0, AU1000_MEM_STNDCTL);
+		break;
+	}
+
+	this->IO_ADDR_R = this->IO_ADDR_W;
+
+	wmb(); /* Drain the writebuffer */
+}
+
+int au1550_device_ready(struct mtd_info *mtd)
+{
+	return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
+}
+
+/**
+ * au1550_select_chip - control -CE line
+ *	Forbid driving -CE manually permitting the NAND controller to do this.
+ *	Keeping -CE asserted during the whole sector reads interferes with the
+ *	NOR flash and PCMCIA drivers as it causes contention on the static bus.
+ *	We only have to hold -CE low for the NAND read commands since the flash
+ *	chip needs it to be asserted during chip not ready time but the NAND
+ *	controller keeps it released.
+ *
+ * @mtd:	MTD device structure
+ * @chip:	chipnumber to select, -1 for deselect
+ */
+static void au1550_select_chip(struct mtd_info *mtd, int chip)
+{
+}
+
+/**
+ * au1550_command - Send command to NAND device
+ * @mtd:	MTD device structure
+ * @command:	the command to be sent
+ * @column:	the column address for this command, -1 if none
+ * @page_addr:	the page address for this command, -1 if none
+ */
+static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
+						chip);
+	int ce_override = 0, i;
+	unsigned long flags = 0;
+
+	/* Begin command latch cycle */
+	au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
+	/*
+	 * Write out the command to the device.
+	 */
+	if (command == NAND_CMD_SEQIN) {
+		int readcmd;
+
+		if (column >= mtd->writesize) {
+			/* OOB area */
+			column -= mtd->writesize;
+			readcmd = NAND_CMD_READOOB;
+		} else if (column < 256) {
+			/* First 256 bytes --> READ0 */
+			readcmd = NAND_CMD_READ0;
+		} else {
+			column -= 256;
+			readcmd = NAND_CMD_READ1;
+		}
+		ctx->write_byte(mtd, readcmd);
+	}
+	ctx->write_byte(mtd, command);
+
+	/* Set ALE and clear CLE to start address cycle */
+	au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
+
+	if (column != -1 || page_addr != -1) {
+		au1550_hwcontrol(mtd, NAND_CTL_SETALE);
+
+		/* Serially input address */
+		if (column != -1) {
+			/* Adjust columns for 16 bit buswidth */
+			if (this->options & NAND_BUSWIDTH_16 &&
+					!nand_opcode_8bits(command))
+				column >>= 1;
+			ctx->write_byte(mtd, column);
+		}
+		if (page_addr != -1) {
+			ctx->write_byte(mtd, (u8)(page_addr & 0xff));
+
+			if (command == NAND_CMD_READ0 ||
+			    command == NAND_CMD_READ1 ||
+			    command == NAND_CMD_READOOB) {
+				/*
+				 * NAND controller will release -CE after
+				 * the last address byte is written, so we'll
+				 * have to forcibly assert it. No interrupts
+				 * are allowed while we do this as we don't
+				 * want the NOR flash or PCMCIA drivers to
+				 * steal our precious bytes of data...
+				 */
+				ce_override = 1;
+				local_irq_save(flags);
+				au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
+			}
+
+			ctx->write_byte(mtd, (u8)(page_addr >> 8));
+
+			if (this->options & NAND_ROW_ADDR_3)
+				ctx->write_byte(mtd,
+						((page_addr >> 16) & 0x0f));
+		}
+		/* Latch in address */
+		au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
+	}
+
+	/*
+	 * Program and erase have their own busy handlers.
+	 * Status and sequential in need no delay.
+	 */
+	switch (command) {
+
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+		return;
+
+	case NAND_CMD_RESET:
+		break;
+
+	case NAND_CMD_READ0:
+	case NAND_CMD_READ1:
+	case NAND_CMD_READOOB:
+		/* Check if we're really driving -CE low (just in case) */
+		if (unlikely(!ce_override))
+			break;
+
+		/* Apply a short delay always to ensure that we do wait tWB. */
+		ndelay(100);
+		/* Wait for a chip to become ready... */
+		for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
+			udelay(1);
+
+		/* Release -CE and re-enable interrupts. */
+		au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
+		local_irq_restore(flags);
+		return;
+	}
+	/* Apply this short delay always to ensure that we do wait tWB. */
+	ndelay(100);
+
+	while(!this->dev_ready(mtd));
+}
+
+static int find_nand_cs(unsigned long nand_base)
+{
+	void __iomem *base =
+			(void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
+	unsigned long addr, staddr, start, mask, end;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		addr = 0x1000 + (i * 0x10);			/* CSx */
+		staddr = __raw_readl(base + addr + 0x08);	/* STADDRx */
+		/* figure out the decoded range of this CS */
+		start = (staddr << 4) & 0xfffc0000;
+		mask = (staddr << 18) & 0xfffc0000;
+		end = (start | (start - 1)) & ~(start ^ mask);
+		if ((nand_base >= start) && (nand_base < end))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int au1550nd_probe(struct platform_device *pdev)
+{
+	struct au1550nd_platdata *pd;
+	struct au1550nd_ctx *ctx;
+	struct nand_chip *this;
+	struct mtd_info *mtd;
+	struct resource *r;
+	int ret, cs;
+
+	pd = dev_get_platdata(&pdev->dev);
+	if (!pd) {
+		dev_err(&pdev->dev, "missing platform data\n");
+		return -ENODEV;
+	}
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no NAND memory resource\n");
+		ret = -ENODEV;
+		goto out1;
+	}
+	if (request_mem_region(r->start, resource_size(r), "au1550-nand")) {
+		dev_err(&pdev->dev, "cannot claim NAND memory area\n");
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	ctx->base = ioremap_nocache(r->start, 0x1000);
+	if (!ctx->base) {
+		dev_err(&pdev->dev, "cannot remap NAND memory area\n");
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	this = &ctx->chip;
+	mtd = nand_to_mtd(this);
+	mtd->dev.parent = &pdev->dev;
+
+	/* figure out which CS# r->start belongs to */
+	cs = find_nand_cs(r->start);
+	if (cs < 0) {
+		dev_err(&pdev->dev, "cannot detect NAND chipselect\n");
+		ret = -ENODEV;
+		goto out3;
+	}
+	ctx->cs = cs;
+
+	this->dev_ready = au1550_device_ready;
+	this->select_chip = au1550_select_chip;
+	this->cmdfunc = au1550_command;
+
+	/* 30 us command delay time */
+	this->chip_delay = 30;
+	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
+
+	if (pd->devwidth)
+		this->options |= NAND_BUSWIDTH_16;
+
+	this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
+	ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
+	this->read_word = au_read_word;
+	this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
+	this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
+
+	ret = nand_scan(mtd, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
+		goto out3;
+	}
+
+	mtd_device_register(mtd, pd->parts, pd->num_parts);
+
+	platform_set_drvdata(pdev, ctx);
+
+	return 0;
+
+out3:
+	iounmap(ctx->base);
+out2:
+	release_mem_region(r->start, resource_size(r));
+out1:
+	kfree(ctx);
+	return ret;
+}
+
+static int au1550nd_remove(struct platform_device *pdev)
+{
+	struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
+	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	nand_release(nand_to_mtd(&ctx->chip));
+	iounmap(ctx->base);
+	release_mem_region(r->start, 0x1000);
+	kfree(ctx);
+	return 0;
+}
+
+static struct platform_driver au1550nd_driver = {
+	.driver = {
+		.name	= "au1550-nand",
+	},
+	.probe		= au1550nd_probe,
+	.remove		= au1550nd_remove,
+};
+
+module_platform_driver(au1550nd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Embedded Edge, LLC");
+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/Makefile b/drivers/mtd/nand/raw/bcm47xxnflash/Makefile
new file mode 100644
index 000000000000..f05b119e134b
--- /dev/null
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/Makefile
@@ -0,0 +1,4 @@
+bcm47xxnflash-y				+= main.o
+bcm47xxnflash-y				+= ops_bcm4706.o
+
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)	+= bcm47xxnflash.o
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
new file mode 100644
index 000000000000..201b9baa52a0
--- /dev/null
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/bcm47xxnflash.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BCM47XXNFLASH_H
+#define __BCM47XXNFLASH_H
+
+#ifndef pr_fmt
+#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+
+struct bcm47xxnflash {
+	struct bcma_drv_cc *cc;
+
+	struct nand_chip nand_chip;
+
+	unsigned curr_command;
+	int curr_page_addr;
+	int curr_column;
+
+	u8 id_data[8];
+};
+
+int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
+
+#endif /* BCM47XXNFLASH */
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
new file mode 100644
index 000000000000..fb31429b70a9
--- /dev/null
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
@@ -0,0 +1,81 @@
+/*
+ * BCM47XX NAND flash driver
+ *
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.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 "bcm47xxnflash.h"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/bcma/bcma.h>
+
+MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rafał Miłecki");
+
+static const char *probes[] = { "bcm47xxpart", NULL };
+
+static int bcm47xxnflash_probe(struct platform_device *pdev)
+{
+	struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+	struct bcm47xxnflash *b47n;
+	struct mtd_info *mtd;
+	int err = 0;
+
+	b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
+	if (!b47n)
+		return -ENOMEM;
+
+	nand_set_controller_data(&b47n->nand_chip, b47n);
+	mtd = nand_to_mtd(&b47n->nand_chip);
+	mtd->dev.parent = &pdev->dev;
+	b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
+
+	if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+		err = bcm47xxnflash_ops_bcm4706_init(b47n);
+	} else {
+		pr_err("Device not supported\n");
+		err = -ENOTSUPP;
+	}
+	if (err) {
+		pr_err("Initialization failed: %d\n", err);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, b47n);
+
+	err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
+	if (err) {
+		pr_err("Failed to register MTD device: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static int bcm47xxnflash_remove(struct platform_device *pdev)
+{
+	struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&nflash->nand_chip));
+
+	return 0;
+}
+
+static struct platform_driver bcm47xxnflash_driver = {
+	.probe	= bcm47xxnflash_probe,
+	.remove = bcm47xxnflash_remove,
+	.driver = {
+		.name = "bcma_nflash",
+	},
+};
+
+module_platform_driver(bcm47xxnflash_driver);
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
new file mode 100644
index 000000000000..54bac5b73f0a
--- /dev/null
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
@@ -0,0 +1,456 @@
+/*
+ * BCM47XX NAND flash driver
+ *
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.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 "bcm47xxnflash.h"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/bcma/bcma.h>
+
+/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
+ * shown ~1000 retries as maxiumum. */
+#define NFLASH_READY_RETRIES		10000
+
+#define NFLASH_SECTOR_SIZE		512
+
+#define NCTL_CMD0			0x00010000
+#define NCTL_COL			0x00020000	/* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
+#define NCTL_ROW			0x00040000	/* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
+#define NCTL_CMD1W			0x00080000
+#define NCTL_READ			0x00100000
+#define NCTL_WRITE			0x00200000
+#define NCTL_SPECADDR			0x01000000
+#define NCTL_READY			0x04000000
+#define NCTL_ERR			0x08000000
+#define NCTL_CSA			0x40000000
+#define NCTL_START			0x80000000
+
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
+{
+	return ((ns * 1000 * clock) / 1000000) + 1;
+}
+
+static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
+{
+	int i = 0;
+
+	bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
+	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+		if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
+			i = 0;
+			break;
+		}
+	}
+	if (i) {
+		pr_err("NFLASH control command not ready!\n");
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
+{
+	int i;
+
+	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+		if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
+			if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
+			    BCMA_CC_NFLASH_CTL_ERR) {
+				pr_err("Error on polling\n");
+				return -EBUSY;
+			} else {
+				return 0;
+			}
+		}
+	}
+
+	pr_err("Polling timeout!\n");
+	return -EBUSY;
+}
+
+/**************************************************
+ * R/W
+ **************************************************/
+
+static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
+					   int len)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+
+	u32 ctlcode;
+	u32 *dest = (u32 *)buf;
+	int i;
+	int toread;
+
+	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+	/* Don't validate column using nand_chip->page_shift, it may be bigger
+	 * when accessing OOB */
+
+	while (len) {
+		/* We can read maximum of 0x200 bytes at once */
+		toread = min(len, 0x200);
+
+		/* Set page and column */
+		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
+				b47n->curr_column);
+		bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
+				b47n->curr_page_addr);
+
+		/* Prepare to read */
+		ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
+			  NCTL_CMD0;
+		ctlcode |= NAND_CMD_READSTART << 8;
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
+			return;
+		if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
+			return;
+
+		/* Eventually read some data :) */
+		for (i = 0; i < toread; i += 4, dest++) {
+			ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
+			if (i == toread - 4) /* Last read goes without that */
+				ctlcode &= ~NCTL_CSA;
+			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+							      ctlcode))
+				return;
+			*dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
+		}
+
+		b47n->curr_column += toread;
+		len -= toread;
+	}
+}
+
+static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
+					    const uint8_t *buf, int len)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+	struct bcma_drv_cc *cc = b47n->cc;
+
+	u32 ctlcode;
+	const u32 *data = (u32 *)buf;
+	int i;
+
+	BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+	/* Don't validate column using nand_chip->page_shift, it may be bigger
+	 * when accessing OOB */
+
+	for (i = 0; i < len; i += 4, data++) {
+		bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
+
+		ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
+		if (i == len - 4) /* Last read goes without that */
+			ctlcode &= ~NCTL_CSA;
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
+			pr_err("%s ctl_cmd didn't work!\n", __func__);
+			return;
+		}
+	}
+
+	b47n->curr_column += len;
+}
+
+/**************************************************
+ * NAND chip ops
+ **************************************************/
+
+static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
+					       unsigned int ctrl)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+	u32 code = 0;
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (cmd & NAND_CTRL_CLE)
+		code = cmd | NCTL_CMD0;
+
+	/* nCS is not needed for reset command */
+	if (cmd != NAND_CMD_RESET)
+		code |= NCTL_CSA;
+
+	bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
+}
+
+/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
+static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
+						  int chip)
+{
+	return;
+}
+
+static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+
+	return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
+}
+
+/*
+ * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
+ * For example, reading chip id is performed in a non-standard way.
+ * Setting column and page is also handled differently, we use a special
+ * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
+ * standard commands would be much more complicated.
+ */
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
+					      unsigned command, int column,
+					      int page_addr)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+	struct bcma_drv_cc *cc = b47n->cc;
+	u32 ctlcode;
+	int i;
+
+	if (column != -1)
+		b47n->curr_column = column;
+	if (page_addr != -1)
+		b47n->curr_page_addr = page_addr;
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
+
+		ndelay(100);
+		nand_wait_ready(mtd);
+		break;
+	case NAND_CMD_READID:
+		ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
+		ctlcode |= NAND_CMD_READID;
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
+			pr_err("READID error\n");
+			break;
+		}
+
+		/*
+		 * Reading is specific, last one has to go without NCTL_CSA
+		 * bit. We don't know how many reads NAND subsystem is going
+		 * to perform, so cache everything.
+		 */
+		for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
+			ctlcode = NCTL_CSA | NCTL_READ;
+			if (i == ARRAY_SIZE(b47n->id_data) - 1)
+				ctlcode &= ~NCTL_CSA;
+			if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+							      ctlcode)) {
+				pr_err("READID error\n");
+				break;
+			}
+			b47n->id_data[i] =
+				bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
+				& 0xFF;
+		}
+
+		break;
+	case NAND_CMD_STATUS:
+		ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+			pr_err("STATUS command error\n");
+		break;
+	case NAND_CMD_READ0:
+		break;
+	case NAND_CMD_READOOB:
+		if (page_addr != -1)
+			b47n->curr_column += mtd->writesize;
+		break;
+	case NAND_CMD_ERASE1:
+		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+				b47n->curr_page_addr);
+		ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
+			  NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+			pr_err("ERASE1 failed\n");
+		break;
+	case NAND_CMD_ERASE2:
+		break;
+	case NAND_CMD_SEQIN:
+		/* Set page and column */
+		bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
+				b47n->curr_column);
+		bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+				b47n->curr_page_addr);
+
+		/* Prepare to write */
+		ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
+		ctlcode |= NAND_CMD_SEQIN;
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+			pr_err("SEQIN failed\n");
+		break;
+	case NAND_CMD_PAGEPROG:
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
+							  NAND_CMD_PAGEPROG))
+			pr_err("PAGEPROG failed\n");
+		if (bcm47xxnflash_ops_bcm4706_poll(cc))
+			pr_err("PAGEPROG not ready\n");
+		break;
+	default:
+		pr_err("Command 0x%X unsupported\n", command);
+		break;
+	}
+	b47n->curr_command = command;
+}
+
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+	struct bcma_drv_cc *cc = b47n->cc;
+	u32 tmp = 0;
+
+	switch (b47n->curr_command) {
+	case NAND_CMD_READID:
+		if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
+			pr_err("Requested invalid id_data: %d\n",
+			       b47n->curr_column);
+			return 0;
+		}
+		return b47n->id_data[b47n->curr_column++];
+	case NAND_CMD_STATUS:
+		if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
+			return 0;
+		return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
+	case NAND_CMD_READOOB:
+		bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
+		return tmp & 0xFF;
+	}
+
+	pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
+	return 0;
+}
+
+static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
+					       uint8_t *buf, int len)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+
+	switch (b47n->curr_command) {
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+		bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+		return;
+	}
+
+	pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
+}
+
+static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
+						const uint8_t *buf, int len)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
+
+	switch (b47n->curr_command) {
+	case NAND_CMD_SEQIN:
+		bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+		return;
+	}
+
+	pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
+}
+
+/**************************************************
+ * Init
+ **************************************************/
+
+int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
+{
+	struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
+	int err;
+	u32 freq;
+	u16 clock;
+	u8 w0, w1, w2, w3, w4;
+
+	unsigned long chipsize; /* MiB */
+	u8 tbits, col_bits, col_size, row_bits, row_bsize;
+	u32 val;
+
+	b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
+	nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
+	nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
+	b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+	b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+	b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+	b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+	b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
+	b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
+
+	nand_chip->chip_delay = 50;
+	b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
+	b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
+
+	/* Enable NAND flash access */
+	bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+		      BCMA_CC_4706_FLASHSCFG_NF1);
+
+	/* Configure wait counters */
+	if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
+		/* 400 MHz */
+		freq = 400000000 / 4;
+	} else {
+		freq = bcma_chipco_pll_read(b47n->cc, 4);
+		freq = (freq & 0xFFF) >> 3;
+		/* Fixed reference clock 25 MHz and m = 2 */
+		freq = (freq * 25000000 / 2) / 4;
+	}
+	clock = freq / 1000000;
+	w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
+	w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
+	w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+	w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+	w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
+	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
+			(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
+
+	/* Scan NAND */
+	err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
+	if (err) {
+		pr_err("Could not scan NAND flash: %d\n", err);
+		goto exit;
+	}
+
+	/* Configure FLASH */
+	chipsize = b47n->nand_chip.chipsize >> 20;
+	tbits = ffs(chipsize); /* find first bit set */
+	if (!tbits || tbits != fls(chipsize)) {
+		pr_err("Invalid flash size: 0x%lX\n", chipsize);
+		err = -ENOTSUPP;
+		goto exit;
+	}
+	tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
+
+	col_bits = b47n->nand_chip.page_shift + 1;
+	col_size = (col_bits + 7) / 8;
+
+	row_bits = tbits - col_bits + 1;
+	row_bsize = (row_bits + 7) / 8;
+
+	val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
+	bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
+
+exit:
+	if (err)
+		bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+			       ~BCMA_CC_4706_FLASHSCFG_NF1);
+	return err;
+}
diff --git a/drivers/mtd/nand/raw/bf5xx_nand.c b/drivers/mtd/nand/raw/bf5xx_nand.c
new file mode 100644
index 000000000000..9a1d8d104570
--- /dev/null
+++ b/drivers/mtd/nand/raw/bf5xx_nand.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright 2006-2008 Analog Devices Inc.
+ *	http://blackfin.uclinux.org/
+ *	Bryan Wu <bryan.wu@analog.com>
+ *
+ * Blackfin BF5xx on-chip NAND flash controller driver
+ *
+ * Derived from s3c2410.c
+ * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
+ *
+ * Derived from cafe.c
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Changelog:
+ *	12-Jun-2007  Bryan Wu:  Initial version
+ *	18-Jul-2007  Bryan Wu:
+ *		- ECC_HW and ECC_SW supported
+ *		- DMA supported in ECC_HW
+ *		- YAFFS tested as rootfs in both ECC_HW and ECC_SW
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME	"bf5xx-nand"
+#define DRV_VERSION	"1.2"
+#define DRV_AUTHOR	"Bryan Wu <bryan.wu@analog.com>"
+#define DRV_DESC	"BF5xx on-chip NAND FLash Controller Driver"
+
+/* NFC_STAT Masks */
+#define NBUSY       0x01  /* Not Busy */
+#define WB_FULL     0x02  /* Write Buffer Full */
+#define PG_WR_STAT  0x04  /* Page Write Pending */
+#define PG_RD_STAT  0x08  /* Page Read Pending */
+#define WB_EMPTY    0x10  /* Write Buffer Empty */
+
+/* NFC_IRQSTAT Masks */
+#define NBUSYIRQ    0x01  /* Not Busy IRQ */
+#define WB_OVF      0x02  /* Write Buffer Overflow */
+#define WB_EDGE     0x04  /* Write Buffer Edge Detect */
+#define RD_RDY      0x08  /* Read Data Ready */
+#define WR_DONE     0x10  /* Page Write Done */
+
+/* NFC_RST Masks */
+#define ECC_RST     0x01  /* ECC (and NFC counters) Reset */
+
+/* NFC_PGCTL Masks */
+#define PG_RD_START 0x01  /* Page Read Start */
+#define PG_WR_START 0x02  /* Page Write Start */
+
+#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
+static int hardware_ecc = 1;
+#else
+static int hardware_ecc;
+#endif
+
+static const unsigned short bfin_nfc_pin_req[] =
+	{P_NAND_CE,
+	 P_NAND_RB,
+	 P_NAND_D0,
+	 P_NAND_D1,
+	 P_NAND_D2,
+	 P_NAND_D3,
+	 P_NAND_D4,
+	 P_NAND_D5,
+	 P_NAND_D6,
+	 P_NAND_D7,
+	 P_NAND_WE,
+	 P_NAND_RE,
+	 P_NAND_CLE,
+	 P_NAND_ALE,
+	 0};
+
+#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
+static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = section * 8;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 7)
+		return -ERANGE;
+
+	oobregion->offset = (section * 8) + 3;
+	oobregion->length = 5;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
+	.ecc = bootrom_ooblayout_ecc,
+	.free = bootrom_ooblayout_free,
+};
+#endif
+
+/*
+ * Data structures for bf5xx nand flash controller driver
+ */
+
+/* bf5xx nand info */
+struct bf5xx_nand_info {
+	/* mtd info */
+	struct nand_hw_control		controller;
+	struct nand_chip		chip;
+
+	/* platform info */
+	struct bf5xx_nand_platform	*platform;
+
+	/* device info */
+	struct device			*device;
+
+	/* DMA stuff */
+	struct completion		dma_completion;
+};
+
+/*
+ * Conversion functions
+ */
+static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
+			    chip);
+}
+
+static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
+{
+	return platform_get_drvdata(pdev);
+}
+
+static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
+{
+	return dev_get_platdata(&pdev->dev);
+}
+
+/*
+ * struct nand_chip interface function pointers
+ */
+
+/*
+ * bf5xx_nand_hwcontrol
+ *
+ * Issue command and address cycles to the chip
+ */
+static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	while (bfin_read_NFC_STAT() & WB_FULL)
+		cpu_relax();
+
+	if (ctrl & NAND_CLE)
+		bfin_write_NFC_CMD(cmd);
+	else if (ctrl & NAND_ALE)
+		bfin_write_NFC_ADDR(cmd);
+	SSYNC();
+}
+
+/*
+ * bf5xx_nand_devready()
+ *
+ * returns 0 if the nand is busy, 1 if it is ready
+ */
+static int bf5xx_nand_devready(struct mtd_info *mtd)
+{
+	unsigned short val = bfin_read_NFC_STAT();
+
+	if ((val & NBUSY) == NBUSY)
+		return 1;
+	else
+		return 0;
+}
+
+/*
+ * ECC functions
+ * These allow the bf5xx to use the controller's ECC
+ * generator block to ECC the data as it passes through
+ */
+
+/*
+ * ECC error correction function
+ */
+static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
+					u_char *read_ecc, u_char *calc_ecc)
+{
+	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+	u32 syndrome[5];
+	u32 calced, stored;
+	int i;
+	unsigned short failing_bit, failing_byte;
+	u_char data;
+
+	calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
+	stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
+
+	syndrome[0] = (calced ^ stored);
+
+	/*
+	 * syndrome 0: all zero
+	 * No error in data
+	 * No action
+	 */
+	if (!syndrome[0] || !calced || !stored)
+		return 0;
+
+	/*
+	 * sysdrome 0: only one bit is one
+	 * ECC data was incorrect
+	 * No action
+	 */
+	if (hweight32(syndrome[0]) == 1) {
+		dev_err(info->device, "ECC data was incorrect!\n");
+		return -EBADMSG;
+	}
+
+	syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
+	syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
+	syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
+	syndrome[4] = syndrome[2] ^ syndrome[3];
+
+	for (i = 0; i < 5; i++)
+		dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
+
+	dev_info(info->device,
+		"calced[0x%08x], stored[0x%08x]\n",
+		calced, stored);
+
+	/*
+	 * sysdrome 0: exactly 11 bits are one, each parity
+	 * and parity' pair is 1 & 0 or 0 & 1.
+	 * 1-bit correctable error
+	 * Correct the error
+	 */
+	if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
+		dev_info(info->device,
+			"1-bit correctable error, correct it.\n");
+		dev_info(info->device,
+			"syndrome[1] 0x%08x\n", syndrome[1]);
+
+		failing_bit = syndrome[1] & 0x7;
+		failing_byte = syndrome[1] >> 0x3;
+		data = *(dat + failing_byte);
+		data = data ^ (0x1 << failing_bit);
+		*(dat + failing_byte) = data;
+
+		return 1;
+	}
+
+	/*
+	 * sysdrome 0: random data
+	 * More than 1-bit error, non-correctable error
+	 * Discard data, mark bad block
+	 */
+	dev_err(info->device,
+		"More than 1-bit error, non-correctable error.\n");
+	dev_err(info->device,
+		"Please discard data, mark bad block\n");
+
+	return -EBADMSG;
+}
+
+static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+					u_char *read_ecc, u_char *calc_ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret, bitflips = 0;
+
+	ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+	if (ret < 0)
+		return ret;
+
+	bitflips = ret;
+
+	/* If ecc size is 512, correct second 256 bytes */
+	if (chip->ecc.size == 512) {
+		dat += 256;
+		read_ecc += 3;
+		calc_ecc += 3;
+		ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+		if (ret < 0)
+			return ret;
+
+		bitflips += ret;
+	}
+
+	return bitflips;
+}
+
+static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	return;
+}
+
+static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
+		const u_char *dat, u_char *ecc_code)
+{
+	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u16 ecc0, ecc1;
+	u32 code[2];
+	u8 *p;
+
+	/* first 3 bytes ECC code for 256 page size */
+	ecc0 = bfin_read_NFC_ECC0();
+	ecc1 = bfin_read_NFC_ECC1();
+
+	code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
+
+	dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
+
+	p = (u8 *) code;
+	memcpy(ecc_code, p, 3);
+
+	/* second 3 bytes ECC code for 512 ecc size */
+	if (chip->ecc.size == 512) {
+		ecc0 = bfin_read_NFC_ECC2();
+		ecc1 = bfin_read_NFC_ECC3();
+		code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
+
+		/* second 3 bytes in ecc_code for second 256
+		 * bytes of 512 page size
+		 */
+		p = (u8 *) (code + 1);
+		memcpy((ecc_code + 3), p, 3);
+		dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
+	}
+
+	return 0;
+}
+
+/*
+ * PIO mode for buffer writing and reading
+ */
+static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	unsigned short val;
+
+	/*
+	 * Data reads are requested by first writing to NFC_DATA_RD
+	 * and then reading back from NFC_READ.
+	 */
+	for (i = 0; i < len; i++) {
+		while (bfin_read_NFC_STAT() & WB_FULL)
+			cpu_relax();
+
+		/* Contents do not matter */
+		bfin_write_NFC_DATA_RD(0x0000);
+		SSYNC();
+
+		while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
+			cpu_relax();
+
+		buf[i] = bfin_read_NFC_READ();
+
+		val = bfin_read_NFC_IRQSTAT();
+		val |= RD_RDY;
+		bfin_write_NFC_IRQSTAT(val);
+		SSYNC();
+	}
+}
+
+static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
+{
+	uint8_t val;
+
+	bf5xx_nand_read_buf(mtd, &val, 1);
+
+	return val;
+}
+
+static void bf5xx_nand_write_buf(struct mtd_info *mtd,
+				const uint8_t *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		while (bfin_read_NFC_STAT() & WB_FULL)
+			cpu_relax();
+
+		bfin_write_NFC_DATA_WR(buf[i]);
+		SSYNC();
+	}
+}
+
+static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+
+	/*
+	 * Data reads are requested by first writing to NFC_DATA_RD
+	 * and then reading back from NFC_READ.
+	 */
+	bfin_write_NFC_DATA_RD(0x5555);
+
+	SSYNC();
+
+	for (i = 0; i < len; i++)
+		p[i] = bfin_read_NFC_READ();
+}
+
+static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
+				const uint8_t *buf, int len)
+{
+	int i;
+	u16 *p = (u16 *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++)
+		bfin_write_NFC_DATA_WR(p[i]);
+
+	SSYNC();
+}
+
+/*
+ * DMA functions for buffer writing and reading
+ */
+static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
+{
+	struct bf5xx_nand_info *info = dev_id;
+
+	clear_dma_irqstat(CH_NFC);
+	disable_dma(CH_NFC);
+	complete(&info->dma_completion);
+
+	return IRQ_HANDLED;
+}
+
+static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
+				uint8_t *buf, int is_read)
+{
+	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	unsigned short val;
+
+	dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
+			mtd, buf, is_read);
+
+	/*
+	 * Before starting a dma transfer, be sure to invalidate/flush
+	 * the cache over the address range of your DMA buffer to
+	 * prevent cache coherency problems. Otherwise very subtle bugs
+	 * can be introduced to your driver.
+	 */
+	if (is_read)
+		invalidate_dcache_range((unsigned int)buf,
+				(unsigned int)(buf + chip->ecc.size));
+	else
+		flush_dcache_range((unsigned int)buf,
+				(unsigned int)(buf + chip->ecc.size));
+
+	/*
+	 * This register must be written before each page is
+	 * transferred to generate the correct ECC register
+	 * values.
+	 */
+	bfin_write_NFC_RST(ECC_RST);
+	SSYNC();
+	while (bfin_read_NFC_RST() & ECC_RST)
+		cpu_relax();
+
+	disable_dma(CH_NFC);
+	clear_dma_irqstat(CH_NFC);
+
+	/* setup DMA register with Blackfin DMA API */
+	set_dma_config(CH_NFC, 0x0);
+	set_dma_start_addr(CH_NFC, (unsigned long) buf);
+
+	/* The DMAs have different size on BF52x and BF54x */
+#ifdef CONFIG_BF52x
+	set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
+	set_dma_x_modify(CH_NFC, 2);
+	val = DI_EN | WDSIZE_16;
+#endif
+
+#ifdef CONFIG_BF54x
+	set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
+	set_dma_x_modify(CH_NFC, 4);
+	val = DI_EN | WDSIZE_32;
+#endif
+	/* setup write or read operation */
+	if (is_read)
+		val |= WNR;
+	set_dma_config(CH_NFC, val);
+	enable_dma(CH_NFC);
+
+	/* Start PAGE read/write operation */
+	if (is_read)
+		bfin_write_NFC_PGCTL(PG_RD_START);
+	else
+		bfin_write_NFC_PGCTL(PG_WR_START);
+	wait_for_completion(&info->dma_completion);
+}
+
+static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
+					uint8_t *buf, int len)
+{
+	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
+
+	if (len == chip->ecc.size)
+		bf5xx_nand_dma_rw(mtd, buf, 1);
+	else
+		bf5xx_nand_read_buf(mtd, buf, len);
+}
+
+static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
+				const uint8_t *buf, int len)
+{
+	struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
+
+	if (len == chip->ecc.size)
+		bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
+	else
+		bf5xx_nand_write_buf(mtd, buf, len);
+}
+
+static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		uint8_t *buf, int oob_required, int page)
+{
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
+	bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return 0;
+}
+
+static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
+		struct nand_chip *chip,	const uint8_t *buf, int oob_required,
+		int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+/*
+ * System initialization functions
+ */
+static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
+{
+	int ret;
+
+	/* Do not use dma */
+	if (!hardware_ecc)
+		return 0;
+
+	init_completion(&info->dma_completion);
+
+	/* Request NFC DMA channel */
+	ret = request_dma(CH_NFC, "BF5XX NFC driver");
+	if (ret < 0) {
+		dev_err(info->device, " unable to get DMA channel\n");
+		return ret;
+	}
+
+#ifdef CONFIG_BF54x
+	/* Setup DMAC1 channel mux for NFC which shared with SDH */
+	bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
+	SSYNC();
+#endif
+
+	set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
+
+	/* Turn off the DMA channel first */
+	disable_dma(CH_NFC);
+	return 0;
+}
+
+static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
+{
+	/* Free NFC DMA channel */
+	if (hardware_ecc)
+		free_dma(CH_NFC);
+}
+
+/*
+ * BF5XX NFC hardware initialization
+ *  - pin mux setup
+ *  - clear interrupt status
+ */
+static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
+{
+	int err = 0;
+	unsigned short val;
+	struct bf5xx_nand_platform *plat = info->platform;
+
+	/* setup NFC_CTL register */
+	dev_info(info->device,
+		"data_width=%d, wr_dly=%d, rd_dly=%d\n",
+		(plat->data_width ? 16 : 8),
+		plat->wr_dly, plat->rd_dly);
+
+	val = (1 << NFC_PG_SIZE_OFFSET) |
+		(plat->data_width << NFC_NWIDTH_OFFSET) |
+		(plat->rd_dly << NFC_RDDLY_OFFSET) |
+		(plat->wr_dly << NFC_WRDLY_OFFSET);
+	dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
+
+	bfin_write_NFC_CTL(val);
+	SSYNC();
+
+	/* clear interrupt status */
+	bfin_write_NFC_IRQMASK(0x0);
+	SSYNC();
+	val = bfin_read_NFC_IRQSTAT();
+	bfin_write_NFC_IRQSTAT(val);
+	SSYNC();
+
+	/* DMA initialization  */
+	if (bf5xx_nand_dma_init(info))
+		err = -ENXIO;
+
+	return err;
+}
+
+/*
+ * Device management interface
+ */
+static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+{
+	struct mtd_info *mtd = nand_to_mtd(&info->chip);
+	struct mtd_partition *parts = info->platform->partitions;
+	int nr = info->platform->nr_partitions;
+
+	return mtd_device_register(mtd, parts, nr);
+}
+
+static int bf5xx_nand_remove(struct platform_device *pdev)
+{
+	struct bf5xx_nand_info *info = to_nand_info(pdev);
+
+	/* first thing we need to do is release all our mtds
+	 * and their partitions, then go through freeing the
+	 * resources used
+	 */
+	nand_release(nand_to_mtd(&info->chip));
+
+	peripheral_free_list(bfin_nfc_pin_req);
+	bf5xx_nand_dma_remove(info);
+
+	return 0;
+}
+
+static int bf5xx_nand_scan(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		return ret;
+
+	if (hardware_ecc) {
+		/*
+		 * for nand with page size > 512B, think it as several sections with 512B
+		 */
+		if (likely(mtd->writesize >= 512)) {
+			chip->ecc.size = 512;
+			chip->ecc.bytes = 6;
+			chip->ecc.strength = 2;
+		} else {
+			chip->ecc.size = 256;
+			chip->ecc.bytes = 3;
+			chip->ecc.strength = 1;
+			bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
+			SSYNC();
+		}
+	}
+
+	return	nand_scan_tail(mtd);
+}
+
+/*
+ * bf5xx_nand_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices
+ */
+static int bf5xx_nand_probe(struct platform_device *pdev)
+{
+	struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
+	struct bf5xx_nand_info *info = NULL;
+	struct nand_chip *chip = NULL;
+	struct mtd_info *mtd = NULL;
+	int err = 0;
+
+	dev_dbg(&pdev->dev, "(%p)\n", pdev);
+
+	if (!plat) {
+		dev_err(&pdev->dev, "no platform specific information\n");
+		return -EINVAL;
+	}
+
+	if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+		dev_err(&pdev->dev, "requesting Peripherals failed\n");
+		return -EFAULT;
+	}
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (info == NULL) {
+		err = -ENOMEM;
+		goto out_err;
+	}
+
+	platform_set_drvdata(pdev, info);
+
+	nand_hw_control_init(&info->controller);
+
+	info->device     = &pdev->dev;
+	info->platform   = plat;
+
+	/* initialise chip data struct */
+	chip = &info->chip;
+	mtd = nand_to_mtd(&info->chip);
+
+	if (plat->data_width)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
+
+	chip->read_buf = (plat->data_width) ?
+		bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
+	chip->write_buf = (plat->data_width) ?
+		bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
+
+	chip->read_byte    = bf5xx_nand_read_byte;
+
+	chip->cmd_ctrl     = bf5xx_nand_hwcontrol;
+	chip->dev_ready    = bf5xx_nand_devready;
+
+	nand_set_controller_data(chip, mtd);
+	chip->controller   = &info->controller;
+
+	chip->IO_ADDR_R    = (void __iomem *) NFC_READ;
+	chip->IO_ADDR_W    = (void __iomem *) NFC_DATA_WR;
+
+	chip->chip_delay   = 0;
+
+	/* initialise mtd info data struct */
+	mtd->dev.parent = &pdev->dev;
+
+	/* initialise the hardware */
+	err = bf5xx_nand_hw_init(info);
+	if (err)
+		goto out_err;
+
+	/* setup hardware ECC data struct */
+	if (hardware_ecc) {
+#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
+		mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
+#endif
+		chip->read_buf      = bf5xx_nand_dma_read_buf;
+		chip->write_buf     = bf5xx_nand_dma_write_buf;
+		chip->ecc.calculate = bf5xx_nand_calculate_ecc;
+		chip->ecc.correct   = bf5xx_nand_correct_data;
+		chip->ecc.mode	    = NAND_ECC_HW;
+		chip->ecc.hwctl	    = bf5xx_nand_enable_hwecc;
+		chip->ecc.read_page_raw = bf5xx_nand_read_page_raw;
+		chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
+	} else {
+		chip->ecc.mode	    = NAND_ECC_SOFT;
+		chip->ecc.algo	= NAND_ECC_HAMMING;
+	}
+
+	/* scan hardware nand chip and setup mtd info data struct */
+	if (bf5xx_nand_scan(mtd)) {
+		err = -ENXIO;
+		goto out_err_nand_scan;
+	}
+
+#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
+	chip->badblockpos = 63;
+#endif
+
+	/* add NAND partition */
+	bf5xx_nand_add_partition(info);
+
+	dev_dbg(&pdev->dev, "initialised ok\n");
+	return 0;
+
+out_err_nand_scan:
+	bf5xx_nand_dma_remove(info);
+out_err:
+	peripheral_free_list(bfin_nfc_pin_req);
+
+	return err;
+}
+
+/* driver device registration */
+static struct platform_driver bf5xx_nand_driver = {
+	.probe		= bf5xx_nand_probe,
+	.remove		= bf5xx_nand_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+	},
+};
+
+module_platform_driver(bf5xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/mtd/nand/raw/brcmnand/Makefile b/drivers/mtd/nand/raw/brcmnand/Makefile
new file mode 100644
index 000000000000..195b845e48b8
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# link order matters; don't link the more generic brcmstb_nand.o before the
+# more specific iproc_nand.o, for instance
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= iproc_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm63138_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= bcm6368_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmstb_nand.o
+obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand.o
diff --git a/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
new file mode 100644
index 000000000000..59444b3a697d
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2015 Broadcom 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/device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "brcmnand.h"
+
+struct bcm63138_nand_soc {
+	struct brcmnand_soc soc;
+	void __iomem *base;
+};
+
+#define BCM63138_NAND_INT_STATUS		0x00
+#define BCM63138_NAND_INT_EN			0x04
+
+enum {
+	BCM63138_CTLRDY		= BIT(4),
+};
+
+static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
+{
+	struct bcm63138_nand_soc *priv =
+			container_of(soc, struct bcm63138_nand_soc, soc);
+	void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
+	u32 val = brcmnand_readl(mmio);
+
+	if (val & BCM63138_CTLRDY) {
+		brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
+		return true;
+	}
+
+	return false;
+}
+
+static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
+{
+	struct bcm63138_nand_soc *priv =
+			container_of(soc, struct bcm63138_nand_soc, soc);
+	void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
+	u32 val = brcmnand_readl(mmio);
+
+	if (en)
+		val |= BCM63138_CTLRDY;
+	else
+		val &= ~BCM63138_CTLRDY;
+
+	brcmnand_writel(val, mmio);
+}
+
+static int bcm63138_nand_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm63138_nand_soc *priv;
+	struct brcmnand_soc *soc;
+	struct resource *res;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	soc = &priv->soc;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	soc->ctlrdy_ack = bcm63138_nand_intc_ack;
+	soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
+
+	return brcmnand_probe(pdev, soc);
+}
+
+static const struct of_device_id bcm63138_nand_of_match[] = {
+	{ .compatible = "brcm,nand-bcm63138" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
+
+static struct platform_driver bcm63138_nand_driver = {
+	.probe			= bcm63138_nand_probe,
+	.remove			= brcmnand_remove,
+	.driver = {
+		.name		= "bcm63138_nand",
+		.pm		= &brcmnand_pm_ops,
+		.of_match_table	= bcm63138_nand_of_match,
+	}
+};
+module_platform_driver(bcm63138_nand_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_DESCRIPTION("NAND driver for BCM63138");
diff --git a/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
new file mode 100644
index 000000000000..34c91b0e1e69
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 Simon Arlott
+ *
+ * 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.
+ *
+ * Derived from bcm63138_nand.c:
+ * Copyright © 2015 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ * Copyright 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/flash/nandflash.c:
+ * Copyright 2000-2010 Broadcom Corporation
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "brcmnand.h"
+
+struct bcm6368_nand_soc {
+	struct brcmnand_soc soc;
+	void __iomem *base;
+};
+
+#define BCM6368_NAND_INT		0x00
+#define  BCM6368_NAND_STATUS_SHIFT	0
+#define  BCM6368_NAND_STATUS_MASK	(0xfff << BCM6368_NAND_STATUS_SHIFT)
+#define  BCM6368_NAND_ENABLE_SHIFT	16
+#define  BCM6368_NAND_ENABLE_MASK	(0xffff << BCM6368_NAND_ENABLE_SHIFT)
+#define BCM6368_NAND_BASE_ADDR0	0x04
+#define BCM6368_NAND_BASE_ADDR1	0x0c
+
+enum {
+	BCM6368_NP_READ		= BIT(0),
+	BCM6368_BLOCK_ERASE	= BIT(1),
+	BCM6368_COPY_BACK	= BIT(2),
+	BCM6368_PAGE_PGM	= BIT(3),
+	BCM6368_CTRL_READY	= BIT(4),
+	BCM6368_DEV_RBPIN	= BIT(5),
+	BCM6368_ECC_ERR_UNC	= BIT(6),
+	BCM6368_ECC_ERR_CORR	= BIT(7),
+};
+
+static bool bcm6368_nand_intc_ack(struct brcmnand_soc *soc)
+{
+	struct bcm6368_nand_soc *priv =
+			container_of(soc, struct bcm6368_nand_soc, soc);
+	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
+	u32 val = brcmnand_readl(mmio);
+
+	if (val & (BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT)) {
+		/* Ack interrupt */
+		val &= ~BCM6368_NAND_STATUS_MASK;
+		val |= BCM6368_CTRL_READY << BCM6368_NAND_STATUS_SHIFT;
+		brcmnand_writel(val, mmio);
+		return true;
+	}
+
+	return false;
+}
+
+static void bcm6368_nand_intc_set(struct brcmnand_soc *soc, bool en)
+{
+	struct bcm6368_nand_soc *priv =
+			container_of(soc, struct bcm6368_nand_soc, soc);
+	void __iomem *mmio = priv->base + BCM6368_NAND_INT;
+	u32 val = brcmnand_readl(mmio);
+
+	/* Don't ack any interrupts */
+	val &= ~BCM6368_NAND_STATUS_MASK;
+
+	if (en)
+		val |= BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT;
+	else
+		val &= ~(BCM6368_CTRL_READY << BCM6368_NAND_ENABLE_SHIFT);
+
+	brcmnand_writel(val, mmio);
+}
+
+static int bcm6368_nand_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm6368_nand_soc *priv;
+	struct brcmnand_soc *soc;
+	struct resource *res;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	soc = &priv->soc;
+
+	res = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "nand-int-base");
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	soc->ctlrdy_ack = bcm6368_nand_intc_ack;
+	soc->ctlrdy_set_enabled = bcm6368_nand_intc_set;
+
+	/* Disable and ack all interrupts  */
+	brcmnand_writel(0, priv->base + BCM6368_NAND_INT);
+	brcmnand_writel(BCM6368_NAND_STATUS_MASK,
+			priv->base + BCM6368_NAND_INT);
+
+	return brcmnand_probe(pdev, soc);
+}
+
+static const struct of_device_id bcm6368_nand_of_match[] = {
+	{ .compatible = "brcm,nand-bcm6368" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match);
+
+static struct platform_driver bcm6368_nand_driver = {
+	.probe			= bcm6368_nand_probe,
+	.remove			= brcmnand_remove,
+	.driver = {
+		.name		= "bcm6368_nand",
+		.pm		= &brcmnand_pm_ops,
+		.of_match_table	= bcm6368_nand_of_match,
+	}
+};
+module_platform_driver(bcm6368_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Arlott");
+MODULE_DESCRIPTION("NAND driver for BCM6368");
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
new file mode 100644
index 000000000000..c28fd2bc1a84
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -0,0 +1,2620 @@
+/*
+ * Copyright © 2010-2015 Broadcom 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/clk.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/log2.h>
+
+#include "brcmnand.h"
+
+/*
+ * This flag controls if WP stays on between erase/write commands to mitigate
+ * flash corruption due to power glitches. Values:
+ * 0: NAND_WP is not used or not available
+ * 1: NAND_WP is set by default, cleared for erase/write operations
+ * 2: NAND_WP is always cleared
+ */
+static int wp_on = 1;
+module_param(wp_on, int, 0444);
+
+/***********************************************************************
+ * Definitions
+ ***********************************************************************/
+
+#define DRV_NAME			"brcmnand"
+
+#define CMD_NULL			0x00
+#define CMD_PAGE_READ			0x01
+#define CMD_SPARE_AREA_READ		0x02
+#define CMD_STATUS_READ			0x03
+#define CMD_PROGRAM_PAGE		0x04
+#define CMD_PROGRAM_SPARE_AREA		0x05
+#define CMD_COPY_BACK			0x06
+#define CMD_DEVICE_ID_READ		0x07
+#define CMD_BLOCK_ERASE			0x08
+#define CMD_FLASH_RESET			0x09
+#define CMD_BLOCKS_LOCK			0x0a
+#define CMD_BLOCKS_LOCK_DOWN		0x0b
+#define CMD_BLOCKS_UNLOCK		0x0c
+#define CMD_READ_BLOCKS_LOCK_STATUS	0x0d
+#define CMD_PARAMETER_READ		0x0e
+#define CMD_PARAMETER_CHANGE_COL	0x0f
+#define CMD_LOW_LEVEL_OP		0x10
+
+struct brcm_nand_dma_desc {
+	u32 next_desc;
+	u32 next_desc_ext;
+	u32 cmd_irq;
+	u32 dram_addr;
+	u32 dram_addr_ext;
+	u32 tfr_len;
+	u32 total_len;
+	u32 flash_addr;
+	u32 flash_addr_ext;
+	u32 cs;
+	u32 pad2[5];
+	u32 status_valid;
+} __packed;
+
+/* Bitfields for brcm_nand_dma_desc::status_valid */
+#define FLASH_DMA_ECC_ERROR	(1 << 8)
+#define FLASH_DMA_CORR_ERROR	(1 << 9)
+
+/* 512B flash cache in the NAND controller HW */
+#define FC_SHIFT		9U
+#define FC_BYTES		512U
+#define FC_WORDS		(FC_BYTES >> 2)
+
+#define BRCMNAND_MIN_PAGESIZE	512
+#define BRCMNAND_MIN_BLOCKSIZE	(8 * 1024)
+#define BRCMNAND_MIN_DEVSIZE	(4ULL * 1024 * 1024)
+
+#define NAND_CTRL_RDY			(INTFC_CTLR_READY | INTFC_FLASH_READY)
+#define NAND_POLL_STATUS_TIMEOUT_MS	100
+
+/* Controller feature flags */
+enum {
+	BRCMNAND_HAS_1K_SECTORS			= BIT(0),
+	BRCMNAND_HAS_PREFETCH			= BIT(1),
+	BRCMNAND_HAS_CACHE_MODE			= BIT(2),
+	BRCMNAND_HAS_WP				= BIT(3),
+};
+
+struct brcmnand_controller {
+	struct device		*dev;
+	struct nand_hw_control	controller;
+	void __iomem		*nand_base;
+	void __iomem		*nand_fc; /* flash cache */
+	void __iomem		*flash_dma_base;
+	unsigned int		irq;
+	unsigned int		dma_irq;
+	int			nand_version;
+
+	/* Some SoCs provide custom interrupt status register(s) */
+	struct brcmnand_soc	*soc;
+
+	/* Some SoCs have a gateable clock for the controller */
+	struct clk		*clk;
+
+	int			cmd_pending;
+	bool			dma_pending;
+	struct completion	done;
+	struct completion	dma_done;
+
+	/* List of NAND hosts (one for each chip-select) */
+	struct list_head host_list;
+
+	struct brcm_nand_dma_desc *dma_desc;
+	dma_addr_t		dma_pa;
+
+	/* in-memory cache of the FLASH_CACHE, used only for some commands */
+	u8			flash_cache[FC_BYTES];
+
+	/* Controller revision details */
+	const u16		*reg_offsets;
+	unsigned int		reg_spacing; /* between CS1, CS2, ... regs */
+	const u8		*cs_offsets; /* within each chip-select */
+	const u8		*cs0_offsets; /* within CS0, if different */
+	unsigned int		max_block_size;
+	const unsigned int	*block_sizes;
+	unsigned int		max_page_size;
+	const unsigned int	*page_sizes;
+	unsigned int		max_oob;
+	u32			features;
+
+	/* for low-power standby/resume only */
+	u32			nand_cs_nand_select;
+	u32			nand_cs_nand_xor;
+	u32			corr_stat_threshold;
+	u32			flash_dma_mode;
+};
+
+struct brcmnand_cfg {
+	u64			device_size;
+	unsigned int		block_size;
+	unsigned int		page_size;
+	unsigned int		spare_area_size;
+	unsigned int		device_width;
+	unsigned int		col_adr_bytes;
+	unsigned int		blk_adr_bytes;
+	unsigned int		ful_adr_bytes;
+	unsigned int		sector_size_1k;
+	unsigned int		ecc_level;
+	/* use for low-power standby/resume only */
+	u32			acc_control;
+	u32			config;
+	u32			config_ext;
+	u32			timing_1;
+	u32			timing_2;
+};
+
+struct brcmnand_host {
+	struct list_head	node;
+
+	struct nand_chip	chip;
+	struct platform_device	*pdev;
+	int			cs;
+
+	unsigned int		last_cmd;
+	unsigned int		last_byte;
+	u64			last_addr;
+	struct brcmnand_cfg	hwcfg;
+	struct brcmnand_controller *ctrl;
+};
+
+enum brcmnand_reg {
+	BRCMNAND_CMD_START = 0,
+	BRCMNAND_CMD_EXT_ADDRESS,
+	BRCMNAND_CMD_ADDRESS,
+	BRCMNAND_INTFC_STATUS,
+	BRCMNAND_CS_SELECT,
+	BRCMNAND_CS_XOR,
+	BRCMNAND_LL_OP,
+	BRCMNAND_CS0_BASE,
+	BRCMNAND_CS1_BASE,		/* CS1 regs, if non-contiguous */
+	BRCMNAND_CORR_THRESHOLD,
+	BRCMNAND_CORR_THRESHOLD_EXT,
+	BRCMNAND_UNCORR_COUNT,
+	BRCMNAND_CORR_COUNT,
+	BRCMNAND_CORR_EXT_ADDR,
+	BRCMNAND_CORR_ADDR,
+	BRCMNAND_UNCORR_EXT_ADDR,
+	BRCMNAND_UNCORR_ADDR,
+	BRCMNAND_SEMAPHORE,
+	BRCMNAND_ID,
+	BRCMNAND_ID_EXT,
+	BRCMNAND_LL_RDATA,
+	BRCMNAND_OOB_READ_BASE,
+	BRCMNAND_OOB_READ_10_BASE,	/* offset 0x10, if non-contiguous */
+	BRCMNAND_OOB_WRITE_BASE,
+	BRCMNAND_OOB_WRITE_10_BASE,	/* offset 0x10, if non-contiguous */
+	BRCMNAND_FC_BASE,
+};
+
+/* BRCMNAND v4.0 */
+static const u16 brcmnand_regs_v40[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x6c,
+	[BRCMNAND_CS_SELECT]		=  0x14,
+	[BRCMNAND_CS_XOR]		=  0x18,
+	[BRCMNAND_LL_OP]		= 0x178,
+	[BRCMNAND_CS0_BASE]		=  0x40,
+	[BRCMNAND_CS1_BASE]		=  0xd0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
+	[BRCMNAND_UNCORR_COUNT]		=     0,
+	[BRCMNAND_CORR_COUNT]		=     0,
+	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
+	[BRCMNAND_CORR_ADDR]		=  0x74,
+	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
+	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
+	[BRCMNAND_SEMAPHORE]		=  0x58,
+	[BRCMNAND_ID]			=  0x60,
+	[BRCMNAND_ID_EXT]		=  0x64,
+	[BRCMNAND_LL_RDATA]		= 0x17c,
+	[BRCMNAND_OOB_READ_BASE]	=  0x20,
+	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
+	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+	[BRCMNAND_FC_BASE]		= 0x200,
+};
+
+/* BRCMNAND v5.0 */
+static const u16 brcmnand_regs_v50[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x6c,
+	[BRCMNAND_CS_SELECT]		=  0x14,
+	[BRCMNAND_CS_XOR]		=  0x18,
+	[BRCMNAND_LL_OP]		= 0x178,
+	[BRCMNAND_CS0_BASE]		=  0x40,
+	[BRCMNAND_CS1_BASE]		=  0xd0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0x84,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=     0,
+	[BRCMNAND_UNCORR_COUNT]		=     0,
+	[BRCMNAND_CORR_COUNT]		=     0,
+	[BRCMNAND_CORR_EXT_ADDR]	=  0x70,
+	[BRCMNAND_CORR_ADDR]		=  0x74,
+	[BRCMNAND_UNCORR_EXT_ADDR]	=  0x78,
+	[BRCMNAND_UNCORR_ADDR]		=  0x7c,
+	[BRCMNAND_SEMAPHORE]		=  0x58,
+	[BRCMNAND_ID]			=  0x60,
+	[BRCMNAND_ID_EXT]		=  0x64,
+	[BRCMNAND_LL_RDATA]		= 0x17c,
+	[BRCMNAND_OOB_READ_BASE]	=  0x20,
+	[BRCMNAND_OOB_READ_10_BASE]	= 0x130,
+	[BRCMNAND_OOB_WRITE_BASE]	=  0x30,
+	[BRCMNAND_OOB_WRITE_10_BASE]	= 0x140,
+	[BRCMNAND_FC_BASE]		= 0x200,
+};
+
+/* BRCMNAND v6.0 - v7.1 */
+static const u16 brcmnand_regs_v60[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x14,
+	[BRCMNAND_CS_SELECT]		=  0x18,
+	[BRCMNAND_CS_XOR]		=  0x1c,
+	[BRCMNAND_LL_OP]		=  0x20,
+	[BRCMNAND_CS0_BASE]		=  0x50,
+	[BRCMNAND_CS1_BASE]		=     0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0xc0,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xc4,
+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+	[BRCMNAND_CORR_COUNT]		= 0x100,
+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+	[BRCMNAND_CORR_ADDR]		= 0x110,
+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+	[BRCMNAND_SEMAPHORE]		= 0x150,
+	[BRCMNAND_ID]			= 0x194,
+	[BRCMNAND_ID_EXT]		= 0x198,
+	[BRCMNAND_LL_RDATA]		= 0x19c,
+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+	[BRCMNAND_FC_BASE]		= 0x400,
+};
+
+/* BRCMNAND v7.1 */
+static const u16 brcmnand_regs_v71[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x14,
+	[BRCMNAND_CS_SELECT]		=  0x18,
+	[BRCMNAND_CS_XOR]		=  0x1c,
+	[BRCMNAND_LL_OP]		=  0x20,
+	[BRCMNAND_CS0_BASE]		=  0x50,
+	[BRCMNAND_CS1_BASE]		=     0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+	[BRCMNAND_CORR_COUNT]		= 0x100,
+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+	[BRCMNAND_CORR_ADDR]		= 0x110,
+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+	[BRCMNAND_SEMAPHORE]		= 0x150,
+	[BRCMNAND_ID]			= 0x194,
+	[BRCMNAND_ID_EXT]		= 0x198,
+	[BRCMNAND_LL_RDATA]		= 0x19c,
+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+	[BRCMNAND_OOB_WRITE_BASE]	= 0x280,
+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+	[BRCMNAND_FC_BASE]		= 0x400,
+};
+
+/* BRCMNAND v7.2 */
+static const u16 brcmnand_regs_v72[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x14,
+	[BRCMNAND_CS_SELECT]		=  0x18,
+	[BRCMNAND_CS_XOR]		=  0x1c,
+	[BRCMNAND_LL_OP]		=  0x20,
+	[BRCMNAND_CS0_BASE]		=  0x50,
+	[BRCMNAND_CS1_BASE]		=     0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+	[BRCMNAND_CORR_COUNT]		= 0x100,
+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+	[BRCMNAND_CORR_ADDR]		= 0x110,
+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+	[BRCMNAND_SEMAPHORE]		= 0x150,
+	[BRCMNAND_ID]			= 0x194,
+	[BRCMNAND_ID_EXT]		= 0x198,
+	[BRCMNAND_LL_RDATA]		= 0x19c,
+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+	[BRCMNAND_FC_BASE]		= 0x600,
+};
+
+enum brcmnand_cs_reg {
+	BRCMNAND_CS_CFG_EXT = 0,
+	BRCMNAND_CS_CFG,
+	BRCMNAND_CS_ACC_CONTROL,
+	BRCMNAND_CS_TIMING1,
+	BRCMNAND_CS_TIMING2,
+};
+
+/* Per chip-select offsets for v7.1 */
+static const u8 brcmnand_cs_offsets_v71[] = {
+	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
+	[BRCMNAND_CS_CFG_EXT]		= 0x04,
+	[BRCMNAND_CS_CFG]		= 0x08,
+	[BRCMNAND_CS_TIMING1]		= 0x0c,
+	[BRCMNAND_CS_TIMING2]		= 0x10,
+};
+
+/* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
+static const u8 brcmnand_cs_offsets[] = {
+	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
+	[BRCMNAND_CS_CFG_EXT]		= 0x04,
+	[BRCMNAND_CS_CFG]		= 0x04,
+	[BRCMNAND_CS_TIMING1]		= 0x08,
+	[BRCMNAND_CS_TIMING2]		= 0x0c,
+};
+
+/* Per chip-select offset for <= v5.0 on CS0 only */
+static const u8 brcmnand_cs_offsets_cs0[] = {
+	[BRCMNAND_CS_ACC_CONTROL]	= 0x00,
+	[BRCMNAND_CS_CFG_EXT]		= 0x08,
+	[BRCMNAND_CS_CFG]		= 0x08,
+	[BRCMNAND_CS_TIMING1]		= 0x10,
+	[BRCMNAND_CS_TIMING2]		= 0x14,
+};
+
+/*
+ * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
+ * one config register, but once the bitfields overflowed, newer controllers
+ * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
+ */
+enum {
+	CFG_BLK_ADR_BYTES_SHIFT		= 8,
+	CFG_COL_ADR_BYTES_SHIFT		= 12,
+	CFG_FUL_ADR_BYTES_SHIFT		= 16,
+	CFG_BUS_WIDTH_SHIFT		= 23,
+	CFG_BUS_WIDTH			= BIT(CFG_BUS_WIDTH_SHIFT),
+	CFG_DEVICE_SIZE_SHIFT		= 24,
+
+	/* Only for pre-v7.1 (with no CFG_EXT register) */
+	CFG_PAGE_SIZE_SHIFT		= 20,
+	CFG_BLK_SIZE_SHIFT		= 28,
+
+	/* Only for v7.1+ (with CFG_EXT register) */
+	CFG_EXT_PAGE_SIZE_SHIFT		= 0,
+	CFG_EXT_BLK_SIZE_SHIFT		= 4,
+};
+
+/* BRCMNAND_INTFC_STATUS */
+enum {
+	INTFC_FLASH_STATUS		= GENMASK(7, 0),
+
+	INTFC_ERASED			= BIT(27),
+	INTFC_OOB_VALID			= BIT(28),
+	INTFC_CACHE_VALID		= BIT(29),
+	INTFC_FLASH_READY		= BIT(30),
+	INTFC_CTLR_READY		= BIT(31),
+};
+
+static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
+{
+	return brcmnand_readl(ctrl->nand_base + offs);
+}
+
+static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
+				 u32 val)
+{
+	brcmnand_writel(val, ctrl->nand_base + offs);
+}
+
+static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
+{
+	static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
+	static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
+	static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
+
+	ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
+
+	/* Only support v4.0+? */
+	if (ctrl->nand_version < 0x0400) {
+		dev_err(ctrl->dev, "version %#x not supported\n",
+			ctrl->nand_version);
+		return -ENODEV;
+	}
+
+	/* Register offsets */
+	if (ctrl->nand_version >= 0x0702)
+		ctrl->reg_offsets = brcmnand_regs_v72;
+	else if (ctrl->nand_version >= 0x0701)
+		ctrl->reg_offsets = brcmnand_regs_v71;
+	else if (ctrl->nand_version >= 0x0600)
+		ctrl->reg_offsets = brcmnand_regs_v60;
+	else if (ctrl->nand_version >= 0x0500)
+		ctrl->reg_offsets = brcmnand_regs_v50;
+	else if (ctrl->nand_version >= 0x0400)
+		ctrl->reg_offsets = brcmnand_regs_v40;
+
+	/* Chip-select stride */
+	if (ctrl->nand_version >= 0x0701)
+		ctrl->reg_spacing = 0x14;
+	else
+		ctrl->reg_spacing = 0x10;
+
+	/* Per chip-select registers */
+	if (ctrl->nand_version >= 0x0701) {
+		ctrl->cs_offsets = brcmnand_cs_offsets_v71;
+	} else {
+		ctrl->cs_offsets = brcmnand_cs_offsets;
+
+		/* v5.0 and earlier has a different CS0 offset layout */
+		if (ctrl->nand_version <= 0x0500)
+			ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
+	}
+
+	/* Page / block sizes */
+	if (ctrl->nand_version >= 0x0701) {
+		/* >= v7.1 use nice power-of-2 values! */
+		ctrl->max_page_size = 16 * 1024;
+		ctrl->max_block_size = 2 * 1024 * 1024;
+	} else {
+		ctrl->page_sizes = page_sizes;
+		if (ctrl->nand_version >= 0x0600)
+			ctrl->block_sizes = block_sizes_v6;
+		else
+			ctrl->block_sizes = block_sizes_v4;
+
+		if (ctrl->nand_version < 0x0400) {
+			ctrl->max_page_size = 4096;
+			ctrl->max_block_size = 512 * 1024;
+		}
+	}
+
+	/* Maximum spare area sector size (per 512B) */
+	if (ctrl->nand_version >= 0x0702)
+		ctrl->max_oob = 128;
+	else if (ctrl->nand_version >= 0x0600)
+		ctrl->max_oob = 64;
+	else if (ctrl->nand_version >= 0x0500)
+		ctrl->max_oob = 32;
+	else
+		ctrl->max_oob = 16;
+
+	/* v6.0 and newer (except v6.1) have prefetch support */
+	if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
+		ctrl->features |= BRCMNAND_HAS_PREFETCH;
+
+	/*
+	 * v6.x has cache mode, but it's implemented differently. Ignore it for
+	 * now.
+	 */
+	if (ctrl->nand_version >= 0x0700)
+		ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
+
+	if (ctrl->nand_version >= 0x0500)
+		ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
+
+	if (ctrl->nand_version >= 0x0700)
+		ctrl->features |= BRCMNAND_HAS_WP;
+	else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
+		ctrl->features |= BRCMNAND_HAS_WP;
+
+	return 0;
+}
+
+static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
+		enum brcmnand_reg reg)
+{
+	u16 offs = ctrl->reg_offsets[reg];
+
+	if (offs)
+		return nand_readreg(ctrl, offs);
+	else
+		return 0;
+}
+
+static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
+				      enum brcmnand_reg reg, u32 val)
+{
+	u16 offs = ctrl->reg_offsets[reg];
+
+	if (offs)
+		nand_writereg(ctrl, offs, val);
+}
+
+static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
+				    enum brcmnand_reg reg, u32 mask, unsigned
+				    int shift, u32 val)
+{
+	u32 tmp = brcmnand_read_reg(ctrl, reg);
+
+	tmp &= ~mask;
+	tmp |= val << shift;
+	brcmnand_write_reg(ctrl, reg, tmp);
+}
+
+static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
+{
+	return __raw_readl(ctrl->nand_fc + word * 4);
+}
+
+static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
+				     int word, u32 val)
+{
+	__raw_writel(val, ctrl->nand_fc + word * 4);
+}
+
+static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
+				     enum brcmnand_cs_reg reg)
+{
+	u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
+	u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
+	u8 cs_offs;
+
+	if (cs == 0 && ctrl->cs0_offsets)
+		cs_offs = ctrl->cs0_offsets[reg];
+	else
+		cs_offs = ctrl->cs_offsets[reg];
+
+	if (cs && offs_cs1)
+		return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
+
+	return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
+}
+
+static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
+{
+	if (ctrl->nand_version < 0x0600)
+		return 1;
+	return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
+}
+
+static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	unsigned int shift = 0, bits;
+	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
+	int cs = host->cs;
+
+	if (ctrl->nand_version >= 0x0702)
+		bits = 7;
+	else if (ctrl->nand_version >= 0x0600)
+		bits = 6;
+	else if (ctrl->nand_version >= 0x0500)
+		bits = 5;
+	else
+		bits = 4;
+
+	if (ctrl->nand_version >= 0x0702) {
+		if (cs >= 4)
+			reg = BRCMNAND_CORR_THRESHOLD_EXT;
+		shift = (cs % 4) * bits;
+	} else if (ctrl->nand_version >= 0x0600) {
+		if (cs >= 5)
+			reg = BRCMNAND_CORR_THRESHOLD_EXT;
+		shift = (cs % 5) * bits;
+	}
+	brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
+}
+
+static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
+{
+	if (ctrl->nand_version < 0x0602)
+		return 24;
+	return 0;
+}
+
+/***********************************************************************
+ * NAND ACC CONTROL bitfield
+ *
+ * Some bits have remained constant throughout hardware revision, while
+ * others have shifted around.
+ ***********************************************************************/
+
+/* Constant for all versions (where supported) */
+enum {
+	/* See BRCMNAND_HAS_CACHE_MODE */
+	ACC_CONTROL_CACHE_MODE				= BIT(22),
+
+	/* See BRCMNAND_HAS_PREFETCH */
+	ACC_CONTROL_PREFETCH				= BIT(23),
+
+	ACC_CONTROL_PAGE_HIT				= BIT(24),
+	ACC_CONTROL_WR_PREEMPT				= BIT(25),
+	ACC_CONTROL_PARTIAL_PAGE			= BIT(26),
+	ACC_CONTROL_RD_ERASED				= BIT(27),
+	ACC_CONTROL_FAST_PGM_RDIN			= BIT(28),
+	ACC_CONTROL_WR_ECC				= BIT(30),
+	ACC_CONTROL_RD_ECC				= BIT(31),
+};
+
+static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
+{
+	if (ctrl->nand_version >= 0x0702)
+		return GENMASK(7, 0);
+	else if (ctrl->nand_version >= 0x0600)
+		return GENMASK(6, 0);
+	else
+		return GENMASK(5, 0);
+}
+
+#define NAND_ACC_CONTROL_ECC_SHIFT	16
+#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
+
+static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
+{
+	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
+
+	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
+
+	/* v7.2 includes additional ECC levels */
+	if (ctrl->nand_version >= 0x0702)
+		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
+
+	return mask;
+}
+
+static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
+	u32 acc_control = nand_readreg(ctrl, offs);
+	u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
+
+	if (en) {
+		acc_control |= ecc_flags; /* enable RD/WR ECC */
+		acc_control |= host->hwcfg.ecc_level
+			       << NAND_ACC_CONTROL_ECC_SHIFT;
+	} else {
+		acc_control &= ~ecc_flags; /* disable RD/WR ECC */
+		acc_control &= ~brcmnand_ecc_level_mask(ctrl);
+	}
+
+	nand_writereg(ctrl, offs, acc_control);
+}
+
+static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
+{
+	if (ctrl->nand_version >= 0x0702)
+		return 9;
+	else if (ctrl->nand_version >= 0x0600)
+		return 7;
+	else if (ctrl->nand_version >= 0x0500)
+		return 6;
+	else
+		return -1;
+}
+
+static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	int shift = brcmnand_sector_1k_shift(ctrl);
+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+						  BRCMNAND_CS_ACC_CONTROL);
+
+	if (shift < 0)
+		return 0;
+
+	return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
+}
+
+static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	int shift = brcmnand_sector_1k_shift(ctrl);
+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+						  BRCMNAND_CS_ACC_CONTROL);
+	u32 tmp;
+
+	if (shift < 0)
+		return;
+
+	tmp = nand_readreg(ctrl, acc_control_offs);
+	tmp &= ~(1 << shift);
+	tmp |= (!!val) << shift;
+	nand_writereg(ctrl, acc_control_offs, tmp);
+}
+
+/***********************************************************************
+ * CS_NAND_SELECT
+ ***********************************************************************/
+
+enum {
+	CS_SELECT_NAND_WP			= BIT(29),
+	CS_SELECT_AUTO_DEVICE_ID_CFG		= BIT(30),
+};
+
+static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
+				    u32 mask, u32 expected_val,
+				    unsigned long timeout_ms)
+{
+	unsigned long limit;
+	u32 val;
+
+	if (!timeout_ms)
+		timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
+
+	limit = jiffies + msecs_to_jiffies(timeout_ms);
+	do {
+		val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
+		if ((val & mask) == expected_val)
+			return 0;
+
+		cpu_relax();
+	} while (time_after(limit, jiffies));
+
+	dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
+		 expected_val, val & mask);
+
+	return -ETIMEDOUT;
+}
+
+static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
+{
+	u32 val = en ? CS_SELECT_NAND_WP : 0;
+
+	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
+}
+
+/***********************************************************************
+ * Flash DMA
+ ***********************************************************************/
+
+enum flash_dma_reg {
+	FLASH_DMA_REVISION		= 0x00,
+	FLASH_DMA_FIRST_DESC		= 0x04,
+	FLASH_DMA_FIRST_DESC_EXT	= 0x08,
+	FLASH_DMA_CTRL			= 0x0c,
+	FLASH_DMA_MODE			= 0x10,
+	FLASH_DMA_STATUS		= 0x14,
+	FLASH_DMA_INTERRUPT_DESC	= 0x18,
+	FLASH_DMA_INTERRUPT_DESC_EXT	= 0x1c,
+	FLASH_DMA_ERROR_STATUS		= 0x20,
+	FLASH_DMA_CURRENT_DESC		= 0x24,
+	FLASH_DMA_CURRENT_DESC_EXT	= 0x28,
+};
+
+static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
+{
+	return ctrl->flash_dma_base;
+}
+
+static inline bool flash_dma_buf_ok(const void *buf)
+{
+	return buf && !is_vmalloc_addr(buf) &&
+		likely(IS_ALIGNED((uintptr_t)buf, 4));
+}
+
+static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
+				    u32 val)
+{
+	brcmnand_writel(val, ctrl->flash_dma_base + offs);
+}
+
+static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
+{
+	return brcmnand_readl(ctrl->flash_dma_base + offs);
+}
+
+/* Low-level operation types: command, address, write, or read */
+enum brcmnand_llop_type {
+	LL_OP_CMD,
+	LL_OP_ADDR,
+	LL_OP_WR,
+	LL_OP_RD,
+};
+
+/***********************************************************************
+ * Internal support functions
+ ***********************************************************************/
+
+static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
+				  struct brcmnand_cfg *cfg)
+{
+	if (ctrl->nand_version <= 0x0701)
+		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
+			cfg->ecc_level == 15;
+	else
+		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
+			cfg->ecc_level == 15) ||
+			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
+}
+
+/*
+ * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
+ * the layout/configuration.
+ * Returns -ERRCODE on failure.
+ */
+static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors)
+		return -ERANGE;
+
+	oobregion->offset = (section * sas) + 6;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int brcmnand_hamming_ooblayout_free(struct mtd_info *mtd, int section,
+					   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors * 2)
+		return -ERANGE;
+
+	oobregion->offset = (section / 2) * sas;
+
+	if (section & 1) {
+		oobregion->offset += 9;
+		oobregion->length = 7;
+	} else {
+		oobregion->length = 6;
+
+		/* First sector of each page may have BBI */
+		if (!section) {
+			/*
+			 * Small-page NAND use byte 6 for BBI while large-page
+			 * NAND use byte 0.
+			 */
+			if (cfg->page_size > 512)
+				oobregion->offset++;
+			oobregion->length--;
+		}
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
+	.ecc = brcmnand_hamming_ooblayout_ecc,
+	.free = brcmnand_hamming_ooblayout_free,
+};
+
+static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors)
+		return -ERANGE;
+
+	oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+	int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
+
+	if (section >= sectors)
+		return -ERANGE;
+
+	if (sas <= chip->ecc.bytes)
+		return 0;
+
+	oobregion->offset = section * sas;
+	oobregion->length = sas - chip->ecc.bytes;
+
+	if (!section) {
+		oobregion->offset++;
+		oobregion->length--;
+	}
+
+	return 0;
+}
+
+static int brcmnand_bch_ooblayout_free_sp(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	int sas = cfg->spare_area_size << cfg->sector_size_1k;
+
+	if (section > 1 || sas - chip->ecc.bytes < 6 ||
+	    (section && sas - chip->ecc.bytes == 6))
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 5;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = sas - chip->ecc.bytes - 6;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
+	.ecc = brcmnand_bch_ooblayout_ecc,
+	.free = brcmnand_bch_ooblayout_free_lp,
+};
+
+static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
+	.ecc = brcmnand_bch_ooblayout_ecc,
+	.free = brcmnand_bch_ooblayout_free_sp,
+};
+
+static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
+{
+	struct brcmnand_cfg *p = &host->hwcfg;
+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct nand_ecc_ctrl *ecc = &host->chip.ecc;
+	unsigned int ecc_level = p->ecc_level;
+	int sas = p->spare_area_size << p->sector_size_1k;
+	int sectors = p->page_size / (512 << p->sector_size_1k);
+
+	if (p->sector_size_1k)
+		ecc_level <<= 1;
+
+	if (is_hamming_ecc(host->ctrl, p)) {
+		ecc->bytes = 3 * sectors;
+		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
+		return 0;
+	}
+
+	/*
+	 * CONTROLLER_VERSION:
+	 *   < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
+	 *  >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
+	 * But we will just be conservative.
+	 */
+	ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
+	if (p->page_size == 512)
+		mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
+	else
+		mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
+
+	if (ecc->bytes >= sas) {
+		dev_err(&host->pdev->dev,
+			"error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
+			ecc->bytes, sas);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void brcmnand_wp(struct mtd_info *mtd, int wp)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+
+	if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
+		static int old_wp = -1;
+		int ret;
+
+		if (old_wp != wp) {
+			dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
+			old_wp = wp;
+		}
+
+		/*
+		 * make sure ctrl/flash ready before and after
+		 * changing state of #WP pin
+		 */
+		ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
+					       NAND_STATUS_READY,
+					       NAND_CTRL_RDY |
+					       NAND_STATUS_READY, 0);
+		if (ret)
+			return;
+
+		brcmnand_set_wp(ctrl, wp);
+		nand_status_op(chip, NULL);
+		/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
+		ret = bcmnand_ctrl_poll_status(ctrl,
+					       NAND_CTRL_RDY |
+					       NAND_STATUS_READY |
+					       NAND_STATUS_WP,
+					       NAND_CTRL_RDY |
+					       NAND_STATUS_READY |
+					       (wp ? 0 : NAND_STATUS_WP), 0);
+
+		if (ret)
+			dev_err_ratelimited(&host->pdev->dev,
+					    "nand #WP expected %s\n",
+					    wp ? "on" : "off");
+	}
+}
+
+/* Helper functions for reading and writing OOB registers */
+static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
+{
+	u16 offset0, offset10, reg_offs;
+
+	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
+	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
+
+	if (offs >= ctrl->max_oob)
+		return 0x77;
+
+	if (offs >= 16 && offset10)
+		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
+	else
+		reg_offs = offset0 + (offs & ~0x03);
+
+	return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
+}
+
+static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
+				 u32 data)
+{
+	u16 offset0, offset10, reg_offs;
+
+	offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
+	offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
+
+	if (offs >= ctrl->max_oob)
+		return;
+
+	if (offs >= 16 && offset10)
+		reg_offs = offset10 + ((offs - 0x10) & ~0x03);
+	else
+		reg_offs = offset0 + (offs & ~0x03);
+
+	nand_writereg(ctrl, reg_offs, data);
+}
+
+/*
+ * read_oob_from_regs - read data from OOB registers
+ * @ctrl: NAND controller
+ * @i: sub-page sector index
+ * @oob: buffer to read to
+ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
+ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
+ */
+static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
+			      int sas, int sector_1k)
+{
+	int tbytes = sas << sector_1k;
+	int j;
+
+	/* Adjust OOB values for 1K sector size */
+	if (sector_1k && (i & 0x01))
+		tbytes = max(0, tbytes - (int)ctrl->max_oob);
+	tbytes = min_t(int, tbytes, ctrl->max_oob);
+
+	for (j = 0; j < tbytes; j++)
+		oob[j] = oob_reg_read(ctrl, j);
+	return tbytes;
+}
+
+/*
+ * write_oob_to_regs - write data to OOB registers
+ * @i: sub-page sector index
+ * @oob: buffer to write from
+ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
+ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
+ */
+static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
+			     const u8 *oob, int sas, int sector_1k)
+{
+	int tbytes = sas << sector_1k;
+	int j;
+
+	/* Adjust OOB values for 1K sector size */
+	if (sector_1k && (i & 0x01))
+		tbytes = max(0, tbytes - (int)ctrl->max_oob);
+	tbytes = min_t(int, tbytes, ctrl->max_oob);
+
+	for (j = 0; j < tbytes; j += 4)
+		oob_reg_write(ctrl, j,
+				(oob[j + 0] << 24) |
+				(oob[j + 1] << 16) |
+				(oob[j + 2] <<  8) |
+				(oob[j + 3] <<  0));
+	return tbytes;
+}
+
+static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
+{
+	struct brcmnand_controller *ctrl = data;
+
+	/* Discard all NAND_CTLRDY interrupts during DMA */
+	if (ctrl->dma_pending)
+		return IRQ_HANDLED;
+
+	complete(&ctrl->done);
+	return IRQ_HANDLED;
+}
+
+/* Handle SoC-specific interrupt hardware */
+static irqreturn_t brcmnand_irq(int irq, void *data)
+{
+	struct brcmnand_controller *ctrl = data;
+
+	if (ctrl->soc->ctlrdy_ack(ctrl->soc))
+		return brcmnand_ctlrdy_irq(irq, data);
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t brcmnand_dma_irq(int irq, void *data)
+{
+	struct brcmnand_controller *ctrl = data;
+
+	complete(&ctrl->dma_done);
+
+	return IRQ_HANDLED;
+}
+
+static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	int ret;
+
+	dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
+		brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
+	BUG_ON(ctrl->cmd_pending != 0);
+	ctrl->cmd_pending = cmd;
+
+	ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
+	WARN_ON(ret);
+
+	mb(); /* flush previous writes */
+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
+			   cmd << brcmnand_cmd_shift(ctrl));
+}
+
+/***********************************************************************
+ * NAND MTD API: read/program/erase
+ ***********************************************************************/
+
+static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
+	unsigned int ctrl)
+{
+	/* intentionally left blank */
+}
+
+static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+	unsigned long timeo = msecs_to_jiffies(100);
+
+	dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
+	if (ctrl->cmd_pending &&
+			wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
+		u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
+					>> brcmnand_cmd_shift(ctrl);
+
+		dev_err_ratelimited(ctrl->dev,
+			"timeout waiting for command %#02x\n", cmd);
+		dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
+			brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
+	}
+	ctrl->cmd_pending = 0;
+	return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
+				 INTFC_FLASH_STATUS;
+}
+
+enum {
+	LLOP_RE				= BIT(16),
+	LLOP_WE				= BIT(17),
+	LLOP_ALE			= BIT(18),
+	LLOP_CLE			= BIT(19),
+	LLOP_RETURN_IDLE		= BIT(31),
+
+	LLOP_DATA_MASK			= GENMASK(15, 0),
+};
+
+static int brcmnand_low_level_op(struct brcmnand_host *host,
+				 enum brcmnand_llop_type type, u32 data,
+				 bool last_op)
+{
+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct nand_chip *chip = &host->chip;
+	struct brcmnand_controller *ctrl = host->ctrl;
+	u32 tmp;
+
+	tmp = data & LLOP_DATA_MASK;
+	switch (type) {
+	case LL_OP_CMD:
+		tmp |= LLOP_WE | LLOP_CLE;
+		break;
+	case LL_OP_ADDR:
+		/* WE | ALE */
+		tmp |= LLOP_WE | LLOP_ALE;
+		break;
+	case LL_OP_WR:
+		/* WE */
+		tmp |= LLOP_WE;
+		break;
+	case LL_OP_RD:
+		/* RE */
+		tmp |= LLOP_RE;
+		break;
+	}
+	if (last_op)
+		/* RETURN_IDLE */
+		tmp |= LLOP_RETURN_IDLE;
+
+	dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
+
+	brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
+	(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
+
+	brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
+	return brcmnand_waitfunc(mtd, chip);
+}
+
+static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
+			     int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+	u64 addr = (u64)page_addr << chip->page_shift;
+	int native_cmd = 0;
+
+	if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
+			command == NAND_CMD_RNDOUT)
+		addr = (u64)column;
+	/* Avoid propagating a negative, don't-care address */
+	else if (page_addr < 0)
+		addr = 0;
+
+	dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
+		(unsigned long long)addr);
+
+	host->last_cmd = command;
+	host->last_byte = 0;
+	host->last_addr = addr;
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		native_cmd = CMD_FLASH_RESET;
+		break;
+	case NAND_CMD_STATUS:
+		native_cmd = CMD_STATUS_READ;
+		break;
+	case NAND_CMD_READID:
+		native_cmd = CMD_DEVICE_ID_READ;
+		break;
+	case NAND_CMD_READOOB:
+		native_cmd = CMD_SPARE_AREA_READ;
+		break;
+	case NAND_CMD_ERASE1:
+		native_cmd = CMD_BLOCK_ERASE;
+		brcmnand_wp(mtd, 0);
+		break;
+	case NAND_CMD_PARAM:
+		native_cmd = CMD_PARAMETER_READ;
+		break;
+	case NAND_CMD_SET_FEATURES:
+	case NAND_CMD_GET_FEATURES:
+		brcmnand_low_level_op(host, LL_OP_CMD, command, false);
+		brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
+		break;
+	case NAND_CMD_RNDOUT:
+		native_cmd = CMD_PARAMETER_CHANGE_COL;
+		addr &= ~((u64)(FC_BYTES - 1));
+		/*
+		 * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
+		 * NB: hwcfg.sector_size_1k may not be initialized yet
+		 */
+		if (brcmnand_get_sector_size_1k(host)) {
+			host->hwcfg.sector_size_1k =
+				brcmnand_get_sector_size_1k(host);
+			brcmnand_set_sector_size_1k(host, 0);
+		}
+		break;
+	}
+
+	if (!native_cmd)
+		return;
+
+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+		(host->cs << 16) | ((addr >> 32) & 0xffff));
+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+
+	brcmnand_send_cmd(host, native_cmd);
+	brcmnand_waitfunc(mtd, chip);
+
+	if (native_cmd == CMD_PARAMETER_READ ||
+			native_cmd == CMD_PARAMETER_CHANGE_COL) {
+		/* Copy flash cache word-wise */
+		u32 *flash_cache = (u32 *)ctrl->flash_cache;
+		int i;
+
+		brcmnand_soc_data_bus_prepare(ctrl->soc, true);
+
+		/*
+		 * Must cache the FLASH_CACHE now, since changes in
+		 * SECTOR_SIZE_1K may invalidate it
+		 */
+		for (i = 0; i < FC_WORDS; i++)
+			/*
+			 * Flash cache is big endian for parameter pages, at
+			 * least on STB SoCs
+			 */
+			flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
+
+		brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
+
+		/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
+		if (host->hwcfg.sector_size_1k)
+			brcmnand_set_sector_size_1k(host,
+						    host->hwcfg.sector_size_1k);
+	}
+
+	/* Re-enable protection is necessary only after erase */
+	if (command == NAND_CMD_ERASE1)
+		brcmnand_wp(mtd, 1);
+}
+
+static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+	uint8_t ret = 0;
+	int addr, offs;
+
+	switch (host->last_cmd) {
+	case NAND_CMD_READID:
+		if (host->last_byte < 4)
+			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
+				(24 - (host->last_byte << 3));
+		else if (host->last_byte < 8)
+			ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
+				(56 - (host->last_byte << 3));
+		break;
+
+	case NAND_CMD_READOOB:
+		ret = oob_reg_read(ctrl, host->last_byte);
+		break;
+
+	case NAND_CMD_STATUS:
+		ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
+					INTFC_FLASH_STATUS;
+		if (wp_on) /* hide WP status */
+			ret |= NAND_STATUS_WP;
+		break;
+
+	case NAND_CMD_PARAM:
+	case NAND_CMD_RNDOUT:
+		addr = host->last_addr + host->last_byte;
+		offs = addr & (FC_BYTES - 1);
+
+		/* At FC_BYTES boundary, switch to next column */
+		if (host->last_byte > 0 && offs == 0)
+			nand_change_read_column_op(chip, addr, NULL, 0, false);
+
+		ret = ctrl->flash_cache[offs];
+		break;
+	case NAND_CMD_GET_FEATURES:
+		if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
+			ret = 0;
+		} else {
+			bool last = host->last_byte ==
+				ONFI_SUBFEATURE_PARAM_LEN - 1;
+			brcmnand_low_level_op(host, LL_OP_RD, 0, last);
+			ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
+		}
+	}
+
+	dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
+	host->last_byte++;
+
+	return ret;
+}
+
+static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++, buf++)
+		*buf = brcmnand_read_byte(mtd);
+}
+
+static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				   int len)
+{
+	int i;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+
+	switch (host->last_cmd) {
+	case NAND_CMD_SET_FEATURES:
+		for (i = 0; i < len; i++)
+			brcmnand_low_level_op(host, LL_OP_WR, buf[i],
+						  (i + 1) == len);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+/**
+ * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
+ * following ahead of time:
+ *  - Is this descriptor the beginning or end of a linked list?
+ *  - What is the (DMA) address of the next descriptor in the linked list?
+ */
+static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
+				  struct brcm_nand_dma_desc *desc, u64 addr,
+				  dma_addr_t buf, u32 len, u8 dma_cmd,
+				  bool begin, bool end,
+				  dma_addr_t next_desc)
+{
+	memset(desc, 0, sizeof(*desc));
+	/* Descriptors are written in native byte order (wordwise) */
+	desc->next_desc = lower_32_bits(next_desc);
+	desc->next_desc_ext = upper_32_bits(next_desc);
+	desc->cmd_irq = (dma_cmd << 24) |
+		(end ? (0x03 << 8) : 0) | /* IRQ | STOP */
+		(!!begin) | ((!!end) << 1); /* head, tail */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	desc->cmd_irq |= 0x01 << 12;
+#endif
+	desc->dram_addr = lower_32_bits(buf);
+	desc->dram_addr_ext = upper_32_bits(buf);
+	desc->tfr_len = len;
+	desc->total_len = len;
+	desc->flash_addr = lower_32_bits(addr);
+	desc->flash_addr_ext = upper_32_bits(addr);
+	desc->cs = host->cs;
+	desc->status_valid = 0x01;
+	return 0;
+}
+
+/**
+ * Kick the FLASH_DMA engine, with a given DMA descriptor
+ */
+static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	unsigned long timeo = msecs_to_jiffies(100);
+
+	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
+	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
+	flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
+	(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
+
+	/* Start FLASH_DMA engine */
+	ctrl->dma_pending = true;
+	mb(); /* flush previous writes */
+	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
+
+	if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
+		dev_err(ctrl->dev,
+				"timeout waiting for DMA; status %#x, error status %#x\n",
+				flash_dma_readl(ctrl, FLASH_DMA_STATUS),
+				flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
+	}
+	ctrl->dma_pending = false;
+	flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
+}
+
+static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
+			      u32 len, u8 dma_cmd)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	dma_addr_t buf_pa;
+	int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
+	if (dma_mapping_error(ctrl->dev, buf_pa)) {
+		dev_err(ctrl->dev, "unable to map buffer for DMA\n");
+		return -ENOMEM;
+	}
+
+	brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
+				   dma_cmd, true, true, 0);
+
+	brcmnand_dma_run(host, ctrl->dma_pa);
+
+	dma_unmap_single(ctrl->dev, buf_pa, len, dir);
+
+	if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
+		return -EBADMSG;
+	else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
+		return -EUCLEAN;
+
+	return 0;
+}
+
+/*
+ * Assumes proper CS is already set
+ */
+static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
+				u64 addr, unsigned int trans, u32 *buf,
+				u8 *oob, u64 *err_addr)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+	int i, j, ret = 0;
+
+	/* Clear error addresses */
+	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
+	brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
+	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0);
+	brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0);
+
+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+			(host->cs << 16) | ((addr >> 32) & 0xffff));
+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+
+	for (i = 0; i < trans; i++, addr += FC_BYTES) {
+		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+				   lower_32_bits(addr));
+		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
+		brcmnand_send_cmd(host, CMD_PAGE_READ);
+		brcmnand_waitfunc(mtd, chip);
+
+		if (likely(buf)) {
+			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
+
+			for (j = 0; j < FC_WORDS; j++, buf++)
+				*buf = brcmnand_read_fc(ctrl, j);
+
+			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
+		}
+
+		if (oob)
+			oob += read_oob_from_regs(ctrl, i, oob,
+					mtd->oobsize / trans,
+					host->hwcfg.sector_size_1k);
+
+		if (!ret) {
+			*err_addr = brcmnand_read_reg(ctrl,
+					BRCMNAND_UNCORR_ADDR) |
+				((u64)(brcmnand_read_reg(ctrl,
+						BRCMNAND_UNCORR_EXT_ADDR)
+					& 0xffff) << 32);
+			if (*err_addr)
+				ret = -EBADMSG;
+		}
+
+		if (!ret) {
+			*err_addr = brcmnand_read_reg(ctrl,
+					BRCMNAND_CORR_ADDR) |
+				((u64)(brcmnand_read_reg(ctrl,
+						BRCMNAND_CORR_EXT_ADDR)
+					& 0xffff) << 32);
+			if (*err_addr)
+				ret = -EUCLEAN;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
+ * error
+ *
+ * Because the HW ECC signals an ECC error if an erase paged has even a single
+ * bitflip, we must check each ECC error to see if it is actually an erased
+ * page with bitflips, not a truly corrupted page.
+ *
+ * On a real error, return a negative error code (-EBADMSG for ECC error), and
+ * buf will contain raw data.
+ * Otherwise, buf gets filled with 0xffs and return the maximum number of
+ * bitflips-per-ECC-sector to the caller.
+ *
+ */
+static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
+		  struct nand_chip *chip, void *buf, u64 addr)
+{
+	int i, sas;
+	void *oob = chip->oob_poi;
+	int bitflips = 0;
+	int page = addr >> chip->page_shift;
+	int ret;
+
+	if (!buf) {
+		buf = chip->data_buf;
+		/* Invalidate page cache */
+		chip->pagebuf = -1;
+	}
+
+	sas = mtd->oobsize / chip->ecc.steps;
+
+	/* read without ecc for verification */
+	ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
+		ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
+						  oob, sas, NULL, 0,
+						  chip->ecc.strength);
+		if (ret < 0)
+			return ret;
+
+		bitflips = max(bitflips, ret);
+	}
+
+	return bitflips;
+}
+
+static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
+			 u64 addr, unsigned int trans, u32 *buf, u8 *oob)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+	u64 err_addr = 0;
+	int err;
+	bool retry = true;
+
+	dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
+
+try_dmaread:
+	brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
+
+	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
+		err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
+					     CMD_PAGE_READ);
+		if (err) {
+			if (mtd_is_bitflip_or_eccerr(err))
+				err_addr = addr;
+			else
+				return -EIO;
+		}
+	} else {
+		if (oob)
+			memset(oob, 0x99, mtd->oobsize);
+
+		err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
+					       oob, &err_addr);
+	}
+
+	if (mtd_is_eccerr(err)) {
+		/*
+		 * On controller version and 7.0, 7.1 , DMA read after a
+		 * prior PIO read that reported uncorrectable error,
+		 * the DMA engine captures this error following DMA read
+		 * cleared only on subsequent DMA read, so just retry once
+		 * to clear a possible false error reported for current DMA
+		 * read
+		 */
+		if ((ctrl->nand_version == 0x0700) ||
+		    (ctrl->nand_version == 0x0701)) {
+			if (retry) {
+				retry = false;
+				goto try_dmaread;
+			}
+		}
+
+		/*
+		 * Controller version 7.2 has hw encoder to detect erased page
+		 * bitflips, apply sw verification for older controllers only
+		 */
+		if (ctrl->nand_version < 0x0702) {
+			err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
+							      addr);
+			/* erased page bitflips corrected */
+			if (err >= 0)
+				return err;
+		}
+
+		dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
+			(unsigned long long)err_addr);
+		mtd->ecc_stats.failed++;
+		/* NAND layer expects zero on ECC errors */
+		return 0;
+	}
+
+	if (mtd_is_bitflip(err)) {
+		unsigned int corrected = brcmnand_count_corrected(ctrl);
+
+		dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
+			(unsigned long long)err_addr);
+		mtd->ecc_stats.corrected += corrected;
+		/* Always exceed the software-imposed threshold */
+		return max(mtd->bitflip_threshold, corrected);
+	}
+
+	return 0;
+}
+
+static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			      uint8_t *buf, int oob_required, int page)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	return brcmnand_read(mtd, chip, host->last_addr,
+			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
+}
+
+static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				  uint8_t *buf, int oob_required, int page)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
+	int ret;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	brcmnand_set_ecc_enabled(host, 0);
+	ret = brcmnand_read(mtd, chip, host->last_addr,
+			mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
+	brcmnand_set_ecc_enabled(host, 1);
+	return ret;
+}
+
+static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			     int page)
+{
+	return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
+			mtd->writesize >> FC_SHIFT,
+			NULL, (u8 *)chip->oob_poi);
+}
+
+static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				 int page)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+
+	brcmnand_set_ecc_enabled(host, 0);
+	brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
+		mtd->writesize >> FC_SHIFT,
+		NULL, (u8 *)chip->oob_poi);
+	brcmnand_set_ecc_enabled(host, 1);
+	return 0;
+}
+
+static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
+			  u64 addr, const u32 *buf, u8 *oob)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	struct brcmnand_controller *ctrl = host->ctrl;
+	unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
+	int status, ret = 0;
+
+	dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
+
+	if (unlikely((unsigned long)buf & 0x03)) {
+		dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
+		buf = (u32 *)((unsigned long)buf & ~0x03);
+	}
+
+	brcmnand_wp(mtd, 0);
+
+	for (i = 0; i < ctrl->max_oob; i += 4)
+		oob_reg_write(ctrl, i, 0xffffffff);
+
+	if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
+		if (brcmnand_dma_trans(host, addr, (u32 *)buf,
+					mtd->writesize, CMD_PROGRAM_PAGE))
+			ret = -EIO;
+		goto out;
+	}
+
+	brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
+			(host->cs << 16) | ((addr >> 32) & 0xffff));
+	(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
+
+	for (i = 0; i < trans; i++, addr += FC_BYTES) {
+		/* full address MUST be set before populating FC */
+		brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
+				   lower_32_bits(addr));
+		(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+
+		if (buf) {
+			brcmnand_soc_data_bus_prepare(ctrl->soc, false);
+
+			for (j = 0; j < FC_WORDS; j++, buf++)
+				brcmnand_write_fc(ctrl, j, *buf);
+
+			brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
+		} else if (oob) {
+			for (j = 0; j < FC_WORDS; j++)
+				brcmnand_write_fc(ctrl, j, 0xffffffff);
+		}
+
+		if (oob) {
+			oob += write_oob_to_regs(ctrl, i, oob,
+					mtd->oobsize / trans,
+					host->hwcfg.sector_size_1k);
+		}
+
+		/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
+		brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
+		status = brcmnand_waitfunc(mtd, chip);
+
+		if (status & NAND_STATUS_FAIL) {
+			dev_info(ctrl->dev, "program failed at %llx\n",
+				(unsigned long long)addr);
+			ret = -EIO;
+			goto out;
+		}
+	}
+out:
+	brcmnand_wp(mtd, 1);
+	return ret;
+}
+
+static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			       const uint8_t *buf, int oob_required, int page)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	void *oob = oob_required ? chip->oob_poi : NULL;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int brcmnand_write_page_raw(struct mtd_info *mtd,
+				   struct nand_chip *chip, const uint8_t *buf,
+				   int oob_required, int page)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	void *oob = oob_required ? chip->oob_poi : NULL;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	brcmnand_set_ecc_enabled(host, 0);
+	brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
+	brcmnand_set_ecc_enabled(host, 1);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+				  int page)
+{
+	return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
+				  NULL, chip->oob_poi);
+}
+
+static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				  int page)
+{
+	struct brcmnand_host *host = nand_get_controller_data(chip);
+	int ret;
+
+	brcmnand_set_ecc_enabled(host, 0);
+	ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
+				 (u8 *)chip->oob_poi);
+	brcmnand_set_ecc_enabled(host, 1);
+
+	return ret;
+}
+
+/***********************************************************************
+ * Per-CS setup (1 NAND device)
+ ***********************************************************************/
+
+static int brcmnand_set_cfg(struct brcmnand_host *host,
+			    struct brcmnand_cfg *cfg)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	struct nand_chip *chip = &host->chip;
+	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
+			BRCMNAND_CS_CFG_EXT);
+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+			BRCMNAND_CS_ACC_CONTROL);
+	u8 block_size = 0, page_size = 0, device_size = 0;
+	u32 tmp;
+
+	if (ctrl->block_sizes) {
+		int i, found;
+
+		for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
+			if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
+				block_size = i;
+				found = 1;
+			}
+		if (!found) {
+			dev_warn(ctrl->dev, "invalid block size %u\n",
+					cfg->block_size);
+			return -EINVAL;
+		}
+	} else {
+		block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
+	}
+
+	if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
+				cfg->block_size > ctrl->max_block_size)) {
+		dev_warn(ctrl->dev, "invalid block size %u\n",
+				cfg->block_size);
+		block_size = 0;
+	}
+
+	if (ctrl->page_sizes) {
+		int i, found;
+
+		for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
+			if (ctrl->page_sizes[i] == cfg->page_size) {
+				page_size = i;
+				found = 1;
+			}
+		if (!found) {
+			dev_warn(ctrl->dev, "invalid page size %u\n",
+					cfg->page_size);
+			return -EINVAL;
+		}
+	} else {
+		page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
+	}
+
+	if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
+				cfg->page_size > ctrl->max_page_size)) {
+		dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
+		return -EINVAL;
+	}
+
+	if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
+		dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
+			(unsigned long long)cfg->device_size);
+		return -EINVAL;
+	}
+	device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
+
+	tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) |
+		(cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) |
+		(cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
+		(!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
+		(device_size << CFG_DEVICE_SIZE_SHIFT);
+	if (cfg_offs == cfg_ext_offs) {
+		tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
+		       (block_size << CFG_BLK_SIZE_SHIFT);
+		nand_writereg(ctrl, cfg_offs, tmp);
+	} else {
+		nand_writereg(ctrl, cfg_offs, tmp);
+		tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
+		      (block_size << CFG_EXT_BLK_SIZE_SHIFT);
+		nand_writereg(ctrl, cfg_ext_offs, tmp);
+	}
+
+	tmp = nand_readreg(ctrl, acc_control_offs);
+	tmp &= ~brcmnand_ecc_level_mask(ctrl);
+	tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
+	tmp &= ~brcmnand_spare_area_mask(ctrl);
+	tmp |= cfg->spare_area_size;
+	nand_writereg(ctrl, acc_control_offs, tmp);
+
+	brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
+
+	/* threshold = ceil(BCH-level * 0.75) */
+	brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
+
+	return 0;
+}
+
+static void brcmnand_print_cfg(struct brcmnand_host *host,
+			       char *buf, struct brcmnand_cfg *cfg)
+{
+	buf += sprintf(buf,
+		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
+		(unsigned long long)cfg->device_size >> 20,
+		cfg->block_size >> 10,
+		cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
+		cfg->page_size >= 1024 ? "KiB" : "B",
+		cfg->spare_area_size, cfg->device_width);
+
+	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
+	if (is_hamming_ecc(host->ctrl, cfg))
+		sprintf(buf, ", Hamming ECC");
+	else if (cfg->sector_size_1k)
+		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
+	else
+		sprintf(buf, ", BCH-%u", cfg->ecc_level);
+}
+
+/*
+ * Minimum number of bytes to address a page. Calculated as:
+ *     roundup(log2(size / page-size) / 8)
+ *
+ * NB: the following does not "round up" for non-power-of-2 'size'; but this is
+ *     OK because many other things will break if 'size' is irregular...
+ */
+static inline int get_blk_adr_bytes(u64 size, u32 writesize)
+{
+	return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
+}
+
+static int brcmnand_setup_dev(struct brcmnand_host *host)
+{
+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+	struct nand_chip *chip = &host->chip;
+	struct brcmnand_controller *ctrl = host->ctrl;
+	struct brcmnand_cfg *cfg = &host->hwcfg;
+	char msg[128];
+	u32 offs, tmp, oob_sector;
+	int ret;
+
+	memset(cfg, 0, sizeof(*cfg));
+
+	ret = of_property_read_u32(nand_get_flash_node(chip),
+				   "brcm,nand-oob-sector-size",
+				   &oob_sector);
+	if (ret) {
+		/* Use detected size */
+		cfg->spare_area_size = mtd->oobsize /
+					(mtd->writesize >> FC_SHIFT);
+	} else {
+		cfg->spare_area_size = oob_sector;
+	}
+	if (cfg->spare_area_size > ctrl->max_oob)
+		cfg->spare_area_size = ctrl->max_oob;
+	/*
+	 * Set oobsize to be consistent with controller's spare_area_size, as
+	 * the rest is inaccessible.
+	 */
+	mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
+
+	cfg->device_size = mtd->size;
+	cfg->block_size = mtd->erasesize;
+	cfg->page_size = mtd->writesize;
+	cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
+	cfg->col_adr_bytes = 2;
+	cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
+
+	if (chip->ecc.mode != NAND_ECC_HW) {
+		dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
+			chip->ecc.mode);
+		return -EINVAL;
+	}
+
+	if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
+		if (chip->ecc.strength == 1 && chip->ecc.size == 512)
+			/* Default to Hamming for 1-bit ECC, if unspecified */
+			chip->ecc.algo = NAND_ECC_HAMMING;
+		else
+			/* Otherwise, BCH */
+			chip->ecc.algo = NAND_ECC_BCH;
+	}
+
+	if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
+						   chip->ecc.size != 512)) {
+		dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
+			chip->ecc.strength, chip->ecc.size);
+		return -EINVAL;
+	}
+
+	switch (chip->ecc.size) {
+	case 512:
+		if (chip->ecc.algo == NAND_ECC_HAMMING)
+			cfg->ecc_level = 15;
+		else
+			cfg->ecc_level = chip->ecc.strength;
+		cfg->sector_size_1k = 0;
+		break;
+	case 1024:
+		if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
+			dev_err(ctrl->dev, "1KB sectors not supported\n");
+			return -EINVAL;
+		}
+		if (chip->ecc.strength & 0x1) {
+			dev_err(ctrl->dev,
+				"odd ECC not supported with 1KB sectors\n");
+			return -EINVAL;
+		}
+
+		cfg->ecc_level = chip->ecc.strength >> 1;
+		cfg->sector_size_1k = 1;
+		break;
+	default:
+		dev_err(ctrl->dev, "unsupported ECC size: %d\n",
+			chip->ecc.size);
+		return -EINVAL;
+	}
+
+	cfg->ful_adr_bytes = cfg->blk_adr_bytes;
+	if (mtd->writesize > 512)
+		cfg->ful_adr_bytes += cfg->col_adr_bytes;
+	else
+		cfg->ful_adr_bytes += 1;
+
+	ret = brcmnand_set_cfg(host, cfg);
+	if (ret)
+		return ret;
+
+	brcmnand_set_ecc_enabled(host, 1);
+
+	brcmnand_print_cfg(host, msg, cfg);
+	dev_info(ctrl->dev, "detected %s\n", msg);
+
+	/* Configure ACC_CONTROL */
+	offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
+	tmp = nand_readreg(ctrl, offs);
+	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
+	tmp &= ~ACC_CONTROL_RD_ERASED;
+
+	/* We need to turn on Read from erased paged protected by ECC */
+	if (ctrl->nand_version >= 0x0702)
+		tmp |= ACC_CONTROL_RD_ERASED;
+	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
+	if (ctrl->features & BRCMNAND_HAS_PREFETCH)
+		tmp &= ~ACC_CONTROL_PREFETCH;
+
+	nand_writereg(ctrl, offs, tmp);
+
+	return 0;
+}
+
+static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	struct platform_device *pdev = host->pdev;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	int ret;
+	u16 cfg_offs;
+
+	ret = of_property_read_u32(dn, "reg", &host->cs);
+	if (ret) {
+		dev_err(&pdev->dev, "can't get chip-select\n");
+		return -ENXIO;
+	}
+
+	mtd = nand_to_mtd(&host->chip);
+	chip = &host->chip;
+
+	nand_set_flash_node(chip, dn);
+	nand_set_controller_data(chip, host);
+	mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
+				   host->cs);
+	if (!mtd->name)
+		return -ENOMEM;
+
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = &pdev->dev;
+
+	chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
+	chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
+
+	chip->cmd_ctrl = brcmnand_cmd_ctrl;
+	chip->cmdfunc = brcmnand_cmdfunc;
+	chip->waitfunc = brcmnand_waitfunc;
+	chip->read_byte = brcmnand_read_byte;
+	chip->read_buf = brcmnand_read_buf;
+	chip->write_buf = brcmnand_write_buf;
+
+	chip->ecc.mode = NAND_ECC_HW;
+	chip->ecc.read_page = brcmnand_read_page;
+	chip->ecc.write_page = brcmnand_write_page;
+	chip->ecc.read_page_raw = brcmnand_read_page_raw;
+	chip->ecc.write_page_raw = brcmnand_write_page_raw;
+	chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
+	chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
+	chip->ecc.read_oob = brcmnand_read_oob;
+	chip->ecc.write_oob = brcmnand_write_oob;
+
+	chip->controller = &ctrl->controller;
+
+	/*
+	 * The bootloader might have configured 16bit mode but
+	 * NAND READID command only works in 8bit mode. We force
+	 * 8bit mode here to ensure that NAND READID commands works.
+	 */
+	cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+	nand_writereg(ctrl, cfg_offs,
+		      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		return ret;
+
+	chip->options |= NAND_NO_SUBPAGE_WRITE;
+	/*
+	 * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
+	 * to/from, and have nand_base pass us a bounce buffer instead, as
+	 * needed.
+	 */
+	chip->options |= NAND_USE_BOUNCE_BUFFER;
+
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->bbt_options |= NAND_BBT_NO_OOB;
+
+	if (brcmnand_setup_dev(host))
+		return -ENXIO;
+
+	chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
+	/* only use our internal HW threshold */
+	mtd->bitflip_threshold = 1;
+
+	ret = brcmstb_choose_ecc_layout(host);
+	if (ret)
+		return ret;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		return ret;
+
+	return mtd_device_register(mtd, NULL, 0);
+}
+
+static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
+					    int restore)
+{
+	struct brcmnand_controller *ctrl = host->ctrl;
+	u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
+	u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
+			BRCMNAND_CS_CFG_EXT);
+	u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
+			BRCMNAND_CS_ACC_CONTROL);
+	u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
+	u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
+
+	if (restore) {
+		nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
+		if (cfg_offs != cfg_ext_offs)
+			nand_writereg(ctrl, cfg_ext_offs,
+				      host->hwcfg.config_ext);
+		nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
+		nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
+		nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
+	} else {
+		host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
+		if (cfg_offs != cfg_ext_offs)
+			host->hwcfg.config_ext =
+				nand_readreg(ctrl, cfg_ext_offs);
+		host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
+		host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
+		host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
+	}
+}
+
+static int brcmnand_suspend(struct device *dev)
+{
+	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
+	struct brcmnand_host *host;
+
+	list_for_each_entry(host, &ctrl->host_list, node)
+		brcmnand_save_restore_cs_config(host, 0);
+
+	ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
+	ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
+	ctrl->corr_stat_threshold =
+		brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
+
+	if (has_flash_dma(ctrl))
+		ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
+
+	return 0;
+}
+
+static int brcmnand_resume(struct device *dev)
+{
+	struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
+	struct brcmnand_host *host;
+
+	if (has_flash_dma(ctrl)) {
+		flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
+		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
+	}
+
+	brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
+	brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
+	brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
+			ctrl->corr_stat_threshold);
+	if (ctrl->soc) {
+		/* Clear/re-enable interrupt */
+		ctrl->soc->ctlrdy_ack(ctrl->soc);
+		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
+	}
+
+	list_for_each_entry(host, &ctrl->host_list, node) {
+		struct nand_chip *chip = &host->chip;
+
+		brcmnand_save_restore_cs_config(host, 1);
+
+		/* Reset the chip, required by some chips after power-up */
+		nand_reset_op(chip);
+	}
+
+	return 0;
+}
+
+const struct dev_pm_ops brcmnand_pm_ops = {
+	.suspend		= brcmnand_suspend,
+	.resume			= brcmnand_resume,
+};
+EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
+
+static const struct of_device_id brcmnand_of_match[] = {
+	{ .compatible = "brcm,brcmnand-v4.0" },
+	{ .compatible = "brcm,brcmnand-v5.0" },
+	{ .compatible = "brcm,brcmnand-v6.0" },
+	{ .compatible = "brcm,brcmnand-v6.1" },
+	{ .compatible = "brcm,brcmnand-v6.2" },
+	{ .compatible = "brcm,brcmnand-v7.0" },
+	{ .compatible = "brcm,brcmnand-v7.1" },
+	{ .compatible = "brcm,brcmnand-v7.2" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, brcmnand_of_match);
+
+/***********************************************************************
+ * Platform driver setup (per controller)
+ ***********************************************************************/
+
+int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *dn = dev->of_node, *child;
+	struct brcmnand_controller *ctrl;
+	struct resource *res;
+	int ret;
+
+	/* We only support device-tree instantiation */
+	if (!dn)
+		return -ENODEV;
+
+	if (!of_match_node(brcmnand_of_match, dn))
+		return -ENODEV;
+
+	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, ctrl);
+	ctrl->dev = dev;
+
+	init_completion(&ctrl->done);
+	init_completion(&ctrl->dma_done);
+	nand_hw_control_init(&ctrl->controller);
+	INIT_LIST_HEAD(&ctrl->host_list);
+
+	/* NAND register range */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctrl->nand_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ctrl->nand_base))
+		return PTR_ERR(ctrl->nand_base);
+
+	/* Enable clock before using NAND registers */
+	ctrl->clk = devm_clk_get(dev, "nand");
+	if (!IS_ERR(ctrl->clk)) {
+		ret = clk_prepare_enable(ctrl->clk);
+		if (ret)
+			return ret;
+	} else {
+		ret = PTR_ERR(ctrl->clk);
+		if (ret == -EPROBE_DEFER)
+			return ret;
+
+		ctrl->clk = NULL;
+	}
+
+	/* Initialize NAND revision */
+	ret = brcmnand_revision_init(ctrl);
+	if (ret)
+		goto err;
+
+	/*
+	 * Most chips have this cache at a fixed offset within 'nand' block.
+	 * Some must specify this region separately.
+	 */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
+	if (res) {
+		ctrl->nand_fc = devm_ioremap_resource(dev, res);
+		if (IS_ERR(ctrl->nand_fc)) {
+			ret = PTR_ERR(ctrl->nand_fc);
+			goto err;
+		}
+	} else {
+		ctrl->nand_fc = ctrl->nand_base +
+				ctrl->reg_offsets[BRCMNAND_FC_BASE];
+	}
+
+	/* FLASH_DMA */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
+	if (res) {
+		ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(ctrl->flash_dma_base)) {
+			ret = PTR_ERR(ctrl->flash_dma_base);
+			goto err;
+		}
+
+		flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
+		flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
+
+		/* Allocate descriptor(s) */
+		ctrl->dma_desc = dmam_alloc_coherent(dev,
+						     sizeof(*ctrl->dma_desc),
+						     &ctrl->dma_pa, GFP_KERNEL);
+		if (!ctrl->dma_desc) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ctrl->dma_irq = platform_get_irq(pdev, 1);
+		if ((int)ctrl->dma_irq < 0) {
+			dev_err(dev, "missing FLASH_DMA IRQ\n");
+			ret = -ENODEV;
+			goto err;
+		}
+
+		ret = devm_request_irq(dev, ctrl->dma_irq,
+				brcmnand_dma_irq, 0, DRV_NAME,
+				ctrl);
+		if (ret < 0) {
+			dev_err(dev, "can't allocate IRQ %d: error %d\n",
+					ctrl->dma_irq, ret);
+			goto err;
+		}
+
+		dev_info(dev, "enabling FLASH_DMA\n");
+	}
+
+	/* Disable automatic device ID config, direct addressing */
+	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
+			 CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
+	/* Disable XOR addressing */
+	brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
+
+	if (ctrl->features & BRCMNAND_HAS_WP) {
+		/* Permanently disable write protection */
+		if (wp_on == 2)
+			brcmnand_set_wp(ctrl, false);
+	} else {
+		wp_on = 0;
+	}
+
+	/* IRQ */
+	ctrl->irq = platform_get_irq(pdev, 0);
+	if ((int)ctrl->irq < 0) {
+		dev_err(dev, "no IRQ defined\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/*
+	 * Some SoCs integrate this controller (e.g., its interrupt bits) in
+	 * interesting ways
+	 */
+	if (soc) {
+		ctrl->soc = soc;
+
+		ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
+				       DRV_NAME, ctrl);
+
+		/* Enable interrupt */
+		ctrl->soc->ctlrdy_ack(ctrl->soc);
+		ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
+	} else {
+		/* Use standard interrupt infrastructure */
+		ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
+				       DRV_NAME, ctrl);
+	}
+	if (ret < 0) {
+		dev_err(dev, "can't allocate IRQ %d: error %d\n",
+			ctrl->irq, ret);
+		goto err;
+	}
+
+	for_each_available_child_of_node(dn, child) {
+		if (of_device_is_compatible(child, "brcm,nandcs")) {
+			struct brcmnand_host *host;
+
+			host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+			if (!host) {
+				of_node_put(child);
+				ret = -ENOMEM;
+				goto err;
+			}
+			host->pdev = pdev;
+			host->ctrl = ctrl;
+
+			ret = brcmnand_init_cs(host, child);
+			if (ret) {
+				devm_kfree(dev, host);
+				continue; /* Try all chip-selects */
+			}
+
+			list_add_tail(&host->node, &ctrl->host_list);
+		}
+	}
+
+	/* No chip-selects could initialize properly */
+	if (list_empty(&ctrl->host_list)) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	clk_disable_unprepare(ctrl->clk);
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(brcmnand_probe);
+
+int brcmnand_remove(struct platform_device *pdev)
+{
+	struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
+	struct brcmnand_host *host;
+
+	list_for_each_entry(host, &ctrl->host_list, node)
+		nand_release(nand_to_mtd(&host->chip));
+
+	clk_disable_unprepare(ctrl->clk);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(brcmnand_remove);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Kevin Cernekee");
+MODULE_AUTHOR("Brian Norris");
+MODULE_DESCRIPTION("NAND driver for Broadcom chips");
+MODULE_ALIAS("platform:brcmnand");
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
new file mode 100644
index 000000000000..5c44cd4aba87
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2015 Broadcom 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.
+ */
+
+#ifndef __BRCMNAND_H__
+#define __BRCMNAND_H__
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+struct platform_device;
+struct dev_pm_ops;
+
+struct brcmnand_soc {
+	bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
+	void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
+	void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
+				 bool is_param);
+};
+
+static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
+						 bool is_param)
+{
+	if (soc && soc->prepare_data_bus)
+		soc->prepare_data_bus(soc, true, is_param);
+}
+
+static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
+						   bool is_param)
+{
+	if (soc && soc->prepare_data_bus)
+		soc->prepare_data_bus(soc, false, is_param);
+}
+
+static inline u32 brcmnand_readl(void __iomem *addr)
+{
+	/*
+	 * MIPS endianness is configured by boot strap, which also reverses all
+	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
+	 * endian I/O).
+	 *
+	 * Other architectures (e.g., ARM) either do not support big endian, or
+	 * else leave I/O in little endian mode.
+	 */
+	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+		return __raw_readl(addr);
+	else
+		return readl_relaxed(addr);
+}
+
+static inline void brcmnand_writel(u32 val, void __iomem *addr)
+{
+	/* See brcmnand_readl() comments */
+	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+		__raw_writel(val, addr);
+	else
+		writel_relaxed(val, addr);
+}
+
+int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
+int brcmnand_remove(struct platform_device *pdev);
+
+extern const struct dev_pm_ops brcmnand_pm_ops;
+
+#endif /* __BRCMNAND_H__ */
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
new file mode 100644
index 000000000000..5c271077ac87
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2015 Broadcom 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/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "brcmnand.h"
+
+static const struct of_device_id brcmstb_nand_of_match[] = {
+	{ .compatible = "brcm,brcmnand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, brcmstb_nand_of_match);
+
+static int brcmstb_nand_probe(struct platform_device *pdev)
+{
+	return brcmnand_probe(pdev, NULL);
+}
+
+static struct platform_driver brcmstb_nand_driver = {
+	.probe			= brcmstb_nand_probe,
+	.remove			= brcmnand_remove,
+	.driver = {
+		.name		= "brcmstb_nand",
+		.pm		= &brcmnand_pm_ops,
+		.of_match_table = brcmstb_nand_of_match,
+	}
+};
+module_platform_driver(brcmstb_nand_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_DESCRIPTION("NAND driver for Broadcom STB chips");
diff --git a/drivers/mtd/nand/raw/brcmnand/iproc_nand.c b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c
new file mode 100644
index 000000000000..4c6ae113664d
--- /dev/null
+++ b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2015 Broadcom 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/device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "brcmnand.h"
+
+struct iproc_nand_soc {
+	struct brcmnand_soc soc;
+
+	void __iomem *idm_base;
+	void __iomem *ext_base;
+	spinlock_t idm_lock;
+};
+
+#define IPROC_NAND_CTLR_READY_OFFSET       0x10
+#define IPROC_NAND_CTLR_READY              BIT(0)
+
+#define IPROC_NAND_IO_CTRL_OFFSET          0x00
+#define IPROC_NAND_APB_LE_MODE             BIT(24)
+#define IPROC_NAND_INT_CTRL_READ_ENABLE    BIT(6)
+
+static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
+{
+	struct iproc_nand_soc *priv =
+			container_of(soc, struct iproc_nand_soc, soc);
+	void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
+	u32 val = brcmnand_readl(mmio);
+
+	if (val & IPROC_NAND_CTLR_READY) {
+		brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
+		return true;
+	}
+
+	return false;
+}
+
+static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
+{
+	struct iproc_nand_soc *priv =
+			container_of(soc, struct iproc_nand_soc, soc);
+	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->idm_lock, flags);
+
+	val = brcmnand_readl(mmio);
+
+	if (en)
+		val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
+	else
+		val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
+
+	brcmnand_writel(val, mmio);
+
+	spin_unlock_irqrestore(&priv->idm_lock, flags);
+}
+
+static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
+				  bool is_param)
+{
+	struct iproc_nand_soc *priv =
+			container_of(soc, struct iproc_nand_soc, soc);
+	void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->idm_lock, flags);
+
+	val = brcmnand_readl(mmio);
+
+	/*
+	 * In the case of BE or when dealing with NAND data, alway configure
+	 * the APB bus to LE mode before accessing the FIFO and back to BE mode
+	 * after the access is done
+	 */
+	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
+		if (prepare)
+			val |= IPROC_NAND_APB_LE_MODE;
+		else
+			val &= ~IPROC_NAND_APB_LE_MODE;
+	} else { /* when in LE accessing the parameter page, keep APB in BE */
+		val &= ~IPROC_NAND_APB_LE_MODE;
+	}
+
+	brcmnand_writel(val, mmio);
+
+	spin_unlock_irqrestore(&priv->idm_lock, flags);
+}
+
+static int iproc_nand_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct iproc_nand_soc *priv;
+	struct brcmnand_soc *soc;
+	struct resource *res;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	soc = &priv->soc;
+
+	spin_lock_init(&priv->idm_lock);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
+	priv->idm_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->idm_base))
+		return PTR_ERR(priv->idm_base);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
+	priv->ext_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->ext_base))
+		return PTR_ERR(priv->ext_base);
+
+	soc->ctlrdy_ack = iproc_nand_intc_ack;
+	soc->ctlrdy_set_enabled = iproc_nand_intc_set;
+	soc->prepare_data_bus = iproc_nand_apb_access;
+
+	return brcmnand_probe(pdev, soc);
+}
+
+static const struct of_device_id iproc_nand_of_match[] = {
+	{ .compatible = "brcm,nand-iproc" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
+
+static struct platform_driver iproc_nand_driver = {
+	.probe			= iproc_nand_probe,
+	.remove			= brcmnand_remove,
+	.driver = {
+		.name		= "iproc_nand",
+		.pm		= &brcmnand_pm_ops,
+		.of_match_table	= iproc_nand_of_match,
+	}
+};
+module_platform_driver(iproc_nand_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_AUTHOR("Ray Jui");
+MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
new file mode 100644
index 000000000000..567ff972d5fc
--- /dev/null
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -0,0 +1,871 @@
+/*
+ * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
+ *
+ * The data sheet for this device can be found at:
+ *    http://wiki.laptop.org/go/Datasheets 
+ *
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ */
+
+#define DEBUG
+
+#include <linux/device.h>
+#undef DEBUG
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/rslib.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+#define CAFE_NAND_CTRL1		0x00
+#define CAFE_NAND_CTRL2		0x04
+#define CAFE_NAND_CTRL3		0x08
+#define CAFE_NAND_STATUS	0x0c
+#define CAFE_NAND_IRQ		0x10
+#define CAFE_NAND_IRQ_MASK	0x14
+#define CAFE_NAND_DATA_LEN	0x18
+#define CAFE_NAND_ADDR1		0x1c
+#define CAFE_NAND_ADDR2		0x20
+#define CAFE_NAND_TIMING1	0x24
+#define CAFE_NAND_TIMING2	0x28
+#define CAFE_NAND_TIMING3	0x2c
+#define CAFE_NAND_NONMEM	0x30
+#define CAFE_NAND_ECC_RESULT	0x3C
+#define CAFE_NAND_DMA_CTRL	0x40
+#define CAFE_NAND_DMA_ADDR0	0x44
+#define CAFE_NAND_DMA_ADDR1	0x48
+#define CAFE_NAND_ECC_SYN01	0x50
+#define CAFE_NAND_ECC_SYN23	0x54
+#define CAFE_NAND_ECC_SYN45	0x58
+#define CAFE_NAND_ECC_SYN67	0x5c
+#define CAFE_NAND_READ_DATA	0x1000
+#define CAFE_NAND_WRITE_DATA	0x2000
+
+#define CAFE_GLOBAL_CTRL	0x3004
+#define CAFE_GLOBAL_IRQ		0x3008
+#define CAFE_GLOBAL_IRQ_MASK	0x300c
+#define CAFE_NAND_RESET		0x3034
+
+/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
+#define CTRL1_CHIPSELECT	(1<<19)
+
+struct cafe_priv {
+	struct nand_chip nand;
+	struct pci_dev *pdev;
+	void __iomem *mmio;
+	struct rs_control *rs;
+	uint32_t ctl1;
+	uint32_t ctl2;
+	int datalen;
+	int nr_data;
+	int data_pos;
+	int page_addr;
+	dma_addr_t dmaaddr;
+	unsigned char *dmabuf;
+};
+
+static int usedma = 1;
+module_param(usedma, int, 0644);
+
+static int skipbbt = 0;
+module_param(skipbbt, int, 0644);
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+static int regdebug = 0;
+module_param(regdebug, int, 0644);
+
+static int checkecc = 1;
+module_param(checkecc, int, 0644);
+
+static unsigned int numtimings;
+static int timing[3];
+module_param_array(timing, int, &numtimings, 0644);
+
+static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
+
+/* Hrm. Why isn't this already conditional on something in the struct device? */
+#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
+
+/* Make it easier to switch to PIO if we need to */
+#define cafe_readl(cafe, addr)			readl((cafe)->mmio + CAFE_##addr)
+#define cafe_writel(cafe, datum, addr)		writel(datum, (cafe)->mmio + CAFE_##addr)
+
+static int cafe_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+	int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
+	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
+
+	cafe_writel(cafe, irqs, NAND_IRQ);
+
+	cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
+		result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
+		cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+	return result;
+}
+
+
+static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+	if (usedma)
+		memcpy(cafe->dmabuf + cafe->datalen, buf, len);
+	else
+		memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
+
+	cafe->datalen += len;
+
+	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
+		len, cafe->datalen);
+}
+
+static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+	if (usedma)
+		memcpy(buf, cafe->dmabuf + cafe->datalen, len);
+	else
+		memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
+
+	cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
+		  len, cafe->datalen);
+	cafe->datalen += len;
+}
+
+static uint8_t cafe_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+	uint8_t d;
+
+	cafe_read_buf(mtd, &d, 1);
+	cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
+
+	return d;
+}
+
+static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+			      int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+	int adrbytes = 0;
+	uint32_t ctl1;
+	uint32_t doneint = 0x80000000;
+
+	cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
+		command, column, page_addr);
+
+	if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
+		/* Second half of a command we already calculated */
+		cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
+		ctl1 = cafe->ctl1;
+		cafe->ctl2 &= ~(1<<30);
+		cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
+			  cafe->ctl1, cafe->nr_data);
+		goto do_command;
+	}
+	/* Reset ECC engine */
+	cafe_writel(cafe, 0, NAND_CTRL2);
+
+	/* Emulate NAND_CMD_READOOB on large-page chips */
+	if (mtd->writesize > 512 &&
+	    command == NAND_CMD_READOOB) {
+		column += mtd->writesize;
+		command = NAND_CMD_READ0;
+	}
+
+	/* FIXME: Do we need to send read command before sending data
+	   for small-page chips, to position the buffer correctly? */
+
+	if (column != -1) {
+		cafe_writel(cafe, column, NAND_ADDR1);
+		adrbytes = 2;
+		if (page_addr != -1)
+			goto write_adr2;
+	} else if (page_addr != -1) {
+		cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
+		page_addr >>= 16;
+	write_adr2:
+		cafe_writel(cafe, page_addr, NAND_ADDR2);
+		adrbytes += 2;
+		if (mtd->size > mtd->writesize << 16)
+			adrbytes++;
+	}
+
+	cafe->data_pos = cafe->datalen = 0;
+
+	/* Set command valid bit, mask in the chip select bit  */
+	ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
+
+	/* Set RD or WR bits as appropriate */
+	if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
+		ctl1 |= (1<<26); /* rd */
+		/* Always 5 bytes, for now */
+		cafe->datalen = 4;
+		/* And one address cycle -- even for STATUS, since the controller doesn't work without */
+		adrbytes = 1;
+	} else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+		   command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
+		ctl1 |= 1<<26; /* rd */
+		/* For now, assume just read to end of page */
+		cafe->datalen = mtd->writesize + mtd->oobsize - column;
+	} else if (command == NAND_CMD_SEQIN)
+		ctl1 |= 1<<25; /* wr */
+
+	/* Set number of address bytes */
+	if (adrbytes)
+		ctl1 |= ((adrbytes-1)|8) << 27;
+
+	if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
+		/* Ignore the first command of a pair; the hardware
+		   deals with them both at once, later */
+		cafe->ctl1 = ctl1;
+		cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
+			  cafe->ctl1, cafe->datalen);
+		return;
+	}
+	/* RNDOUT and READ0 commands need a following byte */
+	if (command == NAND_CMD_RNDOUT)
+		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
+	else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
+		cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
+
+ do_command:
+	cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
+		cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
+
+	/* NB: The datasheet lies -- we really should be subtracting 1 here */
+	cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
+	cafe_writel(cafe, 0x90000000, NAND_IRQ);
+	if (usedma && (ctl1 & (3<<25))) {
+		uint32_t dmactl = 0xc0000000 + cafe->datalen;
+		/* If WR or RD bits set, set up DMA */
+		if (ctl1 & (1<<26)) {
+			/* It's a read */
+			dmactl |= (1<<29);
+			/* ... so it's done when the DMA is done, not just
+			   the command. */
+			doneint = 0x10000000;
+		}
+		cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
+	}
+	cafe->datalen = 0;
+
+	if (unlikely(regdebug)) {
+		int i;
+		printk("About to write command %08x to register 0\n", ctl1);
+		for (i=4; i< 0x5c; i+=4)
+			printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+	}
+
+	cafe_writel(cafe, ctl1, NAND_CTRL1);
+	/* Apply this short delay always to ensure that we do wait tWB in
+	 * any case on any machine. */
+	ndelay(100);
+
+	if (1) {
+		int c;
+		uint32_t irqs;
+
+		for (c = 500000; c != 0; c--) {
+			irqs = cafe_readl(cafe, NAND_IRQ);
+			if (irqs & doneint)
+				break;
+			udelay(1);
+			if (!(c % 100000))
+				cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
+			cpu_relax();
+		}
+		cafe_writel(cafe, doneint, NAND_IRQ);
+		cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
+			     command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
+	}
+
+	WARN_ON(cafe->ctl2 & (1<<30));
+
+	switch (command) {
+
+	case NAND_CMD_CACHEDPROG:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_RNDIN:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_RNDOUT:
+		cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+		return;
+	}
+	nand_wait_ready(mtd);
+	cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+}
+
+static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+
+	/* Mask the appropriate bit into the stored value of ctl1
+	   which will be used by cafe_nand_cmdfunc() */
+	if (chipnr)
+		cafe->ctl1 |= CTRL1_CHIPSELECT;
+	else
+		cafe->ctl1 &= ~CTRL1_CHIPSELECT;
+}
+
+static irqreturn_t cafe_nand_interrupt(int irq, void *id)
+{
+	struct mtd_info *mtd = id;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+	uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
+	cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
+	if (!irqs)
+		return IRQ_NONE;
+
+	cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
+	return IRQ_HANDLED;
+}
+
+static void cafe_nand_bug(struct mtd_info *mtd)
+{
+	BUG();
+}
+
+static int cafe_nand_write_oob(struct mtd_info *mtd,
+			       struct nand_chip *chip, int page)
+{
+	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
+				 mtd->oobsize);
+}
+
+/* Don't use -- use nand_read_oob_std for now */
+static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			      int page)
+{
+	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
+}
+/**
+ * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @buf:	buffer to store read data
+ * @oob_required:	caller expects OOB data read to chip->oob_poi
+ *
+ * The hw generator calculates the error syndrome automatically. Therefore
+ * we need a special oob layout and handling.
+ */
+static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			       uint8_t *buf, int oob_required, int page)
+{
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+	unsigned int max_bitflips = 0;
+
+	cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
+		     cafe_readl(cafe, NAND_ECC_RESULT),
+		     cafe_readl(cafe, NAND_ECC_SYN01));
+
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
+		unsigned short syn[8], pat[4];
+		int pos[4];
+		u8 *oob = chip->oob_poi;
+		int i, n;
+
+		for (i=0; i<8; i+=2) {
+			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
+			syn[i] = cafe->rs->index_of[tmp & 0xfff];
+			syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
+		}
+
+		n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
+		                pat);
+
+		for (i = 0; i < n; i++) {
+			int p = pos[i];
+
+			/* The 12-bit symbols are mapped to bytes here */
+
+			if (p > 1374) {
+				/* out of range */
+				n = -1374;
+			} else if (p == 0) {
+				/* high four bits do not correspond to data */
+				if (pat[i] > 0xff)
+					n = -2048;
+				else
+					buf[0] ^= pat[i];
+			} else if (p == 1365) {
+				buf[2047] ^= pat[i] >> 4;
+				oob[0] ^= pat[i] << 4;
+			} else if (p > 1365) {
+				if ((p & 1) == 1) {
+					oob[3*p/2 - 2048] ^= pat[i] >> 4;
+					oob[3*p/2 - 2047] ^= pat[i] << 4;
+				} else {
+					oob[3*p/2 - 2049] ^= pat[i] >> 8;
+					oob[3*p/2 - 2048] ^= pat[i];
+				}
+			} else if ((p & 1) == 1) {
+				buf[3*p/2] ^= pat[i] >> 4;
+				buf[3*p/2 + 1] ^= pat[i] << 4;
+			} else {
+				buf[3*p/2 - 1] ^= pat[i] >> 8;
+				buf[3*p/2] ^= pat[i];
+			}
+		}
+
+		if (n < 0) {
+			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
+				cafe_readl(cafe, NAND_ADDR2) * 2048);
+			for (i = 0; i < 0x5c; i += 4)
+				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+			mtd->ecc_stats.failed++;
+		} else {
+			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
+			mtd->ecc_stats.corrected += n;
+			max_bitflips = max_t(unsigned int, max_bitflips, n);
+		}
+	}
+
+	return max_bitflips;
+}
+
+static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = chip->ecc.total;
+	oobregion->length = mtd->oobsize - chip->ecc.total;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
+	.ecc = cafe_ooblayout_ecc,
+	.free = cafe_ooblayout_free,
+};
+
+/* Ick. The BBT code really ought to be able to work this bit out
+   for itself from the above, at least for the 2KiB case */
+static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
+static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
+
+static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
+static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
+
+
+static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	14,
+	.len = 4,
+	.veroffs = 18,
+	.maxblocks = 4,
+	.pattern = cafe_bbt_pattern_2048
+};
+
+static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	14,
+	.len = 4,
+	.veroffs = 18,
+	.maxblocks = 4,
+	.pattern = cafe_mirror_pattern_2048
+};
+
+static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	14,
+	.len = 1,
+	.veroffs = 15,
+	.maxblocks = 4,
+	.pattern = cafe_bbt_pattern_512
+};
+
+static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	14,
+	.len = 1,
+	.veroffs = 15,
+	.maxblocks = 4,
+	.pattern = cafe_mirror_pattern_512
+};
+
+
+static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+					  struct nand_chip *chip,
+					  const uint8_t *buf, int oob_required,
+					  int page)
+{
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* Set up ECC autogeneration */
+	cafe->ctl2 |= (1<<30);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+{
+	return 0;
+}
+
+/* F_2[X]/(X**6+X+1)  */
+static unsigned short gf64_mul(u8 a, u8 b)
+{
+	u8 c;
+	unsigned int i;
+
+	c = 0;
+	for (i = 0; i < 6; i++) {
+		if (a & 1)
+			c ^= b;
+		a >>= 1;
+		b <<= 1;
+		if ((b & 0x40) != 0)
+			b ^= 0x43;
+	}
+
+	return c;
+}
+
+/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
+static u16 gf4096_mul(u16 a, u16 b)
+{
+	u8 ah, al, bh, bl, ch, cl;
+
+	ah = a >> 6;
+	al = a & 0x3f;
+	bh = b >> 6;
+	bl = b & 0x3f;
+
+	ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
+	cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
+
+	return (ch << 6) ^ cl;
+}
+
+static int cafe_mul(int x)
+{
+	if (x == 0)
+		return 1;
+	return gf4096_mul(x, 0xe01);
+}
+
+static int cafe_nand_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct mtd_info *mtd;
+	struct cafe_priv *cafe;
+	uint32_t ctrl;
+	int err = 0;
+	int old_dma;
+
+	/* Very old versions shared the same PCI ident for all three
+	   functions on the chip. Verify the class too... */
+	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
+		return -ENODEV;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	pci_set_master(pdev);
+
+	cafe = kzalloc(sizeof(*cafe), GFP_KERNEL);
+	if (!cafe)
+		return  -ENOMEM;
+
+	mtd = nand_to_mtd(&cafe->nand);
+	mtd->dev.parent = &pdev->dev;
+	nand_set_controller_data(&cafe->nand, cafe);
+
+	cafe->pdev = pdev;
+	cafe->mmio = pci_iomap(pdev, 0, 0);
+	if (!cafe->mmio) {
+		dev_warn(&pdev->dev, "failed to iomap\n");
+		err = -ENOMEM;
+		goto out_free_mtd;
+	}
+
+	cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
+	if (!cafe->rs) {
+		err = -ENOMEM;
+		goto out_ior;
+	}
+
+	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
+	cafe->nand.dev_ready = cafe_device_ready;
+	cafe->nand.read_byte = cafe_read_byte;
+	cafe->nand.read_buf = cafe_read_buf;
+	cafe->nand.write_buf = cafe_write_buf;
+	cafe->nand.select_chip = cafe_select_chip;
+	cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
+	cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
+
+	cafe->nand.chip_delay = 0;
+
+	/* Enable the following for a flash based bad block table */
+	cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
+
+	if (skipbbt) {
+		cafe->nand.options |= NAND_SKIP_BBTSCAN;
+		cafe->nand.block_bad = cafe_nand_block_bad;
+	}
+
+	if (numtimings && numtimings != 3) {
+		dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
+	}
+
+	if (numtimings == 3) {
+		cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
+			     timing[0], timing[1], timing[2]);
+	} else {
+		timing[0] = cafe_readl(cafe, NAND_TIMING1);
+		timing[1] = cafe_readl(cafe, NAND_TIMING2);
+		timing[2] = cafe_readl(cafe, NAND_TIMING3);
+
+		if (timing[0] | timing[1] | timing[2]) {
+			cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
+				     timing[0], timing[1], timing[2]);
+		} else {
+			dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
+			timing[0] = timing[1] = timing[2] = 0xffffffff;
+		}
+	}
+
+	/* Start off by resetting the NAND controller completely */
+	cafe_writel(cafe, 1, NAND_RESET);
+	cafe_writel(cafe, 0, NAND_RESET);
+
+	cafe_writel(cafe, timing[0], NAND_TIMING1);
+	cafe_writel(cafe, timing[1], NAND_TIMING2);
+	cafe_writel(cafe, timing[2], NAND_TIMING3);
+
+	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+	err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
+			  "CAFE NAND", mtd);
+	if (err) {
+		dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
+		goto out_ior;
+	}
+
+	/* Disable master reset, enable NAND clock */
+	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+	ctrl &= 0xffffeff0;
+	ctrl |= 0x00007000;
+	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+	cafe_writel(cafe, 0, NAND_DMA_CTRL);
+
+	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+	/* Enable NAND IRQ in global IRQ mask register */
+	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+	cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
+		cafe_readl(cafe, GLOBAL_CTRL),
+		cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+	/* Do not use the DMA for the nand_scan_ident() */
+	old_dma = usedma;
+	usedma = 0;
+
+	/* Scan to find existence of the device */
+	err = nand_scan_ident(mtd, 2, NULL);
+	if (err)
+		goto out_irq;
+
+	cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
+					  &cafe->dmaaddr, GFP_KERNEL);
+	if (!cafe->dmabuf) {
+		err = -ENOMEM;
+		goto out_irq;
+	}
+
+	/* Set up DMA address */
+	cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
+	cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
+
+	cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+		cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+
+	/* Restore the DMA flag */
+	usedma = old_dma;
+
+	cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
+	if (mtd->writesize == 2048)
+		cafe->ctl2 |= 1<<29; /* 2KiB page size */
+
+	/* Set up ECC according to the type of chip we found */
+	mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
+	if (mtd->writesize == 2048) {
+		cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+	} else if (mtd->writesize == 512) {
+		cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+		cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+	} else {
+		printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
+		       mtd->writesize);
+		goto out_free_dma;
+	}
+	cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+	cafe->nand.ecc.size = mtd->writesize;
+	cafe->nand.ecc.bytes = 14;
+	cafe->nand.ecc.strength = 4;
+	cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
+	cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
+	cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
+	cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+	cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+	cafe->nand.ecc.read_page = cafe_nand_read_page;
+	cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+
+	err = nand_scan_tail(mtd);
+	if (err)
+		goto out_free_dma;
+
+	pci_set_drvdata(pdev, mtd);
+
+	mtd->name = "cafe_nand";
+	mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+
+	goto out;
+
+ out_free_dma:
+	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+ out_irq:
+	/* Disable NAND IRQ in global IRQ mask register */
+	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+	free_irq(pdev->irq, mtd);
+ out_ior:
+	pci_iounmap(pdev, cafe->mmio);
+ out_free_mtd:
+	kfree(cafe);
+ out:
+	return err;
+}
+
+static void cafe_nand_remove(struct pci_dev *pdev)
+{
+	struct mtd_info *mtd = pci_get_drvdata(pdev);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+	/* Disable NAND IRQ in global IRQ mask register */
+	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+	free_irq(pdev->irq, mtd);
+	nand_release(mtd);
+	free_rs(cafe->rs);
+	pci_iounmap(pdev, cafe->mmio);
+	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+	kfree(cafe);
+}
+
+static const struct pci_device_id cafe_nand_tbl[] = {
+	{ PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
+
+static int cafe_nand_resume(struct pci_dev *pdev)
+{
+	uint32_t ctrl;
+	struct mtd_info *mtd = pci_get_drvdata(pdev);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+       /* Start off by resetting the NAND controller completely */
+	cafe_writel(cafe, 1, NAND_RESET);
+	cafe_writel(cafe, 0, NAND_RESET);
+	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+
+	/* Restore timing configuration */
+	cafe_writel(cafe, timing[0], NAND_TIMING1);
+	cafe_writel(cafe, timing[1], NAND_TIMING2);
+	cafe_writel(cafe, timing[2], NAND_TIMING3);
+
+        /* Disable master reset, enable NAND clock */
+	ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+	ctrl &= 0xffffeff0;
+	ctrl |= 0x00007000;
+	cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+	cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+	cafe_writel(cafe, 0, NAND_DMA_CTRL);
+	cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+	cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+	/* Set up DMA address */
+	cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+	if (sizeof(cafe->dmaaddr) > 4)
+	/* Shift in two parts to shut the compiler up */
+		cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+	else
+		cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+
+	/* Enable NAND IRQ in global IRQ mask register */
+	cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+	return 0;
+}
+
+static struct pci_driver cafe_nand_pci_driver = {
+	.name = "CAFÉ NAND",
+	.id_table = cafe_nand_tbl,
+	.probe = cafe_nand_probe,
+	.remove = cafe_nand_remove,
+	.resume = cafe_nand_resume,
+};
+
+module_pci_driver(cafe_nand_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
new file mode 100644
index 000000000000..02d6751e9efe
--- /dev/null
+++ b/drivers/mtd/nand/raw/cmx270_nand.c
@@ -0,0 +1,244 @@
+/*
+ *  Copyright (C) 2006 Compulab, Ltd.
+ *  Mike Rapoport <mike@compulab.co.il>
+ *
+ *  Derived from drivers/mtd/nand/h1910.c (removed in v3.10)
+ *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   CM-X270 board.
+ */
+
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/pxa2xx-regs.h>
+
+#define GPIO_NAND_CS	(11)
+#define GPIO_NAND_RB	(89)
+
+/* MTD structure for CM-X270 board */
+static struct mtd_info *cmx270_nand_mtd;
+
+/* remaped IO address of the device */
+static void __iomem *cmx270_nand_io;
+
+/*
+ * Define static partitions for flash device
+ */
+static const struct mtd_partition partition_info[] = {
+	[0] = {
+		.name	= "cmx270-0",
+		.offset	= 0,
+		.size	= MTDPART_SIZ_FULL
+	}
+};
+#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
+
+static u_char cmx270_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	return (readl(this->IO_ADDR_R) >> 16);
+}
+
+static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	for (i=0; i<len; i++)
+		writel((*buf++ << 16), this->IO_ADDR_W);
+}
+
+static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	for (i=0; i<len; i++)
+		*buf++ = readl(this->IO_ADDR_R) >> 16;
+}
+
+static inline void nand_cs_on(void)
+{
+	gpio_set_value(GPIO_NAND_CS, 0);
+}
+
+static void nand_cs_off(void)
+{
+	dsb();
+
+	gpio_set_value(GPIO_NAND_CS, 1);
+}
+
+/*
+ *	hardware specific access to control-lines
+ */
+static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
+			     unsigned int ctrl)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+
+	dsb();
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if ( ctrl & NAND_ALE )
+			nandaddr |=  (1 << 3);
+		else
+			nandaddr &= ~(1 << 3);
+		if ( ctrl & NAND_CLE )
+			nandaddr |=  (1 << 2);
+		else
+			nandaddr &= ~(1 << 2);
+		if ( ctrl & NAND_NCE )
+			nand_cs_on();
+		else
+			nand_cs_off();
+	}
+
+	dsb();
+	this->IO_ADDR_W = (void __iomem*)nandaddr;
+	if (dat != NAND_CMD_NONE)
+		writel((dat << 16), this->IO_ADDR_W);
+
+	dsb();
+}
+
+/*
+ *	read device ready pin
+ */
+static int cmx270_device_ready(struct mtd_info *mtd)
+{
+	dsb();
+
+	return (gpio_get_value(GPIO_NAND_RB));
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init cmx270_init(void)
+{
+	struct nand_chip *this;
+	int ret;
+
+	if (!(machine_is_armcore() && cpu_is_pxa27x()))
+		return -ENODEV;
+
+	ret = gpio_request(GPIO_NAND_CS, "NAND CS");
+	if (ret) {
+		pr_warn("CM-X270: failed to request NAND CS gpio\n");
+		return ret;
+	}
+
+	gpio_direction_output(GPIO_NAND_CS, 1);
+
+	ret = gpio_request(GPIO_NAND_RB, "NAND R/B");
+	if (ret) {
+		pr_warn("CM-X270: failed to request NAND R/B gpio\n");
+		goto err_gpio_request;
+	}
+
+	gpio_direction_input(GPIO_NAND_RB);
+
+	/* Allocate memory for MTD device structure and private data */
+	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+	if (!this) {
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
+
+	cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
+	if (!cmx270_nand_io) {
+		pr_debug("Unable to ioremap NAND device\n");
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+
+	cmx270_nand_mtd = nand_to_mtd(this);
+
+	/* Link the private data with the MTD structure */
+	cmx270_nand_mtd->owner = THIS_MODULE;
+
+	/* insert callbacks */
+	this->IO_ADDR_R = cmx270_nand_io;
+	this->IO_ADDR_W = cmx270_nand_io;
+	this->cmd_ctrl = cmx270_hwcontrol;
+	this->dev_ready = cmx270_device_ready;
+
+	/* 15 us command delay time */
+	this->chip_delay = 20;
+	this->ecc.mode = NAND_ECC_SOFT;
+	this->ecc.algo = NAND_ECC_HAMMING;
+
+	/* read/write functions */
+	this->read_byte = cmx270_read_byte;
+	this->read_buf = cmx270_read_buf;
+	this->write_buf = cmx270_write_buf;
+
+	/* Scan to find existence of the device */
+	ret = nand_scan(cmx270_nand_mtd, 1);
+	if (ret) {
+		pr_notice("No NAND device\n");
+		goto err_scan;
+	}
+
+	/* Register the partitions */
+	ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
+					partition_info, NUM_PARTITIONS);
+	if (ret)
+		goto err_scan;
+
+	/* Return happy */
+	return 0;
+
+err_scan:
+	iounmap(cmx270_nand_io);
+err_ioremap:
+	kfree(this);
+err_kzalloc:
+	gpio_free(GPIO_NAND_RB);
+err_gpio_request:
+	gpio_free(GPIO_NAND_CS);
+
+	return ret;
+
+}
+module_init(cmx270_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit cmx270_cleanup(void)
+{
+	/* Release resources, unregister device */
+	nand_release(cmx270_nand_mtd);
+
+	gpio_free(GPIO_NAND_RB);
+	gpio_free(GPIO_NAND_CS);
+
+	iounmap(cmx270_nand_io);
+
+	kfree(mtd_to_nand(cmx270_nand_mtd));
+}
+module_exit(cmx270_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
new file mode 100644
index 000000000000..be1f28fc7363
--- /dev/null
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -0,0 +1,355 @@
+/*
+ * (C) 2005, 2006 Red Hat Inc.
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ *	   Tom Sylla <tom.sylla@amd.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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash controller found on
+ *   the AMD CS5535/CS5536 companion chipsets for the Geode processor.
+ *   mtd-id for command line partitioning is cs553x_nand_cs[0-3]
+ *   where 0-3 reflects the chip select for NAND.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/msr.h>
+#include <asm/io.h>
+
+#define NR_CS553X_CONTROLLERS	4
+
+#define MSR_DIVIL_GLD_CAP	0x51400000	/* DIVIL capabilitiies */
+#define CAP_CS5535		0x2df000ULL
+#define CAP_CS5536		0x5df500ULL
+
+/* NAND Timing MSRs */
+#define MSR_NANDF_DATA		0x5140001b	/* NAND Flash Data Timing MSR */
+#define MSR_NANDF_CTL		0x5140001c	/* NAND Flash Control Timing */
+#define MSR_NANDF_RSVD		0x5140001d	/* Reserved */
+
+/* NAND BAR MSRs */
+#define MSR_DIVIL_LBAR_FLSH0	0x51400010	/* Flash Chip Select 0 */
+#define MSR_DIVIL_LBAR_FLSH1	0x51400011	/* Flash Chip Select 1 */
+#define MSR_DIVIL_LBAR_FLSH2	0x51400012	/* Flash Chip Select 2 */
+#define MSR_DIVIL_LBAR_FLSH3	0x51400013	/* Flash Chip Select 3 */
+	/* Each made up of... */
+#define FLSH_LBAR_EN		(1ULL<<32)
+#define FLSH_NOR_NAND		(1ULL<<33)	/* 1 for NAND */
+#define FLSH_MEM_IO		(1ULL<<34)	/* 1 for MMIO */
+	/* I/O BARs have BASE_ADDR in bits 15:4, IO_MASK in 47:36 */
+	/* MMIO BARs have BASE_ADDR in bits 31:12, MEM_MASK in 63:44 */
+
+/* Pin function selection MSR (IDE vs. flash on the IDE pins) */
+#define MSR_DIVIL_BALL_OPTS	0x51400015
+#define PIN_OPT_IDE		(1<<0)	/* 0 for flash, 1 for IDE */
+
+/* Registers within the NAND flash controller BAR -- memory mapped */
+#define MM_NAND_DATA		0x00	/* 0 to 0x7ff, in fact */
+#define MM_NAND_CTL		0x800	/* Any even address 0x800-0x80e */
+#define MM_NAND_IO		0x801	/* Any odd address 0x801-0x80f */
+#define MM_NAND_STS		0x810
+#define MM_NAND_ECC_LSB		0x811
+#define MM_NAND_ECC_MSB		0x812
+#define MM_NAND_ECC_COL		0x813
+#define MM_NAND_LAC		0x814
+#define MM_NAND_ECC_CTL		0x815
+
+/* Registers within the NAND flash controller BAR -- I/O mapped */
+#define IO_NAND_DATA		0x00	/* 0 to 3, in fact */
+#define IO_NAND_CTL		0x04
+#define IO_NAND_IO		0x05
+#define IO_NAND_STS		0x06
+#define IO_NAND_ECC_CTL		0x08
+#define IO_NAND_ECC_LSB		0x09
+#define IO_NAND_ECC_MSB		0x0a
+#define IO_NAND_ECC_COL		0x0b
+#define IO_NAND_LAC		0x0c
+
+#define CS_NAND_CTL_DIST_EN	(1<<4)	/* Enable NAND Distract interrupt */
+#define CS_NAND_CTL_RDY_INT_MASK	(1<<3)	/* Enable RDY/BUSY# interrupt */
+#define CS_NAND_CTL_ALE		(1<<2)
+#define CS_NAND_CTL_CLE		(1<<1)
+#define CS_NAND_CTL_CE		(1<<0)	/* Keep low; 1 to reset */
+
+#define CS_NAND_STS_FLASH_RDY	(1<<3)
+#define CS_NAND_CTLR_BUSY	(1<<2)
+#define CS_NAND_CMD_COMP	(1<<1)
+#define CS_NAND_DIST_ST		(1<<0)
+
+#define CS_NAND_ECC_PARITY	(1<<2)
+#define CS_NAND_ECC_CLRECC	(1<<1)
+#define CS_NAND_ECC_ENECC	(1<<0)
+
+static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	while (unlikely(len > 0x800)) {
+		memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
+		buf += 0x800;
+		len -= 0x800;
+	}
+	memcpy_fromio(buf, this->IO_ADDR_R, len);
+}
+
+static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	while (unlikely(len > 0x800)) {
+		memcpy_toio(this->IO_ADDR_R, buf, 0x800);
+		buf += 0x800;
+		len -= 0x800;
+	}
+	memcpy_toio(this->IO_ADDR_R, buf, len);
+}
+
+static unsigned char cs553x_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	return readb(this->IO_ADDR_R);
+}
+
+static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int i = 100000;
+
+	while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
+		udelay(1);
+		i--;
+	}
+	writeb(byte, this->IO_ADDR_W + 0x801);
+}
+
+static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+			     unsigned int ctrl)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	void __iomem *mmio_base = this->IO_ADDR_R;
+	if (ctrl & NAND_CTRL_CHANGE) {
+		unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
+		writeb(ctl, mmio_base + MM_NAND_CTL);
+	}
+	if (cmd != NAND_CMD_NONE)
+		cs553x_write_byte(mtd, cmd);
+}
+
+static int cs553x_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	void __iomem *mmio_base = this->IO_ADDR_R;
+	unsigned char foo = readb(mmio_base + MM_NAND_STS);
+
+	return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
+}
+
+static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	void __iomem *mmio_base = this->IO_ADDR_R;
+
+	writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
+}
+
+static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+	uint32_t ecc;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	void __iomem *mmio_base = this->IO_ADDR_R;
+
+	ecc = readl(mmio_base + MM_NAND_STS);
+
+	ecc_code[1] = ecc >> 8;
+	ecc_code[0] = ecc >> 16;
+	ecc_code[2] = ecc >> 24;
+	return 0;
+}
+
+static struct mtd_info *cs553x_mtd[4];
+
+static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
+{
+	int err = 0;
+	struct nand_chip *this;
+	struct mtd_info *new_mtd;
+
+	printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr);
+
+	if (!mmio) {
+		printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n");
+		return -ENXIO;
+	}
+
+	/* Allocate memory for MTD device structure and private data */
+	this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+	if (!this) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	new_mtd = nand_to_mtd(this);
+
+	/* Link the private data with the MTD structure */
+	new_mtd->owner = THIS_MODULE;
+
+	/* map physical address */
+	this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
+	if (!this->IO_ADDR_R) {
+		printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr);
+		err = -EIO;
+		goto out_mtd;
+	}
+
+	this->cmd_ctrl = cs553x_hwcontrol;
+	this->dev_ready = cs553x_device_ready;
+	this->read_byte = cs553x_read_byte;
+	this->read_buf = cs553x_read_buf;
+	this->write_buf = cs553x_write_buf;
+
+	this->chip_delay = 0;
+
+	this->ecc.mode = NAND_ECC_HW;
+	this->ecc.size = 256;
+	this->ecc.bytes = 3;
+	this->ecc.hwctl  = cs_enable_hwecc;
+	this->ecc.calculate = cs_calculate_ecc;
+	this->ecc.correct  = nand_correct_data;
+	this->ecc.strength = 1;
+
+	/* Enable the following for a flash based bad block table */
+	this->bbt_options = NAND_BBT_USE_FLASH;
+
+	new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
+	if (!new_mtd->name) {
+		err = -ENOMEM;
+		goto out_ior;
+	}
+
+	/* Scan to find existence of the device */
+	err = nand_scan(new_mtd, 1);
+	if (err)
+		goto out_free;
+
+	cs553x_mtd[cs] = new_mtd;
+	goto out;
+
+out_free:
+	kfree(new_mtd->name);
+out_ior:
+	iounmap(this->IO_ADDR_R);
+out_mtd:
+	kfree(this);
+out:
+	return err;
+}
+
+static int is_geode(void)
+{
+	/* These are the CPUs which will have a CS553[56] companion chip */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+	    boot_cpu_data.x86 == 5 &&
+	    boot_cpu_data.x86_model == 10)
+		return 1; /* Geode LX */
+
+	if ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC ||
+	     boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) &&
+	    boot_cpu_data.x86 == 5 &&
+	    boot_cpu_data.x86_model == 5)
+		return 1; /* Geode GX (née GX2) */
+
+	return 0;
+}
+
+static int __init cs553x_init(void)
+{
+	int err = -ENXIO;
+	int i;
+	uint64_t val;
+
+	/* If the CPU isn't a Geode GX or LX, abort */
+	if (!is_geode())
+		return -ENXIO;
+
+	/* If it doesn't have the CS553[56], abort */
+	rdmsrl(MSR_DIVIL_GLD_CAP, val);
+	val &= ~0xFFULL;
+	if (val != CAP_CS5535 && val != CAP_CS5536)
+		return -ENXIO;
+
+	/* If it doesn't have the NAND controller enabled, abort */
+	rdmsrl(MSR_DIVIL_BALL_OPTS, val);
+	if (val & PIN_OPT_IDE) {
+		printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
+		return -ENXIO;
+	}
+
+	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+		rdmsrl(MSR_DIVIL_LBAR_FLSH0 + i, val);
+
+		if ((val & (FLSH_LBAR_EN|FLSH_NOR_NAND)) == (FLSH_LBAR_EN|FLSH_NOR_NAND))
+			err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
+	}
+
+	/* Register all devices together here. This means we can easily hack it to
+	   do mtdconcat etc. if we want to. */
+	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+		if (cs553x_mtd[i]) {
+			/* If any devices registered, return success. Else the last error. */
+			mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
+						  NULL, 0);
+			err = 0;
+		}
+	}
+
+	return err;
+}
+
+module_init(cs553x_init);
+
+static void __exit cs553x_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
+		struct mtd_info *mtd = cs553x_mtd[i];
+		struct nand_chip *this;
+		void __iomem *mmio_base;
+
+		if (!mtd)
+			continue;
+
+		this = mtd_to_nand(mtd);
+		mmio_base = this->IO_ADDR_R;
+
+		/* Release resources, unregister device */
+		nand_release(mtd);
+		kfree(mtd->name);
+		cs553x_mtd[i] = NULL;
+
+		/* unmap physical address */
+		iounmap(mmio_base);
+
+		/* Free the MTD device structure */
+		kfree(this);
+	}
+}
+
+module_exit(cs553x_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("NAND controller driver for AMD CS5535/CS5536 companion chip");
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
new file mode 100644
index 000000000000..ccc8c43abcff
--- /dev/null
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -0,0 +1,879 @@
+/*
+ * davinci_nand.c - NAND Flash Driver for DaVinci family chips
+ *
+ * Copyright © 2006 Texas Instruments.
+ *
+ * Port to 2.6.23 Copyright © 2008 by:
+ *   Sander Huijsen <Shuijsen@optelecom-nkf.com>
+ *   Troy Kisky <troy.kisky@boundarydevices.com>
+ *   Dirk Behme <Dirk.Behme@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+
+#include <linux/platform_data/mtd-davinci.h>
+#include <linux/platform_data/mtd-davinci-aemif.h>
+
+/*
+ * This is a device driver for the NAND flash controller found on the
+ * various DaVinci family chips.  It handles up to four SoC chipselects,
+ * and some flavors of secondary chipselect (e.g. based on A12) as used
+ * with multichip packages.
+ *
+ * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC
+ * available on chips like the DM355 and OMAP-L137 and needed with the
+ * more error-prone MLC NAND chips.
+ *
+ * This driver assumes EM_WAIT connects all the NAND devices' RDY/nBUSY
+ * outputs in a "wire-AND" configuration, with no per-chip signals.
+ */
+struct davinci_nand_info {
+	struct nand_chip	chip;
+
+	struct device		*dev;
+	struct clk		*clk;
+
+	bool			is_readmode;
+
+	void __iomem		*base;
+	void __iomem		*vaddr;
+
+	uint32_t		ioaddr;
+	uint32_t		current_cs;
+
+	uint32_t		mask_chipsel;
+	uint32_t		mask_ale;
+	uint32_t		mask_cle;
+
+	uint32_t		core_chipsel;
+
+	struct davinci_aemif_timing	*timing;
+};
+
+static DEFINE_SPINLOCK(davinci_nand_lock);
+static bool ecc4_busy;
+
+static inline struct davinci_nand_info *to_davinci_nand(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct davinci_nand_info, chip);
+}
+
+static inline unsigned int davinci_nand_readl(struct davinci_nand_info *info,
+		int offset)
+{
+	return __raw_readl(info->base + offset);
+}
+
+static inline void davinci_nand_writel(struct davinci_nand_info *info,
+		int offset, unsigned long value)
+{
+	__raw_writel(value, info->base + offset);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Access to hardware control lines:  ALE, CLE, secondary chipselect.
+ */
+
+static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	struct davinci_nand_info	*info = to_davinci_nand(mtd);
+	uint32_t			addr = info->current_cs;
+	struct nand_chip		*nand = mtd_to_nand(mtd);
+
+	/* Did the control lines change? */
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE)
+			addr |= info->mask_cle;
+		else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
+			addr |= info->mask_ale;
+
+		nand->IO_ADDR_W = (void __iomem __force *)addr;
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		iowrite8(cmd, nand->IO_ADDR_W);
+}
+
+static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct davinci_nand_info	*info = to_davinci_nand(mtd);
+	uint32_t			addr = info->ioaddr;
+
+	/* maybe kick in a second chipselect */
+	if (chip > 0)
+		addr |= info->mask_chipsel;
+	info->current_cs = addr;
+
+	info->chip.IO_ADDR_W = (void __iomem __force *)addr;
+	info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * 1-bit hardware ECC ... context maintained for each core chipselect
+ */
+
+static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
+{
+	struct davinci_nand_info *info = to_davinci_nand(mtd);
+
+	return davinci_nand_readl(info, NANDF1ECC_OFFSET
+			+ 4 * info->core_chipsel);
+}
+
+static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
+{
+	struct davinci_nand_info *info;
+	uint32_t nandcfr;
+	unsigned long flags;
+
+	info = to_davinci_nand(mtd);
+
+	/* Reset ECC hardware */
+	nand_davinci_readecc_1bit(mtd);
+
+	spin_lock_irqsave(&davinci_nand_lock, flags);
+
+	/* Restart ECC hardware */
+	nandcfr = davinci_nand_readl(info, NANDFCR_OFFSET);
+	nandcfr |= BIT(8 + info->core_chipsel);
+	davinci_nand_writel(info, NANDFCR_OFFSET, nandcfr);
+
+	spin_unlock_irqrestore(&davinci_nand_lock, flags);
+}
+
+/*
+ * Read hardware ECC value and pack into three bytes
+ */
+static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
+				      const u_char *dat, u_char *ecc_code)
+{
+	unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
+	unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
+
+	/* invert so that erased block ecc is correct */
+	ecc24 = ~ecc24;
+	ecc_code[0] = (u_char)(ecc24);
+	ecc_code[1] = (u_char)(ecc24 >> 8);
+	ecc_code[2] = (u_char)(ecc24 >> 16);
+
+	return 0;
+}
+
+static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
+				     u_char *read_ecc, u_char *calc_ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
+					  (read_ecc[2] << 16);
+	uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
+					  (calc_ecc[2] << 16);
+	uint32_t diff = eccCalc ^ eccNand;
+
+	if (diff) {
+		if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) {
+			/* Correctable error */
+			if ((diff >> (12 + 3)) < chip->ecc.size) {
+				dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7);
+				return 1;
+			} else {
+				return -EBADMSG;
+			}
+		} else if (!(diff & (diff - 1))) {
+			/* Single bit ECC error in the ECC itself,
+			 * nothing to fix */
+			return 1;
+		} else {
+			/* Uncorrectable error */
+			return -EBADMSG;
+		}
+
+	}
+	return 0;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * 4-bit hardware ECC ... context maintained over entire AEMIF
+ *
+ * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME
+ * since that forces use of a problematic "infix OOB" layout.
+ * Among other things, it trashes manufacturer bad block markers.
+ * Also, and specific to this hardware, it ECC-protects the "prepad"
+ * in the OOB ... while having ECC protection for parts of OOB would
+ * seem useful, the current MTD stack sometimes wants to update the
+ * OOB without recomputing ECC.
+ */
+
+static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
+{
+	struct davinci_nand_info *info = to_davinci_nand(mtd);
+	unsigned long flags;
+	u32 val;
+
+	/* Reset ECC hardware */
+	davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+
+	spin_lock_irqsave(&davinci_nand_lock, flags);
+
+	/* Start 4-bit ECC calculation for read/write */
+	val = davinci_nand_readl(info, NANDFCR_OFFSET);
+	val &= ~(0x03 << 4);
+	val |= (info->core_chipsel << 4) | BIT(12);
+	davinci_nand_writel(info, NANDFCR_OFFSET, val);
+
+	info->is_readmode = (mode == NAND_ECC_READ);
+
+	spin_unlock_irqrestore(&davinci_nand_lock, flags);
+}
+
+/* Read raw ECC code after writing to NAND. */
+static void
+nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
+{
+	const u32 mask = 0x03ff03ff;
+
+	code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask;
+	code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask;
+	code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask;
+	code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask;
+}
+
+/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
+static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
+		const u_char *dat, u_char *ecc_code)
+{
+	struct davinci_nand_info *info = to_davinci_nand(mtd);
+	u32 raw_ecc[4], *p;
+	unsigned i;
+
+	/* After a read, terminate ECC calculation by a dummy read
+	 * of some 4-bit ECC register.  ECC covers everything that
+	 * was read; correct() just uses the hardware state, so
+	 * ecc_code is not needed.
+	 */
+	if (info->is_readmode) {
+		davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+		return 0;
+	}
+
+	/* Pack eight raw 10-bit ecc values into ten bytes, making
+	 * two passes which each convert four values (in upper and
+	 * lower halves of two 32-bit words) into five bytes.  The
+	 * ROM boot loader uses this same packing scheme.
+	 */
+	nand_davinci_readecc_4bit(info, raw_ecc);
+	for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
+		*ecc_code++ =   p[0]        & 0xff;
+		*ecc_code++ = ((p[0] >>  8) & 0x03) | ((p[0] >> 14) & 0xfc);
+		*ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] <<  4) & 0xf0);
+		*ecc_code++ = ((p[1] >>  4) & 0x3f) | ((p[1] >> 10) & 0xc0);
+		*ecc_code++ =  (p[1] >> 18) & 0xff;
+	}
+
+	return 0;
+}
+
+/* Correct up to 4 bits in data we just read, using state left in the
+ * hardware plus the ecc_code computed when it was first written.
+ */
+static int nand_davinci_correct_4bit(struct mtd_info *mtd,
+		u_char *data, u_char *ecc_code, u_char *null)
+{
+	int i;
+	struct davinci_nand_info *info = to_davinci_nand(mtd);
+	unsigned short ecc10[8];
+	unsigned short *ecc16;
+	u32 syndrome[4];
+	u32 ecc_state;
+	unsigned num_errors, corrected;
+	unsigned long timeo;
+
+	/* Unpack ten bytes into eight 10 bit values.  We know we're
+	 * little-endian, and use type punning for less shifting/masking.
+	 */
+	if (WARN_ON(0x01 & (unsigned) ecc_code))
+		return -EINVAL;
+	ecc16 = (unsigned short *)ecc_code;
+
+	ecc10[0] =  (ecc16[0] >>  0) & 0x3ff;
+	ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0);
+	ecc10[2] =  (ecc16[1] >>  4) & 0x3ff;
+	ecc10[3] = ((ecc16[1] >> 14) & 0x3)  | ((ecc16[2] << 2) & 0x3fc);
+	ecc10[4] =  (ecc16[2] >>  8)         | ((ecc16[3] << 8) & 0x300);
+	ecc10[5] =  (ecc16[3] >>  2) & 0x3ff;
+	ecc10[6] = ((ecc16[3] >> 12) & 0xf)  | ((ecc16[4] << 4) & 0x3f0);
+	ecc10[7] =  (ecc16[4] >>  6) & 0x3ff;
+
+	/* Tell ECC controller about the expected ECC codes. */
+	for (i = 7; i >= 0; i--)
+		davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]);
+
+	/* Allow time for syndrome calculation ... then read it.
+	 * A syndrome of all zeroes 0 means no detected errors.
+	 */
+	davinci_nand_readl(info, NANDFSR_OFFSET);
+	nand_davinci_readecc_4bit(info, syndrome);
+	if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
+		return 0;
+
+	/*
+	 * Clear any previous address calculation by doing a dummy read of an
+	 * error address register.
+	 */
+	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
+
+	/* Start address calculation, and wait for it to complete.
+	 * We _could_ start reading more data while this is working,
+	 * to speed up the overall page read.
+	 */
+	davinci_nand_writel(info, NANDFCR_OFFSET,
+			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
+
+	/*
+	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
+	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
+	 * begin trying to poll for the state, you may fall right out of your
+	 * loop without any of the correction calculations having taken place.
+	 * The recommendation from the hardware team is to initially delay as
+	 * long as ECC_STATE reads less than 4. After that, ECC HW has entered
+	 * correction state.
+	 */
+	timeo = jiffies + usecs_to_jiffies(100);
+	do {
+		ecc_state = (davinci_nand_readl(info,
+				NANDFSR_OFFSET) >> 8) & 0x0f;
+		cpu_relax();
+	} while ((ecc_state < 4) && time_before(jiffies, timeo));
+
+	for (;;) {
+		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
+
+		switch ((fsr >> 8) & 0x0f) {
+		case 0:		/* no error, should not happen */
+			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
+			return 0;
+		case 1:		/* five or more errors detected */
+			davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
+			return -EBADMSG;
+		case 2:		/* error addresses computed */
+		case 3:
+			num_errors = 1 + ((fsr >> 16) & 0x03);
+			goto correct;
+		default:	/* still working on it */
+			cpu_relax();
+			continue;
+		}
+	}
+
+correct:
+	/* correct each error */
+	for (i = 0, corrected = 0; i < num_errors; i++) {
+		int error_address, error_value;
+
+		if (i > 1) {
+			error_address = davinci_nand_readl(info,
+						NAND_ERR_ADD2_OFFSET);
+			error_value = davinci_nand_readl(info,
+						NAND_ERR_ERRVAL2_OFFSET);
+		} else {
+			error_address = davinci_nand_readl(info,
+						NAND_ERR_ADD1_OFFSET);
+			error_value = davinci_nand_readl(info,
+						NAND_ERR_ERRVAL1_OFFSET);
+		}
+
+		if (i & 1) {
+			error_address >>= 16;
+			error_value >>= 16;
+		}
+		error_address &= 0x3ff;
+		error_address = (512 + 7) - error_address;
+
+		if (error_address < 512) {
+			data[error_address] ^= error_value;
+			corrected++;
+		}
+	}
+
+	return corrected;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * NOTE:  NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's
+ * how these chips are normally wired.  This translates to both 8 and 16
+ * bit busses using ALE == BIT(3) in byte addresses, and CLE == BIT(4).
+ *
+ * For now we assume that configuration, or any other one which ignores
+ * the two LSBs for NAND access ... so we can issue 32-bit reads/writes
+ * and have that transparently morphed into multiple NAND operations.
+ */
+static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
+		ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
+	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
+		ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
+	else
+		ioread8_rep(chip->IO_ADDR_R, buf, len);
+}
+
+static void nand_davinci_write_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
+		iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
+	else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
+		iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
+	else
+		iowrite8_rep(chip->IO_ADDR_R, buf, len);
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int nand_davinci_dev_ready(struct mtd_info *mtd)
+{
+	struct davinci_nand_info *info = to_davinci_nand(mtd);
+
+	return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* An ECC layout for using 4-bit ECC with small-page flash, storing
+ * ten ECC bytes plus the manufacturer's bad block marker byte, and
+ * and not overlapping the default BBT markers.
+ */
+static int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	if (section > 2)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 5;
+	} else if (section == 1) {
+		oobregion->offset = 6;
+		oobregion->length = 2;
+	} else {
+		oobregion->offset = 13;
+		oobregion->length = 3;
+	}
+
+	return 0;
+}
+
+static int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 8;
+		oobregion->length = 5;
+	} else {
+		oobregion->offset = 16;
+		oobregion->length = mtd->oobsize - 16;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
+	.ecc = hwecc4_ooblayout_small_ecc,
+	.free = hwecc4_ooblayout_small_free,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id davinci_nand_of_match[] = {
+	{.compatible = "ti,davinci-nand", },
+	{.compatible = "ti,keystone-nand", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
+
+static struct davinci_nand_pdata
+	*nand_davinci_get_pdata(struct platform_device *pdev)
+{
+	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
+		struct davinci_nand_pdata *pdata;
+		const char *mode;
+		u32 prop;
+
+		pdata =  devm_kzalloc(&pdev->dev,
+				sizeof(struct davinci_nand_pdata),
+				GFP_KERNEL);
+		pdev->dev.platform_data = pdata;
+		if (!pdata)
+			return ERR_PTR(-ENOMEM);
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-chipselect", &prop))
+			pdev->id = prop;
+		else
+			return ERR_PTR(-EINVAL);
+
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-mask-ale", &prop))
+			pdata->mask_ale = prop;
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-mask-cle", &prop))
+			pdata->mask_cle = prop;
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-mask-chipsel", &prop))
+			pdata->mask_chipsel = prop;
+		if (!of_property_read_string(pdev->dev.of_node,
+			"ti,davinci-ecc-mode", &mode)) {
+			if (!strncmp("none", mode, 4))
+				pdata->ecc_mode = NAND_ECC_NONE;
+			if (!strncmp("soft", mode, 4))
+				pdata->ecc_mode = NAND_ECC_SOFT;
+			if (!strncmp("hw", mode, 2))
+				pdata->ecc_mode = NAND_ECC_HW;
+		}
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-ecc-bits", &prop))
+			pdata->ecc_bits = prop;
+
+		if (!of_property_read_u32(pdev->dev.of_node,
+			"ti,davinci-nand-buswidth", &prop) && prop == 16)
+			pdata->options |= NAND_BUSWIDTH_16;
+
+		if (of_property_read_bool(pdev->dev.of_node,
+			"ti,davinci-nand-use-bbt"))
+			pdata->bbt_options = NAND_BBT_USE_FLASH;
+
+		/*
+		 * Since kernel v4.8, this driver has been fixed to enable
+		 * use of 4-bit hardware ECC with subpages and verified on
+		 * TI's keystone EVMs (K2L, K2HK and K2E).
+		 * However, in the interest of not breaking systems using
+		 * existing UBI partitions, sub-page writes are not being
+		 * (re)enabled. If you want to use subpage writes on Keystone
+		 * platforms (i.e. do not have any existing UBI partitions),
+		 * then use "ti,davinci-nand" as the compatible in your
+		 * device-tree file.
+		 */
+		if (of_device_is_compatible(pdev->dev.of_node,
+					    "ti,keystone-nand")) {
+			pdata->options |= NAND_NO_SUBPAGE_WRITE;
+		}
+	}
+
+	return dev_get_platdata(&pdev->dev);
+}
+#else
+static struct davinci_nand_pdata
+	*nand_davinci_get_pdata(struct platform_device *pdev)
+{
+	return dev_get_platdata(&pdev->dev);
+}
+#endif
+
+static int nand_davinci_probe(struct platform_device *pdev)
+{
+	struct davinci_nand_pdata	*pdata;
+	struct davinci_nand_info	*info;
+	struct resource			*res1;
+	struct resource			*res2;
+	void __iomem			*vaddr;
+	void __iomem			*base;
+	int				ret;
+	uint32_t			val;
+	struct mtd_info			*mtd;
+
+	pdata = nand_davinci_get_pdata(pdev);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+
+	/* insist on board-specific configuration */
+	if (!pdata)
+		return -ENODEV;
+
+	/* which external chipselect will we be managing? */
+	if (pdev->id < 0 || pdev->id > 3)
+		return -ENODEV;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, info);
+
+	res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res1 || !res2) {
+		dev_err(&pdev->dev, "resource missing\n");
+		return -EINVAL;
+	}
+
+	vaddr = devm_ioremap_resource(&pdev->dev, res1);
+	if (IS_ERR(vaddr))
+		return PTR_ERR(vaddr);
+
+	/*
+	 * This registers range is used to setup NAND settings. In case with
+	 * TI AEMIF driver, the same memory address range is requested already
+	 * by AEMIF, so we cannot request it twice, just ioremap.
+	 * The AEMIF and NAND drivers not use the same registers in this range.
+	 */
+	base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
+	if (!base) {
+		dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
+		return -EADDRNOTAVAIL;
+	}
+
+	info->dev		= &pdev->dev;
+	info->base		= base;
+	info->vaddr		= vaddr;
+
+	mtd			= nand_to_mtd(&info->chip);
+	mtd->dev.parent		= &pdev->dev;
+	nand_set_flash_node(&info->chip, pdev->dev.of_node);
+
+	info->chip.IO_ADDR_R	= vaddr;
+	info->chip.IO_ADDR_W	= vaddr;
+	info->chip.chip_delay	= 0;
+	info->chip.select_chip	= nand_davinci_select_chip;
+
+	/* options such as NAND_BBT_USE_FLASH */
+	info->chip.bbt_options	= pdata->bbt_options;
+	/* options such as 16-bit widths */
+	info->chip.options	= pdata->options;
+	info->chip.bbt_td	= pdata->bbt_td;
+	info->chip.bbt_md	= pdata->bbt_md;
+	info->timing		= pdata->timing;
+
+	info->ioaddr		= (uint32_t __force) vaddr;
+
+	info->current_cs	= info->ioaddr;
+	info->core_chipsel	= pdev->id;
+	info->mask_chipsel	= pdata->mask_chipsel;
+
+	/* use nandboot-capable ALE/CLE masks by default */
+	info->mask_ale		= pdata->mask_ale ? : MASK_ALE;
+	info->mask_cle		= pdata->mask_cle ? : MASK_CLE;
+
+	/* Set address of hardware control function */
+	info->chip.cmd_ctrl	= nand_davinci_hwcontrol;
+	info->chip.dev_ready	= nand_davinci_dev_ready;
+
+	/* Speed up buffer I/O */
+	info->chip.read_buf     = nand_davinci_read_buf;
+	info->chip.write_buf    = nand_davinci_write_buf;
+
+	/* Use board-specific ECC config */
+	info->chip.ecc.mode	= pdata->ecc_mode;
+
+	ret = -EINVAL;
+
+	info->clk = devm_clk_get(&pdev->dev, "aemif");
+	if (IS_ERR(info->clk)) {
+		ret = PTR_ERR(info->clk);
+		dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(info->clk);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
+			ret);
+		goto err_clk_enable;
+	}
+
+	spin_lock_irq(&davinci_nand_lock);
+
+	/* put CSxNAND into NAND mode */
+	val = davinci_nand_readl(info, NANDFCR_OFFSET);
+	val |= BIT(info->core_chipsel);
+	davinci_nand_writel(info, NANDFCR_OFFSET, val);
+
+	spin_unlock_irq(&davinci_nand_lock);
+
+	/* Scan to find existence of the device(s) */
+	ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
+	if (ret < 0) {
+		dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
+		goto err;
+	}
+
+	switch (info->chip.ecc.mode) {
+	case NAND_ECC_NONE:
+		pdata->ecc_bits = 0;
+		break;
+	case NAND_ECC_SOFT:
+		pdata->ecc_bits = 0;
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ->ecc_algo field to
+		 * davinci_nand_pdata.
+		 */
+		info->chip.ecc.algo = NAND_ECC_HAMMING;
+		break;
+	case NAND_ECC_HW:
+		if (pdata->ecc_bits == 4) {
+			/* No sanity checks:  CPUs must support this,
+			 * and the chips may not use NAND_BUSWIDTH_16.
+			 */
+
+			/* No sharing 4-bit hardware between chipselects yet */
+			spin_lock_irq(&davinci_nand_lock);
+			if (ecc4_busy)
+				ret = -EBUSY;
+			else
+				ecc4_busy = true;
+			spin_unlock_irq(&davinci_nand_lock);
+
+			if (ret == -EBUSY)
+				return ret;
+
+			info->chip.ecc.calculate = nand_davinci_calculate_4bit;
+			info->chip.ecc.correct = nand_davinci_correct_4bit;
+			info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
+			info->chip.ecc.bytes = 10;
+			info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+			info->chip.ecc.algo = NAND_ECC_BCH;
+		} else {
+			/* 1bit ecc hamming */
+			info->chip.ecc.calculate = nand_davinci_calculate_1bit;
+			info->chip.ecc.correct = nand_davinci_correct_1bit;
+			info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
+			info->chip.ecc.bytes = 3;
+			info->chip.ecc.algo = NAND_ECC_HAMMING;
+		}
+		info->chip.ecc.size = 512;
+		info->chip.ecc.strength = pdata->ecc_bits;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Update ECC layout if needed ... for 1-bit HW ECC, the default
+	 * is OK, but it allocates 6 bytes when only 3 are needed (for
+	 * each 512 bytes).  For the 4-bit HW ECC, that default is not
+	 * usable:  10 bytes are needed, not 6.
+	 */
+	if (pdata->ecc_bits == 4) {
+		int	chunks = mtd->writesize / 512;
+
+		if (!chunks || mtd->oobsize < 16) {
+			dev_dbg(&pdev->dev, "too small\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		/* For small page chips, preserve the manufacturer's
+		 * badblock marking data ... and make sure a flash BBT
+		 * table marker fits in the free bytes.
+		 */
+		if (chunks == 1) {
+			mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
+		} else if (chunks == 4 || chunks == 8) {
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+			info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
+		} else {
+			ret = -EIO;
+			goto err;
+		}
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret < 0)
+		goto err;
+
+	if (pdata->parts)
+		ret = mtd_device_parse_register(mtd, NULL, NULL,
+					pdata->parts, pdata->nr_parts);
+	else
+		ret = mtd_device_register(mtd, NULL, 0);
+	if (ret < 0)
+		goto err;
+
+	val = davinci_nand_readl(info, NRCSR_OFFSET);
+	dev_info(&pdev->dev, "controller rev. %d.%d\n",
+	       (val >> 8) & 0xff, val & 0xff);
+
+	return 0;
+
+err:
+	clk_disable_unprepare(info->clk);
+
+err_clk_enable:
+	spin_lock_irq(&davinci_nand_lock);
+	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
+		ecc4_busy = false;
+	spin_unlock_irq(&davinci_nand_lock);
+	return ret;
+}
+
+static int nand_davinci_remove(struct platform_device *pdev)
+{
+	struct davinci_nand_info *info = platform_get_drvdata(pdev);
+
+	spin_lock_irq(&davinci_nand_lock);
+	if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
+		ecc4_busy = false;
+	spin_unlock_irq(&davinci_nand_lock);
+
+	nand_release(nand_to_mtd(&info->chip));
+
+	clk_disable_unprepare(info->clk);
+
+	return 0;
+}
+
+static struct platform_driver nand_davinci_driver = {
+	.probe		= nand_davinci_probe,
+	.remove		= nand_davinci_remove,
+	.driver		= {
+		.name	= "davinci_nand",
+		.of_match_table = of_match_ptr(davinci_nand_of_match),
+	},
+};
+MODULE_ALIAS("platform:davinci_nand");
+
+module_platform_driver(nand_davinci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Davinci NAND flash driver");
+
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
new file mode 100644
index 000000000000..313c7f50621b
--- /dev/null
+++ b/drivers/mtd/nand/raw/denali.c
@@ -0,0 +1,1408 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright © 2009-2010, Intel Corporation and its suppliers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "denali.h"
+
+MODULE_LICENSE("GPL");
+
+#define DENALI_NAND_NAME    "denali-nand"
+
+/* for Indexed Addressing */
+#define DENALI_INDEXED_CTRL	0x00
+#define DENALI_INDEXED_DATA	0x10
+
+#define DENALI_MAP00		(0 << 26)	/* direct access to buffer */
+#define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
+#define DENALI_MAP10		(2 << 26)	/* high-level control plane */
+#define DENALI_MAP11		(3 << 26)	/* direct controller access */
+
+/* MAP11 access cycle type */
+#define DENALI_MAP11_CMD	((DENALI_MAP11) | 0)	/* command cycle */
+#define DENALI_MAP11_ADDR	((DENALI_MAP11) | 1)	/* address cycle */
+#define DENALI_MAP11_DATA	((DENALI_MAP11) | 2)	/* data cycle */
+
+/* MAP10 commands */
+#define DENALI_ERASE		0x01
+
+#define DENALI_BANK(denali)	((denali)->active_bank << 24)
+
+#define DENALI_INVALID_BANK	-1
+#define DENALI_NR_BANKS		4
+
+/*
+ * The bus interface clock, clk_x, is phase aligned with the core clock.  The
+ * clk_x is an integral multiple N of the core clk.  The value N is configured
+ * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
+ * to the largest value to make it work with any possible configuration.
+ */
+#define DENALI_CLK_X_MULT	6
+
+static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
+}
+
+/*
+ * Direct Addressing - the slave address forms the control information (command
+ * type, bank, block, and page address).  The slave data is the actual data to
+ * be transferred.  This mode requires 28 bits of address region allocated.
+ */
+static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr)
+{
+	return ioread32(denali->host + addr);
+}
+
+static void denali_direct_write(struct denali_nand_info *denali, u32 addr,
+				u32 data)
+{
+	iowrite32(data, denali->host + addr);
+}
+
+/*
+ * Indexed Addressing - address translation module intervenes in passing the
+ * control information.  This mode reduces the required address range.  The
+ * control information and transferred data are latched by the registers in
+ * the translation module.
+ */
+static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr)
+{
+	iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
+	return ioread32(denali->host + DENALI_INDEXED_DATA);
+}
+
+static void denali_indexed_write(struct denali_nand_info *denali, u32 addr,
+				 u32 data)
+{
+	iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
+	iowrite32(data, denali->host + DENALI_INDEXED_DATA);
+}
+
+/*
+ * Use the configuration feature register to determine the maximum number of
+ * banks that the hardware supports.
+ */
+static void denali_detect_max_banks(struct denali_nand_info *denali)
+{
+	uint32_t features = ioread32(denali->reg + FEATURES);
+
+	denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features);
+
+	/* the encoding changed from rev 5.0 to 5.1 */
+	if (denali->revision < 0x0501)
+		denali->max_banks <<= 1;
+}
+
+static void denali_enable_irq(struct denali_nand_info *denali)
+{
+	int i;
+
+	for (i = 0; i < DENALI_NR_BANKS; i++)
+		iowrite32(U32_MAX, denali->reg + INTR_EN(i));
+	iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
+}
+
+static void denali_disable_irq(struct denali_nand_info *denali)
+{
+	int i;
+
+	for (i = 0; i < DENALI_NR_BANKS; i++)
+		iowrite32(0, denali->reg + INTR_EN(i));
+	iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
+}
+
+static void denali_clear_irq(struct denali_nand_info *denali,
+			     int bank, uint32_t irq_status)
+{
+	/* write one to clear bits */
+	iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
+}
+
+static void denali_clear_irq_all(struct denali_nand_info *denali)
+{
+	int i;
+
+	for (i = 0; i < DENALI_NR_BANKS; i++)
+		denali_clear_irq(denali, i, U32_MAX);
+}
+
+static irqreturn_t denali_isr(int irq, void *dev_id)
+{
+	struct denali_nand_info *denali = dev_id;
+	irqreturn_t ret = IRQ_NONE;
+	uint32_t irq_status;
+	int i;
+
+	spin_lock(&denali->irq_lock);
+
+	for (i = 0; i < DENALI_NR_BANKS; i++) {
+		irq_status = ioread32(denali->reg + INTR_STATUS(i));
+		if (irq_status)
+			ret = IRQ_HANDLED;
+
+		denali_clear_irq(denali, i, irq_status);
+
+		if (i != denali->active_bank)
+			continue;
+
+		denali->irq_status |= irq_status;
+
+		if (denali->irq_status & denali->irq_mask)
+			complete(&denali->complete);
+	}
+
+	spin_unlock(&denali->irq_lock);
+
+	return ret;
+}
+
+static void denali_reset_irq(struct denali_nand_info *denali)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&denali->irq_lock, flags);
+	denali->irq_status = 0;
+	denali->irq_mask = 0;
+	spin_unlock_irqrestore(&denali->irq_lock, flags);
+}
+
+static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
+				    uint32_t irq_mask)
+{
+	unsigned long time_left, flags;
+	uint32_t irq_status;
+
+	spin_lock_irqsave(&denali->irq_lock, flags);
+
+	irq_status = denali->irq_status;
+
+	if (irq_mask & irq_status) {
+		/* return immediately if the IRQ has already happened. */
+		spin_unlock_irqrestore(&denali->irq_lock, flags);
+		return irq_status;
+	}
+
+	denali->irq_mask = irq_mask;
+	reinit_completion(&denali->complete);
+	spin_unlock_irqrestore(&denali->irq_lock, flags);
+
+	time_left = wait_for_completion_timeout(&denali->complete,
+						msecs_to_jiffies(1000));
+	if (!time_left) {
+		dev_err(denali->dev, "timeout while waiting for irq 0x%x\n",
+			irq_mask);
+		return 0;
+	}
+
+	return denali->irq_status;
+}
+
+static uint32_t denali_check_irq(struct denali_nand_info *denali)
+{
+	unsigned long flags;
+	uint32_t irq_status;
+
+	spin_lock_irqsave(&denali->irq_lock, flags);
+	irq_status = denali->irq_status;
+	spin_unlock_irqrestore(&denali->irq_lock, flags);
+
+	return irq_status;
+}
+
+static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	int i;
+
+	for (i = 0; i < len; i++)
+		buf[i] = denali->host_read(denali, addr);
+}
+
+static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	int i;
+
+	for (i = 0; i < len; i++)
+		denali->host_write(denali, addr, buf[i]);
+}
+
+static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	uint16_t *buf16 = (uint16_t *)buf;
+	int i;
+
+	for (i = 0; i < len / 2; i++)
+		buf16[i] = denali->host_read(denali, addr);
+}
+
+static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+			       int len)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	const uint16_t *buf16 = (const uint16_t *)buf;
+	int i;
+
+	for (i = 0; i < len / 2; i++)
+		denali->host_write(denali, addr, buf16[i]);
+}
+
+static uint8_t denali_read_byte(struct mtd_info *mtd)
+{
+	uint8_t byte;
+
+	denali_read_buf(mtd, &byte, 1);
+
+	return byte;
+}
+
+static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
+{
+	denali_write_buf(mtd, &byte, 1);
+}
+
+static uint16_t denali_read_word(struct mtd_info *mtd)
+{
+	uint16_t word;
+
+	denali_read_buf16(mtd, (uint8_t *)&word, 2);
+
+	return word;
+}
+
+static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	uint32_t type;
+
+	if (ctrl & NAND_CLE)
+		type = DENALI_MAP11_CMD;
+	else if (ctrl & NAND_ALE)
+		type = DENALI_MAP11_ADDR;
+	else
+		return;
+
+	/*
+	 * Some commands are followed by chip->dev_ready or chip->waitfunc.
+	 * irq_status must be cleared here to catch the R/B# interrupt later.
+	 */
+	if (ctrl & NAND_CTRL_CHANGE)
+		denali_reset_irq(denali);
+
+	denali->host_write(denali, DENALI_BANK(denali) | type, dat);
+}
+
+static int denali_dev_ready(struct mtd_info *mtd)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+	return !!(denali_check_irq(denali) & INTR__INT_ACT);
+}
+
+static int denali_check_erased_page(struct mtd_info *mtd,
+				    struct nand_chip *chip, uint8_t *buf,
+				    unsigned long uncor_ecc_flags,
+				    unsigned int max_bitflips)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	int i, stat;
+
+	for (i = 0; i < ecc_steps; i++) {
+		if (!(uncor_ecc_flags & BIT(i)))
+			continue;
+
+		stat = nand_check_erased_ecc_chunk(buf, ecc_size,
+						  ecc_code, ecc_bytes,
+						  NULL, 0,
+						  chip->ecc.strength);
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+
+		buf += ecc_size;
+		ecc_code += ecc_bytes;
+	}
+
+	return max_bitflips;
+}
+
+static int denali_hw_ecc_fixup(struct mtd_info *mtd,
+			       struct denali_nand_info *denali,
+			       unsigned long *uncor_ecc_flags)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int bank = denali->active_bank;
+	uint32_t ecc_cor;
+	unsigned int max_bitflips;
+
+	ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
+	ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
+
+	if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
+		/*
+		 * This flag is set when uncorrectable error occurs at least in
+		 * one ECC sector.  We can not know "how many sectors", or
+		 * "which sector(s)".  We need erase-page check for all sectors.
+		 */
+		*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
+		return 0;
+	}
+
+	max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor);
+
+	/*
+	 * The register holds the maximum of per-sector corrected bitflips.
+	 * This is suitable for the return value of the ->read_page() callback.
+	 * Unfortunately, we can not know the total number of corrected bits in
+	 * the page.  Increase the stats by max_bitflips. (compromised solution)
+	 */
+	mtd->ecc_stats.corrected += max_bitflips;
+
+	return max_bitflips;
+}
+
+static int denali_sw_ecc_fixup(struct mtd_info *mtd,
+			       struct denali_nand_info *denali,
+			       unsigned long *uncor_ecc_flags, uint8_t *buf)
+{
+	unsigned int ecc_size = denali->nand.ecc.size;
+	unsigned int bitflips = 0;
+	unsigned int max_bitflips = 0;
+	uint32_t err_addr, err_cor_info;
+	unsigned int err_byte, err_sector, err_device;
+	uint8_t err_cor_value;
+	unsigned int prev_sector = 0;
+	uint32_t irq_status;
+
+	denali_reset_irq(denali);
+
+	do {
+		err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS);
+		err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr);
+		err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr);
+
+		err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO);
+		err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE,
+					  err_cor_info);
+		err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE,
+				       err_cor_info);
+
+		/* reset the bitflip counter when crossing ECC sector */
+		if (err_sector != prev_sector)
+			bitflips = 0;
+
+		if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) {
+			/*
+			 * Check later if this is a real ECC error, or
+			 * an erased sector.
+			 */
+			*uncor_ecc_flags |= BIT(err_sector);
+		} else if (err_byte < ecc_size) {
+			/*
+			 * If err_byte is larger than ecc_size, means error
+			 * happened in OOB, so we ignore it. It's no need for
+			 * us to correct it err_device is represented the NAND
+			 * error bits are happened in if there are more than
+			 * one NAND connected.
+			 */
+			int offset;
+			unsigned int flips_in_byte;
+
+			offset = (err_sector * ecc_size + err_byte) *
+					denali->devs_per_cs + err_device;
+
+			/* correct the ECC error */
+			flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
+			buf[offset] ^= err_cor_value;
+			mtd->ecc_stats.corrected += flips_in_byte;
+			bitflips += flips_in_byte;
+
+			max_bitflips = max(max_bitflips, bitflips);
+		}
+
+		prev_sector = err_sector;
+	} while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR));
+
+	/*
+	 * Once handle all ECC errors, controller will trigger an
+	 * ECC_TRANSACTION_DONE interrupt.
+	 */
+	irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE);
+	if (!(irq_status & INTR__ECC_TRANSACTION_DONE))
+		return -EIO;
+
+	return max_bitflips;
+}
+
+static void denali_setup_dma64(struct denali_nand_info *denali,
+			       dma_addr_t dma_addr, int page, int write)
+{
+	uint32_t mode;
+	const int page_count = 1;
+
+	mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
+
+	/* DMA is a three step process */
+
+	/*
+	 * 1. setup transfer type, interrupt when complete,
+	 *    burst len = 64 bytes, the number of pages
+	 */
+	denali->host_write(denali, mode,
+			   0x01002000 | (64 << 16) | (write << 8) | page_count);
+
+	/* 2. set memory low address */
+	denali->host_write(denali, mode, lower_32_bits(dma_addr));
+
+	/* 3. set memory high address */
+	denali->host_write(denali, mode, upper_32_bits(dma_addr));
+}
+
+static void denali_setup_dma32(struct denali_nand_info *denali,
+			       dma_addr_t dma_addr, int page, int write)
+{
+	uint32_t mode;
+	const int page_count = 1;
+
+	mode = DENALI_MAP10 | DENALI_BANK(denali);
+
+	/* DMA is a four step process */
+
+	/* 1. setup transfer type and # of pages */
+	denali->host_write(denali, mode | page,
+			   0x2000 | (write << 8) | page_count);
+
+	/* 2. set memory high address bits 23:8 */
+	denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
+
+	/* 3. set memory low address bits 23:8 */
+	denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300);
+
+	/* 4. interrupt when complete, burst len = 64 bytes */
+	denali->host_write(denali, mode | 0x14000, 0x2400);
+}
+
+static int denali_pio_read(struct denali_nand_info *denali, void *buf,
+			   size_t size, int page, int raw)
+{
+	u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
+	uint32_t *buf32 = (uint32_t *)buf;
+	uint32_t irq_status, ecc_err_mask;
+	int i;
+
+	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+		ecc_err_mask = INTR__ECC_UNCOR_ERR;
+	else
+		ecc_err_mask = INTR__ECC_ERR;
+
+	denali_reset_irq(denali);
+
+	for (i = 0; i < size / 4; i++)
+		*buf32++ = denali->host_read(denali, addr);
+
+	irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
+	if (!(irq_status & INTR__PAGE_XFER_INC))
+		return -EIO;
+
+	if (irq_status & INTR__ERASED_PAGE)
+		memset(buf, 0xff, size);
+
+	return irq_status & ecc_err_mask ? -EBADMSG : 0;
+}
+
+static int denali_pio_write(struct denali_nand_info *denali,
+			    const void *buf, size_t size, int page, int raw)
+{
+	u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
+	const uint32_t *buf32 = (uint32_t *)buf;
+	uint32_t irq_status;
+	int i;
+
+	denali_reset_irq(denali);
+
+	for (i = 0; i < size / 4; i++)
+		denali->host_write(denali, addr, *buf32++);
+
+	irq_status = denali_wait_for_irq(denali,
+				INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
+	if (!(irq_status & INTR__PROGRAM_COMP))
+		return -EIO;
+
+	return 0;
+}
+
+static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
+			   size_t size, int page, int raw, int write)
+{
+	if (write)
+		return denali_pio_write(denali, buf, size, page, raw);
+	else
+		return denali_pio_read(denali, buf, size, page, raw);
+}
+
+static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
+			   size_t size, int page, int raw, int write)
+{
+	dma_addr_t dma_addr;
+	uint32_t irq_mask, irq_status, ecc_err_mask;
+	enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	int ret = 0;
+
+	dma_addr = dma_map_single(denali->dev, buf, size, dir);
+	if (dma_mapping_error(denali->dev, dma_addr)) {
+		dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
+		return denali_pio_xfer(denali, buf, size, page, raw, write);
+	}
+
+	if (write) {
+		/*
+		 * INTR__PROGRAM_COMP is never asserted for the DMA transfer.
+		 * We can use INTR__DMA_CMD_COMP instead.  This flag is asserted
+		 * when the page program is completed.
+		 */
+		irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
+		ecc_err_mask = 0;
+	} else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) {
+		irq_mask = INTR__DMA_CMD_COMP;
+		ecc_err_mask = INTR__ECC_UNCOR_ERR;
+	} else {
+		irq_mask = INTR__DMA_CMD_COMP;
+		ecc_err_mask = INTR__ECC_ERR;
+	}
+
+	iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
+
+	denali_reset_irq(denali);
+	denali->setup_dma(denali, dma_addr, page, write);
+
+	irq_status = denali_wait_for_irq(denali, irq_mask);
+	if (!(irq_status & INTR__DMA_CMD_COMP))
+		ret = -EIO;
+	else if (irq_status & ecc_err_mask)
+		ret = -EBADMSG;
+
+	iowrite32(0, denali->reg + DMA_ENABLE);
+
+	dma_unmap_single(denali->dev, dma_addr, size, dir);
+
+	if (irq_status & INTR__ERASED_PAGE)
+		memset(buf, 0xff, size);
+
+	return ret;
+}
+
+static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
+			    size_t size, int page, int raw, int write)
+{
+	iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE);
+	iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0,
+		  denali->reg + TRANSFER_SPARE_REG);
+
+	if (denali->dma_avail)
+		return denali_dma_xfer(denali, buf, size, page, raw, write);
+	else
+		return denali_pio_xfer(denali, buf, size, page, raw, write);
+}
+
+static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page, int write)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	int writesize = mtd->writesize;
+	int oobsize = mtd->oobsize;
+	uint8_t *bufpoi = chip->oob_poi;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	int oob_skip = denali->oob_skip_bytes;
+	size_t size = writesize + oobsize;
+	int i, pos, len;
+
+	/* BBM at the beginning of the OOB area */
+	if (write)
+		nand_prog_page_begin_op(chip, page, writesize, bufpoi,
+					oob_skip);
+	else
+		nand_read_page_op(chip, page, writesize, bufpoi, oob_skip);
+	bufpoi += oob_skip;
+
+	/* OOB ECC */
+	for (i = 0; i < ecc_steps; i++) {
+		pos = ecc_size + i * (ecc_size + ecc_bytes);
+		len = ecc_bytes;
+
+		if (pos >= writesize)
+			pos += oob_skip;
+		else if (pos + len > writesize)
+			len = writesize - pos;
+
+		if (write)
+			nand_change_write_column_op(chip, pos, bufpoi, len,
+						    false);
+		else
+			nand_change_read_column_op(chip, pos, bufpoi, len,
+						   false);
+		bufpoi += len;
+		if (len < ecc_bytes) {
+			len = ecc_bytes - len;
+			if (write)
+				nand_change_write_column_op(chip, writesize +
+							    oob_skip, bufpoi,
+							    len, false);
+			else
+				nand_change_read_column_op(chip, writesize +
+							   oob_skip, bufpoi,
+							   len, false);
+			bufpoi += len;
+		}
+	}
+
+	/* OOB free */
+	len = oobsize - (bufpoi - chip->oob_poi);
+	if (write)
+		nand_change_write_column_op(chip, size - len, bufpoi, len,
+					    false);
+	else
+		nand_change_read_column_op(chip, size - len, bufpoi, len,
+					   false);
+}
+
+static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	int writesize = mtd->writesize;
+	int oobsize = mtd->oobsize;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	void *tmp_buf = denali->buf;
+	int oob_skip = denali->oob_skip_bytes;
+	size_t size = writesize + oobsize;
+	int ret, i, pos, len;
+
+	ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0);
+	if (ret)
+		return ret;
+
+	/* Arrange the buffer for syndrome payload/ecc layout */
+	if (buf) {
+		for (i = 0; i < ecc_steps; i++) {
+			pos = i * (ecc_size + ecc_bytes);
+			len = ecc_size;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(buf, tmp_buf + pos, len);
+			buf += len;
+			if (len < ecc_size) {
+				len = ecc_size - len;
+				memcpy(buf, tmp_buf + writesize + oob_skip,
+				       len);
+				buf += len;
+			}
+		}
+	}
+
+	if (oob_required) {
+		uint8_t *oob = chip->oob_poi;
+
+		/* BBM at the beginning of the OOB area */
+		memcpy(oob, tmp_buf + writesize, oob_skip);
+		oob += oob_skip;
+
+		/* OOB ECC */
+		for (i = 0; i < ecc_steps; i++) {
+			pos = ecc_size + i * (ecc_size + ecc_bytes);
+			len = ecc_bytes;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(oob, tmp_buf + pos, len);
+			oob += len;
+			if (len < ecc_bytes) {
+				len = ecc_bytes - len;
+				memcpy(oob, tmp_buf + writesize + oob_skip,
+				       len);
+				oob += len;
+			}
+		}
+
+		/* OOB free */
+		len = oobsize - (oob - chip->oob_poi);
+		memcpy(oob, tmp_buf + size - len, len);
+	}
+
+	return 0;
+}
+
+static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			   int page)
+{
+	denali_oob_xfer(mtd, chip, page, 0);
+
+	return 0;
+}
+
+static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+	denali_reset_irq(denali);
+
+	denali_oob_xfer(mtd, chip, page, 1);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			    uint8_t *buf, int oob_required, int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	unsigned long uncor_ecc_flags = 0;
+	int stat = 0;
+	int ret;
+
+	ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
+	if (ret && ret != -EBADMSG)
+		return ret;
+
+	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+		stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
+	else if (ret == -EBADMSG)
+		stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
+
+	if (stat < 0)
+		return stat;
+
+	if (uncor_ecc_flags) {
+		ret = denali_read_oob(mtd, chip, page);
+		if (ret)
+			return ret;
+
+		stat = denali_check_erased_page(mtd, chip, buf,
+						uncor_ecc_flags, stat);
+	}
+
+	return stat;
+}
+
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				 const uint8_t *buf, int oob_required, int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	int writesize = mtd->writesize;
+	int oobsize = mtd->oobsize;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	void *tmp_buf = denali->buf;
+	int oob_skip = denali->oob_skip_bytes;
+	size_t size = writesize + oobsize;
+	int i, pos, len;
+
+	/*
+	 * Fill the buffer with 0xff first except the full page transfer.
+	 * This simplifies the logic.
+	 */
+	if (!buf || !oob_required)
+		memset(tmp_buf, 0xff, size);
+
+	/* Arrange the buffer for syndrome payload/ecc layout */
+	if (buf) {
+		for (i = 0; i < ecc_steps; i++) {
+			pos = i * (ecc_size + ecc_bytes);
+			len = ecc_size;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(tmp_buf + pos, buf, len);
+			buf += len;
+			if (len < ecc_size) {
+				len = ecc_size - len;
+				memcpy(tmp_buf + writesize + oob_skip, buf,
+				       len);
+				buf += len;
+			}
+		}
+	}
+
+	if (oob_required) {
+		const uint8_t *oob = chip->oob_poi;
+
+		/* BBM at the beginning of the OOB area */
+		memcpy(tmp_buf + writesize, oob, oob_skip);
+		oob += oob_skip;
+
+		/* OOB ECC */
+		for (i = 0; i < ecc_steps; i++) {
+			pos = ecc_size + i * (ecc_size + ecc_bytes);
+			len = ecc_bytes;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(tmp_buf + pos, oob, len);
+			oob += len;
+			if (len < ecc_bytes) {
+				len = ecc_bytes - len;
+				memcpy(tmp_buf + writesize + oob_skip, oob,
+				       len);
+				oob += len;
+			}
+		}
+
+		/* OOB free */
+		len = oobsize - (oob - chip->oob_poi);
+		memcpy(tmp_buf + size - len, oob, len);
+	}
+
+	return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
+}
+
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			     const uint8_t *buf, int oob_required, int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+	return denali_data_xfer(denali, (void *)buf, mtd->writesize,
+				page, 0, 1);
+}
+
+static void denali_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+	denali->active_bank = chip;
+}
+
+static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	uint32_t irq_status;
+
+	/* R/B# pin transitioned from low to high? */
+	irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
+
+	return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
+}
+
+static int denali_erase(struct mtd_info *mtd, int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	uint32_t irq_status;
+
+	denali_reset_irq(denali);
+
+	denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
+			   DENALI_ERASE);
+
+	/* wait for erase to complete or failure to occur */
+	irq_status = denali_wait_for_irq(denali,
+					 INTR__ERASE_COMP | INTR__ERASE_FAIL);
+
+	return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
+}
+
+static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+				       const struct nand_data_interface *conf)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	const struct nand_sdr_timings *timings;
+	unsigned long t_clk;
+	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
+	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
+	int addr_2_data_mask;
+	uint32_t tmp;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return PTR_ERR(timings);
+
+	/* clk_x period in picoseconds */
+	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
+	if (!t_clk)
+		return -EINVAL;
+
+	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	/* tREA -> ACC_CLKS */
+	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
+	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
+
+	tmp = ioread32(denali->reg + ACC_CLKS);
+	tmp &= ~ACC_CLKS__VALUE;
+	tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks);
+	iowrite32(tmp, denali->reg + ACC_CLKS);
+
+	/* tRWH -> RE_2_WE */
+	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
+	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
+
+	tmp = ioread32(denali->reg + RE_2_WE);
+	tmp &= ~RE_2_WE__VALUE;
+	tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we);
+	iowrite32(tmp, denali->reg + RE_2_WE);
+
+	/* tRHZ -> RE_2_RE */
+	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
+	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
+
+	tmp = ioread32(denali->reg + RE_2_RE);
+	tmp &= ~RE_2_RE__VALUE;
+	tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re);
+	iowrite32(tmp, denali->reg + RE_2_RE);
+
+	/*
+	 * tCCS, tWHR -> WE_2_RE
+	 *
+	 * With WE_2_RE properly set, the Denali controller automatically takes
+	 * care of the delay; the driver need not set NAND_WAIT_TCCS.
+	 */
+	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
+			       t_clk);
+	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
+
+	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
+	tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
+	tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re);
+	iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
+
+	/* tADL -> ADDR_2_DATA */
+
+	/* for older versions, ADDR_2_DATA is only 6 bit wide */
+	addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
+	if (denali->revision < 0x0501)
+		addr_2_data_mask >>= 1;
+
+	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
+	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
+
+	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
+	tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
+	tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data);
+	iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
+
+	/* tREH, tWH -> RDWR_EN_HI_CNT */
+	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
+				  t_clk);
+	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
+
+	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
+	tmp &= ~RDWR_EN_HI_CNT__VALUE;
+	tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi);
+	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
+
+	/* tRP, tWP -> RDWR_EN_LO_CNT */
+	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
+				  t_clk);
+	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
+				     t_clk);
+	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
+	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
+	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
+
+	tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
+	tmp &= ~RDWR_EN_LO_CNT__VALUE;
+	tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo);
+	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
+
+	/* tCS, tCEA -> CS_SETUP_CNT */
+	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
+			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
+			0);
+	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
+
+	tmp = ioread32(denali->reg + CS_SETUP_CNT);
+	tmp &= ~CS_SETUP_CNT__VALUE;
+	tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup);
+	iowrite32(tmp, denali->reg + CS_SETUP_CNT);
+
+	return 0;
+}
+
+static void denali_reset_banks(struct denali_nand_info *denali)
+{
+	u32 irq_status;
+	int i;
+
+	for (i = 0; i < denali->max_banks; i++) {
+		denali->active_bank = i;
+
+		denali_reset_irq(denali);
+
+		iowrite32(DEVICE_RESET__BANK(i),
+			  denali->reg + DEVICE_RESET);
+
+		irq_status = denali_wait_for_irq(denali,
+			INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
+		if (!(irq_status & INTR__INT_ACT))
+			break;
+	}
+
+	dev_dbg(denali->dev, "%d chips connected\n", i);
+	denali->max_banks = i;
+}
+
+static void denali_hw_init(struct denali_nand_info *denali)
+{
+	/*
+	 * The REVISION register may not be reliable.  Platforms are allowed to
+	 * override it.
+	 */
+	if (!denali->revision)
+		denali->revision = swab16(ioread32(denali->reg + REVISION));
+
+	/*
+	 * tell driver how many bit controller will skip before
+	 * writing ECC code in OOB, this register may be already
+	 * set by firmware. So we read this value out.
+	 * if this value is 0, just let it be.
+	 */
+	denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+	denali_detect_max_banks(denali);
+	iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
+	iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
+
+	iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
+}
+
+int denali_calc_ecc_bytes(int step_size, int strength)
+{
+	/* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
+	return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
+}
+EXPORT_SYMBOL(denali_calc_ecc_bytes);
+
+static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
+			    struct denali_nand_info *denali)
+{
+	int oobavail = mtd->oobsize - denali->oob_skip_bytes;
+	int ret;
+
+	/*
+	 * If .size and .strength are already set (usually by DT),
+	 * check if they are supported by this controller.
+	 */
+	if (chip->ecc.size && chip->ecc.strength)
+		return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
+
+	/*
+	 * We want .size and .strength closest to the chip's requirement
+	 * unless NAND_ECC_MAXIMIZE is requested.
+	 */
+	if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+		ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
+		if (!ret)
+			return 0;
+	}
+
+	/* Max ECC strength is the last thing we can do */
+	return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
+}
+
+static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = denali->oob_skip_bytes;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int denali_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
+	oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
+	.ecc = denali_ooblayout_ecc,
+	.free = denali_ooblayout_free,
+};
+
+static int denali_multidev_fixup(struct denali_nand_info *denali)
+{
+	struct nand_chip *chip = &denali->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	/*
+	 * Support for multi device:
+	 * When the IP configuration is x16 capable and two x8 chips are
+	 * connected in parallel, DEVICES_CONNECTED should be set to 2.
+	 * In this case, the core framework knows nothing about this fact,
+	 * so we should tell it the _logical_ pagesize and anything necessary.
+	 */
+	denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED);
+
+	/*
+	 * On some SoCs, DEVICES_CONNECTED is not auto-detected.
+	 * For those, DEVICES_CONNECTED is left to 0.  Set 1 if it is the case.
+	 */
+	if (denali->devs_per_cs == 0) {
+		denali->devs_per_cs = 1;
+		iowrite32(1, denali->reg + DEVICES_CONNECTED);
+	}
+
+	if (denali->devs_per_cs == 1)
+		return 0;
+
+	if (denali->devs_per_cs != 2) {
+		dev_err(denali->dev, "unsupported number of devices %d\n",
+			denali->devs_per_cs);
+		return -EINVAL;
+	}
+
+	/* 2 chips in parallel */
+	mtd->size <<= 1;
+	mtd->erasesize <<= 1;
+	mtd->writesize <<= 1;
+	mtd->oobsize <<= 1;
+	chip->chipsize <<= 1;
+	chip->page_shift += 1;
+	chip->phys_erase_shift += 1;
+	chip->bbt_erase_shift += 1;
+	chip->chip_shift += 1;
+	chip->pagemask <<= 1;
+	chip->ecc.size <<= 1;
+	chip->ecc.bytes <<= 1;
+	chip->ecc.strength <<= 1;
+	denali->oob_skip_bytes <<= 1;
+
+	return 0;
+}
+
+int denali_init(struct denali_nand_info *denali)
+{
+	struct nand_chip *chip = &denali->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u32 features = ioread32(denali->reg + FEATURES);
+	int ret;
+
+	mtd->dev.parent = denali->dev;
+	denali_hw_init(denali);
+
+	init_completion(&denali->complete);
+	spin_lock_init(&denali->irq_lock);
+
+	denali_clear_irq_all(denali);
+
+	ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+			       IRQF_SHARED, DENALI_NAND_NAME, denali);
+	if (ret) {
+		dev_err(denali->dev, "Unable to request IRQ\n");
+		return ret;
+	}
+
+	denali_enable_irq(denali);
+	denali_reset_banks(denali);
+
+	denali->active_bank = DENALI_INVALID_BANK;
+
+	nand_set_flash_node(chip, denali->dev->of_node);
+	/* Fallback to the default name if DT did not give "label" property */
+	if (!mtd->name)
+		mtd->name = "denali-nand";
+
+	chip->select_chip = denali_select_chip;
+	chip->read_byte = denali_read_byte;
+	chip->write_byte = denali_write_byte;
+	chip->read_word = denali_read_word;
+	chip->cmd_ctrl = denali_cmd_ctrl;
+	chip->dev_ready = denali_dev_ready;
+	chip->waitfunc = denali_waitfunc;
+
+	if (features & FEATURES__INDEX_ADDR) {
+		denali->host_read = denali_indexed_read;
+		denali->host_write = denali_indexed_write;
+	} else {
+		denali->host_read = denali_direct_read;
+		denali->host_write = denali_direct_write;
+	}
+
+	/* clk rate info is needed for setup_data_interface */
+	if (denali->clk_x_rate)
+		chip->setup_data_interface = denali_setup_data_interface;
+
+	ret = nand_scan_ident(mtd, denali->max_banks, NULL);
+	if (ret)
+		goto disable_irq;
+
+	if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
+		denali->dma_avail = 1;
+
+	if (denali->dma_avail) {
+		int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
+
+		ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
+		if (ret) {
+			dev_info(denali->dev,
+				 "Failed to set DMA mask. Disabling DMA.\n");
+			denali->dma_avail = 0;
+		}
+	}
+
+	if (denali->dma_avail) {
+		chip->options |= NAND_USE_BOUNCE_BUFFER;
+		chip->buf_align = 16;
+		if (denali->caps & DENALI_CAP_DMA_64BIT)
+			denali->setup_dma = denali_setup_dma64;
+		else
+			denali->setup_dma = denali_setup_dma32;
+	}
+
+	chip->bbt_options |= NAND_BBT_USE_FLASH;
+	chip->bbt_options |= NAND_BBT_NO_OOB;
+	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+	chip->options |= NAND_NO_SUBPAGE_WRITE;
+
+	ret = denali_ecc_setup(mtd, chip, denali);
+	if (ret) {
+		dev_err(denali->dev, "Failed to setup ECC settings.\n");
+		goto disable_irq;
+	}
+
+	dev_dbg(denali->dev,
+		"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+		chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+
+	iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
+		  FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
+		  denali->reg + ECC_CORRECTION);
+	iowrite32(mtd->erasesize / mtd->writesize,
+		  denali->reg + PAGES_PER_BLOCK);
+	iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
+		  denali->reg + DEVICE_WIDTH);
+	iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG,
+		  denali->reg + TWO_ROW_ADDR_CYCLES);
+	iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
+	iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
+
+	iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
+	iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
+	/* chip->ecc.steps is set by nand_scan_tail(); not available here */
+	iowrite32(mtd->writesize / chip->ecc.size,
+		  denali->reg + CFG_NUM_DATA_BLOCKS);
+
+	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
+
+	if (chip->options & NAND_BUSWIDTH_16) {
+		chip->read_buf = denali_read_buf16;
+		chip->write_buf = denali_write_buf16;
+	} else {
+		chip->read_buf = denali_read_buf;
+		chip->write_buf = denali_write_buf;
+	}
+	chip->ecc.read_page = denali_read_page;
+	chip->ecc.read_page_raw = denali_read_page_raw;
+	chip->ecc.write_page = denali_write_page;
+	chip->ecc.write_page_raw = denali_write_page_raw;
+	chip->ecc.read_oob = denali_read_oob;
+	chip->ecc.write_oob = denali_write_oob;
+	chip->erase = denali_erase;
+
+	ret = denali_multidev_fixup(denali);
+	if (ret)
+		goto disable_irq;
+
+	/*
+	 * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
+	 * use devm_kmalloc() because the memory allocated by devm_ does not
+	 * guarantee DMA-safe alignment.
+	 */
+	denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+	if (!denali->buf) {
+		ret = -ENOMEM;
+		goto disable_irq;
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		goto free_buf;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
+		goto free_buf;
+	}
+	return 0;
+
+free_buf:
+	kfree(denali->buf);
+disable_irq:
+	denali_disable_irq(denali);
+
+	return ret;
+}
+EXPORT_SYMBOL(denali_init);
+
+void denali_remove(struct denali_nand_info *denali)
+{
+	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+
+	nand_release(mtd);
+	kfree(denali->buf);
+	denali_disable_irq(denali);
+}
+EXPORT_SYMBOL(denali_remove);
diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h
new file mode 100644
index 000000000000..9ad33d237378
--- /dev/null
+++ b/drivers/mtd/nand/raw/denali.h
@@ -0,0 +1,335 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __DENALI_H__
+#define __DENALI_H__
+
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+
+#define DEVICE_RESET				0x0
+#define     DEVICE_RESET__BANK(bank)			BIT(bank)
+
+#define TRANSFER_SPARE_REG			0x10
+#define     TRANSFER_SPARE_REG__FLAG			BIT(0)
+
+#define LOAD_WAIT_CNT				0x20
+#define     LOAD_WAIT_CNT__VALUE			GENMASK(15, 0)
+
+#define PROGRAM_WAIT_CNT			0x30
+#define     PROGRAM_WAIT_CNT__VALUE			GENMASK(15, 0)
+
+#define ERASE_WAIT_CNT				0x40
+#define     ERASE_WAIT_CNT__VALUE			GENMASK(15, 0)
+
+#define INT_MON_CYCCNT				0x50
+#define     INT_MON_CYCCNT__VALUE			GENMASK(15, 0)
+
+#define RB_PIN_ENABLED				0x60
+#define     RB_PIN_ENABLED__BANK(bank)			BIT(bank)
+
+#define MULTIPLANE_OPERATION			0x70
+#define     MULTIPLANE_OPERATION__FLAG			BIT(0)
+
+#define MULTIPLANE_READ_ENABLE			0x80
+#define     MULTIPLANE_READ_ENABLE__FLAG		BIT(0)
+
+#define COPYBACK_DISABLE			0x90
+#define     COPYBACK_DISABLE__FLAG			BIT(0)
+
+#define CACHE_WRITE_ENABLE			0xa0
+#define     CACHE_WRITE_ENABLE__FLAG			BIT(0)
+
+#define CACHE_READ_ENABLE			0xb0
+#define     CACHE_READ_ENABLE__FLAG			BIT(0)
+
+#define PREFETCH_MODE				0xc0
+#define     PREFETCH_MODE__PREFETCH_EN			BIT(0)
+#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH	GENMASK(15, 4)
+
+#define CHIP_ENABLE_DONT_CARE			0xd0
+#define     CHIP_EN_DONT_CARE__FLAG			BIT(0)
+
+#define ECC_ENABLE				0xe0
+#define     ECC_ENABLE__FLAG				BIT(0)
+
+#define GLOBAL_INT_ENABLE			0xf0
+#define     GLOBAL_INT_EN_FLAG				BIT(0)
+
+#define TWHR2_AND_WE_2_RE			0x100
+#define     TWHR2_AND_WE_2_RE__WE_2_RE			GENMASK(5, 0)
+#define     TWHR2_AND_WE_2_RE__TWHR2			GENMASK(13, 8)
+
+#define TCWAW_AND_ADDR_2_DATA			0x110
+/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
+#define     TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA		GENMASK(6, 0)
+#define     TCWAW_AND_ADDR_2_DATA__TCWAW		GENMASK(13, 8)
+
+#define RE_2_WE					0x120
+#define     RE_2_WE__VALUE				GENMASK(5, 0)
+
+#define ACC_CLKS				0x130
+#define     ACC_CLKS__VALUE				GENMASK(3, 0)
+
+#define NUMBER_OF_PLANES			0x140
+#define     NUMBER_OF_PLANES__VALUE			GENMASK(2, 0)
+
+#define PAGES_PER_BLOCK				0x150
+#define     PAGES_PER_BLOCK__VALUE			GENMASK(15, 0)
+
+#define DEVICE_WIDTH				0x160
+#define     DEVICE_WIDTH__VALUE				GENMASK(1, 0)
+
+#define DEVICE_MAIN_AREA_SIZE			0x170
+#define     DEVICE_MAIN_AREA_SIZE__VALUE		GENMASK(15, 0)
+
+#define DEVICE_SPARE_AREA_SIZE			0x180
+#define     DEVICE_SPARE_AREA_SIZE__VALUE		GENMASK(15, 0)
+
+#define TWO_ROW_ADDR_CYCLES			0x190
+#define     TWO_ROW_ADDR_CYCLES__FLAG			BIT(0)
+
+#define MULTIPLANE_ADDR_RESTRICT		0x1a0
+#define     MULTIPLANE_ADDR_RESTRICT__FLAG		BIT(0)
+
+#define ECC_CORRECTION				0x1b0
+#define     ECC_CORRECTION__VALUE			GENMASK(4, 0)
+#define     ECC_CORRECTION__ERASE_THRESHOLD		GENMASK(31, 16)
+
+#define READ_MODE				0x1c0
+#define     READ_MODE__VALUE				GENMASK(3, 0)
+
+#define WRITE_MODE				0x1d0
+#define     WRITE_MODE__VALUE				GENMASK(3, 0)
+
+#define COPYBACK_MODE				0x1e0
+#define     COPYBACK_MODE__VALUE			GENMASK(3, 0)
+
+#define RDWR_EN_LO_CNT				0x1f0
+#define     RDWR_EN_LO_CNT__VALUE			GENMASK(4, 0)
+
+#define RDWR_EN_HI_CNT				0x200
+#define     RDWR_EN_HI_CNT__VALUE			GENMASK(4, 0)
+
+#define MAX_RD_DELAY				0x210
+#define     MAX_RD_DELAY__VALUE				GENMASK(3, 0)
+
+#define CS_SETUP_CNT				0x220
+#define     CS_SETUP_CNT__VALUE				GENMASK(4, 0)
+#define     CS_SETUP_CNT__TWB				GENMASK(17, 12)
+
+#define SPARE_AREA_SKIP_BYTES			0x230
+#define     SPARE_AREA_SKIP_BYTES__VALUE		GENMASK(5, 0)
+
+#define SPARE_AREA_MARKER			0x240
+#define     SPARE_AREA_MARKER__VALUE			GENMASK(15, 0)
+
+#define DEVICES_CONNECTED			0x250
+#define     DEVICES_CONNECTED__VALUE			GENMASK(2, 0)
+
+#define DIE_MASK				0x260
+#define     DIE_MASK__VALUE				GENMASK(7, 0)
+
+#define FIRST_BLOCK_OF_NEXT_PLANE		0x270
+#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE		GENMASK(15, 0)
+
+#define WRITE_PROTECT				0x280
+#define     WRITE_PROTECT__FLAG				BIT(0)
+
+#define RE_2_RE					0x290
+#define     RE_2_RE__VALUE				GENMASK(5, 0)
+
+#define MANUFACTURER_ID				0x300
+#define     MANUFACTURER_ID__VALUE			GENMASK(7, 0)
+
+#define DEVICE_ID				0x310
+#define     DEVICE_ID__VALUE				GENMASK(7, 0)
+
+#define DEVICE_PARAM_0				0x320
+#define     DEVICE_PARAM_0__VALUE			GENMASK(7, 0)
+
+#define DEVICE_PARAM_1				0x330
+#define     DEVICE_PARAM_1__VALUE			GENMASK(7, 0)
+
+#define DEVICE_PARAM_2				0x340
+#define     DEVICE_PARAM_2__VALUE			GENMASK(7, 0)
+
+#define LOGICAL_PAGE_DATA_SIZE			0x350
+#define     LOGICAL_PAGE_DATA_SIZE__VALUE		GENMASK(15, 0)
+
+#define LOGICAL_PAGE_SPARE_SIZE			0x360
+#define     LOGICAL_PAGE_SPARE_SIZE__VALUE		GENMASK(15, 0)
+
+#define REVISION				0x370
+#define     REVISION__VALUE				GENMASK(15, 0)
+
+#define ONFI_DEVICE_FEATURES			0x380
+#define     ONFI_DEVICE_FEATURES__VALUE			GENMASK(5, 0)
+
+#define ONFI_OPTIONAL_COMMANDS			0x390
+#define     ONFI_OPTIONAL_COMMANDS__VALUE		GENMASK(5, 0)
+
+#define ONFI_TIMING_MODE			0x3a0
+#define     ONFI_TIMING_MODE__VALUE			GENMASK(5, 0)
+
+#define ONFI_PGM_CACHE_TIMING_MODE		0x3b0
+#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE		GENMASK(5, 0)
+
+#define ONFI_DEVICE_NO_OF_LUNS			0x3c0
+#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS		GENMASK(7, 0)
+#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE		BIT(8)
+
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L	0x3d0
+#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE	GENMASK(15, 0)
+
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U	0x3e0
+#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE	GENMASK(15, 0)
+
+#define FEATURES				0x3f0
+#define     FEATURES__N_BANKS				GENMASK(1, 0)
+#define     FEATURES__ECC_MAX_ERR			GENMASK(5, 2)
+#define     FEATURES__DMA				BIT(6)
+#define     FEATURES__CMD_DMA				BIT(7)
+#define     FEATURES__PARTITION				BIT(8)
+#define     FEATURES__XDMA_SIDEBAND			BIT(9)
+#define     FEATURES__GPREG				BIT(10)
+#define     FEATURES__INDEX_ADDR			BIT(11)
+
+#define TRANSFER_MODE				0x400
+#define     TRANSFER_MODE__VALUE			GENMASK(1, 0)
+
+#define INTR_STATUS(bank)			(0x410 + (bank) * 0x50)
+#define INTR_EN(bank)				(0x420 + (bank) * 0x50)
+/* bit[1:0] is used differently depending on IP version */
+#define     INTR__ECC_UNCOR_ERR				BIT(0)	/* new IP */
+#define     INTR__ECC_TRANSACTION_DONE			BIT(0)	/* old IP */
+#define     INTR__ECC_ERR				BIT(1)	/* old IP */
+#define     INTR__DMA_CMD_COMP				BIT(2)
+#define     INTR__TIME_OUT				BIT(3)
+#define     INTR__PROGRAM_FAIL				BIT(4)
+#define     INTR__ERASE_FAIL				BIT(5)
+#define     INTR__LOAD_COMP				BIT(6)
+#define     INTR__PROGRAM_COMP				BIT(7)
+#define     INTR__ERASE_COMP				BIT(8)
+#define     INTR__PIPE_CPYBCK_CMD_COMP			BIT(9)
+#define     INTR__LOCKED_BLK				BIT(10)
+#define     INTR__UNSUP_CMD				BIT(11)
+#define     INTR__INT_ACT				BIT(12)
+#define     INTR__RST_COMP				BIT(13)
+#define     INTR__PIPE_CMD_ERR				BIT(14)
+#define     INTR__PAGE_XFER_INC				BIT(15)
+#define     INTR__ERASED_PAGE				BIT(16)
+
+#define PAGE_CNT(bank)				(0x430 + (bank) * 0x50)
+#define ERR_PAGE_ADDR(bank)			(0x440 + (bank) * 0x50)
+#define ERR_BLOCK_ADDR(bank)			(0x450 + (bank) * 0x50)
+
+#define ECC_THRESHOLD				0x600
+#define     ECC_THRESHOLD__VALUE			GENMASK(9, 0)
+
+#define ECC_ERROR_BLOCK_ADDRESS			0x610
+#define     ECC_ERROR_BLOCK_ADDRESS__VALUE		GENMASK(15, 0)
+
+#define ECC_ERROR_PAGE_ADDRESS			0x620
+#define     ECC_ERROR_PAGE_ADDRESS__VALUE		GENMASK(11, 0)
+#define     ECC_ERROR_PAGE_ADDRESS__BANK		GENMASK(15, 12)
+
+#define ECC_ERROR_ADDRESS			0x630
+#define     ECC_ERROR_ADDRESS__OFFSET			GENMASK(11, 0)
+#define     ECC_ERROR_ADDRESS__SECTOR			GENMASK(15, 12)
+
+#define ERR_CORRECTION_INFO			0x640
+#define     ERR_CORRECTION_INFO__BYTE			GENMASK(7, 0)
+#define     ERR_CORRECTION_INFO__DEVICE			GENMASK(11, 8)
+#define     ERR_CORRECTION_INFO__UNCOR			BIT(14)
+#define     ERR_CORRECTION_INFO__LAST_ERR		BIT(15)
+
+#define ECC_COR_INFO(bank)			(0x650 + (bank) / 2 * 0x10)
+#define     ECC_COR_INFO__SHIFT(bank)			((bank) % 2 * 8)
+#define     ECC_COR_INFO__MAX_ERRORS			GENMASK(6, 0)
+#define     ECC_COR_INFO__UNCOR_ERR			BIT(7)
+
+#define CFG_DATA_BLOCK_SIZE			0x6b0
+
+#define CFG_LAST_DATA_BLOCK_SIZE		0x6c0
+
+#define CFG_NUM_DATA_BLOCKS			0x6d0
+
+#define CFG_META_DATA_SIZE			0x6e0
+
+#define DMA_ENABLE				0x700
+#define     DMA_ENABLE__FLAG				BIT(0)
+
+#define IGNORE_ECC_DONE				0x710
+#define     IGNORE_ECC_DONE__FLAG			BIT(0)
+
+#define DMA_INTR				0x720
+#define DMA_INTR_EN				0x730
+#define     DMA_INTR__TARGET_ERROR			BIT(0)
+#define     DMA_INTR__DESC_COMP_CHANNEL0		BIT(1)
+#define     DMA_INTR__DESC_COMP_CHANNEL1		BIT(2)
+#define     DMA_INTR__DESC_COMP_CHANNEL2		BIT(3)
+#define     DMA_INTR__DESC_COMP_CHANNEL3		BIT(4)
+#define     DMA_INTR__MEMCOPY_DESC_COMP			BIT(5)
+
+#define TARGET_ERR_ADDR_LO			0x740
+#define     TARGET_ERR_ADDR_LO__VALUE			GENMASK(15, 0)
+
+#define TARGET_ERR_ADDR_HI			0x750
+#define     TARGET_ERR_ADDR_HI__VALUE			GENMASK(15, 0)
+
+#define CHNL_ACTIVE				0x760
+#define     CHNL_ACTIVE__CHANNEL0			BIT(0)
+#define     CHNL_ACTIVE__CHANNEL1			BIT(1)
+#define     CHNL_ACTIVE__CHANNEL2			BIT(2)
+#define     CHNL_ACTIVE__CHANNEL3			BIT(3)
+
+struct denali_nand_info {
+	struct nand_chip nand;
+	unsigned long clk_x_rate;	/* bus interface clock rate */
+	int active_bank;		/* currently selected bank */
+	struct device *dev;
+	void __iomem *reg;		/* Register Interface */
+	void __iomem *host;		/* Host Data/Command Interface */
+	struct completion complete;
+	spinlock_t irq_lock;		/* protect irq_mask and irq_status */
+	u32 irq_mask;			/* interrupts we are waiting for */
+	u32 irq_status;			/* interrupts that have happened */
+	int irq;
+	void *buf;			/* for syndrome layout conversion */
+	dma_addr_t dma_addr;
+	int dma_avail;			/* can support DMA? */
+	int devs_per_cs;		/* devices connected in parallel */
+	int oob_skip_bytes;		/* number of bytes reserved for BBM */
+	int max_banks;
+	unsigned int revision;		/* IP revision */
+	unsigned int caps;		/* IP capability (or quirk) */
+	const struct nand_ecc_caps *ecc_caps;
+	u32 (*host_read)(struct denali_nand_info *denali, u32 addr);
+	void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data);
+	void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr,
+			  int page, int write);
+};
+
+#define DENALI_CAP_HW_ECC_FIXUP			BIT(0)
+#define DENALI_CAP_DMA_64BIT			BIT(1)
+
+int denali_calc_ecc_bytes(int step_size, int strength);
+int denali_init(struct denali_nand_info *denali);
+void denali_remove(struct denali_nand_info *denali);
+
+#endif /* __DENALI_H__ */
diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
new file mode 100644
index 000000000000..cfd33e6ca77f
--- /dev/null
+++ b/drivers/mtd/nand/raw/denali_dt.c
@@ -0,0 +1,163 @@
+/*
+ * NAND Flash Controller Device Driver for DT
+ *
+ * Copyright © 2011, Picochip.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "denali.h"
+
+struct denali_dt {
+	struct denali_nand_info	denali;
+	struct clk		*clk;
+};
+
+struct denali_dt_data {
+	unsigned int revision;
+	unsigned int caps;
+	const struct nand_ecc_caps *ecc_caps;
+};
+
+NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
+		     512, 8, 15);
+static const struct denali_dt_data denali_socfpga_data = {
+	.caps = DENALI_CAP_HW_ECC_FIXUP,
+	.ecc_caps = &denali_socfpga_ecc_caps,
+};
+
+NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
+		     1024, 8, 16, 24);
+static const struct denali_dt_data denali_uniphier_v5a_data = {
+	.caps = DENALI_CAP_HW_ECC_FIXUP |
+		DENALI_CAP_DMA_64BIT,
+	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
+};
+
+NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
+		     1024, 8, 16);
+static const struct denali_dt_data denali_uniphier_v5b_data = {
+	.revision = 0x0501,
+	.caps = DENALI_CAP_HW_ECC_FIXUP |
+		DENALI_CAP_DMA_64BIT,
+	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
+};
+
+static const struct of_device_id denali_nand_dt_ids[] = {
+	{
+		.compatible = "altr,socfpga-denali-nand",
+		.data = &denali_socfpga_data,
+	},
+	{
+		.compatible = "socionext,uniphier-denali-nand-v5a",
+		.data = &denali_uniphier_v5a_data,
+	},
+	{
+		.compatible = "socionext,uniphier-denali-nand-v5b",
+		.data = &denali_uniphier_v5b_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
+
+static int denali_dt_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct denali_dt *dt;
+	const struct denali_dt_data *data;
+	struct denali_nand_info *denali;
+	int ret;
+
+	dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
+	if (!dt)
+		return -ENOMEM;
+	denali = &dt->denali;
+
+	data = of_device_get_match_data(&pdev->dev);
+	if (data) {
+		denali->revision = data->revision;
+		denali->caps = data->caps;
+		denali->ecc_caps = data->ecc_caps;
+	}
+
+	denali->dev = &pdev->dev;
+	denali->irq = platform_get_irq(pdev, 0);
+	if (denali->irq < 0) {
+		dev_err(&pdev->dev, "no irq defined\n");
+		return denali->irq;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
+	denali->reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(denali->reg))
+		return PTR_ERR(denali->reg);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+	denali->host = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(denali->host))
+		return PTR_ERR(denali->host);
+
+	dt->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dt->clk)) {
+		dev_err(&pdev->dev, "no clk available\n");
+		return PTR_ERR(dt->clk);
+	}
+	ret = clk_prepare_enable(dt->clk);
+	if (ret)
+		return ret;
+
+	denali->clk_x_rate = clk_get_rate(dt->clk);
+
+	ret = denali_init(denali);
+	if (ret)
+		goto out_disable_clk;
+
+	platform_set_drvdata(pdev, dt);
+	return 0;
+
+out_disable_clk:
+	clk_disable_unprepare(dt->clk);
+
+	return ret;
+}
+
+static int denali_dt_remove(struct platform_device *pdev)
+{
+	struct denali_dt *dt = platform_get_drvdata(pdev);
+
+	denali_remove(&dt->denali);
+	clk_disable_unprepare(dt->clk);
+
+	return 0;
+}
+
+static struct platform_driver denali_dt_driver = {
+	.probe		= denali_dt_probe,
+	.remove		= denali_dt_remove,
+	.driver		= {
+		.name	= "denali-nand-dt",
+		.of_match_table	= denali_nand_dt_ids,
+	},
+};
+module_platform_driver(denali_dt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("DT driver for Denali NAND controller");
diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c
new file mode 100644
index 000000000000..49cb3e1f8bd0
--- /dev/null
+++ b/drivers/mtd/nand/raw/denali_pci.c
@@ -0,0 +1,131 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright © 2009-2010, Intel Corporation and its suppliers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "denali.h"
+
+#define DENALI_NAND_NAME    "denali-nand-pci"
+
+#define INTEL_CE4100	1
+#define INTEL_MRST	2
+
+/* List of platforms this NAND controller has be integrated into */
+static const struct pci_device_id denali_pci_ids[] = {
+	{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
+	{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
+	{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, denali_pci_ids);
+
+NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);
+
+static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int ret;
+	resource_size_t csr_base, mem_base;
+	unsigned long csr_len, mem_len;
+	struct denali_nand_info *denali;
+
+	denali = devm_kzalloc(&dev->dev, sizeof(*denali), GFP_KERNEL);
+	if (!denali)
+		return -ENOMEM;
+
+	ret = pcim_enable_device(dev);
+	if (ret) {
+		dev_err(&dev->dev, "Spectra: pci_enable_device failed.\n");
+		return ret;
+	}
+
+	if (id->driver_data == INTEL_CE4100) {
+		mem_base = pci_resource_start(dev, 0);
+		mem_len = pci_resource_len(dev, 1);
+		csr_base = pci_resource_start(dev, 1);
+		csr_len = pci_resource_len(dev, 1);
+	} else {
+		csr_base = pci_resource_start(dev, 0);
+		csr_len = pci_resource_len(dev, 0);
+		mem_base = pci_resource_start(dev, 1);
+		mem_len = pci_resource_len(dev, 1);
+		if (!mem_len) {
+			mem_base = csr_base + csr_len;
+			mem_len = csr_len;
+		}
+	}
+
+	pci_set_master(dev);
+	denali->dev = &dev->dev;
+	denali->irq = dev->irq;
+	denali->ecc_caps = &denali_pci_ecc_caps;
+	denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
+	denali->clk_x_rate = 200000000;		/* 200 MHz */
+
+	ret = pci_request_regions(dev, DENALI_NAND_NAME);
+	if (ret) {
+		dev_err(&dev->dev, "Spectra: Unable to request memory regions\n");
+		return ret;
+	}
+
+	denali->reg = ioremap_nocache(csr_base, csr_len);
+	if (!denali->reg) {
+		dev_err(&dev->dev, "Spectra: Unable to remap memory region\n");
+		return -ENOMEM;
+	}
+
+	denali->host = ioremap_nocache(mem_base, mem_len);
+	if (!denali->host) {
+		dev_err(&dev->dev, "Spectra: ioremap_nocache failed!");
+		ret = -ENOMEM;
+		goto failed_remap_reg;
+	}
+
+	ret = denali_init(denali);
+	if (ret)
+		goto failed_remap_mem;
+
+	pci_set_drvdata(dev, denali);
+
+	return 0;
+
+failed_remap_mem:
+	iounmap(denali->host);
+failed_remap_reg:
+	iounmap(denali->reg);
+	return ret;
+}
+
+static void denali_pci_remove(struct pci_dev *dev)
+{
+	struct denali_nand_info *denali = pci_get_drvdata(dev);
+
+	denali_remove(denali);
+	iounmap(denali->reg);
+	iounmap(denali->host);
+}
+
+static struct pci_driver denali_pci_driver = {
+	.name = DENALI_NAND_NAME,
+	.id_table = denali_pci_ids,
+	.probe = denali_pci_probe,
+	.remove = denali_pci_remove,
+};
+module_pci_driver(denali_pci_driver);
+
+MODULE_DESCRIPTION("PCI driver for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
new file mode 100644
index 000000000000..1af77f798fe5
--- /dev/null
+++ b/drivers/mtd/nand/raw/diskonchip.c
@@ -0,0 +1,1709 @@
+/*
+ * (C) 2003 Red Hat, Inc.
+ * (C) 2004 Dan Brown <dan_brown@ieee.org>
+ * (C) 2004 Kalev Lember <kalev@smartlink.ee>
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
+ * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
+ *
+ * Error correction code lifted from the old docecc code
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
+ * Copyright (C) 2000 Netgem S.A.
+ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Interface to generic NAND code for M-Systems DiskOnChip devices
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/rslib.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/doc2000.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/inftl.h>
+#include <linux/module.h>
+
+/* Where to look for the devices? */
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
+#endif
+
+static unsigned long doc_locations[] __initdata = {
+#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
+	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
+	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
+	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
+	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
+	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
+#else
+	0xc8000, 0xca000, 0xcc000, 0xce000,
+	0xd0000, 0xd2000, 0xd4000, 0xd6000,
+	0xd8000, 0xda000, 0xdc000, 0xde000,
+	0xe0000, 0xe2000, 0xe4000, 0xe6000,
+	0xe8000, 0xea000, 0xec000, 0xee000,
+#endif
+#endif
+	0xffffffff };
+
+static struct mtd_info *doclist = NULL;
+
+struct doc_priv {
+	void __iomem *virtadr;
+	unsigned long physadr;
+	u_char ChipID;
+	u_char CDSNControl;
+	int chips_per_floor;	/* The number of chips detected on each floor */
+	int curfloor;
+	int curchip;
+	int mh0_page;
+	int mh1_page;
+	struct mtd_info *nextdoc;
+
+	/* Handle the last stage of initialization (BBT scan, partitioning) */
+	int (*late_init)(struct mtd_info *mtd);
+};
+
+/* This is the ecc value computed by the HW ecc generator upon writing an empty
+   page, one with all 0xff for data. */
+static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
+
+#define INFTL_BBT_RESERVED_BLOCKS 4
+
+#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
+#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
+#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
+
+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+			      unsigned int bitmask);
+static void doc200x_select_chip(struct mtd_info *mtd, int chip);
+
+static int debug = 0;
+module_param(debug, int, 0);
+
+static int try_dword = 1;
+module_param(try_dword, int, 0);
+
+static int no_ecc_failures = 0;
+module_param(no_ecc_failures, int, 0);
+
+static int no_autopart = 0;
+module_param(no_autopart, int, 0);
+
+static int show_firmware_partition = 0;
+module_param(show_firmware_partition, int, 0);
+
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
+static int inftl_bbt_write = 1;
+#else
+static int inftl_bbt_write = 0;
+#endif
+module_param(inftl_bbt_write, int, 0);
+
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
+module_param(doc_config_location, ulong, 0);
+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
+
+/* Sector size for HW ECC */
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA 10 bit words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
+/* Number of roots */
+#define NROOTS 4
+/* First consective root */
+#define FCR 510
+/* Number of symbols */
+#define NN 1023
+
+/* the Reed Solomon control structure */
+static struct rs_control *rs_decoder;
+
+/*
+ * The HW decoder in the DoC ASIC's provides us a error syndrome,
+ * which we must convert to a standard syndrome usable by the generic
+ * Reed-Solomon library code.
+ *
+ * Fabrice Bellard figured this out in the old docecc code. I added
+ * some comments, improved a minor bit and converted it to make use
+ * of the generic Reed-Solomon library. tglx
+ */
+static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
+{
+	int i, j, nerr, errpos[8];
+	uint8_t parity;
+	uint16_t ds[4], s[5], tmp, errval[8], syn[4];
+
+	memset(syn, 0, sizeof(syn));
+	/* Convert the ecc bytes into words */
+	ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
+	ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
+	ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
+	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
+	parity = ecc[1];
+
+	/* Initialize the syndrome buffer */
+	for (i = 0; i < NROOTS; i++)
+		s[i] = ds[0];
+	/*
+	 *  Evaluate
+	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
+	 *  where x = alpha^(FCR + i)
+	 */
+	for (j = 1; j < NROOTS; j++) {
+		if (ds[j] == 0)
+			continue;
+		tmp = rs->index_of[ds[j]];
+		for (i = 0; i < NROOTS; i++)
+			s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
+	}
+
+	/* Calc syn[i] = s[i] / alpha^(v + i) */
+	for (i = 0; i < NROOTS; i++) {
+		if (s[i])
+			syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
+	}
+	/* Call the decoder library */
+	nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
+
+	/* Incorrectable errors ? */
+	if (nerr < 0)
+		return nerr;
+
+	/*
+	 * Correct the errors. The bitpositions are a bit of magic,
+	 * but they are given by the design of the de/encoder circuit
+	 * in the DoC ASIC's.
+	 */
+	for (i = 0; i < nerr; i++) {
+		int index, bitpos, pos = 1015 - errpos[i];
+		uint8_t val;
+		if (pos >= NB_DATA && pos < 1019)
+			continue;
+		if (pos < NB_DATA) {
+			/* extract bit position (MSB first) */
+			pos = 10 * (NB_DATA - 1 - pos) - 6;
+			/* now correct the following 10 bits. At most two bytes
+			   can be modified since pos is even */
+			index = (pos >> 3) ^ 1;
+			bitpos = pos & 7;
+			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
+				val = (uint8_t) (errval[i] >> (2 + bitpos));
+				parity ^= val;
+				if (index < SECTOR_SIZE)
+					data[index] ^= val;
+			}
+			index = ((pos >> 3) + 1) ^ 1;
+			bitpos = (bitpos + 10) & 7;
+			if (bitpos == 0)
+				bitpos = 8;
+			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
+				val = (uint8_t) (errval[i] << (8 - bitpos));
+				parity ^= val;
+				if (index < SECTOR_SIZE)
+					data[index] ^= val;
+			}
+		}
+	}
+	/* If the parity is wrong, no rescue possible */
+	return parity ? -EBADMSG : nerr;
+}
+
+static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
+{
+	volatile char dummy;
+	int i;
+
+	for (i = 0; i < cycles; i++) {
+		if (DoC_is_Millennium(doc))
+			dummy = ReadDOC(doc->virtadr, NOP);
+		else if (DoC_is_MillenniumPlus(doc))
+			dummy = ReadDOC(doc->virtadr, Mplus_NOP);
+		else
+			dummy = ReadDOC(doc->virtadr, DOCStatus);
+	}
+
+}
+
+#define CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(struct doc_priv *doc)
+{
+	void __iomem *docptr = doc->virtadr;
+	unsigned long timeo = jiffies + (HZ * 10);
+
+	if (debug)
+		printk("_DoC_WaitReady...\n");
+	/* Out-of-line routine to wait for chip response */
+	if (DoC_is_MillenniumPlus(doc)) {
+		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
+			if (time_after(jiffies, timeo)) {
+				printk("_DoC_WaitReady timed out.\n");
+				return -EIO;
+			}
+			udelay(1);
+			cond_resched();
+		}
+	} else {
+		while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+			if (time_after(jiffies, timeo)) {
+				printk("_DoC_WaitReady timed out.\n");
+				return -EIO;
+			}
+			udelay(1);
+			cond_resched();
+		}
+	}
+
+	return 0;
+}
+
+static inline int DoC_WaitReady(struct doc_priv *doc)
+{
+	void __iomem *docptr = doc->virtadr;
+	int ret = 0;
+
+	if (DoC_is_MillenniumPlus(doc)) {
+		DoC_Delay(doc, 4);
+
+		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
+			/* Call the out-of-line routine to wait */
+			ret = _DoC_WaitReady(doc);
+	} else {
+		DoC_Delay(doc, 4);
+
+		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+			/* Call the out-of-line routine to wait */
+			ret = _DoC_WaitReady(doc);
+		DoC_Delay(doc, 2);
+	}
+
+	if (debug)
+		printk("DoC_WaitReady OK\n");
+	return ret;
+}
+
+static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	if (debug)
+		printk("write_byte %02x\n", datum);
+	WriteDOC(datum, docptr, CDSNSlowIO);
+	WriteDOC(datum, docptr, 2k_CDSN_IO);
+}
+
+static u_char doc2000_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	u_char ret;
+
+	ReadDOC(docptr, CDSNSlowIO);
+	DoC_Delay(doc, 2);
+	ret = ReadDOC(docptr, 2k_CDSN_IO);
+	if (debug)
+		printk("read_byte returns %02x\n", ret);
+	return ret;
+}
+
+static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+	if (debug)
+		printk("writebuf of %d bytes: ", len);
+	for (i = 0; i < len; i++) {
+		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
+		if (debug && i < 16)
+			printk("%02x ", buf[i]);
+	}
+	if (debug)
+		printk("\n");
+}
+
+static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	if (debug)
+		printk("readbuf of %d bytes: ", len);
+
+	for (i = 0; i < len; i++) {
+		buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
+	}
+}
+
+static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	if (debug)
+		printk("readbuf_dword of %d bytes: ", len);
+
+	if (unlikely((((unsigned long)buf) | len) & 3)) {
+		for (i = 0; i < len; i++) {
+			*(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
+		}
+	} else {
+		for (i = 0; i < len; i += 4) {
+			*(uint32_t *) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
+		}
+	}
+}
+
+static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	uint16_t ret;
+
+	doc200x_select_chip(mtd, nr);
+	doc200x_hwcontrol(mtd, NAND_CMD_READID,
+			  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+	doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	/* We can't use dev_ready here, but at least we wait for the
+	 * command to complete
+	 */
+	udelay(50);
+
+	ret = this->read_byte(mtd) << 8;
+	ret |= this->read_byte(mtd);
+
+	if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
+		/* First chip probe. See if we get same results by 32-bit access */
+		union {
+			uint32_t dword;
+			uint8_t byte[4];
+		} ident;
+		void __iomem *docptr = doc->virtadr;
+
+		doc200x_hwcontrol(mtd, NAND_CMD_READID,
+				  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+		doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+		doc200x_hwcontrol(mtd, NAND_CMD_NONE,
+				  NAND_NCE | NAND_CTRL_CHANGE);
+
+		udelay(50);
+
+		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
+		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
+			printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
+			this->read_buf = &doc2000_readbuf_dword;
+		}
+	}
+
+	return ret;
+}
+
+static void __init doc2000_count_chips(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	uint16_t mfrid;
+	int i;
+
+	/* Max 4 chips per floor on DiskOnChip 2000 */
+	doc->chips_per_floor = 4;
+
+	/* Find out what the first chip is */
+	mfrid = doc200x_ident_chip(mtd, 0);
+
+	/* Find how many chips in each floor. */
+	for (i = 1; i < 4; i++) {
+		if (doc200x_ident_chip(mtd, i) != mfrid)
+			break;
+	}
+	doc->chips_per_floor = i;
+	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
+}
+
+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
+{
+	struct doc_priv *doc = nand_get_controller_data(this);
+
+	int status;
+
+	DoC_WaitReady(doc);
+	nand_status_op(this, NULL);
+	DoC_WaitReady(doc);
+	status = (int)this->read_byte(mtd);
+
+	return status;
+}
+
+static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	WriteDOC(datum, docptr, CDSNSlowIO);
+	WriteDOC(datum, docptr, Mil_CDSN_IO);
+	WriteDOC(datum, docptr, WritePipeTerm);
+}
+
+static u_char doc2001_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	//ReadDOC(docptr, CDSNSlowIO);
+	/* 11.4.5 -- delay twice to allow extended length cycle */
+	DoC_Delay(doc, 2);
+	ReadDOC(docptr, ReadPipeInit);
+	//return ReadDOC(docptr, Mil_CDSN_IO);
+	return ReadDOC(docptr, LastDataRead);
+}
+
+static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	for (i = 0; i < len; i++)
+		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
+	/* Terminate write pipeline */
+	WriteDOC(0x00, docptr, WritePipeTerm);
+}
+
+static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	/* Start read pipeline */
+	ReadDOC(docptr, ReadPipeInit);
+
+	for (i = 0; i < len - 1; i++)
+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
+
+	/* Terminate read pipeline */
+	buf[i] = ReadDOC(docptr, LastDataRead);
+}
+
+static u_char doc2001plus_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	u_char ret;
+
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+	ret = ReadDOC(docptr, Mplus_LastDataRead);
+	if (debug)
+		printk("read_byte returns %02x\n", ret);
+	return ret;
+}
+
+static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	if (debug)
+		printk("writebuf of %d bytes: ", len);
+	for (i = 0; i < len; i++) {
+		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
+		if (debug && i < 16)
+			printk("%02x ", buf[i]);
+	}
+	if (debug)
+		printk("\n");
+}
+
+static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	if (debug)
+		printk("readbuf of %d bytes: ", len);
+
+	/* Start read pipeline */
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+
+	for (i = 0; i < len - 2; i++) {
+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
+		if (debug && i < 16)
+			printk("%02x ", buf[i]);
+	}
+
+	/* Terminate read pipeline */
+	buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
+	if (debug && i < 16)
+		printk("%02x ", buf[len - 2]);
+	buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
+	if (debug && i < 16)
+		printk("%02x ", buf[len - 1]);
+	if (debug)
+		printk("\n");
+}
+
+static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int floor = 0;
+
+	if (debug)
+		printk("select chip (%d)\n", chip);
+
+	if (chip == -1) {
+		/* Disable flash internally */
+		WriteDOC(0, docptr, Mplus_FlashSelect);
+		return;
+	}
+
+	floor = chip / doc->chips_per_floor;
+	chip -= (floor * doc->chips_per_floor);
+
+	/* Assert ChipEnable and deassert WriteProtect */
+	WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
+	nand_reset_op(this);
+
+	doc->curchip = chip;
+	doc->curfloor = floor;
+}
+
+static void doc200x_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int floor = 0;
+
+	if (debug)
+		printk("select chip (%d)\n", chip);
+
+	if (chip == -1)
+		return;
+
+	floor = chip / doc->chips_per_floor;
+	chip -= (floor * doc->chips_per_floor);
+
+	/* 11.4.4 -- deassert CE before changing chip */
+	doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+
+	WriteDOC(floor, docptr, FloorSelect);
+	WriteDOC(chip, docptr, CDSNDeviceSelect);
+
+	doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	doc->curchip = chip;
+	doc->curfloor = floor;
+}
+
+#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
+
+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+			      unsigned int ctrl)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		doc->CDSNControl &= ~CDSN_CTRL_MSK;
+		doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
+		if (debug)
+			printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
+		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+		/* 11.4.3 -- 4 NOPs after CSDNControl write */
+		DoC_Delay(doc, 4);
+	}
+	if (cmd != NAND_CMD_NONE) {
+		if (DoC_is_2000(doc))
+			doc2000_write_byte(mtd, cmd);
+		else
+			doc2001_write_byte(mtd, cmd);
+	}
+}
+
+static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	/*
+	 * Must terminate write pipeline before sending any commands
+	 * to the device.
+	 */
+	if (command == NAND_CMD_PAGEPROG) {
+		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+	}
+
+	/*
+	 * Write out the command to the device.
+	 */
+	if (command == NAND_CMD_SEQIN) {
+		int readcmd;
+
+		if (column >= mtd->writesize) {
+			/* OOB area */
+			column -= mtd->writesize;
+			readcmd = NAND_CMD_READOOB;
+		} else if (column < 256) {
+			/* First 256 bytes --> READ0 */
+			readcmd = NAND_CMD_READ0;
+		} else {
+			column -= 256;
+			readcmd = NAND_CMD_READ1;
+		}
+		WriteDOC(readcmd, docptr, Mplus_FlashCmd);
+	}
+	WriteDOC(command, docptr, Mplus_FlashCmd);
+	WriteDOC(0, docptr, Mplus_WritePipeTerm);
+	WriteDOC(0, docptr, Mplus_WritePipeTerm);
+
+	if (column != -1 || page_addr != -1) {
+		/* Serially input address */
+		if (column != -1) {
+			/* Adjust columns for 16 bit buswidth */
+			if (this->options & NAND_BUSWIDTH_16 &&
+					!nand_opcode_8bits(command))
+				column >>= 1;
+			WriteDOC(column, docptr, Mplus_FlashAddress);
+		}
+		if (page_addr != -1) {
+			WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress);
+			WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
+			if (this->options & NAND_ROW_ADDR_3) {
+				WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
+				printk("high density\n");
+			}
+		}
+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+		/* deassert ALE */
+		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+		    command == NAND_CMD_READOOB || command == NAND_CMD_READID)
+			WriteDOC(0, docptr, Mplus_FlashControl);
+	}
+
+	/*
+	 * program and erase have their own busy handlers
+	 * status and sequential in needs no delay
+	 */
+	switch (command) {
+
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+		return;
+
+	case NAND_CMD_RESET:
+		if (this->dev_ready)
+			break;
+		udelay(this->chip_delay);
+		WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
+		while (!(this->read_byte(mtd) & 0x40)) ;
+		return;
+
+		/* This applies to read commands */
+	default:
+		/*
+		 * If we don't have access to the busy pin, we apply the given
+		 * command delay
+		 */
+		if (!this->dev_ready) {
+			udelay(this->chip_delay);
+			return;
+		}
+	}
+
+	/* Apply this short delay always to ensure that we do wait tWB in
+	 * any case on any machine. */
+	ndelay(100);
+	/* wait until command is processed */
+	while (!this->dev_ready(mtd)) ;
+}
+
+static int doc200x_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	if (DoC_is_MillenniumPlus(doc)) {
+		/* 11.4.2 -- must NOP four times before checking FR/B# */
+		DoC_Delay(doc, 4);
+		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
+			if (debug)
+				printk("not ready\n");
+			return 0;
+		}
+		if (debug)
+			printk("was ready\n");
+		return 1;
+	} else {
+		/* 11.4.2 -- must NOP four times before checking FR/B# */
+		DoC_Delay(doc, 4);
+		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+			if (debug)
+				printk("not ready\n");
+			return 0;
+		}
+		/* 11.4.2 -- Must NOP twice if it's ready */
+		DoC_Delay(doc, 2);
+		if (debug)
+			printk("was ready\n");
+		return 1;
+	}
+}
+
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
+{
+	/* This is our last resort if we couldn't find or create a BBT.  Just
+	   pretend all blocks are good. */
+	return 0;
+}
+
+static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	/* Prime the ECC engine */
+	switch (mode) {
+	case NAND_ECC_READ:
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+		break;
+	case NAND_ECC_WRITE:
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+		break;
+	}
+}
+
+static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+
+	/* Prime the ECC engine */
+	switch (mode) {
+	case NAND_ECC_READ:
+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
+		break;
+	case NAND_ECC_WRITE:
+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+		break;
+	}
+}
+
+/* This code is only called on write */
+static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+	int emptymatch = 1;
+
+	/* flush the pipeline */
+	if (DoC_is_2000(doc)) {
+		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
+		WriteDOC(0, docptr, 2k_CDSN_IO);
+		WriteDOC(0, docptr, 2k_CDSN_IO);
+		WriteDOC(0, docptr, 2k_CDSN_IO);
+		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
+	} else if (DoC_is_MillenniumPlus(doc)) {
+		WriteDOC(0, docptr, Mplus_NOP);
+		WriteDOC(0, docptr, Mplus_NOP);
+		WriteDOC(0, docptr, Mplus_NOP);
+	} else {
+		WriteDOC(0, docptr, NOP);
+		WriteDOC(0, docptr, NOP);
+		WriteDOC(0, docptr, NOP);
+	}
+
+	for (i = 0; i < 6; i++) {
+		if (DoC_is_MillenniumPlus(doc))
+			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
+		else
+			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+		if (ecc_code[i] != empty_write_ecc[i])
+			emptymatch = 0;
+	}
+	if (DoC_is_MillenniumPlus(doc))
+		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+	else
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+#if 0
+	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
+	if (emptymatch) {
+		/* Note: this somewhat expensive test should not be triggered
+		   often.  It could be optimized away by examining the data in
+		   the writebuf routine, and remembering the result. */
+		for (i = 0; i < 512; i++) {
+			if (dat[i] == 0xff)
+				continue;
+			emptymatch = 0;
+			break;
+		}
+	}
+	/* If emptymatch still =1, we do have an all-0xff data buffer.
+	   Return all-0xff ecc value instead of the computed one, so
+	   it'll look just like a freshly-erased page. */
+	if (emptymatch)
+		memset(ecc_code, 0xff, 6);
+#endif
+	return 0;
+}
+
+static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
+				u_char *read_ecc, u_char *isnull)
+{
+	int i, ret = 0;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	void __iomem *docptr = doc->virtadr;
+	uint8_t calc_ecc[6];
+	volatile u_char dummy;
+
+	/* flush the pipeline */
+	if (DoC_is_2000(doc)) {
+		dummy = ReadDOC(docptr, 2k_ECCStatus);
+		dummy = ReadDOC(docptr, 2k_ECCStatus);
+		dummy = ReadDOC(docptr, 2k_ECCStatus);
+	} else if (DoC_is_MillenniumPlus(doc)) {
+		dummy = ReadDOC(docptr, Mplus_ECCConf);
+		dummy = ReadDOC(docptr, Mplus_ECCConf);
+		dummy = ReadDOC(docptr, Mplus_ECCConf);
+	} else {
+		dummy = ReadDOC(docptr, ECCConf);
+		dummy = ReadDOC(docptr, ECCConf);
+		dummy = ReadDOC(docptr, ECCConf);
+	}
+
+	/* Error occurred ? */
+	if (dummy & 0x80) {
+		for (i = 0; i < 6; i++) {
+			if (DoC_is_MillenniumPlus(doc))
+				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
+			else
+				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
+		}
+
+		ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
+		if (ret > 0)
+			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
+	}
+	if (DoC_is_MillenniumPlus(doc))
+		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+	else
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+	if (no_ecc_failures && mtd_is_eccerr(ret)) {
+		printk(KERN_ERR "suppressing ECC failure\n");
+		ret = 0;
+	}
+	return ret;
+}
+
+//u_char mydatabuf[528];
+
+static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = 6;
+
+	return 0;
+}
+
+static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	/*
+	 * The strange out-of-order free bytes definition is a (possibly
+	 * unneeded) attempt to retain compatibility.  It used to read:
+	 *	.oobfree = { {8, 8} }
+	 * Since that leaves two bytes unusable, it was changed.  But the
+	 * following scheme might affect existing jffs2 installs by moving the
+	 * cleanmarker:
+	 *	.oobfree = { {6, 10} }
+	 * jffs2 seems to handle the above gracefully, but the current scheme
+	 * seems safer. The only problem with it is that any code retrieving
+	 * free bytes position must be able to handle out-of-order segments.
+	 */
+	if (!section) {
+		oobregion->offset = 8;
+		oobregion->length = 8;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = 2;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
+	.ecc = doc200x_ooblayout_ecc,
+	.free = doc200x_ooblayout_free,
+};
+
+/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
+   On successful return, buf will contain a copy of the media header for
+   further processing.  id is the string to scan for, and will presumably be
+   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
+   header.  The page #s of the found media headers are placed in mh0_page and
+   mh1_page in the DOC private structure. */
+static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	unsigned offs;
+	int ret;
+	size_t retlen;
+
+	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
+		ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
+		if (retlen != mtd->writesize)
+			continue;
+		if (ret) {
+			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
+		}
+		if (memcmp(buf, id, 6))
+			continue;
+		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
+		if (doc->mh0_page == -1) {
+			doc->mh0_page = offs >> this->page_shift;
+			if (!findmirror)
+				return 1;
+			continue;
+		}
+		doc->mh1_page = offs >> this->page_shift;
+		return 2;
+	}
+	if (doc->mh0_page == -1) {
+		printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
+		return 0;
+	}
+	/* Only one mediaheader was found.  We want buf to contain a
+	   mediaheader on return, so we'll have to re-read the one we found. */
+	offs = doc->mh0_page << this->page_shift;
+	ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
+	if (retlen != mtd->writesize) {
+		/* Insanity.  Give up. */
+		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
+		return 0;
+	}
+	return 1;
+}
+
+static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	int ret = 0;
+	u_char *buf;
+	struct NFTLMediaHeader *mh;
+	const unsigned psize = 1 << this->page_shift;
+	int numparts = 0;
+	unsigned blocks, maxblocks;
+	int offs, numheaders;
+
+	buf = kmalloc(mtd->writesize, GFP_KERNEL);
+	if (!buf) {
+		return 0;
+	}
+	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
+		goto out;
+	mh = (struct NFTLMediaHeader *)buf;
+
+	le16_to_cpus(&mh->NumEraseUnits);
+	le16_to_cpus(&mh->FirstPhysicalEUN);
+	le32_to_cpus(&mh->FormattedSize);
+
+	printk(KERN_INFO "    DataOrgID        = %s\n"
+			 "    NumEraseUnits    = %d\n"
+			 "    FirstPhysicalEUN = %d\n"
+			 "    FormattedSize    = %d\n"
+			 "    UnitSizeFactor   = %d\n",
+		mh->DataOrgID, mh->NumEraseUnits,
+		mh->FirstPhysicalEUN, mh->FormattedSize,
+		mh->UnitSizeFactor);
+
+	blocks = mtd->size >> this->phys_erase_shift;
+	maxblocks = min(32768U, mtd->erasesize - psize);
+
+	if (mh->UnitSizeFactor == 0x00) {
+		/* Auto-determine UnitSizeFactor.  The constraints are:
+		   - There can be at most 32768 virtual blocks.
+		   - There can be at most (virtual block size - page size)
+		   virtual blocks (because MediaHeader+BBT must fit in 1).
+		 */
+		mh->UnitSizeFactor = 0xff;
+		while (blocks > maxblocks) {
+			blocks >>= 1;
+			maxblocks = min(32768U, (maxblocks << 1) + psize);
+			mh->UnitSizeFactor--;
+		}
+		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
+	}
+
+	/* NOTE: The lines below modify internal variables of the NAND and MTD
+	   layers; variables with have already been configured by nand_scan.
+	   Unfortunately, we didn't know before this point what these values
+	   should be.  Thus, this code is somewhat dependent on the exact
+	   implementation of the NAND layer.  */
+	if (mh->UnitSizeFactor != 0xff) {
+		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
+		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
+		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
+		blocks = mtd->size >> this->bbt_erase_shift;
+		maxblocks = min(32768U, mtd->erasesize - psize);
+	}
+
+	if (blocks > maxblocks) {
+		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
+		goto out;
+	}
+
+	/* Skip past the media headers. */
+	offs = max(doc->mh0_page, doc->mh1_page);
+	offs <<= this->page_shift;
+	offs += mtd->erasesize;
+
+	if (show_firmware_partition == 1) {
+		parts[0].name = " DiskOnChip Firmware / Media Header partition";
+		parts[0].offset = 0;
+		parts[0].size = offs;
+		numparts = 1;
+	}
+
+	parts[numparts].name = " DiskOnChip BDTL partition";
+	parts[numparts].offset = offs;
+	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+	offs += parts[numparts].size;
+	numparts++;
+
+	if (offs < mtd->size) {
+		parts[numparts].name = " DiskOnChip Remainder partition";
+		parts[numparts].offset = offs;
+		parts[numparts].size = mtd->size - offs;
+		numparts++;
+	}
+
+	ret = numparts;
+ out:
+	kfree(buf);
+	return ret;
+}
+
+/* This is a stripped-down copy of the code in inftlmount.c */
+static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	int ret = 0;
+	u_char *buf;
+	struct INFTLMediaHeader *mh;
+	struct INFTLPartition *ip;
+	int numparts = 0;
+	int blocks;
+	int vshift, lastvunit = 0;
+	int i;
+	int end = mtd->size;
+
+	if (inftl_bbt_write)
+		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
+
+	buf = kmalloc(mtd->writesize, GFP_KERNEL);
+	if (!buf) {
+		return 0;
+	}
+
+	if (!find_media_headers(mtd, buf, "BNAND", 0))
+		goto out;
+	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
+	mh = (struct INFTLMediaHeader *)buf;
+
+	le32_to_cpus(&mh->NoOfBootImageBlocks);
+	le32_to_cpus(&mh->NoOfBinaryPartitions);
+	le32_to_cpus(&mh->NoOfBDTLPartitions);
+	le32_to_cpus(&mh->BlockMultiplierBits);
+	le32_to_cpus(&mh->FormatFlags);
+	le32_to_cpus(&mh->PercentUsed);
+
+	printk(KERN_INFO "    bootRecordID          = %s\n"
+			 "    NoOfBootImageBlocks   = %d\n"
+			 "    NoOfBinaryPartitions  = %d\n"
+			 "    NoOfBDTLPartitions    = %d\n"
+			 "    BlockMultiplerBits    = %d\n"
+			 "    FormatFlgs            = %d\n"
+			 "    OsakVersion           = %d.%d.%d.%d\n"
+			 "    PercentUsed           = %d\n",
+		mh->bootRecordID, mh->NoOfBootImageBlocks,
+		mh->NoOfBinaryPartitions,
+		mh->NoOfBDTLPartitions,
+		mh->BlockMultiplierBits, mh->FormatFlags,
+		((unsigned char *) &mh->OsakVersion)[0] & 0xf,
+		((unsigned char *) &mh->OsakVersion)[1] & 0xf,
+		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
+		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
+		mh->PercentUsed);
+
+	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
+
+	blocks = mtd->size >> vshift;
+	if (blocks > 32768) {
+		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
+		goto out;
+	}
+
+	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
+	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
+		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
+		goto out;
+	}
+
+	/* Scan the partitions */
+	for (i = 0; (i < 4); i++) {
+		ip = &(mh->Partitions[i]);
+		le32_to_cpus(&ip->virtualUnits);
+		le32_to_cpus(&ip->firstUnit);
+		le32_to_cpus(&ip->lastUnit);
+		le32_to_cpus(&ip->flags);
+		le32_to_cpus(&ip->spareUnits);
+		le32_to_cpus(&ip->Reserved0);
+
+		printk(KERN_INFO	"    PARTITION[%d] ->\n"
+			"        virtualUnits    = %d\n"
+			"        firstUnit       = %d\n"
+			"        lastUnit        = %d\n"
+			"        flags           = 0x%x\n"
+			"        spareUnits      = %d\n",
+			i, ip->virtualUnits, ip->firstUnit,
+			ip->lastUnit, ip->flags,
+			ip->spareUnits);
+
+		if ((show_firmware_partition == 1) &&
+		    (i == 0) && (ip->firstUnit > 0)) {
+			parts[0].name = " DiskOnChip IPL / Media Header partition";
+			parts[0].offset = 0;
+			parts[0].size = mtd->erasesize * ip->firstUnit;
+			numparts = 1;
+		}
+
+		if (ip->flags & INFTL_BINARY)
+			parts[numparts].name = " DiskOnChip BDK partition";
+		else
+			parts[numparts].name = " DiskOnChip BDTL partition";
+		parts[numparts].offset = ip->firstUnit << vshift;
+		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
+		numparts++;
+		if (ip->lastUnit > lastvunit)
+			lastvunit = ip->lastUnit;
+		if (ip->flags & INFTL_LAST)
+			break;
+	}
+	lastvunit++;
+	if ((lastvunit << vshift) < end) {
+		parts[numparts].name = " DiskOnChip Remainder partition";
+		parts[numparts].offset = lastvunit << vshift;
+		parts[numparts].size = end - parts[numparts].offset;
+		numparts++;
+	}
+	ret = numparts;
+ out:
+	kfree(buf);
+	return ret;
+}
+
+static int __init nftl_scan_bbt(struct mtd_info *mtd)
+{
+	int ret, numparts;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	struct mtd_partition parts[2];
+
+	memset((char *)parts, 0, sizeof(parts));
+	/* On NFTL, we have to find the media headers before we can read the
+	   BBTs, since they're stored in the media header eraseblocks. */
+	numparts = nftl_partscan(mtd, parts);
+	if (!numparts)
+		return -EIO;
+	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+				NAND_BBT_VERSION;
+	this->bbt_td->veroffs = 7;
+	this->bbt_td->pages[0] = doc->mh0_page + 1;
+	if (doc->mh1_page != -1) {
+		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
+					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
+					NAND_BBT_VERSION;
+		this->bbt_md->veroffs = 7;
+		this->bbt_md->pages[0] = doc->mh1_page + 1;
+	} else {
+		this->bbt_md = NULL;
+	}
+
+	ret = this->scan_bbt(mtd);
+	if (ret)
+		return ret;
+
+	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
+}
+
+static int __init inftl_scan_bbt(struct mtd_info *mtd)
+{
+	int ret, numparts;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+	struct mtd_partition parts[5];
+
+	if (this->numchips > doc->chips_per_floor) {
+		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
+		return -EIO;
+	}
+
+	if (DoC_is_MillenniumPlus(doc)) {
+		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
+		if (inftl_bbt_write)
+			this->bbt_td->options |= NAND_BBT_WRITE;
+		this->bbt_td->pages[0] = 2;
+		this->bbt_md = NULL;
+	} else {
+		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
+		if (inftl_bbt_write)
+			this->bbt_td->options |= NAND_BBT_WRITE;
+		this->bbt_td->offs = 8;
+		this->bbt_td->len = 8;
+		this->bbt_td->veroffs = 7;
+		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+		this->bbt_td->reserved_block_code = 0x01;
+		this->bbt_td->pattern = "MSYS_BBT";
+
+		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
+		if (inftl_bbt_write)
+			this->bbt_md->options |= NAND_BBT_WRITE;
+		this->bbt_md->offs = 8;
+		this->bbt_md->len = 8;
+		this->bbt_md->veroffs = 7;
+		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
+		this->bbt_md->reserved_block_code = 0x01;
+		this->bbt_md->pattern = "TBB_SYSM";
+	}
+
+	ret = this->scan_bbt(mtd);
+	if (ret)
+		return ret;
+
+	memset((char *)parts, 0, sizeof(parts));
+	numparts = inftl_partscan(mtd, parts);
+	/* At least for now, require the INFTL Media Header.  We could probably
+	   do without it for non-INFTL use, since all it gives us is
+	   autopartitioning, but I want to give it more thought. */
+	if (!numparts)
+		return -EIO;
+	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
+}
+
+static inline int __init doc2000_init(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+
+	this->read_byte = doc2000_read_byte;
+	this->write_buf = doc2000_writebuf;
+	this->read_buf = doc2000_readbuf;
+	doc->late_init = nftl_scan_bbt;
+
+	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
+	doc2000_count_chips(mtd);
+	mtd->name = "DiskOnChip 2000 (NFTL Model)";
+	return (4 * doc->chips_per_floor);
+}
+
+static inline int __init doc2001_init(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+
+	this->read_byte = doc2001_read_byte;
+	this->write_buf = doc2001_writebuf;
+	this->read_buf = doc2001_readbuf;
+
+	ReadDOC(doc->virtadr, ChipID);
+	ReadDOC(doc->virtadr, ChipID);
+	ReadDOC(doc->virtadr, ChipID);
+	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
+		/* It's not a Millennium; it's one of the newer
+		   DiskOnChip 2000 units with a similar ASIC.
+		   Treat it like a Millennium, except that it
+		   can have multiple chips. */
+		doc2000_count_chips(mtd);
+		mtd->name = "DiskOnChip 2000 (INFTL Model)";
+		doc->late_init = inftl_scan_bbt;
+		return (4 * doc->chips_per_floor);
+	} else {
+		/* Bog-standard Millennium */
+		doc->chips_per_floor = 1;
+		mtd->name = "DiskOnChip Millennium";
+		doc->late_init = nftl_scan_bbt;
+		return 1;
+	}
+}
+
+static inline int __init doc2001plus_init(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct doc_priv *doc = nand_get_controller_data(this);
+
+	this->read_byte = doc2001plus_read_byte;
+	this->write_buf = doc2001plus_writebuf;
+	this->read_buf = doc2001plus_readbuf;
+	doc->late_init = inftl_scan_bbt;
+	this->cmd_ctrl = NULL;
+	this->select_chip = doc2001plus_select_chip;
+	this->cmdfunc = doc2001plus_command;
+	this->ecc.hwctl = doc2001plus_enable_hwecc;
+
+	doc->chips_per_floor = 1;
+	mtd->name = "DiskOnChip Millennium Plus";
+
+	return 1;
+}
+
+static int __init doc_probe(unsigned long physadr)
+{
+	unsigned char ChipID;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	struct doc_priv *doc;
+	void __iomem *virtadr;
+	unsigned char save_control;
+	unsigned char tmp, tmpb, tmpc;
+	int reg, len, numchips;
+	int ret = 0;
+
+	if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
+		return -EBUSY;
+	virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
+	if (!virtadr) {
+		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
+		ret = -EIO;
+		goto error_ioremap;
+	}
+
+	/* It's not possible to cleanly detect the DiskOnChip - the
+	 * bootup procedure will put the device into reset mode, and
+	 * it's not possible to talk to it without actually writing
+	 * to the DOCControl register. So we store the current contents
+	 * of the DOCControl register's location, in case we later decide
+	 * that it's not a DiskOnChip, and want to put it back how we
+	 * found it.
+	 */
+	save_control = ReadDOC(virtadr, DOCControl);
+
+	/* Reset the DiskOnChip ASIC */
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
+
+	/* Enable the DiskOnChip ASIC */
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
+
+	ChipID = ReadDOC(virtadr, ChipID);
+
+	switch (ChipID) {
+	case DOC_ChipID_Doc2k:
+		reg = DoC_2k_ECCStatus;
+		break;
+	case DOC_ChipID_DocMil:
+		reg = DoC_ECCConf;
+		break;
+	case DOC_ChipID_DocMilPlus16:
+	case DOC_ChipID_DocMilPlus32:
+	case 0:
+		/* Possible Millennium Plus, need to do more checks */
+		/* Possibly release from power down mode */
+		for (tmp = 0; (tmp < 4); tmp++)
+			ReadDOC(virtadr, Mplus_Power);
+
+		/* Reset the Millennium Plus ASIC */
+		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
+		WriteDOC(tmp, virtadr, Mplus_DOCControl);
+		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
+
+		mdelay(1);
+		/* Enable the Millennium Plus ASIC */
+		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
+		WriteDOC(tmp, virtadr, Mplus_DOCControl);
+		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
+		mdelay(1);
+
+		ChipID = ReadDOC(virtadr, ChipID);
+
+		switch (ChipID) {
+		case DOC_ChipID_DocMilPlus16:
+			reg = DoC_Mplus_Toggle;
+			break;
+		case DOC_ChipID_DocMilPlus32:
+			printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
+		default:
+			ret = -ENODEV;
+			goto notfound;
+		}
+		break;
+
+	default:
+		ret = -ENODEV;
+		goto notfound;
+	}
+	/* Check the TOGGLE bit in the ECC register */
+	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
+	if ((tmp == tmpb) || (tmp != tmpc)) {
+		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
+		ret = -ENODEV;
+		goto notfound;
+	}
+
+	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
+		unsigned char oldval;
+		unsigned char newval;
+		nand = mtd_to_nand(mtd);
+		doc = nand_get_controller_data(nand);
+		/* Use the alias resolution register to determine if this is
+		   in fact the same DOC aliased to a new address.  If writes
+		   to one chip's alias resolution register change the value on
+		   the other chip, they're the same chip. */
+		if (ChipID == DOC_ChipID_DocMilPlus16) {
+			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
+			newval = ReadDOC(virtadr, Mplus_AliasResolution);
+		} else {
+			oldval = ReadDOC(doc->virtadr, AliasResolution);
+			newval = ReadDOC(virtadr, AliasResolution);
+		}
+		if (oldval != newval)
+			continue;
+		if (ChipID == DOC_ChipID_DocMilPlus16) {
+			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
+			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
+			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it
+		} else {
+			WriteDOC(~newval, virtadr, AliasResolution);
+			oldval = ReadDOC(doc->virtadr, AliasResolution);
+			WriteDOC(newval, virtadr, AliasResolution);	// restore it
+		}
+		newval = ~newval;
+		if (oldval == newval) {
+			printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
+			goto notfound;
+		}
+	}
+
+	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
+
+	len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
+	      (2 * sizeof(struct nand_bbt_descr));
+	nand = kzalloc(len, GFP_KERNEL);
+	if (!nand) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	mtd			= nand_to_mtd(nand);
+	doc			= (struct doc_priv *) (nand + 1);
+	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);
+	nand->bbt_md		= nand->bbt_td + 1;
+
+	mtd->owner		= THIS_MODULE;
+	mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
+
+	nand_set_controller_data(nand, doc);
+	nand->select_chip	= doc200x_select_chip;
+	nand->cmd_ctrl		= doc200x_hwcontrol;
+	nand->dev_ready		= doc200x_dev_ready;
+	nand->waitfunc		= doc200x_wait;
+	nand->block_bad		= doc200x_block_bad;
+	nand->ecc.hwctl		= doc200x_enable_hwecc;
+	nand->ecc.calculate	= doc200x_calculate_ecc;
+	nand->ecc.correct	= doc200x_correct_data;
+
+	nand->ecc.mode		= NAND_ECC_HW_SYNDROME;
+	nand->ecc.size		= 512;
+	nand->ecc.bytes		= 6;
+	nand->ecc.strength	= 2;
+	nand->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
+	nand->bbt_options	= NAND_BBT_USE_FLASH;
+	/* Skip the automatic BBT scan so we can run it manually */
+	nand->options		|= NAND_SKIP_BBTSCAN;
+
+	doc->physadr		= physadr;
+	doc->virtadr		= virtadr;
+	doc->ChipID		= ChipID;
+	doc->curfloor		= -1;
+	doc->curchip		= -1;
+	doc->mh0_page		= -1;
+	doc->mh1_page		= -1;
+	doc->nextdoc		= doclist;
+
+	if (ChipID == DOC_ChipID_Doc2k)
+		numchips = doc2000_init(mtd);
+	else if (ChipID == DOC_ChipID_DocMilPlus16)
+		numchips = doc2001plus_init(mtd);
+	else
+		numchips = doc2001_init(mtd);
+
+	if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
+		/* DBB note: i believe nand_release is necessary here, as
+		   buffers may have been allocated in nand_base.  Check with
+		   Thomas. FIX ME! */
+		/* nand_release will call mtd_device_unregister, but we
+		   haven't yet added it.  This is handled without incident by
+		   mtd_device_unregister, as far as I can tell. */
+		nand_release(mtd);
+		kfree(nand);
+		goto fail;
+	}
+
+	/* Success! */
+	doclist = mtd;
+	return 0;
+
+ notfound:
+	/* Put back the contents of the DOCControl register, in case it's not
+	   actually a DiskOnChip.  */
+	WriteDOC(save_control, virtadr, DOCControl);
+ fail:
+	iounmap(virtadr);
+
+error_ioremap:
+	release_mem_region(physadr, DOC_IOREMAP_LEN);
+
+	return ret;
+}
+
+static void release_nanddoc(void)
+{
+	struct mtd_info *mtd, *nextmtd;
+	struct nand_chip *nand;
+	struct doc_priv *doc;
+
+	for (mtd = doclist; mtd; mtd = nextmtd) {
+		nand = mtd_to_nand(mtd);
+		doc = nand_get_controller_data(nand);
+
+		nextmtd = doc->nextdoc;
+		nand_release(mtd);
+		iounmap(doc->virtadr);
+		release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
+		kfree(nand);
+	}
+}
+
+static int __init init_nanddoc(void)
+{
+	int i, ret = 0;
+
+	/* We could create the decoder on demand, if memory is a concern.
+	 * This way we have it handy, if an error happens
+	 *
+	 * Symbolsize is 10 (bits)
+	 * Primitve polynomial is x^10+x^3+1
+	 * first consecutive root is 510
+	 * primitve element to generate roots = 1
+	 * generator polinomial degree = 4
+	 */
+	rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
+	if (!rs_decoder) {
+		printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
+		return -ENOMEM;
+	}
+
+	if (doc_config_location) {
+		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
+		ret = doc_probe(doc_config_location);
+		if (ret < 0)
+			goto outerr;
+	} else {
+		for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
+			doc_probe(doc_locations[i]);
+		}
+	}
+	/* No banner message any more. Print a message if no DiskOnChip
+	   found, so the user knows we at least tried. */
+	if (!doclist) {
+		printk(KERN_INFO "No valid DiskOnChip devices found\n");
+		ret = -ENODEV;
+		goto outerr;
+	}
+	return 0;
+ outerr:
+	free_rs(rs_decoder);
+	return ret;
+}
+
+static void __exit cleanup_nanddoc(void)
+{
+	/* Cleanup the nand/DoC resources */
+	release_nanddoc();
+
+	/* Free the reed solomon resources */
+	if (rs_decoder) {
+		free_rs(rs_decoder);
+	}
+}
+
+module_init(init_nanddoc);
+module_exit(cleanup_nanddoc);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
new file mode 100644
index 000000000000..72f1327c4430
--- /dev/null
+++ b/drivers/mtd/nand/raw/docg4.c
@@ -0,0 +1,1421 @@
+/*
+ *  Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
+ *
+ * mtd nand driver for M-Systems DiskOnChip G4
+ *
+ * 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.
+ *
+ * Tested on the Palm Treo 680.  The G4 is also present on Toshiba Portege, Asus
+ * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
+ * Should work on these as well.  Let me know!
+ *
+ * TODO:
+ *
+ *  Mechanism for management of password-protected areas
+ *
+ *  Hamming ecc when reading oob only
+ *
+ *  According to the M-Sys documentation, this device is also available in a
+ *  "dual-die" configuration having a 256MB capacity, but no mechanism for
+ *  detecting this variant is documented.  Currently this driver assumes 128MB
+ *  capacity.
+ *
+ *  Support for multiple cascaded devices ("floors").  Not sure which gadgets
+ *  contain multiple G4s in a cascaded configuration, if any.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/bch.h>
+#include <linux/bitrev.h>
+#include <linux/jiffies.h>
+
+/*
+ * In "reliable mode" consecutive 2k pages are used in parallel (in some
+ * fashion) to store the same data.  The data can be read back from the
+ * even-numbered pages in the normal manner; odd-numbered pages will appear to
+ * contain junk.  Systems that boot from the docg4 typically write the secondary
+ * program loader (SPL) code in this mode.  The SPL is loaded by the initial
+ * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
+ * to the reset vector address).  This module parameter enables you to use this
+ * driver to write the SPL.  When in this mode, no more than 2k of data can be
+ * written at a time, because the addresses do not increment in the normal
+ * manner, and the starting offset must be within an even-numbered 2k region;
+ * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
+ * 0x1a00, ...  Reliable mode is a special case and should not be used unless
+ * you know what you're doing.
+ */
+static bool reliable_mode;
+module_param(reliable_mode, bool, 0);
+MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
+
+/*
+ * You'll want to ignore badblocks if you're reading a partition that contains
+ * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
+ * it does not use mtd nand's method for marking bad blocks (using oob area).
+ * This will also skip the check of the "page written" flag.
+ */
+static bool ignore_badblocks;
+module_param(ignore_badblocks, bool, 0);
+MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
+
+struct docg4_priv {
+	struct mtd_info	*mtd;
+	struct device *dev;
+	void __iomem *virtadr;
+	int status;
+	struct {
+		unsigned int command;
+		int column;
+		int page;
+	} last_command;
+	uint8_t oob_buf[16];
+	uint8_t ecc_buf[7];
+	int oob_page;
+	struct bch_control *bch;
+};
+
+/*
+ * Defines prefixed with DOCG4 are unique to the diskonchip G4.  All others are
+ * shared with other diskonchip devices (P3, G3 at least).
+ *
+ * Functions with names prefixed with docg4_ are mtd / nand interface functions
+ * (though they may also be called internally).  All others are internal.
+ */
+
+#define DOC_IOSPACE_DATA		0x0800
+
+/* register offsets */
+#define DOC_CHIPID			0x1000
+#define DOC_DEVICESELECT		0x100a
+#define DOC_ASICMODE			0x100c
+#define DOC_DATAEND			0x101e
+#define DOC_NOP				0x103e
+
+#define DOC_FLASHSEQUENCE		0x1032
+#define DOC_FLASHCOMMAND		0x1034
+#define DOC_FLASHADDRESS		0x1036
+#define DOC_FLASHCONTROL		0x1038
+#define DOC_ECCCONF0			0x1040
+#define DOC_ECCCONF1			0x1042
+#define DOC_HAMMINGPARITY		0x1046
+#define DOC_BCH_SYNDROM(idx)		(0x1048 + idx)
+
+#define DOC_ASICMODECONFIRM		0x1072
+#define DOC_CHIPID_INV			0x1074
+#define DOC_POWERMODE			0x107c
+
+#define DOCG4_MYSTERY_REG		0x1050
+
+/* apparently used only to write oob bytes 6 and 7 */
+#define DOCG4_OOB_6_7			0x1052
+
+/* DOC_FLASHSEQUENCE register commands */
+#define DOC_SEQ_RESET			0x00
+#define DOCG4_SEQ_PAGE_READ		0x03
+#define DOCG4_SEQ_FLUSH			0x29
+#define DOCG4_SEQ_PAGEWRITE		0x16
+#define DOCG4_SEQ_PAGEPROG		0x1e
+#define DOCG4_SEQ_BLOCKERASE		0x24
+#define DOCG4_SEQ_SETMODE		0x45
+
+/* DOC_FLASHCOMMAND register commands */
+#define DOCG4_CMD_PAGE_READ             0x00
+#define DOC_CMD_ERASECYCLE2		0xd0
+#define DOCG4_CMD_FLUSH                 0x70
+#define DOCG4_CMD_READ2                 0x30
+#define DOC_CMD_PROG_BLOCK_ADDR		0x60
+#define DOCG4_CMD_PAGEWRITE		0x80
+#define DOC_CMD_PROG_CYCLE2		0x10
+#define DOCG4_CMD_FAST_MODE		0xa3 /* functionality guessed */
+#define DOC_CMD_RELIABLE_MODE		0x22
+#define DOC_CMD_RESET			0xff
+
+/* DOC_POWERMODE register bits */
+#define DOC_POWERDOWN_READY		0x80
+
+/* DOC_FLASHCONTROL register bits */
+#define DOC_CTRL_CE			0x10
+#define DOC_CTRL_UNKNOWN		0x40
+#define DOC_CTRL_FLASHREADY		0x01
+
+/* DOC_ECCCONF0 register bits */
+#define DOC_ECCCONF0_READ_MODE		0x8000
+#define DOC_ECCCONF0_UNKNOWN		0x2000
+#define DOC_ECCCONF0_ECC_ENABLE	        0x1000
+#define DOC_ECCCONF0_DATA_BYTES_MASK	0x07ff
+
+/* DOC_ECCCONF1 register bits */
+#define DOC_ECCCONF1_BCH_SYNDROM_ERR	0x80
+#define DOC_ECCCONF1_ECC_ENABLE         0x07
+#define DOC_ECCCONF1_PAGE_IS_WRITTEN	0x20
+
+/* DOC_ASICMODE register bits */
+#define DOC_ASICMODE_RESET		0x00
+#define DOC_ASICMODE_NORMAL		0x01
+#define DOC_ASICMODE_POWERDOWN		0x02
+#define DOC_ASICMODE_MDWREN		0x04
+#define DOC_ASICMODE_BDETCT_RESET	0x08
+#define DOC_ASICMODE_RSTIN_RESET	0x10
+#define DOC_ASICMODE_RAM_WE		0x20
+
+/* good status values read after read/write/erase operations */
+#define DOCG4_PROGSTATUS_GOOD          0x51
+#define DOCG4_PROGSTATUS_GOOD_2        0xe0
+
+/*
+ * On read operations (page and oob-only), the first byte read from I/O reg is a
+ * status.  On error, it reads 0x73; otherwise, it reads either 0x71 (first read
+ * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
+ */
+#define DOCG4_READ_ERROR           0x02 /* bit 1 indicates read error */
+
+/* anatomy of the device */
+#define DOCG4_CHIP_SIZE        0x8000000
+#define DOCG4_PAGE_SIZE        0x200
+#define DOCG4_PAGES_PER_BLOCK  0x200
+#define DOCG4_BLOCK_SIZE       (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
+#define DOCG4_NUMBLOCKS        (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
+#define DOCG4_OOB_SIZE         0x10
+#define DOCG4_CHIP_SHIFT       27    /* log_2(DOCG4_CHIP_SIZE) */
+#define DOCG4_PAGE_SHIFT       9     /* log_2(DOCG4_PAGE_SIZE) */
+#define DOCG4_ERASE_SHIFT      18    /* log_2(DOCG4_BLOCK_SIZE) */
+
+/* all but the last byte is included in ecc calculation */
+#define DOCG4_BCH_SIZE         (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
+
+#define DOCG4_USERDATA_LEN     520 /* 512 byte page plus 8 oob avail to user */
+
+/* expected values from the ID registers */
+#define DOCG4_IDREG1_VALUE     0x0400
+#define DOCG4_IDREG2_VALUE     0xfbff
+
+/* primitive polynomial used to build the Galois field used by hw ecc gen */
+#define DOCG4_PRIMITIVE_POLY   0x4443
+
+#define DOCG4_M                14  /* Galois field is of order 2^14 */
+#define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
+
+#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
+#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
+
+/*
+ * Bytes 0, 1 are used as badblock marker.
+ * Bytes 2 - 6 are available to the user.
+ * Byte 7 is hamming ecc for first 7 oob bytes only.
+ * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
+ * Byte 15 (the last) is used by the driver as a "page written" flag.
+ */
+static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 7;
+	oobregion->length = 9;
+
+	return 0;
+}
+
+static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 2;
+	oobregion->length = 5;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
+	.ecc = docg4_ooblayout_ecc,
+	.free = docg4_ooblayout_free,
+};
+
+/*
+ * The device has a nop register which M-Sys claims is for the purpose of
+ * inserting precise delays.  But beware; at least some operations fail if the
+ * nop writes are replaced with a generic delay!
+ */
+static inline void write_nop(void __iomem *docptr)
+{
+	writew(0, docptr + DOC_NOP);
+}
+
+static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	uint16_t *p = (uint16_t *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++)
+		p[i] = readw(nand->IO_ADDR_R);
+}
+
+static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	uint16_t *p = (uint16_t *) buf;
+	len >>= 1;
+
+	for (i = 0; i < len; i++)
+		writew(p[i], nand->IO_ADDR_W);
+}
+
+static int poll_status(struct docg4_priv *doc)
+{
+	/*
+	 * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
+	 * register.  Operations known to take a long time (e.g., block erase)
+	 * should sleep for a while before calling this.
+	 */
+
+	uint16_t flash_status;
+	unsigned long timeo;
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	/* hardware quirk requires reading twice initially */
+	flash_status = readw(docptr + DOC_FLASHCONTROL);
+
+	timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
+	do {
+		cpu_relax();
+		flash_status = readb(docptr + DOC_FLASHCONTROL);
+	} while (!(flash_status & DOC_CTRL_FLASHREADY) &&
+		 time_before(jiffies, timeo));
+
+	if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
+		dev_err(doc->dev, "%s: timed out!\n", __func__);
+		return NAND_STATUS_FAIL;
+	}
+
+	return 0;
+}
+
+
+static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
+{
+
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	int status = NAND_STATUS_WP;       /* inverse logic?? */
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	/* report any previously unreported error */
+	if (doc->status) {
+		status |= doc->status;
+		doc->status = 0;
+		return status;
+	}
+
+	status |= poll_status(doc);
+	return status;
+}
+
+static void docg4_select_chip(struct mtd_info *mtd, int chip)
+{
+	/*
+	 * Select among multiple cascaded chips ("floors").  Multiple floors are
+	 * not yet supported, so the only valid non-negative value is 0.
+	 */
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
+
+	if (chip < 0)
+		return;		/* deselected */
+
+	if (chip > 0)
+		dev_warn(doc->dev, "multiple floors currently unsupported\n");
+
+	writew(0, docptr + DOC_DEVICESELECT);
+}
+
+static void reset(struct mtd_info *mtd)
+{
+	/* full device reset */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+
+	writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
+	       docptr + DOC_ASICMODE);
+	writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
+	       docptr + DOC_ASICMODECONFIRM);
+	write_nop(docptr);
+
+	writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
+	       docptr + DOC_ASICMODE);
+	writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
+	       docptr + DOC_ASICMODECONFIRM);
+
+	writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
+
+	poll_status(doc);
+}
+
+static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
+{
+	/* read the 7 hw-generated ecc bytes */
+
+	int i;
+	for (i = 0; i < 7; i++) { /* hw quirk; read twice */
+		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
+		ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
+	}
+}
+
+static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
+{
+	/*
+	 * Called after a page read when hardware reports bitflips.
+	 * Up to four bitflips can be corrected.
+	 */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	int i, numerrs, errpos[4];
+	const uint8_t blank_read_hwecc[8] = {
+		0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
+
+	read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
+
+	/* check if read error is due to a blank page */
+	if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
+		return 0;	/* yes */
+
+	/* skip additional check of "written flag" if ignore_badblocks */
+	if (ignore_badblocks == false) {
+
+		/*
+		 * If the hw ecc bytes are not those of a blank page, there's
+		 * still a chance that the page is blank, but was read with
+		 * errors.  Check the "written flag" in last oob byte, which
+		 * is set to zero when a page is written.  If more than half
+		 * the bits are set, assume a blank page.  Unfortunately, the
+		 * bit flips(s) are not reported in stats.
+		 */
+
+		if (nand->oob_poi[15]) {
+			int bit, numsetbits = 0;
+			unsigned long written_flag = nand->oob_poi[15];
+			for_each_set_bit(bit, &written_flag, 8)
+				numsetbits++;
+			if (numsetbits > 4) { /* assume blank */
+				dev_warn(doc->dev,
+					 "error(s) in blank page "
+					 "at offset %08x\n",
+					 page * DOCG4_PAGE_SIZE);
+				return 0;
+			}
+		}
+	}
+
+	/*
+	 * The hardware ecc unit produces oob_ecc ^ calc_ecc.  The kernel's bch
+	 * algorithm is used to decode this.  However the hw operates on page
+	 * data in a bit order that is the reverse of that of the bch alg,
+	 * requiring that the bits be reversed on the result.  Thanks to Ivan
+	 * Djelic for his analysis!
+	 */
+	for (i = 0; i < 7; i++)
+		doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
+
+	numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
+			     doc->ecc_buf, NULL, errpos);
+
+	if (numerrs == -EBADMSG) {
+		dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
+			 page * DOCG4_PAGE_SIZE);
+		return -EBADMSG;
+	}
+
+	BUG_ON(numerrs < 0);	/* -EINVAL, or anything other than -EBADMSG */
+
+	/* undo last step in BCH alg (modulo mirroring not needed) */
+	for (i = 0; i < numerrs; i++)
+		errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
+
+	/* fix the errors */
+	for (i = 0; i < numerrs; i++) {
+
+		/* ignore if error within oob ecc bytes */
+		if (errpos[i] > DOCG4_USERDATA_LEN * 8)
+			continue;
+
+		/* if error within oob area preceeding ecc bytes... */
+		if (errpos[i] > DOCG4_PAGE_SIZE * 8)
+			change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
+				   (unsigned long *)nand->oob_poi);
+
+		else    /* error in page data */
+			change_bit(errpos[i], (unsigned long *)buf);
+	}
+
+	dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
+		   numerrs, page * DOCG4_PAGE_SIZE);
+
+	return numerrs;
+}
+
+static uint8_t docg4_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+
+	dev_dbg(doc->dev, "%s\n", __func__);
+
+	if (doc->last_command.command == NAND_CMD_STATUS) {
+		int status;
+
+		/*
+		 * Previous nand command was status request, so nand
+		 * infrastructure code expects to read the status here.  If an
+		 * error occurred in a previous operation, report it.
+		 */
+		doc->last_command.command = 0;
+
+		if (doc->status) {
+			status = doc->status;
+			doc->status = 0;
+		}
+
+		/* why is NAND_STATUS_WP inverse logic?? */
+		else
+			status = NAND_STATUS_WP | NAND_STATUS_READY;
+
+		return status;
+	}
+
+	dev_warn(doc->dev, "unexpected call to read_byte()\n");
+
+	return 0;
+}
+
+static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
+{
+	/* write the four address bytes packed in docg4_addr to the device */
+
+	void __iomem *docptr = doc->virtadr;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+	docg4_addr >>= 8;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+	docg4_addr >>= 8;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+	docg4_addr >>= 8;
+	writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
+}
+
+static int read_progstatus(struct docg4_priv *doc)
+{
+	/*
+	 * This apparently checks the status of programming.  Done after an
+	 * erasure, and after page data is written.  On error, the status is
+	 * saved, to be later retrieved by the nand infrastructure code.
+	 */
+	void __iomem *docptr = doc->virtadr;
+
+	/* status is read from the I/O reg */
+	uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
+	uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
+	uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
+
+	dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
+	      __func__, status1, status2, status3);
+
+	if (status1 != DOCG4_PROGSTATUS_GOOD
+	    || status2 != DOCG4_PROGSTATUS_GOOD_2
+	    || status3 != DOCG4_PROGSTATUS_GOOD_2) {
+		doc->status = NAND_STATUS_FAIL;
+		dev_warn(doc->dev, "read_progstatus failed: "
+			 "%02x, %02x, %02x\n", status1, status2, status3);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int pageprog(struct mtd_info *mtd)
+{
+	/*
+	 * Final step in writing a page.  Writes the contents of its
+	 * internal buffer out to the flash array, or some such.
+	 */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	int retval = 0;
+
+	dev_dbg(doc->dev, "docg4: %s\n", __func__);
+
+	writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
+	writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* Just busy-wait; usleep_range() slows things down noticeably. */
+	poll_status(doc);
+
+	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
+	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	retval = read_progstatus(doc);
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+	poll_status(doc);
+	write_nop(docptr);
+
+	return retval;
+}
+
+static void sequence_reset(struct mtd_info *mtd)
+{
+	/* common starting sequence for all operations */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+
+	writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
+	writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
+	writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+	poll_status(doc);
+	write_nop(docptr);
+}
+
+static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
+{
+	/* first step in reading a page */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev,
+	      "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
+
+	sequence_reset(mtd);
+
+	writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+
+	write_addr(doc, docg4_addr);
+
+	write_nop(docptr);
+	writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	poll_status(doc);
+}
+
+static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
+{
+	/* first step in writing a page */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev,
+	      "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
+	sequence_reset(mtd);
+
+	if (unlikely(reliable_mode)) {
+		writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
+		writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
+		writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
+		write_nop(docptr);
+	}
+
+	writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_addr(doc, docg4_addr);
+	write_nop(docptr);
+	write_nop(docptr);
+	poll_status(doc);
+}
+
+static uint32_t mtd_to_docg4_address(int page, int column)
+{
+	/*
+	 * Convert mtd address to format used by the device, 32 bit packed.
+	 *
+	 * Some notes on G4 addressing... The M-Sys documentation on this device
+	 * claims that pages are 2K in length, and indeed, the format of the
+	 * address used by the device reflects that.  But within each page are
+	 * four 512 byte "sub-pages", each with its own oob data that is
+	 * read/written immediately after the 512 bytes of page data.  This oob
+	 * data contains the ecc bytes for the preceeding 512 bytes.
+	 *
+	 * Rather than tell the mtd nand infrastructure that page size is 2k,
+	 * with four sub-pages each, we engage in a little subterfuge and tell
+	 * the infrastructure code that pages are 512 bytes in size.  This is
+	 * done because during the course of reverse-engineering the device, I
+	 * never observed an instance where an entire 2K "page" was read or
+	 * written as a unit.  Each "sub-page" is always addressed individually,
+	 * its data read/written, and ecc handled before the next "sub-page" is
+	 * addressed.
+	 *
+	 * This requires us to convert addresses passed by the mtd nand
+	 * infrastructure code to those used by the device.
+	 *
+	 * The address that is written to the device consists of four bytes: the
+	 * first two are the 2k page number, and the second is the index into
+	 * the page.  The index is in terms of 16-bit half-words and includes
+	 * the preceeding oob data, so e.g., the index into the second
+	 * "sub-page" is 0x108, and the full device address of the start of mtd
+	 * page 0x201 is 0x00800108.
+	 */
+	int g4_page = page / 4;	                      /* device's 2K page */
+	int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
+	return (g4_page << 16) | g4_index;	      /* pack */
+}
+
+static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
+			  int page_addr)
+{
+	/* handle standard nand commands */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
+
+	dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
+	      __func__, command, page_addr, column);
+
+	/*
+	 * Save the command and its arguments.  This enables emulation of
+	 * standard flash devices, and also some optimizations.
+	 */
+	doc->last_command.command = command;
+	doc->last_command.column = column;
+	doc->last_command.page = page_addr;
+
+	switch (command) {
+
+	case NAND_CMD_RESET:
+		reset(mtd);
+		break;
+
+	case NAND_CMD_READ0:
+		read_page_prologue(mtd, g4_addr);
+		break;
+
+	case NAND_CMD_STATUS:
+		/* next call to read_byte() will expect a status */
+		break;
+
+	case NAND_CMD_SEQIN:
+		if (unlikely(reliable_mode)) {
+			uint16_t g4_page = g4_addr >> 16;
+
+			/* writes to odd-numbered 2k pages are invalid */
+			if (g4_page & 0x01)
+				dev_warn(doc->dev,
+					 "invalid reliable mode address\n");
+		}
+
+		write_page_prologue(mtd, g4_addr);
+
+		/* hack for deferred write of oob bytes */
+		if (doc->oob_page == page_addr)
+			memcpy(nand->oob_poi, doc->oob_buf, 16);
+		break;
+
+	case NAND_CMD_PAGEPROG:
+		pageprog(mtd);
+		break;
+
+	/* we don't expect these, based on review of nand_base.c */
+	case NAND_CMD_READOOB:
+	case NAND_CMD_READID:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+		dev_warn(doc->dev, "docg4_command: "
+			 "unexpected nand command 0x%x\n", command);
+		break;
+
+	}
+}
+
+static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
+		     uint8_t *buf, int page, bool use_ecc)
+{
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	uint16_t status, edc_err, *buf16;
+	int bits_corrected = 0;
+
+	dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
+
+	nand_read_page_op(nand, page, 0, NULL, 0);
+
+	writew(DOC_ECCCONF0_READ_MODE |
+	       DOC_ECCCONF0_ECC_ENABLE |
+	       DOC_ECCCONF0_UNKNOWN |
+	       DOCG4_BCH_SIZE,
+	       docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* the 1st byte from the I/O reg is a status; the rest is page data */
+	status = readw(docptr + DOC_IOSPACE_DATA);
+	if (status & DOCG4_READ_ERROR) {
+		dev_err(doc->dev,
+			"docg4_read_page: bad status: 0x%02x\n", status);
+		writew(0, docptr + DOC_DATAEND);
+		return -EIO;
+	}
+
+	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
+
+	docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
+
+	/* this device always reads oob after page data */
+	/* first 14 oob bytes read from I/O reg */
+	docg4_read_buf(mtd, nand->oob_poi, 14);
+
+	/* last 2 read from another reg */
+	buf16 = (uint16_t *)(nand->oob_poi + 14);
+	*buf16 = readw(docptr + DOCG4_MYSTERY_REG);
+
+	write_nop(docptr);
+
+	if (likely(use_ecc == true)) {
+
+		/* read the register that tells us if bitflip(s) detected  */
+		edc_err = readw(docptr + DOC_ECCCONF1);
+		edc_err = readw(docptr + DOC_ECCCONF1);
+		dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
+
+		/* If bitflips are reported, attempt to correct with ecc */
+		if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
+			bits_corrected = correct_data(mtd, buf, page);
+			if (bits_corrected == -EBADMSG)
+				mtd->ecc_stats.failed++;
+			else
+				mtd->ecc_stats.corrected += bits_corrected;
+		}
+	}
+
+	writew(0, docptr + DOC_DATAEND);
+	if (bits_corrected == -EBADMSG)	  /* uncorrectable errors */
+		return 0;
+	return bits_corrected;
+}
+
+
+static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+			       uint8_t *buf, int oob_required, int page)
+{
+	return read_page(mtd, nand, buf, page, false);
+}
+
+static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
+			   uint8_t *buf, int oob_required, int page)
+{
+	return read_page(mtd, nand, buf, page, true);
+}
+
+static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
+			  int page)
+{
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	uint16_t status;
+
+	dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
+
+	nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
+
+	writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* the 1st byte from the I/O reg is a status; the rest is oob data */
+	status = readw(docptr + DOC_IOSPACE_DATA);
+	if (status & DOCG4_READ_ERROR) {
+		dev_warn(doc->dev,
+			 "docg4_read_oob failed: status = 0x%02x\n", status);
+		return -EIO;
+	}
+
+	dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
+
+	docg4_read_buf(mtd, nand->oob_poi, 16);
+
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+
+	return 0;
+}
+
+static int docg4_erase_block(struct mtd_info *mtd, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	uint16_t g4_page;
+	int status;
+
+	dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
+
+	sequence_reset(mtd);
+
+	writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
+	writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+
+	/* only 2 bytes of address are written to specify erase block */
+	g4_page = (uint16_t)(page / 4);  /* to g4's 2k page addressing */
+	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
+	g4_page >>= 8;
+	writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
+	write_nop(docptr);
+
+	/* start the erasure */
+	writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	usleep_range(500, 1000); /* erasure is long; take a snooze */
+	poll_status(doc);
+	writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
+	writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
+	writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+	write_nop(docptr);
+
+	read_progstatus(doc);
+
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+	poll_status(doc);
+	write_nop(docptr);
+
+	status = nand->waitfunc(mtd, nand);
+	if (status < 0)
+		return status;
+
+	return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
+		      const uint8_t *buf, int page, bool use_ecc)
+{
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	uint8_t ecc_buf[8];
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
+
+	writew(DOC_ECCCONF0_ECC_ENABLE |
+	       DOC_ECCCONF0_UNKNOWN |
+	       DOCG4_BCH_SIZE,
+	       docptr + DOC_ECCCONF0);
+	write_nop(docptr);
+
+	/* write the page data */
+	docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
+
+	/* oob bytes 0 through 5 are written to I/O reg */
+	docg4_write_buf16(mtd, nand->oob_poi, 6);
+
+	/* oob byte 6 written to a separate reg */
+	writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
+
+	write_nop(docptr);
+	write_nop(docptr);
+
+	/* write hw-generated ecc bytes to oob */
+	if (likely(use_ecc == true)) {
+		/* oob byte 7 is hamming code */
+		uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
+		hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
+		writew(hamming, docptr + DOCG4_OOB_6_7);
+		write_nop(docptr);
+
+		/* read the 7 bch bytes from ecc regs */
+		read_hw_ecc(docptr, ecc_buf);
+		ecc_buf[7] = 0;         /* clear the "page written" flag */
+	}
+
+	/* write user-supplied bytes to oob */
+	else {
+		writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
+		write_nop(docptr);
+		memcpy(ecc_buf, &nand->oob_poi[8], 8);
+	}
+
+	docg4_write_buf16(mtd, ecc_buf, 8);
+	write_nop(docptr);
+	write_nop(docptr);
+	writew(0, docptr + DOC_DATAEND);
+	write_nop(docptr);
+
+	return nand_prog_page_end_op(nand);
+}
+
+static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+				const uint8_t *buf, int oob_required, int page)
+{
+	return write_page(mtd, nand, buf, page, false);
+}
+
+static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
+			     const uint8_t *buf, int oob_required, int page)
+{
+	return write_page(mtd, nand, buf, page, true);
+}
+
+static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
+			   int page)
+{
+	/*
+	 * Writing oob-only is not really supported, because MLC nand must write
+	 * oob bytes at the same time as page data.  Nonetheless, we save the
+	 * oob buffer contents here, and then write it along with the page data
+	 * if the same page is subsequently written.  This allows user space
+	 * utilities that write the oob data prior to the page data to work
+	 * (e.g., nandwrite).  The disdvantage is that, if the intention was to
+	 * write oob only, the operation is quietly ignored.  Also, oob can get
+	 * corrupted if two concurrent processes are running nandwrite.
+	 */
+
+	/* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	doc->oob_page = page;
+	memcpy(doc->oob_buf, nand->oob_poi, 16);
+	return 0;
+}
+
+static int __init read_factory_bbt(struct mtd_info *mtd)
+{
+	/*
+	 * The device contains a read-only factory bad block table.  Read it and
+	 * update the memory-based bbt accordingly.
+	 */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
+	uint8_t *buf;
+	int i, block;
+	__u32 eccfailed_stats = mtd->ecc_stats.failed;
+
+	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	read_page_prologue(mtd, g4_addr);
+	docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
+
+	/*
+	 * If no memory-based bbt was created, exit.  This will happen if module
+	 * parameter ignore_badblocks is set.  Then why even call this function?
+	 * For an unknown reason, block erase always fails if it's the first
+	 * operation after device power-up.  The above read ensures it never is.
+	 * Ugly, I know.
+	 */
+	if (nand->bbt == NULL)  /* no memory-based bbt */
+		goto exit;
+
+	if (mtd->ecc_stats.failed > eccfailed_stats) {
+		/*
+		 * Whoops, an ecc failure ocurred reading the factory bbt.
+		 * It is stored redundantly, so we get another chance.
+		 */
+		eccfailed_stats = mtd->ecc_stats.failed;
+		docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
+		if (mtd->ecc_stats.failed > eccfailed_stats) {
+			dev_warn(doc->dev,
+				 "The factory bbt could not be read!\n");
+			goto exit;
+		}
+	}
+
+	/*
+	 * Parse factory bbt and update memory-based bbt.  Factory bbt format is
+	 * simple: one bit per block, block numbers increase left to right (msb
+	 * to lsb).  Bit clear means bad block.
+	 */
+	for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
+		int bitnum;
+		unsigned long bits = ~buf[i];
+		for_each_set_bit(bitnum, &bits, 8) {
+			int badblock = block + 7 - bitnum;
+			nand->bbt[badblock / 4] |=
+				0x03 << ((badblock % 4) * 2);
+			mtd->ecc_stats.badblocks++;
+			dev_notice(doc->dev, "factory-marked bad block: %d\n",
+				   badblock);
+		}
+	}
+ exit:
+	kfree(buf);
+	return 0;
+}
+
+static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	/*
+	 * Mark a block as bad.  Bad blocks are marked in the oob area of the
+	 * first page of the block.  The default scan_bbt() in the nand
+	 * infrastructure code works fine for building the memory-based bbt
+	 * during initialization, as does the nand infrastructure function that
+	 * checks if a block is bad by reading the bbt.  This function replaces
+	 * the nand default because writes to oob-only are not supported.
+	 */
+
+	int ret, i;
+	uint8_t *buf;
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	struct nand_bbt_descr *bbtd = nand->badblock_pattern;
+	int page = (int)(ofs >> nand->page_shift);
+	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
+
+	dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
+
+	if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
+		dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
+			 __func__, ofs);
+
+	/* allocate blank buffer for page data */
+	buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* write bit-wise negation of pattern to oob buffer */
+	memset(nand->oob_poi, 0xff, mtd->oobsize);
+	for (i = 0; i < bbtd->len; i++)
+		nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
+
+	/* write first page of block */
+	write_page_prologue(mtd, g4_addr);
+	docg4_write_page(mtd, nand, buf, 1, page);
+	ret = pageprog(mtd);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
+{
+	/* only called when module_param ignore_badblocks is set */
+	return 0;
+}
+
+static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	/*
+	 * Put the device into "deep power-down" mode.  Note that CE# must be
+	 * deasserted for this to take effect.  The xscale, e.g., can be
+	 * configured to float this signal when the processor enters power-down,
+	 * and a suitable pull-up ensures its deassertion.
+	 */
+
+	int i;
+	uint8_t pwr_down;
+	struct docg4_priv *doc = platform_get_drvdata(pdev);
+	void __iomem *docptr = doc->virtadr;
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	/* poll the register that tells us we're ready to go to sleep */
+	for (i = 0; i < 10; i++) {
+		pwr_down = readb(docptr + DOC_POWERMODE);
+		if (pwr_down & DOC_POWERDOWN_READY)
+			break;
+		usleep_range(1000, 4000);
+	}
+
+	if (pwr_down & DOC_POWERDOWN_READY) {
+		dev_err(doc->dev, "suspend failed; "
+			"timeout polling DOC_POWERDOWN_READY\n");
+		return -EIO;
+	}
+
+	writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
+	       docptr + DOC_ASICMODE);
+	writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
+	       docptr + DOC_ASICMODECONFIRM);
+
+	write_nop(docptr);
+
+	return 0;
+}
+
+static int docg4_resume(struct platform_device *pdev)
+{
+
+	/*
+	 * Exit power-down.  Twelve consecutive reads of the address below
+	 * accomplishes this, assuming CE# has been asserted.
+	 */
+
+	struct docg4_priv *doc = platform_get_drvdata(pdev);
+	void __iomem *docptr = doc->virtadr;
+	int i;
+
+	dev_dbg(doc->dev, "%s...\n", __func__);
+
+	for (i = 0; i < 12; i++)
+		readb(docptr + 0x1fff);
+
+	return 0;
+}
+
+static void __init init_mtd_structs(struct mtd_info *mtd)
+{
+	/* initialize mtd and nand data structures */
+
+	/*
+	 * Note that some of the following initializations are not usually
+	 * required within a nand driver because they are performed by the nand
+	 * infrastructure code as part of nand_scan().  In this case they need
+	 * to be initialized here because we skip call to nand_scan_ident() (the
+	 * first half of nand_scan()).  The call to nand_scan_ident() is skipped
+	 * because for this device the chip id is not read in the manner of a
+	 * standard nand device.  Unfortunately, nand_scan_ident() does other
+	 * things as well, such as call nand_set_defaults().
+	 */
+
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+
+	mtd->size = DOCG4_CHIP_SIZE;
+	mtd->name = "Msys_Diskonchip_G4";
+	mtd->writesize = DOCG4_PAGE_SIZE;
+	mtd->erasesize = DOCG4_BLOCK_SIZE;
+	mtd->oobsize = DOCG4_OOB_SIZE;
+	mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
+	nand->chipsize = DOCG4_CHIP_SIZE;
+	nand->chip_shift = DOCG4_CHIP_SHIFT;
+	nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
+	nand->chip_delay = 20;
+	nand->page_shift = DOCG4_PAGE_SHIFT;
+	nand->pagemask = 0x3ffff;
+	nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
+	nand->badblockbits = 8;
+	nand->ecc.mode = NAND_ECC_HW_SYNDROME;
+	nand->ecc.size = DOCG4_PAGE_SIZE;
+	nand->ecc.prepad = 8;
+	nand->ecc.bytes	= 8;
+	nand->ecc.strength = DOCG4_T;
+	nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
+	nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
+	nand->controller = &nand->hwcontrol;
+	nand_hw_control_init(nand->controller);
+
+	/* methods */
+	nand->cmdfunc = docg4_command;
+	nand->waitfunc = docg4_wait;
+	nand->select_chip = docg4_select_chip;
+	nand->read_byte = docg4_read_byte;
+	nand->block_markbad = docg4_block_markbad;
+	nand->read_buf = docg4_read_buf;
+	nand->write_buf = docg4_write_buf16;
+	nand->erase = docg4_erase_block;
+	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
+	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
+	nand->ecc.read_page = docg4_read_page;
+	nand->ecc.write_page = docg4_write_page;
+	nand->ecc.read_page_raw = docg4_read_page_raw;
+	nand->ecc.write_page_raw = docg4_write_page_raw;
+	nand->ecc.read_oob = docg4_read_oob;
+	nand->ecc.write_oob = docg4_write_oob;
+
+	/*
+	 * The way the nand infrastructure code is written, a memory-based bbt
+	 * is not created if NAND_SKIP_BBTSCAN is set.  With no memory bbt,
+	 * nand->block_bad() is used.  So when ignoring bad blocks, we skip the
+	 * scan and define a dummy block_bad() which always returns 0.
+	 */
+	if (ignore_badblocks) {
+		nand->options |= NAND_SKIP_BBTSCAN;
+		nand->block_bad	= docg4_block_neverbad;
+	}
+
+}
+
+static int __init read_id_reg(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct docg4_priv *doc = nand_get_controller_data(nand);
+	void __iomem *docptr = doc->virtadr;
+	uint16_t id1, id2;
+
+	/* check for presence of g4 chip by reading id registers */
+	id1 = readw(docptr + DOC_CHIPID);
+	id1 = readw(docptr + DOCG4_MYSTERY_REG);
+	id2 = readw(docptr + DOC_CHIPID_INV);
+	id2 = readw(docptr + DOCG4_MYSTERY_REG);
+
+	if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
+		dev_info(doc->dev,
+			 "NAND device: 128MiB Diskonchip G4 detected\n");
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
+
+static int __init probe_docg4(struct platform_device *pdev)
+{
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	void __iomem *virtadr;
+	struct docg4_priv *doc;
+	int len, retval;
+	struct resource *r;
+	struct device *dev = &pdev->dev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(dev, "no io memory resource defined!\n");
+		return -ENODEV;
+	}
+
+	virtadr = ioremap(r->start, resource_size(r));
+	if (!virtadr) {
+		dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
+		return -EIO;
+	}
+
+	len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
+	nand = kzalloc(len, GFP_KERNEL);
+	if (nand == NULL) {
+		retval = -ENOMEM;
+		goto fail_unmap;
+	}
+
+	mtd = nand_to_mtd(nand);
+	doc = (struct docg4_priv *) (nand + 1);
+	nand_set_controller_data(nand, doc);
+	mtd->dev.parent = &pdev->dev;
+	doc->virtadr = virtadr;
+	doc->dev = dev;
+
+	init_mtd_structs(mtd);
+
+	/* initialize kernel bch algorithm */
+	doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
+	if (doc->bch == NULL) {
+		retval = -EINVAL;
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, doc);
+
+	reset(mtd);
+	retval = read_id_reg(mtd);
+	if (retval == -ENODEV) {
+		dev_warn(dev, "No diskonchip G4 device found.\n");
+		goto fail;
+	}
+
+	retval = nand_scan_tail(mtd);
+	if (retval)
+		goto fail;
+
+	retval = read_factory_bbt(mtd);
+	if (retval)
+		goto fail;
+
+	retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+	if (retval)
+		goto fail;
+
+	doc->mtd = mtd;
+	return 0;
+
+fail:
+	nand_release(mtd); /* deletes partitions and mtd devices */
+	free_bch(doc->bch);
+	kfree(nand);
+
+fail_unmap:
+	iounmap(virtadr);
+
+	return retval;
+}
+
+static int __exit cleanup_docg4(struct platform_device *pdev)
+{
+	struct docg4_priv *doc = platform_get_drvdata(pdev);
+	nand_release(doc->mtd);
+	free_bch(doc->bch);
+	kfree(mtd_to_nand(doc->mtd));
+	iounmap(doc->virtadr);
+	return 0;
+}
+
+static struct platform_driver docg4_driver = {
+	.driver		= {
+		.name	= "docg4",
+	},
+	.suspend	= docg4_suspend,
+	.resume		= docg4_resume,
+	.remove		= __exit_p(cleanup_docg4),
+};
+
+module_platform_driver_probe(docg4_driver, probe_docg4);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Dunn");
+MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
new file mode 100644
index 000000000000..8b6dcd739ecb
--- /dev/null
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -0,0 +1,979 @@
+/* Freescale Enhanced Local Bus Controller NAND driver
+ *
+ * Copyright © 2006-2007, 2010 Freescale Semiconductor
+ *
+ * Authors: Nick Spence <nick.spence@freescale.com>,
+ *          Scott Wood <scottwood@freescale.com>
+ *          Jack Lan <jack.lan@freescale.com>
+ *          Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/fsl_lbc.h>
+
+#define MAX_BANKS 8
+#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
+#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
+
+/* mtd information per set */
+
+struct fsl_elbc_mtd {
+	struct nand_chip chip;
+	struct fsl_lbc_ctrl *ctrl;
+
+	struct device *dev;
+	int bank;               /* Chip select bank number           */
+	u8 __iomem *vbase;      /* Chip select base virtual address  */
+	int page_size;          /* NAND page size (0=512, 1=2048)    */
+	unsigned int fmr;       /* FCM Flash Mode Register value     */
+};
+
+/* Freescale eLBC FCM controller information */
+
+struct fsl_elbc_fcm_ctrl {
+	struct nand_hw_control controller;
+	struct fsl_elbc_mtd *chips[MAX_BANKS];
+
+	u8 __iomem *addr;        /* Address of assigned FCM buffer        */
+	unsigned int page;       /* Last page written to / read from      */
+	unsigned int read_bytes; /* Number of bytes read during command   */
+	unsigned int column;     /* Saved column from SEQIN               */
+	unsigned int index;      /* Pointer to next byte to 'read'        */
+	unsigned int status;     /* status read from LTESR after last op  */
+	unsigned int mdr;        /* UPM/FCM Data Register value           */
+	unsigned int use_mdr;    /* Non zero if the MDR is to be set      */
+	unsigned int oob;        /* Non zero if operating on OOB data     */
+	unsigned int counter;	 /* counter for the initializations	  */
+	unsigned int max_bitflips;  /* Saved during READ0 cmd		  */
+};
+
+/* These map to the positions used by the FCM hardware ECC generator */
+
+static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (16 * section) + 6;
+	if (priv->fmr & FMR_ECCM)
+		oobregion->offset += 2;
+
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+
+	if (section > chip->ecc.steps)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		if (mtd->writesize > 512)
+			oobregion->offset++;
+		oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
+	} else {
+		oobregion->offset = (16 * section) -
+				    ((priv->fmr & FMR_ECCM) ? 5 : 7);
+		if (section < chip->ecc.steps)
+			oobregion->length = 13;
+		else
+			oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
+	.ecc = fsl_elbc_ooblayout_ecc,
+	.free = fsl_elbc_ooblayout_free,
+};
+
+/*
+ * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
+ * interfere with ECC positions, that's why we implement our own descriptors.
+ * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	11,
+	.len = 4,
+	.veroffs = 15,
+	.maxblocks = 4,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	11,
+	.len = 4,
+	.veroffs = 15,
+	.maxblocks = 4,
+	.pattern = mirror_pattern,
+};
+
+/*=================================*/
+
+/*
+ * Set up the FCM hardware block and page address fields, and the fcm
+ * structure addr field to point to the correct FCM buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
+	int buf_num;
+
+	elbc_fcm_ctrl->page = page_addr;
+
+	if (priv->page_size) {
+		/*
+		 * large page size chip : FPAR[PI] save the lowest 6 bits,
+		 *                        FBAR[BLK] save the other bits.
+		 */
+		out_be32(&lbc->fbar, page_addr >> 6);
+		out_be32(&lbc->fpar,
+		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+		         (oob ? FPAR_LP_MS : 0) | column);
+		buf_num = (page_addr & 1) << 2;
+	} else {
+		/*
+		 * small page size chip : FPAR[PI] save the lowest 5 bits,
+		 *                        FBAR[BLK] save the other bits.
+		 */
+		out_be32(&lbc->fbar, page_addr >> 5);
+		out_be32(&lbc->fpar,
+		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+		         (oob ? FPAR_SP_MS : 0) | column);
+		buf_num = page_addr & 7;
+	}
+
+	elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
+	elbc_fcm_ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
+
+	dev_vdbg(priv->dev, "set_addr: bank=%d, "
+			    "elbc_fcm_ctrl->addr=0x%p (0x%p), "
+	                    "index %x, pes %d ps %d\n",
+		 buf_num, elbc_fcm_ctrl->addr, priv->vbase,
+		 elbc_fcm_ctrl->index,
+	         chip->phys_erase_shift, chip->page_shift);
+}
+
+/*
+ * execute FCM command and wait for it to complete
+ */
+static int fsl_elbc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+
+	/* Setup the FMR[OP] to execute without write protection */
+	out_be32(&lbc->fmr, priv->fmr | 3);
+	if (elbc_fcm_ctrl->use_mdr)
+		out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
+
+	dev_vdbg(priv->dev,
+	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
+	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
+	dev_vdbg(priv->dev,
+	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
+	         "fbcr=%08x bank=%d\n",
+	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
+	         in_be32(&lbc->fbcr), priv->bank);
+
+	ctrl->irq_status = 0;
+	/* execute special operation */
+	out_be32(&lbc->lsor, priv->bank);
+
+	/* wait for FCM complete flag or timeout */
+	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
+	                   FCM_TIMEOUT_MSECS * HZ/1000);
+	elbc_fcm_ctrl->status = ctrl->irq_status;
+	/* store mdr value in case it was needed */
+	if (elbc_fcm_ctrl->use_mdr)
+		elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
+
+	elbc_fcm_ctrl->use_mdr = 0;
+
+	if (elbc_fcm_ctrl->status != LTESR_CC) {
+		dev_info(priv->dev,
+		         "command failed: fir %x fcr %x status %x mdr %x\n",
+		         in_be32(&lbc->fir), in_be32(&lbc->fcr),
+			 elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
+		return -EIO;
+	}
+
+	if (chip->ecc.mode != NAND_ECC_HW)
+		return 0;
+
+	elbc_fcm_ctrl->max_bitflips = 0;
+
+	if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
+		uint32_t lteccr = in_be32(&lbc->lteccr);
+		/*
+		 * if command was a full page read and the ELBC
+		 * has the LTECCR register, then bits 12-15 (ppc order) of
+		 * LTECCR indicates which 512 byte sub-pages had fixed errors.
+		 * bits 28-31 are uncorrectable errors, marked elsewhere.
+		 * for small page nand only 1 bit is used.
+		 * if the ELBC doesn't have the lteccr register it reads 0
+		 * FIXME: 4 bits can be corrected on NANDs with 2k pages, so
+		 * count the number of sub-pages with bitflips and update
+		 * ecc_stats.corrected accordingly.
+		 */
+		if (lteccr & 0x000F000F)
+			out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
+		if (lteccr & 0x000F0000) {
+			mtd->ecc_stats.corrected++;
+			elbc_fcm_ctrl->max_bitflips = 1;
+		}
+	}
+
+	return 0;
+}
+
+static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+{
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+
+	if (priv->page_size) {
+		out_be32(&lbc->fir,
+		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+		         (FIR_OP_CM1 << FIR_OP3_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP4_SHIFT));
+
+		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+	} else {
+		out_be32(&lbc->fir,
+		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP3_SHIFT));
+
+		if (oob)
+			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+		else
+			out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT);
+	}
+}
+
+/* cmdfunc send commands to the FCM */
+static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+                             int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+
+	elbc_fcm_ctrl->use_mdr = 0;
+
+	/* clear the read buffer */
+	elbc_fcm_ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		elbc_fcm_ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 and READ1 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ1:
+		column += 256;
+
+	/* fall-through */
+	case NAND_CMD_READ0:
+		dev_dbg(priv->dev,
+		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+		        " 0x%x, column: 0x%x.\n", page_addr, column);
+
+
+		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
+		set_addr(mtd, 0, page_addr, 0);
+
+		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		elbc_fcm_ctrl->index += column;
+
+		fsl_elbc_do_read(chip, 0);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		dev_vdbg(priv->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+			 " 0x%x, column: 0x%x.\n", page_addr, column);
+
+		out_be32(&lbc->fbcr, mtd->oobsize - column);
+		set_addr(mtd, column, page_addr, 1);
+
+		elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_elbc_do_read(chip, 1);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	case NAND_CMD_READID:
+	case NAND_CMD_PARAM:
+		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD %x\n", command);
+
+		out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
+		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
+		out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);
+		/*
+		 * although currently it's 8 bytes for READID, we always read
+		 * the maximum 256 bytes(for PARAM)
+		 */
+		out_be32(&lbc->fbcr, 256);
+		elbc_fcm_ctrl->read_bytes = 256;
+		elbc_fcm_ctrl->use_mdr = 1;
+		elbc_fcm_ctrl->mdr = column;
+		set_addr(mtd, 0, 0, 0);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		dev_vdbg(priv->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
+		         "page_addr: 0x%x.\n", page_addr);
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+
+		out_be32(&lbc->fir,
+		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
+		         (FIR_OP_CM2 << FIR_OP2_SHIFT) |
+		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+		         (FIR_OP_RS  << FIR_OP4_SHIFT));
+
+		out_be32(&lbc->fcr,
+		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+		         (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
+		         (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
+
+		out_be32(&lbc->fbcr, 0);
+		elbc_fcm_ctrl->read_bytes = 0;
+		elbc_fcm_ctrl->use_mdr = 1;
+
+		fsl_elbc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		__be32 fcr;
+		dev_vdbg(priv->dev,
+			 "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+		         "page_addr: 0x%x, column: 0x%x.\n",
+		         page_addr, column);
+
+		elbc_fcm_ctrl->column = column;
+		elbc_fcm_ctrl->use_mdr = 1;
+
+		if (column >= mtd->writesize) {
+			/* OOB area */
+			column -= mtd->writesize;
+			elbc_fcm_ctrl->oob = 1;
+		} else {
+			WARN_ON(column != 0);
+			elbc_fcm_ctrl->oob = 0;
+		}
+
+		fcr = (NAND_CMD_STATUS   << FCR_CMD1_SHIFT) |
+		      (NAND_CMD_SEQIN    << FCR_CMD2_SHIFT) |
+		      (NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
+
+		if (priv->page_size) {
+			out_be32(&lbc->fir,
+			         (FIR_OP_CM2 << FIR_OP0_SHIFT) |
+			         (FIR_OP_CA  << FIR_OP1_SHIFT) |
+			         (FIR_OP_PA  << FIR_OP2_SHIFT) |
+			         (FIR_OP_WB  << FIR_OP3_SHIFT) |
+			         (FIR_OP_CM3 << FIR_OP4_SHIFT) |
+			         (FIR_OP_CW1 << FIR_OP5_SHIFT) |
+			         (FIR_OP_RS  << FIR_OP6_SHIFT));
+		} else {
+			out_be32(&lbc->fir,
+			         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
+			         (FIR_OP_PA  << FIR_OP3_SHIFT) |
+			         (FIR_OP_WB  << FIR_OP4_SHIFT) |
+			         (FIR_OP_CM3 << FIR_OP5_SHIFT) |
+			         (FIR_OP_CW1 << FIR_OP6_SHIFT) |
+			         (FIR_OP_RS  << FIR_OP7_SHIFT));
+
+			if (elbc_fcm_ctrl->oob)
+				/* OOB area --> READOOB */
+				fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
+			else
+				/* First 256 bytes --> READ0 */
+				fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
+		}
+
+		out_be32(&lbc->fcr, fcr);
+		set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG: {
+		dev_vdbg(priv->dev,
+		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
+			 "writing %d bytes.\n", elbc_fcm_ctrl->index);
+
+		/* if the write did not start at 0 or is not a full page
+		 * then set the exact length, otherwise use a full page
+		 * write so the HW generates the ECC.
+		 */
+		if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
+		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
+			out_be32(&lbc->fbcr,
+				elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
+		else
+			out_be32(&lbc->fbcr, 0);
+
+		fsl_elbc_run_command(mtd);
+		return;
+	}
+
+	/* CMD_STATUS must read the status byte while CEB is active */
+	/* Note - it does not wait for the ready line */
+	case NAND_CMD_STATUS:
+		out_be32(&lbc->fir,
+		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+		         (FIR_OP_RBW << FIR_OP1_SHIFT));
+		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+		out_be32(&lbc->fbcr, 1);
+		set_addr(mtd, 0, 0, 0);
+		elbc_fcm_ctrl->read_bytes = 1;
+
+		fsl_elbc_run_command(mtd);
+
+		/* The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
+		return;
+
+	/* RESET without waiting for the ready line */
+	case NAND_CMD_RESET:
+		dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+		out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
+		out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
+		fsl_elbc_run_command(mtd);
+		return;
+
+	default:
+		dev_err(priv->dev,
+		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+		        command);
+	}
+}
+
+static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+{
+	/* The hardware does not seem to support multiple
+	 * chips per bank.
+	 */
+}
+
+/*
+ * Write buf to the FCM Controller Data Buffer
+ */
+static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len <= 0) {
+		dev_err(priv->dev, "write_buf of %d bytes", len);
+		elbc_fcm_ctrl->status = 0;
+		return;
+	}
+
+	if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
+		dev_err(priv->dev,
+		        "write_buf beyond end of buffer "
+		        "(%d requested, %u available)\n",
+			len, bufsize - elbc_fcm_ctrl->index);
+		len = bufsize - elbc_fcm_ctrl->index;
+	}
+
+	memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
+	/*
+	 * This is workaround for the weird elbc hangs during nand write,
+	 * Scott Wood says: "...perhaps difference in how long it takes a
+	 * write to make it through the localbus compared to a write to IMMR
+	 * is causing problems, and sync isn't helping for some reason."
+	 * Reading back the last byte helps though.
+	 */
+	in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
+
+	elbc_fcm_ctrl->index += len;
+}
+
+/*
+ * read a byte from either the FCM hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+
+	/* If there are still bytes in the FCM, then use the next byte. */
+	if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
+		return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
+
+	dev_err(priv->dev, "read_byte beyond end of buffer\n");
+	return ERR_BYTE;
+}
+
+/*
+ * Read from the FCM Controller Data Buffer
+ */
+static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+	int avail;
+
+	if (len < 0)
+		return;
+
+	avail = min((unsigned int)len,
+			elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
+	memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
+	elbc_fcm_ctrl->index += avail;
+
+	if (len > avail)
+		dev_err(priv->dev,
+		        "read_buf beyond end of buffer "
+		        "(%d requested, %d available)\n",
+		        len, avail);
+}
+
+/* This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+
+	if (elbc_fcm_ctrl->status != LTESR_CC)
+		return NAND_STATUS_FAIL;
+
+	/* The chip always seems to report that it is
+	 * write-protected, even when it is not.
+	 */
+	return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
+}
+
+static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+	unsigned int al;
+
+	/* calculate FMR Address Length field */
+	al = 0;
+	if (chip->pagemask & 0xffff0000)
+		al++;
+	if (chip->pagemask & 0xff000000)
+		al++;
+
+	priv->fmr |= al << FMR_AL_SHIFT;
+
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
+	        chip->numchips);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
+	        chip->chipsize);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+	        chip->pagemask);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+	        chip->chip_delay);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+	        chip->badblockpos);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+	        chip->chip_shift);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+	        chip->page_shift);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+	        chip->phys_erase_shift);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+	        chip->ecc.mode);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+	        chip->ecc.steps);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+	        chip->ecc.bytes);
+	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+	        chip->ecc.total);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
+		mtd->ooblayout);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+	        mtd->erasesize);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+	        mtd->writesize);
+	dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+	        mtd->oobsize);
+
+	/* adjust Option Register and ECC to match Flash page size */
+	if (mtd->writesize == 512) {
+		priv->page_size = 0;
+		clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+	} else if (mtd->writesize == 2048) {
+		priv->page_size = 1;
+		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+	} else {
+		dev_err(priv->dev,
+		        "fsl_elbc_init: page size %d is not supported\n",
+		        mtd->writesize);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			      uint8_t *buf, int oob_required, int page)
+{
+	struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
+
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	if (oob_required)
+		fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+		mtd->ecc_stats.failed++;
+
+	return elbc_fcm_ctrl->max_bitflips;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+				const uint8_t *buf, int oob_required, int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+				uint32_t offset, uint32_t data_len,
+				const uint8_t *buf, int oob_required, int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
+	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+	return nand_prog_page_end_op(chip);
+}
+
+static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
+{
+	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
+	struct nand_chip *chip = &priv->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
+
+	/* Fill in fsl_elbc_mtd structure */
+	mtd->dev.parent = priv->dev;
+	nand_set_flash_node(chip, priv->dev->of_node);
+
+	/* set timeout to maximum */
+	priv->fmr = 15 << FMR_CWTO_SHIFT;
+	if (in_be32(&lbc->bank[priv->bank].or) & OR_FCM_PGS)
+		priv->fmr |= FMR_ECCM;
+
+	/* fill in nand_chip structure */
+	/* set up function call table */
+	chip->read_byte = fsl_elbc_read_byte;
+	chip->write_buf = fsl_elbc_write_buf;
+	chip->read_buf = fsl_elbc_read_buf;
+	chip->select_chip = fsl_elbc_select_chip;
+	chip->cmdfunc = fsl_elbc_cmdfunc;
+	chip->waitfunc = fsl_elbc_wait;
+	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
+
+	chip->bbt_td = &bbt_main_descr;
+	chip->bbt_md = &bbt_mirror_descr;
+
+	/* set up nand options */
+	chip->bbt_options = NAND_BBT_USE_FLASH;
+
+	chip->controller = &elbc_fcm_ctrl->controller;
+	nand_set_controller_data(chip, priv);
+
+	chip->ecc.read_page = fsl_elbc_read_page;
+	chip->ecc.write_page = fsl_elbc_write_page;
+	chip->ecc.write_subpage = fsl_elbc_write_subpage;
+
+	/* If CS Base Register selects full hardware ECC then use it */
+	if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+	    BR_DECC_CHK_GEN) {
+		chip->ecc.mode = NAND_ECC_HW;
+		mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
+		chip->ecc.size = 512;
+		chip->ecc.bytes = 3;
+		chip->ecc.strength = 1;
+	} else {
+		/* otherwise fall back to default software ECC */
+		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
+	}
+
+	return 0;
+}
+
+static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
+{
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+
+	nand_release(mtd);
+
+	kfree(mtd->name);
+
+	if (priv->vbase)
+		iounmap(priv->vbase);
+
+	elbc_fcm_ctrl->chips[priv->bank] = NULL;
+	kfree(priv);
+	return 0;
+}
+
+static DEFINE_MUTEX(fsl_elbc_nand_mutex);
+
+static int fsl_elbc_nand_probe(struct platform_device *pdev)
+{
+	struct fsl_lbc_regs __iomem *lbc;
+	struct fsl_elbc_mtd *priv;
+	struct resource res;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
+	int ret;
+	int bank;
+	struct device *dev;
+	struct device_node *node = pdev->dev.of_node;
+	struct mtd_info *mtd;
+
+	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+		return -ENODEV;
+	lbc = fsl_lbc_ctrl_dev->regs;
+	dev = fsl_lbc_ctrl_dev->dev;
+
+	/* get, allocate and map the memory resource */
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret) {
+		dev_err(dev, "failed to get resource\n");
+		return ret;
+	}
+
+	/* find which chip select it is connected to */
+	for (bank = 0; bank < MAX_BANKS; bank++)
+		if ((in_be32(&lbc->bank[bank].br) & BR_V) &&
+		    (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
+		    (in_be32(&lbc->bank[bank].br) &
+		     in_be32(&lbc->bank[bank].or) & BR_BA)
+		     == fsl_lbc_addr(res.start))
+			break;
+
+	if (bank >= MAX_BANKS) {
+		dev_err(dev, "address did not match any chip selects\n");
+		return -ENODEV;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_lock(&fsl_elbc_nand_mutex);
+	if (!fsl_lbc_ctrl_dev->nand) {
+		elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
+		if (!elbc_fcm_ctrl) {
+			mutex_unlock(&fsl_elbc_nand_mutex);
+			ret = -ENOMEM;
+			goto err;
+		}
+		elbc_fcm_ctrl->counter++;
+
+		nand_hw_control_init(&elbc_fcm_ctrl->controller);
+		fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
+	} else {
+		elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
+	}
+	mutex_unlock(&fsl_elbc_nand_mutex);
+
+	elbc_fcm_ctrl->chips[bank] = priv;
+	priv->bank = bank;
+	priv->ctrl = fsl_lbc_ctrl_dev;
+	priv->dev = &pdev->dev;
+	dev_set_drvdata(priv->dev, priv);
+
+	priv->vbase = ioremap(res.start, resource_size(&res));
+	if (!priv->vbase) {
+		dev_err(dev, "failed to map chip region\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	mtd = nand_to_mtd(&priv->chip);
+	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
+	if (!nand_to_mtd(&priv->chip)->name) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = fsl_elbc_chip_init(priv);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		goto err;
+
+	ret = fsl_elbc_chip_init_tail(mtd);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		goto err;
+
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	mtd_device_parse_register(mtd, part_probe_types, NULL,
+				  NULL, 0);
+
+	printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
+	       (unsigned long long)res.start, priv->bank);
+	return 0;
+
+err:
+	fsl_elbc_chip_remove(priv);
+	return ret;
+}
+
+static int fsl_elbc_nand_remove(struct platform_device *pdev)
+{
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
+	struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
+
+	fsl_elbc_chip_remove(priv);
+
+	mutex_lock(&fsl_elbc_nand_mutex);
+	elbc_fcm_ctrl->counter--;
+	if (!elbc_fcm_ctrl->counter) {
+		fsl_lbc_ctrl_dev->nand = NULL;
+		kfree(elbc_fcm_ctrl);
+	}
+	mutex_unlock(&fsl_elbc_nand_mutex);
+
+	return 0;
+
+}
+
+static const struct of_device_id fsl_elbc_nand_match[] = {
+	{ .compatible = "fsl,elbc-fcm-nand", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
+
+static struct platform_driver fsl_elbc_nand_driver = {
+	.driver = {
+		.name = "fsl,elbc-fcm-nand",
+		.of_match_table = fsl_elbc_nand_match,
+	},
+	.probe = fsl_elbc_nand_probe,
+	.remove = fsl_elbc_nand_remove,
+};
+
+module_platform_driver(fsl_elbc_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver");
diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
new file mode 100644
index 000000000000..4872a7ba6503
--- /dev/null
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -0,0 +1,1117 @@
+/*
+ * Freescale Integrated Flash Controller NAND driver
+ *
+ * Copyright 2011-2012 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/fsl_ifc.h>
+
+#define ERR_BYTE		0xFF /* Value returned for read
+					bytes when read failed	*/
+#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
+					for IFC NAND Machine	*/
+
+struct fsl_ifc_ctrl;
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+	struct nand_chip chip;
+	struct fsl_ifc_ctrl *ctrl;
+
+	struct device *dev;
+	int bank;		/* Chip select bank number		*/
+	unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
+	u8 __iomem *vbase;      /* Chip select base virtual address	*/
+};
+
+/* overview of the fsl ifc controller */
+struct fsl_ifc_nand_ctrl {
+	struct nand_hw_control controller;
+	struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+
+	void __iomem *addr;	/* Address of assigned IFC buffer	*/
+	unsigned int page;	/* Last page written to / read from	*/
+	unsigned int read_bytes;/* Number of bytes read during command	*/
+	unsigned int column;	/* Saved column from SEQIN		*/
+	unsigned int index;	/* Pointer to next byte to 'read'	*/
+	unsigned int oob;	/* Non zero if operating on OOB data	*/
+	unsigned int eccread;	/* Non zero for a full-page ECC read	*/
+	unsigned int counter;	/* counter for the initializations	*/
+	unsigned int max_bitflips;  /* Saved during READ0 cmd		*/
+};
+
+static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+
+/*
+ * Generic flash bbt descriptors
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = mirror_pattern,
+};
+
+static int fsl_ifc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int fsl_ifc_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section > 1)
+		return -ERANGE;
+
+	if (mtd->writesize == 512 &&
+	    !(chip->options & NAND_BUSWIDTH_16)) {
+		if (!section) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 6;
+			oobregion->length = 2;
+		}
+
+		return 0;
+	}
+
+	if (!section) {
+		oobregion->offset = 2;
+		oobregion->length = 6;
+	} else {
+		oobregion->offset = chip->ecc.total + 8;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
+	.ecc = fsl_ifc_ooblayout_ecc,
+	.free = fsl_ifc_ooblayout_free,
+};
+
+/*
+ * Set up the IFC hardware block and page address fields, and the ifc nand
+ * structure addr field to point to the correct IFC buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+	int buf_num;
+
+	ifc_nand_ctrl->page = page_addr;
+	/* Program ROW0/COL0 */
+	ifc_out32(page_addr, &ifc->ifc_nand.row0);
+	ifc_out32((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0);
+
+	buf_num = page_addr & priv->bufnum_mask;
+
+	ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+	ifc_nand_ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		ifc_nand_ctrl->index += mtd->writesize;
+}
+
+/* returns nonzero if entire page is blank */
+static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+			  u32 *eccstat, unsigned int bufnum)
+{
+	u32 reg = eccstat[bufnum / 4];
+	int errors;
+
+	errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+
+	return errors;
+}
+
+/*
+ * execute IFC NAND command and wait for it to complete
+ */
+static void fsl_ifc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+	u32 eccstat[4];
+	int i;
+
+	/* set the chip select for NAND Transaction */
+	ifc_out32(priv->bank << IFC_NAND_CSEL_SHIFT,
+		  &ifc->ifc_nand.nand_csel);
+
+	dev_vdbg(priv->dev,
+			"%s: fir0=%08x fcr0=%08x\n",
+			__func__,
+			ifc_in32(&ifc->ifc_nand.nand_fir0),
+			ifc_in32(&ifc->ifc_nand.nand_fcr0));
+
+	ctrl->nand_stat = 0;
+
+	/* start read/write seq */
+	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
+
+	/* wait for command complete flag or timeout */
+	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
+
+	/* ctrl->nand_stat will be updated from IRQ context */
+	if (!ctrl->nand_stat)
+		dev_err(priv->dev, "Controller is not responding\n");
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+		dev_err(priv->dev, "NAND Flash Timeout Error\n");
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+
+	nctrl->max_bitflips = 0;
+
+	if (nctrl->eccread) {
+		int errors;
+		int bufnum = nctrl->page & priv->bufnum_mask;
+		int sector = bufnum * chip->ecc.steps;
+		int sector_end = sector + chip->ecc.steps - 1;
+		__be32 *eccstat_regs;
+
+		if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
+			eccstat_regs = ifc->ifc_nand.v2_nand_eccstat;
+		else
+			eccstat_regs = ifc->ifc_nand.v1_nand_eccstat;
+
+		for (i = sector / 4; i <= sector_end / 4; i++)
+			eccstat[i] = ifc_in32(&eccstat_regs[i]);
+
+		for (i = sector; i <= sector_end; i++) {
+			errors = check_read_ecc(mtd, ctrl, eccstat, i);
+
+			if (errors == 15) {
+				/*
+				 * Uncorrectable error.
+				 * We'll check for blank pages later.
+				 *
+				 * We disable ECCER reporting due to...
+				 * erratum IFC-A002770 -- so report it now if we
+				 * see an uncorrectable error in ECCSTAT.
+				 */
+				ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
+				continue;
+			}
+
+			mtd->ecc_stats.corrected += errors;
+			nctrl->max_bitflips = max_t(unsigned int,
+						    nctrl->max_bitflips,
+						    errors);
+		}
+
+		nctrl->eccread = 0;
+	}
+}
+
+static void fsl_ifc_do_read(struct nand_chip *chip,
+			    int oob,
+			    struct mtd_info *mtd)
+{
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+
+	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+	if (mtd->writesize > 512) {
+		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT),
+			  &ifc->ifc_nand.nand_fir0);
+		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
+
+		ifc_out32((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			  (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT),
+			  &ifc->ifc_nand.nand_fcr0);
+	} else {
+		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT),
+			  &ifc->ifc_nand.nand_fir0);
+		ifc_out32(0x0, &ifc->ifc_nand.nand_fir1);
+
+		if (oob)
+			ifc_out32(NAND_CMD_READOOB <<
+				  IFC_NAND_FCR0_CMD0_SHIFT,
+				  &ifc->ifc_nand.nand_fcr0);
+		else
+			ifc_out32(NAND_CMD_READ0 <<
+				  IFC_NAND_FCR0_CMD0_SHIFT,
+				  &ifc->ifc_nand.nand_fcr0);
+	}
+}
+
+/* cmdfunc send commands to the IFC NAND Machine */
+static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+			     int column, int page_addr) {
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+
+	/* clear the read buffer */
+	ifc_nand_ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		ifc_nand_ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ0:
+		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
+		set_addr(mtd, 0, page_addr, 0);
+
+		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		ifc_nand_ctrl->index += column;
+
+		if (chip->ecc.mode == NAND_ECC_HW)
+			ifc_nand_ctrl->eccread = 1;
+
+		fsl_ifc_do_read(chip, 0, mtd);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		ifc_out32(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr);
+		set_addr(mtd, column, page_addr, 1);
+
+		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_ifc_do_read(chip, 1, mtd);
+		fsl_ifc_run_command(mtd);
+
+		return;
+
+	case NAND_CMD_READID:
+	case NAND_CMD_PARAM: {
+		int timing = IFC_FIR_OP_RB;
+		if (command == NAND_CMD_PARAM)
+			timing = IFC_FIR_OP_RBCD;
+
+		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (timing << IFC_NAND_FIR0_OP2_SHIFT),
+			  &ifc->ifc_nand.nand_fir0);
+		ifc_out32(command << IFC_NAND_FCR0_CMD0_SHIFT,
+			  &ifc->ifc_nand.nand_fcr0);
+		ifc_out32(column, &ifc->ifc_nand.row3);
+
+		/*
+		 * although currently it's 8 bytes for READID, we always read
+		 * the maximum 256 bytes(for PARAM)
+		 */
+		ifc_out32(256, &ifc->ifc_nand.nand_fbcr);
+		ifc_nand_ctrl->read_bytes = 256;
+
+		set_addr(mtd, 0, 0, 0);
+		fsl_ifc_run_command(mtd);
+		return;
+	}
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT),
+			  &ifc->ifc_nand.nand_fir0);
+
+		ifc_out32((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			  (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT),
+			  &ifc->ifc_nand.nand_fcr0);
+
+		ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
+		ifc_nand_ctrl->read_bytes = 0;
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		u32 nand_fcr0;
+		ifc_nand_ctrl->column = column;
+		ifc_nand_ctrl->oob = 0;
+
+		if (mtd->writesize > 512) {
+			nand_fcr0 =
+				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+				(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
+				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
+
+			ifc_out32(
+				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
+				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT),
+				&ifc->ifc_nand.nand_fir0);
+			ifc_out32(
+				(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
+				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP6_SHIFT) |
+				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT),
+				&ifc->ifc_nand.nand_fir1);
+		} else {
+			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+					IFC_NAND_FCR0_CMD1_SHIFT) |
+				    (NAND_CMD_SEQIN <<
+					IFC_NAND_FCR0_CMD2_SHIFT) |
+				    (NAND_CMD_STATUS <<
+					IFC_NAND_FCR0_CMD3_SHIFT));
+
+			ifc_out32(
+				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+				(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+				(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT),
+				&ifc->ifc_nand.nand_fir0);
+			ifc_out32(
+				(IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
+				(IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
+				(IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP7_SHIFT) |
+				(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT),
+				&ifc->ifc_nand.nand_fir1);
+
+			if (column >= mtd->writesize)
+				nand_fcr0 |=
+				NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+			else
+				nand_fcr0 |=
+				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+		}
+
+		if (column >= mtd->writesize) {
+			/* OOB area --> READOOB */
+			column -= mtd->writesize;
+			ifc_nand_ctrl->oob = 1;
+		}
+		ifc_out32(nand_fcr0, &ifc->ifc_nand.nand_fcr0);
+		set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG: {
+		if (ifc_nand_ctrl->oob) {
+			ifc_out32(ifc_nand_ctrl->index -
+				  ifc_nand_ctrl->column,
+				  &ifc->ifc_nand.nand_fbcr);
+		} else {
+			ifc_out32(0, &ifc->ifc_nand.nand_fbcr);
+		}
+
+		fsl_ifc_run_command(mtd);
+		return;
+	}
+
+	case NAND_CMD_STATUS: {
+		void __iomem *addr;
+
+		ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT),
+			  &ifc->ifc_nand.nand_fir0);
+		ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
+			  &ifc->ifc_nand.nand_fcr0);
+		ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
+		set_addr(mtd, 0, 0, 0);
+		ifc_nand_ctrl->read_bytes = 1;
+
+		fsl_ifc_run_command(mtd);
+
+		/*
+		 * The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		addr = ifc_nand_ctrl->addr;
+		if (chip->options & NAND_BUSWIDTH_16)
+			ifc_out16(ifc_in16(addr) | (NAND_STATUS_WP), addr);
+		else
+			ifc_out8(ifc_in8(addr) | (NAND_STATUS_WP), addr);
+		return;
+	}
+
+	case NAND_CMD_RESET:
+		ifc_out32(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT,
+			  &ifc->ifc_nand.nand_fir0);
+		ifc_out32(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT,
+			  &ifc->ifc_nand.nand_fcr0);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	default:
+		dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
+					__func__, command);
+	}
+}
+
+static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+{
+	/* The hardware does not seem to support multiple
+	 * chips per bank.
+	 */
+}
+
+/*
+ * Write buf to the IFC NAND Controller Data Buffer
+ */
+static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len <= 0) {
+		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+		return;
+	}
+
+	if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %u available)\n",
+			__func__, len, bufsize - ifc_nand_ctrl->index);
+		len = bufsize - ifc_nand_ctrl->index;
+	}
+
+	memcpy_toio(ifc_nand_ctrl->addr + ifc_nand_ctrl->index, buf, len);
+	ifc_nand_ctrl->index += len;
+}
+
+/*
+ * Read a byte from either the IFC hardware buffer
+ * read function for 8-bit buswidth
+ */
+static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	unsigned int offset;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+		offset = ifc_nand_ctrl->index++;
+		return ifc_in8(ifc_nand_ctrl->addr + offset);
+	}
+
+	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+	return ERR_BYTE;
+}
+
+/*
+ * Read two bytes from the IFC hardware buffer
+ * read function for 16-bit buswith
+ */
+static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	uint16_t data;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+		data = ifc_in16(ifc_nand_ctrl->addr + ifc_nand_ctrl->index);
+		ifc_nand_ctrl->index += 2;
+		return (uint8_t) data;
+	}
+
+	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+	return ERR_BYTE;
+}
+
+/*
+ * Read from the IFC Controller Data Buffer
+ */
+static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	int avail;
+
+	if (len < 0) {
+		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+		return;
+	}
+
+	avail = min((unsigned int)len,
+			ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
+	memcpy_fromio(buf, ifc_nand_ctrl->addr + ifc_nand_ctrl->index, avail);
+	ifc_nand_ctrl->index += avail;
+
+	if (len > avail)
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %d available)\n",
+			__func__, len, avail);
+}
+
+/*
+ * This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
+	u32 nand_fsr;
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+		  (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT),
+		  &ifc->ifc_nand.nand_fir0);
+	ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
+		  &ifc->ifc_nand.nand_fcr0);
+	ifc_out32(1, &ifc->ifc_nand.nand_fbcr);
+	set_addr(mtd, 0, 0, 0);
+	ifc_nand_ctrl->read_bytes = 1;
+
+	fsl_ifc_run_command(mtd);
+
+	nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
+
+	/*
+	 * The chip always seems to report that it is
+	 * write-protected, even when it is not.
+	 */
+	return nand_fsr | NAND_STATUS_WP;
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 *ecc = chip->oob_poi;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int i, res, bitflips = 0;
+	struct mtd_oob_region oobregion = { };
+
+	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	ecc += oobregion.offset;
+
+	for (i = 0; i < chip->ecc.steps; ++i) {
+		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+						  NULL, 0,
+						  chip->ecc.strength);
+		if (res < 0)
+			mtd->ecc_stats.failed++;
+		else
+			mtd->ecc_stats.corrected += res;
+
+		bitflips = max(res, bitflips);
+		buf += pkt_size;
+		ecc += ecc_size;
+	}
+
+	return bitflips;
+}
+
+static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			     uint8_t *buf, int oob_required, int page)
+{
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	if (oob_required)
+		fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
+		if (!oob_required)
+			fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+		return check_erased_page(chip, buf);
+	}
+
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+		mtd->ecc_stats.failed++;
+
+	return nctrl->max_bitflips;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			       const uint8_t *buf, int oob_required, int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
+
+	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
+							chip->numchips);
+	dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
+							chip->chipsize);
+	dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
+							chip->pagemask);
+	dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
+							chip->chip_delay);
+	dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
+							chip->badblockpos);
+	dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
+							chip->chip_shift);
+	dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
+							chip->page_shift);
+	dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
+							chip->phys_erase_shift);
+	dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
+							chip->ecc.mode);
+	dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
+							chip->ecc.steps);
+	dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
+							chip->ecc.bytes);
+	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
+							chip->ecc.total);
+	dev_dbg(priv->dev, "%s: mtd->ooblayout = %p\n", __func__,
+							mtd->ooblayout);
+	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
+	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
+	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
+							mtd->erasesize);
+	dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
+							mtd->writesize);
+	dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
+							mtd->oobsize);
+
+	return 0;
+}
+
+static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
+{
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
+	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
+	uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
+	uint32_t cs = priv->bank;
+
+	/* Save CSOR and CSOR_ext */
+	csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
+	csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
+
+	/* chage PageSize 8K and SpareSize 1K*/
+	csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
+	ifc_out32(csor_8k, &ifc_global->csor_cs[cs].csor);
+	ifc_out32(0x0000400, &ifc_global->csor_cs[cs].csor_ext);
+
+	/* READID */
+	ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+		    (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+		    (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
+		    &ifc_runtime->ifc_nand.nand_fir0);
+	ifc_out32(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT,
+		    &ifc_runtime->ifc_nand.nand_fcr0);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.row3);
+
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.nand_fbcr);
+
+	/* Program ROW0/COL0 */
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.row0);
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.col0);
+
+	/* set the chip select for NAND Transaction */
+	ifc_out32(cs << IFC_NAND_CSEL_SHIFT,
+		&ifc_runtime->ifc_nand.nand_csel);
+
+	/* start read seq */
+	ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT,
+		&ifc_runtime->ifc_nand.nandseq_strt);
+
+	/* wait for command complete flag or timeout */
+	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+			   msecs_to_jiffies(IFC_TIMEOUT_MSECS));
+
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+		printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
+
+	/* Restore CSOR and CSOR_ext */
+	ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
+	ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
+}
+
+static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+{
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_global __iomem *ifc_global = ctrl->gregs;
+	struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
+	struct nand_chip *chip = &priv->chip;
+	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+	u32 csor;
+
+	/* Fill in fsl_ifc_mtd structure */
+	mtd->dev.parent = priv->dev;
+	nand_set_flash_node(chip, priv->dev->of_node);
+
+	/* fill in nand_chip structure */
+	/* set up function call table */
+	if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
+		& CSPR_PORT_SIZE_16)
+		chip->read_byte = fsl_ifc_read_byte16;
+	else
+		chip->read_byte = fsl_ifc_read_byte;
+
+	chip->write_buf = fsl_ifc_write_buf;
+	chip->read_buf = fsl_ifc_read_buf;
+	chip->select_chip = fsl_ifc_select_chip;
+	chip->cmdfunc = fsl_ifc_cmdfunc;
+	chip->waitfunc = fsl_ifc_wait;
+	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
+
+	chip->bbt_td = &bbt_main_descr;
+	chip->bbt_md = &bbt_mirror_descr;
+
+	ifc_out32(0x0, &ifc_runtime->ifc_nand.ncfgr);
+
+	/* set up nand options */
+	chip->bbt_options = NAND_BBT_USE_FLASH;
+	chip->options = NAND_NO_SUBPAGE_WRITE;
+
+	if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
+		& CSPR_PORT_SIZE_16) {
+		chip->read_byte = fsl_ifc_read_byte16;
+		chip->options |= NAND_BUSWIDTH_16;
+	} else {
+		chip->read_byte = fsl_ifc_read_byte;
+	}
+
+	chip->controller = &ifc_nand_ctrl->controller;
+	nand_set_controller_data(chip, priv);
+
+	chip->ecc.read_page = fsl_ifc_read_page;
+	chip->ecc.write_page = fsl_ifc_write_page;
+
+	csor = ifc_in32(&ifc_global->csor_cs[priv->bank].csor);
+
+	switch (csor & CSOR_NAND_PGS_MASK) {
+	case CSOR_NAND_PGS_512:
+		if (!(chip->options & NAND_BUSWIDTH_16)) {
+			/* Avoid conflict with bad block marker */
+			bbt_main_descr.offs = 0;
+			bbt_mirror_descr.offs = 0;
+		}
+
+		priv->bufnum_mask = 15;
+		break;
+
+	case CSOR_NAND_PGS_2K:
+		priv->bufnum_mask = 3;
+		break;
+
+	case CSOR_NAND_PGS_4K:
+		priv->bufnum_mask = 1;
+		break;
+
+	case CSOR_NAND_PGS_8K:
+		priv->bufnum_mask = 0;
+		break;
+
+	default:
+		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
+		return -ENODEV;
+	}
+
+	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+	if (csor & CSOR_NAND_ECC_DEC_EN) {
+		chip->ecc.mode = NAND_ECC_HW;
+		mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
+
+		/* Hardware generates ECC per 512 Bytes */
+		chip->ecc.size = 512;
+		if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) {
+			chip->ecc.bytes = 8;
+			chip->ecc.strength = 4;
+		} else {
+			chip->ecc.bytes = 16;
+			chip->ecc.strength = 8;
+		}
+	} else {
+		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
+	}
+
+	if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
+		fsl_ifc_sram_init(priv);
+
+	/*
+	 * As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
+	 * versions which had 8KB. Hence bufnum mask needs to be updated.
+	 */
+	if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
+		priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
+
+	return 0;
+}
+
+static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
+{
+	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+
+	nand_release(mtd);
+
+	kfree(mtd->name);
+
+	if (priv->vbase)
+		iounmap(priv->vbase);
+
+	ifc_nand_ctrl->chips[priv->bank] = NULL;
+
+	return 0;
+}
+
+static int match_bank(struct fsl_ifc_global __iomem *ifc_global, int bank,
+		      phys_addr_t addr)
+{
+	u32 cspr = ifc_in32(&ifc_global->cspr_cs[bank].cspr);
+
+	if (!(cspr & CSPR_V))
+		return 0;
+	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+		return 0;
+
+	return (cspr & CSPR_BA) == convert_ifc_address(addr);
+}
+
+static DEFINE_MUTEX(fsl_ifc_nand_mutex);
+
+static int fsl_ifc_nand_probe(struct platform_device *dev)
+{
+	struct fsl_ifc_runtime __iomem *ifc;
+	struct fsl_ifc_mtd *priv;
+	struct resource res;
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
+	int ret;
+	int bank;
+	struct device_node *node = dev->dev.of_node;
+	struct mtd_info *mtd;
+
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->rregs)
+		return -ENODEV;
+	ifc = fsl_ifc_ctrl_dev->rregs;
+
+	/* get, allocate and map the memory resource */
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret) {
+		dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
+		return ret;
+	}
+
+	/* find which chip select it is connected to */
+	for (bank = 0; bank < fsl_ifc_ctrl_dev->banks; bank++) {
+		if (match_bank(fsl_ifc_ctrl_dev->gregs, bank, res.start))
+			break;
+	}
+
+	if (bank >= fsl_ifc_ctrl_dev->banks) {
+		dev_err(&dev->dev, "%s: address did not match any chip selects\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_lock(&fsl_ifc_nand_mutex);
+	if (!fsl_ifc_ctrl_dev->nand) {
+		ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
+		if (!ifc_nand_ctrl) {
+			mutex_unlock(&fsl_ifc_nand_mutex);
+			return -ENOMEM;
+		}
+
+		ifc_nand_ctrl->read_bytes = 0;
+		ifc_nand_ctrl->index = 0;
+		ifc_nand_ctrl->addr = NULL;
+		fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
+
+		nand_hw_control_init(&ifc_nand_ctrl->controller);
+	} else {
+		ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
+	}
+	mutex_unlock(&fsl_ifc_nand_mutex);
+
+	ifc_nand_ctrl->chips[bank] = priv;
+	priv->bank = bank;
+	priv->ctrl = fsl_ifc_ctrl_dev;
+	priv->dev = &dev->dev;
+
+	priv->vbase = ioremap(res.start, resource_size(&res));
+	if (!priv->vbase) {
+		dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(priv->dev, priv);
+
+	ifc_out32(IFC_NAND_EVTER_EN_OPC_EN |
+		  IFC_NAND_EVTER_EN_FTOER_EN |
+		  IFC_NAND_EVTER_EN_WPER_EN,
+		  &ifc->ifc_nand.nand_evter_en);
+
+	/* enable NAND Machine Interrupts */
+	ifc_out32(IFC_NAND_EVTER_INTR_OPCIR_EN |
+		  IFC_NAND_EVTER_INTR_FTOERIR_EN |
+		  IFC_NAND_EVTER_INTR_WPERIR_EN,
+		  &ifc->ifc_nand.nand_evter_intr_en);
+
+	mtd = nand_to_mtd(&priv->chip);
+	mtd->name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
+	if (!mtd->name) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = fsl_ifc_chip_init(priv);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		goto err;
+
+	ret = fsl_ifc_chip_init_tail(mtd);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		goto err;
+
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	mtd_device_parse_register(mtd, part_probe_types, NULL, NULL, 0);
+
+	dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
+		 (unsigned long long)res.start, priv->bank);
+	return 0;
+
+err:
+	fsl_ifc_chip_remove(priv);
+	return ret;
+}
+
+static int fsl_ifc_nand_remove(struct platform_device *dev)
+{
+	struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
+
+	fsl_ifc_chip_remove(priv);
+
+	mutex_lock(&fsl_ifc_nand_mutex);
+	ifc_nand_ctrl->counter--;
+	if (!ifc_nand_ctrl->counter) {
+		fsl_ifc_ctrl_dev->nand = NULL;
+		kfree(ifc_nand_ctrl);
+	}
+	mutex_unlock(&fsl_ifc_nand_mutex);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_ifc_nand_match[] = {
+	{
+		.compatible = "fsl,ifc-nand",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match);
+
+static struct platform_driver fsl_ifc_nand_driver = {
+	.driver = {
+		.name	= "fsl,ifc-nand",
+		.of_match_table = fsl_ifc_nand_match,
+	},
+	.probe       = fsl_ifc_nand_probe,
+	.remove      = fsl_ifc_nand_remove,
+};
+
+module_platform_driver(fsl_ifc_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
new file mode 100644
index 000000000000..a88e2cf66e0f
--- /dev/null
+++ b/drivers/mtd/nand/raw/fsl_upm.c
@@ -0,0 +1,363 @@
+/*
+ * Freescale UPM NAND driver.
+ *
+ * Copyright © 2007-2008  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <asm/fsl_lbc.h>
+
+#define FSL_UPM_WAIT_RUN_PATTERN  0x1
+#define FSL_UPM_WAIT_WRITE_BYTE   0x2
+#define FSL_UPM_WAIT_WRITE_BUFFER 0x4
+
+struct fsl_upm_nand {
+	struct device *dev;
+	struct nand_chip chip;
+	int last_ctrl;
+	struct mtd_partition *parts;
+	struct fsl_upm upm;
+	uint8_t upm_addr_offset;
+	uint8_t upm_cmd_offset;
+	void __iomem *io_base;
+	int rnb_gpio[NAND_MAX_CHIPS];
+	uint32_t mchip_offsets[NAND_MAX_CHIPS];
+	uint32_t mchip_count;
+	uint32_t mchip_number;
+	int chip_delay;
+	uint32_t wait_flags;
+};
+
+static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
+{
+	return container_of(mtd_to_nand(mtdinfo), struct fsl_upm_nand,
+			    chip);
+}
+
+static int fun_chip_ready(struct mtd_info *mtd)
+{
+	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+
+	if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
+		return 1;
+
+	dev_vdbg(fun->dev, "busy\n");
+	return 0;
+}
+
+static void fun_wait_rnb(struct fsl_upm_nand *fun)
+{
+	if (fun->rnb_gpio[fun->mchip_number] >= 0) {
+		struct mtd_info *mtd = nand_to_mtd(&fun->chip);
+		int cnt = 1000000;
+
+		while (--cnt && !fun_chip_ready(mtd))
+			cpu_relax();
+		if (!cnt)
+			dev_err(fun->dev, "tired waiting for RNB\n");
+	} else {
+		ndelay(100);
+	}
+}
+
+static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+	u32 mar;
+
+	if (!(ctrl & fun->last_ctrl)) {
+		fsl_upm_end_pattern(&fun->upm);
+
+		if (cmd == NAND_CMD_NONE)
+			return;
+
+		fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
+	}
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if (ctrl & NAND_ALE)
+			fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
+		else if (ctrl & NAND_CLE)
+			fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
+	}
+
+	mar = (cmd << (32 - fun->upm.width)) |
+		fun->mchip_offsets[fun->mchip_number];
+	fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
+
+	if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
+		fun_wait_rnb(fun);
+}
+
+static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+
+	if (mchip_nr == -1) {
+		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+	} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
+		fun->mchip_number = mchip_nr;
+		chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
+		chip->IO_ADDR_W = chip->IO_ADDR_R;
+	} else {
+		BUG();
+	}
+}
+
+static uint8_t fun_read_byte(struct mtd_info *mtd)
+{
+	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+
+	return in_8(fun->chip.IO_ADDR_R);
+}
+
+static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+	int i;
+
+	for (i = 0; i < len; i++)
+		buf[i] = in_8(fun->chip.IO_ADDR_R);
+}
+
+static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		out_8(fun->chip.IO_ADDR_W, buf[i]);
+		if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
+			fun_wait_rnb(fun);
+	}
+	if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER)
+		fun_wait_rnb(fun);
+}
+
+static int fun_chip_init(struct fsl_upm_nand *fun,
+			 const struct device_node *upm_np,
+			 const struct resource *io_res)
+{
+	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
+	int ret;
+	struct device_node *flash_np;
+
+	fun->chip.IO_ADDR_R = fun->io_base;
+	fun->chip.IO_ADDR_W = fun->io_base;
+	fun->chip.cmd_ctrl = fun_cmd_ctrl;
+	fun->chip.chip_delay = fun->chip_delay;
+	fun->chip.read_byte = fun_read_byte;
+	fun->chip.read_buf = fun_read_buf;
+	fun->chip.write_buf = fun_write_buf;
+	fun->chip.ecc.mode = NAND_ECC_SOFT;
+	fun->chip.ecc.algo = NAND_ECC_HAMMING;
+	if (fun->mchip_count > 1)
+		fun->chip.select_chip = fun_select_chip;
+
+	if (fun->rnb_gpio[0] >= 0)
+		fun->chip.dev_ready = fun_chip_ready;
+
+	mtd->dev.parent = fun->dev;
+
+	flash_np = of_get_next_child(upm_np, NULL);
+	if (!flash_np)
+		return -ENODEV;
+
+	nand_set_flash_node(&fun->chip, flash_np);
+	mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
+			      flash_np->name);
+	if (!mtd->name) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = nand_scan(mtd, fun->mchip_count);
+	if (ret)
+		goto err;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+err:
+	of_node_put(flash_np);
+	if (ret)
+		kfree(mtd->name);
+	return ret;
+}
+
+static int fun_probe(struct platform_device *ofdev)
+{
+	struct fsl_upm_nand *fun;
+	struct resource io_res;
+	const __be32 *prop;
+	int rnb_gpio;
+	int ret;
+	int size;
+	int i;
+
+	fun = kzalloc(sizeof(*fun), GFP_KERNEL);
+	if (!fun)
+		return -ENOMEM;
+
+	ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res);
+	if (ret) {
+		dev_err(&ofdev->dev, "can't get IO base\n");
+		goto err1;
+	}
+
+	ret = fsl_upm_find(io_res.start, &fun->upm);
+	if (ret) {
+		dev_err(&ofdev->dev, "can't find UPM\n");
+		goto err1;
+	}
+
+	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset",
+			       &size);
+	if (!prop || size != sizeof(uint32_t)) {
+		dev_err(&ofdev->dev, "can't get UPM address offset\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+	fun->upm_addr_offset = *prop;
+
+	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size);
+	if (!prop || size != sizeof(uint32_t)) {
+		dev_err(&ofdev->dev, "can't get UPM command offset\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+	fun->upm_cmd_offset = *prop;
+
+	prop = of_get_property(ofdev->dev.of_node,
+			       "fsl,upm-addr-line-cs-offsets", &size);
+	if (prop && (size / sizeof(uint32_t)) > 0) {
+		fun->mchip_count = size / sizeof(uint32_t);
+		if (fun->mchip_count >= NAND_MAX_CHIPS) {
+			dev_err(&ofdev->dev, "too much multiple chips\n");
+			goto err1;
+		}
+		for (i = 0; i < fun->mchip_count; i++)
+			fun->mchip_offsets[i] = be32_to_cpu(prop[i]);
+	} else {
+		fun->mchip_count = 1;
+	}
+
+	for (i = 0; i < fun->mchip_count; i++) {
+		fun->rnb_gpio[i] = -1;
+		rnb_gpio = of_get_gpio(ofdev->dev.of_node, i);
+		if (rnb_gpio >= 0) {
+			ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
+			if (ret) {
+				dev_err(&ofdev->dev,
+					"can't request RNB gpio #%d\n", i);
+				goto err2;
+			}
+			gpio_direction_input(rnb_gpio);
+			fun->rnb_gpio[i] = rnb_gpio;
+		} else if (rnb_gpio == -EINVAL) {
+			dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i);
+			goto err2;
+		}
+	}
+
+	prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
+	if (prop)
+		fun->chip_delay = be32_to_cpup(prop);
+	else
+		fun->chip_delay = 50;
+
+	prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
+	if (prop && size == sizeof(uint32_t))
+		fun->wait_flags = be32_to_cpup(prop);
+	else
+		fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN |
+				  FSL_UPM_WAIT_WRITE_BYTE;
+
+	fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
+					    resource_size(&io_res));
+	if (!fun->io_base) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	fun->dev = &ofdev->dev;
+	fun->last_ctrl = NAND_CLE;
+
+	ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res);
+	if (ret)
+		goto err2;
+
+	dev_set_drvdata(&ofdev->dev, fun);
+
+	return 0;
+err2:
+	for (i = 0; i < fun->mchip_count; i++) {
+		if (fun->rnb_gpio[i] < 0)
+			break;
+		gpio_free(fun->rnb_gpio[i]);
+	}
+err1:
+	kfree(fun);
+
+	return ret;
+}
+
+static int fun_remove(struct platform_device *ofdev)
+{
+	struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
+	struct mtd_info *mtd = nand_to_mtd(&fun->chip);
+	int i;
+
+	nand_release(mtd);
+	kfree(mtd->name);
+
+	for (i = 0; i < fun->mchip_count; i++) {
+		if (fun->rnb_gpio[i] < 0)
+			break;
+		gpio_free(fun->rnb_gpio[i]);
+	}
+
+	kfree(fun);
+
+	return 0;
+}
+
+static const struct of_device_id of_fun_match[] = {
+	{ .compatible = "fsl,upm-nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_fun_match);
+
+static struct platform_driver of_fun_driver = {
+	.driver = {
+		.name = "fsl,upm-nand",
+		.of_match_table = of_fun_match,
+	},
+	.probe		= fun_probe,
+	.remove		= fun_remove,
+};
+
+module_platform_driver(of_fun_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
+		   "LocalBus User-Programmable Machine");
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
new file mode 100644
index 000000000000..28c48dcc514e
--- /dev/null
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -0,0 +1,1207 @@
+/*
+ * ST Microelectronics
+ * Flexible Static Memory Controller (FSMC)
+ * Driver for NAND portions
+ *
+ * Copyright © 2010 ST Microelectronics
+ * Vipin Kumar <vipin.kumar@st.com>
+ * Ashish Priyadarshi
+ *
+ * Based on drivers/mtd/nand/nomadik_nand.c (removed in v3.8)
+ *  Copyright © 2007 STMicroelectronics Pvt. Ltd.
+ *  Copyright © 2009 Alessandro Rubini
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/resource.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/amba/bus.h>
+#include <mtd/mtd-abi.h>
+
+/* fsmc controller registers for NOR flash */
+#define CTRL			0x0
+	/* ctrl register definitions */
+	#define BANK_ENABLE		(1 << 0)
+	#define MUXED			(1 << 1)
+	#define NOR_DEV			(2 << 2)
+	#define WIDTH_8			(0 << 4)
+	#define WIDTH_16		(1 << 4)
+	#define RSTPWRDWN		(1 << 6)
+	#define WPROT			(1 << 7)
+	#define WRT_ENABLE		(1 << 12)
+	#define WAIT_ENB		(1 << 13)
+
+#define CTRL_TIM		0x4
+	/* ctrl_tim register definitions */
+
+#define FSMC_NOR_BANK_SZ	0x8
+#define FSMC_NOR_REG_SIZE	0x40
+
+#define FSMC_NOR_REG(base, bank, reg)		(base + \
+						FSMC_NOR_BANK_SZ * (bank) + \
+						reg)
+
+/* fsmc controller registers for NAND flash */
+#define PC			0x00
+	/* pc register definitions */
+	#define FSMC_RESET		(1 << 0)
+	#define FSMC_WAITON		(1 << 1)
+	#define FSMC_ENABLE		(1 << 2)
+	#define FSMC_DEVTYPE_NAND	(1 << 3)
+	#define FSMC_DEVWID_8		(0 << 4)
+	#define FSMC_DEVWID_16		(1 << 4)
+	#define FSMC_ECCEN		(1 << 6)
+	#define FSMC_ECCPLEN_512	(0 << 7)
+	#define FSMC_ECCPLEN_256	(1 << 7)
+	#define FSMC_TCLR_1		(1)
+	#define FSMC_TCLR_SHIFT		(9)
+	#define FSMC_TCLR_MASK		(0xF)
+	#define FSMC_TAR_1		(1)
+	#define FSMC_TAR_SHIFT		(13)
+	#define FSMC_TAR_MASK		(0xF)
+#define STS			0x04
+	/* sts register definitions */
+	#define FSMC_CODE_RDY		(1 << 15)
+#define COMM			0x08
+	/* comm register definitions */
+	#define FSMC_TSET_0		0
+	#define FSMC_TSET_SHIFT		0
+	#define FSMC_TSET_MASK		0xFF
+	#define FSMC_TWAIT_6		6
+	#define FSMC_TWAIT_SHIFT	8
+	#define FSMC_TWAIT_MASK		0xFF
+	#define FSMC_THOLD_4		4
+	#define FSMC_THOLD_SHIFT	16
+	#define FSMC_THOLD_MASK		0xFF
+	#define FSMC_THIZ_1		1
+	#define FSMC_THIZ_SHIFT		24
+	#define FSMC_THIZ_MASK		0xFF
+#define ATTRIB			0x0C
+#define IOATA			0x10
+#define ECC1			0x14
+#define ECC2			0x18
+#define ECC3			0x1C
+#define FSMC_NAND_BANK_SZ	0x20
+
+#define FSMC_BUSY_WAIT_TIMEOUT	(1 * HZ)
+
+struct fsmc_nand_timings {
+	uint8_t tclr;
+	uint8_t tar;
+	uint8_t thiz;
+	uint8_t thold;
+	uint8_t twait;
+	uint8_t tset;
+};
+
+enum access_mode {
+	USE_DMA_ACCESS = 1,
+	USE_WORD_ACCESS,
+};
+
+/**
+ * struct fsmc_nand_data - structure for FSMC NAND device state
+ *
+ * @pid:		Part ID on the AMBA PrimeCell format
+ * @mtd:		MTD info for a NAND flash.
+ * @nand:		Chip related info for a NAND flash.
+ * @partitions:		Partition info for a NAND Flash.
+ * @nr_partitions:	Total number of partition of a NAND flash.
+ *
+ * @bank:		Bank number for probed device.
+ * @clk:		Clock structure for FSMC.
+ *
+ * @read_dma_chan:	DMA channel for read access
+ * @write_dma_chan:	DMA channel for write access to NAND
+ * @dma_access_complete: Completion structure
+ *
+ * @data_pa:		NAND Physical port for Data.
+ * @data_va:		NAND port for Data.
+ * @cmd_va:		NAND port for Command.
+ * @addr_va:		NAND port for Address.
+ * @regs_va:		Registers base address for a given bank.
+ */
+struct fsmc_nand_data {
+	u32			pid;
+	struct nand_chip	nand;
+
+	unsigned int		bank;
+	struct device		*dev;
+	enum access_mode	mode;
+	struct clk		*clk;
+
+	/* DMA related objects */
+	struct dma_chan		*read_dma_chan;
+	struct dma_chan		*write_dma_chan;
+	struct completion	dma_access_complete;
+
+	struct fsmc_nand_timings *dev_timings;
+
+	dma_addr_t		data_pa;
+	void __iomem		*data_va;
+	void __iomem		*cmd_va;
+	void __iomem		*addr_va;
+	void __iomem		*regs_va;
+};
+
+static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 2;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int fsmc_ecc1_ooblayout_free(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 8;
+
+	if (section < chip->ecc.steps - 1)
+		oobregion->length = 8;
+	else
+		oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
+	.ecc = fsmc_ecc1_ooblayout_ecc,
+	.free = fsmc_ecc1_ooblayout_free,
+};
+
+/*
+ * ECC placement definitions in oobfree type format.
+ * There are 13 bytes of ecc for every 512 byte block and it has to be read
+ * consecutively and immediately after the 512 byte data block for hardware to
+ * generate the error bit offsets in 512 byte data.
+ */
+static int fsmc_ecc4_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->length = chip->ecc.bytes;
+
+	if (!section && mtd->writesize <= 512)
+		oobregion->offset = 0;
+	else
+		oobregion->offset = (section * 16) + 2;
+
+	return 0;
+}
+
+static int fsmc_ecc4_ooblayout_free(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 15;
+
+	if (section < chip->ecc.steps - 1)
+		oobregion->length = 3;
+	else
+		oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
+	.ecc = fsmc_ecc4_ooblayout_ecc,
+	.free = fsmc_ecc4_ooblayout_free,
+};
+
+static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
+}
+
+/*
+ * fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine
+ *
+ * This routine initializes timing parameters related to NAND memory access in
+ * FSMC registers
+ */
+static void fsmc_nand_setup(struct fsmc_nand_data *host,
+			    struct fsmc_nand_timings *tims)
+{
+	uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
+	uint32_t tclr, tar, thiz, thold, twait, tset;
+
+	tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
+	tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
+	thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT;
+	thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT;
+	twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
+	tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
+
+	if (host->nand.options & NAND_BUSWIDTH_16)
+		writel_relaxed(value | FSMC_DEVWID_16, host->regs_va + PC);
+	else
+		writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + PC);
+
+	writel_relaxed(readl(host->regs_va + PC) | tclr | tar,
+		       host->regs_va + PC);
+	writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM);
+	writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB);
+}
+
+static int fsmc_calc_timings(struct fsmc_nand_data *host,
+			     const struct nand_sdr_timings *sdrt,
+			     struct fsmc_nand_timings *tims)
+{
+	unsigned long hclk = clk_get_rate(host->clk);
+	unsigned long hclkn = NSEC_PER_SEC / hclk;
+	uint32_t thiz, thold, twait, tset;
+
+	if (sdrt->tRC_min < 30000)
+		return -EOPNOTSUPP;
+
+	tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
+	if (tims->tar > FSMC_TAR_MASK)
+		tims->tar = FSMC_TAR_MASK;
+	tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
+	if (tims->tclr > FSMC_TCLR_MASK)
+		tims->tclr = FSMC_TCLR_MASK;
+
+	thiz = sdrt->tCS_min - sdrt->tWP_min;
+	tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
+
+	thold = sdrt->tDH_min;
+	if (thold < sdrt->tCH_min)
+		thold = sdrt->tCH_min;
+	if (thold < sdrt->tCLH_min)
+		thold = sdrt->tCLH_min;
+	if (thold < sdrt->tWH_min)
+		thold = sdrt->tWH_min;
+	if (thold < sdrt->tALH_min)
+		thold = sdrt->tALH_min;
+	if (thold < sdrt->tREH_min)
+		thold = sdrt->tREH_min;
+	tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
+	if (tims->thold == 0)
+		tims->thold = 1;
+	else if (tims->thold > FSMC_THOLD_MASK)
+		tims->thold = FSMC_THOLD_MASK;
+
+	twait = max(sdrt->tRP_min, sdrt->tWP_min);
+	tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+	if (tims->twait == 0)
+		tims->twait = 1;
+	else if (tims->twait > FSMC_TWAIT_MASK)
+		tims->twait = FSMC_TWAIT_MASK;
+
+	tset = max(sdrt->tCS_min - sdrt->tWP_min,
+		   sdrt->tCEA_max - sdrt->tREA_max);
+	tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
+	if (tims->tset == 0)
+		tims->tset = 1;
+	else if (tims->tset > FSMC_TSET_MASK)
+		tims->tset = FSMC_TSET_MASK;
+
+	return 0;
+}
+
+static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
+				     const struct nand_data_interface *conf)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct fsmc_nand_data *host = nand_get_controller_data(nand);
+	struct fsmc_nand_timings tims;
+	const struct nand_sdr_timings *sdrt;
+	int ret;
+
+	sdrt = nand_get_sdr_timings(conf);
+	if (IS_ERR(sdrt))
+		return PTR_ERR(sdrt);
+
+	ret = fsmc_calc_timings(host, sdrt, &tims);
+	if (ret)
+		return ret;
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	fsmc_nand_setup(host, &tims);
+
+	return 0;
+}
+
+/*
+ * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
+ */
+static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+
+	writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCPLEN_256,
+		       host->regs_va + PC);
+	writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCEN,
+		       host->regs_va + PC);
+	writel_relaxed(readl(host->regs_va + PC) | FSMC_ECCEN,
+		       host->regs_va + PC);
+}
+
+/*
+ * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by
+ * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
+ * max of 8-bits)
+ */
+static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
+				uint8_t *ecc)
+{
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+	uint32_t ecc_tmp;
+	unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
+
+	do {
+		if (readl_relaxed(host->regs_va + STS) & FSMC_CODE_RDY)
+			break;
+		else
+			cond_resched();
+	} while (!time_after_eq(jiffies, deadline));
+
+	if (time_after_eq(jiffies, deadline)) {
+		dev_err(host->dev, "calculate ecc timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	ecc_tmp = readl_relaxed(host->regs_va + ECC1);
+	ecc[0] = (uint8_t) (ecc_tmp >> 0);
+	ecc[1] = (uint8_t) (ecc_tmp >> 8);
+	ecc[2] = (uint8_t) (ecc_tmp >> 16);
+	ecc[3] = (uint8_t) (ecc_tmp >> 24);
+
+	ecc_tmp = readl_relaxed(host->regs_va + ECC2);
+	ecc[4] = (uint8_t) (ecc_tmp >> 0);
+	ecc[5] = (uint8_t) (ecc_tmp >> 8);
+	ecc[6] = (uint8_t) (ecc_tmp >> 16);
+	ecc[7] = (uint8_t) (ecc_tmp >> 24);
+
+	ecc_tmp = readl_relaxed(host->regs_va + ECC3);
+	ecc[8] = (uint8_t) (ecc_tmp >> 0);
+	ecc[9] = (uint8_t) (ecc_tmp >> 8);
+	ecc[10] = (uint8_t) (ecc_tmp >> 16);
+	ecc[11] = (uint8_t) (ecc_tmp >> 24);
+
+	ecc_tmp = readl_relaxed(host->regs_va + STS);
+	ecc[12] = (uint8_t) (ecc_tmp >> 16);
+
+	return 0;
+}
+
+/*
+ * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by
+ * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
+ * max of 1-bit)
+ */
+static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
+				uint8_t *ecc)
+{
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+	uint32_t ecc_tmp;
+
+	ecc_tmp = readl_relaxed(host->regs_va + ECC1);
+	ecc[0] = (uint8_t) (ecc_tmp >> 0);
+	ecc[1] = (uint8_t) (ecc_tmp >> 8);
+	ecc[2] = (uint8_t) (ecc_tmp >> 16);
+
+	return 0;
+}
+
+/* Count the number of 0's in buff upto a max of max_bits */
+static int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+	int k, written_bits = 0;
+
+	for (k = 0; k < size; k++) {
+		written_bits += hweight8(~buff[k]);
+		if (written_bits > max_bits)
+			break;
+	}
+
+	return written_bits;
+}
+
+static void dma_complete(void *param)
+{
+	struct fsmc_nand_data *host = param;
+
+	complete(&host->dma_access_complete);
+}
+
+static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
+		enum dma_data_direction direction)
+{
+	struct dma_chan *chan;
+	struct dma_device *dma_dev;
+	struct dma_async_tx_descriptor *tx;
+	dma_addr_t dma_dst, dma_src, dma_addr;
+	dma_cookie_t cookie;
+	unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+	int ret;
+	unsigned long time_left;
+
+	if (direction == DMA_TO_DEVICE)
+		chan = host->write_dma_chan;
+	else if (direction == DMA_FROM_DEVICE)
+		chan = host->read_dma_chan;
+	else
+		return -EINVAL;
+
+	dma_dev = chan->device;
+	dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction);
+
+	if (direction == DMA_TO_DEVICE) {
+		dma_src = dma_addr;
+		dma_dst = host->data_pa;
+	} else {
+		dma_src = host->data_pa;
+		dma_dst = dma_addr;
+	}
+
+	tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
+			len, flags);
+	if (!tx) {
+		dev_err(host->dev, "device_prep_dma_memcpy error\n");
+		ret = -EIO;
+		goto unmap_dma;
+	}
+
+	tx->callback = dma_complete;
+	tx->callback_param = host;
+	cookie = tx->tx_submit(tx);
+
+	ret = dma_submit_error(cookie);
+	if (ret) {
+		dev_err(host->dev, "dma_submit_error %d\n", cookie);
+		goto unmap_dma;
+	}
+
+	dma_async_issue_pending(chan);
+
+	time_left =
+	wait_for_completion_timeout(&host->dma_access_complete,
+				msecs_to_jiffies(3000));
+	if (time_left == 0) {
+		dmaengine_terminate_all(chan);
+		dev_err(host->dev, "wait_for_completion_timeout\n");
+		ret = -ETIMEDOUT;
+		goto unmap_dma;
+	}
+
+	ret = 0;
+
+unmap_dma:
+	dma_unmap_single(dma_dev->dev, dma_addr, len, direction);
+
+	return ret;
+}
+
+/*
+ * fsmc_write_buf - write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ */
+static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
+	int i;
+
+	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+			IS_ALIGNED(len, sizeof(uint32_t))) {
+		uint32_t *p = (uint32_t *)buf;
+		len = len >> 2;
+		for (i = 0; i < len; i++)
+			writel_relaxed(p[i], host->data_va);
+	} else {
+		for (i = 0; i < len; i++)
+			writeb_relaxed(buf[i], host->data_va);
+	}
+}
+
+/*
+ * fsmc_read_buf - read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ */
+static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
+	int i;
+
+	if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+			IS_ALIGNED(len, sizeof(uint32_t))) {
+		uint32_t *p = (uint32_t *)buf;
+		len = len >> 2;
+		for (i = 0; i < len; i++)
+			p[i] = readl_relaxed(host->data_va);
+	} else {
+		for (i = 0; i < len; i++)
+			buf[i] = readb_relaxed(host->data_va);
+	}
+}
+
+/*
+ * fsmc_read_buf_dma - read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ */
+static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
+
+	dma_xfer(host, buf, len, DMA_FROM_DEVICE);
+}
+
+/*
+ * fsmc_write_buf_dma - write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ */
+static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
+		int len)
+{
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+
+	dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
+}
+
+/* fsmc_select_chip - assert or deassert nCE */
+static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+	u32 pc;
+
+	/* Support only one CS */
+	if (chipnr > 0)
+		return;
+
+	pc = readl(host->regs_va + PC);
+	if (chipnr < 0)
+		writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + PC);
+	else
+		writel_relaxed(pc | FSMC_ENABLE, host->regs_va + PC);
+
+	/* nCE line must be asserted before starting any operation */
+	mb();
+}
+
+/*
+ * fsmc_exec_op - hook called by the core to execute NAND operations
+ *
+ * This controller is simple enough and thus does not need to use the parser
+ * provided by the core, instead, handle every situation here.
+ */
+static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
+			bool check_only)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+	const struct nand_op_instr *instr = NULL;
+	int ret = 0;
+	unsigned int op_id;
+	int i;
+
+	pr_debug("Executing operation [%d instructions]:\n", op->ninstrs);
+	for (op_id = 0; op_id < op->ninstrs; op_id++) {
+		instr = &op->instrs[op_id];
+
+		switch (instr->type) {
+		case NAND_OP_CMD_INSTR:
+			pr_debug("  ->CMD      [0x%02x]\n",
+				 instr->ctx.cmd.opcode);
+
+			writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va);
+			break;
+
+		case NAND_OP_ADDR_INSTR:
+			pr_debug("  ->ADDR     [%d cyc]",
+				 instr->ctx.addr.naddrs);
+
+			for (i = 0; i < instr->ctx.addr.naddrs; i++)
+				writeb_relaxed(instr->ctx.addr.addrs[i],
+					       host->addr_va);
+			break;
+
+		case NAND_OP_DATA_IN_INSTR:
+			pr_debug("  ->DATA_IN  [%d B%s]\n", instr->ctx.data.len,
+				 instr->ctx.data.force_8bit ?
+				 ", force 8-bit" : "");
+
+			if (host->mode == USE_DMA_ACCESS)
+				fsmc_read_buf_dma(mtd, instr->ctx.data.buf.in,
+						  instr->ctx.data.len);
+			else
+				fsmc_read_buf(mtd, instr->ctx.data.buf.in,
+					      instr->ctx.data.len);
+			break;
+
+		case NAND_OP_DATA_OUT_INSTR:
+			pr_debug("  ->DATA_OUT [%d B%s]\n", instr->ctx.data.len,
+				 instr->ctx.data.force_8bit ?
+				 ", force 8-bit" : "");
+
+			if (host->mode == USE_DMA_ACCESS)
+				fsmc_write_buf_dma(mtd, instr->ctx.data.buf.out,
+						   instr->ctx.data.len);
+			else
+				fsmc_write_buf(mtd, instr->ctx.data.buf.out,
+					       instr->ctx.data.len);
+			break;
+
+		case NAND_OP_WAITRDY_INSTR:
+			pr_debug("  ->WAITRDY  [max %d ms]\n",
+				 instr->ctx.waitrdy.timeout_ms);
+
+			ret = nand_soft_waitrdy(chip,
+						instr->ctx.waitrdy.timeout_ms);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * fsmc_read_page_hwecc
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @buf:	buffer to store read data
+ * @oob_required:	caller expects OOB data read to chip->oob_poi
+ * @page:	page number to read
+ *
+ * This routine is needed for fsmc version 8 as reading from NAND chip has to be
+ * performed in a strict sequence as follows:
+ * data(512 byte) -> ecc(13 byte)
+ * After this read, fsmc hardware generates and reports error data bits(up to a
+ * max of 8 bits)
+ */
+static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				 uint8_t *buf, int oob_required, int page)
+{
+	int i, j, s, stat, eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	uint8_t *p = buf;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	uint8_t *ecc_code = chip->ecc.code_buf;
+	int off, len, group = 0;
+	/*
+	 * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we
+	 * end up reading 14 bytes (7 words) from oob. The local array is
+	 * to maintain word alignment
+	 */
+	uint16_t ecc_oob[7];
+	uint8_t *oob = (uint8_t *)&ecc_oob[0];
+	unsigned int max_bitflips = 0;
+
+	for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
+		nand_read_page_op(chip, page, s * eccsize, NULL, 0);
+		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+		chip->read_buf(mtd, p, eccsize);
+
+		for (j = 0; j < eccbytes;) {
+			struct mtd_oob_region oobregion;
+			int ret;
+
+			ret = mtd_ooblayout_ecc(mtd, group++, &oobregion);
+			if (ret)
+				return ret;
+
+			off = oobregion.offset;
+			len = oobregion.length;
+
+			/*
+			 * length is intentionally kept a higher multiple of 2
+			 * to read at least 13 bytes even in case of 16 bit NAND
+			 * devices
+			 */
+			if (chip->options & NAND_BUSWIDTH_16)
+				len = roundup(len, 2);
+
+			nand_read_oob_op(chip, page, off, oob + j, len);
+			j += len;
+		}
+
+		memcpy(&ecc_code[i], oob, chip->ecc.bytes);
+		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+
+	return max_bitflips;
+}
+
+/*
+ * fsmc_bch8_correct_data
+ * @mtd:	mtd info structure
+ * @dat:	buffer of read data
+ * @read_ecc:	ecc read from device spare area
+ * @calc_ecc:	ecc calculated from read data
+ *
+ * calc_ecc is a 104 bit information containing maximum of 8 error
+ * offset informations of 13 bits each in 512 bytes of read data.
+ */
+static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
+			     uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+	uint32_t err_idx[8];
+	uint32_t num_err, i;
+	uint32_t ecc1, ecc2, ecc3, ecc4;
+
+	num_err = (readl_relaxed(host->regs_va + STS) >> 10) & 0xF;
+
+	/* no bit flipping */
+	if (likely(num_err == 0))
+		return 0;
+
+	/* too many errors */
+	if (unlikely(num_err > 8)) {
+		/*
+		 * This is a temporary erase check. A newly erased page read
+		 * would result in an ecc error because the oob data is also
+		 * erased to FF and the calculated ecc for an FF data is not
+		 * FF..FF.
+		 * This is a workaround to skip performing correction in case
+		 * data is FF..FF
+		 *
+		 * Logic:
+		 * For every page, each bit written as 0 is counted until these
+		 * number of bits are greater than 8 (the maximum correction
+		 * capability of FSMC for each 512 + 13 bytes)
+		 */
+
+		int bits_ecc = count_written_bits(read_ecc, chip->ecc.bytes, 8);
+		int bits_data = count_written_bits(dat, chip->ecc.size, 8);
+
+		if ((bits_ecc + bits_data) <= 8) {
+			if (bits_data)
+				memset(dat, 0xff, chip->ecc.size);
+			return bits_data;
+		}
+
+		return -EBADMSG;
+	}
+
+	/*
+	 * ------------------- calc_ecc[] bit wise -----------|--13 bits--|
+	 * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--|
+	 *
+	 * calc_ecc is a 104 bit information containing maximum of 8 error
+	 * offset informations of 13 bits each. calc_ecc is copied into a
+	 * uint64_t array and error offset indexes are populated in err_idx
+	 * array
+	 */
+	ecc1 = readl_relaxed(host->regs_va + ECC1);
+	ecc2 = readl_relaxed(host->regs_va + ECC2);
+	ecc3 = readl_relaxed(host->regs_va + ECC3);
+	ecc4 = readl_relaxed(host->regs_va + STS);
+
+	err_idx[0] = (ecc1 >> 0) & 0x1FFF;
+	err_idx[1] = (ecc1 >> 13) & 0x1FFF;
+	err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F);
+	err_idx[3] = (ecc2 >> 7) & 0x1FFF;
+	err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF);
+	err_idx[5] = (ecc3 >> 1) & 0x1FFF;
+	err_idx[6] = (ecc3 >> 14) & 0x1FFF;
+	err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F);
+
+	i = 0;
+	while (num_err--) {
+		change_bit(0, (unsigned long *)&err_idx[i]);
+		change_bit(1, (unsigned long *)&err_idx[i]);
+
+		if (err_idx[i] < chip->ecc.size * 8) {
+			change_bit(err_idx[i], (unsigned long *)dat);
+			i++;
+		}
+	}
+	return i;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+	chan->private = slave;
+	return true;
+}
+
+static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
+				     struct fsmc_nand_data *host,
+				     struct nand_chip *nand)
+{
+	struct device_node *np = pdev->dev.of_node;
+	u32 val;
+	int ret;
+
+	nand->options = 0;
+
+	if (!of_property_read_u32(np, "bank-width", &val)) {
+		if (val == 2) {
+			nand->options |= NAND_BUSWIDTH_16;
+		} else if (val != 1) {
+			dev_err(&pdev->dev, "invalid bank-width %u\n", val);
+			return -EINVAL;
+		}
+	}
+
+	if (of_get_property(np, "nand-skip-bbtscan", NULL))
+		nand->options |= NAND_SKIP_BBTSCAN;
+
+	host->dev_timings = devm_kzalloc(&pdev->dev,
+				sizeof(*host->dev_timings), GFP_KERNEL);
+	if (!host->dev_timings)
+		return -ENOMEM;
+	ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
+						sizeof(*host->dev_timings));
+	if (ret)
+		host->dev_timings = NULL;
+
+	/* Set default NAND bank to 0 */
+	host->bank = 0;
+	if (!of_property_read_u32(np, "bank", &val)) {
+		if (val > 3) {
+			dev_err(&pdev->dev, "invalid bank %u\n", val);
+			return -EINVAL;
+		}
+		host->bank = val;
+	}
+	return 0;
+}
+
+/*
+ * fsmc_nand_probe - Probe function
+ * @pdev:       platform device structure
+ */
+static int __init fsmc_nand_probe(struct platform_device *pdev)
+{
+	struct fsmc_nand_data *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	struct resource *res;
+	void __iomem *base;
+	dma_cap_mask_t mask;
+	int ret = 0;
+	u32 pid;
+	int i;
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	nand = &host->nand;
+
+	ret = fsmc_nand_probe_config_dt(pdev, host, nand);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+	host->data_va = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(host->data_va))
+		return PTR_ERR(host->data_va);
+
+	host->data_pa = (dma_addr_t)res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
+	host->addr_va = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(host->addr_va))
+		return PTR_ERR(host->addr_va);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
+	host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(host->cmd_va))
+		return PTR_ERR(host->cmd_va);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	host->regs_va = base + FSMC_NOR_REG_SIZE +
+		(host->bank * FSMC_NAND_BANK_SZ);
+
+	host->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk)) {
+		dev_err(&pdev->dev, "failed to fetch block clock\n");
+		return PTR_ERR(host->clk);
+	}
+
+	ret = clk_prepare_enable(host->clk);
+	if (ret)
+		return ret;
+
+	/*
+	 * This device ID is actually a common AMBA ID as used on the
+	 * AMBA PrimeCell bus. However it is not a PrimeCell.
+	 */
+	for (pid = 0, i = 0; i < 4; i++)
+		pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
+	host->pid = pid;
+	dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
+		 "revision %02x, config %02x\n",
+		 AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
+		 AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
+
+	host->dev = &pdev->dev;
+
+	if (host->mode == USE_DMA_ACCESS)
+		init_completion(&host->dma_access_complete);
+
+	/* Link all private pointers */
+	mtd = nand_to_mtd(&host->nand);
+	nand_set_controller_data(nand, host);
+	nand_set_flash_node(nand, pdev->dev.of_node);
+
+	mtd->dev.parent = &pdev->dev;
+	nand->exec_op = fsmc_exec_op;
+	nand->select_chip = fsmc_select_chip;
+	nand->chip_delay = 30;
+
+	/*
+	 * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
+	 * can overwrite this value if the DT provides a different value.
+	 */
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.hwctl = fsmc_enable_hwecc;
+	nand->ecc.size = 512;
+	nand->badblockbits = 7;
+
+	if (host->mode == USE_DMA_ACCESS) {
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_MEMCPY, mask);
+		host->read_dma_chan = dma_request_channel(mask, filter, NULL);
+		if (!host->read_dma_chan) {
+			dev_err(&pdev->dev, "Unable to get read dma channel\n");
+			goto err_req_read_chnl;
+		}
+		host->write_dma_chan = dma_request_channel(mask, filter, NULL);
+		if (!host->write_dma_chan) {
+			dev_err(&pdev->dev, "Unable to get write dma channel\n");
+			goto err_req_write_chnl;
+		}
+	}
+
+	if (host->dev_timings)
+		fsmc_nand_setup(host, host->dev_timings);
+	else
+		nand->setup_data_interface = fsmc_setup_data_interface;
+
+	if (AMBA_REV_BITS(host->pid) >= 8) {
+		nand->ecc.read_page = fsmc_read_page_hwecc;
+		nand->ecc.calculate = fsmc_read_hwecc_ecc4;
+		nand->ecc.correct = fsmc_bch8_correct_data;
+		nand->ecc.bytes = 13;
+		nand->ecc.strength = 8;
+	}
+
+	/*
+	 * Scan to find existence of the device
+	 */
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "No NAND Device found!\n");
+		goto err_scan_ident;
+	}
+
+	if (AMBA_REV_BITS(host->pid) >= 8) {
+		switch (mtd->oobsize) {
+		case 16:
+		case 64:
+		case 128:
+		case 224:
+		case 256:
+			break;
+		default:
+			dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
+				 mtd->oobsize);
+			ret = -EINVAL;
+			goto err_probe;
+		}
+
+		mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
+	} else {
+		switch (nand->ecc.mode) {
+		case NAND_ECC_HW:
+			dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
+			nand->ecc.calculate = fsmc_read_hwecc_ecc1;
+			nand->ecc.correct = nand_correct_data;
+			nand->ecc.bytes = 3;
+			nand->ecc.strength = 1;
+			break;
+
+		case NAND_ECC_SOFT:
+			if (nand->ecc.algo == NAND_ECC_BCH) {
+				dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
+				break;
+			}
+
+		case NAND_ECC_ON_DIE:
+			break;
+
+		default:
+			dev_err(&pdev->dev, "Unsupported ECC mode!\n");
+			goto err_probe;
+		}
+
+		/*
+		 * Don't set layout for BCH4 SW ECC. This will be
+		 * generated later in nand_bch_init() later.
+		 */
+		if (nand->ecc.mode == NAND_ECC_HW) {
+			switch (mtd->oobsize) {
+			case 16:
+			case 64:
+			case 128:
+				mtd_set_ooblayout(mtd,
+						  &fsmc_ecc1_ooblayout_ops);
+				break;
+			default:
+				dev_warn(&pdev->dev,
+					 "No oob scheme defined for oobsize %d\n",
+					 mtd->oobsize);
+				ret = -EINVAL;
+				goto err_probe;
+			}
+		}
+	}
+
+	/* Second stage of scan to fill MTD data-structures */
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		goto err_probe;
+
+	mtd->name = "nand";
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret)
+		goto err_probe;
+
+	platform_set_drvdata(pdev, host);
+	dev_info(&pdev->dev, "FSMC NAND driver registration successful\n");
+	return 0;
+
+err_probe:
+err_scan_ident:
+	if (host->mode == USE_DMA_ACCESS)
+		dma_release_channel(host->write_dma_chan);
+err_req_write_chnl:
+	if (host->mode == USE_DMA_ACCESS)
+		dma_release_channel(host->read_dma_chan);
+err_req_read_chnl:
+	clk_disable_unprepare(host->clk);
+	return ret;
+}
+
+/*
+ * Clean up routine
+ */
+static int fsmc_nand_remove(struct platform_device *pdev)
+{
+	struct fsmc_nand_data *host = platform_get_drvdata(pdev);
+
+	if (host) {
+		nand_release(nand_to_mtd(&host->nand));
+
+		if (host->mode == USE_DMA_ACCESS) {
+			dma_release_channel(host->write_dma_chan);
+			dma_release_channel(host->read_dma_chan);
+		}
+		clk_disable_unprepare(host->clk);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fsmc_nand_suspend(struct device *dev)
+{
+	struct fsmc_nand_data *host = dev_get_drvdata(dev);
+	if (host)
+		clk_disable_unprepare(host->clk);
+	return 0;
+}
+
+static int fsmc_nand_resume(struct device *dev)
+{
+	struct fsmc_nand_data *host = dev_get_drvdata(dev);
+	if (host) {
+		clk_prepare_enable(host->clk);
+		if (host->dev_timings)
+			fsmc_nand_setup(host, host->dev_timings);
+	}
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
+
+static const struct of_device_id fsmc_nand_id_table[] = {
+	{ .compatible = "st,spear600-fsmc-nand" },
+	{ .compatible = "stericsson,fsmc-nand" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
+
+static struct platform_driver fsmc_nand_driver = {
+	.remove = fsmc_nand_remove,
+	.driver = {
+		.name = "fsmc-nand",
+		.of_match_table = fsmc_nand_id_table,
+		.pm = &fsmc_nand_pm_ops,
+	},
+};
+
+module_platform_driver_probe(fsmc_nand_driver, fsmc_nand_probe);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi");
+MODULE_DESCRIPTION("NAND driver for SPEAr Platforms");
diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
new file mode 100644
index 000000000000..2780af26d9ab
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpio.c
@@ -0,0 +1,327 @@
+/*
+ * Updated, and converted to generic GPIO based driver by Russell King.
+ *
+ * Written by Ben Dooks <ben@simtec.co.uk>
+ *   Based on 2.4 version by Mark Whittaker
+ *
+ * © 2004 Simtec Electronics
+ *
+ * Device driver for NAND flash that uses a memory mapped interface to
+ * read/write the NAND commands and data, and GPIO pins for control signals
+ * (the DT binding refers to this as "GPIO assisted NAND flash")
+ *
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand-gpio.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+struct gpiomtd {
+	void __iomem		*io_sync;
+	struct nand_chip	nand_chip;
+	struct gpio_nand_platdata plat;
+	struct gpio_desc *nce; /* Optional chip enable */
+	struct gpio_desc *cle;
+	struct gpio_desc *ale;
+	struct gpio_desc *rdy;
+	struct gpio_desc *nwp; /* Optional write protection */
+};
+
+static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip);
+}
+
+
+#ifdef CONFIG_ARM
+/* gpio_nand_dosync()
+ *
+ * Make sure the GPIO state changes occur in-order with writes to NAND
+ * memory region.
+ * Needed on PXA due to bus-reordering within the SoC itself (see section on
+ * I/O ordering in PXA manual (section 2.3, p35)
+ */
+static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
+{
+	unsigned long tmp;
+
+	if (gpiomtd->io_sync) {
+		/*
+		 * Linux memory barriers don't cater for what's required here.
+		 * What's required is what's here - a read from a separate
+		 * region with a dependency on that read.
+		 */
+		tmp = readl(gpiomtd->io_sync);
+		asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp));
+	}
+}
+#else
+static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
+#endif
+
+static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+
+	gpio_nand_dosync(gpiomtd);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if (gpiomtd->nce)
+			gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE));
+		gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE));
+		gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE));
+		gpio_nand_dosync(gpiomtd);
+	}
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
+	gpio_nand_dosync(gpiomtd);
+}
+
+static int gpio_nand_devready(struct mtd_info *mtd)
+{
+	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+
+	return gpiod_get_value(gpiomtd->rdy);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_nand_id_table[] = {
+	{ .compatible = "gpio-control-nand" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
+
+static int gpio_nand_get_config_of(const struct device *dev,
+				   struct gpio_nand_platdata *plat)
+{
+	u32 val;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
+		if (val == 2) {
+			plat->options |= NAND_BUSWIDTH_16;
+		} else if (val != 1) {
+			dev_err(dev, "invalid bank-width %u\n", val);
+			return -EINVAL;
+		}
+	}
+
+	if (!of_property_read_u32(dev->of_node, "chip-delay", &val))
+		plat->chip_delay = val;
+
+	return 0;
+}
+
+static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
+{
+	struct resource *r;
+	u64 addr;
+
+	if (of_property_read_u64(pdev->dev.of_node,
+				       "gpio-control-nand,io-sync-reg", &addr))
+		return NULL;
+
+	r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
+	if (!r)
+		return NULL;
+
+	r->start = addr;
+	r->end = r->start + 0x3;
+	r->flags = IORESOURCE_MEM;
+
+	return r;
+}
+#else /* CONFIG_OF */
+static inline int gpio_nand_get_config_of(const struct device *dev,
+					  struct gpio_nand_platdata *plat)
+{
+	return -ENOSYS;
+}
+
+static inline struct resource *
+gpio_nand_get_io_sync_of(struct platform_device *pdev)
+{
+	return NULL;
+}
+#endif /* CONFIG_OF */
+
+static inline int gpio_nand_get_config(const struct device *dev,
+				       struct gpio_nand_platdata *plat)
+{
+	int ret = gpio_nand_get_config_of(dev, plat);
+
+	if (!ret)
+		return ret;
+
+	if (dev_get_platdata(dev)) {
+		memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static inline struct resource *
+gpio_nand_get_io_sync(struct platform_device *pdev)
+{
+	struct resource *r = gpio_nand_get_io_sync_of(pdev);
+
+	if (r)
+		return r;
+
+	return platform_get_resource(pdev, IORESOURCE_MEM, 1);
+}
+
+static int gpio_nand_remove(struct platform_device *pdev)
+{
+	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&gpiomtd->nand_chip));
+
+	/* Enable write protection and disable the chip */
+	if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
+		gpiod_set_value(gpiomtd->nwp, 0);
+	if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
+		gpiod_set_value(gpiomtd->nce, 0);
+
+	return 0;
+}
+
+static int gpio_nand_probe(struct platform_device *pdev)
+{
+	struct gpiomtd *gpiomtd;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	int ret = 0;
+
+	if (!dev->of_node && !dev_get_platdata(dev))
+		return -EINVAL;
+
+	gpiomtd = devm_kzalloc(dev, sizeof(*gpiomtd), GFP_KERNEL);
+	if (!gpiomtd)
+		return -ENOMEM;
+
+	chip = &gpiomtd->nand_chip;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
+	if (IS_ERR(chip->IO_ADDR_R))
+		return PTR_ERR(chip->IO_ADDR_R);
+
+	res = gpio_nand_get_io_sync(pdev);
+	if (res) {
+		gpiomtd->io_sync = devm_ioremap_resource(dev, res);
+		if (IS_ERR(gpiomtd->io_sync))
+			return PTR_ERR(gpiomtd->io_sync);
+	}
+
+	ret = gpio_nand_get_config(dev, &gpiomtd->plat);
+	if (ret)
+		return ret;
+
+	/* Just enable the chip */
+	gpiomtd->nce = devm_gpiod_get_optional(dev, "nce", GPIOD_OUT_HIGH);
+	if (IS_ERR(gpiomtd->nce))
+		return PTR_ERR(gpiomtd->nce);
+
+	/* We disable write protection once we know probe() will succeed */
+	gpiomtd->nwp = devm_gpiod_get_optional(dev, "nwp", GPIOD_OUT_LOW);
+	if (IS_ERR(gpiomtd->nwp)) {
+		ret = PTR_ERR(gpiomtd->nwp);
+		goto out_ce;
+	}
+
+	gpiomtd->ale = devm_gpiod_get(dev, "ale", GPIOD_OUT_LOW);
+	if (IS_ERR(gpiomtd->ale)) {
+		ret = PTR_ERR(gpiomtd->ale);
+		goto out_ce;
+	}
+
+	gpiomtd->cle = devm_gpiod_get(dev, "cle", GPIOD_OUT_LOW);
+	if (IS_ERR(gpiomtd->cle)) {
+		ret = PTR_ERR(gpiomtd->cle);
+		goto out_ce;
+	}
+
+	gpiomtd->rdy = devm_gpiod_get_optional(dev, "rdy", GPIOD_IN);
+	if (IS_ERR(gpiomtd->rdy)) {
+		ret = PTR_ERR(gpiomtd->rdy);
+		goto out_ce;
+	}
+	/* Using RDY pin */
+	if (gpiomtd->rdy)
+		chip->dev_ready = gpio_nand_devready;
+
+	nand_set_flash_node(chip, pdev->dev.of_node);
+	chip->IO_ADDR_W		= chip->IO_ADDR_R;
+	chip->ecc.mode		= NAND_ECC_SOFT;
+	chip->ecc.algo		= NAND_ECC_HAMMING;
+	chip->options		= gpiomtd->plat.options;
+	chip->chip_delay	= gpiomtd->plat.chip_delay;
+	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;
+
+	mtd			= nand_to_mtd(chip);
+	mtd->dev.parent		= dev;
+
+	platform_set_drvdata(pdev, gpiomtd);
+
+	/* Disable write protection, if wired up */
+	if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
+		gpiod_direction_output(gpiomtd->nwp, 1);
+
+	ret = nand_scan(mtd, 1);
+	if (ret)
+		goto err_wp;
+
+	if (gpiomtd->plat.adjust_parts)
+		gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
+
+	ret = mtd_device_register(mtd, gpiomtd->plat.parts,
+				  gpiomtd->plat.num_parts);
+	if (!ret)
+		return 0;
+
+err_wp:
+	if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
+		gpiod_set_value(gpiomtd->nwp, 0);
+out_ce:
+	if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
+		gpiod_set_value(gpiomtd->nce, 0);
+
+	return ret;
+}
+
+static struct platform_driver gpio_nand_driver = {
+	.probe		= gpio_nand_probe,
+	.remove		= gpio_nand_remove,
+	.driver		= {
+		.name	= "gpio-nand",
+		.of_match_table = of_match_ptr(gpio_nand_id_table),
+	},
+};
+
+module_platform_driver(gpio_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("GPIO NAND Driver");
diff --git a/drivers/mtd/nand/raw/gpmi-nand/Makefile b/drivers/mtd/nand/raw/gpmi-nand/Makefile
new file mode 100644
index 000000000000..3a462487c35e
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpmi-nand/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o
+gpmi_nand-objs += gpmi-nand.o
+gpmi_nand-objs += gpmi-lib.o
diff --git a/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h b/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
new file mode 100644
index 000000000000..05bb91f2f4c4
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpmi-nand/bch-regs.h
@@ -0,0 +1,128 @@
+/*
+ * Freescale GPMI NAND Flash Driver
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef __GPMI_NAND_BCH_REGS_H
+#define __GPMI_NAND_BCH_REGS_H
+
+#define HW_BCH_CTRL				0x00000000
+#define HW_BCH_CTRL_SET				0x00000004
+#define HW_BCH_CTRL_CLR				0x00000008
+#define HW_BCH_CTRL_TOG				0x0000000c
+
+#define BM_BCH_CTRL_COMPLETE_IRQ_EN		(1 << 8)
+#define BM_BCH_CTRL_COMPLETE_IRQ		(1 << 0)
+
+#define HW_BCH_STATUS0				0x00000010
+#define HW_BCH_MODE				0x00000020
+#define HW_BCH_ENCODEPTR			0x00000030
+#define HW_BCH_DATAPTR				0x00000040
+#define HW_BCH_METAPTR				0x00000050
+#define HW_BCH_LAYOUTSELECT			0x00000070
+
+#define HW_BCH_FLASH0LAYOUT0			0x00000080
+
+#define BP_BCH_FLASH0LAYOUT0_NBLOCKS		24
+#define BM_BCH_FLASH0LAYOUT0_NBLOCKS	(0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS)
+#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v)		\
+	(((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS)
+
+#define BP_BCH_FLASH0LAYOUT0_META_SIZE		16
+#define BM_BCH_FLASH0LAYOUT0_META_SIZE	(0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE)
+#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v)	\
+	(((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\
+					 & BM_BCH_FLASH0LAYOUT0_META_SIZE)
+
+#define BP_BCH_FLASH0LAYOUT0_ECC0		12
+#define BM_BCH_FLASH0LAYOUT0_ECC0	(0xf << BP_BCH_FLASH0LAYOUT0_ECC0)
+#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0		11
+#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)
+#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x)				\
+	(GPMI_IS_MX6(x)					\
+		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)	\
+			& MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0)	\
+		: (((v) << BP_BCH_FLASH0LAYOUT0_ECC0)		\
+			& BM_BCH_FLASH0LAYOUT0_ECC0)		\
+	)
+
+#define MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14	10
+#define MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14			\
+				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)
+#define BF_BCH_FLASH0LAYOUT0_GF(v, x)				\
+	((GPMI_IS_MX6(x) && ((v) == 14))			\
+		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)	\
+			& MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14)	\
+		: 0						\
+	)
+
+#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE		0
+#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE		\
+			(0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE	\
+			(0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
+#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x)				\
+	(GPMI_IS_MX6(x)						\
+		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)	\
+		: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)		\
+	)
+
+#define HW_BCH_FLASH0LAYOUT1			0x00000090
+
+#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE		16
+#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE		\
+			(0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v)	\
+	(((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \
+					 & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE)
+
+#define BP_BCH_FLASH0LAYOUT1_ECCN		12
+#define BM_BCH_FLASH0LAYOUT1_ECCN	(0xf << BP_BCH_FLASH0LAYOUT1_ECCN)
+#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN		11
+#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN	(0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)
+#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x)				\
+	(GPMI_IS_MX6(x)					\
+		? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)	\
+			& MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN)	\
+		: (((v) << BP_BCH_FLASH0LAYOUT1_ECCN)		\
+			& BM_BCH_FLASH0LAYOUT1_ECCN)		\
+	)
+
+#define MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14	10
+#define MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14			\
+				(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)
+#define BF_BCH_FLASH0LAYOUT1_GF(v, x)				\
+	((GPMI_IS_MX6(x) && ((v) == 14))			\
+		? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)	\
+			& MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14)	\
+		: 0						\
+	)
+
+#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE		0
+#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE		\
+			(0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE	\
+			(0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
+#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x)				\
+	(GPMI_IS_MX6(x)						\
+		? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)	\
+		: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)		\
+	)
+
+#define HW_BCH_VERSION				0x00000160
+#endif
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
new file mode 100644
index 000000000000..97787246af41
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
@@ -0,0 +1,1510 @@
+/*
+ * Freescale GPMI NAND Flash Driver
+ *
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include "gpmi-nand.h"
+#include "gpmi-regs.h"
+#include "bch-regs.h"
+
+static struct timing_threshold timing_default_threshold = {
+	.max_data_setup_cycles       = (BM_GPMI_TIMING0_DATA_SETUP >>
+						BP_GPMI_TIMING0_DATA_SETUP),
+	.internal_data_setup_in_ns   = 0,
+	.max_sample_delay_factor     = (BM_GPMI_CTRL1_RDN_DELAY >>
+						BP_GPMI_CTRL1_RDN_DELAY),
+	.max_dll_clock_period_in_ns  = 32,
+	.max_dll_delay_in_ns         = 16,
+};
+
+#define MXS_SET_ADDR		0x4
+#define MXS_CLR_ADDR		0x8
+/*
+ * Clear the bit and poll it cleared.  This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
+ */
+static int clear_poll_bit(void __iomem *addr, u32 mask)
+{
+	int timeout = 0x400;
+
+	/* clear the bit */
+	writel(mask, addr + MXS_CLR_ADDR);
+
+	/*
+	 * SFTRST needs 3 GPMI clocks to settle, the reference manual
+	 * recommends to wait 1us.
+	 */
+	udelay(1);
+
+	/* poll the bit becoming clear */
+	while ((readl(addr) & mask) && --timeout)
+		/* nothing */;
+
+	return !timeout;
+}
+
+#define MODULE_CLKGATE		(1 << 30)
+#define MODULE_SFTRST		(1 << 31)
+/*
+ * The current mxs_reset_block() will do two things:
+ *  [1] enable the module.
+ *  [2] reset the module.
+ *
+ * In most of the cases, it's ok.
+ * But in MX23, there is a hardware bug in the BCH block (see erratum #2847).
+ * If you try to soft reset the BCH block, it becomes unusable until
+ * the next hard reset. This case occurs in the NAND boot mode. When the board
+ * boots by NAND, the ROM of the chip will initialize the BCH blocks itself.
+ * So If the driver tries to reset the BCH again, the BCH will not work anymore.
+ * You will see a DMA timeout in this case. The bug has been fixed
+ * in the following chips, such as MX28.
+ *
+ * To avoid this bug, just add a new parameter `just_enable` for
+ * the mxs_reset_block(), and rewrite it here.
+ */
+static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
+{
+	int ret;
+	int timeout = 0x400;
+
+	/* clear and poll SFTRST */
+	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+	if (unlikely(ret))
+		goto error;
+
+	/* clear CLKGATE */
+	writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
+
+	if (!just_enable) {
+		/* set SFTRST to reset the block */
+		writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
+		udelay(1);
+
+		/* poll CLKGATE becoming set */
+		while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout)
+			/* nothing */;
+		if (unlikely(!timeout))
+			goto error;
+	}
+
+	/* clear and poll SFTRST */
+	ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+	if (unlikely(ret))
+		goto error;
+
+	/* clear and poll CLKGATE */
+	ret = clear_poll_bit(reset_addr, MODULE_CLKGATE);
+	if (unlikely(ret))
+		goto error;
+
+	return 0;
+
+error:
+	pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
+	return -ETIMEDOUT;
+}
+
+static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+{
+	struct clk *clk;
+	int ret;
+	int i;
+
+	for (i = 0; i < GPMI_CLK_MAX; i++) {
+		clk = this->resources.clock[i];
+		if (!clk)
+			break;
+
+		if (v) {
+			ret = clk_prepare_enable(clk);
+			if (ret)
+				goto err_clk;
+		} else {
+			clk_disable_unprepare(clk);
+		}
+	}
+	return 0;
+
+err_clk:
+	for (; i > 0; i--)
+		clk_disable_unprepare(this->resources.clock[i - 1]);
+	return ret;
+}
+
+#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
+#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
+
+int gpmi_init(struct gpmi_nand_data *this)
+{
+	struct resources *r = &this->resources;
+	int ret;
+
+	ret = gpmi_enable_clk(this);
+	if (ret)
+		return ret;
+	ret = gpmi_reset_block(r->gpmi_regs, false);
+	if (ret)
+		goto err_out;
+
+	/*
+	 * Reset BCH here, too. We got failures otherwise :(
+	 * See later BCH reset for explanation of MX23 handling
+	 */
+	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+	if (ret)
+		goto err_out;
+
+
+	/* Choose NAND mode. */
+	writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
+
+	/* Set the IRQ polarity. */
+	writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY,
+				r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	/* Disable Write-Protection. */
+	writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	/* Select BCH ECC. */
+	writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	/*
+	 * Decouple the chip select from dma channel. We use dma0 for all
+	 * the chips.
+	 */
+	writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	gpmi_disable_clk(this);
+	return 0;
+err_out:
+	gpmi_disable_clk(this);
+	return ret;
+}
+
+/* This function is very useful. It is called only when the bug occur. */
+void gpmi_dump_info(struct gpmi_nand_data *this)
+{
+	struct resources *r = &this->resources;
+	struct bch_geometry *geo = &this->bch_geometry;
+	u32 reg;
+	int i;
+
+	dev_err(this->dev, "Show GPMI registers :\n");
+	for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
+		reg = readl(r->gpmi_regs + i * 0x10);
+		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+	}
+
+	/* start to print out the BCH info */
+	dev_err(this->dev, "Show BCH registers :\n");
+	for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
+		reg = readl(r->bch_regs + i * 0x10);
+		dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+	}
+	dev_err(this->dev, "BCH Geometry :\n"
+		"GF length              : %u\n"
+		"ECC Strength           : %u\n"
+		"Page Size in Bytes     : %u\n"
+		"Metadata Size in Bytes : %u\n"
+		"ECC Chunk Size in Bytes: %u\n"
+		"ECC Chunk Count        : %u\n"
+		"Payload Size in Bytes  : %u\n"
+		"Auxiliary Size in Bytes: %u\n"
+		"Auxiliary Status Offset: %u\n"
+		"Block Mark Byte Offset : %u\n"
+		"Block Mark Bit Offset  : %u\n",
+		geo->gf_len,
+		geo->ecc_strength,
+		geo->page_size,
+		geo->metadata_size,
+		geo->ecc_chunk_size,
+		geo->ecc_chunk_count,
+		geo->payload_size,
+		geo->auxiliary_size,
+		geo->auxiliary_status_offset,
+		geo->block_mark_byte_offset,
+		geo->block_mark_bit_offset);
+}
+
+/* Configures the geometry for BCH.  */
+int bch_set_geometry(struct gpmi_nand_data *this)
+{
+	struct resources *r = &this->resources;
+	struct bch_geometry *bch_geo = &this->bch_geometry;
+	unsigned int block_count;
+	unsigned int block_size;
+	unsigned int metadata_size;
+	unsigned int ecc_strength;
+	unsigned int page_size;
+	unsigned int gf_len;
+	int ret;
+
+	if (common_nfc_set_geometry(this))
+		return !0;
+
+	block_count   = bch_geo->ecc_chunk_count - 1;
+	block_size    = bch_geo->ecc_chunk_size;
+	metadata_size = bch_geo->metadata_size;
+	ecc_strength  = bch_geo->ecc_strength >> 1;
+	page_size     = bch_geo->page_size;
+	gf_len        = bch_geo->gf_len;
+
+	ret = gpmi_enable_clk(this);
+	if (ret)
+		return ret;
+
+	/*
+	* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
+	* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
+	* On the other hand, the MX28 needs the reset, because one case has been
+	* seen where the BCH produced ECC errors constantly after 10000
+	* consecutive reboots. The latter case has not been seen on the MX23
+	* yet, still we don't know if it could happen there as well.
+	*/
+	ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+	if (ret)
+		goto err_out;
+
+	/* Configure layout 0. */
+	writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
+			| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
+			| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
+			| BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
+			| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
+			r->bch_regs + HW_BCH_FLASH0LAYOUT0);
+
+	writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
+			| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
+			| BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
+			| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
+			r->bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+	/* Set *all* chip selects to use layout 0. */
+	writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
+
+	/* Enable interrupts. */
+	writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
+				r->bch_regs + HW_BCH_CTRL_SET);
+
+	gpmi_disable_clk(this);
+	return 0;
+err_out:
+	gpmi_disable_clk(this);
+	return ret;
+}
+
+/* Converts time in nanoseconds to cycles. */
+static unsigned int ns_to_cycles(unsigned int time,
+			unsigned int period, unsigned int min)
+{
+	unsigned int k;
+
+	k = (time + period - 1) / period;
+	return max(k, min);
+}
+
+#define DEF_MIN_PROP_DELAY	5
+#define DEF_MAX_PROP_DELAY	9
+/* Apply timing to current hardware conditions. */
+static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
+					struct gpmi_nfc_hardware_timing *hw)
+{
+	struct timing_threshold *nfc = &timing_default_threshold;
+	struct resources *r = &this->resources;
+	struct nand_chip *nand = &this->nand;
+	struct nand_timing target = this->timing;
+	bool improved_timing_is_available;
+	unsigned long clock_frequency_in_hz;
+	unsigned int clock_period_in_ns;
+	bool dll_use_half_periods;
+	unsigned int dll_delay_shift;
+	unsigned int max_sample_delay_in_ns;
+	unsigned int address_setup_in_cycles;
+	unsigned int data_setup_in_ns;
+	unsigned int data_setup_in_cycles;
+	unsigned int data_hold_in_cycles;
+	int ideal_sample_delay_in_ns;
+	unsigned int sample_delay_factor;
+	int tEYE;
+	unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
+	unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
+
+	/*
+	 * If there are multiple chips, we need to relax the timings to allow
+	 * for signal distortion due to higher capacitance.
+	 */
+	if (nand->numchips > 2) {
+		target.data_setup_in_ns    += 10;
+		target.data_hold_in_ns     += 10;
+		target.address_setup_in_ns += 10;
+	} else if (nand->numchips > 1) {
+		target.data_setup_in_ns    += 5;
+		target.data_hold_in_ns     += 5;
+		target.address_setup_in_ns += 5;
+	}
+
+	/* Check if improved timing information is available. */
+	improved_timing_is_available =
+		(target.tREA_in_ns  >= 0) &&
+		(target.tRLOH_in_ns >= 0) &&
+		(target.tRHOH_in_ns >= 0);
+
+	/* Inspect the clock. */
+	nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
+	clock_frequency_in_hz = nfc->clock_frequency_in_hz;
+	clock_period_in_ns    = NSEC_PER_SEC / clock_frequency_in_hz;
+
+	/*
+	 * The NFC quantizes setup and hold parameters in terms of clock cycles.
+	 * Here, we quantize the setup and hold timing parameters to the
+	 * next-highest clock period to make sure we apply at least the
+	 * specified times.
+	 *
+	 * For data setup and data hold, the hardware interprets a value of zero
+	 * as the largest possible delay. This is not what's intended by a zero
+	 * in the input parameter, so we impose a minimum of one cycle.
+	 */
+	data_setup_in_cycles    = ns_to_cycles(target.data_setup_in_ns,
+							clock_period_in_ns, 1);
+	data_hold_in_cycles     = ns_to_cycles(target.data_hold_in_ns,
+							clock_period_in_ns, 1);
+	address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns,
+							clock_period_in_ns, 0);
+
+	/*
+	 * The clock's period affects the sample delay in a number of ways:
+	 *
+	 * (1) The NFC HAL tells us the maximum clock period the sample delay
+	 *     DLL can tolerate. If the clock period is greater than half that
+	 *     maximum, we must configure the DLL to be driven by half periods.
+	 *
+	 * (2) We need to convert from an ideal sample delay, in ns, to a
+	 *     "sample delay factor," which the NFC uses. This factor depends on
+	 *     whether we're driving the DLL with full or half periods.
+	 *     Paraphrasing the reference manual:
+	 *
+	 *         AD = SDF x 0.125 x RP
+	 *
+	 * where:
+	 *
+	 *     AD   is the applied delay, in ns.
+	 *     SDF  is the sample delay factor, which is dimensionless.
+	 *     RP   is the reference period, in ns, which is a full clock period
+	 *          if the DLL is being driven by full periods, or half that if
+	 *          the DLL is being driven by half periods.
+	 *
+	 * Let's re-arrange this in a way that's more useful to us:
+	 *
+	 *                        8
+	 *         SDF  =  AD x ----
+	 *                       RP
+	 *
+	 * The reference period is either the clock period or half that, so this
+	 * is:
+	 *
+	 *                        8       AD x DDF
+	 *         SDF  =  AD x -----  =  --------
+	 *                      f x P        P
+	 *
+	 * where:
+	 *
+	 *       f  is 1 or 1/2, depending on how we're driving the DLL.
+	 *       P  is the clock period.
+	 *     DDF  is the DLL Delay Factor, a dimensionless value that
+	 *          incorporates all the constants in the conversion.
+	 *
+	 * DDF will be either 8 or 16, both of which are powers of two. We can
+	 * reduce the cost of this conversion by using bit shifts instead of
+	 * multiplication or division. Thus:
+	 *
+	 *                 AD << DDS
+	 *         SDF  =  ---------
+	 *                     P
+	 *
+	 *     or
+	 *
+	 *         AD  =  (SDF >> DDS) x P
+	 *
+	 * where:
+	 *
+	 *     DDS  is the DLL Delay Shift, the logarithm to base 2 of the DDF.
+	 */
+	if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) {
+		dll_use_half_periods = true;
+		dll_delay_shift      = 3 + 1;
+	} else {
+		dll_use_half_periods = false;
+		dll_delay_shift      = 3;
+	}
+
+	/*
+	 * Compute the maximum sample delay the NFC allows, under current
+	 * conditions. If the clock is running too slowly, no sample delay is
+	 * possible.
+	 */
+	if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns)
+		max_sample_delay_in_ns = 0;
+	else {
+		/*
+		 * Compute the delay implied by the largest sample delay factor
+		 * the NFC allows.
+		 */
+		max_sample_delay_in_ns =
+			(nfc->max_sample_delay_factor * clock_period_in_ns) >>
+								dll_delay_shift;
+
+		/*
+		 * Check if the implied sample delay larger than the NFC
+		 * actually allows.
+		 */
+		if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns)
+			max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
+	}
+
+	/*
+	 * Check if improved timing information is available. If not, we have to
+	 * use a less-sophisticated algorithm.
+	 */
+	if (!improved_timing_is_available) {
+		/*
+		 * Fold the read setup time required by the NFC into the ideal
+		 * sample delay.
+		 */
+		ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns +
+						nfc->internal_data_setup_in_ns;
+
+		/*
+		 * The ideal sample delay may be greater than the maximum
+		 * allowed by the NFC. If so, we can trade off sample delay time
+		 * for more data setup time.
+		 *
+		 * In each iteration of the following loop, we add a cycle to
+		 * the data setup time and subtract a corresponding amount from
+		 * the sample delay until we've satisified the constraints or
+		 * can't do any better.
+		 */
+		while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
+			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+
+			data_setup_in_cycles++;
+			ideal_sample_delay_in_ns -= clock_period_in_ns;
+
+			if (ideal_sample_delay_in_ns < 0)
+				ideal_sample_delay_in_ns = 0;
+
+		}
+
+		/*
+		 * Compute the sample delay factor that corresponds most closely
+		 * to the ideal sample delay. If the result is too large for the
+		 * NFC, use the maximum value.
+		 *
+		 * Notice that we use the ns_to_cycles function to compute the
+		 * sample delay factor. We do this because the form of the
+		 * computation is the same as that for calculating cycles.
+		 */
+		sample_delay_factor =
+			ns_to_cycles(
+				ideal_sample_delay_in_ns << dll_delay_shift,
+							clock_period_in_ns, 0);
+
+		if (sample_delay_factor > nfc->max_sample_delay_factor)
+			sample_delay_factor = nfc->max_sample_delay_factor;
+
+		/* Skip to the part where we return our results. */
+		goto return_results;
+	}
+
+	/*
+	 * If control arrives here, we have more detailed timing information,
+	 * so we can use a better algorithm.
+	 */
+
+	/*
+	 * Fold the read setup time required by the NFC into the maximum
+	 * propagation delay.
+	 */
+	max_prop_delay_in_ns += nfc->internal_data_setup_in_ns;
+
+	/*
+	 * Earlier, we computed the number of clock cycles required to satisfy
+	 * the data setup time. Now, we need to know the actual nanoseconds.
+	 */
+	data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles;
+
+	/*
+	 * Compute tEYE, the width of the data eye when reading from the NAND
+	 * Flash. The eye width is fundamentally determined by the data setup
+	 * time, perturbed by propagation delays and some characteristics of the
+	 * NAND Flash device.
+	 *
+	 * start of the eye = max_prop_delay + tREA
+	 * end of the eye   = min_prop_delay + tRHOH + data_setup
+	 */
+	tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns +
+							(int)data_setup_in_ns;
+
+	tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns;
+
+	/*
+	 * The eye must be open. If it's not, we can try to open it by
+	 * increasing its main forcer, the data setup time.
+	 *
+	 * In each iteration of the following loop, we increase the data setup
+	 * time by a single clock cycle. We do this until either the eye is
+	 * open or we run into NFC limits.
+	 */
+	while ((tEYE <= 0) &&
+			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+		/* Give a cycle to data setup. */
+		data_setup_in_cycles++;
+		/* Synchronize the data setup time with the cycles. */
+		data_setup_in_ns += clock_period_in_ns;
+		/* Adjust tEYE accordingly. */
+		tEYE += clock_period_in_ns;
+	}
+
+	/*
+	 * When control arrives here, the eye is open. The ideal time to sample
+	 * the data is in the center of the eye:
+	 *
+	 *     end of the eye + start of the eye
+	 *     ---------------------------------  -  data_setup
+	 *                    2
+	 *
+	 * After some algebra, this simplifies to the code immediately below.
+	 */
+	ideal_sample_delay_in_ns =
+		((int)max_prop_delay_in_ns +
+			(int)target.tREA_in_ns +
+				(int)min_prop_delay_in_ns +
+					(int)target.tRHOH_in_ns -
+						(int)data_setup_in_ns) >> 1;
+
+	/*
+	 * The following figure illustrates some aspects of a NAND Flash read:
+	 *
+	 *
+	 *           __                   _____________________________________
+	 * RDN         \_________________/
+	 *
+	 *                                         <---- tEYE ----->
+	 *                                        /-----------------\
+	 * Read Data ----------------------------<                   >---------
+	 *                                        \-----------------/
+	 *             ^                 ^                 ^              ^
+	 *             |                 |                 |              |
+	 *             |<--Data Setup -->|<--Delay Time -->|              |
+	 *             |                 |                 |              |
+	 *             |                 |                                |
+	 *             |                 |<--   Quantized Delay Time   -->|
+	 *             |                 |                                |
+	 *
+	 *
+	 * We have some issues we must now address:
+	 *
+	 * (1) The *ideal* sample delay time must not be negative. If it is, we
+	 *     jam it to zero.
+	 *
+	 * (2) The *ideal* sample delay time must not be greater than that
+	 *     allowed by the NFC. If it is, we can increase the data setup
+	 *     time, which will reduce the delay between the end of the data
+	 *     setup and the center of the eye. It will also make the eye
+	 *     larger, which might help with the next issue...
+	 *
+	 * (3) The *quantized* sample delay time must not fall either before the
+	 *     eye opens or after it closes (the latter is the problem
+	 *     illustrated in the above figure).
+	 */
+
+	/* Jam a negative ideal sample delay to zero. */
+	if (ideal_sample_delay_in_ns < 0)
+		ideal_sample_delay_in_ns = 0;
+
+	/*
+	 * Extend the data setup as needed to reduce the ideal sample delay
+	 * below the maximum permitted by the NFC.
+	 */
+	while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
+			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+
+		/* Give a cycle to data setup. */
+		data_setup_in_cycles++;
+		/* Synchronize the data setup time with the cycles. */
+		data_setup_in_ns += clock_period_in_ns;
+		/* Adjust tEYE accordingly. */
+		tEYE += clock_period_in_ns;
+
+		/*
+		 * Decrease the ideal sample delay by one half cycle, to keep it
+		 * in the middle of the eye.
+		 */
+		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
+
+		/* Jam a negative ideal sample delay to zero. */
+		if (ideal_sample_delay_in_ns < 0)
+			ideal_sample_delay_in_ns = 0;
+	}
+
+	/*
+	 * Compute the sample delay factor that corresponds to the ideal sample
+	 * delay. If the result is too large, then use the maximum allowed
+	 * value.
+	 *
+	 * Notice that we use the ns_to_cycles function to compute the sample
+	 * delay factor. We do this because the form of the computation is the
+	 * same as that for calculating cycles.
+	 */
+	sample_delay_factor =
+		ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift,
+							clock_period_in_ns, 0);
+
+	if (sample_delay_factor > nfc->max_sample_delay_factor)
+		sample_delay_factor = nfc->max_sample_delay_factor;
+
+	/*
+	 * These macros conveniently encapsulate a computation we'll use to
+	 * continuously evaluate whether or not the data sample delay is inside
+	 * the eye.
+	 */
+	#define IDEAL_DELAY  ((int) ideal_sample_delay_in_ns)
+
+	#define QUANTIZED_DELAY  \
+		((int) ((sample_delay_factor * clock_period_in_ns) >> \
+							dll_delay_shift))
+
+	#define DELAY_ERROR  (abs(QUANTIZED_DELAY - IDEAL_DELAY))
+
+	#define SAMPLE_IS_NOT_WITHIN_THE_EYE  (DELAY_ERROR > (tEYE >> 1))
+
+	/*
+	 * While the quantized sample time falls outside the eye, reduce the
+	 * sample delay or extend the data setup to move the sampling point back
+	 * toward the eye. Do not allow the number of data setup cycles to
+	 * exceed the maximum allowed by the NFC.
+	 */
+	while (SAMPLE_IS_NOT_WITHIN_THE_EYE &&
+			(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
+		/*
+		 * If control arrives here, the quantized sample delay falls
+		 * outside the eye. Check if it's before the eye opens, or after
+		 * the eye closes.
+		 */
+		if (QUANTIZED_DELAY > IDEAL_DELAY) {
+			/*
+			 * If control arrives here, the quantized sample delay
+			 * falls after the eye closes. Decrease the quantized
+			 * delay time and then go back to re-evaluate.
+			 */
+			if (sample_delay_factor != 0)
+				sample_delay_factor--;
+			continue;
+		}
+
+		/*
+		 * If control arrives here, the quantized sample delay falls
+		 * before the eye opens. Shift the sample point by increasing
+		 * data setup time. This will also make the eye larger.
+		 */
+
+		/* Give a cycle to data setup. */
+		data_setup_in_cycles++;
+		/* Synchronize the data setup time with the cycles. */
+		data_setup_in_ns += clock_period_in_ns;
+		/* Adjust tEYE accordingly. */
+		tEYE += clock_period_in_ns;
+
+		/*
+		 * Decrease the ideal sample delay by one half cycle, to keep it
+		 * in the middle of the eye.
+		 */
+		ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
+
+		/* ...and one less period for the delay time. */
+		ideal_sample_delay_in_ns -= clock_period_in_ns;
+
+		/* Jam a negative ideal sample delay to zero. */
+		if (ideal_sample_delay_in_ns < 0)
+			ideal_sample_delay_in_ns = 0;
+
+		/*
+		 * We have a new ideal sample delay, so re-compute the quantized
+		 * delay.
+		 */
+		sample_delay_factor =
+			ns_to_cycles(
+				ideal_sample_delay_in_ns << dll_delay_shift,
+							clock_period_in_ns, 0);
+
+		if (sample_delay_factor > nfc->max_sample_delay_factor)
+			sample_delay_factor = nfc->max_sample_delay_factor;
+	}
+
+	/* Control arrives here when we're ready to return our results. */
+return_results:
+	hw->data_setup_in_cycles    = data_setup_in_cycles;
+	hw->data_hold_in_cycles     = data_hold_in_cycles;
+	hw->address_setup_in_cycles = address_setup_in_cycles;
+	hw->use_half_periods        = dll_use_half_periods;
+	hw->sample_delay_factor     = sample_delay_factor;
+	hw->device_busy_timeout     = GPMI_DEFAULT_BUSY_TIMEOUT;
+	hw->wrn_dly_sel             = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
+
+	/* Return success. */
+	return 0;
+}
+
+/*
+ * <1> Firstly, we should know what's the GPMI-clock means.
+ *     The GPMI-clock is the internal clock in the gpmi nand controller.
+ *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
+ *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
+ *
+ * <2> Secondly, we should know what's the frequency on the nand chip pins.
+ *     The frequency on the nand chip pins is derived from the GPMI-clock.
+ *     We can get it from the following equation:
+ *
+ *         F = G / (DS + DH)
+ *
+ *         F  : the frequency on the nand chip pins.
+ *         G  : the GPMI clock, such as 100MHz.
+ *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
+ *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
+ *
+ * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
+ *     the nand EDO(extended Data Out) timing could be applied.
+ *     The GPMI implements a feedback read strobe to sample the read data.
+ *     The feedback read strobe can be delayed to support the nand EDO timing
+ *     where the read strobe may deasserts before the read data is valid, and
+ *     read data is valid for some time after read strobe.
+ *
+ *     The following figure illustrates some aspects of a NAND Flash read:
+ *
+ *                   |<---tREA---->|
+ *                   |             |
+ *                   |         |   |
+ *                   |<--tRP-->|   |
+ *                   |         |   |
+ *                  __          ___|__________________________________
+ *     RDN            \________/   |
+ *                                 |
+ *                                 /---------\
+ *     Read Data    --------------<           >---------
+ *                                 \---------/
+ *                                |     |
+ *                                |<-D->|
+ *     FeedbackRDN  ________             ____________
+ *                          \___________/
+ *
+ *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
+ *
+ *
+ * <4> Now, we begin to describe how to compute the right RDN_DELAY.
+ *
+ *  4.1) From the aspect of the nand chip pins:
+ *        Delay = (tREA + C - tRP)               {1}
+ *
+ *        tREA : the maximum read access time. From the ONFI nand standards,
+ *               we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4.
+ *               Please check it in : www.onfi.org
+ *        C    : a constant for adjust the delay. default is 4.
+ *        tRP  : the read pulse width.
+ *               Specified by the HW_GPMI_TIMING0:DATA_SETUP:
+ *                    tRP = (GPMI-clock-period) * DATA_SETUP
+ *
+ *  4.2) From the aspect of the GPMI nand controller:
+ *         Delay = RDN_DELAY * 0.125 * RP        {2}
+ *
+ *         RP   : the DLL reference period.
+ *            if (GPMI-clock-period > DLL_THRETHOLD)
+ *                   RP = GPMI-clock-period / 2;
+ *            else
+ *                   RP = GPMI-clock-period;
+ *
+ *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
+ *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
+ *            is 16ns, but in mx6q, we use 12ns.
+ *
+ *  4.3) since {1} equals {2}, we get:
+ *
+ *                    (tREA + 4 - tRP) * 8
+ *         RDN_DELAY = ---------------------     {3}
+ *                           RP
+ *
+ *  4.4) We only support the fastest asynchronous mode of ONFI nand.
+ *       For some ONFI nand, the mode 4 is the fastest mode;
+ *       while for some ONFI nand, the mode 5 is the fastest mode.
+ *       So we only support the mode 4 and mode 5. It is no need to
+ *       support other modes.
+ */
+static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
+			struct gpmi_nfc_hardware_timing *hw)
+{
+	struct resources *r = &this->resources;
+	unsigned long rate = clk_get_rate(r->clock[0]);
+	int mode = this->timing_mode;
+	int dll_threshold = this->devdata->max_chain_delay;
+	unsigned long delay;
+	unsigned long clk_period;
+	int t_rea;
+	int c = 4;
+	int t_rp;
+	int rp;
+
+	/*
+	 * [1] for GPMI_HW_GPMI_TIMING0:
+	 *     The async mode requires 40MHz for mode 4, 50MHz for mode 5.
+	 *     The GPMI can support 100MHz at most. So if we want to
+	 *     get the 40MHz or 50MHz, we have to set DS=1, DH=1.
+	 *     Set the ADDRESS_SETUP to 0 in mode 4.
+	 */
+	hw->data_setup_in_cycles = 1;
+	hw->data_hold_in_cycles = 1;
+	hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
+
+	/* [2] for GPMI_HW_GPMI_TIMING1 */
+	hw->device_busy_timeout = 0x9000;
+
+	/* [3] for GPMI_HW_GPMI_CTRL1 */
+	hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+
+	/*
+	 * Enlarge 10 times for the numerator and denominator in {3}.
+	 * This make us to get more accurate result.
+	 */
+	clk_period = NSEC_PER_SEC / (rate / 10);
+	dll_threshold *= 10;
+	t_rea = ((mode == 5) ? 16 : 20) * 10;
+	c *= 10;
+
+	t_rp = clk_period * 1; /* DATA_SETUP is 1 */
+
+	if (clk_period > dll_threshold) {
+		hw->use_half_periods = 1;
+		rp = clk_period / 2;
+	} else {
+		hw->use_half_periods = 0;
+		rp = clk_period;
+	}
+
+	/*
+	 * Multiply the numerator with 10, we could do a round off:
+	 *      7.8 round up to 8; 7.4 round down to 7.
+	 */
+	delay  = (((t_rea + c - t_rp) * 8) * 10) / rp;
+	delay = (delay + 5) / 10;
+
+	hw->sample_delay_factor = delay;
+}
+
+static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
+{
+	struct resources  *r = &this->resources;
+	struct nand_chip *nand = &this->nand;
+	struct mtd_info	 *mtd = nand_to_mtd(nand);
+	uint8_t *feature;
+	unsigned long rate;
+	int ret;
+
+	feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
+	if (!feature)
+		return -ENOMEM;
+
+	nand->select_chip(mtd, 0);
+
+	/* [1] send SET FEATURE command to NAND */
+	feature[0] = mode;
+	ret = nand->onfi_set_features(mtd, nand,
+				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
+	if (ret)
+		goto err_out;
+
+	/* [2] send GET FEATURE command to double-check the timing mode */
+	memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
+	ret = nand->onfi_get_features(mtd, nand,
+				ONFI_FEATURE_ADDR_TIMING_MODE, feature);
+	if (ret || feature[0] != mode)
+		goto err_out;
+
+	nand->select_chip(mtd, -1);
+
+	/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
+	rate = (mode == 5) ? 100000000 : 80000000;
+	clk_set_rate(r->clock[0], rate);
+
+	/* Let the gpmi_begin() re-compute the timing again. */
+	this->flags &= ~GPMI_TIMING_INIT_OK;
+
+	this->flags |= GPMI_ASYNC_EDO_ENABLED;
+	this->timing_mode = mode;
+	kfree(feature);
+	dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
+	return 0;
+
+err_out:
+	nand->select_chip(mtd, -1);
+	kfree(feature);
+	dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
+	return -EINVAL;
+}
+
+int gpmi_extra_init(struct gpmi_nand_data *this)
+{
+	struct nand_chip *chip = &this->nand;
+
+	/* Enable the asynchronous EDO feature. */
+	if (GPMI_IS_MX6(this) && chip->onfi_version) {
+		int mode = onfi_get_async_timing_mode(chip);
+
+		/* We only support the timing mode 4 and mode 5. */
+		if (mode & ONFI_TIMING_MODE_5)
+			mode = 5;
+		else if (mode & ONFI_TIMING_MODE_4)
+			mode = 4;
+		else
+			return 0;
+
+		return enable_edo_mode(this, mode);
+	}
+	return 0;
+}
+
+/* Begin the I/O */
+void gpmi_begin(struct gpmi_nand_data *this)
+{
+	struct resources *r = &this->resources;
+	void __iomem *gpmi_regs = r->gpmi_regs;
+	unsigned int   clock_period_in_ns;
+	uint32_t       reg;
+	unsigned int   dll_wait_time_in_us;
+	struct gpmi_nfc_hardware_timing  hw;
+	int ret;
+
+	/* Enable the clock. */
+	ret = gpmi_enable_clk(this);
+	if (ret) {
+		dev_err(this->dev, "We failed in enable the clk\n");
+		goto err_out;
+	}
+
+	/* Only initialize the timing once */
+	if (this->flags & GPMI_TIMING_INIT_OK)
+		return;
+	this->flags |= GPMI_TIMING_INIT_OK;
+
+	if (this->flags & GPMI_ASYNC_EDO_ENABLED)
+		gpmi_compute_edo_timing(this, &hw);
+	else
+		gpmi_nfc_compute_hardware_timing(this, &hw);
+
+	/* [1] Set HW_GPMI_TIMING0 */
+	reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
+		BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         |
+		BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
+
+	writel(reg, gpmi_regs + HW_GPMI_TIMING0);
+
+	/* [2] Set HW_GPMI_TIMING1 */
+	writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
+		gpmi_regs + HW_GPMI_TIMING1);
+
+	/* [3] The following code is to set the HW_GPMI_CTRL1. */
+
+	/* Set the WRN_DLY_SEL */
+	writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
+	writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
+					gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	/* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
+	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
+
+	/* Clear out the DLL control fields. */
+	reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD;
+	writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
+
+	/* If no sample delay is called for, return immediately. */
+	if (!hw.sample_delay_factor)
+		return;
+
+	/* Set RDN_DELAY or HALF_PERIOD. */
+	reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
+		| BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
+
+	writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	/* At last, we enable the DLL. */
+	writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET);
+
+	/*
+	 * After we enable the GPMI DLL, we have to wait 64 clock cycles before
+	 * we can use the GPMI. Calculate the amount of time we need to wait,
+	 * in microseconds.
+	 */
+	clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
+	dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
+
+	if (!dll_wait_time_in_us)
+		dll_wait_time_in_us = 1;
+
+	/* Wait for the DLL to settle. */
+	udelay(dll_wait_time_in_us);
+
+err_out:
+	return;
+}
+
+void gpmi_end(struct gpmi_nand_data *this)
+{
+	gpmi_disable_clk(this);
+}
+
+/* Clears a BCH interrupt. */
+void gpmi_clear_bch(struct gpmi_nand_data *this)
+{
+	struct resources *r = &this->resources;
+	writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR);
+}
+
+/* Returns the Ready/Busy status of the given chip. */
+int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
+{
+	struct resources *r = &this->resources;
+	uint32_t mask = 0;
+	uint32_t reg = 0;
+
+	if (GPMI_IS_MX23(this)) {
+		mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
+		reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
+	} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
+		/*
+		 * In the imx6, all the ready/busy pins are bound
+		 * together. So we only need to check chip 0.
+		 */
+		if (GPMI_IS_MX6(this))
+			chip = 0;
+
+		/* MX28 shares the same R/B register as MX6Q. */
+		mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
+		reg = readl(r->gpmi_regs + HW_GPMI_STAT);
+	} else
+		dev_err(this->dev, "unknown arch.\n");
+	return reg & mask;
+}
+
+static inline void set_dma_type(struct gpmi_nand_data *this,
+					enum dma_ops_type type)
+{
+	this->last_dma_type = this->dma_type;
+	this->dma_type = type;
+}
+
+int gpmi_send_command(struct gpmi_nand_data *this)
+{
+	struct dma_chan *channel = get_dma_chan(this);
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist *sgl;
+	int chip = this->current_chip;
+	u32 pio[3];
+
+	/* [1] send out the PIO words */
+	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE)
+		| BM_GPMI_CTRL0_ADDRESS_INCREMENT
+		| BF_GPMI_CTRL0_XFER_COUNT(this->command_length);
+	pio[1] = pio[2] = 0;
+	desc = dmaengine_prep_slave_sg(channel,
+					(struct scatterlist *)pio,
+					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+	if (!desc)
+		return -EINVAL;
+
+	/* [2] send out the COMMAND + ADDRESS string stored in @buffer */
+	sgl = &this->cmd_sgl;
+
+	sg_init_one(sgl, this->cmd_buffer, this->command_length);
+	dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
+	desc = dmaengine_prep_slave_sg(channel,
+				sgl, 1, DMA_MEM_TO_DEV,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc)
+		return -EINVAL;
+
+	/* [3] submit the DMA */
+	set_dma_type(this, DMA_FOR_COMMAND);
+	return start_dma_without_bch_irq(this, desc);
+}
+
+int gpmi_send_data(struct gpmi_nand_data *this)
+{
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *channel = get_dma_chan(this);
+	int chip = this->current_chip;
+	uint32_t command_mode;
+	uint32_t address;
+	u32 pio[2];
+
+	/* [1] PIO */
+	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(address)
+		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
+	pio[1] = 0;
+	desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
+					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+	if (!desc)
+		return -EINVAL;
+
+	/* [2] send DMA request */
+	prepare_data_dma(this, DMA_TO_DEVICE);
+	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+					1, DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc)
+		return -EINVAL;
+
+	/* [3] submit the DMA */
+	set_dma_type(this, DMA_FOR_WRITE_DATA);
+	return start_dma_without_bch_irq(this, desc);
+}
+
+int gpmi_read_data(struct gpmi_nand_data *this)
+{
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *channel = get_dma_chan(this);
+	int chip = this->current_chip;
+	u32 pio[2];
+
+	/* [1] : send PIO */
+	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA)
+		| BF_GPMI_CTRL0_XFER_COUNT(this->upper_len);
+	pio[1] = 0;
+	desc = dmaengine_prep_slave_sg(channel,
+					(struct scatterlist *)pio,
+					ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
+	if (!desc)
+		return -EINVAL;
+
+	/* [2] : send DMA request */
+	prepare_data_dma(this, DMA_FROM_DEVICE);
+	desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
+					1, DMA_DEV_TO_MEM,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc)
+		return -EINVAL;
+
+	/* [3] : submit the DMA */
+	set_dma_type(this, DMA_FOR_READ_DATA);
+	return start_dma_without_bch_irq(this, desc);
+}
+
+int gpmi_send_page(struct gpmi_nand_data *this,
+			dma_addr_t payload, dma_addr_t auxiliary)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	uint32_t command_mode;
+	uint32_t address;
+	uint32_t ecc_command;
+	uint32_t buffer_mask;
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *channel = get_dma_chan(this);
+	int chip = this->current_chip;
+	u32 pio[6];
+
+	/* A DMA descriptor that does an ECC page read. */
+	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
+	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE;
+	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE |
+				BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(address)
+		| BF_GPMI_CTRL0_XFER_COUNT(0);
+	pio[1] = 0;
+	pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
+		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
+		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
+	pio[3] = geo->page_size;
+	pio[4] = payload;
+	pio[5] = auxiliary;
+
+	desc = dmaengine_prep_slave_sg(channel,
+					(struct scatterlist *)pio,
+					ARRAY_SIZE(pio), DMA_TRANS_NONE,
+					DMA_CTRL_ACK);
+	if (!desc)
+		return -EINVAL;
+
+	set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
+	return start_dma_with_bch_irq(this, desc);
+}
+
+int gpmi_read_page(struct gpmi_nand_data *this,
+				dma_addr_t payload, dma_addr_t auxiliary)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	uint32_t command_mode;
+	uint32_t address;
+	uint32_t ecc_command;
+	uint32_t buffer_mask;
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *channel = get_dma_chan(this);
+	int chip = this->current_chip;
+	u32 pio[6];
+
+	/* [1] Wait for the chip to report ready. */
+	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(address)
+		| BF_GPMI_CTRL0_XFER_COUNT(0);
+	pio[1] = 0;
+	desc = dmaengine_prep_slave_sg(channel,
+				(struct scatterlist *)pio, 2,
+				DMA_TRANS_NONE, 0);
+	if (!desc)
+		return -EINVAL;
+
+	/* [2] Enable the BCH block and read. */
+	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
+	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+	ecc_command  = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE;
+	buffer_mask  = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE
+			| BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
+
+	pio[0] =  BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(address)
+		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
+
+	pio[1] = 0;
+	pio[2] =  BM_GPMI_ECCCTRL_ENABLE_ECC
+		| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
+		| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
+	pio[3] = geo->page_size;
+	pio[4] = payload;
+	pio[5] = auxiliary;
+	desc = dmaengine_prep_slave_sg(channel,
+					(struct scatterlist *)pio,
+					ARRAY_SIZE(pio), DMA_TRANS_NONE,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc)
+		return -EINVAL;
+
+	/* [3] Disable the BCH block */
+	command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
+	address      = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
+
+	pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
+		| BM_GPMI_CTRL0_WORD_LENGTH
+		| BF_GPMI_CTRL0_CS(chip, this)
+		| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
+		| BF_GPMI_CTRL0_ADDRESS(address)
+		| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
+	pio[1] = 0;
+	pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
+	desc = dmaengine_prep_slave_sg(channel,
+				(struct scatterlist *)pio, 3,
+				DMA_TRANS_NONE,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc)
+		return -EINVAL;
+
+	/* [4] submit the DMA */
+	set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
+	return start_dma_with_bch_irq(this, desc);
+}
+
+/**
+ * gpmi_copy_bits - copy bits from one memory region to another
+ * @dst: destination buffer
+ * @dst_bit_off: bit offset we're starting to write at
+ * @src: source buffer
+ * @src_bit_off: bit offset we're starting to read from
+ * @nbits: number of bits to copy
+ *
+ * This functions copies bits from one memory region to another, and is used by
+ * the GPMI driver to copy ECC sections which are not guaranteed to be byte
+ * aligned.
+ *
+ * src and dst should not overlap.
+ *
+ */
+void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
+		    const u8 *src, size_t src_bit_off,
+		    size_t nbits)
+{
+	size_t i;
+	size_t nbytes;
+	u32 src_buffer = 0;
+	size_t bits_in_src_buffer = 0;
+
+	if (!nbits)
+		return;
+
+	/*
+	 * Move src and dst pointers to the closest byte pointer and store bit
+	 * offsets within a byte.
+	 */
+	src += src_bit_off / 8;
+	src_bit_off %= 8;
+
+	dst += dst_bit_off / 8;
+	dst_bit_off %= 8;
+
+	/*
+	 * Initialize the src_buffer value with bits available in the first
+	 * byte of data so that we end up with a byte aligned src pointer.
+	 */
+	if (src_bit_off) {
+		src_buffer = src[0] >> src_bit_off;
+		if (nbits >= (8 - src_bit_off)) {
+			bits_in_src_buffer += 8 - src_bit_off;
+		} else {
+			src_buffer &= GENMASK(nbits - 1, 0);
+			bits_in_src_buffer += nbits;
+		}
+		nbits -= bits_in_src_buffer;
+		src++;
+	}
+
+	/* Calculate the number of bytes that can be copied from src to dst. */
+	nbytes = nbits / 8;
+
+	/* Try to align dst to a byte boundary. */
+	if (dst_bit_off) {
+		if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
+			src_buffer |= src[0] << bits_in_src_buffer;
+			bits_in_src_buffer += 8;
+			src++;
+			nbytes--;
+		}
+
+		if (bits_in_src_buffer >= (8 - dst_bit_off)) {
+			dst[0] &= GENMASK(dst_bit_off - 1, 0);
+			dst[0] |= src_buffer << dst_bit_off;
+			src_buffer >>= (8 - dst_bit_off);
+			bits_in_src_buffer -= (8 - dst_bit_off);
+			dst_bit_off = 0;
+			dst++;
+			if (bits_in_src_buffer > 7) {
+				bits_in_src_buffer -= 8;
+				dst[0] = src_buffer;
+				dst++;
+				src_buffer >>= 8;
+			}
+		}
+	}
+
+	if (!bits_in_src_buffer && !dst_bit_off) {
+		/*
+		 * Both src and dst pointers are byte aligned, thus we can
+		 * just use the optimized memcpy function.
+		 */
+		if (nbytes)
+			memcpy(dst, src, nbytes);
+	} else {
+		/*
+		 * src buffer is not byte aligned, hence we have to copy each
+		 * src byte to the src_buffer variable before extracting a byte
+		 * to store in dst.
+		 */
+		for (i = 0; i < nbytes; i++) {
+			src_buffer |= src[i] << bits_in_src_buffer;
+			dst[i] = src_buffer;
+			src_buffer >>= 8;
+		}
+	}
+	/* Update dst and src pointers */
+	dst += nbytes;
+	src += nbytes;
+
+	/*
+	 * nbits is the number of remaining bits. It should not exceed 8 as
+	 * we've already copied as much bytes as possible.
+	 */
+	nbits %= 8;
+
+	/*
+	 * If there's no more bits to copy to the destination and src buffer
+	 * was already byte aligned, then we're done.
+	 */
+	if (!nbits && !bits_in_src_buffer)
+		return;
+
+	/* Copy the remaining bits to src_buffer */
+	if (nbits)
+		src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
+			      bits_in_src_buffer;
+	bits_in_src_buffer += nbits;
+
+	/*
+	 * In case there were not enough bits to get a byte aligned dst buffer
+	 * prepare the src_buffer variable to match the dst organization (shift
+	 * src_buffer by dst_bit_off and retrieve the least significant bits
+	 * from dst).
+	 */
+	if (dst_bit_off)
+		src_buffer = (src_buffer << dst_bit_off) |
+			     (*dst & GENMASK(dst_bit_off - 1, 0));
+	bits_in_src_buffer += dst_bit_off;
+
+	/*
+	 * Keep most significant bits from dst if we end up with an unaligned
+	 * number of bits.
+	 */
+	nbytes = bits_in_src_buffer / 8;
+	if (bits_in_src_buffer % 8) {
+		src_buffer |= (dst[nbytes] &
+			       GENMASK(7, bits_in_src_buffer % 8)) <<
+			      (nbytes * 8);
+		nbytes++;
+	}
+
+	/* Copy the remaining bytes to dst */
+	for (i = 0; i < nbytes; i++) {
+		dst[i] = src_buffer;
+		src_buffer >>= 8;
+	}
+}
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
new file mode 100644
index 000000000000..61fdd733492f
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -0,0 +1,2182 @@
+/*
+ * Freescale GPMI NAND Flash Driver
+ *
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/sched/task_stack.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include "gpmi-nand.h"
+#include "bch-regs.h"
+
+/* Resource names for the GPMI NAND driver. */
+#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
+#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
+#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
+
+/* add our owner bbt descriptor */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr gpmi_bbt_descr = {
+	.options	= 0,
+	.offs		= 0,
+	.len		= 1,
+	.pattern	= scan_ff_pattern
+};
+
+/*
+ * We may change the layout if we can get the ECC info from the datasheet,
+ * else we will use all the (page + OOB).
+ */
+static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *geo = &this->bch_geometry;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = geo->page_size - mtd->writesize;
+
+	return 0;
+}
+
+static int gpmi_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *geo = &this->bch_geometry;
+
+	if (section)
+		return -ERANGE;
+
+	/* The available oob size we have. */
+	if (geo->page_size < mtd->writesize + mtd->oobsize) {
+		oobregion->offset = geo->page_size - mtd->writesize;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const char * const gpmi_clks_for_mx2x[] = {
+	"gpmi_io",
+};
+
+static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
+	.ecc = gpmi_ooblayout_ecc,
+	.free = gpmi_ooblayout_free,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx23 = {
+	.type = IS_MX23,
+	.bch_max_ecc_strength = 20,
+	.max_chain_delay = 16,
+	.clks = gpmi_clks_for_mx2x,
+	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx28 = {
+	.type = IS_MX28,
+	.bch_max_ecc_strength = 20,
+	.max_chain_delay = 16,
+	.clks = gpmi_clks_for_mx2x,
+	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
+};
+
+static const char * const gpmi_clks_for_mx6[] = {
+	"gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6q = {
+	.type = IS_MX6Q,
+	.bch_max_ecc_strength = 40,
+	.max_chain_delay = 12,
+	.clks = gpmi_clks_for_mx6,
+	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6sx = {
+	.type = IS_MX6SX,
+	.bch_max_ecc_strength = 62,
+	.max_chain_delay = 12,
+	.clks = gpmi_clks_for_mx6,
+	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
+};
+
+static const char * const gpmi_clks_for_mx7d[] = {
+	"gpmi_io", "gpmi_bch_apb",
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx7d = {
+	.type = IS_MX7D,
+	.bch_max_ecc_strength = 62,
+	.max_chain_delay = 12,
+	.clks = gpmi_clks_for_mx7d,
+	.clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
+};
+
+static irqreturn_t bch_irq(int irq, void *cookie)
+{
+	struct gpmi_nand_data *this = cookie;
+
+	gpmi_clear_bch(this);
+	complete(&this->bch_done);
+	return IRQ_HANDLED;
+}
+
+/*
+ *  Calculate the ECC strength by hand:
+ *	E : The ECC strength.
+ *	G : the length of Galois Field.
+ *	N : The chunk count of per page.
+ *	O : the oobsize of the NAND chip.
+ *	M : the metasize of per page.
+ *
+ *	The formula is :
+ *		E * G * N
+ *	      ------------ <= (O - M)
+ *                  8
+ *
+ *      So, we get E by:
+ *                    (O - M) * 8
+ *              E <= -------------
+ *                       G * N
+ */
+static inline int get_ecc_strength(struct gpmi_nand_data *this)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	struct mtd_info	*mtd = nand_to_mtd(&this->nand);
+	int ecc_strength;
+
+	ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8)
+			/ (geo->gf_len * geo->ecc_chunk_count);
+
+	/* We need the minor even number. */
+	return round_down(ecc_strength, 2);
+}
+
+static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+
+	/* Do the sanity check. */
+	if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
+		/* The mx23/mx28 only support the GF13. */
+		if (geo->gf_len == 14)
+			return false;
+	}
+	return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
+}
+
+/*
+ * If we can get the ECC information from the nand chip, we do not
+ * need to calculate them ourselves.
+ *
+ * We may have available oob space in this case.
+ */
+static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int block_mark_bit_offset;
+
+	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+		return -EINVAL;
+
+	switch (chip->ecc_step_ds) {
+	case SZ_512:
+		geo->gf_len = 13;
+		break;
+	case SZ_1K:
+		geo->gf_len = 14;
+		break;
+	default:
+		dev_err(this->dev,
+			"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
+			chip->ecc_strength_ds, chip->ecc_step_ds);
+		return -EINVAL;
+	}
+	geo->ecc_chunk_size = chip->ecc_step_ds;
+	geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
+	if (!gpmi_check_ecc(this))
+		return -EINVAL;
+
+	/* Keep the C >= O */
+	if (geo->ecc_chunk_size < mtd->oobsize) {
+		dev_err(this->dev,
+			"unsupported nand chip. ecc size: %d, oob size : %d\n",
+			chip->ecc_step_ds, mtd->oobsize);
+		return -EINVAL;
+	}
+
+	/* The default value, see comment in the legacy_set_geometry(). */
+	geo->metadata_size = 10;
+
+	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+
+	/*
+	 * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
+	 *
+	 *    |                          P                            |
+	 *    |<----------------------------------------------------->|
+	 *    |                                                       |
+	 *    |                                        (Block Mark)   |
+	 *    |                      P'                      |      | |     |
+	 *    |<-------------------------------------------->|  D   | |  O' |
+	 *    |                                              |<---->| |<--->|
+	 *    V                                              V      V V     V
+	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|     |
+	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+	 *                                                   ^              ^
+	 *                                                   |      O       |
+	 *                                                   |<------------>|
+	 *                                                   |              |
+	 *
+	 *	P : the page size for BCH module.
+	 *	E : The ECC strength.
+	 *	G : the length of Galois Field.
+	 *	N : The chunk count of per page.
+	 *	M : the metasize of per page.
+	 *	C : the ecc chunk size, aka the "data" above.
+	 *	P': the nand chip's page size.
+	 *	O : the nand chip's oob size.
+	 *	O': the free oob.
+	 *
+	 *	The formula for P is :
+	 *
+	 *	            E * G * N
+	 *	       P = ------------ + P' + M
+	 *                      8
+	 *
+	 * The position of block mark moves forward in the ECC-based view
+	 * of page, and the delta is:
+	 *
+	 *                   E * G * (N - 1)
+	 *             D = (---------------- + M)
+	 *                          8
+	 *
+	 * Please see the comment in legacy_set_geometry().
+	 * With the condition C >= O , we still can get same result.
+	 * So the bit position of the physical block mark within the ECC-based
+	 * view of the page is :
+	 *             (P' - D) * 8
+	 */
+	geo->page_size = mtd->writesize + geo->metadata_size +
+		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+
+	geo->payload_size = mtd->writesize;
+
+	geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
+	geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
+				+ ALIGN(geo->ecc_chunk_count, 4);
+
+	if (!this->swap_block_mark)
+		return 0;
+
+	/* For bit swap. */
+	block_mark_bit_offset = mtd->writesize * 8 -
+		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+				+ geo->metadata_size * 8);
+
+	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
+	return 0;
+}
+
+static int legacy_set_geometry(struct gpmi_nand_data *this)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	struct mtd_info *mtd = nand_to_mtd(&this->nand);
+	unsigned int metadata_size;
+	unsigned int status_size;
+	unsigned int block_mark_bit_offset;
+
+	/*
+	 * The size of the metadata can be changed, though we set it to 10
+	 * bytes now. But it can't be too large, because we have to save
+	 * enough space for BCH.
+	 */
+	geo->metadata_size = 10;
+
+	/* The default for the length of Galois Field. */
+	geo->gf_len = 13;
+
+	/* The default for chunk size. */
+	geo->ecc_chunk_size = 512;
+	while (geo->ecc_chunk_size < mtd->oobsize) {
+		geo->ecc_chunk_size *= 2; /* keep C >= O */
+		geo->gf_len = 14;
+	}
+
+	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+
+	/* We use the same ECC strength for all chunks. */
+	geo->ecc_strength = get_ecc_strength(this);
+	if (!gpmi_check_ecc(this)) {
+		dev_err(this->dev,
+			"ecc strength: %d cannot be supported by the controller (%d)\n"
+			"try to use minimum ecc strength that NAND chip required\n",
+			geo->ecc_strength,
+			this->devdata->bch_max_ecc_strength);
+		return -EINVAL;
+	}
+
+	geo->page_size = mtd->writesize + geo->metadata_size +
+		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+	geo->payload_size = mtd->writesize;
+
+	/*
+	 * The auxiliary buffer contains the metadata and the ECC status. The
+	 * metadata is padded to the nearest 32-bit boundary. The ECC status
+	 * contains one byte for every ECC chunk, and is also padded to the
+	 * nearest 32-bit boundary.
+	 */
+	metadata_size = ALIGN(geo->metadata_size, 4);
+	status_size   = ALIGN(geo->ecc_chunk_count, 4);
+
+	geo->auxiliary_size = metadata_size + status_size;
+	geo->auxiliary_status_offset = metadata_size;
+
+	if (!this->swap_block_mark)
+		return 0;
+
+	/*
+	 * We need to compute the byte and bit offsets of
+	 * the physical block mark within the ECC-based view of the page.
+	 *
+	 * NAND chip with 2K page shows below:
+	 *                                             (Block Mark)
+	 *                                                   |      |
+	 *                                                   |  D   |
+	 *                                                   |<---->|
+	 *                                                   V      V
+	 *    +---+----------+-+----------+-+----------+-+----------+-+
+	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|
+	 *    +---+----------+-+----------+-+----------+-+----------+-+
+	 *
+	 * The position of block mark moves forward in the ECC-based view
+	 * of page, and the delta is:
+	 *
+	 *                   E * G * (N - 1)
+	 *             D = (---------------- + M)
+	 *                          8
+	 *
+	 * With the formula to compute the ECC strength, and the condition
+	 *       : C >= O         (C is the ecc chunk size)
+	 *
+	 * It's easy to deduce to the following result:
+	 *
+	 *         E * G       (O - M)      C - M         C - M
+	 *      ----------- <= ------- <=  --------  <  ---------
+	 *           8            N           N          (N - 1)
+	 *
+	 *  So, we get:
+	 *
+	 *                   E * G * (N - 1)
+	 *             D = (---------------- + M) < C
+	 *                          8
+	 *
+	 *  The above inequality means the position of block mark
+	 *  within the ECC-based view of the page is still in the data chunk,
+	 *  and it's NOT in the ECC bits of the chunk.
+	 *
+	 *  Use the following to compute the bit position of the
+	 *  physical block mark within the ECC-based view of the page:
+	 *          (page_size - D) * 8
+	 *
+	 *  --Huang Shijie
+	 */
+	block_mark_bit_offset = mtd->writesize * 8 -
+		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+				+ geo->metadata_size * 8);
+
+	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
+	return 0;
+}
+
+int common_nfc_set_geometry(struct gpmi_nand_data *this)
+{
+	if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
+				|| legacy_set_geometry(this))
+		return set_geometry_by_ecc_info(this);
+
+	return 0;
+}
+
+struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
+{
+	/* We use the DMA channel 0 to access all the nand chips. */
+	return this->dma_chans[0];
+}
+
+/* Can we use the upper's buffer directly for DMA? */
+void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
+{
+	struct scatterlist *sgl = &this->data_sgl;
+	int ret;
+
+	/* first try to map the upper buffer directly */
+	if (virt_addr_valid(this->upper_buf) &&
+		!object_is_on_stack(this->upper_buf)) {
+		sg_init_one(sgl, this->upper_buf, this->upper_len);
+		ret = dma_map_sg(this->dev, sgl, 1, dr);
+		if (ret == 0)
+			goto map_fail;
+
+		this->direct_dma_map_ok = true;
+		return;
+	}
+
+map_fail:
+	/* We have to use our own DMA buffer. */
+	sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
+
+	if (dr == DMA_TO_DEVICE)
+		memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
+
+	dma_map_sg(this->dev, sgl, 1, dr);
+
+	this->direct_dma_map_ok = false;
+}
+
+/* This will be called after the DMA operation is finished. */
+static void dma_irq_callback(void *param)
+{
+	struct gpmi_nand_data *this = param;
+	struct completion *dma_c = &this->dma_done;
+
+	switch (this->dma_type) {
+	case DMA_FOR_COMMAND:
+		dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
+		break;
+
+	case DMA_FOR_READ_DATA:
+		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE);
+		if (this->direct_dma_map_ok == false)
+			memcpy(this->upper_buf, this->data_buffer_dma,
+				this->upper_len);
+		break;
+
+	case DMA_FOR_WRITE_DATA:
+		dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE);
+		break;
+
+	case DMA_FOR_READ_ECC_PAGE:
+	case DMA_FOR_WRITE_ECC_PAGE:
+		/* We have to wait the BCH interrupt to finish. */
+		break;
+
+	default:
+		dev_err(this->dev, "in wrong DMA operation.\n");
+	}
+
+	complete(dma_c);
+}
+
+int start_dma_without_bch_irq(struct gpmi_nand_data *this,
+				struct dma_async_tx_descriptor *desc)
+{
+	struct completion *dma_c = &this->dma_done;
+	unsigned long timeout;
+
+	init_completion(dma_c);
+
+	desc->callback		= dma_irq_callback;
+	desc->callback_param	= this;
+	dmaengine_submit(desc);
+	dma_async_issue_pending(get_dma_chan(this));
+
+	/* Wait for the interrupt from the DMA block. */
+	timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
+	if (!timeout) {
+		dev_err(this->dev, "DMA timeout, last DMA :%d\n",
+			this->last_dma_type);
+		gpmi_dump_info(this);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+/*
+ * This function is used in BCH reading or BCH writing pages.
+ * It will wait for the BCH interrupt as long as ONE second.
+ * Actually, we must wait for two interrupts :
+ *	[1] firstly the DMA interrupt and
+ *	[2] secondly the BCH interrupt.
+ */
+int start_dma_with_bch_irq(struct gpmi_nand_data *this,
+			struct dma_async_tx_descriptor *desc)
+{
+	struct completion *bch_c = &this->bch_done;
+	unsigned long timeout;
+
+	/* Prepare to receive an interrupt from the BCH block. */
+	init_completion(bch_c);
+
+	/* start the DMA */
+	start_dma_without_bch_irq(this, desc);
+
+	/* Wait for the interrupt from the BCH block. */
+	timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
+	if (!timeout) {
+		dev_err(this->dev, "BCH timeout, last DMA :%d\n",
+			this->last_dma_type);
+		gpmi_dump_info(this);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int acquire_register_block(struct gpmi_nand_data *this,
+				  const char *res_name)
+{
+	struct platform_device *pdev = this->pdev;
+	struct resources *res = &this->resources;
+	struct resource *r;
+	void __iomem *p;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
+	p = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+
+	if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
+		res->gpmi_regs = p;
+	else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
+		res->bch_regs = p;
+	else
+		dev_err(this->dev, "unknown resource name : %s\n", res_name);
+
+	return 0;
+}
+
+static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
+{
+	struct platform_device *pdev = this->pdev;
+	const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
+	struct resource *r;
+	int err;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
+	if (!r) {
+		dev_err(this->dev, "Can't get resource for %s\n", res_name);
+		return -ENODEV;
+	}
+
+	err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
+	if (err)
+		dev_err(this->dev, "error requesting BCH IRQ\n");
+
+	return err;
+}
+
+static void release_dma_channels(struct gpmi_nand_data *this)
+{
+	unsigned int i;
+	for (i = 0; i < DMA_CHANS; i++)
+		if (this->dma_chans[i]) {
+			dma_release_channel(this->dma_chans[i]);
+			this->dma_chans[i] = NULL;
+		}
+}
+
+static int acquire_dma_channels(struct gpmi_nand_data *this)
+{
+	struct platform_device *pdev = this->pdev;
+	struct dma_chan *dma_chan;
+
+	/* request dma channel */
+	dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
+	if (!dma_chan) {
+		dev_err(this->dev, "Failed to request DMA channel.\n");
+		goto acquire_err;
+	}
+
+	this->dma_chans[0] = dma_chan;
+	return 0;
+
+acquire_err:
+	release_dma_channels(this);
+	return -EINVAL;
+}
+
+static int gpmi_get_clks(struct gpmi_nand_data *this)
+{
+	struct resources *r = &this->resources;
+	struct clk *clk;
+	int err, i;
+
+	for (i = 0; i < this->devdata->clks_count; i++) {
+		clk = devm_clk_get(this->dev, this->devdata->clks[i]);
+		if (IS_ERR(clk)) {
+			err = PTR_ERR(clk);
+			goto err_clock;
+		}
+
+		r->clock[i] = clk;
+	}
+
+	if (GPMI_IS_MX6(this))
+		/*
+		 * Set the default value for the gpmi clock.
+		 *
+		 * If you want to use the ONFI nand which is in the
+		 * Synchronous Mode, you should change the clock as you need.
+		 */
+		clk_set_rate(r->clock[0], 22000000);
+
+	return 0;
+
+err_clock:
+	dev_dbg(this->dev, "failed in finding the clocks.\n");
+	return err;
+}
+
+static int acquire_resources(struct gpmi_nand_data *this)
+{
+	int ret;
+
+	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
+	if (ret)
+		goto exit_regs;
+
+	ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME);
+	if (ret)
+		goto exit_regs;
+
+	ret = acquire_bch_irq(this, bch_irq);
+	if (ret)
+		goto exit_regs;
+
+	ret = acquire_dma_channels(this);
+	if (ret)
+		goto exit_regs;
+
+	ret = gpmi_get_clks(this);
+	if (ret)
+		goto exit_clock;
+	return 0;
+
+exit_clock:
+	release_dma_channels(this);
+exit_regs:
+	return ret;
+}
+
+static void release_resources(struct gpmi_nand_data *this)
+{
+	release_dma_channels(this);
+}
+
+static int init_hardware(struct gpmi_nand_data *this)
+{
+	int ret;
+
+	/*
+	 * This structure contains the "safe" GPMI timing that should succeed
+	 * with any NAND Flash device
+	 * (although, with less-than-optimal performance).
+	 */
+	struct nand_timing  safe_timing = {
+		.data_setup_in_ns        = 80,
+		.data_hold_in_ns         = 60,
+		.address_setup_in_ns     = 25,
+		.gpmi_sample_delay_in_ns =  6,
+		.tREA_in_ns              = -1,
+		.tRLOH_in_ns             = -1,
+		.tRHOH_in_ns             = -1,
+	};
+
+	/* Initialize the hardwares. */
+	ret = gpmi_init(this);
+	if (ret)
+		return ret;
+
+	this->timing = safe_timing;
+	return 0;
+}
+
+static int read_page_prepare(struct gpmi_nand_data *this,
+			void *destination, unsigned length,
+			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+			void **use_virt, dma_addr_t *use_phys)
+{
+	struct device *dev = this->dev;
+
+	if (virt_addr_valid(destination)) {
+		dma_addr_t dest_phys;
+
+		dest_phys = dma_map_single(dev, destination,
+						length, DMA_FROM_DEVICE);
+		if (dma_mapping_error(dev, dest_phys)) {
+			if (alt_size < length) {
+				dev_err(dev, "Alternate buffer is too small\n");
+				return -ENOMEM;
+			}
+			goto map_failed;
+		}
+		*use_virt = destination;
+		*use_phys = dest_phys;
+		this->direct_dma_map_ok = true;
+		return 0;
+	}
+
+map_failed:
+	*use_virt = alt_virt;
+	*use_phys = alt_phys;
+	this->direct_dma_map_ok = false;
+	return 0;
+}
+
+static inline void read_page_end(struct gpmi_nand_data *this,
+			void *destination, unsigned length,
+			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+			void *used_virt, dma_addr_t used_phys)
+{
+	if (this->direct_dma_map_ok)
+		dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE);
+}
+
+static inline void read_page_swap_end(struct gpmi_nand_data *this,
+			void *destination, unsigned length,
+			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+			void *used_virt, dma_addr_t used_phys)
+{
+	if (!this->direct_dma_map_ok)
+		memcpy(destination, alt_virt, length);
+}
+
+static int send_page_prepare(struct gpmi_nand_data *this,
+			const void *source, unsigned length,
+			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+			const void **use_virt, dma_addr_t *use_phys)
+{
+	struct device *dev = this->dev;
+
+	if (virt_addr_valid(source)) {
+		dma_addr_t source_phys;
+
+		source_phys = dma_map_single(dev, (void *)source, length,
+						DMA_TO_DEVICE);
+		if (dma_mapping_error(dev, source_phys)) {
+			if (alt_size < length) {
+				dev_err(dev, "Alternate buffer is too small\n");
+				return -ENOMEM;
+			}
+			goto map_failed;
+		}
+		*use_virt = source;
+		*use_phys = source_phys;
+		return 0;
+	}
+map_failed:
+	/*
+	 * Copy the content of the source buffer into the alternate
+	 * buffer and set up the return values accordingly.
+	 */
+	memcpy(alt_virt, source, length);
+
+	*use_virt = alt_virt;
+	*use_phys = alt_phys;
+	return 0;
+}
+
+static void send_page_end(struct gpmi_nand_data *this,
+			const void *source, unsigned length,
+			void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
+			const void *used_virt, dma_addr_t used_phys)
+{
+	struct device *dev = this->dev;
+	if (used_virt == source)
+		dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE);
+}
+
+static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
+{
+	struct device *dev = this->dev;
+
+	if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt))
+		dma_free_coherent(dev, this->page_buffer_size,
+					this->page_buffer_virt,
+					this->page_buffer_phys);
+	kfree(this->cmd_buffer);
+	kfree(this->data_buffer_dma);
+	kfree(this->raw_buffer);
+
+	this->cmd_buffer	= NULL;
+	this->data_buffer_dma	= NULL;
+	this->raw_buffer	= NULL;
+	this->page_buffer_virt	= NULL;
+	this->page_buffer_size	=  0;
+}
+
+/* Allocate the DMA buffers */
+static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	struct device *dev = this->dev;
+	struct mtd_info *mtd = nand_to_mtd(&this->nand);
+
+	/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
+	this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
+	if (this->cmd_buffer == NULL)
+		goto error_alloc;
+
+	/*
+	 * [2] Allocate a read/write data buffer.
+	 *     The gpmi_alloc_dma_buffer can be called twice.
+	 *     We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
+	 *     is called before the nand_scan_ident; and we allocate a buffer
+	 *     of the real NAND page size when the gpmi_alloc_dma_buffer is
+	 *     called after the nand_scan_ident.
+	 */
+	this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
+					GFP_DMA | GFP_KERNEL);
+	if (this->data_buffer_dma == NULL)
+		goto error_alloc;
+
+	/*
+	 * [3] Allocate the page buffer.
+	 *
+	 * Both the payload buffer and the auxiliary buffer must appear on
+	 * 32-bit boundaries. We presume the size of the payload buffer is a
+	 * power of two and is much larger than four, which guarantees the
+	 * auxiliary buffer will appear on a 32-bit boundary.
+	 */
+	this->page_buffer_size = geo->payload_size + geo->auxiliary_size;
+	this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size,
+					&this->page_buffer_phys, GFP_DMA);
+	if (!this->page_buffer_virt)
+		goto error_alloc;
+
+	this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+	if (!this->raw_buffer)
+		goto error_alloc;
+
+	/* Slice up the page buffer. */
+	this->payload_virt = this->page_buffer_virt;
+	this->payload_phys = this->page_buffer_phys;
+	this->auxiliary_virt = this->payload_virt + geo->payload_size;
+	this->auxiliary_phys = this->payload_phys + geo->payload_size;
+	return 0;
+
+error_alloc:
+	gpmi_free_dma_buffer(this);
+	return -ENOMEM;
+}
+
+static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	int ret;
+
+	/*
+	 * Every operation begins with a command byte and a series of zero or
+	 * more address bytes. These are distinguished by either the Address
+	 * Latch Enable (ALE) or Command Latch Enable (CLE) signals being
+	 * asserted. When MTD is ready to execute the command, it will deassert
+	 * both latch enables.
+	 *
+	 * Rather than run a separate DMA operation for every single byte, we
+	 * queue them up and run a single DMA operation for the entire series
+	 * of command and data bytes. NAND_CMD_NONE means the END of the queue.
+	 */
+	if ((ctrl & (NAND_ALE | NAND_CLE))) {
+		if (data != NAND_CMD_NONE)
+			this->cmd_buffer[this->command_length++] = data;
+		return;
+	}
+
+	if (!this->command_length)
+		return;
+
+	ret = gpmi_send_command(this);
+	if (ret)
+		dev_err(this->dev, "Chip: %u, Error %d\n",
+			this->current_chip, ret);
+
+	this->command_length = 0;
+}
+
+static int gpmi_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+
+	return gpmi_is_ready(this, this->current_chip);
+}
+
+static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+
+	if ((this->current_chip < 0) && (chipnr >= 0))
+		gpmi_begin(this);
+	else if ((this->current_chip >= 0) && (chipnr < 0))
+		gpmi_end(this);
+
+	this->current_chip = chipnr;
+}
+
+static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+
+	dev_dbg(this->dev, "len is %d\n", len);
+	this->upper_buf	= buf;
+	this->upper_len	= len;
+
+	gpmi_read_data(this);
+}
+
+static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+
+	dev_dbg(this->dev, "len is %d\n", len);
+	this->upper_buf	= (uint8_t *)buf;
+	this->upper_len	= len;
+
+	gpmi_send_data(this);
+}
+
+static uint8_t gpmi_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	uint8_t *buf = this->data_buffer_dma;
+
+	gpmi_read_buf(mtd, buf, 1);
+	return buf[0];
+}
+
+/*
+ * Handles block mark swapping.
+ * It can be called in swapping the block mark, or swapping it back,
+ * because the the operations are the same.
+ */
+static void block_mark_swapping(struct gpmi_nand_data *this,
+				void *payload, void *auxiliary)
+{
+	struct bch_geometry *nfc_geo = &this->bch_geometry;
+	unsigned char *p;
+	unsigned char *a;
+	unsigned int  bit;
+	unsigned char mask;
+	unsigned char from_data;
+	unsigned char from_oob;
+
+	if (!this->swap_block_mark)
+		return;
+
+	/*
+	 * If control arrives here, we're swapping. Make some convenience
+	 * variables.
+	 */
+	bit = nfc_geo->block_mark_bit_offset;
+	p   = payload + nfc_geo->block_mark_byte_offset;
+	a   = auxiliary;
+
+	/*
+	 * Get the byte from the data area that overlays the block mark. Since
+	 * the ECC engine applies its own view to the bits in the page, the
+	 * physical block mark won't (in general) appear on a byte boundary in
+	 * the data.
+	 */
+	from_data = (p[0] >> bit) | (p[1] << (8 - bit));
+
+	/* Get the byte from the OOB. */
+	from_oob = a[0];
+
+	/* Swap them. */
+	a[0] = from_data;
+
+	mask = (0x1 << bit) - 1;
+	p[0] = (p[0] & mask) | (from_oob << bit);
+
+	mask = ~0 << bit;
+	p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
+}
+
+static int gpmi_ecc_read_page_data(struct nand_chip *chip,
+				   uint8_t *buf, int oob_required,
+				   int page)
+{
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *nfc_geo = &this->bch_geometry;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	void          *payload_virt;
+	dma_addr_t    payload_phys;
+	void          *auxiliary_virt;
+	dma_addr_t    auxiliary_phys;
+	unsigned int  i;
+	unsigned char *status;
+	unsigned int  max_bitflips = 0;
+	int           ret;
+
+	dev_dbg(this->dev, "page number is : %d\n", page);
+	ret = read_page_prepare(this, buf, nfc_geo->payload_size,
+					this->payload_virt, this->payload_phys,
+					nfc_geo->payload_size,
+					&payload_virt, &payload_phys);
+	if (ret) {
+		dev_err(this->dev, "Inadequate DMA buffer\n");
+		ret = -ENOMEM;
+		return ret;
+	}
+	auxiliary_virt = this->auxiliary_virt;
+	auxiliary_phys = this->auxiliary_phys;
+
+	/* go! */
+	ret = gpmi_read_page(this, payload_phys, auxiliary_phys);
+	read_page_end(this, buf, nfc_geo->payload_size,
+			this->payload_virt, this->payload_phys,
+			nfc_geo->payload_size,
+			payload_virt, payload_phys);
+	if (ret) {
+		dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
+		return ret;
+	}
+
+	/* Loop over status bytes, accumulating ECC status. */
+	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
+
+	read_page_swap_end(this, buf, nfc_geo->payload_size,
+			   this->payload_virt, this->payload_phys,
+			   nfc_geo->payload_size,
+			   payload_virt, payload_phys);
+
+	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
+		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
+			continue;
+
+		if (*status == STATUS_UNCORRECTABLE) {
+			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+			u8 *eccbuf = this->raw_buffer;
+			int offset, bitoffset;
+			int eccbytes;
+			int flips;
+
+			/* Read ECC bytes into our internal raw_buffer */
+			offset = nfc_geo->metadata_size * 8;
+			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
+			offset -= eccbits;
+			bitoffset = offset % 8;
+			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
+			offset /= 8;
+			eccbytes -= offset;
+			nand_change_read_column_op(chip, offset, eccbuf,
+						   eccbytes, false);
+
+			/*
+			 * ECC data are not byte aligned and we may have
+			 * in-band data in the first and last byte of
+			 * eccbuf. Set non-eccbits to one so that
+			 * nand_check_erased_ecc_chunk() does not count them
+			 * as bitflips.
+			 */
+			if (bitoffset)
+				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
+
+			bitoffset = (bitoffset + eccbits) % 8;
+			if (bitoffset)
+				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
+
+			/*
+			 * The ECC hardware has an uncorrectable ECC status
+			 * code in case we have bitflips in an erased page. As
+			 * nothing was written into this subpage the ECC is
+			 * obviously wrong and we can not trust it. We assume
+			 * at this point that we are reading an erased page and
+			 * try to correct the bitflips in buffer up to
+			 * ecc_strength bitflips. If this is a page with random
+			 * data, we exceed this number of bitflips and have a
+			 * ECC failure. Otherwise we use the corrected buffer.
+			 */
+			if (i == 0) {
+				/* The first block includes metadata */
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						auxiliary_virt,
+						nfc_geo->metadata_size,
+						nfc_geo->ecc_strength);
+			} else {
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						NULL, 0,
+						nfc_geo->ecc_strength);
+			}
+
+			if (flips > 0) {
+				max_bitflips = max_t(unsigned int, max_bitflips,
+						     flips);
+				mtd->ecc_stats.corrected += flips;
+				continue;
+			}
+
+			mtd->ecc_stats.failed++;
+			continue;
+		}
+
+		mtd->ecc_stats.corrected += *status;
+		max_bitflips = max_t(unsigned int, max_bitflips, *status);
+	}
+
+	/* handle the block mark swapping */
+	block_mark_swapping(this, buf, auxiliary_virt);
+
+	if (oob_required) {
+		/*
+		 * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
+		 * for details about our policy for delivering the OOB.
+		 *
+		 * We fill the caller's buffer with set bits, and then copy the
+		 * block mark to th caller's buffer. Note that, if block mark
+		 * swapping was necessary, it has already been done, so we can
+		 * rely on the first byte of the auxiliary buffer to contain
+		 * the block mark.
+		 */
+		memset(chip->oob_poi, ~0, mtd->oobsize);
+		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
+	}
+
+	return max_bitflips;
+}
+
+static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			      uint8_t *buf, int oob_required, int page)
+{
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	return gpmi_ecc_read_page_data(chip, buf, oob_required, page);
+}
+
+/* Fake a virtual small page for the subpage read */
+static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+			uint32_t offs, uint32_t len, uint8_t *buf, int page)
+{
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	void __iomem *bch_regs = this->resources.bch_regs;
+	struct bch_geometry old_geo = this->bch_geometry;
+	struct bch_geometry *geo = &this->bch_geometry;
+	int size = chip->ecc.size; /* ECC chunk size */
+	int meta, n, page_size;
+	u32 r1_old, r2_old, r1_new, r2_new;
+	unsigned int max_bitflips;
+	int first, last, marker_pos;
+	int ecc_parity_size;
+	int col = 0;
+	int old_swap_block_mark = this->swap_block_mark;
+
+	/* The size of ECC parity */
+	ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
+
+	/* Align it with the chunk size */
+	first = offs / size;
+	last = (offs + len - 1) / size;
+
+	if (this->swap_block_mark) {
+		/*
+		 * Find the chunk which contains the Block Marker.
+		 * If this chunk is in the range of [first, last],
+		 * we have to read out the whole page.
+		 * Why? since we had swapped the data at the position of Block
+		 * Marker to the metadata which is bound with the chunk 0.
+		 */
+		marker_pos = geo->block_mark_byte_offset / size;
+		if (last >= marker_pos && first <= marker_pos) {
+			dev_dbg(this->dev,
+				"page:%d, first:%d, last:%d, marker at:%d\n",
+				page, first, last, marker_pos);
+			return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+		}
+	}
+
+	meta = geo->metadata_size;
+	if (first) {
+		col = meta + (size + ecc_parity_size) * first;
+		meta = 0;
+		buf = buf + first * size;
+	}
+
+	nand_read_page_op(chip, page, col, NULL, 0);
+
+	/* Save the old environment */
+	r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
+	r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+	/* change the BCH registers and bch_geometry{} */
+	n = last - first + 1;
+	page_size = meta + (size + ecc_parity_size) * n;
+
+	r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
+			BM_BCH_FLASH0LAYOUT0_META_SIZE);
+	r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
+			| BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
+	writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
+
+	r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
+	r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
+	writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+	geo->ecc_chunk_count = n;
+	geo->payload_size = n * size;
+	geo->page_size = page_size;
+	geo->auxiliary_status_offset = ALIGN(meta, 4);
+
+	dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
+		page, offs, len, col, first, n, page_size);
+
+	/* Read the subpage now */
+	this->swap_block_mark = false;
+	max_bitflips = gpmi_ecc_read_page_data(chip, buf, 0, page);
+
+	/* Restore */
+	writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
+	writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
+	this->bch_geometry = old_geo;
+	this->swap_block_mark = old_swap_block_mark;
+
+	return max_bitflips;
+}
+
+static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+				const uint8_t *buf, int oob_required, int page)
+{
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *nfc_geo = &this->bch_geometry;
+	const void *payload_virt;
+	dma_addr_t payload_phys;
+	const void *auxiliary_virt;
+	dma_addr_t auxiliary_phys;
+	int        ret;
+
+	dev_dbg(this->dev, "ecc write page.\n");
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	if (this->swap_block_mark) {
+		/*
+		 * If control arrives here, we're doing block mark swapping.
+		 * Since we can't modify the caller's buffers, we must copy them
+		 * into our own.
+		 */
+		memcpy(this->payload_virt, buf, mtd->writesize);
+		payload_virt = this->payload_virt;
+		payload_phys = this->payload_phys;
+
+		memcpy(this->auxiliary_virt, chip->oob_poi,
+				nfc_geo->auxiliary_size);
+		auxiliary_virt = this->auxiliary_virt;
+		auxiliary_phys = this->auxiliary_phys;
+
+		/* Handle block mark swapping. */
+		block_mark_swapping(this,
+				(void *)payload_virt, (void *)auxiliary_virt);
+	} else {
+		/*
+		 * If control arrives here, we're not doing block mark swapping,
+		 * so we can to try and use the caller's buffers.
+		 */
+		ret = send_page_prepare(this,
+				buf, mtd->writesize,
+				this->payload_virt, this->payload_phys,
+				nfc_geo->payload_size,
+				&payload_virt, &payload_phys);
+		if (ret) {
+			dev_err(this->dev, "Inadequate payload DMA buffer\n");
+			return 0;
+		}
+
+		ret = send_page_prepare(this,
+				chip->oob_poi, mtd->oobsize,
+				this->auxiliary_virt, this->auxiliary_phys,
+				nfc_geo->auxiliary_size,
+				&auxiliary_virt, &auxiliary_phys);
+		if (ret) {
+			dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
+			goto exit_auxiliary;
+		}
+	}
+
+	/* Ask the NFC. */
+	ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
+	if (ret)
+		dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
+
+	if (!this->swap_block_mark) {
+		send_page_end(this, chip->oob_poi, mtd->oobsize,
+				this->auxiliary_virt, this->auxiliary_phys,
+				nfc_geo->auxiliary_size,
+				auxiliary_virt, auxiliary_phys);
+exit_auxiliary:
+		send_page_end(this, buf, mtd->writesize,
+				this->payload_virt, this->payload_phys,
+				nfc_geo->payload_size,
+				payload_virt, payload_phys);
+	}
+
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(chip);
+}
+
+/*
+ * There are several places in this driver where we have to handle the OOB and
+ * block marks. This is the function where things are the most complicated, so
+ * this is where we try to explain it all. All the other places refer back to
+ * here.
+ *
+ * These are the rules, in order of decreasing importance:
+ *
+ * 1) Nothing the caller does can be allowed to imperil the block mark.
+ *
+ * 2) In read operations, the first byte of the OOB we return must reflect the
+ *    true state of the block mark, no matter where that block mark appears in
+ *    the physical page.
+ *
+ * 3) ECC-based read operations return an OOB full of set bits (since we never
+ *    allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads
+ *    return).
+ *
+ * 4) "Raw" read operations return a direct view of the physical bytes in the
+ *    page, using the conventional definition of which bytes are data and which
+ *    are OOB. This gives the caller a way to see the actual, physical bytes
+ *    in the page, without the distortions applied by our ECC engine.
+ *
+ *
+ * What we do for this specific read operation depends on two questions:
+ *
+ * 1) Are we doing a "raw" read, or an ECC-based read?
+ *
+ * 2) Are we using block mark swapping or transcription?
+ *
+ * There are four cases, illustrated by the following Karnaugh map:
+ *
+ *                    |           Raw           |         ECC-based       |
+ *       -------------+-------------------------+-------------------------+
+ *                    | Read the conventional   |                         |
+ *                    | OOB at the end of the   |                         |
+ *       Swapping     | page and return it. It  |                         |
+ *                    | contains exactly what   |                         |
+ *                    | we want.                | Read the block mark and |
+ *       -------------+-------------------------+ return it in a buffer   |
+ *                    | Read the conventional   | full of set bits.       |
+ *                    | OOB at the end of the   |                         |
+ *                    | page and also the block |                         |
+ *       Transcribing | mark in the metadata.   |                         |
+ *                    | Copy the block mark     |                         |
+ *                    | into the first byte of  |                         |
+ *                    | the OOB.                |                         |
+ *       -------------+-------------------------+-------------------------+
+ *
+ * Note that we break rule #4 in the Transcribing/Raw case because we're not
+ * giving an accurate view of the actual, physical bytes in the page (we're
+ * overwriting the block mark). That's OK because it's more important to follow
+ * rule #2.
+ *
+ * It turns out that knowing whether we want an "ECC-based" or "raw" read is not
+ * easy. When reading a page, for example, the NAND Flash MTD code calls our
+ * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
+ * ECC-based or raw view of the page is implicit in which function it calls
+ * (there is a similar pair of ECC-based/raw functions for writing).
+ */
+static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+				int page)
+{
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+
+	dev_dbg(this->dev, "page number is %d\n", page);
+	/* clear the OOB buffer */
+	memset(chip->oob_poi, ~0, mtd->oobsize);
+
+	/* Read out the conventional OOB. */
+	nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/*
+	 * Now, we want to make sure the block mark is correct. In the
+	 * non-transcribing case (!GPMI_IS_MX23()), we already have it.
+	 * Otherwise, we need to explicitly read it.
+	 */
+	if (GPMI_IS_MX23(this)) {
+		/* Read the block mark into the first byte of the OOB buffer. */
+		nand_read_page_op(chip, page, 0, NULL, 0);
+		chip->oob_poi[0] = chip->read_byte(mtd);
+	}
+
+	return 0;
+}
+
+static int
+gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	struct mtd_oob_region of = { };
+
+	/* Do we have available oob area? */
+	mtd_ooblayout_free(mtd, 0, &of);
+	if (!of.length)
+		return -EPERM;
+
+	if (!nand_is_slc(chip))
+		return -EPERM;
+
+	return nand_prog_page_op(chip, page, mtd->writesize + of.offset,
+				 chip->oob_poi + of.offset, of.length);
+}
+
+/*
+ * This function reads a NAND page without involving the ECC engine (no HW
+ * ECC correction).
+ * The tricky part in the GPMI/BCH controller is that it stores ECC bits
+ * inline (interleaved with payload DATA), and do not align data chunk on
+ * byte boundaries.
+ * We thus need to take care moving the payload data and ECC bits stored in the
+ * page into the provided buffers, which is why we're using gpmi_copy_bits.
+ *
+ * See set_geometry_by_ecc_info inline comments to have a full description
+ * of the layout used by the GPMI controller.
+ */
+static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
+				  struct nand_chip *chip, uint8_t *buf,
+				  int oob_required, int page)
+{
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *nfc_geo = &this->bch_geometry;
+	int eccsize = nfc_geo->ecc_chunk_size;
+	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+	u8 *tmp_buf = this->raw_buffer;
+	size_t src_bit_off;
+	size_t oob_bit_off;
+	size_t oob_byte_off;
+	uint8_t *oob = chip->oob_poi;
+	int step;
+
+	nand_read_page_op(chip, page, 0, tmp_buf,
+			  mtd->writesize + mtd->oobsize);
+
+	/*
+	 * If required, swap the bad block marker and the data stored in the
+	 * metadata section, so that we don't wrongly consider a block as bad.
+	 *
+	 * See the layout description for a detailed explanation on why this
+	 * is needed.
+	 */
+	if (this->swap_block_mark)
+		swap(tmp_buf[0], tmp_buf[mtd->writesize]);
+
+	/*
+	 * Copy the metadata section into the oob buffer (this section is
+	 * guaranteed to be aligned on a byte boundary).
+	 */
+	if (oob_required)
+		memcpy(oob, tmp_buf, nfc_geo->metadata_size);
+
+	oob_bit_off = nfc_geo->metadata_size * 8;
+	src_bit_off = oob_bit_off;
+
+	/* Extract interleaved payload data and ECC bits */
+	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
+		if (buf)
+			gpmi_copy_bits(buf, step * eccsize * 8,
+				       tmp_buf, src_bit_off,
+				       eccsize * 8);
+		src_bit_off += eccsize * 8;
+
+		/* Align last ECC block to align a byte boundary */
+		if (step == nfc_geo->ecc_chunk_count - 1 &&
+		    (oob_bit_off + eccbits) % 8)
+			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
+
+		if (oob_required)
+			gpmi_copy_bits(oob, oob_bit_off,
+				       tmp_buf, src_bit_off,
+				       eccbits);
+
+		src_bit_off += eccbits;
+		oob_bit_off += eccbits;
+	}
+
+	if (oob_required) {
+		oob_byte_off = oob_bit_off / 8;
+
+		if (oob_byte_off < mtd->oobsize)
+			memcpy(oob + oob_byte_off,
+			       tmp_buf + mtd->writesize + oob_byte_off,
+			       mtd->oobsize - oob_byte_off);
+	}
+
+	return 0;
+}
+
+/*
+ * This function writes a NAND page without involving the ECC engine (no HW
+ * ECC generation).
+ * The tricky part in the GPMI/BCH controller is that it stores ECC bits
+ * inline (interleaved with payload DATA), and do not align data chunk on
+ * byte boundaries.
+ * We thus need to take care moving the OOB area at the right place in the
+ * final page, which is why we're using gpmi_copy_bits.
+ *
+ * See set_geometry_by_ecc_info inline comments to have a full description
+ * of the layout used by the GPMI controller.
+ */
+static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
+				   struct nand_chip *chip,
+				   const uint8_t *buf,
+				   int oob_required, int page)
+{
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	struct bch_geometry *nfc_geo = &this->bch_geometry;
+	int eccsize = nfc_geo->ecc_chunk_size;
+	int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+	u8 *tmp_buf = this->raw_buffer;
+	uint8_t *oob = chip->oob_poi;
+	size_t dst_bit_off;
+	size_t oob_bit_off;
+	size_t oob_byte_off;
+	int step;
+
+	/*
+	 * Initialize all bits to 1 in case we don't have a buffer for the
+	 * payload or oob data in order to leave unspecified bits of data
+	 * to their initial state.
+	 */
+	if (!buf || !oob_required)
+		memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize);
+
+	/*
+	 * First copy the metadata section (stored in oob buffer) at the
+	 * beginning of the page, as imposed by the GPMI layout.
+	 */
+	memcpy(tmp_buf, oob, nfc_geo->metadata_size);
+	oob_bit_off = nfc_geo->metadata_size * 8;
+	dst_bit_off = oob_bit_off;
+
+	/* Interleave payload data and ECC bits */
+	for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
+		if (buf)
+			gpmi_copy_bits(tmp_buf, dst_bit_off,
+				       buf, step * eccsize * 8, eccsize * 8);
+		dst_bit_off += eccsize * 8;
+
+		/* Align last ECC block to align a byte boundary */
+		if (step == nfc_geo->ecc_chunk_count - 1 &&
+		    (oob_bit_off + eccbits) % 8)
+			eccbits += 8 - ((oob_bit_off + eccbits) % 8);
+
+		if (oob_required)
+			gpmi_copy_bits(tmp_buf, dst_bit_off,
+				       oob, oob_bit_off, eccbits);
+
+		dst_bit_off += eccbits;
+		oob_bit_off += eccbits;
+	}
+
+	oob_byte_off = oob_bit_off / 8;
+
+	if (oob_required && oob_byte_off < mtd->oobsize)
+		memcpy(tmp_buf + mtd->writesize + oob_byte_off,
+		       oob + oob_byte_off, mtd->oobsize - oob_byte_off);
+
+	/*
+	 * If required, swap the bad block marker and the first byte of the
+	 * metadata section, so that we don't modify the bad block marker.
+	 *
+	 * See the layout description for a detailed explanation on why this
+	 * is needed.
+	 */
+	if (this->swap_block_mark)
+		swap(tmp_buf[0], tmp_buf[mtd->writesize]);
+
+	return nand_prog_page_op(chip, page, 0, tmp_buf,
+				 mtd->writesize + mtd->oobsize);
+}
+
+static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				 int page)
+{
+	return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
+}
+
+static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				 int page)
+{
+	return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
+}
+
+static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct gpmi_nand_data *this = nand_get_controller_data(chip);
+	int ret = 0;
+	uint8_t *block_mark;
+	int column, page, chipnr;
+
+	chipnr = (int)(ofs >> chip->chip_shift);
+	chip->select_chip(mtd, chipnr);
+
+	column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
+
+	/* Write the block mark. */
+	block_mark = this->data_buffer_dma;
+	block_mark[0] = 0; /* bad block marker */
+
+	/* Shift to get page */
+	page = (int)(ofs >> chip->page_shift);
+
+	ret = nand_prog_page_op(chip, page, column, block_mark, 1);
+
+	chip->select_chip(mtd, -1);
+
+	return ret;
+}
+
+static int nand_boot_set_geometry(struct gpmi_nand_data *this)
+{
+	struct boot_rom_geometry *geometry = &this->rom_geometry;
+
+	/*
+	 * Set the boot block stride size.
+	 *
+	 * In principle, we should be reading this from the OTP bits, since
+	 * that's where the ROM is going to get it. In fact, we don't have any
+	 * way to read the OTP bits, so we go with the default and hope for the
+	 * best.
+	 */
+	geometry->stride_size_in_pages = 64;
+
+	/*
+	 * Set the search area stride exponent.
+	 *
+	 * In principle, we should be reading this from the OTP bits, since
+	 * that's where the ROM is going to get it. In fact, we don't have any
+	 * way to read the OTP bits, so we go with the default and hope for the
+	 * best.
+	 */
+	geometry->search_area_stride_exponent = 2;
+	return 0;
+}
+
+static const char  *fingerprint = "STMP";
+static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
+{
+	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
+	struct device *dev = this->dev;
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int search_area_size_in_strides;
+	unsigned int stride;
+	unsigned int page;
+	uint8_t *buffer = chip->data_buf;
+	int saved_chip_number;
+	int found_an_ncb_fingerprint = false;
+
+	/* Compute the number of strides in a search area. */
+	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
+
+	saved_chip_number = this->current_chip;
+	chip->select_chip(mtd, 0);
+
+	/*
+	 * Loop through the first search area, looking for the NCB fingerprint.
+	 */
+	dev_dbg(dev, "Scanning for an NCB fingerprint...\n");
+
+	for (stride = 0; stride < search_area_size_in_strides; stride++) {
+		/* Compute the page addresses. */
+		page = stride * rom_geo->stride_size_in_pages;
+
+		dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page);
+
+		/*
+		 * Read the NCB fingerprint. The fingerprint is four bytes long
+		 * and starts in the 12th byte of the page.
+		 */
+		nand_read_page_op(chip, page, 12, NULL, 0);
+		chip->read_buf(mtd, buffer, strlen(fingerprint));
+
+		/* Look for the fingerprint. */
+		if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
+			found_an_ncb_fingerprint = true;
+			break;
+		}
+
+	}
+
+	chip->select_chip(mtd, saved_chip_number);
+
+	if (found_an_ncb_fingerprint)
+		dev_dbg(dev, "\tFound a fingerprint\n");
+	else
+		dev_dbg(dev, "\tNo fingerprint found\n");
+	return found_an_ncb_fingerprint;
+}
+
+/* Writes a transcription stamp. */
+static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
+{
+	struct device *dev = this->dev;
+	struct boot_rom_geometry *rom_geo = &this->rom_geometry;
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int block_size_in_pages;
+	unsigned int search_area_size_in_strides;
+	unsigned int search_area_size_in_pages;
+	unsigned int search_area_size_in_blocks;
+	unsigned int block;
+	unsigned int stride;
+	unsigned int page;
+	uint8_t      *buffer = chip->data_buf;
+	int saved_chip_number;
+	int status;
+
+	/* Compute the search area geometry. */
+	block_size_in_pages = mtd->erasesize / mtd->writesize;
+	search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
+	search_area_size_in_pages = search_area_size_in_strides *
+					rom_geo->stride_size_in_pages;
+	search_area_size_in_blocks =
+		  (search_area_size_in_pages + (block_size_in_pages - 1)) /
+				    block_size_in_pages;
+
+	dev_dbg(dev, "Search Area Geometry :\n");
+	dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks);
+	dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides);
+	dev_dbg(dev, "\tin Pages  : %u\n", search_area_size_in_pages);
+
+	/* Select chip 0. */
+	saved_chip_number = this->current_chip;
+	chip->select_chip(mtd, 0);
+
+	/* Loop over blocks in the first search area, erasing them. */
+	dev_dbg(dev, "Erasing the search area...\n");
+
+	for (block = 0; block < search_area_size_in_blocks; block++) {
+		/* Erase this block. */
+		dev_dbg(dev, "\tErasing block 0x%x\n", block);
+		status = nand_erase_op(chip, block);
+		if (status)
+			dev_err(dev, "[%s] Erase failed.\n", __func__);
+	}
+
+	/* Write the NCB fingerprint into the page buffer. */
+	memset(buffer, ~0, mtd->writesize);
+	memcpy(buffer + 12, fingerprint, strlen(fingerprint));
+
+	/* Loop through the first search area, writing NCB fingerprints. */
+	dev_dbg(dev, "Writing NCB fingerprints...\n");
+	for (stride = 0; stride < search_area_size_in_strides; stride++) {
+		/* Compute the page addresses. */
+		page = stride * rom_geo->stride_size_in_pages;
+
+		/* Write the first page of the current stride. */
+		dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
+
+		status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
+		if (status)
+			dev_err(dev, "[%s] Write failed.\n", __func__);
+	}
+
+	/* Deselect chip 0. */
+	chip->select_chip(mtd, saved_chip_number);
+	return 0;
+}
+
+static int mx23_boot_init(struct gpmi_nand_data  *this)
+{
+	struct device *dev = this->dev;
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int block_count;
+	unsigned int block;
+	int     chipnr;
+	int     page;
+	loff_t  byte;
+	uint8_t block_mark;
+	int     ret = 0;
+
+	/*
+	 * If control arrives here, we can't use block mark swapping, which
+	 * means we're forced to use transcription. First, scan for the
+	 * transcription stamp. If we find it, then we don't have to do
+	 * anything -- the block marks are already transcribed.
+	 */
+	if (mx23_check_transcription_stamp(this))
+		return 0;
+
+	/*
+	 * If control arrives here, we couldn't find a transcription stamp, so
+	 * so we presume the block marks are in the conventional location.
+	 */
+	dev_dbg(dev, "Transcribing bad block marks...\n");
+
+	/* Compute the number of blocks in the entire medium. */
+	block_count = chip->chipsize >> chip->phys_erase_shift;
+
+	/*
+	 * Loop over all the blocks in the medium, transcribing block marks as
+	 * we go.
+	 */
+	for (block = 0; block < block_count; block++) {
+		/*
+		 * Compute the chip, page and byte addresses for this block's
+		 * conventional mark.
+		 */
+		chipnr = block >> (chip->chip_shift - chip->phys_erase_shift);
+		page = block << (chip->phys_erase_shift - chip->page_shift);
+		byte = block <<  chip->phys_erase_shift;
+
+		/* Send the command to read the conventional block mark. */
+		chip->select_chip(mtd, chipnr);
+		nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
+		block_mark = chip->read_byte(mtd);
+		chip->select_chip(mtd, -1);
+
+		/*
+		 * Check if the block is marked bad. If so, we need to mark it
+		 * again, but this time the result will be a mark in the
+		 * location where we transcribe block marks.
+		 */
+		if (block_mark != 0xff) {
+			dev_dbg(dev, "Transcribing mark in block %u\n", block);
+			ret = chip->block_markbad(mtd, byte);
+			if (ret)
+				dev_err(dev,
+					"Failed to mark block bad with ret %d\n",
+					ret);
+		}
+	}
+
+	/* Write the stamp that indicates we've transcribed the block marks. */
+	mx23_write_transcription_stamp(this);
+	return 0;
+}
+
+static int nand_boot_init(struct gpmi_nand_data  *this)
+{
+	nand_boot_set_geometry(this);
+
+	/* This is ROM arch-specific initilization before the BBT scanning. */
+	if (GPMI_IS_MX23(this))
+		return mx23_boot_init(this);
+	return 0;
+}
+
+static int gpmi_set_geometry(struct gpmi_nand_data *this)
+{
+	int ret;
+
+	/* Free the temporary DMA memory for reading ID. */
+	gpmi_free_dma_buffer(this);
+
+	/* Set up the NFC geometry which is used by BCH. */
+	ret = bch_set_geometry(this);
+	if (ret) {
+		dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
+		return ret;
+	}
+
+	/* Alloc the new DMA buffers according to the pagesize and oobsize */
+	return gpmi_alloc_dma_buffer(this);
+}
+
+static int gpmi_init_last(struct gpmi_nand_data *this)
+{
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct bch_geometry *bch_geo = &this->bch_geometry;
+	int ret;
+
+	/* Set up the medium geometry */
+	ret = gpmi_set_geometry(this);
+	if (ret)
+		return ret;
+
+	/* Init the nand_ecc_ctrl{} */
+	ecc->read_page	= gpmi_ecc_read_page;
+	ecc->write_page	= gpmi_ecc_write_page;
+	ecc->read_oob	= gpmi_ecc_read_oob;
+	ecc->write_oob	= gpmi_ecc_write_oob;
+	ecc->read_page_raw = gpmi_ecc_read_page_raw;
+	ecc->write_page_raw = gpmi_ecc_write_page_raw;
+	ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
+	ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
+	ecc->mode	= NAND_ECC_HW;
+	ecc->size	= bch_geo->ecc_chunk_size;
+	ecc->strength	= bch_geo->ecc_strength;
+	mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
+
+	/*
+	 * We only enable the subpage read when:
+	 *  (1) the chip is imx6, and
+	 *  (2) the size of the ECC parity is byte aligned.
+	 */
+	if (GPMI_IS_MX6(this) &&
+		((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
+		ecc->read_subpage = gpmi_ecc_read_subpage;
+		chip->options |= NAND_SUBPAGE_READ;
+	}
+
+	/*
+	 * Can we enable the extra features? such as EDO or Sync mode.
+	 *
+	 * We do not check the return value now. That's means if we fail in
+	 * enable the extra features, we still can run in the normal way.
+	 */
+	gpmi_extra_init(this);
+
+	return 0;
+}
+
+static int gpmi_nand_init(struct gpmi_nand_data *this)
+{
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info  *mtd = nand_to_mtd(chip);
+	int ret;
+
+	/* init current chip */
+	this->current_chip	= -1;
+
+	/* init the MTD data structures */
+	mtd->name		= "gpmi-nand";
+	mtd->dev.parent		= this->dev;
+
+	/* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */
+	nand_set_controller_data(chip, this);
+	nand_set_flash_node(chip, this->pdev->dev.of_node);
+	chip->select_chip	= gpmi_select_chip;
+	chip->cmd_ctrl		= gpmi_cmd_ctrl;
+	chip->dev_ready		= gpmi_dev_ready;
+	chip->read_byte		= gpmi_read_byte;
+	chip->read_buf		= gpmi_read_buf;
+	chip->write_buf		= gpmi_write_buf;
+	chip->badblock_pattern	= &gpmi_bbt_descr;
+	chip->block_markbad	= gpmi_block_markbad;
+	chip->options		|= NAND_NO_SUBPAGE_WRITE;
+
+	/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
+	this->swap_block_mark = !GPMI_IS_MX23(this);
+
+	/*
+	 * Allocate a temporary DMA buffer for reading ID in the
+	 * nand_scan_ident().
+	 */
+	this->bch_geometry.payload_size = 1024;
+	this->bch_geometry.auxiliary_size = 128;
+	ret = gpmi_alloc_dma_buffer(this);
+	if (ret)
+		goto err_out;
+
+	ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
+	if (ret)
+		goto err_out;
+
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+		chip->bbt_options |= NAND_BBT_NO_OOB;
+
+		if (of_property_read_bool(this->dev->of_node,
+						"fsl,no-blockmark-swap"))
+			this->swap_block_mark = false;
+	}
+	dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+		this->swap_block_mark ? "en" : "dis");
+
+	ret = gpmi_init_last(this);
+	if (ret)
+		goto err_out;
+
+	chip->options |= NAND_SKIP_BBTSCAN;
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		goto err_out;
+
+	ret = nand_boot_init(this);
+	if (ret)
+		goto err_nand_cleanup;
+	ret = chip->scan_bbt(mtd);
+	if (ret)
+		goto err_nand_cleanup;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret)
+		goto err_nand_cleanup;
+	return 0;
+
+err_nand_cleanup:
+	nand_cleanup(chip);
+err_out:
+	gpmi_free_dma_buffer(this);
+	return ret;
+}
+
+static const struct of_device_id gpmi_nand_id_table[] = {
+	{
+		.compatible = "fsl,imx23-gpmi-nand",
+		.data = &gpmi_devdata_imx23,
+	}, {
+		.compatible = "fsl,imx28-gpmi-nand",
+		.data = &gpmi_devdata_imx28,
+	}, {
+		.compatible = "fsl,imx6q-gpmi-nand",
+		.data = &gpmi_devdata_imx6q,
+	}, {
+		.compatible = "fsl,imx6sx-gpmi-nand",
+		.data = &gpmi_devdata_imx6sx,
+	}, {
+		.compatible = "fsl,imx7d-gpmi-nand",
+		.data = &gpmi_devdata_imx7d,
+	}, {}
+};
+MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
+
+static int gpmi_nand_probe(struct platform_device *pdev)
+{
+	struct gpmi_nand_data *this;
+	const struct of_device_id *of_id;
+	int ret;
+
+	this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
+	if (!this)
+		return -ENOMEM;
+
+	of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
+	if (of_id) {
+		this->devdata = of_id->data;
+	} else {
+		dev_err(&pdev->dev, "Failed to find the right device id.\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, this);
+	this->pdev  = pdev;
+	this->dev   = &pdev->dev;
+
+	ret = acquire_resources(this);
+	if (ret)
+		goto exit_acquire_resources;
+
+	ret = init_hardware(this);
+	if (ret)
+		goto exit_nfc_init;
+
+	ret = gpmi_nand_init(this);
+	if (ret)
+		goto exit_nfc_init;
+
+	dev_info(this->dev, "driver registered.\n");
+
+	return 0;
+
+exit_nfc_init:
+	release_resources(this);
+exit_acquire_resources:
+
+	return ret;
+}
+
+static int gpmi_nand_remove(struct platform_device *pdev)
+{
+	struct gpmi_nand_data *this = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&this->nand));
+	gpmi_free_dma_buffer(this);
+	release_resources(this);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int gpmi_pm_suspend(struct device *dev)
+{
+	struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+	release_dma_channels(this);
+	return 0;
+}
+
+static int gpmi_pm_resume(struct device *dev)
+{
+	struct gpmi_nand_data *this = dev_get_drvdata(dev);
+	int ret;
+
+	ret = acquire_dma_channels(this);
+	if (ret < 0)
+		return ret;
+
+	/* re-init the GPMI registers */
+	this->flags &= ~GPMI_TIMING_INIT_OK;
+	ret = gpmi_init(this);
+	if (ret) {
+		dev_err(this->dev, "Error setting GPMI : %d\n", ret);
+		return ret;
+	}
+
+	/* re-init the BCH registers */
+	ret = bch_set_geometry(this);
+	if (ret) {
+		dev_err(this->dev, "Error setting BCH : %d\n", ret);
+		return ret;
+	}
+
+	/* re-init others */
+	gpmi_extra_init(this);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops gpmi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
+};
+
+static struct platform_driver gpmi_nand_driver = {
+	.driver = {
+		.name = "gpmi-nand",
+		.pm = &gpmi_pm_ops,
+		.of_match_table = gpmi_nand_id_table,
+	},
+	.probe   = gpmi_nand_probe,
+	.remove  = gpmi_nand_remove,
+};
+module_platform_driver(gpmi_nand_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
new file mode 100644
index 000000000000..06c1f993912c
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
@@ -0,0 +1,315 @@
+/*
+ * Freescale GPMI NAND Flash Driver
+ *
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
+#define __DRIVERS_MTD_NAND_GPMI_NAND_H
+
+#include <linux/mtd/rawnand.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+
+#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
+struct resources {
+	void __iomem  *gpmi_regs;
+	void __iomem  *bch_regs;
+	unsigned int  dma_low_channel;
+	unsigned int  dma_high_channel;
+	struct clk    *clock[GPMI_CLK_MAX];
+};
+
+/**
+ * struct bch_geometry - BCH geometry description.
+ * @gf_len:                   The length of Galois Field. (e.g., 13 or 14)
+ * @ecc_strength:             A number that describes the strength of the ECC
+ *                            algorithm.
+ * @page_size:                The size, in bytes, of a physical page, including
+ *                            both data and OOB.
+ * @metadata_size:            The size, in bytes, of the metadata.
+ * @ecc_chunk_size:           The size, in bytes, of a single ECC chunk. Note
+ *                            the first chunk in the page includes both data and
+ *                            metadata, so it's a bit larger than this value.
+ * @ecc_chunk_count:          The number of ECC chunks in the page,
+ * @payload_size:             The size, in bytes, of the payload buffer.
+ * @auxiliary_size:           The size, in bytes, of the auxiliary buffer.
+ * @auxiliary_status_offset:  The offset into the auxiliary buffer at which
+ *                            the ECC status appears.
+ * @block_mark_byte_offset:   The byte offset in the ECC-based page view at
+ *                            which the underlying physical block mark appears.
+ * @block_mark_bit_offset:    The bit offset into the ECC-based page view at
+ *                            which the underlying physical block mark appears.
+ */
+struct bch_geometry {
+	unsigned int  gf_len;
+	unsigned int  ecc_strength;
+	unsigned int  page_size;
+	unsigned int  metadata_size;
+	unsigned int  ecc_chunk_size;
+	unsigned int  ecc_chunk_count;
+	unsigned int  payload_size;
+	unsigned int  auxiliary_size;
+	unsigned int  auxiliary_status_offset;
+	unsigned int  block_mark_byte_offset;
+	unsigned int  block_mark_bit_offset;
+};
+
+/**
+ * struct boot_rom_geometry - Boot ROM geometry description.
+ * @stride_size_in_pages:        The size of a boot block stride, in pages.
+ * @search_area_stride_exponent: The logarithm to base 2 of the size of a
+ *                               search area in boot block strides.
+ */
+struct boot_rom_geometry {
+	unsigned int  stride_size_in_pages;
+	unsigned int  search_area_stride_exponent;
+};
+
+/* DMA operations types */
+enum dma_ops_type {
+	DMA_FOR_COMMAND = 1,
+	DMA_FOR_READ_DATA,
+	DMA_FOR_WRITE_DATA,
+	DMA_FOR_READ_ECC_PAGE,
+	DMA_FOR_WRITE_ECC_PAGE
+};
+
+/**
+ * struct nand_timing - Fundamental timing attributes for NAND.
+ * @data_setup_in_ns:         The data setup time, in nanoseconds. Usually the
+ *                            maximum of tDS and tWP. A negative value
+ *                            indicates this characteristic isn't known.
+ * @data_hold_in_ns:          The data hold time, in nanoseconds. Usually the
+ *                            maximum of tDH, tWH and tREH. A negative value
+ *                            indicates this characteristic isn't known.
+ * @address_setup_in_ns:      The address setup time, in nanoseconds. Usually
+ *                            the maximum of tCLS, tCS and tALS. A negative
+ *                            value indicates this characteristic isn't known.
+ * @gpmi_sample_delay_in_ns:  A GPMI-specific timing parameter. A negative value
+ *                            indicates this characteristic isn't known.
+ * @tREA_in_ns:               tREA, in nanoseconds, from the data sheet. A
+ *                            negative value indicates this characteristic isn't
+ *                            known.
+ * @tRLOH_in_ns:              tRLOH, in nanoseconds, from the data sheet. A
+ *                            negative value indicates this characteristic isn't
+ *                            known.
+ * @tRHOH_in_ns:              tRHOH, in nanoseconds, from the data sheet. A
+ *                            negative value indicates this characteristic isn't
+ *                            known.
+ */
+struct nand_timing {
+	int8_t  data_setup_in_ns;
+	int8_t  data_hold_in_ns;
+	int8_t  address_setup_in_ns;
+	int8_t  gpmi_sample_delay_in_ns;
+	int8_t  tREA_in_ns;
+	int8_t  tRLOH_in_ns;
+	int8_t  tRHOH_in_ns;
+};
+
+enum gpmi_type {
+	IS_MX23,
+	IS_MX28,
+	IS_MX6Q,
+	IS_MX6SX,
+	IS_MX7D,
+};
+
+struct gpmi_devdata {
+	enum gpmi_type type;
+	int bch_max_ecc_strength;
+	int max_chain_delay; /* See the async EDO mode */
+	const char * const *clks;
+	const int clks_count;
+};
+
+struct gpmi_nand_data {
+	/* flags */
+#define GPMI_ASYNC_EDO_ENABLED	(1 << 0)
+#define GPMI_TIMING_INIT_OK	(1 << 1)
+	int			flags;
+	const struct gpmi_devdata *devdata;
+
+	/* System Interface */
+	struct device		*dev;
+	struct platform_device	*pdev;
+
+	/* Resources */
+	struct resources	resources;
+
+	/* Flash Hardware */
+	struct nand_timing	timing;
+	int			timing_mode;
+
+	/* BCH */
+	struct bch_geometry	bch_geometry;
+	struct completion	bch_done;
+
+	/* NAND Boot issue */
+	bool			swap_block_mark;
+	struct boot_rom_geometry rom_geometry;
+
+	/* MTD / NAND */
+	struct nand_chip	nand;
+
+	/* General-use Variables */
+	int			current_chip;
+	unsigned int		command_length;
+
+	/* passed from upper layer */
+	uint8_t			*upper_buf;
+	int			upper_len;
+
+	/* for DMA operations */
+	bool			direct_dma_map_ok;
+
+	struct scatterlist	cmd_sgl;
+	char			*cmd_buffer;
+
+	struct scatterlist	data_sgl;
+	char			*data_buffer_dma;
+
+	void			*page_buffer_virt;
+	dma_addr_t		page_buffer_phys;
+	unsigned int		page_buffer_size;
+
+	void			*payload_virt;
+	dma_addr_t		payload_phys;
+
+	void			*auxiliary_virt;
+	dma_addr_t		auxiliary_phys;
+
+	void			*raw_buffer;
+
+	/* DMA channels */
+#define DMA_CHANS		8
+	struct dma_chan		*dma_chans[DMA_CHANS];
+	enum dma_ops_type	last_dma_type;
+	enum dma_ops_type	dma_type;
+	struct completion	dma_done;
+
+	/* private */
+	void			*private;
+};
+
+/**
+ * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
+ * @data_setup_in_cycles:      The data setup time, in cycles.
+ * @data_hold_in_cycles:       The data hold time, in cycles.
+ * @address_setup_in_cycles:   The address setup time, in cycles.
+ * @device_busy_timeout:       The timeout waiting for NAND Ready/Busy,
+ *                             this value is the number of cycles multiplied
+ *                             by 4096.
+ * @use_half_periods:          Indicates the clock is running slowly, so the
+ *                             NFC DLL should use half-periods.
+ * @sample_delay_factor:       The sample delay factor.
+ * @wrn_dly_sel:               The delay on the GPMI write strobe.
+ */
+struct gpmi_nfc_hardware_timing {
+	/* for HW_GPMI_TIMING0 */
+	uint8_t  data_setup_in_cycles;
+	uint8_t  data_hold_in_cycles;
+	uint8_t  address_setup_in_cycles;
+
+	/* for HW_GPMI_TIMING1 */
+	uint16_t device_busy_timeout;
+#define GPMI_DEFAULT_BUSY_TIMEOUT	0x500 /* default busy timeout value.*/
+
+	/* for HW_GPMI_CTRL1 */
+	bool     use_half_periods;
+	uint8_t  sample_delay_factor;
+	uint8_t  wrn_dly_sel;
+};
+
+/**
+ * struct timing_threshold - Timing threshold
+ * @max_data_setup_cycles:       The maximum number of data setup cycles that
+ *                               can be expressed in the hardware.
+ * @internal_data_setup_in_ns:   The time, in ns, that the NFC hardware requires
+ *                               for data read internal setup. In the Reference
+ *                               Manual, see the chapter "High-Speed NAND
+ *                               Timing" for more details.
+ * @max_sample_delay_factor:     The maximum sample delay factor that can be
+ *                               expressed in the hardware.
+ * @max_dll_clock_period_in_ns:  The maximum period of the GPMI clock that the
+ *                               sample delay DLL hardware can possibly work
+ *                               with (the DLL is unusable with longer periods).
+ *                               If the full-cycle period is greater than HALF
+ *                               this value, the DLL must be configured to use
+ *                               half-periods.
+ * @max_dll_delay_in_ns:         The maximum amount of delay, in ns, that the
+ *                               DLL can implement.
+ * @clock_frequency_in_hz:       The clock frequency, in Hz, during the current
+ *                               I/O transaction. If no I/O transaction is in
+ *                               progress, this is the clock frequency during
+ *                               the most recent I/O transaction.
+ */
+struct timing_threshold {
+	const unsigned int      max_chip_count;
+	const unsigned int      max_data_setup_cycles;
+	const unsigned int      internal_data_setup_in_ns;
+	const unsigned int      max_sample_delay_factor;
+	const unsigned int      max_dll_clock_period_in_ns;
+	const unsigned int      max_dll_delay_in_ns;
+	unsigned long           clock_frequency_in_hz;
+
+};
+
+/* Common Services */
+int common_nfc_set_geometry(struct gpmi_nand_data *);
+struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
+void prepare_data_dma(struct gpmi_nand_data *,
+		      enum dma_data_direction dr);
+int start_dma_without_bch_irq(struct gpmi_nand_data *,
+			      struct dma_async_tx_descriptor *);
+int start_dma_with_bch_irq(struct gpmi_nand_data *,
+			   struct dma_async_tx_descriptor *);
+
+/* GPMI-NAND helper function library */
+int gpmi_init(struct gpmi_nand_data *);
+int gpmi_extra_init(struct gpmi_nand_data *);
+void gpmi_clear_bch(struct gpmi_nand_data *);
+void gpmi_dump_info(struct gpmi_nand_data *);
+int bch_set_geometry(struct gpmi_nand_data *);
+int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
+int gpmi_send_command(struct gpmi_nand_data *);
+void gpmi_begin(struct gpmi_nand_data *);
+void gpmi_end(struct gpmi_nand_data *);
+int gpmi_read_data(struct gpmi_nand_data *);
+int gpmi_send_data(struct gpmi_nand_data *);
+int gpmi_send_page(struct gpmi_nand_data *,
+		   dma_addr_t payload, dma_addr_t auxiliary);
+int gpmi_read_page(struct gpmi_nand_data *,
+		   dma_addr_t payload, dma_addr_t auxiliary);
+
+void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
+		    const u8 *src, size_t src_bit_off,
+		    size_t nbits);
+
+/* BCH : Status Block Completion Codes */
+#define STATUS_GOOD		0x00
+#define STATUS_ERASED		0xff
+#define STATUS_UNCORRECTABLE	0xfe
+
+/* Use the devdata to distinguish different Archs. */
+#define GPMI_IS_MX23(x)		((x)->devdata->type == IS_MX23)
+#define GPMI_IS_MX28(x)		((x)->devdata->type == IS_MX28)
+#define GPMI_IS_MX6Q(x)		((x)->devdata->type == IS_MX6Q)
+#define GPMI_IS_MX6SX(x)	((x)->devdata->type == IS_MX6SX)
+#define GPMI_IS_MX7D(x)		((x)->devdata->type == IS_MX7D)
+
+#define GPMI_IS_MX6(x)		(GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \
+				 GPMI_IS_MX7D(x))
+#endif
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
new file mode 100644
index 000000000000..82114cdc8330
--- /dev/null
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-regs.h
@@ -0,0 +1,187 @@
+/*
+ * Freescale GPMI NAND Flash Driver
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef __GPMI_NAND_GPMI_REGS_H
+#define __GPMI_NAND_GPMI_REGS_H
+
+#define HW_GPMI_CTRL0					0x00000000
+#define HW_GPMI_CTRL0_SET				0x00000004
+#define HW_GPMI_CTRL0_CLR				0x00000008
+#define HW_GPMI_CTRL0_TOG				0x0000000c
+
+#define BP_GPMI_CTRL0_COMMAND_MODE			24
+#define BM_GPMI_CTRL0_COMMAND_MODE	(3 << BP_GPMI_CTRL0_COMMAND_MODE)
+#define BF_GPMI_CTRL0_COMMAND_MODE(v)	\
+	(((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE)
+#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE		0x0
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ		0x1
+#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE	0x2
+#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY	0x3
+
+#define BM_GPMI_CTRL0_WORD_LENGTH			(1 << 23)
+#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT		0x0
+#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT		0x1
+
+/*
+ *  Difference in LOCK_CS between imx23 and imx28 :
+ *  This bit may impact the _POWER_ consumption. So some chips
+ *  do not set it.
+ */
+#define MX23_BP_GPMI_CTRL0_LOCK_CS			22
+#define MX28_BP_GPMI_CTRL0_LOCK_CS			27
+#define LOCK_CS_ENABLE					0x1
+#define BF_GPMI_CTRL0_LOCK_CS(v, x)			0x0
+
+/* Difference in CS between imx23 and imx28 */
+#define BP_GPMI_CTRL0_CS				20
+#define MX23_BM_GPMI_CTRL0_CS		(3 << BP_GPMI_CTRL0_CS)
+#define MX28_BM_GPMI_CTRL0_CS		(7 << BP_GPMI_CTRL0_CS)
+#define BF_GPMI_CTRL0_CS(v, x)		(((v) << BP_GPMI_CTRL0_CS) & \
+						(GPMI_IS_MX23((x)) \
+						? MX23_BM_GPMI_CTRL0_CS	\
+						: MX28_BM_GPMI_CTRL0_CS))
+
+#define BP_GPMI_CTRL0_ADDRESS				17
+#define BM_GPMI_CTRL0_ADDRESS		(3 << BP_GPMI_CTRL0_ADDRESS)
+#define BF_GPMI_CTRL0_ADDRESS(v)	\
+		(((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS)
+#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA		0x0
+#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE			0x1
+#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE			0x2
+
+#define BM_GPMI_CTRL0_ADDRESS_INCREMENT			(1 << 16)
+#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED	0x0
+#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED	0x1
+
+#define BP_GPMI_CTRL0_XFER_COUNT			0
+#define BM_GPMI_CTRL0_XFER_COUNT	(0xffff << BP_GPMI_CTRL0_XFER_COUNT)
+#define BF_GPMI_CTRL0_XFER_COUNT(v)	\
+		(((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT)
+
+#define HW_GPMI_COMPARE					0x00000010
+
+#define HW_GPMI_ECCCTRL					0x00000020
+#define HW_GPMI_ECCCTRL_SET				0x00000024
+#define HW_GPMI_ECCCTRL_CLR				0x00000028
+#define HW_GPMI_ECCCTRL_TOG				0x0000002c
+
+#define BP_GPMI_ECCCTRL_ECC_CMD				13
+#define BM_GPMI_ECCCTRL_ECC_CMD		(3 << BP_GPMI_ECCCTRL_ECC_CMD)
+#define BF_GPMI_ECCCTRL_ECC_CMD(v)	\
+		(((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD)
+#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE		0x0
+#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE		0x1
+
+#define BM_GPMI_ECCCTRL_ENABLE_ECC			(1 << 12)
+#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE		0x1
+#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE		0x0
+
+#define BP_GPMI_ECCCTRL_BUFFER_MASK			0
+#define BM_GPMI_ECCCTRL_BUFFER_MASK	(0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK)
+#define BF_GPMI_ECCCTRL_BUFFER_MASK(v)	\
+	(((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK)
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY	0x100
+#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE		0x1FF
+
+#define HW_GPMI_ECCCOUNT				0x00000030
+#define HW_GPMI_PAYLOAD					0x00000040
+#define HW_GPMI_AUXILIARY				0x00000050
+#define HW_GPMI_CTRL1					0x00000060
+#define HW_GPMI_CTRL1_SET				0x00000064
+#define HW_GPMI_CTRL1_CLR				0x00000068
+#define HW_GPMI_CTRL1_TOG				0x0000006c
+
+#define BP_GPMI_CTRL1_DECOUPLE_CS			24
+#define BM_GPMI_CTRL1_DECOUPLE_CS	(1 << BP_GPMI_CTRL1_DECOUPLE_CS)
+
+#define BP_GPMI_CTRL1_WRN_DLY_SEL			22
+#define BM_GPMI_CTRL1_WRN_DLY_SEL	(0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
+#define BF_GPMI_CTRL1_WRN_DLY_SEL(v)  \
+	(((v) << BP_GPMI_CTRL1_WRN_DLY_SEL) & BM_GPMI_CTRL1_WRN_DLY_SEL)
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS		0x0
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS		0x1
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS		0x2
+#define BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY		0x3
+
+#define BM_GPMI_CTRL1_BCH_MODE				(1 << 18)
+
+#define BP_GPMI_CTRL1_DLL_ENABLE			17
+#define BM_GPMI_CTRL1_DLL_ENABLE	(1 << BP_GPMI_CTRL1_DLL_ENABLE)
+
+#define BP_GPMI_CTRL1_HALF_PERIOD			16
+#define BM_GPMI_CTRL1_HALF_PERIOD	(1 << BP_GPMI_CTRL1_HALF_PERIOD)
+
+#define BP_GPMI_CTRL1_RDN_DELAY				12
+#define BM_GPMI_CTRL1_RDN_DELAY		(0xf << BP_GPMI_CTRL1_RDN_DELAY)
+#define BF_GPMI_CTRL1_RDN_DELAY(v)	\
+		(((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY)
+
+#define BM_GPMI_CTRL1_DEV_RESET				(1 << 3)
+#define BV_GPMI_CTRL1_DEV_RESET__ENABLED		0x0
+#define BV_GPMI_CTRL1_DEV_RESET__DISABLED		0x1
+
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY		(1 << 2)
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW	0x0
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH	0x1
+
+#define BM_GPMI_CTRL1_CAMERA_MODE			(1 << 1)
+#define BV_GPMI_CTRL1_GPMI_MODE__NAND			0x0
+#define BV_GPMI_CTRL1_GPMI_MODE__ATA			0x1
+
+#define BM_GPMI_CTRL1_GPMI_MODE				(1 << 0)
+
+#define HW_GPMI_TIMING0					0x00000070
+
+#define BP_GPMI_TIMING0_ADDRESS_SETUP			16
+#define BM_GPMI_TIMING0_ADDRESS_SETUP	(0xff << BP_GPMI_TIMING0_ADDRESS_SETUP)
+#define BF_GPMI_TIMING0_ADDRESS_SETUP(v)	\
+	(((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP)
+
+#define BP_GPMI_TIMING0_DATA_HOLD			8
+#define BM_GPMI_TIMING0_DATA_HOLD	(0xff << BP_GPMI_TIMING0_DATA_HOLD)
+#define BF_GPMI_TIMING0_DATA_HOLD(v)		\
+	(((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD)
+
+#define BP_GPMI_TIMING0_DATA_SETUP			0
+#define BM_GPMI_TIMING0_DATA_SETUP	(0xff << BP_GPMI_TIMING0_DATA_SETUP)
+#define BF_GPMI_TIMING0_DATA_SETUP(v)		\
+	(((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP)
+
+#define HW_GPMI_TIMING1					0x00000080
+#define BP_GPMI_TIMING1_BUSY_TIMEOUT			16
+#define BM_GPMI_TIMING1_BUSY_TIMEOUT	(0xffff << BP_GPMI_TIMING1_BUSY_TIMEOUT)
+#define BF_GPMI_TIMING1_BUSY_TIMEOUT(v)		\
+	(((v) << BP_GPMI_TIMING1_BUSY_TIMEOUT) & BM_GPMI_TIMING1_BUSY_TIMEOUT)
+
+#define HW_GPMI_TIMING2					0x00000090
+#define HW_GPMI_DATA					0x000000a0
+
+/* MX28 uses this to detect READY. */
+#define HW_GPMI_STAT					0x000000b0
+#define MX28_BP_GPMI_STAT_READY_BUSY			24
+#define MX28_BM_GPMI_STAT_READY_BUSY	(0xff << MX28_BP_GPMI_STAT_READY_BUSY)
+#define MX28_BF_GPMI_STAT_READY_BUSY(v)		\
+	(((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY)
+
+/* MX23 uses this to detect READY. */
+#define HW_GPMI_DEBUG					0x000000c0
+#define MX23_BP_GPMI_DEBUG_READY0			28
+#define MX23_BM_GPMI_DEBUG_READY0	(1 << MX23_BP_GPMI_DEBUG_READY0)
+#endif
diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
new file mode 100644
index 000000000000..cb862793ab6d
--- /dev/null
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -0,0 +1,896 @@
+/*
+ * Hisilicon NAND Flash controller driver
+ *
+ * Copyright © 2012-2014 HiSilicon Technologies Co., Ltd.
+ *              http://www.hisilicon.com
+ *
+ * Author: Zhou Wang <wangzhou.bry@gmail.com>
+ * The initial developer of the original code is Zhiyong Cai
+ * <caizhiyong@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sizes.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+
+#define HINFC504_MAX_CHIP                               (4)
+#define HINFC504_W_LATCH                                (5)
+#define HINFC504_R_LATCH                                (7)
+#define HINFC504_RW_LATCH                               (3)
+
+#define HINFC504_NFC_TIMEOUT				(2 * HZ)
+#define HINFC504_NFC_PM_TIMEOUT				(1 * HZ)
+#define HINFC504_NFC_DMA_TIMEOUT			(5 * HZ)
+#define HINFC504_CHIP_DELAY				(25)
+
+#define HINFC504_REG_BASE_ADDRESS_LEN			(0x100)
+#define HINFC504_BUFFER_BASE_ADDRESS_LEN		(2048 + 128)
+
+#define HINFC504_ADDR_CYCLE_MASK			0x4
+
+#define HINFC504_CON					0x00
+#define HINFC504_CON_OP_MODE_NORMAL			BIT(0)
+#define HINFC504_CON_PAGEISZE_SHIFT			(1)
+#define HINFC504_CON_PAGESIZE_MASK			(0x07)
+#define HINFC504_CON_BUS_WIDTH				BIT(4)
+#define HINFC504_CON_READY_BUSY_SEL			BIT(8)
+#define HINFC504_CON_ECCTYPE_SHIFT			(9)
+#define HINFC504_CON_ECCTYPE_MASK			(0x07)
+
+#define HINFC504_PWIDTH					0x04
+#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
+	((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
+
+#define HINFC504_CMD					0x0C
+#define HINFC504_ADDRL					0x10
+#define HINFC504_ADDRH					0x14
+#define HINFC504_DATA_NUM				0x18
+
+#define HINFC504_OP					0x1C
+#define HINFC504_OP_READ_DATA_EN			BIT(1)
+#define HINFC504_OP_WAIT_READY_EN			BIT(2)
+#define HINFC504_OP_CMD2_EN				BIT(3)
+#define HINFC504_OP_WRITE_DATA_EN			BIT(4)
+#define HINFC504_OP_ADDR_EN				BIT(5)
+#define HINFC504_OP_CMD1_EN				BIT(6)
+#define HINFC504_OP_NF_CS_SHIFT                         (7)
+#define HINFC504_OP_NF_CS_MASK				(3)
+#define HINFC504_OP_ADDR_CYCLE_SHIFT			(9)
+#define HINFC504_OP_ADDR_CYCLE_MASK			(7)
+
+#define HINFC504_STATUS                                 0x20
+#define HINFC504_READY					BIT(0)
+
+#define HINFC504_INTEN					0x24
+#define HINFC504_INTEN_DMA				BIT(9)
+#define HINFC504_INTEN_UE				BIT(6)
+#define HINFC504_INTEN_CE				BIT(5)
+
+#define HINFC504_INTS					0x28
+#define HINFC504_INTS_DMA				BIT(9)
+#define HINFC504_INTS_UE				BIT(6)
+#define HINFC504_INTS_CE				BIT(5)
+
+#define HINFC504_INTCLR                                 0x2C
+#define HINFC504_INTCLR_DMA				BIT(9)
+#define HINFC504_INTCLR_UE				BIT(6)
+#define HINFC504_INTCLR_CE				BIT(5)
+
+#define HINFC504_ECC_STATUS                             0x5C
+#define HINFC504_ECC_16_BIT_SHIFT                       12
+
+#define HINFC504_DMA_CTRL				0x60
+#define HINFC504_DMA_CTRL_DMA_START			BIT(0)
+#define HINFC504_DMA_CTRL_WE				BIT(1)
+#define HINFC504_DMA_CTRL_DATA_AREA_EN			BIT(2)
+#define HINFC504_DMA_CTRL_OOB_AREA_EN			BIT(3)
+#define HINFC504_DMA_CTRL_BURST4_EN			BIT(4)
+#define HINFC504_DMA_CTRL_BURST8_EN			BIT(5)
+#define HINFC504_DMA_CTRL_BURST16_EN			BIT(6)
+#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT		(7)
+#define HINFC504_DMA_CTRL_ADDR_NUM_MASK                 (1)
+#define HINFC504_DMA_CTRL_CS_SHIFT			(8)
+#define HINFC504_DMA_CTRL_CS_MASK			(0x03)
+
+#define HINFC504_DMA_ADDR_DATA				0x64
+#define HINFC504_DMA_ADDR_OOB				0x68
+
+#define HINFC504_DMA_LEN				0x6C
+#define HINFC504_DMA_LEN_OOB_SHIFT			(16)
+#define HINFC504_DMA_LEN_OOB_MASK			(0xFFF)
+
+#define HINFC504_DMA_PARA				0x70
+#define HINFC504_DMA_PARA_DATA_RW_EN			BIT(0)
+#define HINFC504_DMA_PARA_OOB_RW_EN			BIT(1)
+#define HINFC504_DMA_PARA_DATA_EDC_EN			BIT(2)
+#define HINFC504_DMA_PARA_OOB_EDC_EN			BIT(3)
+#define HINFC504_DMA_PARA_DATA_ECC_EN			BIT(4)
+#define HINFC504_DMA_PARA_OOB_ECC_EN			BIT(5)
+
+#define HINFC_VERSION                                   0x74
+#define HINFC504_LOG_READ_ADDR				0x7C
+#define HINFC504_LOG_READ_LEN				0x80
+
+#define HINFC504_NANDINFO_LEN				0x10
+
+struct hinfc_host {
+	struct nand_chip	chip;
+	struct device		*dev;
+	void __iomem		*iobase;
+	void __iomem		*mmio;
+	struct completion       cmd_complete;
+	unsigned int		offset;
+	unsigned int		command;
+	int			chipselect;
+	unsigned int		addr_cycle;
+	u32                     addr_value[2];
+	u32                     cache_addr_value[2];
+	char			*buffer;
+	dma_addr_t		dma_buffer;
+	dma_addr_t		dma_oob;
+	int			version;
+	unsigned int            irq_status; /* interrupt status */
+};
+
+static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
+{
+	return readl(host->iobase + reg);
+}
+
+static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
+			       unsigned int reg)
+{
+	writel(value, host->iobase + reg);
+}
+
+static void wait_controller_finished(struct hinfc_host *host)
+{
+	unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
+	int val;
+
+	while (time_before(jiffies, timeout)) {
+		val = hinfc_read(host, HINFC504_STATUS);
+		if (host->command == NAND_CMD_ERASE2) {
+			/* nfc is ready */
+			while (!(val & HINFC504_READY))	{
+				usleep_range(500, 1000);
+				val = hinfc_read(host, HINFC504_STATUS);
+			}
+			return;
+		}
+
+		if (val & HINFC504_READY)
+			return;
+	}
+
+	/* wait cmd timeout */
+	dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
+}
+
+static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info	*mtd = nand_to_mtd(chip);
+	unsigned long val;
+	int ret;
+
+	hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
+	hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
+
+	if (chip->ecc.mode == NAND_ECC_NONE) {
+		hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
+			<< HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
+
+		hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
+			| HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
+	} else {
+		if (host->command == NAND_CMD_READOOB)
+			hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
+			| HINFC504_DMA_PARA_OOB_EDC_EN
+			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
+		else
+			hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
+			| HINFC504_DMA_PARA_OOB_RW_EN
+			| HINFC504_DMA_PARA_DATA_EDC_EN
+			| HINFC504_DMA_PARA_OOB_EDC_EN
+			| HINFC504_DMA_PARA_DATA_ECC_EN
+			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
+
+	}
+
+	val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
+		| HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
+		| HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
+		| ((host->addr_cycle == 4 ? 1 : 0)
+			<< HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
+		| ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
+			<< HINFC504_DMA_CTRL_CS_SHIFT));
+
+	if (todev)
+		val |= HINFC504_DMA_CTRL_WE;
+
+	init_completion(&host->cmd_complete);
+
+	hinfc_write(host, val, HINFC504_DMA_CTRL);
+	ret = wait_for_completion_timeout(&host->cmd_complete,
+			HINFC504_NFC_DMA_TIMEOUT);
+
+	if (!ret) {
+		dev_err(host->dev, "DMA operation(irq) timeout!\n");
+		/* sanity check */
+		val = hinfc_read(host, HINFC504_DMA_CTRL);
+		if (!(val & HINFC504_DMA_CTRL_DMA_START))
+			dev_err(host->dev, "DMA is already done but without irq ACK!\n");
+		else
+			dev_err(host->dev, "DMA is really timeout!\n");
+	}
+}
+
+static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
+{
+	host->addr_value[0] &= 0xffff0000;
+
+	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
+	hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
+		    HINFC504_CMD);
+
+	hisi_nfc_dma_transfer(host, 1);
+
+	return 0;
+}
+
+static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
+{
+	struct mtd_info	*mtd = nand_to_mtd(&host->chip);
+
+	if ((host->addr_value[0] == host->cache_addr_value[0]) &&
+	    (host->addr_value[1] == host->cache_addr_value[1]))
+		return 0;
+
+	host->addr_value[0] &= 0xffff0000;
+
+	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+	hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
+	hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
+		    HINFC504_CMD);
+
+	hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
+	hinfc_write(host, mtd->writesize + mtd->oobsize,
+		    HINFC504_LOG_READ_LEN);
+
+	hisi_nfc_dma_transfer(host, 0);
+
+	host->cache_addr_value[0] = host->addr_value[0];
+	host->cache_addr_value[1] = host->addr_value[1];
+
+	return 0;
+}
+
+static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
+{
+	hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+	hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
+		    HINFC504_CMD);
+
+	hinfc_write(host, HINFC504_OP_WAIT_READY_EN
+		| HINFC504_OP_CMD2_EN
+		| HINFC504_OP_CMD1_EN
+		| HINFC504_OP_ADDR_EN
+		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+			<< HINFC504_OP_NF_CS_SHIFT)
+		| ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
+			<< HINFC504_OP_ADDR_CYCLE_SHIFT),
+		HINFC504_OP);
+
+	wait_controller_finished(host);
+
+	return 0;
+}
+
+static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
+{
+	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
+	hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
+	hinfc_write(host, 0, HINFC504_ADDRL);
+
+	hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
+		| HINFC504_OP_READ_DATA_EN
+		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+			<< HINFC504_OP_NF_CS_SHIFT)
+		| 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
+
+	wait_controller_finished(host);
+
+	return 0;
+}
+
+static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
+{
+	hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
+	hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
+	hinfc_write(host, HINFC504_OP_CMD1_EN
+		| HINFC504_OP_READ_DATA_EN
+		| ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+			<< HINFC504_OP_NF_CS_SHIFT),
+		HINFC504_OP);
+
+	wait_controller_finished(host);
+
+	return 0;
+}
+
+static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
+{
+	hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
+
+	hinfc_write(host, HINFC504_OP_CMD1_EN
+		| ((chipselect & HINFC504_OP_NF_CS_MASK)
+			<< HINFC504_OP_NF_CS_SHIFT)
+		| HINFC504_OP_WAIT_READY_EN,
+		HINFC504_OP);
+
+	wait_controller_finished(host);
+
+	return 0;
+}
+
+static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+
+	if (chipselect < 0)
+		return;
+
+	host->chipselect = chipselect;
+}
+
+static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+
+	if (host->command == NAND_CMD_STATUS)
+		return *(uint8_t *)(host->mmio);
+
+	host->offset++;
+
+	if (host->command == NAND_CMD_READID)
+		return *(uint8_t *)(host->mmio + host->offset - 1);
+
+	return *(uint8_t *)(host->buffer + host->offset - 1);
+}
+
+static u16 hisi_nfc_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+
+	host->offset += 2;
+	return *(u16 *)(host->buffer + host->offset - 2);
+}
+
+static void
+hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+
+	memcpy(host->buffer + host->offset, buf, len);
+	host->offset += len;
+}
+
+static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+
+	memcpy(buf, host->buffer + host->offset, len);
+	host->offset += len;
+}
+
+static void set_addr(struct mtd_info *mtd, int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+	unsigned int command = host->command;
+
+	host->addr_cycle    = 0;
+	host->addr_value[0] = 0;
+	host->addr_value[1] = 0;
+
+	/* Serially input address */
+	if (column != -1) {
+		/* Adjust columns for 16 bit buswidth */
+		if (chip->options & NAND_BUSWIDTH_16 &&
+				!nand_opcode_8bits(command))
+			column >>= 1;
+
+		host->addr_value[0] = column & 0xffff;
+		host->addr_cycle    = 2;
+	}
+	if (page_addr != -1) {
+		host->addr_value[0] |= (page_addr & 0xffff)
+			<< (host->addr_cycle * 8);
+		host->addr_cycle    += 2;
+		if (chip->options & NAND_ROW_ADDR_3) {
+			host->addr_cycle += 1;
+			if (host->command == NAND_CMD_ERASE1)
+				host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
+			else
+				host->addr_value[1] |= ((page_addr >> 16) & 0xff);
+		}
+	}
+}
+
+static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
+		int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hinfc_host *host = nand_get_controller_data(chip);
+	int is_cache_invalid = 1;
+	unsigned int flag = 0;
+
+	host->command =  command;
+
+	switch (command) {
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+		if (command == NAND_CMD_READ0)
+			host->offset = column;
+		else
+			host->offset = column + mtd->writesize;
+
+		is_cache_invalid = 0;
+		set_addr(mtd, column, page_addr);
+		hisi_nfc_send_cmd_readstart(host);
+		break;
+
+	case NAND_CMD_SEQIN:
+		host->offset = column;
+		set_addr(mtd, column, page_addr);
+		break;
+
+	case NAND_CMD_ERASE1:
+		set_addr(mtd, column, page_addr);
+		break;
+
+	case NAND_CMD_PAGEPROG:
+		hisi_nfc_send_cmd_pageprog(host);
+		break;
+
+	case NAND_CMD_ERASE2:
+		hisi_nfc_send_cmd_erase(host);
+		break;
+
+	case NAND_CMD_READID:
+		host->offset = column;
+		memset(host->mmio, 0, 0x10);
+		hisi_nfc_send_cmd_readid(host);
+		break;
+
+	case NAND_CMD_STATUS:
+		flag = hinfc_read(host, HINFC504_CON);
+		if (chip->ecc.mode == NAND_ECC_HW)
+			hinfc_write(host,
+				    flag & ~(HINFC504_CON_ECCTYPE_MASK <<
+				    HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
+
+		host->offset = 0;
+		memset(host->mmio, 0, 0x10);
+		hisi_nfc_send_cmd_status(host);
+		hinfc_write(host, flag, HINFC504_CON);
+		break;
+
+	case NAND_CMD_RESET:
+		hisi_nfc_send_cmd_reset(host, host->chipselect);
+		break;
+
+	default:
+		dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
+			command, column, page_addr);
+	}
+
+	if (is_cache_invalid) {
+		host->cache_addr_value[0] = ~0;
+		host->cache_addr_value[1] = ~0;
+	}
+}
+
+static irqreturn_t hinfc_irq_handle(int irq, void *devid)
+{
+	struct hinfc_host *host = devid;
+	unsigned int flag;
+
+	flag = hinfc_read(host, HINFC504_INTS);
+	/* store interrupts state */
+	host->irq_status |= flag;
+
+	if (flag & HINFC504_INTS_DMA) {
+		hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
+		complete(&host->cmd_complete);
+	} else if (flag & HINFC504_INTS_CE) {
+		hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
+	} else if (flag & HINFC504_INTS_UE) {
+		hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+	struct hinfc_host *host = nand_get_controller_data(chip);
+	int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
+	int stat_1, stat_2;
+
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* errors which can not be corrected by ECC */
+	if (host->irq_status & HINFC504_INTS_UE) {
+		mtd->ecc_stats.failed++;
+	} else if (host->irq_status & HINFC504_INTS_CE) {
+		/* TODO: need add other ECC modes! */
+		switch (chip->ecc.strength) {
+		case 16:
+			status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >>
+					HINFC504_ECC_16_BIT_SHIFT & 0x0fff;
+			stat_2 = status_ecc & 0x3f;
+			stat_1 = status_ecc >> 6 & 0x3f;
+			stat = stat_1 + stat_2;
+			stat_max = max_t(int, stat_1, stat_2);
+		}
+		mtd->ecc_stats.corrected += stat;
+		max_bitflips = max_t(int, max_bitflips, stat_max);
+	}
+	host->irq_status = 0;
+
+	return max_bitflips;
+}
+
+static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+				int page)
+{
+	struct hinfc_host *host = nand_get_controller_data(chip);
+
+	nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
+
+	if (host->irq_status & HINFC504_INTS_UE) {
+		host->irq_status = 0;
+		return -EBADMSG;
+	}
+
+	host->irq_status = 0;
+	return 0;
+}
+
+static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
+		struct nand_chip *chip, const uint8_t *buf, int oob_required,
+		int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	if (oob_required)
+		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static void hisi_nfc_host_init(struct hinfc_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	unsigned int flag = 0;
+
+	host->version = hinfc_read(host, HINFC_VERSION);
+	host->addr_cycle		= 0;
+	host->addr_value[0]		= 0;
+	host->addr_value[1]		= 0;
+	host->cache_addr_value[0]	= ~0;
+	host->cache_addr_value[1]	= ~0;
+	host->chipselect		= 0;
+
+	/* default page size: 2K, ecc_none. need modify */
+	flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
+		| ((0x001 & HINFC504_CON_PAGESIZE_MASK)
+			<< HINFC504_CON_PAGEISZE_SHIFT)
+		| ((0x0 & HINFC504_CON_ECCTYPE_MASK)
+			<< HINFC504_CON_ECCTYPE_SHIFT)
+		| ((chip->options & NAND_BUSWIDTH_16) ?
+			HINFC504_CON_BUS_WIDTH : 0);
+	hinfc_write(host, flag, HINFC504_CON);
+
+	memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
+
+	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
+		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
+
+	/* enable DMA irq */
+	hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
+}
+
+static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	/* FIXME: add ECC bytes position */
+	return -ENOTSUPP;
+}
+
+static int hisi_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 2;
+	oobregion->length = 6;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
+	.ecc = hisi_ooblayout_ecc,
+	.free = hisi_ooblayout_free,
+};
+
+static int hisi_nfc_ecc_probe(struct hinfc_host *host)
+{
+	unsigned int flag;
+	int size, strength, ecc_bits;
+	struct device *dev = host->dev;
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	size = chip->ecc.size;
+	strength = chip->ecc.strength;
+	if (size != 1024) {
+		dev_err(dev, "error ecc size: %d\n", size);
+		return -EINVAL;
+	}
+
+	if ((size == 1024) && ((strength != 8) && (strength != 16) &&
+				(strength != 24) && (strength != 40))) {
+		dev_err(dev, "ecc size and strength do not match\n");
+		return -EINVAL;
+	}
+
+	chip->ecc.size = size;
+	chip->ecc.strength = strength;
+
+	chip->ecc.read_page = hisi_nand_read_page_hwecc;
+	chip->ecc.read_oob = hisi_nand_read_oob;
+	chip->ecc.write_page = hisi_nand_write_page_hwecc;
+
+	switch (chip->ecc.strength) {
+	case 16:
+		ecc_bits = 6;
+		if (mtd->writesize == 2048)
+			mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);
+
+		/* TODO: add more page size support */
+		break;
+
+	/* TODO: add more ecc strength support */
+	default:
+		dev_err(dev, "not support strength: %d\n", chip->ecc.strength);
+		return -EINVAL;
+	}
+
+	flag = hinfc_read(host, HINFC504_CON);
+	/* add ecc type configure */
+	flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK)
+						<< HINFC504_CON_ECCTYPE_SHIFT);
+	hinfc_write(host, flag, HINFC504_CON);
+
+	/* enable ecc irq */
+	flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
+	hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
+		    HINFC504_INTEN);
+
+	return 0;
+}
+
+static int hisi_nfc_probe(struct platform_device *pdev)
+{
+	int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
+	struct device *dev = &pdev->dev;
+	struct hinfc_host *host;
+	struct nand_chip  *chip;
+	struct mtd_info   *mtd;
+	struct resource	  *res;
+	struct device_node *np = dev->of_node;
+
+	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+	host->dev = dev;
+
+	platform_set_drvdata(pdev, host);
+	chip = &host->chip;
+	mtd  = nand_to_mtd(chip);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "no IRQ resource defined\n");
+		ret = -ENXIO;
+		goto err_res;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->iobase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->iobase)) {
+		ret = PTR_ERR(host->iobase);
+		goto err_res;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	host->mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->mmio)) {
+		ret = PTR_ERR(host->mmio);
+		dev_err(dev, "devm_ioremap_resource[1] fail\n");
+		goto err_res;
+	}
+
+	mtd->name		= "hisi_nand";
+	mtd->dev.parent         = &pdev->dev;
+
+	nand_set_controller_data(chip, host);
+	nand_set_flash_node(chip, np);
+	chip->cmdfunc		= hisi_nfc_cmdfunc;
+	chip->select_chip	= hisi_nfc_select_chip;
+	chip->read_byte		= hisi_nfc_read_byte;
+	chip->read_word		= hisi_nfc_read_word;
+	chip->write_buf		= hisi_nfc_write_buf;
+	chip->read_buf		= hisi_nfc_read_buf;
+	chip->chip_delay	= HINFC504_CHIP_DELAY;
+	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+
+	hisi_nfc_host_init(host);
+
+	ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ\n");
+		goto err_res;
+	}
+
+	ret = nand_scan_ident(mtd, max_chips, NULL);
+	if (ret)
+		goto err_res;
+
+	host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
+		&host->dma_buffer, GFP_KERNEL);
+	if (!host->buffer) {
+		ret = -ENOMEM;
+		goto err_res;
+	}
+
+	host->dma_oob = host->dma_buffer + mtd->writesize;
+	memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
+
+	flag = hinfc_read(host, HINFC504_CON);
+	flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
+	switch (mtd->writesize) {
+	case 2048:
+		flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
+	/*
+	 * TODO: add more pagesize support,
+	 * default pagesize has been set in hisi_nfc_host_init
+	 */
+	default:
+		dev_err(dev, "NON-2KB page size nand flash\n");
+		ret = -EINVAL;
+		goto err_res;
+	}
+	hinfc_write(host, flag, HINFC504_CON);
+
+	if (chip->ecc.mode == NAND_ECC_HW)
+		hisi_nfc_ecc_probe(host);
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+		goto err_res;
+	}
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(dev, "Err MTD partition=%d\n", ret);
+		goto err_mtd;
+	}
+
+	return 0;
+
+err_mtd:
+	nand_release(mtd);
+err_res:
+	return ret;
+}
+
+static int hisi_nfc_remove(struct platform_device *pdev)
+{
+	struct hinfc_host *host = platform_get_drvdata(pdev);
+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+
+	nand_release(mtd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int hisi_nfc_suspend(struct device *dev)
+{
+	struct hinfc_host *host = dev_get_drvdata(dev);
+	unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT;
+
+	while (time_before(jiffies, timeout)) {
+		if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) &&
+		    (hinfc_read(host, HINFC504_DMA_CTRL) &
+		     HINFC504_DMA_CTRL_DMA_START)) {
+			cond_resched();
+			return 0;
+		}
+	}
+
+	dev_err(host->dev, "nand controller suspend timeout.\n");
+
+	return -EAGAIN;
+}
+
+static int hisi_nfc_resume(struct device *dev)
+{
+	int cs;
+	struct hinfc_host *host = dev_get_drvdata(dev);
+	struct nand_chip *chip = &host->chip;
+
+	for (cs = 0; cs < chip->numchips; cs++)
+		hisi_nfc_send_cmd_reset(host, cs);
+	hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
+		    HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
+
+	return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
+
+static const struct of_device_id nfc_id_table[] = {
+	{ .compatible = "hisilicon,504-nfc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, nfc_id_table);
+
+static struct platform_driver hisi_nfc_driver = {
+	.driver = {
+		.name  = "hisi_nand",
+		.of_match_table = nfc_id_table,
+		.pm = &hisi_nfc_pm_ops,
+	},
+	.probe		= hisi_nfc_probe,
+	.remove		= hisi_nfc_remove,
+};
+
+module_platform_driver(hisi_nfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhou Wang");
+MODULE_AUTHOR("Zhiyong Cai");
+MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");
diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
new file mode 100644
index 000000000000..613b00a9604b
--- /dev/null
+++ b/drivers/mtd/nand/raw/jz4740_nand.c
@@ -0,0 +1,536 @@
+/*
+ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  JZ4740 SoC NAND controller driver
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/gpio.h>
+
+#include <asm/mach-jz4740/jz4740_nand.h>
+
+#define JZ_REG_NAND_CTRL	0x50
+#define JZ_REG_NAND_ECC_CTRL	0x100
+#define JZ_REG_NAND_DATA	0x104
+#define JZ_REG_NAND_PAR0	0x108
+#define JZ_REG_NAND_PAR1	0x10C
+#define JZ_REG_NAND_PAR2	0x110
+#define JZ_REG_NAND_IRQ_STAT	0x114
+#define JZ_REG_NAND_IRQ_CTRL	0x118
+#define JZ_REG_NAND_ERR(x)	(0x11C + ((x) << 2))
+
+#define JZ_NAND_ECC_CTRL_PAR_READY	BIT(4)
+#define JZ_NAND_ECC_CTRL_ENCODING	BIT(3)
+#define JZ_NAND_ECC_CTRL_RS		BIT(2)
+#define JZ_NAND_ECC_CTRL_RESET		BIT(1)
+#define JZ_NAND_ECC_CTRL_ENABLE		BIT(0)
+
+#define JZ_NAND_STATUS_ERR_COUNT	(BIT(31) | BIT(30) | BIT(29))
+#define JZ_NAND_STATUS_PAD_FINISH	BIT(4)
+#define JZ_NAND_STATUS_DEC_FINISH	BIT(3)
+#define JZ_NAND_STATUS_ENC_FINISH	BIT(2)
+#define JZ_NAND_STATUS_UNCOR_ERROR	BIT(1)
+#define JZ_NAND_STATUS_ERROR		BIT(0)
+
+#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
+
+#define JZ_NAND_MEM_CMD_OFFSET 0x08000
+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
+
+struct jz_nand {
+	struct nand_chip chip;
+	void __iomem *base;
+	struct resource *mem;
+
+	unsigned char banks[JZ_NAND_NUM_BANKS];
+	void __iomem *bank_base[JZ_NAND_NUM_BANKS];
+	struct resource *bank_mem[JZ_NAND_NUM_BANKS];
+
+	int selected_bank;
+
+	struct gpio_desc *busy_gpio;
+	bool is_reading;
+};
+
+static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
+}
+
+static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t ctrl;
+	int banknr;
+
+	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+	ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
+
+	if (chipnr == -1) {
+		banknr = -1;
+	} else {
+		banknr = nand->banks[chipnr] - 1;
+		chip->IO_ADDR_R = nand->bank_base[banknr];
+		chip->IO_ADDR_W = nand->bank_base[banknr];
+	}
+	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+	nand->selected_bank = banknr;
+}
+
+static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t reg;
+	void __iomem *bank_base = nand->bank_base[nand->selected_bank];
+
+	BUG_ON(nand->selected_bank < 0);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
+		if (ctrl & NAND_ALE)
+			bank_base += JZ_NAND_MEM_ADDR_OFFSET;
+		else if (ctrl & NAND_CLE)
+			bank_base += JZ_NAND_MEM_CMD_OFFSET;
+		chip->IO_ADDR_W = bank_base;
+
+		reg = readl(nand->base + JZ_REG_NAND_CTRL);
+		if (ctrl & NAND_NCE)
+			reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
+		else
+			reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
+		writel(reg, nand->base + JZ_REG_NAND_CTRL);
+	}
+	if (dat != NAND_CMD_NONE)
+		writeb(dat, chip->IO_ADDR_W);
+}
+
+static int jz_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	return gpiod_get_value_cansleep(nand->busy_gpio);
+}
+
+static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	uint32_t reg;
+
+	writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
+	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+
+	reg |= JZ_NAND_ECC_CTRL_RESET;
+	reg |= JZ_NAND_ECC_CTRL_ENABLE;
+	reg |= JZ_NAND_ECC_CTRL_RS;
+
+	switch (mode) {
+	case NAND_ECC_READ:
+		reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
+		nand->is_reading = true;
+		break;
+	case NAND_ECC_WRITE:
+		reg |= JZ_NAND_ECC_CTRL_ENCODING;
+		nand->is_reading = false;
+		break;
+	default:
+		break;
+	}
+
+	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+}
+
+static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
+	uint8_t *ecc_code)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	uint32_t reg, status;
+	int i;
+	unsigned int timeout = 1000;
+	static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
+						0x8b, 0xff, 0xb7, 0x6f};
+
+	if (nand->is_reading)
+		return 0;
+
+	do {
+		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+	} while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
+
+	if (timeout == 0)
+	    return -1;
+
+	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+	for (i = 0; i < 9; ++i)
+		ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
+
+	/* If the written data is completly 0xff, we also want to write 0xff as
+	 * ecc, otherwise we will get in trouble when doing subpage writes. */
+	if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
+		memset(ecc_code, 0xff, 9);
+
+	return 0;
+}
+
+static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
+{
+	int offset = index & 0x7;
+	uint16_t data;
+
+	index += (index >> 3);
+
+	data = dat[index];
+	data |= dat[index+1] << 8;
+
+	mask ^= (data >> offset) & 0x1ff;
+	data &= ~(0x1ff << offset);
+	data |= (mask << offset);
+
+	dat[index] = data & 0xff;
+	dat[index+1] = (data >> 8) & 0xff;
+}
+
+static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
+	uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+	struct jz_nand *nand = mtd_to_jz_nand(mtd);
+	int i, error_count, index;
+	uint32_t reg, status, error;
+	unsigned int timeout = 1000;
+
+	for (i = 0; i < 9; ++i)
+		writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
+
+	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+	reg |= JZ_NAND_ECC_CTRL_PAR_READY;
+	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+	do {
+		status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+	} while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
+
+	if (timeout == 0)
+		return -ETIMEDOUT;
+
+	reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+	writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+	if (status & JZ_NAND_STATUS_ERROR) {
+		if (status & JZ_NAND_STATUS_UNCOR_ERROR)
+			return -EBADMSG;
+
+		error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
+
+		for (i = 0; i < error_count; ++i) {
+			error = readl(nand->base + JZ_REG_NAND_ERR(i));
+			index = ((error >> 16) & 0x1ff) - 1;
+			if (index >= 0 && index < 512)
+				jz_nand_correct_data(dat, index, error & 0x1ff);
+		}
+
+		return error_count;
+	}
+
+	return 0;
+}
+
+static int jz_nand_ioremap_resource(struct platform_device *pdev,
+	const char *name, struct resource **res, void *__iomem *base)
+{
+	int ret;
+
+	*res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+	if (!*res) {
+		dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
+		ret = -ENXIO;
+		goto err;
+	}
+
+	*res = request_mem_region((*res)->start, resource_size(*res),
+				pdev->name);
+	if (!*res) {
+		dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
+		ret = -EBUSY;
+		goto err;
+	}
+
+	*base = ioremap((*res)->start, resource_size(*res));
+	if (!*base) {
+		dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
+		ret = -EBUSY;
+		goto err_release_mem;
+	}
+
+	return 0;
+
+err_release_mem:
+	release_mem_region((*res)->start, resource_size(*res));
+err:
+	*res = NULL;
+	*base = NULL;
+	return ret;
+}
+
+static inline void jz_nand_iounmap_resource(struct resource *res,
+					    void __iomem *base)
+{
+	iounmap(base);
+	release_mem_region(res->start, resource_size(res));
+}
+
+static int jz_nand_detect_bank(struct platform_device *pdev,
+			       struct jz_nand *nand, unsigned char bank,
+			       size_t chipnr, uint8_t *nand_maf_id,
+			       uint8_t *nand_dev_id)
+{
+	int ret;
+	char res_name[6];
+	uint32_t ctrl;
+	struct nand_chip *chip = &nand->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 id[2];
+
+	/* Request I/O resource. */
+	sprintf(res_name, "bank%d", bank);
+	ret = jz_nand_ioremap_resource(pdev, res_name,
+					&nand->bank_mem[bank - 1],
+					&nand->bank_base[bank - 1]);
+	if (ret)
+		return ret;
+
+	/* Enable chip in bank. */
+	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
+	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+	if (chipnr == 0) {
+		/* Detect first chip. */
+		ret = nand_scan_ident(mtd, 1, NULL);
+		if (ret)
+			goto notfound_id;
+
+		/* Retrieve the IDs from the first chip. */
+		chip->select_chip(mtd, 0);
+		nand_reset_op(chip);
+		nand_readid_op(chip, 0, id, sizeof(id));
+		*nand_maf_id = id[0];
+		*nand_dev_id = id[1];
+	} else {
+		/* Detect additional chip. */
+		chip->select_chip(mtd, chipnr);
+		nand_reset_op(chip);
+		nand_readid_op(chip, 0, id, sizeof(id));
+		if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
+			ret = -ENODEV;
+			goto notfound_id;
+		}
+
+		/* Update size of the MTD. */
+		chip->numchips++;
+		mtd->size += chip->chipsize;
+	}
+
+	dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
+	return 0;
+
+notfound_id:
+	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
+	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
+	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+				 nand->bank_base[bank - 1]);
+	return ret;
+}
+
+static int jz_nand_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct jz_nand *nand;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	size_t chipnr, bank_idx;
+	uint8_t nand_maf_id = 0, nand_dev_id = 0;
+
+	nand = kzalloc(sizeof(*nand), GFP_KERNEL);
+	if (!nand)
+		return -ENOMEM;
+
+	ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
+	if (ret)
+		goto err_free;
+
+	nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
+	if (IS_ERR(nand->busy_gpio)) {
+		ret = PTR_ERR(nand->busy_gpio);
+		dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
+		    ret);
+		goto err_iounmap_mmio;
+	}
+
+	chip		= &nand->chip;
+	mtd		= nand_to_mtd(chip);
+	mtd->dev.parent = &pdev->dev;
+	mtd->name	= "jz4740-nand";
+
+	chip->ecc.hwctl		= jz_nand_hwctl;
+	chip->ecc.calculate	= jz_nand_calculate_ecc_rs;
+	chip->ecc.correct	= jz_nand_correct_ecc_rs;
+	chip->ecc.mode		= NAND_ECC_HW_OOB_FIRST;
+	chip->ecc.size		= 512;
+	chip->ecc.bytes		= 9;
+	chip->ecc.strength	= 4;
+	chip->ecc.options	= NAND_ECC_GENERIC_ERASED_CHECK;
+
+	chip->chip_delay = 50;
+	chip->cmd_ctrl = jz_nand_cmd_ctrl;
+	chip->select_chip = jz_nand_select_chip;
+
+	if (nand->busy_gpio)
+		chip->dev_ready = jz_nand_dev_ready;
+
+	platform_set_drvdata(pdev, nand);
+
+	/* We are going to autodetect NAND chips in the banks specified in the
+	 * platform data. Although nand_scan_ident() can detect multiple chips,
+	 * it requires those chips to be numbered consecuitively, which is not
+	 * always the case for external memory banks. And a fixed chip-to-bank
+	 * mapping is not practical either, since for example Dingoo units
+	 * produced at different times have NAND chips in different banks.
+	 */
+	chipnr = 0;
+	for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
+		unsigned char bank;
+
+		/* If there is no platform data, look for NAND in bank 1,
+		 * which is the most likely bank since it is the only one
+		 * that can be booted from.
+		 */
+		bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
+		if (bank == 0)
+			break;
+		if (bank > JZ_NAND_NUM_BANKS) {
+			dev_warn(&pdev->dev,
+				"Skipping non-existing bank: %d\n", bank);
+			continue;
+		}
+		/* The detection routine will directly or indirectly call
+		 * jz_nand_select_chip(), so nand->banks has to contain the
+		 * bank we're checking.
+		 */
+		nand->banks[chipnr] = bank;
+		if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
+					&nand_maf_id, &nand_dev_id) == 0)
+			chipnr++;
+		else
+			nand->banks[chipnr] = 0;
+	}
+	if (chipnr == 0) {
+		dev_err(&pdev->dev, "No NAND chips found\n");
+		goto err_iounmap_mmio;
+	}
+
+	if (pdata && pdata->ident_callback) {
+		pdata->ident_callback(pdev, mtd, &pdata->partitions,
+					&pdata->num_partitions);
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(&pdev->dev,  "Failed to scan NAND\n");
+		goto err_unclaim_banks;
+	}
+
+	ret = mtd_device_parse_register(mtd, NULL, NULL,
+					pdata ? pdata->partitions : NULL,
+					pdata ? pdata->num_partitions : 0);
+
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add mtd device\n");
+		goto err_nand_release;
+	}
+
+	dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
+
+	return 0;
+
+err_nand_release:
+	nand_release(mtd);
+err_unclaim_banks:
+	while (chipnr--) {
+		unsigned char bank = nand->banks[chipnr];
+		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+					 nand->bank_base[bank - 1]);
+	}
+	writel(0, nand->base + JZ_REG_NAND_CTRL);
+err_iounmap_mmio:
+	jz_nand_iounmap_resource(nand->mem, nand->base);
+err_free:
+	kfree(nand);
+	return ret;
+}
+
+static int jz_nand_remove(struct platform_device *pdev)
+{
+	struct jz_nand *nand = platform_get_drvdata(pdev);
+	size_t i;
+
+	nand_release(nand_to_mtd(&nand->chip));
+
+	/* Deassert and disable all chips */
+	writel(0, nand->base + JZ_REG_NAND_CTRL);
+
+	for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
+		unsigned char bank = nand->banks[i];
+		if (bank != 0) {
+			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+						 nand->bank_base[bank - 1]);
+		}
+	}
+
+	jz_nand_iounmap_resource(nand->mem, nand->base);
+
+	kfree(nand);
+
+	return 0;
+}
+
+static struct platform_driver jz_nand_driver = {
+	.probe = jz_nand_probe,
+	.remove = jz_nand_remove,
+	.driver = {
+		.name = "jz4740-nand",
+	},
+};
+
+module_platform_driver(jz_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
+MODULE_ALIAS("platform:jz4740-nand");
diff --git a/drivers/mtd/nand/raw/jz4780_bch.c b/drivers/mtd/nand/raw/jz4780_bch.c
new file mode 100644
index 000000000000..731c6051d91e
--- /dev/null
+++ b/drivers/mtd/nand/raw/jz4780_bch.c
@@ -0,0 +1,380 @@
+/*
+ * JZ4780 BCH controller
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "jz4780_bch.h"
+
+#define BCH_BHCR			0x0
+#define BCH_BHCCR			0x8
+#define BCH_BHCNT			0xc
+#define BCH_BHDR			0x10
+#define BCH_BHPAR0			0x14
+#define BCH_BHERR0			0x84
+#define BCH_BHINT			0x184
+#define BCH_BHINTES			0x188
+#define BCH_BHINTEC			0x18c
+#define BCH_BHINTE			0x190
+
+#define BCH_BHCR_BSEL_SHIFT		4
+#define BCH_BHCR_BSEL_MASK		(0x7f << BCH_BHCR_BSEL_SHIFT)
+#define BCH_BHCR_ENCE			BIT(2)
+#define BCH_BHCR_INIT			BIT(1)
+#define BCH_BHCR_BCHE			BIT(0)
+
+#define BCH_BHCNT_PARITYSIZE_SHIFT	16
+#define BCH_BHCNT_PARITYSIZE_MASK	(0x7f << BCH_BHCNT_PARITYSIZE_SHIFT)
+#define BCH_BHCNT_BLOCKSIZE_SHIFT	0
+#define BCH_BHCNT_BLOCKSIZE_MASK	(0x7ff << BCH_BHCNT_BLOCKSIZE_SHIFT)
+
+#define BCH_BHERR_MASK_SHIFT		16
+#define BCH_BHERR_MASK_MASK		(0xffff << BCH_BHERR_MASK_SHIFT)
+#define BCH_BHERR_INDEX_SHIFT		0
+#define BCH_BHERR_INDEX_MASK		(0x7ff << BCH_BHERR_INDEX_SHIFT)
+
+#define BCH_BHINT_ERRC_SHIFT		24
+#define BCH_BHINT_ERRC_MASK		(0x7f << BCH_BHINT_ERRC_SHIFT)
+#define BCH_BHINT_TERRC_SHIFT		16
+#define BCH_BHINT_TERRC_MASK		(0x7f << BCH_BHINT_TERRC_SHIFT)
+#define BCH_BHINT_DECF			BIT(3)
+#define BCH_BHINT_ENCF			BIT(2)
+#define BCH_BHINT_UNCOR			BIT(1)
+#define BCH_BHINT_ERR			BIT(0)
+
+#define BCH_CLK_RATE			(200 * 1000 * 1000)
+
+/* Timeout for BCH calculation/correction. */
+#define BCH_TIMEOUT_US			100000
+
+struct jz4780_bch {
+	struct device *dev;
+	void __iomem *base;
+	struct clk *clk;
+	struct mutex lock;
+};
+
+static void jz4780_bch_init(struct jz4780_bch *bch,
+			    struct jz4780_bch_params *params, bool encode)
+{
+	u32 reg;
+
+	/* Clear interrupt status. */
+	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+
+	/* Set up BCH count register. */
+	reg = params->size << BCH_BHCNT_BLOCKSIZE_SHIFT;
+	reg |= params->bytes << BCH_BHCNT_PARITYSIZE_SHIFT;
+	writel(reg, bch->base + BCH_BHCNT);
+
+	/* Initialise and enable BCH. */
+	reg = BCH_BHCR_BCHE | BCH_BHCR_INIT;
+	reg |= params->strength << BCH_BHCR_BSEL_SHIFT;
+	if (encode)
+		reg |= BCH_BHCR_ENCE;
+	writel(reg, bch->base + BCH_BHCR);
+}
+
+static void jz4780_bch_disable(struct jz4780_bch *bch)
+{
+	writel(readl(bch->base + BCH_BHINT), bch->base + BCH_BHINT);
+	writel(BCH_BHCR_BCHE, bch->base + BCH_BHCCR);
+}
+
+static void jz4780_bch_write_data(struct jz4780_bch *bch, const void *buf,
+				  size_t size)
+{
+	size_t size32 = size / sizeof(u32);
+	size_t size8 = size % sizeof(u32);
+	const u32 *src32;
+	const u8 *src8;
+
+	src32 = (const u32 *)buf;
+	while (size32--)
+		writel(*src32++, bch->base + BCH_BHDR);
+
+	src8 = (const u8 *)src32;
+	while (size8--)
+		writeb(*src8++, bch->base + BCH_BHDR);
+}
+
+static void jz4780_bch_read_parity(struct jz4780_bch *bch, void *buf,
+				   size_t size)
+{
+	size_t size32 = size / sizeof(u32);
+	size_t size8 = size % sizeof(u32);
+	u32 *dest32;
+	u8 *dest8;
+	u32 val, offset = 0;
+
+	dest32 = (u32 *)buf;
+	while (size32--) {
+		*dest32++ = readl(bch->base + BCH_BHPAR0 + offset);
+		offset += sizeof(u32);
+	}
+
+	dest8 = (u8 *)dest32;
+	val = readl(bch->base + BCH_BHPAR0 + offset);
+	switch (size8) {
+	case 3:
+		dest8[2] = (val >> 16) & 0xff;
+	case 2:
+		dest8[1] = (val >> 8) & 0xff;
+	case 1:
+		dest8[0] = val & 0xff;
+		break;
+	}
+}
+
+static bool jz4780_bch_wait_complete(struct jz4780_bch *bch, unsigned int irq,
+				     u32 *status)
+{
+	u32 reg;
+	int ret;
+
+	/*
+	 * While we could use interrupts here and sleep until the operation
+	 * completes, the controller works fairly quickly (usually a few
+	 * microseconds) and so the overhead of sleeping until we get an
+	 * interrupt quite noticeably decreases performance.
+	 */
+	ret = readl_poll_timeout(bch->base + BCH_BHINT, reg,
+				 (reg & irq) == irq, 0, BCH_TIMEOUT_US);
+	if (ret)
+		return false;
+
+	if (status)
+		*status = reg;
+
+	writel(reg, bch->base + BCH_BHINT);
+	return true;
+}
+
+/**
+ * jz4780_bch_calculate() - calculate ECC for a data buffer
+ * @bch: BCH device.
+ * @params: BCH parameters.
+ * @buf: input buffer with raw data.
+ * @ecc_code: output buffer with ECC.
+ *
+ * Return: 0 on success, -ETIMEDOUT if timed out while waiting for BCH
+ * controller.
+ */
+int jz4780_bch_calculate(struct jz4780_bch *bch, struct jz4780_bch_params *params,
+			 const u8 *buf, u8 *ecc_code)
+{
+	int ret = 0;
+
+	mutex_lock(&bch->lock);
+	jz4780_bch_init(bch, params, true);
+	jz4780_bch_write_data(bch, buf, params->size);
+
+	if (jz4780_bch_wait_complete(bch, BCH_BHINT_ENCF, NULL)) {
+		jz4780_bch_read_parity(bch, ecc_code, params->bytes);
+	} else {
+		dev_err(bch->dev, "timed out while calculating ECC\n");
+		ret = -ETIMEDOUT;
+	}
+
+	jz4780_bch_disable(bch);
+	mutex_unlock(&bch->lock);
+	return ret;
+}
+EXPORT_SYMBOL(jz4780_bch_calculate);
+
+/**
+ * jz4780_bch_correct() - detect and correct bit errors
+ * @bch: BCH device.
+ * @params: BCH parameters.
+ * @buf: raw data read from the chip.
+ * @ecc_code: ECC read from the chip.
+ *
+ * Given the raw data and the ECC read from the NAND device, detects and
+ * corrects errors in the data.
+ *
+ * Return: the number of bit errors corrected, -EBADMSG if there are too many
+ * errors to correct or -ETIMEDOUT if we timed out waiting for the controller.
+ */
+int jz4780_bch_correct(struct jz4780_bch *bch, struct jz4780_bch_params *params,
+		       u8 *buf, u8 *ecc_code)
+{
+	u32 reg, mask, index;
+	int i, ret, count;
+
+	mutex_lock(&bch->lock);
+
+	jz4780_bch_init(bch, params, false);
+	jz4780_bch_write_data(bch, buf, params->size);
+	jz4780_bch_write_data(bch, ecc_code, params->bytes);
+
+	if (!jz4780_bch_wait_complete(bch, BCH_BHINT_DECF, &reg)) {
+		dev_err(bch->dev, "timed out while correcting data\n");
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	if (reg & BCH_BHINT_UNCOR) {
+		dev_warn(bch->dev, "uncorrectable ECC error\n");
+		ret = -EBADMSG;
+		goto out;
+	}
+
+	/* Correct any detected errors. */
+	if (reg & BCH_BHINT_ERR) {
+		count = (reg & BCH_BHINT_ERRC_MASK) >> BCH_BHINT_ERRC_SHIFT;
+		ret = (reg & BCH_BHINT_TERRC_MASK) >> BCH_BHINT_TERRC_SHIFT;
+
+		for (i = 0; i < count; i++) {
+			reg = readl(bch->base + BCH_BHERR0 + (i * 4));
+			mask = (reg & BCH_BHERR_MASK_MASK) >>
+						BCH_BHERR_MASK_SHIFT;
+			index = (reg & BCH_BHERR_INDEX_MASK) >>
+						BCH_BHERR_INDEX_SHIFT;
+			buf[(index * 2) + 0] ^= mask;
+			buf[(index * 2) + 1] ^= mask >> 8;
+		}
+	} else {
+		ret = 0;
+	}
+
+out:
+	jz4780_bch_disable(bch);
+	mutex_unlock(&bch->lock);
+	return ret;
+}
+EXPORT_SYMBOL(jz4780_bch_correct);
+
+/**
+ * jz4780_bch_get() - get the BCH controller device
+ * @np: BCH device tree node.
+ *
+ * Gets the BCH controller device from the specified device tree node. The
+ * device must be released with jz4780_bch_release() when it is no longer being
+ * used.
+ *
+ * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
+ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+ */
+static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct jz4780_bch *bch;
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev || !platform_get_drvdata(pdev))
+		return ERR_PTR(-EPROBE_DEFER);
+
+	get_device(&pdev->dev);
+
+	bch = platform_get_drvdata(pdev);
+	clk_prepare_enable(bch->clk);
+
+	return bch;
+}
+
+/**
+ * of_jz4780_bch_get() - get the BCH controller from a DT node
+ * @of_node: the node that contains a bch-controller property.
+ *
+ * Get the bch-controller property from the given device tree
+ * node and pass it to jz4780_bch_get to do the work.
+ *
+ * Return: a pointer to jz4780_bch, errors are encoded into the pointer.
+ * PTR_ERR(-EPROBE_DEFER) if the device hasn't been initialised yet.
+ */
+struct jz4780_bch *of_jz4780_bch_get(struct device_node *of_node)
+{
+	struct jz4780_bch *bch = NULL;
+	struct device_node *np;
+
+	np = of_parse_phandle(of_node, "ingenic,bch-controller", 0);
+
+	if (np) {
+		bch = jz4780_bch_get(np);
+		of_node_put(np);
+	}
+	return bch;
+}
+EXPORT_SYMBOL(of_jz4780_bch_get);
+
+/**
+ * jz4780_bch_release() - release the BCH controller device
+ * @bch: BCH device.
+ */
+void jz4780_bch_release(struct jz4780_bch *bch)
+{
+	clk_disable_unprepare(bch->clk);
+	put_device(bch->dev);
+}
+EXPORT_SYMBOL(jz4780_bch_release);
+
+static int jz4780_bch_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct jz4780_bch *bch;
+	struct resource *res;
+
+	bch = devm_kzalloc(dev, sizeof(*bch), GFP_KERNEL);
+	if (!bch)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	bch->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(bch->base))
+		return PTR_ERR(bch->base);
+
+	jz4780_bch_disable(bch);
+
+	bch->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(bch->clk)) {
+		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(bch->clk));
+		return PTR_ERR(bch->clk);
+	}
+
+	clk_set_rate(bch->clk, BCH_CLK_RATE);
+
+	mutex_init(&bch->lock);
+
+	bch->dev = dev;
+	platform_set_drvdata(pdev, bch);
+
+	return 0;
+}
+
+static const struct of_device_id jz4780_bch_dt_match[] = {
+	{ .compatible = "ingenic,jz4780-bch" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, jz4780_bch_dt_match);
+
+static struct platform_driver jz4780_bch_driver = {
+	.probe		= jz4780_bch_probe,
+	.driver	= {
+		.name	= "jz4780-bch",
+		.of_match_table = of_match_ptr(jz4780_bch_dt_match),
+	},
+};
+module_platform_driver(jz4780_bch_driver);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/jz4780_bch.h b/drivers/mtd/nand/raw/jz4780_bch.h
new file mode 100644
index 000000000000..bf4718088a3a
--- /dev/null
+++ b/drivers/mtd/nand/raw/jz4780_bch.h
@@ -0,0 +1,43 @@
+/*
+ * JZ4780 BCH controller
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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.
+ */
+
+#ifndef __DRIVERS_MTD_NAND_JZ4780_BCH_H__
+#define __DRIVERS_MTD_NAND_JZ4780_BCH_H__
+
+#include <linux/types.h>
+
+struct device;
+struct device_node;
+struct jz4780_bch;
+
+/**
+ * struct jz4780_bch_params - BCH parameters
+ * @size: data bytes per ECC step.
+ * @bytes: ECC bytes per step.
+ * @strength: number of correctable bits per ECC step.
+ */
+struct jz4780_bch_params {
+	int size;
+	int bytes;
+	int strength;
+};
+
+int jz4780_bch_calculate(struct jz4780_bch *bch,
+				struct jz4780_bch_params *params,
+				const u8 *buf, u8 *ecc_code);
+int jz4780_bch_correct(struct jz4780_bch *bch,
+			      struct jz4780_bch_params *params, u8 *buf,
+			      u8 *ecc_code);
+
+void jz4780_bch_release(struct jz4780_bch *bch);
+struct jz4780_bch *of_jz4780_bch_get(struct device_node *np);
+
+#endif /* __DRIVERS_MTD_NAND_JZ4780_BCH_H__ */
diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
new file mode 100644
index 000000000000..e69f6ae4c539
--- /dev/null
+++ b/drivers/mtd/nand/raw/jz4780_nand.c
@@ -0,0 +1,416 @@
+/*
+ * JZ4780 NAND driver
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/jz4780-nemc.h>
+
+#include "jz4780_bch.h"
+
+#define DRV_NAME	"jz4780-nand"
+
+#define OFFSET_DATA	0x00000000
+#define OFFSET_CMD	0x00400000
+#define OFFSET_ADDR	0x00800000
+
+/* Command delay when there is no R/B pin. */
+#define RB_DELAY_US	100
+
+struct jz4780_nand_cs {
+	unsigned int bank;
+	void __iomem *base;
+};
+
+struct jz4780_nand_controller {
+	struct device *dev;
+	struct jz4780_bch *bch;
+	struct nand_hw_control controller;
+	unsigned int num_banks;
+	struct list_head chips;
+	int selected;
+	struct jz4780_nand_cs cs[];
+};
+
+struct jz4780_nand_chip {
+	struct nand_chip chip;
+	struct list_head chip_list;
+
+	struct gpio_desc *busy_gpio;
+	struct gpio_desc *wp_gpio;
+	unsigned int reading: 1;
+};
+
+static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
+}
+
+static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
+{
+	return container_of(ctrl, struct jz4780_nand_controller, controller);
+}
+
+static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+	struct jz4780_nand_cs *cs;
+
+	/* Ensure the currently selected chip is deasserted. */
+	if (chipnr == -1 && nfc->selected >= 0) {
+		cs = &nfc->cs[nfc->selected];
+		jz4780_nemc_assert(nfc->dev, cs->bank, false);
+	}
+
+	nfc->selected = chipnr;
+}
+
+static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				 unsigned int ctrl)
+{
+	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+	struct jz4780_nand_cs *cs;
+
+	if (WARN_ON(nfc->selected < 0))
+		return;
+
+	cs = &nfc->cs[nfc->selected];
+
+	jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE);
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_ALE)
+		writeb(cmd, cs->base + OFFSET_ADDR);
+	else if (ctrl & NAND_CLE)
+		writeb(cmd, cs->base + OFFSET_CMD);
+}
+
+static int jz4780_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+
+	return !gpiod_get_value_cansleep(nand->busy_gpio);
+}
+
+static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+
+	nand->reading = (mode == NAND_ECC_READ);
+}
+
+static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
+				     u8 *ecc_code)
+{
+	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+	struct jz4780_bch_params params;
+
+	/*
+	 * Don't need to generate the ECC when reading, BCH does it for us as
+	 * part of decoding/correction.
+	 */
+	if (nand->reading)
+		return 0;
+
+	params.size = nand->chip.ecc.size;
+	params.bytes = nand->chip.ecc.bytes;
+	params.strength = nand->chip.ecc.strength;
+
+	return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
+}
+
+static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
+				   u8 *read_ecc, u8 *calc_ecc)
+{
+	struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
+	struct jz4780_bch_params params;
+
+	params.size = nand->chip.ecc.size;
+	params.bytes = nand->chip.ecc.bytes;
+	params.strength = nand->chip.ecc.strength;
+
+	return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
+}
+
+static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
+{
+	struct nand_chip *chip = &nand->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
+	int eccbytes;
+
+	chip->ecc.bytes = fls((1 + 8) * chip->ecc.size)	*
+				(chip->ecc.strength / 8);
+
+	switch (chip->ecc.mode) {
+	case NAND_ECC_HW:
+		if (!nfc->bch) {
+			dev_err(dev, "HW BCH selected, but BCH controller not found\n");
+			return -ENODEV;
+		}
+
+		chip->ecc.hwctl = jz4780_nand_ecc_hwctl;
+		chip->ecc.calculate = jz4780_nand_ecc_calculate;
+		chip->ecc.correct = jz4780_nand_ecc_correct;
+		/* fall through */
+	case NAND_ECC_SOFT:
+		dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
+			(nfc->bch) ? "hardware BCH" : "software ECC",
+			chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+		break;
+	case NAND_ECC_NONE:
+		dev_info(dev, "not using ECC\n");
+		break;
+	default:
+		dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
+		return -EINVAL;
+	}
+
+	/* The NAND core will generate the ECC layout for SW ECC */
+	if (chip->ecc.mode != NAND_ECC_HW)
+		return 0;
+
+	/* Generate ECC layout. ECC codes are right aligned in the OOB area. */
+	eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
+
+	if (eccbytes > mtd->oobsize - 2) {
+		dev_err(dev,
+			"invalid ECC config: required %d ECC bytes, but only %d are available",
+			eccbytes, mtd->oobsize - 2);
+		return -EINVAL;
+	}
+
+	mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+
+	return 0;
+}
+
+static int jz4780_nand_init_chip(struct platform_device *pdev,
+				struct jz4780_nand_controller *nfc,
+				struct device_node *np,
+				unsigned int chipnr)
+{
+	struct device *dev = &pdev->dev;
+	struct jz4780_nand_chip *nand;
+	struct jz4780_nand_cs *cs;
+	struct resource *res;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	const __be32 *reg;
+	int ret = 0;
+
+	cs = &nfc->cs[chipnr];
+
+	reg = of_get_property(np, "reg", NULL);
+	if (!reg)
+		return -EINVAL;
+
+	cs->bank = be32_to_cpu(*reg);
+
+	jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr);
+	cs->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cs->base))
+		return PTR_ERR(cs->base);
+
+	nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
+	if (!nand)
+		return -ENOMEM;
+
+	nand->busy_gpio = devm_gpiod_get_optional(dev, "rb", GPIOD_IN);
+
+	if (IS_ERR(nand->busy_gpio)) {
+		ret = PTR_ERR(nand->busy_gpio);
+		dev_err(dev, "failed to request busy GPIO: %d\n", ret);
+		return ret;
+	} else if (nand->busy_gpio) {
+		nand->chip.dev_ready = jz4780_nand_dev_ready;
+	}
+
+	nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
+
+	if (IS_ERR(nand->wp_gpio)) {
+		ret = PTR_ERR(nand->wp_gpio);
+		dev_err(dev, "failed to request WP GPIO: %d\n", ret);
+		return ret;
+	}
+
+	chip = &nand->chip;
+	mtd = nand_to_mtd(chip);
+	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
+				   cs->bank);
+	if (!mtd->name)
+		return -ENOMEM;
+	mtd->dev.parent = dev;
+
+	chip->IO_ADDR_R = cs->base + OFFSET_DATA;
+	chip->IO_ADDR_W = cs->base + OFFSET_DATA;
+	chip->chip_delay = RB_DELAY_US;
+	chip->options = NAND_NO_SUBPAGE_WRITE;
+	chip->select_chip = jz4780_nand_select_chip;
+	chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
+	chip->ecc.mode = NAND_ECC_HW;
+	chip->controller = &nfc->controller;
+	nand_set_flash_node(chip, np);
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		return ret;
+
+	ret = jz4780_nand_init_ecc(nand, dev);
+	if (ret)
+		return ret;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		return ret;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		nand_release(mtd);
+		return ret;
+	}
+
+	list_add_tail(&nand->chip_list, &nfc->chips);
+
+	return 0;
+}
+
+static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
+{
+	struct jz4780_nand_chip *chip;
+
+	while (!list_empty(&nfc->chips)) {
+		chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
+		nand_release(nand_to_mtd(&chip->chip));
+		list_del(&chip->chip_list);
+	}
+}
+
+static int jz4780_nand_init_chips(struct jz4780_nand_controller *nfc,
+				  struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np;
+	int i = 0;
+	int ret;
+	int num_chips = of_get_child_count(dev->of_node);
+
+	if (num_chips > nfc->num_banks) {
+		dev_err(dev, "found %d chips but only %d banks\n", num_chips, nfc->num_banks);
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(dev->of_node, np) {
+		ret = jz4780_nand_init_chip(pdev, nfc, np, i);
+		if (ret) {
+			jz4780_nand_cleanup_chips(nfc);
+			return ret;
+		}
+
+		i++;
+	}
+
+	return 0;
+}
+
+static int jz4780_nand_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	unsigned int num_banks;
+	struct jz4780_nand_controller *nfc;
+	int ret;
+
+	num_banks = jz4780_nemc_num_banks(dev);
+	if (num_banks == 0) {
+		dev_err(dev, "no banks found\n");
+		return -ENODEV;
+	}
+
+	nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	/*
+	 * Check for BCH HW before we call nand_scan_ident, to prevent us from
+	 * having to call it again if the BCH driver returns -EPROBE_DEFER.
+	 */
+	nfc->bch = of_jz4780_bch_get(dev->of_node);
+	if (IS_ERR(nfc->bch))
+		return PTR_ERR(nfc->bch);
+
+	nfc->dev = dev;
+	nfc->num_banks = num_banks;
+
+	nand_hw_control_init(&nfc->controller);
+	INIT_LIST_HEAD(&nfc->chips);
+
+	ret = jz4780_nand_init_chips(nfc, pdev);
+	if (ret) {
+		if (nfc->bch)
+			jz4780_bch_release(nfc->bch);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, nfc);
+	return 0;
+}
+
+static int jz4780_nand_remove(struct platform_device *pdev)
+{
+	struct jz4780_nand_controller *nfc = platform_get_drvdata(pdev);
+
+	if (nfc->bch)
+		jz4780_bch_release(nfc->bch);
+
+	jz4780_nand_cleanup_chips(nfc);
+
+	return 0;
+}
+
+static const struct of_device_id jz4780_nand_dt_match[] = {
+	{ .compatible = "ingenic,jz4780-nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, jz4780_nand_dt_match);
+
+static struct platform_driver jz4780_nand_driver = {
+	.probe		= jz4780_nand_probe,
+	.remove		= jz4780_nand_remove,
+	.driver	= {
+		.name	= DRV_NAME,
+		.of_match_table = of_match_ptr(jz4780_nand_dt_match),
+	},
+};
+module_platform_driver(jz4780_nand_driver);
+
+MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
+MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
new file mode 100644
index 000000000000..e357948a7505
--- /dev/null
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -0,0 +1,909 @@
+/*
+ * Driver for NAND MLC Controller in LPC32xx
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright © 2011 WORK Microwave GmbH
+ * Copyright © 2011, 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * NAND Flash Controller Operation:
+ * - Read: Auto Decode
+ * - Write: Auto Encode
+ * - Tested Page Sizes: 2048, 4096
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/mtd/lpc32xx_mlc.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+
+#define DRV_NAME "lpc32xx_mlc"
+
+/**********************************************************************
+* MLC NAND controller register offsets
+**********************************************************************/
+
+#define MLC_BUFF(x)			(x + 0x00000)
+#define MLC_DATA(x)			(x + 0x08000)
+#define MLC_CMD(x)			(x + 0x10000)
+#define MLC_ADDR(x)			(x + 0x10004)
+#define MLC_ECC_ENC_REG(x)		(x + 0x10008)
+#define MLC_ECC_DEC_REG(x)		(x + 0x1000C)
+#define MLC_ECC_AUTO_ENC_REG(x)		(x + 0x10010)
+#define MLC_ECC_AUTO_DEC_REG(x)		(x + 0x10014)
+#define MLC_RPR(x)			(x + 0x10018)
+#define MLC_WPR(x)			(x + 0x1001C)
+#define MLC_RUBP(x)			(x + 0x10020)
+#define MLC_ROBP(x)			(x + 0x10024)
+#define MLC_SW_WP_ADD_LOW(x)		(x + 0x10028)
+#define MLC_SW_WP_ADD_HIG(x)		(x + 0x1002C)
+#define MLC_ICR(x)			(x + 0x10030)
+#define MLC_TIME_REG(x)			(x + 0x10034)
+#define MLC_IRQ_MR(x)			(x + 0x10038)
+#define MLC_IRQ_SR(x)			(x + 0x1003C)
+#define MLC_LOCK_PR(x)			(x + 0x10044)
+#define MLC_ISR(x)			(x + 0x10048)
+#define MLC_CEH(x)			(x + 0x1004C)
+
+/**********************************************************************
+* MLC_CMD bit definitions
+**********************************************************************/
+#define MLCCMD_RESET			0xFF
+
+/**********************************************************************
+* MLC_ICR bit definitions
+**********************************************************************/
+#define MLCICR_WPROT			(1 << 3)
+#define MLCICR_LARGEBLOCK		(1 << 2)
+#define MLCICR_LONGADDR			(1 << 1)
+#define MLCICR_16BIT			(1 << 0)  /* unsupported by LPC32x0! */
+
+/**********************************************************************
+* MLC_TIME_REG bit definitions
+**********************************************************************/
+#define MLCTIMEREG_TCEA_DELAY(n)	(((n) & 0x03) << 24)
+#define MLCTIMEREG_BUSY_DELAY(n)	(((n) & 0x1F) << 19)
+#define MLCTIMEREG_NAND_TA(n)		(((n) & 0x07) << 16)
+#define MLCTIMEREG_RD_HIGH(n)		(((n) & 0x0F) << 12)
+#define MLCTIMEREG_RD_LOW(n)		(((n) & 0x0F) << 8)
+#define MLCTIMEREG_WR_HIGH(n)		(((n) & 0x0F) << 4)
+#define MLCTIMEREG_WR_LOW(n)		(((n) & 0x0F) << 0)
+
+/**********************************************************************
+* MLC_IRQ_MR and MLC_IRQ_SR bit definitions
+**********************************************************************/
+#define MLCIRQ_NAND_READY		(1 << 5)
+#define MLCIRQ_CONTROLLER_READY		(1 << 4)
+#define MLCIRQ_DECODE_FAILURE		(1 << 3)
+#define MLCIRQ_DECODE_ERROR		(1 << 2)
+#define MLCIRQ_ECC_READY		(1 << 1)
+#define MLCIRQ_WRPROT_FAULT		(1 << 0)
+
+/**********************************************************************
+* MLC_LOCK_PR bit definitions
+**********************************************************************/
+#define MLCLOCKPR_MAGIC			0xA25E
+
+/**********************************************************************
+* MLC_ISR bit definitions
+**********************************************************************/
+#define MLCISR_DECODER_FAILURE		(1 << 6)
+#define MLCISR_ERRORS			((1 << 4) | (1 << 5))
+#define MLCISR_ERRORS_DETECTED		(1 << 3)
+#define MLCISR_ECC_READY		(1 << 2)
+#define MLCISR_CONTROLLER_READY		(1 << 1)
+#define MLCISR_NAND_READY		(1 << 0)
+
+/**********************************************************************
+* MLC_CEH bit definitions
+**********************************************************************/
+#define MLCCEH_NORMAL			(1 << 0)
+
+struct lpc32xx_nand_cfg_mlc {
+	uint32_t tcea_delay;
+	uint32_t busy_delay;
+	uint32_t nand_ta;
+	uint32_t rd_high;
+	uint32_t rd_low;
+	uint32_t wr_high;
+	uint32_t wr_low;
+	int wp_gpio;
+	struct mtd_partition *parts;
+	unsigned num_parts;
+};
+
+static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = ((section + 1) * 16) - nand_chip->ecc.bytes;
+	oobregion->length = nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = 16 * section;
+	oobregion->length = 16 - nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+	.ecc = lpc32xx_ooblayout_ecc,
+	.free = lpc32xx_ooblayout_free,
+};
+
+static struct nand_bbt_descr lpc32xx_nand_bbt = {
+	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+		   NAND_BBT_WRITE,
+	.pages = { 524224, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
+	.options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+		   NAND_BBT_WRITE,
+	.pages = { 524160, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+struct lpc32xx_nand_host {
+	struct nand_chip	nand_chip;
+	struct lpc32xx_mlc_platform_data *pdata;
+	struct clk		*clk;
+	void __iomem		*io_base;
+	int			irq;
+	struct lpc32xx_nand_cfg_mlc	*ncfg;
+	struct completion       comp_nand;
+	struct completion       comp_controller;
+	uint32_t llptr;
+	/*
+	 * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer
+	 */
+	dma_addr_t		oob_buf_phy;
+	/*
+	 * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer
+	 */
+	uint8_t			*oob_buf;
+	/* Physical address of DMA base address */
+	dma_addr_t		io_base_phy;
+
+	struct completion	comp_dma;
+	struct dma_chan		*dma_chan;
+	struct dma_slave_config	dma_slave_config;
+	struct scatterlist	sgl;
+	uint8_t			*dma_buf;
+	uint8_t			*dummy_buf;
+	int			mlcsubpages; /* number of 512bytes-subpages */
+};
+
+/*
+ * Activate/Deactivate DMA Operation:
+ *
+ * Using the PL080 DMA Controller for transferring the 512 byte subpages
+ * instead of doing readl() / writel() in a loop slows it down significantly.
+ * Measurements via getnstimeofday() upon 512 byte subpage reads reveal:
+ *
+ * - readl() of 128 x 32 bits in a loop: ~20us
+ * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us
+ * - DMA read of 512 bytes (32 bit, no bursts): ~100us
+ *
+ * This applies to the transfer itself. In the DMA case: only the
+ * wait_for_completion() (DMA setup _not_ included).
+ *
+ * Note that the 512 bytes subpage transfer is done directly from/to a
+ * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a
+ * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND
+ * controller transferring data between its internal buffer to/from the NAND
+ * chip.)
+ *
+ * Therefore, using the PL080 DMA is disabled by default, for now.
+ *
+ */
+static int use_dma;
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+	uint32_t clkrate, tmp;
+
+	/* Reset MLC controller */
+	writel(MLCCMD_RESET, MLC_CMD(host->io_base));
+	udelay(1000);
+
+	/* Get base clock for MLC block */
+	clkrate = clk_get_rate(host->clk);
+	if (clkrate == 0)
+		clkrate = 104000000;
+
+	/* Unlock MLC_ICR
+	 * (among others, will be locked again automatically) */
+	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+
+	/* Configure MLC Controller: Large Block, 5 Byte Address */
+	tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR;
+	writel(tmp, MLC_ICR(host->io_base));
+
+	/* Unlock MLC_TIME_REG
+	 * (among others, will be locked again automatically) */
+	writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+
+	/* Compute clock setup values, see LPC and NAND manual */
+	tmp = 0;
+	tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1);
+	tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1);
+	tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1);
+	tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1);
+	tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low);
+	tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1);
+	tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low);
+	writel(tmp, MLC_TIME_REG(host->io_base));
+
+	/* Enable IRQ for CONTROLLER_READY and NAND_READY */
+	writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY,
+			MLC_IRQ_MR(host->io_base));
+
+	/* Normal nCE operation: nCE controlled by controller */
+	writel(MLCCEH_NORMAL, MLC_CEH(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				  unsigned int ctrl)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
+
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE)
+			writel(cmd, MLC_CMD(host->io_base));
+		else
+			writel(cmd, MLC_ADDR(host->io_base));
+	}
+}
+
+/*
+ * Read Device Ready (NAND device _and_ controller ready)
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
+
+	if ((readb(MLC_ISR(host->io_base)) &
+	     (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
+	    (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY))
+		return  1;
+
+	return 0;
+}
+
+static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
+{
+	uint8_t sr;
+
+	/* Clear interrupt flag by reading status */
+	sr = readb(MLC_IRQ_SR(host->io_base));
+	if (sr & MLCIRQ_NAND_READY)
+		complete(&host->comp_nand);
+	if (sr & MLCIRQ_CONTROLLER_READY)
+		complete(&host->comp_controller);
+
+	return IRQ_HANDLED;
+}
+
+static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
+		goto exit;
+
+	wait_for_completion(&host->comp_nand);
+
+	while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) {
+		/* Seems to be delayed sometimes by controller */
+		dev_dbg(&mtd->dev, "Warning: NAND not ready.\n");
+		cpu_relax();
+	}
+
+exit:
+	return NAND_STATUS_READY;
+}
+
+static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
+				       struct nand_chip *chip)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
+		goto exit;
+
+	wait_for_completion(&host->comp_controller);
+
+	while (!(readb(MLC_ISR(host->io_base)) &
+		 MLCISR_CONTROLLER_READY)) {
+		dev_dbg(&mtd->dev, "Warning: Controller not ready.\n");
+		cpu_relax();
+	}
+
+exit:
+	return NAND_STATUS_READY;
+}
+
+static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	lpc32xx_waitfunc_nand(mtd, chip);
+	lpc32xx_waitfunc_controller(mtd, chip);
+
+	return NAND_STATUS_READY;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+	if (gpio_is_valid(host->ncfg->wp_gpio))
+		gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+	if (gpio_is_valid(host->ncfg->wp_gpio))
+		gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+	complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len,
+			    enum dma_transfer_direction dir)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	struct dma_async_tx_descriptor *desc;
+	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+	int res;
+
+	sg_init_one(&host->sgl, mem, len);
+
+	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+			 DMA_BIDIRECTIONAL);
+	if (res != 1) {
+		dev_err(mtd->dev.parent, "Failed to map sg list\n");
+		return -ENXIO;
+	}
+	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+				       flags);
+	if (!desc) {
+		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+		goto out1;
+	}
+
+	init_completion(&host->comp_dma);
+	desc->callback = lpc32xx_dma_complete_func;
+	desc->callback_param = &host->comp_dma;
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(host->dma_chan);
+
+	wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
+
+	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+		     DMA_BIDIRECTIONAL);
+	return 0;
+out1:
+	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+		     DMA_BIDIRECTIONAL);
+	return -ENXIO;
+}
+
+static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			     uint8_t *buf, int oob_required, int page)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	int i, j;
+	uint8_t *oobbuf = chip->oob_poi;
+	uint32_t mlc_isr;
+	int res;
+	uint8_t *dma_buf;
+	bool dma_mapped;
+
+	if ((void *)buf <= high_memory) {
+		dma_buf = buf;
+		dma_mapped = true;
+	} else {
+		dma_buf = host->dma_buf;
+		dma_mapped = false;
+	}
+
+	/* Writing Command and Address */
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	/* For all sub-pages */
+	for (i = 0; i < host->mlcsubpages; i++) {
+		/* Start Auto Decode Command */
+		writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
+
+		/* Wait for Controller Ready */
+		lpc32xx_waitfunc_controller(mtd, chip);
+
+		/* Check ECC Error status */
+		mlc_isr = readl(MLC_ISR(host->io_base));
+		if (mlc_isr & MLCISR_DECODER_FAILURE) {
+			mtd->ecc_stats.failed++;
+			dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__);
+		} else if (mlc_isr & MLCISR_ERRORS_DETECTED) {
+			mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1;
+		}
+
+		/* Read 512 + 16 Bytes */
+		if (use_dma) {
+			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+					       DMA_DEV_TO_MEM);
+			if (res)
+				return res;
+		} else {
+			for (j = 0; j < (512 >> 2); j++) {
+				*((uint32_t *)(buf)) =
+					readl(MLC_BUFF(host->io_base));
+				buf += 4;
+			}
+		}
+		for (j = 0; j < (16 >> 2); j++) {
+			*((uint32_t *)(oobbuf)) =
+				readl(MLC_BUFF(host->io_base));
+			oobbuf += 4;
+		}
+	}
+
+	if (use_dma && !dma_mapped)
+		memcpy(buf, dma_buf, mtd->writesize);
+
+	return 0;
+}
+
+static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
+				       struct nand_chip *chip,
+				       const uint8_t *buf, int oob_required,
+				       int page)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	const uint8_t *oobbuf = chip->oob_poi;
+	uint8_t *dma_buf = (uint8_t *)buf;
+	int res;
+	int i, j;
+
+	if (use_dma && (void *)buf >= high_memory) {
+		dma_buf = host->dma_buf;
+		memcpy(dma_buf, buf, mtd->writesize);
+	}
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	for (i = 0; i < host->mlcsubpages; i++) {
+		/* Start Encode */
+		writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
+
+		/* Write 512 + 6 Bytes to Buffer */
+		if (use_dma) {
+			res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+					       DMA_MEM_TO_DEV);
+			if (res)
+				return res;
+		} else {
+			for (j = 0; j < (512 >> 2); j++) {
+				writel(*((uint32_t *)(buf)),
+				       MLC_BUFF(host->io_base));
+				buf += 4;
+			}
+		}
+		writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base));
+		oobbuf += 4;
+		writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base));
+		oobbuf += 12;
+
+		/* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */
+		writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
+
+		/* Wait for Controller Ready */
+		lpc32xx_waitfunc_controller(mtd, chip);
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	/* Read whole page - necessary with MLC controller! */
+	lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+
+	return 0;
+}
+
+static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			      int page)
+{
+	/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
+	return 0;
+}
+
+/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
+static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+{
+	/* Always enabled! */
+}
+
+static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
+{
+	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	dma_cap_mask_t mask;
+
+	if (!host->pdata || !host->pdata->dma_filter) {
+		dev_err(mtd->dev.parent, "no DMA platform data\n");
+		return -ENOENT;
+	}
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
+					     "nand-mlc");
+	if (!host->dma_chan) {
+		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Set direction to a sensible value even if the dmaengine driver
+	 * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x
+	 * driver criticizes it as "alien transfer direction".
+	 */
+	host->dma_slave_config.direction = DMA_DEV_TO_MEM;
+	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_slave_config.src_maxburst = 128;
+	host->dma_slave_config.dst_maxburst = 128;
+	/* DMA controller does flow control: */
+	host->dma_slave_config.device_fc = false;
+	host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy);
+	host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy);
+	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+		goto out1;
+	}
+
+	return 0;
+out1:
+	dma_release_channel(host->dma_chan);
+	return -ENXIO;
+}
+
+static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
+{
+	struct lpc32xx_nand_cfg_mlc *ncfg;
+	struct device_node *np = dev->of_node;
+
+	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
+	if (!ncfg)
+		return NULL;
+
+	of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
+	of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
+	of_property_read_u32(np, "nxp,nand-ta", &ncfg->nand_ta);
+	of_property_read_u32(np, "nxp,rd-high", &ncfg->rd_high);
+	of_property_read_u32(np, "nxp,rd-low", &ncfg->rd_low);
+	of_property_read_u32(np, "nxp,wr-high", &ncfg->wr_high);
+	of_property_read_u32(np, "nxp,wr-low", &ncfg->wr_low);
+
+	if (!ncfg->tcea_delay || !ncfg->busy_delay || !ncfg->nand_ta ||
+	    !ncfg->rd_high || !ncfg->rd_low || !ncfg->wr_high ||
+	    !ncfg->wr_low) {
+		dev_err(dev, "chip parameters not specified correctly\n");
+		return NULL;
+	}
+
+	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+
+	return ncfg;
+}
+
+/*
+ * Probe for NAND controller
+ */
+static int lpc32xx_nand_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_chip;
+	struct resource *rc;
+	int res;
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
+	if (IS_ERR(host->io_base))
+		return PTR_ERR(host->io_base);
+	
+	host->io_base_phy = rc->start;
+
+	nand_chip = &host->nand_chip;
+	mtd = nand_to_mtd(nand_chip);
+	if (pdev->dev.of_node)
+		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+	if (!host->ncfg) {
+		dev_err(&pdev->dev,
+			"Missing or bad NAND config from device tree\n");
+		return -ENOENT;
+	}
+	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (gpio_is_valid(host->ncfg->wp_gpio) &&
+			gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+		dev_err(&pdev->dev, "GPIO not available\n");
+		return -EBUSY;
+	}
+	lpc32xx_wp_disable(host);
+
+	host->pdata = dev_get_platdata(&pdev->dev);
+
+	/* link the private data structures */
+	nand_set_controller_data(nand_chip, host);
+	nand_set_flash_node(nand_chip, pdev->dev.of_node);
+	mtd->dev.parent = &pdev->dev;
+
+	/* Get NAND clock */
+	host->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk)) {
+		dev_err(&pdev->dev, "Clock initialization failure\n");
+		res = -ENOENT;
+		goto err_exit1;
+	}
+	res = clk_prepare_enable(host->clk);
+	if (res)
+		goto err_put_clk;
+
+	nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+	nand_chip->dev_ready = lpc32xx_nand_device_ready;
+	nand_chip->chip_delay = 25; /* us */
+	nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
+	nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+
+	/* Init NAND controller */
+	lpc32xx_nand_setup(host);
+
+	platform_set_drvdata(pdev, host);
+
+	/* Initialize function pointers */
+	nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
+	nand_chip->ecc.read_page_raw = lpc32xx_read_page;
+	nand_chip->ecc.read_page = lpc32xx_read_page;
+	nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel;
+	nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel;
+	nand_chip->ecc.write_oob = lpc32xx_write_oob;
+	nand_chip->ecc.read_oob = lpc32xx_read_oob;
+	nand_chip->ecc.strength = 4;
+	nand_chip->ecc.bytes = 10;
+	nand_chip->waitfunc = lpc32xx_waitfunc;
+
+	nand_chip->options = NAND_NO_SUBPAGE_WRITE;
+	nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+	nand_chip->bbt_td = &lpc32xx_nand_bbt;
+	nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
+
+	if (use_dma) {
+		res = lpc32xx_dma_setup(host);
+		if (res) {
+			res = -EIO;
+			goto err_exit2;
+		}
+	}
+
+	/*
+	 * Scan to find existance of the device and
+	 * Get the type of NAND device SMALL block or LARGE block
+	 */
+	res = nand_scan_ident(mtd, 1, NULL);
+	if (res)
+		goto err_exit3;
+
+	host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+	if (!host->dma_buf) {
+		res = -ENOMEM;
+		goto err_exit3;
+	}
+
+	host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+	if (!host->dummy_buf) {
+		res = -ENOMEM;
+		goto err_exit3;
+	}
+
+	nand_chip->ecc.mode = NAND_ECC_HW;
+	nand_chip->ecc.size = 512;
+	mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+	host->mlcsubpages = mtd->writesize / 512;
+
+	/* initially clear interrupt status */
+	readb(MLC_IRQ_SR(host->io_base));
+
+	init_completion(&host->comp_nand);
+	init_completion(&host->comp_controller);
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0) {
+		dev_err(&pdev->dev, "failed to get platform irq\n");
+		res = -EINVAL;
+		goto err_exit3;
+	}
+
+	if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
+			IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
+		dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
+		res = -ENXIO;
+		goto err_exit3;
+	}
+
+	/*
+	 * Fills out all the uninitialized function pointers with the defaults
+	 * And scans for a bad block table if appropriate.
+	 */
+	res = nand_scan_tail(mtd);
+	if (res)
+		goto err_exit4;
+
+	mtd->name = DRV_NAME;
+
+	res = mtd_device_register(mtd, host->ncfg->parts,
+				  host->ncfg->num_parts);
+	if (!res)
+		return res;
+
+	nand_release(mtd);
+
+err_exit4:
+	free_irq(host->irq, host);
+err_exit3:
+	if (use_dma)
+		dma_release_channel(host->dma_chan);
+err_exit2:
+	clk_disable_unprepare(host->clk);
+err_put_clk:
+	clk_put(host->clk);
+err_exit1:
+	lpc32xx_wp_enable(host);
+	gpio_free(host->ncfg->wp_gpio);
+
+	return res;
+}
+
+/*
+ * Remove NAND device
+ */
+static int lpc32xx_nand_remove(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+
+	nand_release(mtd);
+	free_irq(host->irq, host);
+	if (use_dma)
+		dma_release_channel(host->dma_chan);
+
+	clk_disable_unprepare(host->clk);
+	clk_put(host->clk);
+
+	lpc32xx_wp_enable(host);
+	gpio_free(host->ncfg->wp_gpio);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+	int ret;
+
+	/* Re-enable NAND clock */
+	ret = clk_prepare_enable(host->clk);
+	if (ret)
+		return ret;
+
+	/* Fresh init of NAND controller */
+	lpc32xx_nand_setup(host);
+
+	/* Disable write protect */
+	lpc32xx_wp_disable(host);
+
+	return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+	/* Enable write protect for safety */
+	lpc32xx_wp_enable(host);
+
+	/* Disable clock */
+	clk_disable_unprepare(host->clk);
+	return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+static const struct of_device_id lpc32xx_nand_match[] = {
+	{ .compatible = "nxp,lpc3220-mlc" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+
+static struct platform_driver lpc32xx_nand_driver = {
+	.probe		= lpc32xx_nand_probe,
+	.remove		= lpc32xx_nand_remove,
+	.resume		= lpc32xx_nand_resume,
+	.suspend	= lpc32xx_nand_suspend,
+	.driver		= {
+		.name	= DRV_NAME,
+		.of_match_table = lpc32xx_nand_match,
+	},
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller");
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
new file mode 100644
index 000000000000..5f7cc6da0a7f
--- /dev/null
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -0,0 +1,1032 @@
+/*
+ * NXP LPC32XX NAND SLC driver
+ *
+ * Authors:
+ *    Kevin Wells <kevin.wells@nxp.com>
+ *    Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright © 2011 NXP Semiconductors
+ * Copyright © 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/mtd/lpc32xx_slc.h>
+
+#define LPC32XX_MODNAME		"lpc32xx-nand"
+
+/**********************************************************************
+* SLC NAND controller register offsets
+**********************************************************************/
+
+#define SLC_DATA(x)		(x + 0x000)
+#define SLC_ADDR(x)		(x + 0x004)
+#define SLC_CMD(x)		(x + 0x008)
+#define SLC_STOP(x)		(x + 0x00C)
+#define SLC_CTRL(x)		(x + 0x010)
+#define SLC_CFG(x)		(x + 0x014)
+#define SLC_STAT(x)		(x + 0x018)
+#define SLC_INT_STAT(x)		(x + 0x01C)
+#define SLC_IEN(x)		(x + 0x020)
+#define SLC_ISR(x)		(x + 0x024)
+#define SLC_ICR(x)		(x + 0x028)
+#define SLC_TAC(x)		(x + 0x02C)
+#define SLC_TC(x)		(x + 0x030)
+#define SLC_ECC(x)		(x + 0x034)
+#define SLC_DMA_DATA(x)		(x + 0x038)
+
+/**********************************************************************
+* slc_ctrl register definitions
+**********************************************************************/
+#define SLCCTRL_SW_RESET	(1 << 2) /* Reset the NAND controller bit */
+#define SLCCTRL_ECC_CLEAR	(1 << 1) /* Reset ECC bit */
+#define SLCCTRL_DMA_START	(1 << 0) /* Start DMA channel bit */
+
+/**********************************************************************
+* slc_cfg register definitions
+**********************************************************************/
+#define SLCCFG_CE_LOW		(1 << 5) /* Force CE low bit */
+#define SLCCFG_DMA_ECC		(1 << 4) /* Enable DMA ECC bit */
+#define SLCCFG_ECC_EN		(1 << 3) /* ECC enable bit */
+#define SLCCFG_DMA_BURST	(1 << 2) /* DMA burst bit */
+#define SLCCFG_DMA_DIR		(1 << 1) /* DMA write(0)/read(1) bit */
+#define SLCCFG_WIDTH		(1 << 0) /* External device width, 0=8bit */
+
+/**********************************************************************
+* slc_stat register definitions
+**********************************************************************/
+#define SLCSTAT_DMA_FIFO	(1 << 2) /* DMA FIFO has data bit */
+#define SLCSTAT_SLC_FIFO	(1 << 1) /* SLC FIFO has data bit */
+#define SLCSTAT_NAND_READY	(1 << 0) /* NAND device is ready bit */
+
+/**********************************************************************
+* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
+**********************************************************************/
+#define SLCSTAT_INT_TC		(1 << 1) /* Transfer count bit */
+#define SLCSTAT_INT_RDY_EN	(1 << 0) /* Ready interrupt bit */
+
+/**********************************************************************
+* slc_tac register definitions
+**********************************************************************/
+/* Computation of clock cycles on basis of controller and device clock rates */
+#define SLCTAC_CLOCKS(c, n, s)	(min_t(u32, DIV_ROUND_UP(c, n) - 1, 0xF) << s)
+
+/* Clock setting for RDY write sample wait time in 2*n clocks */
+#define SLCTAC_WDR(n)		(((n) & 0xF) << 28)
+/* Write pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_WWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 24))
+/* Write hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 20))
+/* Write setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 16))
+/* Clock setting for RDY read sample wait time in 2*n clocks */
+#define SLCTAC_RDR(n)		(((n) & 0xF) << 12)
+/* Read pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_RWIDTH(c, n)	(SLCTAC_CLOCKS(c, n, 8))
+/* Read hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RHOLD(c, n)	(SLCTAC_CLOCKS(c, n, 4))
+/* Read setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RSETUP(c, n)	(SLCTAC_CLOCKS(c, n, 0))
+
+/**********************************************************************
+* slc_ecc register definitions
+**********************************************************************/
+/* ECC line party fetch macro */
+#define SLCECC_TO_LINEPAR(n)	(((n) >> 6) & 0x7FFF)
+#define SLCECC_TO_COLPAR(n)	((n) & 0x3F)
+
+/*
+ * DMA requires storage space for the DMA local buffer and the hardware ECC
+ * storage area. The DMA local buffer is only used if DMA mapping fails
+ * during runtime.
+ */
+#define LPC32XX_DMA_DATA_SIZE		4096
+#define LPC32XX_ECC_SAVE_SIZE		((4096 / 256) * 4)
+
+/* Number of bytes used for ECC stored in NAND per 256 bytes */
+#define LPC32XX_SLC_DEV_ECC_BYTES	3
+
+/*
+ * If the NAND base clock frequency can't be fetched, this frequency will be
+ * used instead as the base. This rate is used to setup the timing registers
+ * used for NAND accesses.
+ */
+#define LPC32XX_DEF_BUS_RATE		133250000
+
+/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
+#define LPC32XX_DMA_TIMEOUT		100
+
+/*
+ * NAND ECC Layout for small page NAND devices
+ * Note: For large and huge page devices, the default layouts are used
+ */
+static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = 6;
+	oobregion->offset = 10;
+
+	return 0;
+}
+
+static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		oobregion->length = 4;
+	} else {
+		oobregion->offset = 6;
+		oobregion->length = 4;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
+	.ecc = lpc32xx_ooblayout_ecc,
+	.free = lpc32xx_ooblayout_free,
+};
+
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+/*
+ * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
+ * Note: Large page devices used the default layout
+ */
+static struct nand_bbt_descr bbt_smallpage_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	0,
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	0,
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = mirror_pattern
+};
+
+/*
+ * NAND platform configuration structure
+ */
+struct lpc32xx_nand_cfg_slc {
+	uint32_t wdr_clks;
+	uint32_t wwidth;
+	uint32_t whold;
+	uint32_t wsetup;
+	uint32_t rdr_clks;
+	uint32_t rwidth;
+	uint32_t rhold;
+	uint32_t rsetup;
+	int wp_gpio;
+	struct mtd_partition *parts;
+	unsigned num_parts;
+};
+
+struct lpc32xx_nand_host {
+	struct nand_chip	nand_chip;
+	struct lpc32xx_slc_platform_data *pdata;
+	struct clk		*clk;
+	void __iomem		*io_base;
+	struct lpc32xx_nand_cfg_slc *ncfg;
+
+	struct completion	comp;
+	struct dma_chan		*dma_chan;
+	uint32_t		dma_buf_len;
+	struct dma_slave_config	dma_slave_config;
+	struct scatterlist	sgl;
+
+	/*
+	 * DMA and CPU addresses of ECC work area and data buffer
+	 */
+	uint32_t		*ecc_buf;
+	uint8_t			*data_buf;
+	dma_addr_t		io_base_dma;
+};
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+	uint32_t clkrate, tmp;
+
+	/* Reset SLC controller */
+	writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
+	udelay(1000);
+
+	/* Basic setup */
+	writel(0, SLC_CFG(host->io_base));
+	writel(0, SLC_IEN(host->io_base));
+	writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
+		SLC_ICR(host->io_base));
+
+	/* Get base clock for SLC block */
+	clkrate = clk_get_rate(host->clk);
+	if (clkrate == 0)
+		clkrate = LPC32XX_DEF_BUS_RATE;
+
+	/* Compute clock setup values */
+	tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
+		SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) |
+		SLCTAC_WHOLD(clkrate, host->ncfg->whold) |
+		SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) |
+		SLCTAC_RDR(host->ncfg->rdr_clks) |
+		SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) |
+		SLCTAC_RHOLD(clkrate, host->ncfg->rhold) |
+		SLCTAC_RSETUP(clkrate, host->ncfg->rsetup);
+	writel(tmp, SLC_TAC(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+	unsigned int ctrl)
+{
+	uint32_t tmp;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	/* Does CE state need to be changed? */
+	tmp = readl(SLC_CFG(host->io_base));
+	if (ctrl & NAND_NCE)
+		tmp |= SLCCFG_CE_LOW;
+	else
+		tmp &= ~SLCCFG_CE_LOW;
+	writel(tmp, SLC_CFG(host->io_base));
+
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE)
+			writel(cmd, SLC_CMD(host->io_base));
+		else
+			writel(cmd, SLC_ADDR(host->io_base));
+	}
+}
+
+/*
+ * Read the Device Ready pin
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	int rdy = 0;
+
+	if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
+		rdy = 1;
+
+	return rdy;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+	if (gpio_is_valid(host->ncfg->wp_gpio))
+		gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+	if (gpio_is_valid(host->ncfg->wp_gpio))
+		gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+/*
+ * Prepares SLC for transfers with H/W ECC enabled
+ */
+static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+{
+	/* Hardware ECC is enabled automatically in hardware as needed */
+}
+
+/*
+ * Calculates the ECC for the data
+ */
+static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+				      const unsigned char *buf,
+				      unsigned char *code)
+{
+	/*
+	 * ECC is calculated automatically in hardware during syndrome read
+	 * and write operations, so it doesn't need to be calculated here.
+	 */
+	return 0;
+}
+
+/*
+ * Read a single byte from NAND device
+ */
+static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	return (uint8_t)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device read without ECC
+ */
+static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	/* Direct device read with no ECC */
+	while (len-- > 0)
+		*buf++ = (uint8_t)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device write without ECC
+ */
+static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+	/* Direct device write with no ECC */
+	while (len-- > 0)
+		writel((uint32_t)*buf++, SLC_DATA(host->io_base));
+}
+
+/*
+ * Read the OOB data from the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
+					  struct nand_chip *chip, int page)
+{
+	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
+}
+
+/*
+ * Write the OOB data to the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
+	struct nand_chip *chip, int page)
+{
+	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
+				 mtd->oobsize);
+}
+
+/*
+ * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
+ */
+static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count)
+{
+	int i;
+
+	for (i = 0; i < (count * 3); i += 3) {
+		uint32_t ce = ecc[i / 3];
+		ce = ~(ce << 2) & 0xFFFFFF;
+		spare[i + 2] = (uint8_t)(ce & 0xFF);
+		ce >>= 8;
+		spare[i + 1] = (uint8_t)(ce & 0xFF);
+		ce >>= 8;
+		spare[i] = (uint8_t)(ce & 0xFF);
+	}
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+	complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
+			    void *mem, int len, enum dma_transfer_direction dir)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	struct dma_async_tx_descriptor *desc;
+	int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+	int res;
+
+	host->dma_slave_config.direction = dir;
+	host->dma_slave_config.src_addr = dma;
+	host->dma_slave_config.dst_addr = dma;
+	host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_slave_config.src_maxburst = 4;
+	host->dma_slave_config.dst_maxburst = 4;
+	/* DMA controller does flow control: */
+	host->dma_slave_config.device_fc = false;
+	if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+		dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+		return -ENXIO;
+	}
+
+	sg_init_one(&host->sgl, mem, len);
+
+	res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+			 DMA_BIDIRECTIONAL);
+	if (res != 1) {
+		dev_err(mtd->dev.parent, "Failed to map sg list\n");
+		return -ENXIO;
+	}
+	desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+				       flags);
+	if (!desc) {
+		dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+		goto out1;
+	}
+
+	init_completion(&host->comp);
+	desc->callback = lpc32xx_dma_complete_func;
+	desc->callback_param = &host->comp;
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(host->dma_chan);
+
+	wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
+
+	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+		     DMA_BIDIRECTIONAL);
+
+	return 0;
+out1:
+	dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+		     DMA_BIDIRECTIONAL);
+	return -ENXIO;
+}
+
+/*
+ * DMA read/write transfers with ECC support
+ */
+static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
+			int read)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	int i, status = 0;
+	unsigned long timeout;
+	int res;
+	enum dma_transfer_direction dir =
+		read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+	uint8_t *dma_buf;
+	bool dma_mapped;
+
+	if ((void *)buf <= high_memory) {
+		dma_buf = buf;
+		dma_mapped = true;
+	} else {
+		dma_buf = host->data_buf;
+		dma_mapped = false;
+		if (!read)
+			memcpy(host->data_buf, buf, mtd->writesize);
+	}
+
+	if (read) {
+		writel(readl(SLC_CFG(host->io_base)) |
+		       SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+		       SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
+	} else {
+		writel((readl(SLC_CFG(host->io_base)) |
+			SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
+		       ~SLCCFG_DMA_DIR,
+			SLC_CFG(host->io_base));
+	}
+
+	/* Clear initial ECC */
+	writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
+
+	/* Transfer size is data area only */
+	writel(mtd->writesize, SLC_TC(host->io_base));
+
+	/* Start transfer in the NAND controller */
+	writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
+	       SLC_CTRL(host->io_base));
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		/* Data */
+		res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
+				       dma_buf + i * chip->ecc.size,
+				       mtd->writesize / chip->ecc.steps, dir);
+		if (res)
+			return res;
+
+		/* Always _read_ ECC */
+		if (i == chip->ecc.steps - 1)
+			break;
+		if (!read) /* ECC availability delayed on write */
+			udelay(10);
+		res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
+				       &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
+		if (res)
+			return res;
+	}
+
+	/*
+	 * According to NXP, the DMA can be finished here, but the NAND
+	 * controller may still have buffered data. After porting to using the
+	 * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
+	 * appears to be always true, according to tests. Keeping the check for
+	 * safety reasons for now.
+	 */
+	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
+		dev_warn(mtd->dev.parent, "FIFO not empty!\n");
+		timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
+		while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
+		       time_before(jiffies, timeout))
+			cpu_relax();
+		if (!time_before(jiffies, timeout)) {
+			dev_err(mtd->dev.parent, "FIFO held data too long\n");
+			status = -EIO;
+		}
+	}
+
+	/* Read last calculated ECC value */
+	if (!read)
+		udelay(10);
+	host->ecc_buf[chip->ecc.steps - 1] =
+		readl(SLC_ECC(host->io_base));
+
+	/* Flush DMA */
+	dmaengine_terminate_all(host->dma_chan);
+
+	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
+	    readl(SLC_TC(host->io_base))) {
+		/* Something is left in the FIFO, something is wrong */
+		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
+		status = -EIO;
+	}
+
+	/* Stop DMA & HW ECC */
+	writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
+	       SLC_CTRL(host->io_base));
+	writel(readl(SLC_CFG(host->io_base)) &
+	       ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+		 SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
+
+	if (!dma_mapped && read)
+		memcpy(buf, host->data_buf, mtd->writesize);
+
+	return status;
+}
+
+/*
+ * Read the data and OOB data from the device, use ECC correction with the
+ * data, disable ECC for the OOB data
+ */
+static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
+					   struct nand_chip *chip, uint8_t *buf,
+					   int oob_required, int page)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	struct mtd_oob_region oobregion = { };
+	int stat, i, status, error;
+	uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
+
+	/* Issue read command */
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	/* Read data and oob, calculate ECC */
+	status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
+
+	/* Get OOB data */
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* Convert to stored ECC format */
+	lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
+
+	/* Pointer to ECC data retrieved from NAND spare area */
+	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	if (error)
+		return error;
+
+	oobecc = chip->oob_poi + oobregion.offset;
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		stat = chip->ecc.correct(mtd, buf, oobecc,
+					 &tmpecc[i * chip->ecc.bytes]);
+		if (stat < 0)
+			mtd->ecc_stats.failed++;
+		else
+			mtd->ecc_stats.corrected += stat;
+
+		buf += chip->ecc.size;
+		oobecc += chip->ecc.bytes;
+	}
+
+	return status;
+}
+
+/*
+ * Read the data and OOB data from the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
+					       struct nand_chip *chip,
+					       uint8_t *buf, int oob_required,
+					       int page)
+{
+	/* Issue read command */
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	/* Raw reads can just use the FIFO interface */
+	chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return 0;
+}
+
+/*
+ * Write the data and OOB data to the device, use ECC with the data,
+ * disable ECC for the OOB data
+ */
+static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    const uint8_t *buf,
+					    int oob_required, int page)
+{
+	struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+	struct mtd_oob_region oobregion = { };
+	uint8_t *pb;
+	int error;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	/* Write data, calculate ECC on outbound data */
+	error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
+	if (error)
+		return error;
+
+	/*
+	 * The calculated ECC needs some manual work done to it before
+	 * committing it to NAND. Process the calculated ECC and place
+	 * the resultant values directly into the OOB buffer. */
+	error = mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	if (error)
+		return error;
+
+	pb = chip->oob_poi + oobregion.offset;
+	lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
+
+	/* Write ECC data to device */
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+/*
+ * Write the data and OOB data to the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
+						struct nand_chip *chip,
+						const uint8_t *buf,
+						int oob_required, int page)
+{
+	/* Raw writes can just use the FIFO interface */
+	nand_prog_page_begin_op(chip, page, 0, buf,
+				chip->ecc.size * chip->ecc.steps);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
+{
+	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+	dma_cap_mask_t mask;
+
+	if (!host->pdata || !host->pdata->dma_filter) {
+		dev_err(mtd->dev.parent, "no DMA platform data\n");
+		return -ENOENT;
+	}
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter,
+					     "nand-slc");
+	if (!host->dma_chan) {
+		dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+{
+	struct lpc32xx_nand_cfg_slc *ncfg;
+	struct device_node *np = dev->of_node;
+
+	ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
+	if (!ncfg)
+		return NULL;
+
+	of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
+	of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
+	of_property_read_u32(np, "nxp,whold", &ncfg->whold);
+	of_property_read_u32(np, "nxp,wsetup", &ncfg->wsetup);
+	of_property_read_u32(np, "nxp,rdr-clks", &ncfg->rdr_clks);
+	of_property_read_u32(np, "nxp,rwidth", &ncfg->rwidth);
+	of_property_read_u32(np, "nxp,rhold", &ncfg->rhold);
+	of_property_read_u32(np, "nxp,rsetup", &ncfg->rsetup);
+
+	if (!ncfg->wdr_clks || !ncfg->wwidth || !ncfg->whold ||
+	    !ncfg->wsetup || !ncfg->rdr_clks || !ncfg->rwidth ||
+	    !ncfg->rhold || !ncfg->rsetup) {
+		dev_err(dev, "chip parameters not specified correctly\n");
+		return NULL;
+	}
+
+	ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+
+	return ncfg;
+}
+
+/*
+ * Probe for NAND controller
+ */
+static int lpc32xx_nand_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct resource *rc;
+	int res;
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, rc);
+	if (IS_ERR(host->io_base))
+		return PTR_ERR(host->io_base);
+
+	host->io_base_dma = rc->start;
+	if (pdev->dev.of_node)
+		host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+	if (!host->ncfg) {
+		dev_err(&pdev->dev,
+			"Missing or bad NAND config from device tree\n");
+		return -ENOENT;
+	}
+	if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
+			host->ncfg->wp_gpio, "NAND WP")) {
+		dev_err(&pdev->dev, "GPIO not available\n");
+		return -EBUSY;
+	}
+	lpc32xx_wp_disable(host);
+
+	host->pdata = dev_get_platdata(&pdev->dev);
+
+	chip = &host->nand_chip;
+	mtd = nand_to_mtd(chip);
+	nand_set_controller_data(chip, host);
+	nand_set_flash_node(chip, pdev->dev.of_node);
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = &pdev->dev;
+
+	/* Get NAND clock */
+	host->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk)) {
+		dev_err(&pdev->dev, "Clock failure\n");
+		res = -ENOENT;
+		goto err_exit1;
+	}
+	res = clk_prepare_enable(host->clk);
+	if (res)
+		goto err_exit1;
+
+	/* Set NAND IO addresses and command/ready functions */
+	chip->IO_ADDR_R = SLC_DATA(host->io_base);
+	chip->IO_ADDR_W = SLC_DATA(host->io_base);
+	chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+	chip->dev_ready = lpc32xx_nand_device_ready;
+	chip->chip_delay = 20; /* 20us command delay time */
+
+	/* Init NAND controller */
+	lpc32xx_nand_setup(host);
+
+	platform_set_drvdata(pdev, host);
+
+	/* NAND callbacks for LPC32xx SLC hardware */
+	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+	chip->read_byte = lpc32xx_nand_read_byte;
+	chip->read_buf = lpc32xx_nand_read_buf;
+	chip->write_buf = lpc32xx_nand_write_buf;
+	chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
+	chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
+	chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
+	chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
+	chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
+	chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
+	chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
+	chip->ecc.correct = nand_correct_data;
+	chip->ecc.strength = 1;
+	chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
+
+	/*
+	 * Allocate a large enough buffer for a single huge page plus
+	 * extra space for the spare area and ECC storage area
+	 */
+	host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
+	host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
+				      GFP_KERNEL);
+	if (host->data_buf == NULL) {
+		res = -ENOMEM;
+		goto err_exit2;
+	}
+
+	res = lpc32xx_nand_dma_setup(host);
+	if (res) {
+		res = -EIO;
+		goto err_exit2;
+	}
+
+	/* Find NAND device */
+	res = nand_scan_ident(mtd, 1, NULL);
+	if (res)
+		goto err_exit3;
+
+	/* OOB and ECC CPU and DMA work areas */
+	host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+	/*
+	 * Small page FLASH has a unique OOB layout, but large and huge
+	 * page FLASH use the standard layout. Small page FLASH uses a
+	 * custom BBT marker layout.
+	 */
+	if (mtd->writesize <= 512)
+		mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+
+	/* These sizes remain the same regardless of page size */
+	chip->ecc.size = 256;
+	chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+	chip->ecc.prepad = chip->ecc.postpad = 0;
+
+	/*
+	 * Use a custom BBT marker setup for small page FLASH that
+	 * won't interfere with the ECC layout. Large and huge page
+	 * FLASH use the standard layout.
+	 */
+	if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
+	    mtd->writesize <= 512) {
+		chip->bbt_td = &bbt_smallpage_main_descr;
+		chip->bbt_md = &bbt_smallpage_mirror_descr;
+	}
+
+	/*
+	 * Fills out all the uninitialized function pointers with the defaults
+	 */
+	res = nand_scan_tail(mtd);
+	if (res)
+		goto err_exit3;
+
+	mtd->name = "nxp_lpc3220_slc";
+	res = mtd_device_register(mtd, host->ncfg->parts,
+				  host->ncfg->num_parts);
+	if (!res)
+		return res;
+
+	nand_release(mtd);
+
+err_exit3:
+	dma_release_channel(host->dma_chan);
+err_exit2:
+	clk_disable_unprepare(host->clk);
+err_exit1:
+	lpc32xx_wp_enable(host);
+
+	return res;
+}
+
+/*
+ * Remove NAND device.
+ */
+static int lpc32xx_nand_remove(struct platform_device *pdev)
+{
+	uint32_t tmp;
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+
+	nand_release(mtd);
+	dma_release_channel(host->dma_chan);
+
+	/* Force CE high */
+	tmp = readl(SLC_CTRL(host->io_base));
+	tmp &= ~SLCCFG_CE_LOW;
+	writel(tmp, SLC_CTRL(host->io_base));
+
+	clk_disable_unprepare(host->clk);
+	lpc32xx_wp_enable(host);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+	int ret;
+
+	/* Re-enable NAND clock */
+	ret = clk_prepare_enable(host->clk);
+	if (ret)
+		return ret;
+
+	/* Fresh init of NAND controller */
+	lpc32xx_nand_setup(host);
+
+	/* Disable write protect */
+	lpc32xx_wp_disable(host);
+
+	return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+	uint32_t tmp;
+	struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+	/* Force CE high */
+	tmp = readl(SLC_CTRL(host->io_base));
+	tmp &= ~SLCCFG_CE_LOW;
+	writel(tmp, SLC_CTRL(host->io_base));
+
+	/* Enable write protect for safety */
+	lpc32xx_wp_enable(host);
+
+	/* Disable clock */
+	clk_disable_unprepare(host->clk);
+
+	return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+static const struct of_device_id lpc32xx_nand_match[] = {
+	{ .compatible = "nxp,lpc3220-slc" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+
+static struct platform_driver lpc32xx_nand_driver = {
+	.probe		= lpc32xx_nand_probe,
+	.remove		= lpc32xx_nand_remove,
+	.resume		= lpc32xx_nand_resume,
+	.suspend	= lpc32xx_nand_suspend,
+	.driver		= {
+		.name	= LPC32XX_MODNAME,
+		.of_match_table = lpc32xx_nand_match,
+	},
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
new file mode 100644
index 000000000000..cc21f9633edd
--- /dev/null
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -0,0 +1,2915 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Marvell NAND flash controller driver
+ *
+ * Copyright (C) 2017 Marvell
+ * Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/of_platform.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <asm/unaligned.h>
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
+#include <linux/platform_data/mtd-nand-pxa3xx.h>
+
+/* Data FIFO granularity, FIFO reads/writes must be a multiple of this length */
+#define FIFO_DEPTH		8
+#define FIFO_REP(x)		(x / sizeof(u32))
+#define BCH_SEQ_READS		(32 / FIFO_DEPTH)
+/* NFC does not support transfers of larger chunks at a time */
+#define MAX_CHUNK_SIZE		2112
+/* NFCv1 cannot read more that 7 bytes of ID */
+#define NFCV1_READID_LEN	7
+/* Polling is done at a pace of POLL_PERIOD us until POLL_TIMEOUT is reached */
+#define POLL_PERIOD		0
+#define POLL_TIMEOUT		100000
+/* Interrupt maximum wait period in ms */
+#define IRQ_TIMEOUT		1000
+/* Latency in clock cycles between SoC pins and NFC logic */
+#define MIN_RD_DEL_CNT		3
+/* Maximum number of contiguous address cycles */
+#define MAX_ADDRESS_CYC_NFCV1	5
+#define MAX_ADDRESS_CYC_NFCV2	7
+/* System control registers/bits to enable the NAND controller on some SoCs */
+#define GENCONF_SOC_DEVICE_MUX	0x208
+#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
+#define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20)
+#define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21)
+#define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25)
+#define GENCONF_CLK_GATING_CTRL	0x220
+#define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2)
+#define GENCONF_ND_CLK_CTRL	0x700
+#define GENCONF_ND_CLK_CTRL_EN	BIT(0)
+
+/* NAND controller data flash control register */
+#define NDCR			0x00
+#define NDCR_ALL_INT		GENMASK(11, 0)
+#define NDCR_CS1_CMDDM		BIT(7)
+#define NDCR_CS0_CMDDM		BIT(8)
+#define NDCR_RDYM		BIT(11)
+#define NDCR_ND_ARB_EN		BIT(12)
+#define NDCR_RA_START		BIT(15)
+#define NDCR_RD_ID_CNT(x)	(min_t(unsigned int, x, 0x7) << 16)
+#define NDCR_PAGE_SZ(x)		(x >= 2048 ? BIT(24) : 0)
+#define NDCR_DWIDTH_M		BIT(26)
+#define NDCR_DWIDTH_C		BIT(27)
+#define NDCR_ND_RUN		BIT(28)
+#define NDCR_DMA_EN		BIT(29)
+#define NDCR_ECC_EN		BIT(30)
+#define NDCR_SPARE_EN		BIT(31)
+#define NDCR_GENERIC_FIELDS_MASK (~(NDCR_RA_START | NDCR_PAGE_SZ(2048) | \
+				    NDCR_DWIDTH_M | NDCR_DWIDTH_C))
+
+/* NAND interface timing parameter 0 register */
+#define NDTR0			0x04
+#define NDTR0_TRP(x)		((min_t(unsigned int, x, 0xF) & 0x7) << 0)
+#define NDTR0_TRH(x)		(min_t(unsigned int, x, 0x7) << 3)
+#define NDTR0_ETRP(x)		((min_t(unsigned int, x, 0xF) & 0x8) << 3)
+#define NDTR0_SEL_NRE_EDGE	BIT(7)
+#define NDTR0_TWP(x)		(min_t(unsigned int, x, 0x7) << 8)
+#define NDTR0_TWH(x)		(min_t(unsigned int, x, 0x7) << 11)
+#define NDTR0_TCS(x)		(min_t(unsigned int, x, 0x7) << 16)
+#define NDTR0_TCH(x)		(min_t(unsigned int, x, 0x7) << 19)
+#define NDTR0_RD_CNT_DEL(x)	(min_t(unsigned int, x, 0xF) << 22)
+#define NDTR0_SELCNTR		BIT(26)
+#define NDTR0_TADL(x)		(min_t(unsigned int, x, 0x1F) << 27)
+
+/* NAND interface timing parameter 1 register */
+#define NDTR1			0x0C
+#define NDTR1_TAR(x)		(min_t(unsigned int, x, 0xF) << 0)
+#define NDTR1_TWHR(x)		(min_t(unsigned int, x, 0xF) << 4)
+#define NDTR1_TRHW(x)		(min_t(unsigned int, x / 16, 0x3) << 8)
+#define NDTR1_PRESCALE		BIT(14)
+#define NDTR1_WAIT_MODE		BIT(15)
+#define NDTR1_TR(x)		(min_t(unsigned int, x, 0xFFFF) << 16)
+
+/* NAND controller status register */
+#define NDSR			0x14
+#define NDSR_WRCMDREQ		BIT(0)
+#define NDSR_RDDREQ		BIT(1)
+#define NDSR_WRDREQ		BIT(2)
+#define NDSR_CORERR		BIT(3)
+#define NDSR_UNCERR		BIT(4)
+#define NDSR_CMDD(cs)		BIT(8 - cs)
+#define NDSR_RDY(rb)		BIT(11 + rb)
+#define NDSR_ERRCNT(x)		((x >> 16) & 0x1F)
+
+/* NAND ECC control register */
+#define NDECCCTRL		0x28
+#define NDECCCTRL_BCH_EN	BIT(0)
+
+/* NAND controller data buffer register */
+#define NDDB			0x40
+
+/* NAND controller command buffer 0 register */
+#define NDCB0			0x48
+#define NDCB0_CMD1(x)		((x & 0xFF) << 0)
+#define NDCB0_CMD2(x)		((x & 0xFF) << 8)
+#define NDCB0_ADDR_CYC(x)	((x & 0x7) << 16)
+#define NDCB0_ADDR_GET_NUM_CYC(x) (((x) >> 16) & 0x7)
+#define NDCB0_DBC		BIT(19)
+#define NDCB0_CMD_TYPE(x)	((x & 0x7) << 21)
+#define NDCB0_CSEL		BIT(24)
+#define NDCB0_RDY_BYP		BIT(27)
+#define NDCB0_LEN_OVRD		BIT(28)
+#define NDCB0_CMD_XTYPE(x)	((x & 0x7) << 29)
+
+/* NAND controller command buffer 1 register */
+#define NDCB1			0x4C
+#define NDCB1_COLS(x)		((x & 0xFFFF) << 0)
+#define NDCB1_ADDRS_PAGE(x)	(x << 16)
+
+/* NAND controller command buffer 2 register */
+#define NDCB2			0x50
+#define NDCB2_ADDR5_PAGE(x)	(((x >> 16) & 0xFF) << 0)
+#define NDCB2_ADDR5_CYC(x)	((x & 0xFF) << 0)
+
+/* NAND controller command buffer 3 register */
+#define NDCB3			0x54
+#define NDCB3_ADDR6_CYC(x)	((x & 0xFF) << 16)
+#define NDCB3_ADDR7_CYC(x)	((x & 0xFF) << 24)
+
+/* NAND controller command buffer 0 register 'type' and 'xtype' fields */
+#define TYPE_READ		0
+#define TYPE_WRITE		1
+#define TYPE_ERASE		2
+#define TYPE_READ_ID		3
+#define TYPE_STATUS		4
+#define TYPE_RESET		5
+#define TYPE_NAKED_CMD		6
+#define TYPE_NAKED_ADDR		7
+#define TYPE_MASK		7
+#define XTYPE_MONOLITHIC_RW	0
+#define XTYPE_LAST_NAKED_RW	1
+#define XTYPE_FINAL_COMMAND	3
+#define XTYPE_READ		4
+#define XTYPE_WRITE_DISPATCH	4
+#define XTYPE_NAKED_RW		5
+#define XTYPE_COMMAND_DISPATCH	6
+#define XTYPE_MASK		7
+
+/**
+ * Marvell ECC engine works differently than the others, in order to limit the
+ * size of the IP, hardware engineers chose to set a fixed strength at 16 bits
+ * per subpage, and depending on a the desired strength needed by the NAND chip,
+ * a particular layout mixing data/spare/ecc is defined, with a possible last
+ * chunk smaller that the others.
+ *
+ * @writesize:		Full page size on which the layout applies
+ * @chunk:		Desired ECC chunk size on which the layout applies
+ * @strength:		Desired ECC strength (per chunk size bytes) on which the
+ *			layout applies
+ * @nchunks:		Total number of chunks
+ * @full_chunk_cnt:	Number of full-sized chunks, which is the number of
+ *			repetitions of the pattern:
+ *			(data_bytes + spare_bytes + ecc_bytes).
+ * @data_bytes:		Number of data bytes per chunk
+ * @spare_bytes:	Number of spare bytes per chunk
+ * @ecc_bytes:		Number of ecc bytes per chunk
+ * @last_data_bytes:	Number of data bytes in the last chunk
+ * @last_spare_bytes:	Number of spare bytes in the last chunk
+ * @last_ecc_bytes:	Number of ecc bytes in the last chunk
+ */
+struct marvell_hw_ecc_layout {
+	/* Constraints */
+	int writesize;
+	int chunk;
+	int strength;
+	/* Corresponding layout */
+	int nchunks;
+	int full_chunk_cnt;
+	int data_bytes;
+	int spare_bytes;
+	int ecc_bytes;
+	int last_data_bytes;
+	int last_spare_bytes;
+	int last_ecc_bytes;
+};
+
+#define MARVELL_LAYOUT(ws, dc, ds, nc, fcc, db, sb, eb, ldb, lsb, leb)	\
+	{								\
+		.writesize = ws,					\
+		.chunk = dc,						\
+		.strength = ds,						\
+		.nchunks = nc,						\
+		.full_chunk_cnt = fcc,					\
+		.data_bytes = db,					\
+		.spare_bytes = sb,					\
+		.ecc_bytes = eb,					\
+		.last_data_bytes = ldb,					\
+		.last_spare_bytes = lsb,				\
+		.last_ecc_bytes = leb,					\
+	}
+
+/* Layouts explained in AN-379_Marvell_SoC_NFC_ECC */
+static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
+	MARVELL_LAYOUT(  512,   512,  1,  1,  1,  512,  8,  8,  0,  0,  0),
+	MARVELL_LAYOUT( 2048,   512,  1,  1,  1, 2048, 40, 24,  0,  0,  0),
+	MARVELL_LAYOUT( 2048,   512,  4,  1,  1, 2048, 32, 30,  0,  0,  0),
+	MARVELL_LAYOUT( 4096,   512,  4,  2,  2, 2048, 32, 30,  0,  0,  0),
+	MARVELL_LAYOUT( 4096,   512,  8,  5,  4, 1024,  0, 30,  0, 64, 30),
+};
+
+/**
+ * The Nand Flash Controller has up to 4 CE and 2 RB pins. The CE selection
+ * is made by a field in NDCB0 register, and in another field in NDCB2 register.
+ * The datasheet describes the logic with an error: ADDR5 field is once
+ * declared at the beginning of NDCB2, and another time at its end. Because the
+ * ADDR5 field of NDCB2 may be used by other bytes, it would be more logical
+ * to use the last bit of this field instead of the first ones.
+ *
+ * @cs:			Wanted CE lane.
+ * @ndcb0_csel:		Value of the NDCB0 register with or without the flag
+ *			selecting the wanted CE lane. This is set once when
+ *			the Device Tree is probed.
+ * @rb:			Ready/Busy pin for the flash chip
+ */
+struct marvell_nand_chip_sel {
+	unsigned int cs;
+	u32 ndcb0_csel;
+	unsigned int rb;
+};
+
+/**
+ * NAND chip structure: stores NAND chip device related information
+ *
+ * @chip:		Base NAND chip structure
+ * @node:		Used to store NAND chips into a list
+ * @layout		NAND layout when using hardware ECC
+ * @ndcr:		Controller register value for this NAND chip
+ * @ndtr0:		Timing registers 0 value for this NAND chip
+ * @ndtr1:		Timing registers 1 value for this NAND chip
+ * @selected_die:	Current active CS
+ * @nsels:		Number of CS lines required by the NAND chip
+ * @sels:		Array of CS lines descriptions
+ */
+struct marvell_nand_chip {
+	struct nand_chip chip;
+	struct list_head node;
+	const struct marvell_hw_ecc_layout *layout;
+	u32 ndcr;
+	u32 ndtr0;
+	u32 ndtr1;
+	int addr_cyc;
+	int selected_die;
+	unsigned int nsels;
+	struct marvell_nand_chip_sel sels[0];
+};
+
+static inline struct marvell_nand_chip *to_marvell_nand(struct nand_chip *chip)
+{
+	return container_of(chip, struct marvell_nand_chip, chip);
+}
+
+static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
+							*nand)
+{
+	return &nand->sels[nand->selected_die];
+}
+
+/**
+ * NAND controller capabilities for distinction between compatible strings
+ *
+ * @max_cs_nb:		Number of Chip Select lines available
+ * @max_rb_nb:		Number of Ready/Busy lines available
+ * @need_system_controller: Indicates if the SoC needs to have access to the
+ *                      system controller (ie. to enable the NAND controller)
+ * @legacy_of_bindings:	Indicates if DT parsing must be done using the old
+ *			fashion way
+ * @is_nfcv2:		NFCv2 has numerous enhancements compared to NFCv1, ie.
+ *			BCH error detection and correction algorithm,
+ *			NDCB3 register has been added
+ * @use_dma:		Use dma for data transfers
+ */
+struct marvell_nfc_caps {
+	unsigned int max_cs_nb;
+	unsigned int max_rb_nb;
+	bool need_system_controller;
+	bool legacy_of_bindings;
+	bool is_nfcv2;
+	bool use_dma;
+};
+
+/**
+ * NAND controller structure: stores Marvell NAND controller information
+ *
+ * @controller:		Base controller structure
+ * @dev:		Parent device (used to print error messages)
+ * @regs:		NAND controller registers
+ * @ecc_clk:		ECC block clock, two times the NAND controller clock
+ * @complete:		Completion object to wait for NAND controller events
+ * @assigned_cs:	Bitmask describing already assigned CS lines
+ * @chips:		List containing all the NAND chips attached to
+ *			this NAND controller
+ * @caps:		NAND controller capabilities for each compatible string
+ * @dma_chan:		DMA channel (NFCv1 only)
+ * @dma_buf:		32-bit aligned buffer for DMA transfers (NFCv1 only)
+ */
+struct marvell_nfc {
+	struct nand_hw_control controller;
+	struct device *dev;
+	void __iomem *regs;
+	struct clk *ecc_clk;
+	struct completion complete;
+	unsigned long assigned_cs;
+	struct list_head chips;
+	struct nand_chip *selected_chip;
+	const struct marvell_nfc_caps *caps;
+
+	/* DMA (NFCv1 only) */
+	bool use_dma;
+	struct dma_chan *dma_chan;
+	u8 *dma_buf;
+};
+
+static inline struct marvell_nfc *to_marvell_nfc(struct nand_hw_control *ctrl)
+{
+	return container_of(ctrl, struct marvell_nfc, controller);
+}
+
+/**
+ * NAND controller timings expressed in NAND Controller clock cycles
+ *
+ * @tRP:		ND_nRE pulse width
+ * @tRH:		ND_nRE high duration
+ * @tWP:		ND_nWE pulse time
+ * @tWH:		ND_nWE high duration
+ * @tCS:		Enable signal setup time
+ * @tCH:		Enable signal hold time
+ * @tADL:		Address to write data delay
+ * @tAR:		ND_ALE low to ND_nRE low delay
+ * @tWHR:		ND_nWE high to ND_nRE low for status read
+ * @tRHW:		ND_nRE high duration, read to write delay
+ * @tR:			ND_nWE high to ND_nRE low for read
+ */
+struct marvell_nfc_timings {
+	/* NDTR0 fields */
+	unsigned int tRP;
+	unsigned int tRH;
+	unsigned int tWP;
+	unsigned int tWH;
+	unsigned int tCS;
+	unsigned int tCH;
+	unsigned int tADL;
+	/* NDTR1 fields */
+	unsigned int tAR;
+	unsigned int tWHR;
+	unsigned int tRHW;
+	unsigned int tR;
+};
+
+/**
+ * Derives a duration in numbers of clock cycles.
+ *
+ * @ps: Duration in pico-seconds
+ * @period_ns:  Clock period in nano-seconds
+ *
+ * Convert the duration in nano-seconds, then divide by the period and
+ * return the number of clock periods.
+ */
+#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP(ps / 1000, period_ns))
+#define TO_CYCLES64(ps, period_ns) (DIV_ROUND_UP_ULL(div_u64(ps, 1000), \
+						     period_ns))
+
+/**
+ * NAND driver structure filled during the parsing of the ->exec_op() subop
+ * subset of instructions.
+ *
+ * @ndcb:		Array of values written to NDCBx registers
+ * @cle_ale_delay_ns:	Optional delay after the last CMD or ADDR cycle
+ * @rdy_timeout_ms:	Timeout for waits on Ready/Busy pin
+ * @rdy_delay_ns:	Optional delay after waiting for the RB pin
+ * @data_delay_ns:	Optional delay after the data xfer
+ * @data_instr_idx:	Index of the data instruction in the subop
+ * @data_instr:		Pointer to the data instruction in the subop
+ */
+struct marvell_nfc_op {
+	u32 ndcb[4];
+	unsigned int cle_ale_delay_ns;
+	unsigned int rdy_timeout_ms;
+	unsigned int rdy_delay_ns;
+	unsigned int data_delay_ns;
+	unsigned int data_instr_idx;
+	const struct nand_op_instr *data_instr;
+};
+
+/*
+ * Internal helper to conditionnally apply a delay (from the above structure,
+ * most of the time).
+ */
+static void cond_delay(unsigned int ns)
+{
+	if (!ns)
+		return;
+
+	if (ns < 10000)
+		ndelay(ns);
+	else
+		udelay(DIV_ROUND_UP(ns, 1000));
+}
+
+/*
+ * The controller has many flags that could generate interrupts, most of them
+ * are disabled and polling is used. For the very slow signals, using interrupts
+ * may relax the CPU charge.
+ */
+static void marvell_nfc_disable_int(struct marvell_nfc *nfc, u32 int_mask)
+{
+	u32 reg;
+
+	/* Writing 1 disables the interrupt */
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg | int_mask, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask)
+{
+	u32 reg;
+
+	/* Writing 0 enables the interrupt */
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg & ~int_mask, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask)
+{
+	writel_relaxed(int_mask, nfc->regs + NDSR);
+}
+
+static void marvell_nfc_force_byte_access(struct nand_chip *chip,
+					  bool force_8bit)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr;
+
+	/*
+	 * Callers of this function do not verify if the NAND is using a 16-bit
+	 * an 8-bit bus for normal operations, so we need to take care of that
+	 * here by leaving the configuration unchanged if the NAND does not have
+	 * the NAND_BUSWIDTH_16 flag set.
+	 */
+	if (!(chip->options & NAND_BUSWIDTH_16))
+		return;
+
+	ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (force_8bit)
+		ndcr &= ~(NDCR_DWIDTH_M | NDCR_DWIDTH_C);
+	else
+		ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+	writel_relaxed(ndcr, nfc->regs + NDCR);
+}
+
+static int marvell_nfc_wait_ndrun(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 val;
+	int ret;
+
+	/*
+	 * The command is being processed, wait for the ND_RUN bit to be
+	 * cleared by the NFC. If not, we must clear it by hand.
+	 */
+	ret = readl_relaxed_poll_timeout(nfc->regs + NDCR, val,
+					 (val & NDCR_ND_RUN) == 0,
+					 POLL_PERIOD, POLL_TIMEOUT);
+	if (ret) {
+		dev_err(nfc->dev, "Timeout on NAND controller run mode\n");
+		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
+			       nfc->regs + NDCR);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Any time a command has to be sent to the controller, the following sequence
+ * has to be followed:
+ * - call marvell_nfc_prepare_cmd()
+ *      -> activate the ND_RUN bit that will kind of 'start a job'
+ *      -> wait the signal indicating the NFC is waiting for a command
+ * - send the command (cmd and address cycles)
+ * - enventually send or receive the data
+ * - call marvell_nfc_end_cmd() with the corresponding flag
+ *      -> wait the flag to be triggered or cancel the job with a timeout
+ *
+ * The following helpers are here to factorize the code a bit so that
+ * specialized functions responsible for executing the actual NAND
+ * operations do not have to replicate the same code blocks.
+ */
+static int marvell_nfc_prepare_cmd(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr, val;
+	int ret;
+
+	/* Poll ND_RUN and clear NDSR before issuing any command */
+	ret = marvell_nfc_wait_ndrun(chip);
+	if (ret) {
+		dev_err(nfc->dev, "Last operation did not succeed\n");
+		return ret;
+	}
+
+	ndcr = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(readl(nfc->regs + NDSR), nfc->regs + NDSR);
+
+	/* Assert ND_RUN bit and wait the NFC to be ready */
+	writel_relaxed(ndcr | NDCR_ND_RUN, nfc->regs + NDCR);
+	ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
+					 val & NDSR_WRCMDREQ,
+					 POLL_PERIOD, POLL_TIMEOUT);
+	if (ret) {
+		dev_err(nfc->dev, "Timeout on WRCMDRE\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Command may be written, clear WRCMDREQ status bit */
+	writel_relaxed(NDSR_WRCMDREQ, nfc->regs + NDSR);
+
+	return 0;
+}
+
+static void marvell_nfc_send_cmd(struct nand_chip *chip,
+				 struct marvell_nfc_op *nfc_op)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+	dev_dbg(nfc->dev, "\nNDCR:  0x%08x\n"
+		"NDCB0: 0x%08x\nNDCB1: 0x%08x\nNDCB2: 0x%08x\nNDCB3: 0x%08x\n",
+		(u32)readl_relaxed(nfc->regs + NDCR), nfc_op->ndcb[0],
+		nfc_op->ndcb[1], nfc_op->ndcb[2], nfc_op->ndcb[3]);
+
+	writel_relaxed(to_nand_sel(marvell_nand)->ndcb0_csel | nfc_op->ndcb[0],
+		       nfc->regs + NDCB0);
+	writel_relaxed(nfc_op->ndcb[1], nfc->regs + NDCB0);
+	writel(nfc_op->ndcb[2], nfc->regs + NDCB0);
+
+	/*
+	 * Write NDCB0 four times only if LEN_OVRD is set or if ADDR6 or ADDR7
+	 * fields are used (only available on NFCv2).
+	 */
+	if (nfc_op->ndcb[0] & NDCB0_LEN_OVRD ||
+	    NDCB0_ADDR_GET_NUM_CYC(nfc_op->ndcb[0]) >= 6) {
+		if (!WARN_ON_ONCE(!nfc->caps->is_nfcv2))
+			writel(nfc_op->ndcb[3], nfc->regs + NDCB0);
+	}
+}
+
+static int marvell_nfc_end_cmd(struct nand_chip *chip, int flag,
+			       const char *label)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 val;
+	int ret;
+
+	ret = readl_relaxed_poll_timeout(nfc->regs + NDSR, val,
+					 val & flag,
+					 POLL_PERIOD, POLL_TIMEOUT);
+
+	if (ret) {
+		dev_err(nfc->dev, "Timeout on %s (NDSR: 0x%08x)\n",
+			label, val);
+		if (nfc->dma_chan)
+			dmaengine_terminate_all(nfc->dma_chan);
+		return ret;
+	}
+
+	/*
+	 * DMA function uses this helper to poll on CMDD bits without wanting
+	 * them to be cleared.
+	 */
+	if (nfc->use_dma && (readl_relaxed(nfc->regs + NDCR) & NDCR_DMA_EN))
+		return 0;
+
+	writel_relaxed(flag, nfc->regs + NDSR);
+
+	return 0;
+}
+
+static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	int cs_flag = NDSR_CMDD(to_nand_sel(marvell_nand)->ndcb0_csel);
+
+	return marvell_nfc_end_cmd(chip, cs_flag, "CMDD");
+}
+
+static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	int ret;
+
+	/* Timeout is expressed in ms */
+	if (!timeout_ms)
+		timeout_ms = IRQ_TIMEOUT;
+
+	init_completion(&nfc->complete);
+
+	marvell_nfc_enable_int(nfc, NDCR_RDYM);
+	ret = wait_for_completion_timeout(&nfc->complete,
+					  msecs_to_jiffies(timeout_ms));
+	marvell_nfc_disable_int(nfc, NDCR_RDYM);
+	marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
+	if (!ret) {
+		dev_err(nfc->dev, "Timeout waiting for RB signal\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr_generic;
+
+	if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die)
+		return;
+
+	if (die_nr < 0 || die_nr >= marvell_nand->nsels) {
+		nfc->selected_chip = NULL;
+		marvell_nand->selected_die = -1;
+		return;
+	}
+
+	/*
+	 * Do not change the timing registers when using the DT property
+	 * marvell,nand-keep-config; in that case ->ndtr0 and ->ndtr1 from the
+	 * marvell_nand structure are supposedly empty.
+	 */
+	writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
+	writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
+
+	/*
+	 * Reset the NDCR register to a clean state for this particular chip,
+	 * also clear ND_RUN bit.
+	 */
+	ndcr_generic = readl_relaxed(nfc->regs + NDCR) &
+		       NDCR_GENERIC_FIELDS_MASK & ~NDCR_ND_RUN;
+	writel_relaxed(ndcr_generic | marvell_nand->ndcr, nfc->regs + NDCR);
+
+	/* Also reset the interrupt status register */
+	marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
+
+	nfc->selected_chip = chip;
+	marvell_nand->selected_die = die_nr;
+}
+
+static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
+{
+	struct marvell_nfc *nfc = dev_id;
+	u32 st = readl_relaxed(nfc->regs + NDSR);
+	u32 ien = (~readl_relaxed(nfc->regs + NDCR)) & NDCR_ALL_INT;
+
+	/*
+	 * RDY interrupt mask is one bit in NDCR while there are two status
+	 * bit in NDSR (RDY[cs0/cs2] and RDY[cs1/cs3]).
+	 */
+	if (st & NDSR_RDY(1))
+		st |= NDSR_RDY(0);
+
+	if (!(st & ien))
+		return IRQ_NONE;
+
+	marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
+
+	if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+		complete(&nfc->complete);
+
+	return IRQ_HANDLED;
+}
+
+/* HW ECC related functions */
+static void marvell_nfc_enable_hw_ecc(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (!(ndcr & NDCR_ECC_EN)) {
+		writel_relaxed(ndcr | NDCR_ECC_EN, nfc->regs + NDCR);
+
+		/*
+		 * When enabling BCH, set threshold to 0 to always know the
+		 * number of corrected bitflips.
+		 */
+		if (chip->ecc.algo == NAND_ECC_BCH)
+			writel_relaxed(NDECCCTRL_BCH_EN, nfc->regs + NDECCCTRL);
+	}
+}
+
+static void marvell_nfc_disable_hw_ecc(struct nand_chip *chip)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	u32 ndcr = readl_relaxed(nfc->regs + NDCR);
+
+	if (ndcr & NDCR_ECC_EN) {
+		writel_relaxed(ndcr & ~NDCR_ECC_EN, nfc->regs + NDCR);
+		if (chip->ecc.algo == NAND_ECC_BCH)
+			writel_relaxed(0, nfc->regs + NDECCCTRL);
+	}
+}
+
+/* DMA related helpers */
+static void marvell_nfc_enable_dma(struct marvell_nfc *nfc)
+{
+	u32 reg;
+
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg | NDCR_DMA_EN, nfc->regs + NDCR);
+}
+
+static void marvell_nfc_disable_dma(struct marvell_nfc *nfc)
+{
+	u32 reg;
+
+	reg = readl_relaxed(nfc->regs + NDCR);
+	writel_relaxed(reg & ~NDCR_DMA_EN, nfc->regs + NDCR);
+}
+
+/* Read/write PIO/DMA accessors */
+static int marvell_nfc_xfer_data_dma(struct marvell_nfc *nfc,
+				     enum dma_data_direction direction,
+				     unsigned int len)
+{
+	unsigned int dma_len = min_t(int, ALIGN(len, 32), MAX_CHUNK_SIZE);
+	struct dma_async_tx_descriptor *tx;
+	struct scatterlist sg;
+	dma_cookie_t cookie;
+	int ret;
+
+	marvell_nfc_enable_dma(nfc);
+	/* Prepare the DMA transfer */
+	sg_init_one(&sg, nfc->dma_buf, dma_len);
+	dma_map_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
+	tx = dmaengine_prep_slave_sg(nfc->dma_chan, &sg, 1,
+				     direction == DMA_FROM_DEVICE ?
+				     DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
+				     DMA_PREP_INTERRUPT);
+	if (!tx) {
+		dev_err(nfc->dev, "Could not prepare DMA S/G list\n");
+		return -ENXIO;
+	}
+
+	/* Do the task and wait for it to finish */
+	cookie = dmaengine_submit(tx);
+	ret = dma_submit_error(cookie);
+	if (ret)
+		return -EIO;
+
+	dma_async_issue_pending(nfc->dma_chan);
+	ret = marvell_nfc_wait_cmdd(nfc->selected_chip);
+	dma_unmap_sg(nfc->dma_chan->device->dev, &sg, 1, direction);
+	marvell_nfc_disable_dma(nfc);
+	if (ret) {
+		dev_err(nfc->dev, "Timeout waiting for DMA (status: %d)\n",
+			dmaengine_tx_status(nfc->dma_chan, cookie, NULL));
+		dmaengine_terminate_all(nfc->dma_chan);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_xfer_data_in_pio(struct marvell_nfc *nfc, u8 *in,
+					unsigned int len)
+{
+	unsigned int last_len = len % FIFO_DEPTH;
+	unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
+	int i;
+
+	for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
+		ioread32_rep(nfc->regs + NDDB, in + i, FIFO_REP(FIFO_DEPTH));
+
+	if (last_len) {
+		u8 tmp_buf[FIFO_DEPTH];
+
+		ioread32_rep(nfc->regs + NDDB, tmp_buf, FIFO_REP(FIFO_DEPTH));
+		memcpy(in + last_full_offset, tmp_buf, last_len);
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_xfer_data_out_pio(struct marvell_nfc *nfc, const u8 *out,
+					 unsigned int len)
+{
+	unsigned int last_len = len % FIFO_DEPTH;
+	unsigned int last_full_offset = round_down(len, FIFO_DEPTH);
+	int i;
+
+	for (i = 0; i < last_full_offset; i += FIFO_DEPTH)
+		iowrite32_rep(nfc->regs + NDDB, out + i, FIFO_REP(FIFO_DEPTH));
+
+	if (last_len) {
+		u8 tmp_buf[FIFO_DEPTH];
+
+		memcpy(tmp_buf, out + last_full_offset, last_len);
+		iowrite32_rep(nfc->regs + NDDB, tmp_buf, FIFO_REP(FIFO_DEPTH));
+	}
+
+	return 0;
+}
+
+static void marvell_nfc_check_empty_chunk(struct nand_chip *chip,
+					  u8 *data, int data_len,
+					  u8 *spare, int spare_len,
+					  u8 *ecc, int ecc_len,
+					  unsigned int *max_bitflips)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int bf;
+
+	/*
+	 * Blank pages (all 0xFF) that have not been written may be recognized
+	 * as bad if bitflips occur, so whenever an uncorrectable error occurs,
+	 * check if the entire page (with ECC bytes) is actually blank or not.
+	 */
+	if (!data)
+		data_len = 0;
+	if (!spare)
+		spare_len = 0;
+	if (!ecc)
+		ecc_len = 0;
+
+	bf = nand_check_erased_ecc_chunk(data, data_len, ecc, ecc_len,
+					 spare, spare_len, chip->ecc.strength);
+	if (bf < 0) {
+		mtd->ecc_stats.failed++;
+		return;
+	}
+
+	/* Update the stats and max_bitflips */
+	mtd->ecc_stats.corrected += bf;
+	*max_bitflips = max_t(unsigned int, *max_bitflips, bf);
+}
+
+/*
+ * Check a chunk is correct or not according to hardware ECC engine.
+ * mtd->ecc_stats.corrected is updated, as well as max_bitflips, however
+ * mtd->ecc_stats.failure is not, the function will instead return a non-zero
+ * value indicating that a check on the emptyness of the subpage must be
+ * performed before declaring the subpage corrupted.
+ */
+static int marvell_nfc_hw_ecc_correct(struct nand_chip *chip,
+				      unsigned int *max_bitflips)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	int bf = 0;
+	u32 ndsr;
+
+	ndsr = readl_relaxed(nfc->regs + NDSR);
+
+	/* Check uncorrectable error flag */
+	if (ndsr & NDSR_UNCERR) {
+		writel_relaxed(ndsr, nfc->regs + NDSR);
+
+		/*
+		 * Do not increment ->ecc_stats.failed now, instead, return a
+		 * non-zero value to indicate that this chunk was apparently
+		 * bad, and it should be check to see if it empty or not. If
+		 * the chunk (with ECC bytes) is not declared empty, the calling
+		 * function must increment the failure count.
+		 */
+		return -EBADMSG;
+	}
+
+	/* Check correctable error flag */
+	if (ndsr & NDSR_CORERR) {
+		writel_relaxed(ndsr, nfc->regs + NDSR);
+
+		if (chip->ecc.algo == NAND_ECC_BCH)
+			bf = NDSR_ERRCNT(ndsr);
+		else
+			bf = 1;
+	}
+
+	/* Update the stats and max_bitflips */
+	mtd->ecc_stats.corrected += bf;
+	*max_bitflips = max_t(unsigned int, *max_bitflips, bf);
+
+	return 0;
+}
+
+/* Hamming read helpers */
+static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
+					       u8 *data_buf, u8 *oob_buf,
+					       bool raw, int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
+			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+			   NDCB0_DBC |
+			   NDCB0_CMD1(NAND_CMD_READ0) |
+			   NDCB0_CMD2(NAND_CMD_READSTART),
+		.ndcb[1] = NDCB1_ADDRS_PAGE(page),
+		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
+	};
+	unsigned int oob_bytes = lt->spare_bytes + (raw ? lt->ecc_bytes : 0);
+	int ret;
+
+	/* NFCv2 needs more information about the operation being executed */
+	if (nfc->caps->is_nfcv2)
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				  "RDDREQ while draining FIFO (data/oob)");
+	if (ret)
+		return ret;
+
+	/*
+	 * Read the page then the OOB area. Unlike what is shown in current
+	 * documentation, spare bytes are protected by the ECC engine, and must
+	 * be at the beginning of the OOB area or running this driver on legacy
+	 * systems will prevent the discovery of the BBM/BBT.
+	 */
+	if (nfc->use_dma) {
+		marvell_nfc_xfer_data_dma(nfc, DMA_FROM_DEVICE,
+					  lt->data_bytes + oob_bytes);
+		memcpy(data_buf, nfc->dma_buf, lt->data_bytes);
+		memcpy(oob_buf, nfc->dma_buf + lt->data_bytes, oob_bytes);
+	} else {
+		marvell_nfc_xfer_data_in_pio(nfc, data_buf, lt->data_bytes);
+		marvell_nfc_xfer_data_in_pio(nfc, oob_buf, oob_bytes);
+	}
+
+	ret = marvell_nfc_wait_cmdd(chip);
+
+	return ret;
+}
+
+static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
+						struct nand_chip *chip, u8 *buf,
+						int oob_required, int page)
+{
+	return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
+						   true, page);
+}
+
+static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    u8 *buf, int oob_required,
+					    int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
+	int max_bitflips = 0, ret;
+	u8 *raw_buf;
+
+	marvell_nfc_enable_hw_ecc(chip);
+	marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, false,
+					    page);
+	ret = marvell_nfc_hw_ecc_correct(chip, &max_bitflips);
+	marvell_nfc_disable_hw_ecc(chip);
+
+	if (!ret)
+		return max_bitflips;
+
+	/*
+	 * When ECC failures are detected, check if the full page has been
+	 * written or not. Ignore the failure if it is actually empty.
+	 */
+	raw_buf = kmalloc(full_sz, GFP_KERNEL);
+	if (!raw_buf)
+		return -ENOMEM;
+
+	marvell_nfc_hw_ecc_hmg_do_read_page(chip, raw_buf, raw_buf +
+					    lt->data_bytes, true, page);
+	marvell_nfc_check_empty_chunk(chip, raw_buf, full_sz, NULL, 0, NULL, 0,
+				      &max_bitflips);
+	kfree(raw_buf);
+
+	return max_bitflips;
+}
+
+/*
+ * Spare area in Hamming layouts is not protected by the ECC engine (even if
+ * it appears before the ECC bytes when reading), the ->read_oob_raw() function
+ * also stands for ->read_oob().
+ */
+static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
+					       struct nand_chip *chip, int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf,
+						   chip->oob_poi, true, page);
+}
+
+/* Hamming write helpers */
+static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
+						const u8 *data_buf,
+						const u8 *oob_buf, bool raw,
+						int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) |
+			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+			   NDCB0_CMD1(NAND_CMD_SEQIN) |
+			   NDCB0_CMD2(NAND_CMD_PAGEPROG) |
+			   NDCB0_DBC,
+		.ndcb[1] = NDCB1_ADDRS_PAGE(page),
+		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
+	};
+	unsigned int oob_bytes = lt->spare_bytes + (raw ? lt->ecc_bytes : 0);
+	int ret;
+
+	/* NFCv2 needs more information about the operation being executed */
+	if (nfc->caps->is_nfcv2)
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
+				  "WRDREQ while loading FIFO (data)");
+	if (ret)
+		return ret;
+
+	/* Write the page then the OOB area */
+	if (nfc->use_dma) {
+		memcpy(nfc->dma_buf, data_buf, lt->data_bytes);
+		memcpy(nfc->dma_buf + lt->data_bytes, oob_buf, oob_bytes);
+		marvell_nfc_xfer_data_dma(nfc, DMA_TO_DEVICE, lt->data_bytes +
+					  lt->ecc_bytes + lt->spare_bytes);
+	} else {
+		marvell_nfc_xfer_data_out_pio(nfc, data_buf, lt->data_bytes);
+		marvell_nfc_xfer_data_out_pio(nfc, oob_buf, oob_bytes);
+	}
+
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	ret = marvell_nfc_wait_op(chip,
+				  chip->data_interface.timings.sdr.tPROG_max);
+	return ret;
+}
+
+static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
+						 struct nand_chip *chip,
+						 const u8 *buf,
+						 int oob_required, int page)
+{
+	return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
+						    true, page);
+}
+
+static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     const u8 *buf,
+					     int oob_required, int page)
+{
+	int ret;
+
+	marvell_nfc_enable_hw_ecc(chip);
+	ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi,
+						   false, page);
+	marvell_nfc_disable_hw_ecc(chip);
+
+	return ret;
+}
+
+/*
+ * Spare area in Hamming layouts is not protected by the ECC engine (even if
+ * it appears before the ECC bytes when reading), the ->write_oob_raw() function
+ * also stands for ->write_oob().
+ */
+static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
+						struct nand_chip *chip,
+						int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	memset(chip->data_buf, 0xFF, mtd->writesize);
+
+	return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf,
+						    chip->oob_poi, true, page);
+}
+
+/* BCH read helpers */
+static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
+						struct nand_chip *chip, u8 *buf,
+						int oob_required, int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	u8 *oob = chip->oob_poi;
+	int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
+	int ecc_offset = (lt->full_chunk_cnt * lt->spare_bytes) +
+		lt->last_spare_bytes;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	int ecc_len = lt->ecc_bytes;
+	int chunk;
+
+	if (oob_required)
+		memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	for (chunk = 0; chunk < lt->nchunks; chunk++) {
+		/* Update last chunk length */
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+			ecc_len = lt->last_ecc_bytes;
+		}
+
+		/* Read data bytes*/
+		nand_change_read_column_op(chip, chunk * chunk_size,
+					   buf + (lt->data_bytes * chunk),
+					   data_len, false);
+
+		/* Read spare bytes */
+		nand_read_data_op(chip, oob + (lt->spare_bytes * chunk),
+				  spare_len, false);
+
+		/* Read ECC bytes */
+		nand_read_data_op(chip, oob + ecc_offset +
+				  (ALIGN(lt->ecc_bytes, 32) * chunk),
+				  ecc_len, false);
+	}
+
+	return 0;
+}
+
+static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
+					      u8 *data, unsigned int data_len,
+					      u8 *spare, unsigned int spare_len,
+					      int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int i, ret;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_READ) |
+			   NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+			   NDCB0_LEN_OVRD,
+		.ndcb[1] = NDCB1_ADDRS_PAGE(page),
+		.ndcb[2] = NDCB2_ADDR5_PAGE(page),
+		.ndcb[3] = data_len + spare_len,
+	};
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return;
+
+	if (chunk == 0)
+		nfc_op.ndcb[0] |= NDCB0_DBC |
+				  NDCB0_CMD1(NAND_CMD_READ0) |
+				  NDCB0_CMD2(NAND_CMD_READSTART);
+
+	/*
+	 * Trigger the naked read operation only on the last chunk.
+	 * Otherwise, use monolithic read.
+	 */
+	if (lt->nchunks == 1 || (chunk < lt->nchunks - 1))
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW);
+	else
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+
+	/*
+	 * According to the datasheet, when reading from NDDB
+	 * with BCH enabled, after each 32 bytes reads, we
+	 * have to make sure that the NDSR.RDDREQ bit is set.
+	 *
+	 * Drain the FIFO, 8 32-bit reads at a time, and skip
+	 * the polling on the last read.
+	 *
+	 * Length is a multiple of 32 bytes, hence it is a multiple of 8 too.
+	 */
+	for (i = 0; i < data_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
+		marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				    "RDDREQ while draining FIFO (data)");
+		marvell_nfc_xfer_data_in_pio(nfc, data,
+					     FIFO_DEPTH * BCH_SEQ_READS);
+		data += FIFO_DEPTH * BCH_SEQ_READS;
+	}
+
+	for (i = 0; i < spare_len; i += FIFO_DEPTH * BCH_SEQ_READS) {
+		marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				    "RDDREQ while draining FIFO (OOB)");
+		marvell_nfc_xfer_data_in_pio(nfc, spare,
+					     FIFO_DEPTH * BCH_SEQ_READS);
+		spare += FIFO_DEPTH * BCH_SEQ_READS;
+	}
+}
+
+static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    u8 *buf, int oob_required,
+					    int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
+	u8 *data = buf, *spare = chip->oob_poi, *ecc;
+	int max_bitflips = 0;
+	u32 failure_mask = 0;
+	int chunk, ecc_offset_in_page, ret;
+
+	/*
+	 * With BCH, OOB is not fully used (and thus not read entirely), not
+	 * expected bytes could show up at the end of the OOB buffer if not
+	 * explicitly erased.
+	 */
+	if (oob_required)
+		memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+	marvell_nfc_enable_hw_ecc(chip);
+
+	for (chunk = 0; chunk < lt->nchunks; chunk++) {
+		/* Update length for the last chunk */
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+		}
+
+		/* Read the chunk and detect number of bitflips */
+		marvell_nfc_hw_ecc_bch_read_chunk(chip, chunk, data, data_len,
+						  spare, spare_len, page);
+		ret = marvell_nfc_hw_ecc_correct(chip, &max_bitflips);
+		if (ret)
+			failure_mask |= BIT(chunk);
+
+		data += data_len;
+		spare += spare_len;
+	}
+
+	marvell_nfc_disable_hw_ecc(chip);
+
+	if (!failure_mask)
+		return max_bitflips;
+
+	/*
+	 * Please note that dumping the ECC bytes during a normal read with OOB
+	 * area would add a significant overhead as ECC bytes are "consumed" by
+	 * the controller in normal mode and must be re-read in raw mode. To
+	 * avoid dropping the performances, we prefer not to include them. The
+	 * user should re-read the page in raw mode if ECC bytes are required.
+	 *
+	 * However, for any subpage read error reported by ->correct(), the ECC
+	 * bytes must be read in raw mode and the full subpage must be checked
+	 * to see if it is entirely empty of if there was an actual error.
+	 */
+	for (chunk = 0; chunk < lt->nchunks; chunk++) {
+		/* No failure reported for this chunk, move to the next one */
+		if (!(failure_mask & BIT(chunk)))
+			continue;
+
+		/* Derive ECC bytes positions (in page/buffer) and length */
+		ecc = chip->oob_poi +
+			(lt->full_chunk_cnt * lt->spare_bytes) +
+			lt->last_spare_bytes +
+			(chunk * ALIGN(lt->ecc_bytes, 32));
+		ecc_offset_in_page =
+			(chunk * (lt->data_bytes + lt->spare_bytes +
+				  lt->ecc_bytes)) +
+			(chunk < lt->full_chunk_cnt ?
+			 lt->data_bytes + lt->spare_bytes :
+			 lt->last_data_bytes + lt->last_spare_bytes);
+		ecc_len = chunk < lt->full_chunk_cnt ?
+			lt->ecc_bytes : lt->last_ecc_bytes;
+
+		/* Do the actual raw read of the ECC bytes */
+		nand_change_read_column_op(chip, ecc_offset_in_page,
+					   ecc, ecc_len, false);
+
+		/* Derive data/spare bytes positions (in buffer) and length */
+		data = buf + (chunk * lt->data_bytes);
+		data_len = chunk < lt->full_chunk_cnt ?
+			lt->data_bytes : lt->last_data_bytes;
+		spare = chip->oob_poi + (chunk * (lt->spare_bytes +
+						  lt->ecc_bytes));
+		spare_len = chunk < lt->full_chunk_cnt ?
+			lt->spare_bytes : lt->last_spare_bytes;
+
+		/* Check the entire chunk (data + spare + ecc) for emptyness */
+		marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
+					      spare_len, ecc, ecc_len,
+					      &max_bitflips);
+	}
+
+	return max_bitflips;
+}
+
+static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
+					       struct nand_chip *chip, int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
+}
+
+static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
+					   struct nand_chip *chip, int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
+}
+
+/* BCH write helpers */
+static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
+						 struct nand_chip *chip,
+						 const u8 *buf,
+						 int oob_required, int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int full_chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	int ecc_len = lt->ecc_bytes;
+	int spare_offset = 0;
+	int ecc_offset = (lt->full_chunk_cnt * lt->spare_bytes) +
+		lt->last_spare_bytes;
+	int chunk;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	for (chunk = 0; chunk < lt->nchunks; chunk++) {
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+			ecc_len = lt->last_ecc_bytes;
+		}
+
+		/* Point to the column of the next chunk */
+		nand_change_write_column_op(chip, chunk * full_chunk_size,
+					    NULL, 0, false);
+
+		/* Write the data */
+		nand_write_data_op(chip, buf + (chunk * lt->data_bytes),
+				   data_len, false);
+
+		if (!oob_required)
+			continue;
+
+		/* Write the spare bytes */
+		if (spare_len)
+			nand_write_data_op(chip, chip->oob_poi + spare_offset,
+					   spare_len, false);
+
+		/* Write the ECC bytes */
+		if (ecc_len)
+			nand_write_data_op(chip, chip->oob_poi + ecc_offset,
+					   ecc_len, false);
+
+		spare_offset += spare_len;
+		ecc_offset += ALIGN(ecc_len, 32);
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int
+marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
+				   const u8 *data, unsigned int data_len,
+				   const u8 *spare, unsigned int spare_len,
+				   int page)
+{
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	int ret;
+	struct marvell_nfc_op nfc_op = {
+		.ndcb[0] = NDCB0_CMD_TYPE(TYPE_WRITE) | NDCB0_LEN_OVRD,
+		.ndcb[3] = data_len + spare_len,
+	};
+
+	/*
+	 * First operation dispatches the CMD_SEQIN command, issue the address
+	 * cycles and asks for the first chunk of data.
+	 * All operations in the middle (if any) will issue a naked write and
+	 * also ask for data.
+	 * Last operation (if any) asks for the last chunk of data through a
+	 * last naked write.
+	 */
+	if (chunk == 0) {
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_WRITE_DISPATCH) |
+				  NDCB0_ADDR_CYC(marvell_nand->addr_cyc) |
+				  NDCB0_CMD1(NAND_CMD_SEQIN);
+		nfc_op.ndcb[1] |= NDCB1_ADDRS_PAGE(page);
+		nfc_op.ndcb[2] |= NDCB2_ADDR5_PAGE(page);
+	} else if (chunk < lt->nchunks - 1) {
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_NAKED_RW);
+	} else {
+		nfc_op.ndcb[0] |= NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+	}
+
+	/* Always dispatch the PAGEPROG command on the last chunk */
+	if (chunk == lt->nchunks - 1)
+		nfc_op.ndcb[0] |= NDCB0_CMD2(NAND_CMD_PAGEPROG) | NDCB0_DBC;
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_WRDREQ,
+				  "WRDREQ while loading FIFO (data)");
+	if (ret)
+		return ret;
+
+	/* Transfer the contents */
+	iowrite32_rep(nfc->regs + NDDB, data, FIFO_REP(data_len));
+	iowrite32_rep(nfc->regs + NDDB, spare, FIFO_REP(spare_len));
+
+	return 0;
+}
+
+static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     const u8 *buf,
+					     int oob_required, int page)
+{
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+	const u8 *data = buf;
+	const u8 *spare = chip->oob_poi;
+	int data_len = lt->data_bytes;
+	int spare_len = lt->spare_bytes;
+	int chunk, ret;
+
+	/* Spare data will be written anyway, so clear it to avoid garbage */
+	if (!oob_required)
+		memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+	marvell_nfc_enable_hw_ecc(chip);
+
+	for (chunk = 0; chunk < lt->nchunks; chunk++) {
+		if (chunk >= lt->full_chunk_cnt) {
+			data_len = lt->last_data_bytes;
+			spare_len = lt->last_spare_bytes;
+		}
+
+		marvell_nfc_hw_ecc_bch_write_chunk(chip, chunk, data, data_len,
+						   spare, spare_len, page);
+		data += data_len;
+		spare += spare_len;
+
+		/*
+		 * Waiting only for CMDD or PAGED is not enough, ECC are
+		 * partially written. No flag is set once the operation is
+		 * really finished but the ND_RUN bit is cleared, so wait for it
+		 * before stepping into the next command.
+		 */
+		marvell_nfc_wait_ndrun(chip);
+	}
+
+	ret = marvell_nfc_wait_op(chip,
+				  chip->data_interface.timings.sdr.tPROG_max);
+
+	marvell_nfc_disable_hw_ecc(chip);
+
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
+						struct nand_chip *chip,
+						int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	memset(chip->data_buf, 0xFF, mtd->writesize);
+
+	return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
+}
+
+static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
+					    struct nand_chip *chip, int page)
+{
+	/* Invalidate page cache */
+	chip->pagebuf = -1;
+
+	memset(chip->data_buf, 0xFF, mtd->writesize);
+
+	return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
+}
+
+/* NAND framework ->exec_op() hooks and related helpers */
+static void marvell_nfc_parse_instructions(struct nand_chip *chip,
+					   const struct nand_subop *subop,
+					   struct marvell_nfc_op *nfc_op)
+{
+	const struct nand_op_instr *instr = NULL;
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	bool first_cmd = true;
+	unsigned int op_id;
+	int i;
+
+	/* Reset the input structure as most of its fields will be OR'ed */
+	memset(nfc_op, 0, sizeof(struct marvell_nfc_op));
+
+	for (op_id = 0; op_id < subop->ninstrs; op_id++) {
+		unsigned int offset, naddrs;
+		const u8 *addrs;
+		int len = nand_subop_get_data_len(subop, op_id);
+
+		instr = &subop->instrs[op_id];
+
+		switch (instr->type) {
+		case NAND_OP_CMD_INSTR:
+			if (first_cmd)
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD1(instr->ctx.cmd.opcode);
+			else
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD2(instr->ctx.cmd.opcode) |
+					NDCB0_DBC;
+
+			nfc_op->cle_ale_delay_ns = instr->delay_ns;
+			first_cmd = false;
+			break;
+
+		case NAND_OP_ADDR_INSTR:
+			offset = nand_subop_get_addr_start_off(subop, op_id);
+			naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
+			addrs = &instr->ctx.addr.addrs[offset];
+
+			nfc_op->ndcb[0] |= NDCB0_ADDR_CYC(naddrs);
+
+			for (i = 0; i < min_t(unsigned int, 4, naddrs); i++)
+				nfc_op->ndcb[1] |= addrs[i] << (8 * i);
+
+			if (naddrs >= 5)
+				nfc_op->ndcb[2] |= NDCB2_ADDR5_CYC(addrs[4]);
+			if (naddrs >= 6)
+				nfc_op->ndcb[3] |= NDCB3_ADDR6_CYC(addrs[5]);
+			if (naddrs == 7)
+				nfc_op->ndcb[3] |= NDCB3_ADDR7_CYC(addrs[6]);
+
+			nfc_op->cle_ale_delay_ns = instr->delay_ns;
+			break;
+
+		case NAND_OP_DATA_IN_INSTR:
+			nfc_op->data_instr = instr;
+			nfc_op->data_instr_idx = op_id;
+			nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ);
+			if (nfc->caps->is_nfcv2) {
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
+					NDCB0_LEN_OVRD;
+				nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
+			}
+			nfc_op->data_delay_ns = instr->delay_ns;
+			break;
+
+		case NAND_OP_DATA_OUT_INSTR:
+			nfc_op->data_instr = instr;
+			nfc_op->data_instr_idx = op_id;
+			nfc_op->ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE);
+			if (nfc->caps->is_nfcv2) {
+				nfc_op->ndcb[0] |=
+					NDCB0_CMD_XTYPE(XTYPE_MONOLITHIC_RW) |
+					NDCB0_LEN_OVRD;
+				nfc_op->ndcb[3] |= round_up(len, FIFO_DEPTH);
+			}
+			nfc_op->data_delay_ns = instr->delay_ns;
+			break;
+
+		case NAND_OP_WAITRDY_INSTR:
+			nfc_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms;
+			nfc_op->rdy_delay_ns = instr->delay_ns;
+			break;
+		}
+	}
+}
+
+static int marvell_nfc_xfer_data_pio(struct nand_chip *chip,
+				     const struct nand_subop *subop,
+				     struct marvell_nfc_op *nfc_op)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct nand_op_instr *instr = nfc_op->data_instr;
+	unsigned int op_id = nfc_op->data_instr_idx;
+	unsigned int len = nand_subop_get_data_len(subop, op_id);
+	unsigned int offset = nand_subop_get_data_start_off(subop, op_id);
+	bool reading = (instr->type == NAND_OP_DATA_IN_INSTR);
+	int ret;
+
+	if (instr->ctx.data.force_8bit)
+		marvell_nfc_force_byte_access(chip, true);
+
+	if (reading) {
+		u8 *in = instr->ctx.data.buf.in + offset;
+
+		ret = marvell_nfc_xfer_data_in_pio(nfc, in, len);
+	} else {
+		const u8 *out = instr->ctx.data.buf.out + offset;
+
+		ret = marvell_nfc_xfer_data_out_pio(nfc, out, len);
+	}
+
+	if (instr->ctx.data.force_8bit)
+		marvell_nfc_force_byte_access(chip, false);
+
+	return ret;
+}
+
+static int marvell_nfc_monolithic_access_exec(struct nand_chip *chip,
+					      const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	bool reading;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	reading = (nfc_op.data_instr->type == NAND_OP_DATA_IN_INSTR);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
+				  "RDDREQ/WRDREQ while draining raw data");
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	if (reading) {
+		if (nfc_op.rdy_timeout_ms) {
+			ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+			if (ret)
+				return ret;
+		}
+
+		cond_delay(nfc_op.rdy_delay_ns);
+	}
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.data_delay_ns);
+
+	if (!reading) {
+		if (nfc_op.rdy_timeout_ms) {
+			ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+			if (ret)
+				return ret;
+		}
+
+		cond_delay(nfc_op.rdy_delay_ns);
+	}
+
+	/*
+	 * NDCR ND_RUN bit should be cleared automatically at the end of each
+	 * operation but experience shows that the behavior is buggy when it
+	 * comes to writes (with LEN_OVRD). Clear it by hand in this case.
+	 */
+	if (!reading) {
+		struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
+			       nfc->regs + NDCR);
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_naked_access_exec(struct nand_chip *chip,
+					 const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+
+	/*
+	 * Naked access are different in that they need to be flagged as naked
+	 * by the controller. Reset the controller registers fields that inform
+	 * on the type and refill them according to the ongoing operation.
+	 */
+	nfc_op.ndcb[0] &= ~(NDCB0_CMD_TYPE(TYPE_MASK) |
+			    NDCB0_CMD_XTYPE(XTYPE_MASK));
+	switch (subop->instrs[0].type) {
+	case NAND_OP_CMD_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_CMD);
+		break;
+	case NAND_OP_ADDR_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_NAKED_ADDR);
+		break;
+	case NAND_OP_DATA_IN_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ) |
+				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+		break;
+	case NAND_OP_DATA_OUT_INSTR:
+		nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_WRITE) |
+				  NDCB0_CMD_XTYPE(XTYPE_LAST_NAKED_RW);
+		break;
+	default:
+		/* This should never happen */
+		break;
+	}
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+
+	if (!nfc_op.data_instr) {
+		ret = marvell_nfc_wait_cmdd(chip);
+		cond_delay(nfc_op.cle_ale_delay_ns);
+		return ret;
+	}
+
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ | NDSR_WRDREQ,
+				  "RDDREQ/WRDREQ while draining raw data");
+	if (ret)
+		return ret;
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	/*
+	 * NDCR ND_RUN bit should be cleared automatically at the end of each
+	 * operation but experience shows that the behavior is buggy when it
+	 * comes to writes (with LEN_OVRD). Clear it by hand in this case.
+	 */
+	if (subop->instrs[0].type == NAND_OP_DATA_OUT_INSTR) {
+		struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+		writel_relaxed(readl(nfc->regs + NDCR) & ~NDCR_ND_RUN,
+			       nfc->regs + NDCR);
+	}
+
+	return 0;
+}
+
+static int marvell_nfc_naked_waitrdy_exec(struct nand_chip *chip,
+					  const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+
+	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	return ret;
+}
+
+static int marvell_nfc_read_id_type_exec(struct nand_chip *chip,
+					 const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_READ_ID);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				  "RDDREQ while reading ID");
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	if (nfc_op.rdy_timeout_ms) {
+		ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+		if (ret)
+			return ret;
+	}
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.data_delay_ns);
+
+	return 0;
+}
+
+static int marvell_nfc_read_status_exec(struct nand_chip *chip,
+					const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] &= ~NDCB0_CMD_TYPE(TYPE_READ);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_STATUS);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_end_cmd(chip, NDSR_RDDREQ,
+				  "RDDREQ while reading status");
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	if (nfc_op.rdy_timeout_ms) {
+		ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+		if (ret)
+			return ret;
+	}
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	marvell_nfc_xfer_data_pio(chip, subop, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.data_delay_ns);
+
+	return 0;
+}
+
+static int marvell_nfc_reset_cmd_type_exec(struct nand_chip *chip,
+					   const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_RESET);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	return 0;
+}
+
+static int marvell_nfc_erase_cmd_type_exec(struct nand_chip *chip,
+					   const struct nand_subop *subop)
+{
+	struct marvell_nfc_op nfc_op;
+	int ret;
+
+	marvell_nfc_parse_instructions(chip, subop, &nfc_op);
+	nfc_op.ndcb[0] |= NDCB0_CMD_TYPE(TYPE_ERASE);
+
+	ret = marvell_nfc_prepare_cmd(chip);
+	if (ret)
+		return ret;
+
+	marvell_nfc_send_cmd(chip, &nfc_op);
+	ret = marvell_nfc_wait_cmdd(chip);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.cle_ale_delay_ns);
+
+	ret = marvell_nfc_wait_op(chip, nfc_op.rdy_timeout_ms);
+	if (ret)
+		return ret;
+
+	cond_delay(nfc_op.rdy_delay_ns);
+
+	return 0;
+}
+
+static const struct nand_op_parser marvell_nfcv2_op_parser = NAND_OP_PARSER(
+	/* Monolithic reads/writes */
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_monolithic_access_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC_NFCV2),
+		NAND_OP_PARSER_PAT_CMD_ELEM(true),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_monolithic_access_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2),
+		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE),
+		NAND_OP_PARSER_PAT_CMD_ELEM(true),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+	/* Naked commands */
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV2)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, MAX_CHUNK_SIZE)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_access_exec,
+		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_CHUNK_SIZE)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_waitrdy_exec,
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	);
+
+static const struct nand_op_parser marvell_nfcv1_op_parser = NAND_OP_PARSER(
+	/* Naked commands not supported, use a function for each pattern */
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_read_id_type_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_erase_cmd_type_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYC_NFCV1),
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_read_status_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_reset_cmd_type_exec,
+		NAND_OP_PARSER_PAT_CMD_ELEM(false),
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	NAND_OP_PARSER_PATTERN(
+		marvell_nfc_naked_waitrdy_exec,
+		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+	);
+
+static int marvell_nfc_exec_op(struct nand_chip *chip,
+			       const struct nand_operation *op,
+			       bool check_only)
+{
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+
+	if (nfc->caps->is_nfcv2)
+		return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser,
+					      op, check_only);
+	else
+		return nand_op_parser_exec_op(chip, &marvell_nfcv1_op_parser,
+					      op, check_only);
+}
+
+/*
+ * Layouts were broken in old pxa3xx_nand driver, these are supposed to be
+ * usable.
+ */
+static int marvell_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = (lt->full_chunk_cnt * lt->ecc_bytes) +
+			    lt->last_ecc_bytes;
+	oobregion->offset = mtd->oobsize - oobregion->length;
+
+	return 0;
+}
+
+static int marvell_nand_ooblayout_free(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
+
+	if (section)
+		return -ERANGE;
+
+	/*
+	 * Bootrom looks in bytes 0 & 5 for bad blocks for the
+	 * 4KB page / 4bit BCH combination.
+	 */
+	if (mtd->writesize == SZ_4K && lt->data_bytes == SZ_2K)
+		oobregion->offset = 6;
+	else
+		oobregion->offset = 2;
+
+	oobregion->length = (lt->full_chunk_cnt * lt->spare_bytes) +
+			    lt->last_spare_bytes - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops marvell_nand_ooblayout_ops = {
+	.ecc = marvell_nand_ooblayout_ecc,
+	.free = marvell_nand_ooblayout_free,
+};
+
+static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
+					 struct nand_ecc_ctrl *ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	const struct marvell_hw_ecc_layout *l;
+	int i;
+
+	if (!nfc->caps->is_nfcv2 &&
+	    (mtd->writesize + mtd->oobsize > MAX_CHUNK_SIZE)) {
+		dev_err(nfc->dev,
+			"NFCv1: writesize (%d) cannot be bigger than a chunk (%d)\n",
+			mtd->writesize, MAX_CHUNK_SIZE - mtd->oobsize);
+		return -ENOTSUPP;
+	}
+
+	to_marvell_nand(chip)->layout = NULL;
+	for (i = 0; i < ARRAY_SIZE(marvell_nfc_layouts); i++) {
+		l = &marvell_nfc_layouts[i];
+		if (mtd->writesize == l->writesize &&
+		    ecc->size == l->chunk && ecc->strength == l->strength) {
+			to_marvell_nand(chip)->layout = l;
+			break;
+		}
+	}
+
+	if (!to_marvell_nand(chip)->layout ||
+	    (!nfc->caps->is_nfcv2 && ecc->strength > 1)) {
+		dev_err(nfc->dev,
+			"ECC strength %d at page size %d is not supported\n",
+			ecc->strength, mtd->writesize);
+		return -ENOTSUPP;
+	}
+
+	mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
+	ecc->steps = l->nchunks;
+	ecc->size = l->data_bytes;
+
+	if (ecc->strength == 1) {
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		ecc->read_page_raw = marvell_nfc_hw_ecc_hmg_read_page_raw;
+		ecc->read_page = marvell_nfc_hw_ecc_hmg_read_page;
+		ecc->read_oob_raw = marvell_nfc_hw_ecc_hmg_read_oob_raw;
+		ecc->read_oob = ecc->read_oob_raw;
+		ecc->write_page_raw = marvell_nfc_hw_ecc_hmg_write_page_raw;
+		ecc->write_page = marvell_nfc_hw_ecc_hmg_write_page;
+		ecc->write_oob_raw = marvell_nfc_hw_ecc_hmg_write_oob_raw;
+		ecc->write_oob = ecc->write_oob_raw;
+	} else {
+		chip->ecc.algo = NAND_ECC_BCH;
+		ecc->strength = 16;
+		ecc->read_page_raw = marvell_nfc_hw_ecc_bch_read_page_raw;
+		ecc->read_page = marvell_nfc_hw_ecc_bch_read_page;
+		ecc->read_oob_raw = marvell_nfc_hw_ecc_bch_read_oob_raw;
+		ecc->read_oob = marvell_nfc_hw_ecc_bch_read_oob;
+		ecc->write_page_raw = marvell_nfc_hw_ecc_bch_write_page_raw;
+		ecc->write_page = marvell_nfc_hw_ecc_bch_write_page;
+		ecc->write_oob_raw = marvell_nfc_hw_ecc_bch_write_oob_raw;
+		ecc->write_oob = marvell_nfc_hw_ecc_bch_write_oob;
+	}
+
+	return 0;
+}
+
+static int marvell_nand_ecc_init(struct mtd_info *mtd,
+				 struct nand_ecc_ctrl *ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	int ret;
+
+	if (ecc->mode != NAND_ECC_NONE && (!ecc->size || !ecc->strength)) {
+		if (chip->ecc_step_ds && chip->ecc_strength_ds) {
+			ecc->size = chip->ecc_step_ds;
+			ecc->strength = chip->ecc_strength_ds;
+		} else {
+			dev_info(nfc->dev,
+				 "No minimum ECC strength, using 1b/512B\n");
+			ecc->size = 512;
+			ecc->strength = 1;
+		}
+	}
+
+	switch (ecc->mode) {
+	case NAND_ECC_HW:
+		ret = marvell_nand_hw_ecc_ctrl_init(mtd, ecc);
+		if (ret)
+			return ret;
+		break;
+	case NAND_ECC_NONE:
+	case NAND_ECC_SOFT:
+		if (!nfc->caps->is_nfcv2 && mtd->writesize != SZ_512 &&
+		    mtd->writesize != SZ_2K) {
+			dev_err(nfc->dev, "NFCv1 cannot write %d bytes pages\n",
+				mtd->writesize);
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
+static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	8,
+	.len = 6,
+	.veroffs = 14,
+	.maxblocks = 8,	/* Last 8 blocks in each chip */
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	8,
+	.len = 6,
+	.veroffs = 14,
+	.maxblocks = 8,	/* Last 8 blocks in each chip */
+	.pattern = bbt_mirror_pattern
+};
+
+static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
+					    const struct nand_data_interface
+					    *conf)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+	struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+	unsigned int period_ns = 1000000000 / clk_get_rate(nfc->ecc_clk) * 2;
+	const struct nand_sdr_timings *sdr;
+	struct marvell_nfc_timings nfc_tmg;
+	int read_delay;
+
+	sdr = nand_get_sdr_timings(conf);
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	/*
+	 * SDR timings are given in pico-seconds while NFC timings must be
+	 * expressed in NAND controller clock cycles, which is half of the
+	 * frequency of the accessible ECC clock retrieved by clk_get_rate().
+	 * This is not written anywhere in the datasheet but was observed
+	 * with an oscilloscope.
+	 *
+	 * NFC datasheet gives equations from which thoses calculations
+	 * are derived, they tend to be slightly more restrictives than the
+	 * given core timings and may improve the overall speed.
+	 */
+	nfc_tmg.tRP = TO_CYCLES(DIV_ROUND_UP(sdr->tRC_min, 2), period_ns) - 1;
+	nfc_tmg.tRH = nfc_tmg.tRP;
+	nfc_tmg.tWP = TO_CYCLES(DIV_ROUND_UP(sdr->tWC_min, 2), period_ns) - 1;
+	nfc_tmg.tWH = nfc_tmg.tWP;
+	nfc_tmg.tCS = TO_CYCLES(sdr->tCS_min, period_ns);
+	nfc_tmg.tCH = TO_CYCLES(sdr->tCH_min, period_ns) - 1;
+	nfc_tmg.tADL = TO_CYCLES(sdr->tADL_min, period_ns);
+	/*
+	 * Read delay is the time of propagation from SoC pins to NFC internal
+	 * logic. With non-EDO timings, this is MIN_RD_DEL_CNT clock cycles. In
+	 * EDO mode, an additional delay of tRH must be taken into account so
+	 * the data is sampled on the falling edge instead of the rising edge.
+	 */
+	read_delay = sdr->tRC_min >= 30000 ?
+		MIN_RD_DEL_CNT : MIN_RD_DEL_CNT + nfc_tmg.tRH;
+
+	nfc_tmg.tAR = TO_CYCLES(sdr->tAR_min, period_ns);
+	/*
+	 * tWHR and tRHW are supposed to be read to write delays (and vice
+	 * versa) but in some cases, ie. when doing a change column, they must
+	 * be greater than that to be sure tCCS delay is respected.
+	 */
+	nfc_tmg.tWHR = TO_CYCLES(max_t(int, sdr->tWHR_min, sdr->tCCS_min),
+				 period_ns) - 2,
+	nfc_tmg.tRHW = TO_CYCLES(max_t(int, sdr->tRHW_min, sdr->tCCS_min),
+				 period_ns);
+
+	/*
+	 * NFCv2: Use WAIT_MODE (wait for RB line), do not rely only on delays.
+	 * NFCv1: No WAIT_MODE, tR must be maximal.
+	 */
+	if (nfc->caps->is_nfcv2) {
+		nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns);
+	} else {
+		nfc_tmg.tR = TO_CYCLES64(sdr->tWB_max + sdr->tR_max,
+					 period_ns);
+		if (nfc_tmg.tR + 3 > nfc_tmg.tCH)
+			nfc_tmg.tR = nfc_tmg.tCH - 3;
+		else
+			nfc_tmg.tR = 0;
+	}
+
+	if (chipnr < 0)
+		return 0;
+
+	marvell_nand->ndtr0 =
+		NDTR0_TRP(nfc_tmg.tRP) |
+		NDTR0_TRH(nfc_tmg.tRH) |
+		NDTR0_ETRP(nfc_tmg.tRP) |
+		NDTR0_TWP(nfc_tmg.tWP) |
+		NDTR0_TWH(nfc_tmg.tWH) |
+		NDTR0_TCS(nfc_tmg.tCS) |
+		NDTR0_TCH(nfc_tmg.tCH);
+
+	marvell_nand->ndtr1 =
+		NDTR1_TAR(nfc_tmg.tAR) |
+		NDTR1_TWHR(nfc_tmg.tWHR) |
+		NDTR1_TR(nfc_tmg.tR);
+
+	if (nfc->caps->is_nfcv2) {
+		marvell_nand->ndtr0 |=
+			NDTR0_RD_CNT_DEL(read_delay) |
+			NDTR0_SELCNTR |
+			NDTR0_TADL(nfc_tmg.tADL);
+
+		marvell_nand->ndtr1 |=
+			NDTR1_TRHW(nfc_tmg.tRHW) |
+			NDTR1_WAIT_MODE;
+	}
+
+	return 0;
+}
+
+static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
+				  struct device_node *np)
+{
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(dev);
+	struct marvell_nand_chip *marvell_nand;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	int nsels, ret, i;
+	u32 cs, rb;
+
+	/*
+	 * The legacy "num-cs" property indicates the number of CS on the only
+	 * chip connected to the controller (legacy bindings does not support
+	 * more than one chip). CS are only incremented one by one while the RB
+	 * pin is always the #0.
+	 *
+	 * When not using legacy bindings, a couple of "reg" and "nand-rb"
+	 * properties must be filled. For each chip, expressed as a subnode,
+	 * "reg" points to the CS lines and "nand-rb" to the RB line.
+	 */
+	if (pdata) {
+		nsels = 1;
+	} else if (nfc->caps->legacy_of_bindings &&
+		   !of_get_property(np, "num-cs", &nsels)) {
+		dev_err(dev, "missing num-cs property\n");
+		return -EINVAL;
+	} else if (!of_get_property(np, "reg", &nsels)) {
+		dev_err(dev, "missing reg property\n");
+		return -EINVAL;
+	}
+
+	if (!pdata)
+		nsels /= sizeof(u32);
+	if (!nsels) {
+		dev_err(dev, "invalid reg property size\n");
+		return -EINVAL;
+	}
+
+	/* Alloc the nand chip structure */
+	marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) +
+				    (nsels *
+				     sizeof(struct marvell_nand_chip_sel)),
+				    GFP_KERNEL);
+	if (!marvell_nand) {
+		dev_err(dev, "could not allocate chip structure\n");
+		return -ENOMEM;
+	}
+
+	marvell_nand->nsels = nsels;
+	marvell_nand->selected_die = -1;
+
+	for (i = 0; i < nsels; i++) {
+		if (pdata || nfc->caps->legacy_of_bindings) {
+			/*
+			 * Legacy bindings use the CS lines in natural
+			 * order (0, 1, ...)
+			 */
+			cs = i;
+		} else {
+			/* Retrieve CS id */
+			ret = of_property_read_u32_index(np, "reg", i, &cs);
+			if (ret) {
+				dev_err(dev, "could not retrieve reg property: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
+		if (cs >= nfc->caps->max_cs_nb) {
+			dev_err(dev, "invalid reg value: %u (max CS = %d)\n",
+				cs, nfc->caps->max_cs_nb);
+			return -EINVAL;
+		}
+
+		if (test_and_set_bit(cs, &nfc->assigned_cs)) {
+			dev_err(dev, "CS %d already assigned\n", cs);
+			return -EINVAL;
+		}
+
+		/*
+		 * The cs variable represents the chip select id, which must be
+		 * converted in bit fields for NDCB0 and NDCB2 to select the
+		 * right chip. Unfortunately, due to a lack of information on
+		 * the subject and incoherent documentation, the user should not
+		 * use CS1 and CS3 at all as asserting them is not supported in
+		 * a reliable way (due to multiplexing inside ADDR5 field).
+		 */
+		marvell_nand->sels[i].cs = cs;
+		switch (cs) {
+		case 0:
+		case 2:
+			marvell_nand->sels[i].ndcb0_csel = 0;
+			break;
+		case 1:
+		case 3:
+			marvell_nand->sels[i].ndcb0_csel = NDCB0_CSEL;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Retrieve RB id */
+		if (pdata || nfc->caps->legacy_of_bindings) {
+			/* Legacy bindings always use RB #0 */
+			rb = 0;
+		} else {
+			ret = of_property_read_u32_index(np, "nand-rb", i,
+							 &rb);
+			if (ret) {
+				dev_err(dev,
+					"could not retrieve RB property: %d\n",
+					ret);
+				return ret;
+			}
+		}
+
+		if (rb >= nfc->caps->max_rb_nb) {
+			dev_err(dev, "invalid reg value: %u (max RB = %d)\n",
+				rb, nfc->caps->max_rb_nb);
+			return -EINVAL;
+		}
+
+		marvell_nand->sels[i].rb = rb;
+	}
+
+	chip = &marvell_nand->chip;
+	chip->controller = &nfc->controller;
+	nand_set_flash_node(chip, np);
+
+	chip->exec_op = marvell_nfc_exec_op;
+	chip->select_chip = marvell_nfc_select_chip;
+	if (!of_property_read_bool(np, "marvell,nand-keep-config"))
+		chip->setup_data_interface = marvell_nfc_setup_data_interface;
+
+	mtd = nand_to_mtd(chip);
+	mtd->dev.parent = dev;
+
+	/*
+	 * Default to HW ECC engine mode. If the nand-ecc-mode property is given
+	 * in the DT node, this entry will be overwritten in nand_scan_ident().
+	 */
+	chip->ecc.mode = NAND_ECC_HW;
+
+	/*
+	 * Save a reference value for timing registers before
+	 * ->setup_data_interface() is called.
+	 */
+	marvell_nand->ndtr0 = readl_relaxed(nfc->regs + NDTR0);
+	marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);
+
+	chip->options |= NAND_BUSWIDTH_AUTO;
+	ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
+	if (ret) {
+		dev_err(dev, "could not identify the nand chip\n");
+		return ret;
+	}
+
+	if (pdata && pdata->flash_bbt)
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+		/*
+		 * We'll use a bad block table stored in-flash and don't
+		 * allow writing the bad block marker to the flash.
+		 */
+		chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+		chip->bbt_td = &bbt_main_descr;
+		chip->bbt_md = &bbt_mirror_descr;
+	}
+
+	/* Save the chip-specific fields of NDCR */
+	marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
+	if (chip->options & NAND_BUSWIDTH_16)
+		marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+	/*
+	 * On small page NANDs, only one cycle is needed to pass the
+	 * column address.
+	 */
+	if (mtd->writesize <= 512) {
+		marvell_nand->addr_cyc = 1;
+	} else {
+		marvell_nand->addr_cyc = 2;
+		marvell_nand->ndcr |= NDCR_RA_START;
+	}
+
+	/*
+	 * Now add the number of cycles needed to pass the row
+	 * address.
+	 *
+	 * Addressing a chip using CS 2 or 3 should also need the third row
+	 * cycle but due to inconsistance in the documentation and lack of
+	 * hardware to test this situation, this case is not supported.
+	 */
+	if (chip->options & NAND_ROW_ADDR_3)
+		marvell_nand->addr_cyc += 3;
+	else
+		marvell_nand->addr_cyc += 2;
+
+	if (pdata) {
+		chip->ecc.size = pdata->ecc_step_size;
+		chip->ecc.strength = pdata->ecc_strength;
+	}
+
+	ret = marvell_nand_ecc_init(mtd, &chip->ecc);
+	if (ret) {
+		dev_err(dev, "ECC init failed: %d\n", ret);
+		return ret;
+	}
+
+	if (chip->ecc.mode == NAND_ECC_HW) {
+		/*
+		 * Subpage write not available with hardware ECC, prohibit also
+		 * subpage read as in userspace subpage access would still be
+		 * allowed and subpage write, if used, would lead to numerous
+		 * uncorrectable ECC errors.
+		 */
+		chip->options |= NAND_NO_SUBPAGE_WRITE;
+	}
+
+	if (pdata || nfc->caps->legacy_of_bindings) {
+		/*
+		 * We keep the MTD name unchanged to avoid breaking platforms
+		 * where the MTD cmdline parser is used and the bootloader
+		 * has not been updated to use the new naming scheme.
+		 */
+		mtd->name = "pxa3xx_nand-0";
+	} else if (!mtd->name) {
+		/*
+		 * If the new bindings are used and the bootloader has not been
+		 * updated to pass a new mtdparts parameter on the cmdline, you
+		 * should define the following property in your NAND node, ie:
+		 *
+		 *	label = "main-storage";
+		 *
+		 * This way, mtd->name will be set by the core when
+		 * nand_set_flash_node() is called.
+		 */
+		mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
+					   "%s:nand.%d", dev_name(nfc->dev),
+					   marvell_nand->sels[0].cs);
+		if (!mtd->name) {
+			dev_err(nfc->dev, "Failed to allocate mtd->name\n");
+			return -ENOMEM;
+		}
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata)
+		/* Legacy bindings support only one chip */
+		ret = mtd_device_register(mtd, pdata->parts[0],
+					  pdata->nr_parts[0]);
+	else
+		ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(dev, "failed to register mtd device: %d\n", ret);
+		nand_release(mtd);
+		return ret;
+	}
+
+	list_add_tail(&marvell_nand->node, &nfc->chips);
+
+	return 0;
+}
+
+static int marvell_nand_chips_init(struct device *dev, struct marvell_nfc *nfc)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *nand_np;
+	int max_cs = nfc->caps->max_cs_nb;
+	int nchips;
+	int ret;
+
+	if (!np)
+		nchips = 1;
+	else
+		nchips = of_get_child_count(np);
+
+	if (nchips > max_cs) {
+		dev_err(dev, "too many NAND chips: %d (max = %d CS)\n", nchips,
+			max_cs);
+		return -EINVAL;
+	}
+
+	/*
+	 * Legacy bindings do not use child nodes to exhibit NAND chip
+	 * properties and layout. Instead, NAND properties are mixed with the
+	 * controller ones, and partitions are defined as direct subnodes of the
+	 * NAND controller node.
+	 */
+	if (nfc->caps->legacy_of_bindings) {
+		ret = marvell_nand_chip_init(dev, nfc, np);
+		return ret;
+	}
+
+	for_each_child_of_node(np, nand_np) {
+		ret = marvell_nand_chip_init(dev, nfc, nand_np);
+		if (ret) {
+			of_node_put(nand_np);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
+{
+	struct marvell_nand_chip *entry, *temp;
+
+	list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
+		nand_release(nand_to_mtd(&entry->chip));
+		list_del(&entry->node);
+	}
+}
+
+static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
+{
+	struct platform_device *pdev = container_of(nfc->dev,
+						    struct platform_device,
+						    dev);
+	struct dma_slave_config config = {};
+	struct resource *r;
+	dma_cap_mask_t mask;
+	struct pxad_param param;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_PXA_DMA)) {
+		dev_warn(nfc->dev,
+			 "DMA not enabled in configuration\n");
+		return -ENOTSUPP;
+	}
+
+	ret = dma_set_mask_and_coherent(nfc->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!r) {
+		dev_err(nfc->dev, "No resource defined for data DMA\n");
+		return -ENXIO;
+	}
+
+	param.drcmr = r->start;
+	param.prio = PXAD_PRIO_LOWEST;
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	nfc->dma_chan =
+		dma_request_slave_channel_compat(mask, pxad_filter_fn,
+						 &param, nfc->dev,
+						 "data");
+	if (!nfc->dma_chan) {
+		dev_err(nfc->dev,
+			"Unable to request data DMA channel\n");
+		return -ENODEV;
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -ENXIO;
+
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.src_addr = r->start + NDDB;
+	config.dst_addr = r->start + NDDB;
+	config.src_maxburst = 32;
+	config.dst_maxburst = 32;
+	ret = dmaengine_slave_config(nfc->dma_chan, &config);
+	if (ret < 0) {
+		dev_err(nfc->dev, "Failed to configure DMA channel\n");
+		return ret;
+	}
+
+	/*
+	 * DMA must act on length multiple of 32 and this length may be
+	 * bigger than the destination buffer. Use this buffer instead
+	 * for DMA transfers and then copy the desired amount of data to
+	 * the provided buffer.
+	 */
+	nfc->dma_buf = kmalloc(MAX_CHUNK_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!nfc->dma_buf)
+		return -ENOMEM;
+
+	nfc->use_dma = true;
+
+	return 0;
+}
+
+static int marvell_nfc_init(struct marvell_nfc *nfc)
+{
+	struct device_node *np = nfc->dev->of_node;
+
+	/*
+	 * Some SoCs like A7k/A8k need to enable manually the NAND
+	 * controller, gated clocks and reset bits to avoid being bootloader
+	 * dependent. This is done through the use of the System Functions
+	 * registers.
+	 */
+	if (nfc->caps->need_system_controller) {
+		struct regmap *sysctrl_base =
+			syscon_regmap_lookup_by_phandle(np,
+							"marvell,system-controller");
+		u32 reg;
+
+		if (IS_ERR(sysctrl_base))
+			return PTR_ERR(sysctrl_base);
+
+		reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
+		      GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
+		      GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
+		      GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
+		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+
+		regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
+		reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
+		regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
+
+		regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
+		reg |= GENCONF_ND_CLK_CTRL_EN;
+		regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+	}
+
+	/* Configure the DMA if appropriate */
+	if (!nfc->caps->is_nfcv2)
+		marvell_nfc_init_dma(nfc);
+
+	/*
+	 * ECC operations and interruptions are only enabled when specifically
+	 * needed. ECC shall not be activated in the early stages (fails probe).
+	 * Arbiter flag, even if marked as "reserved", must be set (empirical).
+	 * SPARE_EN bit must always be set or ECC bytes will not be at the same
+	 * offset in the read page and this will fail the protection.
+	 */
+	writel_relaxed(NDCR_ALL_INT | NDCR_ND_ARB_EN | NDCR_SPARE_EN |
+		       NDCR_RD_ID_CNT(NFCV1_READID_LEN), nfc->regs + NDCR);
+	writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
+	writel_relaxed(0, nfc->regs + NDECCCTRL);
+
+	return 0;
+}
+
+static int marvell_nfc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *r;
+	struct marvell_nfc *nfc;
+	int ret;
+	int irq;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(struct marvell_nfc),
+			   GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	nfc->dev = dev;
+	nand_hw_control_init(&nfc->controller);
+	INIT_LIST_HEAD(&nfc->chips);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->regs = devm_ioremap_resource(dev, r);
+	if (IS_ERR(nfc->regs))
+		return PTR_ERR(nfc->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "failed to retrieve irq\n");
+		return irq;
+	}
+
+	nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(nfc->ecc_clk))
+		return PTR_ERR(nfc->ecc_clk);
+
+	ret = clk_prepare_enable(nfc->ecc_clk);
+	if (ret)
+		return ret;
+
+	marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
+	marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
+	ret = devm_request_irq(dev, irq, marvell_nfc_isr,
+			       0, "marvell-nfc", nfc);
+	if (ret)
+		goto unprepare_clk;
+
+	/* Get NAND controller capabilities */
+	if (pdev->id_entry)
+		nfc->caps = (void *)pdev->id_entry->driver_data;
+	else
+		nfc->caps = of_device_get_match_data(&pdev->dev);
+
+	if (!nfc->caps) {
+		dev_err(dev, "Could not retrieve NFC caps\n");
+		ret = -EINVAL;
+		goto unprepare_clk;
+	}
+
+	/* Init the controller and then probe the chips */
+	ret = marvell_nfc_init(nfc);
+	if (ret)
+		goto unprepare_clk;
+
+	platform_set_drvdata(pdev, nfc);
+
+	ret = marvell_nand_chips_init(dev, nfc);
+	if (ret)
+		goto unprepare_clk;
+
+	return 0;
+
+unprepare_clk:
+	clk_disable_unprepare(nfc->ecc_clk);
+
+	return ret;
+}
+
+static int marvell_nfc_remove(struct platform_device *pdev)
+{
+	struct marvell_nfc *nfc = platform_get_drvdata(pdev);
+
+	marvell_nand_chips_cleanup(nfc);
+
+	if (nfc->use_dma) {
+		dmaengine_terminate_all(nfc->dma_chan);
+		dma_release_channel(nfc->dma_chan);
+	}
+
+	clk_disable_unprepare(nfc->ecc_clk);
+
+	return 0;
+}
+
+static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.need_system_controller = true,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_armada370_nfc_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_pxa3xx_nfc_caps = {
+	.max_cs_nb = 2,
+	.max_rb_nb = 1,
+	.use_dma = true,
+};
+
+static const struct marvell_nfc_caps marvell_armada_8k_nfc_legacy_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.need_system_controller = true,
+	.legacy_of_bindings = true,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_armada370_nfc_legacy_caps = {
+	.max_cs_nb = 4,
+	.max_rb_nb = 2,
+	.legacy_of_bindings = true,
+	.is_nfcv2 = true,
+};
+
+static const struct marvell_nfc_caps marvell_pxa3xx_nfc_legacy_caps = {
+	.max_cs_nb = 2,
+	.max_rb_nb = 1,
+	.legacy_of_bindings = true,
+	.use_dma = true,
+};
+
+static const struct platform_device_id marvell_nfc_platform_ids[] = {
+	{
+		.name = "pxa3xx-nand",
+		.driver_data = (kernel_ulong_t)&marvell_pxa3xx_nfc_legacy_caps,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, marvell_nfc_platform_ids);
+
+static const struct of_device_id marvell_nfc_of_ids[] = {
+	{
+		.compatible = "marvell,armada-8k-nand-controller",
+		.data = &marvell_armada_8k_nfc_caps,
+	},
+	{
+		.compatible = "marvell,armada370-nand-controller",
+		.data = &marvell_armada370_nfc_caps,
+	},
+	{
+		.compatible = "marvell,pxa3xx-nand-controller",
+		.data = &marvell_pxa3xx_nfc_caps,
+	},
+	/* Support for old/deprecated bindings: */
+	{
+		.compatible = "marvell,armada-8k-nand",
+		.data = &marvell_armada_8k_nfc_legacy_caps,
+	},
+	{
+		.compatible = "marvell,armada370-nand",
+		.data = &marvell_armada370_nfc_legacy_caps,
+	},
+	{
+		.compatible = "marvell,pxa3xx-nand",
+		.data = &marvell_pxa3xx_nfc_legacy_caps,
+	},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, marvell_nfc_of_ids);
+
+static struct platform_driver marvell_nfc_driver = {
+	.driver	= {
+		.name		= "marvell-nfc",
+		.of_match_table = marvell_nfc_of_ids,
+	},
+	.id_table = marvell_nfc_platform_ids,
+	.probe = marvell_nfc_probe,
+	.remove	= marvell_nfc_remove,
+};
+module_platform_driver(marvell_nfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Marvell NAND controller driver");
diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
new file mode 100644
index 000000000000..913b9d1225c6
--- /dev/null
+++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
@@ -0,0 +1,856 @@
+/*
+ * Copyright 2004-2008 Freescale Semiconductor, Inc.
+ * Copyright 2009 Semihalf.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009;  for details see www.osadl.org.
+ *
+ * Based on original driver from Freescale Semiconductor
+ * written by John Rigby <jrigby@freescale.com> on basis of mxc_nand.c.
+ * Reworked and extended by Piotr Ziecik <kosmo@semihalf.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/gfp.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/mpc5121.h>
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n)	((n) *  0x200)
+
+/* Addresses for NFC SPARE BUFFER areas */
+#define NFC_SPARE_BUFFERS	8
+#define NFC_SPARE_LEN		0x40
+#define NFC_SPARE_AREA(n)	(0x1000 + ((n) * NFC_SPARE_LEN))
+
+/* MPC5121 NFC registers */
+#define NFC_BUF_ADDR		0x1E04
+#define NFC_FLASH_ADDR		0x1E06
+#define NFC_FLASH_CMD		0x1E08
+#define NFC_CONFIG		0x1E0A
+#define NFC_ECC_STATUS1		0x1E0C
+#define NFC_ECC_STATUS2		0x1E0E
+#define NFC_SPAS		0x1E10
+#define NFC_WRPROT		0x1E12
+#define NFC_NF_WRPRST		0x1E18
+#define NFC_CONFIG1		0x1E1A
+#define NFC_CONFIG2		0x1E1C
+#define NFC_UNLOCKSTART_BLK0	0x1E20
+#define NFC_UNLOCKEND_BLK0	0x1E22
+#define NFC_UNLOCKSTART_BLK1	0x1E24
+#define NFC_UNLOCKEND_BLK1	0x1E26
+#define NFC_UNLOCKSTART_BLK2	0x1E28
+#define NFC_UNLOCKEND_BLK2	0x1E2A
+#define NFC_UNLOCKSTART_BLK3	0x1E2C
+#define NFC_UNLOCKEND_BLK3	0x1E2E
+
+/* Bit Definitions: NFC_BUF_ADDR */
+#define NFC_RBA_MASK		(7 << 0)
+#define NFC_ACTIVE_CS_SHIFT	5
+#define NFC_ACTIVE_CS_MASK	(3 << NFC_ACTIVE_CS_SHIFT)
+
+/* Bit Definitions: NFC_CONFIG */
+#define NFC_BLS_UNLOCKED	(1 << 1)
+
+/* Bit Definitions: NFC_CONFIG1 */
+#define NFC_ECC_4BIT		(1 << 0)
+#define NFC_FULL_PAGE_DMA	(1 << 1)
+#define NFC_SPARE_ONLY		(1 << 2)
+#define NFC_ECC_ENABLE		(1 << 3)
+#define NFC_INT_MASK		(1 << 4)
+#define NFC_BIG_ENDIAN		(1 << 5)
+#define NFC_RESET		(1 << 6)
+#define NFC_CE			(1 << 7)
+#define NFC_ONE_CYCLE		(1 << 8)
+#define NFC_PPB_32		(0 << 9)
+#define NFC_PPB_64		(1 << 9)
+#define NFC_PPB_128		(2 << 9)
+#define NFC_PPB_256		(3 << 9)
+#define NFC_PPB_MASK		(3 << 9)
+#define NFC_FULL_PAGE_INT	(1 << 11)
+
+/* Bit Definitions: NFC_CONFIG2 */
+#define NFC_COMMAND		(1 << 0)
+#define NFC_ADDRESS		(1 << 1)
+#define NFC_INPUT		(1 << 2)
+#define NFC_OUTPUT		(1 << 3)
+#define NFC_ID			(1 << 4)
+#define NFC_STATUS		(1 << 5)
+#define NFC_CMD_FAIL		(1 << 15)
+#define NFC_INT			(1 << 15)
+
+/* Bit Definitions: NFC_WRPROT */
+#define NFC_WPC_LOCK_TIGHT	(1 << 0)
+#define NFC_WPC_LOCK		(1 << 1)
+#define NFC_WPC_UNLOCK		(1 << 2)
+
+#define	DRV_NAME		"mpc5121_nfc"
+
+/* Timeouts */
+#define NFC_RESET_TIMEOUT	1000		/* 1 ms */
+#define NFC_TIMEOUT		(HZ / 10)	/* 1/10 s */
+
+struct mpc5121_nfc_prv {
+	struct nand_chip	chip;
+	int			irq;
+	void __iomem		*regs;
+	struct clk		*clk;
+	wait_queue_head_t	irq_waitq;
+	uint			column;
+	int			spareonly;
+	void __iomem		*csreg;
+	struct device		*dev;
+};
+
+static void mpc5121_nfc_done(struct mtd_info *mtd);
+
+/* Read NFC register */
+static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+
+	return in_be16(prv->regs + reg);
+}
+
+/* Write NFC register */
+static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+
+	out_be16(prv->regs + reg, val);
+}
+
+/* Set bits in NFC register */
+static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
+{
+	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
+}
+
+/* Clear bits in NFC register */
+static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
+{
+	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
+}
+
+/* Invoke address cycle */
+static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
+{
+	nfc_write(mtd, NFC_FLASH_ADDR, addr);
+	nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Invoke command cycle */
+static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
+{
+	nfc_write(mtd, NFC_FLASH_CMD, cmd);
+	nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Send data from NFC buffers to NAND flash */
+static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive data from NAND flash */
+static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive ID from NAND flash */
+static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_ID);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive status from NAND flash */
+static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
+	mpc5121_nfc_done(mtd);
+}
+
+/* NFC interrupt handler */
+static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
+{
+	struct mtd_info *mtd = data;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+
+	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
+	wake_up(&prv->irq_waitq);
+
+	return IRQ_HANDLED;
+}
+
+/* Wait for operation complete */
+static void mpc5121_nfc_done(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+	int rv;
+
+	if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
+		nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
+		rv = wait_event_timeout(prv->irq_waitq,
+			(nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
+
+		if (!rv)
+			dev_warn(prv->dev,
+				"Timeout while waiting for interrupt.\n");
+	}
+
+	nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
+}
+
+/* Do address cycle(s) */
+static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u32 pagemask = chip->pagemask;
+
+	if (column != -1) {
+		mpc5121_nfc_send_addr(mtd, column);
+		if (mtd->writesize > 512)
+			mpc5121_nfc_send_addr(mtd, column >> 8);
+	}
+
+	if (page != -1) {
+		do {
+			mpc5121_nfc_send_addr(mtd, page & 0xFF);
+			page >>= 8;
+			pagemask >>= 8;
+		} while (pagemask);
+	}
+}
+
+/* Control chip select signals */
+static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	if (chip < 0) {
+		nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
+		return;
+	}
+
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
+	nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
+							NFC_ACTIVE_CS_MASK);
+	nfc_set(mtd, NFC_CONFIG1, NFC_CE);
+}
+
+/* Init external chip select logic on ADS5121 board */
+static int ads5121_chipselect_init(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
+	if (dn) {
+		prv->csreg = of_iomap(dn, 0);
+		of_node_put(dn);
+		if (!prv->csreg)
+			return -ENOMEM;
+
+		/* CPLD Register 9 controls NAND /CE Lines */
+		prv->csreg += 9;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Control chips select signal on ADS5121 board */
+static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
+	u8 v;
+
+	v = in_8(prv->csreg);
+	v |= 0x0F;
+
+	if (chip >= 0) {
+		mpc5121_nfc_select_chip(mtd, 0);
+		v &= ~(1 << chip);
+	} else
+		mpc5121_nfc_select_chip(mtd, -1);
+
+	out_8(prv->csreg, v);
+}
+
+/* Read NAND Ready/Busy signal */
+static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+{
+	/*
+	 * NFC handles ready/busy signal internally. Therefore, this function
+	 * always returns status as ready.
+	 */
+	return 1;
+}
+
+/* Write command to NAND flash */
+static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
+							int column, int page)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+
+	prv->column = (column >= 0) ? column : 0;
+	prv->spareonly = 0;
+
+	switch (command) {
+	case NAND_CMD_PAGEPROG:
+		mpc5121_nfc_send_prog_page(mtd);
+		break;
+	/*
+	 * NFC does not support sub-page reads and writes,
+	 * so emulate them using full page transfers.
+	 */
+	case NAND_CMD_READ0:
+		column = 0;
+		break;
+
+	case NAND_CMD_READ1:
+		prv->column += 256;
+		command = NAND_CMD_READ0;
+		column = 0;
+		break;
+
+	case NAND_CMD_READOOB:
+		prv->spareonly = 1;
+		command = NAND_CMD_READ0;
+		column = 0;
+		break;
+
+	case NAND_CMD_SEQIN:
+		mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+		column = 0;
+		break;
+
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_READID:
+	case NAND_CMD_STATUS:
+		break;
+
+	default:
+		return;
+	}
+
+	mpc5121_nfc_send_cmd(mtd, command);
+	mpc5121_nfc_addr_cycle(mtd, column, page);
+
+	switch (command) {
+	case NAND_CMD_READ0:
+		if (mtd->writesize > 512)
+			mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
+		mpc5121_nfc_send_read_page(mtd);
+		break;
+
+	case NAND_CMD_READID:
+		mpc5121_nfc_send_read_id(mtd);
+		break;
+
+	case NAND_CMD_STATUS:
+		mpc5121_nfc_send_read_status(mtd);
+		if (chip->options & NAND_BUSWIDTH_16)
+			prv->column = 1;
+		else
+			prv->column = 0;
+		break;
+	}
+}
+
+/* Copy data from/to NFC spare buffers. */
+static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
+						u8 *buffer, uint size, int wr)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
+	uint o, s, sbsize, blksize;
+
+	/*
+	 * NAND spare area is available through NFC spare buffers.
+	 * The NFC divides spare area into (page_size / 512) chunks.
+	 * Each chunk is placed into separate spare memory area, using
+	 * first (spare_size / num_of_chunks) bytes of the buffer.
+	 *
+	 * For NAND device in which the spare area is not divided fully
+	 * by the number of chunks, number of used bytes in each spare
+	 * buffer is rounded down to the nearest even number of bytes,
+	 * and all remaining bytes are added to the last used spare area.
+	 *
+	 * For more information read section 26.6.10 of MPC5121e
+	 * Microcontroller Reference Manual, Rev. 3.
+	 */
+
+	/* Calculate number of valid bytes in each spare buffer */
+	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
+
+	while (size) {
+		/* Calculate spare buffer number */
+		s = offset / sbsize;
+		if (s > NFC_SPARE_BUFFERS - 1)
+			s = NFC_SPARE_BUFFERS - 1;
+
+		/*
+		 * Calculate offset to requested data block in selected spare
+		 * buffer and its size.
+		 */
+		o = offset - (s * sbsize);
+		blksize = min(sbsize - o, size);
+
+		if (wr)
+			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
+							buffer, blksize);
+		else
+			memcpy_fromio(buffer,
+				prv->regs + NFC_SPARE_AREA(s) + o, blksize);
+
+		buffer += blksize;
+		offset += blksize;
+		size -= blksize;
+	};
+}
+
+/* Copy data from/to NFC main and spare buffers */
+static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
+									int wr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+	uint c = prv->column;
+	uint l;
+
+	/* Handle spare area access */
+	if (prv->spareonly || c >= mtd->writesize) {
+		/* Calculate offset from beginning of spare area */
+		if (c >= mtd->writesize)
+			c -= mtd->writesize;
+
+		prv->column += len;
+		mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
+		return;
+	}
+
+	/*
+	 * Handle main area access - limit copy length to prevent
+	 * crossing main/spare boundary.
+	 */
+	l = min((uint)len, mtd->writesize - c);
+	prv->column += l;
+
+	if (wr)
+		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
+	else
+		memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
+
+	/* Handle crossing main/spare boundary */
+	if (l != len) {
+		buf += l;
+		len -= l;
+		mpc5121_nfc_buf_copy(mtd, buf, len, wr);
+	}
+}
+
+/* Read data from NFC buffers */
+static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+}
+
+/* Write data to NFC buffers */
+static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
+						const u_char *buf, int len)
+{
+	mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+}
+
+/* Read byte from NFC buffers */
+static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+{
+	u8 tmp;
+
+	mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
+
+	return tmp;
+}
+
+/* Read word from NFC buffers */
+static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
+{
+	u16 tmp;
+
+	mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+
+	return tmp;
+}
+
+/*
+ * Read NFC configuration from Reset Config Word
+ *
+ * NFC is configured during reset in basis of information stored
+ * in Reset Config Word. There is no other way to set NAND block
+ * size, spare size and bus width.
+ */
+static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+	struct mpc512x_reset_module *rm;
+	struct device_node *rmnode;
+	uint rcw_pagesize = 0;
+	uint rcw_sparesize = 0;
+	uint rcw_width;
+	uint rcwh;
+	uint romloc, ps;
+	int ret = 0;
+
+	rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+	if (!rmnode) {
+		dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' "
+					"node in device tree!\n");
+		return -ENODEV;
+	}
+
+	rm = of_iomap(rmnode, 0);
+	if (!rm) {
+		dev_err(prv->dev, "Error mapping reset module node!\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	rcwh = in_be32(&rm->rcwhr);
+
+	/* Bit 6: NFC bus width */
+	rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+
+	/* Bit 7: NFC Page/Spare size */
+	ps = (rcwh >> 7) & 0x1;
+
+	/* Bits [22:21]: ROM Location */
+	romloc = (rcwh >> 21) & 0x3;
+
+	/* Decode RCW bits */
+	switch ((ps << 2) | romloc) {
+	case 0x00:
+	case 0x01:
+		rcw_pagesize = 512;
+		rcw_sparesize = 16;
+		break;
+	case 0x02:
+	case 0x03:
+		rcw_pagesize = 4096;
+		rcw_sparesize = 128;
+		break;
+	case 0x04:
+	case 0x05:
+		rcw_pagesize = 2048;
+		rcw_sparesize = 64;
+		break;
+	case 0x06:
+	case 0x07:
+		rcw_pagesize = 4096;
+		rcw_sparesize = 218;
+		break;
+	}
+
+	mtd->writesize = rcw_pagesize;
+	mtd->oobsize = rcw_sparesize;
+	if (rcw_width == 2)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	dev_notice(prv->dev, "Configured for "
+				"%u-bit NAND, page size %u "
+				"with %u spare.\n",
+				rcw_width * 8, rcw_pagesize,
+				rcw_sparesize);
+	iounmap(rm);
+out:
+	of_node_put(rmnode);
+	return ret;
+}
+
+/* Free driver resources */
+static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
+
+	if (prv->clk)
+		clk_disable_unprepare(prv->clk);
+
+	if (prv->csreg)
+		iounmap(prv->csreg);
+}
+
+static int mpc5121_nfc_probe(struct platform_device *op)
+{
+	struct device_node *dn = op->dev.of_node;
+	struct clk *clk;
+	struct device *dev = &op->dev;
+	struct mpc5121_nfc_prv *prv;
+	struct resource res;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	unsigned long regs_paddr, regs_size;
+	const __be32 *chips_no;
+	int resettime = 0;
+	int retval = 0;
+	int rev, len;
+
+	/*
+	 * Check SoC revision. This driver supports only NFC
+	 * in MPC5121 revision 2 and MPC5123 revision 3.
+	 */
+	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
+	if ((rev != 2) && (rev != 3)) {
+		dev_err(dev, "SoC revision %u is not supported!\n", rev);
+		return -ENXIO;
+	}
+
+	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
+	if (!prv)
+		return -ENOMEM;
+
+	chip = &prv->chip;
+	mtd = nand_to_mtd(chip);
+
+	mtd->dev.parent = dev;
+	nand_set_controller_data(chip, prv);
+	nand_set_flash_node(chip, dn);
+	prv->dev = dev;
+
+	/* Read NFC configuration from Reset Config Word */
+	retval = mpc5121_nfc_read_hw_config(mtd);
+	if (retval) {
+		dev_err(dev, "Unable to read NFC config!\n");
+		return retval;
+	}
+
+	prv->irq = irq_of_parse_and_map(dn, 0);
+	if (prv->irq == NO_IRQ) {
+		dev_err(dev, "Error mapping IRQ!\n");
+		return -EINVAL;
+	}
+
+	retval = of_address_to_resource(dn, 0, &res);
+	if (retval) {
+		dev_err(dev, "Error parsing memory region!\n");
+		return retval;
+	}
+
+	chips_no = of_get_property(dn, "chips", &len);
+	if (!chips_no || len != sizeof(*chips_no)) {
+		dev_err(dev, "Invalid/missing 'chips' property!\n");
+		return -EINVAL;
+	}
+
+	regs_paddr = res.start;
+	regs_size = resource_size(&res);
+
+	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
+		dev_err(dev, "Error requesting memory region!\n");
+		return -EBUSY;
+	}
+
+	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
+	if (!prv->regs) {
+		dev_err(dev, "Error mapping memory region!\n");
+		return -ENOMEM;
+	}
+
+	mtd->name = "MPC5121 NAND";
+	chip->dev_ready = mpc5121_nfc_dev_ready;
+	chip->cmdfunc = mpc5121_nfc_command;
+	chip->read_byte = mpc5121_nfc_read_byte;
+	chip->read_word = mpc5121_nfc_read_word;
+	chip->read_buf = mpc5121_nfc_read_buf;
+	chip->write_buf = mpc5121_nfc_write_buf;
+	chip->select_chip = mpc5121_nfc_select_chip;
+	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+	chip->bbt_options = NAND_BBT_USE_FLASH;
+	chip->ecc.mode = NAND_ECC_SOFT;
+	chip->ecc.algo = NAND_ECC_HAMMING;
+
+	/* Support external chip-select logic on ADS5121 board */
+	if (of_machine_is_compatible("fsl,mpc5121ads")) {
+		retval = ads5121_chipselect_init(mtd);
+		if (retval) {
+			dev_err(dev, "Chipselect init error!\n");
+			return retval;
+		}
+
+		chip->select_chip = ads5121_select_chip;
+	}
+
+	/* Enable NFC clock */
+	clk = devm_clk_get(dev, "ipg");
+	if (IS_ERR(clk)) {
+		dev_err(dev, "Unable to acquire NFC clock!\n");
+		retval = PTR_ERR(clk);
+		goto error;
+	}
+	retval = clk_prepare_enable(clk);
+	if (retval) {
+		dev_err(dev, "Unable to enable NFC clock!\n");
+		goto error;
+	}
+	prv->clk = clk;
+
+	/* Reset NAND Flash controller */
+	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
+	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
+		if (resettime++ >= NFC_RESET_TIMEOUT) {
+			dev_err(dev, "Timeout while resetting NFC!\n");
+			retval = -EINVAL;
+			goto error;
+		}
+
+		udelay(1);
+	}
+
+	/* Enable write to NFC memory */
+	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
+
+	/* Enable write to all NAND pages */
+	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
+	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
+	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
+
+	/*
+	 * Setup NFC:
+	 *	- Big Endian transfers,
+	 *	- Interrupt after full page read/write.
+	 */
+	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
+							NFC_FULL_PAGE_INT);
+
+	/* Set spare area size */
+	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
+
+	init_waitqueue_head(&prv->irq_waitq);
+	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
+									mtd);
+	if (retval) {
+		dev_err(dev, "Error requesting IRQ!\n");
+		goto error;
+	}
+
+	/* Detect NAND chips */
+	retval = nand_scan(mtd, be32_to_cpup(chips_no));
+	if (retval) {
+		dev_err(dev, "NAND Flash not found !\n");
+		goto error;
+	}
+
+	/* Set erase block size */
+	switch (mtd->erasesize / mtd->writesize) {
+	case 32:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
+		break;
+
+	case 64:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
+		break;
+
+	case 128:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
+		break;
+
+	case 256:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
+		break;
+
+	default:
+		dev_err(dev, "Unsupported NAND flash!\n");
+		retval = -ENXIO;
+		goto error;
+	}
+
+	dev_set_drvdata(dev, mtd);
+
+	/* Register device in MTD */
+	retval = mtd_device_register(mtd, NULL, 0);
+	if (retval) {
+		dev_err(dev, "Error adding MTD device!\n");
+		goto error;
+	}
+
+	return 0;
+error:
+	mpc5121_nfc_free(dev, mtd);
+	return retval;
+}
+
+static int mpc5121_nfc_remove(struct platform_device *op)
+{
+	struct device *dev = &op->dev;
+	struct mtd_info *mtd = dev_get_drvdata(dev);
+
+	nand_release(mtd);
+	mpc5121_nfc_free(dev, mtd);
+
+	return 0;
+}
+
+static const struct of_device_id mpc5121_nfc_match[] = {
+	{ .compatible = "fsl,mpc5121-nfc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
+
+static struct platform_driver mpc5121_nfc_driver = {
+	.probe		= mpc5121_nfc_probe,
+	.remove		= mpc5121_nfc_remove,
+	.driver		= {
+		.name = DRV_NAME,
+		.of_match_table = mpc5121_nfc_match,
+	},
+};
+
+module_platform_driver(mpc5121_nfc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c
new file mode 100644
index 000000000000..40d86a861a70
--- /dev/null
+++ b/drivers/mtd/nand/raw/mtk_ecc.c
@@ -0,0 +1,608 @@
+/*
+ * MTK ECC controller driver.
+ * Copyright (C) 2016  MediaTek Inc.
+ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
+ *
+ * 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/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/mutex.h>
+
+#include "mtk_ecc.h"
+
+#define ECC_IDLE_MASK		BIT(0)
+#define ECC_IRQ_EN		BIT(0)
+#define ECC_PG_IRQ_SEL		BIT(1)
+#define ECC_OP_ENABLE		(1)
+#define ECC_OP_DISABLE		(0)
+
+#define ECC_ENCCON		(0x00)
+#define ECC_ENCCNFG		(0x04)
+#define		ECC_MS_SHIFT		(16)
+#define ECC_ENCDIADDR		(0x08)
+#define ECC_ENCIDLE		(0x0C)
+#define ECC_DECCON		(0x100)
+#define ECC_DECCNFG		(0x104)
+#define		DEC_EMPTY_EN		BIT(31)
+#define		DEC_CNFG_CORRECT	(0x3 << 12)
+#define ECC_DECIDLE		(0x10C)
+#define ECC_DECENUM0		(0x114)
+
+#define ECC_TIMEOUT		(500000)
+
+#define ECC_IDLE_REG(op)	((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
+#define ECC_CTL_REG(op)		((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+
+struct mtk_ecc_caps {
+	u32 err_mask;
+	const u8 *ecc_strength;
+	const u32 *ecc_regs;
+	u8 num_ecc_strength;
+	u8 ecc_mode_shift;
+	u32 parity_bits;
+	int pg_irq_sel;
+};
+
+struct mtk_ecc {
+	struct device *dev;
+	const struct mtk_ecc_caps *caps;
+	void __iomem *regs;
+	struct clk *clk;
+
+	struct completion done;
+	struct mutex lock;
+	u32 sectors;
+
+	u8 *eccdata;
+};
+
+/* ecc strength that each IP supports */
+static const u8 ecc_strength_mt2701[] = {
+	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+	40, 44, 48, 52, 56, 60
+};
+
+static const u8 ecc_strength_mt2712[] = {
+	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+	40, 44, 48, 52, 56, 60, 68, 72, 80
+};
+
+static const u8 ecc_strength_mt7622[] = {
+	4, 6, 8, 10, 12, 14, 16
+};
+
+enum mtk_ecc_regs {
+	ECC_ENCPAR00,
+	ECC_ENCIRQ_EN,
+	ECC_ENCIRQ_STA,
+	ECC_DECDONE,
+	ECC_DECIRQ_EN,
+	ECC_DECIRQ_STA,
+};
+
+static int mt2701_ecc_regs[] = {
+	[ECC_ENCPAR00] =        0x10,
+	[ECC_ENCIRQ_EN] =       0x80,
+	[ECC_ENCIRQ_STA] =      0x84,
+	[ECC_DECDONE] =         0x124,
+	[ECC_DECIRQ_EN] =       0x200,
+	[ECC_DECIRQ_STA] =      0x204,
+};
+
+static int mt2712_ecc_regs[] = {
+	[ECC_ENCPAR00] =        0x300,
+	[ECC_ENCIRQ_EN] =       0x80,
+	[ECC_ENCIRQ_STA] =      0x84,
+	[ECC_DECDONE] =         0x124,
+	[ECC_DECIRQ_EN] =       0x200,
+	[ECC_DECIRQ_STA] =      0x204,
+};
+
+static int mt7622_ecc_regs[] = {
+	[ECC_ENCPAR00] =        0x10,
+	[ECC_ENCIRQ_EN] =       0x30,
+	[ECC_ENCIRQ_STA] =      0x34,
+	[ECC_DECDONE] =         0x11c,
+	[ECC_DECIRQ_EN] =       0x140,
+	[ECC_DECIRQ_STA] =      0x144,
+};
+
+static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+				     enum mtk_ecc_operation op)
+{
+	struct device *dev = ecc->dev;
+	u32 val;
+	int ret;
+
+	ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(op), val,
+					val & ECC_IDLE_MASK,
+					10, ECC_TIMEOUT);
+	if (ret)
+		dev_warn(dev, "%s NOT idle\n",
+			 op == ECC_ENCODE ? "encoder" : "decoder");
+}
+
+static irqreturn_t mtk_ecc_irq(int irq, void *id)
+{
+	struct mtk_ecc *ecc = id;
+	u32 dec, enc;
+
+	dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA])
+		    & ECC_IRQ_EN;
+	if (dec) {
+		dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
+		if (dec & ecc->sectors) {
+			/*
+			 * Clear decode IRQ status once again to ensure that
+			 * there will be no extra IRQ.
+			 */
+			readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA]);
+			ecc->sectors = 0;
+			complete(&ecc->done);
+		} else {
+			return IRQ_HANDLED;
+		}
+	} else {
+		enc = readl(ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_STA])
+		      & ECC_IRQ_EN;
+		if (enc)
+			complete(&ecc->done);
+		else
+			return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+{
+	u32 ecc_bit, dec_sz, enc_sz;
+	u32 reg, i;
+
+	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
+		if (ecc->caps->ecc_strength[i] == config->strength)
+			break;
+	}
+
+	if (i == ecc->caps->num_ecc_strength) {
+		dev_err(ecc->dev, "invalid ecc strength %d\n",
+			config->strength);
+		return -EINVAL;
+	}
+
+	ecc_bit = i;
+
+	if (config->op == ECC_ENCODE) {
+		/* configure ECC encoder (in bits) */
+		enc_sz = config->len << 3;
+
+		reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
+		reg |= (enc_sz << ECC_MS_SHIFT);
+		writel(reg, ecc->regs + ECC_ENCCNFG);
+
+		if (config->mode != ECC_NFI_MODE)
+			writel(lower_32_bits(config->addr),
+			       ecc->regs + ECC_ENCDIADDR);
+
+	} else {
+		/* configure ECC decoder (in bits) */
+		dec_sz = (config->len << 3) +
+			 config->strength * ecc->caps->parity_bits;
+
+		reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
+		reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
+		reg |= DEC_EMPTY_EN;
+		writel(reg, ecc->regs + ECC_DECCNFG);
+
+		if (config->sectors)
+			ecc->sectors = 1 << (config->sectors - 1);
+	}
+
+	return 0;
+}
+
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+		       int sectors)
+{
+	u32 offset, i, err;
+	u32 bitflips = 0;
+
+	stats->corrected = 0;
+	stats->failed = 0;
+
+	for (i = 0; i < sectors; i++) {
+		offset = (i >> 2) << 2;
+		err = readl(ecc->regs + ECC_DECENUM0 + offset);
+		err = err >> ((i % 4) * 8);
+		err &= ecc->caps->err_mask;
+		if (err == ecc->caps->err_mask) {
+			/* uncorrectable errors */
+			stats->failed++;
+			continue;
+		}
+
+		stats->corrected += err;
+		bitflips = max_t(u32, bitflips, err);
+	}
+
+	stats->bitflips = bitflips;
+}
+EXPORT_SYMBOL(mtk_ecc_get_stats);
+
+void mtk_ecc_release(struct mtk_ecc *ecc)
+{
+	clk_disable_unprepare(ecc->clk);
+	put_device(ecc->dev);
+}
+EXPORT_SYMBOL(mtk_ecc_release);
+
+static void mtk_ecc_hw_init(struct mtk_ecc *ecc)
+{
+	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+	writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
+
+	mtk_ecc_wait_idle(ecc, ECC_DECODE);
+	writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
+}
+
+static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct mtk_ecc *ecc;
+
+	pdev = of_find_device_by_node(np);
+	if (!pdev || !platform_get_drvdata(pdev))
+		return ERR_PTR(-EPROBE_DEFER);
+
+	get_device(&pdev->dev);
+	ecc = platform_get_drvdata(pdev);
+	clk_prepare_enable(ecc->clk);
+	mtk_ecc_hw_init(ecc);
+
+	return ecc;
+}
+
+struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
+{
+	struct mtk_ecc *ecc = NULL;
+	struct device_node *np;
+
+	np = of_parse_phandle(of_node, "ecc-engine", 0);
+	if (np) {
+		ecc = mtk_ecc_get(np);
+		of_node_put(np);
+	}
+
+	return ecc;
+}
+EXPORT_SYMBOL(of_mtk_ecc_get);
+
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+{
+	enum mtk_ecc_operation op = config->op;
+	u16 reg_val;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ecc->lock);
+	if (ret) {
+		dev_err(ecc->dev, "interrupted when attempting to lock\n");
+		return ret;
+	}
+
+	mtk_ecc_wait_idle(ecc, op);
+
+	ret = mtk_ecc_config(ecc, config);
+	if (ret) {
+		mutex_unlock(&ecc->lock);
+		return ret;
+	}
+
+	if (config->mode != ECC_NFI_MODE || op != ECC_ENCODE) {
+		init_completion(&ecc->done);
+		reg_val = ECC_IRQ_EN;
+		/*
+		 * For ECC_NFI_MODE, if ecc->caps->pg_irq_sel is 1, then it
+		 * means this chip can only generate one ecc irq during page
+		 * read / write. If is 0, generate one ecc irq each ecc step.
+		 */
+		if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
+			reg_val |= ECC_PG_IRQ_SEL;
+		if (op == ECC_ENCODE)
+			writew(reg_val, ecc->regs +
+			       ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
+		else
+			writew(reg_val, ecc->regs +
+			       ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
+	}
+
+	writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+
+	return 0;
+}
+EXPORT_SYMBOL(mtk_ecc_enable);
+
+void mtk_ecc_disable(struct mtk_ecc *ecc)
+{
+	enum mtk_ecc_operation op = ECC_ENCODE;
+
+	/* find out the running operation */
+	if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
+		op = ECC_DECODE;
+
+	/* disable it */
+	mtk_ecc_wait_idle(ecc, op);
+	if (op == ECC_DECODE) {
+		/*
+		 * Clear decode IRQ status in case there is a timeout to wait
+		 * decode IRQ.
+		 */
+		readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
+		writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
+	} else {
+		writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
+	}
+
+	writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+
+	mutex_unlock(&ecc->lock);
+}
+EXPORT_SYMBOL(mtk_ecc_disable);
+
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op)
+{
+	int ret;
+
+	ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
+	if (!ret) {
+		dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
+			(op == ECC_ENCODE) ? "encoder" : "decoder");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(mtk_ecc_wait_done);
+
+int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+		   u8 *data, u32 bytes)
+{
+	dma_addr_t addr;
+	u32 len;
+	int ret;
+
+	addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
+	ret = dma_mapping_error(ecc->dev, addr);
+	if (ret) {
+		dev_err(ecc->dev, "dma mapping error\n");
+		return -EINVAL;
+	}
+
+	config->op = ECC_ENCODE;
+	config->addr = addr;
+	ret = mtk_ecc_enable(ecc, config);
+	if (ret) {
+		dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
+		return ret;
+	}
+
+	ret = mtk_ecc_wait_done(ecc, ECC_ENCODE);
+	if (ret)
+		goto timeout;
+
+	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+
+	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+	len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
+
+	/* write the parity bytes generated by the ECC back to temp buffer */
+	__ioread32_copy(ecc->eccdata,
+			ecc->regs + ecc->caps->ecc_regs[ECC_ENCPAR00],
+			round_up(len, 4));
+
+	/* copy into possibly unaligned OOB region with actual length */
+	memcpy(data + bytes, ecc->eccdata, len);
+timeout:
+
+	dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
+	mtk_ecc_disable(ecc);
+
+	return ret;
+}
+EXPORT_SYMBOL(mtk_ecc_encode);
+
+void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
+{
+	const u8 *ecc_strength = ecc->caps->ecc_strength;
+	int i;
+
+	for (i = 0; i < ecc->caps->num_ecc_strength; i++) {
+		if (*p <= ecc_strength[i]) {
+			if (!i)
+				*p = ecc_strength[i];
+			else if (*p != ecc_strength[i])
+				*p = ecc_strength[i - 1];
+			return;
+		}
+	}
+
+	*p = ecc_strength[ecc->caps->num_ecc_strength - 1];
+}
+EXPORT_SYMBOL(mtk_ecc_adjust_strength);
+
+unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
+{
+	return ecc->caps->parity_bits;
+}
+EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
+
+static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
+	.err_mask = 0x3f,
+	.ecc_strength = ecc_strength_mt2701,
+	.ecc_regs = mt2701_ecc_regs,
+	.num_ecc_strength = 20,
+	.ecc_mode_shift = 5,
+	.parity_bits = 14,
+	.pg_irq_sel = 0,
+};
+
+static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
+	.err_mask = 0x7f,
+	.ecc_strength = ecc_strength_mt2712,
+	.ecc_regs = mt2712_ecc_regs,
+	.num_ecc_strength = 23,
+	.ecc_mode_shift = 5,
+	.parity_bits = 14,
+	.pg_irq_sel = 1,
+};
+
+static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
+	.err_mask = 0x3f,
+	.ecc_strength = ecc_strength_mt7622,
+	.ecc_regs = mt7622_ecc_regs,
+	.num_ecc_strength = 7,
+	.ecc_mode_shift = 4,
+	.parity_bits = 13,
+	.pg_irq_sel = 0,
+};
+
+static const struct of_device_id mtk_ecc_dt_match[] = {
+	{
+		.compatible = "mediatek,mt2701-ecc",
+		.data = &mtk_ecc_caps_mt2701,
+	}, {
+		.compatible = "mediatek,mt2712-ecc",
+		.data = &mtk_ecc_caps_mt2712,
+	}, {
+		.compatible = "mediatek,mt7622-ecc",
+		.data = &mtk_ecc_caps_mt7622,
+	},
+	{},
+};
+
+static int mtk_ecc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_ecc *ecc;
+	struct resource *res;
+	const struct of_device_id *of_ecc_id = NULL;
+	u32 max_eccdata_size;
+	int irq, ret;
+
+	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
+	if (!ecc)
+		return -ENOMEM;
+
+	of_ecc_id = of_match_device(mtk_ecc_dt_match, &pdev->dev);
+	if (!of_ecc_id)
+		return -ENODEV;
+
+	ecc->caps = of_ecc_id->data;
+
+	max_eccdata_size = ecc->caps->num_ecc_strength - 1;
+	max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
+	max_eccdata_size = (max_eccdata_size * ecc->caps->parity_bits + 7) >> 3;
+	max_eccdata_size = round_up(max_eccdata_size, 4);
+	ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
+	if (!ecc->eccdata)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ecc->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ecc->regs)) {
+		dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
+		return PTR_ERR(ecc->regs);
+	}
+
+	ecc->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(ecc->clk)) {
+		dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
+		return PTR_ERR(ecc->clk);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "failed to get irq: %d\n", irq);
+		return irq;
+	}
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(dev, "failed to set DMA mask\n");
+		return ret;
+	}
+
+	ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
+	if (ret) {
+		dev_err(dev, "failed to request irq\n");
+		return -EINVAL;
+	}
+
+	ecc->dev = dev;
+	mutex_init(&ecc->lock);
+	platform_set_drvdata(pdev, ecc);
+	dev_info(dev, "probed\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_ecc_suspend(struct device *dev)
+{
+	struct mtk_ecc *ecc = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(ecc->clk);
+
+	return 0;
+}
+
+static int mtk_ecc_resume(struct device *dev)
+{
+	struct mtk_ecc *ecc = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(ecc->clk);
+	if (ret) {
+		dev_err(dev, "failed to enable clk\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
+#endif
+
+MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
+
+static struct platform_driver mtk_ecc_driver = {
+	.probe  = mtk_ecc_probe,
+	.driver = {
+		.name  = "mtk-ecc",
+		.of_match_table = of_match_ptr(mtk_ecc_dt_match),
+#ifdef CONFIG_PM_SLEEP
+		.pm = &mtk_ecc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(mtk_ecc_driver);
+
+MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
+MODULE_DESCRIPTION("MTK Nand ECC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/raw/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h
new file mode 100644
index 000000000000..a455df080952
--- /dev/null
+++ b/drivers/mtd/nand/raw/mtk_ecc.h
@@ -0,0 +1,49 @@
+/*
+ * MTK SDG1 ECC controller
+ *
+ * Copyright (c) 2016 Mediatek
+ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
+ * 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 __DRIVERS_MTD_NAND_MTK_ECC_H__
+#define __DRIVERS_MTD_NAND_MTK_ECC_H__
+
+#include <linux/types.h>
+
+enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
+enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
+
+struct device_node;
+struct mtk_ecc;
+
+struct mtk_ecc_stats {
+	u32 corrected;
+	u32 bitflips;
+	u32 failed;
+};
+
+struct mtk_ecc_config {
+	enum mtk_ecc_operation op;
+	enum mtk_ecc_mode mode;
+	dma_addr_t addr;
+	u32 strength;
+	u32 sectors;
+	u32 len;
+};
+
+int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
+void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
+int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
+int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
+void mtk_ecc_disable(struct mtk_ecc *);
+void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
+unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
+
+struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
+void mtk_ecc_release(struct mtk_ecc *);
+
+#endif
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
new file mode 100644
index 000000000000..6977da3a26aa
--- /dev/null
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -0,0 +1,1599 @@
+/*
+ * MTK NAND Flash controller driver.
+ * Copyright (C) 2016 MediaTek Inc.
+ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
+ *
+ * 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/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include "mtk_ecc.h"
+
+/* NAND controller register definition */
+#define NFI_CNFG		(0x00)
+#define		CNFG_AHB		BIT(0)
+#define		CNFG_READ_EN		BIT(1)
+#define		CNFG_DMA_BURST_EN	BIT(2)
+#define		CNFG_BYTE_RW		BIT(6)
+#define		CNFG_HW_ECC_EN		BIT(8)
+#define		CNFG_AUTO_FMT_EN	BIT(9)
+#define		CNFG_OP_CUST		(6 << 12)
+#define NFI_PAGEFMT		(0x04)
+#define		PAGEFMT_FDM_ECC_SHIFT	(12)
+#define		PAGEFMT_FDM_SHIFT	(8)
+#define		PAGEFMT_SEC_SEL_512	BIT(2)
+#define		PAGEFMT_512_2K		(0)
+#define		PAGEFMT_2K_4K		(1)
+#define		PAGEFMT_4K_8K		(2)
+#define		PAGEFMT_8K_16K		(3)
+/* NFI control */
+#define NFI_CON			(0x08)
+#define		CON_FIFO_FLUSH		BIT(0)
+#define		CON_NFI_RST		BIT(1)
+#define		CON_BRD			BIT(8)  /* burst  read */
+#define		CON_BWR			BIT(9)	/* burst  write */
+#define		CON_SEC_SHIFT		(12)
+/* Timming control register */
+#define NFI_ACCCON		(0x0C)
+#define NFI_INTR_EN		(0x10)
+#define		INTR_AHB_DONE_EN	BIT(6)
+#define NFI_INTR_STA		(0x14)
+#define NFI_CMD			(0x20)
+#define NFI_ADDRNOB		(0x30)
+#define NFI_COLADDR		(0x34)
+#define NFI_ROWADDR		(0x38)
+#define NFI_STRDATA		(0x40)
+#define		STAR_EN			(1)
+#define		STAR_DE			(0)
+#define NFI_CNRNB		(0x44)
+#define NFI_DATAW		(0x50)
+#define NFI_DATAR		(0x54)
+#define NFI_PIO_DIRDY		(0x58)
+#define		PIO_DI_RDY		(0x01)
+#define NFI_STA			(0x60)
+#define		STA_CMD			BIT(0)
+#define		STA_ADDR		BIT(1)
+#define		STA_BUSY		BIT(8)
+#define		STA_EMP_PAGE		BIT(12)
+#define		NFI_FSM_CUSTDATA	(0xe << 16)
+#define		NFI_FSM_MASK		(0xf << 16)
+#define NFI_ADDRCNTR		(0x70)
+#define		CNTR_MASK		GENMASK(16, 12)
+#define		ADDRCNTR_SEC_SHIFT	(12)
+#define		ADDRCNTR_SEC(val) \
+		(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
+#define NFI_STRADDR		(0x80)
+#define NFI_BYTELEN		(0x84)
+#define NFI_CSEL		(0x90)
+#define NFI_FDML(x)		(0xA0 + (x) * sizeof(u32) * 2)
+#define NFI_FDMM(x)		(0xA4 + (x) * sizeof(u32) * 2)
+#define NFI_FDM_MAX_SIZE	(8)
+#define NFI_FDM_MIN_SIZE	(1)
+#define NFI_MASTER_STA		(0x224)
+#define		MASTER_STA_MASK		(0x0FFF)
+#define NFI_EMPTY_THRESH	(0x23C)
+
+#define MTK_NAME		"mtk-nand"
+#define KB(x)			((x) * 1024UL)
+#define MB(x)			(KB(x) * 1024UL)
+
+#define MTK_TIMEOUT		(500000)
+#define MTK_RESET_TIMEOUT	(1000000)
+#define MTK_NAND_MAX_NSELS	(2)
+#define MTK_NFC_MIN_SPARE	(16)
+#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
+	((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
+	(tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
+
+struct mtk_nfc_caps {
+	const u8 *spare_size;
+	u8 num_spare_size;
+	u8 pageformat_spare_shift;
+	u8 nfi_clk_div;
+	u8 max_sector;
+	u32 max_sector_size;
+};
+
+struct mtk_nfc_bad_mark_ctl {
+	void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
+	u32 sec;
+	u32 pos;
+};
+
+/*
+ * FDM: region used to store free OOB data
+ */
+struct mtk_nfc_fdm {
+	u32 reg_size;
+	u32 ecc_size;
+};
+
+struct mtk_nfc_nand_chip {
+	struct list_head node;
+	struct nand_chip nand;
+
+	struct mtk_nfc_bad_mark_ctl bad_mark;
+	struct mtk_nfc_fdm fdm;
+	u32 spare_per_sector;
+
+	int nsels;
+	u8 sels[0];
+	/* nothing after this field */
+};
+
+struct mtk_nfc_clk {
+	struct clk *nfi_clk;
+	struct clk *pad_clk;
+};
+
+struct mtk_nfc {
+	struct nand_hw_control controller;
+	struct mtk_ecc_config ecc_cfg;
+	struct mtk_nfc_clk clk;
+	struct mtk_ecc *ecc;
+
+	struct device *dev;
+	const struct mtk_nfc_caps *caps;
+	void __iomem *regs;
+
+	struct completion done;
+	struct list_head chips;
+
+	u8 *buffer;
+};
+
+/*
+ * supported spare size of each IP.
+ * order should be the same with the spare size bitfiled defination of
+ * register NFI_PAGEFMT.
+ */
+static const u8 spare_size_mt2701[] = {
+	16, 26, 27, 28, 32, 36, 40, 44,	48, 49, 50, 51, 52, 62, 63, 64
+};
+
+static const u8 spare_size_mt2712[] = {
+	16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64, 67,
+	74
+};
+
+static const u8 spare_size_mt7622[] = {
+	16, 26, 27, 28
+};
+
+static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
+{
+	return container_of(nand, struct mtk_nfc_nand_chip, nand);
+}
+
+static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i)
+{
+	return (u8 *)p + i * chip->ecc.size;
+}
+
+static inline u8 *oob_ptr(struct nand_chip *chip, int i)
+{
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	u8 *poi;
+
+	/* map the sector's FDM data to free oob:
+	 * the beginning of the oob area stores the FDM data of bad mark sectors
+	 */
+
+	if (i < mtk_nand->bad_mark.sec)
+		poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
+	else if (i == mtk_nand->bad_mark.sec)
+		poi = chip->oob_poi;
+	else
+		poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
+
+	return poi;
+}
+
+static inline int mtk_data_len(struct nand_chip *chip)
+{
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+
+	return chip->ecc.size + mtk_nand->spare_per_sector;
+}
+
+static inline u8 *mtk_data_ptr(struct nand_chip *chip,  int i)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+	return nfc->buffer + i * mtk_data_len(chip);
+}
+
+static inline u8 *mtk_oob_ptr(struct nand_chip *chip, int i)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+	return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
+}
+
+static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
+{
+	writel(val, nfc->regs + reg);
+}
+
+static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
+{
+	writew(val, nfc->regs + reg);
+}
+
+static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
+{
+	writeb(val, nfc->regs + reg);
+}
+
+static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
+{
+	return readl_relaxed(nfc->regs + reg);
+}
+
+static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
+{
+	return readw_relaxed(nfc->regs + reg);
+}
+
+static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
+{
+	return readb_relaxed(nfc->regs + reg);
+}
+
+static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
+{
+	struct device *dev = nfc->dev;
+	u32 val;
+	int ret;
+
+	/* reset all registers and force the NFI master to terminate */
+	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+
+	/* wait for the master to finish the last transaction */
+	ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
+				 !(val & MASTER_STA_MASK), 50,
+				 MTK_RESET_TIMEOUT);
+	if (ret)
+		dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
+			 NFI_MASTER_STA, val);
+
+	/* ensure any status register affected by the NFI master is reset */
+	nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+	nfi_writew(nfc, STAR_DE, NFI_STRDATA);
+}
+
+static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
+{
+	struct device *dev = nfc->dev;
+	u32 val;
+	int ret;
+
+	nfi_writel(nfc, command, NFI_CMD);
+
+	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
+					!(val & STA_CMD), 10,  MTK_TIMEOUT);
+	if (ret) {
+		dev_warn(dev, "nfi core timed out entering command mode\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
+{
+	struct device *dev = nfc->dev;
+	u32 val;
+	int ret;
+
+	nfi_writel(nfc, addr, NFI_COLADDR);
+	nfi_writel(nfc, 0, NFI_ROWADDR);
+	nfi_writew(nfc, 1, NFI_ADDRNOB);
+
+	ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
+					!(val & STA_ADDR), 10, MTK_TIMEOUT);
+	if (ret) {
+		dev_warn(dev, "nfi core timed out entering address mode\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	u32 fmt, spare, i;
+
+	if (!mtd->writesize)
+		return 0;
+
+	spare = mtk_nand->spare_per_sector;
+
+	switch (mtd->writesize) {
+	case 512:
+		fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
+		break;
+	case KB(2):
+		if (chip->ecc.size == 512)
+			fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
+		else
+			fmt = PAGEFMT_512_2K;
+		break;
+	case KB(4):
+		if (chip->ecc.size == 512)
+			fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
+		else
+			fmt = PAGEFMT_2K_4K;
+		break;
+	case KB(8):
+		if (chip->ecc.size == 512)
+			fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
+		else
+			fmt = PAGEFMT_4K_8K;
+		break;
+	case KB(16):
+		fmt = PAGEFMT_8K_16K;
+		break;
+	default:
+		dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
+		return -EINVAL;
+	}
+
+	/*
+	 * the hardware will double the value for this eccsize, so we need to
+	 * halve it
+	 */
+	if (chip->ecc.size == 1024)
+		spare >>= 1;
+
+	for (i = 0; i < nfc->caps->num_spare_size; i++) {
+		if (nfc->caps->spare_size[i] == spare)
+			break;
+	}
+
+	if (i == nfc->caps->num_spare_size) {
+		dev_err(nfc->dev, "invalid spare size %d\n", spare);
+		return -EINVAL;
+	}
+
+	fmt |= i << nfc->caps->pageformat_spare_shift;
+
+	fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
+	fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
+	nfi_writel(nfc, fmt, NFI_PAGEFMT);
+
+	nfc->ecc_cfg.strength = chip->ecc.strength;
+	nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
+
+	return 0;
+}
+
+static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
+
+	if (chip < 0)
+		return;
+
+	mtk_nfc_hw_runtime_config(mtd);
+
+	nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
+}
+
+static int mtk_nfc_dev_ready(struct mtd_info *mtd)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+
+	if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
+		return 0;
+
+	return 1;
+}
+
+static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+
+	if (ctrl & NAND_ALE) {
+		mtk_nfc_send_address(nfc, dat);
+	} else if (ctrl & NAND_CLE) {
+		mtk_nfc_hw_reset(nfc);
+
+		nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
+		mtk_nfc_send_command(nfc, dat);
+	}
+}
+
+static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
+{
+	int rc;
+	u8 val;
+
+	rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
+				       val & PIO_DI_RDY, 10, MTK_TIMEOUT);
+	if (rc < 0)
+		dev_err(nfc->dev, "data not ready\n");
+}
+
+static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	u32 reg;
+
+	/* after each byte read, the NFI_STA reg is reset by the hardware */
+	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+	if (reg != NFI_FSM_CUSTDATA) {
+		reg = nfi_readw(nfc, NFI_CNFG);
+		reg |= CNFG_BYTE_RW | CNFG_READ_EN;
+		nfi_writew(nfc, reg, NFI_CNFG);
+
+		/*
+		 * set to max sector to allow the HW to continue reading over
+		 * unaligned accesses
+		 */
+		reg = (nfc->caps->max_sector << CON_SEC_SHIFT) | CON_BRD;
+		nfi_writel(nfc, reg, NFI_CON);
+
+		/* trigger to fetch data */
+		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+	}
+
+	mtk_nfc_wait_ioready(nfc);
+
+	return nfi_readb(nfc, NFI_DATAR);
+}
+
+static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		buf[i] = mtk_nfc_read_byte(mtd);
+}
+
+static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+	u32 reg;
+
+	reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+
+	if (reg != NFI_FSM_CUSTDATA) {
+		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+		nfi_writew(nfc, reg, NFI_CNFG);
+
+		reg = nfc->caps->max_sector << CON_SEC_SHIFT | CON_BWR;
+		nfi_writel(nfc, reg, NFI_CON);
+
+		nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+	}
+
+	mtk_nfc_wait_ioready(nfc);
+	nfi_writeb(nfc, byte, NFI_DATAW);
+}
+
+static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		mtk_nfc_write_byte(mtd, buf[i]);
+}
+
+static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+					const struct nand_data_interface *conf)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+	const struct nand_sdr_timings *timings;
+	u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return -ENOTSUPP;
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	rate = clk_get_rate(nfc->clk.nfi_clk);
+	/* There is a frequency divider in some IPs */
+	rate /= nfc->caps->nfi_clk_div;
+
+	/* turn clock rate into KHZ */
+	rate /= 1000;
+
+	tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
+	tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
+	tpoecs &= 0xf;
+
+	tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
+	tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
+	tprecs &= 0x3f;
+
+	/* sdr interface has no tCR which means CE# low to RE# low */
+	tc2r = 0;
+
+	tw2r = timings->tWHR_min / 1000;
+	tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
+	tw2r = DIV_ROUND_UP(tw2r - 1, 2);
+	tw2r &= 0xf;
+
+	twh = max(timings->tREH_min, timings->tWH_min) / 1000;
+	twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
+	twh &= 0xf;
+
+	twst = timings->tWP_min / 1000;
+	twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
+	twst &= 0xf;
+
+	trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
+	trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
+	trlt &= 0xf;
+
+	/*
+	 * ACCON: access timing control register
+	 * -------------------------------------
+	 * 31:28: tpoecs, minimum required time for CS post pulling down after
+	 *        accessing the device
+	 * 27:22: tprecs, minimum required time for CS pre pulling down before
+	 *        accessing the device
+	 * 21:16: tc2r, minimum required time from NCEB low to NREB low
+	 * 15:12: tw2r, minimum required time from NWEB high to NREB low.
+	 * 11:08: twh, write enable hold time
+	 * 07:04: twst, write wait states
+	 * 03:00: trlt, read wait states
+	 */
+	trlt = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
+	nfi_writel(nfc, trlt, NFI_ACCCON);
+
+	return 0;
+}
+
+static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	int size = chip->ecc.size + mtk_nand->fdm.reg_size;
+
+	nfc->ecc_cfg.mode = ECC_DMA_MODE;
+	nfc->ecc_cfg.op = ECC_ENCODE;
+
+	return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size);
+}
+
+static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, u8 *b, int c)
+{
+	/* nop */
+}
+
+static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+	u32 bad_pos = nand->bad_mark.pos;
+
+	if (raw)
+		bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+	else
+		bad_pos += nand->bad_mark.sec * chip->ecc.size;
+
+	swap(chip->oob_poi[0], buf[bad_pos]);
+}
+
+static int mtk_nfc_format_subpage(struct mtd_info *mtd, u32 offset,
+				  u32 len, const u8 *buf)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+	u32 start, end;
+	int i, ret;
+
+	start = offset / chip->ecc.size;
+	end = DIV_ROUND_UP(offset + len, chip->ecc.size);
+
+	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+	for (i = 0; i < chip->ecc.steps; i++) {
+		memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+		       chip->ecc.size);
+
+		if (start > i || i >= end)
+			continue;
+
+		if (i == mtk_nand->bad_mark.sec)
+			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+
+		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+
+		/* program the CRC back to the OOB */
+		ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void mtk_nfc_format_page(struct mtd_info *mtd, const u8 *buf)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+	u32 i;
+
+	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+	for (i = 0; i < chip->ecc.steps; i++) {
+		if (buf)
+			memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+			       chip->ecc.size);
+
+		if (i == mtk_nand->bad_mark.sec)
+			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+
+		memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+	}
+}
+
+static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
+				    u32 sectors)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+	u32 vall, valm;
+	u8 *oobptr;
+	int i, j;
+
+	for (i = 0; i < sectors; i++) {
+		oobptr = oob_ptr(chip, start + i);
+		vall = nfi_readl(nfc, NFI_FDML(i));
+		valm = nfi_readl(nfc, NFI_FDMM(i));
+
+		for (j = 0; j < fdm->reg_size; j++)
+			oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+	}
+}
+
+static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+	u32 vall, valm;
+	u8 *oobptr;
+	int i, j;
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		oobptr = oob_ptr(chip, i);
+		vall = 0;
+		valm = 0;
+		for (j = 0; j < 8; j++) {
+			if (j < 4)
+				vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+						<< (j * 8);
+			else
+				valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+						<< ((j - 4) * 8);
+		}
+		nfi_writel(nfc, vall, NFI_FDML(i));
+		nfi_writel(nfc, valm, NFI_FDMM(i));
+	}
+}
+
+static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+				 const u8 *buf, int page, int len)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct device *dev = nfc->dev;
+	dma_addr_t addr;
+	u32 reg;
+	int ret;
+
+	addr = dma_map_single(dev, (void *)buf, len, DMA_TO_DEVICE);
+	ret = dma_mapping_error(nfc->dev, addr);
+	if (ret) {
+		dev_err(nfc->dev, "dma mapping error\n");
+		return -EINVAL;
+	}
+
+	reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
+	nfi_writew(nfc, reg, NFI_CNFG);
+
+	nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
+	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
+	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+
+	init_completion(&nfc->done);
+
+	reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
+	nfi_writel(nfc, reg, NFI_CON);
+	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+	ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
+	if (!ret) {
+		dev_err(dev, "program ahb done timeout\n");
+		nfi_writew(nfc, 0, NFI_INTR_EN);
+		ret = -ETIMEDOUT;
+		goto timeout;
+	}
+
+	ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
+					ADDRCNTR_SEC(reg) >= chip->ecc.steps,
+					10, MTK_TIMEOUT);
+	if (ret)
+		dev_err(dev, "hwecc write timeout\n");
+
+timeout:
+
+	dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
+	nfi_writel(nfc, 0, NFI_CON);
+
+	return ret;
+}
+
+static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			      const u8 *buf, int page, int raw)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	size_t len;
+	const u8 *bufpoi;
+	u32 reg;
+	int ret;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	if (!raw) {
+		/* OOB => FDM: from register,  ECC: from HW */
+		reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
+		nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
+
+		nfc->ecc_cfg.op = ECC_ENCODE;
+		nfc->ecc_cfg.mode = ECC_NFI_MODE;
+		ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
+		if (ret) {
+			/* clear NFI config */
+			reg = nfi_readw(nfc, NFI_CNFG);
+			reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+			nfi_writew(nfc, reg, NFI_CNFG);
+
+			return ret;
+		}
+
+		memcpy(nfc->buffer, buf, mtd->writesize);
+		mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
+		bufpoi = nfc->buffer;
+
+		/* write OOB into the FDM registers (OOB area in MTK NAND) */
+		mtk_nfc_write_fdm(chip);
+	} else {
+		bufpoi = buf;
+	}
+
+	len = mtd->writesize + (raw ? mtd->oobsize : 0);
+	ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
+
+	if (!raw)
+		mtk_ecc_disable(nfc->ecc);
+
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
+				    struct nand_chip *chip, const u8 *buf,
+				    int oob_on, int page)
+{
+	return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+}
+
+static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				  const u8 *buf, int oob_on, int pg)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+	mtk_nfc_format_page(mtd, buf);
+	return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
+}
+
+static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
+				       struct nand_chip *chip, u32 offset,
+				       u32 data_len, const u8 *buf,
+				       int oob_on, int page)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	int ret;
+
+	ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
+	if (ret < 0)
+		return ret;
+
+	/* use the data in the private buffer (now with FDM and CRC) */
+	return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
+}
+
+static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+				 int page)
+{
+	return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+}
+
+static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_ecc_stats stats;
+	int rc, i;
+
+	rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+	if (rc) {
+		memset(buf, 0xff, sectors * chip->ecc.size);
+		for (i = 0; i < sectors; i++)
+			memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+		return 0;
+	}
+
+	mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
+	mtd->ecc_stats.corrected += stats.corrected;
+	mtd->ecc_stats.failed += stats.failed;
+
+	return stats.bitflips;
+}
+
+static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+				u32 data_offs, u32 readlen,
+				u8 *bufpoi, int page, int raw)
+{
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	u32 spare = mtk_nand->spare_per_sector;
+	u32 column, sectors, start, end, reg;
+	dma_addr_t addr;
+	int bitflips;
+	size_t len;
+	u8 *buf;
+	int rc;
+
+	start = data_offs / chip->ecc.size;
+	end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
+
+	sectors = end - start;
+	column = start * (chip->ecc.size + spare);
+
+	len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
+	buf = bufpoi + start * chip->ecc.size;
+
+	nand_read_page_op(chip, page, column, NULL, 0);
+
+	addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
+	rc = dma_mapping_error(nfc->dev, addr);
+	if (rc) {
+		dev_err(nfc->dev, "dma mapping error\n");
+
+		return -EINVAL;
+	}
+
+	reg = nfi_readw(nfc, NFI_CNFG);
+	reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
+	if (!raw) {
+		reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
+		nfi_writew(nfc, reg, NFI_CNFG);
+
+		nfc->ecc_cfg.mode = ECC_NFI_MODE;
+		nfc->ecc_cfg.sectors = sectors;
+		nfc->ecc_cfg.op = ECC_DECODE;
+		rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
+		if (rc) {
+			dev_err(nfc->dev, "ecc enable\n");
+			/* clear NFI_CNFG */
+			reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
+				CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+			nfi_writew(nfc, reg, NFI_CNFG);
+			dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
+
+			return rc;
+		}
+	} else {
+		nfi_writew(nfc, reg, NFI_CNFG);
+	}
+
+	nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
+	nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+	nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
+
+	init_completion(&nfc->done);
+	reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
+	nfi_writel(nfc, reg, NFI_CON);
+	nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+	rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
+	if (!rc)
+		dev_warn(nfc->dev, "read ahb/dma done timeout\n");
+
+	rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
+				       ADDRCNTR_SEC(reg) >= sectors, 10,
+				       MTK_TIMEOUT);
+	if (rc < 0) {
+		dev_err(nfc->dev, "subpage done timeout\n");
+		bitflips = -EIO;
+	} else {
+		bitflips = 0;
+		if (!raw) {
+			rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
+			bitflips = rc < 0 ? -ETIMEDOUT :
+				mtk_nfc_update_ecc_stats(mtd, buf, sectors);
+			mtk_nfc_read_fdm(chip, start, sectors);
+		}
+	}
+
+	dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
+
+	if (raw)
+		goto done;
+
+	mtk_ecc_disable(nfc->ecc);
+
+	if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
+		mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
+done:
+	nfi_writel(nfc, 0, NFI_CON);
+
+	return bitflips;
+}
+
+static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
+				      struct nand_chip *chip, u32 off,
+				      u32 len, u8 *p, int pg)
+{
+	return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+}
+
+static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
+				   struct nand_chip *chip, u8 *p,
+				   int oob_on, int pg)
+{
+	return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
+}
+
+static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				 u8 *buf, int oob_on, int page)
+{
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc *nfc = nand_get_controller_data(chip);
+	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+	int i, ret;
+
+	memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+	ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
+				   page, 1);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+		if (i == mtk_nand->bad_mark.sec)
+			mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+
+		if (buf)
+			memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+			       chip->ecc.size);
+	}
+
+	return ret;
+}
+
+static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+				int page)
+{
+	return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+}
+
+static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
+{
+	/*
+	 * CNRNB: nand ready/busy register
+	 * -------------------------------
+	 * 7:4: timeout register for polling the NAND busy/ready signal
+	 * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
+	 */
+	nfi_writew(nfc, 0xf1, NFI_CNRNB);
+	nfi_writel(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+
+	mtk_nfc_hw_reset(nfc);
+
+	nfi_readl(nfc, NFI_INTR_STA);
+	nfi_writel(nfc, 0, NFI_INTR_EN);
+}
+
+static irqreturn_t mtk_nfc_irq(int irq, void *id)
+{
+	struct mtk_nfc *nfc = id;
+	u16 sta, ien;
+
+	sta = nfi_readw(nfc, NFI_INTR_STA);
+	ien = nfi_readw(nfc, NFI_INTR_EN);
+
+	if (!(sta & ien))
+		return IRQ_NONE;
+
+	nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
+	complete(&nfc->done);
+
+	return IRQ_HANDLED;
+}
+
+static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
+{
+	int ret;
+
+	ret = clk_prepare_enable(clk->nfi_clk);
+	if (ret) {
+		dev_err(dev, "failed to enable nfi clk\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clk->pad_clk);
+	if (ret) {
+		dev_err(dev, "failed to enable pad clk\n");
+		clk_disable_unprepare(clk->nfi_clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
+{
+	clk_disable_unprepare(clk->nfi_clk);
+	clk_disable_unprepare(clk->pad_clk);
+}
+
+static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oob_region)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+	u32 eccsteps;
+
+	eccsteps = mtd->writesize / chip->ecc.size;
+
+	if (section >= eccsteps)
+		return -ERANGE;
+
+	oob_region->length = fdm->reg_size - fdm->ecc_size;
+	oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
+
+	return 0;
+}
+
+static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oob_region)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+	u32 eccsteps;
+
+	if (section)
+		return -ERANGE;
+
+	eccsteps = mtd->writesize / chip->ecc.size;
+	oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
+	oob_region->length = mtd->oobsize - oob_region->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
+	.free = mtk_nfc_ooblayout_free,
+	.ecc = mtk_nfc_ooblayout_ecc,
+};
+
+static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+	u32 ecc_bytes;
+
+	ecc_bytes = DIV_ROUND_UP(nand->ecc.strength *
+				 mtk_ecc_get_parity_bits(nfc->ecc), 8);
+
+	fdm->reg_size = chip->spare_per_sector - ecc_bytes;
+	if (fdm->reg_size > NFI_FDM_MAX_SIZE)
+		fdm->reg_size = NFI_FDM_MAX_SIZE;
+
+	/* bad block mark storage */
+	fdm->ecc_size = 1;
+}
+
+static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
+				     struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+
+	if (mtd->writesize == 512) {
+		bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
+	} else {
+		bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
+		bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
+		bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
+	}
+}
+
+static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+	const u8 *spare = nfc->caps->spare_size;
+	u32 eccsteps, i, closest_spare = 0;
+
+	eccsteps = mtd->writesize / nand->ecc.size;
+	*sps = mtd->oobsize / eccsteps;
+
+	if (nand->ecc.size == 1024)
+		*sps >>= 1;
+
+	if (*sps < MTK_NFC_MIN_SPARE)
+		return -EINVAL;
+
+	for (i = 0; i < nfc->caps->num_spare_size; i++) {
+		if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
+			closest_spare = i;
+			if (*sps == spare[i])
+				break;
+		}
+	}
+
+	*sps = spare[closest_spare];
+
+	if (nand->ecc.size == 1024)
+		*sps <<= 1;
+
+	return 0;
+}
+
+static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct mtk_nfc *nfc = nand_get_controller_data(nand);
+	u32 spare;
+	int free, ret;
+
+	/* support only ecc hw mode */
+	if (nand->ecc.mode != NAND_ECC_HW) {
+		dev_err(dev, "ecc.mode not supported\n");
+		return -EINVAL;
+	}
+
+	/* if optional dt settings not present */
+	if (!nand->ecc.size || !nand->ecc.strength) {
+		/* use datasheet requirements */
+		nand->ecc.strength = nand->ecc_strength_ds;
+		nand->ecc.size = nand->ecc_step_ds;
+
+		/*
+		 * align eccstrength and eccsize
+		 * this controller only supports 512 and 1024 sizes
+		 */
+		if (nand->ecc.size < 1024) {
+			if (mtd->writesize > 512 &&
+			    nfc->caps->max_sector_size > 512) {
+				nand->ecc.size = 1024;
+				nand->ecc.strength <<= 1;
+			} else {
+				nand->ecc.size = 512;
+			}
+		} else {
+			nand->ecc.size = 1024;
+		}
+
+		ret = mtk_nfc_set_spare_per_sector(&spare, mtd);
+		if (ret)
+			return ret;
+
+		/* calculate oob bytes except ecc parity data */
+		free = (nand->ecc.strength * mtk_ecc_get_parity_bits(nfc->ecc)
+			+ 7) >> 3;
+		free = spare - free;
+
+		/*
+		 * enhance ecc strength if oob left is bigger than max FDM size
+		 * or reduce ecc strength if oob size is not enough for ecc
+		 * parity data.
+		 */
+		if (free > NFI_FDM_MAX_SIZE) {
+			spare -= NFI_FDM_MAX_SIZE;
+			nand->ecc.strength = (spare << 3) /
+					     mtk_ecc_get_parity_bits(nfc->ecc);
+		} else if (free < 0) {
+			spare -= NFI_FDM_MIN_SIZE;
+			nand->ecc.strength = (spare << 3) /
+					     mtk_ecc_get_parity_bits(nfc->ecc);
+		}
+	}
+
+	mtk_ecc_adjust_strength(nfc->ecc, &nand->ecc.strength);
+
+	dev_info(dev, "eccsize %d eccstrength %d\n",
+		 nand->ecc.size, nand->ecc.strength);
+
+	return 0;
+}
+
+static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
+				  struct device_node *np)
+{
+	struct mtk_nfc_nand_chip *chip;
+	struct nand_chip *nand;
+	struct mtd_info *mtd;
+	int nsels, len;
+	u32 tmp;
+	int ret;
+	int i;
+
+	if (!of_get_property(np, "reg", &nsels))
+		return -ENODEV;
+
+	nsels /= sizeof(u32);
+	if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
+		dev_err(dev, "invalid reg property size %d\n", nsels);
+		return -EINVAL;
+	}
+
+	chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
+			    GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->nsels = nsels;
+	for (i = 0; i < nsels; i++) {
+		ret = of_property_read_u32_index(np, "reg", i, &tmp);
+		if (ret) {
+			dev_err(dev, "reg property failure : %d\n", ret);
+			return ret;
+		}
+		chip->sels[i] = tmp;
+	}
+
+	nand = &chip->nand;
+	nand->controller = &nfc->controller;
+
+	nand_set_flash_node(nand, np);
+	nand_set_controller_data(nand, nfc);
+
+	nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
+	nand->dev_ready = mtk_nfc_dev_ready;
+	nand->select_chip = mtk_nfc_select_chip;
+	nand->write_byte = mtk_nfc_write_byte;
+	nand->write_buf = mtk_nfc_write_buf;
+	nand->read_byte = mtk_nfc_read_byte;
+	nand->read_buf = mtk_nfc_read_buf;
+	nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+	nand->setup_data_interface = mtk_nfc_setup_data_interface;
+
+	/* set default mode in case dt entry is missing */
+	nand->ecc.mode = NAND_ECC_HW;
+
+	nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
+	nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
+	nand->ecc.write_page = mtk_nfc_write_page_hwecc;
+	nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
+	nand->ecc.write_oob = mtk_nfc_write_oob_std;
+
+	nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
+	nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
+	nand->ecc.read_page = mtk_nfc_read_page_hwecc;
+	nand->ecc.read_oob_raw = mtk_nfc_read_oob_std;
+	nand->ecc.read_oob = mtk_nfc_read_oob_std;
+
+	mtd = nand_to_mtd(nand);
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = dev;
+	mtd->name = MTK_NAME;
+	mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
+
+	mtk_nfc_hw_init(nfc);
+
+	ret = nand_scan_ident(mtd, nsels, NULL);
+	if (ret)
+		return ret;
+
+	/* store bbt magic in page, cause OOB is not protected */
+	if (nand->bbt_options & NAND_BBT_USE_FLASH)
+		nand->bbt_options |= NAND_BBT_NO_OOB;
+
+	ret = mtk_nfc_ecc_init(dev, mtd);
+	if (ret)
+		return -EINVAL;
+
+	if (nand->options & NAND_BUSWIDTH_16) {
+		dev_err(dev, "16bits buswidth not supported");
+		return -EINVAL;
+	}
+
+	ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
+	if (ret)
+		return ret;
+
+	mtk_nfc_set_fdm(&chip->fdm, mtd);
+	mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
+
+	len = mtd->writesize + mtd->oobsize;
+	nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
+	if (!nfc->buffer)
+		return  -ENOMEM;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		return ret;
+
+	ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+	if (ret) {
+		dev_err(dev, "mtd parse partition error\n");
+		nand_release(mtd);
+		return ret;
+	}
+
+	list_add_tail(&chip->node, &nfc->chips);
+
+	return 0;
+}
+
+static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *nand_np;
+	int ret;
+
+	for_each_child_of_node(np, nand_np) {
+		ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
+		if (ret) {
+			of_node_put(nand_np);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
+	.spare_size = spare_size_mt2701,
+	.num_spare_size = 16,
+	.pageformat_spare_shift = 4,
+	.nfi_clk_div = 1,
+	.max_sector = 16,
+	.max_sector_size = 1024,
+};
+
+static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
+	.spare_size = spare_size_mt2712,
+	.num_spare_size = 19,
+	.pageformat_spare_shift = 16,
+	.nfi_clk_div = 2,
+	.max_sector = 16,
+	.max_sector_size = 1024,
+};
+
+static const struct mtk_nfc_caps mtk_nfc_caps_mt7622 = {
+	.spare_size = spare_size_mt7622,
+	.num_spare_size = 4,
+	.pageformat_spare_shift = 4,
+	.nfi_clk_div = 1,
+	.max_sector = 8,
+	.max_sector_size = 512,
+};
+
+static const struct of_device_id mtk_nfc_id_table[] = {
+	{
+		.compatible = "mediatek,mt2701-nfc",
+		.data = &mtk_nfc_caps_mt2701,
+	}, {
+		.compatible = "mediatek,mt2712-nfc",
+		.data = &mtk_nfc_caps_mt2712,
+	}, {
+		.compatible = "mediatek,mt7622-nfc",
+		.data = &mtk_nfc_caps_mt7622,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
+
+static int mtk_nfc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct mtk_nfc *nfc;
+	struct resource *res;
+	const struct of_device_id *of_nfc_id = NULL;
+	int ret, irq;
+
+	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	spin_lock_init(&nfc->controller.lock);
+	init_waitqueue_head(&nfc->controller.wq);
+	INIT_LIST_HEAD(&nfc->chips);
+
+	/* probe defer if not ready */
+	nfc->ecc = of_mtk_ecc_get(np);
+	if (IS_ERR(nfc->ecc))
+		return PTR_ERR(nfc->ecc);
+	else if (!nfc->ecc)
+		return -ENODEV;
+
+	nfc->dev = dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(nfc->regs)) {
+		ret = PTR_ERR(nfc->regs);
+		goto release_ecc;
+	}
+
+	nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
+	if (IS_ERR(nfc->clk.nfi_clk)) {
+		dev_err(dev, "no clk\n");
+		ret = PTR_ERR(nfc->clk.nfi_clk);
+		goto release_ecc;
+	}
+
+	nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
+	if (IS_ERR(nfc->clk.pad_clk)) {
+		dev_err(dev, "no pad clk\n");
+		ret = PTR_ERR(nfc->clk.pad_clk);
+		goto release_ecc;
+	}
+
+	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
+	if (ret)
+		goto release_ecc;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "no nfi irq resource\n");
+		ret = -EINVAL;
+		goto clk_disable;
+	}
+
+	ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
+	if (ret) {
+		dev_err(dev, "failed to request nfi irq\n");
+		goto clk_disable;
+	}
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(dev, "failed to set dma mask\n");
+		goto clk_disable;
+	}
+
+	of_nfc_id = of_match_device(mtk_nfc_id_table, &pdev->dev);
+	if (!of_nfc_id) {
+		ret = -ENODEV;
+		goto clk_disable;
+	}
+
+	nfc->caps = of_nfc_id->data;
+
+	platform_set_drvdata(pdev, nfc);
+
+	ret = mtk_nfc_nand_chips_init(dev, nfc);
+	if (ret) {
+		dev_err(dev, "failed to init nand chips\n");
+		goto clk_disable;
+	}
+
+	return 0;
+
+clk_disable:
+	mtk_nfc_disable_clk(&nfc->clk);
+
+release_ecc:
+	mtk_ecc_release(nfc->ecc);
+
+	return ret;
+}
+
+static int mtk_nfc_remove(struct platform_device *pdev)
+{
+	struct mtk_nfc *nfc = platform_get_drvdata(pdev);
+	struct mtk_nfc_nand_chip *chip;
+
+	while (!list_empty(&nfc->chips)) {
+		chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
+					node);
+		nand_release(nand_to_mtd(&chip->nand));
+		list_del(&chip->node);
+	}
+
+	mtk_ecc_release(nfc->ecc);
+	mtk_nfc_disable_clk(&nfc->clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_nfc_suspend(struct device *dev)
+{
+	struct mtk_nfc *nfc = dev_get_drvdata(dev);
+
+	mtk_nfc_disable_clk(&nfc->clk);
+
+	return 0;
+}
+
+static int mtk_nfc_resume(struct device *dev)
+{
+	struct mtk_nfc *nfc = dev_get_drvdata(dev);
+	struct mtk_nfc_nand_chip *chip;
+	struct nand_chip *nand;
+	int ret;
+	u32 i;
+
+	udelay(200);
+
+	ret = mtk_nfc_enable_clk(dev, &nfc->clk);
+	if (ret)
+		return ret;
+
+	/* reset NAND chip if VCC was powered off */
+	list_for_each_entry(chip, &nfc->chips, node) {
+		nand = &chip->nand;
+		for (i = 0; i < chip->nsels; i++)
+			nand_reset(nand, i);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
+#endif
+
+static struct platform_driver mtk_nfc_driver = {
+	.probe  = mtk_nfc_probe,
+	.remove = mtk_nfc_remove,
+	.driver = {
+		.name  = MTK_NAME,
+		.of_match_table = mtk_nfc_id_table,
+#ifdef CONFIG_PM_SLEEP
+		.pm = &mtk_nfc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(mtk_nfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
+MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
new file mode 100644
index 000000000000..87b5ee66e501
--- /dev/null
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -0,0 +1,1966 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/mach/flash.h>
+#include <linux/platform_data/mtd-mxc_nand.h>
+
+#define DRIVER_NAME "mxc_nand"
+
+/* Addresses for NFC registers */
+#define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
+#define NFC_V1_V2_BUF_ADDR		(host->regs + 0x04)
+#define NFC_V1_V2_FLASH_ADDR		(host->regs + 0x06)
+#define NFC_V1_V2_FLASH_CMD		(host->regs + 0x08)
+#define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
+#define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
+#define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
+#define NFC_V1_V2_RSLTSPARE_AREA	(host->regs + 0x10)
+#define NFC_V1_V2_WRPROT		(host->regs + 0x12)
+#define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
+#define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
+#define NFC_V21_UNLOCKSTART_BLKADDR0	(host->regs + 0x20)
+#define NFC_V21_UNLOCKSTART_BLKADDR1	(host->regs + 0x24)
+#define NFC_V21_UNLOCKSTART_BLKADDR2	(host->regs + 0x28)
+#define NFC_V21_UNLOCKSTART_BLKADDR3	(host->regs + 0x2c)
+#define NFC_V21_UNLOCKEND_BLKADDR0	(host->regs + 0x22)
+#define NFC_V21_UNLOCKEND_BLKADDR1	(host->regs + 0x26)
+#define NFC_V21_UNLOCKEND_BLKADDR2	(host->regs + 0x2a)
+#define NFC_V21_UNLOCKEND_BLKADDR3	(host->regs + 0x2e)
+#define NFC_V1_V2_NF_WRPRST		(host->regs + 0x18)
+#define NFC_V1_V2_CONFIG1		(host->regs + 0x1a)
+#define NFC_V1_V2_CONFIG2		(host->regs + 0x1c)
+
+#define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
+#define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
+#define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
+#define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
+#define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
+#define NFC_V1_V2_CONFIG1_RST		(1 << 6)
+#define NFC_V1_V2_CONFIG1_CE		(1 << 7)
+#define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
+#define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
+#define NFC_V2_CONFIG1_FP_INT		(1 << 11)
+
+#define NFC_V1_V2_CONFIG2_INT		(1 << 15)
+
+/*
+ * Operation modes for the NFC. Valid for v1, v2 and v3
+ * type controllers.
+ */
+#define NFC_CMD				(1 << 0)
+#define NFC_ADDR			(1 << 1)
+#define NFC_INPUT			(1 << 2)
+#define NFC_OUTPUT			(1 << 3)
+#define NFC_ID				(1 << 4)
+#define NFC_STATUS			(1 << 5)
+
+#define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
+#define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
+
+#define NFC_V3_CONFIG1			(host->regs_axi + 0x34)
+#define NFC_V3_CONFIG1_SP_EN		(1 << 0)
+#define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7 ) << 4)
+
+#define NFC_V3_ECC_STATUS_RESULT	(host->regs_axi + 0x38)
+
+#define NFC_V3_LAUNCH			(host->regs_axi + 0x40)
+
+#define NFC_V3_WRPROT			(host->regs_ip + 0x0)
+#define NFC_V3_WRPROT_LOCK_TIGHT	(1 << 0)
+#define NFC_V3_WRPROT_LOCK		(1 << 1)
+#define NFC_V3_WRPROT_UNLOCK		(1 << 2)
+#define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
+
+#define NFC_V3_WRPROT_UNLOCK_BLK_ADD0   (host->regs_ip + 0x04)
+
+#define NFC_V3_CONFIG2			(host->regs_ip + 0x24)
+#define NFC_V3_CONFIG2_PS_512			(0 << 0)
+#define NFC_V3_CONFIG2_PS_2048			(1 << 0)
+#define NFC_V3_CONFIG2_PS_4096			(2 << 0)
+#define NFC_V3_CONFIG2_ONE_CYCLE		(1 << 2)
+#define NFC_V3_CONFIG2_ECC_EN			(1 << 3)
+#define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
+#define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
+#define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
+#define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
+#define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
+#define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
+#define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
+#define NFC_V3_CONFIG2_SPAS(x)			(((x) & 0xff) << 16)
+
+#define NFC_V3_CONFIG3				(host->regs_ip + 0x28)
+#define NFC_V3_CONFIG3_ADD_OP(x)		(((x) & 0x3) << 0)
+#define NFC_V3_CONFIG3_FW8			(1 << 3)
+#define NFC_V3_CONFIG3_SBB(x)			(((x) & 0x7) << 8)
+#define NFC_V3_CONFIG3_NUM_OF_DEVICES(x)	(((x) & 0x7) << 12)
+#define NFC_V3_CONFIG3_RBB_MODE			(1 << 15)
+#define NFC_V3_CONFIG3_NO_SDMA			(1 << 20)
+
+#define NFC_V3_IPC			(host->regs_ip + 0x2C)
+#define NFC_V3_IPC_CREQ			(1 << 0)
+#define NFC_V3_IPC_INT			(1 << 31)
+
+#define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
+
+struct mxc_nand_host;
+
+struct mxc_nand_devtype_data {
+	void (*preset)(struct mtd_info *);
+	int (*read_page)(struct nand_chip *chip, void *buf, void *oob, bool ecc,
+			 int page);
+	void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
+	void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
+	void (*send_page)(struct mtd_info *, unsigned int);
+	void (*send_read_id)(struct mxc_nand_host *);
+	uint16_t (*get_dev_status)(struct mxc_nand_host *);
+	int (*check_int)(struct mxc_nand_host *);
+	void (*irq_control)(struct mxc_nand_host *, int);
+	u32 (*get_ecc_status)(struct mxc_nand_host *);
+	const struct mtd_ooblayout_ops *ooblayout;
+	void (*select_chip)(struct mtd_info *mtd, int chip);
+	int (*setup_data_interface)(struct mtd_info *mtd, int csline,
+				    const struct nand_data_interface *conf);
+	void (*enable_hwecc)(struct nand_chip *chip, bool enable);
+
+	/*
+	 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
+	 * (CONFIG1:INT_MSK is set). To handle this the driver uses
+	 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
+	 */
+	int irqpending_quirk;
+	int needs_ip;
+
+	size_t regs_offset;
+	size_t spare0_offset;
+	size_t axi_offset;
+
+	int spare_len;
+	int eccbytes;
+	int eccsize;
+	int ppb_shift;
+};
+
+struct mxc_nand_host {
+	struct nand_chip	nand;
+	struct device		*dev;
+
+	void __iomem		*spare0;
+	void __iomem		*main_area0;
+
+	void __iomem		*base;
+	void __iomem		*regs;
+	void __iomem		*regs_axi;
+	void __iomem		*regs_ip;
+	int			status_request;
+	struct clk		*clk;
+	int			clk_act;
+	int			irq;
+	int			eccsize;
+	int			used_oobsize;
+	int			active_cs;
+
+	struct completion	op_completion;
+
+	uint8_t			*data_buf;
+	unsigned int		buf_start;
+
+	const struct mxc_nand_devtype_data *devtype_data;
+	struct mxc_nand_platform_data pdata;
+};
+
+static const char * const part_probes[] = {
+	"cmdlinepart", "RedBoot", "ofpart", NULL };
+
+static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+	int i;
+	u32 *t = trg;
+	const __iomem u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		*t++ = __raw_readl(s++);
+}
+
+static void memcpy16_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+	int i;
+	u16 *t = trg;
+	const __iomem u16 *s = src;
+
+	/* We assume that src (IO) is always 32bit aligned */
+	if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
+		memcpy32_fromio(trg, src, size);
+		return;
+	}
+
+	for (i = 0; i < (size >> 1); i++)
+		*t++ = __raw_readw(s++);
+}
+
+static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+	/* __iowrite32_copy use 32bit size values so divide by 4 */
+	__iowrite32_copy(trg, src, size / 4);
+}
+
+static void memcpy16_toio(void __iomem *trg, const void *src, int size)
+{
+	int i;
+	__iomem u16 *t = trg;
+	const u16 *s = src;
+
+	/* We assume that trg (IO) is always 32bit aligned */
+	if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
+		memcpy32_toio(trg, src, size);
+		return;
+	}
+
+	for (i = 0; i < (size >> 1); i++)
+		__raw_writew(*s++, t++);
+}
+
+/*
+ * The controller splits a page into data chunks of 512 bytes + partial oob.
+ * There are writesize / 512 such chunks, the size of the partial oob parts is
+ * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
+ * contains additionally the byte lost by rounding (if any).
+ * This function handles the needed shuffling between host->data_buf (which
+ * holds a page in natural order, i.e. writesize bytes data + oobsize bytes
+ * spare) and the NFC buffer.
+ */
+static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(this);
+	u16 i, oob_chunk_size;
+	u16 num_chunks = mtd->writesize / 512;
+
+	u8 *d = buf;
+	u8 __iomem *s = host->spare0;
+	u16 sparebuf_size = host->devtype_data->spare_len;
+
+	/* size of oob chunk for all but possibly the last one */
+	oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
+
+	if (bfrom) {
+		for (i = 0; i < num_chunks - 1; i++)
+			memcpy16_fromio(d + i * oob_chunk_size,
+					s + i * sparebuf_size,
+					oob_chunk_size);
+
+		/* the last chunk */
+		memcpy16_fromio(d + i * oob_chunk_size,
+				s + i * sparebuf_size,
+				host->used_oobsize - i * oob_chunk_size);
+	} else {
+		for (i = 0; i < num_chunks - 1; i++)
+			memcpy16_toio(&s[i * sparebuf_size],
+				      &d[i * oob_chunk_size],
+				      oob_chunk_size);
+
+		/* the last chunk */
+		memcpy16_toio(&s[i * sparebuf_size],
+			      &d[i * oob_chunk_size],
+			      host->used_oobsize - i * oob_chunk_size);
+	}
+}
+
+/*
+ * MXC NANDFC can only perform full page+spare or spare-only read/write.  When
+ * the upper layers perform a read/write buf operation, the saved column address
+ * is used to index into the full page. So usually this function is called with
+ * column == 0 (unless no column cycle is needed indicated by column == -1)
+ */
+static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+
+	/* Write out column address, if necessary */
+	if (column != -1) {
+		host->devtype_data->send_addr(host, column & 0xff,
+					      page_addr == -1);
+		if (mtd->writesize > 512)
+			/* another col addr cycle for 2k page */
+			host->devtype_data->send_addr(host,
+						      (column >> 8) & 0xff,
+						      false);
+	}
+
+	/* Write out page address, if necessary */
+	if (page_addr != -1) {
+		/* paddr_0 - p_addr_7 */
+		host->devtype_data->send_addr(host, (page_addr & 0xff), false);
+
+		if (mtd->writesize > 512) {
+			if (mtd->size >= 0x10000000) {
+				/* paddr_8 - paddr_15 */
+				host->devtype_data->send_addr(host,
+						(page_addr >> 8) & 0xff,
+						false);
+				host->devtype_data->send_addr(host,
+						(page_addr >> 16) & 0xff,
+						true);
+			} else
+				/* paddr_8 - paddr_15 */
+				host->devtype_data->send_addr(host,
+						(page_addr >> 8) & 0xff, true);
+		} else {
+			if (nand_chip->options & NAND_ROW_ADDR_3) {
+				/* paddr_8 - paddr_15 */
+				host->devtype_data->send_addr(host,
+						(page_addr >> 8) & 0xff,
+						false);
+				host->devtype_data->send_addr(host,
+						(page_addr >> 16) & 0xff,
+						true);
+			} else
+				/* paddr_8 - paddr_15 */
+				host->devtype_data->send_addr(host,
+						(page_addr >> 8) & 0xff, true);
+		}
+	}
+}
+
+static int check_int_v3(struct mxc_nand_host *host)
+{
+	uint32_t tmp;
+
+	tmp = readl(NFC_V3_IPC);
+	if (!(tmp & NFC_V3_IPC_INT))
+		return 0;
+
+	tmp &= ~NFC_V3_IPC_INT;
+	writel(tmp, NFC_V3_IPC);
+
+	return 1;
+}
+
+static int check_int_v1_v2(struct mxc_nand_host *host)
+{
+	uint32_t tmp;
+
+	tmp = readw(NFC_V1_V2_CONFIG2);
+	if (!(tmp & NFC_V1_V2_CONFIG2_INT))
+		return 0;
+
+	if (!host->devtype_data->irqpending_quirk)
+		writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
+
+	return 1;
+}
+
+static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
+{
+	uint16_t tmp;
+
+	tmp = readw(NFC_V1_V2_CONFIG1);
+
+	if (activate)
+		tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
+	else
+		tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
+
+	writew(tmp, NFC_V1_V2_CONFIG1);
+}
+
+static void irq_control_v3(struct mxc_nand_host *host, int activate)
+{
+	uint32_t tmp;
+
+	tmp = readl(NFC_V3_CONFIG2);
+
+	if (activate)
+		tmp &= ~NFC_V3_CONFIG2_INT_MSK;
+	else
+		tmp |= NFC_V3_CONFIG2_INT_MSK;
+
+	writel(tmp, NFC_V3_CONFIG2);
+}
+
+static void irq_control(struct mxc_nand_host *host, int activate)
+{
+	if (host->devtype_data->irqpending_quirk) {
+		if (activate)
+			enable_irq(host->irq);
+		else
+			disable_irq_nosync(host->irq);
+	} else {
+		host->devtype_data->irq_control(host, activate);
+	}
+}
+
+static u32 get_ecc_status_v1(struct mxc_nand_host *host)
+{
+	return readw(NFC_V1_V2_ECC_STATUS_RESULT);
+}
+
+static u32 get_ecc_status_v2(struct mxc_nand_host *host)
+{
+	return readl(NFC_V1_V2_ECC_STATUS_RESULT);
+}
+
+static u32 get_ecc_status_v3(struct mxc_nand_host *host)
+{
+	return readl(NFC_V3_ECC_STATUS_RESULT);
+}
+
+static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
+{
+	struct mxc_nand_host *host = dev_id;
+
+	if (!host->devtype_data->check_int(host))
+		return IRQ_NONE;
+
+	irq_control(host, 0);
+
+	complete(&host->op_completion);
+
+	return IRQ_HANDLED;
+}
+
+/* This function polls the NANDFC to wait for the basic operation to
+ * complete by checking the INT bit of config2 register.
+ */
+static int wait_op_done(struct mxc_nand_host *host, int useirq)
+{
+	int ret = 0;
+
+	/*
+	 * If operation is already complete, don't bother to setup an irq or a
+	 * loop.
+	 */
+	if (host->devtype_data->check_int(host))
+		return 0;
+
+	if (useirq) {
+		unsigned long timeout;
+
+		reinit_completion(&host->op_completion);
+
+		irq_control(host, 1);
+
+		timeout = wait_for_completion_timeout(&host->op_completion, HZ);
+		if (!timeout && !host->devtype_data->check_int(host)) {
+			dev_dbg(host->dev, "timeout waiting for irq\n");
+			ret = -ETIMEDOUT;
+		}
+	} else {
+		int max_retries = 8000;
+		int done;
+
+		do {
+			udelay(1);
+
+			done = host->devtype_data->check_int(host);
+			if (done)
+				break;
+
+		} while (--max_retries);
+
+		if (!done) {
+			dev_dbg(host->dev, "timeout polling for completion\n");
+			ret = -ETIMEDOUT;
+		}
+	}
+
+	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
+
+	return ret;
+}
+
+static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+{
+	/* fill command */
+	writel(cmd, NFC_V3_FLASH_CMD);
+
+	/* send out command */
+	writel(NFC_CMD, NFC_V3_LAUNCH);
+
+	/* Wait for operation to complete */
+	wait_op_done(host, useirq);
+}
+
+/* This function issues the specified command to the NAND device and
+ * waits for completion. */
+static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+{
+	dev_dbg(host->dev, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
+
+	writew(cmd, NFC_V1_V2_FLASH_CMD);
+	writew(NFC_CMD, NFC_V1_V2_CONFIG2);
+
+	if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
+		int max_retries = 100;
+		/* Reset completion is indicated by NFC_CONFIG2 */
+		/* being set to 0 */
+		while (max_retries-- > 0) {
+			if (readw(NFC_V1_V2_CONFIG2) == 0) {
+				break;
+			}
+			udelay(1);
+		}
+		if (max_retries < 0)
+			dev_dbg(host->dev, "%s: RESET failed\n", __func__);
+	} else {
+		/* Wait for operation to complete */
+		wait_op_done(host, useirq);
+	}
+}
+
+static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
+{
+	/* fill address */
+	writel(addr, NFC_V3_FLASH_ADDR0);
+
+	/* send out address */
+	writel(NFC_ADDR, NFC_V3_LAUNCH);
+
+	wait_op_done(host, 0);
+}
+
+/* This function sends an address (or partial address) to the
+ * NAND device. The address is used to select the source/destination for
+ * a NAND command. */
+static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
+{
+	dev_dbg(host->dev, "send_addr(host, 0x%x %d)\n", addr, islast);
+
+	writew(addr, NFC_V1_V2_FLASH_ADDR);
+	writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
+
+	/* Wait for operation to complete */
+	wait_op_done(host, islast);
+}
+
+static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	uint32_t tmp;
+
+	tmp = readl(NFC_V3_CONFIG1);
+	tmp &= ~(7 << 4);
+	writel(tmp, NFC_V3_CONFIG1);
+
+	/* transfer data from NFC ram to nand */
+	writel(ops, NFC_V3_LAUNCH);
+
+	wait_op_done(host, false);
+}
+
+static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+
+	/* NANDFC buffer 0 is used for page read/write */
+	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+
+	writew(ops, NFC_V1_V2_CONFIG2);
+
+	/* Wait for operation to complete */
+	wait_op_done(host, true);
+}
+
+static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	int bufs, i;
+
+	if (mtd->writesize > 512)
+		bufs = 4;
+	else
+		bufs = 1;
+
+	for (i = 0; i < bufs; i++) {
+
+		/* NANDFC buffer 0 is used for page read/write */
+		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
+
+		writew(ops, NFC_V1_V2_CONFIG2);
+
+		/* Wait for operation to complete */
+		wait_op_done(host, true);
+	}
+}
+
+static void send_read_id_v3(struct mxc_nand_host *host)
+{
+	/* Read ID into main buffer */
+	writel(NFC_ID, NFC_V3_LAUNCH);
+
+	wait_op_done(host, true);
+
+	memcpy32_fromio(host->data_buf, host->main_area0, 16);
+}
+
+/* Request the NANDFC to perform a read of the NAND device ID. */
+static void send_read_id_v1_v2(struct mxc_nand_host *host)
+{
+	/* NANDFC buffer 0 is used for device ID output */
+	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+
+	writew(NFC_ID, NFC_V1_V2_CONFIG2);
+
+	/* Wait for operation to complete */
+	wait_op_done(host, true);
+
+	memcpy32_fromio(host->data_buf, host->main_area0, 16);
+}
+
+static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
+{
+	writew(NFC_STATUS, NFC_V3_LAUNCH);
+	wait_op_done(host, true);
+
+	return readl(NFC_V3_CONFIG1) >> 16;
+}
+
+/* This function requests the NANDFC to perform a read of the
+ * NAND device status and returns the current status. */
+static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
+{
+	void __iomem *main_buf = host->main_area0;
+	uint32_t store;
+	uint16_t ret;
+
+	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+
+	/*
+	 * The device status is stored in main_area0. To
+	 * prevent corruption of the buffer save the value
+	 * and restore it afterwards.
+	 */
+	store = readl(main_buf);
+
+	writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
+	wait_op_done(host, true);
+
+	ret = readw(main_buf);
+
+	writel(store, main_buf);
+
+	return ret;
+}
+
+static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable)
+{
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	uint16_t config1;
+
+	if (chip->ecc.mode != NAND_ECC_HW)
+		return;
+
+	config1 = readw(NFC_V1_V2_CONFIG1);
+
+	if (enable)
+		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+	else
+		config1 &= ~NFC_V1_V2_CONFIG1_ECC_EN;
+
+	writew(config1, NFC_V1_V2_CONFIG1);
+}
+
+static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
+{
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	uint32_t config2;
+
+	if (chip->ecc.mode != NAND_ECC_HW)
+		return;
+
+	config2 = readl(NFC_V3_CONFIG2);
+
+	if (enable)
+		config2 |= NFC_V3_CONFIG2_ECC_EN;
+	else
+		config2 &= ~NFC_V3_CONFIG2_ECC_EN;
+
+	writel(config2, NFC_V3_CONFIG2);
+}
+
+/* This functions is used by upper layer to checks if device is ready */
+static int mxc_nand_dev_ready(struct mtd_info *mtd)
+{
+	/*
+	 * NFC handles R/B internally. Therefore, this function
+	 * always returns status as ready.
+	 */
+	return 1;
+}
+
+static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob,
+				 bool ecc, int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	unsigned int bitflips_corrected = 0;
+	int no_subpages;
+	int i;
+
+	host->devtype_data->enable_hwecc(chip, ecc);
+
+	host->devtype_data->send_cmd(host, NAND_CMD_READ0, false);
+	mxc_do_addr_cycle(mtd, 0, page);
+
+	if (mtd->writesize > 512)
+		host->devtype_data->send_cmd(host, NAND_CMD_READSTART, true);
+
+	no_subpages = mtd->writesize >> 9;
+
+	for (i = 0; i < no_subpages; i++) {
+		uint16_t ecc_stats;
+
+		/* NANDFC buffer 0 is used for page read/write */
+		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
+
+		writew(NFC_OUTPUT, NFC_V1_V2_CONFIG2);
+
+		/* Wait for operation to complete */
+		wait_op_done(host, true);
+
+		ecc_stats = get_ecc_status_v1(host);
+
+		ecc_stats >>= 2;
+
+		if (buf && ecc) {
+			switch (ecc_stats & 0x3) {
+			case 0:
+			default:
+				break;
+			case 1:
+				mtd->ecc_stats.corrected++;
+				bitflips_corrected = 1;
+				break;
+			case 2:
+				mtd->ecc_stats.failed++;
+				break;
+			}
+		}
+	}
+
+	if (buf)
+		memcpy32_fromio(buf, host->main_area0, mtd->writesize);
+	if (oob)
+		copy_spare(mtd, true, oob);
+
+	return bitflips_corrected;
+}
+
+static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
+				    void *oob, bool ecc, int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	unsigned int max_bitflips = 0;
+	u32 ecc_stat, err;
+	int no_subpages;
+	u8 ecc_bit_mask, err_limit;
+
+	host->devtype_data->enable_hwecc(chip, ecc);
+
+	host->devtype_data->send_cmd(host, NAND_CMD_READ0, false);
+	mxc_do_addr_cycle(mtd, 0, page);
+
+	if (mtd->writesize > 512)
+		host->devtype_data->send_cmd(host,
+				NAND_CMD_READSTART, true);
+
+	host->devtype_data->send_page(mtd, NFC_OUTPUT);
+
+	if (buf)
+		memcpy32_fromio(buf, host->main_area0, mtd->writesize);
+	if (oob)
+		copy_spare(mtd, true, oob);
+
+	ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
+	err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
+
+	no_subpages = mtd->writesize >> 9;
+
+	ecc_stat = host->devtype_data->get_ecc_status(host);
+
+	do {
+		err = ecc_stat & ecc_bit_mask;
+		if (err > err_limit) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += err;
+			max_bitflips = max_t(unsigned int, max_bitflips, err);
+		}
+
+		ecc_stat >>= 4;
+	} while (--no_subpages);
+
+	return max_bitflips;
+}
+
+static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			      uint8_t *buf, int oob_required, int page)
+{
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	void *oob_buf;
+
+	if (oob_required)
+		oob_buf = chip->oob_poi;
+	else
+		oob_buf = NULL;
+
+	return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
+}
+
+static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				  uint8_t *buf, int oob_required, int page)
+{
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	void *oob_buf;
+
+	if (oob_required)
+		oob_buf = chip->oob_poi;
+	else
+		oob_buf = NULL;
+
+	return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
+}
+
+static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			     int page)
+{
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+
+	return host->devtype_data->read_page(chip, NULL, chip->oob_poi, 0,
+					     page);
+}
+
+static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
+			       bool ecc, int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+
+	host->devtype_data->enable_hwecc(chip, ecc);
+
+	host->devtype_data->send_cmd(host, NAND_CMD_SEQIN, false);
+	mxc_do_addr_cycle(mtd, 0, page);
+
+	memcpy32_toio(host->main_area0, buf, mtd->writesize);
+	copy_spare(mtd, false, chip->oob_poi);
+
+	host->devtype_data->send_page(mtd, NFC_INPUT);
+	host->devtype_data->send_cmd(host, NAND_CMD_PAGEPROG, true);
+	mxc_do_addr_cycle(mtd, 0, page);
+
+	return 0;
+}
+
+static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+				   const uint8_t *buf, int oob_required,
+				   int page)
+{
+	return mxc_nand_write_page(chip, buf, true, page);
+}
+
+static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				   const uint8_t *buf, int oob_required, int page)
+{
+	return mxc_nand_write_page(chip, buf, false, page);
+}
+
+static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			      int page)
+{
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+
+	memset(host->data_buf, 0xff, mtd->writesize);
+
+	return mxc_nand_write_page(chip, host->data_buf, false, page);
+}
+
+static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	uint8_t ret;
+
+	/* Check for status request */
+	if (host->status_request)
+		return host->devtype_data->get_dev_status(host) & 0xFF;
+
+	if (nand_chip->options & NAND_BUSWIDTH_16) {
+		/* only take the lower byte of each word */
+		ret = *(uint16_t *)(host->data_buf + host->buf_start);
+
+		host->buf_start += 2;
+	} else {
+		ret = *(uint8_t *)(host->data_buf + host->buf_start);
+		host->buf_start++;
+	}
+
+	dev_dbg(host->dev, "%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
+	return ret;
+}
+
+static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	uint16_t ret;
+
+	ret = *(uint16_t *)(host->data_buf + host->buf_start);
+	host->buf_start += 2;
+
+	return ret;
+}
+
+/* Write data of length len to buffer buf. The data to be
+ * written on NAND Flash is first copied to RAMbuffer. After the Data Input
+ * Operation by the NFC, the data is written to NAND Flash */
+static void mxc_nand_write_buf(struct mtd_info *mtd,
+				const u_char *buf, int len)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	u16 col = host->buf_start;
+	int n = mtd->oobsize + mtd->writesize - col;
+
+	n = min(n, len);
+
+	memcpy(host->data_buf + col, buf, n);
+
+	host->buf_start += n;
+}
+
+/* Read the data buffer from the NAND Flash. To read the data from NAND
+ * Flash first the data output cycle is initiated by the NFC, which copies
+ * the data to RAMbuffer. This data of length len is then copied to buffer buf.
+ */
+static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	u16 col = host->buf_start;
+	int n = mtd->oobsize + mtd->writesize - col;
+
+	n = min(n, len);
+
+	memcpy(buf, host->data_buf + col, n);
+
+	host->buf_start += n;
+}
+
+/* This function is used by upper layer for select and
+ * deselect of the NAND chip */
+static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+
+	if (chip == -1) {
+		/* Disable the NFC clock */
+		if (host->clk_act) {
+			clk_disable_unprepare(host->clk);
+			host->clk_act = 0;
+		}
+		return;
+	}
+
+	if (!host->clk_act) {
+		/* Enable the NFC clock */
+		clk_prepare_enable(host->clk);
+		host->clk_act = 1;
+	}
+}
+
+static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+
+	if (chip == -1) {
+		/* Disable the NFC clock */
+		if (host->clk_act) {
+			clk_disable_unprepare(host->clk);
+			host->clk_act = 0;
+		}
+		return;
+	}
+
+	if (!host->clk_act) {
+		/* Enable the NFC clock */
+		clk_prepare_enable(host->clk);
+		host->clk_act = 1;
+	}
+
+	host->active_cs = chip;
+	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
+}
+
+#define MXC_V1_ECCBYTES		5
+
+static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 6;
+	oobregion->length = MXC_V1_ECCBYTES;
+
+	return 0;
+}
+
+static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+
+	if (section > nand_chip->ecc.steps)
+		return -ERANGE;
+
+	if (!section) {
+		if (mtd->writesize <= 512) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 2;
+			oobregion->length = 4;
+		}
+	} else {
+		oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
+		if (section < nand_chip->ecc.steps)
+			oobregion->length = (section * 16) + 6 -
+					    oobregion->offset;
+		else
+			oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
+	.ecc = mxc_v1_ooblayout_ecc,
+	.free = mxc_v1_ooblayout_free,
+};
+
+static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * stepsize) + 7;
+	oobregion->length = nand_chip->ecc.bytes;
+
+	return 0;
+}
+
+static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
+
+	if (section >= nand_chip->ecc.steps)
+		return -ERANGE;
+
+	if (!section) {
+		if (mtd->writesize <= 512) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 2;
+			oobregion->length = 4;
+		}
+	} else {
+		oobregion->offset = section * stepsize;
+		oobregion->length = 7;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
+	.ecc = mxc_v2_ooblayout_ecc,
+	.free = mxc_v2_ooblayout_free,
+};
+
+/*
+ * v2 and v3 type controllers can do 4bit or 8bit ecc depending
+ * on how much oob the nand chip has. For 8bit ecc we need at least
+ * 26 bytes of oob data per 512 byte block.
+ */
+static int get_eccsize(struct mtd_info *mtd)
+{
+	int oobbytes_per_512 = 0;
+
+	oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
+
+	if (oobbytes_per_512 < 26)
+		return 4;
+	else
+		return 8;
+}
+
+static void preset_v1(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	uint16_t config1 = 0;
+
+	if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
+		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+
+	if (!host->devtype_data->irqpending_quirk)
+		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
+
+	host->eccsize = 1;
+
+	writew(config1, NFC_V1_V2_CONFIG1);
+	/* preset operation */
+
+	/* Unlock the internal RAM Buffer */
+	writew(0x2, NFC_V1_V2_CONFIG);
+
+	/* Blocks to be unlocked */
+	writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
+	writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
+
+	/* Unlock Block Command for given address range */
+	writew(0x4, NFC_V1_V2_WRPROT);
+}
+
+static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
+					const struct nand_data_interface *conf)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	int tRC_min_ns, tRC_ps, ret;
+	unsigned long rate, rate_round;
+	const struct nand_sdr_timings *timings;
+	u16 config1;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return -ENOTSUPP;
+
+	config1 = readw(NFC_V1_V2_CONFIG1);
+
+	tRC_min_ns = timings->tRC_min / 1000;
+	rate = 1000000000 / tRC_min_ns;
+
+	/*
+	 * For tRC < 30ns we have to use EDO mode. In this case the controller
+	 * does one access per clock cycle. Otherwise the controller does one
+	 * access in two clock cycles, thus we have to double the rate to the
+	 * controller.
+	 */
+	if (tRC_min_ns < 30) {
+		rate_round = clk_round_rate(host->clk, rate);
+		config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
+		tRC_ps = 1000000000 / (rate_round / 1000);
+	} else {
+		rate *= 2;
+		rate_round = clk_round_rate(host->clk, rate);
+		config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
+		tRC_ps = 1000000000 / (rate_round / 1000 / 2);
+	}
+
+	/*
+	 * The timing values compared against are from the i.MX25 Automotive
+	 * datasheet, Table 50. NFC Timing Parameters
+	 */
+	if (timings->tCLS_min > tRC_ps - 1000 ||
+	    timings->tCLH_min > tRC_ps - 2000 ||
+	    timings->tCS_min > tRC_ps - 1000 ||
+	    timings->tCH_min > tRC_ps - 2000 ||
+	    timings->tWP_min > tRC_ps - 1500 ||
+	    timings->tALS_min > tRC_ps ||
+	    timings->tALH_min > tRC_ps - 3000 ||
+	    timings->tDS_min > tRC_ps ||
+	    timings->tDH_min > tRC_ps - 5000 ||
+	    timings->tWC_min > 2 * tRC_ps ||
+	    timings->tWH_min > tRC_ps - 2500 ||
+	    timings->tRR_min > 6 * tRC_ps ||
+	    timings->tRP_min > 3 * tRC_ps / 2 ||
+	    timings->tRC_min > 2 * tRC_ps ||
+	    timings->tREH_min > (tRC_ps / 2) - 2500) {
+		dev_dbg(host->dev, "Timing out of bounds\n");
+		return -EINVAL;
+	}
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	ret = clk_set_rate(host->clk, rate);
+	if (ret)
+		return ret;
+
+	writew(config1, NFC_V1_V2_CONFIG1);
+
+	dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
+		config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
+		"normal");
+
+	return 0;
+}
+
+static void preset_v2(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	uint16_t config1 = 0;
+
+	config1 |= NFC_V2_CONFIG1_FP_INT;
+
+	if (!host->devtype_data->irqpending_quirk)
+		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
+
+	if (mtd->writesize) {
+		uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
+
+		if (nand_chip->ecc.mode == NAND_ECC_HW)
+			config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
+
+		host->eccsize = get_eccsize(mtd);
+		if (host->eccsize == 4)
+			config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
+
+		config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
+	} else {
+		host->eccsize = 1;
+	}
+
+	writew(config1, NFC_V1_V2_CONFIG1);
+	/* preset operation */
+
+	/* Unlock the internal RAM Buffer */
+	writew(0x2, NFC_V1_V2_CONFIG);
+
+	/* Blocks to be unlocked */
+	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
+	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
+	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
+	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
+	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
+	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
+	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
+	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
+
+	/* Unlock Block Command for given address range */
+	writew(0x4, NFC_V1_V2_WRPROT);
+}
+
+static void preset_v3(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(chip);
+	uint32_t config2, config3;
+	int i, addr_phases;
+
+	writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
+	writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
+
+	/* Unlock the internal RAM Buffer */
+	writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
+			NFC_V3_WRPROT);
+
+	/* Blocks to be unlocked */
+	for (i = 0; i < NAND_MAX_CHIPS; i++)
+		writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
+
+	writel(0, NFC_V3_IPC);
+
+	config2 = NFC_V3_CONFIG2_ONE_CYCLE |
+		NFC_V3_CONFIG2_2CMD_PHASES |
+		NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
+		NFC_V3_CONFIG2_ST_CMD(0x70) |
+		NFC_V3_CONFIG2_INT_MSK |
+		NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
+
+	addr_phases = fls(chip->pagemask) >> 3;
+
+	if (mtd->writesize == 2048) {
+		config2 |= NFC_V3_CONFIG2_PS_2048;
+		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
+	} else if (mtd->writesize == 4096) {
+		config2 |= NFC_V3_CONFIG2_PS_4096;
+		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
+	} else {
+		config2 |= NFC_V3_CONFIG2_PS_512;
+		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
+	}
+
+	if (mtd->writesize) {
+		if (chip->ecc.mode == NAND_ECC_HW)
+			config2 |= NFC_V3_CONFIG2_ECC_EN;
+
+		config2 |= NFC_V3_CONFIG2_PPB(
+				ffs(mtd->erasesize / mtd->writesize) - 6,
+				host->devtype_data->ppb_shift);
+		host->eccsize = get_eccsize(mtd);
+		if (host->eccsize == 8)
+			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
+	}
+
+	writel(config2, NFC_V3_CONFIG2);
+
+	config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
+			NFC_V3_CONFIG3_NO_SDMA |
+			NFC_V3_CONFIG3_RBB_MODE |
+			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
+			NFC_V3_CONFIG3_ADD_OP(0);
+
+	if (!(chip->options & NAND_BUSWIDTH_16))
+		config3 |= NFC_V3_CONFIG3_FW8;
+
+	writel(config3, NFC_V3_CONFIG3);
+
+	writel(0, NFC_V3_DELAY_LINE);
+}
+
+/* Used by the upper layer to write command to NAND Flash for
+ * different operations to be carried out on NAND Flash */
+static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+				int column, int page_addr)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+
+	dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
+	      command, column, page_addr);
+
+	/* Reset command state information */
+	host->status_request = false;
+
+	/* Command pre-processing step */
+	switch (command) {
+	case NAND_CMD_RESET:
+		host->devtype_data->preset(mtd);
+		host->devtype_data->send_cmd(host, command, false);
+		break;
+
+	case NAND_CMD_STATUS:
+		host->buf_start = 0;
+		host->status_request = true;
+
+		host->devtype_data->send_cmd(host, command, true);
+		WARN_ONCE(column != -1 || page_addr != -1,
+			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
+			  command, column, page_addr);
+		mxc_do_addr_cycle(mtd, column, page_addr);
+		break;
+
+	case NAND_CMD_READID:
+		host->devtype_data->send_cmd(host, command, true);
+		mxc_do_addr_cycle(mtd, column, page_addr);
+		host->devtype_data->send_read_id(host);
+		host->buf_start = 0;
+		break;
+
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+		host->devtype_data->send_cmd(host, command, false);
+		WARN_ONCE(column != -1,
+			  "Unexpected column value (cmd=%u, col=%d)\n",
+			  command, column);
+		mxc_do_addr_cycle(mtd, column, page_addr);
+
+		break;
+	case NAND_CMD_PARAM:
+		host->devtype_data->send_cmd(host, command, false);
+		mxc_do_addr_cycle(mtd, column, page_addr);
+		host->devtype_data->send_page(mtd, NFC_OUTPUT);
+		memcpy32_fromio(host->data_buf, host->main_area0, 512);
+		host->buf_start = 0;
+		break;
+	default:
+		WARN_ONCE(1, "Unimplemented command (cmd=%u)\n",
+			  command);
+		break;
+	}
+}
+
+static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
+				      struct nand_chip *chip, int addr,
+				      u8 *subfeature_param)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	int i;
+
+	if (!chip->onfi_version ||
+	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+		return -EINVAL;
+
+	host->buf_start = 0;
+
+	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+		chip->write_byte(mtd, subfeature_param[i]);
+
+	memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
+	host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
+	mxc_do_addr_cycle(mtd, addr, -1);
+	host->devtype_data->send_page(mtd, NFC_INPUT);
+
+	return 0;
+}
+
+static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
+				      struct nand_chip *chip, int addr,
+				      u8 *subfeature_param)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+	int i;
+
+	if (!chip->onfi_version ||
+	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+		return -EINVAL;
+
+	host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
+	mxc_do_addr_cycle(mtd, addr, -1);
+	host->devtype_data->send_page(mtd, NFC_OUTPUT);
+	memcpy32_fromio(host->data_buf, host->main_area0, 512);
+	host->buf_start = 0;
+
+	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+		*subfeature_param++ = chip->read_byte(mtd);
+
+	return 0;
+}
+
+/*
+ * The generic flash bbt decriptors overlap with our ecc
+ * hardware, so define some i.MX specific ones.
+ */
+static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs = 0,
+	.len = 4,
+	.veroffs = 4,
+	.maxblocks = 4,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs = 0,
+	.len = 4,
+	.veroffs = 4,
+	.maxblocks = 4,
+	.pattern = mirror_pattern,
+};
+
+/* v1 + irqpending_quirk: i.MX21 */
+static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
+	.preset = preset_v1,
+	.read_page = mxc_nand_read_page_v1,
+	.send_cmd = send_cmd_v1_v2,
+	.send_addr = send_addr_v1_v2,
+	.send_page = send_page_v1,
+	.send_read_id = send_read_id_v1_v2,
+	.get_dev_status = get_dev_status_v1_v2,
+	.check_int = check_int_v1_v2,
+	.irq_control = irq_control_v1_v2,
+	.get_ecc_status = get_ecc_status_v1,
+	.ooblayout = &mxc_v1_ooblayout_ops,
+	.select_chip = mxc_nand_select_chip_v1_v3,
+	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
+	.irqpending_quirk = 1,
+	.needs_ip = 0,
+	.regs_offset = 0xe00,
+	.spare0_offset = 0x800,
+	.spare_len = 16,
+	.eccbytes = 3,
+	.eccsize = 1,
+};
+
+/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
+static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
+	.preset = preset_v1,
+	.read_page = mxc_nand_read_page_v1,
+	.send_cmd = send_cmd_v1_v2,
+	.send_addr = send_addr_v1_v2,
+	.send_page = send_page_v1,
+	.send_read_id = send_read_id_v1_v2,
+	.get_dev_status = get_dev_status_v1_v2,
+	.check_int = check_int_v1_v2,
+	.irq_control = irq_control_v1_v2,
+	.get_ecc_status = get_ecc_status_v1,
+	.ooblayout = &mxc_v1_ooblayout_ops,
+	.select_chip = mxc_nand_select_chip_v1_v3,
+	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
+	.irqpending_quirk = 0,
+	.needs_ip = 0,
+	.regs_offset = 0xe00,
+	.spare0_offset = 0x800,
+	.axi_offset = 0,
+	.spare_len = 16,
+	.eccbytes = 3,
+	.eccsize = 1,
+};
+
+/* v21: i.MX25, i.MX35 */
+static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
+	.preset = preset_v2,
+	.read_page = mxc_nand_read_page_v2_v3,
+	.send_cmd = send_cmd_v1_v2,
+	.send_addr = send_addr_v1_v2,
+	.send_page = send_page_v2,
+	.send_read_id = send_read_id_v1_v2,
+	.get_dev_status = get_dev_status_v1_v2,
+	.check_int = check_int_v1_v2,
+	.irq_control = irq_control_v1_v2,
+	.get_ecc_status = get_ecc_status_v2,
+	.ooblayout = &mxc_v2_ooblayout_ops,
+	.select_chip = mxc_nand_select_chip_v2,
+	.setup_data_interface = mxc_nand_v2_setup_data_interface,
+	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
+	.irqpending_quirk = 0,
+	.needs_ip = 0,
+	.regs_offset = 0x1e00,
+	.spare0_offset = 0x1000,
+	.axi_offset = 0,
+	.spare_len = 64,
+	.eccbytes = 9,
+	.eccsize = 0,
+};
+
+/* v3.2a: i.MX51 */
+static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
+	.preset = preset_v3,
+	.read_page = mxc_nand_read_page_v2_v3,
+	.send_cmd = send_cmd_v3,
+	.send_addr = send_addr_v3,
+	.send_page = send_page_v3,
+	.send_read_id = send_read_id_v3,
+	.get_dev_status = get_dev_status_v3,
+	.check_int = check_int_v3,
+	.irq_control = irq_control_v3,
+	.get_ecc_status = get_ecc_status_v3,
+	.ooblayout = &mxc_v2_ooblayout_ops,
+	.select_chip = mxc_nand_select_chip_v1_v3,
+	.enable_hwecc = mxc_nand_enable_hwecc_v3,
+	.irqpending_quirk = 0,
+	.needs_ip = 1,
+	.regs_offset = 0,
+	.spare0_offset = 0x1000,
+	.axi_offset = 0x1e00,
+	.spare_len = 64,
+	.eccbytes = 0,
+	.eccsize = 0,
+	.ppb_shift = 7,
+};
+
+/* v3.2b: i.MX53 */
+static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
+	.preset = preset_v3,
+	.read_page = mxc_nand_read_page_v2_v3,
+	.send_cmd = send_cmd_v3,
+	.send_addr = send_addr_v3,
+	.send_page = send_page_v3,
+	.send_read_id = send_read_id_v3,
+	.get_dev_status = get_dev_status_v3,
+	.check_int = check_int_v3,
+	.irq_control = irq_control_v3,
+	.get_ecc_status = get_ecc_status_v3,
+	.ooblayout = &mxc_v2_ooblayout_ops,
+	.select_chip = mxc_nand_select_chip_v1_v3,
+	.enable_hwecc = mxc_nand_enable_hwecc_v3,
+	.irqpending_quirk = 0,
+	.needs_ip = 1,
+	.regs_offset = 0,
+	.spare0_offset = 0x1000,
+	.axi_offset = 0x1e00,
+	.spare_len = 64,
+	.eccbytes = 0,
+	.eccsize = 0,
+	.ppb_shift = 8,
+};
+
+static inline int is_imx21_nfc(struct mxc_nand_host *host)
+{
+	return host->devtype_data == &imx21_nand_devtype_data;
+}
+
+static inline int is_imx27_nfc(struct mxc_nand_host *host)
+{
+	return host->devtype_data == &imx27_nand_devtype_data;
+}
+
+static inline int is_imx25_nfc(struct mxc_nand_host *host)
+{
+	return host->devtype_data == &imx25_nand_devtype_data;
+}
+
+static inline int is_imx51_nfc(struct mxc_nand_host *host)
+{
+	return host->devtype_data == &imx51_nand_devtype_data;
+}
+
+static inline int is_imx53_nfc(struct mxc_nand_host *host)
+{
+	return host->devtype_data == &imx53_nand_devtype_data;
+}
+
+static const struct platform_device_id mxcnd_devtype[] = {
+	{
+		.name = "imx21-nand",
+		.driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
+	}, {
+		.name = "imx27-nand",
+		.driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
+	}, {
+		.name = "imx25-nand",
+		.driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
+	}, {
+		.name = "imx51-nand",
+		.driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
+	}, {
+		.name = "imx53-nand",
+		.driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
+
+#ifdef CONFIG_OF
+static const struct of_device_id mxcnd_dt_ids[] = {
+	{
+		.compatible = "fsl,imx21-nand",
+		.data = &imx21_nand_devtype_data,
+	}, {
+		.compatible = "fsl,imx27-nand",
+		.data = &imx27_nand_devtype_data,
+	}, {
+		.compatible = "fsl,imx25-nand",
+		.data = &imx25_nand_devtype_data,
+	}, {
+		.compatible = "fsl,imx51-nand",
+		.data = &imx51_nand_devtype_data,
+	}, {
+		.compatible = "fsl,imx53-nand",
+		.data = &imx53_nand_devtype_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
+
+static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
+{
+	struct device_node *np = host->dev->of_node;
+	const struct of_device_id *of_id =
+		of_match_device(mxcnd_dt_ids, host->dev);
+
+	if (!np)
+		return 1;
+
+	host->devtype_data = of_id->data;
+
+	return 0;
+}
+#else
+static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
+{
+	return 1;
+}
+#endif
+
+static int mxcnd_probe(struct platform_device *pdev)
+{
+	struct nand_chip *this;
+	struct mtd_info *mtd;
+	struct mxc_nand_host *host;
+	struct resource *res;
+	int err = 0;
+
+	/* Allocate memory for MTD device structure and private data */
+	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
+			GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	/* allocate a temporary buffer for the nand_scan_ident() */
+	host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
+	if (!host->data_buf)
+		return -ENOMEM;
+
+	host->dev = &pdev->dev;
+	/* structures must be linked */
+	this = &host->nand;
+	mtd = nand_to_mtd(this);
+	mtd->dev.parent = &pdev->dev;
+	mtd->name = DRIVER_NAME;
+
+	/* 50 us command delay time */
+	this->chip_delay = 5;
+
+	nand_set_controller_data(this, host);
+	nand_set_flash_node(this, pdev->dev.of_node),
+	this->dev_ready = mxc_nand_dev_ready;
+	this->cmdfunc = mxc_nand_command;
+	this->read_byte = mxc_nand_read_byte;
+	this->read_word = mxc_nand_read_word;
+	this->write_buf = mxc_nand_write_buf;
+	this->read_buf = mxc_nand_read_buf;
+	this->onfi_set_features = mxc_nand_onfi_set_features;
+	this->onfi_get_features = mxc_nand_onfi_get_features;
+
+	host->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	err = mxcnd_probe_dt(host);
+	if (err > 0) {
+		struct mxc_nand_platform_data *pdata =
+					dev_get_platdata(&pdev->dev);
+		if (pdata) {
+			host->pdata = *pdata;
+			host->devtype_data = (struct mxc_nand_devtype_data *)
+						pdev->id_entry->driver_data;
+		} else {
+			err = -ENODEV;
+		}
+	}
+	if (err < 0)
+		return err;
+
+	this->setup_data_interface = host->devtype_data->setup_data_interface;
+
+	if (host->devtype_data->needs_ip) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(host->regs_ip))
+			return PTR_ERR(host->regs_ip);
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	} else {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	}
+
+	host->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(host->base))
+		return PTR_ERR(host->base);
+
+	host->main_area0 = host->base;
+
+	if (host->devtype_data->regs_offset)
+		host->regs = host->base + host->devtype_data->regs_offset;
+	host->spare0 = host->base + host->devtype_data->spare0_offset;
+	if (host->devtype_data->axi_offset)
+		host->regs_axi = host->base + host->devtype_data->axi_offset;
+
+	this->ecc.bytes = host->devtype_data->eccbytes;
+	host->eccsize = host->devtype_data->eccsize;
+
+	this->select_chip = host->devtype_data->select_chip;
+	this->ecc.size = 512;
+	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
+
+	if (host->pdata.hw_ecc) {
+		this->ecc.mode = NAND_ECC_HW;
+	} else {
+		this->ecc.mode = NAND_ECC_SOFT;
+		this->ecc.algo = NAND_ECC_HAMMING;
+	}
+
+	/* NAND bus width determines access functions used by upper layer */
+	if (host->pdata.width == 2)
+		this->options |= NAND_BUSWIDTH_16;
+
+	/* update flash based bbt */
+	if (host->pdata.flash_bbt)
+		this->bbt_options |= NAND_BBT_USE_FLASH;
+
+	init_completion(&host->op_completion);
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0)
+		return host->irq;
+
+	/*
+	 * Use host->devtype_data->irq_control() here instead of irq_control()
+	 * because we must not disable_irq_nosync without having requested the
+	 * irq.
+	 */
+	host->devtype_data->irq_control(host, 0);
+
+	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
+			0, DRIVER_NAME, host);
+	if (err)
+		return err;
+
+	err = clk_prepare_enable(host->clk);
+	if (err)
+		return err;
+	host->clk_act = 1;
+
+	/*
+	 * Now that we "own" the interrupt make sure the interrupt mask bit is
+	 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
+	 * on this machine.
+	 */
+	if (host->devtype_data->irqpending_quirk) {
+		disable_irq_nosync(host->irq);
+		host->devtype_data->irq_control(host, 1);
+	}
+
+	/* first scan to find the device and get the page size */
+	err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
+	if (err)
+		goto escan;
+
+	switch (this->ecc.mode) {
+	case NAND_ECC_HW:
+		this->ecc.read_page = mxc_nand_read_page;
+		this->ecc.read_page_raw = mxc_nand_read_page_raw;
+		this->ecc.read_oob = mxc_nand_read_oob;
+		this->ecc.write_page = mxc_nand_write_page_ecc;
+		this->ecc.write_page_raw = mxc_nand_write_page_raw;
+		this->ecc.write_oob = mxc_nand_write_oob;
+		break;
+
+	case NAND_ECC_SOFT:
+		break;
+
+	default:
+		err = -EINVAL;
+		goto escan;
+	}
+
+	if (this->bbt_options & NAND_BBT_USE_FLASH) {
+		this->bbt_td = &bbt_main_descr;
+		this->bbt_md = &bbt_mirror_descr;
+	}
+
+	/* allocate the right size buffer now */
+	devm_kfree(&pdev->dev, (void *)host->data_buf);
+	host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
+					GFP_KERNEL);
+	if (!host->data_buf) {
+		err = -ENOMEM;
+		goto escan;
+	}
+
+	/* Call preset again, with correct writesize this time */
+	host->devtype_data->preset(mtd);
+
+	if (!this->ecc.bytes) {
+		if (host->eccsize == 8)
+			this->ecc.bytes = 18;
+		else if (host->eccsize == 4)
+			this->ecc.bytes = 9;
+	}
+
+	/*
+	 * Experimentation shows that i.MX NFC can only handle up to 218 oob
+	 * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
+	 * into copying invalid data to/from the spare IO buffer, as this
+	 * might cause ECC data corruption when doing sub-page write to a
+	 * partially written page.
+	 */
+	host->used_oobsize = min(mtd->oobsize, 218U);
+
+	if (this->ecc.mode == NAND_ECC_HW) {
+		if (is_imx21_nfc(host) || is_imx27_nfc(host))
+			this->ecc.strength = 1;
+		else
+			this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
+	}
+
+	/* second phase scan */
+	err = nand_scan_tail(mtd);
+	if (err)
+		goto escan;
+
+	/* Register the partitions */
+	mtd_device_parse_register(mtd, part_probes,
+			NULL,
+			host->pdata.parts,
+			host->pdata.nr_parts);
+
+	platform_set_drvdata(pdev, host);
+
+	return 0;
+
+escan:
+	if (host->clk_act)
+		clk_disable_unprepare(host->clk);
+
+	return err;
+}
+
+static int mxcnd_remove(struct platform_device *pdev)
+{
+	struct mxc_nand_host *host = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&host->nand));
+	if (host->clk_act)
+		clk_disable_unprepare(host->clk);
+
+	return 0;
+}
+
+static struct platform_driver mxcnd_driver = {
+	.driver = {
+		   .name = DRIVER_NAME,
+		   .of_match_table = of_match_ptr(mxcnd_dt_ids),
+	},
+	.id_table = mxcnd_devtype,
+	.probe = mxcnd_probe,
+	.remove = mxcnd_remove,
+};
+module_platform_driver(mxcnd_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC NAND MTD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c
new file mode 100644
index 000000000000..22f060f38123
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_amd.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mtd/rawnand.h>
+
+static void amd_nand_decode_id(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	nand_decode_ext_id(chip);
+
+	/*
+	 * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+	 * some Spansion chips have erasesize that conflicts with size
+	 * listed in nand_ids table.
+	 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+	 */
+	if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
+	    chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
+	    mtd->writesize == 512) {
+		mtd->erasesize = 128 * 1024;
+		mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
+	}
+}
+
+static int amd_nand_init(struct nand_chip *chip)
+{
+	if (nand_is_slc(chip))
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+	return 0;
+}
+
+const struct nand_manufacturer_ops amd_nand_manuf_ops = {
+	.detect = amd_nand_decode_id,
+	.init = amd_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
new file mode 100644
index 000000000000..e70ca16a5118
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -0,0 +1,6582 @@
+/*
+ *  Overview:
+ *   This is the generic MTD driver for NAND flash devices. It should be
+ *   capable of working with almost all NAND chips currently available.
+ *
+ *	Additional technical information is available on
+ *	http://www.linux-mtd.infradead.org/doc/nand.html
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *		  2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  Credits:
+ *	David Woodhouse for adding multichip support
+ *
+ *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ *	rework for 2K page size chips
+ *
+ *  TODO:
+ *	Enable cached programming for 2k page size chips
+ *	Check, if mtd->ecctype should be set to MTD_ECC_HW
+ *	if we have HW ECC support.
+ *	BBT table is not serialized, has to be fixed
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/nmi.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand_bch.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+static int nand_get_device(struct mtd_info *mtd, int new_state);
+
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+			     struct mtd_oob_ops *ops);
+
+/* Define default oob placement schemes for large and small page devices */
+static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section > 1)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->offset = 0;
+		if (mtd->oobsize == 16)
+			oobregion->length = 4;
+		else
+			oobregion->length = 3;
+	} else {
+		if (mtd->oobsize == 8)
+			return -ERANGE;
+
+		oobregion->offset = 6;
+		oobregion->length = ecc->total - 4;
+	}
+
+	return 0;
+}
+
+static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	if (mtd->oobsize == 16) {
+		if (section)
+			return -ERANGE;
+
+		oobregion->length = 8;
+		oobregion->offset = 8;
+	} else {
+		oobregion->length = 2;
+		if (!section)
+			oobregion->offset = 3;
+		else
+			oobregion->offset = 6;
+	}
+
+	return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
+	.ecc = nand_ooblayout_ecc_sp,
+	.free = nand_ooblayout_free_sp,
+};
+EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
+
+static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section || !ecc->total)
+		return -ERANGE;
+
+	oobregion->length = ecc->total;
+	oobregion->offset = mtd->oobsize - oobregion->length;
+
+	return 0;
+}
+
+static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = mtd->oobsize - ecc->total - 2;
+	oobregion->offset = 2;
+
+	return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
+	.ecc = nand_ooblayout_ecc_lp,
+	.free = nand_ooblayout_free_lp,
+};
+EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
+
+/*
+ * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
+ * are placed at a fixed offset.
+ */
+static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section)
+		return -ERANGE;
+
+	switch (mtd->oobsize) {
+	case 64:
+		oobregion->offset = 40;
+		break;
+	case 128:
+		oobregion->offset = 80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	oobregion->length = ecc->total;
+	if (oobregion->offset + oobregion->length > mtd->oobsize)
+		return -ERANGE;
+
+	return 0;
+}
+
+static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
+					  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ecc_offset = 0;
+
+	if (section < 0 || section > 1)
+		return -ERANGE;
+
+	switch (mtd->oobsize) {
+	case 64:
+		ecc_offset = 40;
+		break;
+	case 128:
+		ecc_offset = 80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (section == 0) {
+		oobregion->offset = 2;
+		oobregion->length = ecc_offset - 2;
+	} else {
+		oobregion->offset = ecc_offset + ecc->total;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
+	.ecc = nand_ooblayout_ecc_lp_hamming,
+	.free = nand_ooblayout_free_lp_hamming,
+};
+
+static int check_offs_len(struct mtd_info *mtd,
+					loff_t ofs, uint64_t len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret = 0;
+
+	/* Start address must align on block boundary */
+	if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
+		pr_debug("%s: unaligned address\n", __func__);
+		ret = -EINVAL;
+	}
+
+	/* Length must align on block boundary */
+	if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
+		pr_debug("%s: length not block aligned\n", __func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * nand_release_device - [GENERIC] release chip
+ * @mtd: MTD device structure
+ *
+ * Release chip lock and wake up anyone waiting on the device.
+ */
+static void nand_release_device(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	/* Release the controller and the chip */
+	spin_lock(&chip->controller->lock);
+	chip->controller->active = NULL;
+	chip->state = FL_READY;
+	wake_up(&chip->controller->wq);
+	spin_unlock(&chip->controller->lock);
+}
+
+/**
+ * nand_read_byte - [DEFAULT] read one byte from the chip
+ * @mtd: MTD device structure
+ *
+ * Default read function for 8bit buswidth
+ */
+static uint8_t nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	return readb(chip->IO_ADDR_R);
+}
+
+/**
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
+ * @mtd: MTD device structure
+ *
+ * Default read function for 16bit buswidth with endianness conversion.
+ *
+ */
+static uint8_t nand_read_byte16(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
+}
+
+/**
+ * nand_read_word - [DEFAULT] read one word from the chip
+ * @mtd: MTD device structure
+ *
+ * Default read function for 16bit buswidth without endianness conversion.
+ */
+static u16 nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	return readw(chip->IO_ADDR_R);
+}
+
+/**
+ * nand_select_chip - [DEFAULT] control CE line
+ * @mtd: MTD device structure
+ * @chipnr: chipnumber to select, -1 for deselect
+ *
+ * Default select function for 1 chip devices.
+ */
+static void nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	switch (chipnr) {
+	case -1:
+		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+		break;
+	case 0:
+		break;
+
+	default:
+		BUG();
+	}
+}
+
+/**
+ * nand_write_byte - [DEFAULT] write single byte to chip
+ * @mtd: MTD device structure
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0]
+ */
+static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	chip->write_buf(mtd, &byte, 1);
+}
+
+/**
+ * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
+ * @mtd: MTD device structure
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
+ */
+static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint16_t word = byte;
+
+	/*
+	 * It's not entirely clear what should happen to I/O[15:8] when writing
+	 * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
+	 *
+	 *    When the host supports a 16-bit bus width, only data is
+	 *    transferred at the 16-bit width. All address and command line
+	 *    transfers shall use only the lower 8-bits of the data bus. During
+	 *    command transfers, the host may place any value on the upper
+	 *    8-bits of the data bus. During address transfers, the host shall
+	 *    set the upper 8-bits of the data bus to 00h.
+	 *
+	 * One user of the write_byte callback is nand_onfi_set_features. The
+	 * four parameters are specified to be written to I/O[7:0], but this is
+	 * neither an address nor a command transfer. Let's assume a 0 on the
+	 * upper I/O lines is OK.
+	 */
+	chip->write_buf(mtd, (uint8_t *)&word, 2);
+}
+
+/**
+ * nand_write_buf - [DEFAULT] write buffer to chip
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 8bit buswidth.
+ */
+static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	iowrite8_rep(chip->IO_ADDR_W, buf, len);
+}
+
+/**
+ * nand_read_buf - [DEFAULT] read chip data into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 8bit buswidth.
+ */
+static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	ioread8_rep(chip->IO_ADDR_R, buf, len);
+}
+
+/**
+ * nand_write_buf16 - [DEFAULT] write buffer to chip
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 16bit buswidth.
+ */
+static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u16 *p = (u16 *) buf;
+
+	iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
+}
+
+/**
+ * nand_read_buf16 - [DEFAULT] read chip data into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 16bit buswidth.
+ */
+static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u16 *p = (u16 *) buf;
+
+	ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
+}
+
+/**
+ * nand_block_bad - [DEFAULT] Read bad block marker from the chip
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * Check, if the block is bad.
+ */
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+{
+	int page, page_end, res;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u8 bad;
+
+	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+		ofs += mtd->erasesize - mtd->writesize;
+
+	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+	page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
+
+	for (; page < page_end; page++) {
+		res = chip->ecc.read_oob(mtd, chip, page);
+		if (res)
+			return res;
+
+		bad = chip->oob_poi[chip->badblockpos];
+
+		if (likely(chip->badblockbits == 8))
+			res = bad != 0xFF;
+		else
+			res = hweight8(bad) < chip->badblockbits;
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+/**
+ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This is the default implementation, which can be overridden by a hardware
+ * specific driver. It provides the details for writing a bad block marker to a
+ * block.
+ */
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtd_oob_ops ops;
+	uint8_t buf[2] = { 0, 0 };
+	int ret = 0, res, i = 0;
+
+	memset(&ops, 0, sizeof(ops));
+	ops.oobbuf = buf;
+	ops.ooboffs = chip->badblockpos;
+	if (chip->options & NAND_BUSWIDTH_16) {
+		ops.ooboffs &= ~0x01;
+		ops.len = ops.ooblen = 2;
+	} else {
+		ops.len = ops.ooblen = 1;
+	}
+	ops.mode = MTD_OPS_PLACE_OOB;
+
+	/* Write to first/last page(s) if necessary */
+	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+		ofs += mtd->erasesize - mtd->writesize;
+	do {
+		res = nand_do_write_oob(mtd, ofs, &ops);
+		if (!ret)
+			ret = res;
+
+		i++;
+		ofs += mtd->writesize;
+	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+	return ret;
+}
+
+/**
+ * nand_block_markbad_lowlevel - mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This function performs the generic NAND bad block marking steps (i.e., bad
+ * block table(s) and/or marker(s)). We only allow the hardware driver to
+ * specify how to write bad block markers to OOB (chip->block_markbad).
+ *
+ * We try operations in the following order:
+ *
+ *  (1) erase the affected block, to allow OOB marker to be written cleanly
+ *  (2) write bad block marker to OOB area of affected block (unless flag
+ *      NAND_BBT_NO_OOB_BBM is present)
+ *  (3) update the BBT
+ *
+ * Note that we retain the first error encountered in (2) or (3), finish the
+ * procedures, and dump the error in the end.
+*/
+static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int res, ret = 0;
+
+	if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+		struct erase_info einfo;
+
+		/* Attempt erase before marking OOB */
+		memset(&einfo, 0, sizeof(einfo));
+		einfo.mtd = mtd;
+		einfo.addr = ofs;
+		einfo.len = 1ULL << chip->phys_erase_shift;
+		nand_erase_nand(mtd, &einfo, 0);
+
+		/* Write bad block marker to OOB */
+		nand_get_device(mtd, FL_WRITING);
+		ret = chip->block_markbad(mtd, ofs);
+		nand_release_device(mtd);
+	}
+
+	/* Mark block bad in BBT */
+	if (chip->bbt) {
+		res = nand_markbad_bbt(mtd, ofs);
+		if (!ret)
+			ret = res;
+	}
+
+	if (!ret)
+		mtd->ecc_stats.badblocks++;
+
+	return ret;
+}
+
+/**
+ * nand_check_wp - [GENERIC] check if the chip is write protected
+ * @mtd: MTD device structure
+ *
+ * Check, if the device is write protected. The function expects, that the
+ * device is already selected.
+ */
+static int nand_check_wp(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u8 status;
+	int ret;
+
+	/* Broken xD cards report WP despite being writable */
+	if (chip->options & NAND_BROKEN_XD)
+		return 0;
+
+	/* Check the WP bit */
+	ret = nand_status_op(chip, &status);
+	if (ret)
+		return ret;
+
+	return status & NAND_STATUS_WP ? 0 : 1;
+}
+
+/**
+ * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * Check if the block is marked as reserved.
+ */
+static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (!chip->bbt)
+		return 0;
+	/* Return info from the table */
+	return nand_isreserved_bbt(mtd, ofs);
+}
+
+/**
+ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ * @allowbbt: 1, if its allowed to access the bbt area
+ *
+ * Check, if the block is bad. Either by reading the bad block table or
+ * calling of the scan function.
+ */
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (!chip->bbt)
+		return chip->block_bad(mtd, ofs);
+
+	/* Return info from the table */
+	return nand_isbad_bbt(mtd, ofs, allowbbt);
+}
+
+/**
+ * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout
+ *
+ * Helper function for nand_wait_ready used when needing to wait in interrupt
+ * context.
+ */
+static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int i;
+
+	/* Wait for the device to get ready */
+	for (i = 0; i < timeo; i++) {
+		if (chip->dev_ready(mtd))
+			break;
+		touch_softlockup_watchdog();
+		mdelay(1);
+	}
+}
+
+/**
+ * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @mtd: MTD device structure
+ *
+ * Wait for the ready pin after a command, and warn if a timeout occurs.
+ */
+void nand_wait_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	unsigned long timeo = 400;
+
+	if (in_interrupt() || oops_in_progress)
+		return panic_nand_wait_ready(mtd, timeo);
+
+	/* Wait until command is processed or timeout occurs */
+	timeo = jiffies + msecs_to_jiffies(timeo);
+	do {
+		if (chip->dev_ready(mtd))
+			return;
+		cond_resched();
+	} while (time_before(jiffies, timeo));
+
+	if (!chip->dev_ready(mtd))
+		pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+}
+EXPORT_SYMBOL_GPL(nand_wait_ready);
+
+/**
+ * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout in ms
+ *
+ * Wait for status ready (i.e. command done) or timeout.
+ */
+static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+	register struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	timeo = jiffies + msecs_to_jiffies(timeo);
+	do {
+		u8 status;
+
+		ret = nand_read_data_op(chip, &status, sizeof(status), true);
+		if (ret)
+			return;
+
+		if (status & NAND_STATUS_READY)
+			break;
+		touch_softlockup_watchdog();
+	} while (time_before(jiffies, timeo));
+};
+
+/**
+ * nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1
+ * @chip: NAND chip structure
+ * @timeout_ms: Timeout in ms
+ *
+ * Poll the STATUS register using ->exec_op() until the RDY bit becomes 1.
+ * If that does not happen whitin the specified timeout, -ETIMEDOUT is
+ * returned.
+ *
+ * This helper is intended to be used when the controller does not have access
+ * to the NAND R/B pin.
+ *
+ * Be aware that calling this helper from an ->exec_op() implementation means
+ * ->exec_op() must be re-entrant.
+ *
+ * Return 0 if the NAND chip is ready, a negative error otherwise.
+ */
+int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
+{
+	u8 status = 0;
+	int ret;
+
+	if (!chip->exec_op)
+		return -ENOTSUPP;
+
+	ret = nand_status_op(chip, NULL);
+	if (ret)
+		return ret;
+
+	timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
+	do {
+		ret = nand_read_data_op(chip, &status, sizeof(status), true);
+		if (ret)
+			break;
+
+		if (status & NAND_STATUS_READY)
+			break;
+
+		/*
+		 * Typical lowest execution time for a tR on most NANDs is 10us,
+		 * use this as polling delay before doing something smarter (ie.
+		 * deriving a delay from the timeout value, timeout_ms/ratio).
+		 */
+		udelay(10);
+	} while	(time_before(jiffies, timeout_ms));
+
+	/*
+	 * We have to exit READ_STATUS mode in order to read real data on the
+	 * bus in case the WAITRDY instruction is preceding a DATA_IN
+	 * instruction.
+	 */
+	nand_exit_status_op(chip);
+
+	if (ret)
+		return ret;
+
+	return status & NAND_STATUS_READY ? 0 : -ETIMEDOUT;
+};
+EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
+
+/**
+ * nand_command - [DEFAULT] Send command to NAND device
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This function is used for small page devices
+ * (512 Bytes per page).
+ */
+static void nand_command(struct mtd_info *mtd, unsigned int command,
+			 int column, int page_addr)
+{
+	register struct nand_chip *chip = mtd_to_nand(mtd);
+	int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+
+	/* Write out the command to the device */
+	if (command == NAND_CMD_SEQIN) {
+		int readcmd;
+
+		if (column >= mtd->writesize) {
+			/* OOB area */
+			column -= mtd->writesize;
+			readcmd = NAND_CMD_READOOB;
+		} else if (column < 256) {
+			/* First 256 bytes --> READ0 */
+			readcmd = NAND_CMD_READ0;
+		} else {
+			column -= 256;
+			readcmd = NAND_CMD_READ1;
+		}
+		chip->cmd_ctrl(mtd, readcmd, ctrl);
+		ctrl &= ~NAND_CTRL_CHANGE;
+	}
+	if (command != NAND_CMD_NONE)
+		chip->cmd_ctrl(mtd, command, ctrl);
+
+	/* Address cycle, when necessary */
+	ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
+	/* Serially input address */
+	if (column != -1) {
+		/* Adjust columns for 16 bit buswidth */
+		if (chip->options & NAND_BUSWIDTH_16 &&
+				!nand_opcode_8bits(command))
+			column >>= 1;
+		chip->cmd_ctrl(mtd, column, ctrl);
+		ctrl &= ~NAND_CTRL_CHANGE;
+	}
+	if (page_addr != -1) {
+		chip->cmd_ctrl(mtd, page_addr, ctrl);
+		ctrl &= ~NAND_CTRL_CHANGE;
+		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
+		if (chip->options & NAND_ROW_ADDR_3)
+			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
+	}
+	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	/*
+	 * Program and erase have their own busy handlers status and sequential
+	 * in needs no delay
+	 */
+	switch (command) {
+
+	case NAND_CMD_NONE:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_READID:
+	case NAND_CMD_SET_FEATURES:
+		return;
+
+	case NAND_CMD_RESET:
+		if (chip->dev_ready)
+			break;
+		udelay(chip->chip_delay);
+		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+			       NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+		chip->cmd_ctrl(mtd,
+			       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+		nand_wait_status_ready(mtd, 250);
+		return;
+
+		/* This applies to read commands */
+	case NAND_CMD_READ0:
+		/*
+		 * READ0 is sometimes used to exit GET STATUS mode. When this
+		 * is the case no address cycles are requested, and we can use
+		 * this information to detect that we should not wait for the
+		 * device to be ready.
+		 */
+		if (column == -1 && page_addr == -1)
+			return;
+
+	default:
+		/*
+		 * If we don't have access to the busy pin, we apply the given
+		 * command delay
+		 */
+		if (!chip->dev_ready) {
+			udelay(chip->chip_delay);
+			return;
+		}
+	}
+	/*
+	 * Apply this short delay always to ensure that we do wait tWB in
+	 * any case on any machine.
+	 */
+	ndelay(100);
+
+	nand_wait_ready(mtd);
+}
+
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+	/*
+	 * The controller already takes care of waiting for tCCS when the RNDIN
+	 * or RNDOUT command is sent, return directly.
+	 */
+	if (!(chip->options & NAND_WAIT_TCCS))
+		return;
+
+	/*
+	 * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+	 * (which should be safe for all NANDs).
+	 */
+	if (chip->setup_data_interface)
+		ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
+	else
+		ndelay(500);
+}
+
+/**
+ * nand_command_lp - [DEFAULT] Send command to NAND large page device
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page
+ * devices. We don't have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+ */
+static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
+			    int column, int page_addr)
+{
+	register struct nand_chip *chip = mtd_to_nand(mtd);
+
+	/* Emulate NAND_CMD_READOOB */
+	if (command == NAND_CMD_READOOB) {
+		column += mtd->writesize;
+		command = NAND_CMD_READ0;
+	}
+
+	/* Command latch cycle */
+	if (command != NAND_CMD_NONE)
+		chip->cmd_ctrl(mtd, command,
+			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+	if (column != -1 || page_addr != -1) {
+		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+		/* Serially input address */
+		if (column != -1) {
+			/* Adjust columns for 16 bit buswidth */
+			if (chip->options & NAND_BUSWIDTH_16 &&
+					!nand_opcode_8bits(command))
+				column >>= 1;
+			chip->cmd_ctrl(mtd, column, ctrl);
+			ctrl &= ~NAND_CTRL_CHANGE;
+
+			/* Only output a single addr cycle for 8bits opcodes. */
+			if (!nand_opcode_8bits(command))
+				chip->cmd_ctrl(mtd, column >> 8, ctrl);
+		}
+		if (page_addr != -1) {
+			chip->cmd_ctrl(mtd, page_addr, ctrl);
+			chip->cmd_ctrl(mtd, page_addr >> 8,
+				       NAND_NCE | NAND_ALE);
+			if (chip->options & NAND_ROW_ADDR_3)
+				chip->cmd_ctrl(mtd, page_addr >> 16,
+					       NAND_NCE | NAND_ALE);
+		}
+	}
+	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+	/*
+	 * Program and erase have their own busy handlers status, sequential
+	 * in and status need no delay.
+	 */
+	switch (command) {
+
+	case NAND_CMD_NONE:
+	case NAND_CMD_CACHEDPROG:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_READID:
+	case NAND_CMD_SET_FEATURES:
+		return;
+
+	case NAND_CMD_RNDIN:
+		nand_ccs_delay(chip);
+		return;
+
+	case NAND_CMD_RESET:
+		if (chip->dev_ready)
+			break;
+		udelay(chip->chip_delay);
+		chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+			       NAND_NCE | NAND_CTRL_CHANGE);
+		/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+		nand_wait_status_ready(mtd, 250);
+		return;
+
+	case NAND_CMD_RNDOUT:
+		/* No ready / busy check necessary */
+		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
+			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+			       NAND_NCE | NAND_CTRL_CHANGE);
+
+		nand_ccs_delay(chip);
+		return;
+
+	case NAND_CMD_READ0:
+		/*
+		 * READ0 is sometimes used to exit GET STATUS mode. When this
+		 * is the case no address cycles are requested, and we can use
+		 * this information to detect that READSTART should not be
+		 * issued.
+		 */
+		if (column == -1 && page_addr == -1)
+			return;
+
+		chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
+			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+			       NAND_NCE | NAND_CTRL_CHANGE);
+
+		/* This applies to read commands */
+	default:
+		/*
+		 * If we don't have access to the busy pin, we apply the given
+		 * command delay.
+		 */
+		if (!chip->dev_ready) {
+			udelay(chip->chip_delay);
+			return;
+		}
+	}
+
+	/*
+	 * Apply this short delay always to ensure that we do wait tWB in
+	 * any case on any machine.
+	 */
+	ndelay(100);
+
+	nand_wait_ready(mtd);
+}
+
+/**
+ * panic_nand_get_device - [GENERIC] Get chip for selected access
+ * @chip: the nand chip descriptor
+ * @mtd: MTD device structure
+ * @new_state: the state which is requested
+ *
+ * Used when in panic, no locks are taken.
+ */
+static void panic_nand_get_device(struct nand_chip *chip,
+		      struct mtd_info *mtd, int new_state)
+{
+	/* Hardware controller shared among independent devices */
+	chip->controller->active = chip;
+	chip->state = new_state;
+}
+
+/**
+ * nand_get_device - [GENERIC] Get chip for selected access
+ * @mtd: MTD device structure
+ * @new_state: the state which is requested
+ *
+ * Get the device and lock it for exclusive access
+ */
+static int
+nand_get_device(struct mtd_info *mtd, int new_state)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	spinlock_t *lock = &chip->controller->lock;
+	wait_queue_head_t *wq = &chip->controller->wq;
+	DECLARE_WAITQUEUE(wait, current);
+retry:
+	spin_lock(lock);
+
+	/* Hardware controller shared among independent devices */
+	if (!chip->controller->active)
+		chip->controller->active = chip;
+
+	if (chip->controller->active == chip && chip->state == FL_READY) {
+		chip->state = new_state;
+		spin_unlock(lock);
+		return 0;
+	}
+	if (new_state == FL_PM_SUSPENDED) {
+		if (chip->controller->active->state == FL_PM_SUSPENDED) {
+			chip->state = FL_PM_SUSPENDED;
+			spin_unlock(lock);
+			return 0;
+		}
+	}
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(wq, &wait);
+	spin_unlock(lock);
+	schedule();
+	remove_wait_queue(wq, &wait);
+	goto retry;
+}
+
+/**
+ * panic_nand_wait - [GENERIC] wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ * @timeo: timeout
+ *
+ * Wait for command done. This is a helper function for nand_wait used when
+ * we are in interrupt context. May happen when in panic and trying to write
+ * an oops through mtdoops.
+ */
+static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
+			    unsigned long timeo)
+{
+	int i;
+	for (i = 0; i < timeo; i++) {
+		if (chip->dev_ready) {
+			if (chip->dev_ready(mtd))
+				break;
+		} else {
+			int ret;
+			u8 status;
+
+			ret = nand_read_data_op(chip, &status, sizeof(status),
+						true);
+			if (ret)
+				return;
+
+			if (status & NAND_STATUS_READY)
+				break;
+		}
+		mdelay(1);
+	}
+}
+
+/**
+ * nand_wait - [DEFAULT] wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for command done. This applies to erase and program only.
+ */
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+
+	unsigned long timeo = 400;
+	u8 status;
+	int ret;
+
+	/*
+	 * Apply this short delay always to ensure that we do wait tWB in any
+	 * case on any machine.
+	 */
+	ndelay(100);
+
+	ret = nand_status_op(chip, NULL);
+	if (ret)
+		return ret;
+
+	if (in_interrupt() || oops_in_progress)
+		panic_nand_wait(mtd, chip, timeo);
+	else {
+		timeo = jiffies + msecs_to_jiffies(timeo);
+		do {
+			if (chip->dev_ready) {
+				if (chip->dev_ready(mtd))
+					break;
+			} else {
+				ret = nand_read_data_op(chip, &status,
+							sizeof(status), true);
+				if (ret)
+					return ret;
+
+				if (status & NAND_STATUS_READY)
+					break;
+			}
+			cond_resched();
+		} while (time_before(jiffies, timeo));
+	}
+
+	ret = nand_read_data_op(chip, &status, sizeof(status), true);
+	if (ret)
+		return ret;
+
+	/* This can happen if in case of timeout or buggy dev_ready */
+	WARN_ON(!(status & NAND_STATUS_READY));
+	return status;
+}
+
+/**
+ * nand_reset_data_interface - Reset data interface and timings
+ * @chip: The NAND chip
+ * @chipnr: Internal die id
+ *
+ * Reset the Data interface and timings to ONFI mode 0.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	if (!chip->setup_data_interface)
+		return 0;
+
+	/*
+	 * The ONFI specification says:
+	 * "
+	 * To transition from NV-DDR or NV-DDR2 to the SDR data
+	 * interface, the host shall use the Reset (FFh) command
+	 * using SDR timing mode 0. A device in any timing mode is
+	 * required to recognize Reset (FFh) command issued in SDR
+	 * timing mode 0.
+	 * "
+	 *
+	 * Configure the data interface in SDR mode and set the
+	 * timings to timing mode 0.
+	 */
+
+	onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
+	ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+	if (ret)
+		pr_err("Failed to configure data interface to SDR timing mode 0\n");
+
+	return ret;
+}
+
+/**
+ * nand_setup_data_interface - Setup the best data interface and timings
+ * @chip: The NAND chip
+ * @chipnr: Internal die id
+ *
+ * Find and configure the best data interface and NAND timings supported by
+ * the chip and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	if (!chip->setup_data_interface)
+		return 0;
+
+	/*
+	 * Ensure the timing mode has been changed on the chip side
+	 * before changing timings on the controller side.
+	 */
+	if (chip->onfi_version &&
+	    (le16_to_cpu(chip->onfi_params.opt_cmd) &
+	     ONFI_OPT_CMD_SET_GET_FEATURES)) {
+		u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
+			chip->onfi_timing_mode_default,
+		};
+
+		ret = chip->onfi_set_features(mtd, chip,
+				ONFI_FEATURE_ADDR_TIMING_MODE,
+				tmode_param);
+		if (ret)
+			goto err;
+	}
+
+	ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+err:
+	return ret;
+}
+
+/**
+ * nand_init_data_interface - find the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find the best data interface and NAND timings supported by the chip
+ * and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table. After this
+ * function nand_chip->data_interface is initialized with the best timing mode
+ * available.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_init_data_interface(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int modes, mode, ret;
+
+	if (!chip->setup_data_interface)
+		return 0;
+
+	/*
+	 * First try to identify the best timings from ONFI parameters and
+	 * if the NAND does not support ONFI, fallback to the default ONFI
+	 * timing mode.
+	 */
+	modes = onfi_get_async_timing_mode(chip);
+	if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+		if (!chip->onfi_timing_mode_default)
+			return 0;
+
+		modes = GENMASK(chip->onfi_timing_mode_default, 0);
+	}
+
+
+	for (mode = fls(modes) - 1; mode >= 0; mode--) {
+		ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
+		if (ret)
+			continue;
+
+		/*
+		 * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
+		 * controller supports the requested timings.
+		 */
+		ret = chip->setup_data_interface(mtd,
+						 NAND_DATA_IFACE_CHECK_ONLY,
+						 &chip->data_interface);
+		if (!ret) {
+			chip->onfi_timing_mode_default = mode;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * nand_fill_column_cycles - fill the column cycles of an address
+ * @chip: The NAND chip
+ * @addrs: Array of address cycles to fill
+ * @offset_in_page: The offset in the page
+ *
+ * Fills the first or the first two bytes of the @addrs field depending
+ * on the NAND bus width and the page size.
+ *
+ * Returns the number of cycles needed to encode the column, or a negative
+ * error code in case one of the arguments is invalid.
+ */
+static int nand_fill_column_cycles(struct nand_chip *chip, u8 *addrs,
+				   unsigned int offset_in_page)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	/* Make sure the offset is less than the actual page size. */
+	if (offset_in_page > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	/*
+	 * On small page NANDs, there's a dedicated command to access the OOB
+	 * area, and the column address is relative to the start of the OOB
+	 * area, not the start of the page. Asjust the address accordingly.
+	 */
+	if (mtd->writesize <= 512 && offset_in_page >= mtd->writesize)
+		offset_in_page -= mtd->writesize;
+
+	/*
+	 * The offset in page is expressed in bytes, if the NAND bus is 16-bit
+	 * wide, then it must be divided by 2.
+	 */
+	if (chip->options & NAND_BUSWIDTH_16) {
+		if (WARN_ON(offset_in_page % 2))
+			return -EINVAL;
+
+		offset_in_page /= 2;
+	}
+
+	addrs[0] = offset_in_page;
+
+	/*
+	 * Small page NANDs use 1 cycle for the columns, while large page NANDs
+	 * need 2
+	 */
+	if (mtd->writesize <= 512)
+		return 1;
+
+	addrs[1] = offset_in_page >> 8;
+
+	return 2;
+}
+
+static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
+				     unsigned int offset_in_page, void *buf,
+				     unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_sdr_timings *sdr =
+		nand_get_sdr_timings(&chip->data_interface);
+	u8 addrs[4];
+	struct nand_op_instr instrs[] = {
+		NAND_OP_CMD(NAND_CMD_READ0, 0),
+		NAND_OP_ADDR(3, addrs, PSEC_TO_NSEC(sdr->tWB_max)),
+		NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
+				 PSEC_TO_NSEC(sdr->tRR_min)),
+		NAND_OP_DATA_IN(len, buf, 0),
+	};
+	struct nand_operation op = NAND_OPERATION(instrs);
+	int ret;
+
+	/* Drop the DATA_IN instruction if len is set to 0. */
+	if (!len)
+		op.ninstrs--;
+
+	if (offset_in_page >= mtd->writesize)
+		instrs[0].ctx.cmd.opcode = NAND_CMD_READOOB;
+	else if (offset_in_page >= 256 &&
+		 !(chip->options & NAND_BUSWIDTH_16))
+		instrs[0].ctx.cmd.opcode = NAND_CMD_READ1;
+
+	ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
+	if (ret < 0)
+		return ret;
+
+	addrs[1] = page;
+	addrs[2] = page >> 8;
+
+	if (chip->options & NAND_ROW_ADDR_3) {
+		addrs[3] = page >> 16;
+		instrs[1].ctx.addr.naddrs++;
+	}
+
+	return nand_exec_op(chip, &op);
+}
+
+static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
+				     unsigned int offset_in_page, void *buf,
+				     unsigned int len)
+{
+	const struct nand_sdr_timings *sdr =
+		nand_get_sdr_timings(&chip->data_interface);
+	u8 addrs[5];
+	struct nand_op_instr instrs[] = {
+		NAND_OP_CMD(NAND_CMD_READ0, 0),
+		NAND_OP_ADDR(4, addrs, 0),
+		NAND_OP_CMD(NAND_CMD_READSTART, PSEC_TO_NSEC(sdr->tWB_max)),
+		NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
+				 PSEC_TO_NSEC(sdr->tRR_min)),
+		NAND_OP_DATA_IN(len, buf, 0),
+	};
+	struct nand_operation op = NAND_OPERATION(instrs);
+	int ret;
+
+	/* Drop the DATA_IN instruction if len is set to 0. */
+	if (!len)
+		op.ninstrs--;
+
+	ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
+	if (ret < 0)
+		return ret;
+
+	addrs[2] = page;
+	addrs[3] = page >> 8;
+
+	if (chip->options & NAND_ROW_ADDR_3) {
+		addrs[4] = page >> 16;
+		instrs[1].ctx.addr.naddrs++;
+	}
+
+	return nand_exec_op(chip, &op);
+}
+
+/**
+ * nand_read_page_op - Do a READ PAGE operation
+ * @chip: The NAND chip
+ * @page: page to read
+ * @offset_in_page: offset within the page
+ * @buf: buffer used to store the data
+ * @len: length of the buffer
+ *
+ * This function issues a READ PAGE operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_read_page_op(struct nand_chip *chip, unsigned int page,
+		      unsigned int offset_in_page, void *buf, unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	if (chip->exec_op) {
+		if (mtd->writesize > 512)
+			return nand_lp_exec_read_page_op(chip, page,
+							 offset_in_page, buf,
+							 len);
+
+		return nand_sp_exec_read_page_op(chip, page, offset_in_page,
+						 buf, len);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
+	if (len)
+		chip->read_buf(mtd, buf, len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_read_page_op);
+
+/**
+ * nand_read_param_page_op - Do a READ PARAMETER PAGE operation
+ * @chip: The NAND chip
+ * @page: parameter page to read
+ * @buf: buffer used to store the data
+ * @len: length of the buffer
+ *
+ * This function issues a READ PARAMETER PAGE operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+				   unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int i;
+	u8 *p = buf;
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_PARAM, 0),
+			NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)),
+			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
+					 PSEC_TO_NSEC(sdr->tRR_min)),
+			NAND_OP_8BIT_DATA_IN(len, buf, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		/* Drop the DATA_IN instruction if len is set to 0. */
+		if (!len)
+			op.ninstrs--;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
+	for (i = 0; i < len; i++)
+		p[i] = chip->read_byte(mtd);
+
+	return 0;
+}
+
+/**
+ * nand_change_read_column_op - Do a CHANGE READ COLUMN operation
+ * @chip: The NAND chip
+ * @offset_in_page: offset within the page
+ * @buf: buffer used to store the data
+ * @len: length of the buffer
+ * @force_8bit: force 8-bit bus access
+ *
+ * This function issues a CHANGE READ COLUMN operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_change_read_column_op(struct nand_chip *chip,
+			       unsigned int offset_in_page, void *buf,
+			       unsigned int len, bool force_8bit)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	/* Small page NANDs do not support column change. */
+	if (mtd->writesize <= 512)
+		return -ENOTSUPP;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		u8 addrs[2] = {};
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_RNDOUT, 0),
+			NAND_OP_ADDR(2, addrs, 0),
+			NAND_OP_CMD(NAND_CMD_RNDOUTSTART,
+				    PSEC_TO_NSEC(sdr->tCCS_min)),
+			NAND_OP_DATA_IN(len, buf, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+		int ret;
+
+		ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
+		if (ret < 0)
+			return ret;
+
+		/* Drop the DATA_IN instruction if len is set to 0. */
+		if (!len)
+			op.ninstrs--;
+
+		instrs[3].ctx.data.force_8bit = force_8bit;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
+	if (len)
+		chip->read_buf(mtd, buf, len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_change_read_column_op);
+
+/**
+ * nand_read_oob_op - Do a READ OOB operation
+ * @chip: The NAND chip
+ * @page: page to read
+ * @offset_in_oob: offset within the OOB area
+ * @buf: buffer used to store the data
+ * @len: length of the buffer
+ *
+ * This function issues a READ OOB operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
+		     unsigned int offset_in_oob, void *buf, unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (offset_in_oob + len > mtd->oobsize)
+		return -EINVAL;
+
+	if (chip->exec_op)
+		return nand_read_page_op(chip, page,
+					 mtd->writesize + offset_in_oob,
+					 buf, len);
+
+	chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
+	if (len)
+		chip->read_buf(mtd, buf, len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_read_oob_op);
+
+static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
+				  unsigned int offset_in_page, const void *buf,
+				  unsigned int len, bool prog)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_sdr_timings *sdr =
+		nand_get_sdr_timings(&chip->data_interface);
+	u8 addrs[5] = {};
+	struct nand_op_instr instrs[] = {
+		/*
+		 * The first instruction will be dropped if we're dealing
+		 * with a large page NAND and adjusted if we're dealing
+		 * with a small page NAND and the page offset is > 255.
+		 */
+		NAND_OP_CMD(NAND_CMD_READ0, 0),
+		NAND_OP_CMD(NAND_CMD_SEQIN, 0),
+		NAND_OP_ADDR(0, addrs, PSEC_TO_NSEC(sdr->tADL_min)),
+		NAND_OP_DATA_OUT(len, buf, 0),
+		NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)),
+		NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
+	};
+	struct nand_operation op = NAND_OPERATION(instrs);
+	int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
+	int ret;
+	u8 status;
+
+	if (naddrs < 0)
+		return naddrs;
+
+	addrs[naddrs++] = page;
+	addrs[naddrs++] = page >> 8;
+	if (chip->options & NAND_ROW_ADDR_3)
+		addrs[naddrs++] = page >> 16;
+
+	instrs[2].ctx.addr.naddrs = naddrs;
+
+	/* Drop the last two instructions if we're not programming the page. */
+	if (!prog) {
+		op.ninstrs -= 2;
+		/* Also drop the DATA_OUT instruction if empty. */
+		if (!len)
+			op.ninstrs--;
+	}
+
+	if (mtd->writesize <= 512) {
+		/*
+		 * Small pages need some more tweaking: we have to adjust the
+		 * first instruction depending on the page offset we're trying
+		 * to access.
+		 */
+		if (offset_in_page >= mtd->writesize)
+			instrs[0].ctx.cmd.opcode = NAND_CMD_READOOB;
+		else if (offset_in_page >= 256 &&
+			 !(chip->options & NAND_BUSWIDTH_16))
+			instrs[0].ctx.cmd.opcode = NAND_CMD_READ1;
+	} else {
+		/*
+		 * Drop the first command if we're dealing with a large page
+		 * NAND.
+		 */
+		op.instrs++;
+		op.ninstrs--;
+	}
+
+	ret = nand_exec_op(chip, &op);
+	if (!prog || ret)
+		return ret;
+
+	ret = nand_status_op(chip, &status);
+	if (ret)
+		return ret;
+
+	return status;
+}
+
+/**
+ * nand_prog_page_begin_op - starts a PROG PAGE operation
+ * @chip: The NAND chip
+ * @page: page to write
+ * @offset_in_page: offset within the page
+ * @buf: buffer containing the data to write to the page
+ * @len: length of the buffer
+ *
+ * This function issues the first half of a PROG PAGE operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
+			    unsigned int offset_in_page, const void *buf,
+			    unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	if (chip->exec_op)
+		return nand_exec_prog_page_op(chip, page, offset_in_page, buf,
+					      len, false);
+
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
+
+	if (buf)
+		chip->write_buf(mtd, buf, len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
+
+/**
+ * nand_prog_page_end_op - ends a PROG PAGE operation
+ * @chip: The NAND chip
+ *
+ * This function issues the second half of a PROG PAGE operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_prog_page_end_op(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+	u8 status;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_PAGEPROG,
+				    PSEC_TO_NSEC(sdr->tWB_max)),
+			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		ret = nand_exec_op(chip, &op);
+		if (ret)
+			return ret;
+
+		ret = nand_status_op(chip, &status);
+		if (ret)
+			return ret;
+	} else {
+		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+		ret = chip->waitfunc(mtd, chip);
+		if (ret < 0)
+			return ret;
+
+		status = ret;
+	}
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_prog_page_end_op);
+
+/**
+ * nand_prog_page_op - Do a full PROG PAGE operation
+ * @chip: The NAND chip
+ * @page: page to write
+ * @offset_in_page: offset within the page
+ * @buf: buffer containing the data to write to the page
+ * @len: length of the buffer
+ *
+ * This function issues a full PROG PAGE operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
+		      unsigned int offset_in_page, const void *buf,
+		      unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int status;
+
+	if (!len || !buf)
+		return -EINVAL;
+
+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	if (chip->exec_op) {
+		status = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
+						len, true);
+	} else {
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
+		chip->write_buf(mtd, buf, len);
+		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+		status = chip->waitfunc(mtd, chip);
+	}
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_prog_page_op);
+
+/**
+ * nand_change_write_column_op - Do a CHANGE WRITE COLUMN operation
+ * @chip: The NAND chip
+ * @offset_in_page: offset within the page
+ * @buf: buffer containing the data to send to the NAND
+ * @len: length of the buffer
+ * @force_8bit: force 8-bit bus access
+ *
+ * This function issues a CHANGE WRITE COLUMN operation.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_change_write_column_op(struct nand_chip *chip,
+				unsigned int offset_in_page,
+				const void *buf, unsigned int len,
+				bool force_8bit)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (offset_in_page + len > mtd->writesize + mtd->oobsize)
+		return -EINVAL;
+
+	/* Small page NANDs do not support column change. */
+	if (mtd->writesize <= 512)
+		return -ENOTSUPP;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		u8 addrs[2];
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_RNDIN, 0),
+			NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)),
+			NAND_OP_DATA_OUT(len, buf, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+		int ret;
+
+		ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
+		if (ret < 0)
+			return ret;
+
+		instrs[2].ctx.data.force_8bit = force_8bit;
+
+		/* Drop the DATA_OUT instruction if len is set to 0. */
+		if (!len)
+			op.ninstrs--;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
+	if (len)
+		chip->write_buf(mtd, buf, len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_change_write_column_op);
+
+/**
+ * nand_readid_op - Do a READID operation
+ * @chip: The NAND chip
+ * @addr: address cycle to pass after the READID command
+ * @buf: buffer used to store the ID
+ * @len: length of the buffer
+ *
+ * This function sends a READID command and reads back the ID returned by the
+ * NAND.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
+		   unsigned int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int i;
+	u8 *id = buf;
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_READID, 0),
+			NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)),
+			NAND_OP_8BIT_DATA_IN(len, buf, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		/* Drop the DATA_IN instruction if len is set to 0. */
+		if (!len)
+			op.ninstrs--;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
+
+	for (i = 0; i < len; i++)
+		id[i] = chip->read_byte(mtd);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_readid_op);
+
+/**
+ * nand_status_op - Do a STATUS operation
+ * @chip: The NAND chip
+ * @status: out variable to store the NAND status
+ *
+ * This function sends a STATUS command and reads back the status returned by
+ * the NAND.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_status_op(struct nand_chip *chip, u8 *status)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_STATUS,
+				    PSEC_TO_NSEC(sdr->tADL_min)),
+			NAND_OP_8BIT_DATA_IN(1, status, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		if (!status)
+			op.ninstrs--;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+	if (status)
+		*status = chip->read_byte(mtd);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_status_op);
+
+/**
+ * nand_exit_status_op - Exit a STATUS operation
+ * @chip: The NAND chip
+ *
+ * This function sends a READ0 command to cancel the effect of the STATUS
+ * command to avoid reading only the status until a new read command is sent.
+ *
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_exit_status_op(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (chip->exec_op) {
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_READ0, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_exit_status_op);
+
+/**
+ * nand_erase_op - Do an erase operation
+ * @chip: The NAND chip
+ * @eraseblock: block to erase
+ *
+ * This function sends an ERASE command and waits for the NAND to be ready
+ * before returning.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	unsigned int page = eraseblock <<
+			    (chip->phys_erase_shift - chip->page_shift);
+	int ret;
+	u8 status;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		u8 addrs[3] = {	page, page >> 8, page >> 16 };
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_ERASE1, 0),
+			NAND_OP_ADDR(2, addrs, 0),
+			NAND_OP_CMD(NAND_CMD_ERASE2,
+				    PSEC_TO_MSEC(sdr->tWB_max)),
+			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		if (chip->options & NAND_ROW_ADDR_3)
+			instrs[1].ctx.addr.naddrs++;
+
+		ret = nand_exec_op(chip, &op);
+		if (ret)
+			return ret;
+
+		ret = nand_status_op(chip, &status);
+		if (ret)
+			return ret;
+	} else {
+		chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+		chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+
+		ret = chip->waitfunc(mtd, chip);
+		if (ret < 0)
+			return ret;
+
+		status = ret;
+	}
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_erase_op);
+
+/**
+ * nand_set_features_op - Do a SET FEATURES operation
+ * @chip: The NAND chip
+ * @feature: feature id
+ * @data: 4 bytes of data
+ *
+ * This function sends a SET FEATURES command and waits for the NAND to be
+ * ready before returning.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int nand_set_features_op(struct nand_chip *chip, u8 feature,
+				const void *data)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const u8 *params = data;
+	int i, ret;
+	u8 status;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0),
+			NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)),
+			NAND_OP_8BIT_DATA_OUT(ONFI_SUBFEATURE_PARAM_LEN, data,
+					      PSEC_TO_NSEC(sdr->tWB_max)),
+			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		ret = nand_exec_op(chip, &op);
+		if (ret)
+			return ret;
+
+		ret = nand_status_op(chip, &status);
+		if (ret)
+			return ret;
+	} else {
+		chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
+		for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+			chip->write_byte(mtd, params[i]);
+
+		ret = chip->waitfunc(mtd, chip);
+		if (ret < 0)
+			return ret;
+
+		status = ret;
+	}
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * nand_get_features_op - Do a GET FEATURES operation
+ * @chip: The NAND chip
+ * @feature: feature id
+ * @data: 4 bytes of data
+ *
+ * This function sends a GET FEATURES command and waits for the NAND to be
+ * ready before returning.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int nand_get_features_op(struct nand_chip *chip, u8 feature,
+				void *data)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 *params = data;
+	int i;
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0),
+			NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)),
+			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max),
+					 PSEC_TO_NSEC(sdr->tRR_min)),
+			NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN,
+					     data, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
+	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+		params[i] = chip->read_byte(mtd);
+
+	return 0;
+}
+
+/**
+ * nand_reset_op - Do a reset operation
+ * @chip: The NAND chip
+ *
+ * This function sends a RESET command and waits for the NAND to be ready
+ * before returning.
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_reset_op(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (chip->exec_op) {
+		const struct nand_sdr_timings *sdr =
+			nand_get_sdr_timings(&chip->data_interface);
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)),
+			NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_reset_op);
+
+/**
+ * nand_read_data_op - Read data from the NAND
+ * @chip: The NAND chip
+ * @buf: buffer used to store the data
+ * @len: length of the buffer
+ * @force_8bit: force 8-bit bus access
+ *
+ * This function does a raw data read on the bus. Usually used after launching
+ * another NAND operation like nand_read_page_op().
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
+		      bool force_8bit)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (!len || !buf)
+		return -EINVAL;
+
+	if (chip->exec_op) {
+		struct nand_op_instr instrs[] = {
+			NAND_OP_DATA_IN(len, buf, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		instrs[0].ctx.data.force_8bit = force_8bit;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	if (force_8bit) {
+		u8 *p = buf;
+		unsigned int i;
+
+		for (i = 0; i < len; i++)
+			p[i] = chip->read_byte(mtd);
+	} else {
+		chip->read_buf(mtd, buf, len);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_read_data_op);
+
+/**
+ * nand_write_data_op - Write data from the NAND
+ * @chip: The NAND chip
+ * @buf: buffer containing the data to send on the bus
+ * @len: length of the buffer
+ * @force_8bit: force 8-bit bus access
+ *
+ * This function does a raw data write on the bus. Usually used after launching
+ * another NAND operation like nand_write_page_begin_op().
+ * This function does not select/unselect the CS line.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_write_data_op(struct nand_chip *chip, const void *buf,
+		       unsigned int len, bool force_8bit)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (!len || !buf)
+		return -EINVAL;
+
+	if (chip->exec_op) {
+		struct nand_op_instr instrs[] = {
+			NAND_OP_DATA_OUT(len, buf, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		instrs[0].ctx.data.force_8bit = force_8bit;
+
+		return nand_exec_op(chip, &op);
+	}
+
+	if (force_8bit) {
+		const u8 *p = buf;
+		unsigned int i;
+
+		for (i = 0; i < len; i++)
+			chip->write_byte(mtd, p[i]);
+	} else {
+		chip->write_buf(mtd, buf, len);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_write_data_op);
+
+/**
+ * struct nand_op_parser_ctx - Context used by the parser
+ * @instrs: array of all the instructions that must be addressed
+ * @ninstrs: length of the @instrs array
+ * @subop: Sub-operation to be passed to the NAND controller
+ *
+ * This structure is used by the core to split NAND operations into
+ * sub-operations that can be handled by the NAND controller.
+ */
+struct nand_op_parser_ctx {
+	const struct nand_op_instr *instrs;
+	unsigned int ninstrs;
+	struct nand_subop subop;
+};
+
+/**
+ * nand_op_parser_must_split_instr - Checks if an instruction must be split
+ * @pat: the parser pattern element that matches @instr
+ * @instr: pointer to the instruction to check
+ * @start_offset: this is an in/out parameter. If @instr has already been
+ *		  split, then @start_offset is the offset from which to start
+ *		  (either an address cycle or an offset in the data buffer).
+ *		  Conversely, if the function returns true (ie. instr must be
+ *		  split), this parameter is updated to point to the first
+ *		  data/address cycle that has not been taken care of.
+ *
+ * Some NAND controllers are limited and cannot send X address cycles with a
+ * unique operation, or cannot read/write more than Y bytes at the same time.
+ * In this case, split the instruction that does not fit in a single
+ * controller-operation into two or more chunks.
+ *
+ * Returns true if the instruction must be split, false otherwise.
+ * The @start_offset parameter is also updated to the offset at which the next
+ * bundle of instruction must start (if an address or a data instruction).
+ */
+static bool
+nand_op_parser_must_split_instr(const struct nand_op_parser_pattern_elem *pat,
+				const struct nand_op_instr *instr,
+				unsigned int *start_offset)
+{
+	switch (pat->type) {
+	case NAND_OP_ADDR_INSTR:
+		if (!pat->ctx.addr.maxcycles)
+			break;
+
+		if (instr->ctx.addr.naddrs - *start_offset >
+		    pat->ctx.addr.maxcycles) {
+			*start_offset += pat->ctx.addr.maxcycles;
+			return true;
+		}
+		break;
+
+	case NAND_OP_DATA_IN_INSTR:
+	case NAND_OP_DATA_OUT_INSTR:
+		if (!pat->ctx.data.maxlen)
+			break;
+
+		if (instr->ctx.data.len - *start_offset >
+		    pat->ctx.data.maxlen) {
+			*start_offset += pat->ctx.data.maxlen;
+			return true;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return false;
+}
+
+/**
+ * nand_op_parser_match_pat - Checks if a pattern matches the instructions
+ *			      remaining in the parser context
+ * @pat: the pattern to test
+ * @ctx: the parser context structure to match with the pattern @pat
+ *
+ * Check if @pat matches the set or a sub-set of instructions remaining in @ctx.
+ * Returns true if this is the case, false ortherwise. When true is returned,
+ * @ctx->subop is updated with the set of instructions to be passed to the
+ * controller driver.
+ */
+static bool
+nand_op_parser_match_pat(const struct nand_op_parser_pattern *pat,
+			 struct nand_op_parser_ctx *ctx)
+{
+	unsigned int instr_offset = ctx->subop.first_instr_start_off;
+	const struct nand_op_instr *end = ctx->instrs + ctx->ninstrs;
+	const struct nand_op_instr *instr = ctx->subop.instrs;
+	unsigned int i, ninstrs;
+
+	for (i = 0, ninstrs = 0; i < pat->nelems && instr < end; i++) {
+		/*
+		 * The pattern instruction does not match the operation
+		 * instruction. If the instruction is marked optional in the
+		 * pattern definition, we skip the pattern element and continue
+		 * to the next one. If the element is mandatory, there's no
+		 * match and we can return false directly.
+		 */
+		if (instr->type != pat->elems[i].type) {
+			if (!pat->elems[i].optional)
+				return false;
+
+			continue;
+		}
+
+		/*
+		 * Now check the pattern element constraints. If the pattern is
+		 * not able to handle the whole instruction in a single step,
+		 * we have to split it.
+		 * The last_instr_end_off value comes back updated to point to
+		 * the position where we have to split the instruction (the
+		 * start of the next subop chunk).
+		 */
+		if (nand_op_parser_must_split_instr(&pat->elems[i], instr,
+						    &instr_offset)) {
+			ninstrs++;
+			i++;
+			break;
+		}
+
+		instr++;
+		ninstrs++;
+		instr_offset = 0;
+	}
+
+	/*
+	 * This can happen if all instructions of a pattern are optional.
+	 * Still, if there's not at least one instruction handled by this
+	 * pattern, this is not a match, and we should try the next one (if
+	 * any).
+	 */
+	if (!ninstrs)
+		return false;
+
+	/*
+	 * We had a match on the pattern head, but the pattern may be longer
+	 * than the instructions we're asked to execute. We need to make sure
+	 * there's no mandatory elements in the pattern tail.
+	 */
+	for (; i < pat->nelems; i++) {
+		if (!pat->elems[i].optional)
+			return false;
+	}
+
+	/*
+	 * We have a match: update the subop structure accordingly and return
+	 * true.
+	 */
+	ctx->subop.ninstrs = ninstrs;
+	ctx->subop.last_instr_end_off = instr_offset;
+
+	return true;
+}
+
+#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
+static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
+{
+	const struct nand_op_instr *instr;
+	char *prefix = "      ";
+	unsigned int i;
+
+	pr_debug("executing subop:\n");
+
+	for (i = 0; i < ctx->ninstrs; i++) {
+		instr = &ctx->instrs[i];
+
+		if (instr == &ctx->subop.instrs[0])
+			prefix = "    ->";
+
+		switch (instr->type) {
+		case NAND_OP_CMD_INSTR:
+			pr_debug("%sCMD      [0x%02x]\n", prefix,
+				 instr->ctx.cmd.opcode);
+			break;
+		case NAND_OP_ADDR_INSTR:
+			pr_debug("%sADDR     [%d cyc: %*ph]\n", prefix,
+				 instr->ctx.addr.naddrs,
+				 instr->ctx.addr.naddrs < 64 ?
+				 instr->ctx.addr.naddrs : 64,
+				 instr->ctx.addr.addrs);
+			break;
+		case NAND_OP_DATA_IN_INSTR:
+			pr_debug("%sDATA_IN  [%d B%s]\n", prefix,
+				 instr->ctx.data.len,
+				 instr->ctx.data.force_8bit ?
+				 ", force 8-bit" : "");
+			break;
+		case NAND_OP_DATA_OUT_INSTR:
+			pr_debug("%sDATA_OUT [%d B%s]\n", prefix,
+				 instr->ctx.data.len,
+				 instr->ctx.data.force_8bit ?
+				 ", force 8-bit" : "");
+			break;
+		case NAND_OP_WAITRDY_INSTR:
+			pr_debug("%sWAITRDY  [max %d ms]\n", prefix,
+				 instr->ctx.waitrdy.timeout_ms);
+			break;
+		}
+
+		if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1])
+			prefix = "      ";
+	}
+}
+#else
+static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
+{
+	/* NOP */
+}
+#endif
+
+/**
+ * nand_op_parser_exec_op - exec_op parser
+ * @chip: the NAND chip
+ * @parser: patterns description provided by the controller driver
+ * @op: the NAND operation to address
+ * @check_only: when true, the function only checks if @op can be handled but
+ *		does not execute the operation
+ *
+ * Helper function designed to ease integration of NAND controller drivers that
+ * only support a limited set of instruction sequences. The supported sequences
+ * are described in @parser, and the framework takes care of splitting @op into
+ * multiple sub-operations (if required) and pass them back to the ->exec()
+ * callback of the matching pattern if @check_only is set to false.
+ *
+ * NAND controller drivers should call this function from their own ->exec_op()
+ * implementation.
+ *
+ * Returns 0 on success, a negative error code otherwise. A failure can be
+ * caused by an unsupported operation (none of the supported patterns is able
+ * to handle the requested operation), or an error returned by one of the
+ * matching pattern->exec() hook.
+ */
+int nand_op_parser_exec_op(struct nand_chip *chip,
+			   const struct nand_op_parser *parser,
+			   const struct nand_operation *op, bool check_only)
+{
+	struct nand_op_parser_ctx ctx = {
+		.subop.instrs = op->instrs,
+		.instrs = op->instrs,
+		.ninstrs = op->ninstrs,
+	};
+	unsigned int i;
+
+	while (ctx.subop.instrs < op->instrs + op->ninstrs) {
+		int ret;
+
+		for (i = 0; i < parser->npatterns; i++) {
+			const struct nand_op_parser_pattern *pattern;
+
+			pattern = &parser->patterns[i];
+			if (!nand_op_parser_match_pat(pattern, &ctx))
+				continue;
+
+			nand_op_parser_trace(&ctx);
+
+			if (check_only)
+				break;
+
+			ret = pattern->exec(chip, &ctx.subop);
+			if (ret)
+				return ret;
+
+			break;
+		}
+
+		if (i == parser->npatterns) {
+			pr_debug("->exec_op() parser: pattern not found!\n");
+			return -ENOTSUPP;
+		}
+
+		/*
+		 * Update the context structure by pointing to the start of the
+		 * next subop.
+		 */
+		ctx.subop.instrs = ctx.subop.instrs + ctx.subop.ninstrs;
+		if (ctx.subop.last_instr_end_off)
+			ctx.subop.instrs -= 1;
+
+		ctx.subop.first_instr_start_off = ctx.subop.last_instr_end_off;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_op_parser_exec_op);
+
+static bool nand_instr_is_data(const struct nand_op_instr *instr)
+{
+	return instr && (instr->type == NAND_OP_DATA_IN_INSTR ||
+			 instr->type == NAND_OP_DATA_OUT_INSTR);
+}
+
+static bool nand_subop_instr_is_valid(const struct nand_subop *subop,
+				      unsigned int instr_idx)
+{
+	return subop && instr_idx < subop->ninstrs;
+}
+
+static int nand_subop_get_start_off(const struct nand_subop *subop,
+				    unsigned int instr_idx)
+{
+	if (instr_idx)
+		return 0;
+
+	return subop->first_instr_start_off;
+}
+
+/**
+ * nand_subop_get_addr_start_off - Get the start offset in an address array
+ * @subop: The entire sub-operation
+ * @instr_idx: Index of the instruction inside the sub-operation
+ *
+ * During driver development, one could be tempted to directly use the
+ * ->addr.addrs field of address instructions. This is wrong as address
+ * instructions might be split.
+ *
+ * Given an address instruction, returns the offset of the first cycle to issue.
+ */
+int nand_subop_get_addr_start_off(const struct nand_subop *subop,
+				  unsigned int instr_idx)
+{
+	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
+	    subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
+		return -EINVAL;
+
+	return nand_subop_get_start_off(subop, instr_idx);
+}
+EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off);
+
+/**
+ * nand_subop_get_num_addr_cyc - Get the remaining address cycles to assert
+ * @subop: The entire sub-operation
+ * @instr_idx: Index of the instruction inside the sub-operation
+ *
+ * During driver development, one could be tempted to directly use the
+ * ->addr->naddrs field of a data instruction. This is wrong as instructions
+ * might be split.
+ *
+ * Given an address instruction, returns the number of address cycle to issue.
+ */
+int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
+				unsigned int instr_idx)
+{
+	int start_off, end_off;
+
+	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
+	    subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
+		return -EINVAL;
+
+	start_off = nand_subop_get_addr_start_off(subop, instr_idx);
+
+	if (instr_idx == subop->ninstrs - 1 &&
+	    subop->last_instr_end_off)
+		end_off = subop->last_instr_end_off;
+	else
+		end_off = subop->instrs[instr_idx].ctx.addr.naddrs;
+
+	return end_off - start_off;
+}
+EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc);
+
+/**
+ * nand_subop_get_data_start_off - Get the start offset in a data array
+ * @subop: The entire sub-operation
+ * @instr_idx: Index of the instruction inside the sub-operation
+ *
+ * During driver development, one could be tempted to directly use the
+ * ->data->buf.{in,out} field of data instructions. This is wrong as data
+ * instructions might be split.
+ *
+ * Given a data instruction, returns the offset to start from.
+ */
+int nand_subop_get_data_start_off(const struct nand_subop *subop,
+				  unsigned int instr_idx)
+{
+	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
+	    !nand_instr_is_data(&subop->instrs[instr_idx]))
+		return -EINVAL;
+
+	return nand_subop_get_start_off(subop, instr_idx);
+}
+EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off);
+
+/**
+ * nand_subop_get_data_len - Get the number of bytes to retrieve
+ * @subop: The entire sub-operation
+ * @instr_idx: Index of the instruction inside the sub-operation
+ *
+ * During driver development, one could be tempted to directly use the
+ * ->data->len field of a data instruction. This is wrong as data instructions
+ * might be split.
+ *
+ * Returns the length of the chunk of data to send/receive.
+ */
+int nand_subop_get_data_len(const struct nand_subop *subop,
+			    unsigned int instr_idx)
+{
+	int start_off = 0, end_off;
+
+	if (!nand_subop_instr_is_valid(subop, instr_idx) ||
+	    !nand_instr_is_data(&subop->instrs[instr_idx]))
+		return -EINVAL;
+
+	start_off = nand_subop_get_data_start_off(subop, instr_idx);
+
+	if (instr_idx == subop->ninstrs - 1 &&
+	    subop->last_instr_end_off)
+		end_off = subop->last_instr_end_off;
+	else
+		end_off = subop->instrs[instr_idx].ctx.data.len;
+
+	return end_off - start_off;
+}
+EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
+
+/**
+ * nand_reset - Reset and initialize a NAND device
+ * @chip: The NAND chip
+ * @chipnr: Internal die id
+ *
+ * Save the timings data structure, then apply SDR timings mode 0 (see
+ * nand_reset_data_interface for details), do the reset operation, and
+ * apply back the previous timings.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int nand_reset(struct nand_chip *chip, int chipnr)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_data_interface saved_data_intf = chip->data_interface;
+	int ret;
+
+	ret = nand_reset_data_interface(chip, chipnr);
+	if (ret)
+		return ret;
+
+	/*
+	 * The CS line has to be released before we can apply the new NAND
+	 * interface settings, hence this weird ->select_chip() dance.
+	 */
+	chip->select_chip(mtd, chipnr);
+	ret = nand_reset_op(chip);
+	chip->select_chip(mtd, -1);
+	if (ret)
+		return ret;
+
+	chip->select_chip(mtd, chipnr);
+	chip->data_interface = saved_data_intf;
+	ret = nand_setup_data_interface(chip, chipnr);
+	chip->select_chip(mtd, -1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_reset);
+
+/**
+ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
+ * @buf: buffer to test
+ * @len: buffer length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a buffer contains only 0xff, which means the underlying region
+ * has been erased and is ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region is not erased.
+ * Note: The logic of this function has been extracted from the memweight
+ * implementation, except that nand_check_erased_buf function exit before
+ * testing the whole buffer if the number of bitflips exceed the
+ * bitflips_threshold value.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold.
+ */
+static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
+{
+	const unsigned char *bitmap = buf;
+	int bitflips = 0;
+	int weight;
+
+	for (; len && ((uintptr_t)bitmap) % sizeof(long);
+	     len--, bitmap++) {
+		weight = hweight8(*bitmap);
+		bitflips += BITS_PER_BYTE - weight;
+		if (unlikely(bitflips > bitflips_threshold))
+			return -EBADMSG;
+	}
+
+	for (; len >= sizeof(long);
+	     len -= sizeof(long), bitmap += sizeof(long)) {
+		unsigned long d = *((unsigned long *)bitmap);
+		if (d == ~0UL)
+			continue;
+		weight = hweight_long(d);
+		bitflips += BITS_PER_LONG - weight;
+		if (unlikely(bitflips > bitflips_threshold))
+			return -EBADMSG;
+	}
+
+	for (; len > 0; len--, bitmap++) {
+		weight = hweight8(*bitmap);
+		bitflips += BITS_PER_BYTE - weight;
+		if (unlikely(bitflips > bitflips_threshold))
+			return -EBADMSG;
+	}
+
+	return bitflips;
+}
+
+/**
+ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
+ *				 0xff data
+ * @data: data buffer to test
+ * @datalen: data length
+ * @ecc: ECC buffer
+ * @ecclen: ECC length
+ * @extraoob: extra OOB buffer
+ * @extraooblen: extra OOB length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a data buffer and its associated ECC and OOB data contains only
+ * 0xff pattern, which means the underlying region has been erased and is
+ * ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region as not erased.
+ *
+ * Note:
+ * 1/ ECC algorithms are working on pre-defined block sizes which are usually
+ *    different from the NAND page size. When fixing bitflips, ECC engines will
+ *    report the number of errors per chunk, and the NAND core infrastructure
+ *    expect you to return the maximum number of bitflips for the whole page.
+ *    This is why you should always use this function on a single chunk and
+ *    not on the whole page. After checking each chunk you should update your
+ *    max_bitflips value accordingly.
+ * 2/ When checking for bitflips in erased pages you should not only check
+ *    the payload data but also their associated ECC data, because a user might
+ *    have programmed almost all bits to 1 but a few. In this case, we
+ *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
+ *    this case.
+ * 3/ The extraoob argument is optional, and should be used if some of your OOB
+ *    data are protected by the ECC engine.
+ *    It could also be used if you support subpages and want to attach some
+ *    extra OOB data to an ECC chunk.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold. In case of success, the passed buffers are filled with 0xff.
+ */
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+				void *ecc, int ecclen,
+				void *extraoob, int extraooblen,
+				int bitflips_threshold)
+{
+	int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
+
+	data_bitflips = nand_check_erased_buf(data, datalen,
+					      bitflips_threshold);
+	if (data_bitflips < 0)
+		return data_bitflips;
+
+	bitflips_threshold -= data_bitflips;
+
+	ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
+	if (ecc_bitflips < 0)
+		return ecc_bitflips;
+
+	bitflips_threshold -= ecc_bitflips;
+
+	extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
+						  bitflips_threshold);
+	if (extraoob_bitflips < 0)
+		return extraoob_bitflips;
+
+	if (data_bitflips)
+		memset(data, 0xff, datalen);
+
+	if (ecc_bitflips)
+		memset(ecc, 0xff, ecclen);
+
+	if (extraoob_bitflips)
+		memset(extraoob, 0xff, extraooblen);
+
+	return data_bitflips + ecc_bitflips + extraoob_bitflips;
+}
+EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
+
+/**
+ * nand_read_page_raw - [INTERN] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Not for syndrome calculating ECC controllers, which use a special oob layout.
+ */
+int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+		       uint8_t *buf, int oob_required, int page)
+{
+	int ret;
+
+	ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	if (ret)
+		return ret;
+
+	if (oob_required) {
+		ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
+					false);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(nand_read_page_raw);
+
+/**
+ * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * We need a special oob layout and handling even when OOB isn't used.
+ */
+static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
+				       struct nand_chip *chip, uint8_t *buf,
+				       int oob_required, int page)
+{
+	int eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	uint8_t *oob = chip->oob_poi;
+	int steps, size, ret;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (steps = chip->ecc.steps; steps > 0; steps--) {
+		ret = nand_read_data_op(chip, buf, eccsize, false);
+		if (ret)
+			return ret;
+
+		buf += eccsize;
+
+		if (chip->ecc.prepad) {
+			ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
+						false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.prepad;
+		}
+
+		ret = nand_read_data_op(chip, oob, eccbytes, false);
+		if (ret)
+			return ret;
+
+		oob += eccbytes;
+
+		if (chip->ecc.postpad) {
+			ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
+						false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.postpad;
+		}
+	}
+
+	size = mtd->oobsize - (oob - chip->oob_poi);
+	if (size) {
+		ret = nand_read_data_op(chip, oob, size, false);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ */
+static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	int i, eccsize = chip->ecc.size, ret;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	uint8_t *p = buf;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	uint8_t *ecc_code = chip->ecc.code_buf;
+	unsigned int max_bitflips = 0;
+
+	chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	eccsteps = chip->ecc.steps;
+	p = buf;
+
+	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		int stat;
+
+		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+	return max_bitflips;
+}
+
+/**
+ * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @data_offs: offset of requested data within the page
+ * @readlen: data length
+ * @bufpoi: buffer to store read data
+ * @page: page number to read
+ */
+static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
+			int page)
+{
+	int start_step, end_step, num_steps, ret;
+	uint8_t *p;
+	int data_col_addr, i, gaps = 0;
+	int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
+	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+	int index, section = 0;
+	unsigned int max_bitflips = 0;
+	struct mtd_oob_region oobregion = { };
+
+	/* Column address within the page aligned to ECC size (256bytes) */
+	start_step = data_offs / chip->ecc.size;
+	end_step = (data_offs + readlen - 1) / chip->ecc.size;
+	num_steps = end_step - start_step + 1;
+	index = start_step * chip->ecc.bytes;
+
+	/* Data size aligned to ECC ecc.size */
+	datafrag_len = num_steps * chip->ecc.size;
+	eccfrag_len = num_steps * chip->ecc.bytes;
+
+	data_col_addr = start_step * chip->ecc.size;
+	/* If we read not a page aligned data */
+	p = bufpoi + data_col_addr;
+	ret = nand_read_page_op(chip, page, data_col_addr, p, datafrag_len);
+	if (ret)
+		return ret;
+
+	/* Calculate ECC */
+	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
+		chip->ecc.calculate(mtd, p, &chip->ecc.calc_buf[i]);
+
+	/*
+	 * The performance is faster if we position offsets according to
+	 * ecc.pos. Let's make sure that there are no gaps in ECC positions.
+	 */
+	ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
+	if (ret)
+		return ret;
+
+	if (oobregion.length < eccfrag_len)
+		gaps = 1;
+
+	if (gaps) {
+		ret = nand_change_read_column_op(chip, mtd->writesize,
+						 chip->oob_poi, mtd->oobsize,
+						 false);
+		if (ret)
+			return ret;
+	} else {
+		/*
+		 * Send the command to read the particular ECC bytes take care
+		 * about buswidth alignment in read_buf.
+		 */
+		aligned_pos = oobregion.offset & ~(busw - 1);
+		aligned_len = eccfrag_len;
+		if (oobregion.offset & (busw - 1))
+			aligned_len++;
+		if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
+		    (busw - 1))
+			aligned_len++;
+
+		ret = nand_change_read_column_op(chip,
+						 mtd->writesize + aligned_pos,
+						 &chip->oob_poi[aligned_pos],
+						 aligned_len, false);
+		if (ret)
+			return ret;
+	}
+
+	ret = mtd_ooblayout_get_eccbytes(mtd, chip->ecc.code_buf,
+					 chip->oob_poi, index, eccfrag_len);
+	if (ret)
+		return ret;
+
+	p = bufpoi + data_col_addr;
+	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
+		int stat;
+
+		stat = chip->ecc.correct(mtd, p, &chip->ecc.code_buf[i],
+					 &chip->ecc.calc_buf[i]);
+		if (stat == -EBADMSG &&
+		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+			/* check for empty pages with bitflips */
+			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
+						&chip->ecc.code_buf[i],
+						chip->ecc.bytes,
+						NULL, 0,
+						chip->ecc.strength);
+		}
+
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+	return max_bitflips;
+}
+
+/**
+ * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Not for syndrome calculating ECC controllers which need a special oob layout.
+ */
+static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	int i, eccsize = chip->ecc.size, ret;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	uint8_t *p = buf;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	uint8_t *ecc_code = chip->ecc.code_buf;
+	unsigned int max_bitflips = 0;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+
+		ret = nand_read_data_op(chip, p, eccsize, false);
+		if (ret)
+			return ret;
+
+		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+	}
+
+	ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
+	if (ret)
+		return ret;
+
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	eccsteps = chip->ecc.steps;
+	p = buf;
+
+	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		int stat;
+
+		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+		if (stat == -EBADMSG &&
+		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+			/* check for empty pages with bitflips */
+			stat = nand_check_erased_ecc_chunk(p, eccsize,
+						&ecc_code[i], eccbytes,
+						NULL, 0,
+						chip->ecc.strength);
+		}
+
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+	return max_bitflips;
+}
+
+/**
+ * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Hardware ECC for large page chips, require OOB to be read first. For this
+ * ECC mode, the write_page method is re-used from ECC_HW. These methods
+ * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
+ * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
+ * the data area, by overwriting the NAND manufacturer bad block markings.
+ */
+static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+	int i, eccsize = chip->ecc.size, ret;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	uint8_t *p = buf;
+	uint8_t *ecc_code = chip->ecc.code_buf;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	unsigned int max_bitflips = 0;
+
+	/* Read the OOB area first */
+	ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
+	if (ret)
+		return ret;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		int stat;
+
+		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+
+		ret = nand_read_data_op(chip, p, eccsize, false);
+		if (ret)
+			return ret;
+
+		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+		if (stat == -EBADMSG &&
+		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+			/* check for empty pages with bitflips */
+			stat = nand_check_erased_ecc_chunk(p, eccsize,
+						&ecc_code[i], eccbytes,
+						NULL, 0,
+						chip->ecc.strength);
+		}
+
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+	return max_bitflips;
+}
+
+/**
+ * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * The hw generator calculates the error syndrome automatically. Therefore we
+ * need a special oob layout and handling.
+ */
+static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+				   uint8_t *buf, int oob_required, int page)
+{
+	int ret, i, eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
+	uint8_t *p = buf;
+	uint8_t *oob = chip->oob_poi;
+	unsigned int max_bitflips = 0;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		int stat;
+
+		chip->ecc.hwctl(mtd, NAND_ECC_READ);
+
+		ret = nand_read_data_op(chip, p, eccsize, false);
+		if (ret)
+			return ret;
+
+		if (chip->ecc.prepad) {
+			ret = nand_read_data_op(chip, oob, chip->ecc.prepad,
+						false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.prepad;
+		}
+
+		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+
+		ret = nand_read_data_op(chip, oob, eccbytes, false);
+		if (ret)
+			return ret;
+
+		stat = chip->ecc.correct(mtd, p, oob, NULL);
+
+		oob += eccbytes;
+
+		if (chip->ecc.postpad) {
+			ret = nand_read_data_op(chip, oob, chip->ecc.postpad,
+						false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.postpad;
+		}
+
+		if (stat == -EBADMSG &&
+		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
+			/* check for empty pages with bitflips */
+			stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
+							   oob - eccpadbytes,
+							   eccpadbytes,
+							   NULL, 0,
+							   chip->ecc.strength);
+		}
+
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+
+	/* Calculate remaining oob bytes */
+	i = mtd->oobsize - (oob - chip->oob_poi);
+	if (i) {
+		ret = nand_read_data_op(chip, oob, i, false);
+		if (ret)
+			return ret;
+	}
+
+	return max_bitflips;
+}
+
+/**
+ * nand_transfer_oob - [INTERN] Transfer oob to client buffer
+ * @mtd: mtd info structure
+ * @oob: oob destination address
+ * @ops: oob ops structure
+ * @len: size of oob to transfer
+ */
+static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
+				  struct mtd_oob_ops *ops, size_t len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	switch (ops->mode) {
+
+	case MTD_OPS_PLACE_OOB:
+	case MTD_OPS_RAW:
+		memcpy(oob, chip->oob_poi + ops->ooboffs, len);
+		return oob + len;
+
+	case MTD_OPS_AUTO_OOB:
+		ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
+						  ops->ooboffs, len);
+		BUG_ON(ret);
+		return oob + len;
+
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+/**
+ * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
+ * @mtd: MTD device structure
+ * @retry_mode: the retry mode to use
+ *
+ * Some vendors supply a special command to shift the Vt threshold, to be used
+ * when there are too many bitflips in a page (i.e., ECC error). After setting
+ * a new threshold, the host should retry reading the page.
+ */
+static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	pr_debug("setting READ RETRY mode %d\n", retry_mode);
+
+	if (retry_mode >= chip->read_retries)
+		return -EINVAL;
+
+	if (!chip->setup_read_retry)
+		return -EOPNOTSUPP;
+
+	return chip->setup_read_retry(mtd, retry_mode);
+}
+
+/**
+ * nand_do_read_ops - [INTERN] Read data with ECC
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob ops structure
+ *
+ * Internal function. Called with chip held.
+ */
+static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
+			    struct mtd_oob_ops *ops)
+{
+	int chipnr, page, realpage, col, bytes, aligned, oob_required;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret = 0;
+	uint32_t readlen = ops->len;
+	uint32_t oobreadlen = ops->ooblen;
+	uint32_t max_oobsize = mtd_oobavail(mtd, ops);
+
+	uint8_t *bufpoi, *oob, *buf;
+	int use_bufpoi;
+	unsigned int max_bitflips = 0;
+	int retry_mode = 0;
+	bool ecc_fail = false;
+
+	chipnr = (int)(from >> chip->chip_shift);
+	chip->select_chip(mtd, chipnr);
+
+	realpage = (int)(from >> chip->page_shift);
+	page = realpage & chip->pagemask;
+
+	col = (int)(from & (mtd->writesize - 1));
+
+	buf = ops->datbuf;
+	oob = ops->oobbuf;
+	oob_required = oob ? 1 : 0;
+
+	while (1) {
+		unsigned int ecc_failures = mtd->ecc_stats.failed;
+
+		bytes = min(mtd->writesize - col, readlen);
+		aligned = (bytes == mtd->writesize);
+
+		if (!aligned)
+			use_bufpoi = 1;
+		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+			use_bufpoi = !virt_addr_valid(buf) ||
+				     !IS_ALIGNED((unsigned long)buf,
+						 chip->buf_align);
+		else
+			use_bufpoi = 0;
+
+		/* Is the current page in the buffer? */
+		if (realpage != chip->pagebuf || oob) {
+			bufpoi = use_bufpoi ? chip->data_buf : buf;
+
+			if (use_bufpoi && aligned)
+				pr_debug("%s: using read bounce buffer for buf@%p\n",
+						 __func__, buf);
+
+read_retry:
+			/*
+			 * Now read the page into the buffer.  Absent an error,
+			 * the read methods return max bitflips per ecc step.
+			 */
+			if (unlikely(ops->mode == MTD_OPS_RAW))
+				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
+							      oob_required,
+							      page);
+			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
+				 !oob)
+				ret = chip->ecc.read_subpage(mtd, chip,
+							col, bytes, bufpoi,
+							page);
+			else
+				ret = chip->ecc.read_page(mtd, chip, bufpoi,
+							  oob_required, page);
+			if (ret < 0) {
+				if (use_bufpoi)
+					/* Invalidate page cache */
+					chip->pagebuf = -1;
+				break;
+			}
+
+			/* Transfer not aligned data */
+			if (use_bufpoi) {
+				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
+				    !(mtd->ecc_stats.failed - ecc_failures) &&
+				    (ops->mode != MTD_OPS_RAW)) {
+					chip->pagebuf = realpage;
+					chip->pagebuf_bitflips = ret;
+				} else {
+					/* Invalidate page cache */
+					chip->pagebuf = -1;
+				}
+				memcpy(buf, chip->data_buf + col, bytes);
+			}
+
+			if (unlikely(oob)) {
+				int toread = min(oobreadlen, max_oobsize);
+
+				if (toread) {
+					oob = nand_transfer_oob(mtd,
+						oob, ops, toread);
+					oobreadlen -= toread;
+				}
+			}
+
+			if (chip->options & NAND_NEED_READRDY) {
+				/* Apply delay or wait for ready/busy pin */
+				if (!chip->dev_ready)
+					udelay(chip->chip_delay);
+				else
+					nand_wait_ready(mtd);
+			}
+
+			if (mtd->ecc_stats.failed - ecc_failures) {
+				if (retry_mode + 1 < chip->read_retries) {
+					retry_mode++;
+					ret = nand_setup_read_retry(mtd,
+							retry_mode);
+					if (ret < 0)
+						break;
+
+					/* Reset failures; retry */
+					mtd->ecc_stats.failed = ecc_failures;
+					goto read_retry;
+				} else {
+					/* No more retry modes; real failure */
+					ecc_fail = true;
+				}
+			}
+
+			buf += bytes;
+			max_bitflips = max_t(unsigned int, max_bitflips, ret);
+		} else {
+			memcpy(buf, chip->data_buf + col, bytes);
+			buf += bytes;
+			max_bitflips = max_t(unsigned int, max_bitflips,
+					     chip->pagebuf_bitflips);
+		}
+
+		readlen -= bytes;
+
+		/* Reset to retry mode 0 */
+		if (retry_mode) {
+			ret = nand_setup_read_retry(mtd, 0);
+			if (ret < 0)
+				break;
+			retry_mode = 0;
+		}
+
+		if (!readlen)
+			break;
+
+		/* For subsequent reads align to page boundary */
+		col = 0;
+		/* Increment page address */
+		realpage++;
+
+		page = realpage & chip->pagemask;
+		/* Check, if we cross a chip boundary */
+		if (!page) {
+			chipnr++;
+			chip->select_chip(mtd, -1);
+			chip->select_chip(mtd, chipnr);
+		}
+	}
+	chip->select_chip(mtd, -1);
+
+	ops->retlen = ops->len - (size_t) readlen;
+	if (oob)
+		ops->oobretlen = ops->ooblen - oobreadlen;
+
+	if (ret < 0)
+		return ret;
+
+	if (ecc_fail)
+		return -EBADMSG;
+
+	return max_bitflips;
+}
+
+/**
+ * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ */
+int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
+}
+EXPORT_SYMBOL(nand_read_oob_std);
+
+/**
+ * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
+ *			    with syndromes
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ */
+int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+			   int page)
+{
+	int length = mtd->oobsize;
+	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+	int eccsize = chip->ecc.size;
+	uint8_t *bufpoi = chip->oob_poi;
+	int i, toread, sndrnd = 0, pos, ret;
+
+	ret = nand_read_page_op(chip, page, chip->ecc.size, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < chip->ecc.steps; i++) {
+		if (sndrnd) {
+			int ret;
+
+			pos = eccsize + i * (eccsize + chunk);
+			if (mtd->writesize > 512)
+				ret = nand_change_read_column_op(chip, pos,
+								 NULL, 0,
+								 false);
+			else
+				ret = nand_read_page_op(chip, page, pos, NULL,
+							0);
+
+			if (ret)
+				return ret;
+		} else
+			sndrnd = 1;
+		toread = min_t(int, length, chunk);
+
+		ret = nand_read_data_op(chip, bufpoi, toread, false);
+		if (ret)
+			return ret;
+
+		bufpoi += toread;
+		length -= toread;
+	}
+	if (length > 0) {
+		ret = nand_read_data_op(chip, bufpoi, length, false);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(nand_read_oob_syndrome);
+
+/**
+ * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+{
+	return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
+				 mtd->oobsize);
+}
+EXPORT_SYMBOL(nand_write_oob_std);
+
+/**
+ * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
+ *			     with syndrome - only for large page flash
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page)
+{
+	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+	int eccsize = chip->ecc.size, length = mtd->oobsize;
+	int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
+	const uint8_t *bufpoi = chip->oob_poi;
+
+	/*
+	 * data-ecc-data-ecc ... ecc-oob
+	 * or
+	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob
+	 */
+	if (!chip->ecc.prepad && !chip->ecc.postpad) {
+		pos = steps * (eccsize + chunk);
+		steps = 0;
+	} else
+		pos = eccsize;
+
+	ret = nand_prog_page_begin_op(chip, page, pos, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < steps; i++) {
+		if (sndcmd) {
+			if (mtd->writesize <= 512) {
+				uint32_t fill = 0xFFFFFFFF;
+
+				len = eccsize;
+				while (len > 0) {
+					int num = min_t(int, len, 4);
+
+					ret = nand_write_data_op(chip, &fill,
+								 num, false);
+					if (ret)
+						return ret;
+
+					len -= num;
+				}
+			} else {
+				pos = eccsize + i * (eccsize + chunk);
+				ret = nand_change_write_column_op(chip, pos,
+								  NULL, 0,
+								  false);
+				if (ret)
+					return ret;
+			}
+		} else
+			sndcmd = 1;
+		len = min_t(int, length, chunk);
+
+		ret = nand_write_data_op(chip, bufpoi, len, false);
+		if (ret)
+			return ret;
+
+		bufpoi += len;
+		length -= len;
+	}
+	if (length > 0) {
+		ret = nand_write_data_op(chip, bufpoi, length, false);
+		if (ret)
+			return ret;
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+EXPORT_SYMBOL(nand_write_oob_syndrome);
+
+/**
+ * nand_do_read_oob - [INTERN] NAND read out-of-band
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operations description structure
+ *
+ * NAND read out-of-band data from the spare area.
+ */
+static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+			    struct mtd_oob_ops *ops)
+{
+	unsigned int max_bitflips = 0;
+	int page, realpage, chipnr;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct mtd_ecc_stats stats;
+	int readlen = ops->ooblen;
+	int len;
+	uint8_t *buf = ops->oobbuf;
+	int ret = 0;
+
+	pr_debug("%s: from = 0x%08Lx, len = %i\n",
+			__func__, (unsigned long long)from, readlen);
+
+	stats = mtd->ecc_stats;
+
+	len = mtd_oobavail(mtd, ops);
+
+	chipnr = (int)(from >> chip->chip_shift);
+	chip->select_chip(mtd, chipnr);
+
+	/* Shift to get page */
+	realpage = (int)(from >> chip->page_shift);
+	page = realpage & chip->pagemask;
+
+	while (1) {
+		if (ops->mode == MTD_OPS_RAW)
+			ret = chip->ecc.read_oob_raw(mtd, chip, page);
+		else
+			ret = chip->ecc.read_oob(mtd, chip, page);
+
+		if (ret < 0)
+			break;
+
+		len = min(len, readlen);
+		buf = nand_transfer_oob(mtd, buf, ops, len);
+
+		if (chip->options & NAND_NEED_READRDY) {
+			/* Apply delay or wait for ready/busy pin */
+			if (!chip->dev_ready)
+				udelay(chip->chip_delay);
+			else
+				nand_wait_ready(mtd);
+		}
+
+		max_bitflips = max_t(unsigned int, max_bitflips, ret);
+
+		readlen -= len;
+		if (!readlen)
+			break;
+
+		/* Increment page address */
+		realpage++;
+
+		page = realpage & chip->pagemask;
+		/* Check, if we cross a chip boundary */
+		if (!page) {
+			chipnr++;
+			chip->select_chip(mtd, -1);
+			chip->select_chip(mtd, chipnr);
+		}
+	}
+	chip->select_chip(mtd, -1);
+
+	ops->oobretlen = ops->ooblen - readlen;
+
+	if (ret < 0)
+		return ret;
+
+	if (mtd->ecc_stats.failed - stats.failed)
+		return -EBADMSG;
+
+	return max_bitflips;
+}
+
+/**
+ * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @ops: oob operation description structure
+ *
+ * NAND read data and/or out-of-band data.
+ */
+static int nand_read_oob(struct mtd_info *mtd, loff_t from,
+			 struct mtd_oob_ops *ops)
+{
+	int ret;
+
+	ops->retlen = 0;
+
+	if (ops->mode != MTD_OPS_PLACE_OOB &&
+	    ops->mode != MTD_OPS_AUTO_OOB &&
+	    ops->mode != MTD_OPS_RAW)
+		return -ENOTSUPP;
+
+	nand_get_device(mtd, FL_READING);
+
+	if (!ops->datbuf)
+		ret = nand_do_read_oob(mtd, from, ops);
+	else
+		ret = nand_do_read_ops(mtd, from, ops);
+
+	nand_release_device(mtd);
+	return ret;
+}
+
+
+/**
+ * nand_write_page_raw - [INTERN] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ *
+ * Not for syndrome calculating ECC controllers, which use a special oob layout.
+ */
+int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+			const uint8_t *buf, int oob_required, int page)
+{
+	int ret;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	if (ret)
+		return ret;
+
+	if (oob_required) {
+		ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize,
+					 false);
+		if (ret)
+			return ret;
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+EXPORT_SYMBOL(nand_write_page_raw);
+
+/**
+ * nand_write_page_raw_syndrome - [INTERN] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ *
+ * We need a special oob layout and handling even when ECC isn't checked.
+ */
+static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
+					struct nand_chip *chip,
+					const uint8_t *buf, int oob_required,
+					int page)
+{
+	int eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	uint8_t *oob = chip->oob_poi;
+	int steps, size, ret;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (steps = chip->ecc.steps; steps > 0; steps--) {
+		ret = nand_write_data_op(chip, buf, eccsize, false);
+		if (ret)
+			return ret;
+
+		buf += eccsize;
+
+		if (chip->ecc.prepad) {
+			ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
+						 false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.prepad;
+		}
+
+		ret = nand_write_data_op(chip, oob, eccbytes, false);
+		if (ret)
+			return ret;
+
+		oob += eccbytes;
+
+		if (chip->ecc.postpad) {
+			ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
+						 false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.postpad;
+		}
+	}
+
+	size = mtd->oobsize - (oob - chip->oob_poi);
+	if (size) {
+		ret = nand_write_data_op(chip, oob, size, false);
+		if (ret)
+			return ret;
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+/**
+ * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ */
+static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+				 const uint8_t *buf, int oob_required,
+				 int page)
+{
+	int i, eccsize = chip->ecc.size, ret;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	const uint8_t *p = buf;
+
+	/* Software ECC calculation */
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+}
+
+/**
+ * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ */
+static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				  const uint8_t *buf, int oob_required,
+				  int page)
+{
+	int i, eccsize = chip->ecc.size, ret;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	const uint8_t *p = buf;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+		ret = nand_write_data_op(chip, p, eccsize, false);
+		if (ret)
+			return ret;
+
+		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+	}
+
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(chip);
+}
+
+
+/**
+ * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @offset:	column address of subpage within the page
+ * @data_len:	data length
+ * @buf:	data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ */
+static int nand_write_subpage_hwecc(struct mtd_info *mtd,
+				struct nand_chip *chip, uint32_t offset,
+				uint32_t data_len, const uint8_t *buf,
+				int oob_required, int page)
+{
+	uint8_t *oob_buf  = chip->oob_poi;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	int ecc_size      = chip->ecc.size;
+	int ecc_bytes     = chip->ecc.bytes;
+	int ecc_steps     = chip->ecc.steps;
+	uint32_t start_step = offset / ecc_size;
+	uint32_t end_step   = (offset + data_len - 1) / ecc_size;
+	int oob_bytes       = mtd->oobsize / ecc_steps;
+	int step, ret;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (step = 0; step < ecc_steps; step++) {
+		/* configure controller for WRITE access */
+		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+		/* write data (untouched subpages already masked by 0xFF) */
+		ret = nand_write_data_op(chip, buf, ecc_size, false);
+		if (ret)
+			return ret;
+
+		/* mask ECC of un-touched subpages by padding 0xFF */
+		if ((step < start_step) || (step > end_step))
+			memset(ecc_calc, 0xff, ecc_bytes);
+		else
+			chip->ecc.calculate(mtd, buf, ecc_calc);
+
+		/* mask OOB of un-touched subpages by padding 0xFF */
+		/* if oob_required, preserve OOB metadata of written subpage */
+		if (!oob_required || (step < start_step) || (step > end_step))
+			memset(oob_buf, 0xff, oob_bytes);
+
+		buf += ecc_size;
+		ecc_calc += ecc_bytes;
+		oob_buf  += oob_bytes;
+	}
+
+	/* copy calculated ECC for whole page to chip->buffer->oob */
+	/* this include masked-value(0xFF) for unwritten subpages */
+	ecc_calc = chip->ecc.calc_buf;
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	/* write OOB buffer to NAND device */
+	ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(chip);
+}
+
+
+/**
+ * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ *
+ * The hw generator calculates the error syndrome automatically. Therefore we
+ * need a special oob layout and handling.
+ */
+static int nand_write_page_syndrome(struct mtd_info *mtd,
+				    struct nand_chip *chip,
+				    const uint8_t *buf, int oob_required,
+				    int page)
+{
+	int i, eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
+	const uint8_t *p = buf;
+	uint8_t *oob = chip->oob_poi;
+	int ret;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+		ret = nand_write_data_op(chip, p, eccsize, false);
+		if (ret)
+			return ret;
+
+		if (chip->ecc.prepad) {
+			ret = nand_write_data_op(chip, oob, chip->ecc.prepad,
+						 false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.prepad;
+		}
+
+		chip->ecc.calculate(mtd, p, oob);
+
+		ret = nand_write_data_op(chip, oob, eccbytes, false);
+		if (ret)
+			return ret;
+
+		oob += eccbytes;
+
+		if (chip->ecc.postpad) {
+			ret = nand_write_data_op(chip, oob, chip->ecc.postpad,
+						 false);
+			if (ret)
+				return ret;
+
+			oob += chip->ecc.postpad;
+		}
+	}
+
+	/* Calculate remaining oob bytes */
+	i = mtd->oobsize - (oob - chip->oob_poi);
+	if (i) {
+		ret = nand_write_data_op(chip, oob, i, false);
+		if (ret)
+			return ret;
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+
+/**
+ * nand_write_page - write one page
+ * @mtd: MTD device structure
+ * @chip: NAND chip descriptor
+ * @offset: address offset within the page
+ * @data_len: length of actual data to be written
+ * @buf: the data to write
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ * @raw: use _raw version of write_page
+ */
+static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+		uint32_t offset, int data_len, const uint8_t *buf,
+		int oob_required, int page, int raw)
+{
+	int status, subpage;
+
+	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
+		chip->ecc.write_subpage)
+		subpage = offset || (data_len < mtd->writesize);
+	else
+		subpage = 0;
+
+	if (unlikely(raw))
+		status = chip->ecc.write_page_raw(mtd, chip, buf,
+						  oob_required, page);
+	else if (subpage)
+		status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
+						 buf, oob_required, page);
+	else
+		status = chip->ecc.write_page(mtd, chip, buf, oob_required,
+					      page);
+
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+/**
+ * nand_fill_oob - [INTERN] Transfer client buffer to oob
+ * @mtd: MTD device structure
+ * @oob: oob data buffer
+ * @len: oob data write length
+ * @ops: oob ops structure
+ */
+static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
+			      struct mtd_oob_ops *ops)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	/*
+	 * Initialise to all 0xFF, to avoid the possibility of left over OOB
+	 * data from a previous OOB read.
+	 */
+	memset(chip->oob_poi, 0xff, mtd->oobsize);
+
+	switch (ops->mode) {
+
+	case MTD_OPS_PLACE_OOB:
+	case MTD_OPS_RAW:
+		memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+		return oob + len;
+
+	case MTD_OPS_AUTO_OOB:
+		ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
+						  ops->ooboffs, len);
+		BUG_ON(ret);
+		return oob + len;
+
+	default:
+		BUG();
+	}
+	return NULL;
+}
+
+#define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0)
+
+/**
+ * nand_do_write_ops - [INTERN] NAND write with ECC
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operations description structure
+ *
+ * NAND write with ECC.
+ */
+static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
+			     struct mtd_oob_ops *ops)
+{
+	int chipnr, realpage, page, column;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	uint32_t writelen = ops->len;
+
+	uint32_t oobwritelen = ops->ooblen;
+	uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
+
+	uint8_t *oob = ops->oobbuf;
+	uint8_t *buf = ops->datbuf;
+	int ret;
+	int oob_required = oob ? 1 : 0;
+
+	ops->retlen = 0;
+	if (!writelen)
+		return 0;
+
+	/* Reject writes, which are not page aligned */
+	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
+		pr_notice("%s: attempt to write non page aligned data\n",
+			   __func__);
+		return -EINVAL;
+	}
+
+	column = to & (mtd->writesize - 1);
+
+	chipnr = (int)(to >> chip->chip_shift);
+	chip->select_chip(mtd, chipnr);
+
+	/* Check, if it is write protected */
+	if (nand_check_wp(mtd)) {
+		ret = -EIO;
+		goto err_out;
+	}
+
+	realpage = (int)(to >> chip->page_shift);
+	page = realpage & chip->pagemask;
+
+	/* Invalidate the page cache, when we write to the cached page */
+	if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
+	    ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len))
+		chip->pagebuf = -1;
+
+	/* Don't allow multipage oob writes with offset */
+	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	while (1) {
+		int bytes = mtd->writesize;
+		uint8_t *wbuf = buf;
+		int use_bufpoi;
+		int part_pagewr = (column || writelen < mtd->writesize);
+
+		if (part_pagewr)
+			use_bufpoi = 1;
+		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+			use_bufpoi = !virt_addr_valid(buf) ||
+				     !IS_ALIGNED((unsigned long)buf,
+						 chip->buf_align);
+		else
+			use_bufpoi = 0;
+
+		/* Partial page write?, or need to use bounce buffer */
+		if (use_bufpoi) {
+			pr_debug("%s: using write bounce buffer for buf@%p\n",
+					 __func__, buf);
+			if (part_pagewr)
+				bytes = min_t(int, bytes - column, writelen);
+			chip->pagebuf = -1;
+			memset(chip->data_buf, 0xff, mtd->writesize);
+			memcpy(&chip->data_buf[column], buf, bytes);
+			wbuf = chip->data_buf;
+		}
+
+		if (unlikely(oob)) {
+			size_t len = min(oobwritelen, oobmaxlen);
+			oob = nand_fill_oob(mtd, oob, len, ops);
+			oobwritelen -= len;
+		} else {
+			/* We still need to erase leftover OOB data */
+			memset(chip->oob_poi, 0xff, mtd->oobsize);
+		}
+
+		ret = nand_write_page(mtd, chip, column, bytes, wbuf,
+				      oob_required, page,
+				      (ops->mode == MTD_OPS_RAW));
+		if (ret)
+			break;
+
+		writelen -= bytes;
+		if (!writelen)
+			break;
+
+		column = 0;
+		buf += bytes;
+		realpage++;
+
+		page = realpage & chip->pagemask;
+		/* Check, if we cross a chip boundary */
+		if (!page) {
+			chipnr++;
+			chip->select_chip(mtd, -1);
+			chip->select_chip(mtd, chipnr);
+		}
+	}
+
+	ops->retlen = ops->len - writelen;
+	if (unlikely(oob))
+		ops->oobretlen = ops->ooblen;
+
+err_out:
+	chip->select_chip(mtd, -1);
+	return ret;
+}
+
+/**
+ * panic_nand_write - [MTD Interface] NAND write with ECC
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @len: number of bytes to write
+ * @retlen: pointer to variable to store the number of written bytes
+ * @buf: the data to write
+ *
+ * NAND write with ECC. Used when performing writes in interrupt context, this
+ * may for example be called by mtdoops when writing an oops while in panic.
+ */
+static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+			    size_t *retlen, const uint8_t *buf)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int chipnr = (int)(to >> chip->chip_shift);
+	struct mtd_oob_ops ops;
+	int ret;
+
+	/* Grab the device */
+	panic_nand_get_device(chip, mtd, FL_WRITING);
+
+	chip->select_chip(mtd, chipnr);
+
+	/* Wait for the device to get ready */
+	panic_nand_wait(mtd, chip, 400);
+
+	memset(&ops, 0, sizeof(ops));
+	ops.len = len;
+	ops.datbuf = (uint8_t *)buf;
+	ops.mode = MTD_OPS_PLACE_OOB;
+
+	ret = nand_do_write_ops(mtd, to, &ops);
+
+	*retlen = ops.retlen;
+	return ret;
+}
+
+/**
+ * nand_do_write_oob - [MTD Interface] NAND write out-of-band
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
+ *
+ * NAND write out-of-band.
+ */
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+			     struct mtd_oob_ops *ops)
+{
+	int chipnr, page, status, len;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	pr_debug("%s: to = 0x%08x, len = %i\n",
+			 __func__, (unsigned int)to, (int)ops->ooblen);
+
+	len = mtd_oobavail(mtd, ops);
+
+	/* Do not allow write past end of page */
+	if ((ops->ooboffs + ops->ooblen) > len) {
+		pr_debug("%s: attempt to write past end of page\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	chipnr = (int)(to >> chip->chip_shift);
+
+	/*
+	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
+	 * of my DiskOnChip 2000 test units) will clear the whole data page too
+	 * if we don't do this. I have no clue why, but I seem to have 'fixed'
+	 * it in the doc2000 driver in August 1999.  dwmw2.
+	 */
+	nand_reset(chip, chipnr);
+
+	chip->select_chip(mtd, chipnr);
+
+	/* Shift to get page */
+	page = (int)(to >> chip->page_shift);
+
+	/* Check, if it is write protected */
+	if (nand_check_wp(mtd)) {
+		chip->select_chip(mtd, -1);
+		return -EROFS;
+	}
+
+	/* Invalidate the page cache, if we write to the cached page */
+	if (page == chip->pagebuf)
+		chip->pagebuf = -1;
+
+	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
+
+	if (ops->mode == MTD_OPS_RAW)
+		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
+	else
+		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+
+	chip->select_chip(mtd, -1);
+
+	if (status)
+		return status;
+
+	ops->oobretlen = ops->ooblen;
+
+	return 0;
+}
+
+/**
+ * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
+ */
+static int nand_write_oob(struct mtd_info *mtd, loff_t to,
+			  struct mtd_oob_ops *ops)
+{
+	int ret = -ENOTSUPP;
+
+	ops->retlen = 0;
+
+	nand_get_device(mtd, FL_WRITING);
+
+	switch (ops->mode) {
+	case MTD_OPS_PLACE_OOB:
+	case MTD_OPS_AUTO_OOB:
+	case MTD_OPS_RAW:
+		break;
+
+	default:
+		goto out;
+	}
+
+	if (!ops->datbuf)
+		ret = nand_do_write_oob(mtd, to, ops);
+	else
+		ret = nand_do_write_ops(mtd, to, ops);
+
+out:
+	nand_release_device(mtd);
+	return ret;
+}
+
+/**
+ * single_erase - [GENERIC] NAND standard block erase command function
+ * @mtd: MTD device structure
+ * @page: the page address of the block which will be erased
+ *
+ * Standard erase command for NAND chips. Returns NAND status.
+ */
+static int single_erase(struct mtd_info *mtd, int page)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	unsigned int eraseblock;
+
+	/* Send commands to erase a block */
+	eraseblock = page >> (chip->phys_erase_shift - chip->page_shift);
+
+	return nand_erase_op(chip, eraseblock);
+}
+
+/**
+ * nand_erase - [MTD Interface] erase block(s)
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ *
+ * Erase one ore more blocks.
+ */
+static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	return nand_erase_nand(mtd, instr, 0);
+}
+
+/**
+ * nand_erase_nand - [INTERN] erase block(s)
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ * @allowbbt: allow erasing the bbt area
+ *
+ * Erase one ore more blocks.
+ */
+int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+		    int allowbbt)
+{
+	int page, status, pages_per_block, ret, chipnr;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	loff_t len;
+
+	pr_debug("%s: start = 0x%012llx, len = %llu\n",
+			__func__, (unsigned long long)instr->addr,
+			(unsigned long long)instr->len);
+
+	if (check_offs_len(mtd, instr->addr, instr->len))
+		return -EINVAL;
+
+	/* Grab the lock and see if the device is available */
+	nand_get_device(mtd, FL_ERASING);
+
+	/* Shift to get first page */
+	page = (int)(instr->addr >> chip->page_shift);
+	chipnr = (int)(instr->addr >> chip->chip_shift);
+
+	/* Calculate pages in each block */
+	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
+
+	/* Select the NAND device */
+	chip->select_chip(mtd, chipnr);
+
+	/* Check, if it is write protected */
+	if (nand_check_wp(mtd)) {
+		pr_debug("%s: device is write protected!\n",
+				__func__);
+		instr->state = MTD_ERASE_FAILED;
+		goto erase_exit;
+	}
+
+	/* Loop through the pages */
+	len = instr->len;
+
+	instr->state = MTD_ERASING;
+
+	while (len) {
+		/* Check if we have a bad block, we do not erase bad blocks! */
+		if (nand_block_checkbad(mtd, ((loff_t) page) <<
+					chip->page_shift, allowbbt)) {
+			pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
+				    __func__, page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+
+		/*
+		 * Invalidate the page cache, if we erase the block which
+		 * contains the current cached page.
+		 */
+		if (page <= chip->pagebuf && chip->pagebuf <
+		    (page + pages_per_block))
+			chip->pagebuf = -1;
+
+		status = chip->erase(mtd, page & chip->pagemask);
+
+		/* See if block erase succeeded */
+		if (status) {
+			pr_debug("%s: failed erase, page 0x%08x\n",
+					__func__, page);
+			instr->state = MTD_ERASE_FAILED;
+			instr->fail_addr =
+				((loff_t)page << chip->page_shift);
+			goto erase_exit;
+		}
+
+		/* Increment page address and decrement length */
+		len -= (1ULL << chip->phys_erase_shift);
+		page += pages_per_block;
+
+		/* Check, if we cross a chip boundary */
+		if (len && !(page & chip->pagemask)) {
+			chipnr++;
+			chip->select_chip(mtd, -1);
+			chip->select_chip(mtd, chipnr);
+		}
+	}
+	instr->state = MTD_ERASE_DONE;
+
+erase_exit:
+
+	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+
+	/* Deselect and wake up anyone waiting on the device */
+	chip->select_chip(mtd, -1);
+	nand_release_device(mtd);
+
+	/* Do call back function */
+	if (!ret)
+		mtd_erase_callback(instr);
+
+	/* Return more or less happy */
+	return ret;
+}
+
+/**
+ * nand_sync - [MTD Interface] sync
+ * @mtd: MTD device structure
+ *
+ * Sync is actually a wait for chip ready function.
+ */
+static void nand_sync(struct mtd_info *mtd)
+{
+	pr_debug("%s: called\n", __func__);
+
+	/* Grab the lock and see if the device is available */
+	nand_get_device(mtd, FL_SYNCING);
+	/* Release it and go back */
+	nand_release_device(mtd);
+}
+
+/**
+ * nand_block_isbad - [MTD Interface] Check if block at offset is bad
+ * @mtd: MTD device structure
+ * @offs: offset relative to mtd start
+ */
+static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int chipnr = (int)(offs >> chip->chip_shift);
+	int ret;
+
+	/* Select the NAND device */
+	nand_get_device(mtd, FL_READING);
+	chip->select_chip(mtd, chipnr);
+
+	ret = nand_block_checkbad(mtd, offs, 0);
+
+	chip->select_chip(mtd, -1);
+	nand_release_device(mtd);
+
+	return ret;
+}
+
+/**
+ * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ */
+static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	int ret;
+
+	ret = nand_block_isbad(mtd, ofs);
+	if (ret) {
+		/* If it was bad already, return success and do nothing */
+		if (ret > 0)
+			return 0;
+		return ret;
+	}
+
+	return nand_block_markbad_lowlevel(mtd, ofs);
+}
+
+/**
+ * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: length of mtd
+ */
+static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u32 part_start_block;
+	u32 part_end_block;
+	u32 part_start_die;
+	u32 part_end_die;
+
+	/*
+	 * max_bb_per_die and blocks_per_die used to determine
+	 * the maximum bad block count.
+	 */
+	if (!chip->max_bb_per_die || !chip->blocks_per_die)
+		return -ENOTSUPP;
+
+	/* Get the start and end of the partition in erase blocks. */
+	part_start_block = mtd_div_by_eb(ofs, mtd);
+	part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
+
+	/* Get the start and end LUNs of the partition. */
+	part_start_die = part_start_block / chip->blocks_per_die;
+	part_end_die = part_end_block / chip->blocks_per_die;
+
+	/*
+	 * Look up the bad blocks per unit and multiply by the number of units
+	 * that the partition spans.
+	 */
+	return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
+}
+
+/**
+ * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+			int addr, uint8_t *subfeature_param)
+{
+	if (!chip->onfi_version ||
+	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+		return -EINVAL;
+
+	return nand_set_features_op(chip, addr, subfeature_param);
+}
+
+/**
+ * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ */
+static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+			int addr, uint8_t *subfeature_param)
+{
+	if (!chip->onfi_version ||
+	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+	      & ONFI_OPT_CMD_SET_GET_FEATURES))
+		return -EINVAL;
+
+	return nand_get_features_op(chip, addr, subfeature_param);
+}
+
+/**
+ * nand_onfi_get_set_features_notsupp - set/get features stub returning
+ *					-ENOTSUPP
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ *
+ * Should be used by NAND controller drivers that do not support the SET/GET
+ * FEATURES operations.
+ */
+int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
+				       struct nand_chip *chip, int addr,
+				       u8 *subfeature_param)
+{
+	return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
+
+/**
+ * nand_suspend - [MTD Interface] Suspend the NAND flash
+ * @mtd: MTD device structure
+ */
+static int nand_suspend(struct mtd_info *mtd)
+{
+	return nand_get_device(mtd, FL_PM_SUSPENDED);
+}
+
+/**
+ * nand_resume - [MTD Interface] Resume the NAND flash
+ * @mtd: MTD device structure
+ */
+static void nand_resume(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (chip->state == FL_PM_SUSPENDED)
+		nand_release_device(mtd);
+	else
+		pr_err("%s called for a chip which is not in suspended state\n",
+			__func__);
+}
+
+/**
+ * nand_shutdown - [MTD Interface] Finish the current NAND operation and
+ *                 prevent further operations
+ * @mtd: MTD device structure
+ */
+static void nand_shutdown(struct mtd_info *mtd)
+{
+	nand_get_device(mtd, FL_PM_SUSPENDED);
+}
+
+/* Set default functions */
+static void nand_set_defaults(struct nand_chip *chip)
+{
+	unsigned int busw = chip->options & NAND_BUSWIDTH_16;
+
+	/* check for proper chip_delay setup, set 20us if not */
+	if (!chip->chip_delay)
+		chip->chip_delay = 20;
+
+	/* check, if a user supplied command function given */
+	if (!chip->cmdfunc && !chip->exec_op)
+		chip->cmdfunc = nand_command;
+
+	/* check, if a user supplied wait function given */
+	if (chip->waitfunc == NULL)
+		chip->waitfunc = nand_wait;
+
+	if (!chip->select_chip)
+		chip->select_chip = nand_select_chip;
+
+	/* set for ONFI nand */
+	if (!chip->onfi_set_features)
+		chip->onfi_set_features = nand_onfi_set_features;
+	if (!chip->onfi_get_features)
+		chip->onfi_get_features = nand_onfi_get_features;
+
+	/* If called twice, pointers that depend on busw may need to be reset */
+	if (!chip->read_byte || chip->read_byte == nand_read_byte)
+		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
+	if (!chip->read_word)
+		chip->read_word = nand_read_word;
+	if (!chip->block_bad)
+		chip->block_bad = nand_block_bad;
+	if (!chip->block_markbad)
+		chip->block_markbad = nand_default_block_markbad;
+	if (!chip->write_buf || chip->write_buf == nand_write_buf)
+		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+	if (!chip->write_byte || chip->write_byte == nand_write_byte)
+		chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
+	if (!chip->read_buf || chip->read_buf == nand_read_buf)
+		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+	if (!chip->scan_bbt)
+		chip->scan_bbt = nand_default_bbt;
+
+	if (!chip->controller) {
+		chip->controller = &chip->hwcontrol;
+		nand_hw_control_init(chip->controller);
+	}
+
+	if (!chip->buf_align)
+		chip->buf_align = 1;
+}
+
+/* Sanitize ONFI strings so we can safely print them */
+static void sanitize_string(uint8_t *s, size_t len)
+{
+	ssize_t i;
+
+	/* Null terminate */
+	s[len - 1] = 0;
+
+	/* Remove non printable chars */
+	for (i = 0; i < len - 1; i++) {
+		if (s[i] < ' ' || s[i] > 127)
+			s[i] = '?';
+	}
+
+	/* Remove trailing spaces */
+	strim(s);
+}
+
+static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
+{
+	int i;
+	while (len--) {
+		crc ^= *p++ << 8;
+		for (i = 0; i < 8; i++)
+			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+	}
+
+	return crc;
+}
+
+/* Parse the Extended Parameter Page. */
+static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
+					    struct nand_onfi_params *p)
+{
+	struct onfi_ext_param_page *ep;
+	struct onfi_ext_section *s;
+	struct onfi_ext_ecc_info *ecc;
+	uint8_t *cursor;
+	int ret;
+	int len;
+	int i;
+
+	len = le16_to_cpu(p->ext_param_page_length) * 16;
+	ep = kmalloc(len, GFP_KERNEL);
+	if (!ep)
+		return -ENOMEM;
+
+	/* Send our own NAND_CMD_PARAM. */
+	ret = nand_read_param_page_op(chip, 0, NULL, 0);
+	if (ret)
+		goto ext_out;
+
+	/* Use the Change Read Column command to skip the ONFI param pages. */
+	ret = nand_change_read_column_op(chip,
+					 sizeof(*p) * p->num_of_param_pages,
+					 ep, len, true);
+	if (ret)
+		goto ext_out;
+
+	ret = -EINVAL;
+	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+		!= le16_to_cpu(ep->crc))) {
+		pr_debug("fail in the CRC.\n");
+		goto ext_out;
+	}
+
+	/*
+	 * Check the signature.
+	 * Do not strictly follow the ONFI spec, maybe changed in future.
+	 */
+	if (strncmp(ep->sig, "EPPS", 4)) {
+		pr_debug("The signature is invalid.\n");
+		goto ext_out;
+	}
+
+	/* find the ECC section. */
+	cursor = (uint8_t *)(ep + 1);
+	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+		s = ep->sections + i;
+		if (s->type == ONFI_SECTION_TYPE_2)
+			break;
+		cursor += s->length * 16;
+	}
+	if (i == ONFI_EXT_SECTION_MAX) {
+		pr_debug("We can not find the ECC section.\n");
+		goto ext_out;
+	}
+
+	/* get the info we want. */
+	ecc = (struct onfi_ext_ecc_info *)cursor;
+
+	if (!ecc->codeword_size) {
+		pr_debug("Invalid codeword size\n");
+		goto ext_out;
+	}
+
+	chip->ecc_strength_ds = ecc->ecc_bits;
+	chip->ecc_step_ds = 1 << ecc->codeword_size;
+	ret = 0;
+
+ext_out:
+	kfree(ep);
+	return ret;
+}
+
+/*
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
+ */
+static int nand_flash_detect_onfi(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_onfi_params *p = &chip->onfi_params;
+	char id[4];
+	int i, ret, val;
+
+	/* Try ONFI for unknown chip or LP */
+	ret = nand_readid_op(chip, 0x20, id, sizeof(id));
+	if (ret || strncmp(id, "ONFI", 4))
+		return 0;
+
+	ret = nand_read_param_page_op(chip, 0, NULL, 0);
+	if (ret)
+		return 0;
+
+	for (i = 0; i < 3; i++) {
+		ret = nand_read_data_op(chip, p, sizeof(*p), true);
+		if (ret)
+			return 0;
+
+		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
+				le16_to_cpu(p->crc)) {
+			break;
+		}
+	}
+
+	if (i == 3) {
+		pr_err("Could not find valid ONFI parameter page; aborting\n");
+		return 0;
+	}
+
+	/* Check version */
+	val = le16_to_cpu(p->revision);
+	if (val & (1 << 5))
+		chip->onfi_version = 23;
+	else if (val & (1 << 4))
+		chip->onfi_version = 22;
+	else if (val & (1 << 3))
+		chip->onfi_version = 21;
+	else if (val & (1 << 2))
+		chip->onfi_version = 20;
+	else if (val & (1 << 1))
+		chip->onfi_version = 10;
+
+	if (!chip->onfi_version) {
+		pr_info("unsupported ONFI version: %d\n", val);
+		return 0;
+	}
+
+	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+	sanitize_string(p->model, sizeof(p->model));
+	if (!mtd->name)
+		mtd->name = p->model;
+
+	mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+	/*
+	 * pages_per_block and blocks_per_lun may not be a power-of-2 size
+	 * (don't ask me who thought of this...). MTD assumes that these
+	 * dimensions will be power-of-2, so just truncate the remaining area.
+	 */
+	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+	mtd->erasesize *= mtd->writesize;
+
+	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+	/* See erasesize comment */
+	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+	chip->bits_per_cell = p->bits_per_cell;
+
+	chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
+	chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
+
+	if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	if (p->ecc_bits != 0xff) {
+		chip->ecc_strength_ds = p->ecc_bits;
+		chip->ecc_step_ds = 512;
+	} else if (chip->onfi_version >= 21 &&
+		(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+
+		/*
+		 * The nand_flash_detect_ext_param_page() uses the
+		 * Change Read Column command which maybe not supported
+		 * by the chip->cmdfunc. So try to update the chip->cmdfunc
+		 * now. We do not replace user supplied command function.
+		 */
+		if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+			chip->cmdfunc = nand_command_lp;
+
+		/* The Extended Parameter Page is supported since ONFI 2.1. */
+		if (nand_flash_detect_ext_param_page(chip, p))
+			pr_warn("Failed to detect ONFI extended param page\n");
+	} else {
+		pr_warn("Could not retrieve ONFI ECC requirements\n");
+	}
+
+	return 1;
+}
+
+/*
+ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+ */
+static int nand_flash_detect_jedec(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_jedec_params *p = &chip->jedec_params;
+	struct jedec_ecc_info *ecc;
+	char id[5];
+	int i, val, ret;
+
+	/* Try JEDEC for unknown chip or LP */
+	ret = nand_readid_op(chip, 0x40, id, sizeof(id));
+	if (ret || strncmp(id, "JEDEC", sizeof(id)))
+		return 0;
+
+	ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
+	if (ret)
+		return 0;
+
+	for (i = 0; i < 3; i++) {
+		ret = nand_read_data_op(chip, p, sizeof(*p), true);
+		if (ret)
+			return 0;
+
+		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+				le16_to_cpu(p->crc))
+			break;
+	}
+
+	if (i == 3) {
+		pr_err("Could not find valid JEDEC parameter page; aborting\n");
+		return 0;
+	}
+
+	/* Check version */
+	val = le16_to_cpu(p->revision);
+	if (val & (1 << 2))
+		chip->jedec_version = 10;
+	else if (val & (1 << 1))
+		chip->jedec_version = 1; /* vendor specific version */
+
+	if (!chip->jedec_version) {
+		pr_info("unsupported JEDEC version: %d\n", val);
+		return 0;
+	}
+
+	sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+	sanitize_string(p->model, sizeof(p->model));
+	if (!mtd->name)
+		mtd->name = p->model;
+
+	mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+	/* Please reference to the comment for nand_flash_detect_onfi. */
+	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+	mtd->erasesize *= mtd->writesize;
+
+	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+	/* Please reference to the comment for nand_flash_detect_onfi. */
+	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+	chip->bits_per_cell = p->bits_per_cell;
+
+	if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	/* ECC info */
+	ecc = &p->ecc_info[0];
+
+	if (ecc->codeword_size >= 9) {
+		chip->ecc_strength_ds = ecc->ecc_bits;
+		chip->ecc_step_ds = 1 << ecc->codeword_size;
+	} else {
+		pr_warn("Invalid codeword size\n");
+	}
+
+	return 1;
+}
+
+/*
+ * nand_id_has_period - Check if an ID string has a given wraparound period
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+ * @period: the period of repitition
+ *
+ * Check if an ID string is repeated within a given sequence of bytes at
+ * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
+ * period of 3). This is a helper function for nand_id_len(). Returns non-zero
+ * if the repetition has a period of @period; otherwise, returns zero.
+ */
+static int nand_id_has_period(u8 *id_data, int arrlen, int period)
+{
+	int i, j;
+	for (i = 0; i < period; i++)
+		for (j = i + period; j < arrlen; j += period)
+			if (id_data[i] != id_data[j])
+				return 0;
+	return 1;
+}
+
+/*
+ * nand_id_len - Get the length of an ID string returned by CMD_READID
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+
+ * Returns the length of the ID string, according to known wraparound/trailing
+ * zero patterns. If no pattern exists, returns the length of the array.
+ */
+static int nand_id_len(u8 *id_data, int arrlen)
+{
+	int last_nonzero, period;
+
+	/* Find last non-zero byte */
+	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
+		if (id_data[last_nonzero])
+			break;
+
+	/* All zeros */
+	if (last_nonzero < 0)
+		return 0;
+
+	/* Calculate wraparound period */
+	for (period = 1; period < arrlen; period++)
+		if (nand_id_has_period(id_data, arrlen, period))
+			break;
+
+	/* There's a repeated pattern */
+	if (period < arrlen)
+		return period;
+
+	/* There are trailing zeros */
+	if (last_nonzero < arrlen - 1)
+		return last_nonzero + 1;
+
+	/* No pattern detected */
+	return arrlen;
+}
+
+/* Extract the bits of per cell from the 3rd byte of the extended ID */
+static int nand_get_bits_per_cell(u8 cellinfo)
+{
+	int bits;
+
+	bits = cellinfo & NAND_CI_CELLTYPE_MSK;
+	bits >>= NAND_CI_CELLTYPE_SHIFT;
+	return bits + 1;
+}
+
+/*
+ * Many new NAND share similar device ID codes, which represent the size of the
+ * chip. The rest of the parameters must be decoded according to generic or
+ * manufacturer-specific "extended ID" decoding patterns.
+ */
+void nand_decode_ext_id(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int extid;
+	u8 *id_data = chip->id.data;
+	/* The 3rd id byte holds MLC / multichip data */
+	chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
+	/* The 4th id byte is the important one */
+	extid = id_data[3];
+
+	/* Calc pagesize */
+	mtd->writesize = 1024 << (extid & 0x03);
+	extid >>= 2;
+	/* Calc oobsize */
+	mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
+	extid >>= 2;
+	/* Calc blocksize. Blocksize is multiples of 64KiB */
+	mtd->erasesize = (64 * 1024) << (extid & 0x03);
+	extid >>= 2;
+	/* Get buswidth information */
+	if (extid & 0x1)
+		chip->options |= NAND_BUSWIDTH_16;
+}
+EXPORT_SYMBOL_GPL(nand_decode_ext_id);
+
+/*
+ * Old devices have chip data hardcoded in the device ID table. nand_decode_id
+ * decodes a matching ID table entry and assigns the MTD size parameters for
+ * the chip.
+ */
+static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	mtd->erasesize = type->erasesize;
+	mtd->writesize = type->pagesize;
+	mtd->oobsize = mtd->writesize / 32;
+
+	/* All legacy ID NAND are small-page, SLC */
+	chip->bits_per_cell = 1;
+}
+
+/*
+ * Set the bad block marker/indicator (BBM/BBI) patterns according to some
+ * heuristic patterns using various detected parameters (e.g., manufacturer,
+ * page size, cell-type information).
+ */
+static void nand_decode_bbm_options(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	/* Set the bad block position */
+	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
+		chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+	else
+		chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+}
+
+static inline bool is_full_id_nand(struct nand_flash_dev *type)
+{
+	return type->id_len;
+}
+
+static bool find_full_id_nand(struct nand_chip *chip,
+			      struct nand_flash_dev *type)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 *id_data = chip->id.data;
+
+	if (!strncmp(type->id, id_data, type->id_len)) {
+		mtd->writesize = type->pagesize;
+		mtd->erasesize = type->erasesize;
+		mtd->oobsize = type->oobsize;
+
+		chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
+		chip->chipsize = (uint64_t)type->chipsize << 20;
+		chip->options |= type->options;
+		chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
+		chip->ecc_step_ds = NAND_ECC_STEP(type);
+		chip->onfi_timing_mode_default =
+					type->onfi_timing_mode_default;
+
+		if (!mtd->name)
+			mtd->name = type->name;
+
+		return true;
+	}
+	return false;
+}
+
+/*
+ * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
+ * compliant and does not have a full-id or legacy-id entry in the nand_ids
+ * table.
+ */
+static void nand_manufacturer_detect(struct nand_chip *chip)
+{
+	/*
+	 * Try manufacturer detection if available and use
+	 * nand_decode_ext_id() otherwise.
+	 */
+	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+	    chip->manufacturer.desc->ops->detect) {
+		/* The 3rd id byte holds MLC / multichip data */
+		chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
+		chip->manufacturer.desc->ops->detect(chip);
+	} else {
+		nand_decode_ext_id(chip);
+	}
+}
+
+/*
+ * Manufacturer initialization. This function is called for all NANDs including
+ * ONFI and JEDEC compliant ones.
+ * Manufacturer drivers should put all their specific initialization code in
+ * their ->init() hook.
+ */
+static int nand_manufacturer_init(struct nand_chip *chip)
+{
+	if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
+	    !chip->manufacturer.desc->ops->init)
+		return 0;
+
+	return chip->manufacturer.desc->ops->init(chip);
+}
+
+/*
+ * Manufacturer cleanup. This function is called for all NANDs including
+ * ONFI and JEDEC compliant ones.
+ * Manufacturer drivers should put all their specific cleanup code in their
+ * ->cleanup() hook.
+ */
+static void nand_manufacturer_cleanup(struct nand_chip *chip)
+{
+	/* Release manufacturer private data */
+	if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+	    chip->manufacturer.desc->ops->cleanup)
+		chip->manufacturer.desc->ops->cleanup(chip);
+}
+
+/*
+ * Get the flash and manufacturer id and lookup if the type is supported.
+ */
+static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
+{
+	const struct nand_manufacturer *manufacturer;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int busw, ret;
+	u8 *id_data = chip->id.data;
+	u8 maf_id, dev_id;
+
+	/*
+	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
+	 * after power-up.
+	 */
+	ret = nand_reset(chip, 0);
+	if (ret)
+		return ret;
+
+	/* Select the device */
+	chip->select_chip(mtd, 0);
+
+	/* Send the command for reading device ID */
+	ret = nand_readid_op(chip, 0, id_data, 2);
+	if (ret)
+		return ret;
+
+	/* Read manufacturer and device IDs */
+	maf_id = id_data[0];
+	dev_id = id_data[1];
+
+	/*
+	 * Try again to make sure, as some systems the bus-hold or other
+	 * interface concerns can cause random data which looks like a
+	 * possibly credible NAND flash to appear. If the two results do
+	 * not match, ignore the device completely.
+	 */
+
+	/* Read entire ID string */
+	ret = nand_readid_op(chip, 0, id_data, sizeof(chip->id.data));
+	if (ret)
+		return ret;
+
+	if (id_data[0] != maf_id || id_data[1] != dev_id) {
+		pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
+			maf_id, dev_id, id_data[0], id_data[1]);
+		return -ENODEV;
+	}
+
+	chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
+
+	/* Try to identify manufacturer */
+	manufacturer = nand_get_manufacturer(maf_id);
+	chip->manufacturer.desc = manufacturer;
+
+	if (!type)
+		type = nand_flash_ids;
+
+	/*
+	 * Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
+	 * override it.
+	 * This is required to make sure initial NAND bus width set by the
+	 * NAND controller driver is coherent with the real NAND bus width
+	 * (extracted by auto-detection code).
+	 */
+	busw = chip->options & NAND_BUSWIDTH_16;
+
+	/*
+	 * The flag is only set (never cleared), reset it to its default value
+	 * before starting auto-detection.
+	 */
+	chip->options &= ~NAND_BUSWIDTH_16;
+
+	for (; type->name != NULL; type++) {
+		if (is_full_id_nand(type)) {
+			if (find_full_id_nand(chip, type))
+				goto ident_done;
+		} else if (dev_id == type->dev_id) {
+			break;
+		}
+	}
+
+	chip->onfi_version = 0;
+	if (!type->name || !type->pagesize) {
+		/* Check if the chip is ONFI compliant */
+		if (nand_flash_detect_onfi(chip))
+			goto ident_done;
+
+		/* Check if the chip is JEDEC compliant */
+		if (nand_flash_detect_jedec(chip))
+			goto ident_done;
+	}
+
+	if (!type->name)
+		return -ENODEV;
+
+	if (!mtd->name)
+		mtd->name = type->name;
+
+	chip->chipsize = (uint64_t)type->chipsize << 20;
+
+	if (!type->pagesize)
+		nand_manufacturer_detect(chip);
+	else
+		nand_decode_id(chip, type);
+
+	/* Get chip options */
+	chip->options |= type->options;
+
+ident_done:
+
+	if (chip->options & NAND_BUSWIDTH_AUTO) {
+		WARN_ON(busw & NAND_BUSWIDTH_16);
+		nand_set_defaults(chip);
+	} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+		/*
+		 * Check, if buswidth is correct. Hardware drivers should set
+		 * chip correct!
+		 */
+		pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
+			maf_id, dev_id);
+		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+			mtd->name);
+		pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
+			(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
+		return -EINVAL;
+	}
+
+	nand_decode_bbm_options(chip);
+
+	/* Calculate the address shift from the page size */
+	chip->page_shift = ffs(mtd->writesize) - 1;
+	/* Convert chipsize to number of pages per chip -1 */
+	chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+
+	chip->bbt_erase_shift = chip->phys_erase_shift =
+		ffs(mtd->erasesize) - 1;
+	if (chip->chipsize & 0xffffffff)
+		chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
+	else {
+		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
+		chip->chip_shift += 32 - 1;
+	}
+
+	if (chip->chip_shift - chip->page_shift > 16)
+		chip->options |= NAND_ROW_ADDR_3;
+
+	chip->badblockbits = 8;
+	chip->erase = single_erase;
+
+	/* Do not replace user supplied command function! */
+	if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+		chip->cmdfunc = nand_command_lp;
+
+	pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
+		maf_id, dev_id);
+
+	if (chip->onfi_version)
+		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+			chip->onfi_params.model);
+	else if (chip->jedec_version)
+		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+			chip->jedec_params.model);
+	else
+		pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+			type->name);
+
+	pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
+		(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
+		mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
+	return 0;
+}
+
+static const char * const nand_ecc_modes[] = {
+	[NAND_ECC_NONE]		= "none",
+	[NAND_ECC_SOFT]		= "soft",
+	[NAND_ECC_HW]		= "hw",
+	[NAND_ECC_HW_SYNDROME]	= "hw_syndrome",
+	[NAND_ECC_HW_OOB_FIRST]	= "hw_oob_first",
+	[NAND_ECC_ON_DIE]	= "on-die",
+};
+
+static int of_get_nand_ecc_mode(struct device_node *np)
+{
+	const char *pm;
+	int err, i;
+
+	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+		if (!strcasecmp(pm, nand_ecc_modes[i]))
+			return i;
+
+	/*
+	 * For backward compatibility we support few obsoleted values that don't
+	 * have their mappings into nand_ecc_modes_t anymore (they were merged
+	 * with other enums).
+	 */
+	if (!strcasecmp(pm, "soft_bch"))
+		return NAND_ECC_SOFT;
+
+	return -ENODEV;
+}
+
+static const char * const nand_ecc_algos[] = {
+	[NAND_ECC_HAMMING]	= "hamming",
+	[NAND_ECC_BCH]		= "bch",
+};
+
+static int of_get_nand_ecc_algo(struct device_node *np)
+{
+	const char *pm;
+	int err, i;
+
+	err = of_property_read_string(np, "nand-ecc-algo", &pm);
+	if (!err) {
+		for (i = NAND_ECC_HAMMING; i < ARRAY_SIZE(nand_ecc_algos); i++)
+			if (!strcasecmp(pm, nand_ecc_algos[i]))
+				return i;
+		return -ENODEV;
+	}
+
+	/*
+	 * For backward compatibility we also read "nand-ecc-mode" checking
+	 * for some obsoleted values that were specifying ECC algorithm.
+	 */
+	err = of_property_read_string(np, "nand-ecc-mode", &pm);
+	if (err < 0)
+		return err;
+
+	if (!strcasecmp(pm, "soft"))
+		return NAND_ECC_HAMMING;
+	else if (!strcasecmp(pm, "soft_bch"))
+		return NAND_ECC_BCH;
+
+	return -ENODEV;
+}
+
+static int of_get_nand_ecc_step_size(struct device_node *np)
+{
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
+	return ret ? ret : val;
+}
+
+static int of_get_nand_ecc_strength(struct device_node *np)
+{
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
+	return ret ? ret : val;
+}
+
+static int of_get_nand_bus_width(struct device_node *np)
+{
+	u32 val;
+
+	if (of_property_read_u32(np, "nand-bus-width", &val))
+		return 8;
+
+	switch (val) {
+	case 8:
+	case 16:
+		return val;
+	default:
+		return -EIO;
+	}
+}
+
+static bool of_get_nand_on_flash_bbt(struct device_node *np)
+{
+	return of_property_read_bool(np, "nand-on-flash-bbt");
+}
+
+static int nand_dt_init(struct nand_chip *chip)
+{
+	struct device_node *dn = nand_get_flash_node(chip);
+	int ecc_mode, ecc_algo, ecc_strength, ecc_step;
+
+	if (!dn)
+		return 0;
+
+	if (of_get_nand_bus_width(dn) == 16)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	if (of_get_nand_on_flash_bbt(dn))
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	ecc_mode = of_get_nand_ecc_mode(dn);
+	ecc_algo = of_get_nand_ecc_algo(dn);
+	ecc_strength = of_get_nand_ecc_strength(dn);
+	ecc_step = of_get_nand_ecc_step_size(dn);
+
+	if (ecc_mode >= 0)
+		chip->ecc.mode = ecc_mode;
+
+	if (ecc_algo >= 0)
+		chip->ecc.algo = ecc_algo;
+
+	if (ecc_strength >= 0)
+		chip->ecc.strength = ecc_strength;
+
+	if (ecc_step > 0)
+		chip->ecc.size = ecc_step;
+
+	if (of_property_read_bool(dn, "nand-ecc-maximize"))
+		chip->ecc.options |= NAND_ECC_MAXIMIZE;
+
+	return 0;
+}
+
+/**
+ * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: number of chips to scan for
+ * @table: alternative NAND ID table
+ *
+ * This is the first phase of the normal nand_scan() function. It reads the
+ * flash ID and sets up MTD fields accordingly.
+ *
+ */
+int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+		    struct nand_flash_dev *table)
+{
+	int i, nand_maf_id, nand_dev_id;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	/* Enforce the right timings for reset/detection */
+	onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
+
+	ret = nand_dt_init(chip);
+	if (ret)
+		return ret;
+
+	if (!mtd->name && mtd->dev.parent)
+		mtd->name = dev_name(mtd->dev.parent);
+
+	/*
+	 * ->cmdfunc() is legacy and will only be used if ->exec_op() is not
+	 * populated.
+	 */
+	if (!chip->exec_op) {
+		/*
+		 * Default functions assigned for ->cmdfunc() and
+		 * ->select_chip() both expect ->cmd_ctrl() to be populated.
+		 */
+		if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
+			pr_err("->cmd_ctrl() should be provided\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Set the default functions */
+	nand_set_defaults(chip);
+
+	/* Read the flash type */
+	ret = nand_detect(chip, table);
+	if (ret) {
+		if (!(chip->options & NAND_SCAN_SILENT_NODEV))
+			pr_warn("No NAND device found\n");
+		chip->select_chip(mtd, -1);
+		return ret;
+	}
+
+	nand_maf_id = chip->id.data[0];
+	nand_dev_id = chip->id.data[1];
+
+	chip->select_chip(mtd, -1);
+
+	/* Check for a chip array */
+	for (i = 1; i < maxchips; i++) {
+		u8 id[2];
+
+		/* See comment in nand_get_flash_type for reset */
+		nand_reset(chip, i);
+
+		chip->select_chip(mtd, i);
+		/* Send the command for reading device ID */
+		nand_readid_op(chip, 0, id, sizeof(id));
+		/* Read manufacturer and device IDs */
+		if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
+			chip->select_chip(mtd, -1);
+			break;
+		}
+		chip->select_chip(mtd, -1);
+	}
+	if (i > 1)
+		pr_info("%d chips detected\n", i);
+
+	/* Store the number of chips and calc total size for mtd */
+	chip->numchips = i;
+	mtd->size = i * chip->chipsize;
+
+	return 0;
+}
+EXPORT_SYMBOL(nand_scan_ident);
+
+static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
+		return -EINVAL;
+
+	switch (ecc->algo) {
+	case NAND_ECC_HAMMING:
+		ecc->calculate = nand_calculate_ecc;
+		ecc->correct = nand_correct_data;
+		ecc->read_page = nand_read_page_swecc;
+		ecc->read_subpage = nand_read_subpage;
+		ecc->write_page = nand_write_page_swecc;
+		ecc->read_page_raw = nand_read_page_raw;
+		ecc->write_page_raw = nand_write_page_raw;
+		ecc->read_oob = nand_read_oob_std;
+		ecc->write_oob = nand_write_oob_std;
+		if (!ecc->size)
+			ecc->size = 256;
+		ecc->bytes = 3;
+		ecc->strength = 1;
+		return 0;
+	case NAND_ECC_BCH:
+		if (!mtd_nand_has_bch()) {
+			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+			return -EINVAL;
+		}
+		ecc->calculate = nand_bch_calculate_ecc;
+		ecc->correct = nand_bch_correct_data;
+		ecc->read_page = nand_read_page_swecc;
+		ecc->read_subpage = nand_read_subpage;
+		ecc->write_page = nand_write_page_swecc;
+		ecc->read_page_raw = nand_read_page_raw;
+		ecc->write_page_raw = nand_write_page_raw;
+		ecc->read_oob = nand_read_oob_std;
+		ecc->write_oob = nand_write_oob_std;
+
+		/*
+		* Board driver should supply ecc.size and ecc.strength
+		* values to select how many bits are correctable.
+		* Otherwise, default to 4 bits for large page devices.
+		*/
+		if (!ecc->size && (mtd->oobsize >= 64)) {
+			ecc->size = 512;
+			ecc->strength = 4;
+		}
+
+		/*
+		 * if no ecc placement scheme was provided pickup the default
+		 * large page one.
+		 */
+		if (!mtd->ooblayout) {
+			/* handle large page devices only */
+			if (mtd->oobsize < 64) {
+				WARN(1, "OOB layout is required when using software BCH on small pages\n");
+				return -EINVAL;
+			}
+
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+
+		}
+
+		/*
+		 * We can only maximize ECC config when the default layout is
+		 * used, otherwise we don't know how many bytes can really be
+		 * used.
+		 */
+		if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
+		    ecc->options & NAND_ECC_MAXIMIZE) {
+			int steps, bytes;
+
+			/* Always prefer 1k blocks over 512bytes ones */
+			ecc->size = 1024;
+			steps = mtd->writesize / ecc->size;
+
+			/* Reserve 2 bytes for the BBM */
+			bytes = (mtd->oobsize - 2) / steps;
+			ecc->strength = bytes * 8 / fls(8 * ecc->size);
+		}
+
+		/* See nand_bch_init() for details. */
+		ecc->bytes = 0;
+		ecc->priv = nand_bch_init(mtd);
+		if (!ecc->priv) {
+			WARN(1, "BCH ECC initialization failed!\n");
+			return -EINVAL;
+		}
+		return 0;
+	default:
+		WARN(1, "Unsupported ECC algorithm!\n");
+		return -EINVAL;
+	}
+}
+
+/**
+ * nand_check_ecc_caps - check the sanity of preset ECC settings
+ * @chip: nand chip info structure
+ * @caps: ECC caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * When ECC step size and strength are already set, check if they are supported
+ * by the controller and the calculated ECC bytes fit within the chip's OOB.
+ * On success, the calculated ECC bytes is set.
+ */
+int nand_check_ecc_caps(struct nand_chip *chip,
+			const struct nand_ecc_caps *caps, int oobavail)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_ecc_step_info *stepinfo;
+	int preset_step = chip->ecc.size;
+	int preset_strength = chip->ecc.strength;
+	int nsteps, ecc_bytes;
+	int i, j;
+
+	if (WARN_ON(oobavail < 0))
+		return -EINVAL;
+
+	if (!preset_step || !preset_strength)
+		return -ENODATA;
+
+	nsteps = mtd->writesize / preset_step;
+
+	for (i = 0; i < caps->nstepinfos; i++) {
+		stepinfo = &caps->stepinfos[i];
+
+		if (stepinfo->stepsize != preset_step)
+			continue;
+
+		for (j = 0; j < stepinfo->nstrengths; j++) {
+			if (stepinfo->strengths[j] != preset_strength)
+				continue;
+
+			ecc_bytes = caps->calc_ecc_bytes(preset_step,
+							 preset_strength);
+			if (WARN_ON_ONCE(ecc_bytes < 0))
+				return ecc_bytes;
+
+			if (ecc_bytes * nsteps > oobavail) {
+				pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
+				       preset_step, preset_strength);
+				return -ENOSPC;
+			}
+
+			chip->ecc.bytes = ecc_bytes;
+
+			return 0;
+		}
+	}
+
+	pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
+	       preset_step, preset_strength);
+
+	return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
+
+/**
+ * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * If a chip's ECC requirement is provided, try to meet it with the least
+ * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
+ * On success, the chosen ECC settings are set.
+ */
+int nand_match_ecc_req(struct nand_chip *chip,
+		       const struct nand_ecc_caps *caps, int oobavail)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_ecc_step_info *stepinfo;
+	int req_step = chip->ecc_step_ds;
+	int req_strength = chip->ecc_strength_ds;
+	int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
+	int best_step, best_strength, best_ecc_bytes;
+	int best_ecc_bytes_total = INT_MAX;
+	int i, j;
+
+	if (WARN_ON(oobavail < 0))
+		return -EINVAL;
+
+	/* No information provided by the NAND chip */
+	if (!req_step || !req_strength)
+		return -ENOTSUPP;
+
+	/* number of correctable bits the chip requires in a page */
+	req_corr = mtd->writesize / req_step * req_strength;
+
+	for (i = 0; i < caps->nstepinfos; i++) {
+		stepinfo = &caps->stepinfos[i];
+		step_size = stepinfo->stepsize;
+
+		for (j = 0; j < stepinfo->nstrengths; j++) {
+			strength = stepinfo->strengths[j];
+
+			/*
+			 * If both step size and strength are smaller than the
+			 * chip's requirement, it is not easy to compare the
+			 * resulted reliability.
+			 */
+			if (step_size < req_step && strength < req_strength)
+				continue;
+
+			if (mtd->writesize % step_size)
+				continue;
+
+			nsteps = mtd->writesize / step_size;
+
+			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+			if (WARN_ON_ONCE(ecc_bytes < 0))
+				continue;
+			ecc_bytes_total = ecc_bytes * nsteps;
+
+			if (ecc_bytes_total > oobavail ||
+			    strength * nsteps < req_corr)
+				continue;
+
+			/*
+			 * We assume the best is to meet the chip's requrement
+			 * with the least number of ECC bytes.
+			 */
+			if (ecc_bytes_total < best_ecc_bytes_total) {
+				best_ecc_bytes_total = ecc_bytes_total;
+				best_step = step_size;
+				best_strength = strength;
+				best_ecc_bytes = ecc_bytes;
+			}
+		}
+	}
+
+	if (best_ecc_bytes_total == INT_MAX)
+		return -ENOTSUPP;
+
+	chip->ecc.size = best_step;
+	chip->ecc.strength = best_strength;
+	chip->ecc.bytes = best_ecc_bytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_match_ecc_req);
+
+/**
+ * nand_maximize_ecc - choose the max ECC strength available
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * Choose the max ECC strength that is supported on the controller, and can fit
+ * within the chip's OOB.  On success, the chosen ECC settings are set.
+ */
+int nand_maximize_ecc(struct nand_chip *chip,
+		      const struct nand_ecc_caps *caps, int oobavail)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_ecc_step_info *stepinfo;
+	int step_size, strength, nsteps, ecc_bytes, corr;
+	int best_corr = 0;
+	int best_step = 0;
+	int best_strength, best_ecc_bytes;
+	int i, j;
+
+	if (WARN_ON(oobavail < 0))
+		return -EINVAL;
+
+	for (i = 0; i < caps->nstepinfos; i++) {
+		stepinfo = &caps->stepinfos[i];
+		step_size = stepinfo->stepsize;
+
+		/* If chip->ecc.size is already set, respect it */
+		if (chip->ecc.size && step_size != chip->ecc.size)
+			continue;
+
+		for (j = 0; j < stepinfo->nstrengths; j++) {
+			strength = stepinfo->strengths[j];
+
+			if (mtd->writesize % step_size)
+				continue;
+
+			nsteps = mtd->writesize / step_size;
+
+			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+			if (WARN_ON_ONCE(ecc_bytes < 0))
+				continue;
+
+			if (ecc_bytes * nsteps > oobavail)
+				continue;
+
+			corr = strength * nsteps;
+
+			/*
+			 * If the number of correctable bits is the same,
+			 * bigger step_size has more reliability.
+			 */
+			if (corr > best_corr ||
+			    (corr == best_corr && step_size > best_step)) {
+				best_corr = corr;
+				best_step = step_size;
+				best_strength = strength;
+				best_ecc_bytes = ecc_bytes;
+			}
+		}
+	}
+
+	if (!best_corr)
+		return -ENOTSUPP;
+
+	chip->ecc.size = best_step;
+	chip->ecc.strength = best_strength;
+	chip->ecc.bytes = best_ecc_bytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_maximize_ecc);
+
+/*
+ * Check if the chip configuration meet the datasheet requirements.
+
+ * If our configuration corrects A bits per B bytes and the minimum
+ * required correction level is X bits per Y bytes, then we must ensure
+ * both of the following are true:
+ *
+ * (1) A / B >= X / Y
+ * (2) A >= X
+ *
+ * Requirement (1) ensures we can correct for the required bitflip density.
+ * Requirement (2) ensures we can correct even when all bitflips are clumped
+ * in the same sector.
+ */
+static bool nand_ecc_strength_good(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int corr, ds_corr;
+
+	if (ecc->size == 0 || chip->ecc_step_ds == 0)
+		/* Not enough information */
+		return true;
+
+	/*
+	 * We get the number of corrected bits per page to compare
+	 * the correction density.
+	 */
+	corr = (mtd->writesize * ecc->strength) / ecc->size;
+	ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds;
+
+	return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
+}
+
+/**
+ * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ *
+ * This is the second phase of the normal nand_scan() function. It fills out
+ * all the uninitialized function pointers with the defaults and scans for a
+ * bad block table if appropriate.
+ */
+int nand_scan_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret, i;
+
+	/* New bad blocks should be marked in OOB, flash-based BBT, or both */
+	if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+		   !(chip->bbt_options & NAND_BBT_USE_FLASH))) {
+		return -EINVAL;
+	}
+
+	chip->data_buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+	if (!chip->data_buf)
+		return -ENOMEM;
+
+	/*
+	 * FIXME: some NAND manufacturer drivers expect the first die to be
+	 * selected when manufacturer->init() is called. They should be fixed
+	 * to explictly select the relevant die when interacting with the NAND
+	 * chip.
+	 */
+	chip->select_chip(mtd, 0);
+	ret = nand_manufacturer_init(chip);
+	chip->select_chip(mtd, -1);
+	if (ret)
+		goto err_free_buf;
+
+	/* Set the internal oob buffer location, just after the page data */
+	chip->oob_poi = chip->data_buf + mtd->writesize;
+
+	/*
+	 * If no default placement scheme is given, select an appropriate one.
+	 */
+	if (!mtd->ooblayout &&
+	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
+		switch (mtd->oobsize) {
+		case 8:
+		case 16:
+			mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
+			break;
+		case 64:
+		case 128:
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
+			break;
+		default:
+			/*
+			 * Expose the whole OOB area to users if ECC_NONE
+			 * is passed. We could do that for all kind of
+			 * ->oobsize, but we must keep the old large/small
+			 * page with ECC layout when ->oobsize <= 128 for
+			 * compatibility reasons.
+			 */
+			if (ecc->mode == NAND_ECC_NONE) {
+				mtd_set_ooblayout(mtd,
+						&nand_ooblayout_lp_ops);
+				break;
+			}
+
+			WARN(1, "No oob scheme defined for oobsize %d\n",
+				mtd->oobsize);
+			ret = -EINVAL;
+			goto err_nand_manuf_cleanup;
+		}
+	}
+
+	/*
+	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
+	 * selected and we have 256 byte pagesize fallback to software ECC
+	 */
+
+	switch (ecc->mode) {
+	case NAND_ECC_HW_OOB_FIRST:
+		/* Similar to NAND_ECC_HW, but a separate read_page handle */
+		if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
+			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+			ret = -EINVAL;
+			goto err_nand_manuf_cleanup;
+		}
+		if (!ecc->read_page)
+			ecc->read_page = nand_read_page_hwecc_oob_first;
+
+	case NAND_ECC_HW:
+		/* Use standard hwecc read page function? */
+		if (!ecc->read_page)
+			ecc->read_page = nand_read_page_hwecc;
+		if (!ecc->write_page)
+			ecc->write_page = nand_write_page_hwecc;
+		if (!ecc->read_page_raw)
+			ecc->read_page_raw = nand_read_page_raw;
+		if (!ecc->write_page_raw)
+			ecc->write_page_raw = nand_write_page_raw;
+		if (!ecc->read_oob)
+			ecc->read_oob = nand_read_oob_std;
+		if (!ecc->write_oob)
+			ecc->write_oob = nand_write_oob_std;
+		if (!ecc->read_subpage)
+			ecc->read_subpage = nand_read_subpage;
+		if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
+			ecc->write_subpage = nand_write_subpage_hwecc;
+
+	case NAND_ECC_HW_SYNDROME:
+		if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
+		    (!ecc->read_page ||
+		     ecc->read_page == nand_read_page_hwecc ||
+		     !ecc->write_page ||
+		     ecc->write_page == nand_write_page_hwecc)) {
+			WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+			ret = -EINVAL;
+			goto err_nand_manuf_cleanup;
+		}
+		/* Use standard syndrome read/write page function? */
+		if (!ecc->read_page)
+			ecc->read_page = nand_read_page_syndrome;
+		if (!ecc->write_page)
+			ecc->write_page = nand_write_page_syndrome;
+		if (!ecc->read_page_raw)
+			ecc->read_page_raw = nand_read_page_raw_syndrome;
+		if (!ecc->write_page_raw)
+			ecc->write_page_raw = nand_write_page_raw_syndrome;
+		if (!ecc->read_oob)
+			ecc->read_oob = nand_read_oob_syndrome;
+		if (!ecc->write_oob)
+			ecc->write_oob = nand_write_oob_syndrome;
+
+		if (mtd->writesize >= ecc->size) {
+			if (!ecc->strength) {
+				WARN(1, "Driver must set ecc.strength when using hardware ECC\n");
+				ret = -EINVAL;
+				goto err_nand_manuf_cleanup;
+			}
+			break;
+		}
+		pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
+			ecc->size, mtd->writesize);
+		ecc->mode = NAND_ECC_SOFT;
+		ecc->algo = NAND_ECC_HAMMING;
+
+	case NAND_ECC_SOFT:
+		ret = nand_set_ecc_soft_ops(mtd);
+		if (ret) {
+			ret = -EINVAL;
+			goto err_nand_manuf_cleanup;
+		}
+		break;
+
+	case NAND_ECC_ON_DIE:
+		if (!ecc->read_page || !ecc->write_page) {
+			WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
+			ret = -EINVAL;
+			goto err_nand_manuf_cleanup;
+		}
+		if (!ecc->read_oob)
+			ecc->read_oob = nand_read_oob_std;
+		if (!ecc->write_oob)
+			ecc->write_oob = nand_write_oob_std;
+		break;
+
+	case NAND_ECC_NONE:
+		pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
+		ecc->read_page = nand_read_page_raw;
+		ecc->write_page = nand_write_page_raw;
+		ecc->read_oob = nand_read_oob_std;
+		ecc->read_page_raw = nand_read_page_raw;
+		ecc->write_page_raw = nand_write_page_raw;
+		ecc->write_oob = nand_write_oob_std;
+		ecc->size = mtd->writesize;
+		ecc->bytes = 0;
+		ecc->strength = 0;
+		break;
+
+	default:
+		WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode);
+		ret = -EINVAL;
+		goto err_nand_manuf_cleanup;
+	}
+
+	if (ecc->correct || ecc->calculate) {
+		ecc->calc_buf = kmalloc(mtd->oobsize, GFP_KERNEL);
+		ecc->code_buf = kmalloc(mtd->oobsize, GFP_KERNEL);
+		if (!ecc->calc_buf || !ecc->code_buf) {
+			ret = -ENOMEM;
+			goto err_nand_manuf_cleanup;
+		}
+	}
+
+	/* For many systems, the standard OOB write also works for raw */
+	if (!ecc->read_oob_raw)
+		ecc->read_oob_raw = ecc->read_oob;
+	if (!ecc->write_oob_raw)
+		ecc->write_oob_raw = ecc->write_oob;
+
+	/* propagate ecc info to mtd_info */
+	mtd->ecc_strength = ecc->strength;
+	mtd->ecc_step_size = ecc->size;
+
+	/*
+	 * Set the number of read / write steps for one page depending on ECC
+	 * mode.
+	 */
+	ecc->steps = mtd->writesize / ecc->size;
+	if (ecc->steps * ecc->size != mtd->writesize) {
+		WARN(1, "Invalid ECC parameters\n");
+		ret = -EINVAL;
+		goto err_nand_manuf_cleanup;
+	}
+	ecc->total = ecc->steps * ecc->bytes;
+	if (ecc->total > mtd->oobsize) {
+		WARN(1, "Total number of ECC bytes exceeded oobsize\n");
+		ret = -EINVAL;
+		goto err_nand_manuf_cleanup;
+	}
+
+	/*
+	 * The number of bytes available for a client to place data into
+	 * the out of band area.
+	 */
+	ret = mtd_ooblayout_count_freebytes(mtd);
+	if (ret < 0)
+		ret = 0;
+
+	mtd->oobavail = ret;
+
+	/* ECC sanity check: warn if it's too weak */
+	if (!nand_ecc_strength_good(mtd))
+		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
+			mtd->name);
+
+	/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
+	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
+		switch (ecc->steps) {
+		case 2:
+			mtd->subpage_sft = 1;
+			break;
+		case 4:
+		case 8:
+		case 16:
+			mtd->subpage_sft = 2;
+			break;
+		}
+	}
+	chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
+
+	/* Initialize state */
+	chip->state = FL_READY;
+
+	/* Invalidate the pagebuffer reference */
+	chip->pagebuf = -1;
+
+	/* Large page NAND with SOFT_ECC should support subpage reads */
+	switch (ecc->mode) {
+	case NAND_ECC_SOFT:
+		if (chip->page_shift > 9)
+			chip->options |= NAND_SUBPAGE_READ;
+		break;
+
+	default:
+		break;
+	}
+
+	/* Fill in remaining MTD driver data */
+	mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
+	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
+						MTD_CAP_NANDFLASH;
+	mtd->_erase = nand_erase;
+	mtd->_point = NULL;
+	mtd->_unpoint = NULL;
+	mtd->_panic_write = panic_nand_write;
+	mtd->_read_oob = nand_read_oob;
+	mtd->_write_oob = nand_write_oob;
+	mtd->_sync = nand_sync;
+	mtd->_lock = NULL;
+	mtd->_unlock = NULL;
+	mtd->_suspend = nand_suspend;
+	mtd->_resume = nand_resume;
+	mtd->_reboot = nand_shutdown;
+	mtd->_block_isreserved = nand_block_isreserved;
+	mtd->_block_isbad = nand_block_isbad;
+	mtd->_block_markbad = nand_block_markbad;
+	mtd->_max_bad_blocks = nand_max_bad_blocks;
+	mtd->writebufsize = mtd->writesize;
+
+	/*
+	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
+	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+	 * properly set.
+	 */
+	if (!mtd->bitflip_threshold)
+		mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
+
+	/* Initialize the ->data_interface field. */
+	ret = nand_init_data_interface(chip);
+	if (ret)
+		goto err_nand_manuf_cleanup;
+
+	/* Enter fastest possible mode on all dies. */
+	for (i = 0; i < chip->numchips; i++) {
+		chip->select_chip(mtd, i);
+		ret = nand_setup_data_interface(chip, i);
+		chip->select_chip(mtd, -1);
+
+		if (ret)
+			goto err_nand_manuf_cleanup;
+	}
+
+	/* Check, if we should skip the bad block table scan */
+	if (chip->options & NAND_SKIP_BBTSCAN)
+		return 0;
+
+	/* Build bad block table */
+	ret = chip->scan_bbt(mtd);
+	if (ret)
+		goto err_nand_manuf_cleanup;
+
+	return 0;
+
+
+err_nand_manuf_cleanup:
+	nand_manufacturer_cleanup(chip);
+
+err_free_buf:
+	kfree(chip->data_buf);
+	kfree(ecc->code_buf);
+	kfree(ecc->calc_buf);
+
+	return ret;
+}
+EXPORT_SYMBOL(nand_scan_tail);
+
+/*
+ * is_module_text_address() isn't exported, and it's mostly a pointless
+ * test if this is a module _anyway_ -- they'd have to try _really_ hard
+ * to call us from in-kernel code if the core NAND support is modular.
+ */
+#ifdef MODULE
+#define caller_is_module() (1)
+#else
+#define caller_is_module() \
+	is_module_text_address((unsigned long)__builtin_return_address(0))
+#endif
+
+/**
+ * nand_scan - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: number of chips to scan for
+ *
+ * This fills out all the uninitialized function pointers with the defaults.
+ * The flash ID is read and the mtd/chip structures are filled with the
+ * appropriate values.
+ */
+int nand_scan(struct mtd_info *mtd, int maxchips)
+{
+	int ret;
+
+	ret = nand_scan_ident(mtd, maxchips, NULL);
+	if (!ret)
+		ret = nand_scan_tail(mtd);
+	return ret;
+}
+EXPORT_SYMBOL(nand_scan);
+
+/**
+ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+ * @chip: NAND chip object
+ */
+void nand_cleanup(struct nand_chip *chip)
+{
+	if (chip->ecc.mode == NAND_ECC_SOFT &&
+	    chip->ecc.algo == NAND_ECC_BCH)
+		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+
+	/* Free bad block table memory */
+	kfree(chip->bbt);
+	kfree(chip->data_buf);
+	kfree(chip->ecc.code_buf);
+	kfree(chip->ecc.calc_buf);
+
+	/* Free bad block descriptor memory */
+	if (chip->badblock_pattern && chip->badblock_pattern->options
+			& NAND_BBT_DYNAMICSTRUCT)
+		kfree(chip->badblock_pattern);
+
+	/* Free manufacturer priv data. */
+	nand_manufacturer_cleanup(chip);
+}
+EXPORT_SYMBOL_GPL(nand_cleanup);
+
+/**
+ * nand_release - [NAND Interface] Unregister the MTD device and free resources
+ *		  held by the NAND device
+ * @mtd: MTD device structure
+ */
+void nand_release(struct mtd_info *mtd)
+{
+	mtd_device_unregister(mtd);
+	nand_cleanup(mtd_to_nand(mtd));
+}
+EXPORT_SYMBOL_GPL(nand_release);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Generic NAND flash driver code");
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
new file mode 100644
index 000000000000..36092850be2c
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_bbt.c
@@ -0,0 +1,1452 @@
+/*
+ *  Overview:
+ *   Bad block table support for the NAND driver
+ *
+ *  Copyright © 2004 Thomas Gleixner (tglx@linutronix.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.
+ *
+ * Description:
+ *
+ * When nand_scan_bbt is called, then it tries to find the bad block table
+ * depending on the options in the BBT descriptor(s). If no flash based BBT
+ * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
+ * marked good / bad blocks. This information is used to create a memory BBT.
+ * Once a new bad block is discovered then the "factory" information is updated
+ * on the device.
+ * If a flash based BBT is specified then the function first tries to find the
+ * BBT on flash. If a BBT is found then the contents are read and the memory
+ * based BBT is created. If a mirrored BBT is selected then the mirror is
+ * searched too and the versions are compared. If the mirror has a greater
+ * version number, then the mirror BBT is used to build the memory based BBT.
+ * If the tables are not versioned, then we "or" the bad block information.
+ * If one of the BBTs is out of date or does not exist it is (re)created.
+ * If no BBT exists at all then the device is scanned for factory marked
+ * good / bad blocks and the bad block tables are created.
+ *
+ * For manufacturer created BBTs like the one found on M-SYS DOC devices
+ * the BBT is searched and read but never created
+ *
+ * The auto generated bad block table is located in the last good blocks
+ * of the device. The table is mirrored, so it can be updated eventually.
+ * The table is marked in the OOB area with an ident pattern and a version
+ * number which indicates which of both tables is more up to date. If the NAND
+ * controller needs the complete OOB area for the ECC information then the
+ * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
+ * course): it moves the ident pattern and the version byte into the data area
+ * and the OOB area will remain untouched.
+ *
+ * The table uses 2 bits per block
+ * 11b:		block is good
+ * 00b:		block is factory marked bad
+ * 01b, 10b:	block is marked bad due to wear
+ *
+ * The memory bad block table uses the following scheme:
+ * 00b:		block is good
+ * 01b:		block is marked bad due to wear
+ * 10b:		block is reserved (to protect the bbt area)
+ * 11b:		block is factory marked bad
+ *
+ * Multichip devices like DOC store the bad block info per floor.
+ *
+ * Following assumptions are made:
+ * - bbts start at a page boundary, if autolocated on a block boundary
+ * - the space necessary for a bbt in FLASH does not exceed a block boundary
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/bbm.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/export.h>
+#include <linux/string.h>
+
+#define BBT_BLOCK_GOOD		0x00
+#define BBT_BLOCK_WORN		0x01
+#define BBT_BLOCK_RESERVED	0x02
+#define BBT_BLOCK_FACTORY_BAD	0x03
+
+#define BBT_ENTRY_MASK		0x03
+#define BBT_ENTRY_SHIFT		2
+
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
+
+static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
+{
+	uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
+	entry >>= (block & BBT_ENTRY_MASK) * 2;
+	return entry & BBT_ENTRY_MASK;
+}
+
+static inline void bbt_mark_entry(struct nand_chip *chip, int block,
+		uint8_t mark)
+{
+	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
+	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+}
+
+static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
+{
+	if (memcmp(buf, td->pattern, td->len))
+		return -1;
+	return 0;
+}
+
+/**
+ * check_pattern - [GENERIC] check if a pattern is in the buffer
+ * @buf: the buffer to search
+ * @len: the length of buffer to search
+ * @paglen: the pagelength
+ * @td: search pattern descriptor
+ *
+ * Check for a pattern at the given place. Used to search bad block tables and
+ * good / bad block identifiers.
+ */
+static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
+{
+	if (td->options & NAND_BBT_NO_OOB)
+		return check_pattern_no_oob(buf, td);
+
+	/* Compare the pattern */
+	if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
+		return -1;
+
+	return 0;
+}
+
+/**
+ * check_short_pattern - [GENERIC] check if a pattern is in the buffer
+ * @buf: the buffer to search
+ * @td:	search pattern descriptor
+ *
+ * Check for a pattern at the given place. Used to search bad block tables and
+ * good / bad block identifiers. Same as check_pattern, but no optional empty
+ * check.
+ */
+static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
+{
+	/* Compare the pattern */
+	if (memcmp(buf + td->offs, td->pattern, td->len))
+		return -1;
+	return 0;
+}
+
+/**
+ * add_marker_len - compute the length of the marker in data area
+ * @td: BBT descriptor used for computation
+ *
+ * The length will be 0 if the marker is located in OOB area.
+ */
+static u32 add_marker_len(struct nand_bbt_descr *td)
+{
+	u32 len;
+
+	if (!(td->options & NAND_BBT_NO_OOB))
+		return 0;
+
+	len = td->len;
+	if (td->options & NAND_BBT_VERSION)
+		len++;
+	return len;
+}
+
+/**
+ * read_bbt - [GENERIC] Read the bad block table starting from page
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @page: the starting page
+ * @num: the number of bbt descriptors to read
+ * @td: the bbt describtion table
+ * @offs: block number offset in the table
+ *
+ * Read the bad block table starting from page.
+ */
+static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
+		struct nand_bbt_descr *td, int offs)
+{
+	int res, ret = 0, i, j, act = 0;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	size_t retlen, len, totlen;
+	loff_t from;
+	int bits = td->options & NAND_BBT_NRBITS_MSK;
+	uint8_t msk = (uint8_t)((1 << bits) - 1);
+	u32 marker_len;
+	int reserved_block_code = td->reserved_block_code;
+
+	totlen = (num * bits) >> 3;
+	marker_len = add_marker_len(td);
+	from = ((loff_t)page) << this->page_shift;
+
+	while (totlen) {
+		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
+		if (marker_len) {
+			/*
+			 * In case the BBT marker is not in the OOB area it
+			 * will be just in the first page.
+			 */
+			len -= marker_len;
+			from += marker_len;
+			marker_len = 0;
+		}
+		res = mtd_read(mtd, from, len, &retlen, buf);
+		if (res < 0) {
+			if (mtd_is_eccerr(res)) {
+				pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
+					from & ~mtd->writesize);
+				return res;
+			} else if (mtd_is_bitflip(res)) {
+				pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
+					from & ~mtd->writesize);
+				ret = res;
+			} else {
+				pr_info("nand_bbt: error reading BBT\n");
+				return res;
+			}
+		}
+
+		/* Analyse data */
+		for (i = 0; i < len; i++) {
+			uint8_t dat = buf[i];
+			for (j = 0; j < 8; j += bits, act++) {
+				uint8_t tmp = (dat >> j) & msk;
+				if (tmp == msk)
+					continue;
+				if (reserved_block_code && (tmp == reserved_block_code)) {
+					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
+						 (loff_t)(offs + act) <<
+						 this->bbt_erase_shift);
+					bbt_mark_entry(this, offs + act,
+							BBT_BLOCK_RESERVED);
+					mtd->ecc_stats.bbtblocks++;
+					continue;
+				}
+				/*
+				 * Leave it for now, if it's matured we can
+				 * move this message to pr_debug.
+				 */
+				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
+					 (loff_t)(offs + act) <<
+					 this->bbt_erase_shift);
+				/* Factory marked bad or worn out? */
+				if (tmp == 0)
+					bbt_mark_entry(this, offs + act,
+							BBT_BLOCK_FACTORY_BAD);
+				else
+					bbt_mark_entry(this, offs + act,
+							BBT_BLOCK_WORN);
+				mtd->ecc_stats.badblocks++;
+			}
+		}
+		totlen -= len;
+		from += len;
+	}
+	return ret;
+}
+
+/**
+ * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @chip: read the table for a specific chip, -1 read all chips; applies only if
+ *        NAND_BBT_PERCHIP option is set
+ *
+ * Read the bad block table for all chips starting at a given page. We assume
+ * that the bbt bits are in consecutive order.
+ */
+static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int res = 0, i;
+
+	if (td->options & NAND_BBT_PERCHIP) {
+		int offs = 0;
+		for (i = 0; i < this->numchips; i++) {
+			if (chip == -1 || chip == i)
+				res = read_bbt(mtd, buf, td->pages[i],
+					this->chipsize >> this->bbt_erase_shift,
+					td, offs);
+			if (res)
+				return res;
+			offs += this->chipsize >> this->bbt_erase_shift;
+		}
+	} else {
+		res = read_bbt(mtd, buf, td->pages[0],
+				mtd->size >> this->bbt_erase_shift, td, 0);
+		if (res)
+			return res;
+	}
+	return 0;
+}
+
+/* BBT marker is in the first page, no OOB */
+static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+			 struct nand_bbt_descr *td)
+{
+	size_t retlen;
+	size_t len;
+
+	len = td->len;
+	if (td->options & NAND_BBT_VERSION)
+		len++;
+
+	return mtd_read(mtd, offs, len, &retlen, buf);
+}
+
+/**
+ * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @offs: offset at which to scan
+ * @len: length of data region to read
+ *
+ * Scan read data from data+OOB. May traverse multiple pages, interleaving
+ * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
+ * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
+ */
+static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+			 size_t len)
+{
+	struct mtd_oob_ops ops;
+	int res, ret = 0;
+
+	ops.mode = MTD_OPS_PLACE_OOB;
+	ops.ooboffs = 0;
+	ops.ooblen = mtd->oobsize;
+
+	while (len > 0) {
+		ops.datbuf = buf;
+		ops.len = min(len, (size_t)mtd->writesize);
+		ops.oobbuf = buf + ops.len;
+
+		res = mtd_read_oob(mtd, offs, &ops);
+		if (res) {
+			if (!mtd_is_bitflip_or_eccerr(res))
+				return res;
+			else if (mtd_is_eccerr(res) || !ret)
+				ret = res;
+		}
+
+		buf += mtd->oobsize + mtd->writesize;
+		len -= mtd->writesize;
+		offs += mtd->writesize;
+	}
+	return ret;
+}
+
+static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+			 size_t len, struct nand_bbt_descr *td)
+{
+	if (td->options & NAND_BBT_NO_OOB)
+		return scan_read_data(mtd, buf, offs, td);
+	else
+		return scan_read_oob(mtd, buf, offs, len);
+}
+
+/* Scan write data with oob to flash */
+static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
+			  uint8_t *buf, uint8_t *oob)
+{
+	struct mtd_oob_ops ops;
+
+	ops.mode = MTD_OPS_PLACE_OOB;
+	ops.ooboffs = 0;
+	ops.ooblen = mtd->oobsize;
+	ops.datbuf = buf;
+	ops.oobbuf = oob;
+	ops.len = len;
+
+	return mtd_write_oob(mtd, offs, &ops);
+}
+
+static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+{
+	u32 ver_offs = td->veroffs;
+
+	if (!(td->options & NAND_BBT_NO_OOB))
+		ver_offs += mtd->writesize;
+	return ver_offs;
+}
+
+/**
+ * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @md:	descriptor for the bad block table mirror
+ *
+ * Read the bad block table(s) for all chips starting at a given page. We
+ * assume that the bbt bits are in consecutive order.
+ */
+static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	/* Read the primary version, if available */
+	if (td->options & NAND_BBT_VERSION) {
+		scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+			      mtd->writesize, td);
+		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
+		pr_info("Bad block table at page %d, version 0x%02X\n",
+			 td->pages[0], td->version[0]);
+	}
+
+	/* Read the mirror version, if available */
+	if (md && (md->options & NAND_BBT_VERSION)) {
+		scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+			      mtd->writesize, md);
+		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
+		pr_info("Bad block table at page %d, version 0x%02X\n",
+			 md->pages[0], md->version[0]);
+	}
+}
+
+/* Scan a given block partially */
+static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+			   loff_t offs, uint8_t *buf, int numpages)
+{
+	struct mtd_oob_ops ops;
+	int j, ret;
+
+	ops.ooblen = mtd->oobsize;
+	ops.oobbuf = buf;
+	ops.ooboffs = 0;
+	ops.datbuf = NULL;
+	ops.mode = MTD_OPS_PLACE_OOB;
+
+	for (j = 0; j < numpages; j++) {
+		/*
+		 * Read the full oob until read_oob is fixed to handle single
+		 * byte reads for 16 bit buswidth.
+		 */
+		ret = mtd_read_oob(mtd, offs, &ops);
+		/* Ignore ECC errors when checking for BBM */
+		if (ret && !mtd_is_bitflip_or_eccerr(ret))
+			return ret;
+
+		if (check_short_pattern(buf, bd))
+			return 1;
+
+		offs += mtd->writesize;
+	}
+	return 0;
+}
+
+/**
+ * create_bbt - [GENERIC] Create a bad block table by scanning the device
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @bd: descriptor for the good/bad block search pattern
+ * @chip: create the table for a specific chip, -1 read all chips; applies only
+ *        if NAND_BBT_PERCHIP option is set
+ *
+ * Create a bad block table by scanning the device for the given good/bad block
+ * identify pattern.
+ */
+static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
+	struct nand_bbt_descr *bd, int chip)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int i, numblocks, numpages;
+	int startblock;
+	loff_t from;
+
+	pr_info("Scanning device for bad blocks\n");
+
+	if (bd->options & NAND_BBT_SCAN2NDPAGE)
+		numpages = 2;
+	else
+		numpages = 1;
+
+	if (chip == -1) {
+		numblocks = mtd->size >> this->bbt_erase_shift;
+		startblock = 0;
+		from = 0;
+	} else {
+		if (chip >= this->numchips) {
+			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
+			       chip + 1, this->numchips);
+			return -EINVAL;
+		}
+		numblocks = this->chipsize >> this->bbt_erase_shift;
+		startblock = chip * numblocks;
+		numblocks += startblock;
+		from = (loff_t)startblock << this->bbt_erase_shift;
+	}
+
+	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
+		from += mtd->erasesize - (mtd->writesize * numpages);
+
+	for (i = startblock; i < numblocks; i++) {
+		int ret;
+
+		BUG_ON(bd->options & NAND_BBT_NO_OOB);
+
+		ret = scan_block_fast(mtd, bd, from, buf, numpages);
+		if (ret < 0)
+			return ret;
+
+		if (ret) {
+			bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
+			pr_warn("Bad eraseblock %d at 0x%012llx\n",
+				i, (unsigned long long)from);
+			mtd->ecc_stats.badblocks++;
+		}
+
+		from += (1 << this->bbt_erase_shift);
+	}
+	return 0;
+}
+
+/**
+ * search_bbt - [GENERIC] scan the device for a specific bad block table
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ *
+ * Read the bad block table by searching for a given ident pattern. Search is
+ * preformed either from the beginning up or from the end of the device
+ * downwards. The search starts always at the start of a block. If the option
+ * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
+ * the bad block information of this chip. This is necessary to provide support
+ * for certain DOC devices.
+ *
+ * The bbt ident pattern resides in the oob area of the first page in a block.
+ */
+static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int i, chips;
+	int startblock, block, dir;
+	int scanlen = mtd->writesize + mtd->oobsize;
+	int bbtblocks;
+	int blocktopage = this->bbt_erase_shift - this->page_shift;
+
+	/* Search direction top -> down? */
+	if (td->options & NAND_BBT_LASTBLOCK) {
+		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
+		dir = -1;
+	} else {
+		startblock = 0;
+		dir = 1;
+	}
+
+	/* Do we have a bbt per chip? */
+	if (td->options & NAND_BBT_PERCHIP) {
+		chips = this->numchips;
+		bbtblocks = this->chipsize >> this->bbt_erase_shift;
+		startblock &= bbtblocks - 1;
+	} else {
+		chips = 1;
+		bbtblocks = mtd->size >> this->bbt_erase_shift;
+	}
+
+	for (i = 0; i < chips; i++) {
+		/* Reset version information */
+		td->version[i] = 0;
+		td->pages[i] = -1;
+		/* Scan the maximum number of blocks */
+		for (block = 0; block < td->maxblocks; block++) {
+
+			int actblock = startblock + dir * block;
+			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
+
+			/* Read first page */
+			scan_read(mtd, buf, offs, mtd->writesize, td);
+			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
+				td->pages[i] = actblock << blocktopage;
+				if (td->options & NAND_BBT_VERSION) {
+					offs = bbt_get_ver_offs(mtd, td);
+					td->version[i] = buf[offs];
+				}
+				break;
+			}
+		}
+		startblock += this->chipsize >> this->bbt_erase_shift;
+	}
+	/* Check, if we found a bbt for each requested chip */
+	for (i = 0; i < chips; i++) {
+		if (td->pages[i] == -1)
+			pr_warn("Bad block table not found for chip %d\n", i);
+		else
+			pr_info("Bad block table found at page %d, version 0x%02X\n",
+				td->pages[i], td->version[i]);
+	}
+	return 0;
+}
+
+/**
+ * search_read_bbts - [GENERIC] scan the device for bad block table(s)
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @md: descriptor for the bad block table mirror
+ *
+ * Search and read the bad block table(s).
+ */
+static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+			     struct nand_bbt_descr *td,
+			     struct nand_bbt_descr *md)
+{
+	/* Search the primary table */
+	search_bbt(mtd, buf, td);
+
+	/* Search the mirror table */
+	if (md)
+		search_bbt(mtd, buf, md);
+}
+
+/**
+ * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
+ * @this: the NAND device
+ * @td: the BBT description
+ * @md: the mirror BBT descriptor
+ * @chip: the CHIP selector
+ *
+ * This functions returns a positive block number pointing a valid eraseblock
+ * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
+ * all blocks are already used of marked bad. If td->pages[chip] was already
+ * pointing to a valid block we re-use it, otherwise we search for the next
+ * valid one.
+ */
+static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
+			 struct nand_bbt_descr *md, int chip)
+{
+	int startblock, dir, page, numblocks, i;
+
+	/*
+	 * There was already a version of the table, reuse the page. This
+	 * applies for absolute placement too, as we have the page number in
+	 * td->pages.
+	 */
+	if (td->pages[chip] != -1)
+		return td->pages[chip] >>
+				(this->bbt_erase_shift - this->page_shift);
+
+	numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+	if (!(td->options & NAND_BBT_PERCHIP))
+		numblocks *= this->numchips;
+
+	/*
+	 * Automatic placement of the bad block table. Search direction
+	 * top -> down?
+	 */
+	if (td->options & NAND_BBT_LASTBLOCK) {
+		startblock = numblocks * (chip + 1) - 1;
+		dir = -1;
+	} else {
+		startblock = chip * numblocks;
+		dir = 1;
+	}
+
+	for (i = 0; i < td->maxblocks; i++) {
+		int block = startblock + dir * i;
+
+		/* Check, if the block is bad */
+		switch (bbt_get_entry(this, block)) {
+		case BBT_BLOCK_WORN:
+		case BBT_BLOCK_FACTORY_BAD:
+			continue;
+		}
+
+		page = block << (this->bbt_erase_shift - this->page_shift);
+
+		/* Check, if the block is used by the mirror table */
+		if (!md || md->pages[chip] != page)
+			return block;
+	}
+
+	return -ENOSPC;
+}
+
+/**
+ * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
+ * @this: the NAND device
+ * @td: the BBT description
+ * @chip: the CHIP selector
+ * @block: the BBT block to mark
+ *
+ * Blocks reserved for BBT can become bad. This functions is an helper to mark
+ * such blocks as bad. It takes care of updating the in-memory BBT, marking the
+ * block as bad using a bad block marker and invalidating the associated
+ * td->pages[] entry.
+ */
+static void mark_bbt_block_bad(struct nand_chip *this,
+			       struct nand_bbt_descr *td,
+			       int chip, int block)
+{
+	struct mtd_info *mtd = nand_to_mtd(this);
+	loff_t to;
+	int res;
+
+	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+	to = (loff_t)block << this->bbt_erase_shift;
+	res = this->block_markbad(mtd, to);
+	if (res)
+		pr_warn("nand_bbt: error %d while marking block %d bad\n",
+			res, block);
+
+	td->pages[chip] = -1;
+}
+
+/**
+ * write_bbt - [GENERIC] (Re)write the bad block table
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @td: descriptor for the bad block table
+ * @md: descriptor for the bad block table mirror
+ * @chipsel: selector for a specific chip, -1 for all
+ *
+ * (Re)write the bad block table.
+ */
+static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
+		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
+		     int chipsel)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct erase_info einfo;
+	int i, res, chip = 0;
+	int bits, page, offs, numblocks, sft, sftmsk;
+	int nrchips, pageoffs, ooboffs;
+	uint8_t msk[4];
+	uint8_t rcode = td->reserved_block_code;
+	size_t retlen, len = 0;
+	loff_t to;
+	struct mtd_oob_ops ops;
+
+	ops.ooblen = mtd->oobsize;
+	ops.ooboffs = 0;
+	ops.datbuf = NULL;
+	ops.mode = MTD_OPS_PLACE_OOB;
+
+	if (!rcode)
+		rcode = 0xff;
+	/* Write bad block table per chip rather than per device? */
+	if (td->options & NAND_BBT_PERCHIP) {
+		numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+		/* Full device write or specific chip? */
+		if (chipsel == -1) {
+			nrchips = this->numchips;
+		} else {
+			nrchips = chipsel + 1;
+			chip = chipsel;
+		}
+	} else {
+		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
+		nrchips = 1;
+	}
+
+	/* Loop through the chips */
+	while (chip < nrchips) {
+		int block;
+
+		block = get_bbt_block(this, td, md, chip);
+		if (block < 0) {
+			pr_err("No space left to write bad block table\n");
+			res = block;
+			goto outerr;
+		}
+
+		/*
+		 * get_bbt_block() returns a block number, shift the value to
+		 * get a page number.
+		 */
+		page = block << (this->bbt_erase_shift - this->page_shift);
+
+		/* Set up shift count and masks for the flash table */
+		bits = td->options & NAND_BBT_NRBITS_MSK;
+		msk[2] = ~rcode;
+		switch (bits) {
+		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
+			msk[3] = 0x01;
+			break;
+		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
+			msk[3] = 0x03;
+			break;
+		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
+			msk[3] = 0x0f;
+			break;
+		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
+			msk[3] = 0xff;
+			break;
+		default: return -EINVAL;
+		}
+
+		to = ((loff_t)page) << this->page_shift;
+
+		/* Must we save the block contents? */
+		if (td->options & NAND_BBT_SAVECONTENT) {
+			/* Make it block aligned */
+			to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
+			len = 1 << this->bbt_erase_shift;
+			res = mtd_read(mtd, to, len, &retlen, buf);
+			if (res < 0) {
+				if (retlen != len) {
+					pr_info("nand_bbt: error reading block for writing the bad block table\n");
+					return res;
+				}
+				pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n");
+			}
+			/* Read oob data */
+			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
+			ops.oobbuf = &buf[len];
+			res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
+			if (res < 0 || ops.oobretlen != ops.ooblen)
+				goto outerr;
+
+			/* Calc the byte offset in the buffer */
+			pageoffs = page - (int)(to >> this->page_shift);
+			offs = pageoffs << this->page_shift;
+			/* Preset the bbt area with 0xff */
+			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
+			ooboffs = len + (pageoffs * mtd->oobsize);
+
+		} else if (td->options & NAND_BBT_NO_OOB) {
+			ooboffs = 0;
+			offs = td->len;
+			/* The version byte */
+			if (td->options & NAND_BBT_VERSION)
+				offs++;
+			/* Calc length */
+			len = (size_t)(numblocks >> sft);
+			len += offs;
+			/* Make it page aligned! */
+			len = ALIGN(len, mtd->writesize);
+			/* Preset the buffer with 0xff */
+			memset(buf, 0xff, len);
+			/* Pattern is located at the begin of first page */
+			memcpy(buf, td->pattern, td->len);
+		} else {
+			/* Calc length */
+			len = (size_t)(numblocks >> sft);
+			/* Make it page aligned! */
+			len = ALIGN(len, mtd->writesize);
+			/* Preset the buffer with 0xff */
+			memset(buf, 0xff, len +
+			       (len >> this->page_shift)* mtd->oobsize);
+			offs = 0;
+			ooboffs = len;
+			/* Pattern is located in oob area of first page */
+			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
+		}
+
+		if (td->options & NAND_BBT_VERSION)
+			buf[ooboffs + td->veroffs] = td->version[chip];
+
+		/* Walk through the memory table */
+		for (i = 0; i < numblocks; i++) {
+			uint8_t dat;
+			int sftcnt = (i << (3 - sft)) & sftmsk;
+			dat = bbt_get_entry(this, chip * numblocks + i);
+			/* Do not store the reserved bbt blocks! */
+			buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
+		}
+
+		memset(&einfo, 0, sizeof(einfo));
+		einfo.mtd = mtd;
+		einfo.addr = to;
+		einfo.len = 1 << this->bbt_erase_shift;
+		res = nand_erase_nand(mtd, &einfo, 1);
+		if (res < 0) {
+			pr_warn("nand_bbt: error while erasing BBT block %d\n",
+				res);
+			mark_bbt_block_bad(this, td, chip, block);
+			continue;
+		}
+
+		res = scan_write_bbt(mtd, to, len, buf,
+				td->options & NAND_BBT_NO_OOB ? NULL :
+				&buf[len]);
+		if (res < 0) {
+			pr_warn("nand_bbt: error while writing BBT block %d\n",
+				res);
+			mark_bbt_block_bad(this, td, chip, block);
+			continue;
+		}
+
+		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
+			 (unsigned long long)to, td->version[chip]);
+
+		/* Mark it as used */
+		td->pages[chip++] = page;
+	}
+	return 0;
+
+ outerr:
+	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
+	return res;
+}
+
+/**
+ * nand_memory_bbt - [GENERIC] create a memory based bad block table
+ * @mtd: MTD device structure
+ * @bd: descriptor for the good/bad block search pattern
+ *
+ * The function creates a memory based bbt by scanning the device for
+ * manufacturer / software marked good / bad blocks.
+ */
+static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+
+	return create_bbt(mtd, this->data_buf, bd, -1);
+}
+
+/**
+ * check_create - [GENERIC] create and write bbt(s) if necessary
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @bd: descriptor for the good/bad block search pattern
+ *
+ * The function checks the results of the previous call to read_bbt and creates
+ * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
+ * for the chip/device. Update is necessary if one of the tables is missing or
+ * the version nr. of one table is less than the other.
+ */
+static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+{
+	int i, chips, writeops, create, chipsel, res, res2;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct nand_bbt_descr *td = this->bbt_td;
+	struct nand_bbt_descr *md = this->bbt_md;
+	struct nand_bbt_descr *rd, *rd2;
+
+	/* Do we have a bbt per chip? */
+	if (td->options & NAND_BBT_PERCHIP)
+		chips = this->numchips;
+	else
+		chips = 1;
+
+	for (i = 0; i < chips; i++) {
+		writeops = 0;
+		create = 0;
+		rd = NULL;
+		rd2 = NULL;
+		res = res2 = 0;
+		/* Per chip or per device? */
+		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
+		/* Mirrored table available? */
+		if (md) {
+			if (td->pages[i] == -1 && md->pages[i] == -1) {
+				create = 1;
+				writeops = 0x03;
+			} else if (td->pages[i] == -1) {
+				rd = md;
+				writeops = 0x01;
+			} else if (md->pages[i] == -1) {
+				rd = td;
+				writeops = 0x02;
+			} else if (td->version[i] == md->version[i]) {
+				rd = td;
+				if (!(td->options & NAND_BBT_VERSION))
+					rd2 = md;
+			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
+				rd = td;
+				writeops = 0x02;
+			} else {
+				rd = md;
+				writeops = 0x01;
+			}
+		} else {
+			if (td->pages[i] == -1) {
+				create = 1;
+				writeops = 0x01;
+			} else {
+				rd = td;
+			}
+		}
+
+		if (create) {
+			/* Create the bad block table by scanning the device? */
+			if (!(td->options & NAND_BBT_CREATE))
+				continue;
+
+			/* Create the table in memory by scanning the chip(s) */
+			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
+				create_bbt(mtd, buf, bd, chipsel);
+
+			td->version[i] = 1;
+			if (md)
+				md->version[i] = 1;
+		}
+
+		/* Read back first? */
+		if (rd) {
+			res = read_abs_bbt(mtd, buf, rd, chipsel);
+			if (mtd_is_eccerr(res)) {
+				/* Mark table as invalid */
+				rd->pages[i] = -1;
+				rd->version[i] = 0;
+				i--;
+				continue;
+			}
+		}
+		/* If they weren't versioned, read both */
+		if (rd2) {
+			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+			if (mtd_is_eccerr(res2)) {
+				/* Mark table as invalid */
+				rd2->pages[i] = -1;
+				rd2->version[i] = 0;
+				i--;
+				continue;
+			}
+		}
+
+		/* Scrub the flash table(s)? */
+		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
+			writeops = 0x03;
+
+		/* Update version numbers before writing */
+		if (md) {
+			td->version[i] = max(td->version[i], md->version[i]);
+			md->version[i] = td->version[i];
+		}
+
+		/* Write the bad block table to the device? */
+		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
+			res = write_bbt(mtd, buf, td, md, chipsel);
+			if (res < 0)
+				return res;
+		}
+
+		/* Write the mirror bad block table to the device? */
+		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
+			res = write_bbt(mtd, buf, md, td, chipsel);
+			if (res < 0)
+				return res;
+		}
+	}
+	return 0;
+}
+
+/**
+ * mark_bbt_regions - [GENERIC] mark the bad block table regions
+ * @mtd: MTD device structure
+ * @td: bad block table descriptor
+ *
+ * The bad block table regions are marked as "bad" to prevent accidental
+ * erasures / writes. The regions are identified by the mark 0x02.
+ */
+static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int i, j, chips, block, nrblocks, update;
+	uint8_t oldval;
+
+	/* Do we have a bbt per chip? */
+	if (td->options & NAND_BBT_PERCHIP) {
+		chips = this->numchips;
+		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+	} else {
+		chips = 1;
+		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
+	}
+
+	for (i = 0; i < chips; i++) {
+		if ((td->options & NAND_BBT_ABSPAGE) ||
+		    !(td->options & NAND_BBT_WRITE)) {
+			if (td->pages[i] == -1)
+				continue;
+			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
+			oldval = bbt_get_entry(this, block);
+			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+			if ((oldval != BBT_BLOCK_RESERVED) &&
+					td->reserved_block_code)
+				nand_update_bbt(mtd, (loff_t)block <<
+						this->bbt_erase_shift);
+			continue;
+		}
+		update = 0;
+		if (td->options & NAND_BBT_LASTBLOCK)
+			block = ((i + 1) * nrblocks) - td->maxblocks;
+		else
+			block = i * nrblocks;
+		for (j = 0; j < td->maxblocks; j++) {
+			oldval = bbt_get_entry(this, block);
+			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+			if (oldval != BBT_BLOCK_RESERVED)
+				update = 1;
+			block++;
+		}
+		/*
+		 * If we want reserved blocks to be recorded to flash, and some
+		 * new ones have been marked, then we need to update the stored
+		 * bbts.  This should only happen once.
+		 */
+		if (update && td->reserved_block_code)
+			nand_update_bbt(mtd, (loff_t)(block - 1) <<
+					this->bbt_erase_shift);
+	}
+}
+
+/**
+ * verify_bbt_descr - verify the bad block description
+ * @mtd: MTD device structure
+ * @bd: the table to verify
+ *
+ * This functions performs a few sanity checks on the bad block description
+ * table.
+ */
+static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	u32 pattern_len;
+	u32 bits;
+	u32 table_size;
+
+	if (!bd)
+		return;
+
+	pattern_len = bd->len;
+	bits = bd->options & NAND_BBT_NRBITS_MSK;
+
+	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
+			!(this->bbt_options & NAND_BBT_USE_FLASH));
+	BUG_ON(!bits);
+
+	if (bd->options & NAND_BBT_VERSION)
+		pattern_len++;
+
+	if (bd->options & NAND_BBT_NO_OOB) {
+		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
+		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
+		BUG_ON(bd->offs);
+		if (bd->options & NAND_BBT_VERSION)
+			BUG_ON(bd->veroffs != bd->len);
+		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
+	}
+
+	if (bd->options & NAND_BBT_PERCHIP)
+		table_size = this->chipsize >> this->bbt_erase_shift;
+	else
+		table_size = mtd->size >> this->bbt_erase_shift;
+	table_size >>= 3;
+	table_size *= bits;
+	if (bd->options & NAND_BBT_NO_OOB)
+		table_size += pattern_len;
+	BUG_ON(table_size > (1 << this->bbt_erase_shift));
+}
+
+/**
+ * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
+ * @mtd: MTD device structure
+ * @bd: descriptor for the good/bad block search pattern
+ *
+ * The function checks, if a bad block table(s) is/are already available. If
+ * not it scans the device for manufacturer marked good / bad blocks and writes
+ * the bad block table(s) to the selected place.
+ *
+ * The bad block table memory is allocated here. It must be freed by calling
+ * the nand_free_bbt function.
+ */
+static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int len, res;
+	uint8_t *buf;
+	struct nand_bbt_descr *td = this->bbt_td;
+	struct nand_bbt_descr *md = this->bbt_md;
+
+	len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
+	/*
+	 * Allocate memory (2bit per block) and clear the memory bad block
+	 * table.
+	 */
+	this->bbt = kzalloc(len, GFP_KERNEL);
+	if (!this->bbt)
+		return -ENOMEM;
+
+	/*
+	 * If no primary table decriptor is given, scan the device to build a
+	 * memory based bad block table.
+	 */
+	if (!td) {
+		if ((res = nand_memory_bbt(mtd, bd))) {
+			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
+			goto err;
+		}
+		return 0;
+	}
+	verify_bbt_descr(mtd, td);
+	verify_bbt_descr(mtd, md);
+
+	/* Allocate a temporary buffer for one eraseblock incl. oob */
+	len = (1 << this->bbt_erase_shift);
+	len += (len >> this->page_shift) * mtd->oobsize;
+	buf = vmalloc(len);
+	if (!buf) {
+		res = -ENOMEM;
+		goto err;
+	}
+
+	/* Is the bbt at a given page? */
+	if (td->options & NAND_BBT_ABSPAGE) {
+		read_abs_bbts(mtd, buf, td, md);
+	} else {
+		/* Search the bad block table using a pattern in oob */
+		search_read_bbts(mtd, buf, td, md);
+	}
+
+	res = check_create(mtd, buf, bd);
+	if (res)
+		goto err;
+
+	/* Prevent the bbt regions from erasing / writing */
+	mark_bbt_region(mtd, td);
+	if (md)
+		mark_bbt_region(mtd, md);
+
+	vfree(buf);
+	return 0;
+
+err:
+	kfree(this->bbt);
+	this->bbt = NULL;
+	return res;
+}
+
+/**
+ * nand_update_bbt - update bad block table(s)
+ * @mtd: MTD device structure
+ * @offs: the offset of the newly marked block
+ *
+ * The function updates the bad block table(s).
+ */
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int len, res = 0;
+	int chip, chipsel;
+	uint8_t *buf;
+	struct nand_bbt_descr *td = this->bbt_td;
+	struct nand_bbt_descr *md = this->bbt_md;
+
+	if (!this->bbt || !td)
+		return -EINVAL;
+
+	/* Allocate a temporary buffer for one eraseblock incl. oob */
+	len = (1 << this->bbt_erase_shift);
+	len += (len >> this->page_shift) * mtd->oobsize;
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* Do we have a bbt per chip? */
+	if (td->options & NAND_BBT_PERCHIP) {
+		chip = (int)(offs >> this->chip_shift);
+		chipsel = chip;
+	} else {
+		chip = 0;
+		chipsel = -1;
+	}
+
+	td->version[chip]++;
+	if (md)
+		md->version[chip]++;
+
+	/* Write the bad block table to the device? */
+	if (td->options & NAND_BBT_WRITE) {
+		res = write_bbt(mtd, buf, td, md, chipsel);
+		if (res < 0)
+			goto out;
+	}
+	/* Write the mirror bad block table to the device? */
+	if (md && (md->options & NAND_BBT_WRITE)) {
+		res = write_bbt(mtd, buf, md, td, chipsel);
+	}
+
+ out:
+	kfree(buf);
+	return res;
+}
+
+/*
+ * Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks.
+ */
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+/* Generic flash bbt descriptors */
+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	8,
+	.len = 4,
+	.veroffs = 12,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+	.offs =	8,
+	.len = 4,
+	.veroffs = 12,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = mirror_pattern
+};
+
+static struct nand_bbt_descr bbt_main_no_oob_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+		| NAND_BBT_NO_OOB,
+	.len = 4,
+	.veroffs = 4,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+		| NAND_BBT_NO_OOB,
+	.len = 4,
+	.veroffs = 4,
+	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
+	.pattern = mirror_pattern
+};
+
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
+/**
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
+ * @this: NAND chip to create descriptor for
+ *
+ * This function allocates and initializes a nand_bbt_descr for BBM detection
+ * based on the properties of @this. The new descriptor is stored in
+ * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
+ * passed to this function.
+ */
+static int nand_create_badblock_pattern(struct nand_chip *this)
+{
+	struct nand_bbt_descr *bd;
+	if (this->badblock_pattern) {
+		pr_warn("Bad block pattern already allocated; not replacing\n");
+		return -EINVAL;
+	}
+	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+	if (!bd)
+		return -ENOMEM;
+	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
+	bd->offs = this->badblockpos;
+	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
+	bd->pattern = scan_ff_pattern;
+	bd->options |= NAND_BBT_DYNAMICSTRUCT;
+	this->badblock_pattern = bd;
+	return 0;
+}
+
+/**
+ * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
+ * @mtd: MTD device structure
+ *
+ * This function selects the default bad block table support for the device and
+ * calls the nand_scan_bbt function.
+ */
+int nand_default_bbt(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int ret;
+
+	/* Is a flash based bad block table requested? */
+	if (this->bbt_options & NAND_BBT_USE_FLASH) {
+		/* Use the default pattern descriptors */
+		if (!this->bbt_td) {
+			if (this->bbt_options & NAND_BBT_NO_OOB) {
+				this->bbt_td = &bbt_main_no_oob_descr;
+				this->bbt_md = &bbt_mirror_no_oob_descr;
+			} else {
+				this->bbt_td = &bbt_main_descr;
+				this->bbt_md = &bbt_mirror_descr;
+			}
+		}
+	} else {
+		this->bbt_td = NULL;
+		this->bbt_md = NULL;
+	}
+
+	if (!this->badblock_pattern) {
+		ret = nand_create_badblock_pattern(this);
+		if (ret)
+			return ret;
+	}
+
+	return nand_scan_bbt(mtd, this->badblock_pattern);
+}
+
+/**
+ * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
+ * @mtd: MTD device structure
+ * @offs: offset in the device
+ */
+int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int block;
+
+	block = (int)(offs >> this->bbt_erase_shift);
+	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
+}
+
+/**
+ * nand_isbad_bbt - [NAND Interface] Check if a block is bad
+ * @mtd: MTD device structure
+ * @offs: offset in the device
+ * @allowbbt: allow access to bad block table region
+ */
+int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int block, res;
+
+	block = (int)(offs >> this->bbt_erase_shift);
+	res = bbt_get_entry(this, block);
+
+	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+		 (unsigned int)offs, block, res);
+
+	switch (res) {
+	case BBT_BLOCK_GOOD:
+		return 0;
+	case BBT_BLOCK_WORN:
+		return 1;
+	case BBT_BLOCK_RESERVED:
+		return allowbbt ? 0 : 1;
+	}
+	return 1;
+}
+
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the bad block
+ */
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	int block, ret = 0;
+
+	block = (int)(offs >> this->bbt_erase_shift);
+
+	/* Mark bad block in memory */
+	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+	/* Update flash-based bad block table */
+	if (this->bbt_options & NAND_BBT_USE_FLASH)
+		ret = nand_update_bbt(mtd, offs);
+
+	return ret;
+}
diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
new file mode 100644
index 000000000000..505441c9373b
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_bch.c
@@ -0,0 +1,234 @@
+/*
+ * This file provides ECC correction for more than 1 bit per block of data,
+ * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
+ *
+ * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_bch.h>
+#include <linux/bch.h>
+
+/**
+ * struct nand_bch_control - private NAND BCH control structure
+ * @bch:       BCH control structure
+ * @errloc:    error location array
+ * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
+ */
+struct nand_bch_control {
+	struct bch_control   *bch;
+	unsigned int         *errloc;
+	unsigned char        *eccmask;
+};
+
+/**
+ * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
+ * @mtd:	MTD block structure
+ * @buf:	input buffer with raw data
+ * @code:	output buffer with ECC
+ */
+int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+			   unsigned char *code)
+{
+	const struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_bch_control *nbc = chip->ecc.priv;
+	unsigned int i;
+
+	memset(code, 0, chip->ecc.bytes);
+	encode_bch(nbc->bch, buf, chip->ecc.size, code);
+
+	/* apply mask so that an erased page is a valid codeword */
+	for (i = 0; i < chip->ecc.bytes; i++)
+		code[i] ^= nbc->eccmask[i];
+
+	return 0;
+}
+EXPORT_SYMBOL(nand_bch_calculate_ecc);
+
+/**
+ * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd:	MTD block structure
+ * @buf:	raw data read from the chip
+ * @read_ecc:	ECC from the chip
+ * @calc_ecc:	the ECC calculated from raw data
+ *
+ * Detect and correct bit errors for a data byte block
+ */
+int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+			  unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+	const struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_bch_control *nbc = chip->ecc.priv;
+	unsigned int *errloc = nbc->errloc;
+	int i, count;
+
+	count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
+			   NULL, errloc);
+	if (count > 0) {
+		for (i = 0; i < count; i++) {
+			if (errloc[i] < (chip->ecc.size*8))
+				/* error is located in data, correct it */
+				buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
+			/* else error in ecc, no action needed */
+
+			pr_debug("%s: corrected bitflip %u\n", __func__,
+					errloc[i]);
+		}
+	} else if (count < 0) {
+		printk(KERN_ERR "ecc unrecoverable error\n");
+		count = -EBADMSG;
+	}
+	return count;
+}
+EXPORT_SYMBOL(nand_bch_correct_data);
+
+/**
+ * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
+ * @mtd:	MTD block structure
+ *
+ * Returns:
+ *  a pointer to a new NAND BCH control structure, or NULL upon failure
+ *
+ * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
+ * are used to compute BCH parameters m (Galois field order) and t (error
+ * correction capability). @eccbytes should be equal to the number of bytes
+ * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
+ *
+ * Example: to configure 4 bit correction per 512 bytes, you should pass
+ * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
+ * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits)
+ */
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	unsigned int m, t, eccsteps, i;
+	struct nand_bch_control *nbc = NULL;
+	unsigned char *erased_page;
+	unsigned int eccsize = nand->ecc.size;
+	unsigned int eccbytes = nand->ecc.bytes;
+	unsigned int eccstrength = nand->ecc.strength;
+
+	if (!eccbytes && eccstrength) {
+		eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
+		nand->ecc.bytes = eccbytes;
+	}
+
+	if (!eccsize || !eccbytes) {
+		printk(KERN_WARNING "ecc parameters not supplied\n");
+		goto fail;
+	}
+
+	m = fls(1+8*eccsize);
+	t = (eccbytes*8)/m;
+
+	nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
+	if (!nbc)
+		goto fail;
+
+	nbc->bch = init_bch(m, t, 0);
+	if (!nbc->bch)
+		goto fail;
+
+	/* verify that eccbytes has the expected value */
+	if (nbc->bch->ecc_bytes != eccbytes) {
+		printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
+		       eccbytes, nbc->bch->ecc_bytes);
+		goto fail;
+	}
+
+	eccsteps = mtd->writesize/eccsize;
+
+	/* Check that we have an oob layout description. */
+	if (!mtd->ooblayout) {
+		pr_warn("missing oob scheme");
+		goto fail;
+	}
+
+	/* sanity checks */
+	if (8*(eccsize+eccbytes) >= (1 << m)) {
+		printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
+		goto fail;
+	}
+
+	/*
+	 * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(),
+	 * which is called by mtd_ooblayout_count_eccbytes().
+	 * Make sure they are properly initialized before calling
+	 * mtd_ooblayout_count_eccbytes().
+	 * FIXME: we should probably rework the sequencing in nand_scan_tail()
+	 * to avoid setting those fields twice.
+	 */
+	nand->ecc.steps = eccsteps;
+	nand->ecc.total = eccsteps * eccbytes;
+	if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
+		printk(KERN_WARNING "invalid ecc layout\n");
+		goto fail;
+	}
+
+	nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
+	nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
+	if (!nbc->eccmask || !nbc->errloc)
+		goto fail;
+	/*
+	 * compute and store the inverted ecc of an erased ecc block
+	 */
+	erased_page = kmalloc(eccsize, GFP_KERNEL);
+	if (!erased_page)
+		goto fail;
+
+	memset(erased_page, 0xff, eccsize);
+	memset(nbc->eccmask, 0, eccbytes);
+	encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
+	kfree(erased_page);
+
+	for (i = 0; i < eccbytes; i++)
+		nbc->eccmask[i] ^= 0xff;
+
+	if (!eccstrength)
+		nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
+
+	return nbc;
+fail:
+	nand_bch_free(nbc);
+	return NULL;
+}
+EXPORT_SYMBOL(nand_bch_init);
+
+/**
+ * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
+ * @nbc:	NAND BCH control structure
+ */
+void nand_bch_free(struct nand_bch_control *nbc)
+{
+	if (nbc) {
+		free_bch(nbc->bch);
+		kfree(nbc->errloc);
+		kfree(nbc->eccmask);
+		kfree(nbc);
+	}
+}
+EXPORT_SYMBOL(nand_bch_free);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
+MODULE_DESCRIPTION("NAND software BCH ECC support");
diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
new file mode 100644
index 000000000000..3630f0fe8fa4
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_ecc.c
@@ -0,0 +1,531 @@
+/*
+ * This file contains an ECC algorithm that detects and corrects 1 bit
+ * errors in a 256 byte block of data.
+ *
+ * Copyright © 2008 Koninklijke Philips Electronics NV.
+ *                  Author: Frans Meulenbroeks
+ *
+ * Completely replaces the previous ECC implementation which was written by:
+ *   Steven J. Hill (sjhill@realitydiluted.com)
+ *   Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Information on how this algorithm works and how it was developed
+ * can be found in Documentation/mtd/nand_ecc.txt
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+/*
+ * The STANDALONE macro is useful when running the code outside the kernel
+ * e.g. when running the code in a testbed or a benchmark program.
+ * When STANDALONE is used, the module related macros are commented out
+ * as well as the linux include files.
+ * Instead a private definition of mtd_info is given to satisfy the compiler
+ * (the code does not use mtd_info, so the code does not care)
+ */
+#ifndef STANDALONE
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/byteorder.h>
+#else
+#include <stdint.h>
+struct mtd_info;
+#define EXPORT_SYMBOL(x)  /* x */
+
+#define MODULE_LICENSE(x)	/* x */
+#define MODULE_AUTHOR(x)	/* x */
+#define MODULE_DESCRIPTION(x)	/* x */
+
+#define pr_err printf
+#endif
+
+/*
+ * invparity is a 256 byte table that contains the odd parity
+ * for each byte. So if the number of bits in a byte is even,
+ * the array element is 1, and when the number of bits is odd
+ * the array eleemnt is 0.
+ */
+static const char invparity[256] = {
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+};
+
+/*
+ * bitsperbyte contains the number of bits per byte
+ * this is only used for testing and repairing parity
+ * (a precalculated value slightly improves performance)
+ */
+static const char bitsperbyte[256] = {
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+};
+
+/*
+ * addressbits is a lookup table to filter out the bits from the xor-ed
+ * ECC data that identify the faulty location.
+ * this is only used for repairing parity
+ * see the comments in nand_correct_data for more details
+ */
+static const char addressbits[256] = {
+	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
+};
+
+/**
+ * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ *			 block
+ * @buf:	input buffer with raw data
+ * @eccsize:	data bytes per ECC step (256 or 512)
+ * @code:	output buffer with ECC
+ */
+void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
+		       unsigned char *code)
+{
+	int i;
+	const uint32_t *bp = (uint32_t *)buf;
+	/* 256 or 512 bytes/ecc  */
+	const uint32_t eccsize_mult = eccsize >> 8;
+	uint32_t cur;		/* current value in buffer */
+	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
+	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+	uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
+	uint32_t uninitialized_var(rp17);	/* to make compiler happy */
+	uint32_t par;		/* the cumulative parity for all data */
+	uint32_t tmppar;	/* the cumulative parity for this iteration;
+				   for rp12, rp14 and rp16 at the end of the
+				   loop */
+
+	par = 0;
+	rp4 = 0;
+	rp6 = 0;
+	rp8 = 0;
+	rp10 = 0;
+	rp12 = 0;
+	rp14 = 0;
+	rp16 = 0;
+
+	/*
+	 * The loop is unrolled a number of times;
+	 * This avoids if statements to decide on which rp value to update
+	 * Also we process the data by longwords.
+	 * Note: passing unaligned data might give a performance penalty.
+	 * It is assumed that the buffers are aligned.
+	 * tmppar is the cumulative sum of this iteration.
+	 * needed for calculating rp12, rp14, rp16 and par
+	 * also used as a performance improvement for rp6, rp8 and rp10
+	 */
+	for (i = 0; i < eccsize_mult << 2; i++) {
+		cur = *bp++;
+		tmppar = cur;
+		rp4 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp6 ^= tmppar;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp8 ^= tmppar;
+
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		rp6 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp6 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp10 ^= tmppar;
+
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		rp6 ^= cur;
+		rp8 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp6 ^= cur;
+		rp8 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		rp8 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp8 ^= cur;
+
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		rp6 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp6 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+		rp4 ^= cur;
+		cur = *bp++;
+		tmppar ^= cur;
+
+		par ^= tmppar;
+		if ((i & 0x1) == 0)
+			rp12 ^= tmppar;
+		if ((i & 0x2) == 0)
+			rp14 ^= tmppar;
+		if (eccsize_mult == 2 && (i & 0x4) == 0)
+			rp16 ^= tmppar;
+	}
+
+	/*
+	 * handle the fact that we use longword operations
+	 * we'll bring rp4..rp14..rp16 back to single byte entities by
+	 * shifting and xoring first fold the upper and lower 16 bits,
+	 * then the upper and lower 8 bits.
+	 */
+	rp4 ^= (rp4 >> 16);
+	rp4 ^= (rp4 >> 8);
+	rp4 &= 0xff;
+	rp6 ^= (rp6 >> 16);
+	rp6 ^= (rp6 >> 8);
+	rp6 &= 0xff;
+	rp8 ^= (rp8 >> 16);
+	rp8 ^= (rp8 >> 8);
+	rp8 &= 0xff;
+	rp10 ^= (rp10 >> 16);
+	rp10 ^= (rp10 >> 8);
+	rp10 &= 0xff;
+	rp12 ^= (rp12 >> 16);
+	rp12 ^= (rp12 >> 8);
+	rp12 &= 0xff;
+	rp14 ^= (rp14 >> 16);
+	rp14 ^= (rp14 >> 8);
+	rp14 &= 0xff;
+	if (eccsize_mult == 2) {
+		rp16 ^= (rp16 >> 16);
+		rp16 ^= (rp16 >> 8);
+		rp16 &= 0xff;
+	}
+
+	/*
+	 * we also need to calculate the row parity for rp0..rp3
+	 * This is present in par, because par is now
+	 * rp3 rp3 rp2 rp2 in little endian and
+	 * rp2 rp2 rp3 rp3 in big endian
+	 * as well as
+	 * rp1 rp0 rp1 rp0 in little endian and
+	 * rp0 rp1 rp0 rp1 in big endian
+	 * First calculate rp2 and rp3
+	 */
+#ifdef __BIG_ENDIAN
+	rp2 = (par >> 16);
+	rp2 ^= (rp2 >> 8);
+	rp2 &= 0xff;
+	rp3 = par & 0xffff;
+	rp3 ^= (rp3 >> 8);
+	rp3 &= 0xff;
+#else
+	rp3 = (par >> 16);
+	rp3 ^= (rp3 >> 8);
+	rp3 &= 0xff;
+	rp2 = par & 0xffff;
+	rp2 ^= (rp2 >> 8);
+	rp2 &= 0xff;
+#endif
+
+	/* reduce par to 16 bits then calculate rp1 and rp0 */
+	par ^= (par >> 16);
+#ifdef __BIG_ENDIAN
+	rp0 = (par >> 8) & 0xff;
+	rp1 = (par & 0xff);
+#else
+	rp1 = (par >> 8) & 0xff;
+	rp0 = (par & 0xff);
+#endif
+
+	/* finally reduce par to 8 bits */
+	par ^= (par >> 8);
+	par &= 0xff;
+
+	/*
+	 * and calculate rp5..rp15..rp17
+	 * note that par = rp4 ^ rp5 and due to the commutative property
+	 * of the ^ operator we can say:
+	 * rp5 = (par ^ rp4);
+	 * The & 0xff seems superfluous, but benchmarking learned that
+	 * leaving it out gives slightly worse results. No idea why, probably
+	 * it has to do with the way the pipeline in pentium is organized.
+	 */
+	rp5 = (par ^ rp4) & 0xff;
+	rp7 = (par ^ rp6) & 0xff;
+	rp9 = (par ^ rp8) & 0xff;
+	rp11 = (par ^ rp10) & 0xff;
+	rp13 = (par ^ rp12) & 0xff;
+	rp15 = (par ^ rp14) & 0xff;
+	if (eccsize_mult == 2)
+		rp17 = (par ^ rp16) & 0xff;
+
+	/*
+	 * Finally calculate the ECC bits.
+	 * Again here it might seem that there are performance optimisations
+	 * possible, but benchmarks showed that on the system this is developed
+	 * the code below is the fastest
+	 */
+#ifdef CONFIG_MTD_NAND_ECC_SMC
+	code[0] =
+	    (invparity[rp7] << 7) |
+	    (invparity[rp6] << 6) |
+	    (invparity[rp5] << 5) |
+	    (invparity[rp4] << 4) |
+	    (invparity[rp3] << 3) |
+	    (invparity[rp2] << 2) |
+	    (invparity[rp1] << 1) |
+	    (invparity[rp0]);
+	code[1] =
+	    (invparity[rp15] << 7) |
+	    (invparity[rp14] << 6) |
+	    (invparity[rp13] << 5) |
+	    (invparity[rp12] << 4) |
+	    (invparity[rp11] << 3) |
+	    (invparity[rp10] << 2) |
+	    (invparity[rp9] << 1)  |
+	    (invparity[rp8]);
+#else
+	code[1] =
+	    (invparity[rp7] << 7) |
+	    (invparity[rp6] << 6) |
+	    (invparity[rp5] << 5) |
+	    (invparity[rp4] << 4) |
+	    (invparity[rp3] << 3) |
+	    (invparity[rp2] << 2) |
+	    (invparity[rp1] << 1) |
+	    (invparity[rp0]);
+	code[0] =
+	    (invparity[rp15] << 7) |
+	    (invparity[rp14] << 6) |
+	    (invparity[rp13] << 5) |
+	    (invparity[rp12] << 4) |
+	    (invparity[rp11] << 3) |
+	    (invparity[rp10] << 2) |
+	    (invparity[rp9] << 1)  |
+	    (invparity[rp8]);
+#endif
+	if (eccsize_mult == 1)
+		code[2] =
+		    (invparity[par & 0xf0] << 7) |
+		    (invparity[par & 0x0f] << 6) |
+		    (invparity[par & 0xcc] << 5) |
+		    (invparity[par & 0x33] << 4) |
+		    (invparity[par & 0xaa] << 3) |
+		    (invparity[par & 0x55] << 2) |
+		    3;
+	else
+		code[2] =
+		    (invparity[par & 0xf0] << 7) |
+		    (invparity[par & 0x0f] << 6) |
+		    (invparity[par & 0xcc] << 5) |
+		    (invparity[par & 0x33] << 4) |
+		    (invparity[par & 0xaa] << 3) |
+		    (invparity[par & 0x55] << 2) |
+		    (invparity[rp17] << 1) |
+		    (invparity[rp16] << 0);
+}
+EXPORT_SYMBOL(__nand_calculate_ecc);
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ *			 block
+ * @mtd:	MTD block structure
+ * @buf:	input buffer with raw data
+ * @code:	output buffer with ECC
+ */
+int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+		       unsigned char *code)
+{
+	__nand_calculate_ecc(buf,
+			mtd_to_nand(mtd)->ecc.size, code);
+
+	return 0;
+}
+EXPORT_SYMBOL(nand_calculate_ecc);
+
+/**
+ * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @buf:	raw data read from the chip
+ * @read_ecc:	ECC from the chip
+ * @calc_ecc:	the ECC calculated from raw data
+ * @eccsize:	data bytes per ECC step (256 or 512)
+ *
+ * Detect and correct a 1 bit error for eccsize byte block
+ */
+int __nand_correct_data(unsigned char *buf,
+			unsigned char *read_ecc, unsigned char *calc_ecc,
+			unsigned int eccsize)
+{
+	unsigned char b0, b1, b2, bit_addr;
+	unsigned int byte_addr;
+	/* 256 or 512 bytes/ecc  */
+	const uint32_t eccsize_mult = eccsize >> 8;
+
+	/*
+	 * b0 to b2 indicate which bit is faulty (if any)
+	 * we might need the xor result  more than once,
+	 * so keep them in a local var
+	*/
+#ifdef CONFIG_MTD_NAND_ECC_SMC
+	b0 = read_ecc[0] ^ calc_ecc[0];
+	b1 = read_ecc[1] ^ calc_ecc[1];
+#else
+	b0 = read_ecc[1] ^ calc_ecc[1];
+	b1 = read_ecc[0] ^ calc_ecc[0];
+#endif
+	b2 = read_ecc[2] ^ calc_ecc[2];
+
+	/* check if there are any bitfaults */
+
+	/* repeated if statements are slightly more efficient than switch ... */
+	/* ordered in order of likelihood */
+
+	if ((b0 | b1 | b2) == 0)
+		return 0;	/* no error */
+
+	if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
+	    (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
+	    ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
+	     (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
+	/* single bit error */
+		/*
+		 * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
+		 * byte, cp 5/3/1 indicate the faulty bit.
+		 * A lookup table (called addressbits) is used to filter
+		 * the bits from the byte they are in.
+		 * A marginal optimisation is possible by having three
+		 * different lookup tables.
+		 * One as we have now (for b0), one for b2
+		 * (that would avoid the >> 1), and one for b1 (with all values
+		 * << 4). However it was felt that introducing two more tables
+		 * hardly justify the gain.
+		 *
+		 * The b2 shift is there to get rid of the lowest two bits.
+		 * We could also do addressbits[b2] >> 1 but for the
+		 * performance it does not make any difference
+		 */
+		if (eccsize_mult == 1)
+			byte_addr = (addressbits[b1] << 4) + addressbits[b0];
+		else
+			byte_addr = (addressbits[b2 & 0x3] << 8) +
+				    (addressbits[b1] << 4) + addressbits[b0];
+		bit_addr = addressbits[b2 >> 2];
+		/* flip the bit */
+		buf[byte_addr] ^= (1 << bit_addr);
+		return 1;
+
+	}
+	/* count nr of bits; use table lookup, faster than calculating it */
+	if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
+		return 1;	/* error in ECC data; no action needed */
+
+	pr_err("%s: uncorrectable ECC error\n", __func__);
+	return -EBADMSG;
+}
+EXPORT_SYMBOL(__nand_correct_data);
+
+/**
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd:	MTD block structure
+ * @buf:	raw data read from the chip
+ * @read_ecc:	ECC from the chip
+ * @calc_ecc:	the ECC calculated from raw data
+ *
+ * Detect and correct a 1 bit error for 256/512 byte block
+ */
+int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+		      unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+	return __nand_correct_data(buf, read_ecc, calc_ecc,
+				   mtd_to_nand(mtd)->ecc.size);
+}
+EXPORT_SYMBOL(nand_correct_data);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
+MODULE_DESCRIPTION("Generic NAND ECC support");
diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c
new file mode 100644
index 000000000000..d542908a0ebb
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_hynix.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mtd/rawnand.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+#define NAND_HYNIX_CMD_SET_PARAMS	0x36
+#define NAND_HYNIX_CMD_APPLY_PARAMS	0x16
+
+#define NAND_HYNIX_1XNM_RR_REPEAT	8
+
+/**
+ * struct hynix_read_retry - read-retry data
+ * @nregs: number of register to set when applying a new read-retry mode
+ * @regs: register offsets (NAND chip dependent)
+ * @values: array of values to set in registers. The array size is equal to
+ *	    (nregs * nmodes)
+ */
+struct hynix_read_retry {
+	int nregs;
+	const u8 *regs;
+	u8 values[0];
+};
+
+/**
+ * struct hynix_nand - private Hynix NAND struct
+ * @nand_technology: manufacturing process expressed in picometer
+ * @read_retry: read-retry information
+ */
+struct hynix_nand {
+	const struct hynix_read_retry *read_retry;
+};
+
+/**
+ * struct hynix_read_retry_otp - structure describing how the read-retry OTP
+ *				 area
+ * @nregs: number of hynix private registers to set before reading the reading
+ *	   the OTP area
+ * @regs: registers that should be configured
+ * @values: values that should be set in regs
+ * @page: the address to pass to the READ_PAGE command. Depends on the NAND
+ *	  chip
+ * @size: size of the read-retry OTP section
+ */
+struct hynix_read_retry_otp {
+	int nregs;
+	const u8 *regs;
+	const u8 *values;
+	int page;
+	int size;
+};
+
+static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
+{
+	u8 jedecid[5] = { };
+	int ret;
+
+	ret = nand_readid_op(chip, 0x40, jedecid, sizeof(jedecid));
+	if (ret)
+		return false;
+
+	return !strncmp("JEDEC", jedecid, sizeof(jedecid));
+}
+
+static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (chip->exec_op) {
+		struct nand_op_instr instrs[] = {
+			NAND_OP_CMD(cmd, 0),
+		};
+		struct nand_operation op = NAND_OPERATION(instrs);
+
+		return nand_exec_op(chip, &op);
+	}
+
+	chip->cmdfunc(mtd, cmd, -1, -1);
+
+	return 0;
+}
+
+static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u16 column = ((u16)addr << 8) | addr;
+
+	chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
+	chip->write_byte(mtd, val);
+
+	return 0;
+}
+
+static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
+	const u8 *values;
+	int i, ret;
+
+	values = hynix->read_retry->values +
+		 (retry_mode * hynix->read_retry->nregs);
+
+	/* Enter 'Set Hynix Parameters' mode */
+	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
+	if (ret)
+		return ret;
+
+	/*
+	 * Configure the NAND in the requested read-retry mode.
+	 * This is done by setting pre-defined values in internal NAND
+	 * registers.
+	 *
+	 * The set of registers is NAND specific, and the values are either
+	 * predefined or extracted from an OTP area on the NAND (values are
+	 * probably tweaked at production in this case).
+	 */
+	for (i = 0; i < hynix->read_retry->nregs; i++) {
+		ret = hynix_nand_reg_write_op(chip, hynix->read_retry->regs[i],
+					      values[i]);
+		if (ret)
+			return ret;
+	}
+
+	/* Apply the new settings. */
+	return hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
+}
+
+/**
+ * hynix_get_majority - get the value that is occurring the most in a given
+ *			set of values
+ * @in: the array of values to test
+ * @repeat: the size of the in array
+ * @out: pointer used to store the output value
+ *
+ * This function implements the 'majority check' logic that is supposed to
+ * overcome the unreliability of MLC NANDs when reading the OTP area storing
+ * the read-retry parameters.
+ *
+ * It's based on a pretty simple assumption: if we repeat the same value
+ * several times and then take the one that is occurring the most, we should
+ * find the correct value.
+ * Let's hope this dummy algorithm prevents us from losing the read-retry
+ * parameters.
+ */
+static int hynix_get_majority(const u8 *in, int repeat, u8 *out)
+{
+	int i, j, half = repeat / 2;
+
+	/*
+	 * We only test the first half of the in array because we must ensure
+	 * that the value is at least occurring repeat / 2 times.
+	 *
+	 * This loop is suboptimal since we may count the occurrences of the
+	 * same value several time, but we are doing that on small sets, which
+	 * makes it acceptable.
+	 */
+	for (i = 0; i < half; i++) {
+		int cnt = 0;
+		u8 val = in[i];
+
+		/* Count all values that are matching the one at index i. */
+		for (j = i + 1; j < repeat; j++) {
+			if (in[j] == val)
+				cnt++;
+		}
+
+		/* We found a value occurring more than repeat / 2. */
+		if (cnt > half) {
+			*out = val;
+			return 0;
+		}
+	}
+
+	return -EIO;
+}
+
+static int hynix_read_rr_otp(struct nand_chip *chip,
+			     const struct hynix_read_retry_otp *info,
+			     void *buf)
+{
+	int i, ret;
+
+	ret = nand_reset_op(chip);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < info->nregs; i++) {
+		ret = hynix_nand_reg_write_op(chip, info->regs[i],
+					      info->values[i]);
+		if (ret)
+			return ret;
+	}
+
+	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
+	if (ret)
+		return ret;
+
+	/* Sequence to enter OTP mode? */
+	ret = hynix_nand_cmd_op(chip, 0x17);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_cmd_op(chip, 0x4);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_cmd_op(chip, 0x19);
+	if (ret)
+		return ret;
+
+	/* Now read the page */
+	ret = nand_read_page_op(chip, info->page, 0, buf, info->size);
+	if (ret)
+		return ret;
+
+	/* Put everything back to normal */
+	ret = nand_reset_op(chip);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_reg_write_op(chip, 0x38, 0);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
+	if (ret)
+		return ret;
+
+	return nand_read_page_op(chip, 0, 0, NULL, 0);
+}
+
+#define NAND_HYNIX_1XNM_RR_COUNT_OFFS				0
+#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS			8
+#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv)		\
+	(16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize)))
+
+static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs,
+				   int mode, int reg, bool inv, u8 *val)
+{
+	u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT];
+	int val_offs = (mode * nregs) + reg;
+	int set_size = nmodes * nregs;
+	int i, ret;
+
+	for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) {
+		int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv);
+
+		tmp[i] = buf[val_offs + set_offs];
+	}
+
+	ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val);
+	if (ret)
+		return ret;
+
+	if (inv)
+		*val = ~*val;
+
+	return 0;
+}
+
+static u8 hynix_1xnm_mlc_read_retry_regs[] = {
+	0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
+};
+
+static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
+				  const struct hynix_read_retry_otp *info)
+{
+	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
+	struct hynix_read_retry *rr = NULL;
+	int ret, i, j;
+	u8 nregs, nmodes;
+	u8 *buf;
+
+	buf = kmalloc(info->size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = hynix_read_rr_otp(chip, info, buf);
+	if (ret)
+		goto out;
+
+	ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT,
+				 &nmodes);
+	if (ret)
+		goto out;
+
+	ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT,
+				 NAND_HYNIX_1XNM_RR_REPEAT,
+				 &nregs);
+	if (ret)
+		goto out;
+
+	rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL);
+	if (!rr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < nmodes; i++) {
+		for (j = 0; j < nregs; j++) {
+			u8 *val = rr->values + (i * nregs);
+
+			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
+						      false, val);
+			if (!ret)
+				continue;
+
+			ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
+						      true, val);
+			if (ret)
+				goto out;
+		}
+	}
+
+	rr->nregs = nregs;
+	rr->regs = hynix_1xnm_mlc_read_retry_regs;
+	hynix->read_retry = rr;
+	chip->setup_read_retry = hynix_nand_setup_read_retry;
+	chip->read_retries = nmodes;
+
+out:
+	kfree(buf);
+
+	if (ret)
+		kfree(rr);
+
+	return ret;
+}
+
+static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 };
+static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 };
+
+static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = {
+	{
+		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
+		.regs = hynix_mlc_1xnm_rr_otp_regs,
+		.values = hynix_mlc_1xnm_rr_otp_values,
+		.page = 0x21f,
+		.size = 784
+	},
+	{
+		.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
+		.regs = hynix_mlc_1xnm_rr_otp_regs,
+		.values = hynix_mlc_1xnm_rr_otp_values,
+		.page = 0x200,
+		.size = 528,
+	},
+};
+
+static int hynix_nand_rr_init(struct nand_chip *chip)
+{
+	int i, ret = 0;
+	bool valid_jedecid;
+
+	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
+
+	/*
+	 * We only support read-retry for 1xnm NANDs, and those NANDs all
+	 * expose a valid JEDEC ID.
+	 */
+	if (valid_jedecid) {
+		u8 nand_tech = chip->id.data[5] >> 4;
+
+		/* 1xnm technology */
+		if (nand_tech == 4) {
+			for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps);
+			     i++) {
+				/*
+				 * FIXME: Hynix recommend to copy the
+				 * read-retry OTP area into a normal page.
+				 */
+				ret = hynix_mlc_1xnm_rr_init(chip,
+						hynix_mlc_1xnm_rr_otps);
+				if (!ret)
+					break;
+			}
+		}
+	}
+
+	if (ret)
+		pr_warn("failed to initialize read-retry infrastructure");
+
+	return 0;
+}
+
+static void hynix_nand_extract_oobsize(struct nand_chip *chip,
+				       bool valid_jedecid)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 oobsize;
+
+	oobsize = ((chip->id.data[3] >> 2) & 0x3) |
+		  ((chip->id.data[3] >> 4) & 0x4);
+
+	if (valid_jedecid) {
+		switch (oobsize) {
+		case 0:
+			mtd->oobsize = 2048;
+			break;
+		case 1:
+			mtd->oobsize = 1664;
+			break;
+		case 2:
+			mtd->oobsize = 1024;
+			break;
+		case 3:
+			mtd->oobsize = 640;
+			break;
+		default:
+			/*
+			 * We should never reach this case, but if that
+			 * happens, this probably means Hynix decided to use
+			 * a different extended ID format, and we should find
+			 * a way to support it.
+			 */
+			WARN(1, "Invalid OOB size");
+			break;
+		}
+	} else {
+		switch (oobsize) {
+		case 0:
+			mtd->oobsize = 128;
+			break;
+		case 1:
+			mtd->oobsize = 224;
+			break;
+		case 2:
+			mtd->oobsize = 448;
+			break;
+		case 3:
+			mtd->oobsize = 64;
+			break;
+		case 4:
+			mtd->oobsize = 32;
+			break;
+		case 5:
+			mtd->oobsize = 16;
+			break;
+		case 6:
+			mtd->oobsize = 640;
+			break;
+		default:
+			/*
+			 * We should never reach this case, but if that
+			 * happens, this probably means Hynix decided to use
+			 * a different extended ID format, and we should find
+			 * a way to support it.
+			 */
+			WARN(1, "Invalid OOB size");
+			break;
+		}
+	}
+}
+
+static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
+						bool valid_jedecid)
+{
+	u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
+
+	if (valid_jedecid) {
+		/* Reference: H27UCG8T2E datasheet */
+		chip->ecc_step_ds = 1024;
+
+		switch (ecc_level) {
+		case 0:
+			chip->ecc_step_ds = 0;
+			chip->ecc_strength_ds = 0;
+			break;
+		case 1:
+			chip->ecc_strength_ds = 4;
+			break;
+		case 2:
+			chip->ecc_strength_ds = 24;
+			break;
+		case 3:
+			chip->ecc_strength_ds = 32;
+			break;
+		case 4:
+			chip->ecc_strength_ds = 40;
+			break;
+		case 5:
+			chip->ecc_strength_ds = 50;
+			break;
+		case 6:
+			chip->ecc_strength_ds = 60;
+			break;
+		default:
+			/*
+			 * We should never reach this case, but if that
+			 * happens, this probably means Hynix decided to use
+			 * a different extended ID format, and we should find
+			 * a way to support it.
+			 */
+			WARN(1, "Invalid ECC requirements");
+		}
+	} else {
+		/*
+		 * The ECC requirements field meaning depends on the
+		 * NAND technology.
+		 */
+		u8 nand_tech = chip->id.data[5] & 0x7;
+
+		if (nand_tech < 3) {
+			/* > 26nm, reference: H27UBG8T2A datasheet */
+			if (ecc_level < 5) {
+				chip->ecc_step_ds = 512;
+				chip->ecc_strength_ds = 1 << ecc_level;
+			} else if (ecc_level < 7) {
+				if (ecc_level == 5)
+					chip->ecc_step_ds = 2048;
+				else
+					chip->ecc_step_ds = 1024;
+				chip->ecc_strength_ds = 24;
+			} else {
+				/*
+				 * We should never reach this case, but if that
+				 * happens, this probably means Hynix decided
+				 * to use a different extended ID format, and
+				 * we should find a way to support it.
+				 */
+				WARN(1, "Invalid ECC requirements");
+			}
+		} else {
+			/* <= 26nm, reference: H27UBG8T2B datasheet */
+			if (!ecc_level) {
+				chip->ecc_step_ds = 0;
+				chip->ecc_strength_ds = 0;
+			} else if (ecc_level < 5) {
+				chip->ecc_step_ds = 512;
+				chip->ecc_strength_ds = 1 << (ecc_level - 1);
+			} else {
+				chip->ecc_step_ds = 1024;
+				chip->ecc_strength_ds = 24 +
+							(8 * (ecc_level - 5));
+			}
+		}
+	}
+}
+
+static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
+						       bool valid_jedecid)
+{
+	u8 nand_tech;
+
+	/* We need scrambling on all TLC NANDs*/
+	if (chip->bits_per_cell > 2)
+		chip->options |= NAND_NEED_SCRAMBLING;
+
+	/* And on MLC NANDs with sub-3xnm process */
+	if (valid_jedecid) {
+		nand_tech = chip->id.data[5] >> 4;
+
+		/* < 3xnm */
+		if (nand_tech > 0)
+			chip->options |= NAND_NEED_SCRAMBLING;
+	} else {
+		nand_tech = chip->id.data[5] & 0x7;
+
+		/* < 32nm */
+		if (nand_tech > 2)
+			chip->options |= NAND_NEED_SCRAMBLING;
+	}
+}
+
+static void hynix_nand_decode_id(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	bool valid_jedecid;
+	u8 tmp;
+
+	/*
+	 * Exclude all SLC NANDs from this advanced detection scheme.
+	 * According to the ranges defined in several datasheets, it might
+	 * appear that even SLC NANDs could fall in this extended ID scheme.
+	 * If that the case rework the test to let SLC NANDs go through the
+	 * detection process.
+	 */
+	if (chip->id.len < 6 || nand_is_slc(chip)) {
+		nand_decode_ext_id(chip);
+		return;
+	}
+
+	/* Extract pagesize */
+	mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
+
+	tmp = (chip->id.data[3] >> 4) & 0x3;
+	/*
+	 * When bit7 is set that means we start counting at 1MiB, otherwise
+	 * we start counting at 128KiB and shift this value the content of
+	 * ID[3][4:5].
+	 * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
+	 * this case the erasesize is set to 768KiB.
+	 */
+	if (chip->id.data[3] & 0x80)
+		mtd->erasesize = SZ_1M << tmp;
+	else if (tmp == 3)
+		mtd->erasesize = SZ_512K + SZ_256K;
+	else
+		mtd->erasesize = SZ_128K << tmp;
+
+	/*
+	 * Modern Toggle DDR NANDs have a valid JEDECID even though they are
+	 * not exposing a valid JEDEC parameter table.
+	 * These NANDs use a different NAND ID scheme.
+	 */
+	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
+
+	hynix_nand_extract_oobsize(chip, valid_jedecid);
+	hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
+	hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
+}
+
+static void hynix_nand_cleanup(struct nand_chip *chip)
+{
+	struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
+
+	if (!hynix)
+		return;
+
+	kfree(hynix->read_retry);
+	kfree(hynix);
+	nand_set_manufacturer_data(chip, NULL);
+}
+
+static int hynix_nand_init(struct nand_chip *chip)
+{
+	struct hynix_nand *hynix;
+	int ret;
+
+	if (!nand_is_slc(chip))
+		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+	else
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+	hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
+	if (!hynix)
+		return -ENOMEM;
+
+	nand_set_manufacturer_data(chip, hynix);
+
+	ret = hynix_nand_rr_init(chip);
+	if (ret)
+		hynix_nand_cleanup(chip);
+
+	return ret;
+}
+
+const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
+	.detect = hynix_nand_decode_id,
+	.init = hynix_nand_init,
+	.cleanup = hynix_nand_cleanup,
+};
diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
new file mode 100644
index 000000000000..5423c3bb388e
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_ids.c
@@ -0,0 +1,207 @@
+/*
+ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.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/mtd/rawnand.h>
+#include <linux/sizes.h>
+
+#define LP_OPTIONS 0
+#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
+
+#define SP_OPTIONS NAND_NEED_READRDY
+#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
+
+/*
+ * The chip ID list:
+ *    name, device ID, page size, chip size in MiB, eraseblock size, options
+ *
+ * If page size and eraseblock size are 0, the sizes are taken from the
+ * extended chip ID.
+ */
+struct nand_flash_dev nand_flash_ids[] = {
+	/*
+	 * Some incompatible NAND chips share device ID's and so must be
+	 * listed by full ID. We list them first so that we can easily identify
+	 * the most specific match.
+	 */
+	{"TC58NVG0S3E 1G 3.3V 8-bit",
+		{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
+		  SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
+		  2 },
+	{"TC58NVG2S0F 4G 3.3V 8-bit",
+		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
+		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
+	{"TC58NVG2S0H 4G 3.3V 8-bit",
+		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
+		  SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
+	{"TC58NVG3S0F 8G 3.3V 8-bit",
+		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
+		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
+	{"TC58NVG5D2 32G 3.3V 8-bit",
+		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
+		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
+	{"TC58NVG6D2 64G 3.3V 8-bit",
+		{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
+		  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
+	{"SDTNRGAMA 64G 3.3V 8-bit",
+		{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
+		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
+	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
+		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
+		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
+		  NAND_ECC_INFO(40, SZ_1K), 4 },
+
+	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS),
+
+	LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit",  0x33, 16, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit",  0x73, 16, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16),
+	LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16),
+
+	LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit",  0x35, 32, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit",  0x75, 32, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16),
+	LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16),
+
+	LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit",  0x36, 64, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit",  0x76, 64, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16),
+	LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16),
+
+	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x78, 128, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit",  0x39, 128, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit",  0x79, 128, SZ_16K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16),
+	LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16),
+	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16),
+	LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16),
+
+	LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS),
+
+	/*
+	 * These are the new chips with large page size. Their page size and
+	 * eraseblock size are determined from the extended ID bytes.
+	 */
+
+	/* 512 Megabit */
+	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA2,  64, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit",  0xA0,  64, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF2,  64, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xD0,  64, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit",  0xF0,  64, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2,  64, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0,  64, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2,  64, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0,  64, LP_OPTIONS16),
+
+	/* 1 Gigabit */
+	EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit",  0xA1, 128, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xF1, 128, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit",  0xD1, 128, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16),
+
+	/* 2 Gigabit */
+	EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit",  0xAA, 256, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit",  0xDA, 256, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16),
+
+	/* 4 Gigabit */
+	EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit",  0xAC, 512, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit",  0xDC, 512, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16),
+
+	/* 8 Gigabit */
+	EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit",  0xA3, 1024, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit",  0xD3, 1024, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16),
+
+	/* 16 Gigabit */
+	EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit",  0xA5, 2048, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit",  0xD5, 2048, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16),
+
+	/* 32 Gigabit */
+	EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit",  0xA7, 4096, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit",  0xD7, 4096, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16),
+
+	/* 64 Gigabit */
+	EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit",  0xAE, 8192, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit",  0xDE, 8192, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16),
+
+	/* 128 Gigabit */
+	EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit",  0x1A, 16384, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit",  0x3A, 16384, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16),
+
+	/* 256 Gigabit */
+	EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit",  0x1C, 32768, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit",  0x3C, 32768, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16),
+
+	/* 512 Gigabit */
+	EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit",  0x1E, 65536, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit",  0x3E, 65536, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16),
+	EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16),
+
+	{NULL}
+};
+
+/* Manufacturer IDs */
+static const struct nand_manufacturer nand_manufacturers[] = {
+	{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
+	{NAND_MFR_ESMT, "ESMT"},
+	{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
+	{NAND_MFR_FUJITSU, "Fujitsu"},
+	{NAND_MFR_NATIONAL, "National"},
+	{NAND_MFR_RENESAS, "Renesas"},
+	{NAND_MFR_STMICRO, "ST Micro"},
+	{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
+	{NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
+	{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+	{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
+	{NAND_MFR_EON, "Eon"},
+	{NAND_MFR_SANDISK, "SanDisk"},
+	{NAND_MFR_INTEL, "Intel"},
+	{NAND_MFR_ATO, "ATO"},
+	{NAND_MFR_WINBOND, "Winbond"},
+};
+
+/**
+ * nand_get_manufacturer - Get manufacturer information from the manufacturer
+ *			   ID
+ * @id: manufacturer ID
+ *
+ * Returns a pointer a nand_manufacturer object if the manufacturer is defined
+ * in the NAND manufacturers database, NULL otherwise.
+ */
+const struct nand_manufacturer *nand_get_manufacturer(u8 id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
+		if (nand_manufacturers[i].id == id)
+			return &nand_manufacturers[i];
+
+	return NULL;
+}
diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
new file mode 100644
index 000000000000..d290ff2a6d2f
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_macronix.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mtd/rawnand.h>
+
+static int macronix_nand_init(struct nand_chip *chip)
+{
+	if (nand_is_slc(chip))
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+	return 0;
+}
+
+const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
+	.init = macronix_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
new file mode 100644
index 000000000000..02e109ae73f1
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mtd/rawnand.h>
+
+/*
+ * Special Micron status bit that indicates when the block has been
+ * corrected by on-die ECC and should be rewritten
+ */
+#define NAND_STATUS_WRITE_RECOMMENDED	BIT(3)
+
+struct nand_onfi_vendor_micron {
+	u8 two_plane_read;
+	u8 read_cache;
+	u8 read_unique_id;
+	u8 dq_imped;
+	u8 dq_imped_num_settings;
+	u8 dq_imped_feat_addr;
+	u8 rb_pulldown_strength;
+	u8 rb_pulldown_strength_feat_addr;
+	u8 rb_pulldown_strength_num_settings;
+	u8 otp_mode;
+	u8 otp_page_start;
+	u8 otp_data_prot_addr;
+	u8 otp_num_pages;
+	u8 otp_feat_addr;
+	u8 read_retry_options;
+	u8 reserved[72];
+	u8 param_revision;
+} __packed;
+
+static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
+
+	return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
+				       feature);
+}
+
+/*
+ * Configure chip properties from Micron vendor-specific ONFI table
+ */
+static int micron_nand_onfi_init(struct nand_chip *chip)
+{
+	struct nand_onfi_params *p = &chip->onfi_params;
+	struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
+
+	if (!chip->onfi_version)
+		return 0;
+
+	if (le16_to_cpu(p->vendor_revision) < 1)
+		return 0;
+
+	chip->read_retries = micron->read_retry_options;
+	chip->setup_read_retry = micron_nand_setup_read_retry;
+
+	return 0;
+}
+
+static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
+					    struct mtd_oob_region *oobregion)
+{
+	if (section >= 4)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 8;
+	oobregion->length = 8;
+
+	return 0;
+}
+
+static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
+					     struct mtd_oob_region *oobregion)
+{
+	if (section >= 4)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 2;
+	oobregion->length = 6;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
+	.ecc = micron_nand_on_die_ooblayout_ecc,
+	.free = micron_nand_on_die_ooblayout_free,
+};
+
+static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
+{
+	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+
+	if (enable)
+		feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
+
+	return chip->onfi_set_features(nand_to_mtd(chip), chip,
+				       ONFI_FEATURE_ON_DIE_ECC, feature);
+}
+
+static int
+micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+				 uint8_t *buf, int oob_required,
+				 int page)
+{
+	u8 status;
+	int ret, max_bitflips = 0;
+
+	ret = micron_nand_on_die_ecc_setup(chip, true);
+	if (ret)
+		return ret;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		goto out;
+
+	ret = nand_status_op(chip, &status);
+	if (ret)
+		goto out;
+
+	ret = nand_exit_status_op(chip);
+	if (ret)
+		goto out;
+
+	if (status & NAND_STATUS_FAIL)
+		mtd->ecc_stats.failed++;
+
+	/*
+	 * The internal ECC doesn't tell us the number of bitflips
+	 * that have been corrected, but tells us if it recommends to
+	 * rewrite the block. If it's the case, then we pretend we had
+	 * a number of bitflips equal to the ECC strength, which will
+	 * hint the NAND core to rewrite the block.
+	 */
+	else if (status & NAND_STATUS_WRITE_RECOMMENDED)
+		max_bitflips = chip->ecc.strength;
+
+	ret = nand_read_data_op(chip, buf, mtd->writesize, false);
+	if (!ret && oob_required)
+		ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
+					false);
+
+out:
+	micron_nand_on_die_ecc_setup(chip, false);
+
+	return ret ? ret : max_bitflips;
+}
+
+static int
+micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
+				  const uint8_t *buf, int oob_required,
+				  int page)
+{
+	int ret;
+
+	ret = micron_nand_on_die_ecc_setup(chip, true);
+	if (ret)
+		return ret;
+
+	ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
+	micron_nand_on_die_ecc_setup(chip, false);
+
+	return ret;
+}
+
+enum {
+	/* The NAND flash doesn't support on-die ECC */
+	MICRON_ON_DIE_UNSUPPORTED,
+
+	/*
+	 * The NAND flash supports on-die ECC and it can be
+	 * enabled/disabled by a set features command.
+	 */
+	MICRON_ON_DIE_SUPPORTED,
+
+	/*
+	 * The NAND flash supports on-die ECC, and it cannot be
+	 * disabled.
+	 */
+	MICRON_ON_DIE_MANDATORY,
+};
+
+/*
+ * Try to detect if the NAND support on-die ECC. To do this, we enable
+ * the feature, and read back if it has been enabled as expected. We
+ * also check if it can be disabled, because some Micron NANDs do not
+ * allow disabling the on-die ECC and we don't support such NANDs for
+ * now.
+ *
+ * This function also has the side effect of disabling on-die ECC if
+ * it had been left enabled by the firmware/bootloader.
+ */
+static int micron_supports_on_die_ecc(struct nand_chip *chip)
+{
+	u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+	int ret;
+
+	if (chip->onfi_version == 0)
+		return MICRON_ON_DIE_UNSUPPORTED;
+
+	if (chip->bits_per_cell != 1)
+		return MICRON_ON_DIE_UNSUPPORTED;
+
+	ret = micron_nand_on_die_ecc_setup(chip, true);
+	if (ret)
+		return MICRON_ON_DIE_UNSUPPORTED;
+
+	chip->onfi_get_features(nand_to_mtd(chip), chip,
+				ONFI_FEATURE_ON_DIE_ECC, feature);
+	if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
+		return MICRON_ON_DIE_UNSUPPORTED;
+
+	ret = micron_nand_on_die_ecc_setup(chip, false);
+	if (ret)
+		return MICRON_ON_DIE_UNSUPPORTED;
+
+	chip->onfi_get_features(nand_to_mtd(chip), chip,
+				ONFI_FEATURE_ON_DIE_ECC, feature);
+	if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
+		return MICRON_ON_DIE_MANDATORY;
+
+	/*
+	 * Some Micron NANDs have an on-die ECC of 4/512, some other
+	 * 8/512. We only support the former.
+	 */
+	if (chip->onfi_params.ecc_bits != 4)
+		return MICRON_ON_DIE_UNSUPPORTED;
+
+	return MICRON_ON_DIE_SUPPORTED;
+}
+
+static int micron_nand_init(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ondie;
+	int ret;
+
+	ret = micron_nand_onfi_init(chip);
+	if (ret)
+		return ret;
+
+	if (mtd->writesize == 2048)
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+	ondie = micron_supports_on_die_ecc(chip);
+
+	if (ondie == MICRON_ON_DIE_MANDATORY) {
+		pr_err("On-die ECC forcefully enabled, not supported\n");
+		return -EINVAL;
+	}
+
+	if (chip->ecc.mode == NAND_ECC_ON_DIE) {
+		if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
+			pr_err("On-die ECC selected but not supported\n");
+			return -EINVAL;
+		}
+
+		chip->ecc.bytes = 8;
+		chip->ecc.size = 512;
+		chip->ecc.strength = 4;
+		chip->ecc.algo = NAND_ECC_BCH;
+		chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
+		chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
+		chip->ecc.read_page_raw = nand_read_page_raw;
+		chip->ecc.write_page_raw = nand_write_page_raw;
+
+		mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
+	}
+
+	return 0;
+}
+
+const struct nand_manufacturer_ops micron_nand_manuf_ops = {
+	.init = micron_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
new file mode 100644
index 000000000000..ef022f62f74c
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_samsung.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mtd/rawnand.h>
+
+static void samsung_nand_decode_id(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
+	if (chip->id.len == 6 && !nand_is_slc(chip) &&
+	    chip->id.data[5] != 0x00) {
+		u8 extid = chip->id.data[3];
+
+		/* Get pagesize */
+		mtd->writesize = 2048 << (extid & 0x03);
+
+		extid >>= 2;
+
+		/* Get oobsize */
+		switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
+		case 1:
+			mtd->oobsize = 128;
+			break;
+		case 2:
+			mtd->oobsize = 218;
+			break;
+		case 3:
+			mtd->oobsize = 400;
+			break;
+		case 4:
+			mtd->oobsize = 436;
+			break;
+		case 5:
+			mtd->oobsize = 512;
+			break;
+		case 6:
+			mtd->oobsize = 640;
+			break;
+		default:
+			/*
+			 * We should never reach this case, but if that
+			 * happens, this probably means Samsung decided to use
+			 * a different extended ID format, and we should find
+			 * a way to support it.
+			 */
+			WARN(1, "Invalid OOB size value");
+			break;
+		}
+
+		/* Get blocksize */
+		extid >>= 2;
+		mtd->erasesize = (128 * 1024) <<
+				 (((extid >> 1) & 0x04) | (extid & 0x03));
+
+		/* Extract ECC requirements from 5th id byte*/
+		extid = (chip->id.data[4] >> 4) & 0x07;
+		if (extid < 5) {
+			chip->ecc_step_ds = 512;
+			chip->ecc_strength_ds = 1 << extid;
+		} else {
+			chip->ecc_step_ds = 1024;
+			switch (extid) {
+			case 5:
+				chip->ecc_strength_ds = 24;
+				break;
+			case 6:
+				chip->ecc_strength_ds = 40;
+				break;
+			case 7:
+				chip->ecc_strength_ds = 60;
+				break;
+			default:
+				WARN(1, "Could not decode ECC info");
+				chip->ecc_step_ds = 0;
+			}
+		}
+	} else {
+		nand_decode_ext_id(chip);
+
+		if (nand_is_slc(chip)) {
+			switch (chip->id.data[1]) {
+			/* K9F4G08U0D-S[I|C]B0(T00) */
+			case 0xDC:
+				chip->ecc_step_ds = 512;
+				chip->ecc_strength_ds = 1;
+				break;
+
+			/* K9F1G08U0E 21nm chips do not support subpage write */
+			case 0xF1:
+				if (chip->id.len > 4 &&
+				    (chip->id.data[4] & GENMASK(1, 0)) == 0x1)
+					chip->options |= NAND_NO_SUBPAGE_WRITE;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+}
+
+static int samsung_nand_init(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (mtd->writesize > 512)
+		chip->options |= NAND_SAMSUNG_LP_OPTIONS;
+
+	if (!nand_is_slc(chip))
+		chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
+	else
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+	return 0;
+}
+
+const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
+	.detect = samsung_nand_decode_id,
+	.init = samsung_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
new file mode 100644
index 000000000000..9400d039ddbd
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -0,0 +1,324 @@
+/*
+ *  Copyright (C) 2014 Free Electrons
+ *
+ *  Author: Boris BREZILLON <boris.brezillon@free-electrons.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/kernel.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/mtd/rawnand.h>
+
+static const struct nand_data_interface onfi_sdr_timings[] = {
+	/* Mode 0 */
+	{
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
+			.tADL_min = 400000,
+			.tALH_min = 20000,
+			.tALS_min = 50000,
+			.tAR_min = 25000,
+			.tCEA_max = 100000,
+			.tCEH_min = 20000,
+			.tCH_min = 20000,
+			.tCHZ_max = 100000,
+			.tCLH_min = 20000,
+			.tCLR_min = 20000,
+			.tCLS_min = 50000,
+			.tCOH_min = 0,
+			.tCS_min = 70000,
+			.tDH_min = 20000,
+			.tDS_min = 40000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 10000,
+			.tITC_max = 1000000,
+			.tRC_min = 100000,
+			.tREA_max = 40000,
+			.tREH_min = 30000,
+			.tRHOH_min = 0,
+			.tRHW_min = 200000,
+			.tRHZ_max = 200000,
+			.tRLOH_min = 0,
+			.tRP_min = 50000,
+			.tRR_min = 40000,
+			.tRST_max = 250000000000ULL,
+			.tWB_max = 200000,
+			.tWC_min = 100000,
+			.tWH_min = 30000,
+			.tWHR_min = 120000,
+			.tWP_min = 50000,
+			.tWW_min = 100000,
+		},
+	},
+	/* Mode 1 */
+	{
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
+			.tADL_min = 400000,
+			.tALH_min = 10000,
+			.tALS_min = 25000,
+			.tAR_min = 10000,
+			.tCEA_max = 45000,
+			.tCEH_min = 20000,
+			.tCH_min = 10000,
+			.tCHZ_max = 50000,
+			.tCLH_min = 10000,
+			.tCLR_min = 10000,
+			.tCLS_min = 25000,
+			.tCOH_min = 15000,
+			.tCS_min = 35000,
+			.tDH_min = 10000,
+			.tDS_min = 20000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 50000,
+			.tREA_max = 30000,
+			.tREH_min = 15000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 0,
+			.tRP_min = 25000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 45000,
+			.tWH_min = 15000,
+			.tWHR_min = 80000,
+			.tWP_min = 25000,
+			.tWW_min = 100000,
+		},
+	},
+	/* Mode 2 */
+	{
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
+			.tADL_min = 400000,
+			.tALH_min = 10000,
+			.tALS_min = 15000,
+			.tAR_min = 10000,
+			.tCEA_max = 30000,
+			.tCEH_min = 20000,
+			.tCH_min = 10000,
+			.tCHZ_max = 50000,
+			.tCLH_min = 10000,
+			.tCLR_min = 10000,
+			.tCLS_min = 15000,
+			.tCOH_min = 15000,
+			.tCS_min = 25000,
+			.tDH_min = 5000,
+			.tDS_min = 15000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 35000,
+			.tREA_max = 25000,
+			.tREH_min = 15000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 0,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tRP_min = 17000,
+			.tWC_min = 35000,
+			.tWH_min = 15000,
+			.tWHR_min = 80000,
+			.tWP_min = 17000,
+			.tWW_min = 100000,
+		},
+	},
+	/* Mode 3 */
+	{
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
+			.tADL_min = 400000,
+			.tALH_min = 5000,
+			.tALS_min = 10000,
+			.tAR_min = 10000,
+			.tCEA_max = 25000,
+			.tCEH_min = 20000,
+			.tCH_min = 5000,
+			.tCHZ_max = 50000,
+			.tCLH_min = 5000,
+			.tCLR_min = 10000,
+			.tCLS_min = 10000,
+			.tCOH_min = 15000,
+			.tCS_min = 25000,
+			.tDH_min = 5000,
+			.tDS_min = 10000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 30000,
+			.tREA_max = 20000,
+			.tREH_min = 10000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 0,
+			.tRP_min = 15000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 30000,
+			.tWH_min = 10000,
+			.tWHR_min = 80000,
+			.tWP_min = 15000,
+			.tWW_min = 100000,
+		},
+	},
+	/* Mode 4 */
+	{
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
+			.tADL_min = 400000,
+			.tALH_min = 5000,
+			.tALS_min = 10000,
+			.tAR_min = 10000,
+			.tCEA_max = 25000,
+			.tCEH_min = 20000,
+			.tCH_min = 5000,
+			.tCHZ_max = 30000,
+			.tCLH_min = 5000,
+			.tCLR_min = 10000,
+			.tCLS_min = 10000,
+			.tCOH_min = 15000,
+			.tCS_min = 20000,
+			.tDH_min = 5000,
+			.tDS_min = 10000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 25000,
+			.tREA_max = 20000,
+			.tREH_min = 10000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 5000,
+			.tRP_min = 12000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 25000,
+			.tWH_min = 10000,
+			.tWHR_min = 80000,
+			.tWP_min = 12000,
+			.tWW_min = 100000,
+		},
+	},
+	/* Mode 5 */
+	{
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
+			.tADL_min = 400000,
+			.tALH_min = 5000,
+			.tALS_min = 10000,
+			.tAR_min = 10000,
+			.tCEA_max = 25000,
+			.tCEH_min = 20000,
+			.tCH_min = 5000,
+			.tCHZ_max = 30000,
+			.tCLH_min = 5000,
+			.tCLR_min = 10000,
+			.tCLS_min = 10000,
+			.tCOH_min = 15000,
+			.tCS_min = 15000,
+			.tDH_min = 5000,
+			.tDS_min = 7000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 20000,
+			.tREA_max = 16000,
+			.tREH_min = 7000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 5000,
+			.tRP_min = 10000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 20000,
+			.tWH_min = 7000,
+			.tWHR_min = 80000,
+			.tWP_min = 10000,
+			.tWW_min = 100000,
+		},
+	},
+};
+
+/**
+ * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
+ * timings according to the given ONFI timing mode
+ * @mode: ONFI timing mode
+ */
+const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
+{
+	if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
+		return ERR_PTR(-EINVAL);
+
+	return &onfi_sdr_timings[mode].timings.sdr;
+}
+EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
+
+/**
+ * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
+ * given ONFI mode
+ * @mode: The ONFI timing mode
+ */
+int onfi_fill_data_interface(struct nand_chip *chip,
+			     enum nand_data_interface_type type,
+			     int timing_mode)
+{
+	struct nand_data_interface *iface = &chip->data_interface;
+
+	if (type != NAND_SDR_IFACE)
+		return -EINVAL;
+
+	if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+		return -EINVAL;
+
+	*iface = onfi_sdr_timings[timing_mode];
+
+	/*
+	 * Initialize timings that cannot be deduced from timing mode:
+	 * tR, tPROG, tCCS, ...
+	 * These information are part of the ONFI parameter page.
+	 */
+	if (chip->onfi_version) {
+		struct nand_onfi_params *params = &chip->onfi_params;
+		struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+		/* microseconds -> picoseconds */
+		timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog);
+		timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers);
+		timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r);
+
+		/* nanoseconds -> picoseconds */
+		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(onfi_fill_data_interface);
diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c
new file mode 100644
index 000000000000..ab43f027cd23
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_toshiba.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 Free Electrons
+ * Copyright (C) 2017 NextThing Co
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mtd/rawnand.h>
+
+static void toshiba_nand_decode_id(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	nand_decode_ext_id(chip);
+
+	/*
+	 * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+	 * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+	 * follows:
+	 * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+	 *                         110b -> 24nm
+	 * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
+	 */
+	if (chip->id.len >= 6 && nand_is_slc(chip) &&
+	    (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
+	    !(chip->id.data[4] & 0x80) /* !BENAND */)
+		mtd->oobsize = 32 * mtd->writesize >> 9;
+
+	/*
+	 * Extract ECC requirements from 6th id byte.
+	 * For Toshiba SLC, ecc requrements are as follows:
+	 *  - 43nm: 1 bit ECC for each 512Byte is required.
+	 *  - 32nm: 4 bit ECC for each 512Byte is required.
+	 *  - 24nm: 8 bit ECC for each 512Byte is required.
+	 */
+	if (chip->id.len >= 6 && nand_is_slc(chip)) {
+		chip->ecc_step_ds = 512;
+		switch (chip->id.data[5] & 0x7) {
+		case 0x4:
+			chip->ecc_strength_ds = 1;
+			break;
+		case 0x5:
+			chip->ecc_strength_ds = 4;
+			break;
+		case 0x6:
+			chip->ecc_strength_ds = 8;
+			break;
+		default:
+			WARN(1, "Could not get ECC info");
+			chip->ecc_step_ds = 0;
+			break;
+		}
+	}
+}
+
+static int toshiba_nand_init(struct nand_chip *chip)
+{
+	if (nand_is_slc(chip))
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+	return 0;
+}
+
+const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
+	.detect = toshiba_nand_decode_id,
+	.init = toshiba_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
new file mode 100644
index 000000000000..44322a363ba5
--- /dev/null
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -0,0 +1,2392 @@
+/*
+ * NAND flash simulator.
+ *
+ * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ *
+ * Note: NS means "NAND Simulator".
+ * Note: Input means input TO flash chip, output means output FROM chip.
+ *
+ * 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, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/math64.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_bch.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/sched/mm.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+/* Default simulator parameters values */
+#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
+    !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
+    !defined(CONFIG_NANDSIM_THIRD_ID_BYTE)  || \
+    !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
+#define CONFIG_NANDSIM_FIRST_ID_BYTE  0x98
+#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x39
+#define CONFIG_NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
+#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
+#endif
+
+#ifndef CONFIG_NANDSIM_ACCESS_DELAY
+#define CONFIG_NANDSIM_ACCESS_DELAY 25
+#endif
+#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
+#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
+#endif
+#ifndef CONFIG_NANDSIM_ERASE_DELAY
+#define CONFIG_NANDSIM_ERASE_DELAY 2
+#endif
+#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
+#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
+#endif
+#ifndef CONFIG_NANDSIM_INPUT_CYCLE
+#define CONFIG_NANDSIM_INPUT_CYCLE  50
+#endif
+#ifndef CONFIG_NANDSIM_BUS_WIDTH
+#define CONFIG_NANDSIM_BUS_WIDTH  8
+#endif
+#ifndef CONFIG_NANDSIM_DO_DELAYS
+#define CONFIG_NANDSIM_DO_DELAYS  0
+#endif
+#ifndef CONFIG_NANDSIM_LOG
+#define CONFIG_NANDSIM_LOG        0
+#endif
+#ifndef CONFIG_NANDSIM_DBG
+#define CONFIG_NANDSIM_DBG        0
+#endif
+#ifndef CONFIG_NANDSIM_MAX_PARTS
+#define CONFIG_NANDSIM_MAX_PARTS  32
+#endif
+
+static uint access_delay   = CONFIG_NANDSIM_ACCESS_DELAY;
+static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
+static uint erase_delay    = CONFIG_NANDSIM_ERASE_DELAY;
+static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
+static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
+static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
+static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
+static uint log            = CONFIG_NANDSIM_LOG;
+static uint dbg            = CONFIG_NANDSIM_DBG;
+static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
+static unsigned int parts_num;
+static char *badblocks = NULL;
+static char *weakblocks = NULL;
+static char *weakpages = NULL;
+static unsigned int bitflips = 0;
+static char *gravepages = NULL;
+static unsigned int overridesize = 0;
+static char *cache_file = NULL;
+static unsigned int bbt;
+static unsigned int bch;
+static u_char id_bytes[8] = {
+	[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
+	[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
+	[2] = CONFIG_NANDSIM_THIRD_ID_BYTE,
+	[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
+	[4 ... 7] = 0xFF,
+};
+
+module_param_array(id_bytes, byte, NULL, 0400);
+module_param_named(first_id_byte, id_bytes[0], byte, 0400);
+module_param_named(second_id_byte, id_bytes[1], byte, 0400);
+module_param_named(third_id_byte, id_bytes[2], byte, 0400);
+module_param_named(fourth_id_byte, id_bytes[3], byte, 0400);
+module_param(access_delay,   uint, 0400);
+module_param(programm_delay, uint, 0400);
+module_param(erase_delay,    uint, 0400);
+module_param(output_cycle,   uint, 0400);
+module_param(input_cycle,    uint, 0400);
+module_param(bus_width,      uint, 0400);
+module_param(do_delays,      uint, 0400);
+module_param(log,            uint, 0400);
+module_param(dbg,            uint, 0400);
+module_param_array(parts, ulong, &parts_num, 0400);
+module_param(badblocks,      charp, 0400);
+module_param(weakblocks,     charp, 0400);
+module_param(weakpages,      charp, 0400);
+module_param(bitflips,       uint, 0400);
+module_param(gravepages,     charp, 0400);
+module_param(overridesize,   uint, 0400);
+module_param(cache_file,     charp, 0400);
+module_param(bbt,	     uint, 0400);
+module_param(bch,	     uint, 0400);
+
+MODULE_PARM_DESC(id_bytes,       "The ID bytes returned by NAND Flash 'read ID' command");
+MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
+MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID) (obsolete)");
+MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command (obsolete)");
+MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command (obsolete)");
+MODULE_PARM_DESC(access_delay,   "Initial page access delay (microseconds)");
+MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
+MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");
+MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanoseconds)");
+MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanoseconds)");
+MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
+MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
+MODULE_PARM_DESC(log,            "Perform logging if not zero");
+MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
+MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
+/* Page and erase block positions for the following parameters are independent of any partitions */
+MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
+MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
+				 " separated by commas e.g. 113:2 means eb 113"
+				 " can be erased only twice before failing");
+MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"
+				 " separated by commas e.g. 1401:2 means page 1401"
+				 " can be written only twice before failing");
+MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");
+MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
+				 " separated by commas e.g. 1401:2 means page 1401"
+				 " can be read only twice before failing");
+MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
+				 "The size is specified in erase blocks and as the exponent of a power of two"
+				 " e.g. 5 means a size of 32 erase blocks");
+MODULE_PARM_DESC(cache_file,     "File to use to cache nand pages instead of memory");
+MODULE_PARM_DESC(bbt,		 "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
+MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
+				 "be correctable in 512-byte blocks");
+
+/* The largest possible page size */
+#define NS_LARGEST_PAGE_SIZE	4096
+
+/* The prefix for simulator output */
+#define NS_OUTPUT_PREFIX "[nandsim]"
+
+/* Simulator's output macros (logging, debugging, warning, error) */
+#define NS_LOG(args...) \
+	do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
+#define NS_DBG(args...) \
+	do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
+#define NS_WARN(args...) \
+	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
+#define NS_ERR(args...) \
+	do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
+#define NS_INFO(args...) \
+	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
+
+/* Busy-wait delay macros (microseconds, milliseconds) */
+#define NS_UDELAY(us) \
+        do { if (do_delays) udelay(us); } while(0)
+#define NS_MDELAY(us) \
+        do { if (do_delays) mdelay(us); } while(0)
+
+/* Is the nandsim structure initialized ? */
+#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
+
+/* Good operation completion status */
+#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
+
+/* Operation failed completion status */
+#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
+
+/* Calculate the page offset in flash RAM image by (row, column) address */
+#define NS_RAW_OFFSET(ns) \
+	(((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
+
+/* Calculate the OOB offset in flash RAM image by (row, column) address */
+#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
+
+/* After a command is input, the simulator goes to one of the following states */
+#define STATE_CMD_READ0        0x00000001 /* read data from the beginning of page */
+#define STATE_CMD_READ1        0x00000002 /* read data from the second half of page */
+#define STATE_CMD_READSTART    0x00000003 /* read data second command (large page devices) */
+#define STATE_CMD_PAGEPROG     0x00000004 /* start page program */
+#define STATE_CMD_READOOB      0x00000005 /* read OOB area */
+#define STATE_CMD_ERASE1       0x00000006 /* sector erase first command */
+#define STATE_CMD_STATUS       0x00000007 /* read status */
+#define STATE_CMD_SEQIN        0x00000009 /* sequential data input */
+#define STATE_CMD_READID       0x0000000A /* read ID */
+#define STATE_CMD_ERASE2       0x0000000B /* sector erase second command */
+#define STATE_CMD_RESET        0x0000000C /* reset */
+#define STATE_CMD_RNDOUT       0x0000000D /* random output command */
+#define STATE_CMD_RNDOUTSTART  0x0000000E /* random output start command */
+#define STATE_CMD_MASK         0x0000000F /* command states mask */
+
+/* After an address is input, the simulator goes to one of these states */
+#define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */
+#define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */
+#define STATE_ADDR_COLUMN      0x00000030 /* column address was accepted */
+#define STATE_ADDR_ZERO        0x00000040 /* one byte zero address was accepted */
+#define STATE_ADDR_MASK        0x00000070 /* address states mask */
+
+/* During data input/output the simulator is in these states */
+#define STATE_DATAIN           0x00000100 /* waiting for data input */
+#define STATE_DATAIN_MASK      0x00000100 /* data input states mask */
+
+#define STATE_DATAOUT          0x00001000 /* waiting for page data output */
+#define STATE_DATAOUT_ID       0x00002000 /* waiting for ID bytes output */
+#define STATE_DATAOUT_STATUS   0x00003000 /* waiting for status output */
+#define STATE_DATAOUT_MASK     0x00007000 /* data output states mask */
+
+/* Previous operation is done, ready to accept new requests */
+#define STATE_READY            0x00000000
+
+/* This state is used to mark that the next state isn't known yet */
+#define STATE_UNKNOWN          0x10000000
+
+/* Simulator's actions bit masks */
+#define ACTION_CPY       0x00100000 /* copy page/OOB to the internal buffer */
+#define ACTION_PRGPAGE   0x00200000 /* program the internal buffer to flash */
+#define ACTION_SECERASE  0x00300000 /* erase sector */
+#define ACTION_ZEROOFF   0x00400000 /* don't add any offset to address */
+#define ACTION_HALFOFF   0x00500000 /* add to address half of page */
+#define ACTION_OOBOFF    0x00600000 /* add to address OOB offset */
+#define ACTION_MASK      0x00700000 /* action mask */
+
+#define NS_OPER_NUM      13 /* Number of operations supported by the simulator */
+#define NS_OPER_STATES   6  /* Maximum number of states in operation */
+
+#define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */
+#define OPT_PAGE512      0x00000002 /* 512-byte  page chips */
+#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */
+#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
+#define OPT_PAGE4096     0x00000080 /* 4096-byte page chips */
+#define OPT_LARGEPAGE    (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
+#define OPT_SMALLPAGE    (OPT_PAGE512) /* 512-byte page chips */
+
+/* Remove action bits from state */
+#define NS_STATE(x) ((x) & ~ACTION_MASK)
+
+/*
+ * Maximum previous states which need to be saved. Currently saving is
+ * only needed for page program operation with preceded read command
+ * (which is only valid for 512-byte pages).
+ */
+#define NS_MAX_PREVSTATES 1
+
+/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
+#define NS_MAX_HELD_PAGES 16
+
+/*
+ * A union to represent flash memory contents and flash buffer.
+ */
+union ns_mem {
+	u_char *byte;    /* for byte access */
+	uint16_t *word;  /* for 16-bit word access */
+};
+
+/*
+ * The structure which describes all the internal simulator data.
+ */
+struct nandsim {
+	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
+	unsigned int nbparts;
+
+	uint busw;              /* flash chip bus width (8 or 16) */
+	u_char ids[8];          /* chip's ID bytes */
+	uint32_t options;       /* chip's characteristic bits */
+	uint32_t state;         /* current chip state */
+	uint32_t nxstate;       /* next expected state */
+
+	uint32_t *op;           /* current operation, NULL operations isn't known yet  */
+	uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
+	uint16_t npstates;      /* number of previous states saved */
+	uint16_t stateidx;      /* current state index */
+
+	/* The simulated NAND flash pages array */
+	union ns_mem *pages;
+
+	/* Slab allocator for nand pages */
+	struct kmem_cache *nand_pages_slab;
+
+	/* Internal buffer of page + OOB size bytes */
+	union ns_mem buf;
+
+	/* NAND flash "geometry" */
+	struct {
+		uint64_t totsz;     /* total flash size, bytes */
+		uint32_t secsz;     /* flash sector (erase block) size, bytes */
+		uint pgsz;          /* NAND flash page size, bytes */
+		uint oobsz;         /* page OOB area size, bytes */
+		uint64_t totszoob;  /* total flash size including OOB, bytes */
+		uint pgszoob;       /* page size including OOB , bytes*/
+		uint secszoob;      /* sector size including OOB, bytes */
+		uint pgnum;         /* total number of pages */
+		uint pgsec;         /* number of pages per sector */
+		uint secshift;      /* bits number in sector size */
+		uint pgshift;       /* bits number in page size */
+		uint pgaddrbytes;   /* bytes per page address */
+		uint secaddrbytes;  /* bytes per sector address */
+		uint idbytes;       /* the number ID bytes that this chip outputs */
+	} geom;
+
+	/* NAND flash internal registers */
+	struct {
+		unsigned command; /* the command register */
+		u_char   status;  /* the status register */
+		uint     row;     /* the page number */
+		uint     column;  /* the offset within page */
+		uint     count;   /* internal counter */
+		uint     num;     /* number of bytes which must be processed */
+		uint     off;     /* fixed page offset */
+	} regs;
+
+	/* NAND flash lines state */
+        struct {
+                int ce;  /* chip Enable */
+                int cle; /* command Latch Enable */
+                int ale; /* address Latch Enable */
+                int wp;  /* write Protect */
+        } lines;
+
+	/* Fields needed when using a cache file */
+	struct file *cfile; /* Open file */
+	unsigned long *pages_written; /* Which pages have been written */
+	void *file_buf;
+	struct page *held_pages[NS_MAX_HELD_PAGES];
+	int held_cnt;
+};
+
+/*
+ * Operations array. To perform any operation the simulator must pass
+ * through the correspondent states chain.
+ */
+static struct nandsim_operations {
+	uint32_t reqopts;  /* options which are required to perform the operation */
+	uint32_t states[NS_OPER_STATES]; /* operation's states */
+} ops[NS_OPER_NUM] = {
+	/* Read page + OOB from the beginning */
+	{OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,
+			STATE_DATAOUT, STATE_READY}},
+	/* Read page + OOB from the second half */
+	{OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,
+			STATE_DATAOUT, STATE_READY}},
+	/* Read OOB */
+	{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
+			STATE_DATAOUT, STATE_READY}},
+	/* Program page starting from the beginning */
+	{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
+			STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Program page starting from the beginning */
+	{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
+			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Program page starting from the second half */
+	{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
+			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Program OOB */
+	{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
+			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Erase sector */
+	{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
+	/* Read status */
+	{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
+	/* Read ID */
+	{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
+	/* Large page devices read page */
+	{OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY,
+			       STATE_DATAOUT, STATE_READY}},
+	/* Large page devices random page read */
+	{OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY,
+			       STATE_DATAOUT, STATE_READY}},
+};
+
+struct weak_block {
+	struct list_head list;
+	unsigned int erase_block_no;
+	unsigned int max_erases;
+	unsigned int erases_done;
+};
+
+static LIST_HEAD(weak_blocks);
+
+struct weak_page {
+	struct list_head list;
+	unsigned int page_no;
+	unsigned int max_writes;
+	unsigned int writes_done;
+};
+
+static LIST_HEAD(weak_pages);
+
+struct grave_page {
+	struct list_head list;
+	unsigned int page_no;
+	unsigned int max_reads;
+	unsigned int reads_done;
+};
+
+static LIST_HEAD(grave_pages);
+
+static unsigned long *erase_block_wear = NULL;
+static unsigned int wear_eb_count = 0;
+static unsigned long total_wear = 0;
+
+/* MTD structure for NAND controller */
+static struct mtd_info *nsmtd;
+
+static int nandsim_debugfs_show(struct seq_file *m, void *private)
+{
+	unsigned long wmin = -1, wmax = 0, avg;
+	unsigned long deciles[10], decile_max[10], tot = 0;
+	unsigned int i;
+
+	/* Calc wear stats */
+	for (i = 0; i < wear_eb_count; ++i) {
+		unsigned long wear = erase_block_wear[i];
+		if (wear < wmin)
+			wmin = wear;
+		if (wear > wmax)
+			wmax = wear;
+		tot += wear;
+	}
+
+	for (i = 0; i < 9; ++i) {
+		deciles[i] = 0;
+		decile_max[i] = (wmax * (i + 1) + 5) / 10;
+	}
+	deciles[9] = 0;
+	decile_max[9] = wmax;
+	for (i = 0; i < wear_eb_count; ++i) {
+		int d;
+		unsigned long wear = erase_block_wear[i];
+		for (d = 0; d < 10; ++d)
+			if (wear <= decile_max[d]) {
+				deciles[d] += 1;
+				break;
+			}
+	}
+	avg = tot / wear_eb_count;
+
+	/* Output wear report */
+	seq_printf(m, "Total numbers of erases:  %lu\n", tot);
+	seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
+	seq_printf(m, "Average number of erases: %lu\n", avg);
+	seq_printf(m, "Maximum number of erases: %lu\n", wmax);
+	seq_printf(m, "Minimum number of erases: %lu\n", wmin);
+	for (i = 0; i < 10; ++i) {
+		unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+		if (from > decile_max[i])
+			continue;
+		seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
+			from,
+			decile_max[i],
+			deciles[i]);
+	}
+
+	return 0;
+}
+
+static int nandsim_debugfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, nandsim_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations dfs_fops = {
+	.open		= nandsim_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/**
+ * nandsim_debugfs_create - initialize debugfs
+ * @dev: nandsim device description object
+ *
+ * This function creates all debugfs files for UBI device @ubi. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int nandsim_debugfs_create(struct nandsim *dev)
+{
+	struct dentry *root = nsmtd->dbg.dfs_dir;
+	struct dentry *dent;
+
+	/*
+	 * Just skip debugfs initialization when the debugfs directory is
+	 * missing.
+	 */
+	if (IS_ERR_OR_NULL(root)) {
+		if (IS_ENABLED(CONFIG_DEBUG_FS) &&
+		    !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
+			NS_WARN("CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n");
+		return 0;
+	}
+
+	dent = debugfs_create_file("nandsim_wear_report", S_IRUSR,
+				   root, dev, &dfs_fops);
+	if (IS_ERR_OR_NULL(dent)) {
+		NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Allocate array of page pointers, create slab allocation for an array
+ * and initialize the array by NULL pointers.
+ *
+ * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
+ */
+static int __init alloc_device(struct nandsim *ns)
+{
+	struct file *cfile;
+	int i, err;
+
+	if (cache_file) {
+		cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+		if (IS_ERR(cfile))
+			return PTR_ERR(cfile);
+		if (!(cfile->f_mode & FMODE_CAN_READ)) {
+			NS_ERR("alloc_device: cache file not readable\n");
+			err = -EINVAL;
+			goto err_close;
+		}
+		if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
+			NS_ERR("alloc_device: cache file not writeable\n");
+			err = -EINVAL;
+			goto err_close;
+		}
+		ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
+					    sizeof(unsigned long));
+		if (!ns->pages_written) {
+			NS_ERR("alloc_device: unable to allocate pages written array\n");
+			err = -ENOMEM;
+			goto err_close;
+		}
+		ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+		if (!ns->file_buf) {
+			NS_ERR("alloc_device: unable to allocate file buf\n");
+			err = -ENOMEM;
+			goto err_free;
+		}
+		ns->cfile = cfile;
+		return 0;
+	}
+
+	ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
+	if (!ns->pages) {
+		NS_ERR("alloc_device: unable to allocate page array\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < ns->geom.pgnum; i++) {
+		ns->pages[i].byte = NULL;
+	}
+	ns->nand_pages_slab = kmem_cache_create("nandsim",
+						ns->geom.pgszoob, 0, 0, NULL);
+	if (!ns->nand_pages_slab) {
+		NS_ERR("cache_create: unable to create kmem_cache\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+
+err_free:
+	vfree(ns->pages_written);
+err_close:
+	filp_close(cfile, NULL);
+	return err;
+}
+
+/*
+ * Free any allocated pages, and free the array of page pointers.
+ */
+static void free_device(struct nandsim *ns)
+{
+	int i;
+
+	if (ns->cfile) {
+		kfree(ns->file_buf);
+		vfree(ns->pages_written);
+		filp_close(ns->cfile, NULL);
+		return;
+	}
+
+	if (ns->pages) {
+		for (i = 0; i < ns->geom.pgnum; i++) {
+			if (ns->pages[i].byte)
+				kmem_cache_free(ns->nand_pages_slab,
+						ns->pages[i].byte);
+		}
+		kmem_cache_destroy(ns->nand_pages_slab);
+		vfree(ns->pages);
+	}
+}
+
+static char __init *get_partition_name(int i)
+{
+	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
+}
+
+/*
+ * Initialize the nandsim structure.
+ *
+ * RETURNS: 0 if success, -ERRNO if failure.
+ */
+static int __init init_nandsim(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim   *ns   = nand_get_controller_data(chip);
+	int i, ret = 0;
+	uint64_t remains;
+	uint64_t next_offset;
+
+	if (NS_IS_INITIALIZED(ns)) {
+		NS_ERR("init_nandsim: nandsim is already initialized\n");
+		return -EIO;
+	}
+
+	/* Force mtd to not do delays */
+	chip->chip_delay = 0;
+
+	/* Initialize the NAND flash parameters */
+	ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
+	ns->geom.totsz    = mtd->size;
+	ns->geom.pgsz     = mtd->writesize;
+	ns->geom.oobsz    = mtd->oobsize;
+	ns->geom.secsz    = mtd->erasesize;
+	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
+	ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
+	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
+	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
+	ns->geom.pgshift  = chip->page_shift;
+	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
+	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
+	ns->options = 0;
+
+	if (ns->geom.pgsz == 512) {
+		ns->options |= OPT_PAGE512;
+		if (ns->busw == 8)
+			ns->options |= OPT_PAGE512_8BIT;
+	} else if (ns->geom.pgsz == 2048) {
+		ns->options |= OPT_PAGE2048;
+	} else if (ns->geom.pgsz == 4096) {
+		ns->options |= OPT_PAGE4096;
+	} else {
+		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
+		return -EIO;
+	}
+
+	if (ns->options & OPT_SMALLPAGE) {
+		if (ns->geom.totsz <= (32 << 20)) {
+			ns->geom.pgaddrbytes  = 3;
+			ns->geom.secaddrbytes = 2;
+		} else {
+			ns->geom.pgaddrbytes  = 4;
+			ns->geom.secaddrbytes = 3;
+		}
+	} else {
+		if (ns->geom.totsz <= (128 << 20)) {
+			ns->geom.pgaddrbytes  = 4;
+			ns->geom.secaddrbytes = 2;
+		} else {
+			ns->geom.pgaddrbytes  = 5;
+			ns->geom.secaddrbytes = 3;
+		}
+	}
+
+	/* Fill the partition_info structure */
+	if (parts_num > ARRAY_SIZE(ns->partitions)) {
+		NS_ERR("too many partitions.\n");
+		return -EINVAL;
+	}
+	remains = ns->geom.totsz;
+	next_offset = 0;
+	for (i = 0; i < parts_num; ++i) {
+		uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
+
+		if (!part_sz || part_sz > remains) {
+			NS_ERR("bad partition size.\n");
+			return -EINVAL;
+		}
+		ns->partitions[i].name   = get_partition_name(i);
+		if (!ns->partitions[i].name) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		ns->partitions[i].offset = next_offset;
+		ns->partitions[i].size   = part_sz;
+		next_offset += ns->partitions[i].size;
+		remains -= ns->partitions[i].size;
+	}
+	ns->nbparts = parts_num;
+	if (remains) {
+		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
+			NS_ERR("too many partitions.\n");
+			return -EINVAL;
+		}
+		ns->partitions[i].name   = get_partition_name(i);
+		if (!ns->partitions[i].name) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		ns->partitions[i].offset = next_offset;
+		ns->partitions[i].size   = remains;
+		ns->nbparts += 1;
+	}
+
+	if (ns->busw == 16)
+		NS_WARN("16-bit flashes support wasn't tested\n");
+
+	printk("flash size: %llu MiB\n",
+			(unsigned long long)ns->geom.totsz >> 20);
+	printk("page size: %u bytes\n",         ns->geom.pgsz);
+	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
+	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
+	printk("pages number: %u\n",            ns->geom.pgnum);
+	printk("pages per sector: %u\n",        ns->geom.pgsec);
+	printk("bus width: %u\n",               ns->busw);
+	printk("bits in sector size: %u\n",     ns->geom.secshift);
+	printk("bits in page size: %u\n",       ns->geom.pgshift);
+	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
+	printk("flash size with OOB: %llu KiB\n",
+			(unsigned long long)ns->geom.totszoob >> 10);
+	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
+	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
+	printk("options: %#x\n",                ns->options);
+
+	if ((ret = alloc_device(ns)) != 0)
+		return ret;
+
+	/* Allocate / initialize the internal buffer */
+	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+	if (!ns->buf.byte) {
+		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
+			ns->geom.pgszoob);
+		return -ENOMEM;
+	}
+	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
+
+	return 0;
+}
+
+/*
+ * Free the nandsim structure.
+ */
+static void free_nandsim(struct nandsim *ns)
+{
+	kfree(ns->buf.byte);
+	free_device(ns);
+
+	return;
+}
+
+static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
+{
+	char *w;
+	int zero_ok;
+	unsigned int erase_block_no;
+	loff_t offset;
+
+	if (!badblocks)
+		return 0;
+	w = badblocks;
+	do {
+		zero_ok = (*w == '0' ? 1 : 0);
+		erase_block_no = simple_strtoul(w, &w, 0);
+		if (!zero_ok && !erase_block_no) {
+			NS_ERR("invalid badblocks.\n");
+			return -EINVAL;
+		}
+		offset = (loff_t)erase_block_no * ns->geom.secsz;
+		if (mtd_block_markbad(mtd, offset)) {
+			NS_ERR("invalid badblocks.\n");
+			return -EINVAL;
+		}
+		if (*w == ',')
+			w += 1;
+	} while (*w);
+	return 0;
+}
+
+static int parse_weakblocks(void)
+{
+	char *w;
+	int zero_ok;
+	unsigned int erase_block_no;
+	unsigned int max_erases;
+	struct weak_block *wb;
+
+	if (!weakblocks)
+		return 0;
+	w = weakblocks;
+	do {
+		zero_ok = (*w == '0' ? 1 : 0);
+		erase_block_no = simple_strtoul(w, &w, 0);
+		if (!zero_ok && !erase_block_no) {
+			NS_ERR("invalid weakblocks.\n");
+			return -EINVAL;
+		}
+		max_erases = 3;
+		if (*w == ':') {
+			w += 1;
+			max_erases = simple_strtoul(w, &w, 0);
+		}
+		if (*w == ',')
+			w += 1;
+		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+		if (!wb) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		wb->erase_block_no = erase_block_no;
+		wb->max_erases = max_erases;
+		list_add(&wb->list, &weak_blocks);
+	} while (*w);
+	return 0;
+}
+
+static int erase_error(unsigned int erase_block_no)
+{
+	struct weak_block *wb;
+
+	list_for_each_entry(wb, &weak_blocks, list)
+		if (wb->erase_block_no == erase_block_no) {
+			if (wb->erases_done >= wb->max_erases)
+				return 1;
+			wb->erases_done += 1;
+			return 0;
+		}
+	return 0;
+}
+
+static int parse_weakpages(void)
+{
+	char *w;
+	int zero_ok;
+	unsigned int page_no;
+	unsigned int max_writes;
+	struct weak_page *wp;
+
+	if (!weakpages)
+		return 0;
+	w = weakpages;
+	do {
+		zero_ok = (*w == '0' ? 1 : 0);
+		page_no = simple_strtoul(w, &w, 0);
+		if (!zero_ok && !page_no) {
+			NS_ERR("invalid weakpages.\n");
+			return -EINVAL;
+		}
+		max_writes = 3;
+		if (*w == ':') {
+			w += 1;
+			max_writes = simple_strtoul(w, &w, 0);
+		}
+		if (*w == ',')
+			w += 1;
+		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
+		if (!wp) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		wp->page_no = page_no;
+		wp->max_writes = max_writes;
+		list_add(&wp->list, &weak_pages);
+	} while (*w);
+	return 0;
+}
+
+static int write_error(unsigned int page_no)
+{
+	struct weak_page *wp;
+
+	list_for_each_entry(wp, &weak_pages, list)
+		if (wp->page_no == page_no) {
+			if (wp->writes_done >= wp->max_writes)
+				return 1;
+			wp->writes_done += 1;
+			return 0;
+		}
+	return 0;
+}
+
+static int parse_gravepages(void)
+{
+	char *g;
+	int zero_ok;
+	unsigned int page_no;
+	unsigned int max_reads;
+	struct grave_page *gp;
+
+	if (!gravepages)
+		return 0;
+	g = gravepages;
+	do {
+		zero_ok = (*g == '0' ? 1 : 0);
+		page_no = simple_strtoul(g, &g, 0);
+		if (!zero_ok && !page_no) {
+			NS_ERR("invalid gravepagess.\n");
+			return -EINVAL;
+		}
+		max_reads = 3;
+		if (*g == ':') {
+			g += 1;
+			max_reads = simple_strtoul(g, &g, 0);
+		}
+		if (*g == ',')
+			g += 1;
+		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
+		if (!gp) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		gp->page_no = page_no;
+		gp->max_reads = max_reads;
+		list_add(&gp->list, &grave_pages);
+	} while (*g);
+	return 0;
+}
+
+static int read_error(unsigned int page_no)
+{
+	struct grave_page *gp;
+
+	list_for_each_entry(gp, &grave_pages, list)
+		if (gp->page_no == page_no) {
+			if (gp->reads_done >= gp->max_reads)
+				return 1;
+			gp->reads_done += 1;
+			return 0;
+		}
+	return 0;
+}
+
+static void free_lists(void)
+{
+	struct list_head *pos, *n;
+	list_for_each_safe(pos, n, &weak_blocks) {
+		list_del(pos);
+		kfree(list_entry(pos, struct weak_block, list));
+	}
+	list_for_each_safe(pos, n, &weak_pages) {
+		list_del(pos);
+		kfree(list_entry(pos, struct weak_page, list));
+	}
+	list_for_each_safe(pos, n, &grave_pages) {
+		list_del(pos);
+		kfree(list_entry(pos, struct grave_page, list));
+	}
+	kfree(erase_block_wear);
+}
+
+static int setup_wear_reporting(struct mtd_info *mtd)
+{
+	size_t mem;
+
+	wear_eb_count = div_u64(mtd->size, mtd->erasesize);
+	mem = wear_eb_count * sizeof(unsigned long);
+	if (mem / sizeof(unsigned long) != wear_eb_count) {
+		NS_ERR("Too many erase blocks for wear reporting\n");
+		return -ENOMEM;
+	}
+	erase_block_wear = kzalloc(mem, GFP_KERNEL);
+	if (!erase_block_wear) {
+		NS_ERR("Too many erase blocks for wear reporting\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void update_wear(unsigned int erase_block_no)
+{
+	if (!erase_block_wear)
+		return;
+	total_wear += 1;
+	/*
+	 * TODO: Notify this through a debugfs entry,
+	 * instead of showing an error message.
+	 */
+	if (total_wear == 0)
+		NS_ERR("Erase counter total overflow\n");
+	erase_block_wear[erase_block_no] += 1;
+	if (erase_block_wear[erase_block_no] == 0)
+		NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
+}
+
+/*
+ * Returns the string representation of 'state' state.
+ */
+static char *get_state_name(uint32_t state)
+{
+	switch (NS_STATE(state)) {
+		case STATE_CMD_READ0:
+			return "STATE_CMD_READ0";
+		case STATE_CMD_READ1:
+			return "STATE_CMD_READ1";
+		case STATE_CMD_PAGEPROG:
+			return "STATE_CMD_PAGEPROG";
+		case STATE_CMD_READOOB:
+			return "STATE_CMD_READOOB";
+		case STATE_CMD_READSTART:
+			return "STATE_CMD_READSTART";
+		case STATE_CMD_ERASE1:
+			return "STATE_CMD_ERASE1";
+		case STATE_CMD_STATUS:
+			return "STATE_CMD_STATUS";
+		case STATE_CMD_SEQIN:
+			return "STATE_CMD_SEQIN";
+		case STATE_CMD_READID:
+			return "STATE_CMD_READID";
+		case STATE_CMD_ERASE2:
+			return "STATE_CMD_ERASE2";
+		case STATE_CMD_RESET:
+			return "STATE_CMD_RESET";
+		case STATE_CMD_RNDOUT:
+			return "STATE_CMD_RNDOUT";
+		case STATE_CMD_RNDOUTSTART:
+			return "STATE_CMD_RNDOUTSTART";
+		case STATE_ADDR_PAGE:
+			return "STATE_ADDR_PAGE";
+		case STATE_ADDR_SEC:
+			return "STATE_ADDR_SEC";
+		case STATE_ADDR_ZERO:
+			return "STATE_ADDR_ZERO";
+		case STATE_ADDR_COLUMN:
+			return "STATE_ADDR_COLUMN";
+		case STATE_DATAIN:
+			return "STATE_DATAIN";
+		case STATE_DATAOUT:
+			return "STATE_DATAOUT";
+		case STATE_DATAOUT_ID:
+			return "STATE_DATAOUT_ID";
+		case STATE_DATAOUT_STATUS:
+			return "STATE_DATAOUT_STATUS";
+		case STATE_READY:
+			return "STATE_READY";
+		case STATE_UNKNOWN:
+			return "STATE_UNKNOWN";
+	}
+
+	NS_ERR("get_state_name: unknown state, BUG\n");
+	return NULL;
+}
+
+/*
+ * Check if command is valid.
+ *
+ * RETURNS: 1 if wrong command, 0 if right.
+ */
+static int check_command(int cmd)
+{
+	switch (cmd) {
+
+	case NAND_CMD_READ0:
+	case NAND_CMD_READ1:
+	case NAND_CMD_READSTART:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_READOOB:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_READID:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_RESET:
+	case NAND_CMD_RNDOUT:
+	case NAND_CMD_RNDOUTSTART:
+		return 0;
+
+	default:
+		return 1;
+	}
+}
+
+/*
+ * Returns state after command is accepted by command number.
+ */
+static uint32_t get_state_by_command(unsigned command)
+{
+	switch (command) {
+		case NAND_CMD_READ0:
+			return STATE_CMD_READ0;
+		case NAND_CMD_READ1:
+			return STATE_CMD_READ1;
+		case NAND_CMD_PAGEPROG:
+			return STATE_CMD_PAGEPROG;
+		case NAND_CMD_READSTART:
+			return STATE_CMD_READSTART;
+		case NAND_CMD_READOOB:
+			return STATE_CMD_READOOB;
+		case NAND_CMD_ERASE1:
+			return STATE_CMD_ERASE1;
+		case NAND_CMD_STATUS:
+			return STATE_CMD_STATUS;
+		case NAND_CMD_SEQIN:
+			return STATE_CMD_SEQIN;
+		case NAND_CMD_READID:
+			return STATE_CMD_READID;
+		case NAND_CMD_ERASE2:
+			return STATE_CMD_ERASE2;
+		case NAND_CMD_RESET:
+			return STATE_CMD_RESET;
+		case NAND_CMD_RNDOUT:
+			return STATE_CMD_RNDOUT;
+		case NAND_CMD_RNDOUTSTART:
+			return STATE_CMD_RNDOUTSTART;
+	}
+
+	NS_ERR("get_state_by_command: unknown command, BUG\n");
+	return 0;
+}
+
+/*
+ * Move an address byte to the correspondent internal register.
+ */
+static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
+{
+	uint byte = (uint)bt;
+
+	if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
+		ns->regs.column |= (byte << 8 * ns->regs.count);
+	else {
+		ns->regs.row |= (byte << 8 * (ns->regs.count -
+						ns->geom.pgaddrbytes +
+						ns->geom.secaddrbytes));
+	}
+
+	return;
+}
+
+/*
+ * Switch to STATE_READY state.
+ */
+static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
+{
+	NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
+
+	ns->state       = STATE_READY;
+	ns->nxstate     = STATE_UNKNOWN;
+	ns->op          = NULL;
+	ns->npstates    = 0;
+	ns->stateidx    = 0;
+	ns->regs.num    = 0;
+	ns->regs.count  = 0;
+	ns->regs.off    = 0;
+	ns->regs.row    = 0;
+	ns->regs.column = 0;
+	ns->regs.status = status;
+}
+
+/*
+ * If the operation isn't known yet, try to find it in the global array
+ * of supported operations.
+ *
+ * Operation can be unknown because of the following.
+ *   1. New command was accepted and this is the first call to find the
+ *      correspondent states chain. In this case ns->npstates = 0;
+ *   2. There are several operations which begin with the same command(s)
+ *      (for example program from the second half and read from the
+ *      second half operations both begin with the READ1 command). In this
+ *      case the ns->pstates[] array contains previous states.
+ *
+ * Thus, the function tries to find operation containing the following
+ * states (if the 'flag' parameter is 0):
+ *    ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
+ *
+ * If (one and only one) matching operation is found, it is accepted (
+ * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
+ * zeroed).
+ *
+ * If there are several matches, the current state is pushed to the
+ * ns->pstates.
+ *
+ * The operation can be unknown only while commands are input to the chip.
+ * As soon as address command is accepted, the operation must be known.
+ * In such situation the function is called with 'flag' != 0, and the
+ * operation is searched using the following pattern:
+ *     ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
+ *
+ * It is supposed that this pattern must either match one operation or
+ * none. There can't be ambiguity in that case.
+ *
+ * If no matches found, the function does the following:
+ *   1. if there are saved states present, try to ignore them and search
+ *      again only using the last command. If nothing was found, switch
+ *      to the STATE_READY state.
+ *   2. if there are no saved states, switch to the STATE_READY state.
+ *
+ * RETURNS: -2 - no matched operations found.
+ *          -1 - several matches.
+ *           0 - operation is found.
+ */
+static int find_operation(struct nandsim *ns, uint32_t flag)
+{
+	int opsfound = 0;
+	int i, j, idx = 0;
+
+	for (i = 0; i < NS_OPER_NUM; i++) {
+
+		int found = 1;
+
+		if (!(ns->options & ops[i].reqopts))
+			/* Ignore operations we can't perform */
+			continue;
+
+		if (flag) {
+			if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
+				continue;
+		} else {
+			if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates]))
+				continue;
+		}
+
+		for (j = 0; j < ns->npstates; j++)
+			if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
+				&& (ns->options & ops[idx].reqopts)) {
+				found = 0;
+				break;
+			}
+
+		if (found) {
+			idx = i;
+			opsfound += 1;
+		}
+	}
+
+	if (opsfound == 1) {
+		/* Exact match */
+		ns->op = &ops[idx].states[0];
+		if (flag) {
+			/*
+			 * In this case the find_operation function was
+			 * called when address has just began input. But it isn't
+			 * yet fully input and the current state must
+			 * not be one of STATE_ADDR_*, but the STATE_ADDR_*
+			 * state must be the next state (ns->nxstate).
+			 */
+			ns->stateidx = ns->npstates - 1;
+		} else {
+			ns->stateidx = ns->npstates;
+		}
+		ns->npstates = 0;
+		ns->state = ns->op[ns->stateidx];
+		ns->nxstate = ns->op[ns->stateidx + 1];
+		NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
+				idx, get_state_name(ns->state), get_state_name(ns->nxstate));
+		return 0;
+	}
+
+	if (opsfound == 0) {
+		/* Nothing was found. Try to ignore previous commands (if any) and search again */
+		if (ns->npstates != 0) {
+			NS_DBG("find_operation: no operation found, try again with state %s\n",
+					get_state_name(ns->state));
+			ns->npstates = 0;
+			return find_operation(ns, 0);
+
+		}
+		NS_DBG("find_operation: no operations found\n");
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return -2;
+	}
+
+	if (flag) {
+		/* This shouldn't happen */
+		NS_DBG("find_operation: BUG, operation must be known if address is input\n");
+		return -2;
+	}
+
+	NS_DBG("find_operation: there is still ambiguity\n");
+
+	ns->pstates[ns->npstates++] = ns->state;
+
+	return -1;
+}
+
+static void put_pages(struct nandsim *ns)
+{
+	int i;
+
+	for (i = 0; i < ns->held_cnt; i++)
+		put_page(ns->held_pages[i]);
+}
+
+/* Get page cache pages in advance to provide NOFS memory allocation */
+static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
+{
+	pgoff_t index, start_index, end_index;
+	struct page *page;
+	struct address_space *mapping = file->f_mapping;
+
+	start_index = pos >> PAGE_SHIFT;
+	end_index = (pos + count - 1) >> PAGE_SHIFT;
+	if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
+		return -EINVAL;
+	ns->held_cnt = 0;
+	for (index = start_index; index <= end_index; index++) {
+		page = find_get_page(mapping, index);
+		if (page == NULL) {
+			page = find_or_create_page(mapping, index, GFP_NOFS);
+			if (page == NULL) {
+				write_inode_now(mapping->host, 1);
+				page = find_or_create_page(mapping, index, GFP_NOFS);
+			}
+			if (page == NULL) {
+				put_pages(ns);
+				return -ENOMEM;
+			}
+			unlock_page(page);
+		}
+		ns->held_pages[ns->held_cnt++] = page;
+	}
+	return 0;
+}
+
+static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
+{
+	ssize_t tx;
+	int err;
+	unsigned int noreclaim_flag;
+
+	err = get_pages(ns, file, count, pos);
+	if (err)
+		return err;
+	noreclaim_flag = memalloc_noreclaim_save();
+	tx = kernel_read(file, buf, count, &pos);
+	memalloc_noreclaim_restore(noreclaim_flag);
+	put_pages(ns);
+	return tx;
+}
+
+static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
+{
+	ssize_t tx;
+	int err;
+	unsigned int noreclaim_flag;
+
+	err = get_pages(ns, file, count, pos);
+	if (err)
+		return err;
+	noreclaim_flag = memalloc_noreclaim_save();
+	tx = kernel_write(file, buf, count, &pos);
+	memalloc_noreclaim_restore(noreclaim_flag);
+	put_pages(ns);
+	return tx;
+}
+
+/*
+ * Returns a pointer to the current page.
+ */
+static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
+{
+	return &(ns->pages[ns->regs.row]);
+}
+
+/*
+ * Retuns a pointer to the current byte, within the current page.
+ */
+static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
+{
+	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
+}
+
+static int do_read_error(struct nandsim *ns, int num)
+{
+	unsigned int page_no = ns->regs.row;
+
+	if (read_error(page_no)) {
+		prandom_bytes(ns->buf.byte, num);
+		NS_WARN("simulating read error in page %u\n", page_no);
+		return 1;
+	}
+	return 0;
+}
+
+static void do_bit_flips(struct nandsim *ns, int num)
+{
+	if (bitflips && prandom_u32() < (1 << 22)) {
+		int flips = 1;
+		if (bitflips > 1)
+			flips = (prandom_u32() % (int) bitflips) + 1;
+		while (flips--) {
+			int pos = prandom_u32() % (num * 8);
+			ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
+			NS_WARN("read_page: flipping bit %d in page %d "
+				"reading from %d ecc: corrected=%u failed=%u\n",
+				pos, ns->regs.row, ns->regs.column + ns->regs.off,
+				nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
+		}
+	}
+}
+
+/*
+ * Fill the NAND buffer with data read from the specified page.
+ */
+static void read_page(struct nandsim *ns, int num)
+{
+	union ns_mem *mypage;
+
+	if (ns->cfile) {
+		if (!test_bit(ns->regs.row, ns->pages_written)) {
+			NS_DBG("read_page: page %d not written\n", ns->regs.row);
+			memset(ns->buf.byte, 0xFF, num);
+		} else {
+			loff_t pos;
+			ssize_t tx;
+
+			NS_DBG("read_page: page %d written, reading from %d\n",
+				ns->regs.row, ns->regs.column + ns->regs.off);
+			if (do_read_error(ns, num))
+				return;
+			pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
+			if (tx != num) {
+				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+				return;
+			}
+			do_bit_flips(ns, num);
+		}
+		return;
+	}
+
+	mypage = NS_GET_PAGE(ns);
+	if (mypage->byte == NULL) {
+		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
+		memset(ns->buf.byte, 0xFF, num);
+	} else {
+		NS_DBG("read_page: page %d allocated, reading from %d\n",
+			ns->regs.row, ns->regs.column + ns->regs.off);
+		if (do_read_error(ns, num))
+			return;
+		memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
+		do_bit_flips(ns, num);
+	}
+}
+
+/*
+ * Erase all pages in the specified sector.
+ */
+static void erase_sector(struct nandsim *ns)
+{
+	union ns_mem *mypage;
+	int i;
+
+	if (ns->cfile) {
+		for (i = 0; i < ns->geom.pgsec; i++)
+			if (__test_and_clear_bit(ns->regs.row + i,
+						 ns->pages_written)) {
+				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
+			}
+		return;
+	}
+
+	mypage = NS_GET_PAGE(ns);
+	for (i = 0; i < ns->geom.pgsec; i++) {
+		if (mypage->byte != NULL) {
+			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
+			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
+			mypage->byte = NULL;
+		}
+		mypage++;
+	}
+}
+
+/*
+ * Program the specified page with the contents from the NAND buffer.
+ */
+static int prog_page(struct nandsim *ns, int num)
+{
+	int i;
+	union ns_mem *mypage;
+	u_char *pg_off;
+
+	if (ns->cfile) {
+		loff_t off;
+		ssize_t tx;
+		int all;
+
+		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
+		off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+		if (!test_bit(ns->regs.row, ns->pages_written)) {
+			all = 1;
+			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
+		} else {
+			all = 0;
+			tx = read_file(ns, ns->cfile, pg_off, num, off);
+			if (tx != num) {
+				NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+				return -1;
+			}
+		}
+		for (i = 0; i < num; i++)
+			pg_off[i] &= ns->buf.byte[i];
+		if (all) {
+			loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
+			tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
+			if (tx != ns->geom.pgszoob) {
+				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+				return -1;
+			}
+			__set_bit(ns->regs.row, ns->pages_written);
+		} else {
+			tx = write_file(ns, ns->cfile, pg_off, num, off);
+			if (tx != num) {
+				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+				return -1;
+			}
+		}
+		return 0;
+	}
+
+	mypage = NS_GET_PAGE(ns);
+	if (mypage->byte == NULL) {
+		NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
+		/*
+		 * We allocate memory with GFP_NOFS because a flash FS may
+		 * utilize this. If it is holding an FS lock, then gets here,
+		 * then kernel memory alloc runs writeback which goes to the FS
+		 * again and deadlocks. This was seen in practice.
+		 */
+		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
+		if (mypage->byte == NULL) {
+			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
+			return -1;
+		}
+		memset(mypage->byte, 0xFF, ns->geom.pgszoob);
+	}
+
+	pg_off = NS_PAGE_BYTE_OFF(ns);
+	for (i = 0; i < num; i++)
+		pg_off[i] &= ns->buf.byte[i];
+
+	return 0;
+}
+
+/*
+ * If state has any action bit, perform this action.
+ *
+ * RETURNS: 0 if success, -1 if error.
+ */
+static int do_state_action(struct nandsim *ns, uint32_t action)
+{
+	int num;
+	int busdiv = ns->busw == 8 ? 1 : 2;
+	unsigned int erase_block_no, page_no;
+
+	action &= ACTION_MASK;
+
+	/* Check that page address input is correct */
+	if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
+		NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
+		return -1;
+	}
+
+	switch (action) {
+
+	case ACTION_CPY:
+		/*
+		 * Copy page data to the internal buffer.
+		 */
+
+		/* Column shouldn't be very large */
+		if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
+			NS_ERR("do_state_action: column number is too large\n");
+			break;
+		}
+		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+		read_page(ns, num);
+
+		NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
+			num, NS_RAW_OFFSET(ns) + ns->regs.off);
+
+		if (ns->regs.off == 0)
+			NS_LOG("read page %d\n", ns->regs.row);
+		else if (ns->regs.off < ns->geom.pgsz)
+			NS_LOG("read page %d (second half)\n", ns->regs.row);
+		else
+			NS_LOG("read OOB of page %d\n", ns->regs.row);
+
+		NS_UDELAY(access_delay);
+		NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
+
+		break;
+
+	case ACTION_SECERASE:
+		/*
+		 * Erase sector.
+		 */
+
+		if (ns->lines.wp) {
+			NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
+			return -1;
+		}
+
+		if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
+			|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
+			NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
+			return -1;
+		}
+
+		ns->regs.row = (ns->regs.row <<
+				8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
+		ns->regs.column = 0;
+
+		erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
+
+		NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
+				ns->regs.row, NS_RAW_OFFSET(ns));
+		NS_LOG("erase sector %u\n", erase_block_no);
+
+		erase_sector(ns);
+
+		NS_MDELAY(erase_delay);
+
+		if (erase_block_wear)
+			update_wear(erase_block_no);
+
+		if (erase_error(erase_block_no)) {
+			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
+			return -1;
+		}
+
+		break;
+
+	case ACTION_PRGPAGE:
+		/*
+		 * Program page - move internal buffer data to the page.
+		 */
+
+		if (ns->lines.wp) {
+			NS_WARN("do_state_action: device is write-protected, programm\n");
+			return -1;
+		}
+
+		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+		if (num != ns->regs.count) {
+			NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
+					ns->regs.count, num);
+			return -1;
+		}
+
+		if (prog_page(ns, num) == -1)
+			return -1;
+
+		page_no = ns->regs.row;
+
+		NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
+			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
+		NS_LOG("programm page %d\n", ns->regs.row);
+
+		NS_UDELAY(programm_delay);
+		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
+
+		if (write_error(page_no)) {
+			NS_WARN("simulating write failure in page %u\n", page_no);
+			return -1;
+		}
+
+		break;
+
+	case ACTION_ZEROOFF:
+		NS_DBG("do_state_action: set internal offset to 0\n");
+		ns->regs.off = 0;
+		break;
+
+	case ACTION_HALFOFF:
+		if (!(ns->options & OPT_PAGE512_8BIT)) {
+			NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
+				"byte page size 8x chips\n");
+			return -1;
+		}
+		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
+		ns->regs.off = ns->geom.pgsz/2;
+		break;
+
+	case ACTION_OOBOFF:
+		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
+		ns->regs.off = ns->geom.pgsz;
+		break;
+
+	default:
+		NS_DBG("do_state_action: BUG! unknown action\n");
+	}
+
+	return 0;
+}
+
+/*
+ * Switch simulator's state.
+ */
+static void switch_state(struct nandsim *ns)
+{
+	if (ns->op) {
+		/*
+		 * The current operation have already been identified.
+		 * Just follow the states chain.
+		 */
+
+		ns->stateidx += 1;
+		ns->state = ns->nxstate;
+		ns->nxstate = ns->op[ns->stateidx + 1];
+
+		NS_DBG("switch_state: operation is known, switch to the next state, "
+			"state: %s, nxstate: %s\n",
+			get_state_name(ns->state), get_state_name(ns->nxstate));
+
+		/* See, whether we need to do some action */
+		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+
+	} else {
+		/*
+		 * We don't yet know which operation we perform.
+		 * Try to identify it.
+		 */
+
+		/*
+		 *  The only event causing the switch_state function to
+		 *  be called with yet unknown operation is new command.
+		 */
+		ns->state = get_state_by_command(ns->regs.command);
+
+		NS_DBG("switch_state: operation is unknown, try to find it\n");
+
+		if (find_operation(ns, 0) != 0)
+			return;
+
+		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+	}
+
+	/* For 16x devices column means the page offset in words */
+	if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
+		NS_DBG("switch_state: double the column number for 16x device\n");
+		ns->regs.column <<= 1;
+	}
+
+	if (NS_STATE(ns->nxstate) == STATE_READY) {
+		/*
+		 * The current state is the last. Return to STATE_READY
+		 */
+
+		u_char status = NS_STATUS_OK(ns);
+
+		/* In case of data states, see if all bytes were input/output */
+		if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
+			&& ns->regs.count != ns->regs.num) {
+			NS_WARN("switch_state: not all bytes were processed, %d left\n",
+					ns->regs.num - ns->regs.count);
+			status = NS_STATUS_FAILED(ns);
+		}
+
+		NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
+
+		switch_to_ready_state(ns, status);
+
+		return;
+	} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
+		/*
+		 * If the next state is data input/output, switch to it now
+		 */
+
+		ns->state      = ns->nxstate;
+		ns->nxstate    = ns->op[++ns->stateidx + 1];
+		ns->regs.num   = ns->regs.count = 0;
+
+		NS_DBG("switch_state: the next state is data I/O, switch, "
+			"state: %s, nxstate: %s\n",
+			get_state_name(ns->state), get_state_name(ns->nxstate));
+
+		/*
+		 * Set the internal register to the count of bytes which
+		 * are expected to be input or output
+		 */
+		switch (NS_STATE(ns->state)) {
+			case STATE_DATAIN:
+			case STATE_DATAOUT:
+				ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+				break;
+
+			case STATE_DATAOUT_ID:
+				ns->regs.num = ns->geom.idbytes;
+				break;
+
+			case STATE_DATAOUT_STATUS:
+				ns->regs.count = ns->regs.num = 0;
+				break;
+
+			default:
+				NS_ERR("switch_state: BUG! unknown data state\n");
+		}
+
+	} else if (ns->nxstate & STATE_ADDR_MASK) {
+		/*
+		 * If the next state is address input, set the internal
+		 * register to the number of expected address bytes
+		 */
+
+		ns->regs.count = 0;
+
+		switch (NS_STATE(ns->nxstate)) {
+			case STATE_ADDR_PAGE:
+				ns->regs.num = ns->geom.pgaddrbytes;
+
+				break;
+			case STATE_ADDR_SEC:
+				ns->regs.num = ns->geom.secaddrbytes;
+				break;
+
+			case STATE_ADDR_ZERO:
+				ns->regs.num = 1;
+				break;
+
+			case STATE_ADDR_COLUMN:
+				/* Column address is always 2 bytes */
+				ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes;
+				break;
+
+			default:
+				NS_ERR("switch_state: BUG! unknown address state\n");
+		}
+	} else {
+		/*
+		 * Just reset internal counters.
+		 */
+
+		ns->regs.num = 0;
+		ns->regs.count = 0;
+	}
+}
+
+static u_char ns_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+	u_char outb = 0x00;
+
+	/* Sanity and correctness checks */
+	if (!ns->lines.ce) {
+		NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
+		return outb;
+	}
+	if (ns->lines.ale || ns->lines.cle) {
+		NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
+		return outb;
+	}
+	if (!(ns->state & STATE_DATAOUT_MASK)) {
+		NS_WARN("read_byte: unexpected data output cycle, state is %s "
+			"return %#x\n", get_state_name(ns->state), (uint)outb);
+		return outb;
+	}
+
+	/* Status register may be read as many times as it is wanted */
+	if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
+		NS_DBG("read_byte: return %#x status\n", ns->regs.status);
+		return ns->regs.status;
+	}
+
+	/* Check if there is any data in the internal buffer which may be read */
+	if (ns->regs.count == ns->regs.num) {
+		NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
+		return outb;
+	}
+
+	switch (NS_STATE(ns->state)) {
+		case STATE_DATAOUT:
+			if (ns->busw == 8) {
+				outb = ns->buf.byte[ns->regs.count];
+				ns->regs.count += 1;
+			} else {
+				outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
+				ns->regs.count += 2;
+			}
+			break;
+		case STATE_DATAOUT_ID:
+			NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
+			outb = ns->ids[ns->regs.count];
+			ns->regs.count += 1;
+			break;
+		default:
+			BUG();
+	}
+
+	if (ns->regs.count == ns->regs.num) {
+		NS_DBG("read_byte: all bytes were read\n");
+
+		if (NS_STATE(ns->nxstate) == STATE_READY)
+			switch_state(ns);
+	}
+
+	return outb;
+}
+
+static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+
+	/* Sanity and correctness checks */
+	if (!ns->lines.ce) {
+		NS_ERR("write_byte: chip is disabled, ignore write\n");
+		return;
+	}
+	if (ns->lines.ale && ns->lines.cle) {
+		NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
+		return;
+	}
+
+	if (ns->lines.cle == 1) {
+		/*
+		 * The byte written is a command.
+		 */
+
+		if (byte == NAND_CMD_RESET) {
+			NS_LOG("reset chip\n");
+			switch_to_ready_state(ns, NS_STATUS_OK(ns));
+			return;
+		}
+
+		/* Check that the command byte is correct */
+		if (check_command(byte)) {
+			NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
+			return;
+		}
+
+		if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
+			|| NS_STATE(ns->state) == STATE_DATAOUT) {
+			int row = ns->regs.row;
+
+			switch_state(ns);
+			if (byte == NAND_CMD_RNDOUT)
+				ns->regs.row = row;
+		}
+
+		/* Check if chip is expecting command */
+		if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
+			/* Do not warn if only 2 id bytes are read */
+			if (!(ns->regs.command == NAND_CMD_READID &&
+			    NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
+				/*
+				 * We are in situation when something else (not command)
+				 * was expected but command was input. In this case ignore
+				 * previous command(s)/state(s) and accept the last one.
+				 */
+				NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
+					"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
+			}
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		}
+
+		NS_DBG("command byte corresponding to %s state accepted\n",
+			get_state_name(get_state_by_command(byte)));
+		ns->regs.command = byte;
+		switch_state(ns);
+
+	} else if (ns->lines.ale == 1) {
+		/*
+		 * The byte written is an address.
+		 */
+
+		if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
+
+			NS_DBG("write_byte: operation isn't known yet, identify it\n");
+
+			if (find_operation(ns, 1) < 0)
+				return;
+
+			if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+				switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+				return;
+			}
+
+			ns->regs.count = 0;
+			switch (NS_STATE(ns->nxstate)) {
+				case STATE_ADDR_PAGE:
+					ns->regs.num = ns->geom.pgaddrbytes;
+					break;
+				case STATE_ADDR_SEC:
+					ns->regs.num = ns->geom.secaddrbytes;
+					break;
+				case STATE_ADDR_ZERO:
+					ns->regs.num = 1;
+					break;
+				default:
+					BUG();
+			}
+		}
+
+		/* Check that chip is expecting address */
+		if (!(ns->nxstate & STATE_ADDR_MASK)) {
+			NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
+				"switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+
+		/* Check if this is expected byte */
+		if (ns->regs.count == ns->regs.num) {
+			NS_ERR("write_byte: no more address bytes expected\n");
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+
+		accept_addr_byte(ns, byte);
+
+		ns->regs.count += 1;
+
+		NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
+				(uint)byte, ns->regs.count, ns->regs.num);
+
+		if (ns->regs.count == ns->regs.num) {
+			NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
+			switch_state(ns);
+		}
+
+	} else {
+		/*
+		 * The byte written is an input data.
+		 */
+
+		/* Check that chip is expecting data input */
+		if (!(ns->state & STATE_DATAIN_MASK)) {
+			NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
+				"switch to %s\n", (uint)byte,
+				get_state_name(ns->state), get_state_name(STATE_READY));
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+
+		/* Check if this is expected byte */
+		if (ns->regs.count == ns->regs.num) {
+			NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
+					ns->regs.num);
+			return;
+		}
+
+		if (ns->busw == 8) {
+			ns->buf.byte[ns->regs.count] = byte;
+			ns->regs.count += 1;
+		} else {
+			ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
+			ns->regs.count += 2;
+		}
+	}
+
+	return;
+}
+
+static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+
+	ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
+	ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
+	ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
+
+	if (cmd != NAND_CMD_NONE)
+		ns_nand_write_byte(mtd, cmd);
+}
+
+static int ns_device_ready(struct mtd_info *mtd)
+{
+	NS_DBG("device_ready\n");
+	return 1;
+}
+
+static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	NS_DBG("read_word\n");
+
+	return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
+}
+
+static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+
+	/* Check that chip is expecting data input */
+	if (!(ns->state & STATE_DATAIN_MASK)) {
+		NS_ERR("write_buf: data input isn't expected, state is %s, "
+			"switch to STATE_READY\n", get_state_name(ns->state));
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return;
+	}
+
+	/* Check if these are expected bytes */
+	if (ns->regs.count + len > ns->regs.num) {
+		NS_ERR("write_buf: too many input bytes\n");
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return;
+	}
+
+	memcpy(ns->buf.byte + ns->regs.count, buf, len);
+	ns->regs.count += len;
+
+	if (ns->regs.count == ns->regs.num) {
+		NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
+	}
+}
+
+static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+
+	/* Sanity and correctness checks */
+	if (!ns->lines.ce) {
+		NS_ERR("read_buf: chip is disabled\n");
+		return;
+	}
+	if (ns->lines.ale || ns->lines.cle) {
+		NS_ERR("read_buf: ALE or CLE pin is high\n");
+		return;
+	}
+	if (!(ns->state & STATE_DATAOUT_MASK)) {
+		NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
+			get_state_name(ns->state));
+		return;
+	}
+
+	if (NS_STATE(ns->state) != STATE_DATAOUT) {
+		int i;
+
+		for (i = 0; i < len; i++)
+			buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+
+		return;
+	}
+
+	/* Check if these are expected bytes */
+	if (ns->regs.count + len > ns->regs.num) {
+		NS_ERR("read_buf: too many bytes to read\n");
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return;
+	}
+
+	memcpy(buf, ns->buf.byte + ns->regs.count, len);
+	ns->regs.count += len;
+
+	if (ns->regs.count == ns->regs.num) {
+		if (NS_STATE(ns->nxstate) == STATE_READY)
+			switch_state(ns);
+	}
+
+	return;
+}
+
+/*
+ * Module initialization function
+ */
+static int __init ns_init_module(void)
+{
+	struct nand_chip *chip;
+	struct nandsim *nand;
+	int retval = -ENOMEM, i;
+
+	if (bus_width != 8 && bus_width != 16) {
+		NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
+		return -EINVAL;
+	}
+
+	/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
+	chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
+		       GFP_KERNEL);
+	if (!chip) {
+		NS_ERR("unable to allocate core structures.\n");
+		return -ENOMEM;
+	}
+	nsmtd       = nand_to_mtd(chip);
+	nand        = (struct nandsim *)(chip + 1);
+	nand_set_controller_data(chip, (void *)nand);
+
+	/*
+	 * Register simulator's callbacks.
+	 */
+	chip->cmd_ctrl	 = ns_hwcontrol;
+	chip->read_byte  = ns_nand_read_byte;
+	chip->dev_ready  = ns_device_ready;
+	chip->write_buf  = ns_nand_write_buf;
+	chip->read_buf   = ns_nand_read_buf;
+	chip->read_word  = ns_nand_read_word;
+	chip->ecc.mode   = NAND_ECC_SOFT;
+	chip->ecc.algo   = NAND_ECC_HAMMING;
+	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
+	/* and 'badblocks' parameters to work */
+	chip->options   |= NAND_SKIP_BBTSCAN;
+
+	switch (bbt) {
+	case 2:
+		 chip->bbt_options |= NAND_BBT_NO_OOB;
+	case 1:
+		 chip->bbt_options |= NAND_BBT_USE_FLASH;
+	case 0:
+		break;
+	default:
+		NS_ERR("bbt has to be 0..2\n");
+		retval = -EINVAL;
+		goto error;
+	}
+	/*
+	 * Perform minimum nandsim structure initialization to handle
+	 * the initial ID read command correctly
+	 */
+	if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
+		nand->geom.idbytes = 8;
+	else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
+		nand->geom.idbytes = 6;
+	else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
+		nand->geom.idbytes = 4;
+	else
+		nand->geom.idbytes = 2;
+	nand->regs.status = NS_STATUS_OK(nand);
+	nand->nxstate = STATE_UNKNOWN;
+	nand->options |= OPT_PAGE512; /* temporary value */
+	memcpy(nand->ids, id_bytes, sizeof(nand->ids));
+	if (bus_width == 16) {
+		nand->busw = 16;
+		chip->options |= NAND_BUSWIDTH_16;
+	}
+
+	nsmtd->owner = THIS_MODULE;
+
+	if ((retval = parse_weakblocks()) != 0)
+		goto error;
+
+	if ((retval = parse_weakpages()) != 0)
+		goto error;
+
+	if ((retval = parse_gravepages()) != 0)
+		goto error;
+
+	retval = nand_scan_ident(nsmtd, 1, NULL);
+	if (retval) {
+		NS_ERR("cannot scan NAND Simulator device\n");
+		goto error;
+	}
+
+	if (bch) {
+		unsigned int eccsteps, eccbytes;
+		if (!mtd_nand_has_bch()) {
+			NS_ERR("BCH ECC support is disabled\n");
+			retval = -EINVAL;
+			goto error;
+		}
+		/* use 512-byte ecc blocks */
+		eccsteps = nsmtd->writesize/512;
+		eccbytes = (bch*13+7)/8;
+		/* do not bother supporting small page devices */
+		if ((nsmtd->oobsize < 64) || !eccsteps) {
+			NS_ERR("bch not available on small page devices\n");
+			retval = -EINVAL;
+			goto error;
+		}
+		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
+			NS_ERR("invalid bch value %u\n", bch);
+			retval = -EINVAL;
+			goto error;
+		}
+		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_BCH;
+		chip->ecc.size = 512;
+		chip->ecc.strength = bch;
+		chip->ecc.bytes = eccbytes;
+		NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
+	}
+
+	retval = nand_scan_tail(nsmtd);
+	if (retval) {
+		NS_ERR("can't register NAND Simulator\n");
+		goto error;
+	}
+
+	if (overridesize) {
+		uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
+		if (new_size >> overridesize != nsmtd->erasesize) {
+			NS_ERR("overridesize is too big\n");
+			retval = -EINVAL;
+			goto err_exit;
+		}
+		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
+		nsmtd->size = new_size;
+		chip->chipsize = new_size;
+		chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
+		chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+	}
+
+	if ((retval = setup_wear_reporting(nsmtd)) != 0)
+		goto err_exit;
+
+	if ((retval = init_nandsim(nsmtd)) != 0)
+		goto err_exit;
+
+	if ((retval = chip->scan_bbt(nsmtd)) != 0)
+		goto err_exit;
+
+	if ((retval = parse_badblocks(nand, nsmtd)) != 0)
+		goto err_exit;
+
+	/* Register NAND partitions */
+	retval = mtd_device_register(nsmtd, &nand->partitions[0],
+				     nand->nbparts);
+	if (retval != 0)
+		goto err_exit;
+
+	if ((retval = nandsim_debugfs_create(nand)) != 0)
+		goto err_exit;
+
+        return 0;
+
+err_exit:
+	free_nandsim(nand);
+	nand_release(nsmtd);
+	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+		kfree(nand->partitions[i].name);
+error:
+	kfree(chip);
+	free_lists();
+
+	return retval;
+}
+
+module_init(ns_init_module);
+
+/*
+ * Module clean-up function
+ */
+static void __exit ns_cleanup_module(void)
+{
+	struct nand_chip *chip = mtd_to_nand(nsmtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+	int i;
+
+	free_nandsim(ns);    /* Free nandsim private resources */
+	nand_release(nsmtd); /* Unregister driver */
+	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+		kfree(ns->partitions[i].name);
+	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
+	free_lists();
+}
+
+module_exit(ns_cleanup_module);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Artem B. Bityuckiy");
+MODULE_DESCRIPTION ("The NAND flash simulator");
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
new file mode 100644
index 000000000000..d8a806894937
--- /dev/null
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -0,0 +1,286 @@
+/*
+ *  Overview:
+ *   Platform independent driver for NDFC (NanD Flash Controller)
+ *   integrated into EP440 cores
+ *
+ *   Ported to an OF platform driver by Sean MacLennan
+ *
+ *   The NDFC supports multiple chips, but this driver only supports a
+ *   single chip since I do not have access to any boards with
+ *   multiple chips.
+ *
+ *  Author: Thomas Gleixner
+ *
+ *  Copyright 2006 IBM
+ *  Copyright 2008 PIKA Technologies
+ *    Sean MacLennan <smaclennan@pikatech.com>
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ */
+#include <linux/module.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/ndfc.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+
+#define NDFC_MAX_CS    4
+
+struct ndfc_controller {
+	struct platform_device *ofdev;
+	void __iomem *ndfcbase;
+	struct nand_chip chip;
+	int chip_select;
+	struct nand_hw_control ndfc_control;
+};
+
+static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
+
+static void ndfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	uint32_t ccr;
+	struct nand_chip *nchip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
+
+	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
+	if (chip >= 0) {
+		ccr &= ~NDFC_CCR_BS_MASK;
+		ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
+	} else
+		ccr |= NDFC_CCR_RESET_CE;
+	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+}
+
+static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
+	else
+		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
+}
+
+static int ndfc_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+
+	return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+}
+
+static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	uint32_t ccr;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+
+	ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
+	ccr |= NDFC_CCR_RESET_ECC;
+	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+	wmb();
+}
+
+static int ndfc_calculate_ecc(struct mtd_info *mtd,
+			      const u_char *dat, u_char *ecc_code)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+	uint32_t ecc;
+	uint8_t *p = (uint8_t *)&ecc;
+
+	wmb();
+	ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+	/* The NDFC uses Smart Media (SMC) bytes order */
+	ecc_code[0] = p[1];
+	ecc_code[1] = p[2];
+	ecc_code[2] = p[3];
+
+	return 0;
+}
+
+/*
+ * Speedups for buffer read/write/verify
+ *
+ * NDFC allows 32bit read/write of data. So we can speed up the buffer
+ * functions. No further checking, as nand_base will always read/write
+ * page aligned.
+ */
+static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+	uint32_t *p = (uint32_t *) buf;
+
+	for(;len > 0; len -= 4)
+		*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
+}
+
+static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct ndfc_controller *ndfc = nand_get_controller_data(chip);
+	uint32_t *p = (uint32_t *) buf;
+
+	for(;len > 0; len -= 4)
+		out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
+}
+
+/*
+ * Initialize chip structure
+ */
+static int ndfc_chip_init(struct ndfc_controller *ndfc,
+			  struct device_node *node)
+{
+	struct device_node *flash_np;
+	struct nand_chip *chip = &ndfc->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
+	chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
+	chip->cmd_ctrl = ndfc_hwcontrol;
+	chip->dev_ready = ndfc_ready;
+	chip->select_chip = ndfc_select_chip;
+	chip->chip_delay = 50;
+	chip->controller = &ndfc->ndfc_control;
+	chip->read_buf = ndfc_read_buf;
+	chip->write_buf = ndfc_write_buf;
+	chip->ecc.correct = nand_correct_data;
+	chip->ecc.hwctl = ndfc_enable_hwecc;
+	chip->ecc.calculate = ndfc_calculate_ecc;
+	chip->ecc.mode = NAND_ECC_HW;
+	chip->ecc.size = 256;
+	chip->ecc.bytes = 3;
+	chip->ecc.strength = 1;
+	nand_set_controller_data(chip, ndfc);
+
+	mtd->dev.parent = &ndfc->ofdev->dev;
+
+	flash_np = of_get_next_child(node, NULL);
+	if (!flash_np)
+		return -ENODEV;
+	nand_set_flash_node(chip, flash_np);
+
+	mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
+			      flash_np->name);
+	if (!mtd->name) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = nand_scan(mtd, 1);
+	if (ret)
+		goto err;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+
+err:
+	of_node_put(flash_np);
+	if (ret)
+		kfree(mtd->name);
+	return ret;
+}
+
+static int ndfc_probe(struct platform_device *ofdev)
+{
+	struct ndfc_controller *ndfc;
+	const __be32 *reg;
+	u32 ccr;
+	u32 cs;
+	int err, len;
+
+	/* Read the reg property to get the chip select */
+	reg = of_get_property(ofdev->dev.of_node, "reg", &len);
+	if (reg == NULL || len != 12) {
+		dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+		return -ENOENT;
+	}
+
+	cs = be32_to_cpu(reg[0]);
+	if (cs >= NDFC_MAX_CS) {
+		dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs);
+		return -EINVAL;
+	}
+
+	ndfc = &ndfc_ctrl[cs];
+	ndfc->chip_select = cs;
+
+	nand_hw_control_init(&ndfc->ndfc_control);
+	ndfc->ofdev = ofdev;
+	dev_set_drvdata(&ofdev->dev, ndfc);
+
+	ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0);
+	if (!ndfc->ndfcbase) {
+		dev_err(&ofdev->dev, "failed to get memory\n");
+		return -EIO;
+	}
+
+	ccr = NDFC_CCR_BS(ndfc->chip_select);
+
+	/* It is ok if ccr does not exist - just default to 0 */
+	reg = of_get_property(ofdev->dev.of_node, "ccr", NULL);
+	if (reg)
+		ccr |= be32_to_cpup(reg);
+
+	out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
+
+	/* Set the bank settings if given */
+	reg = of_get_property(ofdev->dev.of_node, "bank-settings", NULL);
+	if (reg) {
+		int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
+		out_be32(ndfc->ndfcbase + offset, be32_to_cpup(reg));
+	}
+
+	err = ndfc_chip_init(ndfc, ofdev->dev.of_node);
+	if (err) {
+		iounmap(ndfc->ndfcbase);
+		return err;
+	}
+
+	return 0;
+}
+
+static int ndfc_remove(struct platform_device *ofdev)
+{
+	struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
+	struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
+
+	nand_release(mtd);
+	kfree(mtd->name);
+
+	return 0;
+}
+
+static const struct of_device_id ndfc_match[] = {
+	{ .compatible = "ibm,ndfc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ndfc_match);
+
+static struct platform_driver ndfc_driver = {
+	.driver = {
+		.name = "ndfc",
+		.of_match_table = ndfc_match,
+	},
+	.probe = ndfc_probe,
+	.remove = ndfc_remove,
+};
+
+module_platform_driver(ndfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("OF Platform driver for NDFC");
diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c
new file mode 100644
index 000000000000..af5b32c9a791
--- /dev/null
+++ b/drivers/mtd/nand/raw/nuc900_nand.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright © 2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+
+#define REG_FMICSR   	0x00
+#define REG_SMCSR    	0xa0
+#define REG_SMISR    	0xac
+#define REG_SMCMD    	0xb0
+#define REG_SMADDR   	0xb4
+#define REG_SMDATA   	0xb8
+
+#define RESET_FMI	0x01
+#define NAND_EN		0x08
+#define READYBUSY	(0x01 << 18)
+
+#define SWRST		0x01
+#define PSIZE		(0x01 << 3)
+#define DMARWEN		(0x03 << 1)
+#define BUSWID		(0x01 << 4)
+#define ECC4EN		(0x01 << 5)
+#define WP		(0x01 << 24)
+#define NANDCS		(0x01 << 25)
+#define ENDADDR		(0x01 << 31)
+
+#define read_data_reg(dev)		\
+	__raw_readl((dev)->reg + REG_SMDATA)
+
+#define write_data_reg(dev, val)	\
+	__raw_writel((val), (dev)->reg + REG_SMDATA)
+
+#define write_cmd_reg(dev, val)		\
+	__raw_writel((val), (dev)->reg + REG_SMCMD)
+
+#define write_addr_reg(dev, val)	\
+	__raw_writel((val), (dev)->reg + REG_SMADDR)
+
+struct nuc900_nand {
+	struct nand_chip chip;
+	void __iomem *reg;
+	struct clk *clk;
+	spinlock_t lock;
+};
+
+static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
+}
+
+static const struct mtd_partition partitions[] = {
+	{
+	 .name = "NAND FS 0",
+	 .offset = 0,
+	 .size = 8 * 1024 * 1024
+	},
+	{
+	 .name = "NAND FS 1",
+	 .offset = MTDPART_OFS_APPEND,
+	 .size = MTDPART_SIZ_FULL
+	}
+};
+
+static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
+{
+	unsigned char ret;
+	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+
+	ret = (unsigned char)read_data_reg(nand);
+
+	return ret;
+}
+
+static void nuc900_nand_read_buf(struct mtd_info *mtd,
+				 unsigned char *buf, int len)
+{
+	int i;
+	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+
+	for (i = 0; i < len; i++)
+		buf[i] = (unsigned char)read_data_reg(nand);
+}
+
+static void nuc900_nand_write_buf(struct mtd_info *mtd,
+				  const unsigned char *buf, int len)
+{
+	int i;
+	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+
+	for (i = 0; i < len; i++)
+		write_data_reg(nand, buf[i]);
+}
+
+static int nuc900_check_rb(struct nuc900_nand *nand)
+{
+	unsigned int val;
+	spin_lock(&nand->lock);
+	val = __raw_readl(nand->reg + REG_SMISR);
+	val &= READYBUSY;
+	spin_unlock(&nand->lock);
+
+	return val;
+}
+
+static int nuc900_nand_devready(struct mtd_info *mtd)
+{
+	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+	int ready;
+
+	ready = (nuc900_check_rb(nand)) ? 1 : 0;
+	return ready;
+}
+
+static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
+				   int column, int page_addr)
+{
+	register struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+
+	if (command == NAND_CMD_READOOB) {
+		column += mtd->writesize;
+		command = NAND_CMD_READ0;
+	}
+
+	write_cmd_reg(nand, command & 0xff);
+
+	if (column != -1 || page_addr != -1) {
+
+		if (column != -1) {
+			if (chip->options & NAND_BUSWIDTH_16 &&
+					!nand_opcode_8bits(command))
+				column >>= 1;
+			write_addr_reg(nand, column);
+			write_addr_reg(nand, column >> 8 | ENDADDR);
+		}
+		if (page_addr != -1) {
+			write_addr_reg(nand, page_addr);
+
+			if (chip->options & NAND_ROW_ADDR_3) {
+				write_addr_reg(nand, page_addr >> 8);
+				write_addr_reg(nand, page_addr >> 16 | ENDADDR);
+			} else {
+				write_addr_reg(nand, page_addr >> 8 | ENDADDR);
+			}
+		}
+	}
+
+	switch (command) {
+	case NAND_CMD_CACHEDPROG:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_RNDIN:
+	case NAND_CMD_STATUS:
+		return;
+
+	case NAND_CMD_RESET:
+		if (chip->dev_ready)
+			break;
+		udelay(chip->chip_delay);
+
+		write_cmd_reg(nand, NAND_CMD_STATUS);
+		write_cmd_reg(nand, command);
+
+		while (!nuc900_check_rb(nand))
+			;
+
+		return;
+
+	case NAND_CMD_RNDOUT:
+		write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
+		return;
+
+	case NAND_CMD_READ0:
+
+		write_cmd_reg(nand, NAND_CMD_READSTART);
+	default:
+
+		if (!chip->dev_ready) {
+			udelay(chip->chip_delay);
+			return;
+		}
+	}
+
+	/* Apply this short delay always to ensure that we do wait tWB in
+	 * any case on any machine. */
+	ndelay(100);
+
+	while (!chip->dev_ready(mtd))
+		;
+}
+
+
+static void nuc900_nand_enable(struct nuc900_nand *nand)
+{
+	unsigned int val;
+	spin_lock(&nand->lock);
+	__raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
+
+	val = __raw_readl(nand->reg + REG_FMICSR);
+
+	if (!(val & NAND_EN))
+		__raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
+
+	val = __raw_readl(nand->reg + REG_SMCSR);
+
+	val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
+	val |= WP;
+
+	__raw_writel(val, nand->reg + REG_SMCSR);
+
+	spin_unlock(&nand->lock);
+}
+
+static int nuc900_nand_probe(struct platform_device *pdev)
+{
+	struct nuc900_nand *nuc900_nand;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	struct resource *res;
+
+	nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
+				   GFP_KERNEL);
+	if (!nuc900_nand)
+		return -ENOMEM;
+	chip = &(nuc900_nand->chip);
+	mtd = nand_to_mtd(chip);
+
+	mtd->dev.parent		= &pdev->dev;
+	spin_lock_init(&nuc900_nand->lock);
+
+	nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(nuc900_nand->clk))
+		return -ENOENT;
+	clk_enable(nuc900_nand->clk);
+
+	chip->cmdfunc		= nuc900_nand_command_lp;
+	chip->dev_ready		= nuc900_nand_devready;
+	chip->read_byte		= nuc900_nand_read_byte;
+	chip->write_buf		= nuc900_nand_write_buf;
+	chip->read_buf		= nuc900_nand_read_buf;
+	chip->chip_delay	= 50;
+	chip->options		= 0;
+	chip->ecc.mode		= NAND_ECC_SOFT;
+	chip->ecc.algo		= NAND_ECC_HAMMING;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nuc900_nand->reg))
+		return PTR_ERR(nuc900_nand->reg);
+
+	nuc900_nand_enable(nuc900_nand);
+
+	if (nand_scan(mtd, 1))
+		return -ENXIO;
+
+	mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
+
+	platform_set_drvdata(pdev, nuc900_nand);
+
+	return 0;
+}
+
+static int nuc900_nand_remove(struct platform_device *pdev)
+{
+	struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&nuc900_nand->chip));
+	clk_disable(nuc900_nand->clk);
+
+	return 0;
+}
+
+static struct platform_driver nuc900_nand_driver = {
+	.probe		= nuc900_nand_probe,
+	.remove		= nuc900_nand_remove,
+	.driver		= {
+		.name	= "nuc900-fmi",
+	},
+};
+
+module_platform_driver(nuc900_nand_driver);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-fmi");
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
new file mode 100644
index 000000000000..8cdf7d3d8fa7
--- /dev/null
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -0,0 +1,2316 @@
+/*
+ * Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+ * Copyright © 2004 Micron Technology Inc.
+ * Copyright © 2004 David Brownell
+ *
+ * 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/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/omap-dma.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/mtd/nand_bch.h>
+#include <linux/platform_data/elm.h>
+
+#include <linux/omap-gpmc.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
+
+#define	DRIVER_NAME	"omap2-nand"
+#define	OMAP_NAND_TIMEOUT_MS	5000
+
+#define NAND_Ecc_P1e		(1 << 0)
+#define NAND_Ecc_P2e		(1 << 1)
+#define NAND_Ecc_P4e		(1 << 2)
+#define NAND_Ecc_P8e		(1 << 3)
+#define NAND_Ecc_P16e		(1 << 4)
+#define NAND_Ecc_P32e		(1 << 5)
+#define NAND_Ecc_P64e		(1 << 6)
+#define NAND_Ecc_P128e		(1 << 7)
+#define NAND_Ecc_P256e		(1 << 8)
+#define NAND_Ecc_P512e		(1 << 9)
+#define NAND_Ecc_P1024e		(1 << 10)
+#define NAND_Ecc_P2048e		(1 << 11)
+
+#define NAND_Ecc_P1o		(1 << 16)
+#define NAND_Ecc_P2o		(1 << 17)
+#define NAND_Ecc_P4o		(1 << 18)
+#define NAND_Ecc_P8o		(1 << 19)
+#define NAND_Ecc_P16o		(1 << 20)
+#define NAND_Ecc_P32o		(1 << 21)
+#define NAND_Ecc_P64o		(1 << 22)
+#define NAND_Ecc_P128o		(1 << 23)
+#define NAND_Ecc_P256o		(1 << 24)
+#define NAND_Ecc_P512o		(1 << 25)
+#define NAND_Ecc_P1024o		(1 << 26)
+#define NAND_Ecc_P2048o		(1 << 27)
+
+#define TF(value)	(value ? 1 : 0)
+
+#define P2048e(a)	(TF(a & NAND_Ecc_P2048e)	<< 0)
+#define P2048o(a)	(TF(a & NAND_Ecc_P2048o)	<< 1)
+#define P1e(a)		(TF(a & NAND_Ecc_P1e)		<< 2)
+#define P1o(a)		(TF(a & NAND_Ecc_P1o)		<< 3)
+#define P2e(a)		(TF(a & NAND_Ecc_P2e)		<< 4)
+#define P2o(a)		(TF(a & NAND_Ecc_P2o)		<< 5)
+#define P4e(a)		(TF(a & NAND_Ecc_P4e)		<< 6)
+#define P4o(a)		(TF(a & NAND_Ecc_P4o)		<< 7)
+
+#define P8e(a)		(TF(a & NAND_Ecc_P8e)		<< 0)
+#define P8o(a)		(TF(a & NAND_Ecc_P8o)		<< 1)
+#define P16e(a)		(TF(a & NAND_Ecc_P16e)		<< 2)
+#define P16o(a)		(TF(a & NAND_Ecc_P16o)		<< 3)
+#define P32e(a)		(TF(a & NAND_Ecc_P32e)		<< 4)
+#define P32o(a)		(TF(a & NAND_Ecc_P32o)		<< 5)
+#define P64e(a)		(TF(a & NAND_Ecc_P64e)		<< 6)
+#define P64o(a)		(TF(a & NAND_Ecc_P64o)		<< 7)
+
+#define P128e(a)	(TF(a & NAND_Ecc_P128e)		<< 0)
+#define P128o(a)	(TF(a & NAND_Ecc_P128o)		<< 1)
+#define P256e(a)	(TF(a & NAND_Ecc_P256e)		<< 2)
+#define P256o(a)	(TF(a & NAND_Ecc_P256o)		<< 3)
+#define P512e(a)	(TF(a & NAND_Ecc_P512e)		<< 4)
+#define P512o(a)	(TF(a & NAND_Ecc_P512o)		<< 5)
+#define P1024e(a)	(TF(a & NAND_Ecc_P1024e)	<< 6)
+#define P1024o(a)	(TF(a & NAND_Ecc_P1024o)	<< 7)
+
+#define P8e_s(a)	(TF(a & NAND_Ecc_P8e)		<< 0)
+#define P8o_s(a)	(TF(a & NAND_Ecc_P8o)		<< 1)
+#define P16e_s(a)	(TF(a & NAND_Ecc_P16e)		<< 2)
+#define P16o_s(a)	(TF(a & NAND_Ecc_P16o)		<< 3)
+#define P1e_s(a)	(TF(a & NAND_Ecc_P1e)		<< 4)
+#define P1o_s(a)	(TF(a & NAND_Ecc_P1o)		<< 5)
+#define P2e_s(a)	(TF(a & NAND_Ecc_P2e)		<< 6)
+#define P2o_s(a)	(TF(a & NAND_Ecc_P2o)		<< 7)
+
+#define P4e_s(a)	(TF(a & NAND_Ecc_P4e)		<< 0)
+#define P4o_s(a)	(TF(a & NAND_Ecc_P4o)		<< 1)
+
+#define	PREFETCH_CONFIG1_CS_SHIFT	24
+#define	ECC_CONFIG_CS_SHIFT		1
+#define	CS_MASK				0x7
+#define	ENABLE_PREFETCH			(0x1 << 7)
+#define	DMA_MPU_MODE_SHIFT		2
+#define	ECCSIZE0_SHIFT			12
+#define	ECCSIZE1_SHIFT			22
+#define	ECC1RESULTSIZE			0x1
+#define	ECCCLEAR			0x100
+#define	ECC1				0x1
+#define	PREFETCH_FIFOTHRESHOLD_MAX	0x40
+#define	PREFETCH_FIFOTHRESHOLD(val)	((val) << 8)
+#define	PREFETCH_STATUS_COUNT(val)	(val & 0x00003fff)
+#define	PREFETCH_STATUS_FIFO_CNT(val)	((val >> 24) & 0x7F)
+#define	STATUS_BUFF_EMPTY		0x00000001
+
+#define SECTOR_BYTES		512
+/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
+#define BCH4_BIT_PAD		4
+
+/* GPMC ecc engine settings for read */
+#define BCH_WRAPMODE_1		1	/* BCH wrap mode 1 */
+#define BCH8R_ECC_SIZE0		0x1a	/* ecc_size0 = 26 */
+#define BCH8R_ECC_SIZE1		0x2	/* ecc_size1 = 2 */
+#define BCH4R_ECC_SIZE0		0xd	/* ecc_size0 = 13 */
+#define BCH4R_ECC_SIZE1		0x3	/* ecc_size1 = 3 */
+
+/* GPMC ecc engine settings for write */
+#define BCH_WRAPMODE_6		6	/* BCH wrap mode 6 */
+#define BCH_ECC_SIZE0		0x0	/* ecc_size0 = 0, no oob protection */
+#define BCH_ECC_SIZE1		0x20	/* ecc_size1 = 32 */
+
+#define BADBLOCK_MARKER_LENGTH		2
+
+static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
+				0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
+				0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93,
+				0x07, 0x0e};
+static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
+	0xac, 0x6b, 0xff, 0x99, 0x7b};
+static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
+
+/* Shared among all NAND instances to synchronize access to the ECC Engine */
+static struct nand_hw_control omap_gpmc_controller = {
+	.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
+	.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
+};
+
+struct omap_nand_info {
+	struct nand_chip		nand;
+	struct platform_device		*pdev;
+
+	int				gpmc_cs;
+	bool				dev_ready;
+	enum nand_io			xfer_type;
+	int				devsize;
+	enum omap_ecc			ecc_opt;
+	struct device_node		*elm_of_node;
+
+	unsigned long			phys_base;
+	struct completion		comp;
+	struct dma_chan			*dma;
+	int				gpmc_irq_fifo;
+	int				gpmc_irq_count;
+	enum {
+		OMAP_NAND_IO_READ = 0,	/* read */
+		OMAP_NAND_IO_WRITE,	/* write */
+	} iomode;
+	u_char				*buf;
+	int					buf_len;
+	/* Interface to GPMC */
+	struct gpmc_nand_regs		reg;
+	struct gpmc_nand_ops		*ops;
+	bool				flash_bbt;
+	/* fields specific for BCHx_HW ECC scheme */
+	struct device			*elm_dev;
+	/* NAND ready gpio */
+	struct gpio_desc		*ready_gpiod;
+};
+
+static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct omap_nand_info, nand);
+}
+
+/**
+ * omap_prefetch_enable - configures and starts prefetch transfer
+ * @cs: cs (chip select) number
+ * @fifo_th: fifo threshold to be used for read/ write
+ * @dma_mode: dma mode enable (1) or disable (0)
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
+	unsigned int u32_count, int is_write, struct omap_nand_info *info)
+{
+	u32 val;
+
+	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
+		return -1;
+
+	if (readl(info->reg.gpmc_prefetch_control))
+		return -EBUSY;
+
+	/* Set the amount of bytes to be prefetched */
+	writel(u32_count, info->reg.gpmc_prefetch_config2);
+
+	/* Set dma/mpu mode, the prefetch read / post write and
+	 * enable the engine. Set which cs is has requested for.
+	 */
+	val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
+		PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
+		(dma_mode << DMA_MPU_MODE_SHIFT) | (is_write & 0x1));
+	writel(val, info->reg.gpmc_prefetch_config1);
+
+	/*  Start the prefetch engine */
+	writel(0x1, info->reg.gpmc_prefetch_control);
+
+	return 0;
+}
+
+/**
+ * omap_prefetch_reset - disables and stops the prefetch engine
+ */
+static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
+{
+	u32 config1;
+
+	/* check if the same module/cs is trying to reset */
+	config1 = readl(info->reg.gpmc_prefetch_config1);
+	if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
+		return -EINVAL;
+
+	/* Stop the PFPW engine */
+	writel(0x0, info->reg.gpmc_prefetch_control);
+
+	/* Reset/disable the PFPW engine */
+	writel(0x0, info->reg.gpmc_prefetch_config1);
+
+	return 0;
+}
+
+/**
+ * omap_hwcontrol - hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+
+	if (cmd != NAND_CMD_NONE) {
+		if (ctrl & NAND_CLE)
+			writeb(cmd, info->reg.gpmc_nand_command);
+
+		else if (ctrl & NAND_ALE)
+			writeb(cmd, info->reg.gpmc_nand_address);
+
+		else /* NAND_NCE */
+			writeb(cmd, info->reg.gpmc_nand_data);
+	}
+}
+
+/**
+ * omap_read_buf8 - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+
+	ioread8_rep(nand->IO_ADDR_R, buf, len);
+}
+
+/**
+ * omap_write_buf8 - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	u_char *p = (u_char *)buf;
+	bool status;
+
+	while (len--) {
+		iowrite8(*p++, info->nand.IO_ADDR_W);
+		/* wait until buffer is available for write */
+		do {
+			status = info->ops->nand_writebuffer_empty();
+		} while (!status);
+	}
+}
+
+/**
+ * omap_read_buf16 - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+
+	ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
+}
+
+/**
+ * omap_write_buf16 - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	u16 *p = (u16 *) buf;
+	bool status;
+	/* FIXME try bursts of writesw() or DMA ... */
+	len >>= 1;
+
+	while (len--) {
+		iowrite16(*p++, info->nand.IO_ADDR_W);
+		/* wait until buffer is available for write */
+		do {
+			status = info->ops->nand_writebuffer_empty();
+		} while (!status);
+	}
+}
+
+/**
+ * omap_read_buf_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	uint32_t r_count = 0;
+	int ret = 0;
+	u32 *p = (u32 *)buf;
+
+	/* take care of subpage reads */
+	if (len % 4) {
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_read_buf16(mtd, buf, len % 4);
+		else
+			omap_read_buf8(mtd, buf, len % 4);
+		p = (u32 *) (buf + len % 4);
+		len -= len % 4;
+	}
+
+	/* configure and start prefetch transfer */
+	ret = omap_prefetch_enable(info->gpmc_cs,
+			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
+	if (ret) {
+		/* PFPW engine is busy, use cpu copy method */
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_read_buf16(mtd, (u_char *)p, len);
+		else
+			omap_read_buf8(mtd, (u_char *)p, len);
+	} else {
+		do {
+			r_count = readl(info->reg.gpmc_prefetch_status);
+			r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
+			r_count = r_count >> 2;
+			ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
+			p += r_count;
+			len -= r_count << 2;
+		} while (len);
+		/* disable and stop the PFPW engine */
+		omap_prefetch_reset(info->gpmc_cs, info);
+	}
+}
+
+/**
+ * omap_write_buf_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	uint32_t w_count = 0;
+	int i = 0, ret = 0;
+	u16 *p = (u16 *)buf;
+	unsigned long tim, limit;
+	u32 val;
+
+	/* take care of subpage writes */
+	if (len % 2 != 0) {
+		writeb(*buf, info->nand.IO_ADDR_W);
+		p = (u16 *)(buf + 1);
+		len--;
+	}
+
+	/*  configure and start prefetch transfer */
+	ret = omap_prefetch_enable(info->gpmc_cs,
+			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
+	if (ret) {
+		/* PFPW engine is busy, use cpu copy method */
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_write_buf16(mtd, (u_char *)p, len);
+		else
+			omap_write_buf8(mtd, (u_char *)p, len);
+	} else {
+		while (len) {
+			w_count = readl(info->reg.gpmc_prefetch_status);
+			w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
+			w_count = w_count >> 1;
+			for (i = 0; (i < w_count) && len; i++, len -= 2)
+				iowrite16(*p++, info->nand.IO_ADDR_W);
+		}
+		/* wait for data to flushed-out before reset the prefetch */
+		tim = 0;
+		limit = (loops_per_jiffy *
+					msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+		do {
+			cpu_relax();
+			val = readl(info->reg.gpmc_prefetch_status);
+			val = PREFETCH_STATUS_COUNT(val);
+		} while (val && (tim++ < limit));
+
+		/* disable and stop the PFPW engine */
+		omap_prefetch_reset(info->gpmc_cs, info);
+	}
+}
+
+/*
+ * omap_nand_dma_callback: callback on the completion of dma transfer
+ * @data: pointer to completion data structure
+ */
+static void omap_nand_dma_callback(void *data)
+{
+	complete((struct completion *) data);
+}
+
+/*
+ * omap_nand_dma_transfer: configure and start dma transfer
+ * @mtd: MTD device structure
+ * @addr: virtual address in RAM of source/destination
+ * @len: number of data bytes to be transferred
+ * @is_write: flag for read/write operation
+ */
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+					unsigned int len, int is_write)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct dma_async_tx_descriptor *tx;
+	enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
+							DMA_FROM_DEVICE;
+	struct scatterlist sg;
+	unsigned long tim, limit;
+	unsigned n;
+	int ret;
+	u32 val;
+
+	if (!virt_addr_valid(addr))
+		goto out_copy;
+
+	sg_init_one(&sg, addr, len);
+	n = dma_map_sg(info->dma->device->dev, &sg, 1, dir);
+	if (n == 0) {
+		dev_err(&info->pdev->dev,
+			"Couldn't DMA map a %d byte buffer\n", len);
+		goto out_copy;
+	}
+
+	tx = dmaengine_prep_slave_sg(info->dma, &sg, n,
+		is_write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
+		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!tx)
+		goto out_copy_unmap;
+
+	tx->callback = omap_nand_dma_callback;
+	tx->callback_param = &info->comp;
+	dmaengine_submit(tx);
+
+	init_completion(&info->comp);
+
+	/* setup and start DMA using dma_addr */
+	dma_async_issue_pending(info->dma);
+
+	/*  configure and start prefetch transfer */
+	ret = omap_prefetch_enable(info->gpmc_cs,
+		PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
+	if (ret)
+		/* PFPW engine is busy, use cpu copy method */
+		goto out_copy_unmap;
+
+	wait_for_completion(&info->comp);
+	tim = 0;
+	limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+
+	do {
+		cpu_relax();
+		val = readl(info->reg.gpmc_prefetch_status);
+		val = PREFETCH_STATUS_COUNT(val);
+	} while (val && (tim++ < limit));
+
+	/* disable and stop the PFPW engine */
+	omap_prefetch_reset(info->gpmc_cs, info);
+
+	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
+	return 0;
+
+out_copy_unmap:
+	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
+out_copy:
+	if (info->nand.options & NAND_BUSWIDTH_16)
+		is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
+			: omap_write_buf16(mtd, (u_char *) addr, len);
+	else
+		is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
+			: omap_write_buf8(mtd, (u_char *) addr, len);
+	return 0;
+}
+
+/**
+ * omap_read_buf_dma_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	if (len <= mtd->oobsize)
+		omap_read_buf_pref(mtd, buf, len);
+	else
+		/* start transfer in DMA mode */
+		omap_nand_dma_transfer(mtd, buf, len, 0x0);
+}
+
+/**
+ * omap_write_buf_dma_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_dma_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	if (len <= mtd->oobsize)
+		omap_write_buf_pref(mtd, buf, len);
+	else
+		/* start transfer in DMA mode */
+		omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
+}
+
+/*
+ * omap_nand_irq - GPMC irq handler
+ * @this_irq: gpmc irq number
+ * @dev: omap_nand_info structure pointer is passed here
+ */
+static irqreturn_t omap_nand_irq(int this_irq, void *dev)
+{
+	struct omap_nand_info *info = (struct omap_nand_info *) dev;
+	u32 bytes;
+
+	bytes = readl(info->reg.gpmc_prefetch_status);
+	bytes = PREFETCH_STATUS_FIFO_CNT(bytes);
+	bytes = bytes  & 0xFFFC; /* io in multiple of 4 bytes */
+	if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
+		if (this_irq == info->gpmc_irq_count)
+			goto done;
+
+		if (info->buf_len && (info->buf_len < bytes))
+			bytes = info->buf_len;
+		else if (!info->buf_len)
+			bytes = 0;
+		iowrite32_rep(info->nand.IO_ADDR_W,
+						(u32 *)info->buf, bytes >> 2);
+		info->buf = info->buf + bytes;
+		info->buf_len -= bytes;
+
+	} else {
+		ioread32_rep(info->nand.IO_ADDR_R,
+						(u32 *)info->buf, bytes >> 2);
+		info->buf = info->buf + bytes;
+
+		if (this_irq == info->gpmc_irq_count)
+			goto done;
+	}
+
+	return IRQ_HANDLED;
+
+done:
+	complete(&info->comp);
+
+	disable_irq_nosync(info->gpmc_irq_fifo);
+	disable_irq_nosync(info->gpmc_irq_count);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * omap_read_buf_irq_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	int ret = 0;
+
+	if (len <= mtd->oobsize) {
+		omap_read_buf_pref(mtd, buf, len);
+		return;
+	}
+
+	info->iomode = OMAP_NAND_IO_READ;
+	info->buf = buf;
+	init_completion(&info->comp);
+
+	/*  configure and start prefetch transfer */
+	ret = omap_prefetch_enable(info->gpmc_cs,
+			PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
+	if (ret)
+		/* PFPW engine is busy, use cpu copy method */
+		goto out_copy;
+
+	info->buf_len = len;
+
+	enable_irq(info->gpmc_irq_count);
+	enable_irq(info->gpmc_irq_fifo);
+
+	/* waiting for read to complete */
+	wait_for_completion(&info->comp);
+
+	/* disable and stop the PFPW engine */
+	omap_prefetch_reset(info->gpmc_cs, info);
+	return;
+
+out_copy:
+	if (info->nand.options & NAND_BUSWIDTH_16)
+		omap_read_buf16(mtd, buf, len);
+	else
+		omap_read_buf8(mtd, buf, len);
+}
+
+/*
+ * omap_write_buf_irq_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_irq_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	int ret = 0;
+	unsigned long tim, limit;
+	u32 val;
+
+	if (len <= mtd->oobsize) {
+		omap_write_buf_pref(mtd, buf, len);
+		return;
+	}
+
+	info->iomode = OMAP_NAND_IO_WRITE;
+	info->buf = (u_char *) buf;
+	init_completion(&info->comp);
+
+	/* configure and start prefetch transfer : size=24 */
+	ret = omap_prefetch_enable(info->gpmc_cs,
+		(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
+	if (ret)
+		/* PFPW engine is busy, use cpu copy method */
+		goto out_copy;
+
+	info->buf_len = len;
+
+	enable_irq(info->gpmc_irq_count);
+	enable_irq(info->gpmc_irq_fifo);
+
+	/* waiting for write to complete */
+	wait_for_completion(&info->comp);
+
+	/* wait for data to flushed-out before reset the prefetch */
+	tim = 0;
+	limit = (loops_per_jiffy *  msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+	do {
+		val = readl(info->reg.gpmc_prefetch_status);
+		val = PREFETCH_STATUS_COUNT(val);
+		cpu_relax();
+	} while (val && (tim++ < limit));
+
+	/* disable and stop the PFPW engine */
+	omap_prefetch_reset(info->gpmc_cs, info);
+	return;
+
+out_copy:
+	if (info->nand.options & NAND_BUSWIDTH_16)
+		omap_write_buf16(mtd, buf, len);
+	else
+		omap_write_buf8(mtd, buf, len);
+}
+
+/**
+ * gen_true_ecc - This function will generate true ECC value
+ * @ecc_buf: buffer to store ecc code
+ *
+ * This generated true ECC value can be used when correcting
+ * data read from NAND flash memory core
+ */
+static void gen_true_ecc(u8 *ecc_buf)
+{
+	u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) |
+		((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+
+	ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) |
+			P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
+	ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) |
+			P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+	ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) |
+			P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+/**
+ * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data
+ * @ecc_data1:  ecc code from nand spare area
+ * @ecc_data2:  ecc code from hardware register obtained from hardware ecc
+ * @page_data:  page data
+ *
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer.
+ * If there is no error, %0 is returned. If there is an error but it
+ * was corrected, %1 is returned. Otherwise, %-1 is returned.
+ */
+static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
+			    u8 *ecc_data2,	/* read from register */
+			    u8 *page_data)
+{
+	uint	i;
+	u8	tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+	u8	comp0_bit[8], comp1_bit[8], comp2_bit[8];
+	u8	ecc_bit[24];
+	u8	ecc_sum = 0;
+	u8	find_bit = 0;
+	uint	find_byte = 0;
+	int	isEccFF;
+
+	isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+	gen_true_ecc(ecc_data1);
+	gen_true_ecc(ecc_data2);
+
+	for (i = 0; i <= 2; i++) {
+		*(ecc_data1 + i) = ~(*(ecc_data1 + i));
+		*(ecc_data2 + i) = ~(*(ecc_data2 + i));
+	}
+
+	for (i = 0; i < 8; i++) {
+		tmp0_bit[i]     = *ecc_data1 % 2;
+		*ecc_data1	= *ecc_data1 / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		tmp1_bit[i]	 = *(ecc_data1 + 1) % 2;
+		*(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		tmp2_bit[i]	 = *(ecc_data1 + 2) % 2;
+		*(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		comp0_bit[i]     = *ecc_data2 % 2;
+		*ecc_data2       = *ecc_data2 / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+		*(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+		*(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+	}
+
+	for (i = 0; i < 6; i++)
+		ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+	for (i = 0; i < 8; i++)
+		ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+	for (i = 0; i < 8; i++)
+		ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+	ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+	ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+	for (i = 0; i < 24; i++)
+		ecc_sum += ecc_bit[i];
+
+	switch (ecc_sum) {
+	case 0:
+		/* Not reached because this function is not called if
+		 *  ECC values are equal
+		 */
+		return 0;
+
+	case 1:
+		/* Uncorrectable error */
+		pr_debug("ECC UNCORRECTED_ERROR 1\n");
+		return -EBADMSG;
+
+	case 11:
+		/* UN-Correctable error */
+		pr_debug("ECC UNCORRECTED_ERROR B\n");
+		return -EBADMSG;
+
+	case 12:
+		/* Correctable error */
+		find_byte = (ecc_bit[23] << 8) +
+			    (ecc_bit[21] << 7) +
+			    (ecc_bit[19] << 6) +
+			    (ecc_bit[17] << 5) +
+			    (ecc_bit[15] << 4) +
+			    (ecc_bit[13] << 3) +
+			    (ecc_bit[11] << 2) +
+			    (ecc_bit[9]  << 1) +
+			    ecc_bit[7];
+
+		find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+		pr_debug("Correcting single bit ECC error at offset: "
+				"%d, bit: %d\n", find_byte, find_bit);
+
+		page_data[find_byte] ^= (1 << find_bit);
+
+		return 1;
+	default:
+		if (isEccFF) {
+			if (ecc_data2[0] == 0 &&
+			    ecc_data2[1] == 0 &&
+			    ecc_data2[2] == 0)
+				return 0;
+		}
+		pr_debug("UNCORRECTED_ERROR default\n");
+		return -EBADMSG;
+	}
+}
+
+/**
+ * omap_correct_data - Compares the ECC read with HW generated ECC
+ * @mtd: MTD device structure
+ * @dat: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ *
+ * Compares the ecc read from nand spare area with ECC registers values
+ * and if ECC's mismatched, it will call 'omap_compare_ecc' for error
+ * detection and correction. If there are no errors, %0 is returned. If
+ * there were errors and all of the errors were corrected, the number of
+ * corrected errors is returned. If uncorrectable errors exist, %-1 is
+ * returned.
+ */
+static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
+				u_char *read_ecc, u_char *calc_ecc)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	int blockCnt = 0, i = 0, ret = 0;
+	int stat = 0;
+
+	/* Ex NAND_ECC_HW12_2048 */
+	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+			(info->nand.ecc.size  == 2048))
+		blockCnt = 4;
+	else
+		blockCnt = 1;
+
+	for (i = 0; i < blockCnt; i++) {
+		if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+			ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
+			if (ret < 0)
+				return ret;
+			/* keep track of the number of corrected errors */
+			stat += ret;
+		}
+		read_ecc += 3;
+		calc_ecc += 3;
+		dat      += 512;
+	}
+	return stat;
+}
+
+/**
+ * omap_calcuate_ecc - Generate non-inverted ECC bytes.
+ * @mtd: MTD device structure
+ * @dat: The pointer to data on which ecc is computed
+ * @ecc_code: The ecc_code buffer
+ *
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page. Reading
+ * an erased page will produce an ECC mismatch between generated and read
+ * ECC bytes that has to be dealt with separately.
+ */
+static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+				u_char *ecc_code)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	u32 val;
+
+	val = readl(info->reg.gpmc_ecc_config);
+	if (((val >> ECC_CONFIG_CS_SHIFT) & CS_MASK) != info->gpmc_cs)
+		return -EINVAL;
+
+	/* read ecc result */
+	val = readl(info->reg.gpmc_ecc1_result);
+	*ecc_code++ = val;          /* P128e, ..., P1e */
+	*ecc_code++ = val >> 16;    /* P128o, ..., P1o */
+	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+
+	return 0;
+}
+
+/**
+ * omap_enable_hwecc - This function enables the hardware ecc functionality
+ * @mtd: MTD device structure
+ * @mode: Read/Write mode
+ */
+static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+	u32 val;
+
+	/* clear ecc and enable bits */
+	val = ECCCLEAR | ECC1;
+	writel(val, info->reg.gpmc_ecc_control);
+
+	/* program ecc and result sizes */
+	val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
+			 ECC1RESULTSIZE);
+	writel(val, info->reg.gpmc_ecc_size_config);
+
+	switch (mode) {
+	case NAND_ECC_READ:
+	case NAND_ECC_WRITE:
+		writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
+		break;
+	case NAND_ECC_READSYN:
+		writel(ECCCLEAR, info->reg.gpmc_ecc_control);
+		break;
+	default:
+		dev_info(&info->pdev->dev,
+			"error: unrecognized Mode[%d]!\n", mode);
+		break;
+	}
+
+	/* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+	val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+	writel(val, info->reg.gpmc_ecc_config);
+}
+
+/**
+ * omap_wait - wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND Chip structure
+ *
+ * Wait function is called during Program and erase operations and
+ * the way it is called from MTD layer, we should wait till the NAND
+ * chip is ready after the programming/erase operation has completed.
+ *
+ * Erase can take up to 400ms and program up to 20ms according to
+ * general NAND and SmartMedia specs
+ */
+static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	unsigned long timeo = jiffies;
+	int status, state = this->state;
+
+	if (state == FL_ERASING)
+		timeo += msecs_to_jiffies(400);
+	else
+		timeo += msecs_to_jiffies(20);
+
+	writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
+	while (time_before(jiffies, timeo)) {
+		status = readb(info->reg.gpmc_nand_data);
+		if (status & NAND_STATUS_READY)
+			break;
+		cond_resched();
+	}
+
+	status = readb(info->reg.gpmc_nand_data);
+	return status;
+}
+
+/**
+ * omap_dev_ready - checks the NAND Ready GPIO line
+ * @mtd: MTD device structure
+ *
+ * Returns true if ready and false if busy.
+ */
+static int omap_dev_ready(struct mtd_info *mtd)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+
+	return gpiod_get_value(info->ready_gpiod);
+}
+
+/**
+ * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
+ * @mtd: MTD device structure
+ * @mode: Read/Write mode
+ *
+ * When using BCH with SW correction (i.e. no ELM), sector size is set
+ * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
+ * for both reading and writing with:
+ * eccsize0 = 0  (no additional protected byte in spare area)
+ * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
+ */
+static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
+{
+	unsigned int bch_type;
+	unsigned int dev_width, nsectors;
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	enum omap_ecc ecc_opt = info->ecc_opt;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	u32 val, wr_mode;
+	unsigned int ecc_size1, ecc_size0;
+
+	/* GPMC configurations for calculating ECC */
+	switch (ecc_opt) {
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		bch_type = 0;
+		nsectors = 1;
+		wr_mode	  = BCH_WRAPMODE_6;
+		ecc_size0 = BCH_ECC_SIZE0;
+		ecc_size1 = BCH_ECC_SIZE1;
+		break;
+	case OMAP_ECC_BCH4_CODE_HW:
+		bch_type = 0;
+		nsectors = chip->ecc.steps;
+		if (mode == NAND_ECC_READ) {
+			wr_mode	  = BCH_WRAPMODE_1;
+			ecc_size0 = BCH4R_ECC_SIZE0;
+			ecc_size1 = BCH4R_ECC_SIZE1;
+		} else {
+			wr_mode   = BCH_WRAPMODE_6;
+			ecc_size0 = BCH_ECC_SIZE0;
+			ecc_size1 = BCH_ECC_SIZE1;
+		}
+		break;
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+		bch_type = 1;
+		nsectors = 1;
+		wr_mode	  = BCH_WRAPMODE_6;
+		ecc_size0 = BCH_ECC_SIZE0;
+		ecc_size1 = BCH_ECC_SIZE1;
+		break;
+	case OMAP_ECC_BCH8_CODE_HW:
+		bch_type = 1;
+		nsectors = chip->ecc.steps;
+		if (mode == NAND_ECC_READ) {
+			wr_mode	  = BCH_WRAPMODE_1;
+			ecc_size0 = BCH8R_ECC_SIZE0;
+			ecc_size1 = BCH8R_ECC_SIZE1;
+		} else {
+			wr_mode   = BCH_WRAPMODE_6;
+			ecc_size0 = BCH_ECC_SIZE0;
+			ecc_size1 = BCH_ECC_SIZE1;
+		}
+		break;
+	case OMAP_ECC_BCH16_CODE_HW:
+		bch_type = 0x2;
+		nsectors = chip->ecc.steps;
+		if (mode == NAND_ECC_READ) {
+			wr_mode	  = 0x01;
+			ecc_size0 = 52; /* ECC bits in nibbles per sector */
+			ecc_size1 = 0;  /* non-ECC bits in nibbles per sector */
+		} else {
+			wr_mode	  = 0x01;
+			ecc_size0 = 0;  /* extra bits in nibbles per sector */
+			ecc_size1 = 52; /* OOB bits in nibbles per sector */
+		}
+		break;
+	default:
+		return;
+	}
+
+	writel(ECC1, info->reg.gpmc_ecc_control);
+
+	/* Configure ecc size for BCH */
+	val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT);
+	writel(val, info->reg.gpmc_ecc_size_config);
+
+	dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+
+	/* BCH configuration */
+	val = ((1                        << 16) | /* enable BCH */
+	       (bch_type		 << 12) | /* BCH4/BCH8/BCH16 */
+	       (wr_mode                  <<  8) | /* wrap mode */
+	       (dev_width                <<  7) | /* bus width */
+	       (((nsectors-1) & 0x7)     <<  4) | /* number of sectors */
+	       (info->gpmc_cs            <<  1) | /* ECC CS */
+	       (0x1));                            /* enable ECC */
+
+	writel(val, info->reg.gpmc_ecc_config);
+
+	/* Clear ecc and enable bits */
+	writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
+}
+
+static u8  bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f};
+static u8  bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
+				0x97, 0x79, 0xe5, 0x24, 0xb5};
+
+/**
+ * _omap_calculate_ecc_bch - Generate ECC bytes for one sector
+ * @mtd:	MTD device structure
+ * @dat:	The pointer to data on which ecc is computed
+ * @ecc_code:	The ecc_code buffer
+ * @i:		The sector number (for a multi sector page)
+ *
+ * Support calculating of BCH4/8/16 ECC vectors for one sector
+ * within a page. Sector number is in @i.
+ */
+static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
+				   const u_char *dat, u_char *ecc_calc, int i)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	int eccbytes	= info->nand.ecc.bytes;
+	struct gpmc_nand_regs	*gpmc_regs = &info->reg;
+	u8 *ecc_code;
+	unsigned long bch_val1, bch_val2, bch_val3, bch_val4;
+	u32 val;
+	int j;
+
+	ecc_code = ecc_calc;
+	switch (info->ecc_opt) {
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+	case OMAP_ECC_BCH8_CODE_HW:
+		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
+		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
+		bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]);
+		bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]);
+		*ecc_code++ = (bch_val4 & 0xFF);
+		*ecc_code++ = ((bch_val3 >> 24) & 0xFF);
+		*ecc_code++ = ((bch_val3 >> 16) & 0xFF);
+		*ecc_code++ = ((bch_val3 >> 8) & 0xFF);
+		*ecc_code++ = (bch_val3 & 0xFF);
+		*ecc_code++ = ((bch_val2 >> 24) & 0xFF);
+		*ecc_code++ = ((bch_val2 >> 16) & 0xFF);
+		*ecc_code++ = ((bch_val2 >> 8) & 0xFF);
+		*ecc_code++ = (bch_val2 & 0xFF);
+		*ecc_code++ = ((bch_val1 >> 24) & 0xFF);
+		*ecc_code++ = ((bch_val1 >> 16) & 0xFF);
+		*ecc_code++ = ((bch_val1 >> 8) & 0xFF);
+		*ecc_code++ = (bch_val1 & 0xFF);
+		break;
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+	case OMAP_ECC_BCH4_CODE_HW:
+		bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
+		bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
+		*ecc_code++ = ((bch_val2 >> 12) & 0xFF);
+		*ecc_code++ = ((bch_val2 >> 4) & 0xFF);
+		*ecc_code++ = ((bch_val2 & 0xF) << 4) |
+			((bch_val1 >> 28) & 0xF);
+		*ecc_code++ = ((bch_val1 >> 20) & 0xFF);
+		*ecc_code++ = ((bch_val1 >> 12) & 0xFF);
+		*ecc_code++ = ((bch_val1 >> 4) & 0xFF);
+		*ecc_code++ = ((bch_val1 & 0xF) << 4);
+		break;
+	case OMAP_ECC_BCH16_CODE_HW:
+		val = readl(gpmc_regs->gpmc_bch_result6[i]);
+		ecc_code[0]  = ((val >>  8) & 0xFF);
+		ecc_code[1]  = ((val >>  0) & 0xFF);
+		val = readl(gpmc_regs->gpmc_bch_result5[i]);
+		ecc_code[2]  = ((val >> 24) & 0xFF);
+		ecc_code[3]  = ((val >> 16) & 0xFF);
+		ecc_code[4]  = ((val >>  8) & 0xFF);
+		ecc_code[5]  = ((val >>  0) & 0xFF);
+		val = readl(gpmc_regs->gpmc_bch_result4[i]);
+		ecc_code[6]  = ((val >> 24) & 0xFF);
+		ecc_code[7]  = ((val >> 16) & 0xFF);
+		ecc_code[8]  = ((val >>  8) & 0xFF);
+		ecc_code[9]  = ((val >>  0) & 0xFF);
+		val = readl(gpmc_regs->gpmc_bch_result3[i]);
+		ecc_code[10] = ((val >> 24) & 0xFF);
+		ecc_code[11] = ((val >> 16) & 0xFF);
+		ecc_code[12] = ((val >>  8) & 0xFF);
+		ecc_code[13] = ((val >>  0) & 0xFF);
+		val = readl(gpmc_regs->gpmc_bch_result2[i]);
+		ecc_code[14] = ((val >> 24) & 0xFF);
+		ecc_code[15] = ((val >> 16) & 0xFF);
+		ecc_code[16] = ((val >>  8) & 0xFF);
+		ecc_code[17] = ((val >>  0) & 0xFF);
+		val = readl(gpmc_regs->gpmc_bch_result1[i]);
+		ecc_code[18] = ((val >> 24) & 0xFF);
+		ecc_code[19] = ((val >> 16) & 0xFF);
+		ecc_code[20] = ((val >>  8) & 0xFF);
+		ecc_code[21] = ((val >>  0) & 0xFF);
+		val = readl(gpmc_regs->gpmc_bch_result0[i]);
+		ecc_code[22] = ((val >> 24) & 0xFF);
+		ecc_code[23] = ((val >> 16) & 0xFF);
+		ecc_code[24] = ((val >>  8) & 0xFF);
+		ecc_code[25] = ((val >>  0) & 0xFF);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* ECC scheme specific syndrome customizations */
+	switch (info->ecc_opt) {
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		/* Add constant polynomial to remainder, so that
+		 * ECC of blank pages results in 0x0 on reading back
+		 */
+		for (j = 0; j < eccbytes; j++)
+			ecc_calc[j] ^= bch4_polynomial[j];
+		break;
+	case OMAP_ECC_BCH4_CODE_HW:
+		/* Set  8th ECC byte as 0x0 for ROM compatibility */
+		ecc_calc[eccbytes - 1] = 0x0;
+		break;
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+		/* Add constant polynomial to remainder, so that
+		 * ECC of blank pages results in 0x0 on reading back
+		 */
+		for (j = 0; j < eccbytes; j++)
+			ecc_calc[j] ^= bch8_polynomial[j];
+		break;
+	case OMAP_ECC_BCH8_CODE_HW:
+		/* Set 14th ECC byte as 0x0 for ROM compatibility */
+		ecc_calc[eccbytes - 1] = 0x0;
+		break;
+	case OMAP_ECC_BCH16_CODE_HW:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
+ * @mtd:	MTD device structure
+ * @dat:	The pointer to data on which ecc is computed
+ * @ecc_code:	The ecc_code buffer
+ *
+ * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
+ * when SW based correction is required as ECC is required for one sector
+ * at a time.
+ */
+static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
+				     const u_char *dat, u_char *ecc_calc)
+{
+	return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
+}
+
+/**
+ * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
+ * @mtd:	MTD device structure
+ * @dat:	The pointer to data on which ecc is computed
+ * @ecc_code:	The ecc_code buffer
+ *
+ * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
+ */
+static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
+					const u_char *dat, u_char *ecc_calc)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	int eccbytes = info->nand.ecc.bytes;
+	unsigned long nsectors;
+	int i, ret;
+
+	nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
+	for (i = 0; i < nsectors; i++) {
+		ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
+		if (ret)
+			return ret;
+
+		ecc_calc += eccbytes;
+	}
+
+	return 0;
+}
+
+/**
+ * erased_sector_bitflips - count bit flips
+ * @data:	data sector buffer
+ * @oob:	oob buffer
+ * @info:	omap_nand_info
+ *
+ * Check the bit flips in erased page falls below correctable level.
+ * If falls below, report the page as erased with correctable bit
+ * flip, else report as uncorrectable page.
+ */
+static int erased_sector_bitflips(u_char *data, u_char *oob,
+		struct omap_nand_info *info)
+{
+	int flip_bits = 0, i;
+
+	for (i = 0; i < info->nand.ecc.size; i++) {
+		flip_bits += hweight8(~data[i]);
+		if (flip_bits > info->nand.ecc.strength)
+			return 0;
+	}
+
+	for (i = 0; i < info->nand.ecc.bytes - 1; i++) {
+		flip_bits += hweight8(~oob[i]);
+		if (flip_bits > info->nand.ecc.strength)
+			return 0;
+	}
+
+	/*
+	 * Bit flips falls in correctable level.
+	 * Fill data area with 0xFF
+	 */
+	if (flip_bits) {
+		memset(data, 0xFF, info->nand.ecc.size);
+		memset(oob, 0xFF, info->nand.ecc.bytes);
+	}
+
+	return flip_bits;
+}
+
+/**
+ * omap_elm_correct_data - corrects page data area in case error reported
+ * @mtd:	MTD device structure
+ * @data:	page data
+ * @read_ecc:	ecc read from nand flash
+ * @calc_ecc:	ecc read from HW ECC registers
+ *
+ * Calculated ecc vector reported as zero in case of non-error pages.
+ * In case of non-zero ecc vector, first filter out erased-pages, and
+ * then process data via ELM to detect bit-flips.
+ */
+static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
+				u_char *read_ecc, u_char *calc_ecc)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct nand_ecc_ctrl *ecc = &info->nand.ecc;
+	int eccsteps = info->nand.ecc.steps;
+	int i , j, stat = 0;
+	int eccflag, actual_eccbytes;
+	struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
+	u_char *ecc_vec = calc_ecc;
+	u_char *spare_ecc = read_ecc;
+	u_char *erased_ecc_vec;
+	u_char *buf;
+	int bitflip_count;
+	bool is_error_reported = false;
+	u32 bit_pos, byte_pos, error_max, pos;
+	int err;
+
+	switch (info->ecc_opt) {
+	case OMAP_ECC_BCH4_CODE_HW:
+		/* omit  7th ECC byte reserved for ROM code compatibility */
+		actual_eccbytes = ecc->bytes - 1;
+		erased_ecc_vec = bch4_vector;
+		break;
+	case OMAP_ECC_BCH8_CODE_HW:
+		/* omit 14th ECC byte reserved for ROM code compatibility */
+		actual_eccbytes = ecc->bytes - 1;
+		erased_ecc_vec = bch8_vector;
+		break;
+	case OMAP_ECC_BCH16_CODE_HW:
+		actual_eccbytes = ecc->bytes;
+		erased_ecc_vec = bch16_vector;
+		break;
+	default:
+		dev_err(&info->pdev->dev, "invalid driver configuration\n");
+		return -EINVAL;
+	}
+
+	/* Initialize elm error vector to zero */
+	memset(err_vec, 0, sizeof(err_vec));
+
+	for (i = 0; i < eccsteps ; i++) {
+		eccflag = 0;	/* initialize eccflag */
+
+		/*
+		 * Check any error reported,
+		 * In case of error, non zero ecc reported.
+		 */
+		for (j = 0; j < actual_eccbytes; j++) {
+			if (calc_ecc[j] != 0) {
+				eccflag = 1; /* non zero ecc, error present */
+				break;
+			}
+		}
+
+		if (eccflag == 1) {
+			if (memcmp(calc_ecc, erased_ecc_vec,
+						actual_eccbytes) == 0) {
+				/*
+				 * calc_ecc[] matches pattern for ECC(all 0xff)
+				 * so this is definitely an erased-page
+				 */
+			} else {
+				buf = &data[info->nand.ecc.size * i];
+				/*
+				 * count number of 0-bits in read_buf.
+				 * This check can be removed once a similar
+				 * check is introduced in generic NAND driver
+				 */
+				bitflip_count = erased_sector_bitflips(
+						buf, read_ecc, info);
+				if (bitflip_count) {
+					/*
+					 * number of 0-bits within ECC limits
+					 * So this may be an erased-page
+					 */
+					stat += bitflip_count;
+				} else {
+					/*
+					 * Too many 0-bits. It may be a
+					 * - programmed-page, OR
+					 * - erased-page with many bit-flips
+					 * So this page requires check by ELM
+					 */
+					err_vec[i].error_reported = true;
+					is_error_reported = true;
+				}
+			}
+		}
+
+		/* Update the ecc vector */
+		calc_ecc += ecc->bytes;
+		read_ecc += ecc->bytes;
+	}
+
+	/* Check if any error reported */
+	if (!is_error_reported)
+		return stat;
+
+	/* Decode BCH error using ELM module */
+	elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec);
+
+	err = 0;
+	for (i = 0; i < eccsteps; i++) {
+		if (err_vec[i].error_uncorrectable) {
+			dev_err(&info->pdev->dev,
+				"uncorrectable bit-flips found\n");
+			err = -EBADMSG;
+		} else if (err_vec[i].error_reported) {
+			for (j = 0; j < err_vec[i].error_count; j++) {
+				switch (info->ecc_opt) {
+				case OMAP_ECC_BCH4_CODE_HW:
+					/* Add 4 bits to take care of padding */
+					pos = err_vec[i].error_loc[j] +
+						BCH4_BIT_PAD;
+					break;
+				case OMAP_ECC_BCH8_CODE_HW:
+				case OMAP_ECC_BCH16_CODE_HW:
+					pos = err_vec[i].error_loc[j];
+					break;
+				default:
+					return -EINVAL;
+				}
+				error_max = (ecc->size + actual_eccbytes) * 8;
+				/* Calculate bit position of error */
+				bit_pos = pos % 8;
+
+				/* Calculate byte position of error */
+				byte_pos = (error_max - pos - 1) / 8;
+
+				if (pos < error_max) {
+					if (byte_pos < 512) {
+						pr_debug("bitflip@dat[%d]=%x\n",
+						     byte_pos, data[byte_pos]);
+						data[byte_pos] ^= 1 << bit_pos;
+					} else {
+						pr_debug("bitflip@oob[%d]=%x\n",
+							(byte_pos - 512),
+						     spare_ecc[byte_pos - 512]);
+						spare_ecc[byte_pos - 512] ^=
+							1 << bit_pos;
+					}
+				} else {
+					dev_err(&info->pdev->dev,
+						"invalid bit-flip @ %d:%d\n",
+						byte_pos, bit_pos);
+					err = -EBADMSG;
+				}
+			}
+		}
+
+		/* Update number of correctable errors */
+		stat += err_vec[i].error_count;
+
+		/* Update page data with sector size */
+		data += ecc->size;
+		spare_ecc += ecc->bytes;
+	}
+
+	return (err) ? err : stat;
+}
+
+/**
+ * omap_write_page_bch - BCH ecc based write page function for entire page
+ * @mtd:		mtd info structure
+ * @chip:		nand chip info structure
+ * @buf:		data buffer
+ * @oob_required:	must write chip->oob_poi to OOB
+ * @page:		page
+ *
+ * Custom write page method evolved to support multi sector writing in one shot
+ */
+static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
+			       const uint8_t *buf, int oob_required, int page)
+{
+	int ret;
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	/* Enable GPMC ecc engine */
+	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+	/* Write data */
+	chip->write_buf(mtd, buf, mtd->writesize);
+
+	/* Update ecc vector from GPMC result registers */
+	omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
+
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	/* Write ecc vector to OOB area */
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+/**
+ * omap_write_subpage_bch - BCH hardware ECC based subpage write
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @offset:	column address of subpage within the page
+ * @data_len:	data length
+ * @buf:	data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ *
+ * OMAP optimized subpage write method.
+ */
+static int omap_write_subpage_bch(struct mtd_info *mtd,
+				  struct nand_chip *chip, u32 offset,
+				  u32 data_len, const u8 *buf,
+				  int oob_required, int page)
+{
+	u8 *ecc_calc = chip->ecc.calc_buf;
+	int ecc_size      = chip->ecc.size;
+	int ecc_bytes     = chip->ecc.bytes;
+	int ecc_steps     = chip->ecc.steps;
+	u32 start_step = offset / ecc_size;
+	u32 end_step   = (offset + data_len - 1) / ecc_size;
+	int step, ret = 0;
+
+	/*
+	 * Write entire page at one go as it would be optimal
+	 * as ECC is calculated by hardware.
+	 * ECC is calculated for all subpages but we choose
+	 * only what we want.
+	 */
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	/* Enable GPMC ECC engine */
+	chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+	/* Write data */
+	chip->write_buf(mtd, buf, mtd->writesize);
+
+	for (step = 0; step < ecc_steps; step++) {
+		/* mask ECC of un-touched subpages by padding 0xFF */
+		if (step < start_step || step > end_step)
+			memset(ecc_calc, 0xff, ecc_bytes);
+		else
+			ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step);
+
+		if (ret)
+			return ret;
+
+		buf += ecc_size;
+		ecc_calc += ecc_bytes;
+	}
+
+	/* copy calculated ECC for whole page to chip->buffer->oob */
+	/* this include masked-value(0xFF) for unwritten subpages */
+	ecc_calc = chip->ecc.calc_buf;
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	/* write OOB buffer to NAND device */
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+/**
+ * omap_read_page_bch - BCH ecc based page read function for entire page
+ * @mtd:		mtd info structure
+ * @chip:		nand chip info structure
+ * @buf:		buffer to store read data
+ * @oob_required:	caller requires OOB data read to chip->oob_poi
+ * @page:		page number to read
+ *
+ * For BCH ecc scheme, GPMC used for syndrome calculation and ELM module
+ * used for error correction.
+ * Custom method evolved to support ELM error correction & multi sector
+ * reading. On reading page data area is read along with OOB data with
+ * ecc engine enabled. ecc vector updated after read of OOB data.
+ * For non error pages ecc vector reported as zero.
+ */
+static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	uint8_t *ecc_calc = chip->ecc.calc_buf;
+	uint8_t *ecc_code = chip->ecc.code_buf;
+	int stat, ret;
+	unsigned int max_bitflips = 0;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	/* Enable GPMC ecc engine */
+	chip->ecc.hwctl(mtd, NAND_ECC_READ);
+
+	/* Read data */
+	chip->read_buf(mtd, buf, mtd->writesize);
+
+	/* Read oob bytes */
+	nand_change_read_column_op(chip,
+				   mtd->writesize + BADBLOCK_MARKER_LENGTH,
+				   chip->oob_poi + BADBLOCK_MARKER_LENGTH,
+				   chip->ecc.total, false);
+
+	/* Calculate ecc bytes */
+	omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
+
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
+
+	if (stat < 0) {
+		mtd->ecc_stats.failed++;
+	} else {
+		mtd->ecc_stats.corrected += stat;
+		max_bitflips = max_t(unsigned int, max_bitflips, stat);
+	}
+
+	return max_bitflips;
+}
+
+/**
+ * is_elm_present - checks for presence of ELM module by scanning DT nodes
+ * @omap_nand_info: NAND device structure containing platform data
+ */
+static bool is_elm_present(struct omap_nand_info *info,
+			   struct device_node *elm_node)
+{
+	struct platform_device *pdev;
+
+	/* check whether elm-id is passed via DT */
+	if (!elm_node) {
+		dev_err(&info->pdev->dev, "ELM devicetree node not found\n");
+		return false;
+	}
+	pdev = of_find_device_by_node(elm_node);
+	/* check whether ELM device is registered */
+	if (!pdev) {
+		dev_err(&info->pdev->dev, "ELM device not found\n");
+		return false;
+	}
+	/* ELM module available, now configure it */
+	info->elm_dev = &pdev->dev;
+	return true;
+}
+
+static bool omap2_nand_ecc_check(struct omap_nand_info *info)
+{
+	bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm;
+
+	switch (info->ecc_opt) {
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+		ecc_needs_omap_bch = false;
+		ecc_needs_bch = true;
+		ecc_needs_elm = false;
+		break;
+	case OMAP_ECC_BCH4_CODE_HW:
+	case OMAP_ECC_BCH8_CODE_HW:
+	case OMAP_ECC_BCH16_CODE_HW:
+		ecc_needs_omap_bch = true;
+		ecc_needs_bch = false;
+		ecc_needs_elm = true;
+		break;
+	default:
+		ecc_needs_omap_bch = false;
+		ecc_needs_bch = false;
+		ecc_needs_elm = false;
+		break;
+	}
+
+	if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) {
+		dev_err(&info->pdev->dev,
+			"CONFIG_MTD_NAND_ECC_BCH not enabled\n");
+		return false;
+	}
+	if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) {
+		dev_err(&info->pdev->dev,
+			"CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
+		return false;
+	}
+	if (ecc_needs_elm && !is_elm_present(info, info->elm_of_node)) {
+		dev_err(&info->pdev->dev, "ELM not available\n");
+		return false;
+	}
+
+	return true;
+}
+
+static const char * const nand_xfer_types[] = {
+	[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
+	[NAND_OMAP_POLLED] = "polled",
+	[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
+	[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
+};
+
+static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
+{
+	struct device_node *child = dev->of_node;
+	int i;
+	const char *s;
+	u32 cs;
+
+	if (of_property_read_u32(child, "reg", &cs) < 0) {
+		dev_err(dev, "reg not found in DT\n");
+		return -EINVAL;
+	}
+
+	info->gpmc_cs = cs;
+
+	/* detect availability of ELM module. Won't be present pre-OMAP4 */
+	info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
+	if (!info->elm_of_node) {
+		info->elm_of_node = of_parse_phandle(child, "elm_id", 0);
+		if (!info->elm_of_node)
+			dev_dbg(dev, "ti,elm-id not in DT\n");
+	}
+
+	/* select ecc-scheme for NAND */
+	if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
+		dev_err(dev, "ti,nand-ecc-opt not found\n");
+		return -EINVAL;
+	}
+
+	if (!strcmp(s, "sw")) {
+		info->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
+	} else if (!strcmp(s, "ham1") ||
+		   !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) {
+		info->ecc_opt =	OMAP_ECC_HAM1_CODE_HW;
+	} else if (!strcmp(s, "bch4")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
+	} else if (!strcmp(s, "bch8")) {
+		if (info->elm_of_node)
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW;
+		else
+			info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
+	} else if (!strcmp(s, "bch16")) {
+		info->ecc_opt =	OMAP_ECC_BCH16_CODE_HW;
+	} else {
+		dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n");
+		return -EINVAL;
+	}
+
+	/* select data transfer mode */
+	if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) {
+		for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) {
+			if (!strcasecmp(s, nand_xfer_types[i])) {
+				info->xfer_type = i;
+				return 0;
+			}
+		}
+
+		dev_err(dev, "unrecognized value for ti,nand-xfer-type\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct nand_chip *chip = &info->nand;
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+	    !(chip->options & NAND_BUSWIDTH_16))
+		off = 1;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = off;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int omap_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	struct nand_chip *chip = &info->nand;
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+	    !(chip->options & NAND_BUSWIDTH_16))
+		off = 1;
+
+	if (section)
+		return -ERANGE;
+
+	off += chip->ecc.total;
+	if (off >= mtd->oobsize)
+		return -ERANGE;
+
+	oobregion->offset = off;
+	oobregion->length = mtd->oobsize - off;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
+	.ecc = omap_ooblayout_ecc,
+	.free = omap_ooblayout_free,
+};
+
+static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	/*
+	 * When SW correction is employed, one OMAP specific marker byte is
+	 * reserved after each ECC step.
+	 */
+	oobregion->offset = off + (section * (chip->ecc.bytes + 1));
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int off = BADBLOCK_MARKER_LENGTH;
+
+	if (section)
+		return -ERANGE;
+
+	/*
+	 * When SW correction is employed, one OMAP specific marker byte is
+	 * reserved after each ECC step.
+	 */
+	off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
+	if (off >= mtd->oobsize)
+		return -ERANGE;
+
+	oobregion->offset = off;
+	oobregion->length = mtd->oobsize - off;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
+	.ecc = omap_sw_ooblayout_ecc,
+	.free = omap_sw_ooblayout_free,
+};
+
+static int omap_nand_probe(struct platform_device *pdev)
+{
+	struct omap_nand_info		*info;
+	struct mtd_info			*mtd;
+	struct nand_chip		*nand_chip;
+	int				err;
+	dma_cap_mask_t			mask;
+	struct resource			*res;
+	struct device			*dev = &pdev->dev;
+	int				min_oobbytes = BADBLOCK_MARKER_LENGTH;
+	int				oobbytes_per_step;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
+				GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pdev = pdev;
+
+	err = omap_get_dt_info(dev, info);
+	if (err)
+		return err;
+
+	info->ops = gpmc_omap_get_nand_ops(&info->reg, info->gpmc_cs);
+	if (!info->ops) {
+		dev_err(&pdev->dev, "Failed to get GPMC->NAND interface\n");
+		return -ENODEV;
+	}
+
+	nand_chip		= &info->nand;
+	mtd			= nand_to_mtd(nand_chip);
+	mtd->dev.parent		= &pdev->dev;
+	nand_chip->ecc.priv	= NULL;
+	nand_set_flash_node(nand_chip, dev->of_node);
+
+	if (!mtd->name) {
+		mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					   "omap2-nand.%d", info->gpmc_cs);
+		if (!mtd->name) {
+			dev_err(&pdev->dev, "Failed to set MTD name\n");
+			return -ENOMEM;
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nand_chip->IO_ADDR_R))
+		return PTR_ERR(nand_chip->IO_ADDR_R);
+
+	info->phys_base = res->start;
+
+	nand_chip->controller = &omap_gpmc_controller;
+
+	nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
+	nand_chip->cmd_ctrl  = omap_hwcontrol;
+
+	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
+						    GPIOD_IN);
+	if (IS_ERR(info->ready_gpiod)) {
+		dev_err(dev, "failed to get ready gpio\n");
+		return PTR_ERR(info->ready_gpiod);
+	}
+
+	/*
+	 * If RDY/BSY line is connected to OMAP then use the omap ready
+	 * function and the generic nand_wait function which reads the status
+	 * register after monitoring the RDY/BSY line. Otherwise use a standard
+	 * chip delay which is slightly more than tR (AC Timing) of the NAND
+	 * device and read status register until you get a failure or success
+	 */
+	if (info->ready_gpiod) {
+		nand_chip->dev_ready = omap_dev_ready;
+		nand_chip->chip_delay = 0;
+	} else {
+		nand_chip->waitfunc = omap_wait;
+		nand_chip->chip_delay = 50;
+	}
+
+	if (info->flash_bbt)
+		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	/* scan NAND device connected to chip controller */
+	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
+	err = nand_scan_ident(mtd, 1, NULL);
+	if (err) {
+		dev_err(&info->pdev->dev,
+			"scan failed, may be bus-width mismatch\n");
+		goto return_error;
+	}
+
+	if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
+		nand_chip->bbt_options |= NAND_BBT_NO_OOB;
+	else
+		nand_chip->options |= NAND_SKIP_BBTSCAN;
+
+	/* re-populate low-level callbacks based on xfer modes */
+	switch (info->xfer_type) {
+	case NAND_OMAP_PREFETCH_POLLED:
+		nand_chip->read_buf   = omap_read_buf_pref;
+		nand_chip->write_buf  = omap_write_buf_pref;
+		break;
+
+	case NAND_OMAP_POLLED:
+		/* Use nand_base defaults for {read,write}_buf */
+		break;
+
+	case NAND_OMAP_PREFETCH_DMA:
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_SLAVE, mask);
+		info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
+
+		if (IS_ERR(info->dma)) {
+			dev_err(&pdev->dev, "DMA engine request failed\n");
+			err = PTR_ERR(info->dma);
+			goto return_error;
+		} else {
+			struct dma_slave_config cfg;
+
+			memset(&cfg, 0, sizeof(cfg));
+			cfg.src_addr = info->phys_base;
+			cfg.dst_addr = info->phys_base;
+			cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			cfg.src_maxburst = 16;
+			cfg.dst_maxburst = 16;
+			err = dmaengine_slave_config(info->dma, &cfg);
+			if (err) {
+				dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
+					err);
+				goto return_error;
+			}
+			nand_chip->read_buf   = omap_read_buf_dma_pref;
+			nand_chip->write_buf  = omap_write_buf_dma_pref;
+		}
+		break;
+
+	case NAND_OMAP_PREFETCH_IRQ:
+		info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
+		if (info->gpmc_irq_fifo <= 0) {
+			dev_err(&pdev->dev, "error getting fifo irq\n");
+			err = -ENODEV;
+			goto return_error;
+		}
+		err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
+					omap_nand_irq, IRQF_SHARED,
+					"gpmc-nand-fifo", info);
+		if (err) {
+			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
+						info->gpmc_irq_fifo, err);
+			info->gpmc_irq_fifo = 0;
+			goto return_error;
+		}
+
+		info->gpmc_irq_count = platform_get_irq(pdev, 1);
+		if (info->gpmc_irq_count <= 0) {
+			dev_err(&pdev->dev, "error getting count irq\n");
+			err = -ENODEV;
+			goto return_error;
+		}
+		err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
+					omap_nand_irq, IRQF_SHARED,
+					"gpmc-nand-count", info);
+		if (err) {
+			dev_err(&pdev->dev, "requesting irq(%d) error:%d",
+						info->gpmc_irq_count, err);
+			info->gpmc_irq_count = 0;
+			goto return_error;
+		}
+
+		nand_chip->read_buf  = omap_read_buf_irq_pref;
+		nand_chip->write_buf = omap_write_buf_irq_pref;
+
+		break;
+
+	default:
+		dev_err(&pdev->dev,
+			"xfer_type(%d) not supported!\n", info->xfer_type);
+		err = -EINVAL;
+		goto return_error;
+	}
+
+	if (!omap2_nand_ecc_check(info)) {
+		err = -EINVAL;
+		goto return_error;
+	}
+
+	/*
+	 * Bail out earlier to let NAND_ECC_SOFT code create its own
+	 * ooblayout instead of using ours.
+	 */
+	if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+		nand_chip->ecc.mode = NAND_ECC_SOFT;
+		nand_chip->ecc.algo = NAND_ECC_HAMMING;
+		goto scan_tail;
+	}
+
+	/* populate MTD interface based on ECC scheme */
+	switch (info->ecc_opt) {
+	case OMAP_ECC_HAM1_CODE_HW:
+		pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
+		nand_chip->ecc.mode             = NAND_ECC_HW;
+		nand_chip->ecc.bytes            = 3;
+		nand_chip->ecc.size             = 512;
+		nand_chip->ecc.strength         = 1;
+		nand_chip->ecc.calculate        = omap_calculate_ecc;
+		nand_chip->ecc.hwctl            = omap_enable_hwecc;
+		nand_chip->ecc.correct          = omap_correct_data;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
+
+		if (!(nand_chip->options & NAND_BUSWIDTH_16))
+			min_oobbytes		= 1;
+
+		break;
+
+	case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
+		nand_chip->ecc.mode		= NAND_ECC_HW;
+		nand_chip->ecc.size		= 512;
+		nand_chip->ecc.bytes		= 7;
+		nand_chip->ecc.strength		= 4;
+		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+		nand_chip->ecc.correct		= nand_bch_correct_data;
+		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
+		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+		/* Reserve one byte for the OMAP marker */
+		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
+		/* software bch library is used for locating errors */
+		nand_chip->ecc.priv		= nand_bch_init(mtd);
+		if (!nand_chip->ecc.priv) {
+			dev_err(&info->pdev->dev, "unable to use BCH library\n");
+			err = -EINVAL;
+			goto return_error;
+		}
+		break;
+
+	case OMAP_ECC_BCH4_CODE_HW:
+		pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
+		nand_chip->ecc.mode		= NAND_ECC_HW;
+		nand_chip->ecc.size		= 512;
+		/* 14th bit is kept reserved for ROM-code compatibility */
+		nand_chip->ecc.bytes		= 7 + 1;
+		nand_chip->ecc.strength		= 4;
+		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+		nand_chip->ecc.correct		= omap_elm_correct_data;
+		nand_chip->ecc.read_page	= omap_read_page_bch;
+		nand_chip->ecc.write_page	= omap_write_page_bch;
+		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
+
+		err = elm_config(info->elm_dev, BCH4_ECC,
+				 mtd->writesize / nand_chip->ecc.size,
+				 nand_chip->ecc.size, nand_chip->ecc.bytes);
+		if (err < 0)
+			goto return_error;
+		break;
+
+	case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
+		nand_chip->ecc.mode		= NAND_ECC_HW;
+		nand_chip->ecc.size		= 512;
+		nand_chip->ecc.bytes		= 13;
+		nand_chip->ecc.strength		= 8;
+		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+		nand_chip->ecc.correct		= nand_bch_correct_data;
+		nand_chip->ecc.calculate	= omap_calculate_ecc_bch_sw;
+		mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+		/* Reserve one byte for the OMAP marker */
+		oobbytes_per_step		= nand_chip->ecc.bytes + 1;
+		/* software bch library is used for locating errors */
+		nand_chip->ecc.priv		= nand_bch_init(mtd);
+		if (!nand_chip->ecc.priv) {
+			dev_err(&info->pdev->dev, "unable to use BCH library\n");
+			err = -EINVAL;
+			goto return_error;
+		}
+		break;
+
+	case OMAP_ECC_BCH8_CODE_HW:
+		pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+		nand_chip->ecc.mode		= NAND_ECC_HW;
+		nand_chip->ecc.size		= 512;
+		/* 14th bit is kept reserved for ROM-code compatibility */
+		nand_chip->ecc.bytes		= 13 + 1;
+		nand_chip->ecc.strength		= 8;
+		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+		nand_chip->ecc.correct		= omap_elm_correct_data;
+		nand_chip->ecc.read_page	= omap_read_page_bch;
+		nand_chip->ecc.write_page	= omap_write_page_bch;
+		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
+
+		err = elm_config(info->elm_dev, BCH8_ECC,
+				 mtd->writesize / nand_chip->ecc.size,
+				 nand_chip->ecc.size, nand_chip->ecc.bytes);
+		if (err < 0)
+			goto return_error;
+
+		break;
+
+	case OMAP_ECC_BCH16_CODE_HW:
+		pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
+		nand_chip->ecc.mode		= NAND_ECC_HW;
+		nand_chip->ecc.size		= 512;
+		nand_chip->ecc.bytes		= 26;
+		nand_chip->ecc.strength		= 16;
+		nand_chip->ecc.hwctl		= omap_enable_hwecc_bch;
+		nand_chip->ecc.correct		= omap_elm_correct_data;
+		nand_chip->ecc.read_page	= omap_read_page_bch;
+		nand_chip->ecc.write_page	= omap_write_page_bch;
+		nand_chip->ecc.write_subpage	= omap_write_subpage_bch;
+		mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+		oobbytes_per_step		= nand_chip->ecc.bytes;
+
+		err = elm_config(info->elm_dev, BCH16_ECC,
+				 mtd->writesize / nand_chip->ecc.size,
+				 nand_chip->ecc.size, nand_chip->ecc.bytes);
+		if (err < 0)
+			goto return_error;
+
+		break;
+	default:
+		dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
+		err = -EINVAL;
+		goto return_error;
+	}
+
+	/* check if NAND device's OOB is enough to store ECC signatures */
+	min_oobbytes += (oobbytes_per_step *
+			 (mtd->writesize / nand_chip->ecc.size));
+	if (mtd->oobsize < min_oobbytes) {
+		dev_err(&info->pdev->dev,
+			"not enough OOB bytes required = %d, available=%d\n",
+			min_oobbytes, mtd->oobsize);
+		err = -EINVAL;
+		goto return_error;
+	}
+
+scan_tail:
+	/* second phase scan */
+	err = nand_scan_tail(mtd);
+	if (err)
+		goto return_error;
+
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		goto return_error;
+
+	platform_set_drvdata(pdev, mtd);
+
+	return 0;
+
+return_error:
+	if (!IS_ERR_OR_NULL(info->dma))
+		dma_release_channel(info->dma);
+	if (nand_chip->ecc.priv) {
+		nand_bch_free(nand_chip->ecc.priv);
+		nand_chip->ecc.priv = NULL;
+	}
+	return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+	struct mtd_info *mtd = platform_get_drvdata(pdev);
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct omap_nand_info *info = mtd_to_omap(mtd);
+	if (nand_chip->ecc.priv) {
+		nand_bch_free(nand_chip->ecc.priv);
+		nand_chip->ecc.priv = NULL;
+	}
+	if (info->dma)
+		dma_release_channel(info->dma);
+	nand_release(mtd);
+	return 0;
+}
+
+static const struct of_device_id omap_nand_ids[] = {
+	{ .compatible = "ti,omap2-nand", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_nand_ids);
+
+static struct platform_driver omap_nand_driver = {
+	.probe		= omap_nand_probe,
+	.remove		= omap_nand_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.of_match_table = of_match_ptr(omap_nand_ids),
+	},
+};
+
+module_platform_driver(omap_nand_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c
new file mode 100644
index 000000000000..a3f32f939cc1
--- /dev/null
+++ b/drivers/mtd/nand/raw/omap_elm.c
@@ -0,0 +1,578 @@
+/*
+ * Error Location Module
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define DRIVER_NAME	"omap-elm"
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_data/elm.h>
+
+#define ELM_SYSCONFIG			0x010
+#define ELM_IRQSTATUS			0x018
+#define ELM_IRQENABLE			0x01c
+#define ELM_LOCATION_CONFIG		0x020
+#define ELM_PAGE_CTRL			0x080
+#define ELM_SYNDROME_FRAGMENT_0		0x400
+#define ELM_SYNDROME_FRAGMENT_1		0x404
+#define ELM_SYNDROME_FRAGMENT_2		0x408
+#define ELM_SYNDROME_FRAGMENT_3		0x40c
+#define ELM_SYNDROME_FRAGMENT_4		0x410
+#define ELM_SYNDROME_FRAGMENT_5		0x414
+#define ELM_SYNDROME_FRAGMENT_6		0x418
+#define ELM_LOCATION_STATUS		0x800
+#define ELM_ERROR_LOCATION_0		0x880
+
+/* ELM Interrupt Status Register */
+#define INTR_STATUS_PAGE_VALID		BIT(8)
+
+/* ELM Interrupt Enable Register */
+#define INTR_EN_PAGE_MASK		BIT(8)
+
+/* ELM Location Configuration Register */
+#define ECC_BCH_LEVEL_MASK		0x3
+
+/* ELM syndrome */
+#define ELM_SYNDROME_VALID		BIT(16)
+
+/* ELM_LOCATION_STATUS Register */
+#define ECC_CORRECTABLE_MASK		BIT(8)
+#define ECC_NB_ERRORS_MASK		0x1f
+
+/* ELM_ERROR_LOCATION_0-15 Registers */
+#define ECC_ERROR_LOCATION_MASK		0x1fff
+
+#define ELM_ECC_SIZE			0x7ff
+
+#define SYNDROME_FRAGMENT_REG_SIZE	0x40
+#define ERROR_LOCATION_SIZE		0x100
+
+struct elm_registers {
+	u32 elm_irqenable;
+	u32 elm_sysconfig;
+	u32 elm_location_config;
+	u32 elm_page_ctrl;
+	u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
+};
+
+struct elm_info {
+	struct device *dev;
+	void __iomem *elm_base;
+	struct completion elm_completion;
+	struct list_head list;
+	enum bch_ecc bch_type;
+	struct elm_registers elm_regs;
+	int ecc_steps;
+	int ecc_syndrome_size;
+};
+
+static LIST_HEAD(elm_devices);
+
+static void elm_write_reg(struct elm_info *info, int offset, u32 val)
+{
+	writel(val, info->elm_base + offset);
+}
+
+static u32 elm_read_reg(struct elm_info *info, int offset)
+{
+	return readl(info->elm_base + offset);
+}
+
+/**
+ * elm_config - Configure ELM module
+ * @dev:	ELM device
+ * @bch_type:	Type of BCH ecc
+ */
+int elm_config(struct device *dev, enum bch_ecc bch_type,
+	int ecc_steps, int ecc_step_size, int ecc_syndrome_size)
+{
+	u32 reg_val;
+	struct elm_info *info = dev_get_drvdata(dev);
+
+	if (!info) {
+		dev_err(dev, "Unable to configure elm - device not probed?\n");
+		return -EPROBE_DEFER;
+	}
+	/* ELM cannot detect ECC errors for chunks > 1KB */
+	if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) {
+		dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size);
+		return -EINVAL;
+	}
+	/* ELM support 8 error syndrome process */
+	if (ecc_steps > ERROR_VECTOR_MAX) {
+		dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
+		return -EINVAL;
+	}
+
+	reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
+	elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
+	info->bch_type		= bch_type;
+	info->ecc_steps		= ecc_steps;
+	info->ecc_syndrome_size	= ecc_syndrome_size;
+
+	return 0;
+}
+EXPORT_SYMBOL(elm_config);
+
+/**
+ * elm_configure_page_mode - Enable/Disable page mode
+ * @info:	elm info
+ * @index:	index number of syndrome fragment vector
+ * @enable:	enable/disable flag for page mode
+ *
+ * Enable page mode for syndrome fragment index
+ */
+static void elm_configure_page_mode(struct elm_info *info, int index,
+		bool enable)
+{
+	u32 reg_val;
+
+	reg_val = elm_read_reg(info, ELM_PAGE_CTRL);
+	if (enable)
+		reg_val |= BIT(index);	/* enable page mode */
+	else
+		reg_val &= ~BIT(index);	/* disable page mode */
+
+	elm_write_reg(info, ELM_PAGE_CTRL, reg_val);
+}
+
+/**
+ * elm_load_syndrome - Load ELM syndrome reg
+ * @info:	elm info
+ * @err_vec:	elm error vectors
+ * @ecc:	buffer with calculated ecc
+ *
+ * Load syndrome fragment registers with calculated ecc in reverse order.
+ */
+static void elm_load_syndrome(struct elm_info *info,
+		struct elm_errorvec *err_vec, u8 *ecc)
+{
+	int i, offset;
+	u32 val;
+
+	for (i = 0; i < info->ecc_steps; i++) {
+
+		/* Check error reported */
+		if (err_vec[i].error_reported) {
+			elm_configure_page_mode(info, i, true);
+			offset = ELM_SYNDROME_FRAGMENT_0 +
+				SYNDROME_FRAGMENT_REG_SIZE * i;
+			switch (info->bch_type) {
+			case BCH8_ECC:
+				/* syndrome fragment 0 = ecc[9-12B] */
+				val = cpu_to_be32(*(u32 *) &ecc[9]);
+				elm_write_reg(info, offset, val);
+
+				/* syndrome fragment 1 = ecc[5-8B] */
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[5]);
+				elm_write_reg(info, offset, val);
+
+				/* syndrome fragment 2 = ecc[1-4B] */
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[1]);
+				elm_write_reg(info, offset, val);
+
+				/* syndrome fragment 3 = ecc[0B] */
+				offset += 4;
+				val = ecc[0];
+				elm_write_reg(info, offset, val);
+				break;
+			case BCH4_ECC:
+				/* syndrome fragment 0 = ecc[20-52b] bits */
+				val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
+					((ecc[2] & 0xf) << 28);
+				elm_write_reg(info, offset, val);
+
+				/* syndrome fragment 1 = ecc[0-20b] bits */
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
+				elm_write_reg(info, offset, val);
+				break;
+			case BCH16_ECC:
+				val = cpu_to_be32(*(u32 *) &ecc[22]);
+				elm_write_reg(info, offset, val);
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[18]);
+				elm_write_reg(info, offset, val);
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[14]);
+				elm_write_reg(info, offset, val);
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[10]);
+				elm_write_reg(info, offset, val);
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[6]);
+				elm_write_reg(info, offset, val);
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[2]);
+				elm_write_reg(info, offset, val);
+				offset += 4;
+				val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16;
+				elm_write_reg(info, offset, val);
+				break;
+			default:
+				pr_err("invalid config bch_type\n");
+			}
+		}
+
+		/* Update ecc pointer with ecc byte size */
+		ecc += info->ecc_syndrome_size;
+	}
+}
+
+/**
+ * elm_start_processing - start elm syndrome processing
+ * @info:	elm info
+ * @err_vec:	elm error vectors
+ *
+ * Set syndrome valid bit for syndrome fragment registers for which
+ * elm syndrome fragment registers are loaded. This enables elm module
+ * to start processing syndrome vectors.
+ */
+static void elm_start_processing(struct elm_info *info,
+		struct elm_errorvec *err_vec)
+{
+	int i, offset;
+	u32 reg_val;
+
+	/*
+	 * Set syndrome vector valid, so that ELM module
+	 * will process it for vectors error is reported
+	 */
+	for (i = 0; i < info->ecc_steps; i++) {
+		if (err_vec[i].error_reported) {
+			offset = ELM_SYNDROME_FRAGMENT_6 +
+				SYNDROME_FRAGMENT_REG_SIZE * i;
+			reg_val = elm_read_reg(info, offset);
+			reg_val |= ELM_SYNDROME_VALID;
+			elm_write_reg(info, offset, reg_val);
+		}
+	}
+}
+
+/**
+ * elm_error_correction - locate correctable error position
+ * @info:	elm info
+ * @err_vec:	elm error vectors
+ *
+ * On completion of processing by elm module, error location status
+ * register updated with correctable/uncorrectable error information.
+ * In case of correctable errors, number of errors located from
+ * elm location status register & read the positions from
+ * elm error location register.
+ */
+static void elm_error_correction(struct elm_info *info,
+		struct elm_errorvec *err_vec)
+{
+	int i, j, errors = 0;
+	int offset;
+	u32 reg_val;
+
+	for (i = 0; i < info->ecc_steps; i++) {
+
+		/* Check error reported */
+		if (err_vec[i].error_reported) {
+			offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i;
+			reg_val = elm_read_reg(info, offset);
+
+			/* Check correctable error or not */
+			if (reg_val & ECC_CORRECTABLE_MASK) {
+				offset = ELM_ERROR_LOCATION_0 +
+					ERROR_LOCATION_SIZE * i;
+
+				/* Read count of correctable errors */
+				err_vec[i].error_count = reg_val &
+					ECC_NB_ERRORS_MASK;
+
+				/* Update the error locations in error vector */
+				for (j = 0; j < err_vec[i].error_count; j++) {
+
+					reg_val = elm_read_reg(info, offset);
+					err_vec[i].error_loc[j] = reg_val &
+						ECC_ERROR_LOCATION_MASK;
+
+					/* Update error location register */
+					offset += 4;
+				}
+
+				errors += err_vec[i].error_count;
+			} else {
+				err_vec[i].error_uncorrectable = true;
+			}
+
+			/* Clearing interrupts for processed error vectors */
+			elm_write_reg(info, ELM_IRQSTATUS, BIT(i));
+
+			/* Disable page mode */
+			elm_configure_page_mode(info, i, false);
+		}
+	}
+}
+
+/**
+ * elm_decode_bch_error_page - Locate error position
+ * @dev:	device pointer
+ * @ecc_calc:	calculated ECC bytes from GPMC
+ * @err_vec:	elm error vectors
+ *
+ * Called with one or more error reported vectors & vectors with
+ * error reported is updated in err_vec[].error_reported
+ */
+void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
+		struct elm_errorvec *err_vec)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	u32 reg_val;
+
+	/* Enable page mode interrupt */
+	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
+	elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID);
+	elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK);
+
+	/* Load valid ecc byte to syndrome fragment register */
+	elm_load_syndrome(info, err_vec, ecc_calc);
+
+	/* Enable syndrome processing for which syndrome fragment is updated */
+	elm_start_processing(info, err_vec);
+
+	/* Wait for ELM module to finish locating error correction */
+	wait_for_completion(&info->elm_completion);
+
+	/* Disable page mode interrupt */
+	reg_val = elm_read_reg(info, ELM_IRQENABLE);
+	elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK);
+	elm_error_correction(info, err_vec);
+}
+EXPORT_SYMBOL(elm_decode_bch_error_page);
+
+static irqreturn_t elm_isr(int this_irq, void *dev_id)
+{
+	u32 reg_val;
+	struct elm_info *info = dev_id;
+
+	reg_val = elm_read_reg(info, ELM_IRQSTATUS);
+
+	/* All error vectors processed */
+	if (reg_val & INTR_STATUS_PAGE_VALID) {
+		elm_write_reg(info, ELM_IRQSTATUS,
+				reg_val & INTR_STATUS_PAGE_VALID);
+		complete(&info->elm_completion);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int elm_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct resource *res, *irq;
+	struct elm_info *info;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = &pdev->dev;
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq) {
+		dev_err(&pdev->dev, "no irq resource defined\n");
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	info->elm_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(info->elm_base))
+		return PTR_ERR(info->elm_base);
+
+	ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
+			pdev->name, info);
+	if (ret) {
+		dev_err(&pdev->dev, "failure requesting %pr\n", irq);
+		return ret;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	if (pm_runtime_get_sync(&pdev->dev) < 0) {
+		ret = -EINVAL;
+		pm_runtime_disable(&pdev->dev);
+		dev_err(&pdev->dev, "can't enable clock\n");
+		return ret;
+	}
+
+	init_completion(&info->elm_completion);
+	INIT_LIST_HEAD(&info->list);
+	list_add(&info->list, &elm_devices);
+	platform_set_drvdata(pdev, info);
+	return ret;
+}
+
+static int elm_remove(struct platform_device *pdev)
+{
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * elm_context_save
+ * saves ELM configurations to preserve them across Hardware powered-down
+ */
+static int elm_context_save(struct elm_info *info)
+{
+	struct elm_registers *regs = &info->elm_regs;
+	enum bch_ecc bch_type = info->bch_type;
+	u32 offset = 0, i;
+
+	regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
+	regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
+	regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
+	regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
+	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+		switch (bch_type) {
+		case BCH16_ECC:
+			regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_6 + offset);
+			regs->elm_syndrome_fragment_5[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_5 + offset);
+			regs->elm_syndrome_fragment_4[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_4 + offset);
+		case BCH8_ECC:
+			regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_3 + offset);
+			regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_2 + offset);
+		case BCH4_ECC:
+			regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_1 + offset);
+			regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_0 + offset);
+			break;
+		default:
+			return -EINVAL;
+		}
+		/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
+		 * to be saved for all BCH schemes*/
+		regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_6 + offset);
+	}
+	return 0;
+}
+
+/**
+ * elm_context_restore
+ * writes configurations saved duing power-down back into ELM registers
+ */
+static int elm_context_restore(struct elm_info *info)
+{
+	struct elm_registers *regs = &info->elm_regs;
+	enum bch_ecc bch_type = info->bch_type;
+	u32 offset = 0, i;
+
+	elm_write_reg(info, ELM_IRQENABLE,	 regs->elm_irqenable);
+	elm_write_reg(info, ELM_SYSCONFIG,	 regs->elm_sysconfig);
+	elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
+	elm_write_reg(info, ELM_PAGE_CTRL,	 regs->elm_page_ctrl);
+	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+		switch (bch_type) {
+		case BCH16_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+					regs->elm_syndrome_fragment_6[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset,
+					regs->elm_syndrome_fragment_5[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset,
+					regs->elm_syndrome_fragment_4[i]);
+		case BCH8_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
+					regs->elm_syndrome_fragment_3[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
+					regs->elm_syndrome_fragment_2[i]);
+		case BCH4_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
+					regs->elm_syndrome_fragment_1[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
+					regs->elm_syndrome_fragment_0[i]);
+			break;
+		default:
+			return -EINVAL;
+		}
+		/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
+		elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+					regs->elm_syndrome_fragment_6[i] &
+							 ELM_SYNDROME_VALID);
+	}
+	return 0;
+}
+
+static int elm_suspend(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	elm_context_save(info);
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	pm_runtime_get_sync(dev);
+	elm_context_restore(info);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id elm_of_match[] = {
+	{ .compatible = "ti,am3352-elm" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, elm_of_match);
+#endif
+
+static struct platform_driver elm_driver = {
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.of_match_table = of_match_ptr(elm_of_match),
+		.pm	= &elm_pm_ops,
+	},
+	.probe	= elm_probe,
+	.remove	= elm_remove,
+};
+
+module_platform_driver(elm_driver);
+
+MODULE_DESCRIPTION("ELM driver for BCH error correction");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
new file mode 100644
index 000000000000..7825fd3ce66b
--- /dev/null
+++ b/drivers/mtd/nand/raw/orion_nand.c
@@ -0,0 +1,232 @@
+/*
+ * NAND support for Marvell Orion SoC platforms
+ *
+ * Tzachi Perelstein <tzachi@marvell.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <asm/sizes.h>
+#include <linux/platform_data/mtd-orion_nand.h>
+
+struct orion_nand_info {
+	struct nand_chip chip;
+	struct clk *clk;
+};
+
+static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nc = mtd_to_nand(mtd);
+	struct orion_nand_data *board = nand_get_controller_data(nc);
+	u32 offs;
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		offs = (1 << board->cle);
+	else if (ctrl & NAND_ALE)
+		offs = (1 << board->ale);
+	else
+		return;
+
+	if (nc->options & NAND_BUSWIDTH_16)
+		offs <<= 1;
+
+	writeb(cmd, nc->IO_ADDR_W + offs);
+}
+
+static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	void __iomem *io_base = chip->IO_ADDR_R;
+#if __LINUX_ARM_ARCH__ >= 5
+	uint64_t *buf64;
+#endif
+	int i = 0;
+
+	while (len && (unsigned long)buf & 7) {
+		*buf++ = readb(io_base);
+		len--;
+	}
+#if __LINUX_ARM_ARCH__ >= 5
+	buf64 = (uint64_t *)buf;
+	while (i < len/8) {
+		/*
+		 * Since GCC has no proper constraint (PR 43518)
+		 * force x variable to r2/r3 registers as ldrd instruction
+		 * requires first register to be even.
+		 */
+		register uint64_t x asm ("r2");
+
+		asm volatile ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base));
+		buf64[i++] = x;
+	}
+	i *= 8;
+#else
+	readsl(io_base, buf, len/4);
+	i = len / 4 * 4;
+#endif
+	while (i < len)
+		buf[i++] = readb(io_base);
+}
+
+static int __init orion_nand_probe(struct platform_device *pdev)
+{
+	struct orion_nand_info *info;
+	struct mtd_info *mtd;
+	struct nand_chip *nc;
+	struct orion_nand_data *board;
+	struct resource *res;
+	void __iomem *io_base;
+	int ret = 0;
+	u32 val = 0;
+
+	info = devm_kzalloc(&pdev->dev,
+			sizeof(struct orion_nand_info),
+			GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	nc = &info->chip;
+	mtd = nand_to_mtd(nc);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	io_base = devm_ioremap_resource(&pdev->dev, res);
+
+	if (IS_ERR(io_base))
+		return PTR_ERR(io_base);
+
+	if (pdev->dev.of_node) {
+		board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
+					GFP_KERNEL);
+		if (!board)
+			return -ENOMEM;
+		if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
+			board->cle = (u8)val;
+		else
+			board->cle = 0;
+		if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
+			board->ale = (u8)val;
+		else
+			board->ale = 1;
+		if (!of_property_read_u32(pdev->dev.of_node,
+						"bank-width", &val))
+			board->width = (u8)val * 8;
+		else
+			board->width = 8;
+		if (!of_property_read_u32(pdev->dev.of_node,
+						"chip-delay", &val))
+			board->chip_delay = (u8)val;
+	} else {
+		board = dev_get_platdata(&pdev->dev);
+	}
+
+	mtd->dev.parent = &pdev->dev;
+
+	nand_set_controller_data(nc, board);
+	nand_set_flash_node(nc, pdev->dev.of_node);
+	nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
+	nc->cmd_ctrl = orion_nand_cmd_ctrl;
+	nc->read_buf = orion_nand_read_buf;
+	nc->ecc.mode = NAND_ECC_SOFT;
+	nc->ecc.algo = NAND_ECC_HAMMING;
+
+	if (board->chip_delay)
+		nc->chip_delay = board->chip_delay;
+
+	WARN(board->width > 16,
+		"%d bit bus width out of range",
+		board->width);
+
+	if (board->width == 16)
+		nc->options |= NAND_BUSWIDTH_16;
+
+	if (board->dev_ready)
+		nc->dev_ready = board->dev_ready;
+
+	platform_set_drvdata(pdev, info);
+
+	/* Not all platforms can gate the clock, so it is not
+	   an error if the clock does not exists. */
+	info->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(info->clk)) {
+		ret = PTR_ERR(info->clk);
+		if (ret == -ENOENT) {
+			info->clk = NULL;
+		} else {
+			dev_err(&pdev->dev, "failed to get clock!\n");
+			return ret;
+		}
+	}
+
+	ret = clk_prepare_enable(info->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to prepare clock!\n");
+		return ret;
+	}
+
+	ret = nand_scan(mtd, 1);
+	if (ret)
+		goto no_dev;
+
+	mtd->name = "orion_nand";
+	ret = mtd_device_register(mtd, board->parts, board->nr_parts);
+	if (ret) {
+		nand_release(mtd);
+		goto no_dev;
+	}
+
+	return 0;
+
+no_dev:
+	clk_disable_unprepare(info->clk);
+	return ret;
+}
+
+static int orion_nand_remove(struct platform_device *pdev)
+{
+	struct orion_nand_info *info = platform_get_drvdata(pdev);
+	struct nand_chip *chip = &info->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	nand_release(mtd);
+
+	clk_disable_unprepare(info->clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id orion_nand_of_match_table[] = {
+	{ .compatible = "marvell,orion-nand", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
+#endif
+
+static struct platform_driver orion_nand_driver = {
+	.remove		= orion_nand_remove,
+	.driver		= {
+		.name	= "orion_nand",
+		.of_match_table = of_match_ptr(orion_nand_of_match_table),
+	},
+};
+
+module_platform_driver_probe(orion_nand_driver, orion_nand_probe);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tzachi Perelstein");
+MODULE_DESCRIPTION("NAND glue for Orion platforms");
+MODULE_ALIAS("platform:orion_nand");
diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c
new file mode 100644
index 000000000000..d649d5944826
--- /dev/null
+++ b/drivers/mtd/nand/raw/oxnas_nand.c
@@ -0,0 +1,206 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE		BIT(18)
+#define OXNAS_NAND_CMD_CLE		BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS	1
+
+struct oxnas_nand_ctrl {
+	struct nand_hw_control base;
+	void __iomem *io_base;
+	struct clk *clk;
+	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	iowrite8_rep(oxnas->io_base, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
+	else if (ctrl & NAND_ALE)
+		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *nand_np;
+	struct oxnas_nand_ctrl *oxnas;
+	struct nand_chip *chip;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int nchips = 0;
+	int count = 0;
+	int err = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas),
+			     GFP_KERNEL);
+	if (!oxnas)
+		return -ENOMEM;
+
+	nand_hw_control_init(&oxnas->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(oxnas->io_base))
+		return PTR_ERR(oxnas->io_base);
+
+	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(oxnas->clk))
+		oxnas->clk = NULL;
+
+	/* Only a single chip node is supported */
+	count = of_get_child_count(np);
+	if (count > 1)
+		return -EINVAL;
+
+	err = clk_prepare_enable(oxnas->clk);
+	if (err)
+		return err;
+
+	device_reset_optional(&pdev->dev);
+
+	for_each_child_of_node(np, nand_np) {
+		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+				    GFP_KERNEL);
+		if (!chip) {
+			err = -ENOMEM;
+			goto err_clk_unprepare;
+		}
+
+		chip->controller = &oxnas->base;
+
+		nand_set_flash_node(chip, nand_np);
+		nand_set_controller_data(chip, oxnas);
+
+		mtd = nand_to_mtd(chip);
+		mtd->dev.parent = &pdev->dev;
+		mtd->priv = chip;
+
+		chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+		chip->read_buf = oxnas_nand_read_buf;
+		chip->read_byte = oxnas_nand_read_byte;
+		chip->write_buf = oxnas_nand_write_buf;
+		chip->chip_delay = 30;
+
+		/* Scan to find existence of the device */
+		err = nand_scan(mtd, 1);
+		if (err)
+			goto err_clk_unprepare;
+
+		err = mtd_device_register(mtd, NULL, 0);
+		if (err) {
+			nand_release(mtd);
+			goto err_clk_unprepare;
+		}
+
+		oxnas->chips[nchips] = chip;
+		++nchips;
+	}
+
+	/* Exit if no chips found */
+	if (!nchips) {
+		err = -ENODEV;
+		goto err_clk_unprepare;
+	}
+
+	platform_set_drvdata(pdev, oxnas);
+
+	return 0;
+
+err_clk_unprepare:
+	clk_disable_unprepare(oxnas->clk);
+	return err;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+	struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
+
+	if (oxnas->chips[0])
+		nand_release(nand_to_mtd(oxnas->chips[0]));
+
+	clk_disable_unprepare(oxnas->clk);
+
+	return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+	{ .compatible = "oxsemi,ox820-nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+	.probe	= oxnas_nand_probe,
+	.remove	= oxnas_nand_remove,
+	.driver	= {
+		.name		= "oxnas_nand",
+		.of_match_table = oxnas_nand_match,
+	},
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
new file mode 100644
index 000000000000..a47a7e4bd25a
--- /dev/null
+++ b/drivers/mtd/nand/raw/pasemi_nand.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip NAND flash interface
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+
+#define LBICTRL_LPCCTL_NR		0x00004000
+#define CLE_PIN_CTL			15
+#define ALE_PIN_CTL			14
+
+static unsigned int lpcctl;
+static struct mtd_info *pasemi_nand_mtd;
+static const char driver_name[] = "pasemi-nand";
+
+static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	while (len > 0x800) {
+		memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+		buf += 0x800;
+		len -= 0x800;
+	}
+	memcpy_fromio(buf, chip->IO_ADDR_R, len);
+}
+
+static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	while (len > 0x800) {
+		memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+		buf += 0x800;
+		len -= 0x800;
+	}
+	memcpy_toio(chip->IO_ADDR_R, buf, len);
+}
+
+static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+			     unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+	else
+		out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+
+	/* Push out posted writes */
+	eieio();
+	inl(lpcctl);
+}
+
+int pasemi_device_ready(struct mtd_info *mtd)
+{
+	return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
+}
+
+static int pasemi_nand_probe(struct platform_device *ofdev)
+{
+	struct device *dev = &ofdev->dev;
+	struct pci_dev *pdev;
+	struct device_node *np = dev->of_node;
+	struct resource res;
+	struct nand_chip *chip;
+	int err = 0;
+
+	err = of_address_to_resource(np, 0, &res);
+
+	if (err)
+		return -EINVAL;
+
+	/* We only support one device at the moment */
+	if (pasemi_nand_mtd)
+		return -ENODEV;
+
+	dev_dbg(dev, "pasemi_nand at %pR\n", &res);
+
+	/* Allocate memory for MTD device structure and private data */
+	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+	if (!chip) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	pasemi_nand_mtd = nand_to_mtd(chip);
+
+	/* Link the private data with the MTD structure */
+	pasemi_nand_mtd->dev.parent = dev;
+
+	chip->IO_ADDR_R = of_iomap(np, 0);
+	chip->IO_ADDR_W = chip->IO_ADDR_R;
+
+	if (!chip->IO_ADDR_R) {
+		err = -EIO;
+		goto out_mtd;
+	}
+
+	pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL);
+	if (!pdev) {
+		err = -ENODEV;
+		goto out_ior;
+	}
+
+	lpcctl = pci_resource_start(pdev, 0);
+	pci_dev_put(pdev);
+
+	if (!request_region(lpcctl, 4, driver_name)) {
+		err = -EBUSY;
+		goto out_ior;
+	}
+
+	chip->cmd_ctrl = pasemi_hwcontrol;
+	chip->dev_ready = pasemi_device_ready;
+	chip->read_buf = pasemi_read_buf;
+	chip->write_buf = pasemi_write_buf;
+	chip->chip_delay = 0;
+	chip->ecc.mode = NAND_ECC_SOFT;
+	chip->ecc.algo = NAND_ECC_HAMMING;
+
+	/* Enable the following for a flash based bad block table */
+	chip->bbt_options = NAND_BBT_USE_FLASH;
+
+	/* Scan to find existence of the device */
+	err = nand_scan(pasemi_nand_mtd, 1);
+	if (err)
+		goto out_lpc;
+
+	if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
+		dev_err(dev, "Unable to register MTD device\n");
+		err = -ENODEV;
+		goto out_lpc;
+	}
+
+	dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
+		 lpcctl);
+
+	return 0;
+
+ out_lpc:
+	release_region(lpcctl, 4);
+ out_ior:
+	iounmap(chip->IO_ADDR_R);
+ out_mtd:
+	kfree(chip);
+ out:
+	return err;
+}
+
+static int pasemi_nand_remove(struct platform_device *ofdev)
+{
+	struct nand_chip *chip;
+
+	if (!pasemi_nand_mtd)
+		return 0;
+
+	chip = mtd_to_nand(pasemi_nand_mtd);
+
+	/* Release resources, unregister device */
+	nand_release(pasemi_nand_mtd);
+
+	release_region(lpcctl, 4);
+
+	iounmap(chip->IO_ADDR_R);
+
+	/* Free the MTD device structure */
+	kfree(chip);
+
+	pasemi_nand_mtd = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id pasemi_nand_match[] =
+{
+	{
+		.compatible   = "pasemi,localbus-nand",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, pasemi_nand_match);
+
+static struct platform_driver pasemi_nand_driver =
+{
+	.driver = {
+		.name = driver_name,
+		.of_match_table = pasemi_nand_match,
+	},
+	.probe		= pasemi_nand_probe,
+	.remove		= pasemi_nand_remove,
+};
+
+module_platform_driver(pasemi_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient");
diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
new file mode 100644
index 000000000000..925a1323604d
--- /dev/null
+++ b/drivers/mtd/nand/raw/plat_nand.c
@@ -0,0 +1,144 @@
+/*
+ * Generic NAND driver
+ *
+ * Author: Vitaly Wool <vitalywool@gmail.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/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+
+struct plat_nand_data {
+	struct nand_chip	chip;
+	void __iomem		*io_base;
+};
+
+/*
+ * Probe for the NAND device.
+ */
+static int plat_nand_probe(struct platform_device *pdev)
+{
+	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
+	struct plat_nand_data *data;
+	struct mtd_info *mtd;
+	struct resource *res;
+	const char **part_types;
+	int err = 0;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform_nand_data is missing\n");
+		return -EINVAL;
+	}
+
+	if (pdata->chip.nr_chips < 1) {
+		dev_err(&pdev->dev, "invalid number of chips specified\n");
+		return -EINVAL;
+	}
+
+	/* Allocate memory for the device structure (and zero it) */
+	data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->io_base))
+		return PTR_ERR(data->io_base);
+
+	nand_set_flash_node(&data->chip, pdev->dev.of_node);
+	mtd = nand_to_mtd(&data->chip);
+	mtd->dev.parent = &pdev->dev;
+
+	data->chip.IO_ADDR_R = data->io_base;
+	data->chip.IO_ADDR_W = data->io_base;
+	data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+	data->chip.dev_ready = pdata->ctrl.dev_ready;
+	data->chip.select_chip = pdata->ctrl.select_chip;
+	data->chip.write_buf = pdata->ctrl.write_buf;
+	data->chip.read_buf = pdata->ctrl.read_buf;
+	data->chip.read_byte = pdata->ctrl.read_byte;
+	data->chip.chip_delay = pdata->chip.chip_delay;
+	data->chip.options |= pdata->chip.options;
+	data->chip.bbt_options |= pdata->chip.bbt_options;
+
+	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
+	data->chip.ecc.mode = NAND_ECC_SOFT;
+	data->chip.ecc.algo = NAND_ECC_HAMMING;
+
+	platform_set_drvdata(pdev, data);
+
+	/* Handle any platform specific setup */
+	if (pdata->ctrl.probe) {
+		err = pdata->ctrl.probe(pdev);
+		if (err)
+			goto out;
+	}
+
+	/* Scan to find existence of the device */
+	err = nand_scan(mtd, pdata->chip.nr_chips);
+	if (err)
+		goto out;
+
+	part_types = pdata->chip.part_probe_types;
+
+	err = mtd_device_parse_register(mtd, part_types, NULL,
+					pdata->chip.partitions,
+					pdata->chip.nr_partitions);
+
+	if (!err)
+		return err;
+
+	nand_release(mtd);
+out:
+	if (pdata->ctrl.remove)
+		pdata->ctrl.remove(pdev);
+	return err;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int plat_nand_remove(struct platform_device *pdev)
+{
+	struct plat_nand_data *data = platform_get_drvdata(pdev);
+	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
+
+	nand_release(nand_to_mtd(&data->chip));
+	if (pdata->ctrl.remove)
+		pdata->ctrl.remove(pdev);
+
+	return 0;
+}
+
+static const struct of_device_id plat_nand_match[] = {
+	{ .compatible = "gen_nand" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, plat_nand_match);
+
+static struct platform_driver plat_nand_driver = {
+	.probe	= plat_nand_probe,
+	.remove	= plat_nand_remove,
+	.driver	= {
+		.name		= "gen_nand",
+		.of_match_table = plat_nand_match,
+	},
+};
+
+module_platform_driver(plat_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool");
+MODULE_DESCRIPTION("Simple generic NAND driver");
+MODULE_ALIAS("platform:gen_nand");
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
new file mode 100644
index 000000000000..d75f30263d21
--- /dev/null
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -0,0 +1,2103 @@
+/*
+ * Copyright © 2005 Intel Corporation
+ * Copyright © 2006 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mtd-nand-pxa3xx.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#define	CHIP_DELAY_TIMEOUT	msecs_to_jiffies(200)
+#define NAND_STOP_DELAY		msecs_to_jiffies(40)
+#define PAGE_CHUNK_SIZE		(2048)
+
+/*
+ * Define a buffer size for the initial command that detects the flash device:
+ * STATUS, READID and PARAM.
+ * ONFI param page is 256 bytes, and there are three redundant copies
+ * to be read. JEDEC param page is 512 bytes, and there are also three
+ * redundant copies to be read.
+ * Hence this buffer should be at least 512 x 3. Let's pick 2048.
+ */
+#define INIT_BUFFER_SIZE	2048
+
+/* System control register and bit to enable NAND on some SoCs */
+#define GENCONF_SOC_DEVICE_MUX	0x208
+#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
+
+/* registers and bit definitions */
+#define NDCR		(0x00) /* Control register */
+#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */
+#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */
+#define NDSR		(0x14) /* Status Register */
+#define NDPCR		(0x18) /* Page Count Register */
+#define NDBDR0		(0x1C) /* Bad Block Register 0 */
+#define NDBDR1		(0x20) /* Bad Block Register 1 */
+#define NDECCCTRL	(0x28) /* ECC control */
+#define NDDB		(0x40) /* Data Buffer */
+#define NDCB0		(0x48) /* Command Buffer0 */
+#define NDCB1		(0x4C) /* Command Buffer1 */
+#define NDCB2		(0x50) /* Command Buffer2 */
+
+#define NDCR_SPARE_EN		(0x1 << 31)
+#define NDCR_ECC_EN		(0x1 << 30)
+#define NDCR_DMA_EN		(0x1 << 29)
+#define NDCR_ND_RUN		(0x1 << 28)
+#define NDCR_DWIDTH_C		(0x1 << 27)
+#define NDCR_DWIDTH_M		(0x1 << 26)
+#define NDCR_PAGE_SZ		(0x1 << 24)
+#define NDCR_NCSX		(0x1 << 23)
+#define NDCR_ND_MODE		(0x3 << 21)
+#define NDCR_NAND_MODE   	(0x0)
+#define NDCR_CLR_PG_CNT		(0x1 << 20)
+#define NFCV1_NDCR_ARB_CNTL	(0x1 << 19)
+#define NFCV2_NDCR_STOP_ON_UNCOR	(0x1 << 19)
+#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
+#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
+
+#define NDCR_RA_START		(0x1 << 15)
+#define NDCR_PG_PER_BLK		(0x1 << 14)
+#define NDCR_ND_ARB_EN		(0x1 << 12)
+#define NDCR_INT_MASK           (0xFFF)
+
+#define NDSR_MASK		(0xfff)
+#define NDSR_ERR_CNT_OFF	(16)
+#define NDSR_ERR_CNT_MASK       (0x1f)
+#define NDSR_ERR_CNT(sr)	((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
+#define NDSR_RDY                (0x1 << 12)
+#define NDSR_FLASH_RDY          (0x1 << 11)
+#define NDSR_CS0_PAGED		(0x1 << 10)
+#define NDSR_CS1_PAGED		(0x1 << 9)
+#define NDSR_CS0_CMDD		(0x1 << 8)
+#define NDSR_CS1_CMDD		(0x1 << 7)
+#define NDSR_CS0_BBD		(0x1 << 6)
+#define NDSR_CS1_BBD		(0x1 << 5)
+#define NDSR_UNCORERR		(0x1 << 4)
+#define NDSR_CORERR		(0x1 << 3)
+#define NDSR_WRDREQ		(0x1 << 2)
+#define NDSR_RDDREQ		(0x1 << 1)
+#define NDSR_WRCMDREQ		(0x1)
+
+#define NDCB0_LEN_OVRD		(0x1 << 28)
+#define NDCB0_ST_ROW_EN         (0x1 << 26)
+#define NDCB0_AUTO_RS		(0x1 << 25)
+#define NDCB0_CSEL		(0x1 << 24)
+#define NDCB0_EXT_CMD_TYPE_MASK	(0x7 << 29)
+#define NDCB0_EXT_CMD_TYPE(x)	(((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
+#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
+#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)
+#define NDCB0_NC		(0x1 << 20)
+#define NDCB0_DBC		(0x1 << 19)
+#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)
+#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)
+#define NDCB0_CMD2_MASK		(0xff << 8)
+#define NDCB0_CMD1_MASK		(0xff)
+#define NDCB0_ADDR_CYC_SHIFT	(16)
+
+#define EXT_CMD_TYPE_DISPATCH	6 /* Command dispatch */
+#define EXT_CMD_TYPE_NAKED_RW	5 /* Naked read or Naked write */
+#define EXT_CMD_TYPE_READ	4 /* Read */
+#define EXT_CMD_TYPE_DISP_WR	4 /* Command dispatch with write */
+#define EXT_CMD_TYPE_FINAL	3 /* Final command */
+#define EXT_CMD_TYPE_LAST_RW	1 /* Last naked read/write */
+#define EXT_CMD_TYPE_MONO	0 /* Monolithic read/write */
+
+/*
+ * This should be large enough to read 'ONFI' and 'JEDEC'.
+ * Let's use 7 bytes, which is the maximum ID count supported
+ * by the controller (see NDCR_RD_ID_CNT_MASK).
+ */
+#define READ_ID_BYTES		7
+
+/* macros for registers read/write */
+#define nand_writel(info, off, val)					\
+	do {								\
+		dev_vdbg(&info->pdev->dev,				\
+			 "%s():%d nand_writel(0x%x, 0x%04x)\n",		\
+			 __func__, __LINE__, (val), (off));		\
+		writel_relaxed((val), (info)->mmio_base + (off));	\
+	} while (0)
+
+#define nand_readl(info, off)						\
+	({								\
+		unsigned int _v;					\
+		_v = readl_relaxed((info)->mmio_base + (off));		\
+		dev_vdbg(&info->pdev->dev,				\
+			 "%s():%d nand_readl(0x%04x) = 0x%x\n",		\
+			 __func__, __LINE__, (off), _v);		\
+		_v;							\
+	})
+
+/* error code and state */
+enum {
+	ERR_NONE	= 0,
+	ERR_DMABUSERR	= -1,
+	ERR_SENDCMD	= -2,
+	ERR_UNCORERR	= -3,
+	ERR_BBERR	= -4,
+	ERR_CORERR	= -5,
+};
+
+enum {
+	STATE_IDLE = 0,
+	STATE_PREPARED,
+	STATE_CMD_HANDLE,
+	STATE_DMA_READING,
+	STATE_DMA_WRITING,
+	STATE_DMA_DONE,
+	STATE_PIO_READING,
+	STATE_PIO_WRITING,
+	STATE_CMD_DONE,
+	STATE_READY,
+};
+
+enum pxa3xx_nand_variant {
+	PXA3XX_NAND_VARIANT_PXA,
+	PXA3XX_NAND_VARIANT_ARMADA370,
+	PXA3XX_NAND_VARIANT_ARMADA_8K,
+};
+
+struct pxa3xx_nand_host {
+	struct nand_chip	chip;
+	void			*info_data;
+
+	/* page size of attached chip */
+	int			use_ecc;
+	int			cs;
+
+	/* calculated from pxa3xx_nand_flash data */
+	unsigned int		col_addr_cycles;
+	unsigned int		row_addr_cycles;
+};
+
+struct pxa3xx_nand_info {
+	struct nand_hw_control	controller;
+	struct platform_device	 *pdev;
+
+	struct clk		*clk;
+	void __iomem		*mmio_base;
+	unsigned long		mmio_phys;
+	struct completion	cmd_complete, dev_ready;
+
+	unsigned int 		buf_start;
+	unsigned int		buf_count;
+	unsigned int		buf_size;
+	unsigned int		data_buff_pos;
+	unsigned int		oob_buff_pos;
+
+	/* DMA information */
+	struct scatterlist	sg;
+	enum dma_data_direction	dma_dir;
+	struct dma_chan		*dma_chan;
+	dma_cookie_t		dma_cookie;
+	int			drcmr_dat;
+
+	unsigned char		*data_buff;
+	unsigned char		*oob_buff;
+	dma_addr_t 		data_buff_phys;
+	int 			data_dma_ch;
+
+	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
+	unsigned int		state;
+
+	/*
+	 * This driver supports NFCv1 (as found in PXA SoC)
+	 * and NFCv2 (as found in Armada 370/XP SoC).
+	 */
+	enum pxa3xx_nand_variant variant;
+
+	int			cs;
+	int			use_ecc;	/* use HW ECC ? */
+	int			ecc_bch;	/* using BCH ECC? */
+	int			use_dma;	/* use DMA ? */
+	int			use_spare;	/* use spare ? */
+	int			need_wait;
+
+	/* Amount of real data per full chunk */
+	unsigned int		chunk_size;
+
+	/* Amount of spare data per full chunk */
+	unsigned int		spare_size;
+
+	/* Number of full chunks (i.e chunk_size + spare_size) */
+	unsigned int            nfullchunks;
+
+	/*
+	 * Total number of chunks. If equal to nfullchunks, then there
+	 * are only full chunks. Otherwise, there is one last chunk of
+	 * size (last_chunk_size + last_spare_size)
+	 */
+	unsigned int            ntotalchunks;
+
+	/* Amount of real data in the last chunk */
+	unsigned int		last_chunk_size;
+
+	/* Amount of spare data in the last chunk */
+	unsigned int		last_spare_size;
+
+	unsigned int		ecc_size;
+	unsigned int		ecc_err_cnt;
+	unsigned int		max_bitflips;
+	int 			retcode;
+
+	/*
+	 * Variables only valid during command
+	 * execution. step_chunk_size and step_spare_size is the
+	 * amount of real data and spare data in the current
+	 * chunk. cur_chunk is the current chunk being
+	 * read/programmed.
+	 */
+	unsigned int		step_chunk_size;
+	unsigned int		step_spare_size;
+	unsigned int            cur_chunk;
+
+	/* cached register value */
+	uint32_t		reg_ndcr;
+	uint32_t		ndtr0cs0;
+	uint32_t		ndtr1cs0;
+
+	/* generated NDCBx register values */
+	uint32_t		ndcb0;
+	uint32_t		ndcb1;
+	uint32_t		ndcb2;
+	uint32_t		ndcb3;
+};
+
+static bool use_dma = 1;
+module_param(use_dma, bool, 0444);
+MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
+
+struct pxa3xx_nand_timing {
+	unsigned int	tCH;  /* Enable signal hold time */
+	unsigned int	tCS;  /* Enable signal setup time */
+	unsigned int	tWH;  /* ND_nWE high duration */
+	unsigned int	tWP;  /* ND_nWE pulse time */
+	unsigned int	tRH;  /* ND_nRE high duration */
+	unsigned int	tRP;  /* ND_nRE pulse width */
+	unsigned int	tR;   /* ND_nWE high to ND_nRE low for read */
+	unsigned int	tWHR; /* ND_nWE high to ND_nRE low for status read */
+	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
+};
+
+struct pxa3xx_nand_flash {
+	uint32_t	chip_id;
+	unsigned int	flash_width;	/* Width of Flash memory (DWIDTH_M) */
+	unsigned int	dfc_width;	/* Width of flash controller(DWIDTH_C) */
+	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
+};
+
+static struct pxa3xx_nand_timing timing[] = {
+	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
+	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
+	{ 10, 25, 15,  25, 15,  30, 25000,  60, 10, },
+	{ 10, 35, 15,  25, 15,  25, 25000,  60, 10, },
+};
+
+static struct pxa3xx_nand_flash builtin_flash_types[] = {
+	{ 0x46ec, 16, 16, &timing[1] },
+	{ 0xdaec,  8,  8, &timing[1] },
+	{ 0xd7ec,  8,  8, &timing[1] },
+	{ 0xa12c,  8,  8, &timing[2] },
+	{ 0xb12c, 16, 16, &timing[2] },
+	{ 0xdc2c,  8,  8, &timing[2] },
+	{ 0xcc2c, 16, 16, &timing[2] },
+	{ 0xba20, 16, 16, &timing[3] },
+};
+
+static int pxa3xx_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int nchunks = mtd->writesize / info->chunk_size;
+
+	if (section >= nchunks)
+		return -ERANGE;
+
+	oobregion->offset = ((info->ecc_size + info->spare_size) * section) +
+			    info->spare_size;
+	oobregion->length = info->ecc_size;
+
+	return 0;
+}
+
+static int pxa3xx_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int nchunks = mtd->writesize / info->chunk_size;
+
+	if (section >= nchunks)
+		return -ERANGE;
+
+	if (!info->spare_size)
+		return 0;
+
+	oobregion->offset = section * (info->ecc_size + info->spare_size);
+	oobregion->length = info->spare_size;
+	if (!section) {
+		/*
+		 * Bootrom looks in bytes 0 & 5 for bad blocks for the
+		 * 4KB page / 4bit BCH combination.
+		 */
+		if (mtd->writesize == 4096 && info->chunk_size == 2048) {
+			oobregion->offset += 6;
+			oobregion->length -= 6;
+		} else {
+			oobregion->offset += 2;
+			oobregion->length -= 2;
+		}
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops pxa3xx_ooblayout_ops = {
+	.ecc = pxa3xx_ooblayout_ecc,
+	.free = pxa3xx_ooblayout_free,
+};
+
+static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
+static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	8,
+	.len = 6,
+	.veroffs = 14,
+	.maxblocks = 8,		/* Last 8 blocks in each chip */
+	.pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	8,
+	.len = 6,
+	.veroffs = 14,
+	.maxblocks = 8,		/* Last 8 blocks in each chip */
+	.pattern = bbt_mirror_pattern
+};
+
+#define NDTR0_tCH(c)	(min((c), 7) << 19)
+#define NDTR0_tCS(c)	(min((c), 7) << 16)
+#define NDTR0_tWH(c)	(min((c), 7) << 11)
+#define NDTR0_tWP(c)	(min((c), 7) << 8)
+#define NDTR0_tRH(c)	(min((c), 7) << 3)
+#define NDTR0_tRP(c)	(min((c), 7) << 0)
+
+#define NDTR1_tR(c)	(min((c), 65535) << 16)
+#define NDTR1_tWHR(c)	(min((c), 15) << 4)
+#define NDTR1_tAR(c)	(min((c), 15) << 0)
+
+/* convert nano-seconds to nand flash controller clock cycles */
+#define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000)
+
+static const struct of_device_id pxa3xx_nand_dt_ids[] = {
+	{
+		.compatible = "marvell,pxa3xx-nand",
+		.data       = (void *)PXA3XX_NAND_VARIANT_PXA,
+	},
+	{
+		.compatible = "marvell,armada370-nand",
+		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
+	},
+	{
+		.compatible = "marvell,armada-8k-nand",
+		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA_8K,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
+
+static enum pxa3xx_nand_variant
+pxa3xx_nand_get_variant(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+	if (!of_id)
+		return PXA3XX_NAND_VARIANT_PXA;
+	return (enum pxa3xx_nand_variant)of_id->data;
+}
+
+static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
+				   const struct pxa3xx_nand_timing *t)
+{
+	struct pxa3xx_nand_info *info = host->info_data;
+	unsigned long nand_clk = clk_get_rate(info->clk);
+	uint32_t ndtr0, ndtr1;
+
+	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
+		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
+		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
+		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
+		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
+		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
+
+	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
+		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
+		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
+
+	info->ndtr0cs0 = ndtr0;
+	info->ndtr1cs0 = ndtr1;
+	nand_writel(info, NDTR0CS0, ndtr0);
+	nand_writel(info, NDTR1CS0, ndtr1);
+}
+
+static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
+				       const struct nand_sdr_timings *t)
+{
+	struct pxa3xx_nand_info *info = host->info_data;
+	struct nand_chip *chip = &host->chip;
+	unsigned long nand_clk = clk_get_rate(info->clk);
+	uint32_t ndtr0, ndtr1;
+
+	u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
+	u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000);
+	u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000);
+	u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000);
+	u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000);
+	u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000);
+	u32 tR = chip->chip_delay * 1000;
+	u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
+	u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
+
+	/* fallback to a default value if tR = 0 */
+	if (!tR)
+		tR = 20000;
+
+	ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) |
+		NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) |
+		NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) |
+		NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) |
+		NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) |
+		NDTR0_tRP(ns2cycle(tRP_min, nand_clk));
+
+	ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) |
+		NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) |
+		NDTR1_tAR(ns2cycle(tAR_min, nand_clk));
+
+	info->ndtr0cs0 = ndtr0;
+	info->ndtr1cs0 = ndtr1;
+	nand_writel(info, NDTR0CS0, ndtr0);
+	nand_writel(info, NDTR1CS0, ndtr1);
+}
+
+static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
+					   unsigned int *flash_width,
+					   unsigned int *dfc_width)
+{
+	struct nand_chip *chip = &host->chip;
+	struct pxa3xx_nand_info *info = host->info_data;
+	const struct pxa3xx_nand_flash *f = NULL;
+	int i, id, ntypes;
+	u8 idbuf[2];
+
+	ntypes = ARRAY_SIZE(builtin_flash_types);
+
+	nand_readid_op(chip, 0, idbuf, sizeof(idbuf));
+	id = idbuf[0] | (idbuf[1] << 8);
+
+	for (i = 0; i < ntypes; i++) {
+		f = &builtin_flash_types[i];
+
+		if (f->chip_id == id)
+			break;
+	}
+
+	if (i == ntypes) {
+		dev_err(&info->pdev->dev, "Error: timings not found\n");
+		return -EINVAL;
+	}
+
+	pxa3xx_nand_set_timing(host, f->timing);
+
+	*flash_width = f->flash_width;
+	*dfc_width = f->dfc_width;
+
+	return 0;
+}
+
+static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host,
+					 int mode)
+{
+	const struct nand_sdr_timings *timings;
+
+	mode = fls(mode) - 1;
+	if (mode < 0)
+		mode = 0;
+
+	timings = onfi_async_timing_mode_to_sdr_timings(mode);
+	if (IS_ERR(timings))
+		return PTR_ERR(timings);
+
+	pxa3xx_nand_set_sdr_timing(host, timings);
+
+	return 0;
+}
+
+static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct pxa3xx_nand_info *info = host->info_data;
+	unsigned int flash_width = 0, dfc_width = 0;
+	int mode, err;
+
+	mode = onfi_get_async_timing_mode(chip);
+	if (mode == ONFI_TIMING_MODE_UNKNOWN) {
+		err = pxa3xx_nand_init_timings_compat(host, &flash_width,
+						      &dfc_width);
+		if (err)
+			return err;
+
+		if (flash_width == 16) {
+			info->reg_ndcr |= NDCR_DWIDTH_M;
+			chip->options |= NAND_BUSWIDTH_16;
+		}
+
+		info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0;
+	} else {
+		err = pxa3xx_nand_init_timings_onfi(host, mode);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * NOTE: it is a must to set ND_RUN firstly, then write
+ * command buffer, otherwise, it does not work.
+ * We enable all the interrupt at the same time, and
+ * let pxa3xx_nand_irq to handle all logic.
+ */
+static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
+{
+	uint32_t ndcr;
+
+	ndcr = info->reg_ndcr;
+
+	if (info->use_ecc) {
+		ndcr |= NDCR_ECC_EN;
+		if (info->ecc_bch)
+			nand_writel(info, NDECCCTRL, 0x1);
+	} else {
+		ndcr &= ~NDCR_ECC_EN;
+		if (info->ecc_bch)
+			nand_writel(info, NDECCCTRL, 0x0);
+	}
+
+	if (info->use_dma)
+		ndcr |= NDCR_DMA_EN;
+	else
+		ndcr &= ~NDCR_DMA_EN;
+
+	if (info->use_spare)
+		ndcr |= NDCR_SPARE_EN;
+	else
+		ndcr &= ~NDCR_SPARE_EN;
+
+	ndcr |= NDCR_ND_RUN;
+
+	/* clear status bits and run */
+	nand_writel(info, NDSR, NDSR_MASK);
+	nand_writel(info, NDCR, 0);
+	nand_writel(info, NDCR, ndcr);
+}
+
+static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
+{
+	uint32_t ndcr;
+	int timeout = NAND_STOP_DELAY;
+
+	/* wait RUN bit in NDCR become 0 */
+	ndcr = nand_readl(info, NDCR);
+	while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) {
+		ndcr = nand_readl(info, NDCR);
+		udelay(1);
+	}
+
+	if (timeout <= 0) {
+		ndcr &= ~NDCR_ND_RUN;
+		nand_writel(info, NDCR, ndcr);
+	}
+	if (info->dma_chan)
+		dmaengine_terminate_all(info->dma_chan);
+
+	/* clear status bits */
+	nand_writel(info, NDSR, NDSR_MASK);
+}
+
+static void __maybe_unused
+enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+{
+	uint32_t ndcr;
+
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr & ~int_mask);
+}
+
+static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+{
+	uint32_t ndcr;
+
+	ndcr = nand_readl(info, NDCR);
+	nand_writel(info, NDCR, ndcr | int_mask);
+}
+
+static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
+{
+	if (info->ecc_bch) {
+		u32 val;
+		int ret;
+
+		/*
+		 * According to the datasheet, when reading from NDDB
+		 * with BCH enabled, after each 32 bytes reads, we
+		 * have to make sure that the NDSR.RDDREQ bit is set.
+		 *
+		 * Drain the FIFO 8 32 bits reads at a time, and skip
+		 * the polling on the last read.
+		 */
+		while (len > 8) {
+			ioread32_rep(info->mmio_base + NDDB, data, 8);
+
+			ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val,
+							 val & NDSR_RDDREQ, 1000, 5000);
+			if (ret) {
+				dev_err(&info->pdev->dev,
+					"Timeout on RDDREQ while draining the FIFO\n");
+				return;
+			}
+
+			data += 32;
+			len -= 8;
+		}
+	}
+
+	ioread32_rep(info->mmio_base + NDDB, data, len);
+}
+
+static void handle_data_pio(struct pxa3xx_nand_info *info)
+{
+	switch (info->state) {
+	case STATE_PIO_WRITING:
+		if (info->step_chunk_size)
+			writesl(info->mmio_base + NDDB,
+				info->data_buff + info->data_buff_pos,
+				DIV_ROUND_UP(info->step_chunk_size, 4));
+
+		if (info->step_spare_size)
+			writesl(info->mmio_base + NDDB,
+				info->oob_buff + info->oob_buff_pos,
+				DIV_ROUND_UP(info->step_spare_size, 4));
+		break;
+	case STATE_PIO_READING:
+		if (info->step_chunk_size)
+			drain_fifo(info,
+				   info->data_buff + info->data_buff_pos,
+				   DIV_ROUND_UP(info->step_chunk_size, 4));
+
+		if (info->step_spare_size)
+			drain_fifo(info,
+				   info->oob_buff + info->oob_buff_pos,
+				   DIV_ROUND_UP(info->step_spare_size, 4));
+		break;
+	default:
+		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
+				info->state);
+		BUG();
+	}
+
+	/* Update buffer pointers for multi-page read/write */
+	info->data_buff_pos += info->step_chunk_size;
+	info->oob_buff_pos += info->step_spare_size;
+}
+
+static void pxa3xx_nand_data_dma_irq(void *data)
+{
+	struct pxa3xx_nand_info *info = data;
+	struct dma_tx_state state;
+	enum dma_status status;
+
+	status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
+	if (likely(status == DMA_COMPLETE)) {
+		info->state = STATE_DMA_DONE;
+	} else {
+		dev_err(&info->pdev->dev, "DMA error on data channel\n");
+		info->retcode = ERR_DMABUSERR;
+	}
+	dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+
+	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+	enable_int(info, NDCR_INT_MASK);
+}
+
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{
+	enum dma_transfer_direction direction;
+	struct dma_async_tx_descriptor *tx;
+
+	switch (info->state) {
+	case STATE_DMA_WRITING:
+		info->dma_dir = DMA_TO_DEVICE;
+		direction = DMA_MEM_TO_DEV;
+		break;
+	case STATE_DMA_READING:
+		info->dma_dir = DMA_FROM_DEVICE;
+		direction = DMA_DEV_TO_MEM;
+		break;
+	default:
+		dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
+				info->state);
+		BUG();
+	}
+	info->sg.length = info->chunk_size;
+	if (info->use_spare)
+		info->sg.length += info->spare_size + info->ecc_size;
+	dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+
+	tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
+				     DMA_PREP_INTERRUPT);
+	if (!tx) {
+		dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
+		return;
+	}
+	tx->callback = pxa3xx_nand_data_dma_irq;
+	tx->callback_param = info;
+	info->dma_cookie = dmaengine_submit(tx);
+	dma_async_issue_pending(info->dma_chan);
+	dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
+		__func__, direction, info->dma_cookie, info->sg.length);
+}
+
+static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
+{
+	struct pxa3xx_nand_info *info = data;
+
+	handle_data_pio(info);
+
+	info->state = STATE_CMD_DONE;
+	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+{
+	struct pxa3xx_nand_info *info = devid;
+	unsigned int status, is_completed = 0, is_ready = 0;
+	unsigned int ready, cmd_done;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	if (info->cs == 0) {
+		ready           = NDSR_FLASH_RDY;
+		cmd_done        = NDSR_CS0_CMDD;
+	} else {
+		ready           = NDSR_RDY;
+		cmd_done        = NDSR_CS1_CMDD;
+	}
+
+	status = nand_readl(info, NDSR);
+
+	if (status & NDSR_UNCORERR)
+		info->retcode = ERR_UNCORERR;
+	if (status & NDSR_CORERR) {
+		info->retcode = ERR_CORERR;
+		if ((info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
+		     info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) &&
+		    info->ecc_bch)
+			info->ecc_err_cnt = NDSR_ERR_CNT(status);
+		else
+			info->ecc_err_cnt = 1;
+
+		/*
+		 * Each chunk composing a page is corrected independently,
+		 * and we need to store maximum number of corrected bitflips
+		 * to return it to the MTD layer in ecc.read_page().
+		 */
+		info->max_bitflips = max_t(unsigned int,
+					   info->max_bitflips,
+					   info->ecc_err_cnt);
+	}
+	if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
+		/* whether use dma to transfer data */
+		if (info->use_dma) {
+			disable_int(info, NDCR_INT_MASK);
+			info->state = (status & NDSR_RDDREQ) ?
+				      STATE_DMA_READING : STATE_DMA_WRITING;
+			start_data_dma(info);
+			goto NORMAL_IRQ_EXIT;
+		} else {
+			info->state = (status & NDSR_RDDREQ) ?
+				      STATE_PIO_READING : STATE_PIO_WRITING;
+			ret = IRQ_WAKE_THREAD;
+			goto NORMAL_IRQ_EXIT;
+		}
+	}
+	if (status & cmd_done) {
+		info->state = STATE_CMD_DONE;
+		is_completed = 1;
+	}
+	if (status & ready) {
+		info->state = STATE_READY;
+		is_ready = 1;
+	}
+
+	/*
+	 * Clear all status bit before issuing the next command, which
+	 * can and will alter the status bits and will deserve a new
+	 * interrupt on its own. This lets the controller exit the IRQ
+	 */
+	nand_writel(info, NDSR, status);
+
+	if (status & NDSR_WRCMDREQ) {
+		status &= ~NDSR_WRCMDREQ;
+		info->state = STATE_CMD_HANDLE;
+
+		/*
+		 * Command buffer registers NDCB{0-2} (and optionally NDCB3)
+		 * must be loaded by writing directly either 12 or 16
+		 * bytes directly to NDCB0, four bytes at a time.
+		 *
+		 * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
+		 * but each NDCBx register can be read.
+		 */
+		nand_writel(info, NDCB0, info->ndcb0);
+		nand_writel(info, NDCB0, info->ndcb1);
+		nand_writel(info, NDCB0, info->ndcb2);
+
+		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
+		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
+		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
+			nand_writel(info, NDCB0, info->ndcb3);
+	}
+
+	if (is_completed)
+		complete(&info->cmd_complete);
+	if (is_ready)
+		complete(&info->dev_ready);
+NORMAL_IRQ_EXIT:
+	return ret;
+}
+
+static inline int is_buf_blank(uint8_t *buf, size_t len)
+{
+	for (; len > 0; len--)
+		if (*buf++ != 0xff)
+			return 0;
+	return 1;
+}
+
+static void set_command_address(struct pxa3xx_nand_info *info,
+		unsigned int page_size, uint16_t column, int page_addr)
+{
+	/* small page addr setting */
+	if (page_size < PAGE_CHUNK_SIZE) {
+		info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
+				| (column & 0xFF);
+
+		info->ndcb2 = 0;
+	} else {
+		info->ndcb1 = ((page_addr & 0xFFFF) << 16)
+				| (column & 0xFFFF);
+
+		if (page_addr & 0xFF0000)
+			info->ndcb2 = (page_addr & 0xFF0000) >> 16;
+		else
+			info->ndcb2 = 0;
+	}
+}
+
+static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
+{
+	struct pxa3xx_nand_host *host = info->host[info->cs];
+	struct mtd_info *mtd = nand_to_mtd(&host->chip);
+
+	/* reset data and oob column point to handle data */
+	info->buf_start		= 0;
+	info->buf_count		= 0;
+	info->data_buff_pos	= 0;
+	info->oob_buff_pos	= 0;
+	info->step_chunk_size   = 0;
+	info->step_spare_size   = 0;
+	info->cur_chunk         = 0;
+	info->use_ecc		= 0;
+	info->use_spare		= 1;
+	info->retcode		= ERR_NONE;
+	info->ecc_err_cnt	= 0;
+	info->ndcb3		= 0;
+	info->need_wait		= 0;
+
+	switch (command) {
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+	case NAND_CMD_PAGEPROG:
+		info->use_ecc = 1;
+		break;
+	case NAND_CMD_PARAM:
+		info->use_spare = 0;
+		break;
+	default:
+		info->ndcb1 = 0;
+		info->ndcb2 = 0;
+		break;
+	}
+
+	/*
+	 * If we are about to issue a read command, or about to set
+	 * the write address, then clean the data buffer.
+	 */
+	if (command == NAND_CMD_READ0 ||
+	    command == NAND_CMD_READOOB ||
+	    command == NAND_CMD_SEQIN) {
+
+		info->buf_count = mtd->writesize + mtd->oobsize;
+		memset(info->data_buff, 0xFF, info->buf_count);
+	}
+
+}
+
+static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
+		int ext_cmd_type, uint16_t column, int page_addr)
+{
+	int addr_cycle, exec_cmd;
+	struct pxa3xx_nand_host *host;
+	struct mtd_info *mtd;
+
+	host = info->host[info->cs];
+	mtd = nand_to_mtd(&host->chip);
+	addr_cycle = 0;
+	exec_cmd = 1;
+
+	if (info->cs != 0)
+		info->ndcb0 = NDCB0_CSEL;
+	else
+		info->ndcb0 = 0;
+
+	if (command == NAND_CMD_SEQIN)
+		exec_cmd = 0;
+
+	addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
+				    + host->col_addr_cycles);
+
+	switch (command) {
+	case NAND_CMD_READOOB:
+	case NAND_CMD_READ0:
+		info->buf_start = column;
+		info->ndcb0 |= NDCB0_CMD_TYPE(0)
+				| addr_cycle
+				| NAND_CMD_READ0;
+
+		if (command == NAND_CMD_READOOB)
+			info->buf_start += mtd->writesize;
+
+		if (info->cur_chunk < info->nfullchunks) {
+			info->step_chunk_size = info->chunk_size;
+			info->step_spare_size = info->spare_size;
+		} else {
+			info->step_chunk_size = info->last_chunk_size;
+			info->step_spare_size = info->last_spare_size;
+		}
+
+		/*
+		 * Multiple page read needs an 'extended command type' field,
+		 * which is either naked-read or last-read according to the
+		 * state.
+		 */
+		if (mtd->writesize == PAGE_CHUNK_SIZE) {
+			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
+		} else if (mtd->writesize > PAGE_CHUNK_SIZE) {
+			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
+					| NDCB0_LEN_OVRD
+					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+			info->ndcb3 = info->step_chunk_size +
+				info->step_spare_size;
+		}
+
+		set_command_address(info, mtd->writesize, column, page_addr);
+		break;
+
+	case NAND_CMD_SEQIN:
+
+		info->buf_start = column;
+		set_command_address(info, mtd->writesize, 0, page_addr);
+
+		/*
+		 * Multiple page programming needs to execute the initial
+		 * SEQIN command that sets the page address.
+		 */
+		if (mtd->writesize > PAGE_CHUNK_SIZE) {
+			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+				| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
+				| addr_cycle
+				| command;
+			exec_cmd = 1;
+		}
+		break;
+
+	case NAND_CMD_PAGEPROG:
+		if (is_buf_blank(info->data_buff,
+					(mtd->writesize + mtd->oobsize))) {
+			exec_cmd = 0;
+			break;
+		}
+
+		if (info->cur_chunk < info->nfullchunks) {
+			info->step_chunk_size = info->chunk_size;
+			info->step_spare_size = info->spare_size;
+		} else {
+			info->step_chunk_size = info->last_chunk_size;
+			info->step_spare_size = info->last_spare_size;
+		}
+
+		/* Second command setting for large pages */
+		if (mtd->writesize > PAGE_CHUNK_SIZE) {
+			/*
+			 * Multiple page write uses the 'extended command'
+			 * field. This can be used to issue a command dispatch
+			 * or a naked-write depending on the current stage.
+			 */
+			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+					| NDCB0_LEN_OVRD
+					| NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+			info->ndcb3 = info->step_chunk_size +
+				      info->step_spare_size;
+
+			/*
+			 * This is the command dispatch that completes a chunked
+			 * page program operation.
+			 */
+			if (info->cur_chunk == info->ntotalchunks) {
+				info->ndcb0 = NDCB0_CMD_TYPE(0x1)
+					| NDCB0_EXT_CMD_TYPE(ext_cmd_type)
+					| command;
+				info->ndcb1 = 0;
+				info->ndcb2 = 0;
+				info->ndcb3 = 0;
+			}
+		} else {
+			info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+					| NDCB0_AUTO_RS
+					| NDCB0_ST_ROW_EN
+					| NDCB0_DBC
+					| (NAND_CMD_PAGEPROG << 8)
+					| NAND_CMD_SEQIN
+					| addr_cycle;
+		}
+		break;
+
+	case NAND_CMD_PARAM:
+		info->buf_count = INIT_BUFFER_SIZE;
+		info->ndcb0 |= NDCB0_CMD_TYPE(0)
+				| NDCB0_ADDR_CYC(1)
+				| NDCB0_LEN_OVRD
+				| command;
+		info->ndcb1 = (column & 0xFF);
+		info->ndcb3 = INIT_BUFFER_SIZE;
+		info->step_chunk_size = INIT_BUFFER_SIZE;
+		break;
+
+	case NAND_CMD_READID:
+		info->buf_count = READ_ID_BYTES;
+		info->ndcb0 |= NDCB0_CMD_TYPE(3)
+				| NDCB0_ADDR_CYC(1)
+				| command;
+		info->ndcb1 = (column & 0xFF);
+
+		info->step_chunk_size = 8;
+		break;
+	case NAND_CMD_STATUS:
+		info->buf_count = 1;
+		info->ndcb0 |= NDCB0_CMD_TYPE(4)
+				| NDCB0_ADDR_CYC(1)
+				| command;
+
+		info->step_chunk_size = 8;
+		break;
+
+	case NAND_CMD_ERASE1:
+		info->ndcb0 |= NDCB0_CMD_TYPE(2)
+				| NDCB0_AUTO_RS
+				| NDCB0_ADDR_CYC(3)
+				| NDCB0_DBC
+				| (NAND_CMD_ERASE2 << 8)
+				| NAND_CMD_ERASE1;
+		info->ndcb1 = page_addr;
+		info->ndcb2 = 0;
+
+		break;
+	case NAND_CMD_RESET:
+		info->ndcb0 |= NDCB0_CMD_TYPE(5)
+				| command;
+
+		break;
+
+	case NAND_CMD_ERASE2:
+		exec_cmd = 0;
+		break;
+
+	default:
+		exec_cmd = 0;
+		dev_err(&info->pdev->dev, "non-supported command %x\n",
+				command);
+		break;
+	}
+
+	return exec_cmd;
+}
+
+static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+			 int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int exec_cmd;
+
+	/*
+	 * if this is a x16 device ,then convert the input
+	 * "byte" address into a "word" address appropriate
+	 * for indexing a word-oriented device
+	 */
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		column /= 2;
+
+	/*
+	 * There may be different NAND chip hooked to
+	 * different chip select, so check whether
+	 * chip select has been changed, if yes, reset the timing
+	 */
+	if (info->cs != host->cs) {
+		info->cs = host->cs;
+		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
+	}
+
+	prepare_start_command(info, command);
+
+	info->state = STATE_PREPARED;
+	exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
+
+	if (exec_cmd) {
+		init_completion(&info->cmd_complete);
+		init_completion(&info->dev_ready);
+		info->need_wait = 1;
+		pxa3xx_nand_start(info);
+
+		if (!wait_for_completion_timeout(&info->cmd_complete,
+		    CHIP_DELAY_TIMEOUT)) {
+			dev_err(&info->pdev->dev, "Wait time out!!!\n");
+			/* Stop State Machine for next command cycle */
+			pxa3xx_nand_stop(info);
+		}
+	}
+	info->state = STATE_IDLE;
+}
+
+static void nand_cmdfunc_extended(struct mtd_info *mtd,
+				  const unsigned command,
+				  int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int exec_cmd, ext_cmd_type;
+
+	/*
+	 * if this is a x16 device then convert the input
+	 * "byte" address into a "word" address appropriate
+	 * for indexing a word-oriented device
+	 */
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		column /= 2;
+
+	/*
+	 * There may be different NAND chip hooked to
+	 * different chip select, so check whether
+	 * chip select has been changed, if yes, reset the timing
+	 */
+	if (info->cs != host->cs) {
+		info->cs = host->cs;
+		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
+	}
+
+	/* Select the extended command for the first command */
+	switch (command) {
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+		ext_cmd_type = EXT_CMD_TYPE_MONO;
+		break;
+	case NAND_CMD_SEQIN:
+		ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
+		break;
+	case NAND_CMD_PAGEPROG:
+		ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
+		break;
+	default:
+		ext_cmd_type = 0;
+		break;
+	}
+
+	prepare_start_command(info, command);
+
+	/*
+	 * Prepare the "is ready" completion before starting a command
+	 * transaction sequence. If the command is not executed the
+	 * completion will be completed, see below.
+	 *
+	 * We can do that inside the loop because the command variable
+	 * is invariant and thus so is the exec_cmd.
+	 */
+	info->need_wait = 1;
+	init_completion(&info->dev_ready);
+	do {
+		info->state = STATE_PREPARED;
+
+		exec_cmd = prepare_set_command(info, command, ext_cmd_type,
+					       column, page_addr);
+		if (!exec_cmd) {
+			info->need_wait = 0;
+			complete(&info->dev_ready);
+			break;
+		}
+
+		init_completion(&info->cmd_complete);
+		pxa3xx_nand_start(info);
+
+		if (!wait_for_completion_timeout(&info->cmd_complete,
+		    CHIP_DELAY_TIMEOUT)) {
+			dev_err(&info->pdev->dev, "Wait time out!!!\n");
+			/* Stop State Machine for next command cycle */
+			pxa3xx_nand_stop(info);
+			break;
+		}
+
+		/* Only a few commands need several steps */
+		if (command != NAND_CMD_PAGEPROG &&
+		    command != NAND_CMD_READ0    &&
+		    command != NAND_CMD_READOOB)
+			break;
+
+		info->cur_chunk++;
+
+		/* Check if the sequence is complete */
+		if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
+			break;
+
+		/*
+		 * After a splitted program command sequence has issued
+		 * the command dispatch, the command sequence is complete.
+		 */
+		if (info->cur_chunk == (info->ntotalchunks + 1) &&
+		    command == NAND_CMD_PAGEPROG &&
+		    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
+			break;
+
+		if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
+			/* Last read: issue a 'last naked read' */
+			if (info->cur_chunk == info->ntotalchunks - 1)
+				ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
+			else
+				ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
+
+		/*
+		 * If a splitted program command has no more data to transfer,
+		 * the command dispatch must be issued to complete.
+		 */
+		} else if (command == NAND_CMD_PAGEPROG &&
+			   info->cur_chunk == info->ntotalchunks) {
+				ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
+		}
+	} while (1);
+
+	info->state = STATE_IDLE;
+}
+
+static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
+		struct nand_chip *chip, const uint8_t *buf, int oob_required,
+		int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
+		struct nand_chip *chip, uint8_t *buf, int oob_required,
+		int page)
+{
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (info->retcode == ERR_CORERR && info->use_ecc) {
+		mtd->ecc_stats.corrected += info->ecc_err_cnt;
+
+	} else if (info->retcode == ERR_UNCORERR) {
+		/*
+		 * for blank page (all 0xff), HW will calculate its ECC as
+		 * 0, which is different from the ECC information within
+		 * OOB, ignore such uncorrectable errors
+		 */
+		if (is_buf_blank(buf, mtd->writesize))
+			info->retcode = ERR_NONE;
+		else
+			mtd->ecc_stats.failed++;
+	}
+
+	return info->max_bitflips;
+}
+
+static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	char retval = 0xFF;
+
+	if (info->buf_start < info->buf_count)
+		/* Has just send a new command? */
+		retval = info->data_buff[info->buf_start++];
+
+	return retval;
+}
+
+static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	u16 retval = 0xFFFF;
+
+	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
+		retval = *((u16 *)(info->data_buff+info->buf_start));
+		info->buf_start += 2;
+	}
+	return retval;
+}
+
+static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+	memcpy(buf, info->data_buff + info->buf_start, real_len);
+	info->buf_start += real_len;
+}
+
+static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+	memcpy(info->data_buff + info->buf_start, buf, real_len);
+	info->buf_start += real_len;
+}
+
+static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	return;
+}
+
+static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+
+	if (info->need_wait) {
+		info->need_wait = 0;
+		if (!wait_for_completion_timeout(&info->dev_ready,
+		    CHIP_DELAY_TIMEOUT)) {
+			dev_err(&info->pdev->dev, "Ready time out!!!\n");
+			return NAND_STATUS_FAIL;
+		}
+	}
+
+	/* pxa3xx_nand_send_command has waited for command complete */
+	if (this->state == FL_WRITING || this->state == FL_ERASING) {
+		if (info->retcode == ERR_NONE)
+			return 0;
+		else
+			return NAND_STATUS_FAIL;
+	}
+
+	return NAND_STATUS_READY;
+}
+
+static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_host *host = info->host[info->cs];
+	struct platform_device *pdev = info->pdev;
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	const struct nand_sdr_timings *timings;
+
+	/* Configure default flash values */
+	info->chunk_size = PAGE_CHUNK_SIZE;
+	info->reg_ndcr = 0x0; /* enable all interrupts */
+	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
+	info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
+	info->reg_ndcr |= NDCR_SPARE_EN;
+
+	/* use the common timing to make a try */
+	timings = onfi_async_timing_mode_to_sdr_timings(0);
+	if (IS_ERR(timings))
+		return PTR_ERR(timings);
+
+	pxa3xx_nand_set_sdr_timing(host, timings);
+	return 0;
+}
+
+static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info)
+{
+	struct pxa3xx_nand_host *host = info->host[info->cs];
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
+	info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0;
+	info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
+}
+
+static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
+{
+	struct platform_device *pdev = info->pdev;
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	uint32_t ndcr = nand_readl(info, NDCR);
+
+	/* Set an initial chunk size */
+	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
+	info->reg_ndcr = ndcr &
+		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
+	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
+	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
+	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
+}
+
+static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+{
+	struct platform_device *pdev = info->pdev;
+	struct dma_slave_config	config;
+	dma_cap_mask_t mask;
+	struct pxad_param param;
+	int ret;
+
+	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+	if (info->data_buff == NULL)
+		return -ENOMEM;
+	if (use_dma == 0)
+		return 0;
+
+	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	sg_init_one(&info->sg, info->data_buff, info->buf_size);
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	param.prio = PXAD_PRIO_LOWEST;
+	param.drcmr = info->drcmr_dat;
+	info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
+							  &param, &pdev->dev,
+							  "data");
+	if (!info->dma_chan) {
+		dev_err(&pdev->dev, "unable to request data dma channel\n");
+		return -ENODEV;
+	}
+
+	memset(&config, 0, sizeof(config));
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.src_addr = info->mmio_phys + NDDB;
+	config.dst_addr = info->mmio_phys + NDDB;
+	config.src_maxburst = 32;
+	config.dst_maxburst = 32;
+	ret = dmaengine_slave_config(info->dma_chan, &config);
+	if (ret < 0) {
+		dev_err(&info->pdev->dev,
+			"dma channel configuration failed: %d\n",
+			ret);
+		return ret;
+	}
+
+	/*
+	 * Now that DMA buffers are allocated we turn on
+	 * DMA proper for I/O operations.
+	 */
+	info->use_dma = 1;
+	return 0;
+}
+
+static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+{
+	if (info->use_dma) {
+		dmaengine_terminate_all(info->dma_chan);
+		dma_release_channel(info->dma_chan);
+	}
+	kfree(info->data_buff);
+}
+
+static int pxa_ecc_init(struct pxa3xx_nand_info *info,
+			struct mtd_info *mtd,
+			int strength, int ecc_stepsize, int page_size)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
+		info->nfullchunks = 1;
+		info->ntotalchunks = 1;
+		info->chunk_size = 2048;
+		info->spare_size = 40;
+		info->ecc_size = 24;
+		ecc->mode = NAND_ECC_HW;
+		ecc->size = 512;
+		ecc->strength = 1;
+
+	} else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
+		info->nfullchunks = 1;
+		info->ntotalchunks = 1;
+		info->chunk_size = 512;
+		info->spare_size = 8;
+		info->ecc_size = 8;
+		ecc->mode = NAND_ECC_HW;
+		ecc->size = 512;
+		ecc->strength = 1;
+
+	/*
+	 * Required ECC: 4-bit correction per 512 bytes
+	 * Select: 16-bit correction per 2048 bytes
+	 */
+	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
+		info->ecc_bch = 1;
+		info->nfullchunks = 1;
+		info->ntotalchunks = 1;
+		info->chunk_size = 2048;
+		info->spare_size = 32;
+		info->ecc_size = 32;
+		ecc->mode = NAND_ECC_HW;
+		ecc->size = info->chunk_size;
+		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
+		ecc->strength = 16;
+
+	} else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
+		info->ecc_bch = 1;
+		info->nfullchunks = 2;
+		info->ntotalchunks = 2;
+		info->chunk_size = 2048;
+		info->spare_size = 32;
+		info->ecc_size = 32;
+		ecc->mode = NAND_ECC_HW;
+		ecc->size = info->chunk_size;
+		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
+		ecc->strength = 16;
+
+	/*
+	 * Required ECC: 8-bit correction per 512 bytes
+	 * Select: 16-bit correction per 1024 bytes
+	 */
+	} else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
+		info->ecc_bch = 1;
+		info->nfullchunks = 4;
+		info->ntotalchunks = 5;
+		info->chunk_size = 1024;
+		info->spare_size = 0;
+		info->last_chunk_size = 0;
+		info->last_spare_size = 64;
+		info->ecc_size = 32;
+		ecc->mode = NAND_ECC_HW;
+		ecc->size = info->chunk_size;
+		mtd_set_ooblayout(mtd, &pxa3xx_ooblayout_ops);
+		ecc->strength = 16;
+	} else {
+		dev_err(&info->pdev->dev,
+			"ECC strength %d at page size %d is not supported\n",
+			strength, page_size);
+		return -ENODEV;
+	}
+
+	dev_info(&info->pdev->dev, "ECC strength %d, ECC step size %d\n",
+		 ecc->strength, ecc->size);
+	return 0;
+}
+
+static int pxa3xx_nand_scan(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
+	struct pxa3xx_nand_info *info = host->info_data;
+	struct platform_device *pdev = info->pdev;
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	int ret;
+	uint16_t ecc_strength, ecc_step;
+
+	if (pdata->keep_config) {
+		pxa3xx_nand_detect_config(info);
+	} else {
+		ret = pxa3xx_nand_config_ident(info);
+		if (ret)
+			return ret;
+	}
+
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	/* Device detection must be done with ECC disabled */
+	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
+	    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
+		nand_writel(info, NDECCCTRL, 0x0);
+
+	if (pdata->flash_bbt)
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+	chip->ecc.strength = pdata->ecc_strength;
+	chip->ecc.size = pdata->ecc_step_size;
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		return ret;
+
+	if (!pdata->keep_config) {
+		ret = pxa3xx_nand_init(host);
+		if (ret) {
+			dev_err(&info->pdev->dev, "Failed to init nand: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+		/*
+		 * We'll use a bad block table stored in-flash and don't
+		 * allow writing the bad block marker to the flash.
+		 */
+		chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+		chip->bbt_td = &bbt_main_descr;
+		chip->bbt_md = &bbt_mirror_descr;
+	}
+
+	/*
+	 * If the page size is bigger than the FIFO size, let's check
+	 * we are given the right variant and then switch to the extended
+	 * (aka splitted) command handling,
+	 */
+	if (mtd->writesize > PAGE_CHUNK_SIZE) {
+		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
+		    info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) {
+			chip->cmdfunc = nand_cmdfunc_extended;
+		} else {
+			dev_err(&info->pdev->dev,
+				"unsupported page size on this variant\n");
+			return -ENODEV;
+		}
+	}
+
+	ecc_strength = chip->ecc.strength;
+	ecc_step = chip->ecc.size;
+	if (!ecc_strength || !ecc_step) {
+		ecc_strength = chip->ecc_strength_ds;
+		ecc_step = chip->ecc_step_ds;
+	}
+
+	/* Set default ECC strength requirements on non-ONFI devices */
+	if (ecc_strength < 1 && ecc_step < 1) {
+		ecc_strength = 1;
+		ecc_step = 512;
+	}
+
+	ret = pxa_ecc_init(info, mtd, ecc_strength,
+			   ecc_step, mtd->writesize);
+	if (ret)
+		return ret;
+
+	/* calculate addressing information */
+	if (mtd->writesize >= 2048)
+		host->col_addr_cycles = 2;
+	else
+		host->col_addr_cycles = 1;
+
+	/* release the initial buffer */
+	kfree(info->data_buff);
+
+	/* allocate the real data + oob buffer */
+	info->buf_size = mtd->writesize + mtd->oobsize;
+	ret = pxa3xx_nand_init_buff(info);
+	if (ret)
+		return ret;
+	info->oob_buff = info->data_buff + mtd->writesize;
+
+	if ((mtd->size >> chip->page_shift) > 65536)
+		host->row_addr_cycles = 3;
+	else
+		host->row_addr_cycles = 2;
+
+	if (!pdata->keep_config)
+		pxa3xx_nand_config_tail(info);
+
+	return nand_scan_tail(mtd);
+}
+
+static int alloc_nand_resource(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct pxa3xx_nand_platform_data *pdata;
+	struct pxa3xx_nand_info *info;
+	struct pxa3xx_nand_host *host;
+	struct nand_chip *chip = NULL;
+	struct mtd_info *mtd;
+	struct resource *r;
+	int ret, irq, cs;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (pdata->num_cs <= 0) {
+		dev_err(&pdev->dev, "invalid number of chip selects\n");
+		return -ENODEV;
+	}
+
+	info = devm_kzalloc(&pdev->dev,
+			    sizeof(*info) + sizeof(*host) * pdata->num_cs,
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pdev = pdev;
+	info->variant = pxa3xx_nand_get_variant(pdev);
+	for (cs = 0; cs < pdata->num_cs; cs++) {
+		host = (void *)&info[1] + sizeof(*host) * cs;
+		chip = &host->chip;
+		nand_set_controller_data(chip, host);
+		mtd = nand_to_mtd(chip);
+		info->host[cs] = host;
+		host->cs = cs;
+		host->info_data = info;
+		mtd->dev.parent = &pdev->dev;
+		/* FIXME: all chips use the same device tree partitions */
+		nand_set_flash_node(chip, np);
+
+		nand_set_controller_data(chip, host);
+		chip->ecc.read_page	= pxa3xx_nand_read_page_hwecc;
+		chip->ecc.write_page	= pxa3xx_nand_write_page_hwecc;
+		chip->controller        = &info->controller;
+		chip->waitfunc		= pxa3xx_nand_waitfunc;
+		chip->select_chip	= pxa3xx_nand_select_chip;
+		chip->read_word		= pxa3xx_nand_read_word;
+		chip->read_byte		= pxa3xx_nand_read_byte;
+		chip->read_buf		= pxa3xx_nand_read_buf;
+		chip->write_buf		= pxa3xx_nand_write_buf;
+		chip->options		|= NAND_NO_SUBPAGE_WRITE;
+		chip->cmdfunc		= nand_cmdfunc;
+		chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+		chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+	}
+
+	nand_hw_control_init(chip->controller);
+	info->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(info->clk)) {
+		ret = PTR_ERR(info->clk);
+		dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
+		return ret;
+	}
+	ret = clk_prepare_enable(info->clk);
+	if (ret < 0)
+		return ret;
+
+	if (!np && use_dma) {
+		r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+		if (r == NULL) {
+			dev_err(&pdev->dev,
+				"no resource defined for data DMA\n");
+			ret = -ENXIO;
+			goto fail_disable_clk;
+		}
+		info->drcmr_dat = r->start;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no IRQ resource defined\n");
+		ret = -ENXIO;
+		goto fail_disable_clk;
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(info->mmio_base)) {
+		ret = PTR_ERR(info->mmio_base);
+		dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
+		goto fail_disable_clk;
+	}
+	info->mmio_phys = r->start;
+
+	/* Allocate a buffer to allow flash detection */
+	info->buf_size = INIT_BUFFER_SIZE;
+	info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+	if (info->data_buff == NULL) {
+		ret = -ENOMEM;
+		goto fail_disable_clk;
+	}
+
+	/* initialize all interrupts to be disabled */
+	disable_int(info, NDSR_MASK);
+
+	ret = request_threaded_irq(irq, pxa3xx_nand_irq,
+				   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
+				   pdev->name, info);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
+		goto fail_free_buf;
+	}
+
+	platform_set_drvdata(pdev, info);
+
+	return 0;
+
+fail_free_buf:
+	free_irq(irq, info);
+	kfree(info->data_buff);
+fail_disable_clk:
+	clk_disable_unprepare(info->clk);
+	return ret;
+}
+
+static int pxa3xx_nand_remove(struct platform_device *pdev)
+{
+	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
+	struct pxa3xx_nand_platform_data *pdata;
+	int irq, cs;
+
+	if (!info)
+		return 0;
+
+	pdata = dev_get_platdata(&pdev->dev);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq >= 0)
+		free_irq(irq, info);
+	pxa3xx_nand_free_buff(info);
+
+	/*
+	 * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
+	 * In order to prevent a lockup of the system bus, the DFI bus
+	 * arbitration is granted to SMC upon driver removal. This is done by
+	 * setting the x_ARB_CNTL bit, which also prevents the NAND to have
+	 * access to the bus anymore.
+	 */
+	nand_writel(info, NDCR,
+		    (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
+		    NFCV1_NDCR_ARB_CNTL);
+	clk_disable_unprepare(info->clk);
+
+	for (cs = 0; cs < pdata->num_cs; cs++)
+		nand_release(nand_to_mtd(&info->host[cs]->chip));
+	return 0;
+}
+
+static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
+{
+	struct pxa3xx_nand_platform_data *pdata;
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+
+	if (!of_id)
+		return 0;
+
+	/*
+	 * Some SoCs like A7k/A8k need to enable manually the NAND
+	 * controller to avoid being bootloader dependent. This is done
+	 * through the use of a single bit in the System Functions registers.
+	 */
+	if (pxa3xx_nand_get_variant(pdev) == PXA3XX_NAND_VARIANT_ARMADA_8K) {
+		struct regmap *sysctrl_base = syscon_regmap_lookup_by_phandle(
+			pdev->dev.of_node, "marvell,system-controller");
+		u32 reg;
+
+		if (IS_ERR(sysctrl_base))
+			return PTR_ERR(sysctrl_base);
+
+		regmap_read(sysctrl_base, GENCONF_SOC_DEVICE_MUX, &reg);
+		reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN;
+		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+	}
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
+		pdata->enable_arbiter = 1;
+	if (of_get_property(np, "marvell,nand-keep-config", NULL))
+		pdata->keep_config = 1;
+	of_property_read_u32(np, "num-cs", &pdata->num_cs);
+
+	pdev->dev.platform_data = pdata;
+
+	return 0;
+}
+
+static int pxa3xx_nand_probe(struct platform_device *pdev)
+{
+	struct pxa3xx_nand_platform_data *pdata;
+	struct pxa3xx_nand_info *info;
+	int ret, cs, probe_success, dma_available;
+
+	dma_available = IS_ENABLED(CONFIG_ARM) &&
+		(IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
+	if (use_dma && !dma_available) {
+		use_dma = 0;
+		dev_warn(&pdev->dev,
+			 "This platform can't do DMA on this device\n");
+	}
+
+	ret = pxa3xx_nand_probe_dt(pdev);
+	if (ret)
+		return ret;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -ENODEV;
+	}
+
+	ret = alloc_nand_resource(pdev);
+	if (ret)
+		return ret;
+
+	info = platform_get_drvdata(pdev);
+	probe_success = 0;
+	for (cs = 0; cs < pdata->num_cs; cs++) {
+		struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip);
+
+		/*
+		 * The mtd name matches the one used in 'mtdparts' kernel
+		 * parameter. This name cannot be changed or otherwise
+		 * user's mtd partitions configuration would get broken.
+		 */
+		mtd->name = "pxa3xx_nand-0";
+		info->cs = cs;
+		ret = pxa3xx_nand_scan(mtd);
+		if (ret) {
+			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
+				cs);
+			continue;
+		}
+
+		ret = mtd_device_register(mtd, pdata->parts[cs],
+					  pdata->nr_parts[cs]);
+		if (!ret)
+			probe_success = 1;
+	}
+
+	if (!probe_success) {
+		pxa3xx_nand_remove(pdev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa3xx_nand_suspend(struct device *dev)
+{
+	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
+
+	if (info->state) {
+		dev_err(dev, "driver busy, state = %d\n", info->state);
+		return -EAGAIN;
+	}
+
+	clk_disable(info->clk);
+	return 0;
+}
+
+static int pxa3xx_nand_resume(struct device *dev)
+{
+	struct pxa3xx_nand_info *info = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_enable(info->clk);
+	if (ret < 0)
+		return ret;
+
+	/* We don't want to handle interrupt without calling mtd routine */
+	disable_int(info, NDCR_INT_MASK);
+
+	/*
+	 * Directly set the chip select to a invalid value,
+	 * then the driver would reset the timing according
+	 * to current chip select at the beginning of cmdfunc
+	 */
+	info->cs = 0xff;
+
+	/*
+	 * As the spec says, the NDSR would be updated to 0x1800 when
+	 * doing the nand_clk disable/enable.
+	 * To prevent it damaging state machine of the driver, clear
+	 * all status before resume
+	 */
+	nand_writel(info, NDSR, NDSR_MASK);
+
+	return 0;
+}
+#else
+#define pxa3xx_nand_suspend	NULL
+#define pxa3xx_nand_resume	NULL
+#endif
+
+static const struct dev_pm_ops pxa3xx_nand_pm_ops = {
+	.suspend	= pxa3xx_nand_suspend,
+	.resume		= pxa3xx_nand_resume,
+};
+
+static struct platform_driver pxa3xx_nand_driver = {
+	.driver = {
+		.name	= "pxa3xx-nand",
+		.of_match_table = pxa3xx_nand_dt_ids,
+		.pm	= &pxa3xx_nand_pm_ops,
+	},
+	.probe		= pxa3xx_nand_probe,
+	.remove		= pxa3xx_nand_remove,
+};
+
+module_platform_driver(pxa3xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PXA3xx NAND controller driver");
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
new file mode 100644
index 000000000000..563b759ffca6
--- /dev/null
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -0,0 +1,2921 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/clk.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/delay.h>
+#include <linux/dma/qcom_bam_dma.h>
+#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
+
+/* NANDc reg offsets */
+#define	NAND_FLASH_CMD			0x00
+#define	NAND_ADDR0			0x04
+#define	NAND_ADDR1			0x08
+#define	NAND_FLASH_CHIP_SELECT		0x0c
+#define	NAND_EXEC_CMD			0x10
+#define	NAND_FLASH_STATUS		0x14
+#define	NAND_BUFFER_STATUS		0x18
+#define	NAND_DEV0_CFG0			0x20
+#define	NAND_DEV0_CFG1			0x24
+#define	NAND_DEV0_ECC_CFG		0x28
+#define	NAND_DEV1_ECC_CFG		0x2c
+#define	NAND_DEV1_CFG0			0x30
+#define	NAND_DEV1_CFG1			0x34
+#define	NAND_READ_ID			0x40
+#define	NAND_READ_STATUS		0x44
+#define	NAND_DEV_CMD0			0xa0
+#define	NAND_DEV_CMD1			0xa4
+#define	NAND_DEV_CMD2			0xa8
+#define	NAND_DEV_CMD_VLD		0xac
+#define	SFLASHC_BURST_CFG		0xe0
+#define	NAND_ERASED_CW_DETECT_CFG	0xe8
+#define	NAND_ERASED_CW_DETECT_STATUS	0xec
+#define	NAND_EBI2_ECC_BUF_CFG		0xf0
+#define	FLASH_BUF_ACC			0x100
+
+#define	NAND_CTRL			0xf00
+#define	NAND_VERSION			0xf08
+#define	NAND_READ_LOCATION_0		0xf20
+#define	NAND_READ_LOCATION_1		0xf24
+#define	NAND_READ_LOCATION_2		0xf28
+#define	NAND_READ_LOCATION_3		0xf2c
+
+/* dummy register offsets, used by write_reg_dma */
+#define	NAND_DEV_CMD1_RESTORE		0xdead
+#define	NAND_DEV_CMD_VLD_RESTORE	0xbeef
+
+/* NAND_FLASH_CMD bits */
+#define	PAGE_ACC			BIT(4)
+#define	LAST_PAGE			BIT(5)
+
+/* NAND_FLASH_CHIP_SELECT bits */
+#define	NAND_DEV_SEL			0
+#define	DM_EN				BIT(2)
+
+/* NAND_FLASH_STATUS bits */
+#define	FS_OP_ERR			BIT(4)
+#define	FS_READY_BSY_N			BIT(5)
+#define	FS_MPU_ERR			BIT(8)
+#define	FS_DEVICE_STS_ERR		BIT(16)
+#define	FS_DEVICE_WP			BIT(23)
+
+/* NAND_BUFFER_STATUS bits */
+#define	BS_UNCORRECTABLE_BIT		BIT(8)
+#define	BS_CORRECTABLE_ERR_MSK		0x1f
+
+/* NAND_DEVn_CFG0 bits */
+#define	DISABLE_STATUS_AFTER_WRITE	4
+#define	CW_PER_PAGE			6
+#define	UD_SIZE_BYTES			9
+#define	ECC_PARITY_SIZE_BYTES_RS	19
+#define	SPARE_SIZE_BYTES		23
+#define	NUM_ADDR_CYCLES			27
+#define	STATUS_BFR_READ			30
+#define	SET_RD_MODE_AFTER_STATUS	31
+
+/* NAND_DEVn_CFG0 bits */
+#define	DEV0_CFG1_ECC_DISABLE		0
+#define	WIDE_FLASH			1
+#define	NAND_RECOVERY_CYCLES		2
+#define	CS_ACTIVE_BSY			5
+#define	BAD_BLOCK_BYTE_NUM		6
+#define	BAD_BLOCK_IN_SPARE_AREA		16
+#define	WR_RD_BSY_GAP			17
+#define	ENABLE_BCH_ECC			27
+
+/* NAND_DEV0_ECC_CFG bits */
+#define	ECC_CFG_ECC_DISABLE		0
+#define	ECC_SW_RESET			1
+#define	ECC_MODE			4
+#define	ECC_PARITY_SIZE_BYTES_BCH	8
+#define	ECC_NUM_DATA_BYTES		16
+#define	ECC_FORCE_CLK_OPEN		30
+
+/* NAND_DEV_CMD1 bits */
+#define	READ_ADDR			0
+
+/* NAND_DEV_CMD_VLD bits */
+#define	READ_START_VLD			BIT(0)
+#define	READ_STOP_VLD			BIT(1)
+#define	WRITE_START_VLD			BIT(2)
+#define	ERASE_START_VLD			BIT(3)
+#define	SEQ_READ_START_VLD		BIT(4)
+
+/* NAND_EBI2_ECC_BUF_CFG bits */
+#define	NUM_STEPS			0
+
+/* NAND_ERASED_CW_DETECT_CFG bits */
+#define	ERASED_CW_ECC_MASK		1
+#define	AUTO_DETECT_RES			0
+#define	MASK_ECC			(1 << ERASED_CW_ECC_MASK)
+#define	RESET_ERASED_DET		(1 << AUTO_DETECT_RES)
+#define	ACTIVE_ERASED_DET		(0 << AUTO_DETECT_RES)
+#define	CLR_ERASED_PAGE_DET		(RESET_ERASED_DET | MASK_ECC)
+#define	SET_ERASED_PAGE_DET		(ACTIVE_ERASED_DET | MASK_ECC)
+
+/* NAND_ERASED_CW_DETECT_STATUS bits */
+#define	PAGE_ALL_ERASED			BIT(7)
+#define	CODEWORD_ALL_ERASED		BIT(6)
+#define	PAGE_ERASED			BIT(5)
+#define	CODEWORD_ERASED			BIT(4)
+#define	ERASED_PAGE			(PAGE_ALL_ERASED | PAGE_ERASED)
+#define	ERASED_CW			(CODEWORD_ALL_ERASED | CODEWORD_ERASED)
+
+/* NAND_READ_LOCATION_n bits */
+#define READ_LOCATION_OFFSET		0
+#define READ_LOCATION_SIZE		16
+#define READ_LOCATION_LAST		31
+
+/* Version Mask */
+#define	NAND_VERSION_MAJOR_MASK		0xf0000000
+#define	NAND_VERSION_MAJOR_SHIFT	28
+#define	NAND_VERSION_MINOR_MASK		0x0fff0000
+#define	NAND_VERSION_MINOR_SHIFT	16
+
+/* NAND OP_CMDs */
+#define	PAGE_READ			0x2
+#define	PAGE_READ_WITH_ECC		0x3
+#define	PAGE_READ_WITH_ECC_SPARE	0x4
+#define	PROGRAM_PAGE			0x6
+#define	PAGE_PROGRAM_WITH_ECC		0x7
+#define	PROGRAM_PAGE_SPARE		0x9
+#define	BLOCK_ERASE			0xa
+#define	FETCH_ID			0xb
+#define	RESET_DEVICE			0xd
+
+/* Default Value for NAND_DEV_CMD_VLD */
+#define NAND_DEV_CMD_VLD_VAL		(READ_START_VLD | WRITE_START_VLD | \
+					 ERASE_START_VLD | SEQ_READ_START_VLD)
+
+/* NAND_CTRL bits */
+#define	BAM_MODE_EN			BIT(0)
+
+/*
+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
+ * the driver calls the chunks 'step' or 'codeword' interchangeably
+ */
+#define	NANDC_STEP_SIZE			512
+
+/*
+ * the largest page size we support is 8K, this will have 16 steps/codewords
+ * of 512 bytes each
+ */
+#define	MAX_NUM_STEPS			(SZ_8K / NANDC_STEP_SIZE)
+
+/* we read at most 3 registers per codeword scan */
+#define	MAX_REG_RD			(3 * MAX_NUM_STEPS)
+
+/* ECC modes supported by the controller */
+#define	ECC_NONE	BIT(0)
+#define	ECC_RS_4BIT	BIT(1)
+#define	ECC_BCH_4BIT	BIT(2)
+#define	ECC_BCH_8BIT	BIT(3)
+
+#define nandc_set_read_loc(nandc, reg, offset, size, is_last)	\
+nandc_set_reg(nandc, NAND_READ_LOCATION_##reg,			\
+	      ((offset) << READ_LOCATION_OFFSET) |		\
+	      ((size) << READ_LOCATION_SIZE) |			\
+	      ((is_last) << READ_LOCATION_LAST))
+
+/*
+ * Returns the actual register address for all NAND_DEV_ registers
+ * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
+ */
+#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
+
+/* Returns the NAND register physical address */
+#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
+
+/* Returns the dma address for reg read buffer */
+#define reg_buf_dma_addr(chip, vaddr) \
+	((chip)->reg_read_dma + \
+	((uint8_t *)(vaddr) - (uint8_t *)(chip)->reg_read_buf))
+
+#define QPIC_PER_CW_CMD_ELEMENTS	32
+#define QPIC_PER_CW_CMD_SGL		32
+#define QPIC_PER_CW_DATA_SGL		8
+
+/*
+ * Flags used in DMA descriptor preparation helper functions
+ * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
+ */
+/* Don't set the EOT in current tx BAM sgl */
+#define NAND_BAM_NO_EOT			BIT(0)
+/* Set the NWD flag in current BAM sgl */
+#define NAND_BAM_NWD			BIT(1)
+/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
+#define NAND_BAM_NEXT_SGL		BIT(2)
+/*
+ * Erased codeword status is being used two times in single transfer so this
+ * flag will determine the current value of erased codeword status register
+ */
+#define NAND_ERASED_CW_SET		BIT(4)
+
+/*
+ * This data type corresponds to the BAM transaction which will be used for all
+ * NAND transfers.
+ * @bam_ce - the array of BAM command elements
+ * @cmd_sgl - sgl for NAND BAM command pipe
+ * @data_sgl - sgl for NAND BAM consumer/producer pipe
+ * @bam_ce_pos - the index in bam_ce which is available for next sgl
+ * @bam_ce_start - the index in bam_ce which marks the start position ce
+ *		   for current sgl. It will be used for size calculation
+ *		   for current sgl
+ * @cmd_sgl_pos - current index in command sgl.
+ * @cmd_sgl_start - start index in command sgl.
+ * @tx_sgl_pos - current index in data sgl for tx.
+ * @tx_sgl_start - start index in data sgl for tx.
+ * @rx_sgl_pos - current index in data sgl for rx.
+ * @rx_sgl_start - start index in data sgl for rx.
+ */
+struct bam_transaction {
+	struct bam_cmd_element *bam_ce;
+	struct scatterlist *cmd_sgl;
+	struct scatterlist *data_sgl;
+	u32 bam_ce_pos;
+	u32 bam_ce_start;
+	u32 cmd_sgl_pos;
+	u32 cmd_sgl_start;
+	u32 tx_sgl_pos;
+	u32 tx_sgl_start;
+	u32 rx_sgl_pos;
+	u32 rx_sgl_start;
+};
+
+/*
+ * This data type corresponds to the nand dma descriptor
+ * @list - list for desc_info
+ * @dir - DMA transfer direction
+ * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
+ *	      ADM
+ * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
+ * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
+ * @dma_desc - low level DMA engine descriptor
+ */
+struct desc_info {
+	struct list_head node;
+
+	enum dma_data_direction dir;
+	union {
+		struct scatterlist adm_sgl;
+		struct {
+			struct scatterlist *bam_sgl;
+			int sgl_cnt;
+		};
+	};
+	struct dma_async_tx_descriptor *dma_desc;
+};
+
+/*
+ * holds the current register values that we want to write. acts as a contiguous
+ * chunk of memory which we use to write the controller registers through DMA.
+ */
+struct nandc_regs {
+	__le32 cmd;
+	__le32 addr0;
+	__le32 addr1;
+	__le32 chip_sel;
+	__le32 exec;
+
+	__le32 cfg0;
+	__le32 cfg1;
+	__le32 ecc_bch_cfg;
+
+	__le32 clrflashstatus;
+	__le32 clrreadstatus;
+
+	__le32 cmd1;
+	__le32 vld;
+
+	__le32 orig_cmd1;
+	__le32 orig_vld;
+
+	__le32 ecc_buf_cfg;
+	__le32 read_location0;
+	__le32 read_location1;
+	__le32 read_location2;
+	__le32 read_location3;
+
+	__le32 erased_cw_detect_cfg_clr;
+	__le32 erased_cw_detect_cfg_set;
+};
+
+/*
+ * NAND controller data struct
+ *
+ * @controller:			base controller structure
+ * @host_list:			list containing all the chips attached to the
+ *				controller
+ * @dev:			parent device
+ * @base:			MMIO base
+ * @base_phys:			physical base address of controller registers
+ * @base_dma:			dma base address of controller registers
+ * @core_clk:			controller clock
+ * @aon_clk:			another controller clock
+ *
+ * @chan:			dma channel
+ * @cmd_crci:			ADM DMA CRCI for command flow control
+ * @data_crci:			ADM DMA CRCI for data flow control
+ * @desc_list:			DMA descriptor list (list of desc_infos)
+ *
+ * @data_buffer:		our local DMA buffer for page read/writes,
+ *				used when we can't use the buffer provided
+ *				by upper layers directly
+ * @buf_size/count/start:	markers for chip->read_buf/write_buf functions
+ * @reg_read_buf:		local buffer for reading back registers via DMA
+ * @reg_read_dma:		contains dma address for register read buffer
+ * @reg_read_pos:		marker for data read in reg_read_buf
+ *
+ * @regs:			a contiguous chunk of memory for DMA register
+ *				writes. contains the register values to be
+ *				written to controller
+ * @cmd1/vld:			some fixed controller register values
+ * @props:			properties of current NAND controller,
+ *				initialized via DT match data
+ * @max_cwperpage:		maximum QPIC codewords required. calculated
+ *				from all connected NAND devices pagesize
+ */
+struct qcom_nand_controller {
+	struct nand_hw_control controller;
+	struct list_head host_list;
+
+	struct device *dev;
+
+	void __iomem *base;
+	phys_addr_t base_phys;
+	dma_addr_t base_dma;
+
+	struct clk *core_clk;
+	struct clk *aon_clk;
+
+	union {
+		/* will be used only by QPIC for BAM DMA */
+		struct {
+			struct dma_chan *tx_chan;
+			struct dma_chan *rx_chan;
+			struct dma_chan *cmd_chan;
+		};
+
+		/* will be used only by EBI2 for ADM DMA */
+		struct {
+			struct dma_chan *chan;
+			unsigned int cmd_crci;
+			unsigned int data_crci;
+		};
+	};
+
+	struct list_head desc_list;
+	struct bam_transaction *bam_txn;
+
+	u8		*data_buffer;
+	int		buf_size;
+	int		buf_count;
+	int		buf_start;
+	unsigned int	max_cwperpage;
+
+	__le32 *reg_read_buf;
+	dma_addr_t reg_read_dma;
+	int reg_read_pos;
+
+	struct nandc_regs *regs;
+
+	u32 cmd1, vld;
+	const struct qcom_nandc_props *props;
+};
+
+/*
+ * NAND chip structure
+ *
+ * @chip:			base NAND chip structure
+ * @node:			list node to add itself to host_list in
+ *				qcom_nand_controller
+ *
+ * @cs:				chip select value for this chip
+ * @cw_size:			the number of bytes in a single step/codeword
+ *				of a page, consisting of all data, ecc, spare
+ *				and reserved bytes
+ * @cw_data:			the number of bytes within a codeword protected
+ *				by ECC
+ * @use_ecc:			request the controller to use ECC for the
+ *				upcoming read/write
+ * @bch_enabled:		flag to tell whether BCH ECC mode is used
+ * @ecc_bytes_hw:		ECC bytes used by controller hardware for this
+ *				chip
+ * @status:			value to be returned if NAND_CMD_STATUS command
+ *				is executed
+ * @last_command:		keeps track of last command on this chip. used
+ *				for reading correct status
+ *
+ * @cfg0, cfg1, cfg0_raw..:	NANDc register configurations needed for
+ *				ecc/non-ecc mode for the current nand flash
+ *				device
+ */
+struct qcom_nand_host {
+	struct nand_chip chip;
+	struct list_head node;
+
+	int cs;
+	int cw_size;
+	int cw_data;
+	bool use_ecc;
+	bool bch_enabled;
+	int ecc_bytes_hw;
+	int spare_bytes;
+	int bbm_size;
+	u8 status;
+	int last_command;
+
+	u32 cfg0, cfg1;
+	u32 cfg0_raw, cfg1_raw;
+	u32 ecc_buf_cfg;
+	u32 ecc_bch_cfg;
+	u32 clrflashstatus;
+	u32 clrreadstatus;
+};
+
+/*
+ * This data type corresponds to the NAND controller properties which varies
+ * among different NAND controllers.
+ * @ecc_modes - ecc mode for NAND
+ * @is_bam - whether NAND controller is using BAM
+ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
+ */
+struct qcom_nandc_props {
+	u32 ecc_modes;
+	bool is_bam;
+	u32 dev_cmd_reg_start;
+};
+
+/* Frees the BAM transaction memory */
+static void free_bam_transaction(struct qcom_nand_controller *nandc)
+{
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+
+	devm_kfree(nandc->dev, bam_txn);
+}
+
+/* Allocates and Initializes the BAM transaction */
+static struct bam_transaction *
+alloc_bam_transaction(struct qcom_nand_controller *nandc)
+{
+	struct bam_transaction *bam_txn;
+	size_t bam_txn_size;
+	unsigned int num_cw = nandc->max_cwperpage;
+	void *bam_txn_buf;
+
+	bam_txn_size =
+		sizeof(*bam_txn) + num_cw *
+		((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) +
+		(sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
+		(sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
+
+	bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
+	if (!bam_txn_buf)
+		return NULL;
+
+	bam_txn = bam_txn_buf;
+	bam_txn_buf += sizeof(*bam_txn);
+
+	bam_txn->bam_ce = bam_txn_buf;
+	bam_txn_buf +=
+		sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw;
+
+	bam_txn->cmd_sgl = bam_txn_buf;
+	bam_txn_buf +=
+		sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
+
+	bam_txn->data_sgl = bam_txn_buf;
+
+	return bam_txn;
+}
+
+/* Clears the BAM transaction indexes */
+static void clear_bam_transaction(struct qcom_nand_controller *nandc)
+{
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+
+	if (!nandc->props->is_bam)
+		return;
+
+	bam_txn->bam_ce_pos = 0;
+	bam_txn->bam_ce_start = 0;
+	bam_txn->cmd_sgl_pos = 0;
+	bam_txn->cmd_sgl_start = 0;
+	bam_txn->tx_sgl_pos = 0;
+	bam_txn->tx_sgl_start = 0;
+	bam_txn->rx_sgl_pos = 0;
+	bam_txn->rx_sgl_start = 0;
+
+	sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
+		      QPIC_PER_CW_CMD_SGL);
+	sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
+		      QPIC_PER_CW_DATA_SGL);
+}
+
+static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
+{
+	return container_of(chip, struct qcom_nand_host, chip);
+}
+
+static inline struct qcom_nand_controller *
+get_qcom_nand_controller(struct nand_chip *chip)
+{
+	return container_of(chip->controller, struct qcom_nand_controller,
+			    controller);
+}
+
+static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset)
+{
+	return ioread32(nandc->base + offset);
+}
+
+static inline void nandc_write(struct qcom_nand_controller *nandc, int offset,
+			       u32 val)
+{
+	iowrite32(val, nandc->base + offset);
+}
+
+static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc,
+					  bool is_cpu)
+{
+	if (!nandc->props->is_bam)
+		return;
+
+	if (is_cpu)
+		dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma,
+					MAX_REG_RD *
+					sizeof(*nandc->reg_read_buf),
+					DMA_FROM_DEVICE);
+	else
+		dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma,
+					   MAX_REG_RD *
+					   sizeof(*nandc->reg_read_buf),
+					   DMA_FROM_DEVICE);
+}
+
+static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
+{
+	switch (offset) {
+	case NAND_FLASH_CMD:
+		return &regs->cmd;
+	case NAND_ADDR0:
+		return &regs->addr0;
+	case NAND_ADDR1:
+		return &regs->addr1;
+	case NAND_FLASH_CHIP_SELECT:
+		return &regs->chip_sel;
+	case NAND_EXEC_CMD:
+		return &regs->exec;
+	case NAND_FLASH_STATUS:
+		return &regs->clrflashstatus;
+	case NAND_DEV0_CFG0:
+		return &regs->cfg0;
+	case NAND_DEV0_CFG1:
+		return &regs->cfg1;
+	case NAND_DEV0_ECC_CFG:
+		return &regs->ecc_bch_cfg;
+	case NAND_READ_STATUS:
+		return &regs->clrreadstatus;
+	case NAND_DEV_CMD1:
+		return &regs->cmd1;
+	case NAND_DEV_CMD1_RESTORE:
+		return &regs->orig_cmd1;
+	case NAND_DEV_CMD_VLD:
+		return &regs->vld;
+	case NAND_DEV_CMD_VLD_RESTORE:
+		return &regs->orig_vld;
+	case NAND_EBI2_ECC_BUF_CFG:
+		return &regs->ecc_buf_cfg;
+	case NAND_READ_LOCATION_0:
+		return &regs->read_location0;
+	case NAND_READ_LOCATION_1:
+		return &regs->read_location1;
+	case NAND_READ_LOCATION_2:
+		return &regs->read_location2;
+	case NAND_READ_LOCATION_3:
+		return &regs->read_location3;
+	default:
+		return NULL;
+	}
+}
+
+static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset,
+			  u32 val)
+{
+	struct nandc_regs *regs = nandc->regs;
+	__le32 *reg;
+
+	reg = offset_to_nandc_reg(regs, offset);
+
+	if (reg)
+		*reg = cpu_to_le32(val);
+}
+
+/* helper to configure address register values */
+static void set_address(struct qcom_nand_host *host, u16 column, int page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		column >>= 1;
+
+	nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column);
+	nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff);
+}
+
+/*
+ * update_rw_regs:	set up read/write register values, these will be
+ *			written to the NAND controller registers via DMA
+ *
+ * @num_cw:		number of steps for the read/write operation
+ * @read:		read or write operation
+ */
+static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	u32 cmd, cfg0, cfg1, ecc_bch_cfg;
+
+	if (read) {
+		if (host->use_ecc)
+			cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
+		else
+			cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
+	} else {
+			cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
+	}
+
+	if (host->use_ecc) {
+		cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) |
+				(num_cw - 1) << CW_PER_PAGE;
+
+		cfg1 = host->cfg1;
+		ecc_bch_cfg = host->ecc_bch_cfg;
+	} else {
+		cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+				(num_cw - 1) << CW_PER_PAGE;
+
+		cfg1 = host->cfg1_raw;
+		ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+	}
+
+	nandc_set_reg(nandc, NAND_FLASH_CMD, cmd);
+	nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0);
+	nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1);
+	nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
+	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
+	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
+	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
+	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+	if (read)
+		nandc_set_read_loc(nandc, 0, 0, host->use_ecc ?
+				   host->cw_data : host->cw_size, 1);
+}
+
+/*
+ * Maps the scatter gather list for DMA transfer and forms the DMA descriptor
+ * for BAM. This descriptor will be added in the NAND DMA descriptor queue
+ * which will be submitted to DMA engine.
+ */
+static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
+				  struct dma_chan *chan,
+				  unsigned long flags)
+{
+	struct desc_info *desc;
+	struct scatterlist *sgl;
+	unsigned int sgl_cnt;
+	int ret;
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+	enum dma_transfer_direction dir_eng;
+	struct dma_async_tx_descriptor *dma_desc;
+
+	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	if (chan == nandc->cmd_chan) {
+		sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start];
+		sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start;
+		bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos;
+		dir_eng = DMA_MEM_TO_DEV;
+		desc->dir = DMA_TO_DEVICE;
+	} else if (chan == nandc->tx_chan) {
+		sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start];
+		sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start;
+		bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos;
+		dir_eng = DMA_MEM_TO_DEV;
+		desc->dir = DMA_TO_DEVICE;
+	} else {
+		sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start];
+		sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start;
+		bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos;
+		dir_eng = DMA_DEV_TO_MEM;
+		desc->dir = DMA_FROM_DEVICE;
+	}
+
+	sg_mark_end(sgl + sgl_cnt - 1);
+	ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+	if (ret == 0) {
+		dev_err(nandc->dev, "failure in mapping desc\n");
+		kfree(desc);
+		return -ENOMEM;
+	}
+
+	desc->sgl_cnt = sgl_cnt;
+	desc->bam_sgl = sgl;
+
+	dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng,
+					   flags);
+
+	if (!dma_desc) {
+		dev_err(nandc->dev, "failure in prep desc\n");
+		dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir);
+		kfree(desc);
+		return -EINVAL;
+	}
+
+	desc->dma_desc = dma_desc;
+
+	list_add_tail(&desc->node, &nandc->desc_list);
+
+	return 0;
+}
+
+/*
+ * Prepares the command descriptor for BAM DMA which will be used for NAND
+ * register reads and writes. The command descriptor requires the command
+ * to be formed in command element type so this function uses the command
+ * element from bam transaction ce array and fills the same with required
+ * data. A single SGL can contain multiple command elements so
+ * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
+ * after the current command element.
+ */
+static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+				 int reg_off, const void *vaddr,
+				 int size, unsigned int flags)
+{
+	int bam_ce_size;
+	int i, ret;
+	struct bam_cmd_element *bam_ce_buffer;
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+
+	bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
+
+	/* fill the command desc */
+	for (i = 0; i < size; i++) {
+		if (read)
+			bam_prep_ce(&bam_ce_buffer[i],
+				    nandc_reg_phys(nandc, reg_off + 4 * i),
+				    BAM_READ_COMMAND,
+				    reg_buf_dma_addr(nandc,
+						     (__le32 *)vaddr + i));
+		else
+			bam_prep_ce_le32(&bam_ce_buffer[i],
+					 nandc_reg_phys(nandc, reg_off + 4 * i),
+					 BAM_WRITE_COMMAND,
+					 *((__le32 *)vaddr + i));
+	}
+
+	bam_txn->bam_ce_pos += size;
+
+	/* use the separate sgl after this command */
+	if (flags & NAND_BAM_NEXT_SGL) {
+		bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
+		bam_ce_size = (bam_txn->bam_ce_pos -
+				bam_txn->bam_ce_start) *
+				sizeof(struct bam_cmd_element);
+		sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
+			   bam_ce_buffer, bam_ce_size);
+		bam_txn->cmd_sgl_pos++;
+		bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
+
+		if (flags & NAND_BAM_NWD) {
+			ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+						     DMA_PREP_FENCE |
+						     DMA_PREP_CMD);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Prepares the data descriptor for BAM DMA which will be used for NAND
+ * data reads and writes.
+ */
+static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
+				  const void *vaddr,
+				  int size, unsigned int flags)
+{
+	int ret;
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+
+	if (read) {
+		sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos],
+			   vaddr, size);
+		bam_txn->rx_sgl_pos++;
+	} else {
+		sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos],
+			   vaddr, size);
+		bam_txn->tx_sgl_pos++;
+
+		/*
+		 * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag
+		 * is not set, form the DMA descriptor
+		 */
+		if (!(flags & NAND_BAM_NO_EOT)) {
+			ret = prepare_bam_async_desc(nandc, nandc->tx_chan,
+						     DMA_PREP_INTERRUPT);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read,
+			     int reg_off, const void *vaddr, int size,
+			     bool flow_control)
+{
+	struct desc_info *desc;
+	struct dma_async_tx_descriptor *dma_desc;
+	struct scatterlist *sgl;
+	struct dma_slave_config slave_conf;
+	enum dma_transfer_direction dir_eng;
+	int ret;
+
+	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	sgl = &desc->adm_sgl;
+
+	sg_init_one(sgl, vaddr, size);
+
+	if (read) {
+		dir_eng = DMA_DEV_TO_MEM;
+		desc->dir = DMA_FROM_DEVICE;
+	} else {
+		dir_eng = DMA_MEM_TO_DEV;
+		desc->dir = DMA_TO_DEVICE;
+	}
+
+	ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir);
+	if (ret == 0) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(&slave_conf, 0x00, sizeof(slave_conf));
+
+	slave_conf.device_fc = flow_control;
+	if (read) {
+		slave_conf.src_maxburst = 16;
+		slave_conf.src_addr = nandc->base_dma + reg_off;
+		slave_conf.slave_id = nandc->data_crci;
+	} else {
+		slave_conf.dst_maxburst = 16;
+		slave_conf.dst_addr = nandc->base_dma + reg_off;
+		slave_conf.slave_id = nandc->cmd_crci;
+	}
+
+	ret = dmaengine_slave_config(nandc->chan, &slave_conf);
+	if (ret) {
+		dev_err(nandc->dev, "failed to configure dma channel\n");
+		goto err;
+	}
+
+	dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0);
+	if (!dma_desc) {
+		dev_err(nandc->dev, "failed to prepare desc\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	desc->dma_desc = dma_desc;
+
+	list_add_tail(&desc->node, &nandc->desc_list);
+
+	return 0;
+err:
+	kfree(desc);
+
+	return ret;
+}
+
+/*
+ * read_reg_dma:	prepares a descriptor to read a given number of
+ *			contiguous registers to the reg_read_buf pointer
+ *
+ * @first:		offset of the first register in the contiguous block
+ * @num_regs:		number of registers to read
+ * @flags:		flags to control DMA descriptor preparation
+ */
+static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
+			int num_regs, unsigned int flags)
+{
+	bool flow_control = false;
+	void *vaddr;
+
+	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+	nandc->reg_read_pos += num_regs;
+
+	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
+		first = dev_cmd_reg_addr(nandc, first);
+
+	if (nandc->props->is_bam)
+		return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+					     num_regs, flags);
+
+	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+		flow_control = true;
+
+	return prep_adm_dma_desc(nandc, true, first, vaddr,
+				 num_regs * sizeof(u32), flow_control);
+}
+
+/*
+ * write_reg_dma:	prepares a descriptor to write a given number of
+ *			contiguous registers
+ *
+ * @first:		offset of the first register in the contiguous block
+ * @num_regs:		number of registers to write
+ * @flags:		flags to control DMA descriptor preparation
+ */
+static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
+			 int num_regs, unsigned int flags)
+{
+	bool flow_control = false;
+	struct nandc_regs *regs = nandc->regs;
+	void *vaddr;
+
+	vaddr = offset_to_nandc_reg(regs, first);
+
+	if (first == NAND_ERASED_CW_DETECT_CFG) {
+		if (flags & NAND_ERASED_CW_SET)
+			vaddr = &regs->erased_cw_detect_cfg_set;
+		else
+			vaddr = &regs->erased_cw_detect_cfg_clr;
+	}
+
+	if (first == NAND_EXEC_CMD)
+		flags |= NAND_BAM_NWD;
+
+	if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1)
+		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1);
+
+	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
+		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
+
+	if (nandc->props->is_bam)
+		return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+					     num_regs, flags);
+
+	if (first == NAND_FLASH_CMD)
+		flow_control = true;
+
+	return prep_adm_dma_desc(nandc, false, first, vaddr,
+				 num_regs * sizeof(u32), flow_control);
+}
+
+/*
+ * read_data_dma:	prepares a DMA descriptor to transfer data from the
+ *			controller's internal buffer to the buffer 'vaddr'
+ *
+ * @reg_off:		offset within the controller's data buffer
+ * @vaddr:		virtual address of the buffer we want to write to
+ * @size:		DMA transaction size in bytes
+ * @flags:		flags to control DMA descriptor preparation
+ */
+static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+			 const u8 *vaddr, int size, unsigned int flags)
+{
+	if (nandc->props->is_bam)
+		return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags);
+
+	return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false);
+}
+
+/*
+ * write_data_dma:	prepares a DMA descriptor to transfer data from
+ *			'vaddr' to the controller's internal buffer
+ *
+ * @reg_off:		offset within the controller's data buffer
+ * @vaddr:		virtual address of the buffer we want to read from
+ * @size:		DMA transaction size in bytes
+ * @flags:		flags to control DMA descriptor preparation
+ */
+static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
+			  const u8 *vaddr, int size, unsigned int flags)
+{
+	if (nandc->props->is_bam)
+		return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags);
+
+	return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false);
+}
+
+/*
+ * Helper to prepare DMA descriptors for configuring registers
+ * before reading a NAND page.
+ */
+static void config_nand_page_read(struct qcom_nand_controller *nandc)
+{
+	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
+	write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
+		      NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+}
+
+/*
+ * Helper to prepare DMA descriptors for configuring registers
+ * before reading each codeword in NAND page.
+ */
+static void config_nand_cw_read(struct qcom_nand_controller *nandc)
+{
+	if (nandc->props->is_bam)
+		write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
+			      NAND_BAM_NEXT_SGL);
+
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+	read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
+	read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
+		     NAND_BAM_NEXT_SGL);
+}
+
+/*
+ * Helper to prepare dma descriptors to configure registers needed for reading a
+ * single codeword in page
+ */
+static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
+{
+	config_nand_page_read(nandc);
+	config_nand_cw_read(nandc);
+}
+
+/*
+ * Helper to prepare DMA descriptors used to configure registers needed for
+ * before writing a NAND page.
+ */
+static void config_nand_page_write(struct qcom_nand_controller *nandc)
+{
+	write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+	write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
+	write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
+		      NAND_BAM_NEXT_SGL);
+}
+
+/*
+ * Helper to prepare DMA descriptors for configuring registers
+ * before writing each codeword in NAND page.
+ */
+static void config_nand_cw_write(struct qcom_nand_controller *nandc)
+{
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+}
+
+/*
+ * the following functions are used within chip->cmdfunc() to perform different
+ * NAND_CMD_* commands
+ */
+
+/* sets up descriptors for NAND_CMD_PARAM */
+static int nandc_param(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	/*
+	 * NAND_CMD_PARAM is called before we know much about the FLASH chip
+	 * in use. we configure the controller to perform a raw read of 512
+	 * bytes to read onfi params
+	 */
+	nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
+	nandc_set_reg(nandc, NAND_ADDR0, 0);
+	nandc_set_reg(nandc, NAND_ADDR1, 0);
+	nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
+					| 512 << UD_SIZE_BYTES
+					| 5 << NUM_ADDR_CYCLES
+					| 0 << SPARE_SIZE_BYTES);
+	nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
+					| 0 << CS_ACTIVE_BSY
+					| 17 << BAD_BLOCK_BYTE_NUM
+					| 1 << BAD_BLOCK_IN_SPARE_AREA
+					| 2 << WR_RD_BSY_GAP
+					| 0 << WIDE_FLASH
+					| 1 << DEV0_CFG1_ECC_DISABLE);
+	nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
+
+	/* configure CMD1 and VLD for ONFI param probing */
+	nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
+		      (nandc->vld & ~READ_START_VLD));
+	nandc_set_reg(nandc, NAND_DEV_CMD1,
+		      (nandc->cmd1 & ~(0xFF << READ_ADDR))
+		      | NAND_CMD_PARAM << READ_ADDR);
+
+	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+	nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
+	nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
+	nandc_set_read_loc(nandc, 0, 0, 512, 1);
+
+	write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
+	write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL);
+
+	nandc->buf_count = 512;
+	memset(nandc->data_buffer, 0xff, nandc->buf_count);
+
+	config_nand_single_cw_page_read(nandc);
+
+	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
+		      nandc->buf_count, 0);
+
+	/* restore CMD1 and VLD regs */
+	write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0);
+	write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL);
+
+	return 0;
+}
+
+/* sets up descriptors for NAND_CMD_ERASE1 */
+static int erase_block(struct qcom_nand_host *host, int page_addr)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	nandc_set_reg(nandc, NAND_FLASH_CMD,
+		      BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
+	nandc_set_reg(nandc, NAND_ADDR0, page_addr);
+	nandc_set_reg(nandc, NAND_ADDR1, 0);
+	nandc_set_reg(nandc, NAND_DEV0_CFG0,
+		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
+	nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw);
+	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+	nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus);
+	nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus);
+
+	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+	return 0;
+}
+
+/* sets up descriptors for NAND_CMD_READID */
+static int read_id(struct qcom_nand_host *host, int column)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	if (column == -1)
+		return 0;
+
+	nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID);
+	nandc_set_reg(nandc, NAND_ADDR0, column);
+	nandc_set_reg(nandc, NAND_ADDR1, 0);
+	nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT,
+		      nandc->props->is_bam ? 0 : DM_EN);
+	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+
+	return 0;
+}
+
+/* sets up descriptors for NAND_CMD_RESET */
+static int reset(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE);
+	nandc_set_reg(nandc, NAND_EXEC_CMD, 1);
+
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+	return 0;
+}
+
+/* helpers to submit/free our list of dma descriptors */
+static int submit_descs(struct qcom_nand_controller *nandc)
+{
+	struct desc_info *desc;
+	dma_cookie_t cookie = 0;
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+	int r;
+
+	if (nandc->props->is_bam) {
+		if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) {
+			r = prepare_bam_async_desc(nandc, nandc->rx_chan, 0);
+			if (r)
+				return r;
+		}
+
+		if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) {
+			r = prepare_bam_async_desc(nandc, nandc->tx_chan,
+						   DMA_PREP_INTERRUPT);
+			if (r)
+				return r;
+		}
+
+		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
+			r = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+						   DMA_PREP_CMD);
+			if (r)
+				return r;
+		}
+	}
+
+	list_for_each_entry(desc, &nandc->desc_list, node)
+		cookie = dmaengine_submit(desc->dma_desc);
+
+	if (nandc->props->is_bam) {
+		dma_async_issue_pending(nandc->tx_chan);
+		dma_async_issue_pending(nandc->rx_chan);
+
+		if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE)
+			return -ETIMEDOUT;
+	} else {
+		if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void free_descs(struct qcom_nand_controller *nandc)
+{
+	struct desc_info *desc, *n;
+
+	list_for_each_entry_safe(desc, n, &nandc->desc_list, node) {
+		list_del(&desc->node);
+
+		if (nandc->props->is_bam)
+			dma_unmap_sg(nandc->dev, desc->bam_sgl,
+				     desc->sgl_cnt, desc->dir);
+		else
+			dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1,
+				     desc->dir);
+
+		kfree(desc);
+	}
+}
+
+/* reset the register read buffer for next NAND operation */
+static void clear_read_regs(struct qcom_nand_controller *nandc)
+{
+	nandc->reg_read_pos = 0;
+	nandc_read_buffer_sync(nandc, false);
+}
+
+static void pre_command(struct qcom_nand_host *host, int command)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	nandc->buf_count = 0;
+	nandc->buf_start = 0;
+	host->use_ecc = false;
+	host->last_command = command;
+
+	clear_read_regs(nandc);
+
+	if (command == NAND_CMD_RESET || command == NAND_CMD_READID ||
+	    command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1)
+		clear_bam_transaction(nandc);
+}
+
+/*
+ * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
+ * privately maintained status byte, this status byte can be read after
+ * NAND_CMD_STATUS is called
+ */
+static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int num_cw;
+	int i;
+
+	num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
+	nandc_read_buffer_sync(nandc, true);
+
+	for (i = 0; i < num_cw; i++) {
+		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
+
+		if (flash_status & FS_MPU_ERR)
+			host->status &= ~NAND_STATUS_WP;
+
+		if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
+						 (flash_status &
+						  FS_DEVICE_STS_ERR)))
+			host->status |= NAND_STATUS_FAIL;
+	}
+}
+
+static void post_command(struct qcom_nand_host *host, int command)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	switch (command) {
+	case NAND_CMD_READID:
+		nandc_read_buffer_sync(nandc, true);
+		memcpy(nandc->data_buffer, nandc->reg_read_buf,
+		       nandc->buf_count);
+		break;
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+		parse_erase_write_errors(host, command);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Implements chip->cmdfunc. It's  only used for a limited set of commands.
+ * The rest of the commands wouldn't be called by upper layers. For example,
+ * NAND_CMD_READOOB would never be called because we have our own versions
+ * of read_oob ops for nand_ecc_ctrl.
+ */
+static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
+			       int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	bool wait = false;
+	int ret = 0;
+
+	pre_command(host, command);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		ret = reset(host);
+		wait = true;
+		break;
+
+	case NAND_CMD_READID:
+		nandc->buf_count = 4;
+		ret = read_id(host, column);
+		wait = true;
+		break;
+
+	case NAND_CMD_PARAM:
+		ret = nandc_param(host);
+		wait = true;
+		break;
+
+	case NAND_CMD_ERASE1:
+		ret = erase_block(host, page_addr);
+		wait = true;
+		break;
+
+	case NAND_CMD_READ0:
+		/* we read the entire page for now */
+		WARN_ON(column != 0);
+
+		host->use_ecc = true;
+		set_address(host, 0, page_addr);
+		update_rw_regs(host, ecc->steps, true);
+		break;
+
+	case NAND_CMD_SEQIN:
+		WARN_ON(column != 0);
+		set_address(host, 0, page_addr);
+		break;
+
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_NONE:
+	default:
+		break;
+	}
+
+	if (ret) {
+		dev_err(nandc->dev, "failure executing command %d\n",
+			command);
+		free_descs(nandc);
+		return;
+	}
+
+	if (wait) {
+		ret = submit_descs(nandc);
+		if (ret)
+			dev_err(nandc->dev,
+				"failure submitting descs for command %d\n",
+				command);
+	}
+
+	free_descs(nandc);
+
+	post_command(host, command);
+}
+
+/*
+ * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
+ * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
+ *
+ * when using RS ECC, the HW reports the same erros when reading an erased CW,
+ * but it notifies that it is an erased CW by placing special characters at
+ * certain offsets in the buffer.
+ *
+ * verify if the page is erased or not, and fix up the page for RS ECC by
+ * replacing the special characters with 0xff.
+ */
+static bool erased_chunk_check_and_fixup(u8 *data_buf, int data_len)
+{
+	u8 empty1, empty2;
+
+	/*
+	 * an erased page flags an error in NAND_FLASH_STATUS, check if the page
+	 * is erased by looking for 0x54s at offsets 3 and 175 from the
+	 * beginning of each codeword
+	 */
+
+	empty1 = data_buf[3];
+	empty2 = data_buf[175];
+
+	/*
+	 * if the erased codework markers, if they exist override them with
+	 * 0xffs
+	 */
+	if ((empty1 == 0x54 && empty2 == 0xff) ||
+	    (empty1 == 0xff && empty2 == 0x54)) {
+		data_buf[3] = 0xff;
+		data_buf[175] = 0xff;
+	}
+
+	/*
+	 * check if the entire chunk contains 0xffs or not. if it doesn't, then
+	 * restore the original values at the special offsets
+	 */
+	if (memchr_inv(data_buf, 0xff, data_len)) {
+		data_buf[3] = empty1;
+		data_buf[175] = empty2;
+
+		return false;
+	}
+
+	return true;
+}
+
+struct read_stats {
+	__le32 flash;
+	__le32 buffer;
+	__le32 erased_cw;
+};
+
+/*
+ * reads back status registers set by the controller to notify page read
+ * errors. this is equivalent to what 'ecc->correct()' would do.
+ */
+static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
+			     u8 *oob_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	struct read_stats *buf;
+	int i;
+
+	buf = (struct read_stats *)nandc->reg_read_buf;
+	nandc_read_buffer_sync(nandc, true);
+
+	for (i = 0; i < ecc->steps; i++, buf++) {
+		u32 flash, buffer, erased_cw;
+		int data_len, oob_len;
+
+		if (i == (ecc->steps - 1)) {
+			data_len = ecc->size - ((ecc->steps - 1) << 2);
+			oob_len = ecc->steps << 2;
+		} else {
+			data_len = host->cw_data;
+			oob_len = 0;
+		}
+
+		flash = le32_to_cpu(buf->flash);
+		buffer = le32_to_cpu(buf->buffer);
+		erased_cw = le32_to_cpu(buf->erased_cw);
+
+		if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+			bool erased;
+
+			/* ignore erased codeword errors */
+			if (host->bch_enabled) {
+				erased = (erased_cw & ERASED_CW) == ERASED_CW ?
+					 true : false;
+			} else {
+				erased = erased_chunk_check_and_fixup(data_buf,
+								      data_len);
+			}
+
+			if (erased) {
+				data_buf += data_len;
+				if (oob_buf)
+					oob_buf += oob_len + ecc->bytes;
+				continue;
+			}
+
+			if (buffer & BS_UNCORRECTABLE_BIT) {
+				int ret, ecclen, extraooblen;
+				void *eccbuf;
+
+				eccbuf = oob_buf ? oob_buf + oob_len : NULL;
+				ecclen = oob_buf ? host->ecc_bytes_hw : 0;
+				extraooblen = oob_buf ? oob_len : 0;
+
+				/*
+				 * make sure it isn't an erased page reported
+				 * as not-erased by HW because of a few bitflips
+				 */
+				ret = nand_check_erased_ecc_chunk(data_buf,
+					data_len, eccbuf, ecclen, oob_buf,
+					extraooblen, ecc->strength);
+				if (ret < 0) {
+					mtd->ecc_stats.failed++;
+				} else {
+					mtd->ecc_stats.corrected += ret;
+					max_bitflips =
+						max_t(unsigned int, max_bitflips, ret);
+				}
+			}
+		} else {
+			unsigned int stat;
+
+			stat = buffer & BS_CORRECTABLE_ERR_MSK;
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max(max_bitflips, stat);
+		}
+
+		data_buf += data_len;
+		if (oob_buf)
+			oob_buf += oob_len + ecc->bytes;
+	}
+
+	return max_bitflips;
+}
+
+/*
+ * helper to perform the actual page read operation, used by ecc->read_page(),
+ * ecc->read_oob()
+ */
+static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
+			 u8 *oob_buf)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int i, ret;
+
+	config_nand_page_read(nandc);
+
+	/* queue cmd descs for each codeword */
+	for (i = 0; i < ecc->steps; i++) {
+		int data_size, oob_size;
+
+		if (i == (ecc->steps - 1)) {
+			data_size = ecc->size - ((ecc->steps - 1) << 2);
+			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
+				   host->spare_bytes;
+		} else {
+			data_size = host->cw_data;
+			oob_size = host->ecc_bytes_hw + host->spare_bytes;
+		}
+
+		if (nandc->props->is_bam) {
+			if (data_buf && oob_buf) {
+				nandc_set_read_loc(nandc, 0, 0, data_size, 0);
+				nandc_set_read_loc(nandc, 1, data_size,
+						   oob_size, 1);
+			} else if (data_buf) {
+				nandc_set_read_loc(nandc, 0, 0, data_size, 1);
+			} else {
+				nandc_set_read_loc(nandc, 0, data_size,
+						   oob_size, 1);
+			}
+		}
+
+		config_nand_cw_read(nandc);
+
+		if (data_buf)
+			read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
+				      data_size, 0);
+
+		/*
+		 * when ecc is enabled, the controller doesn't read the real
+		 * or dummy bad block markers in each chunk. To maintain a
+		 * consistent layout across RAW and ECC reads, we just
+		 * leave the real/dummy BBM offsets empty (i.e, filled with
+		 * 0xffs)
+		 */
+		if (oob_buf) {
+			int j;
+
+			for (j = 0; j < host->bbm_size; j++)
+				*oob_buf++ = 0xff;
+
+			read_data_dma(nandc, FLASH_BUF_ACC + data_size,
+				      oob_buf, oob_size, 0);
+		}
+
+		if (data_buf)
+			data_buf += data_size;
+		if (oob_buf)
+			oob_buf += oob_size;
+	}
+
+	ret = submit_descs(nandc);
+	if (ret)
+		dev_err(nandc->dev, "failure to read page/oob\n");
+
+	free_descs(nandc);
+
+	return ret;
+}
+
+/*
+ * a helper that copies the last step/codeword of a page (containing free oob)
+ * into our local buffer
+ */
+static int copy_last_cw(struct qcom_nand_host *host, int page)
+{
+	struct nand_chip *chip = &host->chip;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int size;
+	int ret;
+
+	clear_read_regs(nandc);
+
+	size = host->use_ecc ? host->cw_data : host->cw_size;
+
+	/* prepare a clean read buffer */
+	memset(nandc->data_buffer, 0xff, size);
+
+	set_address(host, host->cw_size * (ecc->steps - 1), page);
+	update_rw_regs(host, 1, true);
+
+	config_nand_single_cw_page_read(nandc);
+
+	read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
+
+	ret = submit_descs(nandc);
+	if (ret)
+		dev_err(nandc->dev, "failed to copy last codeword\n");
+
+	free_descs(nandc);
+
+	return ret;
+}
+
+/* implements ecc->read_page() */
+static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	u8 *data_buf, *oob_buf = NULL;
+	int ret;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+	data_buf = buf;
+	oob_buf = oob_required ? chip->oob_poi : NULL;
+
+	clear_bam_transaction(nandc);
+	ret = read_page_ecc(host, data_buf, oob_buf);
+	if (ret) {
+		dev_err(nandc->dev, "failure to read page\n");
+		return ret;
+	}
+
+	return parse_read_errors(host, data_buf, oob_buf);
+}
+
+/* implements ecc->read_page_raw() */
+static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
+				    struct nand_chip *chip, uint8_t *buf,
+				    int oob_required, int page)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	u8 *data_buf, *oob_buf;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int i, ret;
+	int read_loc;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+	data_buf = buf;
+	oob_buf = chip->oob_poi;
+
+	host->use_ecc = false;
+
+	clear_bam_transaction(nandc);
+	update_rw_regs(host, ecc->steps, true);
+	config_nand_page_read(nandc);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_size1, data_size2, oob_size1, oob_size2;
+		int reg_off = FLASH_BUF_ACC;
+
+		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+		oob_size1 = host->bbm_size;
+
+		if (i == (ecc->steps - 1)) {
+			data_size2 = ecc->size - data_size1 -
+				     ((ecc->steps - 1) << 2);
+			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
+				    host->spare_bytes;
+		} else {
+			data_size2 = host->cw_data - data_size1;
+			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+		}
+
+		if (nandc->props->is_bam) {
+			read_loc = 0;
+			nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
+			read_loc += data_size1;
+
+			nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
+			read_loc += oob_size1;
+
+			nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
+			read_loc += data_size2;
+
+			nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
+		}
+
+		config_nand_cw_read(nandc);
+
+		read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
+		reg_off += data_size1;
+		data_buf += data_size1;
+
+		read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
+		reg_off += oob_size1;
+		oob_buf += oob_size1;
+
+		read_data_dma(nandc, reg_off, data_buf, data_size2, 0);
+		reg_off += data_size2;
+		data_buf += data_size2;
+
+		read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
+		oob_buf += oob_size2;
+	}
+
+	ret = submit_descs(nandc);
+	if (ret)
+		dev_err(nandc->dev, "failure to read raw page\n");
+
+	free_descs(nandc);
+
+	return 0;
+}
+
+/* implements ecc->read_oob() */
+static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			       int page)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret;
+
+	clear_read_regs(nandc);
+	clear_bam_transaction(nandc);
+
+	host->use_ecc = true;
+	set_address(host, 0, page);
+	update_rw_regs(host, ecc->steps, true);
+
+	ret = read_page_ecc(host, NULL, chip->oob_poi);
+	if (ret)
+		dev_err(nandc->dev, "failure to read oob\n");
+
+	return ret;
+}
+
+/* implements ecc->write_page() */
+static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+				 const uint8_t *buf, int oob_required, int page)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	u8 *data_buf, *oob_buf;
+	int i, ret;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	clear_read_regs(nandc);
+	clear_bam_transaction(nandc);
+
+	data_buf = (u8 *)buf;
+	oob_buf = chip->oob_poi;
+
+	host->use_ecc = true;
+	update_rw_regs(host, ecc->steps, false);
+	config_nand_page_write(nandc);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_size, oob_size;
+
+		if (i == (ecc->steps - 1)) {
+			data_size = ecc->size - ((ecc->steps - 1) << 2);
+			oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
+				   host->spare_bytes;
+		} else {
+			data_size = host->cw_data;
+			oob_size = ecc->bytes;
+		}
+
+
+		write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size,
+			       i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0);
+
+		/*
+		 * when ECC is enabled, we don't really need to write anything
+		 * to oob for the first n - 1 codewords since these oob regions
+		 * just contain ECC bytes that's written by the controller
+		 * itself. For the last codeword, we skip the bbm positions and
+		 * write to the free oob area.
+		 */
+		if (i == (ecc->steps - 1)) {
+			oob_buf += host->bbm_size;
+
+			write_data_dma(nandc, FLASH_BUF_ACC + data_size,
+				       oob_buf, oob_size, 0);
+		}
+
+		config_nand_cw_write(nandc);
+
+		data_buf += data_size;
+		oob_buf += oob_size;
+	}
+
+	ret = submit_descs(nandc);
+	if (ret)
+		dev_err(nandc->dev, "failure to write page\n");
+
+	free_descs(nandc);
+
+	if (!ret)
+		ret = nand_prog_page_end_op(chip);
+
+	return ret;
+}
+
+/* implements ecc->write_page_raw() */
+static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
+				     struct nand_chip *chip, const uint8_t *buf,
+				     int oob_required, int page)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	u8 *data_buf, *oob_buf;
+	int i, ret;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	clear_read_regs(nandc);
+	clear_bam_transaction(nandc);
+
+	data_buf = (u8 *)buf;
+	oob_buf = chip->oob_poi;
+
+	host->use_ecc = false;
+	update_rw_regs(host, ecc->steps, false);
+	config_nand_page_write(nandc);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_size1, data_size2, oob_size1, oob_size2;
+		int reg_off = FLASH_BUF_ACC;
+
+		data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
+		oob_size1 = host->bbm_size;
+
+		if (i == (ecc->steps - 1)) {
+			data_size2 = ecc->size - data_size1 -
+				     ((ecc->steps - 1) << 2);
+			oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
+				    host->spare_bytes;
+		} else {
+			data_size2 = host->cw_data - data_size1;
+			oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
+		}
+
+		write_data_dma(nandc, reg_off, data_buf, data_size1,
+			       NAND_BAM_NO_EOT);
+		reg_off += data_size1;
+		data_buf += data_size1;
+
+		write_data_dma(nandc, reg_off, oob_buf, oob_size1,
+			       NAND_BAM_NO_EOT);
+		reg_off += oob_size1;
+		oob_buf += oob_size1;
+
+		write_data_dma(nandc, reg_off, data_buf, data_size2,
+			       NAND_BAM_NO_EOT);
+		reg_off += data_size2;
+		data_buf += data_size2;
+
+		write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
+		oob_buf += oob_size2;
+
+		config_nand_cw_write(nandc);
+	}
+
+	ret = submit_descs(nandc);
+	if (ret)
+		dev_err(nandc->dev, "failure to write raw page\n");
+
+	free_descs(nandc);
+
+	if (!ret)
+		ret = nand_prog_page_end_op(chip);
+
+	return ret;
+}
+
+/*
+ * implements ecc->write_oob()
+ *
+ * the NAND controller cannot write only data or only oob within a codeword,
+ * since ecc is calculated for the combined codeword. we first copy the
+ * entire contents for the last codeword(data + oob), replace the old oob
+ * with the new one in chip->oob_poi, and then write the entire codeword.
+ * this read-copy-write operation results in a slight performance loss.
+ */
+static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+				int page)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	u8 *oob = chip->oob_poi;
+	int data_size, oob_size;
+	int ret;
+
+	host->use_ecc = true;
+
+	clear_bam_transaction(nandc);
+	ret = copy_last_cw(host, page);
+	if (ret)
+		return ret;
+
+	clear_read_regs(nandc);
+	clear_bam_transaction(nandc);
+
+	/* calculate the data and oob size for the last codeword/step */
+	data_size = ecc->size - ((ecc->steps - 1) << 2);
+	oob_size = mtd->oobavail;
+
+	/* override new oob content to last codeword */
+	mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
+				    0, mtd->oobavail);
+
+	set_address(host, host->cw_size * (ecc->steps - 1), page);
+	update_rw_regs(host, 1, false);
+
+	config_nand_page_write(nandc);
+	write_data_dma(nandc, FLASH_BUF_ACC,
+		       nandc->data_buffer, data_size + oob_size, 0);
+	config_nand_cw_write(nandc);
+
+	ret = submit_descs(nandc);
+
+	free_descs(nandc);
+
+	if (ret) {
+		dev_err(nandc->dev, "failure to write oob\n");
+		return -EIO;
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int page, ret, bbpos, bad = 0;
+	u32 flash_status;
+
+	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
+	/*
+	 * configure registers for a raw sub page read, the address is set to
+	 * the beginning of the last codeword, we don't care about reading ecc
+	 * portion of oob. we just want the first few bytes from this codeword
+	 * that contains the BBM
+	 */
+	host->use_ecc = false;
+
+	clear_bam_transaction(nandc);
+	ret = copy_last_cw(host, page);
+	if (ret)
+		goto err;
+
+	flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
+
+	if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
+		dev_warn(nandc->dev, "error when trying to read BBM\n");
+		goto err;
+	}
+
+	bbpos = mtd->writesize - host->cw_size * (ecc->steps - 1);
+
+	bad = nandc->data_buffer[bbpos] != 0xff;
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		bad = bad || (nandc->data_buffer[bbpos + 1] != 0xff);
+err:
+	return bad;
+}
+
+static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int page, ret;
+
+	clear_read_regs(nandc);
+	clear_bam_transaction(nandc);
+
+	/*
+	 * to mark the BBM as bad, we flash the entire last codeword with 0s.
+	 * we don't care about the rest of the content in the codeword since
+	 * we aren't going to use this block again
+	 */
+	memset(nandc->data_buffer, 0x00, host->cw_size);
+
+	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
+	/* prepare write */
+	host->use_ecc = false;
+	set_address(host, host->cw_size * (ecc->steps - 1), page);
+	update_rw_regs(host, 1, false);
+
+	config_nand_page_write(nandc);
+	write_data_dma(nandc, FLASH_BUF_ACC,
+		       nandc->data_buffer, host->cw_size, 0);
+	config_nand_cw_write(nandc);
+
+	ret = submit_descs(nandc);
+
+	free_descs(nandc);
+
+	if (ret) {
+		dev_err(nandc->dev, "failure to update BBM\n");
+		return -EIO;
+	}
+
+	return nand_prog_page_end_op(chip);
+}
+
+/*
+ * the three functions below implement chip->read_byte(), chip->read_buf()
+ * and chip->write_buf() respectively. these aren't used for
+ * reading/writing page data, they are used for smaller data like reading
+ * id, status etc
+ */
+static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	u8 *buf = nandc->data_buffer;
+	u8 ret = 0x0;
+
+	if (host->last_command == NAND_CMD_STATUS) {
+		ret = host->status;
+
+		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
+
+		return ret;
+	}
+
+	if (nandc->buf_start < nandc->buf_count)
+		ret = buf[nandc->buf_start++];
+
+	return ret;
+}
+
+static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
+
+	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
+	nandc->buf_start += real_len;
+}
+
+static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				 int len)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
+
+	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
+
+	nandc->buf_start += real_len;
+}
+
+/* we support only one external chip for now */
+static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	if (chipnr <= 0)
+		return;
+
+	dev_warn(nandc->dev, "invalid chip select\n");
+}
+
+/*
+ * NAND controller page layout info
+ *
+ * Layout with ECC enabled:
+ *
+ * |----------------------|  |---------------------------------|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |    DATA   xx..ECC..yy|  |    DATA     **SPARE**xx..ECC..yy|
+ * |   (516)   xx.......yy|  |  (516-n*4)  **(n*4)**xx.......yy|
+ * |           xx.......yy|  |             *********xx.......yy|
+ * |----------------------|  |---------------------------------|
+ *     codeword 1,2..n-1                  codeword n
+ *  <---(528/532 Bytes)-->    <-------(528/532 Bytes)--------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Reserved byte(s)
+ *
+ * 2K page: n = 4, spare = 16 bytes
+ * 4K page: n = 8, spare = 32 bytes
+ * 8K page: n = 16, spare = 64 bytes
+ *
+ * the qcom nand controller operates at a sub page/codeword level. each
+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
+ * the number of ECC bytes vary based on the ECC strength and the bus width.
+ *
+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
+ *
+ * When we access a page with ECC enabled, the reserved bytes(s) are not
+ * accessible at all. When reading, we fill up these unreadable positions
+ * with 0xffs. When writing, the controller skips writing the inaccessible
+ * bytes.
+ *
+ * Layout with ECC disabled:
+ *
+ * |------------------------------|  |---------------------------------------|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |  DATA1  yy  DATA2   xx..ECC..|  |  DATA1  bb  DATA2   **SPARE**xx..ECC..|
+ * | (size1) yy (size2)  xx.......|  | (size1) bb (size2)  **(n*4)**xx.......|
+ * |         yy          xx.......|  |         bb          *********xx.......|
+ * |------------------------------|  |---------------------------------------|
+ *         codeword 1,2..n-1                        codeword n
+ *  <-------(528/532 Bytes)------>    <-----------(528/532 Bytes)----------->
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = Spare/free bytes
+ * x = Unused byte(s)
+ * y = Dummy Bad Bock byte(s)
+ * b = Real Bad Block byte(s)
+ * size1/size2 = function of codeword size and 'n'
+ *
+ * when the ECC block is disabled, one reserved byte (or two for 16 bit bus
+ * width) is now accessible. For the first n - 1 codewords, these are dummy Bad
+ * Block Markers. In the last codeword, this position contains the real BBM
+ *
+ * In order to have a consistent layout between RAW and ECC modes, we assume
+ * the following OOB layout arrangement:
+ *
+ * |-----------|  |--------------------|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx..ECC..|  |bb*FREEOOB*xx..ECC..|
+ * |yyxx.......|  |bb*********xx.......|
+ * |yyxx.......|  |bb*********xx.......|
+ * |-----------|  |--------------------|
+ *  first n - 1       nth OOB region
+ *  OOB regions
+ *
+ * n = Number of codewords in the page
+ * . = ECC bytes
+ * * = FREE OOB bytes
+ * y = Dummy bad block byte(s) (inaccessible when ECC enabled)
+ * x = Unused byte(s)
+ * b = Real bad block byte(s) (inaccessible when ECC enabled)
+ *
+ * This layout is read as is when ECC is disabled. When ECC is enabled, the
+ * inaccessible Bad Block byte(s) are ignored when we write to a page/oob,
+ * and assumed as 0xffs when we read a page/oob. The ECC, unused and
+ * dummy/real bad block bytes are grouped as ecc bytes (i.e, ecc->bytes is
+ * the sum of the three).
+ */
+static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section > 1)
+		return -ERANGE;
+
+	if (!section) {
+		oobregion->length = (ecc->bytes * (ecc->steps - 1)) +
+				    host->bbm_size;
+		oobregion->offset = 0;
+	} else {
+		oobregion->length = host->ecc_bytes_hw + host->spare_bytes;
+		oobregion->offset = mtd->oobsize - oobregion->length;
+	}
+
+	return 0;
+}
+
+static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = ecc->steps * 4;
+	oobregion->offset = ((ecc->steps - 1) * ecc->bytes) + host->bbm_size;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
+	.ecc = qcom_nand_ooblayout_ecc,
+	.free = qcom_nand_ooblayout_free,
+};
+
+static int qcom_nand_host_setup(struct qcom_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	int cwperpage, bad_block_byte;
+	bool wide_bus;
+	int ecc_mode = 1;
+
+	/*
+	 * the controller requires each step consists of 512 bytes of data.
+	 * bail out if DT has populated a wrong step size.
+	 */
+	if (ecc->size != NANDC_STEP_SIZE) {
+		dev_err(nandc->dev, "invalid ecc size\n");
+		return -EINVAL;
+	}
+
+	wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
+
+	if (ecc->strength >= 8) {
+		/* 8 bit ECC defaults to BCH ECC on all platforms */
+		host->bch_enabled = true;
+		ecc_mode = 1;
+
+		if (wide_bus) {
+			host->ecc_bytes_hw = 14;
+			host->spare_bytes = 0;
+			host->bbm_size = 2;
+		} else {
+			host->ecc_bytes_hw = 13;
+			host->spare_bytes = 2;
+			host->bbm_size = 1;
+		}
+	} else {
+		/*
+		 * if the controller supports BCH for 4 bit ECC, the controller
+		 * uses lesser bytes for ECC. If RS is used, the ECC bytes is
+		 * always 10 bytes
+		 */
+		if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
+			/* BCH */
+			host->bch_enabled = true;
+			ecc_mode = 0;
+
+			if (wide_bus) {
+				host->ecc_bytes_hw = 8;
+				host->spare_bytes = 2;
+				host->bbm_size = 2;
+			} else {
+				host->ecc_bytes_hw = 7;
+				host->spare_bytes = 4;
+				host->bbm_size = 1;
+			}
+		} else {
+			/* RS */
+			host->ecc_bytes_hw = 10;
+
+			if (wide_bus) {
+				host->spare_bytes = 0;
+				host->bbm_size = 2;
+			} else {
+				host->spare_bytes = 1;
+				host->bbm_size = 1;
+			}
+		}
+	}
+
+	/*
+	 * we consider ecc->bytes as the sum of all the non-data content in a
+	 * step. It gives us a clean representation of the oob area (even if
+	 * all the bytes aren't used for ECC).It is always 16 bytes for 8 bit
+	 * ECC and 12 bytes for 4 bit ECC
+	 */
+	ecc->bytes = host->ecc_bytes_hw + host->spare_bytes + host->bbm_size;
+
+	ecc->read_page		= qcom_nandc_read_page;
+	ecc->read_page_raw	= qcom_nandc_read_page_raw;
+	ecc->read_oob		= qcom_nandc_read_oob;
+	ecc->write_page		= qcom_nandc_write_page;
+	ecc->write_page_raw	= qcom_nandc_write_page_raw;
+	ecc->write_oob		= qcom_nandc_write_oob;
+
+	ecc->mode = NAND_ECC_HW;
+
+	mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
+
+	cwperpage = mtd->writesize / ecc->size;
+	nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
+				     cwperpage);
+
+	/*
+	 * DATA_UD_BYTES varies based on whether the read/write command protects
+	 * spare data with ECC too. We protect spare data by default, so we set
+	 * it to main + spare data, which are 512 and 4 bytes respectively.
+	 */
+	host->cw_data = 516;
+
+	/*
+	 * total bytes in a step, either 528 bytes for 4 bit ECC, or 532 bytes
+	 * for 8 bit ECC
+	 */
+	host->cw_size = host->cw_data + ecc->bytes;
+
+	if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
+		dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
+		return -EINVAL;
+	}
+
+	bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
+
+	host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_data << UD_SIZE_BYTES
+				| 0 << DISABLE_STATUS_AFTER_WRITE
+				| 5 << NUM_ADDR_CYCLES
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS
+				| 0 << STATUS_BFR_READ
+				| 1 << SET_RD_MODE_AFTER_STATUS
+				| host->spare_bytes << SPARE_SIZE_BYTES;
+
+	host->cfg1 = 7 << NAND_RECOVERY_CYCLES
+				| 0 <<  CS_ACTIVE_BSY
+				| bad_block_byte << BAD_BLOCK_BYTE_NUM
+				| 0 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| host->bch_enabled << ENABLE_BCH_ECC;
+
+	host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
+				| host->cw_size << UD_SIZE_BYTES
+				| 5 << NUM_ADDR_CYCLES
+				| 0 << SPARE_SIZE_BYTES;
+
+	host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
+				| 0 << CS_ACTIVE_BSY
+				| 17 << BAD_BLOCK_BYTE_NUM
+				| 1 << BAD_BLOCK_IN_SPARE_AREA
+				| 2 << WR_RD_BSY_GAP
+				| wide_bus << WIDE_FLASH
+				| 1 << DEV0_CFG1_ECC_DISABLE;
+
+	host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
+				| 0 << ECC_SW_RESET
+				| host->cw_data << ECC_NUM_DATA_BYTES
+				| 1 << ECC_FORCE_CLK_OPEN
+				| ecc_mode << ECC_MODE
+				| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
+
+	host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+
+	host->clrflashstatus = FS_READY_BSY_N;
+	host->clrreadstatus = 0xc0;
+	nandc->regs->erased_cw_detect_cfg_clr =
+		cpu_to_le32(CLR_ERASED_PAGE_DET);
+	nandc->regs->erased_cw_detect_cfg_set =
+		cpu_to_le32(SET_ERASED_PAGE_DET);
+
+	dev_dbg(nandc->dev,
+		"cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
+		host->cfg0, host->cfg1, host->ecc_buf_cfg, host->ecc_bch_cfg,
+		host->cw_size, host->cw_data, ecc->strength, ecc->bytes,
+		cwperpage);
+
+	return 0;
+}
+
+static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
+{
+	int ret;
+
+	ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(nandc->dev, "failed to set DMA mask\n");
+		return ret;
+	}
+
+	/*
+	 * we use the internal buffer for reading ONFI params, reading small
+	 * data like ID and status, and preforming read-copy-write operations
+	 * when writing to a codeword partially. 532 is the maximum possible
+	 * size of a codeword for our nand controller
+	 */
+	nandc->buf_size = 532;
+
+	nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size,
+					GFP_KERNEL);
+	if (!nandc->data_buffer)
+		return -ENOMEM;
+
+	nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs),
+					GFP_KERNEL);
+	if (!nandc->regs)
+		return -ENOMEM;
+
+	nandc->reg_read_buf = devm_kzalloc(nandc->dev,
+				MAX_REG_RD * sizeof(*nandc->reg_read_buf),
+				GFP_KERNEL);
+	if (!nandc->reg_read_buf)
+		return -ENOMEM;
+
+	if (nandc->props->is_bam) {
+		nandc->reg_read_dma =
+			dma_map_single(nandc->dev, nandc->reg_read_buf,
+				       MAX_REG_RD *
+				       sizeof(*nandc->reg_read_buf),
+				       DMA_FROM_DEVICE);
+		if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) {
+			dev_err(nandc->dev, "failed to DMA MAP reg buffer\n");
+			return -EIO;
+		}
+
+		nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
+		if (!nandc->tx_chan) {
+			dev_err(nandc->dev, "failed to request tx channel\n");
+			return -ENODEV;
+		}
+
+		nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
+		if (!nandc->rx_chan) {
+			dev_err(nandc->dev, "failed to request rx channel\n");
+			return -ENODEV;
+		}
+
+		nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
+		if (!nandc->cmd_chan) {
+			dev_err(nandc->dev, "failed to request cmd channel\n");
+			return -ENODEV;
+		}
+
+		/*
+		 * Initially allocate BAM transaction to read ONFI param page.
+		 * After detecting all the devices, this BAM transaction will
+		 * be freed and the next BAM tranasction will be allocated with
+		 * maximum codeword size
+		 */
+		nandc->max_cwperpage = 1;
+		nandc->bam_txn = alloc_bam_transaction(nandc);
+		if (!nandc->bam_txn) {
+			dev_err(nandc->dev,
+				"failed to allocate bam transaction\n");
+			return -ENOMEM;
+		}
+	} else {
+		nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
+		if (!nandc->chan) {
+			dev_err(nandc->dev,
+				"failed to request slave channel\n");
+			return -ENODEV;
+		}
+	}
+
+	INIT_LIST_HEAD(&nandc->desc_list);
+	INIT_LIST_HEAD(&nandc->host_list);
+
+	nand_hw_control_init(&nandc->controller);
+
+	return 0;
+}
+
+static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
+{
+	if (nandc->props->is_bam) {
+		if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma))
+			dma_unmap_single(nandc->dev, nandc->reg_read_dma,
+					 MAX_REG_RD *
+					 sizeof(*nandc->reg_read_buf),
+					 DMA_FROM_DEVICE);
+
+		if (nandc->tx_chan)
+			dma_release_channel(nandc->tx_chan);
+
+		if (nandc->rx_chan)
+			dma_release_channel(nandc->rx_chan);
+
+		if (nandc->cmd_chan)
+			dma_release_channel(nandc->cmd_chan);
+	} else {
+		if (nandc->chan)
+			dma_release_channel(nandc->chan);
+	}
+}
+
+/* one time setup of a few nand controller registers */
+static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
+{
+	u32 nand_ctrl;
+
+	/* kill onenand */
+	nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+	nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
+		    NAND_DEV_CMD_VLD_VAL);
+
+	/* enable ADM or BAM DMA */
+	if (nandc->props->is_bam) {
+		nand_ctrl = nandc_read(nandc, NAND_CTRL);
+		nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
+	} else {
+		nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
+	}
+
+	/* save the original values of these registers */
+	nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1));
+	nandc->vld = NAND_DEV_CMD_VLD_VAL;
+
+	return 0;
+}
+
+static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
+			       struct qcom_nand_host *host,
+			       struct device_node *dn)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct device *dev = nandc->dev;
+	int ret;
+
+	ret = of_property_read_u32(dn, "reg", &host->cs);
+	if (ret) {
+		dev_err(dev, "can't get chip-select\n");
+		return -ENXIO;
+	}
+
+	nand_set_flash_node(chip, dn);
+	mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
+	if (!mtd->name)
+		return -ENOMEM;
+
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = dev;
+
+	chip->cmdfunc		= qcom_nandc_command;
+	chip->select_chip	= qcom_nandc_select_chip;
+	chip->read_byte		= qcom_nandc_read_byte;
+	chip->read_buf		= qcom_nandc_read_buf;
+	chip->write_buf		= qcom_nandc_write_buf;
+	chip->onfi_set_features	= nand_onfi_get_set_features_notsupp;
+	chip->onfi_get_features	= nand_onfi_get_set_features_notsupp;
+
+	/*
+	 * the bad block marker is readable only when we read the last codeword
+	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
+	 * helpers don't allow us to read BB from a nand chip with ECC
+	 * disabled (MTD_OPS_PLACE_OOB is set by default). use the block_bad
+	 * and block_markbad helpers until we permanently switch to using
+	 * MTD_OPS_RAW for all drivers (with the help of badblockbits)
+	 */
+	chip->block_bad		= qcom_nandc_block_bad;
+	chip->block_markbad	= qcom_nandc_block_markbad;
+
+	chip->controller = &nandc->controller;
+	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
+			 NAND_SKIP_BBTSCAN;
+
+	/* set up initial status value */
+	host->status = NAND_STATUS_READY | NAND_STATUS_WP;
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		return ret;
+
+	ret = qcom_nand_host_setup(host);
+
+	return ret;
+}
+
+static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
+				  struct qcom_nand_host *host,
+				  struct device_node *dn)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		return ret;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret)
+		nand_cleanup(mtd_to_nand(mtd));
+
+	return ret;
+}
+
+static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
+{
+	struct device *dev = nandc->dev;
+	struct device_node *dn = dev->of_node, *child;
+	struct qcom_nand_host *host, *tmp;
+	int ret;
+
+	for_each_available_child_of_node(dn, child) {
+		host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+		if (!host) {
+			of_node_put(child);
+			return -ENOMEM;
+		}
+
+		ret = qcom_nand_host_init(nandc, host, child);
+		if (ret) {
+			devm_kfree(dev, host);
+			continue;
+		}
+
+		list_add_tail(&host->node, &nandc->host_list);
+	}
+
+	if (list_empty(&nandc->host_list))
+		return -ENODEV;
+
+	if (nandc->props->is_bam) {
+		free_bam_transaction(nandc);
+		nandc->bam_txn = alloc_bam_transaction(nandc);
+		if (!nandc->bam_txn) {
+			dev_err(nandc->dev,
+				"failed to allocate bam transaction\n");
+			return -ENOMEM;
+		}
+	}
+
+	list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
+		ret = qcom_nand_mtd_register(nandc, host, child);
+		if (ret) {
+			list_del(&host->node);
+			devm_kfree(dev, host);
+		}
+	}
+
+	if (list_empty(&nandc->host_list))
+		return -ENODEV;
+
+	return 0;
+}
+
+/* parse custom DT properties here */
+static int qcom_nandc_parse_dt(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+	struct device_node *np = nandc->dev->of_node;
+	int ret;
+
+	if (!nandc->props->is_bam) {
+		ret = of_property_read_u32(np, "qcom,cmd-crci",
+					   &nandc->cmd_crci);
+		if (ret) {
+			dev_err(nandc->dev, "command CRCI unspecified\n");
+			return ret;
+		}
+
+		ret = of_property_read_u32(np, "qcom,data-crci",
+					   &nandc->data_crci);
+		if (ret) {
+			dev_err(nandc->dev, "data CRCI unspecified\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int qcom_nandc_probe(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc;
+	const void *dev_data;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+
+	nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
+	if (!nandc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, nandc);
+	nandc->dev = dev;
+
+	dev_data = of_device_get_match_data(dev);
+	if (!dev_data) {
+		dev_err(&pdev->dev, "failed to get device data\n");
+		return -ENODEV;
+	}
+
+	nandc->props = dev_data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nandc->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(nandc->base))
+		return PTR_ERR(nandc->base);
+
+	nandc->base_phys = res->start;
+	nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
+
+	nandc->core_clk = devm_clk_get(dev, "core");
+	if (IS_ERR(nandc->core_clk))
+		return PTR_ERR(nandc->core_clk);
+
+	nandc->aon_clk = devm_clk_get(dev, "aon");
+	if (IS_ERR(nandc->aon_clk))
+		return PTR_ERR(nandc->aon_clk);
+
+	ret = qcom_nandc_parse_dt(pdev);
+	if (ret)
+		return ret;
+
+	ret = qcom_nandc_alloc(nandc);
+	if (ret)
+		goto err_core_clk;
+
+	ret = clk_prepare_enable(nandc->core_clk);
+	if (ret)
+		goto err_core_clk;
+
+	ret = clk_prepare_enable(nandc->aon_clk);
+	if (ret)
+		goto err_aon_clk;
+
+	ret = qcom_nandc_setup(nandc);
+	if (ret)
+		goto err_setup;
+
+	ret = qcom_probe_nand_devices(nandc);
+	if (ret)
+		goto err_setup;
+
+	return 0;
+
+err_setup:
+	clk_disable_unprepare(nandc->aon_clk);
+err_aon_clk:
+	clk_disable_unprepare(nandc->core_clk);
+err_core_clk:
+	qcom_nandc_unalloc(nandc);
+
+	return ret;
+}
+
+static int qcom_nandc_remove(struct platform_device *pdev)
+{
+	struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
+	struct qcom_nand_host *host;
+
+	list_for_each_entry(host, &nandc->host_list, node)
+		nand_release(nand_to_mtd(&host->chip));
+
+	qcom_nandc_unalloc(nandc);
+
+	clk_disable_unprepare(nandc->aon_clk);
+	clk_disable_unprepare(nandc->core_clk);
+
+	return 0;
+}
+
+static const struct qcom_nandc_props ipq806x_nandc_props = {
+	.ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
+	.is_bam = false,
+	.dev_cmd_reg_start = 0x0,
+};
+
+static const struct qcom_nandc_props ipq4019_nandc_props = {
+	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+	.is_bam = true,
+	.dev_cmd_reg_start = 0x0,
+};
+
+static const struct qcom_nandc_props ipq8074_nandc_props = {
+	.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+	.is_bam = true,
+	.dev_cmd_reg_start = 0x7000,
+};
+
+/*
+ * data will hold a struct pointer containing more differences once we support
+ * more controller variants
+ */
+static const struct of_device_id qcom_nandc_of_match[] = {
+	{
+		.compatible = "qcom,ipq806x-nand",
+		.data = &ipq806x_nandc_props,
+	},
+	{
+		.compatible = "qcom,ipq4019-nand",
+		.data = &ipq4019_nandc_props,
+	},
+	{
+		.compatible = "qcom,ipq8074-nand",
+		.data = &ipq8074_nandc_props,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
+
+static struct platform_driver qcom_nandc_driver = {
+	.driver = {
+		.name = "qcom-nandc",
+		.of_match_table = qcom_nandc_of_match,
+	},
+	.probe   = qcom_nandc_probe,
+	.remove  = qcom_nandc_remove,
+};
+module_platform_driver(qcom_nandc_driver);
+
+MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
new file mode 100644
index 000000000000..595635b9e9de
--- /dev/null
+++ b/drivers/mtd/nand/raw/r852.c
@@ -0,0 +1,1079 @@
+/*
+ * Copyright © 2009 - Maxim Levitsky
+ * driver for Ricoh xD readers
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+#include <linux/sched.h>
+#include "sm_common.h"
+#include "r852.h"
+
+
+static bool r852_enable_dma = 1;
+module_param(r852_enable_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)");
+
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+/* read register */
+static inline uint8_t r852_read_reg(struct r852_device *dev, int address)
+{
+	uint8_t reg = readb(dev->mmio + address);
+	return reg;
+}
+
+/* write register */
+static inline void r852_write_reg(struct r852_device *dev,
+						int address, uint8_t value)
+{
+	writeb(value, dev->mmio + address);
+	mmiowb();
+}
+
+
+/* read dword sized register */
+static inline uint32_t r852_read_reg_dword(struct r852_device *dev, int address)
+{
+	uint32_t reg = le32_to_cpu(readl(dev->mmio + address));
+	return reg;
+}
+
+/* write dword sized register */
+static inline void r852_write_reg_dword(struct r852_device *dev,
+							int address, uint32_t value)
+{
+	writel(cpu_to_le32(value), dev->mmio + address);
+	mmiowb();
+}
+
+/* returns pointer to our private structure */
+static inline struct r852_device *r852_get_dev(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	return nand_get_controller_data(chip);
+}
+
+
+/* check if controller supports dma */
+static void r852_dma_test(struct r852_device *dev)
+{
+	dev->dma_usable = (r852_read_reg(dev, R852_DMA_CAP) &
+		(R852_DMA1 | R852_DMA2)) == (R852_DMA1 | R852_DMA2);
+
+	if (!dev->dma_usable)
+		message("Non dma capable device detected, dma disabled");
+
+	if (!r852_enable_dma) {
+		message("disabling dma on user request");
+		dev->dma_usable = 0;
+	}
+}
+
+/*
+ * Enable dma. Enables ether first or second stage of the DMA,
+ * Expects dev->dma_dir and dev->dma_state be set
+ */
+static void r852_dma_enable(struct r852_device *dev)
+{
+	uint8_t dma_reg, dma_irq_reg;
+
+	/* Set up dma settings */
+	dma_reg = r852_read_reg_dword(dev, R852_DMA_SETTINGS);
+	dma_reg &= ~(R852_DMA_READ | R852_DMA_INTERNAL | R852_DMA_MEMORY);
+
+	if (dev->dma_dir)
+		dma_reg |= R852_DMA_READ;
+
+	if (dev->dma_state == DMA_INTERNAL) {
+		dma_reg |= R852_DMA_INTERNAL;
+		/* Precaution to make sure HW doesn't write */
+			/* to random kernel memory */
+		r852_write_reg_dword(dev, R852_DMA_ADDR,
+			cpu_to_le32(dev->phys_bounce_buffer));
+	} else {
+		dma_reg |= R852_DMA_MEMORY;
+		r852_write_reg_dword(dev, R852_DMA_ADDR,
+			cpu_to_le32(dev->phys_dma_addr));
+	}
+
+	/* Precaution: make sure write reached the device */
+	r852_read_reg_dword(dev, R852_DMA_ADDR);
+
+	r852_write_reg_dword(dev, R852_DMA_SETTINGS, dma_reg);
+
+	/* Set dma irq */
+	dma_irq_reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
+	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
+		dma_irq_reg |
+		R852_DMA_IRQ_INTERNAL |
+		R852_DMA_IRQ_ERROR |
+		R852_DMA_IRQ_MEMORY);
+}
+
+/*
+ * Disable dma, called from the interrupt handler, which specifies
+ * success of the operation via 'error' argument
+ */
+static void r852_dma_done(struct r852_device *dev, int error)
+{
+	WARN_ON(dev->dma_stage == 0);
+
+	r852_write_reg_dword(dev, R852_DMA_IRQ_STA,
+			r852_read_reg_dword(dev, R852_DMA_IRQ_STA));
+
+	r852_write_reg_dword(dev, R852_DMA_SETTINGS, 0);
+	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE, 0);
+
+	/* Precaution to make sure HW doesn't write to random kernel memory */
+	r852_write_reg_dword(dev, R852_DMA_ADDR,
+		cpu_to_le32(dev->phys_bounce_buffer));
+	r852_read_reg_dword(dev, R852_DMA_ADDR);
+
+	dev->dma_error = error;
+	dev->dma_stage = 0;
+
+	if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer)
+		pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN,
+			dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+}
+
+/*
+ * Wait, till dma is done, which includes both phases of it
+ */
+static int r852_dma_wait(struct r852_device *dev)
+{
+	long timeout = wait_for_completion_timeout(&dev->dma_done,
+				msecs_to_jiffies(1000));
+	if (!timeout) {
+		dbg("timeout waiting for DMA interrupt");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/*
+ * Read/Write one page using dma. Only pages can be read (512 bytes)
+*/
+static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
+{
+	int bounce = 0;
+	unsigned long flags;
+	int error;
+
+	dev->dma_error = 0;
+
+	/* Set dma direction */
+	dev->dma_dir = do_read;
+	dev->dma_stage = 1;
+	reinit_completion(&dev->dma_done);
+
+	dbg_verbose("doing dma %s ", do_read ? "read" : "write");
+
+	/* Set initial dma state: for reading first fill on board buffer,
+	  from device, for writes first fill the buffer  from memory*/
+	dev->dma_state = do_read ? DMA_INTERNAL : DMA_MEMORY;
+
+	/* if incoming buffer is not page aligned, we should do bounce */
+	if ((unsigned long)buf & (R852_DMA_LEN-1))
+		bounce = 1;
+
+	if (!bounce) {
+		dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf,
+			R852_DMA_LEN,
+			(do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
+
+		if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr))
+			bounce = 1;
+	}
+
+	if (bounce) {
+		dbg_verbose("dma: using bounce buffer");
+		dev->phys_dma_addr = dev->phys_bounce_buffer;
+		if (!do_read)
+			memcpy(dev->bounce_buffer, buf, R852_DMA_LEN);
+	}
+
+	/* Enable DMA */
+	spin_lock_irqsave(&dev->irqlock, flags);
+	r852_dma_enable(dev);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+
+	/* Wait till complete */
+	error = r852_dma_wait(dev);
+
+	if (error) {
+		r852_dma_done(dev, error);
+		return;
+	}
+
+	if (do_read && bounce)
+		memcpy((void *)buf, dev->bounce_buffer, R852_DMA_LEN);
+}
+
+/*
+ * Program data lines of the nand chip to send data to it
+ */
+static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+	uint32_t reg;
+
+	/* Don't allow any access to hardware if we suspect card removal */
+	if (dev->card_unstable)
+		return;
+
+	/* Special case for whole sector read */
+	if (len == R852_DMA_LEN && dev->dma_usable) {
+		r852_do_dma(dev, (uint8_t *)buf, 0);
+		return;
+	}
+
+	/* write DWORD chinks - faster */
+	while (len >= 4) {
+		reg = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+		r852_write_reg_dword(dev, R852_DATALINE, reg);
+		buf += 4;
+		len -= 4;
+
+	}
+
+	/* write rest */
+	while (len > 0) {
+		r852_write_reg(dev, R852_DATALINE, *buf++);
+		len--;
+	}
+}
+
+/*
+ * Read data lines of the nand chip to retrieve data
+ */
+static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+	uint32_t reg;
+
+	if (dev->card_unstable) {
+		/* since we can't signal error here, at least, return
+			predictable buffer */
+		memset(buf, 0, len);
+		return;
+	}
+
+	/* special case for whole sector read */
+	if (len == R852_DMA_LEN && dev->dma_usable) {
+		r852_do_dma(dev, buf, 1);
+		return;
+	}
+
+	/* read in dword sized chunks */
+	while (len >= 4) {
+
+		reg = r852_read_reg_dword(dev, R852_DATALINE);
+		*buf++ = reg & 0xFF;
+		*buf++ = (reg >> 8) & 0xFF;
+		*buf++ = (reg >> 16) & 0xFF;
+		*buf++ = (reg >> 24) & 0xFF;
+		len -= 4;
+	}
+
+	/* read the reset by bytes */
+	while (len--)
+		*buf++ = r852_read_reg(dev, R852_DATALINE);
+}
+
+/*
+ * Read one byte from nand chip
+ */
+static uint8_t r852_read_byte(struct mtd_info *mtd)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+
+	/* Same problem as in r852_read_buf.... */
+	if (dev->card_unstable)
+		return 0;
+
+	return r852_read_reg(dev, R852_DATALINE);
+}
+
+/*
+ * Control several chip lines & send commands
+ */
+static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+
+	if (dev->card_unstable)
+		return;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+
+		dev->ctlreg &= ~(R852_CTL_DATA | R852_CTL_COMMAND |
+				 R852_CTL_ON | R852_CTL_CARDENABLE);
+
+		if (ctrl & NAND_ALE)
+			dev->ctlreg |= R852_CTL_DATA;
+
+		if (ctrl & NAND_CLE)
+			dev->ctlreg |= R852_CTL_COMMAND;
+
+		if (ctrl & NAND_NCE)
+			dev->ctlreg |= (R852_CTL_CARDENABLE | R852_CTL_ON);
+		else
+			dev->ctlreg &= ~R852_CTL_WRITE;
+
+		/* when write is stareted, enable write access */
+		if (dat == NAND_CMD_ERASE1)
+			dev->ctlreg |= R852_CTL_WRITE;
+
+		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+	}
+
+	 /* HACK: NAND_CMD_SEQIN is called without NAND_CTRL_CHANGE, but we need
+		to set write mode */
+	if (dat == NAND_CMD_SEQIN && (dev->ctlreg & R852_CTL_COMMAND)) {
+		dev->ctlreg |= R852_CTL_WRITE;
+		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+	}
+
+	if (dat != NAND_CMD_NONE)
+		r852_write_reg(dev, R852_DATALINE, dat);
+}
+
+/*
+ * Wait till card is ready.
+ * based on nand_wait, but returns errors on DMA error
+ */
+static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct r852_device *dev = nand_get_controller_data(chip);
+
+	unsigned long timeout;
+	u8 status;
+
+	timeout = jiffies + (chip->state == FL_ERASING ?
+		msecs_to_jiffies(400) : msecs_to_jiffies(20));
+
+	while (time_before(jiffies, timeout))
+		if (chip->dev_ready(mtd))
+			break;
+
+	nand_status_op(chip, &status);
+
+	/* Unfortunelly, no way to send detailed error status... */
+	if (dev->dma_error) {
+		status |= NAND_STATUS_FAIL;
+		dev->dma_error = 0;
+	}
+	return status;
+}
+
+/*
+ * Check if card is ready
+ */
+
+static int r852_ready(struct mtd_info *mtd)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+	return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
+}
+
+
+/*
+ * Set ECC engine mode
+*/
+
+static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+
+	if (dev->card_unstable)
+		return;
+
+	switch (mode) {
+	case NAND_ECC_READ:
+	case NAND_ECC_WRITE:
+		/* enable ecc generation/check*/
+		dev->ctlreg |= R852_CTL_ECC_ENABLE;
+
+		/* flush ecc buffer */
+		r852_write_reg(dev, R852_CTL,
+			dev->ctlreg | R852_CTL_ECC_ACCESS);
+
+		r852_read_reg_dword(dev, R852_DATALINE);
+		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+		return;
+
+	case NAND_ECC_READSYN:
+		/* disable ecc generation */
+		dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
+		r852_write_reg(dev, R852_CTL, dev->ctlreg);
+	}
+}
+
+/*
+ * Calculate ECC, only used for writes
+ */
+
+static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
+							uint8_t *ecc_code)
+{
+	struct r852_device *dev = r852_get_dev(mtd);
+	struct sm_oob *oob = (struct sm_oob *)ecc_code;
+	uint32_t ecc1, ecc2;
+
+	if (dev->card_unstable)
+		return 0;
+
+	dev->ctlreg &= ~R852_CTL_ECC_ENABLE;
+	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
+
+	ecc1 = r852_read_reg_dword(dev, R852_DATALINE);
+	ecc2 = r852_read_reg_dword(dev, R852_DATALINE);
+
+	oob->ecc1[0] = (ecc1) & 0xFF;
+	oob->ecc1[1] = (ecc1 >> 8) & 0xFF;
+	oob->ecc1[2] = (ecc1 >> 16) & 0xFF;
+
+	oob->ecc2[0] = (ecc2) & 0xFF;
+	oob->ecc2[1] = (ecc2 >> 8) & 0xFF;
+	oob->ecc2[2] = (ecc2 >> 16) & 0xFF;
+
+	r852_write_reg(dev, R852_CTL, dev->ctlreg);
+	return 0;
+}
+
+/*
+ * Correct the data using ECC, hw did almost everything for us
+ */
+
+static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
+				uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+	uint32_t ecc_reg;
+	uint8_t ecc_status, err_byte;
+	int i, error = 0;
+
+	struct r852_device *dev = r852_get_dev(mtd);
+
+	if (dev->card_unstable)
+		return 0;
+
+	if (dev->dma_error) {
+		dev->dma_error = 0;
+		return -EIO;
+	}
+
+	r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
+	ecc_reg = r852_read_reg_dword(dev, R852_DATALINE);
+	r852_write_reg(dev, R852_CTL, dev->ctlreg);
+
+	for (i = 0 ; i <= 1 ; i++) {
+
+		ecc_status = (ecc_reg >> 8) & 0xFF;
+
+		/* ecc uncorrectable error */
+		if (ecc_status & R852_ECC_FAIL) {
+			dbg("ecc: unrecoverable error, in half %d", i);
+			error = -EBADMSG;
+			goto exit;
+		}
+
+		/* correctable error */
+		if (ecc_status & R852_ECC_CORRECTABLE) {
+
+			err_byte = ecc_reg & 0xFF;
+			dbg("ecc: recoverable error, "
+				"in half %d, byte %d, bit %d", i,
+				err_byte, ecc_status & R852_ECC_ERR_BIT_MSK);
+
+			dat[err_byte] ^=
+				1 << (ecc_status & R852_ECC_ERR_BIT_MSK);
+			error++;
+		}
+
+		dat += 256;
+		ecc_reg >>= 16;
+	}
+exit:
+	return error;
+}
+
+/*
+ * This is copy of nand_read_oob_std
+ * nand_read_oob_syndrome assumes we can send column address - we can't
+ */
+static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			     int page)
+{
+	return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
+}
+
+/*
+ * Start the nand engine
+ */
+
+static void r852_engine_enable(struct r852_device *dev)
+{
+	if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
+		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
+		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
+	} else {
+		r852_write_reg_dword(dev, R852_HW, R852_HW_ENABLED);
+		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
+	}
+	msleep(300);
+	r852_write_reg(dev, R852_CTL, 0);
+}
+
+
+/*
+ * Stop the nand engine
+ */
+
+static void r852_engine_disable(struct r852_device *dev)
+{
+	r852_write_reg_dword(dev, R852_HW, 0);
+	r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
+}
+
+/*
+ * Test if card is present
+ */
+
+static void r852_card_update_present(struct r852_device *dev)
+{
+	unsigned long flags;
+	uint8_t reg;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	reg = r852_read_reg(dev, R852_CARD_STA);
+	dev->card_detected = !!(reg & R852_CARD_STA_PRESENT);
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+}
+
+/*
+ * Update card detection IRQ state according to current card state
+ * which is read in r852_card_update_present
+ */
+static void r852_update_card_detect(struct r852_device *dev)
+{
+	int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
+	dev->card_unstable = 0;
+
+	card_detect_reg &= ~(R852_CARD_IRQ_REMOVE | R852_CARD_IRQ_INSERT);
+	card_detect_reg |= R852_CARD_IRQ_GENABLE;
+
+	card_detect_reg |= dev->card_detected ?
+		R852_CARD_IRQ_REMOVE : R852_CARD_IRQ_INSERT;
+
+	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
+}
+
+static ssize_t r852_media_type_show(struct device *sys_dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
+	struct r852_device *dev = r852_get_dev(mtd);
+	char *data = dev->sm ? "smartmedia" : "xd";
+
+	strcpy(buf, data);
+	return strlen(data);
+}
+
+static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
+
+
+/* Detect properties of card in slot */
+static void r852_update_media_status(struct r852_device *dev)
+{
+	uint8_t reg;
+	unsigned long flags;
+	int readonly;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+	if (!dev->card_detected) {
+		message("card removed");
+		spin_unlock_irqrestore(&dev->irqlock, flags);
+		return ;
+	}
+
+	readonly  = r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_RO;
+	reg = r852_read_reg(dev, R852_DMA_CAP);
+	dev->sm = (reg & (R852_DMA1 | R852_DMA2)) && (reg & R852_SMBIT);
+
+	message("detected %s %s card in slot",
+		dev->sm ? "SmartMedia" : "xD",
+		readonly ? "readonly" : "writeable");
+
+	dev->readonly = readonly;
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+}
+
+/*
+ * Register the nand device
+ * Called when the card is detected
+ */
+static int r852_register_nand_device(struct r852_device *dev)
+{
+	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+
+	WARN_ON(dev->card_registred);
+
+	mtd->dev.parent = &dev->pci_dev->dev;
+
+	if (dev->readonly)
+		dev->chip->options |= NAND_ROM;
+
+	r852_engine_enable(dev);
+
+	if (sm_register_device(mtd, dev->sm))
+		goto error1;
+
+	if (device_create_file(&mtd->dev, &dev_attr_media_type)) {
+		message("can't create media type sysfs attribute");
+		goto error3;
+	}
+
+	dev->card_registred = 1;
+	return 0;
+error3:
+	nand_release(mtd);
+error1:
+	/* Force card redetect */
+	dev->card_detected = 0;
+	return -1;
+}
+
+/*
+ * Unregister the card
+ */
+
+static void r852_unregister_nand_device(struct r852_device *dev)
+{
+	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+
+	if (!dev->card_registred)
+		return;
+
+	device_remove_file(&mtd->dev, &dev_attr_media_type);
+	nand_release(mtd);
+	r852_engine_disable(dev);
+	dev->card_registred = 0;
+}
+
+/* Card state updater */
+static void r852_card_detect_work(struct work_struct *work)
+{
+	struct r852_device *dev =
+		container_of(work, struct r852_device, card_detect_work.work);
+
+	r852_card_update_present(dev);
+	r852_update_card_detect(dev);
+	dev->card_unstable = 0;
+
+	/* False alarm */
+	if (dev->card_detected == dev->card_registred)
+		goto exit;
+
+	/* Read media properties */
+	r852_update_media_status(dev);
+
+	/* Register the card */
+	if (dev->card_detected)
+		r852_register_nand_device(dev);
+	else
+		r852_unregister_nand_device(dev);
+exit:
+	r852_update_card_detect(dev);
+}
+
+/* Ack + disable IRQ generation */
+static void r852_disable_irqs(struct r852_device *dev)
+{
+	uint8_t reg;
+	reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
+	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, reg & ~R852_CARD_IRQ_MASK);
+
+	reg = r852_read_reg_dword(dev, R852_DMA_IRQ_ENABLE);
+	r852_write_reg_dword(dev, R852_DMA_IRQ_ENABLE,
+					reg & ~R852_DMA_IRQ_MASK);
+
+	r852_write_reg(dev, R852_CARD_IRQ_STA, R852_CARD_IRQ_MASK);
+	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, R852_DMA_IRQ_MASK);
+}
+
+/* Interrupt handler */
+static irqreturn_t r852_irq(int irq, void *data)
+{
+	struct r852_device *dev = (struct r852_device *)data;
+
+	uint8_t card_status, dma_status;
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+
+	/* handle card detection interrupts first */
+	card_status = r852_read_reg(dev, R852_CARD_IRQ_STA);
+	r852_write_reg(dev, R852_CARD_IRQ_STA, card_status);
+
+	if (card_status & (R852_CARD_IRQ_INSERT|R852_CARD_IRQ_REMOVE)) {
+
+		ret = IRQ_HANDLED;
+		dev->card_detected = !!(card_status & R852_CARD_IRQ_INSERT);
+
+		/* we shouldn't receive any interrupts if we wait for card
+			to settle */
+		WARN_ON(dev->card_unstable);
+
+		/* disable irqs while card is unstable */
+		/* this will timeout DMA if active, but better that garbage */
+		r852_disable_irqs(dev);
+
+		if (dev->card_unstable)
+			goto out;
+
+		/* let, card state to settle a bit, and then do the work */
+		dev->card_unstable = 1;
+		queue_delayed_work(dev->card_workqueue,
+			&dev->card_detect_work, msecs_to_jiffies(100));
+		goto out;
+	}
+
+
+	/* Handle dma interrupts */
+	dma_status = r852_read_reg_dword(dev, R852_DMA_IRQ_STA);
+	r852_write_reg_dword(dev, R852_DMA_IRQ_STA, dma_status);
+
+	if (dma_status & R852_DMA_IRQ_MASK) {
+
+		ret = IRQ_HANDLED;
+
+		if (dma_status & R852_DMA_IRQ_ERROR) {
+			dbg("received dma error IRQ");
+			r852_dma_done(dev, -EIO);
+			complete(&dev->dma_done);
+			goto out;
+		}
+
+		/* received DMA interrupt out of nowhere? */
+		WARN_ON_ONCE(dev->dma_stage == 0);
+
+		if (dev->dma_stage == 0)
+			goto out;
+
+		/* done device access */
+		if (dev->dma_state == DMA_INTERNAL &&
+				(dma_status & R852_DMA_IRQ_INTERNAL)) {
+
+			dev->dma_state = DMA_MEMORY;
+			dev->dma_stage++;
+		}
+
+		/* done memory DMA */
+		if (dev->dma_state == DMA_MEMORY &&
+				(dma_status & R852_DMA_IRQ_MEMORY)) {
+			dev->dma_state = DMA_INTERNAL;
+			dev->dma_stage++;
+		}
+
+		/* Enable 2nd half of dma dance */
+		if (dev->dma_stage == 2)
+			r852_dma_enable(dev);
+
+		/* Operation done */
+		if (dev->dma_stage == 3) {
+			r852_dma_done(dev, 0);
+			complete(&dev->dma_done);
+		}
+		goto out;
+	}
+
+	/* Handle unknown interrupts */
+	if (dma_status)
+		dbg("bad dma IRQ status = %x", dma_status);
+
+	if (card_status & ~R852_CARD_STA_CD)
+		dbg("strange card status = %x", card_status);
+
+out:
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	return ret;
+}
+
+static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+{
+	int error;
+	struct nand_chip *chip;
+	struct r852_device *dev;
+
+	/* pci initialization */
+	error = pci_enable_device(pci_dev);
+
+	if (error)
+		goto error1;
+
+	pci_set_master(pci_dev);
+
+	error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+	if (error)
+		goto error2;
+
+	error = pci_request_regions(pci_dev, DRV_NAME);
+
+	if (error)
+		goto error3;
+
+	error = -ENOMEM;
+
+	/* init nand chip, but register it only on card insert */
+	chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+
+	if (!chip)
+		goto error4;
+
+	/* commands */
+	chip->cmd_ctrl = r852_cmdctl;
+	chip->waitfunc = r852_wait;
+	chip->dev_ready = r852_ready;
+
+	/* I/O */
+	chip->read_byte = r852_read_byte;
+	chip->read_buf = r852_read_buf;
+	chip->write_buf = r852_write_buf;
+
+	/* ecc */
+	chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+	chip->ecc.size = R852_DMA_LEN;
+	chip->ecc.bytes = SM_OOB_SIZE;
+	chip->ecc.strength = 2;
+	chip->ecc.hwctl = r852_ecc_hwctl;
+	chip->ecc.calculate = r852_ecc_calculate;
+	chip->ecc.correct = r852_ecc_correct;
+
+	/* TODO: hack */
+	chip->ecc.read_oob = r852_read_oob;
+
+	/* init our device structure */
+	dev = kzalloc(sizeof(struct r852_device), GFP_KERNEL);
+
+	if (!dev)
+		goto error5;
+
+	nand_set_controller_data(chip, dev);
+	dev->chip = chip;
+	dev->pci_dev = pci_dev;
+	pci_set_drvdata(pci_dev, dev);
+
+	dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN,
+		&dev->phys_bounce_buffer);
+
+	if (!dev->bounce_buffer)
+		goto error6;
+
+
+	error = -ENODEV;
+	dev->mmio = pci_ioremap_bar(pci_dev, 0);
+
+	if (!dev->mmio)
+		goto error7;
+
+	error = -ENOMEM;
+	dev->tmp_buffer = kzalloc(SM_SECTOR_SIZE, GFP_KERNEL);
+
+	if (!dev->tmp_buffer)
+		goto error8;
+
+	init_completion(&dev->dma_done);
+
+	dev->card_workqueue = create_freezable_workqueue(DRV_NAME);
+
+	if (!dev->card_workqueue)
+		goto error9;
+
+	INIT_DELAYED_WORK(&dev->card_detect_work, r852_card_detect_work);
+
+	/* shutdown everything - precation */
+	r852_engine_disable(dev);
+	r852_disable_irqs(dev);
+
+	r852_dma_test(dev);
+
+	dev->irq = pci_dev->irq;
+	spin_lock_init(&dev->irqlock);
+
+	dev->card_detected = 0;
+	r852_card_update_present(dev);
+
+	/*register irq handler*/
+	error = -ENODEV;
+	if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED,
+			  DRV_NAME, dev))
+		goto error10;
+
+	/* kick initial present test */
+	queue_delayed_work(dev->card_workqueue,
+		&dev->card_detect_work, 0);
+
+
+	printk(KERN_NOTICE DRV_NAME ": driver loaded successfully\n");
+	return 0;
+
+error10:
+	destroy_workqueue(dev->card_workqueue);
+error9:
+	kfree(dev->tmp_buffer);
+error8:
+	pci_iounmap(pci_dev, dev->mmio);
+error7:
+	pci_free_consistent(pci_dev, R852_DMA_LEN,
+		dev->bounce_buffer, dev->phys_bounce_buffer);
+error6:
+	kfree(dev);
+error5:
+	kfree(chip);
+error4:
+	pci_release_regions(pci_dev);
+error3:
+error2:
+	pci_disable_device(pci_dev);
+error1:
+	return error;
+}
+
+static void r852_remove(struct pci_dev *pci_dev)
+{
+	struct r852_device *dev = pci_get_drvdata(pci_dev);
+
+	/* Stop detect workqueue -
+		we are going to unregister the device anyway*/
+	cancel_delayed_work_sync(&dev->card_detect_work);
+	destroy_workqueue(dev->card_workqueue);
+
+	/* Unregister the device, this might make more IO */
+	r852_unregister_nand_device(dev);
+
+	/* Stop interrupts */
+	r852_disable_irqs(dev);
+	free_irq(dev->irq, dev);
+
+	/* Cleanup */
+	kfree(dev->tmp_buffer);
+	pci_iounmap(pci_dev, dev->mmio);
+	pci_free_consistent(pci_dev, R852_DMA_LEN,
+		dev->bounce_buffer, dev->phys_bounce_buffer);
+
+	kfree(dev->chip);
+	kfree(dev);
+
+	/* Shutdown the PCI device */
+	pci_release_regions(pci_dev);
+	pci_disable_device(pci_dev);
+}
+
+static void r852_shutdown(struct pci_dev *pci_dev)
+{
+	struct r852_device *dev = pci_get_drvdata(pci_dev);
+
+	cancel_delayed_work_sync(&dev->card_detect_work);
+	r852_disable_irqs(dev);
+	synchronize_irq(dev->irq);
+	pci_disable_device(pci_dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int r852_suspend(struct device *device)
+{
+	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
+
+	if (dev->ctlreg & R852_CTL_CARDENABLE)
+		return -EBUSY;
+
+	/* First make sure the detect work is gone */
+	cancel_delayed_work_sync(&dev->card_detect_work);
+
+	/* Turn off the interrupts and stop the device */
+	r852_disable_irqs(dev);
+	r852_engine_disable(dev);
+
+	/* If card was pulled off just during the suspend, which is very
+		unlikely, we will remove it on resume, it too late now
+		anyway... */
+	dev->card_unstable = 0;
+	return 0;
+}
+
+static int r852_resume(struct device *device)
+{
+	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
+	struct mtd_info *mtd = nand_to_mtd(dev->chip);
+
+	r852_disable_irqs(dev);
+	r852_card_update_present(dev);
+	r852_engine_disable(dev);
+
+
+	/* If card status changed, just do the work */
+	if (dev->card_detected != dev->card_registred) {
+		dbg("card was %s during low power state",
+			dev->card_detected ? "added" : "removed");
+
+		queue_delayed_work(dev->card_workqueue,
+		&dev->card_detect_work, msecs_to_jiffies(1000));
+		return 0;
+	}
+
+	/* Otherwise, initialize the card */
+	if (dev->card_registred) {
+		r852_engine_enable(dev);
+		dev->chip->select_chip(mtd, 0);
+		nand_reset_op(dev->chip);
+		dev->chip->select_chip(mtd, -1);
+	}
+
+	/* Program card detection IRQ */
+	r852_update_card_detect(dev);
+	return 0;
+}
+#endif
+
+static const struct pci_device_id r852_pci_id_tbl[] = {
+
+	{ PCI_VDEVICE(RICOH, 0x0852), },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl);
+
+static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume);
+
+static struct pci_driver r852_pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= r852_pci_id_tbl,
+	.probe		= r852_probe,
+	.remove		= r852_remove,
+	.shutdown	= r852_shutdown,
+	.driver.pm	= &r852_pm_ops,
+};
+
+module_pci_driver(r852_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
+MODULE_DESCRIPTION("Ricoh 85xx xD/smartmedia card reader driver");
diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h
new file mode 100644
index 000000000000..8713c57f6207
--- /dev/null
+++ b/drivers/mtd/nand/raw/r852.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2009 - Maxim Levitsky
+ * driver for Ricoh xD readers
+ *
+ * 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/pci.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/spinlock.h>
+
+
+/* nand interface + ecc
+   byte write/read does one cycle on nand data lines.
+   dword write/read does 4 cycles
+   if R852_CTL_ECC_ACCESS is set in R852_CTL, then dword read reads
+   results of ecc correction, if DMA read was done before.
+   If write was done two dword reads read generated ecc checksums
+*/
+#define	R852_DATALINE		0x00
+
+/* control register */
+#define R852_CTL		0x04
+#define R852_CTL_COMMAND 	0x01	/* send command (#CLE)*/
+#define R852_CTL_DATA		0x02	/* read/write data (#ALE)*/
+#define R852_CTL_ON		0x04	/* only seem to controls the hd led, */
+					/* but has to be set on start...*/
+#define R852_CTL_RESET		0x08	/* unknown, set only on start once*/
+#define R852_CTL_CARDENABLE	0x10	/* probably (#CE) - always set*/
+#define R852_CTL_ECC_ENABLE	0x20	/* enable ecc engine */
+#define R852_CTL_ECC_ACCESS	0x40	/* read/write ecc via reg #0*/
+#define R852_CTL_WRITE		0x80	/* set when performing writes (#WP) */
+
+/* card detection status */
+#define R852_CARD_STA		0x05
+
+#define R852_CARD_STA_CD	0x01	/* state of #CD line, same as 0x04 */
+#define R852_CARD_STA_RO	0x02	/* card is readonly */
+#define R852_CARD_STA_PRESENT	0x04	/* card is present (#CD) */
+#define R852_CARD_STA_ABSENT	0x08	/* card is absent */
+#define R852_CARD_STA_BUSY	0x80	/* card is busy - (#R/B) */
+
+/* card detection irq status & enable*/
+#define R852_CARD_IRQ_STA	0x06	/* IRQ status */
+#define R852_CARD_IRQ_ENABLE	0x07	/* IRQ enable */
+
+#define R852_CARD_IRQ_CD	0x01	/* fire when #CD lights, same as 0x04*/
+#define R852_CARD_IRQ_REMOVE	0x04	/* detect card removal */
+#define R852_CARD_IRQ_INSERT	0x08	/* detect card insert */
+#define R852_CARD_IRQ_UNK1	0x10	/* unknown */
+#define R852_CARD_IRQ_GENABLE	0x80	/* general enable */
+#define R852_CARD_IRQ_MASK	0x1D
+
+
+
+/* hardware enable */
+#define R852_HW			0x08
+#define R852_HW_ENABLED		0x01	/* hw enabled */
+#define R852_HW_UNKNOWN		0x80
+
+
+/* dma capabilities */
+#define R852_DMA_CAP		0x09
+#define R852_SMBIT		0x20	/* if set with bit #6 or bit #7, then */
+					/* hw is smartmedia */
+#define R852_DMA1		0x40	/* if set w/bit #7, dma is supported */
+#define R852_DMA2		0x80	/* if set w/bit #6, dma is supported */
+
+
+/* physical DMA address - 32 bit value*/
+#define R852_DMA_ADDR		0x0C
+
+
+/* dma settings */
+#define R852_DMA_SETTINGS	0x10
+#define R852_DMA_MEMORY		0x01	/* (memory <-> internal hw buffer) */
+#define R852_DMA_READ		0x02	/* 0 = write, 1 = read */
+#define R852_DMA_INTERNAL	0x04	/* (internal hw buffer <-> card) */
+
+/* dma IRQ status */
+#define R852_DMA_IRQ_STA		0x14
+
+/* dma IRQ enable */
+#define R852_DMA_IRQ_ENABLE	0x18
+
+#define R852_DMA_IRQ_MEMORY	0x01	/* (memory <-> internal hw buffer) */
+#define R852_DMA_IRQ_ERROR	0x02	/* error did happen */
+#define R852_DMA_IRQ_INTERNAL	0x04	/* (internal hw buffer <-> card) */
+#define R852_DMA_IRQ_MASK	0x07	/* mask of all IRQ bits */
+
+
+/* ECC syndrome format - read from reg #0 will return two copies of these for
+   each half of the page.
+   first byte is error byte location, and second, bit location + flags */
+#define R852_ECC_ERR_BIT_MSK	0x07	/* error bit location */
+#define R852_ECC_CORRECT		0x10	/* no errors - (guessed) */
+#define R852_ECC_CORRECTABLE	0x20	/* correctable error exist */
+#define R852_ECC_FAIL		0x40	/* non correctable error detected */
+
+#define R852_DMA_LEN		512
+
+#define DMA_INTERNAL	0
+#define DMA_MEMORY	1
+
+struct r852_device {
+	void __iomem *mmio;		/* mmio */
+	struct nand_chip *chip;		/* nand chip backpointer */
+	struct pci_dev *pci_dev;	/* pci backpointer */
+
+	/* dma area */
+	dma_addr_t phys_dma_addr;	/* bus address of buffer*/
+	struct completion dma_done;	/* data transfer done */
+
+	dma_addr_t phys_bounce_buffer;	/* bus address of bounce buffer */
+	uint8_t *bounce_buffer;		/* virtual address of bounce buffer */
+
+	int dma_dir;			/* 1 = read, 0 = write */
+	int dma_stage;			/* 0 - idle, 1 - first step,
+					   2 - second step */
+
+	int dma_state;			/* 0 = internal, 1 = memory */
+	int dma_error;			/* dma errors */
+	int dma_usable;			/* is it possible to use dma */
+
+	/* card status area */
+	struct delayed_work card_detect_work;
+	struct workqueue_struct *card_workqueue;
+	int card_registred;		/* card registered with mtd */
+	int card_detected;		/* card detected in slot */
+	int card_unstable;		/* whenever the card is inserted,
+					   is not known yet */
+	int readonly;			/* card is readonly */
+	int sm;				/* Is card smartmedia */
+
+	/* interrupt handling */
+	spinlock_t irqlock;		/* IRQ protecting lock */
+	int irq;			/* irq num */
+	/* misc */
+	void *tmp_buffer;		/* temporary buffer */
+	uint8_t ctlreg;			/* cached contents of control reg */
+};
+
+#define DRV_NAME "r852"
+
+
+#define dbg(format, ...) \
+	if (debug) \
+		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
+
+#define dbg_verbose(format, ...) \
+	if (debug > 1) \
+		printk(KERN_DEBUG DRV_NAME ": " format "\n", ## __VA_ARGS__)
+
+
+#define message(format, ...) \
+	printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__)
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
new file mode 100644
index 000000000000..b5bc5f106c09
--- /dev/null
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -0,0 +1,1295 @@
+/*
+ * Copyright © 2004-2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2410/S3C2440/S3C2412 NAND driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#define pr_fmt(fmt) "nand-s3c2410: " fmt
+
+#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/platform_data/mtd-nand-s3c2410.h>
+
+#define S3C2410_NFREG(x) (x)
+
+#define S3C2410_NFCONF		S3C2410_NFREG(0x00)
+#define S3C2410_NFCMD		S3C2410_NFREG(0x04)
+#define S3C2410_NFADDR		S3C2410_NFREG(0x08)
+#define S3C2410_NFDATA		S3C2410_NFREG(0x0C)
+#define S3C2410_NFSTAT		S3C2410_NFREG(0x10)
+#define S3C2410_NFECC		S3C2410_NFREG(0x14)
+#define S3C2440_NFCONT		S3C2410_NFREG(0x04)
+#define S3C2440_NFCMD		S3C2410_NFREG(0x08)
+#define S3C2440_NFADDR		S3C2410_NFREG(0x0C)
+#define S3C2440_NFDATA		S3C2410_NFREG(0x10)
+#define S3C2440_NFSTAT		S3C2410_NFREG(0x20)
+#define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)
+#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
+#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
+#define S3C2410_NFCONF_EN		(1<<15)
+#define S3C2410_NFCONF_INITECC		(1<<12)
+#define S3C2410_NFCONF_nFCE		(1<<11)
+#define S3C2410_NFCONF_TACLS(x)		((x)<<8)
+#define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)
+#define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)
+#define S3C2410_NFSTAT_BUSY		(1<<0)
+#define S3C2440_NFCONF_TACLS(x)		((x)<<12)
+#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
+#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
+#define S3C2440_NFCONT_INITECC		(1<<4)
+#define S3C2440_NFCONT_nFCE		(1<<1)
+#define S3C2440_NFCONT_ENABLE		(1<<0)
+#define S3C2440_NFSTAT_READY		(1<<0)
+#define S3C2412_NFCONF_NANDBOOT		(1<<31)
+#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
+#define S3C2412_NFCONT_nFCE0		(1<<1)
+#define S3C2412_NFSTAT_READY		(1<<0)
+
+/* new oob placement block for use with hardware ecc generation
+ */
+static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = 3;
+
+	return 0;
+}
+
+static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = 8;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
+	.ecc = s3c2410_ooblayout_ecc,
+	.free = s3c2410_ooblayout_free,
+};
+
+/* controller and mtd information */
+
+struct s3c2410_nand_info;
+
+/**
+ * struct s3c2410_nand_mtd - driver MTD structure
+ * @mtd: The MTD instance to pass to the MTD layer.
+ * @chip: The NAND chip information.
+ * @set: The platform information supplied for this set of NAND chips.
+ * @info: Link back to the hardware information.
+ * @scan_res: The result from calling nand_scan_ident().
+*/
+struct s3c2410_nand_mtd {
+	struct nand_chip		chip;
+	struct s3c2410_nand_set		*set;
+	struct s3c2410_nand_info	*info;
+	int				scan_res;
+};
+
+enum s3c_cpu_type {
+	TYPE_S3C2410,
+	TYPE_S3C2412,
+	TYPE_S3C2440,
+};
+
+enum s3c_nand_clk_state {
+	CLOCK_DISABLE	= 0,
+	CLOCK_ENABLE,
+	CLOCK_SUSPEND,
+};
+
+/* overview of the s3c2410 nand state */
+
+/**
+ * struct s3c2410_nand_info - NAND controller state.
+ * @mtds: An array of MTD instances on this controoler.
+ * @platform: The platform data for this board.
+ * @device: The platform device we bound to.
+ * @clk: The clock resource for this controller.
+ * @regs: The area mapped for the hardware registers.
+ * @sel_reg: Pointer to the register controlling the NAND selection.
+ * @sel_bit: The bit in @sel_reg to select the NAND chip.
+ * @mtd_count: The number of MTDs created from this controller.
+ * @save_sel: The contents of @sel_reg to be saved over suspend.
+ * @clk_rate: The clock rate from @clk.
+ * @clk_state: The current clock state.
+ * @cpu_type: The exact type of this controller.
+ */
+struct s3c2410_nand_info {
+	/* mtd info */
+	struct nand_hw_control		controller;
+	struct s3c2410_nand_mtd		*mtds;
+	struct s3c2410_platform_nand	*platform;
+
+	/* device info */
+	struct device			*device;
+	struct clk			*clk;
+	void __iomem			*regs;
+	void __iomem			*sel_reg;
+	int				sel_bit;
+	int				mtd_count;
+	unsigned long			save_sel;
+	unsigned long			clk_rate;
+	enum s3c_nand_clk_state		clk_state;
+
+	enum s3c_cpu_type		cpu_type;
+
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
+	struct notifier_block	freq_transition;
+#endif
+};
+
+struct s3c24XX_nand_devtype_data {
+	enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+	.type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+	.type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+	.type = TYPE_S3C2440,
+};
+
+/* conversion functions */
+
+static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
+			    chip);
+}
+
+static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
+{
+	return s3c2410_nand_mtd_toours(mtd)->info;
+}
+
+static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
+{
+	return platform_get_drvdata(dev);
+}
+
+static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
+{
+	return dev_get_platdata(&dev->dev);
+}
+
+static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
+{
+#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
+ * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
+ * @info: The controller instance.
+ * @new_state: State to which clock should be set.
+ */
+static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
+		enum s3c_nand_clk_state new_state)
+{
+	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
+		return;
+
+	if (info->clk_state == CLOCK_ENABLE) {
+		if (new_state != CLOCK_ENABLE)
+			clk_disable_unprepare(info->clk);
+	} else {
+		if (new_state == CLOCK_ENABLE)
+			clk_prepare_enable(info->clk);
+	}
+
+	info->clk_state = new_state;
+}
+
+/* timing calculations */
+
+#define NS_IN_KHZ 1000000
+
+/**
+ * s3c_nand_calc_rate - calculate timing data.
+ * @wanted: The cycle time in nanoseconds.
+ * @clk: The clock rate in kHz.
+ * @max: The maximum divider value.
+ *
+ * Calculate the timing value from the given parameters.
+ */
+static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
+{
+	int result;
+
+	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
+
+	pr_debug("result %d from %ld, %d\n", result, clk, wanted);
+
+	if (result > max) {
+		pr_err("%d ns is too big for current clock rate %ld\n",
+			wanted, clk);
+		return -1;
+	}
+
+	if (result < 1)
+		result = 1;
+
+	return result;
+}
+
+#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
+
+/* controller setup */
+
+/**
+ * s3c2410_nand_setrate - setup controller timing information.
+ * @info: The controller instance.
+ *
+ * Given the information supplied by the platform, calculate and set
+ * the necessary timing registers in the hardware to generate the
+ * necessary timing cycles to the hardware.
+ */
+static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
+{
+	struct s3c2410_platform_nand *plat = info->platform;
+	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
+	int tacls, twrph0, twrph1;
+	unsigned long clkrate = clk_get_rate(info->clk);
+	unsigned long uninitialized_var(set), cfg, uninitialized_var(mask);
+	unsigned long flags;
+
+	/* calculate the timing information for the controller */
+
+	info->clk_rate = clkrate;
+	clkrate /= 1000;	/* turn clock into kHz for ease of use */
+
+	if (plat != NULL) {
+		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
+		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
+		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
+	} else {
+		/* default timings */
+		tacls = tacls_max;
+		twrph0 = 8;
+		twrph1 = 8;
+	}
+
+	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
+		dev_err(info->device, "cannot get suitable timings\n");
+		return -EINVAL;
+	}
+
+	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
+						twrph1, to_ns(twrph1, clkrate));
+
+	switch (info->cpu_type) {
+	case TYPE_S3C2410:
+		mask = (S3C2410_NFCONF_TACLS(3) |
+			S3C2410_NFCONF_TWRPH0(7) |
+			S3C2410_NFCONF_TWRPH1(7));
+		set = S3C2410_NFCONF_EN;
+		set |= S3C2410_NFCONF_TACLS(tacls - 1);
+		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
+		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
+		break;
+
+	case TYPE_S3C2440:
+	case TYPE_S3C2412:
+		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
+			S3C2440_NFCONF_TWRPH0(7) |
+			S3C2440_NFCONF_TWRPH1(7));
+
+		set = S3C2440_NFCONF_TACLS(tacls - 1);
+		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
+		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
+		break;
+
+	default:
+		BUG();
+	}
+
+	local_irq_save(flags);
+
+	cfg = readl(info->regs + S3C2410_NFCONF);
+	cfg &= ~mask;
+	cfg |= set;
+	writel(cfg, info->regs + S3C2410_NFCONF);
+
+	local_irq_restore(flags);
+
+	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
+
+	return 0;
+}
+
+/**
+ * s3c2410_nand_inithw - basic hardware initialisation
+ * @info: The hardware state.
+ *
+ * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
+ * to setup the hardware access speeds and set the controller to be enabled.
+*/
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
+{
+	int ret;
+
+	ret = s3c2410_nand_setrate(info);
+	if (ret < 0)
+		return ret;
+
+	switch (info->cpu_type) {
+	case TYPE_S3C2410:
+	default:
+		break;
+
+	case TYPE_S3C2440:
+	case TYPE_S3C2412:
+		/* enable the controller and de-assert nFCE */
+
+		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
+	}
+
+	return 0;
+}
+
+/**
+ * s3c2410_nand_select_chip - select the given nand chip
+ * @mtd: The MTD instance for this chip.
+ * @chip: The chip number.
+ *
+ * This is called by the MTD layer to either select a given chip for the
+ * @mtd instance, or to indicate that the access has finished and the
+ * chip can be de-selected.
+ *
+ * The routine ensures that the nFCE line is correctly setup, and any
+ * platform specific selection code is called to route nFCE to the specific
+ * chip.
+ */
+static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct s3c2410_nand_info *info;
+	struct s3c2410_nand_mtd *nmtd;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	unsigned long cur;
+
+	nmtd = nand_get_controller_data(this);
+	info = nmtd->info;
+
+	if (chip != -1)
+		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
+
+	cur = readl(info->sel_reg);
+
+	if (chip == -1) {
+		cur |= info->sel_bit;
+	} else {
+		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
+			dev_err(info->device, "invalid chip %d\n", chip);
+			return;
+		}
+
+		if (info->platform != NULL) {
+			if (info->platform->select_chip != NULL)
+				(info->platform->select_chip) (nmtd->set, chip);
+		}
+
+		cur &= ~info->sel_bit;
+	}
+
+	writel(cur, info->sel_reg);
+
+	if (chip == -1)
+		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
+}
+
+/* s3c2410_nand_hwcontrol
+ *
+ * Issue command and address cycles to the chip
+*/
+
+static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd, info->regs + S3C2410_NFCMD);
+	else
+		writeb(cmd, info->regs + S3C2410_NFADDR);
+}
+
+/* command and control functions */
+
+static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd, info->regs + S3C2440_NFCMD);
+	else
+		writeb(cmd, info->regs + S3C2440_NFADDR);
+}
+
+/* s3c2410_nand_devready()
+ *
+ * returns 0 if the nand is busy, 1 if it is ready
+*/
+
+static int s3c2410_nand_devready(struct mtd_info *mtd)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
+}
+
+static int s3c2440_nand_devready(struct mtd_info *mtd)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
+}
+
+static int s3c2412_nand_devready(struct mtd_info *mtd)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
+}
+
+/* ECC handling functions */
+
+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+				     u_char *read_ecc, u_char *calc_ecc)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	unsigned int diff0, diff1, diff2;
+	unsigned int bit, byte;
+
+	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
+
+	diff0 = read_ecc[0] ^ calc_ecc[0];
+	diff1 = read_ecc[1] ^ calc_ecc[1];
+	diff2 = read_ecc[2] ^ calc_ecc[2];
+
+	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
+		 __func__, 3, read_ecc, 3, calc_ecc,
+		 diff0, diff1, diff2);
+
+	if (diff0 == 0 && diff1 == 0 && diff2 == 0)
+		return 0;		/* ECC is ok */
+
+	/* sometimes people do not think about using the ECC, so check
+	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore
+	 * the error, on the assumption that this is an un-eccd page.
+	 */
+	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
+	    && info->platform->ignore_unset_ecc)
+		return 0;
+
+	/* Can we correct this ECC (ie, one row and column change).
+	 * Note, this is similar to the 256 error code on smartmedia */
+
+	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
+	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
+	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
+		/* calculate the bit position of the error */
+
+		bit  = ((diff2 >> 3) & 1) |
+		       ((diff2 >> 4) & 2) |
+		       ((diff2 >> 5) & 4);
+
+		/* calculate the byte position of the error */
+
+		byte = ((diff2 << 7) & 0x100) |
+		       ((diff1 << 0) & 0x80)  |
+		       ((diff1 << 1) & 0x40)  |
+		       ((diff1 << 2) & 0x20)  |
+		       ((diff1 << 3) & 0x10)  |
+		       ((diff0 >> 4) & 0x08)  |
+		       ((diff0 >> 3) & 0x04)  |
+		       ((diff0 >> 2) & 0x02)  |
+		       ((diff0 >> 1) & 0x01);
+
+		dev_dbg(info->device, "correcting error bit %d, byte %d\n",
+			bit, byte);
+
+		dat[byte] ^= (1 << bit);
+		return 1;
+	}
+
+	/* if there is only one bit difference in the ECC, then
+	 * one of only a row or column parity has changed, which
+	 * means the error is most probably in the ECC itself */
+
+	diff0 |= (diff1 << 8);
+	diff0 |= (diff2 << 16);
+
+	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
+	if ((diff0 & (diff0 - 1)) == 0)
+		return 1;
+
+	return -1;
+}
+
+/* ECC functions
+ *
+ * These allow the s3c2410 and s3c2440 to use the controller's ECC
+ * generator block to ECC the data as it passes through]
+*/
+
+static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	unsigned long ctrl;
+
+	ctrl = readl(info->regs + S3C2410_NFCONF);
+	ctrl |= S3C2410_NFCONF_INITECC;
+	writel(ctrl, info->regs + S3C2410_NFCONF);
+}
+
+static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	unsigned long ctrl;
+
+	ctrl = readl(info->regs + S3C2440_NFCONT);
+	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
+	       info->regs + S3C2440_NFCONT);
+}
+
+static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	unsigned long ctrl;
+
+	ctrl = readl(info->regs + S3C2440_NFCONT);
+	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
+}
+
+static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+				      u_char *ecc_code)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
+	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
+	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
+
+	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
+
+	return 0;
+}
+
+static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+				      u_char *ecc_code)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
+
+	ecc_code[0] = ecc;
+	ecc_code[1] = ecc >> 8;
+	ecc_code[2] = ecc >> 16;
+
+	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
+
+	return 0;
+}
+
+static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+				      u_char *ecc_code)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
+
+	ecc_code[0] = ecc;
+	ecc_code[1] = ecc >> 8;
+	ecc_code[2] = ecc >> 16;
+
+	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
+
+	return 0;
+}
+
+/* over-ride the standard functions for a little more speed. We can
+ * use read/write block to move the data buffers to/from the controller
+*/
+
+static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	readsb(this->IO_ADDR_R, buf, len);
+}
+
+static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
+
+	/* cleanup if we've got less than a word to do */
+	if (len & 3) {
+		buf += len & ~3;
+
+		for (; len & 3; len--)
+			*buf++ = readb(info->regs + S3C2440_NFDATA);
+	}
+}
+
+static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+				   int len)
+{
+	struct nand_chip *this = mtd_to_nand(mtd);
+	writesb(this->IO_ADDR_W, buf, len);
+}
+
+static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+				   int len)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
+
+	/* cleanup any fractional write */
+	if (len & 3) {
+		buf += len & ~3;
+
+		for (; len & 3; len--, buf++)
+			writeb(*buf, info->regs + S3C2440_NFDATA);
+	}
+}
+
+/* cpufreq driver support */
+
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
+
+static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
+					  unsigned long val, void *data)
+{
+	struct s3c2410_nand_info *info;
+	unsigned long newclk;
+
+	info = container_of(nb, struct s3c2410_nand_info, freq_transition);
+	newclk = clk_get_rate(info->clk);
+
+	if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
+	    (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
+		s3c2410_nand_setrate(info);
+	}
+
+	return 0;
+}
+
+static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
+{
+	info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
+
+	return cpufreq_register_notifier(&info->freq_transition,
+					 CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void
+s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
+{
+	cpufreq_unregister_notifier(&info->freq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
+{
+	return 0;
+}
+
+static inline void
+s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
+{
+}
+#endif
+
+/* device management functions */
+
+static int s3c24xx_nand_remove(struct platform_device *pdev)
+{
+	struct s3c2410_nand_info *info = to_nand_info(pdev);
+
+	if (info == NULL)
+		return 0;
+
+	s3c2410_nand_cpufreq_deregister(info);
+
+	/* Release all our mtds  and their partitions, then go through
+	 * freeing the resources used
+	 */
+
+	if (info->mtds != NULL) {
+		struct s3c2410_nand_mtd *ptr = info->mtds;
+		int mtdno;
+
+		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
+			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
+			nand_release(nand_to_mtd(&ptr->chip));
+		}
+	}
+
+	/* free the common resources */
+
+	if (!IS_ERR(info->clk))
+		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
+
+	return 0;
+}
+
+static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
+				      struct s3c2410_nand_mtd *mtd,
+				      struct s3c2410_nand_set *set)
+{
+	if (set) {
+		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
+
+		mtdinfo->name = set->name;
+
+		return mtd_device_parse_register(mtdinfo, NULL, NULL,
+					 set->partitions, set->nr_partitions);
+	}
+
+	return -ENODEV;
+}
+
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+					const struct nand_data_interface *conf)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	struct s3c2410_platform_nand *pdata = info->platform;
+	const struct nand_sdr_timings *timings;
+	int tacls;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return -ENOTSUPP;
+
+	tacls = timings->tCLS_min - timings->tWP_min;
+	if (tacls < 0)
+		tacls = 0;
+
+	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+
+	return s3c2410_nand_setrate(info);
+}
+
+/**
+ * s3c2410_nand_init_chip - initialise a single instance of an chip
+ * @info: The base NAND controller the chip is on.
+ * @nmtd: The new controller MTD instance to fill in.
+ * @set: The information passed from the board specific platform data.
+ *
+ * Initialise the given @nmtd from the information in @info and @set. This
+ * readies the structure for use with the MTD layer functions by ensuring
+ * all pointers are setup and the necessary control routines selected.
+ */
+static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
+				   struct s3c2410_nand_mtd *nmtd,
+				   struct s3c2410_nand_set *set)
+{
+	struct device_node *np = info->device->of_node;
+	struct nand_chip *chip = &nmtd->chip;
+	void __iomem *regs = info->regs;
+
+	nand_set_flash_node(chip, set->of_node);
+
+	chip->write_buf    = s3c2410_nand_write_buf;
+	chip->read_buf     = s3c2410_nand_read_buf;
+	chip->select_chip  = s3c2410_nand_select_chip;
+	chip->chip_delay   = 50;
+	nand_set_controller_data(chip, nmtd);
+	chip->options	   = set->options;
+	chip->controller   = &info->controller;
+
+	/*
+	 * let's keep behavior unchanged for legacy boards booting via pdata and
+	 * auto-detect timings only when booting with a device tree.
+	 */
+	if (np)
+		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+
+	switch (info->cpu_type) {
+	case TYPE_S3C2410:
+		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+		info->sel_reg   = regs + S3C2410_NFCONF;
+		info->sel_bit	= S3C2410_NFCONF_nFCE;
+		chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
+		chip->dev_ready = s3c2410_nand_devready;
+		break;
+
+	case TYPE_S3C2440:
+		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+		info->sel_reg   = regs + S3C2440_NFCONT;
+		info->sel_bit	= S3C2440_NFCONT_nFCE;
+		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+		chip->dev_ready = s3c2440_nand_devready;
+		chip->read_buf  = s3c2440_nand_read_buf;
+		chip->write_buf	= s3c2440_nand_write_buf;
+		break;
+
+	case TYPE_S3C2412:
+		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+		info->sel_reg   = regs + S3C2440_NFCONT;
+		info->sel_bit	= S3C2412_NFCONT_nFCE0;
+		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+		chip->dev_ready = s3c2412_nand_devready;
+
+		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
+			dev_info(info->device, "System booted from NAND\n");
+
+		break;
+	}
+
+	chip->IO_ADDR_R = chip->IO_ADDR_W;
+
+	nmtd->info	   = info;
+	nmtd->set	   = set;
+
+	chip->ecc.mode = info->platform->ecc_mode;
+
+	/*
+	 * If you use u-boot BBT creation code, specifying this flag will
+	 * let the kernel fish out the BBT from the NAND.
+	 */
+	if (set->flash_bbt)
+		chip->bbt_options |= NAND_BBT_USE_FLASH;
+}
+
+/**
+ * s3c2410_nand_update_chip - post probe update
+ * @info: The controller instance.
+ * @nmtd: The driver version of the MTD instance.
+ *
+ * This routine is called after the chip probe has successfully completed
+ * and the relevant per-chip information updated. This call ensure that
+ * we update the internal state accordingly.
+ *
+ * The internal state is currently limited to the ECC state information.
+*/
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+				    struct s3c2410_nand_mtd *nmtd)
+{
+	struct nand_chip *chip = &nmtd->chip;
+
+	switch (chip->ecc.mode) {
+
+	case NAND_ECC_NONE:
+		dev_info(info->device, "ECC disabled\n");
+		break;
+
+	case NAND_ECC_SOFT:
+		/*
+		 * This driver expects Hamming based ECC when ecc_mode is set
+		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+		 * avoid adding an extra ecc_algo field to
+		 * s3c2410_platform_nand.
+		 */
+		chip->ecc.algo = NAND_ECC_HAMMING;
+		dev_info(info->device, "soft ECC\n");
+		break;
+
+	case NAND_ECC_HW:
+		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+		chip->ecc.correct   = s3c2410_nand_correct_data;
+		chip->ecc.strength  = 1;
+
+		switch (info->cpu_type) {
+		case TYPE_S3C2410:
+			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2412:
+			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2440:
+			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+			break;
+		}
+
+		dev_dbg(info->device, "chip %p => page shift %d\n",
+			chip, chip->page_shift);
+
+		/* change the behaviour depending on whether we are using
+		 * the large or small page nand device */
+		if (chip->page_shift > 10) {
+			chip->ecc.size	    = 256;
+			chip->ecc.bytes	    = 3;
+		} else {
+			chip->ecc.size	    = 512;
+			chip->ecc.bytes	    = 3;
+			mtd_set_ooblayout(nand_to_mtd(chip),
+					  &s3c2410_ooblayout_ops);
+		}
+
+		dev_info(info->device, "hardware ECC\n");
+		break;
+
+	default:
+		dev_err(info->device, "invalid ECC mode!\n");
+		return -EINVAL;
+	}
+
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->options |= NAND_SKIP_BBTSCAN;
+
+	return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+	{
+		.compatible = "samsung,s3c2410-nand",
+		.data = &s3c2410_nand_devtype_data,
+	}, {
+		/* also compatible with s3c6400 */
+		.compatible = "samsung,s3c2412-nand",
+		.data = &s3c2412_nand_devtype_data,
+	}, {
+		.compatible = "samsung,s3c2440-nand",
+		.data = &s3c2440_nand_devtype_data,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+	const struct s3c24XX_nand_devtype_data *devtype_data;
+	struct s3c2410_platform_nand *pdata;
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node, *child;
+	struct s3c2410_nand_set *sets;
+
+	devtype_data = of_device_get_match_data(&pdev->dev);
+	if (!devtype_data)
+		return -ENODEV;
+
+	info->cpu_type = devtype_data->type;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdev->dev.platform_data = pdata;
+
+	pdata->nr_sets = of_get_child_count(np);
+	if (!pdata->nr_sets)
+		return 0;
+
+	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets,
+			    GFP_KERNEL);
+	if (!sets)
+		return -ENOMEM;
+
+	pdata->sets = sets;
+
+	for_each_available_child_of_node(np, child) {
+		sets->name = (char *)child->name;
+		sets->of_node = child;
+		sets->nr_chips = 1;
+
+		of_node_get(child);
+
+		sets++;
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+	info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
+	return 0;
+}
+
+/* s3c24xx_nand_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices
+*/
+static int s3c24xx_nand_probe(struct platform_device *pdev)
+{
+	struct s3c2410_platform_nand *plat;
+	struct s3c2410_nand_info *info;
+	struct s3c2410_nand_mtd *nmtd;
+	struct s3c2410_nand_set *sets;
+	struct resource *res;
+	int err = 0;
+	int size;
+	int nr_sets;
+	int setno;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (info == NULL) {
+		err = -ENOMEM;
+		goto exit_error;
+	}
+
+	platform_set_drvdata(pdev, info);
+
+	nand_hw_control_init(&info->controller);
+
+	/* get the clock source and enable it */
+
+	info->clk = devm_clk_get(&pdev->dev, "nand");
+	if (IS_ERR(info->clk)) {
+		dev_err(&pdev->dev, "failed to get clock\n");
+		err = -ENOENT;
+		goto exit_error;
+	}
+
+	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
+
+	if (pdev->dev.of_node)
+		err = s3c24xx_nand_probe_dt(pdev);
+	else
+		err = s3c24xx_nand_probe_pdata(pdev);
+
+	if (err)
+		goto exit_error;
+
+	plat = to_nand_plat(pdev);
+
+	/* allocate and map the resource */
+
+	/* currently we assume we have the one resource */
+	res = pdev->resource;
+	size = resource_size(res);
+
+	info->device	= &pdev->dev;
+	info->platform	= plat;
+
+	info->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(info->regs)) {
+		err = PTR_ERR(info->regs);
+		goto exit_error;
+	}
+
+	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
+
+	sets = (plat != NULL) ? plat->sets : NULL;
+	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
+
+	info->mtd_count = nr_sets;
+
+	/* allocate our information */
+
+	size = nr_sets * sizeof(*info->mtds);
+	info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+	if (info->mtds == NULL) {
+		err = -ENOMEM;
+		goto exit_error;
+	}
+
+	/* initialise all possible chips */
+
+	nmtd = info->mtds;
+
+	for (setno = 0; setno < nr_sets; setno++, nmtd++) {
+		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
+
+		pr_debug("initialising set %d (%p, info %p)\n",
+			 setno, nmtd, info);
+
+		mtd->dev.parent = &pdev->dev;
+		s3c2410_nand_init_chip(info, nmtd, sets);
+
+		nmtd->scan_res = nand_scan_ident(mtd,
+						 (sets) ? sets->nr_chips : 1,
+						 NULL);
+
+		if (nmtd->scan_res == 0) {
+			err = s3c2410_nand_update_chip(info, nmtd);
+			if (err < 0)
+				goto exit_error;
+			nand_scan_tail(mtd);
+			s3c2410_nand_add_partition(info, nmtd, sets);
+		}
+
+		if (sets != NULL)
+			sets++;
+	}
+
+	/* initialise the hardware */
+	err = s3c2410_nand_inithw(info);
+	if (err != 0)
+		goto exit_error;
+
+	err = s3c2410_nand_cpufreq_register(info);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed to init cpufreq support\n");
+		goto exit_error;
+	}
+
+	if (allow_clk_suspend(info)) {
+		dev_info(&pdev->dev, "clock idle support enabled\n");
+		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
+	}
+
+	return 0;
+
+ exit_error:
+	s3c24xx_nand_remove(pdev);
+
+	if (err == 0)
+		err = -EINVAL;
+	return err;
+}
+
+/* PM Support */
+#ifdef CONFIG_PM
+
+static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+
+	if (info) {
+		info->save_sel = readl(info->sel_reg);
+
+		/* For the moment, we must ensure nFCE is high during
+		 * the time we are suspended. This really should be
+		 * handled by suspending the MTDs we are using, but
+		 * that is currently not the case. */
+
+		writel(info->save_sel | info->sel_bit, info->sel_reg);
+
+		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_resume(struct platform_device *dev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+	unsigned long sel;
+
+	if (info) {
+		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
+		s3c2410_nand_inithw(info);
+
+		/* Restore the state of the nFCE line. */
+
+		sel = readl(info->sel_reg);
+		sel &= ~info->sel_bit;
+		sel |= info->save_sel & info->sel_bit;
+		writel(sel, info->sel_reg);
+
+		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
+	}
+
+	return 0;
+}
+
+#else
+#define s3c24xx_nand_suspend NULL
+#define s3c24xx_nand_resume NULL
+#endif
+
+/* driver device registration */
+
+static const struct platform_device_id s3c24xx_driver_ids[] = {
+	{
+		.name		= "s3c2410-nand",
+		.driver_data	= TYPE_S3C2410,
+	}, {
+		.name		= "s3c2440-nand",
+		.driver_data	= TYPE_S3C2440,
+	}, {
+		.name		= "s3c2412-nand",
+		.driver_data	= TYPE_S3C2412,
+	}, {
+		.name		= "s3c6400-nand",
+		.driver_data	= TYPE_S3C2412, /* compatible with 2412 */
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+
+static struct platform_driver s3c24xx_nand_driver = {
+	.probe		= s3c24xx_nand_probe,
+	.remove		= s3c24xx_nand_remove,
+	.suspend	= s3c24xx_nand_suspend,
+	.resume		= s3c24xx_nand_resume,
+	.id_table	= s3c24xx_driver_ids,
+	.driver		= {
+		.name	= "s3c24xx-nand",
+		.of_match_table = s3c24xx_nand_dt_ids,
+	},
+};
+
+module_platform_driver(s3c24xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
new file mode 100644
index 000000000000..c4e7755448e6
--- /dev/null
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -0,0 +1,1250 @@
+/*
+ * SuperH FLCTL nand controller
+ *
+ * Copyright (c) 2008 Renesas Solutions Corp.
+ * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
+ *
+ * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sh_dma.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/sh_flctl.h>
+
+static int flctl_4secc_ooblayout_sp_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 0;
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int flctl_4secc_ooblayout_sp_free(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 12;
+	oobregion->length = 4;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
+	.ecc = flctl_4secc_ooblayout_sp_ecc,
+	.free = flctl_4secc_ooblayout_sp_free,
+};
+
+static int flctl_4secc_ooblayout_lp_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = (section * 16) + 6;
+	oobregion->length = chip->ecc.bytes;
+
+	return 0;
+}
+
+static int flctl_4secc_ooblayout_lp_free(struct mtd_info *mtd, int section,
+					 struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section >= chip->ecc.steps)
+		return -ERANGE;
+
+	oobregion->offset = section * 16;
+	oobregion->length = 6;
+
+	if (!section) {
+		oobregion->offset += 2;
+		oobregion->length -= 2;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
+	.ecc = flctl_4secc_ooblayout_lp_ecc,
+	.free = flctl_4secc_ooblayout_lp_free,
+};
+
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+static struct nand_bbt_descr flctl_4secc_smallpage = {
+	.options = NAND_BBT_SCAN2NDPAGE,
+	.offs = 11,
+	.len = 1,
+	.pattern = scan_ff_pattern,
+};
+
+static struct nand_bbt_descr flctl_4secc_largepage = {
+	.options = NAND_BBT_SCAN2NDPAGE,
+	.offs = 0,
+	.len = 2,
+	.pattern = scan_ff_pattern,
+};
+
+static void empty_fifo(struct sh_flctl *flctl)
+{
+	writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
+	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+}
+
+static void start_translation(struct sh_flctl *flctl)
+{
+	writeb(TRSTRT, FLTRCR(flctl));
+}
+
+static void timeout_error(struct sh_flctl *flctl, const char *str)
+{
+	dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
+}
+
+static void wait_completion(struct sh_flctl *flctl)
+{
+	uint32_t timeout = LOOP_TIMEOUT_MAX;
+
+	while (timeout--) {
+		if (readb(FLTRCR(flctl)) & TREND) {
+			writeb(0x0, FLTRCR(flctl));
+			return;
+		}
+		udelay(1);
+	}
+
+	timeout_error(flctl, __func__);
+	writeb(0x0, FLTRCR(flctl));
+}
+
+static void flctl_dma_complete(void *param)
+{
+	struct sh_flctl *flctl = param;
+
+	complete(&flctl->dma_complete);
+}
+
+static void flctl_release_dma(struct sh_flctl *flctl)
+{
+	if (flctl->chan_fifo0_rx) {
+		dma_release_channel(flctl->chan_fifo0_rx);
+		flctl->chan_fifo0_rx = NULL;
+	}
+	if (flctl->chan_fifo0_tx) {
+		dma_release_channel(flctl->chan_fifo0_tx);
+		flctl->chan_fifo0_tx = NULL;
+	}
+}
+
+static void flctl_setup_dma(struct sh_flctl *flctl)
+{
+	dma_cap_mask_t mask;
+	struct dma_slave_config cfg;
+	struct platform_device *pdev = flctl->pdev;
+	struct sh_flctl_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	int ret;
+
+	if (!pdata)
+		return;
+
+	if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
+		return;
+
+	/* We can only either use DMA for both Tx and Rx or not use it at all */
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
+				(void *)(uintptr_t)pdata->slave_id_fifo0_tx);
+	dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
+		flctl->chan_fifo0_tx);
+
+	if (!flctl->chan_fifo0_tx)
+		return;
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.direction = DMA_MEM_TO_DEV;
+	cfg.dst_addr = flctl->fifo;
+	cfg.src_addr = 0;
+	ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
+	if (ret < 0)
+		goto err;
+
+	flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
+				(void *)(uintptr_t)pdata->slave_id_fifo0_rx);
+	dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
+		flctl->chan_fifo0_rx);
+
+	if (!flctl->chan_fifo0_rx)
+		goto err;
+
+	cfg.direction = DMA_DEV_TO_MEM;
+	cfg.dst_addr = 0;
+	cfg.src_addr = flctl->fifo;
+	ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
+	if (ret < 0)
+		goto err;
+
+	init_completion(&flctl->dma_complete);
+
+	return;
+
+err:
+	flctl_release_dma(flctl);
+}
+
+static void set_addr(struct mtd_info *mtd, int column, int page_addr)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	uint32_t addr = 0;
+
+	if (column == -1) {
+		addr = page_addr;	/* ERASE1 */
+	} else if (page_addr != -1) {
+		/* SEQIN, READ0, etc.. */
+		if (flctl->chip.options & NAND_BUSWIDTH_16)
+			column >>= 1;
+		if (flctl->page_size) {
+			addr = column & 0x0FFF;
+			addr |= (page_addr & 0xff) << 16;
+			addr |= ((page_addr >> 8) & 0xff) << 24;
+			/* big than 128MB */
+			if (flctl->rw_ADRCNT == ADRCNT2_E) {
+				uint32_t 	addr2;
+				addr2 = (page_addr >> 16) & 0xff;
+				writel(addr2, FLADR2(flctl));
+			}
+		} else {
+			addr = column;
+			addr |= (page_addr & 0xff) << 8;
+			addr |= ((page_addr >> 8) & 0xff) << 16;
+			addr |= ((page_addr >> 16) & 0xff) << 24;
+		}
+	}
+	writel(addr, FLADR(flctl));
+}
+
+static void wait_rfifo_ready(struct sh_flctl *flctl)
+{
+	uint32_t timeout = LOOP_TIMEOUT_MAX;
+
+	while (timeout--) {
+		uint32_t val;
+		/* check FIFO */
+		val = readl(FLDTCNTR(flctl)) >> 16;
+		if (val & 0xFF)
+			return;
+		udelay(1);
+	}
+	timeout_error(flctl, __func__);
+}
+
+static void wait_wfifo_ready(struct sh_flctl *flctl)
+{
+	uint32_t len, timeout = LOOP_TIMEOUT_MAX;
+
+	while (timeout--) {
+		/* check FIFO */
+		len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
+		if (len >= 4)
+			return;
+		udelay(1);
+	}
+	timeout_error(flctl, __func__);
+}
+
+static enum flctl_ecc_res_t wait_recfifo_ready
+		(struct sh_flctl *flctl, int sector_number)
+{
+	uint32_t timeout = LOOP_TIMEOUT_MAX;
+	void __iomem *ecc_reg[4];
+	int i;
+	int state = FL_SUCCESS;
+	uint32_t data, size;
+
+	/*
+	 * First this loops checks in FLDTCNTR if we are ready to read out the
+	 * oob data. This is the case if either all went fine without errors or
+	 * if the bottom part of the loop corrected the errors or marked them as
+	 * uncorrectable and the controller is given time to push the data into
+	 * the FIFO.
+	 */
+	while (timeout--) {
+		/* check if all is ok and we can read out the OOB */
+		size = readl(FLDTCNTR(flctl)) >> 24;
+		if ((size & 0xFF) == 4)
+			return state;
+
+		/* check if a correction code has been calculated */
+		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
+			/*
+			 * either we wait for the fifo to be filled or a
+			 * correction pattern is being generated
+			 */
+			udelay(1);
+			continue;
+		}
+
+		/* check for an uncorrectable error */
+		if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
+			/* check if we face a non-empty page */
+			for (i = 0; i < 512; i++) {
+				if (flctl->done_buff[i] != 0xff) {
+					state = FL_ERROR; /* can't correct */
+					break;
+				}
+			}
+
+			if (state == FL_SUCCESS)
+				dev_dbg(&flctl->pdev->dev,
+				"reading empty sector %d, ecc error ignored\n",
+				sector_number);
+
+			writel(0, FL4ECCCR(flctl));
+			continue;
+		}
+
+		/* start error correction */
+		ecc_reg[0] = FL4ECCRESULT0(flctl);
+		ecc_reg[1] = FL4ECCRESULT1(flctl);
+		ecc_reg[2] = FL4ECCRESULT2(flctl);
+		ecc_reg[3] = FL4ECCRESULT3(flctl);
+
+		for (i = 0; i < 3; i++) {
+			uint8_t org;
+			unsigned int index;
+
+			data = readl(ecc_reg[i]);
+
+			if (flctl->page_size)
+				index = (512 * sector_number) +
+					(data >> 16);
+			else
+				index = data >> 16;
+
+			org = flctl->done_buff[index];
+			flctl->done_buff[index] = org ^ (data & 0xFF);
+		}
+		state = FL_REPAIRABLE;
+		writel(0, FL4ECCCR(flctl));
+	}
+
+	timeout_error(flctl, __func__);
+	return FL_TIMEOUT;	/* timeout */
+}
+
+static void wait_wecfifo_ready(struct sh_flctl *flctl)
+{
+	uint32_t timeout = LOOP_TIMEOUT_MAX;
+	uint32_t len;
+
+	while (timeout--) {
+		/* check FLECFIFO */
+		len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
+		if (len >= 4)
+			return;
+		udelay(1);
+	}
+	timeout_error(flctl, __func__);
+}
+
+static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
+					int len, enum dma_data_direction dir)
+{
+	struct dma_async_tx_descriptor *desc = NULL;
+	struct dma_chan *chan;
+	enum dma_transfer_direction tr_dir;
+	dma_addr_t dma_addr;
+	dma_cookie_t cookie;
+	uint32_t reg;
+	int ret;
+
+	if (dir == DMA_FROM_DEVICE) {
+		chan = flctl->chan_fifo0_rx;
+		tr_dir = DMA_DEV_TO_MEM;
+	} else {
+		chan = flctl->chan_fifo0_tx;
+		tr_dir = DMA_MEM_TO_DEV;
+	}
+
+	dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+
+	if (!dma_mapping_error(chan->device->dev, dma_addr))
+		desc = dmaengine_prep_slave_single(chan, dma_addr, len,
+			tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+	if (desc) {
+		reg = readl(FLINTDMACR(flctl));
+		reg |= DREQ0EN;
+		writel(reg, FLINTDMACR(flctl));
+
+		desc->callback = flctl_dma_complete;
+		desc->callback_param = flctl;
+		cookie = dmaengine_submit(desc);
+		if (dma_submit_error(cookie)) {
+			ret = dma_submit_error(cookie);
+			dev_warn(&flctl->pdev->dev,
+				 "DMA submit failed, falling back to PIO\n");
+			goto out;
+		}
+
+		dma_async_issue_pending(chan);
+	} else {
+		/* DMA failed, fall back to PIO */
+		flctl_release_dma(flctl);
+		dev_warn(&flctl->pdev->dev,
+			 "DMA failed, falling back to PIO\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	ret =
+	wait_for_completion_timeout(&flctl->dma_complete,
+				msecs_to_jiffies(3000));
+
+	if (ret <= 0) {
+		dmaengine_terminate_all(chan);
+		dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
+	}
+
+out:
+	reg = readl(FLINTDMACR(flctl));
+	reg &= ~DREQ0EN;
+	writel(reg, FLINTDMACR(flctl));
+
+	dma_unmap_single(chan->device->dev, dma_addr, len, dir);
+
+	/* ret > 0 is success */
+	return ret;
+}
+
+static void read_datareg(struct sh_flctl *flctl, int offset)
+{
+	unsigned long data;
+	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+
+	wait_completion(flctl);
+
+	data = readl(FLDATAR(flctl));
+	*buf = le32_to_cpu(data);
+}
+
+static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+{
+	int i, len_4align;
+	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+
+	len_4align = (rlen + 3) / 4;
+
+	/* initiate DMA transfer */
+	if (flctl->chan_fifo0_rx && rlen >= 32 &&
+		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+			goto convert;	/* DMA success */
+
+	/* do polling transfer */
+	for (i = 0; i < len_4align; i++) {
+		wait_rfifo_ready(flctl);
+		buf[i] = readl(FLDTFIFO(flctl));
+	}
+
+convert:
+	for (i = 0; i < len_4align; i++)
+		buf[i] = be32_to_cpu(buf[i]);
+}
+
+static enum flctl_ecc_res_t read_ecfiforeg
+		(struct sh_flctl *flctl, uint8_t *buff, int sector)
+{
+	int i;
+	enum flctl_ecc_res_t res;
+	unsigned long *ecc_buf = (unsigned long *)buff;
+
+	res = wait_recfifo_ready(flctl , sector);
+
+	if (res != FL_ERROR) {
+		for (i = 0; i < 4; i++) {
+			ecc_buf[i] = readl(FLECFIFO(flctl));
+			ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+		}
+	}
+
+	return res;
+}
+
+static void write_fiforeg(struct sh_flctl *flctl, int rlen,
+						unsigned int offset)
+{
+	int i, len_4align;
+	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+
+	len_4align = (rlen + 3) / 4;
+	for (i = 0; i < len_4align; i++) {
+		wait_wfifo_ready(flctl);
+		writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
+	}
+}
+
+static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
+						unsigned int offset)
+{
+	int i, len_4align;
+	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
+
+	len_4align = (rlen + 3) / 4;
+
+	for (i = 0; i < len_4align; i++)
+		buf[i] = cpu_to_be32(buf[i]);
+
+	/* initiate DMA transfer */
+	if (flctl->chan_fifo0_tx && rlen >= 32 &&
+		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+			return;	/* DMA success */
+
+	/* do polling transfer */
+	for (i = 0; i < len_4align; i++) {
+		wait_wecfifo_ready(flctl);
+		writel(buf[i], FLECFIFO(flctl));
+	}
+}
+
+static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
+	uint32_t flcmdcr_val, addr_len_bytes = 0;
+
+	/* Set SNAND bit if page size is 2048byte */
+	if (flctl->page_size)
+		flcmncr_val |= SNAND_E;
+	else
+		flcmncr_val &= ~SNAND_E;
+
+	/* default FLCMDCR val */
+	flcmdcr_val = DOCMD1_E | DOADR_E;
+
+	/* Set for FLCMDCR */
+	switch (cmd) {
+	case NAND_CMD_ERASE1:
+		addr_len_bytes = flctl->erase_ADRCNT;
+		flcmdcr_val |= DOCMD2_E;
+		break;
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+	case NAND_CMD_RNDOUT:
+		addr_len_bytes = flctl->rw_ADRCNT;
+		flcmdcr_val |= CDSRC_E;
+		if (flctl->chip.options & NAND_BUSWIDTH_16)
+			flcmncr_val |= SEL_16BIT;
+		break;
+	case NAND_CMD_SEQIN:
+		/* This case is that cmd is READ0 or READ1 or READ00 */
+		flcmdcr_val &= ~DOADR_E;	/* ONLY execute 1st cmd */
+		break;
+	case NAND_CMD_PAGEPROG:
+		addr_len_bytes = flctl->rw_ADRCNT;
+		flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
+		if (flctl->chip.options & NAND_BUSWIDTH_16)
+			flcmncr_val |= SEL_16BIT;
+		break;
+	case NAND_CMD_READID:
+		flcmncr_val &= ~SNAND_E;
+		flcmdcr_val |= CDSRC_E;
+		addr_len_bytes = ADRCNT_1;
+		break;
+	case NAND_CMD_STATUS:
+	case NAND_CMD_RESET:
+		flcmncr_val &= ~SNAND_E;
+		flcmdcr_val &= ~(DOADR_E | DOSR_E);
+		break;
+	default:
+		break;
+	}
+
+	/* Set address bytes parameter */
+	flcmdcr_val |= addr_len_bytes;
+
+	/* Now actually write */
+	writel(flcmncr_val, FLCMNCR(flctl));
+	writel(flcmdcr_val, FLCMDCR(flctl));
+	writel(flcmcdr_val, FLCMCDR(flctl));
+}
+
+static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	if (oob_required)
+		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	return 0;
+}
+
+static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				  const uint8_t *buf, int oob_required,
+				  int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+	return nand_prog_page_end_op(chip);
+}
+
+static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	int sector, page_sectors;
+	enum flctl_ecc_res_t ecc_result;
+
+	page_sectors = flctl->page_size ? 4 : 1;
+
+	set_cmd_regs(mtd, NAND_CMD_READ0,
+		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
+
+	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
+		 FLCMNCR(flctl));
+	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+	writel(page_addr << 2, FLADR(flctl));
+
+	empty_fifo(flctl);
+	start_translation(flctl);
+
+	for (sector = 0; sector < page_sectors; sector++) {
+		read_fiforeg(flctl, 512, 512 * sector);
+
+		ecc_result = read_ecfiforeg(flctl,
+			&flctl->done_buff[mtd->writesize + 16 * sector],
+			sector);
+
+		switch (ecc_result) {
+		case FL_REPAIRABLE:
+			dev_info(&flctl->pdev->dev,
+				"applied ecc on page 0x%x", page_addr);
+			mtd->ecc_stats.corrected++;
+			break;
+		case FL_ERROR:
+			dev_warn(&flctl->pdev->dev,
+				"page 0x%x contains corrupted data\n",
+				page_addr);
+			mtd->ecc_stats.failed++;
+			break;
+		default:
+			;
+		}
+	}
+
+	wait_completion(flctl);
+
+	writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
+			FLCMNCR(flctl));
+}
+
+static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	int page_sectors = flctl->page_size ? 4 : 1;
+	int i;
+
+	set_cmd_regs(mtd, NAND_CMD_READ0,
+		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
+
+	empty_fifo(flctl);
+
+	for (i = 0; i < page_sectors; i++) {
+		set_addr(mtd, (512 + 16) * i + 512 , page_addr);
+		writel(16, FLDTCNTR(flctl));
+
+		start_translation(flctl);
+		read_fiforeg(flctl, 16, 16 * i);
+		wait_completion(flctl);
+	}
+}
+
+static void execmd_write_page_sector(struct mtd_info *mtd)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	int page_addr = flctl->seqin_page_addr;
+	int sector, page_sectors;
+
+	page_sectors = flctl->page_size ? 4 : 1;
+
+	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
+			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
+
+	empty_fifo(flctl);
+	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+	writel(page_addr << 2, FLADR(flctl));
+	start_translation(flctl);
+
+	for (sector = 0; sector < page_sectors; sector++) {
+		write_fiforeg(flctl, 512, 512 * sector);
+		write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
+	}
+
+	wait_completion(flctl);
+	writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
+}
+
+static void execmd_write_oob(struct mtd_info *mtd)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	int page_addr = flctl->seqin_page_addr;
+	int sector, page_sectors;
+
+	page_sectors = flctl->page_size ? 4 : 1;
+
+	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
+			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
+
+	for (sector = 0; sector < page_sectors; sector++) {
+		empty_fifo(flctl);
+		set_addr(mtd, sector * 528 + 512, page_addr);
+		writel(16, FLDTCNTR(flctl));	/* set read size */
+
+		start_translation(flctl);
+		write_fiforeg(flctl, 16, 16 * sector);
+		wait_completion(flctl);
+	}
+}
+
+static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
+			int column, int page_addr)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	uint32_t read_cmd = 0;
+
+	pm_runtime_get_sync(&flctl->pdev->dev);
+
+	flctl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		flctl->index = 0;
+
+	switch (command) {
+	case NAND_CMD_READ1:
+	case NAND_CMD_READ0:
+		if (flctl->hwecc) {
+			/* read page with hwecc */
+			execmd_read_page_sector(mtd, page_addr);
+			break;
+		}
+		if (flctl->page_size)
+			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
+				| command);
+		else
+			set_cmd_regs(mtd, command, command);
+
+		set_addr(mtd, 0, page_addr);
+
+		flctl->read_bytes = mtd->writesize + mtd->oobsize;
+		if (flctl->chip.options & NAND_BUSWIDTH_16)
+			column >>= 1;
+		flctl->index += column;
+		goto read_normal_exit;
+
+	case NAND_CMD_READOOB:
+		if (flctl->hwecc) {
+			/* read page with hwecc */
+			execmd_read_oob(mtd, page_addr);
+			break;
+		}
+
+		if (flctl->page_size) {
+			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
+				| NAND_CMD_READ0);
+			set_addr(mtd, mtd->writesize, page_addr);
+		} else {
+			set_cmd_regs(mtd, command, command);
+			set_addr(mtd, 0, page_addr);
+		}
+		flctl->read_bytes = mtd->oobsize;
+		goto read_normal_exit;
+
+	case NAND_CMD_RNDOUT:
+		if (flctl->hwecc)
+			break;
+
+		if (flctl->page_size)
+			set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
+				| command);
+		else
+			set_cmd_regs(mtd, command, command);
+
+		set_addr(mtd, column, 0);
+
+		flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
+		goto read_normal_exit;
+
+	case NAND_CMD_READID:
+		set_cmd_regs(mtd, command, command);
+
+		/* READID is always performed using an 8-bit bus */
+		if (flctl->chip.options & NAND_BUSWIDTH_16)
+			column <<= 1;
+		set_addr(mtd, column, 0);
+
+		flctl->read_bytes = 8;
+		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+		empty_fifo(flctl);
+		start_translation(flctl);
+		read_fiforeg(flctl, flctl->read_bytes, 0);
+		wait_completion(flctl);
+		break;
+
+	case NAND_CMD_ERASE1:
+		flctl->erase1_page_addr = page_addr;
+		break;
+
+	case NAND_CMD_ERASE2:
+		set_cmd_regs(mtd, NAND_CMD_ERASE1,
+			(command << 8) | NAND_CMD_ERASE1);
+		set_addr(mtd, -1, flctl->erase1_page_addr);
+		start_translation(flctl);
+		wait_completion(flctl);
+		break;
+
+	case NAND_CMD_SEQIN:
+		if (!flctl->page_size) {
+			/* output read command */
+			if (column >= mtd->writesize) {
+				column -= mtd->writesize;
+				read_cmd = NAND_CMD_READOOB;
+			} else if (column < 256) {
+				read_cmd = NAND_CMD_READ0;
+			} else {
+				column -= 256;
+				read_cmd = NAND_CMD_READ1;
+			}
+		}
+		flctl->seqin_column = column;
+		flctl->seqin_page_addr = page_addr;
+		flctl->seqin_read_cmd = read_cmd;
+		break;
+
+	case NAND_CMD_PAGEPROG:
+		empty_fifo(flctl);
+		if (!flctl->page_size) {
+			set_cmd_regs(mtd, NAND_CMD_SEQIN,
+					flctl->seqin_read_cmd);
+			set_addr(mtd, -1, -1);
+			writel(0, FLDTCNTR(flctl));	/* set 0 size */
+			start_translation(flctl);
+			wait_completion(flctl);
+		}
+		if (flctl->hwecc) {
+			/* write page with hwecc */
+			if (flctl->seqin_column == mtd->writesize)
+				execmd_write_oob(mtd);
+			else if (!flctl->seqin_column)
+				execmd_write_page_sector(mtd);
+			else
+				printk(KERN_ERR "Invalid address !?\n");
+			break;
+		}
+		set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
+		set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
+		writel(flctl->index, FLDTCNTR(flctl));	/* set write size */
+		start_translation(flctl);
+		write_fiforeg(flctl, flctl->index, 0);
+		wait_completion(flctl);
+		break;
+
+	case NAND_CMD_STATUS:
+		set_cmd_regs(mtd, command, command);
+		set_addr(mtd, -1, -1);
+
+		flctl->read_bytes = 1;
+		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
+		start_translation(flctl);
+		read_datareg(flctl, 0); /* read and end */
+		break;
+
+	case NAND_CMD_RESET:
+		set_cmd_regs(mtd, command, command);
+		set_addr(mtd, -1, -1);
+
+		writel(0, FLDTCNTR(flctl));	/* set 0 size */
+		start_translation(flctl);
+		wait_completion(flctl);
+		break;
+
+	default:
+		break;
+	}
+	goto runtime_exit;
+
+read_normal_exit:
+	writel(flctl->read_bytes, FLDTCNTR(flctl));	/* set read size */
+	empty_fifo(flctl);
+	start_translation(flctl);
+	read_fiforeg(flctl, flctl->read_bytes, 0);
+	wait_completion(flctl);
+runtime_exit:
+	pm_runtime_put_sync(&flctl->pdev->dev);
+	return;
+}
+
+static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	int ret;
+
+	switch (chipnr) {
+	case -1:
+		flctl->flcmncr_base &= ~CE0_ENABLE;
+
+		pm_runtime_get_sync(&flctl->pdev->dev);
+		writel(flctl->flcmncr_base, FLCMNCR(flctl));
+
+		if (flctl->qos_request) {
+			dev_pm_qos_remove_request(&flctl->pm_qos);
+			flctl->qos_request = 0;
+		}
+
+		pm_runtime_put_sync(&flctl->pdev->dev);
+		break;
+	case 0:
+		flctl->flcmncr_base |= CE0_ENABLE;
+
+		if (!flctl->qos_request) {
+			ret = dev_pm_qos_add_request(&flctl->pdev->dev,
+							&flctl->pm_qos,
+							DEV_PM_QOS_RESUME_LATENCY,
+							100);
+			if (ret < 0)
+				dev_err(&flctl->pdev->dev,
+					"PM QoS request failed: %d\n", ret);
+			flctl->qos_request = 1;
+		}
+
+		if (flctl->holden) {
+			pm_runtime_get_sync(&flctl->pdev->dev);
+			writel(HOLDEN, FLHOLDCR(flctl));
+			pm_runtime_put_sync(&flctl->pdev->dev);
+		}
+		break;
+	default:
+		BUG();
+	}
+}
+
+static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+
+	memcpy(&flctl->done_buff[flctl->index], buf, len);
+	flctl->index += len;
+}
+
+static uint8_t flctl_read_byte(struct mtd_info *mtd)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	uint8_t data;
+
+	data = flctl->done_buff[flctl->index];
+	flctl->index++;
+	return data;
+}
+
+static uint16_t flctl_read_word(struct mtd_info *mtd)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
+
+	flctl->index += 2;
+	return *buf;
+}
+
+static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+
+	memcpy(buf, &flctl->done_buff[flctl->index], len);
+	flctl->index += len;
+}
+
+static int flctl_chip_init_tail(struct mtd_info *mtd)
+{
+	struct sh_flctl *flctl = mtd_to_flctl(mtd);
+	struct nand_chip *chip = &flctl->chip;
+
+	if (mtd->writesize == 512) {
+		flctl->page_size = 0;
+		if (chip->chipsize > (32 << 20)) {
+			/* big than 32MB */
+			flctl->rw_ADRCNT = ADRCNT_4;
+			flctl->erase_ADRCNT = ADRCNT_3;
+		} else if (chip->chipsize > (2 << 16)) {
+			/* big than 128KB */
+			flctl->rw_ADRCNT = ADRCNT_3;
+			flctl->erase_ADRCNT = ADRCNT_2;
+		} else {
+			flctl->rw_ADRCNT = ADRCNT_2;
+			flctl->erase_ADRCNT = ADRCNT_1;
+		}
+	} else {
+		flctl->page_size = 1;
+		if (chip->chipsize > (128 << 20)) {
+			/* big than 128MB */
+			flctl->rw_ADRCNT = ADRCNT2_E;
+			flctl->erase_ADRCNT = ADRCNT_3;
+		} else if (chip->chipsize > (8 << 16)) {
+			/* big than 512KB */
+			flctl->rw_ADRCNT = ADRCNT_4;
+			flctl->erase_ADRCNT = ADRCNT_2;
+		} else {
+			flctl->rw_ADRCNT = ADRCNT_3;
+			flctl->erase_ADRCNT = ADRCNT_1;
+		}
+	}
+
+	if (flctl->hwecc) {
+		if (mtd->writesize == 512) {
+			mtd_set_ooblayout(mtd, &flctl_4secc_oob_smallpage_ops);
+			chip->badblock_pattern = &flctl_4secc_smallpage;
+		} else {
+			mtd_set_ooblayout(mtd, &flctl_4secc_oob_largepage_ops);
+			chip->badblock_pattern = &flctl_4secc_largepage;
+		}
+
+		chip->ecc.size = 512;
+		chip->ecc.bytes = 10;
+		chip->ecc.strength = 4;
+		chip->ecc.read_page = flctl_read_page_hwecc;
+		chip->ecc.write_page = flctl_write_page_hwecc;
+		chip->ecc.mode = NAND_ECC_HW;
+
+		/* 4 symbols ECC enabled */
+		flctl->flcmncr_base |= _4ECCEN;
+	} else {
+		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
+	}
+
+	return 0;
+}
+
+static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
+{
+	struct sh_flctl *flctl = dev_id;
+
+	dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
+	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+
+	return IRQ_HANDLED;
+}
+
+struct flctl_soc_config {
+	unsigned long flcmncr_val;
+	unsigned has_hwecc:1;
+	unsigned use_holden:1;
+};
+
+static struct flctl_soc_config flctl_sh7372_config = {
+	.flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
+	.has_hwecc = 1,
+	.use_holden = 1,
+};
+
+static const struct of_device_id of_flctl_match[] = {
+	{ .compatible = "renesas,shmobile-flctl-sh7372",
+				.data = &flctl_sh7372_config },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_flctl_match);
+
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+{
+	const struct flctl_soc_config *config;
+	struct sh_flctl_platform_data *pdata;
+
+	config = of_device_get_match_data(dev);
+	if (!config) {
+		dev_err(dev, "%s: no OF configuration attached\n", __func__);
+		return NULL;
+	}
+
+	pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
+								GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	/* set SoC specific options */
+	pdata->flcmncr_val = config->flcmncr_val;
+	pdata->has_hwecc = config->has_hwecc;
+	pdata->use_holden = config->use_holden;
+
+	return pdata;
+}
+
+static int flctl_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct sh_flctl *flctl;
+	struct mtd_info *flctl_mtd;
+	struct nand_chip *nand;
+	struct sh_flctl_platform_data *pdata;
+	int ret;
+	int irq;
+
+	flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
+	if (!flctl)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	flctl->reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(flctl->reg))
+		return PTR_ERR(flctl->reg);
+	flctl->fifo = res->start + 0x24; /* FLDTFIFO */
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
+			       "flste", flctl);
+	if (ret) {
+		dev_err(&pdev->dev, "request interrupt failed.\n");
+		return ret;
+	}
+
+	if (pdev->dev.of_node)
+		pdata = flctl_parse_dt(&pdev->dev);
+	else
+		pdata = dev_get_platdata(&pdev->dev);
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "no setup data defined\n");
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, flctl);
+	nand = &flctl->chip;
+	flctl_mtd = nand_to_mtd(nand);
+	nand_set_flash_node(nand, pdev->dev.of_node);
+	flctl_mtd->dev.parent = &pdev->dev;
+	flctl->pdev = pdev;
+	flctl->hwecc = pdata->has_hwecc;
+	flctl->holden = pdata->use_holden;
+	flctl->flcmncr_base = pdata->flcmncr_val;
+	flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
+
+	/* Set address of hardware control function */
+	/* 20 us command delay time */
+	nand->chip_delay = 20;
+
+	nand->read_byte = flctl_read_byte;
+	nand->read_word = flctl_read_word;
+	nand->write_buf = flctl_write_buf;
+	nand->read_buf = flctl_read_buf;
+	nand->select_chip = flctl_select_chip;
+	nand->cmdfunc = flctl_cmdfunc;
+	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
+	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
+
+	if (pdata->flcmncr_val & SEL_16BIT)
+		nand->options |= NAND_BUSWIDTH_16;
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_resume(&pdev->dev);
+
+	flctl_setup_dma(flctl);
+
+	ret = nand_scan_ident(flctl_mtd, 1, NULL);
+	if (ret)
+		goto err_chip;
+
+	if (nand->options & NAND_BUSWIDTH_16) {
+		/*
+		 * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
+		 * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
+		 * flctl->flcmncr_base to pdata->flcmncr_val.
+		 */
+		pdata->flcmncr_val |= SEL_16BIT;
+		flctl->flcmncr_base = pdata->flcmncr_val;
+	}
+
+	ret = flctl_chip_init_tail(flctl_mtd);
+	if (ret)
+		goto err_chip;
+
+	ret = nand_scan_tail(flctl_mtd);
+	if (ret)
+		goto err_chip;
+
+	ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+
+	return 0;
+
+err_chip:
+	flctl_release_dma(flctl);
+	pm_runtime_disable(&pdev->dev);
+	return ret;
+}
+
+static int flctl_remove(struct platform_device *pdev)
+{
+	struct sh_flctl *flctl = platform_get_drvdata(pdev);
+
+	flctl_release_dma(flctl);
+	nand_release(nand_to_mtd(&flctl->chip));
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver flctl_driver = {
+	.remove		= flctl_remove,
+	.driver = {
+		.name	= "sh_flctl",
+		.of_match_table = of_match_ptr(of_flctl_match),
+	},
+};
+
+module_platform_driver_probe(flctl_driver, flctl_probe);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+MODULE_DESCRIPTION("SuperH FLCTL driver");
+MODULE_ALIAS("platform:sh_flctl");
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
new file mode 100644
index 000000000000..e93df02c825e
--- /dev/null
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -0,0 +1,233 @@
+/*
+ *  Copyright (C) 2004 Richard Purdie
+ *  Copyright (C) 2008 Dmitry Baryshkov
+ *
+ *  Based on Sharp's NAND driver sharp_sl.c
+ *
+ * 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/genhd.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/sharpsl.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+
+struct sharpsl_nand {
+	struct nand_chip	chip;
+
+	void __iomem		*io;
+};
+
+static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
+}
+
+/* register offset */
+#define ECCLPLB		0x00	/* line parity 7 - 0 bit */
+#define ECCLPUB		0x04	/* line parity 15 - 8 bit */
+#define ECCCP		0x08	/* column parity 5 - 0 bit */
+#define ECCCNTR		0x0C	/* ECC byte counter */
+#define ECCCLRR		0x10	/* cleare ECC */
+#define FLASHIO		0x14	/* Flash I/O */
+#define FLASHCTL	0x18	/* Flash Control */
+
+/* Flash control bit */
+#define FLRYBY		(1 << 5)
+#define FLCE1		(1 << 4)
+#define FLWP		(1 << 3)
+#define FLALE		(1 << 2)
+#define FLCLE		(1 << 1)
+#define FLCE0		(1 << 0)
+
+/*
+ *	hardware specific access to control-lines
+ *	ctrl:
+ *	NAND_CNE: bit 0 -> ! bit 0 & 4
+ *	NAND_CLE: bit 1 -> bit 1
+ *	NAND_ALE: bit 2 -> bit 2
+ *
+ */
+static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		unsigned char bits = ctrl & 0x07;
+
+		bits |= (ctrl & 0x01) << 4;
+
+		bits ^= 0x11;
+
+		writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, chip->IO_ADDR_W);
+}
+
+static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+	return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
+}
+
+static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+	writeb(0, sharpsl->io + ECCCLRR);
+}
+
+static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
+{
+	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+	ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
+	ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
+	ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
+	return readb(sharpsl->io + ECCCNTR) != 0;
+}
+
+/*
+ * Main initialization routine
+ */
+static int sharpsl_nand_probe(struct platform_device *pdev)
+{
+	struct nand_chip *this;
+	struct mtd_info *mtd;
+	struct resource *r;
+	int err = 0;
+	struct sharpsl_nand *sharpsl;
+	struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
+
+	if (!data) {
+		dev_err(&pdev->dev, "no platform data!\n");
+		return -EINVAL;
+	}
+
+	/* Allocate memory for MTD device structure and private data */
+	sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
+	if (!sharpsl)
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no io memory resource defined!\n");
+		err = -ENODEV;
+		goto err_get_res;
+	}
+
+	/* map physical address */
+	sharpsl->io = ioremap(r->start, resource_size(r));
+	if (!sharpsl->io) {
+		dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
+		err = -EIO;
+		goto err_ioremap;
+	}
+
+	/* Get pointer to private data */
+	this = (struct nand_chip *)(&sharpsl->chip);
+
+	/* Link the private data with the MTD structure */
+	mtd = nand_to_mtd(this);
+	mtd->dev.parent = &pdev->dev;
+	mtd_set_ooblayout(mtd, data->ecc_layout);
+
+	platform_set_drvdata(pdev, sharpsl);
+
+	/*
+	 * PXA initialize
+	 */
+	writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = sharpsl->io + FLASHIO;
+	this->IO_ADDR_W = sharpsl->io + FLASHIO;
+	/* Set address of hardware control function */
+	this->cmd_ctrl = sharpsl_nand_hwcontrol;
+	this->dev_ready = sharpsl_nand_dev_ready;
+	/* 15 us command delay time */
+	this->chip_delay = 15;
+	/* set eccmode using hardware ECC */
+	this->ecc.mode = NAND_ECC_HW;
+	this->ecc.size = 256;
+	this->ecc.bytes = 3;
+	this->ecc.strength = 1;
+	this->badblock_pattern = data->badblock_pattern;
+	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
+	this->ecc.calculate = sharpsl_nand_calculate_ecc;
+	this->ecc.correct = nand_correct_data;
+
+	/* Scan to find existence of the device */
+	err = nand_scan(mtd, 1);
+	if (err)
+		goto err_scan;
+
+	/* Register the partitions */
+	mtd->name = "sharpsl-nand";
+
+	err = mtd_device_parse_register(mtd, data->part_parsers, NULL,
+					data->partitions, data->nr_partitions);
+	if (err)
+		goto err_add;
+
+	/* Return happy */
+	return 0;
+
+err_add:
+	nand_release(mtd);
+
+err_scan:
+	iounmap(sharpsl->io);
+err_ioremap:
+err_get_res:
+	kfree(sharpsl);
+	return err;
+}
+
+/*
+ * Clean up routine
+ */
+static int sharpsl_nand_remove(struct platform_device *pdev)
+{
+	struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
+
+	/* Release resources, unregister device */
+	nand_release(nand_to_mtd(&sharpsl->chip));
+
+	iounmap(sharpsl->io);
+
+	/* Free the MTD device structure */
+	kfree(sharpsl);
+
+	return 0;
+}
+
+static struct platform_driver sharpsl_nand_driver = {
+	.driver = {
+		.name	= "sharpsl-nand",
+	},
+	.probe		= sharpsl_nand_probe,
+	.remove		= sharpsl_nand_remove,
+};
+
+module_platform_driver(sharpsl_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
new file mode 100644
index 000000000000..c378705c6e2b
--- /dev/null
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright © 2009 - Maxim Levitsky
+ * Common routines & support for xD format
+ *
+ * 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/kernel.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/module.h>
+#include <linux/sizes.h>
+#include "sm_common.h"
+
+static int oob_sm_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	if (section > 1)
+		return -ERANGE;
+
+	oobregion->length = 3;
+	oobregion->offset = ((section + 1) * 8) - 3;
+
+	return 0;
+}
+
+static int oob_sm_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	switch (section) {
+	case 0:
+		/* reserved */
+		oobregion->offset = 0;
+		oobregion->length = 4;
+		break;
+	case 1:
+		/* LBA1 */
+		oobregion->offset = 6;
+		oobregion->length = 2;
+		break;
+	case 2:
+		/* LBA2 */
+		oobregion->offset = 11;
+		oobregion->length = 2;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops oob_sm_ops = {
+	.ecc = oob_sm_ooblayout_ecc,
+	.free = oob_sm_ooblayout_free,
+};
+
+/* NOTE: This layout is is not compatabable with SmartMedia, */
+/* because the 256 byte devices have page depenent oob layout */
+/* However it does preserve the bad block markers */
+/* If you use smftl, it will bypass this and work correctly */
+/* If you not, then you break SmartMedia compliance anyway */
+
+static int oob_sm_small_ooblayout_ecc(struct mtd_info *mtd, int section,
+				      struct mtd_oob_region *oobregion)
+{
+	if (section)
+		return -ERANGE;
+
+	oobregion->length = 3;
+	oobregion->offset = 0;
+
+	return 0;
+}
+
+static int oob_sm_small_ooblayout_free(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *oobregion)
+{
+	switch (section) {
+	case 0:
+		/* reserved */
+		oobregion->offset = 3;
+		oobregion->length = 2;
+		break;
+	case 1:
+		/* LBA1 */
+		oobregion->offset = 6;
+		oobregion->length = 2;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops oob_sm_small_ops = {
+	.ecc = oob_sm_small_ooblayout_ecc,
+	.free = oob_sm_small_ooblayout_free,
+};
+
+static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct mtd_oob_ops ops;
+	struct sm_oob oob;
+	int ret;
+
+	memset(&oob, -1, SM_OOB_SIZE);
+	oob.block_status = 0x0F;
+
+	/* As long as this function is called on erase block boundaries
+		it will work correctly for 256 byte nand */
+	ops.mode = MTD_OPS_PLACE_OOB;
+	ops.ooboffs = 0;
+	ops.ooblen = mtd->oobsize;
+	ops.oobbuf = (void *)&oob;
+	ops.datbuf = NULL;
+
+
+	ret = mtd_write_oob(mtd, ofs, &ops);
+	if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) {
+		printk(KERN_NOTICE
+			"sm_common: can't mark sector at %i as bad\n",
+								(int)ofs);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
+	LEGACY_ID_NAND("SmartMedia 2MiB 3,3V ROM",   0x5d, 2,   SZ_8K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V",       0xe3, 4,   SZ_8K, 0),
+	LEGACY_ID_NAND("SmartMedia 4MiB 3,3/5V",     0xe5, 4,   SZ_8K, 0),
+	LEGACY_ID_NAND("SmartMedia 4MiB 5V",         0x6b, 4,   SZ_8K, 0),
+	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V ROM",   0xd5, 4,   SZ_8K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V",       0xe6, 8,   SZ_8K, 0),
+	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V ROM",   0xd6, 8,   SZ_8K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V",      0x73, 16,  SZ_16K, 0),
+	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V ROM",  0x57, 16,  SZ_16K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V",      0x75, 32,  SZ_16K, 0),
+	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V ROM",  0x58, 32,  SZ_16K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V",      0x76, 64,  SZ_16K, 0),
+	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V ROM",  0xd9, 64,  SZ_16K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V",     0x79, 128, SZ_16K, 0),
+	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V ROM", 0xda, 128, SZ_16K, NAND_ROM),
+	LEGACY_ID_NAND("SmartMedia 256MiB 3, 3V",    0x71, 256, SZ_16K, 0),
+	LEGACY_ID_NAND("SmartMedia 256MiB 3,3V ROM", 0x5b, 256, SZ_16K, NAND_ROM),
+	{NULL}
+};
+
+static struct nand_flash_dev nand_xd_flash_ids[] = {
+	LEGACY_ID_NAND("xD 16MiB 3,3V",  0x73, 16,   SZ_16K, 0),
+	LEGACY_ID_NAND("xD 32MiB 3,3V",  0x75, 32,   SZ_16K, 0),
+	LEGACY_ID_NAND("xD 64MiB 3,3V",  0x76, 64,   SZ_16K, 0),
+	LEGACY_ID_NAND("xD 128MiB 3,3V", 0x79, 128,  SZ_16K, 0),
+	LEGACY_ID_NAND("xD 256MiB 3,3V", 0x71, 256,  SZ_16K, NAND_BROKEN_XD),
+	LEGACY_ID_NAND("xD 512MiB 3,3V", 0xdc, 512,  SZ_16K, NAND_BROKEN_XD),
+	LEGACY_ID_NAND("xD 1GiB 3,3V",   0xd3, 1024, SZ_16K, NAND_BROKEN_XD),
+	LEGACY_ID_NAND("xD 2GiB 3,3V",   0xd5, 2048, SZ_16K, NAND_BROKEN_XD),
+	{NULL}
+};
+
+int sm_register_device(struct mtd_info *mtd, int smartmedia)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	chip->options |= NAND_SKIP_BBTSCAN;
+
+	/* Scan for card properties */
+	ret = nand_scan_ident(mtd, 1, smartmedia ?
+		nand_smartmedia_flash_ids : nand_xd_flash_ids);
+
+	if (ret)
+		return ret;
+
+	/* Bad block marker position */
+	chip->badblockpos = 0x05;
+	chip->badblockbits = 7;
+	chip->block_markbad = sm_block_markbad;
+
+	/* ECC layout */
+	if (mtd->writesize == SM_SECTOR_SIZE)
+		mtd_set_ooblayout(mtd, &oob_sm_ops);
+	else if (mtd->writesize == SM_SMALL_PAGE)
+		mtd_set_ooblayout(mtd, &oob_sm_small_ops);
+	else
+		return -ENODEV;
+
+	ret = nand_scan_tail(mtd);
+
+	if (ret)
+		return ret;
+
+	return mtd_device_register(mtd, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(sm_register_device);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
+MODULE_DESCRIPTION("Common SmartMedia/xD functions");
diff --git a/drivers/mtd/nand/raw/sm_common.h b/drivers/mtd/nand/raw/sm_common.h
new file mode 100644
index 000000000000..1581671b05ae
--- /dev/null
+++ b/drivers/mtd/nand/raw/sm_common.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2009 - Maxim Levitsky
+ * Common routines & support for SmartMedia/xD format
+ *
+ * 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/bitops.h>
+#include <linux/mtd/mtd.h>
+
+/* Full oob structure as written on the flash */
+struct sm_oob {
+	uint32_t reserved;
+	uint8_t data_status;
+	uint8_t block_status;
+	uint8_t lba_copy1[2];
+	uint8_t ecc2[3];
+	uint8_t lba_copy2[2];
+	uint8_t ecc1[3];
+} __packed;
+
+
+/* one sector is always 512 bytes, but it can consist of two nand pages */
+#define SM_SECTOR_SIZE		512
+
+/* oob area is also 16 bytes, but might be from two pages */
+#define SM_OOB_SIZE		16
+
+/* This is maximum zone size, and all devices that have more that one zone
+   have this size */
+#define SM_MAX_ZONE_SIZE 	1024
+
+/* support for small page nand */
+#define SM_SMALL_PAGE 		256
+#define SM_SMALL_OOB_SIZE	8
+
+
+int sm_register_device(struct mtd_info *mtd, int smartmedia);
+
+
+static inline int sm_sector_valid(struct sm_oob *oob)
+{
+	return hweight16(oob->data_status) >= 5;
+}
+
+static inline int sm_block_valid(struct sm_oob *oob)
+{
+	return hweight16(oob->block_status) >= 7;
+}
+
+static inline int sm_block_erased(struct sm_oob *oob)
+{
+	static const uint32_t erased_pattern[4] = {
+		0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+
+	/* First test for erased block */
+	if (!memcmp(oob, erased_pattern, sizeof(*oob)))
+		return 1;
+	return 0;
+}
diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
new file mode 100644
index 000000000000..9824a9923583
--- /dev/null
+++ b/drivers/mtd/nand/raw/socrates_nand.c
@@ -0,0 +1,241 @@
+/*
+ *  Copyright © 2008 Ilya Yanok, Emcraft Systems
+ *
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+#define FPGA_NAND_CMD_MASK		(0x7 << 28)
+#define FPGA_NAND_CMD_COMMAND		(0x0 << 28)
+#define FPGA_NAND_CMD_ADDR		(0x1 << 28)
+#define FPGA_NAND_CMD_READ		(0x2 << 28)
+#define FPGA_NAND_CMD_WRITE		(0x3 << 28)
+#define FPGA_NAND_BUSY			(0x1 << 15)
+#define FPGA_NAND_ENABLE		(0x1 << 31)
+#define FPGA_NAND_DATA_SHIFT		16
+
+struct socrates_nand_host {
+	struct nand_chip	nand_chip;
+	void __iomem		*io_base;
+	struct device		*dev;
+};
+
+/**
+ * socrates_nand_write_buf -  write buffer to chip
+ * @mtd:	MTD device structure
+ * @buf:	data buffer
+ * @len:	number of bytes to write
+ */
+static void socrates_nand_write_buf(struct mtd_info *mtd,
+		const uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct socrates_nand_host *host = nand_get_controller_data(this);
+
+	for (i = 0; i < len; i++) {
+		out_be32(host->io_base, FPGA_NAND_ENABLE |
+				FPGA_NAND_CMD_WRITE |
+				(buf[i] << FPGA_NAND_DATA_SHIFT));
+	}
+}
+
+/**
+ * socrates_nand_read_buf -  read chip data into buffer
+ * @mtd:	MTD device structure
+ * @buf:	buffer to store date
+ * @len:	number of bytes to read
+ */
+static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd_to_nand(mtd);
+	struct socrates_nand_host *host = nand_get_controller_data(this);
+	uint32_t val;
+
+	val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;
+
+	out_be32(host->io_base, val);
+	for (i = 0; i < len; i++) {
+		buf[i] = (in_be32(host->io_base) >>
+				FPGA_NAND_DATA_SHIFT) & 0xff;
+	}
+}
+
+/**
+ * socrates_nand_read_byte -  read one byte from the chip
+ * @mtd:	MTD device structure
+ */
+static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
+{
+	uint8_t byte;
+	socrates_nand_read_buf(mtd, &byte, sizeof(byte));
+	return byte;
+}
+
+/**
+ * socrates_nand_read_word -  read one word from the chip
+ * @mtd:	MTD device structure
+ */
+static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
+{
+	uint16_t word;
+	socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
+	return word;
+}
+
+/*
+ * Hardware specific access to control-lines
+ */
+static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+		unsigned int ctrl)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
+	uint32_t val;
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		val = FPGA_NAND_CMD_COMMAND;
+	else
+		val = FPGA_NAND_CMD_ADDR;
+
+	if (ctrl & NAND_NCE)
+		val |= FPGA_NAND_ENABLE;
+
+	val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT;
+
+	out_be32(host->io_base, val);
+}
+
+/*
+ * Read the Device Ready pin.
+ */
+static int socrates_nand_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd_to_nand(mtd);
+	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
+
+	if (in_be32(host->io_base) & FPGA_NAND_BUSY)
+		return 0; /* busy */
+	return 1;
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int socrates_nand_probe(struct platform_device *ofdev)
+{
+	struct socrates_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_chip;
+	int res;
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	host->io_base = of_iomap(ofdev->dev.of_node, 0);
+	if (host->io_base == NULL) {
+		dev_err(&ofdev->dev, "ioremap failed\n");
+		return -EIO;
+	}
+
+	nand_chip = &host->nand_chip;
+	mtd = nand_to_mtd(nand_chip);
+	host->dev = &ofdev->dev;
+
+	/* link the private data structures */
+	nand_set_controller_data(nand_chip, host);
+	nand_set_flash_node(nand_chip, ofdev->dev.of_node);
+	mtd->name = "socrates_nand";
+	mtd->dev.parent = &ofdev->dev;
+
+	/*should never be accessed directly */
+	nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
+	nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
+
+	nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
+	nand_chip->read_byte = socrates_nand_read_byte;
+	nand_chip->read_word = socrates_nand_read_word;
+	nand_chip->write_buf = socrates_nand_write_buf;
+	nand_chip->read_buf = socrates_nand_read_buf;
+	nand_chip->dev_ready = socrates_nand_device_ready;
+
+	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
+	nand_chip->ecc.algo = NAND_ECC_HAMMING;
+
+	/* TODO: I have no idea what real delay is. */
+	nand_chip->chip_delay = 20;		/* 20us command delay time */
+
+	dev_set_drvdata(&ofdev->dev, host);
+
+	res = nand_scan(mtd, 1);
+	if (res)
+		goto out;
+
+	res = mtd_device_register(mtd, NULL, 0);
+	if (!res)
+		return res;
+
+	nand_release(mtd);
+
+out:
+	iounmap(host->io_base);
+	return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int socrates_nand_remove(struct platform_device *ofdev)
+{
+	struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
+	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+
+	nand_release(mtd);
+
+	iounmap(host->io_base);
+
+	return 0;
+}
+
+static const struct of_device_id socrates_nand_match[] =
+{
+	{
+		.compatible   = "abb,socrates-nand",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, socrates_nand_match);
+
+static struct platform_driver socrates_nand_driver = {
+	.driver = {
+		.name = "socrates_nand",
+		.of_match_table = socrates_nand_match,
+	},
+	.probe		= socrates_nand_probe,
+	.remove		= socrates_nand_remove,
+};
+
+module_platform_driver(socrates_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ilya Yanok");
+MODULE_DESCRIPTION("NAND driver for Socrates board");
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
new file mode 100644
index 000000000000..f5a55c63935c
--- /dev/null
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -0,0 +1,2321 @@
+/*
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
+ *
+ * Derived from:
+ *	https://github.com/yuq/sunxi-nfc-mtd
+ *	Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
+ *
+ *	https://github.com/hno/Allwinner-Info
+ *	Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
+ *
+ *	Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
+ *	Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#define NFC_REG_CTL		0x0000
+#define NFC_REG_ST		0x0004
+#define NFC_REG_INT		0x0008
+#define NFC_REG_TIMING_CTL	0x000C
+#define NFC_REG_TIMING_CFG	0x0010
+#define NFC_REG_ADDR_LOW	0x0014
+#define NFC_REG_ADDR_HIGH	0x0018
+#define NFC_REG_SECTOR_NUM	0x001C
+#define NFC_REG_CNT		0x0020
+#define NFC_REG_CMD		0x0024
+#define NFC_REG_RCMD_SET	0x0028
+#define NFC_REG_WCMD_SET	0x002C
+#define NFC_REG_IO_DATA		0x0030
+#define NFC_REG_ECC_CTL		0x0034
+#define NFC_REG_ECC_ST		0x0038
+#define NFC_REG_DEBUG		0x003C
+#define NFC_REG_ECC_ERR_CNT(x)	((0x0040 + (x)) & ~0x3)
+#define NFC_REG_USER_DATA(x)	(0x0050 + ((x) * 4))
+#define NFC_REG_SPARE_AREA	0x00A0
+#define NFC_REG_PAT_ID		0x00A4
+#define NFC_RAM0_BASE		0x0400
+#define NFC_RAM1_BASE		0x0800
+
+/* define bit use in NFC_CTL */
+#define NFC_EN			BIT(0)
+#define NFC_RESET		BIT(1)
+#define NFC_BUS_WIDTH_MSK	BIT(2)
+#define NFC_BUS_WIDTH_8		(0 << 2)
+#define NFC_BUS_WIDTH_16	(1 << 2)
+#define NFC_RB_SEL_MSK		BIT(3)
+#define NFC_RB_SEL(x)		((x) << 3)
+#define NFC_CE_SEL_MSK		GENMASK(26, 24)
+#define NFC_CE_SEL(x)		((x) << 24)
+#define NFC_CE_CTL		BIT(6)
+#define NFC_PAGE_SHIFT_MSK	GENMASK(11, 8)
+#define NFC_PAGE_SHIFT(x)	(((x) < 10 ? 0 : (x) - 10) << 8)
+#define NFC_SAM			BIT(12)
+#define NFC_RAM_METHOD		BIT(14)
+#define NFC_DEBUG_CTL		BIT(31)
+
+/* define bit use in NFC_ST */
+#define NFC_RB_B2R		BIT(0)
+#define NFC_CMD_INT_FLAG	BIT(1)
+#define NFC_DMA_INT_FLAG	BIT(2)
+#define NFC_CMD_FIFO_STATUS	BIT(3)
+#define NFC_STA			BIT(4)
+#define NFC_NATCH_INT_FLAG	BIT(5)
+#define NFC_RB_STATE(x)		BIT(x + 8)
+
+/* define bit use in NFC_INT */
+#define NFC_B2R_INT_ENABLE	BIT(0)
+#define NFC_CMD_INT_ENABLE	BIT(1)
+#define NFC_DMA_INT_ENABLE	BIT(2)
+#define NFC_INT_MASK		(NFC_B2R_INT_ENABLE | \
+				 NFC_CMD_INT_ENABLE | \
+				 NFC_DMA_INT_ENABLE)
+
+/* define bit use in NFC_TIMING_CTL */
+#define NFC_TIMING_CTL_EDO	BIT(8)
+
+/* define NFC_TIMING_CFG register layout */
+#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD)		\
+	(((tWB) & 0x3) | (((tADL) & 0x3) << 2) |		\
+	(((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) |		\
+	(((tCAD) & 0x7) << 8))
+
+/* define bit use in NFC_CMD */
+#define NFC_CMD_LOW_BYTE_MSK	GENMASK(7, 0)
+#define NFC_CMD_HIGH_BYTE_MSK	GENMASK(15, 8)
+#define NFC_CMD(x)		(x)
+#define NFC_ADR_NUM_MSK		GENMASK(18, 16)
+#define NFC_ADR_NUM(x)		(((x) - 1) << 16)
+#define NFC_SEND_ADR		BIT(19)
+#define NFC_ACCESS_DIR		BIT(20)
+#define NFC_DATA_TRANS		BIT(21)
+#define NFC_SEND_CMD1		BIT(22)
+#define NFC_WAIT_FLAG		BIT(23)
+#define NFC_SEND_CMD2		BIT(24)
+#define NFC_SEQ			BIT(25)
+#define NFC_DATA_SWAP_METHOD	BIT(26)
+#define NFC_ROW_AUTO_INC	BIT(27)
+#define NFC_SEND_CMD3		BIT(28)
+#define NFC_SEND_CMD4		BIT(29)
+#define NFC_CMD_TYPE_MSK	GENMASK(31, 30)
+#define NFC_NORMAL_OP		(0 << 30)
+#define NFC_ECC_OP		(1 << 30)
+#define NFC_PAGE_OP		(2 << 30)
+
+/* define bit use in NFC_RCMD_SET */
+#define NFC_READ_CMD_MSK	GENMASK(7, 0)
+#define NFC_RND_READ_CMD0_MSK	GENMASK(15, 8)
+#define NFC_RND_READ_CMD1_MSK	GENMASK(23, 16)
+
+/* define bit use in NFC_WCMD_SET */
+#define NFC_PROGRAM_CMD_MSK	GENMASK(7, 0)
+#define NFC_RND_WRITE_CMD_MSK	GENMASK(15, 8)
+#define NFC_READ_CMD0_MSK	GENMASK(23, 16)
+#define NFC_READ_CMD1_MSK	GENMASK(31, 24)
+
+/* define bit use in NFC_ECC_CTL */
+#define NFC_ECC_EN		BIT(0)
+#define NFC_ECC_PIPELINE	BIT(3)
+#define NFC_ECC_EXCEPTION	BIT(4)
+#define NFC_ECC_BLOCK_SIZE_MSK	BIT(5)
+#define NFC_ECC_BLOCK_512	BIT(5)
+#define NFC_RANDOM_EN		BIT(9)
+#define NFC_RANDOM_DIRECTION	BIT(10)
+#define NFC_ECC_MODE_MSK	GENMASK(15, 12)
+#define NFC_ECC_MODE(x)		((x) << 12)
+#define NFC_RANDOM_SEED_MSK	GENMASK(30, 16)
+#define NFC_RANDOM_SEED(x)	((x) << 16)
+
+/* define bit use in NFC_ECC_ST */
+#define NFC_ECC_ERR(x)		BIT(x)
+#define NFC_ECC_ERR_MSK		GENMASK(15, 0)
+#define NFC_ECC_PAT_FOUND(x)	BIT(x + 16)
+#define NFC_ECC_ERR_CNT(b, x)	(((x) >> (((b) % 4) * 8)) & 0xff)
+
+#define NFC_DEFAULT_TIMEOUT_MS	1000
+
+#define NFC_SRAM_SIZE		1024
+
+#define NFC_MAX_CS		7
+
+/*
+ * Ready/Busy detection type: describes the Ready/Busy detection modes
+ *
+ * @RB_NONE:	no external detection available, rely on STATUS command
+ *		and software timeouts
+ * @RB_NATIVE:	use sunxi NAND controller Ready/Busy support. The Ready/Busy
+ *		pin of the NAND flash chip must be connected to one of the
+ *		native NAND R/B pins (those which can be muxed to the NAND
+ *		Controller)
+ * @RB_GPIO:	use a simple GPIO to handle Ready/Busy status. The Ready/Busy
+ *		pin of the NAND flash chip must be connected to a GPIO capable
+ *		pin.
+ */
+enum sunxi_nand_rb_type {
+	RB_NONE,
+	RB_NATIVE,
+	RB_GPIO,
+};
+
+/*
+ * Ready/Busy structure: stores information related to Ready/Busy detection
+ *
+ * @type:	the Ready/Busy detection mode
+ * @info:	information related to the R/B detection mode. Either a gpio
+ *		id or a native R/B id (those supported by the NAND controller).
+ */
+struct sunxi_nand_rb {
+	enum sunxi_nand_rb_type type;
+	union {
+		int gpio;
+		int nativeid;
+	} info;
+};
+
+/*
+ * Chip Select structure: stores information related to NAND Chip Select
+ *
+ * @cs:		the NAND CS id used to communicate with a NAND Chip
+ * @rb:		the Ready/Busy description
+ */
+struct sunxi_nand_chip_sel {
+	u8 cs;
+	struct sunxi_nand_rb rb;
+};
+
+/*
+ * sunxi HW ECC infos: stores information related to HW ECC support
+ *
+ * @mode:	the sunxi ECC mode field deduced from ECC requirements
+ */
+struct sunxi_nand_hw_ecc {
+	int mode;
+};
+
+/*
+ * NAND chip structure: stores NAND chip device related information
+ *
+ * @node:		used to store NAND chips into a list
+ * @nand:		base NAND chip structure
+ * @mtd:		base MTD structure
+ * @clk_rate:		clk_rate required for this NAND chip
+ * @timing_cfg		TIMING_CFG register value for this NAND chip
+ * @selected:		current active CS
+ * @nsels:		number of CS lines required by the NAND chip
+ * @sels:		array of CS lines descriptions
+ */
+struct sunxi_nand_chip {
+	struct list_head node;
+	struct nand_chip nand;
+	unsigned long clk_rate;
+	u32 timing_cfg;
+	u32 timing_ctl;
+	int selected;
+	int addr_cycles;
+	u32 addr[2];
+	int cmd_cycles;
+	u8 cmd[2];
+	int nsels;
+	struct sunxi_nand_chip_sel sels[0];
+};
+
+static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
+{
+	return container_of(nand, struct sunxi_nand_chip, nand);
+}
+
+/*
+ * NAND Controller structure: stores sunxi NAND controller information
+ *
+ * @controller:		base controller structure
+ * @dev:		parent device (used to print error messages)
+ * @regs:		NAND controller registers
+ * @ahb_clk:		NAND Controller AHB clock
+ * @mod_clk:		NAND Controller mod clock
+ * @assigned_cs:	bitmask describing already assigned CS lines
+ * @clk_rate:		NAND controller current clock rate
+ * @chips:		a list containing all the NAND chips attached to
+ *			this NAND controller
+ * @complete:		a completion object used to wait for NAND
+ *			controller events
+ */
+struct sunxi_nfc {
+	struct nand_hw_control controller;
+	struct device *dev;
+	void __iomem *regs;
+	struct clk *ahb_clk;
+	struct clk *mod_clk;
+	struct reset_control *reset;
+	unsigned long assigned_cs;
+	unsigned long clk_rate;
+	struct list_head chips;
+	struct completion complete;
+	struct dma_chan *dmac;
+};
+
+static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
+{
+	return container_of(ctrl, struct sunxi_nfc, controller);
+}
+
+static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
+{
+	struct sunxi_nfc *nfc = dev_id;
+	u32 st = readl(nfc->regs + NFC_REG_ST);
+	u32 ien = readl(nfc->regs + NFC_REG_INT);
+
+	if (!(ien & st))
+		return IRQ_NONE;
+
+	if ((ien & st) == ien)
+		complete(&nfc->complete);
+
+	writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+	writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
+
+	return IRQ_HANDLED;
+}
+
+static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
+				 bool use_polling, unsigned int timeout_ms)
+{
+	int ret;
+
+	if (events & ~NFC_INT_MASK)
+		return -EINVAL;
+
+	if (!timeout_ms)
+		timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
+
+	if (!use_polling) {
+		init_completion(&nfc->complete);
+
+		writel(events, nfc->regs + NFC_REG_INT);
+
+		ret = wait_for_completion_timeout(&nfc->complete,
+						msecs_to_jiffies(timeout_ms));
+		if (!ret)
+			ret = -ETIMEDOUT;
+		else
+			ret = 0;
+
+		writel(0, nfc->regs + NFC_REG_INT);
+	} else {
+		u32 status;
+
+		ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
+					 (status & events) == events, 1,
+					 timeout_ms * 1000);
+	}
+
+	writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
+
+	if (ret)
+		dev_err(nfc->dev, "wait interrupt timedout\n");
+
+	return ret;
+}
+
+static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
+{
+	u32 status;
+	int ret;
+
+	ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
+				 !(status & NFC_CMD_FIFO_STATUS), 1,
+				 NFC_DEFAULT_TIMEOUT_MS * 1000);
+	if (ret)
+		dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
+
+	return ret;
+}
+
+static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
+{
+	u32 ctl;
+	int ret;
+
+	writel(0, nfc->regs + NFC_REG_ECC_CTL);
+	writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
+
+	ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
+				 !(ctl & NFC_RESET), 1,
+				 NFC_DEFAULT_TIMEOUT_MS * 1000);
+	if (ret)
+		dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
+
+	return ret;
+}
+
+static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
+				    int chunksize, int nchunks,
+				    enum dma_data_direction ddir,
+				    struct scatterlist *sg)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct dma_async_tx_descriptor *dmad;
+	enum dma_transfer_direction tdir;
+	dma_cookie_t dmat;
+	int ret;
+
+	if (ddir == DMA_FROM_DEVICE)
+		tdir = DMA_DEV_TO_MEM;
+	else
+		tdir = DMA_MEM_TO_DEV;
+
+	sg_init_one(sg, buf, nchunks * chunksize);
+	ret = dma_map_sg(nfc->dev, sg, 1, ddir);
+	if (!ret)
+		return -ENOMEM;
+
+	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
+	if (!dmad) {
+		ret = -EINVAL;
+		goto err_unmap_buf;
+	}
+
+	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
+	       nfc->regs + NFC_REG_CTL);
+	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
+	writel(chunksize, nfc->regs + NFC_REG_CNT);
+	dmat = dmaengine_submit(dmad);
+
+	ret = dma_submit_error(dmat);
+	if (ret)
+		goto err_clr_dma_flag;
+
+	return 0;
+
+err_clr_dma_flag:
+	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+	       nfc->regs + NFC_REG_CTL);
+
+err_unmap_buf:
+	dma_unmap_sg(nfc->dev, sg, 1, ddir);
+	return ret;
+}
+
+static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
+				     enum dma_data_direction ddir,
+				     struct scatterlist *sg)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+	dma_unmap_sg(nfc->dev, sg, 1, ddir);
+	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+	       nfc->regs + NFC_REG_CTL);
+}
+
+static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct sunxi_nand_rb *rb;
+	int ret;
+
+	if (sunxi_nand->selected < 0)
+		return 0;
+
+	rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
+
+	switch (rb->type) {
+	case RB_NATIVE:
+		ret = !!(readl(nfc->regs + NFC_REG_ST) &
+			 NFC_RB_STATE(rb->info.nativeid));
+		break;
+	case RB_GPIO:
+		ret = gpio_get_value(rb->info.gpio);
+		break;
+	case RB_NONE:
+	default:
+		ret = 0;
+		dev_err(nfc->dev, "cannot check R/B NAND status!\n");
+		break;
+	}
+
+	return ret;
+}
+
+static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct sunxi_nand_chip_sel *sel;
+	u32 ctl;
+
+	if (chip > 0 && chip >= sunxi_nand->nsels)
+		return;
+
+	if (chip == sunxi_nand->selected)
+		return;
+
+	ctl = readl(nfc->regs + NFC_REG_CTL) &
+	      ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
+
+	if (chip >= 0) {
+		sel = &sunxi_nand->sels[chip];
+
+		ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
+		       NFC_PAGE_SHIFT(nand->page_shift);
+		if (sel->rb.type == RB_NONE) {
+			nand->dev_ready = NULL;
+		} else {
+			nand->dev_ready = sunxi_nfc_dev_ready;
+			if (sel->rb.type == RB_NATIVE)
+				ctl |= NFC_RB_SEL(sel->rb.info.nativeid);
+		}
+
+		writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
+
+		if (nfc->clk_rate != sunxi_nand->clk_rate) {
+			clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
+			nfc->clk_rate = sunxi_nand->clk_rate;
+		}
+	}
+
+	writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
+	writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
+	writel(ctl, nfc->regs + NFC_REG_CTL);
+
+	sunxi_nand->selected = chip;
+}
+
+static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	int ret;
+	int cnt;
+	int offs = 0;
+	u32 tmp;
+
+	while (len > offs) {
+		bool poll = false;
+
+		cnt = min(len - offs, NFC_SRAM_SIZE);
+
+		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+		if (ret)
+			break;
+
+		writel(cnt, nfc->regs + NFC_REG_CNT);
+		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
+		writel(tmp, nfc->regs + NFC_REG_CMD);
+
+		/* Arbitrary limit for polling mode */
+		if (cnt < 64)
+			poll = true;
+
+		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
+		if (ret)
+			break;
+
+		if (buf)
+			memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
+				      cnt);
+		offs += cnt;
+	}
+}
+
+static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				int len)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	int ret;
+	int cnt;
+	int offs = 0;
+	u32 tmp;
+
+	while (len > offs) {
+		bool poll = false;
+
+		cnt = min(len - offs, NFC_SRAM_SIZE);
+
+		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+		if (ret)
+			break;
+
+		writel(cnt, nfc->regs + NFC_REG_CNT);
+		memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
+		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+		      NFC_ACCESS_DIR;
+		writel(tmp, nfc->regs + NFC_REG_CMD);
+
+		/* Arbitrary limit for polling mode */
+		if (cnt < 64)
+			poll = true;
+
+		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
+		if (ret)
+			break;
+
+		offs += cnt;
+	}
+}
+
+static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+{
+	uint8_t ret;
+
+	sunxi_nfc_read_buf(mtd, &ret, 1);
+
+	return ret;
+}
+
+static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+			       unsigned int ctrl)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	int ret;
+
+	if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
+	    !(ctrl & (NAND_CLE | NAND_ALE))) {
+		u32 cmd = 0;
+
+		if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
+			return;
+
+		if (sunxi_nand->cmd_cycles--)
+			cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
+
+		if (sunxi_nand->cmd_cycles--) {
+			cmd |= NFC_SEND_CMD2;
+			writel(sunxi_nand->cmd[1],
+			       nfc->regs + NFC_REG_RCMD_SET);
+		}
+
+		sunxi_nand->cmd_cycles = 0;
+
+		if (sunxi_nand->addr_cycles) {
+			cmd |= NFC_SEND_ADR |
+			       NFC_ADR_NUM(sunxi_nand->addr_cycles);
+			writel(sunxi_nand->addr[0],
+			       nfc->regs + NFC_REG_ADDR_LOW);
+		}
+
+		if (sunxi_nand->addr_cycles > 4)
+			writel(sunxi_nand->addr[1],
+			       nfc->regs + NFC_REG_ADDR_HIGH);
+
+		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+		if (ret)
+			return;
+
+		writel(cmd, nfc->regs + NFC_REG_CMD);
+		sunxi_nand->addr[0] = 0;
+		sunxi_nand->addr[1] = 0;
+		sunxi_nand->addr_cycles = 0;
+		sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
+	}
+
+	if (ctrl & NAND_CLE) {
+		sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
+	} else if (ctrl & NAND_ALE) {
+		sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
+				dat << ((sunxi_nand->addr_cycles % 4) * 8);
+		sunxi_nand->addr_cycles++;
+	}
+}
+
+/* These seed values have been extracted from Allwinner's BSP */
+static const u16 sunxi_nfc_randomizer_page_seeds[] = {
+	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+};
+
+/*
+ * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
+ * have been generated using
+ * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
+ * the randomizer engine does internally before de/scrambling OOB data.
+ *
+ * Those tables are statically defined to avoid calculating randomizer state
+ * at runtime.
+ */
+static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
+	0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
+	0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
+	0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
+	0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
+	0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
+	0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
+	0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
+	0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
+	0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
+	0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
+	0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
+	0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
+	0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
+	0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
+	0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
+	0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
+};
+
+static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
+	0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
+	0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
+	0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
+	0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
+	0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
+	0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
+	0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
+	0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
+	0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
+	0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
+	0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
+	0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
+	0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
+	0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
+	0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
+	0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
+};
+
+static u16 sunxi_nfc_randomizer_step(u16 state, int count)
+{
+	state &= 0x7fff;
+
+	/*
+	 * This loop is just a simple implementation of a Fibonacci LFSR using
+	 * the x16 + x15 + 1 polynomial.
+	 */
+	while (count--)
+		state = ((state >> 1) |
+			 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+	return state;
+}
+
+static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
+{
+	const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
+	int mod = mtd_div_by_ws(mtd->erasesize, mtd);
+
+	if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
+		mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
+
+	if (ecc) {
+		if (mtd->ecc_step_size == 512)
+			seeds = sunxi_nfc_randomizer_ecc512_seeds;
+		else
+			seeds = sunxi_nfc_randomizer_ecc1024_seeds;
+	}
+
+	return seeds[page % mod];
+}
+
+static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
+					int page, bool ecc)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+	u16 state;
+
+	if (!(nand->options & NAND_NEED_SCRAMBLING))
+		return;
+
+	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+	state = sunxi_nfc_randomizer_state(mtd, page, ecc);
+	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
+	writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+	if (!(nand->options & NAND_NEED_SCRAMBLING))
+		return;
+
+	writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
+	       nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+	if (!(nand->options & NAND_NEED_SCRAMBLING))
+		return;
+
+	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+	       nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
+{
+	u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
+
+	bbm[0] ^= state;
+	bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
+}
+
+static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
+					   const uint8_t *buf, int len,
+					   bool ecc, int page)
+{
+	sunxi_nfc_randomizer_config(mtd, page, ecc);
+	sunxi_nfc_randomizer_enable(mtd);
+	sunxi_nfc_write_buf(mtd, buf, len);
+	sunxi_nfc_randomizer_disable(mtd);
+}
+
+static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
+					  int len, bool ecc, int page)
+{
+	sunxi_nfc_randomizer_config(mtd, page, ecc);
+	sunxi_nfc_randomizer_enable(mtd);
+	sunxi_nfc_read_buf(mtd, buf, len);
+	sunxi_nfc_randomizer_disable(mtd);
+}
+
+static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
+	u32 ecc_ctl;
+
+	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+	ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
+		     NFC_ECC_BLOCK_SIZE_MSK);
+	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
+		   NFC_ECC_PIPELINE;
+
+	if (nand->ecc.size == 512)
+		ecc_ctl |= NFC_ECC_BLOCK_512;
+
+	writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
+	       nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
+{
+	buf[0] = user_data;
+	buf[1] = user_data >> 8;
+	buf[2] = user_data >> 16;
+	buf[3] = user_data >> 24;
+}
+
+static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
+{
+	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
+						int step, bool bbm, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
+				   oob);
+
+	/* De-randomize the Bad Block Marker. */
+	if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
+		sunxi_nfc_randomize_bbm(mtd, page, oob);
+}
+
+static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
+						const u8 *oob, int step,
+						bool bbm, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	u8 user_data[4];
+
+	/* Randomize the Bad Block Marker. */
+	if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
+		memcpy(user_data, oob, sizeof(user_data));
+		sunxi_nfc_randomize_bbm(mtd, page, user_data);
+		oob = user_data;
+	}
+
+	writel(sunxi_nfc_buf_to_user_data(oob),
+	       nfc->regs + NFC_REG_USER_DATA(step));
+}
+
+static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
+					  unsigned int *max_bitflips, int ret)
+{
+	if (ret < 0) {
+		mtd->ecc_stats.failed++;
+	} else {
+		mtd->ecc_stats.corrected += ret;
+		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+	}
+}
+
+static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
+				    int step, u32 status, bool *erased)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	u32 tmp;
+
+	*erased = false;
+
+	if (status & NFC_ECC_ERR(step))
+		return -EBADMSG;
+
+	if (status & NFC_ECC_PAT_FOUND(step)) {
+		u8 pattern;
+
+		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
+			pattern = 0x0;
+		} else {
+			pattern = 0xff;
+			*erased = true;
+		}
+
+		if (data)
+			memset(data, pattern, ecc->size);
+
+		if (oob)
+			memset(oob, pattern, ecc->bytes + 4);
+
+		return 0;
+	}
+
+	tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
+
+	return NFC_ECC_ERR_CNT(step, tmp);
+}
+
+static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
+				       u8 *data, int data_off,
+				       u8 *oob, int oob_off,
+				       int *cur_off,
+				       unsigned int *max_bitflips,
+				       bool bbm, bool oob_required, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	int raw_mode = 0;
+	bool erased;
+	int ret;
+
+	if (*cur_off != data_off)
+		nand_change_read_column_op(nand, data_off, NULL, 0, false);
+
+	sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
+
+	if (data_off + ecc->size != oob_off)
+		nand_change_read_column_op(nand, oob_off, NULL, 0, false);
+
+	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+	if (ret)
+		return ret;
+
+	sunxi_nfc_randomizer_enable(mtd);
+	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
+	       nfc->regs + NFC_REG_CMD);
+
+	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+	sunxi_nfc_randomizer_disable(mtd);
+	if (ret)
+		return ret;
+
+	*cur_off = oob_off + ecc->bytes + 4;
+
+	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
+				       readl(nfc->regs + NFC_REG_ECC_ST),
+				       &erased);
+	if (erased)
+		return 1;
+
+	if (ret < 0) {
+		/*
+		 * Re-read the data with the randomizer disabled to identify
+		 * bitflips in erased pages.
+		 */
+		if (nand->options & NAND_NEED_SCRAMBLING)
+			nand_change_read_column_op(nand, data_off, data,
+						   ecc->size, false);
+		else
+			memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
+				      ecc->size);
+
+		nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
+					   false);
+
+		ret = nand_check_erased_ecc_chunk(data,	ecc->size,
+						  oob, ecc->bytes + 4,
+						  NULL, 0, ecc->strength);
+		if (ret >= 0)
+			raw_mode = 1;
+	} else {
+		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
+
+		if (oob_required) {
+			nand_change_read_column_op(nand, oob_off, NULL, 0,
+						   false);
+			sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
+						      true, page);
+
+			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
+							    bbm, page);
+		}
+	}
+
+	sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
+
+	return raw_mode;
+}
+
+static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
+					    u8 *oob, int *cur_off,
+					    bool randomize, int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	int offset = ((ecc->bytes + 4) * ecc->steps);
+	int len = mtd->oobsize - offset;
+
+	if (len <= 0)
+		return;
+
+	if (!cur_off || *cur_off != offset)
+		nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
+					   false);
+
+	if (!randomize)
+		sunxi_nfc_read_buf(mtd, oob + offset, len);
+	else
+		sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
+					      false, page);
+
+	if (cur_off)
+		*cur_off = mtd->oobsize + mtd->writesize;
+}
+
+static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
+					    int oob_required, int page,
+					    int nchunks)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	bool randomized = nand->options & NAND_NEED_SCRAMBLING;
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	unsigned int max_bitflips = 0;
+	int ret, i, raw_mode = 0;
+	struct scatterlist sg;
+	u32 status;
+
+	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+	if (ret)
+		return ret;
+
+	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
+				       DMA_FROM_DEVICE, &sg);
+	if (ret)
+		return ret;
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+	sunxi_nfc_randomizer_config(mtd, page, false);
+	sunxi_nfc_randomizer_enable(mtd);
+
+	writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
+	       NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
+
+	dma_async_issue_pending(nfc->dmac);
+
+	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
+	       nfc->regs + NFC_REG_CMD);
+
+	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+	if (ret)
+		dmaengine_terminate_all(nfc->dmac);
+
+	sunxi_nfc_randomizer_disable(mtd);
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
+
+	if (ret)
+		return ret;
+
+	status = readl(nfc->regs + NFC_REG_ECC_ST);
+
+	for (i = 0; i < nchunks; i++) {
+		int data_off = i * ecc->size;
+		int oob_off = i * (ecc->bytes + 4);
+		u8 *data = buf + data_off;
+		u8 *oob = nand->oob_poi + oob_off;
+		bool erased;
+
+		ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
+					       oob_required ? oob : NULL,
+					       i, status, &erased);
+
+		/* ECC errors are handled in the second loop. */
+		if (ret < 0)
+			continue;
+
+		if (oob_required && !erased) {
+			/* TODO: use DMA to retrieve OOB */
+			nand_change_read_column_op(nand,
+						   mtd->writesize + oob_off,
+						   oob, ecc->bytes + 4, false);
+
+			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
+							    !i, page);
+		}
+
+		if (erased)
+			raw_mode = 1;
+
+		sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
+	}
+
+	if (status & NFC_ECC_ERR_MSK) {
+		for (i = 0; i < nchunks; i++) {
+			int data_off = i * ecc->size;
+			int oob_off = i * (ecc->bytes + 4);
+			u8 *data = buf + data_off;
+			u8 *oob = nand->oob_poi + oob_off;
+
+			if (!(status & NFC_ECC_ERR(i)))
+				continue;
+
+			/*
+			 * Re-read the data with the randomizer disabled to
+			 * identify bitflips in erased pages.
+			 * TODO: use DMA to read page in raw mode
+			 */
+			if (randomized)
+				nand_change_read_column_op(nand, data_off,
+							   data, ecc->size,
+							   false);
+
+			/* TODO: use DMA to retrieve OOB */
+			nand_change_read_column_op(nand,
+						   mtd->writesize + oob_off,
+						   oob, ecc->bytes + 4, false);
+
+			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
+							  oob, ecc->bytes + 4,
+							  NULL, 0,
+							  ecc->strength);
+			if (ret >= 0)
+				raw_mode = 1;
+
+			sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
+		}
+	}
+
+	if (oob_required)
+		sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
+						NULL, !raw_mode,
+						page);
+
+	return max_bitflips;
+}
+
+static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
+					const u8 *data, int data_off,
+					const u8 *oob, int oob_off,
+					int *cur_off, bool bbm,
+					int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	int ret;
+
+	if (data_off != *cur_off)
+		nand_change_write_column_op(nand, data_off, NULL, 0, false);
+
+	sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
+
+	if (data_off + ecc->size != oob_off)
+		nand_change_write_column_op(nand, oob_off, NULL, 0, false);
+
+	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+	if (ret)
+		return ret;
+
+	sunxi_nfc_randomizer_enable(mtd);
+	sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
+
+	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+	       NFC_ACCESS_DIR | NFC_ECC_OP,
+	       nfc->regs + NFC_REG_CMD);
+
+	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+	sunxi_nfc_randomizer_disable(mtd);
+	if (ret)
+		return ret;
+
+	*cur_off = oob_off + ecc->bytes + 4;
+
+	return 0;
+}
+
+static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
+					     u8 *oob, int *cur_off,
+					     int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	int offset = ((ecc->bytes + 4) * ecc->steps);
+	int len = mtd->oobsize - offset;
+
+	if (len <= 0)
+		return;
+
+	if (!cur_off || *cur_off != offset)
+		nand_change_write_column_op(nand, offset + mtd->writesize,
+					    NULL, 0, false);
+
+	sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
+
+	if (cur_off)
+		*cur_off = mtd->oobsize + mtd->writesize;
+}
+
+static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
+				      struct nand_chip *chip, uint8_t *buf,
+				      int oob_required, int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	int ret, i, cur_off = 0;
+	bool raw_mode = false;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_off = i * ecc->size;
+		int oob_off = i * (ecc->bytes + 4);
+		u8 *data = buf + data_off;
+		u8 *oob = chip->oob_poi + oob_off;
+
+		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+						  oob_off + mtd->writesize,
+						  &cur_off, &max_bitflips,
+						  !i, oob_required, page);
+		if (ret < 0)
+			return ret;
+		else if (ret)
+			raw_mode = true;
+	}
+
+	if (oob_required)
+		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+						!raw_mode, page);
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return max_bitflips;
+}
+
+static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
+					  struct nand_chip *chip, u8 *buf,
+					  int oob_required, int page)
+{
+	int ret;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
+					       chip->ecc.steps);
+	if (ret >= 0)
+		return ret;
+
+	/* Fallback to PIO mode */
+	return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
+}
+
+static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
+					 struct nand_chip *chip,
+					 u32 data_offs, u32 readlen,
+					 u8 *bufpoi, int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret, i, cur_off = 0;
+	unsigned int max_bitflips = 0;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	for (i = data_offs / ecc->size;
+	     i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
+		int data_off = i * ecc->size;
+		int oob_off = i * (ecc->bytes + 4);
+		u8 *data = bufpoi + data_off;
+		u8 *oob = chip->oob_poi + oob_off;
+
+		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
+						  oob,
+						  oob_off + mtd->writesize,
+						  &cur_off, &max_bitflips, !i,
+						  false, page);
+		if (ret < 0)
+			return ret;
+	}
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return max_bitflips;
+}
+
+static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     u32 data_offs, u32 readlen,
+					     u8 *buf, int page)
+{
+	int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
+	int ret;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
+	if (ret >= 0)
+		return ret;
+
+	/* Fallback to PIO mode */
+	return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
+					     buf, page);
+}
+
+static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
+				       struct nand_chip *chip,
+				       const uint8_t *buf, int oob_required,
+				       int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret, i, cur_off = 0;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_off = i * ecc->size;
+		int oob_off = i * (ecc->bytes + 4);
+		const u8 *data = buf + data_off;
+		const u8 *oob = chip->oob_poi + oob_off;
+
+		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+						   oob_off + mtd->writesize,
+						   &cur_off, !i, page);
+		if (ret)
+			return ret;
+	}
+
+	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+						 &cur_off, page);
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
+					  struct nand_chip *chip,
+					  u32 data_offs, u32 data_len,
+					  const u8 *buf, int oob_required,
+					  int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret, i, cur_off = 0;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	for (i = data_offs / ecc->size;
+	     i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
+		int data_off = i * ecc->size;
+		int oob_off = i * (ecc->bytes + 4);
+		const u8 *data = buf + data_off;
+		const u8 *oob = chip->oob_poi + oob_off;
+
+		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+						   oob_off + mtd->writesize,
+						   &cur_off, !i, page);
+		if (ret)
+			return ret;
+	}
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
+					   struct nand_chip *chip,
+					   const u8 *buf,
+					   int oob_required,
+					   int page)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+	struct scatterlist sg;
+	int ret, i;
+
+	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+	if (ret)
+		return ret;
+
+	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
+				       DMA_TO_DEVICE, &sg);
+	if (ret)
+		goto pio_fallback;
+
+	for (i = 0; i < ecc->steps; i++) {
+		const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
+
+		sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
+	}
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+	sunxi_nfc_randomizer_config(mtd, page, false);
+	sunxi_nfc_randomizer_enable(mtd);
+
+	writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
+	       nfc->regs + NFC_REG_RCMD_SET);
+
+	dma_async_issue_pending(nfc->dmac);
+
+	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
+	       NFC_DATA_TRANS | NFC_ACCESS_DIR,
+	       nfc->regs + NFC_REG_CMD);
+
+	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
+	if (ret)
+		dmaengine_terminate_all(nfc->dmac);
+
+	sunxi_nfc_randomizer_disable(mtd);
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
+
+	if (ret)
+		return ret;
+
+	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+		/* TODO: use DMA to transfer extra OOB bytes ? */
+		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+						 NULL, page);
+
+	return nand_prog_page_end_op(chip);
+
+pio_fallback:
+	return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
+}
+
+static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
+					       struct nand_chip *chip,
+					       uint8_t *buf, int oob_required,
+					       int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	unsigned int max_bitflips = 0;
+	int ret, i, cur_off = 0;
+	bool raw_mode = false;
+
+	nand_read_page_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_off = i * (ecc->size + ecc->bytes + 4);
+		int oob_off = data_off + ecc->size;
+		u8 *data = buf + (i * ecc->size);
+		u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+
+		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+						  oob_off, &cur_off,
+						  &max_bitflips, !i,
+						  oob_required,
+						  page);
+		if (ret < 0)
+			return ret;
+		else if (ret)
+			raw_mode = true;
+	}
+
+	if (oob_required)
+		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+						!raw_mode, page);
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return max_bitflips;
+}
+
+static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
+						struct nand_chip *chip,
+						const uint8_t *buf,
+						int oob_required, int page)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	int ret, i, cur_off = 0;
+
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
+	sunxi_nfc_hw_ecc_enable(mtd);
+
+	for (i = 0; i < ecc->steps; i++) {
+		int data_off = i * (ecc->size + ecc->bytes + 4);
+		int oob_off = data_off + ecc->size;
+		const u8 *data = buf + (i * ecc->size);
+		const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+
+		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
+						   oob, oob_off, &cur_off,
+						   false, page);
+		if (ret)
+			return ret;
+	}
+
+	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+						 &cur_off, page);
+
+	sunxi_nfc_hw_ecc_disable(mtd);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    int page)
+{
+	chip->pagebuf = -1;
+
+	return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
+}
+
+static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     int page)
+{
+	int ret;
+
+	chip->pagebuf = -1;
+
+	memset(chip->data_buf, 0xff, mtd->writesize);
+	ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
+	if (ret)
+		return ret;
+
+	/* Send command to program the OOB data */
+	return nand_prog_page_end_op(chip);
+}
+
+static const s32 tWB_lut[] = {6, 12, 16, 20};
+static const s32 tRHW_lut[] = {4, 8, 12, 20};
+
+static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
+		u32 clk_period)
+{
+	u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
+	int i;
+
+	for (i = 0; i < lut_size; i++) {
+		if (clk_cycles <= lut[i])
+			return i;
+	}
+
+	/* Doesn't fit */
+	return -EINVAL;
+}
+
+#define sunxi_nand_lookup_timing(l, p, c) \
+			_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
+
+static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+					const struct nand_data_interface *conf)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
+	const struct nand_sdr_timings *timings;
+	u32 min_clk_period = 0;
+	s32 tWB, tADL, tWHR, tRHW, tCAD;
+	long real_clk_rate;
+
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return -ENOTSUPP;
+
+	/* T1 <=> tCLS */
+	if (timings->tCLS_min > min_clk_period)
+		min_clk_period = timings->tCLS_min;
+
+	/* T2 <=> tCLH */
+	if (timings->tCLH_min > min_clk_period)
+		min_clk_period = timings->tCLH_min;
+
+	/* T3 <=> tCS */
+	if (timings->tCS_min > min_clk_period)
+		min_clk_period = timings->tCS_min;
+
+	/* T4 <=> tCH */
+	if (timings->tCH_min > min_clk_period)
+		min_clk_period = timings->tCH_min;
+
+	/* T5 <=> tWP */
+	if (timings->tWP_min > min_clk_period)
+		min_clk_period = timings->tWP_min;
+
+	/* T6 <=> tWH */
+	if (timings->tWH_min > min_clk_period)
+		min_clk_period = timings->tWH_min;
+
+	/* T7 <=> tALS */
+	if (timings->tALS_min > min_clk_period)
+		min_clk_period = timings->tALS_min;
+
+	/* T8 <=> tDS */
+	if (timings->tDS_min > min_clk_period)
+		min_clk_period = timings->tDS_min;
+
+	/* T9 <=> tDH */
+	if (timings->tDH_min > min_clk_period)
+		min_clk_period = timings->tDH_min;
+
+	/* T10 <=> tRR */
+	if (timings->tRR_min > (min_clk_period * 3))
+		min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
+
+	/* T11 <=> tALH */
+	if (timings->tALH_min > min_clk_period)
+		min_clk_period = timings->tALH_min;
+
+	/* T12 <=> tRP */
+	if (timings->tRP_min > min_clk_period)
+		min_clk_period = timings->tRP_min;
+
+	/* T13 <=> tREH */
+	if (timings->tREH_min > min_clk_period)
+		min_clk_period = timings->tREH_min;
+
+	/* T14 <=> tRC */
+	if (timings->tRC_min > (min_clk_period * 2))
+		min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
+
+	/* T15 <=> tWC */
+	if (timings->tWC_min > (min_clk_period * 2))
+		min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
+
+	/* T16 - T19 + tCAD */
+	if (timings->tWB_max > (min_clk_period * 20))
+		min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
+
+	if (timings->tADL_min > (min_clk_period * 32))
+		min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
+
+	if (timings->tWHR_min > (min_clk_period * 32))
+		min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
+
+	if (timings->tRHW_min > (min_clk_period * 20))
+		min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
+
+	tWB  = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
+					min_clk_period);
+	if (tWB < 0) {
+		dev_err(nfc->dev, "unsupported tWB\n");
+		return tWB;
+	}
+
+	tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
+	if (tADL > 3) {
+		dev_err(nfc->dev, "unsupported tADL\n");
+		return -EINVAL;
+	}
+
+	tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
+	if (tWHR > 3) {
+		dev_err(nfc->dev, "unsupported tWHR\n");
+		return -EINVAL;
+	}
+
+	tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
+					min_clk_period);
+	if (tRHW < 0) {
+		dev_err(nfc->dev, "unsupported tRHW\n");
+		return tRHW;
+	}
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	/*
+	 * TODO: according to ONFI specs this value only applies for DDR NAND,
+	 * but Allwinner seems to set this to 0x7. Mimic them for now.
+	 */
+	tCAD = 0x7;
+
+	/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
+	chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
+
+	/* Convert min_clk_period from picoseconds to nanoseconds */
+	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
+
+	/*
+	 * Unlike what is stated in Allwinner datasheet, the clk_rate should
+	 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
+	 * This new formula was verified with a scope and validated by
+	 * Allwinner engineers.
+	 */
+	chip->clk_rate = NSEC_PER_SEC / min_clk_period;
+	real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
+	if (real_clk_rate <= 0) {
+		dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate);
+		return -EINVAL;
+	}
+
+	/*
+	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
+	 * output cycle timings shall be used if the host drives tRC less than
+	 * 30 ns.
+	 */
+	min_clk_period = NSEC_PER_SEC / real_clk_rate;
+	chip->timing_ctl = ((min_clk_period * 2) < 30) ?
+			   NFC_TIMING_CTL_EDO : 0;
+
+	return 0;
+}
+
+static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+	if (section >= ecc->steps)
+		return -ERANGE;
+
+	oobregion->offset = section * (ecc->bytes + 4) + 4;
+	oobregion->length = ecc->bytes;
+
+	return 0;
+}
+
+static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
+				     struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+	if (section > ecc->steps)
+		return -ERANGE;
+
+	/*
+	 * The first 2 bytes are used for BB markers, hence we
+	 * only have 2 bytes available in the first user data
+	 * section.
+	 */
+	if (!section && ecc->mode == NAND_ECC_HW) {
+		oobregion->offset = 2;
+		oobregion->length = 2;
+
+		return 0;
+	}
+
+	oobregion->offset = section * (ecc->bytes + 4);
+
+	if (section < ecc->steps)
+		oobregion->length = 4;
+	else
+		oobregion->offset = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
+	.ecc = sunxi_nand_ooblayout_ecc,
+	.free = sunxi_nand_ooblayout_free,
+};
+
+static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
+					      struct nand_ecc_ctrl *ecc,
+					      struct device_node *np)
+{
+	static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	struct sunxi_nand_hw_ecc *data;
+	int nsectors;
+	int ret;
+	int i;
+
+	if (ecc->options & NAND_ECC_MAXIMIZE) {
+		int bytes;
+
+		ecc->size = 1024;
+		nsectors = mtd->writesize / ecc->size;
+
+		/* Reserve 2 bytes for the BBM */
+		bytes = (mtd->oobsize - 2) / nsectors;
+
+		/* 4 non-ECC bytes are added before each ECC bytes section */
+		bytes -= 4;
+
+		/* and bytes has to be even. */
+		if (bytes % 2)
+			bytes--;
+
+		ecc->strength = bytes * 8 / fls(8 * ecc->size);
+
+		for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+			if (strengths[i] > ecc->strength)
+				break;
+		}
+
+		if (!i)
+			ecc->strength = 0;
+		else
+			ecc->strength = strengths[i - 1];
+	}
+
+	if (ecc->size != 512 && ecc->size != 1024)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* Prefer 1k ECC chunk over 512 ones */
+	if (ecc->size == 512 && mtd->writesize > 512) {
+		ecc->size = 1024;
+		ecc->strength *= 2;
+	}
+
+	/* Add ECC info retrieval from DT */
+	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+		if (ecc->strength <= strengths[i]) {
+			/*
+			 * Update ecc->strength value with the actual strength
+			 * that will be used by the ECC engine.
+			 */
+			ecc->strength = strengths[i];
+			break;
+		}
+	}
+
+	if (i >= ARRAY_SIZE(strengths)) {
+		dev_err(nfc->dev, "unsupported strength\n");
+		ret = -ENOTSUPP;
+		goto err;
+	}
+
+	data->mode = i;
+
+	/* HW ECC always request ECC bytes for 1024 bytes blocks */
+	ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
+
+	/* HW ECC always work with even numbers of ECC bytes */
+	ecc->bytes = ALIGN(ecc->bytes, 2);
+
+	nsectors = mtd->writesize / ecc->size;
+
+	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
+	ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
+	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
+	ecc->priv = data;
+
+	return 0;
+
+err:
+	kfree(data);
+
+	return ret;
+}
+
+static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
+{
+	kfree(ecc->priv);
+}
+
+static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
+				       struct nand_ecc_ctrl *ecc,
+				       struct device_node *np)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+	int ret;
+
+	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
+	if (ret)
+		return ret;
+
+	if (nfc->dmac) {
+		ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
+		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
+		ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
+		nand->options |= NAND_USE_BOUNCE_BUFFER;
+	} else {
+		ecc->read_page = sunxi_nfc_hw_ecc_read_page;
+		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
+		ecc->write_page = sunxi_nfc_hw_ecc_write_page;
+	}
+
+	/* TODO: support DMA for raw accesses and subpage write */
+	ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
+	ecc->read_oob_raw = nand_read_oob_std;
+	ecc->write_oob_raw = nand_write_oob_std;
+
+	return 0;
+}
+
+static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
+						struct nand_ecc_ctrl *ecc,
+						struct device_node *np)
+{
+	int ret;
+
+	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
+	if (ret)
+		return ret;
+
+	ecc->prepad = 4;
+	ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
+	ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;
+	ecc->read_oob_raw = nand_read_oob_syndrome;
+	ecc->write_oob_raw = nand_write_oob_syndrome;
+
+	return 0;
+}
+
+static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
+{
+	switch (ecc->mode) {
+	case NAND_ECC_HW:
+	case NAND_ECC_HW_SYNDROME:
+		sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
+		break;
+	case NAND_ECC_NONE:
+	default:
+		break;
+	}
+}
+
+static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
+			       struct device_node *np)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	int ret;
+
+	if (!ecc->size) {
+		ecc->size = nand->ecc_step_ds;
+		ecc->strength = nand->ecc_strength_ds;
+	}
+
+	if (!ecc->size || !ecc->strength)
+		return -EINVAL;
+
+	switch (ecc->mode) {
+	case NAND_ECC_HW:
+		ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
+		if (ret)
+			return ret;
+		break;
+	case NAND_ECC_HW_SYNDROME:
+		ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np);
+		if (ret)
+			return ret;
+		break;
+	case NAND_ECC_NONE:
+	case NAND_ECC_SOFT:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
+				struct device_node *np)
+{
+	struct sunxi_nand_chip *chip;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	int nsels;
+	int ret;
+	int i;
+	u32 tmp;
+
+	if (!of_get_property(np, "reg", &nsels))
+		return -EINVAL;
+
+	nsels /= sizeof(u32);
+	if (!nsels) {
+		dev_err(dev, "invalid reg property size\n");
+		return -EINVAL;
+	}
+
+	chip = devm_kzalloc(dev,
+			    sizeof(*chip) +
+			    (nsels * sizeof(struct sunxi_nand_chip_sel)),
+			    GFP_KERNEL);
+	if (!chip) {
+		dev_err(dev, "could not allocate chip\n");
+		return -ENOMEM;
+	}
+
+	chip->nsels = nsels;
+	chip->selected = -1;
+
+	for (i = 0; i < nsels; i++) {
+		ret = of_property_read_u32_index(np, "reg", i, &tmp);
+		if (ret) {
+			dev_err(dev, "could not retrieve reg property: %d\n",
+				ret);
+			return ret;
+		}
+
+		if (tmp > NFC_MAX_CS) {
+			dev_err(dev,
+				"invalid reg value: %u (max CS = 7)\n",
+				tmp);
+			return -EINVAL;
+		}
+
+		if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+			dev_err(dev, "CS %d already assigned\n", tmp);
+			return -EINVAL;
+		}
+
+		chip->sels[i].cs = tmp;
+
+		if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
+		    tmp < 2) {
+			chip->sels[i].rb.type = RB_NATIVE;
+			chip->sels[i].rb.info.nativeid = tmp;
+		} else {
+			ret = of_get_named_gpio(np, "rb-gpios", i);
+			if (ret >= 0) {
+				tmp = ret;
+				chip->sels[i].rb.type = RB_GPIO;
+				chip->sels[i].rb.info.gpio = tmp;
+				ret = devm_gpio_request(dev, tmp, "nand-rb");
+				if (ret)
+					return ret;
+
+				ret = gpio_direction_input(tmp);
+				if (ret)
+					return ret;
+			} else {
+				chip->sels[i].rb.type = RB_NONE;
+			}
+		}
+	}
+
+	nand = &chip->nand;
+	/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
+	nand->chip_delay = 200;
+	nand->controller = &nfc->controller;
+	/*
+	 * Set the ECC mode to the default value in case nothing is specified
+	 * in the DT.
+	 */
+	nand->ecc.mode = NAND_ECC_HW;
+	nand_set_flash_node(nand, np);
+	nand->select_chip = sunxi_nfc_select_chip;
+	nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
+	nand->read_buf = sunxi_nfc_read_buf;
+	nand->write_buf = sunxi_nfc_write_buf;
+	nand->read_byte = sunxi_nfc_read_byte;
+	nand->setup_data_interface = sunxi_nfc_setup_data_interface;
+
+	mtd = nand_to_mtd(nand);
+	mtd->dev.parent = dev;
+
+	ret = nand_scan_ident(mtd, nsels, NULL);
+	if (ret)
+		return ret;
+
+	if (nand->bbt_options & NAND_BBT_USE_FLASH)
+		nand->bbt_options |= NAND_BBT_NO_OOB;
+
+	if (nand->options & NAND_NEED_SCRAMBLING)
+		nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+	nand->options |= NAND_SUBPAGE_READ;
+
+	ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
+	if (ret) {
+		dev_err(dev, "ECC init failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(dev, "failed to register mtd device: %d\n", ret);
+		nand_release(mtd);
+		return ret;
+	}
+
+	list_add_tail(&chip->node, &nfc->chips);
+
+	return 0;
+}
+
+static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *nand_np;
+	int nchips = of_get_child_count(np);
+	int ret;
+
+	if (nchips > 8) {
+		dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(np, nand_np) {
+		ret = sunxi_nand_chip_init(dev, nfc, nand_np);
+		if (ret) {
+			of_node_put(nand_np);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
+{
+	struct sunxi_nand_chip *chip;
+
+	while (!list_empty(&nfc->chips)) {
+		chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
+					node);
+		nand_release(nand_to_mtd(&chip->nand));
+		sunxi_nand_ecc_cleanup(&chip->nand.ecc);
+		list_del(&chip->node);
+	}
+}
+
+static int sunxi_nfc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *r;
+	struct sunxi_nfc *nfc;
+	int irq;
+	int ret;
+
+	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	nfc->dev = dev;
+	nand_hw_control_init(&nfc->controller);
+	INIT_LIST_HEAD(&nfc->chips);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->regs = devm_ioremap_resource(dev, r);
+	if (IS_ERR(nfc->regs))
+		return PTR_ERR(nfc->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "failed to retrieve irq\n");
+		return irq;
+	}
+
+	nfc->ahb_clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(nfc->ahb_clk)) {
+		dev_err(dev, "failed to retrieve ahb clk\n");
+		return PTR_ERR(nfc->ahb_clk);
+	}
+
+	ret = clk_prepare_enable(nfc->ahb_clk);
+	if (ret)
+		return ret;
+
+	nfc->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(nfc->mod_clk)) {
+		dev_err(dev, "failed to retrieve mod clk\n");
+		ret = PTR_ERR(nfc->mod_clk);
+		goto out_ahb_clk_unprepare;
+	}
+
+	ret = clk_prepare_enable(nfc->mod_clk);
+	if (ret)
+		goto out_ahb_clk_unprepare;
+
+	nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
+	if (IS_ERR(nfc->reset)) {
+		ret = PTR_ERR(nfc->reset);
+		goto out_mod_clk_unprepare;
+	}
+
+	ret = reset_control_deassert(nfc->reset);
+	if (ret) {
+		dev_err(dev, "reset err %d\n", ret);
+		goto out_mod_clk_unprepare;
+	}
+
+	ret = sunxi_nfc_rst(nfc);
+	if (ret)
+		goto out_ahb_reset_reassert;
+
+	writel(0, nfc->regs + NFC_REG_INT);
+	ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
+			       0, "sunxi-nand", nfc);
+	if (ret)
+		goto out_ahb_reset_reassert;
+
+	nfc->dmac = dma_request_slave_channel(dev, "rxtx");
+	if (nfc->dmac) {
+		struct dma_slave_config dmac_cfg = { };
+
+		dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
+		dmac_cfg.dst_addr = dmac_cfg.src_addr;
+		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
+		dmac_cfg.src_maxburst = 4;
+		dmac_cfg.dst_maxburst = 4;
+		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
+	} else {
+		dev_warn(dev, "failed to request rxtx DMA channel\n");
+	}
+
+	platform_set_drvdata(pdev, nfc);
+
+	ret = sunxi_nand_chips_init(dev, nfc);
+	if (ret) {
+		dev_err(dev, "failed to init nand chips\n");
+		goto out_release_dmac;
+	}
+
+	return 0;
+
+out_release_dmac:
+	if (nfc->dmac)
+		dma_release_channel(nfc->dmac);
+out_ahb_reset_reassert:
+	reset_control_assert(nfc->reset);
+out_mod_clk_unprepare:
+	clk_disable_unprepare(nfc->mod_clk);
+out_ahb_clk_unprepare:
+	clk_disable_unprepare(nfc->ahb_clk);
+
+	return ret;
+}
+
+static int sunxi_nfc_remove(struct platform_device *pdev)
+{
+	struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
+
+	sunxi_nand_chips_cleanup(nfc);
+
+	reset_control_assert(nfc->reset);
+
+	if (nfc->dmac)
+		dma_release_channel(nfc->dmac);
+	clk_disable_unprepare(nfc->mod_clk);
+	clk_disable_unprepare(nfc->ahb_clk);
+
+	return 0;
+}
+
+static const struct of_device_id sunxi_nfc_ids[] = {
+	{ .compatible = "allwinner,sun4i-a10-nand" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
+
+static struct platform_driver sunxi_nfc_driver = {
+	.driver = {
+		.name = "sunxi_nand",
+		.of_match_table = sunxi_nfc_ids,
+	},
+	.probe = sunxi_nfc_probe,
+	.remove = sunxi_nfc_remove,
+};
+module_platform_driver(sunxi_nfc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Boris BREZILLON");
+MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
+MODULE_ALIAS("platform:sunxi_nand");
diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
new file mode 100644
index 000000000000..c5bee00b7f5e
--- /dev/null
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2016 Sigma Designs
+ *
+ * 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/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD	0
+#define PBUS_ADDR	4
+#define PBUS_DATA	8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS	0x00
+#define NFC_FLASH_CMD	0x04
+#define NFC_DEVICE_CFG	0x08
+#define NFC_TIMING1	0x0c
+#define NFC_TIMING2	0x10
+#define NFC_XFER_CFG	0x14
+#define NFC_PKT_0_CFG	0x18
+#define NFC_PKT_N_CFG	0x1c
+#define NFC_BB_CFG	0x20
+#define NFC_ADDR_PAGE	0x24
+#define NFC_ADDR_OFFSET	0x28
+#define NFC_XFER_STATUS	0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY	BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ	1
+#define NFC_WRITE	2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY	BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA	0x000
+#define ERROR_REPORT	0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define ERR_COUNT_PKT_0(v)	(((v) >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v)	(((v) >> 8) & 0x3f)
+#define DECODE_FAIL_PKT_0(v)	(((v) & BIT(7)) == 0)
+#define DECODE_FAIL_PKT_N(v)	(((v) & BIT(15)) == 0)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL	0x83c
+#define PBUS_PAD_MODE	0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY	BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW	0
+#define MODE_NFC	BIT(31)
+
+#define METADATA_SIZE	4
+#define BBM_SIZE	6
+#define FIELD_ORDER	15
+
+#define MAX_CS		4
+
+struct tango_nfc {
+	struct nand_hw_control hw;
+	void __iomem *reg_base;
+	void __iomem *mem_base;
+	void __iomem *pbus_base;
+	struct tango_chip *chips[MAX_CS];
+	struct dma_chan *chan;
+	int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+	struct nand_chip nand_chip;
+	void __iomem *base;
+	u32 timing1;
+	u32 timing2;
+	u32 xfer_cfg;
+	u32 pkt_0_cfg;
+	u32 pkt_n_cfg;
+	u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size)	\
+	((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength))
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
+
+#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	if (ctrl & NAND_CLE)
+		writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+	if (ctrl & NAND_ALE)
+		writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+	return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static u8 tango_read_byte(struct mtd_info *mtd)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+	iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+
+	if (idx < 0)
+		return; /* No "chip unselect" function */
+
+	writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+	writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+	writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+	writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+	writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+	writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 *meta = chip->oob_poi + BBM_SIZE;
+	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int i, res, meta_len, bitflips = 0;
+
+	for (i = 0; i < chip->ecc.steps; ++i) {
+		meta_len = i ? 0 : METADATA_SIZE;
+		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+						  meta, meta_len,
+						  chip->ecc.strength);
+		if (res < 0)
+			mtd->ecc_stats.failed++;
+		else
+			mtd->ecc_stats.corrected += res;
+
+		bitflips = max(res, bitflips);
+		buf += pkt_size;
+		ecc += ecc_size;
+	}
+
+	return bitflips;
+}
+
+static int decode_error_report(struct nand_chip *chip)
+{
+	u32 status, res;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+	status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+	if (status & PAGE_IS_EMPTY)
+		return 0;
+
+	res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+	if (DECODE_FAIL_PKT_0(res) || DECODE_FAIL_PKT_N(res))
+		return -EBADMSG;
+
+	/* ERR_COUNT_PKT_N is max, not sum, but that's all we have */
+	mtd->ecc_stats.corrected +=
+		ERR_COUNT_PKT_0(res) + ERR_COUNT_PKT_N(res);
+
+	return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+}
+
+static void tango_dma_callback(void *arg)
+{
+	complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, enum dma_data_direction dir, int cmd,
+		  const void *buf, int len, int page)
+{
+	void __iomem *addr = nfc->reg_base + NFC_STATUS;
+	struct dma_chan *chan = nfc->chan;
+	struct dma_async_tx_descriptor *desc;
+	enum dma_transfer_direction tdir;
+	struct scatterlist sg;
+	struct completion tx_done;
+	int err = -EIO;
+	u32 res, val;
+
+	sg_init_one(&sg, buf, len);
+	if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+		return -EIO;
+
+	tdir = dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+	desc = dmaengine_prep_slave_sg(chan, &sg, 1, tdir, DMA_PREP_INTERRUPT);
+	if (!desc)
+		goto dma_unmap;
+
+	desc->callback = tango_dma_callback;
+	desc->callback_param = &tx_done;
+	init_completion(&tx_done);
+
+	writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+	writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
+	writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+
+	res = wait_for_completion_timeout(&tx_done, HZ);
+	if (res > 0)
+		err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+
+	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+	dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+	return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			   u8 *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, res, len = mtd->writesize;
+
+	if (oob_required)
+		chip->ecc.read_oob(mtd, chip, page);
+
+	err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+	if (err)
+		return err;
+
+	res = decode_error_report(chip);
+	if (res < 0) {
+		chip->ecc.read_oob_raw(mtd, chip, page);
+		res = check_erased_page(chip, buf);
+	}
+
+	return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			    const u8 *buf, int oob_required, int page)
+{
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	int err, status, len = mtd->writesize;
+
+	/* Calling tango_write_oob() would send PAGEPROG twice */
+	if (oob_required)
+		return -ENOTSUPP;
+
+	writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+	err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+	if (err)
+		return err;
+
+	status = chip->waitfunc(mtd, chip);
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	*pos += len;
+
+	if (!*buf) {
+		/* skip over "len" bytes */
+		nand_change_read_column_op(chip, *pos, NULL, 0, false);
+	} else {
+		tango_read_buf(mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	*pos += len;
+
+	if (!*buf) {
+		/* skip over "len" bytes */
+		nand_change_write_column_op(chip, *pos, NULL, 0, false);
+	} else {
+		tango_write_buf(mtd, *buf, len);
+		*buf += len;
+	}
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ *       +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ *       +-----+---+-------+-----+-------+
+ *
+ *       +-----------------+-----+-----------------+
+ * buf = |      PKT_0      | ... |      PKT_N      |
+ *       +-----------------+-----+-----------------+
+ */
+static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 *oob_orig = oob;
+	const int page_size = mtd->writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob)
+		oob += BBM_SIZE;
+
+	aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_read(chip, &buf, pkt_size, &pos);
+		aux_read(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_read(chip, &buf, rem, &pos);
+	aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_read(chip, &buf, pkt_size - rem, &pos);
+	aux_read(chip, &oob, ecc_size, &pos);
+}
+
+static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const u8 *oob_orig = oob;
+	const int page_size = mtd->writesize;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int pos = 0; /* position within physical page */
+	int rem = page_size; /* bytes remaining until BBM area */
+
+	if (oob)
+		oob += BBM_SIZE;
+
+	aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+	while (rem > pkt_size) {
+		aux_write(chip, &buf, pkt_size, &pos);
+		aux_write(chip, &oob, ecc_size, &pos);
+		rem = page_size - pos;
+	}
+
+	aux_write(chip, &buf, rem, &pos);
+	aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+	aux_write(chip, &buf, pkt_size - rem, &pos);
+	aux_write(chip, &oob, ecc_size, &pos);
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+			       u8 *buf, int oob_required, int page)
+{
+	nand_read_page_op(chip, page, 0, NULL, 0);
+	raw_read(chip, buf, chip->oob_poi);
+	return 0;
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				const u8 *buf, int oob_required, int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	raw_write(chip, buf, chip->oob_poi);
+	return nand_prog_page_end_op(chip);
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			  int page)
+{
+	nand_read_page_op(chip, page, 0, NULL, 0);
+	raw_read(chip, NULL, chip->oob_poi);
+	return 0;
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			   int page)
+{
+	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	raw_write(chip, NULL, chip->oob_poi);
+	return nand_prog_page_end_op(chip);
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (idx >= ecc->steps)
+		return -ERANGE;
+
+	res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+	res->length = ecc->bytes;
+
+	return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+	return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+	.ecc	= oob_ecc,
+	.free	= oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+	return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd, int csline,
+			     const struct nand_data_interface *conf)
+{
+	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+	struct tango_chip *tchip = to_tango_chip(chip);
+	u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+	int kHz = nfc->freq_kHz;
+
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
+
+	Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+	Textw = to_ticks(kHz, sdr->tWB_max);
+	Twc = to_ticks(kHz, sdr->tWC_min);
+	Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+	Tacc = to_ticks(kHz, sdr->tREA_max);
+	Thold = to_ticks(kHz, sdr->tREH_min);
+	Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+	Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+	tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+	tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+	return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+	u32 cs;
+	int err, res;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct tango_chip *tchip;
+	struct nand_ecc_ctrl *ecc;
+	struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+	tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+	if (!tchip)
+		return -ENOMEM;
+
+	res = of_property_count_u32_elems(np, "reg");
+	if (res < 0)
+		return res;
+
+	if (res != 1)
+		return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+	err = of_property_read_u32_index(np, "reg", 0, &cs);
+	if (err)
+		return err;
+
+	if (cs >= MAX_CS)
+		return -EINVAL;
+
+	chip = &tchip->nand_chip;
+	ecc = &chip->ecc;
+	mtd = nand_to_mtd(chip);
+
+	chip->read_byte = tango_read_byte;
+	chip->write_buf = tango_write_buf;
+	chip->read_buf = tango_read_buf;
+	chip->select_chip = tango_select_chip;
+	chip->cmd_ctrl = tango_cmd_ctrl;
+	chip->dev_ready = tango_dev_ready;
+	chip->setup_data_interface = tango_set_timings;
+	chip->options = NAND_USE_BOUNCE_BUFFER |
+			NAND_NO_SUBPAGE_WRITE |
+			NAND_WAIT_TCCS;
+	chip->controller = &nfc->hw;
+	tchip->base = nfc->pbus_base + (cs * 256);
+
+	nand_set_flash_node(chip, np);
+	mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+	mtd->dev.parent = dev;
+
+	err = nand_scan_ident(mtd, 1, NULL);
+	if (err)
+		return err;
+
+	ecc->mode = NAND_ECC_HW;
+	ecc->algo = NAND_ECC_BCH;
+	ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+	ecc->read_page_raw = tango_read_page_raw;
+	ecc->write_page_raw = tango_write_page_raw;
+	ecc->read_page = tango_read_page;
+	ecc->write_page = tango_write_page;
+	ecc->read_oob = tango_read_oob;
+	ecc->write_oob = tango_write_oob;
+
+	err = nand_scan_tail(mtd);
+	if (err)
+		return err;
+
+	tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+	tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+	tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+	tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		return err;
+
+	nfc->chips[cs] = tchip;
+
+	return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+	int cs;
+	struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+	dma_release_channel(nfc->chan);
+
+	for (cs = 0; cs < MAX_CS; ++cs) {
+		if (nfc->chips[cs])
+			nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+	}
+
+	return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+	int err;
+	struct clk *clk;
+	struct resource *res;
+	struct tango_nfc *nfc;
+	struct device_node *np;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->reg_base))
+		return PTR_ERR(nfc->reg_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->mem_base))
+		return PTR_ERR(nfc->mem_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->pbus_base))
+		return PTR_ERR(nfc->pbus_base);
+
+	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	nfc->chan = dma_request_chan(&pdev->dev, "rxtx");
+	if (IS_ERR(nfc->chan))
+		return PTR_ERR(nfc->chan);
+
+	platform_set_drvdata(pdev, nfc);
+	nand_hw_control_init(&nfc->hw);
+	nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+	for_each_child_of_node(pdev->dev.of_node, np) {
+		err = chip_init(&pdev->dev, np);
+		if (err) {
+			tango_nand_remove(pdev);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+	{ .compatible = "sigma,smp8758-nand" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tango_nand_ids);
+
+static struct platform_driver tango_nand_driver = {
+	.probe	= tango_nand_probe,
+	.remove	= tango_nand_remove,
+	.driver	= {
+		.name		= "tango-nand",
+		.of_match_table	= tango_nand_ids,
+	},
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
new file mode 100644
index 000000000000..dcaa924502de
--- /dev/null
+++ b/drivers/mtd/nand/raw/tmio_nand.c
@@ -0,0 +1,513 @@
+/*
+ * Toshiba TMIO NAND flash controller driver
+ *
+ * Slightly murky pre-git history of the driver:
+ *
+ * Copyright (c) Ian Molton 2004, 2005, 2008
+ *    Original work, independent of sharps code. Included hardware ECC support.
+ *    Hard ECC did not work for writes in the early revisions.
+ * Copyright (c) Dirk Opfer 2005.
+ *    Modifications developed from sharps code but
+ *    NOT containing any, ported onto Ians base.
+ * Copyright (c) Chris Humbert 2005
+ * Copyright (c) Dmitry Baryshkov 2008
+ *    Minor fixes
+ *
+ * Parts copyright Sebastian Carlier
+ *
+ * This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tmio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/slab.h>
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * NAND Flash Host Controller Configuration Register
+ */
+#define CCR_COMMAND	0x04	/* w Command				*/
+#define CCR_BASE	0x10	/* l NAND Flash Control Reg Base Addr	*/
+#define CCR_INTP	0x3d	/* b Interrupt Pin			*/
+#define CCR_INTE	0x48	/* b Interrupt Enable			*/
+#define CCR_EC		0x4a	/* b Event Control			*/
+#define CCR_ICC		0x4c	/* b Internal Clock Control		*/
+#define CCR_ECCC	0x5b	/* b ECC Control			*/
+#define CCR_NFTC	0x60	/* b NAND Flash Transaction Control	*/
+#define CCR_NFM		0x61	/* b NAND Flash Monitor			*/
+#define CCR_NFPSC	0x62	/* b NAND Flash Power Supply Control	*/
+#define CCR_NFDC	0x63	/* b NAND Flash Detect Control		*/
+
+/*
+ * NAND Flash Control Register
+ */
+#define FCR_DATA	0x00	/* bwl Data Register			*/
+#define FCR_MODE	0x04	/* b Mode Register			*/
+#define FCR_STATUS	0x05	/* b Status Register			*/
+#define FCR_ISR		0x06	/* b Interrupt Status Register		*/
+#define FCR_IMR		0x07	/* b Interrupt Mask Register		*/
+
+/* FCR_MODE Register Command List */
+#define FCR_MODE_DATA	0x94	/* Data Data_Mode */
+#define FCR_MODE_COMMAND 0x95	/* Data Command_Mode */
+#define FCR_MODE_ADDRESS 0x96	/* Data Address_Mode */
+
+#define FCR_MODE_HWECC_CALC	0xB4	/* HW-ECC Data */
+#define FCR_MODE_HWECC_RESULT	0xD4	/* HW-ECC Calc result Read_Mode */
+#define FCR_MODE_HWECC_RESET	0xF4	/* HW-ECC Reset */
+
+#define FCR_MODE_POWER_ON	0x0C	/* Power Supply ON  to SSFDC card */
+#define FCR_MODE_POWER_OFF	0x08	/* Power Supply OFF to SSFDC card */
+
+#define FCR_MODE_LED_OFF	0x00	/* LED OFF */
+#define FCR_MODE_LED_ON		0x04	/* LED ON */
+
+#define FCR_MODE_EJECT_ON	0x68	/* Ejection events active  */
+#define FCR_MODE_EJECT_OFF	0x08	/* Ejection events ignored */
+
+#define FCR_MODE_LOCK		0x6C	/* Lock_Mode. Eject Switch Invalid */
+#define FCR_MODE_UNLOCK		0x0C	/* UnLock_Mode. Eject Switch is valid */
+
+#define FCR_MODE_CONTROLLER_ID	0x40	/* Controller ID Read */
+#define FCR_MODE_STANDBY	0x00	/* SSFDC card Changes Standby State */
+
+#define FCR_MODE_WE		0x80
+#define FCR_MODE_ECC1		0x40
+#define FCR_MODE_ECC0		0x20
+#define FCR_MODE_CE		0x10
+#define FCR_MODE_PCNT1		0x08
+#define FCR_MODE_PCNT0		0x04
+#define FCR_MODE_ALE		0x02
+#define FCR_MODE_CLE		0x01
+
+#define FCR_STATUS_BUSY		0x80
+
+/*--------------------------------------------------------------------------*/
+
+struct tmio_nand {
+	struct nand_chip chip;
+
+	struct platform_device *dev;
+
+	void __iomem *ccr;
+	void __iomem *fcr;
+	unsigned long fcr_base;
+
+	unsigned int irq;
+
+	/* for tmio_nand_read_byte */
+	u8			read;
+	unsigned read_good:1;
+};
+
+static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		u8 mode;
+
+		if (ctrl & NAND_NCE) {
+			mode = FCR_MODE_DATA;
+
+			if (ctrl & NAND_CLE)
+				mode |=  FCR_MODE_CLE;
+			else
+				mode &= ~FCR_MODE_CLE;
+
+			if (ctrl & NAND_ALE)
+				mode |=  FCR_MODE_ALE;
+			else
+				mode &= ~FCR_MODE_ALE;
+		} else {
+			mode = FCR_MODE_STANDBY;
+		}
+
+		tmio_iowrite8(mode, tmio->fcr + FCR_MODE);
+		tmio->read_good = 0;
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		tmio_iowrite8(cmd, chip->IO_ADDR_W);
+}
+
+static int tmio_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+
+	return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
+}
+
+static irqreturn_t tmio_irq(int irq, void *__tmio)
+{
+	struct tmio_nand *tmio = __tmio;
+	struct nand_chip *nand_chip = &tmio->chip;
+
+	/* disable RDYREQ interrupt */
+	tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
+
+	if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
+		dev_warn(&tmio->dev->dev, "spurious interrupt\n");
+
+	wake_up(&nand_chip->controller->wq);
+	return IRQ_HANDLED;
+}
+
+/*
+  *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB.
+  *This interrupt is normally disabled, but for long operations like
+  *erase and write, we enable it to wake us up.  The irq handler
+  *disables the interrupt.
+ */
+static int
+tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+	long timeout;
+	u8 status;
+
+	/* enable RDYREQ interrupt */
+	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
+	tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
+
+	timeout = wait_event_timeout(nand_chip->controller->wq,
+		tmio_nand_dev_ready(mtd),
+		msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
+
+	if (unlikely(!tmio_nand_dev_ready(mtd))) {
+		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
+		dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
+			nand_chip->state == FL_ERASING ? "erase" : "program",
+			nand_chip->state == FL_ERASING ? 400 : 20);
+
+	} else if (unlikely(!timeout)) {
+		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
+		dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
+	}
+
+	nand_status_op(nand_chip, &status);
+	return status;
+}
+
+/*
+  *The TMIO controller combines two 8-bit data bytes into one 16-bit
+  *word. This function separates them so nand_base.c works as expected,
+  *especially its NAND_CMD_READID routines.
+ *
+  *To prevent stale data from being read, tmio_nand_hwcontrol() clears
+  *tmio->read_good.
+ */
+static u_char tmio_nand_read_byte(struct mtd_info *mtd)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+	unsigned int data;
+
+	if (tmio->read_good--)
+		return tmio->read;
+
+	data = tmio_ioread16(tmio->fcr + FCR_DATA);
+	tmio->read = data >> 8;
+	return data;
+}
+
+/*
+  *The TMIO controller converts an 8-bit NAND interface to a 16-bit
+  *bus interface, so all data reads and writes must be 16-bit wide.
+  *Thus, we implement 16-bit versions of the read, write, and verify
+  *buffer functions.
+ */
+static void
+tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+
+	tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
+}
+
+static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+
+	tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
+}
+
+static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+
+	tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
+	tmio_ioread8(tmio->fcr + FCR_DATA);	/* dummy read */
+	tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
+}
+
+static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+							u_char *ecc_code)
+{
+	struct tmio_nand *tmio = mtd_to_tmio(mtd);
+	unsigned int ecc;
+
+	tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
+
+	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
+	ecc_code[1] = ecc;	/* 000-255 LP7-0 */
+	ecc_code[0] = ecc >> 8;	/* 000-255 LP15-8 */
+	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
+	ecc_code[2] = ecc;	/* 000-255 CP5-0,11b */
+	ecc_code[4] = ecc >> 8;	/* 256-511 LP7-0 */
+	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
+	ecc_code[3] = ecc;	/* 256-511 LP15-8 */
+	ecc_code[5] = ecc >> 8;	/* 256-511 CP5-0,11b */
+
+	tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE);
+	return 0;
+}
+
+static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+		unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+	int r0, r1;
+
+	/* assume ecc.size = 512 and ecc.bytes = 6 */
+	r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+	if (r0 < 0)
+		return r0;
+	r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
+	if (r1 < 0)
+		return r1;
+	return r0 + r1;
+}
+
+static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
+{
+	const struct mfd_cell *cell = mfd_get_cell(dev);
+	int ret;
+
+	if (cell->enable) {
+		ret = cell->enable(dev);
+		if (ret)
+			return ret;
+	}
+
+	/* (4Ch) CLKRUN Enable    1st spcrunc */
+	tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
+
+	/* (10h)BaseAddress    0x1000 spba.spba2 */
+	tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
+	tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
+
+	/* (04h)Command Register I/O spcmd */
+	tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
+
+	/* (62h) Power Supply Control ssmpwc */
+	/* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */
+	tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC);
+
+	/* (63h) Detect Control ssmdtc */
+	tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC);
+
+	/* Interrupt status register clear sintst */
+	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
+
+	/* After power supply, Media are reset smode */
+	tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE);
+	tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE);
+	tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA);
+
+	/* Standby Mode smode */
+	tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE);
+
+	mdelay(5);
+
+	return 0;
+}
+
+static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
+{
+	const struct mfd_cell *cell = mfd_get_cell(dev);
+
+	tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
+	if (cell->disable)
+		cell->disable(dev);
+}
+
+static int tmio_probe(struct platform_device *dev)
+{
+	struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
+	struct resource *fcr = platform_get_resource(dev,
+			IORESOURCE_MEM, 0);
+	struct resource *ccr = platform_get_resource(dev,
+			IORESOURCE_MEM, 1);
+	int irq = platform_get_irq(dev, 0);
+	struct tmio_nand *tmio;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_chip;
+	int retval;
+
+	if (data == NULL)
+		dev_warn(&dev->dev, "NULL platform data!\n");
+
+	tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
+	if (!tmio)
+		return -ENOMEM;
+
+	tmio->dev = dev;
+
+	platform_set_drvdata(dev, tmio);
+	nand_chip = &tmio->chip;
+	mtd = nand_to_mtd(nand_chip);
+	mtd->name = "tmio-nand";
+	mtd->dev.parent = &dev->dev;
+
+	tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
+	if (!tmio->ccr)
+		return -EIO;
+
+	tmio->fcr_base = fcr->start & 0xfffff;
+	tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
+	if (!tmio->fcr)
+		return -EIO;
+
+	retval = tmio_hw_init(dev, tmio);
+	if (retval)
+		return retval;
+
+	/* Set address of NAND IO lines */
+	nand_chip->IO_ADDR_R = tmio->fcr;
+	nand_chip->IO_ADDR_W = tmio->fcr;
+
+	/* Set address of hardware control function */
+	nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
+	nand_chip->dev_ready = tmio_nand_dev_ready;
+	nand_chip->read_byte = tmio_nand_read_byte;
+	nand_chip->write_buf = tmio_nand_write_buf;
+	nand_chip->read_buf = tmio_nand_read_buf;
+
+	/* set eccmode using hardware ECC */
+	nand_chip->ecc.mode = NAND_ECC_HW;
+	nand_chip->ecc.size = 512;
+	nand_chip->ecc.bytes = 6;
+	nand_chip->ecc.strength = 2;
+	nand_chip->ecc.hwctl = tmio_nand_enable_hwecc;
+	nand_chip->ecc.calculate = tmio_nand_calculate_ecc;
+	nand_chip->ecc.correct = tmio_nand_correct_data;
+
+	if (data)
+		nand_chip->badblock_pattern = data->badblock_pattern;
+
+	/* 15 us command delay time */
+	nand_chip->chip_delay = 15;
+
+	retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
+				  dev_name(&dev->dev), tmio);
+	if (retval) {
+		dev_err(&dev->dev, "request_irq error %d\n", retval);
+		goto err_irq;
+	}
+
+	tmio->irq = irq;
+	nand_chip->waitfunc = tmio_nand_wait;
+
+	/* Scan to find existence of the device */
+	retval = nand_scan(mtd, 1);
+	if (retval)
+		goto err_irq;
+
+	/* Register the partitions */
+	retval = mtd_device_parse_register(mtd,
+					   data ? data->part_parsers : NULL,
+					   NULL,
+					   data ? data->partition : NULL,
+					   data ? data->num_partitions : 0);
+	if (!retval)
+		return retval;
+
+	nand_release(mtd);
+
+err_irq:
+	tmio_hw_stop(dev, tmio);
+	return retval;
+}
+
+static int tmio_remove(struct platform_device *dev)
+{
+	struct tmio_nand *tmio = platform_get_drvdata(dev);
+
+	nand_release(nand_to_mtd(&tmio->chip));
+	tmio_hw_stop(dev, tmio);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tmio_suspend(struct platform_device *dev, pm_message_t state)
+{
+	const struct mfd_cell *cell = mfd_get_cell(dev);
+
+	if (cell->suspend)
+		cell->suspend(dev);
+
+	tmio_hw_stop(dev, platform_get_drvdata(dev));
+	return 0;
+}
+
+static int tmio_resume(struct platform_device *dev)
+{
+	const struct mfd_cell *cell = mfd_get_cell(dev);
+
+	/* FIXME - is this required or merely another attack of the broken
+	 * SHARP platform? Looks suspicious.
+	 */
+	tmio_hw_init(dev, platform_get_drvdata(dev));
+
+	if (cell->resume)
+		cell->resume(dev);
+
+	return 0;
+}
+#else
+#define tmio_suspend NULL
+#define tmio_resume NULL
+#endif
+
+static struct platform_driver tmio_driver = {
+	.driver.name	= "tmio-nand",
+	.driver.owner	= THIS_MODULE,
+	.probe		= tmio_probe,
+	.remove		= tmio_remove,
+	.suspend	= tmio_suspend,
+	.resume		= tmio_resume,
+};
+
+module_platform_driver(tmio_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov");
+MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller");
+MODULE_ALIAS("platform:tmio-nand");
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
new file mode 100644
index 000000000000..b567d212fe7d
--- /dev/null
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -0,0 +1,423 @@
+/*
+ * TXx9 NAND flash memory controller driver
+ * Based on RBTX49xx patch from CELF patch archive.
+ *
+ * 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.
+ *
+ * (C) Copyright TOSHIBA CORPORATION 2004-2007
+ * All Rights Reserved.
+ */
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+#include <asm/txx9/ndfmc.h>
+
+/* TXX9 NDFMC Registers */
+#define TXX9_NDFDTR	0x00
+#define TXX9_NDFMCR	0x04
+#define TXX9_NDFSR	0x08
+#define TXX9_NDFISR	0x0c
+#define TXX9_NDFIMR	0x10
+#define TXX9_NDFSPR	0x14
+#define TXX9_NDFRSTR	0x18	/* not TX4939 */
+
+/* NDFMCR : NDFMC Mode Control */
+#define TXX9_NDFMCR_WE	0x80
+#define TXX9_NDFMCR_ECC_ALL	0x60
+#define TXX9_NDFMCR_ECC_RESET	0x60
+#define TXX9_NDFMCR_ECC_READ	0x40
+#define TXX9_NDFMCR_ECC_ON	0x20
+#define TXX9_NDFMCR_ECC_OFF	0x00
+#define TXX9_NDFMCR_CE	0x10
+#define TXX9_NDFMCR_BSPRT	0x04	/* TX4925/TX4926 only */
+#define TXX9_NDFMCR_ALE	0x02
+#define TXX9_NDFMCR_CLE	0x01
+/* TX4939 only */
+#define TXX9_NDFMCR_X16	0x0400
+#define TXX9_NDFMCR_DMAREQ_MASK	0x0300
+#define TXX9_NDFMCR_DMAREQ_NODMA	0x0000
+#define TXX9_NDFMCR_DMAREQ_128	0x0100
+#define TXX9_NDFMCR_DMAREQ_256	0x0200
+#define TXX9_NDFMCR_DMAREQ_512	0x0300
+#define TXX9_NDFMCR_CS_MASK	0x0c
+#define TXX9_NDFMCR_CS(ch)	((ch) << 2)
+
+/* NDFMCR : NDFMC Status */
+#define TXX9_NDFSR_BUSY	0x80
+/* TX4939 only */
+#define TXX9_NDFSR_DMARUN	0x40
+
+/* NDFMCR : NDFMC Reset */
+#define TXX9_NDFRSTR_RST	0x01
+
+struct txx9ndfmc_priv {
+	struct platform_device *dev;
+	struct nand_chip chip;
+	int cs;
+	const char *mtdname;
+};
+
+#define MAX_TXX9NDFMC_DEV	4
+struct txx9ndfmc_drvdata {
+	struct mtd_info *mtds[MAX_TXX9NDFMC_DEV];
+	void __iomem *base;
+	unsigned char hold;	/* in gbusclock */
+	unsigned char spw;	/* in gbusclock */
+	struct nand_hw_control hw_control;
+};
+
+static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
+	return txx9_priv->dev;
+}
+
+static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
+{
+	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+
+	return drvdata->base + (reg << plat->shift);
+}
+
+static u32 txx9ndfmc_read(struct platform_device *dev, unsigned int reg)
+{
+	return __raw_readl(ndregaddr(dev, reg));
+}
+
+static void txx9ndfmc_write(struct platform_device *dev,
+			    u32 val, unsigned int reg)
+{
+	__raw_writel(val, ndregaddr(dev, reg));
+}
+
+static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
+{
+	struct platform_device *dev = mtd_to_platdev(mtd);
+
+	return txx9ndfmc_read(dev, TXX9_NDFDTR);
+}
+
+static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				int len)
+{
+	struct platform_device *dev = mtd_to_platdev(mtd);
+	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
+	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_WE, TXX9_NDFMCR);
+	while (len--)
+		__raw_writel(*buf++, ndfdtr);
+	txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
+}
+
+static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct platform_device *dev = mtd_to_platdev(mtd);
+	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
+
+	while (len--)
+		*buf++ = __raw_readl(ndfdtr);
+}
+
+static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
+			       unsigned int ctrl)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
+	struct platform_device *dev = txx9_priv->dev;
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+
+		mcr &= ~(TXX9_NDFMCR_CLE | TXX9_NDFMCR_ALE | TXX9_NDFMCR_CE);
+		mcr |= ctrl & NAND_CLE ? TXX9_NDFMCR_CLE : 0;
+		mcr |= ctrl & NAND_ALE ? TXX9_NDFMCR_ALE : 0;
+		/* TXX9_NDFMCR_CE bit is 0:high 1:low */
+		mcr |= ctrl & NAND_NCE ? TXX9_NDFMCR_CE : 0;
+		if (txx9_priv->cs >= 0 && (ctrl & NAND_NCE)) {
+			mcr &= ~TXX9_NDFMCR_CS_MASK;
+			mcr |= TXX9_NDFMCR_CS(txx9_priv->cs);
+		}
+		txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
+	}
+	if (cmd != NAND_CMD_NONE)
+		txx9ndfmc_write(dev, cmd & 0xff, TXX9_NDFDTR);
+	if (plat->flags & NDFMC_PLAT_FLAG_DUMMYWRITE) {
+		/* dummy write to update external latch */
+		if ((ctrl & NAND_CTRL_CHANGE) && cmd == NAND_CMD_NONE)
+			txx9ndfmc_write(dev, 0, TXX9_NDFDTR);
+	}
+	mmiowb();
+}
+
+static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
+{
+	struct platform_device *dev = mtd_to_platdev(mtd);
+
+	return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
+}
+
+static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+				   uint8_t *ecc_code)
+{
+	struct platform_device *dev = mtd_to_platdev(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int eccbytes;
+	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+
+	mcr &= ~TXX9_NDFMCR_ECC_ALL;
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR);
+	for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) {
+		ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR);
+		ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR);
+		ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR);
+		ecc_code += 3;
+	}
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
+	return 0;
+}
+
+static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
+		unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int eccsize;
+	int corrected = 0;
+	int stat;
+
+	for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
+		stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+		if (stat < 0)
+			return stat;
+		corrected += stat;
+		buf += 256;
+		read_ecc += 3;
+		calc_ecc += 3;
+	}
+	return corrected;
+}
+
+static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	struct platform_device *dev = mtd_to_platdev(mtd);
+	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
+
+	mcr &= ~TXX9_NDFMCR_ECC_ALL;
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_RESET, TXX9_NDFMCR);
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
+	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_ON, TXX9_NDFMCR);
+}
+
+static void txx9ndfmc_initialize(struct platform_device *dev)
+{
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
+	int tmout = 100;
+
+	if (plat->flags & NDFMC_PLAT_FLAG_NO_RSTR)
+		; /* no NDFRSTR.  Write to NDFSPR resets the NDFMC. */
+	else {
+		/* reset NDFMC */
+		txx9ndfmc_write(dev,
+				txx9ndfmc_read(dev, TXX9_NDFRSTR) |
+				TXX9_NDFRSTR_RST,
+				TXX9_NDFRSTR);
+		while (txx9ndfmc_read(dev, TXX9_NDFRSTR) & TXX9_NDFRSTR_RST) {
+			if (--tmout == 0) {
+				dev_err(&dev->dev, "reset failed.\n");
+				break;
+			}
+			udelay(1);
+		}
+	}
+	/* setup Hold Time, Strobe Pulse Width */
+	txx9ndfmc_write(dev, (drvdata->hold << 4) | drvdata->spw, TXX9_NDFSPR);
+	txx9ndfmc_write(dev,
+			(plat->flags & NDFMC_PLAT_FLAG_USE_BSPRT) ?
+			TXX9_NDFMCR_BSPRT : 0, TXX9_NDFMCR);
+}
+
+#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
+	DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
+
+static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int ret;
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (!ret) {
+		if (mtd->writesize >= 512) {
+			/* Hardware ECC 6 byte ECC per 512 Byte data */
+			chip->ecc.size = 512;
+			chip->ecc.bytes = 6;
+		}
+		ret = nand_scan_tail(mtd);
+	}
+	return ret;
+}
+
+static int __init txx9ndfmc_probe(struct platform_device *dev)
+{
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
+	int hold, spw;
+	int i;
+	struct txx9ndfmc_drvdata *drvdata;
+	unsigned long gbusclk = plat->gbus_clock;
+	struct resource *res;
+
+	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	drvdata->base = devm_ioremap_resource(&dev->dev, res);
+	if (IS_ERR(drvdata->base))
+		return PTR_ERR(drvdata->base);
+
+	hold = plat->hold ?: 20; /* tDH */
+	spw = plat->spw ?: 90; /* max(tREADID, tWP, tRP) */
+
+	hold = TXX9NDFMC_NS_TO_CYC(gbusclk, hold);
+	spw = TXX9NDFMC_NS_TO_CYC(gbusclk, spw);
+	if (plat->flags & NDFMC_PLAT_FLAG_HOLDADD)
+		hold -= 2;	/* actual hold time : (HOLD + 2) BUSCLK */
+	spw -= 1;	/* actual wait time : (SPW + 1) BUSCLK */
+	hold = clamp(hold, 1, 15);
+	drvdata->hold = hold;
+	spw = clamp(spw, 1, 15);
+	drvdata->spw = spw;
+	dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
+		 (gbusclk + 500000) / 1000000, hold, spw);
+
+	nand_hw_control_init(&drvdata->hw_control);
+
+	platform_set_drvdata(dev, drvdata);
+	txx9ndfmc_initialize(dev);
+
+	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
+		struct txx9ndfmc_priv *txx9_priv;
+		struct nand_chip *chip;
+		struct mtd_info *mtd;
+
+		if (!(plat->ch_mask & (1 << i)))
+			continue;
+		txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
+				    GFP_KERNEL);
+		if (!txx9_priv)
+			continue;
+		chip = &txx9_priv->chip;
+		mtd = nand_to_mtd(chip);
+		mtd->dev.parent = &dev->dev;
+
+		chip->read_byte = txx9ndfmc_read_byte;
+		chip->read_buf = txx9ndfmc_read_buf;
+		chip->write_buf = txx9ndfmc_write_buf;
+		chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
+		chip->dev_ready = txx9ndfmc_dev_ready;
+		chip->ecc.calculate = txx9ndfmc_calculate_ecc;
+		chip->ecc.correct = txx9ndfmc_correct_data;
+		chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
+		chip->ecc.mode = NAND_ECC_HW;
+		/* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
+		chip->ecc.size = 256;
+		chip->ecc.bytes = 3;
+		chip->ecc.strength = 1;
+		chip->chip_delay = 100;
+		chip->controller = &drvdata->hw_control;
+
+		nand_set_controller_data(chip, txx9_priv);
+		txx9_priv->dev = dev;
+
+		if (plat->ch_mask != 1) {
+			txx9_priv->cs = i;
+			txx9_priv->mtdname = kasprintf(GFP_KERNEL, "%s.%u",
+						       dev_name(&dev->dev), i);
+		} else {
+			txx9_priv->cs = -1;
+			txx9_priv->mtdname = kstrdup(dev_name(&dev->dev),
+						     GFP_KERNEL);
+		}
+		if (!txx9_priv->mtdname) {
+			kfree(txx9_priv);
+			dev_err(&dev->dev, "Unable to allocate MTD name.\n");
+			continue;
+		}
+		if (plat->wide_mask & (1 << i))
+			chip->options |= NAND_BUSWIDTH_16;
+
+		if (txx9ndfmc_nand_scan(mtd)) {
+			kfree(txx9_priv->mtdname);
+			kfree(txx9_priv);
+			continue;
+		}
+		mtd->name = txx9_priv->mtdname;
+
+		mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+		drvdata->mtds[i] = mtd;
+	}
+
+	return 0;
+}
+
+static int __exit txx9ndfmc_remove(struct platform_device *dev)
+{
+	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
+	int i;
+
+	if (!drvdata)
+		return 0;
+	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
+		struct mtd_info *mtd = drvdata->mtds[i];
+		struct nand_chip *chip;
+		struct txx9ndfmc_priv *txx9_priv;
+
+		if (!mtd)
+			continue;
+		chip = mtd_to_nand(mtd);
+		txx9_priv = nand_get_controller_data(chip);
+
+		nand_release(mtd);
+		kfree(txx9_priv->mtdname);
+		kfree(txx9_priv);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int txx9ndfmc_resume(struct platform_device *dev)
+{
+	if (platform_get_drvdata(dev))
+		txx9ndfmc_initialize(dev);
+	return 0;
+}
+#else
+#define txx9ndfmc_resume NULL
+#endif
+
+static struct platform_driver txx9ndfmc_driver = {
+	.remove		= __exit_p(txx9ndfmc_remove),
+	.resume		= txx9ndfmc_resume,
+	.driver		= {
+		.name	= "txx9ndfmc",
+	},
+};
+
+module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");
+MODULE_ALIAS("platform:txx9ndfmc");
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
new file mode 100644
index 000000000000..c2da36c71ae1
--- /dev/null
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -0,0 +1,833 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
+ *
+ * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
+ * Jason ported to M54418TWR and MVFA5 (VF610).
+ * Authors: Stefan Agner <stefan.agner@toradex.com>
+ *          Bill Pringlemeir <bpringlemeir@nbsps.com>
+ *          Shaohui Xie <b21989@freescale.com>
+ *          Jason Jin <Jason.jin@freescale.com>
+ *
+ * Based on original driver mpc5121_nfc.c.
+ *
+ * This 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.
+ *
+ * Limitations:
+ * - Untested on MPC5125 and M54418.
+ * - DMA and pipelining not used.
+ * - 2K pages or less.
+ * - HW ECC: Only 2K page with 64+ OOB.
+ * - HW ECC: Only 24 and 32-bit error correction implemented.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define	DRV_NAME		"vf610_nfc"
+
+/* Register Offsets */
+#define NFC_FLASH_CMD1			0x3F00
+#define NFC_FLASH_CMD2			0x3F04
+#define NFC_COL_ADDR			0x3F08
+#define NFC_ROW_ADDR			0x3F0c
+#define NFC_ROW_ADDR_INC		0x3F14
+#define NFC_FLASH_STATUS1		0x3F18
+#define NFC_FLASH_STATUS2		0x3F1c
+#define NFC_CACHE_SWAP			0x3F28
+#define NFC_SECTOR_SIZE			0x3F2c
+#define NFC_FLASH_CONFIG		0x3F30
+#define NFC_IRQ_STATUS			0x3F38
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n)		((n) *  0x1000)
+
+#define PAGE_2K				0x0800
+#define OOB_64				0x0040
+#define OOB_MAX				0x0100
+
+/*
+ * NFC_CMD2[CODE] values. See section:
+ *  - 31.4.7 Flash Command Code Description, Vybrid manual
+ *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
+ *
+ * Briefly these are bitmasks of controller cycles.
+ */
+#define READ_PAGE_CMD_CODE		0x7EE0
+#define READ_ONFI_PARAM_CMD_CODE	0x4860
+#define PROGRAM_PAGE_CMD_CODE		0x7FC0
+#define ERASE_CMD_CODE			0x4EC0
+#define READ_ID_CMD_CODE		0x4804
+#define RESET_CMD_CODE			0x4040
+#define STATUS_READ_CMD_CODE		0x4068
+
+/* NFC ECC mode define */
+#define ECC_BYPASS			0
+#define ECC_45_BYTE			6
+#define ECC_60_BYTE			7
+
+/*** Register Mask and bit definitions */
+
+/* NFC_FLASH_CMD1 Field */
+#define CMD_BYTE2_MASK				0xFF000000
+#define CMD_BYTE2_SHIFT				24
+
+/* NFC_FLASH_CM2 Field */
+#define CMD_BYTE1_MASK				0xFF000000
+#define CMD_BYTE1_SHIFT				24
+#define CMD_CODE_MASK				0x00FFFF00
+#define CMD_CODE_SHIFT				8
+#define BUFNO_MASK				0x00000006
+#define BUFNO_SHIFT				1
+#define START_BIT				BIT(0)
+
+/* NFC_COL_ADDR Field */
+#define COL_ADDR_MASK				0x0000FFFF
+#define COL_ADDR_SHIFT				0
+
+/* NFC_ROW_ADDR Field */
+#define ROW_ADDR_MASK				0x00FFFFFF
+#define ROW_ADDR_SHIFT				0
+#define ROW_ADDR_CHIP_SEL_RB_MASK		0xF0000000
+#define ROW_ADDR_CHIP_SEL_RB_SHIFT		28
+#define ROW_ADDR_CHIP_SEL_MASK			0x0F000000
+#define ROW_ADDR_CHIP_SEL_SHIFT			24
+
+/* NFC_FLASH_STATUS2 Field */
+#define STATUS_BYTE1_MASK			0x000000FF
+
+/* NFC_FLASH_CONFIG Field */
+#define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000
+#define CONFIG_ECC_SRAM_ADDR_SHIFT		22
+#define CONFIG_ECC_SRAM_REQ_BIT			BIT(21)
+#define CONFIG_DMA_REQ_BIT			BIT(20)
+#define CONFIG_ECC_MODE_MASK			0x000E0000
+#define CONFIG_ECC_MODE_SHIFT			17
+#define CONFIG_FAST_FLASH_BIT			BIT(16)
+#define CONFIG_16BIT				BIT(7)
+#define CONFIG_BOOT_MODE_BIT			BIT(6)
+#define CONFIG_ADDR_AUTO_INCR_BIT		BIT(5)
+#define CONFIG_BUFNO_AUTO_INCR_BIT		BIT(4)
+#define CONFIG_PAGE_CNT_MASK			0xF
+#define CONFIG_PAGE_CNT_SHIFT			0
+
+/* NFC_IRQ_STATUS Field */
+#define IDLE_IRQ_BIT				BIT(29)
+#define IDLE_EN_BIT				BIT(20)
+#define CMD_DONE_CLEAR_BIT			BIT(18)
+#define IDLE_CLEAR_BIT				BIT(17)
+
+/*
+ * ECC status - seems to consume 8 bytes (double word). The documented
+ * status byte is located in the lowest byte of the second word (which is
+ * the 4th or 7th byte depending on endianness).
+ * Calculate an offset to store the ECC status at the end of the buffer.
+ */
+#define ECC_SRAM_ADDR		(PAGE_2K + OOB_MAX - 8)
+
+#define ECC_STATUS		0x4
+#define ECC_STATUS_MASK		0x80
+#define ECC_STATUS_ERR_COUNT	0x3F
+
+enum vf610_nfc_alt_buf {
+	ALT_BUF_DATA = 0,
+	ALT_BUF_ID = 1,
+	ALT_BUF_STAT = 2,
+	ALT_BUF_ONFI = 3,
+};
+
+enum vf610_nfc_variant {
+	NFC_VFC610 = 1,
+};
+
+struct vf610_nfc {
+	struct nand_chip chip;
+	struct device *dev;
+	void __iomem *regs;
+	struct completion cmd_done;
+	uint buf_offset;
+	int write_sz;
+	/* Status and ID are in alternate locations. */
+	enum vf610_nfc_alt_buf alt_buf;
+	enum vf610_nfc_variant variant;
+	struct clk *clk;
+	bool use_hw_ecc;
+	u32 ecc_mode;
+};
+
+static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
+{
+	return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
+}
+
+static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
+{
+	return readl(nfc->regs + reg);
+}
+
+static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
+{
+	writel(val, nfc->regs + reg);
+}
+
+static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
+{
+	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
+}
+
+static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
+{
+	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
+}
+
+static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
+				       u32 mask, u32 shift, u32 val)
+{
+	vf610_nfc_write(nfc, reg,
+			(vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
+}
+
+static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src,
+				    size_t n)
+{
+	/*
+	 * Use this accessor for the internal SRAM buffers. On the ARM
+	 * Freescale Vybrid SoC it's known that the driver can treat
+	 * the SRAM buffer as if it's memory. Other platform might need
+	 * to treat the buffers differently.
+	 *
+	 * For the time being, use memcpy
+	 */
+	memcpy(dst, src, n);
+}
+
+/* Clear flags for upcoming command */
+static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
+{
+	u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
+
+	tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
+	vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
+}
+
+static void vf610_nfc_done(struct vf610_nfc *nfc)
+{
+	unsigned long timeout = msecs_to_jiffies(100);
+
+	/*
+	 * Barrier is needed after this write. This write need
+	 * to be done before reading the next register the first
+	 * time.
+	 * vf610_nfc_set implicates such a barrier by using writel
+	 * to write to the register.
+	 */
+	vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+	vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
+
+	if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
+		dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
+
+	vf610_nfc_clear_status(nfc);
+}
+
+static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col)
+{
+	u32 flash_id;
+
+	if (col < 4) {
+		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1);
+		flash_id >>= (3 - col) * 8;
+	} else {
+		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2);
+		flash_id >>= 24;
+	}
+
+	return flash_id & 0xff;
+}
+
+static u8 vf610_nfc_get_status(struct vf610_nfc *nfc)
+{
+	return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
+}
+
+static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1,
+				   u32 cmd_code)
+{
+	u32 tmp;
+
+	vf610_nfc_clear_status(nfc);
+
+	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2);
+	tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
+	tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
+	tmp |= cmd_code << CMD_CODE_SHIFT;
+	vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp);
+}
+
+static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1,
+				    u32 cmd_byte2, u32 cmd_code)
+{
+	u32 tmp;
+
+	vf610_nfc_send_command(nfc, cmd_byte1, cmd_code);
+
+	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1);
+	tmp &= ~CMD_BYTE2_MASK;
+	tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
+	vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp);
+}
+
+static irqreturn_t vf610_nfc_irq(int irq, void *data)
+{
+	struct mtd_info *mtd = data;
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+	vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+	complete(&nfc->cmd_done);
+
+	return IRQ_HANDLED;
+}
+
+static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
+{
+	if (column != -1) {
+		if (nfc->chip.options & NAND_BUSWIDTH_16)
+			column = column / 2;
+		vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
+				    COL_ADDR_SHIFT, column);
+	}
+	if (page != -1)
+		vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
+				    ROW_ADDR_SHIFT, page);
+}
+
+static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
+{
+	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+			    CONFIG_ECC_MODE_MASK,
+			    CONFIG_ECC_MODE_SHIFT, ecc_mode);
+}
+
+static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
+{
+	vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
+}
+
+static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
+			      int column, int page)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
+
+	nfc->buf_offset = max(column, 0);
+	nfc->alt_buf = ALT_BUF_DATA;
+
+	switch (command) {
+	case NAND_CMD_SEQIN:
+		/* Use valid column/page from preread... */
+		vf610_nfc_addr_cycle(nfc, column, page);
+		nfc->buf_offset = 0;
+
+		/*
+		 * SEQIN => data => PAGEPROG sequence is done by the controller
+		 * hence we do not need to issue the command here...
+		 */
+		return;
+	case NAND_CMD_PAGEPROG:
+		trfr_sz += nfc->write_sz;
+		vf610_nfc_transfer_size(nfc, trfr_sz);
+		vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
+					command, PROGRAM_PAGE_CMD_CODE);
+		if (nfc->use_hw_ecc)
+			vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+		else
+			vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+		break;
+
+	case NAND_CMD_RESET:
+		vf610_nfc_transfer_size(nfc, 0);
+		vf610_nfc_send_command(nfc, command, RESET_CMD_CODE);
+		break;
+
+	case NAND_CMD_READOOB:
+		trfr_sz += mtd->oobsize;
+		column = mtd->writesize;
+		vf610_nfc_transfer_size(nfc, trfr_sz);
+		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+		vf610_nfc_addr_cycle(nfc, column, page);
+		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+		break;
+
+	case NAND_CMD_READ0:
+		trfr_sz += mtd->writesize + mtd->oobsize;
+		vf610_nfc_transfer_size(nfc, trfr_sz);
+		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+		vf610_nfc_addr_cycle(nfc, column, page);
+		vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+		break;
+
+	case NAND_CMD_PARAM:
+		nfc->alt_buf = ALT_BUF_ONFI;
+		trfr_sz = 3 * sizeof(struct nand_onfi_params);
+		vf610_nfc_transfer_size(nfc, trfr_sz);
+		vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
+		vf610_nfc_addr_cycle(nfc, -1, column);
+		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+		break;
+
+	case NAND_CMD_ERASE1:
+		vf610_nfc_transfer_size(nfc, 0);
+		vf610_nfc_send_commands(nfc, command,
+					NAND_CMD_ERASE2, ERASE_CMD_CODE);
+		vf610_nfc_addr_cycle(nfc, column, page);
+		break;
+
+	case NAND_CMD_READID:
+		nfc->alt_buf = ALT_BUF_ID;
+		nfc->buf_offset = 0;
+		vf610_nfc_transfer_size(nfc, 0);
+		vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE);
+		vf610_nfc_addr_cycle(nfc, -1, column);
+		break;
+
+	case NAND_CMD_STATUS:
+		nfc->alt_buf = ALT_BUF_STAT;
+		vf610_nfc_transfer_size(nfc, 0);
+		vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE);
+		break;
+	default:
+		return;
+	}
+
+	vf610_nfc_done(nfc);
+
+	nfc->use_hw_ecc = false;
+	nfc->write_sz = 0;
+}
+
+static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	uint c = nfc->buf_offset;
+
+	/* Alternate buffers are only supported through read_byte */
+	WARN_ON(nfc->alt_buf);
+
+	vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
+
+	nfc->buf_offset += len;
+}
+
+static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				int len)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	uint c = nfc->buf_offset;
+	uint l;
+
+	l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
+	vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
+
+	nfc->write_sz += l;
+	nfc->buf_offset += l;
+}
+
+static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	u8 tmp;
+	uint c = nfc->buf_offset;
+
+	switch (nfc->alt_buf) {
+	case ALT_BUF_ID:
+		tmp = vf610_nfc_get_id(nfc, c);
+		break;
+	case ALT_BUF_STAT:
+		tmp = vf610_nfc_get_status(nfc);
+		break;
+#ifdef __LITTLE_ENDIAN
+	case ALT_BUF_ONFI:
+		/* Reverse byte since the controller uses big endianness */
+		c = nfc->buf_offset ^ 0x3;
+		/* fall-through */
+#endif
+	default:
+		tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
+		break;
+	}
+	nfc->buf_offset++;
+	return tmp;
+}
+
+static u16 vf610_nfc_read_word(struct mtd_info *mtd)
+{
+	u16 tmp;
+
+	vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+	return tmp;
+}
+
+/* If not provided, upper layers apply a fixed delay. */
+static int vf610_nfc_dev_ready(struct mtd_info *mtd)
+{
+	/* NFC handles R/B internally; always ready.  */
+	return 1;
+}
+
+/*
+ * This function supports Vybrid only (MPC5125 would have full RB and four CS)
+ */
+static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
+
+	/* Vybrid only (MPC5125 would have full RB and four CS) */
+	if (nfc->variant != NFC_VFC610)
+		return;
+
+	tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
+
+	if (chip >= 0) {
+		tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
+		tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+	}
+
+	vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
+}
+
+static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
+					 uint8_t *oob, int page)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
+	u8 ecc_status;
+	u8 ecc_count;
+	int flips_threshold = nfc->chip.ecc.strength / 2;
+
+	ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
+	ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
+
+	if (!(ecc_status & ECC_STATUS_MASK))
+		return ecc_count;
+
+	/* Read OOB without ECC unit enabled */
+	vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
+	vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
+
+	/*
+	 * On an erased page, bit count (including OOB) should be zero or
+	 * at least less then half of the ECC strength.
+	 */
+	return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob,
+					   mtd->oobsize, NULL, 0,
+					   flips_threshold);
+}
+
+static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	int eccsize = chip->ecc.size;
+	int stat;
+
+	nand_read_page_op(chip, page, 0, buf, eccsize);
+	if (oob_required)
+		vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
+
+	if (stat < 0) {
+		mtd->ecc_stats.failed++;
+		return 0;
+	} else {
+		mtd->ecc_stats.corrected += stat;
+		return stat;
+	}
+}
+
+static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+				const uint8_t *buf, int oob_required, int page)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	if (oob_required)
+		vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* Always write whole page including OOB due to HW ECC */
+	nfc->use_hw_ecc = true;
+	nfc->write_sz = mtd->writesize + mtd->oobsize;
+
+	return nand_prog_page_end_op(chip);
+}
+
+static const struct of_device_id vf610_nfc_dt_ids[] = {
+	{ .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
+
+static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
+{
+	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
+	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
+	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
+	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
+	vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
+
+	/* Disable virtual pages, only one elementary transfer unit */
+	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
+			    CONFIG_PAGE_CNT_SHIFT, 1);
+}
+
+static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
+{
+	if (nfc->chip.options & NAND_BUSWIDTH_16)
+		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+	else
+		vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+
+	if (nfc->chip.ecc.mode == NAND_ECC_HW) {
+		/* Set ECC status offset in SRAM */
+		vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+				    CONFIG_ECC_SRAM_ADDR_MASK,
+				    CONFIG_ECC_SRAM_ADDR_SHIFT,
+				    ECC_SRAM_ADDR >> 3);
+
+		/* Enable ECC status in SRAM */
+		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
+	}
+}
+
+static int vf610_nfc_probe(struct platform_device *pdev)
+{
+	struct vf610_nfc *nfc;
+	struct resource *res;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+	struct device_node *child;
+	const struct of_device_id *of_id;
+	int err;
+	int irq;
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+	if (!nfc)
+		return -ENOMEM;
+
+	nfc->dev = &pdev->dev;
+	chip = &nfc->chip;
+	mtd = nand_to_mtd(chip);
+
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = nfc->dev;
+	mtd->name = DRV_NAME;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->regs = devm_ioremap_resource(nfc->dev, res);
+	if (IS_ERR(nfc->regs))
+		return PTR_ERR(nfc->regs);
+
+	nfc->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(nfc->clk))
+		return PTR_ERR(nfc->clk);
+
+	err = clk_prepare_enable(nfc->clk);
+	if (err) {
+		dev_err(nfc->dev, "Unable to enable clock!\n");
+		return err;
+	}
+
+	of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
+	nfc->variant = (enum vf610_nfc_variant)of_id->data;
+
+	for_each_available_child_of_node(nfc->dev->of_node, child) {
+		if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
+
+			if (nand_get_flash_node(chip)) {
+				dev_err(nfc->dev,
+					"Only one NAND chip supported!\n");
+				err = -EINVAL;
+				goto err_disable_clk;
+			}
+
+			nand_set_flash_node(chip, child);
+		}
+	}
+
+	if (!nand_get_flash_node(chip)) {
+		dev_err(nfc->dev, "NAND chip sub-node missing!\n");
+		err = -ENODEV;
+		goto err_disable_clk;
+	}
+
+	chip->dev_ready = vf610_nfc_dev_ready;
+	chip->cmdfunc = vf610_nfc_command;
+	chip->read_byte = vf610_nfc_read_byte;
+	chip->read_word = vf610_nfc_read_word;
+	chip->read_buf = vf610_nfc_read_buf;
+	chip->write_buf = vf610_nfc_write_buf;
+	chip->select_chip = vf610_nfc_select_chip;
+	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
+	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
+
+	chip->options |= NAND_NO_SUBPAGE_WRITE;
+
+	init_completion(&nfc->cmd_done);
+
+	err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
+	if (err) {
+		dev_err(nfc->dev, "Error requesting IRQ!\n");
+		goto err_disable_clk;
+	}
+
+	vf610_nfc_preinit_controller(nfc);
+
+	/* first scan to find the device and get the page size */
+	err = nand_scan_ident(mtd, 1, NULL);
+	if (err)
+		goto err_disable_clk;
+
+	vf610_nfc_init_controller(nfc);
+
+	/* Bad block options. */
+	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+		chip->bbt_options |= NAND_BBT_NO_OOB;
+
+	/* Single buffer only, max 256 OOB minus ECC status */
+	if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
+		dev_err(nfc->dev, "Unsupported flash page size\n");
+		err = -ENXIO;
+		goto err_disable_clk;
+	}
+
+	if (chip->ecc.mode == NAND_ECC_HW) {
+		if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+			dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+			err = -ENXIO;
+			goto err_disable_clk;
+		}
+
+		if (chip->ecc.size != mtd->writesize) {
+			dev_err(nfc->dev, "Step size needs to be page size\n");
+			err = -ENXIO;
+			goto err_disable_clk;
+		}
+
+		/* Only 64 byte ECC layouts known */
+		if (mtd->oobsize > 64)
+			mtd->oobsize = 64;
+
+		/* Use default large page ECC layout defined in NAND core */
+		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+		if (chip->ecc.strength == 32) {
+			nfc->ecc_mode = ECC_60_BYTE;
+			chip->ecc.bytes = 60;
+		} else if (chip->ecc.strength == 24) {
+			nfc->ecc_mode = ECC_45_BYTE;
+			chip->ecc.bytes = 45;
+		} else {
+			dev_err(nfc->dev, "Unsupported ECC strength\n");
+			err = -ENXIO;
+			goto err_disable_clk;
+		}
+
+		chip->ecc.read_page = vf610_nfc_read_page;
+		chip->ecc.write_page = vf610_nfc_write_page;
+
+		chip->ecc.size = PAGE_2K;
+	}
+
+	/* second phase scan */
+	err = nand_scan_tail(mtd);
+	if (err)
+		goto err_disable_clk;
+
+	platform_set_drvdata(pdev, mtd);
+
+	/* Register device in MTD */
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		goto err_cleanup_nand;
+	return 0;
+
+err_cleanup_nand:
+	nand_cleanup(chip);
+err_disable_clk:
+	clk_disable_unprepare(nfc->clk);
+	return err;
+}
+
+static int vf610_nfc_remove(struct platform_device *pdev)
+{
+	struct mtd_info *mtd = platform_get_drvdata(pdev);
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+	nand_release(mtd);
+	clk_disable_unprepare(nfc->clk);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vf610_nfc_suspend(struct device *dev)
+{
+	struct mtd_info *mtd = dev_get_drvdata(dev);
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+	clk_disable_unprepare(nfc->clk);
+	return 0;
+}
+
+static int vf610_nfc_resume(struct device *dev)
+{
+	int err;
+
+	struct mtd_info *mtd = dev_get_drvdata(dev);
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+	err = clk_prepare_enable(nfc->clk);
+	if (err)
+		return err;
+
+	vf610_nfc_preinit_controller(nfc);
+	vf610_nfc_init_controller(nfc);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
+
+static struct platform_driver vf610_nfc_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.of_match_table = vf610_nfc_dt_ids,
+		.pm	= &vf610_nfc_pm_ops,
+	},
+	.probe		= vf610_nfc_probe,
+	.remove		= vf610_nfc_remove,
+};
+
+module_platform_driver(vf610_nfc_driver);
+
+MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
+MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
new file mode 100644
index 000000000000..9926b4e3d69d
--- /dev/null
+++ b/drivers/mtd/nand/raw/xway_nand.c
@@ -0,0 +1,245 @@
+/*
+ *  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.
+ *
+ *  Copyright © 2012 John Crispin <john@phrozen.org>
+ *  Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+#include <linux/mtd/rawnand.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+#include <lantiq_soc.h>
+
+/* nand registers */
+#define EBU_ADDSEL1		0x24
+#define EBU_NAND_CON		0xB0
+#define EBU_NAND_WAIT		0xB4
+#define  NAND_WAIT_RD		BIT(0) /* NAND flash status output */
+#define  NAND_WAIT_WR_C		BIT(3) /* NAND Write/Read complete */
+#define EBU_NAND_ECC0		0xB8
+#define EBU_NAND_ECC_AC		0xBC
+
+/*
+ * nand commands
+ * The pins of the NAND chip are selected based on the address bits of the
+ * "register" read and write. There are no special registers, but an
+ * address range and the lower address bits are used to activate the
+ * correct line. For example when the bit (1 << 2) is set in the address
+ * the ALE pin will be activated.
+ */
+#define NAND_CMD_ALE		BIT(2) /* address latch enable */
+#define NAND_CMD_CLE		BIT(3) /* command latch enable */
+#define NAND_CMD_CS		BIT(4) /* chip select */
+#define NAND_CMD_SE		BIT(5) /* spare area access latch */
+#define NAND_CMD_WP		BIT(6) /* write protect */
+#define NAND_WRITE_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
+#define NAND_WRITE_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
+#define NAND_WRITE_DATA		(NAND_CMD_CS)
+#define NAND_READ_DATA		(NAND_CMD_CS)
+
+/* we need to tel the ebu which addr we mapped the nand to */
+#define ADDSEL1_MASK(x)		(x << 4)
+#define ADDSEL1_REGEN		1
+
+/* we need to tell the EBU that we have nand attached and set it up properly */
+#define BUSCON1_SETUP		(1 << 22)
+#define BUSCON1_BCGEN_RES	(0x3 << 12)
+#define BUSCON1_WAITWRC2	(2 << 8)
+#define BUSCON1_WAITRDC2	(2 << 6)
+#define BUSCON1_HOLDC1		(1 << 4)
+#define BUSCON1_RECOVC1		(1 << 2)
+#define BUSCON1_CMULT4		1
+
+#define NAND_CON_CE		(1 << 20)
+#define NAND_CON_OUT_CS1	(1 << 10)
+#define NAND_CON_IN_CS1		(1 << 8)
+#define NAND_CON_PRE_P		(1 << 7)
+#define NAND_CON_WP_P		(1 << 6)
+#define NAND_CON_SE_P		(1 << 5)
+#define NAND_CON_CS_P		(1 << 4)
+#define NAND_CON_CSMUX		(1 << 1)
+#define NAND_CON_NANDM		1
+
+struct xway_nand_data {
+	struct nand_chip	chip;
+	unsigned long		csflags;
+	void __iomem		*nandaddr;
+};
+
+static u8 xway_readb(struct mtd_info *mtd, int op)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct xway_nand_data *data = nand_get_controller_data(chip);
+
+	return readb(data->nandaddr + op);
+}
+
+static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct xway_nand_data *data = nand_get_controller_data(chip);
+
+	writeb(value, data->nandaddr + op);
+}
+
+static void xway_select_chip(struct mtd_info *mtd, int select)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct xway_nand_data *data = nand_get_controller_data(chip);
+
+	switch (select) {
+	case -1:
+		ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
+		ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+		spin_unlock_irqrestore(&ebu_lock, data->csflags);
+		break;
+	case 0:
+		spin_lock_irqsave(&ebu_lock, data->csflags);
+		ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
+		ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
+		break;
+	default:
+		BUG();
+	}
+}
+
+static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		xway_writeb(mtd, NAND_WRITE_CMD, cmd);
+	else if (ctrl & NAND_ALE)
+		xway_writeb(mtd, NAND_WRITE_ADDR, cmd);
+
+	while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+		;
+}
+
+static int xway_dev_ready(struct mtd_info *mtd)
+{
+	return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
+}
+
+static unsigned char xway_read_byte(struct mtd_info *mtd)
+{
+	return xway_readb(mtd, NAND_READ_DATA);
+}
+
+static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
+}
+
+static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int xway_nand_probe(struct platform_device *pdev)
+{
+	struct xway_nand_data *data;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int err;
+	u32 cs;
+	u32 cs_flag = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	data = devm_kzalloc(&pdev->dev, sizeof(struct xway_nand_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	data->nandaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->nandaddr))
+		return PTR_ERR(data->nandaddr);
+
+	nand_set_flash_node(&data->chip, pdev->dev.of_node);
+	mtd = nand_to_mtd(&data->chip);
+	mtd->dev.parent = &pdev->dev;
+
+	data->chip.cmd_ctrl = xway_cmd_ctrl;
+	data->chip.dev_ready = xway_dev_ready;
+	data->chip.select_chip = xway_select_chip;
+	data->chip.write_buf = xway_write_buf;
+	data->chip.read_buf = xway_read_buf;
+	data->chip.read_byte = xway_read_byte;
+	data->chip.chip_delay = 30;
+
+	data->chip.ecc.mode = NAND_ECC_SOFT;
+	data->chip.ecc.algo = NAND_ECC_HAMMING;
+
+	platform_set_drvdata(pdev, data);
+	nand_set_controller_data(&data->chip, data);
+
+	/* load our CS from the DT. Either we find a valid 1 or default to 0 */
+	err = of_property_read_u32(pdev->dev.of_node, "lantiq,cs", &cs);
+	if (!err && cs == 1)
+		cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
+
+	/* setup the EBU to run in NAND mode on our base addr */
+	ltq_ebu_w32(CPHYSADDR(data->nandaddr)
+		    | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
+
+	ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
+		    | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
+		    | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
+
+	ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
+		    | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
+		    | cs_flag, EBU_NAND_CON);
+
+	/* Scan to find existence of the device */
+	err = nand_scan(mtd, 1);
+	if (err)
+		return err;
+
+	err = mtd_device_register(mtd, NULL, 0);
+	if (err)
+		nand_release(mtd);
+
+	return err;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int xway_nand_remove(struct platform_device *pdev)
+{
+	struct xway_nand_data *data = platform_get_drvdata(pdev);
+
+	nand_release(nand_to_mtd(&data->chip));
+
+	return 0;
+}
+
+static const struct of_device_id xway_nand_match[] = {
+	{ .compatible = "lantiq,nand-xway" },
+	{},
+};
+
+static struct platform_driver xway_nand_driver = {
+	.probe	= xway_nand_probe,
+	.remove	= xway_nand_remove,
+	.driver	= {
+		.name		= "lantiq,nand-xway",
+		.of_match_table = xway_nand_match,
+	},
+};
+
+builtin_platform_driver(xway_nand_driver);
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
deleted file mode 100644
index 4c383eeec6f6..000000000000
--- a/drivers/mtd/nand/s3c2410.c
+++ /dev/null
@@ -1,1296 +0,0 @@
-/* linux/drivers/mtd/nand/s3c2410.c
- *
- * Copyright © 2004-2008 Simtec Electronics
- *	http://armlinux.simtec.co.uk/
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2410/S3C2440/S3C2412 NAND driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#define pr_fmt(fmt) "nand-s3c2410: " fmt
-
-#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/platform_data/mtd-nand-s3c2410.h>
-
-#define S3C2410_NFREG(x) (x)
-
-#define S3C2410_NFCONF		S3C2410_NFREG(0x00)
-#define S3C2410_NFCMD		S3C2410_NFREG(0x04)
-#define S3C2410_NFADDR		S3C2410_NFREG(0x08)
-#define S3C2410_NFDATA		S3C2410_NFREG(0x0C)
-#define S3C2410_NFSTAT		S3C2410_NFREG(0x10)
-#define S3C2410_NFECC		S3C2410_NFREG(0x14)
-#define S3C2440_NFCONT		S3C2410_NFREG(0x04)
-#define S3C2440_NFCMD		S3C2410_NFREG(0x08)
-#define S3C2440_NFADDR		S3C2410_NFREG(0x0C)
-#define S3C2440_NFDATA		S3C2410_NFREG(0x10)
-#define S3C2440_NFSTAT		S3C2410_NFREG(0x20)
-#define S3C2440_NFMECC0		S3C2410_NFREG(0x2C)
-#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
-#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
-#define S3C2410_NFCONF_EN		(1<<15)
-#define S3C2410_NFCONF_INITECC		(1<<12)
-#define S3C2410_NFCONF_nFCE		(1<<11)
-#define S3C2410_NFCONF_TACLS(x)		((x)<<8)
-#define S3C2410_NFCONF_TWRPH0(x)	((x)<<4)
-#define S3C2410_NFCONF_TWRPH1(x)	((x)<<0)
-#define S3C2410_NFSTAT_BUSY		(1<<0)
-#define S3C2440_NFCONF_TACLS(x)		((x)<<12)
-#define S3C2440_NFCONF_TWRPH0(x)	((x)<<8)
-#define S3C2440_NFCONF_TWRPH1(x)	((x)<<4)
-#define S3C2440_NFCONT_INITECC		(1<<4)
-#define S3C2440_NFCONT_nFCE		(1<<1)
-#define S3C2440_NFCONT_ENABLE		(1<<0)
-#define S3C2440_NFSTAT_READY		(1<<0)
-#define S3C2412_NFCONF_NANDBOOT		(1<<31)
-#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
-#define S3C2412_NFCONT_nFCE0		(1<<1)
-#define S3C2412_NFSTAT_READY		(1<<0)
-
-/* new oob placement block for use with hardware ecc generation
- */
-static int s3c2410_ooblayout_ecc(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 0;
-	oobregion->length = 3;
-
-	return 0;
-}
-
-static int s3c2410_ooblayout_free(struct mtd_info *mtd, int section,
-				  struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 8;
-	oobregion->length = 8;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops s3c2410_ooblayout_ops = {
-	.ecc = s3c2410_ooblayout_ecc,
-	.free = s3c2410_ooblayout_free,
-};
-
-/* controller and mtd information */
-
-struct s3c2410_nand_info;
-
-/**
- * struct s3c2410_nand_mtd - driver MTD structure
- * @mtd: The MTD instance to pass to the MTD layer.
- * @chip: The NAND chip information.
- * @set: The platform information supplied for this set of NAND chips.
- * @info: Link back to the hardware information.
- * @scan_res: The result from calling nand_scan_ident().
-*/
-struct s3c2410_nand_mtd {
-	struct nand_chip		chip;
-	struct s3c2410_nand_set		*set;
-	struct s3c2410_nand_info	*info;
-	int				scan_res;
-};
-
-enum s3c_cpu_type {
-	TYPE_S3C2410,
-	TYPE_S3C2412,
-	TYPE_S3C2440,
-};
-
-enum s3c_nand_clk_state {
-	CLOCK_DISABLE	= 0,
-	CLOCK_ENABLE,
-	CLOCK_SUSPEND,
-};
-
-/* overview of the s3c2410 nand state */
-
-/**
- * struct s3c2410_nand_info - NAND controller state.
- * @mtds: An array of MTD instances on this controoler.
- * @platform: The platform data for this board.
- * @device: The platform device we bound to.
- * @clk: The clock resource for this controller.
- * @regs: The area mapped for the hardware registers.
- * @sel_reg: Pointer to the register controlling the NAND selection.
- * @sel_bit: The bit in @sel_reg to select the NAND chip.
- * @mtd_count: The number of MTDs created from this controller.
- * @save_sel: The contents of @sel_reg to be saved over suspend.
- * @clk_rate: The clock rate from @clk.
- * @clk_state: The current clock state.
- * @cpu_type: The exact type of this controller.
- */
-struct s3c2410_nand_info {
-	/* mtd info */
-	struct nand_hw_control		controller;
-	struct s3c2410_nand_mtd		*mtds;
-	struct s3c2410_platform_nand	*platform;
-
-	/* device info */
-	struct device			*device;
-	struct clk			*clk;
-	void __iomem			*regs;
-	void __iomem			*sel_reg;
-	int				sel_bit;
-	int				mtd_count;
-	unsigned long			save_sel;
-	unsigned long			clk_rate;
-	enum s3c_nand_clk_state		clk_state;
-
-	enum s3c_cpu_type		cpu_type;
-
-#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
-	struct notifier_block	freq_transition;
-#endif
-};
-
-struct s3c24XX_nand_devtype_data {
-	enum s3c_cpu_type type;
-};
-
-static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
-	.type = TYPE_S3C2410,
-};
-
-static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
-	.type = TYPE_S3C2412,
-};
-
-static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
-	.type = TYPE_S3C2440,
-};
-
-/* conversion functions */
-
-static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct s3c2410_nand_mtd,
-			    chip);
-}
-
-static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
-{
-	return s3c2410_nand_mtd_toours(mtd)->info;
-}
-
-static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
-{
-	return platform_get_drvdata(dev);
-}
-
-static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
-{
-	return dev_get_platdata(&dev->dev);
-}
-
-static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
-{
-#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
-	return 1;
-#else
-	return 0;
-#endif
-}
-
-/**
- * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
- * @info: The controller instance.
- * @new_state: State to which clock should be set.
- */
-static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
-		enum s3c_nand_clk_state new_state)
-{
-	if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
-		return;
-
-	if (info->clk_state == CLOCK_ENABLE) {
-		if (new_state != CLOCK_ENABLE)
-			clk_disable_unprepare(info->clk);
-	} else {
-		if (new_state == CLOCK_ENABLE)
-			clk_prepare_enable(info->clk);
-	}
-
-	info->clk_state = new_state;
-}
-
-/* timing calculations */
-
-#define NS_IN_KHZ 1000000
-
-/**
- * s3c_nand_calc_rate - calculate timing data.
- * @wanted: The cycle time in nanoseconds.
- * @clk: The clock rate in kHz.
- * @max: The maximum divider value.
- *
- * Calculate the timing value from the given parameters.
- */
-static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
-{
-	int result;
-
-	result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
-
-	pr_debug("result %d from %ld, %d\n", result, clk, wanted);
-
-	if (result > max) {
-		pr_err("%d ns is too big for current clock rate %ld\n",
-			wanted, clk);
-		return -1;
-	}
-
-	if (result < 1)
-		result = 1;
-
-	return result;
-}
-
-#define to_ns(ticks, clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
-
-/* controller setup */
-
-/**
- * s3c2410_nand_setrate - setup controller timing information.
- * @info: The controller instance.
- *
- * Given the information supplied by the platform, calculate and set
- * the necessary timing registers in the hardware to generate the
- * necessary timing cycles to the hardware.
- */
-static int s3c2410_nand_setrate(struct s3c2410_nand_info *info)
-{
-	struct s3c2410_platform_nand *plat = info->platform;
-	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
-	int tacls, twrph0, twrph1;
-	unsigned long clkrate = clk_get_rate(info->clk);
-	unsigned long uninitialized_var(set), cfg, uninitialized_var(mask);
-	unsigned long flags;
-
-	/* calculate the timing information for the controller */
-
-	info->clk_rate = clkrate;
-	clkrate /= 1000;	/* turn clock into kHz for ease of use */
-
-	if (plat != NULL) {
-		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
-		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
-		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
-	} else {
-		/* default timings */
-		tacls = tacls_max;
-		twrph0 = 8;
-		twrph1 = 8;
-	}
-
-	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
-		dev_err(info->device, "cannot get suitable timings\n");
-		return -EINVAL;
-	}
-
-	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
-		tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate),
-						twrph1, to_ns(twrph1, clkrate));
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-		mask = (S3C2410_NFCONF_TACLS(3) |
-			S3C2410_NFCONF_TWRPH0(7) |
-			S3C2410_NFCONF_TWRPH1(7));
-		set = S3C2410_NFCONF_EN;
-		set |= S3C2410_NFCONF_TACLS(tacls - 1);
-		set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
-		set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
-		break;
-
-	case TYPE_S3C2440:
-	case TYPE_S3C2412:
-		mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) |
-			S3C2440_NFCONF_TWRPH0(7) |
-			S3C2440_NFCONF_TWRPH1(7));
-
-		set = S3C2440_NFCONF_TACLS(tacls - 1);
-		set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
-		set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
-		break;
-
-	default:
-		BUG();
-	}
-
-	local_irq_save(flags);
-
-	cfg = readl(info->regs + S3C2410_NFCONF);
-	cfg &= ~mask;
-	cfg |= set;
-	writel(cfg, info->regs + S3C2410_NFCONF);
-
-	local_irq_restore(flags);
-
-	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
-
-	return 0;
-}
-
-/**
- * s3c2410_nand_inithw - basic hardware initialisation
- * @info: The hardware state.
- *
- * Do the basic initialisation of the hardware, using s3c2410_nand_setrate()
- * to setup the hardware access speeds and set the controller to be enabled.
-*/
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
-{
-	int ret;
-
-	ret = s3c2410_nand_setrate(info);
-	if (ret < 0)
-		return ret;
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-	default:
-		break;
-
-	case TYPE_S3C2440:
-	case TYPE_S3C2412:
-		/* enable the controller and de-assert nFCE */
-
-		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
-	}
-
-	return 0;
-}
-
-/**
- * s3c2410_nand_select_chip - select the given nand chip
- * @mtd: The MTD instance for this chip.
- * @chip: The chip number.
- *
- * This is called by the MTD layer to either select a given chip for the
- * @mtd instance, or to indicate that the access has finished and the
- * chip can be de-selected.
- *
- * The routine ensures that the nFCE line is correctly setup, and any
- * platform specific selection code is called to route nFCE to the specific
- * chip.
- */
-static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct s3c2410_nand_info *info;
-	struct s3c2410_nand_mtd *nmtd;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	unsigned long cur;
-
-	nmtd = nand_get_controller_data(this);
-	info = nmtd->info;
-
-	if (chip != -1)
-		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
-
-	cur = readl(info->sel_reg);
-
-	if (chip == -1) {
-		cur |= info->sel_bit;
-	} else {
-		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
-			dev_err(info->device, "invalid chip %d\n", chip);
-			return;
-		}
-
-		if (info->platform != NULL) {
-			if (info->platform->select_chip != NULL)
-				(info->platform->select_chip) (nmtd->set, chip);
-		}
-
-		cur &= ~info->sel_bit;
-	}
-
-	writel(cur, info->sel_reg);
-
-	if (chip == -1)
-		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
-}
-
-/* s3c2410_nand_hwcontrol
- *
- * Issue command and address cycles to the chip
-*/
-
-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigned int ctrl)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		writeb(cmd, info->regs + S3C2410_NFCMD);
-	else
-		writeb(cmd, info->regs + S3C2410_NFADDR);
-}
-
-/* command and control functions */
-
-static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigned int ctrl)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		writeb(cmd, info->regs + S3C2440_NFCMD);
-	else
-		writeb(cmd, info->regs + S3C2440_NFADDR);
-}
-
-/* s3c2410_nand_devready()
- *
- * returns 0 if the nand is busy, 1 if it is ready
-*/
-
-static int s3c2410_nand_devready(struct mtd_info *mtd)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
-}
-
-static int s3c2440_nand_devready(struct mtd_info *mtd)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
-}
-
-static int s3c2412_nand_devready(struct mtd_info *mtd)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
-}
-
-/* ECC handling functions */
-
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
-				     u_char *read_ecc, u_char *calc_ecc)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	unsigned int diff0, diff1, diff2;
-	unsigned int bit, byte;
-
-	pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
-
-	diff0 = read_ecc[0] ^ calc_ecc[0];
-	diff1 = read_ecc[1] ^ calc_ecc[1];
-	diff2 = read_ecc[2] ^ calc_ecc[2];
-
-	pr_debug("%s: rd %*phN calc %*phN diff %02x%02x%02x\n",
-		 __func__, 3, read_ecc, 3, calc_ecc,
-		 diff0, diff1, diff2);
-
-	if (diff0 == 0 && diff1 == 0 && diff2 == 0)
-		return 0;		/* ECC is ok */
-
-	/* sometimes people do not think about using the ECC, so check
-	 * to see if we have an 0xff,0xff,0xff read ECC and then ignore
-	 * the error, on the assumption that this is an un-eccd page.
-	 */
-	if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
-	    && info->platform->ignore_unset_ecc)
-		return 0;
-
-	/* Can we correct this ECC (ie, one row and column change).
-	 * Note, this is similar to the 256 error code on smartmedia */
-
-	if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
-	    ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
-	    ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
-		/* calculate the bit position of the error */
-
-		bit  = ((diff2 >> 3) & 1) |
-		       ((diff2 >> 4) & 2) |
-		       ((diff2 >> 5) & 4);
-
-		/* calculate the byte position of the error */
-
-		byte = ((diff2 << 7) & 0x100) |
-		       ((diff1 << 0) & 0x80)  |
-		       ((diff1 << 1) & 0x40)  |
-		       ((diff1 << 2) & 0x20)  |
-		       ((diff1 << 3) & 0x10)  |
-		       ((diff0 >> 4) & 0x08)  |
-		       ((diff0 >> 3) & 0x04)  |
-		       ((diff0 >> 2) & 0x02)  |
-		       ((diff0 >> 1) & 0x01);
-
-		dev_dbg(info->device, "correcting error bit %d, byte %d\n",
-			bit, byte);
-
-		dat[byte] ^= (1 << bit);
-		return 1;
-	}
-
-	/* if there is only one bit difference in the ECC, then
-	 * one of only a row or column parity has changed, which
-	 * means the error is most probably in the ECC itself */
-
-	diff0 |= (diff1 << 8);
-	diff0 |= (diff2 << 16);
-
-	/* equal to "(diff0 & ~(1 << __ffs(diff0)))" */
-	if ((diff0 & (diff0 - 1)) == 0)
-		return 1;
-
-	return -1;
-}
-
-/* ECC functions
- *
- * These allow the s3c2410 and s3c2440 to use the controller's ECC
- * generator block to ECC the data as it passes through]
-*/
-
-static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	unsigned long ctrl;
-
-	ctrl = readl(info->regs + S3C2410_NFCONF);
-	ctrl |= S3C2410_NFCONF_INITECC;
-	writel(ctrl, info->regs + S3C2410_NFCONF);
-}
-
-static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	unsigned long ctrl;
-
-	ctrl = readl(info->regs + S3C2440_NFCONT);
-	writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
-	       info->regs + S3C2440_NFCONT);
-}
-
-static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	unsigned long ctrl;
-
-	ctrl = readl(info->regs + S3C2440_NFCONT);
-	writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
-}
-
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-				      u_char *ecc_code)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-	ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
-	ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
-	ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
-
-	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
-
-	return 0;
-}
-
-static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-				      u_char *ecc_code)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
-
-	ecc_code[0] = ecc;
-	ecc_code[1] = ecc >> 8;
-	ecc_code[2] = ecc >> 16;
-
-	pr_debug("%s: returning ecc %*phN\n", __func__, 3, ecc_code);
-
-	return 0;
-}
-
-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-				      u_char *ecc_code)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
-
-	ecc_code[0] = ecc;
-	ecc_code[1] = ecc >> 8;
-	ecc_code[2] = ecc >> 16;
-
-	pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
-
-	return 0;
-}
-
-/* over-ride the standard functions for a little more speed. We can
- * use read/write block to move the data buffers to/from the controller
-*/
-
-static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	readsb(this->IO_ADDR_R, buf, len);
-}
-
-static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-	readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
-
-	/* cleanup if we've got less than a word to do */
-	if (len & 3) {
-		buf += len & ~3;
-
-		for (; len & 3; len--)
-			*buf++ = readb(info->regs + S3C2440_NFDATA);
-	}
-}
-
-static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
-				   int len)
-{
-	struct nand_chip *this = mtd_to_nand(mtd);
-	writesb(this->IO_ADDR_W, buf, len);
-}
-
-static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
-				   int len)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-	writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
-
-	/* cleanup any fractional write */
-	if (len & 3) {
-		buf += len & ~3;
-
-		for (; len & 3; len--, buf++)
-			writeb(*buf, info->regs + S3C2440_NFDATA);
-	}
-}
-
-/* cpufreq driver support */
-
-#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
-
-static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
-					  unsigned long val, void *data)
-{
-	struct s3c2410_nand_info *info;
-	unsigned long newclk;
-
-	info = container_of(nb, struct s3c2410_nand_info, freq_transition);
-	newclk = clk_get_rate(info->clk);
-
-	if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) ||
-	    (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) {
-		s3c2410_nand_setrate(info);
-	}
-
-	return 0;
-}
-
-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
-{
-	info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition;
-
-	return cpufreq_register_notifier(&info->freq_transition,
-					 CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void
-s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
-{
-	cpufreq_unregister_notifier(&info->freq_transition,
-				    CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info)
-{
-	return 0;
-}
-
-static inline void
-s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info)
-{
-}
-#endif
-
-/* device management functions */
-
-static int s3c24xx_nand_remove(struct platform_device *pdev)
-{
-	struct s3c2410_nand_info *info = to_nand_info(pdev);
-
-	if (info == NULL)
-		return 0;
-
-	s3c2410_nand_cpufreq_deregister(info);
-
-	/* Release all our mtds  and their partitions, then go through
-	 * freeing the resources used
-	 */
-
-	if (info->mtds != NULL) {
-		struct s3c2410_nand_mtd *ptr = info->mtds;
-		int mtdno;
-
-		for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
-			pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
-			nand_release(nand_to_mtd(&ptr->chip));
-		}
-	}
-
-	/* free the common resources */
-
-	if (!IS_ERR(info->clk))
-		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
-
-	return 0;
-}
-
-static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
-				      struct s3c2410_nand_mtd *mtd,
-				      struct s3c2410_nand_set *set)
-{
-	if (set) {
-		struct mtd_info *mtdinfo = nand_to_mtd(&mtd->chip);
-
-		mtdinfo->name = set->name;
-
-		return mtd_device_parse_register(mtdinfo, NULL, NULL,
-					 set->partitions, set->nr_partitions);
-	}
-
-	return -ENODEV;
-}
-
-static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
-					const struct nand_data_interface *conf)
-{
-	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	struct s3c2410_platform_nand *pdata = info->platform;
-	const struct nand_sdr_timings *timings;
-	int tacls;
-
-	timings = nand_get_sdr_timings(conf);
-	if (IS_ERR(timings))
-		return -ENOTSUPP;
-
-	tacls = timings->tCLS_min - timings->tWP_min;
-	if (tacls < 0)
-		tacls = 0;
-
-	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
-	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
-	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
-
-	return s3c2410_nand_setrate(info);
-}
-
-/**
- * s3c2410_nand_init_chip - initialise a single instance of an chip
- * @info: The base NAND controller the chip is on.
- * @nmtd: The new controller MTD instance to fill in.
- * @set: The information passed from the board specific platform data.
- *
- * Initialise the given @nmtd from the information in @info and @set. This
- * readies the structure for use with the MTD layer functions by ensuring
- * all pointers are setup and the necessary control routines selected.
- */
-static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
-				   struct s3c2410_nand_mtd *nmtd,
-				   struct s3c2410_nand_set *set)
-{
-	struct device_node *np = info->device->of_node;
-	struct nand_chip *chip = &nmtd->chip;
-	void __iomem *regs = info->regs;
-
-	nand_set_flash_node(chip, set->of_node);
-
-	chip->write_buf    = s3c2410_nand_write_buf;
-	chip->read_buf     = s3c2410_nand_read_buf;
-	chip->select_chip  = s3c2410_nand_select_chip;
-	chip->chip_delay   = 50;
-	nand_set_controller_data(chip, nmtd);
-	chip->options	   = set->options;
-	chip->controller   = &info->controller;
-
-	/*
-	 * let's keep behavior unchanged for legacy boards booting via pdata and
-	 * auto-detect timings only when booting with a device tree.
-	 */
-	if (np)
-		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
-
-	switch (info->cpu_type) {
-	case TYPE_S3C2410:
-		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
-		info->sel_reg   = regs + S3C2410_NFCONF;
-		info->sel_bit	= S3C2410_NFCONF_nFCE;
-		chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
-		chip->dev_ready = s3c2410_nand_devready;
-		break;
-
-	case TYPE_S3C2440:
-		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
-		info->sel_reg   = regs + S3C2440_NFCONT;
-		info->sel_bit	= S3C2440_NFCONT_nFCE;
-		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
-		chip->dev_ready = s3c2440_nand_devready;
-		chip->read_buf  = s3c2440_nand_read_buf;
-		chip->write_buf	= s3c2440_nand_write_buf;
-		break;
-
-	case TYPE_S3C2412:
-		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
-		info->sel_reg   = regs + S3C2440_NFCONT;
-		info->sel_bit	= S3C2412_NFCONT_nFCE0;
-		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
-		chip->dev_ready = s3c2412_nand_devready;
-
-		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
-			dev_info(info->device, "System booted from NAND\n");
-
-		break;
-	}
-
-	chip->IO_ADDR_R = chip->IO_ADDR_W;
-
-	nmtd->info	   = info;
-	nmtd->set	   = set;
-
-	chip->ecc.mode = info->platform->ecc_mode;
-
-	/*
-	 * If you use u-boot BBT creation code, specifying this flag will
-	 * let the kernel fish out the BBT from the NAND.
-	 */
-	if (set->flash_bbt)
-		chip->bbt_options |= NAND_BBT_USE_FLASH;
-}
-
-/**
- * s3c2410_nand_update_chip - post probe update
- * @info: The controller instance.
- * @nmtd: The driver version of the MTD instance.
- *
- * This routine is called after the chip probe has successfully completed
- * and the relevant per-chip information updated. This call ensure that
- * we update the internal state accordingly.
- *
- * The internal state is currently limited to the ECC state information.
-*/
-static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
-				    struct s3c2410_nand_mtd *nmtd)
-{
-	struct nand_chip *chip = &nmtd->chip;
-
-	switch (chip->ecc.mode) {
-
-	case NAND_ECC_NONE:
-		dev_info(info->device, "ECC disabled\n");
-		break;
-
-	case NAND_ECC_SOFT:
-		/*
-		 * This driver expects Hamming based ECC when ecc_mode is set
-		 * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
-		 * avoid adding an extra ecc_algo field to
-		 * s3c2410_platform_nand.
-		 */
-		chip->ecc.algo = NAND_ECC_HAMMING;
-		dev_info(info->device, "soft ECC\n");
-		break;
-
-	case NAND_ECC_HW:
-		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-		chip->ecc.correct   = s3c2410_nand_correct_data;
-		chip->ecc.strength  = 1;
-
-		switch (info->cpu_type) {
-		case TYPE_S3C2410:
-			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
-			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-			break;
-
-		case TYPE_S3C2412:
-			chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-			chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-			break;
-
-		case TYPE_S3C2440:
-			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-			break;
-		}
-
-		dev_dbg(info->device, "chip %p => page shift %d\n",
-			chip, chip->page_shift);
-
-		/* change the behaviour depending on whether we are using
-		 * the large or small page nand device */
-		if (chip->page_shift > 10) {
-			chip->ecc.size	    = 256;
-			chip->ecc.bytes	    = 3;
-		} else {
-			chip->ecc.size	    = 512;
-			chip->ecc.bytes	    = 3;
-			mtd_set_ooblayout(nand_to_mtd(chip),
-					  &s3c2410_ooblayout_ops);
-		}
-
-		dev_info(info->device, "hardware ECC\n");
-		break;
-
-	default:
-		dev_err(info->device, "invalid ECC mode!\n");
-		return -EINVAL;
-	}
-
-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
-		chip->options |= NAND_SKIP_BBTSCAN;
-
-	return 0;
-}
-
-static const struct of_device_id s3c24xx_nand_dt_ids[] = {
-	{
-		.compatible = "samsung,s3c2410-nand",
-		.data = &s3c2410_nand_devtype_data,
-	}, {
-		/* also compatible with s3c6400 */
-		.compatible = "samsung,s3c2412-nand",
-		.data = &s3c2412_nand_devtype_data,
-	}, {
-		.compatible = "samsung,s3c2440-nand",
-		.data = &s3c2440_nand_devtype_data,
-	},
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
-
-static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
-{
-	const struct s3c24XX_nand_devtype_data *devtype_data;
-	struct s3c2410_platform_nand *pdata;
-	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
-	struct device_node *np = pdev->dev.of_node, *child;
-	struct s3c2410_nand_set *sets;
-
-	devtype_data = of_device_get_match_data(&pdev->dev);
-	if (!devtype_data)
-		return -ENODEV;
-
-	info->cpu_type = devtype_data->type;
-
-	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return -ENOMEM;
-
-	pdev->dev.platform_data = pdata;
-
-	pdata->nr_sets = of_get_child_count(np);
-	if (!pdata->nr_sets)
-		return 0;
-
-	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets,
-			    GFP_KERNEL);
-	if (!sets)
-		return -ENOMEM;
-
-	pdata->sets = sets;
-
-	for_each_available_child_of_node(np, child) {
-		sets->name = (char *)child->name;
-		sets->of_node = child;
-		sets->nr_chips = 1;
-
-		of_node_get(child);
-
-		sets++;
-	}
-
-	return 0;
-}
-
-static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
-{
-	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
-
-	info->cpu_type = platform_get_device_id(pdev)->driver_data;
-
-	return 0;
-}
-
-/* s3c24xx_nand_probe
- *
- * called by device layer when it finds a device matching
- * one our driver can handled. This code checks to see if
- * it can allocate all necessary resources then calls the
- * nand layer to look for devices
-*/
-static int s3c24xx_nand_probe(struct platform_device *pdev)
-{
-	struct s3c2410_platform_nand *plat;
-	struct s3c2410_nand_info *info;
-	struct s3c2410_nand_mtd *nmtd;
-	struct s3c2410_nand_set *sets;
-	struct resource *res;
-	int err = 0;
-	int size;
-	int nr_sets;
-	int setno;
-
-	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-	if (info == NULL) {
-		err = -ENOMEM;
-		goto exit_error;
-	}
-
-	platform_set_drvdata(pdev, info);
-
-	nand_hw_control_init(&info->controller);
-
-	/* get the clock source and enable it */
-
-	info->clk = devm_clk_get(&pdev->dev, "nand");
-	if (IS_ERR(info->clk)) {
-		dev_err(&pdev->dev, "failed to get clock\n");
-		err = -ENOENT;
-		goto exit_error;
-	}
-
-	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
-
-	if (pdev->dev.of_node)
-		err = s3c24xx_nand_probe_dt(pdev);
-	else
-		err = s3c24xx_nand_probe_pdata(pdev);
-
-	if (err)
-		goto exit_error;
-
-	plat = to_nand_plat(pdev);
-
-	/* allocate and map the resource */
-
-	/* currently we assume we have the one resource */
-	res = pdev->resource;
-	size = resource_size(res);
-
-	info->device	= &pdev->dev;
-	info->platform	= plat;
-
-	info->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(info->regs)) {
-		err = PTR_ERR(info->regs);
-		goto exit_error;
-	}
-
-	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
-
-	sets = (plat != NULL) ? plat->sets : NULL;
-	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
-
-	info->mtd_count = nr_sets;
-
-	/* allocate our information */
-
-	size = nr_sets * sizeof(*info->mtds);
-	info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-	if (info->mtds == NULL) {
-		err = -ENOMEM;
-		goto exit_error;
-	}
-
-	/* initialise all possible chips */
-
-	nmtd = info->mtds;
-
-	for (setno = 0; setno < nr_sets; setno++, nmtd++) {
-		struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
-
-		pr_debug("initialising set %d (%p, info %p)\n",
-			 setno, nmtd, info);
-
-		mtd->dev.parent = &pdev->dev;
-		s3c2410_nand_init_chip(info, nmtd, sets);
-
-		nmtd->scan_res = nand_scan_ident(mtd,
-						 (sets) ? sets->nr_chips : 1,
-						 NULL);
-
-		if (nmtd->scan_res == 0) {
-			err = s3c2410_nand_update_chip(info, nmtd);
-			if (err < 0)
-				goto exit_error;
-			nand_scan_tail(mtd);
-			s3c2410_nand_add_partition(info, nmtd, sets);
-		}
-
-		if (sets != NULL)
-			sets++;
-	}
-
-	/* initialise the hardware */
-	err = s3c2410_nand_inithw(info);
-	if (err != 0)
-		goto exit_error;
-
-	err = s3c2410_nand_cpufreq_register(info);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to init cpufreq support\n");
-		goto exit_error;
-	}
-
-	if (allow_clk_suspend(info)) {
-		dev_info(&pdev->dev, "clock idle support enabled\n");
-		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
-	}
-
-	return 0;
-
- exit_error:
-	s3c24xx_nand_remove(pdev);
-
-	if (err == 0)
-		err = -EINVAL;
-	return err;
-}
-
-/* PM Support */
-#ifdef CONFIG_PM
-
-static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
-{
-	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
-
-	if (info) {
-		info->save_sel = readl(info->sel_reg);
-
-		/* For the moment, we must ensure nFCE is high during
-		 * the time we are suspended. This really should be
-		 * handled by suspending the MTDs we are using, but
-		 * that is currently not the case. */
-
-		writel(info->save_sel | info->sel_bit, info->sel_reg);
-
-		s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
-	}
-
-	return 0;
-}
-
-static int s3c24xx_nand_resume(struct platform_device *dev)
-{
-	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
-	unsigned long sel;
-
-	if (info) {
-		s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
-		s3c2410_nand_inithw(info);
-
-		/* Restore the state of the nFCE line. */
-
-		sel = readl(info->sel_reg);
-		sel &= ~info->sel_bit;
-		sel |= info->save_sel & info->sel_bit;
-		writel(sel, info->sel_reg);
-
-		s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
-	}
-
-	return 0;
-}
-
-#else
-#define s3c24xx_nand_suspend NULL
-#define s3c24xx_nand_resume NULL
-#endif
-
-/* driver device registration */
-
-static const struct platform_device_id s3c24xx_driver_ids[] = {
-	{
-		.name		= "s3c2410-nand",
-		.driver_data	= TYPE_S3C2410,
-	}, {
-		.name		= "s3c2440-nand",
-		.driver_data	= TYPE_S3C2440,
-	}, {
-		.name		= "s3c2412-nand",
-		.driver_data	= TYPE_S3C2412,
-	}, {
-		.name		= "s3c6400-nand",
-		.driver_data	= TYPE_S3C2412, /* compatible with 2412 */
-	},
-	{ }
-};
-
-MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
-
-static struct platform_driver s3c24xx_nand_driver = {
-	.probe		= s3c24xx_nand_probe,
-	.remove		= s3c24xx_nand_remove,
-	.suspend	= s3c24xx_nand_suspend,
-	.resume		= s3c24xx_nand_resume,
-	.id_table	= s3c24xx_driver_ids,
-	.driver		= {
-		.name	= "s3c24xx-nand",
-		.of_match_table = s3c24xx_nand_dt_ids,
-	},
-};
-
-module_platform_driver(s3c24xx_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
deleted file mode 100644
index c4e7755448e6..000000000000
--- a/drivers/mtd/nand/sh_flctl.c
+++ /dev/null
@@ -1,1250 +0,0 @@
-/*
- * SuperH FLCTL nand controller
- *
- * Copyright (c) 2008 Renesas Solutions Corp.
- * Copyright (c) 2008 Atom Create Engineering Co., Ltd.
- *
- * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/sh_dma.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/sh_flctl.h>
-
-static int flctl_4secc_ooblayout_sp_ecc(struct mtd_info *mtd, int section,
-					struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 0;
-	oobregion->length = chip->ecc.bytes;
-
-	return 0;
-}
-
-static int flctl_4secc_ooblayout_sp_free(struct mtd_info *mtd, int section,
-					 struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->offset = 12;
-	oobregion->length = 4;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops flctl_4secc_oob_smallpage_ops = {
-	.ecc = flctl_4secc_ooblayout_sp_ecc,
-	.free = flctl_4secc_ooblayout_sp_free,
-};
-
-static int flctl_4secc_ooblayout_lp_ecc(struct mtd_info *mtd, int section,
-					struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = (section * 16) + 6;
-	oobregion->length = chip->ecc.bytes;
-
-	return 0;
-}
-
-static int flctl_4secc_ooblayout_lp_free(struct mtd_info *mtd, int section,
-					 struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (section >= chip->ecc.steps)
-		return -ERANGE;
-
-	oobregion->offset = section * 16;
-	oobregion->length = 6;
-
-	if (!section) {
-		oobregion->offset += 2;
-		oobregion->length -= 2;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops flctl_4secc_oob_largepage_ops = {
-	.ecc = flctl_4secc_ooblayout_lp_ecc,
-	.free = flctl_4secc_ooblayout_lp_free,
-};
-
-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-
-static struct nand_bbt_descr flctl_4secc_smallpage = {
-	.options = NAND_BBT_SCAN2NDPAGE,
-	.offs = 11,
-	.len = 1,
-	.pattern = scan_ff_pattern,
-};
-
-static struct nand_bbt_descr flctl_4secc_largepage = {
-	.options = NAND_BBT_SCAN2NDPAGE,
-	.offs = 0,
-	.len = 2,
-	.pattern = scan_ff_pattern,
-};
-
-static void empty_fifo(struct sh_flctl *flctl)
-{
-	writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
-	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
-}
-
-static void start_translation(struct sh_flctl *flctl)
-{
-	writeb(TRSTRT, FLTRCR(flctl));
-}
-
-static void timeout_error(struct sh_flctl *flctl, const char *str)
-{
-	dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str);
-}
-
-static void wait_completion(struct sh_flctl *flctl)
-{
-	uint32_t timeout = LOOP_TIMEOUT_MAX;
-
-	while (timeout--) {
-		if (readb(FLTRCR(flctl)) & TREND) {
-			writeb(0x0, FLTRCR(flctl));
-			return;
-		}
-		udelay(1);
-	}
-
-	timeout_error(flctl, __func__);
-	writeb(0x0, FLTRCR(flctl));
-}
-
-static void flctl_dma_complete(void *param)
-{
-	struct sh_flctl *flctl = param;
-
-	complete(&flctl->dma_complete);
-}
-
-static void flctl_release_dma(struct sh_flctl *flctl)
-{
-	if (flctl->chan_fifo0_rx) {
-		dma_release_channel(flctl->chan_fifo0_rx);
-		flctl->chan_fifo0_rx = NULL;
-	}
-	if (flctl->chan_fifo0_tx) {
-		dma_release_channel(flctl->chan_fifo0_tx);
-		flctl->chan_fifo0_tx = NULL;
-	}
-}
-
-static void flctl_setup_dma(struct sh_flctl *flctl)
-{
-	dma_cap_mask_t mask;
-	struct dma_slave_config cfg;
-	struct platform_device *pdev = flctl->pdev;
-	struct sh_flctl_platform_data *pdata = dev_get_platdata(&pdev->dev);
-	int ret;
-
-	if (!pdata)
-		return;
-
-	if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
-		return;
-
-	/* We can only either use DMA for both Tx and Rx or not use it at all */
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-
-	flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
-				(void *)(uintptr_t)pdata->slave_id_fifo0_tx);
-	dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
-		flctl->chan_fifo0_tx);
-
-	if (!flctl->chan_fifo0_tx)
-		return;
-
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.direction = DMA_MEM_TO_DEV;
-	cfg.dst_addr = flctl->fifo;
-	cfg.src_addr = 0;
-	ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
-	if (ret < 0)
-		goto err;
-
-	flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
-				(void *)(uintptr_t)pdata->slave_id_fifo0_rx);
-	dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
-		flctl->chan_fifo0_rx);
-
-	if (!flctl->chan_fifo0_rx)
-		goto err;
-
-	cfg.direction = DMA_DEV_TO_MEM;
-	cfg.dst_addr = 0;
-	cfg.src_addr = flctl->fifo;
-	ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
-	if (ret < 0)
-		goto err;
-
-	init_completion(&flctl->dma_complete);
-
-	return;
-
-err:
-	flctl_release_dma(flctl);
-}
-
-static void set_addr(struct mtd_info *mtd, int column, int page_addr)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint32_t addr = 0;
-
-	if (column == -1) {
-		addr = page_addr;	/* ERASE1 */
-	} else if (page_addr != -1) {
-		/* SEQIN, READ0, etc.. */
-		if (flctl->chip.options & NAND_BUSWIDTH_16)
-			column >>= 1;
-		if (flctl->page_size) {
-			addr = column & 0x0FFF;
-			addr |= (page_addr & 0xff) << 16;
-			addr |= ((page_addr >> 8) & 0xff) << 24;
-			/* big than 128MB */
-			if (flctl->rw_ADRCNT == ADRCNT2_E) {
-				uint32_t 	addr2;
-				addr2 = (page_addr >> 16) & 0xff;
-				writel(addr2, FLADR2(flctl));
-			}
-		} else {
-			addr = column;
-			addr |= (page_addr & 0xff) << 8;
-			addr |= ((page_addr >> 8) & 0xff) << 16;
-			addr |= ((page_addr >> 16) & 0xff) << 24;
-		}
-	}
-	writel(addr, FLADR(flctl));
-}
-
-static void wait_rfifo_ready(struct sh_flctl *flctl)
-{
-	uint32_t timeout = LOOP_TIMEOUT_MAX;
-
-	while (timeout--) {
-		uint32_t val;
-		/* check FIFO */
-		val = readl(FLDTCNTR(flctl)) >> 16;
-		if (val & 0xFF)
-			return;
-		udelay(1);
-	}
-	timeout_error(flctl, __func__);
-}
-
-static void wait_wfifo_ready(struct sh_flctl *flctl)
-{
-	uint32_t len, timeout = LOOP_TIMEOUT_MAX;
-
-	while (timeout--) {
-		/* check FIFO */
-		len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF;
-		if (len >= 4)
-			return;
-		udelay(1);
-	}
-	timeout_error(flctl, __func__);
-}
-
-static enum flctl_ecc_res_t wait_recfifo_ready
-		(struct sh_flctl *flctl, int sector_number)
-{
-	uint32_t timeout = LOOP_TIMEOUT_MAX;
-	void __iomem *ecc_reg[4];
-	int i;
-	int state = FL_SUCCESS;
-	uint32_t data, size;
-
-	/*
-	 * First this loops checks in FLDTCNTR if we are ready to read out the
-	 * oob data. This is the case if either all went fine without errors or
-	 * if the bottom part of the loop corrected the errors or marked them as
-	 * uncorrectable and the controller is given time to push the data into
-	 * the FIFO.
-	 */
-	while (timeout--) {
-		/* check if all is ok and we can read out the OOB */
-		size = readl(FLDTCNTR(flctl)) >> 24;
-		if ((size & 0xFF) == 4)
-			return state;
-
-		/* check if a correction code has been calculated */
-		if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
-			/*
-			 * either we wait for the fifo to be filled or a
-			 * correction pattern is being generated
-			 */
-			udelay(1);
-			continue;
-		}
-
-		/* check for an uncorrectable error */
-		if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
-			/* check if we face a non-empty page */
-			for (i = 0; i < 512; i++) {
-				if (flctl->done_buff[i] != 0xff) {
-					state = FL_ERROR; /* can't correct */
-					break;
-				}
-			}
-
-			if (state == FL_SUCCESS)
-				dev_dbg(&flctl->pdev->dev,
-				"reading empty sector %d, ecc error ignored\n",
-				sector_number);
-
-			writel(0, FL4ECCCR(flctl));
-			continue;
-		}
-
-		/* start error correction */
-		ecc_reg[0] = FL4ECCRESULT0(flctl);
-		ecc_reg[1] = FL4ECCRESULT1(flctl);
-		ecc_reg[2] = FL4ECCRESULT2(flctl);
-		ecc_reg[3] = FL4ECCRESULT3(flctl);
-
-		for (i = 0; i < 3; i++) {
-			uint8_t org;
-			unsigned int index;
-
-			data = readl(ecc_reg[i]);
-
-			if (flctl->page_size)
-				index = (512 * sector_number) +
-					(data >> 16);
-			else
-				index = data >> 16;
-
-			org = flctl->done_buff[index];
-			flctl->done_buff[index] = org ^ (data & 0xFF);
-		}
-		state = FL_REPAIRABLE;
-		writel(0, FL4ECCCR(flctl));
-	}
-
-	timeout_error(flctl, __func__);
-	return FL_TIMEOUT;	/* timeout */
-}
-
-static void wait_wecfifo_ready(struct sh_flctl *flctl)
-{
-	uint32_t timeout = LOOP_TIMEOUT_MAX;
-	uint32_t len;
-
-	while (timeout--) {
-		/* check FLECFIFO */
-		len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF;
-		if (len >= 4)
-			return;
-		udelay(1);
-	}
-	timeout_error(flctl, __func__);
-}
-
-static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
-					int len, enum dma_data_direction dir)
-{
-	struct dma_async_tx_descriptor *desc = NULL;
-	struct dma_chan *chan;
-	enum dma_transfer_direction tr_dir;
-	dma_addr_t dma_addr;
-	dma_cookie_t cookie;
-	uint32_t reg;
-	int ret;
-
-	if (dir == DMA_FROM_DEVICE) {
-		chan = flctl->chan_fifo0_rx;
-		tr_dir = DMA_DEV_TO_MEM;
-	} else {
-		chan = flctl->chan_fifo0_tx;
-		tr_dir = DMA_MEM_TO_DEV;
-	}
-
-	dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
-
-	if (!dma_mapping_error(chan->device->dev, dma_addr))
-		desc = dmaengine_prep_slave_single(chan, dma_addr, len,
-			tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
-	if (desc) {
-		reg = readl(FLINTDMACR(flctl));
-		reg |= DREQ0EN;
-		writel(reg, FLINTDMACR(flctl));
-
-		desc->callback = flctl_dma_complete;
-		desc->callback_param = flctl;
-		cookie = dmaengine_submit(desc);
-		if (dma_submit_error(cookie)) {
-			ret = dma_submit_error(cookie);
-			dev_warn(&flctl->pdev->dev,
-				 "DMA submit failed, falling back to PIO\n");
-			goto out;
-		}
-
-		dma_async_issue_pending(chan);
-	} else {
-		/* DMA failed, fall back to PIO */
-		flctl_release_dma(flctl);
-		dev_warn(&flctl->pdev->dev,
-			 "DMA failed, falling back to PIO\n");
-		ret = -EIO;
-		goto out;
-	}
-
-	ret =
-	wait_for_completion_timeout(&flctl->dma_complete,
-				msecs_to_jiffies(3000));
-
-	if (ret <= 0) {
-		dmaengine_terminate_all(chan);
-		dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
-	}
-
-out:
-	reg = readl(FLINTDMACR(flctl));
-	reg &= ~DREQ0EN;
-	writel(reg, FLINTDMACR(flctl));
-
-	dma_unmap_single(chan->device->dev, dma_addr, len, dir);
-
-	/* ret > 0 is success */
-	return ret;
-}
-
-static void read_datareg(struct sh_flctl *flctl, int offset)
-{
-	unsigned long data;
-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
-
-	wait_completion(flctl);
-
-	data = readl(FLDATAR(flctl));
-	*buf = le32_to_cpu(data);
-}
-
-static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
-{
-	int i, len_4align;
-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
-
-	len_4align = (rlen + 3) / 4;
-
-	/* initiate DMA transfer */
-	if (flctl->chan_fifo0_rx && rlen >= 32 &&
-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
-			goto convert;	/* DMA success */
-
-	/* do polling transfer */
-	for (i = 0; i < len_4align; i++) {
-		wait_rfifo_ready(flctl);
-		buf[i] = readl(FLDTFIFO(flctl));
-	}
-
-convert:
-	for (i = 0; i < len_4align; i++)
-		buf[i] = be32_to_cpu(buf[i]);
-}
-
-static enum flctl_ecc_res_t read_ecfiforeg
-		(struct sh_flctl *flctl, uint8_t *buff, int sector)
-{
-	int i;
-	enum flctl_ecc_res_t res;
-	unsigned long *ecc_buf = (unsigned long *)buff;
-
-	res = wait_recfifo_ready(flctl , sector);
-
-	if (res != FL_ERROR) {
-		for (i = 0; i < 4; i++) {
-			ecc_buf[i] = readl(FLECFIFO(flctl));
-			ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
-		}
-	}
-
-	return res;
-}
-
-static void write_fiforeg(struct sh_flctl *flctl, int rlen,
-						unsigned int offset)
-{
-	int i, len_4align;
-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
-
-	len_4align = (rlen + 3) / 4;
-	for (i = 0; i < len_4align; i++) {
-		wait_wfifo_ready(flctl);
-		writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
-	}
-}
-
-static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
-						unsigned int offset)
-{
-	int i, len_4align;
-	unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
-
-	len_4align = (rlen + 3) / 4;
-
-	for (i = 0; i < len_4align; i++)
-		buf[i] = cpu_to_be32(buf[i]);
-
-	/* initiate DMA transfer */
-	if (flctl->chan_fifo0_tx && rlen >= 32 &&
-		flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
-			return;	/* DMA success */
-
-	/* do polling transfer */
-	for (i = 0; i < len_4align; i++) {
-		wait_wecfifo_ready(flctl);
-		writel(buf[i], FLECFIFO(flctl));
-	}
-}
-
-static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
-	uint32_t flcmdcr_val, addr_len_bytes = 0;
-
-	/* Set SNAND bit if page size is 2048byte */
-	if (flctl->page_size)
-		flcmncr_val |= SNAND_E;
-	else
-		flcmncr_val &= ~SNAND_E;
-
-	/* default FLCMDCR val */
-	flcmdcr_val = DOCMD1_E | DOADR_E;
-
-	/* Set for FLCMDCR */
-	switch (cmd) {
-	case NAND_CMD_ERASE1:
-		addr_len_bytes = flctl->erase_ADRCNT;
-		flcmdcr_val |= DOCMD2_E;
-		break;
-	case NAND_CMD_READ0:
-	case NAND_CMD_READOOB:
-	case NAND_CMD_RNDOUT:
-		addr_len_bytes = flctl->rw_ADRCNT;
-		flcmdcr_val |= CDSRC_E;
-		if (flctl->chip.options & NAND_BUSWIDTH_16)
-			flcmncr_val |= SEL_16BIT;
-		break;
-	case NAND_CMD_SEQIN:
-		/* This case is that cmd is READ0 or READ1 or READ00 */
-		flcmdcr_val &= ~DOADR_E;	/* ONLY execute 1st cmd */
-		break;
-	case NAND_CMD_PAGEPROG:
-		addr_len_bytes = flctl->rw_ADRCNT;
-		flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW;
-		if (flctl->chip.options & NAND_BUSWIDTH_16)
-			flcmncr_val |= SEL_16BIT;
-		break;
-	case NAND_CMD_READID:
-		flcmncr_val &= ~SNAND_E;
-		flcmdcr_val |= CDSRC_E;
-		addr_len_bytes = ADRCNT_1;
-		break;
-	case NAND_CMD_STATUS:
-	case NAND_CMD_RESET:
-		flcmncr_val &= ~SNAND_E;
-		flcmdcr_val &= ~(DOADR_E | DOSR_E);
-		break;
-	default:
-		break;
-	}
-
-	/* Set address bytes parameter */
-	flcmdcr_val |= addr_len_bytes;
-
-	/* Now actually write */
-	writel(flcmncr_val, FLCMNCR(flctl));
-	writel(flcmdcr_val, FLCMDCR(flctl));
-	writel(flcmcdr_val, FLCMCDR(flctl));
-}
-
-static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-	if (oob_required)
-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-	return 0;
-}
-
-static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-				  const uint8_t *buf, int oob_required,
-				  int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-	return nand_prog_page_end_op(chip);
-}
-
-static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	int sector, page_sectors;
-	enum flctl_ecc_res_t ecc_result;
-
-	page_sectors = flctl->page_size ? 4 : 1;
-
-	set_cmd_regs(mtd, NAND_CMD_READ0,
-		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
-
-	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
-		 FLCMNCR(flctl));
-	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
-	writel(page_addr << 2, FLADR(flctl));
-
-	empty_fifo(flctl);
-	start_translation(flctl);
-
-	for (sector = 0; sector < page_sectors; sector++) {
-		read_fiforeg(flctl, 512, 512 * sector);
-
-		ecc_result = read_ecfiforeg(flctl,
-			&flctl->done_buff[mtd->writesize + 16 * sector],
-			sector);
-
-		switch (ecc_result) {
-		case FL_REPAIRABLE:
-			dev_info(&flctl->pdev->dev,
-				"applied ecc on page 0x%x", page_addr);
-			mtd->ecc_stats.corrected++;
-			break;
-		case FL_ERROR:
-			dev_warn(&flctl->pdev->dev,
-				"page 0x%x contains corrupted data\n",
-				page_addr);
-			mtd->ecc_stats.failed++;
-			break;
-		default:
-			;
-		}
-	}
-
-	wait_completion(flctl);
-
-	writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
-			FLCMNCR(flctl));
-}
-
-static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	int page_sectors = flctl->page_size ? 4 : 1;
-	int i;
-
-	set_cmd_regs(mtd, NAND_CMD_READ0,
-		(NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
-
-	empty_fifo(flctl);
-
-	for (i = 0; i < page_sectors; i++) {
-		set_addr(mtd, (512 + 16) * i + 512 , page_addr);
-		writel(16, FLDTCNTR(flctl));
-
-		start_translation(flctl);
-		read_fiforeg(flctl, 16, 16 * i);
-		wait_completion(flctl);
-	}
-}
-
-static void execmd_write_page_sector(struct mtd_info *mtd)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	int page_addr = flctl->seqin_page_addr;
-	int sector, page_sectors;
-
-	page_sectors = flctl->page_size ? 4 : 1;
-
-	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
-			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
-
-	empty_fifo(flctl);
-	writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
-	writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
-	writel(page_addr << 2, FLADR(flctl));
-	start_translation(flctl);
-
-	for (sector = 0; sector < page_sectors; sector++) {
-		write_fiforeg(flctl, 512, 512 * sector);
-		write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
-	}
-
-	wait_completion(flctl);
-	writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
-}
-
-static void execmd_write_oob(struct mtd_info *mtd)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	int page_addr = flctl->seqin_page_addr;
-	int sector, page_sectors;
-
-	page_sectors = flctl->page_size ? 4 : 1;
-
-	set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
-			(NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
-
-	for (sector = 0; sector < page_sectors; sector++) {
-		empty_fifo(flctl);
-		set_addr(mtd, sector * 528 + 512, page_addr);
-		writel(16, FLDTCNTR(flctl));	/* set read size */
-
-		start_translation(flctl);
-		write_fiforeg(flctl, 16, 16 * sector);
-		wait_completion(flctl);
-	}
-}
-
-static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
-			int column, int page_addr)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint32_t read_cmd = 0;
-
-	pm_runtime_get_sync(&flctl->pdev->dev);
-
-	flctl->read_bytes = 0;
-	if (command != NAND_CMD_PAGEPROG)
-		flctl->index = 0;
-
-	switch (command) {
-	case NAND_CMD_READ1:
-	case NAND_CMD_READ0:
-		if (flctl->hwecc) {
-			/* read page with hwecc */
-			execmd_read_page_sector(mtd, page_addr);
-			break;
-		}
-		if (flctl->page_size)
-			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
-				| command);
-		else
-			set_cmd_regs(mtd, command, command);
-
-		set_addr(mtd, 0, page_addr);
-
-		flctl->read_bytes = mtd->writesize + mtd->oobsize;
-		if (flctl->chip.options & NAND_BUSWIDTH_16)
-			column >>= 1;
-		flctl->index += column;
-		goto read_normal_exit;
-
-	case NAND_CMD_READOOB:
-		if (flctl->hwecc) {
-			/* read page with hwecc */
-			execmd_read_oob(mtd, page_addr);
-			break;
-		}
-
-		if (flctl->page_size) {
-			set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
-				| NAND_CMD_READ0);
-			set_addr(mtd, mtd->writesize, page_addr);
-		} else {
-			set_cmd_regs(mtd, command, command);
-			set_addr(mtd, 0, page_addr);
-		}
-		flctl->read_bytes = mtd->oobsize;
-		goto read_normal_exit;
-
-	case NAND_CMD_RNDOUT:
-		if (flctl->hwecc)
-			break;
-
-		if (flctl->page_size)
-			set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
-				| command);
-		else
-			set_cmd_regs(mtd, command, command);
-
-		set_addr(mtd, column, 0);
-
-		flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
-		goto read_normal_exit;
-
-	case NAND_CMD_READID:
-		set_cmd_regs(mtd, command, command);
-
-		/* READID is always performed using an 8-bit bus */
-		if (flctl->chip.options & NAND_BUSWIDTH_16)
-			column <<= 1;
-		set_addr(mtd, column, 0);
-
-		flctl->read_bytes = 8;
-		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
-		empty_fifo(flctl);
-		start_translation(flctl);
-		read_fiforeg(flctl, flctl->read_bytes, 0);
-		wait_completion(flctl);
-		break;
-
-	case NAND_CMD_ERASE1:
-		flctl->erase1_page_addr = page_addr;
-		break;
-
-	case NAND_CMD_ERASE2:
-		set_cmd_regs(mtd, NAND_CMD_ERASE1,
-			(command << 8) | NAND_CMD_ERASE1);
-		set_addr(mtd, -1, flctl->erase1_page_addr);
-		start_translation(flctl);
-		wait_completion(flctl);
-		break;
-
-	case NAND_CMD_SEQIN:
-		if (!flctl->page_size) {
-			/* output read command */
-			if (column >= mtd->writesize) {
-				column -= mtd->writesize;
-				read_cmd = NAND_CMD_READOOB;
-			} else if (column < 256) {
-				read_cmd = NAND_CMD_READ0;
-			} else {
-				column -= 256;
-				read_cmd = NAND_CMD_READ1;
-			}
-		}
-		flctl->seqin_column = column;
-		flctl->seqin_page_addr = page_addr;
-		flctl->seqin_read_cmd = read_cmd;
-		break;
-
-	case NAND_CMD_PAGEPROG:
-		empty_fifo(flctl);
-		if (!flctl->page_size) {
-			set_cmd_regs(mtd, NAND_CMD_SEQIN,
-					flctl->seqin_read_cmd);
-			set_addr(mtd, -1, -1);
-			writel(0, FLDTCNTR(flctl));	/* set 0 size */
-			start_translation(flctl);
-			wait_completion(flctl);
-		}
-		if (flctl->hwecc) {
-			/* write page with hwecc */
-			if (flctl->seqin_column == mtd->writesize)
-				execmd_write_oob(mtd);
-			else if (!flctl->seqin_column)
-				execmd_write_page_sector(mtd);
-			else
-				printk(KERN_ERR "Invalid address !?\n");
-			break;
-		}
-		set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN);
-		set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr);
-		writel(flctl->index, FLDTCNTR(flctl));	/* set write size */
-		start_translation(flctl);
-		write_fiforeg(flctl, flctl->index, 0);
-		wait_completion(flctl);
-		break;
-
-	case NAND_CMD_STATUS:
-		set_cmd_regs(mtd, command, command);
-		set_addr(mtd, -1, -1);
-
-		flctl->read_bytes = 1;
-		writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
-		start_translation(flctl);
-		read_datareg(flctl, 0); /* read and end */
-		break;
-
-	case NAND_CMD_RESET:
-		set_cmd_regs(mtd, command, command);
-		set_addr(mtd, -1, -1);
-
-		writel(0, FLDTCNTR(flctl));	/* set 0 size */
-		start_translation(flctl);
-		wait_completion(flctl);
-		break;
-
-	default:
-		break;
-	}
-	goto runtime_exit;
-
-read_normal_exit:
-	writel(flctl->read_bytes, FLDTCNTR(flctl));	/* set read size */
-	empty_fifo(flctl);
-	start_translation(flctl);
-	read_fiforeg(flctl, flctl->read_bytes, 0);
-	wait_completion(flctl);
-runtime_exit:
-	pm_runtime_put_sync(&flctl->pdev->dev);
-	return;
-}
-
-static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	int ret;
-
-	switch (chipnr) {
-	case -1:
-		flctl->flcmncr_base &= ~CE0_ENABLE;
-
-		pm_runtime_get_sync(&flctl->pdev->dev);
-		writel(flctl->flcmncr_base, FLCMNCR(flctl));
-
-		if (flctl->qos_request) {
-			dev_pm_qos_remove_request(&flctl->pm_qos);
-			flctl->qos_request = 0;
-		}
-
-		pm_runtime_put_sync(&flctl->pdev->dev);
-		break;
-	case 0:
-		flctl->flcmncr_base |= CE0_ENABLE;
-
-		if (!flctl->qos_request) {
-			ret = dev_pm_qos_add_request(&flctl->pdev->dev,
-							&flctl->pm_qos,
-							DEV_PM_QOS_RESUME_LATENCY,
-							100);
-			if (ret < 0)
-				dev_err(&flctl->pdev->dev,
-					"PM QoS request failed: %d\n", ret);
-			flctl->qos_request = 1;
-		}
-
-		if (flctl->holden) {
-			pm_runtime_get_sync(&flctl->pdev->dev);
-			writel(HOLDEN, FLHOLDCR(flctl));
-			pm_runtime_put_sync(&flctl->pdev->dev);
-		}
-		break;
-	default:
-		BUG();
-	}
-}
-
-static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-
-	memcpy(&flctl->done_buff[flctl->index], buf, len);
-	flctl->index += len;
-}
-
-static uint8_t flctl_read_byte(struct mtd_info *mtd)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint8_t data;
-
-	data = flctl->done_buff[flctl->index];
-	flctl->index++;
-	return data;
-}
-
-static uint16_t flctl_read_word(struct mtd_info *mtd)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
-
-	flctl->index += 2;
-	return *buf;
-}
-
-static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-
-	memcpy(buf, &flctl->done_buff[flctl->index], len);
-	flctl->index += len;
-}
-
-static int flctl_chip_init_tail(struct mtd_info *mtd)
-{
-	struct sh_flctl *flctl = mtd_to_flctl(mtd);
-	struct nand_chip *chip = &flctl->chip;
-
-	if (mtd->writesize == 512) {
-		flctl->page_size = 0;
-		if (chip->chipsize > (32 << 20)) {
-			/* big than 32MB */
-			flctl->rw_ADRCNT = ADRCNT_4;
-			flctl->erase_ADRCNT = ADRCNT_3;
-		} else if (chip->chipsize > (2 << 16)) {
-			/* big than 128KB */
-			flctl->rw_ADRCNT = ADRCNT_3;
-			flctl->erase_ADRCNT = ADRCNT_2;
-		} else {
-			flctl->rw_ADRCNT = ADRCNT_2;
-			flctl->erase_ADRCNT = ADRCNT_1;
-		}
-	} else {
-		flctl->page_size = 1;
-		if (chip->chipsize > (128 << 20)) {
-			/* big than 128MB */
-			flctl->rw_ADRCNT = ADRCNT2_E;
-			flctl->erase_ADRCNT = ADRCNT_3;
-		} else if (chip->chipsize > (8 << 16)) {
-			/* big than 512KB */
-			flctl->rw_ADRCNT = ADRCNT_4;
-			flctl->erase_ADRCNT = ADRCNT_2;
-		} else {
-			flctl->rw_ADRCNT = ADRCNT_3;
-			flctl->erase_ADRCNT = ADRCNT_1;
-		}
-	}
-
-	if (flctl->hwecc) {
-		if (mtd->writesize == 512) {
-			mtd_set_ooblayout(mtd, &flctl_4secc_oob_smallpage_ops);
-			chip->badblock_pattern = &flctl_4secc_smallpage;
-		} else {
-			mtd_set_ooblayout(mtd, &flctl_4secc_oob_largepage_ops);
-			chip->badblock_pattern = &flctl_4secc_largepage;
-		}
-
-		chip->ecc.size = 512;
-		chip->ecc.bytes = 10;
-		chip->ecc.strength = 4;
-		chip->ecc.read_page = flctl_read_page_hwecc;
-		chip->ecc.write_page = flctl_write_page_hwecc;
-		chip->ecc.mode = NAND_ECC_HW;
-
-		/* 4 symbols ECC enabled */
-		flctl->flcmncr_base |= _4ECCEN;
-	} else {
-		chip->ecc.mode = NAND_ECC_SOFT;
-		chip->ecc.algo = NAND_ECC_HAMMING;
-	}
-
-	return 0;
-}
-
-static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
-{
-	struct sh_flctl *flctl = dev_id;
-
-	dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
-	writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
-
-	return IRQ_HANDLED;
-}
-
-struct flctl_soc_config {
-	unsigned long flcmncr_val;
-	unsigned has_hwecc:1;
-	unsigned use_holden:1;
-};
-
-static struct flctl_soc_config flctl_sh7372_config = {
-	.flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
-	.has_hwecc = 1,
-	.use_holden = 1,
-};
-
-static const struct of_device_id of_flctl_match[] = {
-	{ .compatible = "renesas,shmobile-flctl-sh7372",
-				.data = &flctl_sh7372_config },
-	{},
-};
-MODULE_DEVICE_TABLE(of, of_flctl_match);
-
-static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
-{
-	const struct flctl_soc_config *config;
-	struct sh_flctl_platform_data *pdata;
-
-	config = of_device_get_match_data(dev);
-	if (!config) {
-		dev_err(dev, "%s: no OF configuration attached\n", __func__);
-		return NULL;
-	}
-
-	pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
-								GFP_KERNEL);
-	if (!pdata)
-		return NULL;
-
-	/* set SoC specific options */
-	pdata->flcmncr_val = config->flcmncr_val;
-	pdata->has_hwecc = config->has_hwecc;
-	pdata->use_holden = config->use_holden;
-
-	return pdata;
-}
-
-static int flctl_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct sh_flctl *flctl;
-	struct mtd_info *flctl_mtd;
-	struct nand_chip *nand;
-	struct sh_flctl_platform_data *pdata;
-	int ret;
-	int irq;
-
-	flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
-	if (!flctl)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	flctl->reg = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(flctl->reg))
-		return PTR_ERR(flctl->reg);
-	flctl->fifo = res->start + 0x24; /* FLDTFIFO */
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq);
-		return irq;
-	}
-
-	ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
-			       "flste", flctl);
-	if (ret) {
-		dev_err(&pdev->dev, "request interrupt failed.\n");
-		return ret;
-	}
-
-	if (pdev->dev.of_node)
-		pdata = flctl_parse_dt(&pdev->dev);
-	else
-		pdata = dev_get_platdata(&pdev->dev);
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "no setup data defined\n");
-		return -EINVAL;
-	}
-
-	platform_set_drvdata(pdev, flctl);
-	nand = &flctl->chip;
-	flctl_mtd = nand_to_mtd(nand);
-	nand_set_flash_node(nand, pdev->dev.of_node);
-	flctl_mtd->dev.parent = &pdev->dev;
-	flctl->pdev = pdev;
-	flctl->hwecc = pdata->has_hwecc;
-	flctl->holden = pdata->use_holden;
-	flctl->flcmncr_base = pdata->flcmncr_val;
-	flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
-
-	/* Set address of hardware control function */
-	/* 20 us command delay time */
-	nand->chip_delay = 20;
-
-	nand->read_byte = flctl_read_byte;
-	nand->read_word = flctl_read_word;
-	nand->write_buf = flctl_write_buf;
-	nand->read_buf = flctl_read_buf;
-	nand->select_chip = flctl_select_chip;
-	nand->cmdfunc = flctl_cmdfunc;
-	nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
-	nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
-
-	if (pdata->flcmncr_val & SEL_16BIT)
-		nand->options |= NAND_BUSWIDTH_16;
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_resume(&pdev->dev);
-
-	flctl_setup_dma(flctl);
-
-	ret = nand_scan_ident(flctl_mtd, 1, NULL);
-	if (ret)
-		goto err_chip;
-
-	if (nand->options & NAND_BUSWIDTH_16) {
-		/*
-		 * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
-		 * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
-		 * flctl->flcmncr_base to pdata->flcmncr_val.
-		 */
-		pdata->flcmncr_val |= SEL_16BIT;
-		flctl->flcmncr_base = pdata->flcmncr_val;
-	}
-
-	ret = flctl_chip_init_tail(flctl_mtd);
-	if (ret)
-		goto err_chip;
-
-	ret = nand_scan_tail(flctl_mtd);
-	if (ret)
-		goto err_chip;
-
-	ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
-
-	return 0;
-
-err_chip:
-	flctl_release_dma(flctl);
-	pm_runtime_disable(&pdev->dev);
-	return ret;
-}
-
-static int flctl_remove(struct platform_device *pdev)
-{
-	struct sh_flctl *flctl = platform_get_drvdata(pdev);
-
-	flctl_release_dma(flctl);
-	nand_release(nand_to_mtd(&flctl->chip));
-	pm_runtime_disable(&pdev->dev);
-
-	return 0;
-}
-
-static struct platform_driver flctl_driver = {
-	.remove		= flctl_remove,
-	.driver = {
-		.name	= "sh_flctl",
-		.of_match_table = of_match_ptr(of_flctl_match),
-	},
-};
-
-module_platform_driver_probe(flctl_driver, flctl_probe);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yoshihiro Shimoda");
-MODULE_DESCRIPTION("SuperH FLCTL driver");
-MODULE_ALIAS("platform:sh_flctl");
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
deleted file mode 100644
index f59c455d9f51..000000000000
--- a/drivers/mtd/nand/sharpsl.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * drivers/mtd/nand/sharpsl.c
- *
- *  Copyright (C) 2004 Richard Purdie
- *  Copyright (C) 2008 Dmitry Baryshkov
- *
- *  Based on Sharp's NAND driver sharp_sl.c
- *
- * 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/genhd.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/sharpsl.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-struct sharpsl_nand {
-	struct nand_chip	chip;
-
-	void __iomem		*io;
-};
-
-static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
-}
-
-/* register offset */
-#define ECCLPLB		0x00	/* line parity 7 - 0 bit */
-#define ECCLPUB		0x04	/* line parity 15 - 8 bit */
-#define ECCCP		0x08	/* column parity 5 - 0 bit */
-#define ECCCNTR		0x0C	/* ECC byte counter */
-#define ECCCLRR		0x10	/* cleare ECC */
-#define FLASHIO		0x14	/* Flash I/O */
-#define FLASHCTL	0x18	/* Flash Control */
-
-/* Flash control bit */
-#define FLRYBY		(1 << 5)
-#define FLCE1		(1 << 4)
-#define FLWP		(1 << 3)
-#define FLALE		(1 << 2)
-#define FLCLE		(1 << 1)
-#define FLCE0		(1 << 0)
-
-/*
- *	hardware specific access to control-lines
- *	ctrl:
- *	NAND_CNE: bit 0 -> ! bit 0 & 4
- *	NAND_CLE: bit 1 -> bit 1
- *	NAND_ALE: bit 2 -> bit 2
- *
- */
-static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigned int ctrl)
-{
-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		unsigned char bits = ctrl & 0x07;
-
-		bits |= (ctrl & 0x01) << 4;
-
-		bits ^= 0x11;
-
-		writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
-	}
-
-	if (cmd != NAND_CMD_NONE)
-		writeb(cmd, chip->IO_ADDR_W);
-}
-
-static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
-{
-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
-	return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
-}
-
-static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
-	writeb(0, sharpsl->io + ECCCLRR);
-}
-
-static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
-{
-	struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
-	ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
-	ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
-	ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
-	return readb(sharpsl->io + ECCCNTR) != 0;
-}
-
-/*
- * Main initialization routine
- */
-static int sharpsl_nand_probe(struct platform_device *pdev)
-{
-	struct nand_chip *this;
-	struct mtd_info *mtd;
-	struct resource *r;
-	int err = 0;
-	struct sharpsl_nand *sharpsl;
-	struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
-
-	if (!data) {
-		dev_err(&pdev->dev, "no platform data!\n");
-		return -EINVAL;
-	}
-
-	/* Allocate memory for MTD device structure and private data */
-	sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
-	if (!sharpsl)
-		return -ENOMEM;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		dev_err(&pdev->dev, "no io memory resource defined!\n");
-		err = -ENODEV;
-		goto err_get_res;
-	}
-
-	/* map physical address */
-	sharpsl->io = ioremap(r->start, resource_size(r));
-	if (!sharpsl->io) {
-		dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
-		err = -EIO;
-		goto err_ioremap;
-	}
-
-	/* Get pointer to private data */
-	this = (struct nand_chip *)(&sharpsl->chip);
-
-	/* Link the private data with the MTD structure */
-	mtd = nand_to_mtd(this);
-	mtd->dev.parent = &pdev->dev;
-	mtd_set_ooblayout(mtd, data->ecc_layout);
-
-	platform_set_drvdata(pdev, sharpsl);
-
-	/*
-	 * PXA initialize
-	 */
-	writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
-
-	/* Set address of NAND IO lines */
-	this->IO_ADDR_R = sharpsl->io + FLASHIO;
-	this->IO_ADDR_W = sharpsl->io + FLASHIO;
-	/* Set address of hardware control function */
-	this->cmd_ctrl = sharpsl_nand_hwcontrol;
-	this->dev_ready = sharpsl_nand_dev_ready;
-	/* 15 us command delay time */
-	this->chip_delay = 15;
-	/* set eccmode using hardware ECC */
-	this->ecc.mode = NAND_ECC_HW;
-	this->ecc.size = 256;
-	this->ecc.bytes = 3;
-	this->ecc.strength = 1;
-	this->badblock_pattern = data->badblock_pattern;
-	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
-	this->ecc.calculate = sharpsl_nand_calculate_ecc;
-	this->ecc.correct = nand_correct_data;
-
-	/* Scan to find existence of the device */
-	err = nand_scan(mtd, 1);
-	if (err)
-		goto err_scan;
-
-	/* Register the partitions */
-	mtd->name = "sharpsl-nand";
-
-	err = mtd_device_parse_register(mtd, data->part_parsers, NULL,
-					data->partitions, data->nr_partitions);
-	if (err)
-		goto err_add;
-
-	/* Return happy */
-	return 0;
-
-err_add:
-	nand_release(mtd);
-
-err_scan:
-	iounmap(sharpsl->io);
-err_ioremap:
-err_get_res:
-	kfree(sharpsl);
-	return err;
-}
-
-/*
- * Clean up routine
- */
-static int sharpsl_nand_remove(struct platform_device *pdev)
-{
-	struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
-
-	/* Release resources, unregister device */
-	nand_release(nand_to_mtd(&sharpsl->chip));
-
-	iounmap(sharpsl->io);
-
-	/* Free the MTD device structure */
-	kfree(sharpsl);
-
-	return 0;
-}
-
-static struct platform_driver sharpsl_nand_driver = {
-	.driver = {
-		.name	= "sharpsl-nand",
-	},
-	.probe		= sharpsl_nand_probe,
-	.remove		= sharpsl_nand_remove,
-};
-
-module_platform_driver(sharpsl_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
-MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c
deleted file mode 100644
index c378705c6e2b..000000000000
--- a/drivers/mtd/nand/sm_common.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright © 2009 - Maxim Levitsky
- * Common routines & support for xD format
- *
- * 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/kernel.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/module.h>
-#include <linux/sizes.h>
-#include "sm_common.h"
-
-static int oob_sm_ooblayout_ecc(struct mtd_info *mtd, int section,
-				struct mtd_oob_region *oobregion)
-{
-	if (section > 1)
-		return -ERANGE;
-
-	oobregion->length = 3;
-	oobregion->offset = ((section + 1) * 8) - 3;
-
-	return 0;
-}
-
-static int oob_sm_ooblayout_free(struct mtd_info *mtd, int section,
-				 struct mtd_oob_region *oobregion)
-{
-	switch (section) {
-	case 0:
-		/* reserved */
-		oobregion->offset = 0;
-		oobregion->length = 4;
-		break;
-	case 1:
-		/* LBA1 */
-		oobregion->offset = 6;
-		oobregion->length = 2;
-		break;
-	case 2:
-		/* LBA2 */
-		oobregion->offset = 11;
-		oobregion->length = 2;
-		break;
-	default:
-		return -ERANGE;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops oob_sm_ops = {
-	.ecc = oob_sm_ooblayout_ecc,
-	.free = oob_sm_ooblayout_free,
-};
-
-/* NOTE: This layout is is not compatabable with SmartMedia, */
-/* because the 256 byte devices have page depenent oob layout */
-/* However it does preserve the bad block markers */
-/* If you use smftl, it will bypass this and work correctly */
-/* If you not, then you break SmartMedia compliance anyway */
-
-static int oob_sm_small_ooblayout_ecc(struct mtd_info *mtd, int section,
-				      struct mtd_oob_region *oobregion)
-{
-	if (section)
-		return -ERANGE;
-
-	oobregion->length = 3;
-	oobregion->offset = 0;
-
-	return 0;
-}
-
-static int oob_sm_small_ooblayout_free(struct mtd_info *mtd, int section,
-				       struct mtd_oob_region *oobregion)
-{
-	switch (section) {
-	case 0:
-		/* reserved */
-		oobregion->offset = 3;
-		oobregion->length = 2;
-		break;
-	case 1:
-		/* LBA1 */
-		oobregion->offset = 6;
-		oobregion->length = 2;
-		break;
-	default:
-		return -ERANGE;
-	}
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops oob_sm_small_ops = {
-	.ecc = oob_sm_small_ooblayout_ecc,
-	.free = oob_sm_small_ooblayout_free,
-};
-
-static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-	struct mtd_oob_ops ops;
-	struct sm_oob oob;
-	int ret;
-
-	memset(&oob, -1, SM_OOB_SIZE);
-	oob.block_status = 0x0F;
-
-	/* As long as this function is called on erase block boundaries
-		it will work correctly for 256 byte nand */
-	ops.mode = MTD_OPS_PLACE_OOB;
-	ops.ooboffs = 0;
-	ops.ooblen = mtd->oobsize;
-	ops.oobbuf = (void *)&oob;
-	ops.datbuf = NULL;
-
-
-	ret = mtd_write_oob(mtd, ofs, &ops);
-	if (ret < 0 || ops.oobretlen != SM_OOB_SIZE) {
-		printk(KERN_NOTICE
-			"sm_common: can't mark sector at %i as bad\n",
-								(int)ofs);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
-	LEGACY_ID_NAND("SmartMedia 2MiB 3,3V ROM",   0x5d, 2,   SZ_8K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V",       0xe3, 4,   SZ_8K, 0),
-	LEGACY_ID_NAND("SmartMedia 4MiB 3,3/5V",     0xe5, 4,   SZ_8K, 0),
-	LEGACY_ID_NAND("SmartMedia 4MiB 5V",         0x6b, 4,   SZ_8K, 0),
-	LEGACY_ID_NAND("SmartMedia 4MiB 3,3V ROM",   0xd5, 4,   SZ_8K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V",       0xe6, 8,   SZ_8K, 0),
-	LEGACY_ID_NAND("SmartMedia 8MiB 3,3V ROM",   0xd6, 8,   SZ_8K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V",      0x73, 16,  SZ_16K, 0),
-	LEGACY_ID_NAND("SmartMedia 16MiB 3,3V ROM",  0x57, 16,  SZ_16K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V",      0x75, 32,  SZ_16K, 0),
-	LEGACY_ID_NAND("SmartMedia 32MiB 3,3V ROM",  0x58, 32,  SZ_16K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V",      0x76, 64,  SZ_16K, 0),
-	LEGACY_ID_NAND("SmartMedia 64MiB 3,3V ROM",  0xd9, 64,  SZ_16K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V",     0x79, 128, SZ_16K, 0),
-	LEGACY_ID_NAND("SmartMedia 128MiB 3,3V ROM", 0xda, 128, SZ_16K, NAND_ROM),
-	LEGACY_ID_NAND("SmartMedia 256MiB 3, 3V",    0x71, 256, SZ_16K, 0),
-	LEGACY_ID_NAND("SmartMedia 256MiB 3,3V ROM", 0x5b, 256, SZ_16K, NAND_ROM),
-	{NULL}
-};
-
-static struct nand_flash_dev nand_xd_flash_ids[] = {
-	LEGACY_ID_NAND("xD 16MiB 3,3V",  0x73, 16,   SZ_16K, 0),
-	LEGACY_ID_NAND("xD 32MiB 3,3V",  0x75, 32,   SZ_16K, 0),
-	LEGACY_ID_NAND("xD 64MiB 3,3V",  0x76, 64,   SZ_16K, 0),
-	LEGACY_ID_NAND("xD 128MiB 3,3V", 0x79, 128,  SZ_16K, 0),
-	LEGACY_ID_NAND("xD 256MiB 3,3V", 0x71, 256,  SZ_16K, NAND_BROKEN_XD),
-	LEGACY_ID_NAND("xD 512MiB 3,3V", 0xdc, 512,  SZ_16K, NAND_BROKEN_XD),
-	LEGACY_ID_NAND("xD 1GiB 3,3V",   0xd3, 1024, SZ_16K, NAND_BROKEN_XD),
-	LEGACY_ID_NAND("xD 2GiB 3,3V",   0xd5, 2048, SZ_16K, NAND_BROKEN_XD),
-	{NULL}
-};
-
-int sm_register_device(struct mtd_info *mtd, int smartmedia)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	chip->options |= NAND_SKIP_BBTSCAN;
-
-	/* Scan for card properties */
-	ret = nand_scan_ident(mtd, 1, smartmedia ?
-		nand_smartmedia_flash_ids : nand_xd_flash_ids);
-
-	if (ret)
-		return ret;
-
-	/* Bad block marker position */
-	chip->badblockpos = 0x05;
-	chip->badblockbits = 7;
-	chip->block_markbad = sm_block_markbad;
-
-	/* ECC layout */
-	if (mtd->writesize == SM_SECTOR_SIZE)
-		mtd_set_ooblayout(mtd, &oob_sm_ops);
-	else if (mtd->writesize == SM_SMALL_PAGE)
-		mtd_set_ooblayout(mtd, &oob_sm_small_ops);
-	else
-		return -ENODEV;
-
-	ret = nand_scan_tail(mtd);
-
-	if (ret)
-		return ret;
-
-	return mtd_device_register(mtd, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(sm_register_device);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
-MODULE_DESCRIPTION("Common SmartMedia/xD functions");
diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/sm_common.h
deleted file mode 100644
index 1581671b05ae..000000000000
--- a/drivers/mtd/nand/sm_common.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright © 2009 - Maxim Levitsky
- * Common routines & support for SmartMedia/xD format
- *
- * 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/bitops.h>
-#include <linux/mtd/mtd.h>
-
-/* Full oob structure as written on the flash */
-struct sm_oob {
-	uint32_t reserved;
-	uint8_t data_status;
-	uint8_t block_status;
-	uint8_t lba_copy1[2];
-	uint8_t ecc2[3];
-	uint8_t lba_copy2[2];
-	uint8_t ecc1[3];
-} __packed;
-
-
-/* one sector is always 512 bytes, but it can consist of two nand pages */
-#define SM_SECTOR_SIZE		512
-
-/* oob area is also 16 bytes, but might be from two pages */
-#define SM_OOB_SIZE		16
-
-/* This is maximum zone size, and all devices that have more that one zone
-   have this size */
-#define SM_MAX_ZONE_SIZE 	1024
-
-/* support for small page nand */
-#define SM_SMALL_PAGE 		256
-#define SM_SMALL_OOB_SIZE	8
-
-
-int sm_register_device(struct mtd_info *mtd, int smartmedia);
-
-
-static inline int sm_sector_valid(struct sm_oob *oob)
-{
-	return hweight16(oob->data_status) >= 5;
-}
-
-static inline int sm_block_valid(struct sm_oob *oob)
-{
-	return hweight16(oob->block_status) >= 7;
-}
-
-static inline int sm_block_erased(struct sm_oob *oob)
-{
-	static const uint32_t erased_pattern[4] = {
-		0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
-
-	/* First test for erased block */
-	if (!memcmp(oob, erased_pattern, sizeof(*oob)))
-		return 1;
-	return 0;
-}
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
deleted file mode 100644
index 575997d0ef8a..000000000000
--- a/drivers/mtd/nand/socrates_nand.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * drivers/mtd/nand/socrates_nand.c
- *
- *  Copyright © 2008 Ilya Yanok, Emcraft Systems
- *
- *
- * 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/slab.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-
-#define FPGA_NAND_CMD_MASK		(0x7 << 28)
-#define FPGA_NAND_CMD_COMMAND		(0x0 << 28)
-#define FPGA_NAND_CMD_ADDR		(0x1 << 28)
-#define FPGA_NAND_CMD_READ		(0x2 << 28)
-#define FPGA_NAND_CMD_WRITE		(0x3 << 28)
-#define FPGA_NAND_BUSY			(0x1 << 15)
-#define FPGA_NAND_ENABLE		(0x1 << 31)
-#define FPGA_NAND_DATA_SHIFT		16
-
-struct socrates_nand_host {
-	struct nand_chip	nand_chip;
-	void __iomem		*io_base;
-	struct device		*dev;
-};
-
-/**
- * socrates_nand_write_buf -  write buffer to chip
- * @mtd:	MTD device structure
- * @buf:	data buffer
- * @len:	number of bytes to write
- */
-static void socrates_nand_write_buf(struct mtd_info *mtd,
-		const uint8_t *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct socrates_nand_host *host = nand_get_controller_data(this);
-
-	for (i = 0; i < len; i++) {
-		out_be32(host->io_base, FPGA_NAND_ENABLE |
-				FPGA_NAND_CMD_WRITE |
-				(buf[i] << FPGA_NAND_DATA_SHIFT));
-	}
-}
-
-/**
- * socrates_nand_read_buf -  read chip data into buffer
- * @mtd:	MTD device structure
- * @buf:	buffer to store date
- * @len:	number of bytes to read
- */
-static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	int i;
-	struct nand_chip *this = mtd_to_nand(mtd);
-	struct socrates_nand_host *host = nand_get_controller_data(this);
-	uint32_t val;
-
-	val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;
-
-	out_be32(host->io_base, val);
-	for (i = 0; i < len; i++) {
-		buf[i] = (in_be32(host->io_base) >>
-				FPGA_NAND_DATA_SHIFT) & 0xff;
-	}
-}
-
-/**
- * socrates_nand_read_byte -  read one byte from the chip
- * @mtd:	MTD device structure
- */
-static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
-{
-	uint8_t byte;
-	socrates_nand_read_buf(mtd, &byte, sizeof(byte));
-	return byte;
-}
-
-/**
- * socrates_nand_read_word -  read one word from the chip
- * @mtd:	MTD device structure
- */
-static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
-{
-	uint16_t word;
-	socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
-	return word;
-}
-
-/*
- * Hardware specific access to control-lines
- */
-static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-		unsigned int ctrl)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
-	uint32_t val;
-
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		val = FPGA_NAND_CMD_COMMAND;
-	else
-		val = FPGA_NAND_CMD_ADDR;
-
-	if (ctrl & NAND_NCE)
-		val |= FPGA_NAND_ENABLE;
-
-	val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT;
-
-	out_be32(host->io_base, val);
-}
-
-/*
- * Read the Device Ready pin.
- */
-static int socrates_nand_device_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *nand_chip = mtd_to_nand(mtd);
-	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
-
-	if (in_be32(host->io_base) & FPGA_NAND_BUSY)
-		return 0; /* busy */
-	return 1;
-}
-
-/*
- * Probe for the NAND device.
- */
-static int socrates_nand_probe(struct platform_device *ofdev)
-{
-	struct socrates_nand_host *host;
-	struct mtd_info *mtd;
-	struct nand_chip *nand_chip;
-	int res;
-
-	/* Allocate memory for the device structure (and zero it) */
-	host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	host->io_base = of_iomap(ofdev->dev.of_node, 0);
-	if (host->io_base == NULL) {
-		dev_err(&ofdev->dev, "ioremap failed\n");
-		return -EIO;
-	}
-
-	nand_chip = &host->nand_chip;
-	mtd = nand_to_mtd(nand_chip);
-	host->dev = &ofdev->dev;
-
-	/* link the private data structures */
-	nand_set_controller_data(nand_chip, host);
-	nand_set_flash_node(nand_chip, ofdev->dev.of_node);
-	mtd->name = "socrates_nand";
-	mtd->dev.parent = &ofdev->dev;
-
-	/*should never be accessed directly */
-	nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
-	nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
-
-	nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
-	nand_chip->read_byte = socrates_nand_read_byte;
-	nand_chip->read_word = socrates_nand_read_word;
-	nand_chip->write_buf = socrates_nand_write_buf;
-	nand_chip->read_buf = socrates_nand_read_buf;
-	nand_chip->dev_ready = socrates_nand_device_ready;
-
-	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
-	nand_chip->ecc.algo = NAND_ECC_HAMMING;
-
-	/* TODO: I have no idea what real delay is. */
-	nand_chip->chip_delay = 20;		/* 20us command delay time */
-
-	dev_set_drvdata(&ofdev->dev, host);
-
-	res = nand_scan(mtd, 1);
-	if (res)
-		goto out;
-
-	res = mtd_device_register(mtd, NULL, 0);
-	if (!res)
-		return res;
-
-	nand_release(mtd);
-
-out:
-	iounmap(host->io_base);
-	return res;
-}
-
-/*
- * Remove a NAND device.
- */
-static int socrates_nand_remove(struct platform_device *ofdev)
-{
-	struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
-	struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
-
-	nand_release(mtd);
-
-	iounmap(host->io_base);
-
-	return 0;
-}
-
-static const struct of_device_id socrates_nand_match[] =
-{
-	{
-		.compatible   = "abb,socrates-nand",
-	},
-	{},
-};
-
-MODULE_DEVICE_TABLE(of, socrates_nand_match);
-
-static struct platform_driver socrates_nand_driver = {
-	.driver = {
-		.name = "socrates_nand",
-		.of_match_table = socrates_nand_match,
-	},
-	.probe		= socrates_nand_probe,
-	.remove		= socrates_nand_remove,
-};
-
-module_platform_driver(socrates_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ilya Yanok");
-MODULE_DESCRIPTION("NAND driver for Socrates board");
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
deleted file mode 100644
index f5a55c63935c..000000000000
--- a/drivers/mtd/nand/sunxi_nand.c
+++ /dev/null
@@ -1,2321 +0,0 @@
-/*
- * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
- *
- * Derived from:
- *	https://github.com/yuq/sunxi-nfc-mtd
- *	Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
- *
- *	https://github.com/hno/Allwinner-Info
- *	Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
- *
- *	Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
- *	Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/dmaengine.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/iopoll.h>
-#include <linux/reset.h>
-
-#define NFC_REG_CTL		0x0000
-#define NFC_REG_ST		0x0004
-#define NFC_REG_INT		0x0008
-#define NFC_REG_TIMING_CTL	0x000C
-#define NFC_REG_TIMING_CFG	0x0010
-#define NFC_REG_ADDR_LOW	0x0014
-#define NFC_REG_ADDR_HIGH	0x0018
-#define NFC_REG_SECTOR_NUM	0x001C
-#define NFC_REG_CNT		0x0020
-#define NFC_REG_CMD		0x0024
-#define NFC_REG_RCMD_SET	0x0028
-#define NFC_REG_WCMD_SET	0x002C
-#define NFC_REG_IO_DATA		0x0030
-#define NFC_REG_ECC_CTL		0x0034
-#define NFC_REG_ECC_ST		0x0038
-#define NFC_REG_DEBUG		0x003C
-#define NFC_REG_ECC_ERR_CNT(x)	((0x0040 + (x)) & ~0x3)
-#define NFC_REG_USER_DATA(x)	(0x0050 + ((x) * 4))
-#define NFC_REG_SPARE_AREA	0x00A0
-#define NFC_REG_PAT_ID		0x00A4
-#define NFC_RAM0_BASE		0x0400
-#define NFC_RAM1_BASE		0x0800
-
-/* define bit use in NFC_CTL */
-#define NFC_EN			BIT(0)
-#define NFC_RESET		BIT(1)
-#define NFC_BUS_WIDTH_MSK	BIT(2)
-#define NFC_BUS_WIDTH_8		(0 << 2)
-#define NFC_BUS_WIDTH_16	(1 << 2)
-#define NFC_RB_SEL_MSK		BIT(3)
-#define NFC_RB_SEL(x)		((x) << 3)
-#define NFC_CE_SEL_MSK		GENMASK(26, 24)
-#define NFC_CE_SEL(x)		((x) << 24)
-#define NFC_CE_CTL		BIT(6)
-#define NFC_PAGE_SHIFT_MSK	GENMASK(11, 8)
-#define NFC_PAGE_SHIFT(x)	(((x) < 10 ? 0 : (x) - 10) << 8)
-#define NFC_SAM			BIT(12)
-#define NFC_RAM_METHOD		BIT(14)
-#define NFC_DEBUG_CTL		BIT(31)
-
-/* define bit use in NFC_ST */
-#define NFC_RB_B2R		BIT(0)
-#define NFC_CMD_INT_FLAG	BIT(1)
-#define NFC_DMA_INT_FLAG	BIT(2)
-#define NFC_CMD_FIFO_STATUS	BIT(3)
-#define NFC_STA			BIT(4)
-#define NFC_NATCH_INT_FLAG	BIT(5)
-#define NFC_RB_STATE(x)		BIT(x + 8)
-
-/* define bit use in NFC_INT */
-#define NFC_B2R_INT_ENABLE	BIT(0)
-#define NFC_CMD_INT_ENABLE	BIT(1)
-#define NFC_DMA_INT_ENABLE	BIT(2)
-#define NFC_INT_MASK		(NFC_B2R_INT_ENABLE | \
-				 NFC_CMD_INT_ENABLE | \
-				 NFC_DMA_INT_ENABLE)
-
-/* define bit use in NFC_TIMING_CTL */
-#define NFC_TIMING_CTL_EDO	BIT(8)
-
-/* define NFC_TIMING_CFG register layout */
-#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD)		\
-	(((tWB) & 0x3) | (((tADL) & 0x3) << 2) |		\
-	(((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) |		\
-	(((tCAD) & 0x7) << 8))
-
-/* define bit use in NFC_CMD */
-#define NFC_CMD_LOW_BYTE_MSK	GENMASK(7, 0)
-#define NFC_CMD_HIGH_BYTE_MSK	GENMASK(15, 8)
-#define NFC_CMD(x)		(x)
-#define NFC_ADR_NUM_MSK		GENMASK(18, 16)
-#define NFC_ADR_NUM(x)		(((x) - 1) << 16)
-#define NFC_SEND_ADR		BIT(19)
-#define NFC_ACCESS_DIR		BIT(20)
-#define NFC_DATA_TRANS		BIT(21)
-#define NFC_SEND_CMD1		BIT(22)
-#define NFC_WAIT_FLAG		BIT(23)
-#define NFC_SEND_CMD2		BIT(24)
-#define NFC_SEQ			BIT(25)
-#define NFC_DATA_SWAP_METHOD	BIT(26)
-#define NFC_ROW_AUTO_INC	BIT(27)
-#define NFC_SEND_CMD3		BIT(28)
-#define NFC_SEND_CMD4		BIT(29)
-#define NFC_CMD_TYPE_MSK	GENMASK(31, 30)
-#define NFC_NORMAL_OP		(0 << 30)
-#define NFC_ECC_OP		(1 << 30)
-#define NFC_PAGE_OP		(2 << 30)
-
-/* define bit use in NFC_RCMD_SET */
-#define NFC_READ_CMD_MSK	GENMASK(7, 0)
-#define NFC_RND_READ_CMD0_MSK	GENMASK(15, 8)
-#define NFC_RND_READ_CMD1_MSK	GENMASK(23, 16)
-
-/* define bit use in NFC_WCMD_SET */
-#define NFC_PROGRAM_CMD_MSK	GENMASK(7, 0)
-#define NFC_RND_WRITE_CMD_MSK	GENMASK(15, 8)
-#define NFC_READ_CMD0_MSK	GENMASK(23, 16)
-#define NFC_READ_CMD1_MSK	GENMASK(31, 24)
-
-/* define bit use in NFC_ECC_CTL */
-#define NFC_ECC_EN		BIT(0)
-#define NFC_ECC_PIPELINE	BIT(3)
-#define NFC_ECC_EXCEPTION	BIT(4)
-#define NFC_ECC_BLOCK_SIZE_MSK	BIT(5)
-#define NFC_ECC_BLOCK_512	BIT(5)
-#define NFC_RANDOM_EN		BIT(9)
-#define NFC_RANDOM_DIRECTION	BIT(10)
-#define NFC_ECC_MODE_MSK	GENMASK(15, 12)
-#define NFC_ECC_MODE(x)		((x) << 12)
-#define NFC_RANDOM_SEED_MSK	GENMASK(30, 16)
-#define NFC_RANDOM_SEED(x)	((x) << 16)
-
-/* define bit use in NFC_ECC_ST */
-#define NFC_ECC_ERR(x)		BIT(x)
-#define NFC_ECC_ERR_MSK		GENMASK(15, 0)
-#define NFC_ECC_PAT_FOUND(x)	BIT(x + 16)
-#define NFC_ECC_ERR_CNT(b, x)	(((x) >> (((b) % 4) * 8)) & 0xff)
-
-#define NFC_DEFAULT_TIMEOUT_MS	1000
-
-#define NFC_SRAM_SIZE		1024
-
-#define NFC_MAX_CS		7
-
-/*
- * Ready/Busy detection type: describes the Ready/Busy detection modes
- *
- * @RB_NONE:	no external detection available, rely on STATUS command
- *		and software timeouts
- * @RB_NATIVE:	use sunxi NAND controller Ready/Busy support. The Ready/Busy
- *		pin of the NAND flash chip must be connected to one of the
- *		native NAND R/B pins (those which can be muxed to the NAND
- *		Controller)
- * @RB_GPIO:	use a simple GPIO to handle Ready/Busy status. The Ready/Busy
- *		pin of the NAND flash chip must be connected to a GPIO capable
- *		pin.
- */
-enum sunxi_nand_rb_type {
-	RB_NONE,
-	RB_NATIVE,
-	RB_GPIO,
-};
-
-/*
- * Ready/Busy structure: stores information related to Ready/Busy detection
- *
- * @type:	the Ready/Busy detection mode
- * @info:	information related to the R/B detection mode. Either a gpio
- *		id or a native R/B id (those supported by the NAND controller).
- */
-struct sunxi_nand_rb {
-	enum sunxi_nand_rb_type type;
-	union {
-		int gpio;
-		int nativeid;
-	} info;
-};
-
-/*
- * Chip Select structure: stores information related to NAND Chip Select
- *
- * @cs:		the NAND CS id used to communicate with a NAND Chip
- * @rb:		the Ready/Busy description
- */
-struct sunxi_nand_chip_sel {
-	u8 cs;
-	struct sunxi_nand_rb rb;
-};
-
-/*
- * sunxi HW ECC infos: stores information related to HW ECC support
- *
- * @mode:	the sunxi ECC mode field deduced from ECC requirements
- */
-struct sunxi_nand_hw_ecc {
-	int mode;
-};
-
-/*
- * NAND chip structure: stores NAND chip device related information
- *
- * @node:		used to store NAND chips into a list
- * @nand:		base NAND chip structure
- * @mtd:		base MTD structure
- * @clk_rate:		clk_rate required for this NAND chip
- * @timing_cfg		TIMING_CFG register value for this NAND chip
- * @selected:		current active CS
- * @nsels:		number of CS lines required by the NAND chip
- * @sels:		array of CS lines descriptions
- */
-struct sunxi_nand_chip {
-	struct list_head node;
-	struct nand_chip nand;
-	unsigned long clk_rate;
-	u32 timing_cfg;
-	u32 timing_ctl;
-	int selected;
-	int addr_cycles;
-	u32 addr[2];
-	int cmd_cycles;
-	u8 cmd[2];
-	int nsels;
-	struct sunxi_nand_chip_sel sels[0];
-};
-
-static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
-{
-	return container_of(nand, struct sunxi_nand_chip, nand);
-}
-
-/*
- * NAND Controller structure: stores sunxi NAND controller information
- *
- * @controller:		base controller structure
- * @dev:		parent device (used to print error messages)
- * @regs:		NAND controller registers
- * @ahb_clk:		NAND Controller AHB clock
- * @mod_clk:		NAND Controller mod clock
- * @assigned_cs:	bitmask describing already assigned CS lines
- * @clk_rate:		NAND controller current clock rate
- * @chips:		a list containing all the NAND chips attached to
- *			this NAND controller
- * @complete:		a completion object used to wait for NAND
- *			controller events
- */
-struct sunxi_nfc {
-	struct nand_hw_control controller;
-	struct device *dev;
-	void __iomem *regs;
-	struct clk *ahb_clk;
-	struct clk *mod_clk;
-	struct reset_control *reset;
-	unsigned long assigned_cs;
-	unsigned long clk_rate;
-	struct list_head chips;
-	struct completion complete;
-	struct dma_chan *dmac;
-};
-
-static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
-{
-	return container_of(ctrl, struct sunxi_nfc, controller);
-}
-
-static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
-{
-	struct sunxi_nfc *nfc = dev_id;
-	u32 st = readl(nfc->regs + NFC_REG_ST);
-	u32 ien = readl(nfc->regs + NFC_REG_INT);
-
-	if (!(ien & st))
-		return IRQ_NONE;
-
-	if ((ien & st) == ien)
-		complete(&nfc->complete);
-
-	writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
-	writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT);
-
-	return IRQ_HANDLED;
-}
-
-static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
-				 bool use_polling, unsigned int timeout_ms)
-{
-	int ret;
-
-	if (events & ~NFC_INT_MASK)
-		return -EINVAL;
-
-	if (!timeout_ms)
-		timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
-
-	if (!use_polling) {
-		init_completion(&nfc->complete);
-
-		writel(events, nfc->regs + NFC_REG_INT);
-
-		ret = wait_for_completion_timeout(&nfc->complete,
-						msecs_to_jiffies(timeout_ms));
-		if (!ret)
-			ret = -ETIMEDOUT;
-		else
-			ret = 0;
-
-		writel(0, nfc->regs + NFC_REG_INT);
-	} else {
-		u32 status;
-
-		ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
-					 (status & events) == events, 1,
-					 timeout_ms * 1000);
-	}
-
-	writel(events & NFC_INT_MASK, nfc->regs + NFC_REG_ST);
-
-	if (ret)
-		dev_err(nfc->dev, "wait interrupt timedout\n");
-
-	return ret;
-}
-
-static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
-{
-	u32 status;
-	int ret;
-
-	ret = readl_poll_timeout(nfc->regs + NFC_REG_ST, status,
-				 !(status & NFC_CMD_FIFO_STATUS), 1,
-				 NFC_DEFAULT_TIMEOUT_MS * 1000);
-	if (ret)
-		dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
-
-	return ret;
-}
-
-static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
-{
-	u32 ctl;
-	int ret;
-
-	writel(0, nfc->regs + NFC_REG_ECC_CTL);
-	writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
-
-	ret = readl_poll_timeout(nfc->regs + NFC_REG_CTL, ctl,
-				 !(ctl & NFC_RESET), 1,
-				 NFC_DEFAULT_TIMEOUT_MS * 1000);
-	if (ret)
-		dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
-
-	return ret;
-}
-
-static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
-				    int chunksize, int nchunks,
-				    enum dma_data_direction ddir,
-				    struct scatterlist *sg)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct dma_async_tx_descriptor *dmad;
-	enum dma_transfer_direction tdir;
-	dma_cookie_t dmat;
-	int ret;
-
-	if (ddir == DMA_FROM_DEVICE)
-		tdir = DMA_DEV_TO_MEM;
-	else
-		tdir = DMA_MEM_TO_DEV;
-
-	sg_init_one(sg, buf, nchunks * chunksize);
-	ret = dma_map_sg(nfc->dev, sg, 1, ddir);
-	if (!ret)
-		return -ENOMEM;
-
-	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
-	if (!dmad) {
-		ret = -EINVAL;
-		goto err_unmap_buf;
-	}
-
-	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
-	       nfc->regs + NFC_REG_CTL);
-	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
-	writel(chunksize, nfc->regs + NFC_REG_CNT);
-	dmat = dmaengine_submit(dmad);
-
-	ret = dma_submit_error(dmat);
-	if (ret)
-		goto err_clr_dma_flag;
-
-	return 0;
-
-err_clr_dma_flag:
-	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
-	       nfc->regs + NFC_REG_CTL);
-
-err_unmap_buf:
-	dma_unmap_sg(nfc->dev, sg, 1, ddir);
-	return ret;
-}
-
-static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
-				     enum dma_data_direction ddir,
-				     struct scatterlist *sg)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-
-	dma_unmap_sg(nfc->dev, sg, 1, ddir);
-	writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
-	       nfc->regs + NFC_REG_CTL);
-}
-
-static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	struct sunxi_nand_rb *rb;
-	int ret;
-
-	if (sunxi_nand->selected < 0)
-		return 0;
-
-	rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
-
-	switch (rb->type) {
-	case RB_NATIVE:
-		ret = !!(readl(nfc->regs + NFC_REG_ST) &
-			 NFC_RB_STATE(rb->info.nativeid));
-		break;
-	case RB_GPIO:
-		ret = gpio_get_value(rb->info.gpio);
-		break;
-	case RB_NONE:
-	default:
-		ret = 0;
-		dev_err(nfc->dev, "cannot check R/B NAND status!\n");
-		break;
-	}
-
-	return ret;
-}
-
-static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	struct sunxi_nand_chip_sel *sel;
-	u32 ctl;
-
-	if (chip > 0 && chip >= sunxi_nand->nsels)
-		return;
-
-	if (chip == sunxi_nand->selected)
-		return;
-
-	ctl = readl(nfc->regs + NFC_REG_CTL) &
-	      ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
-
-	if (chip >= 0) {
-		sel = &sunxi_nand->sels[chip];
-
-		ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
-		       NFC_PAGE_SHIFT(nand->page_shift);
-		if (sel->rb.type == RB_NONE) {
-			nand->dev_ready = NULL;
-		} else {
-			nand->dev_ready = sunxi_nfc_dev_ready;
-			if (sel->rb.type == RB_NATIVE)
-				ctl |= NFC_RB_SEL(sel->rb.info.nativeid);
-		}
-
-		writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
-
-		if (nfc->clk_rate != sunxi_nand->clk_rate) {
-			clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
-			nfc->clk_rate = sunxi_nand->clk_rate;
-		}
-	}
-
-	writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
-	writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
-	writel(ctl, nfc->regs + NFC_REG_CTL);
-
-	sunxi_nand->selected = chip;
-}
-
-static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	int ret;
-	int cnt;
-	int offs = 0;
-	u32 tmp;
-
-	while (len > offs) {
-		bool poll = false;
-
-		cnt = min(len - offs, NFC_SRAM_SIZE);
-
-		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-		if (ret)
-			break;
-
-		writel(cnt, nfc->regs + NFC_REG_CNT);
-		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
-		writel(tmp, nfc->regs + NFC_REG_CMD);
-
-		/* Arbitrary limit for polling mode */
-		if (cnt < 64)
-			poll = true;
-
-		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
-		if (ret)
-			break;
-
-		if (buf)
-			memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
-				      cnt);
-		offs += cnt;
-	}
-}
-
-static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-				int len)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	int ret;
-	int cnt;
-	int offs = 0;
-	u32 tmp;
-
-	while (len > offs) {
-		bool poll = false;
-
-		cnt = min(len - offs, NFC_SRAM_SIZE);
-
-		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-		if (ret)
-			break;
-
-		writel(cnt, nfc->regs + NFC_REG_CNT);
-		memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
-		tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
-		      NFC_ACCESS_DIR;
-		writel(tmp, nfc->regs + NFC_REG_CMD);
-
-		/* Arbitrary limit for polling mode */
-		if (cnt < 64)
-			poll = true;
-
-		ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
-		if (ret)
-			break;
-
-		offs += cnt;
-	}
-}
-
-static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
-{
-	uint8_t ret;
-
-	sunxi_nfc_read_buf(mtd, &ret, 1);
-
-	return ret;
-}
-
-static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
-			       unsigned int ctrl)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	int ret;
-
-	if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
-	    !(ctrl & (NAND_CLE | NAND_ALE))) {
-		u32 cmd = 0;
-
-		if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
-			return;
-
-		if (sunxi_nand->cmd_cycles--)
-			cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
-
-		if (sunxi_nand->cmd_cycles--) {
-			cmd |= NFC_SEND_CMD2;
-			writel(sunxi_nand->cmd[1],
-			       nfc->regs + NFC_REG_RCMD_SET);
-		}
-
-		sunxi_nand->cmd_cycles = 0;
-
-		if (sunxi_nand->addr_cycles) {
-			cmd |= NFC_SEND_ADR |
-			       NFC_ADR_NUM(sunxi_nand->addr_cycles);
-			writel(sunxi_nand->addr[0],
-			       nfc->regs + NFC_REG_ADDR_LOW);
-		}
-
-		if (sunxi_nand->addr_cycles > 4)
-			writel(sunxi_nand->addr[1],
-			       nfc->regs + NFC_REG_ADDR_HIGH);
-
-		ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-		if (ret)
-			return;
-
-		writel(cmd, nfc->regs + NFC_REG_CMD);
-		sunxi_nand->addr[0] = 0;
-		sunxi_nand->addr[1] = 0;
-		sunxi_nand->addr_cycles = 0;
-		sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
-	}
-
-	if (ctrl & NAND_CLE) {
-		sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
-	} else if (ctrl & NAND_ALE) {
-		sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
-				dat << ((sunxi_nand->addr_cycles % 4) * 8);
-		sunxi_nand->addr_cycles++;
-	}
-}
-
-/* These seed values have been extracted from Allwinner's BSP */
-static const u16 sunxi_nfc_randomizer_page_seeds[] = {
-	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
-	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
-	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
-	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
-	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
-	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
-	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
-	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
-	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
-	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
-	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
-	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
-	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
-	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
-	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
-	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
-};
-
-/*
- * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
- * have been generated using
- * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
- * the randomizer engine does internally before de/scrambling OOB data.
- *
- * Those tables are statically defined to avoid calculating randomizer state
- * at runtime.
- */
-static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
-	0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
-	0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
-	0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
-	0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
-	0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
-	0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
-	0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
-	0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
-	0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
-	0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
-	0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
-	0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
-	0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
-	0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
-	0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
-	0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
-};
-
-static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
-	0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
-	0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
-	0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
-	0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
-	0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
-	0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
-	0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
-	0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
-	0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
-	0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
-	0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
-	0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
-	0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
-	0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
-	0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
-	0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
-};
-
-static u16 sunxi_nfc_randomizer_step(u16 state, int count)
-{
-	state &= 0x7fff;
-
-	/*
-	 * This loop is just a simple implementation of a Fibonacci LFSR using
-	 * the x16 + x15 + 1 polynomial.
-	 */
-	while (count--)
-		state = ((state >> 1) |
-			 (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
-
-	return state;
-}
-
-static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
-{
-	const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
-	int mod = mtd_div_by_ws(mtd->erasesize, mtd);
-
-	if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
-		mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
-
-	if (ecc) {
-		if (mtd->ecc_step_size == 512)
-			seeds = sunxi_nfc_randomizer_ecc512_seeds;
-		else
-			seeds = sunxi_nfc_randomizer_ecc1024_seeds;
-	}
-
-	return seeds[page % mod];
-}
-
-static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
-					int page, bool ecc)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
-	u16 state;
-
-	if (!(nand->options & NAND_NEED_SCRAMBLING))
-		return;
-
-	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
-	state = sunxi_nfc_randomizer_state(mtd, page, ecc);
-	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
-	writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
-}
-
-static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-
-	if (!(nand->options & NAND_NEED_SCRAMBLING))
-		return;
-
-	writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
-	       nfc->regs + NFC_REG_ECC_CTL);
-}
-
-static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-
-	if (!(nand->options & NAND_NEED_SCRAMBLING))
-		return;
-
-	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
-	       nfc->regs + NFC_REG_ECC_CTL);
-}
-
-static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
-{
-	u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
-
-	bbm[0] ^= state;
-	bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
-}
-
-static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
-					   const uint8_t *buf, int len,
-					   bool ecc, int page)
-{
-	sunxi_nfc_randomizer_config(mtd, page, ecc);
-	sunxi_nfc_randomizer_enable(mtd);
-	sunxi_nfc_write_buf(mtd, buf, len);
-	sunxi_nfc_randomizer_disable(mtd);
-}
-
-static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
-					  int len, bool ecc, int page)
-{
-	sunxi_nfc_randomizer_config(mtd, page, ecc);
-	sunxi_nfc_randomizer_enable(mtd);
-	sunxi_nfc_read_buf(mtd, buf, len);
-	sunxi_nfc_randomizer_disable(mtd);
-}
-
-static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
-	u32 ecc_ctl;
-
-	ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
-	ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
-		     NFC_ECC_BLOCK_SIZE_MSK);
-	ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
-		   NFC_ECC_PIPELINE;
-
-	if (nand->ecc.size == 512)
-		ecc_ctl |= NFC_ECC_BLOCK_512;
-
-	writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
-}
-
-static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-
-	writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
-	       nfc->regs + NFC_REG_ECC_CTL);
-}
-
-static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
-{
-	buf[0] = user_data;
-	buf[1] = user_data >> 8;
-	buf[2] = user_data >> 16;
-	buf[3] = user_data >> 24;
-}
-
-static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
-{
-	return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
-						int step, bool bbm, int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-
-	sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
-				   oob);
-
-	/* De-randomize the Bad Block Marker. */
-	if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
-		sunxi_nfc_randomize_bbm(mtd, page, oob);
-}
-
-static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
-						const u8 *oob, int step,
-						bool bbm, int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	u8 user_data[4];
-
-	/* Randomize the Bad Block Marker. */
-	if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
-		memcpy(user_data, oob, sizeof(user_data));
-		sunxi_nfc_randomize_bbm(mtd, page, user_data);
-		oob = user_data;
-	}
-
-	writel(sunxi_nfc_buf_to_user_data(oob),
-	       nfc->regs + NFC_REG_USER_DATA(step));
-}
-
-static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
-					  unsigned int *max_bitflips, int ret)
-{
-	if (ret < 0) {
-		mtd->ecc_stats.failed++;
-	} else {
-		mtd->ecc_stats.corrected += ret;
-		*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
-	}
-}
-
-static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
-				    int step, u32 status, bool *erased)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	u32 tmp;
-
-	*erased = false;
-
-	if (status & NFC_ECC_ERR(step))
-		return -EBADMSG;
-
-	if (status & NFC_ECC_PAT_FOUND(step)) {
-		u8 pattern;
-
-		if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
-			pattern = 0x0;
-		} else {
-			pattern = 0xff;
-			*erased = true;
-		}
-
-		if (data)
-			memset(data, pattern, ecc->size);
-
-		if (oob)
-			memset(oob, pattern, ecc->bytes + 4);
-
-		return 0;
-	}
-
-	tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
-
-	return NFC_ECC_ERR_CNT(step, tmp);
-}
-
-static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
-				       u8 *data, int data_off,
-				       u8 *oob, int oob_off,
-				       int *cur_off,
-				       unsigned int *max_bitflips,
-				       bool bbm, bool oob_required, int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	int raw_mode = 0;
-	bool erased;
-	int ret;
-
-	if (*cur_off != data_off)
-		nand_change_read_column_op(nand, data_off, NULL, 0, false);
-
-	sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
-
-	if (data_off + ecc->size != oob_off)
-		nand_change_read_column_op(nand, oob_off, NULL, 0, false);
-
-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-	if (ret)
-		return ret;
-
-	sunxi_nfc_randomizer_enable(mtd);
-	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
-	       nfc->regs + NFC_REG_CMD);
-
-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
-	sunxi_nfc_randomizer_disable(mtd);
-	if (ret)
-		return ret;
-
-	*cur_off = oob_off + ecc->bytes + 4;
-
-	ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
-				       readl(nfc->regs + NFC_REG_ECC_ST),
-				       &erased);
-	if (erased)
-		return 1;
-
-	if (ret < 0) {
-		/*
-		 * Re-read the data with the randomizer disabled to identify
-		 * bitflips in erased pages.
-		 */
-		if (nand->options & NAND_NEED_SCRAMBLING)
-			nand_change_read_column_op(nand, data_off, data,
-						   ecc->size, false);
-		else
-			memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
-				      ecc->size);
-
-		nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
-					   false);
-
-		ret = nand_check_erased_ecc_chunk(data,	ecc->size,
-						  oob, ecc->bytes + 4,
-						  NULL, 0, ecc->strength);
-		if (ret >= 0)
-			raw_mode = 1;
-	} else {
-		memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
-
-		if (oob_required) {
-			nand_change_read_column_op(nand, oob_off, NULL, 0,
-						   false);
-			sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
-						      true, page);
-
-			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
-							    bbm, page);
-		}
-	}
-
-	sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
-
-	return raw_mode;
-}
-
-static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
-					    u8 *oob, int *cur_off,
-					    bool randomize, int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	int offset = ((ecc->bytes + 4) * ecc->steps);
-	int len = mtd->oobsize - offset;
-
-	if (len <= 0)
-		return;
-
-	if (!cur_off || *cur_off != offset)
-		nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
-					   false);
-
-	if (!randomize)
-		sunxi_nfc_read_buf(mtd, oob + offset, len);
-	else
-		sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
-					      false, page);
-
-	if (cur_off)
-		*cur_off = mtd->oobsize + mtd->writesize;
-}
-
-static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
-					    int oob_required, int page,
-					    int nchunks)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	bool randomized = nand->options & NAND_NEED_SCRAMBLING;
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	unsigned int max_bitflips = 0;
-	int ret, i, raw_mode = 0;
-	struct scatterlist sg;
-	u32 status;
-
-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-	if (ret)
-		return ret;
-
-	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
-				       DMA_FROM_DEVICE, &sg);
-	if (ret)
-		return ret;
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-	sunxi_nfc_randomizer_config(mtd, page, false);
-	sunxi_nfc_randomizer_enable(mtd);
-
-	writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
-	       NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
-
-	dma_async_issue_pending(nfc->dmac);
-
-	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
-	       nfc->regs + NFC_REG_CMD);
-
-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
-	if (ret)
-		dmaengine_terminate_all(nfc->dmac);
-
-	sunxi_nfc_randomizer_disable(mtd);
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
-
-	if (ret)
-		return ret;
-
-	status = readl(nfc->regs + NFC_REG_ECC_ST);
-
-	for (i = 0; i < nchunks; i++) {
-		int data_off = i * ecc->size;
-		int oob_off = i * (ecc->bytes + 4);
-		u8 *data = buf + data_off;
-		u8 *oob = nand->oob_poi + oob_off;
-		bool erased;
-
-		ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
-					       oob_required ? oob : NULL,
-					       i, status, &erased);
-
-		/* ECC errors are handled in the second loop. */
-		if (ret < 0)
-			continue;
-
-		if (oob_required && !erased) {
-			/* TODO: use DMA to retrieve OOB */
-			nand_change_read_column_op(nand,
-						   mtd->writesize + oob_off,
-						   oob, ecc->bytes + 4, false);
-
-			sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
-							    !i, page);
-		}
-
-		if (erased)
-			raw_mode = 1;
-
-		sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
-	}
-
-	if (status & NFC_ECC_ERR_MSK) {
-		for (i = 0; i < nchunks; i++) {
-			int data_off = i * ecc->size;
-			int oob_off = i * (ecc->bytes + 4);
-			u8 *data = buf + data_off;
-			u8 *oob = nand->oob_poi + oob_off;
-
-			if (!(status & NFC_ECC_ERR(i)))
-				continue;
-
-			/*
-			 * Re-read the data with the randomizer disabled to
-			 * identify bitflips in erased pages.
-			 * TODO: use DMA to read page in raw mode
-			 */
-			if (randomized)
-				nand_change_read_column_op(nand, data_off,
-							   data, ecc->size,
-							   false);
-
-			/* TODO: use DMA to retrieve OOB */
-			nand_change_read_column_op(nand,
-						   mtd->writesize + oob_off,
-						   oob, ecc->bytes + 4, false);
-
-			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
-							  oob, ecc->bytes + 4,
-							  NULL, 0,
-							  ecc->strength);
-			if (ret >= 0)
-				raw_mode = 1;
-
-			sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
-		}
-	}
-
-	if (oob_required)
-		sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
-						NULL, !raw_mode,
-						page);
-
-	return max_bitflips;
-}
-
-static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
-					const u8 *data, int data_off,
-					const u8 *oob, int oob_off,
-					int *cur_off, bool bbm,
-					int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	int ret;
-
-	if (data_off != *cur_off)
-		nand_change_write_column_op(nand, data_off, NULL, 0, false);
-
-	sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
-
-	if (data_off + ecc->size != oob_off)
-		nand_change_write_column_op(nand, oob_off, NULL, 0, false);
-
-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-	if (ret)
-		return ret;
-
-	sunxi_nfc_randomizer_enable(mtd);
-	sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, 0, bbm, page);
-
-	writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
-	       NFC_ACCESS_DIR | NFC_ECC_OP,
-	       nfc->regs + NFC_REG_CMD);
-
-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
-	sunxi_nfc_randomizer_disable(mtd);
-	if (ret)
-		return ret;
-
-	*cur_off = oob_off + ecc->bytes + 4;
-
-	return 0;
-}
-
-static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
-					     u8 *oob, int *cur_off,
-					     int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	int offset = ((ecc->bytes + 4) * ecc->steps);
-	int len = mtd->oobsize - offset;
-
-	if (len <= 0)
-		return;
-
-	if (!cur_off || *cur_off != offset)
-		nand_change_write_column_op(nand, offset + mtd->writesize,
-					    NULL, 0, false);
-
-	sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
-
-	if (cur_off)
-		*cur_off = mtd->oobsize + mtd->writesize;
-}
-
-static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
-				      struct nand_chip *chip, uint8_t *buf,
-				      int oob_required, int page)
-{
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	unsigned int max_bitflips = 0;
-	int ret, i, cur_off = 0;
-	bool raw_mode = false;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_off = i * ecc->size;
-		int oob_off = i * (ecc->bytes + 4);
-		u8 *data = buf + data_off;
-		u8 *oob = chip->oob_poi + oob_off;
-
-		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
-						  oob_off + mtd->writesize,
-						  &cur_off, &max_bitflips,
-						  !i, oob_required, page);
-		if (ret < 0)
-			return ret;
-		else if (ret)
-			raw_mode = true;
-	}
-
-	if (oob_required)
-		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
-						!raw_mode, page);
-
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	return max_bitflips;
-}
-
-static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
-					  struct nand_chip *chip, u8 *buf,
-					  int oob_required, int page)
-{
-	int ret;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
-					       chip->ecc.steps);
-	if (ret >= 0)
-		return ret;
-
-	/* Fallback to PIO mode */
-	return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
-}
-
-static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
-					 struct nand_chip *chip,
-					 u32 data_offs, u32 readlen,
-					 u8 *bufpoi, int page)
-{
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ret, i, cur_off = 0;
-	unsigned int max_bitflips = 0;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-
-	for (i = data_offs / ecc->size;
-	     i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
-		int data_off = i * ecc->size;
-		int oob_off = i * (ecc->bytes + 4);
-		u8 *data = bufpoi + data_off;
-		u8 *oob = chip->oob_poi + oob_off;
-
-		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
-						  oob,
-						  oob_off + mtd->writesize,
-						  &cur_off, &max_bitflips, !i,
-						  false, page);
-		if (ret < 0)
-			return ret;
-	}
-
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	return max_bitflips;
-}
-
-static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
-					     struct nand_chip *chip,
-					     u32 data_offs, u32 readlen,
-					     u8 *buf, int page)
-{
-	int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
-	int ret;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
-	if (ret >= 0)
-		return ret;
-
-	/* Fallback to PIO mode */
-	return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
-					     buf, page);
-}
-
-static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
-				       struct nand_chip *chip,
-				       const uint8_t *buf, int oob_required,
-				       int page)
-{
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ret, i, cur_off = 0;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_off = i * ecc->size;
-		int oob_off = i * (ecc->bytes + 4);
-		const u8 *data = buf + data_off;
-		const u8 *oob = chip->oob_poi + oob_off;
-
-		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
-						   oob_off + mtd->writesize,
-						   &cur_off, !i, page);
-		if (ret)
-			return ret;
-	}
-
-	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
-		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
-						 &cur_off, page);
-
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
-					  struct nand_chip *chip,
-					  u32 data_offs, u32 data_len,
-					  const u8 *buf, int oob_required,
-					  int page)
-{
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ret, i, cur_off = 0;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-
-	for (i = data_offs / ecc->size;
-	     i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
-		int data_off = i * ecc->size;
-		int oob_off = i * (ecc->bytes + 4);
-		const u8 *data = buf + data_off;
-		const u8 *oob = chip->oob_poi + oob_off;
-
-		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
-						   oob_off + mtd->writesize,
-						   &cur_off, !i, page);
-		if (ret)
-			return ret;
-	}
-
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
-					   struct nand_chip *chip,
-					   const u8 *buf,
-					   int oob_required,
-					   int page)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-	struct scatterlist sg;
-	int ret, i;
-
-	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
-	if (ret)
-		return ret;
-
-	ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
-				       DMA_TO_DEVICE, &sg);
-	if (ret)
-		goto pio_fallback;
-
-	for (i = 0; i < ecc->steps; i++) {
-		const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
-
-		sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
-	}
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-	sunxi_nfc_randomizer_config(mtd, page, false);
-	sunxi_nfc_randomizer_enable(mtd);
-
-	writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
-	       nfc->regs + NFC_REG_RCMD_SET);
-
-	dma_async_issue_pending(nfc->dmac);
-
-	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
-	       NFC_DATA_TRANS | NFC_ACCESS_DIR,
-	       nfc->regs + NFC_REG_CMD);
-
-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
-	if (ret)
-		dmaengine_terminate_all(nfc->dmac);
-
-	sunxi_nfc_randomizer_disable(mtd);
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
-
-	if (ret)
-		return ret;
-
-	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
-		/* TODO: use DMA to transfer extra OOB bytes ? */
-		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
-						 NULL, page);
-
-	return nand_prog_page_end_op(chip);
-
-pio_fallback:
-	return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
-}
-
-static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
-					       struct nand_chip *chip,
-					       uint8_t *buf, int oob_required,
-					       int page)
-{
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	unsigned int max_bitflips = 0;
-	int ret, i, cur_off = 0;
-	bool raw_mode = false;
-
-	nand_read_page_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_off = i * (ecc->size + ecc->bytes + 4);
-		int oob_off = data_off + ecc->size;
-		u8 *data = buf + (i * ecc->size);
-		u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
-
-		ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
-						  oob_off, &cur_off,
-						  &max_bitflips, !i,
-						  oob_required,
-						  page);
-		if (ret < 0)
-			return ret;
-		else if (ret)
-			raw_mode = true;
-	}
-
-	if (oob_required)
-		sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
-						!raw_mode, page);
-
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	return max_bitflips;
-}
-
-static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
-						struct nand_chip *chip,
-						const uint8_t *buf,
-						int oob_required, int page)
-{
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	int ret, i, cur_off = 0;
-
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
-	sunxi_nfc_hw_ecc_enable(mtd);
-
-	for (i = 0; i < ecc->steps; i++) {
-		int data_off = i * (ecc->size + ecc->bytes + 4);
-		int oob_off = data_off + ecc->size;
-		const u8 *data = buf + (i * ecc->size);
-		const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
-
-		ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
-						   oob, oob_off, &cur_off,
-						   false, page);
-		if (ret)
-			return ret;
-	}
-
-	if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
-		sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
-						 &cur_off, page);
-
-	sunxi_nfc_hw_ecc_disable(mtd);
-
-	return nand_prog_page_end_op(chip);
-}
-
-static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
-					    struct nand_chip *chip,
-					    int page)
-{
-	chip->pagebuf = -1;
-
-	return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
-}
-
-static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
-					     struct nand_chip *chip,
-					     int page)
-{
-	int ret;
-
-	chip->pagebuf = -1;
-
-	memset(chip->data_buf, 0xff, mtd->writesize);
-	ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
-	if (ret)
-		return ret;
-
-	/* Send command to program the OOB data */
-	return nand_prog_page_end_op(chip);
-}
-
-static const s32 tWB_lut[] = {6, 12, 16, 20};
-static const s32 tRHW_lut[] = {4, 8, 12, 20};
-
-static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
-		u32 clk_period)
-{
-	u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
-	int i;
-
-	for (i = 0; i < lut_size; i++) {
-		if (clk_cycles <= lut[i])
-			return i;
-	}
-
-	/* Doesn't fit */
-	return -EINVAL;
-}
-
-#define sunxi_nand_lookup_timing(l, p, c) \
-			_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-
-static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
-					const struct nand_data_interface *conf)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
-	const struct nand_sdr_timings *timings;
-	u32 min_clk_period = 0;
-	s32 tWB, tADL, tWHR, tRHW, tCAD;
-	long real_clk_rate;
-
-	timings = nand_get_sdr_timings(conf);
-	if (IS_ERR(timings))
-		return -ENOTSUPP;
-
-	/* T1 <=> tCLS */
-	if (timings->tCLS_min > min_clk_period)
-		min_clk_period = timings->tCLS_min;
-
-	/* T2 <=> tCLH */
-	if (timings->tCLH_min > min_clk_period)
-		min_clk_period = timings->tCLH_min;
-
-	/* T3 <=> tCS */
-	if (timings->tCS_min > min_clk_period)
-		min_clk_period = timings->tCS_min;
-
-	/* T4 <=> tCH */
-	if (timings->tCH_min > min_clk_period)
-		min_clk_period = timings->tCH_min;
-
-	/* T5 <=> tWP */
-	if (timings->tWP_min > min_clk_period)
-		min_clk_period = timings->tWP_min;
-
-	/* T6 <=> tWH */
-	if (timings->tWH_min > min_clk_period)
-		min_clk_period = timings->tWH_min;
-
-	/* T7 <=> tALS */
-	if (timings->tALS_min > min_clk_period)
-		min_clk_period = timings->tALS_min;
-
-	/* T8 <=> tDS */
-	if (timings->tDS_min > min_clk_period)
-		min_clk_period = timings->tDS_min;
-
-	/* T9 <=> tDH */
-	if (timings->tDH_min > min_clk_period)
-		min_clk_period = timings->tDH_min;
-
-	/* T10 <=> tRR */
-	if (timings->tRR_min > (min_clk_period * 3))
-		min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
-
-	/* T11 <=> tALH */
-	if (timings->tALH_min > min_clk_period)
-		min_clk_period = timings->tALH_min;
-
-	/* T12 <=> tRP */
-	if (timings->tRP_min > min_clk_period)
-		min_clk_period = timings->tRP_min;
-
-	/* T13 <=> tREH */
-	if (timings->tREH_min > min_clk_period)
-		min_clk_period = timings->tREH_min;
-
-	/* T14 <=> tRC */
-	if (timings->tRC_min > (min_clk_period * 2))
-		min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
-
-	/* T15 <=> tWC */
-	if (timings->tWC_min > (min_clk_period * 2))
-		min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
-
-	/* T16 - T19 + tCAD */
-	if (timings->tWB_max > (min_clk_period * 20))
-		min_clk_period = DIV_ROUND_UP(timings->tWB_max, 20);
-
-	if (timings->tADL_min > (min_clk_period * 32))
-		min_clk_period = DIV_ROUND_UP(timings->tADL_min, 32);
-
-	if (timings->tWHR_min > (min_clk_period * 32))
-		min_clk_period = DIV_ROUND_UP(timings->tWHR_min, 32);
-
-	if (timings->tRHW_min > (min_clk_period * 20))
-		min_clk_period = DIV_ROUND_UP(timings->tRHW_min, 20);
-
-	tWB  = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
-					min_clk_period);
-	if (tWB < 0) {
-		dev_err(nfc->dev, "unsupported tWB\n");
-		return tWB;
-	}
-
-	tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
-	if (tADL > 3) {
-		dev_err(nfc->dev, "unsupported tADL\n");
-		return -EINVAL;
-	}
-
-	tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
-	if (tWHR > 3) {
-		dev_err(nfc->dev, "unsupported tWHR\n");
-		return -EINVAL;
-	}
-
-	tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
-					min_clk_period);
-	if (tRHW < 0) {
-		dev_err(nfc->dev, "unsupported tRHW\n");
-		return tRHW;
-	}
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	/*
-	 * TODO: according to ONFI specs this value only applies for DDR NAND,
-	 * but Allwinner seems to set this to 0x7. Mimic them for now.
-	 */
-	tCAD = 0x7;
-
-	/* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
-	chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
-
-	/* Convert min_clk_period from picoseconds to nanoseconds */
-	min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
-
-	/*
-	 * Unlike what is stated in Allwinner datasheet, the clk_rate should
-	 * be set to (1 / min_clk_period), and not (2 / min_clk_period).
-	 * This new formula was verified with a scope and validated by
-	 * Allwinner engineers.
-	 */
-	chip->clk_rate = NSEC_PER_SEC / min_clk_period;
-	real_clk_rate = clk_round_rate(nfc->mod_clk, chip->clk_rate);
-	if (real_clk_rate <= 0) {
-		dev_err(nfc->dev, "Unable to round clk %lu\n", chip->clk_rate);
-		return -EINVAL;
-	}
-
-	/*
-	 * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
-	 * output cycle timings shall be used if the host drives tRC less than
-	 * 30 ns.
-	 */
-	min_clk_period = NSEC_PER_SEC / real_clk_rate;
-	chip->timing_ctl = ((min_clk_period * 2) < 30) ?
-			   NFC_TIMING_CTL_EDO : 0;
-
-	return 0;
-}
-
-static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
-				    struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-
-	if (section >= ecc->steps)
-		return -ERANGE;
-
-	oobregion->offset = section * (ecc->bytes + 4) + 4;
-	oobregion->length = ecc->bytes;
-
-	return 0;
-}
-
-static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
-				     struct mtd_oob_region *oobregion)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &nand->ecc;
-
-	if (section > ecc->steps)
-		return -ERANGE;
-
-	/*
-	 * The first 2 bytes are used for BB markers, hence we
-	 * only have 2 bytes available in the first user data
-	 * section.
-	 */
-	if (!section && ecc->mode == NAND_ECC_HW) {
-		oobregion->offset = 2;
-		oobregion->length = 2;
-
-		return 0;
-	}
-
-	oobregion->offset = section * (ecc->bytes + 4);
-
-	if (section < ecc->steps)
-		oobregion->length = 4;
-	else
-		oobregion->offset = mtd->oobsize - oobregion->offset;
-
-	return 0;
-}
-
-static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
-	.ecc = sunxi_nand_ooblayout_ecc,
-	.free = sunxi_nand_ooblayout_free,
-};
-
-static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
-					      struct nand_ecc_ctrl *ecc,
-					      struct device_node *np)
-{
-	static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	struct sunxi_nand_hw_ecc *data;
-	int nsectors;
-	int ret;
-	int i;
-
-	if (ecc->options & NAND_ECC_MAXIMIZE) {
-		int bytes;
-
-		ecc->size = 1024;
-		nsectors = mtd->writesize / ecc->size;
-
-		/* Reserve 2 bytes for the BBM */
-		bytes = (mtd->oobsize - 2) / nsectors;
-
-		/* 4 non-ECC bytes are added before each ECC bytes section */
-		bytes -= 4;
-
-		/* and bytes has to be even. */
-		if (bytes % 2)
-			bytes--;
-
-		ecc->strength = bytes * 8 / fls(8 * ecc->size);
-
-		for (i = 0; i < ARRAY_SIZE(strengths); i++) {
-			if (strengths[i] > ecc->strength)
-				break;
-		}
-
-		if (!i)
-			ecc->strength = 0;
-		else
-			ecc->strength = strengths[i - 1];
-	}
-
-	if (ecc->size != 512 && ecc->size != 1024)
-		return -EINVAL;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	/* Prefer 1k ECC chunk over 512 ones */
-	if (ecc->size == 512 && mtd->writesize > 512) {
-		ecc->size = 1024;
-		ecc->strength *= 2;
-	}
-
-	/* Add ECC info retrieval from DT */
-	for (i = 0; i < ARRAY_SIZE(strengths); i++) {
-		if (ecc->strength <= strengths[i]) {
-			/*
-			 * Update ecc->strength value with the actual strength
-			 * that will be used by the ECC engine.
-			 */
-			ecc->strength = strengths[i];
-			break;
-		}
-	}
-
-	if (i >= ARRAY_SIZE(strengths)) {
-		dev_err(nfc->dev, "unsupported strength\n");
-		ret = -ENOTSUPP;
-		goto err;
-	}
-
-	data->mode = i;
-
-	/* HW ECC always request ECC bytes for 1024 bytes blocks */
-	ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
-
-	/* HW ECC always work with even numbers of ECC bytes */
-	ecc->bytes = ALIGN(ecc->bytes, 2);
-
-	nsectors = mtd->writesize / ecc->size;
-
-	if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
-		ret = -EINVAL;
-		goto err;
-	}
-
-	ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
-	ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
-	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
-	ecc->priv = data;
-
-	return 0;
-
-err:
-	kfree(data);
-
-	return ret;
-}
-
-static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
-{
-	kfree(ecc->priv);
-}
-
-static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
-				       struct nand_ecc_ctrl *ecc,
-				       struct device_node *np)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
-	struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
-	int ret;
-
-	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
-	if (ret)
-		return ret;
-
-	if (nfc->dmac) {
-		ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
-		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
-		ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
-		nand->options |= NAND_USE_BOUNCE_BUFFER;
-	} else {
-		ecc->read_page = sunxi_nfc_hw_ecc_read_page;
-		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
-		ecc->write_page = sunxi_nfc_hw_ecc_write_page;
-	}
-
-	/* TODO: support DMA for raw accesses and subpage write */
-	ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
-	ecc->read_oob_raw = nand_read_oob_std;
-	ecc->write_oob_raw = nand_write_oob_std;
-
-	return 0;
-}
-
-static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
-						struct nand_ecc_ctrl *ecc,
-						struct device_node *np)
-{
-	int ret;
-
-	ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
-	if (ret)
-		return ret;
-
-	ecc->prepad = 4;
-	ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
-	ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;
-	ecc->read_oob_raw = nand_read_oob_syndrome;
-	ecc->write_oob_raw = nand_write_oob_syndrome;
-
-	return 0;
-}
-
-static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
-{
-	switch (ecc->mode) {
-	case NAND_ECC_HW:
-	case NAND_ECC_HW_SYNDROME:
-		sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
-		break;
-	case NAND_ECC_NONE:
-	default:
-		break;
-	}
-}
-
-static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
-			       struct device_node *np)
-{
-	struct nand_chip *nand = mtd_to_nand(mtd);
-	int ret;
-
-	if (!ecc->size) {
-		ecc->size = nand->ecc_step_ds;
-		ecc->strength = nand->ecc_strength_ds;
-	}
-
-	if (!ecc->size || !ecc->strength)
-		return -EINVAL;
-
-	switch (ecc->mode) {
-	case NAND_ECC_HW:
-		ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
-		if (ret)
-			return ret;
-		break;
-	case NAND_ECC_HW_SYNDROME:
-		ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np);
-		if (ret)
-			return ret;
-		break;
-	case NAND_ECC_NONE:
-	case NAND_ECC_SOFT:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
-				struct device_node *np)
-{
-	struct sunxi_nand_chip *chip;
-	struct mtd_info *mtd;
-	struct nand_chip *nand;
-	int nsels;
-	int ret;
-	int i;
-	u32 tmp;
-
-	if (!of_get_property(np, "reg", &nsels))
-		return -EINVAL;
-
-	nsels /= sizeof(u32);
-	if (!nsels) {
-		dev_err(dev, "invalid reg property size\n");
-		return -EINVAL;
-	}
-
-	chip = devm_kzalloc(dev,
-			    sizeof(*chip) +
-			    (nsels * sizeof(struct sunxi_nand_chip_sel)),
-			    GFP_KERNEL);
-	if (!chip) {
-		dev_err(dev, "could not allocate chip\n");
-		return -ENOMEM;
-	}
-
-	chip->nsels = nsels;
-	chip->selected = -1;
-
-	for (i = 0; i < nsels; i++) {
-		ret = of_property_read_u32_index(np, "reg", i, &tmp);
-		if (ret) {
-			dev_err(dev, "could not retrieve reg property: %d\n",
-				ret);
-			return ret;
-		}
-
-		if (tmp > NFC_MAX_CS) {
-			dev_err(dev,
-				"invalid reg value: %u (max CS = 7)\n",
-				tmp);
-			return -EINVAL;
-		}
-
-		if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
-			dev_err(dev, "CS %d already assigned\n", tmp);
-			return -EINVAL;
-		}
-
-		chip->sels[i].cs = tmp;
-
-		if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) &&
-		    tmp < 2) {
-			chip->sels[i].rb.type = RB_NATIVE;
-			chip->sels[i].rb.info.nativeid = tmp;
-		} else {
-			ret = of_get_named_gpio(np, "rb-gpios", i);
-			if (ret >= 0) {
-				tmp = ret;
-				chip->sels[i].rb.type = RB_GPIO;
-				chip->sels[i].rb.info.gpio = tmp;
-				ret = devm_gpio_request(dev, tmp, "nand-rb");
-				if (ret)
-					return ret;
-
-				ret = gpio_direction_input(tmp);
-				if (ret)
-					return ret;
-			} else {
-				chip->sels[i].rb.type = RB_NONE;
-			}
-		}
-	}
-
-	nand = &chip->nand;
-	/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
-	nand->chip_delay = 200;
-	nand->controller = &nfc->controller;
-	/*
-	 * Set the ECC mode to the default value in case nothing is specified
-	 * in the DT.
-	 */
-	nand->ecc.mode = NAND_ECC_HW;
-	nand_set_flash_node(nand, np);
-	nand->select_chip = sunxi_nfc_select_chip;
-	nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
-	nand->read_buf = sunxi_nfc_read_buf;
-	nand->write_buf = sunxi_nfc_write_buf;
-	nand->read_byte = sunxi_nfc_read_byte;
-	nand->setup_data_interface = sunxi_nfc_setup_data_interface;
-
-	mtd = nand_to_mtd(nand);
-	mtd->dev.parent = dev;
-
-	ret = nand_scan_ident(mtd, nsels, NULL);
-	if (ret)
-		return ret;
-
-	if (nand->bbt_options & NAND_BBT_USE_FLASH)
-		nand->bbt_options |= NAND_BBT_NO_OOB;
-
-	if (nand->options & NAND_NEED_SCRAMBLING)
-		nand->options |= NAND_NO_SUBPAGE_WRITE;
-
-	nand->options |= NAND_SUBPAGE_READ;
-
-	ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
-	if (ret) {
-		dev_err(dev, "ECC init failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = nand_scan_tail(mtd);
-	if (ret) {
-		dev_err(dev, "nand_scan_tail failed: %d\n", ret);
-		return ret;
-	}
-
-	ret = mtd_device_register(mtd, NULL, 0);
-	if (ret) {
-		dev_err(dev, "failed to register mtd device: %d\n", ret);
-		nand_release(mtd);
-		return ret;
-	}
-
-	list_add_tail(&chip->node, &nfc->chips);
-
-	return 0;
-}
-
-static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
-{
-	struct device_node *np = dev->of_node;
-	struct device_node *nand_np;
-	int nchips = of_get_child_count(np);
-	int ret;
-
-	if (nchips > 8) {
-		dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
-		return -EINVAL;
-	}
-
-	for_each_child_of_node(np, nand_np) {
-		ret = sunxi_nand_chip_init(dev, nfc, nand_np);
-		if (ret) {
-			of_node_put(nand_np);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
-{
-	struct sunxi_nand_chip *chip;
-
-	while (!list_empty(&nfc->chips)) {
-		chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
-					node);
-		nand_release(nand_to_mtd(&chip->nand));
-		sunxi_nand_ecc_cleanup(&chip->nand.ecc);
-		list_del(&chip->node);
-	}
-}
-
-static int sunxi_nfc_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct resource *r;
-	struct sunxi_nfc *nfc;
-	int irq;
-	int ret;
-
-	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
-	if (!nfc)
-		return -ENOMEM;
-
-	nfc->dev = dev;
-	nand_hw_control_init(&nfc->controller);
-	INIT_LIST_HEAD(&nfc->chips);
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nfc->regs = devm_ioremap_resource(dev, r);
-	if (IS_ERR(nfc->regs))
-		return PTR_ERR(nfc->regs);
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "failed to retrieve irq\n");
-		return irq;
-	}
-
-	nfc->ahb_clk = devm_clk_get(dev, "ahb");
-	if (IS_ERR(nfc->ahb_clk)) {
-		dev_err(dev, "failed to retrieve ahb clk\n");
-		return PTR_ERR(nfc->ahb_clk);
-	}
-
-	ret = clk_prepare_enable(nfc->ahb_clk);
-	if (ret)
-		return ret;
-
-	nfc->mod_clk = devm_clk_get(dev, "mod");
-	if (IS_ERR(nfc->mod_clk)) {
-		dev_err(dev, "failed to retrieve mod clk\n");
-		ret = PTR_ERR(nfc->mod_clk);
-		goto out_ahb_clk_unprepare;
-	}
-
-	ret = clk_prepare_enable(nfc->mod_clk);
-	if (ret)
-		goto out_ahb_clk_unprepare;
-
-	nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
-	if (IS_ERR(nfc->reset)) {
-		ret = PTR_ERR(nfc->reset);
-		goto out_mod_clk_unprepare;
-	}
-
-	ret = reset_control_deassert(nfc->reset);
-	if (ret) {
-		dev_err(dev, "reset err %d\n", ret);
-		goto out_mod_clk_unprepare;
-	}
-
-	ret = sunxi_nfc_rst(nfc);
-	if (ret)
-		goto out_ahb_reset_reassert;
-
-	writel(0, nfc->regs + NFC_REG_INT);
-	ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
-			       0, "sunxi-nand", nfc);
-	if (ret)
-		goto out_ahb_reset_reassert;
-
-	nfc->dmac = dma_request_slave_channel(dev, "rxtx");
-	if (nfc->dmac) {
-		struct dma_slave_config dmac_cfg = { };
-
-		dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
-		dmac_cfg.dst_addr = dmac_cfg.src_addr;
-		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
-		dmac_cfg.src_maxburst = 4;
-		dmac_cfg.dst_maxburst = 4;
-		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
-	} else {
-		dev_warn(dev, "failed to request rxtx DMA channel\n");
-	}
-
-	platform_set_drvdata(pdev, nfc);
-
-	ret = sunxi_nand_chips_init(dev, nfc);
-	if (ret) {
-		dev_err(dev, "failed to init nand chips\n");
-		goto out_release_dmac;
-	}
-
-	return 0;
-
-out_release_dmac:
-	if (nfc->dmac)
-		dma_release_channel(nfc->dmac);
-out_ahb_reset_reassert:
-	reset_control_assert(nfc->reset);
-out_mod_clk_unprepare:
-	clk_disable_unprepare(nfc->mod_clk);
-out_ahb_clk_unprepare:
-	clk_disable_unprepare(nfc->ahb_clk);
-
-	return ret;
-}
-
-static int sunxi_nfc_remove(struct platform_device *pdev)
-{
-	struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
-
-	sunxi_nand_chips_cleanup(nfc);
-
-	reset_control_assert(nfc->reset);
-
-	if (nfc->dmac)
-		dma_release_channel(nfc->dmac);
-	clk_disable_unprepare(nfc->mod_clk);
-	clk_disable_unprepare(nfc->ahb_clk);
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_nfc_ids[] = {
-	{ .compatible = "allwinner,sun4i-a10-nand" },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, sunxi_nfc_ids);
-
-static struct platform_driver sunxi_nfc_driver = {
-	.driver = {
-		.name = "sunxi_nand",
-		.of_match_table = sunxi_nfc_ids,
-	},
-	.probe = sunxi_nfc_probe,
-	.remove = sunxi_nfc_remove,
-};
-module_platform_driver(sunxi_nfc_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Boris BREZILLON");
-MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
-MODULE_ALIAS("platform:sunxi_nand");
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
deleted file mode 100644
index c5bee00b7f5e..000000000000
--- a/drivers/mtd/nand/tango_nand.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Copyright (C) 2016 Sigma Designs
- *
- * 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/io.h>
-#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-/* Offsets relative to chip->base */
-#define PBUS_CMD	0
-#define PBUS_ADDR	4
-#define PBUS_DATA	8
-
-/* Offsets relative to reg_base */
-#define NFC_STATUS	0x00
-#define NFC_FLASH_CMD	0x04
-#define NFC_DEVICE_CFG	0x08
-#define NFC_TIMING1	0x0c
-#define NFC_TIMING2	0x10
-#define NFC_XFER_CFG	0x14
-#define NFC_PKT_0_CFG	0x18
-#define NFC_PKT_N_CFG	0x1c
-#define NFC_BB_CFG	0x20
-#define NFC_ADDR_PAGE	0x24
-#define NFC_ADDR_OFFSET	0x28
-#define NFC_XFER_STATUS	0x2c
-
-/* NFC_STATUS values */
-#define CMD_READY	BIT(31)
-
-/* NFC_FLASH_CMD values */
-#define NFC_READ	1
-#define NFC_WRITE	2
-
-/* NFC_XFER_STATUS values */
-#define PAGE_IS_EMPTY	BIT(16)
-
-/* Offsets relative to mem_base */
-#define METADATA	0x000
-#define ERROR_REPORT	0x1c0
-
-/*
- * Error reports are split in two bytes:
- * byte 0 for the first packet in the page (PKT_0)
- * byte 1 for other packets in the page (PKT_N, for N > 0)
- * ERR_COUNT_PKT_N is the max error count over all but the first packet.
- */
-#define ERR_COUNT_PKT_0(v)	(((v) >> 0) & 0x3f)
-#define ERR_COUNT_PKT_N(v)	(((v) >> 8) & 0x3f)
-#define DECODE_FAIL_PKT_0(v)	(((v) & BIT(7)) == 0)
-#define DECODE_FAIL_PKT_N(v)	(((v) & BIT(15)) == 0)
-
-/* Offsets relative to pbus_base */
-#define PBUS_CS_CTRL	0x83c
-#define PBUS_PAD_MODE	0x8f0
-
-/* PBUS_CS_CTRL values */
-#define PBUS_IORDY	BIT(31)
-
-/*
- * PBUS_PAD_MODE values
- * In raw mode, the driver communicates directly with the NAND chips.
- * In NFC mode, the NAND Flash controller manages the communication.
- * We use NFC mode for read and write; raw mode for everything else.
- */
-#define MODE_RAW	0
-#define MODE_NFC	BIT(31)
-
-#define METADATA_SIZE	4
-#define BBM_SIZE	6
-#define FIELD_ORDER	15
-
-#define MAX_CS		4
-
-struct tango_nfc {
-	struct nand_hw_control hw;
-	void __iomem *reg_base;
-	void __iomem *mem_base;
-	void __iomem *pbus_base;
-	struct tango_chip *chips[MAX_CS];
-	struct dma_chan *chan;
-	int freq_kHz;
-};
-
-#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
-
-struct tango_chip {
-	struct nand_chip nand_chip;
-	void __iomem *base;
-	u32 timing1;
-	u32 timing2;
-	u32 xfer_cfg;
-	u32 pkt_0_cfg;
-	u32 pkt_n_cfg;
-	u32 bb_cfg;
-};
-
-#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
-
-#define XFER_CFG(cs, page_count, steps, metadata_size)	\
-	((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
-
-#define PKT_CFG(size, strength) ((size) << 16 | (strength))
-
-#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
-
-#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
-
-static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
-{
-	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
-
-	if (ctrl & NAND_CLE)
-		writeb_relaxed(dat, tchip->base + PBUS_CMD);
-
-	if (ctrl & NAND_ALE)
-		writeb_relaxed(dat, tchip->base + PBUS_ADDR);
-}
-
-static int tango_dev_ready(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-
-	return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
-}
-
-static u8 tango_read_byte(struct mtd_info *mtd)
-{
-	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
-
-	return readb_relaxed(tchip->base + PBUS_DATA);
-}
-
-static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
-{
-	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
-
-	ioread8_rep(tchip->base + PBUS_DATA, buf, len);
-}
-
-static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
-{
-	struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
-
-	iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
-}
-
-static void tango_select_chip(struct mtd_info *mtd, int idx)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-	struct tango_chip *tchip = to_tango_chip(chip);
-
-	if (idx < 0)
-		return; /* No "chip unselect" function */
-
-	writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
-	writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
-	writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
-	writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
-	writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
-	writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
-}
-
-/*
- * The controller does not check for bitflips in erased pages,
- * therefore software must check instead.
- */
-static int check_erased_page(struct nand_chip *chip, u8 *buf)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 *meta = chip->oob_poi + BBM_SIZE;
-	u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
-	const int ecc_size = chip->ecc.bytes;
-	const int pkt_size = chip->ecc.size;
-	int i, res, meta_len, bitflips = 0;
-
-	for (i = 0; i < chip->ecc.steps; ++i) {
-		meta_len = i ? 0 : METADATA_SIZE;
-		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
-						  meta, meta_len,
-						  chip->ecc.strength);
-		if (res < 0)
-			mtd->ecc_stats.failed++;
-		else
-			mtd->ecc_stats.corrected += res;
-
-		bitflips = max(res, bitflips);
-		buf += pkt_size;
-		ecc += ecc_size;
-	}
-
-	return bitflips;
-}
-
-static int decode_error_report(struct nand_chip *chip)
-{
-	u32 status, res;
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-
-	status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
-	if (status & PAGE_IS_EMPTY)
-		return 0;
-
-	res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
-
-	if (DECODE_FAIL_PKT_0(res) || DECODE_FAIL_PKT_N(res))
-		return -EBADMSG;
-
-	/* ERR_COUNT_PKT_N is max, not sum, but that's all we have */
-	mtd->ecc_stats.corrected +=
-		ERR_COUNT_PKT_0(res) + ERR_COUNT_PKT_N(res);
-
-	return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
-}
-
-static void tango_dma_callback(void *arg)
-{
-	complete(arg);
-}
-
-static int do_dma(struct tango_nfc *nfc, enum dma_data_direction dir, int cmd,
-		  const void *buf, int len, int page)
-{
-	void __iomem *addr = nfc->reg_base + NFC_STATUS;
-	struct dma_chan *chan = nfc->chan;
-	struct dma_async_tx_descriptor *desc;
-	enum dma_transfer_direction tdir;
-	struct scatterlist sg;
-	struct completion tx_done;
-	int err = -EIO;
-	u32 res, val;
-
-	sg_init_one(&sg, buf, len);
-	if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
-		return -EIO;
-
-	tdir = dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-	desc = dmaengine_prep_slave_sg(chan, &sg, 1, tdir, DMA_PREP_INTERRUPT);
-	if (!desc)
-		goto dma_unmap;
-
-	desc->callback = tango_dma_callback;
-	desc->callback_param = &tx_done;
-	init_completion(&tx_done);
-
-	writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
-
-	writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
-	writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
-	writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
-
-	dmaengine_submit(desc);
-	dma_async_issue_pending(chan);
-
-	res = wait_for_completion_timeout(&tx_done, HZ);
-	if (res > 0)
-		err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
-
-	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
-
-dma_unmap:
-	dma_unmap_sg(chan->device->dev, &sg, 1, dir);
-
-	return err;
-}
-
-static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-			   u8 *buf, int oob_required, int page)
-{
-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-	int err, res, len = mtd->writesize;
-
-	if (oob_required)
-		chip->ecc.read_oob(mtd, chip, page);
-
-	err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
-	if (err)
-		return err;
-
-	res = decode_error_report(chip);
-	if (res < 0) {
-		chip->ecc.read_oob_raw(mtd, chip, page);
-		res = check_erased_page(chip, buf);
-	}
-
-	return res;
-}
-
-static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-			    const u8 *buf, int oob_required, int page)
-{
-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-	int err, status, len = mtd->writesize;
-
-	/* Calling tango_write_oob() would send PAGEPROG twice */
-	if (oob_required)
-		return -ENOTSUPP;
-
-	writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
-	err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
-	if (err)
-		return err;
-
-	status = chip->waitfunc(mtd, chip);
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
-
-	return 0;
-}
-
-static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	*pos += len;
-
-	if (!*buf) {
-		/* skip over "len" bytes */
-		nand_change_read_column_op(chip, *pos, NULL, 0, false);
-	} else {
-		tango_read_buf(mtd, *buf, len);
-		*buf += len;
-	}
-}
-
-static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-
-	*pos += len;
-
-	if (!*buf) {
-		/* skip over "len" bytes */
-		nand_change_write_column_op(chip, *pos, NULL, 0, false);
-	} else {
-		tango_write_buf(mtd, *buf, len);
-		*buf += len;
-	}
-}
-
-/*
- * Physical page layout (not drawn to scale)
- *
- * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
- *
- * +---+-----------------+-------+-----+-----------+-----+----+-------+
- * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
- * +---+-----------------+-------+-----+-----------+-----+----+-------+
- *
- * Logical page layout:
- *
- *       +-----+---+-------+-----+-------+
- * oob = | BBM | M | ECC_0 | ... | ECC_N |
- *       +-----+---+-------+-----+-------+
- *
- *       +-----------------+-----+-----------------+
- * buf = |      PKT_0      | ... |      PKT_N      |
- *       +-----------------+-----+-----------------+
- */
-static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	u8 *oob_orig = oob;
-	const int page_size = mtd->writesize;
-	const int ecc_size = chip->ecc.bytes;
-	const int pkt_size = chip->ecc.size;
-	int pos = 0; /* position within physical page */
-	int rem = page_size; /* bytes remaining until BBM area */
-
-	if (oob)
-		oob += BBM_SIZE;
-
-	aux_read(chip, &oob, METADATA_SIZE, &pos);
-
-	while (rem > pkt_size) {
-		aux_read(chip, &buf, pkt_size, &pos);
-		aux_read(chip, &oob, ecc_size, &pos);
-		rem = page_size - pos;
-	}
-
-	aux_read(chip, &buf, rem, &pos);
-	aux_read(chip, &oob_orig, BBM_SIZE, &pos);
-	aux_read(chip, &buf, pkt_size - rem, &pos);
-	aux_read(chip, &oob, ecc_size, &pos);
-}
-
-static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
-{
-	struct mtd_info *mtd = nand_to_mtd(chip);
-	const u8 *oob_orig = oob;
-	const int page_size = mtd->writesize;
-	const int ecc_size = chip->ecc.bytes;
-	const int pkt_size = chip->ecc.size;
-	int pos = 0; /* position within physical page */
-	int rem = page_size; /* bytes remaining until BBM area */
-
-	if (oob)
-		oob += BBM_SIZE;
-
-	aux_write(chip, &oob, METADATA_SIZE, &pos);
-
-	while (rem > pkt_size) {
-		aux_write(chip, &buf, pkt_size, &pos);
-		aux_write(chip, &oob, ecc_size, &pos);
-		rem = page_size - pos;
-	}
-
-	aux_write(chip, &buf, rem, &pos);
-	aux_write(chip, &oob_orig, BBM_SIZE, &pos);
-	aux_write(chip, &buf, pkt_size - rem, &pos);
-	aux_write(chip, &oob, ecc_size, &pos);
-}
-
-static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-			       u8 *buf, int oob_required, int page)
-{
-	nand_read_page_op(chip, page, 0, NULL, 0);
-	raw_read(chip, buf, chip->oob_poi);
-	return 0;
-}
-
-static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				const u8 *buf, int oob_required, int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	raw_write(chip, buf, chip->oob_poi);
-	return nand_prog_page_end_op(chip);
-}
-
-static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			  int page)
-{
-	nand_read_page_op(chip, page, 0, NULL, 0);
-	raw_read(chip, NULL, chip->oob_poi);
-	return 0;
-}
-
-static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-			   int page)
-{
-	nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-	raw_write(chip, NULL, chip->oob_poi);
-	return nand_prog_page_end_op(chip);
-}
-
-static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-	if (idx >= ecc->steps)
-		return -ERANGE;
-
-	res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
-	res->length = ecc->bytes;
-
-	return 0;
-}
-
-static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
-{
-	return -ERANGE; /* no free space in spare area */
-}
-
-static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
-	.ecc	= oob_ecc,
-	.free	= oob_free,
-};
-
-static u32 to_ticks(int kHz, int ps)
-{
-	return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
-}
-
-static int tango_set_timings(struct mtd_info *mtd, int csline,
-			     const struct nand_data_interface *conf)
-{
-	const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct tango_nfc *nfc = to_tango_nfc(chip->controller);
-	struct tango_chip *tchip = to_tango_chip(chip);
-	u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
-	int kHz = nfc->freq_kHz;
-
-	if (IS_ERR(sdr))
-		return PTR_ERR(sdr);
-
-	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
-		return 0;
-
-	Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
-	Textw = to_ticks(kHz, sdr->tWB_max);
-	Twc = to_ticks(kHz, sdr->tWC_min);
-	Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
-
-	Tacc = to_ticks(kHz, sdr->tREA_max);
-	Thold = to_ticks(kHz, sdr->tREH_min);
-	Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
-	Textr = to_ticks(kHz, sdr->tRHZ_max);
-
-	tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
-	tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
-
-	return 0;
-}
-
-static int chip_init(struct device *dev, struct device_node *np)
-{
-	u32 cs;
-	int err, res;
-	struct mtd_info *mtd;
-	struct nand_chip *chip;
-	struct tango_chip *tchip;
-	struct nand_ecc_ctrl *ecc;
-	struct tango_nfc *nfc = dev_get_drvdata(dev);
-
-	tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
-	if (!tchip)
-		return -ENOMEM;
-
-	res = of_property_count_u32_elems(np, "reg");
-	if (res < 0)
-		return res;
-
-	if (res != 1)
-		return -ENOTSUPP; /* Multi-CS chips are not supported */
-
-	err = of_property_read_u32_index(np, "reg", 0, &cs);
-	if (err)
-		return err;
-
-	if (cs >= MAX_CS)
-		return -EINVAL;
-
-	chip = &tchip->nand_chip;
-	ecc = &chip->ecc;
-	mtd = nand_to_mtd(chip);
-
-	chip->read_byte = tango_read_byte;
-	chip->write_buf = tango_write_buf;
-	chip->read_buf = tango_read_buf;
-	chip->select_chip = tango_select_chip;
-	chip->cmd_ctrl = tango_cmd_ctrl;
-	chip->dev_ready = tango_dev_ready;
-	chip->setup_data_interface = tango_set_timings;
-	chip->options = NAND_USE_BOUNCE_BUFFER |
-			NAND_NO_SUBPAGE_WRITE |
-			NAND_WAIT_TCCS;
-	chip->controller = &nfc->hw;
-	tchip->base = nfc->pbus_base + (cs * 256);
-
-	nand_set_flash_node(chip, np);
-	mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
-	mtd->dev.parent = dev;
-
-	err = nand_scan_ident(mtd, 1, NULL);
-	if (err)
-		return err;
-
-	ecc->mode = NAND_ECC_HW;
-	ecc->algo = NAND_ECC_BCH;
-	ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
-
-	ecc->read_page_raw = tango_read_page_raw;
-	ecc->write_page_raw = tango_write_page_raw;
-	ecc->read_page = tango_read_page;
-	ecc->write_page = tango_write_page;
-	ecc->read_oob = tango_read_oob;
-	ecc->write_oob = tango_write_oob;
-
-	err = nand_scan_tail(mtd);
-	if (err)
-		return err;
-
-	tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
-	tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
-	tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
-	tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
-
-	err = mtd_device_register(mtd, NULL, 0);
-	if (err)
-		return err;
-
-	nfc->chips[cs] = tchip;
-
-	return 0;
-}
-
-static int tango_nand_remove(struct platform_device *pdev)
-{
-	int cs;
-	struct tango_nfc *nfc = platform_get_drvdata(pdev);
-
-	dma_release_channel(nfc->chan);
-
-	for (cs = 0; cs < MAX_CS; ++cs) {
-		if (nfc->chips[cs])
-			nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
-	}
-
-	return 0;
-}
-
-static int tango_nand_probe(struct platform_device *pdev)
-{
-	int err;
-	struct clk *clk;
-	struct resource *res;
-	struct tango_nfc *nfc;
-	struct device_node *np;
-
-	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
-	if (!nfc)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(nfc->reg_base))
-		return PTR_ERR(nfc->reg_base);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(nfc->mem_base))
-		return PTR_ERR(nfc->mem_base);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(nfc->pbus_base))
-		return PTR_ERR(nfc->pbus_base);
-
-	writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
-
-	clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-
-	nfc->chan = dma_request_chan(&pdev->dev, "rxtx");
-	if (IS_ERR(nfc->chan))
-		return PTR_ERR(nfc->chan);
-
-	platform_set_drvdata(pdev, nfc);
-	nand_hw_control_init(&nfc->hw);
-	nfc->freq_kHz = clk_get_rate(clk) / 1000;
-
-	for_each_child_of_node(pdev->dev.of_node, np) {
-		err = chip_init(&pdev->dev, np);
-		if (err) {
-			tango_nand_remove(pdev);
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-static const struct of_device_id tango_nand_ids[] = {
-	{ .compatible = "sigma,smp8758-nand" },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, tango_nand_ids);
-
-static struct platform_driver tango_nand_driver = {
-	.probe	= tango_nand_probe,
-	.remove	= tango_nand_remove,
-	.driver	= {
-		.name		= "tango-nand",
-		.of_match_table	= tango_nand_ids,
-	},
-};
-
-module_platform_driver(tango_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Sigma Designs");
-MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
deleted file mode 100644
index dcaa924502de..000000000000
--- a/drivers/mtd/nand/tmio_nand.c
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Toshiba TMIO NAND flash controller driver
- *
- * Slightly murky pre-git history of the driver:
- *
- * Copyright (c) Ian Molton 2004, 2005, 2008
- *    Original work, independent of sharps code. Included hardware ECC support.
- *    Hard ECC did not work for writes in the early revisions.
- * Copyright (c) Dirk Opfer 2005.
- *    Modifications developed from sharps code but
- *    NOT containing any, ported onto Ians base.
- * Copyright (c) Chris Humbert 2005
- * Copyright (c) Dmitry Baryshkov 2008
- *    Minor fixes
- *
- * Parts copyright Sebastian Carlier
- *
- * This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tmio.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/slab.h>
-
-/*--------------------------------------------------------------------------*/
-
-/*
- * NAND Flash Host Controller Configuration Register
- */
-#define CCR_COMMAND	0x04	/* w Command				*/
-#define CCR_BASE	0x10	/* l NAND Flash Control Reg Base Addr	*/
-#define CCR_INTP	0x3d	/* b Interrupt Pin			*/
-#define CCR_INTE	0x48	/* b Interrupt Enable			*/
-#define CCR_EC		0x4a	/* b Event Control			*/
-#define CCR_ICC		0x4c	/* b Internal Clock Control		*/
-#define CCR_ECCC	0x5b	/* b ECC Control			*/
-#define CCR_NFTC	0x60	/* b NAND Flash Transaction Control	*/
-#define CCR_NFM		0x61	/* b NAND Flash Monitor			*/
-#define CCR_NFPSC	0x62	/* b NAND Flash Power Supply Control	*/
-#define CCR_NFDC	0x63	/* b NAND Flash Detect Control		*/
-
-/*
- * NAND Flash Control Register
- */
-#define FCR_DATA	0x00	/* bwl Data Register			*/
-#define FCR_MODE	0x04	/* b Mode Register			*/
-#define FCR_STATUS	0x05	/* b Status Register			*/
-#define FCR_ISR		0x06	/* b Interrupt Status Register		*/
-#define FCR_IMR		0x07	/* b Interrupt Mask Register		*/
-
-/* FCR_MODE Register Command List */
-#define FCR_MODE_DATA	0x94	/* Data Data_Mode */
-#define FCR_MODE_COMMAND 0x95	/* Data Command_Mode */
-#define FCR_MODE_ADDRESS 0x96	/* Data Address_Mode */
-
-#define FCR_MODE_HWECC_CALC	0xB4	/* HW-ECC Data */
-#define FCR_MODE_HWECC_RESULT	0xD4	/* HW-ECC Calc result Read_Mode */
-#define FCR_MODE_HWECC_RESET	0xF4	/* HW-ECC Reset */
-
-#define FCR_MODE_POWER_ON	0x0C	/* Power Supply ON  to SSFDC card */
-#define FCR_MODE_POWER_OFF	0x08	/* Power Supply OFF to SSFDC card */
-
-#define FCR_MODE_LED_OFF	0x00	/* LED OFF */
-#define FCR_MODE_LED_ON		0x04	/* LED ON */
-
-#define FCR_MODE_EJECT_ON	0x68	/* Ejection events active  */
-#define FCR_MODE_EJECT_OFF	0x08	/* Ejection events ignored */
-
-#define FCR_MODE_LOCK		0x6C	/* Lock_Mode. Eject Switch Invalid */
-#define FCR_MODE_UNLOCK		0x0C	/* UnLock_Mode. Eject Switch is valid */
-
-#define FCR_MODE_CONTROLLER_ID	0x40	/* Controller ID Read */
-#define FCR_MODE_STANDBY	0x00	/* SSFDC card Changes Standby State */
-
-#define FCR_MODE_WE		0x80
-#define FCR_MODE_ECC1		0x40
-#define FCR_MODE_ECC0		0x20
-#define FCR_MODE_CE		0x10
-#define FCR_MODE_PCNT1		0x08
-#define FCR_MODE_PCNT0		0x04
-#define FCR_MODE_ALE		0x02
-#define FCR_MODE_CLE		0x01
-
-#define FCR_STATUS_BUSY		0x80
-
-/*--------------------------------------------------------------------------*/
-
-struct tmio_nand {
-	struct nand_chip chip;
-
-	struct platform_device *dev;
-
-	void __iomem *ccr;
-	void __iomem *fcr;
-	unsigned long fcr_base;
-
-	unsigned int irq;
-
-	/* for tmio_nand_read_byte */
-	u8			read;
-	unsigned read_good:1;
-};
-
-static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
-}
-
-
-/*--------------------------------------------------------------------------*/
-
-static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigned int ctrl)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		u8 mode;
-
-		if (ctrl & NAND_NCE) {
-			mode = FCR_MODE_DATA;
-
-			if (ctrl & NAND_CLE)
-				mode |=  FCR_MODE_CLE;
-			else
-				mode &= ~FCR_MODE_CLE;
-
-			if (ctrl & NAND_ALE)
-				mode |=  FCR_MODE_ALE;
-			else
-				mode &= ~FCR_MODE_ALE;
-		} else {
-			mode = FCR_MODE_STANDBY;
-		}
-
-		tmio_iowrite8(mode, tmio->fcr + FCR_MODE);
-		tmio->read_good = 0;
-	}
-
-	if (cmd != NAND_CMD_NONE)
-		tmio_iowrite8(cmd, chip->IO_ADDR_W);
-}
-
-static int tmio_nand_dev_ready(struct mtd_info *mtd)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-
-	return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
-}
-
-static irqreturn_t tmio_irq(int irq, void *__tmio)
-{
-	struct tmio_nand *tmio = __tmio;
-	struct nand_chip *nand_chip = &tmio->chip;
-
-	/* disable RDYREQ interrupt */
-	tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
-
-	if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
-		dev_warn(&tmio->dev->dev, "spurious interrupt\n");
-
-	wake_up(&nand_chip->controller->wq);
-	return IRQ_HANDLED;
-}
-
-/*
-  *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB.
-  *This interrupt is normally disabled, but for long operations like
-  *erase and write, we enable it to wake us up.  The irq handler
-  *disables the interrupt.
- */
-static int
-tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-	long timeout;
-	u8 status;
-
-	/* enable RDYREQ interrupt */
-	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
-	tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
-
-	timeout = wait_event_timeout(nand_chip->controller->wq,
-		tmio_nand_dev_ready(mtd),
-		msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
-
-	if (unlikely(!tmio_nand_dev_ready(mtd))) {
-		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
-		dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
-			nand_chip->state == FL_ERASING ? "erase" : "program",
-			nand_chip->state == FL_ERASING ? 400 : 20);
-
-	} else if (unlikely(!timeout)) {
-		tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
-		dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
-	}
-
-	nand_status_op(nand_chip, &status);
-	return status;
-}
-
-/*
-  *The TMIO controller combines two 8-bit data bytes into one 16-bit
-  *word. This function separates them so nand_base.c works as expected,
-  *especially its NAND_CMD_READID routines.
- *
-  *To prevent stale data from being read, tmio_nand_hwcontrol() clears
-  *tmio->read_good.
- */
-static u_char tmio_nand_read_byte(struct mtd_info *mtd)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-	unsigned int data;
-
-	if (tmio->read_good--)
-		return tmio->read;
-
-	data = tmio_ioread16(tmio->fcr + FCR_DATA);
-	tmio->read = data >> 8;
-	return data;
-}
-
-/*
-  *The TMIO controller converts an 8-bit NAND interface to a 16-bit
-  *bus interface, so all data reads and writes must be 16-bit wide.
-  *Thus, we implement 16-bit versions of the read, write, and verify
-  *buffer functions.
- */
-static void
-tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-
-	tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
-}
-
-static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-
-	tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
-}
-
-static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-
-	tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
-	tmio_ioread8(tmio->fcr + FCR_DATA);	/* dummy read */
-	tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
-}
-
-static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-							u_char *ecc_code)
-{
-	struct tmio_nand *tmio = mtd_to_tmio(mtd);
-	unsigned int ecc;
-
-	tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
-
-	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
-	ecc_code[1] = ecc;	/* 000-255 LP7-0 */
-	ecc_code[0] = ecc >> 8;	/* 000-255 LP15-8 */
-	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
-	ecc_code[2] = ecc;	/* 000-255 CP5-0,11b */
-	ecc_code[4] = ecc >> 8;	/* 256-511 LP7-0 */
-	ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
-	ecc_code[3] = ecc;	/* 256-511 LP15-8 */
-	ecc_code[5] = ecc >> 8;	/* 256-511 CP5-0,11b */
-
-	tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE);
-	return 0;
-}
-
-static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
-		unsigned char *read_ecc, unsigned char *calc_ecc)
-{
-	int r0, r1;
-
-	/* assume ecc.size = 512 and ecc.bytes = 6 */
-	r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
-	if (r0 < 0)
-		return r0;
-	r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
-	if (r1 < 0)
-		return r1;
-	return r0 + r1;
-}
-
-static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
-{
-	const struct mfd_cell *cell = mfd_get_cell(dev);
-	int ret;
-
-	if (cell->enable) {
-		ret = cell->enable(dev);
-		if (ret)
-			return ret;
-	}
-
-	/* (4Ch) CLKRUN Enable    1st spcrunc */
-	tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
-
-	/* (10h)BaseAddress    0x1000 spba.spba2 */
-	tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
-	tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
-
-	/* (04h)Command Register I/O spcmd */
-	tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
-
-	/* (62h) Power Supply Control ssmpwc */
-	/* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */
-	tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC);
-
-	/* (63h) Detect Control ssmdtc */
-	tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC);
-
-	/* Interrupt status register clear sintst */
-	tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
-
-	/* After power supply, Media are reset smode */
-	tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE);
-	tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE);
-	tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA);
-
-	/* Standby Mode smode */
-	tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE);
-
-	mdelay(5);
-
-	return 0;
-}
-
-static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
-{
-	const struct mfd_cell *cell = mfd_get_cell(dev);
-
-	tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
-	if (cell->disable)
-		cell->disable(dev);
-}
-
-static int tmio_probe(struct platform_device *dev)
-{
-	struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
-	struct resource *fcr = platform_get_resource(dev,
-			IORESOURCE_MEM, 0);
-	struct resource *ccr = platform_get_resource(dev,
-			IORESOURCE_MEM, 1);
-	int irq = platform_get_irq(dev, 0);
-	struct tmio_nand *tmio;
-	struct mtd_info *mtd;
-	struct nand_chip *nand_chip;
-	int retval;
-
-	if (data == NULL)
-		dev_warn(&dev->dev, "NULL platform data!\n");
-
-	tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
-	if (!tmio)
-		return -ENOMEM;
-
-	tmio->dev = dev;
-
-	platform_set_drvdata(dev, tmio);
-	nand_chip = &tmio->chip;
-	mtd = nand_to_mtd(nand_chip);
-	mtd->name = "tmio-nand";
-	mtd->dev.parent = &dev->dev;
-
-	tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
-	if (!tmio->ccr)
-		return -EIO;
-
-	tmio->fcr_base = fcr->start & 0xfffff;
-	tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
-	if (!tmio->fcr)
-		return -EIO;
-
-	retval = tmio_hw_init(dev, tmio);
-	if (retval)
-		return retval;
-
-	/* Set address of NAND IO lines */
-	nand_chip->IO_ADDR_R = tmio->fcr;
-	nand_chip->IO_ADDR_W = tmio->fcr;
-
-	/* Set address of hardware control function */
-	nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
-	nand_chip->dev_ready = tmio_nand_dev_ready;
-	nand_chip->read_byte = tmio_nand_read_byte;
-	nand_chip->write_buf = tmio_nand_write_buf;
-	nand_chip->read_buf = tmio_nand_read_buf;
-
-	/* set eccmode using hardware ECC */
-	nand_chip->ecc.mode = NAND_ECC_HW;
-	nand_chip->ecc.size = 512;
-	nand_chip->ecc.bytes = 6;
-	nand_chip->ecc.strength = 2;
-	nand_chip->ecc.hwctl = tmio_nand_enable_hwecc;
-	nand_chip->ecc.calculate = tmio_nand_calculate_ecc;
-	nand_chip->ecc.correct = tmio_nand_correct_data;
-
-	if (data)
-		nand_chip->badblock_pattern = data->badblock_pattern;
-
-	/* 15 us command delay time */
-	nand_chip->chip_delay = 15;
-
-	retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
-				  dev_name(&dev->dev), tmio);
-	if (retval) {
-		dev_err(&dev->dev, "request_irq error %d\n", retval);
-		goto err_irq;
-	}
-
-	tmio->irq = irq;
-	nand_chip->waitfunc = tmio_nand_wait;
-
-	/* Scan to find existence of the device */
-	retval = nand_scan(mtd, 1);
-	if (retval)
-		goto err_irq;
-
-	/* Register the partitions */
-	retval = mtd_device_parse_register(mtd,
-					   data ? data->part_parsers : NULL,
-					   NULL,
-					   data ? data->partition : NULL,
-					   data ? data->num_partitions : 0);
-	if (!retval)
-		return retval;
-
-	nand_release(mtd);
-
-err_irq:
-	tmio_hw_stop(dev, tmio);
-	return retval;
-}
-
-static int tmio_remove(struct platform_device *dev)
-{
-	struct tmio_nand *tmio = platform_get_drvdata(dev);
-
-	nand_release(nand_to_mtd(&tmio->chip));
-	tmio_hw_stop(dev, tmio);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int tmio_suspend(struct platform_device *dev, pm_message_t state)
-{
-	const struct mfd_cell *cell = mfd_get_cell(dev);
-
-	if (cell->suspend)
-		cell->suspend(dev);
-
-	tmio_hw_stop(dev, platform_get_drvdata(dev));
-	return 0;
-}
-
-static int tmio_resume(struct platform_device *dev)
-{
-	const struct mfd_cell *cell = mfd_get_cell(dev);
-
-	/* FIXME - is this required or merely another attack of the broken
-	 * SHARP platform? Looks suspicious.
-	 */
-	tmio_hw_init(dev, platform_get_drvdata(dev));
-
-	if (cell->resume)
-		cell->resume(dev);
-
-	return 0;
-}
-#else
-#define tmio_suspend NULL
-#define tmio_resume NULL
-#endif
-
-static struct platform_driver tmio_driver = {
-	.driver.name	= "tmio-nand",
-	.driver.owner	= THIS_MODULE,
-	.probe		= tmio_probe,
-	.remove		= tmio_remove,
-	.suspend	= tmio_suspend,
-	.resume		= tmio_resume,
-};
-
-module_platform_driver(tmio_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov");
-MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller");
-MODULE_ALIAS("platform:tmio-nand");
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
deleted file mode 100644
index b567d212fe7d..000000000000
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * TXx9 NAND flash memory controller driver
- * Based on RBTX49xx patch from CELF patch archive.
- *
- * 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.
- *
- * (C) Copyright TOSHIBA CORPORATION 2004-2007
- * All Rights Reserved.
- */
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <asm/txx9/ndfmc.h>
-
-/* TXX9 NDFMC Registers */
-#define TXX9_NDFDTR	0x00
-#define TXX9_NDFMCR	0x04
-#define TXX9_NDFSR	0x08
-#define TXX9_NDFISR	0x0c
-#define TXX9_NDFIMR	0x10
-#define TXX9_NDFSPR	0x14
-#define TXX9_NDFRSTR	0x18	/* not TX4939 */
-
-/* NDFMCR : NDFMC Mode Control */
-#define TXX9_NDFMCR_WE	0x80
-#define TXX9_NDFMCR_ECC_ALL	0x60
-#define TXX9_NDFMCR_ECC_RESET	0x60
-#define TXX9_NDFMCR_ECC_READ	0x40
-#define TXX9_NDFMCR_ECC_ON	0x20
-#define TXX9_NDFMCR_ECC_OFF	0x00
-#define TXX9_NDFMCR_CE	0x10
-#define TXX9_NDFMCR_BSPRT	0x04	/* TX4925/TX4926 only */
-#define TXX9_NDFMCR_ALE	0x02
-#define TXX9_NDFMCR_CLE	0x01
-/* TX4939 only */
-#define TXX9_NDFMCR_X16	0x0400
-#define TXX9_NDFMCR_DMAREQ_MASK	0x0300
-#define TXX9_NDFMCR_DMAREQ_NODMA	0x0000
-#define TXX9_NDFMCR_DMAREQ_128	0x0100
-#define TXX9_NDFMCR_DMAREQ_256	0x0200
-#define TXX9_NDFMCR_DMAREQ_512	0x0300
-#define TXX9_NDFMCR_CS_MASK	0x0c
-#define TXX9_NDFMCR_CS(ch)	((ch) << 2)
-
-/* NDFMCR : NDFMC Status */
-#define TXX9_NDFSR_BUSY	0x80
-/* TX4939 only */
-#define TXX9_NDFSR_DMARUN	0x40
-
-/* NDFMCR : NDFMC Reset */
-#define TXX9_NDFRSTR_RST	0x01
-
-struct txx9ndfmc_priv {
-	struct platform_device *dev;
-	struct nand_chip chip;
-	int cs;
-	const char *mtdname;
-};
-
-#define MAX_TXX9NDFMC_DEV	4
-struct txx9ndfmc_drvdata {
-	struct mtd_info *mtds[MAX_TXX9NDFMC_DEV];
-	void __iomem *base;
-	unsigned char hold;	/* in gbusclock */
-	unsigned char spw;	/* in gbusclock */
-	struct nand_hw_control hw_control;
-};
-
-static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
-	return txx9_priv->dev;
-}
-
-static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
-{
-	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
-
-	return drvdata->base + (reg << plat->shift);
-}
-
-static u32 txx9ndfmc_read(struct platform_device *dev, unsigned int reg)
-{
-	return __raw_readl(ndregaddr(dev, reg));
-}
-
-static void txx9ndfmc_write(struct platform_device *dev,
-			    u32 val, unsigned int reg)
-{
-	__raw_writel(val, ndregaddr(dev, reg));
-}
-
-static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
-{
-	struct platform_device *dev = mtd_to_platdev(mtd);
-
-	return txx9ndfmc_read(dev, TXX9_NDFDTR);
-}
-
-static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-				int len)
-{
-	struct platform_device *dev = mtd_to_platdev(mtd);
-	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
-	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
-
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_WE, TXX9_NDFMCR);
-	while (len--)
-		__raw_writel(*buf++, ndfdtr);
-	txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
-}
-
-static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct platform_device *dev = mtd_to_platdev(mtd);
-	void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
-
-	while (len--)
-		*buf++ = __raw_readl(ndfdtr);
-}
-
-static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
-			       unsigned int ctrl)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
-	struct platform_device *dev = txx9_priv->dev;
-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
-
-	if (ctrl & NAND_CTRL_CHANGE) {
-		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
-
-		mcr &= ~(TXX9_NDFMCR_CLE | TXX9_NDFMCR_ALE | TXX9_NDFMCR_CE);
-		mcr |= ctrl & NAND_CLE ? TXX9_NDFMCR_CLE : 0;
-		mcr |= ctrl & NAND_ALE ? TXX9_NDFMCR_ALE : 0;
-		/* TXX9_NDFMCR_CE bit is 0:high 1:low */
-		mcr |= ctrl & NAND_NCE ? TXX9_NDFMCR_CE : 0;
-		if (txx9_priv->cs >= 0 && (ctrl & NAND_NCE)) {
-			mcr &= ~TXX9_NDFMCR_CS_MASK;
-			mcr |= TXX9_NDFMCR_CS(txx9_priv->cs);
-		}
-		txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
-	}
-	if (cmd != NAND_CMD_NONE)
-		txx9ndfmc_write(dev, cmd & 0xff, TXX9_NDFDTR);
-	if (plat->flags & NDFMC_PLAT_FLAG_DUMMYWRITE) {
-		/* dummy write to update external latch */
-		if ((ctrl & NAND_CTRL_CHANGE) && cmd == NAND_CMD_NONE)
-			txx9ndfmc_write(dev, 0, TXX9_NDFDTR);
-	}
-	mmiowb();
-}
-
-static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
-{
-	struct platform_device *dev = mtd_to_platdev(mtd);
-
-	return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
-}
-
-static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
-				   uint8_t *ecc_code)
-{
-	struct platform_device *dev = mtd_to_platdev(mtd);
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int eccbytes;
-	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
-
-	mcr &= ~TXX9_NDFMCR_ECC_ALL;
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR);
-	for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) {
-		ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR);
-		ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR);
-		ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR);
-		ecc_code += 3;
-	}
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
-	return 0;
-}
-
-static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
-		unsigned char *read_ecc, unsigned char *calc_ecc)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int eccsize;
-	int corrected = 0;
-	int stat;
-
-	for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
-		stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
-		if (stat < 0)
-			return stat;
-		corrected += stat;
-		buf += 256;
-		read_ecc += 3;
-		calc_ecc += 3;
-	}
-	return corrected;
-}
-
-static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-{
-	struct platform_device *dev = mtd_to_platdev(mtd);
-	u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
-
-	mcr &= ~TXX9_NDFMCR_ECC_ALL;
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_RESET, TXX9_NDFMCR);
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR);
-	txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_ON, TXX9_NDFMCR);
-}
-
-static void txx9ndfmc_initialize(struct platform_device *dev)
-{
-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
-	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
-	int tmout = 100;
-
-	if (plat->flags & NDFMC_PLAT_FLAG_NO_RSTR)
-		; /* no NDFRSTR.  Write to NDFSPR resets the NDFMC. */
-	else {
-		/* reset NDFMC */
-		txx9ndfmc_write(dev,
-				txx9ndfmc_read(dev, TXX9_NDFRSTR) |
-				TXX9_NDFRSTR_RST,
-				TXX9_NDFRSTR);
-		while (txx9ndfmc_read(dev, TXX9_NDFRSTR) & TXX9_NDFRSTR_RST) {
-			if (--tmout == 0) {
-				dev_err(&dev->dev, "reset failed.\n");
-				break;
-			}
-			udelay(1);
-		}
-	}
-	/* setup Hold Time, Strobe Pulse Width */
-	txx9ndfmc_write(dev, (drvdata->hold << 4) | drvdata->spw, TXX9_NDFSPR);
-	txx9ndfmc_write(dev,
-			(plat->flags & NDFMC_PLAT_FLAG_USE_BSPRT) ?
-			TXX9_NDFMCR_BSPRT : 0, TXX9_NDFMCR);
-}
-
-#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
-	DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
-
-static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	int ret;
-
-	ret = nand_scan_ident(mtd, 1, NULL);
-	if (!ret) {
-		if (mtd->writesize >= 512) {
-			/* Hardware ECC 6 byte ECC per 512 Byte data */
-			chip->ecc.size = 512;
-			chip->ecc.bytes = 6;
-		}
-		ret = nand_scan_tail(mtd);
-	}
-	return ret;
-}
-
-static int __init txx9ndfmc_probe(struct platform_device *dev)
-{
-	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
-	int hold, spw;
-	int i;
-	struct txx9ndfmc_drvdata *drvdata;
-	unsigned long gbusclk = plat->gbus_clock;
-	struct resource *res;
-
-	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata)
-		return -ENOMEM;
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	drvdata->base = devm_ioremap_resource(&dev->dev, res);
-	if (IS_ERR(drvdata->base))
-		return PTR_ERR(drvdata->base);
-
-	hold = plat->hold ?: 20; /* tDH */
-	spw = plat->spw ?: 90; /* max(tREADID, tWP, tRP) */
-
-	hold = TXX9NDFMC_NS_TO_CYC(gbusclk, hold);
-	spw = TXX9NDFMC_NS_TO_CYC(gbusclk, spw);
-	if (plat->flags & NDFMC_PLAT_FLAG_HOLDADD)
-		hold -= 2;	/* actual hold time : (HOLD + 2) BUSCLK */
-	spw -= 1;	/* actual wait time : (SPW + 1) BUSCLK */
-	hold = clamp(hold, 1, 15);
-	drvdata->hold = hold;
-	spw = clamp(spw, 1, 15);
-	drvdata->spw = spw;
-	dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
-		 (gbusclk + 500000) / 1000000, hold, spw);
-
-	nand_hw_control_init(&drvdata->hw_control);
-
-	platform_set_drvdata(dev, drvdata);
-	txx9ndfmc_initialize(dev);
-
-	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
-		struct txx9ndfmc_priv *txx9_priv;
-		struct nand_chip *chip;
-		struct mtd_info *mtd;
-
-		if (!(plat->ch_mask & (1 << i)))
-			continue;
-		txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
-				    GFP_KERNEL);
-		if (!txx9_priv)
-			continue;
-		chip = &txx9_priv->chip;
-		mtd = nand_to_mtd(chip);
-		mtd->dev.parent = &dev->dev;
-
-		chip->read_byte = txx9ndfmc_read_byte;
-		chip->read_buf = txx9ndfmc_read_buf;
-		chip->write_buf = txx9ndfmc_write_buf;
-		chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
-		chip->dev_ready = txx9ndfmc_dev_ready;
-		chip->ecc.calculate = txx9ndfmc_calculate_ecc;
-		chip->ecc.correct = txx9ndfmc_correct_data;
-		chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
-		chip->ecc.mode = NAND_ECC_HW;
-		/* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
-		chip->ecc.size = 256;
-		chip->ecc.bytes = 3;
-		chip->ecc.strength = 1;
-		chip->chip_delay = 100;
-		chip->controller = &drvdata->hw_control;
-
-		nand_set_controller_data(chip, txx9_priv);
-		txx9_priv->dev = dev;
-
-		if (plat->ch_mask != 1) {
-			txx9_priv->cs = i;
-			txx9_priv->mtdname = kasprintf(GFP_KERNEL, "%s.%u",
-						       dev_name(&dev->dev), i);
-		} else {
-			txx9_priv->cs = -1;
-			txx9_priv->mtdname = kstrdup(dev_name(&dev->dev),
-						     GFP_KERNEL);
-		}
-		if (!txx9_priv->mtdname) {
-			kfree(txx9_priv);
-			dev_err(&dev->dev, "Unable to allocate MTD name.\n");
-			continue;
-		}
-		if (plat->wide_mask & (1 << i))
-			chip->options |= NAND_BUSWIDTH_16;
-
-		if (txx9ndfmc_nand_scan(mtd)) {
-			kfree(txx9_priv->mtdname);
-			kfree(txx9_priv);
-			continue;
-		}
-		mtd->name = txx9_priv->mtdname;
-
-		mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
-		drvdata->mtds[i] = mtd;
-	}
-
-	return 0;
-}
-
-static int __exit txx9ndfmc_remove(struct platform_device *dev)
-{
-	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
-	int i;
-
-	if (!drvdata)
-		return 0;
-	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
-		struct mtd_info *mtd = drvdata->mtds[i];
-		struct nand_chip *chip;
-		struct txx9ndfmc_priv *txx9_priv;
-
-		if (!mtd)
-			continue;
-		chip = mtd_to_nand(mtd);
-		txx9_priv = nand_get_controller_data(chip);
-
-		nand_release(mtd);
-		kfree(txx9_priv->mtdname);
-		kfree(txx9_priv);
-	}
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int txx9ndfmc_resume(struct platform_device *dev)
-{
-	if (platform_get_drvdata(dev))
-		txx9ndfmc_initialize(dev);
-	return 0;
-}
-#else
-#define txx9ndfmc_resume NULL
-#endif
-
-static struct platform_driver txx9ndfmc_driver = {
-	.remove		= __exit_p(txx9ndfmc_remove),
-	.resume		= txx9ndfmc_resume,
-	.driver		= {
-		.name	= "txx9ndfmc",
-	},
-};
-
-module_platform_driver_probe(txx9ndfmc_driver, txx9ndfmc_probe);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("TXx9 SoC NAND flash controller driver");
-MODULE_ALIAS("platform:txx9ndfmc");
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
deleted file mode 100644
index f367144f3c6f..000000000000
--- a/drivers/mtd/nand/vf610_nfc.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
- *
- * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
- * Jason ported to M54418TWR and MVFA5 (VF610).
- * Authors: Stefan Agner <stefan.agner@toradex.com>
- *          Bill Pringlemeir <bpringlemeir@nbsps.com>
- *          Shaohui Xie <b21989@freescale.com>
- *          Jason Jin <Jason.jin@freescale.com>
- *
- * Based on original driver mpc5121_nfc.c.
- *
- * This 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.
- *
- * Limitations:
- * - Untested on MPC5125 and M54418.
- * - DMA and pipelining not used.
- * - 2K pages or less.
- * - HW ECC: Only 2K page with 64+ OOB.
- * - HW ECC: Only 24 and 32-bit error correction implemented.
- */
-
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#define	DRV_NAME		"vf610_nfc"
-
-/* Register Offsets */
-#define NFC_FLASH_CMD1			0x3F00
-#define NFC_FLASH_CMD2			0x3F04
-#define NFC_COL_ADDR			0x3F08
-#define NFC_ROW_ADDR			0x3F0c
-#define NFC_ROW_ADDR_INC		0x3F14
-#define NFC_FLASH_STATUS1		0x3F18
-#define NFC_FLASH_STATUS2		0x3F1c
-#define NFC_CACHE_SWAP			0x3F28
-#define NFC_SECTOR_SIZE			0x3F2c
-#define NFC_FLASH_CONFIG		0x3F30
-#define NFC_IRQ_STATUS			0x3F38
-
-/* Addresses for NFC MAIN RAM BUFFER areas */
-#define NFC_MAIN_AREA(n)		((n) *  0x1000)
-
-#define PAGE_2K				0x0800
-#define OOB_64				0x0040
-#define OOB_MAX				0x0100
-
-/*
- * NFC_CMD2[CODE] values. See section:
- *  - 31.4.7 Flash Command Code Description, Vybrid manual
- *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
- *
- * Briefly these are bitmasks of controller cycles.
- */
-#define READ_PAGE_CMD_CODE		0x7EE0
-#define READ_ONFI_PARAM_CMD_CODE	0x4860
-#define PROGRAM_PAGE_CMD_CODE		0x7FC0
-#define ERASE_CMD_CODE			0x4EC0
-#define READ_ID_CMD_CODE		0x4804
-#define RESET_CMD_CODE			0x4040
-#define STATUS_READ_CMD_CODE		0x4068
-
-/* NFC ECC mode define */
-#define ECC_BYPASS			0
-#define ECC_45_BYTE			6
-#define ECC_60_BYTE			7
-
-/*** Register Mask and bit definitions */
-
-/* NFC_FLASH_CMD1 Field */
-#define CMD_BYTE2_MASK				0xFF000000
-#define CMD_BYTE2_SHIFT				24
-
-/* NFC_FLASH_CM2 Field */
-#define CMD_BYTE1_MASK				0xFF000000
-#define CMD_BYTE1_SHIFT				24
-#define CMD_CODE_MASK				0x00FFFF00
-#define CMD_CODE_SHIFT				8
-#define BUFNO_MASK				0x00000006
-#define BUFNO_SHIFT				1
-#define START_BIT				BIT(0)
-
-/* NFC_COL_ADDR Field */
-#define COL_ADDR_MASK				0x0000FFFF
-#define COL_ADDR_SHIFT				0
-
-/* NFC_ROW_ADDR Field */
-#define ROW_ADDR_MASK				0x00FFFFFF
-#define ROW_ADDR_SHIFT				0
-#define ROW_ADDR_CHIP_SEL_RB_MASK		0xF0000000
-#define ROW_ADDR_CHIP_SEL_RB_SHIFT		28
-#define ROW_ADDR_CHIP_SEL_MASK			0x0F000000
-#define ROW_ADDR_CHIP_SEL_SHIFT			24
-
-/* NFC_FLASH_STATUS2 Field */
-#define STATUS_BYTE1_MASK			0x000000FF
-
-/* NFC_FLASH_CONFIG Field */
-#define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000
-#define CONFIG_ECC_SRAM_ADDR_SHIFT		22
-#define CONFIG_ECC_SRAM_REQ_BIT			BIT(21)
-#define CONFIG_DMA_REQ_BIT			BIT(20)
-#define CONFIG_ECC_MODE_MASK			0x000E0000
-#define CONFIG_ECC_MODE_SHIFT			17
-#define CONFIG_FAST_FLASH_BIT			BIT(16)
-#define CONFIG_16BIT				BIT(7)
-#define CONFIG_BOOT_MODE_BIT			BIT(6)
-#define CONFIG_ADDR_AUTO_INCR_BIT		BIT(5)
-#define CONFIG_BUFNO_AUTO_INCR_BIT		BIT(4)
-#define CONFIG_PAGE_CNT_MASK			0xF
-#define CONFIG_PAGE_CNT_SHIFT			0
-
-/* NFC_IRQ_STATUS Field */
-#define IDLE_IRQ_BIT				BIT(29)
-#define IDLE_EN_BIT				BIT(20)
-#define CMD_DONE_CLEAR_BIT			BIT(18)
-#define IDLE_CLEAR_BIT				BIT(17)
-
-/*
- * ECC status - seems to consume 8 bytes (double word). The documented
- * status byte is located in the lowest byte of the second word (which is
- * the 4th or 7th byte depending on endianness).
- * Calculate an offset to store the ECC status at the end of the buffer.
- */
-#define ECC_SRAM_ADDR		(PAGE_2K + OOB_MAX - 8)
-
-#define ECC_STATUS		0x4
-#define ECC_STATUS_MASK		0x80
-#define ECC_STATUS_ERR_COUNT	0x3F
-
-enum vf610_nfc_alt_buf {
-	ALT_BUF_DATA = 0,
-	ALT_BUF_ID = 1,
-	ALT_BUF_STAT = 2,
-	ALT_BUF_ONFI = 3,
-};
-
-enum vf610_nfc_variant {
-	NFC_VFC610 = 1,
-};
-
-struct vf610_nfc {
-	struct nand_chip chip;
-	struct device *dev;
-	void __iomem *regs;
-	struct completion cmd_done;
-	uint buf_offset;
-	int write_sz;
-	/* Status and ID are in alternate locations. */
-	enum vf610_nfc_alt_buf alt_buf;
-	enum vf610_nfc_variant variant;
-	struct clk *clk;
-	bool use_hw_ecc;
-	u32 ecc_mode;
-};
-
-static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
-{
-	return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
-}
-
-static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
-{
-	return readl(nfc->regs + reg);
-}
-
-static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
-{
-	writel(val, nfc->regs + reg);
-}
-
-static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
-{
-	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
-}
-
-static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
-{
-	vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
-}
-
-static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
-				       u32 mask, u32 shift, u32 val)
-{
-	vf610_nfc_write(nfc, reg,
-			(vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
-}
-
-static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src,
-				    size_t n)
-{
-	/*
-	 * Use this accessor for the internal SRAM buffers. On the ARM
-	 * Freescale Vybrid SoC it's known that the driver can treat
-	 * the SRAM buffer as if it's memory. Other platform might need
-	 * to treat the buffers differently.
-	 *
-	 * For the time being, use memcpy
-	 */
-	memcpy(dst, src, n);
-}
-
-/* Clear flags for upcoming command */
-static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
-{
-	u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
-
-	tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
-	vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
-}
-
-static void vf610_nfc_done(struct vf610_nfc *nfc)
-{
-	unsigned long timeout = msecs_to_jiffies(100);
-
-	/*
-	 * Barrier is needed after this write. This write need
-	 * to be done before reading the next register the first
-	 * time.
-	 * vf610_nfc_set implicates such a barrier by using writel
-	 * to write to the register.
-	 */
-	vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
-	vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
-
-	if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
-		dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
-
-	vf610_nfc_clear_status(nfc);
-}
-
-static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col)
-{
-	u32 flash_id;
-
-	if (col < 4) {
-		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1);
-		flash_id >>= (3 - col) * 8;
-	} else {
-		flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2);
-		flash_id >>= 24;
-	}
-
-	return flash_id & 0xff;
-}
-
-static u8 vf610_nfc_get_status(struct vf610_nfc *nfc)
-{
-	return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
-}
-
-static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1,
-				   u32 cmd_code)
-{
-	u32 tmp;
-
-	vf610_nfc_clear_status(nfc);
-
-	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2);
-	tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
-	tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
-	tmp |= cmd_code << CMD_CODE_SHIFT;
-	vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp);
-}
-
-static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1,
-				    u32 cmd_byte2, u32 cmd_code)
-{
-	u32 tmp;
-
-	vf610_nfc_send_command(nfc, cmd_byte1, cmd_code);
-
-	tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1);
-	tmp &= ~CMD_BYTE2_MASK;
-	tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
-	vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp);
-}
-
-static irqreturn_t vf610_nfc_irq(int irq, void *data)
-{
-	struct mtd_info *mtd = data;
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-
-	vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
-	complete(&nfc->cmd_done);
-
-	return IRQ_HANDLED;
-}
-
-static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
-{
-	if (column != -1) {
-		if (nfc->chip.options & NAND_BUSWIDTH_16)
-			column = column / 2;
-		vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
-				    COL_ADDR_SHIFT, column);
-	}
-	if (page != -1)
-		vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
-				    ROW_ADDR_SHIFT, page);
-}
-
-static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
-{
-	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
-			    CONFIG_ECC_MODE_MASK,
-			    CONFIG_ECC_MODE_SHIFT, ecc_mode);
-}
-
-static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
-{
-	vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
-}
-
-static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
-			      int column, int page)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-	int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
-
-	nfc->buf_offset = max(column, 0);
-	nfc->alt_buf = ALT_BUF_DATA;
-
-	switch (command) {
-	case NAND_CMD_SEQIN:
-		/* Use valid column/page from preread... */
-		vf610_nfc_addr_cycle(nfc, column, page);
-		nfc->buf_offset = 0;
-
-		/*
-		 * SEQIN => data => PAGEPROG sequence is done by the controller
-		 * hence we do not need to issue the command here...
-		 */
-		return;
-	case NAND_CMD_PAGEPROG:
-		trfr_sz += nfc->write_sz;
-		vf610_nfc_transfer_size(nfc, trfr_sz);
-		vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
-					command, PROGRAM_PAGE_CMD_CODE);
-		if (nfc->use_hw_ecc)
-			vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
-		else
-			vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
-		break;
-
-	case NAND_CMD_RESET:
-		vf610_nfc_transfer_size(nfc, 0);
-		vf610_nfc_send_command(nfc, command, RESET_CMD_CODE);
-		break;
-
-	case NAND_CMD_READOOB:
-		trfr_sz += mtd->oobsize;
-		column = mtd->writesize;
-		vf610_nfc_transfer_size(nfc, trfr_sz);
-		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
-					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
-		vf610_nfc_addr_cycle(nfc, column, page);
-		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
-		break;
-
-	case NAND_CMD_READ0:
-		trfr_sz += mtd->writesize + mtd->oobsize;
-		vf610_nfc_transfer_size(nfc, trfr_sz);
-		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
-					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
-		vf610_nfc_addr_cycle(nfc, column, page);
-		vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
-		break;
-
-	case NAND_CMD_PARAM:
-		nfc->alt_buf = ALT_BUF_ONFI;
-		trfr_sz = 3 * sizeof(struct nand_onfi_params);
-		vf610_nfc_transfer_size(nfc, trfr_sz);
-		vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
-		vf610_nfc_addr_cycle(nfc, -1, column);
-		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
-		break;
-
-	case NAND_CMD_ERASE1:
-		vf610_nfc_transfer_size(nfc, 0);
-		vf610_nfc_send_commands(nfc, command,
-					NAND_CMD_ERASE2, ERASE_CMD_CODE);
-		vf610_nfc_addr_cycle(nfc, column, page);
-		break;
-
-	case NAND_CMD_READID:
-		nfc->alt_buf = ALT_BUF_ID;
-		nfc->buf_offset = 0;
-		vf610_nfc_transfer_size(nfc, 0);
-		vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE);
-		vf610_nfc_addr_cycle(nfc, -1, column);
-		break;
-
-	case NAND_CMD_STATUS:
-		nfc->alt_buf = ALT_BUF_STAT;
-		vf610_nfc_transfer_size(nfc, 0);
-		vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE);
-		break;
-	default:
-		return;
-	}
-
-	vf610_nfc_done(nfc);
-
-	nfc->use_hw_ecc = false;
-	nfc->write_sz = 0;
-}
-
-static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-	uint c = nfc->buf_offset;
-
-	/* Alternate buffers are only supported through read_byte */
-	WARN_ON(nfc->alt_buf);
-
-	vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
-
-	nfc->buf_offset += len;
-}
-
-static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-				int len)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-	uint c = nfc->buf_offset;
-	uint l;
-
-	l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
-	vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
-
-	nfc->write_sz += l;
-	nfc->buf_offset += l;
-}
-
-static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-	u8 tmp;
-	uint c = nfc->buf_offset;
-
-	switch (nfc->alt_buf) {
-	case ALT_BUF_ID:
-		tmp = vf610_nfc_get_id(nfc, c);
-		break;
-	case ALT_BUF_STAT:
-		tmp = vf610_nfc_get_status(nfc);
-		break;
-#ifdef __LITTLE_ENDIAN
-	case ALT_BUF_ONFI:
-		/* Reverse byte since the controller uses big endianness */
-		c = nfc->buf_offset ^ 0x3;
-		/* fall-through */
-#endif
-	default:
-		tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
-		break;
-	}
-	nfc->buf_offset++;
-	return tmp;
-}
-
-static u16 vf610_nfc_read_word(struct mtd_info *mtd)
-{
-	u16 tmp;
-
-	vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
-	return tmp;
-}
-
-/* If not provided, upper layers apply a fixed delay. */
-static int vf610_nfc_dev_ready(struct mtd_info *mtd)
-{
-	/* NFC handles R/B internally; always ready.  */
-	return 1;
-}
-
-/*
- * This function supports Vybrid only (MPC5125 would have full RB and four CS)
- */
-static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-	u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
-
-	/* Vybrid only (MPC5125 would have full RB and four CS) */
-	if (nfc->variant != NFC_VFC610)
-		return;
-
-	tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
-
-	if (chip >= 0) {
-		tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
-		tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
-	}
-
-	vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
-}
-
-/* Count the number of 0's in buff up to max_bits */
-static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
-{
-	uint32_t *buff32 = (uint32_t *)buff;
-	int k, written_bits = 0;
-
-	for (k = 0; k < (size / 4); k++) {
-		written_bits += hweight32(~buff32[k]);
-		if (unlikely(written_bits > max_bits))
-			break;
-	}
-
-	return written_bits;
-}
-
-static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
-					 uint8_t *oob, int page)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-	u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
-	u8 ecc_status;
-	u8 ecc_count;
-	int flips_threshold = nfc->chip.ecc.strength / 2;
-
-	ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
-	ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
-
-	if (!(ecc_status & ECC_STATUS_MASK))
-		return ecc_count;
-
-	/* Read OOB without ECC unit enabled */
-	vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
-	vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
-
-	/*
-	 * On an erased page, bit count (including OOB) should be zero or
-	 * at least less then half of the ECC strength.
-	 */
-	return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob,
-					   mtd->oobsize, NULL, 0,
-					   flips_threshold);
-}
-
-static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
-{
-	int eccsize = chip->ecc.size;
-	int stat;
-
-	nand_read_page_op(chip, page, 0, buf, eccsize);
-	if (oob_required)
-		vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
-
-	if (stat < 0) {
-		mtd->ecc_stats.failed++;
-		return 0;
-	} else {
-		mtd->ecc_stats.corrected += stat;
-		return stat;
-	}
-}
-
-static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-				const uint8_t *buf, int oob_required, int page)
-{
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-
-	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-	if (oob_required)
-		vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	/* Always write whole page including OOB due to HW ECC */
-	nfc->use_hw_ecc = true;
-	nfc->write_sz = mtd->writesize + mtd->oobsize;
-
-	return nand_prog_page_end_op(chip);
-}
-
-static const struct of_device_id vf610_nfc_dt_ids[] = {
-	{ .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
-
-static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
-{
-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
-	vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
-	vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
-
-	/* Disable virtual pages, only one elementary transfer unit */
-	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
-			    CONFIG_PAGE_CNT_SHIFT, 1);
-}
-
-static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
-{
-	if (nfc->chip.options & NAND_BUSWIDTH_16)
-		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
-	else
-		vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
-
-	if (nfc->chip.ecc.mode == NAND_ECC_HW) {
-		/* Set ECC status offset in SRAM */
-		vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
-				    CONFIG_ECC_SRAM_ADDR_MASK,
-				    CONFIG_ECC_SRAM_ADDR_SHIFT,
-				    ECC_SRAM_ADDR >> 3);
-
-		/* Enable ECC status in SRAM */
-		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
-	}
-}
-
-static int vf610_nfc_probe(struct platform_device *pdev)
-{
-	struct vf610_nfc *nfc;
-	struct resource *res;
-	struct mtd_info *mtd;
-	struct nand_chip *chip;
-	struct device_node *child;
-	const struct of_device_id *of_id;
-	int err;
-	int irq;
-
-	nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
-	if (!nfc)
-		return -ENOMEM;
-
-	nfc->dev = &pdev->dev;
-	chip = &nfc->chip;
-	mtd = nand_to_mtd(chip);
-
-	mtd->owner = THIS_MODULE;
-	mtd->dev.parent = nfc->dev;
-	mtd->name = DRV_NAME;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0)
-		return -EINVAL;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	nfc->regs = devm_ioremap_resource(nfc->dev, res);
-	if (IS_ERR(nfc->regs))
-		return PTR_ERR(nfc->regs);
-
-	nfc->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(nfc->clk))
-		return PTR_ERR(nfc->clk);
-
-	err = clk_prepare_enable(nfc->clk);
-	if (err) {
-		dev_err(nfc->dev, "Unable to enable clock!\n");
-		return err;
-	}
-
-	of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
-	nfc->variant = (enum vf610_nfc_variant)of_id->data;
-
-	for_each_available_child_of_node(nfc->dev->of_node, child) {
-		if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
-
-			if (nand_get_flash_node(chip)) {
-				dev_err(nfc->dev,
-					"Only one NAND chip supported!\n");
-				err = -EINVAL;
-				goto error;
-			}
-
-			nand_set_flash_node(chip, child);
-		}
-	}
-
-	if (!nand_get_flash_node(chip)) {
-		dev_err(nfc->dev, "NAND chip sub-node missing!\n");
-		err = -ENODEV;
-		goto err_clk;
-	}
-
-	chip->dev_ready = vf610_nfc_dev_ready;
-	chip->cmdfunc = vf610_nfc_command;
-	chip->read_byte = vf610_nfc_read_byte;
-	chip->read_word = vf610_nfc_read_word;
-	chip->read_buf = vf610_nfc_read_buf;
-	chip->write_buf = vf610_nfc_write_buf;
-	chip->select_chip = vf610_nfc_select_chip;
-	chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
-	chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
-
-	chip->options |= NAND_NO_SUBPAGE_WRITE;
-
-	init_completion(&nfc->cmd_done);
-
-	err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
-	if (err) {
-		dev_err(nfc->dev, "Error requesting IRQ!\n");
-		goto error;
-	}
-
-	vf610_nfc_preinit_controller(nfc);
-
-	/* first scan to find the device and get the page size */
-	err = nand_scan_ident(mtd, 1, NULL);
-	if (err)
-		goto error;
-
-	vf610_nfc_init_controller(nfc);
-
-	/* Bad block options. */
-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
-		chip->bbt_options |= NAND_BBT_NO_OOB;
-
-	/* Single buffer only, max 256 OOB minus ECC status */
-	if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
-		dev_err(nfc->dev, "Unsupported flash page size\n");
-		err = -ENXIO;
-		goto error;
-	}
-
-	if (chip->ecc.mode == NAND_ECC_HW) {
-		if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
-			dev_err(nfc->dev, "Unsupported flash with hwecc\n");
-			err = -ENXIO;
-			goto error;
-		}
-
-		if (chip->ecc.size != mtd->writesize) {
-			dev_err(nfc->dev, "Step size needs to be page size\n");
-			err = -ENXIO;
-			goto error;
-		}
-
-		/* Only 64 byte ECC layouts known */
-		if (mtd->oobsize > 64)
-			mtd->oobsize = 64;
-
-		/* Use default large page ECC layout defined in NAND core */
-		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-		if (chip->ecc.strength == 32) {
-			nfc->ecc_mode = ECC_60_BYTE;
-			chip->ecc.bytes = 60;
-		} else if (chip->ecc.strength == 24) {
-			nfc->ecc_mode = ECC_45_BYTE;
-			chip->ecc.bytes = 45;
-		} else {
-			dev_err(nfc->dev, "Unsupported ECC strength\n");
-			err = -ENXIO;
-			goto error;
-		}
-
-		chip->ecc.read_page = vf610_nfc_read_page;
-		chip->ecc.write_page = vf610_nfc_write_page;
-
-		chip->ecc.size = PAGE_2K;
-	}
-
-	/* second phase scan */
-	err = nand_scan_tail(mtd);
-	if (err)
-		goto error;
-
-	platform_set_drvdata(pdev, mtd);
-
-	/* Register device in MTD */
-	return mtd_device_register(mtd, NULL, 0);
-
-error:
-	of_node_put(nand_get_flash_node(chip));
-err_clk:
-	clk_disable_unprepare(nfc->clk);
-	return err;
-}
-
-static int vf610_nfc_remove(struct platform_device *pdev)
-{
-	struct mtd_info *mtd = platform_get_drvdata(pdev);
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-
-	nand_release(mtd);
-	clk_disable_unprepare(nfc->clk);
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int vf610_nfc_suspend(struct device *dev)
-{
-	struct mtd_info *mtd = dev_get_drvdata(dev);
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-
-	clk_disable_unprepare(nfc->clk);
-	return 0;
-}
-
-static int vf610_nfc_resume(struct device *dev)
-{
-	int err;
-
-	struct mtd_info *mtd = dev_get_drvdata(dev);
-	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
-
-	err = clk_prepare_enable(nfc->clk);
-	if (err)
-		return err;
-
-	vf610_nfc_preinit_controller(nfc);
-	vf610_nfc_init_controller(nfc);
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
-
-static struct platform_driver vf610_nfc_driver = {
-	.driver		= {
-		.name	= DRV_NAME,
-		.of_match_table = vf610_nfc_dt_ids,
-		.pm	= &vf610_nfc_pm_ops,
-	},
-	.probe		= vf610_nfc_probe,
-	.remove		= vf610_nfc_remove,
-};
-
-module_platform_driver(vf610_nfc_driver);
-
-MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
-MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c
deleted file mode 100644
index 9926b4e3d69d..000000000000
--- a/drivers/mtd/nand/xway_nand.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- *  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.
- *
- *  Copyright © 2012 John Crispin <john@phrozen.org>
- *  Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
- */
-
-#include <linux/mtd/rawnand.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
-
-#include <lantiq_soc.h>
-
-/* nand registers */
-#define EBU_ADDSEL1		0x24
-#define EBU_NAND_CON		0xB0
-#define EBU_NAND_WAIT		0xB4
-#define  NAND_WAIT_RD		BIT(0) /* NAND flash status output */
-#define  NAND_WAIT_WR_C		BIT(3) /* NAND Write/Read complete */
-#define EBU_NAND_ECC0		0xB8
-#define EBU_NAND_ECC_AC		0xBC
-
-/*
- * nand commands
- * The pins of the NAND chip are selected based on the address bits of the
- * "register" read and write. There are no special registers, but an
- * address range and the lower address bits are used to activate the
- * correct line. For example when the bit (1 << 2) is set in the address
- * the ALE pin will be activated.
- */
-#define NAND_CMD_ALE		BIT(2) /* address latch enable */
-#define NAND_CMD_CLE		BIT(3) /* command latch enable */
-#define NAND_CMD_CS		BIT(4) /* chip select */
-#define NAND_CMD_SE		BIT(5) /* spare area access latch */
-#define NAND_CMD_WP		BIT(6) /* write protect */
-#define NAND_WRITE_CMD		(NAND_CMD_CS | NAND_CMD_CLE)
-#define NAND_WRITE_ADDR		(NAND_CMD_CS | NAND_CMD_ALE)
-#define NAND_WRITE_DATA		(NAND_CMD_CS)
-#define NAND_READ_DATA		(NAND_CMD_CS)
-
-/* we need to tel the ebu which addr we mapped the nand to */
-#define ADDSEL1_MASK(x)		(x << 4)
-#define ADDSEL1_REGEN		1
-
-/* we need to tell the EBU that we have nand attached and set it up properly */
-#define BUSCON1_SETUP		(1 << 22)
-#define BUSCON1_BCGEN_RES	(0x3 << 12)
-#define BUSCON1_WAITWRC2	(2 << 8)
-#define BUSCON1_WAITRDC2	(2 << 6)
-#define BUSCON1_HOLDC1		(1 << 4)
-#define BUSCON1_RECOVC1		(1 << 2)
-#define BUSCON1_CMULT4		1
-
-#define NAND_CON_CE		(1 << 20)
-#define NAND_CON_OUT_CS1	(1 << 10)
-#define NAND_CON_IN_CS1		(1 << 8)
-#define NAND_CON_PRE_P		(1 << 7)
-#define NAND_CON_WP_P		(1 << 6)
-#define NAND_CON_SE_P		(1 << 5)
-#define NAND_CON_CS_P		(1 << 4)
-#define NAND_CON_CSMUX		(1 << 1)
-#define NAND_CON_NANDM		1
-
-struct xway_nand_data {
-	struct nand_chip	chip;
-	unsigned long		csflags;
-	void __iomem		*nandaddr;
-};
-
-static u8 xway_readb(struct mtd_info *mtd, int op)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct xway_nand_data *data = nand_get_controller_data(chip);
-
-	return readb(data->nandaddr + op);
-}
-
-static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct xway_nand_data *data = nand_get_controller_data(chip);
-
-	writeb(value, data->nandaddr + op);
-}
-
-static void xway_select_chip(struct mtd_info *mtd, int select)
-{
-	struct nand_chip *chip = mtd_to_nand(mtd);
-	struct xway_nand_data *data = nand_get_controller_data(chip);
-
-	switch (select) {
-	case -1:
-		ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
-		ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
-		spin_unlock_irqrestore(&ebu_lock, data->csflags);
-		break;
-	case 0:
-		spin_lock_irqsave(&ebu_lock, data->csflags);
-		ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
-		ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
-		break;
-	default:
-		BUG();
-	}
-}
-
-static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-	if (cmd == NAND_CMD_NONE)
-		return;
-
-	if (ctrl & NAND_CLE)
-		xway_writeb(mtd, NAND_WRITE_CMD, cmd);
-	else if (ctrl & NAND_ALE)
-		xway_writeb(mtd, NAND_WRITE_ADDR, cmd);
-
-	while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
-		;
-}
-
-static int xway_dev_ready(struct mtd_info *mtd)
-{
-	return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
-}
-
-static unsigned char xway_read_byte(struct mtd_info *mtd)
-{
-	return xway_readb(mtd, NAND_READ_DATA);
-}
-
-static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
-}
-
-static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
-}
-
-/*
- * Probe for the NAND device.
- */
-static int xway_nand_probe(struct platform_device *pdev)
-{
-	struct xway_nand_data *data;
-	struct mtd_info *mtd;
-	struct resource *res;
-	int err;
-	u32 cs;
-	u32 cs_flag = 0;
-
-	/* Allocate memory for the device structure (and zero it) */
-	data = devm_kzalloc(&pdev->dev, sizeof(struct xway_nand_data),
-			    GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	data->nandaddr = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(data->nandaddr))
-		return PTR_ERR(data->nandaddr);
-
-	nand_set_flash_node(&data->chip, pdev->dev.of_node);
-	mtd = nand_to_mtd(&data->chip);
-	mtd->dev.parent = &pdev->dev;
-
-	data->chip.cmd_ctrl = xway_cmd_ctrl;
-	data->chip.dev_ready = xway_dev_ready;
-	data->chip.select_chip = xway_select_chip;
-	data->chip.write_buf = xway_write_buf;
-	data->chip.read_buf = xway_read_buf;
-	data->chip.read_byte = xway_read_byte;
-	data->chip.chip_delay = 30;
-
-	data->chip.ecc.mode = NAND_ECC_SOFT;
-	data->chip.ecc.algo = NAND_ECC_HAMMING;
-
-	platform_set_drvdata(pdev, data);
-	nand_set_controller_data(&data->chip, data);
-
-	/* load our CS from the DT. Either we find a valid 1 or default to 0 */
-	err = of_property_read_u32(pdev->dev.of_node, "lantiq,cs", &cs);
-	if (!err && cs == 1)
-		cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
-
-	/* setup the EBU to run in NAND mode on our base addr */
-	ltq_ebu_w32(CPHYSADDR(data->nandaddr)
-		    | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
-
-	ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
-		    | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
-		    | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
-
-	ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
-		    | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
-		    | cs_flag, EBU_NAND_CON);
-
-	/* Scan to find existence of the device */
-	err = nand_scan(mtd, 1);
-	if (err)
-		return err;
-
-	err = mtd_device_register(mtd, NULL, 0);
-	if (err)
-		nand_release(mtd);
-
-	return err;
-}
-
-/*
- * Remove a NAND device.
- */
-static int xway_nand_remove(struct platform_device *pdev)
-{
-	struct xway_nand_data *data = platform_get_drvdata(pdev);
-
-	nand_release(nand_to_mtd(&data->chip));
-
-	return 0;
-}
-
-static const struct of_device_id xway_nand_match[] = {
-	{ .compatible = "lantiq,nand-xway" },
-	{},
-};
-
-static struct platform_driver xway_nand_driver = {
-	.probe	= xway_nand_probe,
-	.remove	= xway_nand_remove,
-	.driver	= {
-		.name		= "lantiq,nand-xway",
-		.of_match_table = xway_nand_match,
-	},
-};
-
-builtin_platform_driver(xway_nand_driver);
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 4237c7cebf02..fa176f5937bb 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -17,7 +17,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/mtd/nand_ecc.h>
-#include "nand/sm_common.h"
+#include "nand/raw/sm_common.h"
 #include "sm_ftl.h"
 
 
diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig
index 1aaa7a95ebc4..ae9e7f7cb31c 100644
--- a/drivers/net/dsa/mv88e6xxx/Kconfig
+++ b/drivers/net/dsa/mv88e6xxx/Kconfig
@@ -18,3 +18,13 @@ config NET_DSA_MV88E6XXX_GLOBAL2
 
 	  It is required on most chips. If the chip you compile the support for
 	  doesn't have such registers set, say N here. In doubt, say Y.
+
+config NET_DSA_MV88E6XXX_PTP
+	bool "PTP support for Marvell 88E6xxx"
+	default n
+	depends on NET_DSA_MV88E6XXX_GLOBAL2
+	imply NETWORK_PHY_TIMESTAMPING
+	imply PTP_1588_CLOCK
+	help
+	  Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch
+	  chips that support it.
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index 58a4a0014e59..50de304abe2f 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -5,6 +5,10 @@ mv88e6xxx-objs += global1.o
 mv88e6xxx-objs += global1_atu.o
 mv88e6xxx-objs += global1_vtu.o
 mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o
+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_avb.o
+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o
+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
 mv88e6xxx-objs += phy.o
 mv88e6xxx-objs += port.o
+mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
 mv88e6xxx-objs += serdes.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index eb328bade225..39c7ad7e490f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -36,8 +36,10 @@
 #include "chip.h"
 #include "global1.h"
 #include "global2.h"
+#include "hwtstamp.h"
 #include "phy.h"
 #include "port.h"
+#include "ptp.h"
 #include "serdes.h"
 
 static void assert_reg_lock(struct mv88e6xxx_chip *chip)
@@ -712,9 +714,12 @@ static void mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
 	for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
 		stat = &mv88e6xxx_hw_stats[i];
 		if (stat->type & types) {
+			mutex_lock(&chip->reg_lock);
 			data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
 							      bank1_select,
 							      histogram);
+			mutex_unlock(&chip->reg_lock);
+
 			j++;
 		}
 	}
@@ -762,14 +767,13 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
 	mutex_lock(&chip->reg_lock);
 
 	ret = mv88e6xxx_stats_snapshot(chip, port);
-	if (ret < 0) {
-		mutex_unlock(&chip->reg_lock);
+	mutex_unlock(&chip->reg_lock);
+
+	if (ret < 0)
 		return;
-	}
 
 	mv88e6xxx_get_stats(chip, port, data);
 
-	mutex_unlock(&chip->reg_lock);
 }
 
 static int mv88e6xxx_stats_set_histogram(struct mv88e6xxx_chip *chip)
@@ -1433,7 +1437,9 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
 	eth_broadcast_addr(addr.mac);
 
 	do {
+		mutex_lock(&chip->reg_lock);
 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
+		mutex_unlock(&chip->reg_lock);
 		if (err)
 			return err;
 
@@ -1466,7 +1472,10 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
 	int err;
 
 	/* Dump port's default Filtering Information Database (VLAN ID 0) */
+	mutex_lock(&chip->reg_lock);
 	err = mv88e6xxx_port_get_fid(chip, port, &fid);
+	mutex_unlock(&chip->reg_lock);
+
 	if (err)
 		return err;
 
@@ -1476,7 +1485,9 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
 
 	/* Dump VLANs' Filtering Information Databases */
 	do {
+		mutex_lock(&chip->reg_lock);
 		err = mv88e6xxx_vtu_getnext(chip, &vlan);
+		mutex_unlock(&chip->reg_lock);
 		if (err)
 			return err;
 
@@ -1496,13 +1507,8 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
 				   dsa_fdb_dump_cb_t *cb, void *data)
 {
 	struct mv88e6xxx_chip *chip = ds->priv;
-	int err;
-
-	mutex_lock(&chip->reg_lock);
-	err = mv88e6xxx_port_db_dump(chip, port, cb, data);
-	mutex_unlock(&chip->reg_lock);
 
-	return err;
+	return mv88e6xxx_port_db_dump(chip, port, cb, data);
 }
 
 static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
@@ -2092,6 +2098,17 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
 	if (err)
 		goto unlock;
 
+	/* Setup PTP Hardware Clock and timestamping */
+	if (chip->info->ptp_support) {
+		err = mv88e6xxx_ptp_setup(chip);
+		if (err)
+			goto unlock;
+
+		err = mv88e6xxx_hwtstamp_setup(chip);
+		if (err)
+			goto unlock;
+	}
+
 unlock:
 	mutex_unlock(&chip->reg_lock);
 
@@ -2472,6 +2489,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
 	.reset = mv88e6352_g1_reset,
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+	.gpio_ops = &mv88e6352_gpio_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -2602,6 +2620,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 	.serdes_power = mv88e6352_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -2673,6 +2692,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 	.serdes_power = mv88e6352_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -2736,6 +2756,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 	.serdes_power = mv88e6390_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -2771,6 +2792,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 	.serdes_power = mv88e6390_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -2843,6 +2865,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 	.serdes_power = mv88e6352_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6352_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -2879,6 +2903,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 	.serdes_power = mv88e6390_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6390_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -2913,6 +2939,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
 	.reset = mv88e6352_g1_reset,
 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6352_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -2945,6 +2973,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
 	.reset = mv88e6352_g1_reset,
 	.vtu_getnext = mv88e6185_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6352_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -2981,6 +3011,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
 	.reset = mv88e6352_g1_reset,
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6390_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3049,6 +3081,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
 	.reset = mv88e6352_g1_reset,
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+	.avb_ops = &mv88e6352_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3086,6 +3119,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
 	.vtu_getnext = mv88e6352_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
 	.serdes_power = mv88e6352_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6352_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -3124,6 +3159,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 	.serdes_power = mv88e6390_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6390_avb_ops,
 };
 
 static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3162,6 +3199,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
 	.vtu_getnext = mv88e6390_g1_vtu_getnext,
 	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
 	.serdes_power = mv88e6390_serdes_power,
+	.gpio_ops = &mv88e6352_gpio_ops,
+	.avb_ops = &mv88e6390_avb_ops,
 };
 
 static const struct mv88e6xxx_info mv88e6xxx_table[] = {
@@ -3267,6 +3306,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6341",
 		.num_databases = 4096,
 		.num_ports = 6,
+		.num_gpio = 11,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3346,6 +3386,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6172",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.num_gpio = 15,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3386,6 +3427,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6176",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.num_gpio = 15,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3424,6 +3466,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6190",
 		.num_databases = 4096,
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_gpio = 16,
 		.max_vid = 8191,
 		.port_base_addr = 0x0,
 		.global1_addr = 0x1b,
@@ -3444,6 +3487,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6190X",
 		.num_databases = 4096,
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_gpio = 16,
 		.max_vid = 8191,
 		.port_base_addr = 0x0,
 		.global1_addr = 0x1b,
@@ -3475,6 +3519,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_DSA,
+		.ptp_support = true,
 		.ops = &mv88e6191_ops,
 	},
 
@@ -3484,6 +3529,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6240",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.num_gpio = 15,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3495,6 +3541,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_EDSA,
+		.ptp_support = true,
 		.ops = &mv88e6240_ops,
 	},
 
@@ -3504,6 +3551,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6290",
 		.num_databases = 4096,
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_gpio = 16,
 		.max_vid = 8191,
 		.port_base_addr = 0x0,
 		.global1_addr = 0x1b,
@@ -3515,6 +3563,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_DSA,
+		.ptp_support = true,
 		.ops = &mv88e6290_ops,
 	},
 
@@ -3524,6 +3573,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6320",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.num_gpio = 15,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3534,6 +3584,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_EDSA,
+		.ptp_support = true,
 		.ops = &mv88e6320_ops,
 	},
 
@@ -3543,6 +3594,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6321",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.num_gpio = 15,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3552,6 +3604,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.atu_move_port_mask = 0xf,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_EDSA,
+		.ptp_support = true,
 		.ops = &mv88e6321_ops,
 	},
 
@@ -3561,6 +3614,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6341",
 		.num_databases = 4096,
 		.num_ports = 6,
+		.num_gpio = 11,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3571,6 +3625,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_EDSA,
+		.ptp_support = true,
 		.ops = &mv88e6341_ops,
 	},
 
@@ -3620,6 +3675,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6352",
 		.num_databases = 4096,
 		.num_ports = 7,
+		.num_gpio = 15,
 		.max_vid = 4095,
 		.port_base_addr = 0x10,
 		.global1_addr = 0x1b,
@@ -3631,6 +3687,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_EDSA,
+		.ptp_support = true,
 		.ops = &mv88e6352_ops,
 	},
 	[MV88E6390] = {
@@ -3639,6 +3696,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6390",
 		.num_databases = 4096,
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_gpio = 16,
 		.max_vid = 8191,
 		.port_base_addr = 0x0,
 		.global1_addr = 0x1b,
@@ -3650,6 +3708,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_DSA,
+		.ptp_support = true,
 		.ops = &mv88e6390_ops,
 	},
 	[MV88E6390X] = {
@@ -3658,6 +3717,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.name = "Marvell 88E6390X",
 		.num_databases = 4096,
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_gpio = 16,
 		.max_vid = 8191,
 		.port_base_addr = 0x0,
 		.global1_addr = 0x1b,
@@ -3669,6 +3729,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.pvt = true,
 		.multi_chip = true,
 		.tag_protocol = DSA_TAG_PROTO_DSA,
+		.ptp_support = true,
 		.ops = &mv88e6390x_ops,
 	},
 };
@@ -3880,6 +3941,11 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
+	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
+	.port_hwtstamp_get	= mv88e6xxx_port_hwtstamp_get,
+	.port_txtstamp		= mv88e6xxx_port_txtstamp,
+	.port_rxtstamp		= mv88e6xxx_port_rxtstamp,
+	.get_ts_info		= mv88e6xxx_get_ts_info,
 };
 
 static struct dsa_switch_driver mv88e6xxx_switch_drv = {
@@ -4022,6 +4088,11 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev)
 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
 	struct mv88e6xxx_chip *chip = ds->priv;
 
+	if (chip->info->ptp_support) {
+		mv88e6xxx_hwtstamp_free(chip);
+		mv88e6xxx_ptp_free(chip);
+	}
+
 	mv88e6xxx_phy_destroy(chip);
 	mv88e6xxx_unregister_switch(chip);
 	mv88e6xxx_mdios_unregister(chip);
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 3dba6e90adcf..97d7915f32c7 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -16,6 +16,8 @@
 #include <linux/irq.h>
 #include <linux/gpio/consumer.h>
 #include <linux/phy.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/timecounter.h>
 #include <net/dsa.h>
 
 #ifndef UINT64_MAX
@@ -39,6 +41,8 @@
 #define MV88E6XXX_MAX_PVT_SWITCHES	32
 #define MV88E6XXX_MAX_PVT_PORTS		16
 
+#define MV88E6XXX_MAX_GPIO	16
+
 enum mv88e6xxx_egress_mode {
 	MV88E6XXX_EGRESS_MODE_UNMODIFIED,
 	MV88E6XXX_EGRESS_MODE_UNTAGGED,
@@ -105,6 +109,7 @@ struct mv88e6xxx_info {
 	const char *name;
 	unsigned int num_databases;
 	unsigned int num_ports;
+	unsigned int num_gpio;
 	unsigned int max_vid;
 	unsigned int port_base_addr;
 	unsigned int global1_addr;
@@ -126,6 +131,9 @@ struct mv88e6xxx_info {
 	 */
 	u8 atu_move_port_mask;
 	const struct mv88e6xxx_ops *ops;
+
+	/* Supports PTP */
+	bool ptp_support;
 };
 
 struct mv88e6xxx_atu_entry {
@@ -146,6 +154,8 @@ struct mv88e6xxx_vtu_entry {
 
 struct mv88e6xxx_bus_ops;
 struct mv88e6xxx_irq_ops;
+struct mv88e6xxx_gpio_ops;
+struct mv88e6xxx_avb_ops;
 
 struct mv88e6xxx_irq {
 	u16 masked;
@@ -154,6 +164,32 @@ struct mv88e6xxx_irq {
 	unsigned int nirqs;
 };
 
+/* state flags for mv88e6xxx_port_hwtstamp::state */
+enum {
+	MV88E6XXX_HWTSTAMP_ENABLED,
+	MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
+};
+
+struct mv88e6xxx_port_hwtstamp {
+	/* Port index */
+	int port_id;
+
+	/* Timestamping state */
+	unsigned long state;
+
+	/* Resources for receive timestamping */
+	struct sk_buff_head rx_queue;
+	struct sk_buff_head rx_queue2;
+
+	/* Resources for transmit timestamping */
+	unsigned long tx_tstamp_start;
+	struct sk_buff *tx_skb;
+	u16 tx_seq_id;
+
+	/* Current timestamp configuration */
+	struct hwtstamp_config tstamp_config;
+};
+
 struct mv88e6xxx_chip {
 	const struct mv88e6xxx_info *info;
 
@@ -209,6 +245,26 @@ struct mv88e6xxx_chip {
 	int watchdog_irq;
 	int atu_prob_irq;
 	int vtu_prob_irq;
+
+	/* GPIO resources */
+	u8 gpio_data[2];
+
+	/* This cyclecounter abstracts the switch PTP time.
+	 * reg_lock must be held for any operation that read()s.
+	 */
+	struct cyclecounter	tstamp_cc;
+	struct timecounter	tstamp_tc;
+	struct delayed_work	overflow_work;
+
+	struct ptp_clock	*ptp_clock;
+	struct ptp_clock_info	ptp_clock_info;
+	struct delayed_work	tai_event_work;
+	struct ptp_pin_desc	pin_config[MV88E6XXX_MAX_GPIO];
+	u16 trig_config;
+	u16 evcap_config;
+
+	/* Per-port timestamping resources. */
+	struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
 };
 
 struct mv88e6xxx_bus_ops {
@@ -344,6 +400,12 @@ struct mv88e6xxx_ops {
 			   struct mv88e6xxx_vtu_entry *entry);
 	int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip,
 			     struct mv88e6xxx_vtu_entry *entry);
+
+	/* GPIO operations */
+	const struct mv88e6xxx_gpio_ops *gpio_ops;
+
+	/* Interface to the AVB/PTP registers */
+	const struct mv88e6xxx_avb_ops *avb_ops;
 };
 
 struct mv88e6xxx_irq_ops {
@@ -355,6 +417,42 @@ struct mv88e6xxx_irq_ops {
 	void (*irq_free)(struct mv88e6xxx_chip *chip);
 };
 
+struct mv88e6xxx_gpio_ops {
+	/* Get/set data on GPIO pin */
+	int (*get_data)(struct mv88e6xxx_chip *chip, unsigned int pin);
+	int (*set_data)(struct mv88e6xxx_chip *chip, unsigned int pin,
+			int value);
+
+	/* get/set GPIO direction */
+	int (*get_dir)(struct mv88e6xxx_chip *chip, unsigned int pin);
+	int (*set_dir)(struct mv88e6xxx_chip *chip, unsigned int pin,
+		       bool input);
+
+	/* get/set GPIO pin control */
+	int (*get_pctl)(struct mv88e6xxx_chip *chip, unsigned int pin,
+			int *func);
+	int (*set_pctl)(struct mv88e6xxx_chip *chip, unsigned int pin,
+			int func);
+};
+
+struct mv88e6xxx_avb_ops {
+	/* Access port-scoped Precision Time Protocol registers */
+	int (*port_ptp_read)(struct mv88e6xxx_chip *chip, int port, int addr,
+			     u16 *data, int len);
+	int (*port_ptp_write)(struct mv88e6xxx_chip *chip, int port, int addr,
+			      u16 data);
+
+	/* Access global Precision Time Protocol registers */
+	int (*ptp_read)(struct mv88e6xxx_chip *chip, int addr, u16 *data,
+			int len);
+	int (*ptp_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
+
+	/* Access global Time Application Interface registers */
+	int (*tai_read)(struct mv88e6xxx_chip *chip, int addr, u16 *data,
+			int len);
+	int (*tai_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
+};
+
 #define STATS_TYPE_PORT		BIT(0)
 #define STATS_TYPE_BANK0	BIT(1)
 #define STATS_TYPE_BANK1	BIT(2)
@@ -386,6 +484,11 @@ static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip)
 	return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0);
 }
 
+static inline unsigned int mv88e6xxx_num_gpio(struct mv88e6xxx_chip *chip)
+{
+	return chip->info->num_gpio;
+}
+
 int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
 int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
 int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c
index af0727877825..5f370f1fc7c4 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.c
+++ b/drivers/net/dsa/mv88e6xxx/global2.c
@@ -20,22 +20,22 @@
 #include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
 #include "global2.h"
 
-static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
+int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
 {
 	return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
 }
 
-static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
+int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
 {
 	return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
 }
 
-static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
+int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
 {
 	return mv88e6xxx_update(chip, chip->info->global2_addr, reg, update);
 }
 
-static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
+int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
 {
 	return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask);
 }
@@ -798,6 +798,7 @@ int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
 						   val);
 }
 
+/* Offset 0x1B: Watchdog Control */
 static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
 {
 	u16 reg;
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 669f59017b12..25f92b3d7157 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -149,7 +149,26 @@
 #define MV88E6390_G2_EEPROM_ADDR_MASK	0xffff
 
 /* Offset 0x16: AVB Command Register */
-#define MV88E6352_G2_AVB_CMD		0x16
+#define MV88E6352_G2_AVB_CMD			0x16
+#define MV88E6352_G2_AVB_CMD_BUSY		0x8000
+#define MV88E6352_G2_AVB_CMD_OP_READ		0x4000
+#define MV88E6352_G2_AVB_CMD_OP_READ_INCR	0x6000
+#define MV88E6352_G2_AVB_CMD_OP_WRITE		0x3000
+#define MV88E6390_G2_AVB_CMD_OP_READ		0x0000
+#define MV88E6390_G2_AVB_CMD_OP_READ_INCR	0x4000
+#define MV88E6390_G2_AVB_CMD_OP_WRITE		0x6000
+#define MV88E6352_G2_AVB_CMD_PORT_MASK		0x0f00
+#define MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL	0xe
+#define MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL	0xf
+#define MV88E6390_G2_AVB_CMD_PORT_MASK		0x1f00
+#define MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL	0x1e
+#define MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL	0x1f
+#define MV88E6352_G2_AVB_CMD_BLOCK_PTP		0
+#define MV88E6352_G2_AVB_CMD_BLOCK_AVB		1
+#define MV88E6352_G2_AVB_CMD_BLOCK_QAV		2
+#define MV88E6352_G2_AVB_CMD_BLOCK_QVB		3
+#define MV88E6352_G2_AVB_CMD_BLOCK_MASK		0x00e0
+#define MV88E6352_G2_AVB_CMD_ADDR_MASK		0x001f
 
 /* Offset 0x17: AVB Data Register */
 #define MV88E6352_G2_AVB_DATA		0x17
@@ -223,6 +242,35 @@
 #define MV88E6352_G2_NOEGR_POLICY	0x2000
 #define MV88E6390_G2_LAG_ID_4		0x2000
 
+/* Scratch/Misc registers accessed through MV88E6XXX_G2_SCRATCH_MISC */
+/* Offset 0x02: Misc Configuration */
+#define MV88E6352_G2_SCRATCH_MISC_CFG		0x02
+#define MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI	0x80
+/* Offset 0x60-0x61: GPIO Configuration */
+#define MV88E6352_G2_SCRATCH_GPIO_CFG0		0x60
+#define MV88E6352_G2_SCRATCH_GPIO_CFG1		0x61
+/* Offset 0x62-0x63: GPIO Direction */
+#define MV88E6352_G2_SCRATCH_GPIO_DIR0		0x62
+#define MV88E6352_G2_SCRATCH_GPIO_DIR1		0x63
+#define MV88E6352_G2_SCRATCH_GPIO_DIR_OUT	0
+#define MV88E6352_G2_SCRATCH_GPIO_DIR_IN	1
+/* Offset 0x64-0x65: GPIO Data */
+#define MV88E6352_G2_SCRATCH_GPIO_DATA0		0x64
+#define MV88E6352_G2_SCRATCH_GPIO_DATA1		0x65
+/* Offset 0x68-0x6F: GPIO Pin Control */
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL0		0x68
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL1		0x69
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL2		0x6A
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL3		0x6B
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL4		0x6C
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL5		0x6D
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL6		0x6E
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL7		0x6F
+
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO	0
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL_TRIG	1
+#define MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ	2
+
 #ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2
 
 static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
@@ -230,6 +278,11 @@ static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
 	return 0;
 }
 
+int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
+int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
+int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update);
+int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
+
 int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port);
 int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port);
 
@@ -267,6 +320,11 @@ int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip);
 extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
 extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
 
+extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops;
+extern const struct mv88e6xxx_avb_ops mv88e6390_avb_ops;
+
+extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops;
+
 #else /* !CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */
 
 static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
@@ -279,6 +337,26 @@ static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip)
 	return 0;
 }
 
+static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
+{
+	return -EOPNOTSUPP;
+}
+
+static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
+{
+	return -EOPNOTSUPP;
+}
+
+static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
+{
+	return -EOPNOTSUPP;
+}
+
+static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip,
 					    int port)
 {
@@ -382,6 +460,11 @@ static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
 static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {};
 static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {};
 
+static const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {};
+static const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {};
+
+static const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {};
+
 #endif /* CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */
 
 #endif /* _MV88E6XXX_GLOBAL2_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global2_avb.c b/drivers/net/dsa/mv88e6xxx/global2_avb.c
new file mode 100644
index 000000000000..2e398ccb88ca
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/global2_avb.c
@@ -0,0 +1,193 @@
+/*
+ * Marvell 88E6xxx Switch Global 2 Registers support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
+ *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * Copyright (c) 2017 National Instruments
+ *	Brandon Streiff <brandon.streiff@ni.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "global2.h"
+
+/* Offset 0x16: AVB Command Register
+ * Offset 0x17: AVB Data Register
+ *
+ * There are two different versions of this register interface:
+ *    "6352": 3-bit "op" field, 4-bit "port" field.
+ *    "6390": 2-bit "op" field, 5-bit "port" field.
+ *
+ * The "op" codes are different between the two, as well as the special
+ * port fields for global PTP and TAI configuration.
+ */
+
+/* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words.
+ * The hardware supports snapshotting up to four contiguous registers.
+ */
+static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop,
+				 u16 *data, int len)
+{
+	int err;
+	int i;
+
+	/* Hardware can only snapshot four words. */
+	if (len > 4)
+		return -E2BIG;
+
+	err = mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, readop);
+	if (err)
+		return err;
+
+	for (i = 0; i < len; ++i) {
+		err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA,
+					&data[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */
+static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop,
+				  u16 data)
+{
+	int err;
+
+	err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data);
+	if (err)
+		return err;
+
+	return mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, writeop);
+}
+
+static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
+					  int port, int addr, u16 *data,
+					  int len)
+{
+	u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ :
+				 MV88E6352_G2_AVB_CMD_OP_READ_INCR) |
+		     (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
+		     addr;
+
+	return mv88e6xxx_g2_avb_read(chip, readop, data, len);
+}
+
+static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
+					   int port, int addr, u16 data)
+{
+	u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
+		      (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
+
+	return mv88e6xxx_g2_avb_write(chip, writeop, data);
+}
+
+static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
+				     u16 *data, int len)
+{
+	return mv88e6352_g2_avb_port_ptp_read(chip,
+					MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
+					addr, data, len);
+}
+
+static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
+				      u16 data)
+{
+	return mv88e6352_g2_avb_port_ptp_write(chip,
+					MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
+					addr, data);
+}
+
+static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
+				     u16 *data, int len)
+{
+	return mv88e6352_g2_avb_port_ptp_read(chip,
+					MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
+					addr, data, len);
+}
+
+static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
+				      u16 data)
+{
+	return mv88e6352_g2_avb_port_ptp_write(chip,
+					MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
+					addr, data);
+}
+
+const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
+	.port_ptp_read		= mv88e6352_g2_avb_port_ptp_read,
+	.port_ptp_write		= mv88e6352_g2_avb_port_ptp_write,
+	.ptp_read		= mv88e6352_g2_avb_ptp_read,
+	.ptp_write		= mv88e6352_g2_avb_ptp_write,
+	.tai_read		= mv88e6352_g2_avb_tai_read,
+	.tai_write		= mv88e6352_g2_avb_tai_write,
+};
+
+static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
+					  int port, int addr, u16 *data,
+					  int len)
+{
+	u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ :
+				 MV88E6390_G2_AVB_CMD_OP_READ_INCR) |
+		     (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
+		     addr;
+
+	return mv88e6xxx_g2_avb_read(chip, readop, data, len);
+}
+
+static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
+					   int port, int addr, u16 data)
+{
+	u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
+		      (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
+
+	return mv88e6xxx_g2_avb_write(chip, writeop, data);
+}
+
+static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
+				     u16 *data, int len)
+{
+	return mv88e6390_g2_avb_port_ptp_read(chip,
+					MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
+					addr, data, len);
+}
+
+static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
+				      u16 data)
+{
+	return mv88e6390_g2_avb_port_ptp_write(chip,
+					MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
+					addr, data);
+}
+
+static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
+				     u16 *data, int len)
+{
+	return mv88e6390_g2_avb_port_ptp_read(chip,
+					MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
+					addr, data, len);
+}
+
+static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
+				      u16 data)
+{
+	return mv88e6390_g2_avb_port_ptp_write(chip,
+					MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
+					addr, data);
+}
+
+const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
+	.port_ptp_read		= mv88e6390_g2_avb_port_ptp_read,
+	.port_ptp_write		= mv88e6390_g2_avb_port_ptp_write,
+	.ptp_read		= mv88e6390_g2_avb_ptp_read,
+	.ptp_write		= mv88e6390_g2_avb_ptp_write,
+	.tai_read		= mv88e6390_g2_avb_tai_read,
+	.tai_write		= mv88e6390_g2_avb_tai_write,
+};
diff --git a/drivers/net/dsa/mv88e6xxx/global2_scratch.c b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
new file mode 100644
index 000000000000..0ff12bff9f0e
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
@@ -0,0 +1,240 @@
+/*
+ * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 National Instruments
+ *      Brandon Streiff <brandon.streiff@ni.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "chip.h"
+#include "global2.h"
+
+/* Offset 0x1A: Scratch and Misc. Register */
+static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
+				     u8 *data)
+{
+	u16 value;
+	int err;
+
+	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
+				 reg << 8);
+	if (err)
+		return err;
+
+	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
+	if (err)
+		return err;
+
+	*data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
+
+	return 0;
+}
+
+static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
+				      u8 data)
+{
+	u16 value = (reg << 8) | data;
+
+	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, value);
+}
+
+/**
+ * mv88e6xxx_g2_scratch_gpio_get_bit - get a bit
+ * @chip: chip private data
+ * @nr: bit index
+ * @set: is bit set?
+ */
+static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
+					int base_reg, unsigned int offset,
+					int *set)
+{
+	int reg = base_reg + (offset / 8);
+	u8 mask = (1 << (offset & 0x7));
+	u8 val;
+	int err;
+
+	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
+	if (err)
+		return err;
+
+	*set = !!(mask & val);
+
+	return 0;
+}
+
+/**
+ * mv88e6xxx_g2_scratch_gpio_set_bit - set (or clear) a bit
+ * @chip: chip private data
+ * @nr: bit index
+ * @set: set if true, clear if false
+ *
+ * Helper function for dealing with the direction and data registers.
+ */
+static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
+					int base_reg, unsigned int offset,
+					int set)
+{
+	int reg = base_reg + (offset / 8);
+	u8 mask = (1 << (offset & 0x7));
+	u8 val;
+	int err;
+
+	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
+	if (err)
+		return err;
+
+	if (set)
+		val |= mask;
+	else
+		val &= ~mask;
+
+	return mv88e6xxx_g2_scratch_write(chip, reg, val);
+}
+
+/**
+ * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
+ * @chip: chip private data
+ * @pin: gpio index
+ *
+ * Return: 0 for low, 1 for high, negative error
+ */
+static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
+					      unsigned int pin)
+{
+	int val = 0;
+	int err;
+
+	err = mv88e6xxx_g2_scratch_get_bit(chip,
+					   MV88E6352_G2_SCRATCH_GPIO_DATA0,
+					   pin, &val);
+	if (err)
+		return err;
+
+	return val;
+}
+
+/**
+ * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
+ * @chip: chip private data
+ * @pin: gpio index
+ * @value: value to set
+ */
+static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
+					      unsigned int pin, int value)
+{
+	u8 mask = (1 << (pin & 0x7));
+	int offset = (pin / 8);
+	int reg;
+
+	reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
+
+	if (value)
+		chip->gpio_data[offset] |= mask;
+	else
+		chip->gpio_data[offset] &= ~mask;
+
+	return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
+}
+
+/**
+ * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
+ * @chip: chip private data
+ * @pin: gpio index
+ *
+ * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
+ */
+static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
+					     unsigned int pin)
+{
+	int val = 0;
+	int err;
+
+	err = mv88e6xxx_g2_scratch_get_bit(chip,
+					   MV88E6352_G2_SCRATCH_GPIO_DIR0,
+					   pin, &val);
+	if (err)
+		return err;
+
+	return val;
+}
+
+/**
+ * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
+ * @chip: chip private data
+ * @pin: gpio index
+ */
+static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,
+					     unsigned int pin, bool input)
+{
+	int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :
+			     MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);
+
+	return mv88e6xxx_g2_scratch_set_bit(chip,
+					    MV88E6352_G2_SCRATCH_GPIO_DIR0,
+					    pin, value);
+}
+
+/**
+ * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting
+ * @chip: chip private data
+ * @pin: gpio index
+ * @func: function number
+ *
+ * Note that the function numbers themselves may vary by chipset.
+ */
+static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,
+					      unsigned int pin, int *func)
+{
+	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
+	int offset = (pin & 0x1) ? 4 : 0;
+	u8 mask = (0x7 << offset);
+	int err;
+	u8 val;
+
+	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
+	if (err)
+		return err;
+
+	*func = (val & mask) >> offset;
+
+	return 0;
+}
+
+/**
+ * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting
+ * @chip: chip private data
+ * @pin: gpio index
+ * @func: function number
+ */
+static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,
+					      unsigned int pin, int func)
+{
+	int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
+	int offset = (pin & 0x1) ? 4 : 0;
+	u8 mask = (0x7 << offset);
+	int err;
+	u8 val;
+
+	err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
+	if (err)
+		return err;
+
+	val = (val & ~mask) | ((func & mask) << offset);
+
+	return mv88e6xxx_g2_scratch_write(chip, reg, val);
+}
+
+const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {
+	.get_data = mv88e6352_g2_scratch_gpio_get_data,
+	.set_data = mv88e6352_g2_scratch_gpio_set_data,
+	.get_dir = mv88e6352_g2_scratch_gpio_get_dir,
+	.set_dir = mv88e6352_g2_scratch_gpio_set_dir,
+	.get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,
+	.set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,
+};
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
new file mode 100644
index 000000000000..ac7694c71266
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -0,0 +1,576 @@
+/*
+ * Marvell 88E6xxx Switch hardware timestamping support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 National Instruments
+ *      Erik Hons <erik.hons@ni.com>
+ *      Brandon Streiff <brandon.streiff@ni.com>
+ *      Dane Wagner <dane.wagner@ni.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "chip.h"
+#include "global2.h"
+#include "hwtstamp.h"
+#include "ptp.h"
+#include <linux/ptp_classify.h>
+
+#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
+
+static int mv88e6xxx_port_ptp_read(struct mv88e6xxx_chip *chip, int port,
+				   int addr, u16 *data, int len)
+{
+	if (!chip->info->ops->avb_ops->port_ptp_read)
+		return -EOPNOTSUPP;
+
+	return chip->info->ops->avb_ops->port_ptp_read(chip, port, addr,
+						       data, len);
+}
+
+static int mv88e6xxx_port_ptp_write(struct mv88e6xxx_chip *chip, int port,
+				    int addr, u16 data)
+{
+	if (!chip->info->ops->avb_ops->port_ptp_write)
+		return -EOPNOTSUPP;
+
+	return chip->info->ops->avb_ops->port_ptp_write(chip, port, addr,
+							data);
+}
+
+static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr,
+			       u16 data)
+{
+	if (!chip->info->ops->avb_ops->ptp_write)
+		return -EOPNOTSUPP;
+
+	return chip->info->ops->avb_ops->ptp_write(chip, addr, data);
+}
+
+/* TX_TSTAMP_TIMEOUT: This limits the time spent polling for a TX
+ * timestamp. When working properly, hardware will produce a timestamp
+ * within 1ms. Software may enounter delays due to MDIO contention, so
+ * the timeout is set accordingly.
+ */
+#define TX_TSTAMP_TIMEOUT	msecs_to_jiffies(20)
+
+int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
+			  struct ethtool_ts_info *info)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+
+	if (!chip->info->ptp_support)
+		return -EOPNOTSUPP;
+
+	info->so_timestamping =
+		SOF_TIMESTAMPING_TX_HARDWARE |
+		SOF_TIMESTAMPING_RX_HARDWARE |
+		SOF_TIMESTAMPING_RAW_HARDWARE;
+	info->phc_index = ptp_clock_index(chip->ptp_clock);
+	info->tx_types =
+		(1 << HWTSTAMP_TX_OFF) |
+		(1 << HWTSTAMP_TX_ON);
+	info->rx_filters =
+		(1 << HWTSTAMP_FILTER_NONE) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
+
+	return 0;
+}
+
+static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
+					 struct hwtstamp_config *config)
+{
+	struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
+	bool tstamp_enable = false;
+	u16 port_config0;
+	int err;
+
+	/* Prevent the TX/RX paths from trying to interact with the
+	 * timestamp hardware while we reconfigure it.
+	 */
+	clear_bit_unlock(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state);
+
+	/* reserved for future extensions */
+	if (config->flags)
+		return -EINVAL;
+
+	switch (config->tx_type) {
+	case HWTSTAMP_TX_OFF:
+		tstamp_enable = false;
+		break;
+	case HWTSTAMP_TX_ON:
+		tstamp_enable = true;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	/* The switch supports timestamping both L2 and L4; one cannot be
+	 * disabled independently of the other.
+	 */
+	switch (config->rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		tstamp_enable = false;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+		break;
+	case HWTSTAMP_FILTER_ALL:
+	default:
+		config->rx_filter = HWTSTAMP_FILTER_NONE;
+		return -ERANGE;
+	}
+
+	if (tstamp_enable) {
+		/* Disable transportSpecific value matching, so that packets
+		 * with either 1588 (0) and 802.1AS (1) will be timestamped.
+		 */
+		port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH;
+	} else {
+		/* Disable PTP. This disables both RX and TX timestamping. */
+		port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP;
+	}
+
+	mutex_lock(&chip->reg_lock);
+	err = mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
+				       port_config0);
+	mutex_unlock(&chip->reg_lock);
+
+	if (err < 0)
+		return err;
+
+	/* Once hardware has been configured, enable timestamp checks
+	 * in the RX/TX paths.
+	 */
+	if (tstamp_enable)
+		set_bit(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state);
+
+	return 0;
+}
+
+int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
+				struct ifreq *ifr)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
+	struct hwtstamp_config config;
+	int err;
+
+	if (!chip->info->ptp_support)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	err = mv88e6xxx_set_hwtstamp_config(chip, port, &config);
+	if (err)
+		return err;
+
+	/* Save the chosen configuration to be returned later. */
+	memcpy(&ps->tstamp_config, &config, sizeof(config));
+
+	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+		-EFAULT : 0;
+}
+
+int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
+				struct ifreq *ifr)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
+	struct hwtstamp_config *config = &ps->tstamp_config;
+
+	if (!chip->info->ptp_support)
+		return -EOPNOTSUPP;
+
+	return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
+		-EFAULT : 0;
+}
+
+/* Get the start of the PTP header in this skb */
+static u8 *parse_ptp_header(struct sk_buff *skb, unsigned int type)
+{
+	u8 *data = skb_mac_header(skb);
+	unsigned int offset = 0;
+
+	if (type & PTP_CLASS_VLAN)
+		offset += VLAN_HLEN;
+
+	switch (type & PTP_CLASS_PMASK) {
+	case PTP_CLASS_IPV4:
+		offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
+		break;
+	case PTP_CLASS_IPV6:
+		offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
+		break;
+	case PTP_CLASS_L2:
+		offset += ETH_HLEN;
+		break;
+	default:
+		return NULL;
+	}
+
+	/* Ensure that the entire header is present in this packet. */
+	if (skb->len + ETH_HLEN < offset + 34)
+		return NULL;
+
+	return data + offset;
+}
+
+/* Returns a pointer to the PTP header if the caller should time stamp,
+ * or NULL if the caller should not.
+ */
+static u8 *mv88e6xxx_should_tstamp(struct mv88e6xxx_chip *chip, int port,
+				   struct sk_buff *skb, unsigned int type)
+{
+	struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
+	u8 *hdr;
+
+	if (!chip->info->ptp_support)
+		return NULL;
+
+	hdr = parse_ptp_header(skb, type);
+	if (!hdr)
+		return NULL;
+
+	if (!test_bit(MV88E6XXX_HWTSTAMP_ENABLED, &ps->state))
+		return NULL;
+
+	return hdr;
+}
+
+static int mv88e6xxx_ts_valid(u16 status)
+{
+	if (!(status & MV88E6XXX_PTP_TS_VALID))
+		return 0;
+	if (status & MV88E6XXX_PTP_TS_STATUS_MASK)
+		return 0;
+	return 1;
+}
+
+static int seq_match(struct sk_buff *skb, u16 ts_seqid)
+{
+	unsigned int type = SKB_PTP_TYPE(skb);
+	u8 *hdr = parse_ptp_header(skb, type);
+	__be16 *seqid;
+
+	seqid = (__be16 *)(hdr + OFF_PTP_SEQUENCE_ID);
+
+	return ts_seqid == ntohs(*seqid);
+}
+
+static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
+			       struct mv88e6xxx_port_hwtstamp *ps,
+			       struct sk_buff *skb, u16 reg,
+			       struct sk_buff_head *rxq)
+{
+	u16 buf[4] = { 0 }, status, seq_id;
+	u64 ns, timelo, timehi;
+	struct skb_shared_hwtstamps *shwt;
+	int err;
+
+	mutex_lock(&chip->reg_lock);
+	err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
+				      reg, buf, ARRAY_SIZE(buf));
+	mutex_unlock(&chip->reg_lock);
+	if (err)
+		pr_err("failed to get the receive time stamp\n");
+
+	status = buf[0];
+	timelo = buf[1];
+	timehi = buf[2];
+	seq_id = buf[3];
+
+	if (status & MV88E6XXX_PTP_TS_VALID) {
+		mutex_lock(&chip->reg_lock);
+		err = mv88e6xxx_port_ptp_write(chip, ps->port_id, reg, 0);
+		mutex_unlock(&chip->reg_lock);
+		if (err)
+			pr_err("failed to clear the receive status\n");
+	}
+	/* Since the device can only handle one time stamp at a time,
+	 * we purge any extra frames from the queue.
+	 */
+	for ( ; skb; skb = skb_dequeue(rxq)) {
+		if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
+			ns = timehi << 16 | timelo;
+
+			mutex_lock(&chip->reg_lock);
+			ns = timecounter_cyc2time(&chip->tstamp_tc, ns);
+			mutex_unlock(&chip->reg_lock);
+			shwt = skb_hwtstamps(skb);
+			memset(shwt, 0, sizeof(*shwt));
+			shwt->hwtstamp = ns_to_ktime(ns);
+			status &= ~MV88E6XXX_PTP_TS_VALID;
+		}
+		netif_rx_ni(skb);
+	}
+}
+
+static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip,
+				    struct mv88e6xxx_port_hwtstamp *ps)
+{
+	struct sk_buff *skb;
+
+	skb = skb_dequeue(&ps->rx_queue);
+
+	if (skb)
+		mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR0_STS,
+				   &ps->rx_queue);
+
+	skb = skb_dequeue(&ps->rx_queue2);
+	if (skb)
+		mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR1_STS,
+				   &ps->rx_queue2);
+}
+
+static int is_pdelay_resp(u8 *msgtype)
+{
+	return (*msgtype & 0xf) == 3;
+}
+
+bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
+			     struct sk_buff *skb, unsigned int type)
+{
+	struct mv88e6xxx_port_hwtstamp *ps;
+	struct mv88e6xxx_chip *chip;
+	u8 *hdr;
+
+	chip = ds->priv;
+	ps = &chip->port_hwtstamp[port];
+
+	if (ps->tstamp_config.rx_filter != HWTSTAMP_FILTER_PTP_V2_EVENT)
+		return false;
+
+	hdr = mv88e6xxx_should_tstamp(chip, port, skb, type);
+	if (!hdr)
+		return false;
+
+	SKB_PTP_TYPE(skb) = type;
+
+	if (is_pdelay_resp(hdr))
+		skb_queue_tail(&ps->rx_queue2, skb);
+	else
+		skb_queue_tail(&ps->rx_queue, skb);
+
+	ptp_schedule_worker(chip->ptp_clock, 0);
+
+	return true;
+}
+
+static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
+				   struct mv88e6xxx_port_hwtstamp *ps)
+{
+	struct skb_shared_hwtstamps shhwtstamps;
+	u16 departure_block[4], status;
+	struct sk_buff *tmp_skb;
+	u32 time_raw;
+	int err;
+	u64 ns;
+
+	if (!ps->tx_skb)
+		return 0;
+
+	mutex_lock(&chip->reg_lock);
+	err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
+				      MV88E6XXX_PORT_PTP_DEP_STS,
+				      departure_block,
+				      ARRAY_SIZE(departure_block));
+	mutex_unlock(&chip->reg_lock);
+
+	if (err)
+		goto free_and_clear_skb;
+
+	if (!(departure_block[0] & MV88E6XXX_PTP_TS_VALID)) {
+		if (time_is_before_jiffies(ps->tx_tstamp_start +
+					   TX_TSTAMP_TIMEOUT)) {
+			dev_warn(chip->dev, "p%d: clearing tx timestamp hang\n",
+				 ps->port_id);
+			goto free_and_clear_skb;
+		}
+		/* The timestamp should be available quickly, while getting it
+		 * is high priority and time bounded to only 10ms. A poll is
+		 * warranted so restart the work.
+		 */
+		return 1;
+	}
+
+	/* We have the timestamp; go ahead and clear valid now */
+	mutex_lock(&chip->reg_lock);
+	mv88e6xxx_port_ptp_write(chip, ps->port_id,
+				 MV88E6XXX_PORT_PTP_DEP_STS, 0);
+	mutex_unlock(&chip->reg_lock);
+
+	status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
+	if (status != MV88E6XXX_PTP_TS_STATUS_NORMAL) {
+		dev_warn(chip->dev, "p%d: tx timestamp overrun\n", ps->port_id);
+		goto free_and_clear_skb;
+	}
+
+	if (departure_block[3] != ps->tx_seq_id) {
+		dev_warn(chip->dev, "p%d: unexpected seq. id\n", ps->port_id);
+		goto free_and_clear_skb;
+	}
+
+	memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+	time_raw = ((u32)departure_block[2] << 16) | departure_block[1];
+	mutex_lock(&chip->reg_lock);
+	ns = timecounter_cyc2time(&chip->tstamp_tc, time_raw);
+	mutex_unlock(&chip->reg_lock);
+	shhwtstamps.hwtstamp = ns_to_ktime(ns);
+
+	dev_dbg(chip->dev,
+		"p%d: txtstamp %llx status 0x%04x skb ID 0x%04x hw ID 0x%04x\n",
+		ps->port_id, ktime_to_ns(shhwtstamps.hwtstamp),
+		departure_block[0], ps->tx_seq_id, departure_block[3]);
+
+	/* skb_complete_tx_timestamp() will free up the client to make
+	 * another timestamp-able transmit. We have to be ready for it
+	 * -- by clearing the ps->tx_skb "flag" -- beforehand.
+	 */
+
+	tmp_skb = ps->tx_skb;
+	ps->tx_skb = NULL;
+	clear_bit_unlock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
+	skb_complete_tx_timestamp(tmp_skb, &shhwtstamps);
+
+	return 0;
+
+free_and_clear_skb:
+	dev_kfree_skb_any(ps->tx_skb);
+	ps->tx_skb = NULL;
+	clear_bit_unlock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state);
+
+	return 0;
+}
+
+long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
+{
+	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+	struct dsa_switch *ds = chip->ds;
+	struct mv88e6xxx_port_hwtstamp *ps;
+	int i, restart = 0;
+
+	for (i = 0; i < ds->num_ports; i++) {
+		if (!dsa_is_user_port(ds, i))
+			continue;
+
+		ps = &chip->port_hwtstamp[i];
+		if (test_bit(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS, &ps->state))
+			restart |= mv88e6xxx_txtstamp_work(chip, ps);
+
+		mv88e6xxx_rxtstamp_work(chip, ps);
+	}
+
+	return restart ? 1 : -1;
+}
+
+bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
+			     struct sk_buff *clone, unsigned int type)
+{
+	struct mv88e6xxx_chip *chip = ds->priv;
+	struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
+	__be16 *seq_ptr;
+	u8 *hdr;
+
+	if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP))
+		return false;
+
+	hdr = mv88e6xxx_should_tstamp(chip, port, clone, type);
+	if (!hdr)
+		return false;
+
+	seq_ptr = (__be16 *)(hdr + OFF_PTP_SEQUENCE_ID);
+
+	if (test_and_set_bit_lock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
+				  &ps->state))
+		return false;
+
+	ps->tx_skb = clone;
+	ps->tx_tstamp_start = jiffies;
+	ps->tx_seq_id = be16_to_cpup(seq_ptr);
+
+	ptp_schedule_worker(chip->ptp_clock, 0);
+	return true;
+}
+
+static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
+{
+	struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
+
+	ps->port_id = port;
+
+	skb_queue_head_init(&ps->rx_queue);
+	skb_queue_head_init(&ps->rx_queue2);
+
+	return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
+					MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP);
+}
+
+int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
+{
+	int err;
+	int i;
+
+	/* Disable timestamping on all ports. */
+	for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
+		err = mv88e6xxx_hwtstamp_port_setup(chip, i);
+		if (err)
+			return err;
+	}
+
+	/* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to
+	 * timestamp. This affects all ports that have timestamping enabled,
+	 * but the timestamp config is per-port; thus we configure all events
+	 * here and only support the HWTSTAMP_FILTER_*_EVENT filter types.
+	 */
+	err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_MSGTYPE,
+				  MV88E6XXX_PTP_MSGTYPE_ALL_EVENT);
+	if (err)
+		return err;
+
+	/* Use ARRIVAL1 for peer delay response messages. */
+	err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_TS_ARRIVAL_PTR,
+				  MV88E6XXX_PTP_MSGTYPE_PDLAY_RES);
+	if (err)
+		return err;
+
+	/* 88E6341 devices default to timestamping at the PHY, but this has
+	 * a hardware issue that results in unreliable timestamps. Force
+	 * these devices to timestamp at the MAC.
+	 */
+	if (chip->info->family == MV88E6XXX_FAMILY_6341) {
+		u16 val = MV88E6341_PTP_CFG_UPDATE |
+			  MV88E6341_PTP_CFG_MODE_IDX |
+			  MV88E6341_PTP_CFG_MODE_TS_AT_MAC;
+		err = mv88e6xxx_ptp_write(chip, MV88E6341_PTP_CFG, val);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
+{
+}
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
new file mode 100644
index 000000000000..bc71c9212a08
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -0,0 +1,172 @@
+/*
+ * Marvell 88E6xxx Switch hardware timestamping support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 National Instruments
+ *      Erik Hons <erik.hons@ni.com>
+ *      Brandon Streiff <brandon.streiff@ni.com>
+ *      Dane Wagner <dane.wagner@ni.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MV88E6XXX_HWTSTAMP_H
+#define _MV88E6XXX_HWTSTAMP_H
+
+#include "chip.h"
+
+/* Global PTP registers */
+/* Offset 0x00: PTP EtherType */
+#define MV88E6XXX_PTP_ETHERTYPE	0x00
+
+/* Offset 0x01: Message Type Timestamp Enables */
+#define MV88E6XXX_PTP_MSGTYPE			0x01
+#define MV88E6XXX_PTP_MSGTYPE_SYNC		0x0001
+#define MV88E6XXX_PTP_MSGTYPE_DELAY_REQ		0x0002
+#define MV88E6XXX_PTP_MSGTYPE_PDLAY_REQ		0x0004
+#define MV88E6XXX_PTP_MSGTYPE_PDLAY_RES		0x0008
+#define MV88E6XXX_PTP_MSGTYPE_ALL_EVENT		0x000f
+
+/* Offset 0x02: Timestamp Arrival Capture Pointers */
+#define MV88E6XXX_PTP_TS_ARRIVAL_PTR	0x02
+
+/* Offset 0x07: PTP Global Configuration */
+#define MV88E6341_PTP_CFG			0x07
+#define MV88E6341_PTP_CFG_UPDATE		0x8000
+#define MV88E6341_PTP_CFG_IDX_MASK		0x7f00
+#define MV88E6341_PTP_CFG_DATA_MASK		0x00ff
+#define MV88E6341_PTP_CFG_MODE_IDX		0x0
+#define MV88E6341_PTP_CFG_MODE_TS_AT_PHY	0x00
+#define MV88E6341_PTP_CFG_MODE_TS_AT_MAC	0x80
+
+/* Offset 0x08: PTP Interrupt Status */
+#define MV88E6XXX_PTP_IRQ_STATUS	0x08
+
+/* Per-Port PTP Registers */
+/* Offset 0x00: PTP Configuration 0 */
+#define MV88E6XXX_PORT_PTP_CFG0				0x00
+#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_SHIFT		12
+#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_MASK		0xf000
+#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_1588		0x0000
+#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_8021AS		0x1000
+#define MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH	0x0800
+#define MV88E6XXX_PORT_PTP_CFG0_DISABLE_OVERWRITE	0x0002
+#define MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP		0x0001
+
+/* Offset 0x01: PTP Configuration 1 */
+#define MV88E6XXX_PORT_PTP_CFG1	0x01
+
+/* Offset 0x02: PTP Configuration 2 */
+#define MV88E6XXX_PORT_PTP_CFG2				0x02
+#define MV88E6XXX_PORT_PTP_CFG2_EMBED_ARRIVAL		0x1000
+#define MV88E6XXX_PORT_PTP_CFG2_DEP_IRQ_EN		0x0002
+#define MV88E6XXX_PORT_PTP_CFG2_ARR_IRQ_EN		0x0001
+
+/* Offset 0x03: PTP LED Configuration */
+#define MV88E6XXX_PORT_PTP_LED_CFG	0x03
+
+/* Offset 0x08: PTP Arrival 0 Status */
+#define MV88E6XXX_PORT_PTP_ARR0_STS	0x08
+
+/* Offset 0x09/0x0A: PTP Arrival 0 Time */
+#define MV88E6XXX_PORT_PTP_ARR0_TIME_LO	0x09
+#define MV88E6XXX_PORT_PTP_ARR0_TIME_HI	0x0a
+
+/* Offset 0x0B: PTP Arrival 0 Sequence ID */
+#define MV88E6XXX_PORT_PTP_ARR0_SEQID	0x0b
+
+/* Offset 0x0C: PTP Arrival 1 Status */
+#define MV88E6XXX_PORT_PTP_ARR1_STS	0x0c
+
+/* Offset 0x0D/0x0E: PTP Arrival 1 Time */
+#define MV88E6XXX_PORT_PTP_ARR1_TIME_LO	0x0d
+#define MV88E6XXX_PORT_PTP_ARR1_TIME_HI	0x0e
+
+/* Offset 0x0F: PTP Arrival 1 Sequence ID */
+#define MV88E6XXX_PORT_PTP_ARR1_SEQID	0x0f
+
+/* Offset 0x10: PTP Departure Status */
+#define MV88E6XXX_PORT_PTP_DEP_STS	0x10
+
+/* Offset 0x11/0x12: PTP Deperture Time */
+#define MV88E6XXX_PORT_PTP_DEP_TIME_LO	0x11
+#define MV88E6XXX_PORT_PTP_DEP_TIME_HI	0x12
+
+/* Offset 0x13: PTP Departure Sequence ID */
+#define MV88E6XXX_PORT_PTP_DEP_SEQID	0x13
+
+/* Status fields for arrival and depature timestamp status registers */
+#define MV88E6XXX_PTP_TS_STATUS_MASK		0x0006
+#define MV88E6XXX_PTP_TS_STATUS_NORMAL		0x0000
+#define MV88E6XXX_PTP_TS_STATUS_OVERWITTEN	0x0002
+#define MV88E6XXX_PTP_TS_STATUS_DISCARDED	0x0004
+#define MV88E6XXX_PTP_TS_VALID			0x0001
+
+#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
+
+int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds, int port,
+				struct ifreq *ifr);
+int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
+				struct ifreq *ifr);
+
+bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
+			     struct sk_buff *clone, unsigned int type);
+bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
+			     struct sk_buff *clone, unsigned int type);
+
+int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
+			  struct ethtool_ts_info *info);
+
+int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
+void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
+
+#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
+
+static inline int mv88e6xxx_port_hwtstamp_set(struct dsa_switch *ds,
+					      int port, struct ifreq *ifr)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds,
+					      int port, struct ifreq *ifr)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
+					   struct sk_buff *clone,
+					   unsigned int type)
+{
+	return false;
+}
+
+static inline bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
+					   struct sk_buff *clone,
+					   unsigned int type)
+{
+	return false;
+}
+
+static inline int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
+					struct ethtool_ts_info *info)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
+{
+	return 0;
+}
+
+static inline void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip)
+{
+}
+
+#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
+
+#endif /* _MV88E6XXX_HWTSTAMP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
new file mode 100644
index 000000000000..bd85e2c390e1
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -0,0 +1,381 @@
+/*
+ * Marvell 88E6xxx Switch PTP support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 National Instruments
+ *      Erik Hons <erik.hons@ni.com>
+ *      Brandon Streiff <brandon.streiff@ni.com>
+ *      Dane Wagner <dane.wagner@ni.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "chip.h"
+#include "global2.h"
+#include "ptp.h"
+
+/* Raw timestamps are in units of 8-ns clock periods. */
+#define CC_SHIFT	28
+#define CC_MULT		(8 << CC_SHIFT)
+#define CC_MULT_NUM	(1 << 9)
+#define CC_MULT_DEM	15625ULL
+
+#define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100)
+
+#define cc_to_chip(cc) container_of(cc, struct mv88e6xxx_chip, tstamp_cc)
+#define dw_overflow_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
+					     overflow_work)
+#define dw_tai_event_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
+					      tai_event_work)
+
+static int mv88e6xxx_tai_read(struct mv88e6xxx_chip *chip, int addr,
+			      u16 *data, int len)
+{
+	if (!chip->info->ops->avb_ops->tai_read)
+		return -EOPNOTSUPP;
+
+	return chip->info->ops->avb_ops->tai_read(chip, addr, data, len);
+}
+
+static int mv88e6xxx_tai_write(struct mv88e6xxx_chip *chip, int addr, u16 data)
+{
+	if (!chip->info->ops->avb_ops->tai_write)
+		return -EOPNOTSUPP;
+
+	return chip->info->ops->avb_ops->tai_write(chip, addr, data);
+}
+
+/* TODO: places where this are called should be using pinctrl */
+static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
+				   int func, int input)
+{
+	int err;
+
+	if (!chip->info->ops->gpio_ops)
+		return -EOPNOTSUPP;
+
+	err = chip->info->ops->gpio_ops->set_dir(chip, pin, input);
+	if (err)
+		return err;
+
+	return chip->info->ops->gpio_ops->set_pctl(chip, pin, func);
+}
+
+static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
+{
+	struct mv88e6xxx_chip *chip = cc_to_chip(cc);
+	u16 phc_time[2];
+	int err;
+
+	err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_TIME_LO, phc_time,
+				 ARRAY_SIZE(phc_time));
+	if (err)
+		return 0;
+	else
+		return ((u32)phc_time[1] << 16) | phc_time[0];
+}
+
+/* mv88e6xxx_config_eventcap - configure TAI event capture
+ * @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external)
+ * @rising: zero for falling-edge trigger, else rising-edge trigger
+ *
+ * This will also reset the capture sequence counter.
+ */
+static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event,
+				     int rising)
+{
+	u16 global_config;
+	u16 cap_config;
+	int err;
+
+	chip->evcap_config = MV88E6XXX_TAI_CFG_CAP_OVERWRITE |
+			     MV88E6XXX_TAI_CFG_CAP_CTR_START;
+	if (!rising)
+		chip->evcap_config |= MV88E6XXX_TAI_CFG_EVREQ_FALLING;
+
+	global_config = (chip->evcap_config | chip->trig_config);
+	err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_CFG, global_config);
+	if (err)
+		return err;
+
+	if (event == PTP_CLOCK_PPS) {
+		cap_config = MV88E6XXX_TAI_EVENT_STATUS_CAP_TRIG;
+	} else if (event == PTP_CLOCK_EXTTS) {
+		/* if STATUS_CAP_TRIG is unset we capture PTP_EVREQ events */
+		cap_config = 0;
+	} else {
+		return -EINVAL;
+	}
+
+	/* Write the capture config; this also clears the capture counter */
+	err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS,
+				  cap_config);
+
+	return err;
+}
+
+static void mv88e6xxx_tai_event_work(struct work_struct *ugly)
+{
+	struct delayed_work *dw = to_delayed_work(ugly);
+	struct mv88e6xxx_chip *chip = dw_tai_event_to_chip(dw);
+	struct ptp_clock_event ev;
+	u16 status[4];
+	u32 raw_ts;
+	int err;
+
+	mutex_lock(&chip->reg_lock);
+	err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_EVENT_STATUS,
+				 status, ARRAY_SIZE(status));
+	mutex_unlock(&chip->reg_lock);
+
+	if (err) {
+		dev_err(chip->dev, "failed to read TAI status register\n");
+		return;
+	}
+	if (status[0] & MV88E6XXX_TAI_EVENT_STATUS_ERROR) {
+		dev_warn(chip->dev, "missed event capture\n");
+		return;
+	}
+	if (!(status[0] & MV88E6XXX_TAI_EVENT_STATUS_VALID))
+		goto out;
+
+	raw_ts = ((u32)status[2] << 16) | status[1];
+
+	/* Clear the valid bit so the next timestamp can come in */
+	status[0] &= ~MV88E6XXX_TAI_EVENT_STATUS_VALID;
+	mutex_lock(&chip->reg_lock);
+	err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, status[0]);
+	mutex_unlock(&chip->reg_lock);
+
+	/* This is an external timestamp */
+	ev.type = PTP_CLOCK_EXTTS;
+
+	/* We only have one timestamping channel. */
+	ev.index = 0;
+	mutex_lock(&chip->reg_lock);
+	ev.timestamp = timecounter_cyc2time(&chip->tstamp_tc, raw_ts);
+	mutex_unlock(&chip->reg_lock);
+
+	ptp_clock_event(chip->ptp_clock, &ev);
+out:
+	schedule_delayed_work(&chip->tai_event_work, TAI_EVENT_WORK_INTERVAL);
+}
+
+static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+	int neg_adj = 0;
+	u32 diff, mult;
+	u64 adj;
+
+	if (scaled_ppm < 0) {
+		neg_adj = 1;
+		scaled_ppm = -scaled_ppm;
+	}
+	mult = CC_MULT;
+	adj = CC_MULT_NUM;
+	adj *= scaled_ppm;
+	diff = div_u64(adj, CC_MULT_DEM);
+
+	mutex_lock(&chip->reg_lock);
+
+	timecounter_read(&chip->tstamp_tc);
+	chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff;
+
+	mutex_unlock(&chip->reg_lock);
+
+	return 0;
+}
+
+static int mv88e6xxx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+
+	mutex_lock(&chip->reg_lock);
+	timecounter_adjtime(&chip->tstamp_tc, delta);
+	mutex_unlock(&chip->reg_lock);
+
+	return 0;
+}
+
+static int mv88e6xxx_ptp_gettime(struct ptp_clock_info *ptp,
+				 struct timespec64 *ts)
+{
+	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+	u64 ns;
+
+	mutex_lock(&chip->reg_lock);
+	ns = timecounter_read(&chip->tstamp_tc);
+	mutex_unlock(&chip->reg_lock);
+
+	*ts = ns_to_timespec64(ns);
+
+	return 0;
+}
+
+static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
+				 const struct timespec64 *ts)
+{
+	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+	u64 ns;
+
+	ns = timespec64_to_ns(ts);
+
+	mutex_lock(&chip->reg_lock);
+	timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns);
+	mutex_unlock(&chip->reg_lock);
+
+	return 0;
+}
+
+static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
+				      struct ptp_clock_request *rq, int on)
+{
+	int rising = (rq->extts.flags & PTP_RISING_EDGE);
+	int func;
+	int pin;
+	int err;
+
+	pin = ptp_find_pin(chip->ptp_clock, PTP_PF_EXTTS, rq->extts.index);
+
+	if (pin < 0)
+		return -EBUSY;
+
+	mutex_lock(&chip->reg_lock);
+
+	if (on) {
+		func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
+
+		err = mv88e6xxx_set_gpio_func(chip, pin, func, true);
+		if (err)
+			goto out;
+
+		schedule_delayed_work(&chip->tai_event_work,
+				      TAI_EVENT_WORK_INTERVAL);
+
+		err = mv88e6xxx_config_eventcap(chip, PTP_CLOCK_EXTTS, rising);
+	} else {
+		func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO;
+
+		err = mv88e6xxx_set_gpio_func(chip, pin, func, true);
+
+		cancel_delayed_work_sync(&chip->tai_event_work);
+	}
+
+out:
+	mutex_unlock(&chip->reg_lock);
+
+	return err;
+}
+
+static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
+				struct ptp_clock_request *rq, int on)
+{
+	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
+
+	switch (rq->type) {
+	case PTP_CLK_REQ_EXTTS:
+		return mv88e6xxx_ptp_enable_extts(chip, rq, on);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
+				enum ptp_pin_function func, unsigned int chan)
+{
+	switch (func) {
+	case PTP_PF_NONE:
+	case PTP_PF_EXTTS:
+		break;
+	case PTP_PF_PEROUT:
+	case PTP_PF_PHYSYNC:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3
+ * seconds; this task forces periodic reads so that we don't miss any.
+ */
+#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 16)
+static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
+{
+	struct delayed_work *dw = to_delayed_work(work);
+	struct mv88e6xxx_chip *chip = dw_overflow_to_chip(dw);
+	struct timespec64 ts;
+
+	mv88e6xxx_ptp_gettime(&chip->ptp_clock_info, &ts);
+
+	schedule_delayed_work(&chip->overflow_work,
+			      MV88E6XXX_TAI_OVERFLOW_PERIOD);
+}
+
+int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
+{
+	int i;
+
+	/* Set up the cycle counter */
+	memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc));
+	chip->tstamp_cc.read	= mv88e6xxx_ptp_clock_read;
+	chip->tstamp_cc.mask	= CYCLECOUNTER_MASK(32);
+	chip->tstamp_cc.mult	= CC_MULT;
+	chip->tstamp_cc.shift	= CC_SHIFT;
+
+	timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc,
+			 ktime_to_ns(ktime_get_real()));
+
+	INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check);
+	INIT_DELAYED_WORK(&chip->tai_event_work, mv88e6xxx_tai_event_work);
+
+	chip->ptp_clock_info.owner = THIS_MODULE;
+	snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name),
+		 dev_name(chip->dev));
+	chip->ptp_clock_info.max_adj	= 1000000;
+
+	chip->ptp_clock_info.n_ext_ts	= 1;
+	chip->ptp_clock_info.n_per_out	= 0;
+	chip->ptp_clock_info.n_pins	= mv88e6xxx_num_gpio(chip);
+	chip->ptp_clock_info.pps	= 0;
+
+	for (i = 0; i < chip->ptp_clock_info.n_pins; ++i) {
+		struct ptp_pin_desc *ppd = &chip->pin_config[i];
+
+		snprintf(ppd->name, sizeof(ppd->name), "mv88e6xxx_gpio%d", i);
+		ppd->index = i;
+		ppd->func = PTP_PF_NONE;
+	}
+	chip->ptp_clock_info.pin_config = chip->pin_config;
+
+	chip->ptp_clock_info.adjfine	= mv88e6xxx_ptp_adjfine;
+	chip->ptp_clock_info.adjtime	= mv88e6xxx_ptp_adjtime;
+	chip->ptp_clock_info.gettime64	= mv88e6xxx_ptp_gettime;
+	chip->ptp_clock_info.settime64	= mv88e6xxx_ptp_settime;
+	chip->ptp_clock_info.enable	= mv88e6xxx_ptp_enable;
+	chip->ptp_clock_info.verify	= mv88e6xxx_ptp_verify;
+	chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
+
+	chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
+	if (IS_ERR(chip->ptp_clock))
+		return PTR_ERR(chip->ptp_clock);
+
+	schedule_delayed_work(&chip->overflow_work,
+			      MV88E6XXX_TAI_OVERFLOW_PERIOD);
+
+	return 0;
+}
+
+void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
+{
+	if (chip->ptp_clock) {
+		cancel_delayed_work_sync(&chip->overflow_work);
+		cancel_delayed_work_sync(&chip->tai_event_work);
+
+		ptp_clock_unregister(chip->ptp_clock);
+		chip->ptp_clock = NULL;
+	}
+}
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
new file mode 100644
index 000000000000..992818ade746
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -0,0 +1,108 @@
+/*
+ * Marvell 88E6xxx Switch PTP support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 National Instruments
+ *      Erik Hons <erik.hons@ni.com>
+ *      Brandon Streiff <brandon.streiff@ni.com>
+ *      Dane Wagner <dane.wagner@ni.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MV88E6XXX_PTP_H
+#define _MV88E6XXX_PTP_H
+
+#include "chip.h"
+
+/* Offset 0x00: TAI Global Config */
+#define MV88E6XXX_TAI_CFG			0x00
+#define MV88E6XXX_TAI_CFG_CAP_OVERWRITE		0x8000
+#define MV88E6XXX_TAI_CFG_CAP_CTR_START		0x4000
+#define MV88E6XXX_TAI_CFG_EVREQ_FALLING		0x2000
+#define MV88E6XXX_TAI_CFG_TRIG_ACTIVE_LO	0x1000
+#define MV88E6XXX_TAI_CFG_IRL_ENABLE		0x0400
+#define MV88E6XXX_TAI_CFG_TRIG_IRQ_EN		0x0200
+#define MV88E6XXX_TAI_CFG_EVREQ_IRQ_EN		0x0100
+#define MV88E6XXX_TAI_CFG_TRIG_LOCK		0x0080
+#define MV88E6XXX_TAI_CFG_BLOCK_UPDATE		0x0008
+#define MV88E6XXX_TAI_CFG_MULTI_PTP		0x0004
+#define MV88E6XXX_TAI_CFG_TRIG_MODE_ONESHOT	0x0002
+#define MV88E6XXX_TAI_CFG_TRIG_ENABLE		0x0001
+
+/* Offset 0x01: Timestamp Clock Period (ps) */
+#define MV88E6XXX_TAI_CLOCK_PERIOD		0x01
+
+/* Offset 0x02/0x03: Trigger Generation Amount */
+#define MV88E6XXX_TAI_TRIG_GEN_AMOUNT_LO	0x02
+#define MV88E6XXX_TAI_TRIG_GEN_AMOUNT_HI	0x03
+
+/* Offset 0x04: Clock Compensation */
+#define MV88E6XXX_TAI_TRIG_CLOCK_COMP		0x04
+
+/* Offset 0x05: Trigger Configuration */
+#define MV88E6XXX_TAI_TRIG_CFG			0x05
+
+/* Offset 0x06: Ingress Rate Limiter Clock Generation Amount */
+#define MV88E6XXX_TAI_IRL_AMOUNT		0x06
+
+/* Offset 0x07: Ingress Rate Limiter Compensation */
+#define MV88E6XXX_TAI_IRL_COMP			0x07
+
+/* Offset 0x08: Ingress Rate Limiter Compensation */
+#define MV88E6XXX_TAI_IRL_COMP_PS		0x08
+
+/* Offset 0x09: Event Status */
+#define MV88E6XXX_TAI_EVENT_STATUS		0x09
+#define MV88E6XXX_TAI_EVENT_STATUS_CAP_TRIG	0x4000
+#define MV88E6XXX_TAI_EVENT_STATUS_ERROR	0x0200
+#define MV88E6XXX_TAI_EVENT_STATUS_VALID	0x0100
+#define MV88E6XXX_TAI_EVENT_STATUS_CTR_MASK	0x00ff
+
+/* Offset 0x0A/0x0B: Event Time */
+#define MV88E6XXX_TAI_EVENT_TIME_LO		0x0a
+#define MV88E6XXX_TAI_EVENT_TYPE_HI		0x0b
+
+/* Offset 0x0E/0x0F: PTP Global Time */
+#define MV88E6XXX_TAI_TIME_LO			0x0e
+#define MV88E6XXX_TAI_TIME_HI			0x0f
+
+/* Offset 0x10/0x11: Trig Generation Time */
+#define MV88E6XXX_TAI_TRIG_TIME_LO		0x10
+#define MV88E6XXX_TAI_TRIG_TIME_HI		0x11
+
+/* Offset 0x12: Lock Status */
+#define MV88E6XXX_TAI_LOCK_STATUS		0x12
+
+#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
+
+long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp);
+int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip);
+void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
+
+#define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip,	\
+				      ptp_clock_info)
+
+#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
+
+static long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
+{
+	return -1;
+}
+
+static inline int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
+{
+	return 0;
+}
+
+static void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
+{
+}
+
+#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
+
+#endif /* _MV88E6XXX_PTP_H */
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index a77ee2f8fb8d..c1841db1b500 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -820,7 +820,7 @@ static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us)
 
 		tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
 
-		udelay(10);
+		usleep_range(10, 20);
 		timeout_us -= (timeout_us > 10) ? 10 : timeout_us;
 	}
 
@@ -922,8 +922,8 @@ static int tg3_ape_send_event(struct tg3 *tp, u32 event)
 	if (!(apedata & APE_FW_STATUS_READY))
 		return -EAGAIN;
 
-	/* Wait for up to 1 millisecond for APE to service previous event. */
-	err = tg3_ape_event_lock(tp, 1000);
+	/* Wait for up to 20 millisecond for APE to service previous event. */
+	err = tg3_ape_event_lock(tp, 20000);
 	if (err)
 		return err;
 
@@ -946,6 +946,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
 
 	switch (kind) {
 	case RESET_KIND_INIT:
+		tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++);
 		tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
 				APE_HOST_SEG_SIG_MAGIC);
 		tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
@@ -962,13 +963,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
 		event = APE_EVENT_STATUS_STATE_START;
 		break;
 	case RESET_KIND_SHUTDOWN:
-		/* With the interface we are currently using,
-		 * APE does not track driver state.  Wiping
-		 * out the HOST SEGMENT SIGNATURE forces
-		 * the APE to assume OS absent status.
-		 */
-		tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
-
 		if (device_may_wakeup(&tp->pdev->dev) &&
 		    tg3_flag(tp, WOL_ENABLE)) {
 			tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED,
@@ -990,6 +984,18 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
 	tg3_ape_send_event(tp, event);
 }
 
+static void tg3_send_ape_heartbeat(struct tg3 *tp,
+				   unsigned long interval)
+{
+	/* Check if hb interval has exceeded */
+	if (!tg3_flag(tp, ENABLE_APE) ||
+	    time_before(jiffies, tp->ape_hb_jiffies + interval))
+		return;
+
+	tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++);
+	tp->ape_hb_jiffies = jiffies;
+}
+
 static void tg3_disable_ints(struct tg3 *tp)
 {
 	int i;
@@ -7262,6 +7268,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
 		}
 	}
 
+	tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1);
 	return work_done;
 
 tx_recovery:
@@ -7344,6 +7351,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
 		}
 	}
 
+	tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1);
 	return work_done;
 
 tx_recovery:
@@ -10732,7 +10740,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
 	if (tg3_flag(tp, ENABLE_APE))
 		/* Write our heartbeat update interval to APE. */
 		tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
-				APE_HOST_HEARTBEAT_INT_DISABLE);
+				APE_HOST_HEARTBEAT_INT_5SEC);
 
 	tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
 
@@ -11077,6 +11085,9 @@ static void tg3_timer(struct timer_list *t)
 		tp->asf_counter = tp->asf_multiplier;
 	}
 
+	/* Update the APE heartbeat every 5 seconds.*/
+	tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL);
+
 	spin_unlock(&tp->lock);
 
 restart_timer:
@@ -16653,6 +16664,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 				       pci_state_reg);
 
 		tg3_ape_lock_init(tp);
+		tp->ape_hb_interval =
+			msecs_to_jiffies(APE_HOST_HEARTBEAT_INT_5SEC);
 	}
 
 	/* Set up tp->grc_local_ctrl before calling
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 47f51cc0566d..1d61aa3efda1 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2508,6 +2508,7 @@
 #define TG3_APE_LOCK_PHY3		5
 #define TG3_APE_LOCK_GPIO		7
 
+#define TG3_APE_HB_INTERVAL             (tp->ape_hb_interval)
 #define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10
 
 
@@ -3423,6 +3424,10 @@ struct tg3 {
 	struct device			*hwmon_dev;
 	bool				link_up;
 	bool				pcierr_recovery;
+
+	u32                             ape_hb;
+	unsigned long                   ape_hb_interval;
+	unsigned long                   ape_hb_jiffies;
 };
 
 /* Accessor macros for chip and asic attributes
diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.c b/drivers/net/ethernet/cavium/common/cavium_ptp.c
index c87c9c684a33..d59497a7bdce 100644
--- a/drivers/net/ethernet/cavium/common/cavium_ptp.c
+++ b/drivers/net/ethernet/cavium/common/cavium_ptp.c
@@ -75,6 +75,8 @@ EXPORT_SYMBOL(cavium_ptp_get);
 
 void cavium_ptp_put(struct cavium_ptp *ptp)
 {
+	if (!ptp)
+		return;
 	pci_dev_put(ptp->pdev);
 }
 EXPORT_SYMBOL(cavium_ptp_put);
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index b68cde9f17d2..7d9c5ffbd041 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -67,11 +67,6 @@ module_param(cpi_alg, int, S_IRUGO);
 MODULE_PARM_DESC(cpi_alg,
 		 "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)");
 
-struct nicvf_xdp_tx {
-	u64 dma_addr;
-	u8  qidx;
-};
-
 static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx)
 {
 	if (nic->sqs_mode)
@@ -507,29 +502,14 @@ static int nicvf_init_resources(struct nicvf *nic)
 	return 0;
 }
 
-static void nicvf_unmap_page(struct nicvf *nic, struct page *page, u64 dma_addr)
-{
-	/* Check if it's a recycled page, if not unmap the DMA mapping.
-	 * Recycled page holds an extra reference.
-	 */
-	if (page_ref_count(page) == 1) {
-		dma_addr &= PAGE_MASK;
-		dma_unmap_page_attrs(&nic->pdev->dev, dma_addr,
-				     RCV_FRAG_LEN + XDP_HEADROOM,
-				     DMA_FROM_DEVICE,
-				     DMA_ATTR_SKIP_CPU_SYNC);
-	}
-}
-
 static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 				struct cqe_rx_t *cqe_rx, struct snd_queue *sq,
 				struct rcv_queue *rq, struct sk_buff **skb)
 {
 	struct xdp_buff xdp;
 	struct page *page;
-	struct nicvf_xdp_tx *xdp_tx = NULL;
 	u32 action;
-	u16 len, err, offset = 0;
+	u16 len, offset = 0;
 	u64 dma_addr, cpu_addr;
 	void *orig_data;
 
@@ -543,7 +523,7 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 	cpu_addr = (u64)phys_to_virt(cpu_addr);
 	page = virt_to_page((void *)cpu_addr);
 
-	xdp.data_hard_start = page_address(page) + RCV_BUF_HEADROOM;
+	xdp.data_hard_start = page_address(page);
 	xdp.data = (void *)cpu_addr;
 	xdp_set_data_meta_invalid(&xdp);
 	xdp.data_end = xdp.data + len;
@@ -563,7 +543,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 
 	switch (action) {
 	case XDP_PASS:
-		nicvf_unmap_page(nic, page, dma_addr);
+		/* Check if it's a recycled page, if not
+		 * unmap the DMA mapping.
+		 *
+		 * Recycled page holds an extra reference.
+		 */
+		if (page_ref_count(page) == 1) {
+			dma_addr &= PAGE_MASK;
+			dma_unmap_page_attrs(&nic->pdev->dev, dma_addr,
+					     RCV_FRAG_LEN + XDP_PACKET_HEADROOM,
+					     DMA_FROM_DEVICE,
+					     DMA_ATTR_SKIP_CPU_SYNC);
+		}
 
 		/* Build SKB and pass on packet to network stack */
 		*skb = build_skb(xdp.data,
@@ -576,20 +567,6 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 	case XDP_TX:
 		nicvf_xdp_sq_append_pkt(nic, sq, (u64)xdp.data, dma_addr, len);
 		return true;
-	case XDP_REDIRECT:
-		/* Save DMA address for use while transmitting */
-		xdp_tx = (struct nicvf_xdp_tx *)page_address(page);
-		xdp_tx->dma_addr = dma_addr;
-		xdp_tx->qidx = nicvf_netdev_qidx(nic, cqe_rx->rq_idx);
-
-		err = xdp_do_redirect(nic->pnicvf->netdev, &xdp, prog);
-		if (!err)
-			return true;
-
-		/* Free the page on error */
-		nicvf_unmap_page(nic, page, dma_addr);
-		put_page(page);
-		break;
 	default:
 		bpf_warn_invalid_xdp_action(action);
 		/* fall through */
@@ -597,7 +574,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 		trace_xdp_exception(nic->netdev, prog, action);
 		/* fall through */
 	case XDP_DROP:
-		nicvf_unmap_page(nic, page, dma_addr);
+		/* Check if it's a recycled page, if not
+		 * unmap the DMA mapping.
+		 *
+		 * Recycled page holds an extra reference.
+		 */
+		if (page_ref_count(page) == 1) {
+			dma_addr &= PAGE_MASK;
+			dma_unmap_page_attrs(&nic->pdev->dev, dma_addr,
+					     RCV_FRAG_LEN + XDP_PACKET_HEADROOM,
+					     DMA_FROM_DEVICE,
+					     DMA_ATTR_SKIP_CPU_SYNC);
+		}
 		put_page(page);
 		return true;
 	}
@@ -1864,50 +1852,6 @@ static int nicvf_xdp(struct net_device *netdev, struct netdev_bpf *xdp)
 	}
 }
 
-static int nicvf_xdp_xmit(struct net_device *netdev, struct xdp_buff *xdp)
-{
-	struct nicvf *nic = netdev_priv(netdev);
-	struct nicvf *snic = nic;
-	struct nicvf_xdp_tx *xdp_tx;
-	struct snd_queue *sq;
-	struct page *page;
-	int err, qidx;
-
-	if (!netif_running(netdev) || !nic->xdp_prog)
-		return -EINVAL;
-
-	page = virt_to_page(xdp->data);
-	xdp_tx = (struct nicvf_xdp_tx *)page_address(page);
-	qidx = xdp_tx->qidx;
-
-	if (xdp_tx->qidx >= nic->xdp_tx_queues)
-		return -EINVAL;
-
-	/* Get secondary Qset's info */
-	if (xdp_tx->qidx >= MAX_SND_QUEUES_PER_QS) {
-		qidx = xdp_tx->qidx / MAX_SND_QUEUES_PER_QS;
-		snic = (struct nicvf *)nic->snicvf[qidx - 1];
-		if (!snic)
-			return -EINVAL;
-		qidx = xdp_tx->qidx % MAX_SND_QUEUES_PER_QS;
-	}
-
-	sq = &snic->qs->sq[qidx];
-	err = nicvf_xdp_sq_append_pkt(snic, sq, (u64)xdp->data,
-				      xdp_tx->dma_addr,
-				      xdp->data_end - xdp->data);
-	if (err)
-		return -ENOMEM;
-
-	nicvf_xdp_sq_doorbell(snic, sq, qidx);
-	return 0;
-}
-
-static void nicvf_xdp_flush(struct net_device *dev)
-{
-	return;
-}
-
 static int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr)
 {
 	struct hwtstamp_config config;
@@ -1986,8 +1930,6 @@ static const struct net_device_ops nicvf_netdev_ops = {
 	.ndo_fix_features       = nicvf_fix_features,
 	.ndo_set_features       = nicvf_set_features,
 	.ndo_bpf		= nicvf_xdp,
-	.ndo_xdp_xmit		= nicvf_xdp_xmit,
-	.ndo_xdp_flush          = nicvf_xdp_flush,
 	.ndo_do_ioctl           = nicvf_ioctl,
 };
 
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
index 3eae9ff9b53a..d42704d07484 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -204,7 +204,7 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr,
 
 	/* Reserve space for header modifications by BPF program */
 	if (rbdr->is_xdp)
-		buf_len += XDP_HEADROOM;
+		buf_len += XDP_PACKET_HEADROOM;
 
 	/* Check if it's recycled */
 	if (pgcache)
@@ -224,9 +224,8 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr,
 			nic->rb_page = NULL;
 			return -ENOMEM;
 		}
-
 		if (pgcache)
-			pgcache->dma_addr = *rbuf + XDP_HEADROOM;
+			pgcache->dma_addr = *rbuf + XDP_PACKET_HEADROOM;
 		nic->rb_page_offset += buf_len;
 	}
 
@@ -1244,7 +1243,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq,
 	int qentry;
 
 	if (subdesc_cnt > sq->xdp_free_cnt)
-		return -1;
+		return 0;
 
 	qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
 
@@ -1255,7 +1254,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq,
 
 	sq->xdp_desc_cnt += subdesc_cnt;
 
-	return 0;
+	return 1;
 }
 
 /* Calculate no of SQ subdescriptors needed to transmit all
@@ -1656,7 +1655,7 @@ static void nicvf_unmap_rcv_buffer(struct nicvf *nic, u64 dma_addr,
 		if (page_ref_count(page) != 1)
 			return;
 
-		len += XDP_HEADROOM;
+		len += XDP_PACKET_HEADROOM;
 		/* Receive buffers in XDP mode are mapped from page start */
 		dma_addr &= PAGE_MASK;
 	}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
index ce1eed7a6d63..5e9a03cf1b4d 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
@@ -11,7 +11,6 @@
 
 #include <linux/netdevice.h>
 #include <linux/iommu.h>
-#include <linux/bpf.h>
 #include <net/xdp.h>
 #include "q_struct.h"
 
@@ -94,9 +93,6 @@
 #define RCV_FRAG_LEN	 (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \
 			 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
-#define RCV_BUF_HEADROOM	128 /* To store dma address for XDP redirect */
-#define XDP_HEADROOM		(XDP_PACKET_HEADROOM + RCV_BUF_HEADROOM)
-
 #define MAX_CQES_FOR_TX		((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
 				 MAX_CQE_PER_PKT_XMIT)
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 557fd8bfd54e..9da6f57901a9 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -472,7 +472,7 @@ int cudbg_collect_cim_la(struct cudbg_init *pdbg_init,
 
 	if (is_t6(padap->params.chip)) {
 		size = padap->params.cim_la_size / 10 + 1;
-		size *= 11 * sizeof(u32);
+		size *= 10 * sizeof(u32);
 	} else {
 		size = padap->params.cim_la_size / 8;
 		size *= 8 * sizeof(u32);
@@ -878,6 +878,86 @@ static int cudbg_get_payload_range(struct adapter *padap, u8 mem_type,
 				      &payload->start, &payload->end);
 }
 
+static int cudbg_memory_read(struct cudbg_init *pdbg_init, int win,
+			     int mtype, u32 addr, u32 len, void *hbuf)
+{
+	u32 win_pf, memoffset, mem_aperture, mem_base;
+	struct adapter *adap = pdbg_init->adap;
+	u32 pos, offset, resid;
+	u32 *res_buf;
+	u64 *buf;
+	int ret;
+
+	/* Argument sanity checks ...
+	 */
+	if (addr & 0x3 || (uintptr_t)hbuf & 0x3)
+		return -EINVAL;
+
+	buf = (u64 *)hbuf;
+
+	/* Try to do 64-bit reads.  Residual will be handled later. */
+	resid = len & 0x7;
+	len -= resid;
+
+	ret = t4_memory_rw_init(adap, win, mtype, &memoffset, &mem_base,
+				&mem_aperture);
+	if (ret)
+		return ret;
+
+	addr = addr + memoffset;
+	win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->pf);
+
+	pos = addr & ~(mem_aperture - 1);
+	offset = addr - pos;
+
+	/* Set up initial PCI-E Memory Window to cover the start of our
+	 * transfer.
+	 */
+	t4_memory_update_win(adap, win, pos | win_pf);
+
+	/* Transfer data from the adapter */
+	while (len > 0) {
+		*buf++ = le64_to_cpu((__force __le64)
+				     t4_read_reg64(adap, mem_base + offset));
+		offset += sizeof(u64);
+		len -= sizeof(u64);
+
+		/* If we've reached the end of our current window aperture,
+		 * move the PCI-E Memory Window on to the next.
+		 */
+		if (offset == mem_aperture) {
+			pos += mem_aperture;
+			offset = 0;
+			t4_memory_update_win(adap, win, pos | win_pf);
+		}
+	}
+
+	res_buf = (u32 *)buf;
+	/* Read residual in 32-bit multiples */
+	while (resid > sizeof(u32)) {
+		*res_buf++ = le32_to_cpu((__force __le32)
+					 t4_read_reg(adap, mem_base + offset));
+		offset += sizeof(u32);
+		resid -= sizeof(u32);
+
+		/* If we've reached the end of our current window aperture,
+		 * move the PCI-E Memory Window on to the next.
+		 */
+		if (offset == mem_aperture) {
+			pos += mem_aperture;
+			offset = 0;
+			t4_memory_update_win(adap, win, pos | win_pf);
+		}
+	}
+
+	/* Transfer residual < 32-bits */
+	if (resid)
+		t4_memory_rw_residual(adap, resid, mem_base + offset,
+				      (u8 *)res_buf, T4_MEMORY_READ);
+
+	return 0;
+}
+
 #define CUDBG_YIELD_ITERATION 256
 
 static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
@@ -937,10 +1017,8 @@ static int cudbg_read_fw_mem(struct cudbg_init *pdbg_init,
 				goto skip_read;
 
 		spin_lock(&padap->win0_lock);
-		rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type,
-				  bytes_read, bytes,
-				  (__be32 *)temp_buff.data,
-				  1);
+		rc = cudbg_memory_read(pdbg_init, MEMWIN_NIC, mem_type,
+				       bytes_read, bytes, temp_buff.data);
 		spin_unlock(&padap->win0_lock);
 		if (rc) {
 			cudbg_err->sys_err = rc;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 9040e13ce4b7..d3fa53db61ee 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -1488,6 +1488,11 @@ u32 t4_read_pcie_cfg4(struct adapter *adap, int reg);
 u32 t4_get_util_window(struct adapter *adap);
 void t4_setup_memwin(struct adapter *adap, u32 memwin_base, u32 window);
 
+int t4_memory_rw_init(struct adapter *adap, int win, int mtype, u32 *mem_off,
+		      u32 *mem_base, u32 *mem_aperture);
+void t4_memory_update_win(struct adapter *adap, int win, u32 addr);
+void t4_memory_rw_residual(struct adapter *adap, u32 off, u32 addr, u8 *buf,
+			   int dir);
 #define T4_MEMORY_WRITE	0
 #define T4_MEMORY_READ	1
 int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, u32 len,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 30485f9a598f..143686c60234 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -102,7 +102,7 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 	case CUDBG_CIM_LA:
 		if (is_t6(adap->params.chip)) {
 			len = adap->params.cim_la_size / 10 + 1;
-			len *= 11 * sizeof(u32);
+			len *= 10 * sizeof(u32);
 		} else {
 			len = adap->params.cim_la_size / 8;
 			len *= 8 * sizeof(u32);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 56bc626ef006..7b452e85de2a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -4982,9 +4982,10 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
 
 	pcie_fw = readl(adap->regs + PCIE_FW_A);
 	/* Check if cxgb4 is the MASTER and fw is initialized */
-	if (!(pcie_fw & PCIE_FW_INIT_F) ||
+	if (num_vfs &&
+	    (!(pcie_fw & PCIE_FW_INIT_F) ||
 	    !(pcie_fw & PCIE_FW_MASTER_VLD_F) ||
-	    PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF) {
+	    PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF)) {
 		dev_warn(&pdev->dev,
 			 "cxgb4 driver needs to be MASTER to support SRIOV\n");
 		return -EOPNOTSUPP;
@@ -5599,24 +5600,24 @@ static void remove_one(struct pci_dev *pdev)
 #if IS_ENABLED(CONFIG_IPV6)
 		t4_cleanup_clip_tbl(adapter);
 #endif
-		iounmap(adapter->regs);
 		if (!is_t4(adapter->params.chip))
 			iounmap(adapter->bar2);
-		pci_disable_pcie_error_reporting(pdev);
-		if ((adapter->flags & DEV_ENABLED)) {
-			pci_disable_device(pdev);
-			adapter->flags &= ~DEV_ENABLED;
-		}
-		pci_release_regions(pdev);
-		kfree(adapter->mbox_log);
-		synchronize_rcu();
-		kfree(adapter);
 	}
 #ifdef CONFIG_PCI_IOV
 	else {
 		cxgb4_iov_configure(adapter->pdev, 0);
 	}
 #endif
+	iounmap(adapter->regs);
+	pci_disable_pcie_error_reporting(pdev);
+	if ((adapter->flags & DEV_ENABLED)) {
+		pci_disable_device(pdev);
+		adapter->flags &= ~DEV_ENABLED;
+	}
+	pci_release_regions(pdev);
+	kfree(adapter->mbox_log);
+	synchronize_rcu();
+	kfree(adapter);
 }
 
 /* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 047609ef0515..bd41f93f73ed 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -483,6 +483,117 @@ static int t4_edc_err_read(struct adapter *adap, int idx)
 	return 0;
 }
 
+/**
+ * t4_memory_rw_init - Get memory window relative offset, base, and size.
+ * @adap: the adapter
+ * @win: PCI-E Memory Window to use
+ * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
+ * @mem_off: memory relative offset with respect to @mtype.
+ * @mem_base: configured memory base address.
+ * @mem_aperture: configured memory window aperture.
+ *
+ * Get the configured memory window's relative offset, base, and size.
+ */
+int t4_memory_rw_init(struct adapter *adap, int win, int mtype, u32 *mem_off,
+		      u32 *mem_base, u32 *mem_aperture)
+{
+	u32 edc_size, mc_size, mem_reg;
+
+	/* Offset into the region of memory which is being accessed
+	 * MEM_EDC0 = 0
+	 * MEM_EDC1 = 1
+	 * MEM_MC   = 2 -- MEM_MC for chips with only 1 memory controller
+	 * MEM_MC1  = 3 -- for chips with 2 memory controllers (e.g. T5)
+	 * MEM_HMA  = 4
+	 */
+	edc_size  = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
+	if (mtype == MEM_HMA) {
+		*mem_off = 2 * (edc_size * 1024 * 1024);
+	} else if (mtype != MEM_MC1) {
+		*mem_off = (mtype * (edc_size * 1024 * 1024));
+	} else {
+		mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
+						      MA_EXT_MEMORY0_BAR_A));
+		*mem_off = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
+	}
+
+	/* Each PCI-E Memory Window is programmed with a window size -- or
+	 * "aperture" -- which controls the granularity of its mapping onto
+	 * adapter memory.  We need to grab that aperture in order to know
+	 * how to use the specified window.  The window is also programmed
+	 * with the base address of the Memory Window in BAR0's address
+	 * space.  For T4 this is an absolute PCI-E Bus Address.  For T5
+	 * the address is relative to BAR0.
+	 */
+	mem_reg = t4_read_reg(adap,
+			      PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A,
+						  win));
+	/* a dead adapter will return 0xffffffff for PIO reads */
+	if (mem_reg == 0xffffffff)
+		return -ENXIO;
+
+	*mem_aperture = 1 << (WINDOW_G(mem_reg) + WINDOW_SHIFT_X);
+	*mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X;
+	if (is_t4(adap->params.chip))
+		*mem_base -= adap->t4_bar0;
+
+	return 0;
+}
+
+/**
+ * t4_memory_update_win - Move memory window to specified address.
+ * @adap: the adapter
+ * @win: PCI-E Memory Window to use
+ * @addr: location to move.
+ *
+ * Move memory window to specified address.
+ */
+void t4_memory_update_win(struct adapter *adap, int win, u32 addr)
+{
+	t4_write_reg(adap,
+		     PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win),
+		     addr);
+	/* Read it back to ensure that changes propagate before we
+	 * attempt to use the new value.
+	 */
+	t4_read_reg(adap,
+		    PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win));
+}
+
+/**
+ * t4_memory_rw_residual - Read/Write residual data.
+ * @adap: the adapter
+ * @off: relative offset within residual to start read/write.
+ * @addr: address within indicated memory type.
+ * @buf: host memory buffer
+ * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0)
+ *
+ * Read/Write residual data less than 32-bits.
+ */
+void t4_memory_rw_residual(struct adapter *adap, u32 off, u32 addr, u8 *buf,
+			   int dir)
+{
+	union {
+		u32 word;
+		char byte[4];
+	} last;
+	unsigned char *bp;
+	int i;
+
+	if (dir == T4_MEMORY_READ) {
+		last.word = le32_to_cpu((__force __le32)
+					t4_read_reg(adap, addr));
+		for (bp = (unsigned char *)buf, i = off; i < 4; i++)
+			bp[i] = last.byte[i];
+	} else {
+		last.word = *buf;
+		for (i = off; i < 4; i++)
+			last.byte[i] = 0;
+		t4_write_reg(adap, addr,
+			     (__force u32)cpu_to_le32(last.word));
+	}
+}
+
 /**
  *	t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
  *	@adap: the adapter
@@ -504,8 +615,9 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 		 u32 len, void *hbuf, int dir)
 {
 	u32 pos, offset, resid, memoffset;
-	u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base;
+	u32 win_pf, mem_aperture, mem_base;
 	u32 *buf;
+	int ret;
 
 	/* Argument sanity checks ...
 	 */
@@ -521,59 +633,26 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 	resid = len & 0x3;
 	len -= resid;
 
-	/* Offset into the region of memory which is being accessed
-	 * MEM_EDC0 = 0
-	 * MEM_EDC1 = 1
-	 * MEM_MC   = 2 -- MEM_MC for chips with only 1 memory controller
-	 * MEM_MC1  = 3 -- for chips with 2 memory controllers (e.g. T5)
-	 * MEM_HMA  = 4
-	 */
-	edc_size  = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
-	if (mtype == MEM_HMA) {
-		memoffset = 2 * (edc_size * 1024 * 1024);
-	} else if (mtype != MEM_MC1) {
-		memoffset = (mtype * (edc_size * 1024 * 1024));
-	} else {
-		mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
-						      MA_EXT_MEMORY0_BAR_A));
-		memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
-	}
+	ret = t4_memory_rw_init(adap, win, mtype, &memoffset, &mem_base,
+				&mem_aperture);
+	if (ret)
+		return ret;
 
 	/* Determine the PCIE_MEM_ACCESS_OFFSET */
 	addr = addr + memoffset;
 
-	/* Each PCI-E Memory Window is programmed with a window size -- or
-	 * "aperture" -- which controls the granularity of its mapping onto
-	 * adapter memory.  We need to grab that aperture in order to know
-	 * how to use the specified window.  The window is also programmed
-	 * with the base address of the Memory Window in BAR0's address
-	 * space.  For T4 this is an absolute PCI-E Bus Address.  For T5
-	 * the address is relative to BAR0.
-	 */
-	mem_reg = t4_read_reg(adap,
-			      PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A,
-						  win));
-	mem_aperture = 1 << (WINDOW_G(mem_reg) + WINDOW_SHIFT_X);
-	mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X;
-	if (is_t4(adap->params.chip))
-		mem_base -= adap->t4_bar0;
 	win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->pf);
 
 	/* Calculate our initial PCI-E Memory Window Position and Offset into
 	 * that Window.
 	 */
-	pos = addr & ~(mem_aperture-1);
+	pos = addr & ~(mem_aperture - 1);
 	offset = addr - pos;
 
 	/* Set up initial PCI-E Memory Window to cover the start of our
-	 * transfer.  (Read it back to ensure that changes propagate before we
-	 * attempt to use the new value.)
+	 * transfer.
 	 */
-	t4_write_reg(adap,
-		     PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win),
-		     pos | win_pf);
-	t4_read_reg(adap,
-		    PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win));
+	t4_memory_update_win(adap, win, pos | win_pf);
 
 	/* Transfer data to/from the adapter as long as there's an integral
 	 * number of 32-bit transfers to complete.
@@ -628,12 +707,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 		if (offset == mem_aperture) {
 			pos += mem_aperture;
 			offset = 0;
-			t4_write_reg(adap,
-				PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A,
-						    win), pos | win_pf);
-			t4_read_reg(adap,
-				PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A,
-						    win));
+			t4_memory_update_win(adap, win, pos | win_pf);
 		}
 	}
 
@@ -642,28 +716,9 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 	 * residual amount.  The PCI-E Memory Window has already been moved
 	 * above (if necessary) to cover this final transfer.
 	 */
-	if (resid) {
-		union {
-			u32 word;
-			char byte[4];
-		} last;
-		unsigned char *bp;
-		int i;
-
-		if (dir == T4_MEMORY_READ) {
-			last.word = le32_to_cpu(
-					(__force __le32)t4_read_reg(adap,
-						mem_base + offset));
-			for (bp = (unsigned char *)buf, i = resid; i < 4; i++)
-				bp[i] = last.byte[i];
-		} else {
-			last.word = *buf;
-			for (i = resid; i < 4; i++)
-				last.byte[i] = 0;
-			t4_write_reg(adap, mem_base + offset,
-				     (__force u32)cpu_to_le32(last.word));
-		}
-	}
+	if (resid)
+		t4_memory_rw_residual(adap, resid, mem_base + offset,
+				      (u8 *)buf, dir);
 
 	return 0;
 }
@@ -2637,7 +2692,6 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
 }
 
 #define EEPROM_STAT_ADDR   0x7bfc
-#define VPD_SIZE           0x800
 #define VPD_BASE           0x400
 #define VPD_BASE_OLD       0
 #define VPD_LEN            1024
@@ -2704,15 +2758,6 @@ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p)
 	if (!vpd)
 		return -ENOMEM;
 
-	/* We have two VPD data structures stored in the adapter VPD area.
-	 * By default, Linux calculates the size of the VPD area by traversing
-	 * the first VPD area at offset 0x0, so we need to tell the OS what
-	 * our real VPD size is.
-	 */
-	ret = pci_set_vpd_size(adapter->pdev, VPD_SIZE);
-	if (ret < 0)
-		goto out;
-
 	/* Card information normally starts at VPD_BASE but early cards had
 	 * it at 0.
 	 */
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 7caa8da48421..a998c36c5e61 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2766,7 +2766,7 @@ static int dpaa_eth_probe(struct platform_device *pdev)
 
 	priv->channel = (u16)channel;
 
-	/* Start a thread that will walk the CPUs with affine portals
+	/* Walk the CPUs with affine portals
 	 * and add this pool channel to each's dequeue mask.
 	 */
 	dpaa_eth_add_channel(priv->channel);
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
index faea674094b9..85306d1b2acf 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -211,7 +211,7 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
 	if (epause->rx_pause)
 		newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
 	if (epause->tx_pause)
-		newadv |= ADVERTISED_Asym_Pause;
+		newadv ^= ADVERTISED_Asym_Pause;
 
 	oldadv = phydev->advertising &
 			(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 27447260215d..996f47568f9e 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -791,6 +791,18 @@ static int ibmvnic_login(struct net_device *netdev)
 	return 0;
 }
 
+static void release_login_buffer(struct ibmvnic_adapter *adapter)
+{
+	kfree(adapter->login_buf);
+	adapter->login_buf = NULL;
+}
+
+static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
+{
+	kfree(adapter->login_rsp_buf);
+	adapter->login_rsp_buf = NULL;
+}
+
 static void release_resources(struct ibmvnic_adapter *adapter)
 {
 	int i;
@@ -813,6 +825,10 @@ static void release_resources(struct ibmvnic_adapter *adapter)
 			}
 		}
 	}
+	kfree(adapter->napi);
+	adapter->napi = NULL;
+
+	release_login_rsp_buffer(adapter);
 }
 
 static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
@@ -1057,6 +1073,35 @@ static int ibmvnic_open(struct net_device *netdev)
 	return rc;
 }
 
+static void clean_rx_pools(struct ibmvnic_adapter *adapter)
+{
+	struct ibmvnic_rx_pool *rx_pool;
+	u64 rx_entries;
+	int rx_scrqs;
+	int i, j;
+
+	if (!adapter->rx_pool)
+		return;
+
+	rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+	rx_entries = adapter->req_rx_add_entries_per_subcrq;
+
+	/* Free any remaining skbs in the rx buffer pools */
+	for (i = 0; i < rx_scrqs; i++) {
+		rx_pool = &adapter->rx_pool[i];
+		if (!rx_pool)
+			continue;
+
+		netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i);
+		for (j = 0; j < rx_entries; j++) {
+			if (rx_pool->rx_buff[j].skb) {
+				dev_kfree_skb_any(rx_pool->rx_buff[j].skb);
+				rx_pool->rx_buff[j].skb = NULL;
+			}
+		}
+	}
+}
+
 static void clean_tx_pools(struct ibmvnic_adapter *adapter)
 {
 	struct ibmvnic_tx_pool *tx_pool;
@@ -1134,7 +1179,7 @@ static int __ibmvnic_close(struct net_device *netdev)
 			}
 		}
 	}
-
+	clean_rx_pools(adapter);
 	clean_tx_pools(adapter);
 	adapter->state = VNIC_CLOSED;
 	return rc;
@@ -1670,8 +1715,6 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 		return 0;
 	}
 
-	netif_carrier_on(netdev);
-
 	/* kick napi */
 	for (i = 0; i < adapter->req_rx_queues; i++)
 		napi_schedule(&adapter->napi[i]);
@@ -1679,6 +1722,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
 	if (adapter->reset_reason != VNIC_RESET_FAILOVER)
 		netdev_notify_peers(netdev);
 
+	netif_carrier_on(netdev);
+
 	return 0;
 }
 
@@ -1853,6 +1898,7 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget)
 				   be16_to_cpu(next->rx_comp.rc));
 			/* free the entry */
 			next->rx_comp.first = 0;
+			dev_kfree_skb_any(rx_buff->skb);
 			remove_buff_from_pool(adapter, rx_buff);
 			continue;
 		}
@@ -3013,6 +3059,7 @@ static void send_login(struct ibmvnic_adapter *adapter)
 	struct vnic_login_client_data *vlcd;
 	int i;
 
+	release_login_rsp_buffer(adapter);
 	client_data_len = vnic_client_data_len(adapter);
 
 	buffer_size =
@@ -3708,6 +3755,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
 
 	dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz,
 			 DMA_BIDIRECTIONAL);
+	release_login_buffer(adapter);
 	dma_unmap_single(dev, adapter->login_rsp_buf_token,
 			 adapter->login_rsp_buf_sz, DMA_BIDIRECTIONAL);
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 46e9f4e0a02c..36d9401a6258 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -507,6 +507,7 @@ struct i40e_pf {
 #define I40E_HW_STOP_FW_LLDP			BIT(16)
 #define I40E_HW_PORT_ID_VALID			BIT(17)
 #define I40E_HW_RESTART_AUTONEG			BIT(18)
+#define I40E_HW_STOPPABLE_FW_LLDP		BIT(19)
 
 	u64 flags;
 #define I40E_FLAG_RX_CSUM_ENABLED		BIT_ULL(0)
@@ -824,6 +825,7 @@ struct i40e_q_vector {
 	struct i40e_ring_container rx;
 	struct i40e_ring_container tx;
 
+	u8 itr_countdown;	/* when 0 should adjust adaptive ITR */
 	u8 num_ringpairs;	/* total number of ring pairs in vector */
 
 	cpumask_t affinity_mask;
@@ -832,8 +834,6 @@ struct i40e_q_vector {
 	struct rcu_head rcu;	/* to avoid race with update stats on free */
 	char name[I40E_INT_NAME_STR_LEN];
 	bool arm_wb_state;
-#define ITR_COUNTDOWN_START 100
-	u8 itr_countdown;	/* when 0 should adjust ITR */
 } ____cacheline_internodealigned_in_smp;
 
 /* lan device */
@@ -1109,4 +1109,10 @@ static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
 
 int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
 int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate);
+int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
+			      struct i40e_cloud_filter *filter,
+			      bool add);
+int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
+				      struct i40e_cloud_filter *filter,
+				      bool add);
 #endif /* _I40E_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 4c3b4243cf65..b829fd365693 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -155,8 +155,8 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 		dev_info(&pf->pdev->dev, "        vlan_features = 0x%08lx\n",
 			 (unsigned long int)nd->vlan_features);
 	}
-	dev_info(&pf->pdev->dev,
-		 "    vlgrp: & = %p\n", vsi->active_vlans);
+	dev_info(&pf->pdev->dev, "    active_vlans is %s\n",
+		 vsi->active_vlans ? "<valid>" : "<null>");
 	dev_info(&pf->pdev->dev,
 		 "    flags = 0x%08lx, netdev_registered = %i, current_netdev_flags = 0x%04x\n",
 		 vsi->flags, vsi->netdev_registered, vsi->current_netdev_flags);
@@ -269,14 +269,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 		if (!rx_ring)
 			continue;
 
-		dev_info(&pf->pdev->dev,
-			 "    rx_rings[%i]: desc = %p\n",
-			 i, rx_ring->desc);
-		dev_info(&pf->pdev->dev,
-			 "    rx_rings[%i]: dev = %p, netdev = %p, rx_bi = %p\n",
-			 i, rx_ring->dev,
-			 rx_ring->netdev,
-			 rx_ring->rx_bi);
 		dev_info(&pf->pdev->dev,
 			 "    rx_rings[%i]: state = %lu, queue_index = %d, reg_idx = %d\n",
 			 i, *rx_ring->state,
@@ -307,17 +299,12 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 			 rx_ring->rx_stats.realloc_count,
 			 rx_ring->rx_stats.page_reuse_count);
 		dev_info(&pf->pdev->dev,
-			 "    rx_rings[%i]: size = %i, dma = 0x%08lx\n",
-			 i, rx_ring->size,
-			 (unsigned long int)rx_ring->dma);
-		dev_info(&pf->pdev->dev,
-			 "    rx_rings[%i]: vsi = %p, q_vector = %p\n",
-			 i, rx_ring->vsi,
-			 rx_ring->q_vector);
+			 "    rx_rings[%i]: size = %i\n",
+			 i, rx_ring->size);
 		dev_info(&pf->pdev->dev,
-			 "    rx_rings[%i]: rx_itr_setting = %d (%s)\n",
-			 i, rx_ring->rx_itr_setting,
-			 ITR_IS_DYNAMIC(rx_ring->rx_itr_setting) ? "dynamic" : "fixed");
+			 "    rx_rings[%i]: itr_setting = %d (%s)\n",
+			 i, rx_ring->itr_setting,
+			 ITR_IS_DYNAMIC(rx_ring->itr_setting) ? "dynamic" : "fixed");
 	}
 	for (i = 0; i < vsi->num_queue_pairs; i++) {
 		struct i40e_ring *tx_ring = READ_ONCE(vsi->tx_rings[i]);
@@ -325,14 +312,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 		if (!tx_ring)
 			continue;
 
-		dev_info(&pf->pdev->dev,
-			 "    tx_rings[%i]: desc = %p\n",
-			 i, tx_ring->desc);
-		dev_info(&pf->pdev->dev,
-			 "    tx_rings[%i]: dev = %p, netdev = %p, tx_bi = %p\n",
-			 i, tx_ring->dev,
-			 tx_ring->netdev,
-			 tx_ring->tx_bi);
 		dev_info(&pf->pdev->dev,
 			 "    tx_rings[%i]: state = %lu, queue_index = %d, reg_idx = %d\n",
 			 i, *tx_ring->state,
@@ -355,20 +334,15 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 			 tx_ring->tx_stats.tx_busy,
 			 tx_ring->tx_stats.tx_done_old);
 		dev_info(&pf->pdev->dev,
-			 "    tx_rings[%i]: size = %i, dma = 0x%08lx\n",
-			 i, tx_ring->size,
-			 (unsigned long int)tx_ring->dma);
-		dev_info(&pf->pdev->dev,
-			 "    tx_rings[%i]: vsi = %p, q_vector = %p\n",
-			 i, tx_ring->vsi,
-			 tx_ring->q_vector);
+			 "    tx_rings[%i]: size = %i\n",
+			 i, tx_ring->size);
 		dev_info(&pf->pdev->dev,
 			 "    tx_rings[%i]: DCB tc = %d\n",
 			 i, tx_ring->dcb_tc);
 		dev_info(&pf->pdev->dev,
-			 "    tx_rings[%i]: tx_itr_setting = %d (%s)\n",
-			 i, tx_ring->tx_itr_setting,
-			 ITR_IS_DYNAMIC(tx_ring->tx_itr_setting) ? "dynamic" : "fixed");
+			 "    tx_rings[%i]: itr_setting = %d (%s)\n",
+			 i, tx_ring->itr_setting,
+			 ITR_IS_DYNAMIC(tx_ring->itr_setting) ? "dynamic" : "fixed");
 	}
 	rcu_read_unlock();
 	dev_info(&pf->pdev->dev,
@@ -466,8 +440,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 		 vsi->info.resp_reserved[6], vsi->info.resp_reserved[7],
 		 vsi->info.resp_reserved[8], vsi->info.resp_reserved[9],
 		 vsi->info.resp_reserved[10], vsi->info.resp_reserved[11]);
-	if (vsi->back)
-		dev_info(&pf->pdev->dev, "    PF = %p\n", vsi->back);
 	dev_info(&pf->pdev->dev, "    idx = %d\n", vsi->idx);
 	dev_info(&pf->pdev->dev,
 		 "    tc_config: numtc = %d, enabled_tc = 0x%x\n",
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 2f5bee713fef..0dcbbda164c4 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -2244,14 +2244,14 @@ static int __i40e_get_coalesce(struct net_device *netdev,
 	rx_ring = vsi->rx_rings[queue];
 	tx_ring = vsi->tx_rings[queue];
 
-	if (ITR_IS_DYNAMIC(rx_ring->rx_itr_setting))
+	if (ITR_IS_DYNAMIC(rx_ring->itr_setting))
 		ec->use_adaptive_rx_coalesce = 1;
 
-	if (ITR_IS_DYNAMIC(tx_ring->tx_itr_setting))
+	if (ITR_IS_DYNAMIC(tx_ring->itr_setting))
 		ec->use_adaptive_tx_coalesce = 1;
 
-	ec->rx_coalesce_usecs = rx_ring->rx_itr_setting & ~I40E_ITR_DYNAMIC;
-	ec->tx_coalesce_usecs = tx_ring->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+	ec->rx_coalesce_usecs = rx_ring->itr_setting & ~I40E_ITR_DYNAMIC;
+	ec->tx_coalesce_usecs = tx_ring->itr_setting & ~I40E_ITR_DYNAMIC;
 
 	/* we use the _usecs_high to store/set the interrupt rate limit
 	 * that the hardware supports, that almost but not quite
@@ -2311,34 +2311,35 @@ static void i40e_set_itr_per_queue(struct i40e_vsi *vsi,
 	struct i40e_pf *pf = vsi->back;
 	struct i40e_hw *hw = &pf->hw;
 	struct i40e_q_vector *q_vector;
-	u16 vector, intrl;
+	u16 intrl;
 
 	intrl = i40e_intrl_usec_to_reg(vsi->int_rate_limit);
 
-	rx_ring->rx_itr_setting = ec->rx_coalesce_usecs;
-	tx_ring->tx_itr_setting = ec->tx_coalesce_usecs;
+	rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
+	tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);
 
 	if (ec->use_adaptive_rx_coalesce)
-		rx_ring->rx_itr_setting |= I40E_ITR_DYNAMIC;
+		rx_ring->itr_setting |= I40E_ITR_DYNAMIC;
 	else
-		rx_ring->rx_itr_setting &= ~I40E_ITR_DYNAMIC;
+		rx_ring->itr_setting &= ~I40E_ITR_DYNAMIC;
 
 	if (ec->use_adaptive_tx_coalesce)
-		tx_ring->tx_itr_setting |= I40E_ITR_DYNAMIC;
+		tx_ring->itr_setting |= I40E_ITR_DYNAMIC;
 	else
-		tx_ring->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
+		tx_ring->itr_setting &= ~I40E_ITR_DYNAMIC;
 
 	q_vector = rx_ring->q_vector;
-	q_vector->rx.itr = ITR_TO_REG(rx_ring->rx_itr_setting);
-	vector = vsi->base_vector + q_vector->v_idx;
-	wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1), q_vector->rx.itr);
+	q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
 
 	q_vector = tx_ring->q_vector;
-	q_vector->tx.itr = ITR_TO_REG(tx_ring->tx_itr_setting);
-	vector = vsi->base_vector + q_vector->v_idx;
-	wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1), q_vector->tx.itr);
+	q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
 
-	wr32(hw, I40E_PFINT_RATEN(vector - 1), intrl);
+	/* The interrupt handler itself will take care of programming
+	 * the Tx and Rx ITR values based on the values we have entered
+	 * into the q_vector, no need to write the values now.
+	 */
+
+	wr32(hw, I40E_PFINT_RATEN(q_vector->reg_idx), intrl);
 	i40e_flush(hw);
 }
 
@@ -2364,11 +2365,11 @@ static int __i40e_set_coalesce(struct net_device *netdev,
 		vsi->work_limit = ec->tx_max_coalesced_frames_irq;
 
 	if (queue < 0) {
-		cur_rx_itr = vsi->rx_rings[0]->rx_itr_setting;
-		cur_tx_itr = vsi->tx_rings[0]->tx_itr_setting;
+		cur_rx_itr = vsi->rx_rings[0]->itr_setting;
+		cur_tx_itr = vsi->tx_rings[0]->itr_setting;
 	} else if (queue < vsi->num_queue_pairs) {
-		cur_rx_itr = vsi->rx_rings[queue]->rx_itr_setting;
-		cur_tx_itr = vsi->tx_rings[queue]->tx_itr_setting;
+		cur_rx_itr = vsi->rx_rings[queue]->itr_setting;
+		cur_tx_itr = vsi->tx_rings[queue]->itr_setting;
 	} else {
 		netif_info(pf, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
 			   vsi->num_queue_pairs - 1);
@@ -2396,7 +2397,7 @@ static int __i40e_set_coalesce(struct net_device *netdev,
 		return -EINVAL;
 	}
 
-	if (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1)) {
+	if (ec->rx_coalesce_usecs > I40E_MAX_ITR) {
 		netif_info(pf, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
 		return -EINVAL;
 	}
@@ -2407,16 +2408,16 @@ static int __i40e_set_coalesce(struct net_device *netdev,
 		return -EINVAL;
 	}
 
-	if (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1)) {
+	if (ec->tx_coalesce_usecs > I40E_MAX_ITR) {
 		netif_info(pf, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
 		return -EINVAL;
 	}
 
 	if (ec->use_adaptive_rx_coalesce && !cur_rx_itr)
-		ec->rx_coalesce_usecs = I40E_MIN_ITR << 1;
+		ec->rx_coalesce_usecs = I40E_MIN_ITR;
 
 	if (ec->use_adaptive_tx_coalesce && !cur_tx_itr)
-		ec->tx_coalesce_usecs = I40E_MIN_ITR << 1;
+		ec->tx_coalesce_usecs = I40E_MIN_ITR;
 
 	intrl_reg = i40e_intrl_usec_to_reg(ec->rx_coalesce_usecs_high);
 	vsi->int_rate_limit = INTRL_REG_TO_USEC(intrl_reg);
@@ -4406,6 +4407,8 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
 	}
 
 flags_complete:
+	changed_flags = orig_flags ^ new_flags;
+
 	/* Before we finalize any flag changes, we need to perform some
 	 * checks to ensure that the changes are supported and safe.
 	 */
@@ -4415,21 +4418,17 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
 	    !(pf->hw_features & I40E_HW_ATR_EVICT_CAPABLE))
 		return -EOPNOTSUPP;
 
-	/* Disable FW LLDP not supported if NPAR active or if FW
-	 * API version < 1.7
+	/* If the driver detected FW LLDP was disabled on init, this flag could
+	 * be set, however we do not support _changing_ the flag if NPAR is
+	 * enabled or FW API version < 1.7.  There are situations where older
+	 * FW versions/NPAR enabled PFs could disable LLDP, however we _must_
+	 * not allow the user to enable/disable LLDP with this flag on
+	 * unsupported FW versions.
 	 */
-	if (new_flags & I40E_FLAG_DISABLE_FW_LLDP) {
-		if (pf->hw.func_caps.npar_enable) {
-			dev_warn(&pf->pdev->dev,
-				 "Unable to stop FW LLDP if NPAR active\n");
-			return -EOPNOTSUPP;
-		}
-
-		if (pf->hw.aq.api_maj_ver < 1 ||
-		    (pf->hw.aq.api_maj_ver == 1 &&
-		     pf->hw.aq.api_min_ver < 7)) {
+	if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
+		if (!(pf->hw_features & I40E_HW_STOPPABLE_FW_LLDP)) {
 			dev_warn(&pf->pdev->dev,
-				 "FW ver does not support stopping FW LLDP\n");
+				 "Device does not support changing FW LLDP\n");
 			return -EOPNOTSUPP;
 		}
 	}
@@ -4439,6 +4438,10 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
 	 * something else has modified the flags variable since we copied it
 	 * originally. We'll just punt with an error and log something in the
 	 * message buffer.
+	 *
+	 * This is the point of no return for this function.  We need to have
+	 * checked any discrepancies or misconfigurations and returned
+	 * EOPNOTSUPP before updating pf->flags here.
 	 */
 	if (cmpxchg64(&pf->flags, orig_flags, new_flags) != orig_flags) {
 		dev_warn(&pf->pdev->dev,
@@ -4446,8 +4449,6 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
 		return -EAGAIN;
 	}
 
-	changed_flags = orig_flags ^ new_flags;
-
 	/* Process any additional changes needed as a result of flag changes.
 	 * The changed_flags value reflects the list of bits that were
 	 * changed in the code above.
@@ -4479,6 +4480,12 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
 		}
 	}
 
+	if ((changed_flags & pf->flags &
+	     I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
+	    (pf->flags & I40E_FLAG_MFP_ENABLED))
+		dev_warn(&pf->pdev->dev,
+			 "Turning on link-down-on-close flag may affect other partitions\n");
+
 	if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
 		if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) {
 			struct i40e_dcbx_config *dcbcfg;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index e31adbc75f9c..f6d37456f3b7 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -69,12 +69,6 @@ static int i40e_reset(struct i40e_pf *pf);
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);
 static void i40e_fdir_sb_setup(struct i40e_pf *pf);
 static int i40e_veb_get_bw_info(struct i40e_veb *veb);
-static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
-				     struct i40e_cloud_filter *filter,
-				     bool add);
-static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
-					     struct i40e_cloud_filter *filter,
-					     bool add);
 static int i40e_get_capabilities(struct i40e_pf *pf,
 				 enum i40e_admin_queue_opc list_type);
 
@@ -215,8 +209,8 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
 
 	if (!pile || needed == 0 || id >= I40E_PILE_VALID_BIT) {
 		dev_info(&pf->pdev->dev,
-			 "param err: pile=%p needed=%d id=0x%04x\n",
-			 pile, needed, id);
+			 "param err: pile=%s needed=%d id=0x%04x\n",
+			 pile ? "<valid>" : "<null>", needed, id);
 		return -EINVAL;
 	}
 
@@ -1380,14 +1374,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
 
 		ether_addr_copy(f->macaddr, macaddr);
 		f->vlan = vlan;
-		/* If we're in overflow promisc mode, set the state directly
-		 * to failed, so we don't bother to try sending the filter
-		 * to the hardware.
-		 */
-		if (test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state))
-			f->state = I40E_FILTER_FAILED;
-		else
-			f->state = I40E_FILTER_NEW;
+		f->state = I40E_FILTER_NEW;
 		INIT_HLIST_NODE(&f->hlist);
 
 		key = i40e_addr_to_hkey(macaddr);
@@ -2116,17 +2103,16 @@ void i40e_aqc_del_filters(struct i40e_vsi *vsi, const char *vsi_name,
  * @list: the list of filters to send to firmware
  * @add_head: Position in the add hlist
  * @num_add: the number of filters to add
- * @promisc_change: set to true on exit if promiscuous mode was forced on
  *
  * Send a request to firmware via AdminQ to add a chunk of filters. Will set
- * promisc_changed to true if the firmware has run out of space for more
- * filters.
+ * __I40E_VSI_OVERFLOW_PROMISC bit in vsi->state if the firmware has run out of
+ * space for more filters.
  */
 static
 void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
 			  struct i40e_aqc_add_macvlan_element_data *list,
 			  struct i40e_new_mac_filter *add_head,
-			  int num_add, bool *promisc_changed)
+			  int num_add)
 {
 	struct i40e_hw *hw = &vsi->back->hw;
 	int aq_err, fcnt;
@@ -2136,7 +2122,6 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
 	fcnt = i40e_update_filter_state(num_add, list, add_head);
 
 	if (fcnt != num_add) {
-		*promisc_changed = true;
 		set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
 		dev_warn(&vsi->back->pdev->dev,
 			 "Error %s adding RX filters on %s, promiscuous mode forced on\n",
@@ -2177,11 +2162,13 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
 							    NULL);
 	}
 
-	if (aq_ret)
+	if (aq_ret) {
+		set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
 		dev_warn(&vsi->back->pdev->dev,
-			 "Error %s setting broadcast promiscuous mode on %s\n",
+			 "Error %s, forcing overflow promiscuous on %s\n",
 			 i40e_aq_str(hw, hw->aq.asq_last_status),
 			 vsi_name);
+	}
 
 	return aq_ret;
 }
@@ -2267,9 +2254,9 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 	struct i40e_mac_filter *f;
 	struct i40e_new_mac_filter *new, *add_head = NULL;
 	struct i40e_hw *hw = &vsi->back->hw;
+	bool old_overflow, new_overflow;
 	unsigned int failed_filters = 0;
 	unsigned int vlan_filters = 0;
-	bool promisc_changed = false;
 	char vsi_name[16] = "PF";
 	int filter_list_len = 0;
 	i40e_status aq_ret = 0;
@@ -2291,6 +2278,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 		usleep_range(1000, 2000);
 	pf = vsi->back;
 
+	old_overflow = test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
+
 	if (vsi->netdev) {
 		changed_flags = vsi->current_netdev_flags ^ vsi->netdev->flags;
 		vsi->current_netdev_flags = vsi->netdev->flags;
@@ -2423,12 +2412,6 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 
 		num_add = 0;
 		hlist_for_each_entry_safe(new, h, &tmp_add_list, hlist) {
-			if (test_bit(__I40E_VSI_OVERFLOW_PROMISC,
-				     vsi->state)) {
-				new->state = I40E_FILTER_FAILED;
-				continue;
-			}
-
 			/* handle broadcast filters by updating the broadcast
 			 * promiscuous flag instead of adding a MAC filter.
 			 */
@@ -2464,15 +2447,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 			/* flush a full buffer */
 			if (num_add == filter_list_len) {
 				i40e_aqc_add_filters(vsi, vsi_name, add_list,
-						     add_head, num_add,
-						     &promisc_changed);
+						     add_head, num_add);
 				memset(add_list, 0, list_size);
 				num_add = 0;
 			}
 		}
 		if (num_add) {
 			i40e_aqc_add_filters(vsi, vsi_name, add_list, add_head,
-					     num_add, &promisc_changed);
+					     num_add);
 		}
 		/* Now move all of the filters from the temp add list back to
 		 * the VSI's list.
@@ -2501,24 +2483,16 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 	}
 	spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
-	/* If promiscuous mode has changed, we need to calculate a new
-	 * threshold for when we are safe to exit
-	 */
-	if (promisc_changed)
-		vsi->promisc_threshold = (vsi->active_filters * 3) / 4;
-
 	/* Check if we are able to exit overflow promiscuous mode. We can
 	 * safely exit if we didn't just enter, we no longer have any failed
 	 * filters, and we have reduced filters below the threshold value.
 	 */
-	if (test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state) &&
-	    !promisc_changed && !failed_filters &&
-	    (vsi->active_filters < vsi->promisc_threshold)) {
+	if (old_overflow && !failed_filters &&
+	    vsi->active_filters < vsi->promisc_threshold) {
 		dev_info(&pf->pdev->dev,
 			 "filter logjam cleared on %s, leaving overflow promiscuous mode\n",
 			 vsi_name);
 		clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
-		promisc_changed = true;
 		vsi->promisc_threshold = 0;
 	}
 
@@ -2528,6 +2502,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 		goto out;
 	}
 
+	new_overflow = test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
+
+	/* If we are entering overflow promiscuous, we need to calculate a new
+	 * threshold for when we are safe to exit
+	 */
+	if (!old_overflow && new_overflow)
+		vsi->promisc_threshold = (vsi->active_filters * 3) / 4;
+
 	/* check for changes in promiscuous modes */
 	if (changed_flags & IFF_ALLMULTI) {
 		bool cur_multipromisc;
@@ -2548,12 +2530,11 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 		}
 	}
 
-	if ((changed_flags & IFF_PROMISC) || promisc_changed) {
+	if ((changed_flags & IFF_PROMISC) || old_overflow != new_overflow) {
 		bool cur_promisc;
 
 		cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
-			       test_bit(__I40E_VSI_OVERFLOW_PROMISC,
-					vsi->state));
+			       new_overflow);
 		aq_ret = i40e_set_promiscuous(pf, cur_promisc);
 		if (aq_ret) {
 			retval = i40e_aq_rc_to_posix(aq_ret,
@@ -3449,15 +3430,20 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
 	for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
 		struct i40e_q_vector *q_vector = vsi->q_vectors[i];
 
-		q_vector->itr_countdown = ITR_COUNTDOWN_START;
-		q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[i]->rx_itr_setting);
-		q_vector->rx.latency_range = I40E_LOW_LATENCY;
+		q_vector->rx.next_update = jiffies + 1;
+		q_vector->rx.target_itr =
+			ITR_TO_REG(vsi->rx_rings[i]->itr_setting);
 		wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
-		     q_vector->rx.itr);
-		q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[i]->tx_itr_setting);
-		q_vector->tx.latency_range = I40E_LOW_LATENCY;
+		     q_vector->rx.target_itr);
+		q_vector->rx.current_itr = q_vector->rx.target_itr;
+
+		q_vector->tx.next_update = jiffies + 1;
+		q_vector->tx.target_itr =
+			ITR_TO_REG(vsi->tx_rings[i]->itr_setting);
 		wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
-		     q_vector->tx.itr);
+		     q_vector->tx.target_itr);
+		q_vector->tx.current_itr = q_vector->tx.target_itr;
+
 		wr32(hw, I40E_PFINT_RATEN(vector - 1),
 		     i40e_intrl_usec_to_reg(vsi->int_rate_limit));
 
@@ -3558,13 +3544,14 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
 	u32 val;
 
 	/* set the ITR configuration */
-	q_vector->itr_countdown = ITR_COUNTDOWN_START;
-	q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[0]->rx_itr_setting);
-	q_vector->rx.latency_range = I40E_LOW_LATENCY;
-	wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.itr);
-	q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[0]->tx_itr_setting);
-	q_vector->tx.latency_range = I40E_LOW_LATENCY;
-	wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr);
+	q_vector->rx.next_update = jiffies + 1;
+	q_vector->rx.target_itr = ITR_TO_REG(vsi->rx_rings[0]->itr_setting);
+	wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr);
+	q_vector->rx.current_itr = q_vector->rx.target_itr;
+	q_vector->tx.next_update = jiffies + 1;
+	q_vector->tx.target_itr = ITR_TO_REG(vsi->tx_rings[0]->itr_setting);
+	wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr);
+	q_vector->tx.current_itr = q_vector->tx.target_itr;
 
 	i40e_enable_misc_int_causes(pf);
 
@@ -5375,7 +5362,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
  * @vsi: VSI to be configured
  *
  **/
-int i40e_get_link_speed(struct i40e_vsi *vsi)
+static int i40e_get_link_speed(struct i40e_vsi *vsi)
 {
 	struct i40e_pf *pf = vsi->back;
 
@@ -6848,8 +6835,8 @@ i40e_set_cld_element(struct i40e_cloud_filter *filter,
  * Add or delete a cloud filter for a specific flow spec.
  * Returns 0 if the filter were successfully added.
  **/
-static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
-				     struct i40e_cloud_filter *filter, bool add)
+int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
+			      struct i40e_cloud_filter *filter, bool add)
 {
 	struct i40e_aqc_cloud_filters_element_data cld_filter;
 	struct i40e_pf *pf = vsi->back;
@@ -6915,9 +6902,9 @@ static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
  * Add or delete a cloud filter for a specific flow spec using big buffer.
  * Returns 0 if the filter were successfully added.
  **/
-static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
-					     struct i40e_cloud_filter *filter,
-					     bool add)
+int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
+				      struct i40e_cloud_filter *filter,
+				      bool add)
 {
 	struct i40e_aqc_cloud_filters_element_bb cld_filter;
 	struct i40e_pf *pf = vsi->back;
@@ -9215,6 +9202,17 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
 	}
 	i40e_get_oem_version(&pf->hw);
 
+	if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
+	    ((hw->aq.fw_maj_ver == 4 && hw->aq.fw_min_ver <= 33) ||
+	     hw->aq.fw_maj_ver < 4) && hw->mac.type == I40E_MAC_XL710) {
+		/* The following delay is necessary for 4.33 firmware and older
+		 * to recover after EMP reset. 200 ms should suffice but we
+		 * put here 300 ms to be sure that FW is ready to operate
+		 * after reset.
+		 */
+		mdelay(300);
+	}
+
 	/* re-verify the eeprom if we just had an EMP reset */
 	if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state))
 		i40e_verify_eeprom(pf);
@@ -9937,18 +9935,17 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi)
 
 	mutex_lock(&pf->switch_mutex);
 	if (!pf->vsi[vsi->idx]) {
-		dev_err(&pf->pdev->dev, "pf->vsi[%d] is NULL, just free vsi[%d](%p,type %d)\n",
-			vsi->idx, vsi->idx, vsi, vsi->type);
+		dev_err(&pf->pdev->dev, "pf->vsi[%d] is NULL, just free vsi[%d](type %d)\n",
+			vsi->idx, vsi->idx, vsi->type);
 		goto unlock_vsi;
 	}
 
 	if (pf->vsi[vsi->idx] != vsi) {
 		dev_err(&pf->pdev->dev,
-			"pf->vsi[%d](%p, type %d) != vsi[%d](%p,type %d): no free!\n",
+			"pf->vsi[%d](type %d) != vsi[%d](type %d): no free!\n",
 			pf->vsi[vsi->idx]->idx,
-			pf->vsi[vsi->idx],
 			pf->vsi[vsi->idx]->type,
-			vsi->idx, vsi, vsi->type);
+			vsi->idx, vsi->type);
 		goto unlock_vsi;
 	}
 
@@ -10018,7 +10015,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
 		ring->dcb_tc = 0;
 		if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
 			ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
-		ring->tx_itr_setting = pf->tx_itr_default;
+		ring->itr_setting = pf->tx_itr_default;
 		vsi->tx_rings[i] = ring++;
 
 		if (!i40e_enabled_xdp_vsi(vsi))
@@ -10036,7 +10033,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
 		if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
 			ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
 		set_ring_xdp(ring);
-		ring->tx_itr_setting = pf->tx_itr_default;
+		ring->itr_setting = pf->tx_itr_default;
 		vsi->xdp_rings[i] = ring++;
 
 setup_rx:
@@ -10049,7 +10046,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
 		ring->count = vsi->num_desc;
 		ring->size = 0;
 		ring->dcb_tc = 0;
-		ring->rx_itr_setting = pf->rx_itr_default;
+		ring->itr_setting = pf->rx_itr_default;
 		vsi->rx_rings[i] = ring;
 	}
 
@@ -10328,9 +10325,6 @@ static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx, int cpu)
 		netif_napi_add(vsi->netdev, &q_vector->napi,
 			       i40e_napi_poll, NAPI_POLL_WEIGHT);
 
-	q_vector->rx.latency_range = I40E_LOW_LATENCY;
-	q_vector->tx.latency_range = I40E_LOW_LATENCY;
-
 	/* tie q_vector and vsi together */
 	vsi->q_vectors[v_idx] = q_vector;
 
@@ -11089,6 +11083,16 @@ static int i40e_sw_init(struct i40e_pf *pf)
 		/* IWARP needs one extra vector for CQP just like MISC.*/
 		pf->num_iwarp_msix = (int)num_online_cpus() + 1;
 	}
+	/* Stopping the FW LLDP engine is only supported on the
+	 * XL710 with a FW ver >= 1.7.  Also, stopping FW LLDP
+	 * engine is not supported if NPAR is functioning on this
+	 * part
+	 */
+	if (pf->hw.mac.type == I40E_MAC_XL710 &&
+	    !pf->hw.func_caps.npar_enable &&
+	    (pf->hw.aq.api_maj_ver > 1 ||
+	     (pf->hw.aq.api_maj_ver == 1 && pf->hw.aq.api_min_ver > 6)))
+		pf->hw_features |= I40E_HW_STOPPABLE_FW_LLDP;
 
 #ifdef CONFIG_PCI_IOV
 	if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index e554aa6cf070..1ec9b1d8023d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -995,99 +995,241 @@ void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
 	}
 }
 
+static inline bool i40e_container_is_rx(struct i40e_q_vector *q_vector,
+					struct i40e_ring_container *rc)
+{
+	return &q_vector->rx == rc;
+}
+
+static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector)
+{
+	unsigned int divisor;
+
+	switch (q_vector->vsi->back->hw.phy.link_info.link_speed) {
+	case I40E_LINK_SPEED_40GB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 1024;
+		break;
+	case I40E_LINK_SPEED_25GB:
+	case I40E_LINK_SPEED_20GB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 512;
+		break;
+	default:
+	case I40E_LINK_SPEED_10GB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 256;
+		break;
+	case I40E_LINK_SPEED_1GB:
+	case I40E_LINK_SPEED_100MB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 32;
+		break;
+	}
+
+	return divisor;
+}
+
 /**
- * i40e_set_new_dynamic_itr - Find new ITR level
+ * i40e_update_itr - update the dynamic ITR value based on statistics
+ * @q_vector: structure containing interrupt and ring information
  * @rc: structure containing ring performance data
  *
- * Returns true if ITR changed, false if not
- *
- * Stores a new ITR value based on packets and byte counts during
- * the last interrupt.  The advantage of per interrupt computation
- * is faster updates and more accurate ITR for the current traffic
- * pattern.  Constants in this function were computed based on
- * theoretical maximum wire speed and thresholds were set based on
- * testing data as well as attempting to minimize response time
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt.  The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern.  Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
  * while increasing bulk throughput.
  **/
-static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
+static void i40e_update_itr(struct i40e_q_vector *q_vector,
+			    struct i40e_ring_container *rc)
 {
-	enum i40e_latency_range new_latency_range = rc->latency_range;
-	u32 new_itr = rc->itr;
-	int bytes_per_usec;
-	unsigned int usecs, estimated_usecs;
+	unsigned int avg_wire_size, packets, bytes, itr;
+	unsigned long next_update = jiffies;
 
-	if (rc->total_packets == 0 || !rc->itr)
-		return false;
+	/* If we don't have any rings just leave ourselves set for maximum
+	 * possible latency so we take ourselves out of the equation.
+	 */
+	if (!rc->ring || !ITR_IS_DYNAMIC(rc->ring->itr_setting))
+		return;
 
-	usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
-	bytes_per_usec = rc->total_bytes / usecs;
+	/* For Rx we want to push the delay up and default to low latency.
+	 * for Tx we want to pull the delay down and default to high latency.
+	 */
+	itr = i40e_container_is_rx(q_vector, rc) ?
+	      I40E_ITR_ADAPTIVE_MIN_USECS | I40E_ITR_ADAPTIVE_LATENCY :
+	      I40E_ITR_ADAPTIVE_MAX_USECS | I40E_ITR_ADAPTIVE_LATENCY;
+
+	/* If we didn't update within up to 1 - 2 jiffies we can assume
+	 * that either packets are coming in so slow there hasn't been
+	 * any work, or that there is so much work that NAPI is dealing
+	 * with interrupt moderation and we don't need to do anything.
+	 */
+	if (time_after(next_update, rc->next_update))
+		goto clear_counts;
+
+	/* If itr_countdown is set it means we programmed an ITR within
+	 * the last 4 interrupt cycles. This has a side effect of us
+	 * potentially firing an early interrupt. In order to work around
+	 * this we need to throw out any data received for a few
+	 * interrupts following the update.
+	 */
+	if (q_vector->itr_countdown) {
+		itr = rc->target_itr;
+		goto clear_counts;
+	}
+
+	packets = rc->total_packets;
+	bytes = rc->total_bytes;
 
-	/* The calculations in this algorithm depend on interrupts actually
-	 * firing at the ITR rate. This may not happen if the packet rate is
-	 * really low, or if we've been napi polling. Check to make sure
-	 * that's not the case before we continue.
+	if (i40e_container_is_rx(q_vector, rc)) {
+		/* If Rx there are 1 to 4 packets and bytes are less than
+		 * 9000 assume insufficient data to use bulk rate limiting
+		 * approach unless Tx is already in bulk rate limiting. We
+		 * are likely latency driven.
+		 */
+		if (packets && packets < 4 && bytes < 9000 &&
+		    (q_vector->tx.target_itr & I40E_ITR_ADAPTIVE_LATENCY)) {
+			itr = I40E_ITR_ADAPTIVE_LATENCY;
+			goto adjust_by_size;
+		}
+	} else if (packets < 4) {
+		/* If we have Tx and Rx ITR maxed and Tx ITR is running in
+		 * bulk mode and we are receiving 4 or fewer packets just
+		 * reset the ITR_ADAPTIVE_LATENCY bit for latency mode so
+		 * that the Rx can relax.
+		 */
+		if (rc->target_itr == I40E_ITR_ADAPTIVE_MAX_USECS &&
+		    (q_vector->rx.target_itr & I40E_ITR_MASK) ==
+		     I40E_ITR_ADAPTIVE_MAX_USECS)
+			goto clear_counts;
+	} else if (packets > 32) {
+		/* If we have processed over 32 packets in a single interrupt
+		 * for Tx assume we need to switch over to "bulk" mode.
+		 */
+		rc->target_itr &= ~I40E_ITR_ADAPTIVE_LATENCY;
+	}
+
+	/* We have no packets to actually measure against. This means
+	 * either one of the other queues on this vector is active or
+	 * we are a Tx queue doing TSO with too high of an interrupt rate.
+	 *
+	 * Between 4 and 56 we can assume that our current interrupt delay
+	 * is only slightly too low. As such we should increase it by a small
+	 * fixed amount.
 	 */
-	estimated_usecs = jiffies_to_usecs(jiffies - rc->last_itr_update);
-	if (estimated_usecs > usecs) {
-		new_latency_range = I40E_LOW_LATENCY;
-		goto reset_latency;
+	if (packets < 56) {
+		itr = rc->target_itr + I40E_ITR_ADAPTIVE_MIN_INC;
+		if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) {
+			itr &= I40E_ITR_ADAPTIVE_LATENCY;
+			itr += I40E_ITR_ADAPTIVE_MAX_USECS;
+		}
+		goto clear_counts;
 	}
 
-	/* simple throttlerate management
-	 *   0-10MB/s   lowest (50000 ints/s)
-	 *  10-20MB/s   low    (20000 ints/s)
-	 *  20-1249MB/s bulk   (18000 ints/s)
+	if (packets <= 256) {
+		itr = min(q_vector->tx.current_itr, q_vector->rx.current_itr);
+		itr &= I40E_ITR_MASK;
+
+		/* Between 56 and 112 is our "goldilocks" zone where we are
+		 * working out "just right". Just report that our current
+		 * ITR is good for us.
+		 */
+		if (packets <= 112)
+			goto clear_counts;
+
+		/* If packet count is 128 or greater we are likely looking
+		 * at a slight overrun of the delay we want. Try halving
+		 * our delay to see if that will cut the number of packets
+		 * in half per interrupt.
+		 */
+		itr /= 2;
+		itr &= I40E_ITR_MASK;
+		if (itr < I40E_ITR_ADAPTIVE_MIN_USECS)
+			itr = I40E_ITR_ADAPTIVE_MIN_USECS;
+
+		goto clear_counts;
+	}
+
+	/* The paths below assume we are dealing with a bulk ITR since
+	 * number of packets is greater than 256. We are just going to have
+	 * to compute a value and try to bring the count under control,
+	 * though for smaller packet sizes there isn't much we can do as
+	 * NAPI polling will likely be kicking in sooner rather than later.
+	 */
+	itr = I40E_ITR_ADAPTIVE_BULK;
+
+adjust_by_size:
+	/* If packet counts are 256 or greater we can assume we have a gross
+	 * overestimation of what the rate should be. Instead of trying to fine
+	 * tune it just use the formula below to try and dial in an exact value
+	 * give the current packet size of the frame.
+	 */
+	avg_wire_size = bytes / packets;
+
+	/* The following is a crude approximation of:
+	 *  wmem_default / (size + overhead) = desired_pkts_per_int
+	 *  rate / bits_per_byte / (size + ethernet overhead) = pkt_rate
+	 *  (desired_pkt_rate / pkt_rate) * usecs_per_sec = ITR value
 	 *
-	 * The math works out because the divisor is in 10^(-6) which
-	 * turns the bytes/us input value into MB/s values, but
-	 * make sure to use usecs, as the register values written
-	 * are in 2 usec increments in the ITR registers, and make sure
-	 * to use the smoothed values that the countdown timer gives us.
+	 * Assuming wmem_default is 212992 and overhead is 640 bytes per
+	 * packet, (256 skb, 64 headroom, 320 shared info), we can reduce the
+	 * formula down to
+	 *
+	 *  (170 * (size + 24)) / (size + 640) = ITR
+	 *
+	 * We first do some math on the packet size and then finally bitshift
+	 * by 8 after rounding up. We also have to account for PCIe link speed
+	 * difference as ITR scales based on this.
 	 */
-	switch (new_latency_range) {
-	case I40E_LOWEST_LATENCY:
-		if (bytes_per_usec > 10)
-			new_latency_range = I40E_LOW_LATENCY;
-		break;
-	case I40E_LOW_LATENCY:
-		if (bytes_per_usec > 20)
-			new_latency_range = I40E_BULK_LATENCY;
-		else if (bytes_per_usec <= 10)
-			new_latency_range = I40E_LOWEST_LATENCY;
-		break;
-	case I40E_BULK_LATENCY:
-	default:
-		if (bytes_per_usec <= 20)
-			new_latency_range = I40E_LOW_LATENCY;
-		break;
+	if (avg_wire_size <= 60) {
+		/* Start at 250k ints/sec */
+		avg_wire_size = 4096;
+	} else if (avg_wire_size <= 380) {
+		/* 250K ints/sec to 60K ints/sec */
+		avg_wire_size *= 40;
+		avg_wire_size += 1696;
+	} else if (avg_wire_size <= 1084) {
+		/* 60K ints/sec to 36K ints/sec */
+		avg_wire_size *= 15;
+		avg_wire_size += 11452;
+	} else if (avg_wire_size <= 1980) {
+		/* 36K ints/sec to 30K ints/sec */
+		avg_wire_size *= 5;
+		avg_wire_size += 22420;
+	} else {
+		/* plateau at a limit of 30K ints/sec */
+		avg_wire_size = 32256;
 	}
 
-reset_latency:
-	rc->latency_range = new_latency_range;
+	/* If we are in low latency mode halve our delay which doubles the
+	 * rate to somewhere between 100K to 16K ints/sec
+	 */
+	if (itr & I40E_ITR_ADAPTIVE_LATENCY)
+		avg_wire_size /= 2;
 
-	switch (new_latency_range) {
-	case I40E_LOWEST_LATENCY:
-		new_itr = I40E_ITR_50K;
-		break;
-	case I40E_LOW_LATENCY:
-		new_itr = I40E_ITR_20K;
-		break;
-	case I40E_BULK_LATENCY:
-		new_itr = I40E_ITR_18K;
-		break;
-	default:
-		break;
+	/* Resultant value is 256 times larger than it needs to be. This
+	 * gives us room to adjust the value as needed to either increase
+	 * or decrease the value based on link speeds of 10G, 2.5G, 1G, etc.
+	 *
+	 * Use addition as we have already recorded the new latency flag
+	 * for the ITR value.
+	 */
+	itr += DIV_ROUND_UP(avg_wire_size, i40e_itr_divisor(q_vector)) *
+	       I40E_ITR_ADAPTIVE_MIN_INC;
+
+	if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) {
+		itr &= I40E_ITR_ADAPTIVE_LATENCY;
+		itr += I40E_ITR_ADAPTIVE_MAX_USECS;
 	}
 
+clear_counts:
+	/* write back value */
+	rc->target_itr = itr;
+
+	/* next update should occur within next jiffy */
+	rc->next_update = next_update + 1;
+
 	rc->total_bytes = 0;
 	rc->total_packets = 0;
-	rc->last_itr_update = jiffies;
-
-	if (new_itr != rc->itr) {
-		rc->itr = new_itr;
-		return true;
-	}
-	return false;
 }
 
 /**
@@ -1991,7 +2133,7 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
  * @rx_buffer: rx buffer to pull data from
  *
  * This function will clean up the contents of the rx_buffer.  It will
- * either recycle the bufer or unmap it and free the associated resources.
+ * either recycle the buffer or unmap it and free the associated resources.
  */
 static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
 			       struct i40e_rx_buffer *rx_buffer)
@@ -2274,29 +2416,45 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 	return failure ? budget : (int)total_rx_packets;
 }
 
-static u32 i40e_buildreg_itr(const int type, const u16 itr)
+static inline u32 i40e_buildreg_itr(const int type, u16 itr)
 {
 	u32 val;
 
+	/* We don't bother with setting the CLEARPBA bit as the data sheet
+	 * points out doing so is "meaningless since it was already
+	 * auto-cleared". The auto-clearing happens when the interrupt is
+	 * asserted.
+	 *
+	 * Hardware errata 28 for also indicates that writing to a
+	 * xxINT_DYN_CTLx CSR with INTENA_MSK (bit 31) set to 0 will clear
+	 * an event in the PBA anyway so we need to rely on the automask
+	 * to hold pending events for us until the interrupt is re-enabled
+	 *
+	 * The itr value is reported in microseconds, and the register
+	 * value is recorded in 2 microsecond units. For this reason we
+	 * only need to shift by the interval shift - 1 instead of the
+	 * full value.
+	 */
+	itr &= I40E_ITR_MASK;
+
 	val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
-	      I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
 	      (type << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
-	      (itr << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT);
+	      (itr << (I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT - 1));
 
 	return val;
 }
 
 /* a small macro to shorten up some long lines */
 #define INTREG I40E_PFINT_DYN_CTLN
-static inline int get_rx_itr(struct i40e_vsi *vsi, int idx)
-{
-	return vsi->rx_rings[idx]->rx_itr_setting;
-}
 
-static inline int get_tx_itr(struct i40e_vsi *vsi, int idx)
-{
-	return vsi->tx_rings[idx]->tx_itr_setting;
-}
+/* The act of updating the ITR will cause it to immediately trigger. In order
+ * to prevent this from throwing off adaptive update statistics we defer the
+ * update so that it can only happen so often. So after either Tx or Rx are
+ * updated we make the adaptive scheme wait until either the ITR completely
+ * expires via the next_update expiration or we have been through at least
+ * 3 interrupts.
+ */
+#define ITR_COUNTDOWN_START 3
 
 /**
  * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt
@@ -2308,10 +2466,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
 					  struct i40e_q_vector *q_vector)
 {
 	struct i40e_hw *hw = &vsi->back->hw;
-	bool rx = false, tx = false;
-	u32 rxval, txval;
-	int idx = q_vector->v_idx;
-	int rx_itr_setting, tx_itr_setting;
+	u32 intval;
 
 	/* If we don't have MSIX, then we only need to re-enable icr0 */
 	if (!(vsi->back->flags & I40E_FLAG_MSIX_ENABLED)) {
@@ -2319,65 +2474,49 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
 		return;
 	}
 
-	/* avoid dynamic calculation if in countdown mode OR if
-	 * all dynamic is disabled
-	 */
-	rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
-
-	rx_itr_setting = get_rx_itr(vsi, idx);
-	tx_itr_setting = get_tx_itr(vsi, idx);
-
-	if (q_vector->itr_countdown > 0 ||
-	    (!ITR_IS_DYNAMIC(rx_itr_setting) &&
-	     !ITR_IS_DYNAMIC(tx_itr_setting))) {
-		goto enable_int;
-	}
-
-	if (ITR_IS_DYNAMIC(rx_itr_setting)) {
-		rx = i40e_set_new_dynamic_itr(&q_vector->rx);
-		rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
-	}
-
-	if (ITR_IS_DYNAMIC(tx_itr_setting)) {
-		tx = i40e_set_new_dynamic_itr(&q_vector->tx);
-		txval = i40e_buildreg_itr(I40E_TX_ITR, q_vector->tx.itr);
-	}
+	/* These will do nothing if dynamic updates are not enabled */
+	i40e_update_itr(q_vector, &q_vector->tx);
+	i40e_update_itr(q_vector, &q_vector->rx);
 
-	if (rx || tx) {
-		/* get the higher of the two ITR adjustments and
-		 * use the same value for both ITR registers
-		 * when in adaptive mode (Rx and/or Tx)
-		 */
-		u16 itr = max(q_vector->tx.itr, q_vector->rx.itr);
-
-		q_vector->tx.itr = q_vector->rx.itr = itr;
-		txval = i40e_buildreg_itr(I40E_TX_ITR, itr);
-		tx = true;
-		rxval = i40e_buildreg_itr(I40E_RX_ITR, itr);
-		rx = true;
-	}
-
-	/* only need to enable the interrupt once, but need
-	 * to possibly update both ITR values
+	/* This block of logic allows us to get away with only updating
+	 * one ITR value with each interrupt. The idea is to perform a
+	 * pseudo-lazy update with the following criteria.
+	 *
+	 * 1. Rx is given higher priority than Tx if both are in same state
+	 * 2. If we must reduce an ITR that is given highest priority.
+	 * 3. We then give priority to increasing ITR based on amount.
 	 */
-	if (rx) {
-		/* set the INTENA_MSK_MASK so that this first write
-		 * won't actually enable the interrupt, instead just
-		 * updating the ITR (it's bit 31 PF and VF)
+	if (q_vector->rx.target_itr < q_vector->rx.current_itr) {
+		/* Rx ITR needs to be reduced, this is highest priority */
+		intval = i40e_buildreg_itr(I40E_RX_ITR,
+					   q_vector->rx.target_itr);
+		q_vector->rx.current_itr = q_vector->rx.target_itr;
+		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	} else if ((q_vector->tx.target_itr < q_vector->tx.current_itr) ||
+		   ((q_vector->rx.target_itr - q_vector->rx.current_itr) <
+		    (q_vector->tx.target_itr - q_vector->tx.current_itr))) {
+		/* Tx ITR needs to be reduced, this is second priority
+		 * Tx ITR needs to be increased more than Rx, fourth priority
 		 */
-		rxval |= BIT(31);
-		/* don't check _DOWN because interrupt isn't being enabled */
-		wr32(hw, INTREG(q_vector->reg_idx), rxval);
+		intval = i40e_buildreg_itr(I40E_TX_ITR,
+					   q_vector->tx.target_itr);
+		q_vector->tx.current_itr = q_vector->tx.target_itr;
+		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	} else if (q_vector->rx.current_itr != q_vector->rx.target_itr) {
+		/* Rx ITR needs to be increased, third priority */
+		intval = i40e_buildreg_itr(I40E_RX_ITR,
+					   q_vector->rx.target_itr);
+		q_vector->rx.current_itr = q_vector->rx.target_itr;
+		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	} else {
+		/* No ITR update, lowest priority */
+		intval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
+		if (q_vector->itr_countdown)
+			q_vector->itr_countdown--;
 	}
 
-enable_int:
 	if (!test_bit(__I40E_VSI_DOWN, vsi->state))
-		wr32(hw, INTREG(q_vector->reg_idx), txval);
-
-	if (q_vector->itr_countdown)
-		q_vector->itr_countdown--;
-	else
-		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+		wr32(hw, INTREG(q_vector->reg_idx), intval);
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 701b708628b0..f75a8fe68fcf 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -30,32 +30,37 @@
 #include <net/xdp.h>
 
 /* Interrupt Throttling and Rate Limiting Goodies */
-
-#define I40E_MAX_ITR               0x0FF0  /* reg uses 2 usec resolution */
-#define I40E_MIN_ITR               0x0001  /* reg uses 2 usec resolution */
-#define I40E_ITR_100K              0x0005
-#define I40E_ITR_50K               0x000A
-#define I40E_ITR_20K               0x0019
-#define I40E_ITR_18K               0x001B
-#define I40E_ITR_8K                0x003E
-#define I40E_ITR_4K                0x007A
-#define I40E_MAX_INTRL             0x3B    /* reg uses 4 usec resolution */
-#define I40E_ITR_RX_DEF            (ITR_REG_TO_USEC(I40E_ITR_20K) | \
-				    I40E_ITR_DYNAMIC)
-#define I40E_ITR_TX_DEF            (ITR_REG_TO_USEC(I40E_ITR_20K) | \
-				    I40E_ITR_DYNAMIC)
-#define I40E_ITR_DYNAMIC           0x8000  /* use top bit as a flag */
-#define I40E_MIN_INT_RATE          250     /* ~= 1000000 / (I40E_MAX_ITR * 2) */
-#define I40E_MAX_INT_RATE          500000  /* == 1000000 / (I40E_MIN_ITR * 2) */
 #define I40E_DEFAULT_IRQ_WORK      256
-#define ITR_TO_REG(setting) ((setting & ~I40E_ITR_DYNAMIC) >> 1)
-#define ITR_IS_DYNAMIC(setting) (!!(setting & I40E_ITR_DYNAMIC))
-#define ITR_REG_TO_USEC(itr_reg) (itr_reg << 1)
+
+/* The datasheet for the X710 and XL710 indicate that the maximum value for
+ * the ITR is 8160usec which is then called out as 0xFF0 with a 2usec
+ * resolution. 8160 is 0x1FE0 when written out in hex. So instead of storing
+ * the register value which is divided by 2 lets use the actual values and
+ * avoid an excessive amount of translation.
+ */
+#define I40E_ITR_DYNAMIC	0x8000	/* use top bit as a flag */
+#define I40E_ITR_MASK		0x1FFE	/* mask for ITR register value */
+#define I40E_MIN_ITR		     2	/* reg uses 2 usec resolution */
+#define I40E_ITR_100K		    10	/* all values below must be even */
+#define I40E_ITR_50K		    20
+#define I40E_ITR_20K		    50
+#define I40E_ITR_18K		    60
+#define I40E_ITR_8K		   122
+#define I40E_MAX_ITR		  8160	/* maximum value as per datasheet */
+#define ITR_TO_REG(setting) ((setting) & ~I40E_ITR_DYNAMIC)
+#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~I40E_ITR_MASK)
+#define ITR_IS_DYNAMIC(setting) (!!((setting) & I40E_ITR_DYNAMIC))
+
+#define I40E_ITR_RX_DEF		(I40E_ITR_20K | I40E_ITR_DYNAMIC)
+#define I40E_ITR_TX_DEF		(I40E_ITR_20K | I40E_ITR_DYNAMIC)
+
 /* 0x40 is the enable bit for interrupt rate limiting, and must be set if
  * the value of the rate limit is non-zero
  */
 #define INTRL_ENA                  BIT(6)
+#define I40E_MAX_INTRL             0x3B    /* reg uses 4 usec resolution */
 #define INTRL_REG_TO_USEC(intrl) ((intrl & ~INTRL_ENA) << 2)
+
 /**
  * i40e_intrl_usec_to_reg - convert interrupt rate limit to register
  * @intrl: interrupt rate limit to convert
@@ -382,8 +387,7 @@ struct i40e_ring {
 	 * these values always store the USER setting, and must be converted
 	 * before programming to a register.
 	 */
-	u16 rx_itr_setting;
-	u16 tx_itr_setting;
+	u16 itr_setting;
 
 	u16 count;			/* Number of descriptors */
 	u16 reg_idx;			/* HW register index of the ring */
@@ -459,21 +463,21 @@ static inline void set_ring_xdp(struct i40e_ring *ring)
 	ring->flags |= I40E_TXR_FLAGS_XDP;
 }
 
-enum i40e_latency_range {
-	I40E_LOWEST_LATENCY = 0,
-	I40E_LOW_LATENCY = 1,
-	I40E_BULK_LATENCY = 2,
-};
+#define I40E_ITR_ADAPTIVE_MIN_INC	0x0002
+#define I40E_ITR_ADAPTIVE_MIN_USECS	0x0002
+#define I40E_ITR_ADAPTIVE_MAX_USECS	0x007e
+#define I40E_ITR_ADAPTIVE_LATENCY	0x8000
+#define I40E_ITR_ADAPTIVE_BULK		0x0000
+#define ITR_IS_BULK(x) (!((x) & I40E_ITR_ADAPTIVE_LATENCY))
 
 struct i40e_ring_container {
-	/* array of pointers to rings */
-	struct i40e_ring *ring;
+	struct i40e_ring *ring;		/* pointer to linked list of ring(s) */
+	unsigned long next_update;	/* jiffies value of next update */
 	unsigned int total_bytes;	/* total bytes processed this int */
 	unsigned int total_packets;	/* total packets processed this int */
-	unsigned long last_itr_update;	/* jiffies of last ITR update */
 	u16 count;
-	enum i40e_latency_range latency_range;
-	u16 itr;
+	u16 target_itr;			/* target ITR setting for ring(s) */
+	u16 current_itr;		/* current ITR setting for ring(s) */
 };
 
 /* iterator for handling rings in ring container */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index cd294e6a8587..b0eed8c0b2f2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -39,7 +39,7 @@
 #define I40E_MASK(mask, shift) ((u32)(mask) << (shift))
 
 #define I40E_MAX_VSI_QP			16
-#define I40E_MAX_VF_VSI			3
+#define I40E_MAX_VF_VSI			4
 #define I40E_MAX_CHAINED_RX_BUFFERS	5
 #define I40E_MAX_PF_UDP_OFFLOAD_PORTS	16
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index e9309fb9084b..5cca083da93c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -257,6 +257,38 @@ static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u16 vsi_id,
 	return pf_queue_id;
 }
 
+/**
+ * i40e_get_real_pf_qid
+ * @vf: pointer to the VF info
+ * @vsi_id: vsi id
+ * @queue_id: queue number
+ *
+ * wrapper function to get pf_queue_id handling ADq code as well
+ **/
+static u16 i40e_get_real_pf_qid(struct i40e_vf *vf, u16 vsi_id, u16 queue_id)
+{
+	int i;
+
+	if (vf->adq_enabled) {
+		/* Although VF considers all the queues(can be 1 to 16) as its
+		 * own but they may actually belong to different VSIs(up to 4).
+		 * We need to find which queues belongs to which VSI.
+		 */
+		for (i = 0; i < vf->num_tc; i++) {
+			if (queue_id < vf->ch[i].num_qps) {
+				vsi_id = vf->ch[i].vsi_id;
+				break;
+			}
+			/* find right queue id which is relative to a
+			 * given VSI.
+			 */
+			queue_id -= vf->ch[i].num_qps;
+			}
+		}
+
+	return i40e_vc_get_pf_queue_id(vf, vsi_id, queue_id);
+}
+
 /**
  * i40e_config_irq_link_list
  * @vf: pointer to the VF info
@@ -310,7 +342,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,
 
 	vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;
 	qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;
-	pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id);
+	pf_queue_id = i40e_get_real_pf_qid(vf, vsi_id, vsi_queue_id);
 	reg = ((qtype << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) | pf_queue_id);
 
 	wr32(hw, reg_idx, reg);
@@ -333,8 +365,9 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,
 		if (next_q < size) {
 			vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;
 			qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;
-			pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id,
-							      vsi_queue_id);
+			pf_queue_id = i40e_get_real_pf_qid(vf,
+							   vsi_id,
+							   vsi_queue_id);
 		} else {
 			pf_queue_id = I40E_QUEUE_END_OF_LIST;
 			qtype = 0;
@@ -669,18 +702,20 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,
 /**
  * i40e_alloc_vsi_res
  * @vf: pointer to the VF info
- * @type: type of VSI to allocate
+ * @idx: VSI index, applies only for ADq mode, zero otherwise
  *
  * alloc VF vsi context & resources
  **/
-static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
+static int i40e_alloc_vsi_res(struct i40e_vf *vf, u8 idx)
 {
 	struct i40e_mac_filter *f = NULL;
 	struct i40e_pf *pf = vf->pf;
 	struct i40e_vsi *vsi;
+	u64 max_tx_rate = 0;
 	int ret = 0;
 
-	vsi = i40e_vsi_setup(pf, type, pf->vsi[pf->lan_vsi]->seid, vf->vf_id);
+	vsi = i40e_vsi_setup(pf, I40E_VSI_SRIOV, pf->vsi[pf->lan_vsi]->seid,
+			     vf->vf_id);
 
 	if (!vsi) {
 		dev_err(&pf->pdev->dev,
@@ -689,7 +724,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
 		ret = -ENOENT;
 		goto error_alloc_vsi_res;
 	}
-	if (type == I40E_VSI_SRIOV) {
+
+	if (!idx) {
 		u64 hena = i40e_pf_get_default_rss_hena(pf);
 		u8 broadcast[ETH_ALEN];
 
@@ -721,17 +757,29 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
 		spin_unlock_bh(&vsi->mac_filter_hash_lock);
 		wr32(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena);
 		wr32(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), (u32)(hena >> 32));
+		/* program mac filter only for VF VSI */
+		ret = i40e_sync_vsi_filters(vsi);
+		if (ret)
+			dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
 	}
 
-	/* program mac filter */
-	ret = i40e_sync_vsi_filters(vsi);
-	if (ret)
-		dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
+	/* storing VSI index and id for ADq and don't apply the mac filter */
+	if (vf->adq_enabled) {
+		vf->ch[idx].vsi_idx = vsi->idx;
+		vf->ch[idx].vsi_id = vsi->id;
+	}
 
 	/* Set VF bandwidth if specified */
 	if (vf->tx_rate) {
+		max_tx_rate = vf->tx_rate;
+	} else if (vf->ch[idx].max_tx_rate) {
+		max_tx_rate = vf->ch[idx].max_tx_rate;
+	}
+
+	if (max_tx_rate) {
+		max_tx_rate = div_u64(max_tx_rate, I40E_BW_CREDIT_DIVISOR);
 		ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid,
-						  vf->tx_rate / 50, 0, NULL);
+						  max_tx_rate, 0, NULL);
 		if (ret)
 			dev_err(&pf->pdev->dev, "Unable to set tx rate, VF %d, error code %d.\n",
 				vf->vf_id, ret);
@@ -741,6 +789,92 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
 	return ret;
 }
 
+/**
+ * i40e_map_pf_queues_to_vsi
+ * @vf: pointer to the VF info
+ *
+ * PF maps LQPs to a VF by programming VSILAN_QTABLE & VPLAN_QTABLE. This
+ * function takes care of first part VSILAN_QTABLE, mapping pf queues to VSI.
+ **/
+static void i40e_map_pf_queues_to_vsi(struct i40e_vf *vf)
+{
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_hw *hw = &pf->hw;
+	u32 reg, num_tc = 1; /* VF has at least one traffic class */
+	u16 vsi_id, qps;
+	int i, j;
+
+	if (vf->adq_enabled)
+		num_tc = vf->num_tc;
+
+	for (i = 0; i < num_tc; i++) {
+		if (vf->adq_enabled) {
+			qps = vf->ch[i].num_qps;
+			vsi_id =  vf->ch[i].vsi_id;
+		} else {
+			qps = pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
+			vsi_id = vf->lan_vsi_id;
+		}
+
+		for (j = 0; j < 7; j++) {
+			if (j * 2 >= qps) {
+				/* end of list */
+				reg = 0x07FF07FF;
+			} else {
+				u16 qid = i40e_vc_get_pf_queue_id(vf,
+								  vsi_id,
+								  j * 2);
+				reg = qid;
+				qid = i40e_vc_get_pf_queue_id(vf, vsi_id,
+							      (j * 2) + 1);
+				reg |= qid << 16;
+			}
+			i40e_write_rx_ctl(hw,
+					  I40E_VSILAN_QTABLE(j, vsi_id),
+					  reg);
+		}
+	}
+}
+
+/**
+ * i40e_map_pf_to_vf_queues
+ * @vf: pointer to the VF info
+ *
+ * PF maps LQPs to a VF by programming VSILAN_QTABLE & VPLAN_QTABLE. This
+ * function takes care of the second part VPLAN_QTABLE & completes VF mappings.
+ **/
+static void i40e_map_pf_to_vf_queues(struct i40e_vf *vf)
+{
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_hw *hw = &pf->hw;
+	u32 reg, total_qps = 0;
+	u32 qps, num_tc = 1; /* VF has at least one traffic class */
+	u16 vsi_id, qid;
+	int i, j;
+
+	if (vf->adq_enabled)
+		num_tc = vf->num_tc;
+
+	for (i = 0; i < num_tc; i++) {
+		if (vf->adq_enabled) {
+			qps = vf->ch[i].num_qps;
+			vsi_id =  vf->ch[i].vsi_id;
+		} else {
+			qps = pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
+			vsi_id = vf->lan_vsi_id;
+		}
+
+		for (j = 0; j < qps; j++) {
+			qid = i40e_vc_get_pf_queue_id(vf, vsi_id, j);
+
+			reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
+			wr32(hw, I40E_VPLAN_QTABLE(total_qps, vf->vf_id),
+			     reg);
+			total_qps++;
+		}
+	}
+}
+
 /**
  * i40e_enable_vf_mappings
  * @vf: pointer to the VF info
@@ -751,8 +885,7 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
 {
 	struct i40e_pf *pf = vf->pf;
 	struct i40e_hw *hw = &pf->hw;
-	u32 reg, total_queue_pairs = 0;
-	int j;
+	u32 reg;
 
 	/* Tell the hardware we're using noncontiguous mapping. HW requires
 	 * that VF queues be mapped using this method, even when they are
@@ -765,30 +898,8 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
 	reg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;
 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);
 
-	/* map PF queues to VF queues */
-	for (j = 0; j < pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs; j++) {
-		u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id, j);
-
-		reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
-		wr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg);
-		total_queue_pairs++;
-	}
-
-	/* map PF queues to VSI */
-	for (j = 0; j < 7; j++) {
-		if (j * 2 >= pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs) {
-			reg = 0x07FF07FF;	/* unused */
-		} else {
-			u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id,
-							  j * 2);
-			reg = qid;
-			qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id,
-						      (j * 2) + 1);
-			reg |= qid << 16;
-		}
-		i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id),
-				  reg);
-	}
+	i40e_map_pf_to_vf_queues(vf);
+	i40e_map_pf_queues_to_vsi(vf);
 
 	i40e_flush(hw);
 }
@@ -824,7 +935,7 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
 	struct i40e_pf *pf = vf->pf;
 	struct i40e_hw *hw = &pf->hw;
 	u32 reg_idx, reg;
-	int i, msix_vf;
+	int i, j, msix_vf;
 
 	/* Start by disabling VF's configuration API to prevent the OS from
 	 * accessing the VF's VSI after it's freed / invalidated.
@@ -846,6 +957,20 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
 		vf->lan_vsi_id = 0;
 		vf->num_mac = 0;
 	}
+
+	/* do the accounting and remove additional ADq VSI's */
+	if (vf->adq_enabled && vf->ch[0].vsi_idx) {
+		for (j = 0; j < vf->num_tc; j++) {
+			/* At this point VSI0 is already released so don't
+			 * release it again and only clear their values in
+			 * structure variables
+			 */
+			if (j)
+				i40e_vsi_release(pf->vsi[vf->ch[j].vsi_idx]);
+			vf->ch[j].vsi_idx = 0;
+			vf->ch[j].vsi_id = 0;
+		}
+	}
 	msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
 
 	/* disable interrupts so the VF starts in a known state */
@@ -891,7 +1016,7 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
 {
 	struct i40e_pf *pf = vf->pf;
 	int total_queue_pairs = 0;
-	int ret;
+	int ret, idx;
 
 	if (vf->num_req_queues &&
 	    vf->num_req_queues <= pf->queues_left + I40E_DEFAULT_QUEUES_PER_VF)
@@ -900,11 +1025,30 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
 		pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;
 
 	/* allocate hw vsi context & associated resources */
-	ret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV);
+	ret = i40e_alloc_vsi_res(vf, 0);
 	if (ret)
 		goto error_alloc;
 	total_queue_pairs += pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
 
+	/* allocate additional VSIs based on tc information for ADq */
+	if (vf->adq_enabled) {
+		if (pf->queues_left >=
+		    (I40E_MAX_VF_QUEUES - I40E_DEFAULT_QUEUES_PER_VF)) {
+			/* TC 0 always belongs to VF VSI */
+			for (idx = 1; idx < vf->num_tc; idx++) {
+				ret = i40e_alloc_vsi_res(vf, idx);
+				if (ret)
+					goto error_alloc;
+			}
+			/* send correct number of queues */
+			total_queue_pairs = I40E_MAX_VF_QUEUES;
+		} else {
+			dev_info(&pf->pdev->dev, "VF %d: Not enough queues to allocate, disabling ADq\n",
+				 vf->vf_id);
+			vf->adq_enabled = false;
+		}
+	}
+
 	/* We account for each VF to get a default number of queue pairs.  If
 	 * the VF has now requested more, we need to account for that to make
 	 * certain we never request more queues than we actually have left in
@@ -1536,6 +1680,27 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg)
 				      sizeof(struct virtchnl_version_info));
 }
 
+/**
+ * i40e_del_qch - delete all the additional VSIs created as a part of ADq
+ * @vf: pointer to VF structure
+ **/
+static void i40e_del_qch(struct i40e_vf *vf)
+{
+	struct i40e_pf *pf = vf->pf;
+	int i;
+
+	/* first element in the array belongs to primary VF VSI and we shouldn't
+	 * delete it. We should however delete the rest of the VSIs created
+	 */
+	for (i = 1; i < vf->num_tc; i++) {
+		if (vf->ch[i].vsi_idx) {
+			i40e_vsi_release(pf->vsi[vf->ch[i].vsi_idx]);
+			vf->ch[i].vsi_idx = 0;
+			vf->ch[i].vsi_id = 0;
+		}
+	}
+}
+
 /**
  * i40e_vc_get_vf_resources_msg
  * @vf: pointer to the VF info
@@ -1631,6 +1796,9 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
 	if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)
 		vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
 
+	if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADQ)
+		vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ADQ;
+
 	vfres->num_vsis = num_vsis;
 	vfres->num_queue_pairs = vf->num_queue_pairs;
 	vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
@@ -1855,27 +2023,37 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 	    (struct virtchnl_vsi_queue_config_info *)msg;
 	struct virtchnl_queue_pair_info *qpi;
 	struct i40e_pf *pf = vf->pf;
-	u16 vsi_id, vsi_queue_id;
+	u16 vsi_id, vsi_queue_id = 0;
 	i40e_status aq_ret = 0;
-	int i;
+	int i, j = 0, idx = 0;
+
+	vsi_id = qci->vsi_id;
 
 	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
 
-	vsi_id = qci->vsi_id;
 	if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
 		aq_ret = I40E_ERR_PARAM;
 		goto error_param;
 	}
+
 	for (i = 0; i < qci->num_queue_pairs; i++) {
 		qpi = &qci->qpair[i];
-		vsi_queue_id = qpi->txq.queue_id;
-		if ((qpi->txq.vsi_id != vsi_id) ||
-		    (qpi->rxq.vsi_id != vsi_id) ||
-		    (qpi->rxq.queue_id != vsi_queue_id) ||
-		    !i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {
+
+		if (!vf->adq_enabled) {
+			vsi_queue_id = qpi->txq.queue_id;
+
+			if (qpi->txq.vsi_id != qci->vsi_id ||
+			    qpi->rxq.vsi_id != qci->vsi_id ||
+			    qpi->rxq.queue_id != vsi_queue_id) {
+				aq_ret = I40E_ERR_PARAM;
+				goto error_param;
+			}
+		}
+
+		if (!i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {
 			aq_ret = I40E_ERR_PARAM;
 			goto error_param;
 		}
@@ -1887,9 +2065,33 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 			aq_ret = I40E_ERR_PARAM;
 			goto error_param;
 		}
+
+		/* For ADq there can be up to 4 VSIs with max 4 queues each.
+		 * VF does not know about these additional VSIs and all
+		 * it cares is about its own queues. PF configures these queues
+		 * to its appropriate VSIs based on TC mapping
+		 **/
+		if (vf->adq_enabled) {
+			if (j == (vf->ch[idx].num_qps - 1)) {
+				idx++;
+				j = 0; /* resetting the queue count */
+				vsi_queue_id = 0;
+			} else {
+				j++;
+				vsi_queue_id++;
+			}
+			vsi_id = vf->ch[idx].vsi_id;
+		}
 	}
 	/* set vsi num_queue_pairs in use to num configured by VF */
-	pf->vsi[vf->lan_vsi_idx]->num_queue_pairs = qci->num_queue_pairs;
+	if (!vf->adq_enabled) {
+		pf->vsi[vf->lan_vsi_idx]->num_queue_pairs =
+			qci->num_queue_pairs;
+	} else {
+		for (i = 0; i < vf->num_tc; i++)
+			pf->vsi[vf->ch[i].vsi_idx]->num_queue_pairs =
+			       vf->ch[i].num_qps;
+	}
 
 error_param:
 	/* send the response to the VF */
@@ -1897,6 +2099,33 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 				       aq_ret);
 }
 
+/**
+ * i40e_validate_queue_map
+ * @vsi_id: vsi id
+ * @queuemap: Tx or Rx queue map
+ *
+ * check if Tx or Rx queue map is valid
+ **/
+static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id,
+				   unsigned long queuemap)
+{
+	u16 vsi_queue_id, queue_id;
+
+	for_each_set_bit(vsi_queue_id, &queuemap, I40E_MAX_VSI_QP) {
+		if (vf->adq_enabled) {
+			vsi_id = vf->ch[vsi_queue_id / I40E_MAX_VF_VSI].vsi_id;
+			queue_id = (vsi_queue_id % I40E_DEFAULT_QUEUES_PER_VF);
+		} else {
+			queue_id = vsi_queue_id;
+		}
+
+		if (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * i40e_vc_config_irq_map_msg
  * @vf: pointer to the VF info
@@ -1911,9 +2140,8 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 	struct virtchnl_irq_map_info *irqmap_info =
 	    (struct virtchnl_irq_map_info *)msg;
 	struct virtchnl_vector_map *map;
-	u16 vsi_id, vsi_queue_id, vector_id;
+	u16 vsi_id, vector_id;
 	i40e_status aq_ret = 0;
-	unsigned long tempmap;
 	int i;
 
 	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
@@ -1923,7 +2151,6 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 
 	for (i = 0; i < irqmap_info->num_vectors; i++) {
 		map = &irqmap_info->vecmap[i];
-
 		vector_id = map->vector_id;
 		vsi_id = map->vsi_id;
 		/* validate msg params */
@@ -1933,23 +2160,14 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 			goto error_param;
 		}
 
-		/* lookout for the invalid queue index */
-		tempmap = map->rxq_map;
-		for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) {
-			if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
-						      vsi_queue_id)) {
-				aq_ret = I40E_ERR_PARAM;
-				goto error_param;
-			}
+		if (i40e_validate_queue_map(vf, vsi_id, map->rxq_map)) {
+			aq_ret = I40E_ERR_PARAM;
+			goto error_param;
 		}
 
-		tempmap = map->txq_map;
-		for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) {
-			if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
-						      vsi_queue_id)) {
-				aq_ret = I40E_ERR_PARAM;
-				goto error_param;
-			}
+		if (i40e_validate_queue_map(vf, vsi_id, map->txq_map)) {
+			aq_ret = I40E_ERR_PARAM;
+			goto error_param;
 		}
 
 		i40e_config_irq_link_list(vf, vsi_id, map);
@@ -1975,6 +2193,7 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 	struct i40e_pf *pf = vf->pf;
 	u16 vsi_id = vqs->vsi_id;
 	i40e_status aq_ret = 0;
+	int i;
 
 	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
 		aq_ret = I40E_ERR_PARAM;
@@ -1993,6 +2212,16 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 
 	if (i40e_vsi_start_rings(pf->vsi[vf->lan_vsi_idx]))
 		aq_ret = I40E_ERR_TIMEOUT;
+
+	/* need to start the rings for additional ADq VSI's as well */
+	if (vf->adq_enabled) {
+		/* zero belongs to LAN VSI */
+		for (i = 1; i < vf->num_tc; i++) {
+			if (i40e_vsi_start_rings(pf->vsi[vf->ch[i].vsi_idx]))
+				aq_ret = I40E_ERR_TIMEOUT;
+		}
+	}
+
 error_param:
 	/* send the response to the VF */
 	return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,
@@ -2687,6 +2916,618 @@ static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg,
 				       aq_ret);
 }
 
+/**
+ * i40e_validate_cloud_filter
+ * @mask: mask for TC filter
+ * @data: data for TC filter
+ *
+ * This function validates cloud filter programmed as TC filter for ADq
+ **/
+static int i40e_validate_cloud_filter(struct i40e_vf *vf,
+				      struct virtchnl_filter *tc_filter)
+{
+	struct virtchnl_l4_spec mask = tc_filter->mask.tcp_spec;
+	struct virtchnl_l4_spec data = tc_filter->data.tcp_spec;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi = NULL;
+	struct i40e_mac_filter *f;
+	struct hlist_node *h;
+	bool found = false;
+	int bkt;
+
+	if (!tc_filter->action) {
+		dev_info(&pf->pdev->dev,
+			 "VF %d: Currently ADq doesn't support Drop Action\n",
+			 vf->vf_id);
+		goto err;
+	}
+
+	/* action_meta is TC number here to which the filter is applied */
+	if (!tc_filter->action_meta ||
+	    tc_filter->action_meta > I40E_MAX_VF_VSI) {
+		dev_info(&pf->pdev->dev, "VF %d: Invalid TC number %u\n",
+			 vf->vf_id, tc_filter->action_meta);
+		goto err;
+	}
+
+	/* Check filter if it's programmed for advanced mode or basic mode.
+	 * There are two ADq modes (for VF only),
+	 * 1. Basic mode: intended to allow as many filter options as possible
+	 *		  to be added to a VF in Non-trusted mode. Main goal is
+	 *		  to add filters to its own MAC and VLAN id.
+	 * 2. Advanced mode: is for allowing filters to be applied other than
+	 *		  its own MAC or VLAN. This mode requires the VF to be
+	 *		  Trusted.
+	 */
+	if (mask.dst_mac[0] && !mask.dst_ip[0]) {
+		vsi = pf->vsi[vf->lan_vsi_idx];
+		f = i40e_find_mac(vsi, data.dst_mac);
+
+		if (!f) {
+			dev_info(&pf->pdev->dev,
+				 "Destination MAC %pM doesn't belong to VF %d\n",
+				 data.dst_mac, vf->vf_id);
+			goto err;
+		}
+
+		if (mask.vlan_id) {
+			hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f,
+					   hlist) {
+				if (f->vlan == ntohs(data.vlan_id)) {
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				dev_info(&pf->pdev->dev,
+					 "VF %d doesn't have any VLAN id %u\n",
+					 vf->vf_id, ntohs(data.vlan_id));
+				goto err;
+			}
+		}
+	} else {
+		/* Check if VF is trusted */
+		if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
+			dev_err(&pf->pdev->dev,
+				"VF %d not trusted, make VF trusted to add advanced mode ADq cloud filters\n",
+				vf->vf_id);
+			return I40E_ERR_CONFIG;
+		}
+	}
+
+	if (mask.dst_mac[0] & data.dst_mac[0]) {
+		if (is_broadcast_ether_addr(data.dst_mac) ||
+		    is_zero_ether_addr(data.dst_mac)) {
+			dev_info(&pf->pdev->dev, "VF %d: Invalid Dest MAC addr %pM\n",
+				 vf->vf_id, data.dst_mac);
+			goto err;
+		}
+	}
+
+	if (mask.src_mac[0] & data.src_mac[0]) {
+		if (is_broadcast_ether_addr(data.src_mac) ||
+		    is_zero_ether_addr(data.src_mac)) {
+			dev_info(&pf->pdev->dev, "VF %d: Invalid Source MAC addr %pM\n",
+				 vf->vf_id, data.src_mac);
+			goto err;
+		}
+	}
+
+	if (mask.dst_port & data.dst_port) {
+		if (!data.dst_port || be16_to_cpu(data.dst_port) > 0xFFFF) {
+			dev_info(&pf->pdev->dev, "VF %d: Invalid Dest port\n",
+				 vf->vf_id);
+			goto err;
+		}
+	}
+
+	if (mask.src_port & data.src_port) {
+		if (!data.src_port || be16_to_cpu(data.src_port) > 0xFFFF) {
+			dev_info(&pf->pdev->dev, "VF %d: Invalid Source port\n",
+				 vf->vf_id);
+			goto err;
+		}
+	}
+
+	if (tc_filter->flow_type != VIRTCHNL_TCP_V6_FLOW &&
+	    tc_filter->flow_type != VIRTCHNL_TCP_V4_FLOW) {
+		dev_info(&pf->pdev->dev, "VF %d: Invalid Flow type\n",
+			 vf->vf_id);
+		goto err;
+	}
+
+	if (mask.vlan_id & data.vlan_id) {
+		if (ntohs(data.vlan_id) > I40E_MAX_VLANID) {
+			dev_info(&pf->pdev->dev, "VF %d: invalid VLAN ID\n",
+				 vf->vf_id);
+			goto err;
+		}
+	}
+
+	return I40E_SUCCESS;
+err:
+	return I40E_ERR_CONFIG;
+}
+
+/**
+ * i40e_find_vsi_from_seid - searches for the vsi with the given seid
+ * @vf: pointer to the VF info
+ * @seid - seid of the vsi it is searching for
+ **/
+static struct i40e_vsi *i40e_find_vsi_from_seid(struct i40e_vf *vf, u16 seid)
+{
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi = NULL;
+	int i;
+
+	for (i = 0; i < vf->num_tc ; i++) {
+		vsi = i40e_find_vsi_from_id(pf, vf->ch[i].vsi_id);
+		if (vsi->seid == seid)
+			return vsi;
+	}
+	return NULL;
+}
+
+/**
+ * i40e_del_all_cloud_filters
+ * @vf: pointer to the VF info
+ *
+ * This function deletes all cloud filters
+ **/
+static void i40e_del_all_cloud_filters(struct i40e_vf *vf)
+{
+	struct i40e_cloud_filter *cfilter = NULL;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi = NULL;
+	struct hlist_node *node;
+	int ret;
+
+	hlist_for_each_entry_safe(cfilter, node,
+				  &vf->cloud_filter_list, cloud_node) {
+		vsi = i40e_find_vsi_from_seid(vf, cfilter->seid);
+
+		if (!vsi) {
+			dev_err(&pf->pdev->dev, "VF %d: no VSI found for matching %u seid, can't delete cloud filter\n",
+				vf->vf_id, cfilter->seid);
+			continue;
+		}
+
+		if (cfilter->dst_port)
+			ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,
+								false);
+		else
+			ret = i40e_add_del_cloud_filter(vsi, cfilter, false);
+		if (ret)
+			dev_err(&pf->pdev->dev,
+				"VF %d: Failed to delete cloud filter, err %s aq_err %s\n",
+				vf->vf_id, i40e_stat_str(&pf->hw, ret),
+				i40e_aq_str(&pf->hw,
+					    pf->hw.aq.asq_last_status));
+
+		hlist_del(&cfilter->cloud_node);
+		kfree(cfilter);
+		vf->num_cloud_filters--;
+	}
+}
+
+/**
+ * i40e_vc_del_cloud_filter
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * This function deletes a cloud filter programmed as TC filter for ADq
+ **/
+static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
+{
+	struct virtchnl_filter *vcf = (struct virtchnl_filter *)msg;
+	struct virtchnl_l4_spec mask = vcf->mask.tcp_spec;
+	struct virtchnl_l4_spec tcf = vcf->data.tcp_spec;
+	struct i40e_cloud_filter cfilter, *cf = NULL;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi = NULL;
+	struct hlist_node *node;
+	i40e_status aq_ret = 0;
+	int i, ret;
+
+	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	if (!vf->adq_enabled) {
+		dev_info(&pf->pdev->dev,
+			 "VF %d: ADq not enabled, can't apply cloud filter\n",
+			 vf->vf_id);
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	if (i40e_validate_cloud_filter(vf, vcf)) {
+		dev_info(&pf->pdev->dev,
+			 "VF %d: Invalid input, can't apply cloud filter\n",
+			 vf->vf_id);
+			aq_ret = I40E_ERR_PARAM;
+			goto err;
+	}
+
+	memset(&cfilter, 0, sizeof(cfilter));
+	/* parse destination mac address */
+	for (i = 0; i < ETH_ALEN; i++)
+		cfilter.dst_mac[i] = mask.dst_mac[i] & tcf.dst_mac[i];
+
+	/* parse source mac address */
+	for (i = 0; i < ETH_ALEN; i++)
+		cfilter.src_mac[i] = mask.src_mac[i] & tcf.src_mac[i];
+
+	cfilter.vlan_id = mask.vlan_id & tcf.vlan_id;
+	cfilter.dst_port = mask.dst_port & tcf.dst_port;
+	cfilter.src_port = mask.src_port & tcf.src_port;
+
+	switch (vcf->flow_type) {
+	case VIRTCHNL_TCP_V4_FLOW:
+		cfilter.n_proto = ETH_P_IP;
+		if (mask.dst_ip[0] & tcf.dst_ip[0])
+			memcpy(&cfilter.ip.v4.dst_ip, tcf.dst_ip,
+			       ARRAY_SIZE(tcf.dst_ip));
+		else if (mask.src_ip[0] & tcf.dst_ip[0])
+			memcpy(&cfilter.ip.v4.src_ip, tcf.src_ip,
+			       ARRAY_SIZE(tcf.dst_ip));
+		break;
+	case VIRTCHNL_TCP_V6_FLOW:
+		cfilter.n_proto = ETH_P_IPV6;
+		if (mask.dst_ip[3] & tcf.dst_ip[3])
+			memcpy(&cfilter.ip.v6.dst_ip6, tcf.dst_ip,
+			       sizeof(cfilter.ip.v6.dst_ip6));
+		if (mask.src_ip[3] & tcf.src_ip[3])
+			memcpy(&cfilter.ip.v6.src_ip6, tcf.src_ip,
+			       sizeof(cfilter.ip.v6.src_ip6));
+		break;
+	default:
+		/* TC filter can be configured based on different combinations
+		 * and in this case IP is not a part of filter config
+		 */
+		dev_info(&pf->pdev->dev, "VF %d: Flow type not configured\n",
+			 vf->vf_id);
+	}
+
+	/* get the vsi to which the tc belongs to */
+	vsi = pf->vsi[vf->ch[vcf->action_meta].vsi_idx];
+	cfilter.seid = vsi->seid;
+	cfilter.flags = vcf->field_flags;
+
+	/* Deleting TC filter */
+	if (tcf.dst_port)
+		ret = i40e_add_del_cloud_filter_big_buf(vsi, &cfilter, false);
+	else
+		ret = i40e_add_del_cloud_filter(vsi, &cfilter, false);
+	if (ret) {
+		dev_err(&pf->pdev->dev,
+			"VF %d: Failed to delete cloud filter, err %s aq_err %s\n",
+			vf->vf_id, i40e_stat_str(&pf->hw, ret),
+			i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+		goto err;
+	}
+
+	hlist_for_each_entry_safe(cf, node,
+				  &vf->cloud_filter_list, cloud_node) {
+		if (cf->seid != cfilter.seid)
+			continue;
+		if (mask.dst_port)
+			if (cfilter.dst_port != cf->dst_port)
+				continue;
+		if (mask.dst_mac[0])
+			if (!ether_addr_equal(cf->src_mac, cfilter.src_mac))
+				continue;
+		/* for ipv4 data to be valid, only first byte of mask is set */
+		if (cfilter.n_proto == ETH_P_IP && mask.dst_ip[0])
+			if (memcmp(&cfilter.ip.v4.dst_ip, &cf->ip.v4.dst_ip,
+				   ARRAY_SIZE(tcf.dst_ip)))
+				continue;
+		/* for ipv6, mask is set for all sixteen bytes (4 words) */
+		if (cfilter.n_proto == ETH_P_IPV6 && mask.dst_ip[3])
+			if (memcmp(&cfilter.ip.v6.dst_ip6, &cf->ip.v6.dst_ip6,
+				   sizeof(cfilter.ip.v6.src_ip6)))
+				continue;
+		if (mask.vlan_id)
+			if (cfilter.vlan_id != cf->vlan_id)
+				continue;
+
+		hlist_del(&cf->cloud_node);
+		kfree(cf);
+		vf->num_cloud_filters--;
+	}
+
+err:
+	return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_CLOUD_FILTER,
+				       aq_ret);
+}
+
+/**
+ * i40e_vc_add_cloud_filter
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * This function adds a cloud filter programmed as TC filter for ADq
+ **/
+static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
+{
+	struct virtchnl_filter *vcf = (struct virtchnl_filter *)msg;
+	struct virtchnl_l4_spec mask = vcf->mask.tcp_spec;
+	struct virtchnl_l4_spec tcf = vcf->data.tcp_spec;
+	struct i40e_cloud_filter *cfilter = NULL;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_vsi *vsi = NULL;
+	i40e_status aq_ret = 0;
+	int i, ret;
+
+	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	if (!vf->adq_enabled) {
+		dev_info(&pf->pdev->dev,
+			 "VF %d: ADq is not enabled, can't apply cloud filter\n",
+			 vf->vf_id);
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	if (i40e_validate_cloud_filter(vf, vcf)) {
+		dev_info(&pf->pdev->dev,
+			 "VF %d: Invalid input/s, can't apply cloud filter\n",
+			 vf->vf_id);
+			aq_ret = I40E_ERR_PARAM;
+			goto err;
+	}
+
+	cfilter = kzalloc(sizeof(*cfilter), GFP_KERNEL);
+	if (!cfilter)
+		return -ENOMEM;
+
+	/* parse destination mac address */
+	for (i = 0; i < ETH_ALEN; i++)
+		cfilter->dst_mac[i] = mask.dst_mac[i] & tcf.dst_mac[i];
+
+	/* parse source mac address */
+	for (i = 0; i < ETH_ALEN; i++)
+		cfilter->src_mac[i] = mask.src_mac[i] & tcf.src_mac[i];
+
+	cfilter->vlan_id = mask.vlan_id & tcf.vlan_id;
+	cfilter->dst_port = mask.dst_port & tcf.dst_port;
+	cfilter->src_port = mask.src_port & tcf.src_port;
+
+	switch (vcf->flow_type) {
+	case VIRTCHNL_TCP_V4_FLOW:
+		cfilter->n_proto = ETH_P_IP;
+		if (mask.dst_ip[0] & tcf.dst_ip[0])
+			memcpy(&cfilter->ip.v4.dst_ip, tcf.dst_ip,
+			       ARRAY_SIZE(tcf.dst_ip));
+		else if (mask.src_ip[0] & tcf.dst_ip[0])
+			memcpy(&cfilter->ip.v4.src_ip, tcf.src_ip,
+			       ARRAY_SIZE(tcf.dst_ip));
+		break;
+	case VIRTCHNL_TCP_V6_FLOW:
+		cfilter->n_proto = ETH_P_IPV6;
+		if (mask.dst_ip[3] & tcf.dst_ip[3])
+			memcpy(&cfilter->ip.v6.dst_ip6, tcf.dst_ip,
+			       sizeof(cfilter->ip.v6.dst_ip6));
+		if (mask.src_ip[3] & tcf.src_ip[3])
+			memcpy(&cfilter->ip.v6.src_ip6, tcf.src_ip,
+			       sizeof(cfilter->ip.v6.src_ip6));
+		break;
+	default:
+		/* TC filter can be configured based on different combinations
+		 * and in this case IP is not a part of filter config
+		 */
+		dev_info(&pf->pdev->dev, "VF %d: Flow type not configured\n",
+			 vf->vf_id);
+	}
+
+	/* get the VSI to which the TC belongs to */
+	vsi = pf->vsi[vf->ch[vcf->action_meta].vsi_idx];
+	cfilter->seid = vsi->seid;
+	cfilter->flags = vcf->field_flags;
+
+	/* Adding cloud filter programmed as TC filter */
+	if (tcf.dst_port)
+		ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter, true);
+	else
+		ret = i40e_add_del_cloud_filter(vsi, cfilter, true);
+	if (ret) {
+		dev_err(&pf->pdev->dev,
+			"VF %d: Failed to add cloud filter, err %s aq_err %s\n",
+			vf->vf_id, i40e_stat_str(&pf->hw, ret),
+			i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+		goto err;
+	}
+
+	INIT_HLIST_NODE(&cfilter->cloud_node);
+	hlist_add_head(&cfilter->cloud_node, &vf->cloud_filter_list);
+	vf->num_cloud_filters++;
+err:
+	return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_CLOUD_FILTER,
+				       aq_ret);
+}
+
+/**
+ * i40e_vc_add_qch_msg: Add queue channel and enable ADq
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ **/
+static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
+{
+	struct virtchnl_tc_info *tci =
+		(struct virtchnl_tc_info *)msg;
+	struct i40e_pf *pf = vf->pf;
+	struct i40e_link_status *ls = &pf->hw.phy.link_info;
+	int i, adq_request_qps = 0, speed = 0;
+	i40e_status aq_ret = 0;
+
+	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	/* ADq cannot be applied if spoof check is ON */
+	if (vf->spoofchk) {
+		dev_err(&pf->pdev->dev,
+			"Spoof check is ON, turn it OFF to enable ADq\n");
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADQ)) {
+		dev_err(&pf->pdev->dev,
+			"VF %d attempting to enable ADq, but hasn't properly negotiated that capability\n",
+			vf->vf_id);
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	/* max number of traffic classes for VF currently capped at 4 */
+	if (!tci->num_tc || tci->num_tc > I40E_MAX_VF_VSI) {
+		dev_err(&pf->pdev->dev,
+			"VF %d trying to set %u TCs, valid range 1-4 TCs per VF\n",
+			vf->vf_id, tci->num_tc);
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	/* validate queues for each TC */
+	for (i = 0; i < tci->num_tc; i++)
+		if (!tci->list[i].count ||
+		    tci->list[i].count > I40E_DEFAULT_QUEUES_PER_VF) {
+			dev_err(&pf->pdev->dev,
+				"VF %d: TC %d trying to set %u queues, valid range 1-4 queues per TC\n",
+				vf->vf_id, i, tci->list[i].count);
+			aq_ret = I40E_ERR_PARAM;
+			goto err;
+		}
+
+	/* need Max VF queues but already have default number of queues */
+	adq_request_qps = I40E_MAX_VF_QUEUES - I40E_DEFAULT_QUEUES_PER_VF;
+
+	if (pf->queues_left < adq_request_qps) {
+		dev_err(&pf->pdev->dev,
+			"No queues left to allocate to VF %d\n",
+			vf->vf_id);
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	} else {
+		/* we need to allocate max VF queues to enable ADq so as to
+		 * make sure ADq enabled VF always gets back queues when it
+		 * goes through a reset.
+		 */
+		vf->num_queue_pairs = I40E_MAX_VF_QUEUES;
+	}
+
+	/* get link speed in MB to validate rate limit */
+	switch (ls->link_speed) {
+	case VIRTCHNL_LINK_SPEED_100MB:
+		speed = SPEED_100;
+		break;
+	case VIRTCHNL_LINK_SPEED_1GB:
+		speed = SPEED_1000;
+		break;
+	case VIRTCHNL_LINK_SPEED_10GB:
+		speed = SPEED_10000;
+		break;
+	case VIRTCHNL_LINK_SPEED_20GB:
+		speed = SPEED_20000;
+		break;
+	case VIRTCHNL_LINK_SPEED_25GB:
+		speed = SPEED_25000;
+		break;
+	case VIRTCHNL_LINK_SPEED_40GB:
+		speed = SPEED_40000;
+		break;
+	default:
+		dev_err(&pf->pdev->dev,
+			"Cannot detect link speed\n");
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	/* parse data from the queue channel info */
+	vf->num_tc = tci->num_tc;
+	for (i = 0; i < vf->num_tc; i++) {
+		if (tci->list[i].max_tx_rate) {
+			if (tci->list[i].max_tx_rate > speed) {
+				dev_err(&pf->pdev->dev,
+					"Invalid max tx rate %llu specified for VF %d.",
+					tci->list[i].max_tx_rate,
+					vf->vf_id);
+				aq_ret = I40E_ERR_PARAM;
+				goto err;
+			} else {
+				vf->ch[i].max_tx_rate =
+					tci->list[i].max_tx_rate;
+			}
+		}
+		vf->ch[i].num_qps = tci->list[i].count;
+	}
+
+	/* set this flag only after making sure all inputs are sane */
+	vf->adq_enabled = true;
+	/* num_req_queues is set when user changes number of queues via ethtool
+	 * and this causes issue for default VSI(which depends on this variable)
+	 * when ADq is enabled, hence reset it.
+	 */
+	vf->num_req_queues = 0;
+
+	/* reset the VF in order to allocate resources */
+	i40e_vc_notify_vf_reset(vf);
+	i40e_reset_vf(vf, false);
+
+	return I40E_SUCCESS;
+
+	/* send the response to the VF */
+err:
+	return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_CHANNELS,
+				       aq_ret);
+}
+
+/**
+ * i40e_vc_del_qch_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ **/
+static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
+{
+	struct i40e_pf *pf = vf->pf;
+	i40e_status aq_ret = 0;
+
+	if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+		aq_ret = I40E_ERR_PARAM;
+		goto err;
+	}
+
+	if (vf->adq_enabled) {
+		i40e_del_all_cloud_filters(vf);
+		i40e_del_qch(vf);
+		vf->adq_enabled = false;
+		vf->num_tc = 0;
+		dev_info(&pf->pdev->dev,
+			 "Deleting Queue Channels and cloud filters for ADq on VF %d\n",
+			 vf->vf_id);
+	} else {
+		dev_info(&pf->pdev->dev, "VF %d trying to delete queue channels but ADq isn't enabled\n",
+			 vf->vf_id);
+		aq_ret = I40E_ERR_PARAM;
+	}
+
+	/* reset the VF in order to allocate resources */
+	i40e_vc_notify_vf_reset(vf);
+	i40e_reset_vf(vf, false);
+
+	return I40E_SUCCESS;
+
+err:
+	return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_CHANNELS,
+				       aq_ret);
+}
+
 /**
  * i40e_vc_process_vf_msg
  * @pf: pointer to the PF structure
@@ -2816,7 +3657,18 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
 	case VIRTCHNL_OP_REQUEST_QUEUES:
 		ret = i40e_vc_request_queues_msg(vf, msg, msglen);
 		break;
-
+	case VIRTCHNL_OP_ENABLE_CHANNELS:
+		ret = i40e_vc_add_qch_msg(vf, msg);
+		break;
+	case VIRTCHNL_OP_DISABLE_CHANNELS:
+		ret = i40e_vc_del_qch_msg(vf, msg);
+		break;
+	case VIRTCHNL_OP_ADD_CLOUD_FILTER:
+		ret = i40e_vc_add_cloud_filter(vf, msg);
+		break;
+	case VIRTCHNL_OP_DEL_CLOUD_FILTER:
+		ret = i40e_vc_del_cloud_filter(vf, msg);
+		break;
 	case VIRTCHNL_OP_UNKNOWN:
 	default:
 		dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n",
@@ -3382,6 +4234,16 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
 	i40e_vc_disable_vf(vf);
 	dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
 		 vf_id, setting ? "" : "un");
+
+	if (vf->adq_enabled) {
+		if (!vf->trusted) {
+			dev_info(&pf->pdev->dev,
+				 "VF %u no longer Trusted, deleting all cloud filters\n",
+				 vf_id);
+			i40e_del_all_cloud_filters(vf);
+		}
+	}
+
 out:
 	return ret;
 }
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 5efc4f92bb37..6852599b2379 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -69,6 +69,19 @@ enum i40e_vf_capabilities {
 	I40E_VIRTCHNL_VF_CAP_IWARP,
 };
 
+/* In ADq, max 4 VSI's can be allocated per VF including primary VF VSI.
+ * These variables are used to store indices, id's and number of queues
+ * for each VSI including that of primary VF VSI. Each Traffic class is
+ * termed as channel and each channel can in-turn have 4 queues which
+ * means max 16 queues overall per VF.
+ */
+struct i40evf_channel {
+	u16 vsi_idx; /* index in PF struct for all channel VSIs */
+	u16 vsi_id; /* VSI ID used by firmware */
+	u16 num_qps; /* number of queue pairs requested by user */
+	u64 max_tx_rate; /* bandwidth rate allocation for VSIs */
+};
+
 /* VF information structure */
 struct i40e_vf {
 	struct i40e_pf *pf;
@@ -111,6 +124,13 @@ struct i40e_vf {
 	u16 num_mac;
 	u16 num_vlan;
 
+	/* ADq related variables */
+	bool adq_enabled; /* flag to enable adq */
+	u8 num_tc;
+	struct i40evf_channel ch[I40E_MAX_VF_VSI];
+	struct hlist_head cloud_filter_list;
+	u16 num_cloud_filters;
+
 	/* RDMA Client */
 	struct virtchnl_iwarp_qvlist_info *qvlist_info;
 };
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index 357d6051281f..eb8f3e327f6b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -392,99 +392,241 @@ void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
 	     val);
 }
 
+static inline bool i40e_container_is_rx(struct i40e_q_vector *q_vector,
+					struct i40e_ring_container *rc)
+{
+	return &q_vector->rx == rc;
+}
+
+static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector)
+{
+	unsigned int divisor;
+
+	switch (q_vector->adapter->link_speed) {
+	case I40E_LINK_SPEED_40GB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 1024;
+		break;
+	case I40E_LINK_SPEED_25GB:
+	case I40E_LINK_SPEED_20GB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 512;
+		break;
+	default:
+	case I40E_LINK_SPEED_10GB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 256;
+		break;
+	case I40E_LINK_SPEED_1GB:
+	case I40E_LINK_SPEED_100MB:
+		divisor = I40E_ITR_ADAPTIVE_MIN_INC * 32;
+		break;
+	}
+
+	return divisor;
+}
+
 /**
- * i40e_set_new_dynamic_itr - Find new ITR level
+ * i40e_update_itr - update the dynamic ITR value based on statistics
+ * @q_vector: structure containing interrupt and ring information
  * @rc: structure containing ring performance data
  *
- * Returns true if ITR changed, false if not
- *
- * Stores a new ITR value based on packets and byte counts during
- * the last interrupt.  The advantage of per interrupt computation
- * is faster updates and more accurate ITR for the current traffic
- * pattern.  Constants in this function were computed based on
- * theoretical maximum wire speed and thresholds were set based on
- * testing data as well as attempting to minimize response time
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt.  The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern.  Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
  * while increasing bulk throughput.
  **/
-static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
+static void i40e_update_itr(struct i40e_q_vector *q_vector,
+			    struct i40e_ring_container *rc)
 {
-	enum i40e_latency_range new_latency_range = rc->latency_range;
-	u32 new_itr = rc->itr;
-	int bytes_per_usec;
-	unsigned int usecs, estimated_usecs;
+	unsigned int avg_wire_size, packets, bytes, itr;
+	unsigned long next_update = jiffies;
 
-	if (rc->total_packets == 0 || !rc->itr)
-		return false;
+	/* If we don't have any rings just leave ourselves set for maximum
+	 * possible latency so we take ourselves out of the equation.
+	 */
+	if (!rc->ring || !ITR_IS_DYNAMIC(rc->ring->itr_setting))
+		return;
+
+	/* For Rx we want to push the delay up and default to low latency.
+	 * for Tx we want to pull the delay down and default to high latency.
+	 */
+	itr = i40e_container_is_rx(q_vector, rc) ?
+	      I40E_ITR_ADAPTIVE_MIN_USECS | I40E_ITR_ADAPTIVE_LATENCY :
+	      I40E_ITR_ADAPTIVE_MAX_USECS | I40E_ITR_ADAPTIVE_LATENCY;
+
+	/* If we didn't update within up to 1 - 2 jiffies we can assume
+	 * that either packets are coming in so slow there hasn't been
+	 * any work, or that there is so much work that NAPI is dealing
+	 * with interrupt moderation and we don't need to do anything.
+	 */
+	if (time_after(next_update, rc->next_update))
+		goto clear_counts;
+
+	/* If itr_countdown is set it means we programmed an ITR within
+	 * the last 4 interrupt cycles. This has a side effect of us
+	 * potentially firing an early interrupt. In order to work around
+	 * this we need to throw out any data received for a few
+	 * interrupts following the update.
+	 */
+	if (q_vector->itr_countdown) {
+		itr = rc->target_itr;
+		goto clear_counts;
+	}
+
+	packets = rc->total_packets;
+	bytes = rc->total_bytes;
 
-	usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
-	bytes_per_usec = rc->total_bytes / usecs;
+	if (i40e_container_is_rx(q_vector, rc)) {
+		/* If Rx there are 1 to 4 packets and bytes are less than
+		 * 9000 assume insufficient data to use bulk rate limiting
+		 * approach unless Tx is already in bulk rate limiting. We
+		 * are likely latency driven.
+		 */
+		if (packets && packets < 4 && bytes < 9000 &&
+		    (q_vector->tx.target_itr & I40E_ITR_ADAPTIVE_LATENCY)) {
+			itr = I40E_ITR_ADAPTIVE_LATENCY;
+			goto adjust_by_size;
+		}
+	} else if (packets < 4) {
+		/* If we have Tx and Rx ITR maxed and Tx ITR is running in
+		 * bulk mode and we are receiving 4 or fewer packets just
+		 * reset the ITR_ADAPTIVE_LATENCY bit for latency mode so
+		 * that the Rx can relax.
+		 */
+		if (rc->target_itr == I40E_ITR_ADAPTIVE_MAX_USECS &&
+		    (q_vector->rx.target_itr & I40E_ITR_MASK) ==
+		     I40E_ITR_ADAPTIVE_MAX_USECS)
+			goto clear_counts;
+	} else if (packets > 32) {
+		/* If we have processed over 32 packets in a single interrupt
+		 * for Tx assume we need to switch over to "bulk" mode.
+		 */
+		rc->target_itr &= ~I40E_ITR_ADAPTIVE_LATENCY;
+	}
 
-	/* The calculations in this algorithm depend on interrupts actually
-	 * firing at the ITR rate. This may not happen if the packet rate is
-	 * really low, or if we've been napi polling. Check to make sure
-	 * that's not the case before we continue.
+	/* We have no packets to actually measure against. This means
+	 * either one of the other queues on this vector is active or
+	 * we are a Tx queue doing TSO with too high of an interrupt rate.
+	 *
+	 * Between 4 and 56 we can assume that our current interrupt delay
+	 * is only slightly too low. As such we should increase it by a small
+	 * fixed amount.
 	 */
-	estimated_usecs = jiffies_to_usecs(jiffies - rc->last_itr_update);
-	if (estimated_usecs > usecs) {
-		new_latency_range = I40E_LOW_LATENCY;
-		goto reset_latency;
+	if (packets < 56) {
+		itr = rc->target_itr + I40E_ITR_ADAPTIVE_MIN_INC;
+		if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) {
+			itr &= I40E_ITR_ADAPTIVE_LATENCY;
+			itr += I40E_ITR_ADAPTIVE_MAX_USECS;
+		}
+		goto clear_counts;
+	}
+
+	if (packets <= 256) {
+		itr = min(q_vector->tx.current_itr, q_vector->rx.current_itr);
+		itr &= I40E_ITR_MASK;
+
+		/* Between 56 and 112 is our "goldilocks" zone where we are
+		 * working out "just right". Just report that our current
+		 * ITR is good for us.
+		 */
+		if (packets <= 112)
+			goto clear_counts;
+
+		/* If packet count is 128 or greater we are likely looking
+		 * at a slight overrun of the delay we want. Try halving
+		 * our delay to see if that will cut the number of packets
+		 * in half per interrupt.
+		 */
+		itr /= 2;
+		itr &= I40E_ITR_MASK;
+		if (itr < I40E_ITR_ADAPTIVE_MIN_USECS)
+			itr = I40E_ITR_ADAPTIVE_MIN_USECS;
+
+		goto clear_counts;
 	}
 
-	/* simple throttlerate management
-	 *   0-10MB/s   lowest (50000 ints/s)
-	 *  10-20MB/s   low    (20000 ints/s)
-	 *  20-1249MB/s bulk   (18000 ints/s)
+	/* The paths below assume we are dealing with a bulk ITR since
+	 * number of packets is greater than 256. We are just going to have
+	 * to compute a value and try to bring the count under control,
+	 * though for smaller packet sizes there isn't much we can do as
+	 * NAPI polling will likely be kicking in sooner rather than later.
+	 */
+	itr = I40E_ITR_ADAPTIVE_BULK;
+
+adjust_by_size:
+	/* If packet counts are 256 or greater we can assume we have a gross
+	 * overestimation of what the rate should be. Instead of trying to fine
+	 * tune it just use the formula below to try and dial in an exact value
+	 * give the current packet size of the frame.
+	 */
+	avg_wire_size = bytes / packets;
+
+	/* The following is a crude approximation of:
+	 *  wmem_default / (size + overhead) = desired_pkts_per_int
+	 *  rate / bits_per_byte / (size + ethernet overhead) = pkt_rate
+	 *  (desired_pkt_rate / pkt_rate) * usecs_per_sec = ITR value
 	 *
-	 * The math works out because the divisor is in 10^(-6) which
-	 * turns the bytes/us input value into MB/s values, but
-	 * make sure to use usecs, as the register values written
-	 * are in 2 usec increments in the ITR registers, and make sure
-	 * to use the smoothed values that the countdown timer gives us.
+	 * Assuming wmem_default is 212992 and overhead is 640 bytes per
+	 * packet, (256 skb, 64 headroom, 320 shared info), we can reduce the
+	 * formula down to
+	 *
+	 *  (170 * (size + 24)) / (size + 640) = ITR
+	 *
+	 * We first do some math on the packet size and then finally bitshift
+	 * by 8 after rounding up. We also have to account for PCIe link speed
+	 * difference as ITR scales based on this.
 	 */
-	switch (new_latency_range) {
-	case I40E_LOWEST_LATENCY:
-		if (bytes_per_usec > 10)
-			new_latency_range = I40E_LOW_LATENCY;
-		break;
-	case I40E_LOW_LATENCY:
-		if (bytes_per_usec > 20)
-			new_latency_range = I40E_BULK_LATENCY;
-		else if (bytes_per_usec <= 10)
-			new_latency_range = I40E_LOWEST_LATENCY;
-		break;
-	case I40E_BULK_LATENCY:
-	default:
-		if (bytes_per_usec <= 20)
-			new_latency_range = I40E_LOW_LATENCY;
-		break;
+	if (avg_wire_size <= 60) {
+		/* Start at 250k ints/sec */
+		avg_wire_size = 4096;
+	} else if (avg_wire_size <= 380) {
+		/* 250K ints/sec to 60K ints/sec */
+		avg_wire_size *= 40;
+		avg_wire_size += 1696;
+	} else if (avg_wire_size <= 1084) {
+		/* 60K ints/sec to 36K ints/sec */
+		avg_wire_size *= 15;
+		avg_wire_size += 11452;
+	} else if (avg_wire_size <= 1980) {
+		/* 36K ints/sec to 30K ints/sec */
+		avg_wire_size *= 5;
+		avg_wire_size += 22420;
+	} else {
+		/* plateau at a limit of 30K ints/sec */
+		avg_wire_size = 32256;
 	}
 
-reset_latency:
-	rc->latency_range = new_latency_range;
+	/* If we are in low latency mode halve our delay which doubles the
+	 * rate to somewhere between 100K to 16K ints/sec
+	 */
+	if (itr & I40E_ITR_ADAPTIVE_LATENCY)
+		avg_wire_size /= 2;
 
-	switch (new_latency_range) {
-	case I40E_LOWEST_LATENCY:
-		new_itr = I40E_ITR_50K;
-		break;
-	case I40E_LOW_LATENCY:
-		new_itr = I40E_ITR_20K;
-		break;
-	case I40E_BULK_LATENCY:
-		new_itr = I40E_ITR_18K;
-		break;
-	default:
-		break;
+	/* Resultant value is 256 times larger than it needs to be. This
+	 * gives us room to adjust the value as needed to either increase
+	 * or decrease the value based on link speeds of 10G, 2.5G, 1G, etc.
+	 *
+	 * Use addition as we have already recorded the new latency flag
+	 * for the ITR value.
+	 */
+	itr += DIV_ROUND_UP(avg_wire_size, i40e_itr_divisor(q_vector)) *
+	       I40E_ITR_ADAPTIVE_MIN_INC;
+
+	if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) {
+		itr &= I40E_ITR_ADAPTIVE_LATENCY;
+		itr += I40E_ITR_ADAPTIVE_MAX_USECS;
 	}
 
+clear_counts:
+	/* write back value */
+	rc->target_itr = itr;
+
+	/* next update should occur within next jiffy */
+	rc->next_update = next_update + 1;
+
 	rc->total_bytes = 0;
 	rc->total_packets = 0;
-	rc->last_itr_update = jiffies;
-
-	if (new_itr != rc->itr) {
-		rc->itr = new_itr;
-		return true;
-	}
-	return false;
 }
 
 /**
@@ -1273,7 +1415,7 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
  * @rx_buffer: rx buffer to pull data from
  *
  * This function will clean up the contents of the rx_buffer.  It will
- * either recycle the bufer or unmap it and free the associated resources.
+ * either recycle the buffer or unmap it and free the associated resources.
  */
 static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
 			       struct i40e_rx_buffer *rx_buffer)
@@ -1457,33 +1599,45 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 	return failure ? budget : (int)total_rx_packets;
 }
 
-static u32 i40e_buildreg_itr(const int type, const u16 itr)
+static inline u32 i40e_buildreg_itr(const int type, u16 itr)
 {
 	u32 val;
 
+	/* We don't bother with setting the CLEARPBA bit as the data sheet
+	 * points out doing so is "meaningless since it was already
+	 * auto-cleared". The auto-clearing happens when the interrupt is
+	 * asserted.
+	 *
+	 * Hardware errata 28 for also indicates that writing to a
+	 * xxINT_DYN_CTLx CSR with INTENA_MSK (bit 31) set to 0 will clear
+	 * an event in the PBA anyway so we need to rely on the automask
+	 * to hold pending events for us until the interrupt is re-enabled
+	 *
+	 * The itr value is reported in microseconds, and the register
+	 * value is recorded in 2 microsecond units. For this reason we
+	 * only need to shift by the interval shift - 1 instead of the
+	 * full value.
+	 */
+	itr &= I40E_ITR_MASK;
+
 	val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
-	      I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
 	      (type << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
-	      (itr << I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT);
+	      (itr << (I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT - 1));
 
 	return val;
 }
 
 /* a small macro to shorten up some long lines */
 #define INTREG I40E_VFINT_DYN_CTLN1
-static inline int get_rx_itr(struct i40e_vsi *vsi, int idx)
-{
-	struct i40evf_adapter *adapter = vsi->back;
 
-	return adapter->rx_rings[idx].rx_itr_setting;
-}
-
-static inline int get_tx_itr(struct i40e_vsi *vsi, int idx)
-{
-	struct i40evf_adapter *adapter = vsi->back;
-
-	return adapter->tx_rings[idx].tx_itr_setting;
-}
+/* The act of updating the ITR will cause it to immediately trigger. In order
+ * to prevent this from throwing off adaptive update statistics we defer the
+ * update so that it can only happen so often. So after either Tx or Rx are
+ * updated we make the adaptive scheme wait until either the ITR completely
+ * expires via the next_update expiration or we have been through at least
+ * 3 interrupts.
+ */
+#define ITR_COUNTDOWN_START 3
 
 /**
  * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt
@@ -1495,70 +1649,51 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
 					  struct i40e_q_vector *q_vector)
 {
 	struct i40e_hw *hw = &vsi->back->hw;
-	bool rx = false, tx = false;
-	u32 rxval, txval;
-	int idx = q_vector->v_idx;
-	int rx_itr_setting, tx_itr_setting;
-
-	/* avoid dynamic calculation if in countdown mode OR if
-	 * all dynamic is disabled
-	 */
-	rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
-
-	rx_itr_setting = get_rx_itr(vsi, idx);
-	tx_itr_setting = get_tx_itr(vsi, idx);
+	u32 intval;
 
-	if (q_vector->itr_countdown > 0 ||
-	    (!ITR_IS_DYNAMIC(rx_itr_setting) &&
-	     !ITR_IS_DYNAMIC(tx_itr_setting))) {
-		goto enable_int;
-	}
-
-	if (ITR_IS_DYNAMIC(rx_itr_setting)) {
-		rx = i40e_set_new_dynamic_itr(&q_vector->rx);
-		rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
-	}
+	/* These will do nothing if dynamic updates are not enabled */
+	i40e_update_itr(q_vector, &q_vector->tx);
+	i40e_update_itr(q_vector, &q_vector->rx);
 
-	if (ITR_IS_DYNAMIC(tx_itr_setting)) {
-		tx = i40e_set_new_dynamic_itr(&q_vector->tx);
-		txval = i40e_buildreg_itr(I40E_TX_ITR, q_vector->tx.itr);
-	}
-
-	if (rx || tx) {
-		/* get the higher of the two ITR adjustments and
-		 * use the same value for both ITR registers
-		 * when in adaptive mode (Rx and/or Tx)
-		 */
-		u16 itr = max(q_vector->tx.itr, q_vector->rx.itr);
-
-		q_vector->tx.itr = q_vector->rx.itr = itr;
-		txval = i40e_buildreg_itr(I40E_TX_ITR, itr);
-		tx = true;
-		rxval = i40e_buildreg_itr(I40E_RX_ITR, itr);
-		rx = true;
-	}
-
-	/* only need to enable the interrupt once, but need
-	 * to possibly update both ITR values
+	/* This block of logic allows us to get away with only updating
+	 * one ITR value with each interrupt. The idea is to perform a
+	 * pseudo-lazy update with the following criteria.
+	 *
+	 * 1. Rx is given higher priority than Tx if both are in same state
+	 * 2. If we must reduce an ITR that is given highest priority.
+	 * 3. We then give priority to increasing ITR based on amount.
 	 */
-	if (rx) {
-		/* set the INTENA_MSK_MASK so that this first write
-		 * won't actually enable the interrupt, instead just
-		 * updating the ITR (it's bit 31 PF and VF)
+	if (q_vector->rx.target_itr < q_vector->rx.current_itr) {
+		/* Rx ITR needs to be reduced, this is highest priority */
+		intval = i40e_buildreg_itr(I40E_RX_ITR,
+					   q_vector->rx.target_itr);
+		q_vector->rx.current_itr = q_vector->rx.target_itr;
+		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	} else if ((q_vector->tx.target_itr < q_vector->tx.current_itr) ||
+		   ((q_vector->rx.target_itr - q_vector->rx.current_itr) <
+		    (q_vector->tx.target_itr - q_vector->tx.current_itr))) {
+		/* Tx ITR needs to be reduced, this is second priority
+		 * Tx ITR needs to be increased more than Rx, fourth priority
 		 */
-		rxval |= BIT(31);
-		/* don't check _DOWN because interrupt isn't being enabled */
-		wr32(hw, INTREG(q_vector->reg_idx), rxval);
+		intval = i40e_buildreg_itr(I40E_TX_ITR,
+					   q_vector->tx.target_itr);
+		q_vector->tx.current_itr = q_vector->tx.target_itr;
+		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	} else if (q_vector->rx.current_itr != q_vector->rx.target_itr) {
+		/* Rx ITR needs to be increased, third priority */
+		intval = i40e_buildreg_itr(I40E_RX_ITR,
+					   q_vector->rx.target_itr);
+		q_vector->rx.current_itr = q_vector->rx.target_itr;
+		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	} else {
+		/* No ITR update, lowest priority */
+		intval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
+		if (q_vector->itr_countdown)
+			q_vector->itr_countdown--;
 	}
 
-enable_int:
 	if (!test_bit(__I40E_VSI_DOWN, vsi->state))
-		wr32(hw, INTREG(q_vector->reg_idx), txval);
-
-	if (q_vector->itr_countdown)
-		q_vector->itr_countdown--;
-	else
-		q_vector->itr_countdown = ITR_COUNTDOWN_START;
+		wr32(hw, INTREG(q_vector->reg_idx), intval);
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
index 7798a6645c3f..9129447d079b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
@@ -28,31 +28,35 @@
 #define _I40E_TXRX_H_
 
 /* Interrupt Throttling and Rate Limiting Goodies */
-
-#define I40E_MAX_ITR               0x0FF0  /* reg uses 2 usec resolution */
-#define I40E_MIN_ITR               0x0001  /* reg uses 2 usec resolution */
-#define I40E_ITR_100K              0x0005
-#define I40E_ITR_50K               0x000A
-#define I40E_ITR_20K               0x0019
-#define I40E_ITR_18K               0x001B
-#define I40E_ITR_8K                0x003E
-#define I40E_ITR_4K                0x007A
-#define I40E_MAX_INTRL             0x3B    /* reg uses 4 usec resolution */
-#define I40E_ITR_RX_DEF            (ITR_REG_TO_USEC(I40E_ITR_20K) | \
-				    I40E_ITR_DYNAMIC)
-#define I40E_ITR_TX_DEF            (ITR_REG_TO_USEC(I40E_ITR_20K) | \
-				    I40E_ITR_DYNAMIC)
-#define I40E_ITR_DYNAMIC           0x8000  /* use top bit as a flag */
-#define I40E_MIN_INT_RATE          250     /* ~= 1000000 / (I40E_MAX_ITR * 2) */
-#define I40E_MAX_INT_RATE          500000  /* == 1000000 / (I40E_MIN_ITR * 2) */
 #define I40E_DEFAULT_IRQ_WORK      256
-#define ITR_TO_REG(setting) ((setting & ~I40E_ITR_DYNAMIC) >> 1)
-#define ITR_IS_DYNAMIC(setting) (!!(setting & I40E_ITR_DYNAMIC))
-#define ITR_REG_TO_USEC(itr_reg) (itr_reg << 1)
+
+/* The datasheet for the X710 and XL710 indicate that the maximum value for
+ * the ITR is 8160usec which is then called out as 0xFF0 with a 2usec
+ * resolution. 8160 is 0x1FE0 when written out in hex. So instead of storing
+ * the register value which is divided by 2 lets use the actual values and
+ * avoid an excessive amount of translation.
+ */
+#define I40E_ITR_DYNAMIC	0x8000	/* use top bit as a flag */
+#define I40E_ITR_MASK		0x1FFE	/* mask for ITR register value */
+#define I40E_MIN_ITR		     2	/* reg uses 2 usec resolution */
+#define I40E_ITR_100K		    10	/* all values below must be even */
+#define I40E_ITR_50K		    20
+#define I40E_ITR_20K		    50
+#define I40E_ITR_18K		    60
+#define I40E_ITR_8K		   122
+#define I40E_MAX_ITR		  8160	/* maximum value as per datasheet */
+#define ITR_TO_REG(setting) ((setting) & ~I40E_ITR_DYNAMIC)
+#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~I40E_ITR_MASK)
+#define ITR_IS_DYNAMIC(setting) (!!((setting) & I40E_ITR_DYNAMIC))
+
+#define I40E_ITR_RX_DEF		(I40E_ITR_20K | I40E_ITR_DYNAMIC)
+#define I40E_ITR_TX_DEF		(I40E_ITR_20K | I40E_ITR_DYNAMIC)
+
 /* 0x40 is the enable bit for interrupt rate limiting, and must be set if
  * the value of the rate limit is non-zero
  */
 #define INTRL_ENA                  BIT(6)
+#define I40E_MAX_INTRL             0x3B    /* reg uses 4 usec resolution */
 #define INTRL_REG_TO_USEC(intrl) ((intrl & ~INTRL_ENA) << 2)
 #define INTRL_USEC_TO_REG(set) ((set) ? ((set) >> 2) | INTRL_ENA : 0)
 #define I40E_INTRL_8K              125     /* 8000 ints/sec */
@@ -362,8 +366,7 @@ struct i40e_ring {
 	 * these values always store the USER setting, and must be converted
 	 * before programming to a register.
 	 */
-	u16 rx_itr_setting;
-	u16 tx_itr_setting;
+	u16 itr_setting;
 
 	u16 count;			/* Number of descriptors */
 	u16 reg_idx;			/* HW register index of the ring */
@@ -425,21 +428,21 @@ static inline void clear_ring_build_skb_enabled(struct i40e_ring *ring)
 	ring->flags &= ~I40E_RXR_FLAGS_BUILD_SKB_ENABLED;
 }
 
-enum i40e_latency_range {
-	I40E_LOWEST_LATENCY = 0,
-	I40E_LOW_LATENCY = 1,
-	I40E_BULK_LATENCY = 2,
-};
+#define I40E_ITR_ADAPTIVE_MIN_INC	0x0002
+#define I40E_ITR_ADAPTIVE_MIN_USECS	0x0002
+#define I40E_ITR_ADAPTIVE_MAX_USECS	0x007e
+#define I40E_ITR_ADAPTIVE_LATENCY	0x8000
+#define I40E_ITR_ADAPTIVE_BULK		0x0000
+#define ITR_IS_BULK(x) (!((x) & I40E_ITR_ADAPTIVE_LATENCY))
 
 struct i40e_ring_container {
-	/* array of pointers to rings */
-	struct i40e_ring *ring;
+	struct i40e_ring *ring;		/* pointer to linked list of ring(s) */
+	unsigned long next_update;	/* jiffies value of next update */
 	unsigned int total_bytes;	/* total bytes processed this int */
 	unsigned int total_packets;	/* total packets processed this int */
-	unsigned long last_itr_update;	/* jiffies of last ITR update */
 	u16 count;
-	enum i40e_latency_range latency_range;
-	u16 itr;
+	u16 target_itr;			/* target ITR setting for ring(s) */
+	u16 current_itr;		/* current ITR setting for ring(s) */
 };
 
 /* iterator for handling rings in ring container */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h
index 9690c1ea019e..e46555ad7122 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf.h
+++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
@@ -52,7 +52,10 @@
 #include <linux/socket.h>
 #include <linux/jiffies.h>
 #include <net/ip6_checksum.h>
+#include <net/pkt_cls.h>
 #include <net/udp.h>
+#include <net/tc_act/tc_gact.h>
+#include <net/tc_act/tc_mirred.h>
 
 #include "i40e_type.h"
 #include <linux/avf/virtchnl.h>
@@ -106,6 +109,7 @@ struct i40e_vsi {
 
 #define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
 #define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4)
+#define I40EVF_MBPS_DIVISOR	125000 /* divisor to convert to Mbps */
 
 /* MAX_MSIX_Q_VECTORS of these are allocated,
  * but we only use one per queue-specific vector.
@@ -117,9 +121,8 @@ struct i40e_q_vector {
 	struct i40e_ring_container rx;
 	struct i40e_ring_container tx;
 	u32 ring_mask;
+	u8 itr_countdown;	/* when 0 should adjust adaptive ITR */
 	u8 num_ringpairs;	/* total number of ring pairs in vector */
-#define ITR_COUNTDOWN_START 100
-	u8 itr_countdown;	/* when 0 or 1 update ITR */
 	u16 v_idx;		/* index in the vsi->q_vector array. */
 	u16 reg_idx;		/* register index of the interrupt */
 	char name[IFNAMSIZ + 15];
@@ -169,6 +172,28 @@ struct i40evf_vlan_filter {
 	bool add;		/* filter needs to be added */
 };
 
+#define I40EVF_MAX_TRAFFIC_CLASS	4
+/* State of traffic class creation */
+enum i40evf_tc_state_t {
+	__I40EVF_TC_INVALID, /* no traffic class, default state */
+	__I40EVF_TC_RUNNING, /* traffic classes have been created */
+};
+
+/* channel info */
+struct i40evf_channel_config {
+	struct virtchnl_channel_info ch_info[I40EVF_MAX_TRAFFIC_CLASS];
+	enum i40evf_tc_state_t state;
+	u8 total_qps;
+};
+
+/* State of cloud filter */
+enum i40evf_cloud_filter_state_t {
+	__I40EVF_CF_INVALID,	 /* cloud filter not added */
+	__I40EVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */
+	__I40EVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */
+	__I40EVF_CF_ACTIVE,	 /* cloud filter is active */
+};
+
 /* Driver state. The order of these is important! */
 enum i40evf_state_t {
 	__I40EVF_STARTUP,		/* driver loaded, probe complete */
@@ -190,6 +215,36 @@ enum i40evf_critical_section_t {
 	__I40EVF_IN_REMOVE_TASK,	/* device being removed */
 };
 
+#define I40EVF_CLOUD_FIELD_OMAC		0x01
+#define I40EVF_CLOUD_FIELD_IMAC		0x02
+#define I40EVF_CLOUD_FIELD_IVLAN	0x04
+#define I40EVF_CLOUD_FIELD_TEN_ID	0x08
+#define I40EVF_CLOUD_FIELD_IIP		0x10
+
+#define I40EVF_CF_FLAGS_OMAC	I40EVF_CLOUD_FIELD_OMAC
+#define I40EVF_CF_FLAGS_IMAC	I40EVF_CLOUD_FIELD_IMAC
+#define I40EVF_CF_FLAGS_IMAC_IVLAN	(I40EVF_CLOUD_FIELD_IMAC |\
+					 I40EVF_CLOUD_FIELD_IVLAN)
+#define I40EVF_CF_FLAGS_IMAC_TEN_ID	(I40EVF_CLOUD_FIELD_IMAC |\
+					 I40EVF_CLOUD_FIELD_TEN_ID)
+#define I40EVF_CF_FLAGS_OMAC_TEN_ID_IMAC	(I40EVF_CLOUD_FIELD_OMAC |\
+						 I40EVF_CLOUD_FIELD_IMAC |\
+						 I40EVF_CLOUD_FIELD_TEN_ID)
+#define I40EVF_CF_FLAGS_IMAC_IVLAN_TEN_ID	(I40EVF_CLOUD_FIELD_IMAC |\
+						 I40EVF_CLOUD_FIELD_IVLAN |\
+						 I40EVF_CLOUD_FIELD_TEN_ID)
+#define I40EVF_CF_FLAGS_IIP	I40E_CLOUD_FIELD_IIP
+
+/* bookkeeping of cloud filters */
+struct i40evf_cloud_filter {
+	enum i40evf_cloud_filter_state_t state;
+	struct list_head list;
+	struct virtchnl_filter f;
+	unsigned long cookie;
+	bool del;		/* filter needs to be deleted */
+	bool add;		/* filter needs to be added */
+};
+
 /* board specific private data structure */
 struct i40evf_adapter {
 	struct timer_list watchdog_timer;
@@ -241,6 +296,7 @@ struct i40evf_adapter {
 #define I40EVF_FLAG_ALLMULTI_ON			BIT(14)
 #define I40EVF_FLAG_LEGACY_RX			BIT(15)
 #define I40EVF_FLAG_REINIT_ITR_NEEDED		BIT(16)
+#define I40EVF_FLAG_QUEUES_DISABLED		BIT(17)
 /* duplicates for common code */
 #define I40E_FLAG_DCB_ENABLED			0
 #define I40E_FLAG_RX_CSUM_ENABLED		I40EVF_FLAG_RX_CSUM_ENABLED
@@ -269,6 +325,10 @@ struct i40evf_adapter {
 #define I40EVF_FLAG_AQ_RELEASE_ALLMULTI		BIT(18)
 #define I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING	BIT(19)
 #define I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING	BIT(20)
+#define I40EVF_FLAG_AQ_ENABLE_CHANNELS		BIT(21)
+#define I40EVF_FLAG_AQ_DISABLE_CHANNELS		BIT(22)
+#define I40EVF_FLAG_AQ_ADD_CLOUD_FILTER		BIT(23)
+#define I40EVF_FLAG_AQ_DEL_CLOUD_FILTER		BIT(24)
 
 	/* OS defined structs */
 	struct net_device *netdev;
@@ -314,6 +374,13 @@ struct i40evf_adapter {
 	u16 rss_lut_size;
 	u8 *rss_key;
 	u8 *rss_lut;
+	/* ADQ related members */
+	struct i40evf_channel_config ch_config;
+	u8 num_tc;
+	struct list_head cloud_filter_list;
+	/* lock to protest access to the cloud filter list */
+	spinlock_t cloud_filter_list_lock;
+	u16 num_cloud_filters;
 };
 
 
@@ -380,4 +447,8 @@ void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len);
 void i40evf_notify_client_l2_params(struct i40e_vsi *vsi);
 void i40evf_notify_client_open(struct i40e_vsi *vsi);
 void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset);
+void i40evf_enable_channels(struct i40evf_adapter *adapter);
+void i40evf_disable_channels(struct i40evf_adapter *adapter);
+void i40evf_add_cloud_filter(struct i40evf_adapter *adapter);
+void i40evf_del_cloud_filter(struct i40evf_adapter *adapter);
 #endif /* _I40EVF_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
index e2d8aa19d205..e6793255de0b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
@@ -457,14 +457,14 @@ static int __i40evf_get_coalesce(struct net_device *netdev,
 	rx_ring = &adapter->rx_rings[queue];
 	tx_ring = &adapter->tx_rings[queue];
 
-	if (ITR_IS_DYNAMIC(rx_ring->rx_itr_setting))
+	if (ITR_IS_DYNAMIC(rx_ring->itr_setting))
 		ec->use_adaptive_rx_coalesce = 1;
 
-	if (ITR_IS_DYNAMIC(tx_ring->tx_itr_setting))
+	if (ITR_IS_DYNAMIC(tx_ring->itr_setting))
 		ec->use_adaptive_tx_coalesce = 1;
 
-	ec->rx_coalesce_usecs = rx_ring->rx_itr_setting & ~I40E_ITR_DYNAMIC;
-	ec->tx_coalesce_usecs = tx_ring->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+	ec->rx_coalesce_usecs = rx_ring->itr_setting & ~I40E_ITR_DYNAMIC;
+	ec->tx_coalesce_usecs = tx_ring->itr_setting & ~I40E_ITR_DYNAMIC;
 
 	return 0;
 }
@@ -502,7 +502,7 @@ static int i40evf_get_per_queue_coalesce(struct net_device *netdev,
 
 /**
  * i40evf_set_itr_per_queue - set ITR values for specific queue
- * @vsi: the VSI to set values for
+ * @adapter: the VF adapter struct to set values for
  * @ec: coalesce settings from ethtool
  * @queue: the queue to modify
  *
@@ -514,33 +514,29 @@ static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter,
 {
 	struct i40e_ring *rx_ring = &adapter->rx_rings[queue];
 	struct i40e_ring *tx_ring = &adapter->tx_rings[queue];
-	struct i40e_vsi *vsi = &adapter->vsi;
-	struct i40e_hw *hw = &adapter->hw;
 	struct i40e_q_vector *q_vector;
-	u16 vector;
 
-	rx_ring->rx_itr_setting = ec->rx_coalesce_usecs;
-	tx_ring->tx_itr_setting = ec->tx_coalesce_usecs;
+	rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
+	tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);
 
-	rx_ring->rx_itr_setting |= I40E_ITR_DYNAMIC;
+	rx_ring->itr_setting |= I40E_ITR_DYNAMIC;
 	if (!ec->use_adaptive_rx_coalesce)
-		rx_ring->rx_itr_setting ^= I40E_ITR_DYNAMIC;
+		rx_ring->itr_setting ^= I40E_ITR_DYNAMIC;
 
-	tx_ring->tx_itr_setting |= I40E_ITR_DYNAMIC;
+	tx_ring->itr_setting |= I40E_ITR_DYNAMIC;
 	if (!ec->use_adaptive_tx_coalesce)
-		tx_ring->tx_itr_setting ^= I40E_ITR_DYNAMIC;
+		tx_ring->itr_setting ^= I40E_ITR_DYNAMIC;
 
 	q_vector = rx_ring->q_vector;
-	q_vector->rx.itr = ITR_TO_REG(rx_ring->rx_itr_setting);
-	vector = vsi->base_vector + q_vector->v_idx;
-	wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, vector - 1), q_vector->rx.itr);
+	q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
 
 	q_vector = tx_ring->q_vector;
-	q_vector->tx.itr = ITR_TO_REG(tx_ring->tx_itr_setting);
-	vector = vsi->base_vector + q_vector->v_idx;
-	wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, vector - 1), q_vector->tx.itr);
+	q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
 
-	i40e_flush(hw);
+	/* The interrupt handler itself will take care of programming
+	 * the Tx and Rx ITR values based on the values we have entered
+	 * into the q_vector, no need to write the values now.
+	 */
 }
 
 /**
@@ -565,8 +561,8 @@ static int __i40evf_set_coalesce(struct net_device *netdev,
 	if (ec->rx_coalesce_usecs == 0) {
 		if (ec->use_adaptive_rx_coalesce)
 			netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
-	} else if ((ec->rx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
-		   (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
+	} else if ((ec->rx_coalesce_usecs < I40E_MIN_ITR) ||
+		   (ec->rx_coalesce_usecs > I40E_MAX_ITR)) {
 		netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
 		return -EINVAL;
 	}
@@ -575,8 +571,8 @@ static int __i40evf_set_coalesce(struct net_device *netdev,
 	if (ec->tx_coalesce_usecs == 0) {
 		if (ec->use_adaptive_tx_coalesce)
 			netif_info(adapter, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
-	} else if ((ec->tx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
-		   (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
+	} else if ((ec->tx_coalesce_usecs < I40E_MIN_ITR) ||
+		   (ec->tx_coalesce_usecs > I40E_MAX_ITR)) {
 		netif_info(adapter, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
 		return -EINVAL;
 	}
@@ -699,6 +695,12 @@ static int i40evf_set_channels(struct net_device *netdev,
 		return -EINVAL;
 	}
 
+	if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
+	    adapter->num_tc) {
+		dev_info(&adapter->pdev->dev, "Cannot set channels since ADq is enabled.\n");
+		return -EINVAL;
+	}
+
 	/* All of these should have already been checked by ethtool before this
 	 * even gets to us, but just to be sure.
 	 */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index 16989ad2ca90..4955ce3ab6a2 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -353,11 +353,12 @@ i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx)
 	rx_ring->vsi = &adapter->vsi;
 	q_vector->rx.ring = rx_ring;
 	q_vector->rx.count++;
-	q_vector->rx.latency_range = I40E_LOW_LATENCY;
-	q_vector->rx.itr = ITR_TO_REG(rx_ring->rx_itr_setting);
+	q_vector->rx.next_update = jiffies + 1;
+	q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
 	q_vector->ring_mask |= BIT(r_idx);
-	q_vector->itr_countdown = ITR_COUNTDOWN_START;
-	wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, v_idx - 1), q_vector->rx.itr);
+	wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx),
+	     q_vector->rx.current_itr);
+	q_vector->rx.current_itr = q_vector->rx.target_itr;
 }
 
 /**
@@ -378,11 +379,12 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
 	tx_ring->vsi = &adapter->vsi;
 	q_vector->tx.ring = tx_ring;
 	q_vector->tx.count++;
-	q_vector->tx.latency_range = I40E_LOW_LATENCY;
-	q_vector->tx.itr = ITR_TO_REG(tx_ring->tx_itr_setting);
-	q_vector->itr_countdown = ITR_COUNTDOWN_START;
+	q_vector->tx.next_update = jiffies + 1;
+	q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
 	q_vector->num_ringpairs++;
-	wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, v_idx - 1), q_vector->tx.itr);
+	wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx),
+	     q_vector->tx.target_itr);
+	q_vector->tx.current_itr = q_vector->tx.target_itr;
 }
 
 /**
@@ -783,7 +785,7 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
  **/
 static struct
 i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
-				      u8 *macaddr)
+				      const u8 *macaddr)
 {
 	struct i40evf_mac_filter *f;
 
@@ -806,7 +808,7 @@ i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
  **/
 static struct
 i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
-				     u8 *macaddr)
+				     const u8 *macaddr)
 {
 	struct i40evf_mac_filter *f;
 
@@ -878,50 +880,64 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
 }
 
 /**
- * i40evf_set_rx_mode - NDO callback to set the netdev filters
- * @netdev: network interface device structure
- **/
-static void i40evf_set_rx_mode(struct net_device *netdev)
+ * i40evf_addr_sync - Callback for dev_(mc|uc)_sync to add address
+ * @netdev: the netdevice
+ * @addr: address to add
+ *
+ * Called by __dev_(mc|uc)_sync when an address needs to be added. We call
+ * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
+ */
+static int i40evf_addr_sync(struct net_device *netdev, const u8 *addr)
 {
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
-	struct i40evf_mac_filter *f, *ftmp;
-	struct netdev_hw_addr *uca;
-	struct netdev_hw_addr *mca;
-	struct netdev_hw_addr *ha;
-
-	/* add addr if not already in the filter list */
-	netdev_for_each_uc_addr(uca, netdev) {
-		i40evf_add_filter(adapter, uca->addr);
-	}
-	netdev_for_each_mc_addr(mca, netdev) {
-		i40evf_add_filter(adapter, mca->addr);
-	}
-
-	spin_lock_bh(&adapter->mac_vlan_list_lock);
-
-	list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
-		netdev_for_each_mc_addr(mca, netdev)
-			if (ether_addr_equal(mca->addr, f->macaddr))
-				goto bottom_of_search_loop;
 
-		netdev_for_each_uc_addr(uca, netdev)
-			if (ether_addr_equal(uca->addr, f->macaddr))
-				goto bottom_of_search_loop;
+	if (i40evf_add_filter(adapter, addr))
+		return 0;
+	else
+		return -ENOMEM;
+}
 
-		for_each_dev_addr(netdev, ha)
-			if (ether_addr_equal(ha->addr, f->macaddr))
-				goto bottom_of_search_loop;
+/**
+ * i40evf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
+ * @netdev: the netdevice
+ * @addr: address to add
+ *
+ * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call
+ * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
+ */
+static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr)
+{
+	struct i40evf_adapter *adapter = netdev_priv(netdev);
+	struct i40evf_mac_filter *f;
 
-		if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr))
-			goto bottom_of_search_loop;
+	/* Under some circumstances, we might receive a request to delete
+	 * our own device address from our uc list. Because we store the
+	 * device address in the VSI's MAC/VLAN filter list, we need to ignore
+	 * such requests and not delete our device address from this list.
+	 */
+	if (ether_addr_equal(addr, netdev->dev_addr))
+		return 0;
 
-		/* f->macaddr wasn't found in uc, mc, or ha list so delete it */
+	f = i40evf_find_filter(adapter, addr);
+	if (f) {
 		f->remove = true;
 		adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
-
-bottom_of_search_loop:
-		continue;
 	}
+	return 0;
+}
+
+/**
+ * i40evf_set_rx_mode - NDO callback to set the netdev filters
+ * @netdev: network interface device structure
+ **/
+static void i40evf_set_rx_mode(struct net_device *netdev)
+{
+	struct i40evf_adapter *adapter = netdev_priv(netdev);
+
+	spin_lock_bh(&adapter->mac_vlan_list_lock);
+	__dev_uc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
+	__dev_mc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
+	spin_unlock_bh(&adapter->mac_vlan_list_lock);
 
 	if (netdev->flags & IFF_PROMISC &&
 	    !(adapter->flags & I40EVF_FLAG_PROMISC_ON))
@@ -936,8 +952,6 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
 	else if (!(netdev->flags & IFF_ALLMULTI) &&
 		 adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
 		adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
-
-	spin_unlock_bh(&adapter->mac_vlan_list_lock);
 }
 
 /**
@@ -1025,7 +1039,9 @@ static void i40evf_up_complete(struct i40evf_adapter *adapter)
 void i40evf_down(struct i40evf_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
+	struct i40evf_vlan_filter *vlf;
 	struct i40evf_mac_filter *f;
+	struct i40evf_cloud_filter *cf;
 
 	if (adapter->state <= __I40EVF_DOWN_PENDING)
 		return;
@@ -1038,17 +1054,29 @@ void i40evf_down(struct i40evf_adapter *adapter)
 
 	spin_lock_bh(&adapter->mac_vlan_list_lock);
 
+	/* clear the sync flag on all filters */
+	__dev_uc_unsync(adapter->netdev, NULL);
+	__dev_mc_unsync(adapter->netdev, NULL);
+
 	/* remove all MAC filters */
 	list_for_each_entry(f, &adapter->mac_filter_list, list) {
 		f->remove = true;
 	}
+
 	/* remove all VLAN filters */
-	list_for_each_entry(f, &adapter->vlan_filter_list, list) {
-		f->remove = true;
+	list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
+		vlf->remove = true;
 	}
 
 	spin_unlock_bh(&adapter->mac_vlan_list_lock);
 
+	/* remove all cloud filters */
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
+		cf->del = true;
+	}
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+
 	if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
 	    adapter->state != __I40EVF_RESETTING) {
 		/* cancel any current operation */
@@ -1059,6 +1087,7 @@ void i40evf_down(struct i40evf_adapter *adapter)
 		 */
 		adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER;
 		adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+		adapter->aq_required |= I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
 		adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
 	}
 
@@ -1144,6 +1173,9 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
 	 */
 	if (adapter->num_req_queues)
 		num_active_queues = adapter->num_req_queues;
+	else if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
+		 adapter->num_tc)
+		num_active_queues = adapter->ch_config.total_qps;
 	else
 		num_active_queues = min_t(int,
 					  adapter->vsi_res->num_queue_pairs,
@@ -1169,7 +1201,7 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
 		tx_ring->netdev = adapter->netdev;
 		tx_ring->dev = &adapter->pdev->dev;
 		tx_ring->count = adapter->tx_desc_count;
-		tx_ring->tx_itr_setting = I40E_ITR_TX_DEF;
+		tx_ring->itr_setting = I40E_ITR_TX_DEF;
 		if (adapter->flags & I40EVF_FLAG_WB_ON_ITR_CAPABLE)
 			tx_ring->flags |= I40E_TXR_FLAGS_WB_ON_ITR;
 
@@ -1178,7 +1210,7 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
 		rx_ring->netdev = adapter->netdev;
 		rx_ring->dev = &adapter->pdev->dev;
 		rx_ring->count = adapter->rx_desc_count;
-		rx_ring->rx_itr_setting = I40E_ITR_RX_DEF;
+		rx_ring->itr_setting = I40E_ITR_RX_DEF;
 	}
 
 	adapter->num_active_queues = num_active_queues;
@@ -1471,6 +1503,16 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter)
 		goto err_alloc_q_vectors;
 	}
 
+	/* If we've made it so far while ADq flag being ON, then we haven't
+	 * bailed out anywhere in middle. And ADq isn't just enabled but actual
+	 * resources have been allocated in the reset path.
+	 * Now we can truly claim that ADq is enabled.
+	 */
+	if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
+	    adapter->num_tc)
+		dev_info(&adapter->pdev->dev, "ADq Enabled, %u TCs created",
+			 adapter->num_tc);
+
 	dev_info(&adapter->pdev->dev, "Multiqueue %s: Queue pair count = %u",
 		 (adapter->num_active_queues > 1) ? "Enabled" : "Disabled",
 		 adapter->num_active_queues);
@@ -1712,6 +1754,27 @@ static void i40evf_watchdog_task(struct work_struct *work)
 		i40evf_set_promiscuous(adapter, 0);
 		goto watchdog_done;
 	}
+
+	if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_CHANNELS) {
+		i40evf_enable_channels(adapter);
+		goto watchdog_done;
+	}
+
+	if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_CHANNELS) {
+		i40evf_disable_channels(adapter);
+		goto watchdog_done;
+	}
+
+	if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_CLOUD_FILTER) {
+		i40evf_add_cloud_filter(adapter);
+		goto watchdog_done;
+	}
+
+	if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_CLOUD_FILTER) {
+		i40evf_del_cloud_filter(adapter);
+		goto watchdog_done;
+	}
+
 	schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
 
 	if (adapter->state == __I40EVF_RUNNING)
@@ -1735,6 +1798,7 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
 {
 	struct i40evf_mac_filter *f, *ftmp;
 	struct i40evf_vlan_filter *fv, *fvtmp;
+	struct i40evf_cloud_filter *cf, *cftmp;
 
 	adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
 
@@ -1756,7 +1820,7 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
 
 	spin_lock_bh(&adapter->mac_vlan_list_lock);
 
-	/* Delete all of the filters, both MAC and VLAN. */
+	/* Delete all of the filters */
 	list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
 		list_del(&f->list);
 		kfree(f);
@@ -1769,6 +1833,14 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
 
 	spin_unlock_bh(&adapter->mac_vlan_list_lock);
 
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) {
+		list_del(&cf->list);
+		kfree(cf);
+		adapter->num_cloud_filters--;
+	}
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+
 	i40evf_free_misc_irq(adapter);
 	i40evf_reset_interrupt_capability(adapter);
 	i40evf_free_queues(adapter);
@@ -1798,9 +1870,11 @@ static void i40evf_reset_task(struct work_struct *work)
 	struct i40evf_adapter *adapter = container_of(work,
 						      struct i40evf_adapter,
 						      reset_task);
+	struct virtchnl_vf_resource *vfres = adapter->vf_res;
 	struct net_device *netdev = adapter->netdev;
 	struct i40e_hw *hw = &adapter->hw;
 	struct i40evf_vlan_filter *vlf;
+	struct i40evf_cloud_filter *cf;
 	struct i40evf_mac_filter *f;
 	u32 reg_val;
 	int i = 0, err;
@@ -1893,6 +1967,7 @@ static void i40evf_reset_task(struct work_struct *work)
 	i40evf_free_all_rx_resources(adapter);
 	i40evf_free_all_tx_resources(adapter);
 
+	adapter->flags |= I40EVF_FLAG_QUEUES_DISABLED;
 	/* kill and reinit the admin queue */
 	i40evf_shutdown_adminq(hw);
 	adapter->current_op = VIRTCHNL_OP_UNKNOWN;
@@ -1924,8 +1999,19 @@ static void i40evf_reset_task(struct work_struct *work)
 
 	spin_unlock_bh(&adapter->mac_vlan_list_lock);
 
+	/* check if TCs are running and re-add all cloud filters */
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	if ((vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
+	    adapter->num_tc) {
+		list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
+			cf->add = true;
+		}
+	}
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+
 	adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER;
 	adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
+	adapter->aq_required |= I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
 	i40evf_misc_irq_enable(adapter);
 
 	mod_timer(&adapter->watchdog_timer, jiffies + 2);
@@ -2190,6 +2276,724 @@ void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
 			i40evf_free_rx_resources(&adapter->rx_rings[i]);
 }
 
+/**
+ * i40evf_validate_tx_bandwidth - validate the max Tx bandwidth
+ * @adapter: board private structure
+ * @max_tx_rate: max Tx bw for a tc
+ **/
+static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter,
+					u64 max_tx_rate)
+{
+	int speed = 0, ret = 0;
+
+	switch (adapter->link_speed) {
+	case I40E_LINK_SPEED_40GB:
+		speed = 40000;
+		break;
+	case I40E_LINK_SPEED_25GB:
+		speed = 25000;
+		break;
+	case I40E_LINK_SPEED_20GB:
+		speed = 20000;
+		break;
+	case I40E_LINK_SPEED_10GB:
+		speed = 10000;
+		break;
+	case I40E_LINK_SPEED_1GB:
+		speed = 1000;
+		break;
+	case I40E_LINK_SPEED_100MB:
+		speed = 100;
+		break;
+	default:
+		break;
+	}
+
+	if (max_tx_rate > speed) {
+		dev_err(&adapter->pdev->dev,
+			"Invalid tx rate specified\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * i40evf_validate_channel_config - validate queue mapping info
+ * @adapter: board private structure
+ * @mqprio_qopt: queue parameters
+ *
+ * This function validates if the config provided by the user to
+ * configure queue channels is valid or not. Returns 0 on a valid
+ * config.
+ **/
+static int i40evf_validate_ch_config(struct i40evf_adapter *adapter,
+				     struct tc_mqprio_qopt_offload *mqprio_qopt)
+{
+	u64 total_max_rate = 0;
+	int i, num_qps = 0;
+	u64 tx_rate = 0;
+	int ret = 0;
+
+	if (mqprio_qopt->qopt.num_tc > I40EVF_MAX_TRAFFIC_CLASS ||
+	    mqprio_qopt->qopt.num_tc < 1)
+		return -EINVAL;
+
+	for (i = 0; i <= mqprio_qopt->qopt.num_tc - 1; i++) {
+		if (!mqprio_qopt->qopt.count[i] ||
+		    mqprio_qopt->qopt.offset[i] != num_qps)
+			return -EINVAL;
+		if (mqprio_qopt->min_rate[i]) {
+			dev_err(&adapter->pdev->dev,
+				"Invalid min tx rate (greater than 0) specified\n");
+			return -EINVAL;
+		}
+		/*convert to Mbps */
+		tx_rate = div_u64(mqprio_qopt->max_rate[i],
+				  I40EVF_MBPS_DIVISOR);
+		total_max_rate += tx_rate;
+		num_qps += mqprio_qopt->qopt.count[i];
+	}
+	if (num_qps > MAX_QUEUES)
+		return -EINVAL;
+
+	ret = i40evf_validate_tx_bandwidth(adapter, total_max_rate);
+	return ret;
+}
+
+/**
+ * i40evf_del_all_cloud_filters - delete all cloud filters
+ * on the traffic classes
+ **/
+static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter)
+{
+	struct i40evf_cloud_filter *cf, *cftmp;
+
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list,
+				 list) {
+		list_del(&cf->list);
+		kfree(cf);
+		adapter->num_cloud_filters--;
+	}
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+}
+
+/**
+ * __i40evf_setup_tc - configure multiple traffic classes
+ * @netdev: network interface device structure
+ * @type_date: tc offload data
+ *
+ * This function processes the config information provided by the
+ * user to configure traffic classes/queue channels and packages the
+ * information to request the PF to setup traffic classes.
+ *
+ * Returns 0 on success.
+ **/
+static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
+{
+	struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
+	struct i40evf_adapter *adapter = netdev_priv(netdev);
+	struct virtchnl_vf_resource *vfres = adapter->vf_res;
+	u8 num_tc = 0, total_qps = 0;
+	int ret = 0, netdev_tc = 0;
+	u64 max_tx_rate;
+	u16 mode;
+	int i;
+
+	num_tc = mqprio_qopt->qopt.num_tc;
+	mode = mqprio_qopt->mode;
+
+	/* delete queue_channel */
+	if (!mqprio_qopt->qopt.hw) {
+		if (adapter->ch_config.state == __I40EVF_TC_RUNNING) {
+			/* reset the tc configuration */
+			netdev_reset_tc(netdev);
+			adapter->num_tc = 0;
+			netif_tx_stop_all_queues(netdev);
+			netif_tx_disable(netdev);
+			i40evf_del_all_cloud_filters(adapter);
+			adapter->aq_required = I40EVF_FLAG_AQ_DISABLE_CHANNELS;
+			goto exit;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	/* add queue channel */
+	if (mode == TC_MQPRIO_MODE_CHANNEL) {
+		if (!(vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)) {
+			dev_err(&adapter->pdev->dev, "ADq not supported\n");
+			return -EOPNOTSUPP;
+		}
+		if (adapter->ch_config.state != __I40EVF_TC_INVALID) {
+			dev_err(&adapter->pdev->dev, "TC configuration already exists\n");
+			return -EINVAL;
+		}
+
+		ret = i40evf_validate_ch_config(adapter, mqprio_qopt);
+		if (ret)
+			return ret;
+		/* Return if same TC config is requested */
+		if (adapter->num_tc == num_tc)
+			return 0;
+		adapter->num_tc = num_tc;
+
+		for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) {
+			if (i < num_tc) {
+				adapter->ch_config.ch_info[i].count =
+					mqprio_qopt->qopt.count[i];
+				adapter->ch_config.ch_info[i].offset =
+					mqprio_qopt->qopt.offset[i];
+				total_qps += mqprio_qopt->qopt.count[i];
+				max_tx_rate = mqprio_qopt->max_rate[i];
+				/* convert to Mbps */
+				max_tx_rate = div_u64(max_tx_rate,
+						      I40EVF_MBPS_DIVISOR);
+				adapter->ch_config.ch_info[i].max_tx_rate =
+					max_tx_rate;
+			} else {
+				adapter->ch_config.ch_info[i].count = 1;
+				adapter->ch_config.ch_info[i].offset = 0;
+			}
+		}
+		adapter->ch_config.total_qps = total_qps;
+		netif_tx_stop_all_queues(netdev);
+		netif_tx_disable(netdev);
+		adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_CHANNELS;
+		netdev_reset_tc(netdev);
+		/* Report the tc mapping up the stack */
+		netdev_set_num_tc(adapter->netdev, num_tc);
+		for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) {
+			u16 qcount = mqprio_qopt->qopt.count[i];
+			u16 qoffset = mqprio_qopt->qopt.offset[i];
+
+			if (i < num_tc)
+				netdev_set_tc_queue(netdev, netdev_tc++, qcount,
+						    qoffset);
+		}
+	}
+exit:
+	return ret;
+}
+
+/**
+ * i40evf_parse_cls_flower - Parse tc flower filters provided by kernel
+ * @adapter: board private structure
+ * @cls_flower: pointer to struct tc_cls_flower_offload
+ * @filter: pointer to cloud filter structure
+ */
+static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
+				   struct tc_cls_flower_offload *f,
+				   struct i40evf_cloud_filter *filter)
+{
+	u16 n_proto_mask = 0;
+	u16 n_proto_key = 0;
+	u8 field_flags = 0;
+	u16 addr_type = 0;
+	u16 n_proto = 0;
+	int i = 0;
+
+	if (f->dissector->used_keys &
+	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
+	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
+	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
+	      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
+		dev_err(&adapter->pdev->dev, "Unsupported key used: 0x%x\n",
+			f->dissector->used_keys);
+		return -EOPNOTSUPP;
+	}
+
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+		struct flow_dissector_key_keyid *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_ENC_KEYID,
+						  f->mask);
+
+		if (mask->keyid != 0)
+			field_flags |= I40EVF_CLOUD_FIELD_TEN_ID;
+	}
+
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
+		struct flow_dissector_key_basic *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_BASIC,
+						  f->key);
+
+		struct flow_dissector_key_basic *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_BASIC,
+						  f->mask);
+		n_proto_key = ntohs(key->n_proto);
+		n_proto_mask = ntohs(mask->n_proto);
+
+		if (n_proto_key == ETH_P_ALL) {
+			n_proto_key = 0;
+			n_proto_mask = 0;
+		}
+		n_proto = n_proto_key & n_proto_mask;
+		if (n_proto != ETH_P_IP && n_proto != ETH_P_IPV6)
+			return -EINVAL;
+		if (n_proto == ETH_P_IPV6) {
+			/* specify flow type as TCP IPv6 */
+			filter->f.flow_type = VIRTCHNL_TCP_V6_FLOW;
+		}
+
+		if (key->ip_proto != IPPROTO_TCP) {
+			dev_info(&adapter->pdev->dev, "Only TCP transport is supported\n");
+			return -EINVAL;
+		}
+	}
+
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+		struct flow_dissector_key_eth_addrs *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
+						  f->key);
+
+		struct flow_dissector_key_eth_addrs *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
+						  f->mask);
+		/* use is_broadcast and is_zero to check for all 0xf or 0 */
+		if (!is_zero_ether_addr(mask->dst)) {
+			if (is_broadcast_ether_addr(mask->dst)) {
+				field_flags |= I40EVF_CLOUD_FIELD_OMAC;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad ether dest mask %pM\n",
+					mask->dst);
+				return I40E_ERR_CONFIG;
+			}
+		}
+
+		if (!is_zero_ether_addr(mask->src)) {
+			if (is_broadcast_ether_addr(mask->src)) {
+				field_flags |= I40EVF_CLOUD_FIELD_IMAC;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad ether src mask %pM\n",
+					mask->src);
+				return I40E_ERR_CONFIG;
+			}
+		}
+
+		if (!is_zero_ether_addr(key->dst))
+			if (is_valid_ether_addr(key->dst) ||
+			    is_multicast_ether_addr(key->dst)) {
+				/* set the mask if a valid dst_mac address */
+				for (i = 0; i < ETH_ALEN; i++)
+					filter->f.mask.tcp_spec.dst_mac[i] |=
+									0xff;
+				ether_addr_copy(filter->f.data.tcp_spec.dst_mac,
+						key->dst);
+			}
+
+		if (!is_zero_ether_addr(key->src))
+			if (is_valid_ether_addr(key->src) ||
+			    is_multicast_ether_addr(key->src)) {
+				/* set the mask if a valid dst_mac address */
+				for (i = 0; i < ETH_ALEN; i++)
+					filter->f.mask.tcp_spec.src_mac[i] |=
+									0xff;
+				ether_addr_copy(filter->f.data.tcp_spec.src_mac,
+						key->src);
+		}
+	}
+
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
+		struct flow_dissector_key_vlan *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_VLAN,
+						  f->key);
+		struct flow_dissector_key_vlan *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_VLAN,
+						  f->mask);
+
+		if (mask->vlan_id) {
+			if (mask->vlan_id == VLAN_VID_MASK) {
+				field_flags |= I40EVF_CLOUD_FIELD_IVLAN;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad vlan mask %u\n",
+					mask->vlan_id);
+				return I40E_ERR_CONFIG;
+			}
+		}
+		filter->f.mask.tcp_spec.vlan_id |= cpu_to_be16(0xffff);
+		filter->f.data.tcp_spec.vlan_id = cpu_to_be16(key->vlan_id);
+	}
+
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
+		struct flow_dissector_key_control *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_CONTROL,
+						  f->key);
+
+		addr_type = key->addr_type;
+	}
+
+	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+		struct flow_dissector_key_ipv4_addrs *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+						  f->key);
+		struct flow_dissector_key_ipv4_addrs *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+						  f->mask);
+
+		if (mask->dst) {
+			if (mask->dst == cpu_to_be32(0xffffffff)) {
+				field_flags |= I40EVF_CLOUD_FIELD_IIP;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad ip dst mask 0x%08x\n",
+					be32_to_cpu(mask->dst));
+				return I40E_ERR_CONFIG;
+			}
+		}
+
+		if (mask->src) {
+			if (mask->src == cpu_to_be32(0xffffffff)) {
+				field_flags |= I40EVF_CLOUD_FIELD_IIP;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
+					be32_to_cpu(mask->dst));
+				return I40E_ERR_CONFIG;
+			}
+		}
+
+		if (field_flags & I40EVF_CLOUD_FIELD_TEN_ID) {
+			dev_info(&adapter->pdev->dev, "Tenant id not allowed for ip filter\n");
+			return I40E_ERR_CONFIG;
+		}
+		if (key->dst) {
+			filter->f.mask.tcp_spec.dst_ip[0] |=
+							cpu_to_be32(0xffffffff);
+			filter->f.data.tcp_spec.dst_ip[0] = key->dst;
+		}
+		if (key->src) {
+			filter->f.mask.tcp_spec.src_ip[0] |=
+							cpu_to_be32(0xffffffff);
+			filter->f.data.tcp_spec.src_ip[0] = key->src;
+		}
+	}
+
+	if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+		struct flow_dissector_key_ipv6_addrs *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+						  f->key);
+		struct flow_dissector_key_ipv6_addrs *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+						  f->mask);
+
+		/* validate mask, make sure it is not IPV6_ADDR_ANY */
+		if (ipv6_addr_any(&mask->dst)) {
+			dev_err(&adapter->pdev->dev, "Bad ipv6 dst mask 0x%02x\n",
+				IPV6_ADDR_ANY);
+			return I40E_ERR_CONFIG;
+		}
+
+		/* src and dest IPv6 address should not be LOOPBACK
+		 * (0:0:0:0:0:0:0:1) which can be represented as ::1
+		 */
+		if (ipv6_addr_loopback(&key->dst) ||
+		    ipv6_addr_loopback(&key->src)) {
+			dev_err(&adapter->pdev->dev,
+				"ipv6 addr should not be loopback\n");
+			return I40E_ERR_CONFIG;
+		}
+		if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))
+			field_flags |= I40EVF_CLOUD_FIELD_IIP;
+
+		if (key->dst.s6_addr) {
+			for (i = 0; i < 4; i++)
+				filter->f.mask.tcp_spec.dst_ip[i] |=
+							cpu_to_be32(0xffffffff);
+			memcpy(&filter->f.data.tcp_spec.dst_ip,
+			       &key->dst.s6_addr32,
+			       sizeof(filter->f.data.tcp_spec.dst_ip));
+		}
+		if (key->src.s6_addr) {
+			for (i = 0; i < 4; i++)
+				filter->f.mask.tcp_spec.src_ip[i] |=
+							cpu_to_be32(0xffffffff);
+			memcpy(&filter->f.data.tcp_spec.src_ip,
+			       &key->src.s6_addr32,
+			       sizeof(filter->f.data.tcp_spec.src_ip));
+		}
+	}
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
+		struct flow_dissector_key_ports *key =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_PORTS,
+						  f->key);
+		struct flow_dissector_key_ports *mask =
+			skb_flow_dissector_target(f->dissector,
+						  FLOW_DISSECTOR_KEY_PORTS,
+						  f->mask);
+
+		if (mask->src) {
+			if (mask->src == cpu_to_be16(0xffff)) {
+				field_flags |= I40EVF_CLOUD_FIELD_IIP;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad src port mask %u\n",
+					be16_to_cpu(mask->src));
+				return I40E_ERR_CONFIG;
+			}
+		}
+
+		if (mask->dst) {
+			if (mask->dst == cpu_to_be16(0xffff)) {
+				field_flags |= I40EVF_CLOUD_FIELD_IIP;
+			} else {
+				dev_err(&adapter->pdev->dev, "Bad dst port mask %u\n",
+					be16_to_cpu(mask->dst));
+				return I40E_ERR_CONFIG;
+			}
+		}
+		if (key->dst) {
+			filter->f.mask.tcp_spec.dst_port |= cpu_to_be16(0xffff);
+			filter->f.data.tcp_spec.dst_port = key->dst;
+		}
+
+		if (key->src) {
+			filter->f.mask.tcp_spec.src_port |= cpu_to_be16(0xffff);
+			filter->f.data.tcp_spec.src_port = key->dst;
+		}
+	}
+	filter->f.field_flags = field_flags;
+
+	return 0;
+}
+
+/**
+ * i40evf_handle_tclass - Forward to a traffic class on the device
+ * @adapter: board private structure
+ * @tc: traffic class index on the device
+ * @filter: pointer to cloud filter structure
+ */
+static int i40evf_handle_tclass(struct i40evf_adapter *adapter, u32 tc,
+				struct i40evf_cloud_filter *filter)
+{
+	if (tc == 0)
+		return 0;
+	if (tc < adapter->num_tc) {
+		if (!filter->f.data.tcp_spec.dst_port) {
+			dev_err(&adapter->pdev->dev,
+				"Specify destination port to redirect to traffic class other than TC0\n");
+			return -EINVAL;
+		}
+	}
+	/* redirect to a traffic class on the same device */
+	filter->f.action = VIRTCHNL_ACTION_TC_REDIRECT;
+	filter->f.action_meta = tc;
+	return 0;
+}
+
+/**
+ * i40evf_configure_clsflower - Add tc flower filters
+ * @adapter: board private structure
+ * @cls_flower: Pointer to struct tc_cls_flower_offload
+ */
+static int i40evf_configure_clsflower(struct i40evf_adapter *adapter,
+				      struct tc_cls_flower_offload *cls_flower)
+{
+	int tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid);
+	struct i40evf_cloud_filter *filter = NULL;
+	int err = 0, count = 50;
+
+	while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+				&adapter->crit_section)) {
+		udelay(1);
+		if (--count == 0)
+			return -EINVAL;
+	}
+
+	if (tc < 0) {
+		dev_err(&adapter->pdev->dev, "Invalid traffic class\n");
+		return -EINVAL;
+	}
+
+	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+	if (!filter) {
+		err = -ENOMEM;
+		goto clearout;
+	}
+	filter->cookie = cls_flower->cookie;
+
+	/* set the mask to all zeroes to begin with */
+	memset(&filter->f.mask.tcp_spec, 0, sizeof(struct virtchnl_l4_spec));
+	/* start out with flow type and eth type IPv4 to begin with */
+	filter->f.flow_type = VIRTCHNL_TCP_V4_FLOW;
+	err = i40evf_parse_cls_flower(adapter, cls_flower, filter);
+	if (err < 0)
+		goto err;
+
+	err = i40evf_handle_tclass(adapter, tc, filter);
+	if (err < 0)
+		goto err;
+
+	/* add filter to the list */
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	list_add_tail(&filter->list, &adapter->cloud_filter_list);
+	adapter->num_cloud_filters++;
+	filter->add = true;
+	adapter->aq_required |= I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+err:
+	if (err)
+		kfree(filter);
+clearout:
+	clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+	return err;
+}
+
+/* i40evf_find_cf - Find the cloud filter in the list
+ * @adapter: Board private structure
+ * @cookie: filter specific cookie
+ *
+ * Returns ptr to the filter object or NULL. Must be called while holding the
+ * cloud_filter_list_lock.
+ */
+static struct i40evf_cloud_filter *i40evf_find_cf(struct i40evf_adapter *adapter,
+						  unsigned long *cookie)
+{
+	struct i40evf_cloud_filter *filter = NULL;
+
+	if (!cookie)
+		return NULL;
+
+	list_for_each_entry(filter, &adapter->cloud_filter_list, list) {
+		if (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))
+			return filter;
+	}
+	return NULL;
+}
+
+/**
+ * i40evf_delete_clsflower - Remove tc flower filters
+ * @adapter: board private structure
+ * @cls_flower: Pointer to struct tc_cls_flower_offload
+ */
+static int i40evf_delete_clsflower(struct i40evf_adapter *adapter,
+				   struct tc_cls_flower_offload *cls_flower)
+{
+	struct i40evf_cloud_filter *filter = NULL;
+	int err = 0;
+
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	filter = i40evf_find_cf(adapter, &cls_flower->cookie);
+	if (filter) {
+		filter->del = true;
+		adapter->aq_required |= I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
+	} else {
+		err = -EINVAL;
+	}
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+
+	return err;
+}
+
+/**
+ * i40evf_setup_tc_cls_flower - flower classifier offloads
+ * @netdev: net device to configure
+ * @type_data: offload data
+ */
+static int i40evf_setup_tc_cls_flower(struct i40evf_adapter *adapter,
+				      struct tc_cls_flower_offload *cls_flower)
+{
+	if (cls_flower->common.chain_index)
+		return -EOPNOTSUPP;
+
+	switch (cls_flower->command) {
+	case TC_CLSFLOWER_REPLACE:
+		return i40evf_configure_clsflower(adapter, cls_flower);
+	case TC_CLSFLOWER_DESTROY:
+		return i40evf_delete_clsflower(adapter, cls_flower);
+	case TC_CLSFLOWER_STATS:
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
+	}
+}
+
+/**
+ * i40evf_setup_tc_block_cb - block callback for tc
+ * @type: type of offload
+ * @type_data: offload data
+ * @cb_priv:
+ *
+ * This function is the block callback for traffic classes
+ **/
+static int i40evf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
+				    void *cb_priv)
+{
+	switch (type) {
+	case TC_SETUP_CLSFLOWER:
+		return i40evf_setup_tc_cls_flower(cb_priv, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/**
+ * i40evf_setup_tc_block - register callbacks for tc
+ * @netdev: network interface device structure
+ * @f: tc offload data
+ *
+ * This function registers block callbacks for tc
+ * offloads
+ **/
+static int i40evf_setup_tc_block(struct net_device *dev,
+				 struct tc_block_offload *f)
+{
+	struct i40evf_adapter *adapter = netdev_priv(dev);
+
+	if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+		return -EOPNOTSUPP;
+
+	switch (f->command) {
+	case TC_BLOCK_BIND:
+		return tcf_block_cb_register(f->block, i40evf_setup_tc_block_cb,
+					     adapter, adapter);
+	case TC_BLOCK_UNBIND:
+		tcf_block_cb_unregister(f->block, i40evf_setup_tc_block_cb,
+					adapter);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/**
+ * i40evf_setup_tc - configure multiple traffic classes
+ * @netdev: network interface device structure
+ * @type: type of offload
+ * @type_date: tc offload data
+ *
+ * This function is the callback to ndo_setup_tc in the
+ * netdev_ops.
+ *
+ * Returns 0 on success
+ **/
+static int i40evf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
+			   void *type_data)
+{
+	switch (type) {
+	case TC_SETUP_QDISC_MQPRIO:
+		return __i40evf_setup_tc(netdev, type_data);
+	case TC_SETUP_BLOCK:
+		return i40evf_setup_tc_block(netdev, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 /**
  * i40evf_open - Called when a network interface is made active
  * @netdev: network interface device structure
@@ -2457,6 +3261,7 @@ static const struct net_device_ops i40evf_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= i40evf_netpoll,
 #endif
+	.ndo_setup_tc		= i40evf_setup_tc,
 };
 
 /**
@@ -2571,6 +3376,9 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
 	if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
 		hw_features |= (NETIF_F_HW_VLAN_CTAG_TX |
 				NETIF_F_HW_VLAN_CTAG_RX);
+	/* Enable cloud filter if ADQ is supported */
+	if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)
+		hw_features |= NETIF_F_HW_TC;
 
 	netdev->hw_features |= hw_features;
 
@@ -2938,9 +3746,11 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	mutex_init(&hw->aq.arq_mutex);
 
 	spin_lock_init(&adapter->mac_vlan_list_lock);
+	spin_lock_init(&adapter->cloud_filter_list_lock);
 
 	INIT_LIST_HEAD(&adapter->mac_filter_list);
 	INIT_LIST_HEAD(&adapter->vlan_filter_list);
+	INIT_LIST_HEAD(&adapter->cloud_filter_list);
 
 	INIT_WORK(&adapter->reset_task, i40evf_reset_task);
 	INIT_WORK(&adapter->adminq_task, i40evf_adminq_task);
@@ -3065,7 +3875,9 @@ static void i40evf_remove(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
+	struct i40evf_vlan_filter *vlf, *vlftmp;
 	struct i40evf_mac_filter *f, *ftmp;
+	struct i40evf_cloud_filter *cf, *cftmp;
 	struct i40e_hw *hw = &adapter->hw;
 	int err;
 	/* Indicate we are in remove and not to run reset_task */
@@ -3087,6 +3899,7 @@ static void i40evf_remove(struct pci_dev *pdev)
 	/* Shut down all the garbage mashers on the detention level */
 	adapter->state = __I40EVF_REMOVE;
 	adapter->aq_required = 0;
+	adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
 	i40evf_request_reset(adapter);
 	msleep(50);
 	/* If the FW isn't responding, kick it once, but only once. */
@@ -3127,13 +3940,21 @@ static void i40evf_remove(struct pci_dev *pdev)
 		list_del(&f->list);
 		kfree(f);
 	}
-	list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
-		list_del(&f->list);
-		kfree(f);
+	list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list,
+				 list) {
+		list_del(&vlf->list);
+		kfree(vlf);
 	}
 
 	spin_unlock_bh(&adapter->mac_vlan_list_lock);
 
+	spin_lock_bh(&adapter->cloud_filter_list_lock);
+	list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) {
+		list_del(&cf->list);
+		kfree(cf);
+	}
+	spin_unlock_bh(&adapter->cloud_filter_list_lock);
+
 	free_netdev(netdev);
 
 	pci_disable_pcie_error_reporting(pdev);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index 50ce0d6c09ef..6134b61e0938 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -161,7 +161,8 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
 	       VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
 	       VIRTCHNL_VF_OFFLOAD_ENCAP |
 	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
-	       VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
+	       VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
+	       VIRTCHNL_VF_OFFLOAD_ADQ;
 
 	adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
 	adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
@@ -344,6 +345,7 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter)
 void i40evf_map_queues(struct i40evf_adapter *adapter)
 {
 	struct virtchnl_irq_map_info *vimi;
+	struct virtchnl_vector_map *vecmap;
 	int v_idx, q_vectors, len;
 	struct i40e_q_vector *q_vector;
 
@@ -367,17 +369,22 @@ void i40evf_map_queues(struct i40evf_adapter *adapter)
 	vimi->num_vectors = adapter->num_msix_vectors;
 	/* Queue vectors first */
 	for (v_idx = 0; v_idx < q_vectors; v_idx++) {
-		q_vector = adapter->q_vectors + v_idx;
-		vimi->vecmap[v_idx].vsi_id = adapter->vsi_res->vsi_id;
-		vimi->vecmap[v_idx].vector_id = v_idx + NONQ_VECS;
-		vimi->vecmap[v_idx].txq_map = q_vector->ring_mask;
-		vimi->vecmap[v_idx].rxq_map = q_vector->ring_mask;
+		q_vector = &adapter->q_vectors[v_idx];
+		vecmap = &vimi->vecmap[v_idx];
+
+		vecmap->vsi_id = adapter->vsi_res->vsi_id;
+		vecmap->vector_id = v_idx + NONQ_VECS;
+		vecmap->txq_map = q_vector->ring_mask;
+		vecmap->rxq_map = q_vector->ring_mask;
+		vecmap->rxitr_idx = I40E_RX_ITR;
+		vecmap->txitr_idx = I40E_TX_ITR;
 	}
 	/* Misc vector last - this is only for AdminQ messages */
-	vimi->vecmap[v_idx].vsi_id = adapter->vsi_res->vsi_id;
-	vimi->vecmap[v_idx].vector_id = 0;
-	vimi->vecmap[v_idx].txq_map = 0;
-	vimi->vecmap[v_idx].rxq_map = 0;
+	vecmap = &vimi->vecmap[v_idx];
+	vecmap->vsi_id = adapter->vsi_res->vsi_id;
+	vecmap->vector_id = 0;
+	vecmap->txq_map = 0;
+	vecmap->rxq_map = 0;
 
 	adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS;
 	i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP,
@@ -459,7 +466,7 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
 		more = true;
 	}
 
-	veal = kzalloc(len, GFP_KERNEL);
+	veal = kzalloc(len, GFP_ATOMIC);
 	if (!veal) {
 		spin_unlock_bh(&adapter->mac_vlan_list_lock);
 		return;
@@ -532,7 +539,7 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
 		      (count * sizeof(struct virtchnl_ether_addr));
 		more = true;
 	}
-	veal = kzalloc(len, GFP_KERNEL);
+	veal = kzalloc(len, GFP_ATOMIC);
 	if (!veal) {
 		spin_unlock_bh(&adapter->mac_vlan_list_lock);
 		return;
@@ -606,7 +613,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
 		      (count * sizeof(u16));
 		more = true;
 	}
-	vvfl = kzalloc(len, GFP_KERNEL);
+	vvfl = kzalloc(len, GFP_ATOMIC);
 	if (!vvfl) {
 		spin_unlock_bh(&adapter->mac_vlan_list_lock);
 		return;
@@ -678,7 +685,7 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
 		      (count * sizeof(u16));
 		more = true;
 	}
-	vvfl = kzalloc(len, GFP_KERNEL);
+	vvfl = kzalloc(len, GFP_ATOMIC);
 	if (!vvfl) {
 		spin_unlock_bh(&adapter->mac_vlan_list_lock);
 		return;
@@ -966,6 +973,201 @@ static void i40evf_print_link_message(struct i40evf_adapter *adapter)
 	netdev_info(netdev, "NIC Link is Up %sbps Full Duplex\n", speed);
 }
 
+/**
+ * i40evf_enable_channel
+ * @adapter: adapter structure
+ *
+ * Request that the PF enable channels as specified by
+ * the user via tc tool.
+ **/
+void i40evf_enable_channels(struct i40evf_adapter *adapter)
+{
+	struct virtchnl_tc_info *vti = NULL;
+	u16 len;
+	int i;
+
+	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+		/* bail because we already have a command pending */
+		dev_err(&adapter->pdev->dev, "Cannot configure mqprio, command %d pending\n",
+			adapter->current_op);
+		return;
+	}
+
+	len = (adapter->num_tc * sizeof(struct virtchnl_channel_info)) +
+	       sizeof(struct virtchnl_tc_info);
+
+	vti = kzalloc(len, GFP_KERNEL);
+	if (!vti)
+		return;
+	vti->num_tc = adapter->num_tc;
+	for (i = 0; i < vti->num_tc; i++) {
+		vti->list[i].count = adapter->ch_config.ch_info[i].count;
+		vti->list[i].offset = adapter->ch_config.ch_info[i].offset;
+		vti->list[i].pad = 0;
+		vti->list[i].max_tx_rate =
+				adapter->ch_config.ch_info[i].max_tx_rate;
+	}
+
+	adapter->ch_config.state = __I40EVF_TC_RUNNING;
+	adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+	adapter->current_op = VIRTCHNL_OP_ENABLE_CHANNELS;
+	adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_CHANNELS;
+	i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS,
+			   (u8 *)vti, len);
+	kfree(vti);
+}
+
+/**
+ * i40evf_disable_channel
+ * @adapter: adapter structure
+ *
+ * Request that the PF disable channels that are configured
+ **/
+void i40evf_disable_channels(struct i40evf_adapter *adapter)
+{
+	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+		/* bail because we already have a command pending */
+		dev_err(&adapter->pdev->dev, "Cannot configure mqprio, command %d pending\n",
+			adapter->current_op);
+		return;
+	}
+
+	adapter->ch_config.state = __I40EVF_TC_INVALID;
+	adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+	adapter->current_op = VIRTCHNL_OP_DISABLE_CHANNELS;
+	adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_CHANNELS;
+	i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS,
+			   NULL, 0);
+}
+
+/**
+ * i40evf_print_cloud_filter
+ * @adapter: adapter structure
+ * @f: cloud filter to print
+ *
+ * Print the cloud filter
+ **/
+static void i40evf_print_cloud_filter(struct i40evf_adapter *adapter,
+				      struct virtchnl_filter f)
+{
+	switch (f.flow_type) {
+	case VIRTCHNL_TCP_V4_FLOW:
+		dev_info(&adapter->pdev->dev, "dst_mac: %pM src_mac: %pM vlan_id: %hu dst_ip: %pI4 src_ip %pI4 dst_port %hu src_port %hu\n",
+			 &f.data.tcp_spec.dst_mac, &f.data.tcp_spec.src_mac,
+			 ntohs(f.data.tcp_spec.vlan_id),
+			 &f.data.tcp_spec.dst_ip[0], &f.data.tcp_spec.src_ip[0],
+			 ntohs(f.data.tcp_spec.dst_port),
+			 ntohs(f.data.tcp_spec.src_port));
+		break;
+	case VIRTCHNL_TCP_V6_FLOW:
+		dev_info(&adapter->pdev->dev, "dst_mac: %pM src_mac: %pM vlan_id: %hu dst_ip: %pI6 src_ip %pI6 dst_port %hu src_port %hu\n",
+			 &f.data.tcp_spec.dst_mac, &f.data.tcp_spec.src_mac,
+			 ntohs(f.data.tcp_spec.vlan_id),
+			 &f.data.tcp_spec.dst_ip, &f.data.tcp_spec.src_ip,
+			 ntohs(f.data.tcp_spec.dst_port),
+			 ntohs(f.data.tcp_spec.src_port));
+		break;
+	}
+}
+
+/**
+ * i40evf_add_cloud_filter
+ * @adapter: adapter structure
+ *
+ * Request that the PF add cloud filters as specified
+ * by the user via tc tool.
+ **/
+void i40evf_add_cloud_filter(struct i40evf_adapter *adapter)
+{
+	struct i40evf_cloud_filter *cf;
+	struct virtchnl_filter *f;
+	int len = 0, count = 0;
+
+	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+		/* bail because we already have a command pending */
+		dev_err(&adapter->pdev->dev, "Cannot add cloud filter, command %d pending\n",
+			adapter->current_op);
+		return;
+	}
+	list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
+		if (cf->add) {
+			count++;
+			break;
+		}
+	}
+	if (!count) {
+		adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
+		return;
+	}
+	adapter->current_op = VIRTCHNL_OP_ADD_CLOUD_FILTER;
+
+	len = sizeof(struct virtchnl_filter);
+	f = kzalloc(len, GFP_KERNEL);
+	if (!f)
+		return;
+
+	list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
+		if (cf->add) {
+			memcpy(f, &cf->f, sizeof(struct virtchnl_filter));
+			cf->add = false;
+			cf->state = __I40EVF_CF_ADD_PENDING;
+			i40evf_send_pf_msg(adapter,
+					   VIRTCHNL_OP_ADD_CLOUD_FILTER,
+					   (u8 *)f, len);
+		}
+	}
+	kfree(f);
+}
+
+/**
+ * i40evf_del_cloud_filter
+ * @adapter: adapter structure
+ *
+ * Request that the PF delete cloud filters as specified
+ * by the user via tc tool.
+ **/
+void i40evf_del_cloud_filter(struct i40evf_adapter *adapter)
+{
+	struct i40evf_cloud_filter *cf, *cftmp;
+	struct virtchnl_filter *f;
+	int len = 0, count = 0;
+
+	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+		/* bail because we already have a command pending */
+		dev_err(&adapter->pdev->dev, "Cannot remove cloud filter, command %d pending\n",
+			adapter->current_op);
+		return;
+	}
+	list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
+		if (cf->del) {
+			count++;
+			break;
+		}
+	}
+	if (!count) {
+		adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
+		return;
+	}
+	adapter->current_op = VIRTCHNL_OP_DEL_CLOUD_FILTER;
+
+	len = sizeof(struct virtchnl_filter);
+	f = kzalloc(len, GFP_KERNEL);
+	if (!f)
+		return;
+
+	list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list, list) {
+		if (cf->del) {
+			memcpy(f, &cf->f, sizeof(struct virtchnl_filter));
+			cf->del = false;
+			cf->state = __I40EVF_CF_DEL_PENDING;
+			i40evf_send_pf_msg(adapter,
+					   VIRTCHNL_OP_DEL_CLOUD_FILTER,
+					   (u8 *)f, len);
+		}
+	}
+	kfree(f);
+}
+
 /**
  * i40evf_request_reset
  * @adapter: adapter structure
@@ -1011,14 +1213,25 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 			if (adapter->link_up == link_up)
 				break;
 
-			/* If we get link up message and start queues before
-			 * our queues are configured it will trigger a TX hang.
-			 * In that case, just ignore the link status message,
-			 * we'll get another one after we enable queues and
-			 * actually prepared to send traffic.
-			 */
-			if (link_up && adapter->state != __I40EVF_RUNNING)
-				break;
+			if (link_up) {
+				/* If we get link up message and start queues
+				 * before our queues are configured it will
+				 * trigger a TX hang. In that case, just ignore
+				 * the link status message,we'll get another one
+				 * after we enable queues and actually prepared
+				 * to send traffic.
+				 */
+				if (adapter->state != __I40EVF_RUNNING)
+					break;
+
+				/* For ADq enabled VF, we reconfigure VSIs and
+				 * re-allocate queues. Hence wait till all
+				 * queues are enabled.
+				 */
+				if (adapter->flags &
+				    I40EVF_FLAG_QUEUES_DISABLED)
+					break;
+			}
 
 			adapter->link_up = link_up;
 			if (link_up) {
@@ -1031,7 +1244,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 			i40evf_print_link_message(adapter);
 			break;
 		case VIRTCHNL_EVENT_RESET_IMPENDING:
-			dev_info(&adapter->pdev->dev, "PF reset warning received\n");
+			dev_info(&adapter->pdev->dev, "Reset warning received from the PF\n");
 			if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
 				adapter->flags |= I40EVF_FLAG_RESET_PENDING;
 				dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
@@ -1063,6 +1276,57 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 			dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
 				i40evf_stat_str(&adapter->hw, v_retval));
 			break;
+		case VIRTCHNL_OP_ENABLE_CHANNELS:
+			dev_err(&adapter->pdev->dev, "Failed to configure queue channels, error %s\n",
+				i40evf_stat_str(&adapter->hw, v_retval));
+			adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
+			adapter->ch_config.state = __I40EVF_TC_INVALID;
+			netdev_reset_tc(netdev);
+			netif_tx_start_all_queues(netdev);
+			break;
+		case VIRTCHNL_OP_DISABLE_CHANNELS:
+			dev_err(&adapter->pdev->dev, "Failed to disable queue channels, error %s\n",
+				i40evf_stat_str(&adapter->hw, v_retval));
+			adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
+			adapter->ch_config.state = __I40EVF_TC_RUNNING;
+			netif_tx_start_all_queues(netdev);
+			break;
+		case VIRTCHNL_OP_ADD_CLOUD_FILTER: {
+			struct i40evf_cloud_filter *cf, *cftmp;
+
+			list_for_each_entry_safe(cf, cftmp,
+						 &adapter->cloud_filter_list,
+						 list) {
+				if (cf->state == __I40EVF_CF_ADD_PENDING) {
+					cf->state = __I40EVF_CF_INVALID;
+					dev_info(&adapter->pdev->dev, "Failed to add cloud filter, error %s\n",
+						 i40evf_stat_str(&adapter->hw,
+								 v_retval));
+					i40evf_print_cloud_filter(adapter,
+								  cf->f);
+					list_del(&cf->list);
+					kfree(cf);
+					adapter->num_cloud_filters--;
+				}
+			}
+			}
+			break;
+		case VIRTCHNL_OP_DEL_CLOUD_FILTER: {
+			struct i40evf_cloud_filter *cf;
+
+			list_for_each_entry(cf, &adapter->cloud_filter_list,
+					    list) {
+				if (cf->state == __I40EVF_CF_DEL_PENDING) {
+					cf->state = __I40EVF_CF_ACTIVE;
+					dev_info(&adapter->pdev->dev, "Failed to del cloud filter, error %s\n",
+						 i40evf_stat_str(&adapter->hw,
+								 v_retval));
+					i40evf_print_cloud_filter(adapter,
+								  cf->f);
+				}
+			}
+			}
+			break;
 		default:
 			dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
 				v_retval,
@@ -1102,6 +1366,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 	case VIRTCHNL_OP_ENABLE_QUEUES:
 		/* enable transmits */
 		i40evf_irq_enable(adapter, true);
+		adapter->flags &= ~I40EVF_FLAG_QUEUES_DISABLED;
 		break;
 	case VIRTCHNL_OP_DISABLE_QUEUES:
 		i40evf_free_all_tx_resources(adapter);
@@ -1156,6 +1421,29 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 		}
 		}
 		break;
+	case VIRTCHNL_OP_ADD_CLOUD_FILTER: {
+		struct i40evf_cloud_filter *cf;
+
+		list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
+			if (cf->state == __I40EVF_CF_ADD_PENDING)
+				cf->state = __I40EVF_CF_ACTIVE;
+		}
+		}
+		break;
+	case VIRTCHNL_OP_DEL_CLOUD_FILTER: {
+		struct i40evf_cloud_filter *cf, *cftmp;
+
+		list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list,
+					 list) {
+			if (cf->state == __I40EVF_CF_DEL_PENDING) {
+				cf->state = __I40EVF_CF_INVALID;
+				list_del(&cf->list);
+				kfree(cf);
+				adapter->num_cloud_filters--;
+			}
+		}
+		}
+		break;
 	default:
 		if (adapter->current_op && (v_opcode != adapter->current_op))
 			dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n",
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index a1d7b88cf083..5a1668cdb461 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7137,6 +7137,7 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
 	int id = port->id;
 	bool allmulti = dev->flags & IFF_ALLMULTI;
 
+retry:
 	mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC);
 	mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti);
 	mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti);
@@ -7144,9 +7145,13 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
 	/* Remove all port->id's mcast enries */
 	mvpp2_prs_mcast_del_all(priv, id);
 
-	if (allmulti && !netdev_mc_empty(dev)) {
-		netdev_for_each_mc_addr(ha, dev)
-			mvpp2_prs_mac_da_accept(priv, id, ha->addr, true);
+	if (!allmulti) {
+		netdev_for_each_mc_addr(ha, dev) {
+			if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
+				allmulti = true;
+				goto retry;
+			}
+		}
 	}
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index 9463c3fa254f..0cadcabfe86f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -20,7 +20,7 @@ mlxsw_spectrum-objs		:= spectrum.o spectrum_buffers.o \
 				   spectrum_cnt.o spectrum_fid.o \
 				   spectrum_ipip.o spectrum_acl_flex_actions.o \
 				   spectrum_mr.o spectrum_mr_tcam.o \
-				   spectrum_qdisc.o
+				   spectrum_qdisc.o spectrum_span.o
 mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB)	+= spectrum_dcb.o
 mlxsw_spectrum-$(CONFIG_NET_DEVLINK) += spectrum_dpipe.o
 obj-$(CONFIG_MLXSW_MINIMAL)	+= mlxsw_minimal.o
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 3dcc58d61506..5e8ea712caa2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -71,6 +71,7 @@
 #include "spectrum_cnt.h"
 #include "spectrum_dpipe.h"
 #include "spectrum_acl_flex_actions.h"
+#include "spectrum_span.h"
 #include "../mlxfw/mlxfw.h"
 
 #define MLXSW_FWREV_MAJOR 13
@@ -487,327 +488,6 @@ static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp)
 	return 0;
 }
 
-static int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
-{
-	int i;
-
-	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN))
-		return -EIO;
-
-	mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core,
-							  MAX_SPAN);
-	mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count,
-					 sizeof(struct mlxsw_sp_span_entry),
-					 GFP_KERNEL);
-	if (!mlxsw_sp->span.entries)
-		return -ENOMEM;
-
-	for (i = 0; i < mlxsw_sp->span.entries_count; i++)
-		INIT_LIST_HEAD(&mlxsw_sp->span.entries[i].bound_ports_list);
-
-	return 0;
-}
-
-static void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
-{
-	int i;
-
-	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
-		struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
-
-		WARN_ON_ONCE(!list_empty(&curr->bound_ports_list));
-	}
-	kfree(mlxsw_sp->span.entries);
-}
-
-static struct mlxsw_sp_span_entry *
-mlxsw_sp_span_entry_create(struct mlxsw_sp_port *port)
-{
-	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
-	struct mlxsw_sp_span_entry *span_entry;
-	char mpat_pl[MLXSW_REG_MPAT_LEN];
-	u8 local_port = port->local_port;
-	int index;
-	int i;
-	int err;
-
-	/* find a free entry to use */
-	index = -1;
-	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
-		if (!mlxsw_sp->span.entries[i].used) {
-			index = i;
-			span_entry = &mlxsw_sp->span.entries[i];
-			break;
-		}
-	}
-	if (index < 0)
-		return NULL;
-
-	/* create a new port analayzer entry for local_port */
-	mlxsw_reg_mpat_pack(mpat_pl, index, local_port, true);
-	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
-	if (err)
-		return NULL;
-
-	span_entry->used = true;
-	span_entry->id = index;
-	span_entry->ref_count = 1;
-	span_entry->local_port = local_port;
-	return span_entry;
-}
-
-static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp,
-					struct mlxsw_sp_span_entry *span_entry)
-{
-	u8 local_port = span_entry->local_port;
-	char mpat_pl[MLXSW_REG_MPAT_LEN];
-	int pa_id = span_entry->id;
-
-	mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false);
-	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
-	span_entry->used = false;
-}
-
-struct mlxsw_sp_span_entry *
-mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port)
-{
-	int i;
-
-	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
-		struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
-
-		if (curr->used && curr->local_port == local_port)
-			return curr;
-	}
-	return NULL;
-}
-
-static struct mlxsw_sp_span_entry
-*mlxsw_sp_span_entry_get(struct mlxsw_sp_port *port)
-{
-	struct mlxsw_sp_span_entry *span_entry;
-
-	span_entry = mlxsw_sp_span_entry_find(port->mlxsw_sp,
-					      port->local_port);
-	if (span_entry) {
-		/* Already exists, just take a reference */
-		span_entry->ref_count++;
-		return span_entry;
-	}
-
-	return mlxsw_sp_span_entry_create(port);
-}
-
-static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
-				   struct mlxsw_sp_span_entry *span_entry)
-{
-	WARN_ON(!span_entry->ref_count);
-	if (--span_entry->ref_count == 0)
-		mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry);
-	return 0;
-}
-
-static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port)
-{
-	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
-	struct mlxsw_sp_span_inspected_port *p;
-	int i;
-
-	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
-		struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
-
-		list_for_each_entry(p, &curr->bound_ports_list, list)
-			if (p->local_port == port->local_port &&
-			    p->type == MLXSW_SP_SPAN_EGRESS)
-				return true;
-	}
-
-	return false;
-}
-
-static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp,
-					 int mtu)
-{
-	return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1;
-}
-
-static int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
-{
-	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
-	char sbib_pl[MLXSW_REG_SBIB_LEN];
-	int err;
-
-	/* If port is egress mirrored, the shared buffer size should be
-	 * updated according to the mtu value
-	 */
-	if (mlxsw_sp_span_is_egress_mirror(port)) {
-		u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu);
-
-		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
-		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
-		if (err) {
-			netdev_err(port->dev, "Could not update shared buffer for mirroring\n");
-			return err;
-		}
-	}
-
-	return 0;
-}
-
-static struct mlxsw_sp_span_inspected_port *
-mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port,
-				    struct mlxsw_sp_span_entry *span_entry)
-{
-	struct mlxsw_sp_span_inspected_port *p;
-
-	list_for_each_entry(p, &span_entry->bound_ports_list, list)
-		if (port->local_port == p->local_port)
-			return p;
-	return NULL;
-}
-
-static int
-mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port,
-				  struct mlxsw_sp_span_entry *span_entry,
-				  enum mlxsw_sp_span_type type,
-				  bool bind)
-{
-	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
-	char mpar_pl[MLXSW_REG_MPAR_LEN];
-	int pa_id = span_entry->id;
-
-	/* bind the port to the SPAN entry */
-	mlxsw_reg_mpar_pack(mpar_pl, port->local_port,
-			    (enum mlxsw_reg_mpar_i_e) type, bind, pa_id);
-	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl);
-}
-
-static int
-mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port,
-				 struct mlxsw_sp_span_entry *span_entry,
-				 enum mlxsw_sp_span_type type,
-				 bool bind)
-{
-	struct mlxsw_sp_span_inspected_port *inspected_port;
-	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
-	char sbib_pl[MLXSW_REG_SBIB_LEN];
-	int err;
-
-	/* if it is an egress SPAN, bind a shared buffer to it */
-	if (type == MLXSW_SP_SPAN_EGRESS) {
-		u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp,
-							     port->dev->mtu);
-
-		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
-		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
-		if (err) {
-			netdev_err(port->dev, "Could not create shared buffer for mirroring\n");
-			return err;
-		}
-	}
-
-	if (bind) {
-		err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
-							true);
-		if (err)
-			goto err_port_bind;
-	}
-
-	inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL);
-	if (!inspected_port) {
-		err = -ENOMEM;
-		goto err_inspected_port_alloc;
-	}
-	inspected_port->local_port = port->local_port;
-	inspected_port->type = type;
-	list_add_tail(&inspected_port->list, &span_entry->bound_ports_list);
-
-	return 0;
-
-err_inspected_port_alloc:
-	if (bind)
-		mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
-						  false);
-err_port_bind:
-	if (type == MLXSW_SP_SPAN_EGRESS) {
-		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
-		mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
-	}
-	return err;
-}
-
-static void
-mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
-				 struct mlxsw_sp_span_entry *span_entry,
-				 enum mlxsw_sp_span_type type,
-				 bool bind)
-{
-	struct mlxsw_sp_span_inspected_port *inspected_port;
-	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
-	char sbib_pl[MLXSW_REG_SBIB_LEN];
-
-	inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry);
-	if (!inspected_port)
-		return;
-
-	if (bind)
-		mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
-						  false);
-	/* remove the SBIB buffer if it was egress SPAN */
-	if (type == MLXSW_SP_SPAN_EGRESS) {
-		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
-		mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
-	}
-
-	mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
-
-	list_del(&inspected_port->list);
-	kfree(inspected_port);
-}
-
-int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
-			     struct mlxsw_sp_port *to,
-			     enum mlxsw_sp_span_type type, bool bind)
-{
-	struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp;
-	struct mlxsw_sp_span_entry *span_entry;
-	int err;
-
-	span_entry = mlxsw_sp_span_entry_get(to);
-	if (!span_entry)
-		return -ENOENT;
-
-	netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n",
-		   span_entry->id);
-
-	err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind);
-	if (err)
-		goto err_port_bind;
-
-	return 0;
-
-err_port_bind:
-	mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
-	return err;
-}
-
-void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port,
-			      enum mlxsw_sp_span_type type, bool bind)
-{
-	struct mlxsw_sp_span_entry *span_entry;
-
-	span_entry = mlxsw_sp_span_entry_find(from->mlxsw_sp,
-					      destination_port);
-	if (!span_entry) {
-		netdev_err(from->dev, "no span entry found\n");
-		return;
-	}
-
-	netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n",
-		   span_entry->id);
-	mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
-}
-
 static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
 				    bool enable, u32 rate)
 {
@@ -4556,13 +4236,11 @@ mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp,
 	u16 lag_id;
 
 	if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) {
-		NL_SET_ERR_MSG(extack,
-			       "spectrum: Exceeded number of supported LAG devices");
+		NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices");
 		return false;
 	}
 	if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
-		NL_SET_ERR_MSG(extack,
-			       "spectrum: LAG device using unsupported Tx type");
+		NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");
 		return false;
 	}
 	return true;
@@ -4804,8 +4482,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
 		    !netif_is_lag_master(upper_dev) &&
 		    !netif_is_bridge_master(upper_dev) &&
 		    !netif_is_ovs_master(upper_dev)) {
-			NL_SET_ERR_MSG(extack,
-				       "spectrum: Unknown upper device type");
+			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
 			return -EINVAL;
 		}
 		if (!info->linking)
@@ -4814,8 +4491,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
 		    (!netif_is_bridge_master(upper_dev) ||
 		     !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
 							  upper_dev))) {
-			NL_SET_ERR_MSG(extack,
-				       "spectrum: Enslaving a port to a device that already has an upper device is not supported");
+			NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported");
 			return -EINVAL;
 		}
 		if (netif_is_lag_master(upper_dev) &&
@@ -4823,24 +4499,20 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
 					       info->upper_info, extack))
 			return -EINVAL;
 		if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) {
-			NL_SET_ERR_MSG(extack,
-				       "spectrum: Master device is a LAG master and this device has a VLAN");
+			NL_SET_ERR_MSG_MOD(extack, "Master device is a LAG master and this device has a VLAN");
 			return -EINVAL;
 		}
 		if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) &&
 		    !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) {
-			NL_SET_ERR_MSG(extack,
-				       "spectrum: Can not put a VLAN on a LAG port");
+			NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port");
 			return -EINVAL;
 		}
 		if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) {
-			NL_SET_ERR_MSG(extack,
-				       "spectrum: Master device is an OVS master and this device has a VLAN");
+			NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN");
 			return -EINVAL;
 		}
 		if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) {
-			NL_SET_ERR_MSG(extack,
-				       "spectrum: Can not put a VLAN on an OVS port");
+			NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port");
 			return -EINVAL;
 		}
 		break;
@@ -4953,7 +4625,7 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
 	case NETDEV_PRECHANGEUPPER:
 		upper_dev = info->upper_dev;
 		if (!netif_is_bridge_master(upper_dev)) {
-			NL_SET_ERR_MSG(extack, "spectrum: VLAN devices only support bridge and VRF uppers");
+			NL_SET_ERR_MSG_MOD(extack, "VLAN devices only support bridge and VRF uppers");
 			return -EINVAL;
 		}
 		if (!info->linking)
@@ -4962,7 +4634,7 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
 		    (!netif_is_bridge_master(upper_dev) ||
 		     !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
 							  upper_dev))) {
-			NL_SET_ERR_MSG(extack, "spectrum: Enslaving a port to a device that already has an upper device is not supported");
+			NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported");
 			return -EINVAL;
 		}
 		break;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index bdd8f94a452c..6718a1f0482c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -80,6 +80,7 @@ enum mlxsw_sp_resource_id {
 
 struct mlxsw_sp_port;
 struct mlxsw_sp_rif;
+struct mlxsw_sp_span_entry;
 
 struct mlxsw_sp_upper {
 	struct net_device *dev;
@@ -111,25 +112,6 @@ struct mlxsw_sp_mid {
 	unsigned long *ports_in_mid; /* bits array */
 };
 
-enum mlxsw_sp_span_type {
-	MLXSW_SP_SPAN_EGRESS,
-	MLXSW_SP_SPAN_INGRESS
-};
-
-struct mlxsw_sp_span_inspected_port {
-	struct list_head list;
-	enum mlxsw_sp_span_type type;
-	u8 local_port;
-};
-
-struct mlxsw_sp_span_entry {
-	u8 local_port;
-	bool used;
-	struct list_head bound_ports_list;
-	int ref_count;
-	int id;
-};
-
 enum mlxsw_sp_port_mall_action_type {
 	MLXSW_SP_PORT_MALL_MIRROR,
 	MLXSW_SP_PORT_MALL_SAMPLE,
@@ -396,16 +378,6 @@ struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev);
 struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
 void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port);
 struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev);
-int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
-			     struct mlxsw_sp_port *to,
-			     enum mlxsw_sp_span_type type,
-			     bool bind);
-void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from,
-			      u8 destination_port,
-			      enum mlxsw_sp_span_type type,
-			      bool bind);
-struct mlxsw_sp_span_entry *
-mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port);
 
 /* spectrum_dcb.c */
 #ifdef CONFIG_MLXSW_SPECTRUM_DCB
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
index 6ca6894125f0..f7e61cecc42b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
@@ -35,6 +35,7 @@
 
 #include "spectrum_acl_flex_actions.h"
 #include "core_acl_flex_actions.h"
+#include "spectrum_span.h"
 
 #define MLXSW_SP_KVDL_ACT_EXT_SIZE 1
 
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
index 7502e53447bd..a1c4b1e63f8d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
@@ -37,122 +37,89 @@
 #include "spectrum_ipip.h"
 
 struct ip_tunnel_parm
-mlxsw_sp_ipip_netdev_parms(const struct net_device *ol_dev)
+mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev)
 {
 	struct ip_tunnel *tun = netdev_priv(ol_dev);
 
 	return tun->parms;
 }
 
-static bool mlxsw_sp_ipip_parms_has_ikey(struct ip_tunnel_parm parms)
+static bool mlxsw_sp_ipip_parms4_has_ikey(struct ip_tunnel_parm parms)
 {
 	return !!(parms.i_flags & TUNNEL_KEY);
 }
 
-static bool mlxsw_sp_ipip_parms_has_okey(struct ip_tunnel_parm parms)
+static bool mlxsw_sp_ipip_parms4_has_okey(struct ip_tunnel_parm parms)
 {
 	return !!(parms.o_flags & TUNNEL_KEY);
 }
 
-static u32 mlxsw_sp_ipip_parms_ikey(struct ip_tunnel_parm parms)
+static u32 mlxsw_sp_ipip_parms4_ikey(struct ip_tunnel_parm parms)
 {
-	return mlxsw_sp_ipip_parms_has_ikey(parms) ?
+	return mlxsw_sp_ipip_parms4_has_ikey(parms) ?
 		be32_to_cpu(parms.i_key) : 0;
 }
 
-static u32 mlxsw_sp_ipip_parms_okey(struct ip_tunnel_parm parms)
+static u32 mlxsw_sp_ipip_parms4_okey(struct ip_tunnel_parm parms)
 {
-	return mlxsw_sp_ipip_parms_has_okey(parms) ?
+	return mlxsw_sp_ipip_parms4_has_okey(parms) ?
 		be32_to_cpu(parms.o_key) : 0;
 }
 
-static __be32 mlxsw_sp_ipip_parms_saddr4(struct ip_tunnel_parm parms)
+static union mlxsw_sp_l3addr
+mlxsw_sp_ipip_parms4_saddr(struct ip_tunnel_parm parms)
 {
-	return parms.iph.saddr;
+	return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.saddr };
 }
 
 static union mlxsw_sp_l3addr
-mlxsw_sp_ipip_parms_saddr(enum mlxsw_sp_l3proto proto,
-			  struct ip_tunnel_parm parms)
+mlxsw_sp_ipip_parms4_daddr(struct ip_tunnel_parm parms)
 {
-	switch (proto) {
-	case MLXSW_SP_L3_PROTO_IPV4:
-		return (union mlxsw_sp_l3addr) {
-			.addr4 = mlxsw_sp_ipip_parms_saddr4(parms),
-		};
-	case MLXSW_SP_L3_PROTO_IPV6:
-		break;
-	}
-
-	WARN_ON(1);
-	return (union mlxsw_sp_l3addr) {
-		.addr4 = 0,
-	};
+	return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.daddr };
 }
 
-static __be32 mlxsw_sp_ipip_parms_daddr4(struct ip_tunnel_parm parms)
+union mlxsw_sp_l3addr
+mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
+			   const struct net_device *ol_dev)
 {
-	return parms.iph.daddr;
-}
+	struct ip_tunnel_parm parms4;
 
-static union mlxsw_sp_l3addr
-mlxsw_sp_ipip_parms_daddr(enum mlxsw_sp_l3proto proto,
-			  struct ip_tunnel_parm parms)
-{
 	switch (proto) {
 	case MLXSW_SP_L3_PROTO_IPV4:
-		return (union mlxsw_sp_l3addr) {
-			.addr4 = mlxsw_sp_ipip_parms_daddr4(parms),
-		};
+		parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
+		return mlxsw_sp_ipip_parms4_saddr(parms4);
 	case MLXSW_SP_L3_PROTO_IPV6:
 		break;
 	}
 
 	WARN_ON(1);
-	return (union mlxsw_sp_l3addr) {
-		.addr4 = 0,
-	};
-}
-
-static bool mlxsw_sp_ipip_netdev_has_ikey(const struct net_device *ol_dev)
-{
-	return mlxsw_sp_ipip_parms_has_ikey(mlxsw_sp_ipip_netdev_parms(ol_dev));
-}
-
-static bool mlxsw_sp_ipip_netdev_has_okey(const struct net_device *ol_dev)
-{
-	return mlxsw_sp_ipip_parms_has_okey(mlxsw_sp_ipip_netdev_parms(ol_dev));
+	return (union mlxsw_sp_l3addr) {0};
 }
 
-static u32 mlxsw_sp_ipip_netdev_ikey(const struct net_device *ol_dev)
+static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev)
 {
-	return mlxsw_sp_ipip_parms_ikey(mlxsw_sp_ipip_netdev_parms(ol_dev));
-}
 
-static u32 mlxsw_sp_ipip_netdev_okey(const struct net_device *ol_dev)
-{
-	return mlxsw_sp_ipip_parms_okey(mlxsw_sp_ipip_netdev_parms(ol_dev));
-}
+	struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 
-union mlxsw_sp_l3addr
-mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
-			   const struct net_device *ol_dev)
-{
-	return mlxsw_sp_ipip_parms_saddr(proto,
-					 mlxsw_sp_ipip_netdev_parms(ol_dev));
-}
-
-static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev)
-{
-	return mlxsw_sp_ipip_parms_daddr4(mlxsw_sp_ipip_netdev_parms(ol_dev));
+	return mlxsw_sp_ipip_parms4_daddr(parms4).addr4;
 }
 
 static union mlxsw_sp_l3addr
 mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
 			   const struct net_device *ol_dev)
 {
-	return mlxsw_sp_ipip_parms_daddr(proto,
-					 mlxsw_sp_ipip_netdev_parms(ol_dev));
+	struct ip_tunnel_parm parms4;
+
+	switch (proto) {
+	case MLXSW_SP_L3_PROTO_IPV4:
+		parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
+		return mlxsw_sp_ipip_parms4_daddr(parms4);
+	case MLXSW_SP_L3_PROTO_IPV6:
+		break;
+	}
+
+	WARN_ON(1);
+	return (union mlxsw_sp_l3addr) {0};
 }
 
 static int
@@ -176,12 +143,17 @@ mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp *mlxsw_sp,
 				     u32 tunnel_index,
 				     struct mlxsw_sp_ipip_entry *ipip_entry)
 {
-	bool has_ikey = mlxsw_sp_ipip_netdev_has_ikey(ipip_entry->ol_dev);
 	u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);
-	u32 ikey = mlxsw_sp_ipip_netdev_ikey(ipip_entry->ol_dev);
 	char rtdp_pl[MLXSW_REG_RTDP_LEN];
+	struct ip_tunnel_parm parms;
 	unsigned int type_check;
+	bool has_ikey;
 	u32 daddr4;
+	u32 ikey;
+
+	parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev);
+	has_ikey = mlxsw_sp_ipip_parms4_has_ikey(parms);
+	ikey = mlxsw_sp_ipip_parms4_ikey(parms);
 
 	mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
 
@@ -273,14 +245,15 @@ static struct mlxsw_sp_rif_ipip_lb_config
 mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp,
 				      const struct net_device *ol_dev)
 {
+	struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev);
 	enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
 
-	lb_ipipt = mlxsw_sp_ipip_netdev_has_okey(ol_dev) ?
+	lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(parms) ?
 		MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP :
 		MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;
 	return (struct mlxsw_sp_rif_ipip_lb_config){
 		.lb_ipipt = lb_ipipt,
-		.okey = mlxsw_sp_ipip_netdev_okey(ol_dev),
+		.okey = mlxsw_sp_ipip_parms4_okey(parms),
 		.ul_protocol = MLXSW_SP_L3_PROTO_IPV4,
 		.saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
 						    ol_dev),
@@ -300,16 +273,12 @@ mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
 	bool update_nhs = false;
 	int err = 0;
 
-	new_parms = mlxsw_sp_ipip_netdev_parms(ipip_entry->ol_dev);
+	new_parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev);
 
-	new_saddr = mlxsw_sp_ipip_parms_saddr(MLXSW_SP_L3_PROTO_IPV4,
-					      new_parms);
-	old_saddr = mlxsw_sp_ipip_parms_saddr(MLXSW_SP_L3_PROTO_IPV4,
-					      ipip_entry->parms);
-	new_daddr = mlxsw_sp_ipip_parms_daddr(MLXSW_SP_L3_PROTO_IPV4,
-					      new_parms);
-	old_daddr = mlxsw_sp_ipip_parms_daddr(MLXSW_SP_L3_PROTO_IPV4,
-					      ipip_entry->parms);
+	new_saddr = mlxsw_sp_ipip_parms4_saddr(new_parms);
+	old_saddr = mlxsw_sp_ipip_parms4_saddr(ipip_entry->parms4);
+	new_daddr = mlxsw_sp_ipip_parms4_daddr(new_parms);
+	old_daddr = mlxsw_sp_ipip_parms4_daddr(ipip_entry->parms4);
 
 	if (!mlxsw_sp_l3addr_eq(&new_saddr, &old_saddr)) {
 		u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
@@ -326,14 +295,14 @@ mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
 		}
 
 		update_tunnel = true;
-	} else if ((mlxsw_sp_ipip_parms_okey(ipip_entry->parms) !=
-		    mlxsw_sp_ipip_parms_okey(new_parms)) ||
-		   ipip_entry->parms.link != new_parms.link) {
+	} else if ((mlxsw_sp_ipip_parms4_okey(ipip_entry->parms4) !=
+		    mlxsw_sp_ipip_parms4_okey(new_parms)) ||
+		   ipip_entry->parms4.link != new_parms.link) {
 		update_tunnel = true;
 	} else if (!mlxsw_sp_l3addr_eq(&new_daddr, &old_daddr)) {
 		update_nhs = true;
-	} else if (mlxsw_sp_ipip_parms_ikey(ipip_entry->parms) !=
-		   mlxsw_sp_ipip_parms_ikey(new_parms)) {
+	} else if (mlxsw_sp_ipip_parms4_ikey(ipip_entry->parms4) !=
+		   mlxsw_sp_ipip_parms4_ikey(new_parms)) {
 		update_decap = true;
 	}
 
@@ -350,7 +319,7 @@ mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp,
 							  false, false, false,
 							  extack);
 
-	ipip_entry->parms = new_parms;
+	ipip_entry->parms4 = new_parms;
 	return err;
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
index 04b08d9d76e9..a4ff5737eccc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
@@ -37,9 +37,10 @@
 
 #include "spectrum_router.h"
 #include <net/ip_fib.h>
+#include <linux/if_tunnel.h>
 
 struct ip_tunnel_parm
-mlxsw_sp_ipip_netdev_parms(const struct net_device *ol_dev);
+mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev);
 
 union mlxsw_sp_l3addr
 mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
@@ -56,7 +57,9 @@ struct mlxsw_sp_ipip_entry {
 	struct mlxsw_sp_rif_ipip_lb *ol_lb;
 	struct mlxsw_sp_fib_entry *decap_fib_entry;
 	struct list_head ipip_list_node;
-	struct ip_tunnel_parm parms;
+	union {
+		struct ip_tunnel_parm parms4;
+	};
 };
 
 struct mlxsw_sp_ipip_ops {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index f0b25baba09a..05146970c19c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -1,10 +1,10 @@
 /*
  * drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
- * Copyright (c) 2016-2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
  * Copyright (c) 2016 Ido Schimmel <idosch@mellanox.com>
  * Copyright (c) 2016 Yotam Gigi <yotamg@mellanox.com>
- * Copyright (c) 2017 Petr Machata <petrm@mellanox.com>
+ * Copyright (c) 2017-2018 Petr Machata <petrm@mellanox.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -788,37 +788,41 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
 					      u32 tb_id,
 					      struct netlink_ext_ack *extack)
 {
+	struct mlxsw_sp_mr_table *mr4_table;
+	struct mlxsw_sp_fib *fib4;
+	struct mlxsw_sp_fib *fib6;
 	struct mlxsw_sp_vr *vr;
 	int err;
 
 	vr = mlxsw_sp_vr_find_unused(mlxsw_sp);
 	if (!vr) {
-		NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers");
+		NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported virtual routers");
 		return ERR_PTR(-EBUSY);
 	}
-	vr->fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
-	if (IS_ERR(vr->fib4))
-		return ERR_CAST(vr->fib4);
-	vr->fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
-	if (IS_ERR(vr->fib6)) {
-		err = PTR_ERR(vr->fib6);
+	fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
+	if (IS_ERR(fib4))
+		return ERR_CAST(fib4);
+	fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
+	if (IS_ERR(fib6)) {
+		err = PTR_ERR(fib6);
 		goto err_fib6_create;
 	}
-	vr->mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
-						 MLXSW_SP_L3_PROTO_IPV4);
-	if (IS_ERR(vr->mr4_table)) {
-		err = PTR_ERR(vr->mr4_table);
+	mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
+					     MLXSW_SP_L3_PROTO_IPV4);
+	if (IS_ERR(mr4_table)) {
+		err = PTR_ERR(mr4_table);
 		goto err_mr_table_create;
 	}
+	vr->fib4 = fib4;
+	vr->fib6 = fib6;
+	vr->mr4_table = mr4_table;
 	vr->tb_id = tb_id;
 	return vr;
 
 err_mr_table_create:
-	mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
-	vr->fib6 = NULL;
+	mlxsw_sp_fib_destroy(mlxsw_sp, fib6);
 err_fib6_create:
-	mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
-	vr->fib4 = NULL;
+	mlxsw_sp_fib_destroy(mlxsw_sp, fib4);
 	return ERR_PTR(err);
 }
 
@@ -1020,9 +1024,11 @@ mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
 			  enum mlxsw_sp_ipip_type ipipt,
 			  struct net_device *ol_dev)
 {
+	const struct mlxsw_sp_ipip_ops *ipip_ops;
 	struct mlxsw_sp_ipip_entry *ipip_entry;
 	struct mlxsw_sp_ipip_entry *ret = NULL;
 
+	ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
 	ipip_entry = kzalloc(sizeof(*ipip_entry), GFP_KERNEL);
 	if (!ipip_entry)
 		return ERR_PTR(-ENOMEM);
@@ -1036,7 +1042,15 @@ mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
 
 	ipip_entry->ipipt = ipipt;
 	ipip_entry->ol_dev = ol_dev;
-	ipip_entry->parms = mlxsw_sp_ipip_netdev_parms(ol_dev);
+
+	switch (ipip_ops->ul_proto) {
+	case MLXSW_SP_L3_PROTO_IPV4:
+		ipip_entry->parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
+		break;
+	case MLXSW_SP_L3_PROTO_IPV6:
+		WARN_ON(1);
+		break;
+	}
 
 	return ipip_entry;
 
@@ -3790,6 +3804,9 @@ mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
 	struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
 	int i;
 
+	if (!list_is_singular(&nh_grp->fib_list))
+		return;
+
 	for (i = 0; i < nh_grp->count; i++) {
 		struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
 
@@ -5786,7 +5803,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event,
 	}
 
 	if (err < 0)
-		NL_SET_ERR_MSG(extack, "spectrum: FIB rules not supported. Aborting offload");
+		NL_SET_ERR_MSG_MOD(extack, "FIB rules not supported. Aborting offload");
 
 	return err;
 }
@@ -6025,7 +6042,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
 
 	err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index);
 	if (err) {
-		NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported router interfaces");
+		NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces");
 		goto err_rif_index_alloc;
 	}
 
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
new file mode 100644
index 000000000000..c3bec37d71ed
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -0,0 +1,356 @@
+/*
+ * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.c
+ * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/list.h>
+
+#include "spectrum.h"
+#include "spectrum_span.h"
+
+int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
+{
+	int i;
+
+	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN))
+		return -EIO;
+
+	mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core,
+							  MAX_SPAN);
+	mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count,
+					 sizeof(struct mlxsw_sp_span_entry),
+					 GFP_KERNEL);
+	if (!mlxsw_sp->span.entries)
+		return -ENOMEM;
+
+	for (i = 0; i < mlxsw_sp->span.entries_count; i++)
+		INIT_LIST_HEAD(&mlxsw_sp->span.entries[i].bound_ports_list);
+
+	return 0;
+}
+
+void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
+{
+	int i;
+
+	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
+		struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
+
+		WARN_ON_ONCE(!list_empty(&curr->bound_ports_list));
+	}
+	kfree(mlxsw_sp->span.entries);
+}
+
+static struct mlxsw_sp_span_entry *
+mlxsw_sp_span_entry_create(struct mlxsw_sp_port *port)
+{
+	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
+	struct mlxsw_sp_span_entry *span_entry;
+	char mpat_pl[MLXSW_REG_MPAT_LEN];
+	u8 local_port = port->local_port;
+	int index;
+	int i;
+	int err;
+
+	/* find a free entry to use */
+	index = -1;
+	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
+		if (!mlxsw_sp->span.entries[i].ref_count) {
+			index = i;
+			span_entry = &mlxsw_sp->span.entries[i];
+			break;
+		}
+	}
+	if (index < 0)
+		return NULL;
+
+	/* create a new port analayzer entry for local_port */
+	mlxsw_reg_mpat_pack(mpat_pl, index, local_port, true);
+	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
+	if (err)
+		return NULL;
+
+	span_entry->id = index;
+	span_entry->ref_count = 1;
+	span_entry->local_port = local_port;
+	return span_entry;
+}
+
+static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp,
+					struct mlxsw_sp_span_entry *span_entry)
+{
+	u8 local_port = span_entry->local_port;
+	char mpat_pl[MLXSW_REG_MPAT_LEN];
+	int pa_id = span_entry->id;
+
+	mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false);
+	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
+}
+
+struct mlxsw_sp_span_entry *
+mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port)
+{
+	int i;
+
+	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
+		struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
+
+		if (curr->ref_count && curr->local_port == local_port)
+			return curr;
+	}
+	return NULL;
+}
+
+static struct mlxsw_sp_span_entry *
+mlxsw_sp_span_entry_get(struct mlxsw_sp_port *port)
+{
+	struct mlxsw_sp_span_entry *span_entry;
+
+	span_entry = mlxsw_sp_span_entry_find(port->mlxsw_sp,
+					      port->local_port);
+	if (span_entry) {
+		/* Already exists, just take a reference */
+		span_entry->ref_count++;
+		return span_entry;
+	}
+
+	return mlxsw_sp_span_entry_create(port);
+}
+
+static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
+				   struct mlxsw_sp_span_entry *span_entry)
+{
+	WARN_ON(!span_entry->ref_count);
+	if (--span_entry->ref_count == 0)
+		mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry);
+	return 0;
+}
+
+static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port)
+{
+	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
+	struct mlxsw_sp_span_inspected_port *p;
+	int i;
+
+	for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
+		struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
+
+		list_for_each_entry(p, &curr->bound_ports_list, list)
+			if (p->local_port == port->local_port &&
+			    p->type == MLXSW_SP_SPAN_EGRESS)
+				return true;
+	}
+
+	return false;
+}
+
+static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp,
+					 int mtu)
+{
+	return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1;
+}
+
+int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
+{
+	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
+	char sbib_pl[MLXSW_REG_SBIB_LEN];
+	int err;
+
+	/* If port is egress mirrored, the shared buffer size should be
+	 * updated according to the mtu value
+	 */
+	if (mlxsw_sp_span_is_egress_mirror(port)) {
+		u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu);
+
+		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
+		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
+		if (err) {
+			netdev_err(port->dev, "Could not update shared buffer for mirroring\n");
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static struct mlxsw_sp_span_inspected_port *
+mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port,
+				    struct mlxsw_sp_span_entry *span_entry)
+{
+	struct mlxsw_sp_span_inspected_port *p;
+
+	list_for_each_entry(p, &span_entry->bound_ports_list, list)
+		if (port->local_port == p->local_port)
+			return p;
+	return NULL;
+}
+
+static int
+mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port,
+				  struct mlxsw_sp_span_entry *span_entry,
+				  enum mlxsw_sp_span_type type,
+				  bool bind)
+{
+	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
+	char mpar_pl[MLXSW_REG_MPAR_LEN];
+	int pa_id = span_entry->id;
+
+	/* bind the port to the SPAN entry */
+	mlxsw_reg_mpar_pack(mpar_pl, port->local_port,
+			    (enum mlxsw_reg_mpar_i_e)type, bind, pa_id);
+	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl);
+}
+
+static int
+mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port,
+				 struct mlxsw_sp_span_entry *span_entry,
+				 enum mlxsw_sp_span_type type,
+				 bool bind)
+{
+	struct mlxsw_sp_span_inspected_port *inspected_port;
+	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
+	char sbib_pl[MLXSW_REG_SBIB_LEN];
+	int err;
+
+	/* if it is an egress SPAN, bind a shared buffer to it */
+	if (type == MLXSW_SP_SPAN_EGRESS) {
+		u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp,
+							     port->dev->mtu);
+
+		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
+		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
+		if (err) {
+			netdev_err(port->dev, "Could not create shared buffer for mirroring\n");
+			return err;
+		}
+	}
+
+	if (bind) {
+		err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
+							true);
+		if (err)
+			goto err_port_bind;
+	}
+
+	inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL);
+	if (!inspected_port) {
+		err = -ENOMEM;
+		goto err_inspected_port_alloc;
+	}
+	inspected_port->local_port = port->local_port;
+	inspected_port->type = type;
+	list_add_tail(&inspected_port->list, &span_entry->bound_ports_list);
+
+	return 0;
+
+err_inspected_port_alloc:
+	if (bind)
+		mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
+						  false);
+err_port_bind:
+	if (type == MLXSW_SP_SPAN_EGRESS) {
+		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
+		mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
+	}
+	return err;
+}
+
+static void
+mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
+				 struct mlxsw_sp_span_entry *span_entry,
+				 enum mlxsw_sp_span_type type,
+				 bool bind)
+{
+	struct mlxsw_sp_span_inspected_port *inspected_port;
+	struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
+	char sbib_pl[MLXSW_REG_SBIB_LEN];
+
+	inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry);
+	if (!inspected_port)
+		return;
+
+	if (bind)
+		mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
+						  false);
+	/* remove the SBIB buffer if it was egress SPAN */
+	if (type == MLXSW_SP_SPAN_EGRESS) {
+		mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
+		mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
+	}
+
+	mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
+
+	list_del(&inspected_port->list);
+	kfree(inspected_port);
+}
+
+int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
+			     struct mlxsw_sp_port *to,
+			     enum mlxsw_sp_span_type type, bool bind)
+{
+	struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp;
+	struct mlxsw_sp_span_entry *span_entry;
+	int err;
+
+	span_entry = mlxsw_sp_span_entry_get(to);
+	if (!span_entry)
+		return -ENOENT;
+
+	netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n",
+		   span_entry->id);
+
+	err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind);
+	if (err)
+		goto err_port_bind;
+
+	return 0;
+
+err_port_bind:
+	mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
+	return err;
+}
+
+void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port,
+			      enum mlxsw_sp_span_type type, bool bind)
+{
+	struct mlxsw_sp_span_entry *span_entry;
+
+	span_entry = mlxsw_sp_span_entry_find(from->mlxsw_sp,
+					      destination_port);
+	if (!span_entry) {
+		netdev_err(from->dev, "no span entry found\n");
+		return;
+	}
+
+	netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n",
+		   span_entry->id);
+	mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
new file mode 100644
index 000000000000..069050e385ff
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
@@ -0,0 +1,73 @@
+/*
+ * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.h
+ * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MLXSW_SPECTRUM_SPAN_H
+#define _MLXSW_SPECTRUM_SPAN_H
+
+#include <linux/types.h>
+
+struct mlxsw_sp;
+struct mlxsw_sp_port;
+
+enum mlxsw_sp_span_type {
+	MLXSW_SP_SPAN_EGRESS,
+	MLXSW_SP_SPAN_INGRESS
+};
+
+struct mlxsw_sp_span_inspected_port {
+	struct list_head list;
+	enum mlxsw_sp_span_type type;
+	u8 local_port;
+};
+
+struct mlxsw_sp_span_entry {
+	u8 local_port;
+	struct list_head bound_ports_list;
+	int ref_count;
+	int id;
+};
+
+int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp);
+
+int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
+			     struct mlxsw_sp_port *to,
+			     enum mlxsw_sp_span_type type, bool bind);
+void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port,
+			      enum mlxsw_sp_span_type type, bool bind);
+struct mlxsw_sp_span_entry *
+mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port);
+
+int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu);
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 593ad31be749..f9f53af04fe1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -1819,7 +1819,7 @@ mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device,
 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
 
 	if (is_vlan_dev(bridge_port->dev)) {
-		NL_SET_ERR_MSG(extack, "spectrum: Can not enslave a VLAN device to a VLAN-aware bridge");
+		NL_SET_ERR_MSG_MOD(extack, "Can not enslave a VLAN device to a VLAN-aware bridge");
 		return -EINVAL;
 	}
 
@@ -1885,7 +1885,7 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
 	u16 vid;
 
 	if (!is_vlan_dev(bridge_port->dev)) {
-		NL_SET_ERR_MSG(extack, "spectrum: Only VLAN devices can be enslaved to a VLAN-unaware bridge");
+		NL_SET_ERR_MSG_MOD(extack, "Only VLAN devices can be enslaved to a VLAN-unaware bridge");
 		return -EINVAL;
 	}
 	vid = vlan_dev_vlan_id(bridge_port->dev);
@@ -1895,7 +1895,7 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
 		return -EINVAL;
 
 	if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) {
-		NL_SET_ERR_MSG(extack, "spectrum: Can not bridge VLAN uppers of the same port");
+		NL_SET_ERR_MSG_MOD(extack, "Can not bridge VLAN uppers of the same port");
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
index adfe474c2cf0..28c1cd5b823b 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
@@ -61,6 +61,13 @@
 #define NFP_FLOWER_MASK_MPLS_BOS	BIT(8)
 #define NFP_FLOWER_MASK_MPLS_Q		BIT(0)
 
+/* Compressed HW representation of TCP Flags */
+#define NFP_FL_TCP_FLAG_URG		BIT(4)
+#define NFP_FL_TCP_FLAG_PSH		BIT(3)
+#define NFP_FL_TCP_FLAG_RST		BIT(2)
+#define NFP_FL_TCP_FLAG_SYN		BIT(1)
+#define NFP_FL_TCP_FLAG_FIN		BIT(0)
+
 #define NFP_FL_SC_ACT_DROP		0x80000000
 #define NFP_FL_SC_ACT_USER		0x7D000000
 #define NFP_FL_SC_ACT_POPV		0x6A000000
@@ -257,7 +264,7 @@ struct nfp_flower_tp_ports {
  *    3                   2                   1
  *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |    DSCP   |ECN|   protocol    |           reserved            |
+ * |    DSCP   |ECN|   protocol    |      ttl      |     flags     |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |                        ipv4_addr_src                          |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -268,7 +275,7 @@ struct nfp_flower_ipv4 {
 	u8 tos;
 	u8 proto;
 	u8 ttl;
-	u8 reserved;
+	u8 flags;
 	__be32 ipv4_src;
 	__be32 ipv4_dst;
 };
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 332ff0fdc038..c5cebf6fb1d3 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -41,6 +41,7 @@
 #include <linux/time64.h>
 #include <linux/types.h>
 #include <net/pkt_cls.h>
+#include <net/tcp.h>
 #include <linux/workqueue.h>
 
 struct net_device;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c
index 37c2ecae2a7a..b3bc8279d4fb 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/match.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/match.c
@@ -181,6 +181,26 @@ nfp_flower_compile_ipv4(struct nfp_flower_ipv4 *frame,
 		frame->tos = flow_ip->tos;
 		frame->ttl = flow_ip->ttl;
 	}
+
+	if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_TCP)) {
+		struct flow_dissector_key_tcp *tcp;
+		u32 tcp_flags;
+
+		tcp = skb_flow_dissector_target(flow->dissector,
+						FLOW_DISSECTOR_KEY_TCP, target);
+		tcp_flags = be16_to_cpu(tcp->flags);
+
+		if (tcp_flags & TCPHDR_FIN)
+			frame->flags |= NFP_FL_TCP_FLAG_FIN;
+		if (tcp_flags & TCPHDR_SYN)
+			frame->flags |= NFP_FL_TCP_FLAG_SYN;
+		if (tcp_flags & TCPHDR_RST)
+			frame->flags |= NFP_FL_TCP_FLAG_RST;
+		if (tcp_flags & TCPHDR_PSH)
+			frame->flags |= NFP_FL_TCP_FLAG_PSH;
+		if (tcp_flags & TCPHDR_URG)
+			frame->flags |= NFP_FL_TCP_FLAG_URG;
+	}
 }
 
 static void
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index eb5c13dea8f5..f3586c519805 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -44,11 +44,16 @@
 #include "../nfp_net.h"
 #include "../nfp_port.h"
 
+#define NFP_FLOWER_SUPPORTED_TCPFLAGS \
+	(TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST | \
+	 TCPHDR_PSH | TCPHDR_URG)
+
 #define NFP_FLOWER_WHITELIST_DISSECTOR \
 	(BIT(FLOW_DISSECTOR_KEY_CONTROL) | \
 	 BIT(FLOW_DISSECTOR_KEY_BASIC) | \
 	 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | \
 	 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | \
+	 BIT(FLOW_DISSECTOR_KEY_TCP) | \
 	 BIT(FLOW_DISSECTOR_KEY_PORTS) | \
 	 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | \
 	 BIT(FLOW_DISSECTOR_KEY_VLAN) | \
@@ -288,6 +293,35 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
 		}
 	}
 
+	if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_TCP)) {
+		struct flow_dissector_key_tcp *tcp;
+		u32 tcp_flags;
+
+		tcp = skb_flow_dissector_target(flow->dissector,
+						FLOW_DISSECTOR_KEY_TCP,
+						flow->key);
+		tcp_flags = be16_to_cpu(tcp->flags);
+
+		if (tcp_flags & ~NFP_FLOWER_SUPPORTED_TCPFLAGS)
+			return -EOPNOTSUPP;
+
+		/* We only support PSH and URG flags when either
+		 * FIN, SYN or RST is present as well.
+		 */
+		if ((tcp_flags & (TCPHDR_PSH | TCPHDR_URG)) &&
+		    !(tcp_flags & (TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST)))
+			return -EOPNOTSUPP;
+
+		/* We need to store TCP flags in the IPv4 key space, thus
+		 * we need to ensure we include a IPv4 key layer if we have
+		 * not done so already.
+		 */
+		if (!(key_layer & NFP_FLOWER_LAYER_IPV4)) {
+			key_layer |= NFP_FLOWER_LAYER_IPV4;
+			key_size += sizeof(struct nfp_flower_ipv4);
+		}
+	}
+
 	ret_key_ls->key_layer = key_layer;
 	ret_key_ls->key_layer_two = key_layer_two;
 	ret_key_ls->key_size = key_size;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
index 4499a7333078..bb63c115537d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
+ * Copyright (C) 2015-2018 Netronome Systems, Inc.
  *
  * This software is dual licensed under the GNU General License Version 2,
  * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -51,12 +51,12 @@
  * The configuration BAR is 8K in size, but due to
  * THB-350, 32k needs to be reserved.
  */
-#define NFP_NET_CFG_BAR_SZ              (32 * 1024)
+#define NFP_NET_CFG_BAR_SZ		(32 * 1024)
 
 /**
  * Offset in Freelist buffer where packet starts on RX
  */
-#define NFP_NET_RX_OFFSET               32
+#define NFP_NET_RX_OFFSET		32
 
 /**
  * LSO parameters
@@ -75,65 +75,65 @@
 #define NFP_NET_META_PORTID		5
 #define NFP_NET_META_CSUM		6 /* checksum complete type */
 
-#define	NFP_META_PORT_ID_CTRL		~0U
+#define NFP_META_PORT_ID_CTRL		~0U
 
 /**
  * Hash type pre-pended when a RSS hash was computed
  */
-#define NFP_NET_RSS_NONE                0
-#define NFP_NET_RSS_IPV4                1
-#define NFP_NET_RSS_IPV6                2
-#define NFP_NET_RSS_IPV6_EX             3
-#define NFP_NET_RSS_IPV4_TCP            4
-#define NFP_NET_RSS_IPV6_TCP            5
-#define NFP_NET_RSS_IPV6_EX_TCP         6
-#define NFP_NET_RSS_IPV4_UDP            7
-#define NFP_NET_RSS_IPV6_UDP            8
-#define NFP_NET_RSS_IPV6_EX_UDP         9
+#define NFP_NET_RSS_NONE		0
+#define NFP_NET_RSS_IPV4		1
+#define NFP_NET_RSS_IPV6		2
+#define NFP_NET_RSS_IPV6_EX		3
+#define NFP_NET_RSS_IPV4_TCP		4
+#define NFP_NET_RSS_IPV6_TCP		5
+#define NFP_NET_RSS_IPV6_EX_TCP		6
+#define NFP_NET_RSS_IPV4_UDP		7
+#define NFP_NET_RSS_IPV6_UDP		8
+#define NFP_NET_RSS_IPV6_EX_UDP		9
 
 /**
  * Ring counts
- * %NFP_NET_TXR_MAX:         Maximum number of TX rings
- * %NFP_NET_RXR_MAX:         Maximum number of RX rings
+ * %NFP_NET_TXR_MAX:	     Maximum number of TX rings
+ * %NFP_NET_RXR_MAX:	     Maximum number of RX rings
  */
-#define NFP_NET_TXR_MAX                 64
-#define NFP_NET_RXR_MAX                 64
+#define NFP_NET_TXR_MAX			64
+#define NFP_NET_RXR_MAX			64
 
 /**
  * Read/Write config words (0x0000 - 0x002c)
- * %NFP_NET_CFG_CTRL:        Global control
+ * %NFP_NET_CFG_CTRL:	     Global control
  * %NFP_NET_CFG_UPDATE:      Indicate which fields are updated
  * %NFP_NET_CFG_TXRS_ENABLE: Bitmask of enabled TX rings
  * %NFP_NET_CFG_RXRS_ENABLE: Bitmask of enabled RX rings
- * %NFP_NET_CFG_MTU:         Set MTU size
+ * %NFP_NET_CFG_MTU:	     Set MTU size
  * %NFP_NET_CFG_FLBUFSZ:     Set freelist buffer size (must be larger than MTU)
- * %NFP_NET_CFG_EXN:         MSI-X table entry for exceptions
- * %NFP_NET_CFG_LSC:         MSI-X table entry for link state changes
+ * %NFP_NET_CFG_EXN:	     MSI-X table entry for exceptions
+ * %NFP_NET_CFG_LSC:	     MSI-X table entry for link state changes
  * %NFP_NET_CFG_MACADDR:     MAC address
  *
  * TODO:
  * - define Error details in UPDATE
  */
-#define NFP_NET_CFG_CTRL                0x0000
-#define   NFP_NET_CFG_CTRL_ENABLE         (0x1 <<  0) /* Global enable */
-#define   NFP_NET_CFG_CTRL_PROMISC        (0x1 <<  1) /* Enable Promisc mode */
-#define   NFP_NET_CFG_CTRL_L2BC           (0x1 <<  2) /* Allow L2 Broadcast */
-#define   NFP_NET_CFG_CTRL_L2MC           (0x1 <<  3) /* Allow L2 Multicast */
-#define   NFP_NET_CFG_CTRL_RXCSUM         (0x1 <<  4) /* Enable RX Checksum */
-#define   NFP_NET_CFG_CTRL_TXCSUM         (0x1 <<  5) /* Enable TX Checksum */
-#define   NFP_NET_CFG_CTRL_RXVLAN         (0x1 <<  6) /* Enable VLAN strip */
-#define   NFP_NET_CFG_CTRL_TXVLAN         (0x1 <<  7) /* Enable VLAN insert */
-#define   NFP_NET_CFG_CTRL_SCATTER        (0x1 <<  8) /* Scatter DMA */
-#define   NFP_NET_CFG_CTRL_GATHER         (0x1 <<  9) /* Gather DMA */
-#define   NFP_NET_CFG_CTRL_LSO            (0x1 << 10) /* LSO/TSO (version 1) */
+#define NFP_NET_CFG_CTRL		0x0000
+#define   NFP_NET_CFG_CTRL_ENABLE	  (0x1 <<  0) /* Global enable */
+#define   NFP_NET_CFG_CTRL_PROMISC	  (0x1 <<  1) /* Enable Promisc mode */
+#define   NFP_NET_CFG_CTRL_L2BC		  (0x1 <<  2) /* Allow L2 Broadcast */
+#define   NFP_NET_CFG_CTRL_L2MC		  (0x1 <<  3) /* Allow L2 Multicast */
+#define   NFP_NET_CFG_CTRL_RXCSUM	  (0x1 <<  4) /* Enable RX Checksum */
+#define   NFP_NET_CFG_CTRL_TXCSUM	  (0x1 <<  5) /* Enable TX Checksum */
+#define   NFP_NET_CFG_CTRL_RXVLAN	  (0x1 <<  6) /* Enable VLAN strip */
+#define   NFP_NET_CFG_CTRL_TXVLAN	  (0x1 <<  7) /* Enable VLAN insert */
+#define   NFP_NET_CFG_CTRL_SCATTER	  (0x1 <<  8) /* Scatter DMA */
+#define   NFP_NET_CFG_CTRL_GATHER	  (0x1 <<  9) /* Gather DMA */
+#define   NFP_NET_CFG_CTRL_LSO		  (0x1 << 10) /* LSO/TSO (version 1) */
 #define   NFP_NET_CFG_CTRL_CTAG_FILTER	  (0x1 << 11) /* VLAN CTAG filtering */
-#define   NFP_NET_CFG_CTRL_RINGCFG        (0x1 << 16) /* Ring runtime changes */
+#define   NFP_NET_CFG_CTRL_RINGCFG	  (0x1 << 16) /* Ring runtime changes */
 #define   NFP_NET_CFG_CTRL_RSS		  (0x1 << 17) /* RSS (version 1) */
-#define   NFP_NET_CFG_CTRL_IRQMOD         (0x1 << 18) /* Interrupt moderation */
-#define   NFP_NET_CFG_CTRL_RINGPRIO       (0x1 << 19) /* Ring priorities */
-#define   NFP_NET_CFG_CTRL_MSIXAUTO       (0x1 << 20) /* MSI-X auto-masking */
-#define   NFP_NET_CFG_CTRL_TXRWB          (0x1 << 21) /* Write-back of TX ring*/
-#define   NFP_NET_CFG_CTRL_L2SWITCH       (0x1 << 22) /* L2 Switch */
+#define   NFP_NET_CFG_CTRL_IRQMOD	  (0x1 << 18) /* Interrupt moderation */
+#define   NFP_NET_CFG_CTRL_RINGPRIO	  (0x1 << 19) /* Ring priorities */
+#define   NFP_NET_CFG_CTRL_MSIXAUTO	  (0x1 << 20) /* MSI-X auto-masking */
+#define   NFP_NET_CFG_CTRL_TXRWB	  (0x1 << 21) /* Write-back of TX ring*/
+#define   NFP_NET_CFG_CTRL_L2SWITCH	  (0x1 << 22) /* L2 Switch */
 #define   NFP_NET_CFG_CTRL_L2SWITCH_LOCAL (0x1 << 23) /* Switch to local */
 #define   NFP_NET_CFG_CTRL_VXLAN	  (0x1 << 24) /* VXLAN tunnel support */
 #define   NFP_NET_CFG_CTRL_NVGRE	  (0x1 << 25) /* NVGRE tunnel support */
@@ -152,35 +152,35 @@
 #define NFP_NET_CFG_CTRL_CHAIN_META	(NFP_NET_CFG_CTRL_RSS2 | \
 					 NFP_NET_CFG_CTRL_CSUM_COMPLETE)
 
-#define NFP_NET_CFG_UPDATE              0x0004
-#define   NFP_NET_CFG_UPDATE_GEN          (0x1 <<  0) /* General update */
-#define   NFP_NET_CFG_UPDATE_RING         (0x1 <<  1) /* Ring config change */
-#define   NFP_NET_CFG_UPDATE_RSS          (0x1 <<  2) /* RSS config change */
-#define   NFP_NET_CFG_UPDATE_TXRPRIO      (0x1 <<  3) /* TX Ring prio change */
-#define   NFP_NET_CFG_UPDATE_RXRPRIO      (0x1 <<  4) /* RX Ring prio change */
-#define   NFP_NET_CFG_UPDATE_MSIX         (0x1 <<  5) /* MSI-X change */
-#define   NFP_NET_CFG_UPDATE_L2SWITCH     (0x1 <<  6) /* Switch changes */
-#define   NFP_NET_CFG_UPDATE_RESET        (0x1 <<  7) /* Update due to FLR */
-#define   NFP_NET_CFG_UPDATE_IRQMOD       (0x1 <<  8) /* IRQ mod change */
+#define NFP_NET_CFG_UPDATE		0x0004
+#define   NFP_NET_CFG_UPDATE_GEN	  (0x1 <<  0) /* General update */
+#define   NFP_NET_CFG_UPDATE_RING	  (0x1 <<  1) /* Ring config change */
+#define   NFP_NET_CFG_UPDATE_RSS	  (0x1 <<  2) /* RSS config change */
+#define   NFP_NET_CFG_UPDATE_TXRPRIO	  (0x1 <<  3) /* TX Ring prio change */
+#define   NFP_NET_CFG_UPDATE_RXRPRIO	  (0x1 <<  4) /* RX Ring prio change */
+#define   NFP_NET_CFG_UPDATE_MSIX	  (0x1 <<  5) /* MSI-X change */
+#define   NFP_NET_CFG_UPDATE_L2SWITCH	  (0x1 <<  6) /* Switch changes */
+#define   NFP_NET_CFG_UPDATE_RESET	  (0x1 <<  7) /* Update due to FLR */
+#define   NFP_NET_CFG_UPDATE_IRQMOD	  (0x1 <<  8) /* IRQ mod change */
 #define   NFP_NET_CFG_UPDATE_VXLAN	  (0x1 <<  9) /* VXLAN port change */
 #define   NFP_NET_CFG_UPDATE_BPF	  (0x1 << 10) /* BPF program load */
 #define   NFP_NET_CFG_UPDATE_MACADDR	  (0x1 << 11) /* MAC address change */
 #define   NFP_NET_CFG_UPDATE_MBOX	  (0x1 << 12) /* Mailbox update */
 #define   NFP_NET_CFG_UPDATE_VF		  (0x1 << 13) /* VF settings change */
-#define   NFP_NET_CFG_UPDATE_ERR          (0x1 << 31) /* A error occurred */
-#define NFP_NET_CFG_TXRS_ENABLE         0x0008
-#define NFP_NET_CFG_RXRS_ENABLE         0x0010
-#define NFP_NET_CFG_MTU                 0x0018
-#define NFP_NET_CFG_FLBUFSZ             0x001c
-#define NFP_NET_CFG_EXN                 0x001f
-#define NFP_NET_CFG_LSC                 0x0020
-#define NFP_NET_CFG_MACADDR             0x0024
+#define   NFP_NET_CFG_UPDATE_ERR	  (0x1 << 31) /* A error occurred */
+#define NFP_NET_CFG_TXRS_ENABLE		0x0008
+#define NFP_NET_CFG_RXRS_ENABLE		0x0010
+#define NFP_NET_CFG_MTU			0x0018
+#define NFP_NET_CFG_FLBUFSZ		0x001c
+#define NFP_NET_CFG_EXN			0x001f
+#define NFP_NET_CFG_LSC			0x0020
+#define NFP_NET_CFG_MACADDR		0x0024
 
 /**
  * Read-only words (0x0030 - 0x0050):
  * %NFP_NET_CFG_VERSION:     Firmware version number
- * %NFP_NET_CFG_STS:         Status
- * %NFP_NET_CFG_CAP:         Capabilities (same bits as %NFP_NET_CFG_CTRL)
+ * %NFP_NET_CFG_STS:	     Status
+ * %NFP_NET_CFG_CAP:	     Capabilities (same bits as %NFP_NET_CFG_CTRL)
  * %NFP_NET_CFG_MAX_TXRINGS: Maximum number of TX rings
  * %NFP_NET_CFG_MAX_RXRINGS: Maximum number of RX rings
  * %NFP_NET_CFG_MAX_MTU:     Maximum support MTU
@@ -190,37 +190,37 @@
  * TODO:
  * - define more STS bits
  */
-#define NFP_NET_CFG_VERSION             0x0030
+#define NFP_NET_CFG_VERSION		0x0030
 #define   NFP_NET_CFG_VERSION_RESERVED_MASK	(0xff << 24)
 #define   NFP_NET_CFG_VERSION_CLASS_MASK  (0xff << 16)
-#define   NFP_NET_CFG_VERSION_CLASS(x)    (((x) & 0xff) << 16)
+#define   NFP_NET_CFG_VERSION_CLASS(x)	  (((x) & 0xff) << 16)
 #define   NFP_NET_CFG_VERSION_CLASS_GENERIC	0
 #define   NFP_NET_CFG_VERSION_MAJOR_MASK  (0xff <<  8)
-#define   NFP_NET_CFG_VERSION_MAJOR(x)    (((x) & 0xff) <<  8)
+#define   NFP_NET_CFG_VERSION_MAJOR(x)	  (((x) & 0xff) <<  8)
 #define   NFP_NET_CFG_VERSION_MINOR_MASK  (0xff <<  0)
-#define   NFP_NET_CFG_VERSION_MINOR(x)    (((x) & 0xff) <<  0)
-#define NFP_NET_CFG_STS                 0x0034
-#define   NFP_NET_CFG_STS_LINK            (0x1 << 0) /* Link up or down */
+#define   NFP_NET_CFG_VERSION_MINOR(x)	  (((x) & 0xff) <<  0)
+#define NFP_NET_CFG_STS			0x0034
+#define   NFP_NET_CFG_STS_LINK		  (0x1 << 0) /* Link up or down */
 /* Link rate */
 #define   NFP_NET_CFG_STS_LINK_RATE_SHIFT 1
 #define   NFP_NET_CFG_STS_LINK_RATE_MASK  0xF
-#define   NFP_NET_CFG_STS_LINK_RATE       \
+#define   NFP_NET_CFG_STS_LINK_RATE	  \
 	(NFP_NET_CFG_STS_LINK_RATE_MASK << NFP_NET_CFG_STS_LINK_RATE_SHIFT)
 #define   NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED   0
-#define   NFP_NET_CFG_STS_LINK_RATE_UNKNOWN       1
-#define   NFP_NET_CFG_STS_LINK_RATE_1G            2
-#define   NFP_NET_CFG_STS_LINK_RATE_10G           3
-#define   NFP_NET_CFG_STS_LINK_RATE_25G           4
-#define   NFP_NET_CFG_STS_LINK_RATE_40G           5
-#define   NFP_NET_CFG_STS_LINK_RATE_50G           6
-#define   NFP_NET_CFG_STS_LINK_RATE_100G          7
-#define NFP_NET_CFG_CAP                 0x0038
-#define NFP_NET_CFG_MAX_TXRINGS         0x003c
-#define NFP_NET_CFG_MAX_RXRINGS         0x0040
-#define NFP_NET_CFG_MAX_MTU             0x0044
+#define   NFP_NET_CFG_STS_LINK_RATE_UNKNOWN	  1
+#define   NFP_NET_CFG_STS_LINK_RATE_1G		  2
+#define   NFP_NET_CFG_STS_LINK_RATE_10G		  3
+#define   NFP_NET_CFG_STS_LINK_RATE_25G		  4
+#define   NFP_NET_CFG_STS_LINK_RATE_40G		  5
+#define   NFP_NET_CFG_STS_LINK_RATE_50G		  6
+#define   NFP_NET_CFG_STS_LINK_RATE_100G	  7
+#define NFP_NET_CFG_CAP			0x0038
+#define NFP_NET_CFG_MAX_TXRINGS		0x003c
+#define NFP_NET_CFG_MAX_RXRINGS		0x0040
+#define NFP_NET_CFG_MAX_MTU		0x0044
 /* Next two words are being used by VFs for solving THB350 issue */
-#define NFP_NET_CFG_START_TXQ           0x0048
-#define NFP_NET_CFG_START_RXQ           0x004c
+#define NFP_NET_CFG_START_TXQ		0x0048
+#define NFP_NET_CFG_START_RXQ		0x004c
 
 /**
  * Prepend configuration
@@ -280,8 +280,8 @@
 /**
  * 40B reserved for future use (0x0098 - 0x00c0)
  */
-#define NFP_NET_CFG_RESERVED            0x0098
-#define NFP_NET_CFG_RESERVED_SZ         0x0028
+#define NFP_NET_CFG_RESERVED		0x0098
+#define NFP_NET_CFG_RESERVED_SZ		0x0028
 
 /**
  * RSS configuration (0x0100 - 0x01ac):
@@ -290,26 +290,26 @@
  * %NFP_NET_CFG_RSS_KEY:     RSS "secret" key
  * %NFP_NET_CFG_RSS_ITBL:    RSS indirection table
  */
-#define NFP_NET_CFG_RSS_BASE            0x0100
-#define NFP_NET_CFG_RSS_CTRL            NFP_NET_CFG_RSS_BASE
-#define   NFP_NET_CFG_RSS_MASK            (0x7f)
-#define   NFP_NET_CFG_RSS_MASK_of(_x)     ((_x) & 0x7f)
-#define   NFP_NET_CFG_RSS_IPV4            (1 <<  8) /* RSS for IPv4 */
-#define   NFP_NET_CFG_RSS_IPV6            (1 <<  9) /* RSS for IPv6 */
-#define   NFP_NET_CFG_RSS_IPV4_TCP        (1 << 10) /* RSS for IPv4/TCP */
-#define   NFP_NET_CFG_RSS_IPV4_UDP        (1 << 11) /* RSS for IPv4/UDP */
-#define   NFP_NET_CFG_RSS_IPV6_TCP        (1 << 12) /* RSS for IPv6/TCP */
-#define   NFP_NET_CFG_RSS_IPV6_UDP        (1 << 13) /* RSS for IPv6/UDP */
+#define NFP_NET_CFG_RSS_BASE		0x0100
+#define NFP_NET_CFG_RSS_CTRL		NFP_NET_CFG_RSS_BASE
+#define   NFP_NET_CFG_RSS_MASK		  (0x7f)
+#define   NFP_NET_CFG_RSS_MASK_of(_x)	  ((_x) & 0x7f)
+#define   NFP_NET_CFG_RSS_IPV4		  (1 <<  8) /* RSS for IPv4 */
+#define   NFP_NET_CFG_RSS_IPV6		  (1 <<  9) /* RSS for IPv6 */
+#define   NFP_NET_CFG_RSS_IPV4_TCP	  (1 << 10) /* RSS for IPv4/TCP */
+#define   NFP_NET_CFG_RSS_IPV4_UDP	  (1 << 11) /* RSS for IPv4/UDP */
+#define   NFP_NET_CFG_RSS_IPV6_TCP	  (1 << 12) /* RSS for IPv6/TCP */
+#define   NFP_NET_CFG_RSS_IPV6_UDP	  (1 << 13) /* RSS for IPv6/UDP */
 #define   NFP_NET_CFG_RSS_HFUNC		  0xff000000
-#define   NFP_NET_CFG_RSS_TOEPLITZ        (1 << 24) /* Use Toeplitz hash */
+#define   NFP_NET_CFG_RSS_TOEPLITZ	  (1 << 24) /* Use Toeplitz hash */
 #define   NFP_NET_CFG_RSS_XOR		  (1 << 25) /* Use XOR as hash */
 #define   NFP_NET_CFG_RSS_CRC32		  (1 << 26) /* Use CRC32 as hash */
 #define   NFP_NET_CFG_RSS_HFUNCS	  3
-#define NFP_NET_CFG_RSS_KEY             (NFP_NET_CFG_RSS_BASE + 0x4)
-#define NFP_NET_CFG_RSS_KEY_SZ          0x28
-#define NFP_NET_CFG_RSS_ITBL            (NFP_NET_CFG_RSS_BASE + 0x4 + \
+#define NFP_NET_CFG_RSS_KEY		(NFP_NET_CFG_RSS_BASE + 0x4)
+#define NFP_NET_CFG_RSS_KEY_SZ		0x28
+#define NFP_NET_CFG_RSS_ITBL		(NFP_NET_CFG_RSS_BASE + 0x4 + \
 					 NFP_NET_CFG_RSS_KEY_SZ)
-#define NFP_NET_CFG_RSS_ITBL_SZ         0x80
+#define NFP_NET_CFG_RSS_ITBL_SZ		0x80
 
 /**
  * TX ring configuration (0x200 - 0x800)
@@ -321,13 +321,13 @@
  * %NFP_NET_CFG_TXR_PRIO:    Per TX ring priority (1B entries)
  * %NFP_NET_CFG_TXR_IRQ_MOD: Per TX ring interrupt moderation packet
  */
-#define NFP_NET_CFG_TXR_BASE            0x0200
-#define NFP_NET_CFG_TXR_ADDR(_x)        (NFP_NET_CFG_TXR_BASE + ((_x) * 0x8))
-#define NFP_NET_CFG_TXR_WB_ADDR(_x)     (NFP_NET_CFG_TXR_BASE + 0x200 + \
+#define NFP_NET_CFG_TXR_BASE		0x0200
+#define NFP_NET_CFG_TXR_ADDR(_x)	(NFP_NET_CFG_TXR_BASE + ((_x) * 0x8))
+#define NFP_NET_CFG_TXR_WB_ADDR(_x)	(NFP_NET_CFG_TXR_BASE + 0x200 + \
 					 ((_x) * 0x8))
-#define NFP_NET_CFG_TXR_SZ(_x)          (NFP_NET_CFG_TXR_BASE + 0x400 + (_x))
-#define NFP_NET_CFG_TXR_VEC(_x)         (NFP_NET_CFG_TXR_BASE + 0x440 + (_x))
-#define NFP_NET_CFG_TXR_PRIO(_x)        (NFP_NET_CFG_TXR_BASE + 0x480 + (_x))
+#define NFP_NET_CFG_TXR_SZ(_x)		(NFP_NET_CFG_TXR_BASE + 0x400 + (_x))
+#define NFP_NET_CFG_TXR_VEC(_x)		(NFP_NET_CFG_TXR_BASE + 0x440 + (_x))
+#define NFP_NET_CFG_TXR_PRIO(_x)	(NFP_NET_CFG_TXR_BASE + 0x480 + (_x))
 #define NFP_NET_CFG_TXR_IRQ_MOD(_x)	(NFP_NET_CFG_TXR_BASE + 0x500 + \
 					 ((_x) * 0x4))
 
@@ -340,11 +340,11 @@
  * %NFP_NET_CFG_RXR_PRIO:    Per RX ring priority (1B entries)
  * %NFP_NET_CFG_RXR_IRQ_MOD: Per RX ring interrupt moderation (4B entries)
  */
-#define NFP_NET_CFG_RXR_BASE            0x0800
-#define NFP_NET_CFG_RXR_ADDR(_x)        (NFP_NET_CFG_RXR_BASE + ((_x) * 0x8))
-#define NFP_NET_CFG_RXR_SZ(_x)          (NFP_NET_CFG_RXR_BASE + 0x200 + (_x))
-#define NFP_NET_CFG_RXR_VEC(_x)         (NFP_NET_CFG_RXR_BASE + 0x240 + (_x))
-#define NFP_NET_CFG_RXR_PRIO(_x)        (NFP_NET_CFG_RXR_BASE + 0x280 + (_x))
+#define NFP_NET_CFG_RXR_BASE		0x0800
+#define NFP_NET_CFG_RXR_ADDR(_x)	(NFP_NET_CFG_RXR_BASE + ((_x) * 0x8))
+#define NFP_NET_CFG_RXR_SZ(_x)		(NFP_NET_CFG_RXR_BASE + 0x200 + (_x))
+#define NFP_NET_CFG_RXR_VEC(_x)		(NFP_NET_CFG_RXR_BASE + 0x240 + (_x))
+#define NFP_NET_CFG_RXR_PRIO(_x)	(NFP_NET_CFG_RXR_BASE + 0x280 + (_x))
 #define NFP_NET_CFG_RXR_IRQ_MOD(_x)	(NFP_NET_CFG_RXR_BASE + 0x300 + \
 					 ((_x) * 0x4))
 
@@ -358,36 +358,36 @@
  * the MSI-X entry and the host driver must clear the register to
  * re-enable the interrupt.
  */
-#define NFP_NET_CFG_ICR_BASE            0x0c00
-#define NFP_NET_CFG_ICR(_x)             (NFP_NET_CFG_ICR_BASE + (_x))
-#define   NFP_NET_CFG_ICR_UNMASKED      0x0
-#define   NFP_NET_CFG_ICR_RXTX          0x1
-#define   NFP_NET_CFG_ICR_LSC           0x2
+#define NFP_NET_CFG_ICR_BASE		0x0c00
+#define NFP_NET_CFG_ICR(_x)		(NFP_NET_CFG_ICR_BASE + (_x))
+#define   NFP_NET_CFG_ICR_UNMASKED	0x0
+#define   NFP_NET_CFG_ICR_RXTX		0x1
+#define   NFP_NET_CFG_ICR_LSC		0x2
 
 /**
  * General device stats (0x0d00 - 0x0d90)
  * all counters are 64bit.
  */
-#define NFP_NET_CFG_STATS_BASE          0x0d00
-#define NFP_NET_CFG_STATS_RX_DISCARDS   (NFP_NET_CFG_STATS_BASE + 0x00)
-#define NFP_NET_CFG_STATS_RX_ERRORS     (NFP_NET_CFG_STATS_BASE + 0x08)
-#define NFP_NET_CFG_STATS_RX_OCTETS     (NFP_NET_CFG_STATS_BASE + 0x10)
-#define NFP_NET_CFG_STATS_RX_UC_OCTETS  (NFP_NET_CFG_STATS_BASE + 0x18)
-#define NFP_NET_CFG_STATS_RX_MC_OCTETS  (NFP_NET_CFG_STATS_BASE + 0x20)
-#define NFP_NET_CFG_STATS_RX_BC_OCTETS  (NFP_NET_CFG_STATS_BASE + 0x28)
-#define NFP_NET_CFG_STATS_RX_FRAMES     (NFP_NET_CFG_STATS_BASE + 0x30)
-#define NFP_NET_CFG_STATS_RX_MC_FRAMES  (NFP_NET_CFG_STATS_BASE + 0x38)
-#define NFP_NET_CFG_STATS_RX_BC_FRAMES  (NFP_NET_CFG_STATS_BASE + 0x40)
-
-#define NFP_NET_CFG_STATS_TX_DISCARDS   (NFP_NET_CFG_STATS_BASE + 0x48)
-#define NFP_NET_CFG_STATS_TX_ERRORS     (NFP_NET_CFG_STATS_BASE + 0x50)
-#define NFP_NET_CFG_STATS_TX_OCTETS     (NFP_NET_CFG_STATS_BASE + 0x58)
-#define NFP_NET_CFG_STATS_TX_UC_OCTETS  (NFP_NET_CFG_STATS_BASE + 0x60)
-#define NFP_NET_CFG_STATS_TX_MC_OCTETS  (NFP_NET_CFG_STATS_BASE + 0x68)
-#define NFP_NET_CFG_STATS_TX_BC_OCTETS  (NFP_NET_CFG_STATS_BASE + 0x70)
-#define NFP_NET_CFG_STATS_TX_FRAMES     (NFP_NET_CFG_STATS_BASE + 0x78)
-#define NFP_NET_CFG_STATS_TX_MC_FRAMES  (NFP_NET_CFG_STATS_BASE + 0x80)
-#define NFP_NET_CFG_STATS_TX_BC_FRAMES  (NFP_NET_CFG_STATS_BASE + 0x88)
+#define NFP_NET_CFG_STATS_BASE		0x0d00
+#define NFP_NET_CFG_STATS_RX_DISCARDS	(NFP_NET_CFG_STATS_BASE + 0x00)
+#define NFP_NET_CFG_STATS_RX_ERRORS	(NFP_NET_CFG_STATS_BASE + 0x08)
+#define NFP_NET_CFG_STATS_RX_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x10)
+#define NFP_NET_CFG_STATS_RX_UC_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x18)
+#define NFP_NET_CFG_STATS_RX_MC_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x20)
+#define NFP_NET_CFG_STATS_RX_BC_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x28)
+#define NFP_NET_CFG_STATS_RX_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x30)
+#define NFP_NET_CFG_STATS_RX_MC_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x38)
+#define NFP_NET_CFG_STATS_RX_BC_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x40)
+
+#define NFP_NET_CFG_STATS_TX_DISCARDS	(NFP_NET_CFG_STATS_BASE + 0x48)
+#define NFP_NET_CFG_STATS_TX_ERRORS	(NFP_NET_CFG_STATS_BASE + 0x50)
+#define NFP_NET_CFG_STATS_TX_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x58)
+#define NFP_NET_CFG_STATS_TX_UC_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x60)
+#define NFP_NET_CFG_STATS_TX_MC_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x68)
+#define NFP_NET_CFG_STATS_TX_BC_OCTETS	(NFP_NET_CFG_STATS_BASE + 0x70)
+#define NFP_NET_CFG_STATS_TX_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x78)
+#define NFP_NET_CFG_STATS_TX_MC_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x80)
+#define NFP_NET_CFG_STATS_TX_BC_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x88)
 
 #define NFP_NET_CFG_STATS_APP0_FRAMES	(NFP_NET_CFG_STATS_BASE + 0x90)
 #define NFP_NET_CFG_STATS_APP0_BYTES	(NFP_NET_CFG_STATS_BASE + 0x98)
@@ -404,11 +404,11 @@
  * %NFP_NET_CFG_TXR_STATS:   TX ring statistics (Packet and Byte count)
  * %NFP_NET_CFG_RXR_STATS:   RX ring statistics (Packet and Byte count)
  */
-#define NFP_NET_CFG_TXR_STATS_BASE      0x1000
-#define NFP_NET_CFG_TXR_STATS(_x)       (NFP_NET_CFG_TXR_STATS_BASE + \
+#define NFP_NET_CFG_TXR_STATS_BASE	0x1000
+#define NFP_NET_CFG_TXR_STATS(_x)	(NFP_NET_CFG_TXR_STATS_BASE + \
 					 ((_x) * 0x10))
-#define NFP_NET_CFG_RXR_STATS_BASE      0x1400
-#define NFP_NET_CFG_RXR_STATS(_x)       (NFP_NET_CFG_RXR_STATS_BASE + \
+#define NFP_NET_CFG_RXR_STATS_BASE	0x1400
+#define NFP_NET_CFG_RXR_STATS(_x)	(NFP_NET_CFG_RXR_STATS_BASE + \
 					 ((_x) * 0x10))
 
 /**
@@ -444,7 +444,7 @@
  * %NFP_NET_CFG_TLV_TYPE:	Offset of type within the TLV
  * %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV
  * %NFP_NET_CFG_TLV_LENGTH:	Offset of length within the TLV
- * %NFP_NET_CFG_TLV_LENGTH_INC:	TLV length increments
+ * %NFP_NET_CFG_TLV_LENGTH_INC: TLV length increments
  * %NFP_NET_CFG_TLV_VALUE:	Offset of value with the TLV
  *
  * List of simple TLV structures, first one starts at %NFP_NET_CFG_TLV_BASE.
@@ -457,12 +457,12 @@
  * Note that the 4 byte TLV header is not counted in %NFP_NET_CFG_TLV_LENGTH.
  */
 #define NFP_NET_CFG_TLV_TYPE		0x00
-#define   NFP_NET_CFG_TLV_TYPE_REQUIRED	  0x8000
+#define   NFP_NET_CFG_TLV_TYPE_REQUIRED   0x8000
 #define NFP_NET_CFG_TLV_LENGTH		0x02
 #define   NFP_NET_CFG_TLV_LENGTH_INC	  4
 #define NFP_NET_CFG_TLV_VALUE		0x04
 
-#define NFP_NET_CFG_TLV_HEADER_REQUIRED	0x80000000
+#define NFP_NET_CFG_TLV_HEADER_REQUIRED 0x80000000
 #define NFP_NET_CFG_TLV_HEADER_TYPE	0x7fff0000
 #define NFP_NET_CFG_TLV_HEADER_LENGTH	0x0000ffff
 
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 7e7704daf5f1..c4949183eef3 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -43,12 +43,6 @@
 
 /* Local Definitions and Declarations */
 
-struct rmnet_walk_data {
-	struct net_device *real_dev;
-	struct list_head *head;
-	struct rmnet_port *port;
-};
-
 static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
 {
 	return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler;
@@ -112,17 +106,14 @@ static int rmnet_register_real_device(struct net_device *real_dev)
 static void rmnet_unregister_bridge(struct net_device *dev,
 				    struct rmnet_port *port)
 {
-	struct net_device *rmnet_dev, *bridge_dev;
 	struct rmnet_port *bridge_port;
+	struct net_device *bridge_dev;
 
 	if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
 		return;
 
 	/* bridge slave handling */
 	if (!port->nr_rmnet_devs) {
-		rmnet_dev = netdev_master_upper_dev_get_rcu(dev);
-		netdev_upper_dev_unlink(dev, rmnet_dev);
-
 		bridge_dev = port->bridge_ep;
 
 		bridge_port = rmnet_get_port_rtnl(bridge_dev);
@@ -132,9 +123,6 @@ static void rmnet_unregister_bridge(struct net_device *dev,
 		bridge_dev = port->bridge_ep;
 
 		bridge_port = rmnet_get_port_rtnl(bridge_dev);
-		rmnet_dev = netdev_master_upper_dev_get_rcu(bridge_dev);
-		netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
-
 		rmnet_unregister_real_device(bridge_dev, bridge_port);
 	}
 }
@@ -173,10 +161,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 	if (err)
 		goto err1;
 
-	err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL, extack);
-	if (err)
-		goto err2;
-
 	port->rmnet_mode = mode;
 
 	hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
@@ -193,8 +177,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 
 	return 0;
 
-err2:
-	rmnet_vnd_dellink(mux_id, port, ep);
 err1:
 	rmnet_unregister_real_device(real_dev, port);
 err0:
@@ -204,14 +186,13 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 
 static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 {
+	struct rmnet_priv *priv = netdev_priv(dev);
 	struct net_device *real_dev;
 	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
 	u8 mux_id;
 
-	rcu_read_lock();
-	real_dev = netdev_master_upper_dev_get_rcu(dev);
-	rcu_read_unlock();
+	real_dev = priv->real_dev;
 
 	if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
 		return;
@@ -219,7 +200,6 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 	port = rmnet_get_port_rtnl(real_dev);
 
 	mux_id = rmnet_vnd_get_mux(dev);
-	netdev_upper_dev_unlink(dev, real_dev);
 
 	ep = rmnet_get_endpoint(port, mux_id);
 	if (ep) {
@@ -233,30 +213,13 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 	unregister_netdevice_queue(dev, head);
 }
 
-static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data)
-{
-	struct rmnet_walk_data *d = data;
-	struct rmnet_endpoint *ep;
-	u8 mux_id;
-
-	mux_id = rmnet_vnd_get_mux(rmnet_dev);
-	ep = rmnet_get_endpoint(d->port, mux_id);
-	if (ep) {
-		hlist_del_init_rcu(&ep->hlnode);
-		rmnet_vnd_dellink(mux_id, d->port, ep);
-		kfree(ep);
-	}
-	netdev_upper_dev_unlink(rmnet_dev, d->real_dev);
-	unregister_netdevice_queue(rmnet_dev, d->head);
-
-	return 0;
-}
-
 static void rmnet_force_unassociate_device(struct net_device *dev)
 {
 	struct net_device *real_dev = dev;
-	struct rmnet_walk_data d;
+	struct hlist_node *tmp_ep;
+	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
+	unsigned long bkt_ep;
 	LIST_HEAD(list);
 
 	if (!rmnet_is_real_dev_registered(real_dev))
@@ -264,16 +227,19 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
 
 	ASSERT_RTNL();
 
-	d.real_dev = real_dev;
-	d.head = &list;
-
 	port = rmnet_get_port_rtnl(dev);
-	d.port = port;
 
 	rcu_read_lock();
 	rmnet_unregister_bridge(dev, port);
 
-	netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d);
+	hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
+		unregister_netdevice_queue(ep->egress_dev, &list);
+		rmnet_vnd_dellink(ep->mux_id, port, ep);
+
+		hlist_del_init_rcu(&ep->hlnode);
+		kfree(ep);
+	}
+
 	rcu_read_unlock();
 	unregister_netdevice_many(&list);
 
@@ -422,11 +388,6 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
 	if (err)
 		return -EBUSY;
 
-	err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
-					   extack);
-	if (err)
-		return -EINVAL;
-
 	slave_port = rmnet_get_port(slave_dev);
 	slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
 	slave_port->bridge_ep = real_dev;
@@ -449,7 +410,6 @@ int rmnet_del_bridge(struct net_device *rmnet_dev,
 	port->rmnet_mode = RMNET_EPMODE_VND;
 	port->bridge_ep = NULL;
 
-	netdev_upper_dev_unlink(slave_dev, rmnet_dev);
 	slave_port = rmnet_get_port(slave_dev);
 	rmnet_unregister_real_device(slave_dev, slave_port);
 
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
index 6bc328fb88e1..b0dbca070c00 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
@@ -38,6 +38,11 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
 	}
 
 	ep = rmnet_get_endpoint(port, mux_id);
+	if (!ep) {
+		kfree_skb(skb);
+		return RX_HANDLER_CONSUMED;
+	}
+
 	vnd = ep->egress_dev;
 
 	ip_family = cmd->flow_control.ip_family;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 570a227acdd8..346d310914df 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -121,7 +121,7 @@ static void rmnet_get_stats64(struct net_device *dev,
 	memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats));
 
 	for_each_possible_cpu(cpu) {
-		pcpu_ptr = this_cpu_ptr(priv->pcpu_stats);
+		pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu);
 
 		do {
 			start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp);
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 96a27b00c90e..b81f4faf7b10 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1018,6 +1018,7 @@ struct ravb_private {
 	u32 dirty_rx[NUM_RX_QUEUE];	/* Producer ring indices */
 	u32 cur_tx[NUM_TX_QUEUE];
 	u32 dirty_tx[NUM_TX_QUEUE];
+	u32 rx_buf_sz;			/* Based on MTU+slack. */
 	struct napi_struct napi[NUM_RX_QUEUE];
 	struct work_struct work;
 	/* MII transceiver section. */
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index c87f57ca4437..54a6265da7a0 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -238,7 +238,7 @@ static void ravb_ring_free(struct net_device *ndev, int q)
 					       le32_to_cpu(desc->dptr)))
 				dma_unmap_single(ndev->dev.parent,
 						 le32_to_cpu(desc->dptr),
-						 PKT_BUF_SZ,
+						 priv->rx_buf_sz,
 						 DMA_FROM_DEVICE);
 		}
 		ring_size = sizeof(struct ravb_ex_rx_desc) *
@@ -300,9 +300,9 @@ static void ravb_ring_format(struct net_device *ndev, int q)
 	for (i = 0; i < priv->num_rx_ring[q]; i++) {
 		/* RX descriptor */
 		rx_desc = &priv->rx_ring[q][i];
-		rx_desc->ds_cc = cpu_to_le16(PKT_BUF_SZ);
+		rx_desc->ds_cc = cpu_to_le16(priv->rx_buf_sz);
 		dma_addr = dma_map_single(ndev->dev.parent, priv->rx_skb[q][i]->data,
-					  PKT_BUF_SZ,
+					  priv->rx_buf_sz,
 					  DMA_FROM_DEVICE);
 		/* We just set the data size to 0 for a failed mapping which
 		 * should prevent DMA from happening...
@@ -346,6 +346,10 @@ static int ravb_ring_init(struct net_device *ndev, int q)
 	int ring_size;
 	int i;
 
+	/* +16 gets room from the status from the card. */
+	priv->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ : ndev->mtu) +
+		ETH_HLEN + VLAN_HLEN;
+
 	/* Allocate RX and TX skb rings */
 	priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
 				  sizeof(*priv->rx_skb[q]), GFP_KERNEL);
@@ -355,7 +359,7 @@ static int ravb_ring_init(struct net_device *ndev, int q)
 		goto error;
 
 	for (i = 0; i < priv->num_rx_ring[q]; i++) {
-		skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
+		skb = netdev_alloc_skb(ndev, priv->rx_buf_sz + RAVB_ALIGN - 1);
 		if (!skb)
 			goto error;
 		ravb_set_buffer_align(skb);
@@ -586,7 +590,7 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
 			skb = priv->rx_skb[q][entry];
 			priv->rx_skb[q][entry] = NULL;
 			dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
-					 PKT_BUF_SZ,
+					 priv->rx_buf_sz,
 					 DMA_FROM_DEVICE);
 			get_ts &= (q == RAVB_NC) ?
 					RAVB_RXTSTAMP_TYPE_V2_L2_EVENT :
@@ -619,11 +623,12 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
 	for (; priv->cur_rx[q] - priv->dirty_rx[q] > 0; priv->dirty_rx[q]++) {
 		entry = priv->dirty_rx[q] % priv->num_rx_ring[q];
 		desc = &priv->rx_ring[q][entry];
-		desc->ds_cc = cpu_to_le16(PKT_BUF_SZ);
+		desc->ds_cc = cpu_to_le16(priv->rx_buf_sz);
 
 		if (!priv->rx_skb[q][entry]) {
 			skb = netdev_alloc_skb(ndev,
-					       PKT_BUF_SZ + RAVB_ALIGN - 1);
+					       priv->rx_buf_sz +
+					       RAVB_ALIGN - 1);
 			if (!skb)
 				break;	/* Better luck next round. */
 			ravb_set_buffer_align(skb);
@@ -1854,6 +1859,17 @@ static int ravb_do_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
 	return phy_mii_ioctl(phydev, req, cmd);
 }
 
+static int ravb_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	if (netif_running(ndev))
+		return -EBUSY;
+
+	ndev->mtu = new_mtu;
+	netdev_update_features(ndev);
+
+	return 0;
+}
+
 static void ravb_set_rx_csum(struct net_device *ndev, bool enable)
 {
 	struct ravb_private *priv = netdev_priv(ndev);
@@ -1895,6 +1911,7 @@ static const struct net_device_ops ravb_netdev_ops = {
 	.ndo_set_rx_mode	= ravb_set_rx_mode,
 	.ndo_tx_timeout		= ravb_tx_timeout,
 	.ndo_do_ioctl		= ravb_do_ioctl,
+	.ndo_change_mtu		= ravb_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_set_features	= ravb_set_features,
@@ -2117,6 +2134,9 @@ static int ravb_probe(struct platform_device *pdev)
 		goto out_release;
 	}
 
+	ndev->max_mtu = 2048 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
+	ndev->min_mtu = ETH_MIN_MTU;
+
 	/* Set function */
 	ndev->netdev_ops = &ravb_netdev_ops;
 	ndev->ethtool_ops = &ravb_ethtool_ops;
@@ -2255,9 +2275,6 @@ static int ravb_wol_setup(struct net_device *ndev)
 	/* Enable MagicPacket */
 	ravb_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
 
-	/* Increased clock usage so device won't be suspended */
-	clk_enable(priv->clk);
-
 	return enable_irq_wake(priv->emac_irq);
 }
 
@@ -2276,9 +2293,6 @@ static int ravb_wol_restore(struct net_device *ndev)
 	if (ret < 0)
 		return ret;
 
-	/* Restore clock usage count */
-	clk_disable(priv->clk);
-
 	return disable_irq_wake(priv->emac_irq);
 }
 
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index a197e11f3a56..d7d5a6d15219 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -40,7 +40,6 @@
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
-#include <linux/clk.h>
 #include <linux/sh_eth.h>
 #include <linux/of_mdio.h>
 
@@ -962,20 +961,16 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
 
 static int sh_eth_check_reset(struct net_device *ndev)
 {
-	int ret = 0;
-	int cnt = 100;
+	int cnt;
 
-	while (cnt > 0) {
+	for (cnt = 100; cnt > 0; cnt--) {
 		if (!(sh_eth_read(ndev, EDMR) & EDMR_SRST_GETHER))
-			break;
+			return 0;
 		mdelay(1);
-		cnt--;
 	}
-	if (cnt <= 0) {
-		netdev_err(ndev, "Device reset failed\n");
-		ret = -ETIMEDOUT;
-	}
-	return ret;
+
+	netdev_err(ndev, "Device reset failed\n");
+	return -ETIMEDOUT;
 }
 
 static int sh_eth_reset(struct net_device *ndev)
@@ -2304,7 +2299,7 @@ static void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
 	wol->supported = 0;
 	wol->wolopts = 0;
 
-	if (mdp->cd->magic && mdp->clk) {
+	if (mdp->cd->magic) {
 		wol->supported = WAKE_MAGIC;
 		wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0;
 	}
@@ -2314,7 +2309,7 @@ static int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
 
-	if (!mdp->cd->magic || !mdp->clk || wol->wolopts & ~WAKE_MAGIC)
+	if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC)
 		return -EOPNOTSUPP;
 
 	mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC);
@@ -3153,11 +3148,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 		goto out_release;
 	}
 
-	/* Get clock, if not found that's OK but Wake-On-Lan is unavailable */
-	mdp->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(mdp->clk))
-		mdp->clk = NULL;
-
 	ndev->base_addr = res->start;
 
 	spin_lock_init(&mdp->lock);
@@ -3278,7 +3268,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 	if (ret)
 		goto out_napi_del;
 
-	if (mdp->cd->magic && mdp->clk)
+	if (mdp->cd->magic)
 		device_set_wakeup_capable(&pdev->dev, 1);
 
 	/* print device information */
@@ -3331,9 +3321,6 @@ static int sh_eth_wol_setup(struct net_device *ndev)
 	/* Enable MagicPacket */
 	sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
 
-	/* Increased clock usage so device won't be suspended */
-	clk_enable(mdp->clk);
-
 	return enable_irq_wake(ndev->irq);
 }
 
@@ -3359,9 +3346,6 @@ static int sh_eth_wol_restore(struct net_device *ndev)
 	if (ret < 0)
 		return ret;
 
-	/* Restore clock usage count */
-	clk_disable(mdp->clk);
-
 	return disable_irq_wake(ndev->irq);
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index 5270d26f0bc6..2d5d4aea3bcb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -48,26 +48,18 @@
 #define MUX_CLK_NUM_PARENTS		2
 
 struct meson8b_dwmac {
-	struct platform_device	*pdev;
-
+	struct device		*dev;
 	void __iomem		*regs;
-
 	phy_interface_t		phy_mode;
+	struct clk		*rgmii_tx_clk;
+	u32			tx_delay_ns;
+};
 
+struct meson8b_dwmac_clk_configs {
 	struct clk_mux		m250_mux;
-	struct clk		*m250_mux_clk;
-	struct clk		*m250_mux_parent[MUX_CLK_NUM_PARENTS];
-
 	struct clk_divider	m250_div;
-	struct clk		*m250_div_clk;
-
 	struct clk_fixed_factor	fixed_div2;
-	struct clk		*fixed_div2_clk;
-
 	struct clk_gate		rgmii_tx_en;
-	struct clk		*rgmii_tx_en_clk;
-
-	u32			tx_delay_ns;
 };
 
 static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
@@ -82,106 +74,99 @@ static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
 	writel(data, dwmac->regs + reg);
 }
 
-static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
+static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac,
+					      const char *name_suffix,
+					      const char **parent_names,
+					      int num_parents,
+					      const struct clk_ops *ops,
+					      struct clk_hw *hw)
 {
 	struct clk_init_data init;
-	int i, ret;
-	struct device *dev = &dwmac->pdev->dev;
 	char clk_name[32];
-	const char *clk_div_parents[1];
-	const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
+
+	snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev),
+		 name_suffix);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = CLK_SET_RATE_PARENT;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	hw->init = &init;
+
+	return devm_clk_register(dwmac->dev, hw);
+}
+
+static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
+{
+	int i, ret;
+	struct clk *clk;
+	struct device *dev = dwmac->dev;
+	const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS];
+	struct meson8b_dwmac_clk_configs *clk_configs;
+
+	clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
+	if (!clk_configs)
+		return -ENOMEM;
 
 	/* get the mux parents from DT */
 	for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
 		char name[16];
 
 		snprintf(name, sizeof(name), "clkin%d", i);
-		dwmac->m250_mux_parent[i] = devm_clk_get(dev, name);
-		if (IS_ERR(dwmac->m250_mux_parent[i])) {
-			ret = PTR_ERR(dwmac->m250_mux_parent[i]);
+		clk = devm_clk_get(dev, name);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
 			if (ret != -EPROBE_DEFER)
 				dev_err(dev, "Missing clock %s\n", name);
 			return ret;
 		}
 
-		mux_parent_names[i] =
-			__clk_get_name(dwmac->m250_mux_parent[i]);
+		mux_parent_names[i] = __clk_get_name(clk);
 	}
 
-	/* create the m250_mux */
-	snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev));
-	init.name = clk_name;
-	init.ops = &clk_mux_ops;
-	init.flags = CLK_SET_RATE_PARENT;
-	init.parent_names = mux_parent_names;
-	init.num_parents = MUX_CLK_NUM_PARENTS;
-
-	dwmac->m250_mux.reg = dwmac->regs + PRG_ETH0;
-	dwmac->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
-	dwmac->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
-	dwmac->m250_mux.flags = 0;
-	dwmac->m250_mux.table = NULL;
-	dwmac->m250_mux.hw.init = &init;
-
-	dwmac->m250_mux_clk = devm_clk_register(dev, &dwmac->m250_mux.hw);
-	if (WARN_ON(IS_ERR(dwmac->m250_mux_clk)))
-		return PTR_ERR(dwmac->m250_mux_clk);
-
-	/* create the m250_div */
-	snprintf(clk_name, sizeof(clk_name), "%s#m250_div", dev_name(dev));
-	init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
-	init.ops = &clk_divider_ops;
-	init.flags = CLK_SET_RATE_PARENT;
-	clk_div_parents[0] = __clk_get_name(dwmac->m250_mux_clk);
-	init.parent_names = clk_div_parents;
-	init.num_parents = ARRAY_SIZE(clk_div_parents);
-
-	dwmac->m250_div.reg = dwmac->regs + PRG_ETH0;
-	dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
-	dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
-	dwmac->m250_div.hw.init = &init;
-	dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED |
+	clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0;
+	clk_configs->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT;
+	clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK;
+	clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parent_names,
+					 MUX_CLK_NUM_PARENTS, &clk_mux_ops,
+					 &clk_configs->m250_mux.hw);
+	if (WARN_ON(IS_ERR(clk)))
+		return PTR_ERR(clk);
+
+	parent_name = __clk_get_name(clk);
+	clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
+	clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
+	clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
+	clk_configs->m250_div.flags = CLK_DIVIDER_ONE_BASED |
 				CLK_DIVIDER_ALLOW_ZERO |
 				CLK_DIVIDER_ROUND_CLOSEST;
-
-	dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw);
-	if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
-		return PTR_ERR(dwmac->m250_div_clk);
-
-	/* create the fixed_div2 */
-	snprintf(clk_name, sizeof(clk_name), "%s#fixed_div2", dev_name(dev));
-	init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
-	init.ops = &clk_fixed_factor_ops;
-	init.flags = CLK_SET_RATE_PARENT;
-	clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
-	init.parent_names = clk_div_parents;
-	init.num_parents = ARRAY_SIZE(clk_div_parents);
-
-	dwmac->fixed_div2.mult = 1;
-	dwmac->fixed_div2.div = 2;
-	dwmac->fixed_div2.hw.init = &init;
-
-	dwmac->fixed_div2_clk = devm_clk_register(dev, &dwmac->fixed_div2.hw);
-	if (WARN_ON(IS_ERR(dwmac->fixed_div2_clk)))
-		return PTR_ERR(dwmac->fixed_div2_clk);
-
-	/* create the rgmii_tx_en */
-	init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#rgmii_tx_en",
-				   dev_name(dev));
-	init.ops = &clk_gate_ops;
-	init.flags = CLK_SET_RATE_PARENT;
-	clk_div_parents[0] = __clk_get_name(dwmac->fixed_div2_clk);
-	init.parent_names = clk_div_parents;
-	init.num_parents = ARRAY_SIZE(clk_div_parents);
-
-	dwmac->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
-	dwmac->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
-	dwmac->rgmii_tx_en.hw.init = &init;
-
-	dwmac->rgmii_tx_en_clk = devm_clk_register(dev,
-						   &dwmac->rgmii_tx_en.hw);
-	if (WARN_ON(IS_ERR(dwmac->rgmii_tx_en_clk)))
-		return PTR_ERR(dwmac->rgmii_tx_en_clk);
+	clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1,
+					 &clk_divider_ops,
+					 &clk_configs->m250_div.hw);
+	if (WARN_ON(IS_ERR(clk)))
+		return PTR_ERR(clk);
+
+	parent_name = __clk_get_name(clk);
+	clk_configs->fixed_div2.mult = 1;
+	clk_configs->fixed_div2.div = 2;
+	clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_name, 1,
+					 &clk_fixed_factor_ops,
+					 &clk_configs->fixed_div2.hw);
+	if (WARN_ON(IS_ERR(clk)))
+		return PTR_ERR(clk);
+
+	parent_name = __clk_get_name(clk);
+	clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
+	clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
+	clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_name, 1,
+					 &clk_gate_ops,
+					 &clk_configs->rgmii_tx_en.hw);
+	if (WARN_ON(IS_ERR(clk)))
+		return PTR_ERR(clk);
+
+	dwmac->rgmii_tx_clk = clk;
 
 	return 0;
 }
@@ -219,19 +204,23 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
 		 * a register) based on the line-speed (125MHz for Gbit speeds,
 		 * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
 		 */
-		ret = clk_set_rate(dwmac->rgmii_tx_en_clk, 125 * 1000 * 1000);
+		ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000);
 		if (ret) {
-			dev_err(&dwmac->pdev->dev,
+			dev_err(dwmac->dev,
 				"failed to set RGMII TX clock\n");
 			return ret;
 		}
 
-		ret = clk_prepare_enable(dwmac->rgmii_tx_en_clk);
+		ret = clk_prepare_enable(dwmac->rgmii_tx_clk);
 		if (ret) {
-			dev_err(&dwmac->pdev->dev,
+			dev_err(dwmac->dev,
 				"failed to enable the RGMII TX clock\n");
 			return ret;
 		}
+
+		devm_add_action_or_reset(dwmac->dev,
+					(void(*)(void *))clk_disable_unprepare,
+					dwmac->rgmii_tx_clk);
 		break;
 
 	case PHY_INTERFACE_MODE_RMII:
@@ -251,7 +240,7 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
 		break;
 
 	default:
-		dev_err(&dwmac->pdev->dev, "unsupported phy-mode %s\n",
+		dev_err(dwmac->dev, "unsupported phy-mode %s\n",
 			phy_modes(dwmac->phy_mode));
 		return -EINVAL;
 	}
@@ -292,7 +281,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
 		goto err_remove_config_dt;
 	}
 
-	dwmac->pdev = pdev;
+	dwmac->dev = &pdev->dev;
 	dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
 	if (dwmac->phy_mode < 0) {
 		dev_err(&pdev->dev, "missing phy-mode property\n");
@@ -317,29 +306,16 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
 
 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 	if (ret)
-		goto err_clk_disable;
+		goto err_remove_config_dt;
 
 	return 0;
 
-err_clk_disable:
-	if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
-		clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
 err_remove_config_dt:
 	stmmac_remove_config_dt(pdev, plat_dat);
 
 	return ret;
 }
 
-static int meson8b_dwmac_remove(struct platform_device *pdev)
-{
-	struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
-
-	if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
-		clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
-
-	return stmmac_pltfr_remove(pdev);
-}
-
 static const struct of_device_id meson8b_dwmac_match[] = {
 	{ .compatible = "amlogic,meson8b-dwmac" },
 	{ .compatible = "amlogic,meson-gxbb-dwmac" },
@@ -349,7 +325,7 @@ MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
 
 static struct platform_driver meson8b_dwmac_driver = {
 	.probe  = meson8b_dwmac_probe,
-	.remove = meson8b_dwmac_remove,
+	.remove = stmmac_pltfr_remove,
 	.driver = {
 		.name           = "meson8b-dwmac",
 		.pm		= &stmmac_pltfr_pm_ops,
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 30612497643c..b97a907ea5aa 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -230,4 +230,5 @@ static __net_init int loopback_net_init(struct net *net)
 /* Registered in net/core/dev.c */
 struct pernet_operations __net_initdata loopback_net_ops = {
 	.init = loopback_net_init,
+	.async = true,
 };
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index ab58224f897f..b3935778b19f 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -75,6 +75,8 @@
 
 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX	0x0
 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN	0x1f
+#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK	(0x1f << 8)
+#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT	8
 
 /* CFG4 bits */
 #define DP83867_CFG4_PORT_MIRROR_EN              BIT(0)
@@ -92,6 +94,7 @@ struct dp83867_private {
 	int io_impedance;
 	int port_mirroring;
 	bool rxctrl_strap_quirk;
+	int clk_output_sel;
 };
 
 static int dp83867_ack_interrupt(struct phy_device *phydev)
@@ -160,6 +163,14 @@ static int dp83867_of_init(struct phy_device *phydev)
 	dp83867->io_impedance = -EINVAL;
 
 	/* Optional configuration */
+	ret = of_property_read_u32(of_node, "ti,clk-output-sel",
+				   &dp83867->clk_output_sel);
+	if (ret || dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK)
+		/* Keep the default value if ti,clk-output-sel is not set
+		 * or too high
+		 */
+		dp83867->clk_output_sel = DP83867_CLK_O_SEL_REF_CLK;
+
 	if (of_property_read_bool(of_node, "ti,max-output-impedance"))
 		dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
 	else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
@@ -295,6 +306,14 @@ static int dp83867_config_init(struct phy_device *phydev)
 	if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
 		dp83867_config_port_mirroring(phydev);
 
+	/* Clock output selection if muxing property is set */
+	if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) {
+		val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG);
+		val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
+		val |= (dp83867->clk_output_sel << DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT);
+		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG, val);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b13eed21c87d..d39ae77707ef 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1382,7 +1382,7 @@ int genphy_setup_forced(struct phy_device *phydev)
 		ctl |= BMCR_FULLDPLX;
 
 	return phy_modify(phydev, MII_BMCR,
-			  BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN, ctl);
+			  ~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
 }
 EXPORT_SYMBOL(genphy_setup_forced);
 
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 5aa59f41bf8c..bd89d1c559ce 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -714,7 +714,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
 }
 
 static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr,
-		  int *usockaddr_len, int peer)
+		  int peer)
 {
 	int len = sizeof(struct sockaddr_pppox);
 	struct sockaddr_pppox sp;
@@ -726,9 +726,7 @@ static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr,
 
 	memcpy(uaddr, &sp, len);
 
-	*usockaddr_len = len;
-
-	return 0;
+	return len;
 }
 
 static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 6dde9a0cfe76..8249d46a7844 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -483,7 +483,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
 }
 
 static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
-	int *usockaddr_len, int peer)
+	int peer)
 {
 	int len = sizeof(struct sockaddr_pppox);
 	struct sockaddr_pppox sp;
@@ -496,9 +496,7 @@ static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
 
 	memcpy(uaddr, &sp, len);
 
-	*usockaddr_len = len;
-
-	return 0;
+	return len;
 }
 
 static int pptp_release(struct socket *sock)
diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c
index ca5e375de27c..e0d6760f3219 100644
--- a/drivers/net/thunderbolt.c
+++ b/drivers/net/thunderbolt.c
@@ -166,6 +166,8 @@ struct tbnet_ring {
  * @connected_work: Worker that finalizes the ThunderboltIP connection
  *		    setup and enables DMA paths for high speed data
  *		    transfers
+ * @disconnect_work: Worker that handles tearing down the ThunderboltIP
+ *		     connection
  * @rx_hdr: Copy of the currently processed Rx frame. Used when a
  *	    network packet consists of multiple Thunderbolt frames.
  *	    In host byte order.
@@ -190,6 +192,7 @@ struct tbnet {
 	int login_retries;
 	struct delayed_work login_work;
 	struct work_struct connected_work;
+	struct work_struct disconnect_work;
 	struct thunderbolt_ip_frame_header rx_hdr;
 	struct tbnet_ring rx_ring;
 	atomic_t frame_id;
@@ -445,7 +448,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data)
 	case TBIP_LOGOUT:
 		ret = tbnet_logout_response(net, route, sequence, command_id);
 		if (!ret)
-			tbnet_tear_down(net, false);
+			queue_work(system_long_wq, &net->disconnect_work);
 		break;
 
 	default:
@@ -659,6 +662,13 @@ static void tbnet_login_work(struct work_struct *work)
 	}
 }
 
+static void tbnet_disconnect_work(struct work_struct *work)
+{
+	struct tbnet *net = container_of(work, typeof(*net), disconnect_work);
+
+	tbnet_tear_down(net, false);
+}
+
 static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf,
 			      const struct thunderbolt_ip_frame_header *hdr)
 {
@@ -881,6 +891,7 @@ static int tbnet_stop(struct net_device *dev)
 
 	napi_disable(&net->napi);
 
+	cancel_work_sync(&net->disconnect_work);
 	tbnet_tear_down(net, true);
 
 	tb_ring_free(net->rx_ring.ring);
@@ -1195,6 +1206,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id)
 	net = netdev_priv(dev);
 	INIT_DELAYED_WORK(&net->login_work, tbnet_login_work);
 	INIT_WORK(&net->connected_work, tbnet_connected_work);
+	INIT_WORK(&net->disconnect_work, tbnet_disconnect_work);
 	mutex_init(&net->connection_lock);
 	atomic_set(&net->command_id, 0);
 	atomic_set(&net->frame_id, 0);
@@ -1270,10 +1282,7 @@ static int __maybe_unused tbnet_suspend(struct device *dev)
 	stop_login(net);
 	if (netif_running(net->dev)) {
 		netif_device_detach(net->dev);
-		tb_ring_stop(net->rx_ring.ring);
-		tb_ring_stop(net->tx_ring.ring);
-		tbnet_free_buffers(&net->rx_ring);
-		tbnet_free_buffers(&net->tx_ring);
+		tbnet_tear_down(net, true);
 	}
 
 	return 0;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 81e6cc951e7f..d531954512c7 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -78,6 +78,7 @@
 #include <linux/mutex.h>
 
 #include <linux/uaccess.h>
+#include <linux/proc_fs.h>
 
 /* Uncomment to enable debugging */
 /* #define TUN_DEBUG 1 */
@@ -1489,27 +1490,23 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile,
 	skb->truesize += skb->data_len;
 
 	for (i = 1; i < it->nr_segs; i++) {
+		struct page_frag *pfrag = &current->task_frag;
 		size_t fragsz = it->iov[i].iov_len;
-		unsigned long offset;
-		struct page *page;
-		void *data;
 
 		if (fragsz == 0 || fragsz > PAGE_SIZE) {
 			err = -EINVAL;
 			goto free;
 		}
 
-		local_bh_disable();
-		data = napi_alloc_frag(fragsz);
-		local_bh_enable();
-		if (!data) {
+		if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) {
 			err = -ENOMEM;
 			goto free;
 		}
 
-		page = virt_to_head_page(data);
-		offset = data - page_address(page);
-		skb_fill_page_desc(skb, i - 1, page, offset, fragsz);
+		skb_fill_page_desc(skb, i - 1, pfrag->page,
+				   pfrag->offset, fragsz);
+		page_ref_inc(pfrag->page);
+		pfrag->offset += fragsz;
 	}
 
 	return skb;
@@ -2290,11 +2287,67 @@ static int tun_validate(struct nlattr *tb[], struct nlattr *data[],
 	return -EINVAL;
 }
 
+static size_t tun_get_size(const struct net_device *dev)
+{
+	BUILD_BUG_ON(sizeof(u32) != sizeof(uid_t));
+	BUILD_BUG_ON(sizeof(u32) != sizeof(gid_t));
+
+	return nla_total_size(sizeof(uid_t)) + /* OWNER */
+	       nla_total_size(sizeof(gid_t)) + /* GROUP */
+	       nla_total_size(sizeof(u8)) + /* TYPE */
+	       nla_total_size(sizeof(u8)) + /* PI */
+	       nla_total_size(sizeof(u8)) + /* VNET_HDR */
+	       nla_total_size(sizeof(u8)) + /* PERSIST */
+	       nla_total_size(sizeof(u8)) + /* MULTI_QUEUE */
+	       nla_total_size(sizeof(u32)) + /* NUM_QUEUES */
+	       nla_total_size(sizeof(u32)) + /* NUM_DISABLED_QUEUES */
+	       0;
+}
+
+static int tun_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct tun_struct *tun = netdev_priv(dev);
+
+	if (nla_put_u8(skb, IFLA_TUN_TYPE, tun->flags & TUN_TYPE_MASK))
+		goto nla_put_failure;
+	if (uid_valid(tun->owner) &&
+	    nla_put_u32(skb, IFLA_TUN_OWNER,
+			from_kuid_munged(current_user_ns(), tun->owner)))
+		goto nla_put_failure;
+	if (gid_valid(tun->group) &&
+	    nla_put_u32(skb, IFLA_TUN_GROUP,
+			from_kgid_munged(current_user_ns(), tun->group)))
+		goto nla_put_failure;
+	if (nla_put_u8(skb, IFLA_TUN_PI, !(tun->flags & IFF_NO_PI)))
+		goto nla_put_failure;
+	if (nla_put_u8(skb, IFLA_TUN_VNET_HDR, !!(tun->flags & IFF_VNET_HDR)))
+		goto nla_put_failure;
+	if (nla_put_u8(skb, IFLA_TUN_PERSIST, !!(tun->flags & IFF_PERSIST)))
+		goto nla_put_failure;
+	if (nla_put_u8(skb, IFLA_TUN_MULTI_QUEUE,
+		       !!(tun->flags & IFF_MULTI_QUEUE)))
+		goto nla_put_failure;
+	if (tun->flags & IFF_MULTI_QUEUE) {
+		if (nla_put_u32(skb, IFLA_TUN_NUM_QUEUES, tun->numqueues))
+			goto nla_put_failure;
+		if (nla_put_u32(skb, IFLA_TUN_NUM_DISABLED_QUEUES,
+				tun->numdisabled))
+			goto nla_put_failure;
+	}
+
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
 static struct rtnl_link_ops tun_link_ops __read_mostly = {
 	.kind		= DRV_NAME,
 	.priv_size	= sizeof(struct tun_struct),
 	.setup		= tun_setup,
 	.validate	= tun_validate,
+	.get_size       = tun_get_size,
+	.fill_info      = tun_fill_info,
 };
 
 static void tun_sock_write_space(struct sock *sk)
@@ -2793,6 +2846,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 	struct tun_struct *tun;
 	void __user* argp = (void __user*)arg;
 	struct ifreq ifr;
+	struct net *net;
 	kuid_t owner;
 	kgid_t group;
 	int sndbuf;
@@ -2801,7 +2855,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 	int le;
 	int ret;
 
-	if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == SOCK_IOC_TYPE) {
+	if (cmd == TUNSETIFF || cmd == TUNSETQUEUE ||
+	    (_IOC_TYPE(cmd) == SOCK_IOC_TYPE && cmd != SIOCGSKNS)) {
 		if (copy_from_user(&ifr, argp, ifreq_len))
 			return -EFAULT;
 	} else {
@@ -2821,6 +2876,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 	rtnl_lock();
 
 	tun = tun_get(tfile);
+	net = sock_net(&tfile->sk);
 	if (cmd == TUNSETIFF) {
 		ret = -EEXIST;
 		if (tun)
@@ -2828,7 +2884,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 
 		ifr.ifr_name[IFNAMSIZ-1] = '\0';
 
-		ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr);
+		ret = tun_set_iff(net, file, &ifr);
 
 		if (ret)
 			goto unlock;
@@ -2850,6 +2906,14 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		tfile->ifindex = ifindex;
 		goto unlock;
 	}
+	if (cmd == SIOCGSKNS) {
+		ret = -EPERM;
+		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+			goto unlock;
+
+		ret = open_related_ns(&net->ns, get_net_ns);
+		goto unlock;
+	}
 
 	ret = -EBADFD;
 	if (!tun)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 139c61c8244a..239c78c53e58 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -736,7 +736,6 @@ static int vrf_rtable_create(struct net_device *dev)
 		return -ENOMEM;
 
 	rth->dst.output	= vrf_output;
-	rth->rt_table_id = vrf->tb_id;
 
 	rcu_assign_pointer(vrf->rth, rth);
 
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 768f63f38341..b799a5384abb 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1599,7 +1599,8 @@ static void wil_probe_client_handle(struct wil6210_priv *wil,
 	 */
 	bool alive = (sta->status == wil_sta_connected);
 
-	cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL);
+	cfg80211_probe_status(ndev, sta->addr, req->cookie, alive,
+			      0, false, GFP_KERNEL);
 }
 
 static struct list_head *next_probe_client(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 1cf22e62e3dd..3c64afa161bf 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -493,6 +493,7 @@ static LIST_HEAD(hwsim_radios);
 static struct workqueue_struct *hwsim_wq;
 static struct rhashtable hwsim_radios_rht;
 static int hwsim_radio_idx;
+static int hwsim_radios_generation = 1;
 
 static struct platform_driver mac80211_hwsim_driver = {
 	.driver = {
@@ -637,6 +638,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
 	[HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING },
 	[HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG },
 	[HWSIM_ATTR_FREQ] = { .type = NLA_U32 },
+	[HWSIM_ATTR_PERM_ADDR] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -2408,6 +2410,7 @@ struct hwsim_new_radio_params {
 	bool destroy_on_close;
 	const char *hwname;
 	bool no_vif;
+	const u8 *perm_addr;
 };
 
 static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
@@ -2572,15 +2575,25 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 	skb_queue_head_init(&data->pending);
 
 	SET_IEEE80211_DEV(hw, data->dev);
-	eth_zero_addr(addr);
-	addr[0] = 0x02;
-	addr[3] = idx >> 8;
-	addr[4] = idx;
-	memcpy(data->addresses[0].addr, addr, ETH_ALEN);
-	memcpy(data->addresses[1].addr, addr, ETH_ALEN);
-	data->addresses[1].addr[0] |= 0x40;
-	hw->wiphy->n_addresses = 2;
-	hw->wiphy->addresses = data->addresses;
+	if (!param->perm_addr) {
+		eth_zero_addr(addr);
+		addr[0] = 0x02;
+		addr[3] = idx >> 8;
+		addr[4] = idx;
+		memcpy(data->addresses[0].addr, addr, ETH_ALEN);
+		/* Why need here second address ? */
+		data->addresses[1].addr[0] |= 0x40;
+		memcpy(data->addresses[1].addr, addr, ETH_ALEN);
+		hw->wiphy->n_addresses = 2;
+		hw->wiphy->addresses = data->addresses;
+		/* possible address clash is checked at hash table insertion */
+	} else {
+		memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN);
+		/* compatibility with automatically generated mac addr */
+		memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN);
+		hw->wiphy->n_addresses = 2;
+		hw->wiphy->addresses = data->addresses;
+	}
 
 	data->channels = param->channels;
 	data->use_chanctx = param->use_chanctx;
@@ -2785,13 +2798,17 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 	err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht,
 				     hwsim_rht_params);
 	if (err < 0) {
-		pr_debug("mac80211_hwsim: radio index %d already present\n",
-			 idx);
+		if (info) {
+			GENL_SET_ERR_MSG(info, "perm addr already present");
+			NL_SET_BAD_ATTR(info->extack,
+					info->attrs[HWSIM_ATTR_PERM_ADDR]);
+		}
 		spin_unlock_bh(&hwsim_radio_lock);
 		goto failed_final_insert;
 	}
 
 	list_add_tail(&data->list, &hwsim_radios);
+	hwsim_radios_generation++;
 	spin_unlock_bh(&hwsim_radio_lock);
 
 	if (idx > 0)
@@ -3210,6 +3227,19 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
 		param.regd = hwsim_world_regdom_custom[idx];
 	}
 
+	if (info->attrs[HWSIM_ATTR_PERM_ADDR]) {
+		if (!is_valid_ether_addr(
+				nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) {
+			GENL_SET_ERR_MSG(info,"MAC is no valid source addr");
+			NL_SET_BAD_ATTR(info->extack,
+					info->attrs[HWSIM_ATTR_PERM_ADDR]);
+			return -EINVAL;
+		}
+
+
+		param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]);
+	}
+
 	ret = mac80211_hwsim_new_radio(info, &param);
 	kfree(hwname);
 	return ret;
@@ -3249,6 +3279,7 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
 		list_del(&data->list);
 		rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
 				       hwsim_rht_params);
+		hwsim_radios_generation++;
 		spin_unlock_bh(&hwsim_radio_lock);
 		mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
 					 info);
@@ -3305,17 +3336,19 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
 static int hwsim_dump_radio_nl(struct sk_buff *skb,
 			       struct netlink_callback *cb)
 {
-	int idx = cb->args[0];
+	int last_idx = cb->args[0];
 	struct mac80211_hwsim_data *data = NULL;
-	int res;
+	int res = 0;
+	void *hdr;
 
 	spin_lock_bh(&hwsim_radio_lock);
+	cb->seq = hwsim_radios_generation;
 
-	if (idx == hwsim_radio_idx)
+	if (last_idx >= hwsim_radio_idx-1)
 		goto done;
 
 	list_for_each_entry(data, &hwsim_radios, list) {
-		if (data->idx < idx)
+		if (data->idx <= last_idx)
 			continue;
 
 		if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk)))
@@ -3328,14 +3361,25 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
 		if (res < 0)
 			break;
 
-		idx = data->idx + 1;
+		last_idx = data->idx;
 	}
 
-	cb->args[0] = idx;
+	cb->args[0] = last_idx;
+
+	/* list changed, but no new element sent, set interrupted flag */
+	if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) {
+		hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
+				  cb->nlh->nlmsg_seq, &hwsim_genl_family,
+				  NLM_F_MULTI, HWSIM_CMD_GET_RADIO);
+		if (!hdr)
+			res = -EMSGSIZE;
+		genl_dump_check_consistent(cb, hdr);
+		genlmsg_end(skb, hdr);
+	}
 
 done:
 	spin_unlock_bh(&hwsim_radio_lock);
-	return skb->len;
+	return res ?: skb->len;
 }
 
 /* Generic Netlink operations array */
@@ -3393,6 +3437,7 @@ static void destroy_radio(struct work_struct *work)
 	struct mac80211_hwsim_data *data =
 		container_of(work, struct mac80211_hwsim_data, destroy_work);
 
+	hwsim_radios_generation++;
 	mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL);
 }
 
@@ -3516,7 +3561,7 @@ static int __init init_mac80211_hwsim(void)
 
 	spin_lock_init(&hwsim_radio_lock);
 
-	hwsim_wq = alloc_workqueue("hwsim_wq",WQ_MEM_RECLAIM,0);
+	hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0);
 	if (!hwsim_wq)
 		return -ENOMEM;
 	rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params);
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h
index a96a79c1eff5..0fe3199f8c72 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -68,7 +68,12 @@ enum hwsim_tx_control_flags {
  *	%HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
  * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters,
  *	returns the radio ID (>= 0) or negative on errors, if successful
- *	then multicast the result
+ *	then multicast the result, uses optional parameter:
+ *	%HWSIM_ATTR_REG_STRICT_REG, %HWSIM_ATTR_SUPPORT_P2P_DEVICE,
+ *	%HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, %HWSIM_ATTR_CHANNELS,
+ *	%HWSIM_ATTR_NO_VIF, %HWSIM_ATTR_RADIO_NAME, %HWSIM_ATTR_USE_CHANCTX,
+ *	%HWSIM_ATTR_REG_HINT_ALPHA2, %HWSIM_ATTR_REG_CUSTOM_REG,
+ *	%HWSIM_ATTR_PERM_ADDR
  * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
  *	%HWSIM_ATTR_RADIO_ID
@@ -126,6 +131,7 @@ enum {
  * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
  * @HWSIM_ATTR_TX_INFO_FLAGS: additional flags for corresponding
  *	rates of %HWSIM_ATTR_TX_INFO
+ * @HWSIM_ATTR_PERM_ADDR: permanent mac address of new radio
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -153,6 +159,7 @@ enum {
 	HWSIM_ATTR_FREQ,
 	HWSIM_ATTR_PAD,
 	HWSIM_ATTR_TX_INFO_FLAGS,
+	HWSIM_ATTR_PERM_ADDR,
 	__HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
diff --git a/drivers/ntb/hw/intel/Makefile b/drivers/ntb/hw/intel/Makefile
index 1b434568d2ad..4ff22af967c6 100644
--- a/drivers/ntb/hw/intel/Makefile
+++ b/drivers/ntb/hw/intel/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_NTB_INTEL) += ntb_hw_intel.o
+ntb_hw_intel-y := ntb_hw_gen1.o ntb_hw_gen3.o
diff --git a/drivers/ntb/hw/intel/ntb_hw_gen1.c b/drivers/ntb/hw/intel/ntb_hw_gen1.c
new file mode 100644
index 000000000000..ffdee98e8ece
--- /dev/null
+++ b/drivers/ntb/hw/intel/ntb_hw_gen1.c
@@ -0,0 +1,2070 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2012 Intel Corporation. All rights reserved.
+ *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
+ *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Intel PCIe NTB Linux driver
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/ntb.h>
+
+#include "ntb_hw_intel.h"
+#include "ntb_hw_gen1.h"
+#include "ntb_hw_gen3.h"
+
+#define NTB_NAME	"ntb_hw_intel"
+#define NTB_DESC	"Intel(R) PCI-E Non-Transparent Bridge Driver"
+#define NTB_VER		"2.0"
+
+MODULE_DESCRIPTION(NTB_DESC);
+MODULE_VERSION(NTB_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+#define bar0_off(base, bar) ((base) + ((bar) << 2))
+#define bar2_off(base, bar) bar0_off(base, (bar) - 2)
+
+static const struct intel_ntb_reg xeon_reg;
+static const struct intel_ntb_alt_reg xeon_pri_reg;
+static const struct intel_ntb_alt_reg xeon_sec_reg;
+static const struct intel_ntb_alt_reg xeon_b2b_reg;
+static const struct intel_ntb_xlat_reg xeon_pri_xlat;
+static const struct intel_ntb_xlat_reg xeon_sec_xlat;
+static const struct ntb_dev_ops intel_ntb_ops;
+
+static const struct file_operations intel_ntb_debugfs_info;
+static struct dentry *debugfs_dir;
+
+static int b2b_mw_idx = -1;
+module_param(b2b_mw_idx, int, 0644);
+MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb.  A "
+		 "value of zero or positive starts from first mw idx, and a "
+		 "negative value starts from last mw idx.  Both sides MUST "
+		 "set the same value here!");
+
+static unsigned int b2b_mw_share;
+module_param(b2b_mw_share, uint, 0644);
+MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the "
+		 "ntb so that the peer ntb only occupies the first half of "
+		 "the mw, so the second half can still be used as a mw.  Both "
+		 "sides MUST set the same value here!");
+
+module_param_named(xeon_b2b_usd_bar2_addr64,
+		   xeon_b2b_usd_addr.bar2_addr64, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64,
+		 "XEON B2B USD BAR 2 64-bit address");
+
+module_param_named(xeon_b2b_usd_bar4_addr64,
+		   xeon_b2b_usd_addr.bar4_addr64, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_usd_bar4_addr64,
+		 "XEON B2B USD BAR 4 64-bit address");
+
+module_param_named(xeon_b2b_usd_bar4_addr32,
+		   xeon_b2b_usd_addr.bar4_addr32, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_usd_bar4_addr32,
+		 "XEON B2B USD split-BAR 4 32-bit address");
+
+module_param_named(xeon_b2b_usd_bar5_addr32,
+		   xeon_b2b_usd_addr.bar5_addr32, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_usd_bar5_addr32,
+		 "XEON B2B USD split-BAR 5 32-bit address");
+
+module_param_named(xeon_b2b_dsd_bar2_addr64,
+		   xeon_b2b_dsd_addr.bar2_addr64, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64,
+		 "XEON B2B DSD BAR 2 64-bit address");
+
+module_param_named(xeon_b2b_dsd_bar4_addr64,
+		   xeon_b2b_dsd_addr.bar4_addr64, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr64,
+		 "XEON B2B DSD BAR 4 64-bit address");
+
+module_param_named(xeon_b2b_dsd_bar4_addr32,
+		   xeon_b2b_dsd_addr.bar4_addr32, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr32,
+		 "XEON B2B DSD split-BAR 4 32-bit address");
+
+module_param_named(xeon_b2b_dsd_bar5_addr32,
+		   xeon_b2b_dsd_addr.bar5_addr32, ullong, 0644);
+MODULE_PARM_DESC(xeon_b2b_dsd_bar5_addr32,
+		 "XEON B2B DSD split-BAR 5 32-bit address");
+
+
+static int xeon_init_isr(struct intel_ntb_dev *ndev);
+
+static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev)
+{
+	ndev->unsafe_flags = 0;
+	ndev->unsafe_flags_ignore = 0;
+
+	/* Only B2B has a workaround to avoid SDOORBELL */
+	if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP)
+		if (!ntb_topo_is_b2b(ndev->ntb.topo))
+			ndev->unsafe_flags |= NTB_UNSAFE_DB;
+
+	/* No low level workaround to avoid SB01BASE */
+	if (ndev->hwerr_flags & NTB_HWERR_SB01BASE_LOCKUP) {
+		ndev->unsafe_flags |= NTB_UNSAFE_DB;
+		ndev->unsafe_flags |= NTB_UNSAFE_SPAD;
+	}
+}
+
+static inline int ndev_is_unsafe(struct intel_ntb_dev *ndev,
+				 unsigned long flag)
+{
+	return !!(flag & ndev->unsafe_flags & ~ndev->unsafe_flags_ignore);
+}
+
+static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev,
+				     unsigned long flag)
+{
+	flag &= ndev->unsafe_flags;
+	ndev->unsafe_flags_ignore |= flag;
+
+	return !!flag;
+}
+
+int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx)
+{
+	if (idx < 0 || idx >= ndev->mw_count)
+		return -EINVAL;
+	return ndev->reg->mw_bar[idx];
+}
+
+static inline int ndev_db_addr(struct intel_ntb_dev *ndev,
+			       phys_addr_t *db_addr, resource_size_t *db_size,
+			       phys_addr_t reg_addr, unsigned long reg)
+{
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
+		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
+
+	if (db_addr) {
+		*db_addr = reg_addr + reg;
+		dev_dbg(&ndev->ntb.pdev->dev, "Peer db addr %llx\n", *db_addr);
+	}
+
+	if (db_size) {
+		*db_size = ndev->reg->db_size;
+		dev_dbg(&ndev->ntb.pdev->dev, "Peer db size %llx\n", *db_size);
+	}
+
+	return 0;
+}
+
+u64 ndev_db_read(struct intel_ntb_dev *ndev,
+			       void __iomem *mmio)
+{
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
+		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
+
+	return ndev->reg->db_ioread(mmio);
+}
+
+int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits,
+				void __iomem *mmio)
+{
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
+		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
+
+	ndev->reg->db_iowrite(db_bits, mmio);
+
+	return 0;
+}
+
+static inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits,
+				   void __iomem *mmio)
+{
+	unsigned long irqflags;
+
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
+		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ndev->db_mask_lock, irqflags);
+	{
+		ndev->db_mask |= db_bits;
+		ndev->reg->db_iowrite(ndev->db_mask, mmio);
+	}
+	spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags);
+
+	return 0;
+}
+
+static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
+				     void __iomem *mmio)
+{
+	unsigned long irqflags;
+
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
+		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ndev->db_mask_lock, irqflags);
+	{
+		ndev->db_mask &= ~db_bits;
+		ndev->reg->db_iowrite(ndev->db_mask, mmio);
+	}
+	spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags);
+
+	return 0;
+}
+
+static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
+{
+	u64 shift, mask;
+
+	shift = ndev->db_vec_shift;
+	mask = BIT_ULL(shift) - 1;
+
+	return mask << (shift * db_vector);
+}
+
+static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx,
+				 phys_addr_t *spad_addr, phys_addr_t reg_addr,
+				 unsigned long reg)
+{
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD))
+		pr_warn_once("%s: NTB unsafe scratchpad access", __func__);
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	if (spad_addr) {
+		*spad_addr = reg_addr + reg + (idx << 2);
+		dev_dbg(&ndev->ntb.pdev->dev, "Peer spad addr %llx\n",
+			*spad_addr);
+	}
+
+	return 0;
+}
+
+static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx,
+				 void __iomem *mmio)
+{
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD))
+		pr_warn_once("%s: NTB unsafe scratchpad access", __func__);
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return 0;
+
+	return ioread32(mmio + (idx << 2));
+}
+
+static inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val,
+				  void __iomem *mmio)
+{
+	if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD))
+		pr_warn_once("%s: NTB unsafe scratchpad access", __func__);
+
+	if (idx < 0 || idx >= ndev->spad_count)
+		return -EINVAL;
+
+	iowrite32(val, mmio + (idx << 2));
+
+	return 0;
+}
+
+static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec)
+{
+	u64 vec_mask;
+
+	vec_mask = ndev_vec_mask(ndev, vec);
+
+	if ((ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) && (vec == 31))
+		vec_mask |= ndev->db_link_mask;
+
+	dev_dbg(&ndev->ntb.pdev->dev, "vec %d vec_mask %llx\n", vec, vec_mask);
+
+	ndev->last_ts = jiffies;
+
+	if (vec_mask & ndev->db_link_mask) {
+		if (ndev->reg->poll_link(ndev))
+			ntb_link_event(&ndev->ntb);
+	}
+
+	if (vec_mask & ndev->db_valid_mask)
+		ntb_db_event(&ndev->ntb, vec);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ndev_vec_isr(int irq, void *dev)
+{
+	struct intel_ntb_vec *nvec = dev;
+
+	dev_dbg(&nvec->ndev->ntb.pdev->dev, "irq: %d  nvec->num: %d\n",
+		irq, nvec->num);
+
+	return ndev_interrupt(nvec->ndev, nvec->num);
+}
+
+static irqreturn_t ndev_irq_isr(int irq, void *dev)
+{
+	struct intel_ntb_dev *ndev = dev;
+
+	return ndev_interrupt(ndev, irq - ndev->ntb.pdev->irq);
+}
+
+int ndev_init_isr(struct intel_ntb_dev *ndev,
+			 int msix_min, int msix_max,
+			 int msix_shift, int total_shift)
+{
+	struct pci_dev *pdev;
+	int rc, i, msix_count, node;
+
+	pdev = ndev->ntb.pdev;
+
+	node = dev_to_node(&pdev->dev);
+
+	/* Mask all doorbell interrupts */
+	ndev->db_mask = ndev->db_valid_mask;
+	ndev->reg->db_iowrite(ndev->db_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
+
+	/* Try to set up msix irq */
+
+	ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec),
+				 GFP_KERNEL, node);
+	if (!ndev->vec)
+		goto err_msix_vec_alloc;
+
+	ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix),
+				  GFP_KERNEL, node);
+	if (!ndev->msix)
+		goto err_msix_alloc;
+
+	for (i = 0; i < msix_max; ++i)
+		ndev->msix[i].entry = i;
+
+	msix_count = pci_enable_msix_range(pdev, ndev->msix,
+					   msix_min, msix_max);
+	if (msix_count < 0)
+		goto err_msix_enable;
+
+	for (i = 0; i < msix_count; ++i) {
+		ndev->vec[i].ndev = ndev;
+		ndev->vec[i].num = i;
+		rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0,
+				 "ndev_vec_isr", &ndev->vec[i]);
+		if (rc)
+			goto err_msix_request;
+	}
+
+	dev_dbg(&pdev->dev, "Using %d msix interrupts\n", msix_count);
+	ndev->db_vec_count = msix_count;
+	ndev->db_vec_shift = msix_shift;
+	return 0;
+
+err_msix_request:
+	while (i-- > 0)
+		free_irq(ndev->msix[i].vector, &ndev->vec[i]);
+	pci_disable_msix(pdev);
+err_msix_enable:
+	kfree(ndev->msix);
+err_msix_alloc:
+	kfree(ndev->vec);
+err_msix_vec_alloc:
+	ndev->msix = NULL;
+	ndev->vec = NULL;
+
+	/* Try to set up msi irq */
+
+	rc = pci_enable_msi(pdev);
+	if (rc)
+		goto err_msi_enable;
+
+	rc = request_irq(pdev->irq, ndev_irq_isr, 0,
+			 "ndev_irq_isr", ndev);
+	if (rc)
+		goto err_msi_request;
+
+	dev_dbg(&pdev->dev, "Using msi interrupts\n");
+	ndev->db_vec_count = 1;
+	ndev->db_vec_shift = total_shift;
+	return 0;
+
+err_msi_request:
+	pci_disable_msi(pdev);
+err_msi_enable:
+
+	/* Try to set up intx irq */
+
+	pci_intx(pdev, 1);
+
+	rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED,
+			 "ndev_irq_isr", ndev);
+	if (rc)
+		goto err_intx_request;
+
+	dev_dbg(&pdev->dev, "Using intx interrupts\n");
+	ndev->db_vec_count = 1;
+	ndev->db_vec_shift = total_shift;
+	return 0;
+
+err_intx_request:
+	return rc;
+}
+
+static void ndev_deinit_isr(struct intel_ntb_dev *ndev)
+{
+	struct pci_dev *pdev;
+	int i;
+
+	pdev = ndev->ntb.pdev;
+
+	/* Mask all doorbell interrupts */
+	ndev->db_mask = ndev->db_valid_mask;
+	ndev->reg->db_iowrite(ndev->db_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
+
+	if (ndev->msix) {
+		i = ndev->db_vec_count;
+		while (i--)
+			free_irq(ndev->msix[i].vector, &ndev->vec[i]);
+		pci_disable_msix(pdev);
+		kfree(ndev->msix);
+		kfree(ndev->vec);
+	} else {
+		free_irq(pdev->irq, ndev);
+		if (pci_dev_msi_enabled(pdev))
+			pci_disable_msi(pdev);
+	}
+}
+
+static ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf,
+				     size_t count, loff_t *offp)
+{
+	struct intel_ntb_dev *ndev;
+	struct pci_dev *pdev;
+	void __iomem *mmio;
+	char *buf;
+	size_t buf_size;
+	ssize_t ret, off;
+	union { u64 v64; u32 v32; u16 v16; u8 v8; } u;
+
+	ndev = filp->private_data;
+	pdev = ndev->ntb.pdev;
+	mmio = ndev->self_mmio;
+
+	buf_size = min(count, 0x800ul);
+
+	buf = kmalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	off = 0;
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB Device Information:\n");
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Connection Topology -\t%s\n",
+			 ntb_topo_string(ndev->ntb.topo));
+
+	if (ndev->b2b_idx != UINT_MAX) {
+		off += scnprintf(buf + off, buf_size - off,
+				 "B2B MW Idx -\t\t%u\n", ndev->b2b_idx);
+		off += scnprintf(buf + off, buf_size - off,
+				 "B2B Offset -\t\t%#lx\n", ndev->b2b_off);
+	}
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "BAR4 Split -\t\t%s\n",
+			 ndev->bar4_split ? "yes" : "no");
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LNK STA -\t\t%#06x\n", ndev->lnk_sta);
+
+	if (!ndev->reg->link_is_up(ndev)) {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Status -\t\tDown\n");
+	} else {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Status -\t\tUp\n");
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Speed -\t\tPCI-E Gen %u\n",
+				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Width -\t\tx%u\n",
+				 NTB_LNK_STA_WIDTH(ndev->lnk_sta));
+	}
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Memory Window Count -\t%u\n", ndev->mw_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Scratchpad Count -\t%u\n", ndev->spad_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Count -\t%u\n", ndev->db_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Vector Count -\t%u\n", ndev->db_vec_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
+
+	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask -\t\t%#llx\n", u.v64);
+
+	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Bell -\t\t%#llx\n", u.v64);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Window Size:\n");
+
+	pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &u.v8);
+	off += scnprintf(buf + off, buf_size - off,
+			 "PBAR23SZ %hhu\n", u.v8);
+	if (!ndev->bar4_split) {
+		pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &u.v8);
+		off += scnprintf(buf + off, buf_size - off,
+				 "PBAR45SZ %hhu\n", u.v8);
+	} else {
+		pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &u.v8);
+		off += scnprintf(buf + off, buf_size - off,
+				 "PBAR4SZ %hhu\n", u.v8);
+		pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &u.v8);
+		off += scnprintf(buf + off, buf_size - off,
+				 "PBAR5SZ %hhu\n", u.v8);
+	}
+
+	pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &u.v8);
+	off += scnprintf(buf + off, buf_size - off,
+			 "SBAR23SZ %hhu\n", u.v8);
+	if (!ndev->bar4_split) {
+		pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &u.v8);
+		off += scnprintf(buf + off, buf_size - off,
+				 "SBAR45SZ %hhu\n", u.v8);
+	} else {
+		pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &u.v8);
+		off += scnprintf(buf + off, buf_size - off,
+				 "SBAR4SZ %hhu\n", u.v8);
+		pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &u.v8);
+		off += scnprintf(buf + off, buf_size - off,
+				 "SBAR5SZ %hhu\n", u.v8);
+	}
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Incoming XLAT:\n");
+
+	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2));
+	off += scnprintf(buf + off, buf_size - off,
+			 "XLAT23 -\t\t%#018llx\n", u.v64);
+
+	if (ndev->bar4_split) {
+		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
+		off += scnprintf(buf + off, buf_size - off,
+				 "XLAT4 -\t\t\t%#06x\n", u.v32);
+
+		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 5));
+		off += scnprintf(buf + off, buf_size - off,
+				 "XLAT5 -\t\t\t%#06x\n", u.v32);
+	} else {
+		u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
+		off += scnprintf(buf + off, buf_size - off,
+				 "XLAT45 -\t\t%#018llx\n", u.v64);
+	}
+
+	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2));
+	off += scnprintf(buf + off, buf_size - off,
+			 "LMT23 -\t\t\t%#018llx\n", u.v64);
+
+	if (ndev->bar4_split) {
+		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
+		off += scnprintf(buf + off, buf_size - off,
+				 "LMT4 -\t\t\t%#06x\n", u.v32);
+		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 5));
+		off += scnprintf(buf + off, buf_size - off,
+				 "LMT5 -\t\t\t%#06x\n", u.v32);
+	} else {
+		u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
+		off += scnprintf(buf + off, buf_size - off,
+				 "LMT45 -\t\t\t%#018llx\n", u.v64);
+	}
+
+	if (pdev_is_gen1(pdev)) {
+		if (ntb_topo_is_b2b(ndev->ntb.topo)) {
+			off += scnprintf(buf + off, buf_size - off,
+					 "\nNTB Outgoing B2B XLAT:\n");
+
+			u.v64 = ioread64(mmio + XEON_PBAR23XLAT_OFFSET);
+			off += scnprintf(buf + off, buf_size - off,
+					 "B2B XLAT23 -\t\t%#018llx\n", u.v64);
+
+			if (ndev->bar4_split) {
+				u.v32 = ioread32(mmio + XEON_PBAR4XLAT_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "B2B XLAT4 -\t\t%#06x\n",
+						 u.v32);
+				u.v32 = ioread32(mmio + XEON_PBAR5XLAT_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "B2B XLAT5 -\t\t%#06x\n",
+						 u.v32);
+			} else {
+				u.v64 = ioread64(mmio + XEON_PBAR45XLAT_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "B2B XLAT45 -\t\t%#018llx\n",
+						 u.v64);
+			}
+
+			u.v64 = ioread64(mmio + XEON_PBAR23LMT_OFFSET);
+			off += scnprintf(buf + off, buf_size - off,
+					 "B2B LMT23 -\t\t%#018llx\n", u.v64);
+
+			if (ndev->bar4_split) {
+				u.v32 = ioread32(mmio + XEON_PBAR4LMT_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "B2B LMT4 -\t\t%#06x\n",
+						 u.v32);
+				u.v32 = ioread32(mmio + XEON_PBAR5LMT_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "B2B LMT5 -\t\t%#06x\n",
+						 u.v32);
+			} else {
+				u.v64 = ioread64(mmio + XEON_PBAR45LMT_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "B2B LMT45 -\t\t%#018llx\n",
+						 u.v64);
+			}
+
+			off += scnprintf(buf + off, buf_size - off,
+					 "\nNTB Secondary BAR:\n");
+
+			u.v64 = ioread64(mmio + XEON_SBAR0BASE_OFFSET);
+			off += scnprintf(buf + off, buf_size - off,
+					 "SBAR01 -\t\t%#018llx\n", u.v64);
+
+			u.v64 = ioread64(mmio + XEON_SBAR23BASE_OFFSET);
+			off += scnprintf(buf + off, buf_size - off,
+					 "SBAR23 -\t\t%#018llx\n", u.v64);
+
+			if (ndev->bar4_split) {
+				u.v32 = ioread32(mmio + XEON_SBAR4BASE_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "SBAR4 -\t\t\t%#06x\n", u.v32);
+				u.v32 = ioread32(mmio + XEON_SBAR5BASE_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "SBAR5 -\t\t\t%#06x\n", u.v32);
+			} else {
+				u.v64 = ioread64(mmio + XEON_SBAR45BASE_OFFSET);
+				off += scnprintf(buf + off, buf_size - off,
+						 "SBAR45 -\t\t%#018llx\n",
+						 u.v64);
+			}
+		}
+
+		off += scnprintf(buf + off, buf_size - off,
+				 "\nXEON NTB Statistics:\n");
+
+		u.v16 = ioread16(mmio + XEON_USMEMMISS_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "Upstream Memory Miss -\t%u\n", u.v16);
+
+		off += scnprintf(buf + off, buf_size - off,
+				 "\nXEON NTB Hardware Errors:\n");
+
+		if (!pci_read_config_word(pdev,
+					  XEON_DEVSTS_OFFSET, &u.v16))
+			off += scnprintf(buf + off, buf_size - off,
+					 "DEVSTS -\t\t%#06x\n", u.v16);
+
+		if (!pci_read_config_word(pdev,
+					  XEON_LINK_STATUS_OFFSET, &u.v16))
+			off += scnprintf(buf + off, buf_size - off,
+					 "LNKSTS -\t\t%#06x\n", u.v16);
+
+		if (!pci_read_config_dword(pdev,
+					   XEON_UNCERRSTS_OFFSET, &u.v32))
+			off += scnprintf(buf + off, buf_size - off,
+					 "UNCERRSTS -\t\t%#06x\n", u.v32);
+
+		if (!pci_read_config_dword(pdev,
+					   XEON_CORERRSTS_OFFSET, &u.v32))
+			off += scnprintf(buf + off, buf_size - off,
+					 "CORERRSTS -\t\t%#06x\n", u.v32);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
+				 size_t count, loff_t *offp)
+{
+	struct intel_ntb_dev *ndev = filp->private_data;
+
+	if (pdev_is_gen1(ndev->ntb.pdev))
+		return ndev_ntb_debugfs_read(filp, ubuf, count, offp);
+	else if (pdev_is_gen3(ndev->ntb.pdev))
+		return ndev_ntb3_debugfs_read(filp, ubuf, count, offp);
+
+	return -ENXIO;
+}
+
+static void ndev_init_debugfs(struct intel_ntb_dev *ndev)
+{
+	if (!debugfs_dir) {
+		ndev->debugfs_dir = NULL;
+		ndev->debugfs_info = NULL;
+	} else {
+		ndev->debugfs_dir =
+			debugfs_create_dir(pci_name(ndev->ntb.pdev),
+					   debugfs_dir);
+		if (!ndev->debugfs_dir)
+			ndev->debugfs_info = NULL;
+		else
+			ndev->debugfs_info =
+				debugfs_create_file("info", S_IRUSR,
+						    ndev->debugfs_dir, ndev,
+						    &intel_ntb_debugfs_info);
+	}
+}
+
+static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
+{
+	debugfs_remove_recursive(ndev->debugfs_dir);
+}
+
+int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
+{
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	return ntb_ndev(ntb)->mw_count;
+}
+
+int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
+			   resource_size_t *addr_align,
+			   resource_size_t *size_align,
+			   resource_size_t *size_max)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	resource_size_t bar_size, mw_size;
+	int bar;
+
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+		idx += 1;
+
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
+
+	if (idx == ndev->b2b_idx)
+		mw_size = bar_size - ndev->b2b_off;
+	else
+		mw_size = bar_size;
+
+	if (addr_align)
+		*addr_align = pci_resource_len(ndev->ntb.pdev, bar);
+
+	if (size_align)
+		*size_align = 1;
+
+	if (size_max)
+		*size_max = mw_size;
+
+	return 0;
+}
+
+static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
+				  dma_addr_t addr, resource_size_t size)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	unsigned long base_reg, xlat_reg, limit_reg;
+	resource_size_t bar_size, mw_size;
+	void __iomem *mmio;
+	u64 base, limit, reg_val;
+	int bar;
+
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+		idx += 1;
+
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
+
+	if (idx == ndev->b2b_idx)
+		mw_size = bar_size - ndev->b2b_off;
+	else
+		mw_size = bar_size;
+
+	/* hardware requires that addr is aligned to bar size */
+	if (addr & (bar_size - 1))
+		return -EINVAL;
+
+	/* make sure the range fits in the usable mw size */
+	if (size > mw_size)
+		return -EINVAL;
+
+	mmio = ndev->self_mmio;
+	base_reg = bar0_off(ndev->xlat_reg->bar0_base, bar);
+	xlat_reg = bar2_off(ndev->xlat_reg->bar2_xlat, bar);
+	limit_reg = bar2_off(ndev->xlat_reg->bar2_limit, bar);
+
+	if (bar < 4 || !ndev->bar4_split) {
+		base = ioread64(mmio + base_reg) & NTB_BAR_MASK_64;
+
+		/* Set the limit if supported, if size is not mw_size */
+		if (limit_reg && size != mw_size)
+			limit = base + size;
+		else
+			limit = 0;
+
+		/* set and verify setting the translation address */
+		iowrite64(addr, mmio + xlat_reg);
+		reg_val = ioread64(mmio + xlat_reg);
+		if (reg_val != addr) {
+			iowrite64(0, mmio + xlat_reg);
+			return -EIO;
+		}
+
+		/* set and verify setting the limit */
+		iowrite64(limit, mmio + limit_reg);
+		reg_val = ioread64(mmio + limit_reg);
+		if (reg_val != limit) {
+			iowrite64(base, mmio + limit_reg);
+			iowrite64(0, mmio + xlat_reg);
+			return -EIO;
+		}
+	} else {
+		/* split bar addr range must all be 32 bit */
+		if (addr & (~0ull << 32))
+			return -EINVAL;
+		if ((addr + size) & (~0ull << 32))
+			return -EINVAL;
+
+		base = ioread32(mmio + base_reg) & NTB_BAR_MASK_32;
+
+		/* Set the limit if supported, if size is not mw_size */
+		if (limit_reg && size != mw_size)
+			limit = base + size;
+		else
+			limit = 0;
+
+		/* set and verify setting the translation address */
+		iowrite32(addr, mmio + xlat_reg);
+		reg_val = ioread32(mmio + xlat_reg);
+		if (reg_val != addr) {
+			iowrite32(0, mmio + xlat_reg);
+			return -EIO;
+		}
+
+		/* set and verify setting the limit */
+		iowrite32(limit, mmio + limit_reg);
+		reg_val = ioread32(mmio + limit_reg);
+		if (reg_val != limit) {
+			iowrite32(base, mmio + limit_reg);
+			iowrite32(0, mmio + xlat_reg);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+u64 intel_ntb_link_is_up(struct ntb_dev *ntb, enum ntb_speed *speed,
+			 enum ntb_width *width)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	if (ndev->reg->link_is_up(ndev)) {
+		if (speed)
+			*speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
+		if (width)
+			*width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
+		return 1;
+	} else {
+		/* TODO MAYBE: is it possible to observe the link speed and
+		 * width while link is training? */
+		if (speed)
+			*speed = NTB_SPEED_NONE;
+		if (width)
+			*width = NTB_WIDTH_NONE;
+		return 0;
+	}
+}
+
+static int intel_ntb_link_enable(struct ntb_dev *ntb,
+				 enum ntb_speed max_speed,
+				 enum ntb_width max_width)
+{
+	struct intel_ntb_dev *ndev;
+	u32 ntb_ctl;
+
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return -EINVAL;
+
+	dev_dbg(&ntb->pdev->dev,
+		"Enabling link with max_speed %d max_width %d\n",
+		max_speed, max_width);
+	if (max_speed != NTB_SPEED_AUTO)
+		dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed);
+	if (max_width != NTB_WIDTH_AUTO)
+		dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width);
+
+	ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+	ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
+	ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+	ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+	if (ndev->bar4_split)
+		ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
+	iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+	return 0;
+}
+
+int intel_ntb_link_disable(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev;
+	u32 ntb_cntl;
+
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return -EINVAL;
+
+	dev_dbg(&ntb->pdev->dev, "Disabling link\n");
+
+	/* Bring NTB link down */
+	ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+	ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
+	ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
+	if (ndev->bar4_split)
+		ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
+	ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
+	iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+	return 0;
+}
+
+int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
+{
+	/* Numbers of inbound and outbound memory windows match */
+	return ntb_ndev(ntb)->mw_count;
+}
+
+int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+			       phys_addr_t *base, resource_size_t *size)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	int bar;
+
+	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+		idx += 1;
+
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	if (base)
+		*base = pci_resource_start(ndev->ntb.pdev, bar) +
+			(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+	if (size)
+		*size = pci_resource_len(ndev->ntb.pdev, bar) -
+			(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
+
+	return 0;
+}
+
+static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
+{
+	return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
+}
+
+u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb)
+{
+	return ntb_ndev(ntb)->db_valid_mask;
+}
+
+int intel_ntb_db_vector_count(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev;
+
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+	return ndev->db_vec_count;
+}
+
+u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	if (db_vector < 0 || db_vector > ndev->db_vec_count)
+		return 0;
+
+	return ndev->db_valid_mask & ndev_vec_mask(ndev, db_vector);
+}
+
+static u64 intel_ntb_db_read(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_read(ndev,
+			    ndev->self_mmio +
+			    ndev->self_reg->db_bell);
+}
+
+static int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_write(ndev, db_bits,
+			     ndev->self_mmio +
+			     ndev->self_reg->db_bell);
+}
+
+int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_set_mask(ndev, db_bits,
+				ndev->self_mmio +
+				ndev->self_reg->db_mask);
+}
+
+int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_clear_mask(ndev, db_bits,
+				  ndev->self_mmio +
+				  ndev->self_reg->db_mask);
+}
+
+int intel_ntb_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr,
+			   resource_size_t *db_size)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_addr(ndev, db_addr, db_size, ndev->peer_addr,
+			    ndev->peer_reg->db_bell);
+}
+
+static int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_write(ndev, db_bits,
+			     ndev->peer_mmio +
+			     ndev->peer_reg->db_bell);
+}
+
+int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb)
+{
+	return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD);
+}
+
+int intel_ntb_spad_count(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev;
+
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+	return ndev->spad_count;
+}
+
+u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_spad_read(ndev, idx,
+			      ndev->self_mmio +
+			      ndev->self_reg->spad);
+}
+
+int intel_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_spad_write(ndev, idx, val,
+			       ndev->self_mmio +
+			       ndev->self_reg->spad);
+}
+
+int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
+			     phys_addr_t *spad_addr)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
+			      ndev->peer_reg->spad);
+}
+
+u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_spad_read(ndev, sidx,
+			      ndev->peer_mmio +
+			      ndev->peer_reg->spad);
+}
+
+int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
+			      u32 val)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_spad_write(ndev, sidx, val,
+			       ndev->peer_mmio +
+			       ndev->peer_reg->spad);
+}
+
+static u64 xeon_db_ioread(void __iomem *mmio)
+{
+	return (u64)ioread16(mmio);
+}
+
+static void xeon_db_iowrite(u64 bits, void __iomem *mmio)
+{
+	iowrite16((u16)bits, mmio);
+}
+
+static int xeon_poll_link(struct intel_ntb_dev *ndev)
+{
+	u16 reg_val;
+	int rc;
+
+	ndev->reg->db_iowrite(ndev->db_link_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_bell);
+
+	rc = pci_read_config_word(ndev->ntb.pdev,
+				  XEON_LINK_STATUS_OFFSET, &reg_val);
+	if (rc)
+		return 0;
+
+	if (reg_val == ndev->lnk_sta)
+		return 0;
+
+	ndev->lnk_sta = reg_val;
+
+	return 1;
+}
+
+int xeon_link_is_up(struct intel_ntb_dev *ndev)
+{
+	if (ndev->ntb.topo == NTB_TOPO_SEC)
+		return 1;
+
+	return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
+}
+
+enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd)
+{
+	switch (ppd & XEON_PPD_TOPO_MASK) {
+	case XEON_PPD_TOPO_B2B_USD:
+		return NTB_TOPO_B2B_USD;
+
+	case XEON_PPD_TOPO_B2B_DSD:
+		return NTB_TOPO_B2B_DSD;
+
+	case XEON_PPD_TOPO_PRI_USD:
+	case XEON_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
+		return NTB_TOPO_PRI;
+
+	case XEON_PPD_TOPO_SEC_USD:
+	case XEON_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
+		return NTB_TOPO_SEC;
+	}
+
+	return NTB_TOPO_NONE;
+}
+
+static inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd)
+{
+	if (ppd & XEON_PPD_SPLIT_BAR_MASK) {
+		dev_dbg(&ndev->ntb.pdev->dev, "PPD %d split bar\n", ppd);
+		return 1;
+	}
+	return 0;
+}
+
+static int xeon_init_isr(struct intel_ntb_dev *ndev)
+{
+	return ndev_init_isr(ndev, XEON_DB_MSIX_VECTOR_COUNT,
+			     XEON_DB_MSIX_VECTOR_COUNT,
+			     XEON_DB_MSIX_VECTOR_SHIFT,
+			     XEON_DB_TOTAL_SHIFT);
+}
+
+static void xeon_deinit_isr(struct intel_ntb_dev *ndev)
+{
+	ndev_deinit_isr(ndev);
+}
+
+static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
+			     const struct intel_b2b_addr *addr,
+			     const struct intel_b2b_addr *peer_addr)
+{
+	struct pci_dev *pdev;
+	void __iomem *mmio;
+	resource_size_t bar_size;
+	phys_addr_t bar_addr;
+	int b2b_bar;
+	u8 bar_sz;
+
+	pdev = ndev->ntb.pdev;
+	mmio = ndev->self_mmio;
+
+	if (ndev->b2b_idx == UINT_MAX) {
+		dev_dbg(&pdev->dev, "not using b2b mw\n");
+		b2b_bar = 0;
+		ndev->b2b_off = 0;
+	} else {
+		b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx);
+		if (b2b_bar < 0)
+			return -EIO;
+
+		dev_dbg(&pdev->dev, "using b2b mw bar %d\n", b2b_bar);
+
+		bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar);
+
+		dev_dbg(&pdev->dev, "b2b bar size %#llx\n", bar_size);
+
+		if (b2b_mw_share && XEON_B2B_MIN_SIZE <= bar_size >> 1) {
+			dev_dbg(&pdev->dev, "b2b using first half of bar\n");
+			ndev->b2b_off = bar_size >> 1;
+		} else if (XEON_B2B_MIN_SIZE <= bar_size) {
+			dev_dbg(&pdev->dev, "b2b using whole bar\n");
+			ndev->b2b_off = 0;
+			--ndev->mw_count;
+		} else {
+			dev_dbg(&pdev->dev, "b2b bar size is too small\n");
+			return -EIO;
+		}
+	}
+
+	/* Reset the secondary bar sizes to match the primary bar sizes,
+	 * except disable or halve the size of the b2b secondary bar.
+	 *
+	 * Note: code for each specific bar size register, because the register
+	 * offsets are not in a consistent order (bar5sz comes after ppd, odd).
+	 */
+	pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &bar_sz);
+	dev_dbg(&pdev->dev, "PBAR23SZ %#x\n", bar_sz);
+	if (b2b_bar == 2) {
+		if (ndev->b2b_off)
+			bar_sz -= 1;
+		else
+			bar_sz = 0;
+	}
+	pci_write_config_byte(pdev, XEON_SBAR23SZ_OFFSET, bar_sz);
+	pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &bar_sz);
+	dev_dbg(&pdev->dev, "SBAR23SZ %#x\n", bar_sz);
+
+	if (!ndev->bar4_split) {
+		pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &bar_sz);
+		dev_dbg(&pdev->dev, "PBAR45SZ %#x\n", bar_sz);
+		if (b2b_bar == 4) {
+			if (ndev->b2b_off)
+				bar_sz -= 1;
+			else
+				bar_sz = 0;
+		}
+		pci_write_config_byte(pdev, XEON_SBAR45SZ_OFFSET, bar_sz);
+		pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &bar_sz);
+		dev_dbg(&pdev->dev, "SBAR45SZ %#x\n", bar_sz);
+	} else {
+		pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &bar_sz);
+		dev_dbg(&pdev->dev, "PBAR4SZ %#x\n", bar_sz);
+		if (b2b_bar == 4) {
+			if (ndev->b2b_off)
+				bar_sz -= 1;
+			else
+				bar_sz = 0;
+		}
+		pci_write_config_byte(pdev, XEON_SBAR4SZ_OFFSET, bar_sz);
+		pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &bar_sz);
+		dev_dbg(&pdev->dev, "SBAR4SZ %#x\n", bar_sz);
+
+		pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &bar_sz);
+		dev_dbg(&pdev->dev, "PBAR5SZ %#x\n", bar_sz);
+		if (b2b_bar == 5) {
+			if (ndev->b2b_off)
+				bar_sz -= 1;
+			else
+				bar_sz = 0;
+		}
+		pci_write_config_byte(pdev, XEON_SBAR5SZ_OFFSET, bar_sz);
+		pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &bar_sz);
+		dev_dbg(&pdev->dev, "SBAR5SZ %#x\n", bar_sz);
+	}
+
+	/* SBAR01 hit by first part of the b2b bar */
+	if (b2b_bar == 0)
+		bar_addr = addr->bar0_addr;
+	else if (b2b_bar == 2)
+		bar_addr = addr->bar2_addr64;
+	else if (b2b_bar == 4 && !ndev->bar4_split)
+		bar_addr = addr->bar4_addr64;
+	else if (b2b_bar == 4)
+		bar_addr = addr->bar4_addr32;
+	else if (b2b_bar == 5)
+		bar_addr = addr->bar5_addr32;
+	else
+		return -EIO;
+
+	dev_dbg(&pdev->dev, "SBAR01 %#018llx\n", bar_addr);
+	iowrite64(bar_addr, mmio + XEON_SBAR0BASE_OFFSET);
+
+	/* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
+	 * The b2b bar is either disabled above, or configured half-size, and
+	 * it starts at the PBAR xlat + offset.
+	 */
+
+	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
+	iowrite64(bar_addr, mmio + XEON_SBAR23BASE_OFFSET);
+	bar_addr = ioread64(mmio + XEON_SBAR23BASE_OFFSET);
+	dev_dbg(&pdev->dev, "SBAR23 %#018llx\n", bar_addr);
+
+	if (!ndev->bar4_split) {
+		bar_addr = addr->bar4_addr64 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite64(bar_addr, mmio + XEON_SBAR45BASE_OFFSET);
+		bar_addr = ioread64(mmio + XEON_SBAR45BASE_OFFSET);
+		dev_dbg(&pdev->dev, "SBAR45 %#018llx\n", bar_addr);
+	} else {
+		bar_addr = addr->bar4_addr32 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + XEON_SBAR4BASE_OFFSET);
+		bar_addr = ioread32(mmio + XEON_SBAR4BASE_OFFSET);
+		dev_dbg(&pdev->dev, "SBAR4 %#010llx\n", bar_addr);
+
+		bar_addr = addr->bar5_addr32 +
+			(b2b_bar == 5 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + XEON_SBAR5BASE_OFFSET);
+		bar_addr = ioread32(mmio + XEON_SBAR5BASE_OFFSET);
+		dev_dbg(&pdev->dev, "SBAR5 %#010llx\n", bar_addr);
+	}
+
+	/* setup incoming bar limits == base addrs (zero length windows) */
+
+	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
+	iowrite64(bar_addr, mmio + XEON_SBAR23LMT_OFFSET);
+	bar_addr = ioread64(mmio + XEON_SBAR23LMT_OFFSET);
+	dev_dbg(&pdev->dev, "SBAR23LMT %#018llx\n", bar_addr);
+
+	if (!ndev->bar4_split) {
+		bar_addr = addr->bar4_addr64 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite64(bar_addr, mmio + XEON_SBAR45LMT_OFFSET);
+		bar_addr = ioread64(mmio + XEON_SBAR45LMT_OFFSET);
+		dev_dbg(&pdev->dev, "SBAR45LMT %#018llx\n", bar_addr);
+	} else {
+		bar_addr = addr->bar4_addr32 +
+			(b2b_bar == 4 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + XEON_SBAR4LMT_OFFSET);
+		bar_addr = ioread32(mmio + XEON_SBAR4LMT_OFFSET);
+		dev_dbg(&pdev->dev, "SBAR4LMT %#010llx\n", bar_addr);
+
+		bar_addr = addr->bar5_addr32 +
+			(b2b_bar == 5 ? ndev->b2b_off : 0);
+		iowrite32(bar_addr, mmio + XEON_SBAR5LMT_OFFSET);
+		bar_addr = ioread32(mmio + XEON_SBAR5LMT_OFFSET);
+		dev_dbg(&pdev->dev, "SBAR5LMT %#05llx\n", bar_addr);
+	}
+
+	/* zero incoming translation addrs */
+	iowrite64(0, mmio + XEON_SBAR23XLAT_OFFSET);
+
+	if (!ndev->bar4_split) {
+		iowrite64(0, mmio + XEON_SBAR45XLAT_OFFSET);
+	} else {
+		iowrite32(0, mmio + XEON_SBAR4XLAT_OFFSET);
+		iowrite32(0, mmio + XEON_SBAR5XLAT_OFFSET);
+	}
+
+	/* zero outgoing translation limits (whole bar size windows) */
+	iowrite64(0, mmio + XEON_PBAR23LMT_OFFSET);
+	if (!ndev->bar4_split) {
+		iowrite64(0, mmio + XEON_PBAR45LMT_OFFSET);
+	} else {
+		iowrite32(0, mmio + XEON_PBAR4LMT_OFFSET);
+		iowrite32(0, mmio + XEON_PBAR5LMT_OFFSET);
+	}
+
+	/* set outgoing translation offsets */
+	bar_addr = peer_addr->bar2_addr64;
+	iowrite64(bar_addr, mmio + XEON_PBAR23XLAT_OFFSET);
+	bar_addr = ioread64(mmio + XEON_PBAR23XLAT_OFFSET);
+	dev_dbg(&pdev->dev, "PBAR23XLAT %#018llx\n", bar_addr);
+
+	if (!ndev->bar4_split) {
+		bar_addr = peer_addr->bar4_addr64;
+		iowrite64(bar_addr, mmio + XEON_PBAR45XLAT_OFFSET);
+		bar_addr = ioread64(mmio + XEON_PBAR45XLAT_OFFSET);
+		dev_dbg(&pdev->dev, "PBAR45XLAT %#018llx\n", bar_addr);
+	} else {
+		bar_addr = peer_addr->bar4_addr32;
+		iowrite32(bar_addr, mmio + XEON_PBAR4XLAT_OFFSET);
+		bar_addr = ioread32(mmio + XEON_PBAR4XLAT_OFFSET);
+		dev_dbg(&pdev->dev, "PBAR4XLAT %#010llx\n", bar_addr);
+
+		bar_addr = peer_addr->bar5_addr32;
+		iowrite32(bar_addr, mmio + XEON_PBAR5XLAT_OFFSET);
+		bar_addr = ioread32(mmio + XEON_PBAR5XLAT_OFFSET);
+		dev_dbg(&pdev->dev, "PBAR5XLAT %#010llx\n", bar_addr);
+	}
+
+	/* set the translation offset for b2b registers */
+	if (b2b_bar == 0)
+		bar_addr = peer_addr->bar0_addr;
+	else if (b2b_bar == 2)
+		bar_addr = peer_addr->bar2_addr64;
+	else if (b2b_bar == 4 && !ndev->bar4_split)
+		bar_addr = peer_addr->bar4_addr64;
+	else if (b2b_bar == 4)
+		bar_addr = peer_addr->bar4_addr32;
+	else if (b2b_bar == 5)
+		bar_addr = peer_addr->bar5_addr32;
+	else
+		return -EIO;
+
+	/* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */
+	dev_dbg(&pdev->dev, "B2BXLAT %#018llx\n", bar_addr);
+	iowrite32(bar_addr, mmio + XEON_B2B_XLAT_OFFSETL);
+	iowrite32(bar_addr >> 32, mmio + XEON_B2B_XLAT_OFFSETU);
+
+	if (b2b_bar) {
+		/* map peer ntb mmio config space registers */
+		ndev->peer_mmio = pci_iomap(pdev, b2b_bar,
+					    XEON_B2B_MIN_SIZE);
+		if (!ndev->peer_mmio)
+			return -EIO;
+
+		ndev->peer_addr = pci_resource_start(pdev, b2b_bar);
+	}
+
+	return 0;
+}
+
+static int xeon_init_ntb(struct intel_ntb_dev *ndev)
+{
+	struct device *dev = &ndev->ntb.pdev->dev;
+	int rc;
+	u32 ntb_ctl;
+
+	if (ndev->bar4_split)
+		ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
+	else
+		ndev->mw_count = XEON_MW_COUNT;
+
+	ndev->spad_count = XEON_SPAD_COUNT;
+	ndev->db_count = XEON_DB_COUNT;
+	ndev->db_link_mask = XEON_DB_LINK_BIT;
+
+	switch (ndev->ntb.topo) {
+	case NTB_TOPO_PRI:
+		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+			dev_err(dev, "NTB Primary config disabled\n");
+			return -EINVAL;
+		}
+
+		/* enable link to allow secondary side device to appear */
+		ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+		ntb_ctl &= ~NTB_CTL_DISABLE;
+		iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+		/* use half the spads for the peer */
+		ndev->spad_count >>= 1;
+		ndev->self_reg = &xeon_pri_reg;
+		ndev->peer_reg = &xeon_sec_reg;
+		ndev->xlat_reg = &xeon_sec_xlat;
+		break;
+
+	case NTB_TOPO_SEC:
+		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+			dev_err(dev, "NTB Secondary config disabled\n");
+			return -EINVAL;
+		}
+		/* use half the spads for the peer */
+		ndev->spad_count >>= 1;
+		ndev->self_reg = &xeon_sec_reg;
+		ndev->peer_reg = &xeon_pri_reg;
+		ndev->xlat_reg = &xeon_pri_xlat;
+		break;
+
+	case NTB_TOPO_B2B_USD:
+	case NTB_TOPO_B2B_DSD:
+		ndev->self_reg = &xeon_pri_reg;
+		ndev->peer_reg = &xeon_b2b_reg;
+		ndev->xlat_reg = &xeon_sec_xlat;
+
+		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
+			ndev->peer_reg = &xeon_pri_reg;
+
+			if (b2b_mw_idx < 0)
+				ndev->b2b_idx = b2b_mw_idx + ndev->mw_count;
+			else
+				ndev->b2b_idx = b2b_mw_idx;
+
+			if (ndev->b2b_idx >= ndev->mw_count) {
+				dev_dbg(dev,
+					"b2b_mw_idx %d invalid for mw_count %u\n",
+					b2b_mw_idx, ndev->mw_count);
+				return -EINVAL;
+			}
+
+			dev_dbg(dev, "setting up b2b mw idx %d means %d\n",
+				b2b_mw_idx, ndev->b2b_idx);
+
+		} else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) {
+			dev_warn(dev, "Reduce doorbell count by 1\n");
+			ndev->db_count -= 1;
+		}
+
+		if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
+			rc = xeon_setup_b2b_mw(ndev,
+					       &xeon_b2b_dsd_addr,
+					       &xeon_b2b_usd_addr);
+		} else {
+			rc = xeon_setup_b2b_mw(ndev,
+					       &xeon_b2b_usd_addr,
+					       &xeon_b2b_dsd_addr);
+		}
+		if (rc)
+			return rc;
+
+		/* Enable Bus Master and Memory Space on the secondary side */
+		iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+			  ndev->self_mmio + XEON_SPCICMD_OFFSET);
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
+
+	ndev->reg->db_iowrite(ndev->db_valid_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
+
+	return 0;
+}
+
+static int xeon_init_dev(struct intel_ntb_dev *ndev)
+{
+	struct pci_dev *pdev;
+	u8 ppd;
+	int rc, mem;
+
+	pdev = ndev->ntb.pdev;
+
+	switch (pdev->device) {
+	/* There is a Xeon hardware errata related to writes to SDOORBELL or
+	 * B2BDOORBELL in conjunction with inbound access to NTB MMIO Space,
+	 * which may hang the system.  To workaround this use the second memory
+	 * window to access the interrupt and scratch pad registers on the
+	 * remote system.
+	 */
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
+		ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
+		break;
+	}
+
+	switch (pdev->device) {
+	/* There is a hardware errata related to accessing any register in
+	 * SB01BASE in the presence of bidirectional traffic crossing the NTB.
+	 */
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
+		ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
+		break;
+	}
+
+	switch (pdev->device) {
+	/* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
+	 * mirrored to the remote system.  Shrink the number of bits by one,
+	 * since bit 14 is the last bit.
+	 */
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
+		ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
+		break;
+	}
+
+	ndev->reg = &xeon_reg;
+
+	rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd);
+	if (rc)
+		return -EIO;
+
+	ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
+	dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd,
+		ntb_topo_string(ndev->ntb.topo));
+	if (ndev->ntb.topo == NTB_TOPO_NONE)
+		return -EINVAL;
+
+	if (ndev->ntb.topo != NTB_TOPO_SEC) {
+		ndev->bar4_split = xeon_ppd_bar4_split(ndev, ppd);
+		dev_dbg(&pdev->dev, "ppd %#x bar4_split %d\n",
+			ppd, ndev->bar4_split);
+	} else {
+		/* This is a way for transparent BAR to figure out if we are
+		 * doing split BAR or not. There is no way for the hw on the
+		 * transparent side to know and set the PPD.
+		 */
+		mem = pci_select_bars(pdev, IORESOURCE_MEM);
+		ndev->bar4_split = hweight32(mem) ==
+			HSX_SPLIT_BAR_MW_COUNT + 1;
+		dev_dbg(&pdev->dev, "mem %#x bar4_split %d\n",
+			mem, ndev->bar4_split);
+	}
+
+	rc = xeon_init_ntb(ndev);
+	if (rc)
+		return rc;
+
+	return xeon_init_isr(ndev);
+}
+
+static void xeon_deinit_dev(struct intel_ntb_dev *ndev)
+{
+	xeon_deinit_isr(ndev);
+}
+
+static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev)
+{
+	int rc;
+
+	pci_set_drvdata(pdev, ndev);
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_pci_enable;
+
+	rc = pci_request_regions(pdev, NTB_NAME);
+	if (rc)
+		goto err_pci_regions;
+
+	pci_set_master(pdev);
+
+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err_dma_mask;
+		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
+	}
+
+	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (rc) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (rc)
+			goto err_dma_mask;
+		dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
+	}
+	rc = dma_coerce_mask_and_coherent(&ndev->ntb.dev,
+					  dma_get_mask(&pdev->dev));
+	if (rc)
+		goto err_dma_mask;
+
+	ndev->self_mmio = pci_iomap(pdev, 0, 0);
+	if (!ndev->self_mmio) {
+		rc = -EIO;
+		goto err_mmio;
+	}
+	ndev->peer_mmio = ndev->self_mmio;
+	ndev->peer_addr = pci_resource_start(pdev, 0);
+
+	return 0;
+
+err_mmio:
+err_dma_mask:
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+err_pci_regions:
+	pci_disable_device(pdev);
+err_pci_enable:
+	pci_set_drvdata(pdev, NULL);
+	return rc;
+}
+
+static void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev)
+{
+	struct pci_dev *pdev = ndev->ntb.pdev;
+
+	if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio)
+		pci_iounmap(pdev, ndev->peer_mmio);
+	pci_iounmap(pdev, ndev->self_mmio);
+
+	pci_clear_master(pdev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static inline void ndev_init_struct(struct intel_ntb_dev *ndev,
+				    struct pci_dev *pdev)
+{
+	ndev->ntb.pdev = pdev;
+	ndev->ntb.topo = NTB_TOPO_NONE;
+	ndev->ntb.ops = &intel_ntb_ops;
+
+	ndev->b2b_off = 0;
+	ndev->b2b_idx = UINT_MAX;
+
+	ndev->bar4_split = 0;
+
+	ndev->mw_count = 0;
+	ndev->spad_count = 0;
+	ndev->db_count = 0;
+	ndev->db_vec_count = 0;
+	ndev->db_vec_shift = 0;
+
+	ndev->ntb_ctl = 0;
+	ndev->lnk_sta = 0;
+
+	ndev->db_valid_mask = 0;
+	ndev->db_link_mask = 0;
+	ndev->db_mask = 0;
+
+	spin_lock_init(&ndev->db_mask_lock);
+}
+
+static int intel_ntb_pci_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	struct intel_ntb_dev *ndev;
+	int rc, node;
+
+	node = dev_to_node(&pdev->dev);
+
+	if (pdev_is_gen1(pdev)) {
+		ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node);
+		if (!ndev) {
+			rc = -ENOMEM;
+			goto err_ndev;
+		}
+
+		ndev_init_struct(ndev, pdev);
+
+		rc = intel_ntb_init_pci(ndev, pdev);
+		if (rc)
+			goto err_init_pci;
+
+		rc = xeon_init_dev(ndev);
+		if (rc)
+			goto err_init_dev;
+
+	} else if (pdev_is_gen3(pdev)) {
+		ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node);
+		if (!ndev) {
+			rc = -ENOMEM;
+			goto err_ndev;
+		}
+
+		ndev_init_struct(ndev, pdev);
+		ndev->ntb.ops = &intel_ntb3_ops;
+
+		rc = intel_ntb_init_pci(ndev, pdev);
+		if (rc)
+			goto err_init_pci;
+
+		rc = gen3_init_dev(ndev);
+		if (rc)
+			goto err_init_dev;
+
+	} else {
+		rc = -EINVAL;
+		goto err_ndev;
+	}
+
+	ndev_reset_unsafe_flags(ndev);
+
+	ndev->reg->poll_link(ndev);
+
+	ndev_init_debugfs(ndev);
+
+	rc = ntb_register_device(&ndev->ntb);
+	if (rc)
+		goto err_register;
+
+	dev_info(&pdev->dev, "NTB device registered.\n");
+
+	return 0;
+
+err_register:
+	ndev_deinit_debugfs(ndev);
+	if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev))
+		xeon_deinit_dev(ndev);
+err_init_dev:
+	intel_ntb_deinit_pci(ndev);
+err_init_pci:
+	kfree(ndev);
+err_ndev:
+	return rc;
+}
+
+static void intel_ntb_pci_remove(struct pci_dev *pdev)
+{
+	struct intel_ntb_dev *ndev = pci_get_drvdata(pdev);
+
+	ntb_unregister_device(&ndev->ntb);
+	ndev_deinit_debugfs(ndev);
+	if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev))
+		xeon_deinit_dev(ndev);
+	intel_ntb_deinit_pci(ndev);
+	kfree(ndev);
+}
+
+static const struct intel_ntb_reg xeon_reg = {
+	.poll_link		= xeon_poll_link,
+	.link_is_up		= xeon_link_is_up,
+	.db_ioread		= xeon_db_ioread,
+	.db_iowrite		= xeon_db_iowrite,
+	.db_size		= sizeof(u32),
+	.ntb_ctl		= XEON_NTBCNTL_OFFSET,
+	.mw_bar			= {2, 4, 5},
+};
+
+static const struct intel_ntb_alt_reg xeon_pri_reg = {
+	.db_bell		= XEON_PDOORBELL_OFFSET,
+	.db_mask		= XEON_PDBMSK_OFFSET,
+	.spad			= XEON_SPAD_OFFSET,
+};
+
+static const struct intel_ntb_alt_reg xeon_sec_reg = {
+	.db_bell		= XEON_SDOORBELL_OFFSET,
+	.db_mask		= XEON_SDBMSK_OFFSET,
+	/* second half of the scratchpads */
+	.spad			= XEON_SPAD_OFFSET + (XEON_SPAD_COUNT << 1),
+};
+
+static const struct intel_ntb_alt_reg xeon_b2b_reg = {
+	.db_bell		= XEON_B2B_DOORBELL_OFFSET,
+	.spad			= XEON_B2B_SPAD_OFFSET,
+};
+
+static const struct intel_ntb_xlat_reg xeon_pri_xlat = {
+	/* Note: no primary .bar0_base visible to the secondary side.
+	 *
+	 * The secondary side cannot get the base address stored in primary
+	 * bars.  The base address is necessary to set the limit register to
+	 * any value other than zero, or unlimited.
+	 *
+	 * WITHOUT THE BASE ADDRESS, THE SECONDARY SIDE CANNOT DISABLE the
+	 * window by setting the limit equal to base, nor can it limit the size
+	 * of the memory window by setting the limit to base + size.
+	 */
+	.bar2_limit		= XEON_PBAR23LMT_OFFSET,
+	.bar2_xlat		= XEON_PBAR23XLAT_OFFSET,
+};
+
+static const struct intel_ntb_xlat_reg xeon_sec_xlat = {
+	.bar0_base		= XEON_SBAR0BASE_OFFSET,
+	.bar2_limit		= XEON_SBAR23LMT_OFFSET,
+	.bar2_xlat		= XEON_SBAR23XLAT_OFFSET,
+};
+
+struct intel_b2b_addr xeon_b2b_usd_addr = {
+	.bar2_addr64		= XEON_B2B_BAR2_ADDR64,
+	.bar4_addr64		= XEON_B2B_BAR4_ADDR64,
+	.bar4_addr32		= XEON_B2B_BAR4_ADDR32,
+	.bar5_addr32		= XEON_B2B_BAR5_ADDR32,
+};
+
+struct intel_b2b_addr xeon_b2b_dsd_addr = {
+	.bar2_addr64		= XEON_B2B_BAR2_ADDR64,
+	.bar4_addr64		= XEON_B2B_BAR4_ADDR64,
+	.bar4_addr32		= XEON_B2B_BAR4_ADDR32,
+	.bar5_addr32		= XEON_B2B_BAR5_ADDR32,
+};
+
+/* operations for primary side of local ntb */
+static const struct ntb_dev_ops intel_ntb_ops = {
+	.mw_count		= intel_ntb_mw_count,
+	.mw_get_align		= intel_ntb_mw_get_align,
+	.mw_set_trans		= intel_ntb_mw_set_trans,
+	.peer_mw_count		= intel_ntb_peer_mw_count,
+	.peer_mw_get_addr	= intel_ntb_peer_mw_get_addr,
+	.link_is_up		= intel_ntb_link_is_up,
+	.link_enable		= intel_ntb_link_enable,
+	.link_disable		= intel_ntb_link_disable,
+	.db_is_unsafe		= intel_ntb_db_is_unsafe,
+	.db_valid_mask		= intel_ntb_db_valid_mask,
+	.db_vector_count	= intel_ntb_db_vector_count,
+	.db_vector_mask		= intel_ntb_db_vector_mask,
+	.db_read		= intel_ntb_db_read,
+	.db_clear		= intel_ntb_db_clear,
+	.db_set_mask		= intel_ntb_db_set_mask,
+	.db_clear_mask		= intel_ntb_db_clear_mask,
+	.peer_db_addr		= intel_ntb_peer_db_addr,
+	.peer_db_set		= intel_ntb_peer_db_set,
+	.spad_is_unsafe		= intel_ntb_spad_is_unsafe,
+	.spad_count		= intel_ntb_spad_count,
+	.spad_read		= intel_ntb_spad_read,
+	.spad_write		= intel_ntb_spad_write,
+	.peer_spad_addr		= intel_ntb_peer_spad_addr,
+	.peer_spad_read		= intel_ntb_peer_spad_read,
+	.peer_spad_write	= intel_ntb_peer_spad_write,
+};
+
+static const struct file_operations intel_ntb_debugfs_info = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = ndev_debugfs_read,
+};
+
+static const struct pci_device_id intel_ntb_pci_tbl[] = {
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BDX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_BDX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_BDX)},
+	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SKX)},
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl);
+
+static struct pci_driver intel_ntb_pci_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = intel_ntb_pci_tbl,
+	.probe = intel_ntb_pci_probe,
+	.remove = intel_ntb_pci_remove,
+};
+
+static int __init intel_ntb_pci_driver_init(void)
+{
+	pr_info("%s %s\n", NTB_DESC, NTB_VER);
+
+	if (debugfs_initialized())
+		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+	return pci_register_driver(&intel_ntb_pci_driver);
+}
+module_init(intel_ntb_pci_driver_init);
+
+static void __exit intel_ntb_pci_driver_exit(void)
+{
+	pci_unregister_driver(&intel_ntb_pci_driver);
+
+	debugfs_remove_recursive(debugfs_dir);
+}
+module_exit(intel_ntb_pci_driver_exit);
diff --git a/drivers/ntb/hw/intel/ntb_hw_gen1.h b/drivers/ntb/hw/intel/ntb_hw_gen1.h
new file mode 100644
index 000000000000..ad8ec1444436
--- /dev/null
+++ b/drivers/ntb/hw/intel/ntb_hw_gen1.h
@@ -0,0 +1,182 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2012-2017 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2012-2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NTB_INTEL_GEN1_H_
+#define _NTB_INTEL_GEN1_H_
+
+#include "ntb_hw_intel.h"
+
+/* Intel Gen1 Xeon hardware */
+#define XEON_PBAR23LMT_OFFSET		0x0000
+#define XEON_PBAR45LMT_OFFSET		0x0008
+#define XEON_PBAR4LMT_OFFSET		0x0008
+#define XEON_PBAR5LMT_OFFSET		0x000c
+#define XEON_PBAR23XLAT_OFFSET		0x0010
+#define XEON_PBAR45XLAT_OFFSET		0x0018
+#define XEON_PBAR4XLAT_OFFSET		0x0018
+#define XEON_PBAR5XLAT_OFFSET		0x001c
+#define XEON_SBAR23LMT_OFFSET		0x0020
+#define XEON_SBAR45LMT_OFFSET		0x0028
+#define XEON_SBAR4LMT_OFFSET		0x0028
+#define XEON_SBAR5LMT_OFFSET		0x002c
+#define XEON_SBAR23XLAT_OFFSET		0x0030
+#define XEON_SBAR45XLAT_OFFSET		0x0038
+#define XEON_SBAR4XLAT_OFFSET		0x0038
+#define XEON_SBAR5XLAT_OFFSET		0x003c
+#define XEON_SBAR0BASE_OFFSET		0x0040
+#define XEON_SBAR23BASE_OFFSET		0x0048
+#define XEON_SBAR45BASE_OFFSET		0x0050
+#define XEON_SBAR4BASE_OFFSET		0x0050
+#define XEON_SBAR5BASE_OFFSET		0x0054
+#define XEON_SBDF_OFFSET		0x005c
+#define XEON_NTBCNTL_OFFSET		0x0058
+#define XEON_PDOORBELL_OFFSET		0x0060
+#define XEON_PDBMSK_OFFSET		0x0062
+#define XEON_SDOORBELL_OFFSET		0x0064
+#define XEON_SDBMSK_OFFSET		0x0066
+#define XEON_USMEMMISS_OFFSET		0x0070
+#define XEON_SPAD_OFFSET		0x0080
+#define XEON_PBAR23SZ_OFFSET		0x00d0
+#define XEON_PBAR45SZ_OFFSET		0x00d1
+#define XEON_PBAR4SZ_OFFSET		0x00d1
+#define XEON_SBAR23SZ_OFFSET		0x00d2
+#define XEON_SBAR45SZ_OFFSET		0x00d3
+#define XEON_SBAR4SZ_OFFSET		0x00d3
+#define XEON_PPD_OFFSET			0x00d4
+#define XEON_PBAR5SZ_OFFSET		0x00d5
+#define XEON_SBAR5SZ_OFFSET		0x00d6
+#define XEON_WCCNTRL_OFFSET		0x00e0
+#define XEON_UNCERRSTS_OFFSET		0x014c
+#define XEON_CORERRSTS_OFFSET		0x0158
+#define XEON_LINK_STATUS_OFFSET		0x01a2
+#define XEON_SPCICMD_OFFSET		0x0504
+#define XEON_DEVCTRL_OFFSET		0x0598
+#define XEON_DEVSTS_OFFSET		0x059a
+#define XEON_SLINK_STATUS_OFFSET	0x05a2
+#define XEON_B2B_SPAD_OFFSET		0x0100
+#define XEON_B2B_DOORBELL_OFFSET	0x0140
+#define XEON_B2B_XLAT_OFFSETL		0x0144
+#define XEON_B2B_XLAT_OFFSETU		0x0148
+#define XEON_PPD_CONN_MASK		0x03
+#define XEON_PPD_CONN_TRANSPARENT	0x00
+#define XEON_PPD_CONN_B2B		0x01
+#define XEON_PPD_CONN_RP		0x02
+#define XEON_PPD_DEV_MASK		0x10
+#define XEON_PPD_DEV_USD		0x00
+#define XEON_PPD_DEV_DSD		0x10
+#define XEON_PPD_SPLIT_BAR_MASK		0x40
+
+#define XEON_PPD_TOPO_MASK	(XEON_PPD_CONN_MASK | XEON_PPD_DEV_MASK)
+#define XEON_PPD_TOPO_PRI_USD	(XEON_PPD_CONN_RP | XEON_PPD_DEV_USD)
+#define XEON_PPD_TOPO_PRI_DSD	(XEON_PPD_CONN_RP | XEON_PPD_DEV_DSD)
+#define XEON_PPD_TOPO_SEC_USD	(XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_USD)
+#define XEON_PPD_TOPO_SEC_DSD	(XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_DSD)
+#define XEON_PPD_TOPO_B2B_USD	(XEON_PPD_CONN_B2B | XEON_PPD_DEV_USD)
+#define XEON_PPD_TOPO_B2B_DSD	(XEON_PPD_CONN_B2B | XEON_PPD_DEV_DSD)
+
+#define XEON_MW_COUNT			2
+#define HSX_SPLIT_BAR_MW_COUNT		3
+#define XEON_DB_COUNT			15
+#define XEON_DB_LINK			15
+#define XEON_DB_LINK_BIT			BIT_ULL(XEON_DB_LINK)
+#define XEON_DB_MSIX_VECTOR_COUNT	4
+#define XEON_DB_MSIX_VECTOR_SHIFT	5
+#define XEON_DB_TOTAL_SHIFT		16
+#define XEON_SPAD_COUNT			16
+
+/* Use the following addresses for translation between b2b ntb devices in case
+ * the hardware default values are not reliable. */
+#define XEON_B2B_BAR0_ADDR	0x1000000000000000ull
+#define XEON_B2B_BAR2_ADDR64	0x2000000000000000ull
+#define XEON_B2B_BAR4_ADDR64	0x4000000000000000ull
+#define XEON_B2B_BAR4_ADDR32	0x20000000u
+#define XEON_B2B_BAR5_ADDR32	0x40000000u
+
+/* The peer ntb secondary config space is 32KB fixed size */
+#define XEON_B2B_MIN_SIZE		0x8000
+
+/* flags to indicate hardware errata */
+#define NTB_HWERR_SDOORBELL_LOCKUP	BIT_ULL(0)
+#define NTB_HWERR_SB01BASE_LOCKUP	BIT_ULL(1)
+#define NTB_HWERR_B2BDOORBELL_BIT14	BIT_ULL(2)
+#define NTB_HWERR_MSIX_VECTOR32_BAD	BIT_ULL(3)
+
+extern struct intel_b2b_addr xeon_b2b_usd_addr;
+extern struct intel_b2b_addr xeon_b2b_dsd_addr;
+
+int ndev_init_isr(struct intel_ntb_dev *ndev, int msix_min, int msix_max,
+		int msix_shift, int total_shift);
+enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd);
+u64 ndev_db_read(struct intel_ntb_dev *ndev, void __iomem *mmio);
+int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits,
+				void __iomem *mmio);
+int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx);
+int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx);
+int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
+		resource_size_t *addr_align, resource_size_t *size_align,
+		resource_size_t *size_max);
+int intel_ntb_peer_mw_count(struct ntb_dev *ntb);
+int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
+		phys_addr_t *base, resource_size_t *size);
+u64 intel_ntb_link_is_up(struct ntb_dev *ntb, enum ntb_speed *speed,
+		enum ntb_width *width);
+int intel_ntb_link_disable(struct ntb_dev *ntb);
+u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb);
+int intel_ntb_db_vector_count(struct ntb_dev *ntb);
+u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector);
+int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits);
+int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits);
+int intel_ntb_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr,
+		resource_size_t *db_size);
+int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb);
+int intel_ntb_spad_count(struct ntb_dev *ntb);
+u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx);
+int intel_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val);
+u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx);
+int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx,
+		u32 val);
+int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
+				    phys_addr_t *spad_addr);
+int xeon_link_is_up(struct intel_ntb_dev *ndev);
+
+#endif
diff --git a/drivers/ntb/hw/intel/ntb_hw_gen3.c b/drivers/ntb/hw/intel/ntb_hw_gen3.c
new file mode 100644
index 000000000000..b3fa24778f94
--- /dev/null
+++ b/drivers/ntb/hw/intel/ntb_hw_gen3.c
@@ -0,0 +1,597 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Intel PCIe GEN3 NTB Linux driver
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/ntb.h>
+
+#include "ntb_hw_intel.h"
+#include "ntb_hw_gen1.h"
+#include "ntb_hw_gen3.h"
+
+static int gen3_poll_link(struct intel_ntb_dev *ndev);
+
+static const struct intel_ntb_reg gen3_reg = {
+	.poll_link		= gen3_poll_link,
+	.link_is_up		= xeon_link_is_up,
+	.db_ioread		= gen3_db_ioread,
+	.db_iowrite		= gen3_db_iowrite,
+	.db_size		= sizeof(u32),
+	.ntb_ctl		= GEN3_NTBCNTL_OFFSET,
+	.mw_bar			= {2, 4},
+};
+
+static const struct intel_ntb_alt_reg gen3_pri_reg = {
+	.db_bell		= GEN3_EM_DOORBELL_OFFSET,
+	.db_clear		= GEN3_IM_INT_STATUS_OFFSET,
+	.db_mask		= GEN3_IM_INT_DISABLE_OFFSET,
+	.spad			= GEN3_IM_SPAD_OFFSET,
+};
+
+static const struct intel_ntb_alt_reg gen3_b2b_reg = {
+	.db_bell		= GEN3_IM_DOORBELL_OFFSET,
+	.db_clear		= GEN3_EM_INT_STATUS_OFFSET,
+	.db_mask		= GEN3_EM_INT_DISABLE_OFFSET,
+	.spad			= GEN3_B2B_SPAD_OFFSET,
+};
+
+static const struct intel_ntb_xlat_reg gen3_sec_xlat = {
+/*	.bar0_base		= GEN3_EMBAR0_OFFSET, */
+	.bar2_limit		= GEN3_IMBAR1XLMT_OFFSET,
+	.bar2_xlat		= GEN3_IMBAR1XBASE_OFFSET,
+};
+
+static int gen3_poll_link(struct intel_ntb_dev *ndev)
+{
+	u16 reg_val;
+	int rc;
+
+	ndev->reg->db_iowrite(ndev->db_link_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_clear);
+
+	rc = pci_read_config_word(ndev->ntb.pdev,
+				  GEN3_LINK_STATUS_OFFSET, &reg_val);
+	if (rc)
+		return 0;
+
+	if (reg_val == ndev->lnk_sta)
+		return 0;
+
+	ndev->lnk_sta = reg_val;
+
+	return 1;
+}
+
+static int gen3_init_isr(struct intel_ntb_dev *ndev)
+{
+	int i;
+
+	/*
+	 * The MSIX vectors and the interrupt status bits are not lined up
+	 * on Skylake. By default the link status bit is bit 32, however it
+	 * is by default MSIX vector0. We need to fixup to line them up.
+	 * The vectors at reset is 1-32,0. We need to reprogram to 0-32.
+	 */
+
+	for (i = 0; i < GEN3_DB_MSIX_VECTOR_COUNT; i++)
+		iowrite8(i, ndev->self_mmio + GEN3_INTVEC_OFFSET + i);
+
+	/* move link status down one as workaround */
+	if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) {
+		iowrite8(GEN3_DB_MSIX_VECTOR_COUNT - 2,
+			 ndev->self_mmio + GEN3_INTVEC_OFFSET +
+			 (GEN3_DB_MSIX_VECTOR_COUNT - 1));
+	}
+
+	return ndev_init_isr(ndev, GEN3_DB_MSIX_VECTOR_COUNT,
+			     GEN3_DB_MSIX_VECTOR_COUNT,
+			     GEN3_DB_MSIX_VECTOR_SHIFT,
+			     GEN3_DB_TOTAL_SHIFT);
+}
+
+static int gen3_setup_b2b_mw(struct intel_ntb_dev *ndev,
+			    const struct intel_b2b_addr *addr,
+			    const struct intel_b2b_addr *peer_addr)
+{
+	struct pci_dev *pdev;
+	void __iomem *mmio;
+	phys_addr_t bar_addr;
+
+	pdev = ndev->ntb.pdev;
+	mmio = ndev->self_mmio;
+
+	/* setup incoming bar limits == base addrs (zero length windows) */
+	bar_addr = addr->bar2_addr64;
+	iowrite64(bar_addr, mmio + GEN3_IMBAR1XLMT_OFFSET);
+	bar_addr = ioread64(mmio + GEN3_IMBAR1XLMT_OFFSET);
+	dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr);
+
+	bar_addr = addr->bar4_addr64;
+	iowrite64(bar_addr, mmio + GEN3_IMBAR2XLMT_OFFSET);
+	bar_addr = ioread64(mmio + GEN3_IMBAR2XLMT_OFFSET);
+	dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr);
+
+	/* zero incoming translation addrs */
+	iowrite64(0, mmio + GEN3_IMBAR1XBASE_OFFSET);
+	iowrite64(0, mmio + GEN3_IMBAR2XBASE_OFFSET);
+
+	ndev->peer_mmio = ndev->self_mmio;
+
+	return 0;
+}
+
+static int gen3_init_ntb(struct intel_ntb_dev *ndev)
+{
+	int rc;
+
+
+	ndev->mw_count = XEON_MW_COUNT;
+	ndev->spad_count = GEN3_SPAD_COUNT;
+	ndev->db_count = GEN3_DB_COUNT;
+	ndev->db_link_mask = GEN3_DB_LINK_BIT;
+
+	/* DB fixup for using 31 right now */
+	if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD)
+		ndev->db_link_mask |= BIT_ULL(31);
+
+	switch (ndev->ntb.topo) {
+	case NTB_TOPO_B2B_USD:
+	case NTB_TOPO_B2B_DSD:
+		ndev->self_reg = &gen3_pri_reg;
+		ndev->peer_reg = &gen3_b2b_reg;
+		ndev->xlat_reg = &gen3_sec_xlat;
+
+		if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
+			rc = gen3_setup_b2b_mw(ndev,
+					      &xeon_b2b_dsd_addr,
+					      &xeon_b2b_usd_addr);
+		} else {
+			rc = gen3_setup_b2b_mw(ndev,
+					      &xeon_b2b_usd_addr,
+					      &xeon_b2b_dsd_addr);
+		}
+
+		if (rc)
+			return rc;
+
+		/* Enable Bus Master and Memory Space on the secondary side */
+		iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+			  ndev->self_mmio + GEN3_SPCICMD_OFFSET);
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
+
+	ndev->reg->db_iowrite(ndev->db_valid_mask,
+			      ndev->self_mmio +
+			      ndev->self_reg->db_mask);
+
+	return 0;
+}
+
+int gen3_init_dev(struct intel_ntb_dev *ndev)
+{
+	struct pci_dev *pdev;
+	u8 ppd;
+	int rc;
+
+	pdev = ndev->ntb.pdev;
+
+	ndev->reg = &gen3_reg;
+
+	rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd);
+	if (rc)
+		return -EIO;
+
+	ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
+	dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd,
+		ntb_topo_string(ndev->ntb.topo));
+	if (ndev->ntb.topo == NTB_TOPO_NONE)
+		return -EINVAL;
+
+	ndev->hwerr_flags |= NTB_HWERR_MSIX_VECTOR32_BAD;
+
+	rc = gen3_init_ntb(ndev);
+	if (rc)
+		return rc;
+
+	return gen3_init_isr(ndev);
+}
+
+ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf,
+				      size_t count, loff_t *offp)
+{
+	struct intel_ntb_dev *ndev;
+	void __iomem *mmio;
+	char *buf;
+	size_t buf_size;
+	ssize_t ret, off;
+	union { u64 v64; u32 v32; u16 v16; } u;
+
+	ndev = filp->private_data;
+	mmio = ndev->self_mmio;
+
+	buf_size = min(count, 0x800ul);
+
+	buf = kmalloc(buf_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	off = 0;
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB Device Information:\n");
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Connection Topology -\t%s\n",
+			 ntb_topo_string(ndev->ntb.topo));
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl);
+	off += scnprintf(buf + off, buf_size - off,
+			 "LNK STA -\t\t%#06x\n", ndev->lnk_sta);
+
+	if (!ndev->reg->link_is_up(ndev))
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Status -\t\tDown\n");
+	else {
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Status -\t\tUp\n");
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Speed -\t\tPCI-E Gen %u\n",
+				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
+		off += scnprintf(buf + off, buf_size - off,
+				 "Link Width -\t\tx%u\n",
+				 NTB_LNK_STA_WIDTH(ndev->lnk_sta));
+	}
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Memory Window Count -\t%u\n", ndev->mw_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Scratchpad Count -\t%u\n", ndev->spad_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Count -\t%u\n", ndev->db_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Vector Count -\t%u\n", ndev->db_vec_count);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
+
+	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Mask -\t\t%#llx\n", u.v64);
+
+	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Doorbell Bell -\t\t%#llx\n", u.v64);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Incoming XLAT:\n");
+
+	u.v64 = ioread64(mmio + GEN3_IMBAR1XBASE_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "IMBAR1XBASE -\t\t%#018llx\n", u.v64);
+
+	u.v64 = ioread64(mmio + GEN3_IMBAR2XBASE_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "IMBAR2XBASE -\t\t%#018llx\n", u.v64);
+
+	u.v64 = ioread64(mmio + GEN3_IMBAR1XLMT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "IMBAR1XLMT -\t\t\t%#018llx\n", u.v64);
+
+	u.v64 = ioread64(mmio + GEN3_IMBAR2XLMT_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "IMBAR2XLMT -\t\t\t%#018llx\n", u.v64);
+
+	if (ntb_topo_is_b2b(ndev->ntb.topo)) {
+		off += scnprintf(buf + off, buf_size - off,
+				 "\nNTB Outgoing B2B XLAT:\n");
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR1XBASE_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR1XBASE -\t\t%#018llx\n", u.v64);
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR2XBASE_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR2XBASE -\t\t%#018llx\n", u.v64);
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR1XLMT_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR1XLMT -\t\t%#018llx\n", u.v64);
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR2XLMT_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR2XLMT -\t\t%#018llx\n", u.v64);
+
+		off += scnprintf(buf + off, buf_size - off,
+				 "\nNTB Secondary BAR:\n");
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR0_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR0 -\t\t%#018llx\n", u.v64);
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR1_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR1 -\t\t%#018llx\n", u.v64);
+
+		u.v64 = ioread64(mmio + GEN3_EMBAR2_OFFSET);
+		off += scnprintf(buf + off, buf_size - off,
+				 "EMBAR2 -\t\t%#018llx\n", u.v64);
+	}
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Statistics:\n");
+
+	u.v16 = ioread16(mmio + GEN3_USMEMMISS_OFFSET);
+	off += scnprintf(buf + off, buf_size - off,
+			 "Upstream Memory Miss -\t%u\n", u.v16);
+
+	off += scnprintf(buf + off, buf_size - off,
+			 "\nNTB Hardware Errors:\n");
+
+	if (!pci_read_config_word(ndev->ntb.pdev,
+				  GEN3_DEVSTS_OFFSET, &u.v16))
+		off += scnprintf(buf + off, buf_size - off,
+				 "DEVSTS -\t\t%#06x\n", u.v16);
+
+	if (!pci_read_config_word(ndev->ntb.pdev,
+				  GEN3_LINK_STATUS_OFFSET, &u.v16))
+		off += scnprintf(buf + off, buf_size - off,
+				 "LNKSTS -\t\t%#06x\n", u.v16);
+
+	if (!pci_read_config_dword(ndev->ntb.pdev,
+				   GEN3_UNCERRSTS_OFFSET, &u.v32))
+		off += scnprintf(buf + off, buf_size - off,
+				 "UNCERRSTS -\t\t%#06x\n", u.v32);
+
+	if (!pci_read_config_dword(ndev->ntb.pdev,
+				   GEN3_CORERRSTS_OFFSET, &u.v32))
+		off += scnprintf(buf + off, buf_size - off,
+				 "CORERRSTS -\t\t%#06x\n", u.v32);
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
+	kfree(buf);
+	return ret;
+}
+
+static int intel_ntb3_link_enable(struct ntb_dev *ntb,
+				  enum ntb_speed max_speed,
+				  enum ntb_width max_width)
+{
+	struct intel_ntb_dev *ndev;
+	u32 ntb_ctl;
+
+	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
+
+	dev_dbg(&ntb->pdev->dev,
+		"Enabling link with max_speed %d max_width %d\n",
+		max_speed, max_width);
+
+	if (max_speed != NTB_SPEED_AUTO)
+		dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed);
+	if (max_width != NTB_WIDTH_AUTO)
+		dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width);
+
+	ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
+	ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
+	ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
+	ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
+	iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
+
+	return 0;
+}
+static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
+				   dma_addr_t addr, resource_size_t size)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	unsigned long xlat_reg, limit_reg;
+	resource_size_t bar_size, mw_size;
+	void __iomem *mmio;
+	u64 base, limit, reg_val;
+	int bar;
+
+	if (pidx != NTB_DEF_PEER_IDX)
+		return -EINVAL;
+
+	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
+		idx += 1;
+
+	bar = ndev_mw_to_bar(ndev, idx);
+	if (bar < 0)
+		return bar;
+
+	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
+
+	if (idx == ndev->b2b_idx)
+		mw_size = bar_size - ndev->b2b_off;
+	else
+		mw_size = bar_size;
+
+	/* hardware requires that addr is aligned to bar size */
+	if (addr & (bar_size - 1))
+		return -EINVAL;
+
+	/* make sure the range fits in the usable mw size */
+	if (size > mw_size)
+		return -EINVAL;
+
+	mmio = ndev->self_mmio;
+	xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10);
+	limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10);
+	base = pci_resource_start(ndev->ntb.pdev, bar);
+
+	/* Set the limit if supported, if size is not mw_size */
+	if (limit_reg && size != mw_size)
+		limit = base + size;
+	else
+		limit = base + mw_size;
+
+	/* set and verify setting the translation address */
+	iowrite64(addr, mmio + xlat_reg);
+	reg_val = ioread64(mmio + xlat_reg);
+	if (reg_val != addr) {
+		iowrite64(0, mmio + xlat_reg);
+		return -EIO;
+	}
+
+	dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val);
+
+	/* set and verify setting the limit */
+	iowrite64(limit, mmio + limit_reg);
+	reg_val = ioread64(mmio + limit_reg);
+	if (reg_val != limit) {
+		iowrite64(base, mmio + limit_reg);
+		iowrite64(0, mmio + xlat_reg);
+		return -EIO;
+	}
+
+	dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val);
+
+	/* setup the EP */
+	limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000;
+	base = ioread64(mmio + GEN3_EMBAR1_OFFSET + (8 * idx));
+	base &= ~0xf;
+
+	if (limit_reg && size != mw_size)
+		limit = base + size;
+	else
+		limit = base + mw_size;
+
+	/* set and verify setting the limit */
+	iowrite64(limit, mmio + limit_reg);
+	reg_val = ioread64(mmio + limit_reg);
+	if (reg_val != limit) {
+		iowrite64(base, mmio + limit_reg);
+		iowrite64(0, mmio + xlat_reg);
+		return -EIO;
+	}
+
+	dev_dbg(&ntb->pdev->dev, "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val);
+
+	return 0;
+}
+
+static int intel_ntb3_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+	int bit;
+
+	if (db_bits & ~ndev->db_valid_mask)
+		return -EINVAL;
+
+	while (db_bits) {
+		bit = __ffs(db_bits);
+		iowrite32(1, ndev->peer_mmio +
+				ndev->peer_reg->db_bell + (bit * 4));
+		db_bits &= db_bits - 1;
+	}
+
+	return 0;
+}
+
+static u64 intel_ntb3_db_read(struct ntb_dev *ntb)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_read(ndev,
+			    ndev->self_mmio +
+			    ndev->self_reg->db_clear);
+}
+
+static int intel_ntb3_db_clear(struct ntb_dev *ntb, u64 db_bits)
+{
+	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
+
+	return ndev_db_write(ndev, db_bits,
+			     ndev->self_mmio +
+			     ndev->self_reg->db_clear);
+}
+
+const struct ntb_dev_ops intel_ntb3_ops = {
+	.mw_count		= intel_ntb_mw_count,
+	.mw_get_align		= intel_ntb_mw_get_align,
+	.mw_set_trans		= intel_ntb3_mw_set_trans,
+	.peer_mw_count		= intel_ntb_peer_mw_count,
+	.peer_mw_get_addr	= intel_ntb_peer_mw_get_addr,
+	.link_is_up		= intel_ntb_link_is_up,
+	.link_enable		= intel_ntb3_link_enable,
+	.link_disable		= intel_ntb_link_disable,
+	.db_valid_mask		= intel_ntb_db_valid_mask,
+	.db_vector_count	= intel_ntb_db_vector_count,
+	.db_vector_mask		= intel_ntb_db_vector_mask,
+	.db_read		= intel_ntb3_db_read,
+	.db_clear		= intel_ntb3_db_clear,
+	.db_set_mask		= intel_ntb_db_set_mask,
+	.db_clear_mask		= intel_ntb_db_clear_mask,
+	.peer_db_addr		= intel_ntb_peer_db_addr,
+	.peer_db_set		= intel_ntb3_peer_db_set,
+	.spad_is_unsafe		= intel_ntb_spad_is_unsafe,
+	.spad_count		= intel_ntb_spad_count,
+	.spad_read		= intel_ntb_spad_read,
+	.spad_write		= intel_ntb_spad_write,
+	.peer_spad_addr		= intel_ntb_peer_spad_addr,
+	.peer_spad_read		= intel_ntb_peer_spad_read,
+	.peer_spad_write	= intel_ntb_peer_spad_write,
+};
+
diff --git a/drivers/ntb/hw/intel/ntb_hw_gen3.h b/drivers/ntb/hw/intel/ntb_hw_gen3.h
new file mode 100644
index 000000000000..75fb86ca27bb
--- /dev/null
+++ b/drivers/ntb/hw/intel/ntb_hw_gen3.h
@@ -0,0 +1,110 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2012-2017 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2012-2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copy
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NTB_INTEL_GEN3_H_
+#define _NTB_INTEL_GEN3_H_
+
+#include "ntb_hw_intel.h"
+
+/* Intel Skylake Xeon hardware */
+#define GEN3_IMBAR1SZ_OFFSET		0x00d0
+#define GEN3_IMBAR2SZ_OFFSET		0x00d1
+#define GEN3_EMBAR1SZ_OFFSET		0x00d2
+#define GEN3_EMBAR2SZ_OFFSET		0x00d3
+#define GEN3_DEVCTRL_OFFSET		0x0098
+#define GEN3_DEVSTS_OFFSET		0x009a
+#define GEN3_UNCERRSTS_OFFSET		0x014c
+#define GEN3_CORERRSTS_OFFSET		0x0158
+#define GEN3_LINK_STATUS_OFFSET		0x01a2
+
+#define GEN3_NTBCNTL_OFFSET		0x0000
+#define GEN3_IMBAR1XBASE_OFFSET		0x0010		/* SBAR2XLAT */
+#define GEN3_IMBAR1XLMT_OFFSET		0x0018		/* SBAR2LMT */
+#define GEN3_IMBAR2XBASE_OFFSET		0x0020		/* SBAR4XLAT */
+#define GEN3_IMBAR2XLMT_OFFSET		0x0028		/* SBAR4LMT */
+#define GEN3_IM_INT_STATUS_OFFSET	0x0040
+#define GEN3_IM_INT_DISABLE_OFFSET	0x0048
+#define GEN3_IM_SPAD_OFFSET		0x0080		/* SPAD */
+#define GEN3_USMEMMISS_OFFSET		0x0070
+#define GEN3_INTVEC_OFFSET		0x00d0
+#define GEN3_IM_DOORBELL_OFFSET		0x0100		/* SDOORBELL0 */
+#define GEN3_B2B_SPAD_OFFSET		0x0180		/* B2B SPAD */
+#define GEN3_EMBAR0XBASE_OFFSET		0x4008		/* B2B_XLAT */
+#define GEN3_EMBAR1XBASE_OFFSET		0x4010		/* PBAR2XLAT */
+#define GEN3_EMBAR1XLMT_OFFSET		0x4018		/* PBAR2LMT */
+#define GEN3_EMBAR2XBASE_OFFSET		0x4020		/* PBAR4XLAT */
+#define GEN3_EMBAR2XLMT_OFFSET		0x4028		/* PBAR4LMT */
+#define GEN3_EM_INT_STATUS_OFFSET	0x4040
+#define GEN3_EM_INT_DISABLE_OFFSET	0x4048
+#define GEN3_EM_SPAD_OFFSET		0x4080		/* remote SPAD */
+#define GEN3_EM_DOORBELL_OFFSET		0x4100		/* PDOORBELL0 */
+#define GEN3_SPCICMD_OFFSET		0x4504		/* SPCICMD */
+#define GEN3_EMBAR0_OFFSET		0x4510		/* SBAR0BASE */
+#define GEN3_EMBAR1_OFFSET		0x4518		/* SBAR23BASE */
+#define GEN3_EMBAR2_OFFSET		0x4520		/* SBAR45BASE */
+
+#define GEN3_DB_COUNT			32
+#define GEN3_DB_LINK			32
+#define GEN3_DB_LINK_BIT		BIT_ULL(GEN3_DB_LINK)
+#define GEN3_DB_MSIX_VECTOR_COUNT	33
+#define GEN3_DB_MSIX_VECTOR_SHIFT	1
+#define GEN3_DB_TOTAL_SHIFT		33
+#define GEN3_SPAD_COUNT			16
+
+static inline u64 gen3_db_ioread(void __iomem *mmio)
+{
+	return ioread64(mmio);
+}
+
+static inline void gen3_db_iowrite(u64 bits, void __iomem *mmio)
+{
+	iowrite64(bits, mmio);
+}
+
+ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf,
+				      size_t count, loff_t *offp);
+int gen3_init_dev(struct intel_ntb_dev *ndev);
+
+extern const struct ntb_dev_ops intel_ntb3_ops;
+
+#endif
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c
deleted file mode 100644
index 156b45cd4a19..000000000000
--- a/drivers/ntb/hw/intel/ntb_hw_intel.c
+++ /dev/null
@@ -1,2691 +0,0 @@
-/*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- *   redistributing this file, you may do so under either license.
- *
- *   GPL LICENSE SUMMARY
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
- *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of version 2 of the GNU General Public License as
- *   published by the Free Software Foundation.
- *
- *   BSD LICENSE
- *
- *   Copyright(c) 2012 Intel Corporation. All rights reserved.
- *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
- *   Copyright (C) 2016 T-Platforms. All Rights Reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copy
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Intel PCIe NTB Linux driver
- *
- * Contact Information:
- * Jon Mason <jon.mason@intel.com>
- */
-
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/ntb.h>
-
-#include "ntb_hw_intel.h"
-
-#define NTB_NAME	"ntb_hw_intel"
-#define NTB_DESC	"Intel(R) PCI-E Non-Transparent Bridge Driver"
-#define NTB_VER		"2.0"
-
-MODULE_DESCRIPTION(NTB_DESC);
-MODULE_VERSION(NTB_VER);
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Intel Corporation");
-
-#define bar0_off(base, bar) ((base) + ((bar) << 2))
-#define bar2_off(base, bar) bar0_off(base, (bar) - 2)
-
-static const struct intel_ntb_reg xeon_reg;
-static const struct intel_ntb_alt_reg xeon_pri_reg;
-static const struct intel_ntb_alt_reg xeon_sec_reg;
-static const struct intel_ntb_alt_reg xeon_b2b_reg;
-static const struct intel_ntb_xlat_reg xeon_pri_xlat;
-static const struct intel_ntb_xlat_reg xeon_sec_xlat;
-static struct intel_b2b_addr xeon_b2b_usd_addr;
-static struct intel_b2b_addr xeon_b2b_dsd_addr;
-static const struct intel_ntb_reg skx_reg;
-static const struct intel_ntb_alt_reg skx_pri_reg;
-static const struct intel_ntb_alt_reg skx_b2b_reg;
-static const struct intel_ntb_xlat_reg skx_sec_xlat;
-static const struct ntb_dev_ops intel_ntb_ops;
-static const struct ntb_dev_ops intel_ntb3_ops;
-
-static const struct file_operations intel_ntb_debugfs_info;
-static struct dentry *debugfs_dir;
-
-static int b2b_mw_idx = -1;
-module_param(b2b_mw_idx, int, 0644);
-MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb.  A "
-		 "value of zero or positive starts from first mw idx, and a "
-		 "negative value starts from last mw idx.  Both sides MUST "
-		 "set the same value here!");
-
-static unsigned int b2b_mw_share;
-module_param(b2b_mw_share, uint, 0644);
-MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the "
-		 "ntb so that the peer ntb only occupies the first half of "
-		 "the mw, so the second half can still be used as a mw.  Both "
-		 "sides MUST set the same value here!");
-
-module_param_named(xeon_b2b_usd_bar2_addr64,
-		   xeon_b2b_usd_addr.bar2_addr64, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64,
-		 "XEON B2B USD BAR 2 64-bit address");
-
-module_param_named(xeon_b2b_usd_bar4_addr64,
-		   xeon_b2b_usd_addr.bar4_addr64, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar4_addr64,
-		 "XEON B2B USD BAR 4 64-bit address");
-
-module_param_named(xeon_b2b_usd_bar4_addr32,
-		   xeon_b2b_usd_addr.bar4_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar4_addr32,
-		 "XEON B2B USD split-BAR 4 32-bit address");
-
-module_param_named(xeon_b2b_usd_bar5_addr32,
-		   xeon_b2b_usd_addr.bar5_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar5_addr32,
-		 "XEON B2B USD split-BAR 5 32-bit address");
-
-module_param_named(xeon_b2b_dsd_bar2_addr64,
-		   xeon_b2b_dsd_addr.bar2_addr64, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64,
-		 "XEON B2B DSD BAR 2 64-bit address");
-
-module_param_named(xeon_b2b_dsd_bar4_addr64,
-		   xeon_b2b_dsd_addr.bar4_addr64, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr64,
-		 "XEON B2B DSD BAR 4 64-bit address");
-
-module_param_named(xeon_b2b_dsd_bar4_addr32,
-		   xeon_b2b_dsd_addr.bar4_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr32,
-		 "XEON B2B DSD split-BAR 4 32-bit address");
-
-module_param_named(xeon_b2b_dsd_bar5_addr32,
-		   xeon_b2b_dsd_addr.bar5_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar5_addr32,
-		 "XEON B2B DSD split-BAR 5 32-bit address");
-
-static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd);
-static int xeon_init_isr(struct intel_ntb_dev *ndev);
-
-#ifndef ioread64
-#ifdef readq
-#define ioread64 readq
-#else
-#define ioread64 _ioread64
-static inline u64 _ioread64(void __iomem *mmio)
-{
-	u64 low, high;
-
-	low = ioread32(mmio);
-	high = ioread32(mmio + sizeof(u32));
-	return low | (high << 32);
-}
-#endif
-#endif
-
-#ifndef iowrite64
-#ifdef writeq
-#define iowrite64 writeq
-#else
-#define iowrite64 _iowrite64
-static inline void _iowrite64(u64 val, void __iomem *mmio)
-{
-	iowrite32(val, mmio);
-	iowrite32(val >> 32, mmio + sizeof(u32));
-}
-#endif
-#endif
-
-static inline int pdev_is_xeon(struct pci_dev *pdev)
-{
-	switch (pdev->device) {
-	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
-		return 1;
-	}
-	return 0;
-}
-
-static inline int pdev_is_skx_xeon(struct pci_dev *pdev)
-{
-	if (pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_SKX)
-		return 1;
-
-	return 0;
-}
-
-static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev)
-{
-	ndev->unsafe_flags = 0;
-	ndev->unsafe_flags_ignore = 0;
-
-	/* Only B2B has a workaround to avoid SDOORBELL */
-	if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP)
-		if (!ntb_topo_is_b2b(ndev->ntb.topo))
-			ndev->unsafe_flags |= NTB_UNSAFE_DB;
-
-	/* No low level workaround to avoid SB01BASE */
-	if (ndev->hwerr_flags & NTB_HWERR_SB01BASE_LOCKUP) {
-		ndev->unsafe_flags |= NTB_UNSAFE_DB;
-		ndev->unsafe_flags |= NTB_UNSAFE_SPAD;
-	}
-}
-
-static inline int ndev_is_unsafe(struct intel_ntb_dev *ndev,
-				 unsigned long flag)
-{
-	return !!(flag & ndev->unsafe_flags & ~ndev->unsafe_flags_ignore);
-}
-
-static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev,
-				     unsigned long flag)
-{
-	flag &= ndev->unsafe_flags;
-	ndev->unsafe_flags_ignore |= flag;
-
-	return !!flag;
-}
-
-static int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx)
-{
-	if (idx < 0 || idx >= ndev->mw_count)
-		return -EINVAL;
-	return ndev->reg->mw_bar[idx];
-}
-
-static inline int ndev_db_addr(struct intel_ntb_dev *ndev,
-			       phys_addr_t *db_addr, resource_size_t *db_size,
-			       phys_addr_t reg_addr, unsigned long reg)
-{
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
-		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
-
-	if (db_addr) {
-		*db_addr = reg_addr + reg;
-		dev_dbg(&ndev->ntb.pdev->dev, "Peer db addr %llx\n", *db_addr);
-	}
-
-	if (db_size) {
-		*db_size = ndev->reg->db_size;
-		dev_dbg(&ndev->ntb.pdev->dev, "Peer db size %llx\n", *db_size);
-	}
-
-	return 0;
-}
-
-static inline u64 ndev_db_read(struct intel_ntb_dev *ndev,
-			       void __iomem *mmio)
-{
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
-		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
-
-	return ndev->reg->db_ioread(mmio);
-}
-
-static inline int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits,
-				void __iomem *mmio)
-{
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
-		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
-
-	if (db_bits & ~ndev->db_valid_mask)
-		return -EINVAL;
-
-	ndev->reg->db_iowrite(db_bits, mmio);
-
-	return 0;
-}
-
-static inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits,
-				   void __iomem *mmio)
-{
-	unsigned long irqflags;
-
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
-		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
-
-	if (db_bits & ~ndev->db_valid_mask)
-		return -EINVAL;
-
-	spin_lock_irqsave(&ndev->db_mask_lock, irqflags);
-	{
-		ndev->db_mask |= db_bits;
-		ndev->reg->db_iowrite(ndev->db_mask, mmio);
-	}
-	spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags);
-
-	return 0;
-}
-
-static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
-				     void __iomem *mmio)
-{
-	unsigned long irqflags;
-
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB))
-		pr_warn_once("%s: NTB unsafe doorbell access", __func__);
-
-	if (db_bits & ~ndev->db_valid_mask)
-		return -EINVAL;
-
-	spin_lock_irqsave(&ndev->db_mask_lock, irqflags);
-	{
-		ndev->db_mask &= ~db_bits;
-		ndev->reg->db_iowrite(ndev->db_mask, mmio);
-	}
-	spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags);
-
-	return 0;
-}
-
-static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
-{
-	u64 shift, mask;
-
-	shift = ndev->db_vec_shift;
-	mask = BIT_ULL(shift) - 1;
-
-	return mask << (shift * db_vector);
-}
-
-static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx,
-				 phys_addr_t *spad_addr, phys_addr_t reg_addr,
-				 unsigned long reg)
-{
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD))
-		pr_warn_once("%s: NTB unsafe scratchpad access", __func__);
-
-	if (idx < 0 || idx >= ndev->spad_count)
-		return -EINVAL;
-
-	if (spad_addr) {
-		*spad_addr = reg_addr + reg + (idx << 2);
-		dev_dbg(&ndev->ntb.pdev->dev, "Peer spad addr %llx\n",
-			*spad_addr);
-	}
-
-	return 0;
-}
-
-static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx,
-				 void __iomem *mmio)
-{
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD))
-		pr_warn_once("%s: NTB unsafe scratchpad access", __func__);
-
-	if (idx < 0 || idx >= ndev->spad_count)
-		return 0;
-
-	return ioread32(mmio + (idx << 2));
-}
-
-static inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val,
-				  void __iomem *mmio)
-{
-	if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD))
-		pr_warn_once("%s: NTB unsafe scratchpad access", __func__);
-
-	if (idx < 0 || idx >= ndev->spad_count)
-		return -EINVAL;
-
-	iowrite32(val, mmio + (idx << 2));
-
-	return 0;
-}
-
-static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec)
-{
-	u64 vec_mask;
-
-	vec_mask = ndev_vec_mask(ndev, vec);
-
-	if ((ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) && (vec == 31))
-		vec_mask |= ndev->db_link_mask;
-
-	dev_dbg(&ndev->ntb.pdev->dev, "vec %d vec_mask %llx\n", vec, vec_mask);
-
-	ndev->last_ts = jiffies;
-
-	if (vec_mask & ndev->db_link_mask) {
-		if (ndev->reg->poll_link(ndev))
-			ntb_link_event(&ndev->ntb);
-	}
-
-	if (vec_mask & ndev->db_valid_mask)
-		ntb_db_event(&ndev->ntb, vec);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t ndev_vec_isr(int irq, void *dev)
-{
-	struct intel_ntb_vec *nvec = dev;
-
-	dev_dbg(&nvec->ndev->ntb.pdev->dev, "irq: %d  nvec->num: %d\n",
-		irq, nvec->num);
-
-	return ndev_interrupt(nvec->ndev, nvec->num);
-}
-
-static irqreturn_t ndev_irq_isr(int irq, void *dev)
-{
-	struct intel_ntb_dev *ndev = dev;
-
-	return ndev_interrupt(ndev, irq - ndev->ntb.pdev->irq);
-}
-
-static int ndev_init_isr(struct intel_ntb_dev *ndev,
-			 int msix_min, int msix_max,
-			 int msix_shift, int total_shift)
-{
-	struct pci_dev *pdev;
-	int rc, i, msix_count, node;
-
-	pdev = ndev->ntb.pdev;
-
-	node = dev_to_node(&pdev->dev);
-
-	/* Mask all doorbell interrupts */
-	ndev->db_mask = ndev->db_valid_mask;
-	ndev->reg->db_iowrite(ndev->db_mask,
-			      ndev->self_mmio +
-			      ndev->self_reg->db_mask);
-
-	/* Try to set up msix irq */
-
-	ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec),
-				 GFP_KERNEL, node);
-	if (!ndev->vec)
-		goto err_msix_vec_alloc;
-
-	ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix),
-				  GFP_KERNEL, node);
-	if (!ndev->msix)
-		goto err_msix_alloc;
-
-	for (i = 0; i < msix_max; ++i)
-		ndev->msix[i].entry = i;
-
-	msix_count = pci_enable_msix_range(pdev, ndev->msix,
-					   msix_min, msix_max);
-	if (msix_count < 0)
-		goto err_msix_enable;
-
-	for (i = 0; i < msix_count; ++i) {
-		ndev->vec[i].ndev = ndev;
-		ndev->vec[i].num = i;
-		rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0,
-				 "ndev_vec_isr", &ndev->vec[i]);
-		if (rc)
-			goto err_msix_request;
-	}
-
-	dev_dbg(&pdev->dev, "Using %d msix interrupts\n", msix_count);
-	ndev->db_vec_count = msix_count;
-	ndev->db_vec_shift = msix_shift;
-	return 0;
-
-err_msix_request:
-	while (i-- > 0)
-		free_irq(ndev->msix[i].vector, &ndev->vec[i]);
-	pci_disable_msix(pdev);
-err_msix_enable:
-	kfree(ndev->msix);
-err_msix_alloc:
-	kfree(ndev->vec);
-err_msix_vec_alloc:
-	ndev->msix = NULL;
-	ndev->vec = NULL;
-
-	/* Try to set up msi irq */
-
-	rc = pci_enable_msi(pdev);
-	if (rc)
-		goto err_msi_enable;
-
-	rc = request_irq(pdev->irq, ndev_irq_isr, 0,
-			 "ndev_irq_isr", ndev);
-	if (rc)
-		goto err_msi_request;
-
-	dev_dbg(&pdev->dev, "Using msi interrupts\n");
-	ndev->db_vec_count = 1;
-	ndev->db_vec_shift = total_shift;
-	return 0;
-
-err_msi_request:
-	pci_disable_msi(pdev);
-err_msi_enable:
-
-	/* Try to set up intx irq */
-
-	pci_intx(pdev, 1);
-
-	rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED,
-			 "ndev_irq_isr", ndev);
-	if (rc)
-		goto err_intx_request;
-
-	dev_dbg(&pdev->dev, "Using intx interrupts\n");
-	ndev->db_vec_count = 1;
-	ndev->db_vec_shift = total_shift;
-	return 0;
-
-err_intx_request:
-	return rc;
-}
-
-static void ndev_deinit_isr(struct intel_ntb_dev *ndev)
-{
-	struct pci_dev *pdev;
-	int i;
-
-	pdev = ndev->ntb.pdev;
-
-	/* Mask all doorbell interrupts */
-	ndev->db_mask = ndev->db_valid_mask;
-	ndev->reg->db_iowrite(ndev->db_mask,
-			      ndev->self_mmio +
-			      ndev->self_reg->db_mask);
-
-	if (ndev->msix) {
-		i = ndev->db_vec_count;
-		while (i--)
-			free_irq(ndev->msix[i].vector, &ndev->vec[i]);
-		pci_disable_msix(pdev);
-		kfree(ndev->msix);
-		kfree(ndev->vec);
-	} else {
-		free_irq(pdev->irq, ndev);
-		if (pci_dev_msi_enabled(pdev))
-			pci_disable_msi(pdev);
-	}
-}
-
-static ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf,
-				      size_t count, loff_t *offp)
-{
-	struct intel_ntb_dev *ndev;
-	void __iomem *mmio;
-	char *buf;
-	size_t buf_size;
-	ssize_t ret, off;
-	union { u64 v64; u32 v32; u16 v16; } u;
-
-	ndev = filp->private_data;
-	mmio = ndev->self_mmio;
-
-	buf_size = min(count, 0x800ul);
-
-	buf = kmalloc(buf_size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	off = 0;
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "NTB Device Information:\n");
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "Connection Topology -\t%s\n",
-			 ntb_topo_string(ndev->ntb.topo));
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl);
-	off += scnprintf(buf + off, buf_size - off,
-			 "LNK STA -\t\t%#06x\n", ndev->lnk_sta);
-
-	if (!ndev->reg->link_is_up(ndev))
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Status -\t\tDown\n");
-	else {
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Status -\t\tUp\n");
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Speed -\t\tPCI-E Gen %u\n",
-				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Width -\t\tx%u\n",
-				 NTB_LNK_STA_WIDTH(ndev->lnk_sta));
-	}
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "Memory Window Count -\t%u\n", ndev->mw_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Scratchpad Count -\t%u\n", ndev->spad_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Count -\t%u\n", ndev->db_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Vector Count -\t%u\n", ndev->db_vec_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift);
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
-
-	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Mask -\t\t%#llx\n", u.v64);
-
-	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Bell -\t\t%#llx\n", u.v64);
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "\nNTB Incoming XLAT:\n");
-
-	u.v64 = ioread64(mmio + SKX_IMBAR1XBASE_OFFSET);
-	off += scnprintf(buf + off, buf_size - off,
-			 "IMBAR1XBASE -\t\t%#018llx\n", u.v64);
-
-	u.v64 = ioread64(mmio + SKX_IMBAR2XBASE_OFFSET);
-	off += scnprintf(buf + off, buf_size - off,
-			 "IMBAR2XBASE -\t\t%#018llx\n", u.v64);
-
-	u.v64 = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET);
-	off += scnprintf(buf + off, buf_size - off,
-			 "IMBAR1XLMT -\t\t\t%#018llx\n", u.v64);
-
-	u.v64 = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET);
-	off += scnprintf(buf + off, buf_size - off,
-			 "IMBAR2XLMT -\t\t\t%#018llx\n", u.v64);
-
-	if (ntb_topo_is_b2b(ndev->ntb.topo)) {
-		off += scnprintf(buf + off, buf_size - off,
-				 "\nNTB Outgoing B2B XLAT:\n");
-
-		u.v64 = ioread64(mmio + SKX_EMBAR1XBASE_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR1XBASE -\t\t%#018llx\n", u.v64);
-
-		u.v64 = ioread64(mmio + SKX_EMBAR2XBASE_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR2XBASE -\t\t%#018llx\n", u.v64);
-
-		u.v64 = ioread64(mmio + SKX_EMBAR1XLMT_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR1XLMT -\t\t%#018llx\n", u.v64);
-
-		u.v64 = ioread64(mmio + SKX_EMBAR2XLMT_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR2XLMT -\t\t%#018llx\n", u.v64);
-
-		off += scnprintf(buf + off, buf_size - off,
-				 "\nNTB Secondary BAR:\n");
-
-		u.v64 = ioread64(mmio + SKX_EMBAR0_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR0 -\t\t%#018llx\n", u.v64);
-
-		u.v64 = ioread64(mmio + SKX_EMBAR1_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR1 -\t\t%#018llx\n", u.v64);
-
-		u.v64 = ioread64(mmio + SKX_EMBAR2_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "EMBAR2 -\t\t%#018llx\n", u.v64);
-	}
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "\nNTB Statistics:\n");
-
-	u.v16 = ioread16(mmio + SKX_USMEMMISS_OFFSET);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Upstream Memory Miss -\t%u\n", u.v16);
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "\nNTB Hardware Errors:\n");
-
-	if (!pci_read_config_word(ndev->ntb.pdev,
-				  SKX_DEVSTS_OFFSET, &u.v16))
-		off += scnprintf(buf + off, buf_size - off,
-				 "DEVSTS -\t\t%#06x\n", u.v16);
-
-	if (!pci_read_config_word(ndev->ntb.pdev,
-				  SKX_LINK_STATUS_OFFSET, &u.v16))
-		off += scnprintf(buf + off, buf_size - off,
-				 "LNKSTS -\t\t%#06x\n", u.v16);
-
-	if (!pci_read_config_dword(ndev->ntb.pdev,
-				   SKX_UNCERRSTS_OFFSET, &u.v32))
-		off += scnprintf(buf + off, buf_size - off,
-				 "UNCERRSTS -\t\t%#06x\n", u.v32);
-
-	if (!pci_read_config_dword(ndev->ntb.pdev,
-				   SKX_CORERRSTS_OFFSET, &u.v32))
-		off += scnprintf(buf + off, buf_size - off,
-				 "CORERRSTS -\t\t%#06x\n", u.v32);
-
-	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf,
-				     size_t count, loff_t *offp)
-{
-	struct intel_ntb_dev *ndev;
-	struct pci_dev *pdev;
-	void __iomem *mmio;
-	char *buf;
-	size_t buf_size;
-	ssize_t ret, off;
-	union { u64 v64; u32 v32; u16 v16; u8 v8; } u;
-
-	ndev = filp->private_data;
-	pdev = ndev->ntb.pdev;
-	mmio = ndev->self_mmio;
-
-	buf_size = min(count, 0x800ul);
-
-	buf = kmalloc(buf_size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	off = 0;
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "NTB Device Information:\n");
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "Connection Topology -\t%s\n",
-			 ntb_topo_string(ndev->ntb.topo));
-
-	if (ndev->b2b_idx != UINT_MAX) {
-		off += scnprintf(buf + off, buf_size - off,
-				 "B2B MW Idx -\t\t%u\n", ndev->b2b_idx);
-		off += scnprintf(buf + off, buf_size - off,
-				 "B2B Offset -\t\t%#lx\n", ndev->b2b_off);
-	}
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "BAR4 Split -\t\t%s\n",
-			 ndev->bar4_split ? "yes" : "no");
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl);
-	off += scnprintf(buf + off, buf_size - off,
-			 "LNK STA -\t\t%#06x\n", ndev->lnk_sta);
-
-	if (!ndev->reg->link_is_up(ndev)) {
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Status -\t\tDown\n");
-	} else {
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Status -\t\tUp\n");
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Speed -\t\tPCI-E Gen %u\n",
-				 NTB_LNK_STA_SPEED(ndev->lnk_sta));
-		off += scnprintf(buf + off, buf_size - off,
-				 "Link Width -\t\tx%u\n",
-				 NTB_LNK_STA_WIDTH(ndev->lnk_sta));
-	}
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "Memory Window Count -\t%u\n", ndev->mw_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Scratchpad Count -\t%u\n", ndev->spad_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Count -\t%u\n", ndev->db_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Vector Count -\t%u\n", ndev->db_vec_count);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift);
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask);
-
-	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Mask -\t\t%#llx\n", u.v64);
-
-	u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell);
-	off += scnprintf(buf + off, buf_size - off,
-			 "Doorbell Bell -\t\t%#llx\n", u.v64);
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "\nNTB Window Size:\n");
-
-	pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &u.v8);
-	off += scnprintf(buf + off, buf_size - off,
-			 "PBAR23SZ %hhu\n", u.v8);
-	if (!ndev->bar4_split) {
-		pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &u.v8);
-		off += scnprintf(buf + off, buf_size - off,
-				 "PBAR45SZ %hhu\n", u.v8);
-	} else {
-		pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &u.v8);
-		off += scnprintf(buf + off, buf_size - off,
-				 "PBAR4SZ %hhu\n", u.v8);
-		pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &u.v8);
-		off += scnprintf(buf + off, buf_size - off,
-				 "PBAR5SZ %hhu\n", u.v8);
-	}
-
-	pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &u.v8);
-	off += scnprintf(buf + off, buf_size - off,
-			 "SBAR23SZ %hhu\n", u.v8);
-	if (!ndev->bar4_split) {
-		pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &u.v8);
-		off += scnprintf(buf + off, buf_size - off,
-				 "SBAR45SZ %hhu\n", u.v8);
-	} else {
-		pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &u.v8);
-		off += scnprintf(buf + off, buf_size - off,
-				 "SBAR4SZ %hhu\n", u.v8);
-		pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &u.v8);
-		off += scnprintf(buf + off, buf_size - off,
-				 "SBAR5SZ %hhu\n", u.v8);
-	}
-
-	off += scnprintf(buf + off, buf_size - off,
-			 "\nNTB Incoming XLAT:\n");
-
-	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2));
-	off += scnprintf(buf + off, buf_size - off,
-			 "XLAT23 -\t\t%#018llx\n", u.v64);
-
-	if (ndev->bar4_split) {
-		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
-		off += scnprintf(buf + off, buf_size - off,
-				 "XLAT4 -\t\t\t%#06x\n", u.v32);
-
-		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 5));
-		off += scnprintf(buf + off, buf_size - off,
-				 "XLAT5 -\t\t\t%#06x\n", u.v32);
-	} else {
-		u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4));
-		off += scnprintf(buf + off, buf_size - off,
-				 "XLAT45 -\t\t%#018llx\n", u.v64);
-	}
-
-	u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2));
-	off += scnprintf(buf + off, buf_size - off,
-			 "LMT23 -\t\t\t%#018llx\n", u.v64);
-
-	if (ndev->bar4_split) {
-		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
-		off += scnprintf(buf + off, buf_size - off,
-				 "LMT4 -\t\t\t%#06x\n", u.v32);
-		u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 5));
-		off += scnprintf(buf + off, buf_size - off,
-				 "LMT5 -\t\t\t%#06x\n", u.v32);
-	} else {
-		u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4));
-		off += scnprintf(buf + off, buf_size - off,
-				 "LMT45 -\t\t\t%#018llx\n", u.v64);
-	}
-
-	if (pdev_is_xeon(pdev)) {
-		if (ntb_topo_is_b2b(ndev->ntb.topo)) {
-			off += scnprintf(buf + off, buf_size - off,
-					 "\nNTB Outgoing B2B XLAT:\n");
-
-			u.v64 = ioread64(mmio + XEON_PBAR23XLAT_OFFSET);
-			off += scnprintf(buf + off, buf_size - off,
-					 "B2B XLAT23 -\t\t%#018llx\n", u.v64);
-
-			if (ndev->bar4_split) {
-				u.v32 = ioread32(mmio + XEON_PBAR4XLAT_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "B2B XLAT4 -\t\t%#06x\n",
-						 u.v32);
-				u.v32 = ioread32(mmio + XEON_PBAR5XLAT_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "B2B XLAT5 -\t\t%#06x\n",
-						 u.v32);
-			} else {
-				u.v64 = ioread64(mmio + XEON_PBAR45XLAT_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "B2B XLAT45 -\t\t%#018llx\n",
-						 u.v64);
-			}
-
-			u.v64 = ioread64(mmio + XEON_PBAR23LMT_OFFSET);
-			off += scnprintf(buf + off, buf_size - off,
-					 "B2B LMT23 -\t\t%#018llx\n", u.v64);
-
-			if (ndev->bar4_split) {
-				u.v32 = ioread32(mmio + XEON_PBAR4LMT_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "B2B LMT4 -\t\t%#06x\n",
-						 u.v32);
-				u.v32 = ioread32(mmio + XEON_PBAR5LMT_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "B2B LMT5 -\t\t%#06x\n",
-						 u.v32);
-			} else {
-				u.v64 = ioread64(mmio + XEON_PBAR45LMT_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "B2B LMT45 -\t\t%#018llx\n",
-						 u.v64);
-			}
-
-			off += scnprintf(buf + off, buf_size - off,
-					 "\nNTB Secondary BAR:\n");
-
-			u.v64 = ioread64(mmio + XEON_SBAR0BASE_OFFSET);
-			off += scnprintf(buf + off, buf_size - off,
-					 "SBAR01 -\t\t%#018llx\n", u.v64);
-
-			u.v64 = ioread64(mmio + XEON_SBAR23BASE_OFFSET);
-			off += scnprintf(buf + off, buf_size - off,
-					 "SBAR23 -\t\t%#018llx\n", u.v64);
-
-			if (ndev->bar4_split) {
-				u.v32 = ioread32(mmio + XEON_SBAR4BASE_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "SBAR4 -\t\t\t%#06x\n", u.v32);
-				u.v32 = ioread32(mmio + XEON_SBAR5BASE_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "SBAR5 -\t\t\t%#06x\n", u.v32);
-			} else {
-				u.v64 = ioread64(mmio + XEON_SBAR45BASE_OFFSET);
-				off += scnprintf(buf + off, buf_size - off,
-						 "SBAR45 -\t\t%#018llx\n",
-						 u.v64);
-			}
-		}
-
-		off += scnprintf(buf + off, buf_size - off,
-				 "\nXEON NTB Statistics:\n");
-
-		u.v16 = ioread16(mmio + XEON_USMEMMISS_OFFSET);
-		off += scnprintf(buf + off, buf_size - off,
-				 "Upstream Memory Miss -\t%u\n", u.v16);
-
-		off += scnprintf(buf + off, buf_size - off,
-				 "\nXEON NTB Hardware Errors:\n");
-
-		if (!pci_read_config_word(pdev,
-					  XEON_DEVSTS_OFFSET, &u.v16))
-			off += scnprintf(buf + off, buf_size - off,
-					 "DEVSTS -\t\t%#06x\n", u.v16);
-
-		if (!pci_read_config_word(pdev,
-					  XEON_LINK_STATUS_OFFSET, &u.v16))
-			off += scnprintf(buf + off, buf_size - off,
-					 "LNKSTS -\t\t%#06x\n", u.v16);
-
-		if (!pci_read_config_dword(pdev,
-					   XEON_UNCERRSTS_OFFSET, &u.v32))
-			off += scnprintf(buf + off, buf_size - off,
-					 "UNCERRSTS -\t\t%#06x\n", u.v32);
-
-		if (!pci_read_config_dword(pdev,
-					   XEON_CORERRSTS_OFFSET, &u.v32))
-			off += scnprintf(buf + off, buf_size - off,
-					 "CORERRSTS -\t\t%#06x\n", u.v32);
-	}
-
-	ret = simple_read_from_buffer(ubuf, count, offp, buf, off);
-	kfree(buf);
-	return ret;
-}
-
-static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
-				 size_t count, loff_t *offp)
-{
-	struct intel_ntb_dev *ndev = filp->private_data;
-
-	if (pdev_is_xeon(ndev->ntb.pdev))
-		return ndev_ntb_debugfs_read(filp, ubuf, count, offp);
-	else if (pdev_is_skx_xeon(ndev->ntb.pdev))
-		return ndev_ntb3_debugfs_read(filp, ubuf, count, offp);
-
-	return -ENXIO;
-}
-
-static void ndev_init_debugfs(struct intel_ntb_dev *ndev)
-{
-	if (!debugfs_dir) {
-		ndev->debugfs_dir = NULL;
-		ndev->debugfs_info = NULL;
-	} else {
-		ndev->debugfs_dir =
-			debugfs_create_dir(pci_name(ndev->ntb.pdev),
-					   debugfs_dir);
-		if (!ndev->debugfs_dir)
-			ndev->debugfs_info = NULL;
-		else
-			ndev->debugfs_info =
-				debugfs_create_file("info", S_IRUSR,
-						    ndev->debugfs_dir, ndev,
-						    &intel_ntb_debugfs_info);
-	}
-}
-
-static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
-{
-	debugfs_remove_recursive(ndev->debugfs_dir);
-}
-
-static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
-{
-	if (pidx != NTB_DEF_PEER_IDX)
-		return -EINVAL;
-
-	return ntb_ndev(ntb)->mw_count;
-}
-
-static int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
-				  resource_size_t *addr_align,
-				  resource_size_t *size_align,
-				  resource_size_t *size_max)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-	resource_size_t bar_size, mw_size;
-	int bar;
-
-	if (pidx != NTB_DEF_PEER_IDX)
-		return -EINVAL;
-
-	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
-		idx += 1;
-
-	bar = ndev_mw_to_bar(ndev, idx);
-	if (bar < 0)
-		return bar;
-
-	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
-
-	if (idx == ndev->b2b_idx)
-		mw_size = bar_size - ndev->b2b_off;
-	else
-		mw_size = bar_size;
-
-	if (addr_align)
-		*addr_align = pci_resource_len(ndev->ntb.pdev, bar);
-
-	if (size_align)
-		*size_align = 1;
-
-	if (size_max)
-		*size_max = mw_size;
-
-	return 0;
-}
-
-static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
-				  dma_addr_t addr, resource_size_t size)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-	unsigned long base_reg, xlat_reg, limit_reg;
-	resource_size_t bar_size, mw_size;
-	void __iomem *mmio;
-	u64 base, limit, reg_val;
-	int bar;
-
-	if (pidx != NTB_DEF_PEER_IDX)
-		return -EINVAL;
-
-	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
-		idx += 1;
-
-	bar = ndev_mw_to_bar(ndev, idx);
-	if (bar < 0)
-		return bar;
-
-	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
-
-	if (idx == ndev->b2b_idx)
-		mw_size = bar_size - ndev->b2b_off;
-	else
-		mw_size = bar_size;
-
-	/* hardware requires that addr is aligned to bar size */
-	if (addr & (bar_size - 1))
-		return -EINVAL;
-
-	/* make sure the range fits in the usable mw size */
-	if (size > mw_size)
-		return -EINVAL;
-
-	mmio = ndev->self_mmio;
-	base_reg = bar0_off(ndev->xlat_reg->bar0_base, bar);
-	xlat_reg = bar2_off(ndev->xlat_reg->bar2_xlat, bar);
-	limit_reg = bar2_off(ndev->xlat_reg->bar2_limit, bar);
-
-	if (bar < 4 || !ndev->bar4_split) {
-		base = ioread64(mmio + base_reg) & NTB_BAR_MASK_64;
-
-		/* Set the limit if supported, if size is not mw_size */
-		if (limit_reg && size != mw_size)
-			limit = base + size;
-		else
-			limit = 0;
-
-		/* set and verify setting the translation address */
-		iowrite64(addr, mmio + xlat_reg);
-		reg_val = ioread64(mmio + xlat_reg);
-		if (reg_val != addr) {
-			iowrite64(0, mmio + xlat_reg);
-			return -EIO;
-		}
-
-		/* set and verify setting the limit */
-		iowrite64(limit, mmio + limit_reg);
-		reg_val = ioread64(mmio + limit_reg);
-		if (reg_val != limit) {
-			iowrite64(base, mmio + limit_reg);
-			iowrite64(0, mmio + xlat_reg);
-			return -EIO;
-		}
-	} else {
-		/* split bar addr range must all be 32 bit */
-		if (addr & (~0ull << 32))
-			return -EINVAL;
-		if ((addr + size) & (~0ull << 32))
-			return -EINVAL;
-
-		base = ioread32(mmio + base_reg) & NTB_BAR_MASK_32;
-
-		/* Set the limit if supported, if size is not mw_size */
-		if (limit_reg && size != mw_size)
-			limit = base + size;
-		else
-			limit = 0;
-
-		/* set and verify setting the translation address */
-		iowrite32(addr, mmio + xlat_reg);
-		reg_val = ioread32(mmio + xlat_reg);
-		if (reg_val != addr) {
-			iowrite32(0, mmio + xlat_reg);
-			return -EIO;
-		}
-
-		/* set and verify setting the limit */
-		iowrite32(limit, mmio + limit_reg);
-		reg_val = ioread32(mmio + limit_reg);
-		if (reg_val != limit) {
-			iowrite32(base, mmio + limit_reg);
-			iowrite32(0, mmio + xlat_reg);
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
-static u64 intel_ntb_link_is_up(struct ntb_dev *ntb,
-				enum ntb_speed *speed,
-				enum ntb_width *width)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	if (ndev->reg->link_is_up(ndev)) {
-		if (speed)
-			*speed = NTB_LNK_STA_SPEED(ndev->lnk_sta);
-		if (width)
-			*width = NTB_LNK_STA_WIDTH(ndev->lnk_sta);
-		return 1;
-	} else {
-		/* TODO MAYBE: is it possible to observe the link speed and
-		 * width while link is training? */
-		if (speed)
-			*speed = NTB_SPEED_NONE;
-		if (width)
-			*width = NTB_WIDTH_NONE;
-		return 0;
-	}
-}
-
-static int intel_ntb_link_enable(struct ntb_dev *ntb,
-				 enum ntb_speed max_speed,
-				 enum ntb_width max_width)
-{
-	struct intel_ntb_dev *ndev;
-	u32 ntb_ctl;
-
-	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
-	if (ndev->ntb.topo == NTB_TOPO_SEC)
-		return -EINVAL;
-
-	dev_dbg(&ntb->pdev->dev,
-		"Enabling link with max_speed %d max_width %d\n",
-		max_speed, max_width);
-	if (max_speed != NTB_SPEED_AUTO)
-		dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed);
-	if (max_width != NTB_WIDTH_AUTO)
-		dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width);
-
-	ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
-	ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
-	ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
-	ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
-	if (ndev->bar4_split)
-		ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP;
-	iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
-	return 0;
-}
-
-static int intel_ntb_link_disable(struct ntb_dev *ntb)
-{
-	struct intel_ntb_dev *ndev;
-	u32 ntb_cntl;
-
-	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
-	if (ndev->ntb.topo == NTB_TOPO_SEC)
-		return -EINVAL;
-
-	dev_dbg(&ntb->pdev->dev, "Disabling link\n");
-
-	/* Bring NTB link down */
-	ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
-	ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP);
-	ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP);
-	if (ndev->bar4_split)
-		ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP);
-	ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK;
-	iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
-	return 0;
-}
-
-static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
-{
-	/* Numbers of inbound and outbound memory windows match */
-	return ntb_ndev(ntb)->mw_count;
-}
-
-static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
-				     phys_addr_t *base, resource_size_t *size)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-	int bar;
-
-	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
-		idx += 1;
-
-	bar = ndev_mw_to_bar(ndev, idx);
-	if (bar < 0)
-		return bar;
-
-	if (base)
-		*base = pci_resource_start(ndev->ntb.pdev, bar) +
-			(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
-
-	if (size)
-		*size = pci_resource_len(ndev->ntb.pdev, bar) -
-			(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
-
-	return 0;
-}
-
-static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
-{
-	return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
-}
-
-static u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb)
-{
-	return ntb_ndev(ntb)->db_valid_mask;
-}
-
-static int intel_ntb_db_vector_count(struct ntb_dev *ntb)
-{
-	struct intel_ntb_dev *ndev;
-
-	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
-	return ndev->db_vec_count;
-}
-
-static u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	if (db_vector < 0 || db_vector > ndev->db_vec_count)
-		return 0;
-
-	return ndev->db_valid_mask & ndev_vec_mask(ndev, db_vector);
-}
-
-static u64 intel_ntb_db_read(struct ntb_dev *ntb)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_read(ndev,
-			    ndev->self_mmio +
-			    ndev->self_reg->db_bell);
-}
-
-static int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_write(ndev, db_bits,
-			     ndev->self_mmio +
-			     ndev->self_reg->db_bell);
-}
-
-static int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_set_mask(ndev, db_bits,
-				ndev->self_mmio +
-				ndev->self_reg->db_mask);
-}
-
-static int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_clear_mask(ndev, db_bits,
-				  ndev->self_mmio +
-				  ndev->self_reg->db_mask);
-}
-
-static int intel_ntb_peer_db_addr(struct ntb_dev *ntb,
-				  phys_addr_t *db_addr,
-				  resource_size_t *db_size)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_addr(ndev, db_addr, db_size, ndev->peer_addr,
-			    ndev->peer_reg->db_bell);
-}
-
-static int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_write(ndev, db_bits,
-			     ndev->peer_mmio +
-			     ndev->peer_reg->db_bell);
-}
-
-static int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb)
-{
-	return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD);
-}
-
-static int intel_ntb_spad_count(struct ntb_dev *ntb)
-{
-	struct intel_ntb_dev *ndev;
-
-	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
-	return ndev->spad_count;
-}
-
-static u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_spad_read(ndev, idx,
-			      ndev->self_mmio +
-			      ndev->self_reg->spad);
-}
-
-static int intel_ntb_spad_write(struct ntb_dev *ntb,
-				int idx, u32 val)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_spad_write(ndev, idx, val,
-			       ndev->self_mmio +
-			       ndev->self_reg->spad);
-}
-
-static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx,
-				    phys_addr_t *spad_addr)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_spad_addr(ndev, sidx, spad_addr, ndev->peer_addr,
-			      ndev->peer_reg->spad);
-}
-
-static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_spad_read(ndev, sidx,
-			      ndev->peer_mmio +
-			      ndev->peer_reg->spad);
-}
-
-static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
-				     int sidx, u32 val)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_spad_write(ndev, sidx, val,
-			       ndev->peer_mmio +
-			       ndev->peer_reg->spad);
-}
-
-/* Skylake Xeon NTB */
-
-static int skx_poll_link(struct intel_ntb_dev *ndev)
-{
-	u16 reg_val;
-	int rc;
-
-	ndev->reg->db_iowrite(ndev->db_link_mask,
-			      ndev->self_mmio +
-			      ndev->self_reg->db_clear);
-
-	rc = pci_read_config_word(ndev->ntb.pdev,
-				  SKX_LINK_STATUS_OFFSET, &reg_val);
-	if (rc)
-		return 0;
-
-	if (reg_val == ndev->lnk_sta)
-		return 0;
-
-	ndev->lnk_sta = reg_val;
-
-	return 1;
-}
-
-static u64 skx_db_ioread(void __iomem *mmio)
-{
-	return ioread64(mmio);
-}
-
-static void skx_db_iowrite(u64 bits, void __iomem *mmio)
-{
-	iowrite64(bits, mmio);
-}
-
-static int skx_init_isr(struct intel_ntb_dev *ndev)
-{
-	int i;
-
-	/*
-	 * The MSIX vectors and the interrupt status bits are not lined up
-	 * on Skylake. By default the link status bit is bit 32, however it
-	 * is by default MSIX vector0. We need to fixup to line them up.
-	 * The vectors at reset is 1-32,0. We need to reprogram to 0-32.
-	 */
-
-	for (i = 0; i < SKX_DB_MSIX_VECTOR_COUNT; i++)
-		iowrite8(i, ndev->self_mmio + SKX_INTVEC_OFFSET + i);
-
-	/* move link status down one as workaround */
-	if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) {
-		iowrite8(SKX_DB_MSIX_VECTOR_COUNT - 2,
-			 ndev->self_mmio + SKX_INTVEC_OFFSET +
-			 (SKX_DB_MSIX_VECTOR_COUNT - 1));
-	}
-
-	return ndev_init_isr(ndev, SKX_DB_MSIX_VECTOR_COUNT,
-			     SKX_DB_MSIX_VECTOR_COUNT,
-			     SKX_DB_MSIX_VECTOR_SHIFT,
-			     SKX_DB_TOTAL_SHIFT);
-}
-
-static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev,
-			    const struct intel_b2b_addr *addr,
-			    const struct intel_b2b_addr *peer_addr)
-{
-	struct pci_dev *pdev;
-	void __iomem *mmio;
-	phys_addr_t bar_addr;
-
-	pdev = ndev->ntb.pdev;
-	mmio = ndev->self_mmio;
-
-	/* setup incoming bar limits == base addrs (zero length windows) */
-	bar_addr = addr->bar2_addr64;
-	iowrite64(bar_addr, mmio + SKX_IMBAR1XLMT_OFFSET);
-	bar_addr = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET);
-	dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr);
-
-	bar_addr = addr->bar4_addr64;
-	iowrite64(bar_addr, mmio + SKX_IMBAR2XLMT_OFFSET);
-	bar_addr = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET);
-	dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr);
-
-	/* zero incoming translation addrs */
-	iowrite64(0, mmio + SKX_IMBAR1XBASE_OFFSET);
-	iowrite64(0, mmio + SKX_IMBAR2XBASE_OFFSET);
-
-	ndev->peer_mmio = ndev->self_mmio;
-
-	return 0;
-}
-
-static int skx_init_ntb(struct intel_ntb_dev *ndev)
-{
-	int rc;
-
-
-	ndev->mw_count = XEON_MW_COUNT;
-	ndev->spad_count = SKX_SPAD_COUNT;
-	ndev->db_count = SKX_DB_COUNT;
-	ndev->db_link_mask = SKX_DB_LINK_BIT;
-
-	/* DB fixup for using 31 right now */
-	if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD)
-		ndev->db_link_mask |= BIT_ULL(31);
-
-	switch (ndev->ntb.topo) {
-	case NTB_TOPO_B2B_USD:
-	case NTB_TOPO_B2B_DSD:
-		ndev->self_reg = &skx_pri_reg;
-		ndev->peer_reg = &skx_b2b_reg;
-		ndev->xlat_reg = &skx_sec_xlat;
-
-		if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
-			rc = skx_setup_b2b_mw(ndev,
-					      &xeon_b2b_dsd_addr,
-					      &xeon_b2b_usd_addr);
-		} else {
-			rc = skx_setup_b2b_mw(ndev,
-					      &xeon_b2b_usd_addr,
-					      &xeon_b2b_dsd_addr);
-		}
-
-		if (rc)
-			return rc;
-
-		/* Enable Bus Master and Memory Space on the secondary side */
-		iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
-			  ndev->self_mmio + SKX_SPCICMD_OFFSET);
-
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
-
-	ndev->reg->db_iowrite(ndev->db_valid_mask,
-			      ndev->self_mmio +
-			      ndev->self_reg->db_mask);
-
-	return 0;
-}
-
-static int skx_init_dev(struct intel_ntb_dev *ndev)
-{
-	struct pci_dev *pdev;
-	u8 ppd;
-	int rc;
-
-	pdev = ndev->ntb.pdev;
-
-	ndev->reg = &skx_reg;
-
-	rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd);
-	if (rc)
-		return -EIO;
-
-	ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
-	dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd,
-		ntb_topo_string(ndev->ntb.topo));
-	if (ndev->ntb.topo == NTB_TOPO_NONE)
-		return -EINVAL;
-
-	if (pdev_is_skx_xeon(pdev))
-		ndev->hwerr_flags |= NTB_HWERR_MSIX_VECTOR32_BAD;
-
-	rc = skx_init_ntb(ndev);
-	if (rc)
-		return rc;
-
-	return skx_init_isr(ndev);
-}
-
-static int intel_ntb3_link_enable(struct ntb_dev *ntb,
-				  enum ntb_speed max_speed,
-				  enum ntb_width max_width)
-{
-	struct intel_ntb_dev *ndev;
-	u32 ntb_ctl;
-
-	ndev = container_of(ntb, struct intel_ntb_dev, ntb);
-
-	dev_dbg(&ntb->pdev->dev,
-		"Enabling link with max_speed %d max_width %d\n",
-		max_speed, max_width);
-
-	if (max_speed != NTB_SPEED_AUTO)
-		dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed);
-	if (max_width != NTB_WIDTH_AUTO)
-		dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width);
-
-	ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
-	ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK);
-	ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP;
-	ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP;
-	iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
-	return 0;
-}
-static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
-				   dma_addr_t addr, resource_size_t size)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-	unsigned long xlat_reg, limit_reg;
-	resource_size_t bar_size, mw_size;
-	void __iomem *mmio;
-	u64 base, limit, reg_val;
-	int bar;
-
-	if (pidx != NTB_DEF_PEER_IDX)
-		return -EINVAL;
-
-	if (idx >= ndev->b2b_idx && !ndev->b2b_off)
-		idx += 1;
-
-	bar = ndev_mw_to_bar(ndev, idx);
-	if (bar < 0)
-		return bar;
-
-	bar_size = pci_resource_len(ndev->ntb.pdev, bar);
-
-	if (idx == ndev->b2b_idx)
-		mw_size = bar_size - ndev->b2b_off;
-	else
-		mw_size = bar_size;
-
-	/* hardware requires that addr is aligned to bar size */
-	if (addr & (bar_size - 1))
-		return -EINVAL;
-
-	/* make sure the range fits in the usable mw size */
-	if (size > mw_size)
-		return -EINVAL;
-
-	mmio = ndev->self_mmio;
-	xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10);
-	limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10);
-	base = pci_resource_start(ndev->ntb.pdev, bar);
-
-	/* Set the limit if supported, if size is not mw_size */
-	if (limit_reg && size != mw_size)
-		limit = base + size;
-	else
-		limit = base + mw_size;
-
-	/* set and verify setting the translation address */
-	iowrite64(addr, mmio + xlat_reg);
-	reg_val = ioread64(mmio + xlat_reg);
-	if (reg_val != addr) {
-		iowrite64(0, mmio + xlat_reg);
-		return -EIO;
-	}
-
-	dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val);
-
-	/* set and verify setting the limit */
-	iowrite64(limit, mmio + limit_reg);
-	reg_val = ioread64(mmio + limit_reg);
-	if (reg_val != limit) {
-		iowrite64(base, mmio + limit_reg);
-		iowrite64(0, mmio + xlat_reg);
-		return -EIO;
-	}
-
-	dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val);
-
-	/* setup the EP */
-	limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000;
-	base = ioread64(mmio + SKX_EMBAR1_OFFSET + (8 * idx));
-	base &= ~0xf;
-
-	if (limit_reg && size != mw_size)
-		limit = base + size;
-	else
-		limit = base + mw_size;
-
-	/* set and verify setting the limit */
-	iowrite64(limit, mmio + limit_reg);
-	reg_val = ioread64(mmio + limit_reg);
-	if (reg_val != limit) {
-		iowrite64(base, mmio + limit_reg);
-		iowrite64(0, mmio + xlat_reg);
-		return -EIO;
-	}
-
-	dev_dbg(&ntb->pdev->dev, "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val);
-
-	return 0;
-}
-
-static int intel_ntb3_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-	int bit;
-
-	if (db_bits & ~ndev->db_valid_mask)
-		return -EINVAL;
-
-	while (db_bits) {
-		bit = __ffs(db_bits);
-		iowrite32(1, ndev->peer_mmio +
-				ndev->peer_reg->db_bell + (bit * 4));
-		db_bits &= db_bits - 1;
-	}
-
-	return 0;
-}
-
-static u64 intel_ntb3_db_read(struct ntb_dev *ntb)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_read(ndev,
-			    ndev->self_mmio +
-			    ndev->self_reg->db_clear);
-}
-
-static int intel_ntb3_db_clear(struct ntb_dev *ntb, u64 db_bits)
-{
-	struct intel_ntb_dev *ndev = ntb_ndev(ntb);
-
-	return ndev_db_write(ndev, db_bits,
-			     ndev->self_mmio +
-			     ndev->self_reg->db_clear);
-}
-
-/* XEON */
-
-static u64 xeon_db_ioread(void __iomem *mmio)
-{
-	return (u64)ioread16(mmio);
-}
-
-static void xeon_db_iowrite(u64 bits, void __iomem *mmio)
-{
-	iowrite16((u16)bits, mmio);
-}
-
-static int xeon_poll_link(struct intel_ntb_dev *ndev)
-{
-	u16 reg_val;
-	int rc;
-
-	ndev->reg->db_iowrite(ndev->db_link_mask,
-			      ndev->self_mmio +
-			      ndev->self_reg->db_bell);
-
-	rc = pci_read_config_word(ndev->ntb.pdev,
-				  XEON_LINK_STATUS_OFFSET, &reg_val);
-	if (rc)
-		return 0;
-
-	if (reg_val == ndev->lnk_sta)
-		return 0;
-
-	ndev->lnk_sta = reg_val;
-
-	return 1;
-}
-
-static int xeon_link_is_up(struct intel_ntb_dev *ndev)
-{
-	if (ndev->ntb.topo == NTB_TOPO_SEC)
-		return 1;
-
-	return NTB_LNK_STA_ACTIVE(ndev->lnk_sta);
-}
-
-static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd)
-{
-	switch (ppd & XEON_PPD_TOPO_MASK) {
-	case XEON_PPD_TOPO_B2B_USD:
-		return NTB_TOPO_B2B_USD;
-
-	case XEON_PPD_TOPO_B2B_DSD:
-		return NTB_TOPO_B2B_DSD;
-
-	case XEON_PPD_TOPO_PRI_USD:
-	case XEON_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */
-		return NTB_TOPO_PRI;
-
-	case XEON_PPD_TOPO_SEC_USD:
-	case XEON_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */
-		return NTB_TOPO_SEC;
-	}
-
-	return NTB_TOPO_NONE;
-}
-
-static inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd)
-{
-	if (ppd & XEON_PPD_SPLIT_BAR_MASK) {
-		dev_dbg(&ndev->ntb.pdev->dev, "PPD %d split bar\n", ppd);
-		return 1;
-	}
-	return 0;
-}
-
-static int xeon_init_isr(struct intel_ntb_dev *ndev)
-{
-	return ndev_init_isr(ndev, XEON_DB_MSIX_VECTOR_COUNT,
-			     XEON_DB_MSIX_VECTOR_COUNT,
-			     XEON_DB_MSIX_VECTOR_SHIFT,
-			     XEON_DB_TOTAL_SHIFT);
-}
-
-static void xeon_deinit_isr(struct intel_ntb_dev *ndev)
-{
-	ndev_deinit_isr(ndev);
-}
-
-static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
-			     const struct intel_b2b_addr *addr,
-			     const struct intel_b2b_addr *peer_addr)
-{
-	struct pci_dev *pdev;
-	void __iomem *mmio;
-	resource_size_t bar_size;
-	phys_addr_t bar_addr;
-	int b2b_bar;
-	u8 bar_sz;
-
-	pdev = ndev->ntb.pdev;
-	mmio = ndev->self_mmio;
-
-	if (ndev->b2b_idx == UINT_MAX) {
-		dev_dbg(&pdev->dev, "not using b2b mw\n");
-		b2b_bar = 0;
-		ndev->b2b_off = 0;
-	} else {
-		b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx);
-		if (b2b_bar < 0)
-			return -EIO;
-
-		dev_dbg(&pdev->dev, "using b2b mw bar %d\n", b2b_bar);
-
-		bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar);
-
-		dev_dbg(&pdev->dev, "b2b bar size %#llx\n", bar_size);
-
-		if (b2b_mw_share && XEON_B2B_MIN_SIZE <= bar_size >> 1) {
-			dev_dbg(&pdev->dev, "b2b using first half of bar\n");
-			ndev->b2b_off = bar_size >> 1;
-		} else if (XEON_B2B_MIN_SIZE <= bar_size) {
-			dev_dbg(&pdev->dev, "b2b using whole bar\n");
-			ndev->b2b_off = 0;
-			--ndev->mw_count;
-		} else {
-			dev_dbg(&pdev->dev, "b2b bar size is too small\n");
-			return -EIO;
-		}
-	}
-
-	/* Reset the secondary bar sizes to match the primary bar sizes,
-	 * except disable or halve the size of the b2b secondary bar.
-	 *
-	 * Note: code for each specific bar size register, because the register
-	 * offsets are not in a consistent order (bar5sz comes after ppd, odd).
-	 */
-	pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &bar_sz);
-	dev_dbg(&pdev->dev, "PBAR23SZ %#x\n", bar_sz);
-	if (b2b_bar == 2) {
-		if (ndev->b2b_off)
-			bar_sz -= 1;
-		else
-			bar_sz = 0;
-	}
-	pci_write_config_byte(pdev, XEON_SBAR23SZ_OFFSET, bar_sz);
-	pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &bar_sz);
-	dev_dbg(&pdev->dev, "SBAR23SZ %#x\n", bar_sz);
-
-	if (!ndev->bar4_split) {
-		pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &bar_sz);
-		dev_dbg(&pdev->dev, "PBAR45SZ %#x\n", bar_sz);
-		if (b2b_bar == 4) {
-			if (ndev->b2b_off)
-				bar_sz -= 1;
-			else
-				bar_sz = 0;
-		}
-		pci_write_config_byte(pdev, XEON_SBAR45SZ_OFFSET, bar_sz);
-		pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &bar_sz);
-		dev_dbg(&pdev->dev, "SBAR45SZ %#x\n", bar_sz);
-	} else {
-		pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &bar_sz);
-		dev_dbg(&pdev->dev, "PBAR4SZ %#x\n", bar_sz);
-		if (b2b_bar == 4) {
-			if (ndev->b2b_off)
-				bar_sz -= 1;
-			else
-				bar_sz = 0;
-		}
-		pci_write_config_byte(pdev, XEON_SBAR4SZ_OFFSET, bar_sz);
-		pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &bar_sz);
-		dev_dbg(&pdev->dev, "SBAR4SZ %#x\n", bar_sz);
-
-		pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &bar_sz);
-		dev_dbg(&pdev->dev, "PBAR5SZ %#x\n", bar_sz);
-		if (b2b_bar == 5) {
-			if (ndev->b2b_off)
-				bar_sz -= 1;
-			else
-				bar_sz = 0;
-		}
-		pci_write_config_byte(pdev, XEON_SBAR5SZ_OFFSET, bar_sz);
-		pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &bar_sz);
-		dev_dbg(&pdev->dev, "SBAR5SZ %#x\n", bar_sz);
-	}
-
-	/* SBAR01 hit by first part of the b2b bar */
-	if (b2b_bar == 0)
-		bar_addr = addr->bar0_addr;
-	else if (b2b_bar == 2)
-		bar_addr = addr->bar2_addr64;
-	else if (b2b_bar == 4 && !ndev->bar4_split)
-		bar_addr = addr->bar4_addr64;
-	else if (b2b_bar == 4)
-		bar_addr = addr->bar4_addr32;
-	else if (b2b_bar == 5)
-		bar_addr = addr->bar5_addr32;
-	else
-		return -EIO;
-
-	dev_dbg(&pdev->dev, "SBAR01 %#018llx\n", bar_addr);
-	iowrite64(bar_addr, mmio + XEON_SBAR0BASE_OFFSET);
-
-	/* Other SBAR are normally hit by the PBAR xlat, except for b2b bar.
-	 * The b2b bar is either disabled above, or configured half-size, and
-	 * it starts at the PBAR xlat + offset.
-	 */
-
-	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
-	iowrite64(bar_addr, mmio + XEON_SBAR23BASE_OFFSET);
-	bar_addr = ioread64(mmio + XEON_SBAR23BASE_OFFSET);
-	dev_dbg(&pdev->dev, "SBAR23 %#018llx\n", bar_addr);
-
-	if (!ndev->bar4_split) {
-		bar_addr = addr->bar4_addr64 +
-			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite64(bar_addr, mmio + XEON_SBAR45BASE_OFFSET);
-		bar_addr = ioread64(mmio + XEON_SBAR45BASE_OFFSET);
-		dev_dbg(&pdev->dev, "SBAR45 %#018llx\n", bar_addr);
-	} else {
-		bar_addr = addr->bar4_addr32 +
-			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + XEON_SBAR4BASE_OFFSET);
-		bar_addr = ioread32(mmio + XEON_SBAR4BASE_OFFSET);
-		dev_dbg(&pdev->dev, "SBAR4 %#010llx\n", bar_addr);
-
-		bar_addr = addr->bar5_addr32 +
-			(b2b_bar == 5 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + XEON_SBAR5BASE_OFFSET);
-		bar_addr = ioread32(mmio + XEON_SBAR5BASE_OFFSET);
-		dev_dbg(&pdev->dev, "SBAR5 %#010llx\n", bar_addr);
-	}
-
-	/* setup incoming bar limits == base addrs (zero length windows) */
-
-	bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0);
-	iowrite64(bar_addr, mmio + XEON_SBAR23LMT_OFFSET);
-	bar_addr = ioread64(mmio + XEON_SBAR23LMT_OFFSET);
-	dev_dbg(&pdev->dev, "SBAR23LMT %#018llx\n", bar_addr);
-
-	if (!ndev->bar4_split) {
-		bar_addr = addr->bar4_addr64 +
-			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite64(bar_addr, mmio + XEON_SBAR45LMT_OFFSET);
-		bar_addr = ioread64(mmio + XEON_SBAR45LMT_OFFSET);
-		dev_dbg(&pdev->dev, "SBAR45LMT %#018llx\n", bar_addr);
-	} else {
-		bar_addr = addr->bar4_addr32 +
-			(b2b_bar == 4 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + XEON_SBAR4LMT_OFFSET);
-		bar_addr = ioread32(mmio + XEON_SBAR4LMT_OFFSET);
-		dev_dbg(&pdev->dev, "SBAR4LMT %#010llx\n", bar_addr);
-
-		bar_addr = addr->bar5_addr32 +
-			(b2b_bar == 5 ? ndev->b2b_off : 0);
-		iowrite32(bar_addr, mmio + XEON_SBAR5LMT_OFFSET);
-		bar_addr = ioread32(mmio + XEON_SBAR5LMT_OFFSET);
-		dev_dbg(&pdev->dev, "SBAR5LMT %#05llx\n", bar_addr);
-	}
-
-	/* zero incoming translation addrs */
-	iowrite64(0, mmio + XEON_SBAR23XLAT_OFFSET);
-
-	if (!ndev->bar4_split) {
-		iowrite64(0, mmio + XEON_SBAR45XLAT_OFFSET);
-	} else {
-		iowrite32(0, mmio + XEON_SBAR4XLAT_OFFSET);
-		iowrite32(0, mmio + XEON_SBAR5XLAT_OFFSET);
-	}
-
-	/* zero outgoing translation limits (whole bar size windows) */
-	iowrite64(0, mmio + XEON_PBAR23LMT_OFFSET);
-	if (!ndev->bar4_split) {
-		iowrite64(0, mmio + XEON_PBAR45LMT_OFFSET);
-	} else {
-		iowrite32(0, mmio + XEON_PBAR4LMT_OFFSET);
-		iowrite32(0, mmio + XEON_PBAR5LMT_OFFSET);
-	}
-
-	/* set outgoing translation offsets */
-	bar_addr = peer_addr->bar2_addr64;
-	iowrite64(bar_addr, mmio + XEON_PBAR23XLAT_OFFSET);
-	bar_addr = ioread64(mmio + XEON_PBAR23XLAT_OFFSET);
-	dev_dbg(&pdev->dev, "PBAR23XLAT %#018llx\n", bar_addr);
-
-	if (!ndev->bar4_split) {
-		bar_addr = peer_addr->bar4_addr64;
-		iowrite64(bar_addr, mmio + XEON_PBAR45XLAT_OFFSET);
-		bar_addr = ioread64(mmio + XEON_PBAR45XLAT_OFFSET);
-		dev_dbg(&pdev->dev, "PBAR45XLAT %#018llx\n", bar_addr);
-	} else {
-		bar_addr = peer_addr->bar4_addr32;
-		iowrite32(bar_addr, mmio + XEON_PBAR4XLAT_OFFSET);
-		bar_addr = ioread32(mmio + XEON_PBAR4XLAT_OFFSET);
-		dev_dbg(&pdev->dev, "PBAR4XLAT %#010llx\n", bar_addr);
-
-		bar_addr = peer_addr->bar5_addr32;
-		iowrite32(bar_addr, mmio + XEON_PBAR5XLAT_OFFSET);
-		bar_addr = ioread32(mmio + XEON_PBAR5XLAT_OFFSET);
-		dev_dbg(&pdev->dev, "PBAR5XLAT %#010llx\n", bar_addr);
-	}
-
-	/* set the translation offset for b2b registers */
-	if (b2b_bar == 0)
-		bar_addr = peer_addr->bar0_addr;
-	else if (b2b_bar == 2)
-		bar_addr = peer_addr->bar2_addr64;
-	else if (b2b_bar == 4 && !ndev->bar4_split)
-		bar_addr = peer_addr->bar4_addr64;
-	else if (b2b_bar == 4)
-		bar_addr = peer_addr->bar4_addr32;
-	else if (b2b_bar == 5)
-		bar_addr = peer_addr->bar5_addr32;
-	else
-		return -EIO;
-
-	/* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */
-	dev_dbg(&pdev->dev, "B2BXLAT %#018llx\n", bar_addr);
-	iowrite32(bar_addr, mmio + XEON_B2B_XLAT_OFFSETL);
-	iowrite32(bar_addr >> 32, mmio + XEON_B2B_XLAT_OFFSETU);
-
-	if (b2b_bar) {
-		/* map peer ntb mmio config space registers */
-		ndev->peer_mmio = pci_iomap(pdev, b2b_bar,
-					    XEON_B2B_MIN_SIZE);
-		if (!ndev->peer_mmio)
-			return -EIO;
-
-		ndev->peer_addr = pci_resource_start(pdev, b2b_bar);
-	}
-
-	return 0;
-}
-
-static int xeon_init_ntb(struct intel_ntb_dev *ndev)
-{
-	struct device *dev = &ndev->ntb.pdev->dev;
-	int rc;
-	u32 ntb_ctl;
-
-	if (ndev->bar4_split)
-		ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT;
-	else
-		ndev->mw_count = XEON_MW_COUNT;
-
-	ndev->spad_count = XEON_SPAD_COUNT;
-	ndev->db_count = XEON_DB_COUNT;
-	ndev->db_link_mask = XEON_DB_LINK_BIT;
-
-	switch (ndev->ntb.topo) {
-	case NTB_TOPO_PRI:
-		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
-			dev_err(dev, "NTB Primary config disabled\n");
-			return -EINVAL;
-		}
-
-		/* enable link to allow secondary side device to appear */
-		ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl);
-		ntb_ctl &= ~NTB_CTL_DISABLE;
-		iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl);
-
-		/* use half the spads for the peer */
-		ndev->spad_count >>= 1;
-		ndev->self_reg = &xeon_pri_reg;
-		ndev->peer_reg = &xeon_sec_reg;
-		ndev->xlat_reg = &xeon_sec_xlat;
-		break;
-
-	case NTB_TOPO_SEC:
-		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
-			dev_err(dev, "NTB Secondary config disabled\n");
-			return -EINVAL;
-		}
-		/* use half the spads for the peer */
-		ndev->spad_count >>= 1;
-		ndev->self_reg = &xeon_sec_reg;
-		ndev->peer_reg = &xeon_pri_reg;
-		ndev->xlat_reg = &xeon_pri_xlat;
-		break;
-
-	case NTB_TOPO_B2B_USD:
-	case NTB_TOPO_B2B_DSD:
-		ndev->self_reg = &xeon_pri_reg;
-		ndev->peer_reg = &xeon_b2b_reg;
-		ndev->xlat_reg = &xeon_sec_xlat;
-
-		if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) {
-			ndev->peer_reg = &xeon_pri_reg;
-
-			if (b2b_mw_idx < 0)
-				ndev->b2b_idx = b2b_mw_idx + ndev->mw_count;
-			else
-				ndev->b2b_idx = b2b_mw_idx;
-
-			if (ndev->b2b_idx >= ndev->mw_count) {
-				dev_dbg(dev,
-					"b2b_mw_idx %d invalid for mw_count %u\n",
-					b2b_mw_idx, ndev->mw_count);
-				return -EINVAL;
-			}
-
-			dev_dbg(dev, "setting up b2b mw idx %d means %d\n",
-				b2b_mw_idx, ndev->b2b_idx);
-
-		} else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) {
-			dev_warn(dev, "Reduce doorbell count by 1\n");
-			ndev->db_count -= 1;
-		}
-
-		if (ndev->ntb.topo == NTB_TOPO_B2B_USD) {
-			rc = xeon_setup_b2b_mw(ndev,
-					       &xeon_b2b_dsd_addr,
-					       &xeon_b2b_usd_addr);
-		} else {
-			rc = xeon_setup_b2b_mw(ndev,
-					       &xeon_b2b_usd_addr,
-					       &xeon_b2b_dsd_addr);
-		}
-		if (rc)
-			return rc;
-
-		/* Enable Bus Master and Memory Space on the secondary side */
-		iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
-			  ndev->self_mmio + XEON_SPCICMD_OFFSET);
-
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
-
-	ndev->reg->db_iowrite(ndev->db_valid_mask,
-			      ndev->self_mmio +
-			      ndev->self_reg->db_mask);
-
-	return 0;
-}
-
-static int xeon_init_dev(struct intel_ntb_dev *ndev)
-{
-	struct pci_dev *pdev;
-	u8 ppd;
-	int rc, mem;
-
-	pdev = ndev->ntb.pdev;
-
-	switch (pdev->device) {
-	/* There is a Xeon hardware errata related to writes to SDOORBELL or
-	 * B2BDOORBELL in conjunction with inbound access to NTB MMIO Space,
-	 * which may hang the system.  To workaround this use the second memory
-	 * window to access the interrupt and scratch pad registers on the
-	 * remote system.
-	 */
-	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
-		ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP;
-		break;
-	}
-
-	switch (pdev->device) {
-	/* There is a hardware errata related to accessing any register in
-	 * SB01BASE in the presence of bidirectional traffic crossing the NTB.
-	 */
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
-		ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP;
-		break;
-	}
-
-	switch (pdev->device) {
-	/* HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
-	 * mirrored to the remote system.  Shrink the number of bits by one,
-	 * since bit 14 is the last bit.
-	 */
-	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
-	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
-	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
-		ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14;
-		break;
-	}
-
-	ndev->reg = &xeon_reg;
-
-	rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd);
-	if (rc)
-		return -EIO;
-
-	ndev->ntb.topo = xeon_ppd_topo(ndev, ppd);
-	dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd,
-		ntb_topo_string(ndev->ntb.topo));
-	if (ndev->ntb.topo == NTB_TOPO_NONE)
-		return -EINVAL;
-
-	if (ndev->ntb.topo != NTB_TOPO_SEC) {
-		ndev->bar4_split = xeon_ppd_bar4_split(ndev, ppd);
-		dev_dbg(&pdev->dev, "ppd %#x bar4_split %d\n",
-			ppd, ndev->bar4_split);
-	} else {
-		/* This is a way for transparent BAR to figure out if we are
-		 * doing split BAR or not. There is no way for the hw on the
-		 * transparent side to know and set the PPD.
-		 */
-		mem = pci_select_bars(pdev, IORESOURCE_MEM);
-		ndev->bar4_split = hweight32(mem) ==
-			HSX_SPLIT_BAR_MW_COUNT + 1;
-		dev_dbg(&pdev->dev, "mem %#x bar4_split %d\n",
-			mem, ndev->bar4_split);
-	}
-
-	rc = xeon_init_ntb(ndev);
-	if (rc)
-		return rc;
-
-	return xeon_init_isr(ndev);
-}
-
-static void xeon_deinit_dev(struct intel_ntb_dev *ndev)
-{
-	xeon_deinit_isr(ndev);
-}
-
-static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev)
-{
-	int rc;
-
-	pci_set_drvdata(pdev, ndev);
-
-	rc = pci_enable_device(pdev);
-	if (rc)
-		goto err_pci_enable;
-
-	rc = pci_request_regions(pdev, NTB_NAME);
-	if (rc)
-		goto err_pci_regions;
-
-	pci_set_master(pdev);
-
-	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-	if (rc) {
-		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc)
-			goto err_dma_mask;
-		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
-	}
-
-	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-	if (rc) {
-		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-		if (rc)
-			goto err_dma_mask;
-		dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
-	}
-	rc = dma_coerce_mask_and_coherent(&ndev->ntb.dev,
-					  dma_get_mask(&pdev->dev));
-	if (rc)
-		goto err_dma_mask;
-
-	ndev->self_mmio = pci_iomap(pdev, 0, 0);
-	if (!ndev->self_mmio) {
-		rc = -EIO;
-		goto err_mmio;
-	}
-	ndev->peer_mmio = ndev->self_mmio;
-	ndev->peer_addr = pci_resource_start(pdev, 0);
-
-	return 0;
-
-err_mmio:
-err_dma_mask:
-	pci_clear_master(pdev);
-	pci_release_regions(pdev);
-err_pci_regions:
-	pci_disable_device(pdev);
-err_pci_enable:
-	pci_set_drvdata(pdev, NULL);
-	return rc;
-}
-
-static void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev)
-{
-	struct pci_dev *pdev = ndev->ntb.pdev;
-
-	if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio)
-		pci_iounmap(pdev, ndev->peer_mmio);
-	pci_iounmap(pdev, ndev->self_mmio);
-
-	pci_clear_master(pdev);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-}
-
-static inline void ndev_init_struct(struct intel_ntb_dev *ndev,
-				    struct pci_dev *pdev)
-{
-	ndev->ntb.pdev = pdev;
-	ndev->ntb.topo = NTB_TOPO_NONE;
-	ndev->ntb.ops = &intel_ntb_ops;
-
-	ndev->b2b_off = 0;
-	ndev->b2b_idx = UINT_MAX;
-
-	ndev->bar4_split = 0;
-
-	ndev->mw_count = 0;
-	ndev->spad_count = 0;
-	ndev->db_count = 0;
-	ndev->db_vec_count = 0;
-	ndev->db_vec_shift = 0;
-
-	ndev->ntb_ctl = 0;
-	ndev->lnk_sta = 0;
-
-	ndev->db_valid_mask = 0;
-	ndev->db_link_mask = 0;
-	ndev->db_mask = 0;
-
-	spin_lock_init(&ndev->db_mask_lock);
-}
-
-static int intel_ntb_pci_probe(struct pci_dev *pdev,
-			       const struct pci_device_id *id)
-{
-	struct intel_ntb_dev *ndev;
-	int rc, node;
-
-	node = dev_to_node(&pdev->dev);
-
-	if (pdev_is_xeon(pdev)) {
-		ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node);
-		if (!ndev) {
-			rc = -ENOMEM;
-			goto err_ndev;
-		}
-
-		ndev_init_struct(ndev, pdev);
-
-		rc = intel_ntb_init_pci(ndev, pdev);
-		if (rc)
-			goto err_init_pci;
-
-		rc = xeon_init_dev(ndev);
-		if (rc)
-			goto err_init_dev;
-
-	} else if (pdev_is_skx_xeon(pdev)) {
-		ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node);
-		if (!ndev) {
-			rc = -ENOMEM;
-			goto err_ndev;
-		}
-
-		ndev_init_struct(ndev, pdev);
-		ndev->ntb.ops = &intel_ntb3_ops;
-
-		rc = intel_ntb_init_pci(ndev, pdev);
-		if (rc)
-			goto err_init_pci;
-
-		rc = skx_init_dev(ndev);
-		if (rc)
-			goto err_init_dev;
-
-	} else {
-		rc = -EINVAL;
-		goto err_ndev;
-	}
-
-	ndev_reset_unsafe_flags(ndev);
-
-	ndev->reg->poll_link(ndev);
-
-	ndev_init_debugfs(ndev);
-
-	rc = ntb_register_device(&ndev->ntb);
-	if (rc)
-		goto err_register;
-
-	dev_info(&pdev->dev, "NTB device registered.\n");
-
-	return 0;
-
-err_register:
-	ndev_deinit_debugfs(ndev);
-	if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev))
-		xeon_deinit_dev(ndev);
-err_init_dev:
-	intel_ntb_deinit_pci(ndev);
-err_init_pci:
-	kfree(ndev);
-err_ndev:
-	return rc;
-}
-
-static void intel_ntb_pci_remove(struct pci_dev *pdev)
-{
-	struct intel_ntb_dev *ndev = pci_get_drvdata(pdev);
-
-	ntb_unregister_device(&ndev->ntb);
-	ndev_deinit_debugfs(ndev);
-	if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev))
-		xeon_deinit_dev(ndev);
-	intel_ntb_deinit_pci(ndev);
-	kfree(ndev);
-}
-
-static const struct intel_ntb_reg xeon_reg = {
-	.poll_link		= xeon_poll_link,
-	.link_is_up		= xeon_link_is_up,
-	.db_ioread		= xeon_db_ioread,
-	.db_iowrite		= xeon_db_iowrite,
-	.db_size		= sizeof(u32),
-	.ntb_ctl		= XEON_NTBCNTL_OFFSET,
-	.mw_bar			= {2, 4, 5},
-};
-
-static const struct intel_ntb_alt_reg xeon_pri_reg = {
-	.db_bell		= XEON_PDOORBELL_OFFSET,
-	.db_mask		= XEON_PDBMSK_OFFSET,
-	.spad			= XEON_SPAD_OFFSET,
-};
-
-static const struct intel_ntb_alt_reg xeon_sec_reg = {
-	.db_bell		= XEON_SDOORBELL_OFFSET,
-	.db_mask		= XEON_SDBMSK_OFFSET,
-	/* second half of the scratchpads */
-	.spad			= XEON_SPAD_OFFSET + (XEON_SPAD_COUNT << 1),
-};
-
-static const struct intel_ntb_alt_reg xeon_b2b_reg = {
-	.db_bell		= XEON_B2B_DOORBELL_OFFSET,
-	.spad			= XEON_B2B_SPAD_OFFSET,
-};
-
-static const struct intel_ntb_xlat_reg xeon_pri_xlat = {
-	/* Note: no primary .bar0_base visible to the secondary side.
-	 *
-	 * The secondary side cannot get the base address stored in primary
-	 * bars.  The base address is necessary to set the limit register to
-	 * any value other than zero, or unlimited.
-	 *
-	 * WITHOUT THE BASE ADDRESS, THE SECONDARY SIDE CANNOT DISABLE the
-	 * window by setting the limit equal to base, nor can it limit the size
-	 * of the memory window by setting the limit to base + size.
-	 */
-	.bar2_limit		= XEON_PBAR23LMT_OFFSET,
-	.bar2_xlat		= XEON_PBAR23XLAT_OFFSET,
-};
-
-static const struct intel_ntb_xlat_reg xeon_sec_xlat = {
-	.bar0_base		= XEON_SBAR0BASE_OFFSET,
-	.bar2_limit		= XEON_SBAR23LMT_OFFSET,
-	.bar2_xlat		= XEON_SBAR23XLAT_OFFSET,
-};
-
-static struct intel_b2b_addr xeon_b2b_usd_addr = {
-	.bar2_addr64		= XEON_B2B_BAR2_ADDR64,
-	.bar4_addr64		= XEON_B2B_BAR4_ADDR64,
-	.bar4_addr32		= XEON_B2B_BAR4_ADDR32,
-	.bar5_addr32		= XEON_B2B_BAR5_ADDR32,
-};
-
-static struct intel_b2b_addr xeon_b2b_dsd_addr = {
-	.bar2_addr64		= XEON_B2B_BAR2_ADDR64,
-	.bar4_addr64		= XEON_B2B_BAR4_ADDR64,
-	.bar4_addr32		= XEON_B2B_BAR4_ADDR32,
-	.bar5_addr32		= XEON_B2B_BAR5_ADDR32,
-};
-
-static const struct intel_ntb_reg skx_reg = {
-	.poll_link		= skx_poll_link,
-	.link_is_up		= xeon_link_is_up,
-	.db_ioread		= skx_db_ioread,
-	.db_iowrite		= skx_db_iowrite,
-	.db_size		= sizeof(u32),
-	.ntb_ctl		= SKX_NTBCNTL_OFFSET,
-	.mw_bar			= {2, 4},
-};
-
-static const struct intel_ntb_alt_reg skx_pri_reg = {
-	.db_bell		= SKX_EM_DOORBELL_OFFSET,
-	.db_clear		= SKX_IM_INT_STATUS_OFFSET,
-	.db_mask		= SKX_IM_INT_DISABLE_OFFSET,
-	.spad			= SKX_IM_SPAD_OFFSET,
-};
-
-static const struct intel_ntb_alt_reg skx_b2b_reg = {
-	.db_bell		= SKX_IM_DOORBELL_OFFSET,
-	.db_clear		= SKX_EM_INT_STATUS_OFFSET,
-	.db_mask		= SKX_EM_INT_DISABLE_OFFSET,
-	.spad			= SKX_B2B_SPAD_OFFSET,
-};
-
-static const struct intel_ntb_xlat_reg skx_sec_xlat = {
-/*	.bar0_base		= SKX_EMBAR0_OFFSET, */
-	.bar2_limit		= SKX_IMBAR1XLMT_OFFSET,
-	.bar2_xlat		= SKX_IMBAR1XBASE_OFFSET,
-};
-
-/* operations for primary side of local ntb */
-static const struct ntb_dev_ops intel_ntb_ops = {
-	.mw_count		= intel_ntb_mw_count,
-	.mw_get_align		= intel_ntb_mw_get_align,
-	.mw_set_trans		= intel_ntb_mw_set_trans,
-	.peer_mw_count		= intel_ntb_peer_mw_count,
-	.peer_mw_get_addr	= intel_ntb_peer_mw_get_addr,
-	.link_is_up		= intel_ntb_link_is_up,
-	.link_enable		= intel_ntb_link_enable,
-	.link_disable		= intel_ntb_link_disable,
-	.db_is_unsafe		= intel_ntb_db_is_unsafe,
-	.db_valid_mask		= intel_ntb_db_valid_mask,
-	.db_vector_count	= intel_ntb_db_vector_count,
-	.db_vector_mask		= intel_ntb_db_vector_mask,
-	.db_read		= intel_ntb_db_read,
-	.db_clear		= intel_ntb_db_clear,
-	.db_set_mask		= intel_ntb_db_set_mask,
-	.db_clear_mask		= intel_ntb_db_clear_mask,
-	.peer_db_addr		= intel_ntb_peer_db_addr,
-	.peer_db_set		= intel_ntb_peer_db_set,
-	.spad_is_unsafe		= intel_ntb_spad_is_unsafe,
-	.spad_count		= intel_ntb_spad_count,
-	.spad_read		= intel_ntb_spad_read,
-	.spad_write		= intel_ntb_spad_write,
-	.peer_spad_addr		= intel_ntb_peer_spad_addr,
-	.peer_spad_read		= intel_ntb_peer_spad_read,
-	.peer_spad_write	= intel_ntb_peer_spad_write,
-};
-
-static const struct ntb_dev_ops intel_ntb3_ops = {
-	.mw_count		= intel_ntb_mw_count,
-	.mw_get_align		= intel_ntb_mw_get_align,
-	.mw_set_trans		= intel_ntb3_mw_set_trans,
-	.peer_mw_count		= intel_ntb_peer_mw_count,
-	.peer_mw_get_addr	= intel_ntb_peer_mw_get_addr,
-	.link_is_up		= intel_ntb_link_is_up,
-	.link_enable		= intel_ntb3_link_enable,
-	.link_disable		= intel_ntb_link_disable,
-	.db_valid_mask		= intel_ntb_db_valid_mask,
-	.db_vector_count	= intel_ntb_db_vector_count,
-	.db_vector_mask		= intel_ntb_db_vector_mask,
-	.db_read		= intel_ntb3_db_read,
-	.db_clear		= intel_ntb3_db_clear,
-	.db_set_mask		= intel_ntb_db_set_mask,
-	.db_clear_mask		= intel_ntb_db_clear_mask,
-	.peer_db_addr		= intel_ntb_peer_db_addr,
-	.peer_db_set		= intel_ntb3_peer_db_set,
-	.spad_is_unsafe		= intel_ntb_spad_is_unsafe,
-	.spad_count		= intel_ntb_spad_count,
-	.spad_read		= intel_ntb_spad_read,
-	.spad_write		= intel_ntb_spad_write,
-	.peer_spad_addr		= intel_ntb_peer_spad_addr,
-	.peer_spad_read		= intel_ntb_peer_spad_read,
-	.peer_spad_write	= intel_ntb_peer_spad_write,
-};
-
-static const struct file_operations intel_ntb_debugfs_info = {
-	.owner = THIS_MODULE,
-	.open = simple_open,
-	.read = ndev_debugfs_read,
-};
-
-static const struct pci_device_id intel_ntb_pci_tbl[] = {
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BDX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_BDX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_BDX)},
-	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SKX)},
-	{0}
-};
-MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl);
-
-static struct pci_driver intel_ntb_pci_driver = {
-	.name = KBUILD_MODNAME,
-	.id_table = intel_ntb_pci_tbl,
-	.probe = intel_ntb_pci_probe,
-	.remove = intel_ntb_pci_remove,
-};
-
-static int __init intel_ntb_pci_driver_init(void)
-{
-	pr_info("%s %s\n", NTB_DESC, NTB_VER);
-
-	if (debugfs_initialized())
-		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-
-	return pci_register_driver(&intel_ntb_pci_driver);
-}
-module_init(intel_ntb_pci_driver_init);
-
-static void __exit intel_ntb_pci_driver_exit(void)
-{
-	pci_unregister_driver(&intel_ntb_pci_driver);
-
-	debugfs_remove_recursive(debugfs_dir);
-}
-module_exit(intel_ntb_pci_driver_exit);
diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h
index 4415aa7ea775..c49ff8970ce3 100644
--- a/drivers/ntb/hw/intel/ntb_hw_intel.h
+++ b/drivers/ntb/hw/intel/ntb_hw_intel.h
@@ -54,6 +54,7 @@
 #include <linux/ntb.h>
 #include <linux/pci.h>
 
+/* PCI device IDs */
 #define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF	0x3725
 #define PCI_DEVICE_ID_INTEL_NTB_PS_JSF	0x3726
 #define PCI_DEVICE_ID_INTEL_NTB_SS_JSF	0x3727
@@ -71,132 +72,7 @@
 #define PCI_DEVICE_ID_INTEL_NTB_SS_BDX	0x6F0F
 #define PCI_DEVICE_ID_INTEL_NTB_B2B_SKX	0x201C
 
-/* Intel Xeon hardware */
-
-#define XEON_PBAR23LMT_OFFSET		0x0000
-#define XEON_PBAR45LMT_OFFSET		0x0008
-#define XEON_PBAR4LMT_OFFSET		0x0008
-#define XEON_PBAR5LMT_OFFSET		0x000c
-#define XEON_PBAR23XLAT_OFFSET		0x0010
-#define XEON_PBAR45XLAT_OFFSET		0x0018
-#define XEON_PBAR4XLAT_OFFSET		0x0018
-#define XEON_PBAR5XLAT_OFFSET		0x001c
-#define XEON_SBAR23LMT_OFFSET		0x0020
-#define XEON_SBAR45LMT_OFFSET		0x0028
-#define XEON_SBAR4LMT_OFFSET		0x0028
-#define XEON_SBAR5LMT_OFFSET		0x002c
-#define XEON_SBAR23XLAT_OFFSET		0x0030
-#define XEON_SBAR45XLAT_OFFSET		0x0038
-#define XEON_SBAR4XLAT_OFFSET		0x0038
-#define XEON_SBAR5XLAT_OFFSET		0x003c
-#define XEON_SBAR0BASE_OFFSET		0x0040
-#define XEON_SBAR23BASE_OFFSET		0x0048
-#define XEON_SBAR45BASE_OFFSET		0x0050
-#define XEON_SBAR4BASE_OFFSET		0x0050
-#define XEON_SBAR5BASE_OFFSET		0x0054
-#define XEON_SBDF_OFFSET		0x005c
-#define XEON_NTBCNTL_OFFSET		0x0058
-#define XEON_PDOORBELL_OFFSET		0x0060
-#define XEON_PDBMSK_OFFSET		0x0062
-#define XEON_SDOORBELL_OFFSET		0x0064
-#define XEON_SDBMSK_OFFSET		0x0066
-#define XEON_USMEMMISS_OFFSET		0x0070
-#define XEON_SPAD_OFFSET		0x0080
-#define XEON_PBAR23SZ_OFFSET		0x00d0
-#define XEON_PBAR45SZ_OFFSET		0x00d1
-#define XEON_PBAR4SZ_OFFSET		0x00d1
-#define XEON_SBAR23SZ_OFFSET		0x00d2
-#define XEON_SBAR45SZ_OFFSET		0x00d3
-#define XEON_SBAR4SZ_OFFSET		0x00d3
-#define XEON_PPD_OFFSET			0x00d4
-#define XEON_PBAR5SZ_OFFSET		0x00d5
-#define XEON_SBAR5SZ_OFFSET		0x00d6
-#define XEON_WCCNTRL_OFFSET		0x00e0
-#define XEON_UNCERRSTS_OFFSET		0x014c
-#define XEON_CORERRSTS_OFFSET		0x0158
-#define XEON_LINK_STATUS_OFFSET		0x01a2
-#define XEON_SPCICMD_OFFSET		0x0504
-#define XEON_DEVCTRL_OFFSET		0x0598
-#define XEON_DEVSTS_OFFSET		0x059a
-#define XEON_SLINK_STATUS_OFFSET	0x05a2
-#define XEON_B2B_SPAD_OFFSET		0x0100
-#define XEON_B2B_DOORBELL_OFFSET	0x0140
-#define XEON_B2B_XLAT_OFFSETL		0x0144
-#define XEON_B2B_XLAT_OFFSETU		0x0148
-#define XEON_PPD_CONN_MASK		0x03
-#define XEON_PPD_CONN_TRANSPARENT	0x00
-#define XEON_PPD_CONN_B2B		0x01
-#define XEON_PPD_CONN_RP		0x02
-#define XEON_PPD_DEV_MASK		0x10
-#define XEON_PPD_DEV_USD		0x00
-#define XEON_PPD_DEV_DSD		0x10
-#define XEON_PPD_SPLIT_BAR_MASK		0x40
-
-#define XEON_PPD_TOPO_MASK	(XEON_PPD_CONN_MASK | XEON_PPD_DEV_MASK)
-#define XEON_PPD_TOPO_PRI_USD	(XEON_PPD_CONN_RP | XEON_PPD_DEV_USD)
-#define XEON_PPD_TOPO_PRI_DSD	(XEON_PPD_CONN_RP | XEON_PPD_DEV_DSD)
-#define XEON_PPD_TOPO_SEC_USD	(XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_USD)
-#define XEON_PPD_TOPO_SEC_DSD	(XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_DSD)
-#define XEON_PPD_TOPO_B2B_USD	(XEON_PPD_CONN_B2B | XEON_PPD_DEV_USD)
-#define XEON_PPD_TOPO_B2B_DSD	(XEON_PPD_CONN_B2B | XEON_PPD_DEV_DSD)
-
-#define XEON_MW_COUNT			2
-#define HSX_SPLIT_BAR_MW_COUNT		3
-#define XEON_DB_COUNT			15
-#define XEON_DB_LINK			15
-#define XEON_DB_LINK_BIT			BIT_ULL(XEON_DB_LINK)
-#define XEON_DB_MSIX_VECTOR_COUNT	4
-#define XEON_DB_MSIX_VECTOR_SHIFT	5
-#define XEON_DB_TOTAL_SHIFT		16
-#define XEON_SPAD_COUNT			16
-
-/* Intel Skylake Xeon hardware */
-#define SKX_IMBAR1SZ_OFFSET		0x00d0
-#define SKX_IMBAR2SZ_OFFSET		0x00d1
-#define SKX_EMBAR1SZ_OFFSET		0x00d2
-#define SKX_EMBAR2SZ_OFFSET		0x00d3
-#define SKX_DEVCTRL_OFFSET		0x0098
-#define SKX_DEVSTS_OFFSET		0x009a
-#define SKX_UNCERRSTS_OFFSET		0x014c
-#define SKX_CORERRSTS_OFFSET		0x0158
-#define SKX_LINK_STATUS_OFFSET		0x01a2
-
-#define SKX_NTBCNTL_OFFSET		0x0000
-#define SKX_IMBAR1XBASE_OFFSET		0x0010		/* SBAR2XLAT */
-#define SKX_IMBAR1XLMT_OFFSET		0x0018		/* SBAR2LMT */
-#define SKX_IMBAR2XBASE_OFFSET		0x0020		/* SBAR4XLAT */
-#define SKX_IMBAR2XLMT_OFFSET		0x0028		/* SBAR4LMT */
-#define SKX_IM_INT_STATUS_OFFSET	0x0040
-#define SKX_IM_INT_DISABLE_OFFSET	0x0048
-#define SKX_IM_SPAD_OFFSET		0x0080		/* SPAD */
-#define SKX_USMEMMISS_OFFSET		0x0070
-#define SKX_INTVEC_OFFSET		0x00d0
-#define SKX_IM_DOORBELL_OFFSET		0x0100		/* SDOORBELL0 */
-#define SKX_B2B_SPAD_OFFSET		0x0180		/* B2B SPAD */
-#define SKX_EMBAR0XBASE_OFFSET		0x4008		/* B2B_XLAT */
-#define SKX_EMBAR1XBASE_OFFSET		0x4010		/* PBAR2XLAT */
-#define SKX_EMBAR1XLMT_OFFSET		0x4018		/* PBAR2LMT */
-#define SKX_EMBAR2XBASE_OFFSET		0x4020		/* PBAR4XLAT */
-#define SKX_EMBAR2XLMT_OFFSET		0x4028		/* PBAR4LMT */
-#define SKX_EM_INT_STATUS_OFFSET	0x4040
-#define SKX_EM_INT_DISABLE_OFFSET	0x4048
-#define SKX_EM_SPAD_OFFSET		0x4080		/* remote SPAD */
-#define SKX_EM_DOORBELL_OFFSET		0x4100		/* PDOORBELL0 */
-#define SKX_SPCICMD_OFFSET		0x4504		/* SPCICMD */
-#define SKX_EMBAR0_OFFSET		0x4510		/* SBAR0BASE */
-#define SKX_EMBAR1_OFFSET		0x4518		/* SBAR23BASE */
-#define SKX_EMBAR2_OFFSET		0x4520		/* SBAR45BASE */
-
-#define SKX_DB_COUNT			32
-#define SKX_DB_LINK			32
-#define SKX_DB_LINK_BIT			BIT_ULL(SKX_DB_LINK)
-#define SKX_DB_MSIX_VECTOR_COUNT	33
-#define SKX_DB_MSIX_VECTOR_SHIFT	1
-#define SKX_DB_TOTAL_SHIFT		33
-#define SKX_SPAD_COUNT			16
-
 /* Ntb control and link status */
-
 #define NTB_CTL_CFG_LOCK		BIT(0)
 #define NTB_CTL_DISABLE			BIT(1)
 #define NTB_CTL_S2P_BAR2_SNOOP		BIT(2)
@@ -213,23 +89,6 @@
 #define NTB_LNK_STA_SPEED(x)		((x) & NTB_LNK_STA_SPEED_MASK)
 #define NTB_LNK_STA_WIDTH(x)		(((x) & NTB_LNK_STA_WIDTH_MASK) >> 4)
 
-/* Use the following addresses for translation between b2b ntb devices in case
- * the hardware default values are not reliable. */
-#define XEON_B2B_BAR0_ADDR	0x1000000000000000ull
-#define XEON_B2B_BAR2_ADDR64	0x2000000000000000ull
-#define XEON_B2B_BAR4_ADDR64	0x4000000000000000ull
-#define XEON_B2B_BAR4_ADDR32	0x20000000u
-#define XEON_B2B_BAR5_ADDR32	0x40000000u
-
-/* The peer ntb secondary config space is 32KB fixed size */
-#define XEON_B2B_MIN_SIZE		0x8000
-
-/* flags to indicate hardware errata */
-#define NTB_HWERR_SDOORBELL_LOCKUP	BIT_ULL(0)
-#define NTB_HWERR_SB01BASE_LOCKUP	BIT_ULL(1)
-#define NTB_HWERR_B2BDOORBELL_BIT14	BIT_ULL(2)
-#define NTB_HWERR_MSIX_VECTOR32_BAD	BIT_ULL(3)
-
 /* flags to indicate unsafe api */
 #define NTB_UNSAFE_DB			BIT_ULL(0)
 #define NTB_UNSAFE_SPAD			BIT_ULL(1)
@@ -328,4 +187,64 @@ struct intel_ntb_dev {
 #define hb_ndev(__work) container_of(__work, struct intel_ntb_dev, \
 				     hb_timer.work)
 
+static inline int pdev_is_gen1(struct pci_dev *pdev)
+{
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_SS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_PS_BDX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
+	case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX:
+		return 1;
+	}
+	return 0;
+}
+
+static inline int pdev_is_gen3(struct pci_dev *pdev)
+{
+	if (pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_SKX)
+		return 1;
+
+	return 0;
+}
+
+#ifndef ioread64
+#ifdef readq
+#define ioread64 readq
+#else
+#define ioread64 _ioread64
+static inline u64 _ioread64(void __iomem *mmio)
+{
+	u64 low, high;
+
+	low = ioread32(mmio);
+	high = ioread32(mmio + sizeof(u32));
+	return low | (high << 32);
+}
+#endif
+#endif
+
+#ifndef iowrite64
+#ifdef writeq
+#define iowrite64 writeq
+#else
+#define iowrite64 _iowrite64
+static inline void _iowrite64(u64 val, void __iomem *mmio)
+{
+	iowrite32(val, mmio);
+	iowrite32(val >> 32, mmio + sizeof(u32));
+}
+#endif
+#endif
+
 #endif
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ad28de96e13f..091aa9449c3a 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1283,6 +1283,190 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
 }
 EXPORT_SYMBOL(of_parse_phandle_with_args);
 
+/**
+ * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it
+ * @np:		pointer to a device tree node containing a list
+ * @list_name:	property name that contains a list
+ * @stem_name:	stem of property names that specify phandles' arguments count
+ * @index:	index of a phandle to parse out
+ * @out_args:	optional pointer to output arguments structure (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_args, on error returns appropriate errno
+ * value. The difference between this function and of_parse_phandle_with_args()
+ * is that this API remaps a phandle if the node the phandle points to has
+ * a <@stem_name>-map property.
+ *
+ * Caller is responsible to call of_node_put() on the returned out_args->np
+ * pointer.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ *	#list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ *	#list-cells = <1>;
+ * }
+ *
+ * phandle3: node3 {
+ * 	#list-cells = <1>;
+ * 	list-map = <0 &phandle2 3>,
+ * 		   <1 &phandle2 2>,
+ * 		   <2 &phandle1 5 1>;
+ *	list-map-mask = <0x3>;
+ * };
+ *
+ * node4 {
+ *	list = <&phandle1 1 2 &phandle3 0>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandle_with_args(node4, "list", "list", 1, &args);
+ */
+int of_parse_phandle_with_args_map(const struct device_node *np,
+				   const char *list_name,
+				   const char *stem_name,
+				   int index, struct of_phandle_args *out_args)
+{
+	char *cells_name, *map_name = NULL, *mask_name = NULL;
+	char *pass_name = NULL;
+	struct device_node *cur, *new = NULL;
+	const __be32 *map, *mask, *pass;
+	static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
+	static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = 0 };
+	__be32 initial_match_array[MAX_PHANDLE_ARGS];
+	const __be32 *match_array = initial_match_array;
+	int i, ret, map_len, match;
+	u32 list_size, new_size;
+
+	if (index < 0)
+		return -EINVAL;
+
+	cells_name = kasprintf(GFP_KERNEL, "#%s-cells", stem_name);
+	if (!cells_name)
+		return -ENOMEM;
+
+	ret = -ENOMEM;
+	map_name = kasprintf(GFP_KERNEL, "%s-map", stem_name);
+	if (!map_name)
+		goto free;
+
+	mask_name = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name);
+	if (!mask_name)
+		goto free;
+
+	pass_name = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name);
+	if (!pass_name)
+		goto free;
+
+	ret = __of_parse_phandle_with_args(np, list_name, cells_name, 0, index,
+					   out_args);
+	if (ret)
+		goto free;
+
+	/* Get the #<list>-cells property */
+	cur = out_args->np;
+	ret = of_property_read_u32(cur, cells_name, &list_size);
+	if (ret < 0)
+		goto put;
+
+	/* Precalculate the match array - this simplifies match loop */
+	for (i = 0; i < list_size; i++)
+		initial_match_array[i] = cpu_to_be32(out_args->args[i]);
+
+	ret = -EINVAL;
+	while (cur) {
+		/* Get the <list>-map property */
+		map = of_get_property(cur, map_name, &map_len);
+		if (!map) {
+			ret = 0;
+			goto free;
+		}
+		map_len /= sizeof(u32);
+
+		/* Get the <list>-map-mask property (optional) */
+		mask = of_get_property(cur, mask_name, NULL);
+		if (!mask)
+			mask = dummy_mask;
+		/* Iterate through <list>-map property */
+		match = 0;
+		while (map_len > (list_size + 1) && !match) {
+			/* Compare specifiers */
+			match = 1;
+			for (i = 0; i < list_size; i++, map_len--)
+				match &= !((match_array[i] ^ *map++) & mask[i]);
+
+			of_node_put(new);
+			new = of_find_node_by_phandle(be32_to_cpup(map));
+			map++;
+			map_len--;
+
+			/* Check if not found */
+			if (!new)
+				goto put;
+
+			if (!of_device_is_available(new))
+				match = 0;
+
+			ret = of_property_read_u32(new, cells_name, &new_size);
+			if (ret)
+				goto put;
+
+			/* Check for malformed properties */
+			if (WARN_ON(new_size > MAX_PHANDLE_ARGS))
+				goto put;
+			if (map_len < new_size)
+				goto put;
+
+			/* Move forward by new node's #<list>-cells amount */
+			map += new_size;
+			map_len -= new_size;
+		}
+		if (!match)
+			goto put;
+
+		/* Get the <list>-map-pass-thru property (optional) */
+		pass = of_get_property(cur, pass_name, NULL);
+		if (!pass)
+			pass = dummy_pass;
+
+		/*
+		 * Successfully parsed a <list>-map translation; copy new
+		 * specifier into the out_args structure, keeping the
+		 * bits specified in <list>-map-pass-thru.
+		 */
+		match_array = map - new_size;
+		for (i = 0; i < new_size; i++) {
+			__be32 val = *(map - new_size + i);
+
+			if (i < list_size) {
+				val &= ~pass[i];
+				val |= cpu_to_be32(out_args->args[i]) & pass[i];
+			}
+
+			out_args->args[i] = be32_to_cpu(val);
+		}
+		out_args->args_count = list_size = new_size;
+		/* Iterate again with new provider */
+		out_args->np = new;
+		of_node_put(cur);
+		cur = new;
+	}
+put:
+	of_node_put(cur);
+	of_node_put(new);
+free:
+	kfree(mask_name);
+	kfree(map_name);
+	kfree(cells_name);
+	kfree(pass_name);
+
+	return ret;
+}
+EXPORT_SYMBOL(of_parse_phandle_with_args_map);
+
 /**
  * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list
  * @np:		pointer to a device tree node containing a list
diff --git a/drivers/of/unittest-data/tests-phandle.dtsi b/drivers/of/unittest-data/tests-phandle.dtsi
index 3c2f09e56b61..6b33be4c4416 100644
--- a/drivers/of/unittest-data/tests-phandle.dtsi
+++ b/drivers/of/unittest-data/tests-phandle.dtsi
@@ -26,6 +26,18 @@
 				#phandle-cells = <3>;
 			};
 
+			provider4: provider4 {
+				#phandle-cells = <2>;
+				phandle-map = <0 1 &provider1 3>,
+					      <4 0 &provider0>,
+					      <16 5 &provider3 3 5 0>,
+					      <200 8 &provider2 23 6>,
+					      <19 0 &provider2 15 0>,
+					      <2 3 &provider3 2 5 3>;
+				phandle-map-mask = <0xff 0xf>;
+				phandle-map-pass-thru = <0x0 0xf0>;
+			};
+
 			consumer-a {
 				phandle-list =	<&provider1 1>,
 						<&provider2 2 0>,
@@ -44,6 +56,19 @@
 				unterminated-string = [40 41 42 43];
 				unterminated-string-list = "first", "second", [40 41 42 43];
 			};
+
+			consumer-b {
+				phandle-list =	<&provider1 1>,
+						<&provider4 2 3>,
+						<0>,
+						<&provider4 4 0x100>,
+						<&provider4 0 0x61>,
+						<&provider0>,
+						<&provider4 19 0x20>;
+				phandle-list-bad-phandle = <12345678 0 0>;
+				phandle-list-bad-args = <&provider2 1 0>,
+							<&provider4 0>;
+			};
 		};
 	};
 };
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 7a9abaae874d..8e23b51eead1 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -453,6 +453,125 @@ static void __init of_unittest_parse_phandle_with_args(void)
 	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 }
 
+static void __init of_unittest_parse_phandle_with_args_map(void)
+{
+	struct device_node *np, *p0, *p1, *p2, *p3;
+	struct of_phandle_args args;
+	int i, rc;
+
+	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b");
+	if (!np) {
+		pr_err("missing testcase data\n");
+		return;
+	}
+
+	p0 = of_find_node_by_path("/testcase-data/phandle-tests/provider0");
+	if (!p0) {
+		pr_err("missing testcase data\n");
+		return;
+	}
+
+	p1 = of_find_node_by_path("/testcase-data/phandle-tests/provider1");
+	if (!p1) {
+		pr_err("missing testcase data\n");
+		return;
+	}
+
+	p2 = of_find_node_by_path("/testcase-data/phandle-tests/provider2");
+	if (!p2) {
+		pr_err("missing testcase data\n");
+		return;
+	}
+
+	p3 = of_find_node_by_path("/testcase-data/phandle-tests/provider3");
+	if (!p3) {
+		pr_err("missing testcase data\n");
+		return;
+	}
+
+	rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
+	unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
+
+	for (i = 0; i < 8; i++) {
+		bool passed = true;
+
+		rc = of_parse_phandle_with_args_map(np, "phandle-list",
+						    "phandle", i, &args);
+
+		/* Test the values from tests-phandle.dtsi */
+		switch (i) {
+		case 0:
+			passed &= !rc;
+			passed &= (args.np == p1);
+			passed &= (args.args_count == 1);
+			passed &= (args.args[0] == 1);
+			break;
+		case 1:
+			passed &= !rc;
+			passed &= (args.np == p3);
+			passed &= (args.args_count == 3);
+			passed &= (args.args[0] == 2);
+			passed &= (args.args[1] == 5);
+			passed &= (args.args[2] == 3);
+			break;
+		case 2:
+			passed &= (rc == -ENOENT);
+			break;
+		case 3:
+			passed &= !rc;
+			passed &= (args.np == p0);
+			passed &= (args.args_count == 0);
+			break;
+		case 4:
+			passed &= !rc;
+			passed &= (args.np == p1);
+			passed &= (args.args_count == 1);
+			passed &= (args.args[0] == 3);
+			break;
+		case 5:
+			passed &= !rc;
+			passed &= (args.np == p0);
+			passed &= (args.args_count == 0);
+			break;
+		case 6:
+			passed &= !rc;
+			passed &= (args.np == p2);
+			passed &= (args.args_count == 2);
+			passed &= (args.args[0] == 15);
+			passed &= (args.args[1] == 0x20);
+			break;
+		case 7:
+			passed &= (rc == -ENOENT);
+			break;
+		default:
+			passed = false;
+		}
+
+		unittest(passed, "index %i - data error on node %s rc=%i\n",
+			 i, args.np->full_name, rc);
+	}
+
+	/* Check for missing list property */
+	rc = of_parse_phandle_with_args_map(np, "phandle-list-missing",
+					    "phandle", 0, &args);
+	unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+
+	/* Check for missing cells,map,mask property */
+	rc = of_parse_phandle_with_args_map(np, "phandle-list",
+					    "phandle-missing", 0, &args);
+	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+
+	/* Check for bad phandle in list */
+	rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle",
+					    "phandle", 0, &args);
+	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+
+	/* Check for incorrectly formed argument list */
+	rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args",
+					    "phandle", 1, &args);
+	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+}
+
 static void __init of_unittest_property_string(void)
 {
 	const char *strings[4];
@@ -2359,6 +2478,7 @@ static int __init of_unittest(void)
 	of_unittest_find_node_by_name();
 	of_unittest_dynamic();
 	of_unittest_parse_phandle_with_args();
+	of_unittest_parse_phandle_with_args_map();
 	of_unittest_printf();
 	of_unittest_property_string();
 	of_unittest_property_copy();
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index fc734014206f..8b14bd326d4a 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3419,22 +3419,29 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE,
 
 static void quirk_chelsio_extend_vpd(struct pci_dev *dev)
 {
-	pci_set_vpd_size(dev, 8192);
-}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x20, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x21, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x22, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x23, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x24, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x25, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x26, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x30, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x31, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x32, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x35, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x36, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x37, quirk_chelsio_extend_vpd);
+	int chip = (dev->device & 0xf000) >> 12;
+	int func = (dev->device & 0x0f00) >>  8;
+	int prod = (dev->device & 0x00ff) >>  0;
+
+	/*
+	 * If this is a T3-based adapter, there's a 1KB VPD area at offset
+	 * 0xc00 which contains the preferred VPD values.  If this is a T4 or
+	 * later based adapter, the special VPD is at offset 0x400 for the
+	 * Physical Functions (the SR-IOV Virtual Functions have no VPD
+	 * Capabilities).  The PCI VPD Access core routines will normally
+	 * compute the size of the VPD by parsing the VPD Data Structure at
+	 * offset 0x000.  This will result in silent failures when attempting
+	 * to accesses these other VPD areas which are beyond those computed
+	 * limits.
+	 */
+	if (chip == 0x0 && prod >= 0x20)
+		pci_set_vpd_size(dev, 8192);
+	else if (chip >= 0x4 && func < 0x8)
+		pci_set_vpd_size(dev, 2048);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+			quirk_chelsio_extend_vpd);
 
 #ifdef CONFIG_ACPI
 /*
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 2c0dbfcff3e6..d2b0329bc98a 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -1866,9 +1866,23 @@ static struct dentry *debugfs_root;
 static void pinctrl_init_device_debugfs(struct pinctrl_dev *pctldev)
 {
 	struct dentry *device_root;
+	const char *debugfs_name;
+
+	if (pctldev->desc->name &&
+			strcmp(dev_name(pctldev->dev), pctldev->desc->name)) {
+		debugfs_name = devm_kasprintf(pctldev->dev, GFP_KERNEL,
+				"%s-%s", dev_name(pctldev->dev),
+				pctldev->desc->name);
+		if (!debugfs_name) {
+			pr_warn("failed to determine debugfs dir name for %s\n",
+				dev_name(pctldev->dev));
+			return;
+		}
+	} else {
+		debugfs_name = dev_name(pctldev->dev);
+	}
 
-	device_root = debugfs_create_dir(dev_name(pctldev->dev),
-					 debugfs_root);
+	device_root = debugfs_create_dir(debugfs_name, debugfs_root);
 	pctldev->device_root = device_root;
 
 	if (IS_ERR(device_root) || !device_root) {
diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c
index 1fda9d6c7ea3..4b91ff74779b 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-axg.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c
@@ -716,7 +716,7 @@ static const char * const uart_b_groups[] = {
 	"uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x",
 };
 
-static const char * const uart_ao_b_gpioz_groups[] = {
+static const char * const uart_ao_b_z_groups[] = {
 	"uart_ao_tx_b_z", "uart_ao_rx_b_z",
 	"uart_ao_cts_b_z", "uart_ao_rts_b_z",
 };
@@ -855,7 +855,7 @@ static struct meson_pmx_func meson_axg_periphs_functions[] = {
 	FUNCTION(nand),
 	FUNCTION(uart_a),
 	FUNCTION(uart_b),
-	FUNCTION(uart_ao_b_gpioz),
+	FUNCTION(uart_ao_b_z),
 	FUNCTION(i2c0),
 	FUNCTION(i2c1),
 	FUNCTION(i2c2),
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 644c5beb05cb..f3f9f1919f78 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -771,6 +771,8 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 {
 	int status, ret;
 	bool mirror = false;
+	struct regmap_config *one_regmap_config = NULL;
+	int raw_chip_address = (addr & ~0x40) >> 1;
 
 	mutex_init(&mcp->lock);
 
@@ -791,22 +793,38 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 	switch (type) {
 #ifdef CONFIG_SPI_MASTER
 	case MCP_TYPE_S08:
-		mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp,
-					       &mcp23x08_regmap);
-		mcp->reg_shift = 0;
-		mcp->chip.ngpio = 8;
-		mcp->chip.label = "mcp23s08";
-		break;
-
 	case MCP_TYPE_S17:
+		switch (type) {
+		case MCP_TYPE_S08:
+			one_regmap_config =
+				devm_kmemdup(dev, &mcp23x08_regmap,
+					sizeof(struct regmap_config), GFP_KERNEL);
+			mcp->reg_shift = 0;
+			mcp->chip.ngpio = 8;
+			mcp->chip.label = devm_kasprintf(dev, GFP_KERNEL,
+					"mcp23s08.%d", raw_chip_address);
+			break;
+		case MCP_TYPE_S17:
+			one_regmap_config =
+				devm_kmemdup(dev, &mcp23x17_regmap,
+					sizeof(struct regmap_config), GFP_KERNEL);
+			mcp->reg_shift = 1;
+			mcp->chip.ngpio = 16;
+			mcp->chip.label = devm_kasprintf(dev, GFP_KERNEL,
+					"mcp23s17.%d", raw_chip_address);
+			break;
+		}
+		if (!one_regmap_config)
+			return -ENOMEM;
+
+		one_regmap_config->name = devm_kasprintf(dev, GFP_KERNEL, "%d", raw_chip_address);
 		mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp,
-					       &mcp23x17_regmap);
-		mcp->reg_shift = 1;
-		mcp->chip.ngpio = 16;
-		mcp->chip.label = "mcp23s17";
+					       one_regmap_config);
 		break;
 
 	case MCP_TYPE_S18:
+		if (!one_regmap_config)
+			return -ENOMEM;
 		mcp->regmap = devm_regmap_init(dev, &mcp23sxx_spi_regmap, mcp,
 					       &mcp23x17_regmap);
 		mcp->reg_shift = 1;
@@ -900,7 +918,14 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 	if (ret < 0)
 		goto fail;
 
-	mcp->pinctrl_desc.name = "mcp23xxx-pinctrl";
+	if (one_regmap_config) {
+		mcp->pinctrl_desc.name = devm_kasprintf(dev, GFP_KERNEL,
+				"mcp23xxx-pinctrl.%d", raw_chip_address);
+		if (!mcp->pinctrl_desc.name)
+			return -ENOMEM;
+	} else {
+		mcp->pinctrl_desc.name = "mcp23xxx-pinctrl";
+	}
 	mcp->pinctrl_desc.pctlops = &mcp_pinctrl_ops;
 	mcp->pinctrl_desc.confops = &mcp_pinconf_ops;
 	mcp->pinctrl_desc.npins = mcp->chip.ngpio;
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index fcaaa92d76df..195492033075 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -147,4 +147,13 @@ config PINCTRL_QCOM_SSBI_PMIC
          which are using SSBI for communication with SoC. Example PMIC's
          devices are pm8058 and pm8921.
 
+config PINCTRL_SDM845
+       tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
+       depends on GPIOLIB && OF
+       select PINCTRL_MSM
+       help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm Technologies Inc TLMM block found on the Qualcomm
+         Technologies Inc SDM845 platform.
+
 endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 8cb45bbd2e7f..0c6f3ddc296d 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o
+obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 495432f3341b..95e5c5ea40af 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -818,7 +818,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 		return -EINVAL;
 
 	chip = &pctrl->chip;
-	chip->base = 0;
+	chip->base = -1;
 	chip->ngpio = ngpio;
 	chip->label = dev_name(pctrl->dev);
 	chip->parent = pctrl->dev;
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
new file mode 100644
index 000000000000..2ab7a8885757
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -0,0 +1,1323 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)					\
+	[msm_mux_##fname] = {				\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+#define NORTH	0x00500000
+#define SOUTH	0x00900000
+#define EAST	0x00100000
+#define REG_SIZE 0x1000
+#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)	\
+	{						\
+		.name = "gpio" #id,			\
+		.pins = gpio##id##_pins,		\
+		.npins = ARRAY_SIZE(gpio##id##_pins),	\
+		.funcs = (int[]){			\
+			msm_mux_gpio, /* gpio mode */	\
+			msm_mux_##f1,			\
+			msm_mux_##f2,			\
+			msm_mux_##f3,			\
+			msm_mux_##f4,			\
+			msm_mux_##f5,			\
+			msm_mux_##f6,			\
+			msm_mux_##f7,			\
+			msm_mux_##f8,			\
+			msm_mux_##f9,			\
+			msm_mux_##f10			\
+		},					\
+		.nfuncs = 11,				\
+		.ctl_reg = base + REG_SIZE * id,		\
+		.io_reg = base + 0x4 + REG_SIZE * id,		\
+		.intr_cfg_reg = base + 0x8 + REG_SIZE * id,	\
+		.intr_status_reg = base + 0xc + REG_SIZE * id,	\
+		.intr_target_reg = base + 0x8 + REG_SIZE * id,	\
+		.mux_bit = 2,			\
+		.pull_bit = 0,			\
+		.drv_bit = 6,			\
+		.oe_bit = 9,			\
+		.in_bit = 0,			\
+		.out_bit = 1,			\
+		.intr_enable_bit = 0,		\
+		.intr_status_bit = 0,		\
+		.intr_target_bit = 5,		\
+		.intr_target_kpss_val = 3,	\
+		.intr_raw_status_bit = 4,	\
+		.intr_polarity_bit = 1,		\
+		.intr_detection_bit = 2,	\
+		.intr_detection_width = 2,	\
+	}
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{						\
+		.name = #pg_name,			\
+		.pins = pg_name##_pins,			\
+		.npins = ARRAY_SIZE(pg_name##_pins),	\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.intr_cfg_reg = 0,			\
+		.intr_status_reg = 0,			\
+		.intr_target_reg = 0,			\
+		.mux_bit = -1,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+		.intr_enable_bit = -1,			\
+		.intr_status_bit = -1,			\
+		.intr_target_bit = -1,			\
+		.intr_raw_status_bit = -1,		\
+		.intr_polarity_bit = -1,		\
+		.intr_detection_bit = -1,		\
+		.intr_detection_width = -1,		\
+	}
+
+#define UFS_RESET(pg_name, offset)				\
+	{						\
+		.name = #pg_name,			\
+		.pins = pg_name##_pins,			\
+		.npins = ARRAY_SIZE(pg_name##_pins),	\
+		.ctl_reg = offset,			\
+		.io_reg = offset + 0x4,			\
+		.intr_cfg_reg = 0,			\
+		.intr_status_reg = 0,			\
+		.intr_target_reg = 0,			\
+		.mux_bit = -1,				\
+		.pull_bit = 3,				\
+		.drv_bit = 0,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = 0,				\
+		.intr_enable_bit = -1,			\
+		.intr_status_bit = -1,			\
+		.intr_target_bit = -1,			\
+		.intr_raw_status_bit = -1,		\
+		.intr_polarity_bit = -1,		\
+		.intr_detection_bit = -1,		\
+		.intr_detection_width = -1,		\
+	}
+static const struct pinctrl_pin_desc sdm845_pins[] = {
+	PINCTRL_PIN(0, "GPIO_0"),
+	PINCTRL_PIN(1, "GPIO_1"),
+	PINCTRL_PIN(2, "GPIO_2"),
+	PINCTRL_PIN(3, "GPIO_3"),
+	PINCTRL_PIN(4, "GPIO_4"),
+	PINCTRL_PIN(5, "GPIO_5"),
+	PINCTRL_PIN(6, "GPIO_6"),
+	PINCTRL_PIN(7, "GPIO_7"),
+	PINCTRL_PIN(8, "GPIO_8"),
+	PINCTRL_PIN(9, "GPIO_9"),
+	PINCTRL_PIN(10, "GPIO_10"),
+	PINCTRL_PIN(11, "GPIO_11"),
+	PINCTRL_PIN(12, "GPIO_12"),
+	PINCTRL_PIN(13, "GPIO_13"),
+	PINCTRL_PIN(14, "GPIO_14"),
+	PINCTRL_PIN(15, "GPIO_15"),
+	PINCTRL_PIN(16, "GPIO_16"),
+	PINCTRL_PIN(17, "GPIO_17"),
+	PINCTRL_PIN(18, "GPIO_18"),
+	PINCTRL_PIN(19, "GPIO_19"),
+	PINCTRL_PIN(20, "GPIO_20"),
+	PINCTRL_PIN(21, "GPIO_21"),
+	PINCTRL_PIN(22, "GPIO_22"),
+	PINCTRL_PIN(23, "GPIO_23"),
+	PINCTRL_PIN(24, "GPIO_24"),
+	PINCTRL_PIN(25, "GPIO_25"),
+	PINCTRL_PIN(26, "GPIO_26"),
+	PINCTRL_PIN(27, "GPIO_27"),
+	PINCTRL_PIN(28, "GPIO_28"),
+	PINCTRL_PIN(29, "GPIO_29"),
+	PINCTRL_PIN(30, "GPIO_30"),
+	PINCTRL_PIN(31, "GPIO_31"),
+	PINCTRL_PIN(32, "GPIO_32"),
+	PINCTRL_PIN(33, "GPIO_33"),
+	PINCTRL_PIN(34, "GPIO_34"),
+	PINCTRL_PIN(35, "GPIO_35"),
+	PINCTRL_PIN(36, "GPIO_36"),
+	PINCTRL_PIN(37, "GPIO_37"),
+	PINCTRL_PIN(38, "GPIO_38"),
+	PINCTRL_PIN(39, "GPIO_39"),
+	PINCTRL_PIN(40, "GPIO_40"),
+	PINCTRL_PIN(41, "GPIO_41"),
+	PINCTRL_PIN(42, "GPIO_42"),
+	PINCTRL_PIN(43, "GPIO_43"),
+	PINCTRL_PIN(44, "GPIO_44"),
+	PINCTRL_PIN(45, "GPIO_45"),
+	PINCTRL_PIN(46, "GPIO_46"),
+	PINCTRL_PIN(47, "GPIO_47"),
+	PINCTRL_PIN(48, "GPIO_48"),
+	PINCTRL_PIN(49, "GPIO_49"),
+	PINCTRL_PIN(50, "GPIO_50"),
+	PINCTRL_PIN(51, "GPIO_51"),
+	PINCTRL_PIN(52, "GPIO_52"),
+	PINCTRL_PIN(53, "GPIO_53"),
+	PINCTRL_PIN(54, "GPIO_54"),
+	PINCTRL_PIN(55, "GPIO_55"),
+	PINCTRL_PIN(56, "GPIO_56"),
+	PINCTRL_PIN(57, "GPIO_57"),
+	PINCTRL_PIN(58, "GPIO_58"),
+	PINCTRL_PIN(59, "GPIO_59"),
+	PINCTRL_PIN(60, "GPIO_60"),
+	PINCTRL_PIN(61, "GPIO_61"),
+	PINCTRL_PIN(62, "GPIO_62"),
+	PINCTRL_PIN(63, "GPIO_63"),
+	PINCTRL_PIN(64, "GPIO_64"),
+	PINCTRL_PIN(65, "GPIO_65"),
+	PINCTRL_PIN(66, "GPIO_66"),
+	PINCTRL_PIN(67, "GPIO_67"),
+	PINCTRL_PIN(68, "GPIO_68"),
+	PINCTRL_PIN(69, "GPIO_69"),
+	PINCTRL_PIN(70, "GPIO_70"),
+	PINCTRL_PIN(71, "GPIO_71"),
+	PINCTRL_PIN(72, "GPIO_72"),
+	PINCTRL_PIN(73, "GPIO_73"),
+	PINCTRL_PIN(74, "GPIO_74"),
+	PINCTRL_PIN(75, "GPIO_75"),
+	PINCTRL_PIN(76, "GPIO_76"),
+	PINCTRL_PIN(77, "GPIO_77"),
+	PINCTRL_PIN(78, "GPIO_78"),
+	PINCTRL_PIN(79, "GPIO_79"),
+	PINCTRL_PIN(80, "GPIO_80"),
+	PINCTRL_PIN(81, "GPIO_81"),
+	PINCTRL_PIN(82, "GPIO_82"),
+	PINCTRL_PIN(83, "GPIO_83"),
+	PINCTRL_PIN(84, "GPIO_84"),
+	PINCTRL_PIN(85, "GPIO_85"),
+	PINCTRL_PIN(86, "GPIO_86"),
+	PINCTRL_PIN(87, "GPIO_87"),
+	PINCTRL_PIN(88, "GPIO_88"),
+	PINCTRL_PIN(89, "GPIO_89"),
+	PINCTRL_PIN(90, "GPIO_90"),
+	PINCTRL_PIN(91, "GPIO_91"),
+	PINCTRL_PIN(92, "GPIO_92"),
+	PINCTRL_PIN(93, "GPIO_93"),
+	PINCTRL_PIN(94, "GPIO_94"),
+	PINCTRL_PIN(95, "GPIO_95"),
+	PINCTRL_PIN(96, "GPIO_96"),
+	PINCTRL_PIN(97, "GPIO_97"),
+	PINCTRL_PIN(98, "GPIO_98"),
+	PINCTRL_PIN(99, "GPIO_99"),
+	PINCTRL_PIN(100, "GPIO_100"),
+	PINCTRL_PIN(101, "GPIO_101"),
+	PINCTRL_PIN(102, "GPIO_102"),
+	PINCTRL_PIN(103, "GPIO_103"),
+	PINCTRL_PIN(104, "GPIO_104"),
+	PINCTRL_PIN(105, "GPIO_105"),
+	PINCTRL_PIN(106, "GPIO_106"),
+	PINCTRL_PIN(107, "GPIO_107"),
+	PINCTRL_PIN(108, "GPIO_108"),
+	PINCTRL_PIN(109, "GPIO_109"),
+	PINCTRL_PIN(110, "GPIO_110"),
+	PINCTRL_PIN(111, "GPIO_111"),
+	PINCTRL_PIN(112, "GPIO_112"),
+	PINCTRL_PIN(113, "GPIO_113"),
+	PINCTRL_PIN(114, "GPIO_114"),
+	PINCTRL_PIN(115, "GPIO_115"),
+	PINCTRL_PIN(116, "GPIO_116"),
+	PINCTRL_PIN(117, "GPIO_117"),
+	PINCTRL_PIN(118, "GPIO_118"),
+	PINCTRL_PIN(119, "GPIO_119"),
+	PINCTRL_PIN(120, "GPIO_120"),
+	PINCTRL_PIN(121, "GPIO_121"),
+	PINCTRL_PIN(122, "GPIO_122"),
+	PINCTRL_PIN(123, "GPIO_123"),
+	PINCTRL_PIN(124, "GPIO_124"),
+	PINCTRL_PIN(125, "GPIO_125"),
+	PINCTRL_PIN(126, "GPIO_126"),
+	PINCTRL_PIN(127, "GPIO_127"),
+	PINCTRL_PIN(128, "GPIO_128"),
+	PINCTRL_PIN(129, "GPIO_129"),
+	PINCTRL_PIN(130, "GPIO_130"),
+	PINCTRL_PIN(131, "GPIO_131"),
+	PINCTRL_PIN(132, "GPIO_132"),
+	PINCTRL_PIN(133, "GPIO_133"),
+	PINCTRL_PIN(134, "GPIO_134"),
+	PINCTRL_PIN(135, "GPIO_135"),
+	PINCTRL_PIN(136, "GPIO_136"),
+	PINCTRL_PIN(137, "GPIO_137"),
+	PINCTRL_PIN(138, "GPIO_138"),
+	PINCTRL_PIN(139, "GPIO_139"),
+	PINCTRL_PIN(140, "GPIO_140"),
+	PINCTRL_PIN(141, "GPIO_141"),
+	PINCTRL_PIN(142, "GPIO_142"),
+	PINCTRL_PIN(143, "GPIO_143"),
+	PINCTRL_PIN(144, "GPIO_144"),
+	PINCTRL_PIN(145, "GPIO_145"),
+	PINCTRL_PIN(146, "GPIO_146"),
+	PINCTRL_PIN(147, "GPIO_147"),
+	PINCTRL_PIN(148, "GPIO_148"),
+	PINCTRL_PIN(149, "GPIO_149"),
+	PINCTRL_PIN(150, "SDC2_CLK"),
+	PINCTRL_PIN(151, "SDC2_CMD"),
+	PINCTRL_PIN(152, "SDC2_DATA"),
+	PINCTRL_PIN(153, "UFS_RESET"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+	static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+
+static const unsigned int sdc2_clk_pins[] = { 150 };
+static const unsigned int sdc2_cmd_pins[] = { 151 };
+static const unsigned int sdc2_data_pins[] = { 152 };
+static const unsigned int ufs_reset_pins[] = { 153 };
+
+enum sdm845_functions {
+	msm_mux_gpio,
+	msm_mux_adsp_ext,
+	msm_mux_agera_pll,
+	msm_mux_atest_char,
+	msm_mux_atest_tsens,
+	msm_mux_atest_tsens2,
+	msm_mux_atest_usb1,
+	msm_mux_atest_usb10,
+	msm_mux_atest_usb11,
+	msm_mux_atest_usb12,
+	msm_mux_atest_usb13,
+	msm_mux_atest_usb2,
+	msm_mux_atest_usb20,
+	msm_mux_atest_usb21,
+	msm_mux_atest_usb22,
+	msm_mux_atest_usb23,
+	msm_mux_audio_ref,
+	msm_mux_btfm_slimbus,
+	msm_mux_cam_mclk,
+	msm_mux_cci_async,
+	msm_mux_cci_i2c,
+	msm_mux_cci_timer0,
+	msm_mux_cci_timer1,
+	msm_mux_cci_timer2,
+	msm_mux_cci_timer3,
+	msm_mux_cci_timer4,
+	msm_mux_cri_trng,
+	msm_mux_cri_trng0,
+	msm_mux_cri_trng1,
+	msm_mux_dbg_out,
+	msm_mux_ddr_bist,
+	msm_mux_ddr_pxi0,
+	msm_mux_ddr_pxi1,
+	msm_mux_ddr_pxi2,
+	msm_mux_ddr_pxi3,
+	msm_mux_edp_hot,
+	msm_mux_edp_lcd,
+	msm_mux_gcc_gp1,
+	msm_mux_gcc_gp2,
+	msm_mux_gcc_gp3,
+	msm_mux_jitter_bist,
+	msm_mux_ldo_en,
+	msm_mux_ldo_update,
+	msm_mux_lpass_slimbus,
+	msm_mux_m_voc,
+	msm_mux_mdp_vsync,
+	msm_mux_mdp_vsync0,
+	msm_mux_mdp_vsync1,
+	msm_mux_mdp_vsync2,
+	msm_mux_mdp_vsync3,
+	msm_mux_mss_lte,
+	msm_mux_nav_pps,
+	msm_mux_pa_indicator,
+	msm_mux_pci_e0,
+	msm_mux_pci_e1,
+	msm_mux_phase_flag,
+	msm_mux_pll_bist,
+	msm_mux_pll_bypassnl,
+	msm_mux_pll_reset,
+	msm_mux_pri_mi2s,
+	msm_mux_pri_mi2s_ws,
+	msm_mux_prng_rosc,
+	msm_mux_qdss_cti,
+	msm_mux_qdss,
+	msm_mux_qlink_enable,
+	msm_mux_qlink_request,
+	msm_mux_qspi_clk,
+	msm_mux_qspi_cs,
+	msm_mux_qspi_data,
+	msm_mux_qua_mi2s,
+	msm_mux_qup0,
+	msm_mux_qup1,
+	msm_mux_qup10,
+	msm_mux_qup11,
+	msm_mux_qup12,
+	msm_mux_qup13,
+	msm_mux_qup14,
+	msm_mux_qup15,
+	msm_mux_qup2,
+	msm_mux_qup3,
+	msm_mux_qup4,
+	msm_mux_qup5,
+	msm_mux_qup6,
+	msm_mux_qup7,
+	msm_mux_qup8,
+	msm_mux_qup9,
+	msm_mux_qup_l4,
+	msm_mux_qup_l5,
+	msm_mux_qup_l6,
+	msm_mux_sd_write,
+	msm_mux_sdc4_clk,
+	msm_mux_sdc4_cmd,
+	msm_mux_sdc4_data,
+	msm_mux_sec_mi2s,
+	msm_mux_sp_cmu,
+	msm_mux_spkr_i2s,
+	msm_mux_ter_mi2s,
+	msm_mux_tgu_ch0,
+	msm_mux_tgu_ch1,
+	msm_mux_tgu_ch2,
+	msm_mux_tgu_ch3,
+	msm_mux_tsense_pwm1,
+	msm_mux_tsense_pwm2,
+	msm_mux_tsif1_clk,
+	msm_mux_tsif1_data,
+	msm_mux_tsif1_en,
+	msm_mux_tsif1_error,
+	msm_mux_tsif1_sync,
+	msm_mux_tsif2_clk,
+	msm_mux_tsif2_data,
+	msm_mux_tsif2_en,
+	msm_mux_tsif2_error,
+	msm_mux_tsif2_sync,
+	msm_mux_uim1_clk,
+	msm_mux_uim1_data,
+	msm_mux_uim1_present,
+	msm_mux_uim1_reset,
+	msm_mux_uim2_clk,
+	msm_mux_uim2_data,
+	msm_mux_uim2_present,
+	msm_mux_uim2_reset,
+	msm_mux_uim_batt,
+	msm_mux_usb_phy,
+	msm_mux_vfr_1,
+	msm_mux_vsense_trigger,
+	msm_mux_wlan1_adc0,
+	msm_mux_wlan1_adc1,
+	msm_mux_wlan2_adc0,
+	msm_mux_wlan2_adc1,
+	msm_mux__,
+};
+
+static const char * const ddr_pxi3_groups[] = {
+	"gpio12", "gpio13",
+};
+static const char * const cam_mclk_groups[] = {
+	"gpio13", "gpio14", "gpio15", "gpio16",
+};
+static const char * const pll_bypassnl_groups[] = {
+	"gpio13",
+};
+static const char * const qdss_groups[] = {
+	"gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19",
+	"gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio26",
+	"gpio27", "gpio28", "gpio29", "gpio30", "gpio41", "gpio42", "gpio43",
+	"gpio44", "gpio75", "gpio76", "gpio77", "gpio79", "gpio80", "gpio93",
+	"gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+	"gpio123", "gpio124",
+};
+static const char * const pll_reset_groups[] = {
+	"gpio14",
+};
+static const char * const cci_i2c_groups[] = {
+	"gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qup1_groups[] = {
+	"gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const cci_timer0_groups[] = {
+	"gpio21",
+};
+static const char * const gcc_gp2_groups[] = {
+	"gpio21", "gpio58",
+};
+static const char * const cci_timer1_groups[] = {
+	"gpio22",
+};
+static const char * const gcc_gp3_groups[] = {
+	"gpio22", "gpio59",
+};
+static const char * const cci_timer2_groups[] = {
+	"gpio23",
+};
+static const char * const cci_timer3_groups[] = {
+	"gpio24",
+};
+static const char * const cci_async_groups[] = {
+	"gpio24", "gpio25", "gpio26",
+};
+static const char * const cci_timer4_groups[] = {
+	"gpio25",
+};
+static const char * const qup2_groups[] = {
+	"gpio27", "gpio28", "gpio29", "gpio30",
+};
+static const char * const phase_flag_groups[] = {
+	"gpio29", "gpio30", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+	"gpio64", "gpio74", "gpio75", "gpio76", "gpio77", "gpio89", "gpio90",
+	"gpio96", "gpio99", "gpio100", "gpio103", "gpio137", "gpio138",
+	"gpio139", "gpio140", "gpio141", "gpio142", "gpio143",
+};
+static const char * const qup11_groups[] = {
+	"gpio31", "gpio32", "gpio33", "gpio34",
+};
+static const char * const qup14_groups[] = {
+	"gpio31", "gpio32", "gpio33", "gpio34",
+};
+static const char * const pci_e0_groups[] = {
+	"gpio35", "gpio36",
+};
+static const char * const jitter_bist_groups[] = {
+	"gpio35",
+};
+static const char * const pll_bist_groups[] = {
+	"gpio36",
+};
+static const char * const atest_tsens_groups[] = {
+	"gpio36",
+};
+static const char * const agera_pll_groups[] = {
+	"gpio37",
+};
+static const char * const usb_phy_groups[] = {
+	"gpio38",
+};
+static const char * const lpass_slimbus_groups[] = {
+	"gpio39", "gpio70", "gpio71", "gpio72",
+};
+static const char * const sd_write_groups[] = {
+	"gpio40",
+};
+static const char * const tsif1_error_groups[] = {
+	"gpio40",
+};
+static const char * const qup3_groups[] = {
+	"gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const qup6_groups[] = {
+	"gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const qup12_groups[] = {
+	"gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const qup10_groups[] = {
+	"gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const qua_mi2s_groups[] = {
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+};
+static const char * const gcc_gp1_groups[] = {
+	"gpio57", "gpio78",
+};
+static const char * const cri_trng0_groups[] = {
+	"gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+	"gpio61",
+};
+static const char * const cri_trng_groups[] = {
+	"gpio62",
+};
+static const char * const pri_mi2s_groups[] = {
+	"gpio64", "gpio65", "gpio67", "gpio68",
+};
+static const char * const sp_cmu_groups[] = {
+	"gpio64",
+};
+static const char * const qup8_groups[] = {
+	"gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+	"gpio66",
+};
+static const char * const spkr_i2s_groups[] = {
+	"gpio69", "gpio70", "gpio71", "gpio72",
+};
+static const char * const audio_ref_groups[] = {
+	"gpio69",
+};
+static const char * const tsense_pwm1_groups[] = {
+	"gpio71",
+};
+static const char * const tsense_pwm2_groups[] = {
+	"gpio71",
+};
+static const char * const btfm_slimbus_groups[] = {
+	"gpio73", "gpio74",
+};
+static const char * const atest_usb2_groups[] = {
+	"gpio73",
+};
+static const char * const ter_mi2s_groups[] = {
+	"gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
+};
+static const char * const atest_usb23_groups[] = {
+	"gpio74",
+};
+static const char * const atest_usb22_groups[] = {
+	"gpio75",
+};
+static const char * const atest_usb21_groups[] = {
+	"gpio76",
+};
+static const char * const atest_usb20_groups[] = {
+	"gpio77",
+};
+static const char * const sec_mi2s_groups[] = {
+	"gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+};
+static const char * const qup15_groups[] = {
+	"gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const qup5_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const tsif1_clk_groups[] = {
+	"gpio89",
+};
+static const char * const qup4_groups[] = {
+	"gpio89", "gpio90", "gpio91", "gpio92",
+};
+static const char * const qspi_cs_groups[] = {
+	"gpio89", "gpio90",
+};
+static const char * const tgu_ch3_groups[] = {
+	"gpio89",
+};
+static const char * const tsif1_en_groups[] = {
+	"gpio90",
+};
+static const char * const mdp_vsync0_groups[] = {
+	"gpio90",
+};
+static const char * const mdp_vsync1_groups[] = {
+	"gpio90",
+};
+static const char * const mdp_vsync2_groups[] = {
+	"gpio90",
+};
+static const char * const mdp_vsync3_groups[] = {
+	"gpio90",
+};
+static const char * const tgu_ch0_groups[] = {
+	"gpio90",
+};
+static const char * const tsif1_data_groups[] = {
+	"gpio91",
+};
+static const char * const sdc4_cmd_groups[] = {
+	"gpio91",
+};
+static const char * const qspi_data_groups[] = {
+	"gpio91", "gpio92", "gpio93", "gpio94",
+};
+static const char * const tgu_ch1_groups[] = {
+	"gpio91",
+};
+static const char * const tsif2_error_groups[] = {
+	"gpio92",
+};
+static const char * const sdc4_data_groups[] = {
+	"gpio92",
+	"gpio94",
+	"gpio95",
+	"gpio96",
+};
+static const char * const vfr_1_groups[] = {
+	"gpio92",
+};
+static const char * const tgu_ch2_groups[] = {
+	"gpio92",
+};
+static const char * const tsif2_clk_groups[] = {
+	"gpio93",
+};
+static const char * const sdc4_clk_groups[] = {
+	"gpio93",
+};
+static const char * const qup7_groups[] = {
+	"gpio93", "gpio94", "gpio95", "gpio96",
+};
+static const char * const tsif2_en_groups[] = {
+	"gpio94",
+};
+static const char * const tsif2_data_groups[] = {
+	"gpio95",
+};
+static const char * const qspi_clk_groups[] = {
+	"gpio95",
+};
+static const char * const tsif2_sync_groups[] = {
+	"gpio96",
+};
+static const char * const ldo_en_groups[] = {
+	"gpio97",
+};
+static const char * const ldo_update_groups[] = {
+	"gpio98",
+};
+static const char * const pci_e1_groups[] = {
+	"gpio102", "gpio103",
+};
+static const char * const prng_rosc_groups[] = {
+	"gpio102",
+};
+static const char * const uim2_data_groups[] = {
+	"gpio105",
+};
+static const char * const qup13_groups[] = {
+	"gpio105", "gpio106", "gpio107", "gpio108",
+};
+static const char * const uim2_clk_groups[] = {
+	"gpio106",
+};
+static const char * const uim2_reset_groups[] = {
+	"gpio107",
+};
+static const char * const uim2_present_groups[] = {
+	"gpio108",
+};
+static const char * const uim1_data_groups[] = {
+	"gpio109",
+};
+static const char * const uim1_clk_groups[] = {
+	"gpio110",
+};
+static const char * const uim1_reset_groups[] = {
+	"gpio111",
+};
+static const char * const uim1_present_groups[] = {
+	"gpio112",
+};
+static const char * const uim_batt_groups[] = {
+	"gpio113",
+};
+static const char * const edp_hot_groups[] = {
+	"gpio113",
+};
+static const char * const nav_pps_groups[] = {
+	"gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128",
+	"gpio129", "gpio129", "gpio143", "gpio143",
+};
+static const char * const atest_char_groups[] = {
+	"gpio117", "gpio118", "gpio119", "gpio120", "gpio121",
+};
+static const char * const adsp_ext_groups[] = {
+	"gpio118",
+};
+static const char * const qlink_request_groups[] = {
+	"gpio130",
+};
+static const char * const qlink_enable_groups[] = {
+	"gpio131",
+};
+static const char * const pa_indicator_groups[] = {
+	"gpio135",
+};
+static const char * const mss_lte_groups[] = {
+	"gpio144", "gpio145",
+};
+static const char * const qup0_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+	"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+	"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+	"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+	"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+	"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+	"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+	"gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+	"gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+	"gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+	"gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+	"gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+	"gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+	"gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+	"gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+	"gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+	"gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+	"gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+	"gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+	"gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+	"gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+	"gpio147", "gpio148", "gpio149",
+};
+static const char * const qup9_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const qdss_cti_groups[] = {
+	"gpio4", "gpio5", "gpio51", "gpio52", "gpio62", "gpio63", "gpio90",
+	"gpio91",
+};
+static const char * const ddr_pxi0_groups[] = {
+	"gpio6", "gpio7",
+};
+static const char * const ddr_bist_groups[] = {
+	"gpio7", "gpio8", "gpio9", "gpio10",
+};
+static const char * const atest_tsens2_groups[] = {
+	"gpio7",
+};
+static const char * const vsense_trigger_groups[] = {
+	"gpio7",
+};
+static const char * const atest_usb1_groups[] = {
+	"gpio7",
+};
+static const char * const qup_l4_groups[] = {
+	"gpio8", "gpio35", "gpio105", "gpio123",
+};
+static const char * const wlan1_adc1_groups[] = {
+	"gpio8",
+};
+static const char * const atest_usb13_groups[] = {
+	"gpio8",
+};
+static const char * const ddr_pxi1_groups[] = {
+	"gpio8", "gpio9",
+};
+static const char * const qup_l5_groups[] = {
+	"gpio9", "gpio36", "gpio106", "gpio124",
+};
+static const char * const wlan1_adc0_groups[] = {
+	"gpio9",
+};
+static const char * const atest_usb12_groups[] = {
+	"gpio9",
+};
+static const char * const mdp_vsync_groups[] = {
+	"gpio10", "gpio11", "gpio12", "gpio97", "gpio98",
+};
+static const char * const qup_l6_groups[] = {
+	"gpio10", "gpio37", "gpio107", "gpio125",
+};
+static const char * const wlan2_adc1_groups[] = {
+	"gpio10",
+};
+static const char * const atest_usb11_groups[] = {
+	"gpio10",
+};
+static const char * const ddr_pxi2_groups[] = {
+	"gpio10", "gpio11",
+};
+static const char * const edp_lcd_groups[] = {
+	"gpio11",
+};
+static const char * const dbg_out_groups[] = {
+	"gpio11",
+};
+static const char * const wlan2_adc0_groups[] = {
+	"gpio11",
+};
+static const char * const atest_usb10_groups[] = {
+	"gpio11",
+};
+static const char * const m_voc_groups[] = {
+	"gpio12",
+};
+static const char * const tsif1_sync_groups[] = {
+	"gpio12",
+};
+
+static const struct msm_function sdm845_functions[] = {
+	FUNCTION(gpio),
+	FUNCTION(adsp_ext),
+	FUNCTION(agera_pll),
+	FUNCTION(atest_char),
+	FUNCTION(atest_tsens),
+	FUNCTION(atest_tsens2),
+	FUNCTION(atest_usb1),
+	FUNCTION(atest_usb10),
+	FUNCTION(atest_usb11),
+	FUNCTION(atest_usb12),
+	FUNCTION(atest_usb13),
+	FUNCTION(atest_usb2),
+	FUNCTION(atest_usb20),
+	FUNCTION(atest_usb21),
+	FUNCTION(atest_usb22),
+	FUNCTION(atest_usb23),
+	FUNCTION(audio_ref),
+	FUNCTION(btfm_slimbus),
+	FUNCTION(cam_mclk),
+	FUNCTION(cci_async),
+	FUNCTION(cci_i2c),
+	FUNCTION(cci_timer0),
+	FUNCTION(cci_timer1),
+	FUNCTION(cci_timer2),
+	FUNCTION(cci_timer3),
+	FUNCTION(cci_timer4),
+	FUNCTION(cri_trng),
+	FUNCTION(cri_trng0),
+	FUNCTION(cri_trng1),
+	FUNCTION(dbg_out),
+	FUNCTION(ddr_bist),
+	FUNCTION(ddr_pxi0),
+	FUNCTION(ddr_pxi1),
+	FUNCTION(ddr_pxi2),
+	FUNCTION(ddr_pxi3),
+	FUNCTION(edp_hot),
+	FUNCTION(edp_lcd),
+	FUNCTION(gcc_gp1),
+	FUNCTION(gcc_gp2),
+	FUNCTION(gcc_gp3),
+	FUNCTION(jitter_bist),
+	FUNCTION(ldo_en),
+	FUNCTION(ldo_update),
+	FUNCTION(lpass_slimbus),
+	FUNCTION(m_voc),
+	FUNCTION(mdp_vsync),
+	FUNCTION(mdp_vsync0),
+	FUNCTION(mdp_vsync1),
+	FUNCTION(mdp_vsync2),
+	FUNCTION(mdp_vsync3),
+	FUNCTION(mss_lte),
+	FUNCTION(nav_pps),
+	FUNCTION(pa_indicator),
+	FUNCTION(pci_e0),
+	FUNCTION(pci_e1),
+	FUNCTION(phase_flag),
+	FUNCTION(pll_bist),
+	FUNCTION(pll_bypassnl),
+	FUNCTION(pll_reset),
+	FUNCTION(pri_mi2s),
+	FUNCTION(pri_mi2s_ws),
+	FUNCTION(prng_rosc),
+	FUNCTION(qdss_cti),
+	FUNCTION(qdss),
+	FUNCTION(qlink_enable),
+	FUNCTION(qlink_request),
+	FUNCTION(qspi_clk),
+	FUNCTION(qspi_cs),
+	FUNCTION(qspi_data),
+	FUNCTION(qua_mi2s),
+	FUNCTION(qup0),
+	FUNCTION(qup1),
+	FUNCTION(qup10),
+	FUNCTION(qup11),
+	FUNCTION(qup12),
+	FUNCTION(qup13),
+	FUNCTION(qup14),
+	FUNCTION(qup15),
+	FUNCTION(qup2),
+	FUNCTION(qup3),
+	FUNCTION(qup4),
+	FUNCTION(qup5),
+	FUNCTION(qup6),
+	FUNCTION(qup7),
+	FUNCTION(qup8),
+	FUNCTION(qup9),
+	FUNCTION(qup_l4),
+	FUNCTION(qup_l5),
+	FUNCTION(qup_l6),
+	FUNCTION(sd_write),
+	FUNCTION(sdc4_clk),
+	FUNCTION(sdc4_cmd),
+	FUNCTION(sdc4_data),
+	FUNCTION(sec_mi2s),
+	FUNCTION(sp_cmu),
+	FUNCTION(spkr_i2s),
+	FUNCTION(ter_mi2s),
+	FUNCTION(tgu_ch0),
+	FUNCTION(tgu_ch1),
+	FUNCTION(tgu_ch2),
+	FUNCTION(tgu_ch3),
+	FUNCTION(tsense_pwm1),
+	FUNCTION(tsense_pwm2),
+	FUNCTION(tsif1_clk),
+	FUNCTION(tsif1_data),
+	FUNCTION(tsif1_en),
+	FUNCTION(tsif1_error),
+	FUNCTION(tsif1_sync),
+	FUNCTION(tsif2_clk),
+	FUNCTION(tsif2_data),
+	FUNCTION(tsif2_en),
+	FUNCTION(tsif2_error),
+	FUNCTION(tsif2_sync),
+	FUNCTION(uim1_clk),
+	FUNCTION(uim1_data),
+	FUNCTION(uim1_present),
+	FUNCTION(uim1_reset),
+	FUNCTION(uim2_clk),
+	FUNCTION(uim2_data),
+	FUNCTION(uim2_present),
+	FUNCTION(uim2_reset),
+	FUNCTION(uim_batt),
+	FUNCTION(usb_phy),
+	FUNCTION(vfr_1),
+	FUNCTION(vsense_trigger),
+	FUNCTION(wlan1_adc0),
+	FUNCTION(wlan1_adc1),
+	FUNCTION(wlan2_adc0),
+	FUNCTION(wlan2_adc1),
+};
+
+/* Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sdm845_groups[] = {
+	PINGROUP(0, EAST, qup0, _, _, _, _, _, _, _, _, _),
+	PINGROUP(1, EAST, qup0, _, _, _, _, _, _, _, _, _),
+	PINGROUP(2, EAST, qup0, _, _, _, _, _, _, _, _, _),
+	PINGROUP(3, EAST, qup0, _, _, _, _, _, _, _, _, _),
+	PINGROUP(4, NORTH, qup9, qdss_cti, _, _, _, _, _, _, _, _),
+	PINGROUP(5, NORTH, qup9, qdss_cti, _, _, _, _, _, _, _, _),
+	PINGROUP(6, NORTH, qup9, _, ddr_pxi0, _, _, _, _, _, _, _),
+	PINGROUP(7, NORTH, qup9, ddr_bist, _, atest_tsens2, vsense_trigger, atest_usb1, ddr_pxi0, _, _, _),
+	PINGROUP(8, EAST, qup_l4, _, ddr_bist, _, _, wlan1_adc1, atest_usb13, ddr_pxi1, _, _),
+	PINGROUP(9, EAST, qup_l5, ddr_bist, _, wlan1_adc0, atest_usb12, ddr_pxi1, _, _, _, _),
+	PINGROUP(10, EAST, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1, atest_usb11, ddr_pxi2, _, _, _, _),
+	PINGROUP(11, EAST, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0, atest_usb10, ddr_pxi2, _, _, _, _),
+	PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, _, _, _, _, _, _),
+	PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, qdss, ddr_pxi3, _, _, _, _, _, _),
+	PINGROUP(14, SOUTH, cam_mclk, pll_reset, qdss, _, _, _, _, _, _, _),
+	PINGROUP(15, SOUTH, cam_mclk, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(16, SOUTH, cam_mclk, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(17, SOUTH, cci_i2c, qup1, qdss, _, _, _, _, _, _, _),
+	PINGROUP(18, SOUTH, cci_i2c, qup1, _, qdss, _, _, _, _, _, _),
+	PINGROUP(19, SOUTH, cci_i2c, qup1, _, qdss, _, _, _, _, _, _),
+	PINGROUP(20, SOUTH, cci_i2c, qup1, _, qdss, _, _, _, _, _, _),
+	PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, qdss, _, _, _, _, _, _, _),
+	PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, qdss, _, _, _, _, _, _, _),
+	PINGROUP(23, SOUTH, cci_timer2, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(24, SOUTH, cci_timer3, cci_async, qdss, _, _, _, _, _, _, _),
+	PINGROUP(25, SOUTH, cci_timer4, cci_async, qdss, _, _, _, _, _, _, _),
+	PINGROUP(26, SOUTH, cci_async, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(27, EAST, qup2, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(28, EAST, qup2, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(29, EAST, qup2, _, phase_flag, qdss, _, _, _, _, _, _),
+	PINGROUP(30, EAST, qup2, phase_flag, qdss, _, _, _, _, _, _, _),
+	PINGROUP(31, NORTH, qup11, qup14, _, _, _, _, _, _, _, _),
+	PINGROUP(32, NORTH, qup11, qup14, _, _, _, _, _, _, _, _),
+	PINGROUP(33, NORTH, qup11, qup14, _, _, _, _, _, _, _, _),
+	PINGROUP(34, NORTH, qup11, qup14, _, _, _, _, _, _, _, _),
+	PINGROUP(35, SOUTH, pci_e0, qup_l4, jitter_bist, _, _, _, _, _, _, _),
+	PINGROUP(36, SOUTH, pci_e0, qup_l5, pll_bist, _, atest_tsens, _, _, _, _, _),
+	PINGROUP(37, SOUTH, qup_l6, agera_pll, _, _, _, _, _, _, _, _),
+	PINGROUP(38, NORTH, usb_phy, _, _, _, _, _, _, _, _, _),
+	PINGROUP(39, EAST, lpass_slimbus, _, _, _, _, _, _, _, _, _),
+	PINGROUP(40, SOUTH, sd_write, tsif1_error, _, _, _, _, _, _, _, _),
+	PINGROUP(41, EAST, qup3, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(42, EAST, qup3, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(43, EAST, qup3, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(44, EAST, qup3, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(45, EAST, qup6, _, _, _, _, _, _, _, _, _),
+	PINGROUP(46, EAST, qup6, _, _, _, _, _, _, _, _, _),
+	PINGROUP(47, EAST, qup6, _, _, _, _, _, _, _, _, _),
+	PINGROUP(48, EAST, qup6, _, _, _, _, _, _, _, _, _),
+	PINGROUP(49, NORTH, qup12, _, _, _, _, _, _, _, _, _),
+	PINGROUP(50, NORTH, qup12, _, _, _, _, _, _, _, _, _),
+	PINGROUP(51, NORTH, qup12, qdss_cti, _, _, _, _, _, _, _, _),
+	PINGROUP(52, NORTH, qup12, phase_flag, qdss_cti, _, _, _, _, _, _, _),
+	PINGROUP(53, NORTH, qup10, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(54, NORTH, qup10, _, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(55, NORTH, qup10, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(56, NORTH, qup10, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(58, NORTH, qua_mi2s, gcc_gp2, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(59, NORTH, qua_mi2s, gcc_gp3, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(60, NORTH, qua_mi2s, cri_trng0, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(61, NORTH, qua_mi2s, cri_trng1, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(62, NORTH, qua_mi2s, cri_trng, phase_flag, qdss_cti, _, _, _, _, _, _),
+	PINGROUP(63, NORTH, qua_mi2s, _, phase_flag, qdss_cti, _, _, _, _, _, _),
+	PINGROUP(64, NORTH, pri_mi2s, sp_cmu, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(65, NORTH, pri_mi2s, qup8, _, _, _, _, _, _, _, _),
+	PINGROUP(66, NORTH, pri_mi2s_ws, qup8, _, _, _, _, _, _, _, _),
+	PINGROUP(67, NORTH, pri_mi2s, qup8, _, _, _, _, _, _, _, _),
+	PINGROUP(68, NORTH, pri_mi2s, qup8, _, _, _, _, _, _, _, _),
+	PINGROUP(69, EAST, spkr_i2s, audio_ref, _, _, _, _, _, _, _, _),
+	PINGROUP(70, EAST, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _, _),
+	PINGROUP(71, EAST, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, _, _, _, _, _, _),
+	PINGROUP(72, EAST, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _, _),
+	PINGROUP(73, EAST, btfm_slimbus, atest_usb2, _, _, _, _, _, _, _, _),
+	PINGROUP(74, EAST, btfm_slimbus, ter_mi2s, phase_flag, atest_usb23, _, _, _, _, _, _),
+	PINGROUP(75, EAST, ter_mi2s, phase_flag, qdss, atest_usb22, _, _, _, _, _, _),
+	PINGROUP(76, EAST, ter_mi2s, phase_flag, qdss, atest_usb21, _, _, _, _, _, _),
+	PINGROUP(77, EAST, ter_mi2s, phase_flag, qdss, atest_usb20, _, _, _, _, _, _),
+	PINGROUP(78, EAST, ter_mi2s, gcc_gp1, _, _, _, _, _, _, _, _),
+	PINGROUP(79, NORTH, sec_mi2s, _, _, qdss, _, _, _, _, _, _),
+	PINGROUP(80, NORTH, sec_mi2s, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(81, NORTH, sec_mi2s, qup15, _, _, _, _, _, _, _, _),
+	PINGROUP(82, NORTH, sec_mi2s, qup15, _, _, _, _, _, _, _, _),
+	PINGROUP(83, NORTH, sec_mi2s, qup15, _, _, _, _, _, _, _, _),
+	PINGROUP(84, NORTH, qup15, _, _, _, _, _, _, _, _, _),
+	PINGROUP(85, EAST, qup5, _, _, _, _, _, _, _, _, _),
+	PINGROUP(86, EAST, qup5, _, _, _, _, _, _, _, _, _),
+	PINGROUP(87, EAST, qup5, _, _, _, _, _, _, _, _, _),
+	PINGROUP(88, EAST, qup5, _, _, _, _, _, _, _, _, _),
+	PINGROUP(89, SOUTH, tsif1_clk, qup4, qspi_cs, tgu_ch3, phase_flag, _, _, _, _, _),
+	PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, qspi_cs, mdp_vsync1,
+			    mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag, qdss_cti),
+	PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, qspi_data, tgu_ch1, _, qdss_cti, _, _, _),
+	PINGROUP(92, SOUTH, tsif2_error, sdc4_data, qup4, qspi_data, vfr_1, tgu_ch2, _, _, _, _),
+	PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, qspi_data, _, qdss, _, _, _, _),
+	PINGROUP(94, SOUTH, tsif2_en, sdc4_data, qup7, qspi_data, _, _, _, _, _, _),
+	PINGROUP(95, SOUTH, tsif2_data, sdc4_data, qup7, qspi_clk, _, _, _, _, _, _),
+	PINGROUP(96, SOUTH, tsif2_sync, sdc4_data, qup7, phase_flag, _, _, _, _, _, _),
+	PINGROUP(97, NORTH, _, _, mdp_vsync, ldo_en, _, _, _, _, _, _),
+	PINGROUP(98, NORTH, _, mdp_vsync, ldo_update, _, _, _, _, _, _, _),
+	PINGROUP(99, NORTH, phase_flag, _, _, _, _, _, _, _, _, _),
+	PINGROUP(100, NORTH, phase_flag, _, _, _, _, _, _, _, _, _),
+	PINGROUP(101, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(102, NORTH, pci_e1, prng_rosc, _, _, _, _, _, _, _, _),
+	PINGROUP(103, NORTH, pci_e1, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(104, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, _, _, _, _, _, _, _),
+	PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, _, _, _, _, _, _, _),
+	PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, _, _, _, _, _, _, _),
+	PINGROUP(108, NORTH, uim2_present, qup13, _, _, _, _, _, _, _, _),
+	PINGROUP(109, NORTH, uim1_data, _, _, _, _, _, _, _, _, _),
+	PINGROUP(110, NORTH, uim1_clk, _, _, _, _, _, _, _, _, _),
+	PINGROUP(111, NORTH, uim1_reset, _, _, _, _, _, _, _, _, _),
+	PINGROUP(112, NORTH, uim1_present, _, _, _, _, _, _, _, _, _),
+	PINGROUP(113, NORTH, uim_batt, edp_hot, _, _, _, _, _, _, _, _),
+	PINGROUP(114, NORTH, _, nav_pps, nav_pps, _, _, _, _, _, _, _),
+	PINGROUP(115, NORTH, _, nav_pps, nav_pps, _, _, _, _, _, _, _),
+	PINGROUP(116, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(117, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _),
+	PINGROUP(118, NORTH, adsp_ext, _, qdss, atest_char, _, _, _, _, _, _),
+	PINGROUP(119, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _),
+	PINGROUP(120, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _),
+	PINGROUP(121, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _),
+	PINGROUP(122, EAST, _, qdss, _, _, _, _, _, _, _, _),
+	PINGROUP(123, EAST, qup_l4, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(124, EAST, qup_l5, _, qdss, _, _, _, _, _, _, _),
+	PINGROUP(125, EAST, qup_l6, _, _, _, _, _, _, _, _, _),
+	PINGROUP(126, EAST, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(127, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(128, NORTH, nav_pps, nav_pps, _, _, _, _, _, _, _, _),
+	PINGROUP(129, NORTH, nav_pps, nav_pps, _, _, _, _, _, _, _, _),
+	PINGROUP(130, NORTH, qlink_request, _, _, _, _, _, _, _, _, _),
+	PINGROUP(131, NORTH, qlink_enable, _, _, _, _, _, _, _, _, _),
+	PINGROUP(132, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(133, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(134, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(135, NORTH, _, pa_indicator, _, _, _, _, _, _, _, _),
+	PINGROUP(136, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(137, NORTH, _, _, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(138, NORTH, _, _, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(139, NORTH, _, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(140, NORTH, _, _, phase_flag, _, _, _, _, _, _, _),
+	PINGROUP(141, NORTH, _, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(142, NORTH, _, phase_flag, _, _, _, _, _, _, _, _),
+	PINGROUP(143, NORTH, _, nav_pps, nav_pps, _, phase_flag, _, _, _, _, _),
+	PINGROUP(144, NORTH, mss_lte, _, _, _, _, _, _, _, _, _),
+	PINGROUP(145, NORTH, mss_lte, _, _, _, _, _, _, _, _, _),
+	PINGROUP(146, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(147, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(148, NORTH, _, _, _, _, _, _, _, _, _, _),
+	PINGROUP(149, NORTH, _, _, _, _, _, _, _, _, _, _),
+	SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
+	SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+	UFS_RESET(ufs_reset, 0x99f000),
+};
+
+static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
+	.pins = sdm845_pins,
+	.npins = ARRAY_SIZE(sdm845_pins),
+	.functions = sdm845_functions,
+	.nfunctions = ARRAY_SIZE(sdm845_functions),
+	.groups = sdm845_groups,
+	.ngroups = ARRAY_SIZE(sdm845_groups),
+	.ngpios = 150,
+};
+
+static int sdm845_pinctrl_probe(struct platform_device *pdev)
+{
+	return msm_pinctrl_probe(pdev, &sdm845_pinctrl);
+}
+
+static const struct of_device_id sdm845_pinctrl_of_match[] = {
+	{ .compatible = "qcom,sdm845-pinctrl", },
+	{ },
+};
+
+static struct platform_driver sdm845_pinctrl_driver = {
+	.driver = {
+		.name = "sdm845-pinctrl",
+		.of_match_table = sdm845_pinctrl_of_match,
+	},
+	.probe = sdm845_pinctrl_probe,
+	.remove = msm_pinctrl_remove,
+};
+
+static int __init sdm845_pinctrl_init(void)
+{
+	return platform_driver_register(&sdm845_pinctrl_driver);
+}
+arch_initcall(sdm845_pinctrl_init);
+
+static void __exit sdm845_pinctrl_exit(void)
+{
+	platform_driver_unregister(&sdm845_pinctrl_driver);
+}
+module_exit(sdm845_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI sdm845 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, sdm845_pinctrl_of_match);
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index a102e74ab24e..176bd6df1238 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -104,6 +104,13 @@ config POWER_RESET_MSM
 	help
 	  Power off and restart support for Qualcomm boards.
 
+config POWER_RESET_OCELOT_RESET
+	bool "Microsemi Ocelot reset driver"
+	depends on MSCC_OCELOT || COMPILE_TEST
+	select MFD_SYSCON
+	help
+	  This driver supports restart for Microsemi Ocelot SoC.
+
 config POWER_RESET_PIIX4_POWEROFF
 	tristate "Intel PIIX4 power-off driver"
 	depends on PCI
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index dcc92f5f7a37..6b9eb1393179 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
 obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
 obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
 obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
+obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
 obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
 obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/ocelot-reset.c b/drivers/power/reset/ocelot-reset.c
new file mode 100644
index 000000000000..5a13a5cc8188
--- /dev/null
+++ b/drivers/power/reset/ocelot-reset.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi MIPS SoC reset driver
+ *
+ * License: Dual MIT/GPL
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/notifier.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+
+struct ocelot_reset_context {
+	void __iomem *base;
+	struct regmap *cpu_ctrl;
+	struct notifier_block restart_handler;
+};
+
+#define ICPU_CFG_CPU_SYSTEM_CTRL_RESET 0x20
+#define CORE_RST_PROTECT BIT(2)
+
+#define SOFT_CHIP_RST BIT(0)
+
+static int ocelot_restart_handle(struct notifier_block *this,
+				 unsigned long mode, void *cmd)
+{
+	struct ocelot_reset_context *ctx = container_of(this, struct
+							ocelot_reset_context,
+							restart_handler);
+
+	/* Make sure the core is not protected from reset */
+	regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_RESET,
+			   CORE_RST_PROTECT, 0);
+
+	writel(SOFT_CHIP_RST, ctx->base);
+
+	pr_emerg("Unable to restart system\n");
+	return NOTIFY_DONE;
+}
+
+static int ocelot_reset_probe(struct platform_device *pdev)
+{
+	struct ocelot_reset_context *ctx;
+	struct resource *res;
+
+	struct device *dev = &pdev->dev;
+	int err;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ctx->base))
+		return PTR_ERR(ctx->base);
+
+	ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
+	if (IS_ERR(ctx->cpu_ctrl))
+		return PTR_ERR(ctx->cpu_ctrl);
+
+	ctx->restart_handler.notifier_call = ocelot_restart_handle;
+	ctx->restart_handler.priority = 192;
+	err = register_restart_handler(&ctx->restart_handler);
+	if (err)
+		dev_err(dev, "can't register restart notifier (err=%d)\n", err);
+
+	return err;
+}
+
+static const struct of_device_id ocelot_reset_of_match[] = {
+	{ .compatible = "mscc,ocelot-chip-reset" },
+	{}
+};
+
+static struct platform_driver ocelot_reset_driver = {
+	.probe = ocelot_reset_probe,
+	.driver = {
+		.name = "ocelot-chip-reset",
+		.of_match_table = ocelot_reset_of_match,
+	},
+};
+builtin_platform_driver(ocelot_reset_driver);
diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 001731e88718..f0d8cc19ad1e 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -35,7 +35,6 @@ struct gpio_charger {
 	struct power_supply *charger;
 	struct power_supply_desc charger_desc;
 	struct gpio_desc *gpiod;
-	bool legacy_gpio_requested;
 };
 
 static irqreturn_t gpio_charger_irq(int irq, void *devid)
@@ -119,7 +118,8 @@ struct gpio_charger_platform_data *gpio_charger_parse_dt(struct device *dev)
 
 static int gpio_charger_probe(struct platform_device *pdev)
 {
-	const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	const struct gpio_charger_platform_data *pdata = dev->platform_data;
 	struct power_supply_config psy_cfg = {};
 	struct gpio_charger *gpio_charger;
 	struct power_supply_desc *charger_desc;
@@ -127,19 +127,18 @@ static int gpio_charger_probe(struct platform_device *pdev)
 	int irq;
 
 	if (!pdata) {
-		pdata = gpio_charger_parse_dt(&pdev->dev);
+		pdata = gpio_charger_parse_dt(dev);
 		if (IS_ERR(pdata)) {
 			ret = PTR_ERR(pdata);
 			if (ret != -EPROBE_DEFER)
-				dev_err(&pdev->dev, "No platform data\n");
+				dev_err(dev, "No platform data\n");
 			return ret;
 		}
 	}
 
-	gpio_charger = devm_kzalloc(&pdev->dev, sizeof(*gpio_charger),
-					GFP_KERNEL);
+	gpio_charger = devm_kzalloc(dev, sizeof(*gpio_charger), GFP_KERNEL);
 	if (!gpio_charger) {
-		dev_err(&pdev->dev, "Failed to alloc driver structure\n");
+		dev_err(dev, "Failed to alloc driver structure\n");
 		return -ENOMEM;
 	}
 
@@ -147,38 +146,32 @@ static int gpio_charger_probe(struct platform_device *pdev)
 	 * This will fetch a GPIO descriptor from device tree, ACPI or
 	 * boardfile descriptor tables. It's good to try this first.
 	 */
-	gpio_charger->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
+	gpio_charger->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
 
 	/*
 	 * If this fails and we're not using device tree, try the
 	 * legacy platform data method.
 	 */
-	if (IS_ERR(gpio_charger->gpiod) && !pdev->dev.of_node) {
+	if (IS_ERR(gpio_charger->gpiod) && !dev->of_node) {
 		/* Non-DT: use legacy GPIO numbers */
 		if (!gpio_is_valid(pdata->gpio)) {
-			dev_err(&pdev->dev, "Invalid gpio pin in pdata\n");
+			dev_err(dev, "Invalid gpio pin in pdata\n");
 			return -EINVAL;
 		}
-		ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
+		ret = devm_gpio_request_one(dev, pdata->gpio, GPIOF_IN,
+						dev_name(dev));
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to request gpio pin: %d\n",
 				ret);
 			return ret;
 		}
-		gpio_charger->legacy_gpio_requested = true;
-		ret = gpio_direction_input(pdata->gpio);
-		if (ret) {
-			dev_err(&pdev->dev, "Failed to set gpio to input: %d\n",
-				ret);
-			goto err_gpio_free;
-		}
 		/* Then convert this to gpiod for now */
 		gpio_charger->gpiod = gpio_to_desc(pdata->gpio);
 	} else if (IS_ERR(gpio_charger->gpiod)) {
 		/* Just try again if this happens */
 		if (PTR_ERR(gpio_charger->gpiod) == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
-		dev_err(&pdev->dev, "error getting GPIO descriptor\n");
+		dev_err(dev, "error getting GPIO descriptor\n");
 		return PTR_ERR(gpio_charger->gpiod);
 	}
 
@@ -192,54 +185,31 @@ static int gpio_charger_probe(struct platform_device *pdev)
 
 	psy_cfg.supplied_to = pdata->supplied_to;
 	psy_cfg.num_supplicants = pdata->num_supplicants;
-	psy_cfg.of_node = pdev->dev.of_node;
+	psy_cfg.of_node = dev->of_node;
 	psy_cfg.drv_data = gpio_charger;
 
-	gpio_charger->pdata = pdata;
-
-	gpio_charger->charger = power_supply_register(&pdev->dev,
-						      charger_desc, &psy_cfg);
+	gpio_charger->charger = devm_power_supply_register(dev, charger_desc,
+							   &psy_cfg);
 	if (IS_ERR(gpio_charger->charger)) {
 		ret = PTR_ERR(gpio_charger->charger);
-		dev_err(&pdev->dev, "Failed to register power supply: %d\n",
-			ret);
-		goto err_gpio_free;
+		dev_err(dev, "Failed to register power supply: %d\n", ret);
+		return ret;
 	}
 
 	irq = gpiod_to_irq(gpio_charger->gpiod);
 	if (irq > 0) {
-		ret = request_any_context_irq(irq, gpio_charger_irq,
+		ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				dev_name(&pdev->dev), gpio_charger->charger);
+				dev_name(dev), gpio_charger->charger);
 		if (ret < 0)
-			dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
+			dev_warn(dev, "Failed to request irq: %d\n", ret);
 		else
 			gpio_charger->irq = irq;
 	}
 
 	platform_set_drvdata(pdev, gpio_charger);
 
-	device_init_wakeup(&pdev->dev, 1);
-
-	return 0;
-
-err_gpio_free:
-	if (gpio_charger->legacy_gpio_requested)
-		gpio_free(pdata->gpio);
-	return ret;
-}
-
-static int gpio_charger_remove(struct platform_device *pdev)
-{
-	struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
-
-	if (gpio_charger->irq)
-		free_irq(gpio_charger->irq, gpio_charger->charger);
-
-	power_supply_unregister(gpio_charger->charger);
-
-	if (gpio_charger->legacy_gpio_requested)
-		gpio_free(gpio_charger->pdata->gpio);
+	device_init_wakeup(dev, 1);
 
 	return 0;
 }
@@ -280,7 +250,6 @@ MODULE_DEVICE_TABLE(of, gpio_charger_match);
 
 static struct platform_driver gpio_charger_driver = {
 	.probe = gpio_charger_probe,
-	.remove = gpio_charger_remove,
 	.driver = {
 		.name = "gpio-charger",
 		.pm = &gpio_charger_pm_ops,
diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c
index 4cfa3f0cd689..9360faca7026 100644
--- a/drivers/power/supply/ltc2941-battery-gauge.c
+++ b/drivers/power/supply/ltc2941-battery-gauge.c
@@ -34,6 +34,10 @@ enum ltc294x_reg {
 	LTC294X_REG_CONTROL		= 0x01,
 	LTC294X_REG_ACC_CHARGE_MSB	= 0x02,
 	LTC294X_REG_ACC_CHARGE_LSB	= 0x03,
+	LTC294X_REG_CHARGE_THR_HIGH_MSB	= 0x04,
+	LTC294X_REG_CHARGE_THR_HIGH_LSB	= 0x05,
+	LTC294X_REG_CHARGE_THR_LOW_MSB	= 0x06,
+	LTC294X_REG_CHARGE_THR_LOW_LSB	= 0x07,
 	LTC294X_REG_VOLTAGE_MSB		= 0x08,
 	LTC294X_REG_VOLTAGE_LSB		= 0x09,
 	LTC2942_REG_TEMPERATURE_MSB	= 0x0C,
@@ -179,21 +183,22 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
 	return ret;
 }
 
-static int ltc294x_read_charge_register(const struct ltc294x_info *info)
-{
+static int ltc294x_read_charge_register(const struct ltc294x_info *info,
+					enum ltc294x_reg reg)
+ {
 	int ret;
 	u8 datar[2];
 
-	ret = ltc294x_read_regs(info->client,
-		LTC294X_REG_ACC_CHARGE_MSB, &datar[0], 2);
+	ret = ltc294x_read_regs(info->client, reg, &datar[0], 2);
 	if (ret < 0)
 		return ret;
 	return (datar[0] << 8) + datar[1];
 }
 
-static int ltc294x_get_charge_now(const struct ltc294x_info *info, int *val)
+static int ltc294x_get_charge(const struct ltc294x_info *info,
+				enum ltc294x_reg reg, int *val)
 {
-	int value = ltc294x_read_charge_register(info);
+	int value = ltc294x_read_charge_register(info, reg);
 
 	if (value < 0)
 		return value;
@@ -245,10 +250,29 @@ static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val)
 	return ret < 0 ? ret : 0;
 }
 
+static int ltc294x_set_charge_thr(const struct ltc294x_info *info,
+					enum ltc294x_reg reg, int val)
+{
+	u8 dataw[2];
+	s32 value;
+
+	value = convert_uAh_to_bin(info, val);
+	/* Direction depends on how sense+/- were connected */
+	if (info->Qlsb < 0)
+		value += 0xFFFF;
+	if ((value < 0) || (value > 0xFFFF)) /* input validation */
+		return -EINVAL;
+
+	/* Set new charge value */
+	dataw[0] = I16_MSB(value);
+	dataw[1] = I16_LSB(value);
+	return ltc294x_write_regs(info->client, reg, &dataw[0], 2);
+}
+
 static int ltc294x_get_charge_counter(
 	const struct ltc294x_info *info, int *val)
 {
-	int value = ltc294x_read_charge_register(info);
+	int value = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB);
 
 	if (value < 0)
 		return value;
@@ -336,8 +360,15 @@ static int ltc294x_get_property(struct power_supply *psy,
 	struct ltc294x_info *info = power_supply_get_drvdata(psy);
 
 	switch (prop) {
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		return ltc294x_get_charge(info, LTC294X_REG_CHARGE_THR_HIGH_MSB,
+						&val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY:
+		return ltc294x_get_charge(info, LTC294X_REG_CHARGE_THR_LOW_MSB,
+						&val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
-		return ltc294x_get_charge_now(info, &val->intval);
+		return ltc294x_get_charge(info, LTC294X_REG_ACC_CHARGE_MSB,
+						&val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
 		return ltc294x_get_charge_counter(info, &val->intval);
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
@@ -358,6 +389,12 @@ static int ltc294x_set_property(struct power_supply *psy,
 	struct ltc294x_info *info = power_supply_get_drvdata(psy);
 
 	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		return ltc294x_set_charge_thr(info,
+			LTC294X_REG_CHARGE_THR_HIGH_MSB, val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY:
+		return ltc294x_set_charge_thr(info,
+			LTC294X_REG_CHARGE_THR_LOW_MSB, val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
 		return ltc294x_set_charge_now(info, val->intval);
 	default:
@@ -369,6 +406,8 @@ static int ltc294x_property_is_writeable(
 	struct power_supply *psy, enum power_supply_property psp)
 {
 	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY:
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
 		return 1;
 	default:
@@ -378,7 +417,7 @@ static int ltc294x_property_is_writeable(
 
 static void ltc294x_update(struct ltc294x_info *info)
 {
-	int charge = ltc294x_read_charge_register(info);
+	int charge = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB);
 
 	if (charge != info->charge) {
 		info->charge = charge;
@@ -397,6 +436,8 @@ static void ltc294x_work(struct work_struct *work)
 
 static enum power_supply_property ltc294x_properties[] = {
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_EMPTY,
 	POWER_SUPPLY_PROP_CHARGE_NOW,
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	POWER_SUPPLY_PROP_TEMP,
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index 9a68914100ad..bb655854713d 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -2880,8 +2880,9 @@ static int tsi721_probe(struct pci_dev *pdev,
 				 "Invalid MRRS override value %d", pcie_mrrs);
 	}
 
-	/* Adjust PCIe completion timeout. */
-	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2);
+	/* Set PCIe completion timeout to 1-10ms */
+	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2,
+					   PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0x2);
 
 	/*
 	 * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index dd4708c58480..4549b93b0ff9 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1937,7 +1937,10 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
 	struct gpio_desc *gpiod;
 	int ret;
 
-	gpiod = gpio_to_desc(config->ena_gpio);
+	if (config->ena_gpiod)
+		gpiod = config->ena_gpiod;
+	else
+		gpiod = gpio_to_desc(config->ena_gpio);
 
 	list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
 		if (pin->gpiod == gpiod) {
@@ -1947,15 +1950,18 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev,
 		}
 	}
 
-	ret = gpio_request_one(config->ena_gpio,
-				GPIOF_DIR_OUT | config->ena_gpio_flags,
-				rdev_get_name(rdev));
-	if (ret)
-		return ret;
+	if (!config->ena_gpiod) {
+		ret = gpio_request_one(config->ena_gpio,
+				       GPIOF_DIR_OUT | config->ena_gpio_flags,
+				       rdev_get_name(rdev));
+		if (ret)
+			return ret;
+	}
 
 	pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
 	if (pin == NULL) {
-		gpio_free(config->ena_gpio);
+		if (!config->ena_gpiod)
+			gpio_free(config->ena_gpio);
 		return -ENOMEM;
 	}
 
@@ -4154,8 +4160,9 @@ regulator_register(const struct regulator_desc *regulator_desc,
 			goto clean;
 	}
 
-	if ((config->ena_gpio || config->ena_gpio_initialized) &&
-	    gpio_is_valid(config->ena_gpio)) {
+	if (config->ena_gpiod ||
+	    ((config->ena_gpio || config->ena_gpio_initialized) &&
+	     gpio_is_valid(config->ena_gpio))) {
 		mutex_lock(&regulator_list_mutex);
 		ret = regulator_ena_gpio_request(rdev, config);
 		mutex_unlock(&regulator_list_mutex);
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index d029c941a1e1..f40c3b8644ae 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -455,8 +456,7 @@ static int da9055_gpio_init(struct da9055_regulator *regulator,
 		char name[18];
 		int gpio_mux = pdata->gpio_ren[id];
 
-		config->ena_gpio = pdata->ena_gpio[id];
-		config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+		config->ena_gpiod = pdata->ena_gpiods[id];
 		config->ena_gpio_invert = 1;
 
 		/*
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index 9b8f47617724..6c122b3df5d0 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -15,7 +15,6 @@
  */
 
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -25,7 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/da9211.h>
 #include "da9211-regulator.h"
@@ -294,9 +293,12 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
 
 		pdata->init_data[n] = da9211_matches[i].init_data;
 		pdata->reg_node[n] = da9211_matches[i].of_node;
-		pdata->gpio_ren[n] =
-			of_get_named_gpio(da9211_matches[i].of_node,
-				"enable-gpios", 0);
+		pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
+								  da9211_matches[i].of_node,
+								  "enable",
+								  0,
+								  GPIOD_OUT_HIGH,
+								  "da9211-enable");
 		n++;
 	}
 
@@ -382,13 +384,10 @@ static int da9211_regulator_init(struct da9211 *chip)
 		config.regmap = chip->regmap;
 		config.of_node = chip->pdata->reg_node[i];
 
-		if (gpio_is_valid(chip->pdata->gpio_ren[i])) {
-			config.ena_gpio = chip->pdata->gpio_ren[i];
-			config.ena_gpio_initialized = true;
-		} else {
-			config.ena_gpio = -EINVAL;
-			config.ena_gpio_initialized = false;
-		}
+		if (chip->pdata->gpiod_ren[i])
+			config.ena_gpiod = chip->pdata->gpiod_ren[i];
+		else
+			config.ena_gpiod = NULL;
 
 		chip->rdev[i] = devm_regulator_register(chip->dev,
 			&da9211_regulators[i], &config);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 092ed6efb3ec..f47264fa1940 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -321,6 +321,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,
 				dev_err(dev,
 					"failed to parse DT for regulator %s\n",
 					child->name);
+				of_node_put(child);
 				return -EINVAL;
 			}
 			match->of_node = of_node_get(child);
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
index 72c8b3e1022b..e0a9c445ed67 100644
--- a/drivers/regulator/stm32-vrefbuf.c
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -51,7 +51,7 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
 	 * arbitrary timeout.
 	 */
 	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
-				 !(val & STM32_VRR), 650, 10000);
+				 val & STM32_VRR, 650, 10000);
 	if (ret) {
 		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
 		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index b609e1d3654b..a3658aa01838 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -6,6 +6,7 @@ config REMOTEPROC
 	select CRC32
 	select FW_LOADER
 	select VIRTIO
+	select WANT_DEV_COREDUMP
 	help
 	  Support for remote processors (such as DSP coprocessors). These
 	  are mainly used on embedded systems.
@@ -90,6 +91,7 @@ config QCOM_ADSP_PIL
 	depends on QCOM_SMEM
 	depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
 	depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
+	depends on QCOM_SYSMON || QCOM_SYSMON=n
 	select MFD_SYSCON
 	select QCOM_MDT_LOADER
 	select QCOM_RPROC_COMMON
@@ -107,6 +109,7 @@ config QCOM_Q6V5_PIL
 	depends on QCOM_SMEM
 	depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
 	depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
+	depends on QCOM_SYSMON || QCOM_SYSMON=n
 	select MFD_SYSCON
 	select QCOM_RPROC_COMMON
 	select QCOM_SCM
@@ -114,12 +117,27 @@ config QCOM_Q6V5_PIL
 	  Say y here to support the Qualcomm Peripherial Image Loader for the
 	  Hexagon V5 based remote processors.
 
+config QCOM_SYSMON
+	tristate "Qualcomm sysmon driver"
+	depends on RPMSG
+	depends on ARCH_QCOM
+	select QCOM_QMI_HELPERS
+	help
+	  The sysmon driver implements a sysmon QMI client and a handler for
+	  the sys_mon SMD and GLINK channel, which are used for graceful
+	  shutdown, retrieving failure information and propagating information
+	  about other subsystems being shut down.
+
+	  Say y here if your system runs firmware on any other subsystems, e.g.
+	  modem or DSP.
+
 config QCOM_WCNSS_PIL
 	tristate "Qualcomm WCNSS Peripheral Image Loader"
 	depends on OF && ARCH_QCOM
 	depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
 	depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
 	depends on QCOM_SMEM
+	depends on QCOM_SYSMON || QCOM_SYSMON=n
 	select QCOM_MDT_LOADER
 	select QCOM_RPROC_COMMON
 	select QCOM_SCM
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 6e16450ce11f..02627ede8d4a 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYSTONE_REMOTEPROC)	+= keystone_remoteproc.o
 obj-$(CONFIG_QCOM_ADSP_PIL)		+= qcom_adsp_pil.o
 obj-$(CONFIG_QCOM_RPROC_COMMON)		+= qcom_common.o
 obj-$(CONFIG_QCOM_Q6V5_PIL)		+= qcom_q6v5_pil.o
+obj-$(CONFIG_QCOM_SYSMON)		+= qcom_sysmon.o
 obj-$(CONFIG_QCOM_WCNSS_PIL)		+= qcom_wcnss_pil.o
 qcom_wcnss_pil-y			+= qcom_wcnss.o
 qcom_wcnss_pil-y			+= qcom_wcnss_iris.o
diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c
index 373c167892d7..89a86ce07f99 100644
--- a/drivers/remoteproc/qcom_adsp_pil.c
+++ b/drivers/remoteproc/qcom_adsp_pil.c
@@ -38,7 +38,10 @@ struct adsp_data {
 	const char *firmware_name;
 	int pas_id;
 	bool has_aggre2_clk;
+
 	const char *ssr_name;
+	const char *sysmon_name;
+	int ssctl_id;
 };
 
 struct qcom_adsp {
@@ -75,6 +78,7 @@ struct qcom_adsp {
 	struct qcom_rproc_glink glink_subdev;
 	struct qcom_rproc_subdev smd_subdev;
 	struct qcom_rproc_ssr ssr_subdev;
+	struct qcom_sysmon *sysmon;
 };
 
 static int adsp_load(struct rproc *rproc, const struct firmware *fw)
@@ -82,7 +86,9 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 
 	return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
-			     adsp->mem_region, adsp->mem_phys, adsp->mem_size);
+			     adsp->mem_region, adsp->mem_phys, adsp->mem_size,
+			     &adsp->mem_reloc);
+
 }
 
 static int adsp_start(struct rproc *rproc)
@@ -177,6 +183,7 @@ static const struct rproc_ops adsp_ops = {
 	.start = adsp_start,
 	.stop = adsp_stop,
 	.da_to_va = adsp_da_to_va,
+	.parse_fw = qcom_register_dump_segments,
 	.load = adsp_load,
 };
 
@@ -201,9 +208,6 @@ static irqreturn_t adsp_fatal_interrupt(int irq, void *dev)
 
 	rproc_report_crash(adsp->rproc, RPROC_FATAL_ERROR);
 
-	if (!IS_ERR(msg))
-		msg[0] = '\0';
-
 	return IRQ_HANDLED;
 }
 
@@ -398,6 +402,9 @@ static int adsp_probe(struct platform_device *pdev)
 	qcom_add_glink_subdev(rproc, &adsp->glink_subdev);
 	qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
 	qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
+	adsp->sysmon = qcom_add_sysmon_subdev(rproc,
+					      desc->sysmon_name,
+					      desc->ssctl_id);
 
 	ret = rproc_add(rproc);
 	if (ret)
@@ -419,6 +426,7 @@ static int adsp_remove(struct platform_device *pdev)
 	rproc_del(adsp->rproc);
 
 	qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
+	qcom_remove_sysmon_subdev(adsp->sysmon);
 	qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
 	qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
 	rproc_free(adsp->rproc);
@@ -432,6 +440,8 @@ static const struct adsp_data adsp_resource_init = {
 		.pas_id = 1,
 		.has_aggre2_clk = false,
 		.ssr_name = "lpass",
+		.sysmon_name = "adsp",
+		.ssctl_id = 0x14,
 };
 
 static const struct adsp_data slpi_resource_init = {
@@ -440,6 +450,8 @@ static const struct adsp_data slpi_resource_init = {
 		.pas_id = 12,
 		.has_aggre2_clk = true,
 		.ssr_name = "dsps",
+		.sysmon_name = "slpi",
+		.ssctl_id = 0x16,
 };
 
 static const struct of_device_id adsp_of_match[] = {
diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c
index 00602499713f..9e47a147c131 100644
--- a/drivers/remoteproc/qcom_common.c
+++ b/drivers/remoteproc/qcom_common.c
@@ -22,6 +22,7 @@
 #include <linux/remoteproc.h>
 #include <linux/rpmsg/qcom_glink.h>
 #include <linux/rpmsg/qcom_smd.h>
+#include <linux/soc/qcom/mdt_loader.h>
 
 #include "remoteproc_internal.h"
 #include "qcom_common.h"
@@ -41,7 +42,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev)
 	return PTR_ERR_OR_ZERO(glink->edge);
 }
 
-static void glink_subdev_remove(struct rproc_subdev *subdev)
+static void glink_subdev_remove(struct rproc_subdev *subdev, bool crashed)
 {
 	struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
 
@@ -79,6 +80,49 @@ void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glin
 }
 EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev);
 
+/**
+ * qcom_register_dump_segments() - register segments for coredump
+ * @rproc:	remoteproc handle
+ * @fw:		firmware header
+ *
+ * Register all segments of the ELF in the remoteproc coredump segment list
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_register_dump_segments(struct rproc *rproc,
+				const struct firmware *fw)
+{
+	const struct elf32_phdr *phdrs;
+	const struct elf32_phdr *phdr;
+	const struct elf32_hdr *ehdr;
+	int ret;
+	int i;
+
+	ehdr = (struct elf32_hdr *)fw->data;
+	phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		phdr = &phdrs[i];
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+			continue;
+
+		if (!phdr->p_memsz)
+			continue;
+
+		ret = rproc_coredump_add_segment(rproc, phdr->p_paddr,
+						 phdr->p_memsz);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_register_dump_segments);
+
 static int smd_subdev_probe(struct rproc_subdev *subdev)
 {
 	struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
@@ -88,7 +132,7 @@ static int smd_subdev_probe(struct rproc_subdev *subdev)
 	return PTR_ERR_OR_ZERO(smd->edge);
 }
 
-static void smd_subdev_remove(struct rproc_subdev *subdev)
+static void smd_subdev_remove(struct rproc_subdev *subdev, bool crashed)
 {
 	struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
 
@@ -157,7 +201,7 @@ static int ssr_notify_start(struct rproc_subdev *subdev)
 	return  0;
 }
 
-static void ssr_notify_stop(struct rproc_subdev *subdev)
+static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed)
 {
 	struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
 
diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h
index 728be9834d8b..58de71e4781c 100644
--- a/drivers/remoteproc/qcom_common.h
+++ b/drivers/remoteproc/qcom_common.h
@@ -4,6 +4,9 @@
 
 #include <linux/remoteproc.h>
 #include "remoteproc_internal.h"
+#include <linux/soc/qcom/qmi.h>
+
+struct qcom_sysmon;
 
 struct qcom_rproc_glink {
 	struct rproc_subdev subdev;
@@ -30,6 +33,8 @@ struct qcom_rproc_ssr {
 void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink);
 void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink);
 
+int qcom_register_dump_segments(struct rproc *rproc, const struct firmware *fw);
+
 void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd);
 void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd);
 
@@ -37,4 +42,22 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
 			 const char *ssr_name);
 void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr);
 
+#if IS_ENABLED(CONFIG_QCOM_SYSMON)
+struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
+					   const char *name,
+					   int ssctl_instance);
+void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon);
+#else
+static inline struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
+							 const char *name,
+							 int ssctl_instance)
+{
+	return NULL;
+}
+
+static inline void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon)
+{
+}
+#endif
+
 #endif
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index b4e5e725848d..8e70a627e0bb 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -168,6 +168,7 @@ struct q6v5 {
 
 	struct qcom_rproc_subdev smd_subdev;
 	struct qcom_rproc_ssr ssr_subdev;
+	struct qcom_sysmon *sysmon;
 	bool need_mem_protection;
 	int mpss_perm;
 	int mba_perm;
@@ -939,9 +940,6 @@ static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
 
 	rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
 
-	if (!IS_ERR(msg))
-		msg[0] = '\0';
-
 	return IRQ_HANDLED;
 }
 
@@ -959,9 +957,6 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
 
 	rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
 
-	if (!IS_ERR(msg))
-		msg[0] = '\0';
-
 	return IRQ_HANDLED;
 }
 
@@ -1215,6 +1210,7 @@ static int q6v5_probe(struct platform_device *pdev)
 	qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS);
 	qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
 	qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
+	qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
 
 	ret = rproc_add(rproc);
 	if (ret)
@@ -1234,6 +1230,7 @@ static int q6v5_remove(struct platform_device *pdev)
 
 	rproc_del(qproc->rproc);
 
+	qcom_remove_sysmon_subdev(qproc->sysmon);
 	qcom_remove_smd_subdev(qproc->rproc, &qproc->smd_subdev);
 	qcom_remove_ssr_subdev(qproc->rproc, &qproc->ssr_subdev);
 	rproc_free(qproc->rproc);
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
new file mode 100644
index 000000000000..f085545d7da5
--- /dev/null
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -0,0 +1,579 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, Linaro Ltd.
+ */
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/notifier.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc/qcom_rproc.h>
+#include <linux/rpmsg.h>
+
+#include "qcom_common.h"
+
+static BLOCKING_NOTIFIER_HEAD(sysmon_notifiers);
+
+struct qcom_sysmon {
+	struct rproc_subdev subdev;
+	struct rproc *rproc;
+
+	struct list_head node;
+
+	const char *name;
+
+	int ssctl_version;
+	int ssctl_instance;
+
+	struct notifier_block nb;
+
+	struct device *dev;
+
+	struct rpmsg_endpoint *ept;
+	struct completion comp;
+	struct mutex lock;
+
+	bool ssr_ack;
+
+	struct qmi_handle qmi;
+	struct sockaddr_qrtr ssctl;
+};
+
+static DEFINE_MUTEX(sysmon_lock);
+static LIST_HEAD(sysmon_list);
+
+/**
+ * sysmon_send_event() - send notification of other remote's SSR event
+ * @sysmon:	sysmon context
+ * @name:	other remote's name
+ */
+static void sysmon_send_event(struct qcom_sysmon *sysmon, const char *name)
+{
+	char req[50];
+	int len;
+	int ret;
+
+	len = snprintf(req, sizeof(req), "ssr:%s:before_shutdown", name);
+	if (len >= sizeof(req))
+		return;
+
+	mutex_lock(&sysmon->lock);
+	reinit_completion(&sysmon->comp);
+	sysmon->ssr_ack = false;
+
+	ret = rpmsg_send(sysmon->ept, req, len);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "failed to send sysmon event\n");
+		goto out_unlock;
+	}
+
+	ret = wait_for_completion_timeout(&sysmon->comp,
+					  msecs_to_jiffies(5000));
+	if (!ret) {
+		dev_err(sysmon->dev, "timeout waiting for sysmon ack\n");
+		goto out_unlock;
+	}
+
+	if (!sysmon->ssr_ack)
+		dev_err(sysmon->dev, "unexpected response to sysmon event\n");
+
+out_unlock:
+	mutex_unlock(&sysmon->lock);
+}
+
+/**
+ * sysmon_request_shutdown() - request graceful shutdown of remote
+ * @sysmon:	sysmon context
+ */
+static void sysmon_request_shutdown(struct qcom_sysmon *sysmon)
+{
+	char *req = "ssr:shutdown";
+	int ret;
+
+	mutex_lock(&sysmon->lock);
+	reinit_completion(&sysmon->comp);
+	sysmon->ssr_ack = false;
+
+	ret = rpmsg_send(sysmon->ept, req, strlen(req) + 1);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "send sysmon shutdown request failed\n");
+		goto out_unlock;
+	}
+
+	ret = wait_for_completion_timeout(&sysmon->comp,
+					  msecs_to_jiffies(5000));
+	if (!ret) {
+		dev_err(sysmon->dev, "timeout waiting for sysmon ack\n");
+		goto out_unlock;
+	}
+
+	if (!sysmon->ssr_ack)
+		dev_err(sysmon->dev,
+			"unexpected response to sysmon shutdown request\n");
+
+out_unlock:
+	mutex_unlock(&sysmon->lock);
+}
+
+static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count,
+			   void *priv, u32 addr)
+{
+	struct qcom_sysmon *sysmon = priv;
+	const char *ssr_ack = "ssr:ack";
+	const int ssr_ack_len = strlen(ssr_ack) + 1;
+
+	if (!sysmon)
+		return -EINVAL;
+
+	if (count >= ssr_ack_len && !memcmp(data, ssr_ack, ssr_ack_len))
+		sysmon->ssr_ack = true;
+
+	complete(&sysmon->comp);
+
+	return 0;
+}
+
+#define SSCTL_SHUTDOWN_REQ		0x21
+#define SSCTL_SUBSYS_EVENT_REQ		0x23
+
+#define SSCTL_MAX_MSG_LEN		7
+
+#define SSCTL_SUBSYS_NAME_LENGTH	15
+
+enum {
+	SSCTL_SSR_EVENT_BEFORE_POWERUP,
+	SSCTL_SSR_EVENT_AFTER_POWERUP,
+	SSCTL_SSR_EVENT_BEFORE_SHUTDOWN,
+	SSCTL_SSR_EVENT_AFTER_SHUTDOWN,
+};
+
+enum {
+	SSCTL_SSR_EVENT_FORCED,
+	SSCTL_SSR_EVENT_GRACEFUL,
+};
+
+struct ssctl_shutdown_resp {
+	struct qmi_response_type_v01 resp;
+};
+
+static struct qmi_elem_info ssctl_shutdown_resp_ei[] = {
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct qmi_response_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x02,
+		.offset		= offsetof(struct ssctl_shutdown_resp, resp),
+		.ei_array	= qmi_response_type_v01_ei,
+	},
+	{}
+};
+
+struct ssctl_subsys_event_req {
+	u8 subsys_name_len;
+	char subsys_name[SSCTL_SUBSYS_NAME_LENGTH];
+	u32 event;
+	u8 evt_driven_valid;
+	u32 evt_driven;
+};
+
+static struct qmi_elem_info ssctl_subsys_event_req_ei[] = {
+	{
+		.data_type	= QMI_DATA_LEN,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x01,
+		.offset		= offsetof(struct ssctl_subsys_event_req,
+					   subsys_name_len),
+		.ei_array	= NULL,
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= SSCTL_SUBSYS_NAME_LENGTH,
+		.elem_size	= sizeof(char),
+		.array_type	= VAR_LEN_ARRAY,
+		.tlv_type	= 0x01,
+		.offset		= offsetof(struct ssctl_subsys_event_req,
+					   subsys_name),
+		.ei_array	= NULL,
+	},
+	{
+		.data_type	= QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint32_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x02,
+		.offset		= offsetof(struct ssctl_subsys_event_req,
+					   event),
+		.ei_array	= NULL,
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x10,
+		.offset		= offsetof(struct ssctl_subsys_event_req,
+					   evt_driven_valid),
+		.ei_array	= NULL,
+	},
+	{
+		.data_type	= QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint32_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x10,
+		.offset		= offsetof(struct ssctl_subsys_event_req,
+					   evt_driven),
+		.ei_array	= NULL,
+	},
+	{}
+};
+
+struct ssctl_subsys_event_resp {
+	struct qmi_response_type_v01 resp;
+};
+
+static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = {
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct qmi_response_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x02,
+		.offset		= offsetof(struct ssctl_subsys_event_resp,
+					   resp),
+		.ei_array	= qmi_response_type_v01_ei,
+	},
+	{}
+};
+
+/**
+ * ssctl_request_shutdown() - request shutdown via SSCTL QMI service
+ * @sysmon:	sysmon context
+ */
+static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
+{
+	struct ssctl_shutdown_resp resp;
+	struct qmi_txn txn;
+	int ret;
+
+	ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "failed to allocate QMI txn\n");
+		return;
+	}
+
+	ret = qmi_send_request(&sysmon->qmi, &sysmon->ssctl, &txn,
+			       SSCTL_SHUTDOWN_REQ, 0, NULL, NULL);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "failed to send shutdown request\n");
+		qmi_txn_cancel(&txn);
+		return;
+	}
+
+	ret = qmi_txn_wait(&txn, 5 * HZ);
+	if (ret < 0)
+		dev_err(sysmon->dev, "failed receiving QMI response\n");
+	else if (resp.resp.result)
+		dev_err(sysmon->dev, "shutdown request failed\n");
+	else
+		dev_dbg(sysmon->dev, "shutdown request completed\n");
+}
+
+/**
+ * ssctl_send_event() - send notification of other remote's SSR event
+ * @sysmon:	sysmon context
+ * @name:	other remote's name
+ */
+static void ssctl_send_event(struct qcom_sysmon *sysmon, const char *name)
+{
+	struct ssctl_subsys_event_resp resp;
+	struct ssctl_subsys_event_req req;
+	struct qmi_txn txn;
+	int ret;
+
+	memset(&resp, 0, sizeof(resp));
+	ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_subsys_event_resp_ei, &resp);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "failed to allocate QMI txn\n");
+		return;
+	}
+
+	memset(&req, 0, sizeof(req));
+	strlcpy(req.subsys_name, name, sizeof(req.subsys_name));
+	req.subsys_name_len = strlen(req.subsys_name);
+	req.event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN;
+	req.evt_driven_valid = true;
+	req.evt_driven = SSCTL_SSR_EVENT_FORCED;
+
+	ret = qmi_send_request(&sysmon->qmi, &sysmon->ssctl, &txn,
+			       SSCTL_SUBSYS_EVENT_REQ, 40,
+			       ssctl_subsys_event_req_ei, &req);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "failed to send shutdown request\n");
+		qmi_txn_cancel(&txn);
+		return;
+	}
+
+	ret = qmi_txn_wait(&txn, 5 * HZ);
+	if (ret < 0)
+		dev_err(sysmon->dev, "failed receiving QMI response\n");
+	else if (resp.resp.result)
+		dev_err(sysmon->dev, "ssr event send failed\n");
+	else
+		dev_dbg(sysmon->dev, "ssr event send completed\n");
+}
+
+/**
+ * ssctl_new_server() - QMI callback indicating a new service
+ * @qmi:	QMI handle
+ * @svc:	service information
+ *
+ * Return: 0 if we're interested in this service, -EINVAL otherwise.
+ */
+static int ssctl_new_server(struct qmi_handle *qmi, struct qmi_service *svc)
+{
+	struct qcom_sysmon *sysmon = container_of(qmi, struct qcom_sysmon, qmi);
+
+	switch (svc->version) {
+	case 1:
+		if (svc->instance != 0)
+			return -EINVAL;
+		if (strcmp(sysmon->name, "modem"))
+			return -EINVAL;
+		break;
+	case 2:
+		if (svc->instance != sysmon->ssctl_instance)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	sysmon->ssctl_version = svc->version;
+
+	sysmon->ssctl.sq_family = AF_QIPCRTR;
+	sysmon->ssctl.sq_node = svc->node;
+	sysmon->ssctl.sq_port = svc->port;
+
+	svc->priv = sysmon;
+
+	return 0;
+}
+
+/**
+ * ssctl_del_server() - QMI callback indicating that @svc is removed
+ * @qmi:	QMI handle
+ * @svc:	service information
+ */
+static void ssctl_del_server(struct qmi_handle *qmi, struct qmi_service *svc)
+{
+	struct qcom_sysmon *sysmon = svc->priv;
+
+	sysmon->ssctl_version = 0;
+}
+
+static const struct qmi_ops ssctl_ops = {
+	.new_server = ssctl_new_server,
+	.del_server = ssctl_del_server,
+};
+
+static int sysmon_start(struct rproc_subdev *subdev)
+{
+	return 0;
+}
+
+static void sysmon_stop(struct rproc_subdev *subdev, bool crashed)
+{
+	struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, subdev);
+
+	blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)sysmon->name);
+
+	/* Don't request graceful shutdown if we've crashed */
+	if (crashed)
+		return;
+
+	if (sysmon->ssctl_version)
+		ssctl_request_shutdown(sysmon);
+	else if (sysmon->ept)
+		sysmon_request_shutdown(sysmon);
+}
+
+/**
+ * sysmon_notify() - notify sysmon target of another's SSR
+ * @nb:		notifier_block associated with sysmon instance
+ * @event:	unused
+ * @data:	SSR identifier of the remote that is going down
+ */
+static int sysmon_notify(struct notifier_block *nb, unsigned long event,
+			 void *data)
+{
+	struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb);
+	struct rproc *rproc = sysmon->rproc;
+	const char *ssr_name = data;
+
+	/* Skip non-running rprocs and the originating instance */
+	if (rproc->state != RPROC_RUNNING || !strcmp(data, sysmon->name)) {
+		dev_dbg(sysmon->dev, "not notifying %s\n", sysmon->name);
+		return NOTIFY_DONE;
+	}
+
+	/* Only SSCTL version 2 supports SSR events */
+	if (sysmon->ssctl_version == 2)
+		ssctl_send_event(sysmon, ssr_name);
+	else if (sysmon->ept)
+		sysmon_send_event(sysmon, ssr_name);
+
+	return NOTIFY_DONE;
+}
+
+/**
+ * qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc
+ * @rproc:	rproc context to associate the subdev with
+ * @name:	name of this subdev, to use in SSR
+ * @ssctl_instance: instance id of the ssctl QMI service
+ *
+ * Return: A new qcom_sysmon object, or NULL on failure
+ */
+struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
+					   const char *name,
+					   int ssctl_instance)
+{
+	struct qcom_sysmon *sysmon;
+	int ret;
+
+	sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL);
+	if (!sysmon)
+		return NULL;
+
+	sysmon->dev = rproc->dev.parent;
+	sysmon->rproc = rproc;
+
+	sysmon->name = name;
+	sysmon->ssctl_instance = ssctl_instance;
+
+	init_completion(&sysmon->comp);
+	mutex_init(&sysmon->lock);
+
+	ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, NULL);
+	if (ret < 0) {
+		dev_err(sysmon->dev, "failed to initialize qmi handle\n");
+		kfree(sysmon);
+		return NULL;
+	}
+
+	qmi_add_lookup(&sysmon->qmi, 43, 0, 0);
+
+	rproc_add_subdev(rproc, &sysmon->subdev, sysmon_start, sysmon_stop);
+
+	sysmon->nb.notifier_call = sysmon_notify;
+	blocking_notifier_chain_register(&sysmon_notifiers, &sysmon->nb);
+
+	mutex_lock(&sysmon_lock);
+	list_add(&sysmon->node, &sysmon_list);
+	mutex_unlock(&sysmon_lock);
+
+	return sysmon;
+}
+EXPORT_SYMBOL_GPL(qcom_add_sysmon_subdev);
+
+/**
+ * qcom_remove_sysmon_subdev() - release a qcom_sysmon
+ * @sysmon:	sysmon context, as retrieved by qcom_add_sysmon_subdev()
+ */
+void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon)
+{
+	if (!sysmon)
+		return;
+
+	mutex_lock(&sysmon_lock);
+	list_del(&sysmon->node);
+	mutex_unlock(&sysmon_lock);
+
+	blocking_notifier_chain_unregister(&sysmon_notifiers, &sysmon->nb);
+
+	rproc_remove_subdev(sysmon->rproc, &sysmon->subdev);
+
+	qmi_handle_release(&sysmon->qmi);
+
+	kfree(sysmon);
+}
+EXPORT_SYMBOL_GPL(qcom_remove_sysmon_subdev);
+
+/**
+ * sysmon_probe() - probe sys_mon channel
+ * @rpdev:	rpmsg device handle
+ *
+ * Find the sysmon context associated with the ancestor remoteproc and assign
+ * this rpmsg device with said sysmon context.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int sysmon_probe(struct rpmsg_device *rpdev)
+{
+	struct qcom_sysmon *sysmon;
+	struct rproc *rproc;
+
+	rproc = rproc_get_by_child(&rpdev->dev);
+	if (!rproc) {
+		dev_err(&rpdev->dev, "sysmon device not child of rproc\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&sysmon_lock);
+	list_for_each_entry(sysmon, &sysmon_list, node) {
+		if (sysmon->rproc == rproc)
+			goto found;
+	}
+	mutex_unlock(&sysmon_lock);
+
+	dev_err(&rpdev->dev, "no sysmon associated with parent rproc\n");
+
+	return -EINVAL;
+
+found:
+	mutex_unlock(&sysmon_lock);
+
+	rpdev->ept->priv = sysmon;
+	sysmon->ept = rpdev->ept;
+
+	return 0;
+}
+
+/**
+ * sysmon_remove() - sys_mon channel remove handler
+ * @rpdev:	rpmsg device handle
+ *
+ * Disassociate the rpmsg device with the sysmon instance.
+ */
+static void sysmon_remove(struct rpmsg_device *rpdev)
+{
+	struct qcom_sysmon *sysmon = rpdev->ept->priv;
+
+	sysmon->ept = NULL;
+}
+
+static const struct rpmsg_device_id sysmon_match[] = {
+	{ "sys_mon" },
+	{}
+};
+
+static struct rpmsg_driver sysmon_driver = {
+	.probe = sysmon_probe,
+	.remove = sysmon_remove,
+	.callback = sysmon_callback,
+	.id_table = sysmon_match,
+	.drv = {
+		.name = "qcom_sysmon",
+	},
+};
+
+module_rpmsg_driver(sysmon_driver);
+
+MODULE_DESCRIPTION("Qualcomm sysmon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 3f0609236a76..b0e07e9f42d5 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -40,6 +40,7 @@
 #define WCNSS_CRASH_REASON_SMEM		422
 #define WCNSS_FIRMWARE_NAME		"wcnss.mdt"
 #define WCNSS_PAS_ID			6
+#define WCNSS_SSCTL_ID			0x13
 
 #define WCNSS_SPARE_NVBIN_DLND		BIT(25)
 
@@ -98,6 +99,7 @@ struct qcom_wcnss {
 	size_t mem_size;
 
 	struct qcom_rproc_subdev smd_subdev;
+	struct qcom_sysmon *sysmon;
 };
 
 static const struct wcnss_data riva_data = {
@@ -153,7 +155,8 @@ static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
 	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
 
 	return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
-			     wcnss->mem_region, wcnss->mem_phys, wcnss->mem_size);
+			     wcnss->mem_region, wcnss->mem_phys,
+			     wcnss->mem_size, &wcnss->mem_reloc);
 }
 
 static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
@@ -308,6 +311,7 @@ static const struct rproc_ops wcnss_ops = {
 	.start = wcnss_start,
 	.stop = wcnss_stop,
 	.da_to_va = wcnss_da_to_va,
+	.parse_fw = qcom_register_dump_segments,
 	.load = wcnss_load,
 };
 
@@ -332,9 +336,6 @@ static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)
 
 	rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);
 
-	if (!IS_ERR(msg))
-		msg[0] = '\0';
-
 	return IRQ_HANDLED;
 }
 
@@ -551,6 +552,7 @@ static int wcnss_probe(struct platform_device *pdev)
 	}
 
 	qcom_add_smd_subdev(rproc, &wcnss->smd_subdev);
+	wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID);
 
 	ret = rproc_add(rproc);
 	if (ret)
@@ -573,6 +575,7 @@ static int wcnss_remove(struct platform_device *pdev)
 	qcom_smem_state_put(wcnss->state);
 	rproc_del(wcnss->rproc);
 
+	qcom_remove_sysmon_subdev(wcnss->sysmon);
 	qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev);
 	rproc_free(wcnss->rproc);
 
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 4170dfbd93bd..6d9c5832ce47 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -33,6 +33,7 @@
 #include <linux/firmware.h>
 #include <linux/string.h>
 #include <linux/debugfs.h>
+#include <linux/devcoredump.h>
 #include <linux/remoteproc.h>
 #include <linux/iommu.h>
 #include <linux/idr.h>
@@ -307,7 +308,7 @@ static int rproc_vdev_do_probe(struct rproc_subdev *subdev)
 	return rproc_add_virtio_dev(rvdev, rvdev->id);
 }
 
-static void rproc_vdev_do_remove(struct rproc_subdev *subdev)
+static void rproc_vdev_do_remove(struct rproc_subdev *subdev, bool crashed)
 {
 	struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
 
@@ -788,17 +789,31 @@ static int rproc_probe_subdevices(struct rproc *rproc)
 
 unroll_registration:
 	list_for_each_entry_continue_reverse(subdev, &rproc->subdevs, node)
-		subdev->remove(subdev);
+		subdev->remove(subdev, true);
 
 	return ret;
 }
 
-static void rproc_remove_subdevices(struct rproc *rproc)
+static void rproc_remove_subdevices(struct rproc *rproc, bool crashed)
 {
 	struct rproc_subdev *subdev;
 
 	list_for_each_entry_reverse(subdev, &rproc->subdevs, node)
-		subdev->remove(subdev);
+		subdev->remove(subdev, crashed);
+}
+
+/**
+ * rproc_coredump_cleanup() - clean up dump_segments list
+ * @rproc: the remote processor handle
+ */
+static void rproc_coredump_cleanup(struct rproc *rproc)
+{
+	struct rproc_dump_segment *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) {
+		list_del(&entry->node);
+		kfree(entry);
+	}
 }
 
 /**
@@ -848,6 +863,8 @@ static void rproc_resource_cleanup(struct rproc *rproc)
 	/* clean up remote vdev entries */
 	list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
 		kref_put(&rvdev->refcount, rproc_vdev_release);
+
+	rproc_coredump_cleanup(rproc);
 }
 
 static int rproc_start(struct rproc *rproc, const struct firmware *fw)
@@ -927,8 +944,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
 
 	rproc->bootaddr = rproc_get_boot_addr(rproc, fw);
 
-	/* load resource table */
-	ret = rproc_load_rsc_table(rproc, fw);
+	/* Load resource table, core dump segment list etc from the firmware */
+	ret = rproc_parse_fw(rproc, fw);
 	if (ret)
 		goto disable_iommu;
 
@@ -992,13 +1009,13 @@ static int rproc_trigger_auto_boot(struct rproc *rproc)
 	return ret;
 }
 
-static int rproc_stop(struct rproc *rproc)
+static int rproc_stop(struct rproc *rproc, bool crashed)
 {
 	struct device *dev = &rproc->dev;
 	int ret;
 
 	/* remove any subdevices for the remote processor */
-	rproc_remove_subdevices(rproc);
+	rproc_remove_subdevices(rproc, crashed);
 
 	/* the installed resource table is no longer accessible */
 	rproc->table_ptr = rproc->cached_table;
@@ -1017,6 +1034,113 @@ static int rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
+/**
+ * rproc_coredump_add_segment() - add segment of device memory to coredump
+ * @rproc:	handle of a remote processor
+ * @da:		device address
+ * @size:	size of segment
+ *
+ * Add device memory to the list of segments to be included in a coredump for
+ * the remoteproc.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size)
+{
+	struct rproc_dump_segment *segment;
+
+	segment = kzalloc(sizeof(*segment), GFP_KERNEL);
+	if (!segment)
+		return -ENOMEM;
+
+	segment->da = da;
+	segment->size = size;
+
+	list_add_tail(&segment->node, &rproc->dump_segments);
+
+	return 0;
+}
+EXPORT_SYMBOL(rproc_coredump_add_segment);
+
+/**
+ * rproc_coredump() - perform coredump
+ * @rproc:	rproc handle
+ *
+ * This function will generate an ELF header for the registered segments
+ * and create a devcoredump device associated with rproc.
+ */
+static void rproc_coredump(struct rproc *rproc)
+{
+	struct rproc_dump_segment *segment;
+	struct elf32_phdr *phdr;
+	struct elf32_hdr *ehdr;
+	size_t data_size;
+	size_t offset;
+	void *data;
+	void *ptr;
+	int phnum = 0;
+
+	if (list_empty(&rproc->dump_segments))
+		return;
+
+	data_size = sizeof(*ehdr);
+	list_for_each_entry(segment, &rproc->dump_segments, node) {
+		data_size += sizeof(*phdr) + segment->size;
+
+		phnum++;
+	}
+
+	data = vmalloc(data_size);
+	if (!data)
+		return;
+
+	ehdr = data;
+
+	memset(ehdr, 0, sizeof(*ehdr));
+	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
+	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	ehdr->e_type = ET_CORE;
+	ehdr->e_machine = EM_NONE;
+	ehdr->e_version = EV_CURRENT;
+	ehdr->e_entry = rproc->bootaddr;
+	ehdr->e_phoff = sizeof(*ehdr);
+	ehdr->e_ehsize = sizeof(*ehdr);
+	ehdr->e_phentsize = sizeof(*phdr);
+	ehdr->e_phnum = phnum;
+
+	phdr = data + ehdr->e_phoff;
+	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
+	list_for_each_entry(segment, &rproc->dump_segments, node) {
+		memset(phdr, 0, sizeof(*phdr));
+		phdr->p_type = PT_LOAD;
+		phdr->p_offset = offset;
+		phdr->p_vaddr = segment->da;
+		phdr->p_paddr = segment->da;
+		phdr->p_filesz = segment->size;
+		phdr->p_memsz = segment->size;
+		phdr->p_flags = PF_R | PF_W | PF_X;
+		phdr->p_align = 0;
+
+		ptr = rproc_da_to_va(rproc, segment->da, segment->size);
+		if (!ptr) {
+			dev_err(&rproc->dev,
+				"invalid coredump segment (%pad, %zu)\n",
+				&segment->da, segment->size);
+			memset(data + offset, 0xff, segment->size);
+		} else {
+			memcpy(data + offset, ptr, segment->size);
+		}
+
+		offset += phdr->p_filesz;
+		phdr++;
+	}
+
+	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
+}
+
 /**
  * rproc_trigger_recovery() - recover a remoteproc
  * @rproc: the remote processor
@@ -1039,10 +1163,13 @@ int rproc_trigger_recovery(struct rproc *rproc)
 	if (ret)
 		return ret;
 
-	ret = rproc_stop(rproc);
+	ret = rproc_stop(rproc, false);
 	if (ret)
 		goto unlock_mutex;
 
+	/* generate coredump */
+	rproc_coredump(rproc);
+
 	/* load firmware */
 	ret = request_firmware(&firmware_p, rproc->firmware, dev);
 	if (ret < 0) {
@@ -1189,7 +1316,7 @@ void rproc_shutdown(struct rproc *rproc)
 	if (!atomic_dec_and_test(&rproc->power))
 		goto out;
 
-	ret = rproc_stop(rproc);
+	ret = rproc_stop(rproc, true);
 	if (ret) {
 		atomic_inc(&rproc->power);
 		goto out;
@@ -1428,7 +1555,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 	/* Default to ELF loader if no load function is specified */
 	if (!rproc->ops->load) {
 		rproc->ops->load = rproc_elf_load_segments;
-		rproc->ops->load_rsc_table = rproc_elf_load_rsc_table;
+		rproc->ops->parse_fw = rproc_elf_load_rsc_table;
 		rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
 		rproc->ops->sanity_check = rproc_elf_sanity_check;
 		rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
@@ -1443,6 +1570,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 	INIT_LIST_HEAD(&rproc->traces);
 	INIT_LIST_HEAD(&rproc->rvdevs);
 	INIT_LIST_HEAD(&rproc->subdevs);
+	INIT_LIST_HEAD(&rproc->dump_segments);
 
 	INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
 
@@ -1535,7 +1663,7 @@ EXPORT_SYMBOL(rproc_del);
 void rproc_add_subdev(struct rproc *rproc,
 		      struct rproc_subdev *subdev,
 		      int (*probe)(struct rproc_subdev *subdev),
-		      void (*remove)(struct rproc_subdev *subdev))
+		      void (*remove)(struct rproc_subdev *subdev, bool crashed))
 {
 	subdev->probe = probe;
 	subdev->remove = remove;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 55a2950c5cb7..7570beb035b5 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -88,11 +88,10 @@ int rproc_load_segments(struct rproc *rproc, const struct firmware *fw)
 	return -EINVAL;
 }
 
-static inline int rproc_load_rsc_table(struct rproc *rproc,
-				       const struct firmware *fw)
+static inline int rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
 {
-	if (rproc->ops->load_rsc_table)
-		return rproc->ops->load_rsc_table(rproc, fw);
+	if (rproc->ops->parse_fw)
+		return rproc->ops->parse_fw(rproc, fw);
 
 	return 0;
 }
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c
index 93cbee1ae8ef..5242e0679df7 100644
--- a/drivers/reset/reset-meson.c
+++ b/drivers/reset/reset-meson.c
@@ -124,29 +124,21 @@ static int meson_reset_deassert(struct reset_controller_dev *rcdev,
 	return meson_reset_level(rcdev, id, false);
 }
 
-static const struct reset_control_ops meson_reset_meson8_ops = {
-	.reset		= meson_reset_reset,
-};
-
-static const struct reset_control_ops meson_reset_gx_ops = {
+static const struct reset_control_ops meson_reset_ops = {
 	.reset		= meson_reset_reset,
 	.assert		= meson_reset_assert,
 	.deassert	= meson_reset_deassert,
 };
 
 static const struct of_device_id meson_reset_dt_ids[] = {
-	 { .compatible = "amlogic,meson8b-reset",
-	   .data = &meson_reset_meson8_ops, },
-	 { .compatible = "amlogic,meson-gxbb-reset",
-	   .data = &meson_reset_gx_ops, },
-	 { .compatible = "amlogic,meson-axg-reset",
-	   .data = &meson_reset_gx_ops, },
+	 { .compatible = "amlogic,meson8b-reset" },
+	 { .compatible = "amlogic,meson-gxbb-reset" },
+	 { .compatible = "amlogic,meson-axg-reset" },
 	 { /* sentinel */ },
 };
 
 static int meson_reset_probe(struct platform_device *pdev)
 {
-	const struct reset_control_ops *ops;
 	struct meson_reset *data;
 	struct resource *res;
 
@@ -154,10 +146,6 @@ static int meson_reset_probe(struct platform_device *pdev)
 	if (!data)
 		return -ENOMEM;
 
-	ops = of_device_get_match_data(&pdev->dev);
-	if (!ops)
-		return -EINVAL;
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	data->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(data->reg_base))
@@ -169,7 +157,7 @@ static int meson_reset_probe(struct platform_device *pdev)
 
 	data->rcdev.owner = THIS_MODULE;
 	data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG;
-	data->rcdev.ops = ops;
+	data->rcdev.ops = &meson_reset_ops;
 	data->rcdev.of_node = pdev->dev.of_node;
 
 	return devm_reset_controller_register(&pdev->dev, &data->rcdev);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8ab5f0a5d323..f6d7e490e714 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1512,7 +1512,7 @@ config RTC_DRV_STARFIRE
 
 config RTC_DRV_TX4939
 	tristate "TX4939 SoC"
-	depends on SOC_TX4939
+	depends on SOC_TX4939 || COMPILE_TEST
 	help
 	  Driver for the internal RTC (Realtime Clock) module found on
 	  Toshiba TX4939 SoC.
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 722d683e0b0f..999ed039da0d 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -453,8 +453,6 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
 
 	rtc_proc_add_device(rtc);
 
-	rtc_nvmem_register(rtc);
-
 	rtc->registered = true;
 	dev_info(rtc->dev.parent, "registered as %s\n",
 		 dev_name(&rtc->dev));
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 672b192f8153..7e253be19ba7 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -17,6 +17,9 @@
 #include <linux/log2.h>
 #include <linux/workqueue.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/rtc.h>
+
 static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
 static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
 
@@ -53,6 +56,8 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
 
 	err = __rtc_read_time(rtc, tm);
 	mutex_unlock(&rtc->ops_lock);
+
+	trace_rtc_read_time(rtc_tm_to_time64(tm), err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_read_time);
@@ -87,6 +92,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
 	mutex_unlock(&rtc->ops_lock);
 	/* A timer might have just expired */
 	schedule_work(&rtc->irqwork);
+
+	trace_rtc_set_time(rtc_tm_to_time64(tm), err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_set_time);
@@ -119,6 +126,8 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
 	}
 
 	mutex_unlock(&rtc->ops_lock);
+
+	trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
 	return err;
 }
 
@@ -316,6 +325,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 	}
 	mutex_unlock(&rtc->ops_lock);
 
+	trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
@@ -352,6 +362,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 	else
 		err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
 
+	trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err);
 	return err;
 }
 
@@ -406,6 +417,7 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 
 		rtc->aie_timer.enabled = 1;
 		timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
+		trace_rtc_timer_enqueue(&rtc->aie_timer);
 	}
 	mutex_unlock(&rtc->ops_lock);
 	return err;
@@ -435,6 +447,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
 		err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
 
 	mutex_unlock(&rtc->ops_lock);
+
+	trace_rtc_alarm_irq_enable(enabled, err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
@@ -709,6 +723,8 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
 		rtc->pie_enabled = enabled;
 	}
 	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+	trace_rtc_irq_set_state(enabled, err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_irq_set_state);
@@ -745,6 +761,8 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
 		}
 	}
 	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+	trace_rtc_irq_set_freq(freq, err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
@@ -779,6 +797,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 	}
 
 	timerqueue_add(&rtc->timerqueue, &timer->node);
+	trace_rtc_timer_enqueue(timer);
 	if (!next || ktime_before(timer->node.expires, next->expires)) {
 		struct rtc_wkalrm alarm;
 		int err;
@@ -790,6 +809,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 			schedule_work(&rtc->irqwork);
 		} else if (err) {
 			timerqueue_del(&rtc->timerqueue, &timer->node);
+			trace_rtc_timer_dequeue(timer);
 			timer->enabled = 0;
 			return err;
 		}
@@ -803,6 +823,7 @@ static void rtc_alarm_disable(struct rtc_device *rtc)
 		return;
 
 	rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
+	trace_rtc_alarm_irq_enable(0, 0);
 }
 
 /**
@@ -821,6 +842,7 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
 {
 	struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
 	timerqueue_del(&rtc->timerqueue, &timer->node);
+	trace_rtc_timer_dequeue(timer);
 	timer->enabled = 0;
 	if (next == &timer->node) {
 		struct rtc_wkalrm alarm;
@@ -871,16 +893,19 @@ void rtc_timer_do_work(struct work_struct *work)
 		/* expire timer */
 		timer = container_of(next, struct rtc_timer, node);
 		timerqueue_del(&rtc->timerqueue, &timer->node);
+		trace_rtc_timer_dequeue(timer);
 		timer->enabled = 0;
 		if (timer->task.func)
 			timer->task.func(timer->task.private_data);
 
+		trace_rtc_timer_fired(timer);
 		/* Re-add/fwd periodic timers */
 		if (ktime_to_ns(timer->period)) {
 			timer->node.expires = ktime_add(timer->node.expires,
 							timer->period);
 			timer->enabled = 1;
 			timerqueue_add(&rtc->timerqueue, &timer->node);
+			trace_rtc_timer_enqueue(timer);
 		}
 	}
 
@@ -902,6 +927,7 @@ void rtc_timer_do_work(struct work_struct *work)
 
 			timer = container_of(next, struct rtc_timer, node);
 			timerqueue_del(&rtc->timerqueue, &timer->node);
+			trace_rtc_timer_dequeue(timer);
 			timer->enabled = 0;
 			dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
 			goto again;
@@ -992,6 +1018,8 @@ int rtc_read_offset(struct rtc_device *rtc, long *offset)
 	mutex_lock(&rtc->ops_lock);
 	ret = rtc->ops->read_offset(rtc->dev.parent, offset);
 	mutex_unlock(&rtc->ops_lock);
+
+	trace_rtc_read_offset(*offset, ret);
 	return ret;
 }
 
@@ -1025,5 +1053,7 @@ int rtc_set_offset(struct rtc_device *rtc, long offset)
 	mutex_lock(&rtc->ops_lock);
 	ret = rtc->ops->set_offset(rtc->dev.parent, offset);
 	mutex_unlock(&rtc->ops_lock);
+
+	trace_rtc_set_offset(offset, ret);
 	return ret;
 }
diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c
index 8567b4ed9ac6..3a02357eb783 100644
--- a/drivers/rtc/nvmem.c
+++ b/drivers/rtc/nvmem.c
@@ -14,8 +14,6 @@
 #include <linux/rtc.h>
 #include <linux/sysfs.h>
 
-#include "rtc-core.h"
-
 /*
  * Deprecated ABI compatibility, this should be removed at some point
  */
@@ -46,7 +44,7 @@ rtc_nvram_write(struct file *filp, struct kobject *kobj,
 	return nvmem_device_write(rtc->nvmem, off, count, buf);
 }
 
-static int rtc_nvram_register(struct rtc_device *rtc)
+static int rtc_nvram_register(struct rtc_device *rtc, size_t size)
 {
 	int err;
 
@@ -64,7 +62,7 @@ static int rtc_nvram_register(struct rtc_device *rtc)
 
 	rtc->nvram->read = rtc_nvram_read;
 	rtc->nvram->write = rtc_nvram_write;
-	rtc->nvram->size = rtc->nvmem_config->size;
+	rtc->nvram->size = size;
 
 	err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
 				    rtc->nvram);
@@ -84,21 +82,28 @@ static void rtc_nvram_unregister(struct rtc_device *rtc)
 /*
  * New ABI, uses nvmem
  */
-void rtc_nvmem_register(struct rtc_device *rtc)
+int rtc_nvmem_register(struct rtc_device *rtc,
+		       struct nvmem_config *nvmem_config)
 {
-	if (!rtc->nvmem_config)
-		return;
+	if (!IS_ERR_OR_NULL(rtc->nvmem))
+		return -EBUSY;
+
+	if (!nvmem_config)
+		return -ENODEV;
 
-	rtc->nvmem_config->dev = &rtc->dev;
-	rtc->nvmem_config->owner = rtc->owner;
-	rtc->nvmem = nvmem_register(rtc->nvmem_config);
+	nvmem_config->dev = &rtc->dev;
+	nvmem_config->owner = rtc->owner;
+	rtc->nvmem = nvmem_register(nvmem_config);
 	if (IS_ERR_OR_NULL(rtc->nvmem))
-		return;
+		return PTR_ERR(rtc->nvmem);
 
 	/* Register the old ABI */
 	if (rtc->nvram_old_abi)
-		rtc_nvram_register(rtc);
+		rtc_nvram_register(rtc, nvmem_config->size);
+
+	return 0;
 }
+EXPORT_SYMBOL_GPL(rtc_nvmem_register);
 
 void rtc_nvmem_unregister(struct rtc_device *rtc)
 {
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 9dca53df3584..b8ec6009171a 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -541,11 +541,10 @@ static const struct rtc_class_ops cmos_rtc_ops = {
 
 #define NVRAM_OFFSET	(RTC_REG_D + 1)
 
-static ssize_t
-cmos_nvram_read(struct file *filp, struct kobject *kobj,
-		struct bin_attribute *attr,
-		char *buf, loff_t off, size_t count)
+static int cmos_nvram_read(void *priv, unsigned int off, void *val,
+			   size_t count)
 {
+	unsigned char *buf = val;
 	int	retval;
 
 	off += NVRAM_OFFSET;
@@ -563,16 +562,13 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
 	return retval;
 }
 
-static ssize_t
-cmos_nvram_write(struct file *filp, struct kobject *kobj,
-		struct bin_attribute *attr,
-		char *buf, loff_t off, size_t count)
+static int cmos_nvram_write(void *priv, unsigned int off, void *val,
+			    size_t count)
 {
-	struct cmos_rtc	*cmos;
+	struct cmos_rtc	*cmos = priv;
+	unsigned char	*buf = val;
 	int		retval;
 
-	cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
-
 	/* NOTE:  on at least PCs and Ataris, the boot firmware uses a
 	 * checksum on part of the NVRAM data.  That's currently ignored
 	 * here.  If userspace is smart enough to know what fields of
@@ -598,17 +594,6 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
 	return retval;
 }
 
-static struct bin_attribute nvram = {
-	.attr = {
-		.name	= "nvram",
-		.mode	= S_IRUGO | S_IWUSR,
-	},
-
-	.read	= cmos_nvram_read,
-	.write	= cmos_nvram_write,
-	/* size gets set up later */
-};
-
 /*----------------------------------------------------------------*/
 
 static struct cmos_rtc	cmos_rtc;
@@ -675,6 +660,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 	unsigned char			rtc_control;
 	unsigned			address_space;
 	u32				flags = 0;
+	struct nvmem_config nvmem_cfg = {
+		.name = "cmos_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.reg_read = cmos_nvram_read,
+		.reg_write = cmos_nvram_write,
+		.priv = &cmos_rtc,
+	};
 
 	/* there can be only one ... */
 	if (cmos_rtc.dev)
@@ -751,8 +744,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 	cmos_rtc.dev = dev;
 	dev_set_drvdata(dev, &cmos_rtc);
 
-	cmos_rtc.rtc = rtc_device_register(driver_name, dev,
-				&cmos_rtc_ops, THIS_MODULE);
+	cmos_rtc.rtc = devm_rtc_allocate_device(dev);
 	if (IS_ERR(cmos_rtc.rtc)) {
 		retval = PTR_ERR(cmos_rtc.rtc);
 		goto cleanup0;
@@ -814,22 +806,25 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 		}
 	}
 
-	/* export at least the first block of NVRAM */
-	nvram.size = address_space - NVRAM_OFFSET;
-	retval = sysfs_create_bin_file(&dev->kobj, &nvram);
-	if (retval < 0) {
-		dev_dbg(dev, "can't create nvram file? %d\n", retval);
+	cmos_rtc.rtc->ops = &cmos_rtc_ops;
+	cmos_rtc.rtc->nvram_old_abi = true;
+	retval = rtc_register_device(cmos_rtc.rtc);
+	if (retval)
 		goto cleanup2;
-	}
 
-	dev_info(dev, "%s%s, %zd bytes nvram%s\n",
-		!is_valid_irq(rtc_irq) ? "no alarms" :
-			cmos_rtc.mon_alrm ? "alarms up to one year" :
-			cmos_rtc.day_alrm ? "alarms up to one month" :
-			"alarms up to one day",
-		cmos_rtc.century ? ", y3k" : "",
-		nvram.size,
-		is_hpet_enabled() ? ", hpet irqs" : "");
+	/* export at least the first block of NVRAM */
+	nvmem_cfg.size = address_space - NVRAM_OFFSET;
+	if (rtc_nvmem_register(cmos_rtc.rtc, &nvmem_cfg))
+		dev_err(dev, "nvmem registration failed\n");
+
+	dev_info(dev, "%s%s, %d bytes nvram%s\n",
+		 !is_valid_irq(rtc_irq) ? "no alarms" :
+		 cmos_rtc.mon_alrm ? "alarms up to one year" :
+		 cmos_rtc.day_alrm ? "alarms up to one month" :
+		 "alarms up to one day",
+		 cmos_rtc.century ? ", y3k" : "",
+		 nvmem_cfg.size,
+		 is_hpet_enabled() ? ", hpet irqs" : "");
 
 	return 0;
 
@@ -838,7 +833,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 		free_irq(rtc_irq, cmos_rtc.rtc);
 cleanup1:
 	cmos_rtc.dev = NULL;
-	rtc_device_unregister(cmos_rtc.rtc);
 cleanup0:
 	if (RTC_IOMAPPED)
 		release_region(ports->start, resource_size(ports));
@@ -862,14 +856,11 @@ static void cmos_do_remove(struct device *dev)
 
 	cmos_do_shutdown(cmos->irq);
 
-	sysfs_remove_bin_file(&dev->kobj, &nvram);
-
 	if (is_valid_irq(cmos->irq)) {
 		free_irq(cmos->irq, cmos->rtc);
 		hpet_unregister_irq_handler(cmos_interrupt);
 	}
 
-	rtc_device_unregister(cmos->rtc);
 	cmos->rtc = NULL;
 
 	ports = cmos->iomem;
diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h
index 513b9bedd2c8..0abf98983e13 100644
--- a/drivers/rtc/rtc-core.h
+++ b/drivers/rtc/rtc-core.h
@@ -46,11 +46,3 @@ static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
 	return NULL;
 }
 #endif
-
-#ifdef CONFIG_RTC_NVMEM
-void rtc_nvmem_register(struct rtc_device *rtc);
-void rtc_nvmem_unregister(struct rtc_device *rtc);
-#else
-static inline void rtc_nvmem_register(struct rtc_device *rtc) {}
-static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
-#endif
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 0ec4be62322b..43bcb17c922e 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -43,7 +43,7 @@ static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *time)
 {
 	struct spi_device	*spi = dev_get_drvdata(dev);
 	u8		buf[1 + RTC_CLCK_LEN];
-	u8		*bp = buf;
+	u8		*bp;
 	int		status;
 
 	/* Enable writing */
@@ -112,7 +112,7 @@ static int ds1302_probe(struct spi_device *spi)
 	struct rtc_device	*rtc;
 	u8		addr;
 	u8		buf[4];
-	u8		*bp = buf;
+	u8		*bp;
 	int		status;
 
 	/* Sanity check board setup data.  This may be hooked up
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index d8df2e9e14ad..3d2400a39da9 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -544,15 +544,6 @@ static int ds1305_nvram_write(void *priv, unsigned int off, void *buf,
 	return spi_sync(spi, &m);
 }
 
-static struct nvmem_config ds1305_nvmem_cfg = {
-	.name = "ds1305_nvram",
-	.word_size = 1,
-	.stride = 1,
-	.size = DS1305_NVRAM_LEN,
-	.reg_read = ds1305_nvram_read,
-	.reg_write = ds1305_nvram_write,
-};
-
 /*----------------------------------------------------------------------*/
 
 /*
@@ -566,6 +557,14 @@ static int ds1305_probe(struct spi_device *spi)
 	u8				addr, value;
 	struct ds1305_platform_data	*pdata = dev_get_platdata(&spi->dev);
 	bool				write_ctrl = false;
+	struct nvmem_config ds1305_nvmem_cfg = {
+		.name = "ds1305_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = DS1305_NVRAM_LEN,
+		.reg_read = ds1305_nvram_read,
+		.reg_write = ds1305_nvram_write,
+	};
 
 	/* Sanity check board setup data.  This may be hooked up
 	 * in 3wire mode, but we don't care.  Note that unless
@@ -703,15 +702,15 @@ static int ds1305_probe(struct spi_device *spi)
 	ds1305->rtc->ops = &ds1305_ops;
 
 	ds1305_nvmem_cfg.priv = ds1305;
-	ds1305->rtc->nvmem_config = &ds1305_nvmem_cfg;
 	ds1305->rtc->nvram_old_abi = true;
-
 	status = rtc_register_device(ds1305->rtc);
 	if (status) {
 		dev_dbg(&spi->dev, "register rtc --> %d\n", status);
 		return status;
 	}
 
+	rtc_nvmem_register(ds1305->rtc, &ds1305_nvmem_cfg);
+
 	/* Maybe set up alarm IRQ; be ready to handle it triggering right
 	 * away.  NOTE that we don't share this.  The signal is active low,
 	 * and we can't ack it before a SPI message delay.  We temporarily
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 923dde912f60..4021d478b9f3 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -114,7 +114,6 @@ enum ds_type {
 #	define RX8025_BIT_XST		0x20
 
 struct ds1307 {
-	struct nvmem_config	nvmem_cfg;
 	enum ds_type		type;
 	unsigned long		flags;
 #define HAS_NVRAM	0		/* bit 0 == sysfs file active */
@@ -1696,24 +1695,26 @@ static int ds1307_probe(struct i2c_client *client,
 		}
 	}
 
-	if (chip->nvram_size) {
-		ds1307->nvmem_cfg.name = "ds1307_nvram";
-		ds1307->nvmem_cfg.word_size = 1;
-		ds1307->nvmem_cfg.stride = 1;
-		ds1307->nvmem_cfg.size = chip->nvram_size;
-		ds1307->nvmem_cfg.reg_read = ds1307_nvram_read;
-		ds1307->nvmem_cfg.reg_write = ds1307_nvram_write;
-		ds1307->nvmem_cfg.priv = ds1307;
-
-		ds1307->rtc->nvmem_config = &ds1307->nvmem_cfg;
-		ds1307->rtc->nvram_old_abi = true;
-	}
-
 	ds1307->rtc->ops = chip->rtc_ops ?: &ds13xx_rtc_ops;
 	err = rtc_register_device(ds1307->rtc);
 	if (err)
 		return err;
 
+	if (chip->nvram_size) {
+		struct nvmem_config nvmem_cfg = {
+			.name = "ds1307_nvram",
+			.word_size = 1,
+			.stride = 1,
+			.size = chip->nvram_size,
+			.reg_read = ds1307_nvram_read,
+			.reg_write = ds1307_nvram_write,
+			.priv = ds1307,
+		};
+
+		ds1307->rtc->nvram_old_abi = true;
+		rtc_nvmem_register(ds1307->rtc, &nvmem_cfg);
+	}
+
 	ds1307_hwmon_register(ds1307);
 	ds1307_clks_register(ds1307);
 
diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c
index 895fbeeb47fe..59d27db2fd37 100644
--- a/drivers/rtc/rtc-ds1343.c
+++ b/drivers/rtc/rtc-ds1343.c
@@ -153,120 +153,22 @@ static ssize_t ds1343_store_glitchfilter(struct device *dev,
 static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter,
 			ds1343_store_glitchfilter);
 
-static ssize_t ds1343_nvram_write(struct file *filp, struct kobject *kobj,
-			struct bin_attribute *attr,
-			char *buf, loff_t off, size_t count)
+static int ds1343_nvram_write(void *priv, unsigned int off, void *val,
+			      size_t bytes)
 {
-	int ret;
-	unsigned char address;
-	struct device *dev = kobj_to_dev(kobj);
-	struct ds1343_priv *priv = dev_get_drvdata(dev);
-
-	address = DS1343_NVRAM + off;
-
-	ret = regmap_bulk_write(priv->map, address, buf, count);
-	if (ret < 0)
-		dev_err(&priv->spi->dev, "Error in nvram write %d", ret);
-
-	return (ret < 0) ? ret : count;
-}
-
-
-static ssize_t ds1343_nvram_read(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *attr,
-				char *buf, loff_t off, size_t count)
-{
-	int ret;
-	unsigned char address;
-	struct device *dev = kobj_to_dev(kobj);
-	struct ds1343_priv *priv = dev_get_drvdata(dev);
-
-	address = DS1343_NVRAM + off;
-
-	ret = regmap_bulk_read(priv->map, address, buf, count);
-	if (ret < 0)
-		dev_err(&priv->spi->dev, "Error in nvram read %d\n", ret);
-
-	return (ret < 0) ? ret : count;
-}
-
-
-static struct bin_attribute nvram_attr = {
-	.attr.name	= "nvram",
-	.attr.mode	= S_IRUGO | S_IWUSR,
-	.read		= ds1343_nvram_read,
-	.write		= ds1343_nvram_write,
-	.size		= DS1343_NVRAM_LEN,
-};
-
-static ssize_t ds1343_show_alarmstatus(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	struct ds1343_priv *priv = dev_get_drvdata(dev);
-	int alarmstatus, data;
-
-	regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+	struct ds1343_priv *ds1343 = priv;
 
-	alarmstatus = !!(data & DS1343_A0IE);
-
-	if (alarmstatus)
-		return sprintf(buf, "enabled\n");
-	else
-		return sprintf(buf, "disabled\n");
+	return regmap_bulk_write(ds1343->map, DS1343_NVRAM + off, val, bytes);
 }
 
-static DEVICE_ATTR(alarm_status, S_IRUGO, ds1343_show_alarmstatus, NULL);
-
-static ssize_t ds1343_show_alarmmode(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static int ds1343_nvram_read(void *priv, unsigned int off, void *val,
+			     size_t bytes)
 {
-	struct ds1343_priv *priv = dev_get_drvdata(dev);
-	int alarm_mode, data;
-	char *alarm_str;
-
-	regmap_read(priv->map, DS1343_ALM0_SEC_REG, &data);
-	alarm_mode = (data & 0x80) >> 4;
-
-	regmap_read(priv->map, DS1343_ALM0_MIN_REG, &data);
-	alarm_mode |= (data & 0x80) >> 5;
-
-	regmap_read(priv->map, DS1343_ALM0_HOUR_REG, &data);
-	alarm_mode |= (data & 0x80) >> 6;
-
-	regmap_read(priv->map, DS1343_ALM0_DAY_REG, &data);
-	alarm_mode |= (data & 0x80) >> 7;
-
-	switch (alarm_mode) {
-	case 15:
-		alarm_str = "each second";
-		break;
+	struct ds1343_priv *ds1343 = priv;
 
-	case 7:
-		alarm_str = "seconds match";
-		break;
-
-	case 3:
-		alarm_str = "minutes and seconds match";
-		break;
-
-	case 1:
-		alarm_str = "hours, minutes and seconds match";
-		break;
-
-	case 0:
-		alarm_str = "day, hours, minutes and seconds match";
-		break;
-
-	default:
-		alarm_str = "invalid";
-		break;
-	}
-
-	return sprintf(buf, "%s\n", alarm_str);
+	return regmap_bulk_read(ds1343->map, DS1343_NVRAM + off, val, bytes);
 }
 
-static DEVICE_ATTR(alarm_mode, S_IRUGO, ds1343_show_alarmmode, NULL);
-
 static ssize_t ds1343_show_tricklecharger(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -313,7 +215,6 @@ static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL);
 
 static int ds1343_sysfs_register(struct device *dev)
 {
-	struct ds1343_priv *priv = dev_get_drvdata(dev);
 	int err;
 
 	err = device_create_file(dev, &dev_attr_glitch_filter);
@@ -321,33 +222,9 @@ static int ds1343_sysfs_register(struct device *dev)
 		return err;
 
 	err = device_create_file(dev, &dev_attr_trickle_charger);
-	if (err)
-		goto error1;
-
-	err = device_create_bin_file(dev, &nvram_attr);
-	if (err)
-		goto error2;
-
-	if (priv->irq <= 0)
-		return err;
-
-	err = device_create_file(dev, &dev_attr_alarm_mode);
-	if (err)
-		goto error3;
-
-	err = device_create_file(dev, &dev_attr_alarm_status);
 	if (!err)
-		return err;
-
-	device_remove_file(dev, &dev_attr_alarm_mode);
-
-error3:
-	device_remove_bin_file(dev, &nvram_attr);
-
-error2:
-	device_remove_file(dev, &dev_attr_trickle_charger);
+		return 0;
 
-error1:
 	device_remove_file(dev, &dev_attr_glitch_filter);
 
 	return err;
@@ -355,17 +232,8 @@ static int ds1343_sysfs_register(struct device *dev)
 
 static void ds1343_sysfs_unregister(struct device *dev)
 {
-	struct ds1343_priv *priv = dev_get_drvdata(dev);
-
 	device_remove_file(dev, &dev_attr_glitch_filter);
 	device_remove_file(dev, &dev_attr_trickle_charger);
-	device_remove_bin_file(dev, &nvram_attr);
-
-	if (priv->irq <= 0)
-		return;
-
-	device_remove_file(dev, &dev_attr_alarm_status);
-	device_remove_file(dev, &dev_attr_alarm_mode);
 }
 
 static int ds1343_read_time(struct device *dev, struct rtc_time *dt)
@@ -599,14 +467,18 @@ static const struct rtc_class_ops ds1343_rtc_ops = {
 static int ds1343_probe(struct spi_device *spi)
 {
 	struct ds1343_priv *priv;
-	struct regmap_config config;
+	struct regmap_config config = { .reg_bits = 8, .val_bits = 8,
+					.write_flag_mask = 0x80, };
 	unsigned int data;
 	int res;
-
-	memset(&config, 0, sizeof(config));
-	config.reg_bits = 8;
-	config.val_bits = 8;
-	config.write_flag_mask = 0x80;
+	struct nvmem_config nvmem_cfg = {
+		.name = "ds1343-",
+		.word_size = 1,
+		.stride = 1,
+		.size = DS1343_NVRAM_LEN,
+		.reg_read = ds1343_nvram_read,
+		.reg_write = ds1343_nvram_write,
+	};
 
 	priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL);
 	if (!priv)
@@ -646,12 +518,19 @@ static int ds1343_probe(struct spi_device *spi)
 	data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0);
 	regmap_write(priv->map, DS1343_STATUS_REG, data);
 
-	priv->rtc = devm_rtc_device_register(&spi->dev, "ds1343",
-					&ds1343_rtc_ops, THIS_MODULE);
-	if (IS_ERR(priv->rtc)) {
-		dev_err(&spi->dev, "unable to register rtc ds1343\n");
+	priv->rtc = devm_rtc_allocate_device(&spi->dev);
+	if (IS_ERR(priv->rtc))
 		return PTR_ERR(priv->rtc);
-	}
+
+	priv->rtc->nvram_old_abi = true;
+	priv->rtc->ops = &ds1343_rtc_ops;
+
+	res = rtc_register_device(priv->rtc);
+	if (res)
+		return res;
+
+	nvmem_cfg.priv = priv;
+	rtc_nvmem_register(priv->rtc, &nvmem_cfg);
 
 	priv->irq = spi->irq;
 
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 1e95312a6f2e..5f55214db9f8 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -422,20 +422,20 @@ static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
 	return 0;
 }
 
-static struct nvmem_config ds1511_nvmem_cfg = {
-	.name = "ds1511_nvram",
-	.word_size = 1,
-	.stride = 1,
-	.size = DS1511_RAM_MAX,
-	.reg_read = ds1511_nvram_read,
-	.reg_write = ds1511_nvram_write,
-};
-
 static int ds1511_rtc_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	struct rtc_plat_data *pdata;
 	int ret = 0;
+	struct nvmem_config ds1511_nvmem_cfg = {
+		.name = "ds1511_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = DS1511_RAM_MAX,
+		.reg_read = ds1511_nvram_read,
+		.reg_write = ds1511_nvram_write,
+		.priv = &pdev->dev,
+	};
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -478,14 +478,14 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
 
 	pdata->rtc->ops = &ds1511_rtc_ops;
 
-	ds1511_nvmem_cfg.priv = &pdev->dev;
-	pdata->rtc->nvmem_config = &ds1511_nvmem_cfg;
 	pdata->rtc->nvram_old_abi = true;
 
 	ret = rtc_register_device(pdata->rtc);
 	if (ret)
 		return ret;
 
+	rtc_nvmem_register(pdata->rtc, &ds1511_nvmem_cfg);
+
 	/*
 	 * if the platform has an interrupt in mind for this device,
 	 * then by all means, set it
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 9961ec646fd2..7334c824371a 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -233,46 +233,32 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
 	.alarm_irq_enable	= ds1553_rtc_alarm_irq_enable,
 };
 
-static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj,
-				 struct bin_attribute *bin_attr,
-				 char *buf, loff_t pos, size_t size)
+static int ds1553_nvram_read(void *priv, unsigned int pos, void *val,
+			     size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct platform_device *pdev = priv;
 	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 	void __iomem *ioaddr = pdata->ioaddr;
-	ssize_t count;
+	u8 *buf = val;
 
-	for (count = 0; count < size; count++)
+	for (; bytes; bytes--)
 		*buf++ = readb(ioaddr + pos++);
-	return count;
+	return 0;
 }
 
-static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj,
-				  struct bin_attribute *bin_attr,
-				  char *buf, loff_t pos, size_t size)
+static int ds1553_nvram_write(void *priv, unsigned int pos, void *val,
+			      size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct platform_device *pdev = priv;
 	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 	void __iomem *ioaddr = pdata->ioaddr;
-	ssize_t count;
+	u8 *buf = val;
 
-	for (count = 0; count < size; count++)
+	for (; bytes; bytes--)
 		writeb(*buf++, ioaddr + pos++);
-	return count;
+	return 0;
 }
 
-static struct bin_attribute ds1553_nvram_attr = {
-	.attr = {
-		.name = "nvram",
-		.mode = S_IRUGO | S_IWUSR,
-	},
-	.size = RTC_OFFSET,
-	.read = ds1553_nvram_read,
-	.write = ds1553_nvram_write,
-};
-
 static int ds1553_rtc_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -280,6 +266,15 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
 	struct rtc_plat_data *pdata;
 	void __iomem *ioaddr;
 	int ret = 0;
+	struct nvmem_config nvmem_cfg = {
+		.name = "ds1553_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = RTC_OFFSET,
+		.reg_read = ds1553_nvram_read,
+		.reg_write = ds1553_nvram_write,
+		.priv = pdev,
+	};
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -308,11 +303,17 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
 	pdata->last_jiffies = jiffies;
 	platform_set_drvdata(pdev, pdata);
 
-	pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-				  &ds1553_rtc_ops, THIS_MODULE);
+	pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(pdata->rtc))
 		return PTR_ERR(pdata->rtc);
 
+	pdata->rtc->ops = &ds1553_rtc_ops;
+	pdata->rtc->nvram_old_abi = true;
+
+	ret = rtc_register_device(pdata->rtc);
+	if (ret)
+		return ret;
+
 	if (pdata->irq > 0) {
 		writeb(0, ioaddr + RTC_INTERRUPTS);
 		if (devm_request_irq(&pdev->dev, pdata->irq,
@@ -323,21 +324,9 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
 		}
 	}
 
-	ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
-	if (ret)
-		dev_err(&pdev->dev, "unable to create sysfs file: %s\n",
-			ds1553_nvram_attr.attr.name);
-
-	return 0;
-}
-
-static int ds1553_rtc_remove(struct platform_device *pdev)
-{
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	if (rtc_nvmem_register(pdata->rtc, &nvmem_cfg))
+		dev_err(&pdev->dev, "unable to register nvmem\n");
 
-	sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
-	if (pdata->irq > 0)
-		writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
 	return 0;
 }
 
@@ -346,7 +335,6 @@ MODULE_ALIAS("platform:rtc-ds1553");
 
 static struct platform_driver ds1553_rtc_driver = {
 	.probe		= ds1553_rtc_probe,
-	.remove		= ds1553_rtc_remove,
 	.driver		= {
 		.name	= "rtc-ds1553",
 	},
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 3abf1cbfb8ce..52baf925a690 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -53,9 +53,7 @@
 struct rtc_plat_data {
 	void __iomem *ioaddr_nvram;
 	void __iomem *ioaddr_rtc;
-	size_t size_nvram;
 	unsigned long last_jiffies;
-	struct bin_attribute nvram_attr;
 };
 
 static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -122,34 +120,28 @@ static const struct rtc_class_ops ds1742_rtc_ops = {
 	.set_time	= ds1742_rtc_set_time,
 };
 
-static ssize_t ds1742_nvram_read(struct file *filp, struct kobject *kobj,
-				 struct bin_attribute *bin_attr,
-				 char *buf, loff_t pos, size_t size)
+static int ds1742_nvram_read(void *priv, unsigned int pos, void *val,
+			     size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	struct rtc_plat_data *pdata = priv;
 	void __iomem *ioaddr = pdata->ioaddr_nvram;
-	ssize_t count;
+	u8 *buf = val;
 
-	for (count = 0; count < size; count++)
+	for (; bytes; bytes--)
 		*buf++ = readb(ioaddr + pos++);
-	return count;
+	return 0;
 }
 
-static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj,
-				  struct bin_attribute *bin_attr,
-				  char *buf, loff_t pos, size_t size)
+static int ds1742_nvram_write(void *priv, unsigned int pos, void *val,
+			      size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	struct rtc_plat_data *pdata = priv;
 	void __iomem *ioaddr = pdata->ioaddr_nvram;
-	ssize_t count;
+	u8 *buf = val;
 
-	for (count = 0; count < size; count++)
+	for (; bytes; bytes--)
 		writeb(*buf++, ioaddr + pos++);
-	return count;
+	return 0;
 }
 
 static int ds1742_rtc_probe(struct platform_device *pdev)
@@ -160,6 +152,14 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
 	struct rtc_plat_data *pdata;
 	void __iomem *ioaddr;
 	int ret = 0;
+	struct nvmem_config nvmem_cfg = {
+		.name = "ds1742_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.reg_read = ds1742_nvram_read,
+		.reg_write = ds1742_nvram_write,
+	};
+
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -171,15 +171,10 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
 		return PTR_ERR(ioaddr);
 
 	pdata->ioaddr_nvram = ioaddr;
-	pdata->size_nvram = resource_size(res) - RTC_SIZE;
-	pdata->ioaddr_rtc = ioaddr + pdata->size_nvram;
+	pdata->ioaddr_rtc = ioaddr + resource_size(res) - RTC_SIZE;
 
-	sysfs_bin_attr_init(&pdata->nvram_attr);
-	pdata->nvram_attr.attr.name = "nvram";
-	pdata->nvram_attr.attr.mode = S_IRUGO | S_IWUSR;
-	pdata->nvram_attr.read = ds1742_nvram_read;
-	pdata->nvram_attr.write = ds1742_nvram_write;
-	pdata->nvram_attr.size = pdata->size_nvram;
+	nvmem_cfg.size = resource_size(res) - RTC_SIZE;
+	nvmem_cfg.priv = pdata;
 
 	/* turn RTC on if it was not on */
 	ioaddr = pdata->ioaddr_rtc;
@@ -196,24 +191,21 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
 
 	pdata->last_jiffies = jiffies;
 	platform_set_drvdata(pdev, pdata);
-	rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-				  &ds1742_rtc_ops, THIS_MODULE);
+
+	rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
 
-	ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
-	if (ret)
-		dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
-			pdata->nvram_attr.attr.name);
+	rtc->ops = &ds1742_rtc_ops;
+	rtc->nvram_old_abi = true;
 
-	return 0;
-}
+	ret = rtc_register_device(rtc);
+	if (ret)
+		return ret;
 
-static int ds1742_rtc_remove(struct platform_device *pdev)
-{
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	if (rtc_nvmem_register(rtc, &nvmem_cfg))
+		dev_err(&pdev->dev, "Unable to register nvmem\n");
 
-	sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
 	return 0;
 }
 
@@ -225,7 +217,6 @@ MODULE_DEVICE_TABLE(of, ds1742_rtc_of_match);
 
 static struct platform_driver ds1742_rtc_driver = {
 	.probe		= ds1742_rtc_probe,
-	.remove		= ds1742_rtc_remove,
 	.driver		= {
 		.name	= "rtc-ds1742",
 		.of_match_table = of_match_ptr(ds1742_rtc_of_match),
diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c
index d67769265185..a1c44d0c8557 100644
--- a/drivers/rtc/rtc-goldfish.c
+++ b/drivers/rtc/rtc-goldfish.c
@@ -235,3 +235,5 @@ static struct platform_driver goldfish_rtc = {
 };
 
 module_platform_driver(goldfish_rtc);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 8dd299c6a1f3..c8b495348229 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -459,6 +459,11 @@ isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
 	}
 
 	/* clear WRTC again */
+	sr = isl1208_i2c_get_sr(client);
+	if (sr < 0) {
+		dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+		return sr;
+	}
 	sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR,
 				       sr & ~ISL1208_REG_SR_WRTC);
 	if (sr < 0) {
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 1ae7da5cfc60..ad5bb21908e5 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -52,13 +52,11 @@ EXPORT_SYMBOL(rtc_year_days);
  */
 void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
 {
-	unsigned int month, year;
-	unsigned long secs;
+	unsigned int month, year, secs;
 	int days;
 
 	/* time must be positive */
-	days = div_s64(time, 86400);
-	secs = time - (unsigned int) days * 86400;
+	days = div_s64_rem(time, 86400, &secs);
 
 	/* day of the week, 1970-01-01 was a Thursday */
 	tm->tm_wday = (days + 4) % 7;
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index d99a705bec07..399fc4255d54 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -334,16 +334,16 @@ static const struct rtc_class_ops m48t02_rtc_ops = {
 	.set_time	= m48t59_rtc_set_time,
 };
 
-static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t pos, size_t size)
+static int m48t59_nvram_read(void *priv, unsigned int offset, void *val,
+			     size_t size)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct platform_device *pdev = priv;
+	struct device *dev = &pdev->dev;
 	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
 	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
 	ssize_t cnt = 0;
 	unsigned long flags;
+	u8 *buf = val;
 
 	spin_lock_irqsave(&m48t59->lock, flags);
 
@@ -352,19 +352,19 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,
 
 	spin_unlock_irqrestore(&m48t59->lock, flags);
 
-	return cnt;
+	return 0;
 }
 
-static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t pos, size_t size)
+static int m48t59_nvram_write(void *priv, unsigned int offset, void *val,
+			      size_t size)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct platform_device *pdev = priv;
+	struct device *dev = &pdev->dev;
 	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
 	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
 	ssize_t cnt = 0;
 	unsigned long flags;
+	u8 *buf = val;
 
 	spin_lock_irqsave(&m48t59->lock, flags);
 
@@ -373,18 +373,9 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,
 
 	spin_unlock_irqrestore(&m48t59->lock, flags);
 
-	return cnt;
+	return 0;
 }
 
-static struct bin_attribute m48t59_nvram_attr = {
-	.attr = {
-		.name = "nvram",
-		.mode = S_IRUGO | S_IWUSR,
-	},
-	.read = m48t59_nvram_read,
-	.write = m48t59_nvram_write,
-};
-
 static int m48t59_rtc_probe(struct platform_device *pdev)
 {
 	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
@@ -393,6 +384,15 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
 	int ret = -ENOMEM;
 	char *name;
 	const struct rtc_class_ops *ops;
+	struct nvmem_config nvmem_cfg = {
+		.name = "m48t59-",
+		.word_size = 1,
+		.stride = 1,
+		.size = pdata->offset,
+		.reg_read = m48t59_nvram_read,
+		.reg_write = m48t59_nvram_write,
+		.priv = pdev,
+	};
 
 	/* This chip could be memory-mapped or I/O-mapped */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -480,23 +480,19 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
 	spin_lock_init(&m48t59->lock);
 	platform_set_drvdata(pdev, m48t59);
 
-	m48t59->rtc = devm_rtc_device_register(&pdev->dev, name, ops,
-						THIS_MODULE);
+	m48t59->rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(m48t59->rtc))
 		return PTR_ERR(m48t59->rtc);
 
-	m48t59_nvram_attr.size = pdata->offset;
+	m48t59->rtc->nvram_old_abi = true;
+	m48t59->rtc->ops = ops;
 
-	ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
+	ret = rtc_register_device(m48t59->rtc);
 	if (ret)
 		return ret;
 
-	return 0;
-}
+	rtc_nvmem_register(m48t59->rtc, &nvmem_cfg);
 
-static int m48t59_rtc_remove(struct platform_device *pdev)
-{
-	sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
 	return 0;
 }
 
@@ -508,7 +504,6 @@ static struct platform_driver m48t59_rtc_driver = {
 		.name	= "rtc-m48t59",
 	},
 	.probe		= m48t59_rtc_probe,
-	.remove		= m48t59_rtc_remove,
 };
 
 module_platform_driver(m48t59_rtc_driver);
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index d9aea9b6d9cd..8d17be1e6650 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -218,21 +218,21 @@ static bool m48t86_verify_chip(struct platform_device *pdev)
 	return false;
 }
 
-static struct nvmem_config m48t86_nvmem_cfg = {
-	.name = "m48t86_nvram",
-	.word_size = 1,
-	.stride = 1,
-	.size = M48T86_NVRAM_LEN,
-	.reg_read = m48t86_nvram_read,
-	.reg_write = m48t86_nvram_write,
-};
-
 static int m48t86_rtc_probe(struct platform_device *pdev)
 {
 	struct m48t86_rtc_info *info;
 	struct resource *res;
 	unsigned char reg;
 	int err;
+	struct nvmem_config m48t86_nvmem_cfg = {
+		.name = "m48t86_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = M48T86_NVRAM_LEN,
+		.reg_read = m48t86_nvram_read,
+		.reg_write = m48t86_nvram_write,
+		.priv = &pdev->dev,
+	};
 
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
@@ -264,15 +264,14 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
 		return PTR_ERR(info->rtc);
 
 	info->rtc->ops = &m48t86_rtc_ops;
-
-	m48t86_nvmem_cfg.priv = &pdev->dev;
-	info->rtc->nvmem_config = &m48t86_nvmem_cfg;
 	info->rtc->nvram_old_abi = true;
 
 	err = rtc_register_device(info->rtc);
 	if (err)
 		return err;
 
+	rtc_nvmem_register(info->rtc, &m48t86_nvmem_cfg);
+
 	/* read battery status */
 	reg = m48t86_readb(&pdev->dev, M48T86_D);
 	dev_info(&pdev->dev, "battery %s\n",
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
index 784221dfc9c7..9e14efb990b2 100644
--- a/drivers/rtc/rtc-mxc_v2.c
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -273,7 +273,7 @@ static const struct rtc_class_ops mxc_rtc_ops = {
 	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
 };
 
-static int mxc_rtc_wait_for_flag(void *__iomem ioaddr, int flag)
+static int mxc_rtc_wait_for_flag(void __iomem *ioaddr, int flag)
 {
 	unsigned int timeout = REG_READ_TIMEOUT;
 
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 09ef802d6e54..e53cb27f4118 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -850,7 +850,6 @@ static int omap_rtc_probe(struct platform_device *pdev)
 
 	rtc->rtc->ops = &omap_rtc_ops;
 	omap_rtc_nvmem_config.priv = rtc;
-	rtc->rtc->nvmem_config = &omap_rtc_nvmem_config;
 
 	/* handle periodic and alarm irqs */
 	ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
@@ -886,6 +885,8 @@ static int omap_rtc_probe(struct platform_device *pdev)
 	if (ret)
 		goto err;
 
+	rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config);
+
 	return 0;
 
 err:
diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c
index ea04e9f0930b..64573cccf7fe 100644
--- a/drivers/rtc/rtc-pcf85363.c
+++ b/drivers/rtc/rtc-pcf85363.c
@@ -80,7 +80,6 @@ static struct i2c_driver pcf85363_driver;
 struct pcf85363 {
 	struct device		*dev;
 	struct rtc_device	*rtc;
-	struct nvmem_config	nvmem_cfg;
 	struct regmap		*regmap;
 };
 
@@ -164,6 +163,15 @@ static int pcf85363_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
 {
 	struct pcf85363 *pcf85363;
+	struct nvmem_config nvmem_cfg = {
+		.name = "pcf85363-",
+		.word_size = 1,
+		.stride = 1,
+		.size = NVRAM_SIZE,
+		.reg_read = pcf85363_nvram_read,
+		.reg_write = pcf85363_nvram_write,
+	};
+	int ret;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
@@ -186,17 +194,14 @@ static int pcf85363_probe(struct i2c_client *client,
 	if (IS_ERR(pcf85363->rtc))
 		return PTR_ERR(pcf85363->rtc);
 
-	pcf85363->nvmem_cfg.name = "pcf85363-";
-	pcf85363->nvmem_cfg.word_size = 1;
-	pcf85363->nvmem_cfg.stride = 1;
-	pcf85363->nvmem_cfg.size = NVRAM_SIZE;
-	pcf85363->nvmem_cfg.reg_read = pcf85363_nvram_read;
-	pcf85363->nvmem_cfg.reg_write = pcf85363_nvram_write;
-	pcf85363->nvmem_cfg.priv = pcf85363;
-	pcf85363->rtc->nvmem_config = &pcf85363->nvmem_cfg;
 	pcf85363->rtc->ops = &rtc_ops;
 
-	return rtc_register_device(pcf85363->rtc);
+	ret = rtc_register_device(pcf85363->rtc);
+
+	nvmem_cfg.priv = pcf85363;
+	rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg);
+
+	return ret;
 }
 
 static const struct of_device_id dev_ids[] = {
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
index 026035373ae6..2c0605132ac0 100644
--- a/drivers/rtc/rtc-rp5c01.c
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -64,7 +64,6 @@ struct rp5c01_priv {
 	u32 __iomem *regs;
 	struct rtc_device *rtc;
 	spinlock_t lock;	/* against concurrent RTC/NVRAM access */
-	struct bin_attribute nvram_attr;
 };
 
 static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
@@ -160,17 +159,15 @@ static const struct rtc_class_ops rp5c01_rtc_ops = {
  * byte is stored in BLOCK10, the low nibble in BLOCK11.
  */
 
-static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj,
-				 struct bin_attribute *bin_attr,
-				 char *buf, loff_t pos, size_t size)
+static int rp5c01_nvram_read(void *_priv, unsigned int pos, void *val,
+			     size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct rp5c01_priv *priv = dev_get_drvdata(dev);
-	ssize_t count;
+	struct rp5c01_priv *priv = _priv;
+	u8 *buf = val;
 
 	spin_lock_irq(&priv->lock);
 
-	for (count = 0; count < size; count++) {
+	for (; bytes; bytes--) {
 		u8 data;
 
 		rp5c01_write(priv,
@@ -187,20 +184,18 @@ static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj,
 	}
 
 	spin_unlock_irq(&priv->lock);
-	return count;
+	return 0;
 }
 
-static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj,
-				  struct bin_attribute *bin_attr,
-				  char *buf, loff_t pos, size_t size)
+static int rp5c01_nvram_write(void *_priv, unsigned int pos, void *val,
+			      size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct rp5c01_priv *priv = dev_get_drvdata(dev);
-	ssize_t count;
+	struct rp5c01_priv *priv = _priv;
+	u8 *buf = val;
 
 	spin_lock_irq(&priv->lock);
 
-	for (count = 0; count < size; count++) {
+	for (; bytes; bytes--) {
 		u8 data = *buf++;
 
 		rp5c01_write(priv,
@@ -216,7 +211,7 @@ static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj,
 	}
 
 	spin_unlock_irq(&priv->lock);
-	return count;
+	return 0;
 }
 
 static int __init rp5c01_rtc_probe(struct platform_device *dev)
@@ -225,6 +220,14 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
 	struct rp5c01_priv *priv;
 	struct rtc_device *rtc;
 	int error;
+	struct nvmem_config nvmem_cfg = {
+		.name = "rp5c01_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = RP5C01_MODE,
+		.reg_read = rp5c01_nvram_read,
+		.reg_write = rp5c01_nvram_write,
+	};
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -238,35 +241,26 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
 	if (!priv->regs)
 		return -ENOMEM;
 
-	sysfs_bin_attr_init(&priv->nvram_attr);
-	priv->nvram_attr.attr.name = "nvram";
-	priv->nvram_attr.attr.mode = S_IRUGO | S_IWUSR;
-	priv->nvram_attr.read = rp5c01_nvram_read;
-	priv->nvram_attr.write = rp5c01_nvram_write;
-	priv->nvram_attr.size = RP5C01_MODE;
-
 	spin_lock_init(&priv->lock);
 
 	platform_set_drvdata(dev, priv);
 
-	rtc = devm_rtc_device_register(&dev->dev, "rtc-rp5c01", &rp5c01_rtc_ops,
-				  THIS_MODULE);
+	rtc = devm_rtc_allocate_device(&dev->dev);
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
+
+	rtc->ops = &rp5c01_rtc_ops;
+	rtc->nvram_old_abi = true;
+
 	priv->rtc = rtc;
 
-	error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
+	error = rtc_register_device(rtc);
 	if (error)
 		return error;
 
-	return 0;
-}
-
-static int __exit rp5c01_rtc_remove(struct platform_device *dev)
-{
-	struct rp5c01_priv *priv = platform_get_drvdata(dev);
+	nvmem_cfg.priv = priv;
+	rtc_nvmem_register(rtc, &nvmem_cfg);
 
-	sysfs_remove_bin_file(&dev->dev.kobj, &priv->nvram_attr);
 	return 0;
 }
 
@@ -274,7 +268,6 @@ static struct platform_driver rp5c01_rtc_driver = {
 	.driver	= {
 		.name	= "rtc-rp5c01",
 	},
-	.remove	= __exit_p(rp5c01_rtc_remove),
 };
 
 module_platform_driver_probe(rp5c01_rtc_driver, rp5c01_rtc_probe);
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index aae2576741a6..29fc3d210392 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -68,7 +68,6 @@ struct rv8803_data {
 	struct mutex flags_lock;
 	u8 ctrl;
 	enum rv8803_type type;
-	struct nvmem_config nvmem_cfg;
 };
 
 static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
@@ -528,6 +527,15 @@ static int rv8803_probe(struct i2c_client *client,
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct rv8803_data *rv8803;
 	int err, flags;
+	struct nvmem_config nvmem_cfg = {
+		.name = "rv8803_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = 1,
+		.reg_read = rv8803_nvram_read,
+		.reg_write = rv8803_nvram_write,
+		.priv = client,
+	};
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 				     I2C_FUNC_SMBUS_I2C_BLOCK)) {
@@ -582,21 +590,6 @@ static int rv8803_probe(struct i2c_client *client,
 		}
 	}
 
-	rv8803->nvmem_cfg.name = "rv8803_nvram",
-	rv8803->nvmem_cfg.word_size = 1,
-	rv8803->nvmem_cfg.stride = 1,
-	rv8803->nvmem_cfg.size = 1,
-	rv8803->nvmem_cfg.reg_read = rv8803_nvram_read,
-	rv8803->nvmem_cfg.reg_write = rv8803_nvram_write,
-	rv8803->nvmem_cfg.priv = client;
-
-	rv8803->rtc->ops = &rv8803_rtc_ops;
-	rv8803->rtc->nvmem_config = &rv8803->nvmem_cfg;
-	rv8803->rtc->nvram_old_abi = true;
-	err = rtc_register_device(rv8803->rtc);
-	if (err)
-		return err;
-
 	err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
 	if (err)
 		return err;
@@ -607,6 +600,14 @@ static int rv8803_probe(struct i2c_client *client,
 		return err;
 	}
 
+	rv8803->rtc->ops = &rv8803_rtc_ops;
+	rv8803->rtc->nvram_old_abi = true;
+	err = rtc_register_device(rv8803->rtc);
+	if (err)
+		return err;
+
+	rtc_nvmem_register(rv8803->rtc, &nvmem_cfg);
+
 	rv8803->rtc->max_user_freq = 1;
 
 	return 0;
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
index 7367f617145c..2a9e151cae99 100644
--- a/drivers/rtc/rtc-sirfsoc.c
+++ b/drivers/rtc/rtc-sirfsoc.c
@@ -204,23 +204,6 @@ static int sirfsoc_rtc_set_time(struct device *dev,
 	return 0;
 }
 
-static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd,
-		unsigned long arg)
-{
-	switch (cmd) {
-	case RTC_PIE_ON:
-	case RTC_PIE_OFF:
-	case RTC_UIE_ON:
-	case RTC_UIE_OFF:
-	case RTC_AIE_ON:
-	case RTC_AIE_OFF:
-		return 0;
-
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-
 static int sirfsoc_rtc_alarm_irq_enable(struct device *dev,
 		unsigned int enabled)
 {
@@ -250,7 +233,6 @@ static const struct rtc_class_ops sirfsoc_rtc_ops = {
 	.set_time = sirfsoc_rtc_set_time,
 	.read_alarm = sirfsoc_rtc_read_alarm,
 	.set_alarm = sirfsoc_rtc_set_alarm,
-	.ioctl = sirfsoc_rtc_ioctl,
 	.alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable
 };
 
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index a456cb6177ea..b670e44306a8 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -242,46 +242,30 @@ static const struct rtc_class_ops stk17ta8_rtc_ops = {
 	.alarm_irq_enable	= stk17ta8_rtc_alarm_irq_enable,
 };
 
-static ssize_t stk17ta8_nvram_read(struct file *filp, struct kobject *kobj,
-				 struct bin_attribute *attr, char *buf,
-				 loff_t pos, size_t size)
+static int stk17ta8_nvram_read(void *priv, unsigned int pos, void *val,
+			       size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	struct rtc_plat_data *pdata = priv;
 	void __iomem *ioaddr = pdata->ioaddr;
-	ssize_t count;
+	u8 *buf = val;
 
-	for (count = 0; count < size; count++)
+	for (; bytes; bytes--)
 		*buf++ = readb(ioaddr + pos++);
-	return count;
+	return 0;
 }
 
-static ssize_t stk17ta8_nvram_write(struct file *filp, struct kobject *kobj,
-				  struct bin_attribute *attr, char *buf,
-				  loff_t pos, size_t size)
+static int stk17ta8_nvram_write(void *priv, unsigned int pos, void *val,
+				size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct platform_device *pdev = to_platform_device(dev);
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	struct rtc_plat_data *pdata = priv;
 	void __iomem *ioaddr = pdata->ioaddr;
-	ssize_t count;
+	u8 *buf = val;
 
-	for (count = 0; count < size; count++)
+	for (; bytes; bytes--)
 		writeb(*buf++, ioaddr + pos++);
-	return count;
+	return 0;
 }
 
-static struct bin_attribute stk17ta8_nvram_attr = {
-	.attr = {
-		.name = "nvram",
-		.mode = S_IRUGO | S_IWUSR,
-	},
-	.size = RTC_OFFSET,
-	.read = stk17ta8_nvram_read,
-	.write = stk17ta8_nvram_write,
-};
-
 static int stk17ta8_rtc_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -290,6 +274,14 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev)
 	struct rtc_plat_data *pdata;
 	void __iomem *ioaddr;
 	int ret = 0;
+	struct nvmem_config nvmem_cfg = {
+		.name = "stk17ta8_nvram",
+		.word_size = 1,
+		.stride = 1,
+		.size = RTC_OFFSET,
+		.reg_read = stk17ta8_nvram_read,
+		.reg_write = stk17ta8_nvram_write,
+	};
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -328,24 +320,21 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev)
 		}
 	}
 
-	pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-				  &stk17ta8_rtc_ops, THIS_MODULE);
+	pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(pdata->rtc))
 		return PTR_ERR(pdata->rtc);
 
-	ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+	pdata->rtc->ops = &stk17ta8_rtc_ops;
+	pdata->rtc->nvram_old_abi = true;
 
-	return ret;
-}
+	ret = rtc_register_device(pdata->rtc);
+	if (ret)
+		return ret;
 
-static int stk17ta8_rtc_remove(struct platform_device *pdev)
-{
-	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	nvmem_cfg.priv = pdata;
+	rtc_nvmem_register(pdata->rtc, &nvmem_cfg);
 
-	sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
-	if (pdata->irq > 0)
-		writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
-	return 0;
+	return ret;
 }
 
 /* work with hotplug and coldplug */
@@ -353,7 +342,6 @@ MODULE_ALIAS("platform:stk17ta8");
 
 static struct platform_driver stk17ta8_rtc_driver = {
 	.probe		= stk17ta8_rtc_probe,
-	.remove		= stk17ta8_rtc_remove,
 	.driver		= {
 		.name	= "stk17ta8",
 	},
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index 560d9a5e0225..1f351308afdc 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -14,7 +14,30 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/gfp.h>
-#include <asm/txx9/tx4939.h>
+
+#define TX4939_RTCCTL_ALME	0x00000080
+#define TX4939_RTCCTL_ALMD	0x00000040
+#define TX4939_RTCCTL_BUSY	0x00000020
+
+#define TX4939_RTCCTL_COMMAND	0x00000007
+#define TX4939_RTCCTL_COMMAND_NOP	0x00000000
+#define TX4939_RTCCTL_COMMAND_GETTIME	0x00000001
+#define TX4939_RTCCTL_COMMAND_SETTIME	0x00000002
+#define TX4939_RTCCTL_COMMAND_GETALARM	0x00000003
+#define TX4939_RTCCTL_COMMAND_SETALARM	0x00000004
+
+#define TX4939_RTCTBC_PM	0x00000080
+#define TX4939_RTCTBC_COMP	0x0000007f
+
+#define TX4939_RTC_REG_RAMSIZE	0x00000100
+#define TX4939_RTC_REG_RWBSIZE	0x00000006
+
+struct tx4939_rtc_reg {
+	__u32 ctl;
+	__u32 adr;
+	__u32 dat;
+	__u32 tbc;
+};
 
 struct tx4939rtc_plat_data {
 	struct rtc_device *rtc;
@@ -86,7 +109,8 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	for (i = 2; i < 6; i++)
 		buf[i] = __raw_readl(&rtcreg->dat);
 	spin_unlock_irq(&pdata->lock);
-	sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
+	sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) |
+		(buf[3] << 8) | buf[2];
 	rtc_time_to_tm(sec, tm);
 	return rtc_valid_tm(tm);
 }
@@ -147,7 +171,8 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 	alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0;
 	alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0;
 	spin_unlock_irq(&pdata->lock);
-	sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
+	sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) |
+		(buf[3] << 8) | buf[2];
 	rtc_time_to_tm(sec, &alrm->time);
 	return rtc_valid_tm(&alrm->time);
 }
@@ -189,58 +214,52 @@ static const struct rtc_class_ops tx4939_rtc_ops = {
 	.alarm_irq_enable	= tx4939_rtc_alarm_irq_enable,
 };
 
-static ssize_t tx4939_rtc_nvram_read(struct file *filp, struct kobject *kobj,
-				     struct bin_attribute *bin_attr,
-				     char *buf, loff_t pos, size_t size)
+static int tx4939_nvram_read(void *priv, unsigned int pos, void *val,
+			     size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
+	struct tx4939rtc_plat_data *pdata = priv;
 	struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
-	ssize_t count;
+	u8 *buf = val;
 
 	spin_lock_irq(&pdata->lock);
-	for (count = 0; count < size; count++) {
+	for (; bytes; bytes--) {
 		__raw_writel(pos++, &rtcreg->adr);
 		*buf++ = __raw_readl(&rtcreg->dat);
 	}
 	spin_unlock_irq(&pdata->lock);
-	return count;
+	return 0;
 }
 
-static ssize_t tx4939_rtc_nvram_write(struct file *filp, struct kobject *kobj,
-				      struct bin_attribute *bin_attr,
-				      char *buf, loff_t pos, size_t size)
+static int tx4939_nvram_write(void *priv, unsigned int pos, void *val,
+			      size_t bytes)
 {
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
+	struct tx4939rtc_plat_data *pdata = priv;
 	struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
-	ssize_t count;
+	u8 *buf = val;
 
 	spin_lock_irq(&pdata->lock);
-	for (count = 0; count < size; count++) {
+	for (; bytes; bytes--) {
 		__raw_writel(pos++, &rtcreg->adr);
 		__raw_writel(*buf++, &rtcreg->dat);
 	}
 	spin_unlock_irq(&pdata->lock);
-	return count;
+	return 0;
 }
 
-static struct bin_attribute tx4939_rtc_nvram_attr = {
-	.attr = {
-		.name = "nvram",
-		.mode = S_IRUGO | S_IWUSR,
-	},
-	.size = TX4939_RTC_REG_RAMSIZE,
-	.read = tx4939_rtc_nvram_read,
-	.write = tx4939_rtc_nvram_write,
-};
-
 static int __init tx4939_rtc_probe(struct platform_device *pdev)
 {
 	struct rtc_device *rtc;
 	struct tx4939rtc_plat_data *pdata;
 	struct resource *res;
 	int irq, ret;
+	struct nvmem_config nvmem_cfg = {
+		.name = "rv8803_nvram",
+		.word_size = 4,
+		.stride = 4,
+		.size = TX4939_RTC_REG_RAMSIZE,
+		.reg_read = tx4939_nvram_read,
+		.reg_write = tx4939_nvram_write,
+	};
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -260,12 +279,21 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
 	if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,
 			     0, pdev->name, &pdev->dev) < 0)
 		return -EBUSY;
-	rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-				  &tx4939_rtc_ops, THIS_MODULE);
+	rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
+
+	rtc->ops = &tx4939_rtc_ops;
+	rtc->nvram_old_abi = true;
+
 	pdata->rtc = rtc;
-	ret = sysfs_create_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
+
+	ret = rtc_register_device(rtc);
+	if (ret)
+		return ret;
+
+	nvmem_cfg.priv = pdata;
+	ret = rtc_nvmem_register(rtc, &nvmem_cfg);
 
 	return ret;
 }
@@ -274,7 +302,6 @@ static int __exit tx4939_rtc_remove(struct platform_device *pdev)
 {
 	struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
-	sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
 	spin_lock_irq(&pdata->lock);
 	tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
 	spin_unlock_irq(&pdata->lock);
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 2fdab400c1fe..a863b0462b43 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -5,5 +5,5 @@
 
 obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/
 
-drivers-y += drivers/s390/built-in.o
+drivers-y += drivers/s390/built-in.a
 
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index a7c15f0085e2..ecef8e73d40b 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2581,8 +2581,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
 	case DASD_CQR_QUEUED:
 		/* request was not started - just set to cleared */
 		cqr->status = DASD_CQR_CLEARED;
-		if (cqr->callback_data == DASD_SLEEPON_START_TAG)
-			cqr->callback_data = DASD_SLEEPON_END_TAG;
 		break;
 	case DASD_CQR_IN_IO:
 		/* request in IO - terminate IO and release again */
@@ -3902,9 +3900,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
 		wait_event(dasd_flush_wq,
 			   (cqr->status != DASD_CQR_CLEAR_PENDING));
 
-		/* mark sleepon requests as ended */
-		if (cqr->callback_data == DASD_SLEEPON_START_TAG)
-			cqr->callback_data = DASD_SLEEPON_END_TAG;
+		/*
+		 * requeue requests to blocklayer will only work
+		 * for block device requests
+		 */
+		if (_dasd_requeue_request(cqr))
+			continue;
 
 		/* remove requests from device and block queue */
 		list_del_init(&cqr->devlist);
@@ -3917,13 +3918,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
 			cqr = refers;
 		}
 
-		/*
-		 * requeue requests to blocklayer will only work
-		 * for block device requests
-		 */
-		if (_dasd_requeue_request(cqr))
-			continue;
-
 		if (cqr->block)
 			list_del_init(&cqr->blocklist);
 		cqr->block->base->discipline->free_cp(
@@ -3940,8 +3934,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
 		list_splice_tail(&requeue_queue, &device->ccw_queue);
 		spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	}
-	/* wake up generic waitqueue for eventually ended sleepon requests */
-	wake_up(&generic_waitq);
+	dasd_schedule_device_bh(device);
 	return rc;
 }
 
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index a2b33a22c82a..d049e2d74484 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -23,7 +23,7 @@ CFLAGS_REMOVE_sclp_early_core.o	+= $(CC_FLAGS_EXPOLINE)
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
 	 sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
-	 sclp_early.o sclp_early_core.o
+	 sclp_early.o sclp_early_core.o sclp_sd.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index f41f6e2ca063..9b10f12d3f53 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -28,6 +28,7 @@
 #define EVTYP_PMSGCMD		0x09
 #define EVTYP_ASYNC		0x0A
 #define EVTYP_CTLPROGIDENT	0x0B
+#define EVTYP_STORE_DATA	0x0C
 #define EVTYP_ERRNOTIFY		0x18
 #define EVTYP_VT220MSG		0x1A
 #define EVTYP_SDIAS		0x1C
@@ -42,6 +43,7 @@
 #define EVTYP_PMSGCMD_MASK	SCLP_EVTYP_MASK(EVTYP_PMSGCMD)
 #define EVTYP_ASYNC_MASK	SCLP_EVTYP_MASK(EVTYP_ASYNC)
 #define EVTYP_CTLPROGIDENT_MASK	SCLP_EVTYP_MASK(EVTYP_CTLPROGIDENT)
+#define EVTYP_STORE_DATA_MASK	SCLP_EVTYP_MASK(EVTYP_STORE_DATA)
 #define EVTYP_ERRNOTIFY_MASK	SCLP_EVTYP_MASK(EVTYP_ERRNOTIFY)
 #define EVTYP_VT220MSG_MASK	SCLP_EVTYP_MASK(EVTYP_VT220MSG)
 #define EVTYP_SDIAS_MASK	SCLP_EVTYP_MASK(EVTYP_SDIAS)
diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c
new file mode 100644
index 000000000000..99f41db5123b
--- /dev/null
+++ b/drivers/s390/char/sclp_sd.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCLP Store Data support and sysfs interface
+ *
+ * Copyright IBM Corp. 2017
+ */
+
+#define KMSG_COMPONENT "sclp_sd"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/completion.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/async.h>
+#include <linux/export.h>
+#include <linux/mutex.h>
+
+#include <asm/pgalloc.h>
+
+#include "sclp.h"
+
+#define SD_EQ_STORE_DATA	0
+#define SD_EQ_HALT		1
+#define SD_EQ_SIZE		2
+
+#define SD_DI_CONFIG		3
+
+struct sclp_sd_evbuf {
+	struct evbuf_header hdr;
+	u8 eq;
+	u8 di;
+	u8 rflags;
+	u64 :56;
+	u32 id;
+	u16 :16;
+	u8 fmt;
+	u8 status;
+	u64 sat;
+	u64 sa;
+	u32 esize;
+	u32 dsize;
+} __packed;
+
+struct sclp_sd_sccb {
+	struct sccb_header hdr;
+	struct sclp_sd_evbuf evbuf;
+} __packed __aligned(PAGE_SIZE);
+
+/**
+ * struct sclp_sd_data - Result of a Store Data request
+ * @esize_bytes: Resulting esize in bytes
+ * @dsize_bytes: Resulting dsize in bytes
+ * @data: Pointer to data - must be released using vfree()
+ */
+struct sclp_sd_data {
+	size_t esize_bytes;
+	size_t dsize_bytes;
+	void *data;
+};
+
+/**
+ * struct sclp_sd_listener - Listener for asynchronous Store Data response
+ * @list: For enqueueing this struct
+ * @id: Event ID of response to listen for
+ * @completion: Can be used to wait for response
+ * @evbuf: Contains the resulting Store Data response after completion
+ */
+struct sclp_sd_listener {
+	struct list_head list;
+	u32 id;
+	struct completion completion;
+	struct sclp_sd_evbuf evbuf;
+};
+
+/**
+ * struct sclp_sd_file - Sysfs representation of a Store Data entity
+ * @kobj: Kobject
+ * @data_attr: Attribute for accessing data contents
+ * @data_mutex: Mutex to serialize access and updates to @data
+ * @data: Data associated with this entity
+ * @di: DI value associated with this entity
+ */
+struct sclp_sd_file {
+	struct kobject kobj;
+	struct bin_attribute data_attr;
+	struct mutex data_mutex;
+	struct sclp_sd_data data;
+	u8 di;
+};
+#define to_sd_file(x) container_of(x, struct sclp_sd_file, kobj)
+
+static struct kset *sclp_sd_kset;
+static struct sclp_sd_file *config_file;
+
+static LIST_HEAD(sclp_sd_queue);
+static DEFINE_SPINLOCK(sclp_sd_queue_lock);
+
+/**
+ * sclp_sd_listener_add() - Add listener for Store Data responses
+ * @listener: Listener to add
+ */
+static void sclp_sd_listener_add(struct sclp_sd_listener *listener)
+{
+	spin_lock_irq(&sclp_sd_queue_lock);
+	list_add_tail(&listener->list, &sclp_sd_queue);
+	spin_unlock_irq(&sclp_sd_queue_lock);
+}
+
+/**
+ * sclp_sd_listener_remove() - Remove listener for Store Data responses
+ * @listener: Listener to remove
+ */
+static void sclp_sd_listener_remove(struct sclp_sd_listener *listener)
+{
+	spin_lock_irq(&sclp_sd_queue_lock);
+	list_del(&listener->list);
+	spin_unlock_irq(&sclp_sd_queue_lock);
+}
+
+/**
+ * sclp_sd_listener_init() - Initialize a Store Data response listener
+ * @id: Event ID to listen for
+ *
+ * Initialize a listener for asynchronous Store Data responses. This listener
+ * can afterwards be used to wait for a specific response and to retrieve
+ * the associated response data.
+ */
+static void sclp_sd_listener_init(struct sclp_sd_listener *listener, u32 id)
+{
+	memset(listener, 0, sizeof(*listener));
+	listener->id = id;
+	init_completion(&listener->completion);
+}
+
+/**
+ * sclp_sd_receiver() - Receiver for Store Data events
+ * @evbuf_hdr: Header of received events
+ *
+ * Process Store Data events and complete listeners with matching event IDs.
+ */
+static void sclp_sd_receiver(struct evbuf_header *evbuf_hdr)
+{
+	struct sclp_sd_evbuf *evbuf = (struct sclp_sd_evbuf *) evbuf_hdr;
+	struct sclp_sd_listener *listener;
+	int found = 0;
+
+	pr_debug("received event (id=0x%08x)\n", evbuf->id);
+	spin_lock(&sclp_sd_queue_lock);
+	list_for_each_entry(listener, &sclp_sd_queue, list) {
+		if (listener->id != evbuf->id)
+			continue;
+
+		listener->evbuf = *evbuf;
+		complete(&listener->completion);
+		found = 1;
+		break;
+	}
+	spin_unlock(&sclp_sd_queue_lock);
+
+	if (!found)
+		pr_debug("unsolicited event (id=0x%08x)\n", evbuf->id);
+}
+
+static struct sclp_register sclp_sd_register = {
+	.send_mask = EVTYP_STORE_DATA_MASK,
+	.receive_mask = EVTYP_STORE_DATA_MASK,
+	.receiver_fn = sclp_sd_receiver,
+};
+
+/**
+ * sclp_sd_sync() - Perform Store Data request synchronously
+ * @page: Address of work page - must be below 2GB
+ * @eq: Input EQ value
+ * @di: Input DI value
+ * @sat: Input SAT value
+ * @sa: Input SA value used to specify the address of the target buffer
+ * @dsize_ptr: Optional pointer to input and output DSIZE value
+ * @esize_ptr: Optional pointer to output ESIZE value
+ *
+ * Perform Store Data request with specified parameters and wait for completion.
+ *
+ * Return %0 on success and store resulting DSIZE and ESIZE values in
+ * @dsize_ptr and @esize_ptr (if provided). Return non-zero on error.
+ */
+static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa,
+			u32 *dsize_ptr, u32 *esize_ptr)
+{
+	struct sclp_sd_sccb *sccb = (void *) page;
+	struct sclp_sd_listener listener;
+	struct sclp_sd_evbuf *evbuf;
+	int rc;
+
+	sclp_sd_listener_init(&listener, (u32) (addr_t) sccb);
+	sclp_sd_listener_add(&listener);
+
+	/* Prepare SCCB */
+	memset(sccb, 0, PAGE_SIZE);
+	sccb->hdr.length = sizeof(sccb->hdr) + sizeof(sccb->evbuf);
+	evbuf = &sccb->evbuf;
+	evbuf->hdr.length = sizeof(*evbuf);
+	evbuf->hdr.type = EVTYP_STORE_DATA;
+	evbuf->eq = eq;
+	evbuf->di = di;
+	evbuf->id = listener.id;
+	evbuf->fmt = 1;
+	evbuf->sat = sat;
+	evbuf->sa = sa;
+	if (dsize_ptr)
+		evbuf->dsize = *dsize_ptr;
+
+	/* Perform command */
+	pr_debug("request (eq=%d, di=%d, id=0x%08x)\n", eq, di, listener.id);
+	rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
+	pr_debug("request done (rc=%d)\n", rc);
+	if (rc)
+		goto out;
+
+	/* Evaluate response */
+	if (sccb->hdr.response_code == 0x73f0) {
+		pr_debug("event not supported\n");
+		rc = -EIO;
+		goto out_remove;
+	}
+	if (sccb->hdr.response_code != 0x0020 || !(evbuf->hdr.flags & 0x80)) {
+		rc = -EIO;
+		goto out;
+	}
+	if (!(evbuf->rflags & 0x80)) {
+		rc = wait_for_completion_interruptible(&listener.completion);
+		if (rc)
+			goto out;
+		evbuf = &listener.evbuf;
+	}
+	switch (evbuf->status) {
+	case 0:
+		if (dsize_ptr)
+			*dsize_ptr = evbuf->dsize;
+		if (esize_ptr)
+			*esize_ptr = evbuf->esize;
+		pr_debug("success (dsize=%u, esize=%u)\n", evbuf->dsize,
+			 evbuf->esize);
+		break;
+	case 3:
+		rc = -ENOENT;
+		break;
+	default:
+		rc = -EIO;
+		break;
+
+	}
+
+out:
+	if (rc && rc != -ENOENT) {
+		/* Provide some information about what went wrong */
+		pr_warn("Store Data request failed (eq=%d, di=%d, "
+			"response=0x%04x, flags=0x%02x, status=%d, rc=%d)\n",
+			eq, di, sccb->hdr.response_code, evbuf->hdr.flags,
+			evbuf->status, rc);
+	}
+
+out_remove:
+	sclp_sd_listener_remove(&listener);
+
+	return rc;
+}
+
+/**
+ * sclp_sd_store_data() - Obtain data for specified Store Data entity
+ * @result: Resulting data
+ * @di: DI value associated with this entity
+ *
+ * Perform a series of Store Data requests to obtain the size and contents of
+ * the specified Store Data entity.
+ *
+ * Return:
+ *   %0:       Success - result is stored in @result. @result->data must be
+ *	       released using vfree() after use.
+ *   %-ENOENT: No data available for this entity
+ *   %<0:      Other error
+ */
+static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di)
+{
+	u32 dsize = 0, esize = 0;
+	unsigned long page, asce = 0;
+	void *data = NULL;
+	int rc;
+
+	page = __get_free_page(GFP_KERNEL | GFP_DMA);
+	if (!page)
+		return -ENOMEM;
+
+	/* Get size */
+	rc = sclp_sd_sync(page, SD_EQ_SIZE, di, 0, 0, &dsize, &esize);
+	if (rc)
+		goto out;
+	if (dsize == 0)
+		goto out_result;
+
+	/* Allocate memory */
+	data = vzalloc((size_t) dsize * PAGE_SIZE);
+	if (!data) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Get translation table for buffer */
+	asce = base_asce_alloc((unsigned long) data, dsize);
+	if (!asce) {
+		vfree(data);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Get data */
+	rc = sclp_sd_sync(page, SD_EQ_STORE_DATA, di, asce, (u64) data, &dsize,
+			  &esize);
+	if (rc) {
+		/* Cancel running request if interrupted */
+		if (rc == -ERESTARTSYS)
+			sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL);
+		vfree(data);
+		goto out;
+	}
+
+out_result:
+	result->esize_bytes = (size_t) esize * PAGE_SIZE;
+	result->dsize_bytes = (size_t) dsize * PAGE_SIZE;
+	result->data = data;
+
+out:
+	base_asce_free(asce);
+	free_page(page);
+
+	return rc;
+}
+
+/**
+ * sclp_sd_data_reset() - Reset Store Data result buffer
+ * @data: Data buffer to reset
+ *
+ * Reset @data to initial state and release associated memory.
+ */
+static void sclp_sd_data_reset(struct sclp_sd_data *data)
+{
+	vfree(data->data);
+	data->data = NULL;
+	data->dsize_bytes = 0;
+	data->esize_bytes = 0;
+}
+
+/**
+ * sclp_sd_file_release() - Release function for sclp_sd_file object
+ * @kobj: Kobject embedded in sclp_sd_file object
+ */
+static void sclp_sd_file_release(struct kobject *kobj)
+{
+	struct sclp_sd_file *sd_file = to_sd_file(kobj);
+
+	sclp_sd_data_reset(&sd_file->data);
+	kfree(sd_file);
+}
+
+/**
+ * sclp_sd_file_update() - Update contents of sclp_sd_file object
+ * @sd_file: Object to update
+ *
+ * Obtain the current version of data associated with the Store Data entity
+ * @sd_file.
+ *
+ * On success, return %0 and generate a KOBJ_CHANGE event to indicate that the
+ * data may have changed. Return non-zero otherwise.
+ */
+static int sclp_sd_file_update(struct sclp_sd_file *sd_file)
+{
+	const char *name = kobject_name(&sd_file->kobj);
+	struct sclp_sd_data data;
+	int rc;
+
+	rc = sclp_sd_store_data(&data, sd_file->di);
+	if (rc) {
+		if (rc == -ENOENT) {
+			pr_info("No data is available for the %s data entity\n",
+				 name);
+		}
+		return rc;
+	}
+
+	mutex_lock(&sd_file->data_mutex);
+	sclp_sd_data_reset(&sd_file->data);
+	sd_file->data = data;
+	mutex_unlock(&sd_file->data_mutex);
+
+	pr_info("A %zu-byte %s data entity was retrieved\n", data.dsize_bytes,
+		name);
+	kobject_uevent(&sd_file->kobj, KOBJ_CHANGE);
+
+	return 0;
+}
+
+/**
+ * sclp_sd_file_update_async() - Wrapper for asynchronous update call
+ * @data: Object to update
+ */
+static void sclp_sd_file_update_async(void *data, async_cookie_t cookie)
+{
+	struct sclp_sd_file *sd_file = data;
+
+	sclp_sd_file_update(sd_file);
+}
+
+/**
+ * reload_store() - Store function for "reload" sysfs attribute
+ * @kobj: Kobject of sclp_sd_file object
+ *
+ * Initiate a reload of the data associated with an sclp_sd_file object.
+ */
+static ssize_t reload_store(struct kobject *kobj, struct kobj_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct sclp_sd_file *sd_file = to_sd_file(kobj);
+
+	sclp_sd_file_update(sd_file);
+
+	return count;
+}
+
+static struct kobj_attribute reload_attr = __ATTR_WO(reload);
+
+static struct attribute *sclp_sd_file_default_attrs[] = {
+	&reload_attr.attr,
+	NULL,
+};
+
+static struct kobj_type sclp_sd_file_ktype = {
+	.sysfs_ops = &kobj_sysfs_ops,
+	.release = sclp_sd_file_release,
+	.default_attrs = sclp_sd_file_default_attrs,
+};
+
+/**
+ * data_read() - Read function for "read" sysfs attribute
+ * @kobj: Kobject of sclp_sd_file object
+ * @buffer: Target buffer
+ * @off: Requested file offset
+ * @size: Requested number of bytes
+ *
+ * Store the requested portion of the Store Data entity contents into the
+ * specified buffer. Return the number of bytes stored on success, or %0
+ * on EOF.
+ */
+static ssize_t data_read(struct file *file, struct kobject *kobj,
+			 struct bin_attribute *attr, char *buffer,
+			 loff_t off, size_t size)
+{
+	struct sclp_sd_file *sd_file = to_sd_file(kobj);
+	size_t data_size;
+	char *data;
+
+	mutex_lock(&sd_file->data_mutex);
+
+	data = sd_file->data.data;
+	data_size = sd_file->data.dsize_bytes;
+	if (!data || off >= data_size) {
+		size = 0;
+	} else {
+		if (off + size > data_size)
+			size = data_size - off;
+		memcpy(buffer, data + off, size);
+	}
+
+	mutex_unlock(&sd_file->data_mutex);
+
+	return size;
+}
+
+/**
+ * sclp_sd_file_create() - Add a sysfs file representing a Store Data entity
+ * @name: Name of file
+ * @di: DI value associated with this entity
+ *
+ * Create a sysfs directory with the given @name located under
+ *
+ *   /sys/firmware/sclp_sd/
+ *
+ * The files in this directory can be used to access the contents of the Store
+ * Data entity associated with @DI.
+ *
+ * Return pointer to resulting sclp_sd_file object on success, %NULL otherwise.
+ * The object must be freed by calling kobject_put() on the embedded kobject
+ * pointer after use.
+ */
+static __init struct sclp_sd_file *sclp_sd_file_create(const char *name, u8 di)
+{
+	struct sclp_sd_file *sd_file;
+	int rc;
+
+	sd_file = kzalloc(sizeof(*sd_file), GFP_KERNEL);
+	if (!sd_file)
+		return NULL;
+	sd_file->di = di;
+	mutex_init(&sd_file->data_mutex);
+
+	/* Create kobject located under /sys/firmware/sclp_sd/ */
+	sd_file->kobj.kset = sclp_sd_kset;
+	rc = kobject_init_and_add(&sd_file->kobj, &sclp_sd_file_ktype, NULL,
+				  "%s", name);
+	if (rc) {
+		kobject_put(&sd_file->kobj);
+		return NULL;
+	}
+
+	sysfs_bin_attr_init(&sd_file->data_attr);
+	sd_file->data_attr.attr.name = "data";
+	sd_file->data_attr.attr.mode = 0444;
+	sd_file->data_attr.read = data_read;
+
+	rc = sysfs_create_bin_file(&sd_file->kobj, &sd_file->data_attr);
+	if (rc) {
+		kobject_put(&sd_file->kobj);
+		return NULL;
+	}
+
+	/*
+	 * For completeness only - users interested in entity data should listen
+	 * for KOBJ_CHANGE instead.
+	 */
+	kobject_uevent(&sd_file->kobj, KOBJ_ADD);
+
+	/* Don't let a slow Store Data request delay further initialization */
+	async_schedule(sclp_sd_file_update_async, sd_file);
+
+	return sd_file;
+}
+
+/**
+ * sclp_sd_init() - Initialize sclp_sd support and register sysfs files
+ */
+static __init int sclp_sd_init(void)
+{
+	int rc;
+
+	rc = sclp_register(&sclp_sd_register);
+	if (rc)
+		return rc;
+
+	/* Create kset named "sclp_sd" located under /sys/firmware/ */
+	rc = -ENOMEM;
+	sclp_sd_kset = kset_create_and_add("sclp_sd", NULL, firmware_kobj);
+	if (!sclp_sd_kset)
+		goto err_kset;
+
+	rc = -EINVAL;
+	config_file = sclp_sd_file_create("config", SD_DI_CONFIG);
+	if (!config_file)
+		goto err_config;
+
+	return 0;
+
+err_config:
+	kset_unregister(sclp_sd_kset);
+err_kset:
+	sclp_unregister(&sclp_sd_register);
+
+	return rc;
+}
+device_initcall(sclp_sd_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8a739b74cfb7..8647ca9199b3 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1059,6 +1059,7 @@ config SCSI_IPR
 	depends on PCI && SCSI && ATA
 	select FW_LOADER
 	select IRQ_POLL
+	select SGL_ALLOC
 	---help---
 	  This driver supports the IBM Power Linux family RAID adapters.
 	  This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
@@ -1576,6 +1577,7 @@ config ZFCP
 config SCSI_PMCRAID
 	tristate "PMC SIERRA Linux MaxRAID adapter support"
 	depends on PCI && SCSI && NET
+	select SGL_ALLOC
 	---help---
 	  This driver supports the PMC SIERRA MaxRAID adapters.
 
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index fcfd28d2884c..de1b3fce936d 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -185,7 +185,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 CFLAGS_ncr53c8xx.o	:= $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
 zalon7xx-objs	:= zalon.o ncr53c8xx.o
 NCR_Q720_mod-objs	:= NCR_Q720.o ncr53c8xx.o
-oktagon_esp_mod-objs	:= oktagon_esp.o oktagon_io.o
 
 # Files generated that shall be removed upon make clean
 clean-files :=	53c700_d.h 53c700_u.h
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 6e110c630d2c..44b09870bf51 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -448,7 +448,7 @@ static __inline__ int NCR53c406a_pio_write(unsigned char *request, unsigned int
 }
 #endif				/* USE_PIO */
 
-static int __init NCR53c406a_detect(struct scsi_host_template * tpnt)
+static int NCR53c406a_detect(struct scsi_host_template * tpnt)
 {
 	int present = 0;
 	struct Scsi_Host *shpnt = NULL;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 0095fcbd1c88..29bf1e60f542 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1231,6 +1231,7 @@ struct src_registers {
 
 #define SRC_ODR_SHIFT		12
 #define SRC_IDR_SHIFT		9
+#define SRC_MSI_READ_MASK	0x1000
 
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 
@@ -1528,6 +1529,7 @@ struct aac_bus_info_response {
 #define AAC_COMM_MESSAGE_TYPE3		5
 
 #define AAC_EXTOPT_SA_FIRMWARE		cpu_to_le32(1<<1)
+#define AAC_EXTOPT_SOFT_RESET		cpu_to_le32(1<<16)
 
 /* MSIX context */
 struct aac_msix_ctx {
@@ -1662,6 +1664,7 @@ struct aac_dev
 	u8			raw_io_64;
 	u8			printf_enabled;
 	u8			in_reset;
+	u8			in_soft_reset;
 	u8			msi;
 	u8			sa_firmware;
 	int			management_fib_count;
@@ -2504,6 +2507,7 @@ struct aac_hba_info {
 #define RCV_TEMP_READINGS		0x00000025
 #define GET_COMM_PREFERRED_SETTINGS	0x00000026
 #define IOP_RESET_FW_FIB_DUMP		0x00000034
+#define DROP_IO			0x00000035
 #define IOP_RESET			0x00001000
 #define IOP_RESET_ALWAYS		0x00001001
 #define RE_INIT_ADAPTER		0x000000ee
@@ -2539,6 +2543,7 @@ struct aac_hba_info {
 #define	FLASH_UPD_PENDING		0x00002000
 #define	FLASH_UPD_SUCCESS		0x00004000
 #define	FLASH_UPD_FAILED		0x00008000
+#define	INVALID_OMR			0xffffffff
 #define	FWUPD_TIMEOUT			(5 * 60)
 
 /*
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index b3b931ab77eb..2664ea0df35f 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1693,8 +1693,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	 *	Map in the registers from the adapter.
 	 */
 	aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
-	if ((*aac_drivers[index].init)(aac))
+	if ((*aac_drivers[index].init)(aac)) {
+		error = -ENODEV;
 		goto out_unmap;
+	}
 
 	if (aac->sync_mode) {
 		if (aac_sync_mode)
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index fde6b6aa86e3..3122389f380f 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -255,7 +255,8 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
 	 */
 	src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
 
-	if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) {
+	if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) &&
+		!dev->in_soft_reset) {
 		ok = 0;
 		start = jiffies;
 
@@ -679,6 +680,25 @@ void aac_set_intx_mode(struct aac_dev *dev)
 	}
 }
 
+static void aac_clear_omr(struct aac_dev *dev)
+{
+	u32 omr_value = 0;
+
+	omr_value = src_readl(dev, MUnit.OMR);
+
+	/*
+	 * Check for PCI Errors or Kernel Panic
+	 */
+	if ((omr_value == INVALID_OMR) || (omr_value & KERNEL_PANIC))
+		omr_value = 0;
+
+	/*
+	 * Preserve MSIX Value if any
+	 */
+	src_writel(dev, MUnit.OMR, omr_value & AAC_INT_MODE_MSIX);
+	src_readl(dev, MUnit.OMR);
+}
+
 static void aac_dump_fw_fib_iop_reset(struct aac_dev *dev)
 {
 	__le32 supported_options3;
@@ -739,6 +759,8 @@ static void aac_send_iop_reset(struct aac_dev *dev)
 
 	aac_set_intx_mode(dev);
 
+	aac_clear_omr(dev);
+
 	src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK);
 
 	msleep(5000);
@@ -748,6 +770,7 @@ static void aac_send_hardware_soft_reset(struct aac_dev *dev)
 {
 	u_int32_t val;
 
+	aac_clear_omr(dev);
 	val = readl(((char *)(dev->base) + IBW_SWR_OFFSET));
 	val |= 0x01;
 	writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET));
@@ -992,6 +1015,148 @@ int aac_src_init(struct aac_dev *dev)
 	return -1;
 }
 
+static int aac_src_wait_sync(struct aac_dev *dev, int *status)
+{
+	unsigned long start = jiffies;
+	unsigned long usecs = 0;
+	int delay = 5 * HZ;
+	int rc = 1;
+
+	while (time_before(jiffies, start+delay)) {
+		/*
+		 * Delay 5 microseconds to let Mon960 get info.
+		 */
+		udelay(5);
+
+		/*
+		 * Mon960 will set doorbell0 bit when it has completed the
+		 * command.
+		 */
+		if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) {
+			/*
+			 * Clear: the doorbell.
+			 */
+			if (dev->msi_enabled)
+				aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT);
+			else
+				src_writel(dev, MUnit.ODR_C,
+					OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+			rc = 0;
+
+			break;
+		}
+
+		/*
+		 * Yield the processor in case we are slow
+		 */
+		usecs = 1 * USEC_PER_MSEC;
+		usleep_range(usecs, usecs + 50);
+	}
+	/*
+	 * Pull the synch status from Mailbox 0.
+	 */
+	if (status && !rc) {
+		status[0] = readl(&dev->IndexRegs->Mailbox[0]);
+		status[1] = readl(&dev->IndexRegs->Mailbox[1]);
+		status[2] = readl(&dev->IndexRegs->Mailbox[2]);
+		status[3] = readl(&dev->IndexRegs->Mailbox[3]);
+		status[4] = readl(&dev->IndexRegs->Mailbox[4]);
+	}
+
+	return rc;
+}
+
+/**
+ *  aac_src_soft_reset	-	perform soft reset to speed up
+ *  access
+ *
+ *  Assumptions: That the controller is in a state where we can
+ *  bring it back to life with an init struct. We can only use
+ *  fast sync commands, as the timeout is 5 seconds.
+ *
+ *  @dev: device to configure
+ *
+ */
+
+static int aac_src_soft_reset(struct aac_dev *dev)
+{
+	u32 status_omr = src_readl(dev, MUnit.OMR);
+	u32 status[5];
+	int rc = 1;
+	int state = 0;
+	char *state_str[7] = {
+		"GET_ADAPTER_PROPERTIES Failed",
+		"GET_ADAPTER_PROPERTIES timeout",
+		"SOFT_RESET not supported",
+		"DROP_IO Failed",
+		"DROP_IO timeout",
+		"Check Health failed"
+	};
+
+	if (status_omr == INVALID_OMR)
+		return 1;       // pcie hosed
+
+	if (!(status_omr & KERNEL_UP_AND_RUNNING))
+		return 1;       // not up and running
+
+	/*
+	 * We go into soft reset mode to allow us to handle response
+	 */
+	dev->in_soft_reset = 1;
+	dev->msi_enabled = status_omr & AAC_INT_MODE_MSIX;
+
+	/* Get adapter properties */
+	rc = aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0,
+		0, 0, 0, status+0, status+1, status+2, status+3, status+4);
+	if (rc)
+		goto out;
+
+	state++;
+	if (aac_src_wait_sync(dev, status)) {
+		rc = 1;
+		goto out;
+	}
+
+	state++;
+	if (!(status[1] & le32_to_cpu(AAC_OPT_EXTENDED) &&
+		(status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)))) {
+		rc = 2;
+		goto out;
+	}
+
+	if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) &&
+		(status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE)))
+		dev->sa_firmware = 1;
+
+	state++;
+	rc = aac_adapter_sync_cmd(dev, DROP_IO, 0, 0, 0, 0, 0, 0,
+		 status+0, status+1, status+2, status+3, status+4);
+
+	if (rc)
+		goto out;
+
+	state++;
+	if (aac_src_wait_sync(dev, status)) {
+		rc = 3;
+		goto out;
+	}
+
+	if (status[1])
+		dev_err(&dev->pdev->dev, "%s: %d outstanding I/O pending\n",
+			__func__, status[1]);
+
+	state++;
+	rc = aac_src_check_health(dev);
+
+out:
+	dev->in_soft_reset = 0;
+	dev->msi_enabled = 0;
+	if (rc)
+		dev_err(&dev->pdev->dev, "%s: %s status = %d", __func__,
+			state_str[state], rc);
+
+return rc;
+}
 /**
  *  aac_srcv_init	-	initialize an SRCv card
  *  @dev: device to configure
@@ -1021,8 +1186,10 @@ int aac_srcv_init(struct aac_dev *dev)
 
 	if (dev->init_reset) {
 		dev->init_reset = false;
-		if (!aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET))
+		if (aac_src_soft_reset(dev)) {
+			aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET);
 			++restart;
+		}
 	}
 
 	/*
@@ -1072,13 +1239,16 @@ int aac_srcv_init(struct aac_dev *dev)
 		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
 		goto error_iounmap;
 	}
+
 	start = jiffies;
 	/*
 	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
 	 */
-	while (!((status = src_readl(dev, MUnit.OMR)) &
-		KERNEL_UP_AND_RUNNING) ||
-		status == 0xffffffff) {
+	do {
+		status = src_readl(dev, MUnit.OMR);
+		if (status == INVALID_OMR)
+			status = 0;
+
 		if ((restart &&
 		  (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
 		  time_after(jiffies, start+HZ*startup_timeout)) {
@@ -1098,7 +1268,8 @@ int aac_srcv_init(struct aac_dev *dev)
 			++restart;
 		}
 		msleep(1);
-	}
+	} while (!(status & KERNEL_UP_AND_RUNNING));
+
 	if (restart && aac_commit)
 		aac_commit = 1;
 	/*
@@ -1234,13 +1405,23 @@ void aac_src_access_devreg(struct aac_dev *dev, int mode)
 
 static int aac_src_get_sync_status(struct aac_dev *dev)
 {
+	int msix_val = 0;
+	int legacy_val = 0;
 
-	int val;
+	msix_val = src_readl(dev, MUnit.ODR_MSI) & SRC_MSI_READ_MASK ? 1 : 0;
 
-	if (dev->msi_enabled)
-		val = src_readl(dev, MUnit.ODR_MSI) & 0x1000 ? 1 : 0;
-	else
-		val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT;
+	if (!dev->msi_enabled) {
+		/*
+		 * if Legacy int status indicates cmd is not complete
+		 * sample MSIx register to see if it indiactes cmd complete,
+		 * if yes set the controller in MSIx mode and consider cmd
+		 * completed
+		 */
+		legacy_val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT;
+		if (!(legacy_val & 1) && msix_val)
+			dev->msi_enabled = 1;
+		return legacy_val;
+	}
 
-	return val;
+	return msix_val;
 }
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
deleted file mode 100644
index 828ae3d9a510..000000000000
--- a/drivers/scsi/aic7xxx/aiclib.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Implementation of Utility functions for all SCSI device types.
- *
- * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
- * Copyright (c) 1997, 1998 Kenneth D. Merry.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $
- * $Id$
- */
-
-#include "aiclib.h"
-
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 8e2f767147cb..5a645b8b9af1 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1889,6 +1889,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
 		/* we will not receive ABTS response for this IO */
 		BNX2FC_IO_DBG(io_req, "Timer context finished processing "
 			   "this scsi cmd\n");
+		return;
 	}
 
 	/* Cancel the timeout_work, as we received IO completion */
diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
index be5ee2d37815..7dbbbb81a1e7 100644
--- a/drivers/scsi/csiostor/csio_lnode.c
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -114,7 +114,7 @@ static enum csio_ln_ev fwevt_to_lnevt[] = {
 static struct csio_lnode *
 csio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid)
 {
-	struct csio_lnode *ln = hw->rln;
+	struct csio_lnode *ln;
 	struct list_head *tmp;
 
 	/* Match siblings lnode with portid */
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 022e421c2185..4b44325d1a82 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -876,6 +876,11 @@ static void alua_rtpg_work(struct work_struct *work)
 
 /**
  * alua_rtpg_queue() - cause RTPG to be submitted asynchronously
+ * @pg: ALUA port group associated with @sdev.
+ * @sdev: SCSI device for which to submit an RTPG.
+ * @qdata: Information about the callback to invoke after the RTPG.
+ * @force: Whether or not to submit an RTPG if a work item that will submit an
+ *         RTPG already has been scheduled.
  *
  * Returns true if and only if alua_rtpg_work() will be called asynchronously.
  * That function is responsible for calling @qdata->fn().
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 57bf43e34863..a0a7e4ff255c 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -42,6 +42,12 @@
 #include "scsi_logging.h"
 
 
+static int shost_eh_deadline = -1;
+
+module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(eh_deadline,
+		 "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
+
 static DEFINE_IDA(host_index_ida);
 
 
@@ -358,12 +364,6 @@ static void scsi_host_dev_release(struct device *dev)
 	kfree(shost);
 }
 
-static int shost_eh_deadline = -1;
-
-module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(eh_deadline,
-		 "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
-
 static struct device_type scsi_host_type = {
 	.name =		"scsi_host",
 	.release =	scsi_host_dev_release,
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 9a0696f68f37..b81a53c4a9a8 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -367,7 +367,7 @@ enum ibmvfc_fcp_rsp_info_codes {
 };
 
 struct ibmvfc_fcp_rsp_info {
-	__be16 reserved;
+	u8 reserved[3];
 	u8 rsp_code;
 	u8 reserved2[4];
 }__attribute__((packed, aligned (2)));
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index e07dd990e585..52735162444f 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3816,10 +3816,8 @@ static struct device_attribute ipr_iopoll_weight_attr = {
  **/
 static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
 {
-	int sg_size, order, bsize_elem, num_elem, i, j;
+	int sg_size, order;
 	struct ipr_sglist *sglist;
-	struct scatterlist *scatterlist;
-	struct page *page;
 
 	/* Get the minimum size per scatter/gather element */
 	sg_size = buf_len / (IPR_MAX_SGLIST - 1);
@@ -3827,45 +3825,18 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
 	/* Get the actual size per element */
 	order = get_order(sg_size);
 
-	/* Determine the actual number of bytes per element */
-	bsize_elem = PAGE_SIZE * (1 << order);
-
-	/* Determine the actual number of sg entries needed */
-	if (buf_len % bsize_elem)
-		num_elem = (buf_len / bsize_elem) + 1;
-	else
-		num_elem = buf_len / bsize_elem;
-
 	/* Allocate a scatter/gather list for the DMA */
-	sglist = kzalloc(sizeof(struct ipr_sglist) +
-			 (sizeof(struct scatterlist) * (num_elem - 1)),
-			 GFP_KERNEL);
-
+	sglist = kzalloc(sizeof(struct ipr_sglist), GFP_KERNEL);
 	if (sglist == NULL) {
 		ipr_trace;
 		return NULL;
 	}
-
-	scatterlist = sglist->scatterlist;
-	sg_init_table(scatterlist, num_elem);
-
 	sglist->order = order;
-	sglist->num_sg = num_elem;
-
-	/* Allocate a bunch of sg elements */
-	for (i = 0; i < num_elem; i++) {
-		page = alloc_pages(GFP_KERNEL, order);
-		if (!page) {
-			ipr_trace;
-
-			/* Free up what we already allocated */
-			for (j = i - 1; j >= 0; j--)
-				__free_pages(sg_page(&scatterlist[j]), order);
-			kfree(sglist);
-			return NULL;
-		}
-
-		sg_set_page(&scatterlist[i], page, 0, 0);
+	sglist->scatterlist = sgl_alloc_order(buf_len, order, false, GFP_KERNEL,
+					      &sglist->num_sg);
+	if (!sglist->scatterlist) {
+		kfree(sglist);
+		return NULL;
 	}
 
 	return sglist;
@@ -3883,11 +3854,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
  **/
 static void ipr_free_ucode_buffer(struct ipr_sglist *sglist)
 {
-	int i;
-
-	for (i = 0; i < sglist->num_sg; i++)
-		__free_pages(sg_page(&sglist->scatterlist[i]), sglist->order);
-
+	sgl_free_order(sglist->scatterlist, sglist->order);
 	kfree(sglist);
 }
 
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index c7f0e9e3cd7d..93570734cbfb 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -1454,7 +1454,7 @@ struct ipr_sglist {
 	u32 num_sg;
 	u32 num_dma_sg;
 	u32 buffer_len;
-	struct scatterlist scatterlist[1];
+	struct scatterlist *scatterlist;
 };
 
 enum ipr_sdt_state {
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 13b37cdffa8e..1ee3868ade07 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -2766,7 +2766,7 @@ static int sci_write_gpio_tx_gp(struct isci_host *ihost, u8 reg_index, u8 reg_co
 		int i;
 
 		for (i = 0; i < 3; i++) {
-			int bit = (i << 2) + 2;
+			int bit;
 
 			bit = try_test_sas_gpio_gp_bit(to_sas_gpio_od(d, i),
 						       write_data, reg_index,
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 6198559abbd8..0ad00dbf912d 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -732,7 +732,7 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
 	struct sockaddr_in6 addr;
-	int rc, len;
+	int rc;
 
 	switch(param) {
 	case ISCSI_PARAM_CONN_PORT:
@@ -745,12 +745,12 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
 		}
 		if (param == ISCSI_PARAM_LOCAL_PORT)
 			rc = kernel_getsockname(tcp_sw_conn->sock,
-						(struct sockaddr *)&addr, &len);
+						(struct sockaddr *)&addr);
 		else
 			rc = kernel_getpeername(tcp_sw_conn->sock,
-						(struct sockaddr *)&addr, &len);
+						(struct sockaddr *)&addr);
 		spin_unlock_bh(&conn->session->frwd_lock);
-		if (rc)
+		if (rc < 0)
 			return rc;
 
 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
@@ -771,7 +771,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
 	struct iscsi_tcp_conn *tcp_conn;
 	struct iscsi_sw_tcp_conn *tcp_sw_conn;
 	struct sockaddr_in6 addr;
-	int rc, len;
+	int rc;
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_IPADDRESS:
@@ -793,9 +793,9 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
 		}
 
 		rc = kernel_getsockname(tcp_sw_conn->sock,
-					(struct sockaddr *)&addr, &len);
+					(struct sockaddr *)&addr);
 		spin_unlock_bh(&session->frwd_lock);
-		if (rc)
+		if (rc < 0)
 			return rc;
 
 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 8660f923ace0..3f3569ec5ce3 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -731,7 +731,7 @@ static void fc_disc_stop_final(struct fc_lport *lport)
  */
 void fc_disc_config(struct fc_lport *lport, void *priv)
 {
-	struct fc_disc *disc = &lport->disc;
+	struct fc_disc *disc;
 
 	if (!lport->tt.disc_start)
 		lport->tt.disc_start = fc_disc_start;
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 61fb46da05d4..9698b9635058 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -760,6 +760,7 @@ struct lpfc_hba {
 	uint8_t  mds_diags_support;
 	uint32_t initial_imax;
 	uint8_t  bbcredit_support;
+	uint8_t  enab_exp_wqcq_pages;
 
 	/* HBA Config Parameters */
 	uint32_t cfg_ack0;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index ac77081e6e9e..7be4bdef4d42 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -259,6 +259,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 				atomic_read(&tgtp->xmt_abort_rsp),
 				atomic_read(&tgtp->xmt_abort_rsp_error));
 
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"DELAY: ctx %08x  fod %08x wqfull %08x\n",
+				atomic_read(&tgtp->defer_ctx),
+				atomic_read(&tgtp->defer_fod),
+				atomic_read(&tgtp->defer_wqfull));
+
 		/* Calculate outstanding IOs */
 		tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
 		tot += atomic_read(&tgtp->xmt_fcp_release);
@@ -905,7 +911,12 @@ lpfc_issue_lip(struct Scsi_Host *shost)
 	LPFC_MBOXQ_t *pmboxq;
 	int mbxstatus = MBXERR_ERROR;
 
+	/*
+	 * If the link is offline, disabled or BLOCK_MGMT_IO
+	 * it doesn't make any sense to allow issue_lip
+	 */
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+	    (phba->hba_flag & LINK_DISABLED) ||
 	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
 		return -EPERM;
 
@@ -3458,8 +3469,8 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
 # tgt_queue_depth:  This parameter is used to limit the number of outstanding
 # commands per target port. Value range is [10,65535]. Default value is 65535.
 */
-LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
-		  "Max number of FCP commands we can queue to a specific target port");
+LPFC_VPORT_ATTR_RW(tgt_queue_depth, 65535, 10, 65535,
+		   "Max number of FCP commands we can queue to a specific target port");
 
 /*
 # hba_queue_depth:  This parameter is used to limit the number of outstanding
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 559f9aa0ed08..14a86b5b51e4 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -254,6 +254,7 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba,
 			    struct lpfc_nvmet_ctxbuf *ctxp);
 int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
 			       struct fc_frame_header *fc_hdr);
+void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq);
 void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba);
 void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba);
 void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 234c7c015982..ba896554a14f 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -2293,10 +2293,11 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		if (phba->nvmet_support) {
 			bf_set(prli_tgt, npr_nvme, 1);
 			bf_set(prli_disc, npr_nvme, 1);
-
 		} else {
 			bf_set(prli_init, npr_nvme, 1);
+			bf_set(prli_conf, npr_nvme, 1);
 		}
+
 		npr_nvme->word1 = cpu_to_be32(npr_nvme->word1);
 		npr_nvme->word4 = cpu_to_be32(npr_nvme->word4);
 		elsiocb->iocb_flag |= LPFC_PRLI_NVME_REQ;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index b159a5c4e388..f5bbac3cadbb 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -696,8 +696,9 @@ lpfc_work_done(struct lpfc_hba *phba)
 		      phba->hba_flag & HBA_SP_QUEUE_EVT)) {
 		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
-			/* Set the lpfc data pending flag */
-			set_bit(LPFC_DATA_READY, &phba->data_flags);
+			/* Preserve legacy behavior. */
+			if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
+				set_bit(LPFC_DATA_READY, &phba->data_flags);
 		} else {
 			if (phba->link_state >= LPFC_LINK_UP ||
 			    phba->link_flag & LS_MDS_LOOPBACK) {
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 73c2f6971d2b..8685d26e6929 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -3212,6 +3212,9 @@ struct lpfc_sli4_parameters {
 #define cfg_cqv_SHIFT				14
 #define cfg_cqv_MASK				0x00000003
 #define cfg_cqv_WORD				word4
+#define cfg_cqpsize_SHIFT			16
+#define cfg_cqpsize_MASK			0x000000ff
+#define cfg_cqpsize_WORD			word4
 	uint32_t word5;
 	uint32_t word6;
 #define cfg_mqv_SHIFT				14
@@ -3290,6 +3293,9 @@ struct lpfc_sli4_parameters {
 #define cfg_eqdr_SHIFT				8
 #define cfg_eqdr_MASK				0x00000001
 #define cfg_eqdr_WORD				word19
+#define cfg_nosr_SHIFT				9
+#define cfg_nosr_MASK				0x00000001
+#define cfg_nosr_WORD				word19
 #define LPFC_NODELAY_MAX_IO		32
 };
 
@@ -4343,9 +4349,9 @@ struct lpfc_nvme_prli {
 #define prli_init_SHIFT                 5
 #define prli_init_MASK                  0x00000001
 #define prli_init_WORD                  word4
-#define prli_recov_SHIFT                8
-#define prli_recov_MASK                 0x00000001
-#define prli_recov_WORD                 word4
+#define prli_conf_SHIFT                 7
+#define prli_conf_MASK                  0x00000001
+#define prli_conf_WORD                  word4
 	uint32_t word5;
 #define prli_fb_sz_SHIFT                0
 #define prli_fb_sz_MASK                 0x0000ffff
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index f539c554588c..465d890220d5 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -958,6 +958,7 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
 	struct lpfc_sli_ring *pring;
 	LIST_HEAD(completions);
 	int i;
+	struct lpfc_iocbq *piocb, *next_iocb;
 
 	if (phba->sli_rev != LPFC_SLI_REV4) {
 		for (i = 0; i < psli->num_rings; i++) {
@@ -983,6 +984,9 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
 		if (!pring)
 			continue;
 		spin_lock_irq(&pring->ring_lock);
+		list_for_each_entry_safe(piocb, next_iocb,
+					 &pring->txcmplq, list)
+			piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
 		list_splice_init(&pring->txcmplq, &completions);
 		pring->txcmplq_cnt = 0;
 		spin_unlock_irq(&pring->ring_lock);
@@ -8011,9 +8015,10 @@ static int
 lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
 {
 	struct lpfc_queue *qdesc;
+	uint32_t wqesize;
 
 	/* Create Fast Path FCP CQs */
-	if (phba->fcp_embed_io)
+	if (phba->enab_exp_wqcq_pages)
 		/* Increase the CQ size when WQEs contain an embedded cdb */
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
 					      phba->sli4_hba.cq_esize,
@@ -8031,15 +8036,18 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
 	phba->sli4_hba.fcp_cq[wqidx] = qdesc;
 
 	/* Create Fast Path FCP WQs */
-	if (phba->fcp_embed_io)
+	if (phba->enab_exp_wqcq_pages) {
 		/* Increase the WQ size when WQEs contain an embedded cdb */
+		wqesize = (phba->fcp_embed_io) ?
+			LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
-					      LPFC_WQE128_SIZE,
+					      wqesize,
 					      LPFC_WQE_EXP_COUNT);
-	else
+	} else
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
 					      phba->sli4_hba.wq_esize,
 					      phba->sli4_hba.wq_ecount);
+
 	if (!qdesc) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"0503 Failed allocate fast-path FCP WQ (%d)\n",
@@ -10465,8 +10473,19 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 		phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
 	}
 
-	if (bf_get(cfg_xib, mbx_sli4_parameters) && phba->cfg_suppress_rsp)
+	/*
+	 * To support Suppress Response feature we must satisfy 3 conditions.
+	 * lpfc_suppress_rsp module parameter must be set (default).
+	 * In SLI4-Parameters Descriptor:
+	 * Extended Inline Buffers (XIB) must be supported.
+	 * Suppress Response IU Not Supported (SRIUNS) must NOT be supported
+	 * (double negative).
+	 */
+	if (phba->cfg_suppress_rsp && bf_get(cfg_xib, mbx_sli4_parameters) &&
+	    !(bf_get(cfg_nosr, mbx_sli4_parameters)))
 		phba->sli.sli_flag |= LPFC_SLI_SUPPRESS_RSP;
+	else
+		phba->cfg_suppress_rsp = 0;
 
 	if (bf_get(cfg_eqdr, mbx_sli4_parameters))
 		phba->sli.sli_flag |= LPFC_SLI_USE_EQDR;
@@ -10476,15 +10495,21 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 		sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
 
 	/*
-	 * Issue IOs with CDB embedded in WQE to minimized the number
-	 * of DMAs the firmware has to do. Setting this to 1 also forces
-	 * the driver to use 128 bytes WQEs for FCP IOs.
+	 * Check whether the adapter supports an embedded copy of the
+	 * FCP CMD IU within the WQE for FCP_Ixxx commands. In order
+	 * to use this option, 128-byte WQEs must be used.
 	 */
 	if (bf_get(cfg_ext_embed_cb, mbx_sli4_parameters))
 		phba->fcp_embed_io = 1;
 	else
 		phba->fcp_embed_io = 0;
 
+	if ((bf_get(cfg_cqpsize, mbx_sli4_parameters) & LPFC_CQ_16K_PAGE_SZ) &&
+	    (bf_get(cfg_wqpsize, mbx_sli4_parameters) & LPFC_WQ_16K_PAGE_SZ) &&
+	    (sli4_params->wqsize & LPFC_WQ_SZ128_SUPPORT))
+		phba->enab_exp_wqcq_pages = 1;
+	else
+		phba->enab_exp_wqcq_pages = 0;
 	/*
 	 * Check if the SLI port supports MDS Diagnostics
 	 */
@@ -11493,13 +11518,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 	/* Remove FC host and then SCSI host with the physical port */
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
-	/*
-	 * Bring down the SLI Layer. This step disables all interrupts,
-	 * clears the rings, discards all mailbox commands, and resets
-	 * the HBA FCoE function.
-	 */
-	lpfc_debugfs_terminate(vport);
-	lpfc_sli4_hba_unset(phba);
 
 	/* Perform ndlp cleanup on the physical port.  The nvme and nvmet
 	 * localports are destroyed after to cleanup all transport memory.
@@ -11508,6 +11526,13 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 	lpfc_nvmet_destroy_targetport(phba);
 	lpfc_nvme_destroy_localport(vport);
 
+	/*
+	 * Bring down the SLI Layer. This step disables all interrupts,
+	 * clears the rings, discards all mailbox commands, and resets
+	 * the HBA FCoE function.
+	 */
+	lpfc_debugfs_terminate(vport);
+	lpfc_sli4_hba_unset(phba);
 
 	lpfc_stop_hba_timers(phba);
 	spin_lock_irq(&phba->hbalock);
@@ -12227,6 +12252,7 @@ int
 lpfc_fof_queue_create(struct lpfc_hba *phba)
 {
 	struct lpfc_queue *qdesc;
+	uint32_t wqesize;
 
 	/* Create FOF EQ */
 	qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
@@ -12240,7 +12266,7 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)
 	if (phba->cfg_fof) {
 
 		/* Create OAS CQ */
-		if (phba->fcp_embed_io)
+		if (phba->enab_exp_wqcq_pages)
 			qdesc = lpfc_sli4_queue_alloc(phba,
 						      LPFC_EXPANDED_PAGE_SIZE,
 						      phba->sli4_hba.cq_esize,
@@ -12256,16 +12282,19 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)
 		phba->sli4_hba.oas_cq = qdesc;
 
 		/* Create OAS WQ */
-		if (phba->fcp_embed_io)
+		if (phba->enab_exp_wqcq_pages) {
+			wqesize = (phba->fcp_embed_io) ?
+				LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
 			qdesc = lpfc_sli4_queue_alloc(phba,
 						      LPFC_EXPANDED_PAGE_SIZE,
-						      LPFC_WQE128_SIZE,
+						      wqesize,
 						      LPFC_WQE_EXP_COUNT);
-		else
+		} else
 			qdesc = lpfc_sli4_queue_alloc(phba,
 						      LPFC_DEFAULT_PAGE_SIZE,
 						      phba->sli4_hba.wq_esize,
 						      phba->sli4_hba.wq_ecount);
+
 		if (!qdesc)
 			goto out_error;
 
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 81fb92967b11..7313ceb0f23b 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -2170,10 +2170,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
 	/* Only FC supports upd bit */
 	if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) &&
 	    (vport->fc_flag & FC_VFI_REGISTERED) &&
-	    (!phba->fc_topology_changed)) {
-		bf_set(lpfc_reg_vfi_vp, reg_vfi, 0);
+	    (!phba->fc_topology_changed))
 		bf_set(lpfc_reg_vfi_upd, reg_vfi, 1);
-	}
 
 	bf_set(lpfc_reg_vfi_bbcr, reg_vfi, 0);
 	bf_set(lpfc_reg_vfi_bbscn, reg_vfi, 0);
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 87c08ff37ddd..41361662ff08 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -753,12 +753,16 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
 	drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys);
 	rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe);
 	if (rc < 0) {
+		(rqbp->rqb_free_buffer)(phba, rqb_entry);
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"6409 Cannot post to RQ %d: %x %x\n",
+				"6409 Cannot post to HRQ %d: %x %x %x "
+				"DRQ %x %x\n",
 				rqb_entry->hrq->queue_id,
 				rqb_entry->hrq->host_index,
-				rqb_entry->hrq->hba_index);
-		(rqbp->rqb_free_buffer)(phba, rqb_entry);
+				rqb_entry->hrq->hba_index,
+				rqb_entry->hrq->entry_count,
+				rqb_entry->drq->host_index,
+				rqb_entry->drq->hba_index);
 	} else {
 		list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list);
 		rqbp->buffer_count++;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index d841aa42f607..b63179d895e2 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,7 +1,7 @@
- /*******************************************************************
+/*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -2011,9 +2011,6 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			}
 		}
 
-		if (bf_get_be32(prli_recov, nvpr))
-			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
-
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 				 "6029 NVME PRLI Cmpl w1 x%08x "
 				 "w4 x%08x w5 x%08x flag x%x, "
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 81e3a4f10c3c..3a103d0895a2 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -241,10 +241,11 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 	ndlp = (struct lpfc_nodelist *)cmdwqe->context1;
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 			 "6047 nvme cmpl Enter "
-			 "Data %p DID %x Xri: %x status %x cmd:%p lsreg:%p "
-			 "bmp:%p ndlp:%p\n",
+			 "Data %p DID %x Xri: %x status %x reason x%x cmd:%p "
+			 "lsreg:%p bmp:%p ndlp:%p\n",
 			 pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
 			 cmdwqe->sli4_xritag, status,
+			 (wcqe->parameter & 0xffff),
 			 cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp);
 
 	lpfc_nvmeio_data(phba, "NVME LS  CMPL: xri x%x stat x%x parm x%x\n",
@@ -419,6 +420,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 {
 	int ret = 0;
 	struct lpfc_nvme_lport *lport;
+	struct lpfc_nvme_rport *rport;
 	struct lpfc_vport *vport;
 	struct lpfc_nodelist *ndlp;
 	struct ulp_bde64 *bpl;
@@ -437,19 +439,18 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 	 */
 
 	lport = (struct lpfc_nvme_lport *)pnvme_lport->private;
+	rport = (struct lpfc_nvme_rport *)pnvme_rport->private;
 	vport = lport->vport;
 
 	if (vport->load_flag & FC_UNLOADING)
 		return -ENODEV;
 
-	if (vport->load_flag & FC_UNLOADING)
-		return -ENODEV;
-
-	ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id);
+	/* Need the ndlp.  It is stored in the driver's rport. */
+	ndlp = rport->ndlp;
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR,
-				 "6051 DID x%06x not an active rport.\n",
-				 pnvme_rport->port_id);
+				 "6051 Remoteport %p, rport has invalid ndlp. "
+				 "Failing LS Req\n", pnvme_rport);
 		return -ENODEV;
 	}
 
@@ -500,8 +501,9 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 
 	/* Expand print to include key fields. */
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
-			 "6149 ENTER.  lport %p, rport %p lsreq%p rqstlen:%d "
-			 "rsplen:%d %pad %pad\n",
+			 "6149 Issue LS Req to DID 0x%06x lport %p, rport %p "
+			 "lsreq%p rqstlen:%d rsplen:%d %pad %pad\n",
+			 ndlp->nlp_DID,
 			 pnvme_lport, pnvme_rport,
 			 pnvme_lsreq, pnvme_lsreq->rqstlen,
 			 pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma,
@@ -517,7 +519,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 				ndlp, 2, 30, 0);
 	if (ret != WQE_SUCCESS) {
 		atomic_inc(&lport->xmt_ls_err);
-		lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
 				 "6052 EXIT. issue ls wqe failed lport %p, "
 				 "rport %p lsreq%p Status %x DID %x\n",
 				 pnvme_lport, pnvme_rport, pnvme_lsreq,
@@ -980,14 +982,14 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
 			phba->cpucheck_cmpl_io[lpfc_ncmd->cpu]++;
 	}
 #endif
-	freqpriv = nCmd->private;
-	freqpriv->nvme_buf = NULL;
 
 	/* NVME targets need completion held off until the abort exchange
 	 * completes unless the NVME Rport is getting unregistered.
 	 */
 
 	if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) {
+		freqpriv = nCmd->private;
+		freqpriv->nvme_buf = NULL;
 		nCmd->done(nCmd);
 		lpfc_ncmd->nvmeCmd = NULL;
 	}
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index 8dbf5c9d51aa..a332a6638b1b 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channsel Host Bus Adapters.                               *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -36,7 +36,7 @@
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/fc/fc_fs.h>
 
-#include <../drivers/nvme/host/nvme.h>
+#include <linux/nvme.h>
 #include <linux/nvme-fc-driver.h>
 #include <linux/nvme-fc.h>
 
@@ -71,6 +71,8 @@ static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *,
 static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *,
 					   struct lpfc_nvmet_rcv_ctx *,
 					   uint32_t, uint16_t);
+static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *,
+				    struct lpfc_nvmet_rcv_ctx *);
 
 void
 lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
@@ -130,7 +132,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 	if (tgtp) {
 		if (status) {
 			atomic_inc(&tgtp->xmt_ls_rsp_error);
-			if (status == IOERR_ABORT_REQUESTED)
+			if (result == IOERR_ABORT_REQUESTED)
 				atomic_inc(&tgtp->xmt_ls_rsp_aborted);
 			if (bf_get(lpfc_wcqe_c_xb, wcqe))
 				atomic_inc(&tgtp->xmt_ls_rsp_xb_set);
@@ -268,8 +270,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
 					 "NVMET RCV BUSY: xri x%x sz %d "
 					 "from %06x\n",
 					 oxid, size, sid);
-			/* defer repost rcv buffer till .defer_rcv callback */
-			ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
 			atomic_inc(&tgtp->rcv_fcp_cmd_out);
 			return;
 		}
@@ -541,7 +541,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 		rsp->transferred_length = 0;
 		if (tgtp) {
 			atomic_inc(&tgtp->xmt_fcp_rsp_error);
-			if (status == IOERR_ABORT_REQUESTED)
+			if (result == IOERR_ABORT_REQUESTED)
 				atomic_inc(&tgtp->xmt_fcp_rsp_aborted);
 		}
 
@@ -741,7 +741,10 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
 	struct lpfc_nvmet_rcv_ctx *ctxp =
 		container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
 	struct lpfc_hba *phba = ctxp->phba;
+	struct lpfc_queue *wq;
 	struct lpfc_iocbq *nvmewqeq;
+	struct lpfc_sli_ring *pring;
+	unsigned long iflags;
 	int rc;
 
 	if (phba->pport->load_flag & FC_UNLOADING) {
@@ -820,6 +823,22 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
 		return 0;
 	}
 
+	if (rc == -EBUSY) {
+		/*
+		 * WQ was full, so queue nvmewqeq to be sent after
+		 * WQE release CQE
+		 */
+		ctxp->flag |= LPFC_NVMET_DEFER_WQFULL;
+		wq = phba->sli4_hba.nvme_wq[rsp->hwqid];
+		pring = wq->pring;
+		spin_lock_irqsave(&pring->ring_lock, iflags);
+		list_add_tail(&nvmewqeq->list, &wq->wqfull_list);
+		wq->q_flag |= HBA_NVMET_WQFULL;
+		spin_unlock_irqrestore(&pring->ring_lock, iflags);
+		atomic_inc(&lpfc_nvmep->defer_wqfull);
+		return 0;
+	}
+
 	/* Give back resources */
 	atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
 	lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
@@ -851,6 +870,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
 	struct lpfc_nvmet_rcv_ctx *ctxp =
 		container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
 	struct lpfc_hba *phba = ctxp->phba;
+	struct lpfc_queue *wq;
 	unsigned long flags;
 
 	if (phba->pport->load_flag & FC_UNLOADING)
@@ -880,6 +900,14 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
 	}
 	ctxp->flag |= LPFC_NVMET_ABORT_OP;
 
+	if (ctxp->flag & LPFC_NVMET_DEFER_WQFULL) {
+		lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+						 ctxp->oxid);
+		wq = phba->sli4_hba.nvme_wq[ctxp->wqeq->hba_wqidx];
+		lpfc_nvmet_wqfull_flush(phba, wq, ctxp);
+		return;
+	}
+
 	/* An state of LPFC_NVMET_STE_RCV means we have just received
 	 * the NVME command and have not started processing it.
 	 * (by issuing any IO WQEs on this exchange yet)
@@ -946,11 +974,9 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
 
 	tgtp = phba->targetport->private;
 	atomic_inc(&tgtp->rcv_fcp_cmd_defer);
-	if (ctxp->flag & LPFC_NVMET_DEFER_RCV_REPOST)
-		lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
-	else
-		nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
-	ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
+
+	/* Free the nvmebuf since a new buffer already replaced it */
+	nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
 }
 
 static struct nvmet_fc_target_template lpfc_tgttemplate = {
@@ -1280,6 +1306,9 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba)
 		atomic_set(&tgtp->xmt_abort_sol, 0);
 		atomic_set(&tgtp->xmt_abort_rsp, 0);
 		atomic_set(&tgtp->xmt_abort_rsp_error, 0);
+		atomic_set(&tgtp->defer_ctx, 0);
+		atomic_set(&tgtp->defer_fod, 0);
+		atomic_set(&tgtp->defer_wqfull, 0);
 	}
 	return error;
 }
@@ -1435,16 +1464,103 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
 	return 0;
 }
 
+static void
+lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq,
+			struct lpfc_nvmet_rcv_ctx *ctxp)
+{
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *nvmewqeq;
+	struct lpfc_iocbq *next_nvmewqeq;
+	unsigned long iflags;
+	struct lpfc_wcqe_complete wcqe;
+	struct lpfc_wcqe_complete *wcqep;
+
+	pring = wq->pring;
+	wcqep = &wcqe;
+
+	/* Fake an ABORT error code back to cmpl routine */
+	memset(wcqep, 0, sizeof(struct lpfc_wcqe_complete));
+	bf_set(lpfc_wcqe_c_status, wcqep, IOSTAT_LOCAL_REJECT);
+	wcqep->parameter = IOERR_ABORT_REQUESTED;
+
+	spin_lock_irqsave(&pring->ring_lock, iflags);
+	list_for_each_entry_safe(nvmewqeq, next_nvmewqeq,
+				 &wq->wqfull_list, list) {
+		if (ctxp) {
+			/* Checking for a specific IO to flush */
+			if (nvmewqeq->context2 == ctxp) {
+				list_del(&nvmewqeq->list);
+				spin_unlock_irqrestore(&pring->ring_lock,
+						       iflags);
+				lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq,
+							  wcqep);
+				return;
+			}
+			continue;
+		} else {
+			/* Flush all IOs */
+			list_del(&nvmewqeq->list);
+			spin_unlock_irqrestore(&pring->ring_lock, iflags);
+			lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep);
+			spin_lock_irqsave(&pring->ring_lock, iflags);
+		}
+	}
+	if (!ctxp)
+		wq->q_flag &= ~HBA_NVMET_WQFULL;
+	spin_unlock_irqrestore(&pring->ring_lock, iflags);
+}
+
+void
+lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
+			  struct lpfc_queue *wq)
+{
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *nvmewqeq;
+	unsigned long iflags;
+	int rc;
+
+	/*
+	 * Some WQE slots are available, so try to re-issue anything
+	 * on the WQ wqfull_list.
+	 */
+	pring = wq->pring;
+	spin_lock_irqsave(&pring->ring_lock, iflags);
+	while (!list_empty(&wq->wqfull_list)) {
+		list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq,
+				 list);
+		spin_unlock_irqrestore(&pring->ring_lock, iflags);
+		rc = lpfc_sli4_issue_wqe(phba, LPFC_FCP_RING, nvmewqeq);
+		spin_lock_irqsave(&pring->ring_lock, iflags);
+		if (rc == -EBUSY) {
+			/* WQ was full again, so put it back on the list */
+			list_add(&nvmewqeq->list, &wq->wqfull_list);
+			spin_unlock_irqrestore(&pring->ring_lock, iflags);
+			return;
+		}
+	}
+	wq->q_flag &= ~HBA_NVMET_WQFULL;
+	spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+#endif
+}
+
 void
 lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
 {
 #if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
 	struct lpfc_nvmet_tgtport *tgtp;
+	struct lpfc_queue *wq;
+	uint32_t qidx;
 
 	if (phba->nvmet_support == 0)
 		return;
 	if (phba->targetport) {
 		tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+		for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++) {
+			wq = phba->sli4_hba.nvme_wq[qidx];
+			lpfc_nvmet_wqfull_flush(phba, wq, NULL);
+		}
 		init_completion(&tgtp->tport_unreg_done);
 		nvmet_fc_unregister_targetport(phba->targetport);
 		wait_for_completion_timeout(&tgtp->tport_unreg_done, 5);
@@ -1694,6 +1810,8 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
 	lpfc_nvmeio_data(phba, "NVMET FCP  RCV: xri x%x sz %d CPU %02x\n",
 			 oxid, size, smp_processor_id());
 
+	tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+
 	if (!ctx_buf) {
 		/* Queue this NVME IO to process later */
 		spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
@@ -1709,10 +1827,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
 		lpfc_post_rq_buffer(
 			phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
 			phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
+
+		atomic_inc(&tgtp->defer_ctx);
 		return;
 	}
 
-	tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
 	payload = (uint32_t *)(nvmebuf->dbuf.virt);
 	sid = sli4_sid_from_fc_hdr(fc_hdr);
 
@@ -1776,12 +1895,20 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
 
 	/* Processing of FCP command is deferred */
 	if (rc == -EOVERFLOW) {
+		/*
+		 * Post a brand new DMA buffer to RQ and defer
+		 * freeing rcv buffer till .defer_rcv callback
+		 */
+		qno = nvmebuf->idx;
+		lpfc_post_rq_buffer(
+			phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
+			phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
+
 		lpfc_nvmeio_data(phba,
 				 "NVMET RCV BUSY: xri x%x sz %d from %06x\n",
 				 oxid, size, sid);
-		/* defer reposting rcv buffer till .defer_rcv callback */
-		ctxp->flag |= LPFC_NVMET_DEFER_RCV_REPOST;
 		atomic_inc(&tgtp->rcv_fcp_cmd_out);
+		atomic_inc(&tgtp->defer_fod);
 		return;
 	}
 	ctxp->rqb_buffer = nvmebuf;
@@ -2163,9 +2290,10 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		if (rsp->op == NVMET_FCOP_READDATA_RSP) {
 			atomic_inc(&tgtp->xmt_fcp_read_rsp);
 			bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1);
-			if ((ndlp->nlp_flag & NLP_SUPPRESS_RSP) &&
-			    (rsp->rsplen == 12)) {
-				bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 1);
+			if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) {
+				if (ndlp->nlp_flag & NLP_SUPPRESS_RSP)
+					bf_set(wqe_sup,
+					       &wqe->fcp_tsend.wqe_com, 1);
 				bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
 				bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
 				bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h
index 5b32c9e4d4ef..c1bcef3f103c 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.h
+++ b/drivers/scsi/lpfc/lpfc_nvmet.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -72,7 +72,6 @@ struct lpfc_nvmet_tgtport {
 	atomic_t xmt_fcp_rsp_aborted;
 	atomic_t xmt_fcp_rsp_drop;
 
-
 	/* Stats counters - lpfc_nvmet_xmt_fcp_abort */
 	atomic_t xmt_fcp_xri_abort_cqe;
 	atomic_t xmt_fcp_abort;
@@ -81,6 +80,11 @@ struct lpfc_nvmet_tgtport {
 	atomic_t xmt_abort_unsol;
 	atomic_t xmt_abort_rsp;
 	atomic_t xmt_abort_rsp_error;
+
+	/* Stats counters - defer IO */
+	atomic_t defer_ctx;
+	atomic_t defer_fod;
+	atomic_t defer_wqfull;
 };
 
 struct lpfc_nvmet_ctx_info {
@@ -131,7 +135,7 @@ struct lpfc_nvmet_rcv_ctx {
 #define LPFC_NVMET_XBUSY		0x4  /* XB bit set on IO cmpl */
 #define LPFC_NVMET_CTX_RLS		0x8  /* ctx free requested */
 #define LPFC_NVMET_ABTS_RCV		0x10  /* ABTS received on exchange */
-#define LPFC_NVMET_DEFER_RCV_REPOST	0x20  /* repost to RQ on defer rcv */
+#define LPFC_NVMET_DEFER_WQFULL		0x40  /* Waiting on a free WQE */
 	struct rqb_dmabuf *rqb_buffer;
 	struct lpfc_nvmet_ctxbuf *ctxbuf;
 
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c0cdaef4db24..c595046a521b 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -3772,20 +3772,18 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
-				 "9025 FCP Read Underrun, expected %d, "
+				 "9025 FCP Underrun, expected %d, "
 				 "residual %d Data: x%x x%x x%x\n",
 				 fcpDl,
 				 scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
 				 cmnd->underflow);
 
 		/*
-		 * If there is an under run check if under run reported by
+		 * If there is an under run, check if under run reported by
 		 * storage array is same as the under run reported by HBA.
 		 * If this is not same, there is a dropped frame.
 		 */
-		if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
-			fcpi_parm &&
-			(scsi_get_resid(cmnd) != fcpi_parm)) {
+		if (fcpi_parm && (scsi_get_resid(cmnd) != fcpi_parm)) {
 			lpfc_printf_vlog(vport, KERN_WARNING,
 					 LOG_FCP | LOG_FCP_ERROR,
 					 "9026 FCP Read Check Error "
@@ -3926,7 +3924,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
 	struct lpfc_nodelist *pnode = rdata->pnode;
 	struct scsi_cmnd *cmd;
-	int depth;
 	unsigned long flags;
 	struct lpfc_fast_path_event *fast_path_evt;
 	struct Scsi_Host *shost;
@@ -4132,16 +4129,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		}
 		spin_unlock_irqrestore(shost->host_lock, flags);
 	} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
-		if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
-		   time_after(jiffies, pnode->last_change_time +
+		if ((pnode->cmd_qdepth != vport->cfg_tgt_queue_depth) &&
+		    time_after(jiffies, pnode->last_change_time +
 			      msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
 			spin_lock_irqsave(shost->host_lock, flags);
-			depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
-				/ 100;
-			depth = depth ? depth : 1;
-			pnode->cmd_qdepth += depth;
-			if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
-				pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
+			pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
 			pnode->last_change_time = jiffies;
 			spin_unlock_irqrestore(shost->host_lock, flags);
 		}
@@ -4564,9 +4556,32 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
 	 */
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
 		goto out_tgt_busy;
-	if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
+	if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) {
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_ERROR,
+				 "3377 Target Queue Full, scsi Id:%d Qdepth:%d"
+				 " Pending command:%d"
+				 " WWNN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, "
+				 " WWPN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				 ndlp->nlp_sid, ndlp->cmd_qdepth,
+				 atomic_read(&ndlp->cmd_pending),
+				 ndlp->nlp_nodename.u.wwn[0],
+				 ndlp->nlp_nodename.u.wwn[1],
+				 ndlp->nlp_nodename.u.wwn[2],
+				 ndlp->nlp_nodename.u.wwn[3],
+				 ndlp->nlp_nodename.u.wwn[4],
+				 ndlp->nlp_nodename.u.wwn[5],
+				 ndlp->nlp_nodename.u.wwn[6],
+				 ndlp->nlp_nodename.u.wwn[7],
+				 ndlp->nlp_portname.u.wwn[0],
+				 ndlp->nlp_portname.u.wwn[1],
+				 ndlp->nlp_portname.u.wwn[2],
+				 ndlp->nlp_portname.u.wwn[3],
+				 ndlp->nlp_portname.u.wwn[4],
+				 ndlp->nlp_portname.u.wwn[5],
+				 ndlp->nlp_portname.u.wwn[6],
+				 ndlp->nlp_portname.u.wwn[7]);
 		goto out_tgt_busy;
-
+	}
 	lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
 	if (lpfc_cmd == NULL) {
 		lpfc_rampdown_queue_depth(phba);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 5f5528a12308..e97d080e9f65 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1,8 +1,7 @@
-
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -129,6 +128,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
 	/* set consumption flag every once in a while */
 	if (!((q->host_index + 1) % q->entry_repost))
 		bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
+	else
+		bf_set(wqe_wqec, &wqe->generic.wqe_com, 0);
 	if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
 		bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
 	lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
@@ -3776,6 +3777,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring  *pring;
 	uint32_t i;
+	struct lpfc_iocbq *piocb, *next_iocb;
 
 	spin_lock_irq(&phba->hbalock);
 	/* Indicate the I/O queues are flushed */
@@ -3790,6 +3792,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 			spin_lock_irq(&pring->ring_lock);
 			/* Retrieve everything on txq */
 			list_splice_init(&pring->txq, &txq);
+			list_for_each_entry_safe(piocb, next_iocb,
+						 &pring->txcmplq, list)
+				piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
 			/* Retrieve everything on the txcmplq */
 			list_splice_init(&pring->txcmplq, &txcmplq);
 			pring->txq_cnt = 0;
@@ -3811,6 +3816,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 		spin_lock_irq(&phba->hbalock);
 		/* Retrieve everything on txq */
 		list_splice_init(&pring->txq, &txq);
+		list_for_each_entry_safe(piocb, next_iocb,
+					 &pring->txcmplq, list)
+			piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
 		/* Retrieve everything on the txcmplq */
 		list_splice_init(&pring->txcmplq, &txcmplq);
 		pring->txq_cnt = 0;
@@ -3842,6 +3850,7 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
 	LIST_HEAD(txcmplq);
 	struct lpfc_sli_ring  *pring;
 	uint32_t i;
+	struct lpfc_iocbq *piocb, *next_iocb;
 
 	if (phba->sli_rev < LPFC_SLI_REV4)
 		return;
@@ -3858,8 +3867,11 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
 	for (i = 0; i < phba->cfg_nvme_io_channel; i++) {
 		pring = phba->sli4_hba.nvme_wq[i]->pring;
 
-		/* Retrieve everything on the txcmplq */
 		spin_lock_irq(&pring->ring_lock);
+		list_for_each_entry_safe(piocb, next_iocb,
+					 &pring->txcmplq, list)
+			piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
+		/* Retrieve everything on the txcmplq */
 		list_splice_init(&pring->txcmplq, &txcmplq);
 		pring->txcmplq_cnt = 0;
 		spin_unlock_irq(&pring->ring_lock);
@@ -6533,9 +6545,11 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 	struct lpfc_rqe hrqe;
 	struct lpfc_rqe drqe;
 	struct lpfc_rqb *rqbp;
+	unsigned long flags;
 	struct rqb_dmabuf *rqb_buffer;
 	LIST_HEAD(rqb_buf_list);
 
+	spin_lock_irqsave(&phba->hbalock, flags);
 	rqbp = hrq->rqbp;
 	for (i = 0; i < count; i++) {
 		/* IF RQ is already full, don't bother */
@@ -6559,6 +6573,15 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 		drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys);
 		rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
 		if (rc < 0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"6421 Cannot post to HRQ %d: %x %x %x "
+					"DRQ %x %x\n",
+					hrq->queue_id,
+					hrq->host_index,
+					hrq->hba_index,
+					hrq->entry_count,
+					drq->host_index,
+					drq->hba_index);
 			rqbp->rqb_free_buffer(phba, rqb_buffer);
 		} else {
 			list_add_tail(&rqb_buffer->hbuf.list,
@@ -6566,6 +6589,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 			rqbp->buffer_count++;
 		}
 	}
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 	return 1;
 }
 
@@ -13230,6 +13254,8 @@ lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
 		if (childwq->queue_id == hba_wqid) {
 			lpfc_sli4_wq_release(childwq,
 					bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+			if (childwq->q_flag & HBA_NVMET_WQFULL)
+				lpfc_nvmet_wqfull_process(phba, childwq);
 			wqid_matched = true;
 			break;
 		}
@@ -13948,6 +13974,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
 
 	INIT_LIST_HEAD(&queue->list);
 	INIT_LIST_HEAD(&queue->wq_list);
+	INIT_LIST_HEAD(&queue->wqfull_list);
 	INIT_LIST_HEAD(&queue->page_list);
 	INIT_LIST_HEAD(&queue->child_list);
 
@@ -14908,7 +14935,8 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 	bf_set(lpfc_mbox_hdr_version, &shdr->request,
 	       phba->sli4_hba.pc_sli4_params.wqv);
 
-	if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT)
+	if ((phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) ||
+	    (wq->page_size > SLI4_PAGE_SIZE))
 		wq_create_version = LPFC_Q_CREATE_VERSION_1;
 	else
 		wq_create_version = LPFC_Q_CREATE_VERSION_0;
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 81fb58e59e60..4545c1fdcb55 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -145,6 +145,7 @@ struct lpfc_rqb {
 struct lpfc_queue {
 	struct list_head list;
 	struct list_head wq_list;
+	struct list_head wqfull_list;
 	enum lpfc_sli4_queue_type type;
 	enum lpfc_sli4_queue_subtype subtype;
 	struct lpfc_hba *phba;
@@ -173,9 +174,11 @@ struct lpfc_queue {
 #define LPFC_EXPANDED_PAGE_SIZE	16384
 #define LPFC_DEFAULT_PAGE_SIZE	4096
 	uint16_t chann;		/* IO channel this queue is associated with */
-	uint16_t db_format;
+	uint8_t db_format;
 #define LPFC_DB_RING_FORMAT	0x01
 #define LPFC_DB_LIST_FORMAT	0x02
+	uint8_t q_flag;
+#define HBA_NVMET_WQFULL	0x1 /* We hit WQ Full condition for NVMET */
 	void __iomem *db_regaddr;
 	/* For q stats */
 	uint32_t q_cnt_1;
@@ -485,6 +488,11 @@ struct lpfc_pc_sli4_params {
 	uint8_t wqpcnt;
 };
 
+#define LPFC_CQ_4K_PAGE_SZ	0x1
+#define LPFC_CQ_16K_PAGE_SZ	0x4
+#define LPFC_WQ_4K_PAGE_SZ	0x1
+#define LPFC_WQ_16K_PAGE_SZ	0x4
+
 struct lpfc_iov {
 	uint32_t pf_number;
 	uint32_t vf_number;
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index c232bf0e8998..4adbf07880a2 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "11.4.0.6"
+#define LPFC_DRIVER_VERSION "11.4.0.7"
 #define LPFC_DRIVER_NAME		"lpfc"
 
 /* Used for SLI 2/3 */
@@ -32,6 +32,6 @@
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
 		LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright (C) 2017 Broadcom. All Rights Reserved. " \
-		"The term \"Broadcom\" refers to Broadcom Limited " \
+#define LPFC_COPYRIGHT "Copyright (C) 2017-2018 Broadcom. All Rights " \
+		"Reserved. The term \"Broadcom\" refers to Broadcom Limited " \
 		"and/or its subsidiaries."
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 13d6e4ec3022..59a87ca328d3 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -2410,8 +2410,11 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
 				continue;
 			}
 
-			for_each_cpu(cpu, mask)
+			for_each_cpu_and(cpu, mask, cpu_online_mask) {
+				if (cpu >= ioc->cpu_msix_table_sz)
+					break;
 				ioc->cpu_msix_table[cpu] = reply_q->msix_index;
+			}
 		}
 		return;
 	}
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 201c8de1853d..95530393872d 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -1025,7 +1025,7 @@ static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd)
 static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd)
 {
 	struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
-	struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+	struct pmcraid_ioadl_desc *ioadl;
 	struct pmcraid_instance *pinstance = cmd->drv_inst;
 	u16 data_size = sizeof(struct pmcraid_inquiry_data);
 
@@ -3175,7 +3175,7 @@ static int pmcraid_build_ioadl(
 
 	struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd;
 	struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb);
-	struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+	struct pmcraid_ioadl_desc *ioadl;
 
 	u32 length = scsi_bufflen(scsi_cmd);
 
@@ -3225,12 +3225,7 @@ static int pmcraid_build_ioadl(
  */
 static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
 {
-	int i;
-
-	for (i = 0; i < sglist->num_sg; i++)
-		__free_pages(sg_page(&(sglist->scatterlist[i])),
-			     sglist->order);
-
+	sgl_free_order(sglist->scatterlist, sglist->order);
 	kfree(sglist);
 }
 
@@ -3247,50 +3242,20 @@ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
 static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
 {
 	struct pmcraid_sglist *sglist;
-	struct scatterlist *scatterlist;
-	struct page *page;
-	int num_elem, i, j;
 	int sg_size;
 	int order;
-	int bsize_elem;
 
 	sg_size = buflen / (PMCRAID_MAX_IOADLS - 1);
 	order = (sg_size > 0) ? get_order(sg_size) : 0;
-	bsize_elem = PAGE_SIZE * (1 << order);
-
-	/* Determine the actual number of sg entries needed */
-	if (buflen % bsize_elem)
-		num_elem = (buflen / bsize_elem) + 1;
-	else
-		num_elem = buflen / bsize_elem;
 
 	/* Allocate a scatter/gather list for the DMA */
-	sglist = kzalloc(sizeof(struct pmcraid_sglist) +
-			 (sizeof(struct scatterlist) * (num_elem - 1)),
-			 GFP_KERNEL);
-
+	sglist = kzalloc(sizeof(struct pmcraid_sglist), GFP_KERNEL);
 	if (sglist == NULL)
 		return NULL;
 
-	scatterlist = sglist->scatterlist;
-	sg_init_table(scatterlist, num_elem);
 	sglist->order = order;
-	sglist->num_sg = num_elem;
-	sg_size = buflen;
-
-	for (i = 0; i < num_elem; i++) {
-		page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order);
-		if (!page) {
-			for (j = i - 1; j >= 0; j--)
-				__free_pages(sg_page(&scatterlist[j]), order);
-			kfree(sglist);
-			return NULL;
-		}
-
-		sg_set_page(&scatterlist[i], page,
-			sg_size < bsize_elem ? sg_size : bsize_elem, 0);
-		sg_size -= bsize_elem;
-	}
+	sgl_alloc_order(buflen, order, false,
+			GFP_KERNEL | GFP_DMA | __GFP_ZERO, &sglist->num_sg);
 
 	return sglist;
 }
@@ -5492,7 +5457,7 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd)
 	struct pmcraid_instance *pinstance = cmd->drv_inst;
 	struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
 	__be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN);
-	struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+	struct pmcraid_ioadl_desc *ioadl;
 	u64 timestamp;
 
 	timestamp = ktime_get_real_seconds() * 1000;
@@ -5665,7 +5630,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
 static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
 {
 	struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
-	struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+	struct pmcraid_ioadl_desc *ioadl;
 	struct pmcraid_instance *pinstance = cmd->drv_inst;
 	__be32 cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table));
 
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 8bfac72a242b..754ef30927e2 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -542,8 +542,7 @@ struct pmcraid_sglist {
 	u32 order;
 	u32 num_sg;
 	u32 num_dma_sg;
-	u32 buffer_len;
-	struct scatterlist scatterlist[1];
+	struct scatterlist *scatterlist;
 };
 
 /* page D0 inquiry data of focal point resource */
diff --git a/drivers/scsi/qedf/qedf_dbg.c b/drivers/scsi/qedf/qedf_dbg.c
index e023f5d0dc12..bd1cef25a900 100644
--- a/drivers/scsi/qedf/qedf_dbg.c
+++ b/drivers/scsi/qedf/qedf_dbg.c
@@ -160,7 +160,7 @@ qedf_uevent_emit(struct Scsi_Host *shost, u32 code, char *msg)
 	switch (code) {
 	case QEDF_UEVENT_CODE_GRCDUMP:
 		if (msg)
-			strncpy(event_string, msg, strlen(msg));
+			strscpy(event_string, msg, sizeof(event_string));
 		else
 			sprintf(event_string, "GRCDUMP=%u", shost->host_no);
 		break;
diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h
index 50083cae84c3..77c27e888969 100644
--- a/drivers/scsi/qedf/qedf_dbg.h
+++ b/drivers/scsi/qedf/qedf_dbg.h
@@ -116,6 +116,14 @@ extern int qedf_create_sysfs_attr(struct Scsi_Host *shost,
 extern void qedf_remove_sysfs_attr(struct Scsi_Host *shost,
 				    struct sysfs_bin_attrs *iter);
 
+struct qedf_debugfs_ops {
+	char *name;
+	struct qedf_list_of_funcs *qedf_funcs;
+};
+
+extern const struct qedf_debugfs_ops qedf_debugfs_ops[];
+extern const struct file_operations qedf_dbg_fops[];
+
 #ifdef CONFIG_DEBUG_FS
 /* DebugFS related code */
 struct qedf_list_of_funcs {
@@ -123,11 +131,6 @@ struct qedf_list_of_funcs {
 	ssize_t (*oper_func)(struct qedf_dbg_ctx *qedf);
 };
 
-struct qedf_debugfs_ops {
-	char *name;
-	struct qedf_list_of_funcs *qedf_funcs;
-};
-
 #define qedf_dbg_fileops(drv, ops) \
 { \
 	.owner  = THIS_MODULE, \
@@ -147,8 +150,8 @@ struct qedf_debugfs_ops {
 }
 
 extern void qedf_dbg_host_init(struct qedf_dbg_ctx *qedf,
-				struct qedf_debugfs_ops *dops,
-				struct file_operations *fops);
+				const struct qedf_debugfs_ops *dops,
+				const struct file_operations *fops);
 extern void qedf_dbg_host_exit(struct qedf_dbg_ctx *qedf);
 extern void qedf_dbg_init(char *drv_name);
 extern void qedf_dbg_exit(void);
diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c
index 2b1ef3075e93..c539a7ae3a7e 100644
--- a/drivers/scsi/qedf/qedf_debugfs.c
+++ b/drivers/scsi/qedf/qedf_debugfs.c
@@ -23,8 +23,8 @@ static struct dentry *qedf_dbg_root;
  **/
 void
 qedf_dbg_host_init(struct qedf_dbg_ctx *qedf,
-		    struct qedf_debugfs_ops *dops,
-		    struct file_operations *fops)
+		    const struct qedf_debugfs_ops *dops,
+		    const struct file_operations *fops)
 {
 	char host_dirname[32];
 	struct dentry *file_dentry = NULL;
@@ -99,7 +99,7 @@ qedf_dbg_exit(void)
 	qedf_dbg_root = NULL;
 }
 
-struct qedf_debugfs_ops qedf_debugfs_ops[] = {
+const struct qedf_debugfs_ops qedf_debugfs_ops[] = {
 	{ "fp_int", NULL },
 	{ "io_trace", NULL },
 	{ "debug", NULL },
diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c
index b15e69586a36..50a50c4249d0 100644
--- a/drivers/scsi/qedf/qedf_io.c
+++ b/drivers/scsi/qedf/qedf_io.c
@@ -917,7 +917,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd)
 	struct qedf_ctx *qedf = lport_priv(lport);
 	struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
 	struct fc_rport_libfc_priv *rp = rport->dd_data;
-	struct qedf_rport *fcport = rport->dd_data;
+	struct qedf_rport *fcport;
 	struct qedf_ioreq *io_req;
 	int rc = 0;
 	int rval;
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index ccd9a08ea030..284ccb566b19 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -23,6 +23,7 @@
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
 #include "qedf.h"
+#include "qedf_dbg.h"
 #include <uapi/linux/pci_regs.h>
 
 const struct qed_fcoe_ops *qed_ops;
@@ -30,9 +31,6 @@ const struct qed_fcoe_ops *qed_ops;
 static int qedf_probe(struct pci_dev *pdev, const struct pci_device_id *id);
 static void qedf_remove(struct pci_dev *pdev);
 
-extern struct qedf_debugfs_ops qedf_debugfs_ops;
-extern struct file_operations qedf_dbg_fops;
-
 /*
  * Driver module parameters.
  */
@@ -3155,8 +3153,8 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
 	}
 
 #ifdef CONFIG_DEBUG_FS
-	qedf_dbg_host_init(&(qedf->dbg_ctx), &qedf_debugfs_ops,
-			    &qedf_dbg_fops);
+	qedf_dbg_host_init(&(qedf->dbg_ctx), qedf_debugfs_ops,
+			    qedf_dbg_fops);
 #endif
 
 	/* Start LL2 */
diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h
index c55572badfb0..358f40567849 100644
--- a/drivers/scsi/qedi/qedi_dbg.h
+++ b/drivers/scsi/qedi/qedi_dbg.h
@@ -134,7 +134,7 @@ struct qedi_debugfs_ops {
 }
 
 void qedi_dbg_host_init(struct qedi_dbg_ctx *qedi,
-			struct qedi_debugfs_ops *dops,
+			const struct qedi_debugfs_ops *dops,
 			const struct file_operations *fops);
 void qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi);
 void qedi_dbg_init(char *drv_name);
diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c
index fd8a1eea3163..fd914ca4149a 100644
--- a/drivers/scsi/qedi/qedi_debugfs.c
+++ b/drivers/scsi/qedi/qedi_debugfs.c
@@ -19,7 +19,7 @@ static struct dentry *qedi_dbg_root;
 
 void
 qedi_dbg_host_init(struct qedi_dbg_ctx *qedi,
-		   struct qedi_debugfs_ops *dops,
+		   const struct qedi_debugfs_ops *dops,
 		   const struct file_operations *fops)
 {
 	char host_dirname[32];
@@ -99,7 +99,7 @@ static struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = {
 	{ NULL, NULL }
 };
 
-struct qedi_debugfs_ops qedi_debugfs_ops[] = {
+const struct qedi_debugfs_ops qedi_debugfs_ops[] = {
 	{ "gbl_ctx", NULL },
 	{ "do_not_recover", qedi_dbg_do_not_recover_ops},
 	{ "io_trace", NULL },
diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
index f5b5a31999aa..a2aa06ed1620 100644
--- a/drivers/scsi/qedi/qedi_gbl.h
+++ b/drivers/scsi/qedi/qedi_gbl.h
@@ -23,8 +23,8 @@ extern uint qedi_io_tracing;
 extern struct scsi_host_template qedi_host_template;
 extern struct iscsi_transport qedi_iscsi_transport;
 extern const struct qed_iscsi_ops *qedi_ops;
-extern struct qedi_debugfs_ops qedi_debugfs_ops;
-extern const struct file_operations qedi_dbg_fops;
+extern const struct qedi_debugfs_ops qedi_debugfs_ops[];
+extern const struct file_operations qedi_dbg_fops[];
 extern struct device_attribute *qedi_shost_attrs[];
 
 int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep);
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 029e2e69b29f..4da3592aec0f 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -1724,7 +1724,6 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf)
 {
 	struct qedi_ctx *qedi = data;
 	struct nvm_iscsi_initiator *initiator;
-	char *str = buf;
 	int rc = 1;
 	u32 ipv6_en, dhcp_en, ip_len;
 	struct nvm_iscsi_block *block;
@@ -1758,32 +1757,32 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf)
 
 	switch (type) {
 	case ISCSI_BOOT_ETH_IP_ADDR:
-		rc = snprintf(str, ip_len, fmt, ip);
+		rc = snprintf(buf, ip_len, fmt, ip);
 		break;
 	case ISCSI_BOOT_ETH_SUBNET_MASK:
-		rc = snprintf(str, ip_len, fmt, sub);
+		rc = snprintf(buf, ip_len, fmt, sub);
 		break;
 	case ISCSI_BOOT_ETH_GATEWAY:
-		rc = snprintf(str, ip_len, fmt, gw);
+		rc = snprintf(buf, ip_len, fmt, gw);
 		break;
 	case ISCSI_BOOT_ETH_FLAGS:
-		rc = snprintf(str, 3, "%hhd\n",
+		rc = snprintf(buf, 3, "%hhd\n",
 			      SYSFS_FLAG_FW_SEL_BOOT);
 		break;
 	case ISCSI_BOOT_ETH_INDEX:
-		rc = snprintf(str, 3, "0\n");
+		rc = snprintf(buf, 3, "0\n");
 		break;
 	case ISCSI_BOOT_ETH_MAC:
-		rc = sysfs_format_mac(str, qedi->mac, ETH_ALEN);
+		rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN);
 		break;
 	case ISCSI_BOOT_ETH_VLAN:
-		rc = snprintf(str, 12, "%d\n",
+		rc = snprintf(buf, 12, "%d\n",
 			      GET_FIELD2(initiator->generic_cont0,
 					 NVM_ISCSI_CFG_INITIATOR_VLAN));
 		break;
 	case ISCSI_BOOT_ETH_ORIGIN:
 		if (dhcp_en)
-			rc = snprintf(str, 3, "3\n");
+			rc = snprintf(buf, 3, "3\n");
 		break;
 	default:
 		rc = 0;
@@ -1819,7 +1818,6 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf)
 {
 	struct qedi_ctx *qedi = data;
 	struct nvm_iscsi_initiator *initiator;
-	char *str = buf;
 	int rc;
 	struct nvm_iscsi_block *block;
 
@@ -1831,8 +1829,8 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf)
 
 	switch (type) {
 	case ISCSI_BOOT_INI_INITIATOR_NAME:
-		rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
-			      initiator->initiator_name.byte);
+		rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN,
+			     initiator->initiator_name.byte);
 		break;
 	default:
 		rc = 0;
@@ -1860,7 +1858,6 @@ static ssize_t
 qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type,
 			char *buf, enum qedi_nvm_tgts idx)
 {
-	char *str = buf;
 	int rc = 1;
 	u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len;
 	struct nvm_iscsi_block *block;
@@ -1899,48 +1896,48 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type,
 
 	switch (type) {
 	case ISCSI_BOOT_TGT_NAME:
-		rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
-			      block->target[idx].target_name.byte);
+		rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN,
+			     block->target[idx].target_name.byte);
 		break;
 	case ISCSI_BOOT_TGT_IP_ADDR:
 		if (ipv6_en)
-			rc = snprintf(str, ip_len, "%pI6\n",
+			rc = snprintf(buf, ip_len, "%pI6\n",
 				      block->target[idx].ipv6_addr.byte);
 		else
-			rc = snprintf(str, ip_len, "%pI4\n",
+			rc = snprintf(buf, ip_len, "%pI4\n",
 				      block->target[idx].ipv4_addr.byte);
 		break;
 	case ISCSI_BOOT_TGT_PORT:
-		rc = snprintf(str, 12, "%d\n",
+		rc = snprintf(buf, 12, "%d\n",
 			      GET_FIELD2(block->target[idx].generic_cont0,
 					 NVM_ISCSI_CFG_TARGET_TCP_PORT));
 		break;
 	case ISCSI_BOOT_TGT_LUN:
-		rc = snprintf(str, 22, "%.*d\n",
+		rc = snprintf(buf, 22, "%.*d\n",
 			      block->target[idx].lun.value[1],
 			      block->target[idx].lun.value[0]);
 		break;
 	case ISCSI_BOOT_TGT_CHAP_NAME:
-		rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
-			      chap_name);
+		rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+			     chap_name);
 		break;
 	case ISCSI_BOOT_TGT_CHAP_SECRET:
-		rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
-			      chap_secret);
+		rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+			     chap_secret);
 		break;
 	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
-		rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
-			      mchap_name);
+		rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+			     mchap_name);
 		break;
 	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
-		rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
-			      mchap_secret);
+		rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+			     mchap_secret);
 		break;
 	case ISCSI_BOOT_TGT_FLAGS:
-		rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT);
+		rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT);
 		break;
 	case ISCSI_BOOT_TGT_NIC_ASSOC:
-		rc = snprintf(str, 3, "0\n");
+		rc = snprintf(buf, 3, "0\n");
 		break;
 	default:
 		rc = 0;
@@ -2303,8 +2300,8 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
 	}
 
 #ifdef CONFIG_DEBUG_FS
-	qedi_dbg_host_init(&qedi->dbg_ctx, &qedi_debugfs_ops,
-			   &qedi_dbg_fops);
+	qedi_dbg_host_init(&qedi->dbg_ctx, qedi_debugfs_ops,
+			   qedi_dbg_fops);
 #endif
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
 		  "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n",
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 3e9dc54b89a3..7e9d8f08b9d5 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -717,7 +717,7 @@ qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval)
 
 /**
  * qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
- * @ha: HA context
+ * @vha: HA context
  * @hardware_locked: Called with the hardware_lock
  */
 void
@@ -887,7 +887,7 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
 
 /**
  * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware.
- * @ha: HA context
+ * @vha: HA context
  * @hardware_locked: Called with the hardware_lock
  */
 void
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 5bf9a59432f6..e4d404c24506 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -21,11 +21,10 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *);
 
 /**
  * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query.
- * @ha: HA context
- * @req_size: request size in bytes
- * @rsp_size: response size in bytes
+ * @vha: HA context
+ * @arg: CT arguments
  *
- * Returns a pointer to the @ha's ms_iocb.
+ * Returns a pointer to the @vha's ms_iocb.
  */
 void *
 qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
@@ -61,9 +60,8 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
 
 /**
  * qla24xx_prep_ms_iocb() - Prepare common CT IOCB fields for SNS CT query.
- * @ha: HA context
- * @req_size: request size in bytes
- * @rsp_size: response size in bytes
+ * @vha: HA context
+ * @arg: CT arguments
  *
  * Returns a pointer to the @ha's ms_iocb.
  */
@@ -101,7 +99,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
 
 /**
  * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
- * @ct_req: CT request buffer
+ * @p: CT request buffer
  * @cmd: GS command
  * @rsp_size: response size in bytes
  *
@@ -196,7 +194,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
 
 /**
  * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command.
- * @ha: HA context
+ * @vha: HA context
  * @fcport: fcport entry to updated
  *
  * Returns 0 on success.
@@ -283,7 +281,7 @@ qla2x00_gid_pt_rsp_size(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * NOTE: Non-Nx_Ports are not requested.
@@ -371,7 +369,7 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
 
 /**
  * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * Returns 0 on success.
@@ -441,7 +439,7 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
 
 /**
  * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * Returns 0 on success.
@@ -583,7 +581,7 @@ static void qla2x00_async_sns_sp_done(void *s, int rc)
 
 /**
  * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -675,7 +673,8 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id)
 
 /**
  * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA.
- * @ha: HA context
+ * @vha: HA context
+ * @type: not used
  *
  * Returns 0 on success.
  */
@@ -769,7 +768,7 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id,
 
 /**
  * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -874,7 +873,7 @@ qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn, size_t size)
 
 /**
  * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -970,7 +969,7 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
- * @ha: HA context
+ * @vha: HA context
  * @cmd: GS command
  * @scmd_len: Subcommand length
  * @data_size: response size in bytes
@@ -1003,7 +1002,7 @@ qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len,
 
 /**
  * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command.
- * @ha: HA context
+ * @vha: HA context
  * @fcport: fcport entry to updated
  *
  * This command uses the old Exectute SNS Command mailbox routine.
@@ -1067,7 +1066,7 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
 
 /**
  * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * This command uses the old Exectute SNS Command mailbox routine.
@@ -1140,7 +1139,7 @@ qla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
 
 /**
  * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * This command uses the old Exectute SNS Command mailbox routine.
@@ -1196,7 +1195,7 @@ qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
 
 /**
  * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * This command uses the old Exectute SNS Command mailbox routine.
@@ -1259,7 +1258,7 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
 
 /**
  * qla2x00_snd_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA.
- * @ha: HA context
+ * @vha: HA context
  *
  * This command uses the old Exectute SNS Command mailbox routine.
  *
@@ -1308,8 +1307,7 @@ qla2x00_sns_rft_id(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA.
- * HBA.
- * @ha: HA context
+ * @vha: HA context
  *
  * This command uses the old Exectute SNS Command mailbox routine.
  *
@@ -1365,7 +1363,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_mgmt_svr_login() - Login to fabric Management Service.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -1401,7 +1399,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
- * @ha: HA context
+ * @vha: HA context
  * @req_size: request size in bytes
  * @rsp_size: response size in bytes
  *
@@ -1439,7 +1437,7 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
 
 /**
  * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
- * @ha: HA context
+ * @vha: HA context
  * @req_size: request size in bytes
  * @rsp_size: response size in bytes
  *
@@ -1496,7 +1494,7 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
 
 /**
  * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
- * @ct_req: CT request buffer
+ * @p: CT request buffer
  * @cmd: GS command
  * @rsp_size: response size in bytes
  *
@@ -1518,8 +1516,8 @@ qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd,
 }
 
 /**
- * qla2x00_fdmi_rhba() -
- * @ha: HA context
+ * qla2x00_fdmi_rhba() - perform RHBA FDMI registration
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -1728,8 +1726,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
 }
 
 /**
- * qla2x00_fdmi_rpa() -
- * @ha: HA context
+ * qla2x00_fdmi_rpa() - perform RPA registration
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -1940,8 +1938,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
 }
 
 /**
- * qla2x00_fdmiv2_rhba() -
- * @ha: HA context
+ * qla2x00_fdmiv2_rhba() - perform RHBA FDMI v2 registration
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2257,7 +2255,7 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_fdmi_dhba() -
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2305,7 +2303,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_fdmiv2_rpa() -
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2635,7 +2633,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_fdmi_register() -
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2693,7 +2691,7 @@ qla2x00_fdmi_register(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * Returns 0 on success.
@@ -2778,7 +2776,7 @@ qla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd,
 
 /**
  * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  * Returns 0 on success.
@@ -2892,7 +2890,7 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
 /**
  * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query.
  *
- * @ha: HA context
+ * @vha: HA context
  * @list: switch info entries to populate
  *
  */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index aececf664654..3640ee4d42de 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -59,8 +59,6 @@ qla2x00_sp_timeout(struct timer_list *t)
 	req->outstanding_cmds[sp->handle] = NULL;
 	iocb = &sp->u.iocb_cmd;
 	iocb->timeout(sp);
-	if (sp->type != SRB_ELS_DCMD)
-		sp->free(sp);
 	spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 }
 
@@ -102,7 +100,6 @@ qla2x00_async_iocb_timeout(void *data)
 	srb_t *sp = data;
 	fc_port_t *fcport = sp->fcport;
 	struct srb_iocb *lio = &sp->u.iocb_cmd;
-	struct event_arg ea;
 
 	if (fcport) {
 		ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
@@ -117,25 +114,13 @@ qla2x00_async_iocb_timeout(void *data)
 
 	switch (sp->type) {
 	case SRB_LOGIN_CMD:
-		if (!fcport)
-			break;
 		/* Retry as needed. */
 		lio->u.logio.data[0] = MBS_COMMAND_ERROR;
 		lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
 			QLA_LOGIO_LOGIN_RETRIED : 0;
-		memset(&ea, 0, sizeof(ea));
-		ea.event = FCME_PLOGI_DONE;
-		ea.fcport = sp->fcport;
-		ea.data[0] = lio->u.logio.data[0];
-		ea.data[1] = lio->u.logio.data[1];
-		ea.sp = sp;
-		qla24xx_handle_plogi_done_event(fcport->vha, &ea);
+		sp->done(sp, QLA_FUNCTION_TIMEOUT);
 		break;
 	case SRB_LOGOUT_CMD:
-		if (!fcport)
-			break;
-		qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT);
-		break;
 	case SRB_CT_PTHRU_CMD:
 	case SRB_MB_IOCB:
 	case SRB_NACK_PLOGI:
@@ -235,12 +220,10 @@ static void
 qla2x00_async_logout_sp_done(void *ptr, int res)
 {
 	srb_t *sp = ptr;
-	struct srb_iocb *lio = &sp->u.iocb_cmd;
 
 	sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
-	if (!test_bit(UNLOADING, &sp->vha->dpc_flags))
-		qla2x00_post_async_logout_done_work(sp->vha, sp->fcport,
-		    lio->u.logio.data);
+	sp->fcport->login_gen++;
+	qlt_logo_completion_handler(sp->fcport, res);
 	sp->free(sp);
 }
 
@@ -2046,7 +2029,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
 
 /**
  * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2077,7 +2060,7 @@ qla2100_pci_config(scsi_qla_host_t *vha)
 
 /**
  * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2159,7 +2142,7 @@ qla2300_pci_config(scsi_qla_host_t *vha)
 
 /**
  * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2203,7 +2186,7 @@ qla24xx_pci_config(scsi_qla_host_t *vha)
 
 /**
  * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2234,7 +2217,7 @@ qla25xx_pci_config(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_isp_firmware() - Choose firmware image.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2270,7 +2253,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_reset_chip() - Reset ISP chip.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2414,6 +2397,7 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
 
 /**
  * qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC.
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2430,7 +2414,7 @@ qla81xx_reset_mpi(scsi_qla_host_t *vha)
 
 /**
  * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2645,7 +2629,7 @@ qla25xx_manipulate_risc_semaphore(scsi_qla_host_t *vha)
 
 /**
  * qla24xx_reset_chip() - Reset ISP24xx chip.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2669,7 +2653,7 @@ qla24xx_reset_chip(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_chip_diag() - Test chip for proper operation.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2688,8 +2672,8 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
 	/* Assume a failed state */
 	rval = QLA_FUNCTION_FAILED;
 
-	ql_dbg(ql_dbg_init, vha, 0x007b,
-	    "Testing device at %lx.\n", (u_long)&reg->flash_address);
+	ql_dbg(ql_dbg_init, vha, 0x007b, "Testing device at %p.\n",
+	       &reg->flash_address);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -2793,7 +2777,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
 
 /**
  * qla24xx_chip_diag() - Test ISP24xx for proper operation.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -3261,7 +3245,7 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_setup_chip() - Load and start RISC firmware.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -3416,7 +3400,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_init_response_q_entries() - Initializes response queue entries.
- * @ha: HA context
+ * @rsp: response queue
  *
  * Beginning of request ring has initialization control block already built
  * by nvram config routine.
@@ -3441,7 +3425,7 @@ qla2x00_init_response_q_entries(struct rsp_que *rsp)
 
 /**
  * qla2x00_update_fw_options() - Read and process firmware options.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -3704,7 +3688,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
 
 /**
  * qla2x00_init_rings() - Initializes firmware.
- * @ha: HA context
+ * @vha: HA context
  *
  * Beginning of request ring has initialization control block already built
  * by nvram config routine.
@@ -3812,7 +3796,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 
 /**
  * qla2x00_fw_ready() - Waits for firmware ready.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -4480,7 +4464,7 @@ qla2x00_rport_del(void *data)
 
 /**
  * qla2x00_alloc_fcport() - Allocate a generic fcport.
- * @ha: HA context
+ * @vha: HA context
  * @flags: allocation flags
  *
  * Returns a pointer to the allocated fcport, or NULL, if none available.
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 4d32426393c7..b7a05aebf065 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -10,6 +10,7 @@
  * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
  * Continuation Type 1 IOCBs to allocate.
  *
+ * @vha: HA context
  * @dsds: number of data segment decriptors needed
  *
  * Returns the number of IOCB entries needed to store @dsds.
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 1b62e943ec49..32ee4182a86b 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -14,7 +14,7 @@
 
 /**
  * qla2x00_get_cmd_direction() - Determine control_flag data direction.
- * @cmd: SCSI command
+ * @sp: SCSI command
  *
  * Returns the proper CF_* direction based on CDB.
  */
@@ -86,7 +86,7 @@ qla2x00_calc_iocbs_64(uint16_t dsds)
 
 /**
  * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns a pointer to the Continuation Type 0 IOCB packet.
  */
@@ -114,7 +114,8 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha)
 
 /**
  * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB.
- * @ha: HA context
+ * @vha: HA context
+ * @req: request queue
  *
  * Returns a pointer to the continuation type 1 IOCB packet.
  */
@@ -445,6 +446,8 @@ qla2x00_start_scsi(srb_t *sp)
 
 /**
  * qla2x00_start_iocbs() - Execute the IOCB command
+ * @vha: HA context
+ * @req: request queue
  */
 void
 qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
@@ -486,7 +489,9 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
 
 /**
  * qla2x00_marker() - Send a marker IOCB to the firmware.
- * @ha: HA context
+ * @vha: HA context
+ * @req: request queue
+ * @rsp: response queue
  * @loop_id: loop ID
  * @lun: LUN
  * @type: marker modifier
@@ -1190,6 +1195,8 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
  * @sp: SRB command to process
  * @cmd_pkt: Command type 3 IOCB
  * @tot_dsds: Total number of segments to transfer
+ * @tot_prot_dsds:
+ * @fw_prot_opts:
  */
 inline int
 qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
@@ -3275,12 +3282,11 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
 	memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
 	abt_iocb->entry_type = ABORT_IOCB_TYPE;
 	abt_iocb->entry_count = 1;
-	abt_iocb->handle =
-	     cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no,
-		 aio->u.abt.cmd_hndl));
+	abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
 	abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
 	abt_iocb->handle_to_abort =
-	    cpu_to_le32(MAKE_HANDLE(req->id, aio->u.abt.cmd_hndl));
+	    cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no,
+				    aio->u.abt.cmd_hndl));
 	abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
 	abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
 	abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 14109d86c3f6..79f538448364 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -259,7 +259,7 @@ qla2300_intr_handler(int irq, void *dev_id)
 
 /**
  * qla2x00_mbx_completion() - Process mailbox command completions.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
  * @mb0: Mailbox0 register
  */
 static void
@@ -272,7 +272,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	/* Read all mbox registers? */
-	mboxes = (1 << ha->mbx_count) - 1;
+	WARN_ON_ONCE(ha->mbx_count > 32);
+	mboxes = (1ULL << ha->mbx_count) - 1;
 	if (!ha->mcp)
 		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
 	else
@@ -612,7 +613,8 @@ qla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id,
 
 /**
  * qla2x00_async_event() - Process aynchronous events.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  * @mb: Mailbox registers (0 - 3)
  */
 void
@@ -1255,7 +1257,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 
 /**
  * qla2x00_process_completed_request() - Process a Fast Post response.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @req: request queue
  * @index: SRB index
  */
 void
@@ -1969,7 +1972,7 @@ static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
 
 /**
  * qla2x00_process_response_queue() - Process response queue entries.
- * @ha: SCSI driver HA context
+ * @rsp: response queue
  */
 void
 qla2x00_process_response_queue(struct rsp_que *rsp)
@@ -2373,7 +2376,8 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
 
 /**
  * qla2x00_status_entry() - Process a Status IOCB entry.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  * @pkt: Entry pointer
  */
 static void
@@ -2750,7 +2754,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
 /**
  * qla2x00_status_cont_entry() - Process a Status Continuations entry.
- * @ha: SCSI driver HA context
+ * @rsp: response queue
  * @pkt: Entry pointer
  *
  * Extended sense data.
@@ -2808,7 +2812,8 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 
 /**
  * qla2x00_error_entry() - Process an error entry.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  * @pkt: Entry pointer
  * return : 1=allow further error analysis. 0=no additional error analysis.
  */
@@ -2867,7 +2872,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
 
 /**
  * qla24xx_mbx_completion() - Process mailbox command completions.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
  * @mb0: Mailbox0 register
  */
 static void
@@ -2880,7 +2885,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
 	/* Read all mbox registers? */
-	mboxes = (1 << ha->mbx_count) - 1;
+	WARN_ON_ONCE(ha->mbx_count > 32);
+	mboxes = (1ULL << ha->mbx_count) - 1;
 	if (!ha->mcp)
 		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
 	else
@@ -2935,7 +2941,8 @@ void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
 
 /**
  * qla24xx_process_response_queue() - Process response queue entries.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  */
 void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 	struct rsp_que *rsp)
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 7397aeddd96c..41b0ee47c6a1 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3385,7 +3385,10 @@ qla8044_read_serdes_word(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data)
 
 /**
  * qla2x00_set_serdes_params() -
- * @ha: HA context
+ * @vha: HA context
+ * @sw_em_1g:
+ * @sw_em_2g:
+ * @sw_em_4g:
  *
  * Returns
  */
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index d5da3981cefe..7113acf42ff3 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -490,7 +490,7 @@ qlafx00_mbx_reg_test(scsi_qla_host_t *vha)
 
 /**
  * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -519,9 +519,9 @@ qlafx00_pci_config(scsi_qla_host_t *vha)
 
 /**
  * qlafx00_warm_reset() - Perform warm reset of iSA(CPUs being reset on SOC).
- * @ha: HA context
+ * @vha: HA context
  *
-  */
+ */
 static inline void
 qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
 {
@@ -625,7 +625,7 @@ qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
 
 /**
  * qlafx00_soft_reset() - Soft Reset ISPFx00.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -644,7 +644,7 @@ qlafx00_soft_reset(scsi_qla_host_t *vha)
 
 /**
  * qlafx00_chip_diag() - Test ISPFx00 for proper operation.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -1408,7 +1408,7 @@ qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp)
 
 /**
  * qlafx00_init_response_q_entries() - Initializes response queue entries.
- * @ha: HA context
+ * @rsp: response queue
  *
  * Beginning of request ring has initialization control block already built
  * by nvram config routine.
@@ -2269,7 +2269,8 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
 
 /**
  * qlafx00_status_entry() - Process a Status IOCB entry.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  * @pkt: Entry pointer
  */
 static void
@@ -2542,7 +2543,7 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
 /**
  * qlafx00_status_cont_entry() - Process a Status Continuations entry.
- * @ha: SCSI driver HA context
+ * @rsp: response queue
  * @pkt: Entry pointer
  *
  * Extended sense data.
@@ -2620,7 +2621,9 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 
 /**
  * qlafx00_multistatus_entry() - Process Multi response queue entries.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
+ * @pkt:
  */
 static void
 qlafx00_multistatus_entry(struct scsi_qla_host *vha,
@@ -2674,8 +2677,11 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
 
 /**
  * qlafx00_error_entry() - Process an error entry.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  * @pkt: Entry pointer
+ * @estatus:
+ * @etype:
  */
 static void
 qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
@@ -2705,7 +2711,8 @@ qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
 
 /**
  * qlafx00_process_response_queue() - Process response queue entries.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
+ * @rsp: response queue
  */
 static void
 qlafx00_process_response_queue(struct scsi_qla_host *vha,
@@ -2781,7 +2788,7 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
 
 /**
  * qlafx00_async_event() - Process aynchronous events.
- * @ha: SCSI driver HA context
+ * @vha: SCSI driver HA context
  */
 static void
 qlafx00_async_event(scsi_qla_host_t *vha)
@@ -2857,10 +2864,9 @@ qlafx00_async_event(scsi_qla_host_t *vha)
 }
 
 /**
- *
  * qlafx00x_mbx_completion() - Process mailbox command completions.
- * @ha: SCSI driver HA context
- * @mb16: Mailbox16 register
+ * @vha: SCSI driver HA context
+ * @mb0:
  */
 static void
 qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index a77c33987703..872d66dd79cd 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1732,7 +1732,7 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
 
 /**
  * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
 */
@@ -1753,7 +1753,7 @@ qla82xx_pci_config(scsi_qla_host_t *vha)
 
 /**
  * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers.
- * @ha: HA context
+ * @vha: HA context
  *
  * Returns 0 on success.
  */
@@ -2008,11 +2008,10 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 		    "MBX pointer ERROR.\n");
 }
 
-/*
+/**
  * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
  * @irq:
  * @dev_id: SCSI driver HA context
- * @regs:
  *
  * Called by system whenever the host adapter generates an interrupt.
  *
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index 525ac35a757b..3a2b0282df14 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -280,9 +280,8 @@ qla8044_clear_qsnt_ready(struct scsi_qla_host *vha)
 }
 
 /**
- *
  * qla8044_lock_recovery - Recovers the idc_lock.
- * @ha : Pointer to adapter structure
+ * @vha : Pointer to adapter structure
  *
  * Lock Recovery Register
  * 5-2	Lock recovery owner: Function ID of driver doing lock recovery,
@@ -1639,10 +1638,10 @@ qla8044_set_rst_ready(struct scsi_qla_host *vha)
 
 /**
  * qla8044_need_reset_handler - Code to start reset sequence
- * @ha: pointer to adapter structure
+ * @vha: pointer to adapter structure
  *
  * Note: IDC lock must be held upon entry
- **/
+ */
 static void
 qla8044_need_reset_handler(struct scsi_qla_host *vha)
 {
@@ -1859,8 +1858,8 @@ qla8044_update_idc_reg(struct scsi_qla_host *vha)
 
 /**
  * qla8044_need_qsnt_handler - Code to start qsnt
- * @ha: pointer to adapter structure
- **/
+ * @vha: pointer to adapter structure
+ */
 static void
 qla8044_need_qsnt_handler(struct scsi_qla_host *vha)
 {
@@ -2031,10 +2030,10 @@ qla8044_device_state_handler(struct scsi_qla_host *vha)
 
 /**
  * qla4_8xxx_check_temp - Check the ISP82XX temperature.
- * @ha: adapter block pointer.
+ * @vha: adapter block pointer.
  *
  * Note: The caller should not hold the idc lock.
- **/
+ */
 static int
 qla8044_check_temp(struct scsi_qla_host *vha)
 {
@@ -2071,10 +2070,10 @@ int qla8044_read_temperature(scsi_qla_host_t *vha)
 
 /**
  * qla8044_check_fw_alive  - Check firmware health
- * @ha: Pointer to host adapter structure.
+ * @vha: Pointer to host adapter structure.
  *
  * Context: Interrupt
- **/
+ */
 int
 qla8044_check_fw_alive(struct scsi_qla_host *vha)
 {
diff --git a/drivers/scsi/qla2xxx/qla_nx2.h b/drivers/scsi/qla2xxx/qla_nx2.h
index 83c1b7e17c80..8ba7c1db07c3 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.h
+++ b/drivers/scsi/qla2xxx/qla_nx2.h
@@ -23,10 +23,6 @@
 #define MD_MIU_TEST_AGT_WRDATA_HI		0x410000A4
 #define MD_MIU_TEST_AGT_WRDATA_ULO		0x410000B0
 #define MD_MIU_TEST_AGT_WRDATA_UHI		0x410000B4
-#define MD_MIU_TEST_AGT_RDDATA_LO		0x410000A8
-#define MD_MIU_TEST_AGT_RDDATA_HI		0x410000AC
-#define MD_MIU_TEST_AGT_RDDATA_ULO		0x410000B8
-#define MD_MIU_TEST_AGT_RDDATA_UHI		0x410000BC
 
 /* MIU_TEST_AGT_CTRL flags. work for SIU as well */
 #define MIU_TA_CTL_WRITE_ENABLE	(MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE)
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 12ee6e02d146..afcb5567998a 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3625,6 +3625,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
 	}
 	qla2x00_wait_for_hba_ready(base_vha);
 
+	qla2x00_wait_for_sess_deletion(base_vha);
+
 	/*
 	 * if UNLOAD flag is already set, then continue unload,
 	 * where it was set first.
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index d2db86ea06b2..04458eb19d38 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -2226,6 +2226,7 @@ qla2x00_erase_flash_sector(struct qla_hw_data *ha, uint32_t addr,
 
 /**
  * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip.
+ * @ha:
  * @man_id: Flash manufacturer ID
  * @flash_id: Flash ID
  */
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index fc89af8fe256..79285ad35e24 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -4871,8 +4871,6 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 				    sess);
 				qlt_send_term_imm_notif(vha, iocb, 1);
 				res = 0;
-				spin_lock_irqsave(&tgt->ha->tgt.sess_lock,
-				    flags);
 				break;
 			}
 
@@ -6299,10 +6297,11 @@ static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn,
 /**
  * qla_tgt_lport_register - register lport with external module
  *
- * @qla_tgt_ops: Pointer for tcm_qla2xxx qla_tgt_ops
- * @wwpn: Passwd FC target WWPN
- * @callback:  lport initialization callback for tcm_qla2xxx code
  * @target_lport_ptr: pointer for tcm_qla2xxx specific lport data
+ * @phys_wwpn:
+ * @npiv_wwpn:
+ * @npiv_wwnn:
+ * @callback:  lport initialization callback for tcm_qla2xxx code
  */
 int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
 		       u64 npiv_wwpn, u64 npiv_wwnn,
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index fc233717355f..817f312023a9 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -168,6 +168,8 @@
 #define DEV_DB_NON_PERSISTENT	0
 #define DEV_DB_PERSISTENT	1
 
+#define QL4_ISP_REG_DISCONNECT 0xffffffffU
+
 #define COPY_ISID(dst_isid, src_isid) {			\
 	int i, j;					\
 	for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;)	\
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 968bd85610f8..43f73583ef5c 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -45,6 +45,8 @@ qla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off)
 	return NULL;
 }
 
+static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8,
+				0x410000AC, 0x410000B8, 0x410000BC };
 #define MAX_CRB_XFORM 60
 static unsigned long crb_addr_xform[MAX_CRB_XFORM];
 static int qla4_8xxx_crb_table_initialized;
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
index 337d9fcf6417..98fe78613eb7 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.h
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -1022,11 +1022,4 @@ struct qla8xxx_minidump_entry_queue {
 #define MD_MIU_TEST_AGT_WRDATA_ULO		0x410000B0
 #define MD_MIU_TEST_AGT_WRDATA_UHI		0x410000B4
 
-#define MD_MIU_TEST_AGT_RDDATA_LO		0x410000A8
-#define MD_MIU_TEST_AGT_RDDATA_HI		0x410000AC
-#define MD_MIU_TEST_AGT_RDDATA_ULO		0x410000B8
-#define MD_MIU_TEST_AGT_RDDATA_UHI		0x410000BC
-
-static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8,
-				0x410000AC, 0x410000B8, 0x410000BC };
 #endif
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 82e889bbe0ed..fc2c97d9a0d6 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -262,6 +262,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha)
+{
+	u32 reg_val = 0;
+	int rval = QLA_SUCCESS;
+
+	if (is_qla8022(ha))
+		reg_val = readl(&ha->qla4_82xx_reg->host_status);
+	else if (is_qla8032(ha) || is_qla8042(ha))
+		reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
+	else
+		reg_val = readw(&ha->reg->ctrl_status);
+
+	if (reg_val == QL4_ISP_REG_DISCONNECT)
+		rval = QLA_ERROR;
+
+	return rval;
+}
+
 static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
 			     uint32_t iface_type, uint32_t payload_size,
 			     uint32_t pid, struct sockaddr *dst_addr)
@@ -9186,10 +9204,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
 	struct srb *srb = NULL;
 	int ret = SUCCESS;
 	int wait = 0;
+	int rval;
 
 	ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n",
 		   ha->host_no, id, lun, cmd, cmd->cmnd[0]);
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	srb = (struct srb *) CMD_SP(cmd);
 	if (!srb) {
@@ -9241,6 +9266,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
 	int ret = FAILED, stat;
+	int rval;
 
 	if (!ddb_entry)
 		return ret;
@@ -9260,6 +9286,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
 		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	/* FIXME: wait for hba to go online */
 	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
 	if (stat != QLA_SUCCESS) {
@@ -9303,6 +9335,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
 	int stat, ret;
+	int rval;
 
 	if (!ddb_entry)
 		return FAILED;
@@ -9320,6 +9353,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
 		      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	stat = qla4xxx_reset_target(ha, ddb_entry);
 	if (stat != QLA_SUCCESS) {
 		starget_printk(KERN_INFO, scsi_target(cmd->device),
@@ -9374,9 +9413,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
 	int return_status = FAILED;
 	struct scsi_qla_host *ha;
+	int rval;
 
 	ha = to_qla_host(cmd->device->host);
 
+	rval = qla4xxx_isp_check_reg(ha);
+	if (rval != QLA_SUCCESS) {
+		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+		return FAILED;
+	}
+
 	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
 		qla4_83xx_set_idc_dontreset(ha);
 
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 2c146b44d95f..ea88906d2cc5 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -157,6 +157,7 @@ static struct {
 	{ RAID_LEVEL_5, "raid5" },
 	{ RAID_LEVEL_50, "raid50" },
 	{ RAID_LEVEL_6, "raid6" },
+	{ RAID_LEVEL_JBOD, "jbod" },
 };
 
 static const char *raid_level_name(enum raid_level level)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index a5986dae9020..26ce022dd6f4 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -6,7 +6,7 @@
  *  anything out of the ordinary is seen.
  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *
- * Copyright (C) 2001 - 2017 Douglas Gilbert
+ * Copyright (C) 2001 - 2018 Douglas Gilbert
  *
  * 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
@@ -61,8 +61,8 @@
 #include "scsi_logging.h"
 
 /* make sure inq_product_rev string corresponds to this version */
-#define SDEBUG_VERSION "0187"	/* format to fit INQUIRY revision field */
-static const char *sdebug_version_date = "20171202";
+#define SDEBUG_VERSION "0188"	/* format to fit INQUIRY revision field */
+static const char *sdebug_version_date = "20180128";
 
 #define MY_NAME "scsi_debug"
 
@@ -234,6 +234,7 @@ static const char *sdebug_version_date = "20171202";
 #define F_INV_OP		0x200
 #define F_FAKE_RW		0x400
 #define F_M_ACCESS		0x800	/* media access */
+#define F_LONG_DELAY		0x1000
 
 #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
 #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
@@ -349,7 +350,7 @@ enum sdeb_opcode_index {
 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
 	SDEB_I_WRITE_BUFFER = 26,
 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
-	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
+	SDEB_I_SYNC_CACHE = 28,		/* 10, 16 */
 	SDEB_I_COMP_WRITE = 29,
 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last (previous + 1) */
 };
@@ -382,7 +383,7 @@ static const unsigned char opcode_ind_arr[256] = {
 /* 0x80; 0x80->0x9f: 16 byte cdbs */
 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
-	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
+	0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
 /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
@@ -398,6 +399,14 @@ static const unsigned char opcode_ind_arr[256] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 };
 
+/*
+ * The following "response" functions return the SCSI mid-level's 4 byte
+ * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
+ * command completion, they can mask their return value with
+ * SDEG_RES_IMMED_MASK .
+ */
+#define SDEG_RES_IMMED_MASK 0x40000000
+
 static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
@@ -420,6 +429,7 @@ static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
 
 /*
  * The following are overflow arrays for cdbs that "hit" the same index in
@@ -499,6 +509,12 @@ static const struct opcode_info_t release_iarr[] = {
 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 };
 
+static const struct opcode_info_t sync_cache_iarr[] = {
+	{0, 0x91, 0, F_LONG_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
+	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
+};
+
 
 /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
  * plus the terminating elements for logic that scans this table such as
@@ -536,8 +552,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },		/* WRITE(16) */
-	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
+		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
+	{0, 0x1b, 0, F_LONG_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
@@ -590,9 +606,10 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
 		 0, 0, 0, 0, 0} },
-	{0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
+	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_LONG_DELAY | F_M_ACCESS,
+	    resp_sync_cache, sync_cache_iarr,
 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
-	     0, 0, 0, 0} },
+	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
@@ -616,6 +633,8 @@ static unsigned int sdebug_guard = DEF_GUARD;
 static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
 static int sdebug_max_luns = DEF_MAX_LUNS;
 static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
+static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
+static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
 static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
 static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
 static int sdebug_no_lun_0 = DEF_NO_LUN_0;
@@ -649,7 +668,6 @@ static bool sdebug_any_injecting_opt;
 static bool sdebug_verbose;
 static bool have_dif_prot;
 static bool sdebug_statistics = DEF_STATISTICS;
-static bool sdebug_mq_active;
 
 static unsigned int sdebug_store_sectors;
 static sector_t sdebug_capacity;	/* in sectors */
@@ -1155,8 +1173,8 @@ static int inquiry_vpd_84(unsigned char *arr)
 static int inquiry_vpd_85(unsigned char *arr)
 {
 	int num = 0;
-	const char * na1 = "https://www.kernel.org/config";
-	const char * na2 = "http://www.kernel.org/log";
+	const char *na1 = "https://www.kernel.org/config";
+	const char *na2 = "http://www.kernel.org/log";
 	int plen, olen;
 
 	arr[num++] = 0x1;	/* lu, storage config */
@@ -1372,7 +1390,7 @@ static int inquiry_vpd_b2(unsigned char *arr)
 static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
 	unsigned char pq_pdt;
-	unsigned char * arr;
+	unsigned char *arr;
 	unsigned char *cmd = scp->cmnd;
 	int alloc_len, n, ret;
 	bool have_wlun, is_disk;
@@ -1523,10 +1541,10 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
 				   0, 0, 0x0, 0x0};
 
-static int resp_requests(struct scsi_cmnd * scp,
-			 struct sdebug_dev_info * devip)
+static int resp_requests(struct scsi_cmnd *scp,
+			 struct sdebug_dev_info *devip)
 {
-	unsigned char * sbuff;
+	unsigned char *sbuff;
 	unsigned char *cmd = scp->cmnd;
 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
 	bool dsense;
@@ -1584,8 +1602,8 @@ static int resp_requests(struct scsi_cmnd * scp,
 	return fill_from_dev_buffer(scp, arr, len);
 }
 
-static int resp_start_stop(struct scsi_cmnd * scp,
-			   struct sdebug_dev_info * devip)
+static int resp_start_stop(struct scsi_cmnd *scp,
+			   struct sdebug_dev_info *devip)
 {
 	unsigned char *cmd = scp->cmnd;
 	int power_cond, stop;
@@ -1597,7 +1615,7 @@ static int resp_start_stop(struct scsi_cmnd * scp,
 	}
 	stop = !(cmd[4] & 1);
 	atomic_xchg(&devip->stopped, stop);
-	return 0;
+	return (cmd[1] & 0x1) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
 }
 
 static sector_t get_sdebug_capacity(void)
@@ -1612,8 +1630,8 @@ static sector_t get_sdebug_capacity(void)
 }
 
 #define SDEBUG_READCAP_ARR_SZ 8
-static int resp_readcap(struct scsi_cmnd * scp,
-			struct sdebug_dev_info * devip)
+static int resp_readcap(struct scsi_cmnd *scp,
+			struct sdebug_dev_info *devip)
 {
 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
 	unsigned int capac;
@@ -1631,8 +1649,8 @@ static int resp_readcap(struct scsi_cmnd * scp,
 }
 
 #define SDEBUG_READCAP16_ARR_SZ 32
-static int resp_readcap16(struct scsi_cmnd * scp,
-			  struct sdebug_dev_info * devip)
+static int resp_readcap16(struct scsi_cmnd *scp,
+			  struct sdebug_dev_info *devip)
 {
 	unsigned char *cmd = scp->cmnd;
 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
@@ -1670,11 +1688,11 @@ static int resp_readcap16(struct scsi_cmnd * scp,
 
 #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
 
-static int resp_report_tgtpgs(struct scsi_cmnd * scp,
-			      struct sdebug_dev_info * devip)
+static int resp_report_tgtpgs(struct scsi_cmnd *scp,
+			      struct sdebug_dev_info *devip)
 {
 	unsigned char *cmd = scp->cmnd;
-	unsigned char * arr;
+	unsigned char *arr;
 	int host_no = devip->sdbg_host->shost->host_no;
 	int n, ret, alen, rlen;
 	int port_group_a, port_group_b, port_a, port_b;
@@ -1926,7 +1944,7 @@ static int resp_rsup_tmfs(struct scsi_cmnd *scp,
 
 /* <<Following mode page info copied from ST318451LW>> */
 
-static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
+static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
 {	/* Read-Write Error Recovery page for mode_sense */
 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
 					5, 0, 0xff, 0xff};
@@ -1937,7 +1955,7 @@ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
 	return sizeof(err_recov_pg);
 }
 
-static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
+static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
 { 	/* Disconnect-Reconnect page for mode_sense */
 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
 					 0, 0, 0, 0, 0, 0, 0, 0};
@@ -1948,7 +1966,7 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
 	return sizeof(disconnect_pg);
 }
 
-static int resp_format_pg(unsigned char * p, int pcontrol, int target)
+static int resp_format_pg(unsigned char *p, int pcontrol, int target)
 {       /* Format device page for mode_sense */
 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
 				     0, 0, 0, 0, 0, 0, 0, 0,
@@ -1968,7 +1986,7 @@ static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
 				     0, 0, 0, 0};
 
-static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
+static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
 { 	/* Caching page for mode_sense */
 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -1988,7 +2006,7 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
 static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
 				    0, 0, 0x2, 0x4b};
 
-static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
 { 	/* Control mode page for mode_sense */
 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
 					0, 0, 0, 0};
@@ -2012,7 +2030,7 @@ static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
 }
 
 
-static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
 {	/* Informational Exceptions control mode page for mode_sense */
 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
 				       0, 0, 0x0, 0x0};
@@ -2027,7 +2045,7 @@ static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
 	return sizeof(iec_m_pg);
 }
 
-static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
 {	/* SAS SSP mode page - short format for mode_sense */
 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
@@ -2039,7 +2057,7 @@ static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
 }
 
 
-static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
+static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
 			      int target_dev_id)
 {	/* SAS phy control and discover mode page for mode_sense */
 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
@@ -2072,7 +2090,7 @@ static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
 	return sizeof(sas_pcd_m_pg);
 }
 
-static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
+static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
 {	/* SAS SSP shared protocol specific port mode subpage */
 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
 		    0, 0, 0, 0, 0, 0, 0, 0,
@@ -2093,7 +2111,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	unsigned char dev_spec;
 	int alloc_len, offset, len, target_dev_id;
 	int target = scp->device->id;
-	unsigned char * ap;
+	unsigned char *ap;
 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
 	unsigned char *cmd = scp->cmnd;
 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
@@ -2324,7 +2342,7 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 	return 0;
 }
 
-static int resp_temp_l_pg(unsigned char * arr)
+static int resp_temp_l_pg(unsigned char *arr)
 {
 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
@@ -2334,7 +2352,7 @@ static int resp_temp_l_pg(unsigned char * arr)
 	return sizeof(temp_l_pg);
 }
 
-static int resp_ie_l_pg(unsigned char * arr)
+static int resp_ie_l_pg(unsigned char *arr)
 {
 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
 		};
@@ -2712,8 +2730,8 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	}
 
 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
-		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
-		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
+		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
+		     ((lba + num) > sdebug_medium_error_start))) {
 		/* claim unrecoverable read error */
 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
 		/* set info field and valid bit for fixed descriptor */
@@ -3562,6 +3580,27 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
 }
 
+static int resp_sync_cache(struct scsi_cmnd *scp,
+			   struct sdebug_dev_info *devip)
+{
+	u64 lba;
+	u32 num_blocks;
+	u8 *cmd = scp->cmnd;
+
+	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
+		lba = get_unaligned_be32(cmd + 2);
+		num_blocks = get_unaligned_be16(cmd + 7);
+	} else {				/* SYNCHRONIZE_CACHE(16) */
+		lba = get_unaligned_be64(cmd + 2);
+		num_blocks = get_unaligned_be32(cmd + 10);
+	}
+	if (lba + num_blocks > sdebug_capacity) {
+		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
+		return check_condition_result;
+	}
+	return (cmd[1] & 0x2) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
+}
+
 #define RL_BUCKET_ELEMS 8
 
 /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
@@ -3727,20 +3766,13 @@ static int resp_xdwriteread_10(struct scsi_cmnd *scp,
 
 static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
 {
-	struct sdebug_queue *sqp = sdebug_q_arr;
+	u32 tag = blk_mq_unique_tag(cmnd->request);
+	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
 
-	if (sdebug_mq_active) {
-		u32 tag = blk_mq_unique_tag(cmnd->request);
-		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
-
-		if (unlikely(hwq >= submit_queues)) {
-			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
-			hwq %= submit_queues;
-		}
-		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
-		return sqp + hwq;
-	} else
-		return sqp;
+	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
+	if (WARN_ON_ONCE(hwq >= submit_queues))
+		hwq = 0;
+	return sdebug_q_arr + hwq;
 }
 
 /* Queued (deferred) command completions converge here. */
@@ -4066,7 +4098,7 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
 	return SUCCESS;
 }
 
-static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
+static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
 {
 	++num_dev_resets;
 	if (SCpnt && SCpnt->device) {
@@ -4118,7 +4150,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
 	return SUCCESS;
 }
 
-static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
+static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
 {
 	struct sdebug_host_info *sdbg_host;
 	struct sdebug_dev_info *devip;
@@ -4151,9 +4183,9 @@ static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
 	return SUCCESS;
 }
 
-static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
+static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
 {
-	struct sdebug_host_info * sdbg_host;
+	struct sdebug_host_info *sdbg_host;
 	struct sdebug_dev_info *devip;
 	int k = 0;
 
@@ -4179,7 +4211,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
 static void __init sdebug_build_parts(unsigned char *ramp,
 				      unsigned long store_size)
 {
-	struct partition * pp;
+	struct partition *pp;
 	int starts[SDEBUG_MAX_PARTS + 2];
 	int sectors_per_part, num_sectors, k;
 	int heads_by_sects, start_sec, end_sec;
@@ -4262,8 +4294,13 @@ static void clear_queue_stats(void)
 static void setup_inject(struct sdebug_queue *sqp,
 			 struct sdebug_queued_cmd *sqcp)
 {
-	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
+	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
+		if (sdebug_every_nth > 0)
+			sqcp->inj_recovered = sqcp->inj_transport
+				= sqcp->inj_dif
+				= sqcp->inj_dix = sqcp->inj_short = 0;
 		return;
+	}
 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
@@ -4278,7 +4315,10 @@ static void setup_inject(struct sdebug_queue *sqp,
  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
  */
 static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
-			 int scsi_result, int delta_jiff, int ndelay)
+			 int scsi_result,
+			 int (*pfp)(struct scsi_cmnd *,
+				    struct sdebug_dev_info *),
+			 int delta_jiff, int ndelay)
 {
 	unsigned long iflags;
 	int k, num_in_q, qdepth, inject;
@@ -4294,9 +4334,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 	}
 	sdp = cmnd->device;
 
-	if (unlikely(sdebug_verbose && scsi_result))
-		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
-			    __func__, scsi_result);
 	if (delta_jiff == 0)
 		goto respond_in_thread;
 
@@ -4351,7 +4388,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 	sqcp = &sqp->qc_arr[k];
 	sqcp->a_cmnd = cmnd;
 	cmnd->host_scribble = (unsigned char *)sqcp;
-	cmnd->result = scsi_result;
 	sd_dp = sqcp->sd_dp;
 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
@@ -4361,6 +4397,22 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 		if (sd_dp == NULL)
 			return SCSI_MLQUEUE_HOST_BUSY;
 	}
+
+	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
+	if (cmnd->result & SDEG_RES_IMMED_MASK) {
+		/*
+		 * This is the F_DELAY_OVERR case. No delay.
+		 */
+		cmnd->result &= ~SDEG_RES_IMMED_MASK;
+		delta_jiff = ndelay = 0;
+	}
+	if (cmnd->result == 0 && scsi_result != 0)
+		cmnd->result = scsi_result;
+
+	if (unlikely(sdebug_verbose && cmnd->result))
+		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
+			    __func__, cmnd->result);
+
 	if (delta_jiff > 0 || ndelay > 0) {
 		ktime_t kt;
 
@@ -4403,7 +4455,10 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 	return 0;
 
 respond_in_thread:	/* call back to mid-layer using invocation thread */
-	cmnd->result = scsi_result;
+	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
+	cmnd->result &= ~SDEG_RES_IMMED_MASK;
+	if (cmnd->result == 0 && scsi_result != 0)
+		cmnd->result = scsi_result;
 	cmnd->scsi_done(cmnd);
 	return 0;
 }
@@ -4440,6 +4495,8 @@ module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
 module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
 module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
 module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
+module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
+module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
 module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
 module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
 module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
@@ -4497,6 +4554,8 @@ MODULE_PARM_DESC(lbprz,
 MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
 MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
 MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
+MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
+MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
 MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
 MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
 MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
@@ -4526,7 +4585,7 @@ MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xff
 #define SDEBUG_INFO_LEN 256
 static char sdebug_info[SDEBUG_INFO_LEN];
 
-static const char * scsi_debug_info(struct Scsi_Host * shp)
+static const char *scsi_debug_info(struct Scsi_Host *shp)
 {
 	int k;
 
@@ -4587,9 +4646,8 @@ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
 		   num_host_resets);
 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
 		   dix_reads, dix_writes, dif_errors);
-	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
-		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
-		   sdebug_mq_active);
+	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
+		   sdebug_statistics);
 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
 		   atomic_read(&sdebug_cmnd_count),
 		   atomic_read(&sdebug_completions),
@@ -5450,7 +5508,7 @@ static void __exit scsi_debug_exit(void)
 device_initcall(scsi_debug_init);
 module_exit(scsi_debug_exit);
 
-static void sdebug_release_adapter(struct device * dev)
+static void sdebug_release_adapter(struct device *dev)
 {
 	struct sdebug_host_info *sdbg_host;
 
@@ -5588,6 +5646,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 	struct sdebug_dev_info *devip;
 	u8 *cmd = scp->cmnd;
 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
+	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
 	int k, na;
 	int errsts = 0;
 	u32 flags;
@@ -5612,13 +5671,8 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 				n += scnprintf(b + n, sb - n, "%02x ",
 					       (u32)cmd[k]);
 		}
-		if (sdebug_mq_active)
-			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
-				    my_name, blk_mq_unique_tag(scp->request),
-				    b);
-		else
-			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
-				    b);
+		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
+			    blk_mq_unique_tag(scp->request), b);
 	}
 	if (fake_host_busy(scp))
 		return SCSI_MLQUEUE_HOST_BUSY;
@@ -5714,20 +5768,30 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 			return 0;	/* ignore command: make trouble */
 	}
 	if (likely(oip->pfp))
-		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
-	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
-		errsts = r_pfp(scp, devip);
+		pfp = oip->pfp;	/* calls a resp_* function */
+	else
+		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
 
 fini:
 	if (F_DELAY_OVERR & flags)
-		return schedule_resp(scp, devip, errsts, 0, 0);
-	else
-		return schedule_resp(scp, devip, errsts, sdebug_jdelay,
+		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
+	else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
+		/*
+		 * If any delay is active, want F_LONG_DELAY to be at least 1
+		 * second and if sdebug_jdelay>0 want a long delay of that
+		 * many seconds.
+		 */
+		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
+
+		jdelay = mult_frac(USER_HZ * jdelay, HZ, USER_HZ);
+		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
+	} else
+		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
 				     sdebug_ndelay);
 check_cond:
-	return schedule_resp(scp, devip, check_condition_result, 0, 0);
+	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
 err_out:
-	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
+	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
 }
 
 static struct scsi_host_template sdebug_driver_template = {
@@ -5757,7 +5821,7 @@ static struct scsi_host_template sdebug_driver_template = {
 	.track_queue_depth =	1,
 };
 
-static int sdebug_driver_probe(struct device * dev)
+static int sdebug_driver_probe(struct device *dev)
 {
 	int error = 0;
 	struct sdebug_host_info *sdbg_host;
@@ -5782,8 +5846,7 @@ static int sdebug_driver_probe(struct device * dev)
 	}
 	/* Decide whether to tell scsi subsystem that we want mq */
 	/* Following should give the same answer for each host */
-	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
-	if (sdebug_mq_active)
+	if (shost_use_blk_mq(hpnt))
 		hpnt->nr_hw_queues = submit_queues;
 
 	sdbg_host->shost = hpnt;
@@ -5855,7 +5918,7 @@ static int sdebug_driver_probe(struct device * dev)
 	return error;
 }
 
-static int sdebug_driver_remove(struct device * dev)
+static int sdebug_driver_remove(struct device *dev)
 {
 	struct sdebug_host_info *sdbg_host;
 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index d042915ce895..96f988a7efda 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -117,6 +117,12 @@ static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
 /**
  * scmd_eh_abort_handler - Handle command aborts
  * @work:	command to be aborted.
+ *
+ * Note: this function must be called only for a command that has timed out.
+ * Because the block layer marks a request as complete before it calls
+ * scsi_times_out(), a .scsi_done() call from the LLD for a command that has
+ * timed out do not have any effect. Hence it is safe to call
+ * scsi_finish_command() from this function.
  */
 void
 scmd_eh_abort_handler(struct work_struct *work)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a86df9ca7d1c..aea5a1ae318b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2607,7 +2607,7 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
 	/* try to eat the UNIT_ATTENTION if there are enough retries */
 	do {
 		result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
-					  timeout, retries, NULL);
+					  timeout, 1, NULL);
 		if (sdev->removable && scsi_sense_valid(sshdr) &&
 		    sshdr->sense_key == UNIT_ATTENTION)
 			sdev->changed = 1;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 91b90f672d23..e56a4ac990c0 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1310,6 +1310,13 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 		}
 	}
 
+	if (sdev->host->hostt->sdev_groups) {
+		error = sysfs_create_groups(&sdev->sdev_gendev.kobj,
+				sdev->host->hostt->sdev_groups);
+		if (error)
+			return error;
+	}
+
 	scsi_autopm_put_device(sdev);
 	return error;
 }
@@ -1349,6 +1356,10 @@ void __scsi_remove_device(struct scsi_device *sdev)
 		if (res != 0)
 			return;
 
+		if (sdev->host->hostt->sdev_groups)
+			sysfs_remove_groups(&sdev->sdev_gendev.kobj,
+					sdev->host->hostt->sdev_groups);
+
 		bsg_unregister_queue(sdev->request_queue);
 		device_unregister(&sdev->sdev_dev);
 		transport_remove_device(dev);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 871ea582029e..2ca150b16764 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -822,11 +822,11 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer)
 	 * fails, the device won't let us write to the echo buffer
 	 * so just return failure */
 	
-	const char spi_test_unit_ready[] = {
+	static const char spi_test_unit_ready[] = {
 		TEST_UNIT_READY, 0, 0, 0, 0, 0
 	};
 
-	const char spi_read_buffer_descriptor[] = {
+	static const char spi_read_buffer_descriptor[] = {
 		READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0
 	};
 
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 40fc7a590e81..6be5ab32c94f 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1657,7 +1657,7 @@ static struct scsi_host_template scsi_driver = {
 	.eh_timed_out =		storvsc_eh_timed_out,
 	.slave_alloc =		storvsc_device_alloc,
 	.slave_configure =	storvsc_device_configure,
-	.cmd_per_lun =		255,
+	.cmd_per_lun =		2048,
 	.this_id =		-1,
 	.use_clustering =	ENABLE_CLUSTERING,
 	/* Make sure we dont get a sg segment crosses a page boundary */
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 5bdcbe8fa958..e68bcdc75bc3 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -608,7 +608,7 @@ static void sym53c416_probe(void)
 	}
 }
 
-int __init sym53c416_detect(struct scsi_host_template *tpnt)
+int sym53c416_detect(struct scsi_host_template *tpnt)
 {
 	unsigned long flags;
 	struct Scsi_Host * shpnt = NULL;
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index ca360daa6a25..378af306fda1 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa
 	 *  Look for the greatest clock divisor that allows an 
 	 *  input speed faster than the period.
 	 */
-	while (div-- > 0)
+	while (--div > 0)
 		if (kpc >= (div_10M[div] << 2)) break;
 
 	/*
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 9310c6c83041..918f5791202d 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -3,6 +3,7 @@
 obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o
 obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o
 obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
-obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
+obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
+ufshcd-core-objs := ufshcd.o ufs-sysfs.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
 obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
new file mode 100644
index 000000000000..cd7174d2d225
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -0,0 +1,739 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Western Digital Corporation
+
+#include <linux/err.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+
+#include "ufs.h"
+#include "ufs-sysfs.h"
+
+static const char *ufschd_uic_link_state_to_string(
+			enum uic_link_state state)
+{
+	switch (state) {
+	case UIC_LINK_OFF_STATE:	return "OFF";
+	case UIC_LINK_ACTIVE_STATE:	return "ACTIVE";
+	case UIC_LINK_HIBERN8_STATE:	return "HIBERN8";
+	default:			return "UNKNOWN";
+	}
+}
+
+static const char *ufschd_ufs_dev_pwr_mode_to_string(
+			enum ufs_dev_pwr_mode state)
+{
+	switch (state) {
+	case UFS_ACTIVE_PWR_MODE:	return "ACTIVE";
+	case UFS_SLEEP_PWR_MODE:	return "SLEEP";
+	case UFS_POWERDOWN_PWR_MODE:	return "POWERDOWN";
+	default:			return "UNKNOWN";
+	}
+}
+
+static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count,
+					     bool rpm)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+	unsigned long flags, value;
+
+	if (kstrtoul(buf, 0, &value))
+		return -EINVAL;
+
+	if (value >= UFS_PM_LVL_MAX)
+		return -EINVAL;
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	if (rpm)
+		hba->rpm_lvl = value;
+	else
+		hba->spm_lvl = value;
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+	return count;
+}
+
+static ssize_t rpm_lvl_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+	int curr_len;
+	u8 lvl;
+
+	curr_len = snprintf(buf, PAGE_SIZE,
+			    "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n",
+			    hba->rpm_lvl,
+			    ufschd_ufs_dev_pwr_mode_to_string(
+				ufs_pm_lvl_states[hba->rpm_lvl].dev_state),
+			    ufschd_uic_link_state_to_string(
+				ufs_pm_lvl_states[hba->rpm_lvl].link_state));
+
+	curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+			     "\nAll available Runtime PM levels info:\n");
+	for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++)
+		curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+				     "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n",
+				    lvl,
+				    ufschd_ufs_dev_pwr_mode_to_string(
+					ufs_pm_lvl_states[lvl].dev_state),
+				    ufschd_uic_link_state_to_string(
+					ufs_pm_lvl_states[lvl].link_state));
+
+	return curr_len;
+}
+
+static ssize_t rpm_lvl_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, true);
+}
+
+static ssize_t spm_lvl_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+	int curr_len;
+	u8 lvl;
+
+	curr_len = snprintf(buf, PAGE_SIZE,
+			    "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n",
+			    hba->spm_lvl,
+			    ufschd_ufs_dev_pwr_mode_to_string(
+				ufs_pm_lvl_states[hba->spm_lvl].dev_state),
+			    ufschd_uic_link_state_to_string(
+				ufs_pm_lvl_states[hba->spm_lvl].link_state));
+
+	curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+			     "\nAll available System PM levels info:\n");
+	for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++)
+		curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+				     "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n",
+				    lvl,
+				    ufschd_ufs_dev_pwr_mode_to_string(
+					ufs_pm_lvl_states[lvl].dev_state),
+				    ufschd_uic_link_state_to_string(
+					ufs_pm_lvl_states[lvl].link_state));
+
+	return curr_len;
+}
+
+static ssize_t spm_lvl_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, false);
+}
+
+static DEVICE_ATTR_RW(rpm_lvl);
+static DEVICE_ATTR_RW(spm_lvl);
+
+static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
+	&dev_attr_rpm_lvl.attr,
+	&dev_attr_spm_lvl.attr,
+	NULL
+};
+
+static const struct attribute_group ufs_sysfs_default_group = {
+	.attrs = ufs_sysfs_ufshcd_attrs,
+};
+
+static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
+				  enum desc_idn desc_id,
+				  u8 desc_index,
+				  u8 param_offset,
+				  u8 *sysfs_buf,
+				  u8 param_size)
+{
+	u8 desc_buf[8] = {0};
+	int ret;
+
+	if (param_size > 8)
+		return -EINVAL;
+
+	ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
+				param_offset, desc_buf, param_size);
+	if (ret)
+		return -EINVAL;
+	switch (param_size) {
+	case 1:
+		ret = sprintf(sysfs_buf, "0x%02X\n", *desc_buf);
+		break;
+	case 2:
+		ret = sprintf(sysfs_buf, "0x%04X\n",
+			get_unaligned_be16(desc_buf));
+		break;
+	case 4:
+		ret = sprintf(sysfs_buf, "0x%08X\n",
+			get_unaligned_be32(desc_buf));
+		break;
+	case 8:
+		ret = sprintf(sysfs_buf, "0x%016llX\n",
+			get_unaligned_be64(desc_buf));
+		break;
+	}
+
+	return ret;
+}
+
+#define UFS_DESC_PARAM(_name, _puname, _duname, _size)			\
+static ssize_t _name##_show(struct device *dev,				\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname,	\
+		0, _duname##_DESC_PARAM##_puname, buf, _size);		\
+}									\
+static DEVICE_ATTR_RO(_name)
+
+#define UFS_DEVICE_DESC_PARAM(_name, _uname, _size)			\
+	UFS_DESC_PARAM(_name, _uname, DEVICE, _size)
+
+UFS_DEVICE_DESC_PARAM(device_type, _DEVICE_TYPE, 1);
+UFS_DEVICE_DESC_PARAM(device_class, _DEVICE_CLASS, 1);
+UFS_DEVICE_DESC_PARAM(device_sub_class, _DEVICE_SUB_CLASS, 1);
+UFS_DEVICE_DESC_PARAM(protocol, _PRTCL, 1);
+UFS_DEVICE_DESC_PARAM(number_of_luns, _NUM_LU, 1);
+UFS_DEVICE_DESC_PARAM(number_of_wluns, _NUM_WLU, 1);
+UFS_DEVICE_DESC_PARAM(boot_enable, _BOOT_ENBL, 1);
+UFS_DEVICE_DESC_PARAM(descriptor_access_enable, _DESC_ACCSS_ENBL, 1);
+UFS_DEVICE_DESC_PARAM(initial_power_mode, _INIT_PWR_MODE, 1);
+UFS_DEVICE_DESC_PARAM(high_priority_lun, _HIGH_PR_LUN, 1);
+UFS_DEVICE_DESC_PARAM(secure_removal_type, _SEC_RMV_TYPE, 1);
+UFS_DEVICE_DESC_PARAM(support_security_lun, _SEC_LU, 1);
+UFS_DEVICE_DESC_PARAM(bkops_termination_latency, _BKOP_TERM_LT, 1);
+UFS_DEVICE_DESC_PARAM(initial_active_icc_level, _ACTVE_ICC_LVL, 1);
+UFS_DEVICE_DESC_PARAM(specification_version, _SPEC_VER, 2);
+UFS_DEVICE_DESC_PARAM(manufacturing_date, _MANF_DATE, 2);
+UFS_DEVICE_DESC_PARAM(manufacturer_id, _MANF_ID, 2);
+UFS_DEVICE_DESC_PARAM(rtt_capability, _RTT_CAP, 1);
+UFS_DEVICE_DESC_PARAM(rtc_update, _FRQ_RTC, 2);
+UFS_DEVICE_DESC_PARAM(ufs_features, _UFS_FEAT, 1);
+UFS_DEVICE_DESC_PARAM(ffu_timeout, _FFU_TMT, 1);
+UFS_DEVICE_DESC_PARAM(queue_depth, _Q_DPTH, 1);
+UFS_DEVICE_DESC_PARAM(device_version, _DEV_VER, 2);
+UFS_DEVICE_DESC_PARAM(number_of_secure_wpa, _NUM_SEC_WPA, 1);
+UFS_DEVICE_DESC_PARAM(psa_max_data_size, _PSA_MAX_DATA, 4);
+UFS_DEVICE_DESC_PARAM(psa_state_timeout, _PSA_TMT, 1);
+
+static struct attribute *ufs_sysfs_device_descriptor[] = {
+	&dev_attr_device_type.attr,
+	&dev_attr_device_class.attr,
+	&dev_attr_device_sub_class.attr,
+	&dev_attr_protocol.attr,
+	&dev_attr_number_of_luns.attr,
+	&dev_attr_number_of_wluns.attr,
+	&dev_attr_boot_enable.attr,
+	&dev_attr_descriptor_access_enable.attr,
+	&dev_attr_initial_power_mode.attr,
+	&dev_attr_high_priority_lun.attr,
+	&dev_attr_secure_removal_type.attr,
+	&dev_attr_support_security_lun.attr,
+	&dev_attr_bkops_termination_latency.attr,
+	&dev_attr_initial_active_icc_level.attr,
+	&dev_attr_specification_version.attr,
+	&dev_attr_manufacturing_date.attr,
+	&dev_attr_manufacturer_id.attr,
+	&dev_attr_rtt_capability.attr,
+	&dev_attr_rtc_update.attr,
+	&dev_attr_ufs_features.attr,
+	&dev_attr_ffu_timeout.attr,
+	&dev_attr_queue_depth.attr,
+	&dev_attr_device_version.attr,
+	&dev_attr_number_of_secure_wpa.attr,
+	&dev_attr_psa_max_data_size.attr,
+	&dev_attr_psa_state_timeout.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_device_descriptor_group = {
+	.name = "device_descriptor",
+	.attrs = ufs_sysfs_device_descriptor,
+};
+
+#define UFS_INTERCONNECT_DESC_PARAM(_name, _uname, _size)		\
+	UFS_DESC_PARAM(_name, _uname, INTERCONNECT, _size)
+
+UFS_INTERCONNECT_DESC_PARAM(unipro_version, _UNIPRO_VER, 2);
+UFS_INTERCONNECT_DESC_PARAM(mphy_version, _MPHY_VER, 2);
+
+static struct attribute *ufs_sysfs_interconnect_descriptor[] = {
+	&dev_attr_unipro_version.attr,
+	&dev_attr_mphy_version.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_interconnect_descriptor_group = {
+	.name = "interconnect_descriptor",
+	.attrs = ufs_sysfs_interconnect_descriptor,
+};
+
+#define UFS_GEOMETRY_DESC_PARAM(_name, _uname, _size)			\
+	UFS_DESC_PARAM(_name, _uname, GEOMETRY, _size)
+
+UFS_GEOMETRY_DESC_PARAM(raw_device_capacity, _DEV_CAP, 8);
+UFS_GEOMETRY_DESC_PARAM(max_number_of_luns, _MAX_NUM_LUN, 1);
+UFS_GEOMETRY_DESC_PARAM(segment_size, _SEG_SIZE, 4);
+UFS_GEOMETRY_DESC_PARAM(allocation_unit_size, _ALLOC_UNIT_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(min_addressable_block_size, _MIN_BLK_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(optimal_read_block_size, _OPT_RD_BLK_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(optimal_write_block_size, _OPT_WR_BLK_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(max_in_buffer_size, _MAX_IN_BUF_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(max_out_buffer_size, _MAX_OUT_BUF_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(rpmb_rw_size, _RPMB_RW_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(dyn_capacity_resource_policy, _DYN_CAP_RSRC_PLC, 1);
+UFS_GEOMETRY_DESC_PARAM(data_ordering, _DATA_ORDER, 1);
+UFS_GEOMETRY_DESC_PARAM(max_number_of_contexts, _MAX_NUM_CTX, 1);
+UFS_GEOMETRY_DESC_PARAM(sys_data_tag_unit_size, _TAG_UNIT_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(sys_data_tag_resource_size, _TAG_RSRC_SIZE, 1);
+UFS_GEOMETRY_DESC_PARAM(secure_removal_types, _SEC_RM_TYPES, 1);
+UFS_GEOMETRY_DESC_PARAM(memory_types, _MEM_TYPES, 2);
+UFS_GEOMETRY_DESC_PARAM(sys_code_memory_max_alloc_units,
+	_SCM_MAX_NUM_UNITS, 4);
+UFS_GEOMETRY_DESC_PARAM(sys_code_memory_capacity_adjustment_factor,
+	_SCM_CAP_ADJ_FCTR, 2);
+UFS_GEOMETRY_DESC_PARAM(non_persist_memory_max_alloc_units,
+	_NPM_MAX_NUM_UNITS, 4);
+UFS_GEOMETRY_DESC_PARAM(non_persist_memory_capacity_adjustment_factor,
+	_NPM_CAP_ADJ_FCTR, 2);
+UFS_GEOMETRY_DESC_PARAM(enh1_memory_max_alloc_units,
+	_ENM1_MAX_NUM_UNITS, 4);
+UFS_GEOMETRY_DESC_PARAM(enh1_memory_capacity_adjustment_factor,
+	_ENM1_CAP_ADJ_FCTR, 2);
+UFS_GEOMETRY_DESC_PARAM(enh2_memory_max_alloc_units,
+	_ENM2_MAX_NUM_UNITS, 4);
+UFS_GEOMETRY_DESC_PARAM(enh2_memory_capacity_adjustment_factor,
+	_ENM2_CAP_ADJ_FCTR, 2);
+UFS_GEOMETRY_DESC_PARAM(enh3_memory_max_alloc_units,
+	_ENM3_MAX_NUM_UNITS, 4);
+UFS_GEOMETRY_DESC_PARAM(enh3_memory_capacity_adjustment_factor,
+	_ENM3_CAP_ADJ_FCTR, 2);
+UFS_GEOMETRY_DESC_PARAM(enh4_memory_max_alloc_units,
+	_ENM4_MAX_NUM_UNITS, 4);
+UFS_GEOMETRY_DESC_PARAM(enh4_memory_capacity_adjustment_factor,
+	_ENM4_CAP_ADJ_FCTR, 2);
+
+static struct attribute *ufs_sysfs_geometry_descriptor[] = {
+	&dev_attr_raw_device_capacity.attr,
+	&dev_attr_max_number_of_luns.attr,
+	&dev_attr_segment_size.attr,
+	&dev_attr_allocation_unit_size.attr,
+	&dev_attr_min_addressable_block_size.attr,
+	&dev_attr_optimal_read_block_size.attr,
+	&dev_attr_optimal_write_block_size.attr,
+	&dev_attr_max_in_buffer_size.attr,
+	&dev_attr_max_out_buffer_size.attr,
+	&dev_attr_rpmb_rw_size.attr,
+	&dev_attr_dyn_capacity_resource_policy.attr,
+	&dev_attr_data_ordering.attr,
+	&dev_attr_max_number_of_contexts.attr,
+	&dev_attr_sys_data_tag_unit_size.attr,
+	&dev_attr_sys_data_tag_resource_size.attr,
+	&dev_attr_secure_removal_types.attr,
+	&dev_attr_memory_types.attr,
+	&dev_attr_sys_code_memory_max_alloc_units.attr,
+	&dev_attr_sys_code_memory_capacity_adjustment_factor.attr,
+	&dev_attr_non_persist_memory_max_alloc_units.attr,
+	&dev_attr_non_persist_memory_capacity_adjustment_factor.attr,
+	&dev_attr_enh1_memory_max_alloc_units.attr,
+	&dev_attr_enh1_memory_capacity_adjustment_factor.attr,
+	&dev_attr_enh2_memory_max_alloc_units.attr,
+	&dev_attr_enh2_memory_capacity_adjustment_factor.attr,
+	&dev_attr_enh3_memory_max_alloc_units.attr,
+	&dev_attr_enh3_memory_capacity_adjustment_factor.attr,
+	&dev_attr_enh4_memory_max_alloc_units.attr,
+	&dev_attr_enh4_memory_capacity_adjustment_factor.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_geometry_descriptor_group = {
+	.name = "geometry_descriptor",
+	.attrs = ufs_sysfs_geometry_descriptor,
+};
+
+#define UFS_HEALTH_DESC_PARAM(_name, _uname, _size)			\
+	UFS_DESC_PARAM(_name, _uname, HEALTH, _size)
+
+UFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1);
+UFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1);
+UFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1);
+
+static struct attribute *ufs_sysfs_health_descriptor[] = {
+	&dev_attr_eol_info.attr,
+	&dev_attr_life_time_estimation_a.attr,
+	&dev_attr_life_time_estimation_b.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_health_descriptor_group = {
+	.name = "health_descriptor",
+	.attrs = ufs_sysfs_health_descriptor,
+};
+
+#define UFS_POWER_DESC_PARAM(_name, _uname, _index)			\
+static ssize_t _name##_index##_show(struct device *dev,			\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_POWER, 0,	\
+		PWR_DESC##_uname##_0 + _index * 2, buf, 2);		\
+}									\
+static DEVICE_ATTR_RO(_name##_index)
+
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 0);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 1);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 2);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 3);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 4);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 5);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 6);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 7);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 8);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 9);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 10);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 11);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 12);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 13);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 14);
+UFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 15);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 0);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 1);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 2);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 3);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 4);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 5);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 6);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 7);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 8);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 9);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 10);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 11);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 12);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 13);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 14);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 15);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 0);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 1);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 2);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 3);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 4);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 5);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 6);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 7);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 8);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 9);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 10);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 11);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 12);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 13);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 14);
+UFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 15);
+
+static struct attribute *ufs_sysfs_power_descriptor[] = {
+	&dev_attr_active_icc_levels_vcc0.attr,
+	&dev_attr_active_icc_levels_vcc1.attr,
+	&dev_attr_active_icc_levels_vcc2.attr,
+	&dev_attr_active_icc_levels_vcc3.attr,
+	&dev_attr_active_icc_levels_vcc4.attr,
+	&dev_attr_active_icc_levels_vcc5.attr,
+	&dev_attr_active_icc_levels_vcc6.attr,
+	&dev_attr_active_icc_levels_vcc7.attr,
+	&dev_attr_active_icc_levels_vcc8.attr,
+	&dev_attr_active_icc_levels_vcc9.attr,
+	&dev_attr_active_icc_levels_vcc10.attr,
+	&dev_attr_active_icc_levels_vcc11.attr,
+	&dev_attr_active_icc_levels_vcc12.attr,
+	&dev_attr_active_icc_levels_vcc13.attr,
+	&dev_attr_active_icc_levels_vcc14.attr,
+	&dev_attr_active_icc_levels_vcc15.attr,
+	&dev_attr_active_icc_levels_vccq0.attr,
+	&dev_attr_active_icc_levels_vccq1.attr,
+	&dev_attr_active_icc_levels_vccq2.attr,
+	&dev_attr_active_icc_levels_vccq3.attr,
+	&dev_attr_active_icc_levels_vccq4.attr,
+	&dev_attr_active_icc_levels_vccq5.attr,
+	&dev_attr_active_icc_levels_vccq6.attr,
+	&dev_attr_active_icc_levels_vccq7.attr,
+	&dev_attr_active_icc_levels_vccq8.attr,
+	&dev_attr_active_icc_levels_vccq9.attr,
+	&dev_attr_active_icc_levels_vccq10.attr,
+	&dev_attr_active_icc_levels_vccq11.attr,
+	&dev_attr_active_icc_levels_vccq12.attr,
+	&dev_attr_active_icc_levels_vccq13.attr,
+	&dev_attr_active_icc_levels_vccq14.attr,
+	&dev_attr_active_icc_levels_vccq15.attr,
+	&dev_attr_active_icc_levels_vccq20.attr,
+	&dev_attr_active_icc_levels_vccq21.attr,
+	&dev_attr_active_icc_levels_vccq22.attr,
+	&dev_attr_active_icc_levels_vccq23.attr,
+	&dev_attr_active_icc_levels_vccq24.attr,
+	&dev_attr_active_icc_levels_vccq25.attr,
+	&dev_attr_active_icc_levels_vccq26.attr,
+	&dev_attr_active_icc_levels_vccq27.attr,
+	&dev_attr_active_icc_levels_vccq28.attr,
+	&dev_attr_active_icc_levels_vccq29.attr,
+	&dev_attr_active_icc_levels_vccq210.attr,
+	&dev_attr_active_icc_levels_vccq211.attr,
+	&dev_attr_active_icc_levels_vccq212.attr,
+	&dev_attr_active_icc_levels_vccq213.attr,
+	&dev_attr_active_icc_levels_vccq214.attr,
+	&dev_attr_active_icc_levels_vccq215.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_power_descriptor_group = {
+	.name = "power_descriptor",
+	.attrs = ufs_sysfs_power_descriptor,
+};
+
+#define UFS_STRING_DESCRIPTOR(_name, _pname)				\
+static ssize_t _name##_show(struct device *dev,				\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	u8 index;							\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	int ret;							\
+	int desc_len = QUERY_DESC_MAX_SIZE;				\
+	u8 *desc_buf;							\
+	desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_ATOMIC);		\
+	if (!desc_buf)							\
+		return -ENOMEM;						\
+	ret = ufshcd_query_descriptor_retry(hba,			\
+		UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE,	\
+		0, 0, desc_buf, &desc_len);				\
+	if (ret) {							\
+		ret = -EINVAL;						\
+		goto out;						\
+	}								\
+	index = desc_buf[DEVICE_DESC_PARAM##_pname];			\
+	memset(desc_buf, 0, QUERY_DESC_MAX_SIZE);			\
+	if (ufshcd_read_string_desc(hba, index, desc_buf,		\
+		QUERY_DESC_MAX_SIZE, true)) {				\
+		ret = -EINVAL;						\
+		goto out;						\
+	}								\
+	ret = snprintf(buf, PAGE_SIZE, "%s\n",				\
+		desc_buf + QUERY_DESC_HDR_SIZE);			\
+out:									\
+	kfree(desc_buf);						\
+	return ret;							\
+}									\
+static DEVICE_ATTR_RO(_name)
+
+UFS_STRING_DESCRIPTOR(manufacturer_name, _MANF_NAME);
+UFS_STRING_DESCRIPTOR(product_name, _PRDCT_NAME);
+UFS_STRING_DESCRIPTOR(oem_id, _OEM_ID);
+UFS_STRING_DESCRIPTOR(serial_number, _SN);
+UFS_STRING_DESCRIPTOR(product_revision, _PRDCT_REV);
+
+static struct attribute *ufs_sysfs_string_descriptors[] = {
+	&dev_attr_manufacturer_name.attr,
+	&dev_attr_product_name.attr,
+	&dev_attr_oem_id.attr,
+	&dev_attr_serial_number.attr,
+	&dev_attr_product_revision.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_string_descriptors_group = {
+	.name = "string_descriptors",
+	.attrs = ufs_sysfs_string_descriptors,
+};
+
+#define UFS_FLAG(_name, _uname)						\
+static ssize_t _name##_show(struct device *dev,				\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	bool flag;							\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	if (ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,		\
+		QUERY_FLAG_IDN##_uname, &flag))				\
+		return -EINVAL;						\
+	return sprintf(buf, "%s\n", flag ? "true" : "false");		\
+}									\
+static DEVICE_ATTR_RO(_name)
+
+UFS_FLAG(device_init, _FDEVICEINIT);
+UFS_FLAG(permanent_wpe, _PERMANENT_WPE);
+UFS_FLAG(power_on_wpe, _PWR_ON_WPE);
+UFS_FLAG(bkops_enable, _BKOPS_EN);
+UFS_FLAG(life_span_mode_enable, _LIFE_SPAN_MODE_ENABLE);
+UFS_FLAG(phy_resource_removal, _FPHYRESOURCEREMOVAL);
+UFS_FLAG(busy_rtc, _BUSY_RTC);
+UFS_FLAG(disable_fw_update, _PERMANENTLY_DISABLE_FW_UPDATE);
+
+static struct attribute *ufs_sysfs_device_flags[] = {
+	&dev_attr_device_init.attr,
+	&dev_attr_permanent_wpe.attr,
+	&dev_attr_power_on_wpe.attr,
+	&dev_attr_bkops_enable.attr,
+	&dev_attr_life_span_mode_enable.attr,
+	&dev_attr_phy_resource_removal.attr,
+	&dev_attr_busy_rtc.attr,
+	&dev_attr_disable_fw_update.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_flags_group = {
+	.name = "flags",
+	.attrs = ufs_sysfs_device_flags,
+};
+
+#define UFS_ATTRIBUTE(_name, _uname)					\
+static ssize_t _name##_show(struct device *dev,				\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	u32 value;							\
+	if (ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,		\
+		QUERY_ATTR_IDN##_uname, 0, 0, &value))			\
+		return -EINVAL;						\
+	return sprintf(buf, "0x%08X\n", value);				\
+}									\
+static DEVICE_ATTR_RO(_name)
+
+UFS_ATTRIBUTE(boot_lun_enabled, _BOOT_LU_EN);
+UFS_ATTRIBUTE(current_power_mode, _POWER_MODE);
+UFS_ATTRIBUTE(active_icc_level, _ACTIVE_ICC_LVL);
+UFS_ATTRIBUTE(ooo_data_enabled, _OOO_DATA_EN);
+UFS_ATTRIBUTE(bkops_status, _BKOPS_STATUS);
+UFS_ATTRIBUTE(purge_status, _PURGE_STATUS);
+UFS_ATTRIBUTE(max_data_in_size, _MAX_DATA_IN);
+UFS_ATTRIBUTE(max_data_out_size, _MAX_DATA_OUT);
+UFS_ATTRIBUTE(reference_clock_frequency, _REF_CLK_FREQ);
+UFS_ATTRIBUTE(configuration_descriptor_lock, _CONF_DESC_LOCK);
+UFS_ATTRIBUTE(max_number_of_rtt, _MAX_NUM_OF_RTT);
+UFS_ATTRIBUTE(exception_event_control, _EE_CONTROL);
+UFS_ATTRIBUTE(exception_event_status, _EE_STATUS);
+UFS_ATTRIBUTE(ffu_status, _FFU_STATUS);
+UFS_ATTRIBUTE(psa_state, _PSA_STATE);
+UFS_ATTRIBUTE(psa_data_size, _PSA_DATA_SIZE);
+
+static struct attribute *ufs_sysfs_attributes[] = {
+	&dev_attr_boot_lun_enabled.attr,
+	&dev_attr_current_power_mode.attr,
+	&dev_attr_active_icc_level.attr,
+	&dev_attr_ooo_data_enabled.attr,
+	&dev_attr_bkops_status.attr,
+	&dev_attr_purge_status.attr,
+	&dev_attr_max_data_in_size.attr,
+	&dev_attr_max_data_out_size.attr,
+	&dev_attr_reference_clock_frequency.attr,
+	&dev_attr_configuration_descriptor_lock.attr,
+	&dev_attr_max_number_of_rtt.attr,
+	&dev_attr_exception_event_control.attr,
+	&dev_attr_exception_event_status.attr,
+	&dev_attr_ffu_status.attr,
+	&dev_attr_psa_state.attr,
+	&dev_attr_psa_data_size.attr,
+	NULL,
+};
+
+static const struct attribute_group ufs_sysfs_attributes_group = {
+	.name = "attributes",
+	.attrs = ufs_sysfs_attributes,
+};
+
+static const struct attribute_group *ufs_sysfs_groups[] = {
+	&ufs_sysfs_default_group,
+	&ufs_sysfs_device_descriptor_group,
+	&ufs_sysfs_interconnect_descriptor_group,
+	&ufs_sysfs_geometry_descriptor_group,
+	&ufs_sysfs_health_descriptor_group,
+	&ufs_sysfs_power_descriptor_group,
+	&ufs_sysfs_string_descriptors_group,
+	&ufs_sysfs_flags_group,
+	&ufs_sysfs_attributes_group,
+	NULL,
+};
+
+#define UFS_LUN_DESC_PARAM(_pname, _puname, _duname, _size)		\
+static ssize_t _pname##_show(struct device *dev,			\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	struct scsi_device *sdev = to_scsi_device(dev);			\
+	struct ufs_hba *hba = shost_priv(sdev->host);			\
+	u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);			\
+	if (!ufs_is_valid_unit_desc_lun(lun))				\
+		return -EINVAL;						\
+	return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname,	\
+		lun, _duname##_DESC_PARAM##_puname, buf, _size);	\
+}									\
+static DEVICE_ATTR_RO(_pname)
+
+#define UFS_UNIT_DESC_PARAM(_name, _uname, _size)			\
+	UFS_LUN_DESC_PARAM(_name, _uname, UNIT, _size)
+
+UFS_UNIT_DESC_PARAM(boot_lun_id, _BOOT_LUN_ID, 1);
+UFS_UNIT_DESC_PARAM(lun_write_protect, _LU_WR_PROTECT, 1);
+UFS_UNIT_DESC_PARAM(lun_queue_depth, _LU_Q_DEPTH, 1);
+UFS_UNIT_DESC_PARAM(psa_sensitive, _PSA_SENSITIVE, 1);
+UFS_UNIT_DESC_PARAM(lun_memory_type, _MEM_TYPE, 1);
+UFS_UNIT_DESC_PARAM(data_reliability, _DATA_RELIABILITY, 1);
+UFS_UNIT_DESC_PARAM(logical_block_size, _LOGICAL_BLK_SIZE, 1);
+UFS_UNIT_DESC_PARAM(logical_block_count, _LOGICAL_BLK_COUNT, 8);
+UFS_UNIT_DESC_PARAM(erase_block_size, _ERASE_BLK_SIZE, 4);
+UFS_UNIT_DESC_PARAM(provisioning_type, _PROVISIONING_TYPE, 1);
+UFS_UNIT_DESC_PARAM(physical_memory_resourse_count, _PHY_MEM_RSRC_CNT, 8);
+UFS_UNIT_DESC_PARAM(context_capabilities, _CTX_CAPABILITIES, 2);
+UFS_UNIT_DESC_PARAM(large_unit_granularity, _LARGE_UNIT_SIZE_M1, 1);
+
+static struct attribute *ufs_sysfs_unit_descriptor[] = {
+	&dev_attr_boot_lun_id.attr,
+	&dev_attr_lun_write_protect.attr,
+	&dev_attr_lun_queue_depth.attr,
+	&dev_attr_psa_sensitive.attr,
+	&dev_attr_lun_memory_type.attr,
+	&dev_attr_data_reliability.attr,
+	&dev_attr_logical_block_size.attr,
+	&dev_attr_logical_block_count.attr,
+	&dev_attr_erase_block_size.attr,
+	&dev_attr_provisioning_type.attr,
+	&dev_attr_physical_memory_resourse_count.attr,
+	&dev_attr_context_capabilities.attr,
+	&dev_attr_large_unit_granularity.attr,
+	NULL,
+};
+
+const struct attribute_group ufs_sysfs_unit_descriptor_group = {
+	.name = "unit_descriptor",
+	.attrs = ufs_sysfs_unit_descriptor,
+};
+
+static ssize_t dyn_cap_needed_attribute_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	u32 value;
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufs_hba *hba = shost_priv(sdev->host);
+	u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);
+
+	if (ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+		QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value))
+		return -EINVAL;
+	return sprintf(buf, "0x%08X\n", value);
+}
+static DEVICE_ATTR_RO(dyn_cap_needed_attribute);
+
+static struct attribute *ufs_sysfs_lun_attributes[] = {
+	&dev_attr_dyn_cap_needed_attribute.attr,
+	NULL,
+};
+
+const struct attribute_group ufs_sysfs_lun_attributes_group = {
+	.attrs = ufs_sysfs_lun_attributes,
+};
+
+void ufs_sysfs_add_nodes(struct device *dev)
+{
+	int ret;
+
+	ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups);
+	if (ret)
+		dev_err(dev,
+			"%s: sysfs groups creation failed (err = %d)\n",
+			__func__, ret);
+}
+
+void ufs_sysfs_remove_nodes(struct device *dev)
+{
+	sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups);
+}
diff --git a/drivers/scsi/ufs/ufs-sysfs.h b/drivers/scsi/ufs/ufs-sysfs.h
new file mode 100644
index 000000000000..e5621e59a432
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-sysfs.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+
+#ifndef __UFS_SYSFS_H__
+#define __UFS_SYSFS_H__
+
+#include <linux/sysfs.h>
+
+#include "ufshcd.h"
+
+void ufs_sysfs_add_nodes(struct device *dev);
+void ufs_sysfs_remove_nodes(struct device *dev);
+
+extern const struct attribute_group ufs_sysfs_unit_descriptor_group;
+extern const struct attribute_group ufs_sysfs_lun_attributes_group;
+#endif
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 54deeb754db5..14e5bf7af0bb 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -130,17 +130,44 @@ enum {
 
 /* Flag idn for Query Requests*/
 enum flag_idn {
-	QUERY_FLAG_IDN_FDEVICEINIT      = 0x01,
-	QUERY_FLAG_IDN_PWR_ON_WPE	= 0x03,
-	QUERY_FLAG_IDN_BKOPS_EN         = 0x04,
+	QUERY_FLAG_IDN_FDEVICEINIT			= 0x01,
+	QUERY_FLAG_IDN_PERMANENT_WPE			= 0x02,
+	QUERY_FLAG_IDN_PWR_ON_WPE			= 0x03,
+	QUERY_FLAG_IDN_BKOPS_EN				= 0x04,
+	QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE		= 0x05,
+	QUERY_FLAG_IDN_PURGE_ENABLE			= 0x06,
+	QUERY_FLAG_IDN_RESERVED2			= 0x07,
+	QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL		= 0x08,
+	QUERY_FLAG_IDN_BUSY_RTC				= 0x09,
+	QUERY_FLAG_IDN_RESERVED3			= 0x0A,
+	QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE	= 0x0B,
 };
 
 /* Attribute idn for Query requests */
 enum attr_idn {
-	QUERY_ATTR_IDN_ACTIVE_ICC_LVL	= 0x03,
-	QUERY_ATTR_IDN_BKOPS_STATUS	= 0x05,
-	QUERY_ATTR_IDN_EE_CONTROL	= 0x0D,
-	QUERY_ATTR_IDN_EE_STATUS	= 0x0E,
+	QUERY_ATTR_IDN_BOOT_LU_EN		= 0x00,
+	QUERY_ATTR_IDN_RESERVED			= 0x01,
+	QUERY_ATTR_IDN_POWER_MODE		= 0x02,
+	QUERY_ATTR_IDN_ACTIVE_ICC_LVL		= 0x03,
+	QUERY_ATTR_IDN_OOO_DATA_EN		= 0x04,
+	QUERY_ATTR_IDN_BKOPS_STATUS		= 0x05,
+	QUERY_ATTR_IDN_PURGE_STATUS		= 0x06,
+	QUERY_ATTR_IDN_MAX_DATA_IN		= 0x07,
+	QUERY_ATTR_IDN_MAX_DATA_OUT		= 0x08,
+	QUERY_ATTR_IDN_DYN_CAP_NEEDED		= 0x09,
+	QUERY_ATTR_IDN_REF_CLK_FREQ		= 0x0A,
+	QUERY_ATTR_IDN_CONF_DESC_LOCK		= 0x0B,
+	QUERY_ATTR_IDN_MAX_NUM_OF_RTT		= 0x0C,
+	QUERY_ATTR_IDN_EE_CONTROL		= 0x0D,
+	QUERY_ATTR_IDN_EE_STATUS		= 0x0E,
+	QUERY_ATTR_IDN_SECONDS_PASSED		= 0x0F,
+	QUERY_ATTR_IDN_CNTX_CONF		= 0x10,
+	QUERY_ATTR_IDN_CORR_PRG_BLK_NUM		= 0x11,
+	QUERY_ATTR_IDN_RESERVED2		= 0x12,
+	QUERY_ATTR_IDN_RESERVED3		= 0x13,
+	QUERY_ATTR_IDN_FFU_STATUS		= 0x14,
+	QUERY_ATTR_IDN_PSA_STATE		= 0x15,
+	QUERY_ATTR_IDN_PSA_DATA_SIZE		= 0x16,
 };
 
 /* Descriptor idn for Query requests */
@@ -154,6 +181,7 @@ enum desc_idn {
 	QUERY_DESC_IDN_RFU_1		= 0x6,
 	QUERY_DESC_IDN_GEOMETRY		= 0x7,
 	QUERY_DESC_IDN_POWER		= 0x8,
+	QUERY_DESC_IDN_HEALTH           = 0x9,
 	QUERY_DESC_IDN_MAX,
 };
 
@@ -169,6 +197,7 @@ enum ufs_desc_def_size {
 	QUERY_DESC_INTERCONNECT_DEF_SIZE	= 0x06,
 	QUERY_DESC_GEOMETRY_DEF_SIZE		= 0x44,
 	QUERY_DESC_POWER_DEF_SIZE		= 0x62,
+	QUERY_DESC_HEALTH_DEF_SIZE		= 0x25,
 };
 
 /* Unit descriptor parameters offsets in bytes*/
@@ -180,6 +209,7 @@ enum unit_desc_param {
 	UNIT_DESC_PARAM_BOOT_LUN_ID		= 0x4,
 	UNIT_DESC_PARAM_LU_WR_PROTECT		= 0x5,
 	UNIT_DESC_PARAM_LU_Q_DEPTH		= 0x6,
+	UNIT_DESC_PARAM_PSA_SENSITIVE		= 0x7,
 	UNIT_DESC_PARAM_MEM_TYPE		= 0x8,
 	UNIT_DESC_PARAM_DATA_RELIABILITY	= 0x9,
 	UNIT_DESC_PARAM_LOGICAL_BLK_SIZE	= 0xA,
@@ -220,6 +250,67 @@ enum device_desc_param {
 	DEVICE_DESC_PARAM_UD_LEN		= 0x1B,
 	DEVICE_DESC_PARAM_RTT_CAP		= 0x1C,
 	DEVICE_DESC_PARAM_FRQ_RTC		= 0x1D,
+	DEVICE_DESC_PARAM_UFS_FEAT		= 0x1F,
+	DEVICE_DESC_PARAM_FFU_TMT		= 0x20,
+	DEVICE_DESC_PARAM_Q_DPTH		= 0x21,
+	DEVICE_DESC_PARAM_DEV_VER		= 0x22,
+	DEVICE_DESC_PARAM_NUM_SEC_WPA		= 0x24,
+	DEVICE_DESC_PARAM_PSA_MAX_DATA		= 0x25,
+	DEVICE_DESC_PARAM_PSA_TMT		= 0x29,
+	DEVICE_DESC_PARAM_PRDCT_REV		= 0x2A,
+};
+
+/* Interconnect descriptor parameters offsets in bytes*/
+enum interconnect_desc_param {
+	INTERCONNECT_DESC_PARAM_LEN		= 0x0,
+	INTERCONNECT_DESC_PARAM_TYPE		= 0x1,
+	INTERCONNECT_DESC_PARAM_UNIPRO_VER	= 0x2,
+	INTERCONNECT_DESC_PARAM_MPHY_VER	= 0x4,
+};
+
+/* Geometry descriptor parameters offsets in bytes*/
+enum geometry_desc_param {
+	GEOMETRY_DESC_PARAM_LEN			= 0x0,
+	GEOMETRY_DESC_PARAM_TYPE		= 0x1,
+	GEOMETRY_DESC_PARAM_DEV_CAP		= 0x4,
+	GEOMETRY_DESC_PARAM_MAX_NUM_LUN		= 0xC,
+	GEOMETRY_DESC_PARAM_SEG_SIZE		= 0xD,
+	GEOMETRY_DESC_PARAM_ALLOC_UNIT_SIZE	= 0x11,
+	GEOMETRY_DESC_PARAM_MIN_BLK_SIZE	= 0x12,
+	GEOMETRY_DESC_PARAM_OPT_RD_BLK_SIZE	= 0x13,
+	GEOMETRY_DESC_PARAM_OPT_WR_BLK_SIZE	= 0x14,
+	GEOMETRY_DESC_PARAM_MAX_IN_BUF_SIZE	= 0x15,
+	GEOMETRY_DESC_PARAM_MAX_OUT_BUF_SIZE	= 0x16,
+	GEOMETRY_DESC_PARAM_RPMB_RW_SIZE	= 0x17,
+	GEOMETRY_DESC_PARAM_DYN_CAP_RSRC_PLC	= 0x18,
+	GEOMETRY_DESC_PARAM_DATA_ORDER		= 0x19,
+	GEOMETRY_DESC_PARAM_MAX_NUM_CTX		= 0x1A,
+	GEOMETRY_DESC_PARAM_TAG_UNIT_SIZE	= 0x1B,
+	GEOMETRY_DESC_PARAM_TAG_RSRC_SIZE	= 0x1C,
+	GEOMETRY_DESC_PARAM_SEC_RM_TYPES	= 0x1D,
+	GEOMETRY_DESC_PARAM_MEM_TYPES		= 0x1E,
+	GEOMETRY_DESC_PARAM_SCM_MAX_NUM_UNITS	= 0x20,
+	GEOMETRY_DESC_PARAM_SCM_CAP_ADJ_FCTR	= 0x24,
+	GEOMETRY_DESC_PARAM_NPM_MAX_NUM_UNITS	= 0x26,
+	GEOMETRY_DESC_PARAM_NPM_CAP_ADJ_FCTR	= 0x2A,
+	GEOMETRY_DESC_PARAM_ENM1_MAX_NUM_UNITS	= 0x2C,
+	GEOMETRY_DESC_PARAM_ENM1_CAP_ADJ_FCTR	= 0x30,
+	GEOMETRY_DESC_PARAM_ENM2_MAX_NUM_UNITS	= 0x32,
+	GEOMETRY_DESC_PARAM_ENM2_CAP_ADJ_FCTR	= 0x36,
+	GEOMETRY_DESC_PARAM_ENM3_MAX_NUM_UNITS	= 0x38,
+	GEOMETRY_DESC_PARAM_ENM3_CAP_ADJ_FCTR	= 0x3C,
+	GEOMETRY_DESC_PARAM_ENM4_MAX_NUM_UNITS	= 0x3E,
+	GEOMETRY_DESC_PARAM_ENM4_CAP_ADJ_FCTR	= 0x42,
+	GEOMETRY_DESC_PARAM_OPT_LOG_BLK_SIZE	= 0x44,
+};
+
+/* Health descriptor parameters offsets in bytes*/
+enum health_desc_param {
+	HEALTH_DESC_PARAM_LEN			= 0x0,
+	HEALTH_DESC_PARAM_TYPE			= 0x1,
+	HEALTH_DESC_PARAM_EOL_INFO		= 0x2,
+	HEALTH_DESC_PARAM_LIFE_TIME_EST_A	= 0x3,
+	HEALTH_DESC_PARAM_LIFE_TIME_EST_B	= 0x4,
 };
 
 /*
@@ -529,4 +620,14 @@ struct ufs_dev_desc {
 	char model[MAX_MODEL_LEN + 1];
 };
 
+/**
+ * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor
+ * @lun: LU number to check
+ * @return: true if the lun has a matching unit descriptor, false otherwise
+ */
+static inline bool ufs_is_valid_unit_desc_lun(u8 lun)
+{
+	return lun == UFS_UPIU_RPMB_WLUN || (lun < UFS_UPIU_MAX_GENERAL_LUN);
+}
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a355d989b414..a64f560efee7 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -44,6 +44,7 @@
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
+#include "ufs-sysfs.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/ufs.h>
@@ -150,7 +151,7 @@ enum {
 #define ufshcd_is_ufs_dev_poweroff(h) \
 	((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
 
-static struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
+struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
 	{UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE},
 	{UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE},
 	{UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE},
@@ -813,28 +814,6 @@ static inline bool ufshcd_is_hba_active(struct ufs_hba *hba)
 		? false : true;
 }
 
-static const char *ufschd_uic_link_state_to_string(
-			enum uic_link_state state)
-{
-	switch (state) {
-	case UIC_LINK_OFF_STATE:	return "OFF";
-	case UIC_LINK_ACTIVE_STATE:	return "ACTIVE";
-	case UIC_LINK_HIBERN8_STATE:	return "HIBERN8";
-	default:			return "UNKNOWN";
-	}
-}
-
-static const char *ufschd_ufs_dev_pwr_mode_to_string(
-			enum ufs_dev_pwr_mode state)
-{
-	switch (state) {
-	case UFS_ACTIVE_PWR_MODE:	return "ACTIVE";
-	case UFS_SLEEP_PWR_MODE:	return "SLEEP";
-	case UFS_POWERDOWN_PWR_MODE:	return "POWERDOWN";
-	default:			return "UNKNOWN";
-	}
-}
-
 u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
 {
 	/* HCI version 1.0 and 1.1 supports UniPro 1.41 */
@@ -2243,21 +2222,6 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 	return ret;
 }
 
-/*
- * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
- * @scsi_lun: scsi LUN id
- *
- * Returns UPIU LUN id
- */
-static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
-{
-	if (scsi_is_wlun(scsi_lun))
-		return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID)
-			| UFS_UPIU_WLUN_ID;
-	else
-		return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID;
-}
-
 /**
  * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
  * @scsi_lun: UPIU W-LUN id
@@ -2725,8 +2689,8 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
  *
  * Returns 0 for success, non-zero in case of failure
 */
-static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
-			enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+		      enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
 {
 	struct ufs_query_req *request = NULL;
 	struct ufs_query_res *response = NULL;
@@ -2894,11 +2858,11 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
  * The buf_len parameter will contain, on return, the length parameter
  * received on the response.
  */
-static int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
-					 enum query_opcode opcode,
-					 enum desc_idn idn, u8 index,
-					 u8 selector,
-					 u8 *desc_buf, int *buf_len)
+int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
+				  enum query_opcode opcode,
+				  enum desc_idn idn, u8 index,
+				  u8 selector,
+				  u8 *desc_buf, int *buf_len)
 {
 	int err;
 	int retries;
@@ -2987,6 +2951,9 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba,
 	case QUERY_DESC_IDN_STRING:
 		*desc_len = QUERY_DESC_MAX_SIZE;
 		break;
+	case QUERY_DESC_IDN_HEALTH:
+		*desc_len = hba->desc_size.hlth_desc;
+		break;
 	case QUERY_DESC_IDN_RFU_0:
 	case QUERY_DESC_IDN_RFU_1:
 		*desc_len = 0;
@@ -3010,12 +2977,12 @@ EXPORT_SYMBOL(ufshcd_map_desc_id_to_length);
  *
  * Return 0 in case of success, non-zero otherwise
  */
-static int ufshcd_read_desc_param(struct ufs_hba *hba,
-				  enum desc_idn desc_id,
-				  int desc_index,
-				  u8 param_offset,
-				  u8 *param_read_buf,
-				  u8 param_size)
+int ufshcd_read_desc_param(struct ufs_hba *hba,
+			   enum desc_idn desc_id,
+			   int desc_index,
+			   u8 param_offset,
+			   u8 *param_read_buf,
+			   u8 param_size)
 {
 	int ret;
 	u8 *desc_buf;
@@ -3111,8 +3078,8 @@ static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
  * Return 0 in case of success, non-zero otherwise
  */
 #define ASCII_STD true
-static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
-				   u8 *buf, u32 size, bool ascii)
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
+			    u8 *buf, u32 size, bool ascii)
 {
 	int err = 0;
 
@@ -3189,7 +3156,7 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba,
 	 * Unit descriptors are only available for general purpose LUs (LUN id
 	 * from 0 to 7) and RPMB Well known LU.
 	 */
-	if (lun != UFS_UPIU_RPMB_WLUN && (lun >= UFS_UPIU_MAX_GENERAL_LUN))
+	if (!ufs_is_valid_unit_desc_lun(lun))
 		return -EOPNOTSUPP;
 
 	return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -4352,6 +4319,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
 	/* REPORT SUPPORTED OPERATION CODES is not supported */
 	sdev->no_report_opcodes = 1;
 
+	/* WRITE_SAME command is not supported */
+	sdev->no_write_same = 1;
 
 	ufshcd_set_queue_depth(sdev);
 
@@ -6298,6 +6267,10 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
 		&hba->desc_size.geom_desc);
 	if (err)
 		hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
+		&hba->desc_size.hlth_desc);
+	if (err)
+		hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
 }
 
 static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
@@ -6308,6 +6281,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
 	hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
 	hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
 	hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+	hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
 }
 
 /**
@@ -6494,6 +6468,12 @@ static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
 	return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER;
 }
 
+static const struct attribute_group *ufshcd_driver_groups[] = {
+	&ufs_sysfs_unit_descriptor_group,
+	&ufs_sysfs_lun_attributes_group,
+	NULL,
+};
+
 static struct scsi_host_template ufshcd_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= UFSHCD,
@@ -6513,6 +6493,7 @@ static struct scsi_host_template ufshcd_driver_template = {
 	.can_queue		= UFSHCD_CAN_QUEUE,
 	.max_host_blocked	= 1,
 	.track_queue_depth	= 1,
+	.sdev_groups		= ufshcd_driver_groups,
 };
 
 static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
@@ -7585,133 +7566,6 @@ int ufshcd_runtime_idle(struct ufs_hba *hba)
 }
 EXPORT_SYMBOL(ufshcd_runtime_idle);
 
-static inline ssize_t ufshcd_pm_lvl_store(struct device *dev,
-					   struct device_attribute *attr,
-					   const char *buf, size_t count,
-					   bool rpm)
-{
-	struct ufs_hba *hba = dev_get_drvdata(dev);
-	unsigned long flags, value;
-
-	if (kstrtoul(buf, 0, &value))
-		return -EINVAL;
-
-	if (value >= UFS_PM_LVL_MAX)
-		return -EINVAL;
-
-	spin_lock_irqsave(hba->host->host_lock, flags);
-	if (rpm)
-		hba->rpm_lvl = value;
-	else
-		hba->spm_lvl = value;
-	spin_unlock_irqrestore(hba->host->host_lock, flags);
-	return count;
-}
-
-static ssize_t ufshcd_rpm_lvl_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct ufs_hba *hba = dev_get_drvdata(dev);
-	int curr_len;
-	u8 lvl;
-
-	curr_len = snprintf(buf, PAGE_SIZE,
-			    "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n",
-			    hba->rpm_lvl,
-			    ufschd_ufs_dev_pwr_mode_to_string(
-				ufs_pm_lvl_states[hba->rpm_lvl].dev_state),
-			    ufschd_uic_link_state_to_string(
-				ufs_pm_lvl_states[hba->rpm_lvl].link_state));
-
-	curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
-			     "\nAll available Runtime PM levels info:\n");
-	for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++)
-		curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
-				     "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n",
-				    lvl,
-				    ufschd_ufs_dev_pwr_mode_to_string(
-					ufs_pm_lvl_states[lvl].dev_state),
-				    ufschd_uic_link_state_to_string(
-					ufs_pm_lvl_states[lvl].link_state));
-
-	return curr_len;
-}
-
-static ssize_t ufshcd_rpm_lvl_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	return ufshcd_pm_lvl_store(dev, attr, buf, count, true);
-}
-
-static void ufshcd_add_rpm_lvl_sysfs_nodes(struct ufs_hba *hba)
-{
-	hba->rpm_lvl_attr.show = ufshcd_rpm_lvl_show;
-	hba->rpm_lvl_attr.store = ufshcd_rpm_lvl_store;
-	sysfs_attr_init(&hba->rpm_lvl_attr.attr);
-	hba->rpm_lvl_attr.attr.name = "rpm_lvl";
-	hba->rpm_lvl_attr.attr.mode = 0644;
-	if (device_create_file(hba->dev, &hba->rpm_lvl_attr))
-		dev_err(hba->dev, "Failed to create sysfs for rpm_lvl\n");
-}
-
-static ssize_t ufshcd_spm_lvl_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct ufs_hba *hba = dev_get_drvdata(dev);
-	int curr_len;
-	u8 lvl;
-
-	curr_len = snprintf(buf, PAGE_SIZE,
-			    "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n",
-			    hba->spm_lvl,
-			    ufschd_ufs_dev_pwr_mode_to_string(
-				ufs_pm_lvl_states[hba->spm_lvl].dev_state),
-			    ufschd_uic_link_state_to_string(
-				ufs_pm_lvl_states[hba->spm_lvl].link_state));
-
-	curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
-			     "\nAll available System PM levels info:\n");
-	for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++)
-		curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
-				     "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n",
-				    lvl,
-				    ufschd_ufs_dev_pwr_mode_to_string(
-					ufs_pm_lvl_states[lvl].dev_state),
-				    ufschd_uic_link_state_to_string(
-					ufs_pm_lvl_states[lvl].link_state));
-
-	return curr_len;
-}
-
-static ssize_t ufshcd_spm_lvl_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
-{
-	return ufshcd_pm_lvl_store(dev, attr, buf, count, false);
-}
-
-static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
-{
-	hba->spm_lvl_attr.show = ufshcd_spm_lvl_show;
-	hba->spm_lvl_attr.store = ufshcd_spm_lvl_store;
-	sysfs_attr_init(&hba->spm_lvl_attr.attr);
-	hba->spm_lvl_attr.attr.name = "spm_lvl";
-	hba->spm_lvl_attr.attr.mode = 0644;
-	if (device_create_file(hba->dev, &hba->spm_lvl_attr))
-		dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
-}
-
-static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
-{
-	ufshcd_add_rpm_lvl_sysfs_nodes(hba);
-	ufshcd_add_spm_lvl_sysfs_nodes(hba);
-}
-
-static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba)
-{
-	device_remove_file(hba->dev, &hba->rpm_lvl_attr);
-	device_remove_file(hba->dev, &hba->spm_lvl_attr);
-}
-
 /**
  * ufshcd_shutdown - shutdown routine
  * @hba: per adapter instance
@@ -7749,7 +7603,7 @@ EXPORT_SYMBOL(ufshcd_shutdown);
  */
 void ufshcd_remove(struct ufs_hba *hba)
 {
-	ufshcd_remove_sysfs_nodes(hba);
+	ufs_sysfs_remove_nodes(hba->dev);
 	scsi_remove_host(hba->host);
 	/* disable interrupts */
 	ufshcd_disable_intr(hba, hba->intr_mask);
@@ -7996,7 +7850,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 	ufshcd_set_ufs_dev_active(hba);
 
 	async_schedule(ufshcd_async_scan, hba);
-	ufshcd_add_sysfs_nodes(hba);
+	ufs_sysfs_add_nodes(hba->dev);
 
 	return 0;
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1332e544da92..deb3c5d382e9 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -229,6 +229,7 @@ struct ufs_desc_size {
 	int interc_desc;
 	int unit_desc;
 	int conf_desc;
+	int hlth_desc;
 };
 
 /**
@@ -841,8 +842,24 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
 }
 
 /* Expose Query-Request API */
+int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
+				  enum query_opcode opcode,
+				  enum desc_idn idn, u8 index,
+				  u8 selector,
+				  u8 *desc_buf, int *buf_len);
+int ufshcd_read_desc_param(struct ufs_hba *hba,
+			   enum desc_idn desc_id,
+			   int desc_index,
+			   u8 param_offset,
+			   u8 *param_read_buf,
+			   u8 param_size);
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+		      enum attr_idn idn, u8 index, u8 selector, u32 *attr_val);
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 	enum flag_idn idn, bool *flag_res);
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
+			    u8 *buf, u32 size, bool ascii);
+
 int ufshcd_hold(struct ufs_hba *hba, bool async);
 void ufshcd_release(struct ufs_hba *hba);
 
@@ -985,4 +1002,21 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
 		hba->vops->dbg_register_dump(hba);
 }
 
+extern struct ufs_pm_lvl_states ufs_pm_lvl_states[];
+
+/*
+ * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
+ * @scsi_lun: scsi LUN id
+ *
+ * Returns UPIU LUN id
+ */
+static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+{
+	if (scsi_is_wlun(scsi_lun))
+		return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID)
+			| UFS_UPIU_WLUN_ID;
+	else
+		return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID;
+}
+
 #endif /* End of Header */
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
index 2bdeebc48901..6289965c42e9 100644
--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
@@ -184,7 +184,8 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
 
 	rstc = devm_reset_control_array_get(&pdev->dev, false, false);
 	if (IS_ERR(rstc)) {
-		dev_err(&pdev->dev, "failed to get reset lines\n");
+		if (PTR_ERR(rstc) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to get reset lines\n");
 		return PTR_ERR(rstc);
 	}
 
@@ -224,7 +225,11 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
 
 static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
 {
-	meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
+	bool powered_off;
+
+	powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
+	if (!powered_off)
+		meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
 }
 
 static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c
index f2d8c3c53ea4..ea091f1f7dae 100644
--- a/drivers/soc/amlogic/meson-gx-socinfo.c
+++ b/drivers/soc/amlogic/meson-gx-socinfo.c
@@ -97,7 +97,7 @@ static const char *socinfo_to_soc_id(u32 socinfo)
 	return "Unknown";
 }
 
-int __init meson_gx_socinfo_init(void)
+static int __init meson_gx_socinfo_init(void)
 {
 	struct soc_device_attribute *soc_dev_attr;
 	struct soc_device *soc_dev;
diff --git a/drivers/soc/amlogic/meson-mx-socinfo.c b/drivers/soc/amlogic/meson-mx-socinfo.c
index 7bfff5ff22a2..78f0f1aeca57 100644
--- a/drivers/soc/amlogic/meson-mx-socinfo.c
+++ b/drivers/soc/amlogic/meson-mx-socinfo.c
@@ -104,7 +104,7 @@ static const struct of_device_id meson_mx_socinfo_analog_top_ids[] = {
 	{ /* sentinel */ }
 };
 
-int __init meson_mx_socinfo_init(void)
+static int __init meson_mx_socinfo_init(void)
 {
 	struct soc_device_attribute *soc_dev_attr;
 	struct soc_device *soc_dev;
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
index 53f7275d6cbd..4bd241047634 100644
--- a/drivers/soc/imx/gpc.c
+++ b/drivers/soc/imx/gpc.c
@@ -18,6 +18,7 @@
 #include <linux/pm_domain.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
 
 #define GPC_CNTR		0x000
 
@@ -254,6 +255,7 @@ static struct imx_pm_domain imx_gpc_domains[] = {
 	{
 		.base = {
 			.name = "ARM",
+			.flags = GENPD_FLAG_ALWAYS_ON,
 		},
 	}, {
 		.base = {
@@ -442,13 +444,19 @@ static int imx_gpc_probe(struct platform_device *pdev)
 			if (domain_index >= of_id_data->num_domains)
 				continue;
 
-			domain = &imx_gpc_domains[domain_index];
+			domain = kmalloc(sizeof(*domain), GFP_KERNEL);
+			if (!domain) {
+				of_node_put(np);
+				return -ENOMEM;
+			}
+			memcpy(domain, &imx_gpc_domains[domain_index], sizeof(*domain));
 			domain->regmap = regmap;
 			domain->ipg_rate_mhz = ipg_rate_mhz;
 
 			pd_pdev = platform_device_alloc("imx-pgc-power-domain",
 							domain_index);
 			if (!pd_pdev) {
+				kfree(domain);
 				of_node_put(np);
 				return -ENOMEM;
 			}
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index afc7ecc3c187..9947598ec4b5 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -18,6 +18,7 @@
 #include <linux/pm_domain.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
 #include <dt-bindings/power/imx7-power.h>
 
 #define GPC_LPCR_A7_BSC			0x000
@@ -155,7 +156,7 @@ static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
 	return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false);
 }
 
-static struct imx7_pgc_domain imx7_pgc_domains[] = {
+static const struct imx7_pgc_domain imx7_pgc_domains[] = {
 	[IMX7_POWER_DOMAIN_MIPI_PHY] = {
 		.genpd = {
 			.name      = "mipi-phy",
@@ -321,7 +322,14 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
 			continue;
 		}
 
-		domain = &imx7_pgc_domains[domain_index];
+		domain = kmalloc(sizeof(*domain), GFP_KERNEL);
+		if (!domain) {
+			of_node_put(np);
+			return -ENOMEM;
+		}
+		memcpy(domain, &imx7_pgc_domains[domain_index],
+		       sizeof(*domain));
+
 		domain->regmap = regmap;
 		domain->genpd.power_on  = imx7_gpc_pu_pgc_sw_pup_req;
 		domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req;
@@ -330,6 +338,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
 						domain_index);
 		if (!pd_pdev) {
 			dev_err(dev, "Failed to allocate platform device\n");
+			kfree(domain);
 			of_node_put(np);
 			return -ENOMEM;
 		}
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 08bd8549242a..17b314d9a148 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -83,12 +83,14 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
  * @mem_region:	allocated memory region to load firmware into
  * @mem_phys:	physical address of allocated memory region
  * @mem_size:	size of the allocated memory region
+ * @reloc_base:	adjusted physical address after relocation
  *
  * Returns 0 on success, negative errno otherwise.
  */
 int qcom_mdt_load(struct device *dev, const struct firmware *fw,
 		  const char *firmware, int pas_id, void *mem_region,
-		  phys_addr_t mem_phys, size_t mem_size)
+		  phys_addr_t mem_phys, size_t mem_size,
+		  phys_addr_t *reloc_base)
 {
 	const struct elf32_phdr *phdrs;
 	const struct elf32_phdr *phdr;
@@ -192,6 +194,9 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
 			memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
 	}
 
+	if (reloc_base)
+		*reloc_base = mem_reloc;
+
 out:
 	kfree(fw_name);
 
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c
index 877611d5c42b..321982277697 100644
--- a/drivers/soc/qcom/qmi_interface.c
+++ b/drivers/soc/qcom/qmi_interface.c
@@ -586,7 +586,6 @@ static struct socket *qmi_sock_create(struct qmi_handle *qmi,
 				      struct sockaddr_qrtr *sq)
 {
 	struct socket *sock;
-	int sl = sizeof(*sq);
 	int ret;
 
 	ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM,
@@ -594,7 +593,7 @@ static struct socket *qmi_sock_create(struct qmi_handle *qmi,
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	ret = kernel_getsockname(sock, (struct sockaddr *)sq, &sl);
+	ret = kernel_getsockname(sock, (struct sockaddr *)sq);
 	if (ret < 0) {
 		sock_release(sock);
 		return ERR_PTR(ret);
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 09550b1da56d..6caa393e3a2d 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -4,7 +4,7 @@ config SOC_RENESAS
 	select SOC_BUS
 	select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \
 			   ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A77970 || \
-			   ARCH_R8A77995
+			   ARCH_R8A77980 || ARCH_R8A77995
 	select SYSC_R8A7743 if ARCH_R8A7743
 	select SYSC_R8A7745 if ARCH_R8A7745
 	select SYSC_R8A7779 if ARCH_R8A7779
@@ -15,6 +15,7 @@ config SOC_RENESAS
 	select SYSC_R8A7795 if ARCH_R8A7795
 	select SYSC_R8A7796 if ARCH_R8A7796
 	select SYSC_R8A77970 if ARCH_R8A77970
+	select SYSC_R8A77980 if ARCH_R8A77980
 	select SYSC_R8A77995 if ARCH_R8A77995
 
 if SOC_RENESAS
@@ -60,6 +61,10 @@ config SYSC_R8A77970
 	bool "R-Car V3M System Controller support" if COMPILE_TEST
 	select SYSC_RCAR
 
+config SYSC_R8A77980
+	bool "R-Car V3H System Controller support" if COMPILE_TEST
+	select SYSC_RCAR
+
 config SYSC_R8A77995
 	bool "R-Car D3 System Controller support" if COMPILE_TEST
 	select SYSC_RCAR
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 845d62a08ce1..d3b7bb3284c0 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_SYSC_R8A7794)	+= r8a7794-sysc.o
 obj-$(CONFIG_SYSC_R8A7795)	+= r8a7795-sysc.o
 obj-$(CONFIG_SYSC_R8A7796)	+= r8a7796-sysc.o
 obj-$(CONFIG_SYSC_R8A77970)	+= r8a77970-sysc.o
+obj-$(CONFIG_SYSC_R8A77980)	+= r8a77980-sysc.o
 obj-$(CONFIG_SYSC_R8A77995)	+= r8a77995-sysc.o
 
 # Family
diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c
index 8c614164718e..caf894f193ed 100644
--- a/drivers/soc/renesas/r8a77970-sysc.c
+++ b/drivers/soc/renesas/r8a77970-sysc.c
@@ -25,12 +25,12 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = {
 	  PD_CPU_NOCR },
 	{ "cr7",	0x240, 0, R8A77970_PD_CR7,	R8A77970_PD_ALWAYS_ON },
 	{ "a3ir",	0x180, 0, R8A77970_PD_A3IR,	R8A77970_PD_ALWAYS_ON },
-	{ "a2ir0",	0x400, 0, R8A77970_PD_A2IR0,	R8A77970_PD_ALWAYS_ON },
-	{ "a2ir1",	0x400, 1, R8A77970_PD_A2IR1,	R8A77970_PD_A2IR0 },
-	{ "a2ir2",	0x400, 2, R8A77970_PD_A2IR2,	R8A77970_PD_A2IR0 },
-	{ "a2ir3",	0x400, 3, R8A77970_PD_A2IR3,	R8A77970_PD_A2IR0 },
-	{ "a2sc0",	0x400, 4, R8A77970_PD_A2SC0,	R8A77970_PD_ALWAYS_ON },
-	{ "a2sc1",	0x400, 5, R8A77970_PD_A2SC1,	R8A77970_PD_A2SC0 },
+	{ "a2ir0",	0x400, 0, R8A77970_PD_A2IR0,	R8A77970_PD_A3IR },
+	{ "a2ir1",	0x400, 1, R8A77970_PD_A2IR1,	R8A77970_PD_A3IR },
+	{ "a2ir2",	0x400, 2, R8A77970_PD_A2IR2,	R8A77970_PD_A3IR },
+	{ "a2ir3",	0x400, 3, R8A77970_PD_A2IR3,	R8A77970_PD_A3IR },
+	{ "a2sc0",	0x400, 4, R8A77970_PD_A2SC0,	R8A77970_PD_A3IR },
+	{ "a2sc1",	0x400, 5, R8A77970_PD_A2SC1,	R8A77970_PD_A3IR },
 };
 
 const struct rcar_sysc_info r8a77970_sysc_info __initconst = {
diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c
new file mode 100644
index 000000000000..9265fb525ef3
--- /dev/null
+++ b/drivers/soc/renesas/r8a77980-sysc.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas R-Car V3H System Controller
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ * Copyright (C) 2018 Cogent Embedded, Inc.
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/power/r8a77980-sysc.h>
+
+#include "rcar-sysc.h"
+
+static const struct rcar_sysc_area r8a77980_areas[] __initconst = {
+	{ "always-on",	    0, 0, R8A77980_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+	{ "ca53-scu",	0x140, 0, R8A77980_PD_CA53_SCU,	R8A77980_PD_ALWAYS_ON,
+	  PD_SCU },
+	{ "ca53-cpu0",	0x200, 0, R8A77980_PD_CA53_CPU0, R8A77980_PD_CA53_SCU,
+	  PD_CPU_NOCR },
+	{ "ca53-cpu1",	0x200, 1, R8A77980_PD_CA53_CPU1, R8A77980_PD_CA53_SCU,
+	  PD_CPU_NOCR },
+	{ "ca53-cpu2",	0x200, 2, R8A77980_PD_CA53_CPU2, R8A77980_PD_CA53_SCU,
+	  PD_CPU_NOCR },
+	{ "ca53-cpu3",	0x200, 3, R8A77980_PD_CA53_CPU3, R8A77980_PD_CA53_SCU,
+	  PD_CPU_NOCR },
+	{ "cr7",	0x240, 0, R8A77980_PD_CR7,	R8A77980_PD_ALWAYS_ON },
+	{ "a3ir",	0x180, 0, R8A77980_PD_A3IR,	R8A77980_PD_ALWAYS_ON },
+	{ "a2ir0",	0x400, 0, R8A77980_PD_A2IR0,	R8A77980_PD_A3IR },
+	{ "a2ir1",	0x400, 1, R8A77980_PD_A2IR1,	R8A77980_PD_A3IR },
+	{ "a2ir2",	0x400, 2, R8A77980_PD_A2IR2,	R8A77980_PD_A3IR },
+	{ "a2ir3",	0x400, 3, R8A77980_PD_A2IR3,	R8A77980_PD_A3IR },
+	{ "a2ir4",	0x400, 4, R8A77980_PD_A2IR4,	R8A77980_PD_A3IR },
+	{ "a2ir5",	0x400, 5, R8A77980_PD_A2IR5,	R8A77980_PD_A3IR },
+	{ "a2sc0",	0x400, 6, R8A77980_PD_A2SC0,	R8A77980_PD_A3IR },
+	{ "a2sc1",	0x400, 7, R8A77980_PD_A2SC1,	R8A77980_PD_A3IR },
+	{ "a2sc2",	0x400, 8, R8A77980_PD_A2SC2,	R8A77980_PD_A3IR },
+	{ "a2sc3",	0x400, 9, R8A77980_PD_A2SC3,	R8A77980_PD_A3IR },
+	{ "a2sc4",	0x400, 10, R8A77980_PD_A2SC4,	R8A77980_PD_A3IR },
+	{ "a2pd0",	0x400, 11, R8A77980_PD_A2PD0,	R8A77980_PD_A3IR },
+	{ "a2pd1",	0x400, 12, R8A77980_PD_A2PD1,	R8A77980_PD_A3IR },
+	{ "a2cn",	0x400, 13, R8A77980_PD_A2CN,	R8A77980_PD_A3IR },
+	{ "a3vip",	0x2c0, 0, R8A77980_PD_A3VIP,	R8A77980_PD_ALWAYS_ON },
+	{ "a3vip1",	0x300, 0, R8A77980_PD_A3VIP1,	R8A77980_PD_A3VIP },
+	{ "a3vip2",	0x280, 0, R8A77980_PD_A3VIP2,	R8A77980_PD_A3VIP },
+};
+
+const struct rcar_sysc_info r8a77980_sysc_info __initconst = {
+	.areas = r8a77980_areas,
+	.num_areas = ARRAY_SIZE(r8a77980_areas),
+};
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
index 3316b028f231..34136664ece4 100644
--- a/drivers/soc/renesas/rcar-rst.c
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -13,8 +13,18 @@
 #include <linux/of_address.h>
 #include <linux/soc/renesas/rcar-rst.h>
 
+#define WDTRSTCR_RESET		0xA55A0002
+#define WDTRSTCR		0x0054
+
+static int rcar_rst_enable_wdt_reset(void __iomem *base)
+{
+	iowrite32(WDTRSTCR_RESET, base + WDTRSTCR);
+	return 0;
+}
+
 struct rst_config {
-	unsigned int modemr;	/* Mode Monitoring Register Offset */
+	unsigned int modemr;		/* Mode Monitoring Register Offset */
+	int (*configure)(void *base);	/* Platform specific configuration */
 };
 
 static const struct rst_config rcar_rst_gen1 __initconst = {
@@ -23,6 +33,11 @@ static const struct rst_config rcar_rst_gen1 __initconst = {
 
 static const struct rst_config rcar_rst_gen2 __initconst = {
 	.modemr = 0x60,
+	.configure = rcar_rst_enable_wdt_reset,
+};
+
+static const struct rst_config rcar_rst_gen3 __initconst = {
+	.modemr = 0x60,
 };
 
 static const struct of_device_id rcar_rst_matches[] __initconst = {
@@ -38,11 +53,12 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
 	{ .compatible = "renesas,r8a7792-rst", .data = &rcar_rst_gen2 },
 	{ .compatible = "renesas,r8a7793-rst", .data = &rcar_rst_gen2 },
 	{ .compatible = "renesas,r8a7794-rst", .data = &rcar_rst_gen2 },
-	/* R-Car Gen3 is handled like R-Car Gen2 */
-	{ .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen2 },
-	{ .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen2 },
-	{ .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen2 },
-	{ .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen2 },
+	/* R-Car Gen3 */
+	{ .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen3 },
+	{ .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen3 },
+	{ .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen3 },
+	{ .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
+	{ .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 },
 	{ /* sentinel */ }
 };
 
@@ -71,6 +87,14 @@ static int __init rcar_rst_init(void)
 	rcar_rst_base = base;
 	cfg = match->data;
 	saved_mode = ioread32(base + cfg->modemr);
+	if (cfg->configure) {
+		error = cfg->configure(base);
+		if (error) {
+			pr_warn("%pOF: Cannot run SoC specific configuration\n",
+				np);
+			goto out_put;
+		}
+	}
 
 	pr_debug("%pOF: MODE = 0x%08x\n", np, saved_mode);
 
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index 52c25a5e2646..72b0f4a9ad4e 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -254,7 +254,7 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
 	pm_genpd_init(genpd, gov, false);
 }
 
-static const struct of_device_id rcar_sysc_matches[] = {
+static const struct of_device_id rcar_sysc_matches[] __initconst = {
 #ifdef CONFIG_SYSC_R8A7743
 	{ .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
 #endif
@@ -287,6 +287,9 @@ static const struct of_device_id rcar_sysc_matches[] = {
 #ifdef CONFIG_SYSC_R8A77970
 	{ .compatible = "renesas,r8a77970-sysc", .data = &r8a77970_sysc_info },
 #endif
+#ifdef CONFIG_SYSC_R8A77980
+	{ .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info },
+#endif
 #ifdef CONFIG_SYSC_R8A77995
 	{ .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info },
 #endif
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h
index 9d9daf9eb91b..974b18619c08 100644
--- a/drivers/soc/renesas/rcar-sysc.h
+++ b/drivers/soc/renesas/rcar-sysc.h
@@ -59,6 +59,7 @@ extern const struct rcar_sysc_info r8a7794_sysc_info;
 extern const struct rcar_sysc_info r8a7795_sysc_info;
 extern const struct rcar_sysc_info r8a7796_sysc_info;
 extern const struct rcar_sysc_info r8a77970_sysc_info;
+extern const struct rcar_sysc_info r8a77980_sysc_info;
 extern const struct rcar_sysc_info r8a77995_sysc_info;
 
 
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 926b7fd6db2d..000834321774 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -149,6 +149,11 @@ static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = {
 	.id	= 0x54,
 };
 
+static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = {
+	.family	= &fam_rcar_gen3,
+	.id	= 0x56,
+};
+
 static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
 	.family	= &fam_rcar_gen3,
 	.id	= 0x58,
@@ -212,6 +217,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
 #ifdef CONFIG_ARCH_R8A77970
 	{ .compatible = "renesas,r8a77970",	.data = &soc_rcar_v3m },
 #endif
+#ifdef CONFIG_ARCH_R8A77980
+	{ .compatible = "renesas,r8a77980",	.data = &soc_rcar_v3h },
+#endif
 #ifdef CONFIG_ARCH_R8A77995
 	{ .compatible = "renesas,r8a77995",	.data = &soc_rcar_d3 },
 #endif
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 15e71fd6c513..dd81b87d79f0 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -43,6 +43,17 @@ static const struct rockchip_grf_info rk3036_grf __initconst = {
 	.num_values = ARRAY_SIZE(rk3036_defaults),
 };
 
+#define RK3228_GRF_SOC_CON6		0x418
+
+static const struct rockchip_grf_value rk3228_defaults[] __initconst = {
+	{ "jtag switching", RK3228_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 8) },
+};
+
+static const struct rockchip_grf_info rk3228_grf __initconst = {
+	.values = rk3228_defaults,
+	.num_values = ARRAY_SIZE(rk3228_defaults),
+};
+
 #define RK3288_GRF_SOC_CON0		0x244
 
 static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
@@ -91,6 +102,9 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
 	{
 		.compatible = "rockchip,rk3036-grf",
 		.data = (void *)&rk3036_grf,
+	}, {
+		.compatible = "rockchip,rk3228-grf",
+		.data = (void *)&rk3228_grf,
 	}, {
 		.compatible = "rockchip,rk3288-grf",
 		.data = (void *)&rk3288_grf,
diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index f56adbd9fb8b..d34ca201b8b7 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -84,11 +84,15 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
 	}, {
 		.compatible = "samsung,exynos5250-pmu",
 		.data = exynos_pmu_data_arm_ptr(exynos5250_pmu_data),
+	}, {
+		.compatible = "samsung,exynos5410-pmu",
 	}, {
 		.compatible = "samsung,exynos5420-pmu",
 		.data = exynos_pmu_data_arm_ptr(exynos5420_pmu_data),
 	}, {
 		.compatible = "samsung,exynos5433-pmu",
+	}, {
+		.compatible = "samsung,exynos7-pmu",
 	},
 	{ /*sentinel*/ },
 };
@@ -126,6 +130,9 @@ static int exynos_pmu_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pmu_context);
 
+	if (devm_of_platform_populate(dev))
+		dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");
+
 	dev_dbg(dev, "Exynos PMU Driver probe done\n");
 	return 0;
 }
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 603783976b81..6fb0347a24f2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -72,10 +72,10 @@ config SPI_ARMADA_3700
 config SPI_ATMEL
 	tristate "Atmel SPI Controller"
 	depends on HAS_DMA
-	depends on (ARCH_AT91 || AVR32 || COMPILE_TEST)
+	depends on (ARCH_AT91 || COMPILE_TEST)
 	help
 	  This selects a driver for the Atmel SPI Controller, present on
-	  many AT32 (AVR32) and AT91 (ARM) chips.
+	  many AT91 (ARM) chips.
 
 config SPI_AU1550
 	tristate "Au1550/Au1200/Au1300 SPI Controller"
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 7428091d3f5b..1431cb98fe40 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -321,7 +321,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
 	struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
 	unsigned long spi_hz, clk_hz, speed;
 	unsigned long spi_used_hz;
-	unsigned long long xfer_time_us;
 
 	/* calculate the registers to handle
 	 *
@@ -358,20 +357,21 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
 	bs->rx_len = tfr->len;
 	bs->pending = 0;
 
-	/* calculate the estimated time in us the transfer runs
-	 * note that there are are 2 idle clocks after each
-	 * chunk getting transferred - in our case the chunk size
-	 * is 3 bytes, so we approximate this by 9 bits/byte
+	/* Calculate the estimated time in us the transfer runs.  Note that
+	 * there are are 2 idle clocks cycles after each chunk getting
+	 * transferred - in our case the chunk size is 3 bytes, so we
+	 * approximate this by 9 cycles/byte.  This is used to find the number
+	 * of Hz per byte per polling limit.  E.g., we can transfer 1 byte in
+	 * 30 µs per 300,000 Hz of bus clock.
 	 */
-	xfer_time_us = tfr->len * 9 * 1000000;
-	do_div(xfer_time_us, spi_used_hz);
-
+#define HZ_PER_BYTE ((9 * 1000000) / BCM2835_AUX_SPI_POLLING_LIMIT_US)
 	/* run in polling mode for short transfers */
-	if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US)
+	if (tfr->len < spi_used_hz / HZ_PER_BYTE)
 		return bcm2835aux_spi_transfer_one_poll(master, spi, tfr);
 
 	/* run in interrupt mode for all others */
 	return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
+#undef HZ_PER_BYTE
 }
 
 static int bcm2835aux_spi_prepare_message(struct spi_master *master,
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 837cb8d0bac6..3db905f5f345 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -112,10 +112,10 @@ static irqreturn_t dma_transfer(struct dw_spi *dws)
 	return IRQ_HANDLED;
 }
 
-static bool mid_spi_can_dma(struct spi_master *master, struct spi_device *spi,
-		struct spi_transfer *xfer)
+static bool mid_spi_can_dma(struct spi_controller *master,
+		struct spi_device *spi, struct spi_transfer *xfer)
 {
-	struct dw_spi *dws = spi_master_get_devdata(master);
+	struct dw_spi *dws = spi_controller_get_devdata(master);
 
 	if (!dws->dma_inited)
 		return false;
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 211cc7d75bf8..f693bfe95ab9 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -135,7 +135,7 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
 
 static void dw_spi_set_cs(struct spi_device *spi, bool enable)
 {
-	struct dw_spi *dws = spi_master_get_devdata(spi->master);
+	struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
 	struct chip_data *chip = spi_get_ctldata(spi);
 
 	/* Chip select logic is inverted from spi_set_cs() */
@@ -250,8 +250,8 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 
 static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 {
-	struct spi_master *master = dev_id;
-	struct dw_spi *dws = spi_master_get_devdata(master);
+	struct spi_controller *master = dev_id;
+	struct dw_spi *dws = spi_controller_get_devdata(master);
 	u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f;
 
 	if (!irq_status)
@@ -277,10 +277,10 @@ static int poll_transfer(struct dw_spi *dws)
 	return 0;
 }
 
-static int dw_spi_transfer_one(struct spi_master *master,
+static int dw_spi_transfer_one(struct spi_controller *master,
 		struct spi_device *spi, struct spi_transfer *transfer)
 {
-	struct dw_spi *dws = spi_master_get_devdata(master);
+	struct dw_spi *dws = spi_controller_get_devdata(master);
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u8 imask = 0;
 	u16 txlevel = 0;
@@ -383,10 +383,10 @@ static int dw_spi_transfer_one(struct spi_master *master,
 	return 1;
 }
 
-static void dw_spi_handle_err(struct spi_master *master,
+static void dw_spi_handle_err(struct spi_controller *master,
 		struct spi_message *msg)
 {
-	struct dw_spi *dws = spi_master_get_devdata(master);
+	struct dw_spi *dws = spi_controller_get_devdata(master);
 
 	if (dws->dma_mapped)
 		dws->dma_ops->dma_stop(dws);
@@ -471,7 +471,7 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
 
 int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 {
-	struct spi_master *master;
+	struct spi_controller *master;
 	int ret;
 
 	BUG_ON(dws == NULL);
@@ -518,8 +518,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 		}
 	}
 
-	spi_master_set_devdata(master, dws);
-	ret = devm_spi_register_master(dev, master);
+	spi_controller_set_devdata(master, dws);
+	ret = devm_spi_register_controller(dev, master);
 	if (ret) {
 		dev_err(&master->dev, "problem registering spi master\n");
 		goto err_dma_exit;
@@ -534,7 +534,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	spi_enable_chip(dws, 0);
 	free_irq(dws->irq, master);
 err_free_master:
-	spi_master_put(master);
+	spi_controller_put(master);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dw_spi_add_host);
@@ -556,7 +556,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
 {
 	int ret;
 
-	ret = spi_master_suspend(dws->master);
+	ret = spi_controller_suspend(dws->master);
 	if (ret)
 		return ret;
 
@@ -570,7 +570,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
 	int ret;
 
 	spi_hw_init(&dws->master->dev, dws);
-	ret = spi_master_resume(dws->master);
+	ret = spi_controller_resume(dws->master);
 	if (ret)
 		dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
 	return ret;
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 5c07cf8f19e0..2cde2473b3e9 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -93,14 +93,14 @@ struct dw_spi_dma_ops {
 	int (*dma_init)(struct dw_spi *dws);
 	void (*dma_exit)(struct dw_spi *dws);
 	int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
-	bool (*can_dma)(struct spi_master *master, struct spi_device *spi,
+	bool (*can_dma)(struct spi_controller *master, struct spi_device *spi,
 			struct spi_transfer *xfer);
 	int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
 	void (*dma_stop)(struct dw_spi *dws);
 };
 
 struct dw_spi {
-	struct spi_master	*master;
+	struct spi_controller	*master;
 	enum dw_ssi_type	type;
 
 	void __iomem		*regs;
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 1c34c9314c8a..b85a93cad44a 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -2,6 +2,7 @@
  * SPI master driver using generic bitbanged GPIO
  *
  * Copyright (C) 2006,2008 David Brownell
+ * Copyright (C) 2017 Linus Walleij
  *
  * 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
@@ -16,10 +17,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
@@ -44,7 +44,11 @@ struct spi_gpio {
 	struct spi_bitbang		bitbang;
 	struct spi_gpio_platform_data	pdata;
 	struct platform_device		*pdev;
-	unsigned long			cs_gpios[0];
+	struct gpio_desc		*sck;
+	struct gpio_desc		*miso;
+	struct gpio_desc		*mosi;
+	struct gpio_desc		**cs_gpios;
+	bool				has_cs;
 };
 
 /*----------------------------------------------------------------------*/
@@ -77,13 +81,6 @@ struct spi_gpio {
 
 #define GENERIC_BITBANG	/* vs tight inlines */
 
-/* all functions referencing these symbols must define pdata */
-#define SPI_MISO_GPIO	((pdata)->miso)
-#define SPI_MOSI_GPIO	((pdata)->mosi)
-#define SPI_SCK_GPIO	((pdata)->sck)
-
-#define SPI_N_CHIPSEL	((pdata)->num_chipselect)
-
 #endif
 
 /*----------------------------------------------------------------------*/
@@ -105,25 +102,27 @@ spi_to_pdata(const struct spi_device *spi)
 	return &spi_to_spi_gpio(spi)->pdata;
 }
 
-/* this is #defined to avoid unused-variable warnings when inlining */
-#define pdata		spi_to_pdata(spi)
-
+/* These helpers are in turn called by the bitbang inlines */
 static inline void setsck(const struct spi_device *spi, int is_on)
 {
-	gpio_set_value_cansleep(SPI_SCK_GPIO, is_on);
+	struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+	gpiod_set_value_cansleep(spi_gpio->sck, is_on);
 }
 
 static inline void setmosi(const struct spi_device *spi, int is_on)
 {
-	gpio_set_value_cansleep(SPI_MOSI_GPIO, is_on);
+	struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+	gpiod_set_value_cansleep(spi_gpio->mosi, is_on);
 }
 
 static inline int getmiso(const struct spi_device *spi)
 {
-	return !!gpio_get_value_cansleep(SPI_MISO_GPIO);
-}
+	struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
 
-#undef pdata
+	return !!gpiod_get_value_cansleep(spi_gpio->miso);
+}
 
 /*
  * NOTE:  this clocks "as fast as we can".  It "should" be a function of the
@@ -216,123 +215,89 @@ static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
 static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
 {
 	struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
-	unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
 
-	/* set initial clock polarity */
+	/* set initial clock line level */
 	if (is_active)
-		setsck(spi, spi->mode & SPI_CPOL);
+		gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL);
+
+	/* Drive chip select line, if we have one */
+	if (spi_gpio->has_cs) {
+		struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select];
 
-	if (cs != SPI_GPIO_NO_CHIPSELECT) {
-		/* SPI is normally active-low */
-		gpio_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+		/* SPI chip selects are normally active-low */
+		gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
 	}
 }
 
 static int spi_gpio_setup(struct spi_device *spi)
 {
-	unsigned long		cs;
+	struct gpio_desc	*cs;
 	int			status = 0;
 	struct spi_gpio		*spi_gpio = spi_to_spi_gpio(spi);
-	struct device_node	*np = spi->master->dev.of_node;
-
-	if (np) {
-		/*
-		 * In DT environments, the CS GPIOs have already been
-		 * initialized from the "cs-gpios" property of the node.
-		 */
-		cs = spi_gpio->cs_gpios[spi->chip_select];
-	} else {
-		/*
-		 * ... otherwise, take it from spi->controller_data
-		 */
-		cs = (uintptr_t) spi->controller_data;
-	}
 
-	if (!spi->controller_state) {
-		if (cs != SPI_GPIO_NO_CHIPSELECT) {
-			status = gpio_request(cs, dev_name(&spi->dev));
-			if (status)
-				return status;
-			status = gpio_direction_output(cs,
-					!(spi->mode & SPI_CS_HIGH));
-		}
-	}
-	if (!status) {
-		/* in case it was initialized from static board data */
-		spi_gpio->cs_gpios[spi->chip_select] = cs;
+	/*
+	 * The CS GPIOs have already been
+	 * initialized from the descriptor lookup.
+	 */
+	cs = spi_gpio->cs_gpios[spi->chip_select];
+	if (!spi->controller_state && cs)
+		status = gpiod_direction_output(cs,
+						!(spi->mode & SPI_CS_HIGH));
+
+	if (!status)
 		status = spi_bitbang_setup(spi);
-	}
 
-	if (status) {
-		if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
-			gpio_free(cs);
-	}
 	return status;
 }
 
 static void spi_gpio_cleanup(struct spi_device *spi)
 {
-	struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
-	unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
-
-	if (cs != SPI_GPIO_NO_CHIPSELECT)
-		gpio_free(cs);
 	spi_bitbang_cleanup(spi);
 }
 
-static int spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
-{
-	int value;
-
-	value = gpio_request(pin, label);
-	if (value == 0) {
-		if (is_in)
-			value = gpio_direction_input(pin);
-		else
-			value = gpio_direction_output(pin, 0);
-	}
-	return value;
-}
-
-static int spi_gpio_request(struct spi_gpio_platform_data *pdata,
-			    const char *label, u16 *res_flags)
+/*
+ * It can be convenient to use this driver with pins that have alternate
+ * functions associated with a "native" SPI controller if a driver for that
+ * controller is not available, or is missing important functionality.
+ *
+ * On platforms which can do so, configure MISO with a weak pullup unless
+ * there's an external pullup on that signal.  That saves power by avoiding
+ * floating signals.  (A weak pulldown would save power too, but many
+ * drivers expect to see all-ones data as the no slave "response".)
+ */
+static int spi_gpio_request(struct device *dev,
+			    struct spi_gpio *spi_gpio,
+			    unsigned int num_chipselects,
+			    u16 *mflags)
 {
-	int value;
-
-	/* NOTE:  SPI_*_GPIO symbols may reference "pdata" */
+	int i;
 
-	if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) {
-		value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false);
-		if (value)
-			goto done;
-	} else {
+	spi_gpio->mosi = devm_gpiod_get_optional(dev, "mosi", GPIOD_OUT_LOW);
+	if (IS_ERR(spi_gpio->mosi))
+		return PTR_ERR(spi_gpio->mosi);
+	if (!spi_gpio->mosi)
 		/* HW configuration without MOSI pin */
-		*res_flags |= SPI_MASTER_NO_TX;
-	}
+		*mflags |= SPI_MASTER_NO_TX;
 
-	if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) {
-		value = spi_gpio_alloc(SPI_MISO_GPIO, label, true);
-		if (value)
-			goto free_mosi;
-	} else {
+	spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN);
+	if (IS_ERR(spi_gpio->miso))
+		return PTR_ERR(spi_gpio->miso);
+	if (!spi_gpio->miso)
 		/* HW configuration without MISO pin */
-		*res_flags |= SPI_MASTER_NO_RX;
-	}
+		*mflags |= SPI_MASTER_NO_RX;
 
-	value = spi_gpio_alloc(SPI_SCK_GPIO, label, false);
-	if (value)
-		goto free_miso;
+	spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
+	if (IS_ERR(spi_gpio->mosi))
+		return PTR_ERR(spi_gpio->mosi);
 
-	goto done;
+	for (i = 0; i < num_chipselects; i++) {
+		spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs",
+							     i, GPIOD_OUT_HIGH);
+		if (IS_ERR(spi_gpio->cs_gpios[i]))
+			return PTR_ERR(spi_gpio->cs_gpios[i]);
+	}
 
-free_miso:
-	if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
-		gpio_free(SPI_MISO_GPIO);
-free_mosi:
-	if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
-		gpio_free(SPI_MOSI_GPIO);
-done:
-	return value;
+	return 0;
 }
 
 #ifdef CONFIG_OF
@@ -358,26 +323,6 @@ static int spi_gpio_probe_dt(struct platform_device *pdev)
 	if (!pdata)
 		return -ENOMEM;
 
-	ret = of_get_named_gpio(np, "gpio-sck", 0);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "gpio-sck property not found\n");
-		goto error_free;
-	}
-	pdata->sck = ret;
-
-	ret = of_get_named_gpio(np, "gpio-miso", 0);
-	if (ret < 0) {
-		dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
-		pdata->miso = SPI_GPIO_NO_MISO;
-	} else
-		pdata->miso = ret;
-
-	ret = of_get_named_gpio(np, "gpio-mosi", 0);
-	if (ret < 0) {
-		dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
-		pdata->mosi = SPI_GPIO_NO_MOSI;
-	} else
-		pdata->mosi = ret;
 
 	ret = of_property_read_u32(np, "num-chipselects", &tmp);
 	if (ret < 0) {
@@ -409,7 +354,6 @@ static int spi_gpio_probe(struct platform_device *pdev)
 	struct spi_gpio_platform_data	*pdata;
 	u16 master_flags = 0;
 	bool use_of = 0;
-	int num_devices;
 
 	status = spi_gpio_probe_dt(pdev);
 	if (status < 0)
@@ -423,59 +367,41 @@ static int spi_gpio_probe(struct platform_device *pdev)
 		return -ENODEV;
 #endif
 
-	if (use_of && !SPI_N_CHIPSEL)
-		num_devices = 1;
-	else
-		num_devices = SPI_N_CHIPSEL;
-
-	status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
-	if (status < 0)
-		return status;
+	master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio));
+	if (!master)
+		return -ENOMEM;
 
-	master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +
-					(sizeof(unsigned long) * num_devices));
-	if (!master) {
-		status = -ENOMEM;
-		goto gpio_free;
-	}
 	spi_gpio = spi_master_get_devdata(master);
+
+	spi_gpio->cs_gpios = devm_kzalloc(&pdev->dev,
+				pdata->num_chipselect * sizeof(*spi_gpio->cs_gpios),
+				GFP_KERNEL);
+	if (!spi_gpio->cs_gpios)
+		return -ENOMEM;
+
 	platform_set_drvdata(pdev, spi_gpio);
 
+	/* Determine if we have chip selects connected */
+	spi_gpio->has_cs = !!pdata->num_chipselect;
+
 	spi_gpio->pdev = pdev;
 	if (pdata)
 		spi_gpio->pdata = *pdata;
 
+	status = spi_gpio_request(&pdev->dev, spi_gpio,
+				  pdata->num_chipselect, &master_flags);
+	if (status)
+		return status;
+
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
 	master->flags = master_flags;
 	master->bus_num = pdev->id;
-	master->num_chipselect = num_devices;
+	/* The master needs to think there is a chipselect even if not connected */
+	master->num_chipselect = spi_gpio->has_cs ? pdata->num_chipselect : 1;
 	master->setup = spi_gpio_setup;
 	master->cleanup = spi_gpio_cleanup;
 #ifdef CONFIG_OF
 	master->dev.of_node = pdev->dev.of_node;
-
-	if (use_of) {
-		int i;
-		struct device_node *np = pdev->dev.of_node;
-
-		/*
-		 * In DT environments, take the CS GPIO from the "cs-gpios"
-		 * property of the node.
-		 */
-
-		if (!SPI_N_CHIPSEL)
-			spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;
-		else
-			for (i = 0; i < SPI_N_CHIPSEL; i++) {
-				status = of_get_named_gpio(np, "cs-gpios", i);
-				if (status < 0) {
-					dev_err(&pdev->dev,
-						"invalid cs-gpios property\n");
-					goto gpio_free;
-				}
-				spi_gpio->cs_gpios[i] = status;
-			}
-	}
 #endif
 
 	spi_gpio->bitbang.master = master;
@@ -496,15 +422,8 @@ static int spi_gpio_probe(struct platform_device *pdev)
 	spi_gpio->bitbang.flags = SPI_CS_HIGH;
 
 	status = spi_bitbang_start(&spi_gpio->bitbang);
-	if (status < 0) {
-gpio_free:
-		if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
-			gpio_free(SPI_MISO_GPIO);
-		if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
-			gpio_free(SPI_MOSI_GPIO);
-		gpio_free(SPI_SCK_GPIO);
+	if (status)
 		spi_master_put(master);
-	}
 
 	return status;
 }
@@ -520,11 +439,6 @@ static int spi_gpio_remove(struct platform_device *pdev)
 	/* stop() unregisters child devices too */
 	spi_bitbang_stop(&spi_gpio->bitbang);
 
-	if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
-		gpio_free(SPI_MISO_GPIO);
-	if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
-		gpio_free(SPI_MOSI_GPIO);
-	gpio_free(SPI_SCK_GPIO);
 	spi_master_put(spi_gpio->bitbang.master);
 
 	return 0;
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index deca63e82ff6..d01a6adc726e 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -90,14 +90,19 @@ struct orion_direct_acc {
 	u32			size;
 };
 
+struct orion_child_options {
+	struct orion_direct_acc direct_access;
+};
+
 struct orion_spi {
 	struct spi_master	*master;
 	void __iomem		*base;
 	struct clk              *clk;
 	struct clk              *axi_clk;
 	const struct orion_spi_dev *devdata;
+	int			unused_hw_gpio;
 
-	struct orion_direct_acc	direct_access[ORION_NUM_CHIPSELECTS];
+	struct orion_child_options	child[ORION_NUM_CHIPSELECTS];
 };
 
 static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
@@ -324,13 +329,13 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable)
 	struct orion_spi *orion_spi;
 	int cs;
 
+	orion_spi = spi_master_get_devdata(spi->master);
+
 	if (gpio_is_valid(spi->cs_gpio))
-		cs = 0;
+		cs = orion_spi->unused_hw_gpio;
 	else
 		cs = spi->chip_select;
 
-	orion_spi = spi_master_get_devdata(spi->master);
-
 	orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
 	orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
 				ORION_SPI_CS(cs));
@@ -435,7 +440,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
 	 * Use SPI direct write mode if base address is available. Otherwise
 	 * fall back to PIO mode for this transfer.
 	 */
-	if ((orion_spi->direct_access[cs].vaddr) && (xfer->tx_buf) &&
+	if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) &&
 	    (word_len == 8)) {
 		unsigned int cnt = count / 4;
 		unsigned int rem = count % 4;
@@ -444,12 +449,12 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
 		 * Send the TX-data to the SPI device via the direct
 		 * mapped address window
 		 */
-		iowrite32_rep(orion_spi->direct_access[cs].vaddr,
+		iowrite32_rep(orion_spi->child[cs].direct_access.vaddr,
 			      xfer->tx_buf, cnt);
 		if (rem) {
 			u32 *buf = (u32 *)xfer->tx_buf;
 
-			iowrite8_rep(orion_spi->direct_access[cs].vaddr,
+			iowrite8_rep(orion_spi->child[cs].direct_access.vaddr,
 				     &buf[cnt], rem);
 		}
 
@@ -498,6 +503,9 @@ static int orion_spi_transfer_one(struct spi_master *master,
 
 static int orion_spi_setup(struct spi_device *spi)
 {
+	if (gpio_is_valid(spi->cs_gpio)) {
+		gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
+	}
 	return orion_spi_setup_transfer(spi, NULL);
 }
 
@@ -620,6 +628,7 @@ static int orion_spi_probe(struct platform_device *pdev)
 
 	spi = spi_master_get_devdata(master);
 	spi->master = master;
+	spi->unused_hw_gpio = -1;
 
 	of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
 	devdata = (of_id) ? of_id->data : &orion_spi_dev_data;
@@ -702,14 +711,14 @@ static int orion_spi_probe(struct platform_device *pdev)
 		 * This needs to get extended for the direct SPI-NOR / SPI-NAND
 		 * support, once this gets implemented.
 		 */
-		spi->direct_access[cs].vaddr = devm_ioremap(&pdev->dev,
+		spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev,
 							    r->start,
 							    PAGE_SIZE);
-		if (!spi->direct_access[cs].vaddr) {
+		if (!spi->child[cs].direct_access.vaddr) {
 			status = -ENOMEM;
 			goto out_rel_axi_clk;
 		}
-		spi->direct_access[cs].size = PAGE_SIZE;
+		spi->child[cs].direct_access.size = PAGE_SIZE;
 
 		dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
 	}
@@ -731,8 +740,44 @@ static int orion_spi_probe(struct platform_device *pdev)
 	if (status < 0)
 		goto out_rel_pm;
 
+	if (master->cs_gpios) {
+		int i;
+		for (i = 0; i < master->num_chipselect; ++i) {
+			char *gpio_name;
+
+			if (!gpio_is_valid(master->cs_gpios[i])) {
+				continue;
+			}
+
+			gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					"%s-CS%d", dev_name(&pdev->dev), i);
+			if (!gpio_name) {
+				status = -ENOMEM;
+				goto out_rel_master;
+			}
+
+			status = devm_gpio_request(&pdev->dev,
+					master->cs_gpios[i], gpio_name);
+			if (status) {
+				dev_err(&pdev->dev,
+					"Can't request GPIO for CS %d\n",
+					master->cs_gpios[i]);
+				goto out_rel_master;
+			}
+			if (spi->unused_hw_gpio == -1) {
+				dev_info(&pdev->dev,
+					"Selected unused HW CS#%d for any GPIO CSes\n",
+					i);
+				spi->unused_hw_gpio = i;
+			}
+		}
+	}
+
+
 	return status;
 
+out_rel_master:
+	spi_unregister_master(master);
 out_rel_pm:
 	pm_runtime_disable(&pdev->dev);
 out_rel_axi_clk:
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index 04f3eecf5cf3..3d7f66080c57 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -191,7 +191,7 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
 {
 	struct pxa2xx_spi_master *pdata = drv_data->master_info;
 	struct device *dev = &drv_data->pdev->dev;
-	struct spi_master *master = drv_data->master;
+	struct spi_controller *master = drv_data->master;
 	dma_cap_mask_t mask;
 
 	dma_cap_zero(mask);
@@ -215,7 +215,7 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
 
 void pxa2xx_spi_dma_release(struct driver_data *drv_data)
 {
-	struct spi_master *master = drv_data->master;
+	struct spi_controller *master = drv_data->master;
 
 	if (master->dma_rx) {
 		dmaengine_terminate_sync(master->dma_rx);
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index b0822d1dba29..713506eff07d 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -415,10 +415,17 @@ static void cs_deassert(struct driver_data *drv_data)
 {
 	struct chip_data *chip =
 		spi_get_ctldata(drv_data->master->cur_msg->spi);
+	unsigned long timeout;
 
 	if (drv_data->ssp_type == CE4100_SSP)
 		return;
 
+	/* Wait until SSP becomes idle before deasserting the CS */
+	timeout = jiffies + msecs_to_jiffies(10);
+	while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY &&
+	       !time_after(jiffies, timeout))
+		cpu_relax();
+
 	if (chip->cs_control) {
 		chip->cs_control(PXA2XX_CS_DEASSERT);
 		return;
@@ -563,7 +570,6 @@ static void giveback(struct driver_data *drv_data)
 {
 	struct spi_transfer* last_transfer;
 	struct spi_message *msg;
-	unsigned long timeout;
 
 	msg = drv_data->master->cur_msg;
 	drv_data->cur_transfer = NULL;
@@ -575,12 +581,6 @@ static void giveback(struct driver_data *drv_data)
 	if (last_transfer->delay_usecs)
 		udelay(last_transfer->delay_usecs);
 
-	/* Wait until SSP becomes idle before deasserting the CS */
-	timeout = jiffies + msecs_to_jiffies(10);
-	while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY &&
-	       !time_after(jiffies, timeout))
-		cpu_relax();
-
 	/* Drop chip select UNLESS cs_change is true or we are returning
 	 * a message with an error, or next message is for another chip
 	 */
@@ -962,7 +962,7 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
 	return clk_div << 8;
 }
 
-static bool pxa2xx_spi_can_dma(struct spi_master *master,
+static bool pxa2xx_spi_can_dma(struct spi_controller *master,
 			       struct spi_device *spi,
 			       struct spi_transfer *xfer)
 {
@@ -976,7 +976,7 @@ static bool pxa2xx_spi_can_dma(struct spi_master *master,
 static void pump_transfers(unsigned long data)
 {
 	struct driver_data *drv_data = (struct driver_data *)data;
-	struct spi_master *master = drv_data->master;
+	struct spi_controller *master = drv_data->master;
 	struct spi_message *message = master->cur_msg;
 	struct chip_data *chip = spi_get_ctldata(message->spi);
 	u32 dma_thresh = chip->dma_threshold;
@@ -1182,10 +1182,10 @@ static void pump_transfers(unsigned long data)
 	pxa2xx_spi_write(drv_data, SSCR1, cr1);
 }
 
-static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
+static int pxa2xx_spi_transfer_one_message(struct spi_controller *master,
 					   struct spi_message *msg)
 {
-	struct driver_data *drv_data = spi_master_get_devdata(master);
+	struct driver_data *drv_data = spi_controller_get_devdata(master);
 
 	/* Initial message state*/
 	msg->state = START_STATE;
@@ -1198,9 +1198,9 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
 	return 0;
 }
 
-static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
+static int pxa2xx_spi_unprepare_transfer(struct spi_controller *master)
 {
-	struct driver_data *drv_data = spi_master_get_devdata(master);
+	struct driver_data *drv_data = spi_controller_get_devdata(master);
 
 	/* Disable the SSP now */
 	pxa2xx_spi_write(drv_data, SSCR0,
@@ -1212,7 +1212,8 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
 static int setup_cs(struct spi_device *spi, struct chip_data *chip,
 		    struct pxa2xx_spi_chip *chip_info)
 {
-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+	struct driver_data *drv_data =
+		spi_controller_get_devdata(spi->controller);
 	struct gpio_desc *gpiod;
 	int err = 0;
 
@@ -1270,7 +1271,8 @@ static int setup(struct spi_device *spi)
 	struct pxa2xx_spi_chip *chip_info;
 	struct chip_data *chip;
 	const struct lpss_config *config;
-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+	struct driver_data *drv_data =
+		spi_controller_get_devdata(spi->controller);
 	uint tx_thres, tx_hi_thres, rx_thres;
 
 	switch (drv_data->ssp_type) {
@@ -1410,7 +1412,8 @@ static int setup(struct spi_device *spi)
 static void cleanup(struct spi_device *spi)
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+	struct driver_data *drv_data =
+		spi_controller_get_devdata(spi->controller);
 
 	if (!chip)
 		return;
@@ -1575,9 +1578,10 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
 }
 #endif
 
-static int pxa2xx_spi_fw_translate_cs(struct spi_master *master, unsigned cs)
+static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master,
+				      unsigned int cs)
 {
-	struct driver_data *drv_data = spi_master_get_devdata(master);
+	struct driver_data *drv_data = spi_controller_get_devdata(master);
 
 	if (has_acpi_companion(&drv_data->pdev->dev)) {
 		switch (drv_data->ssp_type) {
@@ -1602,7 +1606,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct pxa2xx_spi_master *platform_info;
-	struct spi_master *master;
+	struct spi_controller *master;
 	struct driver_data *drv_data;
 	struct ssp_device *ssp;
 	const struct lpss_config *config;
@@ -1633,7 +1637,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 		pxa_ssp_free(ssp);
 		return -ENOMEM;
 	}
-	drv_data = spi_master_get_devdata(master);
+	drv_data = spi_controller_get_devdata(master);
 	drv_data->master = master;
 	drv_data->master_info = platform_info;
 	drv_data->pdev = pdev;
@@ -1651,7 +1655,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 	master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
 	master->fw_translate_cs = pxa2xx_spi_fw_translate_cs;
 	master->auto_runtime_pm = true;
-	master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+	master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
 
 	drv_data->ssp_type = ssp->type;
 
@@ -1793,7 +1797,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 
 	/* Register with the SPI framework */
 	platform_set_drvdata(pdev, drv_data);
-	status = devm_spi_register_master(&pdev->dev, master);
+	status = devm_spi_register_controller(&pdev->dev, master);
 	if (status != 0) {
 		dev_err(&pdev->dev, "problem registering spi master\n");
 		goto out_error_clock_enabled;
@@ -1807,7 +1811,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 	free_irq(ssp->irq, drv_data);
 
 out_error_master_alloc:
-	spi_master_put(master);
+	spi_controller_put(master);
 	pxa_ssp_free(ssp);
 	return status;
 }
@@ -1858,7 +1862,7 @@ static int pxa2xx_spi_suspend(struct device *dev)
 	struct ssp_device *ssp = drv_data->ssp;
 	int status;
 
-	status = spi_master_suspend(drv_data->master);
+	status = spi_controller_suspend(drv_data->master);
 	if (status != 0)
 		return status;
 	pxa2xx_spi_write(drv_data, SSCR0, 0);
@@ -1884,7 +1888,7 @@ static int pxa2xx_spi_resume(struct device *dev)
 		lpss_ssp_setup(drv_data);
 
 	/* Start the queue running */
-	status = spi_master_resume(drv_data->master);
+	status = spi_controller_resume(drv_data->master);
 	if (status != 0) {
 		dev_err(dev, "problem starting queue (%d)\n", status);
 		return status;
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 94f7b0713281..513ec6c6e25b 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -31,7 +31,7 @@ struct driver_data {
 
 	/* SPI framework hookup */
 	enum pxa_ssp_type ssp_type;
-	struct spi_master *master;
+	struct spi_controller *master;
 
 	/* PXA hookup */
 	struct pxa2xx_spi_master *master_info;
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index bbdc53b686dd..6dbba5aff191 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -702,30 +702,32 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
 	size_t pgstart, pgend;
 	int ret = -EINVAL;
 
+	mutex_lock(&ashmem_mutex);
+
 	if (unlikely(!asma->file))
-		return -EINVAL;
+		goto out_unlock;
 
-	if (unlikely(copy_from_user(&pin, p, sizeof(pin))))
-		return -EFAULT;
+	if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) {
+		ret = -EFAULT;
+		goto out_unlock;
+	}
 
 	/* per custom, you can pass zero for len to mean "everything onward" */
 	if (!pin.len)
 		pin.len = PAGE_ALIGN(asma->size) - pin.offset;
 
 	if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
-		return -EINVAL;
+		goto out_unlock;
 
 	if (unlikely(((__u32)-1) - pin.offset < pin.len))
-		return -EINVAL;
+		goto out_unlock;
 
 	if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len))
-		return -EINVAL;
+		goto out_unlock;
 
 	pgstart = pin.offset / PAGE_SIZE;
 	pgend = pgstart + (pin.len / PAGE_SIZE) - 1;
 
-	mutex_lock(&ashmem_mutex);
-
 	switch (cmd) {
 	case ASHMEM_PIN:
 		ret = ashmem_pin(asma, pgstart, pgend);
@@ -738,6 +740,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
 		break;
 	}
 
+out_unlock:
 	mutex_unlock(&ashmem_mutex);
 
 	return ret;
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 57e0d8035b2e..c094be2f15b2 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -33,11 +33,6 @@
 static struct ion_device *internal_dev;
 static int heap_id;
 
-bool ion_buffer_cached(struct ion_buffer *buffer)
-{
-	return !!(buffer->flags & ION_FLAG_CACHED);
-}
-
 /* this function should only be called while dev->lock is held */
 static void ion_buffer_add(struct ion_device *dev,
 			   struct ion_buffer *buffer)
@@ -564,13 +559,9 @@ void ion_device_add_heap(struct ion_heap *heap)
 		debug_file = debugfs_create_file(debug_name,
 						 0644, dev->debug_root, heap,
 						 &debug_shrink_fops);
-		if (!debug_file) {
-			char buf[256], *path;
-
-			path = dentry_path(dev->debug_root, buf, 256);
-			pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
-			       path, debug_name);
-		}
+		if (!debug_file)
+			pr_err("Failed to create ion heap shrinker debugfs at %s\n",
+			       debug_name);
 	}
 
 	dev->heap_cnt++;
@@ -599,12 +590,9 @@ static int ion_device_create(void)
 	}
 
 	idev->debug_root = debugfs_create_dir("ion", NULL);
-	if (!idev->debug_root) {
+	if (!idev->debug_root)
 		pr_err("ion: failed to create debugfs root directory.\n");
-		goto debugfs_done;
-	}
 
-debugfs_done:
 	idev->buffers = RB_ROOT;
 	mutex_init(&idev->buffer_lock);
 	init_rwsem(&idev->lock);
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index a238f23c9116..ea0897812780 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -184,23 +184,6 @@ struct ion_heap {
 			  void *unused);
 };
 
-/**
- * ion_buffer_cached - this ion buffer is cached
- * @buffer:		buffer
- *
- * indicates whether this ion buffer is cached
- */
-bool ion_buffer_cached(struct ion_buffer *buffer);
-
-/**
- * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
- * @buffer:		buffer
- *
- * indicates whether userspace mappings of this buffer will be faulted
- * in, this can affect how buffers are allocated from the heap.
- */
-bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer);
-
 /**
  * ion_device_add_heap - adds a heap to the ion device
  * @heap:		the heap to add
@@ -311,7 +294,6 @@ size_t ion_heap_freelist_size(struct ion_heap *heap);
  * @gfp_mask:		gfp_mask to use from alloc
  * @order:		order of pages in the pool
  * @list:		plist node for list of pools
- * @cached:		it's cached pool or not
  *
  * Allows you to keep a pool of pre allocated pages to use from your heap.
  * Keeping a pool of pages that is ready for dma, ie any cached mapping have
@@ -321,7 +303,6 @@ size_t ion_heap_freelist_size(struct ion_heap *heap);
 struct ion_page_pool {
 	int high_count;
 	int low_count;
-	bool cached;
 	struct list_head high_items;
 	struct list_head low_items;
 	struct mutex mutex;
@@ -330,8 +311,7 @@ struct ion_page_pool {
 	struct plist_node list;
 };
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
-					   bool cached);
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
 void ion_page_pool_destroy(struct ion_page_pool *pool);
 struct page *ion_page_pool_alloc(struct ion_page_pool *pool);
 void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index 94e06925c712..49718c96bf9e 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -12,6 +12,7 @@
 #include <linux/err.h>
 #include <linux/cma.h>
 #include <linux/scatterlist.h>
+#include <linux/highmem.h>
 
 #include "ion.h"
 
@@ -42,6 +43,22 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
 	if (!pages)
 		return -ENOMEM;
 
+	if (PageHighMem(pages)) {
+		unsigned long nr_clear_pages = nr_pages;
+		struct page *page = pages;
+
+		while (nr_clear_pages > 0) {
+			void *vaddr = kmap_atomic(page);
+
+			memset(vaddr, 0, PAGE_SIZE);
+			kunmap_atomic(vaddr);
+			page++;
+			nr_clear_pages--;
+		}
+	} else {
+		memset(page_address(pages), 0, size);
+	}
+
 	table = kmalloc(sizeof(*table), GFP_KERNEL);
 	if (!table)
 		goto err;
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index b3017f12835f..db8f61446917 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -5,24 +5,15 @@
  * Copyright (C) 2011 Google, Inc.
  */
 
-#include <linux/debugfs.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/fs.h>
 #include <linux/list.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
 
 #include "ion.h"
 
-static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
+static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
 {
-	struct page *page = alloc_pages(pool->gfp_mask, pool->order);
-
-	if (!page)
-		return NULL;
-	return page;
+	return alloc_pages(pool->gfp_mask, pool->order);
 }
 
 static void ion_page_pool_free_pages(struct ion_page_pool *pool,
@@ -31,7 +22,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool,
 	__free_pages(page, pool->order);
 }
 
-static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
+static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
 {
 	mutex_lock(&pool->mutex);
 	if (PageHighMem(page)) {
@@ -42,7 +33,6 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
 		pool->low_count++;
 	}
 	mutex_unlock(&pool->mutex);
-	return 0;
 }
 
 static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
@@ -84,13 +74,9 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
 
 void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
 {
-	int ret;
-
 	BUG_ON(pool->order != compound_order(page));
 
-	ret = ion_page_pool_add(pool, page);
-	if (ret)
-		ion_page_pool_free_pages(pool, page);
+	ion_page_pool_add(pool, page);
 }
 
 static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
@@ -137,8 +123,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
 	return freed;
 }
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
-					   bool cached)
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
 {
 	struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
 
@@ -152,8 +137,6 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
 	pool->order = order;
 	mutex_init(&pool->mutex);
 	plist_node_init(&pool->list, order);
-	if (cached)
-		pool->cached = true;
 
 	return pool;
 }
@@ -162,9 +145,3 @@ void ion_page_pool_destroy(struct ion_page_pool *pool)
 {
 	kfree(pool);
 }
-
-static int __init ion_page_pool_init(void)
-{
-	return 0;
-}
-device_initcall(ion_page_pool_init);
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index bc19cdd30637..701eb9f3b0f1 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -41,31 +41,16 @@ static inline unsigned int order_to_size(int order)
 
 struct ion_system_heap {
 	struct ion_heap heap;
-	struct ion_page_pool *uncached_pools[NUM_ORDERS];
-	struct ion_page_pool *cached_pools[NUM_ORDERS];
+	struct ion_page_pool *pools[NUM_ORDERS];
 };
 
-/**
- * The page from page-pool are all zeroed before. We need do cache
- * clean for cached buffer. The uncached buffer are always non-cached
- * since it's allocated. So no need for non-cached pages.
- */
 static struct page *alloc_buffer_page(struct ion_system_heap *heap,
 				      struct ion_buffer *buffer,
 				      unsigned long order)
 {
-	bool cached = ion_buffer_cached(buffer);
-	struct ion_page_pool *pool;
-	struct page *page;
+	struct ion_page_pool *pool = heap->pools[order_to_index(order)];
 
-	if (!cached)
-		pool = heap->uncached_pools[order_to_index(order)];
-	else
-		pool = heap->cached_pools[order_to_index(order)];
-
-	page = ion_page_pool_alloc(pool);
-
-	return page;
+	return ion_page_pool_alloc(pool);
 }
 
 static void free_buffer_page(struct ion_system_heap *heap,
@@ -73,7 +58,6 @@ static void free_buffer_page(struct ion_system_heap *heap,
 {
 	struct ion_page_pool *pool;
 	unsigned int order = compound_order(page);
-	bool cached = ion_buffer_cached(buffer);
 
 	/* go to system */
 	if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) {
@@ -81,10 +65,7 @@ static void free_buffer_page(struct ion_system_heap *heap,
 		return;
 	}
 
-	if (!cached)
-		pool = heap->uncached_pools[order_to_index(order)];
-	else
-		pool = heap->cached_pools[order_to_index(order)];
+	pool = heap->pools[order_to_index(order)];
 
 	ion_page_pool_free(pool, page);
 }
@@ -190,8 +171,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
 static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
 				  int nr_to_scan)
 {
-	struct ion_page_pool *uncached_pool;
-	struct ion_page_pool *cached_pool;
+	struct ion_page_pool *pool;
 	struct ion_system_heap *sys_heap;
 	int nr_total = 0;
 	int i, nr_freed;
@@ -203,26 +183,15 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
 		only_scan = 1;
 
 	for (i = 0; i < NUM_ORDERS; i++) {
-		uncached_pool = sys_heap->uncached_pools[i];
-		cached_pool = sys_heap->cached_pools[i];
+		pool = sys_heap->pools[i];
 
 		if (only_scan) {
-			nr_total += ion_page_pool_shrink(uncached_pool,
+			nr_total += ion_page_pool_shrink(pool,
 							 gfp_mask,
 							 nr_to_scan);
 
-			nr_total += ion_page_pool_shrink(cached_pool,
-							 gfp_mask,
-							 nr_to_scan);
 		} else {
-			nr_freed = ion_page_pool_shrink(uncached_pool,
-							gfp_mask,
-							nr_to_scan);
-			nr_to_scan -= nr_freed;
-			nr_total += nr_freed;
-			if (nr_to_scan <= 0)
-				break;
-			nr_freed = ion_page_pool_shrink(cached_pool,
+			nr_freed = ion_page_pool_shrink(pool,
 							gfp_mask,
 							nr_to_scan);
 			nr_to_scan -= nr_freed;
@@ -253,26 +222,16 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
 	struct ion_page_pool *pool;
 
 	for (i = 0; i < NUM_ORDERS; i++) {
-		pool = sys_heap->uncached_pools[i];
+		pool = sys_heap->pools[i];
 
-		seq_printf(s, "%d order %u highmem pages uncached %lu total\n",
+		seq_printf(s, "%d order %u highmem pages %lu total\n",
 			   pool->high_count, pool->order,
 			   (PAGE_SIZE << pool->order) * pool->high_count);
-		seq_printf(s, "%d order %u lowmem pages uncached %lu total\n",
+		seq_printf(s, "%d order %u lowmem pages %lu total\n",
 			   pool->low_count, pool->order,
 			   (PAGE_SIZE << pool->order) * pool->low_count);
 	}
 
-	for (i = 0; i < NUM_ORDERS; i++) {
-		pool = sys_heap->cached_pools[i];
-
-		seq_printf(s, "%d order %u highmem pages cached %lu total\n",
-			   pool->high_count, pool->order,
-			   (PAGE_SIZE << pool->order) * pool->high_count);
-		seq_printf(s, "%d order %u lowmem pages cached %lu total\n",
-			   pool->low_count, pool->order,
-			   (PAGE_SIZE << pool->order) * pool->low_count);
-	}
 	return 0;
 }
 
@@ -285,8 +244,7 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
 			ion_page_pool_destroy(pools[i]);
 }
 
-static int ion_system_heap_create_pools(struct ion_page_pool **pools,
-					bool cached)
+static int ion_system_heap_create_pools(struct ion_page_pool **pools)
 {
 	int i;
 	gfp_t gfp_flags = low_order_gfp_flags;
@@ -297,7 +255,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools,
 		if (orders[i] > 4)
 			gfp_flags = high_order_gfp_flags;
 
-		pool = ion_page_pool_create(gfp_flags, orders[i], cached);
+		pool = ion_page_pool_create(gfp_flags, orders[i]);
 		if (!pool)
 			goto err_create_pool;
 		pools[i] = pool;
@@ -320,18 +278,12 @@ static struct ion_heap *__ion_system_heap_create(void)
 	heap->heap.type = ION_HEAP_TYPE_SYSTEM;
 	heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
 
-	if (ion_system_heap_create_pools(heap->uncached_pools, false))
+	if (ion_system_heap_create_pools(heap->pools))
 		goto free_heap;
 
-	if (ion_system_heap_create_pools(heap->cached_pools, true))
-		goto destroy_uncached_pools;
-
 	heap->heap.debug_show = ion_system_heap_debug_show;
 	return &heap->heap;
 
-destroy_uncached_pools:
-	ion_system_heap_destroy_pools(heap->uncached_pools);
-
 free_heap:
 	kfree(heap);
 	return ERR_PTR(-ENOMEM);
diff --git a/drivers/staging/ccree/Kconfig b/drivers/staging/ccree/Kconfig
index c94dfe8adb63..168191fa0357 100644
--- a/drivers/staging/ccree/Kconfig
+++ b/drivers/staging/ccree/Kconfig
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
-config CRYPTO_DEV_CCREE
+config CRYPTO_DEV_CCREE_OLD
 	tristate "Support for ARM TrustZone CryptoCell C7XX family of Crypto accelerators"
-	depends on CRYPTO && CRYPTO_HW && OF && HAS_DMA
+	depends on CRYPTO && CRYPTO_HW && OF && HAS_DMA && BROKEN
 	default n
 	select CRYPTO_HASH
 	select CRYPTO_BLKCIPHER
diff --git a/drivers/staging/ccree/Makefile b/drivers/staging/ccree/Makefile
index bdc27970f95f..553db5c45354 100644
--- a/drivers/staging/ccree/Makefile
+++ b/drivers/staging/ccree/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_CRYPTO_DEV_CCREE) := ccree.o
+obj-$(CONFIG_CRYPTO_DEV_CCREE_OLD) := ccree.o
 ccree-y := cc_driver.o cc_buffer_mgr.o cc_request_mgr.o cc_cipher.o cc_hash.o cc_aead.o cc_ivgen.o cc_sram_mgr.o
 ccree-$(CONFIG_CRYPTO_FIPS) += cc_fips.o
 ccree-$(CONFIG_DEBUG_FS) += cc_debugfs.o
diff --git a/drivers/staging/ccree/cc_aead.c b/drivers/staging/ccree/cc_aead.c
index b58413172231..1a58040111c7 100644
--- a/drivers/staging/ccree/cc_aead.c
+++ b/drivers/staging/ccree/cc_aead.c
@@ -257,7 +257,8 @@ static void cc_aead_complete(struct device *dev, void *cc_req, int err)
 	aead_request_complete(areq, err);
 }
 
-static int xcbc_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
+static unsigned int xcbc_setkey(struct cc_hw_desc *desc,
+				struct cc_aead_ctx *ctx)
 {
 	/* Load the AES key */
 	hw_desc_init(&desc[0]);
@@ -297,7 +298,8 @@ static int xcbc_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
 	return 4;
 }
 
-static int hmac_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
+static unsigned int hmac_setkey(struct cc_hw_desc *desc,
+				struct cc_aead_ctx *ctx)
 {
 	unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST };
 	unsigned int digest_ofs = 0;
@@ -307,7 +309,7 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
 			CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
 	struct cc_hmac_s *hmac = &ctx->auth_state.hmac;
 
-	int idx = 0;
+	unsigned int idx = 0;
 	int i;
 
 	/* calc derived HMAC key */
@@ -544,7 +546,8 @@ cc_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
 	struct cc_crypto_req cc_req = {};
 	struct crypto_authenc_key_param *param;
 	struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ];
-	int seq_len = 0, rc = -EINVAL;
+	unsigned int seq_len = 0;
+	int rc = -EINVAL;
 	struct device *dev = drvdata_to_dev(ctx->drvdata);
 
 	dev_dbg(dev, "Setting key in context @%p for %s. key=%p keylen=%u\n",
@@ -1883,7 +1886,7 @@ static int cc_proc_aead(struct aead_request *req,
 			enum drv_crypto_direction direct)
 {
 	int rc = 0;
-	int seq_len = 0;
+	unsigned int seq_len = 0;
 	struct cc_hw_desc desc[MAX_AEAD_PROCESS_SEQ];
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
diff --git a/drivers/staging/ccree/cc_buffer_mgr.c b/drivers/staging/ccree/cc_buffer_mgr.c
index 14b2eabbf70a..6dbc9b4d6eb8 100644
--- a/drivers/staging/ccree/cc_buffer_mgr.c
+++ b/drivers/staging/ccree/cc_buffer_mgr.c
@@ -1018,7 +1018,7 @@ static int cc_aead_chain_data(struct cc_drvdata *drvdata,
 	struct device *dev = drvdata_to_dev(drvdata);
 	enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
 	unsigned int authsize = areq_ctx->req_authsize;
-	int src_last_bytes = 0, dst_last_bytes = 0;
+	u32 src_last_bytes = 0, dst_last_bytes = 0;
 	int rc = 0;
 	u32 src_mapped_nents = 0, dst_mapped_nents = 0;
 	u32 offset = 0;
diff --git a/drivers/staging/ccree/cc_cipher.c b/drivers/staging/ccree/cc_cipher.c
index d4ac0ff2ffcf..13a7fc2094f6 100644
--- a/drivers/staging/ccree/cc_cipher.c
+++ b/drivers/staging/ccree/cc_cipher.c
@@ -630,7 +630,8 @@ static int cc_cipher_process(struct ablkcipher_request *req,
 	struct device *dev = drvdata_to_dev(ctx_p->drvdata);
 	struct cc_hw_desc desc[MAX_ABLKCIPHER_SEQ_LEN];
 	struct cc_crypto_req cc_req = {};
-	int rc, seq_len = 0, cts_restore_flag = 0;
+	int rc, cts_restore_flag = 0;
+	unsigned int seq_len = 0;
 	gfp_t flags = cc_gfp_flags(&req->base);
 
 	dev_dbg(dev, "%s req=%p info=%p nbytes=%d\n",
diff --git a/drivers/staging/ccree/cc_hash.c b/drivers/staging/ccree/cc_hash.c
index 8afc39f10bb3..9529f16d168d 100644
--- a/drivers/staging/ccree/cc_hash.c
+++ b/drivers/staging/ccree/cc_hash.c
@@ -410,7 +410,7 @@ static int cc_hash_digest(struct ahash_request *req)
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
 	cc_sram_addr_t larval_digest_addr =
 		cc_larval_digest_addr(ctx->drvdata, ctx->hash_mode);
-	int idx = 0;
+	unsigned int idx = 0;
 	int rc = 0;
 	gfp_t flags = cc_gfp_flags(&req->base);
 
@@ -506,7 +506,7 @@ static int cc_hash_digest(struct ahash_request *req)
 }
 
 static int cc_restore_hash(struct cc_hw_desc *desc, struct cc_hash_ctx *ctx,
-			   struct ahash_req_ctx *state, int idx)
+			   struct ahash_req_ctx *state, unsigned int idx)
 {
 	/* Restore hash digest */
 	hw_desc_init(&desc[idx]);
@@ -621,7 +621,7 @@ static int cc_hash_finup(struct ahash_request *req)
 	bool is_hmac = ctx->is_hmac;
 	struct cc_crypto_req cc_req = {};
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
-	int idx = 0;
+	unsigned int idx = 0;
 	int rc;
 	gfp_t flags = cc_gfp_flags(&req->base);
 
@@ -680,7 +680,7 @@ static int cc_hash_final(struct ahash_request *req)
 	bool is_hmac = ctx->is_hmac;
 	struct cc_crypto_req cc_req = {};
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
-	int idx = 0;
+	unsigned int idx = 0;
 	int rc;
 	gfp_t flags = cc_gfp_flags(&req->base);
 
@@ -945,7 +945,8 @@ static int cc_xcbc_setkey(struct crypto_ahash *ahash,
 	struct cc_crypto_req cc_req = {};
 	struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash);
 	struct device *dev = drvdata_to_dev(ctx->drvdata);
-	int idx = 0, rc = 0;
+	unsigned int idx = 0;
+	int rc = 0;
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
 
 	dev_dbg(dev, "===== setkey (%d) ====\n", keylen);
@@ -1229,7 +1230,7 @@ static int cc_mac_final(struct ahash_request *req)
 	struct device *dev = drvdata_to_dev(ctx->drvdata);
 	struct cc_crypto_req cc_req = {};
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
-	int idx = 0;
+	unsigned int idx = 0;
 	int rc = 0;
 	u32 key_size, key_len;
 	u32 digestsize = crypto_ahash_digestsize(tfm);
@@ -1351,7 +1352,7 @@ static int cc_mac_finup(struct ahash_request *req)
 	struct device *dev = drvdata_to_dev(ctx->drvdata);
 	struct cc_crypto_req cc_req = {};
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
-	int idx = 0;
+	unsigned int idx = 0;
 	int rc = 0;
 	u32 key_len = 0;
 	u32 digestsize = crypto_ahash_digestsize(tfm);
@@ -1435,7 +1436,7 @@ static int cc_mac_digest(struct ahash_request *req)
 	struct cc_crypto_req cc_req = {};
 	struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
 	u32 key_len;
-	int idx = 0;
+	unsigned int idx = 0;
 	int rc;
 	gfp_t flags = cc_gfp_flags(&req->base);
 
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
index 2817e67df3d5..1ea5747b5f22 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
@@ -1864,7 +1864,6 @@ static int setup_dpni(struct fsl_mc_device *ls_dev)
 	if (err)
 		goto close;
 
-
 	return 0;
 
 close:
diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig
index 1f9100049176..b35ef7ee6901 100644
--- a/drivers/staging/fsl-mc/bus/Kconfig
+++ b/drivers/staging/fsl-mc/bus/Kconfig
@@ -7,7 +7,7 @@
 
 config FSL_MC_BUS
 	bool "QorIQ DPAA2 fsl-mc bus driver"
-	depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86 || PPC)))
+	depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC)))
 	select GENERIC_MSI_IRQ_DOMAIN
 	help
 	  Driver to enable the bus infrastructure for the QorIQ DPAA2
diff --git a/drivers/staging/ipx/af_ipx.c b/drivers/staging/ipx/af_ipx.c
index d21a9d128d3e..5703dd176787 100644
--- a/drivers/staging/ipx/af_ipx.c
+++ b/drivers/staging/ipx/af_ipx.c
@@ -1577,7 +1577,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
 
 
 static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
-			int *uaddr_len, int peer)
+			int peer)
 {
 	struct ipx_address *addr;
 	struct sockaddr_ipx sipx;
@@ -1585,8 +1585,6 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
 	struct ipx_sock *ipxs = ipx_sk(sk);
 	int rc;
 
-	*uaddr_len = sizeof(struct sockaddr_ipx);
-
 	lock_sock(sk);
 	if (peer) {
 		rc = -ENOTCONN;
@@ -1620,7 +1618,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
 	sipx.sipx_zero	 = 0;
 	memcpy(uaddr, &sipx, sizeof(sipx));
 
-	rc = 0;
+	rc = sizeof(struct sockaddr_ipx);
 out:
 	release_sock(sk);
 	return rc;
diff --git a/drivers/staging/irda/net/af_irda.c b/drivers/staging/irda/net/af_irda.c
index 2f1e9ab3d6d0..c13553a9ee11 100644
--- a/drivers/staging/irda/net/af_irda.c
+++ b/drivers/staging/irda/net/af_irda.c
@@ -697,7 +697,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
  *
  */
 static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
-			int *uaddr_len, int peer)
+			int peer)
 {
 	struct sockaddr_irda saddr;
 	struct sock *sk = sock->sk;
@@ -720,11 +720,9 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
 	pr_debug("%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel);
 	pr_debug("%s(), addr = %08x\n", __func__, saddr.sir_addr);
 
-	/* uaddr_len come to us uninitialised */
-	*uaddr_len = sizeof (struct sockaddr_irda);
-	memcpy(uaddr, &saddr, *uaddr_len);
+	memcpy(uaddr, &saddr, sizeof (struct sockaddr_irda));
 
-	return 0;
+	return sizeof (struct sockaddr_irda);
 }
 
 /*
diff --git a/drivers/staging/lustre/TODO b/drivers/staging/lustre/TODO
index f194417d0af7..94446487748a 100644
--- a/drivers/staging/lustre/TODO
+++ b/drivers/staging/lustre/TODO
@@ -1,12 +1,302 @@
-* Possible remaining coding style fix.
-* Remove deadcode.
-* Separate client/server functionality. Functions only used by server can be
-  removed from client.
-* Clean up libcfs layer. Ideally we can remove include/linux/libcfs entirely.
-* Clean up CLIO layer. Lustre client readahead/writeback control needs to better
-  suit kernel providings.
-* Add documents in Documentation.
-* Other minor misc cleanups...
+Currently all the work directed toward the lustre upstream client is tracked
+at the following link:
+
+https://jira.hpdd.intel.com/browse/LU-9679
+
+Under this ticket you will see the following work items that need to be
+addressed:
+
+******************************************************************************
+* libcfs cleanup
+*
+* https://jira.hpdd.intel.com/browse/LU-9859
+*
+* Track all the cleanups and simplification of the libcfs module. Remove
+* functions the kernel provides. Possible intergrate some of the functionality
+* into the kernel proper.
+*
+******************************************************************************
+
+https://jira.hpdd.intel.com/browse/LU-100086
+
+LNET_MINOR conflicts with USERIO_MINOR
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8130
+
+Fix and simplify libcfs hash handling
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8703
+
+The current way we handle SMP is wrong. Platforms like ARM and KNL can have
+core and NUMA setups with things like NUMA nodes with no cores. We need to
+handle such cases. This work also greatly simplified the lustre SMP code.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9019
+
+Replace libcfs time API with standard kernel APIs. Also migrate away from
+jiffies. We found jiffies can vary on nodes which can lead to corner cases
+that can break the file system due to nodes having inconsistent behavior.
+So move to time64_t and ktime_t as much as possible.
+
+******************************************************************************
+* Proper IB support for ko2iblnd
+******************************************************************************
+https://jira.hpdd.intel.com/browse/LU-9179
+
+Poor performance for the ko2iblnd driver. This is related to many of the
+patches below that are missing from the linux client.
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9886
+
+Crash in upstream kiblnd_handle_early_rxs()
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10394 / LU-10526 / LU-10089
+
+Default to default to using MEM_REG
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10459
+
+throttle tx based on queue depth
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9943
+
+correct WR fast reg accounting
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10291
+
+remove concurrent_sends tunable
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10213
+
+calculate qp max_send_wrs properly
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9810
+
+use less CQ entries for each connection
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10129 / LU-9180
+
+rework map_on_demand behavior
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10129
+
+query device capabilities
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10015
+
+fix race at kiblnd_connect_peer
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9983
+
+allow for discontiguous fragments
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9500
+
+Don't Page Align remote_addr with FastReg
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9448
+
+handle empty CPTs
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9507
+
+Don't Assert On Reconnect with MultiQP
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9472
+
+Fix FastReg map/unmap for MLX5
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9425
+
+Turn on 2 sges by default
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8943
+
+Enable Multiple OPA Endpoints between Nodes
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-5718
+
+multiple sges for work request
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9094
+
+kill timedout txs from ibp_tx_queue
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9094
+
+reconnect peer for REJ_INVALID_SERVICE_ID
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8752
+
+Stop MLX5 triggering a dump_cqe
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8874
+
+Move ko2iblnd to latest RDMA changes
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8875 / LU-8874
+
+Change to new RDMA done callback mechanism
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9164 / LU-8874
+
+Incorporate RDMA map/unamp API's into ko2iblnd
+
+******************************************************************************
+* sysfs/debugfs fixes
+*
+* https://jira.hpdd.intel.com/browse/LU-8066
+*
+* The original migration to sysfs was done in haste without properly working
+* utilities to test the changes. This covers the work to restore the proper
+* behavior. Huge project to make this right.
+*
+******************************************************************************
+
+https://jira.hpdd.intel.com/browse/LU-9431
+
+The function class_process_proc_param was used for our mass updates of proc
+tunables. It didn't work with sysfs and it was just ugly so it was removed.
+In the process the ability to mass update thousands of clients was lost. This
+work restores this in a sane way.
+
+------------------------------------------------------------------------------
+https://jira.hpdd.intel.com/browse/LU-9091
+
+One the major request of users is the ability to pass in parameters into a
+sysfs file in various different units. For example we can set max_pages_per_rpc
+but this can vary on platforms due to different platform sizes. So you can
+set this like max_pages_per_rpc=16MiB. The original code to handle this written
+before the string helpers were created so the code doesn't follow that format
+but it would be easy to move to. Currently the string helpers does the reverse
+of what we need, changing bytes to string. We need to change a string to bytes.
+
+******************************************************************************
+* Proper user land to kernel space interface for Lustre
+*
+* https://jira.hpdd.intel.com/browse/LU-9680
+*
+******************************************************************************
+
+https://jira.hpdd.intel.com/browse/LU-8915
+
+Don't use linux list structure as user land arguments for lnet selftest.
+This code is pretty poor quality and really needs to be reworked.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8834
+
+The lustre ioctl LL_IOC_FUTIMES_3 is very generic. Need to either work with
+other file systems with similar functionality and make a common syscall
+interface or rework our server code to automagically do it for us.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-6202
+
+Cleanup up ioctl handling. We have many obsolete ioctls. Also the way we do
+ioctls can be changed over to netlink. This also has the benefit of working
+better with HPC systems that do IO forwarding. Such systems don't like ioctls
+very well.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9667
+
+More cleanups by making our utilities use sysfs instead of ioctls for LNet.
+Also it has been requested to move the remaining ioctls to the netlink API.
+
+******************************************************************************
+* Misc
+******************************************************************************
+
+------------------------------------------------------------------------------
+https://jira.hpdd.intel.com/browse/LU-9855
+
+Clean up obdclass preprocessor code. One of the major eye sores is the various
+pointer redirections and macros used by the obdclass. This makes the code very
+difficult to understand. It was requested by the Al Viro to clean this up before
+we leave staging.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9633
+
+Migrate to sphinx kernel-doc style comments. Add documents in Documentation.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-6142
+
+Possible remaining coding style fix. Remove deadcode. Enforce kernel code
+style. Other minor misc cleanups...
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8837
+
+Separate client/server functionality. Functions only used by server can be
+removed from client. Most of this has been done but we need a inspect of the
+code to make sure.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8964
+
+Lustre client readahead/writeback control needs to better suit kernel providings.
+Currently its being explored. We could end up replacing the CLIO read ahead
+abstract with the kernel proper version.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9862
+
+Patch that landed for LU-7890 leads to static checker errors
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9868
+
+dcache/namei fixes for lustre
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10467
+
+use standard linux wait_events macros work by Neil Brown
+
+------------------------------------------------------------------------------
 
 Please send any patches to Greg Kroah-Hartman <greg@kroah.com>, Andreas Dilger
-<andreas.dilger@intel.com>, and Oleg Drokin <oleg.drokin@intel.com>.
+<andreas.dilger@intel.com>, James Simmons <jsimmons@infradead.org> and
+Oleg Drokin <oleg.drokin@intel.com>.
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
index 1b98f0953afb..9290a19429e7 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
@@ -66,8 +66,8 @@ extern unsigned int libcfs_panic_on_lbug;
 # define DEBUG_SUBSYSTEM S_UNDEFINED
 #endif
 
-#define CDEBUG_DEFAULT_MAX_DELAY (cfs_time_seconds(600))	 /* jiffies */
-#define CDEBUG_DEFAULT_MIN_DELAY ((cfs_time_seconds(1) + 1) / 2) /* jiffies */
+#define CDEBUG_DEFAULT_MAX_DELAY (600 * HZ)	 /* jiffies */
+#define CDEBUG_DEFAULT_MIN_DELAY ((HZ + 1) / 2) /* jiffies */
 #define CDEBUG_DEFAULT_BACKOFF   2
 struct cfs_debug_limit_state {
 	unsigned long   cdls_next;
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h
index 9699646decb9..c4f25be78268 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h
@@ -62,7 +62,7 @@ static inline int cfs_time_aftereq(unsigned long t1, unsigned long t2)
 
 static inline unsigned long cfs_time_shift(int seconds)
 {
-	return cfs_time_add(cfs_time_current(), cfs_time_seconds(seconds));
+	return cfs_time_add(cfs_time_current(), seconds * HZ);
 }
 
 /*
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
index aece13698eb4..805cb326af86 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
@@ -65,11 +65,6 @@ static inline unsigned long cfs_time_current(void)
 	return jiffies;
 }
 
-static inline long cfs_time_seconds(int seconds)
-{
-	return ((long)seconds) * msecs_to_jiffies(MSEC_PER_SEC);
-}
-
 static inline long cfs_duration_sec(long d)
 {
 	return d / msecs_to_jiffies(MSEC_PER_SEC);
@@ -85,7 +80,7 @@ static inline u64 cfs_time_add_64(u64 t, u64 d)
 static inline u64 cfs_time_shift_64(int seconds)
 {
 	return cfs_time_add_64(cfs_time_current_64(),
-			       cfs_time_seconds(seconds));
+			       seconds * HZ);
 }
 
 static inline int cfs_time_before_64(u64 t1, u64 t2)
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index ec84edfda271..7ae2955c4db6 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -1211,7 +1211,7 @@ static struct kib_hca_dev *kiblnd_current_hdev(struct kib_dev *dev)
 			CDEBUG(D_NET, "%s: Wait for failover\n",
 			       dev->ibd_ifname);
 		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1) / 100);
+		schedule_timeout(HZ / 100);
 
 		read_lock_irqsave(&kiblnd_data.kib_global_lock, flags);
 	}
@@ -1921,7 +1921,7 @@ struct list_head *kiblnd_pool_alloc_node(struct kib_poolset *ps)
 
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(interval);
-		if (interval < cfs_time_seconds(1))
+		if (interval < HZ)
 			interval *= 2;
 
 		goto again;
@@ -2541,7 +2541,7 @@ static void kiblnd_base_shutdown(void)
 			       "Waiting for %d threads to terminate\n",
 			       atomic_read(&kiblnd_data.kib_nthreads));
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(cfs_time_seconds(1));
+			schedule_timeout(HZ);
 		}
 
 		/* fall through */
@@ -2592,7 +2592,7 @@ static void kiblnd_shutdown(struct lnet_ni *ni)
 			       libcfs_nid2str(ni->ni_nid),
 			       atomic_read(&net->ibn_npeers));
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(cfs_time_seconds(1));
+			schedule_timeout(HZ);
 		}
 
 		kiblnd_net_fini_pools(net);
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index b3e7f28eb978..ca094555e04b 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -3728,8 +3728,8 @@ kiblnd_failover_thread(void *arg)
 		add_wait_queue(&kiblnd_data.kib_failover_waitq, &wait);
 		write_unlock_irqrestore(glock, flags);
 
-		rc = schedule_timeout(long_sleep ? cfs_time_seconds(10) :
-						   cfs_time_seconds(1));
+		rc = schedule_timeout(long_sleep ? 10 * HZ :
+						   HZ);
 		remove_wait_queue(&kiblnd_data.kib_failover_waitq, &wait);
 		write_lock_irqsave(glock, flags);
 
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index ff292216290d..7086678e1c3e 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -1677,7 +1677,7 @@ ksocknal_destroy_conn(struct ksock_conn *conn)
 	switch (conn->ksnc_rx_state) {
 	case SOCKNAL_RX_LNET_PAYLOAD:
 		last_rcv = conn->ksnc_rx_deadline -
-			   cfs_time_seconds(*ksocknal_tunables.ksnd_timeout);
+			   *ksocknal_tunables.ksnd_timeout * HZ;
 		CERROR("Completing partial receive from %s[%d], ip %pI4h:%d, with error, wanted: %zd, left: %d, last alive is %ld secs ago\n",
 		       libcfs_id2str(conn->ksnc_peer->ksnp_id), conn->ksnc_type,
 		       &conn->ksnc_ipaddr, conn->ksnc_port,
@@ -2356,7 +2356,7 @@ ksocknal_base_shutdown(void)
 				ksocknal_data.ksnd_nthreads);
 			read_unlock(&ksocknal_data.ksnd_global_lock);
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(cfs_time_seconds(1));
+			schedule_timeout(HZ);
 			read_lock(&ksocknal_data.ksnd_global_lock);
 		}
 		read_unlock(&ksocknal_data.ksnd_global_lock);
@@ -2599,7 +2599,7 @@ ksocknal_shutdown(struct lnet_ni *ni)
 		       "waiting for %d peers to disconnect\n",
 		       net->ksnn_npeers);
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1));
+		schedule_timeout(HZ);
 
 		ksocknal_debug_peerhash(ni);
 
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index 11fd3a36424f..63e452f666bf 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -189,7 +189,7 @@ ksocknal_transmit(struct ksock_conn *conn, struct ksock_tx *tx)
 
 	if (ksocknal_data.ksnd_stall_tx) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_tx));
+		schedule_timeout(ksocknal_data.ksnd_stall_tx * HZ);
 	}
 
 	LASSERT(tx->tx_resid);
@@ -294,7 +294,7 @@ ksocknal_receive(struct ksock_conn *conn)
 
 	if (ksocknal_data.ksnd_stall_rx) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_rx));
+		schedule_timeout(ksocknal_data.ksnd_stall_rx * HZ);
 	}
 
 	rc = ksocknal_connsock_addref(conn);
@@ -1780,7 +1780,7 @@ ksocknal_connect(struct ksock_route *route)
 	int rc = 0;
 
 	deadline = cfs_time_add(cfs_time_current(),
-				cfs_time_seconds(*ksocknal_tunables.ksnd_timeout));
+				*ksocknal_tunables.ksnd_timeout * HZ);
 
 	write_lock_bh(&ksocknal_data.ksnd_global_lock);
 
@@ -1878,7 +1878,7 @@ ksocknal_connect(struct ksock_route *route)
 			 * so min_reconnectms should be good heuristic
 			 */
 			route->ksnr_retry_interval =
-				cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms) / 1000;
+				*ksocknal_tunables.ksnd_min_reconnectms * HZ / 1000;
 			route->ksnr_timeout = cfs_time_add(cfs_time_current(),
 							   route->ksnr_retry_interval);
 		}
@@ -1899,10 +1899,10 @@ ksocknal_connect(struct ksock_route *route)
 	route->ksnr_retry_interval *= 2;
 	route->ksnr_retry_interval =
 		max(route->ksnr_retry_interval,
-		    cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms) / 1000);
+		    (long)*ksocknal_tunables.ksnd_min_reconnectms * HZ / 1000);
 	route->ksnr_retry_interval =
 		min(route->ksnr_retry_interval,
-		    cfs_time_seconds(*ksocknal_tunables.ksnd_max_reconnectms) / 1000);
+		    (long)*ksocknal_tunables.ksnd_max_reconnectms * HZ / 1000);
 
 	LASSERT(route->ksnr_retry_interval);
 	route->ksnr_timeout = cfs_time_add(cfs_time_current(),
@@ -1972,7 +1972,7 @@ ksocknal_connd_check_start(time64_t sec, long *timeout)
 
 	if (sec - ksocknal_data.ksnd_connd_failed_stamp <= 1) {
 		/* may run out of resource, retry later */
-		*timeout = cfs_time_seconds(1);
+		*timeout = HZ;
 		return 0;
 	}
 
@@ -2031,8 +2031,8 @@ ksocknal_connd_check_stop(time64_t sec, long *timeout)
 	val = (int)(ksocknal_data.ksnd_connd_starting_stamp +
 		    SOCKNAL_CONND_TIMEOUT - sec);
 
-	*timeout = (val > 0) ? cfs_time_seconds(val) :
-			       cfs_time_seconds(SOCKNAL_CONND_TIMEOUT);
+	*timeout = (val > 0) ? val * HZ :
+			       SOCKNAL_CONND_TIMEOUT * HZ;
 	if (val > 0)
 		return 0;
 
@@ -2307,7 +2307,7 @@ ksocknal_send_keepalive_locked(struct ksock_peer *peer)
 	if (*ksocknal_tunables.ksnd_keepalive <= 0 ||
 	    time_before(cfs_time_current(),
 			cfs_time_add(peer->ksnp_last_alive,
-				     cfs_time_seconds(*ksocknal_tunables.ksnd_keepalive))))
+				     *ksocknal_tunables.ksnd_keepalive * HZ)))
 		return 0;
 
 	if (time_before(cfs_time_current(), peer->ksnp_send_keepalive))
@@ -2563,7 +2563,7 @@ ksocknal_reaper(void *arg)
 					     ksocknal_data.ksnd_peer_hash_size;
 			}
 
-			deadline = cfs_time_add(deadline, cfs_time_seconds(p));
+			deadline = cfs_time_add(deadline, p * HZ);
 		}
 
 		if (nenomem_conns) {
diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c
index 551c45bf4108..c70d2ae29b11 100644
--- a/drivers/staging/lustre/lnet/libcfs/debug.c
+++ b/drivers/staging/lustre/lnet/libcfs/debug.c
@@ -113,7 +113,7 @@ static int param_set_delay_minmax(const char *val,
 	if (rc)
 		return -EINVAL;
 
-	d = cfs_time_seconds(sec) / 100;
+	d = sec * HZ / 100;
 	if (d < min || d > max)
 		return -EINVAL;
 
diff --git a/drivers/staging/lustre/lnet/libcfs/fail.c b/drivers/staging/lustre/lnet/libcfs/fail.c
index 39439b303d65..d3f1e866c6a7 100644
--- a/drivers/staging/lustre/lnet/libcfs/fail.c
+++ b/drivers/staging/lustre/lnet/libcfs/fail.c
@@ -134,7 +134,7 @@ int __cfs_fail_timeout_set(u32 id, u32 value, int ms, int set)
 		CERROR("cfs_fail_timeout id %x sleeping for %dms\n",
 		       id, ms);
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(ms) / 1000);
+		schedule_timeout(ms * HZ / 1000);
 		CERROR("cfs_fail_timeout id %x awake\n", id);
 	}
 	return ret;
diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.c b/drivers/staging/lustre/lnet/libcfs/tracefile.c
index 57913aae1d88..4affca750bc5 100644
--- a/drivers/staging/lustre/lnet/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lnet/libcfs/tracefile.c
@@ -441,7 +441,7 @@ int libcfs_debug_vmsg2(struct libcfs_debug_msg_data *msgdata,
 
 		if (cfs_time_after(cfs_time_current(),
 				   cdls->cdls_next + libcfs_console_max_delay +
-				   cfs_time_seconds(10))) {
+				   10 * HZ)) {
 			/* last timeout was a long time ago */
 			cdls->cdls_delay /= libcfs_console_backoff * 4;
 		} else {
@@ -1071,7 +1071,7 @@ static int tracefiled(void *arg)
 		init_waitqueue_entry(&__wait, current);
 		add_wait_queue(&tctl->tctl_waitq, &__wait);
 		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1));
+		schedule_timeout(HZ);
 		remove_wait_queue(&tctl->tctl_waitq, &__wait);
 	}
 	complete(&tctl->tctl_stop);
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index ee85cab6f437..6c1f4941d4ba 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -365,7 +365,7 @@ lnet_acceptor(void *arg)
 			if (rc != -EAGAIN) {
 				CWARN("Accept error %d: pausing...\n", rc);
 				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout(cfs_time_seconds(1));
+				schedule_timeout(HZ);
 			}
 			continue;
 		}
diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c
index 2c7abad57104..93e6274e9dac 100644
--- a/drivers/staging/lustre/lnet/lnet/api-ni.c
+++ b/drivers/staging/lustre/lnet/lnet/api-ni.c
@@ -970,7 +970,7 @@ lnet_ping_md_unlink(struct lnet_ping_info *pinfo,
 	while (pinfo->pi_features != LNET_PING_FEAT_INVAL) {
 		CDEBUG(D_NET, "Still waiting for ping MD to unlink\n");
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1));
+		schedule_timeout(HZ);
 	}
 
 	cfs_restore_sigs(blocked);
@@ -1109,7 +1109,7 @@ lnet_clear_zombies_nis_locked(void)
 				       libcfs_nid2str(ni->ni_nid));
 			}
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(cfs_time_seconds(1));
+			schedule_timeout(HZ);
 			lnet_net_lock(LNET_LOCK_EX);
 			continue;
 		}
diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c
index c673037dbce4..ed43b3f4b114 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-move.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-move.c
@@ -524,7 +524,7 @@ lnet_peer_is_alive(struct lnet_peer *lp, unsigned long now)
 		return 0;
 
 	deadline = cfs_time_add(lp->lp_last_alive,
-				cfs_time_seconds(lp->lp_ni->ni_peertimeout));
+				lp->lp_ni->ni_peertimeout * HZ);
 	alive = cfs_time_after(deadline, now);
 
 	/* Update obsolete lp_alive except for routers assumed to be dead
@@ -562,7 +562,7 @@ lnet_peer_alive_locked(struct lnet_peer *lp)
 
 		unsigned long next_query =
 			   cfs_time_add(lp->lp_last_query,
-					cfs_time_seconds(lnet_queryinterval));
+					lnet_queryinterval * HZ);
 
 		if (time_before(now, next_query)) {
 			if (lp->lp_alive)
diff --git a/drivers/staging/lustre/lnet/lnet/lib-socket.c b/drivers/staging/lustre/lnet/lnet/lib-socket.c
index ce93806eefca..1bee667802b0 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-socket.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-socket.c
@@ -448,14 +448,13 @@ int
 lnet_sock_getaddr(struct socket *sock, bool remote, __u32 *ip, int *port)
 {
 	struct sockaddr_in sin;
-	int len = sizeof(sin);
 	int rc;
 
 	if (remote)
-		rc = kernel_getpeername(sock, (struct sockaddr *)&sin, &len);
+		rc = kernel_getpeername(sock, (struct sockaddr *)&sin);
 	else
-		rc = kernel_getsockname(sock, (struct sockaddr *)&sin, &len);
-	if (rc) {
+		rc = kernel_getsockname(sock, (struct sockaddr *)&sin);
+	if (rc < 0) {
 		CERROR("Error %d getting sock %s IP/port\n",
 		       rc, remote ? "peer" : "local");
 		return rc;
diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c
index e3468cef273b..a63b7941d435 100644
--- a/drivers/staging/lustre/lnet/lnet/net_fault.c
+++ b/drivers/staging/lustre/lnet/lnet/net_fault.c
@@ -315,9 +315,8 @@ drop_rule_match(struct lnet_drop_rule *rule, lnet_nid_t src,
 				rule->dr_time_base = now;
 
 			rule->dr_drop_time = rule->dr_time_base +
-				cfs_time_seconds(
-					prandom_u32_max(attr->u.drop.da_interval));
-			rule->dr_time_base += cfs_time_seconds(attr->u.drop.da_interval);
+				prandom_u32_max(attr->u.drop.da_interval) * HZ;
+			rule->dr_time_base += attr->u.drop.da_interval * HZ;
 
 			CDEBUG(D_NET, "Drop Rule %s->%s: next drop : %lu\n",
 			       libcfs_nid2str(attr->fa_src),
@@ -440,8 +439,7 @@ static struct delay_daemon_data	delay_dd;
 static unsigned long
 round_timeout(unsigned long timeout)
 {
-	return cfs_time_seconds((unsigned int)
-			cfs_duration_sec(cfs_time_sub(timeout, 0)) + 1);
+	return (unsigned int)rounddown(timeout, HZ) + HZ;
 }
 
 static void
@@ -483,10 +481,8 @@ delay_rule_match(struct lnet_delay_rule *rule, lnet_nid_t src,
 				rule->dl_time_base = now;
 
 			rule->dl_delay_time = rule->dl_time_base +
-				cfs_time_seconds(
-					prandom_u32_max(
-						attr->u.delay.la_interval));
-			rule->dl_time_base += cfs_time_seconds(attr->u.delay.la_interval);
+				prandom_u32_max(attr->u.delay.la_interval) * HZ;
+			rule->dl_time_base += attr->u.delay.la_interval * HZ;
 
 			CDEBUG(D_NET, "Delay Rule %s->%s: next delay : %lu\n",
 			       libcfs_nid2str(attr->fa_src),
diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c
index 3e157c10fec4..3d4caa609c83 100644
--- a/drivers/staging/lustre/lnet/lnet/peer.c
+++ b/drivers/staging/lustre/lnet/lnet/peer.c
@@ -137,7 +137,7 @@ lnet_peer_table_deathrow_wait_locked(struct lnet_peer_table *ptable,
 			       ptable->pt_zombies);
 		}
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1) >> 1);
+		schedule_timeout(HZ >> 1);
 		lnet_net_lock(cpt_locked);
 	}
 }
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index 6504761ca598..ec1d3e58519a 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -808,7 +808,7 @@ lnet_wait_known_routerstate(void)
 			return;
 
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1));
+		schedule_timeout(HZ);
 	}
 }
 
@@ -1011,7 +1011,7 @@ lnet_ping_router_locked(struct lnet_peer *rtr)
 
 	if (secs && !rtr->lp_ping_notsent &&
 	    cfs_time_after(now, cfs_time_add(rtr->lp_ping_timestamp,
-					     cfs_time_seconds(secs)))) {
+					     secs * HZ))) {
 		int rc;
 		struct lnet_process_id id;
 		struct lnet_handle_md mdh;
@@ -1185,7 +1185,7 @@ lnet_prune_rc_data(int wait_unlink)
 		CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET,
 		       "Waiting for rc buffers to unlink\n");
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1) / 4);
+		schedule_timeout(HZ / 4);
 
 		lnet_net_lock(LNET_LOCK_EX);
 	}
@@ -1282,7 +1282,7 @@ lnet_router_checker(void *arg)
 		else
 			wait_event_interruptible_timeout(the_lnet.ln_rc_waitq,
 							 false,
-							 cfs_time_seconds(1));
+							 HZ);
 	}
 
 	lnet_prune_rc_data(1); /* wait for UNLINK */
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 7aa515c34594..6dcc966b293b 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -359,7 +359,7 @@ lstcon_rpc_trans_postwait(struct lstcon_rpc_trans *trans, int timeout)
 
 	rc = wait_event_interruptible_timeout(trans->tas_waitq,
 					      lstcon_rpc_trans_check(trans),
-					      cfs_time_seconds(timeout));
+					      timeout * HZ);
 	rc = (rc > 0) ? 0 : ((rc < 0) ? -EINTR : -ETIMEDOUT);
 
 	mutex_lock(&console_session.ses_mutex);
@@ -1350,7 +1350,7 @@ lstcon_rpc_cleanup_wait(void)
 
 		CWARN("Session is shutting down, waiting for termination of transactions\n");
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1));
+		schedule_timeout(HZ);
 
 		mutex_lock(&console_session.ses_mutex);
 	}
diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c
index c7697f66f663..0ca1e3a780ca 100644
--- a/drivers/staging/lustre/lnet/selftest/framework.c
+++ b/drivers/staging/lustre/lnet/selftest/framework.c
@@ -187,7 +187,7 @@ sfw_del_session_timer(void)
 		return 0;
 	}
 
-	return EBUSY; /* racing with sfw_session_expired() */
+	return -EBUSY; /* racing with sfw_session_expired() */
 }
 
 static void
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index f8198ad1046e..9613b0a77007 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -1604,7 +1604,7 @@ srpc_startup(void)
 
 	/* 1 second pause to avoid timestamp reuse */
 	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(cfs_time_seconds(1));
+	schedule_timeout(HZ);
 	srpc_data.rpc_matchbits = ((__u64)ktime_get_real_seconds()) << 48;
 
 	srpc_data.rpc_state = SRPC_STATE_NONE;
diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h
index ad04534f000c..05466b85e1c0 100644
--- a/drivers/staging/lustre/lnet/selftest/selftest.h
+++ b/drivers/staging/lustre/lnet/selftest/selftest.h
@@ -575,7 +575,7 @@ swi_state2str(int state)
 #define selftest_wait_events()					\
 	do {							\
 		set_current_state(TASK_UNINTERRUPTIBLE);	\
-		schedule_timeout(cfs_time_seconds(1) / 10);	\
+		schedule_timeout(HZ / 10);	\
 	} while (0)
 
 #define lst_wait_until(cond, lock, fmt, ...)				\
diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c
index ab125a8524c5..9716afeb3c94 100644
--- a/drivers/staging/lustre/lnet/selftest/timer.c
+++ b/drivers/staging/lustre/lnet/selftest/timer.c
@@ -177,7 +177,7 @@ stt_timer_main(void *arg)
 
 		rc = wait_event_timeout(stt_data.stt_waitq,
 					stt_data.stt_shuttingdown,
-					cfs_time_seconds(STTIMER_SLOTTIME));
+					STTIMER_SLOTTIME * HZ);
 	}
 
 	spin_lock(&stt_data.stt_lock);
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h
index e0b17052b2ea..239aa2b1268f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h
@@ -60,7 +60,7 @@ struct obd_device;
 #define OBD_LDLM_DEVICENAME  "ldlm"
 
 #define LDLM_DEFAULT_LRU_SIZE (100 * num_online_cpus())
-#define LDLM_DEFAULT_MAX_ALIVE (cfs_time_seconds(3900)) /* 65 min */
+#define LDLM_DEFAULT_MAX_ALIVE (65 * 60 * HZ) /* 65 min */
 #define LDLM_DEFAULT_PARALLEL_AST_LIMIT 1024
 
 /**
diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h
index ca1dce15337e..1efd86f18c1f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lib.h
@@ -76,281 +76,49 @@ int do_set_info_async(struct obd_import *imp,
 
 void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id);
 
-/*
- * l_wait_event is a flexible sleeping function, permitting simple caller
- * configuration of interrupt and timeout sensitivity along with actions to
- * be performed in the event of either exception.
- *
- * The first form of usage looks like this:
- *
- * struct l_wait_info lwi = LWI_TIMEOUT_INTR(timeout, timeout_handler,
- *					   intr_handler, callback_data);
- * rc = l_wait_event(waitq, condition, &lwi);
- *
- * l_wait_event() makes the current process wait on 'waitq' until 'condition'
- * is TRUE or a "killable" signal (SIGTERM, SIKGILL, SIGINT) is pending.  It
- * returns 0 to signify 'condition' is TRUE, but if a signal wakes it before
- * 'condition' becomes true, it optionally calls the specified 'intr_handler'
- * if not NULL, and returns -EINTR.
- *
- * If a non-zero timeout is specified, signals are ignored until the timeout
- * has expired.  At this time, if 'timeout_handler' is not NULL it is called.
- * If it returns FALSE l_wait_event() continues to wait as described above with
- * signals enabled.  Otherwise it returns -ETIMEDOUT.
- *
- * LWI_INTR(intr_handler, callback_data) is shorthand for
- * LWI_TIMEOUT_INTR(0, NULL, intr_handler, callback_data)
- *
- * The second form of usage looks like this:
- *
- * struct l_wait_info lwi = LWI_TIMEOUT(timeout, timeout_handler);
- * rc = l_wait_event(waitq, condition, &lwi);
- *
- * This form is the same as the first except that it COMPLETELY IGNORES
- * SIGNALS.  The caller must therefore beware that if 'timeout' is zero, or if
- * 'timeout_handler' is not NULL and returns FALSE, then the ONLY thing that
- * can unblock the current process is 'condition' becoming TRUE.
- *
- * Another form of usage is:
- * struct l_wait_info lwi = LWI_TIMEOUT_INTERVAL(timeout, interval,
- *					       timeout_handler);
- * rc = l_wait_event(waitq, condition, &lwi);
- * This is the same as previous case, but condition is checked once every
- * 'interval' jiffies (if non-zero).
- *
- * Subtle synchronization point: this macro does *not* necessary takes
- * wait-queue spin-lock before returning, and, hence, following idiom is safe
- * ONLY when caller provides some external locking:
- *
- *	     Thread1			    Thread2
- *
- *   l_wait_event(&obj->wq, ....);				       (1)
- *
- *				    wake_up(&obj->wq):		 (2)
- *					 spin_lock(&q->lock);	  (2.1)
- *					 __wake_up_common(q, ...);     (2.2)
- *					 spin_unlock(&q->lock, flags); (2.3)
- *
- *   kfree(obj);						  (3)
- *
- * As l_wait_event() may "short-cut" execution and return without taking
- * wait-queue spin-lock, some additional synchronization is necessary to
- * guarantee that step (3) can begin only after (2.3) finishes.
- *
- * XXX nikita: some ptlrpc daemon threads have races of that sort.
- *
- */
-static inline int back_to_sleep(void *arg)
-{
-	return 0;
-}
-
-#define LWI_ON_SIGNAL_NOOP ((void (*)(void *))(-1))
-
-struct l_wait_info {
-	long lwi_timeout;
-	long lwi_interval;
-	int	    lwi_allow_intr;
-	int  (*lwi_on_timeout)(void *);
-	void (*lwi_on_signal)(void *);
-	void  *lwi_cb_data;
-};
-
-/* NB: LWI_TIMEOUT ignores signals completely */
-#define LWI_TIMEOUT(time, cb, data)	     \
-((struct l_wait_info) {			 \
-	.lwi_timeout    = time,		 \
-	.lwi_on_timeout = cb,		   \
-	.lwi_cb_data    = data,		 \
-	.lwi_interval   = 0,		    \
-	.lwi_allow_intr = 0		     \
-})
-
-#define LWI_TIMEOUT_INTERVAL(time, interval, cb, data)  \
-((struct l_wait_info) {				 \
-	.lwi_timeout    = time,			 \
-	.lwi_on_timeout = cb,			   \
-	.lwi_cb_data    = data,			 \
-	.lwi_interval   = interval,		     \
-	.lwi_allow_intr = 0			     \
-})
-
-#define LWI_TIMEOUT_INTR(time, time_cb, sig_cb, data)   \
-((struct l_wait_info) {				 \
-	.lwi_timeout    = time,			 \
-	.lwi_on_timeout = time_cb,		      \
-	.lwi_on_signal  = sig_cb,		       \
-	.lwi_cb_data    = data,			 \
-	.lwi_interval   = 0,			    \
-	.lwi_allow_intr = 0			     \
-})
-
-#define LWI_TIMEOUT_INTR_ALL(time, time_cb, sig_cb, data)       \
-((struct l_wait_info) {					 \
-	.lwi_timeout    = time,				 \
-	.lwi_on_timeout = time_cb,			      \
-	.lwi_on_signal  = sig_cb,			       \
-	.lwi_cb_data    = data,				 \
-	.lwi_interval   = 0,				    \
-	.lwi_allow_intr = 1				     \
-})
-
-#define LWI_INTR(cb, data)  LWI_TIMEOUT_INTR(0, NULL, cb, data)
-
 #define LUSTRE_FATAL_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) |		\
 			   sigmask(SIGTERM) | sigmask(SIGQUIT) |	\
 			   sigmask(SIGALRM))
-
-/**
- * wait_queue_entry_t of Linux (version < 2.6.34) is a FIFO list for exclusively
- * waiting threads, which is not always desirable because all threads will
- * be waken up again and again, even user only needs a few of them to be
- * active most time. This is not good for performance because cache can
- * be polluted by different threads.
- *
- * LIFO list can resolve this problem because we always wakeup the most
- * recent active thread by default.
- *
- * NB: please don't call non-exclusive & exclusive wait on the same
- * waitq if add_wait_queue_exclusive_head is used.
- */
-#define add_wait_queue_exclusive_head(waitq, link)		\
-{								\
-	unsigned long flags;					\
-								\
-	spin_lock_irqsave(&((waitq)->lock), flags);		\
-	__add_wait_queue_exclusive(waitq, link);		\
-	spin_unlock_irqrestore(&((waitq)->lock), flags);	\
+static inline int l_fatal_signal_pending(struct task_struct *p)
+{
+	return signal_pending(p) && sigtestsetmask(&p->pending.signal, LUSTRE_FATAL_SIGS);
 }
 
-/*
- * wait for @condition to become true, but no longer than timeout, specified
- * by @info.
- */
-#define __l_wait_event(wq, condition, info, ret, l_add_wait)		   \
-do {									   \
-	wait_queue_entry_t __wait;						 \
-	long __timeout = info->lwi_timeout;			  \
-	sigset_t   __blocked;					      \
-	int   __allow_intr = info->lwi_allow_intr;			     \
-									       \
-	ret = 0;							       \
-	if (condition)							 \
-		break;							 \
-									       \
-	init_waitqueue_entry(&__wait, current);					    \
-	l_add_wait(&wq, &__wait);					      \
-									       \
-	/* Block all signals (just the non-fatal ones if no timeout). */       \
-	if (info->lwi_on_signal && (__timeout == 0 || __allow_intr))   \
-		__blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS);	      \
-	else								   \
-		__blocked = cfs_block_sigsinv(0);			      \
-									       \
-	for (;;) {							     \
-		if (condition)						 \
-			break;						 \
-									       \
-		set_current_state(TASK_INTERRUPTIBLE);			       \
-									       \
-		if (__timeout == 0) {					  \
-			schedule();					       \
-		} else {						       \
-			long interval = info->lwi_interval ?	  \
-					     min_t(long,	     \
-						 info->lwi_interval, __timeout) : \
-					     __timeout;			\
-			long remaining = schedule_timeout(interval);\
-			__timeout = cfs_time_sub(__timeout,		    \
-					    cfs_time_sub(interval, remaining));\
-			if (__timeout == 0) {				  \
-				if (!info->lwi_on_timeout ||		      \
-				    info->lwi_on_timeout(info->lwi_cb_data)) { \
-					ret = -ETIMEDOUT;		      \
-					break;				 \
-				}					      \
-				/* Take signals after the timeout expires. */  \
-				if (info->lwi_on_signal)		       \
-				    (void)cfs_block_sigsinv(LUSTRE_FATAL_SIGS);\
-			}						      \
-		}							      \
-									       \
-		set_current_state(TASK_RUNNING);			       \
-									       \
-		if (condition)						 \
-			break;						 \
-		if (signal_pending(current)) {				    \
-			if (info->lwi_on_signal &&		     \
-			    (__timeout == 0 || __allow_intr)) {		\
-				if (info->lwi_on_signal != LWI_ON_SIGNAL_NOOP) \
-					info->lwi_on_signal(info->lwi_cb_data);\
-				ret = -EINTR;				  \
-				break;					 \
-			}						      \
-			/* We have to do this here because some signals */     \
-			/* are not blockable - ie from strace(1).       */     \
-			/* In these cases we want to schedule_timeout() */     \
-			/* again, because we don't want that to return  */     \
-			/* -EINTR when the RPC actually succeeded.      */     \
-			/* the recalc_sigpending() below will deliver the */     \
-			/* signal properly.			     */     \
-			cfs_clear_sigpending();				\
-		}							      \
-	}								      \
-									       \
-	cfs_restore_sigs(__blocked);					   \
-									       \
-	remove_wait_queue(&wq, &__wait);					   \
-} while (0)
-
-#define l_wait_event(wq, condition, info)		       \
-({							      \
-	int		 __ret;			      \
-	struct l_wait_info *__info = (info);		    \
-								\
-	__l_wait_event(wq, condition, __info,		   \
-		       __ret, add_wait_queue);		   \
-	__ret;						  \
-})
+/** @} lib */
 
-#define l_wait_event_exclusive(wq, condition, info)	     \
-({							      \
-	int		 __ret;			      \
-	struct l_wait_info *__info = (info);		    \
-								\
-	__l_wait_event(wq, condition, __info,		   \
-		       __ret, add_wait_queue_exclusive);	 \
-	__ret;						  \
-})
 
-#define l_wait_event_exclusive_head(wq, condition, info)	\
-({							      \
-	int		 __ret;			      \
-	struct l_wait_info *__info = (info);		    \
-								\
-	__l_wait_event(wq, condition, __info,		   \
-		       __ret, add_wait_queue_exclusive_head);    \
-	__ret;						  \
-})
 
-#define l_wait_condition(wq, condition)			 \
-({							      \
-	struct l_wait_info lwi = { 0 };			 \
-	l_wait_event(wq, condition, &lwi);		      \
+/* l_wait_event_abortable() is a bit like wait_event_killable()
+ * except there is a fixed set of signals which will abort:
+ * LUSTRE_FATAL_SIGS
+ */
+#define l_wait_event_abortable(wq, condition)				\
+({									\
+	sigset_t __blocked;						\
+	int __ret = 0;							\
+	__blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS);		\
+	__ret = wait_event_interruptible(wq, condition);		\
+	cfs_restore_sigs(__blocked);					\
+	__ret;								\
 })
 
-#define l_wait_condition_exclusive(wq, condition)	       \
-({							      \
-	struct l_wait_info lwi = { 0 };			 \
-	l_wait_event_exclusive(wq, condition, &lwi);	    \
+#define l_wait_event_abortable_timeout(wq, condition, timeout)		\
+({									\
+	sigset_t __blocked;						\
+	int __ret = 0;							\
+	__blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS);		\
+	__ret = wait_event_interruptible_timeout(wq, condition, timeout);\
+	cfs_restore_sigs(__blocked);					\
+	__ret;								\
 })
 
-#define l_wait_condition_exclusive_head(wq, condition)	  \
-({							      \
-	struct l_wait_info lwi = { 0 };			 \
-	l_wait_event_exclusive_head(wq, condition, &lwi);       \
+#define l_wait_event_abortable_exclusive(wq, condition)			\
+({									\
+	sigset_t __blocked;						\
+	int __ret = 0;							\
+	__blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS);		\
+	__ret = wait_event_interruptible_exclusive(wq, condition);	\
+	cfs_restore_sigs(__blocked);					\
+	__ret;								\
 })
-
-/** @} lib */
-
 #endif /* _LUSTRE_LIB_H */
diff --git a/drivers/staging/lustre/lustre/include/lustre_lmv.h b/drivers/staging/lustre/lustre/include/lustre_lmv.h
index f4298e5f7543..080ec1f8e19f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lmv.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lmv.h
@@ -63,7 +63,7 @@ lsm_md_eq(const struct lmv_stripe_md *lsm1, const struct lmv_stripe_md *lsm2)
 	    lsm1->lsm_md_master_mdt_index != lsm2->lsm_md_master_mdt_index ||
 	    lsm1->lsm_md_hash_type != lsm2->lsm_md_hash_type ||
 	    lsm1->lsm_md_layout_version != lsm2->lsm_md_layout_version ||
-	    !strcmp(lsm1->lsm_md_pool_name, lsm2->lsm_md_pool_name))
+	    strcmp(lsm1->lsm_md_pool_name, lsm2->lsm_md_pool_name) != 0)
 		return false;
 
 	for (idx = 0; idx < lsm1->lsm_md_stripe_count; idx++) {
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h
index 007e1ec3f0f4..a9c9992a2502 100644
--- a/drivers/staging/lustre/lustre/include/lustre_mdc.h
+++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h
@@ -124,7 +124,7 @@ static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck,
 	 */
 	while (unlikely(lck->rpcl_it == MDC_FAKE_RPCL_IT)) {
 		mutex_unlock(&lck->rpcl_mutex);
-		schedule_timeout(cfs_time_seconds(1) / 4);
+		schedule_timeout(HZ / 4);
 		goto again;
 	}
 
diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h
index 3ff5de4770e8..5a4434e7c85a 100644
--- a/drivers/staging/lustre/lustre/include/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/lustre_net.h
@@ -1260,7 +1260,6 @@ enum {
 	SVC_STARTING    = 1 << 2,
 	SVC_RUNNING     = 1 << 3,
 	SVC_EVENT       = 1 << 4,
-	SVC_SIGNAL      = 1 << 5,
 };
 
 #define PTLRPC_THR_NAME_LEN		32
@@ -1333,11 +1332,6 @@ static inline int thread_is_event(struct ptlrpc_thread *thread)
 	return !!(thread->t_flags & SVC_EVENT);
 }
 
-static inline int thread_is_signal(struct ptlrpc_thread *thread)
-{
-	return !!(thread->t_flags & SVC_SIGNAL);
-}
-
 static inline void thread_clear_flags(struct ptlrpc_thread *thread, __u32 flags)
 {
 	thread->t_flags &= ~flags;
@@ -2268,7 +2262,7 @@ static inline int ptlrpc_send_limit_expired(struct ptlrpc_request *req)
 {
 	if (req->rq_delay_limit != 0 &&
 	    time_before(cfs_time_add(req->rq_queued_time,
-				     cfs_time_seconds(req->rq_delay_limit)),
+				     req->rq_delay_limit * HZ),
 			cfs_time_current())) {
 		return 1;
 	}
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
index 657ab95091a0..411b540b96d9 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
@@ -310,24 +310,6 @@ static int ldlm_process_flock_lock(struct ldlm_lock *req)
 	return LDLM_ITER_CONTINUE;
 }
 
-struct ldlm_flock_wait_data {
-	struct ldlm_lock *fwd_lock;
-};
-
-static void
-ldlm_flock_interrupted_wait(void *data)
-{
-	struct ldlm_lock *lock;
-
-	lock = ((struct ldlm_flock_wait_data *)data)->fwd_lock;
-
-	lock_res_and_lock(lock);
-
-	/* client side - set flag to prevent lock from being put on LRU list */
-	ldlm_set_cbpending(lock);
-	unlock_res_and_lock(lock);
-}
-
 /**
  * Flock completion callback function.
  *
@@ -342,8 +324,6 @@ int
 ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
 {
 	struct file_lock		*getlk = lock->l_ast_data;
-	struct ldlm_flock_wait_data	fwd;
-	struct l_wait_info		lwi;
 	int				rc = 0;
 
 	OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT2, 4);
@@ -372,13 +352,17 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
 
 	LDLM_DEBUG(lock,
 		   "client-side enqueue returned a blocked lock, sleeping");
-	fwd.fwd_lock = lock;
-	lwi = LWI_TIMEOUT_INTR(0, NULL, ldlm_flock_interrupted_wait, &fwd);
 
 	/* Go to sleep until the lock is granted. */
-	rc = l_wait_event(lock->l_waitq, is_granted_or_cancelled(lock), &lwi);
+	rc = l_wait_event_abortable(lock->l_waitq, is_granted_or_cancelled(lock));
 
 	if (rc) {
+		lock_res_and_lock(lock);
+
+		/* client side - set flag to prevent lock from being put on LRU list */
+		ldlm_set_cbpending(lock);
+		unlock_res_and_lock(lock);
+
 		LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
 			   rc);
 		return rc;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
index 7cbc6a06afec..95bea351d21d 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -1349,7 +1349,6 @@ enum ldlm_mode ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
 		if ((flags & LDLM_FL_LVB_READY) && !ldlm_is_lvb_ready(lock)) {
 			__u64 wait_flags = LDLM_FL_LVB_READY |
 				LDLM_FL_DESTROYED | LDLM_FL_FAIL_NOTIFIED;
-			struct l_wait_info lwi;
 
 			if (lock->l_completion_ast) {
 				int err = lock->l_completion_ast(lock,
@@ -1366,13 +1365,10 @@ enum ldlm_mode ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
 				}
 			}
 
-			lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(obd_timeout),
-					       NULL, LWI_ON_SIGNAL_NOOP, NULL);
-
 			/* XXX FIXME see comment on CAN_MATCH in lustre_dlm.h */
-			l_wait_event(lock->l_waitq,
-				     lock->l_flags & wait_flags,
-				     &lwi);
+			wait_event_idle_timeout(lock->l_waitq,
+						lock->l_flags & wait_flags,
+						obd_timeout * HZ);
 			if (!ldlm_is_lvb_ready(lock)) {
 				if (flags & LDLM_FL_TEST_LOCK)
 					LDLM_LOCK_RELEASE(lock);
@@ -1913,14 +1909,12 @@ void ldlm_cancel_callback(struct ldlm_lock *lock)
 		ldlm_set_bl_done(lock);
 		wake_up_all(&lock->l_waitq);
 	} else if (!ldlm_is_bl_done(lock)) {
-		struct l_wait_info lwi = { 0 };
-
 		/*
 		 * The lock is guaranteed to have been canceled once
 		 * returning from this function.
 		 */
 		unlock_res_and_lock(lock);
-		l_wait_event(lock->l_waitq, is_bl_done(lock), &lwi);
+		wait_event_idle(lock->l_waitq, is_bl_done(lock));
 		lock_res_and_lock(lock);
 	}
 }
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
index 5f6e7c933b81..58913e628124 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
@@ -163,7 +163,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
 	LDLM_DEBUG(lock, "client completion callback handler START");
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CANCEL_BL_CB_RACE)) {
-		int to = cfs_time_seconds(1);
+		int to = HZ;
 
 		while (to > 0) {
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -327,7 +327,7 @@ static void ldlm_handle_gl_callback(struct ptlrpc_request *req,
 	    !lock->l_readers && !lock->l_writers &&
 	    cfs_time_after(cfs_time_current(),
 			   cfs_time_add(lock->l_last_used,
-					cfs_time_seconds(10)))) {
+					10 * HZ))) {
 		unlock_res_and_lock(lock);
 		if (ldlm_bl_to_thread_lock(ns, NULL, lock))
 			ldlm_handle_bl_callback(ns, NULL, lock);
@@ -833,17 +833,15 @@ static int ldlm_bl_thread_main(void *arg)
 	/* cannot use bltd after this, it is only on caller's stack */
 
 	while (1) {
-		struct l_wait_info lwi = { 0 };
 		struct ldlm_bl_work_item *blwi = NULL;
 		struct obd_export *exp = NULL;
 		int rc;
 
 		rc = ldlm_bl_get_work(blp, &blwi, &exp);
 		if (!rc)
-			l_wait_event_exclusive(blp->blp_waitq,
-					       ldlm_bl_get_work(blp, &blwi,
-								&exp),
-					       &lwi);
+			wait_event_idle_exclusive(blp->blp_waitq,
+						  ldlm_bl_get_work(blp, &blwi,
+								   &exp));
 		atomic_inc(&blp->blp_busy_threads);
 
 		if (ldlm_bl_thread_need_create(blp, blwi))
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index 8563bd32befa..a0e486b57e08 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -997,8 +997,6 @@ static int ldlm_pools_thread_main(void *arg)
 	       "ldlm_poold", current_pid());
 
 	while (1) {
-		struct l_wait_info lwi;
-
 		/*
 		 * Recal all pools on this tick.
 		 */
@@ -1008,12 +1006,10 @@ static int ldlm_pools_thread_main(void *arg)
 		 * Wait until the next check time, or until we're
 		 * stopped.
 		 */
-		lwi = LWI_TIMEOUT(cfs_time_seconds(c_time),
-				  NULL, NULL);
-		l_wait_event(thread->t_ctl_waitq,
-			     thread_is_stopping(thread) ||
-			     thread_is_event(thread),
-			     &lwi);
+		wait_event_idle_timeout(thread->t_ctl_waitq,
+					thread_is_stopping(thread) ||
+					thread_is_event(thread),
+					c_time * HZ);
 
 		if (thread_test_and_clear_flags(thread, SVC_STOPPING))
 			break;
@@ -1031,7 +1027,6 @@ static int ldlm_pools_thread_main(void *arg)
 
 static int ldlm_pools_thread_start(void)
 {
-	struct l_wait_info lwi = { 0 };
 	struct task_struct *task;
 
 	if (ldlm_pools_thread)
@@ -1052,8 +1047,8 @@ static int ldlm_pools_thread_start(void)
 		ldlm_pools_thread = NULL;
 		return PTR_ERR(task);
 	}
-	l_wait_event(ldlm_pools_thread->t_ctl_waitq,
-		     thread_is_running(ldlm_pools_thread), &lwi);
+	wait_event_idle(ldlm_pools_thread->t_ctl_waitq,
+			thread_is_running(ldlm_pools_thread));
 	return 0;
 }
 
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
index 6aa37463db46..c3c9186b74ce 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
@@ -72,15 +72,6 @@ MODULE_PARM_DESC(ldlm_enqueue_min, "lock enqueue timeout minimum");
 /* in client side, whether the cached locks will be canceled before replay */
 unsigned int ldlm_cancel_unused_locks_before_replay = 1;
 
-static void interrupted_completion_wait(void *data)
-{
-}
-
-struct lock_wait_data {
-	struct ldlm_lock *lwd_lock;
-	__u32	     lwd_conn_cnt;
-};
-
 struct ldlm_async_args {
 	struct lustre_handle lock_handle;
 };
@@ -112,10 +103,8 @@ static int ldlm_request_bufsize(int count, int type)
 	return sizeof(struct ldlm_request) + avail;
 }
 
-static int ldlm_expired_completion_wait(void *data)
+static void ldlm_expired_completion_wait(struct ldlm_lock *lock, __u32 conn_cnt)
 {
-	struct lock_wait_data *lwd = data;
-	struct ldlm_lock *lock = lwd->lwd_lock;
 	struct obd_import *imp;
 	struct obd_device *obd;
 
@@ -135,19 +124,17 @@ static int ldlm_expired_completion_wait(void *data)
 			if (last_dump == 0)
 				libcfs_debug_dumplog();
 		}
-		return 0;
+		return;
 	}
 
 	obd = lock->l_conn_export->exp_obd;
 	imp = obd->u.cli.cl_import;
-	ptlrpc_fail_import(imp, lwd->lwd_conn_cnt);
+	ptlrpc_fail_import(imp, conn_cnt);
 	LDLM_ERROR(lock,
 		   "lock timed out (enqueued at %lld, %llds ago), entering recovery for %s@%s",
 		   (s64)lock->l_last_activity,
 		   (s64)(ktime_get_real_seconds() - lock->l_last_activity),
 		   obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid);
-
-	return 0;
 }
 
 /**
@@ -251,11 +238,10 @@ EXPORT_SYMBOL(ldlm_completion_ast_async);
 int ldlm_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
 {
 	/* XXX ALLOCATE - 160 bytes */
-	struct lock_wait_data lwd;
 	struct obd_device *obd;
 	struct obd_import *imp = NULL;
-	struct l_wait_info lwi;
 	__u32 timeout;
+	__u32 conn_cnt = 0;
 	int rc = 0;
 
 	if (flags == LDLM_FL_WAIT_NOREPROC) {
@@ -281,32 +267,33 @@ int ldlm_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
 
 	timeout = ldlm_cp_timeout(lock);
 
-	lwd.lwd_lock = lock;
 	lock->l_last_activity = ktime_get_real_seconds();
 
-	if (ldlm_is_no_timeout(lock)) {
-		LDLM_DEBUG(lock, "waiting indefinitely because of NO_TIMEOUT");
-		lwi = LWI_INTR(interrupted_completion_wait, &lwd);
-	} else {
-		lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout),
-				       ldlm_expired_completion_wait,
-				       interrupted_completion_wait, &lwd);
-	}
-
 	if (imp) {
 		spin_lock(&imp->imp_lock);
-		lwd.lwd_conn_cnt = imp->imp_conn_cnt;
+		conn_cnt = imp->imp_conn_cnt;
 		spin_unlock(&imp->imp_lock);
 	}
-
 	if (OBD_FAIL_CHECK_RESET(OBD_FAIL_LDLM_INTR_CP_AST,
 				 OBD_FAIL_LDLM_CP_BL_RACE | OBD_FAIL_ONCE)) {
 		ldlm_set_fail_loc(lock);
 		rc = -EINTR;
 	} else {
-		/* Go to sleep until the lock is granted or cancelled. */
-		rc = l_wait_event(lock->l_waitq,
-				  is_granted_or_cancelled(lock), &lwi);
+		/* Go to sleep until the lock is granted or canceled. */
+		if (!ldlm_is_no_timeout(lock)) {
+			/* Wait uninterruptible for a while first */
+			rc = wait_event_idle_timeout(lock->l_waitq,
+						     is_granted_or_cancelled(lock),
+						     timeout * HZ);
+			if (rc == 0)
+				ldlm_expired_completion_wait(lock, conn_cnt);
+		}
+		/* Now wait abortable */
+		if (rc == 0)
+			rc = l_wait_event_abortable(lock->l_waitq,
+						    is_granted_or_cancelled(lock));
+		else
+			rc = 0;
 	}
 
 	if (rc) {
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 9958533cc227..4c44603ab6f9 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -799,7 +799,7 @@ static void cleanup_resource(struct ldlm_resource *res, struct list_head *q,
 			LDLM_DEBUG(lock, "setting FL_LOCAL_ONLY");
 			if (lock->l_flags & LDLM_FL_FAIL_LOC) {
 				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout(cfs_time_seconds(4));
+				schedule_timeout(4 * HZ);
 				set_current_state(TASK_RUNNING);
 			}
 			if (lock->l_completion_ast)
@@ -879,7 +879,6 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force)
 	ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0);
 
 	if (atomic_read(&ns->ns_bref) > 0) {
-		struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 		int rc;
 
 		CDEBUG(D_DLMTRACE,
@@ -887,11 +886,12 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force)
 		       ldlm_ns_name(ns), atomic_read(&ns->ns_bref));
 force_wait:
 		if (force)
-			lwi = LWI_TIMEOUT(msecs_to_jiffies(obd_timeout *
-					  MSEC_PER_SEC) / 4, NULL, NULL);
-
-		rc = l_wait_event(ns->ns_waitq,
-				  atomic_read(&ns->ns_bref) == 0, &lwi);
+			rc = wait_event_idle_timeout(ns->ns_waitq,
+						     atomic_read(&ns->ns_bref) == 0,
+						     obd_timeout * HZ / 4) ? 0 : -ETIMEDOUT;
+		else
+			rc = l_wait_event_abortable(ns->ns_waitq,
+						    atomic_read(&ns->ns_bref) == 0);
 
 		/* Forced cleanups should be able to reclaim all references,
 		 * so it's safe to wait forever... we can't leak locks...
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 549369739d80..dc30b4582234 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -74,6 +74,12 @@ static void ll_release(struct dentry *de)
  * an AST before calling d_revalidate_it().  The dentry still exists (marked
  * INVALID) so d_lookup() matches it, but we have no lock on it (so
  * lock_match() fails) and we spin around real_lookup().
+ *
+ * This race doesn't apply to lookups in d_alloc_parallel(), and for
+ * those we want to ensure that only one dentry with a given name is
+ * in ll_lookup_nd() at a time.  So allow invalid dentries to match
+ * while d_in_lookup().  We will be called again when the lookup
+ * completes, and can give a different answer then.
  */
 static int ll_dcompare(const struct dentry *dentry,
 		       unsigned int len, const char *str,
@@ -93,6 +99,10 @@ static int ll_dcompare(const struct dentry *dentry,
 	if (d_mountpoint((struct dentry *)dentry))
 		return 0;
 
+	/* ensure exclusion against parallel lookup of the same name */
+	if (d_in_lookup((struct dentry*)dentry))
+		return 0;
+
 	if (d_lustre_invalid(dentry))
 		return 1;
 
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 6735a6f006d2..9e96a8ee1783 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -986,16 +986,12 @@ void ll_put_super(struct super_block *sb)
 	}
 
 	/* Wait for unstable pages to be committed to stable storage */
-	if (!force) {
-		struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
-
-		rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq,
-				  !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr),
-				  &lwi);
-	}
+	if (!force)
+		rc = l_wait_event_abortable(sbi->ll_cache->ccc_unstable_waitq,
+					    !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr));
 
 	ccc_count = atomic_long_read(&sbi->ll_cache->ccc_unstable_nr);
-	if (!force && rc != -EINTR)
+	if (!force && rc != -ERESTARTSYS)
 		LASSERTF(!ccc_count, "count: %li\n", ccc_count);
 
 	/* We need to set force before the lov_disconnect in
@@ -1988,8 +1984,7 @@ void ll_umount_begin(struct super_block *sb)
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	struct obd_device *obd;
 	struct obd_ioctl_data *ioc_data;
-	wait_queue_head_t waitq;
-	struct l_wait_info lwi;
+	int cnt = 0;
 
 	CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb,
 	       sb->s_count, atomic_read(&sb->s_active));
@@ -2025,10 +2020,10 @@ void ll_umount_begin(struct super_block *sb)
 	 * and then continue. For now, we just periodically checking for vfs
 	 * to decrement mnt_cnt and hope to finish it within 10sec.
 	 */
-	init_waitqueue_head(&waitq);
-	lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(10),
-				   cfs_time_seconds(1), NULL, NULL);
-	l_wait_event(waitq, may_umount(sbi->ll_mnt.mnt), &lwi);
+	while (cnt < 10 && !may_umount(sbi->ll_mnt.mnt)) {
+		schedule_timeout_uninterruptible(HZ);
+		cnt ++;
+	}
 
 	schedule();
 }
@@ -2143,7 +2138,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
 				md.posix_acl = NULL;
 			}
 #endif
-			rc = -ENOMEM;
+			rc = PTR_ERR(*inode);
 			CERROR("new_inode -fatal: rc %d\n", rc);
 			goto out;
 		}
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index a2687f46a16d..6c9ec462eb41 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -380,52 +380,45 @@ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2)
 }
 
 /*
- * try to reuse three types of dentry:
- * 1. unhashed alias, this one is unhashed by d_invalidate (but it may be valid
- *    by concurrent .revalidate).
- * 2. INVALID alias (common case for no valid ldlm lock held, but this flag may
- *    be cleared by others calling d_lustre_revalidate).
- * 3. DISCONNECTED alias.
+ * Try to reuse unhashed or invalidated dentries.
+ * This is very similar to d_exact_alias(), and any changes in one should be
+ * considered for inclusion in the other.  The differences are that we don't
+ * need an unhashed alias, and we don't want d_compare to be used for
+ * comparison.
  */
 static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
 {
-	struct dentry *alias, *discon_alias, *invalid_alias;
+	struct dentry *alias;
 
 	if (hlist_empty(&inode->i_dentry))
 		return NULL;
 
-	discon_alias = NULL;
-	invalid_alias = NULL;
-
 	spin_lock(&inode->i_lock);
 	hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
 		LASSERT(alias != dentry);
+		/*
+		 * Don't need alias->d_lock here, because aliases with
+		 * d_parent == entry->d_parent are not subject to name or
+		 * parent changes, because the parent inode i_mutex is held.
+		 */
 
-		spin_lock(&alias->d_lock);
-		if ((alias->d_flags & DCACHE_DISCONNECTED) &&
-		    S_ISDIR(inode->i_mode))
-			/* LASSERT(last_discon == NULL); LU-405, bz 20055 */
-			discon_alias = alias;
-		else if (alias->d_parent == dentry->d_parent	     &&
-			 alias->d_name.hash == dentry->d_name.hash       &&
-			 alias->d_name.len == dentry->d_name.len	 &&
-			 memcmp(alias->d_name.name, dentry->d_name.name,
-				dentry->d_name.len) == 0)
-			invalid_alias = alias;
-		spin_unlock(&alias->d_lock);
-
-		if (invalid_alias)
-			break;
-	}
-	alias = invalid_alias ?: discon_alias ?: NULL;
-	if (alias) {
+		if (alias->d_parent != dentry->d_parent)
+			continue;
+		if (alias->d_name.hash != dentry->d_name.hash)
+			continue;
+		if (alias->d_name.len != dentry->d_name.len ||
+		    memcmp(alias->d_name.name, dentry->d_name.name,
+			   dentry->d_name.len) != 0)
+			continue;
 		spin_lock(&alias->d_lock);
 		dget_dlock(alias);
 		spin_unlock(&alias->d_lock);
+		spin_unlock(&inode->i_lock);
+		return alias;
 	}
 	spin_unlock(&inode->i_lock);
 
-	return alias;
+	return NULL;
 }
 
 /*
@@ -434,7 +427,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
  */
 struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
 {
-	if (inode) {
+	if (inode && !S_ISDIR(inode->i_mode)) {
 		struct dentry *new = ll_find_alias(inode, de);
 
 		if (new) {
@@ -445,8 +438,13 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
 			      new, d_inode(new), d_count(new), new->d_flags);
 			return new;
 		}
+		d_add(de, inode);
+	} else {
+		struct dentry *new = d_splice_alias(inode, de);
+
+		if (new)
+			de = new;
 	}
-	d_add(de, inode);
 	CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
 	       de, d_inode(de), d_count(de), de->d_flags);
 	return de;
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 90c7324575e4..6052bfd7ff05 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -864,7 +864,6 @@ static int ll_agl_thread(void *arg)
 	struct ll_sb_info	*sbi    = ll_i2sbi(dir);
 	struct ll_statahead_info *sai;
 	struct ptlrpc_thread *thread;
-	struct l_wait_info	lwi    = { 0 };
 
 	sai = ll_sai_get(dir);
 	thread = &sai->sai_agl_thread;
@@ -885,10 +884,9 @@ static int ll_agl_thread(void *arg)
 	wake_up(&thread->t_ctl_waitq);
 
 	while (1) {
-		l_wait_event(thread->t_ctl_waitq,
-			     !list_empty(&sai->sai_agls) ||
-			     !thread_is_running(thread),
-			     &lwi);
+		wait_event_idle(thread->t_ctl_waitq,
+				!list_empty(&sai->sai_agls) ||
+				!thread_is_running(thread));
 
 		if (!thread_is_running(thread))
 			break;
@@ -932,7 +930,6 @@ static int ll_agl_thread(void *arg)
 static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
 {
 	struct ptlrpc_thread *thread = &sai->sai_agl_thread;
-	struct l_wait_info    lwi    = { 0 };
 	struct ll_inode_info  *plli;
 	struct task_struct *task;
 
@@ -948,9 +945,8 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
 		return;
 	}
 
-	l_wait_event(thread->t_ctl_waitq,
-		     thread_is_running(thread) || thread_is_stopped(thread),
-		     &lwi);
+	wait_event_idle(thread->t_ctl_waitq,
+			thread_is_running(thread) || thread_is_stopped(thread));
 }
 
 /* statahead thread main function */
@@ -968,7 +964,6 @@ static int ll_statahead_thread(void *arg)
 	int		       first  = 0;
 	int		       rc     = 0;
 	struct md_op_data *op_data;
-	struct l_wait_info	lwi    = { 0 };
 
 	sai = ll_sai_get(dir);
 	sa_thread = &sai->sai_thread;
@@ -1069,12 +1064,11 @@ static int ll_statahead_thread(void *arg)
 
 			/* wait for spare statahead window */
 			do {
-				l_wait_event(sa_thread->t_ctl_waitq,
-					     !sa_sent_full(sai) ||
-					     sa_has_callback(sai) ||
-					     !list_empty(&sai->sai_agls) ||
-					     !thread_is_running(sa_thread),
-					     &lwi);
+				wait_event_idle(sa_thread->t_ctl_waitq,
+						!sa_sent_full(sai) ||
+						sa_has_callback(sai) ||
+						!list_empty(&sai->sai_agls) ||
+						!thread_is_running(sa_thread));
 				sa_handle_callback(sai);
 
 				spin_lock(&lli->lli_agl_lock);
@@ -1128,11 +1122,10 @@ static int ll_statahead_thread(void *arg)
 	 * for file release to stop me.
 	 */
 	while (thread_is_running(sa_thread)) {
-		l_wait_event(sa_thread->t_ctl_waitq,
-			     sa_has_callback(sai) ||
-			     !agl_list_empty(sai) ||
-			     !thread_is_running(sa_thread),
-			     &lwi);
+		wait_event_idle(sa_thread->t_ctl_waitq,
+				sa_has_callback(sai) ||
+				!agl_list_empty(sai) ||
+				!thread_is_running(sa_thread));
 
 		sa_handle_callback(sai);
 	}
@@ -1145,9 +1138,8 @@ static int ll_statahead_thread(void *arg)
 
 		CDEBUG(D_READA, "stop agl thread: sai %p pid %u\n",
 		       sai, (unsigned int)agl_thread->t_pid);
-		l_wait_event(agl_thread->t_ctl_waitq,
-			     thread_is_stopped(agl_thread),
-			     &lwi);
+		wait_event_idle(agl_thread->t_ctl_waitq,
+				thread_is_stopped(agl_thread));
 	} else {
 		/* Set agl_thread flags anyway. */
 		thread_set_flags(agl_thread, SVC_STOPPED);
@@ -1159,10 +1151,9 @@ static int ll_statahead_thread(void *arg)
 	 */
 	while (sai->sai_sent != sai->sai_replied) {
 		/* in case we're not woken up, timeout wait */
-		lwi = LWI_TIMEOUT(msecs_to_jiffies(MSEC_PER_SEC >> 3),
-				  NULL, NULL);
-		l_wait_event(sa_thread->t_ctl_waitq,
-			     sai->sai_sent == sai->sai_replied, &lwi);
+		wait_event_idle_timeout(sa_thread->t_ctl_waitq,
+					sai->sai_sent == sai->sai_replied,
+					HZ>>3);
 	}
 
 	/* release resources held by statahead RPCs */
@@ -1382,7 +1373,6 @@ static int revalidate_statahead_dentry(struct inode *dir,
 {
 	struct ll_inode_info *lli = ll_i2info(dir);
 	struct sa_entry *entry = NULL;
-	struct l_wait_info lwi = { 0 };
 	struct ll_dentry_data *ldd;
 	int rc = 0;
 
@@ -1432,10 +1422,8 @@ static int revalidate_statahead_dentry(struct inode *dir,
 		spin_lock(&lli->lli_sa_lock);
 		sai->sai_index_wait = entry->se_index;
 		spin_unlock(&lli->lli_sa_lock);
-		lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(30), NULL,
-				       LWI_ON_SIGNAL_NOOP, NULL);
-		rc = l_wait_event(sai->sai_waitq, sa_ready(entry), &lwi);
-		if (rc < 0) {
+		if (0 == wait_event_idle_timeout(sai->sai_waitq,
+						 sa_ready(entry), 30 * HZ)) {
 			/*
 			 * entry may not be ready, so it may be used by inflight
 			 * statahead RPC, don't free it.
@@ -1520,7 +1508,6 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry)
 {
 	struct ll_inode_info *lli = ll_i2info(dir);
 	struct ll_statahead_info *sai = NULL;
-	struct l_wait_info lwi = { 0 };
 	struct ptlrpc_thread *thread;
 	struct task_struct *task;
 	struct dentry *parent = dentry->d_parent;
@@ -1570,9 +1557,8 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry)
 		goto out;
 	}
 
-	l_wait_event(thread->t_ctl_waitq,
-		     thread_is_running(thread) || thread_is_stopped(thread),
-		     &lwi);
+	wait_event_idle(thread->t_ctl_waitq,
+			thread_is_running(thread) || thread_is_stopped(thread));
 	ll_sai_put(sai);
 
 	/*
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c
index 897cf2cd4a24..86cd4f9fbd0c 100644
--- a/drivers/staging/lustre/lustre/lov/lov_object.c
+++ b/drivers/staging/lustre/lustre/lov/lov_object.c
@@ -723,15 +723,13 @@ static void lov_conf_unlock(struct lov_object *lov)
 
 static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov)
 {
-	struct l_wait_info lwi = { 0 };
-
 	while (atomic_read(&lov->lo_active_ios) > 0) {
 		CDEBUG(D_INODE, "file:" DFID " wait for active IO, now: %d.\n",
 		       PFID(lu_object_fid(lov2lu(lov))),
 		       atomic_read(&lov->lo_active_ios));
 
-		l_wait_event(lov->lo_waitq,
-			     atomic_read(&lov->lo_active_ios) == 0, &lwi);
+		wait_event_idle(lov->lo_waitq,
+				atomic_read(&lov->lo_active_ios) == 0);
 	}
 	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c
index cfa1d7f92b0f..c1e58fcc30b3 100644
--- a/drivers/staging/lustre/lustre/lov/lov_request.c
+++ b/drivers/staging/lustre/lustre/lov/lov_request.c
@@ -99,8 +99,7 @@ static int lov_check_set(struct lov_obd *lov, int idx)
  */
 static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx)
 {
-	wait_queue_head_t waitq;
-	struct l_wait_info lwi;
+	int cnt = 0;
 	struct lov_tgt_desc *tgt;
 	int rc = 0;
 
@@ -125,11 +124,10 @@ static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx)
 
 	mutex_unlock(&lov->lov_lock);
 
-	init_waitqueue_head(&waitq);
-	lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(obd_timeout),
-				   cfs_time_seconds(1), NULL, NULL);
-
-	rc = l_wait_event(waitq, lov_check_set(lov, ost_idx), &lwi);
+	while (cnt < obd_timeout && !lov_check_set(lov, ost_idx)) {
+		schedule_timeout_uninterruptible(HZ);
+		cnt ++;
+	}
 	if (tgt->ltd_active)
 		return 1;
 
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 03e55bca4ada..ab48746ce433 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -838,7 +838,6 @@ static int mdc_getpage(struct obd_export *exp, const struct lu_fid *fid,
 	struct ptlrpc_bulk_desc *desc;
 	struct ptlrpc_request *req;
 	wait_queue_head_t waitq;
-	struct l_wait_info lwi;
 	int resends = 0;
 	int rc;
 	int i;
@@ -888,9 +887,7 @@ static int mdc_getpage(struct obd_export *exp, const struct lu_fid *fid,
 			       exp->exp_obd->obd_name, -EIO);
 			return -EIO;
 		}
-		lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(resends), NULL, NULL,
-				       NULL);
-		l_wait_event(waitq, 0, &lwi);
+		wait_event_idle_timeout(waitq, 0, resends * HZ);
 
 		goto restart_bulk;
 	}
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index 79ff85feab64..c61cd23a96df 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -535,7 +535,6 @@ static int mgc_requeue_thread(void *data)
 	spin_lock(&config_list_lock);
 	rq_state |= RQ_RUNNING;
 	while (!(rq_state & RQ_STOP)) {
-		struct l_wait_info lwi;
 		struct config_llog_data *cld, *cld_prev;
 		int rand = prandom_u32_max(MGC_TIMEOUT_RAND_CENTISEC);
 		int to;
@@ -556,9 +555,9 @@ static int mgc_requeue_thread(void *data)
 		to = msecs_to_jiffies(MGC_TIMEOUT_MIN_SECONDS * MSEC_PER_SEC);
 		/* rand is centi-seconds */
 		to += msecs_to_jiffies(rand * MSEC_PER_SEC / 100);
-		lwi = LWI_TIMEOUT(to, NULL, NULL);
-		l_wait_event(rq_waitq, rq_state & (RQ_STOP | RQ_PRECLEANUP),
-			     &lwi);
+		wait_event_idle_timeout(rq_waitq,
+					rq_state & (RQ_STOP | RQ_PRECLEANUP),
+					to);
 
 		/*
 		 * iterate & processing through the list. for each cld, process
@@ -601,9 +600,7 @@ static int mgc_requeue_thread(void *data)
 			config_log_put(cld_prev);
 
 		/* Wait a bit to see if anyone else needs a requeue */
-		lwi = (struct l_wait_info) { 0 };
-		l_wait_event(rq_waitq, rq_state & (RQ_NOW | RQ_STOP),
-			     &lwi);
+		wait_event_idle(rq_waitq, rq_state & (RQ_NOW | RQ_STOP));
 		spin_lock(&config_list_lock);
 	}
 
@@ -1630,9 +1627,7 @@ int mgc_process_log(struct obd_device *mgc, struct config_llog_data *cld)
 
 		if (rcl == -ESHUTDOWN &&
 		    atomic_read(&mgc->u.cli.cl_mgc_refcount) > 0 && !retry) {
-			int secs = cfs_time_seconds(obd_timeout);
 			struct obd_import *imp;
-			struct l_wait_info lwi;
 
 			mutex_unlock(&cld->cld_lock);
 			imp = class_exp2cliimp(mgc->u.cli.cl_mgc_mgsexp);
@@ -1647,9 +1642,9 @@ int mgc_process_log(struct obd_device *mgc, struct config_llog_data *cld)
 			 */
 			ptlrpc_pinger_force(imp);
 
-			lwi = LWI_TIMEOUT(secs, NULL, NULL);
-			l_wait_event(imp->imp_recovery_waitq,
-				     !mgc_import_in_recovery(imp), &lwi);
+			wait_event_idle_timeout(imp->imp_recovery_waitq,
+						!mgc_import_in_recovery(imp),
+						obd_timeout * HZ);
 
 			if (imp->imp_state == LUSTRE_IMP_FULL) {
 				retry = true;
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c
index 6ec5218a18c1..ab84e011b560 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_io.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c
@@ -1097,23 +1097,24 @@ EXPORT_SYMBOL(cl_sync_io_init);
 int cl_sync_io_wait(const struct lu_env *env, struct cl_sync_io *anchor,
 		    long timeout)
 {
-	struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout),
-						  NULL, NULL, NULL);
-	int rc;
+	int rc = 1;
 
 	LASSERT(timeout >= 0);
 
-	rc = l_wait_event(anchor->csi_waitq,
-			  atomic_read(&anchor->csi_sync_nr) == 0,
-			  &lwi);
-	if (rc < 0) {
+	if (timeout == 0)
+		wait_event_idle(anchor->csi_waitq,
+				atomic_read(&anchor->csi_sync_nr) == 0);
+	else
+		rc = wait_event_idle_timeout(anchor->csi_waitq,
+					     atomic_read(&anchor->csi_sync_nr) == 0,
+					     timeout * HZ);
+	if (rc == 0) {
+		rc = -ETIMEDOUT;
 		CERROR("IO failed: %d, still wait for %d remaining entries\n",
 		       rc, atomic_read(&anchor->csi_sync_nr));
 
-		lwi = (struct l_wait_info) { 0 };
-		(void)l_wait_event(anchor->csi_waitq,
-				   atomic_read(&anchor->csi_sync_nr) == 0,
-				   &lwi);
+		wait_event_idle(anchor->csi_waitq,
+				atomic_read(&anchor->csi_sync_nr) == 0);
 	} else {
 		rc = anchor->csi_sync_rc;
 	}
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index b1d6ba4a3190..8f776a4058a9 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -1237,12 +1237,10 @@ static int obd_zombie_is_idle(void)
  */
 void obd_zombie_barrier(void)
 {
-	struct l_wait_info lwi = { 0 };
-
 	if (obd_zombie_pid == current_pid())
 		/* don't wait for myself */
 		return;
-	l_wait_event(obd_zombie_waitq, obd_zombie_is_idle(), &lwi);
+	wait_event_idle(obd_zombie_waitq, obd_zombie_is_idle());
 }
 EXPORT_SYMBOL(obd_zombie_barrier);
 
@@ -1257,10 +1255,8 @@ static int obd_zombie_impexp_thread(void *unused)
 	obd_zombie_pid = current_pid();
 
 	while (!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags)) {
-		struct l_wait_info lwi = { 0 };
-
-		l_wait_event(obd_zombie_waitq,
-			     !obd_zombie_impexp_check(NULL), &lwi);
+		wait_event_idle(obd_zombie_waitq,
+				!obd_zombie_impexp_check(NULL));
 		obd_zombie_impexp_cull();
 
 		/*
@@ -1336,7 +1332,6 @@ static bool obd_request_slot_avail(struct client_obd *cli,
 int obd_get_request_slot(struct client_obd *cli)
 {
 	struct obd_request_slot_waiter orsw;
-	struct l_wait_info lwi;
 	int rc;
 
 	spin_lock(&cli->cl_loi_list_lock);
@@ -1351,11 +1346,9 @@ int obd_get_request_slot(struct client_obd *cli)
 	orsw.orsw_signaled = false;
 	spin_unlock(&cli->cl_loi_list_lock);
 
-	lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
-	rc = l_wait_event(orsw.orsw_waitq,
-			  obd_request_slot_avail(cli, &orsw) ||
-			  orsw.orsw_signaled,
-			  &lwi);
+	rc = l_wait_event_abortable(orsw.orsw_waitq,
+				    obd_request_slot_avail(cli, &orsw) ||
+				    orsw.orsw_signaled);
 
 	/*
 	 * Here, we must take the lock to avoid the on-stack 'orsw' to be
@@ -1593,7 +1586,6 @@ static inline bool obd_mod_rpc_slot_avail(struct client_obd *cli,
 u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc,
 			 struct lookup_intent *it)
 {
-	struct l_wait_info lwi = LWI_INTR(NULL, NULL);
 	bool close_req = false;
 	u16 i, max;
 
@@ -1631,8 +1623,8 @@ u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc,
 		CDEBUG(D_RPCTRACE, "%s: sleeping for a modify RPC slot opc %u, max %hu\n",
 		       cli->cl_import->imp_obd->obd_name, opc, max);
 
-		l_wait_event(cli->cl_mod_rpcs_waitq,
-			     obd_mod_rpc_slot_avail(cli, close_req), &lwi);
+		wait_event_idle(cli->cl_mod_rpcs_waitq,
+				obd_mod_rpc_slot_avail(cli, close_req));
 	} while (true);
 }
 EXPORT_SYMBOL(obd_get_mod_rpc_slot);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
index 28bbaa2136ac..26aea114a29b 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
@@ -104,7 +104,6 @@ EXPORT_SYMBOL(__llog_ctxt_put);
 
 int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
 {
-	struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 	struct obd_llog_group *olg;
 	int rc, idx;
 
@@ -129,8 +128,8 @@ int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
 		CERROR("Error %d while cleaning up ctxt %p\n",
 		       rc, ctxt);
 
-	l_wait_event(olg->olg_waitq,
-		     llog_group_ctxt_null(olg, idx), &lwi);
+	l_wait_event_abortable(olg->olg_waitq,
+			     llog_group_ctxt_null(olg, idx));
 
 	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index b9c1dc7e61b0..9c5ce5074b66 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -752,7 +752,7 @@ static struct lu_device *echo_device_free(const struct lu_env *env,
 		spin_unlock(&ec->ec_lock);
 		CERROR("echo_client still has objects at cleanup time, wait for 1 second\n");
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(cfs_time_seconds(1));
+		schedule_timeout(HZ);
 		lu_site_purge(env, ed->ed_site, -1);
 		spin_lock(&ec->ec_lock);
 	}
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index 5767ac2a7d16..dacfab12c501 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -934,8 +934,6 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext,
 			   enum osc_extent_state state)
 {
 	struct osc_object *obj = ext->oe_obj;
-	struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(600), NULL,
-						  LWI_ON_SIGNAL_NOOP, NULL);
 	int rc = 0;
 
 	osc_object_lock(obj);
@@ -958,18 +956,19 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext,
 		osc_extent_release(env, ext);
 
 	/* wait for the extent until its state becomes @state */
-	rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state), &lwi);
-	if (rc == -ETIMEDOUT) {
+	rc = wait_event_idle_timeout(ext->oe_waitq,
+				     extent_wait_cb(ext, state), 600 * HZ);
+	if (rc == 0) {
 		OSC_EXTENT_DUMP(D_ERROR, ext,
 				"%s: wait ext to %u timedout, recovery in progress?\n",
 				cli_name(osc_cli(obj)), state);
 
-		lwi = LWI_INTR(NULL, NULL);
-		rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state),
-				  &lwi);
+		wait_event_idle(ext->oe_waitq, extent_wait_cb(ext, state));
 	}
-	if (rc == 0 && ext->oe_rc < 0)
+	if (ext->oe_rc < 0)
 		rc = ext->oe_rc;
+	else
+		rc = 0;
 	return rc;
 }
 
@@ -1569,12 +1568,9 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
 	struct osc_object *osc = oap->oap_obj;
 	struct lov_oinfo *loi = osc->oo_oinfo;
 	struct osc_cache_waiter ocw;
-	struct l_wait_info lwi;
+	unsigned long timeout = (AT_OFF ? obd_timeout : at_max) * HZ;
 	int rc = -EDQUOT;
 
-	lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(AT_OFF ? obd_timeout : at_max),
-			       NULL, LWI_ON_SIGNAL_NOOP, NULL);
-
 	OSC_DUMP_GRANT(D_CACHE, cli, "need:%d\n", bytes);
 
 	spin_lock(&cli->cl_loi_list_lock);
@@ -1617,13 +1613,15 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
 		CDEBUG(D_CACHE, "%s: sleeping for cache space @ %p for %p\n",
 		       cli_name(cli), &ocw, oap);
 
-		rc = l_wait_event(ocw.ocw_waitq, ocw_granted(cli, &ocw), &lwi);
+		rc = wait_event_idle_timeout(ocw.ocw_waitq,
+					     ocw_granted(cli, &ocw), timeout);
 
 		spin_lock(&cli->cl_loi_list_lock);
 
-		if (rc < 0) {
-			/* l_wait_event is interrupted by signal, or timed out */
+		if (rc == 0) {
+			/* wait_event is interrupted by signal, or timed out */
 			list_del_init(&ocw.ocw_entry);
+			rc = -ETIMEDOUT;
 			break;
 		}
 		LASSERT(list_empty(&ocw.ocw_entry));
diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c
index f82c87a77550..6baa8e2e00c9 100644
--- a/drivers/staging/lustre/lustre/osc/osc_object.c
+++ b/drivers/staging/lustre/lustre/osc/osc_object.c
@@ -328,7 +328,7 @@ int osc_object_is_contended(struct osc_object *obj)
 	 * ll_file_is_contended.
 	 */
 	retry_time = cfs_time_add(obj->oo_contention_time,
-				  cfs_time_seconds(osc_contention_time));
+				  osc_contention_time * HZ);
 	if (cfs_time_after(cur_time, retry_time)) {
 		osc_object_clear_contended(obj);
 		return 0;
@@ -454,12 +454,10 @@ struct lu_object *osc_object_alloc(const struct lu_env *env,
 
 int osc_object_invalidate(const struct lu_env *env, struct osc_object *osc)
 {
-	struct l_wait_info lwi = { 0 };
-
 	CDEBUG(D_INODE, "Invalidate osc object: %p, # of active IOs: %d\n",
 	       osc, atomic_read(&osc->oo_nr_ios));
 
-	l_wait_event(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios), &lwi);
+	wait_event_idle(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios));
 
 	/* Discard all dirty pages of this object. */
 	osc_cache_truncate_start(env, osc, 0, NULL);
diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c
index 20094b6309f9..6fdd521feb21 100644
--- a/drivers/staging/lustre/lustre/osc/osc_page.c
+++ b/drivers/staging/lustre/lustre/osc/osc_page.c
@@ -759,7 +759,6 @@ static long osc_lru_reclaim(struct client_obd *cli, unsigned long npages)
 static int osc_lru_alloc(const struct lu_env *env, struct client_obd *cli,
 			 struct osc_page *opg)
 {
-	struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 	struct osc_io *oio = osc_env_io(env);
 	int rc = 0;
 
@@ -782,9 +781,8 @@ static int osc_lru_alloc(const struct lu_env *env, struct client_obd *cli,
 
 		cond_resched();
 
-		rc = l_wait_event(osc_lru_waitq,
-				  atomic_long_read(cli->cl_lru_left) > 0,
-				  &lwi);
+		rc = l_wait_event_abortable(osc_lru_waitq,
+					    atomic_long_read(cli->cl_lru_left) > 0);
 
 		if (rc < 0)
 			break;
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index 45b1ebf33363..074b5ce6284c 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -552,14 +552,12 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp,
 
 	req->rq_interpret_reply = osc_destroy_interpret;
 	if (!osc_can_send_destroy(cli)) {
-		struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
-
 		/*
 		 * Wait until the number of on-going destroy RPCs drops
 		 * under max_rpc_in_flight
 		 */
-		l_wait_event_exclusive(cli->cl_destroy_waitq,
-				       osc_can_send_destroy(cli), &lwi);
+		l_wait_event_abortable_exclusive(cli->cl_destroy_waitq,
+					       osc_can_send_destroy(cli));
 	}
 
 	/* Do not wait for response */
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index bac4b2304bad..3d689d6100bc 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -766,7 +766,7 @@ int ptlrpc_request_bufs_pack(struct ptlrpc_request *request,
 			 * fail_loc
 			 */
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(cfs_time_seconds(2));
+			schedule_timeout(2 * HZ);
 			set_current_state(TASK_RUNNING);
 		}
 	}
@@ -1588,7 +1588,8 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
 		spin_lock(&imp->imp_lock);
 		if (!list_empty(&req->rq_list)) {
 			list_del_init(&req->rq_list);
-			atomic_dec(&req->rq_import->imp_inflight);
+			if (atomic_dec_and_test(&req->rq_import->imp_inflight))
+				wake_up_all(&req->rq_import->imp_recovery_waitq);
 		}
 		spin_unlock(&imp->imp_lock);
 		ptlrpc_rqphase_move(req, RQ_PHASE_NEW);
@@ -1773,7 +1774,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
 		}
 
 		/*
-		 * ptlrpc_set_wait->l_wait_event sets lwi_allow_intr
+		 * ptlrpc_set_wait allow signal to abort the timeout
 		 * so it sets rq_intr regardless of individual rpc
 		 * timeouts. The synchronous IO waiting path sets
 		 * rq_intr irrespective of whether ptlrpcd
@@ -2121,12 +2122,10 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink)
 
 /**
  * Time out all uncompleted requests in request set pointed by \a data
- * Callback used when waiting on sets with l_wait_event.
- * Always returns 1.
+ * Called when wait_event_idle_timeout times out.
  */
-int ptlrpc_expired_set(void *data)
+void ptlrpc_expired_set(struct ptlrpc_request_set *set)
 {
-	struct ptlrpc_request_set *set = data;
 	struct list_head *tmp;
 	time64_t now = ktime_get_real_seconds();
 
@@ -2155,13 +2154,6 @@ int ptlrpc_expired_set(void *data)
 		 */
 		ptlrpc_expire_one_request(req, 1);
 	}
-
-	/*
-	 * When waiting for a whole set, we always break out of the
-	 * sleep so we can recalculate the timeout, or enable interrupts
-	 * if everyone's timed out.
-	 */
-	return 1;
 }
 
 /**
@@ -2177,11 +2169,10 @@ EXPORT_SYMBOL(ptlrpc_mark_interrupted);
 
 /**
  * Interrupts (sets interrupted flag) all uncompleted requests in
- * a set \a data. Callback for l_wait_event for interruptible waits.
+ * a set \a data. Called when l_wait_event_abortable_timeout receives signal.
  */
-static void ptlrpc_interrupted_set(void *data)
+static void ptlrpc_interrupted_set(struct ptlrpc_request_set *set)
 {
-	struct ptlrpc_request_set *set = data;
 	struct list_head *tmp;
 
 	CDEBUG(D_RPCTRACE, "INTERRUPTED SET %p\n", set);
@@ -2251,7 +2242,6 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
 {
 	struct list_head *tmp;
 	struct ptlrpc_request *req;
-	struct l_wait_info lwi;
 	int rc, timeout;
 
 	if (set->set_producer)
@@ -2277,46 +2267,47 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
 		CDEBUG(D_RPCTRACE, "set %p going to sleep for %d seconds\n",
 		       set, timeout);
 
-		if (timeout == 0 && !signal_pending(current))
+		if (timeout == 0 && !signal_pending(current)) {
 			/*
 			 * No requests are in-flight (ether timed out
 			 * or delayed), so we can allow interrupts.
 			 * We still want to block for a limited time,
 			 * so we allow interrupts during the timeout.
 			 */
-			lwi = LWI_TIMEOUT_INTR_ALL(cfs_time_seconds(1),
-						   ptlrpc_expired_set,
-						   ptlrpc_interrupted_set, set);
-		else
+			rc = l_wait_event_abortable_timeout(set->set_waitq,
+							    ptlrpc_check_set(NULL, set),
+							    HZ);
+			if (rc == 0) {
+				rc = -ETIMEDOUT;
+				ptlrpc_expired_set(set);
+			} else if (rc < 0) {
+				rc = -EINTR;
+				ptlrpc_interrupted_set(set);
+			} else
+				rc = 0;
+		} else {
 			/*
 			 * At least one request is in flight, so no
 			 * interrupts are allowed. Wait until all
 			 * complete, or an in-flight req times out.
 			 */
-			lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1),
-					  ptlrpc_expired_set, set);
-
-		rc = l_wait_event(set->set_waitq, ptlrpc_check_set(NULL, set), &lwi);
-
-		/*
-		 * LU-769 - if we ignored the signal because it was already
-		 * pending when we started, we need to handle it now or we risk
-		 * it being ignored forever
-		 */
-		if (rc == -ETIMEDOUT && !lwi.lwi_allow_intr &&
-		    signal_pending(current)) {
-			sigset_t blocked_sigs =
-					   cfs_block_sigsinv(LUSTRE_FATAL_SIGS);
-
-			/*
-			 * In fact we only interrupt for the "fatal" signals
-			 * like SIGINT or SIGKILL. We still ignore less
-			 * important signals since ptlrpc set is not easily
-			 * reentrant from userspace again
-			 */
-			if (signal_pending(current))
-				ptlrpc_interrupted_set(set);
-			cfs_restore_sigs(blocked_sigs);
+			rc = wait_event_idle_timeout(set->set_waitq,
+						     ptlrpc_check_set(NULL, set),
+						     (timeout ? timeout : 1) * HZ);
+			if (rc == 0) {
+				ptlrpc_expired_set(set);
+				rc = -ETIMEDOUT;
+				/*
+				 * LU-769 - if we ignored the signal
+				 * because it was already pending when
+				 * we started, we need to handle it
+				 * now or we risk it being ignored
+				 * forever
+				 */
+				if (l_fatal_signal_pending(current))
+					ptlrpc_interrupted_set(set);
+			} else
+				rc = 0;
 		}
 
 		LASSERT(rc == 0 || rc == -EINTR || rc == -ETIMEDOUT);
@@ -2495,7 +2486,6 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
 {
 	int rc;
 	wait_queue_head_t *wq;
-	struct l_wait_info lwi;
 
 	/* Might sleep. */
 	LASSERT(!in_interrupt());
@@ -2524,7 +2514,7 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
 		return 0;
 
 	/*
-	 * We have to l_wait_event() whatever the result, to give liblustre
+	 * We have to wait_event_idle_timeout() whatever the result, to give liblustre
 	 * a chance to run reply_in_callback(), and to make sure we've
 	 * unlinked before returning a req to the pool.
 	 */
@@ -2538,16 +2528,17 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
 		 * Network access will complete in finite time but the HUGE
 		 * timeout lets us CWARN for visibility of sluggish NALs
 		 */
-		lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(LONG_UNLINK),
-					   cfs_time_seconds(1), NULL, NULL);
-		rc = l_wait_event(*wq, !ptlrpc_client_recv_or_unlink(request),
-				  &lwi);
-		if (rc == 0) {
+		int cnt = 0;
+		while (cnt < LONG_UNLINK &&
+		       (rc = wait_event_idle_timeout(*wq,
+						     !ptlrpc_client_recv_or_unlink(request),
+						     HZ)) == 0)
+			cnt += 1;
+		if (rc > 0) {
 			ptlrpc_rqphase_move(request, request->rq_next_phase);
 			return 1;
 		}
 
-		LASSERT(rc == -ETIMEDOUT);
 		DEBUG_REQ(D_WARNING, request,
 			  "Unexpectedly long timeout receiving_reply=%d req_ulinked=%d reply_unlinked=%d",
 			  request->rq_receiving_reply,
diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c
index 811b7ab3a582..130bacc2c891 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/events.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/events.c
@@ -490,8 +490,6 @@ int ptlrpc_uuid_to_peer(struct obd_uuid *uuid,
 
 static void ptlrpc_ni_fini(void)
 {
-	wait_queue_head_t waitq;
-	struct l_wait_info lwi;
 	int rc;
 	int retries;
 
@@ -515,10 +513,7 @@ static void ptlrpc_ni_fini(void)
 			if (retries != 0)
 				CWARN("Event queue still busy\n");
 
-			/* Wait for a bit */
-			init_waitqueue_head(&waitq);
-			lwi = LWI_TIMEOUT(cfs_time_seconds(2), NULL, NULL);
-			l_wait_event(waitq, 0, &lwi);
+			schedule_timeout_uninterruptible(2 * HZ);
 			break;
 		}
 	}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c
index 5b0f65536c29..faf0f606f013 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/import.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/import.c
@@ -265,7 +265,6 @@ void ptlrpc_invalidate_import(struct obd_import *imp)
 {
 	struct list_head *tmp, *n;
 	struct ptlrpc_request *req;
-	struct l_wait_info lwi;
 	unsigned int timeout;
 	int rc;
 
@@ -306,19 +305,15 @@ void ptlrpc_invalidate_import(struct obd_import *imp)
 		 * callbacks. Cap it at obd_timeout -- these should all
 		 * have been locally cancelled by ptlrpc_abort_inflight.
 		 */
-		lwi = LWI_TIMEOUT_INTERVAL(
-			cfs_timeout_cap(cfs_time_seconds(timeout)),
-			(timeout > 1) ? cfs_time_seconds(1) :
-			cfs_time_seconds(1) / 2,
-			NULL, NULL);
-		rc = l_wait_event(imp->imp_recovery_waitq,
-				  (atomic_read(&imp->imp_inflight) == 0),
-				  &lwi);
-		if (rc) {
+		rc = wait_event_idle_timeout(imp->imp_recovery_waitq,
+					     atomic_read(&imp->imp_inflight) == 0,
+					     obd_timeout * HZ);
+
+		if (rc == 0) {
 			const char *cli_tgt = obd2cli_tgt(imp->imp_obd);
 
-			CERROR("%s: rc = %d waiting for callback (%d != 0)\n",
-			       cli_tgt, rc,
+			CERROR("%s: timeout waiting for callback (%d != 0)\n",
+			       cli_tgt,
 			       atomic_read(&imp->imp_inflight));
 
 			spin_lock(&imp->imp_lock);
@@ -365,7 +360,7 @@ void ptlrpc_invalidate_import(struct obd_import *imp)
 			}
 			spin_unlock(&imp->imp_lock);
 		}
-	} while (rc != 0);
+	} while (rc == 0);
 
 	/*
 	 * Let's additionally check that no new rpcs added to import in
@@ -430,21 +425,19 @@ void ptlrpc_fail_import(struct obd_import *imp, __u32 conn_cnt)
 
 int ptlrpc_reconnect_import(struct obd_import *imp)
 {
-	struct l_wait_info lwi;
-	int secs = cfs_time_seconds(obd_timeout);
 	int rc;
 
 	ptlrpc_pinger_force(imp);
 
 	CDEBUG(D_HA, "%s: recovery started, waiting %u seconds\n",
-	       obd2cli_tgt(imp->imp_obd), secs);
+	       obd2cli_tgt(imp->imp_obd), obd_timeout);
 
-	lwi = LWI_TIMEOUT(secs, NULL, NULL);
-	rc = l_wait_event(imp->imp_recovery_waitq,
-			  !ptlrpc_import_in_recovery(imp), &lwi);
+	rc = wait_event_idle_timeout(imp->imp_recovery_waitq,
+				     !ptlrpc_import_in_recovery(imp),
+				     obd_timeout * HZ);
 	CDEBUG(D_HA, "%s: recovery finished s:%s\n", obd2cli_tgt(imp->imp_obd),
 	       ptlrpc_import_state_name(imp->imp_state));
-	return rc;
+	return rc == 0 ? -ETIMEDOUT : 0;
 }
 EXPORT_SYMBOL(ptlrpc_reconnect_import);
 
@@ -1503,25 +1496,25 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose)
 	}
 
 	if (ptlrpc_import_in_recovery(imp)) {
-		struct l_wait_info lwi;
 		long timeout;
 
 		if (AT_OFF) {
 			if (imp->imp_server_timeout)
-				timeout = cfs_time_seconds(obd_timeout / 2);
+				timeout = obd_timeout * HZ / 2;
 			else
-				timeout = cfs_time_seconds(obd_timeout);
+				timeout = obd_timeout * HZ;
 		} else {
 			int idx = import_at_get_index(imp,
 				imp->imp_client->cli_request_portal);
-			timeout = cfs_time_seconds(
-				at_get(&imp->imp_at.iat_service_estimate[idx]));
+			timeout = at_get(&imp->imp_at.iat_service_estimate[idx]) * HZ;
 		}
 
-		lwi = LWI_TIMEOUT_INTR(cfs_timeout_cap(timeout),
-				       back_to_sleep, LWI_ON_SIGNAL_NOOP, NULL);
-		rc = l_wait_event(imp->imp_recovery_waitq,
-				  !ptlrpc_import_in_recovery(imp), &lwi);
+		if (wait_event_idle_timeout(imp->imp_recovery_waitq,
+					    !ptlrpc_import_in_recovery(imp),
+					    cfs_timeout_cap(timeout)) == 0)
+			l_wait_event_abortable(
+				imp->imp_recovery_waitq,
+				!ptlrpc_import_in_recovery(imp));
 	}
 
 	spin_lock(&imp->imp_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
index 047d712e850c..86883abaad2c 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
@@ -229,7 +229,6 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
 {
 	struct ptlrpc_bulk_desc *desc = req->rq_bulk;
 	wait_queue_head_t *wq;
-	struct l_wait_info lwi;
 	int rc;
 
 	LASSERT(!in_interrupt());     /* might sleep */
@@ -246,7 +245,7 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
 
 	/* the unlink ensures the callback happens ASAP and is the last
 	 * one.  If it fails, it must be because completion just happened,
-	 * but we must still l_wait_event() in this case to give liblustre
+	 * but we must still wait_event() in this case to give liblustre
 	 * a chance to run client_bulk_callback()
 	 */
 	mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw);
@@ -270,15 +269,17 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
 		/* Network access will complete in finite time but the HUGE
 		 * timeout lets us CWARN for visibility of sluggish LNDs
 		 */
-		lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(LONG_UNLINK),
-					   cfs_time_seconds(1), NULL, NULL);
-		rc = l_wait_event(*wq, !ptlrpc_client_bulk_active(req), &lwi);
-		if (rc == 0) {
+		int cnt = 0;
+		while (cnt < LONG_UNLINK &&
+		       (rc = wait_event_idle_timeout(*wq,
+						     !ptlrpc_client_bulk_active(req),
+						     HZ)) == 0)
+			cnt += 1;
+		if (rc > 0) {
 			ptlrpc_rqphase_move(req, req->rq_next_phase);
 			return 1;
 		}
 
-		LASSERT(rc == -ETIMEDOUT);
 		DEBUG_REQ(D_WARNING, req, "Unexpectedly long timeout: desc %p",
 			  desc);
 	}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
index a64e125df95f..f73463ac401f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
@@ -260,17 +260,16 @@ lustre_get_emerg_rs(struct ptlrpc_service_part *svcpt)
 
 	/* See if we have anything in a pool, and wait if nothing */
 	while (list_empty(&svcpt->scp_rep_idle)) {
-		struct l_wait_info lwi;
 		int rc;
 
 		spin_unlock(&svcpt->scp_rep_lock);
 		/* If we cannot get anything for some long time, we better
 		 * bail out instead of waiting infinitely
 		 */
-		lwi = LWI_TIMEOUT(cfs_time_seconds(10), NULL, NULL);
-		rc = l_wait_event(svcpt->scp_rep_waitq,
-				  !list_empty(&svcpt->scp_rep_idle), &lwi);
-		if (rc != 0)
+		rc = wait_event_idle_timeout(svcpt->scp_rep_waitq,
+					     !list_empty(&svcpt->scp_rep_idle),
+					     10 * HZ);
+		if (rc == 0)
 			goto out;
 		spin_lock(&svcpt->scp_rep_lock);
 	}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
index fe6b47bfe8be..639070f6e68e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
@@ -141,7 +141,7 @@ static long pinger_check_timeout(unsigned long time)
 	}
 	mutex_unlock(&pinger_mutex);
 
-	return cfs_time_sub(cfs_time_add(time, cfs_time_seconds(timeout)),
+	return cfs_time_sub(cfs_time_add(time, timeout * HZ),
 					 cfs_time_current());
 }
 
@@ -228,7 +228,6 @@ static int ptlrpc_pinger_main(void *arg)
 	/* And now, loop forever, pinging as needed. */
 	while (1) {
 		unsigned long this_ping = cfs_time_current();
-		struct l_wait_info lwi;
 		long time_to_next_wake;
 		struct timeout_item *item;
 		struct list_head *iter;
@@ -247,7 +246,7 @@ static int ptlrpc_pinger_main(void *arg)
 			if (imp->imp_pingable && imp->imp_next_ping &&
 			    cfs_time_after(imp->imp_next_ping,
 					   cfs_time_add(this_ping,
-							cfs_time_seconds(PING_INTERVAL))))
+							PING_INTERVAL * HZ)))
 				ptlrpc_update_next_ping(imp, 0);
 		}
 		mutex_unlock(&pinger_mutex);
@@ -264,15 +263,12 @@ static int ptlrpc_pinger_main(void *arg)
 		CDEBUG(D_INFO, "next wakeup in " CFS_DURATION_T " (%ld)\n",
 		       time_to_next_wake,
 		       cfs_time_add(this_ping,
-				    cfs_time_seconds(PING_INTERVAL)));
+				    PING_INTERVAL * HZ));
 		if (time_to_next_wake > 0) {
-			lwi = LWI_TIMEOUT(max_t(long, time_to_next_wake,
-						cfs_time_seconds(1)),
-					  NULL, NULL);
-			l_wait_event(thread->t_ctl_waitq,
-				     thread_is_stopping(thread) ||
-				     thread_is_event(thread),
-				     &lwi);
+			wait_event_idle_timeout(thread->t_ctl_waitq,
+						thread_is_stopping(thread) ||
+						thread_is_event(thread),
+						max_t(long, time_to_next_wake, HZ));
 			if (thread_test_and_clear_flags(thread, SVC_STOPPING))
 				break;
 			/* woken after adding import to reset timer */
@@ -291,7 +287,6 @@ static struct ptlrpc_thread pinger_thread;
 
 int ptlrpc_start_pinger(void)
 {
-	struct l_wait_info lwi = { 0 };
 	struct task_struct *task;
 	int rc;
 
@@ -310,8 +305,8 @@ int ptlrpc_start_pinger(void)
 		CERROR("cannot start pinger thread: rc = %d\n", rc);
 		return rc;
 	}
-	l_wait_event(pinger_thread.t_ctl_waitq,
-		     thread_is_running(&pinger_thread), &lwi);
+	wait_event_idle(pinger_thread.t_ctl_waitq,
+			thread_is_running(&pinger_thread));
 
 	return 0;
 }
@@ -320,7 +315,6 @@ static int ptlrpc_pinger_remove_timeouts(void);
 
 int ptlrpc_stop_pinger(void)
 {
-	struct l_wait_info lwi = { 0 };
 	int rc = 0;
 
 	if (thread_is_init(&pinger_thread) ||
@@ -331,8 +325,8 @@ int ptlrpc_stop_pinger(void)
 	thread_set_flags(&pinger_thread, SVC_STOPPING);
 	wake_up(&pinger_thread.t_ctl_waitq);
 
-	l_wait_event(pinger_thread.t_ctl_waitq,
-		     thread_is_stopped(&pinger_thread), &lwi);
+	wait_event_idle(pinger_thread.t_ctl_waitq,
+			thread_is_stopped(&pinger_thread));
 
 	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
index f9decbd1459d..b7a8d7537a66 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
@@ -68,7 +68,7 @@ void ptlrpc_request_cache_free(struct ptlrpc_request *req);
 void ptlrpc_init_xid(void);
 void ptlrpc_set_add_new_req(struct ptlrpcd_ctl *pc,
 			    struct ptlrpc_request *req);
-int ptlrpc_expired_set(void *data);
+void ptlrpc_expired_set(struct ptlrpc_request_set *set);
 int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set);
 void ptlrpc_resend_req(struct ptlrpc_request *request);
 void ptlrpc_set_bulk_mbits(struct ptlrpc_request *req);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index 8b865294d933..6ed77521d025 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -230,12 +230,13 @@ void ptlrpcd_add_req(struct ptlrpc_request *req)
 
 	spin_lock(&req->rq_lock);
 	if (req->rq_invalid_rqset) {
-		struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(5),
-						     back_to_sleep, NULL);
-
 		req->rq_invalid_rqset = 0;
 		spin_unlock(&req->rq_lock);
-		l_wait_event(req->rq_set_waitq, !req->rq_set, &lwi);
+		if (wait_event_idle_timeout(req->rq_set_waitq,
+					    !req->rq_set,
+					    5 * HZ) == 0)
+			wait_event_idle(req->rq_set_waitq,
+					!req->rq_set);
 	} else if (req->rq_set) {
 		/* If we have a valid "rq_set", just reuse it to avoid double
 		 * linked.
@@ -434,16 +435,17 @@ static int ptlrpcd(void *arg)
 	 * new_req_list and ptlrpcd_check() moves them into the set.
 	 */
 	do {
-		struct l_wait_info lwi;
 		int timeout;
 
 		timeout = ptlrpc_set_next_timeout(set);
-		lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1),
-				  ptlrpc_expired_set, set);
 
 		lu_context_enter(&env.le_ctx);
 		lu_context_enter(env.le_ses);
-		l_wait_event(set->set_waitq, ptlrpcd_check(&env, pc), &lwi);
+		if (wait_event_idle_timeout(set->set_waitq,
+					    ptlrpcd_check(&env, pc),
+					    (timeout ? timeout : 1) * HZ) == 0)
+			ptlrpc_expired_set(set);
+
 		lu_context_exit(&env.le_ctx);
 		lu_context_exit(env.le_ses);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c
index e4d3f23e9f3a..7b5f2429d144 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/recover.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c
@@ -346,17 +346,15 @@ int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid, int async)
 		goto out;
 
 	if (!async) {
-		struct l_wait_info lwi;
-		int secs = cfs_time_seconds(obd_timeout);
-
 		CDEBUG(D_HA, "%s: recovery started, waiting %u seconds\n",
-		       obd2cli_tgt(imp->imp_obd), secs);
+		       obd2cli_tgt(imp->imp_obd), obd_timeout);
 
-		lwi = LWI_TIMEOUT(secs, NULL, NULL);
-		rc = l_wait_event(imp->imp_recovery_waitq,
-				  !ptlrpc_import_in_recovery(imp), &lwi);
+		rc = wait_event_idle_timeout(imp->imp_recovery_waitq,
+					     !ptlrpc_import_in_recovery(imp),
+					     obd_timeout * HZ);
 		CDEBUG(D_HA, "%s: recovery finished\n",
 		       obd2cli_tgt(imp->imp_obd));
+		rc = rc? 0 : -ETIMEDOUT;
 	}
 
 out:
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c
index 617e004d00f8..90e3b3022106 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -554,9 +554,8 @@ int ctx_check_refresh(struct ptlrpc_cli_ctx *ctx)
 }
 
 static
-int ctx_refresh_timeout(void *data)
+int ctx_refresh_timeout(struct ptlrpc_request *req)
 {
-	struct ptlrpc_request *req = data;
 	int rc;
 
 	/* conn_cnt is needed in expire_one_request */
@@ -575,10 +574,8 @@ int ctx_refresh_timeout(void *data)
 }
 
 static
-void ctx_refresh_interrupt(void *data)
+void ctx_refresh_interrupt(struct ptlrpc_request *req)
 {
-	struct ptlrpc_request *req = data;
-
 	spin_lock(&req->rq_lock);
 	req->rq_intr = 1;
 	spin_unlock(&req->rq_lock);
@@ -611,7 +608,6 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout)
 {
 	struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
 	struct ptlrpc_sec *sec;
-	struct l_wait_info lwi;
 	int rc;
 
 	LASSERT(ctx);
@@ -743,10 +739,28 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout)
 	req->rq_restart = 0;
 	spin_unlock(&req->rq_lock);
 
-	lwi = LWI_TIMEOUT_INTR(msecs_to_jiffies(timeout * MSEC_PER_SEC),
-			       ctx_refresh_timeout, ctx_refresh_interrupt,
-			       req);
-	rc = l_wait_event(req->rq_reply_waitq, ctx_check_refresh(ctx), &lwi);
+	rc = wait_event_idle_timeout(req->rq_reply_waitq,
+				     ctx_check_refresh(ctx),
+				     timeout * HZ);
+	if (rc == 0 && ctx_refresh_timeout(req) == 0) {
+		/* Keep waiting, but enable some signals */
+		rc = l_wait_event_abortable(req->rq_reply_waitq,
+					    ctx_check_refresh(ctx));
+		if (rc == 0)
+			rc = 1;
+	}
+
+	if (rc > 0)
+		/* condition is true */
+		rc = 0;
+	else if (rc == 0)
+		/* Timed out */
+		rc = -ETIMEDOUT;
+	else {
+		/* Aborted by signal */
+		rc = -EINTR;
+		ctx_refresh_interrupt(req);
+	}
 
 	/*
 	 * following cases could lead us here:
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
index 8d1e0edfcede..48f1a72afd77 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
@@ -142,7 +142,6 @@ static void sec_do_gc(struct ptlrpc_sec *sec)
 static int sec_gc_main(void *arg)
 {
 	struct ptlrpc_thread *thread = arg;
-	struct l_wait_info lwi;
 
 	unshare_fs_struct();
 
@@ -153,7 +152,6 @@ static int sec_gc_main(void *arg)
 	while (1) {
 		struct ptlrpc_sec *sec;
 
-		thread_clear_flags(thread, SVC_SIGNAL);
 		sec_process_ctx_list();
 again:
 		/* go through sec list do gc.
@@ -180,13 +178,9 @@ static int sec_gc_main(void *arg)
 
 		/* check ctx list again before sleep */
 		sec_process_ctx_list();
-
-		lwi = LWI_TIMEOUT(msecs_to_jiffies(SEC_GC_INTERVAL * MSEC_PER_SEC),
-				  NULL, NULL);
-		l_wait_event(thread->t_ctl_waitq,
-			     thread_is_stopping(thread) ||
-			     thread_is_signal(thread),
-			     &lwi);
+		wait_event_idle_timeout(thread->t_ctl_waitq,
+					thread_is_stopping(thread),
+					SEC_GC_INTERVAL * HZ);
 
 		if (thread_test_and_clear_flags(thread, SVC_STOPPING))
 			break;
@@ -199,7 +193,6 @@ static int sec_gc_main(void *arg)
 
 int sptlrpc_gc_init(void)
 {
-	struct l_wait_info lwi = { 0 };
 	struct task_struct *task;
 
 	mutex_init(&sec_gc_mutex);
@@ -216,18 +209,16 @@ int sptlrpc_gc_init(void)
 		return PTR_ERR(task);
 	}
 
-	l_wait_event(sec_gc_thread.t_ctl_waitq,
-		     thread_is_running(&sec_gc_thread), &lwi);
+	wait_event_idle(sec_gc_thread.t_ctl_waitq,
+			thread_is_running(&sec_gc_thread));
 	return 0;
 }
 
 void sptlrpc_gc_fini(void)
 {
-	struct l_wait_info lwi = { 0 };
-
 	thread_set_flags(&sec_gc_thread, SVC_STOPPING);
 	wake_up(&sec_gc_thread.t_ctl_waitq);
 
-	l_wait_event(sec_gc_thread.t_ctl_waitq,
-		     thread_is_stopped(&sec_gc_thread), &lwi);
+	wait_event_idle(sec_gc_thread.t_ctl_waitq,
+			thread_is_stopped(&sec_gc_thread));
 }
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index 63be6e7273f3..29fdb54f16ca 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -1897,15 +1897,6 @@ ptlrpc_check_rqbd_pool(struct ptlrpc_service_part *svcpt)
 	}
 }
 
-static int
-ptlrpc_retry_rqbds(void *arg)
-{
-	struct ptlrpc_service_part *svcpt = arg;
-
-	svcpt->scp_rqbd_timeout = 0;
-	return -ETIMEDOUT;
-}
-
 static inline int
 ptlrpc_threads_enough(struct ptlrpc_service_part *svcpt)
 {
@@ -1968,13 +1959,17 @@ ptlrpc_server_request_incoming(struct ptlrpc_service_part *svcpt)
 	return !list_empty(&svcpt->scp_req_incoming);
 }
 
+/* We perfer lifo queuing, but kernel doesn't provide that yet. */
+#ifndef wait_event_idle_exclusive_lifo
+#define wait_event_idle_exclusive_lifo wait_event_idle_exclusive
+#define wait_event_idle_exclusive_lifo_timeout wait_event_idle_exclusive_timeout
+#endif
+
 static __attribute__((__noinline__)) int
 ptlrpc_wait_event(struct ptlrpc_service_part *svcpt,
 		  struct ptlrpc_thread *thread)
 {
 	/* Don't exit while there are replies to be handled */
-	struct l_wait_info lwi = LWI_TIMEOUT(svcpt->scp_rqbd_timeout,
-					     ptlrpc_retry_rqbds, svcpt);
 
 	/* XXX: Add this back when libcfs watchdog is merged upstream
 	lc_watchdog_disable(thread->t_watchdog);
@@ -1982,13 +1977,25 @@ ptlrpc_wait_event(struct ptlrpc_service_part *svcpt,
 
 	cond_resched();
 
-	l_wait_event_exclusive_head(svcpt->scp_waitq,
-				    ptlrpc_thread_stopping(thread) ||
-				    ptlrpc_server_request_incoming(svcpt) ||
-				    ptlrpc_server_request_pending(svcpt,
-								  false) ||
-				    ptlrpc_rqbd_pending(svcpt) ||
-				    ptlrpc_at_check(svcpt), &lwi);
+	if (svcpt->scp_rqbd_timeout == 0)
+		wait_event_idle_exclusive_lifo(
+			svcpt->scp_waitq,
+			ptlrpc_thread_stopping(thread) ||
+			ptlrpc_server_request_incoming(svcpt) ||
+			ptlrpc_server_request_pending(svcpt,
+						      false) ||
+			ptlrpc_rqbd_pending(svcpt) ||
+			ptlrpc_at_check(svcpt));
+	else if (0 == wait_event_idle_exclusive_lifo_timeout(
+			 svcpt->scp_waitq,
+			 ptlrpc_thread_stopping(thread) ||
+			 ptlrpc_server_request_incoming(svcpt) ||
+			 ptlrpc_server_request_pending(svcpt,
+						       false) ||
+			 ptlrpc_rqbd_pending(svcpt) ||
+			 ptlrpc_at_check(svcpt),
+			 svcpt->scp_rqbd_timeout))
+		svcpt->scp_rqbd_timeout = 0;
 
 	if (ptlrpc_thread_stopping(thread))
 		return -EINTR;
@@ -2149,7 +2156,7 @@ static int ptlrpc_main(void *arg)
 			 * Wait for a timeout (unless something else
 			 * happens) before I try again
 			 */
-			svcpt->scp_rqbd_timeout = cfs_time_seconds(1) / 10;
+			svcpt->scp_rqbd_timeout = HZ / 10;
 			CDEBUG(D_RPCTRACE, "Posted buffers: %d\n",
 			       svcpt->scp_nrqbds_posted);
 		}
@@ -2233,7 +2240,7 @@ static int ptlrpc_hr_main(void *arg)
 	wake_up(&ptlrpc_hr.hr_waitq);
 
 	while (!ptlrpc_hr.hr_stopping) {
-		l_wait_condition(hrt->hrt_waitq, hrt_dont_sleep(hrt, &replies));
+		wait_event_idle(hrt->hrt_waitq, hrt_dont_sleep(hrt, &replies));
 
 		while (!list_empty(&replies)) {
 			struct ptlrpc_reply_state *rs;
@@ -2312,7 +2319,6 @@ static int ptlrpc_start_hr_threads(void)
 
 static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
 {
-	struct l_wait_info lwi = { 0 };
 	struct ptlrpc_thread *thread;
 	LIST_HEAD(zombie);
 
@@ -2341,8 +2347,8 @@ static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
 
 		CDEBUG(D_INFO, "waiting for stopping-thread %s #%u\n",
 		       svcpt->scp_service->srv_thread_name, thread->t_id);
-		l_wait_event(thread->t_ctl_waitq,
-			     thread_is_stopped(thread), &lwi);
+		wait_event_idle(thread->t_ctl_waitq,
+				thread_is_stopped(thread));
 
 		spin_lock(&svcpt->scp_lock);
 	}
@@ -2403,7 +2409,6 @@ int ptlrpc_start_threads(struct ptlrpc_service *svc)
 
 int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
 {
-	struct l_wait_info lwi = { 0 };
 	struct ptlrpc_thread *thread;
 	struct ptlrpc_service *svc;
 	struct task_struct *task;
@@ -2499,9 +2504,8 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
 	if (!wait)
 		return 0;
 
-	l_wait_event(thread->t_ctl_waitq,
-		     thread_is_running(thread) || thread_is_stopped(thread),
-		     &lwi);
+	wait_event_idle(thread->t_ctl_waitq,
+			thread_is_running(thread) || thread_is_stopped(thread));
 
 	rc = thread_is_stopped(thread) ? thread->t_id : 0;
 	return rc;
@@ -2591,13 +2595,12 @@ static void ptlrpc_wait_replies(struct ptlrpc_service_part *svcpt)
 {
 	while (1) {
 		int rc;
-		struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(10),
-						     NULL, NULL);
 
-		rc = l_wait_event(svcpt->scp_waitq,
-				  atomic_read(&svcpt->scp_nreps_difficult) == 0,
-				  &lwi);
-		if (rc == 0)
+		rc = wait_event_idle_timeout(
+			svcpt->scp_waitq,
+			atomic_read(&svcpt->scp_nreps_difficult) == 0,
+			10 * HZ);
+		if (rc > 0)
 			break;
 		CWARN("Unexpectedly long timeout %s %p\n",
 		      svcpt->scp_service->srv_name, svcpt->scp_service);
@@ -2622,7 +2625,7 @@ ptlrpc_service_unlink_rqbd(struct ptlrpc_service *svc)
 {
 	struct ptlrpc_service_part *svcpt;
 	struct ptlrpc_request_buffer_desc *rqbd;
-	struct l_wait_info lwi;
+	int cnt;
 	int rc;
 	int i;
 
@@ -2662,12 +2665,13 @@ ptlrpc_service_unlink_rqbd(struct ptlrpc_service *svc)
 			 * the HUGE timeout lets us CWARN for visibility
 			 * of sluggish LNDs
 			 */
-			lwi = LWI_TIMEOUT_INTERVAL(
-					cfs_time_seconds(LONG_UNLINK),
-					cfs_time_seconds(1), NULL, NULL);
-			rc = l_wait_event(svcpt->scp_waitq,
-					  svcpt->scp_nrqbds_posted == 0, &lwi);
-			if (rc == -ETIMEDOUT) {
+			cnt = 0;
+			while (cnt < LONG_UNLINK &&
+			       (rc = wait_event_idle_timeout(svcpt->scp_waitq,
+							     svcpt->scp_nrqbds_posted == 0,
+							     HZ)) == 0)
+				cnt ++;
+			if (rc == 0) {
 				CWARN("Service %s waiting for request buffers\n",
 				      svcpt->scp_service->srv_name);
 			}
diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h
index 1e114422993a..15db928c4712 100644
--- a/drivers/staging/octeon/ethernet-defines.h
+++ b/drivers/staging/octeon/ethernet-defines.h
@@ -7,10 +7,6 @@
 
 /*
  * A few defines are used to control the operation of this driver:
- *  USE_ASYNC_IOBDMA
- *      Use asynchronous IO access to hardware. This uses Octeon's asynchronous
- *      IOBDMAs to issue IO accesses without stalling. Set this to zero
- *      to disable this. Note that IOBDMAs require CVMSEG.
  *  REUSE_SKBUFFS_WITHOUT_FREE
  *      Allows the TX path to free an skbuff into the FPA hardware pool. This
  *      can significantly improve performance for forwarding and bridging, but
@@ -29,8 +25,6 @@
 #define REUSE_SKBUFFS_WITHOUT_FREE  1
 #endif
 
-#define USE_ASYNC_IOBDMA            (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
-
 /* Maximum number of SKBs to try to free per xmit packet. */
 #define MAX_OUT_QUEUE_DEPTH 1000
 
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index 5e271245273c..c1ae60ce11f5 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -198,11 +198,9 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget)
 	/* Prefetch cvm_oct_device since we know we need it soon */
 	prefetch(cvm_oct_device);
 
-	if (USE_ASYNC_IOBDMA) {
-		/* Save scratch in case userspace is using it */
-		CVMX_SYNCIOBDMA;
-		old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
-	}
+	/* Save scratch in case userspace is using it */
+	CVMX_SYNCIOBDMA;
+	old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
 
 	/* Only allow work for our group (and preserve priorities) */
 	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
@@ -217,10 +215,8 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget)
 			       BIT(rx_group->group));
 	}
 
-	if (USE_ASYNC_IOBDMA) {
-		cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT);
-		did_work_request = 1;
-	}
+	cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT);
+	did_work_request = 1;
 
 	while (rx_count < budget) {
 		struct sk_buff *skb = NULL;
@@ -229,7 +225,7 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget)
 		cvmx_wqe_t *work;
 		int port;
 
-		if (USE_ASYNC_IOBDMA && did_work_request)
+		if (did_work_request)
 			work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH);
 		else
 			work = cvmx_pow_work_request_sync(CVMX_POW_NO_WAIT);
@@ -257,7 +253,7 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget)
 			sizeof(void *));
 		prefetch(pskb);
 
-		if (USE_ASYNC_IOBDMA && rx_count < (budget - 1)) {
+		if (rx_count < (budget - 1)) {
 			cvmx_pow_work_request_async_nocheck(CVMX_SCR_SCRATCH,
 							    CVMX_POW_NO_WAIT);
 			did_work_request = 1;
@@ -400,10 +396,9 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget)
 		cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask);
 	}
 
-	if (USE_ASYNC_IOBDMA) {
-		/* Restore the scratch area */
-		cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
-	}
+	/* Restore the scratch area */
+	cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
+
 	cvm_oct_rx_refill_pool(0);
 
 	return rx_count;
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index df3441b815bb..2aa5fcb7ee32 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -176,23 +176,18 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 		qos = 0;
 	}
 
-	if (USE_ASYNC_IOBDMA) {
-		/* Save scratch in case userspace is using it */
-		CVMX_SYNCIOBDMA;
-		old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
-		old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
-
-		/*
-		 * Fetch and increment the number of packets to be
-		 * freed.
-		 */
-		cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8,
-					       FAU_NUM_PACKET_BUFFERS_TO_FREE,
-					       0);
-		cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
-					       priv->fau + qos * 4,
-					       MAX_SKB_TO_FREE);
-	}
+	/* Save scratch in case userspace is using it */
+	CVMX_SYNCIOBDMA;
+	old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+	old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
+
+	/* Fetch and increment the number of packets to be freed. */
+	cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8,
+				       FAU_NUM_PACKET_BUFFERS_TO_FREE,
+				       0);
+	cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
+				       priv->fau + qos * 4,
+				       MAX_SKB_TO_FREE);
 
 	/*
 	 * We have space for 6 segment pointers, If there will be more
@@ -201,22 +196,11 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (unlikely(skb_shinfo(skb)->nr_frags > 5)) {
 		if (unlikely(__skb_linearize(skb))) {
 			queue_type = QUEUE_DROP;
-			if (USE_ASYNC_IOBDMA) {
-				/*
-				 * Get the number of skbuffs in use
-				 * by the hardware
-				 */
-				CVMX_SYNCIOBDMA;
-				skb_to_free =
-					cvmx_scratch_read64(CVMX_SCR_SCRATCH);
-			} else {
-				/*
-				 * Get the number of skbuffs in use
-				 * by the hardware
-				 */
-				skb_to_free = cvmx_fau_fetch_and_add32(
-					priv->fau + qos * 4, MAX_SKB_TO_FREE);
-			}
+			/* Get the number of skbuffs in use by the
+			 * hardware
+			 */
+			CVMX_SYNCIOBDMA;
+			skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
 			skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free,
 								 priv->fau +
 								 qos * 4);
@@ -384,18 +368,10 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 		pko_command.s.ipoffp1 = skb_network_offset(skb) + 1;
 	}
 
-	if (USE_ASYNC_IOBDMA) {
-		/* Get the number of skbuffs in use by the hardware */
-		CVMX_SYNCIOBDMA;
-		skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
-		buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
-	} else {
-		/* Get the number of skbuffs in use by the hardware */
-		skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
-						       MAX_SKB_TO_FREE);
-		buffers_to_free =
-		    cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
-	}
+	/* Get the number of skbuffs in use by the hardware */
+	CVMX_SYNCIOBDMA;
+	skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+	buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
 
 	skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free,
 						 priv->fau + qos * 4);
@@ -413,9 +389,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 	} else {
 		queue_type = QUEUE_HW;
 	}
-	if (USE_ASYNC_IOBDMA)
-		cvmx_fau_async_fetch_and_add32(
-				CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1);
+	cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1);
 
 	spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
 
@@ -485,16 +459,11 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 		dev_kfree_skb_any(t);
 	}
 
-	if (USE_ASYNC_IOBDMA) {
-		CVMX_SYNCIOBDMA;
-		total_to_clean = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
-		/* Restore the scratch area */
-		cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
-		cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
-	} else {
-		total_to_clean = cvmx_fau_fetch_and_add32(
-						FAU_TOTAL_TX_TO_CLEAN, 1);
-	}
+	CVMX_SYNCIOBDMA;
+	total_to_clean = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+	/* Restore the scratch area */
+	cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
+	cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
 
 	if (total_to_clean & 0x3ff) {
 		/*
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
index 7d9dc2244848..61ba9700d7dc 100644
--- a/drivers/staging/pi433/Documentation/pi433.txt
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -192,10 +192,10 @@ rf params:
 		step_4_0db	- increase in 4 db steps
 		step_5_0db	- increase in 5 db steps
 		step_6_0db	- increase in 6 db steps
-	antennaImpedance
+	antenna_impedance
 		sets the electrical adoption of the antenna
-		fiftyOhm	- for antennas with an impedance of 50Ohm
-		twohundretOhm	- for antennas with an impedance of 200Ohm
+		fifty_ohm	- for antennas with an impedance of 50Ohm
+		two_hundred_ohm	- for antennas with an impedance of 200Ohm
 	lnaGain
 		sets the gain of the low noise amp
 		automatic	- lna gain is determined by an agc
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
index edcd7e798f99..14712e1bd5eb 100644
--- a/drivers/staging/pi433/pi433_if.c
+++ b/drivers/staging/pi433/pi433_if.c
@@ -1183,7 +1183,7 @@ static int pi433_probe(struct spi_device *spi)
 	retval = rf69_set_output_power_level(spi, 13);
 	if (retval < 0)
 		goto minor_failed;
-	retval = rf69_set_antenna_impedance(spi, fiftyOhm);
+	retval = rf69_set_antenna_impedance(spi, fifty_ohm);
 	if (retval < 0)
 		goto minor_failed;
 
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
index 7314f69af198..c4e4ea086a24 100644
--- a/drivers/staging/pi433/pi433_if.h
+++ b/drivers/staging/pi433/pi433_if.h
@@ -116,7 +116,7 @@ struct pi433_rx_cfg {
 
 	__u8			rssi_threshold;
 	enum thresholdDecrement	threshold_decrement;
-	enum antennaImpedance	antenna_impedance;
+	enum antenna_impedance	antenna_impedance;
 	enum lnaGain		lna_gain;
 	enum mantisse		bw_mantisse;	/* normal: 0x50 */
 	__u8			bw_exponent;	/* during AFC: 0x8b */
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
index 7ccdff6ae213..42c2e1c6b386 100644
--- a/drivers/staging/pi433/rf69.c
+++ b/drivers/staging/pi433/rf69.c
@@ -151,11 +151,11 @@ int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
 
 static enum modulation rf69_get_modulation(struct spi_device *spi)
 {
-	u8 currentValue;
+	u8 modulation_reg;
 
-	currentValue = rf69_read_reg(spi, REG_DATAMODUL);
+	modulation_reg = rf69_read_reg(spi, REG_DATAMODUL);
 
-	switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE) {
+	switch (modulation_reg & MASK_DATAMODUL_MODULATION_TYPE) {
 	case DATAMODUL_MODULATION_TYPE_OOK:
 		return OOK;
 	case DATAMODUL_MODULATION_TYPE_FSK:
@@ -330,19 +330,19 @@ int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask)
 	return rf69_clear_bit(spi, REG_PALEVEL, amplifier_mask);
 }
 
-int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+int rf69_set_output_power_level(struct spi_device *spi, u8 power_level)
 {
 	// TODO: Dependency to PA0,1,2 setting
-	powerLevel += 18;
+	power_level += 18;
 
 	// check input value
-	if (powerLevel > 0x1f) {
+	if (power_level > 0x1f) {
 		dev_dbg(&spi->dev, "set: illegal input param");
 		return -EINVAL;
 	}
 
 	// write value
-	return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, powerLevel);
+	return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, power_level);
 }
 
 int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
@@ -386,12 +386,12 @@ int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
 	}
 }
 
-int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance)
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antenna_impedance antenna_impedance)
 {
-	switch (antennaImpedance) {
-	case fiftyOhm:
+	switch (antenna_impedance) {
+	case fifty_ohm:
 		return rf69_clear_bit(spi, REG_LNA, MASK_LNA_ZIN);
-	case twohundretOhm:
+	case two_hundred_ohm:
 		return rf69_set_bit(spi, REG_LNA, MASK_LNA_ZIN);
 	default:
 		dev_dbg(&spi->dev, "set: illegal input param");
@@ -425,7 +425,7 @@ int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
 static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg,
 				     enum mantisse mantisse, u8 exponent)
 {
-	u8 newValue;
+	u8 bandwidth;
 
 	// check value for mantisse and exponent
 	if (exponent > 7) {
@@ -441,29 +441,29 @@ static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg,
 	}
 
 	// read old value
-	newValue = rf69_read_reg(spi, reg);
+	bandwidth = rf69_read_reg(spi, reg);
 
 	// "delete" mantisse and exponent = just keep the DCC setting
-	newValue = newValue & MASK_BW_DCC_FREQ;
+	bandwidth = bandwidth & MASK_BW_DCC_FREQ;
 
 	// add new mantisse
 	switch (mantisse) {
 	case mantisse16:
-		newValue = newValue | BW_MANT_16;
+		bandwidth = bandwidth | BW_MANT_16;
 		break;
 	case mantisse20:
-		newValue = newValue | BW_MANT_20;
+		bandwidth = bandwidth | BW_MANT_20;
 		break;
 	case mantisse24:
-		newValue = newValue | BW_MANT_24;
+		bandwidth = bandwidth | BW_MANT_24;
 		break;
 	}
 
 	// add new exponent
-	newValue = newValue | exponent;
+	bandwidth = bandwidth | exponent;
 
 	// write back
-	return rf69_write_reg(spi, reg, newValue);
+	return rf69_write_reg(spi, reg, bandwidth);
 }
 
 int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
@@ -505,27 +505,27 @@ int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
 {
 	u8 mask;
 	u8 shift;
-	u8 regaddr;
-	u8 regValue;
+	u8 dio_addr;
+	u8 dio_value;
 
 	switch (DIONumber) {
 	case 0:
-		mask = MASK_DIO0; shift = SHIFT_DIO0; regaddr = REG_DIOMAPPING1;
+		mask = MASK_DIO0; shift = SHIFT_DIO0; dio_addr = REG_DIOMAPPING1;
 		break;
 	case 1:
-		mask = MASK_DIO1; shift = SHIFT_DIO1; regaddr = REG_DIOMAPPING1;
+		mask = MASK_DIO1; shift = SHIFT_DIO1; dio_addr = REG_DIOMAPPING1;
 		break;
 	case 2:
-		mask = MASK_DIO2; shift = SHIFT_DIO2; regaddr = REG_DIOMAPPING1;
+		mask = MASK_DIO2; shift = SHIFT_DIO2; dio_addr = REG_DIOMAPPING1;
 		break;
 	case 3:
-		mask = MASK_DIO3; shift = SHIFT_DIO3; regaddr = REG_DIOMAPPING1;
+		mask = MASK_DIO3; shift = SHIFT_DIO3; dio_addr = REG_DIOMAPPING1;
 		break;
 	case 4:
-		mask = MASK_DIO4; shift = SHIFT_DIO4; regaddr = REG_DIOMAPPING2;
+		mask = MASK_DIO4; shift = SHIFT_DIO4; dio_addr = REG_DIOMAPPING2;
 		break;
 	case 5:
-		mask = MASK_DIO5; shift = SHIFT_DIO5; regaddr = REG_DIOMAPPING2;
+		mask = MASK_DIO5; shift = SHIFT_DIO5; dio_addr = REG_DIOMAPPING2;
 		break;
 	default:
 	dev_dbg(&spi->dev, "set: illegal input param");
@@ -533,13 +533,13 @@ int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
 	}
 
 	// read reg
-	regValue = rf69_read_reg(spi, regaddr);
+	dio_value = rf69_read_reg(spi, dio_addr);
 	// delete old value
-	regValue = regValue & ~mask;
+	dio_value = dio_value & ~mask;
 	// add new value
-	regValue = regValue | value << shift;
+	dio_value = dio_value | value << shift;
 	// write back
-	return rf69_write_reg(spi, regaddr, regValue);
+	return rf69_write_reg(spi, dio_addr, dio_value);
 }
 
 bool rf69_get_flag(struct spi_device *spi, enum flag flag)
@@ -645,18 +645,18 @@ int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
 	return rf69_read_mod_write(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_SIZE, (syncSize << 3));
 }
 
-int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8])
 {
 	int retval = 0;
 
-	retval += rf69_write_reg(spi, REG_SYNCVALUE1, syncValues[0]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE2, syncValues[1]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE3, syncValues[2]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE4, syncValues[3]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE5, syncValues[4]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE6, syncValues[5]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE7, syncValues[6]);
-	retval += rf69_write_reg(spi, REG_SYNCVALUE8, syncValues[7]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE1, sync_values[0]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE2, sync_values[1]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE3, sync_values[2]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE4, sync_values[3]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE5, sync_values[4]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE6, sync_values[5]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE7, sync_values[6]);
+	retval += rf69_write_reg(spi, REG_SYNCVALUE8, sync_values[7]);
 
 	return retval;
 }
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
index 09d221b8b6df..2c0d130f7a03 100644
--- a/drivers/staging/pi433/rf69.h
+++ b/drivers/staging/pi433/rf69.h
@@ -34,9 +34,9 @@ int rf69_set_deviation(struct spi_device *spi, u32 deviation);
 int rf69_set_frequency(struct spi_device *spi, u32 frequency);
 int rf69_enable_amplifier(struct spi_device *spi, u8 amplifier_mask);
 int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask);
-int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
+int rf69_set_output_power_level(struct spi_device *spi, u8 power_level);
 int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
-int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antenna_impedance antenna_impedance);
 int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
 int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
 int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
@@ -49,7 +49,7 @@ int rf69_enable_sync(struct spi_device *spi);
 int rf69_disable_sync(struct spi_device *spi);
 int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_condition fifo_fill_condition);
 int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
-int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
+int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8]);
 int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat);
 int rf69_enable_crc(struct spi_device *spi);
 int rf69_disable_crc(struct spi_device *spi);
diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h
index 03440cfa957c..5629af716e4f 100644
--- a/drivers/staging/pi433/rf69_enum.h
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -60,9 +60,9 @@ enum paRamp {
 	ramp10
 };
 
-enum antennaImpedance {
-	fiftyOhm,
-	twohundretOhm
+enum antenna_impedance {
+	fifty_ohm,
+	two_hundred_ohm
 };
 
 enum lnaGain {
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index e8d9858f2942..6b32c142fdcc 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -387,34 +387,27 @@ u8	qos_acm(u8 acm_mask, u8 priority)
 	return change_priority;
 }
 
-static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
+static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib)
 {
-	struct ethhdr etherhdr;
-	struct iphdr ip_hdr;
-	s32 user_prio = 0;
-
-	_rtw_open_pktfile(ppktfile->pkt, ppktfile);
-	_rtw_pktfile_read(ppktfile, (unsigned char *)&etherhdr, ETH_HLEN);
-
-	/*  get user_prio from IP hdr */
 	if (pattrib->ether_type == 0x0800) {
-		_rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr));
-/* 		user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */
-		user_prio = ip_hdr.tos >> 5;
+		struct iphdr ip_hdr;
+
+		skb_copy_bits(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr));
+		pattrib->priority = ip_hdr.tos >> 5;
 	} else if (pattrib->ether_type == ETH_P_PAE) {
 		/*  "When priority processing of data frames is supported, */
 		/*  a STA's SME should send EAPOL-Key frames at the highest priority." */
-		user_prio = 7;
+		pattrib->priority = 7;
+	} else {
+		pattrib->priority = 0;
 	}
 
-	pattrib->priority = user_prio;
 	pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN;
 	pattrib->subtype = WIFI_QOS_DATA_TYPE;
 }
 
 static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib)
 {
-	struct pkt_file pktfile;
 	struct sta_info *psta = NULL;
 	struct ethhdr etherhdr;
 
@@ -425,9 +418,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
 	struct qos_priv		*pqospriv = &pmlmepriv->qospriv;
 	int res = _SUCCESS;
 
-
-	_rtw_open_pktfile(pkt, &pktfile);
-	_rtw_pktfile_read(&pktfile, (u8 *)&etherhdr, ETH_HLEN);
+	skb_copy_bits(pkt, 0, &etherhdr, ETH_HLEN);
 
 	pattrib->ether_type = ntohs(etherhdr.h_proto);
 
@@ -448,16 +439,17 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
 		memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN);
 	}
 
-	pattrib->pktlen = pktfile.pkt_len;
+	pattrib->pktlen = pkt->len - ETH_HLEN;
 
 	if (pattrib->ether_type == ETH_P_IP) {
 		/*  The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */
 		/*  to prevent DHCP protocol fail */
 		u8 tmp[24];
 
-		_rtw_pktfile_read(&pktfile, &tmp[0], 24);
+		skb_copy_bits(pkt, ETH_HLEN, tmp, 24);
+
 		pattrib->dhcp_pkt = 0;
-		if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
+		if (pkt->len > ETH_HLEN + 24 + 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
 			if (pattrib->ether_type == ETH_P_IP) {/*  IP header */
 				if (((tmp[21] == 68) && (tmp[23] == 67)) ||
 				    ((tmp[21] == 67) && (tmp[23] == 68))) {
@@ -516,10 +508,10 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
 
 	if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
 		if (psta->qos_option)
-			set_qos(&pktfile, pattrib);
+			set_qos(pkt, pattrib);
 	} else {
 		if (pqospriv->qos_option) {
-			set_qos(&pktfile, pattrib);
+			set_qos(pkt, pattrib);
 
 			if (pmlmepriv->acm_mask != 0)
 				pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority);
@@ -951,7 +943,6 @@ This sub-routine will perform all the following:
 */
 s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe)
 {
-	struct pkt_file pktfile;
 	s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz;
 	size_t addr;
 	u8 *pframe, *mem_start;
@@ -962,7 +953,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
 	u8 *pbuf_start;
 	s32 bmcst = IS_MCAST(pattrib->ra);
 	s32 res = _SUCCESS;
-
+	size_t remainder = pkt->len - ETH_HLEN;
 
 	psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
 
@@ -987,9 +978,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
 		goto exit;
 	}
 
-	_rtw_open_pktfile(pkt, &pktfile);
-	_rtw_pktfile_read(&pktfile, NULL, ETH_HLEN);
-
 	frg_inx = 0;
 	frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */
 
@@ -1046,12 +1034,9 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
 		if ((pattrib->icv_len > 0) && (pattrib->bswenc))
 			mpdu_len -= pattrib->icv_len;
 
-		if (bmcst) {
-			/*  don't do fragment to broadcat/multicast packets */
-			mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen);
-		} else {
-			mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len);
-		}
+		mem_sz = min_t(size_t, bmcst ? pattrib->pktlen : mpdu_len, remainder);
+		skb_copy_bits(pkt, pkt->len - remainder, pframe, mem_sz);
+		remainder -= mem_sz;
 
 		pframe += mem_sz;
 
@@ -1062,7 +1047,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
 
 		frg_inx++;
 
-		if (bmcst || pktfile.pkt_len == 0) {
+		if (bmcst || remainder == 0) {
 			pattrib->nr_frags = frg_inx;
 
 			pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) +
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index 17967c944946..c3bb183aba38 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -1516,8 +1516,8 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
 	case HW_VAR_CAM_WRITE:
 		{
 			u32 cmd;
-
 			u32 *cam_val = (u32 *)val;
+
 			usb_write32(Adapter, WCAMI, cam_val[0]);
 
 			cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1];
diff --git a/drivers/staging/rtl8188eu/include/xmit_osdep.h b/drivers/staging/rtl8188eu/include/xmit_osdep.h
index 959ef4b3066c..00ebad88f0d1 100644
--- a/drivers/staging/rtl8188eu/include/xmit_osdep.h
+++ b/drivers/staging/rtl8188eu/include/xmit_osdep.h
@@ -18,15 +18,6 @@
 #include <osdep_service.h>
 #include <drv_types.h>
 
-struct pkt_file {
-	struct sk_buff *pkt;
-	size_t pkt_len;	 /* the remainder length of the open_file */
-	unsigned char *cur_buffer;
-	u8 *buf_start;
-	u8 *cur_addr;
-	size_t buf_len;
-};
-
 #define NR_XMITFRAME	256
 
 struct xmit_priv;
@@ -43,10 +34,6 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter,
 			       struct xmit_buf *pxmitbuf, u32 alloc_sz);
 void rtw_os_xmit_resource_free(struct xmit_buf *pxmitbuf);
 
-uint rtw_remainder_len(struct pkt_file *pfile);
-void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile);
-uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen);
-
 void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt);
 void rtw_os_xmit_complete(struct adapter *padapter,
 			  struct xmit_frame *pxframe);
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
index 8bf8248e4ac7..8ac9567c954d 100644
--- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -22,43 +22,6 @@
 #include <xmit_osdep.h>
 #include <osdep_intf.h>
 
-uint rtw_remainder_len(struct pkt_file *pfile)
-{
-	return pfile->buf_len - ((size_t)(pfile->cur_addr) -
-	       (size_t)(pfile->buf_start));
-}
-
-void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
-{
-
-	pfile->pkt = pktptr;
-	pfile->cur_addr = pktptr->data;
-	pfile->buf_start = pktptr->data;
-	pfile->pkt_len = pktptr->len;
-	pfile->buf_len = pktptr->len;
-
-	pfile->cur_buffer = pfile->buf_start;
-
-}
-
-uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
-{
-	uint	len = 0;
-
-
-	len =  rtw_remainder_len(pfile);
-	len = min(rlen, len);
-
-	if (rmem)
-		skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
-
-	pfile->cur_addr += len;
-	pfile->pkt_len -= len;
-
-
-	return len;
-}
-
 int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
 {
 	int i;
diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h
index 32129ac8e169..16b81b1a3f33 100644
--- a/drivers/staging/rtl8723bs/include/drv_types.h
+++ b/drivers/staging/rtl8723bs/include/drv_types.h
@@ -692,9 +692,9 @@ int rtw_suspend_wow(struct adapter *padapter);
 int rtw_resume_process_wow(struct adapter *padapter);
 #endif
 
-__inline static u8 *myid(struct eeprom_priv *peepriv)
+static inline u8 *myid(struct eeprom_priv *peepriv)
 {
-	return (peepriv->mac_addr);
+	return peepriv->mac_addr;
 }
 
 /*  HCI Related header file */
diff --git a/drivers/staging/rtlwifi/wifi.h b/drivers/staging/rtlwifi/wifi.h
index ca0243fa2e66..a23bb1719e35 100644
--- a/drivers/staging/rtlwifi/wifi.h
+++ b/drivers/staging/rtlwifi/wifi.h
@@ -2379,16 +2379,17 @@ struct rtl_hal_usbint_cfg {
 	u32 rx_max_size;
 
 	/* op - rx */
-	void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *);
-	void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *,
-				     struct sk_buff_head *);
+	void (*usb_rx_hdl)(struct ieee80211_hw *hw, struct sk_buff *skb);
+	void (*usb_rx_segregate_hdl)(struct ieee80211_hw *hw,
+				     struct sk_buff *skb,
+				     struct sk_buff_head *skbh);
 
 	/* tx */
-	void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *);
-	int (*usb_tx_post_hdl)(struct ieee80211_hw *, struct urb *,
-			       struct sk_buff *);
-	struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *,
-						struct sk_buff_head *);
+	void (*usb_tx_cleanup)(struct ieee80211_hw *hw, struct sk_buff *skb);
+	int (*usb_tx_post_hdl)(struct ieee80211_hw *hw, struct urb *urb,
+			       struct sk_buff *skb);
+	struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *hw,
+						struct sk_buff_head *skbh);
 
 	/* endpoint mapping */
 	int (*usb_endpoint_mapping)(struct ieee80211_hw *hw);
@@ -2693,12 +2694,12 @@ struct rtl_btc_ops {
 };
 
 struct rtl_halmac_ops {
-	int (*halmac_init_adapter)(struct rtl_priv *);
-	int (*halmac_deinit_adapter)(struct rtl_priv *);
-	int (*halmac_init_hal)(struct rtl_priv *);
-	int (*halmac_deinit_hal)(struct rtl_priv *);
-	int (*halmac_poweron)(struct rtl_priv *);
-	int (*halmac_poweroff)(struct rtl_priv *);
+	int (*halmac_init_adapter)(struct rtl_priv *rtlpriv);
+	int (*halmac_deinit_adapter)(struct rtl_priv *rtlpriv);
+	int (*halmac_init_hal)(struct rtl_priv *rtlpriv);
+	int (*halmac_deinit_hal)(struct rtl_priv *rtlpriv);
+	int (*halmac_poweron)(struct rtl_priv *rtlpriv);
+	int (*halmac_poweroff)(struct rtl_priv *rtlpriv);
 
 	int (*halmac_phy_power_switch)(struct rtl_priv *rtlpriv, u8 enable);
 	int (*halmac_set_mac_address)(struct rtl_priv *rtlpriv, u8 hwport,
diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c
index 313b99104398..4c1f00f551da 100644
--- a/drivers/staging/sm750fb/ddk750_chip.c
+++ b/drivers/staging/sm750fb/ddk750_chip.c
@@ -8,9 +8,9 @@
 
 #define MHz(x) ((x) * 1000000)
 
-static logical_chip_type_t chip;
+static enum logical_chip_type chip;
 
-logical_chip_type_t sm750_get_chip_type(void)
+enum logical_chip_type sm750_get_chip_type(void)
 {
 	return chip;
 }
diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h
index aee82fcaf669..c72aac21b675 100644
--- a/drivers/staging/sm750fb/ddk750_chip.h
+++ b/drivers/staging/sm750fb/ddk750_chip.h
@@ -24,25 +24,23 @@ static inline void poke32(u32 addr, u32 data)
 }
 
 /* This is all the chips recognized by this library */
-typedef enum _logical_chip_type_t {
+enum logical_chip_type {
 	SM_UNKNOWN,
 	SM718,
 	SM750,
 	SM750LE,
-}
-logical_chip_type_t;
+};
 
-typedef enum _clock_type_t {
+enum clock_type {
 	MXCLK_PLL,
 	PRIMARY_PLL,
 	SECONDARY_PLL,
 	VGA0_PLL,
 	VGA1_PLL,
-}
-clock_type_t;
+};
 
 struct pll_value {
-	clock_type_t clockType;
+	enum clock_type clockType;
 	unsigned long inputFreq; /* Input clock frequency to the PLL */
 
 	/* Use this when clockType = PANEL_PLL */
@@ -94,7 +92,7 @@ struct initchip_param {
 	/* More initialization parameter can be added if needed */
 };
 
-logical_chip_type_t sm750_get_chip_type(void);
+enum logical_chip_type sm750_get_chip_type(void);
 void sm750_set_chip_type(unsigned short devId, u8 revId);
 unsigned int sm750_calc_pll_value(unsigned int request, struct  pll_value *pll);
 unsigned int sm750_format_pll_reg(struct pll_value *pPLL);
diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c
index 2cdd87b78e58..7e22d093b091 100644
--- a/drivers/staging/sm750fb/ddk750_mode.c
+++ b/drivers/staging/sm750fb/ddk750_mode.c
@@ -206,7 +206,7 @@ static int programModeRegisters(struct mode_parameter *pModeParam,
 	return ret;
 }
 
-int ddk750_setModeTiming(struct mode_parameter *parm, clock_type_t clock)
+int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock)
 {
 	struct pll_value pll;
 	unsigned int uiActualPixelClk;
diff --git a/drivers/staging/sm750fb/ddk750_mode.h b/drivers/staging/sm750fb/ddk750_mode.h
index 259a9d6a4eb2..2df78a0937b2 100644
--- a/drivers/staging/sm750fb/ddk750_mode.h
+++ b/drivers/staging/sm750fb/ddk750_mode.h
@@ -33,5 +33,5 @@ struct mode_parameter {
 	enum spolarity clock_phase_polarity;
 };
 
-int ddk750_setModeTiming(struct mode_parameter *parm, clock_type_t clock);
+int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock);
 #endif
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
index a8c79864ee4b..f996f8460641 100644
--- a/drivers/staging/sm750fb/sm750_hw.c
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -254,7 +254,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
 	int ret, fmt;
 	u32 reg;
 	struct mode_parameter modparm;
-	clock_type_t clock;
+	enum clock_type clock;
 	struct sm750_dev *sm750_dev;
 	struct lynxfb_par *par;
 
diff --git a/drivers/staging/unisys/visorinput/Kconfig b/drivers/staging/unisys/visorinput/Kconfig
index 655cd62433de..a3817e0f7e5c 100644
--- a/drivers/staging/unisys/visorinput/Kconfig
+++ b/drivers/staging/unisys/visorinput/Kconfig
@@ -4,7 +4,7 @@
 
 config UNISYS_VISORINPUT
 	tristate "Unisys visorinput driver"
-	depends on UNISYSSPAR && UNISYS_VISORBUS && FB && INPUT
+	depends on UNISYSSPAR && UNISYS_VISORBUS && INPUT
 	---help---
 	The Unisys s-Par visorinput driver provides a virtualized system
 	console (keyboard and mouse) that is accessible through the
diff --git a/drivers/staging/unisys/visorinput/Makefile b/drivers/staging/unisys/visorinput/Makefile
index beedca7f0e09..6e4bfa059a1f 100644
--- a/drivers/staging/unisys/visorinput/Makefile
+++ b/drivers/staging/unisys/visorinput/Makefile
@@ -4,4 +4,3 @@
 
 obj-$(CONFIG_UNISYS_VISORINPUT)	+= visorinput.o
 
-ccflags-y += -Idrivers/staging/unisys/include
diff --git a/drivers/staging/unisys/visorinput/ultrainputreport.h b/drivers/staging/unisys/visorinput/ultrainputreport.h
deleted file mode 100644
index 67dac430ce0c..000000000000
--- a/drivers/staging/unisys/visorinput/ultrainputreport.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2010 - 2015 UNISYS CORPORATION
- * All rights reserved.
- */
-
-#ifndef __SPAR_ULTRAINPUTREPORT_H__
-#define __SPAR_ULTRAINPUTREPORT_H__
-
-#include <linux/types.h>
-
-/* These defines identify mouse and keyboard activity which is specified by the
- * firmware to the host using the cmsimpleinput protocol.  @ingroup coretypes
- */
-	/* only motion; arg1=x, arg2=y */
-#define INPUTACTION_XY_MOTION 1
-/* arg1: 1=left,2=center,3=right */
-#define INPUTACTION_MOUSE_BUTTON_DOWN 2
-/* arg1: 1=left,2=center,3=right */
-#define INPUTACTION_MOUSE_BUTTON_UP 3
-/* arg1: 1=left,2=center,3=right */
-#define INPUTACTION_MOUSE_BUTTON_CLICK 4
-/* arg1: 1=left,2=center 3=right */
-#define INPUTACTION_MOUSE_BUTTON_DCLICK 5
-/* arg1: wheel rotation away from user */
-#define INPUTACTION_WHEEL_ROTATE_AWAY 6
-/* arg1: wheel rotation toward user */
-#define INPUTACTION_WHEEL_ROTATE_TOWARD 7
-/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1
- *	 is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st
- *	 byte in the low 8 bits, and the 2nd byte in the high 8 bits.
- *	 E.g., the right ALT key would appear as x'38e0'.
- */
-#define INPUTACTION_KEY_DOWN 64
-/* arg1: scancode (in same format as inputaction_keyDown) */
-#define INPUTACTION_KEY_UP 65
-/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of
- *	 the locking keys, like capslock, numlock, or scrolllock.
- * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON)
- */
-#define INPUTACTION_SET_LOCKING_KEY_STATE 66
-/* arg1: scancode (in same format as inputaction_keyDown */
-#define INPUTACTION_KEY_DOWN_UP 67
-
-struct visor_inputactivity {
-	u16 action;
-	u16 arg1;
-	u16 arg2;
-	u16 arg3;
-} __packed;
-
-struct visor_inputreport {
-	u64 seq_no;
-	struct visor_inputactivity activity;
-} __packed;
-
-#endif
diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c
index d8048e48658f..9693fb559052 100644
--- a/drivers/staging/unisys/visorinput/visorinput.c
+++ b/drivers/staging/unisys/visorinput/visorinput.c
@@ -18,7 +18,36 @@
 #include <linux/uuid.h>
 #include <linux/visorbus.h>
 
-#include "ultrainputreport.h"
+/* These defines identify mouse and keyboard activity which is specified by the
+ * firmware to the host using the cmsimpleinput protocol.  @ingroup coretypes
+ */
+/* only motion; arg1=x, arg2=y */
+#define INPUTACTION_XY_MOTION 1
+
+/* arg1: 1=left,2=center,3=right */
+#define INPUTACTION_MOUSE_BUTTON_DOWN 2
+#define INPUTACTION_MOUSE_BUTTON_UP 3
+#define INPUTACTION_MOUSE_BUTTON_CLICK 4
+#define INPUTACTION_MOUSE_BUTTON_DCLICK 5
+
+/* arg1: wheel rotation away from/toward user */
+#define INPUTACTION_WHEEL_ROTATE_AWAY 6
+#define INPUTACTION_WHEEL_ROTATE_TOWARD 7
+
+/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1
+ *	 is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st
+ *	 byte in the low 8 bits, and the 2nd byte in the high 8 bits.
+ *	 E.g., the right ALT key would appear as x'38e0'.
+ */
+#define INPUTACTION_KEY_DOWN 64
+#define INPUTACTION_KEY_UP 65
+#define INPUTACTION_KEY_DOWN_UP 67
+
+/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of
+ *	 the locking keys, like capslock, numlock, or scrolllock.
+ * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON)
+ */
+#define INPUTACTION_SET_LOCKING_KEY_STATE 66
 
 /* Keyboard channel {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */
 #define VISOR_KEYBOARD_CHANNEL_GUID \
@@ -32,19 +61,45 @@
 		  0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87)
 #define VISOR_MOUSE_CHANNEL_GUID_STR "addf07d4-94a9-46e2-81c3-61abcdbdbd87"
 
-#define PIXELS_ACROSS_DEFAULT 800
-#define PIXELS_DOWN_DEFAULT   600
+#define PIXELS_ACROSS_DEFAULT 1024
+#define PIXELS_DOWN_DEFAULT   768
 #define KEYCODE_TABLE_BYTES   256
 
-enum visorinput_device_type {
+struct visor_inputactivity {
+	u16 action;
+	u16 arg1;
+	u16 arg2;
+	u16 arg3;
+} __packed;
+
+struct visor_inputreport {
+	u64 seq_no;
+	struct visor_inputactivity activity;
+} __packed;
+
+/* header of keyboard/mouse channels */
+struct visor_input_channel_data {
+	u32 n_input_reports;
+	union {
+		struct {
+			u16 x_res;
+			u16 y_res;
+		} mouse;
+		struct {
+			u32 flags;
+		} keyboard;
+	};
+} __packed;
+
+enum visorinput_dev_type {
 	visorinput_keyboard,
 	visorinput_mouse,
 };
 
 /*
- * This is the private data that we store for each device.
- * A pointer to this struct is maintained via
- * dev_get_drvdata() / dev_set_drvdata() for each struct device.
+ * This is the private data that we store for each device. A pointer to this
+ * struct is maintained via dev_get_drvdata() / dev_set_drvdata() for each
+ * struct device.
  */
 struct visorinput_devdata {
 	struct visor_device *dev;
@@ -215,10 +270,9 @@ static int visorinput_open(struct input_dev *visorinput_dev)
 	dev_dbg(&visorinput_dev->dev, "%s opened\n", __func__);
 
 	/*
-	 * If we're not paused, really enable interrupts.
-	 * Regardless of whether we are paused, set a flag indicating
-	 * interrupts should be enabled so when we resume, interrupts
-	 * will really be enabled.
+	 * If we're not paused, really enable interrupts. Regardless of whether
+	 * we are paused, set a flag indicating interrupts should be enabled so
+	 * when we resume, interrupts will really be enabled.
 	 */
 	mutex_lock(&devdata->lock_visor_dev);
 	devdata->interrupts_enabled = true;
@@ -244,10 +298,9 @@ static void visorinput_close(struct input_dev *visorinput_dev)
 	dev_dbg(&visorinput_dev->dev, "%s closed\n", __func__);
 
 	/*
-	 * If we're not paused, really disable interrupts.
-	 * Regardless of whether we are paused, set a flag indicating
-	 * interrupts should be disabled so when we resume we will
-	 * not re-enable them.
+	 * If we're not paused, really disable interrupts. Regardless of
+	 * whether we are paused, set a flag indicating interrupts should be
+	 * disabled so when we resume we will not re-enable them.
 	 */
 	mutex_lock(&devdata->lock_visor_dev);
 	devdata->interrupts_enabled = false;
@@ -260,9 +313,9 @@ static void visorinput_close(struct input_dev *visorinput_dev)
 }
 
 /*
- * setup_client_keyboard() initializes and returns a Linux input node that
- * we can use to deliver keyboard inputs to Linux.  We of course do this when
- * we see keyboard inputs coming in on a keyboard channel.
+ * setup_client_keyboard() initializes and returns a Linux input node that we
+ * can use to deliver keyboard inputs to Linux.  We of course do this when we
+ * see keyboard inputs coming in on a keyboard channel.
  */
 static struct input_dev *setup_client_keyboard(void *devdata,
 					       unsigned char *keycode_table)
@@ -306,10 +359,9 @@ static struct input_dev *setup_client_keyboard(void *devdata,
 	return visorinput_dev;
 }
 
-static struct input_dev *setup_client_mouse(void *devdata)
+static struct input_dev *setup_client_mouse(void *devdata, unsigned int xres,
+					    unsigned int yres)
 {
-	int xres, yres;
-	struct fb_info *fb0;
 	struct input_dev *visorinput_dev = input_allocate_device();
 
 	if (!visorinput_dev)
@@ -327,14 +379,10 @@ static struct input_dev *setup_client_mouse(void *devdata)
 	set_bit(BTN_RIGHT, visorinput_dev->keybit);
 	set_bit(BTN_MIDDLE, visorinput_dev->keybit);
 
-	if (registered_fb[0]) {
-		fb0 = registered_fb[0];
-		xres = fb0->var.xres_virtual;
-		yres = fb0->var.yres_virtual;
-	} else {
+	if (xres == 0)
 		xres = PIXELS_ACROSS_DEFAULT;
+	if (yres == 0)
 		yres = PIXELS_DOWN_DEFAULT;
-	}
 	input_set_abs_params(visorinput_dev, ABS_X, 0, xres, 0, 0);
 	input_set_abs_params(visorinput_dev, ABS_Y, 0, yres, 0, 0);
 
@@ -347,14 +395,15 @@ static struct input_dev *setup_client_mouse(void *devdata)
 	return visorinput_dev;
 }
 
-static struct visorinput_devdata *devdata_create(
-					struct visor_device *dev,
-					enum visorinput_device_type devtype)
+static struct visorinput_devdata *devdata_create(struct visor_device *dev,
+						 enum visorinput_dev_type dtype)
 {
 	struct visorinput_devdata *devdata = NULL;
 	unsigned int extra_bytes = 0;
+	unsigned int size, xres, yres, err;
+	struct visor_input_channel_data data;
 
-	if (devtype == visorinput_keyboard)
+	if (dtype == visorinput_keyboard)
 		/* allocate room for devdata->keycode_table, filled in below */
 		extra_bytes = KEYCODE_TABLE_BYTES * 2;
 	devdata = kzalloc(sizeof(*devdata) + extra_bytes, GFP_KERNEL);
@@ -373,11 +422,11 @@ static struct visorinput_devdata *devdata_create(
 	devdata->paused = true;
 
 	/*
-	 * This is an input device in a client guest partition,
-	 * so we need to create whatever input nodes are necessary to
-	 * deliver our inputs to the guest OS.
+	 * This is an input device in a client guest partition, so we need to
+	 * create whatever input nodes are necessary to deliver our inputs to
+	 * the guest OS.
 	 */
-	switch (devtype) {
+	switch (dtype) {
 	case visorinput_keyboard:
 		devdata->keycode_table_bytes = extra_bytes;
 		memcpy(devdata->keycode_table, visorkbd_keycode,
@@ -390,7 +439,15 @@ static struct visorinput_devdata *devdata_create(
 			goto cleanups_register;
 		break;
 	case visorinput_mouse:
-		devdata->visorinput_dev = setup_client_mouse(devdata);
+		size = sizeof(struct visor_input_channel_data);
+		err = visorbus_read_channel(dev, sizeof(struct channel_header),
+					    &data, size);
+		if (err)
+			goto cleanups_register;
+		xres = data.mouse.x_res;
+		yres = data.mouse.y_res;
+		devdata->visorinput_dev = setup_client_mouse(devdata, xres,
+							     yres);
 		if (!devdata->visorinput_dev)
 			goto cleanups_register;
 		break;
@@ -404,10 +461,9 @@ static struct visorinput_devdata *devdata_create(
 
 	/*
 	 * Device struct is completely set up now, with the exception of
-	 * visorinput_dev being registered.
-	 * We need to unlock before we register the device, because this
-	 * can cause an on-stack call of visorinput_open(), which would
-	 * deadlock if we had the lock.
+	 * visorinput_dev being registered. We need to unlock before we
+	 * register the device, because this can cause an on-stack call of
+	 * visorinput_open(), which would deadlock if we had the lock.
 	 */
 	if (input_register_device(devdata->visorinput_dev)) {
 		input_free_device(devdata->visorinput_dev);
@@ -416,9 +472,9 @@ static struct visorinput_devdata *devdata_create(
 
 	mutex_lock(&devdata->lock_visor_dev);
 	/*
-	 * Establish calls to visorinput_channel_interrupt() if that is
-	 * the desired state that we've kept track of in interrupts_enabled
-	 * while the device was being created.
+	 * Establish calls to visorinput_channel_interrupt() if that is the
+	 * desired state that we've kept track of in interrupts_enabled while
+	 * the device was being created.
 	 */
 	devdata->paused = false;
 	if (devdata->interrupts_enabled)
@@ -437,17 +493,17 @@ static struct visorinput_devdata *devdata_create(
 static int visorinput_probe(struct visor_device *dev)
 {
 	const guid_t *guid;
-	enum visorinput_device_type devtype;
+	enum visorinput_dev_type dtype;
 
 	guid = visorchannel_get_guid(dev->visorchannel);
 	if (guid_equal(guid, &visor_mouse_channel_guid))
-		devtype = visorinput_mouse;
+		dtype = visorinput_mouse;
 	else if (guid_equal(guid, &visor_keyboard_channel_guid))
-		devtype = visorinput_keyboard;
+		dtype = visorinput_keyboard;
 	else
 		return -ENODEV;
 	visorbus_disable_channel_interrupts(dev);
-	if (!devdata_create(dev, devtype))
+	if (!devdata_create(dev, dtype))
 		return -ENOMEM;
 	return 0;
 }
@@ -469,8 +525,8 @@ static void visorinput_remove(struct visor_device *dev)
 	visorbus_disable_channel_interrupts(dev);
 
 	/*
-	 * due to above, at this time no thread of execution will be
-	 * in visorinput_channel_interrupt()
+	 * due to above, at this time no thread of execution will be in
+	 * visorinput_channel_interrupt()
 	 */
 
 	dev_set_drvdata(&dev->device, NULL);
@@ -513,9 +569,8 @@ static void handle_locking_key(struct input_dev *visorinput_dev, int keycode,
 }
 
 /*
- * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode
- * with 0xE0 in the low byte and the extended scancode value in the next
- * higher byte.
+ * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode with
+ * 0xE0 in the low byte and the extended scancode value in the next higher byte.
  */
 static int scancode_to_keycode(int scancode)
 {
@@ -656,8 +711,8 @@ static int visorinput_pause(struct visor_device *dev,
 		visorbus_disable_channel_interrupts(dev);
 
 	/*
-	 * due to above, at this time no thread of execution will be
-	 * in visorinput_channel_interrupt()
+	 * due to above, at this time no thread of execution will be in
+	 * visorinput_channel_interrupt()
 	 */
 	devdata->paused = true;
 	complete_func(dev, 0);
@@ -687,9 +742,9 @@ static int visorinput_resume(struct visor_device *dev,
 	complete_func(dev, 0);
 
 	/*
-	 * Re-establish calls to visorinput_channel_interrupt() if that is
-	 * the desired state that we've kept track of in interrupts_enabled
-	 * while the device was paused.
+	 * Re-establish calls to visorinput_channel_interrupt() if that is the
+	 * desired state that we've kept track of in interrupts_enabled while
+	 * the device was paused.
 	 */
 	if (devdata->interrupts_enabled)
 		visorbus_enable_channel_interrupts(dev);
diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile
index 1ecb261e04ae..fb26b826e640 100644
--- a/drivers/staging/vc04_services/Makefile
+++ b/drivers/staging/vc04_services/Makefile
@@ -4,7 +4,6 @@ obj-$(CONFIG_BCM2835_VCHIQ)	+= vchiq.o
 vchiq-objs := \
    interface/vchiq_arm/vchiq_core.o  \
    interface/vchiq_arm/vchiq_arm.o \
-   interface/vchiq_arm/vchiq_kern_lib.o \
    interface/vchiq_arm/vchiq_2835_arm.o \
    interface/vchiq_arm/vchiq_debugfs.o \
    interface/vchiq_arm/vchiq_shim.o \
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index c2c440009cac..f5cefda49b22 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -193,6 +193,375 @@ static const char *const ioctl_names[] = {
 vchiq_static_assert(ARRAY_SIZE(ioctl_names) ==
 		    (VCHIQ_IOC_MAX + 1));
 
+static VCHIQ_STATUS_T
+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+	unsigned int size, VCHIQ_BULK_DIR_T dir);
+
+#define VCHIQ_INIT_RETRIES 10
+VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out)
+{
+	VCHIQ_STATUS_T status = VCHIQ_ERROR;
+	VCHIQ_STATE_T *state;
+	VCHIQ_INSTANCE_T instance = NULL;
+	int i;
+
+	vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
+
+	/* VideoCore may not be ready due to boot up timing.
+	 * It may never be ready if kernel and firmware are mismatched,so don't
+	 * block forever.
+	 */
+	for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
+		state = vchiq_get_state();
+		if (state)
+			break;
+		udelay(500);
+	}
+	if (i == VCHIQ_INIT_RETRIES) {
+		vchiq_log_error(vchiq_core_log_level,
+			"%s: videocore not initialized\n", __func__);
+		goto failed;
+	} else if (i > 0) {
+		vchiq_log_warning(vchiq_core_log_level,
+			"%s: videocore initialized after %d retries\n",
+			__func__, i);
+	}
+
+	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+	if (!instance) {
+		vchiq_log_error(vchiq_core_log_level,
+			"%s: error allocating vchiq instance\n", __func__);
+		goto failed;
+	}
+
+	instance->connected = 0;
+	instance->state = state;
+	mutex_init(&instance->bulk_waiter_list_mutex);
+	INIT_LIST_HEAD(&instance->bulk_waiter_list);
+
+	*instance_out = instance;
+
+	status = VCHIQ_SUCCESS;
+
+failed:
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p): returning %d", __func__, instance, status);
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_initialise);
+
+VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
+{
+	VCHIQ_STATUS_T status;
+	VCHIQ_STATE_T *state = instance->state;
+
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p) called", __func__, instance);
+
+	if (mutex_lock_killable(&state->mutex) != 0)
+		return VCHIQ_RETRY;
+
+	/* Remove all services */
+	status = vchiq_shutdown_internal(state, instance);
+
+	mutex_unlock(&state->mutex);
+
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p): returning %d", __func__, instance, status);
+
+	if (status == VCHIQ_SUCCESS) {
+		struct list_head *pos, *next;
+
+		list_for_each_safe(pos, next,
+				&instance->bulk_waiter_list) {
+			struct bulk_waiter_node *waiter;
+
+			waiter = list_entry(pos,
+					struct bulk_waiter_node,
+					list);
+			list_del(pos);
+			vchiq_log_info(vchiq_arm_log_level,
+					"bulk_waiter - cleaned up %pK for pid %d",
+					waiter, waiter->pid);
+			kfree(waiter);
+		}
+		kfree(instance);
+	}
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_shutdown);
+
+static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
+{
+	return instance->connected;
+}
+
+VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
+{
+	VCHIQ_STATUS_T status;
+	VCHIQ_STATE_T *state = instance->state;
+
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p) called", __func__, instance);
+
+	if (mutex_lock_killable(&state->mutex) != 0) {
+		vchiq_log_trace(vchiq_core_log_level,
+			"%s: call to mutex_lock failed", __func__);
+		status = VCHIQ_RETRY;
+		goto failed;
+	}
+	status = vchiq_connect_internal(state, instance);
+
+	if (status == VCHIQ_SUCCESS)
+		instance->connected = 1;
+
+	mutex_unlock(&state->mutex);
+
+failed:
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p): returning %d", __func__, instance, status);
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_connect);
+
+VCHIQ_STATUS_T vchiq_add_service(
+	VCHIQ_INSTANCE_T              instance,
+	const VCHIQ_SERVICE_PARAMS_T *params,
+	VCHIQ_SERVICE_HANDLE_T       *phandle)
+{
+	VCHIQ_STATUS_T status;
+	VCHIQ_STATE_T *state = instance->state;
+	VCHIQ_SERVICE_T *service = NULL;
+	int srvstate;
+
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p) called", __func__, instance);
+
+	*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+	srvstate = vchiq_is_connected(instance)
+		? VCHIQ_SRVSTATE_LISTENING
+		: VCHIQ_SRVSTATE_HIDDEN;
+
+	service = vchiq_add_service_internal(
+		state,
+		params,
+		srvstate,
+		instance,
+		NULL);
+
+	if (service) {
+		*phandle = service->handle;
+		status = VCHIQ_SUCCESS;
+	} else
+		status = VCHIQ_ERROR;
+
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p): returning %d", __func__, instance, status);
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_add_service);
+
+VCHIQ_STATUS_T vchiq_open_service(
+	VCHIQ_INSTANCE_T              instance,
+	const VCHIQ_SERVICE_PARAMS_T *params,
+	VCHIQ_SERVICE_HANDLE_T       *phandle)
+{
+	VCHIQ_STATUS_T   status = VCHIQ_ERROR;
+	VCHIQ_STATE_T   *state = instance->state;
+	VCHIQ_SERVICE_T *service = NULL;
+
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p) called", __func__, instance);
+
+	*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+	if (!vchiq_is_connected(instance))
+		goto failed;
+
+	service = vchiq_add_service_internal(state,
+		params,
+		VCHIQ_SRVSTATE_OPENING,
+		instance,
+		NULL);
+
+	if (service) {
+		*phandle = service->handle;
+		status = vchiq_open_service_internal(service, current->pid);
+		if (status != VCHIQ_SUCCESS) {
+			vchiq_remove_service(service->handle);
+			*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+		}
+	}
+
+failed:
+	vchiq_log_trace(vchiq_core_log_level,
+		"%s(%p): returning %d", __func__, instance, status);
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_open_service);
+
+VCHIQ_STATUS_T
+vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
+	const void *data, unsigned int size, void *userdata)
+{
+	return vchiq_bulk_transfer(handle,
+		VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
+		VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
+}
+EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
+
+VCHIQ_STATUS_T
+vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+	unsigned int size, void *userdata)
+{
+	return vchiq_bulk_transfer(handle,
+		VCHI_MEM_HANDLE_INVALID, data, size, userdata,
+		VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
+}
+EXPORT_SYMBOL(vchiq_queue_bulk_receive);
+
+VCHIQ_STATUS_T
+vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
+	unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
+{
+	VCHIQ_STATUS_T status;
+
+	switch (mode) {
+	case VCHIQ_BULK_MODE_NOCALLBACK:
+	case VCHIQ_BULK_MODE_CALLBACK:
+		status = vchiq_bulk_transfer(handle,
+			VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
+			mode, VCHIQ_BULK_TRANSMIT);
+		break;
+	case VCHIQ_BULK_MODE_BLOCKING:
+		status = vchiq_blocking_bulk_transfer(handle,
+			(void *)data, size, VCHIQ_BULK_TRANSMIT);
+		break;
+	default:
+		return VCHIQ_ERROR;
+	}
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_bulk_transmit);
+
+VCHIQ_STATUS_T
+vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+	unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
+{
+	VCHIQ_STATUS_T status;
+
+	switch (mode) {
+	case VCHIQ_BULK_MODE_NOCALLBACK:
+	case VCHIQ_BULK_MODE_CALLBACK:
+		status = vchiq_bulk_transfer(handle,
+			VCHI_MEM_HANDLE_INVALID, data, size, userdata,
+			mode, VCHIQ_BULK_RECEIVE);
+		break;
+	case VCHIQ_BULK_MODE_BLOCKING:
+		status = vchiq_blocking_bulk_transfer(handle,
+			(void *)data, size, VCHIQ_BULK_RECEIVE);
+		break;
+	default:
+		return VCHIQ_ERROR;
+	}
+
+	return status;
+}
+EXPORT_SYMBOL(vchiq_bulk_receive);
+
+static VCHIQ_STATUS_T
+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+	unsigned int size, VCHIQ_BULK_DIR_T dir)
+{
+	VCHIQ_INSTANCE_T instance;
+	VCHIQ_SERVICE_T *service;
+	VCHIQ_STATUS_T status;
+	struct bulk_waiter_node *waiter = NULL;
+	struct list_head *pos;
+
+	service = find_service_by_handle(handle);
+	if (!service)
+		return VCHIQ_ERROR;
+
+	instance = service->instance;
+
+	unlock_service(service);
+
+	mutex_lock(&instance->bulk_waiter_list_mutex);
+	list_for_each(pos, &instance->bulk_waiter_list) {
+		if (list_entry(pos, struct bulk_waiter_node,
+				list)->pid == current->pid) {
+			waiter = list_entry(pos,
+				struct bulk_waiter_node,
+				list);
+			list_del(pos);
+			break;
+		}
+	}
+	mutex_unlock(&instance->bulk_waiter_list_mutex);
+
+	if (waiter) {
+		VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
+
+		if (bulk) {
+			/* This thread has an outstanding bulk transfer. */
+			if ((bulk->data != data) ||
+				(bulk->size != size)) {
+				/* This is not a retry of the previous one.
+				 * Cancel the signal when the transfer
+				 * completes.
+				 */
+				spin_lock(&bulk_waiter_spinlock);
+				bulk->userdata = NULL;
+				spin_unlock(&bulk_waiter_spinlock);
+			}
+		}
+	}
+
+	if (!waiter) {
+		waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
+		if (!waiter) {
+			vchiq_log_error(vchiq_core_log_level,
+				"%s - out of memory", __func__);
+			return VCHIQ_ERROR;
+		}
+	}
+
+	status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
+		data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
+		dir);
+	if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
+		!waiter->bulk_waiter.bulk) {
+		VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
+
+		if (bulk) {
+			/* Cancel the signal when the transfer
+			 * completes.
+			 */
+			spin_lock(&bulk_waiter_spinlock);
+			bulk->userdata = NULL;
+			spin_unlock(&bulk_waiter_spinlock);
+		}
+		kfree(waiter);
+	} else {
+		waiter->pid = current->pid;
+		mutex_lock(&instance->bulk_waiter_list_mutex);
+		list_add(&waiter->list, &instance->bulk_waiter_list);
+		mutex_unlock(&instance->bulk_waiter_list_mutex);
+		vchiq_log_info(vchiq_arm_log_level,
+				"saved bulk_waiter %pK for pid %d",
+				waiter, current->pid);
+	}
+
+	return status;
+}
 /****************************************************************************
 *
 *   add_completion
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h
deleted file mode 100644
index df645813bdae..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-const char *vchiq_get_build_hostname(void);
-const char *vchiq_get_build_version(void);
-const char *vchiq_get_build_time(void);
-const char *vchiq_get_build_date(void);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
deleted file mode 100644
index 43c89a08bda9..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-
-#include "vchiq_core.h"
-#include "vchiq_arm.h"
-#include "vchiq_killable.h"
-
-/* ---- Public Variables ------------------------------------------------- */
-
-/* ---- Private Constants and Types -------------------------------------- */
-
-struct bulk_waiter_node {
-	struct bulk_waiter bulk_waiter;
-	int pid;
-	struct list_head list;
-};
-
-struct vchiq_instance_struct {
-	VCHIQ_STATE_T *state;
-
-	int connected;
-
-	struct list_head bulk_waiter_list;
-	struct mutex bulk_waiter_list_mutex;
-};
-
-static VCHIQ_STATUS_T
-vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-	unsigned int size, VCHIQ_BULK_DIR_T dir);
-
-#define VCHIQ_INIT_RETRIES 10
-VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out)
-{
-	VCHIQ_STATUS_T status = VCHIQ_ERROR;
-	VCHIQ_STATE_T *state;
-	VCHIQ_INSTANCE_T instance = NULL;
-	int i;
-
-	vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
-
-	/* VideoCore may not be ready due to boot up timing.
-	 * It may never be ready if kernel and firmware are mismatched,so don't
-	 * block forever.
-	 */
-	for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
-		state = vchiq_get_state();
-		if (state)
-			break;
-		udelay(500);
-	}
-	if (i == VCHIQ_INIT_RETRIES) {
-		vchiq_log_error(vchiq_core_log_level,
-			"%s: videocore not initialized\n", __func__);
-		goto failed;
-	} else if (i > 0) {
-		vchiq_log_warning(vchiq_core_log_level,
-			"%s: videocore initialized after %d retries\n",
-			__func__, i);
-	}
-
-	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-	if (!instance) {
-		vchiq_log_error(vchiq_core_log_level,
-			"%s: error allocating vchiq instance\n", __func__);
-		goto failed;
-	}
-
-	instance->connected = 0;
-	instance->state = state;
-	mutex_init(&instance->bulk_waiter_list_mutex);
-	INIT_LIST_HEAD(&instance->bulk_waiter_list);
-
-	*instance_out = instance;
-
-	status = VCHIQ_SUCCESS;
-
-failed:
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p): returning %d", __func__, instance, status);
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_initialise);
-
-VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
-{
-	VCHIQ_STATUS_T status;
-	VCHIQ_STATE_T *state = instance->state;
-
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p) called", __func__, instance);
-
-	if (mutex_lock_killable(&state->mutex) != 0)
-		return VCHIQ_RETRY;
-
-	/* Remove all services */
-	status = vchiq_shutdown_internal(state, instance);
-
-	mutex_unlock(&state->mutex);
-
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p): returning %d", __func__, instance, status);
-
-	if (status == VCHIQ_SUCCESS) {
-		struct list_head *pos, *next;
-
-		list_for_each_safe(pos, next,
-				&instance->bulk_waiter_list) {
-			struct bulk_waiter_node *waiter;
-
-			waiter = list_entry(pos,
-					struct bulk_waiter_node,
-					list);
-			list_del(pos);
-			vchiq_log_info(vchiq_arm_log_level,
-					"bulk_waiter - cleaned up %pK for pid %d",
-					waiter, waiter->pid);
-			kfree(waiter);
-		}
-		kfree(instance);
-	}
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_shutdown);
-
-static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
-{
-	return instance->connected;
-}
-
-VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
-{
-	VCHIQ_STATUS_T status;
-	VCHIQ_STATE_T *state = instance->state;
-
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p) called", __func__, instance);
-
-	if (mutex_lock_killable(&state->mutex) != 0) {
-		vchiq_log_trace(vchiq_core_log_level,
-			"%s: call to mutex_lock failed", __func__);
-		status = VCHIQ_RETRY;
-		goto failed;
-	}
-	status = vchiq_connect_internal(state, instance);
-
-	if (status == VCHIQ_SUCCESS)
-		instance->connected = 1;
-
-	mutex_unlock(&state->mutex);
-
-failed:
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p): returning %d", __func__, instance, status);
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_connect);
-
-VCHIQ_STATUS_T vchiq_add_service(
-	VCHIQ_INSTANCE_T              instance,
-	const VCHIQ_SERVICE_PARAMS_T *params,
-	VCHIQ_SERVICE_HANDLE_T       *phandle)
-{
-	VCHIQ_STATUS_T status;
-	VCHIQ_STATE_T *state = instance->state;
-	VCHIQ_SERVICE_T *service = NULL;
-	int srvstate;
-
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p) called", __func__, instance);
-
-	*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-
-	srvstate = vchiq_is_connected(instance)
-		? VCHIQ_SRVSTATE_LISTENING
-		: VCHIQ_SRVSTATE_HIDDEN;
-
-	service = vchiq_add_service_internal(
-		state,
-		params,
-		srvstate,
-		instance,
-		NULL);
-
-	if (service) {
-		*phandle = service->handle;
-		status = VCHIQ_SUCCESS;
-	} else
-		status = VCHIQ_ERROR;
-
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p): returning %d", __func__, instance, status);
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_add_service);
-
-VCHIQ_STATUS_T vchiq_open_service(
-	VCHIQ_INSTANCE_T              instance,
-	const VCHIQ_SERVICE_PARAMS_T *params,
-	VCHIQ_SERVICE_HANDLE_T       *phandle)
-{
-	VCHIQ_STATUS_T   status = VCHIQ_ERROR;
-	VCHIQ_STATE_T   *state = instance->state;
-	VCHIQ_SERVICE_T *service = NULL;
-
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p) called", __func__, instance);
-
-	*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-
-	if (!vchiq_is_connected(instance))
-		goto failed;
-
-	service = vchiq_add_service_internal(state,
-		params,
-		VCHIQ_SRVSTATE_OPENING,
-		instance,
-		NULL);
-
-	if (service) {
-		*phandle = service->handle;
-		status = vchiq_open_service_internal(service, current->pid);
-		if (status != VCHIQ_SUCCESS) {
-			vchiq_remove_service(service->handle);
-			*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-		}
-	}
-
-failed:
-	vchiq_log_trace(vchiq_core_log_level,
-		"%s(%p): returning %d", __func__, instance, status);
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_open_service);
-
-VCHIQ_STATUS_T
-vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
-	const void *data, unsigned int size, void *userdata)
-{
-	return vchiq_bulk_transfer(handle,
-		VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
-		VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
-}
-EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
-
-VCHIQ_STATUS_T
-vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-	unsigned int size, void *userdata)
-{
-	return vchiq_bulk_transfer(handle,
-		VCHI_MEM_HANDLE_INVALID, data, size, userdata,
-		VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
-}
-EXPORT_SYMBOL(vchiq_queue_bulk_receive);
-
-VCHIQ_STATUS_T
-vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
-	unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-{
-	VCHIQ_STATUS_T status;
-
-	switch (mode) {
-	case VCHIQ_BULK_MODE_NOCALLBACK:
-	case VCHIQ_BULK_MODE_CALLBACK:
-		status = vchiq_bulk_transfer(handle,
-			VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
-			mode, VCHIQ_BULK_TRANSMIT);
-		break;
-	case VCHIQ_BULK_MODE_BLOCKING:
-		status = vchiq_blocking_bulk_transfer(handle,
-			(void *)data, size, VCHIQ_BULK_TRANSMIT);
-		break;
-	default:
-		return VCHIQ_ERROR;
-	}
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_bulk_transmit);
-
-VCHIQ_STATUS_T
-vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-	unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-{
-	VCHIQ_STATUS_T status;
-
-	switch (mode) {
-	case VCHIQ_BULK_MODE_NOCALLBACK:
-	case VCHIQ_BULK_MODE_CALLBACK:
-		status = vchiq_bulk_transfer(handle,
-			VCHI_MEM_HANDLE_INVALID, data, size, userdata,
-			mode, VCHIQ_BULK_RECEIVE);
-		break;
-	case VCHIQ_BULK_MODE_BLOCKING:
-		status = vchiq_blocking_bulk_transfer(handle,
-			(void *)data, size, VCHIQ_BULK_RECEIVE);
-		break;
-	default:
-		return VCHIQ_ERROR;
-	}
-
-	return status;
-}
-EXPORT_SYMBOL(vchiq_bulk_receive);
-
-static VCHIQ_STATUS_T
-vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
-	unsigned int size, VCHIQ_BULK_DIR_T dir)
-{
-	VCHIQ_INSTANCE_T instance;
-	VCHIQ_SERVICE_T *service;
-	VCHIQ_STATUS_T status;
-	struct bulk_waiter_node *waiter = NULL;
-	struct list_head *pos;
-
-	service = find_service_by_handle(handle);
-	if (!service)
-		return VCHIQ_ERROR;
-
-	instance = service->instance;
-
-	unlock_service(service);
-
-	mutex_lock(&instance->bulk_waiter_list_mutex);
-	list_for_each(pos, &instance->bulk_waiter_list) {
-		if (list_entry(pos, struct bulk_waiter_node,
-				list)->pid == current->pid) {
-			waiter = list_entry(pos,
-				struct bulk_waiter_node,
-				list);
-			list_del(pos);
-			break;
-		}
-	}
-	mutex_unlock(&instance->bulk_waiter_list_mutex);
-
-	if (waiter) {
-		VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-
-		if (bulk) {
-			/* This thread has an outstanding bulk transfer. */
-			if ((bulk->data != data) ||
-				(bulk->size != size)) {
-				/* This is not a retry of the previous one.
-				 * Cancel the signal when the transfer
-				 * completes.
-				 */
-				spin_lock(&bulk_waiter_spinlock);
-				bulk->userdata = NULL;
-				spin_unlock(&bulk_waiter_spinlock);
-			}
-		}
-	}
-
-	if (!waiter) {
-		waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
-		if (!waiter) {
-			vchiq_log_error(vchiq_core_log_level,
-				"%s - out of memory", __func__);
-			return VCHIQ_ERROR;
-		}
-	}
-
-	status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
-		data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
-		dir);
-	if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
-		!waiter->bulk_waiter.bulk) {
-		VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-
-		if (bulk) {
-			/* Cancel the signal when the transfer
-			 * completes.
-			 */
-			spin_lock(&bulk_waiter_spinlock);
-			bulk->userdata = NULL;
-			spin_unlock(&bulk_waiter_spinlock);
-		}
-		kfree(waiter);
-	} else {
-		waiter->pid = current->pid;
-		mutex_lock(&instance->bulk_waiter_list_mutex);
-		list_add(&waiter->list, &instance->bulk_waiter_list);
-		mutex_unlock(&instance->bulk_waiter_list_mutex);
-		vchiq_log_info(vchiq_arm_log_level,
-				"saved bulk_waiter %pK for pid %d",
-				waiter, current->pid);
-	}
-
-	return status;
-}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
deleted file mode 100644
index c233b866725b..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef VCHIQ_MEMDRV_H
-#define VCHIQ_MEMDRV_H
-
-/* ---- Include Files ----------------------------------------------------- */
-
-#include <linux/kernel.h>
-#include "vchiq_if.h"
-
-/* ---- Constants and Types ---------------------------------------------- */
-
-/* ---- Variable Externs ------------------------------------------------- */
-
-/* ---- Function Prototypes ---------------------------------------------- */
-
-VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
-
-VCHIQ_STATUS_T vchiq_userdrv_create_instance(
-	const VCHIQ_PLATFORM_DATA_T * platform_data);
-
-VCHIQ_STATUS_T vchiq_userdrv_suspend(
-	const VCHIQ_PLATFORM_DATA_T * platform_data);
-
-VCHIQ_STATUS_T vchiq_userdrv_resume(
-	const VCHIQ_PLATFORM_DATA_T * platform_data);
-
-#endif
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c
deleted file mode 100644
index 994b81798134..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "vchiq_build_info.h"
-#include <linux/broadcom/vc_debug_sym.h>
-
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_hostname, "dc4-arm-01");
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_version, "9245b4c35b99b3870e1f7dc598c5692b3c66a6f0 (tainted)");
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_time,    __TIME__);
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_date,    __DATE__);
-
-const char *vchiq_get_build_hostname(void)
-{
-   return vchiq_build_hostname;
-}
-
-const char *vchiq_get_build_version(void)
-{
-   return vchiq_build_version;
-}
-
-const char *vchiq_get_build_date(void)
-{
-   return vchiq_build_date;
-}
-
-const char *vchiq_get_build_time(void)
-{
-   return vchiq_build_time;
-}
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 273176386a51..5bbc56f8779e 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -194,9 +194,6 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
 		if (vnt_rx_data(priv, rcb, urb->actual_length)) {
 			rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
 			if (!rcb->skb) {
-				dev_dbg(&priv->usb->dev,
-					"Failed to re-alloc rx skb\n");
-
 				rcb->in_use = false;
 				return;
 			}
diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c
index e98fc8e93011..2e2187b83156 100644
--- a/drivers/staging/wilc1000/coreconfigurator.c
+++ b/drivers/staging/wilc1000/coreconfigurator.c
@@ -320,8 +320,8 @@ s32 wilc_parse_network_info(u8 *msg_buffer,
 		get_ssid(msa, network_info->ssid, &network_info->ssid_len);
 		get_BSSID(msa, network_info->bssid);
 
-		network_info->ch = get_current_channel_802_11n(msa,
-							rx_len + FCS_LEN);
+		network_info->ch = get_current_channel_802_11n(msa, rx_len
+							       + FCS_LEN);
 
 		index = MAC_HDR_LEN + TIME_STAMP_LEN;
 
diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c
index 358354b3a2b4..5e01f6edfd54 100644
--- a/drivers/staging/wilc1000/host_interface.c
+++ b/drivers/staging/wilc1000/host_interface.c
@@ -265,9 +265,9 @@ static struct wilc_vif *join_req_vif;
 #define FLUSHED_JOIN_REQ 1
 #define FLUSHED_BYTE_POS 79
 
-static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo);
+static void *host_int_parse_join_bss_param(struct network_info *info);
 static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx);
-static s32 Handle_ScanDone(struct wilc_vif *vif, enum scan_event enuEvent);
+static s32 handle_scan_done(struct wilc_vif *vif, enum scan_event enuEvent);
 static void host_if_work(struct work_struct *work);
 
 /*!
@@ -847,7 +847,7 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
 ERRORHANDLER:
 	if (result) {
 		del_timer(&hif_drv->scan_timer);
-		Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
+		handle_scan_done(vif, SCAN_EVENT_ABORTED);
 	}
 
 	kfree(scan_info->ch_freq_list);
@@ -863,8 +863,8 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
 	return result;
 }
 
-static s32 Handle_ScanDone(struct wilc_vif *vif,
-			   enum scan_event enuEvent)
+static s32 handle_scan_done(struct wilc_vif *vif,
+			    enum scan_event enuEvent)
 {
 	s32 result = 0;
 	u8 u8abort_running_scan;
@@ -906,9 +906,9 @@ static s32 Handle_Connect(struct wilc_vif *vif,
 			  struct connect_attr *pstrHostIFconnectAttr)
 {
 	s32 result = 0;
-	struct wid strWIDList[8];
-	u32 u32WidsCount = 0, dummyval = 0;
-	u8 *pu8CurrByte = NULL;
+	struct wid wid_list[8];
+	u32 wid_cnt = 0, dummyval = 0;
+	u8 *cur_byte = NULL;
 	struct join_bss_param *ptstrJoinBssParam;
 	struct host_if_drv *hif_drv = vif->hif_drv;
 
@@ -952,30 +952,30 @@ static s32 Handle_Connect(struct wilc_vif *vif,
 	hif_drv->usr_conn_req.conn_result = pstrHostIFconnectAttr->result;
 	hif_drv->usr_conn_req.arg = pstrHostIFconnectAttr->arg;
 
-	strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT;
-	strWIDList[u32WidsCount].type = WID_INT;
-	strWIDList[u32WidsCount].size = sizeof(u32);
-	strWIDList[u32WidsCount].val = (s8 *)(&(dummyval));
-	u32WidsCount++;
+	wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+	wid_list[wid_cnt].type = WID_INT;
+	wid_list[wid_cnt].size = sizeof(u32);
+	wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+	wid_cnt++;
 
-	strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT;
-	strWIDList[u32WidsCount].type = WID_INT;
-	strWIDList[u32WidsCount].size = sizeof(u32);
-	strWIDList[u32WidsCount].val = (s8 *)(&(dummyval));
-	u32WidsCount++;
+	wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+	wid_list[wid_cnt].type = WID_INT;
+	wid_list[wid_cnt].size = sizeof(u32);
+	wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+	wid_cnt++;
 
-	strWIDList[u32WidsCount].id = WID_FAILED_COUNT;
-	strWIDList[u32WidsCount].type = WID_INT;
-	strWIDList[u32WidsCount].size = sizeof(u32);
-	strWIDList[u32WidsCount].val = (s8 *)(&(dummyval));
-	u32WidsCount++;
+	wid_list[wid_cnt].id = WID_FAILED_COUNT;
+	wid_list[wid_cnt].type = WID_INT;
+	wid_list[wid_cnt].size = sizeof(u32);
+	wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+	wid_cnt++;
 
 	{
-		strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_ASSOCIATE;
-		strWIDList[u32WidsCount].type = WID_BIN_DATA;
-		strWIDList[u32WidsCount].val = hif_drv->usr_conn_req.ies;
-		strWIDList[u32WidsCount].size = hif_drv->usr_conn_req.ies_len;
-		u32WidsCount++;
+		wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
+		wid_list[wid_cnt].type = WID_BIN_DATA;
+		wid_list[wid_cnt].val = hif_drv->usr_conn_req.ies;
+		wid_list[wid_cnt].size = hif_drv->usr_conn_req.ies_len;
+		wid_cnt++;
 
 		if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
 			info_element_size = hif_drv->usr_conn_req.ies_len;
@@ -984,122 +984,122 @@ static s32 Handle_Connect(struct wilc_vif *vif,
 			       info_element_size);
 		}
 	}
-	strWIDList[u32WidsCount].id = (u16)WID_11I_MODE;
-	strWIDList[u32WidsCount].type = WID_CHAR;
-	strWIDList[u32WidsCount].size = sizeof(char);
-	strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.security;
-	u32WidsCount++;
+	wid_list[wid_cnt].id = (u16)WID_11I_MODE;
+	wid_list[wid_cnt].type = WID_CHAR;
+	wid_list[wid_cnt].size = sizeof(char);
+	wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.security;
+	wid_cnt++;
 
 	if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7))
 		mode_11i = hif_drv->usr_conn_req.security;
 
-	strWIDList[u32WidsCount].id = (u16)WID_AUTH_TYPE;
-	strWIDList[u32WidsCount].type = WID_CHAR;
-	strWIDList[u32WidsCount].size = sizeof(char);
-	strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.auth_type;
-	u32WidsCount++;
+	wid_list[wid_cnt].id = (u16)WID_AUTH_TYPE;
+	wid_list[wid_cnt].type = WID_CHAR;
+	wid_list[wid_cnt].size = sizeof(char);
+	wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.auth_type;
+	wid_cnt++;
 
 	if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7))
 		auth_type = (u8)hif_drv->usr_conn_req.auth_type;
 
-	strWIDList[u32WidsCount].id = (u16)WID_JOIN_REQ_EXTENDED;
-	strWIDList[u32WidsCount].type = WID_STR;
-	strWIDList[u32WidsCount].size = 112;
-	strWIDList[u32WidsCount].val = kmalloc(strWIDList[u32WidsCount].size, GFP_KERNEL);
+	wid_list[wid_cnt].id = (u16)WID_JOIN_REQ_EXTENDED;
+	wid_list[wid_cnt].type = WID_STR;
+	wid_list[wid_cnt].size = 112;
+	wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL);
 
 	if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
-		join_req_size = strWIDList[u32WidsCount].size;
+		join_req_size = wid_list[wid_cnt].size;
 		join_req = kmalloc(join_req_size, GFP_KERNEL);
 	}
-	if (!strWIDList[u32WidsCount].val) {
+	if (!wid_list[wid_cnt].val) {
 		result = -EFAULT;
 		goto ERRORHANDLER;
 	}
 
-	pu8CurrByte = strWIDList[u32WidsCount].val;
+	cur_byte = wid_list[wid_cnt].val;
 
 	if (pstrHostIFconnectAttr->ssid) {
-		memcpy(pu8CurrByte, pstrHostIFconnectAttr->ssid, pstrHostIFconnectAttr->ssid_len);
-		pu8CurrByte[pstrHostIFconnectAttr->ssid_len] = '\0';
+		memcpy(cur_byte, pstrHostIFconnectAttr->ssid, pstrHostIFconnectAttr->ssid_len);
+		cur_byte[pstrHostIFconnectAttr->ssid_len] = '\0';
 	}
-	pu8CurrByte += MAX_SSID_LEN;
-	*(pu8CurrByte++) = INFRASTRUCTURE;
+	cur_byte += MAX_SSID_LEN;
+	*(cur_byte++) = INFRASTRUCTURE;
 
 	if (pstrHostIFconnectAttr->ch >= 1 && pstrHostIFconnectAttr->ch <= 14) {
-		*(pu8CurrByte++) = pstrHostIFconnectAttr->ch;
+		*(cur_byte++) = pstrHostIFconnectAttr->ch;
 	} else {
 		netdev_err(vif->ndev, "Channel out of range\n");
-		*(pu8CurrByte++) = 0xFF;
+		*(cur_byte++) = 0xFF;
 	}
-	*(pu8CurrByte++)  = (ptstrJoinBssParam->cap_info) & 0xFF;
-	*(pu8CurrByte++)  = ((ptstrJoinBssParam->cap_info) >> 8) & 0xFF;
+	*(cur_byte++)  = (ptstrJoinBssParam->cap_info) & 0xFF;
+	*(cur_byte++)  = ((ptstrJoinBssParam->cap_info) >> 8) & 0xFF;
 
 	if (pstrHostIFconnectAttr->bssid)
-		memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6);
-	pu8CurrByte += 6;
+		memcpy(cur_byte, pstrHostIFconnectAttr->bssid, 6);
+	cur_byte += 6;
 
 	if (pstrHostIFconnectAttr->bssid)
-		memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6);
-	pu8CurrByte += 6;
+		memcpy(cur_byte, pstrHostIFconnectAttr->bssid, 6);
+	cur_byte += 6;
 
-	*(pu8CurrByte++)  = (ptstrJoinBssParam->beacon_period) & 0xFF;
-	*(pu8CurrByte++)  = ((ptstrJoinBssParam->beacon_period) >> 8) & 0xFF;
-	*(pu8CurrByte++)  =  ptstrJoinBssParam->dtim_period;
+	*(cur_byte++)  = (ptstrJoinBssParam->beacon_period) & 0xFF;
+	*(cur_byte++)  = ((ptstrJoinBssParam->beacon_period) >> 8) & 0xFF;
+	*(cur_byte++)  =  ptstrJoinBssParam->dtim_period;
 
-	memcpy(pu8CurrByte, ptstrJoinBssParam->supp_rates, MAX_RATES_SUPPORTED + 1);
-	pu8CurrByte += (MAX_RATES_SUPPORTED + 1);
+	memcpy(cur_byte, ptstrJoinBssParam->supp_rates, MAX_RATES_SUPPORTED + 1);
+	cur_byte += (MAX_RATES_SUPPORTED + 1);
 
-	*(pu8CurrByte++)  =  ptstrJoinBssParam->wmm_cap;
-	*(pu8CurrByte++)  = ptstrJoinBssParam->uapsd_cap;
+	*(cur_byte++)  =  ptstrJoinBssParam->wmm_cap;
+	*(cur_byte++)  = ptstrJoinBssParam->uapsd_cap;
 
-	*(pu8CurrByte++)  = ptstrJoinBssParam->ht_capable;
+	*(cur_byte++)  = ptstrJoinBssParam->ht_capable;
 	hif_drv->usr_conn_req.ht_capable = ptstrJoinBssParam->ht_capable;
 
-	*(pu8CurrByte++)  =  ptstrJoinBssParam->rsn_found;
-	*(pu8CurrByte++)  =  ptstrJoinBssParam->rsn_grp_policy;
-	*(pu8CurrByte++) =  ptstrJoinBssParam->mode_802_11i;
+	*(cur_byte++)  =  ptstrJoinBssParam->rsn_found;
+	*(cur_byte++)  =  ptstrJoinBssParam->rsn_grp_policy;
+	*(cur_byte++) =  ptstrJoinBssParam->mode_802_11i;
 
-	memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_pcip_policy, sizeof(ptstrJoinBssParam->rsn_pcip_policy));
-	pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_pcip_policy);
+	memcpy(cur_byte, ptstrJoinBssParam->rsn_pcip_policy, sizeof(ptstrJoinBssParam->rsn_pcip_policy));
+	cur_byte += sizeof(ptstrJoinBssParam->rsn_pcip_policy);
 
-	memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_auth_policy, sizeof(ptstrJoinBssParam->rsn_auth_policy));
-	pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_auth_policy);
+	memcpy(cur_byte, ptstrJoinBssParam->rsn_auth_policy, sizeof(ptstrJoinBssParam->rsn_auth_policy));
+	cur_byte += sizeof(ptstrJoinBssParam->rsn_auth_policy);
 
-	memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_cap, sizeof(ptstrJoinBssParam->rsn_cap));
-	pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_cap);
+	memcpy(cur_byte, ptstrJoinBssParam->rsn_cap, sizeof(ptstrJoinBssParam->rsn_cap));
+	cur_byte += sizeof(ptstrJoinBssParam->rsn_cap);
 
-	*(pu8CurrByte++) = REAL_JOIN_REQ;
-	*(pu8CurrByte++) = ptstrJoinBssParam->noa_enabled;
+	*(cur_byte++) = REAL_JOIN_REQ;
+	*(cur_byte++) = ptstrJoinBssParam->noa_enabled;
 
 	if (ptstrJoinBssParam->noa_enabled) {
-		*(pu8CurrByte++) = (ptstrJoinBssParam->tsf) & 0xFF;
-		*(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 8) & 0xFF;
-		*(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 16) & 0xFF;
-		*(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 24) & 0xFF;
+		*(cur_byte++) = (ptstrJoinBssParam->tsf) & 0xFF;
+		*(cur_byte++) = ((ptstrJoinBssParam->tsf) >> 8) & 0xFF;
+		*(cur_byte++) = ((ptstrJoinBssParam->tsf) >> 16) & 0xFF;
+		*(cur_byte++) = ((ptstrJoinBssParam->tsf) >> 24) & 0xFF;
 
-		*(pu8CurrByte++) = ptstrJoinBssParam->opp_enabled;
-		*(pu8CurrByte++) = ptstrJoinBssParam->idx;
+		*(cur_byte++) = ptstrJoinBssParam->opp_enabled;
+		*(cur_byte++) = ptstrJoinBssParam->idx;
 
 		if (ptstrJoinBssParam->opp_enabled)
-			*(pu8CurrByte++) = ptstrJoinBssParam->ct_window;
+			*(cur_byte++) = ptstrJoinBssParam->ct_window;
 
-		*(pu8CurrByte++) = ptstrJoinBssParam->cnt;
+		*(cur_byte++) = ptstrJoinBssParam->cnt;
 
-		memcpy(pu8CurrByte, ptstrJoinBssParam->duration, sizeof(ptstrJoinBssParam->duration));
-		pu8CurrByte += sizeof(ptstrJoinBssParam->duration);
+		memcpy(cur_byte, ptstrJoinBssParam->duration, sizeof(ptstrJoinBssParam->duration));
+		cur_byte += sizeof(ptstrJoinBssParam->duration);
 
-		memcpy(pu8CurrByte, ptstrJoinBssParam->interval, sizeof(ptstrJoinBssParam->interval));
-		pu8CurrByte += sizeof(ptstrJoinBssParam->interval);
+		memcpy(cur_byte, ptstrJoinBssParam->interval, sizeof(ptstrJoinBssParam->interval));
+		cur_byte += sizeof(ptstrJoinBssParam->interval);
 
-		memcpy(pu8CurrByte, ptstrJoinBssParam->start_time, sizeof(ptstrJoinBssParam->start_time));
-		pu8CurrByte += sizeof(ptstrJoinBssParam->start_time);
+		memcpy(cur_byte, ptstrJoinBssParam->start_time, sizeof(ptstrJoinBssParam->start_time));
+		cur_byte += sizeof(ptstrJoinBssParam->start_time);
 	}
 
-	pu8CurrByte = strWIDList[u32WidsCount].val;
-	u32WidsCount++;
+	cur_byte = wid_list[wid_cnt].val;
+	wid_cnt++;
 
 	if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
-		memcpy(join_req, pu8CurrByte, join_req_size);
+		memcpy(join_req, cur_byte, join_req_size);
 		join_req_vif = vif;
 	}
 
@@ -1107,8 +1107,8 @@ static s32 Handle_Connect(struct wilc_vif *vif,
 		memcpy(wilc_connected_ssid,
 		       pstrHostIFconnectAttr->bssid, ETH_ALEN);
 
-	result = wilc_send_config_pkt(vif, SET_CFG, strWIDList,
-				      u32WidsCount,
+	result = wilc_send_config_pkt(vif, SET_CFG, wid_list,
+				      wid_cnt,
 				      wilc_get_vif_idx(vif));
 	if (result) {
 		netdev_err(vif->ndev, "failed to send config packet\n");
@@ -1161,11 +1161,11 @@ static s32 Handle_Connect(struct wilc_vif *vif,
 	kfree(pstrHostIFconnectAttr->ies);
 	pstrHostIFconnectAttr->ies = NULL;
 
-	kfree(pu8CurrByte);
+	kfree(cur_byte);
 	return result;
 }
 
-static s32 Handle_ConnectTimeout(struct wilc_vif *vif)
+static s32 handle_connect_timeout(struct wilc_vif *vif)
 {
 	s32 result = 0;
 	struct connect_info strConnectInfo;
@@ -1288,7 +1288,7 @@ static s32 Handle_RcvdNtwrkInfo(struct wilc_vif *vif,
 				hif_drv->usr_scan_req.rcvd_ch_cnt++;
 
 				pstrNetworkInfo->new_network = true;
-				pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo);
+				pJoinParams = host_int_parse_join_bss_param(pstrNetworkInfo);
 
 				hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
 								  hif_drv->usr_scan_req.arg,
@@ -1467,7 +1467,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct wilc_vif *vif,
 
 			if (hif_drv->usr_scan_req.scan_result) {
 				del_timer(&hif_drv->scan_timer);
-				Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
+				handle_scan_done(vif, SCAN_EVENT_ABORTED);
 			}
 
 			strDisconnectNotifInfo.reason = 0;
@@ -1515,7 +1515,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct wilc_vif *vif,
 			   (hif_drv->usr_scan_req.scan_result)) {
 			del_timer(&hif_drv->scan_timer);
 			if (hif_drv->usr_scan_req.scan_result)
-				Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
+				handle_scan_done(vif, SCAN_EVENT_ABORTED);
 		}
 	}
 
@@ -1525,12 +1525,12 @@ static s32 Handle_RcvdGnrlAsyncInfo(struct wilc_vif *vif,
 	return result;
 }
 
-static int Handle_Key(struct wilc_vif *vif,
+static int handle_key(struct wilc_vif *vif,
 		      struct key_attr *pstrHostIFkeyAttr)
 {
 	s32 result = 0;
 	struct wid wid;
-	struct wid strWIDList[5];
+	struct wid wid_list[5];
 	u8 i;
 	u8 *pu8keybuf;
 	s8 s8idxarray[1];
@@ -1541,15 +1541,15 @@ static int Handle_Key(struct wilc_vif *vif,
 	case WEP:
 
 		if (pstrHostIFkeyAttr->action & ADDKEY_AP) {
-			strWIDList[0].id = (u16)WID_11I_MODE;
-			strWIDList[0].type = WID_CHAR;
-			strWIDList[0].size = sizeof(char);
-			strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.mode;
+			wid_list[0].id = (u16)WID_11I_MODE;
+			wid_list[0].type = WID_CHAR;
+			wid_list[0].size = sizeof(char);
+			wid_list[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.mode;
 
-			strWIDList[1].id = WID_AUTH_TYPE;
-			strWIDList[1].type = WID_CHAR;
-			strWIDList[1].size = sizeof(char);
-			strWIDList[1].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.auth_type;
+			wid_list[1].id = WID_AUTH_TYPE;
+			wid_list[1].type = WID_CHAR;
+			wid_list[1].size = sizeof(char);
+			wid_list[1].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.auth_type;
 
 			pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2,
 					    GFP_KERNEL);
@@ -1564,13 +1564,13 @@ static int Handle_Key(struct wilc_vif *vif,
 
 			kfree(pstrHostIFkeyAttr->attr.wep.key);
 
-			strWIDList[2].id = (u16)WID_WEP_KEY_VALUE;
-			strWIDList[2].type = WID_STR;
-			strWIDList[2].size = pstrHostIFkeyAttr->attr.wep.key_len + 2;
-			strWIDList[2].val = (s8 *)pu8keybuf;
+			wid_list[2].id = (u16)WID_WEP_KEY_VALUE;
+			wid_list[2].type = WID_STR;
+			wid_list[2].size = pstrHostIFkeyAttr->attr.wep.key_len + 2;
+			wid_list[2].val = (s8 *)pu8keybuf;
 
 			result = wilc_send_config_pkt(vif, SET_CFG,
-						      strWIDList, 3,
+						      wid_list, 3,
 						      wilc_get_vif_idx(vif));
 			kfree(pu8keybuf);
 		} else if (pstrHostIFkeyAttr->action & ADDKEY) {
@@ -1632,18 +1632,18 @@ static int Handle_Key(struct wilc_vif *vif,
 			memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key,
 			       pstrHostIFkeyAttr->attr.wpa.key_len);
 
-			strWIDList[0].id = (u16)WID_11I_MODE;
-			strWIDList[0].type = WID_CHAR;
-			strWIDList[0].size = sizeof(char);
-			strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode;
+			wid_list[0].id = (u16)WID_11I_MODE;
+			wid_list[0].type = WID_CHAR;
+			wid_list[0].size = sizeof(char);
+			wid_list[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode;
 
-			strWIDList[1].id = (u16)WID_ADD_RX_GTK;
-			strWIDList[1].type = WID_STR;
-			strWIDList[1].val = (s8 *)pu8keybuf;
-			strWIDList[1].size = RX_MIC_KEY_MSG_LEN;
+			wid_list[1].id = (u16)WID_ADD_RX_GTK;
+			wid_list[1].type = WID_STR;
+			wid_list[1].val = (s8 *)pu8keybuf;
+			wid_list[1].size = RX_MIC_KEY_MSG_LEN;
 
 			result = wilc_send_config_pkt(vif, SET_CFG,
-						      strWIDList, 2,
+						      wid_list, 2,
 						      wilc_get_vif_idx(vif));
 
 			kfree(pu8keybuf);
@@ -1700,18 +1700,18 @@ static int Handle_Key(struct wilc_vif *vif,
 			memcpy(pu8keybuf + 8, pstrHostIFkeyAttr->attr.wpa.key,
 			       pstrHostIFkeyAttr->attr.wpa.key_len);
 
-			strWIDList[0].id = (u16)WID_11I_MODE;
-			strWIDList[0].type = WID_CHAR;
-			strWIDList[0].size = sizeof(char);
-			strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode;
+			wid_list[0].id = (u16)WID_11I_MODE;
+			wid_list[0].type = WID_CHAR;
+			wid_list[0].size = sizeof(char);
+			wid_list[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode;
 
-			strWIDList[1].id = (u16)WID_ADD_PTK;
-			strWIDList[1].type = WID_STR;
-			strWIDList[1].val = (s8 *)pu8keybuf;
-			strWIDList[1].size = PTK_KEY_MSG_LEN + 1;
+			wid_list[1].id = (u16)WID_ADD_PTK;
+			wid_list[1].type = WID_STR;
+			wid_list[1].val = (s8 *)pu8keybuf;
+			wid_list[1].size = PTK_KEY_MSG_LEN + 1;
 
 			result = wilc_send_config_pkt(vif, SET_CFG,
-						      strWIDList, 2,
+						      wid_list, 2,
 						      wilc_get_vif_idx(vif));
 			kfree(pu8keybuf);
 			complete(&hif_drv->comp_test_key_block);
@@ -1892,41 +1892,41 @@ static void Handle_GetRssi(struct wilc_vif *vif)
 static s32 Handle_GetStatistics(struct wilc_vif *vif,
 				struct rf_info *pstrStatistics)
 {
-	struct wid strWIDList[5];
-	u32 u32WidsCount = 0, result = 0;
-
-	strWIDList[u32WidsCount].id = WID_LINKSPEED;
-	strWIDList[u32WidsCount].type = WID_CHAR;
-	strWIDList[u32WidsCount].size = sizeof(char);
-	strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->link_speed;
-	u32WidsCount++;
-
-	strWIDList[u32WidsCount].id = WID_RSSI;
-	strWIDList[u32WidsCount].type = WID_CHAR;
-	strWIDList[u32WidsCount].size = sizeof(char);
-	strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rssi;
-	u32WidsCount++;
-
-	strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT;
-	strWIDList[u32WidsCount].type = WID_INT;
-	strWIDList[u32WidsCount].size = sizeof(u32);
-	strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_cnt;
-	u32WidsCount++;
-
-	strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT;
-	strWIDList[u32WidsCount].type = WID_INT;
-	strWIDList[u32WidsCount].size = sizeof(u32);
-	strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rx_cnt;
-	u32WidsCount++;
-
-	strWIDList[u32WidsCount].id = WID_FAILED_COUNT;
-	strWIDList[u32WidsCount].type = WID_INT;
-	strWIDList[u32WidsCount].size = sizeof(u32);
-	strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_fail_cnt;
-	u32WidsCount++;
-
-	result = wilc_send_config_pkt(vif, GET_CFG, strWIDList,
-				      u32WidsCount,
+	struct wid wid_list[5];
+	u32 wid_cnt = 0, result = 0;
+
+	wid_list[wid_cnt].id = WID_LINKSPEED;
+	wid_list[wid_cnt].type = WID_CHAR;
+	wid_list[wid_cnt].size = sizeof(char);
+	wid_list[wid_cnt].val = (s8 *)&pstrStatistics->link_speed;
+	wid_cnt++;
+
+	wid_list[wid_cnt].id = WID_RSSI;
+	wid_list[wid_cnt].type = WID_CHAR;
+	wid_list[wid_cnt].size = sizeof(char);
+	wid_list[wid_cnt].val = (s8 *)&pstrStatistics->rssi;
+	wid_cnt++;
+
+	wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+	wid_list[wid_cnt].type = WID_INT;
+	wid_list[wid_cnt].size = sizeof(u32);
+	wid_list[wid_cnt].val = (s8 *)&pstrStatistics->tx_cnt;
+	wid_cnt++;
+
+	wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+	wid_list[wid_cnt].type = WID_INT;
+	wid_list[wid_cnt].size = sizeof(u32);
+	wid_list[wid_cnt].val = (s8 *)&pstrStatistics->rx_cnt;
+	wid_cnt++;
+
+	wid_list[wid_cnt].id = WID_FAILED_COUNT;
+	wid_list[wid_cnt].type = WID_INT;
+	wid_list[wid_cnt].size = sizeof(u32);
+	wid_list[wid_cnt].val = (s8 *)&pstrStatistics->tx_fail_cnt;
+	wid_cnt++;
+
+	result = wilc_send_config_pkt(vif, GET_CFG, wid_list,
+				      wid_cnt,
 				      wilc_get_vif_idx(vif));
 
 	if (result)
@@ -1992,7 +1992,7 @@ static void Handle_AddBeacon(struct wilc_vif *vif,
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_ADD_BEACON;
 	wid.type = WID_BIN;
@@ -2001,33 +2001,33 @@ static void Handle_AddBeacon(struct wilc_vif *vif,
 	if (!wid.val)
 		goto ERRORHANDLER;
 
-	pu8CurrByte = wid.val;
-	*pu8CurrByte++ = (pstrSetBeaconParam->interval & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 8) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 16) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 24) & 0xFF);
+	cur_byte = wid.val;
+	*cur_byte++ = (pstrSetBeaconParam->interval & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->interval >> 8) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->interval >> 16) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->interval >> 24) & 0xFF);
 
-	*pu8CurrByte++ = (pstrSetBeaconParam->dtim_period & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 8) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 16) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 24) & 0xFF);
+	*cur_byte++ = (pstrSetBeaconParam->dtim_period & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->dtim_period >> 8) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->dtim_period >> 16) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->dtim_period >> 24) & 0xFF);
 
-	*pu8CurrByte++ = (pstrSetBeaconParam->head_len & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 8) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 16) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 24) & 0xFF);
+	*cur_byte++ = (pstrSetBeaconParam->head_len & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->head_len >> 8) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->head_len >> 16) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->head_len >> 24) & 0xFF);
 
-	memcpy(pu8CurrByte, pstrSetBeaconParam->head, pstrSetBeaconParam->head_len);
-	pu8CurrByte += pstrSetBeaconParam->head_len;
+	memcpy(cur_byte, pstrSetBeaconParam->head, pstrSetBeaconParam->head_len);
+	cur_byte += pstrSetBeaconParam->head_len;
 
-	*pu8CurrByte++ = (pstrSetBeaconParam->tail_len & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 8) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 16) & 0xFF);
-	*pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 24) & 0xFF);
+	*cur_byte++ = (pstrSetBeaconParam->tail_len & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->tail_len >> 8) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->tail_len >> 16) & 0xFF);
+	*cur_byte++ = ((pstrSetBeaconParam->tail_len >> 24) & 0xFF);
 
 	if (pstrSetBeaconParam->tail)
-		memcpy(pu8CurrByte, pstrSetBeaconParam->tail, pstrSetBeaconParam->tail_len);
-	pu8CurrByte += pstrSetBeaconParam->tail_len;
+		memcpy(cur_byte, pstrSetBeaconParam->tail, pstrSetBeaconParam->tail_len);
+	cur_byte += pstrSetBeaconParam->tail_len;
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
 				      wilc_get_vif_idx(vif));
@@ -2044,7 +2044,7 @@ static void Handle_DelBeacon(struct wilc_vif *vif)
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_DEL_BEACON;
 	wid.type = WID_CHAR;
@@ -2054,7 +2054,7 @@ static void Handle_DelBeacon(struct wilc_vif *vif)
 	if (!wid.val)
 		return;
 
-	pu8CurrByte = wid.val;
+	cur_byte = wid.val;
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
 				      wilc_get_vif_idx(vif));
@@ -2065,34 +2065,34 @@ static void Handle_DelBeacon(struct wilc_vif *vif)
 static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer,
 				    struct add_sta_param *pstrStationParam)
 {
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
-	pu8CurrByte = pu8Buffer;
+	cur_byte = pu8Buffer;
 
-	memcpy(pu8CurrByte, pstrStationParam->bssid, ETH_ALEN);
-	pu8CurrByte +=  ETH_ALEN;
+	memcpy(cur_byte, pstrStationParam->bssid, ETH_ALEN);
+	cur_byte +=  ETH_ALEN;
 
-	*pu8CurrByte++ = pstrStationParam->aid & 0xFF;
-	*pu8CurrByte++ = (pstrStationParam->aid >> 8) & 0xFF;
+	*cur_byte++ = pstrStationParam->aid & 0xFF;
+	*cur_byte++ = (pstrStationParam->aid >> 8) & 0xFF;
 
-	*pu8CurrByte++ = pstrStationParam->rates_len;
+	*cur_byte++ = pstrStationParam->rates_len;
 	if (pstrStationParam->rates_len > 0)
-		memcpy(pu8CurrByte, pstrStationParam->rates,
+		memcpy(cur_byte, pstrStationParam->rates,
 		       pstrStationParam->rates_len);
-	pu8CurrByte += pstrStationParam->rates_len;
+	cur_byte += pstrStationParam->rates_len;
 
-	*pu8CurrByte++ = pstrStationParam->ht_supported;
-	memcpy(pu8CurrByte, &pstrStationParam->ht_capa,
+	*cur_byte++ = pstrStationParam->ht_supported;
+	memcpy(cur_byte, &pstrStationParam->ht_capa,
 	       sizeof(struct ieee80211_ht_cap));
-	pu8CurrByte += sizeof(struct ieee80211_ht_cap);
+	cur_byte += sizeof(struct ieee80211_ht_cap);
 
-	*pu8CurrByte++ = pstrStationParam->flags_mask & 0xFF;
-	*pu8CurrByte++ = (pstrStationParam->flags_mask >> 8) & 0xFF;
+	*cur_byte++ = pstrStationParam->flags_mask & 0xFF;
+	*cur_byte++ = (pstrStationParam->flags_mask >> 8) & 0xFF;
 
-	*pu8CurrByte++ = pstrStationParam->flags_set & 0xFF;
-	*pu8CurrByte++ = (pstrStationParam->flags_set >> 8) & 0xFF;
+	*cur_byte++ = pstrStationParam->flags_set & 0xFF;
+	*cur_byte++ = (pstrStationParam->flags_set >> 8) & 0xFF;
 
-	return pu8CurrByte - pu8Buffer;
+	return cur_byte - pu8Buffer;
 }
 
 static void Handle_AddStation(struct wilc_vif *vif,
@@ -2100,7 +2100,7 @@ static void Handle_AddStation(struct wilc_vif *vif,
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_ADD_STA;
 	wid.type = WID_BIN;
@@ -2110,8 +2110,8 @@ static void Handle_AddStation(struct wilc_vif *vif,
 	if (!wid.val)
 		goto ERRORHANDLER;
 
-	pu8CurrByte = wid.val;
-	pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam);
+	cur_byte = wid.val;
+	cur_byte += WILC_HostIf_PackStaParam(cur_byte, pstrStationParam);
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
 				      wilc_get_vif_idx(vif));
@@ -2123,34 +2123,34 @@ static void Handle_AddStation(struct wilc_vif *vif,
 	kfree(wid.val);
 }
 
-static void Handle_DelAllSta(struct wilc_vif *vif,
-			     struct del_all_sta *pstrDelAllStaParam)
+static void handle_del_all_sta(struct wilc_vif *vif,
+			       struct del_all_sta *param)
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *curr_byte;
 	u8 i;
-	u8 au8Zero_Buff[6] = {0};
+	u8 zero_buff[6] = {0};
 
 	wid.id = (u16)WID_DEL_ALL_STA;
 	wid.type = WID_STR;
-	wid.size = (pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1;
+	wid.size = (param->assoc_sta * ETH_ALEN) + 1;
 
-	wid.val = kmalloc((pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL);
+	wid.val = kmalloc((param->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL);
 	if (!wid.val)
 		goto ERRORHANDLER;
 
-	pu8CurrByte = wid.val;
+	curr_byte = wid.val;
 
-	*(pu8CurrByte++) = pstrDelAllStaParam->assoc_sta;
+	*(curr_byte++) = param->assoc_sta;
 
 	for (i = 0; i < MAX_NUM_STA; i++) {
-		if (memcmp(pstrDelAllStaParam->del_all_sta[i], au8Zero_Buff, ETH_ALEN))
-			memcpy(pu8CurrByte, pstrDelAllStaParam->del_all_sta[i], ETH_ALEN);
+		if (memcmp(param->del_all_sta[i], zero_buff, ETH_ALEN))
+			memcpy(curr_byte, param->del_all_sta[i], ETH_ALEN);
 		else
 			continue;
 
-		pu8CurrByte += ETH_ALEN;
+		curr_byte += ETH_ALEN;
 	}
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -2169,7 +2169,7 @@ static void Handle_DelStation(struct wilc_vif *vif,
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_REMOVE_STA;
 	wid.type = WID_BIN;
@@ -2179,9 +2179,9 @@ static void Handle_DelStation(struct wilc_vif *vif,
 	if (!wid.val)
 		goto ERRORHANDLER;
 
-	pu8CurrByte = wid.val;
+	cur_byte = wid.val;
 
-	ether_addr_copy(pu8CurrByte, pstrDelStaParam->mac_addr);
+	ether_addr_copy(cur_byte, pstrDelStaParam->mac_addr);
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
 				      wilc_get_vif_idx(vif));
@@ -2197,7 +2197,7 @@ static void Handle_EditStation(struct wilc_vif *vif,
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_EDIT_STA;
 	wid.type = WID_BIN;
@@ -2207,8 +2207,8 @@ static void Handle_EditStation(struct wilc_vif *vif,
 	if (!wid.val)
 		goto ERRORHANDLER;
 
-	pu8CurrByte = wid.val;
-	pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam);
+	cur_byte = wid.val;
+	cur_byte += WILC_HostIf_PackStaParam(cur_byte, pstrStationParam);
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
 				      wilc_get_vif_idx(vif));
@@ -2294,7 +2294,7 @@ static int Handle_RegisterFrame(struct wilc_vif *vif,
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_REGISTER_FRAME;
 	wid.type = WID_STR;
@@ -2302,11 +2302,11 @@ static int Handle_RegisterFrame(struct wilc_vif *vif,
 	if (!wid.val)
 		return -ENOMEM;
 
-	pu8CurrByte = wid.val;
+	cur_byte = wid.val;
 
-	*pu8CurrByte++ = pstrHostIfRegisterFrame->reg;
-	*pu8CurrByte++ = pstrHostIfRegisterFrame->reg_id;
-	memcpy(pu8CurrByte, &pstrHostIfRegisterFrame->frame_type, sizeof(u16));
+	*cur_byte++ = pstrHostIfRegisterFrame->reg;
+	*cur_byte++ = pstrHostIfRegisterFrame->reg_id;
+	memcpy(cur_byte, &pstrHostIfRegisterFrame->frame_type, sizeof(u16));
 
 	wid.size = sizeof(u16) + 2;
 
@@ -2410,7 +2410,7 @@ static void Handle_SetMulticastFilter(struct wilc_vif *vif,
 {
 	s32 result = 0;
 	struct wid wid;
-	u8 *pu8CurrByte;
+	u8 *cur_byte;
 
 	wid.id = (u16)WID_SETUP_MULTICAST_FILTER;
 	wid.type = WID_BIN;
@@ -2419,19 +2419,19 @@ static void Handle_SetMulticastFilter(struct wilc_vif *vif,
 	if (!wid.val)
 		goto ERRORHANDLER;
 
-	pu8CurrByte = wid.val;
-	*pu8CurrByte++ = (strHostIfSetMulti->enabled & 0xFF);
-	*pu8CurrByte++ = 0;
-	*pu8CurrByte++ = 0;
-	*pu8CurrByte++ = 0;
+	cur_byte = wid.val;
+	*cur_byte++ = (strHostIfSetMulti->enabled & 0xFF);
+	*cur_byte++ = 0;
+	*cur_byte++ = 0;
+	*cur_byte++ = 0;
 
-	*pu8CurrByte++ = (strHostIfSetMulti->cnt & 0xFF);
-	*pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 8) & 0xFF);
-	*pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 16) & 0xFF);
-	*pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 24) & 0xFF);
+	*cur_byte++ = (strHostIfSetMulti->cnt & 0xFF);
+	*cur_byte++ = ((strHostIfSetMulti->cnt >> 8) & 0xFF);
+	*cur_byte++ = ((strHostIfSetMulti->cnt >> 16) & 0xFF);
+	*cur_byte++ = ((strHostIfSetMulti->cnt >> 24) & 0xFF);
 
 	if ((strHostIfSetMulti->cnt) > 0)
-		memcpy(pu8CurrByte, wilc_multicast_mac_addr_list,
+		memcpy(cur_byte, wilc_multicast_mac_addr_list,
 		       ((strHostIfSetMulti->cnt) * ETH_ALEN));
 
 	result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -2511,7 +2511,7 @@ static void host_if_work(struct work_struct *work)
 		break;
 
 	case HOST_IF_MSG_KEY:
-		Handle_Key(msg->vif, &msg->body.key_info);
+		handle_key(msg->vif, &msg->body.key_info);
 		break;
 
 	case HOST_IF_MSG_CFG_PARAMS:
@@ -2532,7 +2532,7 @@ static void host_if_work(struct work_struct *work)
 		if (!wilc_wlan_get_num_conn_ifcs(wilc))
 			wilc_chip_sleep_manually(wilc);
 
-		Handle_ScanDone(msg->vif, SCAN_EVENT_DONE);
+		handle_scan_done(msg->vif, SCAN_EVENT_DONE);
 
 		if (msg->vif->hif_drv->remain_on_ch_pending)
 			Handle_RemainOnChan(msg->vif,
@@ -2574,11 +2574,11 @@ static void host_if_work(struct work_struct *work)
 		break;
 
 	case HOST_IF_MSG_SCAN_TIMER_FIRED:
-		Handle_ScanDone(msg->vif, SCAN_EVENT_ABORTED);
+		handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
 		break;
 
 	case HOST_IF_MSG_CONNECT_TIMER_FIRED:
-		Handle_ConnectTimeout(msg->vif);
+		handle_connect_timeout(msg->vif);
 		break;
 
 	case HOST_IF_MSG_POWER_MGMT:
@@ -2626,7 +2626,7 @@ static void host_if_work(struct work_struct *work)
 		break;
 
 	case HOST_IF_MSG_DEL_ALL_STA:
-		Handle_DelAllSta(msg->vif, &msg->body.del_all_sta_info);
+		handle_del_all_sta(msg->vif, &msg->body.del_all_sta_info);
 		break;
 
 	case HOST_IF_MSG_SET_TX_POWER:
@@ -3870,152 +3870,152 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled,
 	return result;
 }
 
-static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo)
+static void *host_int_parse_join_bss_param(struct network_info *info)
 {
-	struct join_bss_param *pNewJoinBssParam = NULL;
-	u8 *pu8IEs;
-	u16 u16IEsLen;
+	struct join_bss_param *param = NULL;
+	u8 *ies;
+	u16 ies_len;
 	u16 index = 0;
-	u8 suppRatesNo = 0;
-	u8 extSuppRatesNo;
-	u16 jumpOffset;
-	u8 pcipherCount;
-	u8 authCount;
-	u8 pcipherTotalCount = 0;
-	u8 authTotalCount = 0;
+	u8 rates_no = 0;
+	u8 ext_rates_no;
+	u16 offset;
+	u8 pcipher_cnt;
+	u8 auth_cnt;
+	u8 pcipher_total_cnt = 0;
+	u8 auth_total_cnt = 0;
 	u8 i, j;
 
-	pu8IEs = ptstrNetworkInfo->ies;
-	u16IEsLen = ptstrNetworkInfo->ies_len;
-
-	pNewJoinBssParam = kzalloc(sizeof(*pNewJoinBssParam), GFP_KERNEL);
-	if (pNewJoinBssParam) {
-		pNewJoinBssParam->dtim_period = ptstrNetworkInfo->dtim_period;
-		pNewJoinBssParam->beacon_period = ptstrNetworkInfo->beacon_period;
-		pNewJoinBssParam->cap_info = ptstrNetworkInfo->cap_info;
-		memcpy(pNewJoinBssParam->bssid, ptstrNetworkInfo->bssid, 6);
-		memcpy((u8 *)pNewJoinBssParam->ssid, ptstrNetworkInfo->ssid,
-		       ptstrNetworkInfo->ssid_len + 1);
-		pNewJoinBssParam->ssid_len = ptstrNetworkInfo->ssid_len;
-		memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3);
-		memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3);
-
-		while (index < u16IEsLen) {
-			if (pu8IEs[index] == SUPP_RATES_IE) {
-				suppRatesNo = pu8IEs[index + 1];
-				pNewJoinBssParam->supp_rates[0] = suppRatesNo;
+	ies = info->ies;
+	ies_len = info->ies_len;
+
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (param) {
+		param->dtim_period = info->dtim_period;
+		param->beacon_period = info->beacon_period;
+		param->cap_info = info->cap_info;
+		memcpy(param->bssid, info->bssid, 6);
+		memcpy((u8 *)param->ssid, info->ssid,
+		       info->ssid_len + 1);
+		param->ssid_len = info->ssid_len;
+		memset(param->rsn_pcip_policy, 0xFF, 3);
+		memset(param->rsn_auth_policy, 0xFF, 3);
+
+		while (index < ies_len) {
+			if (ies[index] == SUPP_RATES_IE) {
+				rates_no = ies[index + 1];
+				param->supp_rates[0] = rates_no;
 				index += 2;
 
-				for (i = 0; i < suppRatesNo; i++)
-					pNewJoinBssParam->supp_rates[i + 1] = pu8IEs[index + i];
+				for (i = 0; i < rates_no; i++)
+					param->supp_rates[i + 1] = ies[index + i];
 
-				index += suppRatesNo;
-			} else if (pu8IEs[index] == EXT_SUPP_RATES_IE) {
-				extSuppRatesNo = pu8IEs[index + 1];
-				if (extSuppRatesNo > (MAX_RATES_SUPPORTED - suppRatesNo))
-					pNewJoinBssParam->supp_rates[0] = MAX_RATES_SUPPORTED;
+				index += rates_no;
+			} else if (ies[index] == EXT_SUPP_RATES_IE) {
+				ext_rates_no = ies[index + 1];
+				if (ext_rates_no > (MAX_RATES_SUPPORTED - rates_no))
+					param->supp_rates[0] = MAX_RATES_SUPPORTED;
 				else
-					pNewJoinBssParam->supp_rates[0] += extSuppRatesNo;
+					param->supp_rates[0] += ext_rates_no;
 				index += 2;
-				for (i = 0; i < (pNewJoinBssParam->supp_rates[0] - suppRatesNo); i++)
-					pNewJoinBssParam->supp_rates[suppRatesNo + i + 1] = pu8IEs[index + i];
-
-				index += extSuppRatesNo;
-			} else if (pu8IEs[index] == HT_CAPABILITY_IE) {
-				pNewJoinBssParam->ht_capable = true;
-				index += pu8IEs[index + 1] + 2;
-			} else if ((pu8IEs[index] == WMM_IE) &&
-				   (pu8IEs[index + 2] == 0x00) && (pu8IEs[index + 3] == 0x50) &&
-				   (pu8IEs[index + 4] == 0xF2) &&
-				   (pu8IEs[index + 5] == 0x02) &&
-				   ((pu8IEs[index + 6] == 0x00) || (pu8IEs[index + 6] == 0x01)) &&
-				   (pu8IEs[index + 7] == 0x01)) {
-				pNewJoinBssParam->wmm_cap = true;
-
-				if (pu8IEs[index + 8] & BIT(7))
-					pNewJoinBssParam->uapsd_cap = true;
-				index += pu8IEs[index + 1] + 2;
-			} else if ((pu8IEs[index] == P2P_IE) &&
-				 (pu8IEs[index + 2] == 0x50) && (pu8IEs[index + 3] == 0x6f) &&
-				 (pu8IEs[index + 4] == 0x9a) &&
-				 (pu8IEs[index + 5] == 0x09) && (pu8IEs[index + 6] == 0x0c)) {
-				u16 u16P2P_count;
-
-				pNewJoinBssParam->tsf = ptstrNetworkInfo->tsf_lo;
-				pNewJoinBssParam->noa_enabled = 1;
-				pNewJoinBssParam->idx = pu8IEs[index + 9];
-
-				if (pu8IEs[index + 10] & BIT(7)) {
-					pNewJoinBssParam->opp_enabled = 1;
-					pNewJoinBssParam->ct_window = pu8IEs[index + 10];
+				for (i = 0; i < (param->supp_rates[0] - rates_no); i++)
+					param->supp_rates[rates_no + i + 1] = ies[index + i];
+
+				index += ext_rates_no;
+			} else if (ies[index] == HT_CAPABILITY_IE) {
+				param->ht_capable = true;
+				index += ies[index + 1] + 2;
+			} else if ((ies[index] == WMM_IE) &&
+				   (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) &&
+				   (ies[index + 4] == 0xF2) &&
+				   (ies[index + 5] == 0x02) &&
+				   ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) &&
+				   (ies[index + 7] == 0x01)) {
+				param->wmm_cap = true;
+
+				if (ies[index + 8] & BIT(7))
+					param->uapsd_cap = true;
+				index += ies[index + 1] + 2;
+			} else if ((ies[index] == P2P_IE) &&
+				 (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) &&
+				 (ies[index + 4] == 0x9a) &&
+				 (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) {
+				u16 p2p_cnt;
+
+				param->tsf = info->tsf_lo;
+				param->noa_enabled = 1;
+				param->idx = ies[index + 9];
+
+				if (ies[index + 10] & BIT(7)) {
+					param->opp_enabled = 1;
+					param->ct_window = ies[index + 10];
 				} else {
-					pNewJoinBssParam->opp_enabled = 0;
+					param->opp_enabled = 0;
 				}
 
-				pNewJoinBssParam->cnt = pu8IEs[index + 11];
-				u16P2P_count = index + 12;
+				param->cnt = ies[index + 11];
+				p2p_cnt = index + 12;
 
-				memcpy(pNewJoinBssParam->duration, pu8IEs + u16P2P_count, 4);
-				u16P2P_count += 4;
+				memcpy(param->duration, ies + p2p_cnt, 4);
+				p2p_cnt += 4;
 
-				memcpy(pNewJoinBssParam->interval, pu8IEs + u16P2P_count, 4);
-				u16P2P_count += 4;
+				memcpy(param->interval, ies + p2p_cnt, 4);
+				p2p_cnt += 4;
 
-				memcpy(pNewJoinBssParam->start_time, pu8IEs + u16P2P_count, 4);
+				memcpy(param->start_time, ies + p2p_cnt, 4);
 
-				index += pu8IEs[index + 1] + 2;
-			} else if ((pu8IEs[index] == RSN_IE) ||
-				 ((pu8IEs[index] == WPA_IE) && (pu8IEs[index + 2] == 0x00) &&
-				  (pu8IEs[index + 3] == 0x50) && (pu8IEs[index + 4] == 0xF2) &&
-				  (pu8IEs[index + 5] == 0x01)))	{
-				u16 rsnIndex = index;
+				index += ies[index + 1] + 2;
+			} else if ((ies[index] == RSN_IE) ||
+				 ((ies[index] == WPA_IE) && (ies[index + 2] == 0x00) &&
+				  (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) &&
+				  (ies[index + 5] == 0x01)))	{
+				u16 rsn_idx = index;
 
-				if (pu8IEs[rsnIndex] == RSN_IE)	{
-					pNewJoinBssParam->mode_802_11i = 2;
+				if (ies[rsn_idx] == RSN_IE)	{
+					param->mode_802_11i = 2;
 				} else {
-					if (pNewJoinBssParam->mode_802_11i == 0)
-						pNewJoinBssParam->mode_802_11i = 1;
-					rsnIndex += 4;
+					if (param->mode_802_11i == 0)
+						param->mode_802_11i = 1;
+					rsn_idx += 4;
 				}
 
-				rsnIndex += 7;
-				pNewJoinBssParam->rsn_grp_policy = pu8IEs[rsnIndex];
-				rsnIndex++;
-				jumpOffset = pu8IEs[rsnIndex] * 4;
-				pcipherCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex];
-				rsnIndex += 2;
+				rsn_idx += 7;
+				param->rsn_grp_policy = ies[rsn_idx];
+				rsn_idx++;
+				offset = ies[rsn_idx] * 4;
+				pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
+				rsn_idx += 2;
 
-				for (i = pcipherTotalCount, j = 0; i < pcipherCount + pcipherTotalCount && i < 3; i++, j++)
-					pNewJoinBssParam->rsn_pcip_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1];
+				for (i = pcipher_total_cnt, j = 0; i < pcipher_cnt + pcipher_total_cnt && i < 3; i++, j++)
+					param->rsn_pcip_policy[i] = ies[rsn_idx + ((j + 1) * 4) - 1];
 
-				pcipherTotalCount += pcipherCount;
-				rsnIndex += jumpOffset;
+				pcipher_total_cnt += pcipher_cnt;
+				rsn_idx += offset;
 
-				jumpOffset = pu8IEs[rsnIndex] * 4;
+				offset = ies[rsn_idx] * 4;
 
-				authCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex];
-				rsnIndex += 2;
+				auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
+				rsn_idx += 2;
 
-				for (i = authTotalCount, j = 0; i < authTotalCount + authCount; i++, j++)
-					pNewJoinBssParam->rsn_auth_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1];
+				for (i = auth_total_cnt, j = 0; i < auth_total_cnt + auth_cnt; i++, j++)
+					param->rsn_auth_policy[i] = ies[rsn_idx + ((j + 1) * 4) - 1];
 
-				authTotalCount += authCount;
-				rsnIndex += jumpOffset;
+				auth_total_cnt += auth_cnt;
+				rsn_idx += offset;
 
-				if (pu8IEs[index] == RSN_IE) {
-					pNewJoinBssParam->rsn_cap[0] = pu8IEs[rsnIndex];
-					pNewJoinBssParam->rsn_cap[1] = pu8IEs[rsnIndex + 1];
-					rsnIndex += 2;
+				if (ies[index] == RSN_IE) {
+					param->rsn_cap[0] = ies[rsn_idx];
+					param->rsn_cap[1] = ies[rsn_idx + 1];
+					rsn_idx += 2;
 				}
-				pNewJoinBssParam->rsn_found = true;
-				index += pu8IEs[index + 1] + 2;
+				param->rsn_found = true;
+				index += ies[index + 1] + 2;
 			} else {
-				index += pu8IEs[index + 1] + 2;
+				index += ies[index + 1] + 2;
 			}
 		}
 	}
 
-	return (void *)pNewJoinBssParam;
+	return (void *)param;
 }
 
 int wilc_setup_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx)
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index bb65b374c1ce..a08899941491 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -405,7 +405,7 @@ static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
 		cmd.increment = 1;
 		cmd.count = 4;
 		cmd.buffer = (u8 *)&data;
-		cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
+		cmd.block_size = g_sdio.block_size;
 		ret = wilc_sdio_cmd53(wilc, &cmd);
 		if (ret) {
 			dev_err(&func->dev,
@@ -489,7 +489,7 @@ static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
 		cmd.count = nleft;
 		cmd.buffer = buf;
 
-		cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
+		cmd.block_size = block_size;
 
 		if (addr > 0) {
 			if (!sdio_set_func0_csa_address(wilc, addr))
@@ -543,7 +543,7 @@ static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
 		cmd.count = 4;
 		cmd.buffer = (u8 *)data;
 
-		cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
+		cmd.block_size = g_sdio.block_size;
 		ret = wilc_sdio_cmd53(wilc, &cmd);
 		if (ret) {
 			dev_err(&func->dev,
@@ -629,7 +629,7 @@ static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
 		cmd.count = nleft;
 		cmd.buffer = buf;
 
-		cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
+		cmd.block_size = block_size;
 
 		if (addr > 0) {
 			if (!sdio_set_func0_csa_address(wilc, addr))
@@ -871,6 +871,7 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
 {
 	struct sdio_func *func = dev_to_sdio_func(wilc->dev);
 	int ret;
+	int vmm_ctl;
 
 	if (g_sdio.has_thrpt_enh3) {
 		u32 reg;
@@ -909,84 +910,82 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
 				goto _fail_;
 			}
 		}
-	} else {
-		if (g_sdio.irq_gpio) {
-			/* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
-			/* Cannot clear multiple interrupts. Must clear each interrupt individually */
-			u32 flags;
-
-			flags = val & (BIT(MAX_NUM_INT) - 1);
-			if (flags) {
-				int i;
-
-				ret = 1;
-				for (i = 0; i < g_sdio.nint; i++) {
-					if (flags & 1) {
-						struct sdio_cmd52 cmd;
-
-						cmd.read_write = 1;
-						cmd.function = 0;
-						cmd.raw = 0;
-						cmd.address = 0xf8;
-						cmd.data = BIT(i);
-
-						ret = wilc_sdio_cmd52(wilc, &cmd);
-						if (ret) {
-							dev_err(&func->dev,
-								"Failed cmd52, set 0xf8 data (%d) ...\n",
-								__LINE__);
-							goto _fail_;
-						}
+		return 1;
+	}
+	if (g_sdio.irq_gpio) {
+		/* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
+		/*
+		 * Cannot clear multiple interrupts.
+		 * Must clear each interrupt individually.
+		 */
+		u32 flags;
+
+		flags = val & (BIT(MAX_NUM_INT) - 1);
+		if (flags) {
+			int i;
+
+			ret = 1;
+			for (i = 0; i < g_sdio.nint; i++) {
+				if (flags & 1) {
+					struct sdio_cmd52 cmd;
+
+					cmd.read_write = 1;
+					cmd.function = 0;
+					cmd.raw = 0;
+					cmd.address = 0xf8;
+					cmd.data = BIT(i);
+
+					ret = wilc_sdio_cmd52(wilc, &cmd);
+					if (ret) {
+						dev_err(&func->dev,
+							"Failed cmd52, set 0xf8 data (%d) ...\n",
+							__LINE__);
+						goto _fail_;
 					}
-					if (!ret)
-						break;
-					flags >>= 1;
 				}
 				if (!ret)
-					goto _fail_;
-				for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
-					if (flags & 1)
-						dev_err(&func->dev,
-							"Unexpected interrupt cleared %d...\n",
-							i);
-					flags >>= 1;
-				}
+					break;
+				flags >>= 1;
 			}
-		}
-
-		{
-			u32 vmm_ctl;
-
-			vmm_ctl = 0;
-			/* select VMM table 0 */
-			if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
-				vmm_ctl |= BIT(0);
-			/* select VMM table 1 */
-			if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
-				vmm_ctl |= BIT(1);
-			/* enable VMM */
-			if ((val & EN_VMM) == EN_VMM)
-				vmm_ctl |= BIT(2);
-
-			if (vmm_ctl) {
-				struct sdio_cmd52 cmd;
-
-				cmd.read_write = 1;
-				cmd.function = 0;
-				cmd.raw = 0;
-				cmd.address = 0xf6;
-				cmd.data = vmm_ctl;
-				ret = wilc_sdio_cmd52(wilc, &cmd);
-				if (ret) {
+			if (!ret)
+				goto _fail_;
+			for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
+				if (flags & 1)
 					dev_err(&func->dev,
-						"Failed cmd52, set 0xf6 data (%d) ...\n",
-						__LINE__);
-					goto _fail_;
-				}
+						"Unexpected interrupt cleared %d...\n",
+						i);
+				flags >>= 1;
 			}
 		}
 	}
 
+	vmm_ctl = 0;
+	/* select VMM table 0 */
+	if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
+		vmm_ctl |= BIT(0);
+	/* select VMM table 1 */
+	if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
+		vmm_ctl |= BIT(1);
+	/* enable VMM */
+	if ((val & EN_VMM) == EN_VMM)
+		vmm_ctl |= BIT(2);
+
+	if (vmm_ctl) {
+		struct sdio_cmd52 cmd;
+
+		cmd.read_write = 1;
+		cmd.function = 0;
+		cmd.raw = 0;
+		cmd.address = 0xf6;
+		cmd.data = vmm_ctl;
+		ret = wilc_sdio_cmd52(wilc, &cmd);
+		if (ret) {
+			dev_err(&func->dev,
+				"Failed cmd52, set 0xf6 data (%d) ...\n",
+				__LINE__);
+			goto _fail_;
+		}
+	}
 	return 1;
 _fail_:
 	return 0;
diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c
index 8f71a6022721..6b392c946a6f 100644
--- a/drivers/staging/wilc1000/wilc_spi.c
+++ b/drivers/staging/wilc1000/wilc_spi.c
@@ -287,17 +287,19 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 	u8 rsp;
 	int len = 0;
 	int result = N_OK;
+	int retry;
+	u8 crc[2];
 
 	wb[0] = cmd;
 	switch (cmd) {
-	case CMD_SINGLE_READ:                           /* single word (4 bytes) read */
+	case CMD_SINGLE_READ: /* single word (4 bytes) read */
 		wb[1] = (u8)(adr >> 16);
 		wb[2] = (u8)(adr >> 8);
 		wb[3] = (u8)adr;
 		len = 5;
 		break;
 
-	case CMD_INTERNAL_READ:                 /* internal register read */
+	case CMD_INTERNAL_READ: /* internal register read */
 		wb[1] = (u8)(adr >> 8);
 		if (clockless == 1)
 			wb[1] |= BIT(7);
@@ -306,29 +308,29 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 		len = 5;
 		break;
 
-	case CMD_TERMINATE:                                     /* termination */
+	case CMD_TERMINATE:
 		wb[1] = 0x00;
 		wb[2] = 0x00;
 		wb[3] = 0x00;
 		len = 5;
 		break;
 
-	case CMD_REPEAT:                                                /* repeat */
+	case CMD_REPEAT:
 		wb[1] = 0x00;
 		wb[2] = 0x00;
 		wb[3] = 0x00;
 		len = 5;
 		break;
 
-	case CMD_RESET:                                                 /* reset */
+	case CMD_RESET:
 		wb[1] = 0xff;
 		wb[2] = 0xff;
 		wb[3] = 0xff;
 		len = 5;
 		break;
 
-	case CMD_DMA_WRITE:                                     /* dma write */
-	case CMD_DMA_READ:                                      /* dma read */
+	case CMD_DMA_WRITE: /* dma write */
+	case CMD_DMA_READ:  /* dma read */
 		wb[1] = (u8)(adr >> 16);
 		wb[2] = (u8)(adr >> 8);
 		wb[3] = (u8)adr;
@@ -337,8 +339,8 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 		len = 7;
 		break;
 
-	case CMD_DMA_EXT_WRITE:         /* dma extended write */
-	case CMD_DMA_EXT_READ:                  /* dma extended read */
+	case CMD_DMA_EXT_WRITE: /* dma extended write */
+	case CMD_DMA_EXT_READ:  /* dma extended read */
 		wb[1] = (u8)(adr >> 16);
 		wb[2] = (u8)(adr >> 8);
 		wb[3] = (u8)adr;
@@ -348,7 +350,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 		len = 8;
 		break;
 
-	case CMD_INTERNAL_WRITE:                /* internal register write */
+	case CMD_INTERNAL_WRITE: /* internal register write */
 		wb[1] = (u8)(adr >> 8);
 		if (clockless == 1)
 			wb[1] |= BIT(7);
@@ -360,7 +362,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 		len = 8;
 		break;
 
-	case CMD_SINGLE_WRITE:                  /* single word write */
+	case CMD_SINGLE_WRITE: /* single word write */
 		wb[1] = (u8)(adr >> 16);
 		wb[2] = (u8)(adr >> 8);
 		wb[3] = (u8)(adr);
@@ -395,13 +397,12 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 	    cmd == CMD_REPEAT) {
 		len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES);
 	} else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
-		if (!g_spi.crc_off) {
-			len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
-				      + NUM_CRC_BYTES + NUM_DUMMY_BYTES);
-		} else {
-			len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
-				      + NUM_DUMMY_BYTES);
-		}
+		int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
+			+ NUM_DUMMY_BYTES;
+		if (!g_spi.crc_off)
+			len2 = len + tmp + NUM_CRC_BYTES;
+		else
+			len2 = len + tmp;
 	} else {
 		len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES);
 	}
@@ -422,19 +423,13 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 		return N_FAIL;
 	}
 
-	/**
+	/*
 	 * Command/Control response
-	 **/
-	if (cmd == CMD_RESET ||
-	    cmd == CMD_TERMINATE ||
-	    cmd == CMD_REPEAT) {
-		rix++;         /* skip 1 byte */
-	}
+	 */
+	if (cmd == CMD_RESET || cmd == CMD_TERMINATE || cmd == CMD_REPEAT)
+		rix++; /* skip 1 byte */
 
-	/* do { */
 	rsp = rb[rix++];
-	/*	if(rsp == cmd) break; */
-	/* } while(&rptr[1] <= &rb[len2]); */
 
 	if (rsp != cmd) {
 		dev_err(&spi->dev,
@@ -443,9 +438,9 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 		return N_FAIL;
 	}
 
-	/**
+	/*
 	 * State response
-	 **/
+	 */
 	rsp = rb[rix++];
 	if (rsp != 0x00) {
 		dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
@@ -455,15 +450,15 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 
 	if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ ||
 	    cmd == CMD_DMA_READ || cmd == CMD_DMA_EXT_READ) {
-		int retry;
-		/* u16 crc1, crc2; */
-		u8 crc[2];
-		/**
+		/*
 		 * Data Respnose header
-		 **/
+		 */
 		retry = 100;
 		do {
-			/* ensure there is room in buffer later to read data and crc */
+			/*
+			 * ensure there is room in buffer later
+			 * to read data and crc
+			 */
 			if (rix < len2) {
 				rsp = rb[rix++];
 			} else {
@@ -479,129 +474,134 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
 				"Error, data read response (%02x)\n", rsp);
 			return N_RESET;
 		}
+	}
 
-		if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
-			/**
-			 * Read bytes
-			 **/
-			if ((rix + 3) < len2) {
-				b[0] = rb[rix++];
-				b[1] = rb[rix++];
-				b[2] = rb[rix++];
-				b[3] = rb[rix++];
+	if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
+		/*
+		 * Read bytes
+		 */
+		if ((rix + 3) < len2) {
+			b[0] = rb[rix++];
+			b[1] = rb[rix++];
+			b[2] = rb[rix++];
+			b[3] = rb[rix++];
+		} else {
+			dev_err(&spi->dev,
+				"buffer overrun when reading data.\n");
+			return N_FAIL;
+		}
+
+		if (!g_spi.crc_off) {
+			/*
+			 * Read Crc
+			 */
+			if ((rix + 1) < len2) {
+				crc[0] = rb[rix++];
+				crc[1] = rb[rix++];
 			} else {
 				dev_err(&spi->dev,
-					"buffer overrun when reading data.\n");
+					"buffer overrun when reading crc.\n");
 				return N_FAIL;
 			}
+		}
+	} else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
+		int ix;
 
-			if (!g_spi.crc_off) {
-				/**
-				 * Read Crc
-				 **/
-				if ((rix + 1) < len2) {
-					crc[0] = rb[rix++];
-					crc[1] = rb[rix++];
-				} else {
-					dev_err(&spi->dev, "buffer overrun when reading crc.\n");
-					return N_FAIL;
-				}
-			}
-		} else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
-			int ix;
-
-			/* some data may be read in response to dummy bytes. */
-			for (ix = 0; (rix < len2) && (ix < sz); )
-				b[ix++] = rb[rix++];
-
-			sz -= ix;
+		/* some data may be read in response to dummy bytes. */
+		for (ix = 0; (rix < len2) && (ix < sz); )
+			b[ix++] = rb[rix++];
 
-			if (sz > 0) {
-				int nbytes;
+		sz -= ix;
 
-				if (sz <= (DATA_PKT_SZ - ix))
-					nbytes = sz;
-				else
-					nbytes = DATA_PKT_SZ - ix;
+		if (sz > 0) {
+			int nbytes;
 
-				/**
-				 * Read bytes
-				 **/
-				if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
-					dev_err(&spi->dev, "Failed data block read, bus error...\n");
-					result = N_FAIL;
-					goto _error_;
-				}
+			if (sz <= (DATA_PKT_SZ - ix))
+				nbytes = sz;
+			else
+				nbytes = DATA_PKT_SZ - ix;
 
-				/**
-				 * Read Crc
-				 **/
-				if (!g_spi.crc_off) {
-					if (wilc_spi_rx(wilc, crc, 2)) {
-						dev_err(&spi->dev, "Failed data block crc read, bus error...\n");
-						result = N_FAIL;
-						goto _error_;
-					}
-				}
+			/*
+			 * Read bytes
+			 */
+			if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+				dev_err(&spi->dev,
+					"Failed block read, bus err\n");
+				result = N_FAIL;
+				goto _error_;
+			}
 
-				ix += nbytes;
-				sz -= nbytes;
+			/*
+			 * Read Crc
+			 */
+			if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) {
+				dev_err(&spi->dev,
+					"Failed block crc read, bus err\n");
+				result = N_FAIL;
+				goto _error_;
 			}
 
-			/*  if any data in left unread, then read the rest using normal DMA code.*/
-			while (sz > 0) {
-				int nbytes;
-
-				if (sz <= DATA_PKT_SZ)
-					nbytes = sz;
-				else
-					nbytes = DATA_PKT_SZ;
-
-				/**
-				 * read data response only on the next DMA cycles not
-				 * the first DMA since data response header is already
-				 * handled above for the first DMA.
-				 **/
-				/**
-				 * Data Respnose header
-				 **/
-				retry = 10;
-				do {
-					if (wilc_spi_rx(wilc, &rsp, 1)) {
-						dev_err(&spi->dev, "Failed data response read, bus error...\n");
-						result = N_FAIL;
-						break;
-					}
-					if (((rsp >> 4) & 0xf) == 0xf)
-						break;
-				} while (retry--);
-
-				if (result == N_FAIL)
-					break;
+			ix += nbytes;
+			sz -= nbytes;
+		}
+
+		/*
+		 * if any data in left unread,
+		 * then read the rest using normal DMA code.
+		 */
+		while (sz > 0) {
+			int nbytes;
 
-				/**
-				 * Read bytes
-				 **/
-				if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
-					dev_err(&spi->dev, "Failed data block read, bus error...\n");
+			if (sz <= DATA_PKT_SZ)
+				nbytes = sz;
+			else
+				nbytes = DATA_PKT_SZ;
+
+			/*
+			 * read data response only on the next DMA cycles not
+			 * the first DMA since data response header is already
+			 * handled above for the first DMA.
+			 */
+			/*
+			 * Data Respnose header
+			 */
+			retry = 10;
+			do {
+				if (wilc_spi_rx(wilc, &rsp, 1)) {
+					dev_err(&spi->dev,
+						"Failed resp read, bus err\n");
 					result = N_FAIL;
 					break;
 				}
+				if (((rsp >> 4) & 0xf) == 0xf)
+					break;
+			} while (retry--);
 
-				/**
-				 * Read Crc
-				 **/
-				if (!g_spi.crc_off) {
-					if (wilc_spi_rx(wilc, crc, 2)) {
-						dev_err(&spi->dev, "Failed data block crc read, bus error...\n");
-						result = N_FAIL;
-						break;
-					}
-				}
+			if (result == N_FAIL)
+				break;
 
-				ix += nbytes;
-				sz -= nbytes;
+			/*
+			 * Read bytes
+			 */
+			if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+				dev_err(&spi->dev,
+					"Failed block read, bus err\n");
+				result = N_FAIL;
+				break;
 			}
+
+			/*
+			 * Read Crc
+			 */
+			if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) {
+				dev_err(&spi->dev,
+					"Failed block crc read, bus err\n");
+				result = N_FAIL;
+				break;
+			}
+
+			ix += nbytes;
+			sz -= nbytes;
 		}
 	}
 _error_:
@@ -614,11 +614,10 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
 	int ix, nbytes;
 	int result = 1;
 	u8 cmd, order, crc[2] = {0};
-	/* u8 rsp; */
 
-	/**
-	 *      Data
-	 **/
+	/*
+	 * Data
+	 */
 	ix = 0;
 	do {
 		if (sz <= DATA_PKT_SZ)
@@ -626,9 +625,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
 		else
 			nbytes = DATA_PKT_SZ;
 
-		/**
-		 *      Write command
-		 **/
+		/*
+		 * Write command
+		 */
 		cmd = 0xf0;
 		if (ix == 0) {
 			if (sz <= DATA_PKT_SZ)
@@ -650,9 +649,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
 			break;
 		}
 
-		/**
-		 *      Write data
-		 **/
+		/*
+		 * Write data
+		 */
 		if (wilc_spi_tx(wilc, &b[ix], nbytes)) {
 			dev_err(&spi->dev,
 				"Failed data block write, bus error...\n");
@@ -660,9 +659,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
 			break;
 		}
 
-		/**
-		 *      Write Crc
-		 **/
+		/*
+		 * Write Crc
+		 */
 		if (!g_spi.crc_off) {
 			if (wilc_spi_tx(wilc, crc, 2)) {
 				dev_err(&spi->dev, "Failed data block crc write, bus error...\n");
@@ -671,9 +670,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
 			}
 		}
 
-		/**
-		 *      No need to wait for response
-		 **/
+		/*
+		 * No need to wait for response
+		 */
 		ix += nbytes;
 		sz -= nbytes;
 	} while (sz);
@@ -733,7 +732,7 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
 
 	data = cpu_to_le32(data);
 	if (addr < 0x30) {
-		/* Clockless register*/
+		/* Clockless register */
 		cmd = CMD_INTERNAL_WRITE;
 		clockless = 1;
 	}
@@ -751,9 +750,9 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
 	int result;
 	u8 cmd = CMD_DMA_EXT_WRITE;
 
-	/**
-	 *      has to be greated than 4
-	 **/
+	/*
+	 * has to be greated than 4
+	 */
 	if (size <= 4)
 		return 0;
 
@@ -764,9 +763,9 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
 		return 0;
 	}
 
-	/**
-	 *      Data
-	 **/
+	/*
+	 * Data
+	 */
 	result = spi_data_write(wilc, buf, size);
 	if (result != N_OK)
 		dev_err(&spi->dev, "Failed block data write...\n");
@@ -783,7 +782,7 @@ static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
 
 	if (addr < 0x30) {
 		/* dev_err(&spi->dev, "***** read addr %d\n\n", addr); */
-		/* Clockless register*/
+		/* Clockless register */
 		cmd = CMD_INTERNAL_READ;
 		clockless = 1;
 	}
@@ -825,9 +824,9 @@ static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
 
 static int _wilc_spi_deinit(struct wilc *wilc)
 {
-	/**
-	 *      TODO:
-	 **/
+	/*
+	 * TODO:
+	 */
 	return 1;
 }
 
@@ -836,7 +835,6 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
 	struct spi_device *spi = to_spi_device(wilc->dev);
 	u32 reg;
 	u32 chipid;
-
 	static int isinit;
 
 	if (isinit) {
@@ -849,45 +847,53 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
 
 	memset(&g_spi, 0, sizeof(struct wilc_spi));
 
-	/**
-	 *      configure protocol
-	 **/
+	/*
+	 * configure protocol
+	 */
 	g_spi.crc_off = 0;
 
-	/* TODO: We can remove the CRC trials if there is a definite way to reset */
+	/*
+	 * TODO: We can remove the CRC trials if there is a definite
+	 * way to reset
+	 */
 	/* the SPI to it's initial value. */
 	if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
-		/* Read failed. Try with CRC off. This might happen when module
+		/*
+		 * Read failed. Try with CRC off. This might happen when module
 		 * is removed but chip isn't reset
 		 */
 		g_spi.crc_off = 1;
-		dev_err(&spi->dev, "Failed internal read protocol with CRC on, retrying with CRC off...\n");
+		dev_err(&spi->dev,
+			"Failed read with CRC on, retrying with CRC off\n");
 		if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
-			/* Reaad failed with both CRC on and off, something went bad */
-			dev_err(&spi->dev,
-				"Failed internal read protocol...\n");
+			/*
+			 * Read failed with both CRC on and off,
+			 * something went bad
+			 */
+			dev_err(&spi->dev, "Failed internal read protocol\n");
 			return 0;
 		}
 	}
-	if (g_spi.crc_off == 0)	{
-		reg &= ~0xc;    /* disable crc checking */
+	if (g_spi.crc_off == 0) {
+		reg &= ~0xc; /* disable crc checking */
 		reg &= ~0x70;
 		reg |= (0x5 << 4);
 		if (!spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg)) {
-			dev_err(&spi->dev, "[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__);
+			dev_err(&spi->dev,
+				"[wilc spi %d]: Failed internal write reg\n",
+				__LINE__);
 			return 0;
 		}
 		g_spi.crc_off = 1;
 	}
 
-	/**
-	 *      make sure can read back chip id correctly
-	 **/
+	/*
+	 * make sure can read back chip id correctly
+	 */
 	if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) {
 		dev_err(&spi->dev, "Fail cmd read chip id...\n");
 		return 0;
 	}
-	/* dev_err(&spi->dev, "chipid (%08x)\n", chipid); */
 
 	g_spi.has_thrpt_enh = 1;
 
@@ -933,45 +939,46 @@ static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
 	int happened, j;
 	u32 unknown_mask;
 	u32 irq_flags;
+	int k = IRG_FLAGS_OFFSET + 5;
 
 	if (g_spi.has_thrpt_enh) {
 		ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
 					int_status);
-	} else {
-		ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE,
-					&byte_cnt);
-		if (!ret) {
-			dev_err(&spi->dev,
-				"Failed read WILC_VMM_TO_HOST_SIZE ...\n");
-			goto _fail_;
-		}
-		tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
+		return ret;
+	}
+	ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, &byte_cnt);
+	if (!ret) {
+		dev_err(&spi->dev,
+			"Failed read WILC_VMM_TO_HOST_SIZE ...\n");
+		goto _fail_;
+	}
+	tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
 
-		j = 0;
-		do {
-			happened = 0;
+	j = 0;
+	do {
+		happened = 0;
 
-			wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
-			tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
+		wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
+		tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
 
-			if (g_spi.nint > 5) {
-				wilc_spi_read_reg(wilc, 0x1a94,
-						  &irq_flags);
-				tmp |= (((irq_flags >> 0) & 0x7) << (IRG_FLAGS_OFFSET + 5));
-			}
+		if (g_spi.nint > 5) {
+			wilc_spi_read_reg(wilc, 0x1a94, &irq_flags);
+			tmp |= (((irq_flags >> 0) & 0x7) << k);
+		}
 
-			unknown_mask = ~((1ul << g_spi.nint) - 1);
+		unknown_mask = ~((1ul << g_spi.nint) - 1);
 
-			if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) {
-				dev_err(&spi->dev, "Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unknown_mask);
-					happened = 1;
-			}
+		if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) {
+			dev_err(&spi->dev,
+				"Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n",
+				j, tmp, unknown_mask);
+				happened = 1;
+		}
 
-			j++;
-		} while (happened);
+		j++;
+	} while (happened);
 
-		*int_status = tmp;
-	}
+	*int_status = tmp;
 
 _fail_:
 	return ret;
@@ -981,71 +988,69 @@ static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
 {
 	struct spi_device *spi = to_spi_device(wilc->dev);
 	int ret;
+	u32 flags;
+	u32 tbl_ctl;
 
 	if (g_spi.has_thrpt_enh) {
 		ret = spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
 					 val);
-	} else {
-		u32 flags;
-
-		flags = val & (BIT(MAX_NUM_INT) - 1);
-		if (flags) {
-			int i;
-
-			ret = 1;
-			for (i = 0; i < g_spi.nint; i++) {
-				/* No matter what you write 1 or 0, it will clear interrupt. */
-				if (flags & 1)
-					ret = wilc_spi_write_reg(wilc, 0x10c8 + i * 4, 1);
-				if (!ret)
-					break;
-				flags >>= 1;
-			}
-			if (!ret) {
+		return ret;
+	}
+
+	flags = val & (BIT(MAX_NUM_INT) - 1);
+	if (flags) {
+		int i;
+
+		ret = 1;
+		for (i = 0; i < g_spi.nint; i++) {
+			/*
+			 * No matter what you write 1 or 0,
+			 * it will clear interrupt.
+			 */
+			if (flags & 1)
+				ret = wilc_spi_write_reg(wilc,
+							 0x10c8 + i * 4, 1);
+			if (!ret)
+				break;
+			flags >>= 1;
+		}
+		if (!ret) {
+			dev_err(&spi->dev,
+				"Failed wilc_spi_write_reg, set reg %x ...\n",
+				0x10c8 + i * 4);
+			goto _fail_;
+		}
+		for (i = g_spi.nint; i < MAX_NUM_INT; i++) {
+			if (flags & 1)
 				dev_err(&spi->dev,
-					"Failed wilc_spi_write_reg, set reg %x ...\n",
-					0x10c8 + i * 4);
-				goto _fail_;
-			}
-			for (i = g_spi.nint; i < MAX_NUM_INT; i++) {
-				if (flags & 1)
-					dev_err(&spi->dev,
-						"Unexpected interrupt cleared %d...\n",
-						i);
-				flags >>= 1;
-			}
+					"Unexpected interrupt cleared %d...\n",
+					i);
+			flags >>= 1;
 		}
+	}
 
-		{
-			u32 tbl_ctl;
-
-			tbl_ctl = 0;
-			/* select VMM table 0 */
-			if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
-				tbl_ctl |= BIT(0);
-			/* select VMM table 1 */
-			if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
-				tbl_ctl |= BIT(1);
+	tbl_ctl = 0;
+	/* select VMM table 0 */
+	if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
+		tbl_ctl |= BIT(0);
+	/* select VMM table 1 */
+	if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
+		tbl_ctl |= BIT(1);
 
-			ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL,
-						 tbl_ctl);
-			if (!ret) {
-				dev_err(&spi->dev,
-					"fail write reg vmm_tbl_ctl...\n");
-				goto _fail_;
-			}
+	ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL, tbl_ctl);
+	if (!ret) {
+		dev_err(&spi->dev, "fail write reg vmm_tbl_ctl...\n");
+		goto _fail_;
+	}
 
-			if ((val & EN_VMM) == EN_VMM) {
-				/**
-				 *      enable vmm transfer.
-				 **/
-				ret = wilc_spi_write_reg(wilc,
-							 WILC_VMM_CORE_CTL, 1);
-				if (!ret) {
-					dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n");
-					goto _fail_;
-				}
-			}
+	if ((val & EN_VMM) == EN_VMM) {
+		/*
+		 * enable vmm transfer.
+		 */
+		ret = wilc_spi_write_reg(wilc, WILC_VMM_CORE_CTL, 1);
+		if (!ret) {
+			dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n");
+			goto _fail_;
 		}
 	}
 _fail_:
@@ -1065,9 +1070,9 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
 
 	g_spi.nint = nint;
 
-	/**
-	 *      interrupt pin mux select
-	 **/
+	/*
+	 * interrupt pin mux select
+	 */
 	ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, &reg);
 	if (!ret) {
 		dev_err(&spi->dev, "Failed read reg (%08x)...\n",
@@ -1082,9 +1087,9 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
 		return 0;
 	}
 
-	/**
-	 *      interrupt enable
-	 **/
+	/*
+	 * interrupt enable
+	 */
 	ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, &reg);
 	if (!ret) {
 		dev_err(&spi->dev, "Failed read reg (%08x)...\n",
diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c
index acaeafc2c350..1a9ef1a88e16 100644
--- a/drivers/staging/wilc1000/wilc_wlan.c
+++ b/drivers/staging/wilc1000/wilc_wlan.c
@@ -173,11 +173,13 @@ static inline int update_tcp_session(u32 index, u32 ack)
 static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
 				      struct txq_entry_t *txqe)
 {
-	if (pending_base + pending_acks < MAX_PENDING_ACKS) {
-		pending_acks_info[pending_base + pending_acks].ack_num = ack;
-		pending_acks_info[pending_base + pending_acks].txqe = txqe;
-		pending_acks_info[pending_base + pending_acks].session_index = session_index;
-		txqe->tcp_pending_ack_idx = pending_base + pending_acks;
+	u32 i = pending_base + pending_acks;
+
+	if (i < MAX_PENDING_ACKS) {
+		pending_acks_info[i].ack_num = ack;
+		pending_acks_info[i].txqe = txqe;
+		pending_acks_info[i].session_index = session_index;
+		txqe->tcp_pending_ack_idx = i;
 		pending_acks++;
 	}
 	return 0;
@@ -230,8 +232,10 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
 					 (u32)tcp_hdr_ptr[11];
 
 				for (i = 0; i < tcp_session; i++) {
+					u32 j = ack_session_info[i].seq_num;
+
 					if (i < 2 * MAX_TCP_SESSION &&
-					    ack_session_info[i].seq_num == seq_no) {
+					    j == seq_no) {
 						update_tcp_session(i, ack_no);
 						break;
 					}
@@ -258,10 +262,20 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
 
 	spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
 	for (i = pending_base; i < (pending_base + pending_acks); i++) {
-		if (i >= MAX_PENDING_ACKS ||
-		    pending_acks_info[i].session_index >= 2 * MAX_TCP_SESSION)
+		u32 session_index;
+		u32 bigger_ack_num;
+
+		if (i >= MAX_PENDING_ACKS)
+			break;
+
+		session_index = pending_acks_info[i].session_index;
+
+		if (session_index >= 2 * MAX_TCP_SESSION)
 			break;
-		if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) {
+
+		bigger_ack_num = ack_session_info[session_index].bigger_ack_num;
+
+		if (pending_acks_info[i].ack_num < bigger_ack_num) {
 			struct txq_entry_t *tqe;
 
 			tqe = pending_acks_info[i].txqe;
@@ -562,6 +576,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 	u32 vmm_table[WILC_VMM_TBL_SIZE];
 	struct wilc_vif *vif;
 	struct wilc *wilc;
+	const struct wilc_hif_func *func;
 
 	vif = netdev_priv(dev);
 	wilc = vif->wilc;
@@ -615,10 +630,9 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 
 		acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
 		counter = 0;
+		func = wilc->hif_func;
 		do {
-			ret = wilc->hif_func->hif_read_reg(wilc,
-							   WILC_HOST_TX_CTRL,
-							   &reg);
+			ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
 			if (!ret)
 				break;
 
@@ -628,7 +642,8 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 			counter++;
 			if (counter > 200) {
 				counter = 0;
-				ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
+				ret = func->hif_write_reg(wilc,
+							  WILC_HOST_TX_CTRL, 0);
 				break;
 			}
 		} while (!wilc->quit);
@@ -638,18 +653,21 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 
 		timeout = 200;
 		do {
-			ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
+			ret = func->hif_block_tx(wilc,
+						 WILC_VMM_TBL_RX_SHADOW_BASE,
+						 (u8 *)vmm_table,
+						 ((i + 1) * 4));
 			if (!ret)
 				break;
 
-			ret = wilc->hif_func->hif_write_reg(wilc,
-							    WILC_HOST_VMM_CTL,
-							    0x2);
+			ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
 			if (!ret)
 				break;
 
 			do {
-				ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+				ret = func->hif_read_reg(wilc,
+							 WILC_HOST_VMM_CTL,
+							 &reg);
 				if (!ret)
 					break;
 				if ((reg >> 2) & 0x1) {
@@ -659,7 +677,9 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 				release_bus(wilc, RELEASE_ALLOW_SLEEP);
 			} while (--timeout);
 			if (timeout <= 0) {
-				ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
+				ret = func->hif_write_reg(wilc,
+							  WILC_HOST_VMM_CTL,
+							  0x0);
 				break;
 			}
 
@@ -667,11 +687,15 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 				break;
 
 			if (entries == 0) {
-				ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
+				ret = func->hif_read_reg(wilc,
+							 WILC_HOST_TX_CTRL,
+							 &reg);
 				if (!ret)
 					break;
 				reg &= ~BIT(0);
-				ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
+				ret = func->hif_write_reg(wilc,
+							  WILC_HOST_TX_CTRL,
+							  reg);
 				if (!ret)
 					break;
 				break;
@@ -739,11 +763,11 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
 
 		acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
 
-		ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
+		ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
 		if (!ret)
 			goto _end_;
 
-		ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset);
+		ret = func->hif_block_tx_ext(wilc, 0, txb, offset);
 		if (!ret)
 			goto _end_;
 
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c
index aeb5417f3587..2b44f4cc56b7 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.c
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c
@@ -221,7 +221,8 @@ static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
 	return 8;
 }
 
-static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, u32 size)
+static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
+				 u32 size)
 {
 	u8 *buf;
 
@@ -483,20 +484,21 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
 		} while (1);
 	} else if (type == CFG_STR_CMD) {
 		do {
-			if (g_cfg_str[i].id == WID_NIL)
+			u32 id = g_cfg_str[i].id;
+
+			if (id == WID_NIL)
 				break;
 
-			if (g_cfg_str[i].id == wid) {
+			if (id == wid) {
 				u32 size = g_cfg_str[i].str[0] |
 						(g_cfg_str[i].str[1] << 8);
 
 				if (buffer_size >= size) {
-					if (g_cfg_str[i].id == WID_SITE_SURVEY_RESULTS)	{
+					if (id == WID_SITE_SURVEY_RESULTS) {
 						static int toggle;
 
 						i += toggle;
 						toggle ^= 1;
-
 					}
 					memcpy(buffer,  &g_cfg_str[i].str[2],
 					       size);
@@ -523,9 +525,12 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
 	frame += 4;
 	size -= 4;
 
-	/**
-	 *      The  valid types of response messages are 'R' (Response), 'I' (Information), and 'N' (Network Information)
-	 **/
+	/*
+	 * The valid types of response messages are
+	 * 'R' (Response),
+	 * 'I' (Information), and
+	 * 'N' (Network Information)
+	 */
 
 	switch (msg_type) {
 	case 'R':
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 78934e435fcf..d7de9e9c47a2 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -563,7 +563,7 @@ int prism2mgmt_start(struct wlandevice *wlandev, void *msgp)
 	/*** STATION ***/
 	/* Set the REQUIRED config items */
 	/* SSID */
-	pstr = (struct p80211pstrd *)&(msg->ssid.data);
+	pstr = (struct p80211pstrd *)&msg->ssid.data;
 	prism2mgmt_pstr2bytestr(p2bytestr, pstr);
 	result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
 					bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 64c5a57b92e4..99501785cdc1 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1020,7 +1020,7 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
 	struct socket *new_sock, *sock = np->np_socket;
 	struct sockaddr_in sock_in;
 	struct sockaddr_in6 sock_in6;
-	int rc, err;
+	int rc;
 
 	rc = kernel_accept(sock, &new_sock, 0);
 	if (rc < 0)
@@ -1033,8 +1033,8 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
 		memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
 
 		rc = conn->sock->ops->getname(conn->sock,
-				(struct sockaddr *)&sock_in6, &err, 1);
-		if (!rc) {
+				(struct sockaddr *)&sock_in6, 1);
+		if (rc >= 0) {
 			if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) {
 				memcpy(&conn->login_sockaddr, &sock_in6, sizeof(sock_in6));
 			} else {
@@ -1047,8 +1047,8 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
 		}
 
 		rc = conn->sock->ops->getname(conn->sock,
-				(struct sockaddr *)&sock_in6, &err, 0);
-		if (!rc) {
+				(struct sockaddr *)&sock_in6, 0);
+		if (rc >= 0) {
 			if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) {
 				memcpy(&conn->local_sockaddr, &sock_in6, sizeof(sock_in6));
 			} else {
@@ -1063,13 +1063,13 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
 		memset(&sock_in, 0, sizeof(struct sockaddr_in));
 
 		rc = conn->sock->ops->getname(conn->sock,
-				(struct sockaddr *)&sock_in, &err, 1);
-		if (!rc)
+				(struct sockaddr *)&sock_in, 1);
+		if (rc >= 0)
 			memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in));
 
 		rc = conn->sock->ops->getname(conn->sock,
-				(struct sockaddr *)&sock_in, &err, 0);
-		if (!rc)
+				(struct sockaddr *)&sock_in, 0);
+		if (rc >= 0)
 			memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in));
 	}
 
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 3b45c25f296e..e431c5aafe35 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -20,7 +20,6 @@
 
 struct ci_hdrc_imx_platform_flag {
 	unsigned int flags;
-	bool runtime_pm;
 };
 
 static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
@@ -29,7 +28,7 @@ static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
 };
 
 static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
-		CI_HDRC_DISABLE_STREAMING,
+	.flags = CI_HDRC_DISABLE_STREAMING,
 };
 
 static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
@@ -84,6 +83,7 @@ struct ci_hdrc_imx_data {
 	struct clk *clk;
 	struct imx_usbmisc_data *usbmisc_data;
 	bool supports_runtime_pm;
+	bool override_phy_control;
 	bool in_lpm;
 	/* SoC before i.mx6 (except imx23/imx28) needs three clks */
 	bool need_three_clks;
@@ -255,6 +255,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
 	int ret;
 	const struct of_device_id *of_id;
 	const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
+	struct device_node *np = pdev->dev.of_node;
 
 	of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
 	if (!of_id)
@@ -289,6 +290,14 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
 	}
 
 	pdata.usb_phy = data->phy;
+
+	if (of_device_is_compatible(np, "fsl,imx53-usb") && pdata.usb_phy &&
+	    of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) {
+		pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL;
+		data->override_phy_control = true;
+		usb_phy_init(pdata.usb_phy);
+	}
+
 	pdata.flags |= imx_platform_flag->flags;
 	if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
 		data->supports_runtime_pm = true;
@@ -342,6 +351,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
 		pm_runtime_put_noidle(&pdev->dev);
 	}
 	ci_hdrc_remove_device(data->ci_pdev);
+	if (data->override_phy_control)
+		usb_phy_shutdown(data->phy);
 	imx_disable_unprepare_clks(&pdev->dev);
 
 	return 0;
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 8cdf0af156c6..34ad5bf8acd8 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -148,14 +148,21 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
 	if (data->index > 2)
 		return -EINVAL;
 
-	if (data->evdo) {
-		spin_lock_irqsave(&usbmisc->lock, flags);
-		reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
-		val = readl(reg);
-		writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
-		spin_unlock_irqrestore(&usbmisc->lock, flags);
-		usleep_range(5000, 10000); /* needed to stabilize voltage */
-	}
+	if (data->index)
+		return 0;
+
+	spin_lock_irqsave(&usbmisc->lock, flags);
+	reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
+	val = readl(reg);
+
+	if (data->evdo)
+		val |= MX25_BM_EXTERNAL_VBUS_DIVIDER;
+	else
+		val &= ~MX25_BM_EXTERNAL_VBUS_DIVIDER;
+
+	writel(val, reg);
+	spin_unlock_irqrestore(&usbmisc->lock, flags);
+	usleep_range(5000, 10000); /* needed to stabilize voltage */
 
 	return 0;
 }
@@ -308,13 +315,12 @@ static int usbmisc_imx6q_set_wakeup
 	val = readl(usbmisc->base + data->index * 4);
 	if (enabled) {
 		val |= wakeup_setting;
-		writel(val, usbmisc->base + data->index * 4);
 	} else {
 		if (val & MX6_BM_WAKEUP_INTR)
 			pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
 		val &= ~wakeup_setting;
-		writel(val, usbmisc->base + data->index * 4);
 	}
+	writel(val, usbmisc->base + data->index * 4);
 	spin_unlock_irqrestore(&usbmisc->lock, flags);
 
 	return ret;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 06b3b54a0e68..7b366a6c0b49 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -174,6 +174,7 @@ static int acm_wb_alloc(struct acm *acm)
 		wb = &acm->wb[wbn];
 		if (!wb->use) {
 			wb->use = 1;
+			wb->len = 0;
 			return wbn;
 		}
 		wbn = (wbn + 1) % ACM_NW;
@@ -805,16 +806,18 @@ static int acm_tty_write(struct tty_struct *tty,
 static void acm_tty_flush_chars(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	struct acm_wb *cur = acm->putbuffer;
+	struct acm_wb *cur;
 	int err;
 	unsigned long flags;
 
+	spin_lock_irqsave(&acm->write_lock, flags);
+
+	cur = acm->putbuffer;
 	if (!cur) /* nothing to do */
-		return;
+		goto out;
 
 	acm->putbuffer = NULL;
 	err = usb_autopm_get_interface_async(acm->control);
-	spin_lock_irqsave(&acm->write_lock, flags);
 	if (err < 0) {
 		cur->use = 0;
 		acm->putbuffer = cur;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 4024926c1d68..f4a548471f0f 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -226,6 +226,9 @@ static const struct usb_device_id usb_quirk_list[] = {
 	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
 			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+	/* Corsair K70 RGB */
+	{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
+
 	/* Corsair Strafe RGB */
 	{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT },
 
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index e4c3ce0de5de..5bcad1d869b5 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1917,7 +1917,9 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
 		/* Not specific buffer needed for ep0 ZLP */
 		dma_addr_t dma = hs_ep->desc_list_dma;
 
-		dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep);
+		if (!index)
+			dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep);
+
 		dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0);
 	} else {
 		dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
@@ -2974,9 +2976,13 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
 	if (ints & DXEPINT_STSPHSERCVD) {
 		dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__);
 
-		/* Move to STATUS IN for DDMA */
-		if (using_desc_dma(hsotg))
-			dwc2_hsotg_ep0_zlp(hsotg, true);
+		/* Safety check EP0 state when STSPHSERCVD asserted */
+		if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
+			/* Move to STATUS IN for DDMA */
+			if (using_desc_dma(hsotg))
+				dwc2_hsotg_ep0_zlp(hsotg, true);
+		}
+
 	}
 
 	if (ints & DXEPINT_BACK2BACKSETUP)
@@ -3375,12 +3381,6 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
 	dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
 	       DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);
 
-	dwc2_hsotg_enqueue_setup(hsotg);
-
-	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-		dwc2_readl(hsotg->regs + DIEPCTL0),
-		dwc2_readl(hsotg->regs + DOEPCTL0));
-
 	/* clear global NAKs */
 	val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
 	if (!is_usb_reset)
@@ -3391,6 +3391,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
 	mdelay(3);
 
 	hsotg->lx_state = DWC2_L0;
+
+	dwc2_hsotg_enqueue_setup(hsotg);
+
+	dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+		dwc2_readl(hsotg->regs + DIEPCTL0),
+		dwc2_readl(hsotg->regs + DOEPCTL0));
 }
 
 static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index ade2ab00d37a..f1d838a4acd6 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	dwc->current_dr_role = mode;
 }
 
 static void __dwc3_set_mode(struct work_struct *work)
@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work)
 
 	dwc3_set_prtcap(dwc, dwc->desired_dr_role);
 
-	dwc->current_dr_role = dwc->desired_dr_role;
-
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	switch (dwc->desired_dr_role) {
@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
 	 * XHCI driver will reset the host block. If dwc3 was configured for
 	 * host-only mode, then we can return early.
 	 */
-	if (dwc->dr_mode == USB_DR_MODE_HOST)
+	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
 		return 0;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -234,6 +234,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
 		udelay(1);
 	} while (--retries);
 
+	phy_exit(dwc->usb3_generic_phy);
+	phy_exit(dwc->usb2_generic_phy);
+
 	return -ETIMEDOUT;
 }
 
@@ -483,6 +486,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
 	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
 }
 
+static int dwc3_core_ulpi_init(struct dwc3 *dwc)
+{
+	int intf;
+	int ret = 0;
+
+	intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
+
+	if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
+	    (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
+	     dwc->hsphy_interface &&
+	     !strncmp(dwc->hsphy_interface, "ulpi", 4)))
+		ret = dwc3_ulpi_init(dwc);
+
+	return ret;
+}
+
 /**
  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
  * @dwc: Pointer to our controller context structure
@@ -494,7 +513,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
 static int dwc3_phy_setup(struct dwc3 *dwc)
 {
 	u32 reg;
-	int ret;
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
@@ -565,9 +583,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 		}
 		/* FALLTHROUGH */
 	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
-		ret = dwc3_ulpi_init(dwc);
-		if (ret)
-			return ret;
 		/* FALLTHROUGH */
 	default:
 		break;
@@ -724,6 +739,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
 }
 
 static int dwc3_core_get_phy(struct dwc3 *dwc);
+static int dwc3_core_ulpi_init(struct dwc3 *dwc);
 
 /**
  * dwc3_core_init - Low-level initialization of DWC3 Core
@@ -755,17 +771,27 @@ static int dwc3_core_init(struct dwc3 *dwc)
 			dwc->maximum_speed = USB_SPEED_HIGH;
 	}
 
-	ret = dwc3_core_get_phy(dwc);
+	ret = dwc3_phy_setup(dwc);
 	if (ret)
 		goto err0;
 
-	ret = dwc3_core_soft_reset(dwc);
-	if (ret)
-		goto err0;
+	if (!dwc->ulpi_ready) {
+		ret = dwc3_core_ulpi_init(dwc);
+		if (ret)
+			goto err0;
+		dwc->ulpi_ready = true;
+	}
 
-	ret = dwc3_phy_setup(dwc);
+	if (!dwc->phys_ready) {
+		ret = dwc3_core_get_phy(dwc);
+		if (ret)
+			goto err0a;
+		dwc->phys_ready = true;
+	}
+
+	ret = dwc3_core_soft_reset(dwc);
 	if (ret)
-		goto err0;
+		goto err0a;
 
 	dwc3_core_setup_global_control(dwc);
 	dwc3_core_num_eps(dwc);
@@ -838,6 +864,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
 	phy_exit(dwc->usb2_generic_phy);
 	phy_exit(dwc->usb3_generic_phy);
 
+err0a:
+	dwc3_ulpi_exit(dwc);
+
 err0:
 	return ret;
 }
@@ -916,7 +945,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
 	switch (dwc->dr_mode) {
 	case USB_DR_MODE_PERIPHERAL:
-		dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
 		if (dwc->usb2_phy)
@@ -932,7 +960,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 		}
 		break;
 	case USB_DR_MODE_HOST:
-		dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
 		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
 		if (dwc->usb2_phy)
@@ -1234,7 +1261,6 @@ static int dwc3_probe(struct platform_device *pdev)
 
 err3:
 	dwc3_free_event_buffers(dwc);
-	dwc3_ulpi_exit(dwc);
 
 err2:
 	pm_runtime_allow(&pdev->dev);
@@ -1284,7 +1310,7 @@ static int dwc3_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int dwc3_suspend_common(struct dwc3 *dwc)
+static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 {
 	unsigned long	flags;
 
@@ -1296,6 +1322,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
 		dwc3_core_exit(dwc);
 		break;
 	case DWC3_GCTL_PRTCAP_HOST:
+		/* do nothing during host runtime_suspend */
+		if (!PMSG_IS_AUTO(msg))
+			dwc3_core_exit(dwc);
+		break;
 	default:
 		/* do nothing */
 		break;
@@ -1304,7 +1334,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
 	return 0;
 }
 
-static int dwc3_resume_common(struct dwc3 *dwc)
+static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
 {
 	unsigned long	flags;
 	int		ret;
@@ -1320,6 +1350,13 @@ static int dwc3_resume_common(struct dwc3 *dwc)
 		spin_unlock_irqrestore(&dwc->lock, flags);
 		break;
 	case DWC3_GCTL_PRTCAP_HOST:
+		/* nothing to do on host runtime_resume */
+		if (!PMSG_IS_AUTO(msg)) {
+			ret = dwc3_core_init(dwc);
+			if (ret)
+				return ret;
+		}
+		break;
 	default:
 		/* do nothing */
 		break;
@@ -1331,12 +1368,11 @@ static int dwc3_resume_common(struct dwc3 *dwc)
 static int dwc3_runtime_checks(struct dwc3 *dwc)
 {
 	switch (dwc->current_dr_role) {
-	case USB_DR_MODE_PERIPHERAL:
-	case USB_DR_MODE_OTG:
+	case DWC3_GCTL_PRTCAP_DEVICE:
 		if (dwc->connected)
 			return -EBUSY;
 		break;
-	case USB_DR_MODE_HOST:
+	case DWC3_GCTL_PRTCAP_HOST:
 	default:
 		/* do nothing */
 		break;
@@ -1353,7 +1389,7 @@ static int dwc3_runtime_suspend(struct device *dev)
 	if (dwc3_runtime_checks(dwc))
 		return -EBUSY;
 
-	ret = dwc3_suspend_common(dwc);
+	ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
 	if (ret)
 		return ret;
 
@@ -1369,7 +1405,7 @@ static int dwc3_runtime_resume(struct device *dev)
 
 	device_init_wakeup(dev, false);
 
-	ret = dwc3_resume_common(dwc);
+	ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
 	if (ret)
 		return ret;
 
@@ -1416,7 +1452,7 @@ static int dwc3_suspend(struct device *dev)
 	struct dwc3	*dwc = dev_get_drvdata(dev);
 	int		ret;
 
-	ret = dwc3_suspend_common(dwc);
+	ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
 	if (ret)
 		return ret;
 
@@ -1432,7 +1468,7 @@ static int dwc3_resume(struct device *dev)
 
 	pinctrl_pm_select_default_state(dev);
 
-	ret = dwc3_resume_common(dwc);
+	ret = dwc3_resume_common(dwc, PMSG_RESUME);
 	if (ret)
 		return ret;
 
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 03c7aaaac926..860d2bc184d1 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -158,13 +158,15 @@
 #define DWC3_GDBGFIFOSPACE_TYPE(n)	(((n) << 5) & 0x1e0)
 #define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
 
-#define DWC3_TXFIFOQ		1
-#define DWC3_RXFIFOQ		3
-#define DWC3_TXREQQ		5
-#define DWC3_RXREQQ		7
-#define DWC3_RXINFOQ		9
-#define DWC3_DESCFETCHQ		13
-#define DWC3_EVENTQ		15
+#define DWC3_TXFIFOQ		0
+#define DWC3_RXFIFOQ		1
+#define DWC3_TXREQQ		2
+#define DWC3_RXREQQ		3
+#define DWC3_RXINFOQ		4
+#define DWC3_PSTATQ		5
+#define DWC3_DESCFETCHQ		6
+#define DWC3_EVENTQ		7
+#define DWC3_AUXEVENTQ		8
 
 /* Global RX Threshold Configuration Register */
 #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
@@ -795,7 +797,9 @@ struct dwc3_scratchpad_array {
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to USB2 PHY
  * @usb3_generic_phy: pointer to USB3 PHY
+ * @phys_ready: flag to indicate that PHYs are ready
  * @ulpi: pointer to ulpi interface
+ * @ulpi_ready: flag to indicate that ULPI is initialized
  * @u2sel: parameter from Set SEL request.
  * @u2pel: parameter from Set SEL request.
  * @u1sel: parameter from Set SEL request.
@@ -893,7 +897,10 @@ struct dwc3 {
 	struct phy		*usb2_generic_phy;
 	struct phy		*usb3_generic_phy;
 
+	bool			phys_ready;
+
 	struct ulpi		*ulpi;
+	bool			ulpi_ready;
 
 	void __iomem		*regs;
 	size_t			regs_size;
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index 7ae0eefc7cc7..e54c3622eb28 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -143,6 +143,7 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
 		clk_disable_unprepare(simple->clks[i]);
 		clk_put(simple->clks[i]);
 	}
+	simple->num_clocks = 0;
 
 	reset_control_assert(simple->resets);
 	reset_control_put(simple->resets);
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index a4719e853b85..ed8b86517675 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -582,9 +582,25 @@ static int dwc3_omap_resume(struct device *dev)
 	return 0;
 }
 
+static void dwc3_omap_complete(struct device *dev)
+{
+	struct dwc3_omap	*omap = dev_get_drvdata(dev);
+
+	if (extcon_get_state(omap->edev, EXTCON_USB))
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+	if (extcon_get_state(omap->edev, EXTCON_USB_HOST))
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+}
+
 static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
 
 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
+	.complete = dwc3_omap_complete,
 };
 
 #define DEV_PM_OPS	(&dwc3_omap_dev_pm_ops)
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 9c2e4a17918e..18be31d5743a 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -854,7 +854,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 		trb++;
 		trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
 		trace_dwc3_complete_trb(ep0, trb);
-		ep0->trb_enqueue = 0;
+
+		if (r->direction)
+			dwc->eps[1]->trb_enqueue = 0;
+		else
+			dwc->eps[0]->trb_enqueue = 0;
+
 		dwc->ep0_bounced = false;
 	}
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 616ef49ccb49..2bda4eb1e9ac 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2745,6 +2745,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 		break;
 	}
 
+	dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket;
+
 	/* Enable USB2 LPM Capability */
 
 	if ((dwc->revision > DWC3_REVISION_194A) &&
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 8f2cf3baa19c..c2592d883f67 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1855,44 +1855,20 @@ static int ffs_func_eps_enable(struct ffs_function *func)
 
 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
 	while(count--) {
-		struct usb_endpoint_descriptor *ds;
-		struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
-		int needs_comp_desc = false;
-		int desc_idx;
-
-		if (ffs->gadget->speed == USB_SPEED_SUPER) {
-			desc_idx = 2;
-			needs_comp_desc = true;
-		} else if (ffs->gadget->speed == USB_SPEED_HIGH)
-			desc_idx = 1;
-		else
-			desc_idx = 0;
-
-		/* fall-back to lower speed if desc missing for current speed */
-		do {
-			ds = ep->descs[desc_idx];
-		} while (!ds && --desc_idx >= 0);
-
-		if (!ds) {
-			ret = -EINVAL;
-			break;
-		}
-
 		ep->ep->driver_data = ep;
-		ep->ep->desc = ds;
 
-		if (needs_comp_desc) {
-			comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
-					USB_DT_ENDPOINT_SIZE);
-			ep->ep->maxburst = comp_desc->bMaxBurst + 1;
-			ep->ep->comp_desc = comp_desc;
+		ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
+		if (ret) {
+			pr_err("%s: config_ep_by_speed(%s) returned %d\n",
+					__func__, ep->ep->name, ret);
+			break;
 		}
 
 		ret = usb_ep_enable(ep->ep);
 		if (likely(!ret)) {
 			epfile->ep = ep;
-			epfile->in = usb_endpoint_dir_in(ds);
-			epfile->isoc = usb_endpoint_xfer_isoc(ds);
+			epfile->in = usb_endpoint_dir_in(ep->ep->desc);
+			epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
 		} else {
 			break;
 		}
@@ -2979,10 +2955,8 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	struct ffs_data *ffs = func->ffs;
 
 	const int full = !!func->ffs->fs_descs_count;
-	const int high = gadget_is_dualspeed(func->gadget) &&
-		func->ffs->hs_descs_count;
-	const int super = gadget_is_superspeed(func->gadget) &&
-		func->ffs->ss_descs_count;
+	const int high = !!func->ffs->hs_descs_count;
+	const int super = !!func->ffs->ss_descs_count;
 
 	int fs_len, hs_len, ss_len, ret, i;
 	struct ffs_ep *eps_ptr;
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 11fe788b4308..d2dc1f00180b 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -524,6 +524,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
 		return ret;
 	}
+	iad_desc.bFirstInterface = ret;
+
 	std_ac_if_desc.bInterfaceNumber = ret;
 	uac2->ac_intf = ret;
 	uac2->ac_alt = 0;
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 1e9567091d86..0875d38476ee 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -274,7 +274,6 @@ config USB_SNP_UDC_PLAT
 	tristate "Synopsys USB 2.0 Device controller"
 	depends on USB_GADGET && OF && HAS_DMA
 	depends on EXTCON || EXTCON=n
-	select USB_GADGET_DUALSPEED
 	select USB_SNP_CORE
 	default ARCH_BCM_IPROC
 	help
diff --git a/drivers/usb/gadget/udc/bdc/bdc_pci.c b/drivers/usb/gadget/udc/bdc/bdc_pci.c
index 1e940f054cb8..6dbc489513cd 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_pci.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_pci.c
@@ -77,6 +77,7 @@ static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
 	if (ret) {
 		dev_err(&pci->dev,
 			"couldn't add resources to bdc device\n");
+		platform_device_put(bdc);
 		return ret;
 	}
 
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 859d5b11ba4c..1f8b19d9cf97 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -180,8 +180,8 @@ EXPORT_SYMBOL_GPL(usb_ep_alloc_request);
 void usb_ep_free_request(struct usb_ep *ep,
 				       struct usb_request *req)
 {
-	ep->ops->free_request(ep, req);
 	trace_usb_ep_free_request(ep, req, 0);
+	ep->ops->free_request(ep, req);
 }
 EXPORT_SYMBOL_GPL(usb_ep_free_request);
 
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index e5b4ee96c4bf..56b517a38865 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1305,7 +1305,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
 {
 	struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
 
-	if (ep->name)
+	if (ep->ep.name)
 		nuke(ep, -ESHUTDOWN);
 }
 
@@ -1693,7 +1693,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
 		curr_ep = get_ep_by_pipe(udc, i);
 
 		/* If the ep is configured */
-		if (curr_ep->name == NULL) {
+		if (!curr_ep->ep.name) {
 			WARNING("Invalid EP?");
 			continue;
 		}
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 6e87af248367..409cde4e6a51 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -2410,7 +2410,7 @@ static int renesas_usb3_remove(struct platform_device *pdev)
 	__renesas_usb3_ep_free_request(usb3->ep0_req);
 	if (usb3->phy)
 		phy_put(usb3->phy);
-	pm_runtime_disable(usb3_to_dev(usb3));
+	pm_runtime_disable(&pdev->dev);
 
 	return 0;
 }
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index facafdf8fb95..d7641cbdee43 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -774,12 +774,12 @@ static struct urb *request_single_step_set_feature_urb(
 	atomic_inc(&urb->use_count);
 	atomic_inc(&urb->dev->urbnum);
 	urb->setup_dma = dma_map_single(
-			hcd->self.controller,
+			hcd->self.sysdev,
 			urb->setup_packet,
 			sizeof(struct usb_ctrlrequest),
 			DMA_TO_DEVICE);
 	urb->transfer_dma = dma_map_single(
-			hcd->self.controller,
+			hcd->self.sysdev,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
 			DMA_FROM_DEVICE);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 88158324dcae..327630405695 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1188,10 +1188,10 @@ static int submit_single_step_set_feature(
 	 * 15 secs after the setup
 	 */
 	if (is_setup) {
-		/* SETUP pid */
+		/* SETUP pid, and interrupt after SETUP completion */
 		qtd_fill(ehci, qtd, urb->setup_dma,
 				sizeof(struct usb_ctrlrequest),
-				token | (2 /* "setup" */ << 8), 8);
+				QTD_IOC | token | (2 /* "setup" */ << 8), 8);
 
 		submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
 		return 0; /*Return now; we shall come back after 15 seconds*/
@@ -1228,12 +1228,8 @@ static int submit_single_step_set_feature(
 	qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
 	list_add_tail(&qtd->qtd_list, head);
 
-	/* dont fill any data in such packets */
-	qtd_fill(ehci, qtd, 0, 0, token, 0);
-
-	/* by default, enable interrupt on urb completion */
-	if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
-		qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
+	/* Interrupt after STATUS completion */
+	qtd_fill(ehci, qtd, 0, 0, token | QTD_IOC, 0);
 
 	submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
 
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index ee9676349333..84f88fa411cd 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -74,6 +74,7 @@ static const char	hcd_name [] = "ohci_hcd";
 
 #define	STATECHANGE_DELAY	msecs_to_jiffies(300)
 #define	IO_WATCHDOG_DELAY	msecs_to_jiffies(275)
+#define	IO_WATCHDOG_OFF		0xffffff00
 
 #include "ohci.h"
 #include "pci-quirks.h"
@@ -231,7 +232,7 @@ static int ohci_urb_enqueue (
 		}
 
 		/* Start up the I/O watchdog timer, if it's not running */
-		if (!timer_pending(&ohci->io_watchdog) &&
+		if (ohci->prev_frame_no == IO_WATCHDOG_OFF &&
 				list_empty(&ohci->eds_in_use) &&
 				!(ohci->flags & OHCI_QUIRK_QEMU)) {
 			ohci->prev_frame_no = ohci_frame_no(ohci);
@@ -501,6 +502,7 @@ static int ohci_init (struct ohci_hcd *ohci)
 		return 0;
 
 	timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
+	ohci->prev_frame_no = IO_WATCHDOG_OFF;
 
 	ohci->hcca = dma_alloc_coherent (hcd->self.controller,
 			sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
@@ -730,7 +732,7 @@ static void io_watchdog_func(struct timer_list *t)
 	u32		head;
 	struct ed	*ed;
 	struct td	*td, *td_start, *td_next;
-	unsigned	frame_no;
+	unsigned	frame_no, prev_frame_no = IO_WATCHDOG_OFF;
 	unsigned long	flags;
 
 	spin_lock_irqsave(&ohci->lock, flags);
@@ -835,7 +837,7 @@ static void io_watchdog_func(struct timer_list *t)
 			}
 		}
 		if (!list_empty(&ohci->eds_in_use)) {
-			ohci->prev_frame_no = frame_no;
+			prev_frame_no = frame_no;
 			ohci->prev_wdh_cnt = ohci->wdh_cnt;
 			ohci->prev_donehead = ohci_readl(ohci,
 					&ohci->regs->donehead);
@@ -845,6 +847,7 @@ static void io_watchdog_func(struct timer_list *t)
 	}
 
  done:
+	ohci->prev_frame_no = prev_frame_no;
 	spin_unlock_irqrestore(&ohci->lock, flags);
 }
 
@@ -973,6 +976,7 @@ static void ohci_stop (struct usb_hcd *hcd)
 	if (quirk_nec(ohci))
 		flush_work(&ohci->nec_work);
 	del_timer_sync(&ohci->io_watchdog);
+	ohci->prev_frame_no = IO_WATCHDOG_OFF;
 
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
 	ohci_usb_reset(ohci);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index fb7aaa3b9d06..634f3c7bf774 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -311,8 +311,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
 		rc = ohci_rh_suspend (ohci, 0);
 	spin_unlock_irq (&ohci->lock);
 
-	if (rc == 0)
+	if (rc == 0) {
 		del_timer_sync(&ohci->io_watchdog);
+		ohci->prev_frame_no = IO_WATCHDOG_OFF;
+	}
 	return rc;
 }
 
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index b2ec8c399363..4ccb85a67bb3 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -1019,6 +1019,8 @@ static void finish_unlinks(struct ohci_hcd *ohci)
 		 * have modified this list.  normally it's just prepending
 		 * entries (which we'd ignore), but paranoia won't hurt.
 		 */
+		*last = ed->ed_next;
+		ed->ed_next = NULL;
 		modified = 0;
 
 		/* unlink urbs as requested, but rescan the list after
@@ -1077,21 +1079,22 @@ static void finish_unlinks(struct ohci_hcd *ohci)
 			goto rescan_this;
 
 		/*
-		 * If no TDs are queued, take ED off the ed_rm_list.
+		 * If no TDs are queued, ED is now idle.
 		 * Otherwise, if the HC is running, reschedule.
-		 * If not, leave it on the list for further dequeues.
+		 * If the HC isn't running, add ED back to the
+		 * start of the list for later processing.
 		 */
 		if (list_empty(&ed->td_list)) {
-			*last = ed->ed_next;
-			ed->ed_next = NULL;
 			ed->state = ED_IDLE;
 			list_del(&ed->in_use_list);
 		} else if (ohci->rh_state == OHCI_RH_RUNNING) {
-			*last = ed->ed_next;
-			ed->ed_next = NULL;
 			ed_schedule(ohci, ed);
 		} else {
-			last = &ed->ed_next;
+			ed->ed_next = ohci->ed_rm_list;
+			ohci->ed_rm_list = ed;
+			/* Don't loop on the same ED */
+			if (last == &ohci->ed_rm_list)
+				last = &ed->ed_next;
 		}
 
 		if (modified)
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 161536717025..67ad4bb6919a 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -66,6 +66,23 @@
 #define	AX_INDXC		0x30
 #define	AX_DATAC		0x34
 
+#define PT_ADDR_INDX		0xE8
+#define PT_READ_INDX		0xE4
+#define PT_SIG_1_ADDR		0xA520
+#define PT_SIG_2_ADDR		0xA521
+#define PT_SIG_3_ADDR		0xA522
+#define PT_SIG_4_ADDR		0xA523
+#define PT_SIG_1_DATA		0x78
+#define PT_SIG_2_DATA		0x56
+#define PT_SIG_3_DATA		0x34
+#define PT_SIG_4_DATA		0x12
+#define PT4_P1_REG		0xB521
+#define PT4_P2_REG		0xB522
+#define PT2_P1_REG		0xD520
+#define PT2_P2_REG		0xD521
+#define PT1_P1_REG		0xD522
+#define PT1_P2_REG		0xD523
+
 #define	NB_PCIE_INDX_ADDR	0xe0
 #define	NB_PCIE_INDX_DATA	0xe4
 #define	PCIE_P_CNTL		0x10040
@@ -512,6 +529,98 @@ void usb_amd_dev_put(void)
 }
 EXPORT_SYMBOL_GPL(usb_amd_dev_put);
 
+/*
+ * Check if port is disabled in BIOS on AMD Promontory host.
+ * BIOS Disabled ports may wake on connect/disconnect and need
+ * driver workaround to keep them disabled.
+ * Returns true if port is marked disabled.
+ */
+bool usb_amd_pt_check_port(struct device *device, int port)
+{
+	unsigned char value, port_shift;
+	struct pci_dev *pdev;
+	u16 reg;
+
+	pdev = to_pci_dev(device);
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_1_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_1_DATA)
+		return false;
+
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_2_DATA)
+		return false;
+
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_3_DATA)
+		return false;
+
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_4_DATA)
+		return false;
+
+	/* Check disabled port setting, if bit is set port is enabled */
+	switch (pdev->device) {
+	case 0x43b9:
+	case 0x43ba:
+	/*
+	 * device is AMD_PROMONTORYA_4(0x43b9) or PROMONTORYA_3(0x43ba)
+	 * PT4_P1_REG bits[7..1] represents USB2.0 ports 6 to 0
+	 * PT4_P2_REG bits[6..0] represents ports 13 to 7
+	 */
+		if (port > 6) {
+			reg = PT4_P2_REG;
+			port_shift = port - 7;
+		} else {
+			reg = PT4_P1_REG;
+			port_shift = port + 1;
+		}
+		break;
+	case 0x43bb:
+	/*
+	 * device is AMD_PROMONTORYA_2(0x43bb)
+	 * PT2_P1_REG bits[7..5] represents USB2.0 ports 2 to 0
+	 * PT2_P2_REG bits[5..0] represents ports 9 to 3
+	 */
+		if (port > 2) {
+			reg = PT2_P2_REG;
+			port_shift = port - 3;
+		} else {
+			reg = PT2_P1_REG;
+			port_shift = port + 5;
+		}
+		break;
+	case 0x43bc:
+	/*
+	 * device is AMD_PROMONTORYA_1(0x43bc)
+	 * PT1_P1_REG[7..4] represents USB2.0 ports 3 to 0
+	 * PT1_P2_REG[5..0] represents ports 9 to 4
+	 */
+		if (port > 3) {
+			reg = PT1_P2_REG;
+			port_shift = port - 4;
+		} else {
+			reg = PT1_P1_REG;
+			port_shift = port + 4;
+		}
+		break;
+	default:
+		return false;
+	}
+	pci_write_config_word(pdev, PT_ADDR_INDX, reg);
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+
+	return !(value & BIT(port_shift));
+}
+EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
+
 /*
  * Make sure the controller is completely inactive, unable to
  * generate interrupts or do DMA.
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index b68dcb5dd0fd..4ca0d9b7e463 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -17,6 +17,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
 bool usb_xhci_needs_pci_reset(struct pci_dev *pdev);
+bool usb_amd_pt_check_port(struct device *device, int port);
 #else
 struct pci_dev;
 static inline void usb_amd_quirk_pll_disable(void) {}
@@ -25,6 +26,10 @@ static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
 static inline void usb_amd_dev_put(void) {}
 static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
 static inline void sb800_prefetch(struct device *dev, int on) {}
+static inline bool usb_amd_pt_check_port(struct device *device, int port)
+{
+	return false;
+}
 #endif  /* CONFIG_USB_PCI */
 
 #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index e26e685d8a57..5851052d4668 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -211,7 +211,7 @@ static void xhci_ring_dump_segment(struct seq_file *s,
 static int xhci_ring_trb_show(struct seq_file *s, void *unused)
 {
 	int			i;
-	struct xhci_ring	*ring = s->private;
+	struct xhci_ring	*ring = *(struct xhci_ring **)s->private;
 	struct xhci_segment	*seg = ring->first_seg;
 
 	for (i = 0; i < ring->num_segs; i++) {
@@ -387,7 +387,7 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci,
 
 	snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index);
 	epriv->root = xhci_debugfs_create_ring_dir(xhci,
-						   &dev->eps[ep_index].new_ring,
+						   &dev->eps[ep_index].ring,
 						   epriv->name,
 						   spriv->root);
 	spriv->eps[ep_index] = epriv;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 46d5e08f05f1..72ebbc908e19 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1224,17 +1224,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 				temp = readl(port_array[wIndex]);
 				break;
 			}
-
-			/* Software should not attempt to set
-			 * port link state above '3' (U3) and the port
-			 * must be enabled.
-			 */
-			if ((temp & PORT_PE) == 0 ||
-				(link_state > USB_SS_PORT_LS_U3)) {
-				xhci_warn(xhci, "Cannot set link state.\n");
+			/* Port must be enabled */
+			if (!(temp & PORT_PE)) {
+				retval = -ENODEV;
+				break;
+			}
+			/* Can't set port link state above '3' (U3) */
+			if (link_state > USB_SS_PORT_LS_U3) {
+				xhci_warn(xhci, "Cannot set port %d link state %d\n",
+					 wIndex, link_state);
 				goto error;
 			}
-
 			if (link_state == USB_SS_PORT_LS_U3) {
 				slot_id = xhci_find_slot_id_by_port(hcd, xhci,
 						wIndex + 1);
@@ -1522,6 +1522,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
 				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
 				t2 &= ~PORT_WKDISC_E;
 			}
+
+			if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
+			    (hcd->speed < HCD_USB3)) {
+				if (usb_amd_pt_check_port(hcd->self.controller,
+							  port_index))
+					t2 &= ~PORT_WAKE_BITS;
+			}
 		} else
 			t2 &= ~PORT_WAKE_BITS;
 
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 6c79037876db..5262fa571a5d 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -42,6 +42,10 @@
 #define PCI_DEVICE_ID_INTEL_APL_XHCI			0x5aa8
 #define PCI_DEVICE_ID_INTEL_DNV_XHCI			0x19d0
 
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_4			0x43b9
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_3			0x43ba
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_2			0x43bb
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_1			0x43bc
 #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI		0x1142
 
 static const char hcd_name[] = "xhci_hcd";
@@ -125,6 +129,13 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	if (pdev->vendor == PCI_VENDOR_ID_AMD)
 		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 
+	if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+		((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+		(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
+		(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
+		(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
+		xhci->quirks |= XHCI_U2_DISABLE_WAKE;
+
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 		xhci->quirks |= XHCI_LPM_SUPPORT;
 		xhci->quirks |= XHCI_INTEL_HOST;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 1eeb3396300f..25d4b748a56f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -646,8 +646,6 @@ static void xhci_stop(struct usb_hcd *hcd)
 		return;
 	}
 
-	xhci_debugfs_exit(xhci);
-
 	xhci_dbc_exit(xhci);
 
 	spin_lock_irq(&xhci->lock);
@@ -680,6 +678,7 @@ static void xhci_stop(struct usb_hcd *hcd)
 
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
 	xhci_mem_cleanup(xhci);
+	xhci_debugfs_exit(xhci);
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			"xhci_stop completed - status = %x",
 			readl(&xhci->op_regs->status));
@@ -1014,6 +1013,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 
 		xhci_dbg(xhci, "cleaning up memory\n");
 		xhci_mem_cleanup(xhci);
+		xhci_debugfs_exit(xhci);
 		xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
 			    readl(&xhci->op_regs->status));
 
@@ -3544,12 +3544,10 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
 		virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
 		del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
 	}
-
+	xhci_debugfs_remove_slot(xhci, udev->slot_id);
 	ret = xhci_disable_slot(xhci, udev->slot_id);
-	if (ret) {
-		xhci_debugfs_remove_slot(xhci, udev->slot_id);
+	if (ret)
 		xhci_free_virt_device(xhci, udev->slot_id);
-	}
 }
 
 int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 96099a245c69..e4d7d3d06a75 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1822,7 +1822,7 @@ struct xhci_hcd {
 /* For controller with a broken Port Disable implementation */
 #define XHCI_BROKEN_PORT_PED	(1 << 25)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7	(1 << 26)
-/* Reserved. It was XHCI_U2_DISABLE_WAKE */
+#define XHCI_U2_DISABLE_WAKE	(1 << 27)
 #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL	(1 << 28)
 #define XHCI_HW_LPM_DISABLE	(1 << 29)
 
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 63b9e85dc0e9..236a60f53099 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -42,6 +42,9 @@
 #define USB_DEVICE_ID_LD_MICROCASSYTIME		0x1033	/* USB Product ID of Micro-CASSY Time (reserved) */
 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE	0x1035	/* USB Product ID of Micro-CASSY Temperature */
 #define USB_DEVICE_ID_LD_MICROCASSYPH		0x1038	/* USB Product ID of Micro-CASSY pH */
+#define USB_DEVICE_ID_LD_POWERANALYSERCASSY	0x1040	/* USB Product ID of Power Analyser CASSY */
+#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY	0x1042	/* USB Product ID of Converter Controller CASSY */
+#define USB_DEVICE_ID_LD_MACHINETESTCASSY	0x1043	/* USB Product ID of Machine Test CASSY */
 #define USB_DEVICE_ID_LD_JWM		0x1080	/* USB Product ID of Joule and Wattmeter */
 #define USB_DEVICE_ID_LD_DMMP		0x1081	/* USB Product ID of Digital Multimeter P (reserved) */
 #define USB_DEVICE_ID_LD_UMIP		0x1090	/* USB Product ID of UMI P */
@@ -84,6 +87,9 @@ static const struct usb_device_id ld_usb_table[] = {
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
+	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
+	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
 	{ USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index da031c45395a..fbec863350f6 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -602,6 +602,9 @@ static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy)
 	void __iomem *base = phy->io_priv;
 	enum usb_charger_type chgr_type = UNKNOWN_TYPE;
 
+	if (!regmap)
+		return UNKNOWN_TYPE;
+
 	if (mxs_charger_data_contact_detect(mxs_phy))
 		return chgr_type;
 
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 5925d111bd47..39fa2fc1b8b7 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -982,6 +982,10 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt,
 	if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1))
 		goto usbhsf_pio_prepare_pop;
 
+	/* return at this time if the pipe is running */
+	if (usbhs_pipe_is_running(pipe))
+		return 0;
+
 	usbhs_pipe_config_change_bfre(pipe, 1);
 
 	ret = usbhsf_fifo_select(pipe, fifo, 0);
@@ -1172,6 +1176,7 @@ static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt,
 	usbhsf_fifo_clear(pipe, fifo);
 	pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len);
 
+	usbhs_pipe_running(pipe, 0);
 	usbhsf_dma_stop(pipe, fifo);
 	usbhsf_dma_unmap(pkt);
 	usbhsf_fifo_unselect(pipe, pipe->fifo);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5db8ed517e0e..2d8d9150da0c 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -241,6 +241,7 @@ static void option_instat_callback(struct urb *urb);
 #define QUECTEL_PRODUCT_EC21			0x0121
 #define QUECTEL_PRODUCT_EC25			0x0125
 #define QUECTEL_PRODUCT_BG96			0x0296
+#define QUECTEL_PRODUCT_EP06			0x0306
 
 #define CMOTECH_VENDOR_ID			0x16d8
 #define CMOTECH_PRODUCT_6001			0x6001
@@ -689,6 +690,10 @@ static const struct option_blacklist_info yuga_clm920_nc5_blacklist = {
 	.reserved = BIT(1) | BIT(4),
 };
 
+static const struct option_blacklist_info quectel_ep06_blacklist = {
+	.reserved = BIT(4) | BIT(5),
+};
+
 static const struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -1203,6 +1208,8 @@ static const struct usb_device_id option_ids[] = {
 	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
 	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
 	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+	{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06),
+	  .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index 49e552472c3f..dd8ef36ab10e 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -73,6 +73,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
 			goto err;
 
 		sdev->ud.tcp_socket = socket;
+		sdev->ud.sockfd = sockfd;
 
 		spin_unlock_irq(&sdev->ud.lock);
 
@@ -172,6 +173,7 @@ static void stub_shutdown_connection(struct usbip_device *ud)
 	if (ud->tcp_socket) {
 		sockfd_put(ud->tcp_socket);
 		ud->tcp_socket = NULL;
+		ud->sockfd = -1;
 	}
 
 	/* 3. free used data */
@@ -266,6 +268,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)
 	sdev->ud.status		= SDEV_ST_AVAILABLE;
 	spin_lock_init(&sdev->ud.lock);
 	sdev->ud.tcp_socket	= NULL;
+	sdev->ud.sockfd		= -1;
 
 	INIT_LIST_HEAD(&sdev->priv_init);
 	INIT_LIST_HEAD(&sdev->priv_tx);
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index c3e1008aa491..20e3d4609583 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -984,6 +984,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
 	if (vdev->ud.tcp_socket) {
 		sockfd_put(vdev->ud.tcp_socket);
 		vdev->ud.tcp_socket = NULL;
+		vdev->ud.sockfd = -1;
 	}
 	pr_info("release socket\n");
 
@@ -1030,6 +1031,7 @@ static void vhci_device_reset(struct usbip_device *ud)
 	if (ud->tcp_socket) {
 		sockfd_put(ud->tcp_socket);
 		ud->tcp_socket = NULL;
+		ud->sockfd = -1;
 	}
 	ud->status = VDEV_ST_NULL;
 
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 610cba276d47..b5fb56b822fd 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1038,7 +1038,7 @@ static struct socket *get_raw_socket(int fd)
 		struct sockaddr_ll sa;
 		char  buf[MAX_ADDR_LEN];
 	} uaddr;
-	int uaddr_len = sizeof uaddr, r;
+	int r;
 	struct socket *sock = sockfd_lookup(fd, &r);
 
 	if (!sock)
@@ -1050,9 +1050,8 @@ static struct socket *get_raw_socket(int fd)
 		goto err;
 	}
 
-	r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
-			       &uaddr_len, 0);
-	if (r)
+	r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, 0);
+	if (r < 0)
 		goto err;
 
 	if (uaddr.sa.sll_family != AF_PACKET) {
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
index 734a9158946b..ca544aa764b8 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -28,8 +28,6 @@ enum as3711_bl_type {
 
 struct as3711_bl_data {
 	bool powered;
-	const char *fb_name;
-	struct device *fb_dev;
 	enum as3711_bl_type type;
 	int brightness;
 	struct backlight_device *bl;
@@ -262,10 +260,10 @@ static int as3711_bl_register(struct platform_device *pdev,
 static int as3711_backlight_parse_dt(struct device *dev)
 {
 	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
-	struct device_node *bl =
-		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
+	struct device_node *bl, *fb;
 	int ret;
 
+	bl = of_get_child_by_name(dev->parent->of_node, "backlight");
 	if (!bl) {
 		dev_dbg(dev, "backlight node not found\n");
 		return -ENODEV;
@@ -273,26 +271,30 @@ static int as3711_backlight_parse_dt(struct device *dev)
 
 	fb = of_parse_phandle(bl, "su1-dev", 0);
 	if (fb) {
-		pdata->su1_fb = fb->full_name;
+		of_node_put(fb);
+
+		pdata->su1_fb = true;
 
 		ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
 		if (pdata->su1_max_uA <= 0)
 			ret = -EINVAL;
 		if (ret < 0)
-			return ret;
+			goto err_put_bl;
 	}
 
 	fb = of_parse_phandle(bl, "su2-dev", 0);
 	if (fb) {
 		int count = 0;
 
-		pdata->su2_fb = fb->full_name;
+		of_node_put(fb);
+
+		pdata->su2_fb = true;
 
 		ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
 		if (pdata->su2_max_uA <= 0)
 			ret = -EINVAL;
 		if (ret < 0)
-			return ret;
+			goto err_put_bl;
 
 		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
 			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
@@ -314,8 +316,10 @@ static int as3711_backlight_parse_dt(struct device *dev)
 			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
 			count++;
 		}
-		if (count != 1)
-			return -EINVAL;
+		if (count != 1) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 
 		count = 0;
 		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
@@ -334,8 +338,10 @@ static int as3711_backlight_parse_dt(struct device *dev)
 			pdata->su2_fbprot = AS3711_SU2_GPIO4;
 			count++;
 		}
-		if (count != 1)
-			return -EINVAL;
+		if (count != 1) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 
 		count = 0;
 		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
@@ -355,11 +361,20 @@ static int as3711_backlight_parse_dt(struct device *dev)
 		 * At least one su2-auto-curr* must be specified iff
 		 * AS3711_SU2_CURR_AUTO is used
 		 */
-		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO))
-			return -EINVAL;
+		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 	}
 
+	of_node_put(bl);
+
 	return 0;
+
+err_put_bl:
+	of_node_put(bl);
+
+	return ret;
 }
 
 static int as3711_backlight_probe(struct platform_device *pdev)
@@ -412,7 +427,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
 
 	if (pdata->su1_fb) {
 		su = &supply->su1;
-		su->fb_name = pdata->su1_fb;
 		su->type = AS3711_BL_SU1;
 
 		max_brightness = min(pdata->su1_max_uA, 31);
@@ -423,7 +437,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
 
 	if (pdata->su2_fb) {
 		su = &supply->su2;
-		su->fb_name = pdata->su2_fb;
 		su->type = AS3711_BL_SU2;
 
 		switch (pdata->su2_fbprot) {
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index 7b738d60ecc2..f3aa6088f1d9 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
 	if (!pdata)
 		return;
 
-	np = of_find_node_by_name(nproot, "backlight");
+	np = of_get_child_by_name(nproot, "backlight");
 	if (!np) {
 		dev_err(&pdev->dev, "failed to find backlight node\n");
 		return;
@@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
 	if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
 		pdata->dual_string = val;
 
+	of_node_put(np);
+
 	pdev->dev.platform_data = pdata;
 }
 
diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c
index 380917c86276..762e3feed097 100644
--- a/drivers/video/backlight/tps65217_bl.c
+++ b/drivers/video/backlight/tps65217_bl.c
@@ -184,11 +184,11 @@ static struct tps65217_bl_pdata *
 tps65217_bl_parse_dt(struct platform_device *pdev)
 {
 	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
-	struct device_node *node = of_node_get(tps->dev->of_node);
+	struct device_node *node;
 	struct tps65217_bl_pdata *pdata, *err;
 	u32 val;
 
-	node = of_find_node_by_name(node, "backlight");
+	node = of_get_child_by_name(tps->dev->of_node, "backlight");
 	if (!node)
 		return ERR_PTR(-ENODEV);
 
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index aff773bcebdb..37460cd6cabb 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -226,6 +226,7 @@ config ZIIRAVE_WATCHDOG
 config RAVE_SP_WATCHDOG
 	tristate "RAVE SP Watchdog timer"
 	depends on RAVE_SP_CORE
+	depends on NVMEM || !NVMEM
 	select WATCHDOG_CORE
 	help
 	  Support for the watchdog on RAVE SP device.
@@ -903,6 +904,7 @@ config F71808E_WDT
 config SP5100_TCO
 	tristate "AMD/ATI SP5100 TCO Timer/Watchdog"
 	depends on X86 && PCI
+	select WATCHDOG_CORE
 	---help---
 	  Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO
 	  (Total Cost of Ownership) timer is a watchdog timer that will reboot
@@ -1008,6 +1010,7 @@ config WAFER_WDT
 config I6300ESB_WDT
 	tristate "Intel 6300ESB Timer/Watchdog"
 	depends on PCI
+	select WATCHDOG_CORE
 	---help---
 	  Hardware driver for the watchdog timer built into the Intel
 	  6300ESB controller hub.
@@ -1837,6 +1840,7 @@ config WATCHDOG_SUN4V
 config XEN_WDT
 	tristate "Xen Watchdog support"
 	depends on XEN
+	select WATCHDOG_CORE
 	help
 	  Say Y here to support the hypervisor watchdog capability provided
 	  by Xen 4.0 and newer.  The watchdog timeout period is normally one
diff --git a/fs/befs/btree.c b/fs/befs/btree.c
index 1b7e0f7128d6..76a401c48bae 100644
--- a/fs/befs/btree.c
+++ b/fs/befs/btree.c
@@ -6,7 +6,7 @@
  * Licensed under the GNU GPL. See the file COPYING for details.
  *
  * 2002-02-05: Sergey S. Kostyliov added binary search within
- * 		btree nodes.
+ *	btree nodes.
  *
  * Many thanks to:
  *
@@ -88,13 +88,15 @@ struct befs_btree_node {
 static const befs_off_t BEFS_BT_INVAL = 0xffffffffffffffffULL;
 
 /* local functions */
-static int befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds,
-			       befs_btree_super * bt_super,
+static int befs_btree_seekleaf(struct super_block *sb,
+			       const befs_data_stream *ds,
+			       befs_btree_super *bt_super,
 			       struct befs_btree_node *this_node,
-			       befs_off_t * node_off);
+			       befs_off_t *node_off);
 
-static int befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds,
-			      befs_btree_super * sup);
+static int befs_bt_read_super(struct super_block *sb,
+			      const befs_data_stream *ds,
+			      befs_btree_super *sup);
 
 static int befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds,
 			     struct befs_btree_node *node,
@@ -110,11 +112,11 @@ static char *befs_bt_keydata(struct befs_btree_node *node);
 
 static int befs_find_key(struct super_block *sb,
 			 struct befs_btree_node *node,
-			 const char *findkey, befs_off_t * value);
+			 const char *findkey, befs_off_t *value);
 
 static char *befs_bt_get_key(struct super_block *sb,
 			     struct befs_btree_node *node,
-			     int index, u16 * keylen);
+			     int index, u16 *keylen);
 
 static int befs_compare_strings(const void *key1, int keylen1,
 				const void *key2, int keylen2);
@@ -132,7 +134,7 @@ static int befs_compare_strings(const void *key1, int keylen1,
  */
 static int
 befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds,
-		   befs_btree_super * sup)
+		   befs_btree_super *sup)
 {
 	struct buffer_head *bh;
 	befs_disk_btree_super *od_sup;
@@ -163,7 +165,7 @@ befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds,
 	befs_debug(sb, "<--- %s", __func__);
 	return BEFS_OK;
 
-      error:
+error:
 	befs_debug(sb, "<--- %s ERROR", __func__);
 	return BEFS_ERR;
 }
@@ -200,8 +202,8 @@ befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds,
 
 	node->bh = befs_read_datastream(sb, ds, node_off, &off);
 	if (!node->bh) {
-		befs_error(sb, "%s failed to read "
-			   "node at %llu", __func__, node_off);
+		befs_error(sb, "%s failed to read node at %llu",
+			__func__, node_off);
 		befs_debug(sb, "<--- %s ERROR", __func__);
 
 		return BEFS_ERR;
@@ -243,7 +245,7 @@ befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds,
  */
 int
 befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
-		const char *key, befs_off_t * value)
+		const char *key, befs_off_t *value)
 {
 	struct befs_btree_node *this_node;
 	befs_btree_super bt_super;
@@ -253,16 +255,16 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
 	befs_debug(sb, "---> %s Key: %s", __func__, key);
 
 	if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {
-		befs_error(sb,
-			   "befs_btree_find() failed to read index superblock");
+		befs_error(sb, "%s() failed to read index superblock",
+			__func__);
 		goto error;
 	}
 
 	this_node = kmalloc(sizeof(struct befs_btree_node),
 						GFP_NOFS);
 	if (!this_node) {
-		befs_error(sb, "befs_btree_find() failed to allocate %zu "
-			   "bytes of memory", sizeof(struct befs_btree_node));
+		befs_error(sb, "%s() failed to allocate %zu bytes of memory",
+			__func__, sizeof(struct befs_btree_node));
 		goto error;
 	}
 
@@ -271,8 +273,8 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
 	/* read in root node */
 	node_off = bt_super.root_node_ptr;
 	if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
-		befs_error(sb, "befs_btree_find() failed to read "
-			   "node at %llu", node_off);
+		befs_error(sb, "%s() failed to read node at %llu",
+			__func__, node_off);
 		goto error_alloc;
 	}
 
@@ -282,8 +284,8 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
 		if (res == BEFS_BT_OVERFLOW)
 			node_off = this_node->head.overflow;
 		if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) {
-			befs_error(sb, "befs_btree_find() failed to read "
-				   "node at %llu", node_off);
+			befs_error(sb, "%s() failed to read node at %llu",
+				__func__, node_off);
 			goto error_alloc;
 		}
 	}
@@ -304,9 +306,9 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
 		   key, *value);
 	return BEFS_OK;
 
-      error_alloc:
+error_alloc:
 	kfree(this_node);
-      error:
+error:
 	*value = 0;
 	befs_debug(sb, "<--- %s ERROR", __func__);
 	return BEFS_ERR;
@@ -328,7 +330,7 @@ befs_btree_find(struct super_block *sb, const befs_data_stream *ds,
  */
 static int
 befs_find_key(struct super_block *sb, struct befs_btree_node *node,
-	      const char *findkey, befs_off_t * value)
+	      const char *findkey, befs_off_t *value)
 {
 	int first, last, mid;
 	int eq;
@@ -409,8 +411,8 @@ befs_find_key(struct super_block *sb, struct befs_btree_node *node,
  */
 int
 befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
-		loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize,
-		befs_off_t * value)
+		loff_t key_no, size_t bufsize, char *keybuf, size_t *keysize,
+		befs_off_t *value)
 {
 	struct befs_btree_node *this_node;
 	befs_btree_super bt_super;
@@ -426,15 +428,15 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
 	befs_debug(sb, "---> %s", __func__);
 
 	if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) {
-		befs_error(sb,
-			   "befs_btree_read() failed to read index superblock");
+		befs_error(sb, "%s() failed to read index superblock",
+			__func__);
 		goto error;
 	}
 
 	this_node = kmalloc(sizeof(struct befs_btree_node), GFP_NOFS);
 	if (this_node == NULL) {
-		befs_error(sb, "befs_btree_read() failed to allocate %zu "
-			   "bytes of memory", sizeof(struct befs_btree_node));
+		befs_error(sb, "%s() failed to allocate %zu bytes of memory",
+			__func__, sizeof(struct befs_btree_node));
 		goto error;
 	}
 
@@ -490,12 +492,12 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
 	keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen);
 
 	befs_debug(sb, "Read [%llu,%d]: keysize %d",
-		   (long long unsigned int)node_off, (int)cur_key,
+		   (unsigned long long int)node_off, (int)cur_key,
 		   (int)keylen);
 
 	if (bufsize < keylen + 1) {
-		befs_error(sb, "%s keybuf too small (%zu) "
-			   "for key of size %d", __func__, bufsize, keylen);
+		befs_error(sb, "%s keybuf too small (%zu) for key of size %d",
+			__func__, bufsize, keylen);
 		brelse(this_node->bh);
 		goto error_alloc;
 	}
@@ -514,10 +516,10 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
 
 	return BEFS_OK;
 
-      error_alloc:
+error_alloc:
 	kfree(this_node);
 
-      error:
+error:
 	*keysize = 0;
 	*value = 0;
 	befs_debug(sb, "<--- %s ERROR", __func__);
@@ -531,7 +533,7 @@ befs_btree_read(struct super_block *sb, const befs_data_stream *ds,
  * @bt_super: Pointer to the superblock of the btree
  * @this_node: Buffer to return the leafnode in
  * @node_off: Pointer to offset of current node within datastream. Modified
- * 		by the function.
+ *	by the function.
  *
  * Helper function for btree traverse. Moves the current position to the
  * start of the first leaf node.
@@ -542,14 +544,14 @@ static int
 befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds,
 		    befs_btree_super *bt_super,
 		    struct befs_btree_node *this_node,
-		    befs_off_t * node_off)
+		    befs_off_t *node_off)
 {
 
 	befs_debug(sb, "---> %s", __func__);
 
 	if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
-		befs_error(sb, "%s failed to read "
-			   "node at %llu", __func__, *node_off);
+		befs_error(sb, "%s failed to read node at %llu",
+			   __func__, *node_off);
 		goto error;
 	}
 	befs_debug(sb, "Seekleaf to root node %llu", *node_off);
@@ -572,8 +574,8 @@ befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds,
 			*node_off = fs64_to_cpu(sb, valarray[0]);
 		}
 		if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
-			befs_error(sb, "%s failed to read "
-				   "node at %llu", __func__, *node_off);
+			befs_error(sb, "%s failed to read node at %llu",
+				__func__, *node_off);
 			goto error;
 		}
 
@@ -583,7 +585,7 @@ befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds,
 
 	return BEFS_OK;
 
-      error:
+error:
 	befs_debug(sb, "<--- %s ERROR", __func__);
 	return BEFS_ERR;
 }
@@ -623,7 +625,7 @@ befs_bt_keylen_index(struct befs_btree_node *node)
 {
 	const int keylen_align = 8;
 	unsigned long int off =
-	    (sizeof (befs_btree_nodehead) + node->head.all_key_length);
+	    (sizeof(befs_btree_nodehead) + node->head.all_key_length);
 	ulong tmp = off % keylen_align;
 
 	if (tmp)
@@ -643,7 +645,7 @@ static fs64 *
 befs_bt_valarray(struct befs_btree_node *node)
 {
 	void *keylen_index_start = (void *) befs_bt_keylen_index(node);
-	size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
+	size_t keylen_index_size = node->head.all_key_count * sizeof(fs16);
 
 	return (fs64 *) (keylen_index_start + keylen_index_size);
 }
@@ -658,7 +660,7 @@ befs_bt_valarray(struct befs_btree_node *node)
 static char *
 befs_bt_keydata(struct befs_btree_node *node)
 {
-	return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead));
+	return (char *) ((void *) node->od_node + sizeof(befs_btree_nodehead));
 }
 
 /**
@@ -673,7 +675,7 @@ befs_bt_keydata(struct befs_btree_node *node)
  */
 static char *
 befs_bt_get_key(struct super_block *sb, struct befs_btree_node *node,
-		int index, u16 * keylen)
+		int index, u16 *keylen)
 {
 	int prev_key_end;
 	char *keystart;
@@ -714,6 +716,7 @@ befs_compare_strings(const void *key1, int keylen1,
 {
 	int len = min_t(int, keylen1, keylen2);
 	int result = strncmp(key1, key2, len);
+
 	if (result == 0)
 		result = keylen1 - keylen2;
 	return result;
@@ -765,6 +768,7 @@ static int
 btree_compare_float(cont void *key1, int keylen1, const void *key2, int keylen2)
 {
 	float result = *(float *) key1 - *(float *) key2;
+
 	if (result == 0.0f)
 		return 0;
 
@@ -776,6 +780,7 @@ btree_compare_double(cont void *key1, int keylen1,
 		     const void *key2, int keylen2)
 {
 	double result = *(double *) key1 - *(double *) key2;
+
 	if (result == 0.0)
 		return 0;
 
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index bdb201230bae..4679d1d945f9 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -377,6 +377,11 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
 	} else
 		map_addr = vm_mmap(filep, addr, size, prot, type, off);
 
+	if ((type & MAP_FIXED_NOREPLACE) && BAD_ADDR(map_addr))
+		pr_info("%d (%s): Uhuuh, elf segment at %p requested but the memory is mapped already\n",
+				task_pid_nr(current), current->comm,
+				(void *)addr);
+
 	return(map_addr);
 }
 
@@ -575,7 +580,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
 				elf_prot |= PROT_EXEC;
 			vaddr = eppnt->p_vaddr;
 			if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
-				elf_type |= MAP_FIXED;
+				elf_type |= MAP_FIXED_NOREPLACE;
 			else if (no_base && interp_elf_ex->e_type == ET_DYN)
 				load_addr = -vaddr;
 
@@ -890,7 +895,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
 	   the correct location in memory. */
 	for(i = 0, elf_ppnt = elf_phdata;
 	    i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
-		int elf_prot = 0, elf_flags;
+		int elf_prot = 0, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE;
 		unsigned long k, vaddr;
 		unsigned long total_size = 0;
 
@@ -922,6 +927,13 @@ static int load_elf_binary(struct linux_binprm *bprm)
 					 */
 				}
 			}
+
+			/*
+			 * Some binaries have overlapping elf segments and then
+			 * we have to forcefully map over an existing mapping
+			 * e.g. over this newly established brk mapping.
+			 */
+			elf_fixed = MAP_FIXED;
 		}
 
 		if (elf_ppnt->p_flags & PF_R)
@@ -939,7 +951,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
 		 * the ET_DYN load_addr calculations, proceed normally.
 		 */
 		if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
-			elf_flags |= MAP_FIXED;
+			elf_flags |= elf_fixed;
 		} else if (loc->elf_ex.e_type == ET_DYN) {
 			/*
 			 * This logic is run once for the first LOAD Program
@@ -975,7 +987,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
 				load_bias = ELF_ET_DYN_BASE;
 				if (current->flags & PF_RANDOMIZE)
 					load_bias += arch_mmap_rnd();
-				elf_flags |= MAP_FIXED;
+				elf_flags |= elf_fixed;
 			} else
 				load_bias = 0;
 
@@ -1234,7 +1246,7 @@ static int load_elf_library(struct file *file)
 			(eppnt->p_filesz +
 			 ELF_PAGEOFFSET(eppnt->p_vaddr)),
 			PROT_READ | PROT_WRITE | PROT_EXEC,
-			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+			MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_DENYWRITE,
 			(eppnt->p_offset -
 			 ELF_PAGEOFFSET(eppnt->p_vaddr)));
 	if (error != ELF_PAGESTART(eppnt->p_vaddr))
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 4a181fcb5175..00615161cdeb 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -790,8 +790,6 @@ static struct dentry *bd_mount(struct file_system_type *fs_type,
 {
 	struct dentry *dent;
 	dent = mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
-	if (!IS_ERR(dent))
-		dent->d_sb->s_iflags |= SB_I_CGROUPWB;
 	return dent;
 }
 
@@ -883,6 +881,7 @@ struct block_device *bdget(dev_t dev)
 		inode->i_mode = S_IFBLK;
 		inode->i_rdev = dev;
 		inode->i_bdev = bdev;
+		inode->i_flags |= S_CGROUPWB;
 		inode->i_data.a_ops = &def_blk_aops;
 		mapping_set_gfp_mask(&inode->i_data, GFP_USER);
 		spin_lock(&bdev_lock);
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 273351ee4c46..167e5dc7eadd 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -1,7 +1,6 @@
 config BTRFS_FS
 	tristate "Btrfs filesystem support"
-	select CRYPTO
-	select CRYPTO_CRC32C
+	select LIBCRC32C
 	select ZLIB_INFLATE
 	select ZLIB_DEFLATE
 	select LZO_COMPRESS
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index 0c4373628eb4..ca693dd554e9 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -10,7 +10,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 	   export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
 	   compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
 	   reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
-	   uuid-tree.o props.o hash.o free-space-tree.o tree-checker.o
+	   uuid-tree.o props.o free-space-tree.o tree-checker.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 63f0ccc92a71..f527e99c9f8d 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -195,7 +195,6 @@ struct btrfs_inode {
 
 	/* Hook into fs_info->delayed_iputs */
 	struct list_head delayed_iput;
-	long delayed_iput_count;
 
 	/*
 	 * To avoid races between lockless (i_mutex not held) direct IO writes
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 7d51b5a5b505..aa02f4dddfa0 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -96,9 +96,9 @@
 #include <linux/blkdev.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <linux/crc32c.h>
 #include "ctree.h"
 #include "disk-io.h"
-#include "hash.h"
 #include "transaction.h"
 #include "extent_io.h"
 #include "volumes.h"
@@ -1736,7 +1736,7 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state,
 		size_t sublen = i ? PAGE_SIZE :
 				    (PAGE_SIZE - BTRFS_CSUM_SIZE);
 
-		crc = btrfs_crc32c(crc, data, sublen);
+		crc = crc32c(crc, data, sublen);
 	}
 	btrfs_csum_final(crc, csum);
 	if (memcmp(csum, h->csum, state->csum_size))
@@ -2741,7 +2741,7 @@ int btrfsic_submit_bh(int op, int op_flags, struct buffer_head *bh)
 	struct btrfsic_dev_state *dev_state;
 
 	if (!btrfsic_is_initialized)
-		return submit_bh(op, op_flags, bh);
+		return submit_bh_blkcg_css(op, op_flags, bh, blkcg_root_css);
 
 	mutex_lock(&btrfsic_mutex);
 	/* since btrfsic_submit_bh() might also be called before
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 07d049c0c20f..dd8f95866db1 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -1621,12 +1621,23 @@ int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end)
 
 unsigned int btrfs_compress_str2level(const char *str)
 {
-	if (strncmp(str, "zlib", 4) != 0)
+	long level;
+	int max;
+
+	if (strncmp(str, "zlib", 4) == 0)
+		max = 9;
+	else if (strncmp(str, "zstd", 4) == 0)
+		max = 15; // encoded on 4 bits, real max is 22
+	else
 		return 0;
 
-	/* Accepted form: zlib:1 up to zlib:9 and nothing left after the number */
-	if (str[4] == ':' && '1' <= str[5] && str[5] <= '9' && str[6] == 0)
-		return str[5] - '0';
+	/* Accepted form: zxxx:1 up to zxxx:9 and nothing left after the number */
+	str += 4;
+	if (*str == ':')
+		str++;
+
+	if (kstrtoul(str, 10, &level))
+		return BTRFS_ZLIB_DEFAULT_LEVEL;
 
-	return BTRFS_ZLIB_DEFAULT_LEVEL;
+	return (level > max) ? BTRFS_ZLIB_DEFAULT_LEVEL : level;
 }
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 1a462ab85c49..5255e97fae10 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -40,6 +40,7 @@
 #include <linux/sizes.h>
 #include <linux/dynamic_debug.h>
 #include <linux/refcount.h>
+#include <linux/crc32c.h>
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
@@ -98,6 +99,7 @@ static const int btrfs_csum_sizes[] = { 4 };
 
 #define BTRFS_MAX_EXTENT_SIZE SZ_128M
 
+
 /*
  * Count how many BTRFS_MAX_EXTENT_SIZE cover the @size
  */
@@ -707,7 +709,6 @@ struct btrfs_delayed_root;
 #define BTRFS_FS_LOG_RECOVERING			4
 #define BTRFS_FS_OPEN				5
 #define BTRFS_FS_QUOTA_ENABLED			6
-#define BTRFS_FS_QUOTA_ENABLING			7
 #define BTRFS_FS_UPDATE_UUID_TREE_GEN		9
 #define BTRFS_FS_CREATING_FREE_SPACE_TREE	10
 #define BTRFS_FS_BTREE_ERR			11
@@ -788,14 +789,14 @@ struct btrfs_fs_info {
 	unsigned long pending_changes;
 	unsigned long compress_type:4;
 	unsigned int compress_level;
-	int commit_interval;
+	u32 commit_interval;
 	/*
 	 * It is a suggestive number, the read side is safe even it gets a
 	 * wrong number because we will write out the data into a regular
 	 * extent. The write side(mount/remount) is under ->s_umount lock,
 	 * so it is also safe.
 	 */
-	u64 max_inline;
+	u32 max_inline;
 
 	struct btrfs_transaction *running_transaction;
 	wait_queue_head_t transaction_throttle;
@@ -877,7 +878,6 @@ struct btrfs_fs_info {
 	struct rb_root tree_mod_log;
 
 	atomic_t async_delalloc_pages;
-	atomic_t open_ioctl_trans;
 
 	/*
 	 * this is used to protect the following list -- ordered_roots.
@@ -935,7 +935,7 @@ struct btrfs_fs_info {
 	struct btrfs_workqueue *extent_workers;
 	struct task_struct *transaction_kthread;
 	struct task_struct *cleaner_kthread;
-	int thread_pool_size;
+	u32 thread_pool_size;
 
 	struct kobject *space_info_kobj;
 
@@ -1260,12 +1260,13 @@ struct btrfs_root {
 	struct btrfs_subvolume_writers *subv_writers;
 	atomic_t will_be_snapshotted;
 
-	/* For qgroup metadata space reserve */
-	atomic64_t qgroup_meta_rsv;
+	/* For qgroup metadata reserved space */
+	spinlock_t qgroup_meta_rsv_lock;
+	u64 qgroup_meta_rsv_pertrans;
+	u64 qgroup_meta_rsv_prealloc;
 };
 
 struct btrfs_file_private {
-	struct btrfs_trans_handle *trans;
 	void *filldir_buf;
 };
 
@@ -2554,6 +2555,20 @@ BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
 	((unsigned long)(BTRFS_LEAF_DATA_OFFSET + \
 	btrfs_item_offset_nr(leaf, slot)))
 
+static inline u64 btrfs_name_hash(const char *name, int len)
+{
+       return crc32c((u32)~1, name, len);
+}
+
+/*
+ * Figure the key offset of an extended inode ref
+ */
+static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
+                                   int len)
+{
+       return (u64) crc32c(parent_objectid, name, len);
+}
+
 static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
 {
 	return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) &&
@@ -2628,7 +2643,6 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
 						 u64 bytenr);
 void btrfs_get_block_group(struct btrfs_block_group_cache *cache);
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
-int get_block_group_index(struct btrfs_block_group_cache *cache);
 struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
 					     struct btrfs_root *root,
 					     u64 parent, u64 root_objectid,
@@ -2675,8 +2689,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 			 u64 bytenr, u64 num_bytes, u64 parent,
 			 u64 root_objectid, u64 owner, u64 offset);
 
-int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
-				   struct btrfs_fs_info *fs_info);
+int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans);
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
 				   struct btrfs_fs_info *fs_info);
 int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
@@ -2697,8 +2710,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);
 void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache);
 void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache);
-void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
-				       struct btrfs_fs_info *fs_info);
+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans);
 u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info);
 u64 btrfs_metadata_alloc_profile(struct btrfs_fs_info *fs_info);
 u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info);
@@ -2730,11 +2742,10 @@ int btrfs_check_data_free_space(struct inode *inode,
 void btrfs_free_reserved_data_space(struct inode *inode,
 			struct extent_changeset *reserved, u64 start, u64 len);
 void btrfs_delalloc_release_space(struct inode *inode,
-			struct extent_changeset *reserved, u64 start, u64 len);
+				  struct extent_changeset *reserved,
+				  u64 start, u64 len, bool qgroup_free);
 void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
 					    u64 len);
-void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
-				  struct btrfs_fs_info *fs_info);
 void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans);
 int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
 				  struct btrfs_inode *inode);
@@ -2745,10 +2756,12 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 				     u64 *qgroup_reserved, bool use_global_rsv);
 void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
 				      struct btrfs_block_rsv *rsv);
-void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
+void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
+				    bool qgroup_free);
 
 int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);
-void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes);
+void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
+				     bool qgroup_free);
 int btrfs_delalloc_reserve_space(struct inode *inode,
 			struct extent_changeset **reserved, u64 start, u64 len);
 void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
@@ -3193,7 +3206,6 @@ void btrfs_destroy_inode(struct inode *inode);
 int btrfs_drop_inode(struct inode *inode);
 int __init btrfs_init_cachep(void);
 void btrfs_destroy_cachep(void);
-long btrfs_ioctl_trans_end(struct file *file);
 struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
 			 struct btrfs_root *root, int *was_new);
 struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 0530f6f2e4ba..64493a5aeb92 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -23,6 +23,7 @@
 #include "disk-io.h"
 #include "transaction.h"
 #include "ctree.h"
+#include "qgroup.h"
 
 #define BTRFS_DELAYED_WRITEBACK		512
 #define BTRFS_DELAYED_BACKGROUND	128
@@ -552,11 +553,12 @@ static struct btrfs_delayed_item *__btrfs_next_delayed_item(
 }
 
 static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
-					       struct btrfs_fs_info *fs_info,
+					       struct btrfs_root *root,
 					       struct btrfs_delayed_item *item)
 {
 	struct btrfs_block_rsv *src_rsv;
 	struct btrfs_block_rsv *dst_rsv;
+	struct btrfs_fs_info *fs_info = root->fs_info;
 	u64 num_bytes;
 	int ret;
 
@@ -567,6 +569,10 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
 	dst_rsv = &fs_info->delayed_block_rsv;
 
 	num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
+	ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
+	if (ret < 0)
+		return ret;
+
 	ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1);
 	if (!ret) {
 		trace_btrfs_space_reservation(fs_info, "delayed_item",
@@ -578,15 +584,17 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
 	return ret;
 }
 
-static void btrfs_delayed_item_release_metadata(struct btrfs_fs_info *fs_info,
+static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
 						struct btrfs_delayed_item *item)
 {
 	struct btrfs_block_rsv *rsv;
+	struct btrfs_fs_info *fs_info = root->fs_info;
 
 	if (!item->bytes_reserved)
 		return;
 
 	rsv = &fs_info->delayed_block_rsv;
+	btrfs_qgroup_convert_reserved_meta(root, item->bytes_reserved);
 	trace_btrfs_space_reservation(fs_info, "delayed_item",
 				      item->key.objectid, item->bytes_reserved,
 				      0);
@@ -611,6 +619,9 @@ static int btrfs_delayed_inode_reserve_metadata(
 
 	num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
 
+	ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
+	if (ret < 0)
+		return ret;
 	/*
 	 * btrfs_dirty_inode will update the inode under btrfs_join_transaction
 	 * which doesn't reserve space for speed.  This is a problem since we
@@ -630,8 +641,10 @@ static int btrfs_delayed_inode_reserve_metadata(
 		 * EAGAIN to make us stop the transaction we have, so return
 		 * ENOSPC instead so that btrfs_dirty_inode knows what to do.
 		 */
-		if (ret == -EAGAIN)
+		if (ret == -EAGAIN) {
 			ret = -ENOSPC;
+			btrfs_qgroup_free_meta_prealloc(root, num_bytes);
+		}
 		if (!ret) {
 			node->bytes_reserved = num_bytes;
 			trace_btrfs_space_reservation(fs_info,
@@ -653,7 +666,8 @@ static int btrfs_delayed_inode_reserve_metadata(
 }
 
 static void btrfs_delayed_inode_release_metadata(struct btrfs_fs_info *fs_info,
-						struct btrfs_delayed_node *node)
+						struct btrfs_delayed_node *node,
+						bool qgroup_free)
 {
 	struct btrfs_block_rsv *rsv;
 
@@ -665,6 +679,12 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_fs_info *fs_info,
 				      node->inode_id, node->bytes_reserved, 0);
 	btrfs_block_rsv_release(fs_info, rsv,
 				node->bytes_reserved);
+	if (qgroup_free)
+		btrfs_qgroup_free_meta_prealloc(node->root,
+				node->bytes_reserved);
+	else
+		btrfs_qgroup_convert_reserved_meta(node->root,
+				node->bytes_reserved);
 	node->bytes_reserved = 0;
 }
 
@@ -766,7 +786,7 @@ static int btrfs_batch_insert_items(struct btrfs_root *root,
 				    curr->data_len);
 		slot++;
 
-		btrfs_delayed_item_release_metadata(fs_info, curr);
+		btrfs_delayed_item_release_metadata(root, curr);
 
 		list_del(&curr->tree_list);
 		btrfs_release_delayed_item(curr);
@@ -788,7 +808,6 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
 				     struct btrfs_path *path,
 				     struct btrfs_delayed_item *delayed_item)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct extent_buffer *leaf;
 	char *ptr;
 	int ret;
@@ -806,7 +825,7 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
 			    delayed_item->data_len);
 	btrfs_mark_buffer_dirty(leaf);
 
-	btrfs_delayed_item_release_metadata(fs_info, delayed_item);
+	btrfs_delayed_item_release_metadata(root, delayed_item);
 	return 0;
 }
 
@@ -858,7 +877,6 @@ static int btrfs_batch_delete_items(struct btrfs_trans_handle *trans,
 				    struct btrfs_path *path,
 				    struct btrfs_delayed_item *item)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct btrfs_delayed_item *curr, *next;
 	struct extent_buffer *leaf;
 	struct btrfs_key key;
@@ -908,7 +926,7 @@ static int btrfs_batch_delete_items(struct btrfs_trans_handle *trans,
 		goto out;
 
 	list_for_each_entry_safe(curr, next, &head, tree_list) {
-		btrfs_delayed_item_release_metadata(fs_info, curr);
+		btrfs_delayed_item_release_metadata(root, curr);
 		list_del(&curr->tree_list);
 		btrfs_release_delayed_item(curr);
 	}
@@ -1051,7 +1069,7 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
 no_iref:
 	btrfs_release_path(path);
 err_out:
-	btrfs_delayed_inode_release_metadata(fs_info, node);
+	btrfs_delayed_inode_release_metadata(fs_info, node, (ret < 0));
 	btrfs_release_delayed_inode(node);
 
 	return ret;
@@ -1115,9 +1133,9 @@ __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
  * Returns < 0 on error and returns with an aborted transaction with any
  * outstanding delayed items cleaned up.
  */
-static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
-				     struct btrfs_fs_info *fs_info, int nr)
+static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_delayed_root *delayed_root;
 	struct btrfs_delayed_node *curr_node, *prev_node;
 	struct btrfs_path *path;
@@ -1162,16 +1180,14 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
 	return ret;
 }
 
-int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
-			    struct btrfs_fs_info *fs_info)
+int btrfs_run_delayed_items(struct btrfs_trans_handle *trans)
 {
-	return __btrfs_run_delayed_items(trans, fs_info, -1);
+	return __btrfs_run_delayed_items(trans, -1);
 }
 
-int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,
-			       struct btrfs_fs_info *fs_info, int nr)
+int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, int nr)
 {
-	return __btrfs_run_delayed_items(trans, fs_info, nr);
+	return __btrfs_run_delayed_items(trans, nr);
 }
 
 int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
@@ -1443,7 +1459,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
 	btrfs_set_stack_dir_type(dir_item, type);
 	memcpy((char *)(dir_item + 1), name, name_len);
 
-	ret = btrfs_delayed_item_reserve_metadata(trans, fs_info, delayed_item);
+	ret = btrfs_delayed_item_reserve_metadata(trans, dir->root, delayed_item);
 	/*
 	 * we have reserved enough space when we start a new transaction,
 	 * so reserving metadata failure is impossible
@@ -1480,7 +1496,7 @@ static int btrfs_delete_delayed_insertion_item(struct btrfs_fs_info *fs_info,
 		return 1;
 	}
 
-	btrfs_delayed_item_release_metadata(fs_info, item);
+	btrfs_delayed_item_release_metadata(node->root, item);
 	btrfs_release_delayed_item(item);
 	mutex_unlock(&node->mutex);
 	return 0;
@@ -1515,7 +1531,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
 
 	item->key = item_key;
 
-	ret = btrfs_delayed_item_reserve_metadata(trans, fs_info, item);
+	ret = btrfs_delayed_item_reserve_metadata(trans, dir->root, item);
 	/*
 	 * we have reserved enough space when we start a new transaction,
 	 * so reserving metadata failure is impossible.
@@ -1880,7 +1896,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
 	mutex_lock(&delayed_node->mutex);
 	curr_item = __btrfs_first_delayed_insertion_item(delayed_node);
 	while (curr_item) {
-		btrfs_delayed_item_release_metadata(fs_info, curr_item);
+		btrfs_delayed_item_release_metadata(root, curr_item);
 		prev_item = curr_item;
 		curr_item = __btrfs_next_delayed_item(prev_item);
 		btrfs_release_delayed_item(prev_item);
@@ -1888,7 +1904,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
 
 	curr_item = __btrfs_first_delayed_deletion_item(delayed_node);
 	while (curr_item) {
-		btrfs_delayed_item_release_metadata(fs_info, curr_item);
+		btrfs_delayed_item_release_metadata(root, curr_item);
 		prev_item = curr_item;
 		curr_item = __btrfs_next_delayed_item(prev_item);
 		btrfs_release_delayed_item(prev_item);
@@ -1898,7 +1914,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
 		btrfs_release_delayed_iref(delayed_node);
 
 	if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
-		btrfs_delayed_inode_release_metadata(fs_info, delayed_node);
+		btrfs_delayed_inode_release_metadata(fs_info, delayed_node, false);
 		btrfs_release_delayed_inode(delayed_node);
 	}
 	mutex_unlock(&delayed_node->mutex);
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h
index c4189d495934..ae893d85224f 100644
--- a/fs/btrfs/delayed-inode.h
+++ b/fs/btrfs/delayed-inode.h
@@ -111,10 +111,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
 
 int btrfs_inode_delayed_dir_index_count(struct btrfs_inode *inode);
 
-int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
-			    struct btrfs_fs_info *fs_info);
-int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,
-			       struct btrfs_fs_info *fs_info, int nr);
+int btrfs_run_delayed_items(struct btrfs_trans_handle *trans);
+int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, int nr);
 
 void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info);
 
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 7efbc4d1128b..3b0760f7ec8a 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -44,7 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
 						struct btrfs_fs_info *fs_info,
 						struct btrfs_device *srcdev,
 						struct btrfs_device *tgtdev);
-static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
 static int btrfs_dev_replace_kthread(void *data);
 static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info);
 
@@ -174,8 +173,14 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
 			}
 			set_bit(BTRFS_DEV_STATE_REPLACE_TGT,
 				&dev_replace->tgtdev->dev_state);
-			btrfs_init_dev_replace_tgtdev_for_resume(fs_info,
-				dev_replace->tgtdev);
+
+			WARN_ON(fs_info->fs_devices->rw_devices == 0);
+			dev_replace->tgtdev->io_width = fs_info->sectorsize;
+			dev_replace->tgtdev->io_align = fs_info->sectorsize;
+			dev_replace->tgtdev->sector_size = fs_info->sectorsize;
+			dev_replace->tgtdev->fs_info = fs_info;
+			set_bit(BTRFS_DEV_STATE_IN_FS_METADATA,
+				&dev_replace->tgtdev->dev_state);
 		}
 		break;
 	}
@@ -694,20 +699,14 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
 	btrfs_dev_replace_unlock(dev_replace, 0);
 }
 
-int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
-			     struct btrfs_ioctl_dev_replace_args *args)
-{
-	args->result = __btrfs_dev_replace_cancel(fs_info);
-	return 0;
-}
-
-static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
+int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
 {
 	struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
 	struct btrfs_device *tgt_device = NULL;
+	struct btrfs_device *src_device = NULL;
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = fs_info->tree_root;
-	u64 result;
+	int result;
 	int ret;
 
 	if (sb_rdonly(fs_info->sb))
@@ -726,6 +725,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
 	case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
 		result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
 		tgt_device = dev_replace->tgtdev;
+		src_device = dev_replace->srcdev;
 		dev_replace->tgtdev = NULL;
 		dev_replace->srcdev = NULL;
 		break;
@@ -743,6 +743,11 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
 	}
 	ret = btrfs_commit_transaction(trans);
 	WARN_ON(ret);
+
+	btrfs_info(fs_info, "dev_replace from %s (devid %llu) to %s canceled",
+		   btrfs_dev_name(src_device), src_device->devid,
+		   btrfs_dev_name(tgt_device));
+
 	if (tgt_device)
 		btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
 
diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h
index f94a76844ae7..389de365b0db 100644
--- a/fs/btrfs/dev-replace.h
+++ b/fs/btrfs/dev-replace.h
@@ -32,8 +32,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
 		int read_src);
 void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
 			      struct btrfs_ioctl_dev_replace_args *args);
-int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
-			     struct btrfs_ioctl_dev_replace_args *args);
+int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
 void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info);
 int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info);
 int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index cbe421605cd5..29e967b2c667 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -18,7 +18,6 @@
 
 #include "ctree.h"
 #include "disk-io.h"
-#include "hash.h"
 #include "transaction.h"
 
 /*
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 21f34ad0d411..9d2f7e58b9ed 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -31,10 +31,10 @@
 #include <linux/uuid.h>
 #include <linux/semaphore.h>
 #include <linux/error-injection.h>
+#include <linux/crc32c.h>
 #include <asm/unaligned.h>
 #include "ctree.h"
 #include "disk-io.h"
-#include "hash.h"
 #include "transaction.h"
 #include "btrfs_inode.h"
 #include "volumes.h"
@@ -270,7 +270,7 @@ struct extent_map *btree_get_extent(struct btrfs_inode *inode,
 
 u32 btrfs_csum_data(const char *data, u32 seed, size_t len)
 {
-	return btrfs_crc32c(seed, data, len);
+	return crc32c(seed, data, len);
 }
 
 void btrfs_csum_final(u32 crc, u8 *result)
@@ -602,12 +602,12 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
 	 * that we don't try and read the other copies of this block, just
 	 * return -EIO.
 	 */
-	if (found_level == 0 && btrfs_check_leaf_full(root, eb)) {
+	if (found_level == 0 && btrfs_check_leaf_full(fs_info, eb)) {
 		set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 		ret = -EIO;
 	}
 
-	if (found_level > 0 && btrfs_check_node(root, eb))
+	if (found_level > 0 && btrfs_check_node(fs_info, eb))
 		ret = -EIO;
 
 	if (!ret)
@@ -857,6 +857,8 @@ static blk_status_t btree_submit_bio_hook(void *private_data, struct bio *bio,
 	int async = check_async_write(BTRFS_I(inode));
 	blk_status_t ret;
 
+	bio_associate_blkcg(bio, blkcg_root_css);
+
 	if (bio_op(bio) != REQ_OP_WRITE) {
 		/*
 		 * called for a read, do the setup so that checksum validation
@@ -1160,6 +1162,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
 	spin_lock_init(&root->accounting_lock);
 	spin_lock_init(&root->log_extents_lock[0]);
 	spin_lock_init(&root->log_extents_lock[1]);
+	spin_lock_init(&root->qgroup_meta_rsv_lock);
 	mutex_init(&root->objectid_mutex);
 	mutex_init(&root->log_mutex);
 	mutex_init(&root->ordered_extent_mutex);
@@ -1176,7 +1179,6 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
 	atomic_set(&root->orphan_inodes, 0);
 	refcount_set(&root->refs, 1);
 	atomic_set(&root->will_be_snapshotted, 0);
-	atomic64_set(&root->qgroup_meta_rsv, 0);
 	root->log_transid = 0;
 	root->log_transid_committed = -1;
 	root->last_log_commit = 0;
@@ -1808,12 +1810,10 @@ static int transaction_kthread(void *arg)
 		if (unlikely(test_bit(BTRFS_FS_STATE_ERROR,
 				      &fs_info->fs_state)))
 			btrfs_cleanup_transaction(fs_info);
-		set_current_state(TASK_INTERRUPTIBLE);
 		if (!kthread_should_stop() &&
 				(!btrfs_transaction_blocked(fs_info) ||
 				 cannot_commit))
-			schedule_timeout(delay);
-		__set_current_state(TASK_RUNNING);
+			schedule_timeout_interruptible(delay);
 	} while (!kthread_should_stop());
 	return 0;
 }
@@ -2183,7 +2183,7 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info)
 static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info,
 		struct btrfs_fs_devices *fs_devices)
 {
-	int max_active = fs_info->thread_pool_size;
+	u32 max_active = fs_info->thread_pool_size;
 	unsigned int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND;
 
 	fs_info->workers =
@@ -2404,7 +2404,7 @@ int open_ctree(struct super_block *sb,
 	int err = -EINVAL;
 	int num_backups_tried = 0;
 	int backup_index = 0;
-	int max_active;
+	u32 max_active;
 	int clear_free_space_tree = 0;
 
 	tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
@@ -3290,6 +3290,7 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
 	struct buffer_head *bh;
 	int i;
 	int errors = 0;
+	bool primary_failed = false;
 	u64 bytenr;
 
 	if (max_mirrors == 0)
@@ -3306,11 +3307,16 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
 				      BTRFS_SUPER_INFO_SIZE);
 		if (!bh) {
 			errors++;
+			if (i == 0)
+				primary_failed = true;
 			continue;
 		}
 		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
+		if (!buffer_uptodate(bh)) {
 			errors++;
+			if (i == 0)
+				primary_failed = true;
+		}
 
 		/* drop our reference */
 		brelse(bh);
@@ -3319,6 +3325,13 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
 		brelse(bh);
 	}
 
+	/* log error, force error return */
+	if (primary_failed) {
+		btrfs_err(device->fs_info, "error writing primary super block to device %llu",
+			  device->devid);
+		return -1;
+	}
+
 	return errors < i ? 0 : -1;
 }
 
@@ -3344,6 +3357,8 @@ static void write_dev_flush(struct btrfs_device *device)
 		return;
 
 	bio_reset(bio);
+	bio_associate_blkcg(bio, blkcg_root_css);
+
 	bio->bi_end_io = btrfs_end_empty_barrier;
 	bio_set_dev(bio, device->bdev);
 	bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH;
@@ -3851,7 +3866,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
 	 * So here we should only check item pointers, not item data.
 	 */
 	if (btrfs_header_level(buf) == 0 &&
-	    btrfs_check_leaf_relaxed(root, buf)) {
+	    btrfs_check_leaf_relaxed(fs_info, buf)) {
 		btrfs_print_leaf(buf);
 		ASSERT(0);
 	}
@@ -4314,11 +4329,6 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
 		cache = list_first_entry(&cur_trans->dirty_bgs,
 					 struct btrfs_block_group_cache,
 					 dirty_list);
-		if (!cache) {
-			btrfs_err(fs_info, "orphan block group dirty_bgs list");
-			spin_unlock(&cur_trans->dirty_bgs_lock);
-			return;
-		}
 
 		if (!list_empty(&cache->io_list)) {
 			spin_unlock(&cur_trans->dirty_bgs_lock);
@@ -4338,14 +4348,14 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
 	}
 	spin_unlock(&cur_trans->dirty_bgs_lock);
 
+	/*
+	 * Refer to the definition of io_bgs member for details why it's safe
+	 * to use it without any locking
+	 */
 	while (!list_empty(&cur_trans->io_bgs)) {
 		cache = list_first_entry(&cur_trans->io_bgs,
 					 struct btrfs_block_group_cache,
 					 io_list);
-		if (!cache) {
-			btrfs_err(fs_info, "orphan block group on io_bgs list");
-			return;
-		}
 
 		list_del_init(&cache->io_list);
 		spin_lock(&cache->lock);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c1618ab9fecf..14d20e9f82d2 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -27,7 +27,7 @@
 #include <linux/ratelimit.h>
 #include <linux/percpu_counter.h>
 #include <linux/lockdep.h>
-#include "hash.h"
+#include <linux/crc32c.h>
 #include "tree-log.h"
 #include "disk-io.h"
 #include "print-tree.h"
@@ -1203,11 +1203,11 @@ static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
 	__le64 lenum;
 
 	lenum = cpu_to_le64(root_objectid);
-	high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum));
+	high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
 	lenum = cpu_to_le64(owner);
-	low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
+	low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
 	lenum = cpu_to_le64(offset);
-	low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
+	low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
 
 	return ((u64)high_crc << 31) ^ (u64)low_crc;
 }
@@ -3086,7 +3086,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 
 	if (run_all) {
 		if (!list_empty(&trans->new_bgs))
-			btrfs_create_pending_block_groups(trans, fs_info);
+			btrfs_create_pending_block_groups(trans);
 
 		spin_lock(&delayed_refs->lock);
 		node = rb_first(&delayed_refs->href_root);
@@ -3660,9 +3660,9 @@ int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
  * the commit latency by getting rid of the easy block groups while
  * we're still allowing others to join the commit.
  */
-int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
-				   struct btrfs_fs_info *fs_info)
+int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_block_group_cache *cache;
 	struct btrfs_transaction *cur_trans = trans->transaction;
 	int ret = 0;
@@ -3686,7 +3686,7 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
 	 * make sure all the block groups on our dirty list actually
 	 * exist
 	 */
-	btrfs_create_pending_block_groups(trans, fs_info);
+	btrfs_create_pending_block_groups(trans);
 
 	if (!path) {
 		path = btrfs_alloc_path();
@@ -3741,8 +3741,9 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
 				should_put = 0;
 
 				/*
-				 * the cache_write_mutex is protecting
-				 * the io_list
+				 * The cache_write_mutex is protecting the
+				 * io_list, also refer to the definition of
+				 * btrfs_transaction::io_bgs for more details
 				 */
 				list_add_tail(&cache->io_list, io);
 			} else {
@@ -3934,6 +3935,11 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
 	}
 	spin_unlock(&cur_trans->dirty_bgs_lock);
 
+
+	/*
+	 * Refer to the definition of io_bgs member for details why it's safe
+	 * to use it without any locking
+	 */
 	while (!list_empty(io)) {
 		cache = list_first_entry(io, struct btrfs_block_group_cache,
 					 io_list);
@@ -4333,8 +4339,7 @@ int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
 
 		/* commit the current transaction and try again */
 commit_trans:
-		if (need_commit &&
-		    !atomic_read(&fs_info->open_ioctl_trans)) {
+		if (need_commit) {
 			need_commit--;
 
 			if (need_commit > 0) {
@@ -4706,7 +4711,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
 	 */
 	if (trans->can_flush_pending_bgs &&
 	    trans->chunk_bytes_reserved >= (u64)SZ_2M) {
-		btrfs_create_pending_block_groups(trans, fs_info);
+		btrfs_create_pending_block_groups(trans);
 		btrfs_trans_release_chunk_metadata(trans);
 	}
 	return ret;
@@ -4994,7 +4999,7 @@ static void flush_space(struct btrfs_fs_info *fs_info,
 			ret = PTR_ERR(trans);
 			break;
 		}
-		ret = btrfs_run_delayed_items_nr(trans, fs_info, nr);
+		ret = btrfs_run_delayed_items_nr(trans, nr);
 		btrfs_end_transaction(trans);
 		break;
 	case FLUSH_DELALLOC:
@@ -5761,6 +5766,9 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode,
 	if (num_bytes == 0)
 		return 0;
 
+	ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
+	if (ret)
+		return ret;
 	ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
 	if (!ret) {
 		block_rsv_add_bytes(block_rsv, num_bytes, 0);
@@ -5773,11 +5781,16 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode,
 /**
  * btrfs_inode_rsv_release - release any excessive reservation.
  * @inode - the inode we need to release from.
+ * @qgroup_free - free or convert qgroup meta.
+ *   Unlike normal operation, qgroup meta reservation needs to know if
+ *   we are freeing qgroup reservation or just convert them into per-trans.
+ *   Normally @qgroup_free is true for error handler, and false for normal
+ *   release.
  *
  * This is the same as btrfs_block_rsv_release, except that it handles the
  * tracepoint for the reservation.
  */
-static void btrfs_inode_rsv_release(struct btrfs_inode *inode)
+static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
 {
 	struct btrfs_fs_info *fs_info = inode->root->fs_info;
 	struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
@@ -5793,6 +5806,10 @@ static void btrfs_inode_rsv_release(struct btrfs_inode *inode)
 	if (released > 0)
 		trace_btrfs_space_reservation(fs_info, "delalloc",
 					      btrfs_ino(inode), released, 0);
+	if (qgroup_free)
+		btrfs_qgroup_free_meta_prealloc(inode->root, released);
+	else
+		btrfs_qgroup_convert_reserved_meta(inode->root, released);
 }
 
 void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
@@ -5893,24 +5910,6 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
 	WARN_ON(fs_info->delayed_block_rsv.reserved > 0);
 }
 
-void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
-				  struct btrfs_fs_info *fs_info)
-{
-	if (!trans->block_rsv) {
-		ASSERT(!trans->bytes_reserved);
-		return;
-	}
-
-	if (!trans->bytes_reserved)
-		return;
-
-	ASSERT(trans->block_rsv == &fs_info->trans_block_rsv);
-	trace_btrfs_space_reservation(fs_info, "transaction",
-				      trans->transid, trans->bytes_reserved, 0);
-	btrfs_block_rsv_release(fs_info, trans->block_rsv,
-				trans->bytes_reserved);
-	trans->bytes_reserved = 0;
-}
 
 /*
  * To be called after all the new block groups attached to the transaction
@@ -5952,7 +5951,7 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
 	 */
 	u64 num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
 
-	trace_btrfs_space_reservation(fs_info, "orphan", btrfs_ino(inode), 
+	trace_btrfs_space_reservation(fs_info, "orphan", btrfs_ino(inode),
 			num_bytes, 1);
 	return btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1);
 }
@@ -5996,7 +5995,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
 		/* One for parent inode, two for dir entries */
 		num_bytes = 3 * fs_info->nodesize;
-		ret = btrfs_qgroup_reserve_meta(root, num_bytes, true);
+		ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
 		if (ret)
 			return ret;
 	} else {
@@ -6015,7 +6014,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 		ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1);
 
 	if (ret && *qgroup_reserved)
-		btrfs_qgroup_free_meta(root, *qgroup_reserved);
+		btrfs_qgroup_free_meta_prealloc(root, *qgroup_reserved);
 
 	return ret;
 }
@@ -6052,7 +6051,6 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
 int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
-	struct btrfs_root *root = inode->root;
 	unsigned nr_extents;
 	enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
 	int ret = 0;
@@ -6069,13 +6067,13 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
 	if (btrfs_is_free_space_inode(inode)) {
 		flush = BTRFS_RESERVE_NO_FLUSH;
 		delalloc_lock = false;
-	} else if (current->journal_info) {
-		flush = BTRFS_RESERVE_FLUSH_LIMIT;
-	}
+	} else {
+		if (current->journal_info)
+			flush = BTRFS_RESERVE_FLUSH_LIMIT;
 
-	if (flush != BTRFS_RESERVE_NO_FLUSH &&
-	    btrfs_transaction_in_commit(fs_info))
-		schedule_timeout(1);
+		if (btrfs_transaction_in_commit(fs_info))
+			schedule_timeout(1);
+	}
 
 	if (delalloc_lock)
 		mutex_lock(&inode->delalloc_mutex);
@@ -6090,19 +6088,9 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
 	btrfs_calculate_inode_block_rsv_size(fs_info, inode);
 	spin_unlock(&inode->lock);
 
-	if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
-		ret = btrfs_qgroup_reserve_meta(root,
-				nr_extents * fs_info->nodesize, true);
-		if (ret)
-			goto out_fail;
-	}
-
 	ret = btrfs_inode_rsv_refill(inode, flush);
-	if (unlikely(ret)) {
-		btrfs_qgroup_free_meta(root,
-				       nr_extents * fs_info->nodesize);
+	if (unlikely(ret))
 		goto out_fail;
-	}
 
 	if (delalloc_lock)
 		mutex_unlock(&inode->delalloc_mutex);
@@ -6116,7 +6104,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
 	btrfs_calculate_inode_block_rsv_size(fs_info, inode);
 	spin_unlock(&inode->lock);
 
-	btrfs_inode_rsv_release(inode);
+	btrfs_inode_rsv_release(inode, true);
 	if (delalloc_lock)
 		mutex_unlock(&inode->delalloc_mutex);
 	return ret;
@@ -6126,12 +6114,14 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
  * btrfs_delalloc_release_metadata - release a metadata reservation for an inode
  * @inode: the inode to release the reservation for.
  * @num_bytes: the number of bytes we are releasing.
+ * @qgroup_free: free qgroup reservation or convert it to per-trans reservation
  *
  * This will release the metadata reservation for an inode.  This can be called
  * once we complete IO for a given set of bytes to release their metadata
  * reservations, or on error for the same reason.
  */
-void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
+void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
+				     bool qgroup_free)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
 
@@ -6144,13 +6134,14 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
 	if (btrfs_is_testing(fs_info))
 		return;
 
-	btrfs_inode_rsv_release(inode);
+	btrfs_inode_rsv_release(inode, qgroup_free);
 }
 
 /**
  * btrfs_delalloc_release_extents - release our outstanding_extents
  * @inode: the inode to balance the reservation for.
  * @num_bytes: the number of bytes we originally reserved with
+ * @qgroup_free: do we need to free qgroup meta reservation or convert them.
  *
  * When we reserve space we increase outstanding_extents for the extents we may
  * add.  Once we've set the range as delalloc or created our ordered extents we
@@ -6158,7 +6149,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
  * temporarily tracked outstanding_extents.  This _must_ be used in conjunction
  * with btrfs_delalloc_reserve_metadata.
  */
-void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
+void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
+				    bool qgroup_free)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
 	unsigned num_extents;
@@ -6172,7 +6164,7 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
 	if (btrfs_is_testing(fs_info))
 		return;
 
-	btrfs_inode_rsv_release(inode);
+	btrfs_inode_rsv_release(inode, qgroup_free);
 }
 
 /**
@@ -6228,9 +6220,9 @@ int btrfs_delalloc_reserve_space(struct inode *inode,
  */
 void btrfs_delalloc_release_space(struct inode *inode,
 				  struct extent_changeset *reserved,
-				  u64 start, u64 len)
+				  u64 start, u64 len, bool qgroup_free)
 {
-	btrfs_delalloc_release_metadata(BTRFS_I(inode), len);
+	btrfs_delalloc_release_metadata(BTRFS_I(inode), len, qgroup_free);
 	btrfs_free_reserved_data_space(inode, reserved, start, len);
 }
 
@@ -7353,29 +7345,6 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
 	return ret;
 }
 
-int __get_raid_index(u64 flags)
-{
-	if (flags & BTRFS_BLOCK_GROUP_RAID10)
-		return BTRFS_RAID_RAID10;
-	else if (flags & BTRFS_BLOCK_GROUP_RAID1)
-		return BTRFS_RAID_RAID1;
-	else if (flags & BTRFS_BLOCK_GROUP_DUP)
-		return BTRFS_RAID_DUP;
-	else if (flags & BTRFS_BLOCK_GROUP_RAID0)
-		return BTRFS_RAID_RAID0;
-	else if (flags & BTRFS_BLOCK_GROUP_RAID5)
-		return BTRFS_RAID_RAID5;
-	else if (flags & BTRFS_BLOCK_GROUP_RAID6)
-		return BTRFS_RAID_RAID6;
-
-	return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
-}
-
-int get_block_group_index(struct btrfs_block_group_cache *cache)
-{
-	return __get_raid_index(cache->flags);
-}
-
 static const char *btrfs_raid_type_names[BTRFS_NR_RAID_TYPES] = {
 	[BTRFS_RAID_RAID10]	= "raid10",
 	[BTRFS_RAID_RAID1]	= "raid1",
@@ -7490,7 +7459,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
 	u64 empty_cluster = 0;
 	struct btrfs_space_info *space_info;
 	int loop = 0;
-	int index = __get_raid_index(flags);
+	int index = btrfs_bg_flags_to_raid_index(flags);
 	bool failed_cluster_refill = false;
 	bool failed_alloc = false;
 	bool use_cluster = true;
@@ -7576,7 +7545,8 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
 				btrfs_put_block_group(block_group);
 				up_read(&space_info->groups_sem);
 			} else {
-				index = get_block_group_index(block_group);
+				index = btrfs_bg_flags_to_raid_index(
+						block_group->flags);
 				btrfs_lock_block_group(block_group, delalloc);
 				goto have_block_group;
 			}
@@ -7586,7 +7556,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
 	}
 search:
 	have_caching_bg = false;
-	if (index == 0 || index == __get_raid_index(flags))
+	if (index == 0 || index == btrfs_bg_flags_to_raid_index(flags))
 		full_search = true;
 	down_read(&space_info->groups_sem);
 	list_for_each_entry(block_group, &space_info->block_groups[index],
@@ -7844,7 +7814,8 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
 loop:
 		failed_cluster_refill = false;
 		failed_alloc = false;
-		BUG_ON(index != get_block_group_index(block_group));
+		BUG_ON(btrfs_bg_flags_to_raid_index(block_group->flags) !=
+		       index);
 		btrfs_release_block_group(block_group, delalloc);
 		cond_resched();
 	}
@@ -9650,7 +9621,7 @@ int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr)
 	 */
 	target = get_restripe_target(fs_info, block_group->flags);
 	if (target) {
-		index = __get_raid_index(extended_to_chunk(target));
+		index = btrfs_bg_flags_to_raid_index(extended_to_chunk(target));
 	} else {
 		/*
 		 * this is just a balance, so if we were marked as full
@@ -9664,7 +9635,7 @@ int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr)
 			goto out;
 		}
 
-		index = get_block_group_index(block_group);
+		index = btrfs_bg_flags_to_raid_index(block_group->flags);
 	}
 
 	if (index == BTRFS_RAID_RAID10) {
@@ -9916,7 +9887,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
 static void link_block_group(struct btrfs_block_group_cache *cache)
 {
 	struct btrfs_space_info *space_info = cache->space_info;
-	int index = get_block_group_index(cache);
+	int index = btrfs_bg_flags_to_raid_index(cache->flags);
 	bool first = false;
 
 	down_write(&space_info->groups_sem);
@@ -10169,9 +10140,9 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
 	return ret;
 }
 
-void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
-				       struct btrfs_fs_info *fs_info)
+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_block_group_cache *block_group, *tmp;
 	struct btrfs_root *extent_root = fs_info->extent_root;
 	struct btrfs_block_group_item item;
@@ -10336,7 +10307,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 				  block_group->key.offset);
 
 	memcpy(&key, &block_group->key, sizeof(key));
-	index = get_block_group_index(block_group);
+	index = btrfs_bg_flags_to_raid_index(block_group->flags);
 	if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP |
 				  BTRFS_BLOCK_GROUP_RAID1 |
 				  BTRFS_BLOCK_GROUP_RAID10))
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index dfeb74a0be77..4e73705b405e 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -76,8 +76,8 @@ void btrfs_leak_debug_check(void)
 
 	while (!list_empty(&buffers)) {
 		eb = list_entry(buffers.next, struct extent_buffer, leak_list);
-		pr_err("BTRFS: buffer leak start %llu len %lu refs %d\n",
-		       eb->start, eb->len, atomic_read(&eb->refs));
+		pr_err("BTRFS: buffer leak start %llu len %lu refs %d bflags %lu\n",
+		       eb->start, eb->len, atomic_read(&eb->refs), eb->bflags);
 		list_del(&eb->leak_list);
 		kmem_cache_free(extent_buffer_cache, eb);
 	}
@@ -5230,11 +5230,6 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb)
 	}
 }
 
-int extent_buffer_uptodate(struct extent_buffer *eb)
-{
-	return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-}
-
 int read_extent_buffer_pages(struct extent_io_tree *tree,
 			     struct extent_buffer *eb, int wait, int mirror_num)
 {
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index a7a850abd600..da9be2fb0502 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -455,6 +455,11 @@ static inline void extent_buffer_get(struct extent_buffer *eb)
 	atomic_inc(&eb->refs);
 }
 
+static inline int extent_buffer_uptodate(struct extent_buffer *eb)
+{
+	return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
+}
+
 int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
 			 unsigned long start, unsigned long len);
 void read_extent_buffer(const struct extent_buffer *eb, void *dst,
@@ -489,7 +494,6 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb);
 int set_extent_buffer_dirty(struct extent_buffer *eb);
 void set_extent_buffer_uptodate(struct extent_buffer *eb);
 void clear_extent_buffer_uptodate(struct extent_buffer *eb);
-int extent_buffer_uptodate(struct extent_buffer *eb);
 int extent_buffer_under_io(struct extent_buffer *eb);
 int map_private_extent_buffer(const struct extent_buffer *eb,
 			      unsigned long offset, unsigned long min_len,
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index d3bd02105d1c..9573b1a3a441 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -552,6 +552,9 @@ int btrfs_add_extent_mapping(struct extent_map_tree *em_tree,
 		ret = 0;
 
 		existing = search_extent_mapping(em_tree, start, len);
+
+		trace_btrfs_handle_em_exist(existing, em, start, len);
+
 		/*
 		 * existing will always be non-NULL, since there must be
 		 * extent causing the -EEXIST.
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 41ab9073d1d4..5f52cef4b58f 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1691,7 +1691,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 				    force_page_uptodate);
 		if (ret) {
 			btrfs_delalloc_release_extents(BTRFS_I(inode),
-						       reserve_bytes);
+						       reserve_bytes, true);
 			break;
 		}
 
@@ -1703,7 +1703,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 			if (extents_locked == -EAGAIN)
 				goto again;
 			btrfs_delalloc_release_extents(BTRFS_I(inode),
-						       reserve_bytes);
+						       reserve_bytes, true);
 			ret = extents_locked;
 			break;
 		}
@@ -1738,7 +1738,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 						fs_info->sb->s_blocksize_bits;
 			if (only_release_metadata) {
 				btrfs_delalloc_release_metadata(BTRFS_I(inode),
-								release_bytes);
+							release_bytes, true);
 			} else {
 				u64 __pos;
 
@@ -1747,7 +1747,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 					(dirty_pages << PAGE_SHIFT);
 				btrfs_delalloc_release_space(inode,
 						data_reserved, __pos,
-						release_bytes);
+						release_bytes, true);
 			}
 		}
 
@@ -1760,7 +1760,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 		if (extents_locked)
 			unlock_extent_cached(&BTRFS_I(inode)->io_tree,
 					     lockstart, lockend, &cached_state);
-		btrfs_delalloc_release_extents(BTRFS_I(inode), reserve_bytes);
+		btrfs_delalloc_release_extents(BTRFS_I(inode), reserve_bytes,
+					       (ret != 0));
 		if (ret) {
 			btrfs_drop_pages(pages, num_pages);
 			break;
@@ -1800,11 +1801,11 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 		if (only_release_metadata) {
 			btrfs_end_write_no_snapshotting(root);
 			btrfs_delalloc_release_metadata(BTRFS_I(inode),
-					release_bytes);
+					release_bytes, true);
 		} else {
 			btrfs_delalloc_release_space(inode, data_reserved,
 					round_down(pos, fs_info->sectorsize),
-					release_bytes);
+					release_bytes, true);
 		}
 	}
 
@@ -1997,8 +1998,6 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
 {
 	struct btrfs_file_private *private = filp->private_data;
 
-	if (private && private->trans)
-		btrfs_ioctl_trans_end(filp);
 	if (private && private->filldir_buf)
 		kfree(private->filldir_buf);
 	kfree(private);
@@ -2189,12 +2188,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 		goto out;
 	}
 
-	/*
-	 * ok we haven't committed the transaction yet, lets do a commit
-	 */
-	if (file->private_data)
-		btrfs_ioctl_trans_end(file);
-
 	/*
 	 * We use start here because we will need to wait on the IO to complete
 	 * in btrfs_sync_log, which could require joining a transaction (for
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index a9f22ac50d6a..d0dde9e6afd7 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -3547,7 +3547,7 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
 	if (ret) {
 		if (release_metadata)
 			btrfs_delalloc_release_metadata(BTRFS_I(inode),
-					inode->i_size);
+					inode->i_size, true);
 #ifdef DEBUG
 		btrfs_err(fs_info,
 			  "failed to write free ino cache for root %llu",
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index fe5e0324dca9..af36a6a971fe 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1071,7 +1071,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
-	path->reada = 1;
+	path->reada = READA_FORWARD;
 
 	path2 = btrfs_alloc_path();
 	if (!path2) {
@@ -1573,7 +1573,7 @@ int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
 	 */
 	path->skip_locking = 1;
 	path->search_commit_root = 1;
-	path->reada = 1;
+	path->reada = READA_FORWARD;
 
 	info = search_free_space_info(NULL, fs_info, block_group, path, 0);
 	if (IS_ERR(info)) {
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c
deleted file mode 100644
index baacc1866861..000000000000
--- a/fs/btrfs/hash.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 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 <crypto/hash.h>
-#include <linux/err.h>
-#include "hash.h"
-
-static struct crypto_shash *tfm;
-
-int __init btrfs_hash_init(void)
-{
-	tfm = crypto_alloc_shash("crc32c", 0, 0);
-
-	return PTR_ERR_OR_ZERO(tfm);
-}
-
-const char* btrfs_crc32c_impl(void)
-{
-	return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm));
-}
-
-void btrfs_hash_exit(void)
-{
-	crypto_free_shash(tfm);
-}
-
-u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length)
-{
-	SHASH_DESC_ON_STACK(shash, tfm);
-	u32 *ctx = (u32 *)shash_desc_ctx(shash);
-	u32 retval;
-	int err;
-
-	shash->tfm = tfm;
-	shash->flags = 0;
-	*ctx = crc;
-
-	err = crypto_shash_update(shash, address, length);
-	BUG_ON(err);
-
-	retval = *ctx;
-	barrier_data(ctx);
-	return retval;
-}
diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h
deleted file mode 100644
index c3a2ec554361..000000000000
--- a/fs/btrfs/hash.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007 Oracle.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#ifndef __HASH__
-#define __HASH__
-
-int __init btrfs_hash_init(void);
-
-void btrfs_hash_exit(void);
-const char* btrfs_crc32c_impl(void);
-
-u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length);
-
-static inline u64 btrfs_name_hash(const char *name, int len)
-{
-	return btrfs_crc32c((u32)~1, name, len);
-}
-
-/*
- * Figure the key offset of an extended inode ref
- */
-static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
-				    int len)
-{
-	return (u64) btrfs_crc32c(parent_objectid, name, len);
-}
-
-#endif
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index 39c968f80157..83f85f074307 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -18,7 +18,6 @@
 
 #include "ctree.h"
 #include "disk-io.h"
-#include "hash.h"
 #include "transaction.h"
 #include "print-tree.h"
 
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index 022b19336fee..9409dcc7020d 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -500,12 +500,12 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
 	ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc,
 					      prealloc, prealloc, &alloc_hint);
 	if (ret) {
-		btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc);
+		btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc, true);
 		goto out_put;
 	}
 
 	ret = btrfs_write_out_ino_cache(root, trans, path, inode);
-	btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc);
+	btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc, false);
 out_put:
 	iput(inode);
 out_release:
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a79299a89b7d..ad1c4f00d276 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -58,7 +58,6 @@
 #include "free-space-cache.h"
 #include "inode-map.h"
 #include "backref.h"
-#include "hash.h"
 #include "props.h"
 #include "qgroup.h"
 #include "dedupe.h"
@@ -102,7 +101,7 @@ static const unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
 };
 
 static int btrfs_setsize(struct inode *inode, struct iattr *attr);
-static int btrfs_truncate(struct inode *inode);
+static int btrfs_truncate(struct inode *inode, bool skip_writeback);
 static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent);
 static noinline int cow_file_range(struct inode *inode,
 				   struct page *locked_page,
@@ -1262,6 +1261,8 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info,
 		list_del(&sums->list);
 		kfree(sums);
 	}
+	if (ret < 0)
+		return ret;
 	return 1;
 }
 
@@ -1394,10 +1395,23 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 				goto out_check;
 			if (btrfs_extent_readonly(fs_info, disk_bytenr))
 				goto out_check;
-			if (btrfs_cross_ref_exist(root, ino,
-						  found_key.offset -
-						  extent_offset, disk_bytenr))
+			ret = btrfs_cross_ref_exist(root, ino,
+						    found_key.offset -
+						    extent_offset, disk_bytenr);
+			if (ret) {
+				/*
+				 * ret could be -EIO if the above fails to read
+				 * metadata.
+				 */
+				if (ret < 0) {
+					if (cow_start != (u64)-1)
+						cur_offset = cow_start;
+					goto error;
+				}
+
+				WARN_ON_ONCE(nolock);
 				goto out_check;
+			}
 			disk_bytenr += extent_offset;
 			disk_bytenr += cur_offset - found_key.offset;
 			num_bytes = min(end + 1, extent_end) - cur_offset;
@@ -1415,10 +1429,22 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 			 * this ensure that csum for a given extent are
 			 * either valid or do not exist.
 			 */
-			if (csum_exist_in_range(fs_info, disk_bytenr,
-						num_bytes)) {
+			ret = csum_exist_in_range(fs_info, disk_bytenr,
+						  num_bytes);
+			if (ret) {
 				if (!nolock)
 					btrfs_end_write_no_snapshotting(root);
+
+				/*
+				 * ret could be -EIO if the above fails to read
+				 * metadata.
+				 */
+				if (ret < 0) {
+					if (cow_start != (u64)-1)
+						cur_offset = cow_start;
+					goto error;
+				}
+				WARN_ON_ONCE(nolock);
 				goto out_check;
 			}
 			if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
@@ -1847,7 +1873,7 @@ static void btrfs_clear_bit_hook(void *private_data,
 		 */
 		if (*bits & EXTENT_CLEAR_META_RESV &&
 		    root != fs_info->tree_root)
-			btrfs_delalloc_release_metadata(inode, len);
+			btrfs_delalloc_release_metadata(inode, len, false);
 
 		/* For sanity tests. */
 		if (btrfs_is_testing(fs_info))
@@ -1989,6 +2015,15 @@ static blk_status_t btrfs_submit_bio_hook(void *private_data, struct bio *bio,
 
 	skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
+#ifdef CONFIG_BLK_CGROUP
+	/*
+	 * if we're under IO controls, force a synchronous crc and
+	 * IO submission so things get accounted in the proper slots.
+	 */
+	if (!task_css_is_root(current, io_cgrp_id))
+		async = 0;
+#endif
+
 	if (btrfs_is_free_space_inode(BTRFS_I(inode)))
 		metadata = BTRFS_WQ_ENDIO_FREE_SPACE;
 
@@ -2008,10 +2043,10 @@ static blk_status_t btrfs_submit_bio_hook(void *private_data, struct bio *bio,
 				goto out;
 		}
 		goto mapit;
-	} else if (async && !skip_sum) {
+	} else if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) {
 		/* csum items have already been cloned */
-		if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
-			goto mapit;
+		goto mapit;
+	} else if (async && !skip_sum) {
 		/* we're doing a write, do the async checksumming */
 		ret = btrfs_wq_submit_bio(fs_info, bio, mirror_num, bio_flags,
 					  bio_offset, inode,
@@ -2043,12 +2078,15 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
 			     struct inode *inode, struct list_head *list)
 {
 	struct btrfs_ordered_sum *sum;
+	int ret;
 
 	list_for_each_entry(sum, list, list) {
 		trans->adding_csums = true;
-		btrfs_csum_file_blocks(trans,
+		ret = btrfs_csum_file_blocks(trans,
 		       BTRFS_I(inode)->root->fs_info->csum_root, sum);
 		trans->adding_csums = false;
+		if (ret)
+			return ret;
 	}
 	return 0;
 }
@@ -2131,7 +2169,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
 
 	ClearPageChecked(page);
 	set_page_dirty(page);
-	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, false);
 out:
 	unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
 			     &cached_state);
@@ -3062,7 +3100,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
 		goto out;
 	}
 
-	add_pending_csums(trans, inode, &ordered_extent->list);
+	ret = add_pending_csums(trans, inode, &ordered_extent->list);
+	if (ret) {
+		btrfs_abort_transaction(trans, ret);
+		goto out;
+	}
 
 	btrfs_ordered_update_i_size(inode, 0, ordered_extent);
 	ret = btrfs_update_inode_fallback(trans, root, inode);
@@ -3240,6 +3282,16 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
 				      start, (size_t)(end - start + 1));
 }
 
+/*
+ * btrfs_add_delayed_iput - perform a delayed iput on @inode
+ *
+ * @inode: The inode we want to perform iput on
+ *
+ * This function uses the generic vfs_inode::i_count to track whether we should
+ * just decrement it (in case it's > 1) or if this is the last iput then link
+ * the inode to the delayed iput machinery. Delayed iputs are processed at
+ * transaction commit time/superblock commit/cleaner kthread.
+ */
 void btrfs_add_delayed_iput(struct inode *inode)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -3249,12 +3301,8 @@ void btrfs_add_delayed_iput(struct inode *inode)
 		return;
 
 	spin_lock(&fs_info->delayed_iput_lock);
-	if (binode->delayed_iput_count == 0) {
-		ASSERT(list_empty(&binode->delayed_iput));
-		list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
-	} else {
-		binode->delayed_iput_count++;
-	}
+	ASSERT(list_empty(&binode->delayed_iput));
+	list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
 	spin_unlock(&fs_info->delayed_iput_lock);
 }
 
@@ -3267,13 +3315,7 @@ void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
 
 		inode = list_first_entry(&fs_info->delayed_iputs,
 				struct btrfs_inode, delayed_iput);
-		if (inode->delayed_iput_count) {
-			inode->delayed_iput_count--;
-			list_move_tail(&inode->delayed_iput,
-					&fs_info->delayed_iputs);
-		} else {
-			list_del_init(&inode->delayed_iput);
-		}
+		list_del_init(&inode->delayed_iput);
 		spin_unlock(&fs_info->delayed_iput_lock);
 		iput(&inode->vfs_inode);
 		spin_lock(&fs_info->delayed_iput_lock);
@@ -3353,14 +3395,6 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
 			return -ENOMEM;
 	}
 
-	spin_lock(&root->orphan_lock);
-	if (!root->orphan_block_rsv) {
-		root->orphan_block_rsv = block_rsv;
-	} else if (block_rsv) {
-		btrfs_free_block_rsv(fs_info, block_rsv);
-		block_rsv = NULL;
-	}
-
 	if (!test_and_set_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
 			      &inode->runtime_flags)) {
 #if 0
@@ -3375,12 +3409,23 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
 			insert = 1;
 #endif
 		insert = 1;
-		atomic_inc(&root->orphan_inodes);
 	}
 
 	if (!test_and_set_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
 			      &inode->runtime_flags))
 		reserve = 1;
+
+	spin_lock(&root->orphan_lock);
+	/* If someone has created ->orphan_block_rsv, be happy to use it. */
+	if (!root->orphan_block_rsv) {
+		root->orphan_block_rsv = block_rsv;
+	} else if (block_rsv) {
+		btrfs_free_block_rsv(fs_info, block_rsv);
+		block_rsv = NULL;
+	}
+
+	if (insert)
+		atomic_inc(&root->orphan_inodes);
 	spin_unlock(&root->orphan_lock);
 
 	/* grab metadata reservation from transaction handle */
@@ -3637,7 +3682,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
 				goto out;
 			}
 
-			ret = btrfs_truncate(inode);
+			ret = btrfs_truncate(inode, false);
 			if (ret)
 				btrfs_orphan_del(NULL, BTRFS_I(inode));
 		} else {
@@ -4799,8 +4844,8 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
 	page = find_or_create_page(mapping, index, mask);
 	if (!page) {
 		btrfs_delalloc_release_space(inode, data_reserved,
-					     block_start, blocksize);
-		btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize);
+					     block_start, blocksize, true);
+		btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize, true);
 		ret = -ENOMEM;
 		goto out;
 	}
@@ -4867,8 +4912,8 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
 out_unlock:
 	if (ret)
 		btrfs_delalloc_release_space(inode, data_reserved, block_start,
-					     blocksize);
-	btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize);
+					     blocksize, true);
+	btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize, (ret != 0));
 	unlock_page(page);
 	put_page(page);
 out:
@@ -5123,7 +5168,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
 		inode_dio_wait(inode);
 		btrfs_inode_resume_unlocked_dio(BTRFS_I(inode));
 
-		ret = btrfs_truncate(inode);
+		ret = btrfs_truncate(inode, newsize == oldsize);
 		if (ret && inode->i_nlink) {
 			int err;
 
@@ -8706,7 +8751,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 		if (ret < 0 && ret != -EIOCBQUEUED) {
 			if (dio_data.reserve)
 				btrfs_delalloc_release_space(inode, data_reserved,
-					offset, dio_data.reserve);
+					offset, dio_data.reserve, true);
 			/*
 			 * On error we might have left some ordered extents
 			 * without submitting corresponding bios for them, so
@@ -8722,8 +8767,8 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 					false);
 		} else if (ret >= 0 && (size_t)ret < count)
 			btrfs_delalloc_release_space(inode, data_reserved,
-					offset, count - (size_t)ret);
-		btrfs_delalloc_release_extents(BTRFS_I(inode), count);
+					offset, count - (size_t)ret, true);
+		btrfs_delalloc_release_extents(BTRFS_I(inode), count, false);
 	}
 out:
 	if (wakeup)
@@ -9038,7 +9083,8 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
 		if (reserved_space < PAGE_SIZE) {
 			end = page_start + reserved_space - 1;
 			btrfs_delalloc_release_space(inode, data_reserved,
-					page_start, PAGE_SIZE - reserved_space);
+					page_start, PAGE_SIZE - reserved_space,
+					true);
 		}
 	}
 
@@ -9088,23 +9134,23 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
 
 out_unlock:
 	if (!ret) {
-		btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+		btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, true);
 		sb_end_pagefault(inode->i_sb);
 		extent_changeset_free(data_reserved);
 		return VM_FAULT_LOCKED;
 	}
 	unlock_page(page);
 out:
-	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, (ret != 0));
 	btrfs_delalloc_release_space(inode, data_reserved, page_start,
-				     reserved_space);
+				     reserved_space, (ret != 0));
 out_noreserve:
 	sb_end_pagefault(inode->i_sb);
 	extent_changeset_free(data_reserved);
 	return ret;
 }
 
-static int btrfs_truncate(struct inode *inode)
+static int btrfs_truncate(struct inode *inode, bool skip_writeback)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 	struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -9115,10 +9161,12 @@ static int btrfs_truncate(struct inode *inode)
 	u64 mask = fs_info->sectorsize - 1;
 	u64 min_size = btrfs_calc_trunc_metadata_size(fs_info, 1);
 
-	ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
-				       (u64)-1);
-	if (ret)
-		return ret;
+	if (!skip_writeback) {
+		ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
+					       (u64)-1);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * Yes ladies and gentlemen, this is indeed ugly.  The fact is we have
@@ -9328,7 +9376,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
 	ei->dir_index = 0;
 	ei->last_unlink_trans = 0;
 	ei->last_log_commit = 0;
-	ei->delayed_iput_count = 0;
 
 	spin_lock_init(&ei->lock);
 	ei->outstanding_extents = 0;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 111ee282b777..95855de060c3 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -164,9 +164,15 @@ void btrfs_update_iflags(struct inode *inode)
 		new_fl |= S_NOATIME;
 	if (ip->flags & BTRFS_INODE_DIRSYNC)
 		new_fl |= S_DIRSYNC;
+	/*
+	 * The btree_inode will be always in the root cgroup. The cgroup
+	 * writeback can be enabled on regular inodes selectively.
+	 */
+	new_fl |= S_CGROUPWB;
 
 	set_mask_bits(&inode->i_flags,
-		      S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC,
+		      S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC |
+		      S_CGROUPWB,
 		      new_fl);
 }
 
@@ -1197,7 +1203,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
 		spin_unlock(&BTRFS_I(inode)->lock);
 		btrfs_delalloc_release_space(inode, data_reserved,
 				start_index << PAGE_SHIFT,
-				(page_cnt - i_done) << PAGE_SHIFT);
+				(page_cnt - i_done) << PAGE_SHIFT, true);
 	}
 
 
@@ -1215,7 +1221,8 @@ static int cluster_pages_for_defrag(struct inode *inode,
 		unlock_page(pages[i]);
 		put_page(pages[i]);
 	}
-	btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT);
+	btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT,
+				       false);
 	extent_changeset_free(data_reserved);
 	return i_done;
 out:
@@ -1225,8 +1232,9 @@ static int cluster_pages_for_defrag(struct inode *inode,
 	}
 	btrfs_delalloc_release_space(inode, data_reserved,
 			start_index << PAGE_SHIFT,
-			page_cnt << PAGE_SHIFT);
-	btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT);
+			page_cnt << PAGE_SHIFT, true);
+	btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT,
+				       true);
 	extent_changeset_free(data_reserved);
 	return ret;
 
@@ -1758,6 +1766,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
 	struct btrfs_trans_handle *trans;
 	u64 root_flags;
 	u64 flags;
+	bool clear_received_uuid = false;
 	int ret = 0;
 
 	if (!inode_owner_or_capable(inode))
@@ -1807,6 +1816,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
 			btrfs_set_root_flags(&root->root_item,
 				     root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY);
 			spin_unlock(&root->root_item_lock);
+			clear_received_uuid = true;
 		} else {
 			spin_unlock(&root->root_item_lock);
 			btrfs_warn(fs_info,
@@ -1823,6 +1833,24 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
 		goto out_reset;
 	}
 
+	if (clear_received_uuid) {
+	        if (!btrfs_is_empty_uuid(root->root_item.received_uuid)) {
+	                ret = btrfs_uuid_tree_rem(trans, fs_info,
+	                                root->root_item.received_uuid,
+	                                BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+	                                root->root_key.objectid);
+
+	                if (ret && ret != -ENOENT) {
+	                        btrfs_abort_transaction(trans, ret);
+	                        btrfs_end_transaction(trans);
+	                        goto out_reset;
+	                }
+
+	                memset(root->root_item.received_uuid, 0,
+	                                BTRFS_UUID_SIZE);
+	        }
+	}
+
 	ret = btrfs_update_root(trans, fs_info->tree_root,
 				&root->root_key, &root->root_item);
 	if (ret < 0) {
@@ -3936,73 +3964,6 @@ int btrfs_clone_file_range(struct file *src_file, loff_t off,
 	return btrfs_clone_files(dst_file, src_file, off, len, destoff);
 }
 
-/*
- * there are many ways the trans_start and trans_end ioctls can lead
- * to deadlocks.  They should only be used by applications that
- * basically own the machine, and have a very in depth understanding
- * of all the possible deadlocks and enospc problems.
- */
-static long btrfs_ioctl_trans_start(struct file *file)
-{
-	struct inode *inode = file_inode(file);
-	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-	struct btrfs_root *root = BTRFS_I(inode)->root;
-	struct btrfs_trans_handle *trans;
-	struct btrfs_file_private *private;
-	int ret;
-	static bool warned = false;
-
-	ret = -EPERM;
-	if (!capable(CAP_SYS_ADMIN))
-		goto out;
-
-	if (!warned) {
-		btrfs_warn(fs_info,
-			"Userspace transaction mechanism is considered "
-			"deprecated and slated to be removed in 4.17. "
-			"If you have a valid use case please "
-			"speak up on the mailing list");
-		WARN_ON(1);
-		warned = true;
-	}
-
-	ret = -EINPROGRESS;
-	private = file->private_data;
-	if (private && private->trans)
-		goto out;
-	if (!private) {
-		private = kzalloc(sizeof(struct btrfs_file_private),
-				  GFP_KERNEL);
-		if (!private)
-			return -ENOMEM;
-		file->private_data = private;
-	}
-
-	ret = -EROFS;
-	if (btrfs_root_readonly(root))
-		goto out;
-
-	ret = mnt_want_write_file(file);
-	if (ret)
-		goto out;
-
-	atomic_inc(&fs_info->open_ioctl_trans);
-
-	ret = -ENOMEM;
-	trans = btrfs_start_ioctl_transaction(root);
-	if (IS_ERR(trans))
-		goto out_drop;
-
-	private->trans = trans;
-	return 0;
-
-out_drop:
-	atomic_dec(&fs_info->open_ioctl_trans);
-	mnt_drop_write_file(file);
-out:
-	return ret;
-}
-
 static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
 {
 	struct inode *inode = file_inode(file);
@@ -4244,30 +4205,6 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
 	return ret;
 }
 
-/*
- * there are many ways the trans_start and trans_end ioctls can lead
- * to deadlocks.  They should only be used by applications that
- * basically own the machine, and have a very in depth understanding
- * of all the possible deadlocks and enospc problems.
- */
-long btrfs_ioctl_trans_end(struct file *file)
-{
-	struct inode *inode = file_inode(file);
-	struct btrfs_root *root = BTRFS_I(inode)->root;
-	struct btrfs_file_private *private = file->private_data;
-
-	if (!private || !private->trans)
-		return -EINVAL;
-
-	btrfs_end_transaction(private->trans);
-	private->trans = NULL;
-
-	atomic_dec(&root->fs_info->open_ioctl_trans);
-
-	mnt_drop_write_file(file);
-	return 0;
-}
-
 static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
 					    void __user *argp)
 {
@@ -4429,7 +4366,8 @@ static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info,
 		ret = 0;
 		break;
 	case BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL:
-		ret = btrfs_dev_replace_cancel(fs_info, p);
+		p->result = btrfs_dev_replace_cancel(fs_info);
+		ret = 0;
 		break;
 	default:
 		ret = -EINVAL;
@@ -5574,10 +5512,6 @@ long btrfs_ioctl(struct file *file, unsigned int
 		return btrfs_ioctl_dev_info(fs_info, argp);
 	case BTRFS_IOC_BALANCE:
 		return btrfs_ioctl_balance(file, NULL);
-	case BTRFS_IOC_TRANS_START:
-		return btrfs_ioctl_trans_start(file);
-	case BTRFS_IOC_TRANS_END:
-		return btrfs_ioctl_trans_end(file);
 	case BTRFS_IOC_TREE_SEARCH:
 		return btrfs_ioctl_tree_search(file, argp);
 	case BTRFS_IOC_TREE_SEARCH_V2:
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 5b311aeddcc8..c6f5f7e274a5 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -610,7 +610,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
 	btrfs_mod_outstanding_extents(btrfs_inode, -1);
 	spin_unlock(&btrfs_inode->lock);
 	if (root != fs_info->tree_root)
-		btrfs_delalloc_release_metadata(btrfs_inode, entry->len);
+		btrfs_delalloc_release_metadata(btrfs_inode, entry->len, false);
 
 	tree = &btrfs_inode->ordered_tree;
 	spin_lock_irq(&tree->lock);
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 56c4c0ee6381..c53e2cfb72d9 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -151,7 +151,9 @@ static inline int btrfs_ordered_sum_size(struct btrfs_fs_info *fs_info,
 					 unsigned long bytes)
 {
 	int num_sectors = (int)DIV_ROUND_UP(bytes, fs_info->sectorsize);
-	return sizeof(struct btrfs_ordered_sum) + num_sectors * sizeof(u32);
+	int csum_size = btrfs_super_csum_size(fs_info->super_copy);
+
+	return sizeof(struct btrfs_ordered_sum) + num_sectors * csum_size;
 }
 
 static inline void
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index b30a056963ab..28a4be192cbb 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -19,8 +19,8 @@
 #include <linux/hashtable.h>
 #include "props.h"
 #include "btrfs_inode.h"
-#include "hash.h"
 #include "transaction.h"
+#include "ctree.h"
 #include "xattr.h"
 #include "compression.h"
 
@@ -407,7 +407,7 @@ static int prop_compression_apply(struct inode *inode,
 		type = BTRFS_COMPRESS_LZO;
 	else if (!strncmp("zlib", value, 4))
 		type = BTRFS_COMPRESS_ZLIB;
-	else if (!strncmp("zstd", value, len))
+	else if (!strncmp("zstd", value, 4))
 		type = BTRFS_COMPRESS_ZSTD;
 	else
 		return -EINVAL;
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index aa259d6986e1..00f37fec9aac 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -47,6 +47,82 @@
  *  - check all ioctl parameters
  */
 
+/*
+ * Helpers to access qgroup reservation
+ *
+ * Callers should ensure the lock context and type are valid
+ */
+
+static u64 qgroup_rsv_total(const struct btrfs_qgroup *qgroup)
+{
+	u64 ret = 0;
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+		ret += qgroup->rsv.values[i];
+
+	return ret;
+}
+
+#ifdef CONFIG_BTRFS_DEBUG
+static const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type)
+{
+	if (type == BTRFS_QGROUP_RSV_DATA)
+		return "data";
+	if (type == BTRFS_QGROUP_RSV_META_PERTRANS)
+		return "meta_pertrans";
+	if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
+		return "meta_prealloc";
+	return NULL;
+}
+#endif
+
+static void qgroup_rsv_add(struct btrfs_fs_info *fs_info,
+			   struct btrfs_qgroup *qgroup, u64 num_bytes,
+			   enum btrfs_qgroup_rsv_type type)
+{
+	trace_qgroup_update_reserve(fs_info, qgroup, num_bytes, type);
+	qgroup->rsv.values[type] += num_bytes;
+}
+
+static void qgroup_rsv_release(struct btrfs_fs_info *fs_info,
+			       struct btrfs_qgroup *qgroup, u64 num_bytes,
+			       enum btrfs_qgroup_rsv_type type)
+{
+	trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type);
+	if (qgroup->rsv.values[type] >= num_bytes) {
+		qgroup->rsv.values[type] -= num_bytes;
+		return;
+	}
+#ifdef CONFIG_BTRFS_DEBUG
+	WARN_RATELIMIT(1,
+		"qgroup %llu %s reserved space underflow, have %llu to free %llu",
+		qgroup->qgroupid, qgroup_rsv_type_str(type),
+		qgroup->rsv.values[type], num_bytes);
+#endif
+	qgroup->rsv.values[type] = 0;
+}
+
+static void qgroup_rsv_add_by_qgroup(struct btrfs_fs_info *fs_info,
+				     struct btrfs_qgroup *dest,
+				     struct btrfs_qgroup *src)
+{
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+		qgroup_rsv_add(fs_info, dest, src->rsv.values[i], i);
+}
+
+static void qgroup_rsv_release_by_qgroup(struct btrfs_fs_info *fs_info,
+					 struct btrfs_qgroup *dest,
+					  struct btrfs_qgroup *src)
+{
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+		qgroup_rsv_release(fs_info, dest, src->rsv.values[i], i);
+}
+
 static void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq,
 					   int mod)
 {
@@ -826,10 +902,8 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
 	int slot;
 
 	mutex_lock(&fs_info->qgroup_ioctl_lock);
-	if (fs_info->quota_root) {
-		set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags);
+	if (fs_info->quota_root)
 		goto out;
-	}
 
 	fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
 	if (!fs_info->qgroup_ulist) {
@@ -923,8 +997,15 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
 	}
 	spin_lock(&fs_info->qgroup_lock);
 	fs_info->quota_root = quota_root;
-	set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags);
+	set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
 	spin_unlock(&fs_info->qgroup_lock);
+	ret = qgroup_rescan_init(fs_info, 0, 1);
+	if (!ret) {
+	        qgroup_rescan_zero_tracking(fs_info);
+	        btrfs_queue_work(fs_info->qgroup_rescan_workers,
+	                         &fs_info->qgroup_rescan_work);
+	}
+
 out_free_path:
 	btrfs_free_path(path);
 out_free_root:
@@ -991,33 +1072,29 @@ static void qgroup_dirty(struct btrfs_fs_info *fs_info,
 		list_add(&qgroup->dirty, &fs_info->dirty_qgroups);
 }
 
-static void report_reserved_underflow(struct btrfs_fs_info *fs_info,
-				      struct btrfs_qgroup *qgroup,
-				      u64 num_bytes)
-{
-#ifdef CONFIG_BTRFS_DEBUG
-	WARN_ON(qgroup->reserved < num_bytes);
-	btrfs_debug(fs_info,
-		"qgroup %llu reserved space underflow, have: %llu, to free: %llu",
-		qgroup->qgroupid, qgroup->reserved, num_bytes);
-#endif
-	qgroup->reserved = 0;
-}
 /*
- * The easy accounting, if we are adding/removing the only ref for an extent
- * then this qgroup and all of the parent qgroups get their reference and
- * exclusive counts adjusted.
+ * The easy accounting, we're updating qgroup relationship whose child qgroup
+ * only has exclusive extents.
+ *
+ * In this case, all exclsuive extents will also be exlusive for parent, so
+ * excl/rfer just get added/removed.
+ *
+ * So is qgroup reservation space, which should also be added/removed to
+ * parent.
+ * Or when child tries to release reservation space, parent will underflow its
+ * reservation (for relationship adding case).
  *
  * Caller should hold fs_info->qgroup_lock.
  */
 static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 				    struct ulist *tmp, u64 ref_root,
-				    u64 num_bytes, int sign)
+				    struct btrfs_qgroup *src, int sign)
 {
 	struct btrfs_qgroup *qgroup;
 	struct btrfs_qgroup_list *glist;
 	struct ulist_node *unode;
 	struct ulist_iterator uiter;
+	u64 num_bytes = src->excl;
 	int ret = 0;
 
 	qgroup = find_qgroup_rb(fs_info, ref_root);
@@ -1030,13 +1107,11 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 	WARN_ON(sign < 0 && qgroup->excl < num_bytes);
 	qgroup->excl += sign * num_bytes;
 	qgroup->excl_cmpr += sign * num_bytes;
-	if (sign > 0) {
-		trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes);
-		if (qgroup->reserved < num_bytes)
-			report_reserved_underflow(fs_info, qgroup, num_bytes);
-		else
-			qgroup->reserved -= num_bytes;
-	}
+
+	if (sign > 0)
+		qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+	else
+		qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
 
 	qgroup_dirty(fs_info, qgroup);
 
@@ -1056,15 +1131,10 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 		qgroup->rfer_cmpr += sign * num_bytes;
 		WARN_ON(sign < 0 && qgroup->excl < num_bytes);
 		qgroup->excl += sign * num_bytes;
-		if (sign > 0) {
-			trace_qgroup_update_reserve(fs_info, qgroup,
-						    -(s64)num_bytes);
-			if (qgroup->reserved < num_bytes)
-				report_reserved_underflow(fs_info, qgroup,
-							  num_bytes);
-			else
-				qgroup->reserved -= num_bytes;
-		}
+		if (sign > 0)
+			qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+		else
+			qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
 		qgroup->excl_cmpr += sign * num_bytes;
 		qgroup_dirty(fs_info, qgroup);
 
@@ -1107,7 +1177,7 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info,
 	if (qgroup->excl == qgroup->rfer) {
 		ret = 0;
 		err = __qgroup_excl_accounting(fs_info, tmp, dst,
-					       qgroup->excl, sign);
+					       qgroup, sign);
 		if (err < 0) {
 			ret = err;
 			goto out;
@@ -2080,17 +2150,9 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
 {
 	struct btrfs_root *quota_root = fs_info->quota_root;
 	int ret = 0;
-	int start_rescan_worker = 0;
 
 	if (!quota_root)
-		goto out;
-
-	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
-	    test_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags))
-		start_rescan_worker = 1;
-
-	if (test_and_clear_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags))
-		set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+		return ret;
 
 	spin_lock(&fs_info->qgroup_lock);
 	while (!list_empty(&fs_info->dirty_qgroups)) {
@@ -2119,18 +2181,6 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
 	if (ret)
 		fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
 
-	if (!ret && start_rescan_worker) {
-		ret = qgroup_rescan_init(fs_info, 0, 1);
-		if (!ret) {
-			qgroup_rescan_zero_tracking(fs_info);
-			btrfs_queue_work(fs_info->qgroup_rescan_workers,
-					 &fs_info->qgroup_rescan_work);
-		}
-		ret = 0;
-	}
-
-out:
-
 	return ret;
 }
 
@@ -2338,24 +2388,24 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes)
 {
 	if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
-	    qg->reserved + (s64)qg->rfer + num_bytes > qg->max_rfer)
+	    qgroup_rsv_total(qg) + (s64)qg->rfer + num_bytes > qg->max_rfer)
 		return false;
 
 	if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
-	    qg->reserved + (s64)qg->excl + num_bytes > qg->max_excl)
+	    qgroup_rsv_total(qg) + (s64)qg->excl + num_bytes > qg->max_excl)
 		return false;
 
 	return true;
 }
 
-static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
+static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce,
+			  enum btrfs_qgroup_rsv_type type)
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	u64 ref_root = root->root_key.objectid;
 	int ret = 0;
-	int retried = 0;
 	struct ulist_node *unode;
 	struct ulist_iterator uiter;
 
@@ -2369,7 +2419,6 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
 	    capable(CAP_SYS_RESOURCE))
 		enforce = false;
 
-retry:
 	spin_lock(&fs_info->qgroup_lock);
 	quota_root = fs_info->quota_root;
 	if (!quota_root)
@@ -2396,27 +2445,6 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
 		qg = unode_aux_to_qgroup(unode);
 
 		if (enforce && !qgroup_check_limits(qg, num_bytes)) {
-			/*
-			 * Commit the tree and retry, since we may have
-			 * deletions which would free up space.
-			 */
-			if (!retried && qg->reserved > 0) {
-				struct btrfs_trans_handle *trans;
-
-				spin_unlock(&fs_info->qgroup_lock);
-				ret = btrfs_start_delalloc_inodes(root, 0);
-				if (ret)
-					return ret;
-				btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
-				trans = btrfs_join_transaction(root);
-				if (IS_ERR(trans))
-					return PTR_ERR(trans);
-				ret = btrfs_commit_transaction(trans);
-				if (ret)
-					return ret;
-				retried++;
-				goto retry;
-			}
 			ret = -EDQUOT;
 			goto out;
 		}
@@ -2439,8 +2467,8 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
 
 		qg = unode_aux_to_qgroup(unode);
 
-		trace_qgroup_update_reserve(fs_info, qg, num_bytes);
-		qg->reserved += num_bytes;
+		trace_qgroup_update_reserve(fs_info, qg, num_bytes, type);
+		qgroup_rsv_add(fs_info, qg, num_bytes, type);
 	}
 
 out:
@@ -2448,8 +2476,19 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
 	return ret;
 }
 
+/*
+ * Free @num_bytes of reserved space with @type for qgroup.
+ * (normally level 0 qgroup).
+ *
+ * Will handle all higher level qgroup either.
+ *
+ * NOTE: If @num_bytes is (u64)-1, this means to free all bytes of
+ * this qgroup.
+ * This special case is only used for META_PERTRANS type.
+ */
 void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
-			       u64 ref_root, u64 num_bytes)
+			       u64 ref_root, u64 num_bytes,
+			       enum btrfs_qgroup_rsv_type type)
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
@@ -2463,6 +2502,10 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
 	if (num_bytes == 0)
 		return;
 
+	if (num_bytes == (u64)-1 && type != BTRFS_QGROUP_RSV_META_PERTRANS) {
+		WARN(1, "%s: Invalid type to free", __func__);
+		return;
+	}
 	spin_lock(&fs_info->qgroup_lock);
 
 	quota_root = fs_info->quota_root;
@@ -2473,6 +2516,13 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
 	if (!qgroup)
 		goto out;
 
+	if (num_bytes == (u64)-1)
+		/*
+		 * We're freeing all pertrans rsv, get reserved value from
+		 * level 0 qgroup as real num_bytes to free.
+		 */
+		num_bytes = qgroup->rsv.values[type];
+
 	ulist_reinit(fs_info->qgroup_ulist);
 	ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
 			(uintptr_t)qgroup, GFP_ATOMIC);
@@ -2485,11 +2535,8 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
 
 		qg = unode_aux_to_qgroup(unode);
 
-		trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes);
-		if (qg->reserved < num_bytes)
-			report_reserved_underflow(fs_info, qg, num_bytes);
-		else
-			qg->reserved -= num_bytes;
+		trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes, type);
+		qgroup_rsv_release(fs_info, qg, num_bytes, type);
 
 		list_for_each_entry(glist, &qg->groups, next_group) {
 			ret = ulist_add(fs_info->qgroup_ulist,
@@ -2877,7 +2924,7 @@ int btrfs_qgroup_reserve_data(struct inode *inode,
 					to_reserve, QGROUP_RESERVE);
 	if (ret < 0)
 		goto cleanup;
-	ret = qgroup_reserve(root, to_reserve, true);
+	ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA);
 	if (ret < 0)
 		goto cleanup;
 
@@ -2940,7 +2987,8 @@ static int qgroup_free_reserved_data(struct inode *inode,
 			goto out;
 		freed += changeset.bytes_changed;
 	}
-	btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed);
+	btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed,
+				  BTRFS_QGROUP_RSV_DATA);
 	ret = freed;
 out:
 	extent_changeset_release(&changeset);
@@ -2972,7 +3020,7 @@ static int __btrfs_qgroup_release_data(struct inode *inode,
 	if (free)
 		btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info,
 				BTRFS_I(inode)->root->objectid,
-				changeset.bytes_changed);
+				changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA);
 	ret = changeset.bytes_changed;
 out:
 	extent_changeset_release(&changeset);
@@ -3017,8 +3065,48 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len)
 	return __btrfs_qgroup_release_data(inode, NULL, start, len, 0);
 }
 
-int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
-			      bool enforce)
+static void add_root_meta_rsv(struct btrfs_root *root, int num_bytes,
+			      enum btrfs_qgroup_rsv_type type)
+{
+	if (type != BTRFS_QGROUP_RSV_META_PREALLOC &&
+	    type != BTRFS_QGROUP_RSV_META_PERTRANS)
+		return;
+	if (num_bytes == 0)
+		return;
+
+	spin_lock(&root->qgroup_meta_rsv_lock);
+	if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
+		root->qgroup_meta_rsv_prealloc += num_bytes;
+	else
+		root->qgroup_meta_rsv_pertrans += num_bytes;
+	spin_unlock(&root->qgroup_meta_rsv_lock);
+}
+
+static int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes,
+			     enum btrfs_qgroup_rsv_type type)
+{
+	if (type != BTRFS_QGROUP_RSV_META_PREALLOC &&
+	    type != BTRFS_QGROUP_RSV_META_PERTRANS)
+		return 0;
+	if (num_bytes == 0)
+		return 0;
+
+	spin_lock(&root->qgroup_meta_rsv_lock);
+	if (type == BTRFS_QGROUP_RSV_META_PREALLOC) {
+		num_bytes = min_t(u64, root->qgroup_meta_rsv_prealloc,
+				  num_bytes);
+		root->qgroup_meta_rsv_prealloc -= num_bytes;
+	} else {
+		num_bytes = min_t(u64, root->qgroup_meta_rsv_pertrans,
+				  num_bytes);
+		root->qgroup_meta_rsv_pertrans -= num_bytes;
+	}
+	spin_unlock(&root->qgroup_meta_rsv_lock);
+	return num_bytes;
+}
+
+int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
+				enum btrfs_qgroup_rsv_type type, bool enforce)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	int ret;
@@ -3028,31 +3116,39 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
 		return 0;
 
 	BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
-	trace_qgroup_meta_reserve(root, (s64)num_bytes);
-	ret = qgroup_reserve(root, num_bytes, enforce);
+	trace_qgroup_meta_reserve(root, type, (s64)num_bytes);
+	ret = qgroup_reserve(root, num_bytes, enforce, type);
 	if (ret < 0)
 		return ret;
-	atomic64_add(num_bytes, &root->qgroup_meta_rsv);
+	/*
+	 * Record what we have reserved into root.
+	 *
+	 * To avoid quota disabled->enabled underflow.
+	 * In that case, we may try to free space we haven't reserved
+	 * (since quota was disabled), so record what we reserved into root.
+	 * And ensure later release won't underflow this number.
+	 */
+	add_root_meta_rsv(root, num_bytes, type);
 	return ret;
 }
 
-void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
+void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
-	u64 reserved;
 
 	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
 	    !is_fstree(root->objectid))
 		return;
 
-	reserved = atomic64_xchg(&root->qgroup_meta_rsv, 0);
-	if (reserved == 0)
-		return;
-	trace_qgroup_meta_reserve(root, -(s64)reserved);
-	btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved);
+	/* TODO: Update trace point to handle such free */
+	trace_qgroup_meta_free_all_pertrans(root);
+	/* Special value -1 means to free all reserved space */
+	btrfs_qgroup_free_refroot(fs_info, root->objectid, (u64)-1,
+				  BTRFS_QGROUP_RSV_META_PERTRANS);
 }
 
-void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
+void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
+			      enum btrfs_qgroup_rsv_type type)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 
@@ -3060,11 +3156,75 @@ void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
 	    !is_fstree(root->objectid))
 		return;
 
+	/*
+	 * reservation for META_PREALLOC can happen before quota is enabled,
+	 * which can lead to underflow.
+	 * Here ensure we will only free what we really have reserved.
+	 */
+	num_bytes = sub_root_meta_rsv(root, num_bytes, type);
 	BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
-	WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes);
-	atomic64_sub(num_bytes, &root->qgroup_meta_rsv);
-	trace_qgroup_meta_reserve(root, -(s64)num_bytes);
-	btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes);
+	trace_qgroup_meta_reserve(root, type, -(s64)num_bytes);
+	btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type);
+}
+
+static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root,
+				int num_bytes)
+{
+	struct btrfs_root *quota_root = fs_info->quota_root;
+	struct btrfs_qgroup *qgroup;
+	struct ulist_node *unode;
+	struct ulist_iterator uiter;
+	int ret = 0;
+
+	if (num_bytes == 0)
+		return;
+	if (!quota_root)
+		return;
+
+	spin_lock(&fs_info->qgroup_lock);
+	qgroup = find_qgroup_rb(fs_info, ref_root);
+	if (!qgroup)
+		goto out;
+	ulist_reinit(fs_info->qgroup_ulist);
+	ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
+		       (uintptr_t)qgroup, GFP_ATOMIC);
+	if (ret < 0)
+		goto out;
+	ULIST_ITER_INIT(&uiter);
+	while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
+		struct btrfs_qgroup *qg;
+		struct btrfs_qgroup_list *glist;
+
+		qg = unode_aux_to_qgroup(unode);
+
+		qgroup_rsv_release(fs_info, qg, num_bytes,
+				BTRFS_QGROUP_RSV_META_PREALLOC);
+		qgroup_rsv_add(fs_info, qg, num_bytes,
+				BTRFS_QGROUP_RSV_META_PERTRANS);
+		list_for_each_entry(glist, &qg->groups, next_group) {
+			ret = ulist_add(fs_info->qgroup_ulist,
+					glist->group->qgroupid,
+					(uintptr_t)glist->group, GFP_ATOMIC);
+			if (ret < 0)
+				goto out;
+		}
+	}
+out:
+	spin_unlock(&fs_info->qgroup_lock);
+}
+
+void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
+{
+	struct btrfs_fs_info *fs_info = root->fs_info;
+
+	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+	    !is_fstree(root->objectid))
+		return;
+	/* Same as btrfs_qgroup_free_meta_prealloc() */
+	num_bytes = sub_root_meta_rsv(root, num_bytes,
+				      BTRFS_QGROUP_RSV_META_PREALLOC);
+	trace_qgroup_meta_convert(root, num_bytes);
+	qgroup_convert_meta(fs_info, root->objectid, num_bytes);
 }
 
 /*
@@ -3092,7 +3252,7 @@ void btrfs_qgroup_check_reserved_leak(struct inode *inode)
 		}
 		btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info,
 				BTRFS_I(inode)->root->objectid,
-				changeset.bytes_changed);
+				changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA);
 
 	}
 	extent_changeset_release(&changeset);
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index d9984e87cddf..4814d680c50f 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -61,6 +61,47 @@ struct btrfs_qgroup_extent_record {
 	struct ulist *old_roots;
 };
 
+/*
+ * Qgroup reservation types:
+ * DATA:
+ *	space reserved for data
+ *
+ * META_PERTRANS:
+ * 	Space reserved for metadata (per-transaction)
+ * 	Due to the fact that qgroup data is only updated at transaction commit
+ * 	time, reserved space for metadata must be kept until transaction
+ * 	commitment.
+ * 	Any metadata reserved used in btrfs_start_transaction() should be this
+ * 	type.
+ *
+ * META_PREALLOC:
+ *	There are cases where metadata space is reserved before starting
+ *	transaction, and then btrfs_join_transaction() to get a trans handler.
+ *	Any metadata reserved for such usage should be this type.
+ *	And after join_transaction() part (or all) of such reservation should
+ *	be converted into META_PERTRANS.
+ */
+enum btrfs_qgroup_rsv_type {
+	BTRFS_QGROUP_RSV_DATA = 0,
+	BTRFS_QGROUP_RSV_META_PERTRANS,
+	BTRFS_QGROUP_RSV_META_PREALLOC,
+	BTRFS_QGROUP_RSV_LAST,
+};
+
+/*
+ * Represents how many bytes we have reserved for this qgroup.
+ *
+ * Each type should have different reservation behavior.
+ * E.g, data follows its io_tree flag modification, while
+ * *currently* meta is just reserve-and-clear during transcation.
+ *
+ * TODO: Add new type for reservation which can survive transaction commit.
+ * Currect metadata reservation behavior is not suitable for such case.
+ */
+struct btrfs_qgroup_rsv {
+	u64 values[BTRFS_QGROUP_RSV_LAST];
+};
+
 /*
  * one struct for each qgroup, organized in fs_info->qgroup_tree.
  */
@@ -87,7 +128,7 @@ struct btrfs_qgroup {
 	/*
 	 * reservation tracking
 	 */
-	u64 reserved;
+	struct btrfs_qgroup_rsv rsv;
 
 	/*
 	 * lists
@@ -228,12 +269,14 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 			 struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid,
 			 struct btrfs_qgroup_inherit *inherit);
 void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
-			       u64 ref_root, u64 num_bytes);
+			       u64 ref_root, u64 num_bytes,
+			       enum btrfs_qgroup_rsv_type type);
 static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info,
 						 u64 ref_root, u64 num_bytes)
 {
 	trace_btrfs_qgroup_free_delayed_ref(fs_info, ref_root, num_bytes);
-	btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes);
+	btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes,
+				  BTRFS_QGROUP_RSV_DATA);
 }
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
@@ -248,9 +291,54 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len);
 int btrfs_qgroup_free_data(struct inode *inode,
 			struct extent_changeset *reserved, u64 start, u64 len);
 
-int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
-			      bool enforce);
-void btrfs_qgroup_free_meta_all(struct btrfs_root *root);
-void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes);
+int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
+				enum btrfs_qgroup_rsv_type type, bool enforce);
+/* Reserve metadata space for pertrans and prealloc type*/
+static inline int btrfs_qgroup_reserve_meta_pertrans(struct btrfs_root *root,
+				int num_bytes, bool enforce)
+{
+	return __btrfs_qgroup_reserve_meta(root, num_bytes,
+			BTRFS_QGROUP_RSV_META_PERTRANS, enforce);
+}
+static inline int btrfs_qgroup_reserve_meta_prealloc(struct btrfs_root *root,
+				int num_bytes, bool enforce)
+{
+	return __btrfs_qgroup_reserve_meta(root, num_bytes,
+			BTRFS_QGROUP_RSV_META_PREALLOC, enforce);
+}
+
+void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
+			     enum btrfs_qgroup_rsv_type type);
+
+/* Free per-transaction meta reservation for error handler */
+static inline void btrfs_qgroup_free_meta_pertrans(struct btrfs_root *root,
+						   int num_bytes)
+{
+	__btrfs_qgroup_free_meta(root, num_bytes,
+			BTRFS_QGROUP_RSV_META_PERTRANS);
+}
+
+/* Pre-allocated meta reservation can be freed at need */
+static inline void btrfs_qgroup_free_meta_prealloc(struct btrfs_root *root,
+						   int num_bytes)
+{
+	__btrfs_qgroup_free_meta(root, num_bytes,
+			BTRFS_QGROUP_RSV_META_PREALLOC);
+}
+
+/*
+ * Per-transaction meta reservation should be all freed at transaction commit
+ * time
+ */
+void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root);
+
+/*
+ * Convert @num_bytes of META_PREALLOCATED reservation to META_PERTRANS.
+ *
+ * This is called when preallocated meta reservation needs to be used.
+ * Normally after btrfs_join_transaction() call.
+ */
+void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes);
+
 void btrfs_qgroup_check_reserved_leak(struct inode *inode);
 #endif /* __BTRFS_QGROUP__ */
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index f0c3f00e97cb..e61e1ee9af9a 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3226,7 +3226,7 @@ static int relocate_file_extent_cluster(struct inode *inode,
 						   mask);
 			if (!page) {
 				btrfs_delalloc_release_metadata(BTRFS_I(inode),
-							PAGE_SIZE);
+							PAGE_SIZE, true);
 				ret = -ENOMEM;
 				goto out;
 			}
@@ -3245,9 +3245,9 @@ static int relocate_file_extent_cluster(struct inode *inode,
 				unlock_page(page);
 				put_page(page);
 				btrfs_delalloc_release_metadata(BTRFS_I(inode),
-							PAGE_SIZE);
+							PAGE_SIZE, true);
 				btrfs_delalloc_release_extents(BTRFS_I(inode),
-							       PAGE_SIZE);
+							       PAGE_SIZE, true);
 				ret = -EIO;
 				goto out;
 			}
@@ -3268,8 +3268,22 @@ static int relocate_file_extent_cluster(struct inode *inode,
 			nr++;
 		}
 
-		btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL,
-					  0);
+		ret = btrfs_set_extent_delalloc(inode, page_start, page_end, 0,
+						NULL, 0);
+		if (ret) {
+			unlock_page(page);
+			put_page(page);
+			btrfs_delalloc_release_metadata(BTRFS_I(inode),
+							 PAGE_SIZE, true);
+			btrfs_delalloc_release_extents(BTRFS_I(inode),
+			                               PAGE_SIZE, true);
+
+			clear_extent_bits(&BTRFS_I(inode)->io_tree,
+					  page_start, page_end,
+					  EXTENT_LOCKED | EXTENT_BOUNDARY);
+			goto out;
+
+		}
 		set_page_dirty(page);
 
 		unlock_extent(&BTRFS_I(inode)->io_tree,
@@ -3278,7 +3292,8 @@ static int relocate_file_extent_cluster(struct inode *inode,
 		put_page(page);
 
 		index++;
-		btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+		btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE,
+					       false);
 		balance_dirty_pages_ratelimited(inode->i_mapping);
 		btrfs_throttle(fs_info);
 	}
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index ec56f33feea9..beb441d0c5c6 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -4620,7 +4620,6 @@ static int write_page_nocow(struct scrub_ctx *sctx,
 {
 	struct bio *bio;
 	struct btrfs_device *dev;
-	int ret;
 
 	dev = sctx->wr_tgtdev;
 	if (!dev)
@@ -4635,17 +4634,15 @@ static int write_page_nocow(struct scrub_ctx *sctx,
 	bio->bi_iter.bi_sector = physical_for_dev_replace >> 9;
 	bio_set_dev(bio, dev->bdev);
 	bio->bi_opf = REQ_OP_WRITE | REQ_SYNC;
-	ret = bio_add_page(bio, page, PAGE_SIZE, 0);
-	if (ret != PAGE_SIZE) {
-leave_with_eio:
+	/* bio_add_page won't fail on a freshly allocated bio */
+	bio_add_page(bio, page, PAGE_SIZE, 0);
+
+	if (btrfsic_submit_bio_wait(bio)) {
 		bio_put(bio);
 		btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
 		return -EIO;
 	}
 
-	if (btrfsic_submit_bio_wait(bio))
-		goto leave_with_eio;
-
 	bio_put(bio);
 	return 0;
 }
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index f306c608dc28..d748675f9570 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -27,10 +27,10 @@
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/compat.h>
+#include <linux/crc32c.h>
 
 #include "send.h"
 #include "backref.h"
-#include "hash.h"
 #include "locking.h"
 #include "disk-io.h"
 #include "btrfs_inode.h"
@@ -112,6 +112,7 @@ struct send_ctx {
 	u64 cur_inode_mode;
 	u64 cur_inode_rdev;
 	u64 cur_inode_last_extent;
+	u64 cur_inode_next_write_offset;
 
 	u64 send_progress;
 
@@ -695,7 +696,7 @@ static int send_cmd(struct send_ctx *sctx)
 	hdr->len = cpu_to_le32(sctx->send_size - sizeof(*hdr));
 	hdr->crc = 0;
 
-	crc = btrfs_crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
+	crc = crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
 	hdr->crc = cpu_to_le32(crc);
 
 	ret = write_buf(sctx->send_filp, sctx->send_buf, sctx->send_size,
@@ -5005,6 +5006,9 @@ static int send_hole(struct send_ctx *sctx, u64 end)
 	u64 len;
 	int ret = 0;
 
+	if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
+		return send_update_extent(sctx, offset, end - offset);
+
 	p = fs_path_alloc();
 	if (!p)
 		return -ENOMEM;
@@ -5026,6 +5030,7 @@ static int send_hole(struct send_ctx *sctx, u64 end)
 			break;
 		offset += len;
 	}
+	sctx->cur_inode_next_write_offset = offset;
 tlv_put_failure:
 	fs_path_free(p);
 	return ret;
@@ -5261,6 +5266,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
 	} else {
 		ret = send_extent_data(sctx, offset, len);
 	}
+	sctx->cur_inode_next_write_offset = offset + len;
 out:
 	return ret;
 }
@@ -5785,6 +5791,7 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
 	u64 right_gid;
 	int need_chmod = 0;
 	int need_chown = 0;
+	int need_truncate = 1;
 	int pending_move = 0;
 	int refs_processed = 0;
 
@@ -5822,9 +5829,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
 		need_chown = 1;
 		if (!S_ISLNK(sctx->cur_inode_mode))
 			need_chmod = 1;
+		if (sctx->cur_inode_next_write_offset == sctx->cur_inode_size)
+			need_truncate = 0;
 	} else {
+		u64 old_size;
+
 		ret = get_inode_info(sctx->parent_root, sctx->cur_ino,
-				NULL, NULL, &right_mode, &right_uid,
+				&old_size, NULL, &right_mode, &right_uid,
 				&right_gid, NULL);
 		if (ret < 0)
 			goto out;
@@ -5833,6 +5844,10 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
 			need_chown = 1;
 		if (!S_ISLNK(sctx->cur_inode_mode) && left_mode != right_mode)
 			need_chmod = 1;
+		if ((old_size == sctx->cur_inode_size) ||
+		    (sctx->cur_inode_size > old_size &&
+		     sctx->cur_inode_next_write_offset == sctx->cur_inode_size))
+			need_truncate = 0;
 	}
 
 	if (S_ISREG(sctx->cur_inode_mode)) {
@@ -5851,10 +5866,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
 					goto out;
 			}
 		}
-		ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen,
-				sctx->cur_inode_size);
-		if (ret < 0)
-			goto out;
+		if (need_truncate) {
+			ret = send_truncate(sctx, sctx->cur_ino,
+					    sctx->cur_inode_gen,
+					    sctx->cur_inode_size);
+			if (ret < 0)
+				goto out;
+		}
 	}
 
 	if (need_chown) {
@@ -5908,6 +5926,7 @@ static int changed_inode(struct send_ctx *sctx,
 	sctx->cur_ino = key->objectid;
 	sctx->cur_inode_new_gen = 0;
 	sctx->cur_inode_last_extent = (u64)-1;
+	sctx->cur_inode_next_write_offset = 0;
 
 	/*
 	 * Set send_progress to current inode. This will tell all get_cur_xxx
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 6e71a2a78363..53018c687c86 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include <linux/cleancache.h>
 #include <linux/ratelimit.h>
+#include <linux/crc32c.h>
 #include <linux/btrfs.h>
 #include "delayed-inode.h"
 #include "ctree.h"
@@ -48,7 +49,6 @@
 #include "transaction.h"
 #include "btrfs_inode.h"
 #include "print-tree.h"
-#include "hash.h"
 #include "props.h"
 #include "xattr.h"
 #include "volumes.h"
@@ -344,8 +344,8 @@ static const match_table_t tokens = {
 	{Opt_nobarrier, "nobarrier"},
 	{Opt_barrier, "barrier"},
 	{Opt_max_inline, "max_inline=%s"},
-	{Opt_alloc_start, "alloc_start=%s"},
-	{Opt_thread_pool, "thread_pool=%d"},
+	{Opt_alloc_start, "alloc_start=%s"},		/* deprecated */
+	{Opt_thread_pool, "thread_pool=%u"},
 	{Opt_compress, "compress"},
 	{Opt_compress_type, "compress=%s"},
 	{Opt_compress_force, "compress-force"},
@@ -361,7 +361,7 @@ static const match_table_t tokens = {
 	{Opt_norecovery, "norecovery"},
 	{Opt_flushoncommit, "flushoncommit"},
 	{Opt_noflushoncommit, "noflushoncommit"},
-	{Opt_ratio, "metadata_ratio=%d"},
+	{Opt_ratio, "metadata_ratio=%u"},
 	{Opt_discard, "discard"},
 	{Opt_nodiscard, "nodiscard"},
 	{Opt_space_cache, "space_cache"},
@@ -370,7 +370,7 @@ static const match_table_t tokens = {
 	{Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
 	{Opt_enospc_debug, "enospc_debug"},
 	{Opt_noenospc_debug, "noenospc_debug"},
-	{Opt_subvolrootid, "subvolrootid=%d"},
+	{Opt_subvolrootid, "subvolrootid=%d"},		/* deprecated */
 	{Opt_defrag, "autodefrag"},
 	{Opt_nodefrag, "noautodefrag"},
 	{Opt_inode_cache, "inode_cache"},
@@ -381,10 +381,10 @@ static const match_table_t tokens = {
 	{Opt_skip_balance, "skip_balance"},
 	{Opt_check_integrity, "check_int"},
 	{Opt_check_integrity_including_extent_data, "check_int_data"},
-	{Opt_check_integrity_print_mask, "check_int_print_mask=%d"},
+	{Opt_check_integrity_print_mask, "check_int_print_mask=%u"},
 	{Opt_rescan_uuid_tree, "rescan_uuid_tree"},
 	{Opt_fatal_errors, "fatal_errors=%s"},
-	{Opt_commit_interval, "commit=%d"},
+	{Opt_commit_interval, "commit=%u"},
 #ifdef CONFIG_BTRFS_DEBUG
 	{Opt_fragment_data, "fragment=data"},
 	{Opt_fragment_metadata, "fragment=metadata"},
@@ -522,9 +522,10 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 				btrfs_clear_opt(info->mount_opt, NODATASUM);
 				btrfs_set_fs_incompat(info, COMPRESS_LZO);
 				no_compress = 0;
-			} else if (strcmp(args[0].from, "zstd") == 0) {
+			} else if (strncmp(args[0].from, "zstd", 4) == 0) {
 				compress_type = "zstd";
 				info->compress_type = BTRFS_COMPRESS_ZSTD;
+				info->compress_level = btrfs_compress_str2level(args[0].from);
 				btrfs_set_opt(info->mount_opt, COMPRESS);
 				btrfs_clear_opt(info->mount_opt, NODATACOW);
 				btrfs_clear_opt(info->mount_opt, NODATASUM);
@@ -594,12 +595,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			ret = match_int(&args[0], &intarg);
 			if (ret) {
 				goto out;
-			} else if (intarg > 0) {
-				info->thread_pool_size = intarg;
-			} else {
+			} else if (intarg == 0) {
 				ret = -EINVAL;
 				goto out;
 			}
+			info->thread_pool_size = intarg;
 			break;
 		case Opt_max_inline:
 			num = match_strdup(&args[0]);
@@ -608,11 +608,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 				kfree(num);
 
 				if (info->max_inline) {
-					info->max_inline = min_t(u64,
+					info->max_inline = min_t(u32,
 						info->max_inline,
 						info->sectorsize);
 				}
-				btrfs_info(info, "max_inline at %llu",
+				btrfs_info(info, "max_inline at %u",
 					   info->max_inline);
 			} else {
 				ret = -ENOMEM;
@@ -658,16 +658,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			break;
 		case Opt_ratio:
 			ret = match_int(&args[0], &intarg);
-			if (ret) {
-				goto out;
-			} else if (intarg >= 0) {
-				info->metadata_ratio = intarg;
-				btrfs_info(info, "metadata ratio %d",
-					   info->metadata_ratio);
-			} else {
-				ret = -EINVAL;
+			if (ret)
 				goto out;
-			}
+			info->metadata_ratio = intarg;
+			btrfs_info(info, "metadata ratio %u",
+				   info->metadata_ratio);
 			break;
 		case Opt_discard:
 			btrfs_set_and_info(info, DISCARD,
@@ -762,17 +757,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			break;
 		case Opt_check_integrity_print_mask:
 			ret = match_int(&args[0], &intarg);
-			if (ret) {
-				goto out;
-			} else if (intarg >= 0) {
-				info->check_integrity_print_mask = intarg;
-				btrfs_info(info,
-					   "check_integrity_print_mask 0x%x",
-					   info->check_integrity_print_mask);
-			} else {
-				ret = -EINVAL;
+			if (ret)
 				goto out;
-			}
+			info->check_integrity_print_mask = intarg;
+			btrfs_info(info, "check_integrity_print_mask 0x%x",
+				   info->check_integrity_print_mask);
 			break;
 #else
 		case Opt_check_integrity_including_extent_data:
@@ -798,24 +787,18 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 		case Opt_commit_interval:
 			intarg = 0;
 			ret = match_int(&args[0], &intarg);
-			if (ret < 0) {
-				btrfs_err(info, "invalid commit interval");
-				ret = -EINVAL;
+			if (ret)
 				goto out;
-			}
-			if (intarg > 0) {
-				if (intarg > 300) {
-					btrfs_warn(info,
-						"excessive commit interval %d",
-						intarg);
-				}
-				info->commit_interval = intarg;
-			} else {
+			if (intarg == 0) {
 				btrfs_info(info,
-					   "using default commit interval %ds",
+					   "using default commit interval %us",
 					   BTRFS_DEFAULT_COMMIT_INTERVAL);
-				info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+				intarg = BTRFS_DEFAULT_COMMIT_INTERVAL;
+			} else if (intarg > 300) {
+				btrfs_warn(info, "excessive commit interval %d",
+					   intarg);
 			}
+			info->commit_interval = intarg;
 			break;
 #ifdef CONFIG_BTRFS_DEBUG
 		case Opt_fragment_all:
@@ -1186,7 +1169,6 @@ static int btrfs_fill_super(struct super_block *sb,
 	sb->s_flags |= SB_POSIXACL;
 #endif
 	sb->s_flags |= SB_I_VERSION;
-	sb->s_iflags |= SB_I_CGROUPWB;
 
 	err = super_setup_bdi(sb);
 	if (err) {
@@ -1281,10 +1263,10 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 	if (btrfs_test_opt(info, NOBARRIER))
 		seq_puts(seq, ",nobarrier");
 	if (info->max_inline != BTRFS_DEFAULT_MAX_INLINE)
-		seq_printf(seq, ",max_inline=%llu", info->max_inline);
+		seq_printf(seq, ",max_inline=%u", info->max_inline);
 	if (info->thread_pool_size !=  min_t(unsigned long,
 					     num_online_cpus() + 2, 8))
-		seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
+		seq_printf(seq, ",thread_pool=%u", info->thread_pool_size);
 	if (btrfs_test_opt(info, COMPRESS)) {
 		compress_type = btrfs_compress_type2str(info->compress_type);
 		if (btrfs_test_opt(info, FORCE_COMPRESS))
@@ -1340,12 +1322,11 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 				info->check_integrity_print_mask);
 #endif
 	if (info->metadata_ratio)
-		seq_printf(seq, ",metadata_ratio=%d",
-				info->metadata_ratio);
+		seq_printf(seq, ",metadata_ratio=%u", info->metadata_ratio);
 	if (btrfs_test_opt(info, PANIC_ON_FATAL_ERROR))
 		seq_puts(seq, ",fatal_errors=panic");
 	if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
-		seq_printf(seq, ",commit=%d", info->commit_interval);
+		seq_printf(seq, ",commit=%u", info->commit_interval);
 #ifdef CONFIG_BTRFS_DEBUG
 	if (btrfs_test_opt(info, FRAGMENT_DATA))
 		seq_puts(seq, ",fragment=data");
@@ -1690,7 +1671,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 }
 
 static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
-				     int new_pool_size, int old_pool_size)
+				     u32 new_pool_size, u32 old_pool_size)
 {
 	if (new_pool_size == old_pool_size)
 		return;
@@ -1757,8 +1738,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 	unsigned old_flags = sb->s_flags;
 	unsigned long old_opts = fs_info->mount_opt;
 	unsigned long old_compress_type = fs_info->compress_type;
-	u64 old_max_inline = fs_info->max_inline;
-	int old_thread_pool_size = fs_info->thread_pool_size;
+	u32 old_max_inline = fs_info->max_inline;
+	u32 old_thread_pool_size = fs_info->thread_pool_size;
 	unsigned int old_metadata_ratio = fs_info->metadata_ratio;
 	int ret;
 
@@ -2376,22 +2357,18 @@ static void __init btrfs_print_mod_info(void)
 			", ref-verify=on"
 #endif
 			"\n",
-			btrfs_crc32c_impl());
+			crc32c_impl());
 }
 
 static int __init init_btrfs_fs(void)
 {
 	int err;
 
-	err = btrfs_hash_init();
-	if (err)
-		return err;
-
 	btrfs_props_init();
 
 	err = btrfs_init_sysfs();
 	if (err)
-		goto free_hash;
+		return err;
 
 	btrfs_init_compress();
 
@@ -2472,8 +2449,7 @@ static int __init init_btrfs_fs(void)
 free_compress:
 	btrfs_exit_compress();
 	btrfs_exit_sysfs();
-free_hash:
-	btrfs_hash_exit();
+
 	return err;
 }
 
@@ -2493,7 +2469,6 @@ static void __exit exit_btrfs_fs(void)
 	btrfs_exit_sysfs();
 	btrfs_cleanup_fs_uuids();
 	btrfs_exit_compress();
-	btrfs_hash_exit();
 }
 
 late_initcall(init_btrfs_fs);
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
index 9786d8cd0aa6..e74278170806 100644
--- a/fs/btrfs/tests/btrfs-tests.c
+++ b/fs/btrfs/tests/btrfs-tests.c
@@ -278,8 +278,7 @@ int btrfs_run_sanity_tests(void)
 		}
 	}
 	ret = btrfs_test_extent_map();
-	if (ret)
-		goto out;
+
 out:
 	btrfs_destroy_test_fs();
 	return ret;
diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c
index 70c993f01670..c23bd00bdd92 100644
--- a/fs/btrfs/tests/extent-map-tests.c
+++ b/fs/btrfs/tests/extent-map-tests.c
@@ -343,7 +343,7 @@ static void test_case_4(struct extent_map_tree *em_tree)
 	__test_case_4(em_tree, SZ_4K);
 }
 
-int btrfs_test_extent_map()
+int btrfs_test_extent_map(void)
 {
 	struct extent_map_tree *em_tree;
 
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 04f07144b45c..8b6168ff7814 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -37,22 +37,16 @@
 
 static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
 	[TRANS_STATE_RUNNING]		= 0U,
-	[TRANS_STATE_BLOCKED]		= (__TRANS_USERSPACE |
-					   __TRANS_START),
-	[TRANS_STATE_COMMIT_START]	= (__TRANS_USERSPACE |
-					   __TRANS_START |
-					   __TRANS_ATTACH),
-	[TRANS_STATE_COMMIT_DOING]	= (__TRANS_USERSPACE |
-					   __TRANS_START |
+	[TRANS_STATE_BLOCKED]		=  __TRANS_START,
+	[TRANS_STATE_COMMIT_START]	= (__TRANS_START | __TRANS_ATTACH),
+	[TRANS_STATE_COMMIT_DOING]	= (__TRANS_START |
 					   __TRANS_ATTACH |
 					   __TRANS_JOIN),
-	[TRANS_STATE_UNBLOCKED]		= (__TRANS_USERSPACE |
-					   __TRANS_START |
+	[TRANS_STATE_UNBLOCKED]		= (__TRANS_START |
 					   __TRANS_ATTACH |
 					   __TRANS_JOIN |
 					   __TRANS_JOIN_NOLOCK),
-	[TRANS_STATE_COMPLETED]		= (__TRANS_USERSPACE |
-					   __TRANS_START |
+	[TRANS_STATE_COMPLETED]		= (__TRANS_START |
 					   __TRANS_ATTACH |
 					   __TRANS_JOIN |
 					   __TRANS_JOIN_NOLOCK),
@@ -126,9 +120,9 @@ static void clear_btree_io_tree(struct extent_io_tree *tree)
 	spin_unlock(&tree->lock);
 }
 
-static noinline void switch_commit_roots(struct btrfs_transaction *trans,
-					 struct btrfs_fs_info *fs_info)
+static noinline void switch_commit_roots(struct btrfs_transaction *trans)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_root *root, *tmp;
 
 	down_write(&fs_info->commit_root_sem);
@@ -449,11 +443,7 @@ static int may_wait_transaction(struct btrfs_fs_info *fs_info, int type)
 	if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags))
 		return 0;
 
-	if (type == TRANS_USERSPACE)
-		return 1;
-
-	if (type == TRANS_START &&
-	    !atomic_read(&fs_info->open_ioctl_trans))
+	if (type == TRANS_START)
 		return 1;
 
 	return 0;
@@ -508,8 +498,8 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
 	 */
 	if (num_items && root != fs_info->chunk_root) {
 		qgroup_reserved = num_items * fs_info->nodesize;
-		ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved,
-						enforce_qgroups);
+		ret = btrfs_qgroup_reserve_meta_pertrans(root, qgroup_reserved,
+				enforce_qgroups);
 		if (ret)
 			return ERR_PTR(ret);
 
@@ -593,7 +583,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
 got_it:
 	btrfs_record_root_in_trans(h, root);
 
-	if (!current->journal_info && type != TRANS_USERSPACE)
+	if (!current->journal_info)
 		current->journal_info = h;
 	return h;
 
@@ -606,7 +596,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
 		btrfs_block_rsv_release(fs_info, &fs_info->trans_block_rsv,
 					num_bytes);
 reserve_fail:
-	btrfs_qgroup_free_meta(root, qgroup_reserved);
+	btrfs_qgroup_free_meta_pertrans(root, qgroup_reserved);
 	return ERR_PTR(ret);
 }
 
@@ -658,14 +648,6 @@ struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
 	return trans;
 }
 
-struct btrfs_trans_handle *btrfs_start_transaction_lflush(
-					struct btrfs_root *root,
-					unsigned int num_items)
-{
-	return start_transaction(root, num_items, TRANS_START,
-				 BTRFS_RESERVE_FLUSH_LIMIT, true);
-}
-
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root)
 {
 	return start_transaction(root, 0, TRANS_JOIN, BTRFS_RESERVE_NO_FLUSH,
@@ -678,12 +660,6 @@ struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root
 				 BTRFS_RESERVE_NO_FLUSH, true);
 }
 
-struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root)
-{
-	return start_transaction(root, 0, TRANS_USERSPACE,
-				 BTRFS_RESERVE_NO_FLUSH, true);
-}
-
 /*
  * btrfs_attach_transaction() - catch the running transaction
  *
@@ -789,8 +765,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
 
 void btrfs_throttle(struct btrfs_fs_info *fs_info)
 {
-	if (!atomic_read(&fs_info->open_ioctl_trans))
-		wait_current_trans(fs_info);
+	wait_current_trans(fs_info);
 }
 
 static int should_end_transaction(struct btrfs_trans_handle *trans)
@@ -826,6 +801,27 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
 	return should_end_transaction(trans);
 }
 
+static void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans)
+
+{
+	struct btrfs_fs_info *fs_info = trans->fs_info;
+
+	if (!trans->block_rsv) {
+		ASSERT(!trans->bytes_reserved);
+		return;
+	}
+
+	if (!trans->bytes_reserved)
+		return;
+
+	ASSERT(trans->block_rsv == &fs_info->trans_block_rsv);
+	trace_btrfs_space_reservation(fs_info, "transaction",
+				      trans->transid, trans->bytes_reserved, 0);
+	btrfs_block_rsv_release(fs_info, trans->block_rsv,
+				trans->bytes_reserved);
+	trans->bytes_reserved = 0;
+}
+
 static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 				   int throttle)
 {
@@ -843,11 +839,11 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 		return 0;
 	}
 
-	btrfs_trans_release_metadata(trans, info);
+	btrfs_trans_release_metadata(trans);
 	trans->block_rsv = NULL;
 
 	if (!list_empty(&trans->new_bgs))
-		btrfs_create_pending_block_groups(trans, info);
+		btrfs_create_pending_block_groups(trans);
 
 	trans->delayed_ref_updates = 0;
 	if (!trans->sync) {
@@ -864,16 +860,15 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 			must_run_delayed_refs = 2;
 	}
 
-	btrfs_trans_release_metadata(trans, info);
+	btrfs_trans_release_metadata(trans);
 	trans->block_rsv = NULL;
 
 	if (!list_empty(&trans->new_bgs))
-		btrfs_create_pending_block_groups(trans, info);
+		btrfs_create_pending_block_groups(trans);
 
 	btrfs_trans_release_chunk_metadata(trans);
 
-	if (lock && !atomic_read(&info->open_ioctl_trans) &&
-	    should_end_transaction(trans) &&
+	if (lock && should_end_transaction(trans) &&
 	    READ_ONCE(cur_trans->state) == TRANS_STATE_RUNNING) {
 		spin_lock(&info->trans_lock);
 		if (cur_trans->state == TRANS_STATE_RUNNING)
@@ -1072,40 +1067,32 @@ int btrfs_wait_tree_log_extents(struct btrfs_root *log_root, int mark)
 }
 
 /*
- * when btree blocks are allocated, they have some corresponding bits set for
- * them in one of two extent_io trees.  This is used to make sure all of
- * those extents are on disk for transaction or log commit
+ * When btree blocks are allocated the corresponding extents are marked dirty.
+ * This function ensures such extents are persisted on disk for transaction or
+ * log commit.
+ *
+ * @trans: transaction whose dirty pages we'd like to write
  */
-static int btrfs_write_and_wait_marked_extents(struct btrfs_fs_info *fs_info,
-				struct extent_io_tree *dirty_pages, int mark)
+static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans)
 {
-	int ret;
-	int ret2;
+	struct extent_io_tree *dirty_pages = &trans->transaction->dirty_pages;
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct blk_plug plug;
+	int ret, ret2;
 
 	blk_start_plug(&plug);
-	ret = btrfs_write_marked_extents(fs_info, dirty_pages, mark);
+	ret = btrfs_write_marked_extents(fs_info, dirty_pages, EXTENT_DIRTY);
 	blk_finish_plug(&plug);
 	ret2 = btrfs_wait_extents(fs_info, dirty_pages);
 
+	clear_btree_io_tree(&trans->transaction->dirty_pages);
+
 	if (ret)
 		return ret;
-	if (ret2)
+	else if (ret2)
 		return ret2;
-	return 0;
-}
-
-static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
-					    struct btrfs_fs_info *fs_info)
-{
-	int ret;
-
-	ret = btrfs_write_and_wait_marked_extents(fs_info,
-					   &trans->transaction->dirty_pages,
-					   EXTENT_DIRTY);
-	clear_btree_io_tree(&trans->transaction->dirty_pages);
-
-	return ret;
+	else
+		return 0;
 }
 
 /*
@@ -1155,9 +1142,9 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
  * failures will cause the file system to go offline. We still need
  * to clean up the delayed refs.
  */
-static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
-					 struct btrfs_fs_info *fs_info)
+static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
 	struct list_head *io_bgs = &trans->transaction->io_bgs;
 	struct list_head *next;
@@ -1251,9 +1238,9 @@ void btrfs_add_dead_root(struct btrfs_root *root)
 /*
  * update all the cowonly tree roots on disk
  */
-static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
-				    struct btrfs_fs_info *fs_info)
+static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_root *gang[8];
 	int i;
 	int ret;
@@ -1297,7 +1284,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
 			spin_lock(&fs_info->fs_roots_radix_lock);
 			if (err)
 				break;
-			btrfs_qgroup_free_meta_all(root);
+			btrfs_qgroup_free_meta_all_pertrans(root);
 		}
 	}
 	spin_unlock(&fs_info->fs_roots_radix_lock);
@@ -1371,7 +1358,7 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
 	 */
 	mutex_lock(&fs_info->tree_log_mutex);
 
-	ret = commit_fs_roots(trans, fs_info);
+	ret = commit_fs_roots(trans);
 	if (ret)
 		goto out;
 	ret = btrfs_qgroup_account_extents(trans, fs_info);
@@ -1397,11 +1384,11 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
 	 * like chunk and root tree, as they won't affect qgroup.
 	 * And we don't write super to avoid half committed status.
 	 */
-	ret = commit_cowonly_roots(trans, fs_info);
+	ret = commit_cowonly_roots(trans);
 	if (ret)
 		goto out;
-	switch_commit_roots(trans->transaction, fs_info);
-	ret = btrfs_write_and_wait_transaction(trans, fs_info);
+	switch_commit_roots(trans->transaction);
+	ret = btrfs_write_and_wait_transaction(trans);
 	if (ret)
 		btrfs_handle_fs_error(fs_info, ret,
 			"Error while writing out transaction for qgroup");
@@ -1430,9 +1417,10 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
  * the creation of the pending snapshots, just return 0.
  */
 static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
-				   struct btrfs_fs_info *fs_info,
 				   struct btrfs_pending_snapshot *pending)
 {
+
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_key key;
 	struct btrfs_root_item *new_root_item;
 	struct btrfs_root *tree_root = fs_info->tree_root;
@@ -1524,7 +1512,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 	 * otherwise we corrupt the FS during
 	 * snapshot
 	 */
-	ret = btrfs_run_delayed_items(trans, fs_info);
+	ret = btrfs_run_delayed_items(trans);
 	if (ret) {	/* Transaction aborted */
 		btrfs_abort_transaction(trans, ret);
 		goto fail;
@@ -1699,8 +1687,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 /*
  * create all the snapshots we've scheduled for creation
  */
-static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
-					     struct btrfs_fs_info *fs_info)
+static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans)
 {
 	struct btrfs_pending_snapshot *pending, *next;
 	struct list_head *head = &trans->transaction->pending_snapshots;
@@ -1708,7 +1695,7 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
 
 	list_for_each_entry_safe(pending, next, head, list) {
 		list_del(&pending->list);
-		ret = create_pending_snapshot(trans, fs_info, pending);
+		ret = create_pending_snapshot(trans, pending);
 		if (ret)
 			break;
 	}
@@ -1861,10 +1848,9 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
 }
 
 
-static void cleanup_transaction(struct btrfs_trans_handle *trans,
-				struct btrfs_root *root, int err)
+static void cleanup_transaction(struct btrfs_trans_handle *trans, int err)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_transaction *cur_trans = trans->transaction;
 	DEFINE_WAIT(wait);
 
@@ -1904,7 +1890,7 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
 	btrfs_put_transaction(cur_trans);
 	btrfs_put_transaction(cur_trans);
 
-	trace_btrfs_transaction_commit(root);
+	trace_btrfs_transaction_commit(trans->root);
 
 	if (current->journal_info == trans)
 		current->journal_info = NULL;
@@ -1965,7 +1951,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 		return ret;
 	}
 
-	btrfs_trans_release_metadata(trans, fs_info);
+	btrfs_trans_release_metadata(trans);
 	trans->block_rsv = NULL;
 
 	cur_trans = trans->transaction;
@@ -1978,7 +1964,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	smp_wmb();
 
 	if (!list_empty(&trans->new_bgs))
-		btrfs_create_pending_block_groups(trans, fs_info);
+		btrfs_create_pending_block_groups(trans);
 
 	ret = btrfs_run_delayed_refs(trans, fs_info, 0);
 	if (ret) {
@@ -2009,7 +1995,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 		mutex_unlock(&fs_info->ro_block_group_mutex);
 
 		if (run_it)
-			ret = btrfs_start_dirty_block_groups(trans, fs_info);
+			ret = btrfs_start_dirty_block_groups(trans);
 	}
 	if (ret) {
 		btrfs_end_transaction(trans);
@@ -2061,7 +2047,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	if (ret)
 		goto cleanup_transaction;
 
-	ret = btrfs_run_delayed_items(trans, fs_info);
+	ret = btrfs_run_delayed_items(trans);
 	if (ret)
 		goto cleanup_transaction;
 
@@ -2069,7 +2055,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 		   extwriter_counter_read(cur_trans) == 0);
 
 	/* some pending stuffs might be added after the previous flush. */
-	ret = btrfs_run_delayed_items(trans, fs_info);
+	ret = btrfs_run_delayed_items(trans);
 	if (ret)
 		goto cleanup_transaction;
 
@@ -2106,7 +2092,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	 * deal with them in create_pending_snapshot(), which is the
 	 * core function of the snapshot creation.
 	 */
-	ret = create_pending_snapshots(trans, fs_info);
+	ret = create_pending_snapshots(trans);
 	if (ret) {
 		mutex_unlock(&fs_info->reloc_mutex);
 		goto scrub_continue;
@@ -2122,7 +2108,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	 * because all the tree which are snapshoted will be forced to COW
 	 * the nodes and leaves.
 	 */
-	ret = btrfs_run_delayed_items(trans, fs_info);
+	ret = btrfs_run_delayed_items(trans);
 	if (ret) {
 		mutex_unlock(&fs_info->reloc_mutex);
 		goto scrub_continue;
@@ -2157,7 +2143,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	 */
 	mutex_lock(&fs_info->tree_log_mutex);
 
-	ret = commit_fs_roots(trans, fs_info);
+	ret = commit_fs_roots(trans);
 	if (ret) {
 		mutex_unlock(&fs_info->tree_log_mutex);
 		mutex_unlock(&fs_info->reloc_mutex);
@@ -2197,7 +2183,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 		goto scrub_continue;
 	}
 
-	ret = commit_cowonly_roots(trans, fs_info);
+	ret = commit_cowonly_roots(trans);
 	if (ret) {
 		mutex_unlock(&fs_info->tree_log_mutex);
 		mutex_unlock(&fs_info->reloc_mutex);
@@ -2229,7 +2215,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	list_add_tail(&fs_info->chunk_root->dirty_list,
 		      &cur_trans->switch_commits);
 
-	switch_commit_roots(cur_trans, fs_info);
+	switch_commit_roots(cur_trans);
 
 	ASSERT(list_empty(&cur_trans->dirty_bgs));
 	ASSERT(list_empty(&cur_trans->io_bgs));
@@ -2241,7 +2227,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 	       sizeof(*fs_info->super_copy));
 
 	btrfs_update_commit_device_size(fs_info);
-	btrfs_update_commit_device_bytes_used(fs_info, cur_trans);
+	btrfs_update_commit_device_bytes_used(cur_trans);
 
 	clear_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags);
 	clear_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags);
@@ -2256,7 +2242,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 
 	wake_up(&fs_info->transaction_wait);
 
-	ret = btrfs_write_and_wait_transaction(trans, fs_info);
+	ret = btrfs_write_and_wait_transaction(trans);
 	if (ret) {
 		btrfs_handle_fs_error(fs_info, ret,
 				      "Error while writing out transaction");
@@ -2319,13 +2305,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 scrub_continue:
 	btrfs_scrub_continue(fs_info);
 cleanup_transaction:
-	btrfs_trans_release_metadata(trans, fs_info);
+	btrfs_trans_release_metadata(trans);
 	btrfs_trans_release_chunk_metadata(trans);
 	trans->block_rsv = NULL;
 	btrfs_warn(fs_info, "Skipping commit of aborted transaction.");
 	if (current->journal_info == trans)
 		current->journal_info = NULL;
-	cleanup_transaction(trans, trans->root, ret);
+	cleanup_transaction(trans, ret);
 
 	return ret;
 }
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 6beee072b1bd..b6c94ce33503 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -69,6 +69,22 @@ struct btrfs_transaction {
 	struct list_head pending_chunks;
 	struct list_head switch_commits;
 	struct list_head dirty_bgs;
+
+	/*
+	 * There is no explicit lock which protects io_bgs, rather its
+	 * consistency is implied by the fact that all the sites which modify
+	 * it do so under some form of transaction critical section, namely:
+	 *
+	 * - btrfs_start_dirty_block_groups - This function can only ever be
+	 *   run by one of the transaction committers. Refer to
+	 *   BTRFS_TRANS_DIRTY_BG_RUN usage in btrfs_commit_transaction
+	 *
+	 * - btrfs_write_dirty_blockgroups - this is called by
+	 *   commit_cowonly_roots from transaction critical section
+	 *   (TRANS_STATE_COMMIT_DOING)
+	 *
+	 * - btrfs_cleanup_dirty_bgs - called on transaction abort
+	 */
 	struct list_head io_bgs;
 	struct list_head dropped_roots;
 
@@ -89,21 +105,18 @@ struct btrfs_transaction {
 
 #define __TRANS_FREEZABLE	(1U << 0)
 
-#define __TRANS_USERSPACE	(1U << 8)
 #define __TRANS_START		(1U << 9)
 #define __TRANS_ATTACH		(1U << 10)
 #define __TRANS_JOIN		(1U << 11)
 #define __TRANS_JOIN_NOLOCK	(1U << 12)
 #define __TRANS_DUMMY		(1U << 13)
 
-#define TRANS_USERSPACE		(__TRANS_USERSPACE | __TRANS_FREEZABLE)
 #define TRANS_START		(__TRANS_START | __TRANS_FREEZABLE)
 #define TRANS_ATTACH		(__TRANS_ATTACH)
 #define TRANS_JOIN		(__TRANS_JOIN | __TRANS_FREEZABLE)
 #define TRANS_JOIN_NOLOCK	(__TRANS_JOIN_NOLOCK)
 
-#define TRANS_EXTWRITERS	(__TRANS_USERSPACE | __TRANS_START |	\
-				 __TRANS_ATTACH)
+#define TRANS_EXTWRITERS	(__TRANS_START | __TRANS_ATTACH)
 
 #define BTRFS_SEND_TRANS_STUB	((void *)1)
 
@@ -186,15 +199,11 @@ struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
 					struct btrfs_root *root,
 					unsigned int num_items,
 					int min_factor);
-struct btrfs_trans_handle *btrfs_start_transaction_lflush(
-					struct btrfs_root *root,
-					unsigned int num_items);
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_attach_transaction_barrier(
 					struct btrfs_root *root);
-struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root);
 int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid);
 
 void btrfs_add_dead_root(struct btrfs_root *root);
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index c3c8d48f6618..e96cfd93ae3f 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -30,7 +30,6 @@
 #include "tree-checker.h"
 #include "disk-io.h"
 #include "compression.h"
-#include "hash.h"
 
 /*
  * Error message should follow the following format:
@@ -53,7 +52,7 @@
  * Allows callers to customize the output.
  */
 __printf(4, 5)
-static void generic_err(const struct btrfs_root *root,
+static void generic_err(const struct btrfs_fs_info *fs_info,
 			const struct extent_buffer *eb, int slot,
 			const char *fmt, ...)
 {
@@ -65,10 +64,10 @@ static void generic_err(const struct btrfs_root *root,
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	btrfs_crit(root->fs_info,
+	btrfs_crit(fs_info,
 		"corrupt %s: root=%llu block=%llu slot=%d, %pV",
 		btrfs_header_level(eb) == 0 ? "leaf" : "node",
-		root->objectid, btrfs_header_bytenr(eb), slot, &vaf);
+		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf);
 	va_end(args);
 }
 
@@ -77,7 +76,7 @@ static void generic_err(const struct btrfs_root *root,
  * offset has its own meaning.
  */
 __printf(4, 5)
-static void file_extent_err(const struct btrfs_root *root,
+static void file_extent_err(const struct btrfs_fs_info *fs_info,
 			    const struct extent_buffer *eb, int slot,
 			    const char *fmt, ...)
 {
@@ -91,10 +90,11 @@ static void file_extent_err(const struct btrfs_root *root,
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	btrfs_crit(root->fs_info,
+	btrfs_crit(fs_info,
 	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
-		btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
-		btrfs_header_bytenr(eb), slot, key.objectid, key.offset, &vaf);
+		btrfs_header_level(eb) == 0 ? "leaf" : "node",
+		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+		key.objectid, key.offset, &vaf);
 	va_end(args);
 }
 
@@ -102,26 +102,26 @@ static void file_extent_err(const struct btrfs_root *root,
  * Return 0 if the btrfs_file_extent_##name is aligned to @alignment
  * Else return 1
  */
-#define CHECK_FE_ALIGNED(root, leaf, slot, fi, name, alignment)		      \
+#define CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, name, alignment)	      \
 ({									      \
 	if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \
-		file_extent_err((root), (leaf), (slot),			      \
+		file_extent_err((fs_info), (leaf), (slot),		      \
 	"invalid %s for file extent, have %llu, should be aligned to %u",     \
 			(#name), btrfs_file_extent_##name((leaf), (fi)),      \
 			(alignment));					      \
 	(!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment)));   \
 })
 
-static int check_extent_data_item(struct btrfs_root *root,
+static int check_extent_data_item(struct btrfs_fs_info *fs_info,
 				  struct extent_buffer *leaf,
 				  struct btrfs_key *key, int slot)
 {
 	struct btrfs_file_extent_item *fi;
-	u32 sectorsize = root->fs_info->sectorsize;
+	u32 sectorsize = fs_info->sectorsize;
 	u32 item_size = btrfs_item_size_nr(leaf, slot);
 
 	if (!IS_ALIGNED(key->offset, sectorsize)) {
-		file_extent_err(root, leaf, slot,
+		file_extent_err(fs_info, leaf, slot,
 "unaligned file_offset for file extent, have %llu should be aligned to %u",
 			key->offset, sectorsize);
 		return -EUCLEAN;
@@ -130,7 +130,7 @@ static int check_extent_data_item(struct btrfs_root *root,
 	fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
 
 	if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
-		file_extent_err(root, leaf, slot,
+		file_extent_err(fs_info, leaf, slot,
 		"invalid type for file extent, have %u expect range [0, %u]",
 			btrfs_file_extent_type(leaf, fi),
 			BTRFS_FILE_EXTENT_TYPES);
@@ -142,14 +142,14 @@ static int check_extent_data_item(struct btrfs_root *root,
 	 * and must be caught in open_ctree().
 	 */
 	if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
-		file_extent_err(root, leaf, slot,
+		file_extent_err(fs_info, leaf, slot,
 	"invalid compression for file extent, have %u expect range [0, %u]",
 			btrfs_file_extent_compression(leaf, fi),
 			BTRFS_COMPRESS_TYPES);
 		return -EUCLEAN;
 	}
 	if (btrfs_file_extent_encryption(leaf, fi)) {
-		file_extent_err(root, leaf, slot,
+		file_extent_err(fs_info, leaf, slot,
 			"invalid encryption for file extent, have %u expect 0",
 			btrfs_file_extent_encryption(leaf, fi));
 		return -EUCLEAN;
@@ -157,7 +157,7 @@ static int check_extent_data_item(struct btrfs_root *root,
 	if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
 		/* Inline extent must have 0 as key offset */
 		if (key->offset) {
-			file_extent_err(root, leaf, slot,
+			file_extent_err(fs_info, leaf, slot,
 		"invalid file_offset for inline file extent, have %llu expect 0",
 				key->offset);
 			return -EUCLEAN;
@@ -171,7 +171,7 @@ static int check_extent_data_item(struct btrfs_root *root,
 		/* Uncompressed inline extent size must match item size */
 		if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
 		    btrfs_file_extent_ram_bytes(leaf, fi)) {
-			file_extent_err(root, leaf, slot,
+			file_extent_err(fs_info, leaf, slot,
 	"invalid ram_bytes for uncompressed inline extent, have %u expect %llu",
 				item_size, BTRFS_FILE_EXTENT_INLINE_DATA_START +
 				btrfs_file_extent_ram_bytes(leaf, fi));
@@ -182,40 +182,41 @@ static int check_extent_data_item(struct btrfs_root *root,
 
 	/* Regular or preallocated extent has fixed item size */
 	if (item_size != sizeof(*fi)) {
-		file_extent_err(root, leaf, slot,
+		file_extent_err(fs_info, leaf, slot,
 	"invalid item size for reg/prealloc file extent, have %u expect %zu",
 			item_size, sizeof(*fi));
 		return -EUCLEAN;
 	}
-	if (CHECK_FE_ALIGNED(root, leaf, slot, fi, ram_bytes, sectorsize) ||
-	    CHECK_FE_ALIGNED(root, leaf, slot, fi, disk_bytenr, sectorsize) ||
-	    CHECK_FE_ALIGNED(root, leaf, slot, fi, disk_num_bytes, sectorsize) ||
-	    CHECK_FE_ALIGNED(root, leaf, slot, fi, offset, sectorsize) ||
-	    CHECK_FE_ALIGNED(root, leaf, slot, fi, num_bytes, sectorsize))
+	if (CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, ram_bytes, sectorsize) ||
+	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_bytenr, sectorsize) ||
+	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_num_bytes, sectorsize) ||
+	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, offset, sectorsize) ||
+	    CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, num_bytes, sectorsize))
 		return -EUCLEAN;
 	return 0;
 }
 
-static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
-			   struct btrfs_key *key, int slot)
+static int check_csum_item(struct btrfs_fs_info *fs_info,
+			   struct extent_buffer *leaf, struct btrfs_key *key,
+			   int slot)
 {
-	u32 sectorsize = root->fs_info->sectorsize;
-	u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
+	u32 sectorsize = fs_info->sectorsize;
+	u32 csumsize = btrfs_super_csum_size(fs_info->super_copy);
 
 	if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
-		generic_err(root, leaf, slot,
+		generic_err(fs_info, leaf, slot,
 		"invalid key objectid for csum item, have %llu expect %llu",
 			key->objectid, BTRFS_EXTENT_CSUM_OBJECTID);
 		return -EUCLEAN;
 	}
 	if (!IS_ALIGNED(key->offset, sectorsize)) {
-		generic_err(root, leaf, slot,
+		generic_err(fs_info, leaf, slot,
 	"unaligned key offset for csum item, have %llu should be aligned to %u",
 			key->offset, sectorsize);
 		return -EUCLEAN;
 	}
 	if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
-		generic_err(root, leaf, slot,
+		generic_err(fs_info, leaf, slot,
 	"unaligned item size for csum item, have %u should be aligned to %u",
 			btrfs_item_size_nr(leaf, slot), csumsize);
 		return -EUCLEAN;
@@ -228,7 +229,7 @@ static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
  * which represents inode number
  */
 __printf(4, 5)
-static void dir_item_err(const struct btrfs_root *root,
+static void dir_item_err(const struct btrfs_fs_info *fs_info,
 			 const struct extent_buffer *eb, int slot,
 			 const char *fmt, ...)
 {
@@ -242,14 +243,15 @@ static void dir_item_err(const struct btrfs_root *root,
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	btrfs_crit(root->fs_info,
+	btrfs_crit(fs_info,
 	"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
-		btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
-		btrfs_header_bytenr(eb), slot, key.objectid, &vaf);
+		btrfs_header_level(eb) == 0 ? "leaf" : "node",
+		btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+		key.objectid, &vaf);
 	va_end(args);
 }
 
-static int check_dir_item(struct btrfs_root *root,
+static int check_dir_item(struct btrfs_fs_info *fs_info,
 			  struct extent_buffer *leaf,
 			  struct btrfs_key *key, int slot)
 {
@@ -268,7 +270,7 @@ static int check_dir_item(struct btrfs_root *root,
 
 		/* header itself should not cross item boundary */
 		if (cur + sizeof(*di) > item_size) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 		"dir item header crosses item boundary, have %zu boundary %u",
 				cur + sizeof(*di), item_size);
 			return -EUCLEAN;
@@ -277,7 +279,7 @@ static int check_dir_item(struct btrfs_root *root,
 		/* dir type check */
 		dir_type = btrfs_dir_type(leaf, di);
 		if (dir_type >= BTRFS_FT_MAX) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 			"invalid dir item type, have %u expect [0, %u)",
 				dir_type, BTRFS_FT_MAX);
 			return -EUCLEAN;
@@ -285,14 +287,14 @@ static int check_dir_item(struct btrfs_root *root,
 
 		if (key->type == BTRFS_XATTR_ITEM_KEY &&
 		    dir_type != BTRFS_FT_XATTR) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 		"invalid dir item type for XATTR key, have %u expect %u",
 				dir_type, BTRFS_FT_XATTR);
 			return -EUCLEAN;
 		}
 		if (dir_type == BTRFS_FT_XATTR &&
 		    key->type != BTRFS_XATTR_ITEM_KEY) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 			"xattr dir type found for non-XATTR key");
 			return -EUCLEAN;
 		}
@@ -305,21 +307,21 @@ static int check_dir_item(struct btrfs_root *root,
 		name_len = btrfs_dir_name_len(leaf, di);
 		data_len = btrfs_dir_data_len(leaf, di);
 		if (name_len > max_name_len) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 			"dir item name len too long, have %u max %u",
 				name_len, max_name_len);
 			return -EUCLEAN;
 		}
-		if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) {
-			dir_item_err(root, leaf, slot,
+		if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(fs_info)) {
+			dir_item_err(fs_info, leaf, slot,
 			"dir item name and data len too long, have %u max %u",
 				name_len + data_len,
-				BTRFS_MAX_XATTR_SIZE(root->fs_info));
+				BTRFS_MAX_XATTR_SIZE(fs_info));
 			return -EUCLEAN;
 		}
 
 		if (data_len && dir_type != BTRFS_FT_XATTR) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 			"dir item with invalid data len, have %u expect 0",
 				data_len);
 			return -EUCLEAN;
@@ -329,7 +331,7 @@ static int check_dir_item(struct btrfs_root *root,
 
 		/* header and name/data should not cross item boundary */
 		if (cur + total_size > item_size) {
-			dir_item_err(root, leaf, slot,
+			dir_item_err(fs_info, leaf, slot,
 		"dir item data crosses item boundary, have %u boundary %u",
 				cur + total_size, item_size);
 			return -EUCLEAN;
@@ -347,7 +349,7 @@ static int check_dir_item(struct btrfs_root *root,
 					(unsigned long)(di + 1), name_len);
 			name_hash = btrfs_name_hash(namebuf, name_len);
 			if (key->offset != name_hash) {
-				dir_item_err(root, leaf, slot,
+				dir_item_err(fs_info, leaf, slot,
 		"name hash mismatch with key, have 0x%016x expect 0x%016llx",
 					name_hash, key->offset);
 				return -EUCLEAN;
@@ -362,7 +364,7 @@ static int check_dir_item(struct btrfs_root *root,
 /*
  * Common point to switch the item-specific validation.
  */
-static int check_leaf_item(struct btrfs_root *root,
+static int check_leaf_item(struct btrfs_fs_info *fs_info,
 			   struct extent_buffer *leaf,
 			   struct btrfs_key *key, int slot)
 {
@@ -370,24 +372,23 @@ static int check_leaf_item(struct btrfs_root *root,
 
 	switch (key->type) {
 	case BTRFS_EXTENT_DATA_KEY:
-		ret = check_extent_data_item(root, leaf, key, slot);
+		ret = check_extent_data_item(fs_info, leaf, key, slot);
 		break;
 	case BTRFS_EXTENT_CSUM_KEY:
-		ret = check_csum_item(root, leaf, key, slot);
+		ret = check_csum_item(fs_info, leaf, key, slot);
 		break;
 	case BTRFS_DIR_ITEM_KEY:
 	case BTRFS_DIR_INDEX_KEY:
 	case BTRFS_XATTR_ITEM_KEY:
-		ret = check_dir_item(root, leaf, key, slot);
+		ret = check_dir_item(fs_info, leaf, key, slot);
 		break;
 	}
 	return ret;
 }
 
-static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
+static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf,
 		      bool check_item_data)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	/* No valid key type is 0, so all key should be larger than this key */
 	struct btrfs_key prev_key = {0, 0, 0};
 	struct btrfs_key key;
@@ -420,7 +421,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 			eb = btrfs_root_node(check_root);
 			/* if leaf is the root, then it's fine */
 			if (leaf != eb) {
-				generic_err(check_root, leaf, 0,
+				generic_err(fs_info, leaf, 0,
 		"invalid nritems, have %u should not be 0 for non-root leaf",
 					nritems);
 				free_extent_buffer(eb);
@@ -453,7 +454,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 
 		/* Make sure the keys are in the right order */
 		if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
-			generic_err(root, leaf, slot,
+			generic_err(fs_info, leaf, slot,
 	"bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
 				prev_key.objectid, prev_key.type,
 				prev_key.offset, key.objectid, key.type,
@@ -472,7 +473,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 			item_end_expected = btrfs_item_offset_nr(leaf,
 								 slot - 1);
 		if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
-			generic_err(root, leaf, slot,
+			generic_err(fs_info, leaf, slot,
 				"unexpected item end, have %u expect %u",
 				btrfs_item_end_nr(leaf, slot),
 				item_end_expected);
@@ -486,7 +487,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 		 */
 		if (btrfs_item_end_nr(leaf, slot) >
 		    BTRFS_LEAF_DATA_SIZE(fs_info)) {
-			generic_err(root, leaf, slot,
+			generic_err(fs_info, leaf, slot,
 			"slot end outside of leaf, have %u expect range [0, %u]",
 				btrfs_item_end_nr(leaf, slot),
 				BTRFS_LEAF_DATA_SIZE(fs_info));
@@ -496,7 +497,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 		/* Also check if the item pointer overlaps with btrfs item. */
 		if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
 		    btrfs_item_ptr_offset(leaf, slot)) {
-			generic_err(root, leaf, slot,
+			generic_err(fs_info, leaf, slot,
 		"slot overlaps with its data, item end %lu data start %lu",
 				btrfs_item_nr_offset(slot) +
 				sizeof(struct btrfs_item),
@@ -509,7 +510,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 			 * Check if the item size and content meet other
 			 * criteria
 			 */
-			ret = check_leaf_item(root, leaf, &key, slot);
+			ret = check_leaf_item(fs_info, leaf, &key, slot);
 			if (ret < 0)
 				return ret;
 		}
@@ -522,18 +523,19 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
 	return 0;
 }
 
-int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf)
+int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
+			  struct extent_buffer *leaf)
 {
-	return check_leaf(root, leaf, true);
+	return check_leaf(fs_info, leaf, true);
 }
 
-int btrfs_check_leaf_relaxed(struct btrfs_root *root,
+int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
 			     struct extent_buffer *leaf)
 {
-	return check_leaf(root, leaf, false);
+	return check_leaf(fs_info, leaf, false);
 }
 
-int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node)
 {
 	unsigned long nr = btrfs_header_nritems(node);
 	struct btrfs_key key, next_key;
@@ -541,12 +543,12 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
 	u64 bytenr;
 	int ret = 0;
 
-	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) {
-		btrfs_crit(root->fs_info,
+	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
+		btrfs_crit(fs_info,
 "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
-			   root->objectid, node->start,
+			   btrfs_header_owner(node), node->start,
 			   nr == 0 ? "small" : "large", nr,
-			   BTRFS_NODEPTRS_PER_BLOCK(root->fs_info));
+			   BTRFS_NODEPTRS_PER_BLOCK(fs_info));
 		return -EUCLEAN;
 	}
 
@@ -556,21 +558,21 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
 		btrfs_node_key_to_cpu(node, &next_key, slot + 1);
 
 		if (!bytenr) {
-			generic_err(root, node, slot,
+			generic_err(fs_info, node, slot,
 				"invalid NULL node pointer");
 			ret = -EUCLEAN;
 			goto out;
 		}
-		if (!IS_ALIGNED(bytenr, root->fs_info->sectorsize)) {
-			generic_err(root, node, slot,
+		if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
+			generic_err(fs_info, node, slot,
 			"unaligned pointer, have %llu should be aligned to %u",
-				bytenr, root->fs_info->sectorsize);
+				bytenr, fs_info->sectorsize);
 			ret = -EUCLEAN;
 			goto out;
 		}
 
 		if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
-			generic_err(root, node, slot,
+			generic_err(fs_info, node, slot,
 	"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
 				key.objectid, key.type, key.offset,
 				next_key.objectid, next_key.type,
diff --git a/fs/btrfs/tree-checker.h b/fs/btrfs/tree-checker.h
index 3d53e8d6fda0..aba542755710 100644
--- a/fs/btrfs/tree-checker.h
+++ b/fs/btrfs/tree-checker.h
@@ -25,14 +25,15 @@
  * Will check not only the item pointers, but also every possible member
  * in item data.
  */
-int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf);
+int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
+			  struct extent_buffer *leaf);
 
 /*
  * Less strict leaf checker.
  * Will only check item pointers, not reading item data.
  */
-int btrfs_check_leaf_relaxed(struct btrfs_root *root,
+int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
 			     struct extent_buffer *leaf);
-int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
+int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node);
 
 #endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 4fd19b4d6675..6eb702c8f80b 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -21,12 +21,12 @@
 #include <linux/blkdev.h>
 #include <linux/list_sort.h>
 #include <linux/iversion.h>
+#include "ctree.h"
 #include "tree-log.h"
 #include "disk-io.h"
 #include "locking.h"
 #include "print-tree.h"
 #include "backref.h"
-#include "hash.h"
 #include "compression.h"
 #include "qgroup.h"
 #include "inode-map.h"
@@ -853,7 +853,6 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
 				      struct btrfs_inode *dir,
 				      struct btrfs_dir_item *di)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct inode *inode;
 	char *name;
 	int name_len;
@@ -887,7 +886,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto out;
 	else
-		ret = btrfs_run_delayed_items(trans, fs_info);
+		ret = btrfs_run_delayed_items(trans);
 out:
 	kfree(name);
 	iput(inode);
@@ -1005,7 +1004,6 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
 				  u64 ref_index, char *name, int namelen,
 				  int *search_done)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	int ret;
 	char *victim_name;
 	int victim_name_len;
@@ -1063,7 +1061,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
 				kfree(victim_name);
 				if (ret)
 					return ret;
-				ret = btrfs_run_delayed_items(trans, fs_info);
+				ret = btrfs_run_delayed_items(trans);
 				if (ret)
 					return ret;
 				*search_done = 1;
@@ -1134,8 +1132,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
 							victim_name_len);
 					if (!ret)
 						ret = btrfs_run_delayed_items(
-								  trans,
-								  fs_info);
+								  trans);
 				}
 				iput(victim_parent);
 				kfree(victim_name);
@@ -1992,7 +1989,6 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
 				      struct inode *dir,
 				      struct btrfs_key *dir_key)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	int ret;
 	struct extent_buffer *eb;
 	int slot;
@@ -2056,7 +2052,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
 			ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir),
 					BTRFS_I(inode), name, name_len);
 			if (!ret)
-				ret = btrfs_run_delayed_items(trans, fs_info);
+				ret = btrfs_run_delayed_items(trans);
 			kfree(name);
 			iput(inode);
 			if (ret)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2ceb924ca0d6..a89cdf32e28b 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -27,6 +27,7 @@
 #include <linux/raid/pq.h>
 #include <linux/semaphore.h>
 #include <linux/uuid.h>
+#include <linux/list_sort.h>
 #include <asm/div64.h>
 #include "ctree.h"
 #include "extent_map.h"
@@ -708,7 +709,7 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
 	if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
 	    device->devid != BTRFS_DEV_REPLACE_DEVID) {
 		fs_devices->rw_devices++;
-		list_add(&device->dev_alloc_list, &fs_devices->alloc_list);
+		list_add_tail(&device->dev_alloc_list, &fs_devices->alloc_list);
 	}
 	brelse(bh);
 
@@ -1103,6 +1104,20 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 	return ret;
 }
 
+static int devid_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct btrfs_device *dev1, *dev2;
+
+	dev1 = list_entry(a, struct btrfs_device, dev_list);
+	dev2 = list_entry(b, struct btrfs_device, dev_list);
+
+	if (dev1->devid < dev2->devid)
+		return -1;
+	else if (dev1->devid > dev2->devid)
+		return 1;
+	return 0;
+}
+
 int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 		       fmode_t flags, void *holder)
 {
@@ -1113,6 +1128,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 		fs_devices->opened++;
 		ret = 0;
 	} else {
+		list_sort(NULL, &fs_devices->devices, devid_cmp);
 		ret = __btrfs_open_devices(fs_devices, flags, holder);
 	}
 	mutex_unlock(&uuid_mutex);
@@ -2666,19 +2682,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
 	return ret;
 }
 
-void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
-					      struct btrfs_device *tgtdev)
-{
-	u32 sectorsize = fs_info->sectorsize;
-
-	WARN_ON(fs_info->fs_devices->rw_devices == 0);
-	tgtdev->io_width = sectorsize;
-	tgtdev->io_align = sectorsize;
-	tgtdev->sector_size = sectorsize;
-	tgtdev->fs_info = fs_info;
-	set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &tgtdev->dev_state);
-}
-
 static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
 					struct btrfs_device *device)
 {
@@ -4672,7 +4675,7 @@ static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
 	btrfs_set_fs_incompat(info, RAID56);
 }
 
-#define BTRFS_MAX_DEVS(r) ((BTRFS_MAX_ITEM_SIZE(r->fs_info)		\
+#define BTRFS_MAX_DEVS(info) ((BTRFS_MAX_ITEM_SIZE(info)	\
 			- sizeof(struct btrfs_chunk))		\
 			/ sizeof(struct btrfs_stripe) + 1)
 
@@ -4713,10 +4716,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 
 	BUG_ON(!alloc_profile_is_valid(type, 0));
 
-	if (list_empty(&fs_devices->alloc_list))
+	if (list_empty(&fs_devices->alloc_list)) {
+		if (btrfs_test_opt(info, ENOSPC_DEBUG))
+			btrfs_debug(info, "%s: no writable device", __func__);
 		return -ENOSPC;
+	}
 
-	index = __get_raid_index(type);
+	index = btrfs_bg_flags_to_raid_index(type);
 
 	sub_stripes = btrfs_raid_array[index].sub_stripes;
 	dev_stripes = btrfs_raid_array[index].dev_stripes;
@@ -4729,7 +4735,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 		max_stripe_size = SZ_1G;
 		max_chunk_size = 10 * max_stripe_size;
 		if (!devs_max)
-			devs_max = BTRFS_MAX_DEVS(info->chunk_root);
+			devs_max = BTRFS_MAX_DEVS(info);
 	} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
 		/* for larger filesystems, use larger metadata chunks */
 		if (fs_devices->total_rw_bytes > 50ULL * SZ_1G)
@@ -4738,7 +4744,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 			max_stripe_size = SZ_256M;
 		max_chunk_size = max_stripe_size;
 		if (!devs_max)
-			devs_max = BTRFS_MAX_DEVS(info->chunk_root);
+			devs_max = BTRFS_MAX_DEVS(info);
 	} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
 		max_stripe_size = SZ_32M;
 		max_chunk_size = 2 * max_stripe_size;
@@ -4797,8 +4803,14 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 		if (ret == 0)
 			max_avail = max_stripe_size * dev_stripes;
 
-		if (max_avail < BTRFS_STRIPE_LEN * dev_stripes)
+		if (max_avail < BTRFS_STRIPE_LEN * dev_stripes) {
+			if (btrfs_test_opt(info, ENOSPC_DEBUG))
+				btrfs_debug(info,
+			"%s: devid %llu has no free space, have=%llu want=%u",
+					    __func__, device->devid, max_avail,
+					    BTRFS_STRIPE_LEN * dev_stripes);
 			continue;
+		}
 
 		if (ndevs == fs_devices->rw_devices) {
 			WARN(1, "%s: found more than %llu devices\n",
@@ -4823,6 +4835,12 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 
 	if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
 		ret = -ENOSPC;
+		if (btrfs_test_opt(info, ENOSPC_DEBUG)) {
+			btrfs_debug(info,
+	"%s: not enough devices with free space: have=%d minimum required=%d",
+				    __func__, ndevs, min(devs_min,
+				    devs_increment * sub_stripes));
+		}
 		goto error;
 	}
 
@@ -4853,18 +4871,17 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 	 * and compare that answer with the max chunk size
 	 */
 	if (stripe_size * data_stripes > max_chunk_size) {
-		u64 mask = (1ULL << 24) - 1;
-
 		stripe_size = div_u64(max_chunk_size, data_stripes);
 
 		/* bump the answer up to a 16MB boundary */
-		stripe_size = (stripe_size + mask) & ~mask;
+		stripe_size = round_up(stripe_size, SZ_16M);
 
-		/* but don't go higher than the limits we found
-		 * while searching for free extents
+		/*
+		 * But don't go higher than the limits we found while searching
+		 * for free extents
 		 */
-		if (stripe_size > devices_info[ndevs-1].max_avail)
-			stripe_size = devices_info[ndevs-1].max_avail;
+		stripe_size = min(devices_info[ndevs - 1].max_avail,
+				  stripe_size);
 	}
 
 	stripe_size = div_u64(stripe_size, dev_stripes);
@@ -7357,20 +7374,20 @@ void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info)
 }
 
 /* Must be invoked during the transaction commit */
-void btrfs_update_commit_device_bytes_used(struct btrfs_fs_info *fs_info,
-					struct btrfs_transaction *transaction)
+void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans)
 {
+	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct extent_map *em;
 	struct map_lookup *map;
 	struct btrfs_device *dev;
 	int i;
 
-	if (list_empty(&transaction->pending_chunks))
+	if (list_empty(&trans->pending_chunks))
 		return;
 
 	/* In order to kick the device replace finish process */
 	mutex_lock(&fs_info->chunk_mutex);
-	list_for_each_entry(em, &transaction->pending_chunks, list) {
+	list_for_each_entry(em, &trans->pending_chunks, list) {
 		map = em->map_lookup;
 
 		for (i = 0; i < map->num_stripes; i++) {
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 28c28eeadff3..d110fb03ec0d 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -476,8 +476,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,
 				      struct btrfs_device *srcdev);
 void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
 				      struct btrfs_device *tgtdev);
-void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
-					      struct btrfs_device *tgtdev);
 void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_path);
 int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
 			   u64 logical, u64 len);
@@ -546,9 +544,30 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
 	btrfs_dev_stat_set(dev, index, 0);
 }
 
+/*
+ * Convert block group flags (BTRFS_BLOCK_GROUP_*) to btrfs_raid_types, which
+ * can be used as index to access btrfs_raid_array[].
+ */
+static inline enum btrfs_raid_types btrfs_bg_flags_to_raid_index(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_RAID10)
+		return BTRFS_RAID_RAID10;
+	else if (flags & BTRFS_BLOCK_GROUP_RAID1)
+		return BTRFS_RAID_RAID1;
+	else if (flags & BTRFS_BLOCK_GROUP_DUP)
+		return BTRFS_RAID_DUP;
+	else if (flags & BTRFS_BLOCK_GROUP_RAID0)
+		return BTRFS_RAID_RAID0;
+	else if (flags & BTRFS_BLOCK_GROUP_RAID5)
+		return BTRFS_RAID_RAID5;
+	else if (flags & BTRFS_BLOCK_GROUP_RAID6)
+		return BTRFS_RAID_RAID6;
+
+	return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
+}
+
 void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info);
-void btrfs_update_commit_device_bytes_used(struct btrfs_fs_info *fs_info,
-					struct btrfs_transaction *transaction);
+void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans);
 
 struct list_head *btrfs_get_fs_uuids(void);
 void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
index 01a4eab602a3..eb3e39012658 100644
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -26,11 +26,14 @@
 #define ZSTD_BTRFS_MAX_WINDOWLOG 17
 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
 #define ZSTD_BTRFS_DEFAULT_LEVEL 3
+// Max supported by the algorithm is 22, but gains for small blocks (128KB)
+// are limited, thus we cap at 15.
+#define ZSTD_BTRFS_MAX_LEVEL 15
 
-static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len)
+static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len, int level)
 {
-	ZSTD_parameters params = ZSTD_getParams(ZSTD_BTRFS_DEFAULT_LEVEL,
-						src_len, 0);
+	ZSTD_parameters params = ZSTD_getParams(level, src_len, 0);
+	BUG_ON(level > ZSTD_maxCLevel());
 
 	if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
 		params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
@@ -45,6 +48,7 @@ struct workspace {
 	struct list_head list;
 	ZSTD_inBuffer in_buf;
 	ZSTD_outBuffer out_buf;
+	int level;
 };
 
 static void zstd_free_workspace(struct list_head *ws)
@@ -59,7 +63,8 @@ static void zstd_free_workspace(struct list_head *ws)
 static struct list_head *zstd_alloc_workspace(void)
 {
 	ZSTD_parameters params =
-			zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT);
+			zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT,
+						  ZSTD_BTRFS_MAX_LEVEL);
 	struct workspace *workspace;
 
 	workspace = kzalloc(sizeof(*workspace), GFP_KERNEL);
@@ -101,7 +106,7 @@ static int zstd_compress_pages(struct list_head *ws,
 	unsigned long len = *total_out;
 	const unsigned long nr_dest_pages = *out_pages;
 	unsigned long max_out = nr_dest_pages * PAGE_SIZE;
-	ZSTD_parameters params = zstd_get_btrfs_parameters(len);
+	ZSTD_parameters params = zstd_get_btrfs_parameters(len, workspace->level);
 
 	*out_pages = 0;
 	*total_out = 0;
@@ -427,6 +432,10 @@ static int zstd_decompress(struct list_head *ws, unsigned char *data_in,
 
 static void zstd_set_level(struct list_head *ws, unsigned int type)
 {
+	struct workspace *workspace = list_entry(ws, struct workspace, list);
+	unsigned level = (type & 0xF0) >> 4;
+
+	workspace->level = level > 0 ? level : ZSTD_BTRFS_DEFAULT_LEVEL;
 }
 
 const struct btrfs_compress_op btrfs_zstd_compress = {
diff --git a/fs/buffer.c b/fs/buffer.c
index 9a73924db22f..3b2b415f1fcd 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -3049,8 +3049,8 @@ void guard_bio_eod(int op, struct bio *bio)
 	}
 }
 
-static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
-			 enum rw_hint write_hint, struct writeback_control *wbc)
+struct bio *create_bh_bio(int op, int op_flags, struct buffer_head *bh,
+                          enum rw_hint write_hint)
 {
 	struct bio *bio;
 
@@ -3072,11 +3072,6 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
 	 */
 	bio = bio_alloc(GFP_NOIO, 1);
 
-	if (wbc) {
-		wbc_init_bio(wbc, bio);
-		wbc_account_io(wbc, bh->b_page, bh->b_size);
-	}
-
 	bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
 	bio_set_dev(bio, bh->b_bdev);
 	bio->bi_write_hint = write_hint;
@@ -3096,13 +3091,44 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
 		op_flags |= REQ_PRIO;
 	bio_set_op_attrs(bio, op, op_flags);
 
+	return bio;
+}
+
+static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
+			 enum rw_hint write_hint, struct writeback_control *wbc)
+{
+	struct bio *bio;
+
+	bio = create_bh_bio(op, op_flags, bh, write_hint);
+
+	if (wbc) {
+		wbc_init_bio(wbc, bio);
+		wbc_account_io(wbc, bh->b_page, bh->b_size);
+	}
+
 	submit_bio(bio);
 	return 0;
 }
 
+int submit_bh_blkcg_css(int op, int op_flags, struct buffer_head *bh,
+			struct cgroup_subsys_state *blkcg_css)
+{
+	struct bio *bio;
+
+	bio = create_bh_bio(op, op_flags, bh, 0);
+	bio_associate_blkcg(bio, blkcg_css);
+	submit_bio(bio);
+	return 0;
+}
+EXPORT_SYMBOL(submit_bh_blkcg_css);
+
 int submit_bh(int op, int op_flags, struct buffer_head *bh)
 {
-	return submit_bh_wbc(op, op_flags, bh, 0, NULL);
+	struct bio *bio;
+
+	bio = create_bh_bio(op, op_flags, bh, 0);
+	submit_bio(bio);
+	return 0;
 }
 EXPORT_SYMBOL(submit_bh);
 
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 687da62daf4e..e901ef6a4813 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -189,6 +189,7 @@ config CIFS_NFSD_EXPORT
 config CIFS_SMB311
 	bool "SMB3.1.1 network file system support (Experimental)"
 	depends on CIFS
+	select CRYPTO_SHA512
 
 	help
 	  This enables experimental support for the newest, SMB3.1.1, dialect.
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index f2b0a7f124da..6fa6d459678e 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -36,37 +36,6 @@
 #include <crypto/skcipher.h>
 #include <crypto/aead.h>
 
-static int
-cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
-{
-	int rc;
-	unsigned int size;
-
-	if (server->secmech.sdescmd5 != NULL)
-		return 0; /* already allocated */
-
-	server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
-	if (IS_ERR(server->secmech.md5)) {
-		cifs_dbg(VFS, "could not allocate crypto md5\n");
-		rc = PTR_ERR(server->secmech.md5);
-		server->secmech.md5 = NULL;
-		return rc;
-	}
-
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.md5);
-	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdescmd5) {
-		crypto_free_shash(server->secmech.md5);
-		server->secmech.md5 = NULL;
-		return -ENOMEM;
-	}
-	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
-	server->secmech.sdescmd5->shash.flags = 0x0;
-
-	return 0;
-}
-
 int __cifs_calc_signature(struct smb_rqst *rqst,
 			struct TCP_Server_Info *server, char *signature,
 			struct shash_desc *shash)
@@ -132,13 +101,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
 	if (!rqst->rq_iov || !signature || !server)
 		return -EINVAL;
 
-	if (!server->secmech.sdescmd5) {
-		rc = cifs_crypto_shash_md5_allocate(server);
-		if (rc) {
-			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
-			return -1;
-		}
-	}
+	rc = cifs_alloc_hash("md5", &server->secmech.md5,
+			     &server->secmech.sdescmd5);
+	if (rc)
+		return -1;
 
 	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
 	if (rc) {
@@ -663,37 +629,6 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
 	return rc;
 }
 
-static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
-{
-	int rc;
-	unsigned int size;
-
-	/* check if already allocated */
-	if (server->secmech.sdeschmacmd5)
-		return 0;
-
-	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
-	if (IS_ERR(server->secmech.hmacmd5)) {
-		cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
-		rc = PTR_ERR(server->secmech.hmacmd5);
-		server->secmech.hmacmd5 = NULL;
-		return rc;
-	}
-
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.hmacmd5);
-	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdeschmacmd5) {
-		crypto_free_shash(server->secmech.hmacmd5);
-		server->secmech.hmacmd5 = NULL;
-		return -ENOMEM;
-	}
-	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
-	server->secmech.sdeschmacmd5->shash.flags = 0x0;
-
-	return 0;
-}
-
 int
 setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 {
@@ -757,9 +692,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
 	mutex_lock(&ses->server->srv_mutex);
 
-	rc = crypto_hmacmd5_alloc(ses->server);
+	rc = cifs_alloc_hash("hmac(md5)",
+			     &ses->server->secmech.hmacmd5,
+			     &ses->server->secmech.sdeschmacmd5);
 	if (rc) {
-		cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
 		goto unlock;
 	}
 
@@ -893,6 +829,11 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
 		server->secmech.md5 = NULL;
 	}
 
+	if (server->secmech.md5) {
+		crypto_free_shash(server->secmech.sha512);
+		server->secmech.sha512 = NULL;
+	}
+
 	if (server->secmech.hmacmd5) {
 		crypto_free_shash(server->secmech.hmacmd5);
 		server->secmech.hmacmd5 = NULL;
@@ -916,4 +857,6 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
 	server->secmech.sdeschmacmd5 = NULL;
 	kfree(server->secmech.sdescmd5);
 	server->secmech.sdescmd5 = NULL;
+	kfree(server->secmech.sdescsha512);
+	server->secmech.sdescsha512 = NULL;
 }
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 32cdea67bbfd..f715609b13f3 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1486,6 +1486,7 @@ MODULE_SOFTDEP("pre: nls");
 MODULE_SOFTDEP("pre: aes");
 MODULE_SOFTDEP("pre: cmac");
 MODULE_SOFTDEP("pre: sha256");
+MODULE_SOFTDEP("pre: sha512");
 MODULE_SOFTDEP("pre: aead2");
 MODULE_SOFTDEP("pre: ccm");
 module_init(init_cifs)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 48f7c197cd2d..765fc2c9fd91 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -130,10 +130,12 @@ struct cifs_secmech {
 	struct crypto_shash *md5; /* md5 hash function */
 	struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
 	struct crypto_shash *cmacaes; /* block-cipher based MAC function */
+	struct crypto_shash *sha512; /* sha512 hash function */
 	struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
 	struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
 	struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 	struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
+	struct sdesc *sdescsha512; /* ctxt to generate smb3.11 signing key */
 	struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
 	struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
 };
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 93d565186698..365a414a75e9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -542,4 +542,9 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
 struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
 void cifs_aio_ctx_release(struct kref *refcount);
 int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
+
+int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
+		    struct sdesc **sdesc);
+void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
+
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 60b5a11ee11b..889a840172eb 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -50,25 +50,12 @@ static int
 symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
 {
 	int rc;
-	unsigned int size;
-	struct crypto_shash *md5;
-	struct sdesc *sdescmd5;
-
-	md5 = crypto_alloc_shash("md5", 0, 0);
-	if (IS_ERR(md5)) {
-		rc = PTR_ERR(md5);
-		cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n",
-			 __func__, rc);
-		return rc;
-	}
-	size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
-	sdescmd5 = kmalloc(size, GFP_KERNEL);
-	if (!sdescmd5) {
-		rc = -ENOMEM;
+	struct crypto_shash *md5 = NULL;
+	struct sdesc *sdescmd5 = NULL;
+
+	rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
+	if (rc)
 		goto symlink_hash_err;
-	}
-	sdescmd5->shash.tfm = md5;
-	sdescmd5->shash.flags = 0x0;
 
 	rc = crypto_shash_init(&sdescmd5->shash);
 	if (rc) {
@@ -85,9 +72,7 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
 		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
 
 symlink_hash_err:
-	crypto_free_shash(md5);
-	kfree(sdescmd5);
-
+	cifs_free_hash(&md5, &sdescmd5);
 	return rc;
 }
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index a0dbced4a45c..460084a8eac5 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -848,3 +848,57 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
 	iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len);
 	return 0;
 }
+
+/**
+ * cifs_alloc_hash - allocate hash and hash context together
+ *
+ * The caller has to make sure @sdesc is initialized to either NULL or
+ * a valid context. Both can be freed via cifs_free_hash().
+ */
+int
+cifs_alloc_hash(const char *name,
+		struct crypto_shash **shash, struct sdesc **sdesc)
+{
+	int rc = 0;
+	size_t size;
+
+	if (*sdesc != NULL)
+		return 0;
+
+	*shash = crypto_alloc_shash(name, 0, 0);
+	if (IS_ERR(*shash)) {
+		cifs_dbg(VFS, "could not allocate crypto %s\n", name);
+		rc = PTR_ERR(*shash);
+		*shash = NULL;
+		*sdesc = NULL;
+		return rc;
+	}
+
+	size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
+	*sdesc = kmalloc(size, GFP_KERNEL);
+	if (*sdesc == NULL) {
+		cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name);
+		crypto_free_shash(*shash);
+		*shash = NULL;
+		return -ENOMEM;
+	}
+
+	(*sdesc)->shash.tfm = *shash;
+	(*sdesc)->shash.flags = 0x0;
+	return 0;
+}
+
+/**
+ * cifs_free_hash - free hash and hash context together
+ *
+ * Freeing a NULL hash or context is safe.
+ */
+void
+cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
+{
+	kfree(*sdesc);
+	*sdesc = NULL;
+	if (*shash)
+		crypto_free_shash(*shash);
+	*shash = NULL;
+}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 63778ac22fd9..ab4c20687cc0 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1738,8 +1738,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 		rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
 						 &name_len,
 						 tcon->treeName, path);
-		if (rc)
+		if (rc) {
+			cifs_small_buf_release(req);
 			return rc;
+		}
 		req->NameLength = cpu_to_le16(name_len * 2);
 		uni_path_len = copy_size;
 		path = copy_path;
@@ -1750,8 +1752,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 		if (uni_path_len % 8 != 0) {
 			copy_size = roundup(uni_path_len, 8);
 			copy_path = kzalloc(copy_size, GFP_KERNEL);
-			if (!copy_path)
+			if (!copy_path) {
+				cifs_small_buf_release(req);
 				return -ENOMEM;
+			}
 			memcpy((char *)copy_path, (const char *)path,
 			       uni_path_len);
 			uni_path_len = copy_size;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 05287b01f596..3b8e9c2e55bc 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -202,4 +202,7 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
 
 extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
 					enum securityEnum);
+#ifdef CONFIG_CIFS_SMB311
+extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
+#endif
 #endif			/* _SMB2PROTO_H */
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 99493946e2f9..bf49cb73b9e6 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -43,77 +43,62 @@
 static int
 smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
-	int rc;
-	unsigned int size;
+	return cifs_alloc_hash("hmac(sha256)",
+			       &server->secmech.hmacsha256,
+			       &server->secmech.sdeschmacsha256);
+}
 
-	if (server->secmech.sdeschmacsha256 != NULL)
-		return 0; /* already allocated */
+static int
+smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
+{
+	struct cifs_secmech *p = &server->secmech;
+	int rc;
 
-	server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
-	if (IS_ERR(server->secmech.hmacsha256)) {
-		cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
-		rc = PTR_ERR(server->secmech.hmacsha256);
-		server->secmech.hmacsha256 = NULL;
-		return rc;
-	}
+	rc = cifs_alloc_hash("hmac(sha256)",
+			     &p->hmacsha256,
+			     &p->sdeschmacsha256);
+	if (rc)
+		goto err;
 
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.hmacsha256);
-	server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdeschmacsha256) {
-		crypto_free_shash(server->secmech.hmacsha256);
-		server->secmech.hmacsha256 = NULL;
-		return -ENOMEM;
-	}
-	server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
-	server->secmech.sdeschmacsha256->shash.flags = 0x0;
+	rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
+	if (rc)
+		goto err;
 
 	return 0;
+err:
+	cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
+	return rc;
 }
 
-static int
-smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
+#ifdef CONFIG_CIFS_SMB311
+int
+smb311_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
-	unsigned int size;
-	int rc;
-
-	if (server->secmech.sdesccmacaes != NULL)
-		return 0;  /* already allocated */
+	struct cifs_secmech *p = &server->secmech;
+	int rc = 0;
 
-	rc = smb2_crypto_shash_allocate(server);
+	rc = cifs_alloc_hash("hmac(sha256)",
+			     &p->hmacsha256,
+			     &p->sdeschmacsha256);
 	if (rc)
 		return rc;
 
-	server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(server->secmech.cmacaes)) {
-		cifs_dbg(VFS, "could not allocate crypto cmac-aes");
-		kfree(server->secmech.sdeschmacsha256);
-		server->secmech.sdeschmacsha256 = NULL;
-		crypto_free_shash(server->secmech.hmacsha256);
-		server->secmech.hmacsha256 = NULL;
-		rc = PTR_ERR(server->secmech.cmacaes);
-		server->secmech.cmacaes = NULL;
-		return rc;
-	}
+	rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
+	if (rc)
+		goto err;
 
-	size = sizeof(struct shash_desc) +
-			crypto_shash_descsize(server->secmech.cmacaes);
-	server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
-	if (!server->secmech.sdesccmacaes) {
-		cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
-		kfree(server->secmech.sdeschmacsha256);
-		server->secmech.sdeschmacsha256 = NULL;
-		crypto_free_shash(server->secmech.hmacsha256);
-		crypto_free_shash(server->secmech.cmacaes);
-		server->secmech.hmacsha256 = NULL;
-		server->secmech.cmacaes = NULL;
-		return -ENOMEM;
-	}
-	server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
-	server->secmech.sdesccmacaes->shash.flags = 0x0;
+	rc = cifs_alloc_hash("sha512", &p->sha512, &p->sdescsha512);
+	if (rc)
+		goto err;
 
 	return 0;
+
+err:
+	cifs_free_hash(&p->cmacaes, &p->sdesccmacaes);
+	cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
+	return rc;
 }
+#endif
 
 static struct cifs_ses *
 smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
@@ -457,7 +442,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 		cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
 		return rc;
 	}
-	
+
 	rc = __cifs_calc_signature(rqst, server, sigptr,
 				   &server->secmech.sdesccmacaes->shash);
 
diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c
index 91710eb571fb..5aa0b54b32ce 100644
--- a/fs/cifs/smbdirect.c
+++ b/fs/cifs/smbdirect.c
@@ -1025,7 +1025,7 @@ static int smbd_post_send(struct smbd_connection *info,
 
 	for (i = 0; i < request->num_sge; i++) {
 		log_rdma_send(INFO,
-			"rdma_request sge[%d] addr=%llu legnth=%u\n",
+			"rdma_request sge[%d] addr=%llu length=%u\n",
 			i, request->sge[0].addr, request->sge[0].length);
 		ib_dma_sync_single_for_device(
 			info->id->device,
@@ -2295,7 +2295,7 @@ static void smbd_mr_recovery_work(struct work_struct *work)
 				rc = ib_dereg_mr(smbdirect_mr->mr);
 				if (rc) {
 					log_rdma_mr(ERR,
-						"ib_dereg_mr faield rc=%x\n",
+						"ib_dereg_mr failed rc=%x\n",
 						rc);
 					smbd_disconnect_rdma_connection(info);
 				}
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index c12bffefa3c9..a0b80ac651a6 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -121,25 +121,12 @@ int
 mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
 {
 	int rc;
-	unsigned int size;
-	struct crypto_shash *md4;
-	struct sdesc *sdescmd4;
-
-	md4 = crypto_alloc_shash("md4", 0, 0);
-	if (IS_ERR(md4)) {
-		rc = PTR_ERR(md4);
-		cifs_dbg(VFS, "%s: Crypto md4 allocation error %d\n",
-			 __func__, rc);
-		return rc;
-	}
-	size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
-	sdescmd4 = kmalloc(size, GFP_KERNEL);
-	if (!sdescmd4) {
-		rc = -ENOMEM;
+	struct crypto_shash *md4 = NULL;
+	struct sdesc *sdescmd4 = NULL;
+
+	rc = cifs_alloc_hash("md4", &md4, &sdescmd4);
+	if (rc)
 		goto mdfour_err;
-	}
-	sdescmd4->shash.tfm = md4;
-	sdescmd4->shash.flags = 0x0;
 
 	rc = crypto_shash_init(&sdescmd4->shash);
 	if (rc) {
@@ -156,9 +143,7 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
 		cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__);
 
 mdfour_err:
-	crypto_free_shash(md4);
-	kfree(sdescmd4);
-
+	cifs_free_hash(&md4, &sdescmd4);
 	return rc;
 }
 
diff --git a/fs/dcache.c b/fs/dcache.c
index 7c38f39958bc..b3dc1870caa8 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -287,7 +287,8 @@ void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry
 		spin_unlock(&dentry->d_lock);
 		name->name = p->name;
 	} else {
-		memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN);
+		memcpy(name->inline_name, dentry->d_iname,
+		       dentry->d_name.len + 1);
 		spin_unlock(&dentry->d_lock);
 		name->name = name->inline_name;
 	}
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index cff79ea0c01d..5243989a60cc 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -482,7 +482,6 @@ static void lowcomms_error_report(struct sock *sk)
 {
 	struct connection *con;
 	struct sockaddr_storage saddr;
-	int buflen;
 	void (*orig_report)(struct sock *) = NULL;
 
 	read_lock_bh(&sk->sk_callback_lock);
@@ -492,7 +491,7 @@ static void lowcomms_error_report(struct sock *sk)
 
 	orig_report = listen_sock.sk_error_report;
 	if (con->sock == NULL ||
-	    kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) {
+	    kernel_getpeername(con->sock, (struct sockaddr *)&saddr) < 0) {
 		printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
 				   "sending to node %d, port %d, "
 				   "sk_err=%d/%d\n", dlm_our_nodeid(),
@@ -757,8 +756,8 @@ static int tcp_accept_from_sock(struct connection *con)
 
 	/* Get the connected socket's peer */
 	memset(&peeraddr, 0, sizeof(peeraddr));
-	if (newsock->ops->getname(newsock, (struct sockaddr *)&peeraddr,
-				  &len, 2)) {
+	len = newsock->ops->getname(newsock, (struct sockaddr *)&peeraddr, 2);
+	if (len < 0) {
 		result = -ECONNABORTED;
 		goto accept_err;
 	}
diff --git a/fs/exec.c b/fs/exec.c
index 7eb8d21bcab9..e7b69e14649f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1333,6 +1333,7 @@ void setup_new_exec(struct linux_binprm * bprm)
 	if (bprm->secureexec) {
 		/* Make sure parent cannot signal privileged process. */
 		current->pdeath_signal = 0;
+		current->signal->pdeath_signal_proc = 0;
 
 		/*
 		 * For secureexec, reset the stack limit to sane default to
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 9b2ac55ac34f..5d5e9f7b98d6 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1373,7 +1373,7 @@ void ext2_set_inode_flags(struct inode *inode)
 	unsigned int flags = EXT2_I(inode)->i_flags;
 
 	inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME |
-				S_DIRSYNC | S_DAX);
+				S_DIRSYNC | S_DAX | S_CGROUPWB);
 	if (flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
 	if (flags & EXT2_APPEND_FL)
@@ -1386,6 +1386,7 @@ void ext2_set_inode_flags(struct inode *inode)
 		inode->i_flags |= S_DIRSYNC;
 	if (test_opt(inode->i_sb, DAX) && S_ISREG(inode->i_mode))
 		inode->i_flags |= S_DAX;
+	inode->i_flags |= S_CGROUPWB;
 }
 
 struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 7666c065b96f..ca201bfd6d03 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -930,7 +930,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
 		((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
 		 SB_POSIXACL : 0);
-	sb->s_iflags |= SB_I_CGROUPWB;
 
 	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
 	    (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c94780075b04..2a47c2f715bb 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4668,9 +4668,11 @@ void ext4_set_inode_flags(struct inode *inode)
 		new_fl |= S_DAX;
 	if (flags & EXT4_ENCRYPT_FL)
 		new_fl |= S_ENCRYPTED;
+	if (!ext4_should_journal_data(inode))
+		new_fl |= S_CGROUPWB;
 	inode_set_flags(inode, new_fl,
 			S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX|
-			S_ENCRYPTED);
+			S_ENCRYPTED|S_CGROUPWB);
 }
 
 static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 39bf464c35f1..0df696e63819 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3621,8 +3621,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 		}
 		if (test_opt(sb, DELALLOC))
 			clear_opt(sb, DELALLOC);
-	} else {
-		sb->s_iflags |= SB_I_CGROUPWB;
 	}
 
 	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 205add3d0f3a..f34652c4288f 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -48,9 +48,10 @@ void f2fs_set_inode_flags(struct inode *inode)
 		new_fl |= S_DIRSYNC;
 	if (f2fs_encrypted_inode(inode))
 		new_fl |= S_ENCRYPTED;
+	new_fl |= S_CGROUPWB;
 	inode_set_flags(inode, new_fl,
 			S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|
-			S_ENCRYPTED);
+			S_ENCRYPTED|S_CGROUPWB);
 }
 
 static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 8173ae688814..ebcd58476fc7 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -2560,7 +2560,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
 		(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
 	memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
-	sb->s_iflags |= SB_I_CGROUPWB;
 
 	/* init f2fs-specific super block info */
 	sbi->valid_super_block = valid_super_block;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 624f18bbfd2b..0a9e516461d5 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1205,7 +1205,7 @@ static void fuse_kill_sb_anon(struct super_block *sb)
 static struct file_system_type fuse_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "fuse",
-	.fs_flags	= FS_HAS_SUBTYPE,
+	.fs_flags	= FS_HAS_SUBTYPE | FS_IMA_NO_CACHE,
 	.mount		= fuse_mount,
 	.kill_sb	= fuse_kill_sb_anon,
 };
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 2c908b31d6c9..8f17719842ec 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -307,6 +307,20 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
 		spin_unlock(&group->notification_lock);
 		ret = put_user(send_len, (int __user *) p);
 		break;
+#ifdef CONFIG_CHECKPOINT_RESTORE
+	case INOTIFY_IOC_SETNEXTWD:
+		ret = -EINVAL;
+		if (arg >= 1 && arg <= INT_MAX) {
+			struct inotify_group_private_data *data;
+
+			data = &group->inotify_data;
+			spin_lock(&data->idr_lock);
+			idr_set_cursor(&data->idr, (unsigned int)arg);
+			spin_unlock(&data->idr_lock);
+			ret = 0;
+		}
+		break;
+#endif /* CONFIG_CHECKPOINT_RESTORE */
 	}
 
 	return ret;
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 36b0772701a0..60702d677bd4 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -184,6 +184,7 @@ int open_related_ns(struct ns_common *ns,
 
 	return fd;
 }
+EXPORT_SYMBOL_GPL(open_related_ns);
 
 static long ns_ioctl(struct file *filp, unsigned int ioctl,
 			unsigned long arg)
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index eac5140aac47..e5076185cc1e 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1819,7 +1819,7 @@ int o2net_register_hb_callbacks(void)
 
 static int o2net_accept_one(struct socket *sock, int *more)
 {
-	int ret, slen;
+	int ret;
 	struct sockaddr_in sin;
 	struct socket *new_sock = NULL;
 	struct o2nm_node *node = NULL;
@@ -1864,9 +1864,7 @@ static int o2net_accept_one(struct socket *sock, int *more)
 		goto out;
 	}
 
-	slen = sizeof(sin);
-	ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin,
-				       &slen, 1);
+	ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin, 1);
 	if (ret < 0)
 		goto out;
 
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 9479f99c2145..e4b9085a657a 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -3539,7 +3539,7 @@ static int ocfs2_downconvert_lock(struct ocfs2_super *osb,
 	 * we can recover correctly from node failure. Otherwise, we may get
 	 * invalid LVB in LKB, but without DLM_SBF_VALNOTVALID being set.
 	 */
-	if (!ocfs2_is_o2cb_active() &&
+	if (ocfs2_userspace_stack(osb) &&
 	    lockres->l_ops->flags & LOCK_TYPE_USES_LVB)
 		lvb = 1;
 
diff --git a/fs/ocfs2/filecheck.c b/fs/ocfs2/filecheck.c
index e87279e49ba3..f65f2b2f594d 100644
--- a/fs/ocfs2/filecheck.c
+++ b/fs/ocfs2/filecheck.c
@@ -53,36 +53,6 @@ static const char * const ocfs2_filecheck_errs[] = {
 	"UNSUPPORTED"
 };
 
-static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
-static LIST_HEAD(ocfs2_filecheck_sysfs_list);
-
-struct ocfs2_filecheck {
-	struct list_head fc_head;	/* File check entry list head */
-	spinlock_t fc_lock;
-	unsigned int fc_max;	/* Maximum number of entry in list */
-	unsigned int fc_size;	/* Current entry count in list */
-	unsigned int fc_done;	/* Finished entry count in list */
-};
-
-struct ocfs2_filecheck_sysfs_entry {	/* sysfs entry per mounting */
-	struct list_head fs_list;
-	atomic_t fs_count;
-	struct super_block *fs_sb;
-	struct kset *fs_devicekset;
-	struct kset *fs_fcheckkset;
-	struct ocfs2_filecheck *fs_fcheck;
-};
-
-#define OCFS2_FILECHECK_MAXSIZE		100
-#define OCFS2_FILECHECK_MINSIZE		10
-
-/* File check operation type */
-enum {
-	OCFS2_FILECHECK_TYPE_CHK = 0,	/* Check a file(inode) */
-	OCFS2_FILECHECK_TYPE_FIX,	/* Fix a file(inode) */
-	OCFS2_FILECHECK_TYPE_SET = 100	/* Set entry list maximum size */
-};
-
 struct ocfs2_filecheck_entry {
 	struct list_head fe_list;
 	unsigned long fe_ino;
@@ -110,34 +80,84 @@ ocfs2_filecheck_error(int errno)
 	return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
 }
 
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
-				    char *buf);
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count);
-static struct kobj_attribute ocfs2_attr_filecheck_chk =
+static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					char *buf);
+static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
+					struct kobj_attribute *attr,
+					const char *buf, size_t count);
+static struct kobj_attribute ocfs2_filecheck_attr_chk =
 					__ATTR(check, S_IRUSR | S_IWUSR,
-					ocfs2_filecheck_show,
-					ocfs2_filecheck_store);
-static struct kobj_attribute ocfs2_attr_filecheck_fix =
+					ocfs2_filecheck_attr_show,
+					ocfs2_filecheck_attr_store);
+static struct kobj_attribute ocfs2_filecheck_attr_fix =
 					__ATTR(fix, S_IRUSR | S_IWUSR,
-					ocfs2_filecheck_show,
-					ocfs2_filecheck_store);
-static struct kobj_attribute ocfs2_attr_filecheck_set =
+					ocfs2_filecheck_attr_show,
+					ocfs2_filecheck_attr_store);
+static struct kobj_attribute ocfs2_filecheck_attr_set =
 					__ATTR(set, S_IRUSR | S_IWUSR,
-					ocfs2_filecheck_show,
-					ocfs2_filecheck_store);
+					ocfs2_filecheck_attr_show,
+					ocfs2_filecheck_attr_store);
+static struct attribute *ocfs2_filecheck_attrs[] = {
+	&ocfs2_filecheck_attr_chk.attr,
+	&ocfs2_filecheck_attr_fix.attr,
+	&ocfs2_filecheck_attr_set.attr,
+	NULL
+};
+
+static void ocfs2_filecheck_release(struct kobject *kobj)
+{
+	struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj,
+				struct ocfs2_filecheck_sysfs_entry, fs_kobj);
+
+	complete(&entry->fs_kobj_unregister);
+}
+
+static ssize_t
+ocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	ssize_t ret = -EIO;
+	struct kobj_attribute *kattr = container_of(attr,
+					struct kobj_attribute, attr);
+
+	kobject_get(kobj);
+	if (kattr->show)
+		ret = kattr->show(kobj, kattr, buf);
+	kobject_put(kobj);
+	return ret;
+}
+
+static ssize_t
+ocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr,
+			const char *buf, size_t count)
+{
+	ssize_t ret = -EIO;
+	struct kobj_attribute *kattr = container_of(attr,
+					struct kobj_attribute, attr);
+
+	kobject_get(kobj);
+	if (kattr->store)
+		ret = kattr->store(kobj, kattr, buf, count);
+	kobject_put(kobj);
+	return ret;
+}
+
+static const struct sysfs_ops ocfs2_filecheck_ops = {
+	.show = ocfs2_filecheck_show,
+	.store = ocfs2_filecheck_store,
+};
+
+static struct kobj_type ocfs2_ktype_filecheck = {
+	.default_attrs = ocfs2_filecheck_attrs,
+	.sysfs_ops = &ocfs2_filecheck_ops,
+	.release = ocfs2_filecheck_release,
+};
 
 static void
 ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
 {
 	struct ocfs2_filecheck_entry *p;
 
-	if (!atomic_dec_and_test(&entry->fs_count))
-		wait_on_atomic_t(&entry->fs_count, atomic_t_wait,
-				 TASK_UNINTERRUPTIBLE);
-
 	spin_lock(&entry->fs_fcheck->fc_lock);
 	while (!list_empty(&entry->fs_fcheck->fc_head)) {
 		p = list_first_entry(&entry->fs_fcheck->fc_head,
@@ -148,151 +168,48 @@ ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
 	}
 	spin_unlock(&entry->fs_fcheck->fc_lock);
 
-	kset_unregister(entry->fs_fcheckkset);
-	kset_unregister(entry->fs_devicekset);
 	kfree(entry->fs_fcheck);
-	kfree(entry);
-}
-
-static void
-ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry)
-{
-	spin_lock(&ocfs2_filecheck_sysfs_lock);
-	list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list);
-	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+	entry->fs_fcheck = NULL;
 }
 
-static int ocfs2_filecheck_sysfs_del(const char *devname)
+int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb)
 {
-	struct ocfs2_filecheck_sysfs_entry *p;
-
-	spin_lock(&ocfs2_filecheck_sysfs_lock);
-	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
-		if (!strcmp(p->fs_sb->s_id, devname)) {
-			list_del(&p->fs_list);
-			spin_unlock(&ocfs2_filecheck_sysfs_lock);
-			ocfs2_filecheck_sysfs_free(p);
-			return 0;
-		}
-	}
-	spin_unlock(&ocfs2_filecheck_sysfs_lock);
-	return 1;
-}
-
-static void
-ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry)
-{
-	if (atomic_dec_and_test(&entry->fs_count))
-		wake_up_atomic_t(&entry->fs_count);
-}
-
-static struct ocfs2_filecheck_sysfs_entry *
-ocfs2_filecheck_sysfs_get(const char *devname)
-{
-	struct ocfs2_filecheck_sysfs_entry *p = NULL;
-
-	spin_lock(&ocfs2_filecheck_sysfs_lock);
-	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
-		if (!strcmp(p->fs_sb->s_id, devname)) {
-			atomic_inc(&p->fs_count);
-			spin_unlock(&ocfs2_filecheck_sysfs_lock);
-			return p;
-		}
-	}
-	spin_unlock(&ocfs2_filecheck_sysfs_lock);
-	return NULL;
-}
-
-int ocfs2_filecheck_create_sysfs(struct super_block *sb)
-{
-	int ret = 0;
-	struct kset *device_kset = NULL;
-	struct kset *fcheck_kset = NULL;
-	struct ocfs2_filecheck *fcheck = NULL;
-	struct ocfs2_filecheck_sysfs_entry *entry = NULL;
-	struct attribute **attrs = NULL;
-	struct attribute_group attrgp;
-
-	if (!ocfs2_kset)
-		return -ENOMEM;
-
-	attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS);
-	if (!attrs) {
-		ret = -ENOMEM;
-		goto error;
-	} else {
-		attrs[0] = &ocfs2_attr_filecheck_chk.attr;
-		attrs[1] = &ocfs2_attr_filecheck_fix.attr;
-		attrs[2] = &ocfs2_attr_filecheck_set.attr;
-		attrs[3] = NULL;
-		memset(&attrgp, 0, sizeof(attrgp));
-		attrgp.attrs = attrs;
-	}
+	int ret;
+	struct ocfs2_filecheck *fcheck;
+	struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent;
 
 	fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
-	if (!fcheck) {
-		ret = -ENOMEM;
-		goto error;
-	} else {
-		INIT_LIST_HEAD(&fcheck->fc_head);
-		spin_lock_init(&fcheck->fc_lock);
-		fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
-		fcheck->fc_size = 0;
-		fcheck->fc_done = 0;
-	}
-
-	if (strlen(sb->s_id) <= 0) {
-		mlog(ML_ERROR,
-		"Cannot get device basename when create filecheck sysfs\n");
-		ret = -ENODEV;
-		goto error;
-	}
-
-	device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj);
-	if (!device_kset) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	if (!fcheck)
+		return -ENOMEM;
 
-	fcheck_kset = kset_create_and_add("filecheck", NULL,
-					  &device_kset->kobj);
-	if (!fcheck_kset) {
-		ret = -ENOMEM;
-		goto error;
+	INIT_LIST_HEAD(&fcheck->fc_head);
+	spin_lock_init(&fcheck->fc_lock);
+	fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
+	fcheck->fc_size = 0;
+	fcheck->fc_done = 0;
+
+	entry->fs_kobj.kset = osb->osb_dev_kset;
+	init_completion(&entry->fs_kobj_unregister);
+	ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck,
+					NULL, "filecheck");
+	if (ret) {
+		kfree(fcheck);
+		return ret;
 	}
 
-	ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp);
-	if (ret)
-		goto error;
-
-	entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS);
-	if (!entry) {
-		ret = -ENOMEM;
-		goto error;
-	} else {
-		atomic_set(&entry->fs_count, 1);
-		entry->fs_sb = sb;
-		entry->fs_devicekset = device_kset;
-		entry->fs_fcheckkset = fcheck_kset;
-		entry->fs_fcheck = fcheck;
-		ocfs2_filecheck_sysfs_add(entry);
-	}
-
-	kfree(attrs);
+	entry->fs_fcheck = fcheck;
 	return 0;
-
-error:
-	kfree(attrs);
-	kfree(entry);
-	kfree(fcheck);
-	kset_unregister(fcheck_kset);
-	kset_unregister(device_kset);
-	return ret;
 }
 
-int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
+void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb)
 {
-	return ocfs2_filecheck_sysfs_del(sb->s_id);
+	if (!osb->osb_fc_ent.fs_fcheck)
+		return;
+
+	kobject_del(&osb->osb_fc_ent.fs_kobj);
+	kobject_put(&osb->osb_fc_ent.fs_kobj);
+	wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister);
+	ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent);
 }
 
 static int
@@ -309,7 +226,7 @@ ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
 
 	spin_lock(&ent->fs_fcheck->fc_lock);
 	if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
-		mlog(ML_ERROR,
+		mlog(ML_NOTICE,
 		"Cannot set online file check maximum entry number "
 		"to %u due to too many pending entries(%u)\n",
 		len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
@@ -386,7 +303,7 @@ ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
 	return 0;
 }
 
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
+static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
 				    struct kobj_attribute *attr,
 				    char *buf)
 {
@@ -394,19 +311,12 @@ static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
 	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
 	unsigned int type;
 	struct ocfs2_filecheck_entry *p;
-	struct ocfs2_filecheck_sysfs_entry *ent;
+	struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
+				struct ocfs2_filecheck_sysfs_entry, fs_kobj);
 
 	if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
 		return -EINVAL;
 
-	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
-	if (!ent) {
-		mlog(ML_ERROR,
-		"Cannot get the corresponding entry via device basename %s\n",
-		kobj->name);
-		return -ENODEV;
-	}
-
 	if (type == OCFS2_FILECHECK_TYPE_SET) {
 		spin_lock(&ent->fs_fcheck->fc_lock);
 		total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
@@ -440,11 +350,26 @@ static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
 	spin_unlock(&ent->fs_fcheck->fc_lock);
 
 exit:
-	ocfs2_filecheck_sysfs_put(ent);
 	return total;
 }
 
-static int
+static inline int
+ocfs2_filecheck_is_dup_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+				unsigned long ino)
+{
+	struct ocfs2_filecheck_entry *p;
+
+	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+		if (!p->fe_done) {
+			if (p->fe_ino == ino)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+static inline int
 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
 {
 	struct ocfs2_filecheck_entry *p;
@@ -483,21 +408,21 @@ static void
 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
 			   struct ocfs2_filecheck_entry *entry)
 {
-	entry->fe_done = 1;
 	spin_lock(&ent->fs_fcheck->fc_lock);
+	entry->fe_done = 1;
 	ent->fs_fcheck->fc_done++;
 	spin_unlock(&ent->fs_fcheck->fc_lock);
 }
 
 static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
 		       unsigned long ino, unsigned int flags)
 {
 	unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
 	struct inode *inode = NULL;
 	int rc;
 
-	inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0);
+	inode = ocfs2_iget(osb, ino, flags, 0);
 	if (IS_ERR(inode)) {
 		rc = (int)(-(long)inode);
 		if (rc >= OCFS2_FILECHECK_ERR_START &&
@@ -515,11 +440,14 @@ static void
 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
 			     struct ocfs2_filecheck_entry *entry)
 {
+	struct ocfs2_super *osb = container_of(ent, struct ocfs2_super,
+						osb_fc_ent);
+
 	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
 				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
 	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
 				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
 	else
 		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
@@ -527,30 +455,21 @@ ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
 	ocfs2_filecheck_done_entry(ent, entry);
 }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
+static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
 				     struct kobj_attribute *attr,
 				     const char *buf, size_t count)
 {
+	ssize_t ret = 0;
 	struct ocfs2_filecheck_args args;
 	struct ocfs2_filecheck_entry *entry;
-	struct ocfs2_filecheck_sysfs_entry *ent;
-	ssize_t ret = 0;
+	struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
+				struct ocfs2_filecheck_sysfs_entry, fs_kobj);
 
 	if (count == 0)
 		return count;
 
-	if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) {
-		mlog(ML_ERROR, "Invalid arguments for online file check\n");
+	if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args))
 		return -EINVAL;
-	}
-
-	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
-	if (!ent) {
-		mlog(ML_ERROR,
-		"Cannot get the corresponding entry via device basename %s\n",
-		kobj->parent->name);
-		return -ENODEV;
-	}
 
 	if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
 		ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
@@ -564,13 +483,16 @@ static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
 	}
 
 	spin_lock(&ent->fs_fcheck->fc_lock);
-	if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-	    (ent->fs_fcheck->fc_done == 0)) {
-		mlog(ML_ERROR,
+	if (ocfs2_filecheck_is_dup_entry(ent, args.fa_ino)) {
+		ret = -EEXIST;
+		kfree(entry);
+	} else if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
+		(ent->fs_fcheck->fc_done == 0)) {
+		mlog(ML_NOTICE,
 		"Cannot do more file check "
 		"since file check queue(%u) is full now\n",
 		ent->fs_fcheck->fc_max);
-		ret = -EBUSY;
+		ret = -EAGAIN;
 		kfree(entry);
 	} else {
 		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
@@ -595,6 +517,5 @@ static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
 		ocfs2_filecheck_handle_entry(ent, entry);
 
 exit:
-	ocfs2_filecheck_sysfs_put(ent);
 	return (!ret ? count : ret);
 }
diff --git a/fs/ocfs2/filecheck.h b/fs/ocfs2/filecheck.h
index e5cd002a2c09..6a22ee79e8d0 100644
--- a/fs/ocfs2/filecheck.h
+++ b/fs/ocfs2/filecheck.h
@@ -43,7 +43,32 @@ enum {
 #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
 #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
 
-int ocfs2_filecheck_create_sysfs(struct super_block *sb);
-int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+struct ocfs2_filecheck {
+	struct list_head fc_head;	/* File check entry list head */
+	spinlock_t fc_lock;
+	unsigned int fc_max;	/* Maximum number of entry in list */
+	unsigned int fc_size;	/* Current entry count in list */
+	unsigned int fc_done;	/* Finished entry count in list */
+};
+
+#define OCFS2_FILECHECK_MAXSIZE		100
+#define OCFS2_FILECHECK_MINSIZE		10
+
+/* File check operation type */
+enum {
+	OCFS2_FILECHECK_TYPE_CHK = 0,	/* Check a file(inode) */
+	OCFS2_FILECHECK_TYPE_FIX,	/* Fix a file(inode) */
+	OCFS2_FILECHECK_TYPE_SET = 100	/* Set entry list maximum size */
+};
+
+struct ocfs2_filecheck_sysfs_entry {	/* sysfs entry per partition */
+	struct kobject fs_kobj;
+	struct completion fs_kobj_unregister;
+	struct ocfs2_filecheck *fs_fcheck;
+};
+
+
+int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb);
+void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb);
 
 #endif  /* FILECHECK_H */
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 6867eef2e06b..4f86ac0027b5 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -50,6 +50,8 @@
 
 #include "reservations.h"
 
+#include "filecheck.h"
+
 /* Caching of metadata buffers */
 
 /* Most user visible OCFS2 inodes will have very few pieces of
@@ -472,6 +474,12 @@ struct ocfs2_super
 	 * workqueue and schedule on our own.
 	 */
 	struct workqueue_struct *ocfs2_wq;
+
+	/* sysfs directory per partition */
+	struct kset *osb_dev_kset;
+
+	/* file check related stuff */
+	struct ocfs2_filecheck_sysfs_entry osb_fc_ent;
 };
 
 #define OCFS2_SB(sb)	    ((struct ocfs2_super *)(sb)->s_fs_info)
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index d6c350ba25b9..c4b029c43464 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -48,12 +48,6 @@ static char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl";
  */
 static struct ocfs2_stack_plugin *active_stack;
 
-inline int ocfs2_is_o2cb_active(void)
-{
-	return !strcmp(active_stack->sp_name, OCFS2_STACK_PLUGIN_O2CB);
-}
-EXPORT_SYMBOL_GPL(ocfs2_is_o2cb_active);
-
 static struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name)
 {
 	struct ocfs2_stack_plugin *p;
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h
index e3036e1790e8..f2dce10fae54 100644
--- a/fs/ocfs2/stackglue.h
+++ b/fs/ocfs2/stackglue.h
@@ -298,9 +298,6 @@ void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_p
 int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin);
 void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin);
 
-/* In ocfs2_downconvert_lock(), we need to know which stack we are using */
-int ocfs2_is_o2cb_active(void);
-
 extern struct kset *ocfs2_kset;
 
 #endif  /* STACKGLUE_H */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index ffa4952d432b..342b240aa255 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1161,6 +1161,23 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	ocfs2_complete_mount_recovery(osb);
 
+	osb->osb_dev_kset = kset_create_and_add(sb->s_id, NULL,
+						&ocfs2_kset->kobj);
+	if (!osb->osb_dev_kset) {
+		status = -ENOMEM;
+		mlog(ML_ERROR, "Unable to create device kset %s.\n", sb->s_id);
+		goto read_super_error;
+	}
+
+	/* Create filecheck sysfs related directories/files at
+	 * /sys/fs/ocfs2/<devname>/filecheck */
+	if (ocfs2_filecheck_create_sysfs(osb)) {
+		status = -ENOMEM;
+		mlog(ML_ERROR, "Unable to create filecheck sysfs directory at "
+			"/sys/fs/ocfs2/%s/filecheck.\n", sb->s_id);
+		goto read_super_error;
+	}
+
 	if (ocfs2_mount_local(osb))
 		snprintf(nodestr, sizeof(nodestr), "local");
 	else
@@ -1199,9 +1216,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	/* Start this when the mount is almost sure of being successful */
 	ocfs2_orphan_scan_start(osb);
 
-	/* Create filecheck sysfile /sys/fs/ocfs2/<devname>/filecheck */
-	ocfs2_filecheck_create_sysfs(sb);
-
 	return status;
 
 read_super_error:
@@ -1653,7 +1667,6 @@ static void ocfs2_put_super(struct super_block *sb)
 
 	ocfs2_sync_blockdev(sb);
 	ocfs2_dismount_volume(sb, 0);
-	ocfs2_filecheck_remove_sysfs(sb);
 }
 
 static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -1899,6 +1912,12 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 	osb = OCFS2_SB(sb);
 	BUG_ON(!osb);
 
+	/* Remove file check sysfs related directores/files,
+	 * and wait for the pending file check operations */
+	ocfs2_filecheck_remove_sysfs(osb);
+
+	kset_unregister(osb->osb_dev_kset);
+
 	debugfs_remove(osb->osb_ctxt);
 
 	/* Orphan scan should be stopped as early as possible */
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index bb94ce9da5c8..97a916ea8b86 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -19,6 +19,142 @@
 #include <linux/ratelimit.h>
 #include "overlayfs.h"
 
+static int ovl_encode_maybe_copy_up(struct dentry *dentry)
+{
+	int err;
+
+	if (ovl_dentry_upper(dentry))
+		return 0;
+
+	err = ovl_want_write(dentry);
+	if (!err) {
+		err = ovl_copy_up(dentry);
+		ovl_drop_write(dentry);
+	}
+
+	if (err) {
+		pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n",
+				    dentry, err);
+	}
+
+	return err;
+}
+
+/*
+ * Before encoding a non-upper directory file handle from real layer N, we need
+ * to check if it will be possible to reconnect an overlay dentry from the real
+ * lower decoded dentry. This is done by following the overlay ancestry up to a
+ * "layer N connected" ancestor and verifying that all parents along the way are
+ * "layer N connectable". If an ancestor that is NOT "layer N connectable" is
+ * found, we need to copy up an ancestor, which is "layer N connectable", thus
+ * making that ancestor "layer N connected". For example:
+ *
+ * layer 1: /a
+ * layer 2: /a/b/c
+ *
+ * The overlay dentry /a is NOT "layer 2 connectable", because if dir /a is
+ * copied up and renamed, upper dir /a will be indexed by lower dir /a from
+ * layer 1. The dir /a from layer 2 will never be indexed, so the algorithm (*)
+ * in ovl_lookup_real_ancestor() will not be able to lookup a connected overlay
+ * dentry from the connected lower dentry /a/b/c.
+ *
+ * To avoid this problem on decode time, we need to copy up an ancestor of
+ * /a/b/c, which is "layer 2 connectable", on encode time. That ancestor is
+ * /a/b. After copy up (and index) of /a/b, it will become "layer 2 connected"
+ * and when the time comes to decode the file handle from lower dentry /a/b/c,
+ * ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding
+ * a connected overlay dentry will be accomplished.
+ *
+ * (*) the algorithm in ovl_lookup_real_ancestor() can be improved to lookup an
+ * entry /a in the lower layers above layer N and find the indexed dir /a from
+ * layer 1. If that improvement is made, then the check for "layer N connected"
+ * will need to verify there are no redirects in lower layers above N. In the
+ * example above, /a will be "layer 2 connectable". However, if layer 2 dir /a
+ * is a target of a layer 1 redirect, then /a will NOT be "layer 2 connectable":
+ *
+ * layer 1: /A (redirect = /a)
+ * layer 2: /a/b/c
+ */
+
+/* Return the lowest layer for encoding a connectable file handle */
+static int ovl_connectable_layer(struct dentry *dentry)
+{
+	struct ovl_entry *oe = OVL_E(dentry);
+
+	/* We can get overlay root from root of any layer */
+	if (dentry == dentry->d_sb->s_root)
+		return oe->numlower;
+
+	/*
+	 * If it's an unindexed merge dir, then it's not connectable with any
+	 * lower layer
+	 */
+	if (ovl_dentry_upper(dentry) &&
+	    !ovl_test_flag(OVL_INDEX, d_inode(dentry)))
+		return 0;
+
+	/* We can get upper/overlay path from indexed/lower dentry */
+	return oe->lowerstack[0].layer->idx;
+}
+
+/*
+ * @dentry is "connected" if all ancestors up to root or a "connected" ancestor
+ * have the same uppermost lower layer as the origin's layer. We may need to
+ * copy up a "connectable" ancestor to make it "connected". A "connected" dentry
+ * cannot become non "connected", so cache positive result in dentry flags.
+ *
+ * Return the connected origin layer or < 0 on error.
+ */
+static int ovl_connect_layer(struct dentry *dentry)
+{
+	struct dentry *next, *parent = NULL;
+	int origin_layer;
+	int err = 0;
+
+	if (WARN_ON(dentry == dentry->d_sb->s_root) ||
+	    WARN_ON(!ovl_dentry_lower(dentry)))
+		return -EIO;
+
+	origin_layer = OVL_E(dentry)->lowerstack[0].layer->idx;
+	if (ovl_dentry_test_flag(OVL_E_CONNECTED, dentry))
+		return origin_layer;
+
+	/* Find the topmost origin layer connectable ancestor of @dentry */
+	next = dget(dentry);
+	for (;;) {
+		parent = dget_parent(next);
+		if (WARN_ON(parent == next)) {
+			err = -EIO;
+			break;
+		}
+
+		/*
+		 * If @parent is not origin layer connectable, then copy up
+		 * @next which is origin layer connectable and we are done.
+		 */
+		if (ovl_connectable_layer(parent) < origin_layer) {
+			err = ovl_encode_maybe_copy_up(next);
+			break;
+		}
+
+		/* If @parent is connected or indexed we are done */
+		if (ovl_dentry_test_flag(OVL_E_CONNECTED, parent) ||
+		    ovl_test_flag(OVL_INDEX, d_inode(parent)))
+			break;
+
+		dput(next);
+		next = parent;
+	}
+
+	dput(parent);
+	dput(next);
+
+	if (!err)
+		ovl_dentry_set_flag(OVL_E_CONNECTED, dentry);
+
+	return err ?: origin_layer;
+}
+
 /*
  * We only need to encode origin if there is a chance that the same object was
  * encoded pre copy up and then we need to stay consistent with the same
@@ -41,73 +177,59 @@
  * L = lower file handle
  *
  * (*) Connecting an overlay dir from real lower dentry is not always
- * possible when there are redirects in lower layers. To mitigate this case,
- * we copy up the lower dir first and then encode an upper dir file handle.
+ * possible when there are redirects in lower layers and non-indexed merge dirs.
+ * To mitigate those case, we may copy up the lower dir ancestor before encode
+ * a lower dir file handle.
+ *
+ * Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
  */
-static bool ovl_should_encode_origin(struct dentry *dentry)
+static int ovl_check_encode_origin(struct dentry *dentry)
 {
 	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
 
+	/* Upper file handle for pure upper */
 	if (!ovl_dentry_lower(dentry))
-		return false;
+		return 0;
 
 	/*
-	 * Decoding a merge dir, whose origin's parent is under a redirected
-	 * lower dir is not always possible. As a simple aproximation, we do
-	 * not encode lower dir file handles when overlay has multiple lower
-	 * layers and origin is below the topmost lower layer.
+	 * Upper file handle for non-indexed upper.
 	 *
-	 * TODO: copy up only the parent that is under redirected lower.
+	 * Root is never indexed, so if there's an upper layer, encode upper for
+	 * root.
 	 */
-	if (d_is_dir(dentry) && ofs->upper_mnt &&
-	    OVL_E(dentry)->lowerstack[0].layer->idx > 1)
-		return false;
-
-	/* Decoding a non-indexed upper from origin is not implemented */
 	if (ovl_dentry_upper(dentry) &&
 	    !ovl_test_flag(OVL_INDEX, d_inode(dentry)))
-		return false;
-
-	return true;
-}
-
-static int ovl_encode_maybe_copy_up(struct dentry *dentry)
-{
-	int err;
-
-	if (ovl_dentry_upper(dentry))
 		return 0;
 
-	err = ovl_want_write(dentry);
-	if (err)
-		return err;
-
-	err = ovl_copy_up(dentry);
+	/*
+	 * Decoding a merge dir, whose origin's ancestor is under a redirected
+	 * lower dir or under a non-indexed upper is not always possible.
+	 * ovl_connect_layer() will try to make origin's layer "connected" by
+	 * copying up a "connectable" ancestor.
+	 */
+	if (d_is_dir(dentry) && ofs->upper_mnt)
+		return ovl_connect_layer(dentry);
 
-	ovl_drop_write(dentry);
-	return err;
+	/* Lower file handle for indexed and non-upper dir/non-dir */
+	return 1;
 }
 
 static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
 {
-	struct dentry *origin = ovl_dentry_lower(dentry);
 	struct ovl_fh *fh = NULL;
-	int err;
+	int err, enc_lower;
 
 	/*
-	 * If we should not encode a lower dir file handle, copy up and encode
-	 * an upper dir file handle.
+	 * Check if we should encode a lower or upper file handle and maybe
+	 * copy up an ancestor to make lower file handle connectable.
 	 */
-	if (!ovl_should_encode_origin(dentry)) {
-		err = ovl_encode_maybe_copy_up(dentry);
-		if (err)
-			goto fail;
-
-		origin = NULL;
-	}
+	err = enc_lower = ovl_check_encode_origin(dentry);
+	if (enc_lower < 0)
+		goto fail;
 
-	/* Encode an upper or origin file handle */
-	fh = ovl_encode_fh(origin ?: ovl_dentry_upper(dentry), !origin);
+	/* Encode an upper or lower file handle */
+	fh = ovl_encode_fh(enc_lower ? ovl_dentry_lower(dentry) :
+				       ovl_dentry_upper(dentry), !enc_lower);
 	err = PTR_ERR(fh);
 	if (IS_ERR(fh))
 		goto fail;
@@ -355,8 +477,8 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
 		dput(upper);
 	}
 
-	if (!this)
-		return NULL;
+	if (IS_ERR_OR_NULL(this))
+		return this;
 
 	if (WARN_ON(ovl_dentry_real_at(this, layer->idx) != real)) {
 		dput(this);
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index fcd97b783fa1..3b1bd469accd 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -669,38 +669,59 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real,
 	return inode;
 }
 
+/*
+ * Does overlay inode need to be hashed by lower inode?
+ */
+static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
+			     struct dentry *lower, struct dentry *index)
+{
+	struct ovl_fs *ofs = sb->s_fs_info;
+
+	/* No, if pure upper */
+	if (!lower)
+		return false;
+
+	/* Yes, if already indexed */
+	if (index)
+		return true;
+
+	/* Yes, if won't be copied up */
+	if (!ofs->upper_mnt)
+		return true;
+
+	/* No, if lower hardlink is or will be broken on copy up */
+	if ((upper || !ovl_indexdir(sb)) &&
+	    !d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
+		return false;
+
+	/* No, if non-indexed upper with NFS export */
+	if (sb->s_export_op && upper)
+		return false;
+
+	/* Otherwise, hash by lower inode for fsnotify */
+	return true;
+}
+
 struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
 			    struct dentry *lowerdentry, struct dentry *index,
 			    unsigned int numlower)
 {
-	struct ovl_fs *ofs = sb->s_fs_info;
 	struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
 	struct inode *inode;
-	/* Already indexed or could be indexed on copy up? */
-	bool indexed = (index || (ovl_indexdir(sb) && !upperdentry));
-	struct dentry *origin = indexed ? lowerdentry : NULL;
+	bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index);
 	bool is_dir;
 
-	if (WARN_ON(upperdentry && indexed && !lowerdentry))
-		return ERR_PTR(-EIO);
-
 	if (!realinode)
 		realinode = d_inode(lowerdentry);
 
 	/*
-	 * Copy up origin (lower) may exist for non-indexed non-dir upper, but
-	 * we must not use lower as hash key in that case.
-	 * Hash non-dir that is or could be indexed by origin inode.
-	 * Hash dir that is or could be merged by origin inode.
-	 * Hash pure upper and non-indexed non-dir by upper inode.
-	 * Hash non-indexed dir by upper inode for NFS export.
+	 * Copy up origin (lower) may exist for non-indexed upper, but we must
+	 * not use lower as hash key if this is a broken hardlink.
 	 */
 	is_dir = S_ISDIR(realinode->i_mode);
-	if (is_dir && (indexed || !sb->s_export_op || !ofs->upper_mnt))
-		origin = lowerdentry;
-
-	if (upperdentry || origin) {
-		struct inode *key = d_inode(origin ?: upperdentry);
+	if (upperdentry || bylower) {
+		struct inode *key = d_inode(bylower ? lowerdentry :
+						      upperdentry);
 		unsigned int nlink = is_dir ? 1 : realinode->i_nlink;
 
 		inode = iget5_locked(sb, (unsigned long) key,
@@ -728,6 +749,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
 			nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink);
 		set_nlink(inode, nlink);
 	} else {
+		/* Lower hardlink that will be broken on copy up */
 		inode = new_inode(sb);
 		if (!inode)
 			goto out_nomem;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 0df25a9c94bd..225ff1171147 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -40,6 +40,7 @@ enum ovl_inode_flag {
 enum ovl_entry_flag {
 	OVL_E_UPPER_ALIAS,
 	OVL_E_OPAQUE,
+	OVL_E_CONNECTED,
 };
 
 /*
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 9ee37c76091d..7c24619ae7fc 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1359,6 +1359,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
 	/* Root is always merge -> can have whiteouts */
 	ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry));
+	ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry);
 	ovl_inode_init(d_inode(root_dentry), upperpath.dentry,
 		       ovl_dentry_lower(root_dentry));
 
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 68c06ae7888c..da6f8733c9c5 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -237,6 +237,7 @@ static __net_exit void proc_net_ns_exit(struct net *net)
 static struct pernet_operations __net_initdata proc_net_ns_ops = {
 	.init = proc_net_ns_init,
 	.exit = proc_net_ns_exit,
+	.async = true,
 };
 
 int __init proc_net_init(void)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index ec6d2983a5cb..b66fc8de7d34 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -287,15 +287,18 @@ static void show_vma_header_prefix(struct seq_file *m,
 				   dev_t dev, unsigned long ino)
 {
 	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
-	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
-		   start,
-		   end,
-		   flags & VM_READ ? 'r' : '-',
-		   flags & VM_WRITE ? 'w' : '-',
-		   flags & VM_EXEC ? 'x' : '-',
-		   flags & VM_MAYSHARE ? 's' : 'p',
-		   pgoff,
-		   MAJOR(dev), MINOR(dev), ino);
+	seq_put_hex_ll(m, NULL, start, 8);
+	seq_put_hex_ll(m, "-", end, 8);
+	seq_putc(m, ' ');
+	seq_putc(m, flags & VM_READ ? 'r' : '-');
+	seq_putc(m, flags & VM_WRITE ? 'w' : '-');
+	seq_putc(m, flags & VM_EXEC ? 'x' : '-');
+	seq_putc(m, flags & VM_MAYSHARE ? 's' : 'p');
+	seq_put_hex_ll(m, " ", pgoff, 8);
+	seq_put_hex_ll(m, " ", MAJOR(dev), 2);
+	seq_put_hex_ll(m, ":", MINOR(dev), 2);
+	seq_put_decimal_ull(m, " ", ino);
+	seq_putc(m, ' ');
 }
 
 static void
diff --git a/fs/seq_file.c b/fs/seq_file.c
index eea09f6d8830..f36ab451ade2 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -698,11 +698,6 @@ void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
 	if (m->count + 1 >= m->size)
 		goto overflow;
 
-	if (num < 10) {
-		m->buf[m->count++] = num + '0';
-		return;
-	}
-
 	len = num_to_str(m->buf + m->count, m->size - m->count, num);
 	if (!len)
 		goto overflow;
@@ -715,6 +710,51 @@ void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
 }
 EXPORT_SYMBOL(seq_put_decimal_ull);
 
+/**
+ * seq_put_hex_ll - put a number in hexadecimal notation
+ * @m: seq_file identifying the buffer to which data should be written
+ * @delimiter: a string which is printed before the number
+ * @v: the number
+ * @width: a minimum field width
+ *
+ * seq_put_hex_ll(m, "", v, 8) is equal to seq_printf(m, "0x08llx", v)
+ *
+ * This routine is very quick when you show lots of numbers.
+ * In usual cases, it will be better to use seq_printf(). It's easier to read.
+ */
+void seq_put_hex_ll(struct seq_file *m, const char *delimiter,
+				unsigned long long v, int width)
+{
+	int i, len;
+
+	if (delimiter && delimiter[0]) {
+		if (delimiter[1] == 0)
+			seq_putc(m, delimiter[0]);
+		else
+			seq_puts(m, delimiter);
+	}
+
+	/* If x is 0, the result of __builtin_clzll is undefined */
+	if (v == 0)
+		len = 1;
+	else
+		len = (sizeof(v) * 8 - __builtin_clzll(v) + 3) / 4;
+
+	if (len < width)
+		len = width;
+
+	if (m->count + len > m->size) {
+		seq_set_overflow(m);
+		return;
+	}
+
+	for (i = len - 1; i >= 0; i--) {
+		m->buf[m->count + i] = hex_asc[0xf & v];
+		v = v >> 4;
+	}
+	m->count += len;
+}
+
 void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num)
 {
 	int len;
@@ -737,11 +777,6 @@ void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num
 		num = -num;
 	}
 
-	if (num < 10) {
-		m->buf[m->count++] = num + '0';
-		return;
-	}
-
 	len = num_to_str(m->buf + m->count, m->size - m->count, num);
 	if (!len)
 		goto overflow;
@@ -782,8 +817,14 @@ EXPORT_SYMBOL(seq_write);
 void seq_pad(struct seq_file *m, char c)
 {
 	int size = m->pad_until - m->count;
-	if (size > 0)
-		seq_printf(m, "%*s", size, "");
+	if (size > 0) {
+		if (size + m->count > m->size) {
+			seq_set_overflow(m);
+			return;
+		}
+		memset(m->buf + m->count, ' ', size);
+		m->count += size;
+	}
 	if (c)
 		seq_putc(m, c);
 }
diff --git a/fs/udf/super.c b/fs/udf/super.c
index f73239a9a97d..28ee2ac2503d 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -64,14 +64,13 @@
 #include <linux/init.h>
 #include <linux/uaccess.h>
 
-#define VDS_POS_PRIMARY_VOL_DESC	0
-#define VDS_POS_UNALLOC_SPACE_DESC	1
-#define VDS_POS_LOGICAL_VOL_DESC	2
-#define VDS_POS_PARTITION_DESC		3
-#define VDS_POS_IMP_USE_VOL_DESC	4
-#define VDS_POS_VOL_DESC_PTR		5
-#define VDS_POS_TERMINATING_DESC	6
-#define VDS_POS_LENGTH			7
+enum {
+	VDS_POS_PRIMARY_VOL_DESC,
+	VDS_POS_UNALLOC_SPACE_DESC,
+	VDS_POS_LOGICAL_VOL_DESC,
+	VDS_POS_IMP_USE_VOL_DESC,
+	VDS_POS_LENGTH
+};
 
 #define VSD_FIRST_SECTOR_OFFSET		32768
 #define VSD_MAX_SECTOR_OFFSET		0x800000
@@ -1592,6 +1591,60 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
 	sbi->s_lvid_bh = NULL;
 }
 
+/*
+ * Step for reallocation of table of partition descriptor sequence numbers.
+ * Must be power of 2.
+ */
+#define PART_DESC_ALLOC_STEP 32
+
+struct desc_seq_scan_data {
+	struct udf_vds_record vds[VDS_POS_LENGTH];
+	unsigned int size_part_descs;
+	struct udf_vds_record *part_descs_loc;
+};
+
+static struct udf_vds_record *handle_partition_descriptor(
+				struct buffer_head *bh,
+				struct desc_seq_scan_data *data)
+{
+	struct partitionDesc *desc = (struct partitionDesc *)bh->b_data;
+	int partnum;
+
+	partnum = le16_to_cpu(desc->partitionNumber);
+	if (partnum >= data->size_part_descs) {
+		struct udf_vds_record *new_loc;
+		unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
+
+		new_loc = kzalloc(sizeof(*new_loc) * new_size, GFP_KERNEL);
+		if (!new_loc)
+			return ERR_PTR(-ENOMEM);
+		memcpy(new_loc, data->part_descs_loc,
+		       data->size_part_descs * sizeof(*new_loc));
+		kfree(data->part_descs_loc);
+		data->part_descs_loc = new_loc;
+		data->size_part_descs = new_size;
+	}
+	return &(data->part_descs_loc[partnum]);
+}
+
+
+static struct udf_vds_record *get_volume_descriptor_record(uint16_t ident,
+		struct buffer_head *bh, struct desc_seq_scan_data *data)
+{
+	switch (ident) {
+	case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
+		return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]);
+	case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
+		return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]);
+	case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
+		return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]);
+	case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
+		return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]);
+	case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
+		return handle_partition_descriptor(bh, data);
+	}
+	return NULL;
+}
 
 /*
  * Process a main/reserve volume descriptor sequence.
@@ -1608,18 +1661,23 @@ static noinline int udf_process_sequence(
 		struct kernel_lb_addr *fileset)
 {
 	struct buffer_head *bh = NULL;
-	struct udf_vds_record vds[VDS_POS_LENGTH];
 	struct udf_vds_record *curr;
 	struct generic_desc *gd;
 	struct volDescPtr *vdp;
 	bool done = false;
 	uint32_t vdsn;
 	uint16_t ident;
-	long next_s = 0, next_e = 0;
 	int ret;
 	unsigned int indirections = 0;
-
-	memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
+	struct desc_seq_scan_data data;
+	unsigned int i;
+
+	memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
+	data.size_part_descs = PART_DESC_ALLOC_STEP;
+	data.part_descs_loc = kzalloc(sizeof(*data.part_descs_loc) *
+					data.size_part_descs, GFP_KERNEL);
+	if (!data.part_descs_loc)
+		return -ENOMEM;
 
 	/*
 	 * Read the main descriptor sequence and find which descriptors
@@ -1628,79 +1686,51 @@ static noinline int udf_process_sequence(
 	for (; (!done && block <= lastblock); block++) {
 
 		bh = udf_read_tagged(sb, block, block, &ident);
-		if (!bh) {
-			udf_err(sb,
-				"Block %llu of volume descriptor sequence is corrupted or we could not read it\n",
-				(unsigned long long)block);
-			return -EAGAIN;
-		}
+		if (!bh)
+			break;
 
 		/* Process each descriptor (ISO 13346 3/8.3-8.4) */
 		gd = (struct generic_desc *)bh->b_data;
 		vdsn = le32_to_cpu(gd->volDescSeqNum);
 		switch (ident) {
-		case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
-			curr = &vds[VDS_POS_PRIMARY_VOL_DESC];
-			if (vdsn >= curr->volDescSeqNum) {
-				curr->volDescSeqNum = vdsn;
-				curr->block = block;
-			}
-			break;
 		case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
-			curr = &vds[VDS_POS_VOL_DESC_PTR];
-			if (vdsn >= curr->volDescSeqNum) {
-				curr->volDescSeqNum = vdsn;
-				curr->block = block;
-
-				vdp = (struct volDescPtr *)bh->b_data;
-				next_s = le32_to_cpu(
-					vdp->nextVolDescSeqExt.extLocation);
-				next_e = le32_to_cpu(
-					vdp->nextVolDescSeqExt.extLength);
-				next_e = next_e >> sb->s_blocksize_bits;
-				next_e += next_s;
+			if (++indirections > UDF_MAX_TD_NESTING) {
+				udf_err(sb, "too many Volume Descriptor "
+					"Pointers (max %u supported)\n",
+					UDF_MAX_TD_NESTING);
+				brelse(bh);
+				return -EIO;
 			}
+
+			vdp = (struct volDescPtr *)bh->b_data;
+			block = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
+			lastblock = le32_to_cpu(
+				vdp->nextVolDescSeqExt.extLength) >>
+				sb->s_blocksize_bits;
+			lastblock += block - 1;
+			/* For loop is going to increment 'block' again */
+			block--;
 			break;
+		case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
 		case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
-			curr = &vds[VDS_POS_IMP_USE_VOL_DESC];
-			if (vdsn >= curr->volDescSeqNum) {
-				curr->volDescSeqNum = vdsn;
-				curr->block = block;
-			}
-			break;
-		case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
-			curr = &vds[VDS_POS_PARTITION_DESC];
-			if (!curr->block)
-				curr->block = block;
-			break;
 		case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
-			curr = &vds[VDS_POS_LOGICAL_VOL_DESC];
-			if (vdsn >= curr->volDescSeqNum) {
-				curr->volDescSeqNum = vdsn;
-				curr->block = block;
-			}
-			break;
 		case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
-			curr = &vds[VDS_POS_UNALLOC_SPACE_DESC];
+		case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
+			curr = get_volume_descriptor_record(ident, bh, &data);
+			if (IS_ERR(curr)) {
+				brelse(bh);
+				return PTR_ERR(curr);
+			}
+			/* Descriptor we don't care about? */
+			if (!curr)
+				break;
 			if (vdsn >= curr->volDescSeqNum) {
 				curr->volDescSeqNum = vdsn;
 				curr->block = block;
 			}
 			break;
 		case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
-			if (++indirections > UDF_MAX_TD_NESTING) {
-				udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING);
-				brelse(bh);
-				return -EIO;
-			}
-
-			vds[VDS_POS_TERMINATING_DESC].block = block;
-			if (next_e) {
-				block = next_s;
-				lastblock = next_e;
-				next_s = next_e = 0;
-			} else
-				done = true;
+			done = true;
 			break;
 		}
 		brelse(bh);
@@ -1709,31 +1739,27 @@ static noinline int udf_process_sequence(
 	 * Now read interesting descriptors again and process them
 	 * in a suitable order
 	 */
-	if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) {
+	if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) {
 		udf_err(sb, "Primary Volume Descriptor not found!\n");
 		return -EAGAIN;
 	}
-	ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block);
+	ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block);
 	if (ret < 0)
 		return ret;
 
-	if (vds[VDS_POS_LOGICAL_VOL_DESC].block) {
+	if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) {
 		ret = udf_load_logicalvol(sb,
-					  vds[VDS_POS_LOGICAL_VOL_DESC].block,
-					  fileset);
+				data.vds[VDS_POS_LOGICAL_VOL_DESC].block,
+				fileset);
 		if (ret < 0)
 			return ret;
 	}
 
-	if (vds[VDS_POS_PARTITION_DESC].block) {
-		/*
-		 * We rescan the whole descriptor sequence to find
-		 * partition descriptor blocks and process them.
-		 */
-		for (block = vds[VDS_POS_PARTITION_DESC].block;
-		     block < vds[VDS_POS_TERMINATING_DESC].block;
-		     block++) {
-			ret = udf_load_partdesc(sb, block);
+	/* Now handle prevailing Partition Descriptors */
+	for (i = 0; i < data.size_part_descs; i++) {
+		if (data.part_descs_loc[i].block) {
+			ret = udf_load_partdesc(sb,
+						data.part_descs_loc[i].block);
 			if (ret < 0)
 				return ret;
 		}
@@ -1760,13 +1786,13 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
 	main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
 	main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
 	main_e = main_e >> sb->s_blocksize_bits;
-	main_e += main_s;
+	main_e += main_s - 1;
 
 	/* Locate the reserve sequence */
 	reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
 	reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
 	reserve_e = reserve_e >> sb->s_blocksize_bits;
-	reserve_e += reserve_s;
+	reserve_e += reserve_s - 1;
 
 	/* Process the main & reserve sequences */
 	/* responsible for finding the PartitionDesc(s) */
diff --git a/include/asm-generic/5level-fixup.h b/include/asm-generic/5level-fixup.h
index dfbd9d990637..9c2e0708eb82 100644
--- a/include/asm-generic/5level-fixup.h
+++ b/include/asm-generic/5level-fixup.h
@@ -8,6 +8,7 @@
 #define P4D_SHIFT			PGDIR_SHIFT
 #define P4D_SIZE			PGDIR_SIZE
 #define P4D_MASK			PGDIR_MASK
+#define MAX_PTRS_PER_P4D		1
 #define PTRS_PER_P4D			1
 
 #define p4d_t				pgd_t
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 963b755d19b0..a7613e1b0c87 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -52,6 +52,7 @@ struct bug_entry {
 #ifndef HAVE_ARCH_BUG
 #define BUG() do { \
 	printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+	barrier_before_unreachable(); \
 	panic("BUG!"); \
 } while (0)
 #endif
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index 8f22f55de17a..1a29b2a0282b 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -8,10 +8,11 @@
 
 typedef struct { pgd_t pgd; } p4d_t;
 
-#define P4D_SHIFT	PGDIR_SHIFT
-#define PTRS_PER_P4D	1
-#define P4D_SIZE	(1UL << P4D_SHIFT)
-#define P4D_MASK	(~(P4D_SIZE-1))
+#define P4D_SHIFT		PGDIR_SHIFT
+#define MAX_PTRS_PER_P4D	1
+#define PTRS_PER_P4D		1
+#define P4D_SIZE		(1UL << P4D_SHIFT)
+#define P4D_MASK		(~(P4D_SIZE-1))
 
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
diff --git a/include/crypto/engine.h b/include/crypto/engine.h
index dd04c1699b51..1cbec29af3d6 100644
--- a/include/crypto/engine.h
+++ b/include/crypto/engine.h
@@ -17,7 +17,10 @@
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/akcipher.h>
 #include <crypto/hash.h>
+#include <crypto/skcipher.h>
 
 #define ENGINE_NAME_LEN	30
 /*
@@ -37,12 +40,6 @@
  * @unprepare_crypt_hardware: there are currently no more requests on the
  * queue so the subsystem notifies the driver that it may relax the
  * hardware by issuing this call
- * @prepare_cipher_request: do some prepare if need before handle the current request
- * @unprepare_cipher_request: undo any work done by prepare_cipher_request()
- * @cipher_one_request: do encryption for current request
- * @prepare_hash_request: do some prepare if need before handle the current request
- * @unprepare_hash_request: undo any work done by prepare_hash_request()
- * @hash_one_request: do hash for current request
  * @kworker: kthread worker struct for request pump
  * @pump_requests: work struct for scheduling work to the request pump
  * @priv_data: the engine private data
@@ -65,19 +62,6 @@ struct crypto_engine {
 	int (*prepare_crypt_hardware)(struct crypto_engine *engine);
 	int (*unprepare_crypt_hardware)(struct crypto_engine *engine);
 
-	int (*prepare_cipher_request)(struct crypto_engine *engine,
-				      struct ablkcipher_request *req);
-	int (*unprepare_cipher_request)(struct crypto_engine *engine,
-					struct ablkcipher_request *req);
-	int (*prepare_hash_request)(struct crypto_engine *engine,
-				    struct ahash_request *req);
-	int (*unprepare_hash_request)(struct crypto_engine *engine,
-				      struct ahash_request *req);
-	int (*cipher_one_request)(struct crypto_engine *engine,
-				  struct ablkcipher_request *req);
-	int (*hash_one_request)(struct crypto_engine *engine,
-				struct ahash_request *req);
-
 	struct kthread_worker           *kworker;
 	struct kthread_work             pump_requests;
 
@@ -85,19 +69,45 @@ struct crypto_engine {
 	struct crypto_async_request	*cur_req;
 };
 
-int crypto_transfer_cipher_request(struct crypto_engine *engine,
-				   struct ablkcipher_request *req,
-				   bool need_pump);
-int crypto_transfer_cipher_request_to_engine(struct crypto_engine *engine,
-					     struct ablkcipher_request *req);
-int crypto_transfer_hash_request(struct crypto_engine *engine,
-				 struct ahash_request *req, bool need_pump);
+/*
+ * struct crypto_engine_op - crypto hardware engine operations
+ * @prepare__request: do some prepare if need before handle the current request
+ * @unprepare_request: undo any work done by prepare_request()
+ * @do_one_request: do encryption for current request
+ */
+struct crypto_engine_op {
+	int (*prepare_request)(struct crypto_engine *engine,
+			       void *areq);
+	int (*unprepare_request)(struct crypto_engine *engine,
+				 void *areq);
+	int (*do_one_request)(struct crypto_engine *engine,
+			      void *areq);
+};
+
+struct crypto_engine_ctx {
+	struct crypto_engine_op op;
+};
+
+int crypto_transfer_ablkcipher_request_to_engine(struct crypto_engine *engine,
+						 struct ablkcipher_request *req);
+int crypto_transfer_aead_request_to_engine(struct crypto_engine *engine,
+					   struct aead_request *req);
+int crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine,
+					       struct akcipher_request *req);
 int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine,
-					   struct ahash_request *req);
-void crypto_finalize_cipher_request(struct crypto_engine *engine,
-				    struct ablkcipher_request *req, int err);
+					       struct ahash_request *req);
+int crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine,
+					       struct skcipher_request *req);
+void crypto_finalize_ablkcipher_request(struct crypto_engine *engine,
+					struct ablkcipher_request *req, int err);
+void crypto_finalize_aead_request(struct crypto_engine *engine,
+				  struct aead_request *req, int err);
+void crypto_finalize_akcipher_request(struct crypto_engine *engine,
+				      struct akcipher_request *req, int err);
 void crypto_finalize_hash_request(struct crypto_engine *engine,
 				  struct ahash_request *req, int err);
+void crypto_finalize_skcipher_request(struct crypto_engine *engine,
+				      struct skcipher_request *req, int err);
 int crypto_engine_start(struct crypto_engine *engine);
 int crypto_engine_stop(struct crypto_engine *engine);
 struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt);
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 27040a46d50a..a0b0ad9d585e 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -126,11 +126,6 @@ int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc);
 int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc);
 int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc);
 
-int ahash_mcryptd_update(struct ahash_request *desc);
-int ahash_mcryptd_final(struct ahash_request *desc);
-int ahash_mcryptd_finup(struct ahash_request *desc);
-int ahash_mcryptd_digest(struct ahash_request *desc);
-
 int crypto_init_shash_ops_async(struct crypto_tfm *tfm);
 
 static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h
index 9b30fec302c8..d9c6d549f971 100644
--- a/include/drm/bridge/dw_mipi_dsi.h
+++ b/include/drm/bridge/dw_mipi_dsi.h
@@ -10,6 +10,8 @@
 #ifndef __DW_MIPI_DSI__
 #define __DW_MIPI_DSI__
 
+struct dw_mipi_dsi;
+
 struct dw_mipi_dsi_phy_ops {
 	int (*init)(void *priv_data);
 	int (*get_lane_mbps)(void *priv_data, struct drm_display_mode *mode,
@@ -29,11 +31,14 @@ struct dw_mipi_dsi_plat_data {
 	void *priv_data;
 };
 
-int dw_mipi_dsi_probe(struct platform_device *pdev,
-		      const struct dw_mipi_dsi_plat_data *plat_data);
-void dw_mipi_dsi_remove(struct platform_device *pdev);
-int dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-		     const struct dw_mipi_dsi_plat_data *plat_data);
-void dw_mipi_dsi_unbind(struct device *dev);
+struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev,
+				      const struct dw_mipi_dsi_plat_data
+				      *plat_data);
+void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi);
+struct dw_mipi_dsi *dw_mipi_dsi_bind(struct platform_device *pdev,
+				     struct drm_encoder *encoder,
+				     const struct dw_mipi_dsi_plat_data
+				     *plat_data);
+void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi);
 
 #endif /* __DW_MIPI_DSI__ */
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 1c27526c499e..2c711a24c80c 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -134,6 +134,15 @@ struct drm_crtc_commit {
 	 * &drm_pending_vblank_event pointer to clean up private events.
 	 */
 	struct drm_pending_vblank_event *event;
+
+	/**
+	 * @abort_completion:
+	 *
+	 * A flag that's set after drm_atomic_helper_setup_commit takes a second
+	 * reference for the completion of $drm_crtc_state.event. It's used by
+	 * the free code to remove the second reference if commit fails.
+	 */
+	bool abort_completion;
 };
 
 struct __drm_planes_state {
@@ -145,7 +154,7 @@ struct __drm_crtcs_state {
 	struct drm_crtc *ptr;
 	struct drm_crtc_state *state, *old_state, *new_state;
 	s32 __user *out_fence_ptr;
-	unsigned last_vblank_count;
+	u64 last_vblank_count;
 };
 
 struct __drm_connnectors_state {
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 682d01ba920c..3270fec46979 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -29,6 +29,7 @@
 #include <drm/drm_modes.h>
 
 struct drm_bridge;
+struct drm_bridge_timings;
 struct drm_panel;
 
 /**
@@ -90,7 +91,7 @@ struct drm_bridge_funcs {
 	 *
 	 * drm_mode_status Enum
 	 */
-	enum drm_mode_status (*mode_valid)(struct drm_bridge *crtc,
+	enum drm_mode_status (*mode_valid)(struct drm_bridge *bridge,
 					   const struct drm_display_mode *mode);
 
 	/**
@@ -222,6 +223,35 @@ struct drm_bridge_funcs {
 	void (*enable)(struct drm_bridge *bridge);
 };
 
+/**
+ * struct drm_bridge_timings - timing information for the bridge
+ */
+struct drm_bridge_timings {
+	/**
+	 * @sampling_edge:
+	 *
+	 * Tells whether the bridge samples the digital input signal
+	 * from the display engine on the positive or negative edge of the
+	 * clock, this should reuse the DRM_BUS_FLAG_PIXDATA_[POS|NEG]EDGE
+	 * bitwise flags from the DRM connector (bit 2 and 3 valid).
+	 */
+	u32 sampling_edge;
+	/**
+	 * @setup_time_ps:
+	 *
+	 * Defines the time in picoseconds the input data lines must be
+	 * stable before the clock edge.
+	 */
+	u32 setup_time_ps;
+	/**
+	 * @hold_time_ps:
+	 *
+	 * Defines the time in picoseconds taken for the bridge to sample the
+	 * input signal after the clock edge.
+	 */
+	u32 hold_time_ps;
+};
+
 /**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
@@ -229,6 +259,8 @@ struct drm_bridge_funcs {
  * @next: the next bridge in the encoder chain
  * @of_node: device node pointer to the bridge
  * @list: to keep track of all added bridges
+ * @timings: the timing specification for the bridge, if any (may
+ * be NULL)
  * @funcs: control functions
  * @driver_private: pointer to the bridge driver's internal context
  */
@@ -240,6 +272,7 @@ struct drm_bridge {
 	struct device_node *of_node;
 #endif
 	struct list_head list;
+	const struct drm_bridge_timings *timings;
 
 	const struct drm_bridge_funcs *funcs;
 	void *driver_private;
diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h
index beab0f0d0cfb..bfe1639df02d 100644
--- a/include/drm/drm_cache.h
+++ b/include/drm/drm_cache.h
@@ -38,6 +38,8 @@
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
 void drm_clflush_sg(struct sg_table *st);
 void drm_clflush_virt_range(void *addr, unsigned long length);
+u64 drm_get_max_iomem(void);
+
 
 static inline bool drm_arch_can_wc_memory(void)
 {
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ed38df4ac204..758a176e7b57 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -419,6 +419,12 @@ struct drm_connector_state {
 	 * upscaling, mostly used for built-in panels.
 	 */
 	unsigned int scaling_mode;
+
+	/**
+	 * @content_protection: Connector property to request content
+	 * protection. This is most commonly used for HDCP.
+	 */
+	unsigned int content_protection;
 };
 
 /**
@@ -766,6 +772,7 @@ struct drm_cmdline_mode {
  * @tile_h_size: horizontal size of this tile.
  * @tile_v_size: vertical size of this tile.
  * @scaling_mode_property:  Optional atomic property to control the upscaling.
+ * @content_protection_property: Optional property to control content protection
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -856,6 +863,12 @@ struct drm_connector {
 
 	struct drm_property *scaling_mode_property;
 
+	/**
+	 * @content_protection_property: DRM ENUM property for content
+	 * protection
+	 */
+	struct drm_property *content_protection_property;
+
 	/**
 	 * @path_blob_ptr:
 	 *
@@ -1065,6 +1078,7 @@ const char *drm_get_dvi_i_subconnector_name(int val);
 const char *drm_get_dvi_i_select_name(int val);
 const char *drm_get_tv_subconnector_name(int val);
 const char *drm_get_tv_select_name(int val);
+const char *drm_get_content_protection_name(int val);
 
 int drm_mode_create_dvi_i_properties(struct drm_device *dev);
 int drm_mode_create_tv_properties(struct drm_device *dev,
@@ -1073,6 +1087,8 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
 int drm_mode_create_scaling_mode_property(struct drm_device *dev);
 int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
 					       u32 scaling_mode_mask);
+int drm_connector_attach_content_protection_property(
+		struct drm_connector *connector);
 int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
 int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
 
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 76e237bd989b..6914633037a5 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -77,5 +77,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev);
 
 void drm_kms_helper_poll_disable(struct drm_device *dev);
 void drm_kms_helper_poll_enable(struct drm_device *dev);
+bool drm_kms_helper_is_poll_worker(void);
 
 #endif
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index da58a428c8d7..c239e6e24a10 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -75,6 +75,7 @@
 #define DP_MAX_DOWNSPREAD                   0x003
 # define DP_MAX_DOWNSPREAD_0_5		    (1 << 0)
 # define DP_NO_AUX_HANDSHAKE_LINK_TRAINING  (1 << 6)
+# define DP_TPS4_SUPPORTED                  (1 << 7)
 
 #define DP_NORP                             0x004
 
@@ -334,6 +335,7 @@
 # define DP_LINK_BW_1_62		    0x06
 # define DP_LINK_BW_2_7			    0x0a
 # define DP_LINK_BW_5_4			    0x14    /* 1.2 */
+# define DP_LINK_BW_8_1			    0x1e    /* 1.4 */
 
 #define DP_LANE_COUNT_SET	            0x101
 # define DP_LANE_COUNT_MASK		    0x0f
@@ -344,7 +346,9 @@
 # define DP_TRAINING_PATTERN_1		    1
 # define DP_TRAINING_PATTERN_2		    2
 # define DP_TRAINING_PATTERN_3		    3	    /* 1.2 */
+# define DP_TRAINING_PATTERN_4              7       /* 1.4 */
 # define DP_TRAINING_PATTERN_MASK	    0x3
+# define DP_TRAINING_PATTERN_MASK_1_4	    0xf
 
 /* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */
 # define DP_LINK_QUAL_PATTERN_11_DISABLE    (0 << 2)
@@ -836,6 +840,23 @@
 #define DP_CEC_TX_MESSAGE_BUFFER               0x3020
 #define DP_CEC_MESSAGE_BUFFER_LENGTH             0x10
 
+#define DP_AUX_HDCP_BKSV		0x68000
+#define DP_AUX_HDCP_RI_PRIME		0x68005
+#define DP_AUX_HDCP_AKSV		0x68007
+#define DP_AUX_HDCP_AN			0x6800C
+#define DP_AUX_HDCP_V_PRIME(h)		(0x68014 + h * 4)
+#define DP_AUX_HDCP_BCAPS		0x68028
+# define DP_BCAPS_REPEATER_PRESENT	BIT(1)
+# define DP_BCAPS_HDCP_CAPABLE		BIT(0)
+#define DP_AUX_HDCP_BSTATUS		0x68029
+# define DP_BSTATUS_REAUTH_REQ		BIT(3)
+# define DP_BSTATUS_LINK_FAILURE	BIT(2)
+# define DP_BSTATUS_R0_PRIME_READY	BIT(1)
+# define DP_BSTATUS_READY		BIT(0)
+#define DP_AUX_HDCP_BINFO		0x6802A
+#define DP_AUX_HDCP_KSV_FIFO		0x6802C
+#define DP_AUX_HDCP_AINFO		0x6803B
+
 /* DP 1.2 Sideband message defines */
 /* peer device type - DP 1.2a Table 2-92 */
 #define DP_PEER_DEVICE_NONE		0x0
@@ -970,6 +991,20 @@ drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
 		dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED;
 }
 
+static inline bool
+drm_dp_tps4_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
+{
+	return dpcd[DP_DPCD_REV] >= 0x14 &&
+		dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED;
+}
+
+static inline u8
+drm_dp_training_pattern_mask(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
+{
+	return (dpcd[DP_DPCD_REV] >= 0x14) ? DP_TRAINING_PATTERN_MASK_1_4 :
+		DP_TRAINING_PATTERN_MASK;
+}
+
 static inline bool
 drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
 {
diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index 6942e84b6edd..3e86408dac9f 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -38,6 +38,7 @@ struct drm_mode_fb_cmd2;
  * @cpp: Number of bytes per pixel (per plane)
  * @hsub: Horizontal chroma subsampling factor
  * @vsub: Vertical chroma subsampling factor
+ * @has_alpha: Does the format embeds an alpha component?
  */
 struct drm_format_info {
 	u32 format;
@@ -46,6 +47,7 @@ struct drm_format_info {
 	u8 cpp[3];
 	u8 hsub;
 	u8 vsub;
+	bool has_alpha;
 };
 
 /**
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 9c55c2acaa2b..3583b98a1718 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -115,21 +115,6 @@ struct drm_gem_object {
 	 */
 	int name;
 
-	/**
-	 * @read_domains:
-	 *
-	 * Read memory domains. These monitor which caches contain read/write data
-	 * related to the object. When transitioning from one set of domains
-	 * to another, the driver is called to ensure that caches are suitably
-	 * flushed and invalidated.
-	 */
-	uint32_t read_domains;
-
-	/**
-	 * @write_domain: Corresponding unique write memory domain.
-	 */
-	uint32_t write_domain;
-
 	/**
 	 * @dma_buf:
 	 *
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h
new file mode 100644
index 000000000000..562fa7df2637
--- /dev/null
+++ b/include/drm/drm_hdcp.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * Authors:
+ * Sean Paul <seanpaul@chromium.org>
+ */
+
+#ifndef _DRM_HDCP_H_INCLUDED_
+#define _DRM_HDCP_H_INCLUDED_
+
+/* Period of hdcp checks (to ensure we're still authenticated) */
+#define DRM_HDCP_CHECK_PERIOD_MS		(128 * 16)
+
+/* Shared lengths/masks between HDMI/DVI/DisplayPort */
+#define DRM_HDCP_AN_LEN				8
+#define DRM_HDCP_BSTATUS_LEN			2
+#define DRM_HDCP_KSV_LEN			5
+#define DRM_HDCP_RI_LEN				2
+#define DRM_HDCP_V_PRIME_PART_LEN		4
+#define DRM_HDCP_V_PRIME_NUM_PARTS		5
+#define DRM_HDCP_NUM_DOWNSTREAM(x)		(x & 0x3f)
+#define DRM_HDCP_MAX_CASCADE_EXCEEDED(x)	(x & BIT(3))
+#define DRM_HDCP_MAX_DEVICE_EXCEEDED(x)		(x & BIT(7))
+
+/* Slave address for the HDCP registers in the receiver */
+#define DRM_HDCP_DDC_ADDR			0x3A
+
+/* HDCP register offsets for HDMI/DVI devices */
+#define DRM_HDCP_DDC_BKSV			0x00
+#define DRM_HDCP_DDC_RI_PRIME			0x08
+#define DRM_HDCP_DDC_AKSV			0x10
+#define DRM_HDCP_DDC_AN				0x18
+#define DRM_HDCP_DDC_V_PRIME(h)			(0x20 + h * 4)
+#define DRM_HDCP_DDC_BCAPS			0x40
+#define  DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT	BIT(6)
+#define  DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY	BIT(5)
+#define DRM_HDCP_DDC_BSTATUS			0x41
+#define DRM_HDCP_DDC_KSV_FIFO			0x43
+
+#endif
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 2cb6f02df64a..7569f22ffef6 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -36,6 +36,7 @@ struct drm_device;
 struct drm_atomic_state;
 struct drm_mode_fb_cmd2;
 struct drm_format_info;
+struct drm_display_mode;
 
 /**
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
@@ -101,6 +102,17 @@ struct drm_mode_config_funcs {
 	 */
 	void (*output_poll_changed)(struct drm_device *dev);
 
+	/**
+	 * @mode_valid:
+	 *
+	 * Device specific validation of display modes. Can be used to reject
+	 * modes that can never be supported. Only device wide constraints can
+	 * be checked here. crtc/encoder/bridge/connector specific constraints
+	 * should be checked in the .mode_valid() hook for each specific object.
+	 */
+	enum drm_mode_status (*mode_valid)(struct drm_device *dev,
+					   const struct drm_display_mode *mode);
+
 	/**
 	 * @atomic_check:
 	 *
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 9f3421c8efcd..0d310beae6af 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -131,9 +131,6 @@ enum drm_mode_status {
 	MODE_ERROR = -1
 };
 
-#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
-				    DRM_MODE_TYPE_CRTC_C)
-
 #define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
 	.name = nm, .status = 0, .type = (t), .clock = (c), \
 	.hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
@@ -245,26 +242,25 @@ struct drm_display_mode {
 	 * A bitmask of flags, mostly about the source of a mode. Possible flags
 	 * are:
 	 *
-	 *  - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, effectively
-	 *    unused.
 	 *  - DRM_MODE_TYPE_PREFERRED: Preferred mode, usually the native
 	 *    resolution of an LCD panel. There should only be one preferred
 	 *    mode per connector at any given time.
 	 *  - DRM_MODE_TYPE_DRIVER: Mode created by the driver, which is all of
 	 *    them really. Drivers must set this bit for all modes they create
 	 *    and expose to userspace.
+	 *  - DRM_MODE_TYPE_USERDEF: Mode defined via kernel command line
 	 *
 	 * Plus a big list of flags which shouldn't be used at all, but are
-	 * still around since these flags are also used in the userspace ABI:
+	 * still around since these flags are also used in the userspace ABI.
+	 * We no longer accept modes with these types though:
 	 *
+	 *  - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, unused.
+	 *    Use DRM_MODE_TYPE_DRIVER instead.
 	 *  - DRM_MODE_TYPE_DEFAULT: Again a leftover, use
 	 *    DRM_MODE_TYPE_PREFERRED instead.
 	 *  - DRM_MODE_TYPE_CLOCK_C and DRM_MODE_TYPE_CRTC_C: Define leftovers
 	 *    which are stuck around for hysterical raisins only. No one has an
 	 *    idea what they were meant for. Don't use.
-	 *  - DRM_MODE_TYPE_USERDEF: Mode defined by userspace, again a vestige
-	 *    from older kms designs where userspace had to first add a custom
-	 *    mode to the kernel's mode list before it could use it. Don't use.
 	 */
 	unsigned int type;
 
@@ -299,8 +295,8 @@ struct drm_display_mode {
 	 *  - DRM_MODE_FLAG_PCSYNC: composite sync is active high.
 	 *  - DRM_MODE_FLAG_NCSYNC: composite sync is active low.
 	 *  - DRM_MODE_FLAG_HSKEW: hskew provided (not used?).
-	 *  - DRM_MODE_FLAG_BCAST: not used?
-	 *  - DRM_MODE_FLAG_PIXMUX: not used?
+	 *  - DRM_MODE_FLAG_BCAST: <deprecated>
+	 *  - DRM_MODE_FLAG_PIXMUX: <deprecated>
 	 *  - DRM_MODE_FLAG_DBLCLK: double-clocked mode.
 	 *  - DRM_MODE_FLAG_CLKDIV2: half-clocked mode.
 	 *
@@ -448,7 +444,8 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev);
 void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
 void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
 			       const struct drm_display_mode *in);
-int drm_mode_convert_umode(struct drm_display_mode *out,
+int drm_mode_convert_umode(struct drm_device *dev,
+			   struct drm_display_mode *out,
 			   const struct drm_mode_modeinfo *in);
 void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
 void drm_mode_debug_printmodeline(const struct drm_display_mode *mode);
@@ -501,7 +498,8 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
 					const struct drm_display_mode *mode2);
 
 /* for use by the crtc helper probe functions */
-enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode);
+enum drm_mode_status drm_mode_validate_driver(struct drm_device *dev,
+					      const struct drm_display_mode *mode);
 enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode,
 					    int maxX, int maxY);
 enum drm_mode_status
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
index 9cd9e36f77b5..4d5f5d6cf6a6 100644
--- a/include/drm/drm_prime.h
+++ b/include/drm/drm_prime.h
@@ -54,6 +54,9 @@ struct device;
 
 struct dma_buf_export_info;
 struct dma_buf;
+struct dma_buf_attachment;
+
+enum dma_data_direction;
 
 struct drm_device;
 struct drm_gem_object;
@@ -79,6 +82,25 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
 struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
 				      struct dma_buf_export_info *exp_info);
 void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
+int drm_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev,
+		       struct dma_buf_attachment *attach);
+void drm_gem_map_detach(struct dma_buf *dma_buf,
+			struct dma_buf_attachment *attach);
+struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
+				     enum dma_data_direction dir);
+void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
+			   struct sg_table *sgt,
+			   enum dma_data_direction dir);
+void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf);
+void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr);
+void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
+				 unsigned long page_num);
+void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
+				  unsigned long page_num, void *addr);
+void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num);
+void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num,
+			   void *addr);
+int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma);
 
 int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
 				     dma_addr_t *addrs, int max_pages);
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 848b463a0af5..16d46e2a6854 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -179,7 +179,9 @@ void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
 void drm_crtc_vblank_off(struct drm_crtc *crtc);
 void drm_crtc_vblank_reset(struct drm_crtc *crtc);
 void drm_crtc_vblank_on(struct drm_crtc *crtc);
-u32 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
+u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc);
+void drm_vblank_restore(struct drm_device *dev, unsigned int pipe);
+void drm_crtc_vblank_restore(struct drm_crtc *crtc);
 
 bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
 					   unsigned int pipe, int *max_error,
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index 545c6e0fea7d..346b1f5cb180 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -26,9 +26,8 @@
 
 /* MAX_PORT is the number of port
  * It must be sync with I915_MAX_PORTS defined i915_drv.h
- * 5 should be enough as only HSW, BDW, SKL need such fix.
  */
-#define MAX_PORTS 5
+#define MAX_PORTS 6
 
 /**
  * struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver
diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h
index 5db0458dd832..0b2ba46fa00b 100644
--- a/include/drm/i915_pciids.h
+++ b/include/drm/i915_pciids.h
@@ -414,24 +414,21 @@
 	INTEL_CFL_U_GT2_IDS(info), \
 	INTEL_CFL_U_GT3_IDS(info)
 
-/* CNL U 2+2 */
-#define INTEL_CNL_U_GT2_IDS(info) \
-	INTEL_VGA_DEVICE(0x5A52, info), \
-	INTEL_VGA_DEVICE(0x5A5A, info), \
-	INTEL_VGA_DEVICE(0x5A42, info), \
-	INTEL_VGA_DEVICE(0x5A4A, info)
-
-/* CNL Y 2+2 */
-#define INTEL_CNL_Y_GT2_IDS(info) \
+/* CNL */
+#define INTEL_CNL_IDS(info) \
 	INTEL_VGA_DEVICE(0x5A51, info), \
 	INTEL_VGA_DEVICE(0x5A59, info), \
 	INTEL_VGA_DEVICE(0x5A41, info), \
 	INTEL_VGA_DEVICE(0x5A49, info), \
-	INTEL_VGA_DEVICE(0x5A71, info), \
-	INTEL_VGA_DEVICE(0x5A79, info)
-
-#define INTEL_CNL_IDS(info) \
-	INTEL_CNL_U_GT2_IDS(info), \
-	INTEL_CNL_Y_GT2_IDS(info)
+	INTEL_VGA_DEVICE(0x5A52, info), \
+	INTEL_VGA_DEVICE(0x5A5A, info), \
+	INTEL_VGA_DEVICE(0x5A42, info), \
+	INTEL_VGA_DEVICE(0x5A4A, info), \
+	INTEL_VGA_DEVICE(0x5A50, info), \
+	INTEL_VGA_DEVICE(0x5A40, info), \
+	INTEL_VGA_DEVICE(0x5A54, info), \
+	INTEL_VGA_DEVICE(0x5A5C, info), \
+	INTEL_VGA_DEVICE(0x5A44, info), \
+	INTEL_VGA_DEVICE(0x5A4C, info)
 
 #endif /* _I915_PCIIDS_H */
diff --git a/include/drm/tinydrm/ili9341.h b/include/drm/tinydrm/ili9341.h
deleted file mode 100644
index 807a09f43cad..000000000000
--- a/include/drm/tinydrm/ili9341.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * ILI9341 LCD controller
- *
- * Copyright 2016 Noralf Trønnes
- *
- * 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 __LINUX_ILI9341_H
-#define __LINUX_ILI9341_H
-
-#define ILI9341_FRMCTR1    0xb1
-#define ILI9341_FRMCTR2    0xb2
-#define ILI9341_FRMCTR3    0xb3
-#define ILI9341_INVTR      0xb4
-#define ILI9341_PRCTR      0xb5
-#define ILI9341_DISCTRL    0xb6
-#define ILI9341_ETMOD      0xb7
-
-#define ILI9341_PWCTRL1    0xc0
-#define ILI9341_PWCTRL2    0xc1
-#define ILI9341_VMCTRL1    0xc5
-#define ILI9341_VMCTRL2    0xc7
-#define ILI9341_PWCTRLA    0xcb
-#define ILI9341_PWCTRLB    0xcf
-
-#define ILI9341_RDID1      0xda
-#define ILI9341_RDID2      0xdb
-#define ILI9341_RDID3      0xdc
-#define ILI9341_RDID4      0xd3
-
-#define ILI9341_PGAMCTRL   0xe0
-#define ILI9341_NGAMCTRL   0xe1
-#define ILI9341_DGAMCTRL1  0xe2
-#define ILI9341_DGAMCTRL2  0xe3
-#define ILI9341_DTCTRLA    0xe8
-#define ILI9341_DTCTRLB    0xea
-#define ILI9341_PWRSEQ     0xed
-
-#define ILI9341_EN3GAM     0xf2
-#define ILI9341_IFCTRL     0xf6
-#define ILI9341_PUMPCTRL   0xf7
-
-#define ILI9341_MADCTL_MH  BIT(2)
-#define ILI9341_MADCTL_BGR BIT(3)
-#define ILI9341_MADCTL_ML  BIT(4)
-#define ILI9341_MADCTL_MV  BIT(5)
-#define ILI9341_MADCTL_MX  BIT(6)
-#define ILI9341_MADCTL_MY  BIT(7)
-
-#endif /* __LINUX_ILI9341_H */
diff --git a/include/drm/tinydrm/mipi-dbi.h b/include/drm/tinydrm/mipi-dbi.h
index 5d0e82b36eaf..44e824af2ef6 100644
--- a/include/drm/tinydrm/mipi-dbi.h
+++ b/include/drm/tinydrm/mipi-dbi.h
@@ -67,11 +67,12 @@ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
 		  const struct drm_simple_display_pipe_funcs *pipe_funcs,
 		  struct drm_driver *driver,
 		  const struct drm_display_mode *mode, unsigned int rotation);
-void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe,
-			  struct drm_crtc_state *crtc_state);
+void mipi_dbi_enable_flush(struct mipi_dbi *mipi);
 void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe);
 void mipi_dbi_hw_reset(struct mipi_dbi *mipi);
 bool mipi_dbi_display_is_on(struct mipi_dbi *mipi);
+int mipi_dbi_poweron_reset(struct mipi_dbi *mipi);
+int mipi_dbi_poweron_conditional_reset(struct mipi_dbi *mipi);
 u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len);
 
 int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val);
diff --git a/include/dt-bindings/clock/rk3328-cru.h b/include/dt-bindings/clock/rk3328-cru.h
index d2b26a4b43eb..a82a0109faff 100644
--- a/include/dt-bindings/clock/rk3328-cru.h
+++ b/include/dt-bindings/clock/rk3328-cru.h
@@ -193,7 +193,6 @@
 #define HCLK_VPU_PRE		324
 #define HCLK_VIO_PRE		325
 #define HCLK_VPU		326
-#define HCLK_VIO		327
 #define HCLK_BUS_PRE		328
 #define HCLK_PERI_PRE		329
 #define HCLK_H264		330
diff --git a/include/dt-bindings/net/ti-dp83867.h b/include/dt-bindings/net/ti-dp83867.h
index 172744a72eb7..7b1656427cbe 100644
--- a/include/dt-bindings/net/ti-dp83867.h
+++ b/include/dt-bindings/net/ti-dp83867.h
@@ -42,4 +42,18 @@
 #define	DP83867_RGMIIDCTL_3_75_NS	0xe
 #define	DP83867_RGMIIDCTL_4_00_NS	0xf
 
+/* IO_MUX_CFG - Clock output selection */
+#define DP83867_CLK_O_SEL_CHN_A_RCLK		0x0
+#define DP83867_CLK_O_SEL_CHN_B_RCLK		0x1
+#define DP83867_CLK_O_SEL_CHN_C_RCLK		0x2
+#define DP83867_CLK_O_SEL_CHN_D_RCLK		0x3
+#define DP83867_CLK_O_SEL_CHN_A_RCLK_DIV5	0x4
+#define DP83867_CLK_O_SEL_CHN_B_RCLK_DIV5	0x5
+#define DP83867_CLK_O_SEL_CHN_C_RCLK_DIV5	0x6
+#define DP83867_CLK_O_SEL_CHN_D_RCLK_DIV5	0x7
+#define DP83867_CLK_O_SEL_CHN_A_TCLK		0x8
+#define DP83867_CLK_O_SEL_CHN_B_TCLK		0x9
+#define DP83867_CLK_O_SEL_CHN_C_TCLK		0xA
+#define DP83867_CLK_O_SEL_CHN_D_TCLK		0xB
+#define DP83867_CLK_O_SEL_REF_CLK		0xC
 #endif
diff --git a/include/dt-bindings/power/r8a77980-sysc.h b/include/dt-bindings/power/r8a77980-sysc.h
new file mode 100644
index 000000000000..2c90c1237725
--- /dev/null
+++ b/include/dt-bindings/power/r8a77980-sysc.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ * Copyright (C) 2018 Cogent Embedded, Inc.
+ */
+#ifndef __DT_BINDINGS_POWER_R8A77980_SYSC_H__
+#define __DT_BINDINGS_POWER_R8A77980_SYSC_H__
+
+/*
+ * These power domain indices match the numbers of the interrupt bits
+ * representing the power areas in the various Interrupt Registers
+ * (e.g. SYSCISR, Interrupt Status Register)
+ */
+
+#define R8A77980_PD_A2SC2		0
+#define R8A77980_PD_A2SC3		1
+#define R8A77980_PD_A2SC4		2
+#define R8A77980_PD_A2PD0		3
+#define R8A77980_PD_A2PD1		4
+#define R8A77980_PD_CA53_CPU0		5
+#define R8A77980_PD_CA53_CPU1		6
+#define R8A77980_PD_CA53_CPU2		7
+#define R8A77980_PD_CA53_CPU3		8
+#define R8A77980_PD_A2CN		10
+#define R8A77980_PD_A3VIP		11
+#define R8A77980_PD_A2IR5		12
+#define R8A77980_PD_CR7			13
+#define R8A77980_PD_A2IR4		15
+#define R8A77980_PD_CA53_SCU		21
+#define R8A77980_PD_A2IR0		23
+#define R8A77980_PD_A3IR		24
+#define R8A77980_PD_A3VIP1		25
+#define R8A77980_PD_A3VIP2		26
+#define R8A77980_PD_A2IR1		27
+#define R8A77980_PD_A2IR2		28
+#define R8A77980_PD_A2IR3		29
+#define R8A77980_PD_A2SC0		30
+#define R8A77980_PD_A2SC1		31
+
+/* Always-on power area */
+#define R8A77980_PD_ALWAYS_ON		32
+
+#endif /* __DT_BINDINGS_POWER_R8A77980_SYSC_H__ */
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 2f7a29242b87..38cd77b39a64 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -26,7 +26,8 @@
 #define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
 #define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
 
-int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+int iort_register_domain_token(int trans_id, phys_addr_t base,
+			       struct fwnode_handle *fw_node);
 void iort_deregister_domain_token(int trans_id);
 struct fwnode_handle *iort_find_domain_token(int trans_id);
 #ifdef CONFIG_ACPI_IORT
@@ -38,6 +39,7 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
 /* IOMMU interface */
 void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size);
 const struct iommu_ops *iort_iommu_configure(struct device *dev);
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
 #else
 static inline void acpi_iort_init(void) { }
 static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
@@ -52,6 +54,9 @@ static inline void iort_dma_setup(struct device *dev, u64 *dma_addr,
 static inline const struct iommu_ops *iort_iommu_configure(
 				      struct device *dev)
 { return NULL; }
+static inline
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{ return 0; }
 #endif
 
 #endif /* __ACPI_IORT_H__ */
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index 4d356e168692..40373920ea58 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -113,10 +113,12 @@ extern void aarp_proto_init(void);
 /* Inter module exports */
 
 /* Give a device find its atif control structure */
+#if IS_ENABLED(CONFIG_IRDA) || IS_ENABLED(CONFIG_ATALK)
 static inline struct atalk_iface *atalk_find_dev(struct net_device *dev)
 {
 	return dev->atalk_ptr;
 }
+#endif
 
 extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
 extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
diff --git a/include/linux/avf/virtchnl.h b/include/linux/avf/virtchnl.h
index 3ce61342fa31..b0a7f315bfbe 100644
--- a/include/linux/avf/virtchnl.h
+++ b/include/linux/avf/virtchnl.h
@@ -136,15 +136,21 @@ enum virtchnl_ops {
 	VIRTCHNL_OP_ENABLE_VLAN_STRIPPING = 27,
 	VIRTCHNL_OP_DISABLE_VLAN_STRIPPING = 28,
 	VIRTCHNL_OP_REQUEST_QUEUES = 29,
+	VIRTCHNL_OP_ENABLE_CHANNELS = 30,
+	VIRTCHNL_OP_DISABLE_CHANNELS = 31,
+	VIRTCHNL_OP_ADD_CLOUD_FILTER = 32,
+	VIRTCHNL_OP_DEL_CLOUD_FILTER = 33,
 };
 
-/* This macro is used to generate a compilation error if a structure
+/* These macros are used to generate compilation errors if a structure/union
  * is not exactly the correct length. It gives a divide by zero error if the
- * structure is not of the correct size, otherwise it creates an enum that is
- * never used.
+ * structure/union is not of the correct size, otherwise it creates an enum
+ * that is never used.
  */
 #define VIRTCHNL_CHECK_STRUCT_LEN(n, X) enum virtchnl_static_assert_enum_##X \
 	{ virtchnl_static_assert_##X = (n)/((sizeof(struct X) == (n)) ? 1 : 0) }
+#define VIRTCHNL_CHECK_UNION_LEN(n, X) enum virtchnl_static_asset_enum_##X \
+	{ virtchnl_static_assert_##X = (n)/((sizeof(union X) == (n)) ? 1 : 0) }
 
 /* Virtual channel message descriptor. This overlays the admin queue
  * descriptor. All other data is passed in external buffers.
@@ -244,6 +250,7 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vsi_resource);
 #define VIRTCHNL_VF_OFFLOAD_ENCAP		0X00100000
 #define VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM		0X00200000
 #define VIRTCHNL_VF_OFFLOAD_RX_ENCAP_CSUM	0X00400000
+#define VIRTCHNL_VF_OFFLOAD_ADQ			0X00800000
 
 #define VF_BASE_MODE_OFFLOADS (VIRTCHNL_VF_OFFLOAD_L2 | \
 			       VIRTCHNL_VF_OFFLOAD_VLAN | \
@@ -496,6 +503,81 @@ struct virtchnl_rss_hena {
 
 VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_rss_hena);
 
+/* VIRTCHNL_OP_ENABLE_CHANNELS
+ * VIRTCHNL_OP_DISABLE_CHANNELS
+ * VF sends these messages to enable or disable channels based on
+ * the user specified queue count and queue offset for each traffic class.
+ * This struct encompasses all the information that the PF needs from
+ * VF to create a channel.
+ */
+struct virtchnl_channel_info {
+	u16 count; /* number of queues in a channel */
+	u16 offset; /* queues in a channel start from 'offset' */
+	u32 pad;
+	u64 max_tx_rate;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_channel_info);
+
+struct virtchnl_tc_info {
+	u32	num_tc;
+	u32	pad;
+	struct	virtchnl_channel_info list[1];
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(24, virtchnl_tc_info);
+
+/* VIRTCHNL_ADD_CLOUD_FILTER
+ * VIRTCHNL_DEL_CLOUD_FILTER
+ * VF sends these messages to add or delete a cloud filter based on the
+ * user specified match and action filters. These structures encompass
+ * all the information that the PF needs from the VF to add/delete a
+ * cloud filter.
+ */
+
+struct virtchnl_l4_spec {
+	u8	src_mac[ETH_ALEN];
+	u8	dst_mac[ETH_ALEN];
+	__be16	vlan_id;
+	__be16	pad; /* reserved for future use */
+	__be32	src_ip[4];
+	__be32	dst_ip[4];
+	__be16	src_port;
+	__be16	dst_port;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(52, virtchnl_l4_spec);
+
+union virtchnl_flow_spec {
+	struct	virtchnl_l4_spec tcp_spec;
+	u8	buffer[128]; /* reserved for future use */
+};
+
+VIRTCHNL_CHECK_UNION_LEN(128, virtchnl_flow_spec);
+
+enum virtchnl_action {
+	/* action types */
+	VIRTCHNL_ACTION_DROP = 0,
+	VIRTCHNL_ACTION_TC_REDIRECT,
+};
+
+enum virtchnl_flow_type {
+	/* flow types */
+	VIRTCHNL_TCP_V4_FLOW = 0,
+	VIRTCHNL_TCP_V6_FLOW,
+};
+
+struct virtchnl_filter {
+	union	virtchnl_flow_spec data;
+	union	virtchnl_flow_spec mask;
+	enum	virtchnl_flow_type flow_type;
+	enum	virtchnl_action action;
+	u32	action_meta;
+	__u8	field_flags;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(272, virtchnl_filter);
+
 /* VIRTCHNL_OP_EVENT
  * PF sends this message to inform the VF driver of events that may affect it.
  * No direct response is expected from the VF, though it may generate other
@@ -711,6 +793,25 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
 	case VIRTCHNL_OP_REQUEST_QUEUES:
 		valid_len = sizeof(struct virtchnl_vf_res_request);
 		break;
+	case VIRTCHNL_OP_ENABLE_CHANNELS:
+		valid_len = sizeof(struct virtchnl_tc_info);
+		if (msglen >= valid_len) {
+			struct virtchnl_tc_info *vti =
+				(struct virtchnl_tc_info *)msg;
+			valid_len += vti->num_tc *
+				sizeof(struct virtchnl_channel_info);
+			if (vti->num_tc == 0)
+				err_msg_format = true;
+		}
+		break;
+	case VIRTCHNL_OP_DISABLE_CHANNELS:
+		break;
+	case VIRTCHNL_OP_ADD_CLOUD_FILTER:
+		valid_len = sizeof(struct virtchnl_filter);
+		break;
+	case VIRTCHNL_OP_DEL_CLOUD_FILTER:
+		valid_len = sizeof(struct virtchnl_filter);
+		break;
 	/* These are always errors coming from the VF. */
 	case VIRTCHNL_OP_EVENT:
 	case VIRTCHNL_OP_UNKNOWN:
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 3e4ce54d84ab..f8894dbc0b19 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -251,7 +251,7 @@ static inline bool inode_cgwb_enabled(struct inode *inode)
 		cgroup_subsys_on_dfl(io_cgrp_subsys) &&
 		bdi_cap_account_dirty(bdi) &&
 		(bdi->capabilities & BDI_CAP_CGROUP_WRITEBACK) &&
-		(inode->i_sb->s_iflags & SB_I_CGROUPWB);
+		IS_CGROUPWB(inode);
 }
 
 /**
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 894e5d125de6..c2fbd97684ca 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -14,6 +14,7 @@
 #include <linux/pagemap.h>
 #include <linux/wait.h>
 #include <linux/atomic.h>
+#include <linux/cgroup.h>
 
 #ifdef CONFIG_BLOCK
 
@@ -200,6 +201,8 @@ void ll_rw_block(int, int, int, struct buffer_head * bh[]);
 int sync_dirty_buffer(struct buffer_head *bh);
 int __sync_dirty_buffer(struct buffer_head *bh, int op_flags);
 void write_dirty_buffer(struct buffer_head *bh, int op_flags);
+int submit_bh_blkcg_css(int op, int op_flags, struct buffer_head *bh,
+			struct cgroup_subsys_state *blkcg_css);
 int submit_bh(int, int, struct buffer_head *);
 void write_boundary_block(struct block_device *bdev,
 			sector_t bblock, unsigned blocksize);
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 9f242b876fde..8e12d7c54308 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -81,6 +81,11 @@ enum {
 	 * Enable cpuset controller in v1 cgroup to use v2 behavior.
 	 */
 	CGRP_ROOT_CPUSET_V2_MODE = (1 << 4),
+
+	/*
+	 * Enable cgroup-aware OOM killer.
+	 */
+	CGRP_GROUP_OOM = (1 << 5),
 };
 
 /* cftype->flags */
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 73bc63e0a1c4..901c1ccb3374 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -207,6 +207,15 @@
 #endif
 #endif
 
+/*
+ * calling noreturn functions, __builtin_unreachable() and __builtin_trap()
+ * confuse the stack allocation in gcc, leading to overly large stack
+ * frames, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365
+ *
+ * Adding an empty inline assembly before it works around the problem
+ */
+#define barrier_before_unreachable() asm volatile("")
+
 /*
  * Mark a position in code as unreachable.  This can be used to
  * suppress control flow warnings after asm blocks that transfer
@@ -217,7 +226,11 @@
  * unreleased.  Really, we need to have autoconf for the kernel.
  */
 #define unreachable() \
-	do { annotate_unreachable(); __builtin_unreachable(); } while (0)
+	do {					\
+		annotate_unreachable();		\
+		barrier_before_unreachable();	\
+		__builtin_unreachable();	\
+	} while (0)
 
 /* Mark a function definition as prohibited from being cloned. */
 #define __noclone	__attribute__((__noclone__, __optimize__("no-tracer")))
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index e835fc0423ec..ab4711c63601 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -86,6 +86,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
 # define barrier_data(ptr) barrier()
 #endif
 
+/* workaround for GCC PR82365 if needed */
+#ifndef barrier_before_unreachable
+# define barrier_before_unreachable() do { } while (0)
+#endif
+
 /* Unreachable code */
 #ifdef CONFIG_STACK_VALIDATION
 /*
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index b511f6d24b42..e2013dd4d5a4 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -59,6 +59,8 @@ phys_addr_t paddr_vmcoreinfo_note(void);
 	vmcoreinfo_append_str("NUMBER(%s)=%ld\n", #name, (long)name)
 #define VMCOREINFO_CONFIG(name) \
 	vmcoreinfo_append_str("CONFIG_%s=y\n", #name)
+#define VMCOREINFO_PHYS_BASE(value) \
+	vmcoreinfo_append_str("PHYS_BASE=%lx\n", (unsigned long)value)
 
 extern u32 *vmcoreinfo_note;
 
diff --git a/include/linux/crc32c.h b/include/linux/crc32c.h
index 357ae4611a45..bd21af828ff6 100644
--- a/include/linux/crc32c.h
+++ b/include/linux/crc32c.h
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 
 extern u32 crc32c(u32 crc, const void *address, unsigned int length);
+extern const char *crc32c_impl(void);
 
 /* This macro exists for backwards-compatibility. */
 #define crc32c_le crc32c
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index f838764993eb..861be5cab1df 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -470,7 +470,11 @@ typedef void (*dma_async_tx_callback_result)(void *dma_async_param,
 				const struct dmaengine_result *result);
 
 struct dmaengine_unmap_data {
+#if IS_ENABLED(CONFIG_DMA_ENGINE_RAID)
+	u16 map_cnt;
+#else
 	u8 map_cnt;
+#endif
 	u8 to_cnt;
 	u8 from_cnt;
 	u8 bidi_cnt;
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 276932d75975..fdb691b520c0 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -20,7 +20,6 @@
 #include <linux/set_memory.h>
 #include <linux/kallsyms.h>
 
-#include <net/xdp.h>
 #include <net/sch_generic.h>
 
 #include <uapi/linux/filter.h>
@@ -30,6 +29,7 @@ struct sk_buff;
 struct sock;
 struct seccomp_data;
 struct bpf_prog_aux;
+struct xdp_rxq_info;
 
 /* ArgX, context and stack frame pointer register positions. Note,
  * Arg1, Arg2, Arg3, etc are used as argument mappings of function
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2a815560fda0..d0f2b1573713 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1314,7 +1314,6 @@ extern int send_sigurg(struct fown_struct *fown);
 #define UMOUNT_UNUSED	0x80000000	/* Flag guaranteed to be unused */
 
 /* sb->s_iflags */
-#define SB_I_CGROUPWB	0x00000001	/* cgroup-aware writeback enabled */
 #define SB_I_NOEXEC	0x00000002	/* Ignore executables on this fs */
 #define SB_I_NODEV	0x00000004	/* Ignore devices on this fs */
 
@@ -1865,6 +1864,7 @@ struct super_operations {
 #define S_DAX		0	/* Make all the DAX code disappear */
 #endif
 #define S_ENCRYPTED	16384	/* Encrypted file (using fs/crypto/) */
+#define S_CGROUPWB	32768	/* Enable cgroup writeback for this inode */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -1905,6 +1905,7 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags
 #define IS_NOSEC(inode)		((inode)->i_flags & S_NOSEC)
 #define IS_DAX(inode)		((inode)->i_flags & S_DAX)
 #define IS_ENCRYPTED(inode)	((inode)->i_flags & S_ENCRYPTED)
+#define IS_CGROUPWB(inode)	((inode)->i_flags & S_CGROUPWB)
 
 #define IS_WHITEOUT(inode)	(S_ISCHR(inode->i_mode) && \
 				 (inode)->i_rdev == WHITEOUT_DEV)
@@ -2069,6 +2070,7 @@ struct file_system_type {
 #define FS_BINARY_MOUNTDATA	2
 #define FS_HAS_SUBTYPE		4
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
+#define FS_IMA_NO_CACHE		16	/* Force IMA to re-measure, re-appraise, re-audit files */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
 	struct dentry *(*mount) (struct file_system_type *, int,
 		       const char *, void *);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 091a81cf330f..0efe80b59156 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -851,7 +851,7 @@ extern int hidinput_connect(struct hid_device *hid, unsigned int force);
 extern void hidinput_disconnect(struct hid_device *);
 
 int hid_set_field(struct hid_field *, unsigned, __s32);
-int hid_input_report(struct hid_device *, int type, u8 *, int, int);
+int hid_input_report(struct hid_device *, int type, u8 *, u32, int);
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
 struct hid_field *hidinput_get_led_field(struct hid_device *hid);
 unsigned int hidinput_count_leds(struct hid_device *hid);
@@ -1102,13 +1102,13 @@ static inline void hid_hw_wait(struct hid_device *hdev)
  *
  * @report: the report we want to know the length
  */
-static inline int hid_report_len(struct hid_report *report)
+static inline u32 hid_report_len(struct hid_report *report)
 {
 	/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
 	return ((report->size - 1) >> 3) + 1 + (report->id > 0);
 }
 
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 		int interrupt);
 
 /* HID quirks API */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index ee6657a0ed69..8fe7e4306816 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -8,6 +8,7 @@
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
  * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
  * Copyright (c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (c) 2018        Intel 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
@@ -2111,7 +2112,7 @@ enum ieee80211_key_len {
 #define FILS_ERP_MAX_REALM_LEN		253
 #define FILS_ERP_MAX_RRK_LEN		64
 
-#define PMK_MAX_LEN			48
+#define PMK_MAX_LEN			64
 
 /* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
 enum ieee80211_pub_actioncode {
@@ -2501,6 +2502,17 @@ static inline u8 *ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr)
 		return (u8 *)hdr + 24;
 }
 
+/**
+ * ieee80211_get_tid - get qos TID
+ * @hdr: the frame
+ */
+static inline u8 ieee80211_get_tid(struct ieee80211_hdr *hdr)
+{
+	u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+	return qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
 /**
  * ieee80211_get_SA - get pointer to SA
  * @hdr: the frame
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8dad3dd26eae..ef169d67df92 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -209,12 +209,12 @@
 #define DMA_FECTL_IM (((u32)1) << 31)
 
 /* FSTS_REG */
-#define DMA_FSTS_PPF ((u32)2)
-#define DMA_FSTS_PFO ((u32)1)
-#define DMA_FSTS_IQE (1 << 4)
-#define DMA_FSTS_ICE (1 << 5)
-#define DMA_FSTS_ITE (1 << 6)
-#define DMA_FSTS_PRO (1 << 7)
+#define DMA_FSTS_PFO (1 << 0) /* Primary Fault Overflow */
+#define DMA_FSTS_PPF (1 << 1) /* Primary Pending Fault */
+#define DMA_FSTS_IQE (1 << 4) /* Invalidation Queue Error */
+#define DMA_FSTS_ICE (1 << 5) /* Invalidation Completion Error */
+#define DMA_FSTS_ITE (1 << 6) /* Invalidation Time-out Error */
+#define DMA_FSTS_PRO (1 << 7) /* Page Request Overflow */
 #define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
 
 /* FRCD_REG, 32 bits access */
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 69c238210325..5426627f9c55 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -4,9 +4,7 @@
 #define _LINUX_INTERRUPT_H
 
 #include <linux/kernel.h>
-#include <linux/linkage.h>
 #include <linux/bitops.h>
-#include <linux/preempt.h>
 #include <linux/cpumask.h>
 #include <linux/irqreturn.h>
 #include <linux/irqnr.h>
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 41b8c5757859..19938ee6eb31 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -465,23 +465,23 @@ static inline int iommu_map(struct iommu_domain *domain, unsigned long iova,
 	return -ENODEV;
 }
 
-static inline int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
-			      size_t size)
+static inline size_t iommu_unmap(struct iommu_domain *domain,
+				 unsigned long iova, size_t size)
 {
-	return -ENODEV;
+	return 0;
 }
 
-static inline int iommu_unmap_fast(struct iommu_domain *domain, unsigned long iova,
-				   int gfp_order)
+static inline size_t iommu_unmap_fast(struct iommu_domain *domain,
+				      unsigned long iova, int gfp_order)
 {
-	return -ENODEV;
+	return 0;
 }
 
 static inline size_t iommu_map_sg(struct iommu_domain *domain,
 				  unsigned long iova, struct scatterlist *sg,
 				  unsigned int nents, int prot)
 {
-	return -ENODEV;
+	return 0;
 }
 
 static inline void iommu_flush_tlb_all(struct iommu_domain *domain)
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index adc13474a53b..d6459bd1376d 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -18,7 +18,7 @@ extern unsigned char kasan_zero_page[PAGE_SIZE];
 extern pte_t kasan_zero_pte[PTRS_PER_PTE];
 extern pmd_t kasan_zero_pmd[PTRS_PER_PMD];
 extern pud_t kasan_zero_pud[PTRS_PER_PUD];
-extern p4d_t kasan_zero_p4d[PTRS_PER_P4D];
+extern p4d_t kasan_zero_p4d[MAX_PTRS_PER_P4D];
 
 void kasan_populate_zero_shadow(const void *shadow_start,
 				const void *shadow_end);
diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h
index fec5076eda91..cc8fa109cfa3 100644
--- a/include/linux/kconfig.h
+++ b/include/linux/kconfig.h
@@ -4,6 +4,12 @@
 
 #include <generated/autoconf.h>
 
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#else
+#define __LITTLE_ENDIAN 1234
+#endif
+
 #define __ARG_PLACEHOLDER_1 0,
 #define __take_second_arg(__ignored, val, ...) val
 
diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h
index bb8129a3474d..96def9d15b1b 100644
--- a/include/linux/list_lru.h
+++ b/include/linux/list_lru.h
@@ -32,6 +32,7 @@ struct list_lru_one {
 };
 
 struct list_lru_memcg {
+	struct rcu_head		rcu;
 	/* array of per cgroup lists, indexed by memcg_cache_id */
 	struct list_lru_one	*lru[0];
 };
@@ -43,7 +44,7 @@ struct list_lru_node {
 	struct list_lru_one	lru;
 #if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB)
 	/* for cgroup aware lrus points to per cgroup lists, otherwise NULL */
-	struct list_lru_memcg	*memcg_lrus;
+	struct list_lru_memcg	__rcu *memcg_lrus;
 #endif
 	long nr_items;
 } ____cacheline_aligned_in_smp;
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 882046863581..c79cdf9f8138 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -35,6 +35,7 @@ struct mem_cgroup;
 struct page;
 struct mm_struct;
 struct kmem_cache;
+struct oom_control;
 
 /* Cgroup-specific page state, on top of universal node page state */
 enum memcg_stat_item {
@@ -202,6 +203,13 @@ struct mem_cgroup {
 	/* OOM-Killer disable */
 	int		oom_kill_disable;
 
+	/*
+	 * Treat the sub-tree as an indivisible memory consumer,
+	 * kill all belonging tasks if the memory cgroup selected
+	 * as OOM victim.
+	 */
+	bool oom_group;
+
 	/* handle for "memory.events" */
 	struct cgroup_file events_file;
 
@@ -344,6 +352,11 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
 	return css ? container_of(css, struct mem_cgroup, css) : NULL;
 }
 
+static inline void mem_cgroup_put(struct mem_cgroup *memcg)
+{
+	css_put(&memcg->css);
+}
+
 #define mem_cgroup_from_counter(counter, member)	\
 	container_of(counter, struct mem_cgroup, member)
 
@@ -482,6 +495,13 @@ static inline bool task_in_memcg_oom(struct task_struct *p)
 
 bool mem_cgroup_oom_synchronize(bool wait);
 
+bool mem_cgroup_select_oom_victim(struct oom_control *oc);
+
+static inline bool mem_cgroup_oom_group(struct mem_cgroup *memcg)
+{
+	return memcg->oom_group;
+}
+
 #ifdef CONFIG_MEMCG_SWAP
 extern int do_swap_account;
 #endif
@@ -523,9 +543,11 @@ static inline void __mod_memcg_state(struct mem_cgroup *memcg,
 static inline void mod_memcg_state(struct mem_cgroup *memcg,
 				   int idx, int val)
 {
-	preempt_disable();
+	unsigned long flags;
+
+	local_irq_save(flags);
 	__mod_memcg_state(memcg, idx, val);
-	preempt_enable();
+	local_irq_restore(flags);
 }
 
 /**
@@ -606,9 +628,11 @@ static inline void __mod_lruvec_state(struct lruvec *lruvec,
 static inline void mod_lruvec_state(struct lruvec *lruvec,
 				    enum node_stat_item idx, int val)
 {
-	preempt_disable();
+	unsigned long flags;
+
+	local_irq_save(flags);
 	__mod_lruvec_state(lruvec, idx, val);
-	preempt_enable();
+	local_irq_restore(flags);
 }
 
 static inline void __mod_lruvec_page_state(struct page *page,
@@ -630,9 +654,11 @@ static inline void __mod_lruvec_page_state(struct page *page,
 static inline void mod_lruvec_page_state(struct page *page,
 					 enum node_stat_item idx, int val)
 {
-	preempt_disable();
+	unsigned long flags;
+
+	local_irq_save(flags);
 	__mod_lruvec_page_state(page, idx, val);
-	preempt_enable();
+	local_irq_restore(flags);
 }
 
 unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
@@ -659,9 +685,11 @@ static inline void __count_memcg_events(struct mem_cgroup *memcg,
 static inline void count_memcg_events(struct mem_cgroup *memcg,
 				      int idx, unsigned long count)
 {
-	preempt_disable();
+	unsigned long flags;
+
+	local_irq_save(flags);
 	__count_memcg_events(memcg, idx, count);
-	preempt_enable();
+	local_irq_restore(flags);
 }
 
 /* idx can be of type enum memcg_event_item or vm_event_item */
@@ -781,6 +809,10 @@ static inline bool task_in_mem_cgroup(struct task_struct *task,
 	return true;
 }
 
+static inline void mem_cgroup_put(struct mem_cgroup *memcg)
+{
+}
+
 static inline struct mem_cgroup *
 mem_cgroup_iter(struct mem_cgroup *root,
 		struct mem_cgroup *prev,
@@ -973,6 +1005,16 @@ static inline
 void count_memcg_event_mm(struct mm_struct *mm, enum vm_event_item idx)
 {
 }
+
+static inline bool mem_cgroup_select_oom_victim(struct oom_control *oc)
+{
+	return false;
+}
+
+static inline bool mem_cgroup_oom_group(struct mem_cgroup *memcg)
+{
+	return false;
+}
 #endif /* CONFIG_MEMCG */
 
 /* idx can be of type enum memcg_stat_item or node_stat_item */
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index aba5f86eb038..787411bdeadb 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -234,9 +234,6 @@ void put_online_mems(void);
 void mem_hotplug_begin(void);
 void mem_hotplug_done(void);
 
-extern void set_zone_contiguous(struct zone *zone);
-extern void clear_zone_contiguous(struct zone *zone);
-
 #else /* ! CONFIG_MEMORY_HOTPLUG */
 #define pfn_to_online_page(pfn)			\
 ({						\
diff --git a/include/linux/mfd/as3711.h b/include/linux/mfd/as3711.h
index 34cc85864be5..ddd0b953323b 100644
--- a/include/linux/mfd/as3711.h
+++ b/include/linux/mfd/as3711.h
@@ -108,9 +108,9 @@ struct as3711_regulator_pdata {
 };
 
 struct as3711_bl_pdata {
-	const char *su1_fb;
+	bool su1_fb;
 	int su1_max_uA;
-	const char *su2_fb;
+	bool su2_fb;
 	int su2_max_uA;
 	enum as3711_su2_feedback su2_feedback;
 	enum as3711_su2_fbprot su2_fbprot;
diff --git a/include/linux/mfd/da9055/pdata.h b/include/linux/mfd/da9055/pdata.h
index 04e092be4b07..1a94fa2ac309 100644
--- a/include/linux/mfd/da9055/pdata.h
+++ b/include/linux/mfd/da9055/pdata.h
@@ -12,6 +12,7 @@
 #define DA9055_MAX_REGULATORS	8
 
 struct da9055;
+struct gpio_desc;
 
 enum gpio_select {
 	NO_GPIO = 0,
@@ -47,7 +48,7 @@ struct da9055_pdata {
 	 * controls the regulator set A/B, 0 if  not available.
 	 */
 	enum gpio_select *reg_rsel;
-	/* GPIOs to enable regulator, 0 if not available */
-	int *ena_gpio;
+	/* GPIO descriptors to enable regulator, NULL if not available */
+	struct gpio_desc **ena_gpiods;
 };
 #endif /* __DA9055_PDATA_H */
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 396a103c8bc6..91f92215ca74 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -36,7 +36,6 @@
 	} while (0)
 
 /* tmio MMC platform flags */
-#define TMIO_MMC_WRPROTECT_DISABLE	BIT(0)
 /*
  * Some controllers can support a 2-byte block size when the bus width
  * is configured in 4-bit mode.
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index a2246cf670ba..0c6fe904bc97 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -7,8 +7,7 @@
 #include <linux/migrate_mode.h>
 #include <linux/hugetlb.h>
 
-typedef struct page *new_page_t(struct page *page, unsigned long private,
-				int **reason);
+typedef struct page *new_page_t(struct page *page, unsigned long private);
 typedef void free_page_t(struct page *page, unsigned long private);
 
 /*
@@ -43,9 +42,9 @@ static inline struct page *new_page_nodemask(struct page *page,
 		return alloc_huge_page_nodemask(page_hstate(compound_head(page)),
 				preferred_nid, nodemask);
 
-	if (thp_migration_supported() && PageTransHuge(page)) {
-		order = HPAGE_PMD_ORDER;
+	if (PageTransHuge(page)) {
 		gfp_mask |= GFP_TRANSHUGE;
+		order = HPAGE_PMD_ORDER;
 	}
 
 	if (PageHighMem(page) || (zone_idx(page_zone(page)) == ZONE_MOVABLE))
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ad06d42adb1a..47c06fd20f6a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2096,6 +2096,7 @@ extern void setup_per_cpu_pageset(void);
 
 extern void zone_pcp_update(struct zone *zone);
 extern void zone_pcp_reset(struct zone *zone);
+extern void setup_zone_pageset(struct zone *zone);
 
 /* page_alloc.c */
 extern int min_free_kbytes;
@@ -2604,6 +2605,7 @@ enum mf_action_page_type {
 	MF_MSG_POISONED_HUGE,
 	MF_MSG_HUGE,
 	MF_MSG_FREE_HUGE,
+	MF_MSG_NON_PMD_HUGE,
 	MF_MSG_UNMAP_FAILED,
 	MF_MSG_DIRTY_SWAPCACHE,
 	MF_MSG_CLEAN_SWAPCACHE,
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 7522a6987595..e09fe563d5dc 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -886,7 +886,7 @@ int min_free_kbytes_sysctl_handler(struct ctl_table *, int,
 					void __user *, size_t *, loff_t *);
 int watermark_scale_factor_sysctl_handler(struct ctl_table *, int,
 					void __user *, size_t *, loff_t *);
-extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1];
+extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES];
 int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int,
 					void __user *, size_t *, loff_t *);
 int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *, int,
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 3bf8f954b642..3102bd754d18 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -1,6 +1,4 @@
 /*
- *  linux/include/linux/mtd/bbm.h
- *
  *  NAND family Bad Block Management (BBM) header file
  *    - Bad Block Table (BBT) implementation
  *
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
new file mode 100644
index 000000000000..792ea5c26329
--- /dev/null
+++ b/include/linux/mtd/nand.h
@@ -0,0 +1,731 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright 2017 - Free Electrons
+ *
+ *  Authors:
+ *	Boris Brezillon <boris.brezillon@free-electrons.com>
+ *	Peter Pan <peterpandong@micron.com>
+ */
+
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
+
+#include <linux/mtd/mtd.h>
+
+/**
+ * struct nand_memory_organization - Memory organization structure
+ * @bits_per_cell: number of bits per NAND cell
+ * @pagesize: page size
+ * @oobsize: OOB area size
+ * @pages_per_eraseblock: number of pages per eraseblock
+ * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @planes_per_lun: number of planes per LUN
+ * @luns_per_target: number of LUN per target (target is a synonym for die)
+ * @ntargets: total number of targets exposed by the NAND device
+ */
+struct nand_memory_organization {
+	unsigned int bits_per_cell;
+	unsigned int pagesize;
+	unsigned int oobsize;
+	unsigned int pages_per_eraseblock;
+	unsigned int eraseblocks_per_lun;
+	unsigned int planes_per_lun;
+	unsigned int luns_per_target;
+	unsigned int ntargets;
+};
+
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)	\
+	{							\
+		.bits_per_cell = (bpc),				\
+		.pagesize = (ps),				\
+		.oobsize = (os),				\
+		.pages_per_eraseblock = (ppe),			\
+		.eraseblocks_per_lun = (epl),			\
+		.planes_per_lun = (ppl),			\
+		.luns_per_target = (lpt),			\
+		.ntargets = (nt),				\
+	}
+
+/**
+ * struct nand_row_converter - Information needed to convert an absolute offset
+ *			       into a row address
+ * @lun_addr_shift: position of the LUN identifier in the row address
+ * @eraseblock_addr_shift: position of the eraseblock identifier in the row
+ *			   address
+ */
+struct nand_row_converter {
+	unsigned int lun_addr_shift;
+	unsigned int eraseblock_addr_shift;
+};
+
+/**
+ * struct nand_pos - NAND position object
+ * @target: the NAND target/die
+ * @lun: the LUN identifier
+ * @plane: the plane within the LUN
+ * @eraseblock: the eraseblock within the LUN
+ * @page: the page within the LUN
+ *
+ * These information are usually used by specific sub-layers to select the
+ * appropriate target/die and generate a row address to pass to the device.
+ */
+struct nand_pos {
+	unsigned int target;
+	unsigned int lun;
+	unsigned int plane;
+	unsigned int eraseblock;
+	unsigned int page;
+};
+
+/**
+ * struct nand_page_io_req - NAND I/O request object
+ * @pos: the position this I/O request is targeting
+ * @dataoffs: the offset within the page
+ * @datalen: number of data bytes to read from/write to this page
+ * @databuf: buffer to store data in or get data from
+ * @ooboffs: the OOB offset within the page
+ * @ooblen: the number of OOB bytes to read from/write to this page
+ * @oobbuf: buffer to store OOB data in or get OOB data from
+ *
+ * This object is used to pass per-page I/O requests to NAND sub-layers. This
+ * way all useful information are already formatted in a useful way and
+ * specific NAND layers can focus on translating these information into
+ * specific commands/operations.
+ */
+struct nand_page_io_req {
+	struct nand_pos pos;
+	unsigned int dataoffs;
+	unsigned int datalen;
+	union {
+		const void *out;
+		void *in;
+	} databuf;
+	unsigned int ooboffs;
+	unsigned int ooblen;
+	union {
+		const void *out;
+		void *in;
+	} oobbuf;
+};
+
+/**
+ * struct nand_ecc_req - NAND ECC requirements
+ * @strength: ECC strength
+ * @step_size: ECC step/block size
+ */
+struct nand_ecc_req {
+	unsigned int strength;
+	unsigned int step_size;
+};
+
+#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
+
+/**
+ * struct nand_bbt - bad block table object
+ * @cache: in memory BBT cache
+ */
+struct nand_bbt {
+	unsigned long *cache;
+};
+
+struct nand_device;
+
+/**
+ * struct nand_ops - NAND operations
+ * @erase: erase a specific block. No need to check if the block is bad before
+ *	   erasing, this has been taken care of by the generic NAND layer
+ * @markbad: mark a specific block bad. No need to check if the block is
+ *	     already marked bad, this has been taken care of by the generic
+ *	     NAND layer. This method should just write the BBM (Bad Block
+ *	     Marker) so that future call to struct_nand_ops->isbad() return
+ *	     true
+ * @isbad: check whether a block is bad or not. This method should just read
+ *	   the BBM and return whether the block is bad or not based on what it
+ *	   reads
+ *
+ * These are all low level operations that should be implemented by specialized
+ * NAND layers (SPI NAND, raw NAND, ...).
+ */
+struct nand_ops {
+	int (*erase)(struct nand_device *nand, const struct nand_pos *pos);
+	int (*markbad)(struct nand_device *nand, const struct nand_pos *pos);
+	bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos);
+};
+
+/**
+ * struct nand_device - NAND device
+ * @mtd: MTD instance attached to the NAND device
+ * @memorg: memory layout
+ * @eccreq: ECC requirements
+ * @rowconv: position to row address converter
+ * @bbt: bad block table info
+ * @ops: NAND operations attached to the NAND device
+ *
+ * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
+ * should declare their own NAND object embedding a nand_device struct (that's
+ * how inheritance is done).
+ * struct_nand_device->memorg and struct_nand_device->eccreq should be filled
+ * at device detection time to reflect the NAND device
+ * capabilities/requirements. Once this is done nanddev_init() can be called.
+ * It will take care of converting NAND information into MTD ones, which means
+ * the specialized NAND layers should never manually tweak
+ * struct_nand_device->mtd except for the ->_read/write() hooks.
+ */
+struct nand_device {
+	struct mtd_info mtd;
+	struct nand_memory_organization memorg;
+	struct nand_ecc_req eccreq;
+	struct nand_row_converter rowconv;
+	struct nand_bbt bbt;
+	const struct nand_ops *ops;
+};
+
+/**
+ * struct nand_io_iter - NAND I/O iterator
+ * @req: current I/O request
+ * @oobbytes_per_page: maximum number of OOB bytes per page
+ * @dataleft: remaining number of data bytes to read/write
+ * @oobleft: remaining number of OOB bytes to read/write
+ *
+ * Can be used by specialized NAND layers to iterate over all pages covered
+ * by an MTD I/O request, which should greatly simplifies the boiler-plate
+ * code needed to read/write data from/to a NAND device.
+ */
+struct nand_io_iter {
+	struct nand_page_io_req req;
+	unsigned int oobbytes_per_page;
+	unsigned int dataleft;
+	unsigned int oobleft;
+};
+
+/**
+ * mtd_to_nanddev() - Get the NAND device attached to the MTD instance
+ * @mtd: MTD instance
+ *
+ * Return: the NAND device embedding @mtd.
+ */
+static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct nand_device, mtd);
+}
+
+/**
+ * nanddev_to_mtd() - Get the MTD device attached to a NAND device
+ * @nand: NAND device
+ *
+ * Return: the MTD device embedded in @nand.
+ */
+static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand)
+{
+	return &nand->mtd;
+}
+
+/*
+ * nanddev_bits_per_cell() - Get the number of bits per cell
+ * @nand: NAND device
+ *
+ * Return: the number of bits per cell.
+ */
+static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand)
+{
+	return nand->memorg.bits_per_cell;
+}
+
+/**
+ * nanddev_page_size() - Get NAND page size
+ * @nand: NAND device
+ *
+ * Return: the page size.
+ */
+static inline size_t nanddev_page_size(const struct nand_device *nand)
+{
+	return nand->memorg.pagesize;
+}
+
+/**
+ * nanddev_per_page_oobsize() - Get NAND OOB size
+ * @nand: NAND device
+ *
+ * Return: the OOB size.
+ */
+static inline unsigned int
+nanddev_per_page_oobsize(const struct nand_device *nand)
+{
+	return nand->memorg.oobsize;
+}
+
+/**
+ * nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock
+ * @nand: NAND device
+ *
+ * Return: the number of pages per eraseblock.
+ */
+static inline unsigned int
+nanddev_pages_per_eraseblock(const struct nand_device *nand)
+{
+	return nand->memorg.pages_per_eraseblock;
+}
+
+/**
+ * nanddev_per_page_oobsize() - Get NAND erase block size
+ * @nand: NAND device
+ *
+ * Return: the eraseblock size.
+ */
+static inline size_t nanddev_eraseblock_size(const struct nand_device *nand)
+{
+	return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock;
+}
+
+/**
+ * nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN
+ * @nand: NAND device
+ *
+ * Return: the number of eraseblocks per LUN.
+ */
+static inline unsigned int
+nanddev_eraseblocks_per_lun(const struct nand_device *nand)
+{
+	return nand->memorg.eraseblocks_per_lun;
+}
+
+/**
+ * nanddev_target_size() - Get the total size provided by a single target/die
+ * @nand: NAND device
+ *
+ * Return: the total size exposed by a single target/die in bytes.
+ */
+static inline u64 nanddev_target_size(const struct nand_device *nand)
+{
+	return (u64)nand->memorg.luns_per_target *
+	       nand->memorg.eraseblocks_per_lun *
+	       nand->memorg.pages_per_eraseblock *
+	       nand->memorg.pagesize;
+}
+
+/**
+ * nanddev_ntarget() - Get the total of targets
+ * @nand: NAND device
+ *
+ * Return: the number of targets/dies exposed by @nand.
+ */
+static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
+{
+	return nand->memorg.ntargets;
+}
+
+/**
+ * nanddev_neraseblocks() - Get the total number of erasablocks
+ * @nand: NAND device
+ *
+ * Return: the total number of eraseblocks exposed by @nand.
+ */
+static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand)
+{
+	return (u64)nand->memorg.luns_per_target *
+	       nand->memorg.eraseblocks_per_lun *
+	       nand->memorg.pages_per_eraseblock;
+}
+
+/**
+ * nanddev_size() - Get NAND size
+ * @nand: NAND device
+ *
+ * Return: the total size (in bytes) exposed by @nand.
+ */
+static inline u64 nanddev_size(const struct nand_device *nand)
+{
+	return nanddev_target_size(nand) * nanddev_ntargets(nand);
+}
+
+/**
+ * nanddev_get_memorg() - Extract memory organization info from a NAND device
+ * @nand: NAND device
+ *
+ * This can be used by the upper layer to fill the memorg info before calling
+ * nanddev_init().
+ *
+ * Return: the memorg object embedded in the NAND device.
+ */
+static inline struct nand_memory_organization *
+nanddev_get_memorg(struct nand_device *nand)
+{
+	return &nand->memorg;
+}
+
+int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
+		 struct module *owner);
+void nanddev_cleanup(struct nand_device *nand);
+
+/**
+ * nanddev_register() - Register a NAND device
+ * @nand: NAND device
+ *
+ * Register a NAND device.
+ * This function is just a wrapper around mtd_device_register()
+ * registering the MTD device embedded in @nand.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+static inline int nanddev_register(struct nand_device *nand)
+{
+	return mtd_device_register(&nand->mtd, NULL, 0);
+}
+
+/**
+ * nanddev_unregister() - Unregister a NAND device
+ * @nand: NAND device
+ *
+ * Unregister a NAND device.
+ * This function is just a wrapper around mtd_device_unregister()
+ * unregistering the MTD device embedded in @nand.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+static inline int nanddev_unregister(struct nand_device *nand)
+{
+	return mtd_device_unregister(&nand->mtd);
+}
+
+/**
+ * nanddev_set_of_node() - Attach a DT node to a NAND device
+ * @nand: NAND device
+ * @np: DT node
+ *
+ * Attach a DT node to a NAND device.
+ */
+static inline void nanddev_set_of_node(struct nand_device *nand,
+				       struct device_node *np)
+{
+	mtd_set_of_node(&nand->mtd, np);
+}
+
+/**
+ * nanddev_get_of_node() - Retrieve the DT node attached to a NAND device
+ * @nand: NAND device
+ *
+ * Return: the DT node attached to @nand.
+ */
+static inline struct device_node *nanddev_get_of_node(struct nand_device *nand)
+{
+	return mtd_get_of_node(&nand->mtd);
+}
+
+/**
+ * nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position
+ * @nand: NAND device
+ * @offs: absolute NAND offset (usually passed by the MTD layer)
+ * @pos: a NAND position object to fill in
+ *
+ * Converts @offs into a nand_pos representation.
+ *
+ * Return: the offset within the NAND page pointed by @pos.
+ */
+static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand,
+					       loff_t offs,
+					       struct nand_pos *pos)
+{
+	unsigned int pageoffs;
+	u64 tmp = offs;
+
+	pageoffs = do_div(tmp, nand->memorg.pagesize);
+	pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock);
+	pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun);
+	pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
+	pos->lun = do_div(tmp, nand->memorg.luns_per_target);
+	pos->target = tmp;
+
+	return pageoffs;
+}
+
+/**
+ * nanddev_pos_cmp() - Compare two NAND positions
+ * @a: First NAND position
+ * @b: Second NAND position
+ *
+ * Compares two NAND positions.
+ *
+ * Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b.
+ */
+static inline int nanddev_pos_cmp(const struct nand_pos *a,
+				  const struct nand_pos *b)
+{
+	if (a->target != b->target)
+		return a->target < b->target ? -1 : 1;
+
+	if (a->lun != b->lun)
+		return a->lun < b->lun ? -1 : 1;
+
+	if (a->eraseblock != b->eraseblock)
+		return a->eraseblock < b->eraseblock ? -1 : 1;
+
+	if (a->page != b->page)
+		return a->page < b->page ? -1 : 1;
+
+	return 0;
+}
+
+/**
+ * nanddev_pos_to_offs() - Convert a NAND position into an absolute offset
+ * @nand: NAND device
+ * @pos: the NAND position to convert
+ *
+ * Converts @pos NAND position into an absolute offset.
+ *
+ * Return: the absolute offset. Note that @pos points to the beginning of a
+ *	   page, if one wants to point to a specific offset within this page
+ *	   the returned offset has to be adjusted manually.
+ */
+static inline loff_t nanddev_pos_to_offs(struct nand_device *nand,
+					 const struct nand_pos *pos)
+{
+	unsigned int npages;
+
+	npages = pos->page +
+		 ((pos->eraseblock +
+		   (pos->lun +
+		    (pos->target * nand->memorg.luns_per_target)) *
+		   nand->memorg.eraseblocks_per_lun) *
+		  nand->memorg.pages_per_eraseblock);
+
+	return (loff_t)npages * nand->memorg.pagesize;
+}
+
+/**
+ * nanddev_pos_to_row() - Extract a row address from a NAND position
+ * @nand: NAND device
+ * @pos: the position to convert
+ *
+ * Converts a NAND position into a row address that can then be passed to the
+ * device.
+ *
+ * Return: the row address extracted from @pos.
+ */
+static inline unsigned int nanddev_pos_to_row(struct nand_device *nand,
+					      const struct nand_pos *pos)
+{
+	return (pos->lun << nand->rowconv.lun_addr_shift) |
+	       (pos->eraseblock << nand->rowconv.eraseblock_addr_shift) |
+	       pos->page;
+}
+
+/**
+ * nanddev_pos_next_target() - Move a position to the next target/die
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next target/die. Useful when you
+ * want to iterate over all targets/dies of a NAND device.
+ */
+static inline void nanddev_pos_next_target(struct nand_device *nand,
+					   struct nand_pos *pos)
+{
+	pos->page = 0;
+	pos->plane = 0;
+	pos->eraseblock = 0;
+	pos->lun = 0;
+	pos->target++;
+}
+
+/**
+ * nanddev_pos_next_lun() - Move a position to the next LUN
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next LUN. Useful when you want to
+ * iterate over all LUNs of a NAND device.
+ */
+static inline void nanddev_pos_next_lun(struct nand_device *nand,
+					struct nand_pos *pos)
+{
+	if (pos->lun >= nand->memorg.luns_per_target - 1)
+		return nanddev_pos_next_target(nand, pos);
+
+	pos->lun++;
+	pos->page = 0;
+	pos->plane = 0;
+	pos->eraseblock = 0;
+}
+
+/**
+ * nanddev_pos_next_eraseblock() - Move a position to the next eraseblock
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next eraseblock. Useful when you
+ * want to iterate over all eraseblocks of a NAND device.
+ */
+static inline void nanddev_pos_next_eraseblock(struct nand_device *nand,
+					       struct nand_pos *pos)
+{
+	if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1)
+		return nanddev_pos_next_lun(nand, pos);
+
+	pos->eraseblock++;
+	pos->page = 0;
+	pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
+}
+
+/**
+ * nanddev_pos_next_eraseblock() - Move a position to the next page
+ * @nand: NAND device
+ * @pos: the position to update
+ *
+ * Updates @pos to point to the start of the next page. Useful when you want to
+ * iterate over all pages of a NAND device.
+ */
+static inline void nanddev_pos_next_page(struct nand_device *nand,
+					 struct nand_pos *pos)
+{
+	if (pos->page >= nand->memorg.pages_per_eraseblock - 1)
+		return nanddev_pos_next_eraseblock(nand, pos);
+
+	pos->page++;
+}
+
+/**
+ * nand_io_iter_init - Initialize a NAND I/O iterator
+ * @nand: NAND device
+ * @offs: absolute offset
+ * @req: MTD request
+ * @iter: NAND I/O iterator
+ *
+ * Initializes a NAND iterator based on the information passed by the MTD
+ * layer.
+ */
+static inline void nanddev_io_iter_init(struct nand_device *nand,
+					loff_t offs, struct mtd_oob_ops *req,
+					struct nand_io_iter *iter)
+{
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+
+	iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
+	iter->req.ooboffs = req->ooboffs;
+	iter->oobbytes_per_page = mtd_oobavail(mtd, req);
+	iter->dataleft = req->len;
+	iter->oobleft = req->ooblen;
+	iter->req.databuf.in = req->datbuf;
+	iter->req.datalen = min_t(unsigned int,
+				  nand->memorg.pagesize - iter->req.dataoffs,
+				  iter->dataleft);
+	iter->req.oobbuf.in = req->oobbuf;
+	iter->req.ooblen = min_t(unsigned int,
+				 iter->oobbytes_per_page - iter->req.ooboffs,
+				 iter->oobleft);
+}
+
+/**
+ * nand_io_iter_next_page - Move to the next page
+ * @nand: NAND device
+ * @iter: NAND I/O iterator
+ *
+ * Updates the @iter to point to the next page.
+ */
+static inline void nanddev_io_iter_next_page(struct nand_device *nand,
+					     struct nand_io_iter *iter)
+{
+	nanddev_pos_next_page(nand, &iter->req.pos);
+	iter->dataleft -= iter->req.datalen;
+	iter->req.databuf.in += iter->req.datalen;
+	iter->oobleft -= iter->req.ooblen;
+	iter->req.oobbuf.in += iter->req.ooblen;
+	iter->req.dataoffs = 0;
+	iter->req.ooboffs = 0;
+	iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize,
+				  iter->dataleft);
+	iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page,
+				 iter->oobleft);
+}
+
+/**
+ * nand_io_iter_end - Should end iteration or not
+ * @nand: NAND device
+ * @iter: NAND I/O iterator
+ *
+ * Check whether @iter has reached the end of the NAND portion it was asked to
+ * iterate on or not.
+ *
+ * Return: true if @iter has reached the end of the iteration request, false
+ *	   otherwise.
+ */
+static inline bool nanddev_io_iter_end(struct nand_device *nand,
+				       const struct nand_io_iter *iter)
+{
+	if (iter->dataleft || iter->oobleft)
+		return false;
+
+	return true;
+}
+
+/**
+ * nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O
+ *			   request
+ * @nand: NAND device
+ * @start: start address to read/write from
+ * @req: MTD I/O request
+ * @iter: NAND I/O iterator
+ *
+ * Should be used for iterate over pages that are contained in an MTD request.
+ */
+#define nanddev_io_for_each_page(nand, start, req, iter)		\
+	for (nanddev_io_iter_init(nand, start, req, iter);		\
+	     !nanddev_io_iter_end(nand, iter);				\
+	     nanddev_io_iter_next_page(nand, iter))
+
+bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
+bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
+int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
+int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
+
+/* BBT related functions */
+enum nand_bbt_block_status {
+	NAND_BBT_BLOCK_STATUS_UNKNOWN,
+	NAND_BBT_BLOCK_GOOD,
+	NAND_BBT_BLOCK_WORN,
+	NAND_BBT_BLOCK_RESERVED,
+	NAND_BBT_BLOCK_FACTORY_BAD,
+	NAND_BBT_BLOCK_NUM_STATUS,
+};
+
+int nanddev_bbt_init(struct nand_device *nand);
+void nanddev_bbt_cleanup(struct nand_device *nand);
+int nanddev_bbt_update(struct nand_device *nand);
+int nanddev_bbt_get_block_status(const struct nand_device *nand,
+				 unsigned int entry);
+int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
+				 enum nand_bbt_block_status status);
+int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block);
+
+/**
+ * nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry
+ * @nand: NAND device
+ * @pos: the NAND position we want to get BBT entry for
+ *
+ * Return the BBT entry used to store information about the eraseblock pointed
+ * by @pos.
+ *
+ * Return: the BBT entry storing information about eraseblock pointed by @pos.
+ */
+static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand,
+						    const struct nand_pos *pos)
+{
+	return pos->eraseblock +
+	       ((pos->lun + (pos->target * nand->memorg.luns_per_target)) *
+		nand->memorg.eraseblocks_per_lun);
+}
+
+/**
+ * nanddev_bbt_is_initialized() - Check if the BBT has been initialized
+ * @nand: NAND device
+ *
+ * Return: true if the BBT has been initialized, false otherwise.
+ */
+static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
+{
+	return !!nand->bbt.cache;
+}
+
+/* MTD -> NAND helper functions. */
+int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
+
+#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h
index 4d8406c81652..8a2decf7462c 100644
--- a/include/linux/mtd/nand_ecc.h
+++ b/include/linux/mtd/nand_ecc.h
@@ -1,6 +1,4 @@
 /*
- *  drivers/mtd/nand_ecc.h
- *
  *  Copyright (C) 2000-2010 Steven J. Hill <sjhill@realitydiluted.com>
  *			    David Woodhouse <dwmw2@infradead.org>
  *			    Thomas Gleixner <tglx@linutronix.de>
diff --git a/include/linux/mtd/ndfc.h b/include/linux/mtd/ndfc.h
index d0558a982628..357e88b3263a 100644
--- a/include/linux/mtd/ndfc.h
+++ b/include/linux/mtd/ndfc.h
@@ -1,6 +1,4 @@
 /*
- *  linux/include/linux/mtd/ndfc.h
- *
  *  Copyright (c) 2006 Thomas Gleixner <tglx@linutronix.de>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/include/linux/net.h b/include/linux/net.h
index 91216b16feb7..000d1aada74f 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -146,7 +146,7 @@ struct proto_ops {
 				      struct socket *newsock, int flags, bool kern);
 	int		(*getname)   (struct socket *sock,
 				      struct sockaddr *addr,
-				      int *sockaddr_len, int peer);
+				      int peer);
 	__poll_t	(*poll)	     (struct file *file, struct socket *sock,
 				      struct poll_table_struct *wait);
 	int		(*ioctl)     (struct socket *sock, unsigned int cmd,
@@ -294,10 +294,8 @@ int kernel_listen(struct socket *sock, int backlog);
 int kernel_accept(struct socket *sock, struct socket **newsock, int flags);
 int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
 		   int flags);
-int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-		       int *addrlen);
-int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-		       int *addrlen);
+int kernel_getsockname(struct socket *sock, struct sockaddr *addr);
+int kernel_getpeername(struct socket *sock, struct sockaddr *addr);
 int kernel_getsockopt(struct socket *sock, int level, int optname, char *optval,
 		      int *optlen);
 int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5eef6c8e2741..dbe6344b727a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1798,11 +1798,17 @@ struct net_device {
 #if IS_ENABLED(CONFIG_TIPC)
 	struct tipc_bearer __rcu *tipc_ptr;
 #endif
+#if IS_ENABLED(CONFIG_IRDA) || IS_ENABLED(CONFIG_ATALK)
 	void 			*atalk_ptr;
+#endif
 	struct in_device __rcu	*ip_ptr;
+#if IS_ENABLED(CONFIG_DECNET)
 	struct dn_dev __rcu     *dn_ptr;
+#endif
 	struct inet6_dev __rcu	*ip6_ptr;
+#if IS_ENABLED(CONFIG_AX25)
 	void			*ax25_ptr;
+#endif
 	struct wireless_dev	*ieee80211_ptr;
 	struct wpan_dev		*ieee802154_ptr;
 #if IS_ENABLED(CONFIG_MPLS_ROUTING)
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
index fbc98e2c8228..e791ebc65c9c 100644
--- a/include/linux/nospec.h
+++ b/include/linux/nospec.h
@@ -5,6 +5,7 @@
 
 #ifndef _LINUX_NOSPEC_H
 #define _LINUX_NOSPEC_H
+#include <asm/barrier.h>
 
 /**
  * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
@@ -29,26 +30,6 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
 }
 #endif
 
-/*
- * Warn developers about inappropriate array_index_nospec() usage.
- *
- * Even if the CPU speculates past the WARN_ONCE branch, the
- * sign bit of @index is taken into account when generating the
- * mask.
- *
- * This warning is compiled out when the compiler can infer that
- * @index and @size are less than LONG_MAX.
- */
-#define array_index_mask_nospec_check(index, size)				\
-({										\
-	if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX,			\
-	    "array_index_nospec() limited to range of [0, LONG_MAX]\n"))	\
-		_mask = 0;							\
-	else									\
-		_mask = array_index_mask_nospec(index, size);			\
-	_mask;									\
-})
-
 /*
  * array_index_nospec - sanitize an array index after a bounds check
  *
@@ -67,12 +48,11 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
 ({									\
 	typeof(index) _i = (index);					\
 	typeof(size) _s = (size);					\
-	unsigned long _mask = array_index_mask_nospec_check(_i, _s);	\
+	unsigned long _mask = array_index_mask_nospec(_i, _s);		\
 									\
 	BUILD_BUG_ON(sizeof(_i) > sizeof(long));			\
 	BUILD_BUG_ON(sizeof(_s) > sizeof(long));			\
 									\
-	_i &= _mask;							\
-	_i;								\
+	(typeof(_i)) (_i & _mask);					\
 })
 #endif /* _LINUX_NOSPEC_H */
diff --git a/include/linux/of.h b/include/linux/of.h
index da1ee95241c1..7258bbc85e4e 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -363,6 +363,9 @@ extern struct device_node *of_parse_phandle(const struct device_node *np,
 extern int of_parse_phandle_with_args(const struct device_node *np,
 	const char *list_name, const char *cells_name, int index,
 	struct of_phandle_args *out_args);
+extern int of_parse_phandle_with_args_map(const struct device_node *np,
+	const char *list_name, const char *stem_name, int index,
+	struct of_phandle_args *out_args);
 extern int of_parse_phandle_with_fixed_args(const struct device_node *np,
 	const char *list_name, int cells_count, int index,
 	struct of_phandle_args *out_args);
@@ -815,6 +818,15 @@ static inline int of_parse_phandle_with_args(const struct device_node *np,
 	return -ENOSYS;
 }
 
+static inline int of_parse_phandle_with_args_map(const struct device_node *np,
+						 const char *list_name,
+						 const char *stem_name,
+						 int index,
+						 struct of_phandle_args *out_args)
+{
+	return -ENOSYS;
+}
+
 static inline int of_parse_phandle_with_fixed_args(const struct device_node *np,
 	const char *list_name, int cells_count, int index,
 	struct of_phandle_args *out_args)
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 5bad038ac012..d4d41c01a74d 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -10,6 +10,13 @@
 #include <linux/sched/coredump.h> /* MMF_* */
 #include <linux/mm.h> /* VM_FAULT* */
 
+
+/*
+ * Special value returned by victim selection functions to indicate
+ * that are inflight OOM victims.
+ */
+#define INFLIGHT_VICTIM ((void *)-1UL)
+
 struct zonelist;
 struct notifier_block;
 struct mem_cgroup;
@@ -40,7 +47,8 @@ struct oom_control {
 
 	/* Used by oom implementation, do not set */
 	unsigned long totalpages;
-	struct task_struct *chosen;
+	struct task_struct *chosen_task;
+	struct mem_cgroup *chosen_memcg;
 	unsigned long chosen_points;
 };
 
@@ -111,6 +119,8 @@ extern void oom_killer_enable(void);
 
 extern struct task_struct *find_lock_task_mm(struct task_struct *p);
 
+extern int oom_evaluate_task(struct task_struct *task, void *arg);
+
 /* sysctls */
 extern int sysctl_oom_dump_tasks;
 extern int sysctl_oom_kill_allocating_task;
diff --git a/include/linux/page-isolation.h b/include/linux/page-isolation.h
index cdad58bbfd8b..4ae347cbc36d 100644
--- a/include/linux/page-isolation.h
+++ b/include/linux/page-isolation.h
@@ -63,7 +63,6 @@ undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
 int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
 			bool skip_hwpoisoned_pages);
 
-struct page *alloc_migrate_target(struct page *page, unsigned long private,
-				int **resultp);
+struct page *alloc_migrate_target(struct page *page, unsigned long private);
 
 #endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 024a1beda008..25b7a3535d26 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -949,11 +949,6 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
 struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
 struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
 					    unsigned int devfn);
-static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
-						   unsigned int devfn)
-{
-	return pci_get_domain_bus_and_slot(0, bus, devfn);
-}
 struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
 int pci_dev_present(const struct pci_device_id *ids);
 
@@ -1661,9 +1656,6 @@ static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
 static inline struct pci_dev *pci_get_slot(struct pci_bus *bus,
 						unsigned int devfn)
 { return NULL; }
-static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
-						unsigned int devfn)
-{ return NULL; }
 static inline struct pci_dev *pci_get_domain_bus_and_slot(int domain,
 					unsigned int bus, unsigned int devfn)
 { return NULL; }
diff --git a/include/linux/platform_data/asoc-ti-mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h
index e684543254f3..e319d0a2ec82 100644
--- a/include/linux/platform_data/asoc-ti-mcbsp.h
+++ b/include/linux/platform_data/asoc-ti-mcbsp.h
@@ -25,10 +25,6 @@
 #include <linux/spinlock.h>
 #include <linux/clk.h>
 
-#define MCBSP_CONFIG_TYPE2	0x2
-#define MCBSP_CONFIG_TYPE3	0x3
-#define MCBSP_CONFIG_TYPE4	0x4
-
 /* Platform specific configuration */
 struct omap_mcbsp_ops {
 	void (*request)(unsigned int);
@@ -47,14 +43,6 @@ struct omap_mcbsp_platform_data {
 	int (*force_ick_on)(struct clk *clk, bool force_on);
 };
 
-/**
- * omap_mcbsp_dev_attr - OMAP McBSP device attributes for omap_hwmod
- * @sidetone: name of the sidetone device
- */
-struct omap_mcbsp_dev_attr {
-	const char *sidetone;
-};
-
 void omap3_mcbsp_init_pdata_callback(struct omap_mcbsp_platform_data *pdata);
 
 #endif
diff --git a/include/linux/platform_data/gpio-omap.h b/include/linux/platform_data/gpio-omap.h
index cb2618147c34..8612855691b2 100644
--- a/include/linux/platform_data/gpio-omap.h
+++ b/include/linux/platform_data/gpio-omap.h
@@ -157,11 +157,6 @@
 #define OMAP_MPUIO(nr)		(OMAP_MAX_GPIO_LINES + (nr))
 #define OMAP_GPIO_IS_MPUIO(nr)	((nr) >= OMAP_MAX_GPIO_LINES)
 
-struct omap_gpio_dev_attr {
-	int bank_width;		/* GPIO bank width */
-	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
-};
-
 struct omap_gpio_reg_offs {
 	u16 revision;
 	u16 direction;
diff --git a/include/linux/platform_data/spi-omap2-mcspi.h b/include/linux/platform_data/spi-omap2-mcspi.h
index 13c83a25958a..0bf9fddb8306 100644
--- a/include/linux/platform_data/spi-omap2-mcspi.h
+++ b/include/linux/platform_data/spi-omap2-mcspi.h
@@ -2,10 +2,6 @@
 #ifndef _OMAP2_MCSPI_H
 #define _OMAP2_MCSPI_H
 
-#define OMAP2_MCSPI_REV 0
-#define OMAP3_MCSPI_REV 1
-#define OMAP4_MCSPI_REV 2
-
 #define OMAP4_MCSPI_REG_OFFSET 0x100
 
 #define MCSPI_PINDIR_D0_IN_D1_OUT	0
@@ -17,10 +13,6 @@ struct omap2_mcspi_platform_config {
 	unsigned int pin_dir:1;
 };
 
-struct omap2_mcspi_dev_attr {
-	unsigned short num_chipselect;
-};
-
 struct omap2_mcspi_device_config {
 	unsigned turbo_mode:1;
 
diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
index a079656b614c..059242030631 100644
--- a/include/linux/ptp_classify.h
+++ b/include/linux/ptp_classify.h
@@ -75,5 +75,9 @@ void __init ptp_classifier_init(void);
 static inline void ptp_classifier_init(void)
 {
 }
+static inline unsigned int ptp_classify_raw(struct sk_buff *skb)
+{
+	return PTP_CLASS_NONE;
+}
 #endif
 #endif /* _PTP_CLASSIFY_H_ */
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index b884b7794187..6894976b54e3 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -296,13 +296,14 @@ static inline void *__ptr_ring_consume(struct ptr_ring *r)
 {
 	void *ptr;
 
+	/* The READ_ONCE in __ptr_ring_peek guarantees that anyone
+	 * accessing data through the pointer is up to date. Pairs
+	 * with smp_wmb in __ptr_ring_produce.
+	 */
 	ptr = __ptr_ring_peek(r);
 	if (ptr)
 		__ptr_ring_discard_one(r);
 
-	/* Make sure anyone accessing data through the pointer is up to date. */
-	/* Pairs with smp_wmb in __ptr_ring_produce. */
-	smp_read_barrier_depends();
 	return ptr;
 }
 
@@ -469,7 +470,7 @@ static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r,
  */
 static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp)
 {
-	if (size * sizeof(void *) > KMALLOC_MAX_SIZE)
+	if (size > KMALLOC_MAX_SIZE / sizeof(void *))
 		return NULL;
 	return kvmalloc_array(size, sizeof(void *), gfp | __GFP_ZERO);
 }
diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h
index 31e1ff69efc8..ec8655514283 100644
--- a/include/linux/raid_class.h
+++ b/include/linux/raid_class.h
@@ -38,6 +38,7 @@ enum raid_level {
 	RAID_LEVEL_5,
 	RAID_LEVEL_50,
 	RAID_LEVEL_6,
+	RAID_LEVEL_JBOD,
 };
 
 struct raid_data {
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 043d04784675..36360d07f25b 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -214,10 +214,12 @@ do { \
 #endif
 
 /*
- * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic
- * initialization and destruction of rcu_head on the stack. rcu_head structures
- * allocated dynamically in the heap or defined statically don't need any
- * initialization.
+ * The init_rcu_head_on_stack() and destroy_rcu_head_on_stack() calls
+ * are needed for dynamic initialization and destruction of rcu_head
+ * on the stack, and init_rcu_head()/destroy_rcu_head() are needed for
+ * dynamic initialization and destruction of statically allocated rcu_head
+ * structures.  However, rcu_head structures allocated dynamically in the
+ * heap don't need any initialization.
  */
 #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
 void init_rcu_head(struct rcu_head *head);
diff --git a/include/linux/regulator/da9211.h b/include/linux/regulator/da9211.h
index f2fd2d3bf58f..d1f2073e4d5f 100644
--- a/include/linux/regulator/da9211.h
+++ b/include/linux/regulator/da9211.h
@@ -21,6 +21,8 @@
 
 #define DA9211_MAX_REGULATORS	2
 
+struct gpio_desc;
+
 enum da9211_chip_id {
 	DA9211,
 	DA9212,
@@ -39,7 +41,7 @@ struct da9211_pdata {
 	 * 2 : 2 phase 2 buck
 	 */
 	int num_buck;
-	int gpio_ren[DA9211_MAX_REGULATORS];
+	struct gpio_desc *gpiod_ren[DA9211_MAX_REGULATORS];
 	struct device_node *reg_node[DA9211_MAX_REGULATORS];
 	struct regulator_init_data *init_data[DA9211_MAX_REGULATORS];
 };
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 4c00486b7a78..4fc96cb8e5d7 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -19,6 +19,7 @@
 #include <linux/notifier.h>
 #include <linux/regulator/consumer.h>
 
+struct gpio_desc;
 struct regmap;
 struct regulator_dev;
 struct regulator_config;
@@ -387,6 +388,7 @@ struct regulator_desc {
  *                        initialized, meaning that >= 0 is a valid gpio
  *                        identifier and < 0 is a non existent gpio.
  * @ena_gpio: GPIO controlling regulator enable.
+ * @ena_gpiod: GPIO descriptor controlling regulator enable.
  * @ena_gpio_invert: Sense for GPIO enable control.
  * @ena_gpio_flags: Flags to use when calling gpio_request_one()
  */
@@ -399,6 +401,7 @@ struct regulator_config {
 
 	bool ena_gpio_initialized;
 	int ena_gpio;
+	struct gpio_desc *ena_gpiod;
 	unsigned int ena_gpio_invert:1;
 	unsigned int ena_gpio_flags;
 };
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 728d421fffe9..d09a9c7af109 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -344,7 +344,7 @@ struct rproc_ops {
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
 	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
-	int (*load_rsc_table)(struct rproc *rproc, const struct firmware *fw);
+	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	struct resource_table *(*find_loaded_rsc_table)(
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
@@ -394,6 +394,21 @@ enum rproc_crash_type {
 	RPROC_FATAL_ERROR,
 };
 
+/**
+ * struct rproc_dump_segment - segment info from ELF header
+ * @node:	list node related to the rproc segment list
+ * @da:		device address of the segment
+ * @size:	size of the segment
+ */
+struct rproc_dump_segment {
+	struct list_head node;
+
+	dma_addr_t da;
+	size_t size;
+
+	loff_t offset;
+};
+
 /**
  * struct rproc - represents a physical remote processor device
  * @node: list node of this rproc object
@@ -424,6 +439,7 @@ enum rproc_crash_type {
  * @cached_table: copy of the resource table
  * @table_sz: size of @cached_table
  * @has_iommu: flag to indicate if remote processor is behind an MMU
+ * @dump_segments: list of segments in the firmware
  */
 struct rproc {
 	struct list_head node;
@@ -455,19 +471,21 @@ struct rproc {
 	size_t table_sz;
 	bool has_iommu;
 	bool auto_boot;
+	struct list_head dump_segments;
 };
 
 /**
  * struct rproc_subdev - subdevice tied to a remoteproc
  * @node: list node related to the rproc subdevs list
  * @probe: probe function, called as the rproc is started
- * @remove: remove function, called as the rproc is stopped
+ * @remove: remove function, called as the rproc is being stopped, the @crashed
+ *	    parameter indicates if this originates from the a recovery
  */
 struct rproc_subdev {
 	struct list_head node;
 
 	int (*probe)(struct rproc_subdev *subdev);
-	void (*remove)(struct rproc_subdev *subdev);
+	void (*remove)(struct rproc_subdev *subdev, bool crashed);
 };
 
 /* we currently support only two vrings per rvdev */
@@ -534,6 +552,7 @@ void rproc_free(struct rproc *rproc);
 int rproc_boot(struct rproc *rproc);
 void rproc_shutdown(struct rproc *rproc);
 void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
+int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size);
 
 static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
 {
@@ -550,7 +569,7 @@ static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
 void rproc_add_subdev(struct rproc *rproc,
 		      struct rproc_subdev *subdev,
 		      int (*probe)(struct rproc_subdev *subdev),
-		      void (*remove)(struct rproc_subdev *subdev));
+		      void (*remove)(struct rproc_subdev *subdev, bool graceful));
 
 void rproc_remove_subdev(struct rproc *rproc, struct rproc_subdev *subdev);
 
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index fc6c90b57be0..3b65b201169c 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -145,7 +145,6 @@ struct rtc_device {
 
 	bool registered;
 
-	struct nvmem_config *nvmem_config;
 	struct nvmem_device *nvmem;
 	/* Old ABI support */
 	bool nvram_old_abi;
@@ -212,10 +211,6 @@ void rtc_aie_update_irq(void *private);
 void rtc_uie_update_irq(void *private);
 enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer);
 
-int rtc_register(rtc_task_t *task);
-int rtc_unregister(rtc_task_t *task);
-int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
-
 void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data);
 int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
 		    ktime_t expires, ktime_t period);
@@ -271,4 +266,17 @@ extern int rtc_hctosys_ret;
 #define rtc_hctosys_ret -ENODEV
 #endif
 
+#ifdef CONFIG_RTC_NVMEM
+int rtc_nvmem_register(struct rtc_device *rtc,
+		       struct nvmem_config *nvmem_config);
+void rtc_nvmem_unregister(struct rtc_device *rtc);
+#else
+static inline int rtc_nvmem_register(struct rtc_device *rtc,
+				     struct nvmem_config *nvmem_config)
+{
+	return -ENODEV;
+}
+static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
+#endif
+
 #endif /* _LINUX_RTC_H_ */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 1fdcde96eb65..e9ee9ad0a681 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -36,6 +36,7 @@ extern int rtnl_is_locked(void);
 
 extern wait_queue_head_t netdev_unregistering_wq;
 extern struct mutex net_mutex;
+extern struct rw_semaphore net_sem;
 
 #ifdef CONFIG_PROVE_LOCKING
 extern bool lockdep_rtnl_is_held(void);
diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h
index 1149533aa2fa..59946c9fe05a 100644
--- a/include/linux/sched/mm.h
+++ b/include/linux/sched/mm.h
@@ -36,7 +36,13 @@ static inline void mmgrab(struct mm_struct *mm)
 	atomic_inc(&mm->mm_count);
 }
 
-extern void mmdrop(struct mm_struct *mm);
+extern void __mmdrop(struct mm_struct *mm);
+
+static inline void mmdrop(struct mm_struct *mm)
+{
+	if (unlikely(atomic_dec_and_test(&mm->mm_count)))
+		__mmdrop(mm);
+}
 
 /**
  * mmget() - Pin the address space associated with a &struct mm_struct.
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 23b4f9cb82db..18f2b9a6c137 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -104,6 +104,9 @@ struct signal_struct {
 	int			group_stop_count;
 	unsigned int		flags; /* see SIGNAL_* flags below */
 
+	/* The signal sent when the parent dies: */
+	int			pdeath_signal_proc;
+
 	/*
 	 * PR_SET_CHILD_SUBREAPER marks a process, like a service
 	 * manager, to re-parent orphan (double-forking) child processes
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index ab437dd2e3b9..440f1351ad57 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -121,6 +121,9 @@ void seq_puts(struct seq_file *m, const char *s);
 void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
 			 unsigned long long num);
 void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num);
+void seq_put_hex_ll(struct seq_file *m, const char *delimiter,
+		    unsigned long long v, int width);
+
 void seq_escape(struct seq_file *m, const char *s, const char *esc);
 
 void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h
index a7f004a3c177..463ed28d2b27 100644
--- a/include/linux/serial_s3c.h
+++ b/include/linux/serial_s3c.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  *  Internal header file for Samsung S3C2410 serial ports (UART0-2)
  *
@@ -10,21 +11,7 @@
  *  Internal header file for MX1ADS serial ports (UART1 & 2)
  *
  *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
+ */
 
 #ifndef __ASM_ARM_REGS_SERIAL_H
 #define __ASM_ARM_REGS_SERIAL_H
diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index 388ff2936a87..a3894918a436 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -75,6 +75,6 @@ struct shrinker {
 #define SHRINKER_NUMA_AWARE	(1 << 0)
 #define SHRINKER_MEMCG_AWARE	(1 << 1)
 
-extern int register_shrinker(struct shrinker *);
+extern __must_check int register_shrinker(struct shrinker *);
 extern void unregister_shrinker(struct shrinker *);
 #endif
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 5ebc0f869720..9bc1750ca3d3 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -466,6 +466,9 @@ struct ubuf_info {
 
 #define skb_uarg(SKB)	((struct ubuf_info *)(skb_shinfo(SKB)->destructor_arg))
 
+int mm_account_pinned_pages(struct mmpin *mmp, size_t size);
+void mm_unaccount_pinned_pages(struct mmpin *mmp);
+
 struct ubuf_info *sock_zerocopy_alloc(struct sock *sk, size_t size);
 struct ubuf_info *sock_zerocopy_realloc(struct sock *sk, size_t size,
 					struct ubuf_info *uarg);
@@ -3646,7 +3649,7 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
 	return true;
 }
 
-/* For small packets <= CHECKSUM_BREAK peform checksum complete directly
+/* For small packets <= CHECKSUM_BREAK perform checksum complete directly
  * in checksum_init.
  */
 #define CHECKSUM_BREAK 76
diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h
index bd8e0864b059..5b98bbdabc25 100644
--- a/include/linux/soc/qcom/mdt_loader.h
+++ b/include/linux/soc/qcom/mdt_loader.h
@@ -14,6 +14,7 @@ struct firmware;
 ssize_t qcom_mdt_get_size(const struct firmware *fw);
 int qcom_mdt_load(struct device *dev, const struct firmware *fw,
 		  const char *fw_name, int pas_id, void *mem_region,
-		  phys_addr_t mem_phys, size_t mem_size);
+		  phys_addr_t mem_phys, size_t mem_size,
+		  phys_addr_t *reloc_base);
 
 #endif
diff --git a/include/linux/soc/samsung/exynos-pmu.h b/include/linux/soc/samsung/exynos-pmu.h
index e57eb4b6cc5a..fc0b445bb36b 100644
--- a/include/linux/soc/samsung/exynos-pmu.h
+++ b/include/linux/soc/samsung/exynos-pmu.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * Header for EXYNOS PMU Driver support
- *
- * 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 __LINUX_SOC_EXYNOS_PMU_H
diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h
index bebdde5dccd6..66dcb9ec273a 100644
--- a/include/linux/soc/samsung/exynos-regs-pmu.h
+++ b/include/linux/soc/samsung/exynos-regs-pmu.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2010-2015 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * EXYNOS - Power management unit definition
  *
- * 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.
- *
- *
  * Notice:
  * This is not a list of all Exynos Power Management Unit SFRs.
  * There are too many of them, not mentioning subtle differences
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 9286a5a8c60c..1ce1f768a58c 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -353,4 +353,6 @@ extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen
 			  unsigned int flags, struct timespec *timeout);
 extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
 			  unsigned int vlen, unsigned int flags);
+
+extern struct ns_common *get_net_ns(struct ns_common *ns);
 #endif /* _LINUX_SOCKET_H */
diff --git a/include/linux/spi/spi_gpio.h b/include/linux/spi/spi_gpio.h
index e7bd89a59cd1..9e7e83d8645b 100644
--- a/include/linux/spi/spi_gpio.h
+++ b/include/linux/spi/spi_gpio.h
@@ -8,64 +8,17 @@
  *   - id the same as the SPI bus number it implements
  *   - dev.platform data pointing to a struct spi_gpio_platform_data
  *
- * Or, see the driver code for information about speedups that are
- * possible on platforms that support inlined access for GPIOs (no
- * spi_gpio_platform_data is used).
- *
- * Use spi_board_info with these busses in the usual way, being sure
- * that the controller_data being the GPIO used for each device's
- * chipselect:
- *
- *	static struct spi_board_info ... [] = {
- *	...
- *		// this slave uses GPIO 42 for its chipselect
- *		.controller_data = (void *) 42,
- *	...
- *		// this one uses GPIO 86 for its chipselect
- *		.controller_data = (void *) 86,
- *	...
- *	};
- *
- * If chipselect is not used (there's only one device on the bus), assign
- * SPI_GPIO_NO_CHIPSELECT to the controller_data:
- *		.controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
- *
- * If the MISO or MOSI pin is not available then it should be set to
- * SPI_GPIO_NO_MISO or SPI_GPIO_NO_MOSI.
+ * Use spi_board_info with these busses in the usual way.
  *
  * If the bitbanged bus is later switched to a "native" controller,
  * that platform_device and controller_data should be removed.
  */
 
-#define SPI_GPIO_NO_CHIPSELECT		((unsigned long)-1l)
-#define SPI_GPIO_NO_MISO		((unsigned long)-1l)
-#define SPI_GPIO_NO_MOSI		((unsigned long)-1l)
-
 /**
  * struct spi_gpio_platform_data - parameter for bitbanged SPI master
- * @sck: number of the GPIO used for clock output
- * @mosi: number of the GPIO used for Master Output, Slave In (MOSI) data
- * @miso: number of the GPIO used for Master Input, Slave Output (MISO) data
  * @num_chipselect: how many slaves to allow
- *
- * All GPIO signals used with the SPI bus managed through this driver
- * (chipselects, MOSI, MISO, SCK) must be configured as GPIOs, instead
- * of some alternate function.
- *
- * It can be convenient to use this driver with pins that have alternate
- * functions associated with a "native" SPI controller if a driver for that
- * controller is not available, or is missing important functionality.
- *
- * On platforms which can do so, configure MISO with a weak pullup unless
- * there's an external pullup on that signal.  That saves power by avoiding
- * floating signals.  (A weak pulldown would save power too, but many
- * drivers expect to see all-ones data as the no slave "response".)
  */
 struct spi_gpio_platform_data {
-	unsigned	sck;
-	unsigned long	mosi;
-	unsigned long	miso;
-
 	u16		num_chipselect;
 };
 
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 7b6a59f722a3..a1a3f4ed94ce 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -337,8 +337,6 @@ extern void deactivate_file_page(struct page *page);
 extern void mark_page_lazyfree(struct page *page);
 extern void swap_setup(void);
 
-extern void add_page_to_unevictable_list(struct page *page);
-
 extern void lru_cache_add_active_or_unevictable(struct page *page,
 						struct vm_area_struct *vma);
 
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index b17bcce58bc4..588a0e4b1ab9 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -31,6 +31,7 @@ struct timespec64 get_monotonic_coarse64(void);
 extern void getrawmonotonic64(struct timespec64 *ts);
 extern void ktime_get_ts64(struct timespec64 *ts);
 extern time64_t ktime_get_seconds(void);
+extern time64_t __ktime_get_real_seconds(void);
 extern time64_t ktime_get_real_seconds(void);
 
 extern int __getnstimeofday64(struct timespec64 *tv);
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 8a1442c4e513..c20acfcf647d 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -540,6 +540,14 @@ extern int  perf_trace_init(struct perf_event *event);
 extern void perf_trace_destroy(struct perf_event *event);
 extern int  perf_trace_add(struct perf_event *event, int flags);
 extern void perf_trace_del(struct perf_event *event, int flags);
+#ifdef CONFIG_KPROBE_EVENTS
+extern int  perf_kprobe_init(struct perf_event *event, bool is_retprobe);
+extern void perf_kprobe_destroy(struct perf_event *event);
+#endif
+#ifdef CONFIG_UPROBE_EVENTS
+extern int  perf_uprobe_init(struct perf_event *event, bool is_retprobe);
+extern void perf_uprobe_destroy(struct perf_event *event);
+#endif
 extern int  ftrace_profile_set_filter(struct perf_event *event, int event_id,
 				     char *filter_str);
 extern void ftrace_profile_free_filter(struct perf_event *event);
diff --git a/include/linux/types.h b/include/linux/types.h
index c94d59ef96cc..ec13d02b3481 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -217,7 +217,7 @@ struct ustat {
  *
  * This guarantee is important for few reasons:
  *  - future call_rcu_lazy() will make use of lower bits in the pointer;
- *  - the structure shares storage spacer in struct page with @compound_head,
+ *  - the structure shares storage space in struct page with @compound_head,
  *    which encode PageTail() in bit 0. The guarantee is needed to avoid
  *    false-positive PageTail().
  */
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 55a611486bac..d9f131ecf708 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -599,6 +599,120 @@ do {										\
 	__ret;									\
 })
 
+/**
+ * wait_event_idle - wait for a condition without contributing to system load
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true.
+ * The @condition is checked each time the waitqueue @wq_head is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ */
+#define wait_event_idle(wq_head, condition)					\
+do {										\
+	might_sleep();								\
+	if (!(condition))							\
+		___wait_event(wq_head, condition, TASK_IDLE, 0, 0, schedule());	\
+} while (0)
+
+/**
+ * wait_event_idle_exclusive - wait for a condition with contributing to system load
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true.
+ * The @condition is checked each time the waitqueue @wq_head is woken up.
+ *
+ * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag
+ * set thus if other processes wait on the same list, when this
+ * process is woken further processes are not considered.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ */
+#define wait_event_idle_exclusive(wq_head, condition)				\
+do {										\
+	might_sleep();								\
+	if (!(condition))							\
+		___wait_event(wq_head, condition, TASK_IDLE, 1, 0, schedule());	\
+} while (0)
+
+#define __wait_event_idle_timeout(wq_head, condition, timeout)			\
+	___wait_event(wq_head, ___wait_cond_timeout(condition),			\
+		      TASK_IDLE, 0, timeout,					\
+		      __ret = schedule_timeout(__ret))
+
+/**
+ * wait_event_idle_timeout - sleep without load until a condition becomes true or a timeout elapses
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq_head is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * Returns:
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * or the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed.
+ */
+#define wait_event_idle_timeout(wq_head, condition, timeout)			\
+({										\
+	long __ret = timeout;							\
+	might_sleep();								\
+	if (!___wait_cond_timeout(condition))					\
+		__ret = __wait_event_idle_timeout(wq_head, condition, timeout);	\
+	__ret;									\
+})
+
+#define __wait_event_idle_exclusive_timeout(wq_head, condition, timeout)	\
+	___wait_event(wq_head, ___wait_cond_timeout(condition),			\
+		      TASK_IDLE, 1, timeout,					\
+		      __ret = schedule_timeout(__ret))
+
+/**
+ * wait_event_idle_exclusive_timeout - sleep without load until a condition becomes true or a timeout elapses
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq_head is woken up.
+ *
+ * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag
+ * set thus if other processes wait on the same list, when this
+ * process is woken further processes are not considered.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * Returns:
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * or the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed.
+ */
+#define wait_event_idle_exclusive_timeout(wq_head, condition, timeout)		\
+({										\
+	long __ret = timeout;							\
+	might_sleep();								\
+	if (!___wait_cond_timeout(condition))					\
+		__ret = __wait_event_idle_exclusive_timeout(wq_head, condition, timeout);\
+	__ret;									\
+})
+
 extern int do_wait_intr(wait_queue_head_t *, wait_queue_entry_t *);
 extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *);
 
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 4a54ef96aff5..bc0cda180c8b 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -465,6 +465,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
 
 extern void workqueue_set_max_active(struct workqueue_struct *wq,
 				     int max_active);
+extern struct work_struct *current_work(void);
 extern bool current_is_workqueue_rescuer(void);
 extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
 extern unsigned int work_busy(struct work_struct *work);
diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h
index 57ec319a7f44..cf0add70b0e7 100644
--- a/include/media/cec-notifier.h
+++ b/include/media/cec-notifier.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * cec-notifier.h - notify CEC drivers of physical address changes
  *
  * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
  * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef LINUX_CEC_NOTIFIER_H
diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h
index 83b3e17e0a07..ed16c6dde0ba 100644
--- a/include/media/cec-pin.h
+++ b/include/media/cec-pin.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * cec-pin.h - low-level CEC pin control
  *
  * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef LINUX_CEC_PIN_H
diff --git a/include/media/cec.h b/include/media/cec.h
index 7cdf71d7125a..9afba9b558df 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * cec - HDMI Consumer Electronics Control support header
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _MEDIA_CEC_H
diff --git a/include/media/i2c/ad9389b.h b/include/media/i2c/ad9389b.h
index 5ba9af869b8b..30f9ea9a1273 100644
--- a/include/media/i2c/ad9389b.h
+++ b/include/media/i2c/ad9389b.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Analog Devices AD9389B/AD9889B video encoder driver header
  *
  * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef AD9389B_H
diff --git a/include/media/i2c/adv7511.h b/include/media/i2c/adv7511.h
index 61c3d711cc69..1874c05f486f 100644
--- a/include/media/i2c/adv7511.h
+++ b/include/media/i2c/adv7511.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Analog Devices ADV7511 HDMI Transmitter Device Driver
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef ADV7511_H
diff --git a/include/media/i2c/adv7604.h b/include/media/i2c/adv7604.h
index 2e6857dee0cc..77a9799128b6 100644
--- a/include/media/i2c/adv7604.h
+++ b/include/media/i2c/adv7604.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * adv7604 - Analog Devices ADV7604 video decoder driver
  *
  * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 #ifndef _ADV7604_
diff --git a/include/media/i2c/adv7842.h b/include/media/i2c/adv7842.h
index 7f53ada9bdf1..05e01f0dd3c2 100644
--- a/include/media/i2c/adv7842.h
+++ b/include/media/i2c/adv7842.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * adv7842 - Analog Devices ADV7842 video decoder driver
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 #ifndef _ADV7842_
diff --git a/include/media/i2c/tc358743.h b/include/media/i2c/tc358743.h
index 4513f2f9cfbc..b343650c2948 100644
--- a/include/media/i2c/tc358743.h
+++ b/include/media/i2c/tc358743.h
@@ -1,22 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * tc358743 - Toshiba HDMI to CSI-2 bridge
  *
- * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
- * reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  */
 
 /*
diff --git a/include/media/i2c/ths7303.h b/include/media/i2c/ths7303.h
index 834e2f95b630..95492d12786d 100644
--- a/include/media/i2c/ths7303.h
+++ b/include/media/i2c/ths7303.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (C) 2013 Texas Instruments Inc
  *
@@ -7,15 +8,6 @@
  *     Hans Verkuil <hans.verkuil@cisco.com>
  *     Lad, Prabhakar <prabhakar.lad@ti.com>
  *     Martin Bugge <marbugge@cisco.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #ifndef THS7353_H
diff --git a/include/media/i2c/uda1342.h b/include/media/i2c/uda1342.h
index cd156403a368..cb412d4c1088 100644
--- a/include/media/i2c/uda1342.h
+++ b/include/media/i2c/uda1342.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * uda1342.h - definition for uda1342 inputs
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 #ifndef _UDA1342_H_
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index aed4272d47f5..fc3a92668bab 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -23,13 +23,6 @@
 #include <linux/timer.h>
 #include <media/rc-map.h>
 
-extern int rc_core_debug;
-#define IR_dprintk(level, fmt, ...)				\
-do {								\
-	if (rc_core_debug >= level)				\
-		printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__);	\
-} while (0)
-
 /**
  * enum rc_driver_type - type of the RC driver.
  *
diff --git a/include/media/tpg/v4l2-tpg.h b/include/media/tpg/v4l2-tpg.h
index 823fadede7bf..eb191e85d363 100644
--- a/include/media/tpg/v4l2-tpg.h
+++ b/include/media/tpg/v4l2-tpg.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * v4l2-tpg.h - Test Pattern Generator
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _V4L2_TPG_H_
diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h
index ebf00e07a515..8778263a8f5d 100644
--- a/include/media/v4l2-dv-timings.h
+++ b/include/media/v4l2-dv-timings.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * v4l2-dv-timings - Internal header with dv-timings helper functions
  *
  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
  */
 
 #ifndef __V4L2_DV_TIMINGS_H
diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h
index d2125f0cc7cd..595c3ba05f23 100644
--- a/include/media/v4l2-rect.h
+++ b/include/media/v4l2-rect.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * v4l2-rect.h - v4l2_rect helper functions
  *
  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _V4L2_RECT_H_
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 6ed9692f20bd..9c2f22695025 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -87,12 +87,15 @@ struct tc_action_ops {
 		       struct tcf_result *);
 	int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
 	void	(*cleanup)(struct tc_action *);
-	int     (*lookup)(struct net *, struct tc_action **, u32);
+	int     (*lookup)(struct net *net, struct tc_action **a, u32 index,
+			  struct netlink_ext_ack *extack);
 	int     (*init)(struct net *net, struct nlattr *nla,
 			struct nlattr *est, struct tc_action **act, int ovr,
-			int bind);
+			int bind, struct netlink_ext_ack *extack);
 	int     (*walk)(struct net *, struct sk_buff *,
-			struct netlink_callback *, int, const struct tc_action_ops *);
+			struct netlink_callback *, int,
+			const struct tc_action_ops *,
+			struct netlink_ext_ack *);
 	void	(*stats_update)(struct tc_action *, u64, u32, u64);
 	struct net_device *(*get_dev)(const struct tc_action *a);
 };
@@ -137,7 +140,8 @@ static inline void tc_action_net_exit(struct list_head *net_list,
 
 int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
 		       struct netlink_callback *cb, int type,
-		       const struct tc_action_ops *ops);
+		       const struct tc_action_ops *ops,
+		       struct netlink_ext_ack *extack);
 int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
 bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
 		    int bind);
@@ -162,10 +166,11 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
 		    int nr_actions, struct tcf_result *res);
 int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
 		    struct nlattr *est, char *name, int ovr, int bind,
-		    struct list_head *actions);
+		    struct list_head *actions, struct netlink_ext_ack *extack);
 struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 				    struct nlattr *nla, struct nlattr *est,
-				    char *name, int ovr, int bind);
+				    char *name, int ovr, int bind,
+				    struct netlink_ext_ack *extack);
 int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
 int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 76fb39c272a7..c91bc87931c7 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -318,10 +318,12 @@ void ax25_digi_invert(const ax25_digi *, ax25_digi *);
 extern ax25_dev *ax25_dev_list;
 extern spinlock_t ax25_dev_lock;
 
+#if IS_ENABLED(CONFIG_AX25)
 static inline ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
 {
 	return dev->ax25_ptr;
 }
+#endif
 
 ax25_dev *ax25_addr_ax25dev(ax25_address *);
 void ax25_dev_device_up(struct net_device *);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 81174f9b8d14..56e905cd4b07 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1147,6 +1147,7 @@ struct cfg80211_tid_stats {
  * @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer
  * @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
  *	(IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
+ * @ack_signal: signal strength (in dBm) of the last ACK frame.
  */
 struct station_info {
 	u64 filled;
@@ -1191,6 +1192,7 @@ struct station_info {
 	u64 rx_duration;
 	u8 rx_beacon_signal_avg;
 	struct cfg80211_tid_stats pertid[IEEE80211_NUM_TIDS + 1];
+	s8 ack_signal;
 };
 
 #if IS_ENABLED(CONFIG_CFG80211)
@@ -1905,11 +1907,16 @@ struct cfg80211_auth_request {
  * @ASSOC_REQ_DISABLE_HT:  Disable HT (802.11n)
  * @ASSOC_REQ_DISABLE_VHT:  Disable VHT
  * @ASSOC_REQ_USE_RRM: Declare RRM capability in this association
+ * @CONNECT_REQ_EXTERNAL_AUTH_SUPPORT: User space indicates external
+ *	authentication capability. Drivers can offload authentication to
+ *	userspace if this flag is set. Only applicable for cfg80211_connect()
+ *	request (connect callback).
  */
 enum cfg80211_assoc_req_flags {
-	ASSOC_REQ_DISABLE_HT		= BIT(0),
-	ASSOC_REQ_DISABLE_VHT		= BIT(1),
-	ASSOC_REQ_USE_RRM		= BIT(2),
+	ASSOC_REQ_DISABLE_HT			= BIT(0),
+	ASSOC_REQ_DISABLE_VHT			= BIT(1),
+	ASSOC_REQ_USE_RRM			= BIT(2),
+	CONNECT_REQ_EXTERNAL_AUTH_SUPPORT	= BIT(3),
 };
 
 /**
@@ -2600,6 +2607,33 @@ struct cfg80211_pmk_conf {
 	const u8 *pmk_r0_name;
 };
 
+/**
+ * struct cfg80211_external_auth_params - Trigger External authentication.
+ *
+ * Commonly used across the external auth request and event interfaces.
+ *
+ * @action: action type / trigger for external authentication. Only significant
+ *	for the authentication request event interface (driver to user space).
+ * @bssid: BSSID of the peer with which the authentication has
+ *	to happen. Used by both the authentication request event and
+ *	authentication response command interface.
+ * @ssid: SSID of the AP.  Used by both the authentication request event and
+ *	authentication response command interface.
+ * @key_mgmt_suite: AKM suite of the respective authentication. Used by the
+ *	authentication request event interface.
+ * @status: status code, %WLAN_STATUS_SUCCESS for successful authentication,
+ *	use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space cannot give you
+ *	the real status code for failures. Used only for the authentication
+ *	response command interface (user space to driver).
+ */
+struct cfg80211_external_auth_params {
+	enum nl80211_external_auth_action action;
+	u8 bssid[ETH_ALEN] __aligned(2);
+	struct cfg80211_ssid ssid;
+	unsigned int key_mgmt_suite;
+	u16 status;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -2923,6 +2957,9 @@ struct cfg80211_pmk_conf {
  *	(invoked with the wireless_dev mutex held)
  * @del_pmk: delete the previously configured PMK for the given authenticator.
  *	(invoked with the wireless_dev mutex held)
+ *
+ * @external_auth: indicates result of offloaded authentication processing from
+ *     user space
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3216,6 +3253,8 @@ struct cfg80211_ops {
 			   const struct cfg80211_pmk_conf *conf);
 	int	(*del_pmk)(struct wiphy *wiphy, struct net_device *dev,
 			   const u8 *aa);
+	int     (*external_auth)(struct wiphy *wiphy, struct net_device *dev,
+				 struct cfg80211_external_auth_params *params);
 };
 
 /*
@@ -3516,6 +3555,35 @@ enum wiphy_vendor_command_flags {
 	WIPHY_VENDOR_CMD_NEED_RUNNING = BIT(2),
 };
 
+/**
+ * enum wiphy_opmode_flag - Station's ht/vht operation mode information flags
+ *
+ * @STA_OPMODE_MAX_BW_CHANGED: Max Bandwidth changed
+ * @STA_OPMODE_SMPS_MODE_CHANGED: SMPS mode changed
+ * @STA_OPMODE_N_SS_CHANGED: max N_SS (number of spatial streams) changed
+ *
+ */
+enum wiphy_opmode_flag {
+	STA_OPMODE_MAX_BW_CHANGED	= BIT(0),
+	STA_OPMODE_SMPS_MODE_CHANGED	= BIT(1),
+	STA_OPMODE_N_SS_CHANGED		= BIT(2),
+};
+
+/**
+ * struct sta_opmode_info - Station's ht/vht operation mode information
+ * @changed: contains value from &enum wiphy_opmode_flag
+ * @smps_mode: New SMPS mode of a station
+ * @bw: new max bandwidth value of a station
+ * @rx_nss: new rx_nss value of a station
+ */
+
+struct sta_opmode_info {
+	u32 changed;
+	u8 smps_mode;
+	u8 bw;
+	u8 rx_nss;
+};
+
 /**
  * struct wiphy_vendor_command - vendor command definition
  * @info: vendor command identifying information, as used in nl80211
@@ -5684,6 +5752,20 @@ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
 void cfg80211_radar_event(struct wiphy *wiphy,
 			  struct cfg80211_chan_def *chandef, gfp_t gfp);
 
+/**
+ * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event
+ * @dev: network device
+ * @mac: MAC address of a station which opmode got modified
+ * @sta_opmode: station's current opmode value
+ * @gfp: context flags
+ *
+ * Driver should call this function when station's opmode modified via action
+ * frame.
+ */
+void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
+				       struct sta_opmode_info *sta_opmode,
+				       gfp_t gfp);
+
 /**
  * cfg80211_cac_event - Channel availability check (CAC) event
  * @netdev: network device
@@ -5758,10 +5840,13 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
  * @addr: the address of the peer
  * @cookie: the cookie filled in @probe_client previously
  * @acked: indicates whether probe was acked or not
+ * @ack_signal: signal strength (in dBm) of the ACK frame.
+ * @is_valid_ack_signal: indicates the ack_signal is valid or not.
  * @gfp: allocation flags
  */
 void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
-			   u64 cookie, bool acked, gfp_t gfp);
+			   u64 cookie, bool acked, s32 ack_signal,
+			   bool is_valid_ack_signal, gfp_t gfp);
 
 /**
  * cfg80211_report_obss_beacon - report beacon from other APs
@@ -6202,6 +6287,17 @@ void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
 /* ethtool helper */
 void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
 
+/**
+ * cfg80211_external_auth_request - userspace request for authentication
+ * @netdev: network device
+ * @params: External authentication parameters
+ * @gfp: allocation flags
+ * Returns: 0 on success, < 0 on error
+ */
+int cfg80211_external_auth_request(struct net_device *netdev,
+				   struct cfg80211_external_auth_params *params,
+				   gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6cb602dd970c..0ad17b63684d 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -19,6 +19,7 @@
 #include <linux/workqueue.h>
 #include <linux/of.h>
 #include <linux/ethtool.h>
+#include <linux/net_tstamp.h>
 #include <net/devlink.h>
 #include <net/switchdev.h>
 
@@ -101,6 +102,7 @@ struct dsa_platform_data {
 };
 
 struct packet_type;
+struct dsa_switch;
 
 struct dsa_device_ops {
 	struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -367,6 +369,12 @@ struct dsa_switch_ops {
 	int	(*set_wol)(struct dsa_switch *ds, int port,
 			   struct ethtool_wolinfo *w);
 
+	/*
+	 * ethtool timestamp info
+	 */
+	int	(*get_ts_info)(struct dsa_switch *ds, int port,
+			       struct ethtool_ts_info *ts);
+
 	/*
 	 * Suspend and resume
 	 */
@@ -469,6 +477,18 @@ struct dsa_switch_ops {
 					 int port, struct net_device *br);
 	void	(*crosschip_bridge_leave)(struct dsa_switch *ds, int sw_index,
 					  int port, struct net_device *br);
+
+	/*
+	 * PTP functionality
+	 */
+	int	(*port_hwtstamp_get)(struct dsa_switch *ds, int port,
+				     struct ifreq *ifr);
+	int	(*port_hwtstamp_set)(struct dsa_switch *ds, int port,
+				     struct ifreq *ifr);
+	bool	(*port_txtstamp)(struct dsa_switch *ds, int port,
+				 struct sk_buff *clone, unsigned int type);
+	bool	(*port_rxtstamp)(struct dsa_switch *ds, int port,
+				 struct sk_buff *skb, unsigned int type);
 };
 
 struct dsa_switch_driver {
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index d91f9e7f4d71..960236fb1681 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -149,6 +149,8 @@ enum ieee80211_radiotap_ampdu_flags {
 	IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008,
 	IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010,
 	IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020,
+	IEEE80211_RADIOTAP_AMPDU_EOF = 0x0040,
+	IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN = 0x0080,
 };
 
 /* for IEEE80211_RADIOTAP_VHT */
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index 5a54c9570977..500f81375200 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -32,7 +32,7 @@ int inet_shutdown(struct socket *sock, int how);
 int inet_listen(struct socket *sock, int backlog);
 void inet_sock_destruct(struct sock *sk);
 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
-int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
+int inet_getname(struct socket *sock, struct sockaddr *uaddr,
 		 int peer);
 int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 int inet_ctl_sock_create(struct sock **sk, unsigned short family,
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 27d23a65f3cd..ac0866bb9e93 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -179,6 +179,9 @@ void rt6_disable_ip(struct net_device *dev, unsigned long event);
 void rt6_sync_down_dev(struct net_device *dev, unsigned long event);
 void rt6_multipath_rebalance(struct rt6_info *rt);
 
+void rt6_uncached_list_add(struct rt6_info *rt);
+void rt6_uncached_list_del(struct rt6_info *rt);
+
 static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
 {
 	const struct dst_entry *dst = skb_dst(skb);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 8606c9113d3f..7a98cd583c73 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1056,7 +1056,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu);
 
 int inet6_release(struct socket *sock);
 int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
-int inet6_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
+int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
 		  int peer);
 int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index d747ef975cd8..33fd9ba7e0e5 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -127,6 +127,17 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb);
 int lwtunnel_input(struct sk_buff *skb);
 int lwtunnel_xmit(struct sk_buff *skb);
 
+static inline void lwtunnel_set_redirect(struct dst_entry *dst)
+{
+	if (lwtunnel_output_redirect(dst->lwtstate)) {
+		dst->lwtstate->orig_output = dst->output;
+		dst->output = lwtunnel_output;
+	}
+	if (lwtunnel_input_redirect(dst->lwtstate)) {
+		dst->lwtstate->orig_input = dst->input;
+		dst->input = lwtunnel_input;
+	}
+}
 #else
 
 static inline void lwtstate_free(struct lwtunnel_state *lws)
@@ -158,6 +169,10 @@ static inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate)
 	return false;
 }
 
+static inline void lwtunnel_set_redirect(struct dst_entry *dst)
+{
+}
+
 static inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate,
 					     unsigned int mtu)
 {
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 906e90223066..2fd59ed3be00 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6,6 +6,7 @@
  * Copyright 2007-2010	Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018        Intel 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
@@ -934,6 +935,7 @@ struct ieee80211_tx_info {
 			u8 ampdu_len;
 			u8 antenna;
 			u16 tx_time;
+			bool is_valid_ack_signal;
 			void *status_driver_data[19 / sizeof(void *)];
 		} status;
 		struct {
@@ -1098,6 +1100,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  *	the first subframe.
  * @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must
  *	be done in the hardware.
+ * @RX_FLAG_AMPDU_EOF_BIT: Value of the EOF bit in the A-MPDU delimiter for this
+ *	frame
+ * @RX_FLAG_AMPDU_EOF_BIT_KNOWN: The EOF value is known
  */
 enum mac80211_rx_flags {
 	RX_FLAG_MMIC_ERROR		= BIT(0),
@@ -1124,6 +1129,8 @@ enum mac80211_rx_flags {
 	RX_FLAG_MIC_STRIPPED		= BIT(21),
 	RX_FLAG_ALLOW_SAME_PN		= BIT(22),
 	RX_FLAG_ICV_STRIPPED		= BIT(23),
+	RX_FLAG_AMPDU_EOF_BIT		= BIT(24),
+	RX_FLAG_AMPDU_EOF_BIT_KNOWN	= BIT(25),
 };
 
 /**
@@ -2063,6 +2070,14 @@ struct ieee80211_txq {
  * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on
  *	TDLS links.
  *
+ * @IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP: The driver requires the
+ *	mgd_prepare_tx() callback to be called before transmission of a
+ *	deauthentication frame in case the association was completed but no
+ *	beacon was heard. This is required in multi-channel scenarios, where the
+ *	virtual interface might not be given air time for the transmission of
+ *	the frame, as it is not synced with the AP/P2P GO yet, and thus the
+ *	deauthentication frame might not be transmitted.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -2106,6 +2121,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_REPORTS_LOW_ACK,
 	IEEE80211_HW_SUPPORTS_TX_FRAG,
 	IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
+	IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
 
 	/* keep last, obviously */
 	NUM_IEEE80211_HW_FLAGS
@@ -3350,6 +3366,9 @@ enum ieee80211_reconfig_type {
  *	management frame prior to having successfully associated to allow the
  *	driver to give it channel time for the transmission, to get a response
  *	and to be able to synchronize with the GO.
+ *	For drivers that set %IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, mac80211
+ *	would also call this function before transmitting a deauthentication
+ *	frame in case that no beacon was heard from the AP/P2P GO.
  *	The callback will be called before each transmission and upon return
  *	mac80211 will transmit the frame right away.
  *	The callback is optional and can (should!) sleep.
@@ -4149,7 +4168,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid);
  * The TX headroom reserved by mac80211 for its own tx_status functions.
  * This is enough for the radiotap header.
  */
-#define IEEE80211_TX_STATUS_HEADROOM	14
+#define IEEE80211_TX_STATUS_HEADROOM	ALIGN(14, 4)
 
 /**
  * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index f306b2aa15a4..9158ec1ad06f 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -313,6 +313,12 @@ struct pernet_operations {
 	void (*exit_batch)(struct list_head *net_exit_list);
 	unsigned int *id;
 	size_t size;
+	/*
+	 * Indicates above methods are allowed to be executed in parallel
+	 * with methods of any other pernet_operations, i.e. they are not
+	 * need synchronization via net_mutex.
+	 */
+	bool async;
 };
 
 /*
diff --git a/include/net/route.h b/include/net/route.h
index 1eb9ce470e25..ccf52f0958bb 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -65,8 +65,6 @@ struct rtable {
 	/* Miscellaneous cached information */
 	u32			rt_pmtu;
 
-	u32			rt_table_id;
-
 	struct list_head	rt_uncached;
 	struct uncached_list	*rt_uncached_list;
 };
@@ -227,6 +225,9 @@ struct in_ifaddr;
 void fib_add_ifaddr(struct in_ifaddr *);
 void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
 
+void rt_add_uncached_list(struct rtable *rt);
+void rt_del_uncached_list(struct rtable *rt);
+
 static inline void ip_rt_put(struct rtable *rt)
 {
 	/* dst_release() accepts a NULL parameter.
diff --git a/include/net/sock.h b/include/net/sock.h
index 169c92afcafa..3aa7b7d6e6c7 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1584,7 +1584,7 @@ int sock_no_bind(struct socket *, struct sockaddr *, int);
 int sock_no_connect(struct socket *, struct sockaddr *, int, int);
 int sock_no_socketpair(struct socket *, struct socket *);
 int sock_no_accept(struct socket *, struct socket *, int, bool);
-int sock_no_getname(struct socket *, struct sockaddr *, int *, int);
+int sock_no_getname(struct socket *, struct sockaddr *, int);
 __poll_t sock_no_poll(struct file *, struct socket *,
 			  struct poll_table_struct *);
 int sock_no_ioctl(struct socket *, unsigned int, unsigned long);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e3fc667f9ac2..92b06c6e7732 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -374,7 +374,8 @@ enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
 					      struct sk_buff *skb,
 					      const struct tcphdr *th);
 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
-			   struct request_sock *req, bool fastopen);
+			   struct request_sock *req, bool fastopen,
+			   bool *lost_race);
 int tcp_child_process(struct sock *parent, struct sock *child,
 		      struct sk_buff *skb);
 void tcp_enter_loss(struct sock *sk);
diff --git a/include/net/udplite.h b/include/net/udplite.h
index 81bdbf97319b..9185e45b997f 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -64,6 +64,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
 		UDP_SKB_CB(skb)->cscov = cscov;
 		if (skb->ip_summed == CHECKSUM_COMPLETE)
 			skb->ip_summed = CHECKSUM_NONE;
+		skb->csum_valid = 0;
         }
 
 	return 0;
diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h
index c2d81167c858..2cdf8dcf4bdc 100644
--- a/include/rdma/restrack.h
+++ b/include/rdma/restrack.h
@@ -28,10 +28,6 @@ enum rdma_restrack_type {
 	 * @RDMA_RESTRACK_QP: Queue pair (QP)
 	 */
 	RDMA_RESTRACK_QP,
-	/**
-	 * @RDMA_RESTRACK_XRCD: XRC domain (XRCD)
-	 */
-	RDMA_RESTRACK_XRCD,
 	/**
 	 * @RDMA_RESTRACK_MAX: Last entry, used for array dclarations
 	 */
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index 6da44079aa58..38287d9d23a1 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -276,10 +276,7 @@ struct uverbs_object_tree_def {
  */
 
 struct uverbs_ptr_attr {
-	union {
-		u64		data;
-		void	__user *ptr;
-	};
+	u64		data;
 	u16		len;
 	/* Combination of bits from enum UVERBS_ATTR_F_XXXX */
 	u16		flags;
@@ -351,38 +348,60 @@ static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr
 }
 
 static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle,
-				 size_t idx, const void *from)
+				 size_t idx, const void *from, size_t size)
 {
 	const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
 	u16 flags;
+	size_t min_size;
 
 	if (IS_ERR(attr))
 		return PTR_ERR(attr);
 
+	min_size = min_t(size_t, attr->ptr_attr.len, size);
+	if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
+		return -EFAULT;
+
 	flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT;
-	return (!copy_to_user(attr->ptr_attr.ptr, from, attr->ptr_attr.len) &&
-		!put_user(flags, &attr->uattr->flags)) ? 0 : -EFAULT;
+	if (put_user(flags, &attr->uattr->flags))
+		return -EFAULT;
+
+	return 0;
 }
 
-static inline int _uverbs_copy_from(void *to, size_t to_size,
+static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)
+{
+	return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data);
+}
+
+static inline int _uverbs_copy_from(void *to,
 				    const struct uverbs_attr_bundle *attrs_bundle,
-				    size_t idx)
+				    size_t idx,
+				    size_t size)
 {
 	const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
 
 	if (IS_ERR(attr))
 		return PTR_ERR(attr);
 
-	if (to_size <= sizeof(((struct ib_uverbs_attr *)0)->data))
+	/*
+	 * Validation ensures attr->ptr_attr.len >= size. If the caller is
+	 * using UVERBS_ATTR_SPEC_F_MIN_SZ then it must call copy_from with
+	 * the right size.
+	 */
+	if (unlikely(size < attr->ptr_attr.len))
+		return -EINVAL;
+
+	if (uverbs_attr_ptr_is_inline(attr))
 		memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len);
-	else if (copy_from_user(to, attr->ptr_attr.ptr, attr->ptr_attr.len))
+	else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data),
+				attr->ptr_attr.len))
 		return -EFAULT;
 
 	return 0;
 }
 
 #define uverbs_copy_from(to, attrs_bundle, idx)				      \
-	_uverbs_copy_from(to, sizeof(*(to)), attrs_bundle, idx)
+	_uverbs_copy_from(to, attrs_bundle, idx, sizeof(*to))
 
 /* =================================================
  *	 Definitions -> Specs infrastructure
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 1a1df0d21ee3..19317585ae48 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -476,6 +476,12 @@ struct scsi_host_template {
 	 */
 	struct device_attribute **sdev_attrs;
 
+	/*
+	 * Pointer to the SCSI device attribute groups for this host,
+	 * NULL terminated.
+	 */
+	const struct attribute_group **sdev_groups;
+
 	/*
 	 * List of hosts per template.
 	 *
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index 67be2445941a..8a5a8404966e 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -161,4 +161,6 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct dma_slave_config *slave_config);
 
+#define SND_DMAENGINE_PCM_DRV_NAME "snd_dmaengine_pcm"
+
 #endif
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 4f42affe777c..5ebcc51c0a6a 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1710,6 +1710,7 @@ struct snd_emu10k1 {
 	unsigned int ecard_ctrl;		/* ecard control bits */
 	unsigned int address_mode;		/* address mode */
 	unsigned long dma_mask;			/* PCI DMA mask */
+	bool iommu_workaround;			/* IOMMU workaround needed */
 	unsigned int delay_pcm_irq;		/* in samples */
 	int max_cache_pages;			/* max memory size / PAGE_SIZE */
 	struct snd_dma_buffer silent_page;	/* silent page */
@@ -1718,7 +1719,6 @@ struct snd_emu10k1 {
 	struct snd_dma_buffer p16v_buffer;
 
 	struct snd_util_memhdr *memhdr;		/* page allocation list */
-	struct snd_emu10k1_memblk *reserved_page;	/* reserved page */
 
 	struct list_head mapped_link_head;
 	struct list_head mapped_order_link_head;
@@ -1878,6 +1878,8 @@ void snd_p16v_resume(struct snd_emu10k1 *emu);
 /* memory allocation */
 struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream);
 int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
+int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
+					struct snd_dma_buffer *dmab);
 struct snd_util_memblk *snd_emu10k1_synth_alloc(struct snd_emu10k1 *emu, unsigned int size);
 int snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
 int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, int size);
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 68169e3749de..4c93ff5301bd 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -146,6 +146,8 @@ int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid,
 			int flags, unsigned int verb, unsigned int parm);
 bool snd_hdac_check_power_state(struct hdac_device *hdac,
 		hda_nid_t nid, unsigned int target_state);
+unsigned int snd_hdac_sync_power_state(struct hdac_device *hdac,
+		      hda_nid_t nid, unsigned int target_state);
 /**
  * snd_hdac_read_parm - read a codec parameter
  * @codec: the codec object
diff --git a/include/sound/rt5659.h b/include/sound/rt5659.h
index 656c4d58948d..9012e2b25360 100644
--- a/include/sound/rt5659.h
+++ b/include/sound/rt5659.h
@@ -30,6 +30,7 @@ enum rt5659_dmic2_data_pin {
 enum rt5659_jd_src {
 	RT5659_JD_NULL,
 	RT5659_JD3,
+	RT5659_JD_HDA_HEADER,
 };
 
 struct rt5659_platform_data {
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 747fd583b9dc..6a11b0239f74 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -586,10 +586,17 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
 				unsigned int mask, unsigned int value);
 
 #ifdef CONFIG_SND_SOC_AC97_BUS
-struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
-struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+#define snd_soc_alloc_ac97_codec(codec) \
+	snd_soc_alloc_ac97_component(&codec->component)
+#define snd_soc_new_ac97_codec(codec, id, id_mask) \
+	snd_soc_new_ac97_component(&codec->component, id, id_mask)
+#define snd_soc_free_ac97_codec(ac97) \
+	snd_soc_free_ac97_component(ac97)
+
+struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
+struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
 	unsigned int id, unsigned int id_mask);
-void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
+void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
 
 int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
 int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index c3ac5ec86519..965c650a5273 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -71,6 +71,12 @@ TRACE_DEFINE_ENUM(COMMIT_TRANS);
 		 { BTRFS_FILE_EXTENT_REG,	"REG"	 },		\
 		 { BTRFS_FILE_EXTENT_PREALLOC,	"PREALLOC"})
 
+#define show_qgroup_rsv_type(type)					\
+	__print_symbolic(type,						\
+		{ BTRFS_QGROUP_RSV_DATA,	  "DATA"	},	\
+		{ BTRFS_QGROUP_RSV_META_PERTRANS, "META_PERTRANS" },	\
+		{ BTRFS_QGROUP_RSV_META_PREALLOC, "META_PREALLOC" })
+
 #define BTRFS_GROUP_FLAGS	\
 	{ BTRFS_BLOCK_GROUP_DATA,	"DATA"},	\
 	{ BTRFS_BLOCK_GROUP_SYSTEM,	"SYSTEM"},	\
@@ -248,6 +254,41 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
 		  __entry->refs, __entry->compress_type)
 );
 
+TRACE_EVENT(btrfs_handle_em_exist,
+
+	TP_PROTO(const struct extent_map *existing, const struct extent_map *map, u64 start, u64 len),
+
+	TP_ARGS(existing, map, start, len),
+
+	TP_STRUCT__entry(
+		__field(	u64,  e_start		)
+		__field(	u64,  e_len		)
+		__field(	u64,  map_start		)
+		__field(	u64,  map_len		)
+		__field(	u64,  start		)
+		__field(	u64,  len		)
+	),
+
+	TP_fast_assign(
+		__entry->e_start	= existing->start;
+		__entry->e_len		= existing->len;
+		__entry->map_start	= map->start;
+		__entry->map_len	= map->len;
+		__entry->start		= start;
+		__entry->len		= len;
+	),
+
+	TP_printk("start=%llu len=%llu "
+		  "existing(start=%llu len=%llu) "
+		  "em(start=%llu len=%llu)",
+		  (unsigned long long)__entry->start,
+		  (unsigned long long)__entry->len,
+		  (unsigned long long)__entry->e_start,
+		  (unsigned long long)__entry->e_len,
+		  (unsigned long long)__entry->map_start,
+		  (unsigned long long)__entry->map_len)
+);
+
 /* file extent item */
 DECLARE_EVENT_CLASS(btrfs__file_extent_item_regular,
 
@@ -1598,28 +1639,52 @@ TRACE_EVENT(qgroup_update_counters,
 TRACE_EVENT(qgroup_update_reserve,
 
 	TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup,
-		 s64 diff),
+		 s64 diff, int type),
 
-	TP_ARGS(fs_info, qgroup, diff),
+	TP_ARGS(fs_info, qgroup, diff, type),
 
 	TP_STRUCT__entry_btrfs(
 		__field(	u64,	qgid			)
 		__field(	u64,	cur_reserved		)
 		__field(	s64,	diff			)
+		__field(	int,	type			)
 	),
 
 	TP_fast_assign_btrfs(fs_info,
 		__entry->qgid		= qgroup->qgroupid;
-		__entry->cur_reserved	= qgroup->reserved;
+		__entry->cur_reserved	= qgroup->rsv.values[type];
 		__entry->diff		= diff;
 	),
 
-	TP_printk_btrfs("qgid=%llu cur_reserved=%llu diff=%lld",
-		__entry->qgid, __entry->cur_reserved, __entry->diff)
+	TP_printk_btrfs("qgid=%llu type=%s cur_reserved=%llu diff=%lld",
+		__entry->qgid, show_qgroup_rsv_type(__entry->type),
+		__entry->cur_reserved, __entry->diff)
 );
 
 TRACE_EVENT(qgroup_meta_reserve,
 
+	TP_PROTO(struct btrfs_root *root, s64 diff, int type),
+
+	TP_ARGS(root, diff, type),
+
+	TP_STRUCT__entry_btrfs(
+		__field(	u64,	refroot			)
+		__field(	s64,	diff			)
+		__field(	int,	type			)
+	),
+
+	TP_fast_assign_btrfs(root->fs_info,
+		__entry->refroot	= root->objectid;
+		__entry->diff		= diff;
+	),
+
+	TP_printk_btrfs("refroot=%llu(%s) type=%s diff=%lld",
+		show_root_type(__entry->refroot),
+		show_qgroup_rsv_type(__entry->type), __entry->diff)
+);
+
+TRACE_EVENT(qgroup_meta_convert,
+
 	TP_PROTO(struct btrfs_root *root, s64 diff),
 
 	TP_ARGS(root, diff),
@@ -1627,6 +1692,7 @@ TRACE_EVENT(qgroup_meta_reserve,
 	TP_STRUCT__entry_btrfs(
 		__field(	u64,	refroot			)
 		__field(	s64,	diff			)
+		__field(	int,	type			)
 	),
 
 	TP_fast_assign_btrfs(root->fs_info,
@@ -1634,8 +1700,36 @@ TRACE_EVENT(qgroup_meta_reserve,
 		__entry->diff		= diff;
 	),
 
-	TP_printk_btrfs("refroot=%llu(%s) diff=%lld",
-		show_root_type(__entry->refroot), __entry->diff)
+	TP_printk_btrfs("refroot=%llu(%s) type=%s->%s diff=%lld",
+		show_root_type(__entry->refroot),
+		show_qgroup_rsv_type(BTRFS_QGROUP_RSV_META_PREALLOC),
+		show_qgroup_rsv_type(BTRFS_QGROUP_RSV_META_PERTRANS),
+		__entry->diff)
+);
+
+TRACE_EVENT(qgroup_meta_free_all_pertrans,
+
+	TP_PROTO(struct btrfs_root *root),
+
+	TP_ARGS(root),
+
+	TP_STRUCT__entry_btrfs(
+		__field(	u64,	refroot			)
+		__field(	s64,	diff			)
+		__field(	int,	type			)
+	),
+
+	TP_fast_assign_btrfs(root->fs_info,
+		__entry->refroot	= root->objectid;
+		spin_lock(&root->qgroup_meta_rsv_lock);
+		__entry->diff		= -(s64)root->qgroup_meta_rsv_pertrans;
+		spin_unlock(&root->qgroup_meta_rsv_lock);
+		__entry->type		= BTRFS_QGROUP_RSV_META_PERTRANS;
+	),
+
+	TP_printk_btrfs("refroot=%llu(%s) type=%s diff=%lld",
+		show_root_type(__entry->refroot),
+		show_qgroup_rsv_type(__entry->type), __entry->diff)
 );
 
 DECLARE_EVENT_CLASS(btrfs__prelim_ref,
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index 0b50fda80db0..d8c33298c153 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -179,6 +179,10 @@ TRACE_EVENT(rcu_grace_period_init,
  *
  *	"snap": Captured snapshot of expedited grace period sequence number.
  *	"start": Started a real expedited grace period.
+ *	"reset": Started resetting the tree
+ *	"select": Started selecting the CPUs to wait on.
+ *	"selectofl": Selected CPU partially offline.
+ *	"startwait": Started waiting on selected CPUs.
  *	"end": Ended a real expedited grace period.
  *	"endwake": Woke piggybackers up.
  *	"done": Someone else did the expedited grace period for us.
diff --git a/include/trace/events/rtc.h b/include/trace/events/rtc.h
new file mode 100644
index 000000000000..621333f1c890
--- /dev/null
+++ b/include/trace/events/rtc.h
@@ -0,0 +1,206 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rtc
+
+#if !defined(_TRACE_RTC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_RTC_H
+
+#include <linux/rtc.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(rtc_time_alarm_class,
+
+	TP_PROTO(time64_t secs, int err),
+
+	TP_ARGS(secs, err),
+
+	TP_STRUCT__entry(
+		__field(time64_t, secs)
+		__field(int, err)
+	),
+
+	TP_fast_assign(
+		__entry->secs = secs;
+		__entry->err = err;
+	),
+
+	TP_printk("UTC (%lld) (%d)",
+		  __entry->secs, __entry->err
+	)
+);
+
+DEFINE_EVENT(rtc_time_alarm_class, rtc_set_time,
+
+	TP_PROTO(time64_t secs, int err),
+
+	TP_ARGS(secs, err)
+);
+
+DEFINE_EVENT(rtc_time_alarm_class, rtc_read_time,
+
+	TP_PROTO(time64_t secs, int err),
+
+	TP_ARGS(secs, err)
+);
+
+DEFINE_EVENT(rtc_time_alarm_class, rtc_set_alarm,
+
+	TP_PROTO(time64_t secs, int err),
+
+	TP_ARGS(secs, err)
+);
+
+DEFINE_EVENT(rtc_time_alarm_class, rtc_read_alarm,
+
+	TP_PROTO(time64_t secs, int err),
+
+	TP_ARGS(secs, err)
+);
+
+TRACE_EVENT(rtc_irq_set_freq,
+
+	TP_PROTO(int freq, int err),
+
+	TP_ARGS(freq, err),
+
+	TP_STRUCT__entry(
+		__field(int, freq)
+		__field(int, err)
+	),
+
+	TP_fast_assign(
+		__entry->freq = freq;
+		__entry->err = err;
+	),
+
+	TP_printk("set RTC periodic IRQ frequency:%u (%d)",
+		  __entry->freq, __entry->err
+	)
+);
+
+TRACE_EVENT(rtc_irq_set_state,
+
+	TP_PROTO(int enabled, int err),
+
+	TP_ARGS(enabled, err),
+
+	TP_STRUCT__entry(
+		__field(int, enabled)
+		__field(int, err)
+	),
+
+	TP_fast_assign(
+		__entry->enabled = enabled;
+		__entry->err = err;
+	),
+
+	TP_printk("%s RTC 2^N Hz periodic IRQs (%d)",
+		  __entry->enabled ? "enable" : "disable",
+		  __entry->err
+	)
+);
+
+TRACE_EVENT(rtc_alarm_irq_enable,
+
+	TP_PROTO(unsigned int enabled, int err),
+
+	TP_ARGS(enabled, err),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, enabled)
+		__field(int, err)
+	),
+
+	TP_fast_assign(
+		__entry->enabled = enabled;
+		__entry->err = err;
+	),
+
+	TP_printk("%s RTC alarm IRQ (%d)",
+		  __entry->enabled ? "enable" : "disable",
+		  __entry->err
+	)
+);
+
+DECLARE_EVENT_CLASS(rtc_offset_class,
+
+	TP_PROTO(long offset, int err),
+
+	TP_ARGS(offset, err),
+
+	TP_STRUCT__entry(
+		__field(long, offset)
+		__field(int, err)
+	),
+
+	TP_fast_assign(
+		__entry->offset = offset;
+		__entry->err = err;
+	),
+
+	TP_printk("RTC offset: %ld (%d)",
+		  __entry->offset, __entry->err
+	)
+);
+
+DEFINE_EVENT(rtc_offset_class, rtc_set_offset,
+
+	TP_PROTO(long offset, int err),
+
+	TP_ARGS(offset, err)
+);
+
+DEFINE_EVENT(rtc_offset_class, rtc_read_offset,
+
+	TP_PROTO(long offset, int err),
+
+	TP_ARGS(offset, err)
+);
+
+DECLARE_EVENT_CLASS(rtc_timer_class,
+
+	TP_PROTO(struct rtc_timer *timer),
+
+	TP_ARGS(timer),
+
+	TP_STRUCT__entry(
+		__field(struct rtc_timer *, timer)
+		__field(ktime_t, expires)
+		__field(ktime_t, period)
+	),
+
+	TP_fast_assign(
+		__entry->timer = timer;
+		__entry->expires = timer->node.expires;
+		__entry->period = timer->period;
+	),
+
+	TP_printk("RTC timer:(%p) expires:%lld period:%lld",
+		  __entry->timer, __entry->expires, __entry->period
+	)
+);
+
+DEFINE_EVENT(rtc_timer_class, rtc_timer_enqueue,
+
+	TP_PROTO(struct rtc_timer *timer),
+
+	TP_ARGS(timer)
+);
+
+DEFINE_EVENT(rtc_timer_class, rtc_timer_dequeue,
+
+	TP_PROTO(struct rtc_timer *timer),
+
+	TP_ARGS(timer)
+);
+
+DEFINE_EVENT(rtc_timer_class, rtc_timer_fired,
+
+	TP_PROTO(struct rtc_timer *timer),
+
+	TP_ARGS(timer)
+);
+
+#endif /* _TRACE_RTC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index f8b134f5608f..e7ee32861d51 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -27,6 +27,9 @@
 # define MAP_UNINITIALIZED 0x0		/* Don't support this flag */
 #endif
 
+/* 0x0100 - 0x80000 flags are defined in asm-generic/mman.h */
+#define MAP_FIXED_NOREPLACE	0x100000	/* MAP_FIXED which doesn't unmap underlying mapping */
+
 /*
  * Flags for mlock
  */
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 5597a87154e5..2c575794fb52 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -38,14 +38,18 @@ extern "C" {
 #define DRM_DISPLAY_MODE_LEN	32
 #define DRM_PROP_NAME_LEN	32
 
-#define DRM_MODE_TYPE_BUILTIN	(1<<0)
-#define DRM_MODE_TYPE_CLOCK_C	((1<<1) | DRM_MODE_TYPE_BUILTIN)
-#define DRM_MODE_TYPE_CRTC_C	((1<<2) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_BUILTIN	(1<<0) /* deprecated */
+#define DRM_MODE_TYPE_CLOCK_C	((1<<1) | DRM_MODE_TYPE_BUILTIN) /* deprecated */
+#define DRM_MODE_TYPE_CRTC_C	((1<<2) | DRM_MODE_TYPE_BUILTIN) /* deprecated */
 #define DRM_MODE_TYPE_PREFERRED	(1<<3)
-#define DRM_MODE_TYPE_DEFAULT	(1<<4)
+#define DRM_MODE_TYPE_DEFAULT	(1<<4) /* deprecated */
 #define DRM_MODE_TYPE_USERDEF	(1<<5)
 #define DRM_MODE_TYPE_DRIVER	(1<<6)
 
+#define DRM_MODE_TYPE_ALL	(DRM_MODE_TYPE_PREFERRED |	\
+				 DRM_MODE_TYPE_USERDEF |	\
+				 DRM_MODE_TYPE_DRIVER)
+
 /* Video mode flags */
 /* bit compatible with the xrandr RR_ definitions (bits 0-13)
  *
@@ -66,8 +70,8 @@ extern "C" {
 #define DRM_MODE_FLAG_PCSYNC			(1<<7)
 #define DRM_MODE_FLAG_NCSYNC			(1<<8)
 #define DRM_MODE_FLAG_HSKEW			(1<<9) /* hskew provided */
-#define DRM_MODE_FLAG_BCAST			(1<<10)
-#define DRM_MODE_FLAG_PIXMUX			(1<<11)
+#define DRM_MODE_FLAG_BCAST			(1<<10) /* deprecated */
+#define DRM_MODE_FLAG_PIXMUX			(1<<11) /* deprecated */
 #define DRM_MODE_FLAG_DBLCLK			(1<<12)
 #define DRM_MODE_FLAG_CLKDIV2			(1<<13)
  /*
@@ -99,6 +103,20 @@ extern "C" {
 #define  DRM_MODE_FLAG_PIC_AR_16_9 \
 			(DRM_MODE_PICTURE_ASPECT_16_9<<19)
 
+#define  DRM_MODE_FLAG_ALL	(DRM_MODE_FLAG_PHSYNC |		\
+				 DRM_MODE_FLAG_NHSYNC |		\
+				 DRM_MODE_FLAG_PVSYNC |		\
+				 DRM_MODE_FLAG_NVSYNC |		\
+				 DRM_MODE_FLAG_INTERLACE |	\
+				 DRM_MODE_FLAG_DBLSCAN |	\
+				 DRM_MODE_FLAG_CSYNC |		\
+				 DRM_MODE_FLAG_PCSYNC |		\
+				 DRM_MODE_FLAG_NCSYNC |		\
+				 DRM_MODE_FLAG_HSKEW |		\
+				 DRM_MODE_FLAG_DBLCLK |		\
+				 DRM_MODE_FLAG_CLKDIV2 |	\
+				 DRM_MODE_FLAG_3D_MASK)
+
 /* DPMS flags */
 /* bit compatible with the xorg definitions. */
 #define DRM_MODE_DPMS_ON	0
@@ -173,6 +191,10 @@ extern "C" {
 		DRM_MODE_REFLECT_X | \
 		DRM_MODE_REFLECT_Y)
 
+/* Content Protection Flags */
+#define DRM_MODE_CONTENT_PROTECTION_UNDESIRED	0
+#define DRM_MODE_CONTENT_PROTECTION_DESIRED     1
+#define DRM_MODE_CONTENT_PROTECTION_ENABLED     2
 
 struct drm_mode_modeinfo {
 	__u32 clock;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 536ee4febd74..29fa48e4755d 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1358,7 +1358,9 @@ struct drm_intel_overlay_attrs {
  * active on a given plane.
  */
 
-#define I915_SET_COLORKEY_NONE		(1<<0) /* disable color key matching */
+#define I915_SET_COLORKEY_NONE		(1<<0) /* Deprecated. Instead set
+						* flags==0 to disable colorkeying.
+						*/
 #define I915_SET_COLORKEY_DESTINATION	(1<<1)
 #define I915_SET_COLORKEY_SOURCE	(1<<2)
 struct drm_intel_sprite_colorkey {
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index bbbaffad772d..c06d0a5bdd80 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -201,10 +201,12 @@ struct drm_msm_gem_submit_bo {
 #define MSM_SUBMIT_NO_IMPLICIT   0x80000000 /* disable implicit sync */
 #define MSM_SUBMIT_FENCE_FD_IN   0x40000000 /* enable input fence_fd */
 #define MSM_SUBMIT_FENCE_FD_OUT  0x20000000 /* enable output fence_fd */
+#define MSM_SUBMIT_SUDO          0x10000000 /* run submitted cmds from RB */
 #define MSM_SUBMIT_FLAGS                ( \
 		MSM_SUBMIT_NO_IMPLICIT   | \
 		MSM_SUBMIT_FENCE_FD_IN   | \
 		MSM_SUBMIT_FENCE_FD_OUT  | \
+		MSM_SUBMIT_SUDO          | \
 		0)
 
 /* Each cmdstream submit consists of a table of buffers involved, and
diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h
index 52263b575bdc..b95a0e11cb07 100644
--- a/include/uapi/drm/vc4_drm.h
+++ b/include/uapi/drm/vc4_drm.h
@@ -42,6 +42,9 @@ extern "C" {
 #define DRM_VC4_GET_TILING                        0x09
 #define DRM_VC4_LABEL_BO                          0x0a
 #define DRM_VC4_GEM_MADVISE                       0x0b
+#define DRM_VC4_PERFMON_CREATE                    0x0c
+#define DRM_VC4_PERFMON_DESTROY                   0x0d
+#define DRM_VC4_PERFMON_GET_VALUES                0x0e
 
 #define DRM_IOCTL_VC4_SUBMIT_CL           DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
 #define DRM_IOCTL_VC4_WAIT_SEQNO          DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
@@ -55,6 +58,9 @@ extern "C" {
 #define DRM_IOCTL_VC4_GET_TILING          DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling)
 #define DRM_IOCTL_VC4_LABEL_BO            DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo)
 #define DRM_IOCTL_VC4_GEM_MADVISE         DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GEM_MADVISE, struct drm_vc4_gem_madvise)
+#define DRM_IOCTL_VC4_PERFMON_CREATE      DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_CREATE, struct drm_vc4_perfmon_create)
+#define DRM_IOCTL_VC4_PERFMON_DESTROY     DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_DESTROY, struct drm_vc4_perfmon_destroy)
+#define DRM_IOCTL_VC4_PERFMON_GET_VALUES  DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_GET_VALUES, struct drm_vc4_perfmon_get_values)
 
 struct drm_vc4_submit_rcl_surface {
 	__u32 hindex; /* Handle index, or ~0 if not present. */
@@ -173,6 +179,15 @@ struct drm_vc4_submit_cl {
 	 * wait ioctl).
 	 */
 	__u64 seqno;
+
+	/* ID of the perfmon to attach to this job. 0 means no perfmon. */
+	__u32 perfmonid;
+
+	/* Unused field to align this struct on 64 bits. Must be set to 0.
+	 * If one ever needs to add an u32 field to this struct, this field
+	 * can be used.
+	 */
+	__u32 pad2;
 };
 
 /**
@@ -308,6 +323,7 @@ struct drm_vc4_get_hang_state {
 #define DRM_VC4_PARAM_SUPPORTS_THREADED_FS	5
 #define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER	6
 #define DRM_VC4_PARAM_SUPPORTS_MADVISE		7
+#define DRM_VC4_PARAM_SUPPORTS_PERFMON		8
 
 struct drm_vc4_get_param {
 	__u32 param;
@@ -352,6 +368,66 @@ struct drm_vc4_gem_madvise {
 	__u32 pad;
 };
 
+enum {
+	VC4_PERFCNT_FEP_VALID_PRIMS_NO_RENDER,
+	VC4_PERFCNT_FEP_VALID_PRIMS_RENDER,
+	VC4_PERFCNT_FEP_CLIPPED_QUADS,
+	VC4_PERFCNT_FEP_VALID_QUADS,
+	VC4_PERFCNT_TLB_QUADS_NOT_PASSING_STENCIL,
+	VC4_PERFCNT_TLB_QUADS_NOT_PASSING_Z_AND_STENCIL,
+	VC4_PERFCNT_TLB_QUADS_PASSING_Z_AND_STENCIL,
+	VC4_PERFCNT_TLB_QUADS_ZERO_COVERAGE,
+	VC4_PERFCNT_TLB_QUADS_NON_ZERO_COVERAGE,
+	VC4_PERFCNT_TLB_QUADS_WRITTEN_TO_COLOR_BUF,
+	VC4_PERFCNT_PLB_PRIMS_OUTSIDE_VIEWPORT,
+	VC4_PERFCNT_PLB_PRIMS_NEED_CLIPPING,
+	VC4_PERFCNT_PSE_PRIMS_REVERSED,
+	VC4_PERFCNT_QPU_TOTAL_IDLE_CYCLES,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_VERTEX_COORD_SHADING,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_FRAGMENT_SHADING,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_EXEC_VALID_INST,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_TMUS,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_SCOREBOARD,
+	VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_VARYINGS,
+	VC4_PERFCNT_QPU_TOTAL_INST_CACHE_HIT,
+	VC4_PERFCNT_QPU_TOTAL_INST_CACHE_MISS,
+	VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_HIT,
+	VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_MISS,
+	VC4_PERFCNT_TMU_TOTAL_TEXT_QUADS_PROCESSED,
+	VC4_PERFCNT_TMU_TOTAL_TEXT_CACHE_MISS,
+	VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VDW_STALLED,
+	VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VCD_STALLED,
+	VC4_PERFCNT_L2C_TOTAL_L2_CACHE_HIT,
+	VC4_PERFCNT_L2C_TOTAL_L2_CACHE_MISS,
+	VC4_PERFCNT_NUM_EVENTS,
+};
+
+#define DRM_VC4_MAX_PERF_COUNTERS	16
+
+struct drm_vc4_perfmon_create {
+	__u32 id;
+	__u32 ncounters;
+	__u8 events[DRM_VC4_MAX_PERF_COUNTERS];
+};
+
+struct drm_vc4_perfmon_destroy {
+	__u32 id;
+};
+
+/*
+ * Returns the values of the performance counters tracked by this
+ * perfmon (as an array of ncounters u64 values).
+ *
+ * No implicit synchronization is performed, so the user has to
+ * guarantee that any jobs using this perfmon have already been
+ * completed  (probably by blocking on the seqno returned by the
+ * last exec that used the perfmon).
+ */
+struct drm_vc4_perfmon_get_values {
+	__u32 id;
+	__u64 values_ptr;
+};
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h
index 28e8a2a86e16..8997d5068c08 100644
--- a/include/uapi/linux/cec-funcs.h
+++ b/include/uapi/linux/cec-funcs.h
@@ -3,35 +3,6 @@
  * cec - HDMI Consumer Electronics Control message functions
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * Alternatively you can redistribute this file under the terms of the
- * BSD license as stated below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. The names of its contributors may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _CEC_UAPI_FUNCS_H
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
index b51fbe1941a7..20fe091b7e96 100644
--- a/include/uapi/linux/cec.h
+++ b/include/uapi/linux/cec.h
@@ -3,35 +3,6 @@
  * cec - HDMI Consumer Electronics Control public header
  *
  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may 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.
- *
- * Alternatively you can redistribute this file under the terms of the
- * BSD license as stated below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. The names of its contributors may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
  */
 
 #ifndef _CEC_UAPI_H
diff --git a/include/uapi/linux/errqueue.h b/include/uapi/linux/errqueue.h
index dc64cfaf13da..28812eda4209 100644
--- a/include/uapi/linux/errqueue.h
+++ b/include/uapi/linux/errqueue.h
@@ -20,11 +20,13 @@ struct sock_extended_err {
 #define SO_EE_ORIGIN_ICMP6	3
 #define SO_EE_ORIGIN_TXSTATUS	4
 #define SO_EE_ORIGIN_ZEROCOPY	5
+#define SO_EE_ORIGIN_ZCOOKIE	6
 #define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
 
 #define SO_EE_OFFENDER(ee)	((struct sockaddr*)((ee)+1))
 
 #define SO_EE_CODE_ZEROCOPY_COPIED	1
+#define	SO_EE_ORIGIN_MAX_ZCOOKIES	8
 
 /**
  *	struct scm_timestamping - timestamps exposed through cmsg
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index f8cb5760ea4f..2e4a6c1accaa 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -23,7 +23,6 @@
 #define _UAPI_LINUX_IF_ETHER_H
 
 #include <linux/types.h>
-#include <linux/libc-compat.h>
 
 /*
  *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
@@ -89,6 +88,7 @@
 #define ETH_P_AOE	0x88A2		/* ATA over Ethernet		*/
 #define ETH_P_8021AD	0x88A8          /* 802.1ad Service VLAN		*/
 #define ETH_P_802_EX1	0x88B5		/* 802.1 Local Experimental 1.  */
+#define ETH_P_PREAUTH	0x88C7		/* 802.11 Preauthentication */
 #define ETH_P_TIPC	0x88CA		/* TIPC 			*/
 #define ETH_P_MACSEC	0x88E5		/* 802.1ae MACsec */
 #define ETH_P_8021AH	0x88E7          /* 802.1ah Backbone Service Tag */
@@ -151,6 +151,11 @@
  *	This is an Ethernet frame header.
  */
 
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR		1
+#endif
+
 #if __UAPI_DEF_ETHHDR
 struct ethhdr {
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6d9447700e18..11d0c0ea2bfa 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -941,4 +941,22 @@ enum {
 	IFLA_EVENT_BONDING_OPTIONS,	/* change in bonding options */
 };
 
+/* tun section */
+
+enum {
+	IFLA_TUN_UNSPEC,
+	IFLA_TUN_OWNER,
+	IFLA_TUN_GROUP,
+	IFLA_TUN_TYPE,
+	IFLA_TUN_PI,
+	IFLA_TUN_VNET_HDR,
+	IFLA_TUN_PERSIST,
+	IFLA_TUN_MULTI_QUEUE,
+	IFLA_TUN_NUM_QUEUES,
+	IFLA_TUN_NUM_DISABLED_QUEUES,
+	__IFLA_TUN_MAX,
+};
+
+#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
+
 #endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/include/uapi/linux/inotify.h b/include/uapi/linux/inotify.h
index 5474461683db..4800bf2a531d 100644
--- a/include/uapi/linux/inotify.h
+++ b/include/uapi/linux/inotify.h
@@ -71,5 +71,13 @@ struct inotify_event {
 #define IN_CLOEXEC O_CLOEXEC
 #define IN_NONBLOCK O_NONBLOCK
 
+/*
+ * ioctl numbers: inotify uses 'I' prefix for all ioctls,
+ * except historical FIONREAD, which is based on 'T'.
+ *
+ * INOTIFY_IOC_SETNEXTWD: set desired number of next created
+ * watch descriptor.
+ */
+#define INOTIFY_IOC_SETNEXTWD	_IOW('I', 0, __s32)
 
 #endif /* _UAPI_LINUX_INOTIFY_H */
diff --git a/include/uapi/linux/ipmi_bmc.h b/include/uapi/linux/ipmi_bmc.h
new file mode 100644
index 000000000000..2f9f97e6123a
--- /dev/null
+++ b/include/uapi/linux/ipmi_bmc.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2018, Intel Corporation.
+
+#ifndef _UAPI_LINUX_IPMI_BMC_H
+#define _UAPI_LINUX_IPMI_BMC_H
+
+#include <linux/ioctl.h>
+
+#define __IPMI_BMC_IOCTL_MAGIC        0xB1
+#define IPMI_BMC_IOCTL_SET_SMS_ATN    _IO(__IPMI_BMC_IOCTL_MAGIC, 0x00)
+#define IPMI_BMC_IOCTL_CLEAR_SMS_ATN  _IO(__IPMI_BMC_IOCTL_MAGIC, 0x01)
+#define IPMI_BMC_IOCTL_FORCE_ABORT    _IO(__IPMI_BMC_IOCTL_MAGIC, 0x02)
+
+#endif /* _UAPI_LINUX_KCS_BMC_H */
diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h
index fc29efaa918c..8254c937c9f4 100644
--- a/include/uapi/linux/libc-compat.h
+++ b/include/uapi/linux/libc-compat.h
@@ -264,10 +264,4 @@
 
 #endif /* __GLIBC__ */
 
-/* Definitions for if_ether.h */
-/* allow libcs like musl to deactivate this, glibc does not implement this. */
-#ifndef __UAPI_DEF_ETHHDR
-#define __UAPI_DEF_ETHHDR		1
-#endif
-
 #endif /* _UAPI_LIBC_COMPAT_H */
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c587a61c32bf..c13c84304be3 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -992,6 +992,32 @@
  *
  * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
  *
+ * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
+ *	drivers that do not define separate commands for authentication and
+ *	association, but rely on user space for the authentication to happen.
+ *	This interface acts both as the event request (driver to user space)
+ *	to trigger the authentication and command response (userspace to
+ *	driver) to indicate the authentication status.
+ *
+ *	User space uses the %NL80211_CMD_CONNECT command to the host driver to
+ *	trigger a connection. The host driver selects a BSS and further uses
+ *	this interface to offload only the authentication part to the user
+ *	space. Authentication frames are passed between the driver and user
+ *	space through the %NL80211_CMD_FRAME interface. Host driver proceeds
+ *	further with the association after getting successful authentication
+ *	status. User space indicates the authentication status through
+ *	%NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
+ *	command interface.
+ *
+ *	Host driver reports this status on an authentication failure to the
+ *	user space through the connect result as the user space would have
+ *	initiated the connection through the connect request.
+ *
+ * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's
+ *	ht opmode or vht opmode changes using any of &NL80211_ATTR_SMPS_MODE,
+ *	&NL80211_ATTR_CHANNEL_WIDTH,&NL80211_ATTR_NSS attributes with its
+ *	address(specified in &NL80211_ATTR_MAC).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1198,6 +1224,10 @@ enum nl80211_commands {
 
 	NL80211_CMD_RELOAD_REGDB,
 
+	NL80211_CMD_EXTERNAL_AUTH,
+
+	NL80211_CMD_STA_OPMODE_CHANGED,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -2153,6 +2183,19 @@ enum nl80211_commands {
  * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
  * @NL80211_ATTR_PORT_AUTHORIZED: (reserved)
  *
+ * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
+ *     authentication operation (u32 attribute with an
+ *     &enum nl80211_external_auth_action value). This is used with the
+ *     &NL80211_CMD_EXTERNAL_AUTH request event.
+ * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
+ *     space supports external authentication. This attribute shall be used
+ *     only with %NL80211_CMD_CONNECT request. The driver may offload
+ *     authentication processing to user space if this capability is indicated
+ *     in NL80211_CMD_CONNECT requests from the user space.
+ *
+ * @NL80211_ATTR_NSS: Station's New/updated  RX_NSS value notified using this
+ *	u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2579,6 +2622,12 @@ enum nl80211_attrs {
 	NL80211_ATTR_PMKR0_NAME,
 	NL80211_ATTR_PORT_AUTHORIZED,
 
+	NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+	NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
+
+	NL80211_ATTR_NSS,
+	NL80211_ATTR_ACK_SIGNAL,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2899,6 +2948,7 @@ enum nl80211_sta_bss_param {
  * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
  *	received from the station (u64, usec)
  * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2937,6 +2987,7 @@ enum nl80211_sta_info {
 	NL80211_STA_INFO_TID_STATS,
 	NL80211_STA_INFO_RX_DURATION,
 	NL80211_STA_INFO_PAD,
+	NL80211_STA_INFO_ACK_SIGNAL,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -4945,6 +4996,9 @@ enum nl80211_feature_flags {
  *	probe request tx deferral and suppression
  * @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
  *	value in %NL80211_ATTR_USE_MFP.
+ * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
+ * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
+ * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4972,6 +5026,9 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
 	NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
 	NL80211_EXT_FEATURE_MFP_OPTIONAL,
+	NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
+	NL80211_EXT_FEATURE_LOW_POWER_SCAN,
+	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
@@ -5032,6 +5089,10 @@ enum nl80211_timeout_reason {
  * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
  * requests.
  *
+ * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and
+ * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only
+ * one of them can be used in the request.
+ *
  * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
  * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
  * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
@@ -5059,7 +5120,20 @@ enum nl80211_timeout_reason {
  *	and suppression (if it has received a broadcast Probe Response frame,
  *	Beacon frame or FILS Discovery frame from an AP that the STA considers
  *	a suitable candidate for (re-)association - suitable in terms of
- *	SSID and/or RSSI
+ *	SSID and/or RSSI.
+ * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to
+ *	accomplish the scan. Thus, this flag intends the driver to perform the
+ *	scan request with lesser span/duration. It is specific to the driver
+ *	implementations on how this is accomplished. Scan accuracy may get
+ *	impacted with this flag.
+ * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume
+ *	optimal possible power. Drivers can resort to their specific means to
+ *	optimize the power. Scan accuracy may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan
+ *	results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum
+ *	possible scan results. This flag hints the driver to use the best
+ *	possible scan configuration to improve the accuracy in scanning.
+ *	Latency and power use may get impacted with this flag.
  */
 enum nl80211_scan_flags {
 	NL80211_SCAN_FLAG_LOW_PRIORITY				= 1<<0,
@@ -5070,6 +5144,9 @@ enum nl80211_scan_flags {
 	NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP		= 1<<5,
 	NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE		= 1<<6,
 	NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION	= 1<<7,
+	NL80211_SCAN_FLAG_LOW_SPAN				= 1<<8,
+	NL80211_SCAN_FLAG_LOW_POWER				= 1<<9,
+	NL80211_SCAN_FLAG_HIGH_ACCURACY				= 1<<10,
 };
 
 /**
@@ -5469,4 +5546,15 @@ enum nl80211_nan_match_attributes {
 	NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
 };
 
+/**
+ * nl80211_external_auth_action - Action to perform with external
+ *     authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
+ * @NL80211_EXTERNAL_AUTH_START: Start the authentication.
+ * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
+ */
+enum nl80211_external_auth_action {
+	NL80211_EXTERNAL_AUTH_START,
+	NL80211_EXTERNAL_AUTH_ABORT,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index e0739a1aa4b2..6f873503552d 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -380,10 +380,14 @@ struct perf_event_attr {
 	__u32			bp_type;
 	union {
 		__u64		bp_addr;
+		__u64		kprobe_func; /* for perf_kprobe */
+		__u64		uprobe_path; /* for perf_uprobe */
 		__u64		config1; /* extension of config */
 	};
 	union {
 		__u64		bp_len;
+		__u64		kprobe_addr; /* when kprobe_func == NULL */
+		__u64		probe_offset; /* for perf_[k,u]probe */
 		__u64		config2; /* extension of config1 */
 	};
 	__u64	branch_sample_type; /* enum perf_branch_sample_type */
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index af5f8c2df87a..3165863aa187 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -207,4 +207,8 @@ struct prctl_mm_map {
 # define PR_SVE_VL_LEN_MASK		0xffff
 # define PR_SVE_VL_INHERIT		(1 << 17) /* inherit across exec */
 
+/* Process-based variant of PDEATHSIG */
+#define PR_SET_PDEATHSIG_PROC		48
+#define PR_GET_PDEATHSIG_PROC		49
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/include/uapi/linux/rds.h b/include/uapi/linux/rds.h
index e71d4491f225..12e3bca32cad 100644
--- a/include/uapi/linux/rds.h
+++ b/include/uapi/linux/rds.h
@@ -103,6 +103,7 @@
 #define RDS_CMSG_MASKED_ATOMIC_FADD	8
 #define RDS_CMSG_MASKED_ATOMIC_CSWP	9
 #define RDS_CMSG_RXPATH_LATENCY		11
+#define	RDS_CMSG_ZCOPY_COOKIE		12
 
 #define RDS_INFO_FIRST			10000
 #define RDS_INFO_COUNTERS		10000
diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
index 0f272818a4d2..be69135eb361 100644
--- a/include/uapi/linux/sysctl.h
+++ b/include/uapi/linux/sysctl.h
@@ -27,6 +27,10 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 
+#ifndef __KERNEL__
+#include <stddef.h>		/* For size_t. */
+#endif
+
 #define CTL_MAXNAME 10		/* how many path components do we allow in a
 				   call to sysctl?   In other words, what is
 				   the largest acceptable value for the nlen
diff --git a/include/uapi/rdma/hfi/hfi1_user.h b/include/uapi/rdma/hfi/hfi1_user.h
index 791bea2f8297..43b46bf6f8bb 100644
--- a/include/uapi/rdma/hfi/hfi1_user.h
+++ b/include/uapi/rdma/hfi/hfi1_user.h
@@ -219,7 +219,7 @@ struct sdma_req_info {
 	 * in charge of managing its own ring.
 	 */
 	__u16 comp_idx;
-} __packed;
+} __attribute__((__packed__));
 
 /*
  * SW KDETH header.
@@ -230,7 +230,7 @@ struct hfi1_kdeth_header {
 	__le16 jkey;
 	__le16 hcrc;
 	__le32 swdata[7];
-} __packed;
+}  __attribute__((__packed__));
 
 /*
  * Structure describing the headers that User space uses. The
@@ -241,7 +241,7 @@ struct hfi1_pkt_header {
 	__be16 lrh[4];
 	__be32 bth[3];
 	struct hfi1_kdeth_header kdeth;
-} __packed;
+}  __attribute__((__packed__));
 
 
 /*
diff --git a/include/uapi/rdma/ocrdma-abi.h b/include/uapi/rdma/ocrdma-abi.h
index ad64a3cea1cd..e0475d59cdf0 100644
--- a/include/uapi/rdma/ocrdma-abi.h
+++ b/include/uapi/rdma/ocrdma-abi.h
@@ -127,7 +127,7 @@ struct ocrdma_create_qp_uresp {
 	__u32 db_rq_offset;
 	__u32 db_shift;
 	__u64 rsvd[11];
-} __packed;
+};
 
 struct ocrdma_create_srq_uresp {
 	__u16 rq_dbid;
diff --git a/include/uapi/rdma/rdma_user_ioctl.h b/include/uapi/rdma/rdma_user_ioctl.h
index 03557b5f9aa6..46de0885e800 100644
--- a/include/uapi/rdma/rdma_user_ioctl.h
+++ b/include/uapi/rdma/rdma_user_ioctl.h
@@ -65,7 +65,7 @@ struct ib_uverbs_attr {
 	__u16 len;		/* only for pointers */
 	__u16 flags;		/* combination of UVERBS_ATTR_F_XXXX */
 	__u16 reserved;
-	__u64 data;		/* ptr to command, inline data or idr/fd */
+	__aligned_u64 data;	/* ptr to command, inline data or idr/fd */
 };
 
 struct ib_uverbs_ioctl_hdr {
@@ -73,7 +73,7 @@ struct ib_uverbs_ioctl_hdr {
 	__u16 object_id;
 	__u16 method_id;
 	__u16 num_attrs;
-	__u64 reserved;
+	__aligned_u64 reserved;
 	struct ib_uverbs_attr  attrs[0];
 };
 
diff --git a/include/uapi/rdma/rdma_user_rxe.h b/include/uapi/rdma/rdma_user_rxe.h
index bdeea948b2f3..e3e6852b58eb 100644
--- a/include/uapi/rdma/rdma_user_rxe.h
+++ b/include/uapi/rdma/rdma_user_rxe.h
@@ -35,6 +35,9 @@
 #define RDMA_USER_RXE_H
 
 #include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
 
 union rxe_gid {
 	__u8	raw[16];
@@ -57,7 +60,6 @@ struct rxe_av {
 	__u8			network_type;
 	struct rxe_global_route	grh;
 	union {
-		struct sockaddr		_sockaddr;
 		struct sockaddr_in	_sockaddr_in;
 		struct sockaddr_in6	_sockaddr_in6;
 	} sgid_addr, dgid_addr;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index d7f309f74dec..cff46bddf700 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1611,8 +1611,10 @@ static int __init init_mqueue_fs(void)
 		goto out_filesystem;
 
 	m = kern_mount_data(&mqueue_fs_type, &init_ipc_ns);
-	if (IS_ERR(m))
+	if (IS_ERR(m)) {
+		error = PTR_ERR(m);
 		goto out_filesystem;
+	}
 	init_ipc_ns.mq_mnt = m;
 	return 0;
 
diff --git a/kernel/audit.c b/kernel/audit.c
index 227db99b0f19..5fea8ab76402 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -38,7 +38,8 @@
  *	  6) Support low-overhead kernel-based filtering to minimize the
  *	     information that must be passed to user-space.
  *
- * Example user-space utilities: http://people.redhat.com/sgrubb/audit/
+ * Audit userspace, documentation, tests, and bug/issue trackers:
+ * 	https://github.com/linux-audit
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -1526,6 +1527,7 @@ static struct pernet_operations audit_net_ops __net_initdata = {
 	.exit = audit_net_exit,
 	.id = &audit_net_id,
 	.size = sizeof(struct audit_net),
+	.async = true,
 };
 
 /* Initialize audit support at boot time. */
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4a1758adb222..d7a807e81451 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -258,8 +258,8 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *
 		goto exit_err;
 #ifdef CONFIG_AUDITSYSCALL
 	case AUDIT_FILTER_ENTRY:
-		if (rule->action == AUDIT_ALWAYS)
-			goto exit_err;
+		pr_err("AUDIT_FILTER_ENTRY is deprecated\n");
+		goto exit_err;
 	case AUDIT_FILTER_EXIT:
 	case AUDIT_FILTER_TASK:
 #endif
@@ -496,7 +496,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 			if (!gid_valid(f->gid))
 				goto exit_free;
 			break;
-		case AUDIT_SESSIONID:
 		case AUDIT_ARCH:
 			entry->rule.arch_f = f;
 			break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e80459f7e132..4e0a4ac803db 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1511,30 +1511,28 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
 	struct audit_context *context = tsk->audit_context;
 	enum audit_state     state;
 
-	if (!context)
+	if (!audit_enabled || !context)
 		return;
 
 	BUG_ON(context->in_syscall || context->name_count);
 
-	if (!audit_enabled)
+	state = context->state;
+	if (state == AUDIT_DISABLED)
 		return;
 
+	context->dummy = !audit_n_rules;
+	if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
+		context->prio = 0;
+		if (auditd_test_task(tsk))
+			return;
+	}
+
 	context->arch	    = syscall_get_arch();
 	context->major      = major;
 	context->argv[0]    = a1;
 	context->argv[1]    = a2;
 	context->argv[2]    = a3;
 	context->argv[3]    = a4;
-
-	state = context->state;
-	context->dummy = !audit_n_rules;
-	if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
-		context->prio = 0;
-		state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
-	}
-	if (state == AUDIT_DISABLED)
-		return;
-
 	context->serial     = 0;
 	context->ctime = current_kernel_time64();
 	context->in_syscall = 1;
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index b1f66480135b..a364c408f25a 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -73,11 +73,11 @@ static int array_map_alloc_check(union bpf_attr *attr)
 static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 {
 	bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
-	int numa_node = bpf_map_attr_numa_node(attr);
+	int ret, numa_node = bpf_map_attr_numa_node(attr);
 	u32 elem_size, index_mask, max_entries;
 	bool unpriv = !capable(CAP_SYS_ADMIN);
+	u64 cost, array_size, mask64;
 	struct bpf_array *array;
-	u64 array_size, mask64;
 
 	elem_size = round_up(attr->value_size, 8);
 
@@ -109,8 +109,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 		array_size += (u64) max_entries * elem_size;
 
 	/* make sure there is no u32 overflow later in round_up() */
-	if (array_size >= U32_MAX - PAGE_SIZE)
+	cost = array_size;
+	if (cost >= U32_MAX - PAGE_SIZE)
 		return ERR_PTR(-ENOMEM);
+	if (percpu) {
+		cost += (u64)attr->max_entries * elem_size * num_possible_cpus();
+		if (cost >= U32_MAX - PAGE_SIZE)
+			return ERR_PTR(-ENOMEM);
+	}
+	cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
+
+	ret = bpf_map_precharge_memlock(cost);
+	if (ret < 0)
+		return ERR_PTR(ret);
 
 	/* allocate all map elements and zero-initialize them */
 	array = bpf_map_area_alloc(array_size, numa_node);
@@ -121,20 +132,13 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 
 	/* copy mandatory map attributes */
 	bpf_map_init_from_attr(&array->map, attr);
+	array->map.pages = cost;
 	array->elem_size = elem_size;
 
-	if (!percpu)
-		goto out;
-
-	array_size += (u64) attr->max_entries * elem_size * num_possible_cpus();
-
-	if (array_size >= U32_MAX - PAGE_SIZE ||
-	    bpf_array_alloc_percpu(array)) {
+	if (percpu && bpf_array_alloc_percpu(array)) {
 		bpf_map_area_free(array);
 		return ERR_PTR(-ENOMEM);
 	}
-out:
-	array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT;
 
 	return &array->map;
 }
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 29ca9208dcfa..d315b393abdd 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1590,7 +1590,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
 	 * so always copy 'cnt' prog_ids to the user.
 	 * In a rare race the user will see zero prog_ids
 	 */
-	ids = kcalloc(cnt, sizeof(u32), GFP_USER);
+	ids = kcalloc(cnt, sizeof(u32), GFP_USER | __GFP_NOWARN);
 	if (!ids)
 		return -ENOMEM;
 	rcu_read_lock();
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index fbfdada6caee..a4bb0b34375a 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -334,7 +334,7 @@ static int cpu_map_kthread_run(void *data)
 static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu,
 						       int map_id)
 {
-	gfp_t gfp = GFP_ATOMIC|__GFP_NOWARN;
+	gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
 	struct bpf_cpu_map_entry *rcpu;
 	int numa, err;
 
diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c
index 7b469d10d0e9..a75e02c961b5 100644
--- a/kernel/bpf/lpm_trie.c
+++ b/kernel/bpf/lpm_trie.c
@@ -555,7 +555,10 @@ static void trie_free(struct bpf_map *map)
 	struct lpm_trie_node __rcu **slot;
 	struct lpm_trie_node *node;
 
-	raw_spin_lock(&trie->lock);
+	/* Wait for outstanding programs to complete
+	 * update/lookup/delete/get_next_key and free the trie.
+	 */
+	synchronize_rcu();
 
 	/* Always start at the root and walk down to a node that has no
 	 * children. Then free that node, nullify its reference in the parent
@@ -569,7 +572,7 @@ static void trie_free(struct bpf_map *map)
 			node = rcu_dereference_protected(*slot,
 					lockdep_is_held(&trie->lock));
 			if (!node)
-				goto unlock;
+				goto out;
 
 			if (rcu_access_pointer(node->child[0])) {
 				slot = &node->child[0];
@@ -587,8 +590,8 @@ static void trie_free(struct bpf_map *map)
 		}
 	}
 
-unlock:
-	raw_spin_unlock(&trie->lock);
+out:
+	kfree(trie);
 }
 
 static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 48c33417d13c..a927e89dad6e 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -521,8 +521,8 @@ static struct smap_psock *smap_init_psock(struct sock *sock,
 static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
 {
 	struct bpf_stab *stab;
-	int err = -EINVAL;
 	u64 cost;
+	int err;
 
 	if (!capable(CAP_NET_ADMIN))
 		return ERR_PTR(-EPERM);
@@ -547,6 +547,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
 
 	/* make sure page count doesn't overflow */
 	cost = (u64) stab->map.max_entries * sizeof(struct sock *);
+	err = -EINVAL;
 	if (cost >= U32_MAX - PAGE_SIZE)
 		goto free_stab;
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5fb69a85d967..3c74b163eaeb 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -508,10 +508,6 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
 static const int caller_saved[CALLER_SAVED_REGS] = {
 	BPF_REG_0, BPF_REG_1, BPF_REG_2, BPF_REG_3, BPF_REG_4, BPF_REG_5
 };
-#define CALLEE_SAVED_REGS 5
-static const int callee_saved[CALLEE_SAVED_REGS] = {
-	BPF_REG_6, BPF_REG_7, BPF_REG_8, BPF_REG_9
-};
 
 static void __mark_reg_not_init(struct bpf_reg_state *reg);
 
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 8cda3bc3ae22..55fff758a803 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -680,6 +680,7 @@ struct css_set init_css_set = {
 	 */
 	.dfl_cgrp		= &cgrp_dfl_root.cgrp,
 };
+EXPORT_SYMBOL_GPL(init_css_set);
 
 static int css_set_count	= 1;	/* 1 for init_css_set */
 
@@ -1731,6 +1732,9 @@ static int parse_cgroup_root_flags(char *data, unsigned int *root_flags)
 		if (!strcmp(token, "nsdelegate")) {
 			*root_flags |= CGRP_ROOT_NS_DELEGATE;
 			continue;
+		} else if (!strcmp(token, "groupoom")) {
+			*root_flags |= CGRP_GROUP_OOM;
+			continue;
 		}
 
 		pr_err("cgroup2: unknown option \"%s\"\n", token);
@@ -1747,6 +1751,11 @@ static void apply_cgroup_root_flags(unsigned int root_flags)
 			cgrp_dfl_root.flags |= CGRP_ROOT_NS_DELEGATE;
 		else
 			cgrp_dfl_root.flags &= ~CGRP_ROOT_NS_DELEGATE;
+
+		if (root_flags & CGRP_GROUP_OOM)
+			cgrp_dfl_root.flags |= CGRP_GROUP_OOM;
+		else
+			cgrp_dfl_root.flags &= ~CGRP_GROUP_OOM;
 	}
 }
 
@@ -1754,6 +1763,8 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root
 {
 	if (cgrp_dfl_root.flags & CGRP_ROOT_NS_DELEGATE)
 		seq_puts(seq, ",nsdelegate");
+	if (cgrp_dfl_root.flags & CGRP_GROUP_OOM)
+		seq_puts(seq, ",groupoom");
 	return 0;
 }
 
@@ -5911,7 +5922,8 @@ static struct kobj_attribute cgroup_delegate_attr = __ATTR_RO(delegate);
 static ssize_t features_show(struct kobject *kobj, struct kobj_attribute *attr,
 			     char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "nsdelegate\n");
+	return snprintf(buf, PAGE_SIZE, "nsdelegate\n"
+					"groupoom\n");
 }
 static struct kobj_attribute cgroup_features_attr = __ATTR_RO(features);
 
diff --git a/kernel/cred.c b/kernel/cred.c
index ecf03657e71c..0192a94670e1 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -448,6 +448,7 @@ int commit_creds(struct cred *new)
 		if (task->mm)
 			set_dumpable(task->mm, suid_dumpable);
 		task->pdeath_signal = 0;
+		task->signal->pdeath_signal_proc = 0;
 		smp_wmb();
 	}
 
diff --git a/kernel/debug/kdb/kdb_bp.c b/kernel/debug/kdb/kdb_bp.c
index 90ff129c88a2..62c301ad0773 100644
--- a/kernel/debug/kdb/kdb_bp.c
+++ b/kernel/debug/kdb/kdb_bp.c
@@ -242,11 +242,11 @@ static void kdb_printbp(kdb_bp_t *bp, int i)
 	kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT);
 
 	if (bp->bp_enabled)
-		kdb_printf("\n    is enabled");
+		kdb_printf("\n    is enabled ");
 	else
 		kdb_printf("\n    is disabled");
 
-	kdb_printf("\taddr at %016lx, hardtype=%d installed=%d\n",
+	kdb_printf("  addr at %016lx, hardtype=%d installed=%d\n",
 		   bp->bp_addr, bp->bp_type, bp->bp_installed);
 
 	kdb_printf("\n");
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index dbb0781a0533..e405677ee08d 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -1150,6 +1150,16 @@ void kdb_set_current_task(struct task_struct *p)
 	kdb_current_regs = NULL;
 }
 
+static void drop_newline(char *buf)
+{
+	size_t len = strlen(buf);
+
+	if (len == 0)
+		return;
+	if (*(buf + len - 1) == '\n')
+		*(buf + len - 1) = '\0';
+}
+
 /*
  * kdb_local - The main code for kdb.  This routine is invoked on a
  *	specific processor, it is not global.  The main kdb() routine
@@ -1327,6 +1337,7 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
 		cmdptr = cmd_head;
 		diag = kdb_parse(cmdbuf);
 		if (diag == KDB_NOTFOUND) {
+			drop_newline(cmdbuf);
 			kdb_printf("Unknown kdb command: '%s'\n", cmdbuf);
 			diag = 0;
 		}
@@ -1566,6 +1577,7 @@ static int kdb_md(int argc, const char **argv)
 	int symbolic = 0;
 	int valid = 0;
 	int phys = 0;
+	int raw = 0;
 
 	kdbgetintenv("MDCOUNT", &mdcount);
 	kdbgetintenv("RADIX", &radix);
@@ -1575,9 +1587,10 @@ static int kdb_md(int argc, const char **argv)
 	repeat = mdcount * 16 / bytesperword;
 
 	if (strcmp(argv[0], "mdr") == 0) {
-		if (argc != 2)
+		if (argc == 2 || (argc == 0 && last_addr != 0))
+			valid = raw = 1;
+		else
 			return KDB_ARGCOUNT;
-		valid = 1;
 	} else if (isdigit(argv[0][2])) {
 		bytesperword = (int)(argv[0][2] - '0');
 		if (bytesperword == 0) {
@@ -1613,7 +1626,10 @@ static int kdb_md(int argc, const char **argv)
 		radix = last_radix;
 		bytesperword = last_bytesperword;
 		repeat = last_repeat;
-		mdcount = ((repeat * bytesperword) + 15) / 16;
+		if (raw)
+			mdcount = repeat;
+		else
+			mdcount = ((repeat * bytesperword) + 15) / 16;
 	}
 
 	if (argc) {
@@ -1630,7 +1646,10 @@ static int kdb_md(int argc, const char **argv)
 			diag = kdbgetularg(argv[nextarg], &val);
 			if (!diag) {
 				mdcount = (int) val;
-				repeat = mdcount * 16 / bytesperword;
+				if (raw)
+					repeat = mdcount;
+				else
+					repeat = mdcount * 16 / bytesperword;
 			}
 		}
 		if (argc >= nextarg+1) {
@@ -1640,8 +1659,15 @@ static int kdb_md(int argc, const char **argv)
 		}
 	}
 
-	if (strcmp(argv[0], "mdr") == 0)
-		return kdb_mdr(addr, mdcount);
+	if (strcmp(argv[0], "mdr") == 0) {
+		int ret;
+		last_addr = addr;
+		ret = kdb_mdr(addr, mdcount);
+		last_addr += mdcount;
+		last_repeat = mdcount;
+		last_bytesperword = bytesperword; // to make REPEAT happy
+		return ret;
+	}
 
 	switch (radix) {
 	case 10:
@@ -2473,41 +2499,6 @@ static int kdb_kill(int argc, const char **argv)
 	return 0;
 }
 
-struct kdb_tm {
-	int tm_sec;	/* seconds */
-	int tm_min;	/* minutes */
-	int tm_hour;	/* hours */
-	int tm_mday;	/* day of the month */
-	int tm_mon;	/* month */
-	int tm_year;	/* year */
-};
-
-static void kdb_gmtime(struct timespec *tv, struct kdb_tm *tm)
-{
-	/* This will work from 1970-2099, 2100 is not a leap year */
-	static int mon_day[] = { 31, 29, 31, 30, 31, 30, 31,
-				 31, 30, 31, 30, 31 };
-	memset(tm, 0, sizeof(*tm));
-	tm->tm_sec  = tv->tv_sec % (24 * 60 * 60);
-	tm->tm_mday = tv->tv_sec / (24 * 60 * 60) +
-		(2 * 365 + 1); /* shift base from 1970 to 1968 */
-	tm->tm_min =  tm->tm_sec / 60 % 60;
-	tm->tm_hour = tm->tm_sec / 60 / 60;
-	tm->tm_sec =  tm->tm_sec % 60;
-	tm->tm_year = 68 + 4*(tm->tm_mday / (4*365+1));
-	tm->tm_mday %= (4*365+1);
-	mon_day[1] = 29;
-	while (tm->tm_mday >= mon_day[tm->tm_mon]) {
-		tm->tm_mday -= mon_day[tm->tm_mon];
-		if (++tm->tm_mon == 12) {
-			tm->tm_mon = 0;
-			++tm->tm_year;
-			mon_day[1] = 28;
-		}
-	}
-	++tm->tm_mday;
-}
-
 /*
  * Most of this code has been lifted from kernel/timer.c::sys_sysinfo().
  * I cannot call that code directly from kdb, it has an unconditional
@@ -2515,10 +2506,10 @@ static void kdb_gmtime(struct timespec *tv, struct kdb_tm *tm)
  */
 static void kdb_sysinfo(struct sysinfo *val)
 {
-	struct timespec uptime;
-	ktime_get_ts(&uptime);
+	u64 uptime = ktime_get_mono_fast_ns();
+
 	memset(val, 0, sizeof(*val));
-	val->uptime = uptime.tv_sec;
+	val->uptime = div_u64(uptime, NSEC_PER_SEC);
 	val->loads[0] = avenrun[0];
 	val->loads[1] = avenrun[1];
 	val->loads[2] = avenrun[2];
@@ -2533,8 +2524,8 @@ static void kdb_sysinfo(struct sysinfo *val)
  */
 static int kdb_summary(int argc, const char **argv)
 {
-	struct timespec now;
-	struct kdb_tm tm;
+	time64_t now;
+	struct tm tm;
 	struct sysinfo val;
 
 	if (argc)
@@ -2548,9 +2539,9 @@ static int kdb_summary(int argc, const char **argv)
 	kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
 	kdb_printf("ccversion  %s\n", __stringify(CCVERSION));
 
-	now = __current_kernel_time();
-	kdb_gmtime(&now, &tm);
-	kdb_printf("date       %04d-%02d-%02d %02d:%02d:%02d "
+	now = __ktime_get_real_seconds();
+	time64_to_tm(now, 0, &tm);
+	kdb_printf("date       %04ld-%02d-%02d %02d:%02d:%02d "
 		   "tz_minuteswest %d\n",
 		1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
 		tm.tm_hour, tm.tm_min, tm.tm_sec,
diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c
index d35cc2d3a4cc..990b3cc526c8 100644
--- a/kernel/debug/kdb/kdb_support.c
+++ b/kernel/debug/kdb/kdb_support.c
@@ -129,13 +129,13 @@ int kdbnearsym(unsigned long addr, kdb_symtab_t *symtab)
 		}
 		if (i >= ARRAY_SIZE(kdb_name_table)) {
 			debug_kfree(kdb_name_table[0]);
-			memcpy(kdb_name_table, kdb_name_table+1,
+			memmove(kdb_name_table, kdb_name_table+1,
 			       sizeof(kdb_name_table[0]) *
 			       (ARRAY_SIZE(kdb_name_table)-1));
 		} else {
 			debug_kfree(knt1);
 			knt1 = kdb_name_table[i];
-			memcpy(kdb_name_table+i, kdb_name_table+i+1,
+			memmove(kdb_name_table+i, kdb_name_table+i+1,
 			       sizeof(kdb_name_table[0]) *
 			       (ARRAY_SIZE(kdb_name_table)-i-1));
 		}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 96db9ae5d5af..57898102847f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7996,9 +7996,119 @@ static struct pmu perf_tracepoint = {
 	.read		= perf_swevent_read,
 };
 
+#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
+/*
+ * Flags in config, used by dynamic PMU kprobe and uprobe
+ * The flags should match following PMU_FORMAT_ATTR().
+ *
+ * PERF_PROBE_CONFIG_IS_RETPROBE if set, create kretprobe/uretprobe
+ *                               if not set, create kprobe/uprobe
+ */
+enum perf_probe_config {
+	PERF_PROBE_CONFIG_IS_RETPROBE = 1U << 0,  /* [k,u]retprobe */
+};
+
+PMU_FORMAT_ATTR(retprobe, "config:0");
+
+static struct attribute *probe_attrs[] = {
+	&format_attr_retprobe.attr,
+	NULL,
+};
+
+static struct attribute_group probe_format_group = {
+	.name = "format",
+	.attrs = probe_attrs,
+};
+
+static const struct attribute_group *probe_attr_groups[] = {
+	&probe_format_group,
+	NULL,
+};
+#endif
+
+#ifdef CONFIG_KPROBE_EVENTS
+static int perf_kprobe_event_init(struct perf_event *event);
+static struct pmu perf_kprobe = {
+	.task_ctx_nr	= perf_sw_context,
+	.event_init	= perf_kprobe_event_init,
+	.add		= perf_trace_add,
+	.del		= perf_trace_del,
+	.start		= perf_swevent_start,
+	.stop		= perf_swevent_stop,
+	.read		= perf_swevent_read,
+	.attr_groups	= probe_attr_groups,
+};
+
+static int perf_kprobe_event_init(struct perf_event *event)
+{
+	int err;
+	bool is_retprobe;
+
+	if (event->attr.type != perf_kprobe.type)
+		return -ENOENT;
+	/*
+	 * no branch sampling for probe events
+	 */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
+	is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
+	err = perf_kprobe_init(event, is_retprobe);
+	if (err)
+		return err;
+
+	event->destroy = perf_kprobe_destroy;
+
+	return 0;
+}
+#endif /* CONFIG_KPROBE_EVENTS */
+
+#ifdef CONFIG_UPROBE_EVENTS
+static int perf_uprobe_event_init(struct perf_event *event);
+static struct pmu perf_uprobe = {
+	.task_ctx_nr	= perf_sw_context,
+	.event_init	= perf_uprobe_event_init,
+	.add		= perf_trace_add,
+	.del		= perf_trace_del,
+	.start		= perf_swevent_start,
+	.stop		= perf_swevent_stop,
+	.read		= perf_swevent_read,
+	.attr_groups	= probe_attr_groups,
+};
+
+static int perf_uprobe_event_init(struct perf_event *event)
+{
+	int err;
+	bool is_retprobe;
+
+	if (event->attr.type != perf_uprobe.type)
+		return -ENOENT;
+	/*
+	 * no branch sampling for probe events
+	 */
+	if (has_branch_stack(event))
+		return -EOPNOTSUPP;
+
+	is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
+	err = perf_uprobe_init(event, is_retprobe);
+	if (err)
+		return err;
+
+	event->destroy = perf_uprobe_destroy;
+
+	return 0;
+}
+#endif /* CONFIG_UPROBE_EVENTS */
+
 static inline void perf_tp_register(void)
 {
 	perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);
+#ifdef CONFIG_KPROBE_EVENTS
+	perf_pmu_register(&perf_kprobe, "kprobe", -1);
+#endif
+#ifdef CONFIG_UPROBE_EVENTS
+	perf_pmu_register(&perf_uprobe, "uprobe", -1);
+#endif
 }
 
 static void perf_event_free_filter(struct perf_event *event)
@@ -8075,13 +8185,32 @@ static void perf_event_free_bpf_handler(struct perf_event *event)
 }
 #endif
 
+/*
+ * returns true if the event is a tracepoint, or a kprobe/upprobe created
+ * with perf_event_open()
+ */
+static inline bool perf_event_is_tracing(struct perf_event *event)
+{
+	if (event->pmu == &perf_tracepoint)
+		return true;
+#ifdef CONFIG_KPROBE_EVENTS
+	if (event->pmu == &perf_kprobe)
+		return true;
+#endif
+#ifdef CONFIG_UPROBE_EVENTS
+	if (event->pmu == &perf_uprobe)
+		return true;
+#endif
+	return false;
+}
+
 static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
 {
 	bool is_kprobe, is_tracepoint, is_syscall_tp;
 	struct bpf_prog *prog;
 	int ret;
 
-	if (event->attr.type != PERF_TYPE_TRACEPOINT)
+	if (!perf_event_is_tracing(event))
 		return perf_event_set_bpf_handler(event, prog_fd);
 
 	is_kprobe = event->tp_event->flags & TRACE_EVENT_FL_UKPROBE;
@@ -8127,7 +8256,7 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
 
 static void perf_event_free_bpf_prog(struct perf_event *event)
 {
-	if (event->attr.type != PERF_TYPE_TRACEPOINT) {
+	if (!perf_event_is_tracing(event)) {
 		perf_event_free_bpf_handler(event);
 		return;
 	}
@@ -8546,47 +8675,36 @@ perf_event_set_addr_filter(struct perf_event *event, char *filter_str)
 	return ret;
 }
 
-static int
-perf_tracepoint_set_filter(struct perf_event *event, char *filter_str)
-{
-	struct perf_event_context *ctx = event->ctx;
-	int ret;
-
-	/*
-	 * Beware, here be dragons!!
-	 *
-	 * the tracepoint muck will deadlock against ctx->mutex, but the tracepoint
-	 * stuff does not actually need it. So temporarily drop ctx->mutex. As per
-	 * perf_event_ctx_lock() we already have a reference on ctx.
-	 *
-	 * This can result in event getting moved to a different ctx, but that
-	 * does not affect the tracepoint state.
-	 */
-	mutex_unlock(&ctx->mutex);
-	ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
-	mutex_lock(&ctx->mutex);
-
-	return ret;
-}
-
 static int perf_event_set_filter(struct perf_event *event, void __user *arg)
 {
-	char *filter_str;
 	int ret = -EINVAL;
-
-	if ((event->attr.type != PERF_TYPE_TRACEPOINT ||
-	    !IS_ENABLED(CONFIG_EVENT_TRACING)) &&
-	    !has_addr_filter(event))
-		return -EINVAL;
+	char *filter_str;
 
 	filter_str = strndup_user(arg, PAGE_SIZE);
 	if (IS_ERR(filter_str))
 		return PTR_ERR(filter_str);
 
-	if (IS_ENABLED(CONFIG_EVENT_TRACING) &&
-	    event->attr.type == PERF_TYPE_TRACEPOINT)
-		ret = perf_tracepoint_set_filter(event, filter_str);
-	else if (has_addr_filter(event))
+#ifdef CONFIG_EVENT_TRACING
+	if (perf_event_is_tracing(event)) {
+		struct perf_event_context *ctx = event->ctx;
+
+		/*
+		 * Beware, here be dragons!!
+		 *
+		 * the tracepoint muck will deadlock against ctx->mutex, but
+		 * the tracepoint stuff does not actually need it. So
+		 * temporarily drop ctx->mutex. As per perf_event_ctx_lock() we
+		 * already have a reference on ctx.
+		 *
+		 * This can result in event getting moved to a different ctx,
+		 * but that does not affect the tracepoint state.
+		 */
+		mutex_unlock(&ctx->mutex);
+		ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
+		mutex_lock(&ctx->mutex);
+	} else
+#endif
+	if (has_addr_filter(event))
 		ret = perf_event_set_addr_filter(event, filter_str);
 
 	kfree(filter_str);
diff --git a/kernel/exit.c b/kernel/exit.c
index 995453d9fb55..42ca71a44c9a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -635,6 +635,10 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
 	if (unlikely(p->exit_state == EXIT_DEAD))
 		return;
 
+	if (p->signal->pdeath_signal_proc)
+		group_send_sig_info(p->signal->pdeath_signal_proc,
+				    SEND_SIG_NOINFO, p);
+
 	/* We don't want people slaying init. */
 	p->exit_signal = SIGCHLD;
 
diff --git a/kernel/fork.c b/kernel/fork.c
index be8aa5b98666..f19b04de452b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -592,7 +592,7 @@ static void check_mm(struct mm_struct *mm)
  * is dropped: either by a lazy thread or by
  * mmput. Free the page directory and the mm.
  */
-static void __mmdrop(struct mm_struct *mm)
+void __mmdrop(struct mm_struct *mm)
 {
 	BUG_ON(mm == &init_mm);
 	mm_free_pgd(mm);
@@ -603,18 +603,7 @@ static void __mmdrop(struct mm_struct *mm)
 	put_user_ns(mm->user_ns);
 	free_mm(mm);
 }
-
-void mmdrop(struct mm_struct *mm)
-{
-	/*
-	 * The implicit full barrier implied by atomic_dec_and_test() is
-	 * required by the membarrier system call before returning to
-	 * user-space, after storing to rq->curr.
-	 */
-	if (unlikely(atomic_dec_and_test(&mm->mm_count)))
-		__mmdrop(mm);
-}
-EXPORT_SYMBOL_GPL(mmdrop);
+EXPORT_SYMBOL_GPL(__mmdrop);
 
 static void mmdrop_async_fn(struct work_struct *work)
 {
@@ -1480,6 +1469,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 
 	mutex_init(&sig->cred_guard_mutex);
 
+	sig->pdeath_signal_proc = current->signal->pdeath_signal_proc;
+
 	return 0;
 }
 
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0f922729bab9..d2b3c59f1200 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -855,10 +855,14 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
 	 * This code is triggered unconditionally. Check the affinity
 	 * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
 	 */
-	if (cpumask_available(desc->irq_common_data.affinity))
-		cpumask_copy(mask, desc->irq_common_data.affinity);
-	else
+	if (cpumask_available(desc->irq_common_data.affinity)) {
+		const struct cpumask *m;
+
+		m = irq_data_get_effective_affinity_mask(&desc->irq_data);
+		cpumask_copy(mask, m);
+	} else {
 		valid = false;
+	}
 	raw_spin_unlock_irq(&desc->lock);
 
 	if (valid)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index fc1123583fa6..8e015f35532e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -48,6 +48,7 @@
 #include <linux/sched/clock.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/task_stack.h>
+#include <linux/kexec.h>
 
 #include <linux/uaccess.h>
 #include <asm/sections.h>
@@ -2335,10 +2336,6 @@ void console_unlock(void)
 
 		printk_safe_enter_irqsave(flags);
 		raw_spin_lock(&logbuf_lock);
-		if (seen_seq != log_next_seq) {
-			wake_klogd = true;
-			seen_seq = log_next_seq;
-		}
 
 		if (console_seq < log_first_seq) {
 			len = sprintf(text, "** %u printk messages dropped **\n",
@@ -2417,12 +2414,17 @@ void console_unlock(void)
 	up_console_sem();
 
 	/*
-	 * Someone could have filled up the buffer again, so re-check if there's
-	 * something to flush. In case we cannot trylock the console_sem again,
-	 * there's a new owner and the console_unlock() from them will do the
-	 * flush, no worries.
+	 * Check whether userland needs notification.  Also, someone could
+	 * have filled up the buffer again, so re-check if there's
+	 * something to flush. In case we cannot trylock the console_sem
+	 * again, there's a new owner and the console_unlock() from them
+	 * will do the flush, no worries.
 	 */
 	raw_spin_lock(&logbuf_lock);
+	if (seen_seq != log_next_seq) {
+		wake_klogd = true;
+		seen_seq = log_next_seq;
+	}
 	retry = console_seq != log_next_seq;
 	raw_spin_unlock(&logbuf_lock);
 	printk_safe_exit_irqrestore(flags);
@@ -3287,9 +3289,11 @@ void __init dump_stack_set_arch_desc(const char *fmt, ...)
  */
 void dump_stack_print_info(const char *log_lvl)
 {
-	printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
+	printk("%sCPU: %d PID: %d Comm: %.20s %s%s %s %.*s\n",
 	       log_lvl, raw_smp_processor_id(), current->pid, current->comm,
-	       print_tainted(), init_utsname()->release,
+	       kexec_crash_loaded() ? "Kdump: loaded " : "",
+	       print_tainted(),
+	       init_utsname()->release,
 	       (int)strcspn(init_utsname()->version, " "),
 	       init_utsname()->version);
 
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index 6334f2c1abd0..1c868bcfd705 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -77,12 +77,18 @@ static inline void rcu_seq_start(unsigned long *sp)
 	WARN_ON_ONCE(rcu_seq_state(*sp) != 1);
 }
 
+/* Compute the end-of-grace-period value for the specified sequence number. */
+static inline unsigned long rcu_seq_endval(unsigned long *sp)
+{
+	return (*sp | RCU_SEQ_STATE_MASK) + 1;
+}
+
 /* Adjust sequence number for end of update-side operation. */
 static inline void rcu_seq_end(unsigned long *sp)
 {
 	smp_mb(); /* Ensure update-side operation before counter increment. */
 	WARN_ON_ONCE(!rcu_seq_state(*sp));
-	WRITE_ONCE(*sp, (*sp | RCU_SEQ_STATE_MASK) + 1);
+	WRITE_ONCE(*sp, rcu_seq_endval(sp));
 }
 
 /* Take a snapshot of the update side's sequence number. */
@@ -295,9 +301,19 @@ static inline void rcu_init_levelspread(int *levelspread, const int *levelcnt)
  * Iterate over all possible CPUs in a leaf RCU node.
  */
 #define for_each_leaf_node_possible_cpu(rnp, cpu) \
-	for ((cpu) = cpumask_next(rnp->grplo - 1, cpu_possible_mask); \
-	     cpu <= rnp->grphi; \
-	     cpu = cpumask_next((cpu), cpu_possible_mask))
+	for ((cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \
+	     (cpu) <= rnp->grphi; \
+	     (cpu) = cpumask_next((cpu), cpu_possible_mask))
+
+/*
+ * Iterate over all CPUs in a leaf RCU node's specified mask.
+ */
+#define rcu_find_next_bit(rnp, cpu, mask) \
+	((rnp)->grplo + find_next_bit(&(mask), BITS_PER_LONG, (cpu)))
+#define for_each_leaf_node_cpu_mask(rnp, cpu, mask) \
+	for ((cpu) = rcu_find_next_bit((rnp), 0, (mask)); \
+	     (cpu) <= rnp->grphi; \
+	     (cpu) = rcu_find_next_bit((rnp), (cpu) + 1 - (rnp->grplo), (mask)))
 
 /*
  * Wrappers for the rcu_node::lock acquire and release.
@@ -337,7 +353,7 @@ do {									\
 } while (0)
 
 #define raw_spin_unlock_irqrestore_rcu_node(p, flags)			\
-	raw_spin_unlock_irqrestore(&ACCESS_PRIVATE(p, lock), flags)	\
+	raw_spin_unlock_irqrestore(&ACCESS_PRIVATE(p, lock), flags)
 
 #define raw_spin_trylock_rcu_node(p)					\
 ({									\
@@ -348,6 +364,9 @@ do {									\
 	___locked;							\
 })
 
+#define raw_lockdep_assert_held_rcu_node(p)				\
+	lockdep_assert_held(&ACCESS_PRIVATE(p, lock))
+
 #endif /* #if defined(SRCU) || !defined(TINY_RCU) */
 
 #ifdef CONFIG_TINY_RCU
@@ -356,24 +375,20 @@ static inline bool rcu_gp_is_normal(void) { return true; }
 static inline bool rcu_gp_is_expedited(void) { return false; }
 static inline void rcu_expedite_gp(void) { }
 static inline void rcu_unexpedite_gp(void) { }
+static inline void rcu_request_urgent_qs_task(struct task_struct *t) { }
 #else /* #ifdef CONFIG_TINY_RCU */
 bool rcu_gp_is_normal(void);     /* Internal RCU use. */
 bool rcu_gp_is_expedited(void);  /* Internal RCU use. */
 void rcu_expedite_gp(void);
 void rcu_unexpedite_gp(void);
 void rcupdate_announce_bootup_oddness(void);
+void rcu_request_urgent_qs_task(struct task_struct *t);
 #endif /* #else #ifdef CONFIG_TINY_RCU */
 
 #define RCU_SCHEDULER_INACTIVE	0
 #define RCU_SCHEDULER_INIT	1
 #define RCU_SCHEDULER_RUNNING	2
 
-#ifdef CONFIG_TINY_RCU
-static inline void rcu_request_urgent_qs_task(struct task_struct *t) { }
-#else /* #ifdef CONFIG_TINY_RCU */
-void rcu_request_urgent_qs_task(struct task_struct *t);
-#endif /* #else #ifdef CONFIG_TINY_RCU */
-
 enum rcutorture_type {
 	RCU_FLAVOR,
 	RCU_BH_FLAVOR,
diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c
index d1ebdf9868bb..777e7a6a0292 100644
--- a/kernel/rcu/rcuperf.c
+++ b/kernel/rcu/rcuperf.c
@@ -61,11 +61,30 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.vnet.ibm.com>");
 #define VERBOSE_PERFOUT_ERRSTRING(s) \
 	do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } while (0)
 
+/*
+ * The intended use cases for the nreaders and nwriters module parameters
+ * are as follows:
+ *
+ * 1.	Specify only the nr_cpus kernel boot parameter.  This will
+ *	set both nreaders and nwriters to the value specified by
+ *	nr_cpus for a mixed reader/writer test.
+ *
+ * 2.	Specify the nr_cpus kernel boot parameter, but set
+ *	rcuperf.nreaders to zero.  This will set nwriters to the
+ *	value specified by nr_cpus for an update-only test.
+ *
+ * 3.	Specify the nr_cpus kernel boot parameter, but set
+ *	rcuperf.nwriters to zero.  This will set nreaders to the
+ *	value specified by nr_cpus for a read-only test.
+ *
+ * Various other use cases may of course be specified.
+ */
+
 torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");
 torture_param(int, gp_async_max, 1000, "Max # outstanding waits per reader");
 torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
 torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
-torture_param(int, nreaders, 0, "Number of RCU reader threads");
+torture_param(int, nreaders, -1, "Number of RCU reader threads");
 torture_param(int, nwriters, -1, "Number of RCU updater threads");
 torture_param(bool, shutdown, !IS_ENABLED(MODULE),
 	      "Shutdown at end of performance tests.");
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 308e6fdbced8..680c96d8c00f 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -909,34 +909,38 @@ rcu_torture_writer(void *arg)
 	int nsynctypes = 0;
 
 	VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
-	if (!can_expedite) {
+	if (!can_expedite)
 		pr_alert("%s" TORTURE_FLAG
-			 " GP expediting controlled from boot/sysfs for %s,\n",
+			 " GP expediting controlled from boot/sysfs for %s.\n",
 			 torture_type, cur_ops->name);
-		pr_alert("%s" TORTURE_FLAG
-			 " Disabled dynamic grace-period expediting.\n",
-			 torture_type);
-	}
 
 	/* Initialize synctype[] array.  If none set, take default. */
 	if (!gp_cond1 && !gp_exp1 && !gp_normal1 && !gp_sync1)
 		gp_cond1 = gp_exp1 = gp_normal1 = gp_sync1 = true;
-	if (gp_cond1 && cur_ops->get_state && cur_ops->cond_sync)
+	if (gp_cond1 && cur_ops->get_state && cur_ops->cond_sync) {
 		synctype[nsynctypes++] = RTWS_COND_GET;
-	else if (gp_cond && (!cur_ops->get_state || !cur_ops->cond_sync))
-		pr_alert("rcu_torture_writer: gp_cond without primitives.\n");
-	if (gp_exp1 && cur_ops->exp_sync)
+		pr_info("%s: Testing conditional GPs.\n", __func__);
+	} else if (gp_cond && (!cur_ops->get_state || !cur_ops->cond_sync)) {
+		pr_alert("%s: gp_cond without primitives.\n", __func__);
+	}
+	if (gp_exp1 && cur_ops->exp_sync) {
 		synctype[nsynctypes++] = RTWS_EXP_SYNC;
-	else if (gp_exp && !cur_ops->exp_sync)
-		pr_alert("rcu_torture_writer: gp_exp without primitives.\n");
-	if (gp_normal1 && cur_ops->deferred_free)
+		pr_info("%s: Testing expedited GPs.\n", __func__);
+	} else if (gp_exp && !cur_ops->exp_sync) {
+		pr_alert("%s: gp_exp without primitives.\n", __func__);
+	}
+	if (gp_normal1 && cur_ops->deferred_free) {
 		synctype[nsynctypes++] = RTWS_DEF_FREE;
-	else if (gp_normal && !cur_ops->deferred_free)
-		pr_alert("rcu_torture_writer: gp_normal without primitives.\n");
-	if (gp_sync1 && cur_ops->sync)
+		pr_info("%s: Testing asynchronous GPs.\n", __func__);
+	} else if (gp_normal && !cur_ops->deferred_free) {
+		pr_alert("%s: gp_normal without primitives.\n", __func__);
+	}
+	if (gp_sync1 && cur_ops->sync) {
 		synctype[nsynctypes++] = RTWS_SYNC;
-	else if (gp_sync && !cur_ops->sync)
-		pr_alert("rcu_torture_writer: gp_sync without primitives.\n");
+		pr_info("%s: Testing normal GPs.\n", __func__);
+	} else if (gp_sync && !cur_ops->sync) {
+		pr_alert("%s: gp_sync without primitives.\n", __func__);
+	}
 	if (WARN_ONCE(nsynctypes == 0,
 		      "rcu_torture_writer: No update-side primitives.\n")) {
 		/*
@@ -1011,6 +1015,9 @@ rcu_torture_writer(void *arg)
 				rcu_unexpedite_gp();
 			if (++expediting > 3)
 				expediting = -expediting;
+		} else if (!can_expedite) { /* Disabled during boot, recheck. */
+			can_expedite = !rcu_gp_is_expedited() &&
+				       !rcu_gp_is_normal();
 		}
 		rcu_torture_writer_state = RTWS_STUTTER;
 		stutter_wait("rcu_torture_writer");
@@ -1021,6 +1028,10 @@ rcu_torture_writer(void *arg)
 	while (can_expedite && expediting++ < 0)
 		rcu_unexpedite_gp();
 	WARN_ON_ONCE(can_expedite && rcu_gp_is_expedited());
+	if (!can_expedite)
+		pr_alert("%s" TORTURE_FLAG
+			 " Dynamic grace-period expediting was disabled.\n",
+			 torture_type);
 	rcu_torture_writer_state = RTWS_STOPPING;
 	torture_kthread_stopping("rcu_torture_writer");
 	return 0;
@@ -1045,13 +1056,13 @@ rcu_torture_fakewriter(void *arg)
 		    torture_random(&rand) % (nfakewriters * 8) == 0) {
 			cur_ops->cb_barrier();
 		} else if (gp_normal == gp_exp) {
-			if (torture_random(&rand) & 0x80)
+			if (cur_ops->sync && torture_random(&rand) & 0x80)
 				cur_ops->sync();
-			else
+			else if (cur_ops->exp_sync)
 				cur_ops->exp_sync();
-		} else if (gp_normal) {
+		} else if (gp_normal && cur_ops->sync) {
 			cur_ops->sync();
-		} else {
+		} else if (cur_ops->exp_sync) {
 			cur_ops->exp_sync();
 		}
 		stutter_wait("rcu_torture_fakewriter");
@@ -1557,11 +1568,10 @@ static int rcu_torture_barrier_init(void)
 	atomic_set(&barrier_cbs_count, 0);
 	atomic_set(&barrier_cbs_invoked, 0);
 	barrier_cbs_tasks =
-		kzalloc(n_barrier_cbs * sizeof(barrier_cbs_tasks[0]),
+		kcalloc(n_barrier_cbs, sizeof(barrier_cbs_tasks[0]),
 			GFP_KERNEL);
 	barrier_cbs_wq =
-		kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]),
-			GFP_KERNEL);
+		kcalloc(n_barrier_cbs, sizeof(barrier_cbs_wq[0]), GFP_KERNEL);
 	if (barrier_cbs_tasks == NULL || !barrier_cbs_wq)
 		return -ENOMEM;
 	for (i = 0; i < n_barrier_cbs; i++) {
@@ -1674,7 +1684,7 @@ static void rcu_torture_err_cb(struct rcu_head *rhp)
 	 * next grace period.  Unlikely, but can happen.  If it
 	 * does happen, the debug-objects subsystem won't have splatted.
 	 */
-	pr_alert("rcutorture: duplicated callback was invoked.\n");
+	pr_alert("%s: duplicated callback was invoked.\n", KBUILD_MODNAME);
 }
 #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
@@ -1691,7 +1701,7 @@ static void rcu_test_debug_objects(void)
 
 	init_rcu_head_on_stack(&rh1);
 	init_rcu_head_on_stack(&rh2);
-	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+	pr_alert("%s: WARN: Duplicate call_rcu() test starting.\n", KBUILD_MODNAME);
 
 	/* Try to queue the rh2 pair of callbacks for the same grace period. */
 	preempt_disable(); /* Prevent preemption from interrupting test. */
@@ -1706,11 +1716,11 @@ static void rcu_test_debug_objects(void)
 
 	/* Wait for them all to get done so we can safely return. */
 	rcu_barrier();
-	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	pr_alert("%s: WARN: Duplicate call_rcu() test complete.\n", KBUILD_MODNAME);
 	destroy_rcu_head_on_stack(&rh1);
 	destroy_rcu_head_on_stack(&rh2);
 #else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+	pr_alert("%s: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n", KBUILD_MODNAME);
 #endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 }
 
@@ -1799,7 +1809,7 @@ rcu_torture_init(void)
 	if (firsterr)
 		goto unwind;
 	if (nfakewriters > 0) {
-		fakewriter_tasks = kzalloc(nfakewriters *
+		fakewriter_tasks = kcalloc(nfakewriters,
 					   sizeof(fakewriter_tasks[0]),
 					   GFP_KERNEL);
 		if (fakewriter_tasks == NULL) {
@@ -1814,7 +1824,7 @@ rcu_torture_init(void)
 		if (firsterr)
 			goto unwind;
 	}
-	reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
+	reader_tasks = kcalloc(nrealreaders, sizeof(reader_tasks[0]),
 			       GFP_KERNEL);
 	if (reader_tasks == NULL) {
 		VERBOSE_TOROUT_ERRSTRING("out of memory");
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
index d5cea81378cc..39e50febe0b4 100644
--- a/kernel/rcu/srcutree.c
+++ b/kernel/rcu/srcutree.c
@@ -386,7 +386,7 @@ void cleanup_srcu_struct(struct srcu_struct *sp)
 		flush_delayed_work(&per_cpu_ptr(sp->sda, cpu)->work);
 	if (WARN_ON(rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)) != SRCU_STATE_IDLE) ||
 	    WARN_ON(srcu_readers_active(sp))) {
-		pr_info("cleanup_srcu_struct: Active srcu_struct %p state: %d\n", sp, rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)));
+		pr_info("%s: Active srcu_struct %p state: %d\n", __func__, sp, rcu_seq_state(READ_ONCE(sp->srcu_gp_seq)));
 		return; /* Caller forgot to stop doing call_srcu()? */
 	}
 	free_percpu(sp->sda);
@@ -439,7 +439,7 @@ static void srcu_gp_start(struct srcu_struct *sp)
 	struct srcu_data *sdp = this_cpu_ptr(sp->sda);
 	int state;
 
-	lockdep_assert_held(&sp->lock);
+	lockdep_assert_held(&ACCESS_PRIVATE(sp, lock));
 	WARN_ON_ONCE(ULONG_CMP_GE(sp->srcu_gp_seq, sp->srcu_gp_seq_needed));
 	rcu_segcblist_advance(&sdp->srcu_cblist,
 			      rcu_seq_current(&sp->srcu_gp_seq));
@@ -527,11 +527,11 @@ static void srcu_gp_end(struct srcu_struct *sp)
 {
 	unsigned long cbdelay;
 	bool cbs;
+	bool last_lvl;
 	int cpu;
 	unsigned long flags;
 	unsigned long gpseq;
 	int idx;
-	int idxnext;
 	unsigned long mask;
 	struct srcu_data *sdp;
 	struct srcu_node *snp;
@@ -555,11 +555,11 @@ static void srcu_gp_end(struct srcu_struct *sp)
 
 	/* Initiate callback invocation as needed. */
 	idx = rcu_seq_ctr(gpseq) % ARRAY_SIZE(snp->srcu_have_cbs);
-	idxnext = (idx + 1) % ARRAY_SIZE(snp->srcu_have_cbs);
 	rcu_for_each_node_breadth_first(sp, snp) {
 		spin_lock_irq_rcu_node(snp);
 		cbs = false;
-		if (snp >= sp->level[rcu_num_lvls - 1])
+		last_lvl = snp >= sp->level[rcu_num_lvls - 1];
+		if (last_lvl)
 			cbs = snp->srcu_have_cbs[idx] == gpseq;
 		snp->srcu_have_cbs[idx] = gpseq;
 		rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1);
@@ -572,13 +572,16 @@ static void srcu_gp_end(struct srcu_struct *sp)
 			srcu_schedule_cbs_snp(sp, snp, mask, cbdelay);
 
 		/* Occasionally prevent srcu_data counter wrap. */
-		if (!(gpseq & counter_wrap_check))
+		if (!(gpseq & counter_wrap_check) && last_lvl)
 			for (cpu = snp->grplo; cpu <= snp->grphi; cpu++) {
 				sdp = per_cpu_ptr(sp->sda, cpu);
 				spin_lock_irqsave_rcu_node(sdp, flags);
 				if (ULONG_CMP_GE(gpseq,
 						 sdp->srcu_gp_seq_needed + 100))
 					sdp->srcu_gp_seq_needed = gpseq;
+				if (ULONG_CMP_GE(gpseq,
+						 sdp->srcu_gp_seq_needed_exp + 100))
+					sdp->srcu_gp_seq_needed_exp = gpseq;
 				spin_unlock_irqrestore_rcu_node(sdp, flags);
 			}
 	}
@@ -593,9 +596,7 @@ static void srcu_gp_end(struct srcu_struct *sp)
 	    ULONG_CMP_LT(gpseq, sp->srcu_gp_seq_needed)) {
 		srcu_gp_start(sp);
 		spin_unlock_irq_rcu_node(sp);
-		/* Throttle expedited grace periods: Should be rare! */
-		srcu_reschedule(sp, rcu_seq_ctr(gpseq) & 0x3ff
-				    ? 0 : SRCU_INTERVAL);
+		srcu_reschedule(sp, 0);
 	} else {
 		spin_unlock_irq_rcu_node(sp);
 	}
@@ -626,7 +627,7 @@ static void srcu_funnel_exp_start(struct srcu_struct *sp, struct srcu_node *snp,
 		spin_unlock_irqrestore_rcu_node(snp, flags);
 	}
 	spin_lock_irqsave_rcu_node(sp, flags);
-	if (!ULONG_CMP_LT(sp->srcu_gp_seq_needed_exp, s))
+	if (ULONG_CMP_LT(sp->srcu_gp_seq_needed_exp, s))
 		sp->srcu_gp_seq_needed_exp = s;
 	spin_unlock_irqrestore_rcu_node(sp, flags);
 }
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 491bdf39f276..b699e7c58f21 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1161,7 +1161,7 @@ static int rcu_is_cpu_rrupt_from_idle(void)
  */
 static void rcu_gpnum_ovf(struct rcu_node *rnp, struct rcu_data *rdp)
 {
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	if (ULONG_CMP_LT(READ_ONCE(rdp->gpnum) + ULONG_MAX / 4, rnp->gpnum))
 		WRITE_ONCE(rdp->gpwrap, true);
 	if (ULONG_CMP_LT(rdp->rcu_iw_gpnum + ULONG_MAX / 4, rnp->gpnum))
@@ -1350,6 +1350,7 @@ static void rcu_check_gp_kthread_starvation(struct rcu_state *rsp)
 		       rsp->gp_kthread ? rsp->gp_kthread->state : ~0,
 		       rsp->gp_kthread ? task_cpu(rsp->gp_kthread) : -1);
 		if (rsp->gp_kthread) {
+			pr_err("RCU grace-period kthread stack dump:\n");
 			sched_show_task(rsp->gp_kthread);
 			wake_up_process(rsp->gp_kthread);
 		}
@@ -1628,7 +1629,7 @@ void rcu_cpu_stall_reset(void)
 static unsigned long rcu_cbs_completed(struct rcu_state *rsp,
 				       struct rcu_node *rnp)
 {
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 
 	/*
 	 * If RCU is idle, we just wait for the next grace period.
@@ -1675,7 +1676,7 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp,
 	bool ret = false;
 	struct rcu_node *rnp_root = rcu_get_root(rdp->rsp);
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 
 	/*
 	 * Pick up grace-period number for new callbacks.  If this
@@ -1803,7 +1804,7 @@ static bool rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
 {
 	bool ret = false;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 
 	/* If no pending (not yet ready to invoke) callbacks, nothing to do. */
 	if (!rcu_segcblist_pend_cbs(&rdp->cblist))
@@ -1843,7 +1844,7 @@ static bool rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
 static bool rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
 			    struct rcu_data *rdp)
 {
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 
 	/* If no pending (not yet ready to invoke) callbacks, nothing to do. */
 	if (!rcu_segcblist_pend_cbs(&rdp->cblist))
@@ -1871,7 +1872,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp,
 	bool ret;
 	bool need_gp;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 
 	/* Handle the ends of any preceding grace periods first. */
 	if (rdp->completed == rnp->completed &&
@@ -2139,7 +2140,8 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
 	 */
 	rcu_for_each_node_breadth_first(rsp, rnp) {
 		raw_spin_lock_irq_rcu_node(rnp);
-		WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp));
+		if (WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp)))
+			dump_blkd_tasks(rnp, 10);
 		WARN_ON_ONCE(rnp->qsmask);
 		WRITE_ONCE(rnp->completed, rsp->gpnum);
 		rdp = this_cpu_ptr(rsp->rda);
@@ -2296,7 +2298,7 @@ static bool
 rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
 		      struct rcu_data *rdp)
 {
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	if (!rsp->gp_kthread || !cpu_needs_another_gp(rsp, rdp)) {
 		/*
 		 * Either we have not yet spawned the grace-period
@@ -2358,7 +2360,7 @@ static bool rcu_start_gp(struct rcu_state *rsp)
 static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
 	__releases(rcu_get_root(rsp)->lock)
 {
-	lockdep_assert_held(&rcu_get_root(rsp)->lock);
+	raw_lockdep_assert_held_rcu_node(rcu_get_root(rsp));
 	WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
 	WRITE_ONCE(rsp->gp_flags, READ_ONCE(rsp->gp_flags) | RCU_GP_FLAG_FQS);
 	raw_spin_unlock_irqrestore_rcu_node(rcu_get_root(rsp), flags);
@@ -2383,7 +2385,7 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp,
 	unsigned long oldmask = 0;
 	struct rcu_node *rnp_c;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 
 	/* Walk up the rcu_node hierarchy. */
 	for (;;) {
@@ -2447,7 +2449,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_state *rsp,
 	unsigned long mask;
 	struct rcu_node *rnp_p;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	if (rcu_state_p == &rcu_sched_state || rsp != rcu_state_p ||
 	    rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) {
 		raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
@@ -2592,7 +2594,7 @@ static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf)
 	long mask;
 	struct rcu_node *rnp = rnp_leaf;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	if (!IS_ENABLED(CONFIG_HOTPLUG_CPU) ||
 	    rnp->qsmaskinit || rcu_preempt_has_tasks(rnp))
 		return;
@@ -2691,7 +2693,6 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 	/* Update counts and requeue any remaining callbacks. */
 	rcu_segcblist_insert_done_cbs(&rdp->cblist, &rcl);
 	smp_mb(); /* List handling before counting for rcu_barrier(). */
-	rdp->n_cbs_invoked += count;
 	rcu_segcblist_insert_count(&rdp->cblist, &rcl);
 
 	/* Reinstate batch limit if we have worked down the excess. */
@@ -2845,10 +2846,8 @@ static void force_quiescent_state(struct rcu_state *rsp)
 		      !raw_spin_trylock(&rnp->fqslock);
 		if (rnp_old != NULL)
 			raw_spin_unlock(&rnp_old->fqslock);
-		if (ret) {
-			rsp->n_force_qs_lh++;
+		if (ret)
 			return;
-		}
 		rnp_old = rnp;
 	}
 	/* rnp_old == rcu_get_root(rsp), rnp == NULL. */
@@ -2857,7 +2856,6 @@ static void force_quiescent_state(struct rcu_state *rsp)
 	raw_spin_lock_irqsave_rcu_node(rnp_old, flags);
 	raw_spin_unlock(&rnp_old->fqslock);
 	if (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
-		rsp->n_force_qs_lh++;
 		raw_spin_unlock_irqrestore_rcu_node(rnp_old, flags);
 		return;  /* Someone beat us to it. */
 	}
@@ -3355,8 +3353,6 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
 {
 	struct rcu_node *rnp = rdp->mynode;
 
-	rdp->n_rcu_pending++;
-
 	/* Check for CPU stalls, if enabled. */
 	check_cpu_stall(rsp, rdp);
 
@@ -3365,48 +3361,31 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
 		return 0;
 
 	/* Is the RCU core waiting for a quiescent state from this CPU? */
-	if (rcu_scheduler_fully_active &&
-	    rdp->core_needs_qs && rdp->cpu_no_qs.b.norm &&
-	    rdp->rcu_qs_ctr_snap == __this_cpu_read(rcu_dynticks.rcu_qs_ctr)) {
-		rdp->n_rp_core_needs_qs++;
-	} else if (rdp->core_needs_qs && !rdp->cpu_no_qs.b.norm) {
-		rdp->n_rp_report_qs++;
+	if (rdp->core_needs_qs && !rdp->cpu_no_qs.b.norm)
 		return 1;
-	}
 
 	/* Does this CPU have callbacks ready to invoke? */
-	if (rcu_segcblist_ready_cbs(&rdp->cblist)) {
-		rdp->n_rp_cb_ready++;
+	if (rcu_segcblist_ready_cbs(&rdp->cblist))
 		return 1;
-	}
 
 	/* Has RCU gone idle with this CPU needing another grace period? */
-	if (cpu_needs_another_gp(rsp, rdp)) {
-		rdp->n_rp_cpu_needs_gp++;
+	if (cpu_needs_another_gp(rsp, rdp))
 		return 1;
-	}
 
 	/* Has another RCU grace period completed?  */
-	if (READ_ONCE(rnp->completed) != rdp->completed) { /* outside lock */
-		rdp->n_rp_gp_completed++;
+	if (READ_ONCE(rnp->completed) != rdp->completed) /* outside lock */
 		return 1;
-	}
 
 	/* Has a new RCU grace period started? */
 	if (READ_ONCE(rnp->gpnum) != rdp->gpnum ||
-	    unlikely(READ_ONCE(rdp->gpwrap))) { /* outside lock */
-		rdp->n_rp_gp_started++;
+	    unlikely(READ_ONCE(rdp->gpwrap))) /* outside lock */
 		return 1;
-	}
 
 	/* Does this CPU need a deferred NOCB wakeup? */
-	if (rcu_nocb_need_deferred_wakeup(rdp)) {
-		rdp->n_rp_nocb_defer_wakeup++;
+	if (rcu_nocb_need_deferred_wakeup(rdp))
 		return 1;
-	}
 
 	/* nothing to do */
-	rdp->n_rp_need_nothing++;
 	return 0;
 }
 
@@ -3618,7 +3597,7 @@ static void rcu_init_new_rnp(struct rcu_node *rnp_leaf)
 	long mask;
 	struct rcu_node *rnp = rnp_leaf;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	for (;;) {
 		mask = rnp->grpmask;
 		rnp = rnp->parent;
@@ -3636,12 +3615,9 @@ static void rcu_init_new_rnp(struct rcu_node *rnp_leaf)
 static void __init
 rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
 {
-	unsigned long flags;
 	struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
-	struct rcu_node *rnp = rcu_get_root(rsp);
 
 	/* Set up local state, ensuring consistent view of global state. */
-	raw_spin_lock_irqsave_rcu_node(rnp, flags);
 	rdp->grpmask = leaf_node_cpu_bit(rdp->mynode, cpu);
 	rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
 	WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != 1);
@@ -3649,7 +3625,6 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
 	rdp->cpu = cpu;
 	rdp->rsp = rsp;
 	rcu_boot_init_nocb_percpu_data(rdp);
-	raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 }
 
 /*
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 6488a3b0e729..478b79e91b28 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -146,12 +146,6 @@ struct rcu_node {
 				/*  boosting for this rcu_node structure. */
 	unsigned int boost_kthread_status;
 				/* State of boost_kthread_task for tracing. */
-	unsigned long n_tasks_boosted;
-				/* Total number of tasks boosted. */
-	unsigned long n_exp_boosts;
-				/* Number of tasks boosted for expedited GP. */
-	unsigned long n_normal_boosts;
-				/* Number of tasks boosted for normal GP. */
 #ifdef CONFIG_RCU_NOCB_CPU
 	struct swait_queue_head nocb_gp_wq[2];
 				/* Place for rcu_nocb_kthread() to wait GP. */
@@ -184,13 +178,6 @@ union rcu_noqs {
 	u16 s; /* Set of bits, aggregate OR here. */
 };
 
-/* Index values for nxttail array in struct rcu_data. */
-#define RCU_DONE_TAIL		0	/* Also RCU_WAIT head. */
-#define RCU_WAIT_TAIL		1	/* Also RCU_NEXT_READY head. */
-#define RCU_NEXT_READY_TAIL	2	/* Also RCU_NEXT head. */
-#define RCU_NEXT_TAIL		3
-#define RCU_NEXT_SIZE		4
-
 /* Per-CPU data for read-copy update. */
 struct rcu_data {
 	/* 1) quiescent-state and grace-period handling : */
@@ -217,8 +204,6 @@ struct rcu_data {
 					/* different grace periods. */
 	long		qlen_last_fqs_check;
 					/* qlen at last check for QS forcing */
-	unsigned long	n_cbs_invoked;	/* count of RCU cbs invoked. */
-	unsigned long	n_nocbs_invoked; /* count of no-CBs RCU cbs invoked. */
 	unsigned long	n_force_qs_snap;
 					/* did other CPU force QS recently? */
 	long		blimit;		/* Upper limit on a processed batch */
@@ -234,18 +219,7 @@ struct rcu_data {
 					/* Grace period that needs help */
 					/*  from cond_resched(). */
 
-	/* 5) __rcu_pending() statistics. */
-	unsigned long n_rcu_pending;	/* rcu_pending() calls since boot. */
-	unsigned long n_rp_core_needs_qs;
-	unsigned long n_rp_report_qs;
-	unsigned long n_rp_cb_ready;
-	unsigned long n_rp_cpu_needs_gp;
-	unsigned long n_rp_gp_completed;
-	unsigned long n_rp_gp_started;
-	unsigned long n_rp_nocb_defer_wakeup;
-	unsigned long n_rp_need_nothing;
-
-	/* 6) _rcu_barrier(), OOM callbacks, and expediting. */
+	/* 5) _rcu_barrier(), OOM callbacks, and expediting. */
 	struct rcu_head barrier_head;
 #ifdef CONFIG_RCU_FAST_NO_HZ
 	struct rcu_head oom_head;
@@ -256,7 +230,7 @@ struct rcu_data {
 	atomic_long_t exp_workdone3;	/* # done by others #3. */
 	int exp_dynticks_snap;		/* Double-check need for IPI. */
 
-	/* 7) Callback offloading. */
+	/* 6) Callback offloading. */
 #ifdef CONFIG_RCU_NOCB_CPU
 	struct rcu_head *nocb_head;	/* CBs waiting for kthread. */
 	struct rcu_head **nocb_tail;
@@ -283,7 +257,7 @@ struct rcu_data {
 					/* Leader CPU takes GP-end wakeups. */
 #endif /* #ifdef CONFIG_RCU_NOCB_CPU */
 
-	/* 8) RCU CPU stall data. */
+	/* 7) RCU CPU stall data. */
 	unsigned int softirq_snap;	/* Snapshot of softirq activity. */
 	/* ->rcu_iw* fields protected by leaf rcu_node ->lock. */
 	struct irq_work rcu_iw;		/* Check for non-irq activity. */
@@ -374,10 +348,6 @@ struct rcu_state {
 						/*  kthreads, if configured. */
 	unsigned long n_force_qs;		/* Number of calls to */
 						/*  force_quiescent_state(). */
-	unsigned long n_force_qs_lh;		/* ~Number of calls leaving */
-						/*  due to lock unavailable. */
-	unsigned long n_force_qs_ngp;		/* Number of calls leaving */
-						/*  due to no GP active. */
 	unsigned long gp_start;			/* Time at which GP started, */
 						/*  but in jiffies. */
 	unsigned long gp_activity;		/* Time of last GP kthread */
@@ -463,6 +433,7 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
 static void rcu_preempt_check_callbacks(void);
 void call_rcu(struct rcu_head *head, rcu_callback_t func);
 static void __init __rcu_init_preempt(void);
+static void dump_blkd_tasks(struct rcu_node *rnp, int ncheck);
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
 static void invoke_rcu_callbacks_kthread(void);
diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
index 46d61b597731..6ad87642f44a 100644
--- a/kernel/rcu/tree_exp.h
+++ b/kernel/rcu/tree_exp.h
@@ -28,6 +28,15 @@ static void rcu_exp_gp_seq_start(struct rcu_state *rsp)
 	rcu_seq_start(&rsp->expedited_sequence);
 }
 
+/*
+ * Return then value that expedited-grace-period counter will have
+ * at the end of the current grace period.
+ */
+static __maybe_unused unsigned long rcu_exp_gp_seq_endval(struct rcu_state *rsp)
+{
+	return rcu_seq_endval(&rsp->expedited_sequence);
+}
+
 /*
  * Record the end of an expedited grace period.
  */
@@ -366,21 +375,30 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,
 	int ret;
 	struct rcu_node *rnp;
 
+	trace_rcu_exp_grace_period(rsp->name, rcu_exp_gp_seq_endval(rsp), TPS("reset"));
 	sync_exp_reset_tree(rsp);
+	trace_rcu_exp_grace_period(rsp->name, rcu_exp_gp_seq_endval(rsp), TPS("select"));
 	rcu_for_each_leaf_node(rsp, rnp) {
 		raw_spin_lock_irqsave_rcu_node(rnp, flags);
 
 		/* Each pass checks a CPU for identity, offline, and idle. */
 		mask_ofl_test = 0;
-		for_each_leaf_node_possible_cpu(rnp, cpu) {
+		for_each_leaf_node_cpu_mask(rnp, cpu, rnp->expmask) {
+			unsigned long mask = leaf_node_cpu_bit(rnp, cpu);
 			struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
+			struct rcu_dynticks *rdtp = per_cpu_ptr(&rcu_dynticks, cpu);
+			int snap;
 
-			rdp->exp_dynticks_snap =
-				rcu_dynticks_snap(rdp->dynticks);
 			if (raw_smp_processor_id() == cpu ||
-			    rcu_dynticks_in_eqs(rdp->exp_dynticks_snap) ||
-			    !(rnp->qsmaskinitnext & rdp->grpmask))
-				mask_ofl_test |= rdp->grpmask;
+			    !(rnp->qsmaskinitnext & mask)) {
+				mask_ofl_test |= mask;
+			} else {
+				snap = rcu_dynticks_snap(rdtp);
+				if (rcu_dynticks_in_eqs(snap))
+					mask_ofl_test |= mask;
+				else
+					rdp->exp_dynticks_snap = snap;
+			}
 		}
 		mask_ofl_ipi = rnp->expmask & ~mask_ofl_test;
 
@@ -394,7 +412,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,
 		raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 
 		/* IPI the remaining CPUs for expedited quiescent state. */
-		for_each_leaf_node_possible_cpu(rnp, cpu) {
+		for_each_leaf_node_cpu_mask(rnp, cpu, rnp->expmask) {
 			unsigned long mask = leaf_node_cpu_bit(rnp, cpu);
 			struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
 
@@ -417,6 +435,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,
 			    (rnp->expmask & mask)) {
 				/* Online, so delay for a bit and try again. */
 				raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+				trace_rcu_exp_grace_period(rsp->name, rcu_exp_gp_seq_endval(rsp), TPS("selectofl"));
 				schedule_timeout_uninterruptible(1);
 				goto retry_ipi;
 			}
@@ -443,6 +462,7 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
 	struct rcu_node *rnp_root = rcu_get_root(rsp);
 	int ret;
 
+	trace_rcu_exp_grace_period(rsp->name, rcu_exp_gp_seq_endval(rsp), TPS("startwait"));
 	jiffies_stall = rcu_jiffies_till_stall_check();
 	jiffies_start = jiffies;
 
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index fb88a028deec..26d7a31e81cb 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -180,7 +180,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp)
 			 (rnp->expmask & rdp->grpmask ? RCU_EXP_BLKD : 0);
 	struct task_struct *t = current;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	WARN_ON_ONCE(rdp->mynode != rnp);
 	WARN_ON_ONCE(rnp->level != rcu_num_lvls - 1);
 
@@ -560,8 +560,14 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp)
 	}
 	t = list_entry(rnp->gp_tasks->prev,
 		       struct task_struct, rcu_node_entry);
-	list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry)
+	list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) {
+		/*
+		 * We could be printing a lot while holding a spinlock.
+		 * Avoid triggering hard lockup.
+		 */
+		touch_nmi_watchdog();
 		sched_show_task(t);
+	}
 	raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 }
 
@@ -647,7 +653,8 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
 	struct task_struct *t;
 
 	RCU_LOCKDEP_WARN(preemptible(), "rcu_preempt_check_blocked_tasks() invoked with preemption enabled!!!\n");
-	WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp));
+	if (WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp)))
+		dump_blkd_tasks(rnp, 10);
 	if (rcu_preempt_has_tasks(rnp)) {
 		rnp->gp_tasks = rnp->blkd_tasks.next;
 		t = container_of(rnp->gp_tasks, struct task_struct,
@@ -800,6 +807,27 @@ void exit_rcu(void)
 	__rcu_read_unlock();
 }
 
+/*
+ * Dump the blocked-tasks state, but limit the list dump to the
+ * specified number of elements.
+ */
+static void dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
+{
+	int i;
+	struct list_head *lhp;
+
+	lockdep_assert_held(&rnp->lock);
+	pr_info("%s: grp: %d-%d level: %d ->qamask %#lx ->gp_tasks %p ->boost_tasks %p ->exp_tasks %p &->blkd_tasks: %p offset: %u\n", __func__, rnp->grplo, rnp->grphi, rnp->level, rnp->qsmask, rnp->gp_tasks, rnp->boost_tasks, rnp->exp_tasks, &rnp->blkd_tasks, (unsigned int)offsetof(typeof(*rnp), blkd_tasks));
+	pr_cont("\t->blkd_tasks");
+	i = 0;
+	list_for_each(lhp, &rnp->blkd_tasks) {
+		pr_cont(" %p", lhp);
+		if (++i >= 10)
+			break;
+	}
+	pr_cont("\n");
+}
+
 #else /* #ifdef CONFIG_PREEMPT_RCU */
 
 static struct rcu_state *const rcu_state_p = &rcu_sched_state;
@@ -908,6 +936,14 @@ void exit_rcu(void)
 {
 }
 
+/*
+ * Dump the guaranteed-empty blocked-tasks state.  Trust but verify.
+ */
+static void dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
+{
+	WARN_ON_ONCE(!list_empty(&rnp->blkd_tasks));
+}
+
 #endif /* #else #ifdef CONFIG_PREEMPT_RCU */
 
 #ifdef CONFIG_RCU_BOOST
@@ -957,14 +993,10 @@ static int rcu_boost(struct rcu_node *rnp)
 	 * expedited grace period must boost all blocked tasks, including
 	 * those blocking the pre-existing normal grace period.
 	 */
-	if (rnp->exp_tasks != NULL) {
+	if (rnp->exp_tasks != NULL)
 		tb = rnp->exp_tasks;
-		rnp->n_exp_boosts++;
-	} else {
+	else
 		tb = rnp->boost_tasks;
-		rnp->n_normal_boosts++;
-	}
-	rnp->n_tasks_boosted++;
 
 	/*
 	 * We boost task t by manufacturing an rt_mutex that appears to
@@ -1042,7 +1074,7 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
 {
 	struct task_struct *t;
 
-	lockdep_assert_held(&rnp->lock);
+	raw_lockdep_assert_held_rcu_node(rnp);
 	if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) {
 		raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 		return;
@@ -1677,6 +1709,12 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
 	char *ticks_title;
 	unsigned long ticks_value;
 
+	/*
+	 * We could be printing a lot while holding a spinlock.  Avoid
+	 * triggering hard lockup.
+	 */
+	touch_nmi_watchdog();
+
 	if (rsp->gpnum == rdp->gpnum) {
 		ticks_title = "ticks this GP";
 		ticks_value = rdp->ticks_this_gp;
@@ -2235,7 +2273,6 @@ static int rcu_nocb_kthread(void *arg)
 		smp_mb__before_atomic();  /* _add after CB invocation. */
 		atomic_long_add(-c, &rdp->nocb_q_count);
 		atomic_long_add(-cl, &rdp->nocb_q_count_lazy);
-		rdp->n_nocbs_invoked += c;
 	}
 	return 0;
 }
@@ -2312,8 +2349,11 @@ void __init rcu_init_nohz(void)
 		cpumask_and(rcu_nocb_mask, cpu_possible_mask,
 			    rcu_nocb_mask);
 	}
-	pr_info("\tOffload RCU callbacks from CPUs: %*pbl.\n",
-		cpumask_pr_args(rcu_nocb_mask));
+	if (cpumask_empty(rcu_nocb_mask))
+		pr_info("\tOffload RCU callbacks from CPUs: (none).\n");
+	else
+		pr_info("\tOffload RCU callbacks from CPUs: %*pbl.\n",
+			cpumask_pr_args(rcu_nocb_mask));
 	if (rcu_nocb_poll)
 		pr_info("\tPoll for callbacks from no-CBs CPUs.\n");
 
diff --git a/kernel/relay.c b/kernel/relay.c
index c3029402f15c..c955b10c973c 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -163,7 +163,7 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan)
 {
 	struct rchan_buf *buf;
 
-	if (chan->n_subbufs > UINT_MAX / sizeof(size_t *))
+	if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *))
 		return NULL;
 
 	buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e7c535eee0a6..c94895bc5a2c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6683,13 +6683,18 @@ static int tg_cfs_schedulable_down(struct task_group *tg, void *data)
 		parent_quota = parent_b->hierarchical_quota;
 
 		/*
-		 * Ensure max(child_quota) <= parent_quota, inherit when no
+		 * Ensure max(child_quota) <= parent_quota.  On cgroup2,
+		 * always take the min.  On cgroup1, only inherit when no
 		 * limit is set:
 		 */
-		if (quota == RUNTIME_INF)
-			quota = parent_quota;
-		else if (parent_quota != RUNTIME_INF && quota > parent_quota)
-			return -EINVAL;
+		if (cgroup_subsys_on_dfl(cpu_cgrp_subsys)) {
+			quota = min(quota, parent_quota);
+		} else {
+			if (quota == RUNTIME_INF)
+				quota = parent_quota;
+			else if (parent_quota != RUNTIME_INF && quota > parent_quota)
+				return -EINVAL;
+		}
 	}
 	cfs_b->hierarchical_quota = quota;
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5eb3ffc9be84..820f94c9b200 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2823,7 +2823,7 @@ void reweight_task(struct task_struct *p, int prio)
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
-# ifdef CONFIG_SMP
+#ifdef CONFIG_SMP
 /*
  * All this does is approximate the hierarchical proportion which includes that
  * global sum we all love to hate.
@@ -2974,7 +2974,7 @@ static long calc_group_runnable(struct cfs_rq *cfs_rq, long shares)
 
 	return clamp_t(long, runnable, MIN_SHARES, shares);
 }
-# endif /* CONFIG_SMP */
+#endif /* CONFIG_SMP */
 
 static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
 
diff --git a/kernel/sys.c b/kernel/sys.c
index f2289de20e19..31a2866b7abd 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2213,6 +2213,17 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case PR_GET_PDEATHSIG:
 		error = put_user(me->pdeath_signal, (int __user *)arg2);
 		break;
+	case PR_SET_PDEATHSIG_PROC:
+		if (!valid_signal(arg2)) {
+			error = -EINVAL;
+			break;
+		}
+		me->signal->pdeath_signal_proc = arg2;
+		break;
+	case PR_GET_PDEATHSIG_PROC:
+		error = put_user(me->signal->pdeath_signal_proc,
+				 (int __user *)arg2);
+		break;
 	case PR_GET_DUMPABLE:
 		error = get_dumpable(me->mm);
 		break;
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index f6b5f19223d6..78eabc41eaa6 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -113,16 +113,6 @@ config NO_HZ_FULL
 
 endchoice
 
-config NO_HZ_FULL_ALL
-       bool "Full dynticks system on all CPUs by default (except CPU 0)"
-       depends on NO_HZ_FULL
-       help
-         If the user doesn't pass the nohz_full boot option to
-	 define the range of full dynticks CPUs, consider that all
-	 CPUs in the system are full dynticks by default.
-	 Note the boot CPU will still be kept outside the range to
-	 handle the timekeeping duty.
-
 config NO_HZ
 	bool "Old Idle dynticks config"
 	depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 29a5733eff83..ccd3782da0bf 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -405,30 +405,12 @@ static int tick_nohz_cpu_down(unsigned int cpu)
 	return 0;
 }
 
-static int tick_nohz_init_all(void)
-{
-	int err = -1;
-
-#ifdef CONFIG_NO_HZ_FULL_ALL
-	if (!alloc_cpumask_var(&tick_nohz_full_mask, GFP_KERNEL)) {
-		WARN(1, "NO_HZ: Can't allocate full dynticks cpumask\n");
-		return err;
-	}
-	err = 0;
-	cpumask_setall(tick_nohz_full_mask);
-	tick_nohz_full_running = true;
-#endif
-	return err;
-}
-
 void __init tick_nohz_init(void)
 {
 	int cpu, ret;
 
-	if (!tick_nohz_full_running) {
-		if (tick_nohz_init_all() < 0)
-			return;
-	}
+	if (!tick_nohz_full_running)
+		return;
 
 	/*
 	 * Full dynticks uses irq work to drive the tick rescheduling on safe
diff --git a/kernel/time/timekeeping_internal.h b/kernel/time/timekeeping_internal.h
index fdbeeb02dde9..cf5c0828ee31 100644
--- a/kernel/time/timekeeping_internal.h
+++ b/kernel/time/timekeeping_internal.h
@@ -31,6 +31,4 @@ static inline u64 clocksource_delta(u64 now, u64 last, u64 mask)
 }
 #endif
 
-extern time64_t __ktime_get_real_seconds(void);
-
 #endif /* _TIMEKEEPING_INTERNAL_H */
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index fc2838ac8b78..c0a9e310d715 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -872,6 +872,8 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
 		return -EINVAL;
 	if (copy_from_user(&query, uquery, sizeof(query)))
 		return -EFAULT;
+	if (query.ids_len > BPF_TRACE_MAX_PROGS)
+		return -E2BIG;
 
 	mutex_lock(&bpf_event_mutex);
 	ret = bpf_prog_array_copy_info(event->tp_event->prog_array,
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 55d6dff37daf..2c416509b834 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include "trace.h"
+#include "trace_probe.h"
 
 static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
 
@@ -237,6 +238,107 @@ void perf_trace_destroy(struct perf_event *p_event)
 	mutex_unlock(&event_mutex);
 }
 
+#ifdef CONFIG_KPROBE_EVENTS
+int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe)
+{
+	int ret;
+	char *func = NULL;
+	struct trace_event_call *tp_event;
+
+	if (p_event->attr.kprobe_func) {
+		func = kzalloc(KSYM_NAME_LEN, GFP_KERNEL);
+		if (!func)
+			return -ENOMEM;
+		ret = strncpy_from_user(
+			func, u64_to_user_ptr(p_event->attr.kprobe_func),
+			KSYM_NAME_LEN);
+		if (ret < 0)
+			goto out;
+
+		if (func[0] == '\0') {
+			kfree(func);
+			func = NULL;
+		}
+	}
+
+	tp_event = create_local_trace_kprobe(
+		func, (void *)(unsigned long)(p_event->attr.kprobe_addr),
+		p_event->attr.probe_offset, is_retprobe);
+	if (IS_ERR(tp_event)) {
+		ret = PTR_ERR(tp_event);
+		goto out;
+	}
+
+	ret = perf_trace_event_init(tp_event, p_event);
+	if (ret)
+		destroy_local_trace_kprobe(tp_event);
+out:
+	kfree(func);
+	return ret;
+}
+
+void perf_kprobe_destroy(struct perf_event *p_event)
+{
+	perf_trace_event_close(p_event);
+	perf_trace_event_unreg(p_event);
+
+	destroy_local_trace_kprobe(p_event->tp_event);
+}
+#endif /* CONFIG_KPROBE_EVENTS */
+
+#ifdef CONFIG_UPROBE_EVENTS
+int perf_uprobe_init(struct perf_event *p_event, bool is_retprobe)
+{
+	int ret;
+	char *path = NULL;
+	struct trace_event_call *tp_event;
+
+	if (!p_event->attr.uprobe_path)
+		return -EINVAL;
+	path = kzalloc(PATH_MAX, GFP_KERNEL);
+	if (!path)
+		return -ENOMEM;
+	ret = strncpy_from_user(
+		path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX);
+	if (ret < 0)
+		goto out;
+	if (path[0] == '\0') {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tp_event = create_local_trace_uprobe(
+		path, p_event->attr.probe_offset, is_retprobe);
+	if (IS_ERR(tp_event)) {
+		ret = PTR_ERR(tp_event);
+		goto out;
+	}
+
+	/*
+	 * local trace_uprobe need to hold event_mutex to call
+	 * uprobe_buffer_enable() and uprobe_buffer_disable().
+	 * event_mutex is not required for local trace_kprobes.
+	 */
+	mutex_lock(&event_mutex);
+	ret = perf_trace_event_init(tp_event, p_event);
+	if (ret)
+		destroy_local_trace_uprobe(tp_event);
+	mutex_unlock(&event_mutex);
+out:
+	kfree(path);
+	return ret;
+}
+
+void perf_uprobe_destroy(struct perf_event *p_event)
+{
+	mutex_lock(&event_mutex);
+	perf_trace_event_close(p_event);
+	perf_trace_event_unreg(p_event);
+	mutex_unlock(&event_mutex);
+	destroy_local_trace_uprobe(p_event->tp_event);
+}
+#endif /* CONFIG_UPROBE_EVENTS */
+
 int perf_trace_add(struct perf_event *p_event, int flags)
 {
 	struct trace_event_call *tp_event = p_event->tp_event;
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 1fad24acd444..5ce9b8cf7be3 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -462,6 +462,14 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 			disable_kprobe(&tk->rp.kp);
 		wait = 1;
 	}
+
+	/*
+	 * if tk is not added to any list, it must be a local trace_kprobe
+	 * created with perf_event_open. We don't need to wait for these
+	 * trace_kprobes
+	 */
+	if (list_empty(&tk->list))
+		wait = 0;
  out:
 	if (wait) {
 		/*
@@ -1358,12 +1366,9 @@ static struct trace_event_functions kprobe_funcs = {
 	.trace		= print_kprobe_event
 };
 
-static int register_kprobe_event(struct trace_kprobe *tk)
+static inline void init_trace_event_call(struct trace_kprobe *tk,
+					 struct trace_event_call *call)
 {
-	struct trace_event_call *call = &tk->tp.call;
-	int ret;
-
-	/* Initialize trace_event_call */
 	INIT_LIST_HEAD(&call->class->fields);
 	if (trace_kprobe_is_return(tk)) {
 		call->event.funcs = &kretprobe_funcs;
@@ -1372,6 +1377,19 @@ static int register_kprobe_event(struct trace_kprobe *tk)
 		call->event.funcs = &kprobe_funcs;
 		call->class->define_fields = kprobe_event_define_fields;
 	}
+
+	call->flags = TRACE_EVENT_FL_KPROBE;
+	call->class->reg = kprobe_register;
+	call->data = tk;
+}
+
+static int register_kprobe_event(struct trace_kprobe *tk)
+{
+	struct trace_event_call *call = &tk->tp.call;
+	int ret = 0;
+
+	init_trace_event_call(tk, call);
+
 	if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
 		return -ENOMEM;
 	ret = register_trace_event(&call->event);
@@ -1379,9 +1397,6 @@ static int register_kprobe_event(struct trace_kprobe *tk)
 		kfree(call->print_fmt);
 		return -ENODEV;
 	}
-	call->flags = TRACE_EVENT_FL_KPROBE;
-	call->class->reg = kprobe_register;
-	call->data = tk;
 	ret = trace_add_event_call(call);
 	if (ret) {
 		pr_info("Failed to register kprobe event: %s\n",
@@ -1403,6 +1418,66 @@ static int unregister_kprobe_event(struct trace_kprobe *tk)
 	return ret;
 }
 
+#ifdef CONFIG_PERF_EVENTS
+/* create a trace_kprobe, but don't add it to global lists */
+struct trace_event_call *
+create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
+			  bool is_return)
+{
+	struct trace_kprobe *tk;
+	int ret;
+	char *event;
+
+	/*
+	 * local trace_kprobes are not added to probe_list, so they are never
+	 * searched in find_trace_kprobe(). Therefore, there is no concern of
+	 * duplicated name here.
+	 */
+	event = func ? func : "DUMMY_EVENT";
+
+	tk = alloc_trace_kprobe(KPROBE_EVENT_SYSTEM, event, (void *)addr, func,
+				offs, 0 /* maxactive */, 0 /* nargs */,
+				is_return);
+
+	if (IS_ERR(tk)) {
+		pr_info("Failed to allocate trace_probe.(%d)\n",
+			(int)PTR_ERR(tk));
+		return ERR_CAST(tk);
+	}
+
+	init_trace_event_call(tk, &tk->tp.call);
+
+	if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	ret = __register_trace_kprobe(tk);
+	if (ret < 0)
+		goto error;
+
+	return &tk->tp.call;
+error:
+	free_trace_kprobe(tk);
+	return ERR_PTR(ret);
+}
+
+void destroy_local_trace_kprobe(struct trace_event_call *event_call)
+{
+	struct trace_kprobe *tk;
+
+	tk = container_of(event_call, struct trace_kprobe, tp.call);
+
+	if (trace_probe_is_enabled(&tk->tp)) {
+		WARN_ON(1);
+		return;
+	}
+
+	__unregister_trace_kprobe(tk);
+	free_trace_kprobe(tk);
+}
+#endif /* CONFIG_PERF_EVENTS */
+
 /* Make a tracefs interface for controlling probe points */
 static __init int init_kprobe_trace(void)
 {
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index e101c5bb9eda..0745f895f780 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -416,3 +416,14 @@ store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
 }
 
 extern int set_print_fmt(struct trace_probe *tp, bool is_return);
+
+#ifdef CONFIG_PERF_EVENTS
+extern struct trace_event_call *
+create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
+			  bool is_return);
+extern void destroy_local_trace_kprobe(struct trace_event_call *event_call);
+
+extern struct trace_event_call *
+create_local_trace_uprobe(char *name, unsigned long offs, bool is_return);
+extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
+#endif
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 268029ae1be6..2014f4351ae0 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -1292,16 +1292,25 @@ static struct trace_event_functions uprobe_funcs = {
 	.trace		= print_uprobe_event
 };
 
-static int register_uprobe_event(struct trace_uprobe *tu)
+static inline void init_trace_event_call(struct trace_uprobe *tu,
+					 struct trace_event_call *call)
 {
-	struct trace_event_call *call = &tu->tp.call;
-	int ret;
-
-	/* Initialize trace_event_call */
 	INIT_LIST_HEAD(&call->class->fields);
 	call->event.funcs = &uprobe_funcs;
 	call->class->define_fields = uprobe_event_define_fields;
 
+	call->flags = TRACE_EVENT_FL_UPROBE;
+	call->class->reg = trace_uprobe_register;
+	call->data = tu;
+}
+
+static int register_uprobe_event(struct trace_uprobe *tu)
+{
+	struct trace_event_call *call = &tu->tp.call;
+	int ret = 0;
+
+	init_trace_event_call(tu, call);
+
 	if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
 		return -ENOMEM;
 
@@ -1311,9 +1320,6 @@ static int register_uprobe_event(struct trace_uprobe *tu)
 		return -ENODEV;
 	}
 
-	call->flags = TRACE_EVENT_FL_UPROBE;
-	call->class->reg = trace_uprobe_register;
-	call->data = tu;
 	ret = trace_add_event_call(call);
 
 	if (ret) {
@@ -1339,6 +1345,70 @@ static int unregister_uprobe_event(struct trace_uprobe *tu)
 	return 0;
 }
 
+#ifdef CONFIG_PERF_EVENTS
+struct trace_event_call *
+create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
+{
+	struct trace_uprobe *tu;
+	struct inode *inode;
+	struct path path;
+	int ret;
+
+	ret = kern_path(name, LOOKUP_FOLLOW, &path);
+	if (ret)
+		return ERR_PTR(ret);
+
+	inode = igrab(d_inode(path.dentry));
+	path_put(&path);
+
+	if (!inode || !S_ISREG(inode->i_mode)) {
+		iput(inode);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/*
+	 * local trace_kprobes are not added to probe_list, so they are never
+	 * searched in find_trace_kprobe(). Therefore, there is no concern of
+	 * duplicated name "DUMMY_EVENT" here.
+	 */
+	tu = alloc_trace_uprobe(UPROBE_EVENT_SYSTEM, "DUMMY_EVENT", 0,
+				is_return);
+
+	if (IS_ERR(tu)) {
+		pr_info("Failed to allocate trace_uprobe.(%d)\n",
+			(int)PTR_ERR(tu));
+		return ERR_CAST(tu);
+	}
+
+	tu->offset = offs;
+	tu->inode = inode;
+	tu->filename = kstrdup(name, GFP_KERNEL);
+	init_trace_event_call(tu, &tu->tp.call);
+
+	if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	return &tu->tp.call;
+error:
+	free_trace_uprobe(tu);
+	return ERR_PTR(ret);
+}
+
+void destroy_local_trace_uprobe(struct trace_event_call *event_call)
+{
+	struct trace_uprobe *tu;
+
+	tu = container_of(event_call, struct trace_uprobe, tp.call);
+
+	kfree(tu->tp.call.print_fmt);
+	tu->tp.call.print_fmt = NULL;
+
+	free_trace_uprobe(tu);
+}
+#endif /* CONFIG_PERF_EVENTS */
+
 /* Make a trace interface for controling probe points */
 static __init int init_uprobe_trace(void)
 {
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 017044c26233..bb9a519cbf50 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -4179,6 +4179,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
 }
 EXPORT_SYMBOL_GPL(workqueue_set_max_active);
 
+/**
+ * current_work - retrieve %current task's work struct
+ *
+ * Determine if %current task is a workqueue worker and what it's working on.
+ * Useful to find out the context that the %current task is running in.
+ *
+ * Return: work struct if %current task is a workqueue worker, %NULL otherwise.
+ */
+struct work_struct *current_work(void)
+{
+	struct worker *worker = current_wq_worker();
+
+	return worker ? worker->current_work : NULL;
+}
+EXPORT_SYMBOL(current_work);
+
 /**
  * current_is_workqueue_rescuer - is %current workqueue rescuer?
  *
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6088408ef26c..7c66b7152578 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -324,11 +324,11 @@ config DEBUG_SECTION_MISMATCH
 	    the analysis would not catch the illegal reference.
 	    This option tells gcc to inline less (but it does result in
 	    a larger kernel).
-	  - Run the section mismatch analysis for each module/built-in.o file.
+	  - Run the section mismatch analysis for each module/built-in.a file.
 	    When we run the section mismatch analysis on vmlinux.o, we
 	    lose valuable information about where the mismatch was
 	    introduced.
-	    Running the analysis for each module/built-in.o file
+	    Running the analysis for each module/built-in.a file
 	    tells where the mismatch happens much closer to the
 	    source. The drawback is that the same mismatch is
 	    reported at least twice.
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index 2f5349c6e81a..faab2c4ea024 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -42,14 +42,18 @@ static struct debug_obj		obj_static_pool[ODEBUG_POOL_SIZE] __initdata;
 static DEFINE_RAW_SPINLOCK(pool_lock);
 
 static HLIST_HEAD(obj_pool);
+static HLIST_HEAD(obj_to_free);
 
 static int			obj_pool_min_free = ODEBUG_POOL_SIZE;
 static int			obj_pool_free = ODEBUG_POOL_SIZE;
 static int			obj_pool_used;
 static int			obj_pool_max_used;
+/* The number of objs on the global free list */
+static int			obj_nr_tofree;
 static struct kmem_cache	*obj_cache;
 
 static int			debug_objects_maxchain __read_mostly;
+static int			debug_objects_maxchecked __read_mostly;
 static int			debug_objects_fixups __read_mostly;
 static int			debug_objects_warnings __read_mostly;
 static int			debug_objects_enabled __read_mostly
@@ -96,12 +100,32 @@ static const char *obj_states[ODEBUG_STATE_MAX] = {
 static void fill_pool(void)
 {
 	gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
-	struct debug_obj *new;
+	struct debug_obj *new, *obj;
 	unsigned long flags;
 
 	if (likely(obj_pool_free >= debug_objects_pool_min_level))
 		return;
 
+	/*
+	 * Reuse objs from the global free list; they will be reinitialized
+	 * when allocating.
+	 */
+	while (obj_nr_tofree && (obj_pool_free < obj_pool_min_free)) {
+		raw_spin_lock_irqsave(&pool_lock, flags);
+		/*
+		 * Recheck with the lock held as the worker thread might have
+		 * won the race and freed the global free list already.
+		 */
+		if (obj_nr_tofree) {
+			obj = hlist_entry(obj_to_free.first, typeof(*obj), node);
+			hlist_del(&obj->node);
+			obj_nr_tofree--;
+			hlist_add_head(&obj->node, &obj_pool);
+			obj_pool_free++;
+		}
+		raw_spin_unlock_irqrestore(&pool_lock, flags);
+	}
+
 	if (unlikely(!obj_cache))
 		return;
 
@@ -177,62 +201,75 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
  * workqueue function to free objects.
  *
  * To reduce contention on the global pool_lock, the actual freeing of
- * debug objects will be delayed if the pool_lock is busy. We also free
- * the objects in a batch of 4 for each lock/unlock cycle.
+ * debug objects will be delayed if the pool_lock is busy.
  */
-#define ODEBUG_FREE_BATCH	4
-
 static void free_obj_work(struct work_struct *work)
 {
-	struct debug_obj *objs[ODEBUG_FREE_BATCH];
+	struct hlist_node *tmp;
+	struct debug_obj *obj;
 	unsigned long flags;
-	int i;
+	HLIST_HEAD(tofree);
 
 	if (!raw_spin_trylock_irqsave(&pool_lock, flags))
 		return;
-	while (obj_pool_free >= debug_objects_pool_size + ODEBUG_FREE_BATCH) {
-		for (i = 0; i < ODEBUG_FREE_BATCH; i++) {
-			objs[i] = hlist_entry(obj_pool.first,
-					      typeof(*objs[0]), node);
-			hlist_del(&objs[i]->node);
-		}
 
-		obj_pool_free -= ODEBUG_FREE_BATCH;
-		debug_objects_freed += ODEBUG_FREE_BATCH;
-		/*
-		 * We release pool_lock across kmem_cache_free() to
-		 * avoid contention on pool_lock.
-		 */
-		raw_spin_unlock_irqrestore(&pool_lock, flags);
-		for (i = 0; i < ODEBUG_FREE_BATCH; i++)
-			kmem_cache_free(obj_cache, objs[i]);
-		if (!raw_spin_trylock_irqsave(&pool_lock, flags))
-			return;
+	/*
+	 * The objs on the pool list might be allocated before the work is
+	 * run, so recheck if pool list it full or not, if not fill pool
+	 * list from the global free list
+	 */
+	while (obj_nr_tofree && obj_pool_free < debug_objects_pool_size) {
+		obj = hlist_entry(obj_to_free.first, typeof(*obj), node);
+		hlist_del(&obj->node);
+		hlist_add_head(&obj->node, &obj_pool);
+		obj_pool_free++;
+		obj_nr_tofree--;
+	}
+
+	/*
+	 * Pool list is already full and there are still objs on the free
+	 * list. Move remaining free objs to a temporary list to free the
+	 * memory outside the pool_lock held region.
+	 */
+	if (obj_nr_tofree) {
+		hlist_move_list(&obj_to_free, &tofree);
+		obj_nr_tofree = 0;
 	}
 	raw_spin_unlock_irqrestore(&pool_lock, flags);
+
+	hlist_for_each_entry_safe(obj, tmp, &tofree, node) {
+		hlist_del(&obj->node);
+		kmem_cache_free(obj_cache, obj);
+	}
 }
 
-/*
- * Put the object back into the pool and schedule work to free objects
- * if necessary.
- */
-static void free_object(struct debug_obj *obj)
+static bool __free_object(struct debug_obj *obj)
 {
 	unsigned long flags;
-	int sched = 0;
+	bool work;
 
 	raw_spin_lock_irqsave(&pool_lock, flags);
-	/*
-	 * schedule work when the pool is filled and the cache is
-	 * initialized:
-	 */
-	if (obj_pool_free > debug_objects_pool_size && obj_cache)
-		sched = 1;
-	hlist_add_head(&obj->node, &obj_pool);
-	obj_pool_free++;
+	work = (obj_pool_free > debug_objects_pool_size) && obj_cache;
 	obj_pool_used--;
+
+	if (work) {
+		obj_nr_tofree++;
+		hlist_add_head(&obj->node, &obj_to_free);
+	} else {
+		obj_pool_free++;
+		hlist_add_head(&obj->node, &obj_pool);
+	}
 	raw_spin_unlock_irqrestore(&pool_lock, flags);
-	if (sched)
+	return work;
+}
+
+/*
+ * Put the object back into the pool and schedule work to free objects
+ * if necessary.
+ */
+static void free_object(struct debug_obj *obj)
+{
+	if (__free_object(obj))
 		schedule_work(&debug_obj_work);
 }
 
@@ -714,13 +751,13 @@ EXPORT_SYMBOL_GPL(debug_object_active_state);
 static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 {
 	unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
-	struct hlist_node *tmp;
-	HLIST_HEAD(freelist);
 	struct debug_obj_descr *descr;
 	enum debug_obj_state state;
 	struct debug_bucket *db;
+	struct hlist_node *tmp;
 	struct debug_obj *obj;
-	int cnt;
+	int cnt, objs_checked = 0;
+	bool work = false;
 
 	saddr = (unsigned long) address;
 	eaddr = saddr + size;
@@ -751,21 +788,24 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 				goto repeat;
 			default:
 				hlist_del(&obj->node);
-				hlist_add_head(&obj->node, &freelist);
+				work |= __free_object(obj);
 				break;
 			}
 		}
 		raw_spin_unlock_irqrestore(&db->lock, flags);
 
-		/* Now free them */
-		hlist_for_each_entry_safe(obj, tmp, &freelist, node) {
-			hlist_del(&obj->node);
-			free_object(obj);
-		}
-
 		if (cnt > debug_objects_maxchain)
 			debug_objects_maxchain = cnt;
+
+		objs_checked += cnt;
 	}
+
+	if (objs_checked > debug_objects_maxchecked)
+		debug_objects_maxchecked = objs_checked;
+
+	/* Schedule work to actually kmem_cache_free() objects */
+	if (work)
+		schedule_work(&debug_obj_work);
 }
 
 void debug_check_no_obj_freed(const void *address, unsigned long size)
@@ -780,12 +820,14 @@ void debug_check_no_obj_freed(const void *address, unsigned long size)
 static int debug_stats_show(struct seq_file *m, void *v)
 {
 	seq_printf(m, "max_chain     :%d\n", debug_objects_maxchain);
+	seq_printf(m, "max_checked   :%d\n", debug_objects_maxchecked);
 	seq_printf(m, "warnings      :%d\n", debug_objects_warnings);
 	seq_printf(m, "fixups        :%d\n", debug_objects_fixups);
 	seq_printf(m, "pool_free     :%d\n", obj_pool_free);
 	seq_printf(m, "pool_min_free :%d\n", obj_pool_min_free);
 	seq_printf(m, "pool_used     :%d\n", obj_pool_used);
 	seq_printf(m, "pool_max_used :%d\n", obj_pool_max_used);
+	seq_printf(m, "on_free_list  :%d\n", obj_nr_tofree);
 	seq_printf(m, "objs_allocated:%d\n", debug_objects_allocated);
 	seq_printf(m, "objs_freed    :%d\n", debug_objects_freed);
 	return 0;
diff --git a/lib/idr.c b/lib/idr.c
index c98d77fcf393..99ec5bc89d25 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -431,7 +431,6 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
 			bitmap = this_cpu_xchg(ida_bitmap, NULL);
 			if (!bitmap)
 				return -EAGAIN;
-			memset(bitmap, 0, sizeof(*bitmap));
 			bitmap->bitmap[0] = tmp >> RADIX_TREE_EXCEPTIONAL_SHIFT;
 			rcu_assign_pointer(*slot, bitmap);
 		}
@@ -464,7 +463,6 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
 			bitmap = this_cpu_xchg(ida_bitmap, NULL);
 			if (!bitmap)
 				return -EAGAIN;
-			memset(bitmap, 0, sizeof(*bitmap));
 			__set_bit(bit, bitmap->bitmap);
 			radix_tree_iter_replace(root, &iter, slot, bitmap);
 		}
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 9fe6ec8fda28..9539d7ab3ea8 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -650,6 +650,7 @@ static void uevent_net_exit(struct net *net)
 static struct pernet_operations uevent_net_ops = {
 	.init	= uevent_net_init,
 	.exit	= uevent_net_exit,
+	.async  = true,
 };
 
 static int __init kobject_uevent_init(void)
diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c
index 9f79547d1b97..f0a2934605bf 100644
--- a/lib/libcrc32c.c
+++ b/lib/libcrc32c.c
@@ -71,6 +71,12 @@ static void __exit libcrc32c_mod_fini(void)
 	crypto_free_shash(tfm);
 }
 
+const char *crc32c_impl(void)
+{
+	return crypto_shash_driver_name(tfm);
+}
+EXPORT_SYMBOL(crc32c_impl);
+
 module_init(libcrc32c_mod_init);
 module_exit(libcrc32c_mod_fini);
 
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 0a7ae3288a24..8e00138d593f 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -2125,7 +2125,7 @@ int ida_pre_get(struct ida *ida, gfp_t gfp)
 		preempt_enable();
 
 	if (!this_cpu_read(ida_bitmap)) {
-		struct ida_bitmap *bitmap = kmalloc(sizeof(*bitmap), gfp);
+		struct ida_bitmap *bitmap = kzalloc(sizeof(*bitmap), gfp);
 		if (!bitmap)
 			return 0;
 		if (this_cpu_cmpxchg(ida_bitmap, NULL, bitmap))
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 77ee6ced11b1..d7a708f82559 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1849,7 +1849,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 {
 	const int default_width = 2 * sizeof(void *);
 
-	if (!ptr && *fmt != 'K') {
+	if (!ptr && *fmt != 'K' && *fmt != 'x') {
 		/*
 		 * Print (null) with the same width as a pointer so it makes
 		 * tabular output look nice.
diff --git a/localversion-next b/localversion-next
new file mode 100644
index 000000000000..477f12143475
--- /dev/null
+++ b/localversion-next
@@ -0,0 +1 @@
+-next-20180220
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index b5f940ce0143..ffa0c6b9e78a 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -231,11 +231,46 @@ static ssize_t stable_pages_required_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(stable_pages_required);
 
+static ssize_t strictlimit_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct backing_dev_info *bdi = dev_get_drvdata(dev);
+	unsigned int val;
+	ssize_t ret;
+
+	ret = kstrtouint(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	switch (val) {
+	case 0:
+		bdi->capabilities &= ~BDI_CAP_STRICTLIMIT;
+		break;
+	case 1:
+		bdi->capabilities |= BDI_CAP_STRICTLIMIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+static ssize_t strictlimit_show(struct device *dev,
+		struct device_attribute *attr, char *page)
+{
+	struct backing_dev_info *bdi = dev_get_drvdata(dev);
+
+	return snprintf(page, PAGE_SIZE-1, "%d\n",
+			!!(bdi->capabilities & BDI_CAP_STRICTLIMIT));
+}
+static DEVICE_ATTR_RW(strictlimit);
+
 static struct attribute *bdi_dev_attrs[] = {
 	&dev_attr_read_ahead_kb.attr,
 	&dev_attr_min_ratio.attr,
 	&dev_attr_max_ratio.attr,
 	&dev_attr_stable_pages_required.attr,
+	&dev_attr_strictlimit.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(bdi_dev);
diff --git a/mm/cma.c b/mm/cma.c
index 0607729abf3b..a8062af9ba9c 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -38,6 +38,7 @@
 #include <trace/events/cma.h>
 
 #include "cma.h"
+#include "internal.h"
 
 struct cma cma_areas[MAX_CMA_AREAS];
 unsigned cma_area_count;
@@ -108,23 +109,25 @@ static int __init cma_activate_area(struct cma *cma)
 	if (!cma->bitmap)
 		return -ENOMEM;
 
-	WARN_ON_ONCE(!pfn_valid(pfn));
-	zone = page_zone(pfn_to_page(pfn));
-
 	do {
 		unsigned j;
 
 		base_pfn = pfn;
+		if (!pfn_valid(base_pfn))
+			goto err;
+
+		zone = page_zone(pfn_to_page(base_pfn));
 		for (j = pageblock_nr_pages; j; --j, pfn++) {
-			WARN_ON_ONCE(!pfn_valid(pfn));
+			if (!pfn_valid(pfn))
+				goto err;
+
 			/*
-			 * alloc_contig_range requires the pfn range
-			 * specified to be in the same zone. Make this
-			 * simple by forcing the entire CMA resv range
-			 * to be in the same zone.
+			 * In init_cma_reserved_pageblock(), present_pages
+			 * is adjusted with assumption that all pages in
+			 * the pageblock come from a single zone.
 			 */
 			if (page_zone(pfn_to_page(pfn)) != zone)
-				goto not_in_zone;
+				goto err;
 		}
 		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
 	} while (--i);
@@ -138,7 +141,7 @@ static int __init cma_activate_area(struct cma *cma)
 
 	return 0;
 
-not_in_zone:
+err:
 	pr_err("CMA area %s could not be activated\n", cma->name);
 	kfree(cma->bitmap);
 	cma->count = 0;
@@ -148,6 +151,41 @@ static int __init cma_activate_area(struct cma *cma)
 static int __init cma_init_reserved_areas(void)
 {
 	int i;
+	struct zone *zone;
+	pg_data_t *pgdat;
+
+	if (!cma_area_count)
+		return 0;
+
+	for_each_online_pgdat(pgdat) {
+		unsigned long start_pfn = UINT_MAX, end_pfn = 0;
+
+		zone = &pgdat->node_zones[ZONE_MOVABLE];
+
+		/*
+		 * In this case, we cannot adjust the zone range
+		 * since it is now maximum node span and we don't
+		 * know original zone range.
+		 */
+		if (populated_zone(zone))
+			continue;
+
+		for (i = 0; i < cma_area_count; i++) {
+			if (pfn_to_nid(cma_areas[i].base_pfn) !=
+				pgdat->node_id)
+				continue;
+
+			start_pfn = min(start_pfn, cma_areas[i].base_pfn);
+			end_pfn = max(end_pfn, cma_areas[i].base_pfn +
+						cma_areas[i].count);
+		}
+
+		if (!end_pfn)
+			continue;
+
+		zone->zone_start_pfn = start_pfn;
+		zone->spanned_pages = end_pfn - start_pfn;
+	}
 
 	for (i = 0; i < cma_area_count; i++) {
 		int ret = cma_activate_area(&cma_areas[i]);
@@ -156,9 +194,32 @@ static int __init cma_init_reserved_areas(void)
 			return ret;
 	}
 
+	/*
+	 * Reserved pages for ZONE_MOVABLE are now activated and
+	 * this would change ZONE_MOVABLE's managed page counter and
+	 * the other zones' present counter. We need to re-calculate
+	 * various zone information that depends on this initialization.
+	 */
+	build_all_zonelists(NULL);
+	for_each_populated_zone(zone) {
+		if (zone_idx(zone) == ZONE_MOVABLE) {
+			zone_pcp_reset(zone);
+			setup_zone_pageset(zone);
+		} else
+			zone_pcp_update(zone);
+
+		set_zone_contiguous(zone);
+	}
+
+	/*
+	 * We need to re-init per zone wmark by calling
+	 * init_per_zone_wmark_min() but doesn't call here because it is
+	 * registered on core_initcall and it will be called later than us.
+	 */
+
 	return 0;
 }
-core_initcall(cma_init_reserved_areas);
+pure_initcall(cma_init_reserved_areas);
 
 /**
  * cma_init_reserved_mem() - create custom contiguous area from reserved memory
diff --git a/mm/compaction.c b/mm/compaction.c
index 2c8999d027ab..0e569e68b022 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1165,8 +1165,7 @@ static void isolate_freepages(struct compact_control *cc)
  * from the isolated freelists in the block we are migrating to.
  */
 static struct page *compaction_alloc(struct page *migratepage,
-					unsigned long data,
-					int **result)
+					unsigned long data)
 {
 	struct compact_control *cc = (struct compact_control *)data;
 	struct page *freepage;
@@ -1450,14 +1449,12 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
 	 * if compaction succeeds.
 	 * For costly orders, we require low watermark instead of min for
 	 * compaction to proceed to increase its chances.
-	 * ALLOC_CMA is used, as pages in CMA pageblocks are considered
-	 * suitable migration targets
 	 */
 	watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?
 				low_wmark_pages(zone) : min_wmark_pages(zone);
 	watermark += compact_gap(order);
 	if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,
-						ALLOC_CMA, wmark_target))
+						0, wmark_target))
 		return COMPACT_SKIPPED;
 
 	return COMPACT_CONTINUE;
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 87ab9b8f56b5..13441808eb66 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2407,6 +2407,12 @@ static void __split_huge_page_tail(struct page *head, int tail,
 
 	page_tail->index = head->index + tail;
 	page_cpupid_xchg_last(page_tail, page_cpupid_last(head));
+
+	/*
+	 * always add to the tail because some iterators expect new
+	 * pages to show after the currently processed elements - e.g.
+	 * migrate_pages
+	 */
 	lru_add_page_tail(head, page_tail, lruvec, list);
 }
 
diff --git a/mm/internal.h b/mm/internal.h
index e6bd35182dae..62d8c34e63d5 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -168,6 +168,9 @@ extern void post_alloc_hook(struct page *page, unsigned int order,
 					gfp_t gfp_flags);
 extern int user_min_free_kbytes;
 
+extern void set_zone_contiguous(struct zone *zone);
+extern void clear_zone_contiguous(struct zone *zone);
+
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
 
 /*
@@ -495,7 +498,6 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
 #define ALLOC_HARDER		0x10 /* try to alloc harder */
 #define ALLOC_HIGH		0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET		0x40 /* check for correct cpuset */
-#define ALLOC_CMA		0x80 /* allow allocations from CMA areas */
 
 enum ttu_flags;
 struct tlbflush_unmap_batch;
@@ -538,4 +540,5 @@ static inline bool is_migrate_highatomic_page(struct page *page)
 }
 
 void setup_zone_pageset(struct zone *zone);
+extern struct page *alloc_new_node_page(struct page *page, unsigned long node);
 #endif	/* __MM_INTERNAL_H */
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index e13d911251e7..0d9d9d268f32 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -791,6 +791,41 @@ DEFINE_ASAN_SET_SHADOW(f5);
 DEFINE_ASAN_SET_SHADOW(f8);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
+static bool shadow_mapped(unsigned long addr)
+{
+	pgd_t *pgd = pgd_offset_k(addr);
+	p4d_t *p4d;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	if (pgd_none(*pgd))
+		return false;
+	p4d = p4d_offset(pgd, addr);
+	if (p4d_none(*p4d))
+		return false;
+	pud = pud_offset(p4d, addr);
+	if (pud_none(*pud))
+		return false;
+
+	/*
+	 * We can't use pud_large() or pud_huge(), the first one
+	 * is arch-specific, the last one depend on HUGETLB_PAGE.
+	 * So let's abuse pud_bad(), if bud is bad it's has to
+	 * because it's huge.
+	 */
+	if (pud_bad(*pud))
+		return true;
+	pmd = pmd_offset(pud, addr);
+	if (pmd_none(*pmd))
+		return false;
+
+	if (pmd_bad(*pmd))
+		return true;
+	pte = pte_offset_kernel(pmd, addr);
+	return !pte_none(*pte);
+}
+
 static int __meminit kasan_mem_notifier(struct notifier_block *nb,
 			unsigned long action, void *data)
 {
@@ -812,6 +847,14 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb,
 	case MEM_GOING_ONLINE: {
 		void *ret;
 
+		/*
+		 * If shadow is mapped already than it must have been mapped
+		 * during the boot. This could happen if we onlining previously
+		 * offlined memory.
+		 */
+		if (shadow_mapped(shadow_start))
+			return NOTIFY_OK;
+
 		ret = __vmalloc_node_range(shadow_size, PAGE_SIZE, shadow_start,
 					shadow_end, GFP_KERNEL,
 					PAGE_KERNEL, VM_NO_GUARD,
@@ -823,8 +866,18 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb,
 		kmemleak_ignore(ret);
 		return NOTIFY_OK;
 	}
-	case MEM_OFFLINE:
-		vfree((void *)shadow_start);
+	case MEM_OFFLINE: {
+		struct vm_struct *vm;
+
+		/*
+		 * Only hot-added memory have vm_area. Freeing shadow
+		 * mapped during boot would be tricky, so we'll just
+		 * have to keep it.
+		 */
+		vm = find_vm_area((void *)shadow_start);
+		if (vm)
+			vfree((void *)shadow_start);
+	}
 	}
 
 	return NOTIFY_OK;
diff --git a/mm/kasan/kasan_init.c b/mm/kasan/kasan_init.c
index 554e4c0f23a2..f436246ccc79 100644
--- a/mm/kasan/kasan_init.c
+++ b/mm/kasan/kasan_init.c
@@ -31,7 +31,7 @@
 unsigned char kasan_zero_page[PAGE_SIZE] __page_aligned_bss;
 
 #if CONFIG_PGTABLE_LEVELS > 4
-p4d_t kasan_zero_p4d[PTRS_PER_P4D] __page_aligned_bss;
+p4d_t kasan_zero_p4d[MAX_PTRS_PER_P4D] __page_aligned_bss;
 #endif
 #if CONFIG_PGTABLE_LEVELS > 3
 pud_t kasan_zero_pud[PTRS_PER_PUD] __page_aligned_bss;
diff --git a/mm/ksm.c b/mm/ksm.c
index 293721f5da70..30ebdbfaf373 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1318,10 +1318,10 @@ bool is_page_sharing_candidate(struct stable_node *stable_node)
 	return __is_page_sharing_candidate(stable_node, 0);
 }
 
-struct page *stable_node_dup(struct stable_node **_stable_node_dup,
-			     struct stable_node **_stable_node,
-			     struct rb_root *root,
-			     bool prune_stale_stable_nodes)
+static struct page *stable_node_dup(struct stable_node **_stable_node_dup,
+				    struct stable_node **_stable_node,
+				    struct rb_root *root,
+				    bool prune_stale_stable_nodes)
 {
 	struct stable_node *dup, *found = NULL, *stable_node = *_stable_node;
 	struct hlist_node *hlist_safe;
diff --git a/mm/list_lru.c b/mm/list_lru.c
index fd41e969ede5..d9c84c5bda1d 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/list_lru.h>
+#include <linux/prefetch.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/memcontrol.h>
@@ -52,14 +53,15 @@ static inline bool list_lru_memcg_aware(struct list_lru *lru)
 static inline struct list_lru_one *
 list_lru_from_memcg_idx(struct list_lru_node *nlru, int idx)
 {
+	struct list_lru_memcg *memcg_lrus;
 	/*
-	 * The lock protects the array of per cgroup lists from relocation
-	 * (see memcg_update_list_lru_node).
+	 * Either lock or RCU protects the array of per cgroup lists
+	 * from relocation (see memcg_update_list_lru_node).
 	 */
-	lockdep_assert_held(&nlru->lock);
-	if (nlru->memcg_lrus && idx >= 0)
-		return nlru->memcg_lrus->lru[idx];
-
+	memcg_lrus = rcu_dereference_check(nlru->memcg_lrus,
+					   lockdep_is_held(&nlru->lock));
+	if (memcg_lrus && idx >= 0)
+		return memcg_lrus->lru[idx];
 	return &nlru->lru;
 }
 
@@ -132,6 +134,12 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item)
 	struct list_lru_node *nlru = &lru->node[nid];
 	struct list_lru_one *l;
 
+	/*
+	 * Prefetch the neighboring list entries to reduce lock hold time.
+	 */
+	prefetchw(item->prev);
+	prefetchw(item->next);
+
 	spin_lock(&nlru->lock);
 	if (!list_empty(item)) {
 		l = list_lru_from_kmem(nlru, item);
@@ -168,10 +176,10 @@ static unsigned long __list_lru_count_one(struct list_lru *lru,
 	struct list_lru_one *l;
 	unsigned long count;
 
-	spin_lock(&nlru->lock);
+	rcu_read_lock();
 	l = list_lru_from_memcg_idx(nlru, memcg_idx);
 	count = l->nr_items;
-	spin_unlock(&nlru->lock);
+	rcu_read_unlock();
 
 	return count;
 }
@@ -324,24 +332,41 @@ static int __memcg_init_list_lru_node(struct list_lru_memcg *memcg_lrus,
 
 static int memcg_init_list_lru_node(struct list_lru_node *nlru)
 {
+	struct list_lru_memcg *memcg_lrus;
 	int size = memcg_nr_cache_ids;
 
-	nlru->memcg_lrus = kvmalloc(size * sizeof(void *), GFP_KERNEL);
-	if (!nlru->memcg_lrus)
+	memcg_lrus = kvmalloc(sizeof(*memcg_lrus) +
+			      size * sizeof(void *), GFP_KERNEL);
+	if (!memcg_lrus)
 		return -ENOMEM;
 
-	if (__memcg_init_list_lru_node(nlru->memcg_lrus, 0, size)) {
-		kvfree(nlru->memcg_lrus);
+	if (__memcg_init_list_lru_node(memcg_lrus, 0, size)) {
+		kvfree(memcg_lrus);
 		return -ENOMEM;
 	}
+	RCU_INIT_POINTER(nlru->memcg_lrus, memcg_lrus);
 
 	return 0;
 }
 
 static void memcg_destroy_list_lru_node(struct list_lru_node *nlru)
 {
-	__memcg_destroy_list_lru_node(nlru->memcg_lrus, 0, memcg_nr_cache_ids);
-	kvfree(nlru->memcg_lrus);
+	struct list_lru_memcg *memcg_lrus;
+	/*
+	 * This is called when shrinker has already been unregistered,
+	 * and nobody can use it. So, there is no need to use kvfree_rcu().
+	 */
+	memcg_lrus = rcu_dereference_protected(nlru->memcg_lrus, true);
+	__memcg_destroy_list_lru_node(memcg_lrus, 0, memcg_nr_cache_ids);
+	kvfree(memcg_lrus);
+}
+
+static void kvfree_rcu(struct rcu_head *head)
+{
+	struct list_lru_memcg *mlru;
+
+	mlru = container_of(head, struct list_lru_memcg, rcu);
+	kvfree(mlru);
 }
 
 static int memcg_update_list_lru_node(struct list_lru_node *nlru,
@@ -351,8 +376,9 @@ static int memcg_update_list_lru_node(struct list_lru_node *nlru,
 
 	BUG_ON(old_size > new_size);
 
-	old = nlru->memcg_lrus;
-	new = kvmalloc(new_size * sizeof(void *), GFP_KERNEL);
+	old = rcu_dereference_protected(nlru->memcg_lrus,
+					lockdep_is_held(&list_lrus_mutex));
+	new = kvmalloc(sizeof(*new) + new_size * sizeof(void *), GFP_KERNEL);
 	if (!new)
 		return -ENOMEM;
 
@@ -361,29 +387,33 @@ static int memcg_update_list_lru_node(struct list_lru_node *nlru,
 		return -ENOMEM;
 	}
 
-	memcpy(new, old, old_size * sizeof(void *));
+	memcpy(&new->lru, &old->lru, old_size * sizeof(void *));
 
 	/*
-	 * The lock guarantees that we won't race with a reader
-	 * (see list_lru_from_memcg_idx).
+	 * The locking below allows readers that hold nlru->lock avoid taking
+	 * rcu_read_lock (see list_lru_from_memcg_idx).
 	 *
 	 * Since list_lru_{add,del} may be called under an IRQ-safe lock,
 	 * we have to use IRQ-safe primitives here to avoid deadlock.
 	 */
 	spin_lock_irq(&nlru->lock);
-	nlru->memcg_lrus = new;
+	rcu_assign_pointer(nlru->memcg_lrus, new);
 	spin_unlock_irq(&nlru->lock);
 
-	kvfree(old);
+	call_rcu(&old->rcu, kvfree_rcu);
 	return 0;
 }
 
 static void memcg_cancel_update_list_lru_node(struct list_lru_node *nlru,
 					      int old_size, int new_size)
 {
+	struct list_lru_memcg *memcg_lrus;
+
+	memcg_lrus = rcu_dereference_protected(nlru->memcg_lrus,
+					       lockdep_is_held(&list_lrus_mutex));
 	/* do not bother shrinking the array back to the old size, because we
 	 * cannot handle allocation failures here */
-	__memcg_destroy_list_lru_node(nlru->memcg_lrus, old_size, new_size);
+	__memcg_destroy_list_lru_node(memcg_lrus, old_size, new_size);
 }
 
 static int memcg_init_list_lru(struct list_lru *lru, bool memcg_aware)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 670e99b68aa6..afdb35cf4d0e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -888,7 +888,8 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
  * value, the function breaks the iteration loop and returns the value.
  * Otherwise, it will iterate over all tasks and return 0.
  *
- * This function must not be called for the root memory cgroup.
+ * If memcg is the root memory cgroup, this function will iterate only
+ * over tasks belonging directly to the root memory cgroup.
  */
 int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
 			  int (*fn)(struct task_struct *, void *), void *arg)
@@ -896,8 +897,6 @@ int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
 	struct mem_cgroup *iter;
 	int ret = 0;
 
-	BUG_ON(memcg == root_mem_cgroup);
-
 	for_each_mem_cgroup_tree(iter, memcg) {
 		struct css_task_iter it;
 		struct task_struct *task;
@@ -906,7 +905,7 @@ int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
 		while (!ret && (task = css_task_iter_next(&it)))
 			ret = fn(task, arg);
 		css_task_iter_end(&it);
-		if (ret) {
+		if (ret || memcg == root_mem_cgroup) {
 			mem_cgroup_iter_break(memcg, iter);
 			break;
 		}
@@ -2592,6 +2591,224 @@ static inline bool memcg_has_children(struct mem_cgroup *memcg)
 	return ret;
 }
 
+static long memcg_oom_badness(struct mem_cgroup *memcg,
+			      const nodemask_t *nodemask,
+			      unsigned long totalpages)
+{
+	long points = 0;
+	int nid;
+	pg_data_t *pgdat;
+
+	for_each_node_state(nid, N_MEMORY) {
+		if (nodemask && !node_isset(nid, *nodemask))
+			continue;
+
+		points += mem_cgroup_node_nr_lru_pages(memcg, nid,
+				LRU_ALL_ANON | BIT(LRU_UNEVICTABLE));
+
+		pgdat = NODE_DATA(nid);
+		points += lruvec_page_state(mem_cgroup_lruvec(pgdat, memcg),
+					    NR_SLAB_UNRECLAIMABLE);
+	}
+
+	points += memcg_page_state(memcg, MEMCG_KERNEL_STACK_KB) /
+		(PAGE_SIZE / 1024);
+	points += memcg_page_state(memcg, MEMCG_SOCK);
+	points += memcg_page_state(memcg, MEMCG_SWAP);
+
+	return points;
+}
+
+/*
+ * Checks if the given memcg is a valid OOM victim and returns a number,
+ * which means the folowing:
+ *   -1: there are inflight OOM victim tasks, belonging to the memcg
+ *    0: memcg is not eligible, e.g. all belonging tasks are protected
+ *       by oom_score_adj set to OOM_SCORE_ADJ_MIN
+ *   >0: memcg is eligible, and the returned value is an estimation
+ *       of the memory footprint
+ */
+static long oom_evaluate_memcg(struct mem_cgroup *memcg,
+			       const nodemask_t *nodemask,
+			       unsigned long totalpages)
+{
+	struct css_task_iter it;
+	struct task_struct *task;
+	int eligible = 0;
+
+	/*
+	 * Root memory cgroup is a special case:
+	 * we don't have necessary stats to evaluate it exactly as
+	 * leaf memory cgroups, so we approximate it's oom_score
+	 * by summing oom_score of all belonging tasks, which are
+	 * owners of their mm structs.
+	 *
+	 * If there are inflight OOM victim tasks inside
+	 * the root memcg, we return -1.
+	 */
+	if (memcg == root_mem_cgroup) {
+		struct css_task_iter it;
+		struct task_struct *task;
+		long score = 0;
+
+		css_task_iter_start(&memcg->css, 0, &it);
+		while ((task = css_task_iter_next(&it))) {
+			if (tsk_is_oom_victim(task) &&
+			    !test_bit(MMF_OOM_SKIP,
+				      &task->signal->oom_mm->flags)) {
+				score = -1;
+				break;
+			}
+
+			task_lock(task);
+			if (!task->mm || task->mm->owner != task) {
+				task_unlock(task);
+				continue;
+			}
+			task_unlock(task);
+
+			score += oom_badness(task, memcg, nodemask,
+					     totalpages);
+		}
+		css_task_iter_end(&it);
+
+		return score;
+	}
+
+	/*
+	 * Memcg is OOM eligible if there are OOM killable tasks inside.
+	 *
+	 * We treat tasks with oom_score_adj set to OOM_SCORE_ADJ_MIN
+	 * as unkillable.
+	 *
+	 * If there are inflight OOM victim tasks inside the memcg,
+	 * we return -1.
+	 */
+	css_task_iter_start(&memcg->css, 0, &it);
+	while ((task = css_task_iter_next(&it))) {
+		if (!eligible &&
+		    task->signal->oom_score_adj != OOM_SCORE_ADJ_MIN)
+			eligible = 1;
+
+		if (tsk_is_oom_victim(task) &&
+		    !test_bit(MMF_OOM_SKIP, &task->signal->oom_mm->flags)) {
+			eligible = -1;
+			break;
+		}
+	}
+	css_task_iter_end(&it);
+
+	if (eligible <= 0)
+		return eligible;
+
+	return memcg_oom_badness(memcg, nodemask, totalpages);
+}
+
+static void select_victim_memcg(struct mem_cgroup *root, struct oom_control *oc)
+{
+	struct mem_cgroup *iter, *group = NULL;
+	long group_score = 0;
+
+	oc->chosen_memcg = NULL;
+	oc->chosen_points = 0;
+
+	/*
+	 * If OOM is memcg-wide, and the memcg has the oom_group flag set,
+	 * all tasks belonging to the memcg should be killed.
+	 * So, we mark the memcg as a victim.
+	 */
+	if (oc->memcg && mem_cgroup_oom_group(oc->memcg)) {
+		oc->chosen_memcg = oc->memcg;
+		css_get(&oc->chosen_memcg->css);
+		return;
+	}
+
+	/*
+	 * The oom_score is calculated for leaf memory cgroups (including
+	 * the root memcg).
+	 * Non-leaf oom_group cgroups accumulating score of descendant
+	 * leaf memory cgroups.
+	 */
+	rcu_read_lock();
+	for_each_mem_cgroup_tree(iter, root) {
+		long score;
+
+		/*
+		 * We don't consider non-leaf non-oom_group memory cgroups
+		 * as OOM victims.
+		 */
+		if (memcg_has_children(iter) && iter != root_mem_cgroup &&
+		    !mem_cgroup_oom_group(iter))
+			continue;
+
+		/*
+		 * If group is not set or we've ran out of the group's sub-tree,
+		 * we should set group and reset group_score.
+		 */
+		if (!group || group == root_mem_cgroup ||
+		    !mem_cgroup_is_descendant(iter, group)) {
+			group = iter;
+			group_score = 0;
+		}
+
+		if (memcg_has_children(iter) && iter != root_mem_cgroup)
+			continue;
+
+		score = oom_evaluate_memcg(iter, oc->nodemask, oc->totalpages);
+
+		/*
+		 * Ignore empty and non-eligible memory cgroups.
+		 */
+		if (score == 0)
+			continue;
+
+		/*
+		 * If there are inflight OOM victims, we don't need
+		 * to look further for new victims.
+		 */
+		if (score == -1) {
+			oc->chosen_memcg = INFLIGHT_VICTIM;
+			mem_cgroup_iter_break(root, iter);
+			break;
+		}
+
+		group_score += score;
+
+		if (group_score > oc->chosen_points) {
+			oc->chosen_points = group_score;
+			oc->chosen_memcg = group;
+		}
+	}
+
+	if (oc->chosen_memcg && oc->chosen_memcg != INFLIGHT_VICTIM)
+		css_get(&oc->chosen_memcg->css);
+
+	rcu_read_unlock();
+}
+
+bool mem_cgroup_select_oom_victim(struct oom_control *oc)
+{
+	struct mem_cgroup *root;
+
+	if (mem_cgroup_disabled())
+		return false;
+
+	if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
+		return false;
+
+	if (!(cgrp_dfl_root.flags & CGRP_GROUP_OOM))
+		return false;
+
+	if (oc->memcg)
+		root = oc->memcg;
+	else
+		root = root_mem_cgroup;
+
+	select_victim_memcg(root, oc);
+
+	return oc->chosen_memcg;
+}
+
 /*
  * Reclaims as many pages from the given memcg as possible.
  *
@@ -5187,6 +5404,39 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
 	return nbytes;
 }
 
+static int memory_oom_group_show(struct seq_file *m, void *v)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
+	bool oom_group = memcg->oom_group;
+
+	if (!(cgrp_dfl_root.flags & CGRP_GROUP_OOM))
+		return -ENOTSUPP;
+
+	seq_printf(m, "%d\n", oom_group);
+
+	return 0;
+}
+
+static ssize_t memory_oom_group_write(struct kernfs_open_file *of,
+				      char *buf, size_t nbytes,
+				      loff_t off)
+{
+	struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+	int oom_group;
+	int err;
+
+	if (!(cgrp_dfl_root.flags & CGRP_GROUP_OOM))
+		return -ENOTSUPP;
+
+	err = kstrtoint(strstrip(buf), 0, &oom_group);
+	if (err)
+		return err;
+
+	memcg->oom_group = oom_group;
+
+	return nbytes;
+}
+
 static int memory_events_show(struct seq_file *m, void *v)
 {
 	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
@@ -5306,6 +5556,12 @@ static struct cftype memory_files[] = {
 		.seq_show = memory_max_show,
 		.write = memory_max_write,
 	},
+	{
+		.name = "oom_group",
+		.flags = CFTYPE_NOT_ON_ROOT | CFTYPE_NS_DELEGATABLE,
+		.seq_show = memory_oom_group_show,
+		.write = memory_oom_group_write,
+	},
 	{
 		.name = "events",
 		.flags = CFTYPE_NOT_ON_ROOT,
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8291b75f42c8..9d142b9b86dc 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -502,6 +502,7 @@ static const char * const action_page_types[] = {
 	[MF_MSG_POISONED_HUGE]		= "huge page already hardware poisoned",
 	[MF_MSG_HUGE]			= "huge page",
 	[MF_MSG_FREE_HUGE]		= "free huge page",
+	[MF_MSG_NON_PMD_HUGE]		= "non-pmd-sized huge page",
 	[MF_MSG_UNMAP_FAILED]		= "unmapping failed page",
 	[MF_MSG_DIRTY_SWAPCACHE]	= "dirty swapcache page",
 	[MF_MSG_CLEAN_SWAPCACHE]	= "clean swapcache page",
@@ -1084,6 +1085,21 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
 		return 0;
 	}
 
+	/*
+	 * TODO: hwpoison for pud-sized hugetlb doesn't work right now, so
+	 * simply disable it. In order to make it work properly, we need
+	 * make sure that:
+	 *  - conversion of a pud that maps an error hugetlb into hwpoison
+	 *    entry properly works, and
+	 *  - other mm code walking over page table is aware of pud-aligned
+	 *    hwpoison entries.
+	 */
+	if (huge_page_size(page_hstate(head)) > PMD_SIZE) {
+		action_result(pfn, MF_MSG_NON_PMD_HUGE, MF_IGNORED);
+		res = -EBUSY;
+		goto out;
+	}
+
 	if (!hwpoison_user_mappings(p, pfn, flags, &head)) {
 		action_result(pfn, MF_MSG_UNMAP_FAILED, MF_IGNORED);
 		res = -EBUSY;
@@ -1471,7 +1487,7 @@ int unpoison_memory(unsigned long pfn)
 }
 EXPORT_SYMBOL(unpoison_memory);
 
-static struct page *new_page(struct page *p, unsigned long private, int **x)
+static struct page *new_page(struct page *p, unsigned long private)
 {
 	int nid = page_to_nid(p);
 
diff --git a/mm/memory.c b/mm/memory.c
index 5fcfc24904d1..2031cb12aafa 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3052,7 +3052,6 @@ int do_swap_page(struct vm_fault *vmf)
 	flush_icache_page(vma, page);
 	if (pte_swp_soft_dirty(vmf->orig_pte))
 		pte = pte_mksoft_dirty(pte);
-	set_pte_at(vma->vm_mm, vmf->address, vmf->pte, pte);
 	vmf->orig_pte = pte;
 
 	/* ksm created a completely new copy */
@@ -3065,6 +3064,7 @@ int do_swap_page(struct vm_fault *vmf)
 		mem_cgroup_commit_charge(page, memcg, true, false);
 		activate_page(page);
 	}
+	set_pte_at(vma->vm_mm, vmf->address, vmf->pte, pte);
 
 	swap_free(entry);
 	if (mem_cgroup_swap_full(page) ||
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index b2bd52ff7605..6a9bee33ffa7 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -689,6 +689,10 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
 	if (PageReserved(pfn_to_page(start_pfn)))
 		for (i = 0; i < nr_pages; i++) {
 			page = pfn_to_page(start_pfn + i);
+			if (PageHWPoison(page)) {
+				ClearPageReserved(page);
+				continue;
+			}
 			(*online_page_callback)(page);
 			onlined_pages++;
 		}
@@ -1337,8 +1341,7 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
 	return 0;
 }
 
-static struct page *new_node_page(struct page *page, unsigned long private,
-		int **result)
+static struct page *new_node_page(struct page *page, unsigned long private)
 {
 	int nid = page_to_nid(page);
 	nodemask_t nmask = node_states[N_MEMORY];
@@ -1381,7 +1384,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 			if (isolate_huge_page(page, &source))
 				move_pages -= 1 << compound_order(head);
 			continue;
-		} else if (thp_migration_supported() && PageTransHuge(page))
+		} else if (PageTransHuge(page))
 			pfn = page_to_pfn(compound_head(page))
 				+ hpage_nr_pages(page) - 1;
 
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index d879f1d8a44a..a8b7d59002e8 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -446,15 +446,6 @@ static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
 		__split_huge_pmd(walk->vma, pmd, addr, false, NULL);
 		goto out;
 	}
-	if (!thp_migration_supported()) {
-		get_page(page);
-		spin_unlock(ptl);
-		lock_page(page);
-		ret = split_huge_page(page);
-		unlock_page(page);
-		put_page(page);
-		goto out;
-	}
 	if (!queue_pages_required(page, qp)) {
 		ret = 1;
 		goto unlock;
@@ -495,7 +486,7 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
 
 	if (pmd_trans_unstable(pmd))
 		return 0;
-retry:
+
 	pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
 	for (; addr != end; pte++, addr += PAGE_SIZE) {
 		if (!pte_present(*pte))
@@ -511,22 +502,6 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
 			continue;
 		if (!queue_pages_required(page, qp))
 			continue;
-		if (PageTransCompound(page) && !thp_migration_supported()) {
-			get_page(page);
-			pte_unmap_unlock(pte, ptl);
-			lock_page(page);
-			ret = split_huge_page(page);
-			unlock_page(page);
-			put_page(page);
-			/* Failed to split -- skip. */
-			if (ret) {
-				pte = pte_offset_map_lock(walk->mm, pmd,
-						addr, &ptl);
-				continue;
-			}
-			goto retry;
-		}
-
 		migrate_page_add(page, qp->pagelist, flags);
 	}
 	pte_unmap_unlock(pte - 1, ptl);
@@ -942,12 +917,13 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
 	}
 }
 
-static struct page *new_node_page(struct page *page, unsigned long node, int **x)
+/* page allocation callback for NUMA node migration */
+struct page *alloc_new_node_page(struct page *page, unsigned long node)
 {
 	if (PageHuge(page))
 		return alloc_huge_page_node(page_hstate(compound_head(page)),
 					node);
-	else if (thp_migration_supported() && PageTransHuge(page)) {
+	else if (PageTransHuge(page)) {
 		struct page *thp;
 
 		thp = alloc_pages_node(node,
@@ -986,7 +962,7 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
 			flags | MPOL_MF_DISCONTIG_OK, &pagelist);
 
 	if (!list_empty(&pagelist)) {
-		err = migrate_pages(&pagelist, new_node_page, NULL, dest,
+		err = migrate_pages(&pagelist, alloc_new_node_page, NULL, dest,
 					MIGRATE_SYNC, MR_SYSCALL);
 		if (err)
 			putback_movable_pages(&pagelist);
@@ -1107,7 +1083,7 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from,
  * list of pages handed to migrate_pages()--which is how we get here--
  * is in virtual address order.
  */
-static struct page *new_page(struct page *page, unsigned long start, int **x)
+static struct page *new_page(struct page *page, unsigned long start)
 {
 	struct vm_area_struct *vma;
 	unsigned long uninitialized_var(address);
@@ -1123,7 +1099,7 @@ static struct page *new_page(struct page *page, unsigned long start, int **x)
 	if (PageHuge(page)) {
 		return alloc_huge_page_vma(page_hstate(compound_head(page)),
 				vma, address);
-	} else if (thp_migration_supported() && PageTransHuge(page)) {
+	} else if (PageTransHuge(page)) {
 		struct page *thp;
 
 		thp = alloc_hugepage_vma(GFP_TRANSHUGE, vma, address,
@@ -1152,7 +1128,7 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from,
 	return -ENOSYS;
 }
 
-static struct page *new_page(struct page *page, unsigned long start, int **x)
+static struct page *new_page(struct page *page, unsigned long start)
 {
 	return NULL;
 }
diff --git a/mm/migrate.c b/mm/migrate.c
index 1e5525a25691..5d0dc7b85f90 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1136,10 +1136,12 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
 				   enum migrate_reason reason)
 {
 	int rc = MIGRATEPAGE_SUCCESS;
-	int *result = NULL;
 	struct page *newpage;
 
-	newpage = get_new_page(page, private, &result);
+	if (!thp_migration_supported() && PageTransHuge(page))
+		return -ENOMEM;
+
+	newpage = get_new_page(page, private);
 	if (!newpage)
 		return -ENOMEM;
 
@@ -1160,14 +1162,6 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
 		goto out;
 	}
 
-	if (unlikely(PageTransHuge(page) && !PageTransHuge(newpage))) {
-		lock_page(page);
-		rc = split_huge_page(page);
-		unlock_page(page);
-		if (rc)
-			goto out;
-	}
-
 	rc = __unmap_and_move(page, newpage, force, mode);
 	if (rc == MIGRATEPAGE_SUCCESS)
 		set_page_owner_migrate_reason(newpage, reason);
@@ -1230,12 +1224,6 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
 			put_page(newpage);
 	}
 
-	if (result) {
-		if (rc)
-			*result = rc;
-		else
-			*result = page_to_nid(newpage);
-	}
 	return rc;
 }
 
@@ -1263,7 +1251,6 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 				enum migrate_mode mode, int reason)
 {
 	int rc = -EAGAIN;
-	int *result = NULL;
 	int page_was_mapped = 0;
 	struct page *new_hpage;
 	struct anon_vma *anon_vma = NULL;
@@ -1280,7 +1267,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 		return -ENOSYS;
 	}
 
-	new_hpage = get_new_page(hpage, private, &result);
+	new_hpage = get_new_page(hpage, private);
 	if (!new_hpage)
 		return -ENOMEM;
 
@@ -1344,12 +1331,6 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 	else
 		putback_active_hugepage(new_hpage);
 
-	if (result) {
-		if (rc)
-			*result = rc;
-		else
-			*result = page_to_nid(new_hpage);
-	}
 	return rc;
 }
 
@@ -1394,6 +1375,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
 		retry = 0;
 
 		list_for_each_entry_safe(page, page2, from, lru) {
+retry:
 			cond_resched();
 
 			if (PageHuge(page))
@@ -1407,6 +1389,26 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
 
 			switch(rc) {
 			case -ENOMEM:
+				/*
+				 * THP migration might be unsupported or the
+				 * allocation could've failed so we should
+				 * retry on the same page with the THP split
+				 * to base pages.
+				 *
+				 * Head page is retried immediately and tail
+				 * pages are added to the tail of the list so
+				 * we encounter them after the rest of the list
+				 * is processed.
+				 */
+				if (PageTransHuge(page)) {
+					lock_page(page);
+					rc = split_huge_page_to_list(page, from);
+					unlock_page(page);
+					if (!rc) {
+						list_safe_reset_next(page, page2, lru);
+						goto retry;
+					}
+				}
 				nr_failed++;
 				goto out;
 			case -EAGAIN:
@@ -1443,141 +1445,101 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
 }
 
 #ifdef CONFIG_NUMA
-/*
- * Move a list of individual pages
- */
-struct page_to_node {
-	unsigned long addr;
-	struct page *page;
-	int node;
-	int status;
-};
 
-static struct page *new_page_node(struct page *p, unsigned long private,
-		int **result)
+static int store_status(int __user *status, int start, int value, int nr)
 {
-	struct page_to_node *pm = (struct page_to_node *)private;
-
-	while (pm->node != MAX_NUMNODES && pm->page != p)
-		pm++;
+	while (nr-- > 0) {
+		if (put_user(value, status + start))
+			return -EFAULT;
+		start++;
+	}
 
-	if (pm->node == MAX_NUMNODES)
-		return NULL;
+	return 0;
+}
 
-	*result = &pm->status;
+static int do_move_pages_to_node(struct mm_struct *mm,
+		struct list_head *pagelist, int node)
+{
+	int err;
 
-	if (PageHuge(p))
-		return alloc_huge_page_node(page_hstate(compound_head(p)),
-					pm->node);
-	else if (thp_migration_supported() && PageTransHuge(p)) {
-		struct page *thp;
+	if (list_empty(pagelist))
+		return 0;
 
-		thp = alloc_pages_node(pm->node,
-			(GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_RECLAIM,
-			HPAGE_PMD_ORDER);
-		if (!thp)
-			return NULL;
-		prep_transhuge_page(thp);
-		return thp;
-	} else
-		return __alloc_pages_node(pm->node,
-				GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
+	err = migrate_pages(pagelist, alloc_new_node_page, NULL, node,
+			MIGRATE_SYNC, MR_SYSCALL);
+	if (err)
+		putback_movable_pages(pagelist);
+	return err;
 }
 
 /*
- * Move a set of pages as indicated in the pm array. The addr
- * field must be set to the virtual address of the page to be moved
- * and the node number must contain a valid target node.
- * The pm array ends with node = MAX_NUMNODES.
+ * Resolves the given address to a struct page, isolates it from the LRU and
+ * puts it to the given pagelist.
+ * Returns -errno if the page cannot be found/isolated or 0 when it has been
+ * queued or the page doesn't need to be migrated because it is already on
+ * the target node
  */
-static int do_move_page_to_node_array(struct mm_struct *mm,
-				      struct page_to_node *pm,
-				      int migrate_all)
+static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
+		int node, struct list_head *pagelist, bool migrate_all)
 {
+	struct vm_area_struct *vma;
+	struct page *page;
+	unsigned int follflags;
 	int err;
-	struct page_to_node *pp;
-	LIST_HEAD(pagelist);
 
 	down_read(&mm->mmap_sem);
+	err = -EFAULT;
+	vma = find_vma(mm, addr);
+	if (!vma || addr < vma->vm_start || !vma_migratable(vma))
+		goto out;
 
-	/*
-	 * Build a list of pages to migrate
-	 */
-	for (pp = pm; pp->node != MAX_NUMNODES; pp++) {
-		struct vm_area_struct *vma;
-		struct page *page;
-		struct page *head;
-		unsigned int follflags;
-
-		err = -EFAULT;
-		vma = find_vma(mm, pp->addr);
-		if (!vma || pp->addr < vma->vm_start || !vma_migratable(vma))
-			goto set_status;
-
-		/* FOLL_DUMP to ignore special (like zero) pages */
-		follflags = FOLL_GET | FOLL_DUMP;
-		if (!thp_migration_supported())
-			follflags |= FOLL_SPLIT;
-		page = follow_page(vma, pp->addr, follflags);
+	/* FOLL_DUMP to ignore special (like zero) pages */
+	follflags = FOLL_GET | FOLL_DUMP;
+	page = follow_page(vma, addr, follflags);
 
-		err = PTR_ERR(page);
-		if (IS_ERR(page))
-			goto set_status;
+	err = PTR_ERR(page);
+	if (IS_ERR(page))
+		goto out;
 
-		err = -ENOENT;
-		if (!page)
-			goto set_status;
+	err = -ENOENT;
+	if (!page)
+		goto out;
 
-		err = page_to_nid(page);
+	err = 0;
+	if (page_to_nid(page) == node)
+		goto out_putpage;
 
-		if (err == pp->node)
-			/*
-			 * Node already in the right place
-			 */
-			goto put_and_set;
+	err = -EACCES;
+	if (page_mapcount(page) > 1 && !migrate_all)
+		goto out_putpage;
 
-		err = -EACCES;
-		if (page_mapcount(page) > 1 &&
-				!migrate_all)
-			goto put_and_set;
-
-		if (PageHuge(page)) {
-			if (PageHead(page)) {
-				isolate_huge_page(page, &pagelist);
-				err = 0;
-				pp->page = page;
-			}
-			goto put_and_set;
+	if (PageHuge(page)) {
+		if (PageHead(page)) {
+			isolate_huge_page(page, pagelist);
+			err = 0;
 		}
+	} else {
+		struct page *head;
 
-		pp->page = compound_head(page);
 		head = compound_head(page);
 		err = isolate_lru_page(head);
-		if (!err) {
-			list_add_tail(&head->lru, &pagelist);
-			mod_node_page_state(page_pgdat(head),
-				NR_ISOLATED_ANON + page_is_file_cache(head),
-				hpage_nr_pages(head));
-		}
-put_and_set:
-		/*
-		 * Either remove the duplicate refcount from
-		 * isolate_lru_page() or drop the page ref if it was
-		 * not isolated.
-		 */
-		put_page(page);
-set_status:
-		pp->status = err;
-	}
-
-	err = 0;
-	if (!list_empty(&pagelist)) {
-		err = migrate_pages(&pagelist, new_page_node, NULL,
-				(unsigned long)pm, MIGRATE_SYNC, MR_SYSCALL);
 		if (err)
-			putback_movable_pages(&pagelist);
-	}
+			goto out_putpage;
 
+		err = 0;
+		list_add_tail(&head->lru, pagelist);
+		mod_node_page_state(page_pgdat(head),
+			NR_ISOLATED_ANON + page_is_file_cache(head),
+			hpage_nr_pages(head));
+	}
+out_putpage:
+	/*
+	 * Either remove the duplicate refcount from
+	 * isolate_lru_page() or drop the page ref if it was
+	 * not isolated.
+	 */
+	put_page(page);
+out:
 	up_read(&mm->mmap_sem);
 	return err;
 }
@@ -1592,79 +1554,79 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
 			 const int __user *nodes,
 			 int __user *status, int flags)
 {
-	struct page_to_node *pm;
-	unsigned long chunk_nr_pages;
-	unsigned long chunk_start;
-	int err;
-
-	err = -ENOMEM;
-	pm = (struct page_to_node *)__get_free_page(GFP_KERNEL);
-	if (!pm)
-		goto out;
+	int current_node = NUMA_NO_NODE;
+	LIST_HEAD(pagelist);
+	int start, i;
+	int err = 0, err1;
 
 	migrate_prep();
 
-	/*
-	 * Store a chunk of page_to_node array in a page,
-	 * but keep the last one as a marker
-	 */
-	chunk_nr_pages = (PAGE_SIZE / sizeof(struct page_to_node)) - 1;
-
-	for (chunk_start = 0;
-	     chunk_start < nr_pages;
-	     chunk_start += chunk_nr_pages) {
-		int j;
-
-		if (chunk_start + chunk_nr_pages > nr_pages)
-			chunk_nr_pages = nr_pages - chunk_start;
-
-		/* fill the chunk pm with addrs and nodes from user-space */
-		for (j = 0; j < chunk_nr_pages; j++) {
-			const void __user *p;
-			int node;
-
-			err = -EFAULT;
-			if (get_user(p, pages + j + chunk_start))
-				goto out_pm;
-			pm[j].addr = (unsigned long) p;
+	for (i = start = 0; i < nr_pages; i++) {
+		const void __user *p;
+		unsigned long addr;
+		int node;
 
-			if (get_user(node, nodes + j + chunk_start))
-				goto out_pm;
-
-			err = -ENODEV;
-			if (node < 0 || node >= MAX_NUMNODES)
-				goto out_pm;
-
-			if (!node_state(node, N_MEMORY))
-				goto out_pm;
-
-			err = -EACCES;
-			if (!node_isset(node, task_nodes))
-				goto out_pm;
+		err = -EFAULT;
+		if (get_user(p, pages + i))
+			goto out_flush;
+		if (get_user(node, nodes + i))
+			goto out_flush;
+		addr = (unsigned long)p;
+
+		err = -ENODEV;
+		if (node < 0 || node >= MAX_NUMNODES)
+			goto out_flush;
+		if (!node_state(node, N_MEMORY))
+			goto out_flush;
 
-			pm[j].node = node;
+		err = -EACCES;
+		if (!node_isset(node, task_nodes))
+			goto out_flush;
+
+		if (current_node == NUMA_NO_NODE) {
+			current_node = node;
+			start = i;
+		} else if (node != current_node) {
+			err = do_move_pages_to_node(mm, &pagelist, current_node);
+			if (err)
+				goto out;
+			err = store_status(status, start, current_node, i - start);
+			if (err)
+				goto out;
+			start = i;
+			current_node = node;
 		}
 
-		/* End marker for this chunk */
-		pm[chunk_nr_pages].node = MAX_NUMNODES;
+		/*
+		 * Errors in the page lookup or isolation are not fatal and we simply
+		 * report them via status
+		 */
+		err = add_page_for_migration(mm, addr, current_node,
+				&pagelist, flags & MPOL_MF_MOVE_ALL);
+		if (!err)
+			continue;
 
-		/* Migrate this chunk */
-		err = do_move_page_to_node_array(mm, pm,
-						 flags & MPOL_MF_MOVE_ALL);
-		if (err < 0)
-			goto out_pm;
+		err = store_status(status, i, err, 1);
+		if (err)
+			goto out_flush;
 
-		/* Return status information */
-		for (j = 0; j < chunk_nr_pages; j++)
-			if (put_user(pm[j].status, status + j + chunk_start)) {
-				err = -EFAULT;
-				goto out_pm;
-			}
+		err = do_move_pages_to_node(mm, &pagelist, current_node);
+		if (err)
+			goto out;
+		if (i > start) {
+			err = store_status(status, start, current_node, i - start);
+			if (err)
+				goto out;
+		}
+		current_node = NUMA_NO_NODE;
 	}
-	err = 0;
-
-out_pm:
-	free_page((unsigned long)pm);
+out_flush:
+	/* Make sure we do not overwrite the existing error */
+	err1 = do_move_pages_to_node(mm, &pagelist, current_node);
+	if (!err1)
+		err1 = store_status(status, start, current_node, i - start);
+	if (!err)
+		err = err1;
 out:
 	return err;
 }
@@ -1835,8 +1797,7 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
 }
 
 static struct page *alloc_misplaced_dst_page(struct page *page,
-					   unsigned long data,
-					   int **result)
+					   unsigned long data)
 {
 	int nid = (int) data;
 	struct page *newpage;
diff --git a/mm/mlock.c b/mm/mlock.c
index 79398200e423..74e5a6547c3d 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -64,6 +64,12 @@ void clear_page_mlock(struct page *page)
 	mod_zone_page_state(page_zone(page), NR_MLOCK,
 			    -hpage_nr_pages(page));
 	count_vm_event(UNEVICTABLE_PGCLEARED);
+	/*
+	 * The previous TestClearPageMlocked() corresponds to the smp_mb()
+	 * in __pagevec_lru_add_fn().
+	 *
+	 * See __pagevec_lru_add_fn for more explanation.
+	 */
 	if (!isolate_lru_page(page)) {
 		putback_lru_page(page);
 	} else {
diff --git a/mm/mmap.c b/mm/mmap.c
index 9efdc021ad22..4bb038e7984b 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1342,6 +1342,10 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
 		if (!(file && path_noexec(&file->f_path)))
 			prot |= PROT_EXEC;
 
+	/* force arch specific MAP_FIXED handling in get_unmapped_area */
+	if (flags & MAP_FIXED_NOREPLACE)
+		flags |= MAP_FIXED;
+
 	if (!(flags & MAP_FIXED))
 		addr = round_hint_to_min(addr);
 
@@ -1365,6 +1369,13 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
 	if (offset_in_page(addr))
 		return addr;
 
+	if (flags & MAP_FIXED_NOREPLACE) {
+		struct vm_area_struct *vma = find_vma(mm, addr);
+
+		if (vma && vma->vm_start <= addr)
+			return -EEXIST;
+	}
+
 	if (prot == PROT_EXEC) {
 		pkey = execute_only_pkey(mm);
 		if (pkey < 0)
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index f2e7dfb81eee..8219001708e0 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -309,7 +309,7 @@ static enum oom_constraint constrained_alloc(struct oom_control *oc)
 	return CONSTRAINT_NONE;
 }
 
-static int oom_evaluate_task(struct task_struct *task, void *arg)
+int oom_evaluate_task(struct task_struct *task, void *arg)
 {
 	struct oom_control *oc = arg;
 	unsigned long points;
@@ -343,26 +343,26 @@ static int oom_evaluate_task(struct task_struct *task, void *arg)
 		goto next;
 
 	/* Prefer thread group leaders for display purposes */
-	if (points == oc->chosen_points && thread_group_leader(oc->chosen))
+	if (points == oc->chosen_points && thread_group_leader(oc->chosen_task))
 		goto next;
 select:
-	if (oc->chosen)
-		put_task_struct(oc->chosen);
+	if (oc->chosen_task)
+		put_task_struct(oc->chosen_task);
 	get_task_struct(task);
-	oc->chosen = task;
+	oc->chosen_task = task;
 	oc->chosen_points = points;
 next:
 	return 0;
 abort:
-	if (oc->chosen)
-		put_task_struct(oc->chosen);
-	oc->chosen = (void *)-1UL;
+	if (oc->chosen_task)
+		put_task_struct(oc->chosen_task);
+	oc->chosen_task = INFLIGHT_VICTIM;
 	return 1;
 }
 
 /*
  * Simple selection loop. We choose the process with the highest number of
- * 'points'. In case scan was aborted, oc->chosen is set to -1.
+ * 'points'. In case scan was aborted, oc->chosen_task is set to -1.
  */
 static void select_bad_process(struct oom_control *oc)
 {
@@ -834,67 +834,22 @@ static bool task_will_free_mem(struct task_struct *task)
 	return ret;
 }
 
-static void oom_kill_process(struct oom_control *oc, const char *message)
+static void __oom_kill_process(struct task_struct *victim)
 {
-	struct task_struct *p = oc->chosen;
-	unsigned int points = oc->chosen_points;
-	struct task_struct *victim = p;
-	struct task_struct *child;
-	struct task_struct *t;
+	struct task_struct *p;
 	struct mm_struct *mm;
-	unsigned int victim_points = 0;
-	static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
-					      DEFAULT_RATELIMIT_BURST);
 	bool can_oom_reap = true;
 
 	/*
-	 * If the task is already exiting, don't alarm the sysadmin or kill
-	 * its children or threads, just give it access to memory reserves
-	 * so it can die quickly
+	 * __oom_kill_process() is used to kill all tasks belonging to
+	 * the selected memory cgroup, so we should check that we're not
+	 * trying to kill an unkillable task.
 	 */
-	task_lock(p);
-	if (task_will_free_mem(p)) {
-		mark_oom_victim(p);
-		wake_oom_reaper(p);
-		task_unlock(p);
-		put_task_struct(p);
+	if (is_global_init(victim) || (victim->flags & PF_KTHREAD) ||
+	    victim->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
+		put_task_struct(victim);
 		return;
 	}
-	task_unlock(p);
-
-	if (__ratelimit(&oom_rs))
-		dump_header(oc, p);
-
-	pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n",
-		message, task_pid_nr(p), p->comm, points);
-
-	/*
-	 * If any of p's children has a different mm and is eligible for kill,
-	 * the one with the highest oom_badness() score is sacrificed for its
-	 * parent.  This attempts to lose the minimal amount of work done while
-	 * still freeing memory.
-	 */
-	read_lock(&tasklist_lock);
-	for_each_thread(p, t) {
-		list_for_each_entry(child, &t->children, sibling) {
-			unsigned int child_points;
-
-			if (process_shares_mm(child, p->mm))
-				continue;
-			/*
-			 * oom_badness() returns 0 if the thread is unkillable
-			 */
-			child_points = oom_badness(child,
-				oc->memcg, oc->nodemask, oc->totalpages);
-			if (child_points > victim_points) {
-				put_task_struct(victim);
-				victim = child;
-				victim_points = child_points;
-				get_task_struct(victim);
-			}
-		}
-	}
-	read_unlock(&tasklist_lock);
 
 	p = find_lock_task_mm(victim);
 	if (!p) {
@@ -969,6 +924,108 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
 }
 #undef K
 
+static void oom_kill_process(struct oom_control *oc, const char *message)
+{
+	struct task_struct *p = oc->chosen_task;
+	unsigned int points = oc->chosen_points;
+	struct task_struct *victim = p;
+	struct task_struct *child;
+	struct task_struct *t;
+	unsigned int victim_points = 0;
+	static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
+					      DEFAULT_RATELIMIT_BURST);
+
+	/*
+	 * If the task is already exiting, don't alarm the sysadmin or kill
+	 * its children or threads, just give it access to memory reserves
+	 * so it can die quickly
+	 */
+	task_lock(p);
+	if (task_will_free_mem(p)) {
+		mark_oom_victim(p);
+		wake_oom_reaper(p);
+		task_unlock(p);
+		put_task_struct(p);
+		return;
+	}
+	task_unlock(p);
+
+	if (__ratelimit(&oom_rs))
+		dump_header(oc, p);
+
+	pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n",
+		message, task_pid_nr(p), p->comm, points);
+
+	/*
+	 * If any of p's children has a different mm and is eligible for kill,
+	 * the one with the highest oom_badness() score is sacrificed for its
+	 * parent.  This attempts to lose the minimal amount of work done while
+	 * still freeing memory.
+	 */
+	read_lock(&tasklist_lock);
+	for_each_thread(p, t) {
+		list_for_each_entry(child, &t->children, sibling) {
+			unsigned int child_points;
+
+			if (process_shares_mm(child, p->mm))
+				continue;
+			/*
+			 * oom_badness() returns 0 if the thread is unkillable
+			 */
+			child_points = oom_badness(child,
+				oc->memcg, oc->nodemask, oc->totalpages);
+			if (child_points > victim_points) {
+				put_task_struct(victim);
+				victim = child;
+				victim_points = child_points;
+				get_task_struct(victim);
+			}
+		}
+	}
+	read_unlock(&tasklist_lock);
+
+	__oom_kill_process(victim);
+}
+
+static int oom_kill_memcg_member(struct task_struct *task, void *unused)
+{
+	get_task_struct(task);
+	__oom_kill_process(task);
+	return 0;
+}
+
+static bool oom_kill_memcg_victim(struct oom_control *oc)
+{
+	if (oc->chosen_memcg == NULL || oc->chosen_memcg == INFLIGHT_VICTIM)
+		return oc->chosen_memcg;
+
+	/*
+	 * If memory.oom_group is set, kill all tasks belonging to the sub-tree
+	 * of the chosen memory cgroup, otherwise kill the task with the biggest
+	 * memory footprint.
+	 */
+	if (mem_cgroup_oom_group(oc->chosen_memcg)) {
+		mem_cgroup_scan_tasks(oc->chosen_memcg, oom_kill_memcg_member,
+				      NULL);
+		/* We have one or more terminating processes at this point. */
+		oc->chosen_task = INFLIGHT_VICTIM;
+	} else {
+		oc->chosen_points = 0;
+		oc->chosen_task = NULL;
+		mem_cgroup_scan_tasks(oc->chosen_memcg, oom_evaluate_task, oc);
+
+		if (oc->chosen_task == NULL ||
+		    oc->chosen_task == INFLIGHT_VICTIM)
+			goto out;
+
+		__oom_kill_process(oc->chosen_task);
+	}
+
+out:
+	mem_cgroup_put(oc->chosen_memcg);
+	return oc->chosen_task;
+}
+
 /*
  * Determines whether the kernel must panic because of the panic_on_oom sysctl.
  */
@@ -1021,6 +1078,7 @@ bool out_of_memory(struct oom_control *oc)
 {
 	unsigned long freed = 0;
 	enum oom_constraint constraint = CONSTRAINT_NONE;
+	bool delay = false; /* if set, delay next allocation attempt */
 
 	if (oom_killer_disabled)
 		return false;
@@ -1065,27 +1123,37 @@ bool out_of_memory(struct oom_control *oc)
 	    current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) &&
 	    current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) {
 		get_task_struct(current);
-		oc->chosen = current;
+		oc->chosen_task = current;
 		oom_kill_process(oc, "Out of memory (oom_kill_allocating_task)");
 		return true;
 	}
 
+	if (mem_cgroup_select_oom_victim(oc) && oom_kill_memcg_victim(oc)) {
+		delay = true;
+		goto out;
+	}
+
 	select_bad_process(oc);
 	/* Found nothing?!?! Either we hang forever, or we panic. */
-	if (!oc->chosen && !is_sysrq_oom(oc) && !is_memcg_oom(oc)) {
+	if (!oc->chosen_task && !is_sysrq_oom(oc) && !is_memcg_oom(oc)) {
 		dump_header(oc, NULL);
 		panic("Out of memory and no killable processes...\n");
 	}
-	if (oc->chosen && oc->chosen != (void *)-1UL) {
+	if (oc->chosen_task && oc->chosen_task != INFLIGHT_VICTIM) {
 		oom_kill_process(oc, !is_memcg_oom(oc) ? "Out of memory" :
 				 "Memory cgroup out of memory");
-		/*
-		 * Give the killed process a good chance to exit before trying
-		 * to allocate memory again.
-		 */
-		schedule_timeout_killable(1);
+		delay = true;
 	}
-	return !!oc->chosen;
+
+out:
+	/*
+	 * Give the killed process a good chance to exit before trying
+	 * to allocate memory again.
+	 */
+	if (delay)
+		schedule_timeout_killable(1);
+
+	return !!oc->chosen_task;
 }
 
 /*
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 81e18ceef579..e2b42f603b1a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -204,17 +204,18 @@ static void __free_pages_ok(struct page *page, unsigned int order);
  * TBD: should special case ZONE_DMA32 machines here - in those we normally
  * don't need any ZONE_NORMAL reservation
  */
-int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = {
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES] = {
 #ifdef CONFIG_ZONE_DMA
-	 256,
+	[ZONE_DMA] = 256,
 #endif
 #ifdef CONFIG_ZONE_DMA32
-	 256,
+	[ZONE_DMA32] = 256,
 #endif
+	[ZONE_NORMAL] = 32,
 #ifdef CONFIG_HIGHMEM
-	 32,
+	[ZONE_HIGHMEM] = 0,
 #endif
-	 32,
+	[ZONE_MOVABLE] = 0,
 };
 
 EXPORT_SYMBOL(totalram_pages);
@@ -1635,16 +1636,38 @@ void __init page_alloc_init_late(void)
 }
 
 #ifdef CONFIG_CMA
+static void __init adjust_present_page_count(struct page *page, long count)
+{
+	struct zone *zone = page_zone(page);
+
+	/* We don't need to hold a lock since it is boot-up process */
+	zone->present_pages += count;
+}
+
 /* Free whole pageblock and set its migration type to MIGRATE_CMA. */
 void __init init_cma_reserved_pageblock(struct page *page)
 {
 	unsigned i = pageblock_nr_pages;
+	unsigned long pfn = page_to_pfn(page);
 	struct page *p = page;
+	int nid = page_to_nid(page);
+
+	/*
+	 * ZONE_MOVABLE will steal present pages from other zones by
+	 * changing page links so page_zone() is changed. Before that,
+	 * we need to adjust previous zone's page count first.
+	 */
+	adjust_present_page_count(page, -pageblock_nr_pages);
 
 	do {
 		__ClearPageReserved(p);
 		set_page_count(p, 0);
-	} while (++p, --i);
+
+		/* Steal pages from other zones */
+		set_page_links(p, ZONE_MOVABLE, nid, pfn);
+	} while (++p, ++pfn, --i);
+
+	adjust_present_page_count(page, pageblock_nr_pages);
 
 	set_pageblock_migratetype(page, MIGRATE_CMA);
 
@@ -2762,7 +2785,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
 		 * exists.
 		 */
 		watermark = min_wmark_pages(zone) + (1UL << order);
-		if (!zone_watermark_ok(zone, 0, watermark, 0, ALLOC_CMA))
+		if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
 			return 0;
 
 		__mod_zone_freepage_state(zone, -(1UL << order), mt);
@@ -3038,12 +3061,6 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
 	}
 
 
-#ifdef CONFIG_CMA
-	/* If allocation can't use CMA areas don't use free CMA pages */
-	if (!(alloc_flags & ALLOC_CMA))
-		free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES);
-#endif
-
 	/*
 	 * Check watermarks for an order-0 allocation request. If these
 	 * are not met, then a high-order request also cannot go ahead
@@ -3070,10 +3087,8 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
 		}
 
 #ifdef CONFIG_CMA
-		if ((alloc_flags & ALLOC_CMA) &&
-		    !list_empty(&area->free_list[MIGRATE_CMA])) {
+		if (!list_empty(&area->free_list[MIGRATE_CMA]))
 			return true;
-		}
 #endif
 		if (alloc_harder &&
 			!list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
@@ -3093,13 +3108,6 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,
 		unsigned long mark, int classzone_idx, unsigned int alloc_flags)
 {
 	long free_pages = zone_page_state(z, NR_FREE_PAGES);
-	long cma_pages = 0;
-
-#ifdef CONFIG_CMA
-	/* If allocation can't use CMA areas don't use free CMA pages */
-	if (!(alloc_flags & ALLOC_CMA))
-		cma_pages = zone_page_state(z, NR_FREE_CMA_PAGES);
-#endif
 
 	/*
 	 * Fast check for order-0 only. If this fails then the reserves
@@ -3108,7 +3116,7 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,
 	 * the caller is !atomic then it'll uselessly search the free
 	 * list. That corner case is then slower but it is harmless.
 	 */
-	if (!order && (free_pages - cma_pages) > mark + z->lowmem_reserve[classzone_idx])
+	if (!order && free_pages > mark + z->lowmem_reserve[classzone_idx])
 		return true;
 
 	return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
@@ -3724,10 +3732,6 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
 	} else if (unlikely(rt_task(current)) && !in_interrupt())
 		alloc_flags |= ALLOC_HARDER;
 
-#ifdef CONFIG_CMA
-	if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
-		alloc_flags |= ALLOC_CMA;
-#endif
 	return alloc_flags;
 }
 
@@ -4194,9 +4198,6 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,
 	if (should_fail_alloc_page(gfp_mask, order))
 		return false;
 
-	if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE)
-		*alloc_flags |= ALLOC_CMA;
-
 	return true;
 }
 
@@ -6082,6 +6083,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
 {
 	enum zone_type j;
 	int nid = pgdat->node_id;
+	unsigned long node_end_pfn = 0;
 
 	pgdat_resize_init(pgdat);
 #ifdef CONFIG_NUMA_BALANCING
@@ -6109,9 +6111,13 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
 		struct zone *zone = pgdat->node_zones + j;
 		unsigned long size, realsize, freesize, memmap_pages;
 		unsigned long zone_start_pfn = zone->zone_start_pfn;
+		unsigned long movable_size = 0;
 
 		size = zone->spanned_pages;
 		realsize = freesize = zone->present_pages;
+		if (zone_end_pfn(zone) > node_end_pfn)
+			node_end_pfn = zone_end_pfn(zone);
+
 
 		/*
 		 * Adjust freesize so that it accounts for how much memory
@@ -6160,12 +6166,30 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
 		zone_seqlock_init(zone);
 		zone_pcp_init(zone);
 
-		if (!size)
+		/*
+		 * The size of the CMA area is unknown now so we need to
+		 * prepare the memory for the usemap at maximum.
+		 */
+		if (IS_ENABLED(CONFIG_CMA) && j == ZONE_MOVABLE &&
+			pgdat->node_spanned_pages) {
+			movable_size = node_end_pfn - pgdat->node_start_pfn;
+		}
+
+		if (!size && !movable_size)
 			continue;
 
 		set_pageblock_order();
-		setup_usemap(pgdat, zone, zone_start_pfn, size);
-		init_currently_empty_zone(zone, zone_start_pfn, size);
+		if (movable_size) {
+			zone->zone_start_pfn = pgdat->node_start_pfn;
+			zone->spanned_pages = movable_size;
+			setup_usemap(pgdat, zone,
+				pgdat->node_start_pfn, movable_size);
+			init_currently_empty_zone(zone,
+				pgdat->node_start_pfn, movable_size);
+		} else {
+			setup_usemap(pgdat, zone, zone_start_pfn, size);
+			init_currently_empty_zone(zone, zone_start_pfn, size);
+		}
 		memmap_init(size, nid, j, zone_start_pfn);
 	}
 }
@@ -6977,13 +7001,15 @@ static void setup_per_zone_lowmem_reserve(void)
 				struct zone *lower_zone;
 
 				idx--;
-
-				if (sysctl_lowmem_reserve_ratio[idx] < 1)
-					sysctl_lowmem_reserve_ratio[idx] = 1;
-
 				lower_zone = pgdat->node_zones + idx;
-				lower_zone->lowmem_reserve[j] = managed_pages /
-					sysctl_lowmem_reserve_ratio[idx];
+
+				if (sysctl_lowmem_reserve_ratio[idx] < 1) {
+					sysctl_lowmem_reserve_ratio[idx] = 0;
+					lower_zone->lowmem_reserve[j] = 0;
+				} else {
+					lower_zone->lowmem_reserve[j] =
+						managed_pages / sysctl_lowmem_reserve_ratio[idx];
+				}
 				managed_pages += lower_zone->managed_pages;
 			}
 		}
@@ -7774,7 +7800,7 @@ void free_contig_range(unsigned long pfn, unsigned nr_pages)
 }
 #endif
 
-#ifdef CONFIG_MEMORY_HOTPLUG
+#if defined CONFIG_MEMORY_HOTPLUG || defined CONFIG_CMA
 /*
  * The zone indicated has a new number of managed_pages; batch sizes and percpu
  * page high values need to be recalulated.
diff --git a/mm/page_io.c b/mm/page_io.c
index b41cf9644585..6dca817ae7a0 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -250,7 +250,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
 		unlock_page(page);
 		goto out;
 	}
-	if (frontswap_store(page) == 0) {
+	if (!PageTransHuge(page) && frontswap_store(page) == 0) {
 		set_page_writeback(page);
 		unlock_page(page);
 		end_page_writeback(page);
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 165ed8117bd1..53d801235e22 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -293,8 +293,7 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
 	return pfn < end_pfn ? -EBUSY : 0;
 }
 
-struct page *alloc_migrate_target(struct page *page, unsigned long private,
-				  int **resultp)
+struct page *alloc_migrate_target(struct page *page, unsigned long private)
 {
 	return new_page_nodemask(page, numa_node_id(), &node_states[N_MEMORY]);
 }
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 9886c6073828..5881468f4253 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -274,7 +274,7 @@ void pagetypeinfo_showmixedcount_print(struct seq_file *m,
 	 */
 	for (; pfn < end_pfn; ) {
 		if (!pfn_valid(pfn)) {
-			pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
+			pfn = ALIGN(pfn + 1, pageblock_nr_pages);
 			continue;
 		}
 
@@ -541,7 +541,7 @@ static void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone)
 		unsigned long block_end_pfn;
 
 		if (!pfn_valid(pfn)) {
-			pfn = ALIGN(pfn + 1, MAX_ORDER_NR_PAGES);
+			pfn = ALIGN(pfn + 1, pageblock_nr_pages);
 			continue;
 		}
 
diff --git a/mm/percpu-km.c b/mm/percpu-km.c
index d2a76642c4ae..38de70ab1a0d 100644
--- a/mm/percpu-km.c
+++ b/mm/percpu-km.c
@@ -34,7 +34,7 @@
 #include <linux/log2.h>
 
 static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
-			       int page_start, int page_end)
+			       int page_start, int page_end, gfp_t gfp)
 {
 	return 0;
 }
@@ -45,18 +45,18 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
 	/* nada */
 }
 
-static struct pcpu_chunk *pcpu_create_chunk(void)
+static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
 {
 	const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT;
 	struct pcpu_chunk *chunk;
 	struct page *pages;
 	int i;
 
-	chunk = pcpu_alloc_chunk();
+	chunk = pcpu_alloc_chunk(gfp);
 	if (!chunk)
 		return NULL;
 
-	pages = alloc_pages(GFP_KERNEL, order_base_2(nr_pages));
+	pages = alloc_pages(gfp, order_base_2(nr_pages));
 	if (!pages) {
 		pcpu_free_chunk(chunk);
 		return NULL;
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c
index 9158e5a81391..d8078de912de 100644
--- a/mm/percpu-vm.c
+++ b/mm/percpu-vm.c
@@ -37,7 +37,7 @@ static struct page **pcpu_get_pages(void)
 	lockdep_assert_held(&pcpu_alloc_mutex);
 
 	if (!pages)
-		pages = pcpu_mem_zalloc(pages_size);
+		pages = pcpu_mem_zalloc(pages_size, GFP_KERNEL);
 	return pages;
 }
 
@@ -73,18 +73,21 @@ static void pcpu_free_pages(struct pcpu_chunk *chunk,
  * @pages: array to put the allocated pages into, indexed by pcpu_page_idx()
  * @page_start: page index of the first page to be allocated
  * @page_end: page index of the last page to be allocated + 1
+ * @gfp: allocation flags passed to the underlying allocator
  *
  * Allocate pages [@page_start,@page_end) into @pages for all units.
  * The allocation is for @chunk.  Percpu core doesn't care about the
  * content of @pages and will pass it verbatim to pcpu_map_pages().
  */
 static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
-			    struct page **pages, int page_start, int page_end)
+			    struct page **pages, int page_start, int page_end,
+			    gfp_t gfp)
 {
-	const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM;
 	unsigned int cpu, tcpu;
 	int i;
 
+	gfp |= __GFP_HIGHMEM;
+
 	for_each_possible_cpu(cpu) {
 		for (i = page_start; i < page_end; i++) {
 			struct page **pagep = &pages[pcpu_page_idx(cpu, i)];
@@ -262,6 +265,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
  * @chunk: chunk of interest
  * @page_start: the start page
  * @page_end: the end page
+ * @gfp: allocation flags passed to the underlying memory allocator
  *
  * For each cpu, populate and map pages [@page_start,@page_end) into
  * @chunk.
@@ -270,7 +274,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
  * pcpu_alloc_mutex, does GFP_KERNEL allocation.
  */
 static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
-			       int page_start, int page_end)
+			       int page_start, int page_end, gfp_t gfp)
 {
 	struct page **pages;
 
@@ -278,7 +282,7 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
 	if (!pages)
 		return -ENOMEM;
 
-	if (pcpu_alloc_pages(chunk, pages, page_start, page_end))
+	if (pcpu_alloc_pages(chunk, pages, page_start, page_end, gfp))
 		return -ENOMEM;
 
 	if (pcpu_map_pages(chunk, pages, page_start, page_end)) {
@@ -325,12 +329,12 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
 	pcpu_free_pages(chunk, pages, page_start, page_end);
 }
 
-static struct pcpu_chunk *pcpu_create_chunk(void)
+static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
 {
 	struct pcpu_chunk *chunk;
 	struct vm_struct **vms;
 
-	chunk = pcpu_alloc_chunk();
+	chunk = pcpu_alloc_chunk(gfp);
 	if (!chunk)
 		return NULL;
 
diff --git a/mm/percpu.c b/mm/percpu.c
index 50e7fdf84055..fa3f854634a1 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -447,26 +447,25 @@ static void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits,
 /**
  * pcpu_mem_zalloc - allocate memory
  * @size: bytes to allocate
+ * @gfp: allocation flags
  *
  * Allocate @size bytes.  If @size is smaller than PAGE_SIZE,
- * kzalloc() is used; otherwise, vzalloc() is used.  The returned
- * memory is always zeroed.
- *
- * CONTEXT:
- * Does GFP_KERNEL allocation.
+ * kzalloc() is used; otherwise, the equivalent of vzalloc() is used.
+ * This is to facilitate passing through whitelisted flags.  The
+ * returned memory is always zeroed.
  *
  * RETURNS:
  * Pointer to the allocated area on success, NULL on failure.
  */
-static void *pcpu_mem_zalloc(size_t size)
+static void *pcpu_mem_zalloc(size_t size, gfp_t gfp)
 {
 	if (WARN_ON_ONCE(!slab_is_available()))
 		return NULL;
 
 	if (size <= PAGE_SIZE)
-		return kzalloc(size, GFP_KERNEL);
+		return kzalloc(size, gfp);
 	else
-		return vzalloc(size);
+		return __vmalloc(size, gfp | __GFP_ZERO, PAGE_KERNEL);
 }
 
 /**
@@ -1154,12 +1153,12 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
 	return chunk;
 }
 
-static struct pcpu_chunk *pcpu_alloc_chunk(void)
+static struct pcpu_chunk *pcpu_alloc_chunk(gfp_t gfp)
 {
 	struct pcpu_chunk *chunk;
 	int region_bits;
 
-	chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size);
+	chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size, gfp);
 	if (!chunk)
 		return NULL;
 
@@ -1168,17 +1167,17 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
 	region_bits = pcpu_chunk_map_bits(chunk);
 
 	chunk->alloc_map = pcpu_mem_zalloc(BITS_TO_LONGS(region_bits) *
-					   sizeof(chunk->alloc_map[0]));
+					   sizeof(chunk->alloc_map[0]), gfp);
 	if (!chunk->alloc_map)
 		goto alloc_map_fail;
 
 	chunk->bound_map = pcpu_mem_zalloc(BITS_TO_LONGS(region_bits + 1) *
-					   sizeof(chunk->bound_map[0]));
+					   sizeof(chunk->bound_map[0]), gfp);
 	if (!chunk->bound_map)
 		goto bound_map_fail;
 
 	chunk->md_blocks = pcpu_mem_zalloc(pcpu_chunk_nr_blocks(chunk) *
-					   sizeof(chunk->md_blocks[0]));
+					   sizeof(chunk->md_blocks[0]), gfp);
 	if (!chunk->md_blocks)
 		goto md_blocks_fail;
 
@@ -1277,9 +1276,11 @@ static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk,
  * pcpu_addr_to_page		- translate address to physical address
  * pcpu_verify_alloc_info	- check alloc_info is acceptable during init
  */
-static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size);
-static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size);
-static struct pcpu_chunk *pcpu_create_chunk(void);
+static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
+			       int page_start, int page_end, gfp_t gfp);
+static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
+				  int page_start, int page_end);
+static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp);
 static void pcpu_destroy_chunk(struct pcpu_chunk *chunk);
 static struct page *pcpu_addr_to_page(void *addr);
 static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai);
@@ -1339,6 +1340,8 @@ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
 static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
 				 gfp_t gfp)
 {
+	/* whitelisted flags that can be passed to the backing allocators */
+	gfp_t pcpu_gfp = gfp & (GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
 	bool is_atomic = (gfp & GFP_KERNEL) != GFP_KERNEL;
 	bool do_warn = !(gfp & __GFP_NOWARN);
 	static int warn_limit = 10;
@@ -1421,7 +1424,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
 	}
 
 	if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) {
-		chunk = pcpu_create_chunk();
+		chunk = pcpu_create_chunk(pcpu_gfp);
 		if (!chunk) {
 			err = "failed to allocate new chunk";
 			goto fail;
@@ -1450,7 +1453,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
 					   page_start, page_end) {
 			WARN_ON(chunk->immutable);
 
-			ret = pcpu_populate_chunk(chunk, rs, re);
+			ret = pcpu_populate_chunk(chunk, rs, re, pcpu_gfp);
 
 			spin_lock_irqsave(&pcpu_lock, flags);
 			if (ret) {
@@ -1561,10 +1564,17 @@ void __percpu *__alloc_reserved_percpu(size_t size, size_t align)
  * pcpu_balance_workfn - manage the amount of free chunks and populated pages
  * @work: unused
  *
- * Reclaim all fully free chunks except for the first one.
+ * Reclaim all fully free chunks except for the first one.  This is also
+ * responsible for maintaining the pool of empty populated pages.  However,
+ * it is possible that this is called when physical memory is scarce causing
+ * OOM killer to be triggered.  We should avoid doing so until an actual
+ * allocation causes the failure as it is possible that requests can be
+ * serviced from already backed regions.
  */
 static void pcpu_balance_workfn(struct work_struct *work)
 {
+	/* gfp flags passed to underlying allocators */
+	const gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
 	LIST_HEAD(to_free);
 	struct list_head *free_head = &pcpu_slot[pcpu_nr_slots - 1];
 	struct pcpu_chunk *chunk, *next;
@@ -1645,7 +1655,7 @@ static void pcpu_balance_workfn(struct work_struct *work)
 					   chunk->nr_pages) {
 			int nr = min(re - rs, nr_to_pop);
 
-			ret = pcpu_populate_chunk(chunk, rs, rs + nr);
+			ret = pcpu_populate_chunk(chunk, rs, rs + nr, gfp);
 			if (!ret) {
 				nr_to_pop -= nr;
 				spin_lock_irq(&pcpu_lock);
@@ -1662,7 +1672,7 @@ static void pcpu_balance_workfn(struct work_struct *work)
 
 	if (nr_to_pop) {
 		/* ran out of chunks to populate, create a new one and retry */
-		chunk = pcpu_create_chunk();
+		chunk = pcpu_create_chunk(gfp);
 		if (chunk) {
 			spin_lock_irq(&pcpu_lock);
 			pcpu_chunk_relocate(chunk, -1);
diff --git a/mm/swap.c b/mm/swap.c
index 567a7b96e41d..2d337710218f 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -445,30 +445,6 @@ void lru_cache_add(struct page *page)
 	__lru_cache_add(page);
 }
 
-/**
- * add_page_to_unevictable_list - add a page to the unevictable list
- * @page:  the page to be added to the unevictable list
- *
- * Add page directly to its zone's unevictable list.  To avoid races with
- * tasks that might be making the page evictable, through eg. munlock,
- * munmap or exit, while it's not on the lru, we want to add the page
- * while it's locked or otherwise "invisible" to other tasks.  This is
- * difficult to do when using the pagevec cache, so bypass that.
- */
-void add_page_to_unevictable_list(struct page *page)
-{
-	struct pglist_data *pgdat = page_pgdat(page);
-	struct lruvec *lruvec;
-
-	spin_lock_irq(&pgdat->lru_lock);
-	lruvec = mem_cgroup_page_lruvec(page, pgdat);
-	ClearPageActive(page);
-	SetPageUnevictable(page);
-	SetPageLRU(page);
-	add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
-	spin_unlock_irq(&pgdat->lru_lock);
-}
-
 /**
  * lru_cache_add_active_or_unevictable
  * @page:  the page to be added to LRU
@@ -484,13 +460,9 @@ void lru_cache_add_active_or_unevictable(struct page *page,
 {
 	VM_BUG_ON_PAGE(PageLRU(page), page);
 
-	if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED)) {
+	if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED))
 		SetPageActive(page);
-		lru_cache_add(page);
-		return;
-	}
-
-	if (!TestSetPageMlocked(page)) {
+	else if (!TestSetPageMlocked(page)) {
 		/*
 		 * We use the irq-unsafe __mod_zone_page_stat because this
 		 * counter is not modified from interrupt context, and the pte
@@ -500,7 +472,7 @@ void lru_cache_add_active_or_unevictable(struct page *page,
 				    hpage_nr_pages(page));
 		count_vm_event(UNEVICTABLE_PGMLOCKED);
 	}
-	add_page_to_unevictable_list(page);
+	lru_cache_add(page);
 }
 
 /*
@@ -886,15 +858,55 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
 static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
 				 void *arg)
 {
-	int file = page_is_file_cache(page);
-	int active = PageActive(page);
-	enum lru_list lru = page_lru(page);
+	enum lru_list lru;
+	int was_unevictable = TestClearPageUnevictable(page);
 
 	VM_BUG_ON_PAGE(PageLRU(page), page);
 
 	SetPageLRU(page);
+	/*
+	 * Page becomes evictable in two ways:
+	 * 1) Within LRU lock [munlock_vma_pages() and __munlock_pagevec()].
+	 * 2) Before acquiring LRU lock to put the page to correct LRU and then
+	 *   a) do PageLRU check with lock [check_move_unevictable_pages]
+	 *   b) do PageLRU check before lock [clear_page_mlock]
+	 *
+	 * (1) & (2a) are ok as LRU lock will serialize them. For (2b), we need
+	 * following strict ordering:
+	 *
+	 * #0: __pagevec_lru_add_fn		#1: clear_page_mlock
+	 *
+	 * SetPageLRU()				TestClearPageMlocked()
+	 * smp_mb() // explicit ordering	// above provides strict
+	 *					// ordering
+	 * PageMlocked()			PageLRU()
+	 *
+	 *
+	 * if '#1' does not observe setting of PG_lru by '#0' and fails
+	 * isolation, the explicit barrier will make sure that page_evictable
+	 * check will put the page in correct LRU. Without smp_mb(), SetPageLRU
+	 * can be reordered after PageMlocked check and can make '#1' to fail
+	 * the isolation of the page whose Mlocked bit is cleared (#0 is also
+	 * looking at the same page) and the evictable page will be stranded
+	 * in an unevictable LRU.
+	 */
+	smp_mb();
+
+	if (page_evictable(page)) {
+		lru = page_lru(page);
+		update_page_reclaim_stat(lruvec, page_is_file_cache(page),
+					 PageActive(page));
+		if (was_unevictable)
+			count_vm_event(UNEVICTABLE_PGRESCUED);
+	} else {
+		lru = LRU_UNEVICTABLE;
+		ClearPageActive(page);
+		SetPageUnevictable(page);
+		if (!was_unevictable)
+			count_vm_event(UNEVICTABLE_PGCULLED);
+	}
+
 	add_page_to_lru_list(page, lruvec, lru);
-	update_page_reclaim_stat(lruvec, file, active);
 	trace_mm_lru_insertion(page, lru);
 }
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
index c7a33717d079..902c1df5564d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -85,7 +85,7 @@ PLIST_HEAD(swap_active_head);
  * is held and the locking order requires swap_lock to be taken
  * before any swap_info_struct->lock.
  */
-struct plist_head *swap_avail_heads;
+static struct plist_head *swap_avail_heads;
 static DEFINE_SPINLOCK(swap_avail_lock);
 
 struct swap_info_struct *swap_info[MAX_SWAPFILES];
@@ -1800,8 +1800,6 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 	dec_mm_counter(vma->vm_mm, MM_SWAPENTS);
 	inc_mm_counter(vma->vm_mm, MM_ANONPAGES);
 	get_page(page);
-	set_pte_at(vma->vm_mm, addr, pte,
-		   pte_mkold(mk_pte(page, vma->vm_page_prot)));
 	if (page == swapcache) {
 		page_add_anon_rmap(page, vma, addr, false);
 		mem_cgroup_commit_charge(page, memcg, true, false);
@@ -1810,6 +1808,8 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 		mem_cgroup_commit_charge(page, memcg, false, false);
 		lru_cache_add_active_or_unevictable(page, vma);
 	}
+	set_pte_at(vma->vm_mm, addr, pte,
+		   pte_mkold(mk_pte(page, vma->vm_page_prot)));
 	swap_free(entry);
 	/*
 	 * Move the page to the active list so it is not
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 444749669187..d1c1e00b08bb 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -55,6 +55,7 @@
 
 #include <linux/swapops.h>
 #include <linux/balloon_compaction.h>
+#include <linux/frontswap.h>
 
 #include "internal.h"
 
@@ -769,64 +770,7 @@ int remove_mapping(struct address_space *mapping, struct page *page)
  */
 void putback_lru_page(struct page *page)
 {
-	bool is_unevictable;
-	int was_unevictable = PageUnevictable(page);
-
-	VM_BUG_ON_PAGE(PageLRU(page), page);
-
-redo:
-	ClearPageUnevictable(page);
-
-	if (page_evictable(page)) {
-		/*
-		 * For evictable pages, we can use the cache.
-		 * In event of a race, worst case is we end up with an
-		 * unevictable page on [in]active list.
-		 * We know how to handle that.
-		 */
-		is_unevictable = false;
-		lru_cache_add(page);
-	} else {
-		/*
-		 * Put unevictable pages directly on zone's unevictable
-		 * list.
-		 */
-		is_unevictable = true;
-		add_page_to_unevictable_list(page);
-		/*
-		 * When racing with an mlock or AS_UNEVICTABLE clearing
-		 * (page is unlocked) make sure that if the other thread
-		 * does not observe our setting of PG_lru and fails
-		 * isolation/check_move_unevictable_pages,
-		 * we see PG_mlocked/AS_UNEVICTABLE cleared below and move
-		 * the page back to the evictable list.
-		 *
-		 * The other side is TestClearPageMlocked() or shmem_lock().
-		 */
-		smp_mb();
-	}
-
-	/*
-	 * page's status can change while we move it among lru. If an evictable
-	 * page is on unevictable list, it never be freed. To avoid that,
-	 * check after we added it to the list, again.
-	 */
-	if (is_unevictable && page_evictable(page)) {
-		if (!isolate_lru_page(page)) {
-			put_page(page);
-			goto redo;
-		}
-		/* This means someone else dropped this page from LRU
-		 * So, it will be freed or putback to LRU again. There is
-		 * nothing to do here.
-		 */
-	}
-
-	if (was_unevictable && !is_unevictable)
-		count_vm_event(UNEVICTABLE_PGRESCUED);
-	else if (!was_unevictable && is_unevictable)
-		count_vm_event(UNEVICTABLE_PGCULLED);
-
+	lru_cache_add(page);
 	put_page(page);		/* drop ref from isolate */
 }
 
@@ -1120,14 +1064,23 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 					/* cannot split THP, skip it */
 					if (!can_split_huge_page(page, NULL))
 						goto activate_locked;
+					/*
+					 * Split THP if frontswap enabled,
+					 * because it cannot process THP
+					 */
+					if (frontswap_enabled()) {
+						if (split_huge_page_to_list(
+							page, page_list))
+							goto activate_locked;
+					}
 					/*
 					 * Split pages without a PMD map right
 					 * away. Chances are some or all of the
 					 * tail pages can be freed without IO.
 					 */
-					if (!compound_mapcount(page) &&
-					    split_huge_page_to_list(page,
-								    page_list))
+					else if (!compound_mapcount(page) &&
+						 split_huge_page_to_list(page,
+							page_list))
 						goto activate_locked;
 				}
 				if (!add_to_swap(page)) {
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index c3013505c305..b7f61cd1c709 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -84,18 +84,19 @@
  * This is made more complicated by various memory models and PAE.
  */
 
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
+#ifndef MAX_POSSIBLE_PHYSMEM_BITS
+#ifdef MAX_PHYSMEM_BITS
+#define MAX_POSSIBLE_PHYSMEM_BITS MAX_PHYSMEM_BITS
+#else
 /*
  * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
  * be PAGE_SHIFT
  */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#define MAX_POSSIBLE_PHYSMEM_BITS BITS_PER_LONG
 #endif
 #endif
-#define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
+
+#define _PFN_BITS		(MAX_POSSIBLE_PHYSMEM_BITS - PAGE_SHIFT)
 
 /*
  * Memory for allocating for handle keeps object position by
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 03a9fc0771c0..9b6bc5abe946 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1238,7 +1238,7 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
  * fields into the sockaddr.
  */
 static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
-			 int *uaddr_len, int peer)
+			 int peer)
 {
 	struct sockaddr_at sat;
 	struct sock *sk = sock->sk;
@@ -1251,7 +1251,6 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
 		if (atalk_autobind(sk) < 0)
 			goto out;
 
-	*uaddr_len = sizeof(struct sockaddr_at);
 	memset(&sat, 0, sizeof(sat));
 
 	if (peer) {
@@ -1268,9 +1267,9 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
 		sat.sat_port	    = at->src_port;
 	}
 
-	err = 0;
 	sat.sat_family = AF_APPLETALK;
 	memcpy(uaddr, &sat, sizeof(sat));
+	err = sizeof(struct sockaddr_at);
 
 out:
 	release_sock(sk);
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index e1140b3bdcaa..2cb10af16afc 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -87,21 +87,20 @@ static int pvc_getsockopt(struct socket *sock, int level, int optname,
 }
 
 static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr,
-		       int *sockaddr_len, int peer)
+		       int peer)
 {
 	struct sockaddr_atmpvc *addr;
 	struct atm_vcc *vcc = ATM_SD(sock);
 
 	if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
 		return -ENOTCONN;
-	*sockaddr_len = sizeof(struct sockaddr_atmpvc);
 	addr = (struct sockaddr_atmpvc *)sockaddr;
 	memset(addr, 0, sizeof(*addr));
 	addr->sap_family = AF_ATMPVC;
 	addr->sap_addr.itf = vcc->dev->number;
 	addr->sap_addr.vpi = vcc->vpi;
 	addr->sap_addr.vci = vcc->vci;
-	return 0;
+	return sizeof(struct sockaddr_atmpvc);
 }
 
 static const struct proto_ops pvc_proto_ops = {
diff --git a/net/atm/svc.c b/net/atm/svc.c
index c458adcbc177..2f91b766ac42 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -419,15 +419,14 @@ static int svc_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
-		       int *sockaddr_len, int peer)
+		       int peer)
 {
 	struct sockaddr_atmsvc *addr;
 
-	*sockaddr_len = sizeof(struct sockaddr_atmsvc);
 	addr = (struct sockaddr_atmsvc *) sockaddr;
 	memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
 	       sizeof(struct sockaddr_atmsvc));
-	return 0;
+	return sizeof(struct sockaddr_atmsvc);
 }
 
 int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 47fdd399626b..c8319ed48485 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1388,7 +1388,7 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
-	int *uaddr_len, int peer)
+	int peer)
 {
 	struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
 	struct sock *sk = sock->sk;
@@ -1427,7 +1427,7 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
 			fsa->fsa_digipeater[0] = null_ax25_address;
 		}
 	}
-	*uaddr_len = sizeof (struct full_sockaddr_ax25);
+	err = sizeof (struct full_sockaddr_ax25);
 
 out:
 	release_sock(sk);
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 3394e6791673..66c0781773df 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -934,8 +934,8 @@ static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
 		/* Slave connection state and connectable mode bit 38
 		 * and scannable bit 21.
 		 */
-		if (connectable && (!(hdev->le_states[4] & 0x01) ||
-				    !(hdev->le_states[2] & 0x40)))
+		if (connectable && (!(hdev->le_states[4] & 0x40) ||
+				    !(hdev->le_states[2] & 0x20)))
 			return false;
 	}
 
@@ -948,7 +948,7 @@ static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
 		/* Master connection state and connectable mode bit 35 and
 		 * scannable 19.
 		 */
-		if (connectable && (!(hdev->le_states[4] & 0x10) ||
+		if (connectable && (!(hdev->le_states[4] & 0x08) ||
 				    !(hdev->le_states[2] & 0x08)))
 			return false;
 	}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 923e9a271872..1506e1632394 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -1340,7 +1340,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
 }
 
 static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
-			    int *addr_len, int peer)
+			    int peer)
 {
 	struct sockaddr_hci *haddr = (struct sockaddr_hci *)addr;
 	struct sock *sk = sock->sk;
@@ -1360,10 +1360,10 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
 		goto done;
 	}
 
-	*addr_len = sizeof(*haddr);
 	haddr->hci_family = AF_BLUETOOTH;
 	haddr->hci_dev    = hdev->id;
 	haddr->hci_channel= hci_pi(sk)->channel;
+	err = sizeof(*haddr);
 
 done:
 	release_sock(sk);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 67a8642f57ea..686bdc6b35b0 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -358,7 +358,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
 }
 
 static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
-			      int *len, int peer)
+			      int peer)
 {
 	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
 	struct sock *sk = sock->sk;
@@ -373,7 +373,6 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
 
 	memset(la, 0, sizeof(struct sockaddr_l2));
 	addr->sa_family = AF_BLUETOOTH;
-	*len = sizeof(struct sockaddr_l2);
 
 	la->l2_psm = chan->psm;
 
@@ -387,7 +386,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
 		la->l2_bdaddr_type = chan->src_type;
 	}
 
-	return 0;
+	return sizeof(struct sockaddr_l2);
 }
 
 static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 1aaccf637479..93a3b219db09 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -533,7 +533,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
 	return err;
 }
 
-static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int peer)
 {
 	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
 	struct sock *sk = sock->sk;
@@ -552,8 +552,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
 	else
 		bacpy(&sa->rc_bdaddr, &rfcomm_pi(sk)->src);
 
-	*len = sizeof(struct sockaddr_rc);
-	return 0;
+	return sizeof(struct sockaddr_rc);
 }
 
 static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg,
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 08df57665e1f..413b8ee49fec 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -680,7 +680,7 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock,
 }
 
 static int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
-			    int *len, int peer)
+			    int peer)
 {
 	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
 	struct sock *sk = sock->sk;
@@ -688,14 +688,13 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
 	BT_DBG("sock %p, sk %p", sock, sk);
 
 	addr->sa_family = AF_BLUETOOTH;
-	*len = sizeof(struct sockaddr_sco);
 
 	if (peer)
 		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->dst);
 	else
 		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->src);
 
-	return 0;
+	return sizeof(struct sockaddr_sco);
 }
 
 static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg,
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 0254c35b2bf0..126a8ea73c96 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -255,6 +255,9 @@ static ssize_t brport_show(struct kobject *kobj,
 	struct brport_attribute *brport_attr = to_brport_attr(attr);
 	struct net_bridge_port *p = to_brport(kobj);
 
+	if (!brport_attr->show)
+		return -EINVAL;
+
 	return brport_attr->show(p, buf);
 }
 
diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
index 279527f8b1fe..ce7152a12bd8 100644
--- a/net/bridge/netfilter/ebt_among.c
+++ b/net/bridge/netfilter/ebt_among.c
@@ -187,17 +187,17 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 	expected_length += ebt_mac_wormhash_size(wh_src);
 
 	if (em->match_size != EBT_ALIGN(expected_length)) {
-		pr_info("wrong size: %d against expected %d, rounded to %zd\n",
-			em->match_size, expected_length,
-			EBT_ALIGN(expected_length));
+		pr_err_ratelimited("wrong size: %d against expected %d, rounded to %zd\n",
+				   em->match_size, expected_length,
+				   EBT_ALIGN(expected_length));
 		return -EINVAL;
 	}
 	if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
-		pr_info("dst integrity fail: %x\n", -err);
+		pr_err_ratelimited("dst integrity fail: %x\n", -err);
 		return -EINVAL;
 	}
 	if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
-		pr_info("src integrity fail: %x\n", -err);
+		pr_err_ratelimited("src integrity fail: %x\n", -err);
 		return -EINVAL;
 	}
 	return 0;
diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index 61a9f1be1263..165b9d678cf1 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -72,8 +72,8 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
 	/* Check for overflow. */
 	if (info->burst == 0 ||
 	    user2credits(info->avg * info->burst) < user2credits(info->avg)) {
-		pr_info("overflow, try lower: %u/%u\n",
-			info->avg, info->burst);
+		pr_info_ratelimited("overflow, try lower: %u/%u\n",
+				    info->avg, info->burst);
 		return -EINVAL;
 	}
 
diff --git a/net/can/raw.c b/net/can/raw.c
index f2ecc43376a1..1051eee82581 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -470,7 +470,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
 }
 
 static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
-		       int *len, int peer)
+		       int peer)
 {
 	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
 	struct sock *sk = sock->sk;
@@ -483,9 +483,7 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
 	addr->can_family  = AF_CAN;
 	addr->can_ifindex = ro->ifindex;
 
-	*len = sizeof(*addr);
-
-	return 0;
+	return sizeof(*addr);
 }
 
 static int raw_setsockopt(struct socket *sock, int level, int optname,
diff --git a/net/core/dev.c b/net/core/dev.c
index dda9d7b9a840..5bdcc5a161fe 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2382,8 +2382,11 @@ EXPORT_SYMBOL(netdev_set_num_tc);
  */
 int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
 {
+	bool disabling;
 	int rc;
 
+	disabling = txq < dev->real_num_tx_queues;
+
 	if (txq < 1 || txq > dev->num_tx_queues)
 		return -EINVAL;
 
@@ -2399,15 +2402,19 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
 		if (dev->num_tc)
 			netif_setup_tc(dev, txq);
 
-		if (txq < dev->real_num_tx_queues) {
+		dev->real_num_tx_queues = txq;
+
+		if (disabling) {
+			synchronize_net();
 			qdisc_reset_all_tx_gt(dev, txq);
 #ifdef CONFIG_XPS
 			netif_reset_xps_queues_gt(dev, txq);
 #endif
 		}
+	} else {
+		dev->real_num_tx_queues = txq;
 	}
 
-	dev->real_num_tx_queues = txq;
 	return 0;
 }
 EXPORT_SYMBOL(netif_set_real_num_tx_queues);
@@ -8134,8 +8141,9 @@ void netdev_run_todo(void)
 		BUG_ON(!list_empty(&dev->ptype_specific));
 		WARN_ON(rcu_access_pointer(dev->ip_ptr));
 		WARN_ON(rcu_access_pointer(dev->ip6_ptr));
+#if IS_ENABLED(CONFIG_DECNET)
 		WARN_ON(dev->dn_ptr);
-
+#endif
 		if (dev->priv_destructor)
 			dev->priv_destructor(dev);
 		if (dev->needs_free_netdev)
@@ -8833,6 +8841,7 @@ static void __net_exit netdev_exit(struct net *net)
 static struct pernet_operations __net_initdata netdev_net_ops = {
 	.init = netdev_init,
 	.exit = netdev_exit,
+	.async = true,
 };
 
 static void __net_exit default_device_exit(struct net *net)
@@ -8933,6 +8942,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
 static struct pernet_operations __net_initdata default_device_ops = {
 	.exit = default_device_exit,
 	.exit_batch = default_device_exit_batch,
+	.async = true,
 };
 
 /*
diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 0c048bdeb016..5ace0705a3f9 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -171,6 +171,7 @@ static void __net_exit fib_notifier_net_exit(struct net *net)
 static struct pernet_operations fib_notifier_net_ops = {
 	.init = fib_notifier_net_init,
 	.exit = fib_notifier_net_exit,
+	.async = true,
 };
 
 static int __init fib_notifier_init(void)
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 98e1066c3d55..cb071b8e8d17 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1030,6 +1030,7 @@ static void __net_exit fib_rules_net_exit(struct net *net)
 static struct pernet_operations fib_rules_net_ops = {
 	.init = fib_rules_net_init,
 	.exit = fib_rules_net_exit,
+	.async = true,
 };
 
 static int __init fib_rules_init(void)
diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c
index e010bb800d7b..65b51e778782 100644
--- a/net/core/net-procfs.c
+++ b/net/core/net-procfs.c
@@ -349,6 +349,7 @@ static void __net_exit dev_proc_net_exit(struct net *net)
 static struct pernet_operations __net_initdata dev_proc_ops = {
 	.init = dev_proc_net_init,
 	.exit = dev_proc_net_exit,
+	.async = true,
 };
 
 static int dev_mc_seq_show(struct seq_file *seq, void *v)
@@ -405,6 +406,7 @@ static void __net_exit dev_mc_net_exit(struct net *net)
 static struct pernet_operations __net_initdata dev_mc_net_ops = {
 	.init = dev_mc_net_init,
 	.exit = dev_mc_net_exit,
+	.async = true,
 };
 
 int __init dev_proc_init(void)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3cad5f51afd3..bcab9a938d6f 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -29,6 +29,7 @@
 
 static LIST_HEAD(pernet_list);
 static struct list_head *first_device = &pernet_list;
+/* Used only if there are !async pernet_operations registered */
 DEFINE_MUTEX(net_mutex);
 
 LIST_HEAD(net_namespace_list);
@@ -41,6 +42,12 @@ struct net init_net = {
 EXPORT_SYMBOL(init_net);
 
 static bool init_net_initialized;
+static unsigned nr_sync_pernet_ops;
+/*
+ * net_sem: protects: pernet_list, net_generic_ids, nr_sync_pernet_ops,
+ * init_net_initialized and first_device pointer.
+ */
+DECLARE_RWSEM(net_sem);
 
 #define MIN_PERNET_OPS_ID	\
 	((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *))
@@ -65,11 +72,10 @@ static int net_assign_generic(struct net *net, unsigned int id, void *data)
 {
 	struct net_generic *ng, *old_ng;
 
-	BUG_ON(!mutex_is_locked(&net_mutex));
 	BUG_ON(id < MIN_PERNET_OPS_ID);
 
 	old_ng = rcu_dereference_protected(net->gen,
-					   lockdep_is_held(&net_mutex));
+					   lockdep_is_held(&net_sem));
 	if (old_ng->s.len > id) {
 		old_ng->ptr[id] = data;
 		return 0;
@@ -286,7 +292,7 @@ struct net *get_net_ns_by_id(struct net *net, int id)
  */
 static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
 {
-	/* Must be called with net_mutex held */
+	/* Must be called with net_sem held */
 	const struct pernet_operations *ops, *saved_ops;
 	int error = 0;
 	LIST_HEAD(net_exit_list);
@@ -303,6 +309,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
 		if (error < 0)
 			goto out_undo;
 	}
+	rtnl_lock();
+	list_add_tail_rcu(&net->list, &net_namespace_list);
+	rtnl_unlock();
 out:
 	return error;
 
@@ -331,6 +340,7 @@ static int __net_init net_defaults_init_net(struct net *net)
 
 static struct pernet_operations net_defaults_ops = {
 	.init = net_defaults_init_net,
+	.async = true,
 };
 
 static __init int net_defaults_init(void)
@@ -408,32 +418,32 @@ struct net *copy_net_ns(unsigned long flags,
 
 	net = net_alloc();
 	if (!net) {
-		dec_net_namespaces(ucounts);
-		return ERR_PTR(-ENOMEM);
+		rv = -ENOMEM;
+		goto dec_ucounts;
 	}
-
+	refcount_set(&net->passive, 1);
+	net->ucounts = ucounts;
 	get_user_ns(user_ns);
 
-	rv = mutex_lock_killable(&net_mutex);
-	if (rv < 0) {
-		net_free(net);
-		dec_net_namespaces(ucounts);
-		put_user_ns(user_ns);
-		return ERR_PTR(rv);
+	rv = down_read_killable(&net_sem);
+	if (rv < 0)
+		goto put_userns;
+	if (nr_sync_pernet_ops) {
+		rv = mutex_lock_killable(&net_mutex);
+		if (rv < 0)
+			goto up_read;
 	}
-
-	net->ucounts = ucounts;
 	rv = setup_net(net, user_ns);
-	if (rv == 0) {
-		rtnl_lock();
-		list_add_tail_rcu(&net->list, &net_namespace_list);
-		rtnl_unlock();
-	}
-	mutex_unlock(&net_mutex);
+	if (nr_sync_pernet_ops)
+		mutex_unlock(&net_mutex);
+up_read:
+	up_read(&net_sem);
 	if (rv < 0) {
-		dec_net_namespaces(ucounts);
+put_userns:
 		put_user_ns(user_ns);
 		net_drop_ns(net);
+dec_ucounts:
+		dec_net_namespaces(ucounts);
 		return ERR_PTR(rv);
 	}
 	return net;
@@ -481,7 +491,9 @@ static void cleanup_net(struct work_struct *work)
 	list_replace_init(&cleanup_list, &net_kill_list);
 	spin_unlock_irq(&cleanup_list_lock);
 
-	mutex_lock(&net_mutex);
+	down_read(&net_sem);
+	if (nr_sync_pernet_ops)
+		mutex_lock(&net_mutex);
 
 	/* Don't let anyone else find us. */
 	rtnl_lock();
@@ -516,11 +528,14 @@ static void cleanup_net(struct work_struct *work)
 	list_for_each_entry_reverse(ops, &pernet_list, list)
 		ops_exit_list(ops, &net_exit_list);
 
+	if (nr_sync_pernet_ops)
+		mutex_unlock(&net_mutex);
+
 	/* Free the net generic variables */
 	list_for_each_entry_reverse(ops, &pernet_list, list)
 		ops_free_list(ops, &net_exit_list);
 
-	mutex_unlock(&net_mutex);
+	up_read(&net_sem);
 
 	/* Ensure there are no outstanding rcu callbacks using this
 	 * network namespace.
@@ -547,8 +562,10 @@ static void cleanup_net(struct work_struct *work)
  */
 void net_ns_barrier(void)
 {
+	down_write(&net_sem);
 	mutex_lock(&net_mutex);
 	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL(net_ns_barrier);
 
@@ -633,6 +650,7 @@ static __net_exit void net_ns_net_exit(struct net *net)
 static struct pernet_operations __net_initdata net_ns_ops = {
 	.init = net_ns_net_init,
 	.exit = net_ns_net_exit,
+	.async = true,
 };
 
 static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
@@ -875,17 +893,12 @@ static int __init net_ns_init(void)
 
 	rcu_assign_pointer(init_net.gen, ng);
 
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	if (setup_net(&init_net, &init_user_ns))
 		panic("Could not setup the initial network namespace");
 
 	init_net_initialized = true;
-
-	rtnl_lock();
-	list_add_tail_rcu(&init_net.list, &net_namespace_list);
-	rtnl_unlock();
-
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 
 	register_pernet_subsys(&net_ns_ops);
 
@@ -989,6 +1002,9 @@ static int register_pernet_operations(struct list_head *list,
 		rcu_barrier();
 		if (ops->id)
 			ida_remove(&net_generic_ids, *ops->id);
+	} else if (!ops->async) {
+		pr_info_once("Pernet operations %ps are sync.\n", ops);
+		nr_sync_pernet_ops++;
 	}
 
 	return error;
@@ -996,7 +1012,8 @@ static int register_pernet_operations(struct list_head *list,
 
 static void unregister_pernet_operations(struct pernet_operations *ops)
 {
-	
+	if (!ops->async)
+		BUG_ON(nr_sync_pernet_ops-- == 0);
 	__unregister_pernet_operations(ops);
 	rcu_barrier();
 	if (ops->id)
@@ -1025,9 +1042,9 @@ static void unregister_pernet_operations(struct pernet_operations *ops)
 int register_pernet_subsys(struct pernet_operations *ops)
 {
 	int error;
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	error =  register_pernet_operations(first_device, ops);
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 	return error;
 }
 EXPORT_SYMBOL_GPL(register_pernet_subsys);
@@ -1043,9 +1060,9 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys);
  */
 void unregister_pernet_subsys(struct pernet_operations *ops)
 {
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	unregister_pernet_operations(ops);
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
 
@@ -1071,11 +1088,11 @@ EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
 int register_pernet_device(struct pernet_operations *ops)
 {
 	int error;
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	error = register_pernet_operations(&pernet_list, ops);
 	if (!error && (first_device == &pernet_list))
 		first_device = &ops->list;
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 	return error;
 }
 EXPORT_SYMBOL_GPL(register_pernet_device);
@@ -1091,11 +1108,11 @@ EXPORT_SYMBOL_GPL(register_pernet_device);
  */
 void unregister_pernet_device(struct pernet_operations *ops)
 {
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	if (&ops->list == first_device)
 		first_device = first_device->next;
 	unregister_pernet_operations(ops);
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_device);
 
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index bc290413a49d..67f375cfb982 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -454,11 +454,11 @@ static void rtnl_lock_unregistering_all(void)
 void rtnl_link_unregister(struct rtnl_link_ops *ops)
 {
 	/* Close the race with cleanup_net() */
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	rtnl_lock_unregistering_all();
 	__rtnl_link_unregister(ops);
 	rtnl_unlock();
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL_GPL(rtnl_link_unregister);
 
@@ -4724,6 +4724,7 @@ static void __net_exit rtnetlink_net_exit(struct net *net)
 static struct pernet_operations rtnetlink_net_ops = {
 	.init = rtnetlink_net_init,
 	.exit = rtnetlink_net_exit,
+	.async = true,
 };
 
 void __init rtnetlink_init(void)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 09bd89c90a71..1a7485a2cdfa 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -890,7 +890,7 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
 }
 EXPORT_SYMBOL_GPL(skb_morph);
 
-static int mm_account_pinned_pages(struct mmpin *mmp, size_t size)
+int mm_account_pinned_pages(struct mmpin *mmp, size_t size)
 {
 	unsigned long max_pg, num_pg, new_pg, old_pg;
 	struct user_struct *user;
@@ -919,14 +919,16 @@ static int mm_account_pinned_pages(struct mmpin *mmp, size_t size)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(mm_account_pinned_pages);
 
-static void mm_unaccount_pinned_pages(struct mmpin *mmp)
+void mm_unaccount_pinned_pages(struct mmpin *mmp)
 {
 	if (mmp->user) {
 		atomic_long_sub(mmp->num_pg, &mmp->user->locked_vm);
 		free_uid(mmp->user);
 	}
 }
+EXPORT_SYMBOL_GPL(mm_unaccount_pinned_pages);
 
 struct ubuf_info *sock_zerocopy_alloc(struct sock *sk, size_t size)
 {
diff --git a/net/core/sock.c b/net/core/sock.c
index c501499a04fe..a1fa4a548f1b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1049,18 +1049,21 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
 		break;
 
 	case SO_ZEROCOPY:
-		if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+		if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6) {
+			if (sk->sk_protocol != IPPROTO_TCP)
+				ret = -ENOTSUPP;
+			else if (sk->sk_state != TCP_CLOSE)
+				ret = -EBUSY;
+		} else if (sk->sk_family != PF_RDS) {
 			ret = -ENOTSUPP;
-		else if (sk->sk_protocol != IPPROTO_TCP)
-			ret = -ENOTSUPP;
-		else if (sk->sk_state != TCP_CLOSE)
-			ret = -EBUSY;
-		else if (val < 0 || val > 1)
-			ret = -EINVAL;
-		else
-			sock_valbool_flag(sk, SOCK_ZEROCOPY, valbool);
-		break;
-
+		}
+		if (!ret) {
+			if (val < 0 || val > 1)
+				ret = -EINVAL;
+			else
+				sock_valbool_flag(sk, SOCK_ZEROCOPY, valbool);
+			break;
+		}
 	default:
 		ret = -ENOPROTOOPT;
 		break;
@@ -1274,7 +1277,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 	{
 		char address[128];
 
-		if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2))
+		lv = sock->ops->getname(sock, (struct sockaddr *)address, 2);
+		if (lv < 0)
 			return -ENOTCONN;
 		if (lv < len)
 			return -EINVAL;
@@ -2497,7 +2501,7 @@ int sock_no_accept(struct socket *sock, struct socket *newsock, int flags,
 EXPORT_SYMBOL(sock_no_accept);
 
 int sock_no_getname(struct socket *sock, struct sockaddr *saddr,
-		    int *len, int peer)
+		    int peer)
 {
 	return -EOPNOTSUPP;
 }
@@ -3111,6 +3115,7 @@ static void __net_exit sock_inuse_exit_net(struct net *net)
 static struct pernet_operations net_inuse_ops = {
 	.init = sock_inuse_init_net,
 	.exit = sock_inuse_exit_net,
+	.async = true,
 };
 
 static __init int net_inuse_init(void)
@@ -3384,6 +3389,7 @@ static __net_exit void proto_exit_net(struct net *net)
 static __net_initdata struct pernet_operations proto_net_ops = {
 	.init = proto_init_net,
 	.exit = proto_exit_net,
+	.async = true,
 };
 
 static int __init proto_init(void)
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 146b50e30659..aee5642affd9 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -328,6 +328,7 @@ static void __net_exit diag_net_exit(struct net *net)
 static struct pernet_operations diag_net_ops = {
 	.init = diag_net_init,
 	.exit = diag_net_exit,
+	.async = true,
 };
 
 static int __init sock_diag_init(void)
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index f2d0462611c3..d714f65782b7 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -572,6 +572,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net)
 static __net_initdata struct pernet_operations sysctl_core_ops = {
 	.init = sysctl_core_net_init,
 	.exit = sysctl_core_net_exit,
+	.async = true,
 };
 
 static __init int sysctl_core_init(void)
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 91dd09f79808..2ee8306c23e3 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1180,14 +1180,12 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 
-static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len,int peer)
+static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int peer)
 {
 	struct sockaddr_dn *sa = (struct sockaddr_dn *)uaddr;
 	struct sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
 
-	*uaddr_len = sizeof(struct sockaddr_dn);
-
 	lock_sock(sk);
 
 	if (peer) {
@@ -1205,7 +1203,7 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len
 
 	release_sock(sk);
 
-	return 0;
+	return sizeof(struct sockaddr_dn);
 }
 
 
@@ -1338,6 +1336,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
 	lock_sock(sk);
 	err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
 	release_sock(sk);
+#ifdef CONFIG_NETFILTER
+	/* we need to exclude all possible ENOPROTOOPTs except default case */
+	if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
+	    optname != DSO_STREAM && optname != DSO_SEQPACKET)
+		err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
 
 	return err;
 }
@@ -1445,15 +1449,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
 		dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
 		break;
 
-	default:
-#ifdef CONFIG_NETFILTER
-		return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
-#endif
-	case DSO_LINKINFO:
-	case DSO_STREAM:
-	case DSO_SEQPACKET:
-		return -ENOPROTOOPT;
-
 	case DSO_MAXWINDOW:
 		if (optlen != sizeof(unsigned long))
 			return -EINVAL;
@@ -1501,6 +1496,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
 			return -EINVAL;
 		scp->info_loc = u.info;
 		break;
+
+	case DSO_LINKINFO:
+	case DSO_STREAM:
+	case DSO_SEQPACKET:
+	default:
+		return -ENOPROTOOPT;
 	}
 
 	return 0;
@@ -1514,6 +1515,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use
 	lock_sock(sk);
 	err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
 	release_sock(sk);
+#ifdef CONFIG_NETFILTER
+	if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
+	    optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
+	    optname != DSO_CONREJECT) {
+		int len;
+
+		if (get_user(len, optlen))
+			return -EFAULT;
+
+		err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+		if (err >= 0)
+			err = put_user(len, optlen);
+	}
+#endif
 
 	return err;
 }
@@ -1579,26 +1594,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
 		r_data = &link;
 		break;
 
-	default:
-#ifdef CONFIG_NETFILTER
-	{
-		int ret, len;
-
-		if (get_user(len, optlen))
-			return -EFAULT;
-
-		ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
-		if (ret >= 0)
-			ret = put_user(len, optlen);
-		return ret;
-	}
-#endif
-	case DSO_STREAM:
-	case DSO_SEQPACKET:
-	case DSO_CONACCEPT:
-	case DSO_CONREJECT:
-		return -ENOPROTOOPT;
-
 	case DSO_MAXWINDOW:
 		if (r_len > sizeof(unsigned long))
 			r_len = sizeof(unsigned long);
@@ -1630,6 +1625,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
 			r_len = sizeof(unsigned char);
 		r_data = &scp->info_rem;
 		break;
+
+	case DSO_STREAM:
+	case DSO_SEQPACKET:
+	case DSO_CONACCEPT:
+	case DSO_CONREJECT:
+	default:
+		return -ENOPROTOOPT;
 	}
 
 	if (r_data) {
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 6a9d0f50fbee..e63c554e0623 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -23,6 +23,7 @@
 #include <linux/netdevice.h>
 #include <linux/sysfs.h>
 #include <linux/phy_fixed.h>
+#include <linux/ptp_classify.h>
 #include <linux/gpio/consumer.h>
 #include <linux/etherdevice.h>
 
@@ -122,6 +123,38 @@ struct net_device *dsa_dev_to_net_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dsa_dev_to_net_device);
 
+/* Determine if we should defer delivery of skb until we have a rx timestamp.
+ *
+ * Called from dsa_switch_rcv. For now, this will only work if tagging is
+ * enabled on the switch. Normally the MAC driver would retrieve the hardware
+ * timestamp when it reads the packet out of the hardware. However in a DSA
+ * switch, the DSA driver owning the interface to which the packet is
+ * delivered is never notified unless we do so here.
+ */
+static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p,
+				       struct sk_buff *skb)
+{
+	struct dsa_switch *ds = p->dp->ds;
+	unsigned int type;
+
+	if (skb_headroom(skb) < ETH_HLEN)
+		return false;
+
+	__skb_push(skb, ETH_HLEN);
+
+	type = ptp_classify_raw(skb);
+
+	__skb_pull(skb, ETH_HLEN);
+
+	if (type == PTP_CLASS_NONE)
+		return false;
+
+	if (likely(ds->ops->port_rxtstamp))
+		return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type);
+
+	return false;
+}
+
 static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
 			  struct packet_type *pt, struct net_device *unused)
 {
@@ -157,6 +190,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
 	s->rx_bytes += skb->len;
 	u64_stats_update_end(&s->syncp);
 
+	if (dsa_skb_defer_rx_timestamp(p, skb))
+		return 0;
+
 	netif_receive_skb(skb);
 
 	return 0;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index f52307296de4..3376dad6dcfd 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -21,6 +21,7 @@
 #include <net/tc_act/tc_mirred.h>
 #include <linux/if_bridge.h>
 #include <linux/netpoll.h>
+#include <linux/ptp_classify.h>
 
 #include "dsa_priv.h"
 
@@ -255,6 +256,22 @@ dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
 
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->dp->ds;
+	int port = p->dp->index;
+
+	/* Pass through to switch driver if it supports timestamping */
+	switch (cmd) {
+	case SIOCGHWTSTAMP:
+		if (ds->ops->port_hwtstamp_get)
+			return ds->ops->port_hwtstamp_get(ds, port, ifr);
+		break;
+	case SIOCSHWTSTAMP:
+		if (ds->ops->port_hwtstamp_set)
+			return ds->ops->port_hwtstamp_set(ds, port, ifr);
+		break;
+	}
+
 	if (!dev->phydev)
 		return -ENODEV;
 
@@ -385,6 +402,30 @@ static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,
 	return NETDEV_TX_OK;
 }
 
+static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
+				 struct sk_buff *skb)
+{
+	struct dsa_switch *ds = p->dp->ds;
+	struct sk_buff *clone;
+	unsigned int type;
+
+	type = ptp_classify_raw(skb);
+	if (type == PTP_CLASS_NONE)
+		return;
+
+	if (!ds->ops->port_txtstamp)
+		return;
+
+	clone = skb_clone_sk(skb);
+	if (!clone)
+		return;
+
+	if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type))
+		return;
+
+	kfree_skb(clone);
+}
+
 static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
@@ -397,6 +438,11 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 	s->tx_bytes += skb->len;
 	u64_stats_update_end(&s->syncp);
 
+	/* Identify PTP protocol packets, clone them, and pass them to the
+	 * switch driver
+	 */
+	dsa_skb_tx_timestamp(p, skb);
+
 	/* Transmit function may have to reallocate the original SKB,
 	 * in which case it must have freed it. Only free it here on error.
 	 */
@@ -918,6 +964,18 @@ static int dsa_slave_set_rxnfc(struct net_device *dev,
 	return ds->ops->set_rxnfc(ds, dp->index, nfc);
 }
 
+static int dsa_slave_get_ts_info(struct net_device *dev,
+				 struct ethtool_ts_info *ts)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->dp->ds;
+
+	if (!ds->ops->get_ts_info)
+		return -EOPNOTSUPP;
+
+	return ds->ops->get_ts_info(ds, p->dp->index, ts);
+}
+
 static const struct ethtool_ops dsa_slave_ethtool_ops = {
 	.get_drvinfo		= dsa_slave_get_drvinfo,
 	.get_regs_len		= dsa_slave_get_regs_len,
@@ -938,6 +996,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
 	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
 	.get_rxnfc		= dsa_slave_get_rxnfc,
 	.set_rxnfc		= dsa_slave_set_rxnfc,
+	.get_ts_info		= dsa_slave_get_ts_info,
 };
 
 /* legacy way, bypassing the bridge *****************************************/
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index e4329e161943..e8c7fad8c329 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -723,7 +723,7 @@ EXPORT_SYMBOL(inet_accept);
  *	This does both peername and sockname.
  */
 int inet_getname(struct socket *sock, struct sockaddr *uaddr,
-			int *uaddr_len, int peer)
+			int peer)
 {
 	struct sock *sk		= sock->sk;
 	struct inet_sock *inet	= inet_sk(sk);
@@ -745,8 +745,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr,
 		sin->sin_addr.s_addr = addr;
 	}
 	memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
-	*uaddr_len = sizeof(*sin);
-	return 0;
+	return sizeof(*sin);
 }
 EXPORT_SYMBOL(inet_getname);
 
@@ -1736,6 +1735,7 @@ static __net_exit void ipv4_mib_exit_net(struct net *net)
 static __net_initdata struct pernet_operations ipv4_mib_ops = {
 	.init = ipv4_mib_init_net,
 	.exit = ipv4_mib_exit_net,
+	.async = true,
 };
 
 static int __init init_ipv4_mibs(void)
@@ -1789,6 +1789,7 @@ static __net_exit void inet_exit_net(struct net *net)
 static __net_initdata struct pernet_operations af_inet_ops = {
 	.init = inet_init_net,
 	.exit = inet_exit_net,
+	.async = true,
 };
 
 static int __init init_inet_pernet_ops(void)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index f28f06c91ead..7dc9de8444a9 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1447,6 +1447,7 @@ static void __net_exit arp_net_exit(struct net *net)
 static struct pernet_operations arp_net_ops = {
 	.init = arp_net_init,
 	.exit = arp_net_exit,
+	.async = true,
 };
 
 static int __init arp_proc_init(void)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 40f001782c1b..5ae0d1f097ca 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2469,6 +2469,7 @@ static __net_exit void devinet_exit_net(struct net *net)
 static __net_initdata struct pernet_operations devinet_ops = {
 	.init = devinet_init_net,
 	.exit = devinet_exit_net,
+	.async = true,
 };
 
 static struct rtnl_af_ops inet_af_ops __read_mostly = {
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 296d0b956bfe..97689012b357 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -654,7 +654,7 @@ static void esp_input_restore_header(struct sk_buff *skb)
 static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi)
 {
 	struct xfrm_state *x = xfrm_input_state(skb);
-	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)skb->data;
+	struct ip_esp_hdr *esph;
 
 	/* For ESN we move the header forward by 4 bytes to
 	 * accomodate the high bits.  We will move it back after
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index f05afaf3235c..ac71c3d496c0 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1362,6 +1362,7 @@ static void __net_exit fib_net_exit(struct net *net)
 static struct pernet_operations fib_net_ops = {
 	.init = fib_net_init,
 	.exit = fib_net_exit,
+	.async = true,
 };
 
 void __init ip_fib_init(void)
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index c586597da20d..cd46d7666598 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -646,6 +646,11 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
 					    fi->fib_nh, cfg, extack))
 				return 1;
 		}
+#ifdef CONFIG_IP_ROUTE_CLASSID
+		if (cfg->fc_flow &&
+		    cfg->fc_flow != fi->fib_nh->nh_tclassid)
+			return 1;
+#endif
 		if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
 		    (!cfg->fc_gw  || cfg->fc_gw == fi->fib_nh->nh_gw))
 			return 0;
@@ -1760,13 +1765,11 @@ void fib_select_multipath(struct fib_result *res, int hash)
 void fib_select_path(struct net *net, struct fib_result *res,
 		     struct flowi4 *fl4, const struct sk_buff *skb)
 {
-	bool oif_check;
-
-	oif_check = (fl4->flowi4_oif == 0 ||
-		     fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF);
+	if (fl4->flowi4_oif && !(fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF))
+		goto check_saddr;
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-	if (res->fi->fib_nhs > 1 && oif_check) {
+	if (res->fi->fib_nhs > 1) {
 		int h = fib_multipath_hash(res->fi, fl4, skb);
 
 		fib_select_multipath(res, h);
@@ -1775,10 +1778,10 @@ void fib_select_path(struct net *net, struct fib_result *res,
 #endif
 	if (!res->prefixlen &&
 	    res->table->tb_num_default > 1 &&
-	    res->type == RTN_UNICAST && oif_check)
+	    res->type == RTN_UNICAST)
 		fib_select_default(fl4, res);
 
+check_saddr:
 	if (!fl4->saddr)
 		fl4->saddr = FIB_RES_PREFSRC(net, *res);
 }
-EXPORT_SYMBOL_GPL(fib_select_path);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 1617604c9284..cc56efa64d5c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1257,6 +1257,7 @@ static int __net_init icmp_sk_init(struct net *net)
 static struct pernet_operations __net_initdata icmp_sk_ops = {
        .init = icmp_sk_init,
        .exit = icmp_sk_exit,
+       .async = true,
 };
 
 int __init icmp_init(void)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index f2402581fef1..c2743763777e 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -3028,6 +3028,7 @@ static void __net_exit igmp_net_exit(struct net *net)
 static struct pernet_operations igmp_net_ops = {
 	.init = igmp_net_init,
 	.exit = igmp_net_exit,
+	.async = true,
 };
 #endif
 
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index bbf1b94942c0..5e843ae5e468 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -885,6 +885,7 @@ static void __net_exit ipv4_frags_exit_net(struct net *net)
 static struct pernet_operations ip4_frags_ops = {
 	.init = ipv4_frags_init_net,
 	.exit = ipv4_frags_exit_net,
+	.async = true,
 };
 
 void __init ipfrag_init(void)
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 008be04ac1cc..74c962b9b09c 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -258,7 +258,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
 			src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
 			if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
 				return -EINVAL;
-			ipc->oif = src_info->ipi6_ifindex;
+			if (src_info->ipi6_ifindex)
+				ipc->oif = src_info->ipi6_ifindex;
 			ipc->addr = src_info->ipi6_addr.s6_addr32[3];
 			continue;
 		}
@@ -288,7 +289,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
 				return -EINVAL;
 			info = (struct in_pktinfo *)CMSG_DATA(cmsg);
-			ipc->oif = info->ipi_ifindex;
+			if (info->ipi_ifindex)
+				ipc->oif = info->ipi_ifindex;
 			ipc->addr = info->ipi_spec_dst.s_addr;
 			break;
 		}
@@ -1567,10 +1569,7 @@ int ip_getsockopt(struct sock *sk, int level,
 		if (get_user(len, optlen))
 			return -EFAULT;
 
-		lock_sock(sk);
-		err = nf_getsockopt(sk, PF_INET, optname, optval,
-				&len);
-		release_sock(sk);
+		err = nf_getsockopt(sk, PF_INET, optname, optval, &len);
 		if (err >= 0)
 			err = put_user(len, optlen);
 		return err;
@@ -1602,9 +1601,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
 		if (get_user(len, optlen))
 			return -EFAULT;
 
-		lock_sock(sk);
 		err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
-		release_sock(sk);
 		if (err >= 0)
 			err = put_user(len, optlen);
 		return err;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index b05689bbba31..7c7ac9d32e77 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -3327,6 +3327,7 @@ static void __net_exit ipmr_net_exit(struct net *net)
 static struct pernet_operations ipmr_net_ops = {
 	.init = ipmr_net_init,
 	.exit = ipmr_net_exit,
+	.async = true,
 };
 
 int __init ip_mr_init(void)
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 4ffe302f9b82..e3e420f3ba7b 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -252,6 +252,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
 			}
 			if (table_base + v
 			    != arpt_next_entry(e)) {
+				if (unlikely(stackidx >= private->stacksize)) {
+					verdict = NF_DROP;
+					break;
+				}
 				jumpstack[stackidx++] = e;
 			}
 
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 9a71f3149507..d4f7584d2dbe 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -330,8 +330,13 @@ ipt_do_table(struct sk_buff *skb,
 				continue;
 			}
 			if (table_base + v != ipt_next_entry(e) &&
-			    !(e->ip.flags & IPT_F_GOTO))
+			    !(e->ip.flags & IPT_F_GOTO)) {
+				if (unlikely(stackidx >= private->stacksize)) {
+					verdict = NF_DROP;
+					break;
+				}
 				jumpstack[stackidx++] = e;
+			}
 
 			e = get_entry(table_base, v);
 			continue;
@@ -1911,6 +1916,7 @@ static void __net_exit ip_tables_net_exit(struct net *net)
 static struct pernet_operations ip_tables_net_ops = {
 	.init = ip_tables_net_init,
 	.exit = ip_tables_net_exit,
+	.async = true,
 };
 
 static int __init ip_tables_init(void)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 3a84a60f6b39..4b02ab39ebc5 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -107,12 +107,6 @@ clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
 
 	local_bh_disable();
 	if (refcount_dec_and_lock(&c->entries, &cn->lock)) {
-		list_del_rcu(&c->list);
-		spin_unlock(&cn->lock);
-		local_bh_enable();
-
-		unregister_netdevice_notifier(&c->notifier);
-
 		/* In case anyone still accesses the file, the open/close
 		 * functions are also incrementing the refcount on their own,
 		 * so it's safe to remove the entry even if it's in use. */
@@ -120,6 +114,12 @@ clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
 		if (cn->procdir)
 			proc_remove(c->pde);
 #endif
+		list_del_rcu(&c->list);
+		spin_unlock(&cn->lock);
+		local_bh_enable();
+
+		unregister_netdevice_notifier(&c->notifier);
+
 		return;
 	}
 	local_bh_enable();
@@ -154,8 +154,12 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
 #endif
 		if (unlikely(!refcount_inc_not_zero(&c->refcount)))
 			c = NULL;
-		else if (entry)
-			refcount_inc(&c->entries);
+		else if (entry) {
+			if (unlikely(!refcount_inc_not_zero(&c->entries))) {
+				clusterip_config_put(c);
+				c = NULL;
+			}
+		}
 	}
 	rcu_read_unlock_bh();
 
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 270765236f5e..aaaf9a81fbc9 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -98,17 +98,15 @@ static int ecn_tg_check(const struct xt_tgchk_param *par)
 	const struct ipt_ECN_info *einfo = par->targinfo;
 	const struct ipt_entry *e = par->entryinfo;
 
-	if (einfo->operation & IPT_ECN_OP_MASK) {
-		pr_info("unsupported ECN operation %x\n", einfo->operation);
+	if (einfo->operation & IPT_ECN_OP_MASK)
 		return -EINVAL;
-	}
-	if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
-		pr_info("new ECT codepoint %x out of mask\n", einfo->ip_ect);
+
+	if (einfo->ip_ect & ~IPT_ECN_IP_MASK)
 		return -EINVAL;
-	}
+
 	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) &&
 	    (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
-		pr_info("cannot use TCP operations on a non-tcp rule\n");
+		pr_info_ratelimited("cannot use operation on non-tcp rule\n");
 		return -EINVAL;
 	}
 	return 0;
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 8bd0d7b26632..e8bed3390e58 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -74,13 +74,13 @@ static int reject_tg_check(const struct xt_tgchk_param *par)
 	const struct ipt_entry *e = par->entryinfo;
 
 	if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
-		pr_info("ECHOREPLY no longer supported.\n");
+		pr_info_ratelimited("ECHOREPLY no longer supported.\n");
 		return -EINVAL;
 	} else if (rejinfo->with == IPT_TCP_RESET) {
 		/* Must specify that it's a TCP packet */
 		if (e->ip.proto != IPPROTO_TCP ||
 		    (e->ip.invflags & XT_INV_PROTO)) {
-			pr_info("TCP_RESET invalid for non-tcp\n");
+			pr_info_ratelimited("TCP_RESET invalid for non-tcp\n");
 			return -EINVAL;
 		}
 	}
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
index 37fb9552e858..fd01f13c896a 100644
--- a/net/ipv4/netfilter/ipt_rpfilter.c
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -105,14 +105,14 @@ static int rpfilter_check(const struct xt_mtchk_param *par)
 	const struct xt_rpfilter_info *info = par->matchinfo;
 	unsigned int options = ~XT_RPFILTER_OPTION_MASK;
 	if (info->flags & options) {
-		pr_info("unknown options encountered");
+		pr_info_ratelimited("unknown options\n");
 		return -EINVAL;
 	}
 
 	if (strcmp(par->table, "mangle") != 0 &&
 	    strcmp(par->table, "raw") != 0) {
-		pr_info("match only valid in the \'raw\' "
-			"or \'mangle\' tables, not \'%s\'.\n", par->table);
+		pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n",
+				    par->table);
 		return -EINVAL;
 	}
 
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 9ac92ea7b93c..c1c136a93911 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -87,6 +87,7 @@ static void __net_exit iptable_filter_net_exit(struct net *net)
 static struct pernet_operations iptable_filter_net_ops = {
 	.init = iptable_filter_net_init,
 	.exit = iptable_filter_net_exit,
+	.async = true,
 };
 
 static int __init iptable_filter_init(void)
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index b8f0db54b197..0164def9c808 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -1204,6 +1204,7 @@ static void __net_exit ping_v4_proc_exit_net(struct net *net)
 static struct pernet_operations ping_v4_net_ops = {
 	.init = ping_v4_proc_init_net,
 	.exit = ping_v4_proc_exit_net,
+	.async = true,
 };
 
 int __init ping_proc_init(void)
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index dc5edc8f7564..fdabc70283b6 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -549,6 +549,7 @@ static __net_exit void ip_proc_exit_net(struct net *net)
 static __net_initdata struct pernet_operations ip_proc_ops = {
 	.init = ip_proc_init_net,
 	.exit = ip_proc_exit_net,
+	.async = true,
 };
 
 int __init ip_misc_proc_init(void)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 9b367fc48d7d..54648d20bf0f 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -1156,6 +1156,7 @@ static __net_exit void raw_exit_net(struct net *net)
 static __net_initdata struct pernet_operations raw_net_ops = {
 	.init = raw_init_net,
 	.exit = raw_exit_net,
+	.async = true,
 };
 
 int __init raw_proc_init(void)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 49cc1c1df1ba..d673c5758878 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -417,6 +417,7 @@ static void __net_exit ip_rt_do_proc_exit(struct net *net)
 static struct pernet_operations ip_rt_proc_ops __net_initdata =  {
 	.init = ip_rt_do_proc_init,
 	.exit = ip_rt_do_proc_exit,
+	.async = true,
 };
 
 static int __init ip_rt_proc_init(void)
@@ -1383,7 +1384,7 @@ struct uncached_list {
 
 static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list);
 
-static void rt_add_uncached_list(struct rtable *rt)
+void rt_add_uncached_list(struct rtable *rt)
 {
 	struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list);
 
@@ -1394,14 +1395,8 @@ static void rt_add_uncached_list(struct rtable *rt)
 	spin_unlock_bh(&ul->lock);
 }
 
-static void ipv4_dst_destroy(struct dst_entry *dst)
+void rt_del_uncached_list(struct rtable *rt)
 {
-	struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
-	struct rtable *rt = (struct rtable *) dst;
-
-	if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
-		kfree(p);
-
 	if (!list_empty(&rt->rt_uncached)) {
 		struct uncached_list *ul = rt->rt_uncached_list;
 
@@ -1411,6 +1406,17 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
 	}
 }
 
+static void ipv4_dst_destroy(struct dst_entry *dst)
+{
+	struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
+	struct rtable *rt = (struct rtable *)dst;
+
+	if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
+		kfree(p);
+
+	rt_del_uncached_list(rt);
+}
+
 void rt_flush_dev(struct net_device *dev)
 {
 	struct net *net = dev_net(dev);
@@ -1508,7 +1514,6 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
 		rt->rt_pmtu = 0;
 		rt->rt_gateway = 0;
 		rt->rt_uses_gateway = 0;
-		rt->rt_table_id = 0;
 		INIT_LIST_HEAD(&rt->rt_uncached);
 
 		rt->dst.output = ip_output;
@@ -1644,19 +1649,6 @@ static void ip_del_fnhe(struct fib_nh *nh, __be32 daddr)
 	spin_unlock_bh(&fnhe_lock);
 }
 
-static void set_lwt_redirect(struct rtable *rth)
-{
-	if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
-		rth->dst.lwtstate->orig_output = rth->dst.output;
-		rth->dst.output = lwtunnel_output;
-	}
-
-	if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
-		rth->dst.lwtstate->orig_input = rth->dst.input;
-		rth->dst.input = lwtunnel_input;
-	}
-}
-
 /* called in rcu_read_lock() section */
 static int __mkroute_input(struct sk_buff *skb,
 			   const struct fib_result *res,
@@ -1739,15 +1731,13 @@ static int __mkroute_input(struct sk_buff *skb,
 	}
 
 	rth->rt_is_input = 1;
-	if (res->table)
-		rth->rt_table_id = res->table->tb_id;
 	RT_CACHE_STAT_INC(in_slow_tot);
 
 	rth->dst.input = ip_forward;
 
 	rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag,
 		       do_cache);
-	set_lwt_redirect(rth);
+	lwtunnel_set_redirect(&rth->dst);
 	skb_dst_set(skb, &rth->dst);
 out:
 	err = 0;
@@ -1846,7 +1836,6 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
 
 	return mhash >> 1;
 }
-EXPORT_SYMBOL_GPL(fib_multipath_hash);
 #endif /* CONFIG_IP_ROUTE_MULTIPATH */
 
 static int ip_mkroute_input(struct sk_buff *skb,
@@ -2014,8 +2003,6 @@ out:	return err;
 	rth->dst.tclassid = itag;
 #endif
 	rth->rt_is_input = 1;
-	if (res->table)
-		rth->rt_table_id = res->table->tb_id;
 
 	RT_CACHE_STAT_INC(in_slow_tot);
 	if (res->type == RTN_UNREACHABLE) {
@@ -2244,8 +2231,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 		return ERR_PTR(-ENOBUFS);
 
 	rth->rt_iif = orig_oif;
-	if (res->table)
-		rth->rt_table_id = res->table->tb_id;
 
 	RT_CACHE_STAT_INC(out_slow_tot);
 
@@ -2267,7 +2252,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
 	}
 
 	rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0, do_cache);
-	set_lwt_redirect(rth);
+	lwtunnel_set_redirect(&rth->dst);
 
 	return rth;
 }
@@ -2775,7 +2760,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 		rt->rt_flags |= RTCF_NOTIFY;
 
 	if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE)
-		table_id = rt->rt_table_id;
+		table_id = res.table ? res.table->tb_id : 0;
 
 	if (rtm->rtm_flags & RTM_F_FIB_MATCH) {
 		if (!res.fi) {
@@ -2994,6 +2979,7 @@ static __net_exit void sysctl_route_net_exit(struct net *net)
 static __net_initdata struct pernet_operations sysctl_route_ops = {
 	.init = sysctl_route_net_init,
 	.exit = sysctl_route_net_exit,
+	.async = true,
 };
 #endif
 
@@ -3007,6 +2993,7 @@ static __net_init int rt_genid_init(struct net *net)
 
 static __net_initdata struct pernet_operations rt_genid_ops = {
 	.init = rt_genid_init,
+	.async = true,
 };
 
 static int __net_init ipv4_inetpeer_init(struct net *net)
@@ -3032,6 +3019,7 @@ static void __net_exit ipv4_inetpeer_exit(struct net *net)
 static __net_initdata struct pernet_operations ipv4_inetpeer_ops = {
 	.init	=	ipv4_inetpeer_init,
 	.exit	=	ipv4_inetpeer_exit,
+	.async	=	true,
 };
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 93e172118a94..89683d868b37 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1219,6 +1219,7 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net)
 static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
 	.init = ipv4_sysctl_init_net,
 	.exit = ipv4_sysctl_exit_net,
+	.async = true,
 };
 
 static __init int sysctl_ipv4_init(void)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 575d3c1fb6e8..a6b48f6253e3 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5870,10 +5870,12 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
 	tp->rx_opt.saw_tstamp = 0;
 	req = tp->fastopen_rsk;
 	if (req) {
+		bool req_stolen;
+
 		WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
 		    sk->sk_state != TCP_FIN_WAIT1);
 
-		if (!tcp_check_req(sk, skb, req, true))
+		if (!tcp_check_req(sk, skb, req, true, &req_stolen))
 			goto discard;
 	}
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f8ad397e285e..f3e52bc98980 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1672,6 +1672,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
 
 	if (sk->sk_state == TCP_NEW_SYN_RECV) {
 		struct request_sock *req = inet_reqsk(sk);
+		bool req_stolen = false;
 		struct sock *nsk;
 
 		sk = req->rsk_listener;
@@ -1694,10 +1695,20 @@ int tcp_v4_rcv(struct sk_buff *skb)
 			th = (const struct tcphdr *)skb->data;
 			iph = ip_hdr(skb);
 			tcp_v4_fill_cb(skb, iph, th);
-			nsk = tcp_check_req(sk, skb, req, false);
+			nsk = tcp_check_req(sk, skb, req, false, &req_stolen);
 		}
 		if (!nsk) {
 			reqsk_put(req);
+			if (req_stolen) {
+				/* Another cpu got exclusive access to req
+				 * and created a full blown socket.
+				 * Try to feed this packet to this socket
+				 * instead of discarding it.
+				 */
+				tcp_v4_restore_cb(skb);
+				sock_put(sk);
+				goto lookup;
+			}
 			goto discard_and_relse;
 		}
 		if (nsk == sk) {
@@ -2387,6 +2398,7 @@ static void __net_exit tcp4_proc_exit_net(struct net *net)
 static struct pernet_operations tcp4_net_ops = {
 	.init = tcp4_proc_init_net,
 	.exit = tcp4_proc_exit_net,
+	.async = true,
 };
 
 int __init tcp4_proc_init(void)
@@ -2573,6 +2585,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
        .init	   = tcp_sk_init,
        .exit	   = tcp_sk_exit,
        .exit_batch = tcp_sk_exit_batch,
+       .async	   = true,
 };
 
 void __init tcp_v4_init(void)
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 03b51cdcc731..aa6fea9f3328 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -1024,6 +1024,7 @@ static void __net_exit tcp_net_metrics_exit_batch(struct list_head *net_exit_lis
 static __net_initdata struct pernet_operations tcp_net_metrics_ops = {
 	.init		=	tcp_net_metrics_init,
 	.exit_batch	=	tcp_net_metrics_exit_batch,
+	.async		=	true,
 };
 
 void __init tcp_metrics_init(void)
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index a8384b0c11f8..e7e36433cdb5 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -578,7 +578,7 @@ EXPORT_SYMBOL(tcp_create_openreq_child);
 
 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
 			   struct request_sock *req,
-			   bool fastopen)
+			   bool fastopen, bool *req_stolen)
 {
 	struct tcp_options_received tmp_opt;
 	struct sock *child;
@@ -785,6 +785,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
 
 	sock_rps_save_rxhash(child, skb);
 	tcp_synack_rtt_meas(child, req);
+	*req_stolen = !own_req;
 	return inet_csk_complete_hashdance(sk, child, req, own_req);
 
 listen_overflow:
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e9f985e42405..b2bca373f8be 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2027,6 +2027,24 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk)
 	}
 }
 
+static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len)
+{
+	struct sk_buff *skb, *next;
+
+	skb = tcp_send_head(sk);
+	tcp_for_write_queue_from_safe(skb, next, sk) {
+		if (len <= skb->len)
+			break;
+
+		if (unlikely(TCP_SKB_CB(skb)->eor))
+			return false;
+
+		len -= skb->len;
+	}
+
+	return true;
+}
+
 /* Create a new MTU probe if we are ready.
  * MTU probe is regularly attempting to increase the path MTU by
  * deliberately sending larger packets.  This discovers routing
@@ -2099,6 +2117,9 @@ static int tcp_mtu_probe(struct sock *sk)
 			return 0;
 	}
 
+	if (!tcp_can_coalesce_send_queue_head(sk, probe_size))
+		return -1;
+
 	/* We're allowed to probe.  Build it now. */
 	nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false);
 	if (!nskb)
@@ -2134,6 +2155,10 @@ static int tcp_mtu_probe(struct sock *sk)
 			/* We've eaten all the data from this skb.
 			 * Throw it away. */
 			TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags;
+			/* If this is the last SKB we copy and eor is set
+			 * we need to propagate it to the new skb.
+			 */
+			TCP_SKB_CB(nskb)->eor = TCP_SKB_CB(skb)->eor;
 			tcp_unlink_write_queue(skb, sk);
 			sk_wmem_free_skb(sk, skb);
 		} else {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index bfaefe560b5c..3013404d0935 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2024,6 +2024,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
 		err = udplite_checksum_init(skb, uh);
 		if (err)
 			return err;
+
+		if (UDP_SKB_CB(skb)->partial_cov) {
+			skb->csum = inet_compute_pseudo(skb, proto);
+			return 0;
+		}
 	}
 
 	/* Note, we are only interested in != 0 or == 0, thus the
@@ -2757,6 +2762,7 @@ static void __net_exit udp4_proc_exit_net(struct net *net)
 static struct pernet_operations udp4_net_ops = {
 	.init = udp4_proc_init_net,
 	.exit = udp4_proc_exit_net,
+	.async = true,
 };
 
 int __init udp4_proc_init(void)
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index f96614e9b9a5..72f2c3806408 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -104,6 +104,7 @@ static void __net_exit udplite4_proc_exit_net(struct net *net)
 static struct pernet_operations udplite4_net_ops = {
 	.init = udplite4_proc_init_net,
 	.exit = udplite4_proc_exit_net,
+	.async = true,
 };
 
 static __init int udplite4_proc_init(void)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 05017e2c849c..5f6222e3d21e 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -100,8 +100,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 	xdst->u.rt.rt_gateway = rt->rt_gateway;
 	xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
 	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
-	xdst->u.rt.rt_table_id = rt->rt_table_id;
 	INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
+	rt_add_uncached_list(&xdst->u.rt);
 
 	return 0;
 }
@@ -241,7 +241,8 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
 	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 
 	dst_destroy_metrics_generic(dst);
-
+	if (xdst->u.rt.rt_uncached_list)
+		rt_del_uncached_list(&xdst->u.rt);
 	xfrm_dst_destroy(xdst);
 }
 
@@ -365,6 +366,7 @@ static void __net_exit xfrm4_net_exit(struct net *net)
 static struct pernet_operations __net_initdata xfrm4_net_ops = {
 	.init	= xfrm4_net_init,
 	.exit	= xfrm4_net_exit,
+	.async	= true,
 };
 
 static void __init xfrm4_policy_init(void)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e1846b97ee69..4facfe0b1888 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4257,6 +4257,7 @@ static void __net_exit if6_proc_net_exit(struct net *net)
 static struct pernet_operations if6_proc_net_ops = {
 	.init = if6_proc_net_init,
 	.exit = if6_proc_net_exit,
+	.async = true,
 };
 
 int __init if6_proc_init(void)
@@ -6550,6 +6551,7 @@ static void __net_exit addrconf_exit_net(struct net *net)
 static struct pernet_operations addrconf_ops = {
 	.init = addrconf_init_net,
 	.exit = addrconf_exit_net,
+	.async = true,
 };
 
 static struct rtnl_af_ops inet6_ops __read_mostly = {
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 1d6ced37ad71..ba2e63633370 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -344,6 +344,7 @@ static void __net_exit ip6addrlbl_net_exit(struct net *net)
 static struct pernet_operations ipv6_addr_label_ops = {
 	.init = ip6addrlbl_net_init,
 	.exit = ip6addrlbl_net_exit,
+	.async = true,
 };
 
 int __init ipv6_addr_label_init(void)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 416917719a6f..dbbe04018813 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -470,7 +470,7 @@ EXPORT_SYMBOL_GPL(inet6_destroy_sock);
  */
 
 int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
-		 int *uaddr_len, int peer)
+		 int peer)
 {
 	struct sockaddr_in6 *sin = (struct sockaddr_in6 *)uaddr;
 	struct sock *sk = sock->sk;
@@ -500,8 +500,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
 	}
 	sin->sin6_scope_id = ipv6_iface_scope_id(&sin->sin6_addr,
 						 sk->sk_bound_dev_if);
-	*uaddr_len = sizeof(*sin);
-	return 0;
+	return sizeof(*sin);
 }
 EXPORT_SYMBOL(inet6_getname);
 
@@ -858,6 +857,7 @@ static void __net_exit inet6_net_exit(struct net *net)
 static struct pernet_operations inet6_net_ops = {
 	.init = inet6_net_init,
 	.exit = inet6_net_exit,
+	.async = true,
 };
 
 static const struct ipv6_stub ipv6_stub_impl = {
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index b240f24a6e52..95a2c9e8699a 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -368,6 +368,7 @@ static void __net_exit fib6_rules_net_exit(struct net *net)
 static struct pernet_operations fib6_rules_net_ops = {
 	.init = fib6_rules_net_init,
 	.exit = fib6_rules_net_exit,
+	.async = true,
 };
 
 int __init fib6_rules_init(void)
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 6ae5dd3f4d0d..4fa4f1b150a4 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -997,6 +997,7 @@ static void __net_exit icmpv6_sk_exit(struct net *net)
 static struct pernet_operations icmpv6_sk_ops = {
 	.init = icmpv6_sk_init,
 	.exit = icmpv6_sk_exit,
+	.async = true,
 };
 
 int __init icmpv6_init(void)
diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c
index ec43d18b5ff9..547515e8450a 100644
--- a/net/ipv6/ip6_checksum.c
+++ b/net/ipv6/ip6_checksum.c
@@ -73,6 +73,11 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
 		err = udplite_checksum_init(skb, uh);
 		if (err)
 			return err;
+
+		if (UDP_SKB_CB(skb)->partial_cov) {
+			skb->csum = ip6_compute_pseudo(skb, proto);
+			return 0;
+		}
 	}
 
 	/* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 92b8d8c75eed..cab95cf3b39f 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -2160,6 +2160,7 @@ static void fib6_net_exit(struct net *net)
 static struct pernet_operations fib6_net_ops = {
 	.init = fib6_net_init,
 	.exit = fib6_net_exit,
+	.async = true,
 };
 
 int __init fib6_init(void)
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 3dab664ff503..6ddf52282894 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -873,6 +873,7 @@ static void __net_exit ip6_flowlabel_net_exit(struct net *net)
 static struct pernet_operations ip6_flowlabel_net_ops = {
 	.init = ip6_flowlabel_proc_init,
 	.exit = ip6_flowlabel_net_exit,
+	.async = true,
 };
 
 int ip6_flowlabel_init(void)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 9f6cace9c817..295eb5ecaee5 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1397,6 +1397,7 @@ static void __net_exit ip6mr_net_exit(struct net *net)
 static struct pernet_operations ip6mr_net_ops = {
 	.init = ip6mr_net_init,
 	.exit = ip6mr_net_exit,
+	.async = true,
 };
 
 int __init ip6_mr_init(void)
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index d78d41fc4b1a..24535169663d 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1367,10 +1367,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
 		if (get_user(len, optlen))
 			return -EFAULT;
 
-		lock_sock(sk);
-		err = nf_getsockopt(sk, PF_INET6, optname, optval,
-				&len);
-		release_sock(sk);
+		err = nf_getsockopt(sk, PF_INET6, optname, optval, &len);
 		if (err >= 0)
 			err = put_user(len, optlen);
 	}
@@ -1409,10 +1406,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
 		if (get_user(len, optlen))
 			return -EFAULT;
 
-		lock_sock(sk);
-		err = compat_nf_getsockopt(sk, PF_INET6,
-					   optname, optval, &len);
-		release_sock(sk);
+		err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len);
 		if (err >= 0)
 			err = put_user(len, optlen);
 	}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 9b9d2ff01b35..d9bb933dd5c4 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2997,6 +2997,7 @@ static void __net_exit igmp6_net_exit(struct net *net)
 static struct pernet_operations igmp6_net_ops = {
 	.init = igmp6_net_init,
 	.exit = igmp6_net_exit,
+	.async = true,
 };
 
 int __init igmp6_init(void)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f61a5b613b52..0a19ce3a6f7f 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1882,6 +1882,7 @@ static void __net_exit ndisc_net_exit(struct net *net)
 static struct pernet_operations ndisc_net_ops = {
 	.init = ndisc_net_init,
 	.exit = ndisc_net_exit,
+	.async = true,
 };
 
 int __init ndisc_init(void)
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index af4c917e0836..62358b93bbac 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -352,6 +352,10 @@ ip6t_do_table(struct sk_buff *skb,
 			}
 			if (table_base + v != ip6t_next_entry(e) &&
 			    !(e->ipv6.flags & IP6T_F_GOTO)) {
+				if (unlikely(stackidx >= private->stacksize)) {
+					verdict = NF_DROP;
+					break;
+				}
 				jumpstack[stackidx++] = e;
 			}
 
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index fa51a205918d..38dea8ff680f 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -85,14 +85,14 @@ static int reject_tg6_check(const struct xt_tgchk_param *par)
 	const struct ip6t_entry *e = par->entryinfo;
 
 	if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
-		pr_info("ECHOREPLY is not supported.\n");
+		pr_info_ratelimited("ECHOREPLY is not supported\n");
 		return -EINVAL;
 	} else if (rejinfo->with == IP6T_TCP_RESET) {
 		/* Must specify that it's a TCP packet */
 		if (!(e->ipv6.flags & IP6T_F_PROTO) ||
 		    e->ipv6.proto != IPPROTO_TCP ||
 		    (e->ipv6.invflags & XT_INV_PROTO)) {
-			pr_info("TCP_RESET illegal for non-tcp\n");
+			pr_info_ratelimited("TCP_RESET illegal for non-tcp\n");
 			return -EINVAL;
 		}
 	}
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c
index b12e61b7b16c..94deb69bbbda 100644
--- a/net/ipv6/netfilter/ip6t_rpfilter.c
+++ b/net/ipv6/netfilter/ip6t_rpfilter.c
@@ -103,14 +103,14 @@ static int rpfilter_check(const struct xt_mtchk_param *par)
 	unsigned int options = ~XT_RPFILTER_OPTION_MASK;
 
 	if (info->flags & options) {
-		pr_info("unknown options encountered");
+		pr_info_ratelimited("unknown options\n");
 		return -EINVAL;
 	}
 
 	if (strcmp(par->table, "mangle") != 0 &&
 	    strcmp(par->table, "raw") != 0) {
-		pr_info("match only valid in the \'raw\' "
-			"or \'mangle\' tables, not \'%s\'.\n", par->table);
+		pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n",
+				    par->table);
 		return -EINVAL;
 	}
 
diff --git a/net/ipv6/netfilter/ip6t_srh.c b/net/ipv6/netfilter/ip6t_srh.c
index 9642164107ce..33719d5560c8 100644
--- a/net/ipv6/netfilter/ip6t_srh.c
+++ b/net/ipv6/netfilter/ip6t_srh.c
@@ -122,12 +122,14 @@ static int srh_mt6_check(const struct xt_mtchk_param *par)
 	const struct ip6t_srh *srhinfo = par->matchinfo;
 
 	if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
-		pr_err("unknown srh match flags  %X\n", srhinfo->mt_flags);
+		pr_info_ratelimited("unknown srh match flags  %X\n",
+				    srhinfo->mt_flags);
 		return -EINVAL;
 	}
 
 	if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
-		pr_err("unknown srh invflags %X\n", srhinfo->mt_invflags);
+		pr_info_ratelimited("unknown srh invflags %X\n",
+				    srhinfo->mt_invflags);
 		return -EINVAL;
 	}
 
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index d12c55dad7d1..318c6e914234 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -240,6 +240,7 @@ static void __net_init ping_v6_proc_exit_net(struct net *net)
 static struct pernet_operations ping_v6_net_ops = {
 	.init = ping_v6_proc_init_net,
 	.exit = ping_v6_proc_exit_net,
+	.async = true,
 };
 #endif
 
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index b67814242f78..b8858c546f41 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -343,6 +343,7 @@ static void __net_exit ipv6_proc_exit_net(struct net *net)
 static struct pernet_operations ipv6_proc_ops = {
 	.init = ipv6_proc_init_net,
 	.exit = ipv6_proc_exit_net,
+	.async = true,
 };
 
 int __init ipv6_misc_proc_init(void)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4c25339b1984..10a4ac4933b7 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1332,6 +1332,7 @@ static void __net_exit raw6_exit_net(struct net *net)
 static struct pernet_operations raw6_net_ops = {
 	.init = raw6_init_net,
 	.exit = raw6_exit_net,
+	.async = true,
 };
 
 int __init raw6_proc_init(void)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index afbc000ad4f2..b5da69c83123 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -733,6 +733,7 @@ static void __net_exit ipv6_frags_exit_net(struct net *net)
 static struct pernet_operations ip6_frags_ops = {
 	.init = ipv6_frags_init_net,
 	.exit = ipv6_frags_exit_net,
+	.async = true,
 };
 
 int __init ipv6_frag_init(void)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9dcfadddd800..ae5abfdbef82 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -128,7 +128,7 @@ struct uncached_list {
 
 static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
 
-static void rt6_uncached_list_add(struct rt6_info *rt)
+void rt6_uncached_list_add(struct rt6_info *rt)
 {
 	struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
 
@@ -139,7 +139,7 @@ static void rt6_uncached_list_add(struct rt6_info *rt)
 	spin_unlock_bh(&ul->lock);
 }
 
-static void rt6_uncached_list_del(struct rt6_info *rt)
+void rt6_uncached_list_del(struct rt6_info *rt)
 {
 	if (!list_empty(&rt->rt6i_uncached)) {
 		struct uncached_list *ul = rt->rt6i_uncached_list;
@@ -2671,14 +2671,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
 		if (err)
 			goto out;
 		rt->dst.lwtstate = lwtstate_get(lwtstate);
-		if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
-			rt->dst.lwtstate->orig_output = rt->dst.output;
-			rt->dst.output = lwtunnel_output;
-		}
-		if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
-			rt->dst.lwtstate->orig_input = rt->dst.input;
-			rt->dst.input = lwtunnel_input;
-		}
+		lwtunnel_set_redirect(&rt->dst);
 	}
 
 	ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
@@ -4979,6 +4972,7 @@ static void __net_exit ip6_route_net_exit_late(struct net *net)
 static struct pernet_operations ip6_route_net_ops = {
 	.init = ip6_route_net_init,
 	.exit = ip6_route_net_exit,
+	.async = true,
 };
 
 static int __net_init ipv6_inetpeer_init(struct net *net)
@@ -5004,11 +4998,13 @@ static void __net_exit ipv6_inetpeer_exit(struct net *net)
 static struct pernet_operations ipv6_inetpeer_ops = {
 	.init	=	ipv6_inetpeer_init,
 	.exit	=	ipv6_inetpeer_exit,
+	.async	=	true,
 };
 
 static struct pernet_operations ip6_route_net_late_ops = {
 	.init = ip6_route_net_init_late,
 	.exit = ip6_route_net_exit_late,
+	.async = true,
 };
 
 static struct notifier_block ip6_route_dev_notifier = {
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
index 7f5621d09571..c3f13c3bd8a9 100644
--- a/net/ipv6/seg6.c
+++ b/net/ipv6/seg6.c
@@ -395,6 +395,7 @@ static void __net_exit seg6_net_exit(struct net *net)
 static struct pernet_operations ip6_segments_ops = {
 	.init = seg6_net_init,
 	.exit = seg6_net_exit,
+	.async = true,
 };
 
 static const struct genl_ops seg6_genl_ops[] = {
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index a789a8ac6a64..262f791f1b9b 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -251,6 +251,7 @@ static void __net_exit ipv6_sysctl_net_exit(struct net *net)
 static struct pernet_operations ipv6_sysctl_net_ops = {
 	.init = ipv6_sysctl_net_init,
 	.exit = ipv6_sysctl_net_exit,
+	.async = true,
 };
 
 static struct ctl_table_header *ip6_header;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 412139f4eccd..5425d7b100ee 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1451,6 +1451,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 
 	if (sk->sk_state == TCP_NEW_SYN_RECV) {
 		struct request_sock *req = inet_reqsk(sk);
+		bool req_stolen = false;
 		struct sock *nsk;
 
 		sk = req->rsk_listener;
@@ -1470,10 +1471,20 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 			th = (const struct tcphdr *)skb->data;
 			hdr = ipv6_hdr(skb);
 			tcp_v6_fill_cb(skb, hdr, th);
-			nsk = tcp_check_req(sk, skb, req, false);
+			nsk = tcp_check_req(sk, skb, req, false, &req_stolen);
 		}
 		if (!nsk) {
 			reqsk_put(req);
+			if (req_stolen) {
+				/* Another cpu got exclusive access to req
+				 * and created a full blown socket.
+				 * Try to feed this packet to this socket
+				 * instead of discarding it.
+				 */
+				tcp_v6_restore_cb(skb);
+				sock_put(sk);
+				goto lookup;
+			}
 			goto discard_and_relse;
 		}
 		if (nsk == sk) {
@@ -1996,6 +2007,7 @@ static struct pernet_operations tcpv6_net_ops = {
 	.init	    = tcpv6_net_init,
 	.exit	    = tcpv6_net_exit,
 	.exit_batch = tcpv6_net_exit_batch,
+	.async	    = true,
 };
 
 int __init tcpv6_init(void)
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 14ae32bb1f3d..f3839780dc31 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -123,6 +123,7 @@ static void __net_exit udplite6_proc_exit_net(struct net *net)
 static struct pernet_operations udplite6_net_ops = {
 	.init = udplite6_proc_init_net,
 	.exit = udplite6_proc_exit_net,
+	.async = true,
 };
 
 int __init udplite6_proc_init(void)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 09fb44ee3b45..cbb270bd81b0 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -113,6 +113,9 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 	xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
 	xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
 	xdst->u.rt6.rt6i_src = rt->rt6i_src;
+	INIT_LIST_HEAD(&xdst->u.rt6.rt6i_uncached);
+	rt6_uncached_list_add(&xdst->u.rt6);
+	atomic_inc(&dev_net(dev)->ipv6.rt6_stats->fib_rt_uncache);
 
 	return 0;
 }
@@ -244,6 +247,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
 	if (likely(xdst->u.rt6.rt6i_idev))
 		in6_dev_put(xdst->u.rt6.rt6i_idev);
 	dst_destroy_metrics_generic(dst);
+	if (xdst->u.rt6.rt6i_uncached_list)
+		rt6_uncached_list_del(&xdst->u.rt6);
 	xfrm_dst_destroy(xdst);
 }
 
@@ -395,6 +400,7 @@ static void __net_exit xfrm6_net_exit(struct net *net)
 static struct pernet_operations xfrm6_net_ops = {
 	.init	= xfrm6_net_init,
 	.exit	= xfrm6_net_exit,
+	.async	= true,
 };
 
 int __init xfrm6_init(void)
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 1e8cc7bcbca3..81ce15ffb878 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -989,14 +989,13 @@ static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
 }
 
 static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
-			     int *len, int peer)
+			     int peer)
 {
 	struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr;
 	struct sock *sk = sock->sk;
 	struct iucv_sock *iucv = iucv_sk(sk);
 
 	addr->sa_family = AF_IUCV;
-	*len = sizeof(struct sockaddr_iucv);
 
 	if (peer) {
 		memcpy(siucv->siucv_user_id, iucv->dst_user_id, 8);
@@ -1009,7 +1008,7 @@ static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
 	memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr));
 	memset(&siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
 
-	return 0;
+	return sizeof(struct sockaddr_iucv);
 }
 
 /**
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index f297d53a11aa..435594648dac 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1417,6 +1417,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
 	 */
 	if (csk->sk_user_data) {
 		write_unlock_bh(&csk->sk_callback_lock);
+		strp_stop(&psock->strp);
 		strp_done(&psock->strp);
 		kmem_cache_free(kcm_psockp, psock);
 		return -EALREADY;
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index ff61124fdf59..4614585e1720 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -349,7 +349,7 @@ static int l2tp_ip_disconnect(struct sock *sk, int flags)
 }
 
 static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
-			   int *uaddr_len, int peer)
+			   int peer)
 {
 	struct sock *sk		= sock->sk;
 	struct inet_sock *inet	= inet_sk(sk);
@@ -370,8 +370,7 @@ static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
 		lsa->l2tp_conn_id = lsk->conn_id;
 		lsa->l2tp_addr.s_addr = addr;
 	}
-	*uaddr_len = sizeof(*lsa);
-	return 0;
+	return sizeof(*lsa);
 }
 
 static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 192344688c06..efea58b66295 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -421,7 +421,7 @@ static int l2tp_ip6_disconnect(struct sock *sk, int flags)
 }
 
 static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
-			    int *uaddr_len, int peer)
+			    int peer)
 {
 	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)uaddr;
 	struct sock *sk = sock->sk;
@@ -449,8 +449,7 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
 	}
 	if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL)
 		lsa->l2tp_scope_id = sk->sk_bound_dev_if;
-	*uaddr_len = sizeof(*lsa);
-	return 0;
+	return sizeof(*lsa);
 }
 
 static int l2tp_ip6_backlog_recv(struct sock *sk, struct sk_buff *skb)
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 59f246d7b290..99a03c72db4f 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -870,7 +870,7 @@ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
 /* getname() support.
  */
 static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
-			    int *usockaddr_len, int peer)
+			    int peer)
 {
 	int len = 0;
 	int error = 0;
@@ -969,8 +969,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
 		memcpy(uaddr, &sp, len);
 	}
 
-	*usockaddr_len = len;
-	error = 0;
+	error = len;
 
 	sock_put(sk);
 end:
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index c38d16f22d2a..01dcc0823d1f 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -971,7 +971,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
  *	Return the address information of a socket.
  */
 static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
-			  int *uaddrlen, int peer)
+			  int peer)
 {
 	struct sockaddr_llc sllc;
 	struct sock *sk = sock->sk;
@@ -982,7 +982,6 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
 	lock_sock(sk);
 	if (sock_flag(sk, SOCK_ZAPPED))
 		goto out;
-	*uaddrlen = sizeof(sllc);
 	if (peer) {
 		rc = -ENOTCONN;
 		if (sk->sk_state != TCP_ESTABLISHED)
@@ -1003,9 +1002,9 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
 			       IFHWADDRLEN);
 		}
 	}
-	rc = 0;
 	sllc.sllc_family = AF_LLC;
 	memcpy(uaddr, &sllc, sizeof(sllc));
+	rc = sizeof(sllc);
 out:
 	release_sock(sk);
 	return rc;
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index a8b1616cec41..1f3188d03840 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -8,6 +8,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018        Intel 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
@@ -304,9 +305,6 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
 			 * driver so reject the timeout update.
 			 */
 			status = WLAN_STATUS_REQUEST_DECLINED;
-			ieee80211_send_addba_resp(sta->sdata, sta->sta.addr,
-						  tid, dialog_token, status,
-						  1, buf_size, timeout);
 			goto end;
 		}
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 46028e12e216..f4195a0f0279 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2892,7 +2892,7 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
 	}
 	if (beacon->probe_resp_len) {
 		new_beacon->probe_resp_len = beacon->probe_resp_len;
-		beacon->probe_resp = pos;
+		new_beacon->probe_resp = pos;
 		memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
 		pos += beacon->probe_resp_len;
 	}
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 1f466d12a6bc..a75653affbf7 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -212,6 +212,7 @@ static const char *hw_flag_names[] = {
 	FLAG(REPORTS_LOW_ACK),
 	FLAG(SUPPORTS_TX_FRAG),
 	FLAG(SUPPORTS_TDLS_BUFFER_STA),
+	FLAG(DEAUTH_NEED_MGD_TX_PREP),
 #undef FLAG
 };
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 444ea8d127fe..4105081dc1df 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -160,12 +160,12 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 		       sta->cparams.ecn ? "yes" : "no");
 	p += scnprintf(p,
 		       bufsz+buf-p,
-		       "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n");
+		       "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets flags\n");
 
 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
 		txqi = to_txq_info(sta->sta.txq[i]);
 		p += scnprintf(p, bufsz+buf-p,
-			       "%d %d %u %u %u %u %u %u %u %u %u\n",
+			       "%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s)\n",
 			       txqi->txq.tid,
 			       txqi->txq.ac,
 			       txqi->tin.backlog_bytes,
@@ -176,7 +176,11 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 			       txqi->tin.overlimit,
 			       txqi->tin.collisions,
 			       txqi->tin.tx_bytes,
-			       txqi->tin.tx_packets);
+			       txqi->tin.tx_packets,
+			       txqi->flags,
+			       txqi->flags & (1<<IEEE80211_TXQ_STOP) ? "STOP" : "RUN",
+			       txqi->flags & (1<<IEEE80211_TXQ_AMPDU) ? " AMPDU" : "",
+			       txqi->flags & (1<<IEEE80211_TXQ_NO_AMSDU) ? " NO-AMSDU" : "");
 	}
 
 	rcu_read_unlock();
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 26900025de2f..ae9c33cd8ada 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1467,7 +1467,7 @@ struct ieee802_11_elems {
 	const struct ieee80211_timeout_interval_ie *timeout_int;
 	const u8 *opmode_notif;
 	const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
-	const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
+	struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
 	const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
 
 	/* length of them, respectively */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 5fe01f82df12..d13ba064951f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1324,8 +1324,7 @@ static void ieee80211_iface_work(struct work_struct *work)
 			mutex_lock(&local->sta_mtx);
 			sta = sta_info_get_bss(sdata, mgmt->sa);
 			if (sta) {
-				u16 tid = *ieee80211_get_qos_ctl(hdr) &
-						IEEE80211_QOS_CTL_TID_MASK;
+				u16 tid = ieee80211_get_tid(hdr);
 
 				__ieee80211_stop_rx_ba_session(
 					sta, tid, WLAN_BACK_RECIPIENT,
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 73ac607beb5d..6a381cbe1e33 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1255,13 +1255,12 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
 }
 
 static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
-			       struct ieee80211_mgmt *mgmt, size_t len)
+			       struct ieee80211_mgmt *mgmt, size_t len,
+			       struct ieee802_11_elems *elems)
 {
 	struct ieee80211_mgmt *mgmt_fwd;
 	struct sk_buff *skb;
 	struct ieee80211_local *local = sdata->local;
-	u8 *pos = mgmt->u.action.u.chan_switch.variable;
-	size_t offset_ttl;
 
 	skb = dev_alloc_skb(local->tx_headroom + len);
 	if (!skb)
@@ -1269,13 +1268,9 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
 	skb_reserve(skb, local->tx_headroom);
 	mgmt_fwd = skb_put(skb, len);
 
-	/* offset_ttl is based on whether the secondary channel
-	 * offset is available or not. Subtract 1 from the mesh TTL
-	 * and disable the initiator flag before forwarding.
-	 */
-	offset_ttl = (len < 42) ? 7 : 10;
-	*(pos + offset_ttl) -= 1;
-	*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+	elems->mesh_chansw_params_ie->mesh_ttl--;
+	elems->mesh_chansw_params_ie->mesh_flags &=
+		~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
 
 	memcpy(mgmt_fwd, mgmt, len);
 	eth_broadcast_addr(mgmt_fwd->da);
@@ -1323,7 +1318,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
 
 	/* forward or re-broadcast the CSA frame */
 	if (fwd_csa) {
-		if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
+		if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
 			mcsa_dbg(sdata, "Failed to forward the CSA frame");
 	}
 }
diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c
index 408649bd4702..37e172701a63 100644
--- a/net/mac80211/michael.c
+++ b/net/mac80211/michael.c
@@ -35,7 +35,7 @@ static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key,
 	da = ieee80211_get_DA(hdr);
 	sa = ieee80211_get_SA(hdr);
 	if (ieee80211_is_data_qos(hdr->frame_control))
-		tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+		tid = ieee80211_get_tid(hdr);
 	else
 		tid = 0;
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 39b660b9a908..7f6955aa03c9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -7,6 +7,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018        Intel 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
@@ -2008,9 +2009,22 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 		ieee80211_flush_queues(local, sdata, true);
 
 	/* deauthenticate/disassociate now */
-	if (tx || frame_buf)
+	if (tx || frame_buf) {
+		struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+		/*
+		 * In multi channel scenarios guarantee that the virtual
+		 * interface is granted immediate airtime to transmit the
+		 * deauthentication frame by calling mgd_prepare_tx, if the
+		 * driver requested so.
+		 */
+		if (ieee80211_hw_check(&local->hw, DEAUTH_NEED_MGD_TX_PREP) &&
+		    !ifmgd->have_beacon)
+			drv_mgd_prepare_tx(sdata->local, sdata);
+
 		ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
 					       reason, tx, frame_buf);
+	}
 
 	/* flush out frame - make sure the deauth was actually sent */
 	if (tx)
@@ -2151,7 +2165,7 @@ static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
 					   u16 tx_time)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+	u16 tid = ieee80211_get_tid(hdr);
 	int ac = ieee80211_ac_from_tid(tid);
 	struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
 	unsigned long now = jiffies;
@@ -3368,6 +3382,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 	bssid = ifmgd->associated->bssid;
 
 	/* Track average RSSI from the Beacon frames of the current AP */
+	if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
+		goto skip_signal_processing;
 	if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
 		ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
 		ewma_beacon_signal_init(&ifmgd->ave_beacon_signal);
@@ -3454,6 +3470,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 				sig, GFP_KERNEL);
 		}
 	}
+skip_signal_processing:
 
 	if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
 		mlme_dbg_ratelimited(sdata,
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 4a5bdad9f303..fb586b6e5d49 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -669,7 +669,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
 	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
 		return;
 
-	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+	tid = ieee80211_get_tid(hdr);
 	if (likely(sta->ampdu_mlme.tid_tx[tid]))
 		return;
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fd580614085b..3fa15b01e627 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -439,6 +439,10 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
 			flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
+		if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
+			flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
+		if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
+			flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
 		put_unaligned_le16(flags, pos);
 		pos += 2;
 		if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
@@ -1185,7 +1189,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
 
 	ack_policy = *ieee80211_get_qos_ctl(hdr) &
 		     IEEE80211_QOS_CTL_ACK_POLICY_MASK;
-	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+	tid = ieee80211_get_tid(hdr);
 
 	tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
 	if (!tid_agg_rx) {
@@ -1524,9 +1528,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
 		   ieee80211_has_pm(hdr->frame_control) &&
 		   (ieee80211_is_data_qos(hdr->frame_control) ||
 		    ieee80211_is_qos_nullfunc(hdr->frame_control))) {
-		u8 tid;
-
-		tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+		u8 tid = ieee80211_get_tid(hdr);
 
 		ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid);
 	}
@@ -2791,7 +2793,8 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
 	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
 		int sig = 0;
 
-		if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM))
+		if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
+		    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
 			sig = status->signal;
 
 		cfg80211_report_obss_beacon(rx->local->hw.wiphy,
@@ -2848,6 +2851,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 		case WLAN_HT_ACTION_SMPS: {
 			struct ieee80211_supported_band *sband;
 			enum ieee80211_smps_mode smps_mode;
+			struct sta_opmode_info sta_opmode = {};
 
 			/* convert to HT capability */
 			switch (mgmt->u.action.u.ht_smps.smps_control) {
@@ -2868,17 +2872,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 			if (rx->sta->sta.smps_mode == smps_mode)
 				goto handled;
 			rx->sta->sta.smps_mode = smps_mode;
+			sta_opmode.smps_mode = smps_mode;
+			sta_opmode.changed = STA_OPMODE_SMPS_MODE_CHANGED;
 
 			sband = rx->local->hw.wiphy->bands[status->band];
 
 			rate_control_rate_update(local, sband, rx->sta,
 						 IEEE80211_RC_SMPS_CHANGED);
+			cfg80211_sta_opmode_change_notify(sdata->dev,
+							  rx->sta->addr,
+							  &sta_opmode,
+							  GFP_KERNEL);
 			goto handled;
 		}
 		case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
 			struct ieee80211_supported_band *sband;
 			u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
 			enum ieee80211_sta_rx_bandwidth max_bw, new_bw;
+			struct sta_opmode_info sta_opmode = {};
 
 			/* If it doesn't support 40 MHz it can't change ... */
 			if (!(rx->sta->sta.ht_cap.cap &
@@ -2899,9 +2910,15 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
 			rx->sta->sta.bandwidth = new_bw;
 			sband = rx->local->hw.wiphy->bands[status->band];
+			sta_opmode.bw = new_bw;
+			sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
 
 			rate_control_rate_update(local, sband, rx->sta,
 						 IEEE80211_RC_BW_CHANGED);
+			cfg80211_sta_opmode_change_notify(sdata->dev,
+							  rx->sta->addr,
+							  &sta_opmode,
+							  GFP_KERNEL);
 			goto handled;
 		}
 		default:
@@ -3118,7 +3135,8 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
 	 * it transmitted were processed or returned.
 	 */
 
-	if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM))
+	if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
+	    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
 		sig = status->signal;
 
 	if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ef2becaade50..a3b1bcc2b461 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -73,7 +73,9 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 	bool signal_valid;
 	struct ieee80211_sub_if_data *scan_sdata;
 
-	if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
+	if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
+		bss_meta.signal = 0; /* invalid signal indication */
+	else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
 		bss_meta.signal = rx_status->signal * 100;
 	else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
 		bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index ee0181778a42..029334835747 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -8,6 +8,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2008, Intel Corporation
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2018        Intel 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
@@ -27,7 +28,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 				 u32 sta_flags, u8 *bssid,
 				 struct ieee80211_csa_ie *csa_ie)
 {
-	enum nl80211_band new_band;
+	enum nl80211_band new_band = current_band;
 	int new_freq;
 	u8 new_chan_no;
 	struct ieee80211_channel *new_chan;
@@ -55,15 +56,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 				elems->ext_chansw_ie->new_operating_class,
 				&new_band)) {
 			sdata_info(sdata,
-				   "cannot understand ECSA IE operating class %d, disconnecting\n",
+				   "cannot understand ECSA IE operating class, %d, ignoring\n",
 				   elems->ext_chansw_ie->new_operating_class);
-			return -EINVAL;
 		}
 		new_chan_no = elems->ext_chansw_ie->new_ch_num;
 		csa_ie->count = elems->ext_chansw_ie->count;
 		csa_ie->mode = elems->ext_chansw_ie->mode;
 	} else if (elems->ch_switch_ie) {
-		new_band = current_band;
 		new_chan_no = elems->ch_switch_ie->new_ch_num;
 		csa_ie->count = elems->ch_switch_ie->count;
 		csa_ie->mode = elems->ch_switch_ie->mode;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 0c5627f8a104..655c3d8b0d80 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -314,7 +314,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 
 	if (ieee80211_hw_check(hw, USES_RSS)) {
 		sta->pcpu_rx_stats =
-			alloc_percpu(struct ieee80211_sta_rx_stats);
+			alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp);
 		if (!sta->pcpu_rx_stats)
 			goto free;
 	}
@@ -433,6 +433,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 	if (sta->sta.txq[0])
 		kfree(to_txq_info(sta->sta.txq[0]));
 free:
+	free_percpu(sta->pcpu_rx_stats);
 #ifdef CONFIG_MAC80211_MESH
 	kfree(sta->mesh);
 #endif
@@ -2287,6 +2288,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 		sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
 		sinfo->expected_throughput = thr;
 	}
+
+	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL)) &&
+	    sta->status_stats.ack_signal_filled) {
+		sinfo->ack_signal = sta->status_stats.last_ack_signal;
+		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
+	}
 }
 
 u32 sta_get_expected_throughput(struct sta_info *sta)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index cd53619435b6..f64eb86ca64b 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -548,6 +548,8 @@ struct sta_info {
 		u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
 		u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
 		unsigned long last_ack;
+		s8 last_ack_signal;
+		bool ack_signal_filled;
 	} status_stats;
 
 	/* Updated from TX path only, no locking requirements */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index da7427a41529..743e89c5926c 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -187,9 +187,16 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
 	struct ieee80211_mgmt *mgmt = (void *) skb->data;
 	struct ieee80211_local *local = sta->local;
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
 
-	if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
+	if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
 		sta->status_stats.last_ack = jiffies;
+		if (txinfo->status.is_valid_ack_signal) {
+			sta->status_stats.last_ack_signal =
+					 (s8)txinfo->status.ack_signal;
+			sta->status_stats.ack_signal_filled = true;
+		}
+	}
 
 	if (ieee80211_is_data_qos(mgmt->frame_control)) {
 		struct ieee80211_hdr *hdr = (void *) skb->data;
@@ -487,6 +494,8 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
 			    ieee80211_is_qos_nullfunc(hdr->frame_control))
 				cfg80211_probe_status(sdata->dev, hdr->addr1,
 						      cookie, acked,
+						      info->status.ack_signal,
+						      info->status.is_valid_ack_signal,
 						      GFP_ATOMIC);
 			else
 				cfg80211_mgmt_tx_status(&sdata->wdev, cookie,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 25904af38839..933c67b5f845 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -797,7 +797,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-	u8 *qc;
 	int tid;
 
 	/*
@@ -844,9 +843,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 		return TX_CONTINUE;
 
 	/* include per-STA, per-TID sequence counter */
-
-	qc = ieee80211_get_qos_ctl(hdr);
-	tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+	tid = ieee80211_get_tid(hdr);
 	tx->sta->tx_stats.msdu[tid]++;
 
 	hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
@@ -1158,7 +1155,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	int tid;
-	u8 *qc;
 
 	memset(tx, 0, sizeof(*tx));
 	tx->skb = skb;
@@ -1198,8 +1194,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 	    !ieee80211_hw_check(&local->hw, TX_AMPDU_SETUP_IN_HW)) {
 		struct tid_ampdu_tx *tid_tx;
 
-		qc = ieee80211_get_qos_ctl(hdr);
-		tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+		tid = ieee80211_get_tid(hdr);
 
 		tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
 		if (tid_tx) {
@@ -1921,7 +1916,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_hdr *hdr;
 	int headroom;
 	bool may_encrypt;
 
@@ -3574,6 +3569,14 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 	if (!IS_ERR_OR_NULL(sta)) {
 		struct ieee80211_fast_tx *fast_tx;
 
+		/* We need a bit of data queued to build aggregates properly, so
+		 * instruct the TCP stack to allow more than a single ms of data
+		 * to be queued in the stack. The value is a bit-shift of 1
+		 * second, so 8 is ~4ms of queued data. Only affects local TCP
+		 * sockets.
+		 */
+		sk_pacing_shift_update(skb->sk, 8);
+
 		fast_tx = rcu_dereference(sta->fast_tx);
 
 		if (fast_tx &&
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index b9276ac849fa..5714dee76b12 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -447,6 +447,7 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 				  enum nl80211_band band)
 {
 	enum ieee80211_sta_rx_bandwidth new_bw;
+	struct sta_opmode_info sta_opmode = {};
 	u32 changed = 0;
 	u8 nss;
 
@@ -460,7 +461,9 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 
 	if (sta->sta.rx_nss != nss) {
 		sta->sta.rx_nss = nss;
+		sta_opmode.rx_nss = nss;
 		changed |= IEEE80211_RC_NSS_CHANGED;
+		sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
 	}
 
 	switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
@@ -481,9 +484,15 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 	new_bw = ieee80211_sta_cur_vht_bw(sta);
 	if (new_bw != sta->sta.bandwidth) {
 		sta->sta.bandwidth = new_bw;
+		sta_opmode.bw = new_bw;
 		changed |= IEEE80211_RC_BW_CHANGED;
+		sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED;
 	}
 
+	if (sta_opmode.changed)
+		cfg80211_sta_opmode_change_notify(sdata->dev, sta->addr,
+						  &sta_opmode, GFP_KERNEL);
+
 	return changed;
 }
 
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 785056cb76f6..58d0b258b684 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -340,7 +340,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
 	a4_included = ieee80211_has_a4(hdr->frame_control);
 
 	if (ieee80211_is_data_qos(hdr->frame_control))
-		qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+		qos_tid = ieee80211_get_tid(hdr);
 	else
 		qos_tid = 0;
 
@@ -601,8 +601,7 @@ static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad)
 	aad[23] = 0;
 
 	if (ieee80211_is_data_qos(hdr->frame_control))
-		qos_tid = *ieee80211_get_qos_ctl(hdr) &
-			IEEE80211_QOS_CTL_TID_MASK;
+		qos_tid = ieee80211_get_tid(hdr);
 	else
 		qos_tid = 0;
 
@@ -867,8 +866,7 @@ ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
 		return RX_DROP_UNUSABLE;
 
 	if (ieee80211_is_data_qos(hdr->frame_control))
-		qos_tid = *ieee80211_get_qos_ctl(hdr) &
-				IEEE80211_QOS_CTL_TID_MASK;
+		qos_tid = ieee80211_get_tid(hdr);
 	else
 		qos_tid = 0;
 
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 0f6b8172fb9a..d72cc786c7b7 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -629,6 +629,7 @@ static void __net_exit netfilter_net_exit(struct net *net)
 static struct pernet_operations netfilter_net_ops = {
 	.init = netfilter_net_init,
 	.exit = netfilter_net_exit,
+	.async = true,
 };
 
 int __init netfilter_init(void)
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index bcd9b7bde4ee..569631d2b2a1 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -436,7 +436,7 @@ static bool tcp_state_active(int state)
 	return tcp_state_active_table[state];
 }
 
-static struct tcp_states_t tcp_states [] = {
+static struct tcp_states_t tcp_states[] = {
 /*	INPUT */
 /*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
 /*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
@@ -459,7 +459,7 @@ static struct tcp_states_t tcp_states [] = {
 /*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
 };
 
-static struct tcp_states_t tcp_states_dos [] = {
+static struct tcp_states_t tcp_states_dos[] = {
 /*	INPUT */
 /*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
 /*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSA }},
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index c2c1b16b7538..1ba3da51050d 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -577,6 +577,7 @@ static void __net_exit nf_log_net_exit(struct net *net)
 static struct pernet_operations nf_log_net_ops = {
 	.init = nf_log_net_init,
 	.exit = nf_log_net_exit,
+	.async = true,
 };
 
 int __init netfilter_log_init(void)
diff --git a/net/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c
index fbce552a796e..7d7466dbf663 100644
--- a/net/netfilter/nf_nat_proto_common.c
+++ b/net/netfilter/nf_nat_proto_common.c
@@ -41,7 +41,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,
 				 const struct nf_conn *ct,
 				 u16 *rover)
 {
-	unsigned int range_size, min, i;
+	unsigned int range_size, min, max, i;
 	__be16 *portptr;
 	u_int16_t off;
 
@@ -71,7 +71,10 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,
 		}
 	} else {
 		min = ntohs(range->min_proto.all);
-		range_size = ntohs(range->max_proto.all) - min + 1;
+		max = ntohs(range->max_proto.all);
+		if (unlikely(max < min))
+			swap(max, min);
+		range_size = max - min + 1;
 	}
 
 	if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 2f685ee1f9c8..d9deebe599ec 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -434,36 +434,35 @@ int xt_check_match(struct xt_mtchk_param *par,
 		 * ebt_among is exempt from centralized matchsize checking
 		 * because it uses a dynamic-size data set.
 		 */
-		pr_err("%s_tables: %s.%u match: invalid size "
-		       "%u (kernel) != (user) %u\n",
-		       xt_prefix[par->family], par->match->name,
-		       par->match->revision,
-		       XT_ALIGN(par->match->matchsize), size);
+		pr_err_ratelimited("%s_tables: %s.%u match: invalid size %u (kernel) != (user) %u\n",
+				   xt_prefix[par->family], par->match->name,
+				   par->match->revision,
+				   XT_ALIGN(par->match->matchsize), size);
 		return -EINVAL;
 	}
 	if (par->match->table != NULL &&
 	    strcmp(par->match->table, par->table) != 0) {
-		pr_err("%s_tables: %s match: only valid in %s table, not %s\n",
-		       xt_prefix[par->family], par->match->name,
-		       par->match->table, par->table);
+		pr_info_ratelimited("%s_tables: %s match: only valid in %s table, not %s\n",
+				    xt_prefix[par->family], par->match->name,
+				    par->match->table, par->table);
 		return -EINVAL;
 	}
 	if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
 		char used[64], allow[64];
 
-		pr_err("%s_tables: %s match: used from hooks %s, but only "
-		       "valid from %s\n",
-		       xt_prefix[par->family], par->match->name,
-		       textify_hooks(used, sizeof(used), par->hook_mask,
-		                     par->family),
-		       textify_hooks(allow, sizeof(allow), par->match->hooks,
-		                     par->family));
+		pr_info_ratelimited("%s_tables: %s match: used from hooks %s, but only valid from %s\n",
+				    xt_prefix[par->family], par->match->name,
+				    textify_hooks(used, sizeof(used),
+						  par->hook_mask, par->family),
+				    textify_hooks(allow, sizeof(allow),
+						  par->match->hooks,
+						  par->family));
 		return -EINVAL;
 	}
 	if (par->match->proto && (par->match->proto != proto || inv_proto)) {
-		pr_err("%s_tables: %s match: only valid for protocol %u\n",
-		       xt_prefix[par->family], par->match->name,
-		       par->match->proto);
+		pr_info_ratelimited("%s_tables: %s match: only valid for protocol %u\n",
+				    xt_prefix[par->family], par->match->name,
+				    par->match->proto);
 		return -EINVAL;
 	}
 	if (par->match->checkentry != NULL) {
@@ -814,36 +813,35 @@ int xt_check_target(struct xt_tgchk_param *par,
 	int ret;
 
 	if (XT_ALIGN(par->target->targetsize) != size) {
-		pr_err("%s_tables: %s.%u target: invalid size "
-		       "%u (kernel) != (user) %u\n",
-		       xt_prefix[par->family], par->target->name,
-		       par->target->revision,
-		       XT_ALIGN(par->target->targetsize), size);
+		pr_err_ratelimited("%s_tables: %s.%u target: invalid size %u (kernel) != (user) %u\n",
+				   xt_prefix[par->family], par->target->name,
+				   par->target->revision,
+				   XT_ALIGN(par->target->targetsize), size);
 		return -EINVAL;
 	}
 	if (par->target->table != NULL &&
 	    strcmp(par->target->table, par->table) != 0) {
-		pr_err("%s_tables: %s target: only valid in %s table, not %s\n",
-		       xt_prefix[par->family], par->target->name,
-		       par->target->table, par->table);
+		pr_info_ratelimited("%s_tables: %s target: only valid in %s table, not %s\n",
+				    xt_prefix[par->family], par->target->name,
+				    par->target->table, par->table);
 		return -EINVAL;
 	}
 	if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
 		char used[64], allow[64];
 
-		pr_err("%s_tables: %s target: used from hooks %s, but only "
-		       "usable from %s\n",
-		       xt_prefix[par->family], par->target->name,
-		       textify_hooks(used, sizeof(used), par->hook_mask,
-		                     par->family),
-		       textify_hooks(allow, sizeof(allow), par->target->hooks,
-		                     par->family));
+		pr_info_ratelimited("%s_tables: %s target: used from hooks %s, but only usable from %s\n",
+				    xt_prefix[par->family], par->target->name,
+				    textify_hooks(used, sizeof(used),
+						  par->hook_mask, par->family),
+				    textify_hooks(allow, sizeof(allow),
+						  par->target->hooks,
+						  par->family));
 		return -EINVAL;
 	}
 	if (par->target->proto && (par->target->proto != proto || inv_proto)) {
-		pr_err("%s_tables: %s target: only valid for protocol %u\n",
-		       xt_prefix[par->family], par->target->name,
-		       par->target->proto);
+		pr_info_ratelimited("%s_tables: %s target: only valid for protocol %u\n",
+				    xt_prefix[par->family], par->target->name,
+				    par->target->proto);
 		return -EINVAL;
 	}
 	if (par->target->checkentry != NULL) {
@@ -1004,10 +1002,6 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
 	if (sz < sizeof(*info))
 		return NULL;
 
-	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-	if ((size >> PAGE_SHIFT) + 2 > totalram_pages)
-		return NULL;
-
 	/* __GFP_NORETRY is not fully supported by kvmalloc but it should
 	 * work reasonably well if sz is too large and bail out rather
 	 * than shoot all processes down before realizing there is nothing
@@ -1765,6 +1759,7 @@ static void __net_exit xt_net_exit(struct net *net)
 static struct pernet_operations xt_net_ops = {
 	.init = xt_net_init,
 	.exit = xt_net_exit,
+	.async = true,
 };
 
 static int __init xt_init(void)
diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c
index c502419d6306..f368ee6741db 100644
--- a/net/netfilter/xt_AUDIT.c
+++ b/net/netfilter/xt_AUDIT.c
@@ -120,8 +120,8 @@ static int audit_tg_check(const struct xt_tgchk_param *par)
 	const struct xt_audit_info *info = par->targinfo;
 
 	if (info->type > XT_AUDIT_TYPE_MAX) {
-		pr_info("Audit type out of range (valid range: 0..%hhu)\n",
-			XT_AUDIT_TYPE_MAX);
+		pr_info_ratelimited("Audit type out of range (valid range: 0..%hhu)\n",
+				    XT_AUDIT_TYPE_MAX);
 		return -ERANGE;
 	}
 
diff --git a/net/netfilter/xt_CHECKSUM.c b/net/netfilter/xt_CHECKSUM.c
index 0f642ef8cd26..9f4151ec3e06 100644
--- a/net/netfilter/xt_CHECKSUM.c
+++ b/net/netfilter/xt_CHECKSUM.c
@@ -36,13 +36,13 @@ static int checksum_tg_check(const struct xt_tgchk_param *par)
 	const struct xt_CHECKSUM_info *einfo = par->targinfo;
 
 	if (einfo->operation & ~XT_CHECKSUM_OP_FILL) {
-		pr_info("unsupported CHECKSUM operation %x\n", einfo->operation);
+		pr_info_ratelimited("unsupported CHECKSUM operation %x\n",
+				    einfo->operation);
 		return -EINVAL;
 	}
-	if (!einfo->operation) {
-		pr_info("no CHECKSUM operation enabled\n");
+	if (!einfo->operation)
 		return -EINVAL;
-	}
+
 	return 0;
 }
 
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index da56c06a443c..f3f1caac949b 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -91,8 +91,8 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par)
 
 	if (strcmp(par->table, "mangle") != 0 &&
 	    strcmp(par->table, "security") != 0) {
-		pr_info("target only valid in the \'mangle\' "
-			"or \'security\' tables, not \'%s\'.\n", par->table);
+		pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
+				    par->table);
 		return -EINVAL;
 	}
 
@@ -102,14 +102,14 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par)
 		break;
 
 	default:
-		pr_info("invalid mode: %hu\n", info->mode);
+		pr_info_ratelimited("invalid mode: %hu\n", info->mode);
 		return -EINVAL;
 	}
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0)
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 	return ret;
 }
 
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 5a152e2acfd5..8790190c6feb 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -82,15 +82,14 @@ xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
 
 	proto = xt_ct_find_proto(par);
 	if (!proto) {
-		pr_info("You must specify a L4 protocol, and not use "
-			"inversions on it.\n");
+		pr_info_ratelimited("You must specify a L4 protocol and not use inversions on it\n");
 		return -ENOENT;
 	}
 
 	helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
 						    proto);
 	if (helper == NULL) {
-		pr_info("No such helper \"%s\"\n", helper_name);
+		pr_info_ratelimited("No such helper \"%s\"\n", helper_name);
 		return -ENOENT;
 	}
 
@@ -124,6 +123,7 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
 	const struct nf_conntrack_l4proto *l4proto;
 	struct ctnl_timeout *timeout;
 	struct nf_conn_timeout *timeout_ext;
+	const char *errmsg = NULL;
 	int ret = 0;
 	u8 proto;
 
@@ -131,29 +131,29 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
 	timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
 	if (timeout_find_get == NULL) {
 		ret = -ENOENT;
-		pr_info("Timeout policy base is empty\n");
+		errmsg = "Timeout policy base is empty";
 		goto out;
 	}
 
 	proto = xt_ct_find_proto(par);
 	if (!proto) {
 		ret = -EINVAL;
-		pr_info("You must specify a L4 protocol, and not use "
-			"inversions on it.\n");
+		errmsg = "You must specify a L4 protocol and not use inversions on it";
 		goto out;
 	}
 
 	timeout = timeout_find_get(par->net, timeout_name);
 	if (timeout == NULL) {
 		ret = -ENOENT;
-		pr_info("No such timeout policy \"%s\"\n", timeout_name);
+		pr_info_ratelimited("No such timeout policy \"%s\"\n",
+				    timeout_name);
 		goto out;
 	}
 
 	if (timeout->l3num != par->family) {
 		ret = -EINVAL;
-		pr_info("Timeout policy `%s' can only be used by L3 protocol "
-			"number %d\n", timeout_name, timeout->l3num);
+		pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n",
+				    timeout_name, 3, timeout->l3num);
 		goto err_put_timeout;
 	}
 	/* Make sure the timeout policy matches any existing protocol tracker,
@@ -162,9 +162,8 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
 	l4proto = __nf_ct_l4proto_find(par->family, proto);
 	if (timeout->l4proto->l4proto != l4proto->l4proto) {
 		ret = -EINVAL;
-		pr_info("Timeout policy `%s' can only be used by L4 protocol "
-			"number %d\n",
-			timeout_name, timeout->l4proto->l4proto);
+		pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n",
+				    timeout_name, 4, timeout->l4proto->l4proto);
 		goto err_put_timeout;
 	}
 	timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
@@ -180,6 +179,8 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
 	__xt_ct_tg_timeout_put(timeout);
 out:
 	rcu_read_unlock();
+	if (errmsg)
+		pr_info_ratelimited("%s\n", errmsg);
 	return ret;
 #else
 	return -EOPNOTSUPP;
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
index 3f83d38c4e5b..098ed851b7a7 100644
--- a/net/netfilter/xt_DSCP.c
+++ b/net/netfilter/xt_DSCP.c
@@ -66,10 +66,8 @@ static int dscp_tg_check(const struct xt_tgchk_param *par)
 {
 	const struct xt_DSCP_info *info = par->targinfo;
 
-	if (info->dscp > XT_DSCP_MAX) {
-		pr_info("dscp %x out of range\n", info->dscp);
+	if (info->dscp > XT_DSCP_MAX)
 		return -EDOM;
-	}
 	return 0;
 }
 
diff --git a/net/netfilter/xt_HL.c b/net/netfilter/xt_HL.c
index 1535e87ed9bd..4653b071bed4 100644
--- a/net/netfilter/xt_HL.c
+++ b/net/netfilter/xt_HL.c
@@ -105,10 +105,8 @@ static int ttl_tg_check(const struct xt_tgchk_param *par)
 {
 	const struct ipt_TTL_info *info = par->targinfo;
 
-	if (info->mode > IPT_TTL_MAXMODE) {
-		pr_info("TTL: invalid or unknown mode %u\n", info->mode);
+	if (info->mode > IPT_TTL_MAXMODE)
 		return -EINVAL;
-	}
 	if (info->mode != IPT_TTL_SET && info->ttl == 0)
 		return -EINVAL;
 	return 0;
@@ -118,15 +116,10 @@ static int hl_tg6_check(const struct xt_tgchk_param *par)
 {
 	const struct ip6t_HL_info *info = par->targinfo;
 
-	if (info->mode > IP6T_HL_MAXMODE) {
-		pr_info("invalid or unknown mode %u\n", info->mode);
+	if (info->mode > IP6T_HL_MAXMODE)
 		return -EINVAL;
-	}
-	if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
-		pr_info("increment/decrement does not "
-			"make sense with value 0\n");
+	if (info->mode != IP6T_HL_SET && info->hop_limit == 0)
 		return -EINVAL;
-	}
 	return 0;
 }
 
diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c
index 60e6dbe12460..9c75f419cd80 100644
--- a/net/netfilter/xt_HMARK.c
+++ b/net/netfilter/xt_HMARK.c
@@ -9,6 +9,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/icmp.h>
@@ -312,29 +314,30 @@ hmark_tg_v4(struct sk_buff *skb, const struct xt_action_param *par)
 static int hmark_tg_check(const struct xt_tgchk_param *par)
 {
 	const struct xt_hmark_info *info = par->targinfo;
+	const char *errmsg = "proto mask must be zero with L3 mode";
 
-	if (!info->hmodulus) {
-		pr_info("xt_HMARK: hash modulus can't be zero\n");
+	if (!info->hmodulus)
 		return -EINVAL;
-	}
+
 	if (info->proto_mask &&
-	    (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))) {
-		pr_info("xt_HMARK: proto mask must be zero with L3 mode\n");
-		return -EINVAL;
-	}
+	    (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)))
+		goto err;
+
 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK) &&
 	    (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT_MASK) |
-			     XT_HMARK_FLAG(XT_HMARK_DPORT_MASK)))) {
-		pr_info("xt_HMARK: spi-mask and port-mask can't be combined\n");
+			     XT_HMARK_FLAG(XT_HMARK_DPORT_MASK))))
 		return -EINVAL;
-	}
+
 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI) &&
 	    (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT) |
 			     XT_HMARK_FLAG(XT_HMARK_DPORT)))) {
-		pr_info("xt_HMARK: spi-set and port-set can't be combined\n");
-		return -EINVAL;
+		errmsg = "spi-set and port-set can't be combined";
+		goto err;
 	}
 	return 0;
+err:
+	pr_info_ratelimited("%s\n", errmsg);
+	return -EINVAL;
 }
 
 static struct xt_target hmark_tg_reg[] __read_mostly = {
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index 6c2482b709b1..1ac6600bfafd 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -146,11 +146,11 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
 	timer_setup(&info->timer->timer, idletimer_tg_expired, 0);
 	info->timer->refcnt = 1;
 
+	INIT_WORK(&info->timer->work, idletimer_tg_work);
+
 	mod_timer(&info->timer->timer,
 		  msecs_to_jiffies(info->timeout * 1000) + jiffies);
 
-	INIT_WORK(&info->timer->work, idletimer_tg_work);
-
 	return 0;
 
 out_free_attr:
@@ -191,7 +191,10 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
 		pr_debug("timeout value is zero\n");
 		return -EINVAL;
 	}
-
+	if (info->timeout >= INT_MAX / 1000) {
+		pr_debug("timeout value is too big\n");
+		return -EINVAL;
+	}
 	if (info->label[0] == '\0' ||
 	    strnlen(info->label,
 		    MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c
index 1dcad893df78..19846445504d 100644
--- a/net/netfilter/xt_LED.c
+++ b/net/netfilter/xt_LED.c
@@ -111,10 +111,8 @@ static int led_tg_check(const struct xt_tgchk_param *par)
 	struct xt_led_info_internal *ledinternal;
 	int err;
 
-	if (ledinfo->id[0] == '\0') {
-		pr_info("No 'id' parameter given.\n");
+	if (ledinfo->id[0] == '\0')
 		return -EINVAL;
-	}
 
 	mutex_lock(&xt_led_mutex);
 
@@ -138,13 +136,14 @@ static int led_tg_check(const struct xt_tgchk_param *par)
 
 	err = led_trigger_register(&ledinternal->netfilter_led_trigger);
 	if (err) {
-		pr_err("Trigger name is already in use.\n");
+		pr_info_ratelimited("Trigger name is already in use.\n");
 		goto exit_alloc;
 	}
 
-	/* See if we need to set up a timer */
-	if (ledinfo->delay > 0)
-		timer_setup(&ledinternal->timer, led_timeout_callback, 0);
+	/* Since the letinternal timer can be shared between multiple targets,
+	 * always set it up, even if the current target does not need it
+	 */
+	timer_setup(&ledinternal->timer, led_timeout_callback, 0);
 
 	list_add_tail(&ledinternal->list, &xt_led_triggers);
 
@@ -181,8 +180,7 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par)
 
 	list_del(&ledinternal->list);
 
-	if (ledinfo->delay > 0)
-		del_timer_sync(&ledinternal->timer);
+	del_timer_sync(&ledinternal->timer);
 
 	led_trigger_unregister(&ledinternal->netfilter_led_trigger);
 
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index a360b99a958a..a9aca80a32ae 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -8,6 +8,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
@@ -67,13 +69,13 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par)
 	init_hashrandom(&jhash_initval);
 
 	if (info->queues_total == 0) {
-		pr_err("NFQUEUE: number of total queues is 0\n");
+		pr_info_ratelimited("number of total queues is 0\n");
 		return -EINVAL;
 	}
 	maxid = info->queues_total - 1 + info->queuenum;
 	if (maxid > 0xffff) {
-		pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n",
-		       info->queues_total, maxid);
+		pr_info_ratelimited("number of queues (%u) out of range (got %u)\n",
+				    info->queues_total, maxid);
 		return -ERANGE;
 	}
 	if (par->target->revision == 2 && info->flags > 1)
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index 9faf5e050b79..4ad5fe27e08b 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -60,18 +60,20 @@ static int checkentry_lsm(struct xt_secmark_target_info *info)
 				       &info->secid);
 	if (err) {
 		if (err == -EINVAL)
-			pr_info("invalid security context \'%s\'\n", info->secctx);
+			pr_info_ratelimited("invalid security context \'%s\'\n",
+					    info->secctx);
 		return err;
 	}
 
 	if (!info->secid) {
-		pr_info("unable to map security context \'%s\'\n", info->secctx);
+		pr_info_ratelimited("unable to map security context \'%s\'\n",
+				    info->secctx);
 		return -ENOENT;
 	}
 
 	err = security_secmark_relabel_packet(info->secid);
 	if (err) {
-		pr_info("unable to obtain relabeling permission\n");
+		pr_info_ratelimited("unable to obtain relabeling permission\n");
 		return err;
 	}
 
@@ -86,14 +88,14 @@ static int secmark_tg_check(const struct xt_tgchk_param *par)
 
 	if (strcmp(par->table, "mangle") != 0 &&
 	    strcmp(par->table, "security") != 0) {
-		pr_info("target only valid in the \'mangle\' "
-			"or \'security\' tables, not \'%s\'.\n", par->table);
+		pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
+				    par->table);
 		return -EINVAL;
 	}
 
 	if (mode && mode != info->mode) {
-		pr_info("mode already set to %hu cannot mix with "
-			"rules for mode %hu\n", mode, info->mode);
+		pr_info_ratelimited("mode already set to %hu cannot mix with rules for mode %hu\n",
+				    mode, info->mode);
 		return -EINVAL;
 	}
 
@@ -101,7 +103,7 @@ static int secmark_tg_check(const struct xt_tgchk_param *par)
 	case SECMARK_MODE_SEL:
 		break;
 	default:
-		pr_info("invalid mode: %hu\n", info->mode);
+		pr_info_ratelimited("invalid mode: %hu\n", info->mode);
 		return -EINVAL;
 	}
 
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 99bb8e410f22..98efb202f8b4 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -273,8 +273,7 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
 	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
 			   (1 << NF_INET_LOCAL_OUT) |
 			   (1 << NF_INET_POST_ROUTING))) != 0) {
-		pr_info("path-MTU clamping only supported in "
-			"FORWARD, OUTPUT and POSTROUTING hooks\n");
+		pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
 		return -EINVAL;
 	}
 	if (par->nft_compat)
@@ -283,7 +282,7 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
 	xt_ematch_foreach(ematch, e)
 		if (find_syn_match(ematch))
 			return 0;
-	pr_info("Only works on TCP SYN packets\n");
+	pr_info_ratelimited("Only works on TCP SYN packets\n");
 	return -EINVAL;
 }
 
@@ -298,8 +297,7 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
 	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
 			   (1 << NF_INET_LOCAL_OUT) |
 			   (1 << NF_INET_POST_ROUTING))) != 0) {
-		pr_info("path-MTU clamping only supported in "
-			"FORWARD, OUTPUT and POSTROUTING hooks\n");
+		pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
 		return -EINVAL;
 	}
 	if (par->nft_compat)
@@ -308,7 +306,7 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
 	xt_ematch_foreach(ematch, e)
 		if (find_syn_match(ematch))
 			return 0;
-	pr_info("Only works on TCP SYN packets\n");
+	pr_info_ratelimited("Only works on TCP SYN packets\n");
 	return -EINVAL;
 }
 #endif
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index 17d7705e3bd4..8c89323c06af 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -540,8 +540,7 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
 	    !(i->invflags & IP6T_INV_PROTO))
 		return 0;
 
-	pr_info("Can be used only in combination with "
-		"either -p tcp or -p udp\n");
+	pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
 	return -EINVAL;
 }
 #endif
@@ -559,8 +558,7 @@ static int tproxy_tg4_check(const struct xt_tgchk_param *par)
 	    && !(i->invflags & IPT_INV_PROTO))
 		return 0;
 
-	pr_info("Can be used only in combination with "
-		"either -p tcp or -p udp\n");
+	pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
 	return -EINVAL;
 }
 
diff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c
index 911a7c0da504..89e281b3bfc2 100644
--- a/net/netfilter/xt_addrtype.c
+++ b/net/netfilter/xt_addrtype.c
@@ -164,48 +164,47 @@ addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 
 static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
 {
+	const char *errmsg = "both incoming and outgoing interface limitation cannot be selected";
 	struct xt_addrtype_info_v1 *info = par->matchinfo;
 
 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&
-	    info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
-		pr_info("both incoming and outgoing "
-			"interface limitation cannot be selected\n");
-		return -EINVAL;
-	}
+	    info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
+		goto err;
 
 	if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
 	    (1 << NF_INET_LOCAL_IN)) &&
 	    info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
-		pr_info("output interface limitation "
-			"not valid in PREROUTING and INPUT\n");
-		return -EINVAL;
+		errmsg = "output interface limitation not valid in PREROUTING and INPUT";
+		goto err;
 	}
 
 	if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
 	    (1 << NF_INET_LOCAL_OUT)) &&
 	    info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) {
-		pr_info("input interface limitation "
-			"not valid in POSTROUTING and OUTPUT\n");
-		return -EINVAL;
+		errmsg = "input interface limitation not valid in POSTROUTING and OUTPUT";
+		goto err;
 	}
 
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 	if (par->family == NFPROTO_IPV6) {
 		if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) {
-			pr_err("ipv6 BLACKHOLE matching not supported\n");
-			return -EINVAL;
+			errmsg = "ipv6 BLACKHOLE matching not supported";
+			goto err;
 		}
 		if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) {
-			pr_err("ipv6 PROHIBIT (THROW, NAT ..) matching not supported\n");
-			return -EINVAL;
+			errmsg = "ipv6 PROHIBIT (THROW, NAT ..) matching not supported";
+			goto err;
 		}
 		if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) {
-			pr_err("ipv6 does not support BROADCAST matching\n");
-			return -EINVAL;
+			errmsg = "ipv6 does not support BROADCAST matching";
+			goto err;
 		}
 	}
 #endif
 	return 0;
+err:
+	pr_info_ratelimited("%s\n", errmsg);
+	return -EINVAL;
 }
 
 static struct xt_match addrtype_mt_reg[] __read_mostly = {
diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c
index 06b090d8e901..a2cf8a6236d6 100644
--- a/net/netfilter/xt_bpf.c
+++ b/net/netfilter/xt_bpf.c
@@ -7,6 +7,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/skbuff.h>
@@ -34,7 +36,7 @@ static int __bpf_mt_check_bytecode(struct sock_filter *insns, __u16 len,
 	program.filter = insns;
 
 	if (bpf_prog_create(ret, &program)) {
-		pr_info("bpf: check failed: parse error\n");
+		pr_info_ratelimited("check failed: parse error\n");
 		return -EINVAL;
 	}
 
diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c
index 891f4e7e8ea7..7df2dece57d3 100644
--- a/net/netfilter/xt_cgroup.c
+++ b/net/netfilter/xt_cgroup.c
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/skbuff.h>
 #include <linux/module.h>
 #include <linux/netfilter/x_tables.h>
@@ -48,7 +50,7 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
 	}
 
 	if (info->has_path && info->has_classid) {
-		pr_info("xt_cgroup: both path and classid specified\n");
+		pr_info_ratelimited("path and classid specified\n");
 		return -EINVAL;
 	}
 
@@ -56,8 +58,8 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
 	if (info->has_path) {
 		cgrp = cgroup_get_from_path(info->path);
 		if (IS_ERR(cgrp)) {
-			pr_info("xt_cgroup: invalid path, errno=%ld\n",
-				PTR_ERR(cgrp));
+			pr_info_ratelimited("invalid path, errno=%ld\n",
+					    PTR_ERR(cgrp));
 			return -EINVAL;
 		}
 		info->priv = cgrp;
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index 57ef175dfbfa..0068688995c8 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -135,14 +135,12 @@ static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
 	struct xt_cluster_match_info *info = par->matchinfo;
 
 	if (info->total_nodes > XT_CLUSTER_NODES_MAX) {
-		pr_info("you have exceeded the maximum "
-			"number of cluster nodes (%u > %u)\n",
-			info->total_nodes, XT_CLUSTER_NODES_MAX);
+		pr_info_ratelimited("you have exceeded the maximum number of cluster nodes (%u > %u)\n",
+				    info->total_nodes, XT_CLUSTER_NODES_MAX);
 		return -EINVAL;
 	}
 	if (info->node_mask >= (1ULL << info->total_nodes)) {
-		pr_info("this node mask cannot be "
-			"higher than the total number of nodes\n");
+		pr_info_ratelimited("node mask cannot exceed total number of nodes\n");
 		return -EDOM;
 	}
 	return 0;
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index cad0b7b5eb35..93cb018c3055 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -112,8 +112,8 @@ static int connbytes_mt_check(const struct xt_mtchk_param *par)
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0)
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 
 	/*
 	 * This filter cannot function correctly unless connection tracking
diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c
index 23372879e6e3..4fa4efd24353 100644
--- a/net/netfilter/xt_connlabel.c
+++ b/net/netfilter/xt_connlabel.c
@@ -57,14 +57,15 @@ static int connlabel_mt_check(const struct xt_mtchk_param *par)
 	int ret;
 
 	if (info->options & ~options) {
-		pr_err("Unknown options in mask %x\n", info->options);
+		pr_info_ratelimited("Unknown options in mask %x\n",
+				    info->options);
 		return -EINVAL;
 	}
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0) {
-		pr_info("cannot load conntrack support for proto=%u\n",
-							par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 		return ret;
 	}
 
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index ec377cc6a369..809639ce6f5a 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -79,8 +79,8 @@ static int connmark_tg_check(const struct xt_tgchk_param *par)
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0)
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 	return ret;
 }
 
@@ -109,8 +109,8 @@ static int connmark_mt_check(const struct xt_mtchk_param *par)
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0)
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 	return ret;
 }
 
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 39cf1d019240..df80fe7d391c 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -272,8 +272,8 @@ static int conntrack_mt_check(const struct xt_mtchk_param *par)
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0)
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 	return ret;
 }
 
diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c
index 236ac8008909..a4c2b862f820 100644
--- a/net/netfilter/xt_dscp.c
+++ b/net/netfilter/xt_dscp.c
@@ -46,10 +46,8 @@ static int dscp_mt_check(const struct xt_mtchk_param *par)
 {
 	const struct xt_dscp_info *info = par->matchinfo;
 
-	if (info->dscp > XT_DSCP_MAX) {
-		pr_info("dscp %x out of range\n", info->dscp);
+	if (info->dscp > XT_DSCP_MAX)
 		return -EDOM;
-	}
 
 	return 0;
 }
diff --git a/net/netfilter/xt_ecn.c b/net/netfilter/xt_ecn.c
index 3c831a8efebc..c7ad4afa5fb8 100644
--- a/net/netfilter/xt_ecn.c
+++ b/net/netfilter/xt_ecn.c
@@ -97,7 +97,7 @@ static int ecn_mt_check4(const struct xt_mtchk_param *par)
 
 	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
 	    (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
-		pr_info("cannot match TCP bits in rule for non-tcp packets\n");
+		pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n");
 		return -EINVAL;
 	}
 
@@ -139,7 +139,7 @@ static int ecn_mt_check6(const struct xt_mtchk_param *par)
 
 	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
 	    (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) {
-		pr_info("cannot match TCP bits in rule for non-tcp packets\n");
+		pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n");
 		return -EINVAL;
 	}
 
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index ca6847403ca2..66f5aca62a08 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -523,7 +523,8 @@ static u64 user2rate(u64 user)
 	if (user != 0) {
 		return div64_u64(XT_HASHLIMIT_SCALE_v2, user);
 	} else {
-		pr_warn("invalid rate from userspace: %llu\n", user);
+		pr_info_ratelimited("invalid rate from userspace: %llu\n",
+				    user);
 		return 0;
 	}
 }
@@ -774,7 +775,7 @@ hashlimit_mt_common(const struct sk_buff *skb, struct xt_action_param *par,
 		if (!dh->rateinfo.prev_window &&
 		    (dh->rateinfo.current_rate <= dh->rateinfo.burst)) {
 			spin_unlock(&dh->lock);
-			rcu_read_unlock_bh();
+			local_bh_enable();
 			return !(cfg->mode & XT_HASHLIMIT_INVERT);
 		} else {
 			goto overlimit;
@@ -865,33 +866,34 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
 	}
 
 	if (cfg->mode & ~XT_HASHLIMIT_ALL) {
-		pr_info("Unknown mode mask %X, kernel too old?\n",
-						cfg->mode);
+		pr_info_ratelimited("Unknown mode mask %X, kernel too old?\n",
+				    cfg->mode);
 		return -EINVAL;
 	}
 
 	/* Check for overflow. */
 	if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
 		if (cfg->avg == 0 || cfg->avg > U32_MAX) {
-			pr_info("hashlimit invalid rate\n");
+			pr_info_ratelimited("invalid rate\n");
 			return -ERANGE;
 		}
 
 		if (cfg->interval == 0) {
-			pr_info("hashlimit invalid interval\n");
+			pr_info_ratelimited("invalid interval\n");
 			return -EINVAL;
 		}
 	} else if (cfg->mode & XT_HASHLIMIT_BYTES) {
 		if (user2credits_byte(cfg->avg) == 0) {
-			pr_info("overflow, rate too high: %llu\n", cfg->avg);
+			pr_info_ratelimited("overflow, rate too high: %llu\n",
+					    cfg->avg);
 			return -EINVAL;
 		}
 	} else if (cfg->burst == 0 ||
-		    user2credits(cfg->avg * cfg->burst, revision) <
-		    user2credits(cfg->avg, revision)) {
-			pr_info("overflow, try lower: %llu/%llu\n",
-				cfg->avg, cfg->burst);
-			return -ERANGE;
+		   user2credits(cfg->avg * cfg->burst, revision) <
+		   user2credits(cfg->avg, revision)) {
+		pr_info_ratelimited("overflow, try lower: %llu/%llu\n",
+				    cfg->avg, cfg->burst);
+		return -ERANGE;
 	}
 
 	mutex_lock(&hashlimit_mutex);
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index 38a78151c0e9..fd077aeaaed9 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -61,8 +61,8 @@ static int helper_mt_check(const struct xt_mtchk_param *par)
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0) {
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 		return ret;
 	}
 	info->name[sizeof(info->name) - 1] = '\0';
diff --git a/net/netfilter/xt_ipcomp.c b/net/netfilter/xt_ipcomp.c
index 7ca64a50db04..57f1df575701 100644
--- a/net/netfilter/xt_ipcomp.c
+++ b/net/netfilter/xt_ipcomp.c
@@ -72,7 +72,7 @@ static int comp_mt_check(const struct xt_mtchk_param *par)
 
 	/* Must specify no unknown invflags */
 	if (compinfo->invflags & ~XT_IPCOMP_INV_MASK) {
-		pr_err("unknown flags %X\n", compinfo->invflags);
+		pr_info_ratelimited("unknown flags %X\n", compinfo->invflags);
 		return -EINVAL;
 	}
 	return 0;
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c
index 42540d26c2b8..1d950a6100af 100644
--- a/net/netfilter/xt_ipvs.c
+++ b/net/netfilter/xt_ipvs.c
@@ -158,7 +158,8 @@ static int ipvs_mt_check(const struct xt_mtchk_param *par)
 	    && par->family != NFPROTO_IPV6
 #endif
 		) {
-		pr_info("protocol family %u not supported\n", par->family);
+		pr_info_ratelimited("protocol family %u not supported\n",
+				    par->family);
 		return -EINVAL;
 	}
 
diff --git a/net/netfilter/xt_l2tp.c b/net/netfilter/xt_l2tp.c
index 8aee572771f2..c43482bf48e6 100644
--- a/net/netfilter/xt_l2tp.c
+++ b/net/netfilter/xt_l2tp.c
@@ -216,7 +216,7 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par)
 	/* Check for invalid flags */
 	if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION |
 			    XT_L2TP_TYPE)) {
-		pr_info("unknown flags: %x\n", info->flags);
+		pr_info_ratelimited("unknown flags: %x\n", info->flags);
 		return -EINVAL;
 	}
 
@@ -225,7 +225,8 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par)
 	    (!(info->flags & XT_L2TP_SID)) &&
 	    ((!(info->flags & XT_L2TP_TYPE)) ||
 	     (info->type != XT_L2TP_TYPE_CONTROL))) {
-		pr_info("invalid flags combination: %x\n", info->flags);
+		pr_info_ratelimited("invalid flags combination: %x\n",
+				    info->flags);
 		return -EINVAL;
 	}
 
@@ -234,19 +235,22 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par)
 	 */
 	if (info->flags & XT_L2TP_VERSION) {
 		if ((info->version < 2) || (info->version > 3)) {
-			pr_info("wrong L2TP version: %u\n", info->version);
+			pr_info_ratelimited("wrong L2TP version: %u\n",
+					    info->version);
 			return -EINVAL;
 		}
 
 		if (info->version == 2) {
 			if ((info->flags & XT_L2TP_TID) &&
 			    (info->tid > 0xffff)) {
-				pr_info("v2 tid > 0xffff: %u\n", info->tid);
+				pr_info_ratelimited("v2 tid > 0xffff: %u\n",
+						    info->tid);
 				return -EINVAL;
 			}
 			if ((info->flags & XT_L2TP_SID) &&
 			    (info->sid > 0xffff)) {
-				pr_info("v2 sid > 0xffff: %u\n", info->sid);
+				pr_info_ratelimited("v2 sid > 0xffff: %u\n",
+						    info->sid);
 				return -EINVAL;
 			}
 		}
@@ -268,13 +272,13 @@ static int l2tp_mt_check4(const struct xt_mtchk_param *par)
 
 	if ((ip->proto != IPPROTO_UDP) &&
 	    (ip->proto != IPPROTO_L2TP)) {
-		pr_info("missing protocol rule (udp|l2tpip)\n");
+		pr_info_ratelimited("missing protocol rule (udp|l2tpip)\n");
 		return -EINVAL;
 	}
 
 	if ((ip->proto == IPPROTO_L2TP) &&
 	    (info->version == 2)) {
-		pr_info("v2 doesn't support IP mode\n");
+		pr_info_ratelimited("v2 doesn't support IP mode\n");
 		return -EINVAL;
 	}
 
@@ -295,13 +299,13 @@ static int l2tp_mt_check6(const struct xt_mtchk_param *par)
 
 	if ((ip->proto != IPPROTO_UDP) &&
 	    (ip->proto != IPPROTO_L2TP)) {
-		pr_info("missing protocol rule (udp|l2tpip)\n");
+		pr_info_ratelimited("missing protocol rule (udp|l2tpip)\n");
 		return -EINVAL;
 	}
 
 	if ((ip->proto == IPPROTO_L2TP) &&
 	    (info->version == 2)) {
-		pr_info("v2 doesn't support IP mode\n");
+		pr_info_ratelimited("v2 doesn't support IP mode\n");
 		return -EINVAL;
 	}
 
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index 61403b77361c..55d18cd67635 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -106,8 +106,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
 	/* Check for overflow. */
 	if (r->burst == 0
 	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-		pr_info("Overflow, try lower: %u/%u\n",
-			r->avg, r->burst);
+		pr_info_ratelimited("Overflow, try lower: %u/%u\n",
+				    r->avg, r->burst);
 		return -ERANGE;
 	}
 
diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c
index 0fd14d1eb09d..bdb689cdc829 100644
--- a/net/netfilter/xt_nat.c
+++ b/net/netfilter/xt_nat.c
@@ -8,6 +8,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
@@ -19,8 +21,7 @@ static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
 	const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
 
 	if (mr->rangesize != 1) {
-		pr_info("%s: multiple ranges no longer supported\n",
-			par->target->name);
+		pr_info_ratelimited("multiple ranges no longer supported\n");
 		return -EINVAL;
 	}
 	return nf_ct_netns_get(par->net, par->family);
diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c
index 6f92d25590a8..c8674deed4eb 100644
--- a/net/netfilter/xt_nfacct.c
+++ b/net/netfilter/xt_nfacct.c
@@ -6,6 +6,8 @@
  * it under the terms of the GNU General Public License version 2 (or any
  * later at your option) as published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
@@ -39,8 +41,8 @@ nfacct_mt_checkentry(const struct xt_mtchk_param *par)
 
 	nfacct = nfnl_acct_find_get(par->net, info->name);
 	if (nfacct == NULL) {
-		pr_info("xt_nfacct: accounting object with name `%s' "
-			"does not exists\n", info->name);
+		pr_info_ratelimited("accounting object `%s' does not exists\n",
+				    info->name);
 		return -ENOENT;
 	}
 	info->nfacct = nfacct;
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index bb33598e4530..9d6d67b953ac 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -107,9 +107,7 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)
 	     info->invert & XT_PHYSDEV_OP_BRIDGED) &&
 	    par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
 	    (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
-		pr_info("using --physdev-out and --physdev-is-out are only "
-			"supported in the FORWARD and POSTROUTING chains with "
-			"bridged traffic.\n");
+		pr_info_ratelimited("--physdev-out and --physdev-is-out only supported in the FORWARD and POSTROUTING chains with bridged traffic\n");
 		if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
 			return -EINVAL;
 	}
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
index 5639fb03bdd9..13f8ccf946d6 100644
--- a/net/netfilter/xt_policy.c
+++ b/net/netfilter/xt_policy.c
@@ -132,26 +132,29 @@ policy_mt(const struct sk_buff *skb, struct xt_action_param *par)
 static int policy_mt_check(const struct xt_mtchk_param *par)
 {
 	const struct xt_policy_info *info = par->matchinfo;
+	const char *errmsg = "neither incoming nor outgoing policy selected";
+
+	if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))
+		goto err;
 
-	if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
-		pr_info("neither incoming nor outgoing policy selected\n");
-		return -EINVAL;
-	}
 	if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
 	    (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) {
-		pr_info("output policy not valid in PREROUTING and INPUT\n");
-		return -EINVAL;
+		errmsg = "output policy not valid in PREROUTING and INPUT";
+		goto err;
 	}
 	if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
 	    (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) {
-		pr_info("input policy not valid in POSTROUTING and OUTPUT\n");
-		return -EINVAL;
+		errmsg = "input policy not valid in POSTROUTING and OUTPUT";
+		goto err;
 	}
 	if (info->len > XT_POLICY_MAX_ELEM) {
-		pr_info("too many policy elements\n");
-		return -EINVAL;
+		errmsg = "too many policy elements";
+		goto err;
 	}
 	return 0;
+err:
+	pr_info_ratelimited("%s\n", errmsg);
+	return -EINVAL;
 }
 
 static struct xt_match policy_mt_reg[] __read_mostly = {
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 245fa350a7a8..6d232d18faff 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -342,8 +342,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
 	net_get_random_once(&hash_rnd, sizeof(hash_rnd));
 
 	if (info->check_set & ~XT_RECENT_VALID_FLAGS) {
-		pr_info("Unsupported user space flags (%08x)\n",
-			info->check_set);
+		pr_info_ratelimited("Unsupported userspace flags (%08x)\n",
+				    info->check_set);
 		return -EINVAL;
 	}
 	if (hweight8(info->check_set &
@@ -357,8 +357,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
 	if ((info->check_set & XT_RECENT_REAP) && !info->seconds)
 		return -EINVAL;
 	if (info->hit_count >= XT_RECENT_MAX_NSTAMPS) {
-		pr_info("hitcount (%u) is larger than allowed maximum (%u)\n",
-			info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
+		pr_info_ratelimited("hitcount (%u) is larger than allowed maximum (%u)\n",
+				    info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
 		return -EINVAL;
 	}
 	if (info->name[0] == '\0' ||
@@ -587,7 +587,7 @@ recent_mt_proc_write(struct file *file, const char __user *input,
 		add = true;
 		break;
 	default:
-		pr_info("Need \"+ip\", \"-ip\" or \"/\"\n");
+		pr_info_ratelimited("Need \"+ip\", \"-ip\" or \"/\"\n");
 		return -EINVAL;
 	}
 
@@ -601,10 +601,8 @@ recent_mt_proc_write(struct file *file, const char __user *input,
 		succ   = in4_pton(c, size, (void *)&addr, '\n', NULL);
 	}
 
-	if (!succ) {
-		pr_info("illegal address written to procfs\n");
+	if (!succ)
 		return -EINVAL;
-	}
 
 	spin_lock_bh(&recent_lock);
 	e = recent_entry_lookup(t, &addr, family, 0);
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c
index 16b6b11ee83f..6f4c5217d835 100644
--- a/net/netfilter/xt_set.c
+++ b/net/netfilter/xt_set.c
@@ -92,12 +92,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 
 	if (index == IPSET_INVALID_ID) {
-		pr_warn("Cannot find set identified by id %u to match\n",
-			info->match_set.index);
+		pr_info_ratelimited("Cannot find set identified by id %u to match\n",
+				    info->match_set.index);
 		return -ENOENT;
 	}
 	if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
-		pr_warn("Protocol error: set match dimension is over the limit!\n");
+		pr_info_ratelimited("set match dimension is over the limit!\n");
 		ip_set_nfnl_put(par->net, info->match_set.index);
 		return -ERANGE;
 	}
@@ -143,12 +143,12 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 
 	if (index == IPSET_INVALID_ID) {
-		pr_warn("Cannot find set identified by id %u to match\n",
-			info->match_set.index);
+		pr_info_ratelimited("Cannot find set identified by id %u to match\n",
+				    info->match_set.index);
 		return -ENOENT;
 	}
 	if (info->match_set.dim > IPSET_DIM_MAX) {
-		pr_warn("Protocol error: set match dimension is over the limit!\n");
+		pr_info_ratelimited("set match dimension is over the limit!\n");
 		ip_set_nfnl_put(par->net, info->match_set.index);
 		return -ERANGE;
 	}
@@ -241,8 +241,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
 	if (info->add_set.index != IPSET_INVALID_ID) {
 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find add_set index %u as target\n",
-				info->add_set.index);
+			pr_info_ratelimited("Cannot find add_set index %u as target\n",
+					    info->add_set.index);
 			return -ENOENT;
 		}
 	}
@@ -250,8 +250,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
 	if (info->del_set.index != IPSET_INVALID_ID) {
 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find del_set index %u as target\n",
-				info->del_set.index);
+			pr_info_ratelimited("Cannot find del_set index %u as target\n",
+					    info->del_set.index);
 			if (info->add_set.index != IPSET_INVALID_ID)
 				ip_set_nfnl_put(par->net, info->add_set.index);
 			return -ENOENT;
@@ -259,7 +259,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
 	}
 	if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
 	    info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
-		pr_warn("Protocol error: SET target dimension is over the limit!\n");
+		pr_info_ratelimited("SET target dimension over the limit!\n");
 		if (info->add_set.index != IPSET_INVALID_ID)
 			ip_set_nfnl_put(par->net, info->add_set.index);
 		if (info->del_set.index != IPSET_INVALID_ID)
@@ -316,8 +316,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
 	if (info->add_set.index != IPSET_INVALID_ID) {
 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find add_set index %u as target\n",
-				info->add_set.index);
+			pr_info_ratelimited("Cannot find add_set index %u as target\n",
+					    info->add_set.index);
 			return -ENOENT;
 		}
 	}
@@ -325,8 +325,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
 	if (info->del_set.index != IPSET_INVALID_ID) {
 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find del_set index %u as target\n",
-				info->del_set.index);
+			pr_info_ratelimited("Cannot find del_set index %u as target\n",
+					    info->del_set.index);
 			if (info->add_set.index != IPSET_INVALID_ID)
 				ip_set_nfnl_put(par->net, info->add_set.index);
 			return -ENOENT;
@@ -334,7 +334,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
 	}
 	if (info->add_set.dim > IPSET_DIM_MAX ||
 	    info->del_set.dim > IPSET_DIM_MAX) {
-		pr_warn("Protocol error: SET target dimension is over the limit!\n");
+		pr_info_ratelimited("SET target dimension over the limit!\n");
 		if (info->add_set.index != IPSET_INVALID_ID)
 			ip_set_nfnl_put(par->net, info->add_set.index);
 		if (info->del_set.index != IPSET_INVALID_ID)
@@ -444,8 +444,8 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 		index = ip_set_nfnl_get_byindex(par->net,
 						info->add_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find add_set index %u as target\n",
-				info->add_set.index);
+			pr_info_ratelimited("Cannot find add_set index %u as target\n",
+					    info->add_set.index);
 			return -ENOENT;
 		}
 	}
@@ -454,8 +454,8 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 		index = ip_set_nfnl_get_byindex(par->net,
 						info->del_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find del_set index %u as target\n",
-				info->del_set.index);
+			pr_info_ratelimited("Cannot find del_set index %u as target\n",
+					    info->del_set.index);
 			if (info->add_set.index != IPSET_INVALID_ID)
 				ip_set_nfnl_put(par->net,
 						info->add_set.index);
@@ -465,7 +465,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 
 	if (info->map_set.index != IPSET_INVALID_ID) {
 		if (strncmp(par->table, "mangle", 7)) {
-			pr_warn("--map-set only usable from mangle table\n");
+			pr_info_ratelimited("--map-set only usable from mangle table\n");
 			return -EINVAL;
 		}
 		if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
@@ -473,14 +473,14 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 		     !(par->hook_mask & (1 << NF_INET_FORWARD |
 					 1 << NF_INET_LOCAL_OUT |
 					 1 << NF_INET_POST_ROUTING))) {
-			pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
+			pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
 			return -EINVAL;
 		}
 		index = ip_set_nfnl_get_byindex(par->net,
 						info->map_set.index);
 		if (index == IPSET_INVALID_ID) {
-			pr_warn("Cannot find map_set index %u as target\n",
-				info->map_set.index);
+			pr_info_ratelimited("Cannot find map_set index %u as target\n",
+					    info->map_set.index);
 			if (info->add_set.index != IPSET_INVALID_ID)
 				ip_set_nfnl_put(par->net,
 						info->add_set.index);
@@ -494,7 +494,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 	if (info->add_set.dim > IPSET_DIM_MAX ||
 	    info->del_set.dim > IPSET_DIM_MAX ||
 	    info->map_set.dim > IPSET_DIM_MAX) {
-		pr_warn("Protocol error: SET target dimension is over the limit!\n");
+		pr_info_ratelimited("SET target dimension over the limit!\n");
 		if (info->add_set.index != IPSET_INVALID_ID)
 			ip_set_nfnl_put(par->net, info->add_set.index);
 		if (info->del_set.index != IPSET_INVALID_ID)
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 575d2153e3b8..2ac7f674d19b 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -171,7 +171,8 @@ static int socket_mt_v1_check(const struct xt_mtchk_param *par)
 		return err;
 
 	if (info->flags & ~XT_SOCKET_FLAGS_V1) {
-		pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1);
+		pr_info_ratelimited("unknown flags 0x%x\n",
+				    info->flags & ~XT_SOCKET_FLAGS_V1);
 		return -EINVAL;
 	}
 	return 0;
@@ -187,7 +188,8 @@ static int socket_mt_v2_check(const struct xt_mtchk_param *par)
 		return err;
 
 	if (info->flags & ~XT_SOCKET_FLAGS_V2) {
-		pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2);
+		pr_info_ratelimited("unknown flags 0x%x\n",
+				    info->flags & ~XT_SOCKET_FLAGS_V2);
 		return -EINVAL;
 	}
 	return 0;
@@ -203,8 +205,8 @@ static int socket_mt_v3_check(const struct xt_mtchk_param *par)
 	if (err)
 		return err;
 	if (info->flags & ~XT_SOCKET_FLAGS_V3) {
-		pr_info("unknown flags 0x%x\n",
-			info->flags & ~XT_SOCKET_FLAGS_V3);
+		pr_info_ratelimited("unknown flags 0x%x\n",
+				    info->flags & ~XT_SOCKET_FLAGS_V3);
 		return -EINVAL;
 	}
 	return 0;
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index 5fbd79194d21..0b41c0befe3c 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -44,8 +44,8 @@ static int state_mt_check(const struct xt_mtchk_param *par)
 
 	ret = nf_ct_netns_get(par->net, par->family);
 	if (ret < 0)
-		pr_info("cannot load conntrack support for proto=%u\n",
-			par->family);
+		pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+				    par->family);
 	return ret;
 }
 
diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c
index 1b01eec1fbda..0160f505e337 100644
--- a/net/netfilter/xt_time.c
+++ b/net/netfilter/xt_time.c
@@ -235,13 +235,13 @@ static int time_mt_check(const struct xt_mtchk_param *par)
 
 	if (info->daytime_start > XT_TIME_MAX_DAYTIME ||
 	    info->daytime_stop > XT_TIME_MAX_DAYTIME) {
-		pr_info("invalid argument - start or "
-			"stop time greater than 23:59:59\n");
+		pr_info_ratelimited("invalid argument - start or stop time greater than 23:59:59\n");
 		return -EDOM;
 	}
 
 	if (info->flags & ~XT_TIME_ALL_FLAGS) {
-		pr_info("unknown flags 0x%x\n", info->flags & ~XT_TIME_ALL_FLAGS);
+		pr_info_ratelimited("unknown flags 0x%x\n",
+				    info->flags & ~XT_TIME_ALL_FLAGS);
 		return -EINVAL;
 	}
 
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 22dc1b9d6362..c070dfc0190a 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1472,6 +1472,16 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
 		iface = rcu_dereference(netlbl_unlhsh_def);
 	if (iface == NULL || !iface->valid)
 		goto unlabel_getattr_nolabel;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	/* When resolving a fallback label, check the sk_buff version as
+	 * it is possible (e.g. SCTP) to have family = PF_INET6 while
+	 * receiving ip_hdr(skb)->version = 4.
+	 */
+	if (family == PF_INET6 && ip_hdr(skb)->version == 4)
+		family = PF_INET;
+#endif /* IPv6 */
+
 	switch (family) {
 	case PF_INET: {
 		struct iphdr *hdr4;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 2ad445c1d27c..63cb55d3c2fd 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -253,6 +253,7 @@ static struct pernet_operations netlink_tap_net_ops = {
 	.exit = netlink_tap_exit_net,
 	.id   = &netlink_tap_net_id,
 	.size = sizeof(struct netlink_tap_net),
+	.async = true,
 };
 
 static bool netlink_filter_tap(const struct sk_buff *skb)
@@ -1105,7 +1106,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
 }
 
 static int netlink_getname(struct socket *sock, struct sockaddr *addr,
-			   int *addr_len, int peer)
+			   int peer)
 {
 	struct sock *sk = sock->sk;
 	struct netlink_sock *nlk = nlk_sk(sk);
@@ -1113,7 +1114,6 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr,
 
 	nladdr->nl_family = AF_NETLINK;
 	nladdr->nl_pad = 0;
-	*addr_len = sizeof(*nladdr);
 
 	if (peer) {
 		nladdr->nl_pid = nlk->dst_portid;
@@ -1124,7 +1124,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr,
 		nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
 		netlink_unlock_table();
 	}
-	return 0;
+	return sizeof(*nladdr);
 }
 
 static int netlink_ioctl(struct socket *sock, unsigned int cmd,
@@ -2724,6 +2724,7 @@ static void __init netlink_add_usersock_entry(void)
 static struct pernet_operations __net_initdata netlink_net_ops = {
 	.init = netlink_net_init,
 	.exit = netlink_net_exit,
+	.async = true,
 };
 
 static inline u32 netlink_hash(const void *data, u32 len, u32 seed)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 6f02499ef007..a6f63a5faee7 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1035,6 +1035,7 @@ static void __net_exit genl_pernet_exit(struct net *net)
 static struct pernet_operations genl_pernet_ops = {
 	.init = genl_pernet_init,
 	.exit = genl_pernet_exit,
+	.async = true,
 };
 
 static int __init genl_init(void)
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 9ba30c63be3d..35bb6807927f 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -829,11 +829,12 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
-	int *uaddr_len, int peer)
+	int peer)
 {
 	struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
 	struct sock *sk = sock->sk;
 	struct nr_sock *nr = nr_sk(sk);
+	int uaddr_len;
 
 	memset(&sax->fsa_ax25, 0, sizeof(struct sockaddr_ax25));
 
@@ -848,16 +849,16 @@ static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
 		sax->fsa_ax25.sax25_call   = nr->user_addr;
 		memset(sax->fsa_digipeater, 0, sizeof(sax->fsa_digipeater));
 		sax->fsa_digipeater[0]     = nr->dest_addr;
-		*uaddr_len = sizeof(struct full_sockaddr_ax25);
+		uaddr_len = sizeof(struct full_sockaddr_ax25);
 	} else {
 		sax->fsa_ax25.sax25_family = AF_NETROM;
 		sax->fsa_ax25.sax25_ndigis = 0;
 		sax->fsa_ax25.sax25_call   = nr->source_addr;
-		*uaddr_len = sizeof(struct sockaddr_ax25);
+		uaddr_len = sizeof(struct sockaddr_ax25);
 	}
 	release_sock(sk);
 
-	return 0;
+	return uaddr_len;
 }
 
 int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c
index 367d8c027101..2ceefa183cee 100644
--- a/net/nfc/llcp_commands.c
+++ b/net/nfc/llcp_commands.c
@@ -149,6 +149,10 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
 
 	pr_debug("uri: %s, len: %zu\n", uri, uri_len);
 
+	/* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */
+	if (WARN_ON_ONCE(uri_len > U8_MAX - 4))
+		return NULL;
+
 	sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
 	if (sdreq == NULL)
 		return NULL;
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index 376040092142..ea0c0c6f1874 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -497,7 +497,7 @@ static int llcp_sock_accept(struct socket *sock, struct socket *newsock,
 }
 
 static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr,
-			     int *len, int peer)
+			     int peer)
 {
 	struct sock *sk = sock->sk;
 	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -510,7 +510,6 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr,
 		 llcp_sock->dsap, llcp_sock->ssap);
 
 	memset(llcp_addr, 0, sizeof(*llcp_addr));
-	*len = sizeof(struct sockaddr_nfc_llcp);
 
 	lock_sock(sk);
 	if (!llcp_sock->dev) {
@@ -528,7 +527,7 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr,
 	       llcp_addr->service_name_len);
 	release_sock(sk);
 
-	return 0;
+	return sizeof(struct sockaddr_nfc_llcp);
 }
 
 static inline __poll_t llcp_accept_poll(struct sock *parent)
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index c0b83dc9d993..f018eafc2a0d 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -61,7 +61,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
 };
 
 static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
-	[NFC_SDP_ATTR_URI] = { .type = NLA_STRING },
+	[NFC_SDP_ATTR_URI] = { .type = NLA_STRING,
+			       .len = U8_MAX - 4 },
 	[NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
 };
 
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index e0f3f4aeeb4f..2c5a6fe5d749 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3409,7 +3409,7 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 }
 
 static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,
-			       int *uaddr_len, int peer)
+			       int peer)
 {
 	struct net_device *dev;
 	struct sock *sk	= sock->sk;
@@ -3424,13 +3424,12 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,
 	if (dev)
 		strlcpy(uaddr->sa_data, dev->name, sizeof(uaddr->sa_data));
 	rcu_read_unlock();
-	*uaddr_len = sizeof(*uaddr);
 
-	return 0;
+	return sizeof(*uaddr);
 }
 
 static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
-			  int *uaddr_len, int peer)
+			  int peer)
 {
 	struct net_device *dev;
 	struct sock *sk = sock->sk;
@@ -3455,9 +3454,8 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
 		sll->sll_halen = 0;
 	}
 	rcu_read_unlock();
-	*uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen;
 
-	return 0;
+	return offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen;
 }
 
 static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
@@ -4559,6 +4557,7 @@ static void __net_exit packet_net_exit(struct net *net)
 static struct pernet_operations packet_net_ops = {
 	.init = packet_net_init,
 	.exit = packet_net_exit,
+	.async = true,
 };
 
 
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index fffcd69f63ff..f9b40e6a18a5 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -326,7 +326,7 @@ static int pn_socket_accept(struct socket *sock, struct socket *newsock,
 }
 
 static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
-				int *sockaddr_len, int peer)
+				int peer)
 {
 	struct sock *sk = sock->sk;
 	struct pn_sock *pn = pn_sk(sk);
@@ -337,8 +337,7 @@ static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
 		pn_sockaddr_set_object((struct sockaddr_pn *)addr,
 					pn->sobject);
 
-	*sockaddr_len = sizeof(struct sockaddr_pn);
-	return 0;
+	return sizeof(struct sockaddr_pn);
 }
 
 static __poll_t pn_socket_poll(struct file *file, struct socket *sock,
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index 5fb3929e3d7d..b33e5aeb4c06 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -893,7 +893,7 @@ static int qrtr_connect(struct socket *sock, struct sockaddr *saddr,
 }
 
 static int qrtr_getname(struct socket *sock, struct sockaddr *saddr,
-			int *len, int peer)
+			int peer)
 {
 	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
 	struct sockaddr_qrtr qaddr;
@@ -912,12 +912,11 @@ static int qrtr_getname(struct socket *sock, struct sockaddr *saddr,
 	}
 	release_sock(sk);
 
-	*len = sizeof(qaddr);
 	qaddr.sq_family = AF_QIPCRTR;
 
 	memcpy(saddr, &qaddr, sizeof(qaddr));
 
-	return 0;
+	return sizeof(qaddr);
 }
 
 static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index 744c637c86b0..a937f18896ae 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -110,7 +110,7 @@ void rds_wake_sk_sleep(struct rds_sock *rs)
 }
 
 static int rds_getname(struct socket *sock, struct sockaddr *uaddr,
-		       int *uaddr_len, int peer)
+		       int peer)
 {
 	struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
 	struct rds_sock *rs = rds_sk_to_rs(sock->sk);
@@ -131,8 +131,7 @@ static int rds_getname(struct socket *sock, struct sockaddr *uaddr,
 
 	sin->sin_family = AF_INET;
 
-	*uaddr_len = sizeof(*sin);
-	return 0;
+	return sizeof(*sin);
 }
 
 /*
@@ -183,6 +182,8 @@ static __poll_t rds_poll(struct file *file, struct socket *sock,
 		mask |= (EPOLLIN | EPOLLRDNORM);
 	if (rs->rs_snd_bytes < rds_sk_sndbuf(rs))
 		mask |= (EPOLLOUT | EPOLLWRNORM);
+	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
+		mask |= POLLERR;
 	read_unlock_irqrestore(&rs->rs_recv_lock, flags);
 
 	/* clear state any time we wake a seen-congested socket */
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 94e190febfdd..2da3176bf792 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -224,7 +224,7 @@ static struct rds_connection *__rds_conn_create(struct net *net,
 	if (rds_destroy_pending(conn))
 		ret = -ENETDOWN;
 	else
-		ret = trans->conn_alloc(conn, gfp);
+		ret = trans->conn_alloc(conn, GFP_ATOMIC);
 	if (ret) {
 		rcu_read_unlock();
 		kfree(conn->c_path);
diff --git a/net/rds/message.c b/net/rds/message.c
index 4318cc9b78f7..651834513481 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -33,6 +33,9 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+#include <linux/errqueue.h>
 
 #include "rds.h"
 
@@ -53,20 +56,92 @@ void rds_message_addref(struct rds_message *rm)
 }
 EXPORT_SYMBOL_GPL(rds_message_addref);
 
+static inline bool skb_zcookie_add(struct sk_buff *skb, u32 cookie)
+{
+	struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
+	int ncookies;
+	u32 *ptr;
+
+	if (serr->ee.ee_origin != SO_EE_ORIGIN_ZCOOKIE)
+		return false;
+	ncookies = serr->ee.ee_data;
+	if (ncookies == SO_EE_ORIGIN_MAX_ZCOOKIES)
+		return false;
+	ptr = skb_put(skb, sizeof(u32));
+	*ptr = cookie;
+	serr->ee.ee_data = ++ncookies;
+	return true;
+}
+
+static void rds_rm_zerocopy_callback(struct rds_sock *rs,
+				     struct rds_znotifier *znotif)
+{
+	struct sock *sk = rds_rs_to_sk(rs);
+	struct sk_buff *skb, *tail;
+	struct sock_exterr_skb *serr;
+	unsigned long flags;
+	struct sk_buff_head *q;
+	u32 cookie = znotif->z_cookie;
+
+	q = &sk->sk_error_queue;
+	spin_lock_irqsave(&q->lock, flags);
+	tail = skb_peek_tail(q);
+
+	if (tail && skb_zcookie_add(tail, cookie)) {
+		spin_unlock_irqrestore(&q->lock, flags);
+		mm_unaccount_pinned_pages(&znotif->z_mmp);
+		consume_skb(rds_skb_from_znotifier(znotif));
+		sk->sk_error_report(sk);
+		return;
+	}
+
+	skb = rds_skb_from_znotifier(znotif);
+	serr = SKB_EXT_ERR(skb);
+	memset(&serr->ee, 0, sizeof(serr->ee));
+	serr->ee.ee_errno = 0;
+	serr->ee.ee_origin = SO_EE_ORIGIN_ZCOOKIE;
+	serr->ee.ee_info = 0;
+	WARN_ON(!skb_zcookie_add(skb, cookie));
+
+	__skb_queue_tail(q, skb);
+
+	spin_unlock_irqrestore(&q->lock, flags);
+	sk->sk_error_report(sk);
+
+	mm_unaccount_pinned_pages(&znotif->z_mmp);
+}
+
 /*
  * This relies on dma_map_sg() not touching sg[].page during merging.
  */
 static void rds_message_purge(struct rds_message *rm)
 {
-	unsigned long i;
+	unsigned long i, flags;
+	bool zcopy = false;
 
 	if (unlikely(test_bit(RDS_MSG_PAGEVEC, &rm->m_flags)))
 		return;
 
+	spin_lock_irqsave(&rm->m_rs_lock, flags);
+	if (rm->m_rs) {
+		struct rds_sock *rs = rm->m_rs;
+
+		if (rm->data.op_mmp_znotifier) {
+			zcopy = true;
+			rds_rm_zerocopy_callback(rs, rm->data.op_mmp_znotifier);
+			rm->data.op_mmp_znotifier = NULL;
+		}
+		sock_put(rds_rs_to_sk(rs));
+		rm->m_rs = NULL;
+	}
+	spin_unlock_irqrestore(&rm->m_rs_lock, flags);
+
 	for (i = 0; i < rm->data.op_nents; i++) {
-		rdsdebug("putting data page %p\n", (void *)sg_page(&rm->data.op_sg[i]));
 		/* XXX will have to put_page for page refs */
-		__free_page(sg_page(&rm->data.op_sg[i]));
+		if (!zcopy)
+			__free_page(sg_page(&rm->data.op_sg[i]));
+		else
+			put_page(sg_page(&rm->data.op_sg[i]));
 	}
 	rm->data.op_nents = 0;
 
@@ -266,12 +341,14 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
 	return rm;
 }
 
-int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from)
+int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from,
+			       bool zcopy)
 {
 	unsigned long to_copy, nbytes;
 	unsigned long sg_off;
 	struct scatterlist *sg;
 	int ret = 0;
+	int length = iov_iter_count(from);
 
 	rm->m_inc.i_hdr.h_len = cpu_to_be32(iov_iter_count(from));
 
@@ -281,6 +358,53 @@ int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from)
 	sg = rm->data.op_sg;
 	sg_off = 0; /* Dear gcc, sg->page will be null from kzalloc. */
 
+	if (zcopy) {
+		int total_copied = 0;
+		struct sk_buff *skb;
+
+		skb = alloc_skb(SO_EE_ORIGIN_MAX_ZCOOKIES * sizeof(u32),
+				GFP_KERNEL);
+		if (!skb)
+			return -ENOMEM;
+		rm->data.op_mmp_znotifier = RDS_ZCOPY_SKB(skb);
+		if (mm_account_pinned_pages(&rm->data.op_mmp_znotifier->z_mmp,
+					    length)) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		while (iov_iter_count(from)) {
+			struct page *pages;
+			size_t start;
+			ssize_t copied;
+
+			copied = iov_iter_get_pages(from, &pages, PAGE_SIZE,
+						    1, &start);
+			if (copied < 0) {
+				struct mmpin *mmp;
+				int i;
+
+				for (i = 0; i < rm->data.op_nents; i++)
+					put_page(sg_page(&rm->data.op_sg[i]));
+				mmp = &rm->data.op_mmp_znotifier->z_mmp;
+				mm_unaccount_pinned_pages(mmp);
+				ret = -EFAULT;
+				goto err;
+			}
+			total_copied += copied;
+			iov_iter_advance(from, copied);
+			length -= copied;
+			sg_set_page(sg, pages, copied, start);
+			rm->data.op_nents++;
+			sg++;
+		}
+		WARN_ON_ONCE(length != 0);
+		return ret;
+err:
+		consume_skb(skb);
+		rm->data.op_mmp_znotifier = NULL;
+		return ret;
+	} /* zcopy */
+
 	while (iov_iter_count(from)) {
 		if (!sg_page(sg)) {
 			ret = rds_page_remainder_alloc(sg, iov_iter_count(from),
diff --git a/net/rds/rds.h b/net/rds/rds.h
index 7301b9b01890..31cd38852050 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -356,6 +356,19 @@ static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie)
 #define RDS_MSG_PAGEVEC		7
 #define RDS_MSG_FLUSH		8
 
+struct rds_znotifier {
+	struct list_head	z_list;
+	struct mmpin		z_mmp;
+	u32			z_cookie;
+};
+
+#define	RDS_ZCOPY_SKB(__skb)	((struct rds_znotifier *)&((__skb)->cb[0]))
+
+static inline struct sk_buff *rds_skb_from_znotifier(struct rds_znotifier *z)
+{
+	return container_of((void *)z, struct sk_buff, cb);
+}
+
 struct rds_message {
 	refcount_t		m_refcount;
 	struct list_head	m_sock_item;
@@ -436,6 +449,7 @@ struct rds_message {
 			unsigned int		op_count;
 			unsigned int		op_dmasg;
 			unsigned int		op_dmaoff;
+			struct rds_znotifier	*op_mmp_znotifier;
 			struct scatterlist	*op_sg;
 		} data;
 	};
@@ -771,7 +785,8 @@ rds_conn_connecting(struct rds_connection *conn)
 /* message.c */
 struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp);
 struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents);
-int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from);
+int rds_message_copy_from_user(struct rds_message *rm, struct iov_iter *from,
+			       bool zcopy);
 struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len);
 void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
 				 __be16 dport, u64 seq);
diff --git a/net/rds/recv.c b/net/rds/recv.c
index b25bcfe411ca..b080961464df 100644
--- a/net/rds/recv.c
+++ b/net/rds/recv.c
@@ -594,6 +594,8 @@ int rds_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
 
 	if (msg_flags & MSG_OOB)
 		goto out;
+	if (msg_flags & MSG_ERRQUEUE)
+		return sock_recv_errqueue(sk, msg, size, SOL_IP, IP_RECVERR);
 
 	while (1) {
 		/* If there are pending notifications, do those - and nothing else */
diff --git a/net/rds/send.c b/net/rds/send.c
index b1b0022b8370..028ab598ac1b 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -649,7 +649,6 @@ static void rds_send_remove_from_sock(struct list_head *messages, int status)
 				rm->rdma.op_notifier = NULL;
 			}
 			was_on_sock = 1;
-			rm->m_rs = NULL;
 		}
 		spin_unlock(&rs->rs_lock);
 
@@ -756,9 +755,6 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
 		 */
 		if (!test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) {
 			spin_unlock_irqrestore(&cp->cp_lock, flags);
-			spin_lock_irqsave(&rm->m_rs_lock, flags);
-			rm->m_rs = NULL;
-			spin_unlock_irqrestore(&rm->m_rs_lock, flags);
 			continue;
 		}
 		list_del_init(&rm->m_conn_item);
@@ -774,7 +770,6 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
 		__rds_send_complete(rs, rm, RDS_RDMA_CANCELED);
 		spin_unlock(&rs->rs_lock);
 
-		rm->m_rs = NULL;
 		spin_unlock_irqrestore(&rm->m_rs_lock, flags);
 
 		rds_message_put(rm);
@@ -798,7 +793,6 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
 		__rds_send_complete(rs, rm, RDS_RDMA_CANCELED);
 		spin_unlock(&rs->rs_lock);
 
-		rm->m_rs = NULL;
 		spin_unlock_irqrestore(&rm->m_rs_lock, flags);
 
 		rds_message_put(rm);
@@ -849,6 +843,7 @@ static int rds_send_queue_rm(struct rds_sock *rs, struct rds_connection *conn,
 		list_add_tail(&rm->m_sock_item, &rs->rs_send_queue);
 		set_bit(RDS_MSG_ON_SOCK, &rm->m_flags);
 		rds_message_addref(rm);
+		sock_hold(rds_rs_to_sk(rs));
 		rm->m_rs = rs;
 
 		/* The code ordering is a little weird, but we're
@@ -880,12 +875,13 @@ static int rds_send_queue_rm(struct rds_sock *rs, struct rds_connection *conn,
  * rds_message is getting to be quite complicated, and we'd like to allocate
  * it all in one go. This figures out how big it needs to be up front.
  */
-static int rds_rm_size(struct msghdr *msg, int data_len)
+static int rds_rm_size(struct msghdr *msg, int num_sgs)
 {
 	struct cmsghdr *cmsg;
 	int size = 0;
 	int cmsg_groups = 0;
 	int retval;
+	bool zcopy_cookie = false;
 
 	for_each_cmsghdr(cmsg, msg) {
 		if (!CMSG_OK(msg, cmsg))
@@ -904,6 +900,8 @@ static int rds_rm_size(struct msghdr *msg, int data_len)
 
 			break;
 
+		case RDS_CMSG_ZCOPY_COOKIE:
+			zcopy_cookie = true;
 		case RDS_CMSG_RDMA_DEST:
 		case RDS_CMSG_RDMA_MAP:
 			cmsg_groups |= 2;
@@ -924,7 +922,10 @@ static int rds_rm_size(struct msghdr *msg, int data_len)
 
 	}
 
-	size += ceil(data_len, PAGE_SIZE) * sizeof(struct scatterlist);
+	if ((msg->msg_flags & MSG_ZEROCOPY) && !zcopy_cookie)
+		return -EINVAL;
+
+	size += num_sgs * sizeof(struct scatterlist);
 
 	/* Ensure (DEST, MAP) are never used with (ARGS, ATOMIC) */
 	if (cmsg_groups == 3)
@@ -933,6 +934,18 @@ static int rds_rm_size(struct msghdr *msg, int data_len)
 	return size;
 }
 
+static int rds_cmsg_zcopy(struct rds_sock *rs, struct rds_message *rm,
+			  struct cmsghdr *cmsg)
+{
+	u32 *cookie;
+
+	if (cmsg->cmsg_len < CMSG_LEN(sizeof(*cookie)))
+		return -EINVAL;
+	cookie = CMSG_DATA(cmsg);
+	rm->data.op_mmp_znotifier->z_cookie = *cookie;
+	return 0;
+}
+
 static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
 			 struct msghdr *msg, int *allocated_mr)
 {
@@ -975,6 +988,10 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
 			ret = rds_cmsg_atomic(rs, rm, cmsg);
 			break;
 
+		case RDS_CMSG_ZCOPY_COOKIE:
+			ret = rds_cmsg_zcopy(rs, rm, cmsg);
+			break;
+
 		default:
 			return -EINVAL;
 		}
@@ -1045,10 +1062,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 	long timeo = sock_sndtimeo(sk, nonblock);
 	struct rds_conn_path *cpath;
 	size_t total_payload_len = payload_len, rdma_payload_len = 0;
+	bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) &&
+		      sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY));
+	int num_sgs = ceil(payload_len, PAGE_SIZE);
 
 	/* Mirror Linux UDP mirror of BSD error message compatibility */
 	/* XXX: Perhaps MSG_MORE someday */
-	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) {
+	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT | MSG_ZEROCOPY)) {
 		ret = -EOPNOTSUPP;
 		goto out;
 	}
@@ -1092,8 +1112,15 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 		goto out;
 	}
 
+	if (zcopy) {
+		if (rs->rs_transport->t_type != RDS_TRANS_TCP) {
+			ret = -EOPNOTSUPP;
+			goto out;
+		}
+		num_sgs = iov_iter_npages(&msg->msg_iter, INT_MAX);
+	}
 	/* size of rm including all sgs */
-	ret = rds_rm_size(msg, payload_len);
+	ret = rds_rm_size(msg, num_sgs);
 	if (ret < 0)
 		goto out;
 
@@ -1105,12 +1132,12 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 
 	/* Attach data to the rm */
 	if (payload_len) {
-		rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE));
+		rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
 		if (!rm->data.op_sg) {
 			ret = -ENOMEM;
 			goto out;
 		}
-		ret = rds_message_copy_from_user(rm, &msg->msg_iter);
+		ret = rds_message_copy_from_user(rm, &msg->msg_iter, zcopy);
 		if (ret)
 			goto out;
 	}
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index 44c4652721af..08230a145042 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -227,7 +227,6 @@ static void rds_tcp_tc_info(struct socket *rds_sock, unsigned int len,
 	struct rds_tcp_connection *tc;
 	unsigned long flags;
 	struct sockaddr_in sin;
-	int sinlen;
 	struct socket *sock;
 
 	spin_lock_irqsave(&rds_tcp_tc_list_lock, flags);
@@ -239,12 +238,10 @@ static void rds_tcp_tc_info(struct socket *rds_sock, unsigned int len,
 
 		sock = tc->t_sock;
 		if (sock) {
-			sock->ops->getname(sock, (struct sockaddr *)&sin,
-					   &sinlen, 0);
+			sock->ops->getname(sock, (struct sockaddr *)&sin, 0);
 			tsinfo.local_addr = sin.sin_addr.s_addr;
 			tsinfo.local_port = sin.sin_port;
-			sock->ops->getname(sock, (struct sockaddr *)&sin,
-					   &sinlen, 1);
+			sock->ops->getname(sock, (struct sockaddr *)&sin, 1);
 			tsinfo.peer_addr = sin.sin_addr.s_addr;
 			tsinfo.peer_port = sin.sin_port;
 		}
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 083bd251406f..5170373b797c 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -938,7 +938,7 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
-	int *uaddr_len, int peer)
+	int peer)
 {
 	struct full_sockaddr_rose *srose = (struct full_sockaddr_rose *)uaddr;
 	struct sock *sk = sock->sk;
@@ -964,8 +964,7 @@ static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
 			srose->srose_digis[n] = rose->source_digis[n];
 	}
 
-	*uaddr_len = sizeof(struct full_sockaddr_rose);
-	return 0;
+	return sizeof(struct full_sockaddr_rose);
 }
 
 int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct rose_neigh *neigh, unsigned int lci)
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index cc21e8db25b0..9d45d8b56744 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -517,9 +517,10 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 			ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,
 				       sizeof(unsigned int), &id32);
 		} else {
+			unsigned long idl = call->user_call_ID;
+
 			ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,
-				       sizeof(unsigned long),
-				       &call->user_call_ID);
+				       sizeof(unsigned long), &idl);
 		}
 		if (ret < 0)
 			goto error_unlock_call;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index eba6682727dd..1f65d6ada9ff 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -202,7 +202,8 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
 
 int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
 		       struct netlink_callback *cb, int type,
-		       const struct tc_action_ops *ops)
+		       const struct tc_action_ops *ops,
+		       struct netlink_ext_ack *extack)
 {
 	struct tcf_idrinfo *idrinfo = tn->idrinfo;
 
@@ -211,7 +212,8 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
 	} else if (type == RTM_GETACTION) {
 		return tcf_dump_walker(idrinfo, skb, cb);
 	} else {
-		WARN(1, "tcf_generic_walker: unknown action %d\n", type);
+		WARN(1, "tcf_generic_walker: unknown command %d\n", type);
+		NL_SET_ERR_MSG(extack, "tcf_generic_walker: unknown command");
 		return -EINVAL;
 	}
 }
@@ -605,7 +607,8 @@ static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
 
 struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 				    struct nlattr *nla, struct nlattr *est,
-				    char *name, int ovr, int bind)
+				    char *name, int ovr, int bind,
+				    struct netlink_ext_ack *extack)
 {
 	struct tc_action *a;
 	struct tc_action_ops *a_o;
@@ -616,31 +619,40 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 	int err;
 
 	if (name == NULL) {
-		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
+		err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, extack);
 		if (err < 0)
 			goto err_out;
 		err = -EINVAL;
 		kind = tb[TCA_ACT_KIND];
-		if (kind == NULL)
+		if (!kind) {
+			NL_SET_ERR_MSG(extack, "TC action kind must be specified");
 			goto err_out;
-		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
+		}
+		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ) {
+			NL_SET_ERR_MSG(extack, "TC action name too long");
 			goto err_out;
+		}
 		if (tb[TCA_ACT_COOKIE]) {
 			int cklen = nla_len(tb[TCA_ACT_COOKIE]);
 
-			if (cklen > TC_COOKIE_MAX_SIZE)
+			if (cklen > TC_COOKIE_MAX_SIZE) {
+				NL_SET_ERR_MSG(extack, "TC cookie size above the maximum");
 				goto err_out;
+			}
 
 			cookie = nla_memdup_cookie(tb);
 			if (!cookie) {
+				NL_SET_ERR_MSG(extack, "No memory to generate TC cookie");
 				err = -ENOMEM;
 				goto err_out;
 			}
 		}
 	} else {
-		err = -EINVAL;
-		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
+		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ) {
+			NL_SET_ERR_MSG(extack, "TC action name too long");
+			err = -EINVAL;
 			goto err_out;
+		}
 	}
 
 	a_o = tc_lookup_action_n(act_name);
@@ -663,15 +675,17 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 			goto err_mod;
 		}
 #endif
+		NL_SET_ERR_MSG(extack, "Failed to load TC action module");
 		err = -ENOENT;
 		goto err_out;
 	}
 
 	/* backward compatibility for policer */
 	if (name == NULL)
-		err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind);
+		err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, ovr, bind,
+				extack);
 	else
-		err = a_o->init(net, nla, est, &a, ovr, bind);
+		err = a_o->init(net, nla, est, &a, ovr, bind, extack);
 	if (err < 0)
 		goto err_mod;
 
@@ -697,6 +711,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 
 			list_add_tail(&a->list, &actions);
 			tcf_action_destroy(&actions, bind);
+			NL_SET_ERR_MSG(extack, "Failed to init TC action chain");
 			return ERR_PTR(err);
 		}
 	}
@@ -726,19 +741,20 @@ static void cleanup_a(struct list_head *actions, int ovr)
 
 int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
 		    struct nlattr *est, char *name, int ovr, int bind,
-		    struct list_head *actions)
+		    struct list_head *actions, struct netlink_ext_ack *extack)
 {
 	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 	struct tc_action *act;
 	int err;
 	int i;
 
-	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL);
+	err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, extack);
 	if (err < 0)
 		return err;
 
 	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
-		act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind);
+		act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind,
+					extack);
 		if (IS_ERR(act)) {
 			err = PTR_ERR(act);
 			goto err;
@@ -822,7 +838,7 @@ static int tca_get_fill(struct sk_buff *skb, struct list_head *actions,
 	t->tca__pad2 = 0;
 
 	nest = nla_nest_start(skb, TCA_ACT_TAB);
-	if (nest == NULL)
+	if (!nest)
 		goto out_nlmsg_trim;
 
 	if (tcf_action_dump(skb, actions, bind, ref) < 0)
@@ -840,7 +856,8 @@ static int tca_get_fill(struct sk_buff *skb, struct list_head *actions,
 
 static int
 tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
-	       struct list_head *actions, int event)
+	       struct list_head *actions, int event,
+	       struct netlink_ext_ack *extack)
 {
 	struct sk_buff *skb;
 
@@ -849,6 +866,7 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
 		return -ENOBUFS;
 	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event,
 			 0, 0) <= 0) {
+		NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while adding TC action");
 		kfree_skb(skb);
 		return -EINVAL;
 	}
@@ -857,7 +875,8 @@ tcf_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
 }
 
 static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
-					  struct nlmsghdr *n, u32 portid)
+					  struct nlmsghdr *n, u32 portid,
+					  struct netlink_ext_ack *extack)
 {
 	struct nlattr *tb[TCA_ACT_MAX + 1];
 	const struct tc_action_ops *ops;
@@ -865,22 +884,26 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
 	int index;
 	int err;
 
-	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
+	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, extack);
 	if (err < 0)
 		goto err_out;
 
 	err = -EINVAL;
 	if (tb[TCA_ACT_INDEX] == NULL ||
-	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index))
+	    nla_len(tb[TCA_ACT_INDEX]) < sizeof(index)) {
+		NL_SET_ERR_MSG(extack, "Invalid TC action index value");
 		goto err_out;
+	}
 	index = nla_get_u32(tb[TCA_ACT_INDEX]);
 
 	err = -EINVAL;
 	ops = tc_lookup_action(tb[TCA_ACT_KIND]);
-	if (!ops) /* could happen in batch of actions */
+	if (!ops) { /* could happen in batch of actions */
+		NL_SET_ERR_MSG(extack, "Specified TC action not found");
 		goto err_out;
+	}
 	err = -ENOENT;
-	if (ops->lookup(net, &a, index) == 0)
+	if (ops->lookup(net, &a, index, extack) == 0)
 		goto err_mod;
 
 	module_put(ops->owner);
@@ -893,7 +916,8 @@ static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
 }
 
 static int tca_action_flush(struct net *net, struct nlattr *nla,
-			    struct nlmsghdr *n, u32 portid)
+			    struct nlmsghdr *n, u32 portid,
+			    struct netlink_ext_ack *extack)
 {
 	struct sk_buff *skb;
 	unsigned char *b;
@@ -907,39 +931,45 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 	int err = -ENOMEM;
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
-	if (!skb) {
-		pr_debug("tca_action_flush: failed skb alloc\n");
+	if (!skb)
 		return err;
-	}
 
 	b = skb_tail_pointer(skb);
 
-	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, NULL);
+	err = nla_parse_nested(tb, TCA_ACT_MAX, nla, NULL, extack);
 	if (err < 0)
 		goto err_out;
 
 	err = -EINVAL;
 	kind = tb[TCA_ACT_KIND];
 	ops = tc_lookup_action(kind);
-	if (!ops) /*some idjot trying to flush unknown action */
+	if (!ops) { /*some idjot trying to flush unknown action */
+		NL_SET_ERR_MSG(extack, "Cannot flush unknown TC action");
 		goto err_out;
+	}
 
 	nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION,
 			sizeof(*t), 0);
-	if (!nlh)
+	if (!nlh) {
+		NL_SET_ERR_MSG(extack, "Failed to create TC action flush notification");
 		goto out_module_put;
+	}
 	t = nlmsg_data(nlh);
 	t->tca_family = AF_UNSPEC;
 	t->tca__pad1 = 0;
 	t->tca__pad2 = 0;
 
 	nest = nla_nest_start(skb, TCA_ACT_TAB);
-	if (nest == NULL)
+	if (!nest) {
+		NL_SET_ERR_MSG(extack, "Failed to add new netlink message");
 		goto out_module_put;
+	}
 
-	err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops);
-	if (err <= 0)
+	err = ops->walk(net, skb, &dcb, RTM_DELACTION, ops, extack);
+	if (err <= 0) {
+		nla_nest_cancel(skb, nest);
 		goto out_module_put;
+	}
 
 	nla_nest_end(skb, nest);
 
@@ -950,6 +980,8 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 			     n->nlmsg_flags & NLM_F_ECHO);
 	if (err > 0)
 		return 0;
+	if (err < 0)
+		NL_SET_ERR_MSG(extack, "Failed to send TC action flush notification");
 
 	return err;
 
@@ -962,7 +994,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 
 static int
 tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
-	       u32 portid)
+	       u32 portid, struct netlink_ext_ack *extack)
 {
 	int ret;
 	struct sk_buff *skb;
@@ -973,6 +1005,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
 
 	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
 			 0, 1) <= 0) {
+		NL_SET_ERR_MSG(extack, "Failed to fill netlink TC action attributes");
 		kfree_skb(skb);
 		return -EINVAL;
 	}
@@ -980,6 +1013,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
 	/* now do the delete */
 	ret = tcf_action_destroy(actions, 0);
 	if (ret < 0) {
+		NL_SET_ERR_MSG(extack, "Failed to delete TC action");
 		kfree_skb(skb);
 		return ret;
 	}
@@ -993,26 +1027,27 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
 
 static int
 tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
-	      u32 portid, int event)
+	      u32 portid, int event, struct netlink_ext_ack *extack)
 {
 	int i, ret;
 	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 	struct tc_action *act;
 	LIST_HEAD(actions);
 
-	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, NULL);
+	ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, extack);
 	if (ret < 0)
 		return ret;
 
 	if (event == RTM_DELACTION && n->nlmsg_flags & NLM_F_ROOT) {
-		if (tb[1] != NULL)
-			return tca_action_flush(net, tb[1], n, portid);
-		else
-			return -EINVAL;
+		if (tb[1])
+			return tca_action_flush(net, tb[1], n, portid, extack);
+
+		NL_SET_ERR_MSG(extack, "Invalid netlink attributes while flushing TC action");
+		return -EINVAL;
 	}
 
 	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
-		act = tcf_action_get_1(net, tb[i], n, portid);
+		act = tcf_action_get_1(net, tb[i], n, portid, extack);
 		if (IS_ERR(act)) {
 			ret = PTR_ERR(act);
 			goto err;
@@ -1022,9 +1057,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 	}
 
 	if (event == RTM_GETACTION)
-		ret = tcf_get_notify(net, portid, n, &actions, event);
+		ret = tcf_get_notify(net, portid, n, &actions, event, extack);
 	else { /* delete */
-		ret = tcf_del_notify(net, n, &actions, portid);
+		ret = tcf_del_notify(net, n, &actions, portid, extack);
 		if (ret)
 			goto err;
 		return ret;
@@ -1037,7 +1072,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 
 static int
 tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
-	       u32 portid)
+	       u32 portid, struct netlink_ext_ack *extack)
 {
 	struct sk_buff *skb;
 	int err = 0;
@@ -1048,6 +1083,7 @@ tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
 
 	if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
 			 RTM_NEWACTION, 0, 0) <= 0) {
+		NL_SET_ERR_MSG(extack, "Failed to fill netlink attributes while deleting TC action");
 		kfree_skb(skb);
 		return -EINVAL;
 	}
@@ -1060,16 +1096,18 @@ tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
 }
 
 static int tcf_action_add(struct net *net, struct nlattr *nla,
-			  struct nlmsghdr *n, u32 portid, int ovr)
+			  struct nlmsghdr *n, u32 portid, int ovr,
+			  struct netlink_ext_ack *extack)
 {
 	int ret = 0;
 	LIST_HEAD(actions);
 
-	ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, &actions);
+	ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, &actions,
+			      extack);
 	if (ret)
 		return ret;
 
-	return tcf_add_notify(net, n, &actions, portid);
+	return tcf_add_notify(net, n, &actions, portid, extack);
 }
 
 static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
@@ -1097,7 +1135,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
 		return ret;
 
 	if (tca[TCA_ACT_TAB] == NULL) {
-		pr_notice("tc_ctl_action: received NO action attribs\n");
+		NL_SET_ERR_MSG(extack, "Netlink action attributes missing");
 		return -EINVAL;
 	}
 
@@ -1113,17 +1151,18 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
 		if (n->nlmsg_flags & NLM_F_REPLACE)
 			ovr = 1;
 replay:
-		ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr);
+		ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr,
+				     extack);
 		if (ret == -EAGAIN)
 			goto replay;
 		break;
 	case RTM_DELACTION:
 		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
-				    portid, RTM_DELACTION);
+				    portid, RTM_DELACTION, extack);
 		break;
 	case RTM_GETACTION:
 		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
-				    portid, RTM_GETACTION);
+				    portid, RTM_GETACTION, extack);
 		break;
 	default:
 		BUG();
@@ -1218,7 +1257,7 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
 	if (nest == NULL)
 		goto out_module_put;
 
-	ret = a_o->walk(net, skb, cb, RTM_GETACTION, a_o);
+	ret = a_o->walk(net, skb, cb, RTM_GETACTION, a_o, NULL);
 	if (ret < 0)
 		goto out_module_put;
 
@@ -1454,6 +1493,7 @@ static struct pernet_operations tcf_action_net_ops = {
 	.exit = tcf_action_net_exit,
 	.id = &tcf_action_net_id,
 	.size = sizeof(struct tcf_action_net),
+	.async = true,
 };
 
 static int __init tc_action_init(void)
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index b3f2c15affa7..cb3c5d403c88 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -272,7 +272,7 @@ static void tcf_bpf_prog_fill_cfg(const struct tcf_bpf *prog,
 
 static int tcf_bpf_init(struct net *net, struct nlattr *nla,
 			struct nlattr *est, struct tc_action **act,
-			int replace, int bind)
+			int replace, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, bpf_net_id);
 	struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
@@ -367,14 +367,16 @@ static void tcf_bpf_cleanup(struct tc_action *act)
 
 static int tcf_bpf_walker(struct net *net, struct sk_buff *skb,
 			  struct netlink_callback *cb, int type,
-			  const struct tc_action_ops *ops)
+			  const struct tc_action_ops *ops,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, bpf_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_bpf_search(struct net *net, struct tc_action **a, u32 index,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, bpf_net_id);
 
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 2b15ba84e0c8..e4b880fa51fe 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -96,7 +96,8 @@ static const struct nla_policy connmark_policy[TCA_CONNMARK_MAX + 1] = {
 
 static int tcf_connmark_init(struct net *net, struct nlattr *nla,
 			     struct nlattr *est, struct tc_action **a,
-			     int ovr, int bind)
+			     int ovr, int bind,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, connmark_net_id);
 	struct nlattr *tb[TCA_CONNMARK_MAX + 1];
@@ -176,14 +177,16 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_connmark_walker(struct net *net, struct sk_buff *skb,
 			       struct netlink_callback *cb, int type,
-			       const struct tc_action_ops *ops)
+			       const struct tc_action_ops *ops,
+			       struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, connmark_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_connmark_search(struct net *net, struct tc_action **a, u32 index,
+			       struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, connmark_net_id);
 
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index b7ba9b06b147..d5c2e528d150 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -46,7 +46,7 @@ static struct tc_action_ops act_csum_ops;
 
 static int tcf_csum_init(struct net *net, struct nlattr *nla,
 			 struct nlattr *est, struct tc_action **a, int ovr,
-			 int bind)
+			 int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, csum_net_id);
 	struct tcf_csum_params *params_old, *params_new;
@@ -631,14 +631,16 @@ static void tcf_csum_cleanup(struct tc_action *a)
 
 static int tcf_csum_walker(struct net *net, struct sk_buff *skb,
 			   struct netlink_callback *cb, int type,
-			   const struct tc_action_ops *ops)
+			   const struct tc_action_ops *ops,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, csum_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_csum_search(struct net *net, struct tc_action **a, u32 index,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, csum_net_id);
 
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index b56986d41c87..f072bcf33760 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -56,7 +56,7 @@ static const struct nla_policy gact_policy[TCA_GACT_MAX + 1] = {
 
 static int tcf_gact_init(struct net *net, struct nlattr *nla,
 			 struct nlattr *est, struct tc_action **a,
-			 int ovr, int bind)
+			 int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, gact_net_id);
 	struct nlattr *tb[TCA_GACT_MAX + 1];
@@ -201,14 +201,16 @@ static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_gact_walker(struct net *net, struct sk_buff *skb,
 			   struct netlink_callback *cb, int type,
-			   const struct tc_action_ops *ops)
+			   const struct tc_action_ops *ops,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, gact_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_gact_search(struct net *net, struct tc_action **a, u32 index,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, gact_net_id);
 
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 5954e992685a..a5994cf0512b 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -447,7 +447,7 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
 
 static int tcf_ife_init(struct net *net, struct nlattr *nla,
 			struct nlattr *est, struct tc_action **a,
-			int ovr, int bind)
+			int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, ife_net_id);
 	struct nlattr *tb[TCA_IFE_MAX + 1];
@@ -824,14 +824,16 @@ static int tcf_ife_act(struct sk_buff *skb, const struct tc_action *a,
 
 static int tcf_ife_walker(struct net *net, struct sk_buff *skb,
 			  struct netlink_callback *cb, int type,
-			  const struct tc_action_ops *ops)
+			  const struct tc_action_ops *ops,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, ife_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_ife_search(struct net *net, struct tc_action **a, u32 index,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, ife_net_id);
 
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 06e380ae0928..9784629090ad 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -193,7 +193,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
 
 static int tcf_ipt_init(struct net *net, struct nlattr *nla,
 			struct nlattr *est, struct tc_action **a, int ovr,
-			int bind)
+			int bind, struct netlink_ext_ack *extack)
 {
 	return __tcf_ipt_init(net, ipt_net_id, nla, est, a, &act_ipt_ops, ovr,
 			      bind);
@@ -201,7 +201,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla,
 
 static int tcf_xt_init(struct net *net, struct nlattr *nla,
 		       struct nlattr *est, struct tc_action **a, int ovr,
-		       int bind)
+		       int bind, struct netlink_ext_ack *extack)
 {
 	return __tcf_ipt_init(net, xt_net_id, nla, est, a, &act_xt_ops, ovr,
 			      bind);
@@ -303,14 +303,16 @@ static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind,
 
 static int tcf_ipt_walker(struct net *net, struct sk_buff *skb,
 			  struct netlink_callback *cb, int type,
-			  const struct tc_action_ops *ops)
+			  const struct tc_action_ops *ops,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, ipt_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, ipt_net_id);
 
@@ -351,14 +353,16 @@ static struct pernet_operations ipt_net_ops = {
 
 static int tcf_xt_walker(struct net *net, struct sk_buff *skb,
 			 struct netlink_callback *cb, int type,
-			 const struct tc_action_ops *ops)
+			 const struct tc_action_ops *ops,
+			 struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, xt_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index,
+			 struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, xt_net_id);
 
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index e6ff88f72900..fd34015331ab 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -69,7 +69,7 @@ static struct tc_action_ops act_mirred_ops;
 
 static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 			   struct nlattr *est, struct tc_action **a, int ovr,
-			   int bind)
+			   int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, mirred_net_id);
 	struct nlattr *tb[TCA_MIRRED_MAX + 1];
@@ -80,13 +80,17 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 	bool exists = false;
 	int ret;
 
-	if (nla == NULL)
+	if (!nla) {
+		NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed");
 		return -EINVAL;
-	ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy, NULL);
+	}
+	ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy, extack);
 	if (ret < 0)
 		return ret;
-	if (tb[TCA_MIRRED_PARMS] == NULL)
+	if (!tb[TCA_MIRRED_PARMS]) {
+		NL_SET_ERR_MSG_MOD(extack, "Missing required mirred parameters");
 		return -EINVAL;
+	}
 	parm = nla_data(tb[TCA_MIRRED_PARMS]);
 
 	exists = tcf_idr_check(tn, parm->index, a, bind);
@@ -102,6 +106,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 	default:
 		if (exists)
 			tcf_idr_release(*a, bind);
+		NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option");
 		return -EINVAL;
 	}
 	if (parm->ifindex) {
@@ -117,8 +122,10 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
 	}
 
 	if (!exists) {
-		if (dev == NULL)
+		if (!dev) {
+			NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
 			return -EINVAL;
+		}
 		ret = tcf_idr_create(tn, parm->index, est, a,
 				     &act_mirred_ops, bind, true);
 		if (ret)
@@ -265,14 +272,16 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind,
 
 static int tcf_mirred_walker(struct net *net, struct sk_buff *skb,
 			     struct netlink_callback *cb, int type,
-			     const struct tc_action_ops *ops)
+			     const struct tc_action_ops *ops,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, mirred_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, mirred_net_id);
 
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 98c6a4b2f523..4b5848b6c252 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -37,7 +37,8 @@ static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
 };
 
 static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
-			struct tc_action **a, int ovr, int bind)
+			struct tc_action **a, int ovr, int bind,
+			struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, nat_net_id);
 	struct nlattr *tb[TCA_NAT_MAX + 1];
@@ -277,14 +278,16 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_nat_walker(struct net *net, struct sk_buff *skb,
 			  struct netlink_callback *cb, int type,
-			  const struct tc_action_ops *ops)
+			  const struct tc_action_ops *ops,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, nat_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index,
+			  struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, nat_net_id);
 
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 349beaffb29e..094303c27c5e 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -132,7 +132,7 @@ static int tcf_pedit_key_ex_dump(struct sk_buff *skb,
 
 static int tcf_pedit_init(struct net *net, struct nlattr *nla,
 			  struct nlattr *est, struct tc_action **a,
-			  int ovr, int bind)
+			  int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, pedit_net_id);
 	struct nlattr *tb[TCA_PEDIT_MAX + 1];
@@ -419,14 +419,16 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_pedit_walker(struct net *net, struct sk_buff *skb,
 			    struct netlink_callback *cb, int type,
-			    const struct tc_action_ops *ops)
+			    const struct tc_action_ops *ops,
+			    struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, pedit_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_pedit_search(struct net *net, struct tc_action **a, u32 index,
+			    struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, pedit_net_id);
 
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 95d3c9097b25..ff55bd6c7db0 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -58,11 +58,12 @@ static struct tc_action_ops act_police_ops;
 
 static int tcf_act_police_walker(struct net *net, struct sk_buff *skb,
 				 struct netlink_callback *cb, int type,
-				 const struct tc_action_ops *ops)
+				 const struct tc_action_ops *ops,
+				 struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, police_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
 static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
@@ -74,7 +75,8 @@ static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
 
 static int tcf_act_police_init(struct net *net, struct nlattr *nla,
 			       struct nlattr *est, struct tc_action **a,
-			       int ovr, int bind)
+			       int ovr, int bind,
+			       struct netlink_ext_ack *extack)
 {
 	int ret = 0, err;
 	struct nlattr *tb[TCA_POLICE_MAX + 1];
@@ -304,7 +306,8 @@ static int tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a,
 	return -1;
 }
 
-static int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_police_search(struct net *net, struct tc_action **a, u32 index,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, police_net_id);
 
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 1ba0df238756..9765145aaf40 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -37,7 +37,7 @@ static const struct nla_policy sample_policy[TCA_SAMPLE_MAX + 1] = {
 
 static int tcf_sample_init(struct net *net, struct nlattr *nla,
 			   struct nlattr *est, struct tc_action **a, int ovr,
-			   int bind)
+			   int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, sample_net_id);
 	struct nlattr *tb[TCA_SAMPLE_MAX + 1];
@@ -202,14 +202,16 @@ static int tcf_sample_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_sample_walker(struct net *net, struct sk_buff *skb,
 			     struct netlink_callback *cb, int type,
-			     const struct tc_action_ops *ops)
+			     const struct tc_action_ops *ops,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, sample_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, sample_net_id);
 
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 425eac11f6da..8244e221fe4f 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -79,7 +79,7 @@ static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = {
 
 static int tcf_simp_init(struct net *net, struct nlattr *nla,
 			 struct nlattr *est, struct tc_action **a,
-			 int ovr, int bind)
+			 int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, simp_net_id);
 	struct nlattr *tb[TCA_DEF_MAX + 1];
@@ -170,14 +170,16 @@ static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_simp_walker(struct net *net, struct sk_buff *skb,
 			   struct netlink_callback *cb, int type,
-			   const struct tc_action_ops *ops)
+			   const struct tc_action_ops *ops,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, simp_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_simp_search(struct net *net, struct tc_action **a, u32 index,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, simp_net_id);
 
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 5a3f691bb545..ddf69fc01bdf 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -66,7 +66,7 @@ static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
 
 static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
 			    struct nlattr *est, struct tc_action **a,
-			    int ovr, int bind)
+			    int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
 	struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
@@ -208,14 +208,16 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb,
 			      struct netlink_callback *cb, int type,
-			      const struct tc_action_ops *ops)
+			      const struct tc_action_ops *ops,
+			      struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index,
+			      struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
 
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index fa975262dbac..a406f191cb84 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -84,7 +84,7 @@ static const struct nla_policy skbmod_policy[TCA_SKBMOD_MAX + 1] = {
 
 static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
 			   struct nlattr *est, struct tc_action **a,
-			   int ovr, int bind)
+			   int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, skbmod_net_id);
 	struct nlattr *tb[TCA_SKBMOD_MAX + 1];
@@ -232,14 +232,16 @@ static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_skbmod_walker(struct net *net, struct sk_buff *skb,
 			     struct netlink_callback *cb, int type,
-			     const struct tc_action_ops *ops)
+			     const struct tc_action_ops *ops,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, skbmod_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_skbmod_search(struct net *net, struct tc_action **a, u32 index,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, skbmod_net_id);
 
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index 0e23aac09ad6..41ff9d0e5c62 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -70,7 +70,7 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = {
 
 static int tunnel_key_init(struct net *net, struct nlattr *nla,
 			   struct nlattr *est, struct tc_action **a,
-			   int ovr, int bind)
+			   int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 	struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1];
@@ -291,14 +291,16 @@ static int tunnel_key_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tunnel_key_walker(struct net *net, struct sk_buff *skb,
 			     struct netlink_callback *cb, int type,
-			     const struct tc_action_ops *ops)
+			     const struct tc_action_ops *ops,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index)
+static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index,
+			     struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
 
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index e1a1b3f3983a..71411a255f04 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -109,7 +109,7 @@ static const struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
 
 static int tcf_vlan_init(struct net *net, struct nlattr *nla,
 			 struct nlattr *est, struct tc_action **a,
-			 int ovr, int bind)
+			 int ovr, int bind, struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, vlan_net_id);
 	struct nlattr *tb[TCA_VLAN_MAX + 1];
@@ -267,14 +267,16 @@ static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
 
 static int tcf_vlan_walker(struct net *net, struct sk_buff *skb,
 			   struct netlink_callback *cb, int type,
-			   const struct tc_action_ops *ops)
+			   const struct tc_action_ops *ops,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, vlan_net_id);
 
-	return tcf_generic_walker(tn, skb, cb, type, ops);
+	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
 }
 
-static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index)
+static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index,
+			   struct netlink_ext_ack *extack)
 {
 	struct tc_action_net *tn = net_generic(net, vlan_net_id);
 
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 2bc1bc23d42e..3e14d38e5d42 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -376,17 +376,12 @@ struct tcf_net {
 static unsigned int tcf_net_id;
 
 static int tcf_block_insert(struct tcf_block *block, struct net *net,
-			    u32 block_index, struct netlink_ext_ack *extack)
+			    struct netlink_ext_ack *extack)
 {
 	struct tcf_net *tn = net_generic(net, tcf_net_id);
-	int err;
 
-	err = idr_alloc_u32(&tn->idr, block, &block_index, block_index,
-			    GFP_KERNEL);
-	if (err)
-		return err;
-	block->index = block_index;
-	return 0;
+	return idr_alloc_u32(&tn->idr, block, &block->index, block->index,
+			     GFP_KERNEL);
 }
 
 static void tcf_block_remove(struct tcf_block *block, struct net *net)
@@ -397,6 +392,7 @@ static void tcf_block_remove(struct tcf_block *block, struct net *net)
 }
 
 static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
+					  u32 block_index,
 					  struct netlink_ext_ack *extack)
 {
 	struct tcf_block *block;
@@ -419,10 +415,13 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
 		err = -ENOMEM;
 		goto err_chain_create;
 	}
-	block->net = qdisc_net(q);
 	block->refcnt = 1;
 	block->net = net;
-	block->q = q;
+	block->index = block_index;
+
+	/* Don't store q pointer for blocks which are shared */
+	if (!tcf_block_shared(block))
+		block->q = q;
 	return block;
 
 err_chain_create:
@@ -518,13 +517,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
 	}
 
 	if (!block) {
-		block = tcf_block_create(net, q, extack);
+		block = tcf_block_create(net, q, ei->block_index, extack);
 		if (IS_ERR(block))
 			return PTR_ERR(block);
 		created = true;
-		if (ei->block_index) {
-			err = tcf_block_insert(block, net,
-					       ei->block_index, extack);
+		if (tcf_block_shared(block)) {
+			err = tcf_block_insert(block, net, extack);
 			if (err)
 				goto err_block_insert;
 		}
@@ -1434,7 +1432,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
 		if (exts->police && tb[exts->police]) {
 			act = tcf_action_init_1(net, tp, tb[exts->police],
 						rate_tlv, "police", ovr,
-						TCA_ACT_BIND);
+						TCA_ACT_BIND, extack);
 			if (IS_ERR(act))
 				return PTR_ERR(act);
 
@@ -1447,7 +1445,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
 
 			err = tcf_action_init(net, tp, tb[exts->action],
 					      rate_tlv, NULL, ovr, TCA_ACT_BIND,
-					      &actions);
+					      &actions, extack);
 			if (err)
 				return err;
 			list_for_each_entry(act, &actions, list)
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 6c7601a530e3..ed8b6a24b9e9 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -96,7 +96,7 @@ struct tc_u_hnode {
 
 struct tc_u_common {
 	struct tc_u_hnode __rcu	*hlist;
-	struct tcf_block	*block;
+	void			*ptr;
 	int			refcnt;
 	struct idr		handle_idr;
 	struct hlist_node	hnode;
@@ -330,9 +330,25 @@ static struct hlist_head *tc_u_common_hash;
 #define U32_HASH_SHIFT 10
 #define U32_HASH_SIZE (1 << U32_HASH_SHIFT)
 
+static void *tc_u_common_ptr(const struct tcf_proto *tp)
+{
+	struct tcf_block *block = tp->chain->block;
+
+	/* The block sharing is currently supported only
+	 * for classless qdiscs. In that case we use block
+	 * for tc_u_common identification. In case the
+	 * block is not shared, block->q is a valid pointer
+	 * and we can use that. That works for classful qdiscs.
+	 */
+	if (tcf_block_shared(block))
+		return block;
+	else
+		return block->q;
+}
+
 static unsigned int tc_u_hash(const struct tcf_proto *tp)
 {
-	return hash_ptr(tp->chain->block, U32_HASH_SHIFT);
+	return hash_ptr(tc_u_common_ptr(tp), U32_HASH_SHIFT);
 }
 
 static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp)
@@ -342,7 +358,7 @@ static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp)
 
 	h = tc_u_hash(tp);
 	hlist_for_each_entry(tc, &tc_u_common_hash[h], hnode) {
-		if (tc->block == tp->chain->block)
+		if (tc->ptr == tc_u_common_ptr(tp))
 			return tc;
 	}
 	return NULL;
@@ -371,7 +387,7 @@ static int u32_init(struct tcf_proto *tp)
 			kfree(root_ht);
 			return -ENOBUFS;
 		}
-		tp_c->block = tp->chain->block;
+		tp_c->ptr = tc_u_common_ptr(tp);
 		INIT_HLIST_NODE(&tp_c->hnode);
 		idr_init(&tp_c->handle_idr);
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index d512f49ee83c..27e672c12492 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -2128,6 +2128,7 @@ static void __net_exit psched_net_exit(struct net *net)
 static struct pernet_operations psched_net_ops = {
 	.init = psched_net_init,
 	.exit = psched_net_exit,
+	.async = true,
 };
 
 static int __init pktsched_init(void)
diff --git a/net/sctp/Makefile b/net/sctp/Makefile
index 6776582ec449..e845e4588535 100644
--- a/net/sctp/Makefile
+++ b/net/sctp/Makefile
@@ -15,6 +15,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
 	  offload.o stream_sched.o stream_sched_prio.o \
 	  stream_sched_rr.o stream_interleave.o
 
+sctp_diag-y := diag.o
+
 sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o
 sctp-$(CONFIG_PROC_FS) += proc.o
 sctp-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/sctp/debug.c b/net/sctp/debug.c
index 291c97b07058..8f6c2e8c0953 100644
--- a/net/sctp/debug.c
+++ b/net/sctp/debug.c
@@ -81,6 +81,12 @@ const char *sctp_cname(const union sctp_subtype cid)
 	case SCTP_CID_RECONF:
 		return "RECONF";
 
+	case SCTP_CID_I_DATA:
+		return "I_DATA";
+
+	case SCTP_CID_I_FWD_TSN:
+		return "I_FWD_TSN";
+
 	default:
 		break;
 	}
diff --git a/net/sctp/diag.c b/net/sctp/diag.c
new file mode 100644
index 000000000000..078f01a8d582
--- /dev/null
+++ b/net/sctp/diag.c
@@ -0,0 +1,557 @@
+/* SCTP kernel implementation
+ * (C) Copyright Red Hat Inc. 2017
+ *
+ * This file is part of the SCTP kernel implementation
+ *
+ * These functions implement sctp diag support.
+ *
+ * This SCTP implementation 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, or (at your option)
+ * any later version.
+ *
+ * This SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ *                 ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email addresched(es):
+ *    lksctp developers <linux-sctp@vger.kernel.org>
+ *
+ * Written or modified by:
+ *    Xin Long <lucien.xin@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/inet_diag.h>
+#include <linux/sock_diag.h>
+#include <net/sctp/sctp.h>
+
+static void sctp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
+			       void *info);
+
+/* define some functions to make asoc/ep fill look clean */
+static void inet_diag_msg_sctpasoc_fill(struct inet_diag_msg *r,
+					struct sock *sk,
+					struct sctp_association *asoc)
+{
+	union sctp_addr laddr, paddr;
+	struct dst_entry *dst;
+	struct timer_list *t3_rtx = &asoc->peer.primary_path->T3_rtx_timer;
+
+	laddr = list_entry(asoc->base.bind_addr.address_list.next,
+			   struct sctp_sockaddr_entry, list)->a;
+	paddr = asoc->peer.primary_path->ipaddr;
+	dst = asoc->peer.primary_path->dst;
+
+	r->idiag_family = sk->sk_family;
+	r->id.idiag_sport = htons(asoc->base.bind_addr.port);
+	r->id.idiag_dport = htons(asoc->peer.port);
+	r->id.idiag_if = dst ? dst->dev->ifindex : 0;
+	sock_diag_save_cookie(sk, r->id.idiag_cookie);
+
+#if IS_ENABLED(CONFIG_IPV6)
+	if (sk->sk_family == AF_INET6) {
+		*(struct in6_addr *)r->id.idiag_src = laddr.v6.sin6_addr;
+		*(struct in6_addr *)r->id.idiag_dst = paddr.v6.sin6_addr;
+	} else
+#endif
+	{
+		memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
+		memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
+
+		r->id.idiag_src[0] = laddr.v4.sin_addr.s_addr;
+		r->id.idiag_dst[0] = paddr.v4.sin_addr.s_addr;
+	}
+
+	r->idiag_state = asoc->state;
+	if (timer_pending(t3_rtx)) {
+		r->idiag_timer = SCTP_EVENT_TIMEOUT_T3_RTX;
+		r->idiag_retrans = asoc->rtx_data_chunks;
+		r->idiag_expires = jiffies_to_msecs(t3_rtx->expires - jiffies);
+	} else {
+		r->idiag_timer = 0;
+		r->idiag_retrans = 0;
+		r->idiag_expires = 0;
+	}
+}
+
+static int inet_diag_msg_sctpladdrs_fill(struct sk_buff *skb,
+					 struct list_head *address_list)
+{
+	struct sctp_sockaddr_entry *laddr;
+	int addrlen = sizeof(struct sockaddr_storage);
+	int addrcnt = 0;
+	struct nlattr *attr;
+	void *info = NULL;
+
+	list_for_each_entry_rcu(laddr, address_list, list)
+		addrcnt++;
+
+	attr = nla_reserve(skb, INET_DIAG_LOCALS, addrlen * addrcnt);
+	if (!attr)
+		return -EMSGSIZE;
+
+	info = nla_data(attr);
+	list_for_each_entry_rcu(laddr, address_list, list) {
+		memcpy(info, &laddr->a, sizeof(laddr->a));
+		memset(info + sizeof(laddr->a), 0, addrlen - sizeof(laddr->a));
+		info += addrlen;
+	}
+
+	return 0;
+}
+
+static int inet_diag_msg_sctpaddrs_fill(struct sk_buff *skb,
+					struct sctp_association *asoc)
+{
+	int addrlen = sizeof(struct sockaddr_storage);
+	struct sctp_transport *from;
+	struct nlattr *attr;
+	void *info = NULL;
+
+	attr = nla_reserve(skb, INET_DIAG_PEERS,
+			   addrlen * asoc->peer.transport_count);
+	if (!attr)
+		return -EMSGSIZE;
+
+	info = nla_data(attr);
+	list_for_each_entry(from, &asoc->peer.transport_addr_list,
+			    transports) {
+		memcpy(info, &from->ipaddr, sizeof(from->ipaddr));
+		memset(info + sizeof(from->ipaddr), 0,
+		       addrlen - sizeof(from->ipaddr));
+		info += addrlen;
+	}
+
+	return 0;
+}
+
+/* sctp asoc/ep fill*/
+static int inet_sctp_diag_fill(struct sock *sk, struct sctp_association *asoc,
+			       struct sk_buff *skb,
+			       const struct inet_diag_req_v2 *req,
+			       struct user_namespace *user_ns,
+			       int portid, u32 seq, u16 nlmsg_flags,
+			       const struct nlmsghdr *unlh,
+			       bool net_admin)
+{
+	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
+	struct list_head *addr_list;
+	struct inet_diag_msg *r;
+	struct nlmsghdr  *nlh;
+	int ext = req->idiag_ext;
+	struct sctp_infox infox;
+	void *info = NULL;
+
+	nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r),
+			nlmsg_flags);
+	if (!nlh)
+		return -EMSGSIZE;
+
+	r = nlmsg_data(nlh);
+	BUG_ON(!sk_fullsock(sk));
+
+	if (asoc) {
+		inet_diag_msg_sctpasoc_fill(r, sk, asoc);
+	} else {
+		inet_diag_msg_common_fill(r, sk);
+		r->idiag_state = sk->sk_state;
+		r->idiag_timer = 0;
+		r->idiag_retrans = 0;
+	}
+
+	if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin))
+		goto errout;
+
+	if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) {
+		u32 mem[SK_MEMINFO_VARS];
+		int amt;
+
+		if (asoc && asoc->ep->sndbuf_policy)
+			amt = asoc->sndbuf_used;
+		else
+			amt = sk_wmem_alloc_get(sk);
+		mem[SK_MEMINFO_WMEM_ALLOC] = amt;
+		if (asoc && asoc->ep->rcvbuf_policy)
+			amt = atomic_read(&asoc->rmem_alloc);
+		else
+			amt = sk_rmem_alloc_get(sk);
+		mem[SK_MEMINFO_RMEM_ALLOC] = amt;
+		mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf;
+		mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf;
+		mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
+		mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued;
+		mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
+		mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len;
+		mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops);
+
+		if (nla_put(skb, INET_DIAG_SKMEMINFO, sizeof(mem), &mem) < 0)
+			goto errout;
+	}
+
+	if (ext & (1 << (INET_DIAG_INFO - 1))) {
+		struct nlattr *attr;
+
+		attr = nla_reserve_64bit(skb, INET_DIAG_INFO,
+					 sizeof(struct sctp_info),
+					 INET_DIAG_PAD);
+		if (!attr)
+			goto errout;
+
+		info = nla_data(attr);
+	}
+	infox.sctpinfo = (struct sctp_info *)info;
+	infox.asoc = asoc;
+	sctp_diag_get_info(sk, r, &infox);
+
+	addr_list = asoc ? &asoc->base.bind_addr.address_list
+			 : &ep->base.bind_addr.address_list;
+	if (inet_diag_msg_sctpladdrs_fill(skb, addr_list))
+		goto errout;
+
+	if (asoc && (ext & (1 << (INET_DIAG_CONG - 1))))
+		if (nla_put_string(skb, INET_DIAG_CONG, "reno") < 0)
+			goto errout;
+
+	if (asoc && inet_diag_msg_sctpaddrs_fill(skb, asoc))
+		goto errout;
+
+	nlmsg_end(skb, nlh);
+	return 0;
+
+errout:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+/* callback and param */
+struct sctp_comm_param {
+	struct sk_buff *skb;
+	struct netlink_callback *cb;
+	const struct inet_diag_req_v2 *r;
+	const struct nlmsghdr *nlh;
+	bool net_admin;
+};
+
+static size_t inet_assoc_attr_size(struct sctp_association *asoc)
+{
+	int addrlen = sizeof(struct sockaddr_storage);
+	int addrcnt = 0;
+	struct sctp_sockaddr_entry *laddr;
+
+	list_for_each_entry_rcu(laddr, &asoc->base.bind_addr.address_list,
+				list)
+		addrcnt++;
+
+	return	  nla_total_size(sizeof(struct sctp_info))
+		+ nla_total_size(1) /* INET_DIAG_SHUTDOWN */
+		+ nla_total_size(1) /* INET_DIAG_TOS */
+		+ nla_total_size(1) /* INET_DIAG_TCLASS */
+		+ nla_total_size(4) /* INET_DIAG_MARK */
+		+ nla_total_size(addrlen * asoc->peer.transport_count)
+		+ nla_total_size(addrlen * addrcnt)
+		+ nla_total_size(sizeof(struct inet_diag_meminfo))
+		+ nla_total_size(sizeof(struct inet_diag_msg))
+		+ 64;
+}
+
+static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p)
+{
+	struct sctp_association *assoc = tsp->asoc;
+	struct sock *sk = tsp->asoc->base.sk;
+	struct sctp_comm_param *commp = p;
+	struct sk_buff *in_skb = commp->skb;
+	const struct inet_diag_req_v2 *req = commp->r;
+	const struct nlmsghdr *nlh = commp->nlh;
+	struct net *net = sock_net(in_skb->sk);
+	struct sk_buff *rep;
+	int err;
+
+	err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
+	if (err)
+		goto out;
+
+	err = -ENOMEM;
+	rep = nlmsg_new(inet_assoc_attr_size(assoc), GFP_KERNEL);
+	if (!rep)
+		goto out;
+
+	lock_sock(sk);
+	if (sk != assoc->base.sk) {
+		release_sock(sk);
+		sk = assoc->base.sk;
+		lock_sock(sk);
+	}
+	err = inet_sctp_diag_fill(sk, assoc, rep, req,
+				  sk_user_ns(NETLINK_CB(in_skb).sk),
+				  NETLINK_CB(in_skb).portid,
+				  nlh->nlmsg_seq, 0, nlh,
+				  commp->net_admin);
+	release_sock(sk);
+	if (err < 0) {
+		WARN_ON(err == -EMSGSIZE);
+		kfree_skb(rep);
+		goto out;
+	}
+
+	err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid,
+			      MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+out:
+	return err;
+}
+
+static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
+{
+	struct sctp_endpoint *ep = tsp->asoc->ep;
+	struct sctp_comm_param *commp = p;
+	struct sock *sk = ep->base.sk;
+	struct sk_buff *skb = commp->skb;
+	struct netlink_callback *cb = commp->cb;
+	const struct inet_diag_req_v2 *r = commp->r;
+	struct sctp_association *assoc;
+	int err = 0;
+
+	lock_sock(sk);
+	list_for_each_entry(assoc, &ep->asocs, asocs) {
+		if (cb->args[4] < cb->args[1])
+			goto next;
+
+		if (r->id.idiag_sport != htons(assoc->base.bind_addr.port) &&
+		    r->id.idiag_sport)
+			goto next;
+		if (r->id.idiag_dport != htons(assoc->peer.port) &&
+		    r->id.idiag_dport)
+			goto next;
+
+		if (!cb->args[3] &&
+		    inet_sctp_diag_fill(sk, NULL, skb, r,
+					sk_user_ns(NETLINK_CB(cb->skb).sk),
+					NETLINK_CB(cb->skb).portid,
+					cb->nlh->nlmsg_seq,
+					NLM_F_MULTI, cb->nlh,
+					commp->net_admin) < 0) {
+			err = 1;
+			goto release;
+		}
+		cb->args[3] = 1;
+
+		if (inet_sctp_diag_fill(sk, assoc, skb, r,
+					sk_user_ns(NETLINK_CB(cb->skb).sk),
+					NETLINK_CB(cb->skb).portid,
+					cb->nlh->nlmsg_seq, 0, cb->nlh,
+					commp->net_admin) < 0) {
+			err = 1;
+			goto release;
+		}
+next:
+		cb->args[4]++;
+	}
+	cb->args[1] = 0;
+	cb->args[3] = 0;
+	cb->args[4] = 0;
+release:
+	release_sock(sk);
+	return err;
+}
+
+static int sctp_sock_filter(struct sctp_transport *tsp, void *p)
+{
+	struct sctp_endpoint *ep = tsp->asoc->ep;
+	struct sctp_comm_param *commp = p;
+	struct sock *sk = ep->base.sk;
+	const struct inet_diag_req_v2 *r = commp->r;
+	struct sctp_association *assoc =
+		list_entry(ep->asocs.next, struct sctp_association, asocs);
+
+	/* find the ep only once through the transports by this condition */
+	if (tsp->asoc != assoc)
+		return 0;
+
+	if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family)
+		return 0;
+
+	return 1;
+}
+
+static int sctp_ep_dump(struct sctp_endpoint *ep, void *p)
+{
+	struct sctp_comm_param *commp = p;
+	struct sock *sk = ep->base.sk;
+	struct sk_buff *skb = commp->skb;
+	struct netlink_callback *cb = commp->cb;
+	const struct inet_diag_req_v2 *r = commp->r;
+	struct net *net = sock_net(skb->sk);
+	struct inet_sock *inet = inet_sk(sk);
+	int err = 0;
+
+	if (!net_eq(sock_net(sk), net))
+		goto out;
+
+	if (cb->args[4] < cb->args[1])
+		goto next;
+
+	if (!(r->idiag_states & TCPF_LISTEN) && !list_empty(&ep->asocs))
+		goto next;
+
+	if (r->sdiag_family != AF_UNSPEC &&
+	    sk->sk_family != r->sdiag_family)
+		goto next;
+
+	if (r->id.idiag_sport != inet->inet_sport &&
+	    r->id.idiag_sport)
+		goto next;
+
+	if (r->id.idiag_dport != inet->inet_dport &&
+	    r->id.idiag_dport)
+		goto next;
+
+	if (inet_sctp_diag_fill(sk, NULL, skb, r,
+				sk_user_ns(NETLINK_CB(cb->skb).sk),
+				NETLINK_CB(cb->skb).portid,
+				cb->nlh->nlmsg_seq, NLM_F_MULTI,
+				cb->nlh, commp->net_admin) < 0) {
+		err = 2;
+		goto out;
+	}
+next:
+	cb->args[4]++;
+out:
+	return err;
+}
+
+/* define the functions for sctp_diag_handler*/
+static void sctp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
+			       void *info)
+{
+	struct sctp_infox *infox = (struct sctp_infox *)info;
+
+	if (infox->asoc) {
+		r->idiag_rqueue = atomic_read(&infox->asoc->rmem_alloc);
+		r->idiag_wqueue = infox->asoc->sndbuf_used;
+	} else {
+		r->idiag_rqueue = sk->sk_ack_backlog;
+		r->idiag_wqueue = sk->sk_max_ack_backlog;
+	}
+	if (infox->sctpinfo)
+		sctp_get_sctp_info(sk, infox->asoc, infox->sctpinfo);
+}
+
+static int sctp_diag_dump_one(struct sk_buff *in_skb,
+			      const struct nlmsghdr *nlh,
+			      const struct inet_diag_req_v2 *req)
+{
+	struct net *net = sock_net(in_skb->sk);
+	union sctp_addr laddr, paddr;
+	struct sctp_comm_param commp = {
+		.skb = in_skb,
+		.r = req,
+		.nlh = nlh,
+		.net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN),
+	};
+
+	if (req->sdiag_family == AF_INET) {
+		laddr.v4.sin_port = req->id.idiag_sport;
+		laddr.v4.sin_addr.s_addr = req->id.idiag_src[0];
+		laddr.v4.sin_family = AF_INET;
+
+		paddr.v4.sin_port = req->id.idiag_dport;
+		paddr.v4.sin_addr.s_addr = req->id.idiag_dst[0];
+		paddr.v4.sin_family = AF_INET;
+	} else {
+		laddr.v6.sin6_port = req->id.idiag_sport;
+		memcpy(&laddr.v6.sin6_addr, req->id.idiag_src,
+		       sizeof(laddr.v6.sin6_addr));
+		laddr.v6.sin6_family = AF_INET6;
+
+		paddr.v6.sin6_port = req->id.idiag_dport;
+		memcpy(&paddr.v6.sin6_addr, req->id.idiag_dst,
+		       sizeof(paddr.v6.sin6_addr));
+		paddr.v6.sin6_family = AF_INET6;
+	}
+
+	return sctp_transport_lookup_process(sctp_tsp_dump_one,
+					     net, &laddr, &paddr, &commp);
+}
+
+static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
+			   const struct inet_diag_req_v2 *r, struct nlattr *bc)
+{
+	u32 idiag_states = r->idiag_states;
+	struct net *net = sock_net(skb->sk);
+	struct sctp_comm_param commp = {
+		.skb = skb,
+		.cb = cb,
+		.r = r,
+		.net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN),
+	};
+	int pos = cb->args[2];
+
+	/* eps hashtable dumps
+	 * args:
+	 * 0 : if it will traversal listen sock
+	 * 1 : to record the sock pos of this time's traversal
+	 * 4 : to work as a temporary variable to traversal list
+	 */
+	if (cb->args[0] == 0) {
+		if (!(idiag_states & TCPF_LISTEN))
+			goto skip;
+		if (sctp_for_each_endpoint(sctp_ep_dump, &commp))
+			goto done;
+skip:
+		cb->args[0] = 1;
+		cb->args[1] = 0;
+		cb->args[4] = 0;
+	}
+
+	/* asocs by transport hashtable dump
+	 * args:
+	 * 1 : to record the assoc pos of this time's traversal
+	 * 2 : to record the transport pos of this time's traversal
+	 * 3 : to mark if we have dumped the ep info of the current asoc
+	 * 4 : to work as a temporary variable to traversal list
+	 * 5 : to save the sk we get from travelsing the tsp list.
+	 */
+	if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
+		goto done;
+
+	sctp_for_each_transport(sctp_sock_filter, sctp_sock_dump,
+				net, &pos, &commp);
+	cb->args[2] = pos;
+
+done:
+	cb->args[1] = cb->args[4];
+	cb->args[4] = 0;
+}
+
+static const struct inet_diag_handler sctp_diag_handler = {
+	.dump		 = sctp_diag_dump,
+	.dump_one	 = sctp_diag_dump_one,
+	.idiag_get_info  = sctp_diag_get_info,
+	.idiag_type	 = IPPROTO_SCTP,
+	.idiag_info_size = sizeof(struct sctp_info),
+};
+
+static int __init sctp_diag_init(void)
+{
+	return inet_diag_register(&sctp_diag_handler);
+}
+
+static void __exit sctp_diag_exit(void)
+{
+	inet_diag_unregister(&sctp_diag_handler);
+}
+
+module_init(sctp_diag_init);
+module_exit(sctp_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-132);
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 141c9c466ec1..0247cc432e02 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -897,15 +897,12 @@ int sctp_hash_transport(struct sctp_transport *t)
 	rhl_for_each_entry_rcu(transport, tmp, list, node)
 		if (transport->asoc->ep == t->asoc->ep) {
 			rcu_read_unlock();
-			err = -EEXIST;
-			goto out;
+			return -EEXIST;
 		}
 	rcu_read_unlock();
 
 	err = rhltable_insert_key(&sctp_transport_hashtable, &arg,
 				  &t->node, sctp_hash_params);
-
-out:
 	if (err)
 		pr_err_once("insert transport fail, errno %d\n", err);
 
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e35d4f73d2df..0d873c58e516 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -952,16 +952,16 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
 
 /* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */
 static int sctp_getname(struct socket *sock, struct sockaddr *uaddr,
-			int *uaddr_len, int peer)
+			int peer)
 {
 	int rc;
 
-	rc = inet6_getname(sock, uaddr, uaddr_len, peer);
+	rc = inet6_getname(sock, uaddr, peer);
 
-	if (rc != 0)
+	if (rc < 0)
 		return rc;
 
-	*uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk),
+	rc = sctp_v6_addr_to_user(sctp_sk(sock->sk),
 					  (union sctp_addr *)uaddr);
 
 	return rc;
diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c
deleted file mode 100644
index a72a7d925d46..000000000000
--- a/net/sctp/sctp_diag.c
+++ /dev/null
@@ -1,526 +0,0 @@
-#include <linux/module.h>
-#include <linux/inet_diag.h>
-#include <linux/sock_diag.h>
-#include <net/sctp/sctp.h>
-
-static void sctp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
-			       void *info);
-
-/* define some functions to make asoc/ep fill look clean */
-static void inet_diag_msg_sctpasoc_fill(struct inet_diag_msg *r,
-					struct sock *sk,
-					struct sctp_association *asoc)
-{
-	union sctp_addr laddr, paddr;
-	struct dst_entry *dst;
-	struct timer_list *t3_rtx = &asoc->peer.primary_path->T3_rtx_timer;
-
-	laddr = list_entry(asoc->base.bind_addr.address_list.next,
-			   struct sctp_sockaddr_entry, list)->a;
-	paddr = asoc->peer.primary_path->ipaddr;
-	dst = asoc->peer.primary_path->dst;
-
-	r->idiag_family = sk->sk_family;
-	r->id.idiag_sport = htons(asoc->base.bind_addr.port);
-	r->id.idiag_dport = htons(asoc->peer.port);
-	r->id.idiag_if = dst ? dst->dev->ifindex : 0;
-	sock_diag_save_cookie(sk, r->id.idiag_cookie);
-
-#if IS_ENABLED(CONFIG_IPV6)
-	if (sk->sk_family == AF_INET6) {
-		*(struct in6_addr *)r->id.idiag_src = laddr.v6.sin6_addr;
-		*(struct in6_addr *)r->id.idiag_dst = paddr.v6.sin6_addr;
-	} else
-#endif
-	{
-		memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src));
-		memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst));
-
-		r->id.idiag_src[0] = laddr.v4.sin_addr.s_addr;
-		r->id.idiag_dst[0] = paddr.v4.sin_addr.s_addr;
-	}
-
-	r->idiag_state = asoc->state;
-	if (timer_pending(t3_rtx)) {
-		r->idiag_timer = SCTP_EVENT_TIMEOUT_T3_RTX;
-		r->idiag_retrans = asoc->rtx_data_chunks;
-		r->idiag_expires = jiffies_to_msecs(t3_rtx->expires - jiffies);
-	} else {
-		r->idiag_timer = 0;
-		r->idiag_retrans = 0;
-		r->idiag_expires = 0;
-	}
-}
-
-static int inet_diag_msg_sctpladdrs_fill(struct sk_buff *skb,
-					 struct list_head *address_list)
-{
-	struct sctp_sockaddr_entry *laddr;
-	int addrlen = sizeof(struct sockaddr_storage);
-	int addrcnt = 0;
-	struct nlattr *attr;
-	void *info = NULL;
-
-	list_for_each_entry_rcu(laddr, address_list, list)
-		addrcnt++;
-
-	attr = nla_reserve(skb, INET_DIAG_LOCALS, addrlen * addrcnt);
-	if (!attr)
-		return -EMSGSIZE;
-
-	info = nla_data(attr);
-	list_for_each_entry_rcu(laddr, address_list, list) {
-		memcpy(info, &laddr->a, sizeof(laddr->a));
-		memset(info + sizeof(laddr->a), 0, addrlen - sizeof(laddr->a));
-		info += addrlen;
-	}
-
-	return 0;
-}
-
-static int inet_diag_msg_sctpaddrs_fill(struct sk_buff *skb,
-					struct sctp_association *asoc)
-{
-	int addrlen = sizeof(struct sockaddr_storage);
-	struct sctp_transport *from;
-	struct nlattr *attr;
-	void *info = NULL;
-
-	attr = nla_reserve(skb, INET_DIAG_PEERS,
-			   addrlen * asoc->peer.transport_count);
-	if (!attr)
-		return -EMSGSIZE;
-
-	info = nla_data(attr);
-	list_for_each_entry(from, &asoc->peer.transport_addr_list,
-			    transports) {
-		memcpy(info, &from->ipaddr, sizeof(from->ipaddr));
-		memset(info + sizeof(from->ipaddr), 0,
-		       addrlen - sizeof(from->ipaddr));
-		info += addrlen;
-	}
-
-	return 0;
-}
-
-/* sctp asoc/ep fill*/
-static int inet_sctp_diag_fill(struct sock *sk, struct sctp_association *asoc,
-			       struct sk_buff *skb,
-			       const struct inet_diag_req_v2 *req,
-			       struct user_namespace *user_ns,
-			       int portid, u32 seq, u16 nlmsg_flags,
-			       const struct nlmsghdr *unlh,
-			       bool net_admin)
-{
-	struct sctp_endpoint *ep = sctp_sk(sk)->ep;
-	struct list_head *addr_list;
-	struct inet_diag_msg *r;
-	struct nlmsghdr  *nlh;
-	int ext = req->idiag_ext;
-	struct sctp_infox infox;
-	void *info = NULL;
-
-	nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r),
-			nlmsg_flags);
-	if (!nlh)
-		return -EMSGSIZE;
-
-	r = nlmsg_data(nlh);
-	BUG_ON(!sk_fullsock(sk));
-
-	if (asoc) {
-		inet_diag_msg_sctpasoc_fill(r, sk, asoc);
-	} else {
-		inet_diag_msg_common_fill(r, sk);
-		r->idiag_state = sk->sk_state;
-		r->idiag_timer = 0;
-		r->idiag_retrans = 0;
-	}
-
-	if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin))
-		goto errout;
-
-	if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) {
-		u32 mem[SK_MEMINFO_VARS];
-		int amt;
-
-		if (asoc && asoc->ep->sndbuf_policy)
-			amt = asoc->sndbuf_used;
-		else
-			amt = sk_wmem_alloc_get(sk);
-		mem[SK_MEMINFO_WMEM_ALLOC] = amt;
-		if (asoc && asoc->ep->rcvbuf_policy)
-			amt = atomic_read(&asoc->rmem_alloc);
-		else
-			amt = sk_rmem_alloc_get(sk);
-		mem[SK_MEMINFO_RMEM_ALLOC] = amt;
-		mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf;
-		mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf;
-		mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
-		mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued;
-		mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
-		mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len;
-		mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops);
-
-		if (nla_put(skb, INET_DIAG_SKMEMINFO, sizeof(mem), &mem) < 0)
-			goto errout;
-	}
-
-	if (ext & (1 << (INET_DIAG_INFO - 1))) {
-		struct nlattr *attr;
-
-		attr = nla_reserve_64bit(skb, INET_DIAG_INFO,
-					 sizeof(struct sctp_info),
-					 INET_DIAG_PAD);
-		if (!attr)
-			goto errout;
-
-		info = nla_data(attr);
-	}
-	infox.sctpinfo = (struct sctp_info *)info;
-	infox.asoc = asoc;
-	sctp_diag_get_info(sk, r, &infox);
-
-	addr_list = asoc ? &asoc->base.bind_addr.address_list
-			 : &ep->base.bind_addr.address_list;
-	if (inet_diag_msg_sctpladdrs_fill(skb, addr_list))
-		goto errout;
-
-	if (asoc && (ext & (1 << (INET_DIAG_CONG - 1))))
-		if (nla_put_string(skb, INET_DIAG_CONG, "reno") < 0)
-			goto errout;
-
-	if (asoc && inet_diag_msg_sctpaddrs_fill(skb, asoc))
-		goto errout;
-
-	nlmsg_end(skb, nlh);
-	return 0;
-
-errout:
-	nlmsg_cancel(skb, nlh);
-	return -EMSGSIZE;
-}
-
-/* callback and param */
-struct sctp_comm_param {
-	struct sk_buff *skb;
-	struct netlink_callback *cb;
-	const struct inet_diag_req_v2 *r;
-	const struct nlmsghdr *nlh;
-	bool net_admin;
-};
-
-static size_t inet_assoc_attr_size(struct sctp_association *asoc)
-{
-	int addrlen = sizeof(struct sockaddr_storage);
-	int addrcnt = 0;
-	struct sctp_sockaddr_entry *laddr;
-
-	list_for_each_entry_rcu(laddr, &asoc->base.bind_addr.address_list,
-				list)
-		addrcnt++;
-
-	return	  nla_total_size(sizeof(struct sctp_info))
-		+ nla_total_size(1) /* INET_DIAG_SHUTDOWN */
-		+ nla_total_size(1) /* INET_DIAG_TOS */
-		+ nla_total_size(1) /* INET_DIAG_TCLASS */
-		+ nla_total_size(4) /* INET_DIAG_MARK */
-		+ nla_total_size(addrlen * asoc->peer.transport_count)
-		+ nla_total_size(addrlen * addrcnt)
-		+ nla_total_size(sizeof(struct inet_diag_meminfo))
-		+ nla_total_size(sizeof(struct inet_diag_msg))
-		+ 64;
-}
-
-static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p)
-{
-	struct sctp_association *assoc = tsp->asoc;
-	struct sock *sk = tsp->asoc->base.sk;
-	struct sctp_comm_param *commp = p;
-	struct sk_buff *in_skb = commp->skb;
-	const struct inet_diag_req_v2 *req = commp->r;
-	const struct nlmsghdr *nlh = commp->nlh;
-	struct net *net = sock_net(in_skb->sk);
-	struct sk_buff *rep;
-	int err;
-
-	err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
-	if (err)
-		goto out;
-
-	err = -ENOMEM;
-	rep = nlmsg_new(inet_assoc_attr_size(assoc), GFP_KERNEL);
-	if (!rep)
-		goto out;
-
-	lock_sock(sk);
-	if (sk != assoc->base.sk) {
-		release_sock(sk);
-		sk = assoc->base.sk;
-		lock_sock(sk);
-	}
-	err = inet_sctp_diag_fill(sk, assoc, rep, req,
-				  sk_user_ns(NETLINK_CB(in_skb).sk),
-				  NETLINK_CB(in_skb).portid,
-				  nlh->nlmsg_seq, 0, nlh,
-				  commp->net_admin);
-	release_sock(sk);
-	if (err < 0) {
-		WARN_ON(err == -EMSGSIZE);
-		kfree_skb(rep);
-		goto out;
-	}
-
-	err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid,
-			      MSG_DONTWAIT);
-	if (err > 0)
-		err = 0;
-out:
-	return err;
-}
-
-static int sctp_sock_dump(struct sctp_transport *tsp, void *p)
-{
-	struct sctp_endpoint *ep = tsp->asoc->ep;
-	struct sctp_comm_param *commp = p;
-	struct sock *sk = ep->base.sk;
-	struct sk_buff *skb = commp->skb;
-	struct netlink_callback *cb = commp->cb;
-	const struct inet_diag_req_v2 *r = commp->r;
-	struct sctp_association *assoc;
-	int err = 0;
-
-	lock_sock(sk);
-	list_for_each_entry(assoc, &ep->asocs, asocs) {
-		if (cb->args[4] < cb->args[1])
-			goto next;
-
-		if (r->id.idiag_sport != htons(assoc->base.bind_addr.port) &&
-		    r->id.idiag_sport)
-			goto next;
-		if (r->id.idiag_dport != htons(assoc->peer.port) &&
-		    r->id.idiag_dport)
-			goto next;
-
-		if (!cb->args[3] &&
-		    inet_sctp_diag_fill(sk, NULL, skb, r,
-					sk_user_ns(NETLINK_CB(cb->skb).sk),
-					NETLINK_CB(cb->skb).portid,
-					cb->nlh->nlmsg_seq,
-					NLM_F_MULTI, cb->nlh,
-					commp->net_admin) < 0) {
-			err = 1;
-			goto release;
-		}
-		cb->args[3] = 1;
-
-		if (inet_sctp_diag_fill(sk, assoc, skb, r,
-					sk_user_ns(NETLINK_CB(cb->skb).sk),
-					NETLINK_CB(cb->skb).portid,
-					cb->nlh->nlmsg_seq, 0, cb->nlh,
-					commp->net_admin) < 0) {
-			err = 1;
-			goto release;
-		}
-next:
-		cb->args[4]++;
-	}
-	cb->args[1] = 0;
-	cb->args[3] = 0;
-	cb->args[4] = 0;
-release:
-	release_sock(sk);
-	return err;
-}
-
-static int sctp_sock_filter(struct sctp_transport *tsp, void *p)
-{
-	struct sctp_endpoint *ep = tsp->asoc->ep;
-	struct sctp_comm_param *commp = p;
-	struct sock *sk = ep->base.sk;
-	const struct inet_diag_req_v2 *r = commp->r;
-	struct sctp_association *assoc =
-		list_entry(ep->asocs.next, struct sctp_association, asocs);
-
-	/* find the ep only once through the transports by this condition */
-	if (tsp->asoc != assoc)
-		return 0;
-
-	if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family)
-		return 0;
-
-	return 1;
-}
-
-static int sctp_ep_dump(struct sctp_endpoint *ep, void *p)
-{
-	struct sctp_comm_param *commp = p;
-	struct sock *sk = ep->base.sk;
-	struct sk_buff *skb = commp->skb;
-	struct netlink_callback *cb = commp->cb;
-	const struct inet_diag_req_v2 *r = commp->r;
-	struct net *net = sock_net(skb->sk);
-	struct inet_sock *inet = inet_sk(sk);
-	int err = 0;
-
-	if (!net_eq(sock_net(sk), net))
-		goto out;
-
-	if (cb->args[4] < cb->args[1])
-		goto next;
-
-	if (!(r->idiag_states & TCPF_LISTEN) && !list_empty(&ep->asocs))
-		goto next;
-
-	if (r->sdiag_family != AF_UNSPEC &&
-	    sk->sk_family != r->sdiag_family)
-		goto next;
-
-	if (r->id.idiag_sport != inet->inet_sport &&
-	    r->id.idiag_sport)
-		goto next;
-
-	if (r->id.idiag_dport != inet->inet_dport &&
-	    r->id.idiag_dport)
-		goto next;
-
-	if (inet_sctp_diag_fill(sk, NULL, skb, r,
-				sk_user_ns(NETLINK_CB(cb->skb).sk),
-				NETLINK_CB(cb->skb).portid,
-				cb->nlh->nlmsg_seq, NLM_F_MULTI,
-				cb->nlh, commp->net_admin) < 0) {
-		err = 2;
-		goto out;
-	}
-next:
-	cb->args[4]++;
-out:
-	return err;
-}
-
-/* define the functions for sctp_diag_handler*/
-static void sctp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
-			       void *info)
-{
-	struct sctp_infox *infox = (struct sctp_infox *)info;
-
-	if (infox->asoc) {
-		r->idiag_rqueue = atomic_read(&infox->asoc->rmem_alloc);
-		r->idiag_wqueue = infox->asoc->sndbuf_used;
-	} else {
-		r->idiag_rqueue = sk->sk_ack_backlog;
-		r->idiag_wqueue = sk->sk_max_ack_backlog;
-	}
-	if (infox->sctpinfo)
-		sctp_get_sctp_info(sk, infox->asoc, infox->sctpinfo);
-}
-
-static int sctp_diag_dump_one(struct sk_buff *in_skb,
-			      const struct nlmsghdr *nlh,
-			      const struct inet_diag_req_v2 *req)
-{
-	struct net *net = sock_net(in_skb->sk);
-	union sctp_addr laddr, paddr;
-	struct sctp_comm_param commp = {
-		.skb = in_skb,
-		.r = req,
-		.nlh = nlh,
-		.net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN),
-	};
-
-	if (req->sdiag_family == AF_INET) {
-		laddr.v4.sin_port = req->id.idiag_sport;
-		laddr.v4.sin_addr.s_addr = req->id.idiag_src[0];
-		laddr.v4.sin_family = AF_INET;
-
-		paddr.v4.sin_port = req->id.idiag_dport;
-		paddr.v4.sin_addr.s_addr = req->id.idiag_dst[0];
-		paddr.v4.sin_family = AF_INET;
-	} else {
-		laddr.v6.sin6_port = req->id.idiag_sport;
-		memcpy(&laddr.v6.sin6_addr, req->id.idiag_src,
-		       sizeof(laddr.v6.sin6_addr));
-		laddr.v6.sin6_family = AF_INET6;
-
-		paddr.v6.sin6_port = req->id.idiag_dport;
-		memcpy(&paddr.v6.sin6_addr, req->id.idiag_dst,
-		       sizeof(paddr.v6.sin6_addr));
-		paddr.v6.sin6_family = AF_INET6;
-	}
-
-	return sctp_transport_lookup_process(sctp_tsp_dump_one,
-					     net, &laddr, &paddr, &commp);
-}
-
-static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-			   const struct inet_diag_req_v2 *r, struct nlattr *bc)
-{
-	u32 idiag_states = r->idiag_states;
-	struct net *net = sock_net(skb->sk);
-	struct sctp_comm_param commp = {
-		.skb = skb,
-		.cb = cb,
-		.r = r,
-		.net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN),
-	};
-	int pos = cb->args[2];
-
-	/* eps hashtable dumps
-	 * args:
-	 * 0 : if it will traversal listen sock
-	 * 1 : to record the sock pos of this time's traversal
-	 * 4 : to work as a temporary variable to traversal list
-	 */
-	if (cb->args[0] == 0) {
-		if (!(idiag_states & TCPF_LISTEN))
-			goto skip;
-		if (sctp_for_each_endpoint(sctp_ep_dump, &commp))
-			goto done;
-skip:
-		cb->args[0] = 1;
-		cb->args[1] = 0;
-		cb->args[4] = 0;
-	}
-
-	/* asocs by transport hashtable dump
-	 * args:
-	 * 1 : to record the assoc pos of this time's traversal
-	 * 2 : to record the transport pos of this time's traversal
-	 * 3 : to mark if we have dumped the ep info of the current asoc
-	 * 4 : to work as a temporary variable to traversal list
-	 * 5 : to save the sk we get from travelsing the tsp list.
-	 */
-	if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
-		goto done;
-
-	sctp_for_each_transport(sctp_sock_filter, sctp_sock_dump,
-				net, &pos, &commp);
-	cb->args[2] = pos;
-
-done:
-	cb->args[1] = cb->args[4];
-	cb->args[4] = 0;
-}
-
-static const struct inet_diag_handler sctp_diag_handler = {
-	.dump		 = sctp_diag_dump,
-	.dump_one	 = sctp_diag_dump_one,
-	.idiag_get_info  = sctp_diag_get_info,
-	.idiag_type	 = IPPROTO_SCTP,
-	.idiag_info_size = sizeof(struct sctp_info),
-};
-
-static int __init sctp_diag_init(void)
-{
-	return inet_diag_register(&sctp_diag_handler);
-}
-
-static void __exit sctp_diag_exit(void)
-{
-	inet_diag_unregister(&sctp_diag_handler);
-}
-
-module_init(sctp_diag_init);
-module_exit(sctp_diag_exit);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-132);
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index cedf672487f9..f799043abec9 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -6,7 +6,7 @@
  *
  * This file is part of the SCTP kernel implementation
  *
- * These functions manipulate sctp tsn mapping array.
+ * This file contains sctp stream maniuplation primitives and helpers.
  *
  * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
diff --git a/net/sctp/stream_interleave.c b/net/sctp/stream_interleave.c
index 8c7cf8f08711..d3764c181299 100644
--- a/net/sctp/stream_interleave.c
+++ b/net/sctp/stream_interleave.c
@@ -3,7 +3,8 @@
  *
  * This file is part of the SCTP kernel implementation
  *
- * These functions manipulate sctp stream queue/scheduling.
+ * These functions implement sctp stream message interleaving, mostly
+ * including I-DATA and I-FORWARD-TSN chunks process.
  *
  * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
@@ -954,12 +955,8 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 	__u32 freed = 0;
 	__u16 needed;
 
-	if (chunk) {
-		needed = ntohs(chunk->chunk_hdr->length);
-		needed -= sizeof(struct sctp_idata_chunk);
-	} else {
-		needed = SCTP_DEFAULT_MAXWINDOW;
-	}
+	needed = ntohs(chunk->chunk_hdr->length) -
+		 sizeof(struct sctp_idata_chunk);
 
 	if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) {
 		freed = sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed);
@@ -971,9 +968,8 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 						       needed);
 	}
 
-	if (chunk && freed >= needed)
-		if (sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0)
-			sctp_intl_start_pd(ulpq, gfp);
+	if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0)
+		sctp_intl_start_pd(ulpq, gfp);
 
 	sk_mem_reclaim(asoc->base.sk);
 }
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index da1a5cdefd13..38ae22b65e77 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -281,7 +281,6 @@ int smc_netinfo_by_tcpsk(struct socket *clcsock,
 	struct in_device *in_dev;
 	struct sockaddr_in addr;
 	int rc = -ENOENT;
-	int len;
 
 	if (!dst) {
 		rc = -ENOTCONN;
@@ -293,7 +292,7 @@ int smc_netinfo_by_tcpsk(struct socket *clcsock,
 	}
 
 	/* get address to which the internal TCP socket is bound */
-	kernel_getsockname(clcsock, (struct sockaddr *)&addr, &len);
+	kernel_getsockname(clcsock, (struct sockaddr *)&addr);
 	/* analyze IPv4 specific data of net_device belonging to TCP socket */
 	rcu_read_lock();
 	in_dev = __in_dev_get_rcu(dst->dev);
@@ -771,7 +770,7 @@ static void smc_listen_work(struct work_struct *work)
 	u8 buf[SMC_CLC_MAX_LEN];
 	struct smc_link *link;
 	int reason_code = 0;
-	int rc = 0, len;
+	int rc = 0;
 	__be32 subnet;
 	u8 prefix_len;
 	u8 ibport;
@@ -824,7 +823,7 @@ static void smc_listen_work(struct work_struct *work)
 	}
 
 	/* get address of the peer connected to the internal TCP socket */
-	kernel_getpeername(newclcsock, (struct sockaddr *)&peeraddr, &len);
+	kernel_getpeername(newclcsock, (struct sockaddr *)&peeraddr);
 
 	/* allocate connection / link group */
 	mutex_lock(&smc_create_lgr_pending);
@@ -1075,7 +1074,7 @@ static int smc_accept(struct socket *sock, struct socket *new_sock,
 }
 
 static int smc_getname(struct socket *sock, struct sockaddr *addr,
-		       int *len, int peer)
+		       int peer)
 {
 	struct smc_sock *smc;
 
@@ -1085,7 +1084,7 @@ static int smc_getname(struct socket *sock, struct sockaddr *addr,
 
 	smc = smc_sk(sock->sk);
 
-	return smc->clcsock->ops->getname(smc->clcsock, addr, len, peer);
+	return smc->clcsock->ops->getname(smc->clcsock, addr, peer);
 }
 
 static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
diff --git a/net/socket.c b/net/socket.c
index a93c99b518ca..ab58e57c09ca 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -104,7 +104,6 @@
 #include <linux/ipv6_route.h>
 #include <linux/route.h>
 #include <linux/sockios.h>
-#include <linux/atalk.h>
 #include <net/busy_poll.h>
 #include <linux/errqueue.h>
 
@@ -991,10 +990,11 @@ static long sock_do_ioctl(struct net *net, struct socket *sock,
  *	what to do with it - that's up to the protocol still.
  */
 
-static struct ns_common *get_net_ns(struct ns_common *ns)
+struct ns_common *get_net_ns(struct ns_common *ns)
 {
 	return &get_net(container_of(ns, struct net, ns))->ns;
 }
+EXPORT_SYMBOL_GPL(get_net_ns);
 
 static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
@@ -1573,8 +1573,9 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
 		goto out_fd;
 
 	if (upeer_sockaddr) {
-		if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
-					  &len, 2) < 0) {
+		len = newsock->ops->getname(newsock,
+					(struct sockaddr *)&address, 2);
+		if (len < 0) {
 			err = -ECONNABORTED;
 			goto out_fd;
 		}
@@ -1654,7 +1655,7 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
 {
 	struct socket *sock;
 	struct sockaddr_storage address;
-	int len, err, fput_needed;
+	int err, fput_needed;
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 	if (!sock)
@@ -1664,10 +1665,11 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
 	if (err)
 		goto out_put;
 
-	err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0);
-	if (err)
+	err = sock->ops->getname(sock, (struct sockaddr *)&address, 0);
+	if (err < 0)
 		goto out_put;
-	err = move_addr_to_user(&address, len, usockaddr, usockaddr_len);
+        /* "err" is actually length in this case */
+	err = move_addr_to_user(&address, err, usockaddr, usockaddr_len);
 
 out_put:
 	fput_light(sock->file, fput_needed);
@@ -1685,7 +1687,7 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
 {
 	struct socket *sock;
 	struct sockaddr_storage address;
-	int len, err, fput_needed;
+	int err, fput_needed;
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 	if (sock != NULL) {
@@ -1695,11 +1697,10 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
 			return err;
 		}
 
-		err =
-		    sock->ops->getname(sock, (struct sockaddr *)&address, &len,
-				       1);
-		if (!err)
-			err = move_addr_to_user(&address, len, usockaddr,
+		err = sock->ops->getname(sock, (struct sockaddr *)&address, 1);
+		if (err >= 0)
+			/* "err" is actually length in this case */
+			err = move_addr_to_user(&address, err, usockaddr,
 						usockaddr_len);
 		fput_light(sock->file, fput_needed);
 	}
@@ -3166,17 +3167,15 @@ int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
 }
 EXPORT_SYMBOL(kernel_connect);
 
-int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-			 int *addrlen)
+int kernel_getsockname(struct socket *sock, struct sockaddr *addr)
 {
-	return sock->ops->getname(sock, addr, addrlen, 0);
+	return sock->ops->getname(sock, addr, 0);
 }
 EXPORT_SYMBOL(kernel_getsockname);
 
-int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-			 int *addrlen)
+int kernel_getpeername(struct socket *sock, struct sockaddr *addr)
 {
-	return sock->ops->getname(sock, addr, addrlen, 1);
+	return sock->ops->getname(sock, addr, 1);
 }
 EXPORT_SYMBOL(kernel_getpeername);
 
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 6e432ecd7f99..806395687bb6 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1231,7 +1231,7 @@ static const struct sockaddr_in6 rpc_in6addr_loopback = {
  * negative errno is returned.
  */
 static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
-			struct sockaddr *buf, int buflen)
+			struct sockaddr *buf)
 {
 	struct socket *sock;
 	int err;
@@ -1269,7 +1269,7 @@ static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
 		goto out_release;
 	}
 
-	err = kernel_getsockname(sock, buf, &buflen);
+	err = kernel_getsockname(sock, buf);
 	if (err < 0) {
 		dprintk("RPC:       getsockname failed (%d)\n", err);
 		goto out_release;
@@ -1353,7 +1353,7 @@ int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
 	rcu_read_unlock();
 
 	rpc_set_port(sap, 0);
-	err = rpc_sockname(net, sap, salen, buf, buflen);
+	err = rpc_sockname(net, sap, salen, buf);
 	put_net(net);
 	if (err != 0)
 		/* Couldn't discover local address, return ANYADDR */
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 943f2a745cd5..08cd951aaeea 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -832,12 +832,13 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 	}
 	set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
 
-	err = kernel_getpeername(newsock, sin, &slen);
+	err = kernel_getpeername(newsock, sin);
 	if (err < 0) {
 		net_warn_ratelimited("%s: peername failed (err %d)!\n",
 				     serv->sv_name, -err);
 		goto failed;		/* aborted connection or whatever */
 	}
+	slen = err;
 
 	/* Ideally, we would want to reject connections from unauthorized
 	 * hosts here, but when we get encryption, the IP of the host won't
@@ -866,7 +867,8 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 	if (IS_ERR(newsvsk))
 		goto failed;
 	svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
-	err = kernel_getsockname(newsock, sin, &slen);
+	err = kernel_getsockname(newsock, sin);
+	slen = err;
 	if (unlikely(err < 0)) {
 		dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err);
 		slen = offsetof(struct sockaddr, sa_data);
@@ -1465,7 +1467,8 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
 		err = PTR_ERR(svsk);
 		goto out;
 	}
-	if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
+	salen = kernel_getsockname(svsk->sk_sock, sin);
+	if (salen >= 0)
 		svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
 	svc_add_new_perm_xprt(serv, &svsk->sk_xprt);
 	return svc_one_sock_name(svsk, name_return, len);
@@ -1539,10 +1542,10 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
 	if (error < 0)
 		goto bummer;
 
-	newlen = len;
-	error = kernel_getsockname(sock, newsin, &newlen);
+	error = kernel_getsockname(sock, newsin);
 	if (error < 0)
 		goto bummer;
+	newlen = error;
 
 	if (protocol == IPPROTO_TCP) {
 		if ((error = kernel_listen(sock, 64)) < 0)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index a6b8c1f8f92a..956e29c1438d 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1794,10 +1794,9 @@ static void xs_sock_set_reuseport(struct socket *sock)
 static unsigned short xs_sock_getport(struct socket *sock)
 {
 	struct sockaddr_storage buf;
-	int buflen;
 	unsigned short port = 0;
 
-	if (kernel_getsockname(sock, (struct sockaddr *)&buf, &buflen) < 0)
+	if (kernel_getsockname(sock, (struct sockaddr *)&buf) < 0)
 		goto out;
 	switch (buf.ss_family) {
 	case AF_INET6:
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 9aed6fe1bf1a..f424539829b7 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -89,6 +89,7 @@ static void __net_exit sysctl_net_exit(struct net *net)
 static struct pernet_operations sysctl_pernet_ops = {
 	.init = sysctl_net_init,
 	.exit = sysctl_net_exit,
+	.async = true,
 };
 
 static struct ctl_table_header *net_header;
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
index 37bb0bfbd936..1edb7192aa2f 100644
--- a/net/tipc/Makefile
+++ b/net/tipc/Makefile
@@ -9,7 +9,7 @@ tipc-y	+= addr.o bcast.o bearer.o \
 	   core.o link.o discover.o msg.o  \
 	   name_distr.o  subscr.o monitor.o name_table.o net.o  \
 	   netlink.o netlink_compat.o node.o socket.o eth_media.o \
-	   server.o socket.o group.o
+	   topsrv.o socket.o group.o
 
 tipc-$(CONFIG_TIPC_MEDIA_UDP)	+= udp_media.o
 tipc-$(CONFIG_TIPC_MEDIA_IB)	+= ib_media.o
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index c8001471da6c..f3d2e83313e1 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -813,7 +813,7 @@ int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
-int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
 {
 	int err;
 	char *name;
@@ -835,20 +835,27 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
 
 	name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
 
-	rtnl_lock();
 	bearer = tipc_bearer_find(net, name);
-	if (!bearer) {
-		rtnl_unlock();
+	if (!bearer)
 		return -EINVAL;
-	}
 
 	bearer_disable(net, bearer);
-	rtnl_unlock();
 
 	return 0;
 }
 
-int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
+int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+
+	rtnl_lock();
+	err = __tipc_nl_bearer_disable(skb, info);
+	rtnl_unlock();
+
+	return err;
+}
+
+int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
 {
 	int err;
 	char *bearer;
@@ -890,15 +897,18 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
 			prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
 	}
 
+	return tipc_enable_bearer(net, bearer, domain, prio, attrs);
+}
+
+int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+
 	rtnl_lock();
-	err = tipc_enable_bearer(net, bearer, domain, prio, attrs);
-	if (err) {
-		rtnl_unlock();
-		return err;
-	}
+	err = __tipc_nl_bearer_enable(skb, info);
 	rtnl_unlock();
 
-	return 0;
+	return err;
 }
 
 int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
@@ -944,13 +954,13 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
-int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
 {
-	int err;
-	char *name;
 	struct tipc_bearer *b;
 	struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
 	struct net *net = sock_net(skb->sk);
+	char *name;
+	int err;
 
 	if (!info->attrs[TIPC_NLA_BEARER])
 		return -EINVAL;
@@ -965,35 +975,42 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 	name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
 
-	rtnl_lock();
 	b = tipc_bearer_find(net, name);
-	if (!b) {
-		rtnl_unlock();
+	if (!b)
 		return -EINVAL;
-	}
 
 	if (attrs[TIPC_NLA_BEARER_PROP]) {
 		struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
 
 		err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
 					      props);
-		if (err) {
-			rtnl_unlock();
+		if (err)
 			return err;
-		}
 
-		if (props[TIPC_NLA_PROP_TOL])
+		if (props[TIPC_NLA_PROP_TOL]) {
 			b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
+			tipc_node_apply_tolerance(net, b);
+		}
 		if (props[TIPC_NLA_PROP_PRIO])
 			b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
 		if (props[TIPC_NLA_PROP_WIN])
 			b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
 	}
-	rtnl_unlock();
 
 	return 0;
 }
 
+int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+
+	rtnl_lock();
+	err = __tipc_nl_bearer_set(skb, info);
+	rtnl_unlock();
+
+	return err;
+}
+
 static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
 			       struct tipc_media *media, int nlflags)
 {
@@ -1115,7 +1132,7 @@ int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
-int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
 {
 	int err;
 	char *name;
@@ -1133,22 +1150,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 	name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]);
 
-	rtnl_lock();
 	m = tipc_media_find(name);
-	if (!m) {
-		rtnl_unlock();
+	if (!m)
 		return -EINVAL;
-	}
 
 	if (attrs[TIPC_NLA_MEDIA_PROP]) {
 		struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
 
 		err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP],
 					      props);
-		if (err) {
-			rtnl_unlock();
+		if (err)
 			return err;
-		}
 
 		if (props[TIPC_NLA_PROP_TOL])
 			m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
@@ -1157,7 +1169,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
 		if (props[TIPC_NLA_PROP_WIN])
 			m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
 	}
-	rtnl_unlock();
 
 	return 0;
 }
+
+int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+
+	rtnl_lock();
+	err = __tipc_nl_media_set(skb, info);
+	rtnl_unlock();
+
+	return err;
+}
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 42d6eeeb646d..a53613d95bc9 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -188,15 +188,19 @@ extern struct tipc_media udp_media_info;
 #endif
 
 int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
 
 int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
 
 int tipc_media_set_priority(const char *name, u32 new_value);
 int tipc_media_set_window(const char *name, u32 new_value);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 20b21af2ff14..ff8b071654f5 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -64,7 +64,7 @@ struct tipc_bearer;
 struct tipc_bc_base;
 struct tipc_link;
 struct tipc_name_table;
-struct tipc_server;
+struct tipc_topsrv;
 struct tipc_monitor;
 
 #define TIPC_MOD_VER "2.0.0"
@@ -112,7 +112,7 @@ struct tipc_net {
 	struct list_head dist_queue;
 
 	/* Topology subscription server */
-	struct tipc_server *topsrv;
+	struct tipc_topsrv *topsrv;
 	atomic_t subscription_count;
 };
 
@@ -131,7 +131,7 @@ static inline struct list_head *tipc_nodes(struct net *net)
 	return &tipc_net(net)->node_list;
 }
 
-static inline struct tipc_server *tipc_topsrv(struct net *net)
+static inline struct tipc_topsrv *tipc_topsrv(struct net *net)
 {
 	return tipc_net(net)->topsrv;
 }
diff --git a/net/tipc/group.c b/net/tipc/group.c
index 122162a31816..03086ccb7746 100644
--- a/net/tipc/group.c
+++ b/net/tipc/group.c
@@ -37,7 +37,7 @@
 #include "addr.h"
 #include "group.h"
 #include "bcast.h"
-#include "server.h"
+#include "topsrv.h"
 #include "msg.h"
 #include "socket.h"
 #include "node.h"
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2d6b2aed30e0..3c230466804d 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2126,7 +2126,8 @@ void tipc_link_set_tolerance(struct tipc_link *l, u32 tol,
 			     struct sk_buff_head *xmitq)
 {
 	l->tolerance = tol;
-	tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, tol, 0, xmitq);
+	if (link_is_up(l))
+		tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, tol, 0, xmitq);
 }
 
 void tipc_link_set_prio(struct tipc_link *l, u32 prio,
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index ed0457cc99d6..e01c9c691ba2 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -326,10 +326,10 @@ static struct publication *tipc_nameseq_insert_publ(struct net *net,
 
 	/* Any subscriptions waiting for notification?  */
 	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
-		tipc_subscrp_report_overlap(s, publ->lower, publ->upper,
-					    TIPC_PUBLISHED, publ->ref,
-					    publ->node, publ->scope,
-					    created_subseq);
+		tipc_sub_report_overlap(s, publ->lower, publ->upper,
+					TIPC_PUBLISHED, publ->ref,
+					publ->node, publ->scope,
+					created_subseq);
 	}
 	return publ;
 }
@@ -397,10 +397,9 @@ static struct publication *tipc_nameseq_remove_publ(struct net *net,
 
 	/* Notify any waiting subscriptions */
 	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
-		tipc_subscrp_report_overlap(s, publ->lower, publ->upper,
-					    TIPC_WITHDRAWN, publ->ref,
-					    publ->node, publ->scope,
-					    removed_subseq);
+		tipc_sub_report_overlap(s, publ->lower, publ->upper,
+					TIPC_WITHDRAWN, publ->ref, publ->node,
+					publ->scope, removed_subseq);
 	}
 
 	return publ;
@@ -412,33 +411,37 @@ static struct publication *tipc_nameseq_remove_publ(struct net *net,
  * sequence overlapping with the requested sequence
  */
 static void tipc_nameseq_subscribe(struct name_seq *nseq,
-				   struct tipc_subscription *s,
-				   bool status)
+				   struct tipc_subscription *sub)
 {
 	struct sub_seq *sseq = nseq->sseqs;
 	struct tipc_name_seq ns;
+	struct tipc_subscr *s = &sub->evt.s;
+	bool no_status;
 
-	tipc_subscrp_convert_seq(&s->evt.s.seq, s->swap, &ns);
+	ns.type = tipc_sub_read(s, seq.type);
+	ns.lower = tipc_sub_read(s, seq.lower);
+	ns.upper = tipc_sub_read(s, seq.upper);
+	no_status = tipc_sub_read(s, filter) & TIPC_SUB_NO_STATUS;
 
-	tipc_subscrp_get(s);
-	list_add(&s->nameseq_list, &nseq->subscriptions);
+	tipc_sub_get(sub);
+	list_add(&sub->nameseq_list, &nseq->subscriptions);
 
-	if (!status || !sseq)
+	if (no_status || !sseq)
 		return;
 
 	while (sseq != &nseq->sseqs[nseq->first_free]) {
-		if (tipc_subscrp_check_overlap(&ns, sseq->lower, sseq->upper)) {
+		if (tipc_sub_check_overlap(&ns, sseq->lower, sseq->upper)) {
 			struct publication *crs;
 			struct name_info *info = sseq->info;
 			int must_report = 1;
 
 			list_for_each_entry(crs, &info->zone_list, zone_list) {
-				tipc_subscrp_report_overlap(s, sseq->lower,
-							    sseq->upper,
-							    TIPC_PUBLISHED,
-							    crs->ref, crs->node,
-							    crs->scope,
-							    must_report);
+				tipc_sub_report_overlap(sub, sseq->lower,
+							sseq->upper,
+							TIPC_PUBLISHED,
+							crs->ref, crs->node,
+							crs->scope,
+							must_report);
 				must_report = 0;
 			}
 		}
@@ -808,24 +811,27 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
 /**
  * tipc_nametbl_subscribe - add a subscription object to the name table
  */
-void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status)
+void tipc_nametbl_subscribe(struct tipc_subscription *sub)
 {
-	struct tipc_net *tn = net_generic(s->net, tipc_net_id);
-	u32 type = tipc_subscrp_convert_seq_type(s->evt.s.seq.type, s->swap);
+	struct tipc_net *tn = tipc_net(sub->net);
+	struct tipc_subscr *s = &sub->evt.s;
+	u32 type = tipc_sub_read(s, seq.type);
 	int index = hash(type);
 	struct name_seq *seq;
 	struct tipc_name_seq ns;
 
 	spin_lock_bh(&tn->nametbl_lock);
-	seq = nametbl_find_seq(s->net, type);
+	seq = nametbl_find_seq(sub->net, type);
 	if (!seq)
 		seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
 	if (seq) {
 		spin_lock_bh(&seq->lock);
-		tipc_nameseq_subscribe(seq, s, status);
+		tipc_nameseq_subscribe(seq, sub);
 		spin_unlock_bh(&seq->lock);
 	} else {
-		tipc_subscrp_convert_seq(&s->evt.s.seq, s->swap, &ns);
+		ns.type = tipc_sub_read(s, seq.type);
+		ns.lower = tipc_sub_read(s, seq.lower);
+		ns.upper = tipc_sub_read(s, seq.upper);
 		pr_warn("Failed to create subscription for {%u,%u,%u}\n",
 			ns.type, ns.lower, ns.upper);
 	}
@@ -835,18 +841,19 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status)
 /**
  * tipc_nametbl_unsubscribe - remove a subscription object from name table
  */
-void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
+void tipc_nametbl_unsubscribe(struct tipc_subscription *sub)
 {
-	struct tipc_net *tn = net_generic(s->net, tipc_net_id);
+	struct tipc_subscr *s = &sub->evt.s;
+	struct tipc_net *tn = tipc_net(sub->net);
 	struct name_seq *seq;
-	u32 type = tipc_subscrp_convert_seq_type(s->evt.s.seq.type, s->swap);
+	u32 type = tipc_sub_read(s, seq.type);
 
 	spin_lock_bh(&tn->nametbl_lock);
-	seq = nametbl_find_seq(s->net, type);
+	seq = nametbl_find_seq(sub->net, type);
 	if (seq != NULL) {
 		spin_lock_bh(&seq->lock);
-		list_del_init(&s->nameseq_list);
-		tipc_subscrp_put(s);
+		list_del_init(&sub->nameseq_list);
+		tipc_sub_put(sub);
 		if (!seq->first_free && list_empty(&seq->subscriptions)) {
 			hlist_del_init_rcu(&seq->ns_list);
 			kfree(seq->sseqs);
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index f56e7cb3d436..17652602d5e2 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -120,7 +120,7 @@ struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
 struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
 					     u32 lower, u32 node, u32 ref,
 					     u32 key);
-void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status);
+void tipc_nametbl_subscribe(struct tipc_subscription *s);
 void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
 int tipc_nametbl_init(struct net *net);
 void tipc_nametbl_stop(struct net *net);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 719c5924b638..1a2fde0d6f61 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -200,7 +200,7 @@ int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len;
 }
 
-int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
 {
 	struct net *net = sock_net(skb->sk);
 	struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -241,10 +241,19 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
 		if (!tipc_addr_node_valid(addr))
 			return -EINVAL;
 
-		rtnl_lock();
 		tipc_net_start(net, addr);
-		rtnl_unlock();
 	}
 
 	return 0;
 }
+
+int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+
+	rtnl_lock();
+	err = __tipc_nl_net_set(skb, info);
+	rtnl_unlock();
+
+	return err;
+}
diff --git a/net/tipc/net.h b/net/tipc/net.h
index c7c254902873..c0306aa2374b 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -47,5 +47,6 @@ void tipc_net_stop(struct net *net);
 
 int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
 
 #endif
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index e48f0b2c01b9..4492cda45566 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -285,10 +285,6 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
 	if (!trans_buf)
 		return -ENOMEM;
 
-	err = (*cmd->transcode)(cmd, trans_buf, msg);
-	if (err)
-		goto trans_out;
-
 	attrbuf = kmalloc((tipc_genl_family.maxattr + 1) *
 			sizeof(struct nlattr *), GFP_KERNEL);
 	if (!attrbuf) {
@@ -296,27 +292,34 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
 		goto trans_out;
 	}
 
-	err = nla_parse(attrbuf, tipc_genl_family.maxattr,
-			(const struct nlattr *)trans_buf->data,
-			trans_buf->len, NULL, NULL);
-	if (err)
-		goto parse_out;
-
 	doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (!doit_buf) {
 		err = -ENOMEM;
-		goto parse_out;
+		goto attrbuf_out;
 	}
 
-	doit_buf->sk = msg->dst_sk;
-
 	memset(&info, 0, sizeof(info));
 	info.attrs = attrbuf;
 
+	rtnl_lock();
+	err = (*cmd->transcode)(cmd, trans_buf, msg);
+	if (err)
+		goto doit_out;
+
+	err = nla_parse(attrbuf, tipc_genl_family.maxattr,
+			(const struct nlattr *)trans_buf->data,
+			trans_buf->len, NULL, NULL);
+	if (err)
+		goto doit_out;
+
+	doit_buf->sk = msg->dst_sk;
+
 	err = (*cmd->doit)(doit_buf, &info);
+doit_out:
+	rtnl_unlock();
 
 	kfree_skb(doit_buf);
-parse_out:
+attrbuf_out:
 	kfree(attrbuf);
 trans_out:
 	kfree_skb(trans_buf);
@@ -722,13 +725,13 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
 
 	media = tipc_media_find(lc->name);
 	if (media) {
-		cmd->doit = &tipc_nl_media_set;
+		cmd->doit = &__tipc_nl_media_set;
 		return tipc_nl_compat_media_set(skb, msg);
 	}
 
 	bearer = tipc_bearer_find(msg->net, lc->name);
 	if (bearer) {
-		cmd->doit = &tipc_nl_bearer_set;
+		cmd->doit = &__tipc_nl_bearer_set;
 		return tipc_nl_compat_bearer_set(skb, msg);
 	}
 
@@ -1089,12 +1092,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
 		return tipc_nl_compat_dumpit(&dump, msg);
 	case TIPC_CMD_ENABLE_BEARER:
 		msg->req_type = TIPC_TLV_BEARER_CONFIG;
-		doit.doit = tipc_nl_bearer_enable;
+		doit.doit = __tipc_nl_bearer_enable;
 		doit.transcode = tipc_nl_compat_bearer_enable;
 		return tipc_nl_compat_doit(&doit, msg);
 	case TIPC_CMD_DISABLE_BEARER:
 		msg->req_type = TIPC_TLV_BEARER_NAME;
-		doit.doit = tipc_nl_bearer_disable;
+		doit.doit = __tipc_nl_bearer_disable;
 		doit.transcode = tipc_nl_compat_bearer_disable;
 		return tipc_nl_compat_doit(&doit, msg);
 	case TIPC_CMD_SHOW_LINK_STATS:
@@ -1148,12 +1151,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
 		return tipc_nl_compat_dumpit(&dump, msg);
 	case TIPC_CMD_SET_NODE_ADDR:
 		msg->req_type = TIPC_TLV_NET_ADDR;
-		doit.doit = tipc_nl_net_set;
+		doit.doit = __tipc_nl_net_set;
 		doit.transcode = tipc_nl_compat_net_set;
 		return tipc_nl_compat_doit(&doit, msg);
 	case TIPC_CMD_SET_NETID:
 		msg->req_type = TIPC_TLV_UNSIGNED;
-		doit.doit = tipc_nl_net_set;
+		doit.doit = __tipc_nl_net_set;
 		doit.transcode = tipc_nl_compat_net_set;
 		return tipc_nl_compat_doit(&doit, msg);
 	case TIPC_CMD_GET_NETID:
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 9036d8756e73..389193d7cf67 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1618,6 +1618,30 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
 	kfree_skb(skb);
 }
 
+void tipc_node_apply_tolerance(struct net *net, struct tipc_bearer *b)
+{
+	struct tipc_net *tn = tipc_net(net);
+	int bearer_id = b->identity;
+	struct sk_buff_head xmitq;
+	struct tipc_link_entry *e;
+	struct tipc_node *n;
+
+	__skb_queue_head_init(&xmitq);
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(n, &tn->node_list, list) {
+		tipc_node_write_lock(n);
+		e = &n->links[bearer_id];
+		if (e->link)
+			tipc_link_set_tolerance(e->link, b->tolerance, &xmitq);
+		tipc_node_write_unlock(n);
+		tipc_bearer_xmit(net, bearer_id, &xmitq, &e->maddr);
+	}
+
+	rcu_read_unlock();
+}
+
 int tipc_nl_peer_rm(struct sk_buff *skb, struct genl_info *info)
 {
 	struct net *net = sock_net(skb->sk);
diff --git a/net/tipc/node.h b/net/tipc/node.h
index acd58d23a70e..4ce5e3a185c0 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -65,6 +65,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
 			  struct tipc_media_addr *maddr,
 			  bool *respond, bool *dupl_addr);
 void tipc_node_delete_links(struct net *net, int bearer_id);
+void tipc_node_apply_tolerance(struct net *net, struct tipc_bearer *b);
 int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
 			   char *linkname, size_t len);
 int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
diff --git a/net/tipc/server.c b/net/tipc/server.c
deleted file mode 100644
index df0c563c90cd..000000000000
--- a/net/tipc/server.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * net/tipc/server.c: TIPC server infrastructure
- *
- * Copyright (c) 2012-2013, Wind River Systems
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "server.h"
-#include "core.h"
-#include "socket.h"
-#include "addr.h"
-#include "msg.h"
-#include <net/sock.h>
-#include <linux/module.h>
-
-/* Number of messages to send before rescheduling */
-#define MAX_SEND_MSG_COUNT	25
-#define MAX_RECV_MSG_COUNT	25
-#define CF_CONNECTED		1
-#define CF_SERVER		2
-
-#define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data)
-
-/**
- * struct tipc_conn - TIPC connection structure
- * @kref: reference counter to connection object
- * @conid: connection identifier
- * @sock: socket handler associated with connection
- * @flags: indicates connection state
- * @server: pointer to connected server
- * @rwork: receive work item
- * @usr_data: user-specified field
- * @rx_action: what to do when connection socket is active
- * @outqueue: pointer to first outbound message in queue
- * @outqueue_lock: control access to the outqueue
- * @outqueue: list of connection objects for its server
- * @swork: send work item
- */
-struct tipc_conn {
-	struct kref kref;
-	int conid;
-	struct socket *sock;
-	unsigned long flags;
-	struct tipc_server *server;
-	struct work_struct rwork;
-	int (*rx_action) (struct tipc_conn *con);
-	void *usr_data;
-	struct list_head outqueue;
-	spinlock_t outqueue_lock;
-	struct work_struct swork;
-};
-
-/* An entry waiting to be sent */
-struct outqueue_entry {
-	struct list_head list;
-	struct kvec iov;
-	struct sockaddr_tipc dest;
-};
-
-static void tipc_recv_work(struct work_struct *work);
-static void tipc_send_work(struct work_struct *work);
-static void tipc_clean_outqueues(struct tipc_conn *con);
-
-static void tipc_conn_kref_release(struct kref *kref)
-{
-	struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
-	struct tipc_server *s = con->server;
-	struct sockaddr_tipc *saddr = s->saddr;
-	struct socket *sock = con->sock;
-	struct sock *sk;
-
-	if (sock) {
-		sk = sock->sk;
-		if (test_bit(CF_SERVER, &con->flags)) {
-			__module_get(sock->ops->owner);
-			__module_get(sk->sk_prot_creator->owner);
-		}
-		saddr->scope = -TIPC_NODE_SCOPE;
-		kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
-		sock_release(sock);
-		con->sock = NULL;
-	}
-	spin_lock_bh(&s->idr_lock);
-	idr_remove(&s->conn_idr, con->conid);
-	s->idr_in_use--;
-	spin_unlock_bh(&s->idr_lock);
-	tipc_clean_outqueues(con);
-	kfree(con);
-}
-
-static void conn_put(struct tipc_conn *con)
-{
-	kref_put(&con->kref, tipc_conn_kref_release);
-}
-
-static void conn_get(struct tipc_conn *con)
-{
-	kref_get(&con->kref);
-}
-
-static struct tipc_conn *tipc_conn_lookup(struct tipc_server *s, int conid)
-{
-	struct tipc_conn *con;
-
-	spin_lock_bh(&s->idr_lock);
-	con = idr_find(&s->conn_idr, conid);
-	if (con) {
-		if (!test_bit(CF_CONNECTED, &con->flags) ||
-		    !kref_get_unless_zero(&con->kref))
-			con = NULL;
-	}
-	spin_unlock_bh(&s->idr_lock);
-	return con;
-}
-
-static void sock_data_ready(struct sock *sk)
-{
-	struct tipc_conn *con;
-
-	read_lock_bh(&sk->sk_callback_lock);
-	con = sock2con(sk);
-	if (con && test_bit(CF_CONNECTED, &con->flags)) {
-		conn_get(con);
-		if (!queue_work(con->server->rcv_wq, &con->rwork))
-			conn_put(con);
-	}
-	read_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void sock_write_space(struct sock *sk)
-{
-	struct tipc_conn *con;
-
-	read_lock_bh(&sk->sk_callback_lock);
-	con = sock2con(sk);
-	if (con && test_bit(CF_CONNECTED, &con->flags)) {
-		conn_get(con);
-		if (!queue_work(con->server->send_wq, &con->swork))
-			conn_put(con);
-	}
-	read_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void tipc_register_callbacks(struct socket *sock, struct tipc_conn *con)
-{
-	struct sock *sk = sock->sk;
-
-	write_lock_bh(&sk->sk_callback_lock);
-
-	sk->sk_data_ready = sock_data_ready;
-	sk->sk_write_space = sock_write_space;
-	sk->sk_user_data = con;
-
-	con->sock = sock;
-
-	write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void tipc_close_conn(struct tipc_conn *con)
-{
-	struct tipc_server *s = con->server;
-	struct sock *sk = con->sock->sk;
-	bool disconnect = false;
-
-	write_lock_bh(&sk->sk_callback_lock);
-	disconnect = test_and_clear_bit(CF_CONNECTED, &con->flags);
-	if (disconnect) {
-		sk->sk_user_data = NULL;
-		if (con->conid)
-			s->tipc_conn_release(con->conid, con->usr_data);
-	}
-	write_unlock_bh(&sk->sk_callback_lock);
-
-	/* Handle concurrent calls from sending and receiving threads */
-	if (!disconnect)
-		return;
-
-	/* Don't flush pending works, -just let them expire */
-	kernel_sock_shutdown(con->sock, SHUT_RDWR);
-	conn_put(con);
-}
-
-static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s)
-{
-	struct tipc_conn *con;
-	int ret;
-
-	con = kzalloc(sizeof(struct tipc_conn), GFP_ATOMIC);
-	if (!con)
-		return ERR_PTR(-ENOMEM);
-
-	kref_init(&con->kref);
-	INIT_LIST_HEAD(&con->outqueue);
-	spin_lock_init(&con->outqueue_lock);
-	INIT_WORK(&con->swork, tipc_send_work);
-	INIT_WORK(&con->rwork, tipc_recv_work);
-
-	spin_lock_bh(&s->idr_lock);
-	ret = idr_alloc(&s->conn_idr, con, 0, 0, GFP_ATOMIC);
-	if (ret < 0) {
-		kfree(con);
-		spin_unlock_bh(&s->idr_lock);
-		return ERR_PTR(-ENOMEM);
-	}
-	con->conid = ret;
-	s->idr_in_use++;
-	spin_unlock_bh(&s->idr_lock);
-
-	set_bit(CF_CONNECTED, &con->flags);
-	con->server = s;
-
-	return con;
-}
-
-static int tipc_receive_from_sock(struct tipc_conn *con)
-{
-	struct tipc_server *s = con->server;
-	struct sock *sk = con->sock->sk;
-	struct sockaddr_tipc addr;
-	struct msghdr msg = {};
-	struct kvec iov;
-	void *buf;
-	int ret;
-
-	buf = kmem_cache_alloc(s->rcvbuf_cache, GFP_ATOMIC);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto out_close;
-	}
-
-	iov.iov_base = buf;
-	iov.iov_len = s->max_rcvbuf_size;
-	msg.msg_name = &addr;
-	iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, iov.iov_len);
-	ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
-	if (ret <= 0) {
-		kmem_cache_free(s->rcvbuf_cache, buf);
-		goto out_close;
-	}
-
-	read_lock_bh(&sk->sk_callback_lock);
-	if (test_bit(CF_CONNECTED, &con->flags))
-		ret = s->tipc_conn_recvmsg(sock_net(con->sock->sk), con->conid,
-					   &addr, con->usr_data, buf, ret);
-	read_unlock_bh(&sk->sk_callback_lock);
-	kmem_cache_free(s->rcvbuf_cache, buf);
-	if (ret < 0)
-		tipc_conn_terminate(s, con->conid);
-	return ret;
-
-out_close:
-	if (ret != -EWOULDBLOCK)
-		tipc_close_conn(con);
-	else if (ret == 0)
-		/* Don't return success if we really got EOF */
-		ret = -EAGAIN;
-
-	return ret;
-}
-
-static int tipc_accept_from_sock(struct tipc_conn *con)
-{
-	struct tipc_server *s = con->server;
-	struct socket *sock = con->sock;
-	struct socket *newsock;
-	struct tipc_conn *newcon;
-	int ret;
-
-	ret = kernel_accept(sock, &newsock, O_NONBLOCK);
-	if (ret < 0)
-		return ret;
-
-	newcon = tipc_alloc_conn(con->server);
-	if (IS_ERR(newcon)) {
-		ret = PTR_ERR(newcon);
-		sock_release(newsock);
-		return ret;
-	}
-
-	newcon->rx_action = tipc_receive_from_sock;
-	tipc_register_callbacks(newsock, newcon);
-
-	/* Notify that new connection is incoming */
-	newcon->usr_data = s->tipc_conn_new(newcon->conid);
-	if (!newcon->usr_data) {
-		sock_release(newsock);
-		conn_put(newcon);
-		return -ENOMEM;
-	}
-
-	/* Wake up receive process in case of 'SYN+' message */
-	newsock->sk->sk_data_ready(newsock->sk);
-	return ret;
-}
-
-static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
-{
-	struct tipc_server *s = con->server;
-	struct socket *sock = NULL;
-	int ret;
-
-	ret = sock_create_kern(s->net, AF_TIPC, SOCK_SEQPACKET, 0, &sock);
-	if (ret < 0)
-		return NULL;
-	ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE,
-				(char *)&s->imp, sizeof(s->imp));
-	if (ret < 0)
-		goto create_err;
-	ret = kernel_bind(sock, (struct sockaddr *)s->saddr, sizeof(*s->saddr));
-	if (ret < 0)
-		goto create_err;
-
-	switch (s->type) {
-	case SOCK_STREAM:
-	case SOCK_SEQPACKET:
-		con->rx_action = tipc_accept_from_sock;
-
-		ret = kernel_listen(sock, 0);
-		if (ret < 0)
-			goto create_err;
-		break;
-	case SOCK_DGRAM:
-	case SOCK_RDM:
-		con->rx_action = tipc_receive_from_sock;
-		break;
-	default:
-		pr_err("Unknown socket type %d\n", s->type);
-		goto create_err;
-	}
-
-	/* As server's listening socket owner and creator is the same module,
-	 * we have to decrease TIPC module reference count to guarantee that
-	 * it remains zero after the server socket is created, otherwise,
-	 * executing "rmmod" command is unable to make TIPC module deleted
-	 * after TIPC module is inserted successfully.
-	 *
-	 * However, the reference count is ever increased twice in
-	 * sock_create_kern(): one is to increase the reference count of owner
-	 * of TIPC socket's proto_ops struct; another is to increment the
-	 * reference count of owner of TIPC proto struct. Therefore, we must
-	 * decrement the module reference count twice to ensure that it keeps
-	 * zero after server's listening socket is created. Of course, we
-	 * must bump the module reference count twice as well before the socket
-	 * is closed.
-	 */
-	module_put(sock->ops->owner);
-	module_put(sock->sk->sk_prot_creator->owner);
-	set_bit(CF_SERVER, &con->flags);
-
-	return sock;
-
-create_err:
-	kernel_sock_shutdown(sock, SHUT_RDWR);
-	sock_release(sock);
-	return NULL;
-}
-
-static int tipc_open_listening_sock(struct tipc_server *s)
-{
-	struct socket *sock;
-	struct tipc_conn *con;
-
-	con = tipc_alloc_conn(s);
-	if (IS_ERR(con))
-		return PTR_ERR(con);
-
-	sock = tipc_create_listen_sock(con);
-	if (!sock) {
-		idr_remove(&s->conn_idr, con->conid);
-		s->idr_in_use--;
-		kfree(con);
-		return -EINVAL;
-	}
-
-	tipc_register_callbacks(sock, con);
-	return 0;
-}
-
-static struct outqueue_entry *tipc_alloc_entry(void *data, int len)
-{
-	struct outqueue_entry *entry;
-	void *buf;
-
-	entry = kmalloc(sizeof(struct outqueue_entry), GFP_ATOMIC);
-	if (!entry)
-		return NULL;
-
-	buf = kmemdup(data, len, GFP_ATOMIC);
-	if (!buf) {
-		kfree(entry);
-		return NULL;
-	}
-
-	entry->iov.iov_base = buf;
-	entry->iov.iov_len = len;
-
-	return entry;
-}
-
-static void tipc_free_entry(struct outqueue_entry *e)
-{
-	kfree(e->iov.iov_base);
-	kfree(e);
-}
-
-static void tipc_clean_outqueues(struct tipc_conn *con)
-{
-	struct outqueue_entry *e, *safe;
-
-	spin_lock_bh(&con->outqueue_lock);
-	list_for_each_entry_safe(e, safe, &con->outqueue, list) {
-		list_del(&e->list);
-		tipc_free_entry(e);
-	}
-	spin_unlock_bh(&con->outqueue_lock);
-}
-
-int tipc_conn_sendmsg(struct tipc_server *s, int conid,
-		      struct sockaddr_tipc *addr, void *data, size_t len)
-{
-	struct outqueue_entry *e;
-	struct tipc_conn *con;
-
-	con = tipc_conn_lookup(s, conid);
-	if (!con)
-		return -EINVAL;
-
-	if (!test_bit(CF_CONNECTED, &con->flags)) {
-		conn_put(con);
-		return 0;
-	}
-
-	e = tipc_alloc_entry(data, len);
-	if (!e) {
-		conn_put(con);
-		return -ENOMEM;
-	}
-
-	if (addr)
-		memcpy(&e->dest, addr, sizeof(struct sockaddr_tipc));
-
-	spin_lock_bh(&con->outqueue_lock);
-	list_add_tail(&e->list, &con->outqueue);
-	spin_unlock_bh(&con->outqueue_lock);
-
-	if (!queue_work(s->send_wq, &con->swork))
-		conn_put(con);
-	return 0;
-}
-
-void tipc_conn_terminate(struct tipc_server *s, int conid)
-{
-	struct tipc_conn *con;
-
-	con = tipc_conn_lookup(s, conid);
-	if (con) {
-		tipc_close_conn(con);
-		conn_put(con);
-	}
-}
-
-bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
-			     u32 upper, u32 filter, int *conid)
-{
-	struct tipc_subscriber *scbr;
-	struct tipc_subscr sub;
-	struct tipc_server *s;
-	struct tipc_conn *con;
-
-	sub.seq.type = type;
-	sub.seq.lower = lower;
-	sub.seq.upper = upper;
-	sub.timeout = TIPC_WAIT_FOREVER;
-	sub.filter = filter;
-	*(u32 *)&sub.usr_handle = port;
-
-	con = tipc_alloc_conn(tipc_topsrv(net));
-	if (IS_ERR(con))
-		return false;
-
-	*conid = con->conid;
-	s = con->server;
-	scbr = s->tipc_conn_new(*conid);
-	if (!scbr) {
-		conn_put(con);
-		return false;
-	}
-
-	con->usr_data = scbr;
-	con->sock = NULL;
-	s->tipc_conn_recvmsg(net, *conid, NULL, scbr, &sub, sizeof(sub));
-	return true;
-}
-
-void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
-{
-	struct tipc_conn *con;
-	struct tipc_server *srv;
-
-	con = tipc_conn_lookup(tipc_topsrv(net), conid);
-	if (!con)
-		return;
-
-	test_and_clear_bit(CF_CONNECTED, &con->flags);
-	srv = con->server;
-	if (con->conid)
-		srv->tipc_conn_release(con->conid, con->usr_data);
-	conn_put(con);
-	conn_put(con);
-}
-
-static void tipc_send_kern_top_evt(struct net *net, struct tipc_event *evt)
-{
-	u32 port = *(u32 *)&evt->s.usr_handle;
-	u32 self = tipc_own_addr(net);
-	struct sk_buff_head evtq;
-	struct sk_buff *skb;
-
-	skb = tipc_msg_create(TOP_SRV, 0, INT_H_SIZE, sizeof(*evt),
-			      self, self, port, port, 0);
-	if (!skb)
-		return;
-	msg_set_dest_droppable(buf_msg(skb), true);
-	memcpy(msg_data(buf_msg(skb)), evt, sizeof(*evt));
-	skb_queue_head_init(&evtq);
-	__skb_queue_tail(&evtq, skb);
-	tipc_sk_rcv(net, &evtq);
-}
-
-static void tipc_send_to_sock(struct tipc_conn *con)
-{
-	struct tipc_server *s = con->server;
-	struct outqueue_entry *e;
-	struct tipc_event *evt;
-	struct msghdr msg;
-	int count = 0;
-	int ret;
-
-	spin_lock_bh(&con->outqueue_lock);
-	while (test_bit(CF_CONNECTED, &con->flags)) {
-		e = list_entry(con->outqueue.next, struct outqueue_entry, list);
-		if ((struct list_head *) e == &con->outqueue)
-			break;
-
-		spin_unlock_bh(&con->outqueue_lock);
-
-		if (con->sock) {
-			memset(&msg, 0, sizeof(msg));
-			msg.msg_flags = MSG_DONTWAIT;
-			if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
-				msg.msg_name = &e->dest;
-				msg.msg_namelen = sizeof(struct sockaddr_tipc);
-			}
-			ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
-					     e->iov.iov_len);
-			if (ret == -EWOULDBLOCK || ret == 0) {
-				cond_resched();
-				goto out;
-			} else if (ret < 0) {
-				goto send_err;
-			}
-		} else {
-			evt = e->iov.iov_base;
-			tipc_send_kern_top_evt(s->net, evt);
-		}
-		/* Don't starve users filling buffers */
-		if (++count >= MAX_SEND_MSG_COUNT) {
-			cond_resched();
-			count = 0;
-		}
-
-		spin_lock_bh(&con->outqueue_lock);
-		list_del(&e->list);
-		tipc_free_entry(e);
-	}
-	spin_unlock_bh(&con->outqueue_lock);
-out:
-	return;
-
-send_err:
-	tipc_close_conn(con);
-}
-
-static void tipc_recv_work(struct work_struct *work)
-{
-	struct tipc_conn *con = container_of(work, struct tipc_conn, rwork);
-	int count = 0;
-
-	while (test_bit(CF_CONNECTED, &con->flags)) {
-		if (con->rx_action(con))
-			break;
-
-		/* Don't flood Rx machine */
-		if (++count >= MAX_RECV_MSG_COUNT) {
-			cond_resched();
-			count = 0;
-		}
-	}
-	conn_put(con);
-}
-
-static void tipc_send_work(struct work_struct *work)
-{
-	struct tipc_conn *con = container_of(work, struct tipc_conn, swork);
-
-	if (test_bit(CF_CONNECTED, &con->flags))
-		tipc_send_to_sock(con);
-
-	conn_put(con);
-}
-
-static void tipc_work_stop(struct tipc_server *s)
-{
-	destroy_workqueue(s->rcv_wq);
-	destroy_workqueue(s->send_wq);
-}
-
-static int tipc_work_start(struct tipc_server *s)
-{
-	s->rcv_wq = alloc_ordered_workqueue("tipc_rcv", 0);
-	if (!s->rcv_wq) {
-		pr_err("can't start tipc receive workqueue\n");
-		return -ENOMEM;
-	}
-
-	s->send_wq = alloc_ordered_workqueue("tipc_send", 0);
-	if (!s->send_wq) {
-		pr_err("can't start tipc send workqueue\n");
-		destroy_workqueue(s->rcv_wq);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-int tipc_server_start(struct tipc_server *s)
-{
-	int ret;
-
-	spin_lock_init(&s->idr_lock);
-	idr_init(&s->conn_idr);
-	s->idr_in_use = 0;
-
-	s->rcvbuf_cache = kmem_cache_create(s->name, s->max_rcvbuf_size,
-					    0, SLAB_HWCACHE_ALIGN, NULL);
-	if (!s->rcvbuf_cache)
-		return -ENOMEM;
-
-	ret = tipc_work_start(s);
-	if (ret < 0) {
-		kmem_cache_destroy(s->rcvbuf_cache);
-		return ret;
-	}
-	ret = tipc_open_listening_sock(s);
-	if (ret < 0) {
-		tipc_work_stop(s);
-		kmem_cache_destroy(s->rcvbuf_cache);
-		return ret;
-	}
-	return ret;
-}
-
-void tipc_server_stop(struct tipc_server *s)
-{
-	struct tipc_conn *con;
-	int id;
-
-	spin_lock_bh(&s->idr_lock);
-	for (id = 0; s->idr_in_use; id++) {
-		con = idr_find(&s->conn_idr, id);
-		if (con) {
-			spin_unlock_bh(&s->idr_lock);
-			tipc_close_conn(con);
-			spin_lock_bh(&s->idr_lock);
-		}
-	}
-	spin_unlock_bh(&s->idr_lock);
-
-	tipc_work_stop(s);
-	kmem_cache_destroy(s->rcvbuf_cache);
-	idr_destroy(&s->conn_idr);
-}
diff --git a/net/tipc/server.h b/net/tipc/server.h
deleted file mode 100644
index 64df7513cd70..000000000000
--- a/net/tipc/server.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * net/tipc/server.h: Include file for TIPC server code
- *
- * Copyright (c) 2012-2013, Wind River Systems
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _TIPC_SERVER_H
-#define _TIPC_SERVER_H
-
-#include <linux/idr.h>
-#include <linux/tipc.h>
-#include <net/net_namespace.h>
-
-#define TIPC_SERVER_NAME_LEN	32
-#define TIPC_SUB_CLUSTER_SCOPE  0x20
-#define TIPC_SUB_NODE_SCOPE     0x40
-#define TIPC_SUB_NO_STATUS      0x80
-
-/**
- * struct tipc_server - TIPC server structure
- * @conn_idr: identifier set of connection
- * @idr_lock: protect the connection identifier set
- * @idr_in_use: amount of allocated identifier entry
- * @net: network namspace instance
- * @rcvbuf_cache: memory cache of server receive buffer
- * @rcv_wq: receive workqueue
- * @send_wq: send workqueue
- * @max_rcvbuf_size: maximum permitted receive message length
- * @tipc_conn_new: callback will be called when new connection is incoming
- * @tipc_conn_release: callback will be called before releasing the connection
- * @tipc_conn_recvmsg: callback will be called when message arrives
- * @saddr: TIPC server address
- * @name: server name
- * @imp: message importance
- * @type: socket type
- */
-struct tipc_server {
-	struct idr conn_idr;
-	spinlock_t idr_lock;
-	int idr_in_use;
-	struct net *net;
-	struct kmem_cache *rcvbuf_cache;
-	struct workqueue_struct *rcv_wq;
-	struct workqueue_struct *send_wq;
-	int max_rcvbuf_size;
-	void *(*tipc_conn_new)(int conid);
-	void (*tipc_conn_release)(int conid, void *usr_data);
-	int (*tipc_conn_recvmsg)(struct net *net, int conid,
-				 struct sockaddr_tipc *addr, void *usr_data,
-				 void *buf, size_t len);
-	struct sockaddr_tipc *saddr;
-	char name[TIPC_SERVER_NAME_LEN];
-	int imp;
-	int type;
-};
-
-int tipc_conn_sendmsg(struct tipc_server *s, int conid,
-		      struct sockaddr_tipc *addr, void *data, size_t len);
-
-bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
-			     u32 upper, u32 filter, int *conid);
-void tipc_topsrv_kern_unsubscr(struct net *net, int conid);
-
-/**
- * tipc_conn_terminate - terminate connection with server
- *
- * Note: Must call it in process context since it might sleep
- */
-void tipc_conn_terminate(struct tipc_server *s, int conid);
-int tipc_server_start(struct tipc_server *s);
-
-void tipc_server_stop(struct tipc_server *s);
-
-#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index b0323ec7971e..f93477187a90 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -665,7 +665,7 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
  *       a completely predictable manner).
  */
 static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
-			int *uaddr_len, int peer)
+			int peer)
 {
 	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
 	struct sock *sk = sock->sk;
@@ -684,13 +684,12 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
 		addr->addr.id.node = tn->own_addr;
 	}
 
-	*uaddr_len = sizeof(*addr);
 	addr->addrtype = TIPC_ADDR_ID;
 	addr->family = AF_TIPC;
 	addr->scope = 0;
 	addr->addr.name.domain = 0;
 
-	return 0;
+	return sizeof(*addr);
 }
 
 /**
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 68e26470c516..6925a989569b 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -1,7 +1,7 @@
 /*
  * net/tipc/subscr.c: TIPC network topology service
  *
- * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2000-2017, Ericsson AB
  * Copyright (c) 2005-2007, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -38,61 +38,30 @@
 #include "name_table.h"
 #include "subscr.h"
 
-/**
- * struct tipc_subscriber - TIPC network topology subscriber
- * @kref: reference counter to tipc_subscription object
- * @conid: connection identifier to server connecting to subscriber
- * @lock: control access to subscriber
- * @subscrp_list: list of subscription objects for this subscriber
- */
-struct tipc_subscriber {
-	struct kref kref;
-	int conid;
-	spinlock_t lock;
-	struct list_head subscrp_list;
-};
-
-static void tipc_subscrb_put(struct tipc_subscriber *subscriber);
-
-/**
- * htohl - convert value to endianness used by destination
- * @in: value to convert
- * @swap: non-zero if endianness must be reversed
- *
- * Returns converted value
- */
-static u32 htohl(u32 in, int swap)
-{
-	return swap ? swab32(in) : in;
-}
-
-static void tipc_subscrp_send_event(struct tipc_subscription *sub,
-				    u32 found_lower, u32 found_upper,
-				    u32 event, u32 port_ref, u32 node)
+static void tipc_sub_send_event(struct tipc_subscription *sub,
+				u32 found_lower, u32 found_upper,
+				u32 event, u32 port, u32 node)
 {
-	struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
-	struct tipc_subscriber *subscriber = sub->subscriber;
-	struct kvec msg_sect;
+	struct tipc_event *evt = &sub->evt;
 
-	msg_sect.iov_base = (void *)&sub->evt;
-	msg_sect.iov_len = sizeof(struct tipc_event);
-	sub->evt.event = htohl(event, sub->swap);
-	sub->evt.found_lower = htohl(found_lower, sub->swap);
-	sub->evt.found_upper = htohl(found_upper, sub->swap);
-	sub->evt.port.ref = htohl(port_ref, sub->swap);
-	sub->evt.port.node = htohl(node, sub->swap);
-	tipc_conn_sendmsg(tn->topsrv, subscriber->conid, NULL,
-			  msg_sect.iov_base, msg_sect.iov_len);
+	if (sub->inactive)
+		return;
+	tipc_evt_write(evt, event, event);
+	tipc_evt_write(evt, found_lower, found_lower);
+	tipc_evt_write(evt, found_upper, found_upper);
+	tipc_evt_write(evt, port.ref, port);
+	tipc_evt_write(evt, port.node, node);
+	tipc_topsrv_queue_evt(sub->net, sub->conid, event, evt);
 }
 
 /**
- * tipc_subscrp_check_overlap - test for subscription overlap with the
+ * tipc_sub_check_overlap - test for subscription overlap with the
  * given values
  *
  * Returns 1 if there is overlap, otherwise 0.
  */
-int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
-			       u32 found_upper)
+int tipc_sub_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
+			   u32 found_upper)
 {
 	if (found_lower < seq->lower)
 		found_lower = seq->lower;
@@ -103,298 +72,98 @@ int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
 	return 1;
 }
 
-u32 tipc_subscrp_convert_seq_type(u32 type, int swap)
-{
-	return htohl(type, swap);
-}
-
-void tipc_subscrp_convert_seq(struct tipc_name_seq *in, int swap,
-			      struct tipc_name_seq *out)
-{
-	out->type = htohl(in->type, swap);
-	out->lower = htohl(in->lower, swap);
-	out->upper = htohl(in->upper, swap);
-}
-
-void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower,
-				 u32 found_upper, u32 event, u32 port_ref,
-				 u32 node, u32 scope, int must)
+void tipc_sub_report_overlap(struct tipc_subscription *sub,
+			     u32 found_lower, u32 found_upper,
+			     u32 event, u32 port, u32 node,
+			     u32 scope, int must)
 {
-	u32 filter = htohl(sub->evt.s.filter, sub->swap);
+	struct tipc_subscr *s = &sub->evt.s;
+	u32 filter = tipc_sub_read(s, filter);
 	struct tipc_name_seq seq;
 
-	tipc_subscrp_convert_seq(&sub->evt.s.seq, sub->swap, &seq);
-	if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper))
+	seq.type = tipc_sub_read(s, seq.type);
+	seq.lower = tipc_sub_read(s, seq.lower);
+	seq.upper = tipc_sub_read(s, seq.upper);
+
+	if (!tipc_sub_check_overlap(&seq, found_lower, found_upper))
 		return;
+
 	if (!must && !(filter & TIPC_SUB_PORTS))
 		return;
 	if (filter & TIPC_SUB_CLUSTER_SCOPE && scope == TIPC_NODE_SCOPE)
 		return;
 	if (filter & TIPC_SUB_NODE_SCOPE && scope != TIPC_NODE_SCOPE)
 		return;
-
-	tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref,
-				node);
+	spin_lock(&sub->lock);
+	tipc_sub_send_event(sub, found_lower, found_upper,
+			    event, port, node);
+	spin_unlock(&sub->lock);
 }
 
-static void tipc_subscrp_timeout(struct timer_list *t)
+static void tipc_sub_timeout(struct timer_list *t)
 {
 	struct tipc_subscription *sub = from_timer(sub, t, timer);
-	struct tipc_subscriber *subscriber = sub->subscriber;
-
-	spin_lock_bh(&subscriber->lock);
-	tipc_nametbl_unsubscribe(sub);
-	list_del(&sub->subscrp_list);
-	spin_unlock_bh(&subscriber->lock);
-
-	/* Notify subscriber of timeout */
-	tipc_subscrp_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
-				TIPC_SUBSCR_TIMEOUT, 0, 0);
-
-	tipc_subscrp_put(sub);
-}
-
-static void tipc_subscrb_kref_release(struct kref *kref)
-{
-	kfree(container_of(kref,struct tipc_subscriber, kref));
-}
-
-static void tipc_subscrb_put(struct tipc_subscriber *subscriber)
-{
-	kref_put(&subscriber->kref, tipc_subscrb_kref_release);
-}
+	struct tipc_subscr *s = &sub->evt.s;
 
-static void tipc_subscrb_get(struct tipc_subscriber *subscriber)
-{
-	kref_get(&subscriber->kref);
+	spin_lock(&sub->lock);
+	tipc_sub_send_event(sub, s->seq.lower, s->seq.upper,
+			    TIPC_SUBSCR_TIMEOUT, 0, 0);
+	sub->inactive = true;
+	spin_unlock(&sub->lock);
 }
 
-static void tipc_subscrp_kref_release(struct kref *kref)
+static void tipc_sub_kref_release(struct kref *kref)
 {
-	struct tipc_subscription *sub = container_of(kref,
-						     struct tipc_subscription,
-						     kref);
-	struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
-	struct tipc_subscriber *subscriber = sub->subscriber;
-
-	atomic_dec(&tn->subscription_count);
-	kfree(sub);
-	tipc_subscrb_put(subscriber);
+	kfree(container_of(kref, struct tipc_subscription, kref));
 }
 
-void tipc_subscrp_put(struct tipc_subscription *subscription)
+void tipc_sub_put(struct tipc_subscription *subscription)
 {
-	kref_put(&subscription->kref, tipc_subscrp_kref_release);
+	kref_put(&subscription->kref, tipc_sub_kref_release);
 }
 
-void tipc_subscrp_get(struct tipc_subscription *subscription)
+void tipc_sub_get(struct tipc_subscription *subscription)
 {
 	kref_get(&subscription->kref);
 }
 
-/* tipc_subscrb_subscrp_delete - delete a specific subscription or all
- * subscriptions for a given subscriber.
- */
-static void tipc_subscrb_subscrp_delete(struct tipc_subscriber *subscriber,
-					struct tipc_subscr *s)
-{
-	struct list_head *subscription_list = &subscriber->subscrp_list;
-	struct tipc_subscription *sub, *temp;
-	u32 timeout;
-
-	spin_lock_bh(&subscriber->lock);
-	list_for_each_entry_safe(sub, temp, subscription_list,  subscrp_list) {
-		if (s && memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr)))
-			continue;
-
-		timeout = htohl(sub->evt.s.timeout, sub->swap);
-		if (timeout == TIPC_WAIT_FOREVER || del_timer(&sub->timer)) {
-			tipc_nametbl_unsubscribe(sub);
-			list_del(&sub->subscrp_list);
-			tipc_subscrp_put(sub);
-		}
-
-		if (s)
-			break;
-	}
-	spin_unlock_bh(&subscriber->lock);
-}
-
-static struct tipc_subscriber *tipc_subscrb_create(int conid)
-{
-	struct tipc_subscriber *subscriber;
-
-	subscriber = kzalloc(sizeof(*subscriber), GFP_ATOMIC);
-	if (!subscriber) {
-		pr_warn("Subscriber rejected, no memory\n");
-		return NULL;
-	}
-	INIT_LIST_HEAD(&subscriber->subscrp_list);
-	kref_init(&subscriber->kref);
-	subscriber->conid = conid;
-	spin_lock_init(&subscriber->lock);
-
-	return subscriber;
-}
-
-static void tipc_subscrb_delete(struct tipc_subscriber *subscriber)
-{
-	tipc_subscrb_subscrp_delete(subscriber, NULL);
-	tipc_subscrb_put(subscriber);
-}
-
-static void tipc_subscrp_cancel(struct tipc_subscr *s,
-				struct tipc_subscriber *subscriber)
-{
-	tipc_subscrb_get(subscriber);
-	tipc_subscrb_subscrp_delete(subscriber, s);
-	tipc_subscrb_put(subscriber);
-}
-
-static struct tipc_subscription *tipc_subscrp_create(struct net *net,
-						     struct tipc_subscr *s,
-						     int swap)
+struct tipc_subscription *tipc_sub_subscribe(struct net *net,
+					     struct tipc_subscr *s,
+					     int conid)
 {
-	struct tipc_net *tn = net_generic(net, tipc_net_id);
+	u32 filter = tipc_sub_read(s, filter);
 	struct tipc_subscription *sub;
-	u32 filter = htohl(s->filter, swap);
+	u32 timeout;
 
-	/* Refuse subscription if global limit exceeded */
-	if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
-		pr_warn("Subscription rejected, limit reached (%u)\n",
-			TIPC_MAX_SUBSCRIPTIONS);
+	if ((filter & TIPC_SUB_PORTS && filter & TIPC_SUB_SERVICE) ||
+	    (tipc_sub_read(s, seq.lower) > tipc_sub_read(s, seq.upper))) {
+		pr_warn("Subscription rejected, illegal request\n");
 		return NULL;
 	}
-
-	/* Allocate subscription object */
 	sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
 	if (!sub) {
 		pr_warn("Subscription rejected, no memory\n");
 		return NULL;
 	}
-
-	/* Initialize subscription object */
 	sub->net = net;
-	if (((filter & TIPC_SUB_PORTS) && (filter & TIPC_SUB_SERVICE)) ||
-	    (htohl(s->seq.lower, swap) > htohl(s->seq.upper, swap))) {
-		pr_warn("Subscription rejected, illegal request\n");
-		kfree(sub);
-		return NULL;
-	}
-
-	sub->swap = swap;
+	sub->conid = conid;
+	sub->inactive = false;
 	memcpy(&sub->evt.s, s, sizeof(*s));
-	atomic_inc(&tn->subscription_count);
+	spin_lock_init(&sub->lock);
 	kref_init(&sub->kref);
-	return sub;
-}
-
-static int tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s,
-				  struct tipc_subscriber *subscriber, int swap,
-				  bool status)
-{
-	struct tipc_subscription *sub = NULL;
-	u32 timeout;
-
-	sub = tipc_subscrp_create(net, s, swap);
-	if (!sub)
-		return -1;
-
-	spin_lock_bh(&subscriber->lock);
-	list_add(&sub->subscrp_list, &subscriber->subscrp_list);
-	sub->subscriber = subscriber;
-	tipc_nametbl_subscribe(sub, status);
-	tipc_subscrb_get(subscriber);
-	spin_unlock_bh(&subscriber->lock);
-
-	timer_setup(&sub->timer, tipc_subscrp_timeout, 0);
-	timeout = htohl(sub->evt.s.timeout, swap);
-
+	tipc_nametbl_subscribe(sub);
+	timer_setup(&sub->timer, tipc_sub_timeout, 0);
+	timeout = tipc_sub_read(&sub->evt.s, timeout);
 	if (timeout != TIPC_WAIT_FOREVER)
 		mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
-	return 0;
-}
-
-/* Handle one termination request for the subscriber */
-static void tipc_subscrb_release_cb(int conid, void *usr_data)
-{
-	tipc_subscrb_delete((struct tipc_subscriber *)usr_data);
-}
-
-/* Handle one request to create a new subscription for the subscriber */
-static int tipc_subscrb_rcv_cb(struct net *net, int conid,
-			       struct sockaddr_tipc *addr, void *usr_data,
-			       void *buf, size_t len)
-{
-	struct tipc_subscriber *subscriber = usr_data;
-	struct tipc_subscr *s = (struct tipc_subscr *)buf;
-	bool status;
-	int swap;
-
-	/* Determine subscriber's endianness */
-	swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE |
-			      TIPC_SUB_CANCEL));
-
-	/* Detect & process a subscription cancellation request */
-	if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
-		s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
-		tipc_subscrp_cancel(s, subscriber);
-		return 0;
-	}
-	status = !(s->filter & htohl(TIPC_SUB_NO_STATUS, swap));
-	return tipc_subscrp_subscribe(net, s, subscriber, swap, status);
-}
-
-/* Handle one request to establish a new subscriber */
-static void *tipc_subscrb_connect_cb(int conid)
-{
-	return (void *)tipc_subscrb_create(conid);
-}
-
-int tipc_topsrv_start(struct net *net)
-{
-	struct tipc_net *tn = net_generic(net, tipc_net_id);
-	const char name[] = "topology_server";
-	struct tipc_server *topsrv;
-	struct sockaddr_tipc *saddr;
-
-	saddr = kzalloc(sizeof(*saddr), GFP_ATOMIC);
-	if (!saddr)
-		return -ENOMEM;
-	saddr->family			= AF_TIPC;
-	saddr->addrtype			= TIPC_ADDR_NAMESEQ;
-	saddr->addr.nameseq.type	= TIPC_TOP_SRV;
-	saddr->addr.nameseq.lower	= TIPC_TOP_SRV;
-	saddr->addr.nameseq.upper	= TIPC_TOP_SRV;
-	saddr->scope			= TIPC_NODE_SCOPE;
-
-	topsrv = kzalloc(sizeof(*topsrv), GFP_ATOMIC);
-	if (!topsrv) {
-		kfree(saddr);
-		return -ENOMEM;
-	}
-	topsrv->net			= net;
-	topsrv->saddr			= saddr;
-	topsrv->imp			= TIPC_CRITICAL_IMPORTANCE;
-	topsrv->type			= SOCK_SEQPACKET;
-	topsrv->max_rcvbuf_size		= sizeof(struct tipc_subscr);
-	topsrv->tipc_conn_recvmsg	= tipc_subscrb_rcv_cb;
-	topsrv->tipc_conn_new		= tipc_subscrb_connect_cb;
-	topsrv->tipc_conn_release	= tipc_subscrb_release_cb;
-
-	strncpy(topsrv->name, name, strlen(name) + 1);
-	tn->topsrv = topsrv;
-	atomic_set(&tn->subscription_count, 0);
-
-	return tipc_server_start(topsrv);
+	return sub;
 }
 
-void tipc_topsrv_stop(struct net *net)
+void tipc_sub_unsubscribe(struct tipc_subscription *sub)
 {
-	struct tipc_net *tn = net_generic(net, tipc_net_id);
-	struct tipc_server *topsrv = tn->topsrv;
-
-	tipc_server_stop(topsrv);
-	kfree(topsrv->saddr);
-	kfree(topsrv);
+	tipc_nametbl_unsubscribe(sub);
+	if (sub->evt.s.timeout != TIPC_WAIT_FOREVER)
+		del_timer_sync(&sub->timer);
+	list_del(&sub->sub_list);
+	tipc_sub_put(sub);
 }
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index f3edca775d9f..8b2d22b18f22 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -1,7 +1,7 @@
 /*
  * net/tipc/subscr.h: Include file for TIPC network topology service
  *
- * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2003-2017, Ericsson AB
  * Copyright (c) 2005-2007, 2012-2013, Wind River Systems
  * All rights reserved.
  *
@@ -37,48 +37,72 @@
 #ifndef _TIPC_SUBSCR_H
 #define _TIPC_SUBSCR_H
 
-#include "server.h"
+#include "topsrv.h"
 
-#define TIPC_MAX_SUBSCRIPTIONS	65535
-#define TIPC_MAX_PUBLICATIONS	65535
+#define TIPC_MAX_SUBSCR         65535
+#define TIPC_MAX_PUBLICATIONS   65535
 
 struct tipc_subscription;
-struct tipc_subscriber;
+struct tipc_conn;
 
 /**
  * struct tipc_subscription - TIPC network topology subscription object
  * @subscriber: pointer to its subscriber
  * @seq: name sequence associated with subscription
- * @net: point to network namespace
  * @timer: timer governing subscription duration (optional)
  * @nameseq_list: adjacent subscriptions in name sequence's subscription list
- * @subscrp_list: adjacent subscriptions in subscriber's subscription list
- * @swap: indicates if subscriber uses opposite endianness in its messages
+ * @sub_list: adjacent subscriptions in subscriber's subscription list
  * @evt: template for events generated by subscription
  */
 struct tipc_subscription {
 	struct kref kref;
-	struct tipc_subscriber *subscriber;
 	struct net *net;
 	struct timer_list timer;
 	struct list_head nameseq_list;
-	struct list_head subscrp_list;
-	int swap;
+	struct list_head sub_list;
 	struct tipc_event evt;
+	int conid;
+	bool inactive;
+	spinlock_t lock; /* serialize up/down and timer events */
 };
 
-int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
-			       u32 found_upper);
-void tipc_subscrp_report_overlap(struct tipc_subscription *sub,
-				 u32 found_lower, u32 found_upper, u32 event,
-				 u32 port_ref, u32 node, u32 scope, int must);
-void tipc_subscrp_convert_seq(struct tipc_name_seq *in, int swap,
-			      struct tipc_name_seq *out);
-u32 tipc_subscrp_convert_seq_type(u32 type, int swap);
+struct tipc_subscription *tipc_sub_subscribe(struct net *net,
+					     struct tipc_subscr *s,
+					     int conid);
+void tipc_sub_unsubscribe(struct tipc_subscription *sub);
+
+int tipc_sub_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
+			   u32 found_upper);
+void tipc_sub_report_overlap(struct tipc_subscription *sub,
+			     u32 found_lower, u32 found_upper,
+			     u32 event, u32 port, u32 node,
+			     u32 scope, int must);
 int tipc_topsrv_start(struct net *net);
 void tipc_topsrv_stop(struct net *net);
 
-void tipc_subscrp_put(struct tipc_subscription *subscription);
-void tipc_subscrp_get(struct tipc_subscription *subscription);
+void tipc_sub_put(struct tipc_subscription *subscription);
+void tipc_sub_get(struct tipc_subscription *subscription);
+
+#define TIPC_FILTER_MASK (TIPC_SUB_PORTS | TIPC_SUB_SERVICE | TIPC_SUB_CANCEL)
+
+/* tipc_sub_read - return field_ of struct sub_ in host endian format
+ */
+#define tipc_sub_read(sub_, field_)					\
+	({								\
+		struct tipc_subscr *sub__ = sub_;			\
+		u32 val__ = (sub__)->field_;				\
+		int swap_ = !((sub__)->filter & TIPC_FILTER_MASK);	\
+		(swap_ ? swab32(val__) : val__);			\
+	})
+
+/* tipc_evt_write - write val_ to field_ of struct evt_ in user endian format
+ */
+#define tipc_evt_write(evt_, field_, val_)				\
+	({								\
+		struct tipc_event *evt__ = evt_;			\
+		u32 val__ = val_;					\
+		int swap_ = !((evt__)->s.filter & (TIPC_FILTER_MASK));	\
+		(evt__)->field_ = swap_ ? swab32(val__) : val__;	\
+	})
 
 #endif
diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c
new file mode 100644
index 000000000000..c8e34ef22c30
--- /dev/null
+++ b/net/tipc/topsrv.c
@@ -0,0 +1,703 @@
+/*
+ * net/tipc/server.c: TIPC server infrastructure
+ *
+ * Copyright (c) 2012-2013, Wind River Systems
+ * Copyright (c) 2017-2018, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "subscr.h"
+#include "topsrv.h"
+#include "core.h"
+#include "socket.h"
+#include "addr.h"
+#include "msg.h"
+#include <net/sock.h>
+#include <linux/module.h>
+
+/* Number of messages to send before rescheduling */
+#define MAX_SEND_MSG_COUNT	25
+#define MAX_RECV_MSG_COUNT	25
+#define CF_CONNECTED		1
+#define CF_SERVER		2
+
+#define TIPC_SERVER_NAME_LEN	32
+
+/**
+ * struct tipc_topsrv - TIPC server structure
+ * @conn_idr: identifier set of connection
+ * @idr_lock: protect the connection identifier set
+ * @idr_in_use: amount of allocated identifier entry
+ * @net: network namspace instance
+ * @rcvbuf_cache: memory cache of server receive buffer
+ * @rcv_wq: receive workqueue
+ * @send_wq: send workqueue
+ * @max_rcvbuf_size: maximum permitted receive message length
+ * @tipc_conn_new: callback will be called when new connection is incoming
+ * @tipc_conn_release: callback will be called before releasing the connection
+ * @tipc_conn_recvmsg: callback will be called when message arrives
+ * @name: server name
+ * @imp: message importance
+ * @type: socket type
+ */
+struct tipc_topsrv {
+	struct idr conn_idr;
+	spinlock_t idr_lock; /* for idr list */
+	int idr_in_use;
+	struct net *net;
+	struct work_struct awork;
+	struct workqueue_struct *rcv_wq;
+	struct workqueue_struct *send_wq;
+	int max_rcvbuf_size;
+	struct socket *listener;
+	char name[TIPC_SERVER_NAME_LEN];
+};
+
+/**
+ * struct tipc_conn - TIPC connection structure
+ * @kref: reference counter to connection object
+ * @conid: connection identifier
+ * @sock: socket handler associated with connection
+ * @flags: indicates connection state
+ * @server: pointer to connected server
+ * @sub_list: lsit to all pertaing subscriptions
+ * @sub_lock: lock protecting the subscription list
+ * @outqueue_lock: control access to the outqueue
+ * @rwork: receive work item
+ * @rx_action: what to do when connection socket is active
+ * @outqueue: pointer to first outbound message in queue
+ * @outqueue_lock: control access to the outqueue
+ * @swork: send work item
+ */
+struct tipc_conn {
+	struct kref kref;
+	int conid;
+	struct socket *sock;
+	unsigned long flags;
+	struct tipc_topsrv *server;
+	struct list_head sub_list;
+	spinlock_t sub_lock; /* for subscription list */
+	struct work_struct rwork;
+	struct list_head outqueue;
+	spinlock_t outqueue_lock; /* for outqueue */
+	struct work_struct swork;
+};
+
+/* An entry waiting to be sent */
+struct outqueue_entry {
+	bool inactive;
+	struct tipc_event evt;
+	struct list_head list;
+};
+
+static void tipc_conn_recv_work(struct work_struct *work);
+static void tipc_conn_send_work(struct work_struct *work);
+static void tipc_topsrv_kern_evt(struct net *net, struct tipc_event *evt);
+static void tipc_conn_delete_sub(struct tipc_conn *con, struct tipc_subscr *s);
+
+static bool connected(struct tipc_conn *con)
+{
+	return con && test_bit(CF_CONNECTED, &con->flags);
+}
+
+static void tipc_conn_kref_release(struct kref *kref)
+{
+	struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
+	struct tipc_topsrv *s = con->server;
+	struct outqueue_entry *e, *safe;
+
+	spin_lock_bh(&s->idr_lock);
+	idr_remove(&s->conn_idr, con->conid);
+	s->idr_in_use--;
+	spin_unlock_bh(&s->idr_lock);
+	if (con->sock)
+		sock_release(con->sock);
+
+	spin_lock_bh(&con->outqueue_lock);
+	list_for_each_entry_safe(e, safe, &con->outqueue, list) {
+		list_del(&e->list);
+		kfree(e);
+	}
+	spin_unlock_bh(&con->outqueue_lock);
+	kfree(con);
+}
+
+static void conn_put(struct tipc_conn *con)
+{
+	kref_put(&con->kref, tipc_conn_kref_release);
+}
+
+static void conn_get(struct tipc_conn *con)
+{
+	kref_get(&con->kref);
+}
+
+static void tipc_conn_close(struct tipc_conn *con)
+{
+	struct sock *sk = con->sock->sk;
+	bool disconnect = false;
+
+	write_lock_bh(&sk->sk_callback_lock);
+	disconnect = test_and_clear_bit(CF_CONNECTED, &con->flags);
+
+	if (disconnect) {
+		sk->sk_user_data = NULL;
+		tipc_conn_delete_sub(con, NULL);
+	}
+	write_unlock_bh(&sk->sk_callback_lock);
+
+	/* Handle concurrent calls from sending and receiving threads */
+	if (!disconnect)
+		return;
+
+	/* Don't flush pending works, -just let them expire */
+	kernel_sock_shutdown(con->sock, SHUT_RDWR);
+
+	conn_put(con);
+}
+
+static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s)
+{
+	struct tipc_conn *con;
+	int ret;
+
+	con = kzalloc(sizeof(*con), GFP_ATOMIC);
+	if (!con)
+		return ERR_PTR(-ENOMEM);
+
+	kref_init(&con->kref);
+	INIT_LIST_HEAD(&con->outqueue);
+	INIT_LIST_HEAD(&con->sub_list);
+	spin_lock_init(&con->outqueue_lock);
+	spin_lock_init(&con->sub_lock);
+	INIT_WORK(&con->swork, tipc_conn_send_work);
+	INIT_WORK(&con->rwork, tipc_conn_recv_work);
+
+	spin_lock_bh(&s->idr_lock);
+	ret = idr_alloc(&s->conn_idr, con, 0, 0, GFP_ATOMIC);
+	if (ret < 0) {
+		kfree(con);
+		spin_unlock_bh(&s->idr_lock);
+		return ERR_PTR(-ENOMEM);
+	}
+	con->conid = ret;
+	s->idr_in_use++;
+	spin_unlock_bh(&s->idr_lock);
+
+	set_bit(CF_CONNECTED, &con->flags);
+	con->server = s;
+
+	return con;
+}
+
+static struct tipc_conn *tipc_conn_lookup(struct tipc_topsrv *s, int conid)
+{
+	struct tipc_conn *con;
+
+	spin_lock_bh(&s->idr_lock);
+	con = idr_find(&s->conn_idr, conid);
+	if (!connected(con) || !kref_get_unless_zero(&con->kref))
+		con = NULL;
+	spin_unlock_bh(&s->idr_lock);
+	return con;
+}
+
+/* tipc_conn_delete_sub - delete a specific or all subscriptions
+ * for a given subscriber
+ */
+static void tipc_conn_delete_sub(struct tipc_conn *con, struct tipc_subscr *s)
+{
+	struct tipc_net *tn = tipc_net(con->server->net);
+	struct list_head *sub_list = &con->sub_list;
+	struct tipc_subscription *sub, *tmp;
+
+	spin_lock_bh(&con->sub_lock);
+	list_for_each_entry_safe(sub, tmp, sub_list, sub_list) {
+		if (!s || !memcmp(s, &sub->evt.s, sizeof(*s))) {
+			tipc_sub_unsubscribe(sub);
+			atomic_dec(&tn->subscription_count);
+		} else if (s) {
+			break;
+		}
+	}
+	spin_unlock_bh(&con->sub_lock);
+}
+
+static void tipc_conn_send_to_sock(struct tipc_conn *con)
+{
+	struct list_head *queue = &con->outqueue;
+	struct tipc_topsrv *srv = con->server;
+	struct outqueue_entry *e;
+	struct tipc_event *evt;
+	struct msghdr msg;
+	struct kvec iov;
+	int count = 0;
+	int ret;
+
+	spin_lock_bh(&con->outqueue_lock);
+
+	while (!list_empty(queue)) {
+		e = list_first_entry(queue, struct outqueue_entry, list);
+		evt = &e->evt;
+		spin_unlock_bh(&con->outqueue_lock);
+
+		if (e->inactive)
+			tipc_conn_delete_sub(con, &evt->s);
+
+		memset(&msg, 0, sizeof(msg));
+		msg.msg_flags = MSG_DONTWAIT;
+		iov.iov_base = evt;
+		iov.iov_len = sizeof(*evt);
+		msg.msg_name = NULL;
+
+		if (con->sock) {
+			ret = kernel_sendmsg(con->sock, &msg, &iov,
+					     1, sizeof(*evt));
+			if (ret == -EWOULDBLOCK || ret == 0) {
+				cond_resched();
+				return;
+			} else if (ret < 0) {
+				return tipc_conn_close(con);
+			}
+		} else {
+			tipc_topsrv_kern_evt(srv->net, evt);
+		}
+
+		/* Don't starve users filling buffers */
+		if (++count >= MAX_SEND_MSG_COUNT) {
+			cond_resched();
+			count = 0;
+		}
+		spin_lock_bh(&con->outqueue_lock);
+		list_del(&e->list);
+		kfree(e);
+	}
+	spin_unlock_bh(&con->outqueue_lock);
+}
+
+static void tipc_conn_send_work(struct work_struct *work)
+{
+	struct tipc_conn *con = container_of(work, struct tipc_conn, swork);
+
+	if (connected(con))
+		tipc_conn_send_to_sock(con);
+
+	conn_put(con);
+}
+
+/* tipc_conn_queue_evt() - interrupt level call from a subscription instance
+ * The queued work is launched into tipc_send_work()->tipc_send_to_sock()
+ */
+void tipc_topsrv_queue_evt(struct net *net, int conid,
+			   u32 event, struct tipc_event *evt)
+{
+	struct tipc_topsrv *srv = tipc_topsrv(net);
+	struct outqueue_entry *e;
+	struct tipc_conn *con;
+
+	con = tipc_conn_lookup(srv, conid);
+	if (!con)
+		return;
+
+	if (!connected(con))
+		goto err;
+
+	e = kmalloc(sizeof(*e), GFP_ATOMIC);
+	if (!e)
+		goto err;
+	e->inactive = (event == TIPC_SUBSCR_TIMEOUT);
+	memcpy(&e->evt, evt, sizeof(*evt));
+	spin_lock_bh(&con->outqueue_lock);
+	list_add_tail(&e->list, &con->outqueue);
+	spin_unlock_bh(&con->outqueue_lock);
+
+	if (queue_work(srv->send_wq, &con->swork))
+		return;
+err:
+	conn_put(con);
+}
+
+/* tipc_conn_write_space - interrupt callback after a sendmsg EAGAIN
+ * Indicates that there now is more space in the send buffer
+ * The queued work is launched into tipc_send_work()->tipc_conn_send_to_sock()
+ */
+static void tipc_conn_write_space(struct sock *sk)
+{
+	struct tipc_conn *con;
+
+	read_lock_bh(&sk->sk_callback_lock);
+	con = sk->sk_user_data;
+	if (connected(con)) {
+		conn_get(con);
+		if (!queue_work(con->server->send_wq, &con->swork))
+			conn_put(con);
+	}
+	read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static int tipc_conn_rcv_sub(struct tipc_topsrv *srv,
+			     struct tipc_conn *con,
+			     struct tipc_subscr *s)
+{
+	struct tipc_net *tn = tipc_net(srv->net);
+	struct tipc_subscription *sub;
+
+	if (tipc_sub_read(s, filter) & TIPC_SUB_CANCEL) {
+		tipc_conn_delete_sub(con, s);
+		return 0;
+	}
+	if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCR) {
+		pr_warn("Subscription rejected, max (%u)\n", TIPC_MAX_SUBSCR);
+		return -1;
+	}
+	sub = tipc_sub_subscribe(srv->net, s, con->conid);
+	if (!sub)
+		return -1;
+	atomic_inc(&tn->subscription_count);
+	spin_lock_bh(&con->sub_lock);
+	list_add(&sub->sub_list, &con->sub_list);
+	spin_unlock_bh(&con->sub_lock);
+	return 0;
+}
+
+static int tipc_conn_rcv_from_sock(struct tipc_conn *con)
+{
+	struct tipc_topsrv *srv = con->server;
+	struct sock *sk = con->sock->sk;
+	struct msghdr msg = {};
+	struct tipc_subscr s;
+	struct kvec iov;
+	int ret;
+
+	iov.iov_base = &s;
+	iov.iov_len = sizeof(s);
+	msg.msg_name = NULL;
+	iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, iov.iov_len);
+	ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
+	if (ret == -EWOULDBLOCK)
+		return -EWOULDBLOCK;
+	if (ret > 0) {
+		read_lock_bh(&sk->sk_callback_lock);
+		ret = tipc_conn_rcv_sub(srv, con, &s);
+		read_unlock_bh(&sk->sk_callback_lock);
+	}
+	if (ret < 0)
+		tipc_conn_close(con);
+
+	return ret;
+}
+
+static void tipc_conn_recv_work(struct work_struct *work)
+{
+	struct tipc_conn *con = container_of(work, struct tipc_conn, rwork);
+	int count = 0;
+
+	while (connected(con)) {
+		if (tipc_conn_rcv_from_sock(con))
+			break;
+
+		/* Don't flood Rx machine */
+		if (++count >= MAX_RECV_MSG_COUNT) {
+			cond_resched();
+			count = 0;
+		}
+	}
+	conn_put(con);
+}
+
+/* tipc_conn_data_ready - interrupt callback indicating the socket has data
+ * The queued work is launched into tipc_recv_work()->tipc_conn_rcv_from_sock()
+ */
+static void tipc_conn_data_ready(struct sock *sk)
+{
+	struct tipc_conn *con;
+
+	read_lock_bh(&sk->sk_callback_lock);
+	con = sk->sk_user_data;
+	if (connected(con)) {
+		conn_get(con);
+		if (!queue_work(con->server->rcv_wq, &con->rwork))
+			conn_put(con);
+	}
+	read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void tipc_topsrv_accept(struct work_struct *work)
+{
+	struct tipc_topsrv *srv = container_of(work, struct tipc_topsrv, awork);
+	struct socket *lsock = srv->listener;
+	struct socket *newsock;
+	struct tipc_conn *con;
+	struct sock *newsk;
+	int ret;
+
+	while (1) {
+		ret = kernel_accept(lsock, &newsock, O_NONBLOCK);
+		if (ret < 0)
+			return;
+		con = tipc_conn_alloc(srv);
+		if (IS_ERR(con)) {
+			ret = PTR_ERR(con);
+			sock_release(newsock);
+			return;
+		}
+		/* Register callbacks */
+		newsk = newsock->sk;
+		write_lock_bh(&newsk->sk_callback_lock);
+		newsk->sk_data_ready = tipc_conn_data_ready;
+		newsk->sk_write_space = tipc_conn_write_space;
+		newsk->sk_user_data = con;
+		con->sock = newsock;
+		write_unlock_bh(&newsk->sk_callback_lock);
+
+		/* Wake up receive process in case of 'SYN+' message */
+		newsk->sk_data_ready(newsk);
+	}
+}
+
+/* tipc_toprsv_listener_data_ready - interrupt callback with connection request
+ * The queued job is launched into tipc_topsrv_accept()
+ */
+static void tipc_topsrv_listener_data_ready(struct sock *sk)
+{
+	struct tipc_topsrv *srv;
+
+	read_lock_bh(&sk->sk_callback_lock);
+	srv = sk->sk_user_data;
+	if (srv->listener)
+		queue_work(srv->rcv_wq, &srv->awork);
+	read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static int tipc_topsrv_create_listener(struct tipc_topsrv *srv)
+{
+	int imp = TIPC_CRITICAL_IMPORTANCE;
+	struct socket *lsock = NULL;
+	struct sockaddr_tipc saddr;
+	struct sock *sk;
+	int rc;
+
+	rc = sock_create_kern(srv->net, AF_TIPC, SOCK_SEQPACKET, 0, &lsock);
+	if (rc < 0)
+		return rc;
+
+	srv->listener = lsock;
+	sk = lsock->sk;
+	write_lock_bh(&sk->sk_callback_lock);
+	sk->sk_data_ready = tipc_topsrv_listener_data_ready;
+	sk->sk_user_data = srv;
+	write_unlock_bh(&sk->sk_callback_lock);
+
+	rc = kernel_setsockopt(lsock, SOL_TIPC, TIPC_IMPORTANCE,
+			       (char *)&imp, sizeof(imp));
+	if (rc < 0)
+		goto err;
+
+	saddr.family	                = AF_TIPC;
+	saddr.addrtype		        = TIPC_ADDR_NAMESEQ;
+	saddr.addr.nameseq.type	        = TIPC_TOP_SRV;
+	saddr.addr.nameseq.lower	= TIPC_TOP_SRV;
+	saddr.addr.nameseq.upper	= TIPC_TOP_SRV;
+	saddr.scope			= TIPC_NODE_SCOPE;
+
+	rc = kernel_bind(lsock, (struct sockaddr *)&saddr, sizeof(saddr));
+	if (rc < 0)
+		goto err;
+	rc = kernel_listen(lsock, 0);
+	if (rc < 0)
+		goto err;
+
+	/* As server's listening socket owner and creator is the same module,
+	 * we have to decrease TIPC module reference count to guarantee that
+	 * it remains zero after the server socket is created, otherwise,
+	 * executing "rmmod" command is unable to make TIPC module deleted
+	 * after TIPC module is inserted successfully.
+	 *
+	 * However, the reference count is ever increased twice in
+	 * sock_create_kern(): one is to increase the reference count of owner
+	 * of TIPC socket's proto_ops struct; another is to increment the
+	 * reference count of owner of TIPC proto struct. Therefore, we must
+	 * decrement the module reference count twice to ensure that it keeps
+	 * zero after server's listening socket is created. Of course, we
+	 * must bump the module reference count twice as well before the socket
+	 * is closed.
+	 */
+	module_put(lsock->ops->owner);
+	module_put(sk->sk_prot_creator->owner);
+
+	return 0;
+err:
+	sock_release(lsock);
+	return -EINVAL;
+}
+
+bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
+			     u32 upper, u32 filter, int *conid)
+{
+	struct tipc_subscr sub;
+	struct tipc_conn *con;
+	int rc;
+
+	sub.seq.type = type;
+	sub.seq.lower = lower;
+	sub.seq.upper = upper;
+	sub.timeout = TIPC_WAIT_FOREVER;
+	sub.filter = filter;
+	*(u32 *)&sub.usr_handle = port;
+
+	con = tipc_conn_alloc(tipc_topsrv(net));
+	if (IS_ERR(con))
+		return false;
+
+	*conid = con->conid;
+	con->sock = NULL;
+	rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub);
+	if (rc >= 0)
+		return true;
+	conn_put(con);
+	return false;
+}
+
+void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
+{
+	struct tipc_conn *con;
+
+	con = tipc_conn_lookup(tipc_topsrv(net), conid);
+	if (!con)
+		return;
+
+	test_and_clear_bit(CF_CONNECTED, &con->flags);
+	tipc_conn_delete_sub(con, NULL);
+	conn_put(con);
+	conn_put(con);
+}
+
+static void tipc_topsrv_kern_evt(struct net *net, struct tipc_event *evt)
+{
+	u32 port = *(u32 *)&evt->s.usr_handle;
+	u32 self = tipc_own_addr(net);
+	struct sk_buff_head evtq;
+	struct sk_buff *skb;
+
+	skb = tipc_msg_create(TOP_SRV, 0, INT_H_SIZE, sizeof(*evt),
+			      self, self, port, port, 0);
+	if (!skb)
+		return;
+	msg_set_dest_droppable(buf_msg(skb), true);
+	memcpy(msg_data(buf_msg(skb)), evt, sizeof(*evt));
+	skb_queue_head_init(&evtq);
+	__skb_queue_tail(&evtq, skb);
+	tipc_sk_rcv(net, &evtq);
+}
+
+static int tipc_topsrv_work_start(struct tipc_topsrv *s)
+{
+	s->rcv_wq = alloc_ordered_workqueue("tipc_rcv", 0);
+	if (!s->rcv_wq) {
+		pr_err("can't start tipc receive workqueue\n");
+		return -ENOMEM;
+	}
+
+	s->send_wq = alloc_ordered_workqueue("tipc_send", 0);
+	if (!s->send_wq) {
+		pr_err("can't start tipc send workqueue\n");
+		destroy_workqueue(s->rcv_wq);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void tipc_topsrv_work_stop(struct tipc_topsrv *s)
+{
+	destroy_workqueue(s->rcv_wq);
+	destroy_workqueue(s->send_wq);
+}
+
+int tipc_topsrv_start(struct net *net)
+{
+	struct tipc_net *tn = tipc_net(net);
+	const char name[] = "topology_server";
+	struct tipc_topsrv *srv;
+	int ret;
+
+	srv = kzalloc(sizeof(*srv), GFP_ATOMIC);
+	if (!srv)
+		return -ENOMEM;
+
+	srv->net = net;
+	srv->max_rcvbuf_size = sizeof(struct tipc_subscr);
+	INIT_WORK(&srv->awork, tipc_topsrv_accept);
+
+	strncpy(srv->name, name, strlen(name) + 1);
+	tn->topsrv = srv;
+	atomic_set(&tn->subscription_count, 0);
+
+	spin_lock_init(&srv->idr_lock);
+	idr_init(&srv->conn_idr);
+	srv->idr_in_use = 0;
+
+	ret = tipc_topsrv_work_start(srv);
+	if (ret < 0)
+		return ret;
+
+	ret = tipc_topsrv_create_listener(srv);
+	if (ret < 0)
+		tipc_topsrv_work_stop(srv);
+
+	return ret;
+}
+
+void tipc_topsrv_stop(struct net *net)
+{
+	struct tipc_topsrv *srv = tipc_topsrv(net);
+	struct socket *lsock = srv->listener;
+	struct tipc_conn *con;
+	int id;
+
+	spin_lock_bh(&srv->idr_lock);
+	for (id = 0; srv->idr_in_use; id++) {
+		con = idr_find(&srv->conn_idr, id);
+		if (con) {
+			spin_unlock_bh(&srv->idr_lock);
+			tipc_conn_close(con);
+			spin_lock_bh(&srv->idr_lock);
+		}
+	}
+	__module_get(lsock->ops->owner);
+	__module_get(lsock->sk->sk_prot_creator->owner);
+	srv->listener = NULL;
+	spin_unlock_bh(&srv->idr_lock);
+	sock_release(lsock);
+	tipc_topsrv_work_stop(srv);
+	idr_destroy(&srv->conn_idr);
+	kfree(srv);
+}
diff --git a/net/tipc/topsrv.h b/net/tipc/topsrv.h
new file mode 100644
index 000000000000..c7ea71293748
--- /dev/null
+++ b/net/tipc/topsrv.h
@@ -0,0 +1,54 @@
+/*
+ * net/tipc/server.h: Include file for TIPC server code
+ *
+ * Copyright (c) 2012-2013, Wind River Systems
+ * Copyright (c) 2017, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_SERVER_H
+#define _TIPC_SERVER_H
+
+#include "core.h"
+
+#define TIPC_SERVER_NAME_LEN	32
+#define TIPC_SUB_CLUSTER_SCOPE  0x20
+#define TIPC_SUB_NODE_SCOPE     0x40
+#define TIPC_SUB_NO_STATUS      0x80
+
+void tipc_topsrv_queue_evt(struct net *net, int conid,
+			   u32 event, struct tipc_event *evt);
+
+bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
+			     u32 upper, u32 filter, int *conid);
+void tipc_topsrv_kern_unsubscr(struct net *net, int conid);
+
+#endif
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index b0d5fcea47e7..e9b4b53ab53e 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -308,8 +308,11 @@ static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval,
 			goto out;
 		}
 		lock_sock(sk);
-		memcpy(crypto_info_aes_gcm_128->iv, ctx->iv,
+		memcpy(crypto_info_aes_gcm_128->iv,
+		       ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE,
 		       TLS_CIPHER_AES_GCM_128_IV_SIZE);
+		memcpy(crypto_info_aes_gcm_128->rec_seq, ctx->rec_seq,
+		       TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
 		release_sock(sk);
 		if (copy_to_user(optval,
 				 crypto_info_aes_gcm_128,
@@ -375,7 +378,7 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
 	rc = copy_from_user(crypto_info, optval, sizeof(*crypto_info));
 	if (rc) {
 		rc = -EFAULT;
-		goto out;
+		goto err_crypto_info;
 	}
 
 	/* check version */
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d545e1d0dea2..bc2970a8e7f3 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -637,7 +637,7 @@ static int unix_stream_connect(struct socket *, struct sockaddr *,
 			       int addr_len, int flags);
 static int unix_socketpair(struct socket *, struct socket *);
 static int unix_accept(struct socket *, struct socket *, int, bool);
-static int unix_getname(struct socket *, struct sockaddr *, int *, int);
+static int unix_getname(struct socket *, struct sockaddr *, int);
 static __poll_t unix_poll(struct file *, struct socket *, poll_table *);
 static __poll_t unix_dgram_poll(struct file *, struct socket *,
 				    poll_table *);
@@ -1453,7 +1453,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 
-static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
 {
 	struct sock *sk = sock->sk;
 	struct unix_sock *u;
@@ -1476,12 +1476,12 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
 	if (!u->addr) {
 		sunaddr->sun_family = AF_UNIX;
 		sunaddr->sun_path[0] = 0;
-		*uaddr_len = sizeof(short);
+		err = sizeof(short);
 	} else {
 		struct unix_address *addr = u->addr;
 
-		*uaddr_len = addr->len;
-		memcpy(sunaddr, addr->name, *uaddr_len);
+		err = addr->len;
+		memcpy(sunaddr, addr->name, addr->len);
 	}
 	unix_state_unlock(sk);
 	sock_put(sk);
@@ -1825,7 +1825,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 }
 
 /* We use paged skbs for stream sockets, and limit occupancy to 32768
- * bytes, and a minimun of a full page.
+ * bytes, and a minimum of a full page.
  */
 #define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768))
 
@@ -2913,6 +2913,7 @@ static void __net_exit unix_net_exit(struct net *net)
 static struct pernet_operations unix_net_ops = {
 	.init = unix_net_init,
 	.exit = unix_net_exit,
+	.async = true,
 };
 
 static int __init af_unix_init(void)
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index e0fc84daed94..aac9b8f6552e 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -759,7 +759,7 @@ vsock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 }
 
 static int vsock_getname(struct socket *sock,
-			 struct sockaddr *addr, int *addr_len, int peer)
+			 struct sockaddr *addr, int peer)
 {
 	int err;
 	struct sock *sk;
@@ -794,7 +794,7 @@ static int vsock_getname(struct socket *sock,
 	 */
 	BUILD_BUG_ON(sizeof(*vm_addr) > 128);
 	memcpy(addr, vm_addr, sizeof(*vm_addr));
-	*addr_len = sizeof(*vm_addr);
+	err = sizeof(*vm_addr);
 
 out:
 	release_sock(sk);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a6f3cac8c640..670aa229168a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1340,6 +1340,7 @@ static void __net_exit cfg80211_pernet_exit(struct net *net)
 
 static struct pernet_operations cfg80211_pernet_ops = {
 	.exit = cfg80211_pernet_exit,
+	.async = true,
 };
 
 static int __init cfg80211_init(void)
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 51aa55618ef7..b12da6ef3c12 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -170,9 +170,28 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 		enum nl80211_bss_scan_width scan_width;
 		struct ieee80211_supported_band *sband =
 				rdev->wiphy.bands[setup->chandef.chan->band];
-		scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
-		setup->basic_rates = ieee80211_mandatory_rates(sband,
-							       scan_width);
+
+		if (setup->chandef.chan->band == NL80211_BAND_2GHZ) {
+			int i;
+
+			/*
+			 * Older versions selected the mandatory rates for
+			 * 2.4 GHz as well, but were broken in that only
+			 * 1 Mbps was regarded as a mandatory rate. Keep
+			 * using just 1 Mbps as the default basic rate for
+			 * mesh to be interoperable with older versions.
+			 */
+			for (i = 0; i < sband->n_bitrates; i++) {
+				if (sband->bitrates[i].bitrate == 10) {
+					setup->basic_rates = BIT(i);
+					break;
+				}
+			}
+		} else {
+			scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
+			setup->basic_rates = ieee80211_mandatory_rates(sband,
+								       scan_width);
+		}
 	}
 
 	err = cfg80211_chandef_dfs_required(&rdev->wiphy,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9c0dcc8324b0..a910150f8169 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -421,6 +421,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 	[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
 	[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
 	[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
+	[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -3923,9 +3924,10 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
 			return false;
 		return true;
 	case NL80211_CMD_CONNECT:
-		/* SAE not supported yet */
-		if (auth_type == NL80211_AUTHTYPE_SAE)
+		if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
+		    auth_type == NL80211_AUTHTYPE_SAE)
 			return false;
+
 		/* FILS with SK PFS or PK not supported yet */
 		if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
 		    auth_type == NL80211_AUTHTYPE_FILS_PK)
@@ -4487,6 +4489,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
 	PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
 	PUT_SINFO_U64(BEACON_RX, rx_beacon);
 	PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
+	PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
 
 #undef PUT_SINFO
 #undef PUT_SINFO_U64
@@ -5848,7 +5851,6 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
 	return genlmsg_reply(msg, info);
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
  out:
 	nlmsg_free(msg);
 	return -ENOBUFS;
@@ -6329,7 +6331,6 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
 nla_put_failure_rcu:
 	rcu_read_unlock();
 nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 put_failure:
 	nlmsg_free(msg);
 	return -EMSGSIZE;
@@ -6718,8 +6719,17 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
 
 	*flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
 
-	if ((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-	    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN))
+	if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+	     !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
+	    ((*flags & NL80211_SCAN_FLAG_LOW_SPAN) &&
+	     !wiphy_ext_feature_isset(wiphy,
+				      NL80211_EXT_FEATURE_LOW_SPAN_SCAN)) ||
+	    ((*flags & NL80211_SCAN_FLAG_LOW_POWER) &&
+	     !wiphy_ext_feature_isset(wiphy,
+				      NL80211_EXT_FEATURE_LOW_POWER_SCAN)) ||
+	    ((*flags & NL80211_SCAN_FLAG_HIGH_ACCURACY) &&
+	     !wiphy_ext_feature_isset(wiphy,
+				      NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN)))
 		return -EOPNOTSUPP;
 
 	if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
@@ -9155,6 +9165,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 	}
 
+	if (nla_get_flag(info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])) {
+		if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+			GENL_SET_ERR_MSG(info,
+					 "external auth requires connection ownership");
+			return -EINVAL;
+		}
+		connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
+	}
+
 	wdev_lock(dev->ieee80211_ptr);
 
 	err = cfg80211_connect(rdev, dev, &connect, connkeys,
@@ -12463,6 +12482,41 @@ static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
 	return ret;
 }
 
+static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct cfg80211_external_auth_params params;
+
+	if (!rdev->ops->external_auth)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_SSID])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_BSSID])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_STATUS_CODE])
+		return -EINVAL;
+
+	memset(&params, 0, sizeof(params));
+
+	params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+	if (params.ssid.ssid_len == 0 ||
+	    params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN)
+		return -EINVAL;
+	memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]),
+	       params.ssid.ssid_len);
+
+	memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]),
+	       ETH_ALEN);
+
+	params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+
+	return rdev_external_auth(rdev, dev, &params);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -13358,6 +13412,14 @@ static const struct genl_ops nl80211_ops[] = {
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_EXTERNAL_AUTH,
+		.doit = nl80211_external_auth,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 
 };
 
@@ -13672,7 +13734,6 @@ void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
 	return;
 
 nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -13720,7 +13781,6 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -13808,7 +13868,6 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -13884,7 +13943,6 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -13924,7 +13982,6 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -13954,7 +14011,6 @@ void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -13991,7 +14047,6 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14024,7 +14079,6 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14065,7 +14119,6 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
@@ -14104,7 +14157,6 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14159,7 +14211,6 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
 	return;
 
 nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14205,7 +14256,6 @@ static void nl80211_send_remain_on_chan_event(
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14319,7 +14369,6 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_conn_failed);
@@ -14356,7 +14405,6 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
 	return true;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 	return true;
 }
@@ -14440,7 +14488,6 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
 	return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -14484,7 +14531,6 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
@@ -14693,7 +14739,6 @@ static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14751,7 +14796,6 @@ nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14804,7 +14848,6 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
@@ -14886,12 +14929,67 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 
+void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
+				       struct sta_opmode_info *sta_opmode,
+				       gfp_t gfp)
+{
+	struct sk_buff *msg;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+	void *hdr;
+
+	if (WARN_ON(!mac))
+		return;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STA_OPMODE_CHANGED);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
+		goto nla_put_failure;
+
+	if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
+		goto nla_put_failure;
+
+	if ((sta_opmode->changed & STA_OPMODE_SMPS_MODE_CHANGED) &&
+	    nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, sta_opmode->smps_mode))
+		goto nla_put_failure;
+
+	if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) &&
+	    nla_put_u8(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
+		goto nla_put_failure;
+
+	if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) &&
+	    nla_put_u8(msg, NL80211_ATTR_NSS, sta_opmode->rx_nss))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+				NL80211_MCGRP_MLME, gfp);
+
+	return;
+
+nla_put_failure:
+	nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_sta_opmode_change_notify);
+
 void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
-			   u64 cookie, bool acked, gfp_t gfp)
+			   u64 cookie, bool acked, s32 ack_signal,
+			   bool is_valid_ack_signal, gfp_t gfp)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -14916,7 +15014,9 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
 	    nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie,
 			      NL80211_ATTR_PAD) ||
-	    (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
+	    (acked && nla_put_flag(msg, NL80211_ATTR_ACK)) ||
+	    (is_valid_ack_signal && nla_put_s32(msg, NL80211_ATTR_ACK_SIGNAL,
+						ack_signal)))
 		goto nla_put_failure;
 
 	genlmsg_end(msg, hdr);
@@ -14926,7 +15026,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_probe_status);
@@ -14971,8 +15070,6 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
 
  nla_put_failure:
 	spin_unlock_bh(&rdev->beacon_registrations_lock);
-	if (hdr)
-		genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_report_obss_beacon);
@@ -15188,7 +15285,6 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
 	return;
 
  nla_put_failure:
-	genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_tdls_oper_request);
@@ -15333,8 +15429,6 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
 	return;
 
  nla_put_failure:
-	if (hdr)
-		genlmsg_cancel(msg, hdr);
 	nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
@@ -15369,6 +15463,47 @@ void nl80211_send_ap_stopped(struct wireless_dev *wdev)
 	nlmsg_free(msg);
 }
 
+int cfg80211_external_auth_request(struct net_device *dev,
+				   struct cfg80211_external_auth_params *params,
+				   gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+	struct sk_buff *msg;
+	void *hdr;
+
+	if (!wdev->conn_owner_nlportid)
+		return -EINVAL;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH);
+	if (!hdr)
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+	    nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) ||
+	    nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+			params->action) ||
+	    nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) ||
+	    nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len,
+		    params->ssid.ssid))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+	genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
+			wdev->conn_owner_nlportid);
+	return 0;
+
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+EXPORT_SYMBOL(cfg80211_external_auth_request);
+
 /* initialisation/exit functions */
 
 int __init nl80211_init(void)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 0c06240d25af..84f23ae015fc 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1190,4 +1190,19 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_int(&rdev->wiphy, ret);
 	return ret;
 }
+
+static inline int
+rdev_external_auth(struct cfg80211_registered_device *rdev,
+		   struct net_device *dev,
+		   struct cfg80211_external_auth_params *params)
+{
+	int ret = -EOPNOTSUPP;
+
+	trace_rdev_external_auth(&rdev->wiphy, dev, params);
+	if (rdev->ops->external_auth)
+		ret = rdev->ops->external_auth(&rdev->wiphy, dev, params);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index fdb3646274a5..701cfd7acc1b 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1032,6 +1032,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 	wdev->current_bss = NULL;
 	wdev->ssid_len = 0;
 	wdev->conn_owner_nlportid = 0;
+	kzfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
 
 	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index bcfedd39e7a3..5152938b358d 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2319,6 +2319,29 @@ TRACE_EVENT(rdev_del_pmk,
 		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(aa))
 );
 
+TRACE_EVENT(rdev_external_auth,
+	    TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		     struct cfg80211_external_auth_params *params),
+	    TP_ARGS(wiphy, netdev, params),
+	    TP_STRUCT__entry(WIPHY_ENTRY
+			     NETDEV_ENTRY
+			     MAC_ENTRY(bssid)
+			     __array(u8, ssid, IEEE80211_MAX_SSID_LEN + 1)
+			     __field(u16, status)
+	    ),
+	    TP_fast_assign(WIPHY_ASSIGN;
+			   NETDEV_ASSIGN;
+			   MAC_ASSIGN(bssid, params->bssid);
+			   memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
+			   memcpy(__entry->ssid, params->ssid.ssid,
+				  params->ssid.ssid_len);
+			   __entry->status = params->status;
+	    ),
+	    TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+		      ", ssid: %s, status: %u", WIPHY_PR_ARG, NETDEV_PR_ARG,
+		      __entry->bssid, __entry->ssid, __entry->status)
+);
+
 /*************************************************************
  *	     cfg80211 exported functions traces		     *
  *************************************************************/
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index 9efbfc753347..bc7064486b15 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -390,6 +390,7 @@ static void __net_exit wext_pernet_exit(struct net *net)
 static struct pernet_operations wext_pernet_ops = {
 	.init = wext_pernet_init,
 	.exit = wext_pernet_exit,
+	.async = true,
 };
 
 static int __init wireless_nlevent_init(void)
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 562cc11131f6..d49aa79b7997 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -896,7 +896,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags,
 }
 
 static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
-		       int *uaddr_len, int peer)
+		       int peer)
 {
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
 	struct sock *sk = sock->sk;
@@ -913,7 +913,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
 		sx25->sx25_addr = x25->source_addr;
 
 	sx25->sx25_family = AF_X25;
-	*uaddr_len = sizeof(*sx25);
+	rc = sizeof(*sx25);
 
 out:
 	return rc;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 7a23078132cf..7612bcf4d92c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1891,7 +1891,7 @@ static void xfrm_policy_queue_process(struct timer_list *t)
 	spin_unlock(&pq->hold_queue.lock);
 
 	dst_hold(xfrm_dst_path(dst));
-	dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, 0);
+	dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, XFRM_LOOKUP_QUEUE);
 	if (IS_ERR(dst))
 		goto purge_queue;
 
@@ -2982,6 +2982,7 @@ static void __net_exit xfrm_net_exit(struct net *net)
 static struct pernet_operations __net_initdata xfrm_net_ops = {
 	.init = xfrm_net_init,
 	.exit = xfrm_net_exit,
+	.async = true,
 };
 
 void __init xfrm_init(void)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 54e21f19d722..f9d2f2233f09 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2056,6 +2056,11 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
 	struct xfrm_mgr *km;
 	struct xfrm_policy *pol = NULL;
 
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall())
+		return -EOPNOTSUPP;
+#endif
+
 	if (!optval && !optlen) {
 		xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
 		xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 7f52b8eb177d..080035f056d9 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -121,22 +121,17 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
 	struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
 	struct xfrm_replay_state_esn *rs;
 
-	if (p->flags & XFRM_STATE_ESN) {
-		if (!rt)
-			return -EINVAL;
+	if (!rt)
+		return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
 
-		rs = nla_data(rt);
+	rs = nla_data(rt);
 
-		if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
-			return -EINVAL;
-
-		if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
-		    nla_len(rt) != sizeof(*rs))
-			return -EINVAL;
-	}
+	if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
+		return -EINVAL;
 
-	if (!rt)
-		return 0;
+	if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
+	    nla_len(rt) != sizeof(*rs))
+		return -EINVAL;
 
 	/* As only ESP and AH support ESN feature. */
 	if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
diff --git a/samples/Kconfig b/samples/Kconfig
index c332a3b9de05..4cb8af2f810f 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -62,6 +62,15 @@ config SAMPLE_KDB
 	  Build an example of how to dynamically add the hello
 	  command to the kdb shell.
 
+config SAMPLE_QMI_CLIENT
+	tristate "Build qmi client sample -- loadable modules only"
+	depends on m
+	depends on ARCH_QCOM
+	select QCOM_QMI_HELPERS
+	help
+	  Build an QMI client sample driver, which demonstrates how to
+	  communicate with a remote QRTR service, using QMI encoded messages.
+
 config SAMPLE_RPMSG_CLIENT
 	tristate "Build rpmsg client sample -- loadable modules only"
 	depends on RPMSG && m
diff --git a/samples/Makefile b/samples/Makefile
index db54e766ddb1..a30833a2a19e 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -3,4 +3,4 @@
 obj-$(CONFIG_SAMPLES)	+= kobject/ kprobes/ trace_events/ livepatch/ \
 			   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
 			   configfs/ connector/ v4l/ trace_printk/ blackfin/ \
-			   vfio-mdev/ statx/
+			   vfio-mdev/ statx/ qmi/
diff --git a/samples/bpf/xdp_redirect_user.c b/samples/bpf/xdp_redirect_user.c
index d54e91eb6cbf..b701b5c21342 100644
--- a/samples/bpf/xdp_redirect_user.c
+++ b/samples/bpf/xdp_redirect_user.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <libgen.h>
+#include <sys/resource.h>
 
 #include "bpf_load.h"
 #include "bpf_util.h"
@@ -75,6 +76,7 @@ static void usage(const char *prog)
 
 int main(int argc, char **argv)
 {
+	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
 	const char *optstr = "SN";
 	char filename[256];
 	int ret, opt, key = 0;
@@ -98,6 +100,11 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
+	if (setrlimit(RLIMIT_MEMLOCK, &r)) {
+		perror("setrlimit(RLIMIT_MEMLOCK)");
+		return 1;
+	}
+
 	ifindex_in = strtoul(argv[optind], NULL, 0);
 	ifindex_out = strtoul(argv[optind + 1], NULL, 0);
 	printf("input: %d output: %d\n", ifindex_in, ifindex_out);
diff --git a/samples/qmi/Makefile b/samples/qmi/Makefile
new file mode 100644
index 000000000000..2b111d2769df
--- /dev/null
+++ b/samples/qmi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SAMPLE_QMI_CLIENT) += qmi_sample_client.o
diff --git a/samples/qmi/qmi_sample_client.c b/samples/qmi/qmi_sample_client.c
new file mode 100644
index 000000000000..c9e7276c3d83
--- /dev/null
+++ b/samples/qmi/qmi_sample_client.c
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sample in-kernel QMI client driver
+ *
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2017 Linaro Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/qrtr.h>
+#include <linux/net.h>
+#include <linux/completion.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <net/sock.h>
+#include <linux/soc/qcom/qmi.h>
+
+#define PING_REQ1_TLV_TYPE		0x1
+#define PING_RESP1_TLV_TYPE		0x2
+#define PING_OPT1_TLV_TYPE		0x10
+#define PING_OPT2_TLV_TYPE		0x11
+
+#define DATA_REQ1_TLV_TYPE		0x1
+#define DATA_RESP1_TLV_TYPE		0x2
+#define DATA_OPT1_TLV_TYPE		0x10
+#define DATA_OPT2_TLV_TYPE		0x11
+
+#define TEST_MED_DATA_SIZE_V01		8192
+#define TEST_MAX_NAME_SIZE_V01		255
+
+#define TEST_PING_REQ_MSG_ID_V01	0x20
+#define TEST_DATA_REQ_MSG_ID_V01	0x21
+
+#define TEST_PING_REQ_MAX_MSG_LEN_V01	266
+#define TEST_DATA_REQ_MAX_MSG_LEN_V01	8456
+
+struct test_name_type_v01 {
+	u32 name_len;
+	char name[TEST_MAX_NAME_SIZE_V01];
+};
+
+static struct qmi_elem_info test_name_type_v01_ei[] = {
+	{
+		.data_type	= QMI_DATA_LEN,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= QMI_COMMON_TLV_TYPE,
+		.offset		= offsetof(struct test_name_type_v01,
+					   name_len),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= TEST_MAX_NAME_SIZE_V01,
+		.elem_size	= sizeof(char),
+		.array_type	= VAR_LEN_ARRAY,
+		.tlv_type	= QMI_COMMON_TLV_TYPE,
+		.offset		= offsetof(struct test_name_type_v01,
+					   name),
+	},
+	{}
+};
+
+struct test_ping_req_msg_v01 {
+	char ping[4];
+
+	u8 client_name_valid;
+	struct test_name_type_v01 client_name;
+};
+
+static struct qmi_elem_info test_ping_req_msg_v01_ei[] = {
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 4,
+		.elem_size	= sizeof(char),
+		.array_type	= STATIC_ARRAY,
+		.tlv_type	= PING_REQ1_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_req_msg_v01,
+					   ping),
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= PING_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_req_msg_v01,
+					   client_name_valid),
+	},
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct test_name_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= PING_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_req_msg_v01,
+					   client_name),
+		.ei_array	= test_name_type_v01_ei,
+	},
+	{}
+};
+
+struct test_ping_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+
+	u8 pong_valid;
+	char pong[4];
+
+	u8 service_name_valid;
+	struct test_name_type_v01 service_name;
+};
+
+static struct qmi_elem_info test_ping_resp_msg_v01_ei[] = {
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct qmi_response_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= PING_RESP1_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_resp_msg_v01,
+					   resp),
+		.ei_array	= qmi_response_type_v01_ei,
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= PING_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_resp_msg_v01,
+					   pong_valid),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 4,
+		.elem_size	= sizeof(char),
+		.array_type	= STATIC_ARRAY,
+		.tlv_type	= PING_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_resp_msg_v01,
+					   pong),
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= PING_OPT2_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_resp_msg_v01,
+					   service_name_valid),
+	},
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct test_name_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= PING_OPT2_TLV_TYPE,
+		.offset		= offsetof(struct test_ping_resp_msg_v01,
+					   service_name),
+		.ei_array	= test_name_type_v01_ei,
+	},
+	{}
+};
+
+struct test_data_req_msg_v01 {
+	u32 data_len;
+	u8 data[TEST_MED_DATA_SIZE_V01];
+
+	u8 client_name_valid;
+	struct test_name_type_v01 client_name;
+};
+
+static struct qmi_elem_info test_data_req_msg_v01_ei[] = {
+	{
+		.data_type	= QMI_DATA_LEN,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u32),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_REQ1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= TEST_MED_DATA_SIZE_V01,
+		.elem_size	= sizeof(u8),
+		.array_type	= VAR_LEN_ARRAY,
+		.tlv_type	= DATA_REQ1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_req_msg_v01,
+					   client_name_valid),
+	},
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct test_name_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_req_msg_v01,
+					   client_name),
+		.ei_array	= test_name_type_v01_ei,
+	},
+	{}
+};
+
+struct test_data_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+
+	u8 data_valid;
+	u32 data_len;
+	u8 data[TEST_MED_DATA_SIZE_V01];
+
+	u8 service_name_valid;
+	struct test_name_type_v01 service_name;
+};
+
+static struct qmi_elem_info test_data_resp_msg_v01_ei[] = {
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct qmi_response_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_RESP1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_resp_msg_v01,
+					   resp),
+		.ei_array	= qmi_response_type_v01_ei,
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_resp_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type	= QMI_DATA_LEN,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u32),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_resp_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= TEST_MED_DATA_SIZE_V01,
+		.elem_size	= sizeof(u8),
+		.array_type	= VAR_LEN_ARRAY,
+		.tlv_type	= DATA_OPT1_TLV_TYPE,
+		.offset		= offsetof(struct test_data_resp_msg_v01,
+					   data),
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(u8),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_OPT2_TLV_TYPE,
+		.offset		= offsetof(struct test_data_resp_msg_v01,
+					   service_name_valid),
+	},
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= 1,
+		.elem_size	= sizeof(struct test_name_type_v01),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= DATA_OPT2_TLV_TYPE,
+		.offset		= offsetof(struct test_data_resp_msg_v01,
+					   service_name),
+		.ei_array	= test_name_type_v01_ei,
+	},
+	{}
+};
+
+/*
+ * ping_write() - ping_pong debugfs file write handler
+ * @file:	debugfs file context
+ * @user_buf:	reference to the user data (ignored)
+ * @count:	number of bytes in @user_buf
+ * @ppos:	offset in @file to write
+ *
+ * This function allows user space to send out a ping_pong QMI encoded message
+ * to the associated remote test service and will return with the result of the
+ * transaction. It serves as an example of how to provide a custom response
+ * handler.
+ *
+ * Return: @count, or negative errno on failure.
+ */
+static ssize_t ping_write(struct file *file, const char __user *user_buf,
+			  size_t count, loff_t *ppos)
+{
+	struct qmi_handle *qmi = file->private_data;
+	struct test_ping_req_msg_v01 req = {};
+	struct qmi_txn txn;
+	int ret;
+
+	memcpy(req.ping, "ping", sizeof(req.ping));
+
+	ret = qmi_txn_init(qmi, &txn, NULL, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = qmi_send_request(qmi, NULL, &txn,
+			       TEST_PING_REQ_MSG_ID_V01,
+			       TEST_PING_REQ_MAX_MSG_LEN_V01,
+			       test_ping_req_msg_v01_ei, &req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		return ret;
+	}
+
+	ret = qmi_txn_wait(&txn, 5 * HZ);
+	if (ret < 0)
+		count = ret;
+
+	return count;
+}
+
+static const struct file_operations ping_fops = {
+	.open = simple_open,
+	.write = ping_write,
+};
+
+static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+			 struct qmi_txn *txn, const void *data)
+{
+	const struct test_ping_resp_msg_v01 *resp = data;
+
+	if (!txn) {
+		pr_err("spurious ping response\n");
+		return;
+	}
+
+	if (resp->resp.result == QMI_RESULT_FAILURE_V01)
+		txn->result = -ENXIO;
+	else if (!resp->pong_valid || memcmp(resp->pong, "pong", 4))
+		txn->result = -EINVAL;
+
+	complete(&txn->completion);
+}
+
+/*
+ * data_write() - data debugfs file write handler
+ * @file:	debugfs file context
+ * @user_buf:	reference to the user data
+ * @count:	number of bytes in @user_buf
+ * @ppos:	offset in @file to write
+ *
+ * This function allows user space to send out a data QMI encoded message to
+ * the associated remote test service and will return with the result of the
+ * transaction. It serves as an example of how to have the QMI helpers decode a
+ * transaction response into a provided object automatically.
+ *
+ * Return: @count, or negative errno on failure.
+ */
+static ssize_t data_write(struct file *file, const char __user *user_buf,
+			  size_t count, loff_t *ppos)
+
+{
+	struct qmi_handle *qmi = file->private_data;
+	struct test_data_resp_msg_v01 *resp;
+	struct test_data_req_msg_v01 *req;
+	struct qmi_txn txn;
+	int ret;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->data_len = min_t(size_t, sizeof(req->data), count);
+	if (copy_from_user(req->data, user_buf, req->data_len)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = qmi_txn_init(qmi, &txn, test_data_resp_msg_v01_ei, resp);
+	if (ret < 0)
+		goto out;
+
+	ret = qmi_send_request(qmi, NULL, &txn,
+			       TEST_DATA_REQ_MSG_ID_V01,
+			       TEST_DATA_REQ_MAX_MSG_LEN_V01,
+			       test_data_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, 5 * HZ);
+	if (ret < 0) {
+		goto out;
+	} else if (!resp->data_valid ||
+		   resp->data_len != req->data_len ||
+		   memcmp(resp->data, req->data, req->data_len)) {
+		pr_err("response data doesn't match expectation\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = count;
+
+out:
+	kfree(resp);
+	kfree(req);
+
+	return ret;
+}
+
+static const struct file_operations data_fops = {
+	.open = simple_open,
+	.write = data_write,
+};
+
+static struct qmi_msg_handler qmi_sample_handlers[] = {
+	{
+		.type = QMI_RESPONSE,
+		.msg_id = TEST_PING_REQ_MSG_ID_V01,
+		.ei = test_ping_resp_msg_v01_ei,
+		.decoded_size = sizeof(struct test_ping_req_msg_v01),
+		.fn = ping_pong_cb
+	},
+	{}
+};
+
+struct qmi_sample {
+	struct qmi_handle qmi;
+
+	struct dentry *de_dir;
+	struct dentry *de_data;
+	struct dentry *de_ping;
+};
+
+static struct dentry *qmi_debug_dir;
+
+static int qmi_sample_probe(struct platform_device *pdev)
+{
+	struct sockaddr_qrtr *sq;
+	struct qmi_sample *sample;
+	char path[20];
+	int ret;
+
+	sample = devm_kzalloc(&pdev->dev, sizeof(*sample), GFP_KERNEL);
+	if (!sample)
+		return -ENOMEM;
+
+	ret = qmi_handle_init(&sample->qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01,
+			      NULL,
+			      qmi_sample_handlers);
+	if (ret < 0)
+		return ret;
+
+	sq = dev_get_platdata(&pdev->dev);
+	ret = kernel_connect(sample->qmi.sock, (struct sockaddr *)sq,
+			     sizeof(*sq), 0);
+	if (ret < 0) {
+		pr_err("failed to connect to remote service port\n");
+		goto err_release_qmi_handle;
+	}
+
+	snprintf(path, sizeof(path), "%d:%d", sq->sq_node, sq->sq_port);
+
+	sample->de_dir = debugfs_create_dir(path, qmi_debug_dir);
+	if (IS_ERR(sample->de_dir)) {
+		ret = PTR_ERR(sample->de_dir);
+		goto err_release_qmi_handle;
+	}
+
+	sample->de_data = debugfs_create_file("data", 0600, sample->de_dir,
+					      sample, &data_fops);
+	if (IS_ERR(sample->de_data)) {
+		ret = PTR_ERR(sample->de_data);
+		goto err_remove_de_dir;
+	}
+
+	sample->de_ping = debugfs_create_file("ping", 0600, sample->de_dir,
+					      sample, &ping_fops);
+	if (IS_ERR(sample->de_ping)) {
+		ret = PTR_ERR(sample->de_ping);
+		goto err_remove_de_data;
+	}
+
+	platform_set_drvdata(pdev, sample);
+
+	return 0;
+
+err_remove_de_data:
+	debugfs_remove(sample->de_data);
+err_remove_de_dir:
+	debugfs_remove(sample->de_dir);
+err_release_qmi_handle:
+	qmi_handle_release(&sample->qmi);
+
+	return ret;
+}
+
+static int qmi_sample_remove(struct platform_device *pdev)
+{
+	struct qmi_sample *sample = platform_get_drvdata(pdev);
+
+	debugfs_remove(sample->de_ping);
+	debugfs_remove(sample->de_data);
+	debugfs_remove(sample->de_dir);
+
+	qmi_handle_release(&sample->qmi);
+
+	return 0;
+}
+
+static struct platform_driver qmi_sample_driver = {
+	.probe = qmi_sample_probe,
+	.remove = qmi_sample_remove,
+	.driver = {
+		.name = "qmi_sample_client",
+	},
+};
+
+static int qmi_sample_new_server(struct qmi_handle *qmi,
+				 struct qmi_service *service)
+{
+	struct platform_device *pdev;
+	struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
+	int ret;
+
+	pdev = platform_device_alloc("qmi_sample_client", PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(pdev, &sq, sizeof(sq));
+	if (ret)
+		goto err_put_device;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto err_put_device;
+
+	service->priv = pdev;
+
+	return 0;
+
+err_put_device:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static void qmi_sample_del_server(struct qmi_handle *qmi,
+				  struct qmi_service *service)
+{
+	struct platform_device *pdev = service->priv;
+
+	platform_device_unregister(pdev);
+}
+
+static struct qmi_handle lookup_client;
+
+static struct qmi_ops lookup_ops = {
+	.new_server = qmi_sample_new_server,
+	.del_server = qmi_sample_del_server,
+};
+
+static int qmi_sample_init(void)
+{
+	int ret;
+
+	qmi_debug_dir = debugfs_create_dir("qmi_sample", NULL);
+	if (IS_ERR(qmi_debug_dir)) {
+		pr_err("failed to create qmi_sample dir\n");
+		return PTR_ERR(qmi_debug_dir);
+	}
+
+	ret = platform_driver_register(&qmi_sample_driver);
+	if (ret)
+		goto err_remove_debug_dir;
+
+	ret = qmi_handle_init(&lookup_client, 0, &lookup_ops, NULL);
+	if (ret < 0)
+		goto err_unregister_driver;
+
+	qmi_add_lookup(&lookup_client, 15, 0, 0);
+
+	return 0;
+
+err_unregister_driver:
+	platform_driver_unregister(&qmi_sample_driver);
+err_remove_debug_dir:
+	debugfs_remove(qmi_debug_dir);
+
+	return ret;
+}
+
+static void qmi_sample_exit(void)
+{
+	qmi_handle_release(&lookup_client);
+
+	platform_driver_unregister(&qmi_sample_driver);
+
+	debugfs_remove(qmi_debug_dir);
+}
+
+module_init(qmi_sample_init);
+module_exit(qmi_sample_exit);
+
+MODULE_DESCRIPTION("Sample QMI client driver");
+MODULE_LICENSE("GPL v2");
diff --git a/samples/sockmap/Makefile b/samples/sockmap/Makefile
index 73f1da4d116c..9bf2881bd11b 100644
--- a/samples/sockmap/Makefile
+++ b/samples/sockmap/Makefile
@@ -2,7 +2,7 @@
 hostprogs-y := sockmap
 
 # Libbpf dependencies
-LIBBPF := ../../tools/lib/bpf/bpf.o
+LIBBPF := ../../tools/lib/bpf/bpf.o ../../tools/lib/bpf/nlattr.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 HOSTCFLAGS += -I$(srctree)/tools/lib/
diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c
index 7c25c0c112bc..95a54a89a532 100644
--- a/samples/sockmap/sockmap_user.c
+++ b/samples/sockmap/sockmap_user.c
@@ -566,6 +566,7 @@ int main(int argc, char **argv)
 	else
 		fprintf(stderr, "unknown test\n");
 out:
+	bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
 	close(s1);
 	close(s2);
 	close(p1);
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 065324a8046f..34cbd81024b0 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -368,7 +368,7 @@ ksym_dep_filter =                                                            \
 	    $(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;;        \
 	  boot*|build*|cpp_its_S|*cpp_lds_S|dtc|host*|vdso*) : ;;            \
 	  *) echo "Don't know how to preprocess $(1)" >&2; false ;;          \
-	esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p'
+	esac | tr ";" "\n" | sed -n 's/^.*=== __KSYM_\(.*\) ===.*$$/KSYM_\1/p'
 
 cmd_and_fixdep =                                                             \
 	$(echo-cmd) $(cmd_$(1));                                             \
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 47cddf32aeba..b36ecb30c0c8 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -77,7 +77,7 @@ obj-y += $(obj)/lib-ksyms.o
 endif
 
 ifneq ($(strip $(obj-y) $(need-builtin)),)
-builtin-target := $(obj)/built-in.o
+builtin-target := $(obj)/built-in.a
 endif
 
 modorder-target := $(obj)/modules.order
@@ -104,7 +104,7 @@ ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),)
   cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $< ;
 endif
 
-# Do section mismatch analysis for each module/built-in.o
+# Do section mismatch analysis for each module/built-in.a
 ifdef CONFIG_DEBUG_SECTION_MISMATCH
   cmd_secanalysis = ; scripts/mod/modpost $@
 endif
@@ -306,7 +306,7 @@ endef
 
 # List module undefined symbols (or empty line if not enabled)
 ifdef CONFIG_TRIM_UNUSED_KSYMS
-cmd_undef_syms = $(NM) $@ | sed -n 's/^ \+U //p' | xargs echo
+cmd_undef_syms = $(NM) $@ | sed -n 's/^  *U //p' | xargs echo
 else
 cmd_undef_syms = echo
 endif
@@ -450,17 +450,15 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ;
 #
 ifdef builtin-target
 
-ifdef CONFIG_THIN_ARCHIVES
-  cmd_make_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS)
-  cmd_make_empty_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS)
-  quiet_cmd_link_o_target = AR      $@
-else
-  cmd_make_builtin = $(LD) $(ld_flags) -r -o
-  cmd_make_empty_builtin = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS)
-  quiet_cmd_link_o_target = LD      $@
-endif
+# built-in.a archives are made with no symbol table or index which
+# makes them small and fast, but unable to be used by the linker.
+# scripts/link-vmlinux.sh builds an aggregate built-in.a with a symbol
+# table and index.
+cmd_make_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS)
+cmd_make_empty_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS)
+quiet_cmd_link_o_target = AR      $@
 
-# If the list of objects to link is empty, just create an empty built-in.o
+# If the list of objects to link is empty, just create an empty built-in.a
 cmd_link_o_target = $(if $(strip $(obj-y)),\
 		      $(cmd_make_builtin) $@ $(filter $(obj-y), $^) \
 		      $(cmd_secanalysis),\
@@ -491,11 +489,8 @@ $(modorder-target): $(subdir-ym) FORCE
 ifdef lib-target
 quiet_cmd_link_l_target = AR      $@
 
-ifdef CONFIG_THIN_ARCHIVES
-  cmd_link_l_target = rm -f $@; $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y)
-else
-  cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
-endif
+# lib target archives do get a symbol table and index
+cmd_link_l_target = rm -f $@; $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y)
 
 $(lib-target): $(lib-y) FORCE
 	$(call if_changed,link_l_target)
@@ -543,13 +538,8 @@ $($(subst $(obj)/,,$(@:.o=-m)))), $^)
 
 cmd_link_multi-link = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
 
-ifdef CONFIG_THIN_ARCHIVES
-  quiet_cmd_link_multi-y = AR      $@
-  cmd_link_multi-y = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(link_multi_deps)
-else
-  quiet_cmd_link_multi-y = LD      $@
-  cmd_link_multi-y = $(cmd_link_multi-link)
-endif
+quiet_cmd_link_multi-y = AR      $@
+cmd_link_multi-y = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(link_multi_deps)
 
 quiet_cmd_link_multi-m = LD [M]  $@
 cmd_link_multi-m = $(cmd_link_multi-link)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 5589bae34af6..3b151bb390cb 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -27,7 +27,7 @@ modorder	:= $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko
 
 # Handle objects in subdirs
 # ---------------------------------------------------------------------------
-# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o
+# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.a
 #   and add the directory to the list of dirs to descend into: $(subdir-y)
 # o if we encounter foo/ in $(obj-m), remove it from $(obj-m)
 #   and add the directory to the list of dirs to descend into: $(subdir-m)
@@ -35,7 +35,7 @@ __subdir-y	:= $(patsubst %/,%,$(filter %/, $(obj-y)))
 subdir-y	+= $(__subdir-y)
 __subdir-m	:= $(patsubst %/,%,$(filter %/, $(obj-m)))
 subdir-m	+= $(__subdir-m)
-obj-y		:= $(patsubst %/, %/built-in.o, $(obj-y))
+obj-y		:= $(patsubst %/, %/built-in.a, $(obj-y))
 obj-m		:= $(filter-out %/, $(obj-m))
 
 # Subdirectories we need to descend into
@@ -54,7 +54,7 @@ multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
 
 # $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to
 # tell kbuild to descend
-subdir-obj-y := $(filter %/built-in.o, $(obj-y))
+subdir-obj-y := $(filter %/built-in.a, $(obj-y))
 
 # Replace multi-part objects by their individual parts, look at local dir only
 real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh
index 513da1a4a2da..a162258ab606 100755
--- a/scripts/adjust_autoksyms.sh
+++ b/scripts/adjust_autoksyms.sh
@@ -60,7 +60,9 @@ cat > "$new_ksyms_file" << EOT
 
 EOT
 [ "$(ls -A "$MODVERDIR")" ] &&
-sed -ns -e '3{s/ /\n/g;/^$/!p;}' "$MODVERDIR"/*.mod | sort -u |
+for mod in "$MODVERDIR"/*.mod; do
+	sed -n -e '3{s/ /\n/g;/^$/!p;}' "$mod"
+done | sort -u |
 while read sym; do
 	if [ -n "$CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX" ]; then
 		sym="${sym#_}"
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 86a3c0e5cfbc..10e528b3a08f 100755
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -194,7 +194,7 @@ input_file() {
 	source="$1"
 	if [ -f "$1" ]; then
 		${dep_list}header "$1"
-		is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
+		is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\{0,1\}/cpio/')"
 		if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
 			cpio_file=$1
 			echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index a18bca720995..593f8879c641 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -31,13 +31,13 @@ trap 'rm -f "$OUTDIR/$FILE" "$OUTDIR/$FILE.sed"' EXIT
 for i in "$@"
 do
 	FILE="$(basename "$i")"
-	sed -r \
-		-e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \
-		-e 's/__attribute_const__([ \t]|$)/\1/g' \
+	sed -E \
+		-e 's/([[:space:](])(__user|__force|__iomem)[[:space:]]/\1/g' \
+		-e 's/__attribute_const__([[:space:]]|$)/\1/g' \
 		-e 's@^#include <linux/compiler(|_types).h>@@' \
 		-e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \
-		-e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \
-		-e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \
+		-e 's/(^|[[:space:](])(inline|asm|volatile)([[:space:](]|$)/\1__\2__\3/g' \
+		-e 's@#(ifndef|define|endif[[:space:]]*/[*])[[:space:]]*_UAPI@#\1 @' \
 		"$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1
 	scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ "$OUTDIR/$FILE.sed" \
 		> "$OUTDIR/$FILE"
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index fee8952037b1..dc68d76f21ab 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -363,7 +363,7 @@ my $doc_sect = $doc_com .
 my $doc_content = $doc_com_body . '(.*)';
 my $doc_block = $doc_com . 'DOC:\s*(.*)?';
 my $doc_inline_start = '^\s*/\*\*\s*$';
-my $doc_inline_sect = '\s*\*\s*(@[\w\s]+):(.*)';
+my $doc_inline_sect = '\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)';
 my $doc_inline_end = '^\s*\*/\s*$';
 my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$';
 my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;';
@@ -1873,7 +1873,7 @@ sub process_file($) {
 	    }
 	    elsif (/$doc_decl/o) {
 		$identifier = $1;
-		if (/\s*([\w\s]+?)\s*-/) {
+		if (/\s*([\w\s]+?)(\(\))?\s*-/) {
 		    $identifier = $1;
 		}
 
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index c0d129d7f430..bf9a24e51b9b 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -4,7 +4,7 @@
 # link vmlinux
 #
 # vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_INIT) and
-# $(KBUILD_VMLINUX_MAIN) and $(KBUILD_VMLINUX_LIBS). Most are built-in.o files
+# $(KBUILD_VMLINUX_MAIN) and $(KBUILD_VMLINUX_LIBS). Most are built-in.a files
 # from top-level directories in the kernel tree, others are specified in
 # arch/$(ARCH)/Makefile. Ordering when linking is important, and
 # $(KBUILD_VMLINUX_INIT) must be first. $(KBUILD_VMLINUX_LIBS) are archives
@@ -18,7 +18,7 @@
 #   |   +--< init/version.o + more
 #   |
 #   +--< $(KBUILD_VMLINUX_MAIN)
-#   |    +--< drivers/built-in.o mm/built-in.o + more
+#   |    +--< drivers/built-in.a mm/built-in.a + more
 #   |
 #   +--< $(KBUILD_VMLINUX_LIBS)
 #   |    +--< lib/lib.a + more
@@ -51,17 +51,15 @@ info()
 #
 # Traditional incremental style of link does not require this step
 #
-# built-in.o output file
+# built-in.a output file
 #
 archive_builtin()
 {
-	if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
-		info AR built-in.o
-		rm -f built-in.o;
-		${AR} rcsTP${KBUILD_ARFLAGS} built-in.o			\
-					${KBUILD_VMLINUX_INIT}		\
-					${KBUILD_VMLINUX_MAIN}
-	fi
+	info AR built-in.a
+	rm -f built-in.a;
+	${AR} rcsTP${KBUILD_ARFLAGS} built-in.a			\
+				${KBUILD_VMLINUX_INIT}		\
+				${KBUILD_VMLINUX_MAIN}
 }
 
 # Link of vmlinux.o used for section mismatch analysis
@@ -70,20 +68,13 @@ modpost_link()
 {
 	local objects
 
-	if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
-		objects="--whole-archive				\
-			built-in.o					\
-			--no-whole-archive				\
-			--start-group					\
-			${KBUILD_VMLINUX_LIBS}				\
-			--end-group"
-	else
-		objects="${KBUILD_VMLINUX_INIT}				\
-			--start-group					\
-			${KBUILD_VMLINUX_MAIN}				\
-			${KBUILD_VMLINUX_LIBS}				\
-			--end-group"
-	fi
+	objects="--whole-archive				\
+		built-in.a					\
+		--no-whole-archive				\
+		--start-group					\
+		${KBUILD_VMLINUX_LIBS}				\
+		--end-group"
+
 	${LD} ${LDFLAGS} -r -o ${1} ${objects}
 }
 
@@ -96,46 +87,28 @@ vmlinux_link()
 	local objects
 
 	if [ "${SRCARCH}" != "um" ]; then
-		if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
-			objects="--whole-archive			\
-				built-in.o				\
-				--no-whole-archive			\
-				--start-group				\
-				${KBUILD_VMLINUX_LIBS}			\
-				--end-group				\
-				${1}"
-		else
-			objects="${KBUILD_VMLINUX_INIT}			\
-				--start-group				\
-				${KBUILD_VMLINUX_MAIN}			\
-				${KBUILD_VMLINUX_LIBS}			\
-				--end-group				\
-				${1}"
-		fi
-
-		${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}		\
+		objects="--whole-archive			\
+			built-in.a				\
+			--no-whole-archive			\
+			--start-group				\
+			${KBUILD_VMLINUX_LIBS}			\
+			--end-group				\
+			${1}"
+
+		${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}	\
 			-T ${lds} ${objects}
 	else
-		if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
-			objects="-Wl,--whole-archive			\
-				built-in.o				\
-				-Wl,--no-whole-archive			\
-				-Wl,--start-group			\
-				${KBUILD_VMLINUX_LIBS}			\
-				-Wl,--end-group				\
-				${1}"
-		else
-			objects="${KBUILD_VMLINUX_INIT}			\
-				-Wl,--start-group			\
-				${KBUILD_VMLINUX_MAIN}			\
-				${KBUILD_VMLINUX_LIBS}			\
-				-Wl,--end-group				\
-				${1}"
-		fi
-
-		${CC} ${CFLAGS_vmlinux} -o ${2}				\
-			-Wl,-T,${lds}					\
-			${objects}					\
+		objects="-Wl,--whole-archive			\
+			built-in.a				\
+			-Wl,--no-whole-archive			\
+			-Wl,--start-group			\
+			${KBUILD_VMLINUX_LIBS}			\
+			-Wl,--end-group				\
+			${1}"
+
+		${CC} ${CFLAGS_vmlinux} -o ${2}			\
+			-Wl,-T,${lds}				\
+			${objects}				\
 			-lutil -lrt -lpthread
 		rm -f linux
 	fi
@@ -191,7 +164,7 @@ cleanup()
 	rm -f .tmp_System.map
 	rm -f .tmp_kallsyms*
 	rm -f .tmp_vmlinux*
-	rm -f built-in.o
+	rm -f built-in.a
 	rm -f System.map
 	rm -f vmlinux
 	rm -f vmlinux.o
diff --git a/scripts/namespace.pl b/scripts/namespace.pl
index 729c547fc9e1..6135574a6f39 100755
--- a/scripts/namespace.pl
+++ b/scripts/namespace.pl
@@ -164,7 +164,7 @@ sub linux_objects
 	s:^\./::;
 	if (/.*\.o$/ &&
 		! (
-		m:/built-in.o$:
+		m:/built-in.a$:
 		|| m:arch/x86/vdso/:
 		|| m:arch/x86/boot/:
 		|| m:arch/ia64/ia32/ia32.o$:
diff --git a/scripts/split-man.pl b/scripts/split-man.pl
new file mode 100755
index 000000000000..bfe16cbe42df
--- /dev/null
+++ b/scripts/split-man.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+# SPDX-License-Identifier: GPL-2.0
+#
+# Author: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+#
+# Produce manpages from kernel-doc.
+# See Documentation/doc-guide/kernel-doc.rst for instructions
+
+if ($#ARGV < 0) {
+   die "where do I put the results?\n";
+}
+
+mkdir $ARGV[0],0777;
+$state = 0;
+while (<STDIN>) {
+    if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) {
+	if ($state == 1) { close OUT }
+	$state = 1;
+	$fn = "$ARGV[0]/$1.9";
+	print STDERR "Creating $fn\n";
+	open OUT, ">$fn" or die "can't open $fn: $!\n";
+	print OUT $_;
+    } elsif ($state != 0) {
+	print OUT $_;
+    }
+}
+
+close OUT;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 9a65eeaf7dfa..6631fda41c03 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -688,6 +688,7 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
 	aa_inherit_files(bprm->cred, current->files);
 
 	current->pdeath_signal = 0;
+	current->signal->pdeath_signal_proc = 0;
 
 	/* reset soft limits and set hard limits for the new label */
 	__aa_transition_rlimits(label, new_ctx->label);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2cfb0c714967..55d914934614 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -25,6 +25,7 @@
 #include <linux/xattr.h>
 #include <linux/ima.h>
 #include <linux/iversion.h>
+#include <linux/fs.h>
 
 #include "ima.h"
 
@@ -229,9 +230,19 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
 				 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
 				 IMA_ACTION_FLAGS);
 
-	if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags))
-		/* reset all flags if ima_inode_setxattr was called */
+	/*
+	 * Reset the measure, appraise and audit cached flags either if:
+	 * - ima_inode_setxattr was called, or
+	 * - based on filesystem feature flag
+	 * forcing the file to be re-evaluated.
+	 */
+	if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags)) {
+		iint->flags &= ~IMA_DONE_MASK;
+	} else if (inode->i_sb->s_type->fs_flags & FS_IMA_NO_CACHE) {
 		iint->flags &= ~IMA_DONE_MASK;
+		if (action & IMA_MEASURE)
+			iint->measured_pcrs = 0;
+	}
 
 	/* Determine if already appraised/measured based on bitmask
 	 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8644d864e3c1..35ef1e9045e8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2564,6 +2564,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
 
 	/* Always clear parent death signal on SID transitions. */
 	current->pdeath_signal = 0;
+	current->signal->pdeath_signal_proc = 0;
 
 	/* Check whether the new SID can inherit resource limits from the old
 	 * SID.  If not, reset all soft limits to the lower of the current
diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c
index cd6932e5225c..9094f4b3b367 100644
--- a/security/tomoyo/network.c
+++ b/security/tomoyo/network.c
@@ -655,10 +655,11 @@ int tomoyo_socket_listen_permission(struct socket *sock)
 		return 0;
 	{
 		const int error = sock->ops->getname(sock, (struct sockaddr *)
-						     &addr, &addr_len, 0);
+						     &addr, 0);
 
-		if (error)
+		if (error < 0)
 			return error;
+		addr_len = error;
 	}
 	address.protocol = type;
 	address.operation = TOMOYO_NETWORK_LISTEN;
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 06f845e293cb..7ba100bb1c3f 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -3,6 +3,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -1064,3 +1065,37 @@ bool snd_hdac_check_power_state(struct hdac_device *hdac,
 	return (state == target_state);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_check_power_state);
+/**
+ * snd_hdac_sync_power_state - wait until actual power state matches
+ * with the target state
+ *
+ * @hdac: the HDAC device
+ * @nid: NID to send the command
+ * @target_state: target state to check for
+ *
+ * Return power state or PS_ERROR if codec rejects GET verb.
+ */
+unsigned int snd_hdac_sync_power_state(struct hdac_device *codec,
+			hda_nid_t nid, unsigned int power_state)
+{
+	unsigned long end_time = jiffies + msecs_to_jiffies(500);
+	unsigned int state, actual_state, count;
+
+	for (count = 0; count < 500; count++) {
+		state = snd_hdac_codec_read(codec, nid, 0,
+				AC_VERB_GET_POWER_STATE, 0);
+		if (state & AC_PWRST_ERROR) {
+			msleep(20);
+			break;
+		}
+		actual_state = (state >> 4) & 0x0f;
+		if (actual_state == power_state)
+			break;
+		if (time_after_eq(jiffies, end_time))
+			break;
+		/* wait until the codec reachs to the target state */
+		msleep(1);
+	}
+	return state;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_sync_power_state);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index ccf4415a1c7b..18267de3a269 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/iommu.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -1272,12 +1273,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
 	release_firmware(emu->dock_fw);
 	if (emu->irq >= 0)
 		free_irq(emu->irq, emu);
-	/* remove reserved page */
-	if (emu->reserved_page) {
-		snd_emu10k1_synth_free(emu,
-			(struct snd_util_memblk *)emu->reserved_page);
-		emu->reserved_page = NULL;
-	}
 	snd_util_memhdr_free(emu->memhdr);
 	if (emu->silent_page.area)
 		snd_dma_free_pages(&emu->silent_page);
@@ -1764,6 +1759,38 @@ static struct snd_emu_chip_details emu_chip_details[] = {
 	{ } /* terminator */
 };
 
+/*
+ * The chip (at least the Audigy 2 CA0102 chip, but most likely others, too)
+ * has a problem that from time to time it likes to do few DMA reads a bit
+ * beyond its normal allocation and gets very confused if these reads get
+ * blocked by a IOMMU.
+ *
+ * This behaviour has been observed for the first (reserved) page
+ * (for which it happens multiple times at every playback), often for various
+ * synth pages and sometimes for PCM playback buffers and the page table
+ * memory itself.
+ *
+ * As a workaround let's widen these DMA allocations by an extra page if we
+ * detect that the device is behind a non-passthrough IOMMU.
+ */
+static void snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu)
+{
+	struct iommu_domain *domain;
+
+	emu->iommu_workaround = false;
+
+	if (!iommu_present(emu->card->dev->bus))
+		return;
+
+	domain = iommu_get_domain_for_dev(emu->card->dev);
+	if (domain && domain->type == IOMMU_DOMAIN_IDENTITY)
+		return;
+
+	dev_notice(emu->card->dev,
+		   "non-passthrough IOMMU detected, widening DMA allocations");
+	emu->iommu_workaround = true;
+}
+
 int snd_emu10k1_create(struct snd_card *card,
 		       struct pci_dev *pci,
 		       unsigned short extin_mask,
@@ -1776,6 +1803,7 @@ int snd_emu10k1_create(struct snd_card *card,
 	struct snd_emu10k1 *emu;
 	int idx, err;
 	int is_audigy;
+	size_t page_table_size;
 	unsigned int silent_page;
 	const struct snd_emu_chip_details *c;
 	static struct snd_device_ops ops = {
@@ -1873,12 +1901,13 @@ int snd_emu10k1_create(struct snd_card *card,
 
 	is_audigy = emu->audigy = c->emu10k2_chip;
 
+	snd_emu10k1_detect_iommu(emu);
+
 	/* set addressing mode */
 	emu->address_mode = is_audigy ? 0 : 1;
 	/* set the DMA transfer mask */
 	emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
-	if (dma_set_mask(&pci->dev, emu->dma_mask) < 0 ||
-	    dma_set_coherent_mask(&pci->dev, emu->dma_mask) < 0) {
+	if (dma_set_mask_and_coherent(&pci->dev, emu->dma_mask) < 0) {
 		dev_err(card->dev,
 			"architecture does not support PCI busmaster DMA with mask 0x%lx\n",
 			emu->dma_mask);
@@ -1900,11 +1929,17 @@ int snd_emu10k1_create(struct snd_card *card,
 	emu->port = pci_resource_start(pci, 0);
 
 	emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
-	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
-				(emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) {
+
+	page_table_size = sizeof(u32) * (emu->address_mode ? MAXPAGES1 :
+					 MAXPAGES0);
+	if (snd_emu10k1_alloc_pages_maybe_wider(emu, page_table_size,
+						&emu->ptb_pages) < 0) {
 		err = -ENOMEM;
 		goto error;
 	}
+	dev_dbg(card->dev, "page table address range is %.8lx:%.8lx\n",
+		(unsigned long)emu->ptb_pages.addr,
+		(unsigned long)(emu->ptb_pages.addr + emu->ptb_pages.bytes));
 
 	emu->page_ptr_table = vmalloc(emu->max_cache_pages * sizeof(void *));
 	emu->page_addr_table = vmalloc(emu->max_cache_pages *
@@ -1914,11 +1949,16 @@ int snd_emu10k1_create(struct snd_card *card,
 		goto error;
 	}
 
-	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
-				EMUPAGESIZE, &emu->silent_page) < 0) {
+	if (snd_emu10k1_alloc_pages_maybe_wider(emu, EMUPAGESIZE,
+						&emu->silent_page) < 0) {
 		err = -ENOMEM;
 		goto error;
 	}
+	dev_dbg(card->dev, "silent page range is %.8lx:%.8lx\n",
+		(unsigned long)emu->silent_page.addr,
+		(unsigned long)(emu->silent_page.addr +
+				emu->silent_page.bytes));
+
 	emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
 	if (emu->memhdr == NULL) {
 		err = -ENOMEM;
@@ -1993,13 +2033,8 @@ int snd_emu10k1_create(struct snd_card *card,
 		SPCS_GENERATIONSTATUS | 0x00001200 |
 		0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
 
-	emu->reserved_page = (struct snd_emu10k1_memblk *)
-		snd_emu10k1_synth_alloc(emu, 4096);
-	if (emu->reserved_page)
-		emu->reserved_page->map_locked = 1;
-
 	/* Clear silent pages and set up pointers */
-	memset(emu->silent_page.area, 0, PAGE_SIZE);
+	memset(emu->silent_page.area, 0, emu->silent_page.bytes);
 	silent_page = emu->silent_page.addr << emu->address_mode;
 	for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
 		((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 2683b9717215..cefe613ef7b7 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -411,12 +411,20 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
 	struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_emu10k1_pcm *epcm = runtime->private_data;
+	size_t alloc_size;
 	int err;
 
 	if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
 		return err;
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+
+	alloc_size = params_buffer_bytes(hw_params);
+	if (emu->iommu_workaround)
+		alloc_size += EMUPAGESIZE;
+	err = snd_pcm_lib_malloc_pages(substream, alloc_size);
+	if (err < 0)
 		return err;
+	if (emu->iommu_workaround && runtime->dma_bytes >= EMUPAGESIZE)
+		runtime->dma_bytes -= EMUPAGESIZE;
 	if (err > 0) {	/* change */
 		int mapped;
 		if (epcm->memblk != NULL)
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 4f1f69be1865..5865f3b90b34 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -34,7 +34,10 @@
  * aligned pages in others
  */
 #define __set_ptb_entry(emu,page,addr) \
-	(((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
+	(((__le32 *)(emu)->ptb_pages.area)[page] = \
+	 cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
+#define __get_ptb_entry(emu, page) \
+	(le32_to_cpu(((__le32 *)(emu)->ptb_pages.area)[page]))
 
 #define UNIT_PAGES		(PAGE_SIZE / EMUPAGESIZE)
 #define MAX_ALIGN_PAGES0		(MAXPAGES0 / UNIT_PAGES)
@@ -44,8 +47,7 @@
 /* get offset address from aligned page */
 #define aligned_page_offset(page)	((page) << PAGE_SHIFT)
 
-#if PAGE_SIZE == 4096
-/* page size == EMUPAGESIZE */
+#if PAGE_SIZE == EMUPAGESIZE && !IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
 /* fill PTB entrie(s) corresponding to page with addr */
 #define set_ptb_entry(emu,page,addr)	__set_ptb_entry(emu,page,addr)
 /* fill PTB entrie(s) corresponding to page with silence pointer */
@@ -58,6 +60,8 @@ static inline void set_ptb_entry(struct snd_emu10k1 *emu, int page, dma_addr_t a
 	page *= UNIT_PAGES;
 	for (i = 0; i < UNIT_PAGES; i++, page++) {
 		__set_ptb_entry(emu, page, addr);
+		dev_dbg(emu->card->dev, "mapped page %d to entry %.8x\n", page,
+			(unsigned int)__get_ptb_entry(emu, page));
 		addr += EMUPAGESIZE;
 	}
 }
@@ -65,9 +69,12 @@ static inline void set_silent_ptb(struct snd_emu10k1 *emu, int page)
 {
 	int i;
 	page *= UNIT_PAGES;
-	for (i = 0; i < UNIT_PAGES; i++, page++)
+	for (i = 0; i < UNIT_PAGES; i++, page++) {
 		/* do not increment ptr */
 		__set_ptb_entry(emu, page, emu->silent_page.addr);
+		dev_dbg(emu->card->dev, "mapped silent page %d to entry %.8x\n",
+			page, (unsigned int)__get_ptb_entry(emu, page));
+	}
 }
 #endif /* PAGE_SIZE */
 
@@ -102,7 +109,7 @@ static void emu10k1_memblk_init(struct snd_emu10k1_memblk *blk)
  */
 static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct list_head **nextp)
 {
-	int page = 0, found_page = -ENOMEM;
+	int page = 1, found_page = -ENOMEM;
 	int max_size = npages;
 	int size;
 	struct list_head *candidate = &emu->mapped_link_head;
@@ -147,6 +154,10 @@ static int map_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
 	page = search_empty_map_area(emu, blk->pages, &next);
 	if (page < 0) /* not found */
 		return page;
+	if (page == 0) {
+		dev_err(emu->card->dev, "trying to map zero (reserved) page\n");
+		return -EINVAL;
+	}
 	/* insert this block in the proper position of mapped list */
 	list_add_tail(&blk->mapped_link, next);
 	/* append this as a newest block in order list */
@@ -177,7 +188,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
 		q = get_emu10k1_memblk(p, mapped_link);
 		start_page = q->mapped_page + q->pages;
 	} else
-		start_page = 0;
+		start_page = 1;
 	if ((p = blk->mapped_link.next) != &emu->mapped_link_head) {
 		q = get_emu10k1_memblk(p, mapped_link);
 		end_page = q->mapped_page;
@@ -366,6 +377,33 @@ int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk)
 	return snd_emu10k1_synth_free(emu, blk);
 }
 
+/*
+ * allocate DMA pages, widening the allocation if necessary
+ *
+ * See the comment above snd_emu10k1_detect_iommu() in emu10k1_main.c why
+ * this might be needed.
+ *
+ * If you modify this function check whether __synth_free_pages() also needs
+ * changes.
+ */
+int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
+					struct snd_dma_buffer *dmab)
+{
+	if (emu->iommu_workaround) {
+		size_t npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+		size_t size_real = npages * PAGE_SIZE;
+
+		/*
+		 * The device has been observed to accesses up to 256 extra
+		 * bytes, but use 1k to be safe.
+		 */
+		if (size_real < size + 1024)
+			size += PAGE_SIZE;
+	}
+
+	return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+				   snd_dma_pci_data(emu->pci), size, dmab);
+}
 
 /*
  * memory allocation using multiple pages (for synth)
@@ -450,10 +488,27 @@ static void get_single_page_range(struct snd_util_memhdr *hdr,
 static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
 			       int last_page)
 {
+	struct snd_dma_buffer dmab;
 	int page;
 
+	dmab.dev.type = SNDRV_DMA_TYPE_DEV;
+	dmab.dev.dev = snd_dma_pci_data(emu->pci);
+
 	for (page = first_page; page <= last_page; page++) {
-		free_page((unsigned long)emu->page_ptr_table[page]);
+		if (emu->page_ptr_table[page] == NULL)
+			continue;
+		dmab.area = emu->page_ptr_table[page];
+		dmab.addr = emu->page_addr_table[page];
+
+		/*
+		 * please keep me in sync with logic in
+		 * snd_emu10k1_alloc_pages_maybe_wider()
+		 */
+		dmab.bytes = PAGE_SIZE;
+		if (emu->iommu_workaround)
+			dmab.bytes *= 2;
+
+		snd_dma_free_pages(&dmab);
 		emu->page_addr_table[page] = 0;
 		emu->page_ptr_table[page] = NULL;
 	}
@@ -465,30 +520,30 @@ static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
 static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
 {
 	int page, first_page, last_page;
+	struct snd_dma_buffer dmab;
 
 	emu10k1_memblk_init(blk);
 	get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
 	/* allocate kernel pages */
 	for (page = first_page; page <= last_page; page++) {
-		/* first try to allocate from <4GB zone */
-		struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 |
-					    __GFP_NOWARN);
-		if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) {
-			if (p)
-				__free_page(p);
-			/* try to allocate from <16MB zone */
-			p = alloc_page(GFP_ATOMIC | GFP_DMA |
-				       __GFP_NORETRY | /* no OOM-killer */
-				       __GFP_NOWARN);
+		if (snd_emu10k1_alloc_pages_maybe_wider(emu, PAGE_SIZE,
+							&dmab) < 0)
+			goto __fail;
+		if (!is_valid_page(emu, dmab.addr)) {
+			snd_dma_free_pages(&dmab);
+			goto __fail;
 		}
-		if (!p) {
-			__synth_free_pages(emu, first_page, page - 1);
-			return -ENOMEM;
-		}
-		emu->page_addr_table[page] = page_to_phys(p);
-		emu->page_ptr_table[page] = page_address(p);
+		emu->page_addr_table[page] = dmab.addr;
+		emu->page_ptr_table[page] = dmab.area;
 	}
 	return 0;
+
+__fail:
+	/* release allocated pages */
+	last_page = page - 1;
+	__synth_free_pages(emu, first_page, last_page);
+
+	return -ENOMEM;
 }
 
 /*
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e018ecbf78a8..5bc3a7468e17 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2702,32 +2702,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all);
 
-/*
- * wait until the state is reached, returns the current state
- */
-static unsigned int hda_sync_power_state(struct hda_codec *codec,
-					 hda_nid_t fg,
-					 unsigned int power_state)
-{
-	unsigned long end_time = jiffies + msecs_to_jiffies(500);
-	unsigned int state, actual_state;
-
-	for (;;) {
-		state = snd_hda_codec_read(codec, fg, 0,
-					   AC_VERB_GET_POWER_STATE, 0);
-		if (state & AC_PWRST_ERROR)
-			break;
-		actual_state = (state >> 4) & 0x0f;
-		if (actual_state == power_state)
-			break;
-		if (time_after_eq(jiffies, end_time))
-			break;
-		/* wait until the codec reachs to the target state */
-		msleep(1);
-	}
-	return state;
-}
-
 /**
  * snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
  * @codec: the HDA codec
@@ -2790,7 +2764,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
 						   state);
 			snd_hda_codec_set_power_to_all(codec, fg, power_state);
 		}
-		state = hda_sync_power_state(codec, fg, power_state);
+		state = snd_hda_sync_power_state(codec, fg, power_state);
 		if (!(state & AC_PWRST_ERROR))
 			break;
 	}
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5b5c324c99b9..321e78baa63c 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -622,7 +622,11 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
 {
 	return snd_hdac_check_power_state(&codec->core, nid, target_state);
 }
-
+static inline bool snd_hda_sync_power_state(struct hda_codec *codec,
+			   hda_nid_t nid, unsigned int target_state)
+{
+	return snd_hdac_sync_power_state(&codec->core, nid, target_state);
+}
 unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
 					     hda_nid_t nid,
 					     unsigned int power_state);
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index d5838402f667..6cbf9cf4d1a4 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -3,6 +3,15 @@ config SND_SOC_AMD_ACP
 	help
 	 This option enables ACP DMA support on AMD platform.
 
+config SND_SOC_AMD_CZ_DA7219MX98357_MACH
+	tristate "AMD CZ support for DA7219 and MAX9835"
+	select SND_SOC_DA7219
+	select SND_SOC_MAX98357A
+	select SND_SOC_ADAU7002
+	depends on SND_SOC_AMD_ACP && I2C
+	help
+	 This option enables machine driver for DA7219 and MAX9835.
+
 config SND_SOC_AMD_CZ_RT5645_MACH
 	tristate "AMD CZ support for RT5645"
 	select SND_SOC_RT5645
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index f07fd2e2870a..79b0622fa5d3 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -1,5 +1,7 @@
 acp_audio_dma-objs := acp-pcm-dma.o
+snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
 snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
 
 obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
+obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
 obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
new file mode 100644
index 000000000000..bbe0f103e6a8
--- /dev/null
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -0,0 +1,246 @@
+/*
+ * Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec
+ *
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+
+#define CZ_PLAT_CLK 24000000
+#define MCLK_RATE 24576000
+#define DUAL_CHANNEL		2
+
+static struct snd_soc_jack cz_jack;
+
+static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_component *component = codec_dai->component;
+
+	dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK,
+				     CZ_PLAT_CLK, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
+				  CZ_PLAT_CLK, MCLK_RATE);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_card_jack_new(card, "Headset Jack",
+				SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				&cz_jack, NULL, 0);
+	if (ret) {
+		dev_err(card->dev, "HP jack creation failed %d\n", ret);
+		return ret;
+	}
+
+	da7219_aad_jack_det(component, &cz_jack);
+
+	return 0;
+}
+
+static const unsigned int channels[] = {
+	DUAL_CHANNEL,
+};
+
+static const unsigned int rates[] = {
+	48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list  = rates,
+	.mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+	.count = ARRAY_SIZE(channels),
+	.list = channels,
+	.mask = 0,
+};
+
+static int cz_fe_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/*
+	 * On this platform for PCM device we support stereo
+	 */
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &constraints_channels);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				   &constraints_rates);
+
+	return 0;
+}
+
+static struct snd_soc_ops cz_da7219_cap_ops = {
+	.startup = cz_fe_startup,
+};
+
+static struct snd_soc_dai_link cz_dai_7219_98357[] = {
+	{
+		.name = "amd-da7219-play",
+		.stream_name = "Playback",
+		.platform_name = "acp_audio_dma.0.auto",
+		.cpu_dai_name = "designware-i2s.3.auto",
+		.codec_dai_name = "da7219-hifi",
+		.codec_name = "i2c-DLGS7219:00",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.init = cz_da7219_init,
+		.dpcm_playback = 1,
+	},
+	{
+		.name = "amd-da7219-cap",
+		.stream_name = "Capture",
+		.platform_name = "acp_audio_dma.0.auto",
+		.cpu_dai_name = "designware-i2s.4.auto",
+		.codec_dai_name = "da7219-hifi",
+		.codec_name = "i2c-DLGS7219:00",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.dpcm_capture = 1,
+		.ops = &cz_da7219_cap_ops,
+	},
+	{
+		.name = "amd-max98357-play",
+		.stream_name = "HiFi Playback",
+		.platform_name = "acp_audio_dma.0.auto",
+		.cpu_dai_name = "designware-i2s.1.auto",
+		.codec_dai_name = "HiFi",
+		.codec_name = "MX98357A:00",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.dpcm_playback = 1,
+	},
+	{
+		.name = "dmic",
+		.stream_name = "DMIC Capture",
+		.platform_name = "acp_audio_dma.0.auto",
+		.cpu_dai_name = "designware-i2s.2.auto",
+		.codec_dai_name = "adau7002-hifi",
+		.codec_name = "ADAU7002:00",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+				| SND_SOC_DAIFMT_CBM_CFM,
+		.dpcm_capture = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget cz_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route cz_audio_route[] = {
+	{"Headphones", NULL, "HPL"},
+	{"Headphones", NULL, "HPR"},
+	{"MIC", NULL, "Headset Mic"},
+	{"Speakers", NULL, "Speaker"},
+	{"PDM_DAT", NULL, "Int Mic"},
+};
+
+static const struct snd_kcontrol_new cz_mc_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphones"),
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static struct snd_soc_card cz_card = {
+	.name = "acpd7219m98357",
+	.owner = THIS_MODULE,
+	.dai_link = cz_dai_7219_98357,
+	.num_links = ARRAY_SIZE(cz_dai_7219_98357),
+	.dapm_widgets = cz_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cz_widgets),
+	.dapm_routes = cz_audio_route,
+	.num_dapm_routes = ARRAY_SIZE(cz_audio_route),
+	.controls = cz_mc_controls,
+	.num_controls = ARRAY_SIZE(cz_mc_controls),
+};
+
+static int cz_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct snd_soc_card *card;
+
+	card = &cz_card;
+	cz_card.dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
+	if (ret) {
+		dev_err(&pdev->dev,
+				"devm_snd_soc_register_card(%s) failed: %d\n",
+				cz_card.name, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static const struct acpi_device_id cz_audio_acpi_match[] = {
+	{ "AMD7219", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
+
+static struct platform_driver cz_pcm_driver = {
+	.driver = {
+		.name = "cz-da7219-max98357a",
+		.acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = cz_probe,
+};
+
+module_platform_driver(cz_pcm_driver);
+
+MODULE_AUTHOR("akshu.agrawal@amd.com");
+MODULE_DESCRIPTION("DA7219 & MAX98357A audio support");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index c33a512283a4..91c47752d9a9 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -23,6 +23,8 @@
 #include <drm/amd_asic_type.h>
 #include "acp.h"
 
+#define DRV_NAME "acp_audio_dma"
+
 #define PLAYBACK_MIN_NUM_PERIODS    2
 #define PLAYBACK_MAX_NUM_PERIODS    2
 #define PLAYBACK_MAX_PERIOD_SIZE    16384
@@ -182,19 +184,18 @@ static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
  * system memory <-> ACP SRAM
  */
 static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
-					u32 size, int direction,
-					u32 pte_offset, u32 asic_type)
+					u32 size, int direction, u32 pte_offset,
+					u16 ch, u32 sram_bank,
+					u16 dma_dscr_idx, u32 asic_type)
 {
 	u16 i;
-	u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
 	acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
 
 	for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
 		dmadscr[i].xfer_val = 0;
 		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
-			dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
-			dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS
-					+ (i * (size/2));
+			dma_dscr_idx = dma_dscr_idx + i;
+			dmadscr[i].dest = sram_bank + (i * (size/2));
 			dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
 				+ (pte_offset * SZ_4K) + (i * (size/2));
 			switch (asic_type) {
@@ -209,25 +210,19 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
 				(size / 2);
 			}
 		} else {
-			dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
+			dma_dscr_idx = dma_dscr_idx + i;
+			dmadscr[i].src = sram_bank + (i * (size/2));
+			dmadscr[i].dest =
+			ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+			(pte_offset * SZ_4K) + (i * (size/2));
 			switch (asic_type) {
 			case CHIP_STONEY:
-				dmadscr[i].src = ACP_SHARED_RAM_BANK_3_ADDRESS +
-				(i * (size/2));
-				dmadscr[i].dest =
-				ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
-				(pte_offset * SZ_4K) + (i * (size/2));
 				dmadscr[i].xfer_val |=
 				BIT(22) |
 				(ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC << 16) |
 				(size / 2);
 				break;
 			default:
-				dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
-				(i * (size/2));
-				dmadscr[i].dest =
-				ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
-				(pte_offset * SZ_4K) + (i * (size/2));
 				dmadscr[i].xfer_val |=
 				BIT(22) |
 				(ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
@@ -237,72 +232,49 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
 		config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
 						&dmadscr[i]);
 	}
-	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
-		config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM,
-					PLAYBACK_START_DMA_DESCR_CH12,
-					NUM_DSCRS_PER_CHANNEL,
-					ACP_DMA_PRIORITY_LEVEL_NORMAL);
-	else
-		config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM,
-					CAPTURE_START_DMA_DESCR_CH14,
-					NUM_DSCRS_PER_CHANNEL,
-					ACP_DMA_PRIORITY_LEVEL_NORMAL);
+	config_acp_dma_channel(acp_mmio, ch,
+				dma_dscr_idx - 1,
+				NUM_DSCRS_PER_CHANNEL,
+				ACP_DMA_PRIORITY_LEVEL_NORMAL);
 }
 
 /* Initialize the DMA descriptor information for transfer between
  * ACP SRAM <-> I2S
  */
-static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
-					u32 size, int direction,
-					u32 asic_type)
+static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
+						int direction, u32 sram_bank,
+						u16 destination, u16 ch,
+						u16 dma_dscr_idx, u32 asic_type)
 {
 
 	u16 i;
-	u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
 	acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
 
 	for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
 		dmadscr[i].xfer_val = 0;
 		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
-			dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i;
-			dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS +
-					 (i * (size/2));
+			dma_dscr_idx = dma_dscr_idx + i;
+			dmadscr[i].src = sram_bank  + (i * (size/2));
 			/* dmadscr[i].dest is unused by hardware. */
 			dmadscr[i].dest = 0;
-			dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) |
+			dmadscr[i].xfer_val |= BIT(22) | (destination << 16) |
 						(size / 2);
 		} else {
-			dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
+			dma_dscr_idx = dma_dscr_idx + i;
 			/* dmadscr[i].src is unused by hardware. */
 			dmadscr[i].src = 0;
-			switch (asic_type) {
-			case CHIP_STONEY:
-				dmadscr[i].dest =
-					 ACP_SHARED_RAM_BANK_3_ADDRESS +
-					(i * (size / 2));
-				break;
-			default:
-				dmadscr[i].dest =
-					 ACP_SHARED_RAM_BANK_5_ADDRESS +
-					(i * (size / 2));
-			}
+			dmadscr[i].dest =
+				 sram_bank + (i * (size / 2));
 			dmadscr[i].xfer_val |= BIT(22) |
-					(FROM_ACP_I2S_1 << 16) | (size / 2);
+				(destination << 16) | (size / 2);
 		}
 		config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
 						&dmadscr[i]);
 	}
 	/* Configure the DMA channel with the above descriptore */
-	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
-		config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
-					PLAYBACK_START_DMA_DESCR_CH13,
-					NUM_DSCRS_PER_CHANNEL,
-					ACP_DMA_PRIORITY_LEVEL_NORMAL);
-	else
-		config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
-					CAPTURE_START_DMA_DESCR_CH15,
-					NUM_DSCRS_PER_CHANNEL,
-					ACP_DMA_PRIORITY_LEVEL_NORMAL);
+	config_acp_dma_channel(acp_mmio, ch, dma_dscr_idx - 1,
+				NUM_DSCRS_PER_CHANNEL,
+				ACP_DMA_PRIORITY_LEVEL_NORMAL);
 }
 
 /* Create page table entries in ACP SRAM for the allocated memory */
@@ -344,23 +316,51 @@ static void config_acp_dma(void __iomem *acp_mmio,
 			struct audio_substream_data *audio_config,
 			u32 asic_type)
 {
-	u32 pte_offset;
+	u32 pte_offset, sram_bank;
+	u16 ch1, ch2, destination, dma_dscr_idx;
 
-	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) {
 		pte_offset = ACP_PLAYBACK_PTE_OFFSET;
-	else
+		ch1 = SYSRAM_TO_ACP_CH_NUM;
+		ch2 = ACP_TO_I2S_DMA_CH_NUM;
+		sram_bank = ACP_SHARED_RAM_BANK_1_ADDRESS;
+		destination = TO_ACP_I2S_1;
+
+	} else {
 		pte_offset = ACP_CAPTURE_PTE_OFFSET;
+		ch1 = SYSRAM_TO_ACP_CH_NUM;
+		ch2 = ACP_TO_I2S_DMA_CH_NUM;
+		switch (asic_type) {
+		case CHIP_STONEY:
+			sram_bank = ACP_SHARED_RAM_BANK_3_ADDRESS;
+			break;
+		default:
+			sram_bank = ACP_SHARED_RAM_BANK_5_ADDRESS;
+		}
+		destination = FROM_ACP_I2S_1;
+	}
 
 	acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
 			pte_offset);
+	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+	else
+		dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
 
 	/* Configure System memory <-> ACP SRAM DMA descriptors */
 	set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
-				audio_config->direction, pte_offset, asic_type);
+				       audio_config->direction, pte_offset,
+					ch1, sram_bank, dma_dscr_idx, asic_type);
 
+	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
+	else
+		dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15;
 	/* Configure ACP SRAM <-> I2S DMA descriptors */
 	set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
-				audio_config->direction, asic_type);
+					audio_config->direction, sram_bank,
+					destination, ch2, dma_dscr_idx,
+					asic_type);
 }
 
 /* Start a given DMA channel transfer */
@@ -662,7 +662,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
 				       1, 0);
 		acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
 
-		snd_pcm_period_elapsed(irq_data->play_stream);
+		snd_pcm_period_elapsed(irq_data->play_i2ssp_stream);
 
 		acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
 				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
@@ -685,7 +685,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
 
 	if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
 		valid_irq = true;
-		snd_pcm_period_elapsed(irq_data->capture_stream);
+		snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
 		acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
 				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
 	}
@@ -702,8 +702,8 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
-	struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev);
-
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+	struct audio_drv_data *intr_data = dev_get_drvdata(component->dev);
 	struct audio_substream_data *adata =
 		kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
 	if (adata == NULL)
@@ -730,7 +730,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 	ret = snd_pcm_hw_constraint_integer(runtime,
 					    SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0) {
-		dev_err(prtd->platform->dev, "set integer constraint failed\n");
+		dev_err(component->dev, "set integer constraint failed\n");
 		kfree(adata);
 		return ret;
 	}
@@ -743,11 +743,11 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 	 * This enablement is not required for another stream, if current
 	 * stream is not closed
 	*/
-	if (!intr_data->play_stream && !intr_data->capture_stream)
+	if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream)
 		acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		intr_data->play_stream = substream;
+		intr_data->play_i2ssp_stream = substream;
 		/* For Stoney, Memory gating is disabled,i.e SRAM Banks
 		 * won't be turned off. The default state for SRAM banks is ON.
 		 * Setting SRAM bank state code skipped for STONEY platform.
@@ -758,7 +758,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 							bank, true);
 		}
 	} else {
-		intr_data->capture_stream = substream;
+		intr_data->capture_i2ssp_stream = substream;
 		if (intr_data->asic_type != CHIP_STONEY) {
 			for (bank = 5; bank <= 8; bank++)
 				acp_set_sram_bank_state(intr_data->acp_mmio,
@@ -778,7 +778,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime;
 	struct audio_substream_data *rtd;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
-	struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+	struct audio_drv_data *adata = dev_get_drvdata(component->dev);
 
 	runtime = substream->runtime;
 	rtd = runtime->private_data;
@@ -857,11 +858,11 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
 	bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (bytescount > rtd->renderbytescount)
-			bytescount = bytescount - rtd->renderbytescount;
+		if (bytescount > rtd->i2ssp_renderbytescount)
+			bytescount = bytescount - rtd->i2ssp_renderbytescount;
 	} else {
-		if (bytescount > rtd->capturebytescount)
-			bytescount = bytescount - rtd->capturebytescount;
+		if (bytescount > rtd->i2ssp_capturebytescount)
+			bytescount = bytescount - rtd->i2ssp_capturebytescount;
 	}
 	pos = do_div(bytescount, buffersize);
 	return bytes_to_frames(runtime, pos);
@@ -907,6 +908,7 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
 	struct audio_substream_data *rtd = runtime->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
 
 	if (!rtd)
 		return -EINVAL;
@@ -917,14 +919,14 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 		bytescount = acp_get_byte_count(rtd->acp_mmio,
 						substream->stream);
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (rtd->renderbytescount == 0)
-				rtd->renderbytescount = bytescount;
+			if (rtd->i2ssp_renderbytescount == 0)
+				rtd->i2ssp_renderbytescount = bytescount;
 			acp_dma_start(rtd->acp_mmio,
 						SYSRAM_TO_ACP_CH_NUM, false);
 			while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
 						BIT(SYSRAM_TO_ACP_CH_NUM)) {
 				if (!loops--) {
-					dev_err(prtd->platform->dev,
+					dev_err(component->dev,
 						"acp dma start timeout\n");
 					return -ETIMEDOUT;
 				}
@@ -935,8 +937,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 					ACP_TO_I2S_DMA_CH_NUM, true);
 
 		} else {
-			if (rtd->capturebytescount == 0)
-				rtd->capturebytescount = bytescount;
+			if (rtd->i2ssp_capturebytescount == 0)
+				rtd->i2ssp_capturebytescount = bytescount;
 			acp_dma_start(rtd->acp_mmio,
 					    I2S_TO_ACP_DMA_CH_NUM, true);
 		}
@@ -953,11 +955,11 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			ret = acp_dma_stop(rtd->acp_mmio,
 					ACP_TO_I2S_DMA_CH_NUM);
-			rtd->renderbytescount = 0;
+			rtd->i2ssp_renderbytescount = 0;
 		} else {
 			ret = acp_dma_stop(rtd->acp_mmio,
 					I2S_TO_ACP_DMA_CH_NUM);
-			rtd->capturebytescount = 0;
+			rtd->i2ssp_capturebytescount = 0;
 		}
 		break;
 	default:
@@ -970,7 +972,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
-	struct audio_drv_data *adata = dev_get_drvdata(rtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct audio_drv_data *adata = dev_get_drvdata(component->dev);
 
 	switch (adata->asic_type) {
 	case CHIP_STONEY:
@@ -987,7 +990,7 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
 		break;
 	}
 	if (ret < 0)
-		dev_err(rtd->platform->dev,
+		dev_err(component->dev,
 				"buffer preallocation failer error:%d\n", ret);
 	return ret;
 }
@@ -998,12 +1001,13 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct audio_substream_data *rtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *prtd = substream->private_data;
-	struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
+	struct audio_drv_data *adata = dev_get_drvdata(component->dev);
 
 	kfree(rtd);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		adata->play_stream = NULL;
+		adata->play_i2ssp_stream = NULL;
 		/* For Stoney, Memory gating is disabled,i.e SRAM Banks
 		 * won't be turned off. The default state for SRAM banks is ON.
 		 * Setting SRAM bank state code skipped for STONEY platform.
@@ -1015,7 +1019,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
 				false);
 		}
 	} else  {
-		adata->capture_stream = NULL;
+		adata->capture_i2ssp_stream = NULL;
 		if (adata->asic_type != CHIP_STONEY) {
 			for (bank = 5; bank <= 8; bank++)
 				acp_set_sram_bank_state(adata->acp_mmio, bank,
@@ -1026,7 +1030,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
 	/* Disable ACP irq, when the current stream is being closed and
 	 * another stream is also not active.
 	*/
-	if (!adata->play_stream && !adata->capture_stream)
+	if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream)
 		acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
 
 	return 0;
@@ -1044,7 +1048,8 @@ static const struct snd_pcm_ops acp_dma_ops = {
 	.prepare = acp_dma_prepare,
 };
 
-static struct snd_soc_platform_driver acp_asoc_platform = {
+static struct snd_soc_component_driver acp_asoc_platform = {
+	.name = DRV_NAME,
 	.ops = &acp_dma_ops,
 	.pcm_new = acp_dma_new,
 };
@@ -1076,8 +1081,9 @@ static int acp_audio_probe(struct platform_device *pdev)
 	 * and device doesn't generate any interrupts.
 	 */
 
-	audio_drv_data->play_stream = NULL;
-	audio_drv_data->capture_stream = NULL;
+	audio_drv_data->play_i2ssp_stream = NULL;
+	audio_drv_data->capture_i2ssp_stream = NULL;
+
 	audio_drv_data->asic_type =  *pdata;
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -1102,7 +1108,8 @@ static int acp_audio_probe(struct platform_device *pdev)
 		return status;
 	}
 
-	status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
+	status = devm_snd_soc_register_component(&pdev->dev,
+						&acp_asoc_platform, NULL, 0);
 	if (status != 0) {
 		dev_err(&pdev->dev, "Fail to register ALSA platform device\n");
 		return status;
@@ -1123,7 +1130,6 @@ static int acp_audio_remove(struct platform_device *pdev)
 	status = acp_deinit(adata->acp_mmio);
 	if (status)
 		dev_err(&pdev->dev, "ACP Deinit failed status:%d\n", status);
-	snd_soc_unregister_platform(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	return 0;
@@ -1141,7 +1147,7 @@ static int acp_pcm_resume(struct device *dev)
 		return status;
 	}
 
-	if (adata->play_stream && adata->play_stream->runtime) {
+	if (adata->play_i2ssp_stream && adata->play_i2ssp_stream->runtime) {
 		/* For Stoney, Memory gating is disabled,i.e SRAM Banks
 		 * won't be turned off. The default state for SRAM banks is ON.
 		 * Setting SRAM bank state code skipped for STONEY platform.
@@ -1152,17 +1158,17 @@ static int acp_pcm_resume(struct device *dev)
 						true);
 		}
 		config_acp_dma(adata->acp_mmio,
-			adata->play_stream->runtime->private_data,
+			adata->play_i2ssp_stream->runtime->private_data,
 			adata->asic_type);
 	}
-	if (adata->capture_stream && adata->capture_stream->runtime) {
+	if (adata->capture_i2ssp_stream && adata->capture_i2ssp_stream->runtime) {
 		if (adata->asic_type != CHIP_STONEY) {
 			for (bank = 5; bank <= 8; bank++)
 				acp_set_sram_bank_state(adata->acp_mmio, bank,
 						true);
 		}
 		config_acp_dma(adata->acp_mmio,
-			adata->capture_stream->runtime->private_data,
+			adata->capture_i2ssp_stream->runtime->private_data,
 			adata->asic_type);
 	}
 	acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
index 941aed6bb364..b79b922b08a0 100644
--- a/sound/soc/amd/acp-rt5645.c
+++ b/sound/soc/amd/acp-rt5645.c
@@ -71,9 +71,9 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
 	struct snd_soc_card *card;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *codec;
 
-	codec = rtd->codec;
+	codec = rtd->codec_dai->component;
 	card = rtd->card;
 
 	ret = snd_soc_card_jack_new(card, "Headset Jack",
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index ecb458935d1e..27803b26fc35 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -84,14 +84,14 @@ struct audio_substream_data {
 	u16 num_of_pages;
 	u16 direction;
 	uint64_t size;
-	u64 renderbytescount;
-	u64 capturebytescount;
+	u64 i2ssp_renderbytescount;
+	u64 i2ssp_capturebytescount;
 	void __iomem *acp_mmio;
 };
 
 struct audio_drv_data {
-	struct snd_pcm_substream *play_stream;
-	struct snd_pcm_substream *capture_stream;
+	struct snd_pcm_substream *play_i2ssp_stream;
+	struct snd_pcm_substream *capture_i2ssp_stream;
 	void __iomem *acp_mmio;
 	u32 asic_type;
 };
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index ebabed69f0e6..9baaf6bc5fbd 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -32,6 +32,7 @@ struct atmel_classd {
 	struct regmap *regmap;
 	struct clk *pclk;
 	struct clk *gclk;
+	struct device *dev;
 	int irq;
 	const struct atmel_classd_pdata *pdata;
 };
@@ -165,7 +166,7 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
 	struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
 
 	if (params_physical_width(params) != 16) {
-		dev_err(rtd->platform->dev,
+		dev_err(dd->dev,
 			"only supports 16-bit audio data\n");
 		return -EINVAL;
 	}
@@ -247,9 +248,9 @@ static const char * const pwm_type[] = {
 	"Single ended", "Differential"
 };
 
-static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
+static int atmel_classd_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
 	struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
 	const struct atmel_classd_pdata *pdata = dd->pdata;
 	u32 mask, val;
@@ -283,16 +284,16 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
 		default:
 			val |= (CLASSD_MR_NOVR_VAL_10NS
 				<< CLASSD_MR_NOVR_VAL_SHIFT);
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				"non-overlapping value %d is invalid, the default value 10 is specified\n",
 				pdata->non_overlap_time);
 			break;
 		}
 	}
 
-	snd_soc_update_bits(codec, CLASSD_MR, mask, val);
+	snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
 
-	dev_info(codec->dev,
+	dev_info(component->dev,
 		"PWM modulation type is %s, non-overlapping is %s\n",
 		pwm_type[pdata->pwm_type],
 		pdata->non_overlap_enable?"enabled":"disabled");
@@ -300,21 +301,23 @@ static int atmel_classd_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int atmel_classd_codec_resume(struct snd_soc_codec *codec)
+static int atmel_classd_component_resume(struct snd_soc_component *component)
 {
-	struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
 	struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
 
 	return regcache_sync(dd->regmap);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_classd = {
-	.probe		= atmel_classd_codec_probe,
-	.resume		= atmel_classd_codec_resume,
-	.component_driver = {
-		.controls		= atmel_classd_snd_controls,
-		.num_controls		= ARRAY_SIZE(atmel_classd_snd_controls),
-	},
+static struct snd_soc_component_driver soc_component_dev_classd = {
+	.probe			= atmel_classd_component_probe,
+	.resume			= atmel_classd_component_resume,
+	.controls		= atmel_classd_snd_controls,
+	.num_controls		= ARRAY_SIZE(atmel_classd_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* codec dai component */
@@ -330,7 +333,7 @@ static int atmel_classd_codec_dai_startup(struct snd_pcm_substream *substream,
 static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
 	int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u32 mask, val;
 
 	mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK;
@@ -340,7 +343,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
 	else
 		val = 0;
 
-	snd_soc_update_bits(codec, CLASSD_MR, mask, val);
+	snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
 
 	return 0;
 }
@@ -379,7 +382,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int fs;
 	int i, best, best_val, cur_val, ret;
 	u32 mask, val;
@@ -397,7 +400,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	dev_dbg(codec->dev,
+	dev_dbg(component->dev,
 		"Selected SAMPLE_RATE of %dHz, GCLK_RATE of %ldHz\n",
 		sample_rates[best].rate, sample_rates[best].gclk_rate);
 
@@ -411,7 +414,7 @@ atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream,
 	val = (sample_rates[best].dsp_clk << CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT)
 	| (sample_rates[best].sample_rate << CLASSD_INTPMR_FRAME_SHIFT);
 
-	snd_soc_update_bits(codec, CLASSD_INTPMR, mask, val);
+	snd_soc_component_update_bits(component, CLASSD_INTPMR, mask, val);
 
 	return clk_prepare_enable(dd->gclk);
 }
@@ -429,9 +432,9 @@ atmel_classd_codec_dai_shutdown(struct snd_pcm_substream *substream,
 static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
 					struct snd_soc_dai *codec_dai)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
-	snd_soc_update_bits(codec, CLASSD_MR,
+	snd_soc_component_update_bits(component, CLASSD_MR,
 				CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK,
 				(CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
 				|(CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT));
@@ -442,7 +445,7 @@ static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream,
 static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
 					int cmd, struct snd_soc_dai *codec_dai)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u32 mask, val;
 
 	mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK;
@@ -463,7 +466,7 @@ static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, CLASSD_MR, mask, val);
+	snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
 
 	return 0;
 }
@@ -587,6 +590,7 @@ static int atmel_classd_probe(struct platform_device *pdev)
 	}
 
 	dd->phy_base = res->start;
+	dd->dev = dev;
 
 	dd->regmap = devm_regmap_init_mmio(dev, io_base,
 					&atmel_classd_regmap_config);
@@ -612,10 +616,10 @@ static int atmel_classd_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(dev, &soc_codec_dev_classd,
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_classd,
 					&atmel_classd_codec_dai, 1);
 	if (ret) {
-		dev_err(dev, "could not register codec: %d\n", ret);
+		dev_err(dev, "could not register component: %d\n", ret);
 		return ret;
 	}
 
@@ -643,13 +647,11 @@ static int atmel_classd_probe(struct platform_device *pdev)
 	return 0;
 
 unregister_codec:
-	snd_soc_unregister_codec(dev);
 	return ret;
 }
 
 static int atmel_classd_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 91b7069c3499..99ca23d527c9 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -393,7 +393,7 @@ static const struct snd_pcm_ops atmel_pcm_ops = {
 	.mmap		= atmel_pcm_mmap,
 };
 
-static struct snd_soc_platform_driver atmel_soc_platform = {
+static struct snd_soc_component_driver atmel_soc_platform = {
 	.ops		= &atmel_pcm_ops,
 	.pcm_new	= atmel_pcm_new,
 	.pcm_free	= atmel_pcm_free,
@@ -401,13 +401,13 @@ static struct snd_soc_platform_driver atmel_soc_platform = {
 
 int atmel_pcm_pdc_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(dev, &atmel_soc_platform);
+	return devm_snd_soc_register_component(dev, &atmel_soc_platform,
+					       NULL, 0);
 }
 EXPORT_SYMBOL(atmel_pcm_pdc_platform_register);
 
 void atmel_pcm_pdc_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(dev);
 }
 EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister);
 
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index 8e3d34be9e69..94f852574a44 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -32,6 +32,7 @@ struct atmel_pdmic {
 	struct regmap *regmap;
 	struct clk *pclk;
 	struct clk *gclk;
+	struct device *dev;
 	int irq;
 	struct snd_pcm_substream *substream;
 	const struct atmel_pdmic_pdata *pdata;
@@ -206,7 +207,7 @@ atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream,
 	ret = snd_hwparams_to_dma_slave_config(substream, params,
 					       slave_config);
 	if (ret) {
-		dev_err(rtd->platform->dev,
+		dev_err(dd->dev,
 			"hw params to dma slave configure failed\n");
 		return ret;
 	}
@@ -288,14 +289,14 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
 static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int dgain_val, scale_val;
 	int i;
 
-	dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
+	dgain_val = (snd_soc_component_read32(component, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
 		    >> PDMIC_DSPR1_DGAIN_SHIFT;
 
-	scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
+	scale_val = (snd_soc_component_read32(component, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
 		    >> PDMIC_DSPR0_SCALE_SHIFT;
 
 	for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) {
@@ -312,7 +313,7 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int max = mc->max;
 	unsigned int val;
 	int ret;
@@ -322,12 +323,12 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
 	if (val > max)
 		return -EINVAL;
 
-	ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
+	ret = snd_soc_component_update_bits(component, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
 			 mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT);
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
+	ret = snd_soc_component_update_bits(component, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
 			 mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT);
 	if (ret < 0)
 		return ret;
@@ -346,23 +347,25 @@ SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0,
 SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1),
 };
 
-static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
+static int atmel_pdmic_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
 	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
 
-	snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
+	snd_soc_component_update_bits(component, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
 		     (u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT));
 
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_pdmic = {
-	.probe		= atmel_pdmic_codec_probe,
-	.component_driver = {
-		.controls		= atmel_pdmic_snd_controls,
-		.num_controls		= ARRAY_SIZE(atmel_pdmic_snd_controls),
-	},
+static struct snd_soc_component_driver soc_component_dev_pdmic = {
+	.probe			= atmel_pdmic_component_probe,
+	.controls		= atmel_pdmic_snd_controls,
+	.num_controls		= ARRAY_SIZE(atmel_pdmic_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* codec dai component */
@@ -375,7 +378,7 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int rate_min = substream->runtime->hw.rate_min;
 	unsigned int rate_max = substream->runtime->hw.rate_max;
 	int fs = params_rate(params);
@@ -385,13 +388,13 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
 	u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal;
 
 	if (params_channels(params) != 1) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"only supports one channel\n");
 		return -EINVAL;
 	}
 
 	if ((fs < rate_min) || (fs > rate_max)) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"sample rate is %dHz, min rate is %dHz, max rate is %dHz\n",
 			fs, rate_min, rate_max);
 
@@ -436,10 +439,10 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
 		mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT;
 	}
 
-	snd_soc_update_bits(codec, PDMIC_MR,
+	snd_soc_component_update_bits(component, PDMIC_MR,
 		PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val);
 
-	snd_soc_update_bits(codec, PDMIC_DSPR0,
+	snd_soc_component_update_bits(component, PDMIC_DSPR0,
 		PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val);
 
 	return 0;
@@ -448,9 +451,9 @@ atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
 static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
 					struct snd_soc_dai *codec_dai)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
-	snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+	snd_soc_component_update_bits(component, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
 			    PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
 
 	return 0;
@@ -459,7 +462,7 @@ static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
 static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
 					int cmd, struct snd_soc_dai *codec_dai)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u32 val;
 
 	switch (cmd) {
@@ -477,7 +480,7 @@ static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
+	snd_soc_component_update_bits(component, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
 
 	return 0;
 }
@@ -596,6 +599,7 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	dd->pdata = pdata;
+	dd->dev = dev;
 
 	dd->irq = platform_get_irq(pdev, 0);
 	if (dd->irq < 0) {
@@ -679,10 +683,10 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 	/* register codec and codec dai */
 	atmel_pdmic_codec_dai.capture.rate_min = rate_min;
 	atmel_pdmic_codec_dai.capture.rate_max = rate_max;
-	ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic,
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_pdmic,
 				     &atmel_pdmic_codec_dai, 1);
 	if (ret) {
-		dev_err(dev, "could not register codec: %d\n", ret);
+		dev_err(dev, "could not register component: %d\n", ret);
 		return ret;
 	}
 
@@ -710,13 +714,11 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
 	return 0;
 
 unregister_codec:
-	snd_soc_unregister_codec(dev);
 	return ret;
 }
 
 static int atmel_pdmic_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 6a035ca0f521..fb650659c3a3 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -32,6 +32,8 @@
 
 /*#define PCM_DEBUG*/
 
+#define DRV_NAME "dbdma2"
+
 #define MSG(x...)	printk(KERN_INFO "au1xpsc_pcm: " x)
 #ifdef PCM_DEBUG
 #define DBG		MSG
@@ -187,8 +189,8 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
 static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
 {
 	struct snd_soc_pcm_runtime *rtd = ss->private_data;
-	struct au1xpsc_audio_dmadata *pcd =
-				snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component);
 	return &pcd[ss->stream];
 }
 
@@ -327,7 +329,8 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 }
 
 /* au1xpsc audio platform */
-static struct snd_soc_platform_driver au1xpsc_soc_platform = {
+static struct snd_soc_component_driver au1xpsc_soc_component = {
+	.name		= DRV_NAME,
 	.ops		= &au1xpsc_pcm_ops,
 	.pcm_new	= au1xpsc_pcm_new,
 };
@@ -344,8 +347,8 @@ static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, dmadata);
 
-	return devm_snd_soc_register_platform(&pdev->dev,
-					      &au1xpsc_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev,
+					&au1xpsc_soc_component, NULL, 0);
 }
 
 static struct platform_driver au1xpsc_pcm_driver = {
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index 19457e2b351e..efff1e293a1b 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -21,6 +21,8 @@
 
 #include "psc.h"
 
+#define DRV_NAME "au1x_dma"
+
 struct pcm_period {
 	u32 start;
 	u32 relative_end;	/* relative to start of buffer */
@@ -174,7 +176,8 @@ static const struct snd_pcm_hardware alchemy_pcm_hardware = {
 static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
 {
 	struct snd_soc_pcm_runtime *rtd = ss->private_data;
-	return snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	return snd_soc_component_get_drvdata(component);
 }
 
 static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
@@ -297,7 +300,8 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
+static struct snd_soc_component_driver alchemy_pcm_soc_component = {
+	.name		= DRV_NAME,
 	.ops		= &alchemy_pcm_ops,
 	.pcm_new	= alchemy_pcm_new,
 };
@@ -312,8 +316,8 @@ static int alchemy_pcm_drvprobe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, ctx);
 
-	return devm_snd_soc_register_platform(&pdev->dev,
-					      &alchemy_pcm_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev,
+					&alchemy_pcm_soc_component, NULL, 0);
 }
 
 static struct platform_driver alchemy_pcmdma_driver = {
diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index d616e096462e..123ecf5479d7 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -820,7 +820,7 @@ static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static struct snd_soc_platform_driver cygnus_soc_platform = {
+static struct snd_soc_component_driver cygnus_soc_platform = {
 	.ops		= &cygnus_pcm_ops,
 	.pcm_new	= cygnus_dma_new,
 	.pcm_free	= cygnus_dma_free_dma_buffers,
@@ -840,7 +840,8 @@ int cygnus_soc_platform_register(struct device *dev,
 		return rc;
 	}
 
-	rc = snd_soc_register_platform(dev, &cygnus_soc_platform);
+	rc = devm_snd_soc_register_component(dev, &cygnus_soc_platform,
+					     NULL, 0);
 	if (rc) {
 		dev_err(dev, "%s failed\n", __func__);
 		return rc;
@@ -851,8 +852,6 @@ int cygnus_soc_platform_register(struct device *dev,
 
 int cygnus_soc_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 8c1d1983b8f9..08bceb519c29 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -453,7 +453,7 @@ static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
+static struct snd_soc_component_driver bf5xx_ac97_soc_component = {
 	.ops			= &bf5xx_pcm_ac97_ops,
 	.pcm_new	= bf5xx_pcm_ac97_new,
 	.pcm_free	= bf5xx_pcm_free_dma_buffers,
@@ -461,8 +461,8 @@ static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
 
 static int bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev,
-					      &bf5xx_ac97_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev,
+					&bf5xx_ac97_soc_component, NULL, 0);
 }
 
 static struct platform_driver bf5xx_pcm_driver = {
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 51cae76f14e6..6712b01dabd1 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -347,15 +347,15 @@ static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
 				SNDRV_DMA_TYPE_DEV, card->dev, size, size);
 }
 
-static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
+static struct snd_soc_component_driver bf5xx_i2s_soc_component = {
 	.ops		= &bf5xx_pcm_i2s_ops,
 	.pcm_new	= bf5xx_pcm_i2s_new,
 };
 
 static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev,
-					      &bf5xx_i2s_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev,
+					&bf5xx_i2s_soc_component, NULL, 0);
 }
 
 static struct platform_driver bfin_i2s_pcm_driver = {
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index be8ea723dff9..3c3ef422853d 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -139,7 +139,7 @@ struct pm860x_priv {
 	unsigned int		pcmclk;
 	unsigned int		dir;
 	unsigned int		filter;
-	struct snd_soc_codec	*codec;
+	struct snd_soc_component *component;
 	struct i2c_client	*i2c;
 	struct regmap		*regmap;
 	struct pm860x_chip	*chip;
@@ -272,15 +272,15 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	int val[2], val2[2], i;
 
-	val[0] = snd_soc_read(codec, reg) & 0x3f;
-	val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
-	val2[0] = snd_soc_read(codec, reg2) & 0x3f;
-	val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
+	val[0] = snd_soc_component_read32(component, reg) & 0x3f;
+	val[1] = (snd_soc_component_read32(component, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+	val2[0] = snd_soc_component_read32(component, reg2) & 0x3f;
+	val2[1] = (snd_soc_component_read32(component, PM860X_SIDETONE_SHIFT)) & 0xf;
 
 	for (i = 0; i < ARRAY_SIZE(st_table); i++) {
 		if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
@@ -296,7 +296,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	int err;
@@ -308,18 +308,18 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
 	if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
 		return -EINVAL;
 
-	err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
+	err = snd_soc_component_update_bits(component, reg, 0x3f, st_table[val].m);
 	if (err < 0)
 		return err;
-	err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
+	err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0xf0,
 				  st_table[val].n << 4);
 	if (err < 0)
 		return err;
 
-	err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
+	err = snd_soc_component_update_bits(component, reg2, 0x3f, st_table[val2].m);
 	if (err < 0)
 		return err;
-	err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
+	err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0x0f,
 				  st_table[val2].n);
 	return err;
 }
@@ -329,15 +329,15 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	unsigned int shift = mc->shift;
 	int max = mc->max, val, val2;
 	unsigned int mask = (1 << fls(max)) - 1;
 
-	val = snd_soc_read(codec, reg) >> shift;
-	val2 = snd_soc_read(codec, reg2) >> shift;
+	val = snd_soc_component_read32(component, reg) >> shift;
+	val2 = snd_soc_component_read32(component, reg2) >> shift;
 	ucontrol->value.integer.value[0] = (max - val) & mask;
 	ucontrol->value.integer.value[1] = (max - val2) & mask;
 
@@ -349,7 +349,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	unsigned int shift = mc->shift;
@@ -365,11 +365,11 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 	val = val << shift;
 	val2 = val2 << shift;
 
-	err = snd_soc_update_bits(codec, reg, val_mask, val);
+	err = snd_soc_component_update_bits(component, reg, val_mask, val);
 	if (err < 0)
 		return err;
 
-	err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+	err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
 	return err;
 }
 
@@ -382,7 +382,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	/*
 	 * In order to avoid current on the load, mute power-on and power-off
@@ -390,8 +390,8 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 	 * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
 	 * finished.
 	 */
-	snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
-	snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+	snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+	snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
 			    RSYNC_CHANGE, RSYNC_CHANGE);
 	return 0;
 }
@@ -399,7 +399,7 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int dac = 0;
 	int data;
 
@@ -412,28 +412,28 @@ static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
 		if (dac) {
 			/* Auto mute in power-on sequence. */
 			dac |= MODULATOR;
-			snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+			snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
 					    DAC_MUTE, DAC_MUTE);
-			snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+			snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
 					    RSYNC_CHANGE, RSYNC_CHANGE);
 			/* update dac */
-			snd_soc_update_bits(codec, PM860X_DAC_EN_2,
+			snd_soc_component_update_bits(component, PM860X_DAC_EN_2,
 					    dac, dac);
 		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		if (dac) {
 			/* Auto mute in power-off sequence. */
-			snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+			snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
 					    DAC_MUTE, DAC_MUTE);
-			snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+			snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
 					    RSYNC_CHANGE, RSYNC_CHANGE);
 			/* update dac */
-			data = snd_soc_read(codec, PM860X_DAC_EN_2);
+			data = snd_soc_component_read32(component, PM860X_DAC_EN_2);
 			data &= ~dac;
 			if (!(data & (DAC_LEFT | DAC_RIGHT)))
 				data &= ~MODULATOR;
-			snd_soc_write(codec, PM860X_DAC_EN_2, data);
+			snd_soc_component_write(component, PM860X_DAC_EN_2, data);
 		}
 		break;
 	}
@@ -922,13 +922,13 @@ static const struct snd_soc_dapm_route pm860x_dapm_routes[] = {
  */
 static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
 
 	if (mute)
 		data = mask;
-	snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
-	snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+	snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, mask, data);
+	snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
 			    RSYNC_CHANGE, RSYNC_CHANGE);
 	return 0;
 }
@@ -937,7 +937,7 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned char inf = 0, mask = 0;
 
 	/* bit size */
@@ -952,7 +952,7 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 	mask |= PCM_INF2_18WL;
-	snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+	snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
 
 	/* sample rate */
 	switch (params_rate(params)) {
@@ -971,7 +971,7 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
+	snd_soc_component_update_bits(component, PM860X_PCM_RATE, 0x0f, inf);
 
 	return 0;
 }
@@ -979,8 +979,8 @@ static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
 static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
 				  unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 	unsigned char inf = 0, mask = 0;
 	int ret = -EINVAL;
 
@@ -1012,15 +1012,15 @@ static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	mask |= PCM_MODE_MASK;
 	if (ret)
 		return ret;
-	snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+	snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
 	return 0;
 }
 
 static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 
 	if (dir == PM860X_CLK_DIR_OUT)
 		pm860x->dir = PM860X_CLK_DIR_OUT;
@@ -1034,7 +1034,7 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned char inf;
 
 	/* bit size */
@@ -1048,7 +1048,7 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
 
 	/* sample rate */
 	switch (params_rate(params)) {
@@ -1076,7 +1076,7 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
+	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_4, 0xf, inf);
 
 	return 0;
 }
@@ -1084,8 +1084,8 @@ static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
 static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
 				  unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 	unsigned char inf = 0, mask = 0;
 
 	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
@@ -1116,14 +1116,14 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 	mask |= PCM_MODE_MASK;
-	snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
+	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, mask, inf);
 	return 0;
 }
 
-static int pm860x_set_bias_level(struct snd_soc_codec *codec,
+static int pm860x_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 	int data;
 
 	switch (level) {
@@ -1134,7 +1134,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Enable Audio PLL & Audio section */
 			data = AUDIO_PLL | AUDIO_SECTION_ON;
 			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
@@ -1216,7 +1216,7 @@ static struct snd_soc_dai_driver pm860x_dai[] = {
 	},
 };
 
-static irqreturn_t pm860x_codec_handler(int irq, void *data)
+static irqreturn_t pm860x_component_handler(int irq, void *data)
 {
 	struct pm860x_priv *pm860x = data;
 	int status, shrt, report = 0, mic_report = 0;
@@ -1230,7 +1230,7 @@ static irqreturn_t pm860x_codec_handler(int irq, void *data)
 #ifndef CONFIG_SND_SOC_88PM860X_MODULE
 	if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 |
 		      SHORT_LO1 | SHORT_LO2))
-		trace_snd_soc_jack_irq(dev_name(pm860x->codec->dev));
+		trace_snd_soc_jack_irq(dev_name(pm860x->component->dev));
 #endif
 
 	if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
@@ -1256,17 +1256,17 @@ static irqreturn_t pm860x_codec_handler(int irq, void *data)
 		snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
 				    SND_JACK_MICROPHONE);
 
-	dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
+	dev_dbg(pm860x->component->dev, "headphone report:0x%x, mask:%x\n",
 		report, mask);
-	dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
+	dev_dbg(pm860x->component->dev, "microphone report:0x%x\n", mic_report);
 	return IRQ_HANDLED;
 }
 
-int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
+int pm860x_hs_jack_detect(struct snd_soc_component *component,
 			  struct snd_soc_jack *jack,
 			  int det, int hook, int hs_shrt, int lo_shrt)
 {
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 	int data;
 
 	pm860x->det.hp_jack = jack;
@@ -1290,15 +1290,15 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
 	}
 
 	/* sync status */
-	pm860x_codec_handler(0, pm860x);
+	pm860x_component_handler(0, pm860x);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
 
-int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
+int pm860x_mic_jack_detect(struct snd_soc_component *component,
 			   struct snd_soc_jack *jack, int det)
 {
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 
 	pm860x->det.mic_jack = jack;
 	pm860x->det.mic_det = det;
@@ -1308,25 +1308,25 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
 				MICDET_MASK, MICDET_MASK);
 
 	/* sync status */
-	pm860x_codec_handler(0, pm860x);
+	pm860x_component_handler(0, pm860x);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
 
-static int pm860x_probe(struct snd_soc_codec *codec)
+static int pm860x_probe(struct snd_soc_component *component)
 {
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 	int i, ret;
 
-	pm860x->codec = codec;
-	snd_soc_codec_init_regmap(codec,  pm860x->regmap);
+	pm860x->component = component;
+	snd_soc_component_init_regmap(component,  pm860x->regmap);
 
 	for (i = 0; i < 4; i++) {
 		ret = request_threaded_irq(pm860x->irq[i], NULL,
-					   pm860x_codec_handler, IRQF_ONESHOT,
+					   pm860x_component_handler, IRQF_ONESHOT,
 					   pm860x->name[i], pm860x);
 		if (ret < 0) {
-			dev_err(codec->dev, "Failed to request IRQ!\n");
+			dev_err(component->dev, "Failed to request IRQ!\n");
 			goto out;
 		}
 	}
@@ -1339,29 +1339,29 @@ static int pm860x_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int pm860x_remove(struct snd_soc_codec *codec)
+static void pm860x_remove(struct snd_soc_component *component)
 {
-	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 3; i >= 0; i--)
 		free_irq(pm860x->irq[i], pm860x);
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_pm860x = {
-	.probe		= pm860x_probe,
-	.remove		= pm860x_remove,
-	.set_bias_level	= pm860x_set_bias_level,
-
-	.component_driver = {
-		.controls		= pm860x_snd_controls,
-		.num_controls		= ARRAY_SIZE(pm860x_snd_controls),
-		.dapm_widgets		= pm860x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pm860x_dapm_widgets),
-		.dapm_routes		= pm860x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pm860x_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_pm860x = {
+	.probe			= pm860x_probe,
+	.remove			= pm860x_remove,
+	.set_bias_level		= pm860x_set_bias_level,
+	.controls		= pm860x_snd_controls,
+	.num_controls		= ARRAY_SIZE(pm860x_snd_controls),
+	.dapm_widgets		= pm860x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pm860x_dapm_widgets),
+	.dapm_routes		= pm860x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pm860x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int pm860x_codec_probe(struct platform_device *pdev)
@@ -1393,10 +1393,11 @@ static int pm860x_codec_probe(struct platform_device *pdev)
 		strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
 	}
 
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				     &soc_component_dev_pm860x,
 				     pm860x_dai, ARRAY_SIZE(pm860x_dai));
 	if (ret) {
-		dev_err(&pdev->dev, "Failed to register codec\n");
+		dev_err(&pdev->dev, "Failed to register component\n");
 		return -EINVAL;
 	}
 	return ret;
@@ -1404,7 +1405,6 @@ static int pm860x_codec_probe(struct platform_device *pdev)
 
 static int pm860x_codec_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
index f7282f4f4a79..33aa9ff3463f 100644
--- a/sound/soc/codecs/88pm860x-codec.h
+++ b/sound/soc/codecs/88pm860x-codec.h
@@ -88,9 +88,9 @@
 #define PM860X_SHORT_LINEOUT		(1 << 4)
 #define PM860X_DET_MASK			0x1F
 
-extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+extern int pm860x_hs_jack_detect(struct snd_soc_component *, struct snd_soc_jack *,
 				 int, int, int, int);
-extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+extern int pm860x_mic_jack_detect(struct snd_soc_component *, struct snd_soc_jack *,
 				  int);
 
 #endif	/* __88PM860X_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 2b331f7266ab..80f4deb29685 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_ADAU7002
 	select SND_SOC_ADS117X
 	select SND_SOC_AK4104 if SPI_MASTER
+	select SND_SOC_AK4458 if I2C
 	select SND_SOC_AK4535 if I2C
 	select SND_SOC_AK4554
 	select SND_SOC_AK4613 if I2C
@@ -42,6 +43,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_AK5386
+	select SND_SOC_AK5558 if I2C
 	select SND_SOC_ALC5623 if I2C
 	select SND_SOC_ALC5632 if I2C
 	select SND_SOC_BT_SCO
@@ -375,6 +377,11 @@ config SND_SOC_AK4104
 	tristate "AKM AK4104 CODEC"
 	depends on SPI_MASTER
 
+config SND_SOC_AK4458
+	tristate "AKM AK4458 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+
 config SND_SOC_AK4535
 	tristate
 
@@ -398,6 +405,11 @@ config SND_SOC_AK4671
 config SND_SOC_AK5386
 	tristate "AKM AK5638 CODEC"
 
+config SND_SOC_AK5558
+	tristate "AKM AK5558 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+
 config SND_SOC_ALC5623
        tristate "Realtek ALC5623 CODEC"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index da1571336f1e..cea7a6993929 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o
 snd-soc-adav803-objs := adav803.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
+snd-soc-ak4458-objs := ak4458.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4554-objs := ak4554.o
 snd-soc-ak4613-objs := ak4613.o
@@ -34,6 +35,7 @@ snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
+snd-soc-ak5558-objs := ak5558.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-cq93vc-objs := cq93vc.o
@@ -270,6 +272,7 @@ obj-$(CONFIG_SND_SOC_ADAV801)  += snd-soc-adav801.o
 obj-$(CONFIG_SND_SOC_ADAV803)  += snd-soc-adav803.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
+obj-$(CONFIG_SND_SOC_AK4458)	+= snd-soc-ak4458.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4554)	+= snd-soc-ak4554.o
 obj-$(CONFIG_SND_SOC_AK4613)	+= snd-soc-ak4613.o
@@ -277,6 +280,7 @@ obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_AK5386)	+= snd-soc-ak5386.o
+obj-$(CONFIG_SND_SOC_AK5558)	+= snd-soc-ak5558.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
@@ -387,7 +391,6 @@ obj-$(CONFIG_SND_SOC_SIGMADSP)	+= snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o
 obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP)	+= snd-soc-sigmadsp-regmap.o
 obj-$(CONFIG_SND_SOC_SI476X)	+= snd-soc-si476x.o
-obj-$(CONFIG_SND_SOC_SN95031)	+=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif-rx.o snd-soc-spdif-tx.o
 obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
 obj-$(CONFIG_SND_SOC_SSM2518)	+= snd-soc-ssm2518.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 006627b8c3a8..03bbbcd3b6c1 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1037,86 +1037,86 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = {
 };
 
 /* ANC FIR-coefficients configuration sequence */
-static void anc_fir(struct snd_soc_codec *codec,
+static void anc_fir(struct snd_soc_component *component,
 		unsigned int bnk, unsigned int par, unsigned int val)
 {
 	if (par == 0 && bnk == 0)
-		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 			BIT(AB8500_ANCCONF1_ANCFIRUPDATE),
 			BIT(AB8500_ANCCONF1_ANCFIRUPDATE));
 
-	snd_soc_write(codec, AB8500_ANCCONF5, val >> 8 & 0xff);
-	snd_soc_write(codec, AB8500_ANCCONF6, val &  0xff);
+	snd_soc_component_write(component, AB8500_ANCCONF5, val >> 8 & 0xff);
+	snd_soc_component_write(component, AB8500_ANCCONF6, val &  0xff);
 
 	if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1)
-		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 			BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0);
 }
 
 /* ANC IIR-coefficients configuration sequence */
-static void anc_iir(struct snd_soc_codec *codec, unsigned int bnk,
+static void anc_iir(struct snd_soc_component *component, unsigned int bnk,
 		unsigned int par, unsigned int val)
 {
 	if (par == 0) {
 		if (bnk == 0) {
-			snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 					BIT(AB8500_ANCCONF1_ANCIIRINIT),
 					BIT(AB8500_ANCCONF1_ANCIIRINIT));
 			usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
-			snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 					BIT(AB8500_ANCCONF1_ANCIIRINIT), 0);
 			usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
 		} else {
-			snd_soc_update_bits(codec, AB8500_ANCCONF1,
+			snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 					BIT(AB8500_ANCCONF1_ANCIIRUPDATE),
 					BIT(AB8500_ANCCONF1_ANCIIRUPDATE));
 		}
 	} else if (par > 3) {
-		snd_soc_write(codec, AB8500_ANCCONF7, 0);
-		snd_soc_write(codec, AB8500_ANCCONF8, val >> 16 & 0xff);
+		snd_soc_component_write(component, AB8500_ANCCONF7, 0);
+		snd_soc_component_write(component, AB8500_ANCCONF8, val >> 16 & 0xff);
 	}
 
-	snd_soc_write(codec, AB8500_ANCCONF7, val >> 8 & 0xff);
-	snd_soc_write(codec, AB8500_ANCCONF8, val & 0xff);
+	snd_soc_component_write(component, AB8500_ANCCONF7, val >> 8 & 0xff);
+	snd_soc_component_write(component, AB8500_ANCCONF8, val & 0xff);
 
 	if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1)
-		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 			BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0);
 }
 
 /* ANC IIR-/FIR-coefficients configuration sequence */
-static void anc_configure(struct snd_soc_codec *codec,
+static void anc_configure(struct snd_soc_component *component,
 			bool apply_fir, bool apply_iir)
 {
-	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
 	unsigned int bnk, par, val;
 
-	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+	dev_dbg(component->dev, "%s: Enter.\n", __func__);
 
 	if (apply_fir)
-		snd_soc_update_bits(codec, AB8500_ANCCONF1,
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 			BIT(AB8500_ANCCONF1_ENANC), 0);
 
-	snd_soc_update_bits(codec, AB8500_ANCCONF1,
+	snd_soc_component_update_bits(component, AB8500_ANCCONF1,
 		BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC));
 
 	if (apply_fir)
 		for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
 			for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) {
-				val = snd_soc_read(codec,
+				val = snd_soc_component_read32(component,
 						drvdata->anc_fir_values[par]);
-				anc_fir(codec, bnk, par, val);
+				anc_fir(component, bnk, par, val);
 			}
 
 	if (apply_iir)
 		for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
 			for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) {
-				val = snd_soc_read(codec,
+				val = snd_soc_component_read32(component,
 						drvdata->anc_iir_values[par]);
-				anc_iir(codec, bnk, par, val);
+				anc_iir(component, bnk, par, val);
 			}
 
-	dev_dbg(codec->dev, "%s: Exit.\n", __func__);
+	dev_dbg(component->dev, "%s: Exit.\n", __func__);
 }
 
 /*
@@ -1126,8 +1126,8 @@ static void anc_configure(struct snd_soc_codec *codec,
 static int sid_status_control_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
 
 	mutex_lock(&drvdata->ctrl_lock);
 	ucontrol->value.enumerated.item[0] = drvdata->sid_status;
@@ -1140,15 +1140,15 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
 static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
 	unsigned int param, sidconf, val;
 	int status = 1;
 
-	dev_dbg(codec->dev, "%s: Enter\n", __func__);
+	dev_dbg(component->dev, "%s: Enter\n", __func__);
 
 	if (ucontrol->value.enumerated.item[0] != SID_APPLY_FIR) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: ERROR: This control supports '%s' only!\n",
 			__func__, enum_sid_state[SID_APPLY_FIR]);
 		return -EIO;
@@ -1156,10 +1156,10 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 
 	mutex_lock(&drvdata->ctrl_lock);
 
-	sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
+	sidconf = snd_soc_component_read32(component, AB8500_SIDFIRCONF);
 	if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
 		if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) {
-			dev_err(codec->dev, "%s: Sidetone busy while off!\n",
+			dev_err(component->dev, "%s: Sidetone busy while off!\n",
 				__func__);
 			status = -EPERM;
 		} else {
@@ -1168,18 +1168,18 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 		goto out;
 	}
 
-	snd_soc_write(codec, AB8500_SIDFIRADR, 0);
+	snd_soc_component_write(component, AB8500_SIDFIRADR, 0);
 
 	for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) {
-		val = snd_soc_read(codec, drvdata->sid_fir_values[param]);
-		snd_soc_write(codec, AB8500_SIDFIRCOEF1, val >> 8 & 0xff);
-		snd_soc_write(codec, AB8500_SIDFIRCOEF2, val & 0xff);
+		val = snd_soc_component_read32(component, drvdata->sid_fir_values[param]);
+		snd_soc_component_write(component, AB8500_SIDFIRCOEF1, val >> 8 & 0xff);
+		snd_soc_component_write(component, AB8500_SIDFIRCOEF2, val & 0xff);
 	}
 
-	snd_soc_update_bits(codec, AB8500_SIDFIRADR,
+	snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
 		BIT(AB8500_SIDFIRADR_FIRSIDSET),
 		BIT(AB8500_SIDFIRADR_FIRSIDSET));
-	snd_soc_update_bits(codec, AB8500_SIDFIRADR,
+	snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
 		BIT(AB8500_SIDFIRADR_FIRSIDSET), 0);
 
 	drvdata->sid_status = SID_FIR_CONFIGURED;
@@ -1187,7 +1187,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 out:
 	mutex_unlock(&drvdata->ctrl_lock);
 
-	dev_dbg(codec->dev, "%s: Exit\n", __func__);
+	dev_dbg(component->dev, "%s: Exit\n", __func__);
 
 	return status;
 }
@@ -1195,8 +1195,8 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
 static int anc_status_control_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
 
 	mutex_lock(&drvdata->ctrl_lock);
 	ucontrol->value.enumerated.item[0] = drvdata->anc_status;
@@ -1208,10 +1208,10 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
 static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
-	struct device *dev = codec->dev;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
+	struct device *dev = component->dev;
 	bool apply_fir, apply_iir;
 	unsigned int req;
 	int status;
@@ -1244,7 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
 	}
 	snd_soc_dapm_sync(dapm);
 
-	anc_configure(codec, apply_fir, apply_iir);
+	anc_configure(component, apply_fir, apply_iir);
 
 	if (apply_fir) {
 		if (drvdata->anc_status == ANC_IIR_CONFIGURED)
@@ -1291,8 +1291,8 @@ static int filter_control_info(struct snd_kcontrol *kcontrol,
 static int filter_control_get(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
 	struct filter_control *fc =
 			(struct filter_control *)kcontrol->private_value;
 	unsigned int i;
@@ -1308,8 +1308,8 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
 static int filter_control_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
 	struct filter_control *fc =
 			(struct filter_control *)kcontrol->private_value;
 	unsigned int i;
@@ -1926,11 +1926,11 @@ enum ab8500_filter {
  * Extended interface for codec-driver
  */
 
-static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
+static int ab8500_audio_init_audioblock(struct snd_soc_component *component)
 {
 	int status;
 
-	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+	dev_dbg(component->dev, "%s: Enter.\n", __func__);
 
 	/* Reset audio-registers and disable 32kHz-clock output 2 */
 	status = ab8500_sysctrl_write(AB8500_STW4500CTRL3,
@@ -1943,26 +1943,26 @@ static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
+static int ab8500_audio_setup_mics(struct snd_soc_component *component,
 			struct amic_settings *amics)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	u8 value8;
 	unsigned int value;
 	int status;
 	const struct snd_soc_dapm_route *route;
 
-	dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+	dev_dbg(component->dev, "%s: Enter.\n", __func__);
 
 	/* Set DMic-clocks to outputs */
-	status = abx500_get_register_interruptible(codec->dev, AB8500_MISC,
+	status = abx500_get_register_interruptible(component->dev, AB8500_MISC,
 						AB8500_GPIO_DIR4_REG,
 						&value8);
 	if (status < 0)
 		return status;
 	value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
 		GPIO31_DIR_OUTPUT;
-	status = abx500_set_register_interruptible(codec->dev,
+	status = abx500_set_register_interruptible(component->dev,
 						AB8500_MISC,
 						AB8500_GPIO_DIR4_REG,
 						value);
@@ -1970,41 +1970,41 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
 		return status;
 
 	/* Attach regulators to AMic DAPM-paths */
-	dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
+	dev_dbg(component->dev, "%s: Mic 1a regulator: %s\n", __func__,
 		amic_micbias_str(amics->mic1a_micbias));
 	route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
 	status = snd_soc_dapm_add_routes(dapm, route, 1);
-	dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
+	dev_dbg(component->dev, "%s: Mic 1b regulator: %s\n", __func__,
 		amic_micbias_str(amics->mic1b_micbias));
 	route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
 	status |= snd_soc_dapm_add_routes(dapm, route, 1);
-	dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
+	dev_dbg(component->dev, "%s: Mic 2 regulator: %s\n", __func__,
 		amic_micbias_str(amics->mic2_micbias));
 	route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
 	status |= snd_soc_dapm_add_routes(dapm, route, 1);
 	if (status < 0) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
 			__func__, status);
 		return status;
 	}
 
 	/* Set AMic-configuration */
-	dev_dbg(codec->dev, "%s: Mic 1 mic-type: %s\n", __func__,
+	dev_dbg(component->dev, "%s: Mic 1 mic-type: %s\n", __func__,
 		amic_type_str(amics->mic1_type));
-	snd_soc_update_bits(codec, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX,
+	snd_soc_component_update_bits(component, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX,
 			amics->mic1_type == AMIC_TYPE_DIFFERENTIAL ?
 				0 : AB8500_ANAGAINX_ENSEMICX);
-	dev_dbg(codec->dev, "%s: Mic 2 mic-type: %s\n", __func__,
+	dev_dbg(component->dev, "%s: Mic 2 mic-type: %s\n", __func__,
 		amic_type_str(amics->mic2_type));
-	snd_soc_update_bits(codec, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX,
+	snd_soc_component_update_bits(component, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX,
 			amics->mic2_type == AMIC_TYPE_DIFFERENTIAL ?
 				0 : AB8500_ANAGAINX_ENSEMICX);
 
 	return 0;
 }
 
-static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec,
+static int ab8500_audio_set_ear_cmv(struct snd_soc_component *component,
 				enum ear_cm_voltage ear_cmv)
 {
 	char *cmv_str;
@@ -2023,14 +2023,14 @@ static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec,
 		cmv_str = "1.58V";
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: Unknown earpiece CM-voltage (%d)!\n",
 			__func__, (int)ear_cmv);
 		return -EINVAL;
 	}
-	dev_dbg(codec->dev, "%s: Earpiece CM-voltage: %s\n", __func__,
+	dev_dbg(component->dev, "%s: Earpiece CM-voltage: %s\n", __func__,
 		cmv_str);
-	snd_soc_update_bits(codec, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM,
+	snd_soc_component_update_bits(component, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM,
 			ear_cmv);
 
 	return 0;
@@ -2040,7 +2040,7 @@ static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
 				unsigned int delay)
 {
 	unsigned int mask, val;
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	mask = BIT(AB8500_DIGIFCONF2_IF0DEL);
 	val = 0;
@@ -2052,21 +2052,21 @@ static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
 		val |= BIT(AB8500_DIGIFCONF2_IF0DEL);
 		break;
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupported bit-delay (0x%x)!\n",
 			__func__, delay);
 		return -EINVAL;
 	}
 
-	dev_dbg(dai->codec->dev, "%s: IF0 Bit-delay: %d bits.\n",
+	dev_dbg(dai->component->dev, "%s: IF0 Bit-delay: %d bits.\n",
 		__func__, delay);
-	snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
 
 	return 0;
 }
 
 /* Gates clocking according format mask */
-static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec,
+static int ab8500_codec_set_dai_clock_gate(struct snd_soc_component *component,
 					unsigned int fmt)
 {
 	unsigned int mask;
@@ -2079,22 +2079,22 @@ static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec,
 
 	switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
 	case SND_SOC_DAIFMT_CONT: /* continuous clock */
-		dev_dbg(codec->dev, "%s: IF0 Clock is continuous.\n",
+		dev_dbg(component->dev, "%s: IF0 Clock is continuous.\n",
 			__func__);
 		val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
 		break;
 	case SND_SOC_DAIFMT_GATED: /* clock is gated */
-		dev_dbg(codec->dev, "%s: IF0 Clock is gated.\n",
+		dev_dbg(component->dev, "%s: IF0 Clock is gated.\n",
 			__func__);
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: ERROR: Unsupported clock mask (0x%x)!\n",
 			__func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF1, mask, val);
 
 	return 0;
 }
@@ -2103,10 +2103,10 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	unsigned int mask;
 	unsigned int val;
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int status;
 
-	dev_dbg(codec->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt);
+	dev_dbg(component->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt);
 
 	mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) |
 			BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) |
@@ -2116,32 +2116,32 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0 Master-mode: AB8500 master.\n", __func__);
 		val |= BIT(AB8500_DIGIFCONF3_IF0MASTER);
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0 Master-mode: AB8500 slave.\n", __func__);
 		break;
 	case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
 	case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: The device is either a master or a slave.\n",
 			__func__);
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupporter master mask 0x%x\n",
 			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF3, mask, val);
 
 	/* Set clock gating */
-	status = ab8500_codec_set_dai_clock_gate(codec, fmt);
+	status = ab8500_codec_set_dai_clock_gate(component, fmt);
 	if (status) {
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Failed to set clock gate (%d).\n",
 			__func__, status);
 		return status;
@@ -2157,27 +2157,27 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S: /* I2S mode */
-		dev_dbg(dai->codec->dev, "%s: IF0 Protocol: I2S\n", __func__);
+		dev_dbg(dai->component->dev, "%s: IF0 Protocol: I2S\n", __func__);
 		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1);
 		ab8500_audio_set_bit_delay(dai, 0);
 		break;
 
 	case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0 Protocol: DSP A (TDM)\n", __func__);
 		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
 		ab8500_audio_set_bit_delay(dai, 1);
 		break;
 
 	case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0 Protocol: DSP B (TDM)\n", __func__);
 		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
 		ab8500_audio_set_bit_delay(dai, 0);
 		break;
 
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupported format (0x%x)!\n",
 			__func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
 		return -EINVAL;
@@ -2185,37 +2185,37 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0: Normal bit clock, normal frame\n",
 			__func__);
 		break;
 	case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0: Normal bit clock, inverted frame\n",
 			__func__);
 		val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
 		break;
 	case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0: Inverted bit clock, normal frame\n",
 			__func__);
 		val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
 		break;
 	case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: IF0: Inverted bit clock, inverted frame\n",
 			__func__);
 		val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
 		val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
 		break;
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupported INV mask 0x%x\n",
 			__func__, fmt & SND_SOC_DAIFMT_INV_MASK);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
 
 	return 0;
 }
@@ -2224,7 +2224,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 		unsigned int tx_mask, unsigned int rx_mask,
 		int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val, mask, slot, slots_active;
 
 	mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
@@ -2245,17 +2245,17 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 			BIT(AB8500_DIGIFCONF2_IF0WL0);
 		break;
 	default:
-		dev_err(dai->codec->dev, "%s: Unsupported slot-width 0x%x\n",
+		dev_err(dai->component->dev, "%s: Unsupported slot-width 0x%x\n",
 			__func__, slot_width);
 		return -EINVAL;
 	}
 
-	dev_dbg(dai->codec->dev, "%s: IF0 slot-width: %d bits.\n",
+	dev_dbg(dai->component->dev, "%s: IF0 slot-width: %d bits.\n",
 		__func__, slot_width);
-	snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
 
 	/* Setup TDM clocking according to slot count */
-	dev_dbg(dai->codec->dev, "%s: Slots, total: %d\n", __func__, slots);
+	dev_dbg(dai->component->dev, "%s: Slots, total: %d\n", __func__, slots);
 	mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
 			BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
 	switch (slots) {
@@ -2273,12 +2273,12 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 			BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
 		break;
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupported number of slots (%d)!\n",
 			__func__, slots);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF1, mask, val);
 
 	/* Setup TDM DA according to active tx slots */
 
@@ -2289,7 +2289,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
 	slots_active = hweight32(tx_mask);
 
-	dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
+	dev_dbg(dai->component->dev, "%s: Slots, active, TX: %d\n", __func__,
 		slots_active);
 
 	switch (slots_active) {
@@ -2297,26 +2297,26 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 		break;
 	case 1:
 		slot = ffs(tx_mask);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF1, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF3, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF2, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF4, mask, slot);
 		break;
 	case 2:
 		slot = ffs(tx_mask);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF1, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF3, mask, slot);
 		slot = fls(tx_mask);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
-		snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF2, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF4, mask, slot);
 		break;
 	case 8:
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: In 8-channel mode DA-from-slot mapping is set manually.",
 			__func__);
 		break;
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: Unsupported number of active TX-slots (%d)!\n",
 			__func__, slots_active);
 		return -EINVAL;
@@ -2330,7 +2330,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
 	slots_active = hweight32(rx_mask);
 
-	dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
+	dev_dbg(dai->component->dev, "%s: Slots, active, RX: %d\n", __func__,
 		slots_active);
 
 	switch (slots_active) {
@@ -2338,29 +2338,29 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
 		break;
 	case 1:
 		slot = ffs(rx_mask);
-		snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot),
+		snd_soc_component_update_bits(component, AB8500_ADSLOTSEL(slot),
 				AB8500_MASK_SLOT(slot),
 				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
 		break;
 	case 2:
 		slot = ffs(rx_mask);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 				AB8500_ADSLOTSEL(slot),
 				AB8500_MASK_SLOT(slot),
 				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
 		slot = fls(rx_mask);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 				AB8500_ADSLOTSEL(slot),
 				AB8500_MASK_SLOT(slot),
 				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
 		break;
 	case 8:
-		dev_dbg(dai->codec->dev,
+		dev_dbg(dai->component->dev,
 			"%s: In 8-channel mode AD-to-slot mapping is set manually.",
 			__func__);
 		break;
 	default:
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: Unsupported number of active RX-slots (%d)!\n",
 			__func__, slots_active);
 		return -EINVAL;
@@ -2458,10 +2458,10 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
 	}
 }
 
-static int ab8500_codec_probe(struct snd_soc_codec *codec)
+static int ab8500_codec_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct device *dev = codec->dev;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct device *dev = component->dev;
 	struct device_node *np = dev->of_node;
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
 	struct ab8500_codec_platform_data codec_pdata;
@@ -2472,19 +2472,19 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
 	ab8500_codec_of_probe(dev, np, &codec_pdata);
 
-	status = ab8500_audio_setup_mics(codec, &codec_pdata.amics);
+	status = ab8500_audio_setup_mics(component, &codec_pdata.amics);
 	if (status < 0) {
 		pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
 		return status;
 	}
-	status = ab8500_audio_set_ear_cmv(codec, codec_pdata.ear_cmv);
+	status = ab8500_audio_set_ear_cmv(component, codec_pdata.ear_cmv);
 	if (status < 0) {
 		pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n",
 			__func__, status);
 		return status;
 	}
 
-	status = ab8500_audio_init_audioblock(codec);
+	status = ab8500_audio_init_audioblock(component);
 	if (status < 0) {
 		dev_err(dev, "%s: failed to init audio-block (%d)!\n",
 			__func__, status);
@@ -2492,13 +2492,13 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 	}
 
 	/* Override HW-defaults */
-	snd_soc_write(codec, AB8500_ANACONF5,
+	snd_soc_component_write(component, AB8500_ANACONF5,
 		      BIT(AB8500_ANACONF5_HSAUTOEN));
-	snd_soc_write(codec, AB8500_SHORTCIRCONF,
+	snd_soc_component_write(component, AB8500_SHORTCIRCONF,
 		      BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
 
 	/* Add filter controls */
-	status = snd_soc_add_codec_controls(codec, ab8500_filter_controls,
+	status = snd_soc_add_component_controls(component, ab8500_filter_controls,
 				ARRAY_SIZE(ab8500_filter_controls));
 	if (status < 0) {
 		dev_err(dev,
@@ -2523,16 +2523,18 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 	return status;
 }
 
-static const struct snd_soc_codec_driver ab8500_codec_driver = {
-	.probe =		ab8500_codec_probe,
-	.component_driver = {
-		.controls =		ab8500_ctrls,
-		.num_controls =		ARRAY_SIZE(ab8500_ctrls),
-		.dapm_widgets =		ab8500_dapm_widgets,
-		.num_dapm_widgets =	ARRAY_SIZE(ab8500_dapm_widgets),
-		.dapm_routes =		ab8500_dapm_routes,
-		.num_dapm_routes =	ARRAY_SIZE(ab8500_dapm_routes),
-	},
+static const struct snd_soc_component_driver ab8500_component_driver = {
+	.probe			= ab8500_codec_probe,
+	.controls		= ab8500_ctrls,
+	.num_controls		= ARRAY_SIZE(ab8500_ctrls),
+	.dapm_widgets		= ab8500_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ab8500_dapm_widgets),
+	.dapm_routes		= ab8500_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ab8500_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ab8500_codec_driver_probe(struct platform_device *pdev)
@@ -2561,7 +2563,8 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
 	}
 
 	dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
-	status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver,
+	status = devm_snd_soc_register_component(&pdev->dev,
+				&ab8500_component_driver,
 				ab8500_codec_dai,
 				ARRAY_SIZE(ab8500_codec_dai));
 	if (status < 0)
@@ -2572,21 +2575,11 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
 	return status;
 }
 
-static int ab8500_codec_driver_remove(struct platform_device *pdev)
-{
-	dev_dbg(&pdev->dev, "%s Enter.\n", __func__);
-
-	snd_soc_unregister_codec(&pdev->dev);
-
-	return 0;
-}
-
 static struct platform_driver ab8500_codec_platform_driver = {
 	.driver	= {
 		.name	= "ab8500-codec",
 	},
 	.probe		= ab8500_codec_driver_probe,
-	.remove		= ab8500_codec_driver_remove,
 };
 module_platform_driver(ab8500_codec_platform_driver);
 
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 440b4ce54376..02b4d01adb40 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -36,8 +36,8 @@ static const struct snd_soc_dapm_route ac97_routes[] = {
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -65,7 +65,7 @@ static struct snd_soc_dai_driver ac97_dai = {
 	.ops = &ac97_dai_ops,
 };
 
-static int ac97_soc_probe(struct snd_soc_codec *codec)
+static int ac97_soc_probe(struct snd_soc_component *component)
 {
 	struct snd_ac97 *ac97;
 	struct snd_ac97_bus *ac97_bus;
@@ -73,7 +73,7 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
 	int ret;
 
 	/* add codec as bus device for standard ac97 */
-	ret = snd_ac97_bus(codec->component.card->snd_card, 0, soc_ac97_ops,
+	ret = snd_ac97_bus(component->card->snd_card, 0, soc_ac97_ops,
 			   NULL, &ac97_bus);
 	if (ret < 0)
 		return ret;
@@ -83,25 +83,25 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
 	if (ret < 0)
 		return ret;
 
-	snd_soc_codec_set_drvdata(codec, ac97);
+	snd_soc_component_set_drvdata(component, ac97);
 
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int ac97_soc_suspend(struct snd_soc_codec *codec)
+static int ac97_soc_suspend(struct snd_soc_component *component)
 {
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 
 	snd_ac97_suspend(ac97);
 
 	return 0;
 }
 
-static int ac97_soc_resume(struct snd_soc_codec *codec)
+static int ac97_soc_resume(struct snd_soc_component *component)
 {
 
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 
 	snd_ac97_resume(ac97);
 
@@ -112,28 +112,28 @@ static int ac97_soc_resume(struct snd_soc_codec *codec)
 #define ac97_soc_resume NULL
 #endif
 
-static const struct snd_soc_codec_driver soc_codec_dev_ac97 = {
-	.probe = 	ac97_soc_probe,
-	.suspend =	ac97_soc_suspend,
-	.resume =	ac97_soc_resume,
-
-	.component_driver = {
-		.dapm_widgets		= ac97_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ac97_widgets),
-		.dapm_routes		= ac97_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ac97_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ac97 = {
+	.probe			= ac97_soc_probe,
+	.suspend		= ac97_soc_suspend,
+	.resume			= ac97_soc_resume,
+	.dapm_widgets		= ac97_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ac97_widgets),
+	.dapm_routes		= ac97_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ac97_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ac97_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_ac97, &ac97_dai, 1);
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ac97, &ac97_dai, 1);
 }
 
 static int ac97_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index d0361caad09e..ada663bf5648 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -164,7 +164,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
-	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(dai->component);
 	int word_len = 0;
 
 	/* bit size */
@@ -228,17 +228,17 @@ static struct snd_soc_dai_driver ad183x_dais[] = {
 };
 
 #ifdef CONFIG_PM
-static int ad1836_suspend(struct snd_soc_codec *codec)
+static int ad1836_suspend(struct snd_soc_component *component)
 {
-	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
 	/* reset clock control mode */
 	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
 		AD1836_ADC_SERFMT_MASK, 0);
 }
 
-static int ad1836_resume(struct snd_soc_codec *codec)
+static int ad1836_resume(struct snd_soc_component *component)
 {
-	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
 	/* restore clock control mode */
 	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
 		AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
@@ -248,10 +248,10 @@ static int ad1836_resume(struct snd_soc_codec *codec)
 #define ad1836_resume  NULL
 #endif
 
-static int ad1836_probe(struct snd_soc_codec *codec)
+static int ad1836_probe(struct snd_soc_component *component)
 {
-	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int num_dacs, num_adcs;
 	int ret = 0;
 	int i;
@@ -277,7 +277,7 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 	if (ad1836->type == AD1836) {
 		/* left/right diff:PGA/MUX */
 		regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A);
-		ret = snd_soc_add_codec_controls(codec, ad1836_controls,
+		ret = snd_soc_add_component_controls(component, ad1836_controls,
 				ARRAY_SIZE(ad1836_controls));
 		if (ret)
 			return ret;
@@ -285,11 +285,11 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 		regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00);
 	}
 
-	ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2);
+	ret = snd_soc_add_component_controls(component, ad183x_dac_controls, num_dacs * 2);
 	if (ret)
 		return ret;
 
-	ret = snd_soc_add_codec_controls(codec, ad183x_adc_controls, num_adcs);
+	ret = snd_soc_add_component_controls(component, ad183x_adc_controls, num_adcs);
 	if (ret)
 		return ret;
 
@@ -313,28 +313,29 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 }
 
 /* power down chip */
-static int ad1836_remove(struct snd_soc_codec *codec)
+static void ad1836_remove(struct snd_soc_component *component)
 {
-	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
 	/* reset clock control mode */
-	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+	regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
 		AD1836_ADC_SERFMT_MASK, 0);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
-	.probe = ad1836_probe,
-	.remove = ad1836_remove,
-	.suspend = ad1836_suspend,
-	.resume = ad1836_resume,
-
-	.component_driver = {
-		.controls		= ad183x_controls,
-		.num_controls		= ARRAY_SIZE(ad183x_controls),
-		.dapm_widgets		= ad183x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ad183x_dapm_widgets),
-		.dapm_routes		= ad183x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ad183x_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ad1836 = {
+	.probe			= ad1836_probe,
+	.remove			= ad1836_remove,
+	.suspend		= ad1836_suspend,
+	.resume			= ad1836_resume,
+	.controls		= ad183x_controls,
+	.num_controls		= ARRAY_SIZE(ad183x_controls),
+	.dapm_widgets		= ad183x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad183x_dapm_widgets),
+	.dapm_routes		= ad183x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ad183x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct reg_default ad1836_reg_defaults[] = {
@@ -382,17 +383,11 @@ static int ad1836_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, ad1836);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_ad1836, &ad183x_dais[ad1836->type], 1);
 	return ret;
 }
 
-static int ad1836_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static const struct spi_device_id ad1836_ids[] = {
 	{ "ad1835", AD1835 },
 	{ "ad1836", AD1836 },
@@ -408,7 +403,6 @@ static struct spi_driver ad1836_spi_driver = {
 		.name	= "ad1836",
 	},
 	.probe		= ad1836_spi_probe,
-	.remove		= ad1836_spi_remove,
 	.id_table	= ad1836_ids,
 };
 
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c
index 171313664bc8..b9551334f6b4 100644
--- a/sound/soc/codecs/ad193x-i2c.c
+++ b/sound/soc/codecs/ad193x-i2c.c
@@ -35,18 +35,11 @@ static int ad193x_i2c_probe(struct i2c_client *client,
 			    (enum ad193x_type)id->driver_data);
 }
 
-static int ad193x_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static struct i2c_driver ad193x_i2c_driver = {
 	.driver = {
 		.name = "ad193x",
 	},
 	.probe    = ad193x_i2c_probe,
-	.remove   = ad193x_i2c_remove,
 	.id_table = ad193x_id,
 };
 module_i2c_driver(ad193x_i2c_driver);
diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c
index 23c28573bdb7..3c1394a803b8 100644
--- a/sound/soc/codecs/ad193x-spi.c
+++ b/sound/soc/codecs/ad193x-spi.c
@@ -29,12 +29,6 @@ static int ad193x_spi_probe(struct spi_device *spi)
 			    (enum ad193x_type)id->driver_data);
 }
 
-static int ad193x_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static const struct spi_device_id ad193x_spi_id[] = {
 	{ "ad193x", AD193X },
 	{ "ad1933", AD1933 },
@@ -51,7 +45,6 @@ static struct spi_driver ad193x_spi_driver = {
 		.name	= "ad193x",
 	},
 	.probe		= ad193x_spi_probe,
-	.remove		= ad193x_spi_remove,
 	.id_table	= ad193x_spi_id,
 };
 module_spi_driver(ad193x_spi_driver);
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index d10988eec0c1..4b60ebee491d 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -130,7 +130,7 @@ static inline bool ad193x_has_adc(const struct ad193x_priv *ad193x)
 
 static int ad193x_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec);
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);
 
 	if (mute)
 		regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
@@ -146,7 +146,7 @@ static int ad193x_mute(struct snd_soc_dai *dai, int mute)
 static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			       unsigned int rx_mask, int slots, int width)
 {
-	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec);
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);
 	unsigned int channels;
 
 	switch (slots) {
@@ -179,7 +179,7 @@ static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec_dai->codec);
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component);
 	unsigned int adc_serfmt = 0;
 	unsigned int adc_fmt = 0;
 	unsigned int dac_fmt = 0;
@@ -257,8 +257,8 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
 	switch (freq) {
 	case 12288000:
 	case 18432000:
@@ -275,8 +275,8 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
 	int word_len = 0, master_rate = 0;
-	struct snd_soc_codec *codec = dai->codec;
-	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
 
 	/* bit size */
 	switch (params_width(params)) {
@@ -351,10 +351,10 @@ static struct snd_soc_dai_driver ad193x_dai = {
 	.ops = &ad193x_dai_ops,
 };
 
-static int ad193x_codec_probe(struct snd_soc_codec *codec)
+static int ad193x_component_probe(struct snd_soc_component *component)
 {
-	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int num, ret;
 
 	/* default setting for ad193x */
@@ -382,7 +382,7 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
 	if (ad193x_has_adc(ad193x)) {
 		/* add adc controls */
 		num = ARRAY_SIZE(ad193x_adc_snd_controls);
-		ret = snd_soc_add_codec_controls(codec,
+		ret = snd_soc_add_component_controls(component,
 						 ad193x_adc_snd_controls,
 						 num);
 		if (ret)
@@ -408,16 +408,18 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ad193x = {
-	.probe = ad193x_codec_probe,
-	.component_driver = {
-		.controls		= ad193x_snd_controls,
-		.num_controls		= ARRAY_SIZE(ad193x_snd_controls),
-		.dapm_widgets		= ad193x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ad193x_dapm_widgets),
-		.dapm_routes		= audio_paths,
-		.num_dapm_routes	= ARRAY_SIZE(audio_paths),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ad193x = {
+	.probe			= ad193x_component_probe,
+	.controls		= ad193x_snd_controls,
+	.num_controls		= ARRAY_SIZE(ad193x_snd_controls),
+	.dapm_widgets		= ad193x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad193x_dapm_widgets),
+	.dapm_routes		= audio_paths,
+	.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 const struct regmap_config ad193x_regmap_config = {
@@ -442,7 +444,7 @@ int ad193x_probe(struct device *dev, struct regmap *regmap,
 
 	dev_set_drvdata(dev, ad193x);
 
-	return snd_soc_register_codec(dev, &soc_codec_dev_ad193x,
+	return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x,
 		&ad193x_dai, 1);
 }
 EXPORT_SYMBOL_GPL(ad193x_probe);
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index ce89bfb42094..16dab3f00a1c 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -205,9 +205,9 @@ static struct snd_soc_dai_driver ad1980_dai = {
 #define AD1980_VENDOR_ID 0x41445300
 #define AD1980_VENDOR_MASK 0xffffff00
 
-static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
+static int ad1980_reset(struct snd_soc_component *component, int try_warm)
 {
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 	unsigned int retry_cnt = 0;
 	int ret;
 
@@ -223,16 +223,16 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
 		 * case the first nibble of data is eaten by the addr. (Tag is
 		 * always 16 bit)
 		 */
-		snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
+		snd_soc_component_write(component, AC97_AD_SERIAL_CFG, 0x9900);
 
 	} while (retry_cnt++ < 10);
 
-	dev_err(codec->dev, "Failed to reset: AC97 link error\n");
+	dev_err(component->dev, "Failed to reset: AC97 link error\n");
 
 	return -EIO;
 }
 
-static int ad1980_soc_probe(struct snd_soc_codec *codec)
+static int ad1980_soc_probe(struct snd_soc_component *component)
 {
 	struct snd_ac97 *ac97;
 	struct regmap *regmap;
@@ -240,10 +240,10 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
 	u16 vendor_id2;
 	u16 ext_status;
 
-	ac97 = snd_soc_new_ac97_codec(codec, 0, 0);
+	ac97 = snd_soc_new_ac97_component(component, 0, 0);
 	if (IS_ERR(ac97)) {
 		ret = PTR_ERR(ac97);
-		dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
+		dev_err(component->dev, "Failed to register AC97 component: %d\n", ret);
 		return ret;
 	}
 
@@ -253,72 +253,66 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
 		goto err_free_ac97;
 	}
 
-	snd_soc_codec_init_regmap(codec, regmap);
-	snd_soc_codec_set_drvdata(codec, ac97);
+	snd_soc_component_init_regmap(component, regmap);
+	snd_soc_component_set_drvdata(component, ac97);
 
-	ret = ad1980_reset(codec, 0);
+	ret = ad1980_reset(component, 0);
 	if (ret < 0)
 		goto reset_err;
 
-	vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
+	vendor_id2 = snd_soc_component_read32(component, AC97_VENDOR_ID2);
 	if (vendor_id2 == 0x5374) {
-		dev_warn(codec->dev,
+		dev_warn(component->dev,
 			"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
 	}
 
 	/* unmute captures and playbacks volume */
-	snd_soc_write(codec, AC97_MASTER, 0x0000);
-	snd_soc_write(codec, AC97_PCM, 0x0000);
-	snd_soc_write(codec, AC97_REC_GAIN, 0x0000);
-	snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
-	snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000);
+	snd_soc_component_write(component, AC97_MASTER, 0x0000);
+	snd_soc_component_write(component, AC97_PCM, 0x0000);
+	snd_soc_component_write(component, AC97_REC_GAIN, 0x0000);
+	snd_soc_component_write(component, AC97_CENTER_LFE_MASTER, 0x0000);
+	snd_soc_component_write(component, AC97_SURROUND_MASTER, 0x0000);
 
 	/*power on LFE/CENTER/Surround DACs*/
-	ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS);
-	snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
+	ext_status = snd_soc_component_read32(component, AC97_EXTENDED_STATUS);
+	snd_soc_component_write(component, AC97_EXTENDED_STATUS, ext_status&~0x3800);
 
 	return 0;
 
 reset_err:
-	snd_soc_codec_exit_regmap(codec);
+	snd_soc_component_exit_regmap(component);
 err_free_ac97:
-	snd_soc_free_ac97_codec(ac97);
+	snd_soc_free_ac97_component(ac97);
 	return ret;
 }
 
-static int ad1980_soc_remove(struct snd_soc_codec *codec)
+static void ad1980_soc_remove(struct snd_soc_component *component)
 {
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_exit_regmap(codec);
-	snd_soc_free_ac97_codec(ac97);
-	return 0;
+	snd_soc_component_exit_regmap(component);
+	snd_soc_free_ac97_component(ac97);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
-	.probe = 	ad1980_soc_probe,
-	.remove = 	ad1980_soc_remove,
-
-	.component_driver = {
-		.controls		= ad1980_snd_ac97_controls,
-		.num_controls		= ARRAY_SIZE(ad1980_snd_ac97_controls),
-		.dapm_widgets		= ad1980_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ad1980_dapm_widgets),
-		.dapm_routes		= ad1980_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ad1980_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ad1980 = {
+	.probe			= ad1980_soc_probe,
+	.remove			= ad1980_soc_remove,
+	.controls		= ad1980_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(ad1980_snd_ac97_controls),
+	.dapm_widgets		= ad1980_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad1980_dapm_widgets),
+	.dapm_routes		= ad1980_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ad1980_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ad1980_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_ad1980, &ad1980_dai, 1);
-}
-
-static int ad1980_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ad1980, &ad1980_dai, 1);
 }
 
 static struct platform_driver ad1980_codec_driver = {
@@ -327,7 +321,6 @@ static struct platform_driver ad1980_codec_driver = {
 	},
 
 	.probe = ad1980_probe,
-	.remove = ad1980_remove,
 };
 
 module_platform_driver(ad1980_codec_driver);
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index d8d86a0fea60..03ee571e1b7a 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -54,25 +54,21 @@ static struct snd_soc_dai_driver ad73311_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
-	.component_driver = {
-		.dapm_widgets		= ad73311_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ad73311_dapm_widgets),
-		.dapm_routes		= ad73311_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ad73311_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ad73311 = {
+	.dapm_widgets		= ad73311_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad73311_dapm_widgets),
+	.dapm_routes		= ad73311_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ad73311_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ad73311_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_ad73311, &ad73311_dai, 1);
-}
-
-static int ad73311_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ad73311, &ad73311_dai, 1);
 }
 
 static struct platform_driver ad73311_codec_driver = {
@@ -81,7 +77,6 @@ static struct platform_driver ad73311_codec_driver = {
 	},
 
 	.probe = ad73311_probe,
-	.remove = ad73311_remove,
 };
 
 module_platform_driver(ad73311_codec_driver);
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index a865945d776a..f22ff9f6ab47 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -549,8 +549,8 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = {
 static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 	unsigned int pll_id = w->name[3] - '1';
 	unsigned int val;
 
@@ -821,8 +821,8 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
 static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
 	struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 	unsigned int dai;
 	const char *clk;
 
@@ -842,8 +842,8 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
 static int adau1373_check_src(struct snd_soc_dapm_widget *source,
 	struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 	unsigned int dai;
 
 	dai = sink->name[3] - '1';
@@ -1031,8 +1031,8 @@ static const struct snd_soc_dapm_route adau1373_dapm_routes[] = {
 static int adau1373_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 	struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
 	unsigned int div;
 	unsigned int freq;
@@ -1098,8 +1098,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
 
 static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 	struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
 	unsigned int ctrl;
 
@@ -1158,7 +1158,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,
 	int clk_id, unsigned int freq, int dir)
 {
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(dai->component);
 	struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
 
 	switch (clk_id) {
@@ -1250,10 +1250,10 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
 	},
 };
 
-static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
+static int adau1373_set_pll(struct snd_soc_component *component, int pll_id,
 	int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 	unsigned int dpll_div = 0;
 	uint8_t pll_regs[5];
 	int ret;
@@ -1348,10 +1348,10 @@ static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
 	return false;
 }
 
-static int adau1373_probe(struct snd_soc_codec *codec)
+static int adau1373_probe(struct snd_soc_component *component)
 {
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
-	struct adau1373_platform_data *pdata = codec->dev->platform_data;
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	struct adau1373_platform_data *pdata = component->dev->platform_data;
 	bool lineout_differential = false;
 	unsigned int val;
 	int i;
@@ -1369,7 +1369,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)
 				pdata->drc_setting[i]);
 		}
 
-		snd_soc_add_codec_controls(codec, adau1373_drc_controls,
+		snd_soc_add_component_controls(component, adau1373_drc_controls,
 			pdata->num_drc);
 
 		val = 0;
@@ -1394,7 +1394,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)
 	}
 
 	if (!lineout_differential) {
-		snd_soc_add_codec_controls(codec, adau1373_lineout2_controls,
+		snd_soc_add_component_controls(component, adau1373_lineout2_controls,
 			ARRAY_SIZE(adau1373_lineout2_controls));
 	}
 
@@ -1404,10 +1404,10 @@ static int adau1373_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int adau1373_set_bias_level(struct snd_soc_codec *codec,
+static int adau1373_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -1426,9 +1426,9 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adau1373_resume(struct snd_soc_codec *codec)
+static int adau1373_resume(struct snd_soc_component *component)
 {
-	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
 
 	regcache_sync(adau1373->regmap);
 
@@ -1458,22 +1458,20 @@ static const struct regmap_config adau1373_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
 };
 
-static const struct snd_soc_codec_driver adau1373_codec_driver = {
-	.probe =	adau1373_probe,
-	.resume =	adau1373_resume,
-	.set_bias_level = adau1373_set_bias_level,
-	.idle_bias_off = true,
-
-	.set_pll = adau1373_set_pll,
-
-	.component_driver = {
-		.controls		= adau1373_controls,
-		.num_controls		= ARRAY_SIZE(adau1373_controls),
-		.dapm_widgets		= adau1373_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adau1373_dapm_widgets),
-		.dapm_routes		= adau1373_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adau1373_dapm_routes),
-	},
+static const struct snd_soc_component_driver adau1373_component_driver = {
+	.probe			= adau1373_probe,
+	.resume			= adau1373_resume,
+	.set_bias_level		= adau1373_set_bias_level,
+	.set_pll		= adau1373_set_pll,
+	.controls		= adau1373_controls,
+	.num_controls		= ARRAY_SIZE(adau1373_controls),
+	.dapm_widgets		= adau1373_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1373_dapm_widgets),
+	.dapm_routes		= adau1373_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1373_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int adau1373_i2c_probe(struct i2c_client *client,
@@ -1495,17 +1493,12 @@ static int adau1373_i2c_probe(struct i2c_client *client,
 
 	dev_set_drvdata(&client->dev, adau1373);
 
-	ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver,
+	ret = devm_snd_soc_register_component(&client->dev,
+			&adau1373_component_driver,
 			adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
 	return ret;
 }
 
-static int adau1373_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id adau1373_i2c_id[] = {
 	{ "adau1373", 0 },
 	{ }
@@ -1517,7 +1510,6 @@ static struct i2c_driver adau1373_i2c_driver = {
 		.name = "adau1373",
 	},
 	.probe = adau1373_i2c_probe,
-	.remove = adau1373_i2c_remove,
 	.id_table = adau1373_i2c_id,
 };
 
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 805afac8146b..b5a61741c800 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -298,10 +298,10 @@ static const struct sigmadsp_ops adau1701_sigmadsp_ops = {
 	.safeload = adau1701_safeload,
 };
 
-static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
+static int adau1701_reset(struct snd_soc_component *component, unsigned int clkdiv,
 	unsigned int rate)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	sigmadsp_reset(adau1701->sigmadsp);
@@ -348,7 +348,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
 	if (clkdiv != ADAU1707_CLKDIV_UNSET) {
 		ret = sigmadsp_setup(adau1701->sigmadsp, rate);
 		if (ret) {
-			dev_warn(codec->dev, "Failed to load firmware\n");
+			dev_warn(component->dev, "Failed to load firmware\n");
 			return ret;
 		}
 	}
@@ -362,10 +362,10 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
 	return 0;
 }
 
-static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
+static int adau1701_set_capture_pcm_format(struct snd_soc_component *component,
 					   struct snd_pcm_hw_params *params)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;
 	unsigned int val;
 
@@ -403,10 +403,10 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
+static int adau1701_set_playback_pcm_format(struct snd_soc_component *component,
 					    struct snd_pcm_hw_params *params)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
@@ -435,8 +435,8 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
 static int adau1701_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	unsigned int clkdiv = adau1701->sysclk / params_rate(params);
 	unsigned int val;
 	int ret;
@@ -447,7 +447,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
 	 * firmware upload.
 	 */
 	if (clkdiv != adau1701->pll_clkdiv) {
-		ret = adau1701_reset(codec, clkdiv, params_rate(params));
+		ret = adau1701_reset(component, clkdiv, params_rate(params));
 		if (ret < 0)
 			return ret;
 	}
@@ -470,16 +470,16 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
 		ADAU1701_DSPCTRL_SR_MASK, val);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		return adau1701_set_playback_pcm_format(codec, params);
+		return adau1701_set_playback_pcm_format(component, params);
 	else
-		return adau1701_set_capture_pcm_format(codec, params);
+		return adau1701_set_capture_pcm_format(component, params);
 }
 
 static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	unsigned int serictl = 0x00, seroctl = 0x00;
 	bool invert_lrclk;
 
@@ -548,11 +548,11 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int adau1701_set_bias_level(struct snd_soc_codec *codec,
+static int adau1701_set_bias_level(struct snd_soc_component *component,
 		enum snd_soc_bias_level level)
 {
 	unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD;
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -576,9 +576,9 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
 
 static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int mask = ADAU1701_DSPCTRL_DAM;
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (mute)
@@ -591,11 +591,11 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
-static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int adau1701_set_sysclk(struct snd_soc_component *component, int clk_id,
 	int source, unsigned int freq, int dir)
 {
 	unsigned int val;
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case ADAU1701_CLK_SRC_OSC:
@@ -618,7 +618,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 static int adau1701_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(dai->component);
 
 	return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
 }
@@ -664,20 +664,20 @@ static const struct of_device_id adau1701_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
 #endif
 
-static int adau1701_probe(struct snd_soc_codec *codec)
+static int adau1701_probe(struct snd_soc_component *component)
 {
 	int i, ret;
 	unsigned int val;
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 
-	ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component);
+	ret = sigmadsp_attach(adau1701->sigmadsp, component);
 	if (ret)
 		return ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
 				    adau1701->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
 		return ret;
 	}
 
@@ -690,7 +690,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
 
 	/* initalize with pre-configured pll mode settings */
-	ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
+	ret = adau1701_reset(component, adau1701->pll_clkdiv, 0);
 	if (ret < 0)
 		goto exit_regulators_disable;
 
@@ -715,22 +715,20 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int adau1701_remove(struct snd_soc_codec *codec)
+static void adau1701_remove(struct snd_soc_component *component)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(adau1701->gpio_nreset))
 		gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
 
 	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int adau1701_suspend(struct snd_soc_codec *codec)
+static int adau1701_suspend(struct snd_soc_component *component)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 
 	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies),
 			       adau1701->supplies);
@@ -738,42 +736,41 @@ static int adau1701_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int adau1701_resume(struct snd_soc_codec *codec)
+static int adau1701_resume(struct snd_soc_component *component)
 {
-	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
 	int ret;
 
         ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
 				    adau1701->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
 		return ret;
 	}
 
-	return adau1701_reset(codec, adau1701->pll_clkdiv, 0);
+	return adau1701_reset(component, adau1701->pll_clkdiv, 0);
 }
 #else
 #define adau1701_resume 	NULL
 #define adau1701_suspend 	NULL
 #endif /* CONFIG_PM */
 
-static const struct snd_soc_codec_driver adau1701_codec_drv = {
+static const struct snd_soc_component_driver adau1701_component_drv = {
 	.probe			= adau1701_probe,
 	.remove			= adau1701_remove,
 	.resume			= adau1701_resume,
 	.suspend		= adau1701_suspend,
 	.set_bias_level		= adau1701_set_bias_level,
-	.idle_bias_off		= true,
-
-	.component_driver = {
-		.controls		= adau1701_controls,
-		.num_controls		= ARRAY_SIZE(adau1701_controls),
-		.dapm_widgets		= adau1701_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
-		.dapm_routes		= adau1701_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
-	},
+	.controls		= adau1701_controls,
+	.num_controls		= ARRAY_SIZE(adau1701_controls),
+	.dapm_widgets		= adau1701_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
+	.dapm_routes		= adau1701_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
 	.set_sysclk		= adau1701_set_sysclk,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config adau1701_regmap = {
@@ -889,7 +886,8 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 		goto exit_regulators_disable;
 	}
 
-	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
+	ret = devm_snd_soc_register_component(&client->dev,
+			&adau1701_component_drv,
 			&adau1701_dai, 1);
 
 exit_regulators_disable:
@@ -898,12 +896,6 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 	return ret;
 }
 
-static int adau1701_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id adau1701_i2c_id[] = {
 	{ "adau1401", 0 },
 	{ "adau1401a", 0 },
@@ -919,7 +911,6 @@ static struct i2c_driver adau1701_i2c_driver = {
 		.of_match_table	= of_match_ptr(adau1701_dt_ids),
 	},
 	.probe		= adau1701_i2c_probe,
-	.remove		= adau1701_i2c_remove,
 	.id_table	= adau1701_i2c_id,
 };
 
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index 3bc3cc559dde..be136e981653 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -255,8 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control =
 static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	/* After any power changes have been made the dejitter circuit
 	 * has to be reinitialized. */
@@ -445,10 +445,10 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
 	{ "Digital Clock 1", NULL, "SYSCLK" },
 };
 
-static int adau1761_set_bias_level(struct snd_soc_codec *codec,
+static int adau1761_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -460,7 +460,7 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec,
 		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
 			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
 			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			regcache_sync(adau->regmap);
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -474,9 +474,9 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec,
 }
 
 static enum adau1761_output_mode adau1761_get_lineout_mode(
-	struct snd_soc_codec *codec)
+	struct snd_soc_component *component)
 {
-	struct adau1761_platform_data *pdata = codec->dev->platform_data;
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
 
 	if (pdata)
 		return pdata->lineout_mode;
@@ -484,11 +484,11 @@ static enum adau1761_output_mode adau1761_get_lineout_mode(
 	return ADAU1761_OUTPUT_MODE_LINE;
 }
 
-static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
+static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau1761_platform_data *pdata = codec->dev->platform_data;
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	enum adau1761_digmic_jackdet_pin_mode mode;
 	unsigned int val = 0;
 	int ret;
@@ -513,7 +513,7 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 		if (pdata->jackdetect_active_low)
 			val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW;
 
-		ret = snd_soc_add_codec_controls(codec,
+		ret = snd_soc_add_component_controls(component,
 			adau1761_jack_detect_controls,
 			ARRAY_SIZE(adau1761_jack_detect_controls));
 		if (ret)
@@ -546,11 +546,11 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
+static int adau1761_setup_headphone_mode(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
-	struct adau1761_platform_data *pdata = codec->dev->platform_data;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
 	enum adau1761_output_mode mode;
 	int ret;
 
@@ -588,7 +588,7 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
 			adau1761_capless_dapm_routes,
 			ARRAY_SIZE(adau1761_capless_dapm_routes));
 	} else {
-		ret = snd_soc_add_codec_controls(codec, adau1761_mono_controls,
+		ret = snd_soc_add_component_controls(component, adau1761_mono_controls,
 			ARRAY_SIZE(adau1761_mono_controls));
 		if (ret)
 			return ret;
@@ -640,14 +640,14 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg)
 	return adau17x1_readable_register(dev, reg);
 }
 
-static int adau1761_codec_probe(struct snd_soc_codec *codec)
+static int adau1761_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau1761_platform_data *pdata = codec->dev->platform_data;
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	ret = adau17x1_add_widgets(codec);
+	ret = adau17x1_add_widgets(component);
 	if (ret < 0)
 		return ret;
 
@@ -658,20 +658,20 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
 		regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL,
 			ADAU1761_DIFF_INPUT_VOL_LDEN,
 			ADAU1761_DIFF_INPUT_VOL_LDEN);
-		ret = snd_soc_add_codec_controls(codec,
+		ret = snd_soc_add_component_controls(component,
 			adau1761_differential_mode_controls,
 			ARRAY_SIZE(adau1761_differential_mode_controls));
 		if (ret)
 			return ret;
 	} else {
-		ret = snd_soc_add_codec_controls(codec,
+		ret = snd_soc_add_component_controls(component,
 			adau1761_single_mode_controls,
 			ARRAY_SIZE(adau1761_single_mode_controls));
 		if (ret)
 			return ret;
 	}
 
-	switch (adau1761_get_lineout_mode(codec)) {
+	switch (adau1761_get_lineout_mode(component)) {
 	case ADAU1761_OUTPUT_MODE_LINE:
 		break;
 	case ADAU1761_OUTPUT_MODE_HEADPHONE:
@@ -686,11 +686,11 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
 		return -EINVAL;
 	}
 
-	ret = adau1761_setup_headphone_mode(codec);
+	ret = adau1761_setup_headphone_mode(component);
 	if (ret)
 		return ret;
 
-	ret = adau1761_setup_digmic_jackdetect(codec);
+	ret = adau1761_setup_digmic_jackdetect(component);
 	if (ret)
 		return ret;
 
@@ -706,27 +706,28 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
 			return ret;
 	}
 
-	ret = adau17x1_add_routes(codec);
+	ret = adau17x1_add_routes(component);
 	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver adau1761_codec_driver = {
-	.probe = adau1761_codec_probe,
-	.resume	= adau17x1_resume,
-	.set_bias_level	= adau1761_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= adau1761_controls,
-		.num_controls		= ARRAY_SIZE(adau1761_controls),
-		.dapm_widgets		= adau1x61_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adau1x61_dapm_widgets),
-		.dapm_routes		= adau1x61_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adau1x61_dapm_routes),
-	},
+static const struct snd_soc_component_driver adau1761_component_driver = {
+	.probe			= adau1761_component_probe,
+	.resume			= adau17x1_resume,
+	.set_bias_level		= adau1761_set_bias_level,
+	.controls		= adau1761_controls,
+	.num_controls		= ARRAY_SIZE(adau1761_controls),
+	.dapm_widgets		= adau1x61_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1x61_dapm_widgets),
+	.dapm_routes		= adau1x61_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1x61_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
@@ -793,7 +794,8 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
 	 * reaches standby and the core clock is enabled */
 	regcache_cache_only(regmap, true);
 
-	return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
+	return devm_snd_soc_register_component(dev, &adau1761_component_driver,
+					       dai_drv, 1);
 }
 EXPORT_SYMBOL_GPL(adau1761_probe);
 
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index 546071c6c0d0..6a6655730cd4 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -174,8 +174,8 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
 static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	/* After any power changes have been made the dejitter circuit
 	 * has to be reinitialized. */
@@ -314,10 +314,10 @@ static const struct snd_soc_dapm_route adau1781_dmic_dapm_routes[] = {
 	{ "Right Decimator", NULL, "DMIC Select" },
 };
 
-static int adau1781_set_bias_level(struct snd_soc_codec *codec,
+static int adau1781_set_bias_level(struct snd_soc_component *component,
 		enum snd_soc_bias_level level)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -380,14 +380,14 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
 		ADAU1781_INPUT_DIFFERNTIAL, val);
 }
 
-static int adau1781_codec_probe(struct snd_soc_codec *codec)
+static int adau1781_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1781_platform_data *pdata = dev_get_platdata(component->dev);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	ret = adau17x1_add_widgets(codec);
+	ret = adau17x1_add_widgets(component);
 	if (ret)
 		return ret;
 
@@ -419,27 +419,28 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
 			return ret;
 	}
 
-	ret = adau17x1_add_routes(codec);
+	ret = adau17x1_add_routes(component);
 	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver adau1781_codec_driver = {
-	.probe = adau1781_codec_probe,
-	.resume = adau17x1_resume,
-	.set_bias_level = adau1781_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= adau1781_controls,
-		.num_controls		= ARRAY_SIZE(adau1781_controls),
-		.dapm_widgets		= adau1781_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adau1781_dapm_widgets),
-		.dapm_routes		= adau1781_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adau1781_dapm_routes),
-	},
+static const struct snd_soc_component_driver adau1781_component_driver = {
+	.probe			= adau1781_component_probe,
+	.resume			= adau17x1_resume,
+	.set_bias_level		= adau1781_set_bias_level,
+	.controls		= adau1781_controls,
+	.num_controls		= ARRAY_SIZE(adau1781_controls),
+	.dapm_widgets		= adau1781_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1781_dapm_widgets),
+	.dapm_routes		= adau1781_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1781_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
@@ -498,7 +499,7 @@ int adau1781_probe(struct device *dev, struct regmap *regmap,
 	if (ret)
 		return ret;
 
-	return snd_soc_register_codec(dev, &adau1781_codec_driver,
+	return devm_snd_soc_register_component(dev, &adau1781_component_driver,
 		&adau1781_dai_driver, 1);
 }
 EXPORT_SYMBOL_GPL(adau1781_probe);
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 6758f789b712..80c2a06285bb 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -63,8 +63,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
 static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		adau->pll_regs[5] = 1;
@@ -93,8 +93,8 @@ static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
 static int adau17x1_adc_fixup(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	/*
 	 * If we are capturing, toggle the ADOSR bit in Converter Control 0 to
@@ -177,11 +177,11 @@ static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
 static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	struct snd_soc_dapm_update update = { 0 };
+	struct snd_soc_dapm_update update = {};
 	unsigned int stream = e->shift_l;
 	unsigned int val, change;
 	int reg;
@@ -205,7 +205,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
 	else
 		reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
 
-	change = snd_soc_test_bits(codec, reg, 0xff, val);
+	change = snd_soc_component_test_bits(component, reg, 0xff, val);
 	if (change) {
 		update.kcontrol = kcontrol;
 		update.mask = 0xff;
@@ -222,8 +222,8 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
 static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int stream = e->shift_l;
 	unsigned int reg, val;
@@ -328,8 +328,8 @@ EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
 static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
 	int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	if (freq_in < 8000000 || freq_in > 27000000)
@@ -353,8 +353,8 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
 static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
-	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dai->component);
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
 	bool is_pll;
 	bool was_pll;
 
@@ -438,8 +438,8 @@ static int adau17x1_auto_pll(struct snd_soc_dai *dai,
 static int adau17x1_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	unsigned int val, div, dsp_div;
 	unsigned int freq;
 	int ret;
@@ -531,7 +531,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
 static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
 		unsigned int fmt)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
 	unsigned int ctrl0, ctrl1;
 	int lrclk_pol;
 
@@ -603,7 +603,7 @@ static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
 static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
 	unsigned int ser_ctrl0, ser_ctrl1;
 	unsigned int conv_ctrl0, conv_ctrl1;
 
@@ -728,7 +728,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
 static int adau17x1_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
 
 	if (adau->sigmadsp)
 		return sigmadsp_restrict_params(adau->sigmadsp, substream);
@@ -746,10 +746,10 @@ const struct snd_soc_dai_ops adau17x1_dai_ops = {
 };
 EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
 
-int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
+int adau17x1_set_micbias_voltage(struct snd_soc_component *component,
 	enum adau17x1_micbias_voltage micbias)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	switch (micbias) {
 	case ADAU17X1_MICBIAS_0_90_AVDD:
@@ -858,13 +858,13 @@ int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
 }
 EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
 
-int adau17x1_add_widgets(struct snd_soc_codec *codec)
+int adau17x1_add_widgets(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	ret = snd_soc_add_codec_controls(codec, adau17x1_controls,
+	ret = snd_soc_add_component_controls(component, adau17x1_controls,
 		ARRAY_SIZE(adau17x1_controls));
 	if (ret)
 		return ret;
@@ -882,9 +882,9 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
 		if (!adau->sigmadsp)
 			return 0;
 
-		ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
+		ret = sigmadsp_attach(adau->sigmadsp, component);
 		if (ret) {
-			dev_err(codec->dev, "Failed to attach firmware: %d\n",
+			dev_err(component->dev, "Failed to attach firmware: %d\n",
 				ret);
 			return ret;
 		}
@@ -894,10 +894,10 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
 
-int adau17x1_add_routes(struct snd_soc_codec *codec)
+int adau17x1_add_routes(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_soc_dapm_add_routes(dapm, adau17x1_dapm_routes,
@@ -920,12 +920,12 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(adau17x1_add_routes);
 
-int adau17x1_resume(struct snd_soc_codec *codec)
+int adau17x1_resume(struct snd_soc_component *component)
 {
-	struct adau *adau = snd_soc_codec_get_drvdata(codec);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
 
 	if (adau->switch_mode)
-		adau->switch_mode(codec->dev);
+		adau->switch_mode(component->dev);
 
 	regcache_sync(adau->regmap);
 
@@ -998,7 +998,6 @@ void adau17x1_remove(struct device *dev)
 {
 	struct adau *adau = dev_get_drvdata(dev);
 
-	snd_soc_unregister_codec(dev);
 	if (adau->mclk)
 		clk_disable_unprepare(adau->mclk);
 }
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index eaf8f933bab8..a7b1cb770814 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -53,18 +53,18 @@ struct adau {
 	struct sigmadsp *sigmadsp;
 };
 
-int adau17x1_add_widgets(struct snd_soc_codec *codec);
-int adau17x1_add_routes(struct snd_soc_codec *codec);
+int adau17x1_add_widgets(struct snd_soc_component *component);
+int adau17x1_add_routes(struct snd_soc_component *component);
 int adau17x1_probe(struct device *dev, struct regmap *regmap,
 	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
 	const char *firmware_name);
 void adau17x1_remove(struct device *dev);
-int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
+int adau17x1_set_micbias_voltage(struct snd_soc_component *component,
 	enum adau17x1_micbias_voltage micbias);
 bool adau17x1_readable_register(struct device *dev, unsigned int reg);
 bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
 bool adau17x1_precious_register(struct device *dev, unsigned int reg);
-int adau17x1_resume(struct snd_soc_codec *codec);
+int adau17x1_resume(struct snd_soc_component *component);
 
 extern const struct snd_soc_dai_ops adau17x1_dai_ops;
 
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
index 21e7394a972a..e7fe1ee5cdeb 100644
--- a/sound/soc/codecs/adau1977-i2c.c
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -29,12 +29,6 @@ static int adau1977_i2c_probe(struct i2c_client *client,
 		id->driver_data, NULL);
 }
 
-static int adau1977_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id adau1977_i2c_ids[] = {
 	{ "adau1977", ADAU1977 },
 	{ "adau1978", ADAU1978 },
@@ -48,7 +42,6 @@ static struct i2c_driver adau1977_i2c_driver = {
 		.name = "adau1977",
 	},
 	.probe = adau1977_i2c_probe,
-	.remove = adau1977_i2c_remove,
 	.id_table = adau1977_i2c_ids,
 };
 module_i2c_driver(adau1977_i2c_driver);
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c
index 0b46d88b481c..84ffbde9583f 100644
--- a/sound/soc/codecs/adau1977-spi.c
+++ b/sound/soc/codecs/adau1977-spi.c
@@ -46,12 +46,6 @@ static int adau1977_spi_probe(struct spi_device *spi)
 		id->driver_data, adau1977_spi_switch_mode);
 }
 
-static int adau1977_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static const struct spi_device_id adau1977_spi_ids[] = {
 	{ "adau1977", ADAU1977 },
 	{ "adau1978", ADAU1978 },
@@ -65,7 +59,6 @@ static struct spi_driver adau1977_spi_driver = {
 		.name = "adau1977",
 	},
 	.probe = adau1977_spi_probe,
-	.remove = adau1977_spi_remove,
 	.id_table = adau1977_spi_ids,
 };
 module_spi_driver(adau1977_spi_driver);
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index e384f212beb2..116af6a9ce3b 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -294,8 +294,8 @@ static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate,
 static int adau1977_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
 	unsigned int rate = params_rate(params);
 	unsigned int slot_width;
 	unsigned int ctrl0, ctrl0_mask;
@@ -471,10 +471,10 @@ static int adau1977_power_enable(struct adau1977 *adau1977)
 	return ret;
 }
 
-static int adau1977_set_bias_level(struct snd_soc_codec *codec,
+static int adau1977_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (level) {
@@ -483,7 +483,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			ret = adau1977_power_enable(adau1977);
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -497,7 +497,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
 static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	unsigned int rx_mask, int slots, int width)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int ctrl0, ctrl1, drv;
 	unsigned int slot[4];
 	unsigned int i;
@@ -603,7 +603,7 @@ static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
 static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int val;
 
 	if (mute)
@@ -617,7 +617,7 @@ static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
 
 static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0;
 	bool invert_lrclk;
 	int ret;
@@ -704,7 +704,7 @@ static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int adau1977_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
 	u64 formats = 0;
 
 	if (adau1977->slot_width == 16)
@@ -729,7 +729,7 @@ static int adau1977_startup(struct snd_pcm_substream *substream,
 
 static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int val;
 
 	if (tristate)
@@ -790,10 +790,10 @@ static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq)
 	return true;
 }
 
-static int adau1977_set_sysclk(struct snd_soc_codec *codec,
+static int adau1977_set_sysclk(struct snd_soc_component *component,
 	int clk_id, int source, unsigned int freq, int dir)
 {
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
 	unsigned int mask = 0;
 	unsigned int clk_src;
 	unsigned int ret;
@@ -844,10 +844,10 @@ static int adau1977_set_sysclk(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adau1977_codec_probe(struct snd_soc_codec *codec)
+static int adau1977_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (adau1977->type) {
@@ -865,20 +865,19 @@ static int adau1977_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver adau1977_codec_driver = {
-	.probe = adau1977_codec_probe,
-	.set_bias_level = adau1977_set_bias_level,
-	.set_sysclk = adau1977_set_sysclk,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= adau1977_snd_controls,
-		.num_controls		= ARRAY_SIZE(adau1977_snd_controls),
-		.dapm_widgets		= adau1977_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adau1977_dapm_widgets),
-		.dapm_routes		= adau1977_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adau1977_dapm_routes),
-	},
+static const struct snd_soc_component_driver adau1977_component_driver = {
+	.probe			= adau1977_component_probe,
+	.set_bias_level		= adau1977_set_bias_level,
+	.set_sysclk		= adau1977_set_sysclk,
+	.controls		= adau1977_snd_controls,
+	.num_controls		= ARRAY_SIZE(adau1977_snd_controls),
+	.dapm_widgets		= adau1977_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1977_dapm_widgets),
+	.dapm_routes		= adau1977_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1977_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int adau1977_setup_micbias(struct adau1977 *adau1977)
@@ -968,7 +967,7 @@ int adau1977_probe(struct device *dev, struct regmap *regmap,
 	if (ret)
 		return ret;
 
-	return snd_soc_register_codec(dev, &adau1977_codec_driver,
+	return devm_snd_soc_register_component(dev, &adau1977_component_driver,
 			&adau1977_dai, 1);
 
 err_poweroff:
diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c
index 6384c5491de8..fdff86878287 100644
--- a/sound/soc/codecs/adau7002.c
+++ b/sound/soc/codecs/adau7002.c
@@ -7,6 +7,7 @@
  * Licensed under the GPL-2.
  */
 
+#include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -38,24 +39,26 @@ static struct snd_soc_dai_driver adau7002_dai = {
 	},
 };
 
-static const struct snd_soc_codec_driver adau7002_codec_driver = {
-	.component_driver = {
-		.dapm_widgets		= adau7002_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adau7002_widgets),
-		.dapm_routes		= adau7002_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adau7002_routes),
-	},
+static const struct snd_soc_component_driver adau7002_component_driver = {
+	.dapm_widgets		= adau7002_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau7002_widgets),
+	.dapm_routes		= adau7002_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau7002_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int adau7002_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &adau7002_codec_driver,
+	return devm_snd_soc_register_component(&pdev->dev,
+			&adau7002_component_driver,
 			&adau7002_dai, 1);
 }
 
 static int adau7002_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
@@ -67,10 +70,19 @@ static const struct of_device_id adau7002_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, adau7002_dt_ids);
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id adau7002_acpi_match[] = {
+	{ "ADAU7002", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, adau7002_acpi_match);
+#endif
+
 static struct platform_driver adau7002_driver = {
 	.driver = {
 		.name = "adau7002",
 		.of_match_table	= of_match_ptr(adau7002_dt_ids),
+		.acpi_match_table = ACPI_PTR(adau7002_acpi_match),
 	},
 	.probe = adau7002_probe,
 	.remove = adau7002_remove,
diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c
index 055f1228c2b4..d82f79dd1b38 100644
--- a/sound/soc/codecs/adav801.c
+++ b/sound/soc/codecs/adav801.c
@@ -30,18 +30,11 @@ static int adav80x_spi_probe(struct spi_device *spi)
 	return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
 }
 
-static int adav80x_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver adav80x_spi_driver = {
 	.driver = {
 		.name	= "adav801",
 	},
 	.probe		= adav80x_spi_probe,
-	.remove		= adav80x_spi_remove,
 	.id_table	= adav80x_spi_id,
 };
 module_spi_driver(adav80x_spi_driver);
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
index 52881faedcf6..deb14bc0f1f7 100644
--- a/sound/soc/codecs/adav803.c
+++ b/sound/soc/codecs/adav803.c
@@ -27,18 +27,11 @@ static int adav803_probe(struct i2c_client *client,
 		devm_regmap_init_i2c(client, &adav80x_regmap_config));
 }
 
-static int adav803_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static struct i2c_driver adav803_driver = {
 	.driver = {
 		.name = "adav803",
 	},
 	.probe = adav803_probe,
-	.remove = adav803_remove,
 	.id_table = adav803_id,
 };
 module_i2c_driver(adav803_driver);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index da7ca81f47cf..db21ecbe0762 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -212,8 +212,8 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
 static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	const char *clk;
 
 	switch (adav80x->clk_src) {
@@ -236,8 +236,8 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
 static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 
 	return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
 }
@@ -281,9 +281,9 @@ static const struct snd_soc_dapm_route adav80x_dapm_routes[] = {
 	{ "AIFAUXIN", NULL, "SYSCLK" },
 };
 
-static int adav80x_set_deemph(struct snd_soc_codec *codec)
+static int adav80x_set_deemph(struct snd_soc_component *component)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (adav80x->deemph) {
@@ -315,8 +315,8 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec)
 static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 
 	if (deemph > 1)
@@ -324,14 +324,14 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
 
 	adav80x->deemph = deemph;
 
-	return adav80x_set_deemph(codec);
+	return adav80x_set_deemph(component);
 }
 
 static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = adav80x->deemph;
 	return 0;
@@ -365,8 +365,8 @@ static unsigned int adav80x_port_ctrl_regs[2][2] = {
 
 static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int capture = 0x00;
 	unsigned int playback = 0x00;
 
@@ -415,10 +415,10 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 }
 
-static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
+static int adav80x_set_adc_clock(struct snd_soc_component *component,
 		unsigned int sample_rate)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (sample_rate <= 48000)
@@ -432,10 +432,10 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
+static int adav80x_set_dac_clock(struct snd_soc_component *component,
 		unsigned int sample_rate)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (sample_rate <= 48000)
@@ -450,10 +450,10 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
+static int adav80x_set_capture_pcm_format(struct snd_soc_component *component,
 		struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	switch (params_width(params)) {
@@ -479,10 +479,10 @@ static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
+static int adav80x_set_playback_pcm_format(struct snd_soc_component *component,
 		struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)
@@ -514,32 +514,32 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
 static int adav80x_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int rate = params_rate(params);
 
 	if (rate * 256 != adav80x->sysclk)
 		return -EINVAL;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		adav80x_set_playback_pcm_format(codec, dai, params);
-		adav80x_set_dac_clock(codec, rate);
+		adav80x_set_playback_pcm_format(component, dai, params);
+		adav80x_set_dac_clock(component, rate);
 	} else {
-		adav80x_set_capture_pcm_format(codec, dai, params);
-		adav80x_set_adc_clock(codec, rate);
+		adav80x_set_capture_pcm_format(component, dai, params);
+		adav80x_set_adc_clock(component, rate);
 	}
 	adav80x->rate = rate;
-	adav80x_set_deemph(codec);
+	adav80x_set_deemph(component);
 
 	return 0;
 }
 
-static int adav80x_set_sysclk(struct snd_soc_codec *codec,
+static int adav80x_set_sysclk(struct snd_soc_component *component,
 			      int clk_id, int source,
 			      unsigned int freq, int dir)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (dir == SND_SOC_CLOCK_IN) {
 		switch (clk_id) {
@@ -619,11 +619,11 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
+static int adav80x_set_pll(struct snd_soc_component *component, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int pll_ctrl1 = 0;
 	unsigned int pll_ctrl2 = 0;
 	unsigned int pll_src;
@@ -694,10 +694,10 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
 	return 0;
 }
 
-static int adav80x_set_bias_level(struct snd_soc_codec *codec,
+static int adav80x_set_bias_level(struct snd_soc_component *component,
 		enum snd_soc_bias_level level)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 	unsigned int mask = ADAV80X_DAC_CTRL1_PD;
 
 	switch (level) {
@@ -722,10 +722,10 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,
 static int adav80x_dai_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 
-	if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
+	if (!snd_soc_component_is_active(component) || !adav80x->rate)
 		return 0;
 
 	return snd_pcm_hw_constraint_single(substream->runtime,
@@ -735,10 +735,10 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,
 static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 
-	if (!snd_soc_codec_is_active(codec))
+	if (!snd_soc_component_is_active(component))
 		adav80x->rate = 0;
 }
 
@@ -799,10 +799,10 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
 	},
 };
 
-static int adav80x_probe(struct snd_soc_codec *codec)
+static int adav80x_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 
 	/* Force PLLs on for SYSCLK output */
 	snd_soc_dapm_force_enable_pin(dapm, "PLL1");
@@ -816,32 +816,32 @@ static int adav80x_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int adav80x_resume(struct snd_soc_codec *codec)
+static int adav80x_resume(struct snd_soc_component *component)
 {
-	struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
 
 	regcache_sync(adav80x->regmap);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver adav80x_codec_driver = {
-	.probe = adav80x_probe,
-	.resume = adav80x_resume,
-	.set_bias_level = adav80x_set_bias_level,
-	.suspend_bias_off = true,
-
-	.set_pll = adav80x_set_pll,
-	.set_sysclk = adav80x_set_sysclk,
-
-	.component_driver = {
-		.controls		= adav80x_controls,
-		.num_controls		= ARRAY_SIZE(adav80x_controls),
-		.dapm_widgets		= adav80x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(adav80x_dapm_widgets),
-		.dapm_routes		= adav80x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(adav80x_dapm_routes),
-	},
+static const struct snd_soc_component_driver adav80x_component_driver = {
+	.probe			= adav80x_probe,
+	.resume			= adav80x_resume,
+	.set_bias_level		= adav80x_set_bias_level,
+	.set_pll		= adav80x_set_pll,
+	.set_sysclk		= adav80x_set_sysclk,
+	.controls		= adav80x_controls,
+	.num_controls		= ARRAY_SIZE(adav80x_controls),
+	.dapm_widgets		= adav80x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adav80x_dapm_widgets),
+	.dapm_routes		= adav80x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adav80x_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
@@ -858,7 +858,7 @@ int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
 	dev_set_drvdata(dev, adav80x);
 	adav80x->regmap = regmap;
 
-	return snd_soc_register_codec(dev, &adav80x_codec_driver,
+	return devm_snd_soc_register_component(dev, &adav80x_component_driver,
 		adav80x_dais, ARRAY_SIZE(adav80x_dais));
 }
 EXPORT_SYMBOL_GPL(adav80x_bus_probe);
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index b7f0057c0239..bcd45ff5db0c 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -58,25 +58,21 @@ static struct snd_soc_dai_driver ads117x_dai = {
 		.formats = ADS117X_FORMATS,},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_ads117x = {
-	.component_driver = {
-		.dapm_widgets		= ads117x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ads117x_dapm_widgets),
-		.dapm_routes		= ads117x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ads117x_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ads117x = {
+	.dapm_widgets		= ads117x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ads117x_dapm_widgets),
+	.dapm_routes		= ads117x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ads117x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ads117x_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_ads117x, &ads117x_dai, 1);
-}
-
-static int ads117x_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ads117x, &ads117x_dai, 1);
 }
 
 #if defined(CONFIG_OF)
@@ -95,7 +91,6 @@ static struct platform_driver ads117x_codec_driver = {
 	},
 
 	.probe = ads117x_probe,
-	.remove = ads117x_remove,
 };
 
 module_platform_driver(ads117x_codec_driver);
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index dbb184118f2e..32bc545c19cf 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -65,8 +65,8 @@ static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
 static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
 	int val = 0;
 	int ret;
 
@@ -81,7 +81,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
 		break;
 	default:
-		dev_err(codec->dev, "invalid dai format\n");
+		dev_err(component->dev, "invalid dai format\n");
 		return -EINVAL;
 	}
 
@@ -102,8 +102,8 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
 	int ret, val = 0;
 
 	/* set the IEC958 bits: consumer mode, no copyright bit */
@@ -141,7 +141,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
 		val |= IEC958_AES3_CON_FS_192000;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported sampling rate\n");
+		dev_err(component->dev, "unsupported sampling rate\n");
 		return -EINVAL;
 	}
 
@@ -174,14 +174,14 @@ static struct snd_soc_dai_driver ak4104_dai = {
 	.ops = &ak4101_dai_ops,
 };
 
-static int ak4104_probe(struct snd_soc_codec *codec)
+static int ak4104_probe(struct snd_soc_component *component)
 {
-	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_enable(ak4104->regulator);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unable to enable regulator: %d\n", ret);
+		dev_err(component->dev, "Unable to enable regulator: %d\n", ret);
 		return ret;
 	}
 
@@ -205,30 +205,28 @@ static int ak4104_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int ak4104_remove(struct snd_soc_codec *codec)
+static void ak4104_remove(struct snd_soc_component *component)
 {
-	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
 
 	regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
 			   AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
 	regulator_disable(ak4104->regulator);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int ak4104_soc_suspend(struct snd_soc_codec *codec)
+static int ak4104_soc_suspend(struct snd_soc_component *component)
 {
-	struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
 
 	regulator_disable(priv->regulator);
 
 	return 0;
 }
 
-static int ak4104_soc_resume(struct snd_soc_codec *codec)
+static int ak4104_soc_resume(struct snd_soc_component *component)
 {
-	struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_enable(priv->regulator);
@@ -242,18 +240,19 @@ static int ak4104_soc_resume(struct snd_soc_codec *codec)
 #define ak4104_soc_resume	NULL
 #endif /* CONFIG_PM */
 
-static const struct snd_soc_codec_driver soc_codec_device_ak4104 = {
-	.probe = ak4104_probe,
-	.remove = ak4104_remove,
-	.suspend = ak4104_soc_suspend,
-	.resume = ak4104_soc_resume,
-
-	.component_driver = {
-		.dapm_widgets		= ak4104_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4104_dapm_widgets),
-		.dapm_routes		= ak4104_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ak4104_dapm_routes),
-	}
+static const struct snd_soc_component_driver soc_component_device_ak4104 = {
+	.probe			= ak4104_probe,
+	.remove			= ak4104_remove,
+	.suspend		= ak4104_soc_suspend,
+	.resume			= ak4104_soc_resume,
+	.dapm_widgets		= ak4104_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4104_dapm_widgets),
+	.dapm_routes		= ak4104_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ak4104_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ak4104_regmap = {
@@ -323,17 +322,11 @@ static int ak4104_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, ak4104);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_device_ak4104, &ak4104_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_device_ak4104, &ak4104_dai, 1);
 	return ret;
 }
 
-static int ak4104_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static const struct of_device_id ak4104_of_match[] = {
 	{ .compatible = "asahi-kasei,ak4104", },
 	{ }
@@ -353,7 +346,6 @@ static struct spi_driver ak4104_spi_driver = {
 	},
 	.id_table = ak4104_id_table,
 	.probe  = ak4104_spi_probe,
-	.remove = ak4104_spi_remove,
 };
 
 module_spi_driver(ak4104_spi_driver);
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
new file mode 100644
index 000000000000..d2815ac9cffa
--- /dev/null
+++ b/sound/soc/codecs/ak4458.c
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Audio driver for AK4458 DAC
+ *
+ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation
+ * Copyright 2018 NXP
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/i2c.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+
+#include "ak4458.h"
+
+/* AK4458 Codec Private Data */
+struct ak4458_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct gpio_desc *reset_gpiod;
+	struct gpio_desc *mute_gpiod;
+	int digfil;	/* SSLOW, SD, SLOW bits */
+	int fs;		/* sampling rate */
+	int fmt;
+	int slots;
+	int slot_width;
+};
+
+static const struct reg_default ak4458_reg_defaults[] = {
+	{ 0x00, 0x0C },	/*	0x00	AK4458_00_CONTROL1	*/
+	{ 0x01, 0x22 },	/*	0x01	AK4458_01_CONTROL2	*/
+	{ 0x02, 0x00 },	/*	0x02	AK4458_02_CONTROL3	*/
+	{ 0x03, 0xFF },	/*	0x03	AK4458_03_LCHATT	*/
+	{ 0x04, 0xFF },	/*	0x04	AK4458_04_RCHATT	*/
+	{ 0x05, 0x00 },	/*	0x05	AK4458_05_CONTROL4	*/
+	{ 0x06, 0x00 },	/*	0x06	AK4458_06_DSD1		*/
+	{ 0x07, 0x03 },	/*	0x07	AK4458_07_CONTROL5	*/
+	{ 0x08, 0x00 },	/*	0x08	AK4458_08_SOUND_CONTROL	*/
+	{ 0x09, 0x00 },	/*	0x09	AK4458_09_DSD2		*/
+	{ 0x0A, 0x0D },	/*	0x0A	AK4458_0A_CONTROL6	*/
+	{ 0x0B, 0x0C },	/*	0x0B	AK4458_0B_CONTROL7	*/
+	{ 0x0C, 0x00 },	/*	0x0C	AK4458_0C_CONTROL8	*/
+	{ 0x0D, 0x00 },	/*	0x0D	AK4458_0D_CONTROL9	*/
+	{ 0x0E, 0x50 },	/*	0x0E	AK4458_0E_CONTROL10	*/
+	{ 0x0F, 0xFF },	/*	0x0F	AK4458_0F_L2CHATT	*/
+	{ 0x10, 0xFF },	/*	0x10	AK4458_10_R2CHATT	*/
+	{ 0x11, 0xFF },	/*	0x11	AK4458_11_L3CHATT	*/
+	{ 0x12, 0xFF },	/*	0x12	AK4458_12_R3CHATT	*/
+	{ 0x13, 0xFF },	/*	0x13	AK4458_13_L4CHATT	*/
+	{ 0x14, 0xFF },	/*	0x14	AK4458_14_R4CHATT	*/
+};
+
+/*
+ * Volume control:
+ * from -127 to 0 dB in 0.5 dB steps (mute instead of -127.5 dB)
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+
+/*
+ * DEM1 bit DEM0 bit Mode
+ * 0 0 44.1kHz
+ * 0 1 OFF (default)
+ * 1 0 48kHz
+ * 1 1 32kHz
+ */
+static const char * const ak4458_dem_select_texts[] = {
+	"44.1kHz", "OFF", "48kHz", "32kHz"
+};
+
+/*
+ * SSLOW, SD, SLOW bits Digital Filter Setting
+ * 0, 0, 0 : Sharp Roll-Off Filter
+ * 0, 0, 1 : Slow Roll-Off Filter
+ * 0, 1, 0 : Short delay Sharp Roll-Off Filter
+ * 0, 1, 1 : Short delay Slow Roll-Off Filter
+ * 1, *, * : Super Slow Roll-Off Filter
+ */
+static const char * const ak4458_digfil_select_texts[] = {
+	"Sharp Roll-Off Filter",
+	"Slow Roll-Off Filter",
+	"Short delay Sharp Roll-Off Filter",
+	"Short delay Slow Roll-Off Filter",
+	"Super Slow Roll-Off Filter"
+};
+
+/*
+ * DZFB: Inverting Enable of DZF
+ * 0: DZF goes H at Zero Detection
+ * 1: DZF goes L at Zero Detection
+ */
+static const char * const ak4458_dzfb_select_texts[] = {"H", "L"};
+
+/*
+ * SC1-0 bits: Sound Mode Setting
+ * 0 0 : Sound Mode 0
+ * 0 1 : Sound Mode 1
+ * 1 0 : Sound Mode 2
+ * 1 1 : Reserved
+ */
+static const char * const ak4458_sc_select_texts[] = {
+	"Sound Mode 0", "Sound Mode 1", "Sound Mode 2"
+};
+
+/* FIR2-0 bits: FIR Filter Mode Setting */
+static const char * const ak4458_fir_select_texts[] = {
+	"Mode 0", "Mode 1", "Mode 2", "Mode 3",
+	"Mode 4", "Mode 5", "Mode 6", "Mode 7",
+};
+
+/* ATS1-0 bits Attenuation Speed */
+static const char * const ak4458_ats_select_texts[] = {
+	"4080/fs", "2040/fs", "510/fs", "255/fs",
+};
+
+/* DIF2 bit Audio Interface Format Setting(BICK fs) */
+static const char * const ak4458_dif_select_texts[] = {"32fs,48fs", "64fs",};
+
+static const struct soc_enum ak4458_dac1_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_01_CONTROL2, 1,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_dac2_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_0A_CONTROL6, 0,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_dac3_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_0E_CONTROL10, 4,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_dac4_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_0E_CONTROL10, 6,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_digfil_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4458_digfil_select_texts),
+			    ak4458_digfil_select_texts);
+static const struct soc_enum ak4458_dzfb_enum =
+	SOC_ENUM_SINGLE(AK4458_02_CONTROL3, 2,
+			ARRAY_SIZE(ak4458_dzfb_select_texts),
+			ak4458_dzfb_select_texts);
+static const struct soc_enum ak4458_sm_enum =
+	SOC_ENUM_SINGLE(AK4458_08_SOUND_CONTROL, 0,
+			ARRAY_SIZE(ak4458_sc_select_texts),
+			ak4458_sc_select_texts);
+static const struct soc_enum ak4458_fir_enum =
+	SOC_ENUM_SINGLE(AK4458_0C_CONTROL8, 0,
+			ARRAY_SIZE(ak4458_fir_select_texts),
+			ak4458_fir_select_texts);
+static const struct soc_enum ak4458_ats_enum =
+	SOC_ENUM_SINGLE(AK4458_0B_CONTROL7, 6,
+			ARRAY_SIZE(ak4458_ats_select_texts),
+			ak4458_ats_select_texts);
+static const struct soc_enum ak4458_dif_enum =
+	SOC_ENUM_SINGLE(AK4458_00_CONTROL1, 3,
+			ARRAY_SIZE(ak4458_dif_select_texts),
+			ak4458_dif_select_texts);
+
+static int get_digfil(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = ak4458->digfil;
+
+	return 0;
+}
+
+static int set_digfil(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int num;
+
+	num = ucontrol->value.enumerated.item[0];
+	if (num > 4)
+		return -EINVAL;
+
+	ak4458->digfil = num;
+
+	/* write SD bit */
+	snd_soc_component_update_bits(component, AK4458_01_CONTROL2,
+			    AK4458_SD_MASK,
+			    ((ak4458->digfil & 0x02) << 4));
+
+	/* write SLOW bit */
+	snd_soc_component_update_bits(component, AK4458_02_CONTROL3,
+			    AK4458_SLOW_MASK,
+			    (ak4458->digfil & 0x01));
+
+	/* write SSLOW bit */
+	snd_soc_component_update_bits(component, AK4458_05_CONTROL4,
+			    AK4458_SSLOW_MASK,
+			    ((ak4458->digfil & 0x04) >> 2));
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new ak4458_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", AK4458_03_LCHATT,
+			 AK4458_04_RCHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", AK4458_0F_L2CHATT,
+			 AK4458_10_R2CHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", AK4458_11_L3CHATT,
+			 AK4458_12_R3CHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", AK4458_13_L4CHATT,
+			 AK4458_14_R4CHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_ENUM("AK4458 De-emphasis Response DAC1", ak4458_dac1_dem_enum),
+	SOC_ENUM("AK4458 De-emphasis Response DAC2", ak4458_dac2_dem_enum),
+	SOC_ENUM("AK4458 De-emphasis Response DAC3", ak4458_dac3_dem_enum),
+	SOC_ENUM("AK4458 De-emphasis Response DAC4", ak4458_dac4_dem_enum),
+	SOC_ENUM_EXT("AK4458 Digital Filter Setting", ak4458_digfil_enum,
+		     get_digfil, set_digfil),
+	SOC_ENUM("AK4458 Inverting Enable of DZFB", ak4458_dzfb_enum),
+	SOC_ENUM("AK4458 Sound Mode", ak4458_sm_enum),
+	SOC_ENUM("AK4458 FIR Filter Mode Setting", ak4458_fir_enum),
+	SOC_ENUM("AK4458 Attenuation transition Time Setting",
+		 ak4458_ats_enum),
+	SOC_ENUM("AK4458 BICK fs Setting", ak4458_dif_enum),
+};
+
+/* ak4458 dapm widgets */
+static const struct snd_soc_dapm_widget ak4458_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("AK4458 DAC1", NULL, AK4458_0A_CONTROL6, 2, 0),/*pw*/
+	SND_SOC_DAPM_AIF_IN("AK4458 SDTI", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTA"),
+
+	SND_SOC_DAPM_DAC("AK4458 DAC2", NULL, AK4458_0A_CONTROL6, 3, 0),/*pw*/
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTB"),
+
+	SND_SOC_DAPM_DAC("AK4458 DAC3", NULL, AK4458_0B_CONTROL7, 2, 0),/*pw*/
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTC"),
+
+	SND_SOC_DAPM_DAC("AK4458 DAC4", NULL, AK4458_0B_CONTROL7, 3, 0),/*pw*/
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTD"),
+};
+
+static const struct snd_soc_dapm_route ak4458_intercon[] = {
+	{"AK4458 DAC1",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTA",	NULL,	"AK4458 DAC1"},
+
+	{"AK4458 DAC2",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTB",	NULL,	"AK4458 DAC2"},
+
+	{"AK4458 DAC3",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTC",	NULL,	"AK4458 DAC3"},
+
+	{"AK4458 DAC4",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTD",	NULL,	"AK4458 DAC4"},
+};
+
+static int ak4458_rstn_control(struct snd_soc_component *component, int bit)
+{
+	int ret;
+
+	if (bit)
+		ret = snd_soc_component_update_bits(component,
+					  AK4458_00_CONTROL1,
+					  AK4458_RSTN_MASK,
+					  0x1);
+	else
+		ret = snd_soc_component_update_bits(component,
+					  AK4458_00_CONTROL1,
+					  AK4458_RSTN_MASK,
+					  0x0);
+	return ret;
+}
+
+static int ak4458_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int pcm_width = max(params_physical_width(params), ak4458->slot_width);
+	int nfs1;
+	u8 format;
+
+	nfs1 = params_rate(params);
+	ak4458->fs = nfs1;
+
+	/* Master Clock Frequency Auto Setting Mode Enable */
+	snd_soc_component_update_bits(component, AK4458_00_CONTROL1, 0x80, 0x80);
+
+	switch (pcm_width) {
+	case 16:
+		if (ak4458->fmt == SND_SOC_DAIFMT_I2S)
+			format = AK4458_DIF_24BIT_I2S;
+		else
+			format = AK4458_DIF_16BIT_LSB;
+		break;
+	case 32:
+		switch (ak4458->fmt) {
+		case SND_SOC_DAIFMT_I2S:
+			format = AK4458_DIF_32BIT_I2S;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			format = AK4458_DIF_32BIT_MSB;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			format = AK4458_DIF_32BIT_LSB;
+			break;
+		case SND_SOC_DAIFMT_DSP_B:
+			format = AK4458_DIF_32BIT_MSB;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
+			    AK4458_DIF_MASK, format);
+
+	ak4458_rstn_control(component, 0);
+	ak4458_rstn_control(component, 1);
+
+	return 0;
+}
+
+static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM: /* Master Mode is not supported */
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		dev_err(component->dev, "Master mode unsupported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_DSP_B:
+		ak4458->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(component->dev, "Audio format 0x%02X unsupported\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	ak4458_rstn_control(component, 0);
+	ak4458_rstn_control(component, 1);
+
+	return 0;
+}
+
+static const int att_speed[] = { 4080, 2040, 510, 255 };
+
+static int ak4458_set_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int nfs, ndt, ret, reg;
+	int ats;
+
+	nfs = ak4458->fs;
+
+	reg = snd_soc_component_read32(component, AK4458_0B_CONTROL7);
+	ats = (reg & AK4458_ATS_MASK) >> AK4458_ATS_SHIFT;
+
+	ndt = att_speed[ats] / (nfs / 1000);
+
+	if (mute) {
+		ret = snd_soc_component_update_bits(component, AK4458_01_CONTROL2,  0x01, 1);
+		mdelay(ndt);
+		if (ak4458->mute_gpiod)
+			gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
+	} else {
+		if (ak4458->mute_gpiod)
+			gpiod_set_value_cansleep(ak4458->mute_gpiod, 0);
+		ret = snd_soc_component_update_bits(component, AK4458_01_CONTROL2, 0x01, 0);
+		mdelay(ndt);
+	}
+
+	return 0;
+}
+
+static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int mode;
+
+	ak4458->slots = slots;
+	ak4458->slot_width = slot_width;
+
+	switch (slots * slot_width) {
+	case 128:
+		mode = AK4458_MODE_TDM128;
+		break;
+	case 256:
+		mode = AK4458_MODE_TDM256;
+		break;
+	case 512:
+		mode = AK4458_MODE_TDM512;
+		break;
+	default:
+		mode = AK4458_MODE_NORMAL;
+		break;
+	}
+
+	snd_soc_component_update_bits(component, AK4458_0A_CONTROL6,
+			    AK4458_MODE_MASK,
+			    mode);
+
+	return 0;
+}
+
+#define AK4458_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static const unsigned int ak4458_rates[] = {
+	8000, 11025,  16000, 22050,
+	32000, 44100, 48000, 88200,
+	96000, 176400, 192000, 352800,
+	384000, 705600, 768000, 1411200,
+	2822400,
+};
+
+static const struct snd_pcm_hw_constraint_list ak4458_rate_constraints = {
+	.count = ARRAY_SIZE(ak4458_rates),
+	.list = ak4458_rates,
+};
+
+static int ak4458_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	int ret;
+
+	ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &ak4458_rate_constraints);
+
+	return ret;
+}
+
+static struct snd_soc_dai_ops ak4458_dai_ops = {
+	.startup        = ak4458_startup,
+	.hw_params	= ak4458_hw_params,
+	.set_fmt	= ak4458_set_dai_fmt,
+	.digital_mute	= ak4458_set_dai_mute,
+	.set_tdm_slot	= ak4458_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ak4458_dai = {
+	.name = "ak4458-aif",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = AK4458_FORMATS,
+	},
+	.ops = &ak4458_dai_ops,
+};
+
+static void ak4458_power_off(struct ak4458_priv *ak4458)
+{
+	if (ak4458->reset_gpiod) {
+		gpiod_set_value_cansleep(ak4458->reset_gpiod, 0);
+		usleep_range(1000, 2000);
+	}
+}
+
+static void ak4458_power_on(struct ak4458_priv *ak4458)
+{
+	if (ak4458->reset_gpiod) {
+		gpiod_set_value_cansleep(ak4458->reset_gpiod, 1);
+		usleep_range(1000, 2000);
+	}
+}
+
+static void ak4458_init(struct snd_soc_component *component)
+{
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	/* External Mute ON */
+	if (ak4458->mute_gpiod)
+		gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
+
+	ak4458_power_on(ak4458);
+
+	snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
+			    0x80, 0x80);   /* ACKS bit = 1; 10000000 */
+
+	ak4458_rstn_control(component, 1);
+}
+
+static int ak4458_probe(struct snd_soc_component *component)
+{
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	ak4458_init(component);
+
+	ak4458->fs = 48000;
+
+	return 0;
+}
+
+static void ak4458_remove(struct snd_soc_component *component)
+{
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	ak4458_power_off(ak4458);
+}
+
+#ifdef CONFIG_PM
+static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
+{
+	struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
+
+	regcache_cache_only(ak4458->regmap, true);
+
+	ak4458_power_off(ak4458);
+
+	if (ak4458->mute_gpiod)
+		gpiod_set_value_cansleep(ak4458->mute_gpiod, 0);
+
+	return 0;
+}
+
+static int __maybe_unused ak4458_runtime_resume(struct device *dev)
+{
+	struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
+
+	if (ak4458->mute_gpiod)
+		gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
+
+	ak4458_power_off(ak4458);
+	ak4458_power_on(ak4458);
+
+	regcache_cache_only(ak4458->regmap, false);
+	regcache_mark_dirty(ak4458->regmap);
+
+	return regcache_sync(ak4458->regmap);
+}
+#endif /* CONFIG_PM */
+
+struct snd_soc_component_driver soc_codec_dev_ak4458 = {
+	.probe			= ak4458_probe,
+	.remove			= ak4458_remove,
+	.controls		= ak4458_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4458_snd_controls),
+	.dapm_widgets		= ak4458_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4458_dapm_widgets),
+	.dapm_routes		= ak4458_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4458_intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak4458_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4458_14_R4CHATT,
+	.reg_defaults = ak4458_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4458_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct dev_pm_ops ak4458_pm = {
+	SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static int ak4458_i2c_probe(struct i2c_client *i2c)
+{
+	struct ak4458_priv *ak4458;
+	int ret;
+
+	ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL);
+	if (!ak4458)
+		return -ENOMEM;
+
+	ak4458->regmap = devm_regmap_init_i2c(i2c, &ak4458_regmap);
+	if (IS_ERR(ak4458->regmap))
+		return PTR_ERR(ak4458->regmap);
+
+	i2c_set_clientdata(i2c, ak4458);
+	ak4458->dev = &i2c->dev;
+
+	ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(ak4458->reset_gpiod))
+		return PTR_ERR(ak4458->reset_gpiod);
+
+	ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute",
+						     GPIOD_OUT_LOW);
+	if (IS_ERR(ak4458->mute_gpiod))
+		return PTR_ERR(ak4458->mute_gpiod);
+
+	ret = devm_snd_soc_register_component(ak4458->dev, &soc_codec_dev_ak4458,
+				     &ak4458_dai, 1);
+	if (ret < 0) {
+		dev_err(ak4458->dev, "Failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(&i2c->dev);
+
+	return 0;
+}
+
+static int ak4458_i2c_remove(struct i2c_client *i2c)
+{
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static const struct of_device_id ak4458_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4458", },
+	{ },
+};
+
+static struct i2c_driver ak4458_i2c_driver = {
+	.driver = {
+		.name = "ak4458",
+		.pm = &ak4458_pm,
+		.of_match_table = ak4458_of_match,
+		},
+	.probe_new = ak4458_i2c_probe,
+	.remove = ak4458_i2c_remove,
+};
+
+module_i2c_driver(ak4458_i2c_driver);
+
+MODULE_AUTHOR("Junichi Wakasugi <wakasugi.jb@om.asahi-kasei.co.jp>");
+MODULE_AUTHOR("Mihai Serban <mihai.serban@nxp.com>");
+MODULE_DESCRIPTION("ASoC AK4458 DAC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4458.h b/sound/soc/codecs/ak4458.h
new file mode 100644
index 000000000000..16d9d22a413a
--- /dev/null
+++ b/sound/soc/codecs/ak4458.h
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Audio driver for AK4458
+ *
+ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation
+ * Copyright 2018 NXP
+ */
+
+#ifndef _AK4458_H
+#define _AK4458_H
+
+#include <linux/regmap.h>
+
+/* Settings */
+
+#define AK4458_00_CONTROL1			0x00
+#define AK4458_01_CONTROL2			0x01
+#define AK4458_02_CONTROL3			0x02
+#define AK4458_03_LCHATT			0x03
+#define AK4458_04_RCHATT			0x04
+#define AK4458_05_CONTROL4			0x05
+#define AK4458_06_DSD1				0x06
+#define AK4458_07_CONTROL5			0x07
+#define AK4458_08_SOUND_CONTROL			0x08
+#define AK4458_09_DSD2				0x09
+#define AK4458_0A_CONTROL6			0x0A
+#define AK4458_0B_CONTROL7			0x0B
+#define AK4458_0C_CONTROL8			0x0C
+#define AK4458_0D_CONTROL9			0x0D
+#define AK4458_0E_CONTROL10			0x0E
+#define AK4458_0F_L2CHATT			0x0F
+#define AK4458_10_R2CHATT			0x10
+#define AK4458_11_L3CHATT			0x11
+#define AK4458_12_R3CHATT			0x12
+#define AK4458_13_L4CHATT			0x13
+#define AK4458_14_R4CHATT			0x14
+
+/* Bitfield Definitions */
+
+/* AK4458_00_CONTROL1 (0x00) Fields
+ * Addr Register Name  D7     D6    D5    D4    D3    D2    D1    D0
+ * 00H  Control 1      ACKS   0     0     0     DIF2  DIF1  DIF0  RSTN
+ */
+
+/* Digital Filter (SD, SLOW, SSLOW) */
+#define AK4458_SD_MASK		GENMASK(5, 5)
+#define AK4458_SLOW_MASK	GENMASK(0, 0)
+#define AK4458_SSLOW_MASK	GENMASK(0, 0)
+
+/* DIF2	1 0
+ *  x	1 0 MSB justified  Figure 3 (default)
+ *  x	1 1 I2S Compliment  Figure 4
+ */
+#define AK4458_DIF_SHIFT	1
+#define AK4458_DIF_MASK		GENMASK(3, 1)
+
+#define AK4458_DIF_16BIT_LSB	(0 << 1)
+#define AK4458_DIF_24BIT_I2S	(3 << 1)
+#define AK4458_DIF_32BIT_LSB	(5 << 1)
+#define AK4458_DIF_32BIT_MSB	(6 << 1)
+#define AK4458_DIF_32BIT_I2S	(7 << 1)
+
+/* AK4458_00_CONTROL1 (0x00) D0 bit */
+#define AK4458_RSTN_MASK	GENMASK(0, 0)
+#define AK4458_RSTN		(0x1 << 0)
+
+/* AK4458_0A_CONTROL6 Mode bits */
+#define AK4458_MODE_SHIFT	6
+#define AK4458_MODE_MASK	GENMASK(7, 6)
+#define AK4458_MODE_NORMAL	(0 << AK4458_MODE_SHIFT)
+#define AK4458_MODE_TDM128	(1 << AK4458_MODE_SHIFT)
+#define AK4458_MODE_TDM256	(2 << AK4458_MODE_SHIFT)
+#define AK4458_MODE_TDM512	(3 << AK4458_MODE_SHIFT)
+
+/* DAC Digital attenuator transition time setting
+ * Table 19
+ * Mode	ATS1	ATS2	ATT speed
+ * 0	0	0	4080/fs
+ * 1	0	1	2040/fs
+ * 2	1	0	510/fs
+ * 3	1	1	255/fs
+ * */
+#define AK4458_ATS_SHIFT	6
+#define AK4458_ATS_MASK		GENMASK(7, 6)
+
+#endif /* _AK4458_H */
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index e3c157dc88db..31f609910bd6 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -251,8 +251,8 @@ static const struct snd_soc_dapm_route ak4535_audio_map[] = {
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4535_priv *ak4535 = snd_soc_component_get_drvdata(component);
 
 	ak4535->sysclk = freq;
 	return 0;
@@ -262,9 +262,9 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
-	u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
+	struct snd_soc_component *component = dai->component;
+	struct ak4535_priv *ak4535 = snd_soc_component_get_drvdata(component);
+	u8 mode2 = snd_soc_component_read32(component, AK4535_MODE2) & ~(0x3 << 5);
 	int rate = params_rate(params), fs = 256;
 
 	if (rate)
@@ -283,14 +283,14 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set rate */
-	snd_soc_write(codec, AK4535_MODE2, mode2);
+	snd_soc_component_write(component, AK4535_MODE2, mode2);
 	return 0;
 }
 
 static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 mode1 = 0;
 
 	/* interface format */
@@ -308,37 +308,37 @@ static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	/* use 32 fs for BCLK to save power */
 	mode1 |= 0x4;
 
-	snd_soc_write(codec, AK4535_MODE1, mode1);
+	snd_soc_component_write(component, AK4535_MODE1, mode1);
 	return 0;
 }
 
 static int ak4535_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, AK4535_DAC);
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, AK4535_DAC);
 	if (!mute)
-		snd_soc_write(codec, AK4535_DAC, mute_reg & ~0x20);
+		snd_soc_component_write(component, AK4535_DAC, mute_reg & ~0x20);
 	else
-		snd_soc_write(codec, AK4535_DAC, mute_reg | 0x20);
+		snd_soc_component_write(component, AK4535_DAC, mute_reg | 0x20);
 	return 0;
 }
 
-static int ak4535_set_bias_level(struct snd_soc_codec *codec,
+static int ak4535_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0);
+		snd_soc_component_update_bits(component, AK4535_DAC, 0x20, 0);
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0x20);
+		snd_soc_component_update_bits(component, AK4535_DAC, 0x20, 0x20);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0x80);
-		snd_soc_update_bits(codec, AK4535_PM2, 0x80, 0);
+		snd_soc_component_update_bits(component, AK4535_PM1, 0x80, 0x80);
+		snd_soc_component_update_bits(component, AK4535_PM2, 0x80, 0);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
+		snd_soc_component_update_bits(component, AK4535_PM1, 0x80, 0);
 		break;
 	}
 	return 0;
@@ -372,9 +372,9 @@ static struct snd_soc_dai_driver ak4535_dai = {
 	.ops = &ak4535_dai_ops,
 };
 
-static int ak4535_resume(struct snd_soc_codec *codec)
+static int ak4535_resume(struct snd_soc_component *component)
 {
-	snd_soc_cache_sync(codec);
+	snd_soc_component_cache_sync(component);
 	return 0;
 }
 
@@ -390,19 +390,20 @@ static const struct regmap_config ak4535_regmap = {
 	.num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults),
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
-	.resume =	ak4535_resume,
-	.set_bias_level = ak4535_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= ak4535_snd_controls,
-		.num_controls		= ARRAY_SIZE(ak4535_snd_controls),
-		.dapm_widgets		= ak4535_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4535_dapm_widgets),
-		.dapm_routes		= ak4535_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(ak4535_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ak4535 = {
+	.resume			= ak4535_resume,
+	.set_bias_level		= ak4535_set_bias_level,
+	.controls		= ak4535_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4535_snd_controls),
+	.dapm_widgets		= ak4535_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4535_dapm_widgets),
+	.dapm_routes		= ak4535_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(ak4535_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ak4535_i2c_probe(struct i2c_client *i2c,
@@ -425,18 +426,12 @@ static int ak4535_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, ak4535);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_ak4535, &ak4535_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_ak4535, &ak4535_dai, 1);
 
 	return ret;
 }
 
-static int ak4535_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id ak4535_i2c_id[] = {
 	{ "ak4535", 0 },
 	{ }
@@ -448,7 +443,6 @@ static struct i2c_driver ak4535_i2c_driver = {
 		.name = "ak4535",
 	},
 	.probe =    ak4535_i2c_probe,
-	.remove =   ak4535_i2c_remove,
 	.id_table = ak4535_i2c_id,
 };
 
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index 0bb4fe5c122a..b7ee13406d93 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -64,28 +64,24 @@ static struct snd_soc_dai_driver ak4554_dai = {
 	.symmetric_rates = 1,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
-	.component_driver = {
-		.dapm_widgets		= ak4554_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4554_dapm_widgets),
-		.dapm_routes		= ak4554_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ak4554_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ak4554 = {
+	.dapm_widgets		= ak4554_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4554_dapm_widgets),
+	.dapm_routes		= ak4554_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ak4554_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ak4554_soc_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-				      &soc_codec_dev_ak4554,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_ak4554,
 				      &ak4554_dai, 1);
 }
 
-static int ak4554_soc_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static const struct of_device_id ak4554_of_match[] = {
 	{ .compatible = "asahi-kasei,ak4554" },
 	{},
@@ -98,7 +94,6 @@ static struct platform_driver ak4554_driver = {
 		.of_match_table = ak4554_of_match,
 	},
 	.probe	= ak4554_soc_probe,
-	.remove	= ak4554_soc_remove,
 };
 module_platform_driver(ak4554_driver);
 
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 3d1cf4784e87..8523ff9351cf 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -243,9 +243,9 @@ static const struct snd_soc_dapm_route ak4613_intercon[] = {
 static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
-	struct device *dev = codec->dev;
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
 
 	mutex_lock(&priv->lock);
 	priv->cnt--;
@@ -305,8 +305,8 @@ static void ak4613_hw_constraints(struct ak4613_priv *priv,
 static int ak4613_dai_startup(struct snd_pcm_substream *substream,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
 
 	priv->cnt++;
 
@@ -318,8 +318,8 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream,
 static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
 
 	priv->sysclk = freq;
 
@@ -328,8 +328,8 @@ static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
 
 static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
 
 	fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
 
@@ -366,10 +366,10 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
 	const struct ak4613_interface *iface;
-	struct device *dev = codec->dev;
+	struct device *dev = component->dev;
 	unsigned int width = params_width(params);
 	unsigned int fmt = priv->fmt;
 	unsigned int rate;
@@ -434,11 +434,11 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
 
 	fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
 
-	snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
-	snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2);
+	snd_soc_component_update_bits(component, CTRL1, FMT_MASK, fmt_ctrl);
+	snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2);
 
-	snd_soc_update_bits(codec, ICTRL, ICTRL_MASK, priv->ic);
-	snd_soc_update_bits(codec, OCTRL, OCTRL_MASK, priv->oc);
+	snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic);
+	snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc);
 
 hw_params_end:
 	if (ret < 0)
@@ -447,7 +447,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int ak4613_set_bias_level(struct snd_soc_codec *codec,
+static int ak4613_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	u8 mgmt1 = 0;
@@ -467,7 +467,7 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	}
 
-	snd_soc_write(codec, PW_MGMT1, mgmt1);
+	snd_soc_component_write(component, PW_MGMT1, mgmt1);
 
 	return 0;
 }
@@ -504,8 +504,8 @@ static void ak4613_dummy_write(struct work_struct *work)
 static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
 
 	/*
 	 * FIXME
@@ -537,7 +537,7 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 		return  0;
 
-	priv->component = &codec->component;
+	priv->component = component;
 	schedule_work(&priv->dummy_write_work);
 
 	return 0;
@@ -582,35 +582,36 @@ static struct snd_soc_dai_driver ak4613_dai = {
 	.symmetric_rates = 1,
 };
 
-static int ak4613_suspend(struct snd_soc_codec *codec)
+static int ak4613_suspend(struct snd_soc_component *component)
 {
-	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
 
 	regcache_cache_only(regmap, true);
 	regcache_mark_dirty(regmap);
 	return 0;
 }
 
-static int ak4613_resume(struct snd_soc_codec *codec)
+static int ak4613_resume(struct snd_soc_component *component)
 {
-	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
 
 	regcache_cache_only(regmap, false);
 	return regcache_sync(regmap);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
+static const struct snd_soc_component_driver soc_component_dev_ak4613 = {
 	.suspend		= ak4613_suspend,
 	.resume			= ak4613_resume,
 	.set_bias_level		= ak4613_set_bias_level,
-	.component_driver = {
-		.controls		= ak4613_snd_controls,
-		.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
-		.dapm_widgets		= ak4613_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
-		.dapm_routes		= ak4613_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
-	},
+	.controls		= ak4613_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
+	.dapm_widgets		= ak4613_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
+	.dapm_routes		= ak4613_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static void ak4613_parse_of(struct ak4613_priv *priv,
@@ -677,13 +678,12 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
-	return snd_soc_register_codec(dev, &soc_codec_dev_ak4613,
+	return devm_snd_soc_register_component(dev, &soc_component_dev_ak4613,
 				      &ak4613_dai, 1);
 }
 
 static int ak4613_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 60142ff32d4f..05869beff26e 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -70,9 +70,9 @@ static const struct reg_default ak4641_reg_defaults[] = {
 
 static const int deemph_settings[] = {44100, 0, 48000, 32000};
 
-static int ak4641_set_deemph(struct snd_soc_codec *codec)
+static int ak4641_set_deemph(struct snd_soc_component *component)
 {
-	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
 	int i, best = 0;
 
 	for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) {
@@ -86,16 +86,16 @@ static int ak4641_set_deemph(struct snd_soc_codec *codec)
 			best = i;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d\n", best);
+	dev_dbg(component->dev, "Set deemphasis %d\n", best);
 
-	return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best);
+	return snd_soc_component_update_bits(component, AK4641_DAC, 0x3, best);
 }
 
 static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
 	int deemph = ucontrol->value.integer.value[0];
 
 	if (deemph > 1)
@@ -103,14 +103,14 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
 
 	ak4641->deemph = deemph;
 
-	return ak4641_set_deemph(codec);
+	return ak4641_set_deemph(component);
 }
 
 static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = ak4641->deemph;
 	return 0;
@@ -307,8 +307,8 @@ static const struct snd_soc_dapm_route ak4641_audio_map[] = {
 static int ak4641_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
 
 	ak4641->sysclk = freq;
 	return 0;
@@ -318,8 +318,8 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
 	int rate = params_rate(params), fs = 256;
 	u8 mode2;
 
@@ -340,16 +340,16 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
 		mode2 = (0x0 << 5);
 		break;
 	default:
-		dev_err(codec->dev, "Error: unsupported fs=%d\n", fs);
+		dev_err(component->dev, "Error: unsupported fs=%d\n", fs);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2);
+	snd_soc_component_update_bits(component, AK4641_MODE2, (0x3 << 5), mode2);
 
 	/* Update de-emphasis filter for the new rate */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		ak4641->playback_fs = rate;
-		ak4641_set_deemph(codec);
+		ak4641_set_deemph(component);
 	}
 
 	return 0;
@@ -358,7 +358,7 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
 static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
 				  unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 btif;
 	int ret;
 
@@ -380,7 +380,7 @@ static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	ret = snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
+	ret = snd_soc_component_update_bits(component, AK4641_BTIF, (0x3 << 5), btif);
 	if (ret < 0)
 		return ret;
 
@@ -390,7 +390,7 @@ static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 mode1 = 0;
 
 	/* interface format */
@@ -405,34 +405,34 @@ static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	return snd_soc_write(codec, AK4641_MODE1, mode1);
+	return snd_soc_component_write(component, AK4641_MODE1, mode1);
 }
 
 static int ak4641_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0);
+	return snd_soc_component_update_bits(component, AK4641_DAC, 0x20, mute ? 0x20 : 0);
 }
 
-static int ak4641_set_bias_level(struct snd_soc_codec *codec,
+static int ak4641_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
-	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+	struct ak4641_platform_data *pdata = component->dev->platform_data;
 	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* unmute */
-		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0);
+		snd_soc_component_update_bits(component, AK4641_DAC, 0x20, 0);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* mute */
-		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
+		snd_soc_component_update_bits(component, AK4641_DAC, 0x20, 0x20);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			if (pdata && gpio_is_valid(pdata->gpio_power))
 				gpio_set_value(pdata->gpio_power, 1);
 			mdelay(1);
@@ -442,16 +442,16 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
 
 			ret = regcache_sync(ak4641->regmap);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to sync cache: %d\n", ret);
 				return ret;
 			}
 		}
-		snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80);
-		snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0);
+		snd_soc_component_update_bits(component, AK4641_PM1, 0x80, 0x80);
+		snd_soc_component_update_bits(component, AK4641_PM2, 0x80, 0);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0);
+		snd_soc_component_update_bits(component, AK4641_PM1, 0x80, 0);
 		if (pdata && gpio_is_valid(pdata->gpio_npdn))
 			gpio_set_value(pdata->gpio_npdn, 0);
 		if (pdata && gpio_is_valid(pdata->gpio_power))
@@ -524,17 +524,19 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 },
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
-	.component_driver = {
-		.controls		= ak4641_snd_controls,
-		.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
-		.dapm_widgets		= ak4641_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
-		.dapm_routes		= ak4641_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ak4641 = {
+	.controls		= ak4641_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
+	.dapm_widgets		= ak4641_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
+	.dapm_routes		= ak4641_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
 	.set_bias_level		= ak4641_set_bias_level,
-	.suspend_bias_off	= true,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ak4641_regmap = {
@@ -583,7 +585,8 @@ static int ak4641_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, ak4641);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_ak4641,
 				ak4641_dai, ARRAY_SIZE(ak4641_dai));
 	if (ret != 0)
 		goto err_gpio2;
@@ -608,8 +611,6 @@ static int ak4641_i2c_remove(struct i2c_client *i2c)
 {
 	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
 
-	snd_soc_unregister_codec(&i2c->dev);
-
 	if (pdata) {
 		if (gpio_is_valid(pdata->gpio_power)) {
 			gpio_set_value(pdata->gpio_power, 0);
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 29530c567bd9..605055964529 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -178,19 +178,19 @@ static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = {
 static int ak4642_lout_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMD:
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Power save mode ON */
-		snd_soc_update_bits(codec, SG_SL2, LOPS, LOPS);
+		snd_soc_component_update_bits(component, SG_SL2, LOPS, LOPS);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMD:
 		/* Power save mode OFF */
 		msleep(300);
-		snd_soc_update_bits(codec, SG_SL2, LOPS, 0);
+		snd_soc_component_update_bits(component, SG_SL2, LOPS, 0);
 		break;
 	}
 
@@ -282,7 +282,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 			      struct snd_soc_dai *dai)
 {
 	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (is_play) {
 		/*
@@ -295,8 +295,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 		 * This operation came from example code of
 		 * "ASAHI KASEI AK4642" (japanese) manual p97.
 		 */
-		snd_soc_write(codec, L_IVC, 0x91); /* volume */
-		snd_soc_write(codec, R_IVC, 0x91); /* volume */
+		snd_soc_component_write(component, L_IVC, 0x91); /* volume */
+		snd_soc_component_write(component, R_IVC, 0x91); /* volume */
 	} else {
 		/*
 		 * start stereo input
@@ -311,11 +311,11 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 		 * This operation came from example code of
 		 * "ASAHI KASEI AK4642" (japanese) manual p94.
 		 */
-		snd_soc_update_bits(codec, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);
-		snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
-		snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
-		snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL);
-		snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
+		snd_soc_component_update_bits(component, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);
+		snd_soc_component_write(component, TIMER, ZTM(0x3) | WTM(0x3));
+		snd_soc_component_write(component, ALC_CTL1, ALC | LMTH0);
+		snd_soc_component_update_bits(component, PW_MGMT1, PMADL, PMADL);
+		snd_soc_component_update_bits(component, PW_MGMT3, PMADR, PMADR);
 	}
 
 	return 0;
@@ -325,22 +325,22 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
 	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (is_play) {
 	} else {
 		/* stop stereo input */
-		snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
-		snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
-		snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
+		snd_soc_component_update_bits(component, PW_MGMT1, PMADL, 0);
+		snd_soc_component_update_bits(component, PW_MGMT3, PMADR, 0);
+		snd_soc_component_update_bits(component, ALC_CTL1, ALC, 0);
 	}
 }
 
 static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4642_priv *priv = snd_soc_component_get_drvdata(component);
 	u8 pll;
 	int extended_freq = 0;
 
@@ -382,14 +382,14 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
 	if (extended_freq && !priv->drvdata->extended_frequencies)
 		return -EINVAL;
 
-	snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
+	snd_soc_component_update_bits(component, MD_CTL1, PLL_MASK, pll);
 
 	return 0;
 }
 
 static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 data;
 	u8 bcko;
 
@@ -407,8 +407,8 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, PW_MGMT2, MS | MCKO | PMPLL, data);
-	snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko);
+	snd_soc_component_update_bits(component, PW_MGMT2, MS | MCKO | PMPLL, data);
+	snd_soc_component_update_bits(component, MD_CTL1, BCKO_MASK, bcko);
 
 	/* format type */
 	data = 0;
@@ -425,12 +425,12 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data);
+	snd_soc_component_update_bits(component, MD_CTL1, DIF_MASK, data);
 
 	return 0;
 }
 
-static int ak4642_set_mcko(struct snd_soc_codec *codec,
+static int ak4642_set_mcko(struct snd_soc_component *component,
 			   u32 frequency)
 {
 	static const u32 fs_list[] = {
@@ -458,7 +458,7 @@ static int ak4642_set_mcko(struct snd_soc_codec *codec,
 	for (ps = 0; ps < ARRAY_SIZE(ps_list); ps++) {
 		for (fs = 0; fs < ARRAY_SIZE(fs_list); fs++) {
 			if (frequency == ps_list[ps] * fs_list[fs]) {
-				snd_soc_write(codec, MD_CTL2,
+				snd_soc_component_write(component, MD_CTL2,
 					      PSs(ps) | FSs(fs));
 				return 0;
 			}
@@ -472,25 +472,25 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak4642_priv *priv = snd_soc_component_get_drvdata(component);
 	u32 rate = clk_get_rate(priv->mcko);
 
 	if (!rate)
 		rate = params_rate(params) * 256;
 
-	return ak4642_set_mcko(codec, rate);
+	return ak4642_set_mcko(component, rate);
 }
 
-static int ak4642_set_bias_level(struct snd_soc_codec *codec,
+static int ak4642_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, PW_MGMT1, 0x00);
+		snd_soc_component_write(component, PW_MGMT1, 0x00);
 		break;
 	default:
-		snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
+		snd_soc_component_update_bits(component, PW_MGMT1, PMVCM, PMVCM);
 		break;
 	}
 
@@ -523,46 +523,47 @@ static struct snd_soc_dai_driver ak4642_dai = {
 	.symmetric_rates = 1,
 };
 
-static int ak4642_suspend(struct snd_soc_codec *codec)
+static int ak4642_suspend(struct snd_soc_component *component)
 {
-	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
 
 	regcache_cache_only(regmap, true);
 	regcache_mark_dirty(regmap);
 	return 0;
 }
 
-static int ak4642_resume(struct snd_soc_codec *codec)
+static int ak4642_resume(struct snd_soc_component *component)
 {
-	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
 
 	regcache_cache_only(regmap, false);
 	regcache_sync(regmap);
 	return 0;
 }
-static int ak4642_probe(struct snd_soc_codec *codec)
+static int ak4642_probe(struct snd_soc_component *component)
 {
-	struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak4642_priv *priv = snd_soc_component_get_drvdata(component);
 
 	if (priv->mcko)
-		ak4642_set_mcko(codec, clk_get_rate(priv->mcko));
+		ak4642_set_mcko(component, clk_get_rate(priv->mcko));
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+static const struct snd_soc_component_driver soc_component_dev_ak4642 = {
 	.probe			= ak4642_probe,
 	.suspend		= ak4642_suspend,
 	.resume			= ak4642_resume,
 	.set_bias_level		= ak4642_set_bias_level,
-	.component_driver = {
-		.controls		= ak4642_snd_controls,
-		.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
-		.dapm_widgets		= ak4642_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
-		.dapm_routes		= ak4642_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
-	},
+	.controls		= ak4642_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
+	.dapm_widgets		= ak4642_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
+	.dapm_routes		= ak4642_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ak4642_regmap = {
@@ -675,14 +676,8 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
-	return snd_soc_register_codec(dev,
-				      &soc_codec_dev_ak4642, &ak4642_dai, 1);
-}
-
-static int ak4642_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
+	return devm_snd_soc_register_component(dev,
+				&soc_component_dev_ak4642, &ak4642_dai, 1);
 }
 
 static const struct of_device_id ak4642_of_match[] = {
@@ -707,7 +702,6 @@ static struct i2c_driver ak4642_i2c_driver = {
 		.of_match_table = ak4642_of_match,
 	},
 	.probe		= ak4642_i2c_probe,
-	.remove		= ak4642_i2c_remove,
 	.id_table	= ak4642_i2c_id,
 };
 
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index dcfdff56fc5a..7133fd69c641 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -163,15 +163,15 @@ static const struct snd_kcontrol_new ak4671_snd_controls[] = {
 static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
+		snd_soc_component_update_bits(component, AK4671_LOUT2_POWER_MANAGERMENT,
 				    AK4671_MUTEN, AK4671_MUTEN);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
+		snd_soc_component_update_bits(component, AK4671_LOUT2_POWER_MANAGERMENT,
 				    AK4671_MUTEN, 0);
 		break;
 	}
@@ -427,10 +427,10 @@ static int ak4671_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 fs;
 
-	fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
+	fs = snd_soc_component_read32(component, AK4671_PLL_MODE_SELECT0);
 	fs &= ~AK4671_FS;
 
 	switch (params_rate(params)) {
@@ -465,7 +465,7 @@ static int ak4671_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs);
+	snd_soc_component_write(component, AK4671_PLL_MODE_SELECT0, fs);
 
 	return 0;
 }
@@ -473,10 +473,10 @@ static int ak4671_hw_params(struct snd_pcm_substream *substream,
 static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 		unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 pll;
 
-	pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
+	pll = snd_soc_component_read32(component, AK4671_PLL_MODE_SELECT0);
 	pll &= ~AK4671_PLL;
 
 	switch (freq) {
@@ -511,19 +511,19 @@ static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll);
+	snd_soc_component_write(component, AK4671_PLL_MODE_SELECT0, pll);
 
 	return 0;
 }
 
 static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 mode;
 	u8 format;
 
 	/* set master/slave audio interface */
-	mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1);
+	mode = snd_soc_component_read32(component, AK4671_PLL_MODE_SELECT1);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -537,7 +537,7 @@ static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	/* interface format */
-	format = snd_soc_read(codec, AK4671_FORMAT_SELECT);
+	format = snd_soc_component_read32(component, AK4671_FORMAT_SELECT);
 	format &= ~AK4671_DIF;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -557,24 +557,24 @@ static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	/* set mode and format */
-	snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode);
-	snd_soc_write(codec, AK4671_FORMAT_SELECT, format);
+	snd_soc_component_write(component, AK4671_PLL_MODE_SELECT1, mode);
+	snd_soc_component_write(component, AK4671_FORMAT_SELECT, format);
 
 	return 0;
 }
 
-static int ak4671_set_bias_level(struct snd_soc_codec *codec,
+static int ak4671_set_bias_level(struct snd_soc_component *component,
 		enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, AK4671_AD_DA_POWER_MANAGEMENT,
+		snd_soc_component_update_bits(component, AK4671_AD_DA_POWER_MANAGEMENT,
 				    AK4671_PMVCM, AK4671_PMVCM);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
+		snd_soc_component_write(component, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
 		break;
 	}
 	return 0;
@@ -610,16 +610,18 @@ static struct snd_soc_dai_driver ak4671_dai = {
 	.ops = &ak4671_dai_ops,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
-	.set_bias_level = ak4671_set_bias_level,
-	.component_driver = {
-		.controls		= ak4671_snd_controls,
-		.num_controls		= ARRAY_SIZE(ak4671_snd_controls),
-		.dapm_widgets		= ak4671_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak4671_dapm_widgets),
-		.dapm_routes		= ak4671_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(ak4671_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ak4671 = {
+	.set_bias_level		= ak4671_set_bias_level,
+	.controls		= ak4671_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4671_snd_controls),
+	.dapm_widgets		= ak4671_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4671_dapm_widgets),
+	.dapm_routes		= ak4671_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4671_intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ak4671_regmap = {
@@ -645,17 +647,11 @@ static int ak4671_i2c_probe(struct i2c_client *client,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&client->dev,
-			&soc_codec_dev_ak4671, &ak4671_dai, 1);
+	ret = devm_snd_soc_register_component(&client->dev,
+			&soc_component_dev_ak4671, &ak4671_dai, 1);
 	return ret;
 }
 
-static int ak4671_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id ak4671_i2c_id[] = {
 	{ "ak4671", 0 },
 	{ }
@@ -667,7 +663,6 @@ static struct i2c_driver ak4671_i2c_driver = {
 		.name = "ak4671-codec",
 	},
 	.probe = ak4671_i2c_probe,
-	.remove = ak4671_i2c_remove,
 	.id_table = ak4671_i2c_id,
 };
 
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index d0e16c03815c..d212960b4dda 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -38,30 +38,29 @@ static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
 	{ "Capture", NULL, "AINR" },
 };
 
-static int ak5386_soc_probe(struct snd_soc_codec *codec)
+static int ak5386_soc_probe(struct snd_soc_component *component)
 {
-	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
 	return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
 }
 
-static int ak5386_soc_remove(struct snd_soc_codec *codec)
+static void ak5386_soc_remove(struct snd_soc_component *component)
 {
-	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
 	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int ak5386_soc_suspend(struct snd_soc_codec *codec)
+static int ak5386_soc_suspend(struct snd_soc_component *component)
 {
-	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
 	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
 	return 0;
 }
 
-static int ak5386_soc_resume(struct snd_soc_codec *codec)
+static int ak5386_soc_resume(struct snd_soc_component *component)
 {
-	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
 	return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
 }
 #else
@@ -69,28 +68,30 @@ static int ak5386_soc_resume(struct snd_soc_codec *codec)
 #define ak5386_soc_resume	NULL
 #endif /* CONFIG_PM */
 
-static const struct snd_soc_codec_driver soc_codec_ak5386 = {
-	.probe = ak5386_soc_probe,
-	.remove = ak5386_soc_remove,
-	.suspend = ak5386_soc_suspend,
-	.resume = ak5386_soc_resume,
-	.component_driver = {
-		.dapm_widgets		= ak5386_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ak5386_dapm_widgets),
-		.dapm_routes		= ak5386_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ak5386_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_ak5386 = {
+	.probe			= ak5386_soc_probe,
+	.remove			= ak5386_soc_remove,
+	.suspend		= ak5386_soc_suspend,
+	.resume			= ak5386_soc_resume,
+	.dapm_widgets		= ak5386_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak5386_dapm_widgets),
+	.dapm_routes		= ak5386_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ak5386_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	format &= SND_SOC_DAIFMT_FORMAT_MASK;
 	if (format != SND_SOC_DAIFMT_LEFT_J &&
 	    format != SND_SOC_DAIFMT_I2S) {
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -101,8 +102,8 @@ static int ak5386_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
 
 	/*
 	 * From the datasheet:
@@ -123,8 +124,8 @@ static int ak5386_hw_params(struct snd_pcm_substream *substream,
 static int ak5386_hw_free(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(priv->reset_gpio))
 		gpio_set_value(priv->reset_gpio, 0);
@@ -192,19 +193,12 @@ static int ak5386_probe(struct platform_device *pdev)
 					  "AK5386 Reset"))
 			priv->reset_gpio = -EINVAL;
 
-	return snd_soc_register_codec(dev, &soc_codec_ak5386,
+	return devm_snd_soc_register_component(dev, &soc_component_ak5386,
 				      &ak5386_dai, 1);
 }
 
-static int ak5386_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static struct platform_driver ak5386_driver = {
 	.probe		= ak5386_probe,
-	.remove		= ak5386_remove,
 	.driver		= {
 		.name	= "ak5386",
 		.of_match_table = of_match_ptr(ak5386_dt_ids),
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
new file mode 100644
index 000000000000..f2248315677e
--- /dev/null
+++ b/sound/soc/codecs/ak5558.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Audio driver for AK5558 ADC
+ *
+ * Copyright (C) 2015 Asahi Kasei Microdevices Corporation
+ * Copyright 2018 NXP
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ak5558.h"
+
+/* AK5558 Codec Private Data */
+struct ak5558_priv {
+	struct snd_soc_component component;
+	struct regmap *regmap;
+	struct i2c_client *i2c;
+	struct gpio_desc *reset_gpiod; /* Reset & Power down GPIO */
+	int slots;
+	int slot_width;
+};
+
+/* ak5558 register cache & default register settings */
+static const struct reg_default ak5558_reg[] = {
+	{ 0x0, 0xFF },	/*	0x00	AK5558_00_POWER_MANAGEMENT1	*/
+	{ 0x1, 0x01 },	/*	0x01	AK5558_01_POWER_MANAGEMENT2	*/
+	{ 0x2, 0x01 },	/*	0x02	AK5558_02_CONTROL1		*/
+	{ 0x3, 0x00 },	/*	0x03	AK5558_03_CONTROL2		*/
+	{ 0x4, 0x00 },	/*	0x04	AK5558_04_CONTROL3		*/
+	{ 0x5, 0x00 }	/*	0x05	AK5558_05_DSD			*/
+};
+
+static const char * const mono_texts[] = {
+	"8 Slot", "2 Slot", "4 Slot", "1 Slot",
+};
+
+static const struct soc_enum ak5558_mono_enum[] = {
+	SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1,
+			ARRAY_SIZE(mono_texts), mono_texts),
+};
+
+static const char * const digfil_texts[] = {
+	"Sharp Roll-Off", "Show Roll-Off",
+	"Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off",
+};
+
+static const struct soc_enum ak5558_adcset_enum[] = {
+	SOC_ENUM_SINGLE(AK5558_04_CONTROL3, 0,
+			ARRAY_SIZE(digfil_texts), digfil_texts),
+};
+
+static const struct snd_kcontrol_new ak5558_snd_controls[] = {
+	SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]),
+	SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]),
+};
+
+static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
+	/* Analog Input */
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+	SND_SOC_DAPM_INPUT("AIN4"),
+	SND_SOC_DAPM_INPUT("AIN5"),
+	SND_SOC_DAPM_INPUT("AIN6"),
+	SND_SOC_DAPM_INPUT("AIN7"),
+	SND_SOC_DAPM_INPUT("AIN8"),
+
+	SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0),
+	SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0),
+	SND_SOC_DAPM_ADC("ADC Ch3", NULL, AK5558_00_POWER_MANAGEMENT1, 2, 0),
+	SND_SOC_DAPM_ADC("ADC Ch4", NULL, AK5558_00_POWER_MANAGEMENT1, 3, 0),
+	SND_SOC_DAPM_ADC("ADC Ch5", NULL, AK5558_00_POWER_MANAGEMENT1, 4, 0),
+	SND_SOC_DAPM_ADC("ADC Ch6", NULL, AK5558_00_POWER_MANAGEMENT1, 5, 0),
+	SND_SOC_DAPM_ADC("ADC Ch7", NULL, AK5558_00_POWER_MANAGEMENT1, 6, 0),
+	SND_SOC_DAPM_ADC("ADC Ch8", NULL, AK5558_00_POWER_MANAGEMENT1, 7, 0),
+
+	SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route ak5558_intercon[] = {
+	{"ADC Ch1", NULL, "AIN1"},
+	{"SDTO", NULL, "ADC Ch1"},
+
+	{"ADC Ch2", NULL, "AIN2"},
+	{"SDTO", NULL, "ADC Ch2"},
+
+	{"ADC Ch3", NULL, "AIN3"},
+	{"SDTO", NULL, "ADC Ch3"},
+
+	{"ADC Ch4", NULL, "AIN4"},
+	{"SDTO", NULL, "ADC Ch4"},
+
+	{"ADC Ch5", NULL, "AIN5"},
+	{"SDTO", NULL, "ADC Ch5"},
+
+	{"ADC Ch6", NULL, "AIN6"},
+	{"SDTO", NULL, "ADC Ch6"},
+
+	{"ADC Ch7", NULL, "AIN7"},
+	{"SDTO", NULL, "ADC Ch7"},
+
+	{"ADC Ch8", NULL, "AIN8"},
+	{"SDTO", NULL, "ADC Ch8"},
+};
+
+static int ak5558_set_mcki(struct snd_soc_component *component)
+{
+	return snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_CKS,
+				   AK5558_CKS_AUTO);
+}
+
+static int ak5558_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+	u8 bits;
+	int pcm_width = max(params_physical_width(params), ak5558->slot_width);
+
+	/* set master/slave audio interface */
+	bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
+	bits &= ~AK5558_BITS;
+
+	switch (pcm_width) {
+	case 16:
+		bits |= AK5558_DIF_24BIT_MODE;
+		break;
+	case 32:
+		bits |= AK5558_DIF_32BIT_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_BITS, bits);
+
+	return 0;
+}
+
+static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 format;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		dev_err(dai->dev, "Clock mode unsupported");
+		return -EINVAL;
+	}
+
+	/* set master/slave audio interface */
+	format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
+	format &= ~AK5558_DIF;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format |= AK5558_DIF_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format |= AK5558_DIF_MSB_MODE;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		format |= AK5558_DIF_MSB_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_DIF, format);
+
+	return 0;
+}
+
+static int ak5558_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots,
+			       int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+	int tdm_mode;
+
+	ak5558->slots = slots;
+	ak5558->slot_width = slot_width;
+
+	switch (slots * slot_width) {
+	case 128:
+		tdm_mode = AK5558_MODE_TDM128;
+		break;
+	case 256:
+		tdm_mode = AK5558_MODE_TDM256;
+		break;
+	case 512:
+		tdm_mode = AK5558_MODE_TDM512;
+		break;
+	default:
+		tdm_mode = AK5558_MODE_NORMAL;
+		break;
+	}
+
+	snd_soc_component_update_bits(component, AK5558_03_CONTROL2, AK5558_MODE_BITS,
+			    tdm_mode);
+	return 0;
+}
+
+#define AK5558_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static const unsigned int ak5558_rates[] = {
+	8000, 11025,  16000, 22050,
+	32000, 44100, 48000, 88200,
+	96000, 176400, 192000, 352800,
+	384000, 705600, 768000, 1411200,
+	2822400,
+};
+
+static const struct snd_pcm_hw_constraint_list ak5558_rate_constraints = {
+	.count = ARRAY_SIZE(ak5558_rates),
+	.list = ak5558_rates,
+};
+
+static int ak5558_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &ak5558_rate_constraints);
+}
+
+static struct snd_soc_dai_ops ak5558_dai_ops = {
+	.startup        = ak5558_startup,
+	.hw_params	= ak5558_hw_params,
+
+	.set_fmt	= ak5558_set_dai_fmt,
+	.set_tdm_slot   = ak5558_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ak5558_dai = {
+	.name = "ak5558-aif",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = AK5558_FORMATS,
+	},
+	.ops = &ak5558_dai_ops,
+};
+
+static void ak5558_power_off(struct ak5558_priv *ak5558)
+{
+	if (!ak5558->reset_gpiod)
+		return;
+
+	gpiod_set_value_cansleep(ak5558->reset_gpiod, 0);
+	usleep_range(1000, 2000);
+}
+
+static void ak5558_power_on(struct ak5558_priv *ak5558)
+{
+	if (!ak5558->reset_gpiod)
+		return;
+
+	gpiod_set_value_cansleep(ak5558->reset_gpiod, 1);
+	usleep_range(1000, 2000);
+}
+
+static int ak5558_probe(struct snd_soc_component *component)
+{
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+
+	ak5558_power_on(ak5558);
+	return ak5558_set_mcki(component);
+}
+
+static void ak5558_remove(struct snd_soc_component *component)
+{
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+
+	ak5558_power_off(ak5558);
+}
+
+static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
+{
+	struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
+
+	regcache_cache_only(ak5558->regmap, true);
+	ak5558_power_off(ak5558);
+
+	return 0;
+}
+
+static int __maybe_unused ak5558_runtime_resume(struct device *dev)
+{
+	struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
+
+	ak5558_power_off(ak5558);
+	ak5558_power_on(ak5558);
+
+	regcache_cache_only(ak5558->regmap, false);
+	regcache_mark_dirty(ak5558->regmap);
+
+	return regcache_sync(ak5558->regmap);
+}
+
+const struct dev_pm_ops ak5558_pm = {
+	SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+struct snd_soc_component_driver soc_codec_dev_ak5558 = {
+	.probe			= ak5558_probe,
+	.remove			= ak5558_remove,
+	.controls		= ak5558_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak5558_snd_controls),
+	.dapm_widgets		= ak5558_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak5558_dapm_widgets),
+	.dapm_routes		= ak5558_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak5558_intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak5558_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK5558_05_DSD,
+	.reg_defaults = ak5558_reg,
+	.num_reg_defaults = ARRAY_SIZE(ak5558_reg),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ak5558_i2c_probe(struct i2c_client *i2c)
+{
+	struct ak5558_priv *ak5558;
+	int ret = 0;
+
+	ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL);
+	if (!ak5558)
+		return -ENOMEM;
+
+	ak5558->regmap = devm_regmap_init_i2c(i2c, &ak5558_regmap);
+	if (IS_ERR(ak5558->regmap))
+		return PTR_ERR(ak5558->regmap);
+
+	i2c_set_clientdata(i2c, ak5558);
+	ak5558->i2c = i2c;
+
+	ak5558->reset_gpiod = devm_gpiod_get_optional(&i2c->dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(ak5558->reset_gpiod))
+		return PTR_ERR(ak5558->reset_gpiod);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_codec_dev_ak5558,
+				     &ak5558_dai, 1);
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&i2c->dev);
+
+	return 0;
+}
+
+static int ak5558_i2c_remove(struct i2c_client *i2c)
+{
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static const struct of_device_id ak5558_i2c_dt_ids[] = {
+	{ .compatible = "asahi-kasei,ak5558"},
+	{ }
+};
+
+static struct i2c_driver ak5558_i2c_driver = {
+	.driver = {
+		.name = "ak5558",
+		.of_match_table = of_match_ptr(ak5558_i2c_dt_ids),
+		.pm = &ak5558_pm,
+	},
+	.probe_new = ak5558_i2c_probe,
+	.remove = ak5558_i2c_remove,
+};
+
+module_i2c_driver(ak5558_i2c_driver);
+
+MODULE_AUTHOR("Junichi Wakasugi <wakasugi.jb@om.asahi-kasei.co.jp>");
+MODULE_AUTHOR("Mihai Serban <mihai.serban@nxp.com>");
+MODULE_DESCRIPTION("ASoC AK5558 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak5558.h b/sound/soc/codecs/ak5558.h
new file mode 100644
index 000000000000..7c9e37374f39
--- /dev/null
+++ b/sound/soc/codecs/ak5558.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Audio driver header for AK5558
+ *
+ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation
+ * Copyright 2018 NXP
+ */
+
+#ifndef _AK5558_H
+#define _AK5558_H
+
+#define AK5558_00_POWER_MANAGEMENT1    0x00
+#define AK5558_01_POWER_MANAGEMENT2    0x01
+#define AK5558_02_CONTROL1             0x02
+#define AK5558_03_CONTROL2             0x03
+#define AK5558_04_CONTROL3             0x04
+#define AK5558_05_DSD                  0x05
+
+/* AK5558_02_CONTROL1 fields */
+#define AK5558_DIF			GENMASK(1, 1)
+#define AK5558_DIF_MSB_MODE		(0 << 1)
+#define AK5558_DIF_I2S_MODE		(1 << 1)
+
+#define AK5558_BITS			GENMASK(2, 2)
+#define AK5558_DIF_24BIT_MODE		(0 << 2)
+#define AK5558_DIF_32BIT_MODE		(1 << 2)
+
+#define AK5558_CKS			GENMASK(6, 3)
+#define AK5558_CKS_128FS_192KHZ		(0 << 3)
+#define AK5558_CKS_192FS_192KHZ		(1 << 3)
+#define AK5558_CKS_256FS_48KHZ		(2 << 3)
+#define AK5558_CKS_256FS_96KHZ		(3 << 3)
+#define AK5558_CKS_384FS_96KHZ		(4 << 3)
+#define AK5558_CKS_384FS_48KHZ		(5 << 3)
+#define AK5558_CKS_512FS_48KHZ		(6 << 3)
+#define AK5558_CKS_768FS_48KHZ		(7 << 3)
+#define AK5558_CKS_64FS_384KHZ		(8 << 3)
+#define AK5558_CKS_32FS_768KHZ		(9 << 3)
+#define AK5558_CKS_96FS_384KHZ		(10 << 3)
+#define AK5558_CKS_48FS_768KHZ		(11 << 3)
+#define AK5558_CKS_64FS_768KHZ		(12 << 3)
+#define AK5558_CKS_1024FS_16KHZ		(13 << 3)
+#define AK5558_CKS_AUTO			(15 << 3)
+
+/* AK5558_03_CONTROL2 fields */
+#define AK5558_MODE_BITS	GENMASK(6, 5)
+#define AK5558_MODE_NORMAL	(0 << 5)
+#define AK5558_MODE_TDM128	(1 << 5)
+#define AK5558_MODE_TDM256	(2 << 5)
+#define AK5558_MODE_TDM512	(3 << 5)
+
+#endif
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 1db965a93632..981a32973c08 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -47,28 +47,28 @@ struct alc5623_priv {
 	unsigned int jack_det_ctrl;
 };
 
-static inline int alc5623_reset(struct snd_soc_codec *codec)
+static inline int alc5623_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, ALC5623_RESET, 0);
+	return snd_soc_component_write(component, ALC5623_RESET, 0);
 }
 
 static int amp_mixer_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	/* to power-on/off class-d amp generators/speaker */
 	/* need to write to 'index-46h' register :        */
 	/* so write index num (here 0x46) to reg 0x6a     */
 	/* and then 0xffff/0 to reg 0x6c                  */
-	snd_soc_write(codec, ALC5623_HID_CTRL_INDEX, 0x46);
+	snd_soc_component_write(component, ALC5623_HID_CTRL_INDEX, 0x46);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
+		snd_soc_component_write(component, ALC5623_HID_CTRL_DATA, 0xFFFF);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0);
+		snd_soc_component_write(component, ALC5623_HID_CTRL_DATA, 0);
 		break;
 	}
 
@@ -526,7 +526,7 @@ static int alc5623_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
 	int i;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int gbl_clk = 0, pll_div = 0;
 	u16 reg;
 
@@ -534,12 +534,12 @@ static int alc5623_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		return -ENODEV;
 
 	/* Disable PLL power */
-	snd_soc_update_bits(codec, ALC5623_PWR_MANAG_ADD2,
+	snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD2,
 				ALC5623_PWR_ADD2_PLL,
 				0);
 
 	/* pll is not used in slave mode */
-	reg = snd_soc_read(codec, ALC5623_DAI_CONTROL);
+	reg = snd_soc_component_read32(component, ALC5623_DAI_CONTROL);
 	if (reg & ALC5623_DAI_SDP_SLAVE_MODE)
 		return 0;
 
@@ -575,13 +575,13 @@ static int alc5623_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	if (!pll_div)
 		return -EINVAL;
 
-	snd_soc_write(codec, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
-	snd_soc_write(codec, ALC5623_PLL_CTRL, pll_div);
-	snd_soc_update_bits(codec, ALC5623_PWR_MANAG_ADD2,
+	snd_soc_component_write(component, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
+	snd_soc_component_write(component, ALC5623_PLL_CTRL, pll_div);
+	snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD2,
 				ALC5623_PWR_ADD2_PLL,
 				ALC5623_PWR_ADD2_PLL);
 	gbl_clk |= ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL;
-	snd_soc_write(codec, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
+	snd_soc_component_write(component, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
 
 	return 0;
 }
@@ -604,9 +604,9 @@ static const struct _coeff_div coeff_div[] = {
 	{384*1, 0x0c6b},
 };
 
-static int get_coeff(struct snd_soc_codec *codec, int rate)
+static int get_coeff(struct snd_soc_component *component, int rate)
 {
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
@@ -622,8 +622,8 @@ static int get_coeff(struct snd_soc_codec *codec, int rate)
 static int alc5623_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case  8192000:
@@ -643,7 +643,7 @@ static int alc5623_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -695,18 +695,18 @@ static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	return snd_soc_write(codec, ALC5623_DAI_CONTROL, iface);
+	return snd_soc_component_write(component, ALC5623_DAI_CONTROL, iface);
 }
 
 static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
 	int coeff, rate;
 	u16 iface;
 
-	iface = snd_soc_read(codec, ALC5623_DAI_CONTROL);
+	iface = snd_soc_component_read32(component, ALC5623_DAI_CONTROL);
 	iface &= ~ALC5623_DAI_I2S_DL_MASK;
 
 	/* bit size */
@@ -728,30 +728,30 @@ static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set iface & srate */
-	snd_soc_write(codec, ALC5623_DAI_CONTROL, iface);
+	snd_soc_component_write(component, ALC5623_DAI_CONTROL, iface);
 	rate = params_rate(params);
-	coeff = get_coeff(codec, rate);
+	coeff = get_coeff(component, rate);
 	if (coeff < 0)
 		return -EINVAL;
 
 	coeff = coeff_div[coeff].regvalue;
-	dev_dbg(codec->dev, "%s: sysclk=%d,rate=%d,coeff=0x%04x\n",
+	dev_dbg(component->dev, "%s: sysclk=%d,rate=%d,coeff=0x%04x\n",
 		__func__, alc5623->sysclk, rate, coeff);
-	snd_soc_write(codec, ALC5623_STEREO_AD_DA_CLK_CTRL, coeff);
+	snd_soc_component_write(component, ALC5623_STEREO_AD_DA_CLK_CTRL, coeff);
 
 	return 0;
 }
 
 static int alc5623_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 hp_mute = ALC5623_MISC_M_DAC_L_INPUT | ALC5623_MISC_M_DAC_R_INPUT;
-	u16 mute_reg = snd_soc_read(codec, ALC5623_MISC_CTRL) & ~hp_mute;
+	u16 mute_reg = snd_soc_component_read32(component, ALC5623_MISC_CTRL) & ~hp_mute;
 
 	if (mute)
 		mute_reg |= hp_mute;
 
-	return snd_soc_write(codec, ALC5623_MISC_CTRL, mute_reg);
+	return snd_soc_component_write(component, ALC5623_MISC_CTRL, mute_reg);
 }
 
 #define ALC5623_ADD2_POWER_EN (ALC5623_PWR_ADD2_VREF \
@@ -769,60 +769,60 @@ static int alc5623_mute(struct snd_soc_dai *dai, int mute)
 	(ALC5623_PWR_ADD1_SHORT_CURR_DET_EN \
 	| ALC5623_PWR_ADD1_HP_OUT_AMP)
 
-static void enable_power_depop(struct snd_soc_codec *codec)
+static void enable_power_depop(struct snd_soc_component *component)
 {
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_update_bits(codec, ALC5623_PWR_MANAG_ADD1,
+	snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD1,
 				ALC5623_PWR_ADD1_SOFTGEN_EN,
 				ALC5623_PWR_ADD1_SOFTGEN_EN);
 
-	snd_soc_write(codec, ALC5623_PWR_MANAG_ADD3, ALC5623_ADD3_POWER_EN);
+	snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, ALC5623_ADD3_POWER_EN);
 
-	snd_soc_update_bits(codec, ALC5623_MISC_CTRL,
+	snd_soc_component_update_bits(component, ALC5623_MISC_CTRL,
 				ALC5623_MISC_HP_DEPOP_MODE2_EN,
 				ALC5623_MISC_HP_DEPOP_MODE2_EN);
 
 	msleep(500);
 
-	snd_soc_write(codec, ALC5623_PWR_MANAG_ADD2, ALC5623_ADD2_POWER_EN);
+	snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, ALC5623_ADD2_POWER_EN);
 
 	/* avoid writing '1' into 5622 reserved bits */
 	if (alc5623->id == 0x22)
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1,
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1,
 			ALC5623_ADD1_POWER_EN_5622);
 	else
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1,
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1,
 			ALC5623_ADD1_POWER_EN);
 
 	/* disable HP Depop2 */
-	snd_soc_update_bits(codec, ALC5623_MISC_CTRL,
+	snd_soc_component_update_bits(component, ALC5623_MISC_CTRL,
 				ALC5623_MISC_HP_DEPOP_MODE2_EN,
 				0);
 
 }
 
-static int alc5623_set_bias_level(struct snd_soc_codec *codec,
+static int alc5623_set_bias_level(struct snd_soc_component *component,
 				      enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		enable_power_depop(codec);
+		enable_power_depop(component);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* everything off except vref/vmid, */
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD2,
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2,
 				ALC5623_PWR_ADD2_VREF);
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD3,
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3,
 				ALC5623_PWR_ADD3_MAIN_BIAS);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* everything off, dac mute, inactive */
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD2, 0);
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD3, 0);
-		snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0);
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, 0);
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, 0);
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1, 0);
 		break;
 	}
 	return 0;
@@ -862,25 +862,25 @@ static struct snd_soc_dai_driver alc5623_dai = {
 	.ops = &alc5623_dai_ops,
 };
 
-static int alc5623_suspend(struct snd_soc_codec *codec)
+static int alc5623_suspend(struct snd_soc_component *component)
 {
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(alc5623->regmap, true);
 
 	return 0;
 }
 
-static int alc5623_resume(struct snd_soc_codec *codec)
+static int alc5623_resume(struct snd_soc_component *component)
 {
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	/* Sync reg_cache with the hardware */
 	regcache_cache_only(alc5623->regmap, false);
 	ret = regcache_sync(alc5623->regmap);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to sync register cache: %d\n",
+		dev_err(component->dev, "Failed to sync register cache: %d\n",
 			ret);
 		regcache_cache_only(alc5623->regmap, true);
 		return ret;
@@ -889,41 +889,41 @@ static int alc5623_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int alc5623_probe(struct snd_soc_codec *codec)
+static int alc5623_probe(struct snd_soc_component *component)
 {
-	struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	alc5623_reset(codec);
+	alc5623_reset(component);
 
 	if (alc5623->add_ctrl) {
-		snd_soc_write(codec, ALC5623_ADD_CTRL_REG,
+		snd_soc_component_write(component, ALC5623_ADD_CTRL_REG,
 				alc5623->add_ctrl);
 	}
 
 	if (alc5623->jack_det_ctrl) {
-		snd_soc_write(codec, ALC5623_JACK_DET_CTRL,
+		snd_soc_component_write(component, ALC5623_JACK_DET_CTRL,
 				alc5623->jack_det_ctrl);
 	}
 
 	switch (alc5623->id) {
 	case 0x21:
-		snd_soc_add_codec_controls(codec, alc5621_vol_snd_controls,
+		snd_soc_add_component_controls(component, alc5621_vol_snd_controls,
 			ARRAY_SIZE(alc5621_vol_snd_controls));
 		break;
 	case 0x22:
-		snd_soc_add_codec_controls(codec, alc5622_vol_snd_controls,
+		snd_soc_add_component_controls(component, alc5622_vol_snd_controls,
 			ARRAY_SIZE(alc5622_vol_snd_controls));
 		break;
 	case 0x23:
-		snd_soc_add_codec_controls(codec, alc5623_vol_snd_controls,
+		snd_soc_add_component_controls(component, alc5623_vol_snd_controls,
 			ARRAY_SIZE(alc5623_vol_snd_controls));
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	snd_soc_add_codec_controls(codec, alc5623_snd_controls,
+	snd_soc_add_component_controls(component, alc5623_snd_controls,
 			ARRAY_SIZE(alc5623_snd_controls));
 
 	snd_soc_dapm_new_controls(dapm, alc5623_dapm_widgets,
@@ -951,12 +951,16 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_device_alc5623 = {
-	.probe = alc5623_probe,
-	.suspend = alc5623_suspend,
-	.resume = alc5623_resume,
-	.set_bias_level = alc5623_set_bias_level,
-	.suspend_bias_off = true,
+static const struct snd_soc_component_driver soc_component_device_alc5623 = {
+	.probe			= alc5623_probe,
+	.suspend		= alc5623_suspend,
+	.resume			= alc5623_resume,
+	.set_bias_level		= alc5623_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config alc5623_regmap = {
@@ -1052,20 +1056,14 @@ static int alc5623_i2c_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, alc5623);
 
-	ret =  snd_soc_register_codec(&client->dev,
-		&soc_codec_device_alc5623, &alc5623_dai, 1);
+	ret =  devm_snd_soc_register_component(&client->dev,
+		&soc_component_device_alc5623, &alc5623_dai, 1);
 	if (ret != 0)
 		dev_err(&client->dev, "Failed to register codec: %d\n", ret);
 
 	return ret;
 }
 
-static int alc5623_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id alc5623_i2c_table[] = {
 	{"alc5621", 0x21},
 	{"alc5622", 0x22},
@@ -1087,7 +1085,6 @@ static struct i2c_driver alc5623_i2c_driver = {
 		.of_match_table = of_match_ptr(alc5623_of_match),
 	},
 	.probe = alc5623_i2c_probe,
-	.remove =  alc5623_i2c_remove,
 	.id_table = alc5623_i2c_table,
 };
 
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index adb80d8719bd..08034a6d4c5a 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -116,20 +116,20 @@ static inline int alc5632_reset(struct regmap *map)
 static int amp_mixer_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	/* to power-on/off class-d amp generators/speaker */
 	/* need to write to 'index-46h' register :        */
 	/* so write index num (here 0x46) to reg 0x6a     */
 	/* and then 0xffff/0 to reg 0x6c                  */
-	snd_soc_write(codec, ALC5632_HID_CTRL_INDEX, 0x46);
+	snd_soc_component_write(component, ALC5632_HID_CTRL_INDEX, 0x46);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
+		snd_soc_component_write(component, ALC5632_HID_CTRL_DATA, 0xFFFF);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0);
+		snd_soc_component_write(component, ALC5632_HID_CTRL_DATA, 0);
 		break;
 	}
 
@@ -681,7 +681,7 @@ static int alc5632_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
 	int i;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int gbl_clk = 0, pll_div = 0;
 	u16 reg;
 
@@ -689,15 +689,15 @@ static int alc5632_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		return -EINVAL;
 
 	/* Disable PLL power */
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_PWR_ADD2_PLL1,
 				0);
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_PWR_ADD2_PLL2,
 				0);
 
 	/* pll is not used in slave mode */
-	reg = snd_soc_read(codec, ALC5632_DAI_CONTROL);
+	reg = snd_soc_component_read32(component, ALC5632_DAI_CONTROL);
 	if (reg & ALC5632_DAI_SDP_SLAVE_MODE)
 		return 0;
 
@@ -745,19 +745,19 @@ static int alc5632_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		return -EINVAL;
 
 	/* choose MCLK/BCLK/VBCLK */
-	snd_soc_write(codec, ALC5632_GPCR2, gbl_clk);
+	snd_soc_component_write(component, ALC5632_GPCR2, gbl_clk);
 	/* choose PLL1 clock rate */
-	snd_soc_write(codec, ALC5632_PLL1_CTRL, pll_div);
+	snd_soc_component_write(component, ALC5632_PLL1_CTRL, pll_div);
 	/* enable PLL1 */
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_PWR_ADD2_PLL1,
 				ALC5632_PWR_ADD2_PLL1);
 	/* enable PLL2 */
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_PWR_ADD2_PLL2,
 				ALC5632_PWR_ADD2_PLL2);
 	/* use PLL1 as main SYSCLK */
-	snd_soc_update_bits(codec, ALC5632_GPCR1,
+	snd_soc_component_update_bits(component, ALC5632_GPCR1,
 			ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1,
 			ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1);
 
@@ -775,9 +775,9 @@ static const struct _coeff_div coeff_div[] = {
 	{512*1, 0x3075},
 };
 
-static int get_coeff(struct snd_soc_codec *codec, int rate)
+static int get_coeff(struct snd_soc_component *component, int rate)
 {
-	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
@@ -793,8 +793,8 @@ static int get_coeff(struct snd_soc_codec *codec, int rate)
 static int alc5632_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case  4096000:
@@ -815,7 +815,7 @@ static int alc5632_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -864,17 +864,17 @@ static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	return snd_soc_write(codec, ALC5632_DAI_CONTROL, iface);
+	return snd_soc_component_write(component, ALC5632_DAI_CONTROL, iface);
 }
 
 static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int coeff, rate;
 	u16 iface;
 
-	iface = snd_soc_read(codec, ALC5632_DAI_CONTROL);
+	iface = snd_soc_component_read32(component, ALC5632_DAI_CONTROL);
 	iface &= ~ALC5632_DAI_I2S_DL_MASK;
 
 	/* bit size */
@@ -893,29 +893,29 @@ static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set iface & srate */
-	snd_soc_write(codec, ALC5632_DAI_CONTROL, iface);
+	snd_soc_component_write(component, ALC5632_DAI_CONTROL, iface);
 	rate = params_rate(params);
-	coeff = get_coeff(codec, rate);
+	coeff = get_coeff(component, rate);
 	if (coeff < 0)
 		return -EINVAL;
 
 	coeff = coeff_div[coeff].regvalue;
-	snd_soc_write(codec, ALC5632_DAC_CLK_CTRL1, coeff);
+	snd_soc_component_write(component, ALC5632_DAC_CLK_CTRL1, coeff);
 
 	return 0;
 }
 
 static int alc5632_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 hp_mute = ALC5632_MISC_HP_DEPOP_MUTE_L
 						|ALC5632_MISC_HP_DEPOP_MUTE_R;
-	u16 mute_reg = snd_soc_read(codec, ALC5632_MISC_CTRL) & ~hp_mute;
+	u16 mute_reg = snd_soc_component_read32(component, ALC5632_MISC_CTRL) & ~hp_mute;
 
 	if (mute)
 		mute_reg |= hp_mute;
 
-	return snd_soc_write(codec, ALC5632_MISC_CTRL, mute_reg);
+	return snd_soc_component_write(component, ALC5632_MISC_CTRL, mute_reg);
 }
 
 #define ALC5632_ADD2_POWER_EN (ALC5632_PWR_ADD2_VREF)
@@ -929,73 +929,73 @@ static int alc5632_mute(struct snd_soc_dai *dai, int mute)
 		| ALC5632_PWR_ADD1_HP_OUT_ENH_AMP \
 		| ALC5632_PWR_ADD1_MAIN_BIAS)
 
-static void enable_power_depop(struct snd_soc_codec *codec)
+static void enable_power_depop(struct snd_soc_component *component)
 {
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
 				ALC5632_PWR_ADD1_SOFTGEN_EN,
 				ALC5632_PWR_ADD1_SOFTGEN_EN);
 
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD3,
 				ALC5632_ADD3_POWER_EN,
 				ALC5632_ADD3_POWER_EN);
 
-	snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
+	snd_soc_component_update_bits(component, ALC5632_MISC_CTRL,
 				ALC5632_MISC_HP_DEPOP_MODE2_EN,
 				ALC5632_MISC_HP_DEPOP_MODE2_EN);
 
 	/* "normal" mode: 0 @ 26 */
 	/* set all PR0-7 mixers to 0 */
-	snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
+	snd_soc_component_update_bits(component, ALC5632_PWR_DOWN_CTRL_STATUS,
 				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
 				0);
 
 	msleep(500);
 
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_ADD2_POWER_EN,
 				ALC5632_ADD2_POWER_EN);
 
-	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
 				ALC5632_ADD1_POWER_EN,
 				ALC5632_ADD1_POWER_EN);
 
 	/* disable HP Depop2 */
-	snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
+	snd_soc_component_update_bits(component, ALC5632_MISC_CTRL,
 				ALC5632_MISC_HP_DEPOP_MODE2_EN,
 				0);
 
 }
 
-static int alc5632_set_bias_level(struct snd_soc_codec *codec,
+static int alc5632_set_bias_level(struct snd_soc_component *component,
 				      enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		enable_power_depop(codec);
+		enable_power_depop(component);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* everything off except vref/vmid, */
-		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
 				ALC5632_PWR_MANAG_ADD1_MASK,
 				ALC5632_PWR_ADD1_MAIN_BIAS);
-		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_PWR_MANAG_ADD2_MASK,
 				ALC5632_PWR_ADD2_VREF);
 		/* "normal" mode: 0 @ 26 */
-		snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
+		snd_soc_component_update_bits(component, ALC5632_PWR_DOWN_CTRL_STATUS,
 				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
 				0xffff ^ (ALC5632_PWR_VREF_PR3
 				| ALC5632_PWR_VREF_PR2));
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* everything off, dac mute, inactive */
-		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
 				ALC5632_PWR_MANAG_ADD2_MASK, 0);
-		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD3,
 				ALC5632_PWR_MANAG_ADD3_MASK, 0);
-		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
 				ALC5632_PWR_MANAG_ADD1_MASK, 0);
 		break;
 	}
@@ -1038,9 +1038,9 @@ static struct snd_soc_dai_driver alc5632_dai = {
 };
 
 #ifdef CONFIG_PM
-static int alc5632_resume(struct snd_soc_codec *codec)
+static int alc5632_resume(struct snd_soc_component *component)
 {
-	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
 
 	regcache_sync(alc5632->regmap);
 
@@ -1050,13 +1050,13 @@ static int alc5632_resume(struct snd_soc_codec *codec)
 #define	alc5632_resume	NULL
 #endif
 
-static int alc5632_probe(struct snd_soc_codec *codec)
+static int alc5632_probe(struct snd_soc_component *component)
 {
-	struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
 
 	switch (alc5632->id) {
 	case 0x5c:
-		snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls,
+		snd_soc_add_component_controls(component, alc5632_vol_snd_controls,
 			ARRAY_SIZE(alc5632_vol_snd_controls));
 		break;
 	default:
@@ -1066,20 +1066,21 @@ static int alc5632_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_device_alc5632 = {
-	.probe = alc5632_probe,
-	.resume = alc5632_resume,
-	.set_bias_level = alc5632_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= alc5632_snd_controls,
-		.num_controls		= ARRAY_SIZE(alc5632_snd_controls),
-		.dapm_widgets		= alc5632_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(alc5632_dapm_widgets),
-		.dapm_routes		= alc5632_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(alc5632_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_device_alc5632 = {
+	.probe			= alc5632_probe,
+	.resume			= alc5632_resume,
+	.set_bias_level		= alc5632_set_bias_level,
+	.controls		= alc5632_snd_controls,
+	.num_controls		= ARRAY_SIZE(alc5632_snd_controls),
+	.dapm_widgets		= alc5632_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(alc5632_dapm_widgets),
+	.dapm_routes		= alc5632_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(alc5632_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config alc5632_regmap = {
@@ -1151,23 +1152,17 @@ static int alc5632_i2c_probe(struct i2c_client *client,
 		return -EINVAL;
 	}
 
-	ret = snd_soc_register_codec(&client->dev,
-		&soc_codec_device_alc5632, &alc5632_dai, 1);
+	ret = devm_snd_soc_register_component(&client->dev,
+		&soc_component_device_alc5632, &alc5632_dai, 1);
 
 	if (ret < 0) {
-		dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&client->dev, "Failed to register component: %d\n", ret);
 		return ret;
 	}
 
 	return ret;
 }
 
-static int alc5632_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id alc5632_i2c_table[] = {
 	{"alc5632", 0x5c},
 	{}
@@ -1187,7 +1182,6 @@ static struct i2c_driver alc5632_i2c_driver = {
 		.of_match_table = of_match_ptr(alc5632_of_match),
 	},
 	.probe = alc5632_i2c_probe,
-	.remove =  alc5632_i2c_remove,
 	.id_table = alc5632_i2c_table,
 };
 
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index b3375e19598a..ffcfe8ea1848 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -84,13 +84,13 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	int val;
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
+		val = snd_soc_component_read32(component, ARIZONA_INTERRUPT_RAW_STATUS_3);
 		if (val & ARIZONA_SPK_OVERHEAT_STS) {
 			dev_crit(arizona->dev,
 				 "Speaker not enabled due to temperature\n");
@@ -169,10 +169,10 @@ static const struct snd_soc_dapm_widget arizona_spkr =
 			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
 
-int arizona_init_spk(struct snd_soc_codec *codec)
+int arizona_init_spk(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int ret;
 
@@ -238,10 +238,10 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = {
 	{ "OUT6R", NULL, "OUT6L" },
 };
 
-int arizona_init_mono(struct snd_soc_codec *codec)
+int arizona_init_mono(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int i;
 
@@ -255,11 +255,9 @@ int arizona_init_mono(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(arizona_init_mono);
 
-int arizona_init_gpio(struct snd_soc_codec *codec)
+int arizona_init_gpio(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int i;
 
@@ -882,9 +880,9 @@ const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
 };
 EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
 
-static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
+static void arizona_in_set_vu(struct snd_soc_component *component, int ena)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 	int i;
 
@@ -894,15 +892,15 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 		val = 0;
 
 	for (i = 0; i < priv->num_inputs; i++)
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 				    ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
 				    ARIZONA_IN_VU, val);
 }
 
-bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
+bool arizona_input_analog(struct snd_soc_component *component, int shift)
 {
 	unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
-	unsigned int val = snd_soc_read(codec, reg);
+	unsigned int val = snd_soc_component_read32(component, reg);
 
 	return !(val & ARIZONA_IN1_MODE_MASK);
 }
@@ -911,8 +909,8 @@ EXPORT_SYMBOL_GPL(arizona_input_analog);
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 
 	if (w->shift % 2)
@@ -925,25 +923,25 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		priv->in_pending++;
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
+		snd_soc_component_update_bits(component, reg, ARIZONA_IN1L_MUTE, 0);
 
 		/* If this is the last input pending then allow VU */
 		priv->in_pending--;
 		if (priv->in_pending == 0) {
 			msleep(1);
-			arizona_in_set_vu(codec, 1);
+			arizona_in_set_vu(component, 1);
 		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
 				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Disable volume updates if no inputs are enabled */
-		reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
+		reg = snd_soc_component_read32(component, ARIZONA_INPUT_ENABLES);
 		if (reg == 0)
-			arizona_in_set_vu(codec, 0);
+			arizona_in_set_vu(component, 0);
 		break;
 	default:
 		break;
@@ -957,8 +955,8 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 
 	switch (event) {
@@ -1001,7 +999,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		case ARIZONA_OUT4R_ENA_SHIFT:
 			priv->out_up_pending--;
 			if (!priv->out_up_pending && priv->out_up_delay) {
-				dev_dbg(codec->dev, "Power up delay: %d\n",
+				dev_dbg(component->dev, "Power up delay: %d\n",
 					priv->out_up_delay);
 				msleep(priv->out_up_delay);
 				priv->out_up_delay = 0;
@@ -1054,7 +1052,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 		case ARIZONA_OUT4R_ENA_SHIFT:
 			priv->out_down_pending--;
 			if (!priv->out_down_pending && priv->out_down_delay) {
-				dev_dbg(codec->dev, "Power down delay: %d\n",
+				dev_dbg(component->dev, "Power down delay: %d\n",
 					priv->out_down_delay);
 				msleep(priv->out_down_delay);
 				priv->out_down_delay = 0;
@@ -1076,8 +1074,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	unsigned int mask = 1 << w->shift;
 	unsigned int val;
@@ -1111,15 +1109,15 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(arizona_hp_ev);
 
-static int arizona_dvfs_enable(struct snd_soc_codec *codec)
+static int arizona_dvfs_enable(struct snd_soc_component *component)
 {
-	const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int ret;
 
 	ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
 	if (ret) {
-		dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
+		dev_err(component->dev, "Failed to boost DCVDD: %d\n", ret);
 		return ret;
 	}
 
@@ -1128,7 +1126,7 @@ static int arizona_dvfs_enable(struct snd_soc_codec *codec)
 				 ARIZONA_SUBSYS_MAX_FREQ,
 				 ARIZONA_SUBSYS_MAX_FREQ);
 	if (ret) {
-		dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
+		dev_err(component->dev, "Failed to enable subsys max: %d\n", ret);
 		regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
 		return ret;
 	}
@@ -1136,9 +1134,9 @@ static int arizona_dvfs_enable(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int arizona_dvfs_disable(struct snd_soc_codec *codec)
+static int arizona_dvfs_disable(struct snd_soc_component *component)
 {
-	const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int ret;
 
@@ -1146,28 +1144,28 @@ static int arizona_dvfs_disable(struct snd_soc_codec *codec)
 				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
 				 ARIZONA_SUBSYS_MAX_FREQ, 0);
 	if (ret) {
-		dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
+		dev_err(component->dev, "Failed to disable subsys max: %d\n", ret);
 		return ret;
 	}
 
 	ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
 	if (ret) {
-		dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
+		dev_err(component->dev, "Failed to unboost DCVDD: %d\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
-int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
+int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	mutex_lock(&priv->dvfs_lock);
 
 	if (!priv->dvfs_cached && !priv->dvfs_reqs) {
-		ret = arizona_dvfs_enable(codec);
+		ret = arizona_dvfs_enable(component);
 		if (ret)
 			goto err;
 	}
@@ -1179,9 +1177,9 @@ int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
 }
 EXPORT_SYMBOL_GPL(arizona_dvfs_up);
 
-int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
+int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int old_reqs;
 	int ret = 0;
 
@@ -1191,7 +1189,7 @@ int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
 	priv->dvfs_reqs &= ~flags;
 
 	if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
-		ret = arizona_dvfs_disable(codec);
+		ret = arizona_dvfs_disable(component);
 
 	mutex_unlock(&priv->dvfs_lock);
 	return ret;
@@ -1201,8 +1199,8 @@ EXPORT_SYMBOL_GPL(arizona_dvfs_down);
 int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	mutex_lock(&priv->dvfs_lock);
@@ -1210,7 +1208,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		if (priv->dvfs_reqs)
-			ret = arizona_dvfs_enable(codec);
+			ret = arizona_dvfs_enable(component);
 
 		priv->dvfs_cached = false;
 		break;
@@ -1222,7 +1220,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
 		priv->dvfs_cached = true;
 
 		if (priv->dvfs_reqs)
-			ret = arizona_dvfs_disable(codec);
+			ret = arizona_dvfs_disable(component);
 		break;
 	default:
 		break;
@@ -1243,7 +1241,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int val;
 
 	switch (event) {
@@ -1257,7 +1255,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w,
 		return 0;
 	}
 
-	snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val);
+	snd_soc_component_write(component, ARIZONA_CLOCK_CONTROL, val);
 
 	return 0;
 }
@@ -1277,10 +1275,10 @@ static unsigned int arizona_opclk_ref_44k1_rates[] = {
 	45158400,
 };
 
-static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
+static int arizona_set_opclk(struct snd_soc_component *component, unsigned int clk,
 			     unsigned int freq)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 	unsigned int *rates;
 	int ref, div, refclk;
@@ -1308,9 +1306,9 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
 		div = 1;
 		while (rates[ref] / div >= freq && div < 32) {
 			if (rates[ref] / div == freq) {
-				dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
+				dev_dbg(component->dev, "Configured %dHz OPCLK\n",
 					freq);
-				snd_soc_update_bits(codec, reg,
+				snd_soc_component_update_bits(component, reg,
 						    ARIZONA_OPCLK_DIV_MASK |
 						    ARIZONA_OPCLK_SEL_MASK,
 						    (div <<
@@ -1322,22 +1320,22 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
 		}
 	}
 
-	dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
+	dev_err(component->dev, "Unable to generate %dHz OPCLK\n", freq);
 	return -EINVAL;
 }
 
 int arizona_clk_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	unsigned int val;
 	int clk_idx;
 	int ret;
 
 	ret = regmap_read(arizona->regmap, w->reg, &val);
 	if (ret) {
-		dev_err(codec->dev, "Failed to check clock source: %d\n", ret);
+		dev_err(component->dev, "Failed to check clock source: %d\n", ret);
 		return ret;
 	}
 
@@ -1366,10 +1364,10 @@ int arizona_clk_ev(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(arizona_clk_ev);
 
-int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+int arizona_set_sysclk(struct snd_soc_component *component, int clk_id,
 		       int source, unsigned int freq, int dir)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	char *name;
 	unsigned int reg;
@@ -1391,7 +1389,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		break;
 	case ARIZONA_CLK_OPCLK:
 	case ARIZONA_CLK_ASYNC_OPCLK:
-		return arizona_set_opclk(codec, clk_id, freq);
+		return arizona_set_opclk(component, clk_id, freq);
 	default:
 		return -EINVAL;
 	}
@@ -1445,8 +1443,8 @@ EXPORT_SYMBOL_GPL(arizona_set_sysclk);
 
 static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int lrclk, bclk, mode, base;
 
@@ -1620,8 +1618,8 @@ static const struct snd_pcm_hw_constraint_list arizona_constraint = {
 static int arizona_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	unsigned int base_rate;
 
@@ -1651,10 +1649,10 @@ static int arizona_startup(struct snd_pcm_substream *substream,
 					  &dai_priv->constraint);
 }
 
-static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
+static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component,
 					unsigned int rate)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	struct reg_sequence dac_comp[] = {
 		{ 0x80, 0x3 },
@@ -1680,8 +1678,8 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
 				  struct snd_pcm_hw_params *params,
 				  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	int base = dai->driver->base;
 	int i, sr_val, ret;
@@ -1704,9 +1702,9 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
 	case WM5102:
 	case WM8997:
 		if (arizona_sr_vals[sr_val] >= 88200)
-			ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
+			ret = arizona_dvfs_up(component, ARIZONA_DVFS_SR1_RQ);
 		else
-			ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
+			ret = arizona_dvfs_down(component, ARIZONA_DVFS_SR1_RQ);
 
 		if (ret) {
 			arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
@@ -1721,24 +1719,24 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
 	case ARIZONA_CLK_SYSCLK:
 		switch (priv->arizona->type) {
 		case WM5102:
-			arizona_wm5102_set_dac_comp(codec,
+			arizona_wm5102_set_dac_comp(component,
 						    params_rate(params));
 			break;
 		default:
 			break;
 		}
 
-		snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
+		snd_soc_component_update_bits(component, ARIZONA_SAMPLE_RATE_1,
 				    ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
 		if (base)
-			snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
+			snd_soc_component_update_bits(component, base + ARIZONA_AIF_RATE_CTRL,
 					    ARIZONA_AIF1_RATE_MASK, 0);
 		break;
 	case ARIZONA_CLK_ASYNCCLK:
-		snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
+		snd_soc_component_update_bits(component, ARIZONA_ASYNC_SAMPLE_RATE_1,
 				    ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
 		if (base)
-			snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
+			snd_soc_component_update_bits(component, base + ARIZONA_AIF_RATE_CTRL,
 					    ARIZONA_AIF1_RATE_MASK,
 					    8 << ARIZONA_AIF1_RATE_SHIFT);
 		break;
@@ -1750,20 +1748,20 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
+static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
 				    int base, int bclk, int lrclk, int frame)
 {
 	int val;
 
-	val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_BCLK_CTRL);
 	if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
 		return true;
 
-	val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_TX_BCLK_RATE);
 	if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
 		return true;
 
-	val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_FRAME_CTRL_1);
 	if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
 			     ARIZONA_AIF1TX_SLOT_LEN_MASK)))
 		return true;
@@ -1775,8 +1773,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int base = dai->driver->base;
 	const int *rates;
@@ -1813,7 +1811,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* Force multiple of 2 channels for I2S mode */
-	val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_FORMAT);
 	val &= ARIZONA_AIF1_FMT_MASK;
 	if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
 		arizona_aif_dbg(dai, "Forcing stereo mode\n");
@@ -1841,13 +1839,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
 
 	frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
 
-	reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
+	reconfig = arizona_aif_cfg_changed(component, base, bclk, lrclk, frame);
 
 	if (reconfig) {
 		/* Save AIF TX/RX state */
-		aif_tx_state = snd_soc_read(codec,
+		aif_tx_state = snd_soc_component_read32(component,
 					    base + ARIZONA_AIF_TX_ENABLES);
-		aif_rx_state = snd_soc_read(codec,
+		aif_rx_state = snd_soc_component_read32(component,
 					    base + ARIZONA_AIF_RX_ENABLES);
 		/* Disable AIF TX/RX before reconfiguring it */
 		regmap_update_bits_async(arizona->regmap,
@@ -1908,9 +1906,9 @@ static const char *arizona_dai_clk_str(int clk_id)
 static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
 	struct snd_soc_dapm_route routes[2];
 
@@ -1926,12 +1924,12 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
 		return 0;
 
 	if (dai->active) {
-		dev_err(codec->dev, "Can't change clock on active DAI %d\n",
+		dev_err(component->dev, "Can't change clock on active DAI %d\n",
 			dai->id);
 		return -EBUSY;
 	}
 
-	dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
+	dev_dbg(component->dev, "Setting AIF%d to %s\n", dai->id + 1,
 		arizona_dai_clk_str(clk_id));
 
 	memset(&routes, 0, sizeof(routes));
@@ -1953,7 +1951,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
 
 static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int base = dai->driver->base;
 	unsigned int reg;
 
@@ -1962,7 +1960,7 @@ static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
 	else
 		reg = 0;
 
-	return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
+	return snd_soc_component_update_bits(component, base + ARIZONA_AIF_RATE_CTRL,
 				   ARIZONA_AIF1_TRI, reg);
 }
 
@@ -1970,8 +1968,8 @@ static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
 					 unsigned int base,
 					 int channels, unsigned int mask)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int slot, i;
 
@@ -1992,8 +1990,8 @@ static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
 static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	int base = dai->driver->base;
 	int rx_max_chan = dai->driver->playback.channels_max;
@@ -2645,7 +2643,7 @@ EXPORT_SYMBOL_GPL(arizona_init_fll);
 /**
  * arizona_set_output_mode - Set the mode of the specified output
  *
- * @codec: Device to configure
+ * @component: Device to configure
  * @output: Output number
  * @diff: True to set the output to differential mode
  *
@@ -2658,7 +2656,7 @@ EXPORT_SYMBOL_GPL(arizona_init_fll);
  * Most systems have a single static configuration and should use
  * platform data instead.
  */
-int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
+int arizona_set_output_mode(struct snd_soc_component *component, int output, bool diff)
 {
 	unsigned int reg, val;
 
@@ -2672,7 +2670,7 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
 	else
 		val = 0;
 
-	return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
+	return snd_soc_component_update_bits(component, reg, ARIZONA_OUT1_MONO, val);
 }
 EXPORT_SYMBOL_GPL(arizona_set_output_mode);
 
@@ -2721,8 +2719,8 @@ static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
 int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	struct soc_bytes *params = (void *)kcontrol->private_value;
 	unsigned int val;
 	__be16 *data;
@@ -2765,8 +2763,8 @@ EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
 int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
 			   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	__be16 *data = (__be16 *)ucontrol->value.bytes.data;
 	s16 val = be16_to_cpu(*data);
 
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index dfdf6d8c9687..e3ccee5627c6 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -273,7 +273,7 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
 
 int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
 		   int event);
-int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source,
+int arizona_set_sysclk(struct snd_soc_component *component, int clk_id, int source,
 		       unsigned int freq, int dir);
 
 extern const struct snd_soc_dai_ops arizona_dai_ops;
@@ -297,8 +297,8 @@ struct arizona_fll {
 	char clock_ok_name[ARIZONA_FLL_NAME_LEN];
 };
 
-int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
-int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
+int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags);
+int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags);
 int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event);
 void arizona_init_dvfs(struct arizona_priv *priv);
@@ -310,9 +310,9 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
 int arizona_set_fll(struct arizona_fll *fll, int source,
 		    unsigned int Fref, unsigned int Fout);
 
-int arizona_init_spk(struct snd_soc_codec *codec);
-int arizona_init_gpio(struct snd_soc_codec *codec);
-int arizona_init_mono(struct snd_soc_codec *codec);
+int arizona_init_spk(struct snd_soc_component *component);
+int arizona_init_gpio(struct snd_soc_component *component);
+int arizona_init_mono(struct snd_soc_component *component);
 
 int arizona_init_common(struct arizona *arizona);
 int arizona_init_vol_limit(struct arizona *arizona);
@@ -322,20 +322,20 @@ int arizona_free_spk_irqs(struct arizona *arizona);
 
 int arizona_init_dai(struct arizona_priv *priv, int dai);
 
-int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
+int arizona_set_output_mode(struct snd_soc_component *component, int output,
 			    bool diff);
 
-bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
+bool arizona_input_analog(struct snd_soc_component *component, int shift);
 
 const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
 
-static inline int arizona_register_notifier(struct snd_soc_codec *codec,
+static inline int arizona_register_notifier(struct snd_soc_component *component,
 					    struct notifier_block *nb,
 					    int (*notify)
 					    (struct notifier_block *nb,
 					    unsigned long action, void *data))
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 
 	nb->notifier_call = notify;
@@ -343,10 +343,10 @@ static inline int arizona_register_notifier(struct snd_soc_codec *codec,
 	return blocking_notifier_chain_register(&arizona->notifier, nb);
 }
 
-static inline int arizona_unregister_notifier(struct snd_soc_codec *codec,
+static inline int arizona_unregister_notifier(struct snd_soc_component *component,
 					      struct notifier_block *nb)
 {
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 
 	return blocking_notifier_chain_unregister(&arizona->notifier, nb);
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index 806191addb44..842204203eb3 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -62,25 +62,26 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
 	}
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
-	.component_driver = {
-		.dapm_widgets		= bt_sco_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(bt_sco_widgets),
-		.dapm_routes		= bt_sco_routes,
-		.num_dapm_routes	= ARRAY_SIZE(bt_sco_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_bt_sco = {
+	.dapm_widgets		= bt_sco_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(bt_sco_widgets),
+	.dapm_routes		= bt_sco_routes,
+	.num_dapm_routes	= ARRAY_SIZE(bt_sco_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int bt_sco_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_bt_sco,
 				      bt_sco_dai, ARRAY_SIZE(bt_sco_dai));
 }
 
 static int bt_sco_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 3bf93652bb31..3301861d3502 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -45,7 +45,7 @@ static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
 
 static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 reg;
 
 	if (mute)
@@ -53,7 +53,7 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
 	else
 		reg = 0;
 
-	snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
+	snd_soc_component_update_bits(component, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
 			    reg);
 
 	return 0;
@@ -72,23 +72,23 @@ static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return -EINVAL;
 }
 
-static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
+static int cq93vc_set_bias_level(struct snd_soc_component *component,
 				enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_write(codec, DAVINCI_VC_REG12,
+		snd_soc_component_write(component, DAVINCI_VC_REG12,
 			     DAVINCI_VC_REG12_POWER_ALL_ON);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec, DAVINCI_VC_REG12,
+		snd_soc_component_write(component, DAVINCI_VC_REG12,
 			     DAVINCI_VC_REG12_POWER_ALL_OFF);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* force all power off */
-		snd_soc_write(codec, DAVINCI_VC_REG12,
+		snd_soc_component_write(component, DAVINCI_VC_REG12,
 			     DAVINCI_VC_REG12_POWER_ALL_OFF);
 		break;
 	}
@@ -130,24 +130,25 @@ static int cq93vc_probe(struct snd_soc_component *component)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
-	.set_bias_level = cq93vc_set_bias_level,
-	.component_driver = {
-		.probe = cq93vc_probe,
-		.controls = cq93vc_snd_controls,
-		.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cq93vc = {
+	.set_bias_level		= cq93vc_set_bias_level,
+	.probe			= cq93vc_probe,
+	.controls		= cq93vc_snd_controls,
+	.num_controls		= ARRAY_SIZE(cq93vc_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int cq93vc_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_cq93vc, &cq93vc_dai, 1);
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_cq93vc, &cq93vc_dai, 1);
 }
 
 static int cq93vc_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index bc3a72e4c4ed..4297058b6938 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -43,7 +43,7 @@ static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
 
 struct  cs35l32_private {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
 	struct cs35l32_platform_data pdata;
 	struct gpio_desc *reset_gpio;
@@ -154,16 +154,16 @@ static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
 
 static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+		snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
 				    CS35L32_ADSP_MASTER_MASK,
 				CS35L32_ADSP_MASTER_MASK);
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+		snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
 				    CS35L32_ADSP_MASTER_MASK, 0);
 		break;
 	default:
@@ -175,9 +175,9 @@ static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
 static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	return snd_soc_update_bits(codec, CS35L32_PWRCTL2,
+	return snd_soc_component_update_bits(component, CS35L32_PWRCTL2,
 					CS35L32_SDOUT_3ST, tristate << 3);
 }
 
@@ -202,7 +202,7 @@ static struct snd_soc_dai_driver cs35l32_dai[] = {
 	}
 };
 
-static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
+static int cs35l32_component_set_sysclk(struct snd_soc_component *component,
 			      int clk_id, int source, unsigned int freq, int dir)
 {
 	unsigned int val;
@@ -224,21 +224,22 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	return snd_soc_update_bits(codec, CS35L32_CLK_CTL,
+	return snd_soc_component_update_bits(component, CS35L32_CLK_CTL,
 			CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
-	.set_sysclk = cs35l32_codec_set_sysclk,
-
-	.component_driver = {
-		.controls		= cs35l32_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs35l32_snd_controls),
-		.dapm_widgets		= cs35l32_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs35l32_dapm_widgets),
-		.dapm_routes		= cs35l32_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cs35l32_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs35l32 = {
+	.set_sysclk		= cs35l32_component_set_sysclk,
+	.controls		= cs35l32_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs35l32_snd_controls),
+	.dapm_widgets		= cs35l32_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l32_dapm_widgets),
+	.dapm_routes		= cs35l32_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l32_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* Current and threshold powerup sequence Pg37 in datasheet */
@@ -483,8 +484,8 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
 	/* Clear MCLK Error Bit since we don't have the clock yet */
 	ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs35l32, cs35l32_dai,
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs35l32, cs35l32_dai,
 			ARRAY_SIZE(cs35l32_dai));
 	if (ret < 0)
 		goto err_disable;
@@ -501,8 +502,6 @@ static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
 {
 	struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
 
-	snd_soc_unregister_codec(&i2c_client->dev);
-
 	/* Hold down reset */
 	gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
 
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index 854cf8f27605..668cd3754209 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -42,7 +42,7 @@
 #define CS35L33_BOOT_DELAY	50
 
 struct cs35l33_private {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct cs35l33_pdata pdata;
 	struct regmap *regmap;
 	struct gpio_desc *reset_gpio;
@@ -201,8 +201,8 @@ static const struct snd_kcontrol_new cs35l33_snd_controls[] = {
 static int cs35l33_spkrdrv_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -211,15 +211,15 @@ static int cs35l33_spkrdrv_event(struct snd_soc_dapm_widget *w,
 			priv->amp_cal = true;
 			regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL,
 				    CS35L33_AMP_CAL, 0);
-			dev_dbg(codec->dev, "Amp calibration done\n");
+			dev_dbg(component->dev, "Amp calibration done\n");
 		}
-		dev_dbg(codec->dev, "Amp turned on\n");
+		dev_dbg(component->dev, "Amp turned on\n");
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		dev_dbg(codec->dev, "Amp turned off\n");
+		dev_dbg(component->dev, "Amp turned off\n");
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 		break;
 	}
 
@@ -229,8 +229,8 @@ static int cs35l33_spkrdrv_event(struct snd_soc_dapm_widget *w,
 static int cs35l33_sdin_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	switch (event) {
@@ -240,14 +240,14 @@ static int cs35l33_sdin_event(struct snd_soc_dapm_widget *w,
 		val = priv->is_tdm_mode ? 0 : CS35L33_PDN_TDM;
 		regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
 				    CS35L33_PDN_TDM, val);
-		dev_dbg(codec->dev, "BST turned on\n");
+		dev_dbg(component->dev, "BST turned on\n");
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		dev_dbg(codec->dev, "SDIN turned on\n");
+		dev_dbg(component->dev, "SDIN turned on\n");
 		if (!priv->amp_cal) {
 			regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL,
 				    CS35L33_AMP_CAL, CS35L33_AMP_CAL);
-			dev_dbg(codec->dev, "Amp calibration started\n");
+			dev_dbg(component->dev, "Amp calibration started\n");
 			usleep_range(10000, 11000);
 		}
 		break;
@@ -257,10 +257,10 @@ static int cs35l33_sdin_event(struct snd_soc_dapm_widget *w,
 		usleep_range(4000, 4100);
 		regmap_update_bits(priv->regmap, CS35L33_PWRCTL1,
 				    CS35L33_PDN_BST, CS35L33_PDN_BST);
-		dev_dbg(codec->dev, "BST and SDIN turned off\n");
+		dev_dbg(component->dev, "BST and SDIN turned off\n");
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 
 	}
 
@@ -270,8 +270,8 @@ static int cs35l33_sdin_event(struct snd_soc_dapm_widget *w,
 static int cs35l33_sdout_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 	unsigned int mask = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM;
 	unsigned int mask2 = CS35L33_SDOUT_3ST_TDM;
 	unsigned int val, val2;
@@ -289,15 +289,15 @@ static int cs35l33_sdout_event(struct snd_soc_dapm_widget *w,
 			/* set sdout_3st_tdm */
 			val2 = CS35L33_SDOUT_3ST_TDM;
 		}
-		dev_dbg(codec->dev, "SDOUT turned on\n");
+		dev_dbg(component->dev, "SDOUT turned on\n");
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		val = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM;
 		val2 = CS35L33_SDOUT_3ST_TDM;
-		dev_dbg(codec->dev, "SDOUT turned off\n");
+		dev_dbg(component->dev, "SDOUT turned off\n");
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 		return 0;
 	}
 
@@ -360,11 +360,11 @@ static const struct snd_soc_dapm_route cs35l33_vp_vbst_mon_route[] = {
 	{"VBSTMON", NULL, "MON"},
 };
 
-static int cs35l33_set_bias_level(struct snd_soc_codec *codec,
+static int cs35l33_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
 	unsigned int val;
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -441,19 +441,19 @@ static int cs35l33_get_mclk_coeff(int mclk, int srate)
 
 static int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 		regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL,
 			CS35L33_MS_MASK, CS35L33_MS_MASK);
-		dev_dbg(codec->dev, "Audio port in master mode\n");
+		dev_dbg(component->dev, "Audio port in master mode\n");
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
 		regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL,
 			CS35L33_MS_MASK, 0);
-		dev_dbg(codec->dev, "Audio port in slave mode\n");
+		dev_dbg(component->dev, "Audio port in slave mode\n");
 		break;
 	default:
 		return -EINVAL;
@@ -466,11 +466,11 @@ static int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		 * closely, it is dsp-a with fsync shifted left by half bclk
 		 */
 		priv->is_tdm_mode = true;
-		dev_dbg(codec->dev, "Audio port in TDM mode\n");
+		dev_dbg(component->dev, "Audio port in TDM mode\n");
 		break;
 	case SND_SOC_DAIFMT_I2S:
 		priv->is_tdm_mode = false;
-		dev_dbg(codec->dev, "Audio port in I2S mode\n");
+		dev_dbg(component->dev, "Audio port in I2S mode\n");
 		break;
 	default:
 		return -EINVAL;
@@ -483,8 +483,8 @@ static int cs35l33_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 	int sample_size = params_width(params);
 	int coeff = cs35l33_get_mclk_coeff(priv->mclk_int, params_rate(params));
 
@@ -505,7 +505,7 @@ static int cs35l33_pcm_hw_params(struct snd_pcm_substream *substream,
 			sample_size << CS35L33_AUDIN_RX_DEPTH_SHIFT);
 	}
 
-	dev_dbg(codec->dev, "sample rate=%d, bits per sample=%d\n",
+	dev_dbg(component->dev, "sample rate=%d, bits per sample=%d\n",
 		params_rate(params), params_width(params));
 
 	return 0;
@@ -532,8 +532,8 @@ static int cs35l33_pcm_startup(struct snd_pcm_substream *substream,
 
 static int cs35l33_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 
 	if (tristate) {
 		regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
@@ -553,9 +553,9 @@ static int cs35l33_set_tristate(struct snd_soc_dai *dai, int tristate)
 static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 	unsigned int reg, bit_pos, i;
 	int slot, slot_num;
 
@@ -567,7 +567,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	if (slot >= 0) {
 		regmap_update_bits(priv->regmap, CS35L33_RX_AUD,
 			CS35L33_X_LOC, slot);
-		dev_dbg(codec->dev, "Audio starts from slots %d", slot);
+		dev_dbg(component->dev, "Audio starts from slots %d", slot);
 	}
 
 	/*
@@ -593,7 +593,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		if (slot_num == 0) {
 			regmap_update_bits(priv->regmap, CS35L33_TX_VMON,
 				CS35L33_X_STATE | CS35L33_X_LOC, slot);
-			dev_dbg(codec->dev, "VMON enabled in slots %d-%d",
+			dev_dbg(component->dev, "VMON enabled in slots %d-%d",
 				slot, slot + 1);
 		}
 
@@ -601,7 +601,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		if (slot_num == 3) {
 			regmap_update_bits(priv->regmap, CS35L33_TX_IMON,
 				CS35L33_X_STATE | CS35L33_X_LOC, slot);
-			dev_dbg(codec->dev, "IMON enabled in slots %d-%d",
+			dev_dbg(component->dev, "IMON enabled in slots %d-%d",
 				slot, slot + 1);
 		}
 
@@ -611,7 +611,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				CS35L33_X_STATE | CS35L33_X_LOC, slot);
 			snd_soc_dapm_add_routes(dapm,
 				&cs35l33_vp_vbst_mon_route[0], 2);
-			dev_dbg(codec->dev, "VPMON enabled in slots %d", slot);
+			dev_dbg(component->dev, "VPMON enabled in slots %d", slot);
 		}
 
 		/* configure VBSTMON_TX_LOC */
@@ -620,7 +620,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				CS35L33_X_STATE | CS35L33_X_LOC, slot);
 			snd_soc_dapm_add_routes(dapm,
 				&cs35l33_vp_vbst_mon_route[2], 2);
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"VBSTMON enabled in slots %d", slot);
 		}
 
@@ -638,10 +638,10 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
-static int cs35l33_codec_set_sysclk(struct snd_soc_codec *codec,
+static int cs35l33_component_set_sysclk(struct snd_soc_component *component,
 		int clk_id, int source, unsigned int freq, int dir)
 {
-	struct cs35l33_private *cs35l33 = snd_soc_codec_get_drvdata(codec);
+	struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case CS35L33_MCLK_5644:
@@ -663,7 +663,7 @@ static int cs35l33_codec_set_sysclk(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "external mclk freq=%d, internal mclk freq=%d\n",
+	dev_dbg(component->dev, "external mclk freq=%d, internal mclk freq=%d\n",
 		freq, cs35l33->mclk_int);
 
 	return 0;
@@ -698,12 +698,12 @@ static struct snd_soc_dai_driver cs35l33_dai = {
 		.symmetric_rates = 1,
 };
 
-static int cs35l33_set_hg_data(struct snd_soc_codec *codec,
+static int cs35l33_set_hg_data(struct snd_soc_component *component,
 			       struct cs35l33_pdata *pdata)
 {
 	struct cs35l33_hg *hg_config = &pdata->hg_config;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
 
 	if (hg_config->enable_hg_algo) {
 		regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL,
@@ -747,20 +747,20 @@ static int cs35l33_set_hg_data(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int cs35l33_set_bst_ipk(struct snd_soc_codec *codec, unsigned int bst)
+static int cs35l33_set_bst_ipk(struct snd_soc_component *component, unsigned int bst)
 {
-	struct cs35l33_private *cs35l33 = snd_soc_codec_get_drvdata(codec);
+	struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component);
 	int ret = 0, steps = 0;
 
 	/* Boost current in uA */
 	if (bst > 3600000 || bst < 1850000) {
-		dev_err(codec->dev, "Invalid boost current %d\n", bst);
+		dev_err(component->dev, "Invalid boost current %d\n", bst);
 		ret = -EINVAL;
 		goto err;
 	}
 
 	if (bst % 15625) {
-		dev_err(codec->dev, "Current not a multiple of 15625uA (%d)\n",
+		dev_err(component->dev, "Current not a multiple of 15625uA (%d)\n",
 			bst);
 		ret = -EINVAL;
 		goto err;
@@ -778,12 +778,12 @@ static int cs35l33_set_bst_ipk(struct snd_soc_codec *codec, unsigned int bst)
 	return ret;
 }
 
-static int cs35l33_probe(struct snd_soc_codec *codec)
+static int cs35l33_probe(struct snd_soc_component *component)
 {
-	struct cs35l33_private *cs35l33 = snd_soc_codec_get_drvdata(codec);
+	struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component);
 
-	cs35l33->codec = codec;
-	pm_runtime_get_sync(codec->dev);
+	cs35l33->component = component;
+	pm_runtime_get_sync(component->dev);
 
 	regmap_update_bits(cs35l33->regmap, CS35L33_PROTECT_CTL,
 		CS35L33_ALIVE_WD_DIS, 0x8);
@@ -799,24 +799,24 @@ static int cs35l33_probe(struct snd_soc_codec *codec)
 		cs35l33->pdata.amp_drv_sel << CS35L33_AMP_DRV_SEL_SHIFT);
 
 	if (cs35l33->pdata.boost_ipk)
-		cs35l33_set_bst_ipk(codec, cs35l33->pdata.boost_ipk);
+		cs35l33_set_bst_ipk(component, cs35l33->pdata.boost_ipk);
 
 	if (cs35l33->enable_soft_ramp) {
-		snd_soc_update_bits(codec, CS35L33_DAC_CTL,
+		snd_soc_component_update_bits(component, CS35L33_DAC_CTL,
 			CS35L33_DIGSFT, CS35L33_DIGSFT);
-		snd_soc_update_bits(codec, CS35L33_DAC_CTL,
+		snd_soc_component_update_bits(component, CS35L33_DAC_CTL,
 			CS35L33_DSR_RATE, cs35l33->pdata.ramp_rate);
 	} else {
-		snd_soc_update_bits(codec, CS35L33_DAC_CTL,
+		snd_soc_component_update_bits(component, CS35L33_DAC_CTL,
 			CS35L33_DIGSFT, 0);
 	}
 
 	/* update IMON scaling rate if different from default of 0x8 */
 	if (cs35l33->pdata.imon_adc_scale != 0x8)
-		snd_soc_update_bits(codec, CS35L33_ADC_CTL,
+		snd_soc_component_update_bits(component, CS35L33_ADC_CTL,
 			CS35L33_IMON_SCALE, cs35l33->pdata.imon_adc_scale);
 
-	cs35l33_set_hg_data(codec, &(cs35l33->pdata));
+	cs35l33_set_hg_data(component, &(cs35l33->pdata));
 
 	/*
 	 * unmask important interrupts that causes the chip to enter
@@ -826,26 +826,24 @@ static int cs35l33_probe(struct snd_soc_codec *codec)
 		CS35L33_M_OTE | CS35L33_M_OTW | CS35L33_M_AMP_SHORT |
 		CS35L33_M_CAL_ERR, 0);
 
-	pm_runtime_put_sync(codec->dev);
+	pm_runtime_put_sync(component->dev);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs35l33 = {
-	.probe = cs35l33_probe,
-
-	.set_bias_level = cs35l33_set_bias_level,
-	.set_sysclk = cs35l33_codec_set_sysclk,
-
-	.component_driver = {
-		.controls		= cs35l33_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs35l33_snd_controls),
-		.dapm_widgets		= cs35l33_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs35l33_dapm_widgets),
-		.dapm_routes		= cs35l33_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cs35l33_audio_map),
-	},
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_cs35l33 = {
+	.probe			= cs35l33_probe,
+	.set_bias_level		= cs35l33_set_bias_level,
+	.set_sysclk		= cs35l33_component_set_sysclk,
+	.controls		= cs35l33_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs35l33_snd_controls),
+	.dapm_widgets		= cs35l33_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l33_dapm_widgets),
+	.dapm_routes		= cs35l33_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l33_audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config cs35l33_regmap = {
@@ -967,7 +965,7 @@ static int cs35l33_get_hg_data(const struct device_node *np,
 static irqreturn_t cs35l33_irq_thread(int irq, void *data)
 {
 	struct cs35l33_private *cs35l33 = data;
-	struct snd_soc_codec *codec = cs35l33->codec;
+	struct snd_soc_component *component = cs35l33->component;
 	unsigned int sticky_val1, sticky_val2, current_val, mask1, mask2;
 
 	regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_2,
@@ -989,9 +987,9 @@ static irqreturn_t cs35l33_irq_thread(int irq, void *data)
 	/* handle the interrupts */
 
 	if (sticky_val1 & CS35L33_AMP_SHORT) {
-		dev_crit(codec->dev, "Amp short error\n");
+		dev_crit(component->dev, "Amp short error\n");
 		if (!(current_val & CS35L33_AMP_SHORT)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Amp short error release\n");
 			regmap_update_bits(cs35l33->regmap,
 				CS35L33_AMP_CTL,
@@ -1007,13 +1005,13 @@ static irqreturn_t cs35l33_irq_thread(int irq, void *data)
 	}
 
 	if (sticky_val1 & CS35L33_CAL_ERR) {
-		dev_err(codec->dev, "Cal error\n");
+		dev_err(component->dev, "Cal error\n");
 
 		/* redo the calibration in next power up */
 		cs35l33->amp_cal = false;
 
 		if (!(current_val & CS35L33_CAL_ERR)) {
-			dev_dbg(codec->dev, "Cal error release\n");
+			dev_dbg(component->dev, "Cal error release\n");
 			regmap_update_bits(cs35l33->regmap,
 				CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS,
 				0);
@@ -1027,9 +1025,9 @@ static irqreturn_t cs35l33_irq_thread(int irq, void *data)
 	}
 
 	if (sticky_val1 & CS35L33_OTE) {
-		dev_crit(codec->dev, "Over temperature error\n");
+		dev_crit(component->dev, "Over temperature error\n");
 		if (!(current_val & CS35L33_OTE)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Over temperature error release\n");
 			regmap_update_bits(cs35l33->regmap,
 				CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0);
@@ -1042,9 +1040,9 @@ static irqreturn_t cs35l33_irq_thread(int irq, void *data)
 	}
 
 	if (sticky_val1 & CS35L33_OTW) {
-		dev_err(codec->dev, "Over temperature warning\n");
+		dev_err(component->dev, "Over temperature warning\n");
 		if (!(current_val & CS35L33_OTW)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Over temperature warning release\n");
 			regmap_update_bits(cs35l33->regmap,
 				CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0);
@@ -1056,21 +1054,21 @@ static irqreturn_t cs35l33_irq_thread(int irq, void *data)
 		}
 	}
 	if (CS35L33_ALIVE_ERR & sticky_val1)
-		dev_err(codec->dev, "ERROR: ADSPCLK Interrupt\n");
+		dev_err(component->dev, "ERROR: ADSPCLK Interrupt\n");
 
 	if (CS35L33_MCLK_ERR & sticky_val1)
-		dev_err(codec->dev, "ERROR: MCLK Interrupt\n");
+		dev_err(component->dev, "ERROR: MCLK Interrupt\n");
 
 	if (CS35L33_VMON_OVFL & sticky_val2)
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"ERROR: VMON Overflow Interrupt\n");
 
 	if (CS35L33_IMON_OVFL & sticky_val2)
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"ERROR: IMON Overflow Interrupt\n");
 
 	if (CS35L33_VPMON_OVFL & sticky_val2)
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"ERROR: VPMON Overflow Interrupt\n");
 
 	return IRQ_HANDLED;
@@ -1236,10 +1234,10 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client,
 	pm_runtime_set_active(&i2c_client->dev);
 	pm_runtime_enable(&i2c_client->dev);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs35l33, &cs35l33_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs35l33, &cs35l33_dai, 1);
 	if (ret < 0) {
-		dev_err(&i2c_client->dev, "%s: Register codec failed\n",
+		dev_err(&i2c_client->dev, "%s: Register component failed\n",
 			__func__);
 		goto err_enable;
 	}
@@ -1257,8 +1255,6 @@ static int cs35l33_i2c_remove(struct i2c_client *client)
 {
 	struct cs35l33_private *cs35l33 = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
-
 	gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
 
 	pm_runtime_disable(&client->dev);
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 0600d5264c4c..5063c05afa27 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -43,7 +43,7 @@
 #define CS35L34_START_DELAY 50
 
 struct  cs35l34_private {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct cs35l34_platform_data pdata;
 	struct regmap *regmap;
 	struct regulator_bulk_data core_supplies[2];
@@ -237,8 +237,8 @@ static bool cs35l34_precious_register(struct device *dev, unsigned int reg)
 static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (event) {
@@ -250,7 +250,7 @@ static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w,
 		ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1,
 						CS35L34_PDN_ALL, 0);
 		if (ret < 0) {
-			dev_err(codec->dev, "Cannot set Power bits %d\n", ret);
+			dev_err(component->dev, "Cannot set Power bits %d\n", ret);
 			return ret;
 		}
 		usleep_range(5000, 5100);
@@ -272,8 +272,8 @@ static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w,
 static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
 	unsigned int reg, bit_pos;
 	int slot, slot_num;
 
@@ -284,7 +284,7 @@ static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	/* scan rx_mask for aud slot */
 	slot = ffs(rx_mask) - 1;
 	if (slot >= 0)
-		snd_soc_update_bits(codec, CS35L34_TDM_RX_CTL_1_AUDIN,
+		snd_soc_component_update_bits(component, CS35L34_TDM_RX_CTL_1_AUDIN,
 					CS35L34_X_LOC, slot);
 
 	/* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot)
@@ -294,10 +294,10 @@ static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	slot_num = 0;
 
 	/* disable vpmon/vbstmon: enable later if set in tx_mask */
-	snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON,
+	snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_3_VPMON,
 				CS35L34_X_STATE | CS35L34_X_LOC,
 				CS35L34_X_STATE | CS35L34_X_LOC);
-	snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_4_VBSTMON,
+	snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_4_VBSTMON,
 				CS35L34_X_STATE | CS35L34_X_LOC,
 				CS35L34_X_STATE | CS35L34_X_LOC);
 
@@ -305,22 +305,22 @@ static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	while (slot >= 0) {
 		/* configure VMON_TX_LOC */
 		if (slot_num == 0)
-			snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_1_VMON,
+			snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_1_VMON,
 					CS35L34_X_STATE | CS35L34_X_LOC, slot);
 
 		/* configure IMON_TX_LOC */
 		if (slot_num == 4) {
-			snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_2_IMON,
+			snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_2_IMON,
 					CS35L34_X_STATE | CS35L34_X_LOC, slot);
 		}
 		/* configure VPMON_TX_LOC */
 		if (slot_num == 3) {
-			snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON,
+			snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_3_VPMON,
 					CS35L34_X_STATE | CS35L34_X_LOC, slot);
 		}
 		/* configure VBSTMON_TX_LOC */
 		if (slot_num == 7) {
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 				CS35L34_TDM_TX_CTL_4_VBSTMON,
 				CS35L34_X_STATE | CS35L34_X_LOC, slot);
 		}
@@ -328,7 +328,7 @@ static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		/* Enable the relevant tx slot */
 		reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8);
 		bit_pos = slot - ((slot / 8) * (8));
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 			1 << bit_pos, 1 << bit_pos);
 
 		tx_mask &= ~(1 << slot);
@@ -342,8 +342,8 @@ static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -382,8 +382,8 @@ static const struct snd_kcontrol_new cs35l34_snd_controls[] = {
 static int cs35l34_mclk_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
 	int ret, i;
 	unsigned int reg;
 
@@ -524,8 +524,8 @@ static int cs35l34_get_mclk_coeff(int mclk, int srate)
 
 static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -546,15 +546,15 @@ static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
 	int srate = params_rate(params);
 	int ret;
 
 	int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate);
 
 	if (coeff < 0) {
-		dev_err(codec->dev, "ERROR: Invalid mclk %d and/or srate %d\n",
+		dev_err(component->dev, "ERROR: Invalid mclk %d and/or srate %d\n",
 			priv->mclk_int, srate);
 		return coeff;
 	}
@@ -562,7 +562,7 @@ static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
 	ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
 		CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate);
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to set clock state %d\n", ret);
+		dev_err(component->dev, "Failed to set clock state %d\n", ret);
 
 	return ret;
 }
@@ -590,13 +590,13 @@ static int cs35l34_pcm_startup(struct snd_pcm_substream *substream,
 static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
 
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (tristate)
-		snd_soc_update_bits(codec, CS35L34_PWRCTL3,
+		snd_soc_component_update_bits(component, CS35L34_PWRCTL3,
 					CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT);
 	else
-		snd_soc_update_bits(codec, CS35L34_PWRCTL3,
+		snd_soc_component_update_bits(component, CS35L34_PWRCTL3,
 					CS35L34_PDN_SDOUT, 0);
 	return 0;
 }
@@ -604,8 +604,8 @@ static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate)
 static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l34_private *cs35l34 = snd_soc_component_get_drvdata(component);
 	unsigned int value;
 
 	switch (freq) {
@@ -634,7 +634,7 @@ static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai,
 		cs35l34->mclk_int = freq / 2;
 	break;
 	default:
-		dev_err(codec->dev, "ERROR: Invalid Frequency %d\n", freq);
+		dev_err(component->dev, "ERROR: Invalid Frequency %d\n", freq);
 		cs35l34->mclk_int = 0;
 		return -EINVAL;
 	}
@@ -676,7 +676,7 @@ static struct snd_soc_dai_driver cs35l34_dai = {
 static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34,
 	unsigned int inductor)
 {
-	struct snd_soc_codec *codec = cs35l34->codec;
+	struct snd_soc_component *component = cs35l34->component;
 
 	switch (inductor) {
 	case 1000: /* 1 uH */
@@ -708,19 +708,19 @@ static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34,
 		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3);
 		break;
 	default:
-		dev_err(codec->dev, "%s Invalid Inductor Value %d uH\n",
+		dev_err(component->dev, "%s Invalid Inductor Value %d uH\n",
 			__func__, inductor);
 		return -EINVAL;
 	}
 	return 0;
 }
 
-static int cs35l34_probe(struct snd_soc_codec *codec)
+static int cs35l34_probe(struct snd_soc_component *component)
 {
 	int ret = 0;
-	struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec);
+	struct cs35l34_private *cs35l34 = snd_soc_component_get_drvdata(component);
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	/* Set over temperature warning attenuation to 6 dB */
 	regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
@@ -773,23 +773,24 @@ static int cs35l34_probe(struct snd_soc_codec *codec)
 		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL,
 			1, 1);
 
-	pm_runtime_put_sync(codec->dev);
+	pm_runtime_put_sync(component->dev);
 
 	return ret;
 }
 
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs35l34 = {
-	.probe = cs35l34_probe,
-
-	.component_driver = {
-		.dapm_widgets = cs35l34_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(cs35l34_dapm_widgets),
-		.dapm_routes = cs35l34_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(cs35l34_audio_map),
-		.controls = cs35l34_snd_controls,
-		.num_controls = ARRAY_SIZE(cs35l34_snd_controls),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs35l34 = {
+	.probe			= cs35l34_probe,
+	.dapm_widgets		= cs35l34_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l34_dapm_widgets),
+	.dapm_routes		= cs35l34_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l34_audio_map),
+	.controls		= cs35l34_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs35l34_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct regmap_config cs35l34_regmap = {
@@ -864,7 +865,7 @@ static int cs35l34_handle_of_data(struct i2c_client *i2c_client,
 static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 {
 	struct cs35l34_private *cs35l34 = data;
-	struct snd_soc_codec *codec = cs35l34->codec;
+	struct snd_soc_component *component = cs35l34->component;
 	unsigned int sticky1, sticky2, sticky3, sticky4;
 	unsigned int mask1, mask2, mask3, mask4, current1;
 
@@ -887,11 +888,11 @@ static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &current1);
 
 	if (sticky1 & CS35L34_CAL_ERR) {
-		dev_err(codec->dev, "Cal error\n");
+		dev_err(component->dev, "Cal error\n");
 
 		/* error is no longer asserted; safe to reset */
 		if (!(current1 & CS35L34_CAL_ERR)) {
-			dev_dbg(codec->dev, "Cal error release\n");
+			dev_dbg(component->dev, "Cal error release\n");
 			regmap_update_bits(cs35l34->regmap,
 					CS35L34_PROT_RELEASE_CTL,
 					CS35L34_CAL_ERR_RLS, 0);
@@ -907,14 +908,14 @@ static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 	}
 
 	if (sticky1 & CS35L34_ALIVE_ERR)
-		dev_err(codec->dev, "Alive error\n");
+		dev_err(component->dev, "Alive error\n");
 
 	if (sticky1 & CS35L34_AMP_SHORT) {
-		dev_crit(codec->dev, "Amp short error\n");
+		dev_crit(component->dev, "Amp short error\n");
 
 		/* error is no longer asserted; safe to reset */
 		if (!(current1 & CS35L34_AMP_SHORT)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Amp short error release\n");
 			regmap_update_bits(cs35l34->regmap,
 					CS35L34_PROT_RELEASE_CTL,
@@ -930,11 +931,11 @@ static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 	}
 
 	if (sticky1 & CS35L34_OTW) {
-		dev_crit(codec->dev, "Over temperature warning\n");
+		dev_crit(component->dev, "Over temperature warning\n");
 
 		/* error is no longer asserted; safe to reset */
 		if (!(current1 & CS35L34_OTW)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Over temperature warning release\n");
 			regmap_update_bits(cs35l34->regmap,
 					CS35L34_PROT_RELEASE_CTL,
@@ -950,11 +951,11 @@ static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 	}
 
 	if (sticky1 & CS35L34_OTE) {
-		dev_crit(codec->dev, "Over temperature error\n");
+		dev_crit(component->dev, "Over temperature error\n");
 
 		/* error is no longer asserted; safe to reset */
 		if (!(current1 & CS35L34_OTE)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Over temperature error release\n");
 			regmap_update_bits(cs35l34->regmap,
 					CS35L34_PROT_RELEASE_CTL,
@@ -970,7 +971,7 @@ static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 	}
 
 	if (sticky3 & CS35L34_BST_HIGH) {
-		dev_crit(codec->dev, "VBST too high error; powering off!\n");
+		dev_crit(component->dev, "VBST too high error; powering off!\n");
 		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2,
 				CS35L34_PDN_AMP, CS35L34_PDN_AMP);
 		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1,
@@ -978,7 +979,7 @@ static irqreturn_t cs35l34_irq_thread(int irq, void *data)
 	}
 
 	if (sticky3 & CS35L34_LBST_SHORT) {
-		dev_crit(codec->dev, "LBST short error; powering off!\n");
+		dev_crit(component->dev, "LBST short error; powering off!\n");
 		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2,
 				CS35L34_PDN_AMP, CS35L34_PDN_AMP);
 		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1,
@@ -1108,11 +1109,11 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client,
 	pm_runtime_set_active(&i2c_client->dev);
 	pm_runtime_enable(&i2c_client->dev);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs35l34, &cs35l34_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs35l34, &cs35l34_dai, 1);
 	if (ret < 0) {
 		dev_err(&i2c_client->dev,
-			"%s: Register codec failed\n", __func__);
+			"%s: Register component failed\n", __func__);
 		goto err_regulator;
 	}
 
@@ -1129,8 +1130,6 @@ static int cs35l34_i2c_remove(struct i2c_client *client)
 {
 	struct cs35l34_private *cs35l34 = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
-
 	gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
 
 	pm_runtime_disable(&client->dev);
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 129978d1243e..a4a2cb171bdf 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -194,8 +194,8 @@ static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35)
 static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (event) {
@@ -231,7 +231,7 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
 				   1 << CS35L35_AMP_DIGSFT_SHIFT);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 		ret = -EINVAL;
 	}
 	return ret;
@@ -240,8 +240,8 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
 static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 	unsigned int reg[4];
 	int i;
 
@@ -301,7 +301,7 @@ static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w,
 
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 	}
 	return 0;
 }
@@ -369,8 +369,8 @@ static const struct snd_soc_dapm_route cs35l35_audio_map[] = {
 
 static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -470,8 +470,8 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 	struct classh_cfg *classh = &cs35l35->pdata.classh_algo;
 	int srate = params_rate(params);
 	int ret = 0;
@@ -482,7 +482,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 	int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate);
 
 	if (clk_ctl < 0) {
-		dev_err(codec->dev, "Invalid CLK:Rate %d:%d\n",
+		dev_err(component->dev, "Invalid CLK:Rate %d:%d\n",
 			cs35l35->sysclk, srate);
 		return -EINVAL;
 	}
@@ -490,7 +490,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 	ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2,
 			  CS35L35_CLK_CTL2_MASK, clk_ctl);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to set port config %d\n", ret);
+		dev_err(component->dev, "Failed to set port config %d\n", ret);
 		return ret;
 	}
 
@@ -509,7 +509,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 					CS35L35_CH_WKFET_DEL_MASK,
 					0 << CS35L35_CH_WKFET_DEL_SHIFT);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to set fet config %d\n",
+			dev_err(component->dev, "Failed to set fet config %d\n",
 				ret);
 			return ret;
 		}
@@ -531,7 +531,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 			audin_format = CS35L35_SDIN_DEPTH_24;
 			break;
 		default:
-			dev_err(codec->dev, "Unsupported Width %d\n",
+			dev_err(component->dev, "Unsupported Width %d\n",
 				params_width(params));
 			return -EINVAL;
 		}
@@ -554,7 +554,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 		 * to configure the CLOCK_CTL3 register correctly
 		 */
 		if ((cs35l35->sclk / srate) % 4) {
-			dev_err(codec->dev, "Unsupported sclk/fs ratio %d:%d\n",
+			dev_err(component->dev, "Unsupported sclk/fs ratio %d:%d\n",
 					cs35l35->sclk, srate);
 			return -EINVAL;
 		}
@@ -568,7 +568,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 			case CS35L35_SP_SCLKS_64FS:
 				break;
 			default:
-				dev_err(codec->dev, "ratio not supported\n");
+				dev_err(component->dev, "ratio not supported\n");
 				return -EINVAL;
 			}
 		} else {
@@ -578,7 +578,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 			case CS35L35_SP_SCLKS_64FS:
 				break;
 			default:
-				dev_err(codec->dev, "ratio not supported\n");
+				dev_err(component->dev, "ratio not supported\n");
 				return -EINVAL;
 			}
 		}
@@ -587,7 +587,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream,
 					CS35L35_SP_SCLKS_MASK, sp_sclks <<
 					CS35L35_SP_SCLKS_SHIFT);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to set fsclk %d\n", ret);
+			dev_err(component->dev, "Failed to set fsclk %d\n", ret);
 			return ret;
 		}
 	}
@@ -607,8 +607,8 @@ static const struct snd_pcm_hw_constraint_list cs35l35_constraints = {
 static int cs35l35_pcm_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 
 	if (!substream->runtime)
 		return 0;
@@ -635,8 +635,8 @@ static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = {
 static int cs35l35_pdm_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 
 	if (!substream->runtime)
 		return 0;
@@ -655,8 +655,8 @@ static int cs35l35_pdm_startup(struct snd_pcm_substream *substream,
 static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 
 	/* Need the SCLK Frequency regardless of sysclk source for I2S */
 	cs35l35->sclk = freq;
@@ -712,11 +712,11 @@ static struct snd_soc_dai_driver cs35l35_dai[] = {
 	},
 };
 
-static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
+static int cs35l35_component_set_sysclk(struct snd_soc_component *component,
 				int clk_id, int source, unsigned int freq,
 				int dir)
 {
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 	int clksrc;
 	int ret = 0;
 
@@ -731,7 +731,7 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
 		clksrc = CS35L35_CLK_SOURCE_PDM;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid CLK Source\n");
+		dev_err(component->dev, "Invalid CLK Source\n");
 		return -EINVAL;
 	}
 
@@ -749,7 +749,7 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
 		cs35l35->sysclk = freq;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid CLK Frequency Input : %d\n", freq);
+		dev_err(component->dev, "Invalid CLK Frequency Input : %d\n", freq);
 		return -EINVAL;
 	}
 
@@ -757,7 +757,7 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
 				CS35L35_CLK_SOURCE_MASK,
 				clksrc << CS35L35_CLK_SOURCE_SHIFT);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to set sysclk %d\n", ret);
+		dev_err(component->dev, "Failed to set sysclk %d\n", ret);
 		return ret;
 	}
 
@@ -834,9 +834,9 @@ static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35,
 	return 0;
 }
 
-static int cs35l35_codec_probe(struct snd_soc_codec *codec)
+static int cs35l35_component_probe(struct snd_soc_component *component)
 {
-	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
 	struct classh_cfg *classh = &cs35l35->pdata.classh_algo;
 	struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg;
 	int ret;
@@ -880,7 +880,7 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
 			regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL,
 					CS35L35_CH_STEREO_MASK,
 					1 << CS35L35_CH_STEREO_SHIFT);
-		ret = snd_soc_add_codec_controls(codec, cs35l35_adv_controls,
+		ret = snd_soc_add_component_controls(component, cs35l35_adv_controls,
 					ARRAY_SIZE(cs35l35_adv_controls));
 		if (ret)
 			return ret;
@@ -1079,20 +1079,19 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
-	.probe = cs35l35_codec_probe,
-	.set_sysclk = cs35l35_codec_set_sysclk,
-	.component_driver = {
-		.dapm_widgets = cs35l35_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets),
-
-		.dapm_routes = cs35l35_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map),
-
-		.controls = cs35l35_aud_controls,
-		.num_controls = ARRAY_SIZE(cs35l35_aud_controls),
-	},
-
+static const struct snd_soc_component_driver soc_component_dev_cs35l35 = {
+	.probe			= cs35l35_component_probe,
+	.set_sysclk		= cs35l35_component_set_sysclk,
+	.dapm_widgets		= cs35l35_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l35_dapm_widgets),
+	.dapm_routes		= cs35l35_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l35_audio_map),
+	.controls		= cs35l35_aud_controls,
+	.num_controls		= ARRAY_SIZE(cs35l35_aud_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct regmap_config cs35l35_regmap = {
@@ -1617,10 +1616,10 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
 	regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
 		CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT);
 
-	ret =  snd_soc_register_codec(dev, &soc_codec_dev_cs35l35, cs35l35_dai,
-				      ARRAY_SIZE(cs35l35_dai));
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_cs35l35,
+					cs35l35_dai, ARRAY_SIZE(cs35l35_dai));
 	if (ret < 0) {
-		dev_err(dev, "Failed to register codec: %d\n", ret);
+		dev_err(dev, "Failed to register component: %d\n", ret);
 		goto err;
 	}
 
@@ -1634,12 +1633,6 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
 	return ret;
 }
 
-static int cs35l35_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct of_device_id cs35l35_of_match[] = {
 	{.compatible = "cirrus,cs35l35"},
 	{},
@@ -1660,7 +1653,6 @@ static struct i2c_driver cs35l35_i2c_driver = {
 	},
 	.id_table = cs35l35_id,
 	.probe = cs35l35_i2c_probe,
-	.remove = cs35l35_i2c_remove,
 };
 
 module_i2c_driver(cs35l35_i2c_driver);
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index fd966bb851cb..275677de669f 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -322,12 +322,12 @@ static int cs4265_get_clk_index(int mclk, int rate)
 static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 			unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	if (clk_id != 0) {
-		dev_err(codec->dev, "Invalid clk_id %d\n", clk_id);
+		dev_err(component->dev, "Invalid clk_id %d\n", clk_id);
 		return -EINVAL;
 	}
 	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
@@ -337,24 +337,24 @@ static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 		}
 	}
 	cs4265->sysclk = 0;
-	dev_err(codec->dev, "Invalid freq parameter %d\n", freq);
+	dev_err(component->dev, "Invalid freq parameter %d\n", freq);
 	return -EINVAL;
 }
 
 static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
 	u8 iface = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
 				CS4265_ADC_MASTER,
 				CS4265_ADC_MASTER);
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
 				CS4265_ADC_MASTER,
 				0);
 		break;
@@ -383,20 +383,20 @@ static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
 static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute) {
-		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
 			CS4265_DAC_CTL_MUTE,
 			CS4265_DAC_CTL_MUTE);
-		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
 			CS4265_SPDIF_CTL2_MUTE,
 			CS4265_SPDIF_CTL2_MUTE);
 	} else {
-		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
 			CS4265_DAC_CTL_MUTE,
 			0);
-		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
 			CS4265_SPDIF_CTL2_MUTE,
 			0);
 	}
@@ -407,8 +407,8 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
 				     struct snd_pcm_hw_params *params,
 				     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
 	int index;
 
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
@@ -418,45 +418,45 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
 	if (index >= 0) {
-		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
 			CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
-		snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
+		snd_soc_component_update_bits(component, CS4265_MCLK_FREQ,
 			CS4265_MCLK_FREQ_MASK,
 			clk_map_table[index].mclkdiv << 4);
 
 	} else {
-		dev_err(codec->dev, "can't get correct mclk\n");
+		dev_err(component->dev, "can't get correct mclk\n");
 		return -EINVAL;
 	}
 
 	switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
 			CS4265_DAC_CTL_DIF, (1 << 4));
-		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
 			CS4265_ADC_DIF, (1 << 4));
-		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
 			CS4265_SPDIF_CTL2_DIF, (1 << 6));
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
 		if (params_width(params) == 16) {
-			snd_soc_update_bits(codec, CS4265_DAC_CTL,
+			snd_soc_component_update_bits(component, CS4265_DAC_CTL,
 				CS4265_DAC_CTL_DIF, (2 << 4));
-			snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+			snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
 				CS4265_SPDIF_CTL2_DIF, (2 << 6));
 		} else {
-			snd_soc_update_bits(codec, CS4265_DAC_CTL,
+			snd_soc_component_update_bits(component, CS4265_DAC_CTL,
 				CS4265_DAC_CTL_DIF, (3 << 4));
-			snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+			snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
 				CS4265_SPDIF_CTL2_DIF, (3 << 6));
 		}
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		snd_soc_update_bits(codec, CS4265_DAC_CTL,
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
 			CS4265_DAC_CTL_DIF, 0);
-		snd_soc_update_bits(codec, CS4265_ADC_CTL,
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
 			CS4265_ADC_DIF, 0);
-		snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
 			CS4265_SPDIF_CTL2_DIF, 0);
 
 		break;
@@ -466,23 +466,23 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int cs4265_set_bias_level(struct snd_soc_codec *codec,
+static int cs4265_set_bias_level(struct snd_soc_component *component,
 					enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, CS4265_PWRCTL,
+		snd_soc_component_update_bits(component, CS4265_PWRCTL,
 			CS4265_PWRCTL_PDN, 0);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, CS4265_PWRCTL,
+		snd_soc_component_update_bits(component, CS4265_PWRCTL,
 			CS4265_PWRCTL_PDN,
 			CS4265_PWRCTL_PDN);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, CS4265_PWRCTL,
+		snd_soc_component_update_bits(component, CS4265_PWRCTL,
 			CS4265_PWRCTL_PDN,
 			CS4265_PWRCTL_PDN);
 		break;
@@ -544,17 +544,18 @@ static struct snd_soc_dai_driver cs4265_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_cs4265 = {
-	.set_bias_level = cs4265_set_bias_level,
-
-	.component_driver = {
-		.controls		= cs4265_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs4265_snd_controls),
-		.dapm_widgets		= cs4265_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs4265_dapm_widgets),
-		.dapm_routes		= cs4265_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cs4265_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_cs4265 = {
+	.set_bias_level		= cs4265_set_bias_level,
+	.controls		= cs4265_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4265_snd_controls),
+	.dapm_widgets		= cs4265_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4265_dapm_widgets),
+	.dapm_routes		= cs4265_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs4265_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config cs4265_regmap = {
@@ -616,18 +617,12 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
 
 	regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_cs4265, cs4265_dai,
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_cs4265, cs4265_dai,
 			ARRAY_SIZE(cs4265_dai));
 	return ret;
 }
 
-static int cs4265_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct of_device_id cs4265_of_match[] = {
 	{ .compatible = "cirrus,cs4265", },
 	{ }
@@ -647,7 +642,6 @@ static struct i2c_driver cs4265_i2c_driver = {
 	},
 	.id_table = cs4265_id,
 	.probe =    cs4265_i2c_probe,
-	.remove =   cs4265_i2c_remove,
 };
 
 module_i2c_driver(cs4265_i2c_driver);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 84f86745c30e..2a7a4168c072 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -254,8 +254,8 @@ static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
 static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 
 	cs4270->mclk = freq;
 	return 0;
@@ -277,8 +277,8 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 
 	/* set DAI format */
 	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -287,7 +287,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "invalid dai format\n");
+		dev_err(component->dev, "invalid dai format\n");
 		return -EINVAL;
 	}
 
@@ -301,7 +301,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		break;
 	default:
 		/* all other modes are unsupported by the hardware */
-		dev_err(codec->dev, "Unknown master/slave configuration\n");
+		dev_err(component->dev, "Unknown master/slave configuration\n");
 		return -EINVAL;
 	}
 
@@ -326,8 +326,8 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 	int ret;
 	unsigned int i;
 	unsigned int rate;
@@ -346,13 +346,13 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 
 	if (i == NUM_MCLK_RATIOS) {
 		/* We did not find a matching ratio */
-		dev_err(codec->dev, "could not find matching ratio\n");
+		dev_err(component->dev, "could not find matching ratio\n");
 		return -EINVAL;
 	}
 
 	/* Set the sample rate */
 
-	reg = snd_soc_read(codec, CS4270_MODE);
+	reg = snd_soc_component_read32(component, CS4270_MODE);
 	reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);
 	reg |= cs4270_mode_ratios[i].mclk;
 
@@ -361,15 +361,15 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 	else
 		reg |= cs4270_mode_ratios[i].speed_mode;
 
-	ret = snd_soc_write(codec, CS4270_MODE, reg);
+	ret = snd_soc_component_write(component, CS4270_MODE, reg);
 	if (ret < 0) {
-		dev_err(codec->dev, "i2c write failed\n");
+		dev_err(component->dev, "i2c write failed\n");
 		return ret;
 	}
 
 	/* Set the DAI format */
 
-	reg = snd_soc_read(codec, CS4270_FORMAT);
+	reg = snd_soc_component_read32(component, CS4270_FORMAT);
 	reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);
 
 	switch (cs4270->mode) {
@@ -380,13 +380,13 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
 		reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;
 		break;
 	default:
-		dev_err(codec->dev, "unknown dai format\n");
+		dev_err(component->dev, "unknown dai format\n");
 		return -EINVAL;
 	}
 
-	ret = snd_soc_write(codec, CS4270_FORMAT, reg);
+	ret = snd_soc_component_write(component, CS4270_FORMAT, reg);
 	if (ret < 0) {
-		dev_err(codec->dev, "i2c write failed\n");
+		dev_err(component->dev, "i2c write failed\n");
 		return ret;
 	}
 
@@ -405,11 +405,11 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
  */
 static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 	int reg6;
 
-	reg6 = snd_soc_read(codec, CS4270_MUTE);
+	reg6 = snd_soc_component_read32(component, CS4270_MUTE);
 
 	if (mute)
 		reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
@@ -418,7 +418,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
 		reg6 |= cs4270->manual_mute;
 	}
 
-	return snd_soc_write(codec, CS4270_MUTE, reg6);
+	return snd_soc_component_write(component, CS4270_MUTE, reg6);
 }
 
 /**
@@ -438,8 +438,8 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
 static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 	int left = !ucontrol->value.integer.value[0];
 	int right = !ucontrol->value.integer.value[1];
 
@@ -501,9 +501,9 @@ static struct snd_soc_dai_driver cs4270_dai = {
  * This function is called when ASoC has all the pieces it needs to
  * instantiate a sound driver.
  */
-static int cs4270_probe(struct snd_soc_codec *codec)
+static int cs4270_probe(struct snd_soc_component *component)
 {
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	/* Disable auto-mute.  This feature appears to be buggy.  In some
@@ -511,9 +511,9 @@ static int cs4270_probe(struct snd_soc_codec *codec)
 	 * this feature disabled by default.  An application (e.g. alsactl) can
 	 * re-enabled it by using the controls.
 	 */
-	ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
+	ret = snd_soc_component_update_bits(component, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "i2c write failed\n");
+		dev_err(component->dev, "i2c write failed\n");
 		return ret;
 	}
 
@@ -522,10 +522,10 @@ static int cs4270_probe(struct snd_soc_codec *codec)
 	 * playback has started.  An application (e.g. alsactl) can
 	 * re-enabled it by using the controls.
 	 */
-	ret = snd_soc_update_bits(codec, CS4270_TRANS,
+	ret = snd_soc_component_update_bits(component, CS4270_TRANS,
 		CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "i2c write failed\n");
+		dev_err(component->dev, "i2c write failed\n");
 		return ret;
 	}
 
@@ -541,13 +541,11 @@ static int cs4270_probe(struct snd_soc_codec *codec)
  *
  * This function is the counterpart to cs4270_probe().
  */
-static int cs4270_remove(struct snd_soc_codec *codec)
+static void cs4270_remove(struct snd_soc_component *component)
 {
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 
 	regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-
-	return 0;
 };
 
 #ifdef CONFIG_PM
@@ -561,16 +559,16 @@ static int cs4270_remove(struct snd_soc_codec *codec)
  * and all registers are written back to the hardware when resuming.
  */
 
-static int cs4270_soc_suspend(struct snd_soc_codec *codec)
+static int cs4270_soc_suspend(struct snd_soc_component *component)
 {
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 	int reg, ret;
 
-	reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
+	reg = snd_soc_component_read32(component, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
 	if (reg < 0)
 		return reg;
 
-	ret = snd_soc_write(codec, CS4270_PWRCTL, reg);
+	ret = snd_soc_component_write(component, CS4270_PWRCTL, reg);
 	if (ret < 0)
 		return ret;
 
@@ -580,9 +578,9 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int cs4270_soc_resume(struct snd_soc_codec *codec)
+static int cs4270_soc_resume(struct snd_soc_component *component)
 {
-	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
 	int reg, ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
@@ -598,10 +596,10 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
 	regcache_sync(cs4270->regmap);
 
 	/* ... then disable the power-down bits */
-	reg = snd_soc_read(codec, CS4270_PWRCTL);
+	reg = snd_soc_component_read32(component, CS4270_PWRCTL);
 	reg &= ~CS4270_PWRCTL_PDN_ALL;
 
-	return snd_soc_write(codec, CS4270_PWRCTL, reg);
+	return snd_soc_component_write(component, CS4270_PWRCTL, reg);
 }
 #else
 #define cs4270_soc_suspend	NULL
@@ -611,20 +609,21 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
 /*
  * ASoC codec driver structure
  */
-static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
-	.probe =		cs4270_probe,
-	.remove =		cs4270_remove,
-	.suspend =		cs4270_soc_suspend,
-	.resume =		cs4270_soc_resume,
-
-	.component_driver = {
-		.controls =		cs4270_snd_controls,
-		.num_controls =		ARRAY_SIZE(cs4270_snd_controls),
-		.dapm_widgets =		cs4270_dapm_widgets,
-		.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets),
-		.dapm_routes =		cs4270_dapm_routes,
-		.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_device_cs4270 = {
+	.probe			= cs4270_probe,
+	.remove			= cs4270_remove,
+	.suspend		= cs4270_soc_suspend,
+	.resume			= cs4270_soc_resume,
+	.controls		= cs4270_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4270_snd_controls),
+	.dapm_widgets		= cs4270_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4270_dapm_widgets),
+	.dapm_routes		= cs4270_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4270_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /*
@@ -718,23 +717,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
 
 	i2c_set_clientdata(i2c_client, cs4270);
 
-	ret = snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_device_cs4270, &cs4270_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_device_cs4270, &cs4270_dai, 1);
 	return ret;
 }
 
-/**
- * cs4270_i2c_remove - remove an I2C device
- * @i2c_client: the I2C client object
- *
- * This function is the counterpart to cs4270_i2c_probe().
- */
-static int cs4270_i2c_remove(struct i2c_client *i2c_client)
-{
-	snd_soc_unregister_codec(&i2c_client->dev);
-	return 0;
-}
-
 /*
  * cs4270_id - I2C device IDs supported by this driver
  */
@@ -757,7 +744,6 @@ static struct i2c_driver cs4270_i2c_driver = {
 	},
 	.id_table = cs4270_id,
 	.probe = cs4270_i2c_probe,
-	.remove = cs4270_i2c_remove,
 };
 
 module_i2c_driver(cs4270_i2c_driver);
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c
index dcb3223d7d8f..ff737304d50b 100644
--- a/sound/soc/codecs/cs4271-i2c.c
+++ b/sound/soc/codecs/cs4271-i2c.c
@@ -33,12 +33,6 @@ static int cs4271_i2c_probe(struct i2c_client *client,
 			    devm_regmap_init_i2c(client, &config));
 }
 
-static int cs4271_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id cs4271_i2c_id[] = {
 	{ "cs4271", 0 },
 	{ }
@@ -51,7 +45,6 @@ static struct i2c_driver cs4271_i2c_driver = {
 		.of_match_table = of_match_ptr(cs4271_dt_ids),
 	},
 	.probe = cs4271_i2c_probe,
-	.remove = cs4271_i2c_remove,
 	.id_table = cs4271_i2c_id,
 };
 module_i2c_driver(cs4271_i2c_driver);
diff --git a/sound/soc/codecs/cs4271-spi.c b/sound/soc/codecs/cs4271-spi.c
index 1ff5f520196a..217f6dc869e5 100644
--- a/sound/soc/codecs/cs4271-spi.c
+++ b/sound/soc/codecs/cs4271-spi.c
@@ -33,19 +33,12 @@ static int cs4271_spi_probe(struct spi_device *spi)
 	return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
 }
 
-static int cs4271_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver cs4271_spi_driver = {
 	.driver = {
 		.name	= "cs4271",
 		.of_match_table = of_match_ptr(cs4271_dt_ids),
 	},
 	.probe		= cs4271_spi_probe,
-	.remove		= cs4271_spi_remove,
 };
 module_spi_driver(cs4271_spi_driver);
 
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 49a80627af12..849fdb2cb260 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -206,8 +206,8 @@ static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {
 static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	cs4271->mclk = freq;
 	return 0;
@@ -216,8 +216,8 @@ static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 	int ret;
 
@@ -230,7 +230,7 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		val |= CS4271_MODE1_MASTER;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -250,7 +250,7 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			return ret;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -263,9 +263,9 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 static int cs4271_deemph[] = {0, 44100, 48000, 32000};
 
-static int cs4271_set_deemph(struct snd_soc_codec *codec)
+static int cs4271_set_deemph(struct snd_soc_component *component)
 {
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 	int i, ret;
 	int val = CS4271_DACCTL_DEM_DIS;
 
@@ -289,8 +289,8 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec)
 static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = cs4271->deemph;
 	return 0;
@@ -299,11 +299,11 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
 static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	cs4271->deemph = ucontrol->value.integer.value[0];
-	return cs4271_set_deemph(codec);
+	return cs4271_set_deemph(component);
 }
 
 struct cs4271_clk_cfg {
@@ -349,8 +349,8 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 	int i, ret;
 	unsigned int ratio, val;
 
@@ -399,7 +399,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 			break;
 
 	if (i == CS4171_NR_RATIOS) {
-		dev_err(codec->dev, "Invalid sample rate\n");
+		dev_err(component->dev, "Invalid sample rate\n");
 		return -EINVAL;
 	}
 
@@ -410,13 +410,13 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		return ret;
 
-	return cs4271_set_deemph(codec);
+	return cs4271_set_deemph(component);
 }
 
 static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 	int ret;
 	int val_a = 0;
 	int val_b = 0;
@@ -493,9 +493,9 @@ static struct snd_soc_dai_driver cs4271_dai = {
 	.symmetric_rates = 1,
 };
 
-static int cs4271_reset(struct snd_soc_codec *codec)
+static int cs4271_reset(struct snd_soc_component *component)
 {
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(cs4271->gpio_nreset)) {
 		gpio_direction_output(cs4271->gpio_nreset, 0);
@@ -508,10 +508,10 @@ static int cs4271_reset(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int cs4271_soc_suspend(struct snd_soc_codec *codec)
+static int cs4271_soc_suspend(struct snd_soc_component *component)
 {
 	int ret;
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	/* Set power-down bit */
 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
@@ -525,20 +525,20 @@ static int cs4271_soc_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int cs4271_soc_resume(struct snd_soc_codec *codec)
+static int cs4271_soc_resume(struct snd_soc_component *component)
 {
 	int ret;
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
 				    cs4271->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
 		return ret;
 	}
 
 	/* Do a proper reset after power up */
-	cs4271_reset(codec);
+	cs4271_reset(component);
 
 	/* Restore codec state */
 	ret = regcache_sync(cs4271->regmap);
@@ -567,20 +567,20 @@ MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
 EXPORT_SYMBOL_GPL(cs4271_dt_ids);
 #endif
 
-static int cs4271_codec_probe(struct snd_soc_codec *codec)
+static int cs4271_component_probe(struct snd_soc_component *component)
 {
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
-	struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+	struct cs4271_platform_data *cs4271plat = component->dev->platform_data;
 	int ret;
 	bool amutec_eq_bmutec = false;
 
 #ifdef CONFIG_OF
-	if (of_match_device(cs4271_dt_ids, codec->dev)) {
-		if (of_get_property(codec->dev->of_node,
+	if (of_match_device(cs4271_dt_ids, component->dev)) {
+		if (of_get_property(component->dev->of_node,
 				     "cirrus,amutec-eq-bmutec", NULL))
 			amutec_eq_bmutec = true;
 
-		if (of_get_property(codec->dev->of_node,
+		if (of_get_property(component->dev->of_node,
 				     "cirrus,enable-soft-reset", NULL))
 			cs4271->enable_soft_reset = true;
 	}
@@ -589,7 +589,7 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
 	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
 				    cs4271->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
 		return ret;
 	}
 
@@ -599,7 +599,7 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
 	}
 
 	/* Reset codec */
-	cs4271_reset(codec);
+	cs4271_reset(component);
 
 	ret = regcache_sync(cs4271->regmap);
 	if (ret < 0)
@@ -625,9 +625,9 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int cs4271_codec_remove(struct snd_soc_codec *codec)
+static void cs4271_component_remove(struct snd_soc_component *component)
 {
-	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(cs4271->gpio_nreset))
 		/* Set codec to the reset state */
@@ -635,24 +635,23 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec)
 
 	regcache_mark_dirty(cs4271->regmap);
 	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
-
-	return 0;
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
-	.probe			= cs4271_codec_probe,
-	.remove			= cs4271_codec_remove,
+static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
+	.probe			= cs4271_component_probe,
+	.remove			= cs4271_component_remove,
 	.suspend		= cs4271_soc_suspend,
 	.resume			= cs4271_soc_resume,
-
-	.component_driver = {
-		.controls		= cs4271_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
-		.dapm_widgets		= cs4271_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
-		.dapm_routes		= cs4271_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
-	},
+	.controls		= cs4271_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
+	.dapm_widgets		= cs4271_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
+	.dapm_routes		= cs4271_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int cs4271_common_probe(struct device *dev,
@@ -721,8 +720,8 @@ int cs4271_probe(struct device *dev, struct regmap *regmap)
 	dev_set_drvdata(dev, cs4271);
 	cs4271->regmap = regmap;
 
-	return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai,
-				      1);
+	return devm_snd_soc_register_component(dev, &soc_component_dev_cs4271,
+					       &cs4271_dai, 1);
 }
 EXPORT_SYMBOL_GPL(cs4271_probe);
 
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index a2324a0e72ee..651329bf9743 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -468,33 +468,33 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
 static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
 				struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Enable the channels */
-		snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN,
+		snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
 				CS42L42_ASP_RX0_CH_EN_MASK,
 				(CS42L42_ASP_RX0_CH1_EN |
 				CS42L42_ASP_RX0_CH2_EN) <<
 				CS42L42_ASP_RX0_CH_EN_SHIFT);
 
 		/* Power up */
-		snd_soc_update_bits(codec, CS42L42_PWR_CTL1,
+		snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
 			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
 				CS42L42_HP_PDN_MASK, 0);
 	} else if (event & SND_SOC_DAPM_PRE_PMD) {
 		/* Disable the channels */
-		snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN,
+		snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
 				CS42L42_ASP_RX0_CH_EN_MASK, 0);
 
 		/* Power down */
-		snd_soc_update_bits(codec, CS42L42_PWR_CTL1,
+		snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
 			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
 				CS42L42_HP_PDN_MASK,
 			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
 				CS42L42_HP_PDN_MASK);
 	} else {
-		dev_err(codec->dev, "Invalid event 0x%x\n", event);
+		dev_err(component->dev, "Invalid event 0x%x\n", event);
 	}
 	return 0;
 }
@@ -515,10 +515,10 @@ static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
 	{"HP", NULL, "HPDRV"}
 };
 
-static int cs42l42_set_bias_level(struct snd_soc_codec *codec,
+static int cs42l42_set_bias_level(struct snd_soc_component *component,
 					enum snd_soc_bias_level level)
 {
-	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -527,14 +527,14 @@ static int cs42l42_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l42->regmap, false);
 			regcache_sync(cs42l42->regmap);
 			ret = regulator_bulk_enable(
 						ARRAY_SIZE(cs42l42->supplies),
 						cs42l42->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable regulators: %d\n",
 					ret);
 				return ret;
@@ -552,30 +552,28 @@ static int cs42l42_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int cs42l42_codec_probe(struct snd_soc_codec *codec)
+static int cs42l42_component_probe(struct snd_soc_component *component)
 {
 	struct cs42l42_private *cs42l42 =
-		(struct cs42l42_private *)snd_soc_codec_get_drvdata(codec);
+		(struct cs42l42_private *)snd_soc_component_get_drvdata(component);
 
-	cs42l42->codec = codec;
+	cs42l42->component = component;
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs42l42 = {
-	.probe = cs42l42_codec_probe,
-	.set_bias_level = cs42l42_set_bias_level,
-	.ignore_pmdown_time = true,
-
-	.component_driver = {
-		.dapm_widgets = cs42l42_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets),
-		.dapm_routes = cs42l42_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map),
-
-		.controls = cs42l42_snd_controls,
-		.num_controls = ARRAY_SIZE(cs42l42_snd_controls),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
+	.probe			= cs42l42_component_probe,
+	.set_bias_level		= cs42l42_set_bias_level,
+	.dapm_widgets		= cs42l42_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l42_dapm_widgets),
+	.dapm_routes		= cs42l42_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l42_audio_map),
+	.controls		= cs42l42_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l42_snd_controls),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 struct cs42l42_pll_params {
@@ -613,16 +611,16 @@ static const struct cs42l42_pll_params pll_ratio_table[] = {
 	{ 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 }
 };
 
-static int cs42l42_pll_config(struct snd_soc_codec *codec)
+static int cs42l42_pll_config(struct snd_soc_component *component)
 {
-	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
 	int i;
 	u32 fsync;
 
 	for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
 		if (pll_ratio_table[i].sclk == cs42l42->sclk) {
 			/* Configure the internal sample rate */
-			snd_soc_update_bits(codec, CS42L42_MCLK_CTL,
+			snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
 					CS42L42_INTERNAL_FS_MASK,
 					((pll_ratio_table[i].mclk_int !=
 					12000000) &&
@@ -632,7 +630,7 @@ static int cs42l42_pll_config(struct snd_soc_codec *codec)
 			/* Set the MCLK src (PLL or SCLK) and the divide
 			 * ratio
 			 */
-			snd_soc_update_bits(codec, CS42L42_MCLK_SRC_SEL,
+			snd_soc_component_update_bits(component, CS42L42_MCLK_SRC_SEL,
 					CS42L42_MCLK_SRC_SEL_MASK |
 					CS42L42_MCLKDIV_MASK,
 					(pll_ratio_table[i].mclk_src_sel
@@ -643,62 +641,62 @@ static int cs42l42_pll_config(struct snd_soc_codec *codec)
 			fsync = cs42l42->sclk / cs42l42->srate;
 			if (((fsync * cs42l42->srate) != cs42l42->sclk)
 				|| ((fsync % 2) != 0)) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Unsupported sclk %d/sample rate %d\n",
 					cs42l42->sclk,
 					cs42l42->srate);
 				return -EINVAL;
 			}
 			/* Set the LRCLK period */
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_FSYNC_P_LOWER,
 					CS42L42_FSYNC_PERIOD_MASK,
 					CS42L42_FRAC0_VAL(fsync - 1) <<
 					CS42L42_FSYNC_PERIOD_SHIFT);
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_FSYNC_P_UPPER,
 					CS42L42_FSYNC_PERIOD_MASK,
 					CS42L42_FRAC1_VAL(fsync - 1) <<
 					CS42L42_FSYNC_PERIOD_SHIFT);
 			/* Set the LRCLK to 50% duty cycle */
 			fsync = fsync / 2;
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_FSYNC_PW_LOWER,
 					CS42L42_FSYNC_PULSE_WIDTH_MASK,
 					CS42L42_FRAC0_VAL(fsync - 1) <<
 					CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_FSYNC_PW_UPPER,
 					CS42L42_FSYNC_PULSE_WIDTH_MASK,
 					CS42L42_FRAC1_VAL(fsync - 1) <<
 					CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_ASP_FRM_CFG,
 					CS42L42_ASP_5050_MASK,
 					CS42L42_ASP_5050_MASK);
 			/* Set the frame delay to 1.0 SCLK clocks */
-			snd_soc_update_bits(codec, CS42L42_ASP_FRM_CFG,
+			snd_soc_component_update_bits(component, CS42L42_ASP_FRM_CFG,
 					CS42L42_ASP_FSD_MASK,
 					CS42L42_ASP_FSD_1_0 <<
 					CS42L42_ASP_FSD_SHIFT);
 			/* Set the sample rates (96k or lower) */
-			snd_soc_update_bits(codec, CS42L42_FS_RATE_EN,
+			snd_soc_component_update_bits(component, CS42L42_FS_RATE_EN,
 					CS42L42_FS_EN_MASK,
 					(CS42L42_FS_EN_IASRC_96K |
 					CS42L42_FS_EN_OASRC_96K) <<
 					CS42L42_FS_EN_SHIFT);
 			/* Set the input/output internal MCLK clock ~12 MHz */
-			snd_soc_update_bits(codec, CS42L42_IN_ASRC_CLK,
+			snd_soc_component_update_bits(component, CS42L42_IN_ASRC_CLK,
 					CS42L42_CLK_IASRC_SEL_MASK,
 					CS42L42_CLK_IASRC_SEL_12 <<
 					CS42L42_CLK_IASRC_SEL_SHIFT);
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_OUT_ASRC_CLK,
 					CS42L42_CLK_OASRC_SEL_MASK,
 					CS42L42_CLK_OASRC_SEL_12 <<
 					CS42L42_CLK_OASRC_SEL_SHIFT);
 			/* channel 1 on low LRCLK, 32 bit */
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_ASP_RX_DAI0_CH1_AP_RES,
 					CS42L42_ASP_RX_CH_AP_MASK |
 					CS42L42_ASP_RX_CH_RES_MASK,
@@ -707,7 +705,7 @@ static int cs42l42_pll_config(struct snd_soc_codec *codec)
 					(CS42L42_ASP_RX_CH_RES_32 <<
 					CS42L42_ASP_RX_CH_RES_SHIFT));
 			/* Channel 2 on high LRCLK, 32 bit */
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					CS42L42_ASP_RX_DAI0_CH2_AP_RES,
 					CS42L42_ASP_RX_CH_AP_MASK |
 					CS42L42_ASP_RX_CH_RES_MASK,
@@ -717,50 +715,50 @@ static int cs42l42_pll_config(struct snd_soc_codec *codec)
 					CS42L42_ASP_RX_CH_RES_SHIFT));
 			if (pll_ratio_table[i].mclk_src_sel == 0) {
 				/* Pass the clock straight through */
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_CTL1,
 					CS42L42_PLL_START_MASK,	0);
 			} else {
 				/* Configure PLL per table 4-5 */
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_DIV_CFG1,
 					CS42L42_SCLK_PREDIV_MASK,
 					pll_ratio_table[i].sclk_prediv
 					<< CS42L42_SCLK_PREDIV_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_DIV_INT,
 					CS42L42_PLL_DIV_INT_MASK,
 					pll_ratio_table[i].pll_div_int
 					<< CS42L42_PLL_DIV_INT_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_DIV_FRAC0,
 					CS42L42_PLL_DIV_FRAC_MASK,
 					CS42L42_FRAC0_VAL(
 					pll_ratio_table[i].pll_div_frac)
 					<< CS42L42_PLL_DIV_FRAC_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_DIV_FRAC1,
 					CS42L42_PLL_DIV_FRAC_MASK,
 					CS42L42_FRAC1_VAL(
 					pll_ratio_table[i].pll_div_frac)
 					<< CS42L42_PLL_DIV_FRAC_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_DIV_FRAC2,
 					CS42L42_PLL_DIV_FRAC_MASK,
 					CS42L42_FRAC2_VAL(
 					pll_ratio_table[i].pll_div_frac)
 					<< CS42L42_PLL_DIV_FRAC_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_CTL4,
 					CS42L42_PLL_MODE_MASK,
 					pll_ratio_table[i].pll_mode
 					<< CS42L42_PLL_MODE_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_CTL3,
 					CS42L42_PLL_DIVOUT_MASK,
 					pll_ratio_table[i].pll_divout
 					<< CS42L42_PLL_DIVOUT_SHIFT);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					CS42L42_PLL_CAL_RATIO,
 					CS42L42_PLL_CAL_RATIO_MASK,
 					pll_ratio_table[i].pll_cal_ratio
@@ -775,7 +773,7 @@ static int cs42l42_pll_config(struct snd_soc_codec *codec)
 
 static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u32 asp_cfg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -820,7 +818,7 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		break;
 	}
 
-	snd_soc_update_bits(codec, CS42L42_ASP_CLK_CFG,
+	snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG,
 				CS42L42_ASP_MODE_MASK |
 				CS42L42_ASP_SCPOL_IN_DAC_MASK |
 				CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
@@ -832,14 +830,14 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
 	int retval;
 
 	cs42l42->srate = params_rate(params);
 	cs42l42->swidth = params_width(params);
 
-	retval = cs42l42_pll_config(codec);
+	retval = cs42l42_pll_config(component);
 
 	return retval;
 }
@@ -847,8 +845,8 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
 static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
 
 	cs42l42->sclk = freq;
 
@@ -857,7 +855,7 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
 
 static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int regval;
 	u8 fullScaleVol;
 
@@ -865,25 +863,25 @@ static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
 		/* Mark SCLK as not present to turn on the internal
 		 * oscillator.
 		 */
-		snd_soc_update_bits(codec, CS42L42_OSC_SWITCH,
+		snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
 						CS42L42_SCLK_PRESENT_MASK, 0);
 
-		snd_soc_update_bits(codec, CS42L42_PLL_CTL1,
+		snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
 				CS42L42_PLL_START_MASK,
 				0 << CS42L42_PLL_START_SHIFT);
 
 		/* Mute the headphone */
-		snd_soc_update_bits(codec, CS42L42_HP_CTL,
+		snd_soc_component_update_bits(component, CS42L42_HP_CTL,
 				CS42L42_HP_ANA_AMUTE_MASK |
 				CS42L42_HP_ANA_BMUTE_MASK,
 				CS42L42_HP_ANA_AMUTE_MASK |
 				CS42L42_HP_ANA_BMUTE_MASK);
 	} else {
-		snd_soc_update_bits(codec, CS42L42_PLL_CTL1,
+		snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
 				CS42L42_PLL_START_MASK,
 				1 << CS42L42_PLL_START_SHIFT);
 		/* Read the headphone load */
-		regval = snd_soc_read(codec, CS42L42_LOAD_DET_RCSTAT);
+		regval = snd_soc_component_read32(component, CS42L42_LOAD_DET_RCSTAT);
 		if (((regval & CS42L42_RLA_STAT_MASK) >>
 			CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
 			fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
@@ -892,13 +890,13 @@ static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
 		}
 
 		/* Un-mute the headphone, set the full scale volume flag */
-		snd_soc_update_bits(codec, CS42L42_HP_CTL,
+		snd_soc_component_update_bits(component, CS42L42_HP_CTL,
 				CS42L42_HP_ANA_AMUTE_MASK |
 				CS42L42_HP_ANA_BMUTE_MASK |
 				CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
 
 		/* Mark SCLK as present, turn off internal oscillator */
-		snd_soc_update_bits(codec, CS42L42_OSC_SWITCH,
+		snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
 				CS42L42_SCLK_PRESENT_MASK,
 				CS42L42_SCLK_PRESENT_MASK);
 	}
@@ -1262,16 +1260,16 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
 
 	switch (bias_level) {
 	case 1: /* Function C button press */
-		dev_dbg(cs42l42->codec->dev, "Function C button press\n");
+		dev_dbg(cs42l42->component->dev, "Function C button press\n");
 		break;
 	case 2: /* Function B button press */
-		dev_dbg(cs42l42->codec->dev, "Function B button press\n");
+		dev_dbg(cs42l42->component->dev, "Function B button press\n");
 		break;
 	case 3: /* Function D button press */
-		dev_dbg(cs42l42->codec->dev, "Function D button press\n");
+		dev_dbg(cs42l42->component->dev, "Function D button press\n");
 		break;
 	case 4: /* Function A button press */
-		dev_dbg(cs42l42->codec->dev, "Function A button press\n");
+		dev_dbg(cs42l42->component->dev, "Function A button press\n");
 		break;
 	}
 
@@ -1340,7 +1338,7 @@ static const struct cs42l42_irq_params irq_params_table[] = {
 static irqreturn_t cs42l42_irq_thread(int irq, void *data)
 {
 	struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data;
-	struct snd_soc_codec *codec = cs42l42->codec;
+	struct snd_soc_component *component = cs42l42->component;
 	unsigned int stickies[12];
 	unsigned int masks[12];
 	unsigned int current_plug_status;
@@ -1372,7 +1370,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
 	if ((~masks[5]) & irq_params_table[5].mask) {
 		if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) {
 			cs42l42_process_hs_type_detect(cs42l42);
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Auto detect done (%d)\n",
 				cs42l42->hs_type);
 		}
@@ -1392,7 +1390,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
 			if (cs42l42->plug_state != CS42L42_TS_UNPLUG) {
 				cs42l42->plug_state = CS42L42_TS_UNPLUG;
 				cs42l42_cancel_hs_type_detect(cs42l42);
-				dev_dbg(codec->dev,
+				dev_dbg(component->dev,
 					"Unplug event\n");
 			}
 			break;
@@ -1410,7 +1408,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
 
 			if (current_button_status &
 				CS42L42_M_DETECT_TF_MASK) {
-				dev_dbg(codec->dev,
+				dev_dbg(component->dev,
 					"Button released\n");
 			} else if (current_button_status &
 				CS42L42_M_DETECT_FT_MASK) {
@@ -1879,8 +1877,8 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
 	cs42l42_set_interrupt_masks(cs42l42);
 
 	/* Register codec for machine driver */
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs42l42, &cs42l42_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l42, &cs42l42_dai, 1);
 	if (ret < 0)
 		goto err_disable;
 	return 0;
@@ -1895,8 +1893,6 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
 {
 	struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
 
-	snd_soc_unregister_codec(&i2c_client->dev);
-
 	/* Hold down reset */
 	gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
 
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index d87a0a5322d5..09b0a93203ef 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -754,7 +754,7 @@ static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
 
 struct  cs42l42_private {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES];
 	struct gpio_desc *reset_gpio;
 	struct completion pdn_done;
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index 9bad478474fa..4b5731a41876 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -35,20 +35,12 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c,
 	return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
 }
 
-static int cs42l51_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static struct i2c_driver cs42l51_i2c_driver = {
 	.driver = {
 		.name = "cs42l51",
 		.of_match_table = cs42l51_of_match,
 	},
 	.probe = cs42l51_i2c_probe,
-	.remove = cs42l51_i2c_remove,
 	.id_table = cs42l51_i2c_id,
 };
 
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index f8072f1897d4..5080d7a3c279 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -54,8 +54,8 @@ struct cs42l51_private {
 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned long value = snd_soc_component_read32(component, CS42L51_PCM_MIXER)&3;
 
 	switch (value) {
 	default:
@@ -82,7 +82,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
 static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned char val;
 
 	switch (ucontrol->value.enumerated.item[0]) {
@@ -98,7 +98,7 @@ static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
 		break;
 	}
 
-	snd_soc_write(codec, CS42L51_PCM_MIXER, val);
+	snd_soc_component_write(component, CS42L51_PCM_MIXER, val);
 
 	return 1;
 }
@@ -153,17 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
+		snd_soc_component_update_bits(component, CS42L51_POWER_CTL1,
 				    CS42L51_POWER_CTL1_PDN,
 				    CS42L51_POWER_CTL1_PDN);
 		break;
 	default:
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
+		snd_soc_component_update_bits(component, CS42L51_POWER_CTL1,
 				    CS42L51_POWER_CTL1_PDN, 0);
 		break;
 	}
@@ -263,8 +263,8 @@ static const struct snd_soc_dapm_route cs42l51_routes[] = {
 static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
 
 	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
@@ -273,7 +273,7 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "invalid DAI format\n");
+		dev_err(component->dev, "invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -285,7 +285,7 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		cs42l51->func = MODE_SLAVE_AUTO;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown master/slave configuration\n");
+		dev_err(component->dev, "Unknown master/slave configuration\n");
 		return -EINVAL;
 	}
 
@@ -326,8 +326,8 @@ static struct cs42l51_ratios slave_auto_ratios[] = {
 static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
 
 	cs42l51->mclk = freq;
 	return 0;
@@ -337,8 +337,8 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
 	int ret;
 	unsigned int i;
 	unsigned int rate;
@@ -370,12 +370,12 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
 
 	if (i == nr_ratios) {
 		/* We did not find a matching ratio */
-		dev_err(codec->dev, "could not find matching ratio\n");
+		dev_err(component->dev, "could not find matching ratio\n");
 		return -EINVAL;
 	}
 
-	intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
-	power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
+	intf_ctl = snd_soc_component_read32(component, CS42L51_INTF_CTL);
+	power_ctl = snd_soc_component_read32(component, CS42L51_MIC_POWER_CTL);
 
 	intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
 			| CS42L51_INTF_CTL_DAC_FORMAT(7));
@@ -418,24 +418,24 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
 			fmt = CS42L51_DAC_DIF_RJ24;
 			break;
 		default:
-			dev_err(codec->dev, "unknown format\n");
+			dev_err(component->dev, "unknown format\n");
 			return -EINVAL;
 		}
 		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
 		break;
 	default:
-		dev_err(codec->dev, "unknown format\n");
+		dev_err(component->dev, "unknown format\n");
 		return -EINVAL;
 	}
 
 	if (ratios[i].mclk)
 		power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
 
-	ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
+	ret = snd_soc_component_write(component, CS42L51_INTF_CTL, intf_ctl);
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
+	ret = snd_soc_component_write(component, CS42L51_MIC_POWER_CTL, power_ctl);
 	if (ret < 0)
 		return ret;
 
@@ -444,18 +444,18 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
 
 static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int reg;
 	int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
 
-	reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
+	reg = snd_soc_component_read32(component, CS42L51_DAC_OUT_CTL);
 
 	if (mute)
 		reg |= mask;
 	else
 		reg &= ~mask;
 
-	return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
+	return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg);
 }
 
 static const struct snd_soc_dai_ops cs42l51_dai_ops = {
@@ -484,7 +484,7 @@ static struct snd_soc_dai_driver cs42l51_dai = {
 	.ops = &cs42l51_dai_ops,
 };
 
-static int cs42l51_codec_probe(struct snd_soc_codec *codec)
+static int cs42l51_component_probe(struct snd_soc_component *component)
 {
 	int ret, reg;
 
@@ -497,24 +497,25 @@ static int cs42l51_codec_probe(struct snd_soc_codec *codec)
 	 */
 	reg = CS42L51_DAC_CTL_DATA_SEL(1)
 		| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
-	ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+	ret = snd_soc_component_write(component, CS42L51_DAC_CTL, reg);
 	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
-	.probe = cs42l51_codec_probe,
-
-	.component_driver = {
-		.controls		= cs42l51_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs42l51_snd_controls),
-		.dapm_widgets		= cs42l51_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs42l51_dapm_widgets),
-		.dapm_routes		= cs42l51_routes,
-		.num_dapm_routes	= ARRAY_SIZE(cs42l51_routes),
-	},
+static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
+	.probe			= cs42l51_component_probe,
+	.controls		= cs42l51_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l51_snd_controls),
+	.dapm_widgets		= cs42l51_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l51_dapm_widgets),
+	.dapm_routes		= cs42l51_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l51_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 const struct regmap_config cs42l51_regmap = {
@@ -555,8 +556,8 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
 	dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
 		 val & CS42L51_CHIP_REV_MASK);
 
-	ret =  snd_soc_register_codec(dev,
-			&soc_codec_device_cs42l51, &cs42l51_dai, 1);
+	ret = devm_snd_soc_register_component(dev,
+			&soc_component_device_cs42l51, &cs42l51_dai, 1);
 error:
 	return ret;
 }
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 9731e5dff291..3d83c1be1292 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -42,7 +42,7 @@ struct sp_config {
 
 struct  cs42l52_private {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct device *dev;
 	struct sp_config config;
 	struct cs42l52_platform_data pdata;
@@ -473,17 +473,17 @@ static const struct snd_kcontrol_new cs42l52_micb_controls[] = {
 	SOC_ENUM("MICB Select", micb_enum),
 };
 
-static int cs42l52_add_mic_controls(struct snd_soc_codec *codec)
+static int cs42l52_add_mic_controls(struct snd_soc_component *component)
 {
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 	struct cs42l52_platform_data *pdata = &cs42l52->pdata;
 
 	if (!pdata->mica_diff_cfg)
-		snd_soc_add_codec_controls(codec, cs42l52_mica_controls,
+		snd_soc_add_component_controls(component, cs42l52_mica_controls,
 				     ARRAY_SIZE(cs42l52_mica_controls));
 
 	if (!pdata->micb_diff_cfg)
-		snd_soc_add_codec_controls(codec, cs42l52_micb_controls,
+		snd_soc_add_component_controls(component, cs42l52_micb_controls,
 				     ARRAY_SIZE(cs42l52_micb_controls));
 
 	return 0;
@@ -716,13 +716,13 @@ static int cs42l52_get_clk(int mclk, int rate)
 static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
 			int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 
 	if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
 		cs42l52->sysclk = freq;
 	} else {
-		dev_err(codec->dev, "Invalid freq parameter\n");
+		dev_err(component->dev, "Invalid freq parameter\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -730,8 +730,8 @@ static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
 
 static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 	u8 iface = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -783,21 +783,21 @@ static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 	cs42l52->config.format = iface;
-	snd_soc_write(codec, CS42L52_IFACE_CTL1, cs42l52->config.format);
+	snd_soc_component_write(component, CS42L52_IFACE_CTL1, cs42l52->config.format);
 
 	return 0;
 }
 
 static int cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute)
-		snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+		snd_soc_component_update_bits(component, CS42L52_PB_CTL1,
 				    CS42L52_PB_CTL1_MUTE_MASK,
 				CS42L52_PB_CTL1_MUTE);
 	else
-		snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+		snd_soc_component_update_bits(component, CS42L52_PB_CTL1,
 				    CS42L52_PB_CTL1_MUTE_MASK,
 				CS42L52_PB_CTL1_UNMUTE);
 
@@ -808,8 +808,8 @@ static int cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
 				     struct snd_pcm_hw_params *params,
 				     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 	u32 clk = 0;
 	int index;
 
@@ -823,36 +823,36 @@ static int cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
 		(clk_map_table[index].ratio << CLK_RATIO_SHIFT) |
 		clk_map_table[index].mclkdiv2;
 
-		snd_soc_write(codec, CS42L52_CLK_CTL, clk);
+		snd_soc_component_write(component, CS42L52_CLK_CTL, clk);
 	} else {
-		dev_err(codec->dev, "can't get correct mclk\n");
+		dev_err(component->dev, "can't get correct mclk\n");
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
+static int cs42l52_set_bias_level(struct snd_soc_component *component,
 					enum snd_soc_bias_level level)
 {
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, CS42L52_PWRCTL1,
+		snd_soc_component_update_bits(component, CS42L52_PWRCTL1,
 				    CS42L52_PWRCTL1_PDN_CODEC, 0);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l52->regmap, false);
 			regcache_sync(cs42l52->regmap);
 		}
-		snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+		snd_soc_component_write(component, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+		snd_soc_component_write(component, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
 		regcache_cache_only(cs42l52->regmap, true);
 		break;
 	}
@@ -902,8 +902,8 @@ static void cs42l52_beep_work(struct work_struct *work)
 {
 	struct cs42l52_private *cs42l52 =
 		container_of(work, struct cs42l52_private, beep_work);
-	struct snd_soc_codec *codec = cs42l52->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = cs42l52->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int i;
 	int val = 0;
 	int best = 0;
@@ -915,18 +915,18 @@ static void cs42l52_beep_work(struct work_struct *work)
 				best = i;
 		}
 
-		dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
 			beep_rates[best], cs42l52->beep_rate);
 
 		val = (best << CS42L52_BEEP_RATE_SHIFT);
 
 		snd_soc_dapm_enable_pin(dapm, "Beep");
 	} else {
-		dev_dbg(codec->dev, "Disabling beep\n");
+		dev_dbg(component->dev, "Disabling beep\n");
 		snd_soc_dapm_disable_pin(dapm, "Beep");
 	}
 
-	snd_soc_update_bits(codec, CS42L52_BEEP_FREQ,
+	snd_soc_component_update_bits(component, CS42L52_BEEP_FREQ,
 			    CS42L52_BEEP_RATE_MASK, val);
 
 	snd_soc_dapm_sync(dapm);
@@ -938,10 +938,10 @@ static void cs42l52_beep_work(struct work_struct *work)
 static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
 			     unsigned int code, int hz)
 {
-	struct snd_soc_codec *codec = input_get_drvdata(dev);
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = input_get_drvdata(dev);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
 
 	switch (code) {
 	case SND_BELL:
@@ -978,14 +978,14 @@ static ssize_t cs42l52_beep_set(struct device *dev,
 
 static DEVICE_ATTR(beep, 0200, NULL, cs42l52_beep_set);
 
-static void cs42l52_init_beep(struct snd_soc_codec *codec)
+static void cs42l52_init_beep(struct snd_soc_component *component)
 {
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	cs42l52->beep = devm_input_allocate_device(codec->dev);
+	cs42l52->beep = devm_input_allocate_device(component->dev);
 	if (!cs42l52->beep) {
-		dev_err(codec->dev, "Failed to allocate beep device\n");
+		dev_err(component->dev, "Failed to allocate beep device\n");
 		return;
 	}
 
@@ -993,49 +993,49 @@ static void cs42l52_init_beep(struct snd_soc_codec *codec)
 	cs42l52->beep_rate = 0;
 
 	cs42l52->beep->name = "CS42L52 Beep Generator";
-	cs42l52->beep->phys = dev_name(codec->dev);
+	cs42l52->beep->phys = dev_name(component->dev);
 	cs42l52->beep->id.bustype = BUS_I2C;
 
 	cs42l52->beep->evbit[0] = BIT_MASK(EV_SND);
 	cs42l52->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
 	cs42l52->beep->event = cs42l52_beep_event;
-	cs42l52->beep->dev.parent = codec->dev;
-	input_set_drvdata(cs42l52->beep, codec);
+	cs42l52->beep->dev.parent = component->dev;
+	input_set_drvdata(cs42l52->beep, component);
 
 	ret = input_register_device(cs42l52->beep);
 	if (ret != 0) {
 		cs42l52->beep = NULL;
-		dev_err(codec->dev, "Failed to register beep device\n");
+		dev_err(component->dev, "Failed to register beep device\n");
 	}
 
-	ret = device_create_file(codec->dev, &dev_attr_beep);
+	ret = device_create_file(component->dev, &dev_attr_beep);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+		dev_err(component->dev, "Failed to create keyclick file: %d\n",
 			ret);
 	}
 }
 
-static void cs42l52_free_beep(struct snd_soc_codec *codec)
+static void cs42l52_free_beep(struct snd_soc_component *component)
 {
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 
-	device_remove_file(codec->dev, &dev_attr_beep);
+	device_remove_file(component->dev, &dev_attr_beep);
 	cancel_work_sync(&cs42l52->beep_work);
 	cs42l52->beep = NULL;
 
-	snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
+	snd_soc_component_update_bits(component, CS42L52_BEEP_TONE_CTL,
 			    CS42L52_BEEP_EN_MASK, 0);
 }
 
-static int cs42l52_probe(struct snd_soc_codec *codec)
+static int cs42l52_probe(struct snd_soc_component *component)
 {
-	struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(cs42l52->regmap, true);
 
-	cs42l52_add_mic_controls(codec);
+	cs42l52_add_mic_controls(component);
 
-	cs42l52_init_beep(codec);
+	cs42l52_init_beep(component);
 
 	cs42l52->sysclk = CS42L52_DEFAULT_CLK;
 	cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
@@ -1043,27 +1043,26 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int cs42l52_remove(struct snd_soc_codec *codec)
+static void cs42l52_remove(struct snd_soc_component *component)
 {
-	cs42l52_free_beep(codec);
-
-	return 0;
+	cs42l52_free_beep(component);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
-	.probe = cs42l52_probe,
-	.remove = cs42l52_remove,
-	.set_bias_level = cs42l52_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= cs42l52_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs42l52_snd_controls),
-		.dapm_widgets		= cs42l52_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs42l52_dapm_widgets),
-		.dapm_routes		= cs42l52_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cs42l52_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs42l52 = {
+	.probe			= cs42l52_probe,
+	.remove			= cs42l52_remove,
+	.set_bias_level		= cs42l52_set_bias_level,
+	.controls		= cs42l52_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l52_snd_controls),
+	.dapm_widgets		= cs42l52_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l52_dapm_widgets),
+	.dapm_routes		= cs42l52_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l52_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* Current and threshold powerup sequence Pg37 */
@@ -1202,19 +1201,13 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
 				   CS42L52_IFACE_CTL2_BIAS_LVL,
 				cs42l52->pdata.micbias_lvl);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs42l52, &cs42l52_dai, 1);
+	ret =  devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l52, &cs42l52_dai, 1);
 	if (ret < 0)
 		return ret;
 	return 0;
 }
 
-static int cs42l52_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct of_device_id cs42l52_of_match[] = {
 	{ .compatible = "cirrus,cs42l52", },
 	{},
@@ -1235,7 +1228,6 @@ static struct i2c_driver cs42l52_i2c_driver = {
 	},
 	.id_table = cs42l52_id,
 	.probe =    cs42l52_i2c_probe,
-	.remove =   cs42l52_i2c_remove,
 };
 
 module_i2c_driver(cs42l52_i2c_driver);
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index fd7b8d32c2b2..a5c8736fad77 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -45,7 +45,7 @@ static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
 
 struct  cs42l56_private {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct device *dev;
 	struct cs42l56_platform_data pdata;
 	struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
@@ -726,8 +726,8 @@ static int cs42l56_get_mclk_ratio(int mclk, int rate)
 static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
 			int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case CS42L56_MCLK_5P6448MHZ:
@@ -753,10 +753,10 @@ static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
 	}
 	cs42l56->mclk = freq;
 
-	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
 			    CS42L56_MCLK_PREDIV_MASK,
 				cs42l56->mclk_prediv);
-	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
 			    CS42L56_MCLK_DIV2_MASK,
 				cs42l56->mclk_div2);
 
@@ -765,8 +765,8 @@ static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
 
 static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -803,22 +803,22 @@ static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
 			    CS42L56_MS_MODE_MASK, cs42l56->iface);
-	snd_soc_update_bits(codec, CS42L56_SERIAL_FMT,
+	snd_soc_component_update_bits(component, CS42L56_SERIAL_FMT,
 			    CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
-	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
 			    CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
 	return 0;
 }
 
 static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute) {
 		/* Hit the DSP Mixer first */
-		snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
+		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
 				    CS42L56_ADCAMIX_MUTE_MASK |
 				    CS42L56_ADCBMIX_MUTE_MASK |
 				    CS42L56_PCMAMIX_MUTE_MASK |
@@ -827,21 +827,21 @@ static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
 				    CS42L56_MSTA_MUTE_MASK,
 				    CS42L56_MUTE_ALL);
 		/* Mute ADC's */
-		snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
+		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
 				    CS42L56_ADCA_MUTE_MASK |
 				    CS42L56_ADCB_MUTE_MASK,
 				    CS42L56_MUTE_ALL);
 		/* HP And LO */
-		snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
-		snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
-		snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
-		snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
 	} else {
-		snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
+		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
 				    CS42L56_ADCAMIX_MUTE_MASK |
 				    CS42L56_ADCBMIX_MUTE_MASK |
 				    CS42L56_PCMAMIX_MUTE_MASK |
@@ -850,18 +850,18 @@ static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
 				    CS42L56_MSTA_MUTE_MASK,
 				    CS42L56_UNMUTE);
 
-		snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
+		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
 				    CS42L56_ADCA_MUTE_MASK |
 				    CS42L56_ADCB_MUTE_MASK,
 				    CS42L56_UNMUTE);
 
-		snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
-		snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
-		snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
-		snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
+		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
 	}
 	return 0;
@@ -871,39 +871,39 @@ static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
 				     struct snd_pcm_hw_params *params,
 				     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 	int ratio;
 
 	ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
 	if (ratio >= 0) {
-		snd_soc_update_bits(codec, CS42L56_CLKCTL_2,
+		snd_soc_component_update_bits(component, CS42L56_CLKCTL_2,
 				    CS42L56_CLK_RATIO_MASK, ratio);
 	} else {
-		dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n");
+		dev_err(component->dev, "unsupported mclk/sclk/lrclk ratio\n");
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
+static int cs42l56_set_bias_level(struct snd_soc_component *component,
 					enum snd_soc_bias_level level)
 {
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
 				    CS42L56_MCLK_DIS_MASK, 0);
-		snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
+		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
 				    CS42L56_PDN_ALL_MASK, 0);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l56->regmap, false);
 			regcache_sync(cs42l56->regmap);
 			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
@@ -915,13 +915,13 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
 				return ret;
 			}
 		}
-		snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
+		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
 				    CS42L56_PDN_ALL_MASK, 1);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
+		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
 				    CS42L56_PDN_ALL_MASK, 1);
-		snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
 				    CS42L56_MCLK_DIS_MASK, 1);
 		regcache_cache_only(cs42l56->regmap, true);
 		regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
@@ -974,8 +974,8 @@ static void cs42l56_beep_work(struct work_struct *work)
 {
 	struct cs42l56_private *cs42l56 =
 		container_of(work, struct cs42l56_private, beep_work);
-	struct snd_soc_codec *codec = cs42l56->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = cs42l56->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int i;
 	int val = 0;
 	int best = 0;
@@ -987,18 +987,18 @@ static void cs42l56_beep_work(struct work_struct *work)
 				best = i;
 		}
 
-		dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
 			beep_freq[best], cs42l56->beep_rate);
 
 		val = (best << CS42L56_BEEP_RATE_SHIFT);
 
 		snd_soc_dapm_enable_pin(dapm, "Beep");
 	} else {
-		dev_dbg(codec->dev, "Disabling beep\n");
+		dev_dbg(component->dev, "Disabling beep\n");
 		snd_soc_dapm_disable_pin(dapm, "Beep");
 	}
 
-	snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME,
+	snd_soc_component_update_bits(component, CS42L56_BEEP_FREQ_ONTIME,
 			    CS42L56_BEEP_FREQ_MASK, val);
 
 	snd_soc_dapm_sync(dapm);
@@ -1010,10 +1010,10 @@ static void cs42l56_beep_work(struct work_struct *work)
 static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
 			     unsigned int code, int hz)
 {
-	struct snd_soc_codec *codec = input_get_drvdata(dev);
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = input_get_drvdata(dev);
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
 
 	switch (code) {
 	case SND_BELL:
@@ -1050,14 +1050,14 @@ static ssize_t cs42l56_beep_set(struct device *dev,
 
 static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
 
-static void cs42l56_init_beep(struct snd_soc_codec *codec)
+static void cs42l56_init_beep(struct snd_soc_component *component)
 {
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	cs42l56->beep = devm_input_allocate_device(codec->dev);
+	cs42l56->beep = devm_input_allocate_device(component->dev);
 	if (!cs42l56->beep) {
-		dev_err(codec->dev, "Failed to allocate beep device\n");
+		dev_err(component->dev, "Failed to allocate beep device\n");
 		return;
 	}
 
@@ -1065,68 +1065,67 @@ static void cs42l56_init_beep(struct snd_soc_codec *codec)
 	cs42l56->beep_rate = 0;
 
 	cs42l56->beep->name = "CS42L56 Beep Generator";
-	cs42l56->beep->phys = dev_name(codec->dev);
+	cs42l56->beep->phys = dev_name(component->dev);
 	cs42l56->beep->id.bustype = BUS_I2C;
 
 	cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
 	cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
 	cs42l56->beep->event = cs42l56_beep_event;
-	cs42l56->beep->dev.parent = codec->dev;
-	input_set_drvdata(cs42l56->beep, codec);
+	cs42l56->beep->dev.parent = component->dev;
+	input_set_drvdata(cs42l56->beep, component);
 
 	ret = input_register_device(cs42l56->beep);
 	if (ret != 0) {
 		cs42l56->beep = NULL;
-		dev_err(codec->dev, "Failed to register beep device\n");
+		dev_err(component->dev, "Failed to register beep device\n");
 	}
 
-	ret = device_create_file(codec->dev, &dev_attr_beep);
+	ret = device_create_file(component->dev, &dev_attr_beep);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+		dev_err(component->dev, "Failed to create keyclick file: %d\n",
 			ret);
 	}
 }
 
-static void cs42l56_free_beep(struct snd_soc_codec *codec)
+static void cs42l56_free_beep(struct snd_soc_component *component)
 {
-	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
 
-	device_remove_file(codec->dev, &dev_attr_beep);
+	device_remove_file(component->dev, &dev_attr_beep);
 	cancel_work_sync(&cs42l56->beep_work);
 	cs42l56->beep = NULL;
 
-	snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG,
+	snd_soc_component_update_bits(component, CS42L56_BEEP_TONE_CFG,
 			    CS42L56_BEEP_EN_MASK, 0);
 }
 
-static int cs42l56_probe(struct snd_soc_codec *codec)
+static int cs42l56_probe(struct snd_soc_component *component)
 {
-	cs42l56_init_beep(codec);
+	cs42l56_init_beep(component);
 
 	return 0;
 }
 
-static int cs42l56_remove(struct snd_soc_codec *codec)
+static void cs42l56_remove(struct snd_soc_component *component)
 {
-	cs42l56_free_beep(codec);
-
-	return 0;
+	cs42l56_free_beep(component);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
-	.probe = cs42l56_probe,
-	.remove = cs42l56_remove,
-	.set_bias_level = cs42l56_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= cs42l56_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
-		.dapm_widgets		= cs42l56_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
-		.dapm_routes		= cs42l56_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs42l56 = {
+	.probe			= cs42l56_probe,
+	.remove			= cs42l56_remove,
+	.set_bias_level		= cs42l56_set_bias_level,
+	.controls		= cs42l56_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
+	.dapm_widgets		= cs42l56_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
+	.dapm_routes		= cs42l56_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config cs42l56_regmap = {
@@ -1315,8 +1314,8 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
 				   CS42L56_ADAPT_PWR_MASK,
 				cs42l56->pdata.adaptive_pwr);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs42l56, &cs42l56_dai, 1);
+	ret =  devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l56, &cs42l56_dai, 1);
 	if (ret < 0)
 		return ret;
 
@@ -1332,7 +1331,6 @@ static int cs42l56_i2c_remove(struct i2c_client *client)
 {
 	struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
 			       cs42l56->supplies);
 	return 0;
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index aebaa97490b6..36b57ee00a30 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -490,8 +490,8 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
 static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 		/* 150 ms delay between setting PDN and MCLKDIS */
@@ -506,8 +506,8 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 		/* 50 ms delay between setting PDN and MCLKDIS */
@@ -524,8 +524,8 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
 static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 		/* 30 ms delay between setting PDN and MCLKDIS */
@@ -884,8 +884,8 @@ static int cs42l73_get_mclk_coeff(int mclk, int srate)
 
 static int cs42l73_set_mclk(struct snd_soc_dai *dai, unsigned int freq)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 
 	int mclkx_coeff;
 	u32 mclk = 0;
@@ -899,14 +899,14 @@ static int cs42l73_set_mclk(struct snd_soc_dai *dai, unsigned int freq)
 	mclk = cs42l73_mclkx_coeffs[mclkx_coeff].mclkx /
 		cs42l73_mclkx_coeffs[mclkx_coeff].ratio;
 
-	dev_dbg(codec->dev, "MCLK%u %u  <-> internal MCLK %u\n",
+	dev_dbg(component->dev, "MCLK%u %u  <-> internal MCLK %u\n",
 		 priv->mclksel + 1, cs42l73_mclkx_coeffs[mclkx_coeff].mclkx,
 		 mclk);
 
 	dmmcc = (priv->mclksel << 4) |
 		(cs42l73_mclkx_coeffs[mclkx_coeff].mclkdiv << 1);
 
-	snd_soc_write(codec, CS42L73_DMMCC, dmmcc);
+	snd_soc_component_write(component, CS42L73_DMMCC, dmmcc);
 
 	priv->sysclk = mclkx_coeff;
 	priv->mclk = mclk;
@@ -917,8 +917,8 @@ static int cs42l73_set_mclk(struct snd_soc_dai *dai, unsigned int freq)
 static int cs42l73_set_sysclk(struct snd_soc_dai *dai,
 			      int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case CS42L73_CLKID_MCLK1:
@@ -930,7 +930,7 @@ static int cs42l73_set_sysclk(struct snd_soc_dai *dai,
 	}
 
 	if ((cs42l73_set_mclk(dai, freq)) < 0) {
-		dev_err(codec->dev, "Unable to set MCLK for dai %s\n",
+		dev_err(component->dev, "Unable to set MCLK for dai %s\n",
 			dai->name);
 		return -EINVAL;
 	}
@@ -942,14 +942,14 @@ static int cs42l73_set_sysclk(struct snd_soc_dai *dai,
 
 static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 	u8 id = codec_dai->id;
 	unsigned int inv, format;
 	u8 spc, mmcc;
 
-	spc = snd_soc_read(codec, CS42L73_SPC(id));
-	mmcc = snd_soc_read(codec, CS42L73_MMCC(id));
+	spc = snd_soc_component_read32(component, CS42L73_SPC(id));
+	mmcc = snd_soc_component_read32(component, CS42L73_MMCC(id));
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -974,12 +974,12 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_B:
 		if (mmcc & CS42L73_MS_MASTER) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"PCM format in slave mode only\n");
 			return -EINVAL;
 		}
 		if (id == CS42L73_ASP) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"PCM format is not supported on ASP port\n");
 			return -EINVAL;
 		}
@@ -1029,7 +1029,7 @@ static unsigned int cs42l73_get_xspfs_coeff(u32 rate)
 	return 0;		/* 0 = Don't know */
 }
 
-static void cs42l73_update_asrc(struct snd_soc_codec *codec, int id, int srate)
+static void cs42l73_update_asrc(struct snd_soc_component *component, int id, int srate)
 {
 	u8 spfs = 0;
 
@@ -1038,13 +1038,13 @@ static void cs42l73_update_asrc(struct snd_soc_codec *codec, int id, int srate)
 
 	switch (id) {
 	case CS42L73_XSP:
-		snd_soc_update_bits(codec, CS42L73_VXSPFS, 0x0f, spfs);
+		snd_soc_component_update_bits(component, CS42L73_VXSPFS, 0x0f, spfs);
 	break;
 	case CS42L73_ASP:
-		snd_soc_update_bits(codec, CS42L73_ASPC, 0x3c, spfs << 2);
+		snd_soc_component_update_bits(component, CS42L73_ASPC, 0x3c, spfs << 2);
 	break;
 	case CS42L73_VSP:
-		snd_soc_update_bits(codec, CS42L73_VXSPFS, 0xf0, spfs << 4);
+		snd_soc_component_update_bits(component, CS42L73_VXSPFS, 0xf0, spfs << 4);
 	break;
 	default:
 	break;
@@ -1055,8 +1055,8 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
 	int id = dai->id;
 	int mclk_coeff;
 	int srate = params_rate(params);
@@ -1070,7 +1070,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
 		if (mclk_coeff < 0)
 			return -EINVAL;
 
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			 "DAI[%d]: MCLK %u, srate %u, MMCC[5:0] = %x\n",
 			 id, priv->mclk, srate,
 			 cs42l73_mclk_coeffs[mclk_coeff].mmcc);
@@ -1091,38 +1091,38 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
 	/* Update ASRCs */
 	priv->config[id].srate = srate;
 
-	snd_soc_write(codec, CS42L73_SPC(id), priv->config[id].spc);
-	snd_soc_write(codec, CS42L73_MMCC(id), priv->config[id].mmcc);
+	snd_soc_component_write(component, CS42L73_SPC(id), priv->config[id].spc);
+	snd_soc_component_write(component, CS42L73_MMCC(id), priv->config[id].mmcc);
 
-	cs42l73_update_asrc(codec, id, srate);
+	cs42l73_update_asrc(component, id, srate);
 
 	return 0;
 }
 
-static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
+static int cs42l73_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0);
-		snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0);
+		snd_soc_component_update_bits(component, CS42L73_DMMCC, CS42L73_MCLKDIS, 0);
+		snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 0);
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(cs42l73->regmap, false);
 			regcache_sync(cs42l73->regmap);
 		}
-		snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);
+		snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 1);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);
+		snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 1);
 		if (cs42l73->shutdwn_delay > 0) {
 			mdelay(cs42l73->shutdwn_delay);
 			cs42l73->shutdwn_delay = 0;
@@ -1131,7 +1131,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
 				     * down.
 				     */
 		}
-		snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
+		snd_soc_component_update_bits(component, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
 		break;
 	}
 	return 0;
@@ -1139,10 +1139,10 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
 
 static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int id = dai->id;
 
-	return snd_soc_update_bits(codec, CS42L73_SPC(id), CS42L73_SP_3ST,
+	return snd_soc_component_update_bits(component, CS42L73_SPC(id), CS42L73_SP_3ST,
 				   tristate << 7);
 }
 
@@ -1235,13 +1235,13 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
 	 }
 };
 
-static int cs42l73_probe(struct snd_soc_codec *codec)
+static int cs42l73_probe(struct snd_soc_component *component)
 {
-	struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
 
 	/* Set Charge Pump Frequency */
 	if (cs42l73->pdata.chgfreq)
-		snd_soc_update_bits(codec, CS42L73_CPFCHC,
+		snd_soc_component_update_bits(component, CS42L73_CPFCHC,
 				    CS42L73_CHARGEPUMP_MASK,
 					cs42l73->pdata.chgfreq << 4);
 
@@ -1252,19 +1252,20 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
-	.probe = cs42l73_probe,
-	.set_bias_level = cs42l73_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= cs42l73_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs42l73_snd_controls),
-		.dapm_widgets		= cs42l73_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs42l73_dapm_widgets),
-		.dapm_routes		= cs42l73_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cs42l73_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs42l73 = {
+	.probe			= cs42l73_probe,
+	.set_bias_level		= cs42l73_set_bias_level,
+	.controls		= cs42l73_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l73_snd_controls),
+	.dapm_widgets		= cs42l73_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l73_dapm_widgets),
+	.dapm_routes		= cs42l73_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l73_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config cs42l73_regmap = {
@@ -1361,20 +1362,14 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
 	dev_info(&i2c_client->dev,
 		 "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
 
-	ret =  snd_soc_register_codec(&i2c_client->dev,
-			&soc_codec_dev_cs42l73, cs42l73_dai,
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l73, cs42l73_dai,
 			ARRAY_SIZE(cs42l73_dai));
 	if (ret < 0)
 		return ret;
 	return 0;
 }
 
-static int cs42l73_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct of_device_id cs42l73_of_match[] = {
 	{ .compatible = "cirrus,cs42l73", },
 	{},
@@ -1395,7 +1390,6 @@ static struct i2c_driver cs42l73_i2c_driver = {
 		   },
 	.id_table = cs42l73_id,
 	.probe = cs42l73_i2c_probe,
-	.remove = cs42l73_i2c_remove,
 
 };
 
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index 800c1d549347..0214e3ab9da0 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -33,7 +33,6 @@ static int cs42xx8_i2c_probe(struct i2c_client *i2c,
 
 static int cs42xx8_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&i2c->dev);
 	pm_runtime_disable(&i2c->dev);
 
 	return 0;
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index c1785bd4ff19..ebb9e0cf8364 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -194,8 +194,8 @@ static const struct cs42xx8_ratios cs42xx8_ratios[] = {
 static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 
 	cs42xx8->sysclk = freq;
 
@@ -205,8 +205,8 @@ static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			       unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 	u32 val;
 
 	/* Set DAI format */
@@ -224,7 +224,7 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported dai format\n");
+		dev_err(component->dev, "unsupported dai format\n");
 		return -EINVAL;
 	}
 
@@ -241,7 +241,7 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		cs42xx8->slave_mode = false;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported master/slave mode\n");
+		dev_err(component->dev, "unsupported master/slave mode\n");
 		return -EINVAL;
 	}
 
@@ -252,8 +252,8 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	u32 ratio = cs42xx8->sysclk / params_rate(params);
 	u32 i, fm, val, mask;
@@ -267,7 +267,7 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (i == ARRAY_SIZE(cs42xx8_ratios)) {
-		dev_err(codec->dev, "unsupported sysclk ratio\n");
+		dev_err(component->dev, "unsupported sysclk ratio\n");
 		return -EINVAL;
 	}
 
@@ -285,8 +285,8 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
 
 static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
 	u8 dac_unmute = cs42xx8->tx_channels ?
 		        ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
 
@@ -382,14 +382,14 @@ const struct regmap_config cs42xx8_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
 
-static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
+static int cs42xx8_component_probe(struct snd_soc_component *component)
 {
-	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	switch (cs42xx8->drvdata->num_adcs) {
 	case 3:
-		snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
+		snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,
 					ARRAY_SIZE(cs42xx8_adc3_snd_controls));
 		snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
 					ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
@@ -406,18 +406,17 @@ static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver cs42xx8_driver = {
-	.probe = cs42xx8_codec_probe,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= cs42xx8_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),
-		.dapm_widgets		= cs42xx8_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),
-		.dapm_routes		= cs42xx8_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),
-	},
+static const struct snd_soc_component_driver cs42xx8_driver = {
+	.probe			= cs42xx8_component_probe,
+	.controls		= cs42xx8_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),
+	.dapm_widgets		= cs42xx8_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),
+	.dapm_routes		= cs42xx8_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 const struct cs42xx8_driver_data cs42448_data = {
@@ -520,9 +519,9 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
 	/* Each adc supports stereo input */
 	cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
 
-	ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
+	ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
 	if (ret) {
-		dev_err(dev, "failed to register codec:%d\n", ret);
+		dev_err(dev, "failed to register component:%d\n", ret);
 		goto err_enable;
 	}
 
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index 5ba0edc19df4..feca0a672976 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -236,12 +236,12 @@ static const struct cs43130_pll_params *cs43130_get_pll_table(
 	return NULL;
 }
 
-static int cs43130_pll_config(struct snd_soc_codec *codec)
+static int cs43130_pll_config(struct snd_soc_component *component)
 {
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 	const struct cs43130_pll_params *pll_entry;
 
-	dev_dbg(codec->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
+	dev_dbg(component->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
 		cs43130->mclk, cs43130->mclk_int);
 
 	pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int);
@@ -286,11 +286,11 @@ static int cs43130_pll_config(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int source,
 			   unsigned int freq_in, unsigned int freq_out)
 {
 	int ret = 0;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (freq_in) {
 	case 9600000:
@@ -306,7 +306,7 @@ static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
 		cs43130->mclk = freq_in;
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"unsupported pll input reference clock:%d\n", freq_in);
 		return -EINVAL;
 	}
@@ -319,21 +319,21 @@ static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
 		cs43130->mclk_int = freq_out;
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"unsupported pll output ref clock: %u\n", freq_out);
 		return -EINVAL;
 	}
 
-	ret = cs43130_pll_config(codec);
-	dev_dbg(codec->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
+	ret = cs43130_pll_config(component);
+	dev_dbg(component->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
 	return ret;
 }
 
-static int cs43130_change_clksrc(struct snd_soc_codec *codec,
+static int cs43130_change_clksrc(struct snd_soc_component *component,
 				 enum cs43130_mclk_src_sel src)
 {
 	int ret;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 	int mclk_int_decoded;
 
 	if (src == cs43130->mclk_int_src) {
@@ -349,7 +349,7 @@ static int cs43130_change_clksrc(struct snd_soc_codec *codec,
 		mclk_int_decoded = CS43130_MCLK_24P5;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
+		dev_err(component->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
 		return -EINVAL;
 	}
 
@@ -373,7 +373,7 @@ static int cs43130_change_clksrc(struct snd_soc_codec *codec,
 					   CS43130_XTAL_RDY_INT_MASK,
 					   1 << CS43130_XTAL_RDY_INT_SHIFT);
 			if (ret == 0) {
-				dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n");
+				dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
 				return -ETIMEDOUT;
 			}
 		}
@@ -409,7 +409,7 @@ static int cs43130_change_clksrc(struct snd_soc_codec *codec,
 					   CS43130_XTAL_RDY_INT_MASK,
 					   1 << CS43130_XTAL_RDY_INT_SHIFT);
 			if (ret == 0) {
-				dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n");
+				dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
 				return -ETIMEDOUT;
 			}
 		}
@@ -425,7 +425,7 @@ static int cs43130_change_clksrc(struct snd_soc_codec *codec,
 				   CS43130_PLL_RDY_INT_MASK,
 				   1 << CS43130_PLL_RDY_INT_SHIFT);
 		if (ret == 0) {
-			dev_err(codec->dev, "Timeout waiting for PLL_READY interrupt\n");
+			dev_err(component->dev, "Timeout waiting for PLL_READY interrupt\n");
 			return -ETIMEDOUT;
 		}
 
@@ -456,7 +456,7 @@ static int cs43130_change_clksrc(struct snd_soc_codec *codec,
 				   1 << CS43130_PDN_PLL_SHIFT);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid MCLK source value\n");
+		dev_err(component->dev, "Invalid MCLK source value\n");
 		return -EINVAL;
 	}
 
@@ -774,8 +774,8 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 	unsigned int required_clk;
 	u8 dsd_speed;
 
@@ -787,11 +787,11 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
 		else
 			required_clk = CS43130_MCLK_24M;
 
-		cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk);
+		cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
 		if (cs43130->pll_bypass)
-			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
 		else
-			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
 	}
 
 	cs43130->clk_req++;
@@ -807,7 +807,7 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
 		dsd_speed = 1;
 		break;
 	default:
-		dev_err(codec->dev, "Rate(%u) not supported\n",
+		dev_err(component->dev, "Rate(%u) not supported\n",
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -833,8 +833,8 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 	const struct cs43130_rate_map *rate_map;
 	unsigned int sclk = cs43130->dais[dai->id].sclk;
 	unsigned int bitwidth_sclk;
@@ -850,11 +850,11 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
 		else
 			required_clk = CS43130_MCLK_24M;
 
-		cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk);
+		cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
 		if (cs43130->pll_bypass)
-			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
 		else
-			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
 	}
 
 	cs43130->clk_req++;
@@ -878,7 +878,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
 			dsd_speed = 1;
 			break;
 		default:
-			dev_err(codec->dev, "Rate(%u) not supported\n",
+			dev_err(component->dev, "Rate(%u) not supported\n",
 				params_rate(params));
 			return -EINVAL;
 		}
@@ -895,7 +895,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
 		regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI (%d)\n", dai->id);
+		dev_err(component->dev, "Invalid DAI (%d)\n", dai->id);
 		return -EINVAL;
 	}
 
@@ -919,21 +919,21 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
 
 	if (!sclk) {
 		/* at this point, SCLK must be set */
-		dev_err(codec->dev, "SCLK freq is not set\n");
+		dev_err(component->dev, "SCLK freq is not set\n");
 		return -EINVAL;
 	}
 
 	bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params);
 	if (bitwidth_sclk < bitwidth_dai) {
-		dev_err(codec->dev, "Format not supported: SCLK freq is too low\n");
+		dev_err(component->dev, "Format not supported: SCLK freq is too low\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev,
+	dev_dbg(component->dev,
 		"sclk = %u, fs = %d, bitwidth_dai = %u\n",
 		sclk, params_rate(params), bitwidth_dai);
 
-	dev_dbg(codec->dev,
+	dev_dbg(component->dev,
 		"bitwidth_sclk = %u, num_ch = %u\n",
 		bitwidth_sclk, params_channels(params));
 
@@ -946,14 +946,14 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
 static int cs43130_hw_free(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	mutex_lock(&cs43130->clk_mutex);
 	cs43130->clk_req--;
 	if (!cs43130->clk_req) {
 		/* no DAI is currently using clk */
-		cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO);
+		cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
 		cs43130_pcm_dsd_mix(false, cs43130->regmap);
 	}
 	mutex_unlock(&cs43130->clk_mutex);
@@ -1023,8 +1023,8 @@ static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol,
 {
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int *item = ucontrol->value.enumerated.item;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (item[0] >= e->items)
@@ -1144,8 +1144,8 @@ static const struct reg_sequence unmute_seq[] = {
 static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1192,7 +1192,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 		return -EINVAL;
 	}
 	return 0;
@@ -1201,8 +1201,8 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
 static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1249,7 +1249,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
 		return -EINVAL;
 	}
 	return 0;
@@ -1270,8 +1270,8 @@ static const struct reg_sequence dac_postpmd_seq[] = {
 static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1325,7 +1325,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAC event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid DAC event = 0x%x\n", event);
 		return -EINVAL;
 	}
 	return 0;
@@ -1350,8 +1350,8 @@ static const struct reg_sequence hpin_postpmu_seq[] = {
 static int cs43130_hpin_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
@@ -1363,7 +1363,7 @@ static int cs43130_hpin_event(struct snd_soc_dapm_widget *w,
 				       ARRAY_SIZE(hpin_postpmu_seq));
 		break;
 	default:
-		dev_err(codec->dev, "Invalid HPIN event = 0x%x\n", event);
+		dev_err(component->dev, "Invalid HPIN event = 0x%x\n", event);
 		return -EINVAL;
 	}
 	return 0;
@@ -1471,8 +1471,8 @@ static int cs43130_dop_startup(struct snd_pcm_substream *substream,
 
 static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
@@ -1482,7 +1482,7 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported mode\n");
+		dev_err(component->dev, "unsupported mode\n");
 		return -EINVAL;
 	}
 
@@ -1500,12 +1500,12 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B;
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"unsupported audio format\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "dai_id = %d,  dai_mode = %u, dai_format = %u\n",
+	dev_dbg(component->dev, "dai_id = %d,  dai_mode = %u, dai_format = %u\n",
 		codec_dai->id,
 		cs43130->dais[codec_dai->id].dai_mode,
 		cs43130->dais[codec_dai->id].dai_format);
@@ -1515,8 +1515,8 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
 static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
@@ -1526,11 +1526,11 @@ static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported DAI format.\n");
+		dev_err(component->dev, "Unsupported DAI format.\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "dai_mode = 0x%x\n",
+	dev_dbg(component->dev, "dai_mode = 0x%x\n",
 		cs43130->dais[codec_dai->id].dai_mode);
 
 	return 0;
@@ -1539,11 +1539,11 @@ static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
 	cs43130->dais[codec_dai->id].sclk = freq;
-	dev_dbg(codec->dev, "dai_id = %d,  sclk = %u\n", codec_dai->id,
+	dev_dbg(component->dev, "dai_id = %d,  sclk = %u\n", codec_dai->id,
 		cs43130->dais[codec_dai->id].sclk);
 
 	return 0;
@@ -1627,13 +1627,13 @@ static struct snd_soc_dai_driver cs43130_dai[] = {
 
 };
 
-static int cs43130_codec_set_sysclk(struct snd_soc_codec *codec,
+static int cs43130_component_set_sysclk(struct snd_soc_component *component,
 				    int clk_id, int source, unsigned int freq,
 				    int dir)
 {
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
+	dev_dbg(component->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
 		clk_id, source, freq, dir);
 
 	switch (freq) {
@@ -1642,14 +1642,14 @@ static int cs43130_codec_set_sysclk(struct snd_soc_codec *codec,
 		cs43130->mclk = freq;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", freq);
+		dev_err(component->dev, "Invalid MCLK INT freq: %u\n", freq);
 		return -EINVAL;
 	}
 
 	if (source == CS43130_MCLK_SRC_EXT) {
 		cs43130->pll_bypass = true;
 	} else {
-		dev_err(codec->dev, "Invalid MCLK source\n");
+		dev_err(component->dev, "Invalid MCLK source\n");
 		return -EINVAL;
 	}
 
@@ -1929,7 +1929,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
 	unsigned int reg;
 	u32 addr;
 	u16 impedance;
-	struct snd_soc_codec *codec = cs43130->codec;
+	struct snd_soc_component *component = cs43130->component;
 
 	switch (msk) {
 	case CS43130_HPLOAD_DC_INT:
@@ -1959,7 +1959,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
 		else
 			cs43130->hpload_dc[HP_RIGHT] = impedance;
 
-		dev_dbg(codec->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
+		dev_dbg(component->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
 			impedance);
 	} else {
 		if (left_ch)
@@ -1967,7 +1967,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
 		else
 			cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance;
 
-		dev_dbg(codec->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
+		dev_dbg(component->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
 			cs43130->ac_freq[ac_idx], !left_ch, impedance);
 	}
 
@@ -1981,7 +1981,7 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130,
 	int ret;
 	unsigned int msk;
 	u16 ac_reg_val;
-	struct snd_soc_codec *codec = cs43130->codec;
+	struct snd_soc_component *component = cs43130->component;
 
 	reinit_completion(&cs43130->hpload_evt);
 
@@ -2004,17 +2004,17 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130,
 					  msecs_to_jiffies(1000));
 	regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk);
 	if (!ret) {
-		dev_err(codec->dev, "Timeout waiting for HPLOAD interrupt\n");
+		dev_err(component->dev, "Timeout waiting for HPLOAD interrupt\n");
 		return -1;
 	}
 
-	dev_dbg(codec->dev, "HP load stat: %x, INT_MASK_4: %x\n",
+	dev_dbg(component->dev, "HP load stat: %x, INT_MASK_4: %x\n",
 		cs43130->hpload_stat, msk);
 	if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT |
 				     CS43130_HPLOAD_UNPLUG_INT |
 				     CS43130_HPLOAD_OOR_INT)) ||
 	    !(cs43130->hpload_stat & rslt_msk)) {
-		dev_dbg(codec->dev, "HP load measure failed\n");
+		dev_dbg(component->dev, "HP load measure failed\n");
 		return -1;
 	}
 
@@ -2056,11 +2056,11 @@ static void cs43130_imp_meas(struct work_struct *wk)
 	unsigned int reg, seq_size;
 	int i, ret, ac_idx;
 	struct cs43130_private *cs43130;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct reg_sequences *hpload_seq;
 
 	cs43130 = container_of(wk, struct cs43130_private, work);
-	codec = cs43130->codec;
+	component = cs43130->component;
 
 	if (!cs43130->mclk)
 		return;
@@ -2070,11 +2070,11 @@ static void cs43130_imp_meas(struct work_struct *wk)
 	mutex_lock(&cs43130->clk_mutex);
 	if (!cs43130->clk_req) {
 		/* clk not in use */
-		cs43130_set_pll(codec, 0, 0, cs43130->mclk, CS43130_MCLK_22M);
+		cs43130_set_pll(component, 0, 0, cs43130->mclk, CS43130_MCLK_22M);
 		if (cs43130->pll_bypass)
-			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT);
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
 		else
-			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
 	}
 
 	cs43130->clk_req++;
@@ -2125,9 +2125,9 @@ static void cs43130_imp_meas(struct work_struct *wk)
 		snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE,
 				    CS43130_JACK_MASK);
 
-	dev_dbg(codec->dev, "Set HP output control. DC threshold\n");
+	dev_dbg(component->dev, "Set HP output control. DC threshold\n");
 	for (i = 0; i < CS43130_DC_THRESHOLD; i++)
-		dev_dbg(codec->dev, "DC threshold[%d]: %u.\n", i,
+		dev_dbg(component->dev, "DC threshold[%d]: %u.\n", i,
 			cs43130->dc_threshold[i]);
 
 	cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT],
@@ -2154,14 +2154,14 @@ static void cs43130_imp_meas(struct work_struct *wk)
 	cs43130->clk_req--;
 	/* clk not in use */
 	if (!cs43130->clk_req)
-		cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO);
+		cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
 	mutex_unlock(&cs43130->clk_mutex);
 }
 
 static irqreturn_t cs43130_irq_thread(int irq, void *data)
 {
 	struct cs43130_private *cs43130 = (struct cs43130_private *)data;
-	struct snd_soc_codec *codec = cs43130->codec;
+	struct snd_soc_component *component = cs43130->component;
 	unsigned int stickies[CS43130_NUM_INT];
 	unsigned int irq_occurrence = 0;
 	unsigned int masks[CS43130_NUM_INT];
@@ -2179,7 +2179,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 		for (j = 0; j < 8; j++)
 			irq_occurrence += (stickies[i] >> j) & 1;
 	}
-	dev_dbg(codec->dev, "number of interrupts occurred (%u)\n",
+	dev_dbg(component->dev, "number of interrupts occurred (%u)\n",
 		irq_occurrence);
 
 	if (!irq_occurrence)
@@ -2197,7 +2197,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"DC load has not completed before AC load (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
@@ -2206,7 +2206,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_err(codec->dev, "HP unplugged during measurement (%x)\n",
+		dev_err(component->dev, "HP unplugged during measurement (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
 		return IRQ_HANDLED;
@@ -2214,7 +2214,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_OOR_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_err(codec->dev, "HP load out of range (%x)\n",
+		dev_err(component->dev, "HP load out of range (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
 		return IRQ_HANDLED;
@@ -2222,7 +2222,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_AC_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_dbg(codec->dev, "HP AC load measurement done (%x)\n",
+		dev_dbg(component->dev, "HP AC load measurement done (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
 		return IRQ_HANDLED;
@@ -2230,7 +2230,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_DC_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_dbg(codec->dev, "HP DC load measurement done (%x)\n",
+		dev_dbg(component->dev, "HP DC load measurement done (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
 		return IRQ_HANDLED;
@@ -2238,7 +2238,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_ON_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_dbg(codec->dev, "HP load state machine on done (%x)\n",
+		dev_dbg(component->dev, "HP load state machine on done (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
 		return IRQ_HANDLED;
@@ -2246,19 +2246,19 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 
 	if (stickies[3] & CS43130_HPLOAD_OFF_INT) {
 		cs43130->hpload_stat = stickies[3];
-		dev_dbg(codec->dev, "HP load state machine off done (%x)\n",
+		dev_dbg(component->dev, "HP load state machine off done (%x)\n",
 			cs43130->hpload_stat);
 		complete(&cs43130->hpload_evt);
 		return IRQ_HANDLED;
 	}
 
 	if (stickies[0] & CS43130_XTAL_ERR_INT) {
-		dev_err(codec->dev, "Crystal err: clock is not running\n");
+		dev_err(component->dev, "Crystal err: clock is not running\n");
 		return IRQ_HANDLED;
 	}
 
 	if (stickies[0] & CS43130_HP_UNPLUG_INT) {
-		dev_dbg(codec->dev, "HP unplugged\n");
+		dev_dbg(component->dev, "HP unplugged\n");
 		cs43130->hpload_done = false;
 		snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK);
 		return IRQ_HANDLED;
@@ -2267,7 +2267,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 	if (stickies[0] & CS43130_HP_PLUG_INT) {
 		if (cs43130->dc_meas && !cs43130->hpload_done &&
 		    !work_busy(&cs43130->work)) {
-			dev_dbg(codec->dev, "HP load queue work\n");
+			dev_dbg(component->dev, "HP load queue work\n");
 			queue_work(cs43130->wq, &cs43130->work);
 		}
 
@@ -2279,14 +2279,14 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
 	return IRQ_NONE;
 }
 
-static int cs43130_probe(struct snd_soc_codec *codec)
+static int cs43130_probe(struct snd_soc_component *component)
 {
 	int ret;
-	struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_card *card = codec->component.card;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_card *card = component->card;
 	unsigned int reg;
 
-	cs43130->codec = codec;
+	cs43130->component = component;
 
 	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) {
 		regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET,
@@ -2299,25 +2299,25 @@ static int cs43130_probe(struct snd_soc_codec *codec)
 	ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK,
 				    &cs43130->jack, NULL, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Cannot create jack\n");
+		dev_err(component->dev, "Cannot create jack\n");
 		return ret;
 	}
 
 	cs43130->hpload_done = false;
 	if (cs43130->dc_meas) {
-		ret = device_create_file(codec->dev, &dev_attr_hpload_dc_l);
+		ret = device_create_file(component->dev, &dev_attr_hpload_dc_l);
 		if (ret < 0)
 			return ret;
 
-		ret = device_create_file(codec->dev, &dev_attr_hpload_dc_r);
+		ret = device_create_file(component->dev, &dev_attr_hpload_dc_r);
 		if (ret < 0)
 			return ret;
 
-		ret = device_create_file(codec->dev, &dev_attr_hpload_ac_l);
+		ret = device_create_file(component->dev, &dev_attr_hpload_ac_l);
 		if (ret < 0)
 			return ret;
 
-		ret = device_create_file(codec->dev, &dev_attr_hpload_ac_r);
+		ret = device_create_file(component->dev, &dev_attr_hpload_ac_r);
 		if (ret < 0)
 			return ret;
 
@@ -2338,14 +2338,16 @@ static int cs43130_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs43130 = {
+static struct snd_soc_component_driver soc_component_dev_cs43130 = {
 	.probe			= cs43130_probe,
-	.component_driver = {
-		.controls		= cs43130_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs43130_snd_controls),
-	},
-	.set_sysclk		= cs43130_codec_set_sysclk,
+	.controls		= cs43130_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs43130_snd_controls),
+	.set_sysclk		= cs43130_component_set_sysclk,
 	.set_pll		= cs43130_set_pll,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config cs43130_regmap = {
@@ -2536,33 +2538,34 @@ static int cs43130_i2c_probe(struct i2c_client *client,
 		memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes),
 		       analog_hp_routes, sizeof(analog_hp_routes));
 
-		soc_codec_dev_cs43130.component_driver.dapm_widgets =
+		soc_component_dev_cs43130.dapm_widgets =
 			all_hp_widgets;
-		soc_codec_dev_cs43130.component_driver.num_dapm_widgets =
+		soc_component_dev_cs43130.num_dapm_widgets =
 			ARRAY_SIZE(all_hp_widgets);
-		soc_codec_dev_cs43130.component_driver.dapm_routes =
+		soc_component_dev_cs43130.dapm_routes =
 			all_hp_routes;
-		soc_codec_dev_cs43130.component_driver.num_dapm_routes =
+		soc_component_dev_cs43130.num_dapm_routes =
 			ARRAY_SIZE(all_hp_routes);
 		break;
 	case CS43198_CHIP_ID:
 	case CS4399_CHIP_ID:
-		soc_codec_dev_cs43130.component_driver.dapm_widgets =
+		soc_component_dev_cs43130.dapm_widgets =
 			digital_hp_widgets;
-		soc_codec_dev_cs43130.component_driver.num_dapm_widgets =
+		soc_component_dev_cs43130.num_dapm_widgets =
 			ARRAY_SIZE(digital_hp_widgets);
-		soc_codec_dev_cs43130.component_driver.dapm_routes =
+		soc_component_dev_cs43130.dapm_routes =
 			digital_hp_routes;
-		soc_codec_dev_cs43130.component_driver.num_dapm_routes =
+		soc_component_dev_cs43130.num_dapm_routes =
 			ARRAY_SIZE(digital_hp_routes);
 		break;
 	}
 
-	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130,
+	ret = devm_snd_soc_register_component(&client->dev,
+				     &soc_component_dev_cs43130,
 				     cs43130_dai, ARRAY_SIZE(cs43130_dai));
 	if (ret < 0) {
 		dev_err(&client->dev,
-			"snd_soc_register_codec failed with ret = %d\n", ret);
+			"snd_soc_register_component failed with ret = %d\n", ret);
 		goto err;
 	}
 
@@ -2604,8 +2607,6 @@ static int cs43130_i2c_remove(struct i2c_client *client)
 	pm_runtime_disable(&client->dev);
 	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
 
-	snd_soc_unregister_codec(&client->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h
index 781258418d89..c3c6eef61e87 100644
--- a/sound/soc/codecs/cs43130.h
+++ b/sound/soc/codecs/cs43130.h
@@ -508,7 +508,7 @@ struct cs43130_dai {
 };
 
 struct	cs43130_private {
-	struct snd_soc_codec		*codec;
+	struct snd_soc_component	*component;
 	struct regmap			*regmap;
 	struct regulator_bulk_data	supplies[CS43130_NUM_SUPPLIES];
 	struct gpio_desc		*reset_gpio;
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 0a749c79ef57..bee0e343723f 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -74,8 +74,8 @@ static bool cs4349_writeable_register(struct device *dev, unsigned int reg)
 static int cs4349_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4349_private *cs4349 = snd_soc_component_get_drvdata(component);
 	unsigned int fmt;
 
 	fmt = format & SND_SOC_DAIFMT_FORMAT_MASK;
@@ -97,8 +97,8 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct cs4349_private *cs4349 = snd_soc_component_get_drvdata(component);
 	int fmt, ret;
 
 	cs4349->rate = params_rate(params);
@@ -126,7 +126,7 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	ret = snd_soc_update_bits(codec, CS4349_MODE, DIF_MASK,
+	ret = snd_soc_component_update_bits(component, CS4349_MODE, DIF_MASK,
 				  MODE_FORMAT(fmt));
 	if (ret < 0)
 		return ret;
@@ -136,14 +136,14 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int cs4349_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int reg;
 
 	reg = 0;
 	if (mute)
 		reg = MUTE_AB_MASK;
 
-	return snd_soc_update_bits(codec, CS4349_MUTE, MUTE_AB_MASK, reg);
+	return snd_soc_component_update_bits(component, CS4349_MUTE, MUTE_AB_MASK, reg);
 }
 
 static DECLARE_TLV_DB_SCALE(dig_tlv, -12750, 50, 0);
@@ -255,15 +255,17 @@ static struct snd_soc_dai_driver cs4349_dai = {
 	.symmetric_rates = 1,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs4349 = {
-	.component_driver = {
-		.controls		= cs4349_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
-		.dapm_widgets		= cs4349_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
-		.dapm_routes		= cs4349_routes,
-		.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_cs4349 = {
+	.controls		= cs4349_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
+	.dapm_widgets		= cs4349_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
+	.dapm_routes		= cs4349_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config cs4349_regmap = {
@@ -305,7 +307,8 @@ static int cs4349_i2c_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, cs4349);
 
-	return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4349,
+	return devm_snd_soc_register_component(&client->dev,
+		&soc_component_dev_cs4349,
 		&cs4349_dai, 1);
 }
 
@@ -313,8 +316,6 @@ static int cs4349_i2c_remove(struct i2c_client *client)
 {
 	struct cs4349_private *cs4349 = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
-
 	/* Hold down reset */
 	gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
 
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index be2750680838..c93d3f7e8e36 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -33,6 +33,8 @@
 #include "wm_adsp.h"
 #include "cs47l24.h"
 
+#define DRV_NAME "cs47l24-codec"
+
 struct cs47l24_priv {
 	struct arizona_priv core;
 	struct arizona_fll fll[2];
@@ -60,14 +62,14 @@ static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
 static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	unsigned int v;
 	int ret;
 
 	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret);
+		dev_err(component->dev, "Failed to read SYSCLK state: %d\n", ret);
 		return ret;
 	}
 
@@ -929,10 +931,10 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
 	{ "DSP3 Voice Trigger", "Switch", "DSP3" },
 };
 
-static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec);
+	struct cs47l24_priv *cs47l24 = snd_soc_component_get_drvdata(component);
 
 	switch (fll_id) {
 	case CS47L24_FLL1:
@@ -1069,7 +1071,8 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
 static int cs47l24_open(struct snd_compr_stream *stream)
 {
 	struct snd_soc_pcm_runtime *rtd = stream->private_data;
-	struct cs47l24_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->core.arizona;
 	int n_adsp;
 
@@ -1115,33 +1118,32 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int cs47l24_codec_probe(struct snd_soc_codec *codec)
+static int cs47l24_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->core.arizona;
 	int ret;
 
 	arizona->dapm = dapm;
-	snd_soc_codec_init_regmap(codec, arizona->regmap);
+	snd_soc_component_init_regmap(component, arizona->regmap);
 
-	ret = arizona_init_spk(codec);
+	ret = arizona_init_spk(component);
 	if (ret < 0)
 		return ret;
 
-	arizona_init_gpio(codec);
-	arizona_init_mono(codec);
+	arizona_init_gpio(component);
+	arizona_init_mono(component);
 
-	ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
+	ret = wm_adsp2_component_probe(&priv->core.adsp[1], component);
 	if (ret)
 		goto err_adsp2_codec_probe;
 
-	ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec);
+	ret = wm_adsp2_component_probe(&priv->core.adsp[2], component);
 	if (ret)
 		goto err_adsp2_codec_probe;
 
-	ret = snd_soc_add_codec_controls(codec,
+	ret = snd_soc_add_component_controls(component,
 					 &arizona_adsp2_rate_controls[1], 2);
 	if (ret)
 		goto err_adsp2_codec_probe;
@@ -1151,22 +1153,20 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 
 err_adsp2_codec_probe:
-	wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
-	wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+	wm_adsp2_component_remove(&priv->core.adsp[1], component);
+	wm_adsp2_component_remove(&priv->core.adsp[2], component);
 
 	return ret;
 }
 
-static int cs47l24_codec_remove(struct snd_soc_codec *codec)
+static void cs47l24_component_remove(struct snd_soc_component *component)
 {
-	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
 
-	wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
-	wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+	wm_adsp2_component_remove(&priv->core.adsp[1], component);
+	wm_adsp2_component_remove(&priv->core.adsp[2], component);
 
 	priv->core.arizona->dapm = NULL;
-
-	return 0;
 }
 
 #define CS47L24_DIG_VU 0x0200
@@ -1177,37 +1177,32 @@ static unsigned int cs47l24_digital_vu[] = {
 	ARIZONA_DAC_DIGITAL_VOLUME_4L,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
-	.probe = cs47l24_codec_probe,
-	.remove = cs47l24_codec_remove,
-
-	.idle_bias_off = true,
-
-	.set_sysclk = arizona_set_sysclk,
-	.set_pll = cs47l24_set_fll,
-
-	.component_driver = {
-		.controls		= cs47l24_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs47l24_snd_controls),
-		.dapm_widgets		= cs47l24_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs47l24_dapm_widgets),
-		.dapm_routes		= cs47l24_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(cs47l24_dapm_routes),
-	},
-};
-
-static const struct snd_compr_ops cs47l24_compr_ops = {
-	.open = cs47l24_open,
-	.free = wm_adsp_compr_free,
-	.set_params = wm_adsp_compr_set_params,
-	.get_caps = wm_adsp_compr_get_caps,
-	.trigger = wm_adsp_compr_trigger,
-	.pointer = wm_adsp_compr_pointer,
-	.copy = wm_adsp_compr_copy,
+static struct snd_compr_ops cs47l24_compr_ops = {
+	.open		= cs47l24_open,
+	.free		= wm_adsp_compr_free,
+	.set_params	= wm_adsp_compr_set_params,
+	.get_caps	= wm_adsp_compr_get_caps,
+	.trigger	= wm_adsp_compr_trigger,
+	.pointer	= wm_adsp_compr_pointer,
+	.copy		= wm_adsp_compr_copy,
 };
 
-static const struct snd_soc_platform_driver cs47l24_compr_platform = {
-	.compr_ops = &cs47l24_compr_ops,
+static const struct snd_soc_component_driver soc_component_dev_cs47l24 = {
+	.probe			= cs47l24_component_probe,
+	.remove			= cs47l24_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= cs47l24_set_fll,
+	.name			= DRV_NAME,
+	.compr_ops		= &cs47l24_compr_ops,
+	.controls		= cs47l24_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs47l24_snd_controls),
+	.dapm_widgets		= cs47l24_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs47l24_dapm_widgets),
+	.dapm_routes		= cs47l24_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs47l24_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int cs47l24_probe(struct platform_device *pdev)
@@ -1298,23 +1293,16 @@ static int cs47l24_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_dsp_irq;
 
-	ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
-		goto err_spk_irqs;
-	}
-
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_cs47l24,
 				      cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
-		goto err_platform;
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
 	}
 
 	return ret;
 
-err_platform:
-	snd_soc_unregister_platform(&pdev->dev);
 err_spk_irqs:
 	arizona_free_spk_irqs(arizona);
 err_dsp_irq:
@@ -1328,8 +1316,6 @@ static int cs47l24_remove(struct platform_device *pdev)
 	struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev);
 	struct arizona *arizona = cs47l24->core.arizona;
 
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	wm_adsp2_remove(&cs47l24->core.adsp[1]);
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index c7edf2df5e36..8995ea45b4ca 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -549,7 +549,7 @@ static int cs53l30_get_mclk_coeff(int mclk_rate, int srate)
 static int cs53l30_set_sysclk(struct snd_soc_dai *dai,
 			      int clk_id, unsigned int freq, int dir)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
 	int mclkx_coeff;
 	u32 mclk_rate;
 
@@ -572,7 +572,7 @@ static int cs53l30_set_sysclk(struct snd_soc_dai *dai,
 
 static int cs53l30_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
 	u8 aspcfg = 0, aspctl1 = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -626,7 +626,7 @@ static int cs53l30_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
 	int srate = params_rate(params);
 	int mclk_coeff;
 
@@ -650,11 +650,11 @@ static int cs53l30_pcm_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int cs53l30_set_bias_level(struct snd_soc_codec *codec,
+static int cs53l30_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 	int i, inter_max_check, ret;
 
@@ -670,7 +670,7 @@ static int cs53l30_set_bias_level(struct snd_soc_codec *codec,
 		if (dapm->bias_level == SND_SOC_BIAS_OFF) {
 			ret = clk_prepare_enable(priv->mclk);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"failed to enable MCLK: %d\n", ret);
 				return ret;
 			}
@@ -736,7 +736,7 @@ static int cs53l30_set_bias_level(struct snd_soc_codec *codec,
 
 static int cs53l30_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
 	u8 val = tristate ? CS53L30_ASP_3ST : 0;
 
 	return regmap_update_bits(priv->regmap, CS53L30_ASP_CTL1,
@@ -770,7 +770,7 @@ static int cs53l30_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
 	unsigned int loc[CS53L30_TDM_SLOT_MAX] = {48, 48, 48, 48};
 	unsigned int slot_next, slot_step;
 	u64 tx_enable = 0;
@@ -840,7 +840,7 @@ static int cs53l30_set_dai_tdm_slot(struct snd_soc_dai *dai,
 
 static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
 
 	gpiod_set_value_cansleep(priv->mute_gpio, mute);
 
@@ -876,10 +876,10 @@ static struct snd_soc_dai_driver cs53l30_dai = {
 	.symmetric_rates = 1,
 };
 
-static int cs53l30_codec_probe(struct snd_soc_codec *codec)
+static int cs53l30_component_probe(struct snd_soc_component *component)
 {
-	struct cs53l30_private *priv = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (priv->use_sdout2)
 		snd_soc_dapm_add_routes(dapm, cs53l30_dapm_routes_sdout2,
@@ -891,19 +891,18 @@ static int cs53l30_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver cs53l30_driver = {
-	.probe = cs53l30_codec_probe,
-	.set_bias_level = cs53l30_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= cs53l30_snd_controls,
-		.num_controls		= ARRAY_SIZE(cs53l30_snd_controls),
-		.dapm_widgets		= cs53l30_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cs53l30_dapm_widgets),
-		.dapm_routes		= cs53l30_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(cs53l30_dapm_routes),
-	},
+static const struct snd_soc_component_driver cs53l30_driver = {
+	.probe			= cs53l30_component_probe,
+	.set_bias_level		= cs53l30_set_bias_level,
+	.controls		= cs53l30_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs53l30_snd_controls),
+	.dapm_widgets		= cs53l30_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs53l30_dapm_widgets),
+	.dapm_routes		= cs53l30_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs53l30_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct regmap_config cs53l30_regmap = {
@@ -1033,9 +1032,9 @@ static int cs53l30_i2c_probe(struct i2c_client *client,
 
 	dev_info(dev, "Cirrus Logic CS53L30, Revision: %02X\n", reg & 0xFF);
 
-	ret = snd_soc_register_codec(dev, &cs53l30_driver, &cs53l30_dai, 1);
+	ret = devm_snd_soc_register_component(dev, &cs53l30_driver, &cs53l30_dai, 1);
 	if (ret) {
-		dev_err(dev, "failed to register codec: %d\n", ret);
+		dev_err(dev, "failed to register component: %d\n", ret);
 		goto error;
 	}
 
@@ -1051,8 +1050,6 @@ static int cs53l30_i2c_remove(struct i2c_client *client)
 {
 	struct cs53l30_private *cs53l30 = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
-
 	/* Hold down reset */
 	gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
 
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 95bb10ba80dc..07dd33b09596 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -89,10 +89,10 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
 	{"ADC", NULL, "Input Mixer"},
 };
 
-static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
+static unsigned int cx20442_read_reg_cache(struct snd_soc_component *component,
 					   unsigned int reg)
 {
-	struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
 
 	if (reg >= 1)
 		return -EINVAL;
@@ -153,10 +153,10 @@ static int cx20442_pm_to_v253_vsp(u8 value)
 	return (value & (1 << CX20442_AGC)) ? -EINVAL : 0;
 }
 
-static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
+static int cx20442_write(struct snd_soc_component *component, unsigned int reg,
 							unsigned int value)
 {
-	struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
 	int vls, vsp, old, len;
 	char buf[18];
 
@@ -193,7 +193,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
 	if (unlikely(len > (ARRAY_SIZE(buf) - 1)))
 		return -ENOMEM;
 
-	dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
+	dev_dbg(component->dev, "%s: %s\n", __func__, buf);
 	if (cx20442->tty->ops->write(cx20442->tty, buf, len) != len)
 		return -EIO;
 
@@ -240,19 +240,19 @@ static int v253_open(struct tty_struct *tty)
 /* Line discipline .close() */
 static void v253_close(struct tty_struct *tty)
 {
-	struct snd_soc_codec *codec = tty->disc_data;
+	struct snd_soc_component *component = tty->disc_data;
 	struct cx20442_priv *cx20442;
 
 	tty->disc_data = NULL;
 
-	if (!codec)
+	if (!component)
 		return;
 
-	cx20442 = snd_soc_codec_get_drvdata(codec);
+	cx20442 = snd_soc_component_get_drvdata(component);
 
 	/* Prevent the codec driver from further accessing the modem */
 	cx20442->tty = NULL;
-	codec->component.card->pop_time = 0;
+	component->card->pop_time = 0;
 }
 
 /* Line discipline .hangup() */
@@ -266,20 +266,20 @@ static int v253_hangup(struct tty_struct *tty)
 static void v253_receive(struct tty_struct *tty,
 				const unsigned char *cp, char *fp, int count)
 {
-	struct snd_soc_codec *codec = tty->disc_data;
+	struct snd_soc_component *component = tty->disc_data;
 	struct cx20442_priv *cx20442;
 
-	if (!codec)
+	if (!component)
 		return;
 
-	cx20442 = snd_soc_codec_get_drvdata(codec);
+	cx20442 = snd_soc_component_get_drvdata(component);
 
 	if (!cx20442->tty) {
 		/* First modem response, complete setup procedure */
 
 		/* Set up codec driver access to modem controls */
 		cx20442->tty = tty;
-		codec->component.card->pop_time = 1;
+		component->card->pop_time = 1;
 	}
 }
 
@@ -323,15 +323,15 @@ static struct snd_soc_dai_driver cx20442_dai = {
 	},
 };
 
-static int cx20442_set_bias_level(struct snd_soc_codec *codec,
+static int cx20442_set_bias_level(struct snd_soc_component *component,
 		enum snd_soc_bias_level level)
 {
-	struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
 	int err = 0;
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
-		if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_STANDBY)
+		if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_STANDBY)
 			break;
 		if (IS_ERR(cx20442->por))
 			err = PTR_ERR(cx20442->por);
@@ -339,7 +339,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
 			err = regulator_enable(cx20442->por);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_PREPARE)
+		if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_PREPARE)
 			break;
 		if (IS_ERR(cx20442->por))
 			err = PTR_ERR(cx20442->por);
@@ -353,7 +353,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
 	return err;
 }
 
-static int cx20442_codec_probe(struct snd_soc_codec *codec)
+static int cx20442_component_probe(struct snd_soc_component *component)
 {
 	struct cx20442_priv *cx20442;
 
@@ -361,21 +361,21 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
 	if (cx20442 == NULL)
 		return -ENOMEM;
 
-	cx20442->por = regulator_get(codec->dev, "POR");
+	cx20442->por = regulator_get(component->dev, "POR");
 	if (IS_ERR(cx20442->por))
-		dev_warn(codec->dev, "failed to get the regulator");
+		dev_warn(component->dev, "failed to get the regulator");
 	cx20442->tty = NULL;
 
-	snd_soc_codec_set_drvdata(codec, cx20442);
-	codec->component.card->pop_time = 0;
+	snd_soc_component_set_drvdata(component, cx20442);
+	component->card->pop_time = 0;
 
 	return 0;
 }
 
 /* power down chip */
-static int cx20442_codec_remove(struct snd_soc_codec *codec)
+static void cx20442_component_remove(struct snd_soc_component *component)
 {
-	struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
 
 	if (cx20442->tty) {
 		struct tty_struct *tty = cx20442->tty;
@@ -387,36 +387,30 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
 		regulator_put(cx20442->por);
 	}
 
-	snd_soc_codec_set_drvdata(codec, NULL);
+	snd_soc_component_set_drvdata(component, NULL);
 	kfree(cx20442);
-	return 0;
 }
 
-static const struct snd_soc_codec_driver cx20442_codec_dev = {
-	.probe = 	cx20442_codec_probe,
-	.remove = 	cx20442_codec_remove,
-	.set_bias_level = cx20442_set_bias_level,
-	.read = cx20442_read_reg_cache,
-	.write = cx20442_write,
-
-	.component_driver = {
-		.dapm_widgets		= cx20442_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(cx20442_dapm_widgets),
-		.dapm_routes		= cx20442_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(cx20442_audio_map),
-	},
+static const struct snd_soc_component_driver cx20442_component_dev = {
+	.probe			= cx20442_component_probe,
+	.remove			= cx20442_component_remove,
+	.set_bias_level		= cx20442_set_bias_level,
+	.read			= cx20442_read_reg_cache,
+	.write			= cx20442_write,
+	.dapm_widgets		= cx20442_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cx20442_dapm_widgets),
+	.dapm_routes		= cx20442_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cx20442_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&cx20442_codec_dev, &cx20442_dai, 1);
-}
-
-static int cx20442_platform_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&cx20442_component_dev, &cx20442_dai, 1);
 }
 
 static struct platform_driver cx20442_platform_driver = {
@@ -424,7 +418,6 @@ static struct platform_driver cx20442_platform_driver = {
 		.name = "cx20442-codec",
 		},
 	.probe = cx20442_platform_probe,
-	.remove = cx20442_platform_remove,
 };
 
 module_platform_driver(cx20442_platform_driver);
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 1af443ccbc51..07153be52c52 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -331,12 +331,12 @@ static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
 static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 
 	if (ucontrol->value.integer.value[0]) {
 		/* Check if noise suppression is enabled */
-		if (snd_soc_read(codec, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) {
-			dev_dbg(codec->dev,
+		if (snd_soc_component_read32(component, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) {
+			dev_dbg(component->dev,
 				"Disable noise suppression to enable ALC\n");
 			return -EINVAL;
 		}
@@ -354,32 +354,32 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
 static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	u8 val;
 
 	if (ucontrol->value.integer.value[0]) {
 		/* Check if ALC is enabled */
-		if (snd_soc_read(codec, DA7210_ADC) & DA7210_ADC_ALC_EN)
+		if (snd_soc_component_read32(component, DA7210_ADC) & DA7210_ADC_ALC_EN)
 			goto err;
 
 		/* Check ZC for HP and AUX1 PGA */
-		if ((snd_soc_read(codec, DA7210_ZERO_CROSS) &
+		if ((snd_soc_component_read32(component, DA7210_ZERO_CROSS) &
 			(DA7210_AUX1_L_ZC | DA7210_AUX1_R_ZC | DA7210_HP_L_ZC |
 			DA7210_HP_R_ZC)) != (DA7210_AUX1_L_ZC |
 			DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | DA7210_HP_R_ZC))
 			goto err;
 
 		/* Check INPGA_L_VOL and INPGA_R_VOL */
-		val = snd_soc_read(codec, DA7210_IN_GAIN);
+		val = snd_soc_component_read32(component, DA7210_IN_GAIN);
 		if (((val & DA7210_INPGA_L_VOL) < DA7210_INPGA_MIN_VOL_NS) ||
 			(((val & DA7210_INPGA_R_VOL) >> 4) <
 			DA7210_INPGA_MIN_VOL_NS))
 			goto err;
 
 		/* Check AUX1_L_VOL and AUX1_R_VOL */
-		if (((snd_soc_read(codec, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) <
+		if (((snd_soc_component_read32(component, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) <
 		    DA7210_AUX1_MIN_VOL_NS) ||
-		    ((snd_soc_read(codec, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) <
+		    ((snd_soc_component_read32(component, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) <
 		    DA7210_AUX1_MIN_VOL_NS))
 			goto err;
 	}
@@ -760,19 +760,19 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
 	u32 dai_cfg1;
 	u32 fs, sysclk;
 
 	/* set DAI source to Left and Right ADC */
-	snd_soc_write(codec, DA7210_DAI_SRC_SEL,
+	snd_soc_component_write(component, DA7210_DAI_SRC_SEL,
 		     DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
 
 	/* Enable DAI */
-	snd_soc_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
+	snd_soc_component_write(component, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
 
-	dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1);
+	dai_cfg1 = 0xFC & snd_soc_component_read32(component, DA7210_DAI_CFG1);
 
 	switch (params_width(params)) {
 	case 16:
@@ -791,7 +791,7 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1);
+	snd_soc_component_write(component, DA7210_DAI_CFG1, dai_cfg1);
 
 	switch (params_rate(params)) {
 	case 8000:
@@ -839,17 +839,17 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* Disable active mode */
-	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+	snd_soc_component_update_bits(component, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
 
-	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
+	snd_soc_component_update_bits(component, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
 
 	if (da7210->mclk_rate && (da7210->mclk_rate != sysclk)) {
 		/* PLL mode, disable PLL bypass */
-		snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0);
+		snd_soc_component_update_bits(component, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0);
 
 		if (!da7210->master) {
 			/* PLL slave mode, also enable SRM */
-			snd_soc_update_bits(codec, DA7210_PLL,
+			snd_soc_component_update_bits(component, DA7210_PLL,
 						   (DA7210_MCLK_SRM_EN |
 						    DA7210_MCLK_DET_EN),
 						   (DA7210_MCLK_SRM_EN |
@@ -857,13 +857,13 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 		}
 	} else {
 		/* PLL bypass mode, enable PLL bypass and Auto Detection */
-		snd_soc_update_bits(codec, DA7210_PLL, DA7210_MCLK_DET_EN,
+		snd_soc_component_update_bits(component, DA7210_PLL, DA7210_MCLK_DET_EN,
 						       DA7210_MCLK_DET_EN);
-		snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP,
+		snd_soc_component_update_bits(component, DA7210_PLL_DIV3, DA7210_PLL_BYP,
 							    DA7210_PLL_BYP);
 	}
 	/* Enable active mode */
-	snd_soc_update_bits(codec, DA7210_STARTUP1,
+	snd_soc_component_update_bits(component, DA7210_STARTUP1,
 			    DA7210_SC_MST_EN, DA7210_SC_MST_EN);
 
 	return 0;
@@ -874,16 +874,16 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
  */
 static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
 	u32 dai_cfg1;
 	u32 dai_cfg3;
 
-	dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1);
-	dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3);
+	dai_cfg1 = 0x7f & snd_soc_component_read32(component, DA7210_DAI_CFG1);
+	dai_cfg3 = 0xfc & snd_soc_component_read32(component, DA7210_DAI_CFG3);
 
-	if ((snd_soc_read(codec, DA7210_PLL) & DA7210_PLL_EN) &&
-		(!(snd_soc_read(codec, DA7210_PLL_DIV3) & DA7210_PLL_BYP)))
+	if ((snd_soc_component_read32(component, DA7210_PLL) & DA7210_PLL_EN) &&
+		(!(snd_soc_component_read32(component, DA7210_PLL_DIV3) & DA7210_PLL_BYP)))
 		return -EINVAL;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -923,21 +923,21 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 	 */
 	dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
 
-	snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1);
-	snd_soc_write(codec, DA7210_DAI_CFG3, dai_cfg3);
+	snd_soc_component_write(component, DA7210_DAI_CFG1, dai_cfg1);
+	snd_soc_component_write(component, DA7210_DAI_CFG3, dai_cfg3);
 
 	return 0;
 }
 
 static int da7210_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u8 mute_reg = snd_soc_read(codec, DA7210_DAC_HPF) & 0xFB;
+	struct snd_soc_component *component = dai->component;
+	u8 mute_reg = snd_soc_component_read32(component, DA7210_DAC_HPF) & 0xFB;
 
 	if (mute)
-		snd_soc_write(codec, DA7210_DAC_HPF, mute_reg | 0x4);
+		snd_soc_component_write(component, DA7210_DAC_HPF, mute_reg | 0x4);
 	else
-		snd_soc_write(codec, DA7210_DAC_HPF, mute_reg);
+		snd_soc_component_write(component, DA7210_DAC_HPF, mute_reg);
 	return 0;
 }
 
@@ -947,8 +947,8 @@ static int da7210_mute(struct snd_soc_dai *dai, int mute)
 static int da7210_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case DA7210_CLKSRC_MCLK:
@@ -988,8 +988,8 @@ static int da7210_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
 
 	u8 pll_div1, pll_div2, pll_div3, cnt;
 
@@ -1014,18 +1014,18 @@ static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		goto err;
 
 	/* Disable active mode */
-	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+	snd_soc_component_update_bits(component, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
 	/* Write PLL dividers */
-	snd_soc_write(codec, DA7210_PLL_DIV1, pll_div1);
-	snd_soc_write(codec, DA7210_PLL_DIV2, pll_div2);
-	snd_soc_update_bits(codec, DA7210_PLL_DIV3,
+	snd_soc_component_write(component, DA7210_PLL_DIV1, pll_div1);
+	snd_soc_component_write(component, DA7210_PLL_DIV2, pll_div2);
+	snd_soc_component_update_bits(component, DA7210_PLL_DIV3,
 				   DA7210_PLL_DIV_L_MASK, pll_div3);
 
 	/* Enable PLL */
-	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+	snd_soc_component_update_bits(component, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
 
 	/* Enable active mode */
-	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN,
+	snd_soc_component_update_bits(component, DA7210_STARTUP1, DA7210_SC_MST_EN,
 						    DA7210_SC_MST_EN);
 	return 0;
 err:
@@ -1064,53 +1064,53 @@ static struct snd_soc_dai_driver da7210_dai = {
 	.symmetric_rates = 1,
 };
 
-static int da7210_probe(struct snd_soc_codec *codec)
+static int da7210_probe(struct snd_soc_component *component)
 {
-	struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
 
-	dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
+	dev_info(component->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
 	da7210->mclk_rate       = 0;    /* This will be set from set_sysclk() */
 	da7210->master          = 0;    /* This will be set from set_fmt() */
 
 	/* Enable internal regulator & bias current */
-	snd_soc_write(codec, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN);
+	snd_soc_component_write(component, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN);
 
 	/*
 	 * ADC settings
 	 */
 
 	/* Enable Left & Right MIC PGA and Mic Bias */
-	snd_soc_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
-	snd_soc_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
+	snd_soc_component_write(component, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
+	snd_soc_component_write(component, DA7210_MIC_R, DA7210_MIC_R_EN);
 
 	/* Enable Left and Right input PGA */
-	snd_soc_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
-	snd_soc_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
+	snd_soc_component_write(component, DA7210_INMIX_L, DA7210_IN_L_EN);
+	snd_soc_component_write(component, DA7210_INMIX_R, DA7210_IN_R_EN);
 
 	/* Enable Left and Right ADC */
-	snd_soc_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
+	snd_soc_component_write(component, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
 
 	/*
 	 * DAC settings
 	 */
 
 	/* Enable Left and Right DAC */
-	snd_soc_write(codec, DA7210_DAC_SEL,
+	snd_soc_component_write(component, DA7210_DAC_SEL,
 		     DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
 		     DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
 
 	/* Enable Left and Right out PGA */
-	snd_soc_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
-	snd_soc_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
+	snd_soc_component_write(component, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
+	snd_soc_component_write(component, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
 
 	/* Enable Left and Right HeadPhone PGA */
-	snd_soc_write(codec, DA7210_HP_CFG,
+	snd_soc_component_write(component, DA7210_HP_CFG,
 		     DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
 		     DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
 
 	/* Enable ramp mode for DAC gain update */
-	snd_soc_write(codec, DA7210_SOFTMUTE, DA7210_RAMP_EN);
+	snd_soc_component_write(component, DA7210_SOFTMUTE, DA7210_RAMP_EN);
 
 	/*
 	 * For DA7210 codec, there are two ways to enable/disable analog IOs
@@ -1138,43 +1138,44 @@ static int da7210_probe(struct snd_soc_codec *codec)
 	 */
 
 	/* Enable Line out amplifiers */
-	snd_soc_write(codec, DA7210_OUT1_L, DA7210_OUT1_L_EN);
-	snd_soc_write(codec, DA7210_OUT1_R, DA7210_OUT1_R_EN);
-	snd_soc_write(codec, DA7210_OUT2, DA7210_OUT2_EN |
+	snd_soc_component_write(component, DA7210_OUT1_L, DA7210_OUT1_L_EN);
+	snd_soc_component_write(component, DA7210_OUT1_R, DA7210_OUT1_R_EN);
+	snd_soc_component_write(component, DA7210_OUT2, DA7210_OUT2_EN |
 		     DA7210_OUT2_OUTMIX_L | DA7210_OUT2_OUTMIX_R);
 
 	/* Enable Aux1 */
-	snd_soc_write(codec, DA7210_AUX1_L, DA7210_AUX1_L_EN);
-	snd_soc_write(codec, DA7210_AUX1_R, DA7210_AUX1_R_EN);
+	snd_soc_component_write(component, DA7210_AUX1_L, DA7210_AUX1_L_EN);
+	snd_soc_component_write(component, DA7210_AUX1_R, DA7210_AUX1_R_EN);
 	/* Enable Aux2 */
-	snd_soc_write(codec, DA7210_AUX2, DA7210_AUX2_EN);
+	snd_soc_component_write(component, DA7210_AUX2, DA7210_AUX2_EN);
 
 	/* Set PLL Master clock range 10-20 MHz, enable PLL bypass */
-	snd_soc_write(codec, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
+	snd_soc_component_write(component, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
 					      DA7210_PLL_BYP);
 
 	/* Diable PLL and bypass it */
-	snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
+	snd_soc_component_write(component, DA7210_PLL, DA7210_PLL_FS_48000);
 
 	/* Activate all enabled subsystem */
-	snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
+	snd_soc_component_write(component, DA7210_STARTUP1, DA7210_SC_MST_EN);
 
-	dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
+	dev_info(component->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+static const struct snd_soc_component_driver soc_component_dev_da7210 = {
 	.probe			= da7210_probe,
-
-	.component_driver = {
-		.controls		= da7210_snd_controls,
-		.num_controls		= ARRAY_SIZE(da7210_snd_controls),
-		.dapm_widgets		= da7210_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
-		.dapm_routes		= da7210_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
-	},
+	.controls		= da7210_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7210_snd_controls),
+	.dapm_widgets		= da7210_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
+	.dapm_routes		= da7210_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 #if IS_ENABLED(CONFIG_I2C)
@@ -1232,20 +1233,14 @@ static int da7210_i2c_probe(struct i2c_client *i2c,
 	if (ret != 0)
 		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_da7210, &da7210_dai, 1);
+	ret =  snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da7210, &da7210_dai, 1);
 	if (ret < 0)
-		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
 
 	return ret;
 }
 
-static int da7210_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id da7210_i2c_id[] = {
 	{ "da7210", 0 },
 	{ }
@@ -1258,7 +1253,6 @@ static struct i2c_driver da7210_i2c_driver = {
 		.name = "da7210",
 	},
 	.probe		= da7210_i2c_probe,
-	.remove		= da7210_i2c_remove,
 	.id_table	= da7210_i2c_id,
 };
 #endif
@@ -1325,24 +1319,17 @@ static int da7210_spi_probe(struct spi_device *spi)
 	if (ret != 0)
 		dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_da7210, &da7210_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_da7210, &da7210_dai, 1);
 
 	return ret;
 }
 
-static int da7210_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver da7210_spi_driver = {
 	.driver = {
 		.name = "da7210",
 	},
 	.probe = da7210_spi_probe,
-	.remove = da7210_spi_remove
 };
 #endif
 
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index b2b4e90fc02a..54cb5f24969f 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -194,7 +194,7 @@ static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate,
  * Control Functions
  */
 
-static int da7213_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
+static int da7213_get_alc_data(struct snd_soc_component *component, u8 reg_val)
 {
 	int mid_data, top_data;
 	int sum = 0;
@@ -203,17 +203,17 @@ static int da7213_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
 	for (iteration = 0; iteration < DA7213_ALC_AVG_ITERATIONS;
 	     iteration++) {
 		/* Select the left or right channel and capture data */
-		snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL, reg_val);
+		snd_soc_component_write(component, DA7213_ALC_CIC_OP_LVL_CTRL, reg_val);
 
 		/* Select middle 8 bits for read back from data register */
-		snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL,
+		snd_soc_component_write(component, DA7213_ALC_CIC_OP_LVL_CTRL,
 			      reg_val | DA7213_ALC_DATA_MIDDLE);
-		mid_data = snd_soc_read(codec, DA7213_ALC_CIC_OP_LVL_DATA);
+		mid_data = snd_soc_component_read32(component, DA7213_ALC_CIC_OP_LVL_DATA);
 
 		/* Select top 8 bits for read back from data register */
-		snd_soc_write(codec, DA7213_ALC_CIC_OP_LVL_CTRL,
+		snd_soc_component_write(component, DA7213_ALC_CIC_OP_LVL_CTRL,
 			      reg_val | DA7213_ALC_DATA_TOP);
-		top_data = snd_soc_read(codec, DA7213_ALC_CIC_OP_LVL_DATA);
+		top_data = snd_soc_component_read32(component, DA7213_ALC_CIC_OP_LVL_DATA);
 
 		sum += ((mid_data << 8) | (top_data << 16));
 	}
@@ -221,17 +221,17 @@ static int da7213_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
 	return sum / DA7213_ALC_AVG_ITERATIONS;
 }
 
-static void da7213_alc_calib_man(struct snd_soc_codec *codec)
+static void da7213_alc_calib_man(struct snd_soc_component *component)
 {
 	u8 reg_val;
 	int avg_left_data, avg_right_data, offset_l, offset_r;
 
 	/* Calculate average for Left and Right data */
 	/* Left Data */
-	avg_left_data = da7213_get_alc_data(codec,
+	avg_left_data = da7213_get_alc_data(component,
 			DA7213_ALC_CIC_OP_CHANNEL_LEFT);
 	/* Right Data */
-	avg_right_data = da7213_get_alc_data(codec,
+	avg_right_data = da7213_get_alc_data(component,
 			 DA7213_ALC_CIC_OP_CHANNEL_RIGHT);
 
 	/* Calculate DC offset */
@@ -239,122 +239,122 @@ static void da7213_alc_calib_man(struct snd_soc_codec *codec)
 	offset_r = -avg_right_data;
 
 	reg_val = (offset_l & DA7213_ALC_OFFSET_15_8) >> 8;
-	snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_M_L, reg_val);
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_M_L, reg_val);
 	reg_val = (offset_l & DA7213_ALC_OFFSET_19_16) >> 16;
-	snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_U_L, reg_val);
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_U_L, reg_val);
 
 	reg_val = (offset_r & DA7213_ALC_OFFSET_15_8) >> 8;
-	snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_M_R, reg_val);
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_M_R, reg_val);
 	reg_val = (offset_r & DA7213_ALC_OFFSET_19_16) >> 16;
-	snd_soc_write(codec, DA7213_ALC_OFFSET_MAN_U_R, reg_val);
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_U_R, reg_val);
 
 	/* Enable analog/digital gain mode & offset cancellation */
-	snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
+	snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
 			    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE,
 			    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE);
 }
 
-static void da7213_alc_calib_auto(struct snd_soc_codec *codec)
+static void da7213_alc_calib_auto(struct snd_soc_component *component)
 {
 	u8 alc_ctrl1;
 
 	/* Begin auto calibration and wait for completion */
-	snd_soc_update_bits(codec, DA7213_ALC_CTRL1, DA7213_ALC_AUTO_CALIB_EN,
+	snd_soc_component_update_bits(component, DA7213_ALC_CTRL1, DA7213_ALC_AUTO_CALIB_EN,
 			    DA7213_ALC_AUTO_CALIB_EN);
 	do {
-		alc_ctrl1 = snd_soc_read(codec, DA7213_ALC_CTRL1);
+		alc_ctrl1 = snd_soc_component_read32(component, DA7213_ALC_CTRL1);
 	} while (alc_ctrl1 & DA7213_ALC_AUTO_CALIB_EN);
 
 	/* If auto calibration fails, fall back to digital gain only mode */
 	if (alc_ctrl1 & DA7213_ALC_CALIB_OVERFLOW) {
-		dev_warn(codec->dev,
+		dev_warn(component->dev,
 			 "ALC auto calibration failed with overflow\n");
-		snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
+		snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
 				    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE,
 				    0);
 	} else {
 		/* Enable analog/digital gain mode & offset cancellation */
-		snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
+		snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
 				    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE,
 				    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE);
 	}
 
 }
 
-static void da7213_alc_calib(struct snd_soc_codec *codec)
+static void da7213_alc_calib(struct snd_soc_component *component)
 {
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 	u8 adc_l_ctrl, adc_r_ctrl;
 	u8 mixin_l_sel, mixin_r_sel;
 	u8 mic_1_ctrl, mic_2_ctrl;
 
 	/* Save current values from ADC control registers */
-	adc_l_ctrl = snd_soc_read(codec, DA7213_ADC_L_CTRL);
-	adc_r_ctrl = snd_soc_read(codec, DA7213_ADC_R_CTRL);
+	adc_l_ctrl = snd_soc_component_read32(component, DA7213_ADC_L_CTRL);
+	adc_r_ctrl = snd_soc_component_read32(component, DA7213_ADC_R_CTRL);
 
 	/* Save current values from MIXIN_L/R_SELECT registers */
-	mixin_l_sel = snd_soc_read(codec, DA7213_MIXIN_L_SELECT);
-	mixin_r_sel = snd_soc_read(codec, DA7213_MIXIN_R_SELECT);
+	mixin_l_sel = snd_soc_component_read32(component, DA7213_MIXIN_L_SELECT);
+	mixin_r_sel = snd_soc_component_read32(component, DA7213_MIXIN_R_SELECT);
 
 	/* Save current values from MIC control registers */
-	mic_1_ctrl = snd_soc_read(codec, DA7213_MIC_1_CTRL);
-	mic_2_ctrl = snd_soc_read(codec, DA7213_MIC_2_CTRL);
+	mic_1_ctrl = snd_soc_component_read32(component, DA7213_MIC_1_CTRL);
+	mic_2_ctrl = snd_soc_component_read32(component, DA7213_MIC_2_CTRL);
 
 	/* Enable ADC Left and Right */
-	snd_soc_update_bits(codec, DA7213_ADC_L_CTRL, DA7213_ADC_EN,
+	snd_soc_component_update_bits(component, DA7213_ADC_L_CTRL, DA7213_ADC_EN,
 			    DA7213_ADC_EN);
-	snd_soc_update_bits(codec, DA7213_ADC_R_CTRL, DA7213_ADC_EN,
+	snd_soc_component_update_bits(component, DA7213_ADC_R_CTRL, DA7213_ADC_EN,
 			    DA7213_ADC_EN);
 
 	/* Enable MIC paths */
-	snd_soc_update_bits(codec, DA7213_MIXIN_L_SELECT,
+	snd_soc_component_update_bits(component, DA7213_MIXIN_L_SELECT,
 			    DA7213_MIXIN_L_MIX_SELECT_MIC_1 |
 			    DA7213_MIXIN_L_MIX_SELECT_MIC_2,
 			    DA7213_MIXIN_L_MIX_SELECT_MIC_1 |
 			    DA7213_MIXIN_L_MIX_SELECT_MIC_2);
-	snd_soc_update_bits(codec, DA7213_MIXIN_R_SELECT,
+	snd_soc_component_update_bits(component, DA7213_MIXIN_R_SELECT,
 			    DA7213_MIXIN_R_MIX_SELECT_MIC_2 |
 			    DA7213_MIXIN_R_MIX_SELECT_MIC_1,
 			    DA7213_MIXIN_R_MIX_SELECT_MIC_2 |
 			    DA7213_MIXIN_R_MIX_SELECT_MIC_1);
 
 	/* Mute MIC PGAs */
-	snd_soc_update_bits(codec, DA7213_MIC_1_CTRL, DA7213_MUTE_EN,
+	snd_soc_component_update_bits(component, DA7213_MIC_1_CTRL, DA7213_MUTE_EN,
 			    DA7213_MUTE_EN);
-	snd_soc_update_bits(codec, DA7213_MIC_2_CTRL, DA7213_MUTE_EN,
+	snd_soc_component_update_bits(component, DA7213_MIC_2_CTRL, DA7213_MUTE_EN,
 			    DA7213_MUTE_EN);
 
 	/* Perform calibration */
 	if (da7213->alc_calib_auto)
-		da7213_alc_calib_auto(codec);
+		da7213_alc_calib_auto(component);
 	else
-		da7213_alc_calib_man(codec);
+		da7213_alc_calib_man(component);
 
 	/* Restore MIXIN_L/R_SELECT registers to their original states */
-	snd_soc_write(codec, DA7213_MIXIN_L_SELECT, mixin_l_sel);
-	snd_soc_write(codec, DA7213_MIXIN_R_SELECT, mixin_r_sel);
+	snd_soc_component_write(component, DA7213_MIXIN_L_SELECT, mixin_l_sel);
+	snd_soc_component_write(component, DA7213_MIXIN_R_SELECT, mixin_r_sel);
 
 	/* Restore ADC control registers to their original states */
-	snd_soc_write(codec, DA7213_ADC_L_CTRL, adc_l_ctrl);
-	snd_soc_write(codec, DA7213_ADC_R_CTRL, adc_r_ctrl);
+	snd_soc_component_write(component, DA7213_ADC_L_CTRL, adc_l_ctrl);
+	snd_soc_component_write(component, DA7213_ADC_R_CTRL, adc_r_ctrl);
 
 	/* Restore original values of MIC control registers */
-	snd_soc_write(codec, DA7213_MIC_1_CTRL, mic_1_ctrl);
-	snd_soc_write(codec, DA7213_MIC_2_CTRL, mic_2_ctrl);
+	snd_soc_component_write(component, DA7213_MIC_1_CTRL, mic_1_ctrl);
+	snd_soc_component_write(component, DA7213_MIC_2_CTRL, mic_2_ctrl);
 }
 
 static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
 
 	/* If ALC in operation, make sure calibrated offsets are updated */
 	if ((!ret) && (da7213->alc_en))
-		da7213_alc_calib(codec);
+		da7213_alc_calib(component);
 
 	return ret;
 }
@@ -362,14 +362,14 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
 static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 
 	/* Force ALC offset calibration if enabling ALC */
 	if (ucontrol->value.integer.value[0] ||
 	    ucontrol->value.integer.value[1]) {
 		if (!da7213->alc_en) {
-			da7213_alc_calib(codec);
+			da7213_alc_calib(component);
 			da7213->alc_en = true;
 		}
 	} else {
@@ -735,8 +735,8 @@ static const struct snd_kcontrol_new da7213_dapm_mixoutr_controls[] = {
 static int da7213_dai_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 	u8 pll_ctrl, pll_status;
 	int i = 0;
 	bool srm_lock = false;
@@ -745,29 +745,29 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Enable DAI clks for master mode */
 		if (da7213->master)
-			snd_soc_update_bits(codec, DA7213_DAI_CLK_MODE,
+			snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE,
 					    DA7213_DAI_CLK_EN_MASK,
 					    DA7213_DAI_CLK_EN_MASK);
 
 		/* PC synchronised to DAI */
-		snd_soc_update_bits(codec, DA7213_PC_COUNT,
+		snd_soc_component_update_bits(component, DA7213_PC_COUNT,
 				    DA7213_PC_FREERUN_MASK, 0);
 
 		/* If SRM not enabled then nothing more to do */
-		pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL);
+		pll_ctrl = snd_soc_component_read32(component, DA7213_PLL_CTRL);
 		if (!(pll_ctrl & DA7213_PLL_SRM_EN))
 			return 0;
 
 		/* Assist 32KHz mode PLL lock */
 		if (pll_ctrl & DA7213_PLL_32K_MODE) {
-			snd_soc_write(codec, 0xF0, 0x8B);
-			snd_soc_write(codec, 0xF2, 0x03);
-			snd_soc_write(codec, 0xF0, 0x00);
+			snd_soc_component_write(component, 0xF0, 0x8B);
+			snd_soc_component_write(component, 0xF2, 0x03);
+			snd_soc_component_write(component, 0xF0, 0x00);
 		}
 
 		/* Check SRM has locked */
 		do {
-			pll_status = snd_soc_read(codec, DA7213_PLL_STATUS);
+			pll_status = snd_soc_component_read32(component, DA7213_PLL_STATUS);
 			if (pll_status & DA7219_PLL_SRM_LOCK) {
 				srm_lock = true;
 			} else {
@@ -777,26 +777,26 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w,
 		} while ((i < DA7213_SRM_CHECK_RETRIES) && (!srm_lock));
 
 		if (!srm_lock)
-			dev_warn(codec->dev, "SRM failed to lock\n");
+			dev_warn(component->dev, "SRM failed to lock\n");
 
 		return 0;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Revert 32KHz PLL lock udpates if applied previously */
-		pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL);
+		pll_ctrl = snd_soc_component_read32(component, DA7213_PLL_CTRL);
 		if (pll_ctrl & DA7213_PLL_32K_MODE) {
-			snd_soc_write(codec, 0xF0, 0x8B);
-			snd_soc_write(codec, 0xF2, 0x01);
-			snd_soc_write(codec, 0xF0, 0x00);
+			snd_soc_component_write(component, 0xF0, 0x8B);
+			snd_soc_component_write(component, 0xF2, 0x01);
+			snd_soc_component_write(component, 0xF0, 0x00);
 		}
 
 		/* PC free-running */
-		snd_soc_update_bits(codec, DA7213_PC_COUNT,
+		snd_soc_component_update_bits(component, DA7213_PC_COUNT,
 				    DA7213_PC_FREERUN_MASK,
 				    DA7213_PC_FREERUN_MASK);
 
 		/* Disable DAI clks if in master mode */
 		if (da7213->master)
-			snd_soc_update_bits(codec, DA7213_DAI_CLK_MODE,
+			snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE,
 					    DA7213_DAI_CLK_EN_MASK, 0);
 		return 0;
 	default:
@@ -1150,7 +1150,7 @@ static int da7213_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 dai_ctrl = 0;
 	u8 fs;
 
@@ -1208,17 +1208,17 @@ static int da7213_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_WORD_LENGTH_MASK,
+	snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_WORD_LENGTH_MASK,
 			    dai_ctrl);
-	snd_soc_write(codec, DA7213_SR, fs);
+	snd_soc_component_write(component, DA7213_SR, fs);
 
 	return 0;
 }
 
 static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 	u8 dai_clk_mode = 0, dai_ctrl = 0;
 	u8 dai_offset = 0;
 
@@ -1305,27 +1305,27 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	/* By default only 64 BCLK per WCLK is supported */
 	dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64;
 
-	snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode);
-	snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
+	snd_soc_component_write(component, DA7213_DAI_CLK_MODE, dai_clk_mode);
+	snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
 			    dai_ctrl);
-	snd_soc_write(codec, DA7213_DAI_OFFSET, dai_offset);
+	snd_soc_component_write(component, DA7213_DAI_OFFSET, dai_offset);
 
 	return 0;
 }
 
 static int da7213_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute) {
-		snd_soc_update_bits(codec, DA7213_DAC_L_CTRL,
+		snd_soc_component_update_bits(component, DA7213_DAC_L_CTRL,
 				    DA7213_MUTE_EN, DA7213_MUTE_EN);
-		snd_soc_update_bits(codec, DA7213_DAC_R_CTRL,
+		snd_soc_component_update_bits(component, DA7213_DAC_R_CTRL,
 				    DA7213_MUTE_EN, DA7213_MUTE_EN);
 	} else {
-		snd_soc_update_bits(codec, DA7213_DAC_L_CTRL,
+		snd_soc_component_update_bits(component, DA7213_DAC_L_CTRL,
 				    DA7213_MUTE_EN, 0);
-		snd_soc_update_bits(codec, DA7213_DAC_R_CTRL,
+		snd_soc_component_update_bits(component, DA7213_DAC_R_CTRL,
 				    DA7213_MUTE_EN, 0);
 	}
 
@@ -1338,8 +1338,8 @@ static int da7213_mute(struct snd_soc_dai *dai, int mute)
 static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq))
@@ -1353,11 +1353,11 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 	switch (clk_id) {
 	case DA7213_CLKSRC_MCLK:
-		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
 				    DA7213_PLL_MCLK_SQR_EN, 0);
 		break;
 	case DA7213_CLKSRC_MCLK_SQR:
-		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
 				    DA7213_PLL_MCLK_SQR_EN,
 				    DA7213_PLL_MCLK_SQR_EN);
 		break;
@@ -1387,8 +1387,8 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 
 	u8 pll_ctrl, indiv_bits, indiv;
 	u8 pll_frac_top, pll_frac_bot, pll_integer;
@@ -1398,7 +1398,7 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	/* Workout input divider based on MCLK rate */
 	if (da7213->mclk_rate == 32768) {
 		if (!da7213->master) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"32KHz only valid if codec is clock master\n");
 			return -EINVAL;
 		}
@@ -1411,7 +1411,7 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 
 	} else {
 		if (da7213->mclk_rate < 5000000) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"PLL input clock %d below valid range\n",
 				da7213->mclk_rate);
 			return -EINVAL;
@@ -1428,7 +1428,7 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ;
 			indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL;
 		} else {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"PLL input clock %d above valid range\n",
 				da7213->mclk_rate);
 			return -EINVAL;
@@ -1441,7 +1441,7 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	/* Configure PLL */
 	switch (source) {
 	case DA7213_SYSCLK_MCLK:
-		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
 				    DA7213_PLL_INDIV_MASK |
 				    DA7213_PLL_MODE_MASK, pll_ctrl);
 		return 0;
@@ -1453,7 +1453,7 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		break;
 	case DA7213_SYSCLK_PLL_32KHZ:
 		if (da7213->mclk_rate != 32768) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"32KHz mode only valid with 32KHz MCLK\n");
 			return -EINVAL;
 		}
@@ -1462,7 +1462,7 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		fout = DA7213_PLL_FREQ_OUT_94310400;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid PLL config\n");
+		dev_err(component->dev, "Invalid PLL config\n");
 		return -EINVAL;
 	}
 
@@ -1474,22 +1474,22 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	pll_frac_bot = (frac_div) & DA7213_BYTE_MASK;
 
 	/* Write PLL dividers */
-	snd_soc_write(codec, DA7213_PLL_FRAC_TOP, pll_frac_top);
-	snd_soc_write(codec, DA7213_PLL_FRAC_BOT, pll_frac_bot);
-	snd_soc_write(codec, DA7213_PLL_INTEGER, pll_integer);
+	snd_soc_component_write(component, DA7213_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA7213_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA7213_PLL_INTEGER, pll_integer);
 
 	/* Enable PLL */
 	pll_ctrl |= DA7213_PLL_EN;
-	snd_soc_update_bits(codec, DA7213_PLL_CTRL,
+	snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
 			    DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK,
 			    pll_ctrl);
 
 	/* Assist 32KHz mode PLL lock */
 	if (source == DA7213_SYSCLK_PLL_32KHZ) {
-		snd_soc_write(codec, 0xF0, 0x8B);
-		snd_soc_write(codec, 0xF1, 0x03);
-		snd_soc_write(codec, 0xF1, 0x01);
-		snd_soc_write(codec, 0xF0, 0x00);
+		snd_soc_component_write(component, 0xF0, 0x8B);
+		snd_soc_component_write(component, 0xF1, 0x03);
+		snd_soc_component_write(component, 0xF1, 0x01);
+		snd_soc_component_write(component, 0xF0, 0x00);
 	}
 
 	return 0;
@@ -1526,10 +1526,10 @@ static struct snd_soc_dai_driver da7213_dai = {
 	.symmetric_rates = 1,
 };
 
-static int da7213_set_bias_level(struct snd_soc_codec *codec,
+static int da7213_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1537,11 +1537,11 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Enable MCLK for transition to ON state */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
 			if (da7213->mclk) {
 				ret = clk_prepare_enable(da7213->mclk);
 				if (ret) {
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Failed to enable mclk\n");
 					return ret;
 				}
@@ -1549,9 +1549,9 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 		}
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Enable VMID reference & master bias */
-			snd_soc_update_bits(codec, DA7213_REFERENCES,
+			snd_soc_component_update_bits(component, DA7213_REFERENCES,
 					    DA7213_VMID_EN | DA7213_BIAS_EN,
 					    DA7213_VMID_EN | DA7213_BIAS_EN);
 		} else {
@@ -1562,7 +1562,7 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* Disable VMID reference & master bias */
-		snd_soc_update_bits(codec, DA7213_REFERENCES,
+		snd_soc_component_update_bits(component, DA7213_REFERENCES,
 				    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
 		break;
 	}
@@ -1588,7 +1588,7 @@ MODULE_DEVICE_TABLE(acpi, da7213_acpi_match);
 #endif
 
 static enum da7213_micbias_voltage
-	da7213_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+	da7213_of_micbias_lvl(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1600:
@@ -1600,39 +1600,39 @@ static enum da7213_micbias_voltage
 	case 3000:
 		return DA7213_MICBIAS_3_0V;
 	default:
-		dev_warn(codec->dev, "Invalid micbias level\n");
+		dev_warn(component->dev, "Invalid micbias level\n");
 		return DA7213_MICBIAS_2_2V;
 	}
 }
 
 static enum da7213_dmic_data_sel
-	da7213_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str)
+	da7213_of_dmic_data_sel(struct snd_soc_component *component, const char *str)
 {
 	if (!strcmp(str, "lrise_rfall")) {
 		return DA7213_DMIC_DATA_LRISE_RFALL;
 	} else if (!strcmp(str, "lfall_rrise")) {
 		return DA7213_DMIC_DATA_LFALL_RRISE;
 	} else {
-		dev_warn(codec->dev, "Invalid DMIC data select type\n");
+		dev_warn(component->dev, "Invalid DMIC data select type\n");
 		return DA7213_DMIC_DATA_LRISE_RFALL;
 	}
 }
 
 static enum da7213_dmic_samplephase
-	da7213_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str)
+	da7213_of_dmic_samplephase(struct snd_soc_component *component, const char *str)
 {
 	if (!strcmp(str, "on_clkedge")) {
 		return DA7213_DMIC_SAMPLE_ON_CLKEDGE;
 	} else if (!strcmp(str, "between_clkedge")) {
 		return DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE;
 	} else {
-		dev_warn(codec->dev, "Invalid DMIC sample phase\n");
+		dev_warn(component->dev, "Invalid DMIC sample phase\n");
 		return DA7213_DMIC_SAMPLE_ON_CLKEDGE;
 	}
 }
 
 static enum da7213_dmic_clk_rate
-	da7213_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val)
+	da7213_of_dmic_clkrate(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1500000:
@@ -1640,46 +1640,46 @@ static enum da7213_dmic_clk_rate
 	case 3000000:
 		return DA7213_DMIC_CLK_3_0MHZ;
 	default:
-		dev_warn(codec->dev, "Invalid DMIC clock rate\n");
+		dev_warn(component->dev, "Invalid DMIC clock rate\n");
 		return DA7213_DMIC_CLK_1_5MHZ;
 	}
 }
 
 static struct da7213_platform_data
-	*da7213_fw_to_pdata(struct snd_soc_codec *codec)
+	*da7213_fw_to_pdata(struct snd_soc_component *component)
 {
-	struct device *dev = codec->dev;
+	struct device *dev = component->dev;
 	struct da7213_platform_data *pdata;
 	const char *fw_str;
 	u32 fw_val32;
 
-	pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+	pdata = devm_kzalloc(component->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 		return NULL;
 
 	if (device_property_read_u32(dev, "dlg,micbias1-lvl", &fw_val32) >= 0)
-		pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, fw_val32);
+		pdata->micbias1_lvl = da7213_of_micbias_lvl(component, fw_val32);
 	else
 		pdata->micbias1_lvl = DA7213_MICBIAS_2_2V;
 
 	if (device_property_read_u32(dev, "dlg,micbias2-lvl", &fw_val32) >= 0)
-		pdata->micbias2_lvl = da7213_of_micbias_lvl(codec, fw_val32);
+		pdata->micbias2_lvl = da7213_of_micbias_lvl(component, fw_val32);
 	else
 		pdata->micbias2_lvl = DA7213_MICBIAS_2_2V;
 
 	if (!device_property_read_string(dev, "dlg,dmic-data-sel", &fw_str))
-		pdata->dmic_data_sel = da7213_of_dmic_data_sel(codec, fw_str);
+		pdata->dmic_data_sel = da7213_of_dmic_data_sel(component, fw_str);
 	else
 		pdata->dmic_data_sel = DA7213_DMIC_DATA_LRISE_RFALL;
 
 	if (!device_property_read_string(dev, "dlg,dmic-samplephase", &fw_str))
 		pdata->dmic_samplephase =
-			da7213_of_dmic_samplephase(codec, fw_str);
+			da7213_of_dmic_samplephase(component, fw_str);
 	else
 		pdata->dmic_samplephase = DA7213_DMIC_SAMPLE_ON_CLKEDGE;
 
 	if (device_property_read_u32(dev, "dlg,dmic-clkrate", &fw_val32) >= 0)
-		pdata->dmic_clk_rate = da7213_of_dmic_clkrate(codec, fw_val32);
+		pdata->dmic_clk_rate = da7213_of_dmic_clkrate(component, fw_val32);
 	else
 		pdata->dmic_clk_rate = DA7213_DMIC_CLK_3_0MHZ;
 
@@ -1687,41 +1687,41 @@ static struct da7213_platform_data
 }
 
 
-static int da7213_probe(struct snd_soc_codec *codec)
+static int da7213_probe(struct snd_soc_component *component)
 {
-	struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
 
 	/* Default to using ALC auto offset calibration mode. */
-	snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
+	snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
 			    DA7213_ALC_CALIB_MODE_MAN, 0);
 	da7213->alc_calib_auto = true;
 
 	/* Default PC counter to free-running */
-	snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
+	snd_soc_component_update_bits(component, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
 			    DA7213_PC_FREERUN_MASK);
 
 	/* Enable all Gain Ramps */
-	snd_soc_update_bits(codec, DA7213_AUX_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_AUX_L_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_AUX_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_AUX_R_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_MIXIN_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_MIXIN_L_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_MIXIN_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_MIXIN_R_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_ADC_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_ADC_L_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_ADC_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_ADC_R_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_DAC_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_DAC_L_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_DAC_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_DAC_R_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_HP_L_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_HP_R_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
-	snd_soc_update_bits(codec, DA7213_LINE_CTRL,
+	snd_soc_component_update_bits(component, DA7213_LINE_CTRL,
 			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
 
 	/*
@@ -1732,28 +1732,28 @@ static int da7213_probe(struct snd_soc_codec *codec)
 	 * being managed by DAPM while other (non power related) bits are
 	 * enabled here
 	 */
-	snd_soc_update_bits(codec, DA7213_MIXIN_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_MIXIN_L_CTRL,
 			    DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN);
-	snd_soc_update_bits(codec, DA7213_MIXIN_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_MIXIN_R_CTRL,
 			    DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN);
 
-	snd_soc_update_bits(codec, DA7213_MIXOUT_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_MIXOUT_L_CTRL,
 			    DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN);
-	snd_soc_update_bits(codec, DA7213_MIXOUT_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_MIXOUT_R_CTRL,
 			    DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN);
 
-	snd_soc_update_bits(codec, DA7213_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7213_HP_L_CTRL,
 			    DA7213_HP_AMP_OE, DA7213_HP_AMP_OE);
-	snd_soc_update_bits(codec, DA7213_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7213_HP_R_CTRL,
 			    DA7213_HP_AMP_OE, DA7213_HP_AMP_OE);
 
-	snd_soc_update_bits(codec, DA7213_LINE_CTRL,
+	snd_soc_component_update_bits(component, DA7213_LINE_CTRL,
 			    DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE);
 
 	/* Handle DT/Platform data */
-	da7213->pdata = dev_get_platdata(codec->dev);
+	da7213->pdata = dev_get_platdata(component->dev);
 	if (!da7213->pdata)
-		da7213->pdata = da7213_fw_to_pdata(codec);
+		da7213->pdata = da7213_fw_to_pdata(component);
 
 	/* Set platform data values */
 	if (da7213->pdata) {
@@ -1779,7 +1779,7 @@ static int da7213_probe(struct snd_soc_codec *codec)
 					 DA7213_MICBIAS2_LEVEL_SHIFT);
 			break;
 		}
-		snd_soc_update_bits(codec, DA7213_MICBIAS_CTRL,
+		snd_soc_component_update_bits(component, DA7213_MICBIAS_CTRL,
 				    DA7213_MICBIAS1_LEVEL_MASK |
 				    DA7213_MICBIAS2_LEVEL_MASK, micbias_lvl);
 
@@ -1805,14 +1805,14 @@ static int da7213_probe(struct snd_soc_codec *codec)
 				     DA7213_DMIC_CLK_RATE_SHIFT);
 			break;
 		}
-		snd_soc_update_bits(codec, DA7213_MIC_CONFIG,
+		snd_soc_component_update_bits(component, DA7213_MIC_CONFIG,
 				    DA7213_DMIC_DATA_SEL_MASK |
 				    DA7213_DMIC_SAMPLEPHASE_MASK |
 				    DA7213_DMIC_CLK_RATE_MASK, dmic_cfg);
 	}
 
 	/* Check if MCLK provided */
-	da7213->mclk = devm_clk_get(codec->dev, "mclk");
+	da7213->mclk = devm_clk_get(component->dev, "mclk");
 	if (IS_ERR(da7213->mclk)) {
 		if (PTR_ERR(da7213->mclk) != -ENOENT)
 			return PTR_ERR(da7213->mclk);
@@ -1823,18 +1823,19 @@ static int da7213_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_da7213 = {
+static const struct snd_soc_component_driver soc_component_dev_da7213 = {
 	.probe			= da7213_probe,
 	.set_bias_level		= da7213_set_bias_level,
-
-	.component_driver = {
-		.controls		= da7213_snd_controls,
-		.num_controls		= ARRAY_SIZE(da7213_snd_controls),
-		.dapm_widgets		= da7213_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
-		.dapm_routes		= da7213_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
-	},
+	.controls		= da7213_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7213_snd_controls),
+	.dapm_widgets		= da7213_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
+	.dapm_routes		= da7213_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config da7213_regmap_config = {
@@ -1866,21 +1867,15 @@ static int da7213_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_da7213, &da7213_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da7213, &da7213_dai, 1);
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register da7213 codec: %d\n",
+		dev_err(&i2c->dev, "Failed to register da7213 component: %d\n",
 			ret);
 	}
 	return ret;
 }
 
-static int da7213_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id da7213_i2c_id[] = {
 	{ "da7213", 0 },
 	{ }
@@ -1895,7 +1890,6 @@ static struct i2c_driver da7213_i2c_driver = {
 		.acpi_match_table = ACPI_PTR(da7213_acpi_match),
 	},
 	.probe		= da7213_i2c_probe,
-	.remove		= da7213_remove,
 	.id_table	= da7213_i2c_id,
 };
 
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 96c644a15b11..ddc90ac0b19f 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -291,7 +291,7 @@ static const struct soc_enum da7218_cp_tau_delay =
  */
 
 /* ALC */
-static void da7218_alc_calib(struct snd_soc_codec *codec)
+static void da7218_alc_calib(struct snd_soc_component *component)
 {
 	u8 mic_1_ctrl, mic_2_ctrl;
 	u8 mixin_1_ctrl, mixin_2_ctrl;
@@ -302,59 +302,59 @@ static void da7218_alc_calib(struct snd_soc_codec *codec)
 	bool calibrated = false;
 
 	/* Save current state of MIC control registers */
-	mic_1_ctrl = snd_soc_read(codec, DA7218_MIC_1_CTRL);
-	mic_2_ctrl = snd_soc_read(codec, DA7218_MIC_2_CTRL);
+	mic_1_ctrl = snd_soc_component_read32(component, DA7218_MIC_1_CTRL);
+	mic_2_ctrl = snd_soc_component_read32(component, DA7218_MIC_2_CTRL);
 
 	/* Save current state of input mixer control registers */
-	mixin_1_ctrl = snd_soc_read(codec, DA7218_MIXIN_1_CTRL);
-	mixin_2_ctrl = snd_soc_read(codec, DA7218_MIXIN_2_CTRL);
+	mixin_1_ctrl = snd_soc_component_read32(component, DA7218_MIXIN_1_CTRL);
+	mixin_2_ctrl = snd_soc_component_read32(component, DA7218_MIXIN_2_CTRL);
 
 	/* Save current state of input filter control registers */
-	in_1l_filt_ctrl = snd_soc_read(codec, DA7218_IN_1L_FILTER_CTRL);
-	in_1r_filt_ctrl = snd_soc_read(codec, DA7218_IN_1R_FILTER_CTRL);
-	in_2l_filt_ctrl = snd_soc_read(codec, DA7218_IN_2L_FILTER_CTRL);
-	in_2r_filt_ctrl = snd_soc_read(codec, DA7218_IN_2R_FILTER_CTRL);
+	in_1l_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_1L_FILTER_CTRL);
+	in_1r_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_1R_FILTER_CTRL);
+	in_2l_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_2L_FILTER_CTRL);
+	in_2r_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_2R_FILTER_CTRL);
 
 	/* Save current state of input HPF control registers */
-	in_1_hpf_ctrl = snd_soc_read(codec, DA7218_IN_1_HPF_FILTER_CTRL);
-	in_2_hpf_ctrl = snd_soc_read(codec, DA7218_IN_2_HPF_FILTER_CTRL);
+	in_1_hpf_ctrl = snd_soc_component_read32(component, DA7218_IN_1_HPF_FILTER_CTRL);
+	in_2_hpf_ctrl = snd_soc_component_read32(component, DA7218_IN_2_HPF_FILTER_CTRL);
 
 	/* Enable then Mute MIC PGAs */
-	snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK,
 			    DA7218_MIC_1_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK,
 			    DA7218_MIC_2_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_MIC_1_CTRL,
+	snd_soc_component_update_bits(component, DA7218_MIC_1_CTRL,
 			    DA7218_MIC_1_AMP_MUTE_EN_MASK,
 			    DA7218_MIC_1_AMP_MUTE_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_MIC_2_CTRL,
+	snd_soc_component_update_bits(component, DA7218_MIC_2_CTRL,
 			    DA7218_MIC_2_AMP_MUTE_EN_MASK,
 			    DA7218_MIC_2_AMP_MUTE_EN_MASK);
 
 	/* Enable input mixers unmuted */
-	snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+	snd_soc_component_update_bits(component, DA7218_MIXIN_1_CTRL,
 			    DA7218_MIXIN_1_AMP_EN_MASK |
 			    DA7218_MIXIN_1_AMP_MUTE_EN_MASK,
 			    DA7218_MIXIN_1_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+	snd_soc_component_update_bits(component, DA7218_MIXIN_2_CTRL,
 			    DA7218_MIXIN_2_AMP_EN_MASK |
 			    DA7218_MIXIN_2_AMP_MUTE_EN_MASK,
 			    DA7218_MIXIN_2_AMP_EN_MASK);
 
 	/* Enable input filters unmuted */
-	snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_1L_FILTER_CTRL,
 			    DA7218_IN_1L_FILTER_EN_MASK |
 			    DA7218_IN_1L_MUTE_EN_MASK,
 			    DA7218_IN_1L_FILTER_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_1R_FILTER_CTRL,
 			    DA7218_IN_1R_FILTER_EN_MASK |
 			    DA7218_IN_1R_MUTE_EN_MASK,
 			    DA7218_IN_1R_FILTER_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_2L_FILTER_CTRL,
 			    DA7218_IN_2L_FILTER_EN_MASK |
 			    DA7218_IN_2L_MUTE_EN_MASK,
 			    DA7218_IN_2L_FILTER_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_2R_FILTER_CTRL,
 			    DA7218_IN_2R_FILTER_EN_MASK |
 			    DA7218_IN_2R_MUTE_EN_MASK,
 			    DA7218_IN_2R_FILTER_EN_MASK);
@@ -364,16 +364,16 @@ static void da7218_alc_calib(struct snd_soc_codec *codec)
 	 * rates above 32KHz the ADC signals will be stopped and will cause
 	 * calibration to lock up.
 	 */
-	snd_soc_update_bits(codec, DA7218_IN_1_HPF_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_1_HPF_FILTER_CTRL,
 			    DA7218_IN_1_VOICE_EN_MASK, 0);
-	snd_soc_update_bits(codec, DA7218_IN_2_HPF_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_2_HPF_FILTER_CTRL,
 			    DA7218_IN_2_VOICE_EN_MASK, 0);
 
 	/* Perform auto calibration */
-	snd_soc_update_bits(codec, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK,
+	snd_soc_component_update_bits(component, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK,
 			    DA7218_CALIB_AUTO_EN_MASK);
 	do {
-		calib_ctrl = snd_soc_read(codec, DA7218_CALIB_CTRL);
+		calib_ctrl = snd_soc_component_read32(component, DA7218_CALIB_CTRL);
 		if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) {
 			++i;
 			usleep_range(DA7218_ALC_CALIB_DELAY_MIN,
@@ -386,51 +386,51 @@ static void da7218_alc_calib(struct snd_soc_codec *codec)
 
 	/* If auto calibration fails, disable DC offset, hybrid ALC */
 	if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) {
-		dev_warn(codec->dev,
+		dev_warn(component->dev,
 			 "ALC auto calibration failed - %s\n",
 			 (calibrated) ? "overflow" : "timeout");
-		snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+		snd_soc_component_update_bits(component, DA7218_CALIB_CTRL,
 				    DA7218_CALIB_OFFSET_EN_MASK, 0);
-		snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+		snd_soc_component_update_bits(component, DA7218_ALC_CTRL1,
 				    DA7218_ALC_SYNC_MODE_MASK, 0);
 
 	} else {
 		/* Enable DC offset cancellation */
-		snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+		snd_soc_component_update_bits(component, DA7218_CALIB_CTRL,
 				    DA7218_CALIB_OFFSET_EN_MASK,
 				    DA7218_CALIB_OFFSET_EN_MASK);
 
 		/* Enable ALC hybrid mode */
-		snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+		snd_soc_component_update_bits(component, DA7218_ALC_CTRL1,
 				    DA7218_ALC_SYNC_MODE_MASK,
 				    DA7218_ALC_SYNC_MODE_CH1 |
 				    DA7218_ALC_SYNC_MODE_CH2);
 	}
 
 	/* Restore input HPF control registers to original states */
-	snd_soc_write(codec, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
-	snd_soc_write(codec, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);
+	snd_soc_component_write(component, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
+	snd_soc_component_write(component, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);
 
 	/* Restore input filter control registers to original states */
-	snd_soc_write(codec, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
-	snd_soc_write(codec, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
-	snd_soc_write(codec, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
-	snd_soc_write(codec, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);
 
 	/* Restore input mixer control registers to original state */
-	snd_soc_write(codec, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
-	snd_soc_write(codec, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);
+	snd_soc_component_write(component, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
+	snd_soc_component_write(component, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);
 
 	/* Restore MIC control registers to original states */
-	snd_soc_write(codec, DA7218_MIC_1_CTRL, mic_1_ctrl);
-	snd_soc_write(codec, DA7218_MIC_2_CTRL, mic_2_ctrl);
+	snd_soc_component_write(component, DA7218_MIC_1_CTRL, mic_1_ctrl);
+	snd_soc_component_write(component, DA7218_MIC_2_CTRL, mic_2_ctrl);
 }
 
 static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
@@ -440,7 +440,7 @@ static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
 	 * make sure calibrated offsets are updated.
 	 */
 	if ((ret == 1) && (da7218->alc_en))
-		da7218_alc_calib(codec);
+		da7218_alc_calib(component);
 
 	return ret;
 }
@@ -450,8 +450,8 @@ static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *) kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	unsigned int lvalue = ucontrol->value.integer.value[0];
 	unsigned int rvalue = ucontrol->value.integer.value[1];
 	unsigned int lshift = mc->shift;
@@ -460,7 +460,7 @@ static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
 
 	/* Force ALC offset calibration if enabling ALC */
 	if ((lvalue || rvalue) && (!da7218->alc_en))
-		da7218_alc_calib(codec);
+		da7218_alc_calib(component);
 
 	/* Update bits to detail which channels are enabled/disabled */
 	da7218->alc_en &= ~mask;
@@ -473,8 +473,8 @@ static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
 static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mixer_ctrl =
 		(struct soc_mixer_control *) kcontrol->private_value;
 	unsigned int reg = mixer_ctrl->reg;
@@ -497,8 +497,8 @@ static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
 static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mixer_ctrl =
 		(struct soc_mixer_control *) kcontrol->private_value;
 	unsigned int reg = mixer_ctrl->reg;
@@ -517,8 +517,8 @@ static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
 static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mixer_ctrl =
 		(struct soc_mixer_control *) kcontrol->private_value;
 	unsigned int lvalue = ucontrol->value.integer.value[0];
@@ -537,15 +537,15 @@ static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
 	 * power the path (IN_FILTER widget events). This handling avoids
 	 * unwanted level detect events.
 	 */
-	return snd_soc_write(codec, mixer_ctrl->reg,
+	return snd_soc_component_write(component, mixer_ctrl->reg,
 			     (da7218->in_filt_en & da7218->mic_lvl_det_en));
 }
 
 static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mixer_ctrl =
 		(struct soc_mixer_control *) kcontrol->private_value;
 	unsigned int lshift = mixer_ctrl->shift;
@@ -564,8 +564,8 @@ static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
 static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct soc_bytes_ext *bytes_ext =
 		(struct soc_bytes_ext *) kcontrol->private_value;
 
@@ -589,8 +589,8 @@ static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
 static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct soc_bytes_ext *bytes_ext =
 		(struct soc_bytes_ext *) kcontrol->private_value;
 	u8 reg, out_filt1l;
@@ -617,8 +617,8 @@ static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
 	}
 
 	/* Make sure at least out filter1 enabled to allow programming */
-	out_filt1l = snd_soc_read(codec, DA7218_OUT_1L_FILTER_CTRL);
-	snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL,
+	out_filt1l = snd_soc_component_read32(component, DA7218_OUT_1L_FILTER_CTRL);
+	snd_soc_component_write(component, DA7218_OUT_1L_FILTER_CTRL,
 		      out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK);
 
 	for (i = 0; i < bytes_ext->max; ++i) {
@@ -628,7 +628,7 @@ static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
 	}
 
 	/* Restore filter to previous setting */
-	snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, out_filt1l);
+	snd_soc_component_write(component, DA7218_OUT_1L_FILTER_CTRL, out_filt1l);
 
 	return 0;
 }
@@ -1349,8 +1349,8 @@ static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = {
 static int da7218_in_filter_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	u8 mask;
 
 	switch (w->reg) {
@@ -1389,7 +1389,7 @@ static int da7218_in_filter_event(struct snd_soc_dapm_widget *w,
 	}
 
 	/* Enable configured level detection paths */
-	snd_soc_write(codec, DA7218_LVL_DET_CTRL,
+	snd_soc_component_write(component, DA7218_LVL_DET_CTRL,
 		      (da7218->in_filt_en & da7218->mic_lvl_det_en));
 
 	return 0;
@@ -1398,8 +1398,8 @@ static int da7218_in_filter_event(struct snd_soc_dapm_widget *w,
 static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	u8 pll_ctrl, pll_status, refosc_cal;
 	int i;
 	bool success;
@@ -1408,14 +1408,14 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMU:
 		if (da7218->master)
 			/* Enable DAI clks for master mode */
-			snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+			snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
 					    DA7218_DAI_CLK_EN_MASK,
 					    DA7218_DAI_CLK_EN_MASK);
 
 		/* Tune reference oscillator */
-		snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+		snd_soc_component_write(component, DA7218_PLL_REFOSC_CAL,
 			      DA7218_PLL_REFOSC_CAL_START_MASK);
-		snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+		snd_soc_component_write(component, DA7218_PLL_REFOSC_CAL,
 			      DA7218_PLL_REFOSC_CAL_START_MASK |
 			      DA7218_PLL_REFOSC_CAL_EN_MASK);
 
@@ -1423,7 +1423,7 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 		i = 0;
 		success = false;
 		do {
-			refosc_cal = snd_soc_read(codec, DA7218_PLL_REFOSC_CAL);
+			refosc_cal = snd_soc_component_read32(component, DA7218_PLL_REFOSC_CAL);
 			if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) {
 				success = true;
 			} else {
@@ -1434,15 +1434,15 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 		} while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success));
 
 		if (!success)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				 "Reference oscillator failed calibration\n");
 
 		/* PC synchronised to DAI */
-		snd_soc_write(codec, DA7218_PC_COUNT,
+		snd_soc_component_write(component, DA7218_PC_COUNT,
 			      DA7218_PC_RESYNC_AUTO_MASK);
 
 		/* If SRM not enabled, we don't need to check status */
-		pll_ctrl = snd_soc_read(codec, DA7218_PLL_CTRL);
+		pll_ctrl = snd_soc_component_read32(component, DA7218_PLL_CTRL);
 		if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM)
 			return 0;
 
@@ -1450,7 +1450,7 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 		i = 0;
 		success = false;
 		do {
-			pll_status = snd_soc_read(codec, DA7218_PLL_STATUS);
+			pll_status = snd_soc_component_read32(component, DA7218_PLL_STATUS);
 			if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) {
 				success = true;
 			} else {
@@ -1460,16 +1460,16 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 		} while ((i < DA7218_SRM_CHECK_TRIES) && (!success));
 
 		if (!success)
-			dev_warn(codec->dev, "SRM failed to lock\n");
+			dev_warn(component->dev, "SRM failed to lock\n");
 
 		return 0;
 	case SND_SOC_DAPM_POST_PMD:
 		/* PC free-running */
-		snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+		snd_soc_component_write(component, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
 
 		if (da7218->master)
 			/* Disable DAI clks for master mode */
-			snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+			snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
 					    DA7218_DAI_CLK_EN_MASK, 0);
 
 		return 0;
@@ -1481,8 +1481,8 @@ static int da7218_dai_event(struct snd_soc_dapm_widget *w,
 static int da7218_cp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 
 	/*
 	 * If this is DA7217 and we're using single supply for differential
@@ -1493,11 +1493,11 @@ static int da7218_cp_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+		snd_soc_component_update_bits(component, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
 				    DA7218_CP_EN_MASK);
 		return 0;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+		snd_soc_component_update_bits(component, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
 				    0);
 		return 0;
 	default:
@@ -1508,17 +1508,17 @@ static int da7218_cp_event(struct snd_soc_dapm_widget *w,
 static int da7218_hp_pga_event(struct snd_soc_dapm_widget *w,
 			       struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* Enable headphone output */
-		snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK,
+		snd_soc_component_update_bits(component, w->reg, DA7218_HP_AMP_OE_MASK,
 				    DA7218_HP_AMP_OE_MASK);
 		return 0;
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Headphone output high impedance */
-		snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, 0);
+		snd_soc_component_update_bits(component, w->reg, DA7218_HP_AMP_OE_MASK, 0);
 		return 0;
 	default:
 		return -EINVAL;
@@ -1813,8 +1813,8 @@ static const struct snd_soc_dapm_route da7218_audio_map[] = {
 static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	if (da7218->mclk_rate == freq)
@@ -1828,12 +1828,12 @@ static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 	switch (clk_id) {
 	case DA7218_CLKSRC_MCLK_SQR:
-		snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
 				    DA7218_PLL_MCLK_SQR_EN_MASK,
 				    DA7218_PLL_MCLK_SQR_EN_MASK);
 		break;
 	case DA7218_CLKSRC_MCLK:
-		snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
 				    DA7218_PLL_MCLK_SQR_EN_MASK, 0);
 		break;
 	default:
@@ -1859,8 +1859,8 @@ static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 
 	u8 pll_ctrl, indiv_bits, indiv;
 	u8 pll_frac_top, pll_frac_bot, pll_integer;
@@ -1869,7 +1869,7 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 
 	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
 	if (da7218->mclk_rate < 2000000) {
-		dev_err(codec->dev, "PLL input clock %d below valid range\n",
+		dev_err(component->dev, "PLL input clock %d below valid range\n",
 			da7218->mclk_rate);
 		return -EINVAL;
 	} else if (da7218->mclk_rate <= 4500000) {
@@ -1888,7 +1888,7 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		indiv_bits = DA7218_PLL_INDIV_36_TO_54_MHZ;
 		indiv = DA7218_PLL_INDIV_36_TO_54_MHZ_VAL;
 	} else {
-		dev_err(codec->dev, "PLL input clock %d above valid range\n",
+		dev_err(component->dev, "PLL input clock %d above valid range\n",
 			da7218->mclk_rate);
 		return -EINVAL;
 	}
@@ -1899,7 +1899,7 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	switch (source) {
 	case DA7218_SYSCLK_MCLK:
 		pll_ctrl |= DA7218_PLL_MODE_BYPASS;
-		snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
 				    DA7218_PLL_INDIV_MASK |
 				    DA7218_PLL_MODE_MASK, pll_ctrl);
 		return 0;
@@ -1910,7 +1910,7 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		pll_ctrl |= DA7218_PLL_MODE_SRM;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid PLL config\n");
+		dev_err(component->dev, "Invalid PLL config\n");
 		return -EINVAL;
 	}
 
@@ -1922,10 +1922,10 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	pll_frac_bot = (frac_div) & DA7218_BYTE_MASK;
 
 	/* Write PLL config & dividers */
-	snd_soc_write(codec, DA7218_PLL_FRAC_TOP, pll_frac_top);
-	snd_soc_write(codec, DA7218_PLL_FRAC_BOT, pll_frac_bot);
-	snd_soc_write(codec, DA7218_PLL_INTEGER, pll_integer);
-	snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+	snd_soc_component_write(component, DA7218_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA7218_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA7218_PLL_INTEGER, pll_integer);
+	snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
 			    DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK,
 			    pll_ctrl);
 
@@ -1934,8 +1934,8 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 
 static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	u8 dai_clk_mode = 0, dai_ctrl = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -2012,8 +2012,8 @@ static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	/* By default 64 BCLKs per WCLK is supported */
 	dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64;
 
-	snd_soc_write(codec, DA7218_DAI_CLK_MODE, dai_clk_mode);
-	snd_soc_update_bits(codec, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK,
+	snd_soc_component_write(component, DA7218_DAI_CLK_MODE, dai_clk_mode);
+	snd_soc_component_update_bits(component, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK,
 			    dai_ctrl);
 
 	return 0;
@@ -2023,16 +2023,16 @@ static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				   unsigned int tx_mask, unsigned int rx_mask,
 				   int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 dai_bclks_per_wclk;
 	u32 frame_size;
 
 	/* No channels enabled so disable TDM, revert to 64-bit frames */
 	if (!tx_mask) {
-		snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+		snd_soc_component_update_bits(component, DA7218_DAI_TDM_CTRL,
 				    DA7218_DAI_TDM_CH_EN_MASK |
 				    DA7218_DAI_TDM_MODE_EN_MASK, 0);
-		snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+		snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
 				    DA7218_DAI_BCLKS_PER_WCLK_MASK,
 				    DA7218_DAI_BCLKS_PER_WCLK_64);
 		return 0;
@@ -2040,14 +2040,14 @@ static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai,
 
 	/* Check we have valid slots */
 	if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) {
-		dev_err(codec->dev, "Invalid number of slots, max = %d\n",
+		dev_err(component->dev, "Invalid number of slots, max = %d\n",
 			DA7218_DAI_TDM_MAX_SLOTS);
 		return -EINVAL;
 	}
 
 	/* Check we have a valid offset given (first 2 bytes of rx_mask) */
 	if (rx_mask >> DA7218_2BYTE_SHIFT) {
-		dev_err(codec->dev, "Invalid slot offset, max = %d\n",
+		dev_err(component->dev, "Invalid slot offset, max = %d\n",
 			DA7218_2BYTE_MASK);
 		return -EINVAL;
 	}
@@ -2068,18 +2068,18 @@ static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai,
 		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid frame size\n");
+		dev_err(component->dev, "Invalid frame size\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+	snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
 			    DA7218_DAI_BCLKS_PER_WCLK_MASK,
 			    dai_bclks_per_wclk);
-	snd_soc_write(codec, DA7218_DAI_OFFSET_LOWER,
+	snd_soc_component_write(component, DA7218_DAI_OFFSET_LOWER,
 		      (rx_mask & DA7218_BYTE_MASK));
-	snd_soc_write(codec, DA7218_DAI_OFFSET_UPPER,
+	snd_soc_component_write(component, DA7218_DAI_OFFSET_UPPER,
 		      ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK));
-	snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+	snd_soc_component_update_bits(component, DA7218_DAI_TDM_CTRL,
 			    DA7218_DAI_TDM_CH_EN_MASK |
 			    DA7218_DAI_TDM_MODE_EN_MASK,
 			    (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) |
@@ -2092,7 +2092,7 @@ static int da7218_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 dai_ctrl = 0, fs;
 	unsigned int channels;
 
@@ -2115,7 +2115,7 @@ static int da7218_hw_params(struct snd_pcm_substream *substream,
 
 	channels = params_channels(params);
 	if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Invalid number of channels, only 1 to %d supported\n",
 			DA7218_DAI_CH_NUM_MAX);
 		return -EINVAL;
@@ -2160,11 +2160,11 @@ static int da7218_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, DA7218_DAI_CTRL,
+	snd_soc_component_update_bits(component, DA7218_DAI_CTRL,
 			    DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK,
 			    dai_ctrl);
 	/* SRs tied for ADCs and DACs. */
-	snd_soc_write(codec, DA7218_SR,
+	snd_soc_component_write(component, DA7218_SR,
 		      (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT));
 
 	return 0;
@@ -2208,15 +2208,15 @@ static struct snd_soc_dai_driver da7218_dai = {
  * HP Detect
  */
 
-int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+int da7218_hpldet(struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 
 	if (da7218->dev_id == DA7217_DEV_ID)
 		return -EINVAL;
 
 	da7218->jack = jack;
-	snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+	snd_soc_component_update_bits(component, DA7218_HPLDET_JACK,
 			    DA7218_HPLDET_JACK_EN_MASK,
 			    jack ? DA7218_HPLDET_JACK_EN_MASK : 0);
 
@@ -2224,23 +2224,23 @@ int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 }
 EXPORT_SYMBOL_GPL(da7218_hpldet);
 
-static void da7218_micldet_irq(struct snd_soc_codec *codec)
+static void da7218_micldet_irq(struct snd_soc_component *component)
 {
 	char *envp[] = {
 		"EVENT=MIC_LEVEL_DETECT",
 		NULL,
 	};
 
-	kobject_uevent_env(&codec->dev->kobj, KOBJ_CHANGE, envp);
+	kobject_uevent_env(&component->dev->kobj, KOBJ_CHANGE, envp);
 }
 
-static void da7218_hpldet_irq(struct snd_soc_codec *codec)
+static void da7218_hpldet_irq(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	u8 jack_status;
 	int report;
 
-	jack_status = snd_soc_read(codec, DA7218_EVENT_STATUS);
+	jack_status = snd_soc_component_read32(component, DA7218_EVENT_STATUS);
 
 	if (jack_status & DA7218_HPLDET_JACK_STS_MASK)
 		report = SND_JACK_HEADPHONE;
@@ -2256,24 +2256,24 @@ static void da7218_hpldet_irq(struct snd_soc_codec *codec)
 
 static irqreturn_t da7218_irq_thread(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
+	struct snd_soc_component *component = data;
 	u8 status;
 
 	/* Read IRQ status reg */
-	status = snd_soc_read(codec, DA7218_EVENT);
+	status = snd_soc_component_read32(component, DA7218_EVENT);
 	if (!status)
 		return IRQ_NONE;
 
 	/* Mic level detect */
 	if (status & DA7218_LVL_DET_EVENT_MASK)
-		da7218_micldet_irq(codec);
+		da7218_micldet_irq(component);
 
 	/* HP detect */
 	if (status & DA7218_HPLDET_JACK_EVENT_MASK)
-		da7218_hpldet_irq(codec);
+		da7218_hpldet_irq(component);
 
 	/* Clear interrupts */
-	snd_soc_write(codec, DA7218_EVENT, status);
+	snd_soc_component_write(component, DA7218_EVENT, status);
 
 	return IRQ_HANDLED;
 }
@@ -2300,7 +2300,7 @@ static inline int da7218_of_get_id(struct device *dev)
 }
 
 static enum da7218_micbias_voltage
-	da7218_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+	da7218_of_micbias_lvl(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1200:
@@ -2322,13 +2322,13 @@ static enum da7218_micbias_voltage
 	case 3000:
 		return DA7218_MICBIAS_3_0V;
 	default:
-		dev_warn(codec->dev, "Invalid micbias level");
+		dev_warn(component->dev, "Invalid micbias level");
 		return DA7218_MICBIAS_1_6V;
 	}
 }
 
 static enum da7218_mic_amp_in_sel
-	da7218_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str)
+	da7218_of_mic_amp_in_sel(struct snd_soc_component *component, const char *str)
 {
 	if (!strcmp(str, "diff")) {
 		return DA7218_MIC_AMP_IN_SEL_DIFF;
@@ -2337,39 +2337,39 @@ static enum da7218_mic_amp_in_sel
 	} else if (!strcmp(str, "se_n")) {
 		return DA7218_MIC_AMP_IN_SEL_SE_N;
 	} else {
-		dev_warn(codec->dev, "Invalid mic input type selection");
+		dev_warn(component->dev, "Invalid mic input type selection");
 		return DA7218_MIC_AMP_IN_SEL_DIFF;
 	}
 }
 
 static enum da7218_dmic_data_sel
-	da7218_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str)
+	da7218_of_dmic_data_sel(struct snd_soc_component *component, const char *str)
 {
 	if (!strcmp(str, "lrise_rfall")) {
 		return DA7218_DMIC_DATA_LRISE_RFALL;
 	} else if (!strcmp(str, "lfall_rrise")) {
 		return DA7218_DMIC_DATA_LFALL_RRISE;
 	} else {
-		dev_warn(codec->dev, "Invalid DMIC data type selection");
+		dev_warn(component->dev, "Invalid DMIC data type selection");
 		return DA7218_DMIC_DATA_LRISE_RFALL;
 	}
 }
 
 static enum da7218_dmic_samplephase
-	da7218_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str)
+	da7218_of_dmic_samplephase(struct snd_soc_component *component, const char *str)
 {
 	if (!strcmp(str, "on_clkedge")) {
 		return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
 	} else if (!strcmp(str, "between_clkedge")) {
 		return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE;
 	} else {
-		dev_warn(codec->dev, "Invalid DMIC sample phase");
+		dev_warn(component->dev, "Invalid DMIC sample phase");
 		return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
 	}
 }
 
 static enum da7218_dmic_clk_rate
-	da7218_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val)
+	da7218_of_dmic_clkrate(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1500000:
@@ -2377,13 +2377,13 @@ static enum da7218_dmic_clk_rate
 	case 3000000:
 		return DA7218_DMIC_CLK_3_0MHZ;
 	default:
-		dev_warn(codec->dev, "Invalid DMIC clock rate");
+		dev_warn(component->dev, "Invalid DMIC clock rate");
 		return DA7218_DMIC_CLK_3_0MHZ;
 	}
 }
 
 static enum da7218_hpldet_jack_rate
-	da7218_of_jack_rate(struct snd_soc_codec *codec, u32 val)
+	da7218_of_jack_rate(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 5:
@@ -2403,13 +2403,13 @@ static enum da7218_hpldet_jack_rate
 	case 640:
 		return DA7218_HPLDET_JACK_RATE_640US;
 	default:
-		dev_warn(codec->dev, "Invalid jack detect rate");
+		dev_warn(component->dev, "Invalid jack detect rate");
 		return DA7218_HPLDET_JACK_RATE_40US;
 	}
 }
 
 static enum da7218_hpldet_jack_debounce
-	da7218_of_jack_debounce(struct snd_soc_codec *codec, u32 val)
+	da7218_of_jack_debounce(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 0:
@@ -2421,13 +2421,13 @@ static enum da7218_hpldet_jack_debounce
 	case 4:
 		return DA7218_HPLDET_JACK_DEBOUNCE_4;
 	default:
-		dev_warn(codec->dev, "Invalid jack debounce");
+		dev_warn(component->dev, "Invalid jack debounce");
 		return DA7218_HPLDET_JACK_DEBOUNCE_2;
 	}
 }
 
 static enum da7218_hpldet_jack_thr
-	da7218_of_jack_thr(struct snd_soc_codec *codec, u32 val)
+	da7218_of_jack_thr(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 84:
@@ -2439,76 +2439,76 @@ static enum da7218_hpldet_jack_thr
 	case 96:
 		return DA7218_HPLDET_JACK_THR_96PCT;
 	default:
-		dev_warn(codec->dev, "Invalid jack threshold level");
+		dev_warn(component->dev, "Invalid jack threshold level");
 		return DA7218_HPLDET_JACK_THR_84PCT;
 	}
 }
 
-static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
+static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
-	struct device_node *np = codec->dev->of_node;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct device_node *np = component->dev->of_node;
 	struct device_node *hpldet_np;
 	struct da7218_pdata *pdata;
 	struct da7218_hpldet_pdata *hpldet_pdata;
 	const char *of_str;
 	u32 of_val32;
 
-	pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+	pdata = devm_kzalloc(component->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 		return NULL;
 
 	if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0)
-		pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32);
+		pdata->micbias1_lvl = da7218_of_micbias_lvl(component, of_val32);
 	else
 		pdata->micbias1_lvl = DA7218_MICBIAS_1_6V;
 
 	if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0)
-		pdata->micbias2_lvl = da7218_of_micbias_lvl(codec, of_val32);
+		pdata->micbias2_lvl = da7218_of_micbias_lvl(component, of_val32);
 	else
 		pdata->micbias2_lvl = DA7218_MICBIAS_1_6V;
 
 	if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str))
 		pdata->mic1_amp_in_sel =
-			da7218_of_mic_amp_in_sel(codec, of_str);
+			da7218_of_mic_amp_in_sel(component, of_str);
 	else
 		pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
 
 	if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str))
 		pdata->mic2_amp_in_sel =
-			da7218_of_mic_amp_in_sel(codec, of_str);
+			da7218_of_mic_amp_in_sel(component, of_str);
 	else
 		pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
 
 	if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str))
-		pdata->dmic1_data_sel =	da7218_of_dmic_data_sel(codec, of_str);
+		pdata->dmic1_data_sel =	da7218_of_dmic_data_sel(component, of_str);
 	else
 		pdata->dmic1_data_sel =	DA7218_DMIC_DATA_LRISE_RFALL;
 
 	if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str))
 		pdata->dmic1_samplephase =
-			da7218_of_dmic_samplephase(codec, of_str);
+			da7218_of_dmic_samplephase(component, of_str);
 	else
 		pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
 
 	if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0)
-		pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+		pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(component, of_val32);
 	else
 		pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
 
 	if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str))
-		pdata->dmic2_data_sel = da7218_of_dmic_data_sel(codec, of_str);
+		pdata->dmic2_data_sel = da7218_of_dmic_data_sel(component, of_str);
 	else
 		pdata->dmic2_data_sel =	DA7218_DMIC_DATA_LRISE_RFALL;
 
 	if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str))
 		pdata->dmic2_samplephase =
-			da7218_of_dmic_samplephase(codec, of_str);
+			da7218_of_dmic_samplephase(component, of_str);
 	else
 		pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
 
 	if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0)
-		pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+		pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(component, of_val32);
 	else
 		pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
 
@@ -2522,7 +2522,7 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
 		if (!hpldet_np)
 			return pdata;
 
-		hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata),
+		hpldet_pdata = devm_kzalloc(component->dev, sizeof(*hpldet_pdata),
 					    GFP_KERNEL);
 		if (!hpldet_pdata) {
 			of_node_put(hpldet_np);
@@ -2533,14 +2533,14 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
 		if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us",
 					 &of_val32) >= 0)
 			hpldet_pdata->jack_rate =
-				da7218_of_jack_rate(codec, of_val32);
+				da7218_of_jack_rate(component, of_val32);
 		else
 			hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US;
 
 		if (of_property_read_u32(hpldet_np, "dlg,jack-debounce",
 					 &of_val32) >= 0)
 			hpldet_pdata->jack_debounce =
-				da7218_of_jack_debounce(codec, of_val32);
+				da7218_of_jack_debounce(component, of_val32);
 		else
 			hpldet_pdata->jack_debounce =
 				DA7218_HPLDET_JACK_DEBOUNCE_2;
@@ -2548,7 +2548,7 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
 		if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct",
 					 &of_val32) >= 0)
 			hpldet_pdata->jack_thr =
-				da7218_of_jack_thr(codec, of_val32);
+				da7218_of_jack_thr(component, of_val32);
 		else
 			hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT;
 
@@ -2572,10 +2572,10 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
  * Codec driver functions
  */
 
-static int da7218_set_bias_level(struct snd_soc_codec *codec,
+static int da7218_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -2583,11 +2583,11 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Enable MCLK for transition to ON state */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
 			if (da7218->mclk) {
 				ret = clk_prepare_enable(da7218->mclk);
 				if (ret) {
-					dev_err(codec->dev, "Failed to enable mclk\n");
+					dev_err(component->dev, "Failed to enable mclk\n");
 					return ret;
 				}
 			}
@@ -2595,14 +2595,14 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec,
 
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Master bias */
-			snd_soc_update_bits(codec, DA7218_REFERENCES,
+			snd_soc_component_update_bits(component, DA7218_REFERENCES,
 					    DA7218_BIAS_EN_MASK,
 					    DA7218_BIAS_EN_MASK);
 
 			/* Internal LDO */
-			snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+			snd_soc_component_update_bits(component, DA7218_LDO_CTRL,
 					    DA7218_LDO_EN_MASK,
 					    DA7218_LDO_EN_MASK);
 		} else {
@@ -2615,11 +2615,11 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec,
 		/* Only disable if jack detection disabled */
 		if (!da7218->jack) {
 			/* Internal LDO */
-			snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+			snd_soc_component_update_bits(component, DA7218_LDO_CTRL,
 					    DA7218_LDO_EN_MASK, 0);
 
 			/* Master bias */
-			snd_soc_update_bits(codec, DA7218_REFERENCES,
+			snd_soc_component_update_bits(component, DA7218_REFERENCES,
 					    DA7218_BIAS_EN_MASK, 0);
 		}
 		break;
@@ -2634,9 +2634,9 @@ static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = {
 	[DA7218_SUPPLY_VDDIO] = "VDDIO",
 };
 
-static int da7218_handle_supplies(struct snd_soc_codec *codec)
+static int da7218_handle_supplies(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct regulator *vddio;
 	u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V;
 	int i, ret;
@@ -2645,10 +2645,10 @@ static int da7218_handle_supplies(struct snd_soc_codec *codec)
 	for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
 		da7218->supplies[i].supply = da7218_supply_names[i];
 
-	ret = devm_regulator_bulk_get(codec->dev, DA7218_NUM_SUPPLIES,
+	ret = devm_regulator_bulk_get(component->dev, DA7218_NUM_SUPPLIES,
 				      da7218->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to get supplies\n");
+		dev_err(component->dev, "Failed to get supplies\n");
 		return ret;
 	}
 
@@ -2656,29 +2656,29 @@ static int da7218_handle_supplies(struct snd_soc_codec *codec)
 	vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer;
 	ret = regulator_get_voltage(vddio);
 	if (ret < 1500000)
-		dev_warn(codec->dev, "Invalid VDDIO voltage\n");
+		dev_warn(component->dev, "Invalid VDDIO voltage\n");
 	else if (ret < 2500000)
 		io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V;
 
 	/* Enable main supplies */
 	ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to enable supplies\n");
+		dev_err(component->dev, "Failed to enable supplies\n");
 		return ret;
 	}
 
 	/* Ensure device in active mode */
-	snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK);
+	snd_soc_component_write(component, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK);
 
 	/* Update IO voltage level range */
-	snd_soc_write(codec, DA7218_IO_CTRL, io_voltage_lvl);
+	snd_soc_component_write(component, DA7218_IO_CTRL, io_voltage_lvl);
 
 	return 0;
 }
 
-static void da7218_handle_pdata(struct snd_soc_codec *codec)
+static void da7218_handle_pdata(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	struct da7218_pdata *pdata = da7218->pdata;
 
 	if (pdata) {
@@ -2719,14 +2719,14 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 			break;
 		}
 
-		snd_soc_write(codec, DA7218_MICBIAS_CTRL, micbias_lvl);
+		snd_soc_component_write(component, DA7218_MICBIAS_CTRL, micbias_lvl);
 
 		/* Mic */
 		switch (pdata->mic1_amp_in_sel) {
 		case DA7218_MIC_AMP_IN_SEL_DIFF:
 		case DA7218_MIC_AMP_IN_SEL_SE_P:
 		case DA7218_MIC_AMP_IN_SEL_SE_N:
-			snd_soc_write(codec, DA7218_MIC_1_SELECT,
+			snd_soc_component_write(component, DA7218_MIC_1_SELECT,
 				      pdata->mic1_amp_in_sel);
 			break;
 		}
@@ -2735,7 +2735,7 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 		case DA7218_MIC_AMP_IN_SEL_DIFF:
 		case DA7218_MIC_AMP_IN_SEL_SE_P:
 		case DA7218_MIC_AMP_IN_SEL_SE_N:
-			snd_soc_write(codec, DA7218_MIC_2_SELECT,
+			snd_soc_component_write(component, DA7218_MIC_2_SELECT,
 				      pdata->mic2_amp_in_sel);
 			break;
 		}
@@ -2765,7 +2765,7 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 			break;
 		}
 
-		snd_soc_update_bits(codec, DA7218_DMIC_1_CTRL,
+		snd_soc_component_update_bits(component, DA7218_DMIC_1_CTRL,
 				    DA7218_DMIC_1_DATA_SEL_MASK |
 				    DA7218_DMIC_1_SAMPLEPHASE_MASK |
 				    DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg);
@@ -2795,7 +2795,7 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 			break;
 		}
 
-		snd_soc_update_bits(codec, DA7218_DMIC_2_CTRL,
+		snd_soc_component_update_bits(component, DA7218_DMIC_2_CTRL,
 				    DA7218_DMIC_2_DATA_SEL_MASK |
 				    DA7218_DMIC_2_SAMPLEPHASE_MASK |
 				    DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg);
@@ -2806,9 +2806,9 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 				pdata->hp_diff_single_supply;
 
 			if (da7218->hp_single_supply) {
-				snd_soc_write(codec, DA7218_HP_DIFF_UNLOCK,
+				snd_soc_component_write(component, DA7218_HP_DIFF_UNLOCK,
 					      DA7218_HP_DIFF_UNLOCK_VAL);
-				snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+				snd_soc_component_update_bits(component, DA7218_HP_DIFF_CTRL,
 						    DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK,
 						    DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK);
 			}
@@ -2857,7 +2857,7 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 					 DA7218_HPLDET_JACK_THR_SHIFT);
 				break;
 			}
-			snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+			snd_soc_component_update_bits(component, DA7218_HPLDET_JACK,
 					    DA7218_HPLDET_JACK_RATE_MASK |
 					    DA7218_HPLDET_JACK_DEBOUNCE_MASK |
 					    DA7218_HPLDET_JACK_THR_MASK,
@@ -2873,31 +2873,31 @@ static void da7218_handle_pdata(struct snd_soc_codec *codec)
 			if (hpldet_pdata->discharge)
 				hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK;
 
-			snd_soc_write(codec, DA7218_HPLDET_CTRL, hpldet_cfg);
+			snd_soc_component_write(component, DA7218_HPLDET_CTRL, hpldet_cfg);
 		}
 	}
 }
 
-static int da7218_probe(struct snd_soc_codec *codec)
+static int da7218_probe(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	/* Regulator configuration */
-	ret = da7218_handle_supplies(codec);
+	ret = da7218_handle_supplies(component);
 	if (ret)
 		return ret;
 
 	/* Handle DT/Platform data */
-	if (codec->dev->of_node)
-		da7218->pdata = da7218_of_to_pdata(codec);
+	if (component->dev->of_node)
+		da7218->pdata = da7218_of_to_pdata(component);
 	else
-		da7218->pdata = dev_get_platdata(codec->dev);
+		da7218->pdata = dev_get_platdata(component->dev);
 
-	da7218_handle_pdata(codec);
+	da7218_handle_pdata(component);
 
 	/* Check if MCLK provided, if not the clock is NULL */
-	da7218->mclk = devm_clk_get(codec->dev, "mclk");
+	da7218->mclk = devm_clk_get(component->dev, "mclk");
 	if (IS_ERR(da7218->mclk)) {
 		if (PTR_ERR(da7218->mclk) != -ENOENT) {
 			ret = PTR_ERR(da7218->mclk);
@@ -2908,74 +2908,74 @@ static int da7218_probe(struct snd_soc_codec *codec)
 	}
 
 	/* Default PC to free-running */
-	snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+	snd_soc_component_write(component, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
 
 	/*
 	 * Default Output Filter mixers to off otherwise DAPM will power
 	 * Mic to HP passthrough paths by default at startup.
 	 */
-	snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1L, 0);
-	snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1R, 0);
+	snd_soc_component_write(component, DA7218_DROUTING_OUTFILT_1L, 0);
+	snd_soc_component_write(component, DA7218_DROUTING_OUTFILT_1R, 0);
 
 	/* Default CP to normal load, power mode */
-	snd_soc_update_bits(codec, DA7218_CP_CTRL,
+	snd_soc_component_update_bits(component, DA7218_CP_CTRL,
 			    DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0);
 
 	/* Default gain ramping */
-	snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+	snd_soc_component_update_bits(component, DA7218_MIXIN_1_CTRL,
 			    DA7218_MIXIN_1_AMP_RAMP_EN_MASK,
 			    DA7218_MIXIN_1_AMP_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+	snd_soc_component_update_bits(component, DA7218_MIXIN_2_CTRL,
 			    DA7218_MIXIN_2_AMP_RAMP_EN_MASK,
 			    DA7218_MIXIN_2_AMP_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_1L_FILTER_CTRL,
 			    DA7218_IN_1L_RAMP_EN_MASK,
 			    DA7218_IN_1L_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_1R_FILTER_CTRL,
 			    DA7218_IN_1R_RAMP_EN_MASK,
 			    DA7218_IN_1R_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_2L_FILTER_CTRL,
 			    DA7218_IN_2L_RAMP_EN_MASK,
 			    DA7218_IN_2L_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_IN_2R_FILTER_CTRL,
 			    DA7218_IN_2R_RAMP_EN_MASK,
 			    DA7218_IN_2R_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_DGS_GAIN_CTRL,
+	snd_soc_component_update_bits(component, DA7218_DGS_GAIN_CTRL,
 			    DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_OUT_1L_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_OUT_1L_FILTER_CTRL,
 			    DA7218_OUT_1L_RAMP_EN_MASK,
 			    DA7218_OUT_1L_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_OUT_1R_FILTER_CTRL,
+	snd_soc_component_update_bits(component, DA7218_OUT_1R_FILTER_CTRL,
 			    DA7218_OUT_1R_RAMP_EN_MASK,
 			    DA7218_OUT_1R_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7218_HP_L_CTRL,
 			    DA7218_HP_L_AMP_RAMP_EN_MASK,
 			    DA7218_HP_L_AMP_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7218_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7218_HP_R_CTRL,
 			    DA7218_HP_R_AMP_RAMP_EN_MASK,
 			    DA7218_HP_R_AMP_RAMP_EN_MASK);
 
 	/* Default infinite tone gen, start/stop by Kcontrol */
-	snd_soc_write(codec, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK);
+	snd_soc_component_write(component, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK);
 
 	/* DA7217 specific config */
 	if (da7218->dev_id == DA7217_DEV_ID) {
-		snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+		snd_soc_component_update_bits(component, DA7218_HP_DIFF_CTRL,
 				    DA7218_HP_AMP_DIFF_MODE_EN_MASK,
 				    DA7218_HP_AMP_DIFF_MODE_EN_MASK);
 
 		/* Only DA7218 supports HP detect, mask off for DA7217 */
-		snd_soc_write(codec, DA7218_EVENT_MASK,
+		snd_soc_component_write(component, DA7218_EVENT_MASK,
 			      DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK);
 	}
 
 	if (da7218->irq) {
-		ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL,
+		ret = devm_request_threaded_irq(component->dev, da7218->irq, NULL,
 						da7218_irq_thread,
 						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-						"da7218", codec);
+						"da7218", component);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+			dev_err(component->dev, "Failed to request IRQ %d: %d\n",
 				da7218->irq, ret);
 			goto err_disable_reg;
 		}
@@ -2990,39 +2990,37 @@ static int da7218_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int da7218_remove(struct snd_soc_codec *codec)
+static void da7218_remove(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 
 	regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int da7218_suspend(struct snd_soc_codec *codec)
+static int da7218_suspend(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 
-	da7218_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	da7218_set_bias_level(component, SND_SOC_BIAS_OFF);
 
 	/* Put device into standby mode if jack detection disabled */
 	if (!da7218->jack)
-		snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, 0);
+		snd_soc_component_write(component, DA7218_SYSTEM_ACTIVE, 0);
 
 	return 0;
 }
 
-static int da7218_resume(struct snd_soc_codec *codec)
+static int da7218_resume(struct snd_soc_component *component)
 {
-	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
 
 	/* Put device into active mode if previously moved to standby */
 	if (!da7218->jack)
-		snd_soc_write(codec, DA7218_SYSTEM_ACTIVE,
+		snd_soc_component_write(component, DA7218_SYSTEM_ACTIVE,
 			      DA7218_SYSTEM_ACTIVE_MASK);
 
-	da7218_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	da7218_set_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	return 0;
 }
@@ -3031,21 +3029,22 @@ static int da7218_resume(struct snd_soc_codec *codec)
 #define da7218_resume NULL
 #endif
 
-static const struct snd_soc_codec_driver soc_codec_dev_da7218 = {
+static const struct snd_soc_component_driver soc_component_dev_da7218 = {
 	.probe			= da7218_probe,
 	.remove			= da7218_remove,
 	.suspend		= da7218_suspend,
 	.resume			= da7218_resume,
 	.set_bias_level		= da7218_set_bias_level,
-
-	.component_driver = {
-		.controls		= da7218_snd_controls,
-		.num_controls		= ARRAY_SIZE(da7218_snd_controls),
-		.dapm_widgets		= da7218_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
-		.dapm_routes		= da7218_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
-	},
+	.controls		= da7218_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7218_snd_controls),
+	.dapm_widgets		= da7218_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
+	.dapm_routes		= da7218_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 
@@ -3295,21 +3294,15 @@ static int da7218_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_da7218, &da7218_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da7218, &da7218_dai, 1);
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register da7218 codec: %d\n",
+		dev_err(&i2c->dev, "Failed to register da7218 component: %d\n",
 			ret);
 	}
 	return ret;
 }
 
-static int da7218_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id da7218_i2c_id[] = {
 	{ "da7217", DA7217_DEV_ID },
 	{ "da7218", DA7218_DEV_ID },
@@ -3323,7 +3316,6 @@ static struct i2c_driver da7218_i2c_driver = {
 		.of_match_table = of_match_ptr(da7218_of_match),
 	},
 	.probe		= da7218_i2c_probe,
-	.remove		= da7218_i2c_remove,
 	.id_table	= da7218_i2c_id,
 };
 
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
index 4f7ec21069a4..19e6cee2e42e 100644
--- a/sound/soc/codecs/da7218.h
+++ b/sound/soc/codecs/da7218.h
@@ -1410,6 +1410,6 @@ struct da7218_priv {
 };
 
 /* HP detect control */
-int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+int da7218_hpldet(struct snd_soc_component *component, struct snd_soc_jack *jack);
 
 #endif /* _DA7218_H */
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index 1d1d10dd92ae..a49ab751a036 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -32,9 +32,9 @@
  * Detection control
  */
 
-void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
 	da7219->aad->jack = jack;
 	da7219->aad->jack_inserted = false;
@@ -43,7 +43,7 @@ void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 	snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);
 
 	/* Enable/Disable jack detection */
-	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 			    DA7219_ACCDET_EN_MASK,
 			    (jack ? DA7219_ACCDET_EN_MASK : 0));
 }
@@ -57,17 +57,17 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
 {
 	struct da7219_aad_priv *da7219_aad =
 		container_of(work, struct da7219_aad_priv, btn_det_work);
-	struct snd_soc_codec *codec = da7219_aad->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = da7219_aad->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	u8 statusa, micbias_ctrl;
 	bool micbias_up = false;
 	int retries = 0;
 
 	/* Drive headphones/lineout */
-	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 			    DA7219_HP_L_AMP_OE_MASK,
 			    DA7219_HP_L_AMP_OE_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 			    DA7219_HP_R_AMP_OE_MASK,
 			    DA7219_HP_R_AMP_OE_MASK);
 
@@ -76,7 +76,7 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
 	snd_soc_dapm_sync(dapm);
 
 	do {
-		statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
+		statusa = snd_soc_component_read32(component, DA7219_ACCDET_STATUS_A);
 		if (statusa & DA7219_MICBIAS_UP_STS_MASK)
 			micbias_up = true;
 		else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)
@@ -84,7 +84,7 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
 	} while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));
 
 	if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
-		dev_warn(codec->dev, "Mic bias status check timed out");
+		dev_warn(component->dev, "Mic bias status check timed out");
 
 	/*
 	 * Mic bias pulse required to enable mic, must be done before enabling
@@ -92,16 +92,16 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
 	 */
 	if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {
 		/* Pulse higher level voltage */
-		micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
-		snd_soc_update_bits(codec, DA7219_MICBIAS_CTRL,
+		micbias_ctrl = snd_soc_component_read32(component, DA7219_MICBIAS_CTRL);
+		snd_soc_component_update_bits(component, DA7219_MICBIAS_CTRL,
 				    DA7219_MICBIAS1_LEVEL_MASK,
 				    da7219_aad->micbias_pulse_lvl);
 		msleep(da7219_aad->micbias_pulse_time);
-		snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_ctrl);
+		snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_ctrl);
 
 	}
 
-	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 			    DA7219_BUTTON_CONFIG_MASK,
 			    da7219_aad->btn_cfg);
 }
@@ -110,9 +110,9 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 {
 	struct da7219_aad_priv *da7219_aad =
 		container_of(work, struct da7219_aad_priv, hptest_work);
-	struct snd_soc_codec *codec = da7219_aad->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = da7219_aad->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
 	u16 tonegen_freq_hptest;
 	u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
@@ -127,7 +127,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 	if (da7219->mclk) {
 		ret = clk_prepare_enable(da7219->mclk);
 		if (ret) {
-			dev_err(codec->dev, "Failed to enable mclk - %d\n", ret);
+			dev_err(component->dev, "Failed to enable mclk - %d\n", ret);
 			mutex_unlock(&da7219->pll_lock);
 			mutex_unlock(&da7219->ctrl_lock);
 			snd_soc_dapm_mutex_unlock(dapm);
@@ -142,90 +142,90 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 	 * If MCLK is present, but PLL is not enabled then we enable it here to
 	 * ensure a consistent detection procedure.
 	 */
-	pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS);
+	pll_srm_sts = snd_soc_component_read32(component, DA7219_PLL_SRM_STS);
 	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {
 		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
 
-		pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL);
+		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
 		if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)
-			da7219_set_pll(codec, DA7219_SYSCLK_PLL,
+			da7219_set_pll(component, DA7219_SYSCLK_PLL,
 				       DA7219_PLL_FREQ_OUT_98304);
 	} else {
 		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
 	}
 
 	/* Ensure gain ramping at fastest rate */
-	gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
-	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
+	gain_ramp_ctrl = snd_soc_component_read32(component, DA7219_GAIN_RAMP_CTRL);
+	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
 
 	/* Bypass cache so it saves current settings */
 	regcache_cache_bypass(da7219->regmap, true);
 
 	/* Make sure Tone Generator is disabled */
-	snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
+	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
 
 	/* Enable HPTest block, 1KOhms check */
-	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
 			    DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
 			    DA7219_HPTEST_EN_MASK |
 			    DA7219_HPTEST_RES_SEL_1KOHMS);
 
 	/* Set gains to 0db */
-	snd_soc_write(codec, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
-	snd_soc_write(codec, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
-	snd_soc_write(codec, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
-	snd_soc_write(codec, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
 
 	/* Disable DAC filters, EQs and soft mute */
-	snd_soc_update_bits(codec, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
+	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
 			    0);
-	snd_soc_update_bits(codec, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
+	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
 			    0);
-	snd_soc_update_bits(codec, DA7219_DAC_FILTERS5,
+	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS5,
 			    DA7219_DAC_SOFTMUTE_EN_MASK, 0);
 
 	/* Enable HP left & right paths */
-	snd_soc_update_bits(codec, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
 			    DA7219_CP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_DIG_ROUTING_DAC,
+	snd_soc_component_update_bits(component, DA7219_DIG_ROUTING_DAC,
 			    DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
 			    DA7219_DAC_L_SRC_TONEGEN |
 			    DA7219_DAC_R_SRC_TONEGEN);
-	snd_soc_update_bits(codec, DA7219_DAC_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL,
 			    DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
 			    DA7219_DAC_L_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_DAC_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL,
 			    DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
 			    DA7219_DAC_R_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_MIXOUT_L_SELECT,
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_SELECT,
 			    DA7219_MIXOUT_L_MIX_SELECT_MASK,
 			    DA7219_MIXOUT_L_MIX_SELECT_MASK);
-	snd_soc_update_bits(codec, DA7219_MIXOUT_R_SELECT,
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_SELECT,
 			    DA7219_MIXOUT_R_MIX_SELECT_MASK,
 			    DA7219_MIXOUT_R_MIX_SELECT_MASK);
-	snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1L,
+	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1L,
 			    DA7219_OUTFILT_ST_1L_SRC_MASK,
 			    DA7219_DMIX_ST_SRC_OUTFILT1L);
-	snd_soc_update_bits(codec, DA7219_DROUTING_ST_OUTFILT_1R,
+	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1R,
 			    DA7219_OUTFILT_ST_1R_SRC_MASK,
 			    DA7219_DMIX_ST_SRC_OUTFILT1R);
-	snd_soc_update_bits(codec, DA7219_MIXOUT_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_CTRL,
 			    DA7219_MIXOUT_L_AMP_EN_MASK,
 			    DA7219_MIXOUT_L_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_CTRL,
 			    DA7219_MIXOUT_R_AMP_EN_MASK,
 			    DA7219_MIXOUT_R_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
 			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
 			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
 	msleep(DA7219_SETTLING_DELAY);
-	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 			    DA7219_HP_L_AMP_MUTE_EN_MASK |
 			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
-	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 			    DA7219_HP_R_AMP_MUTE_EN_MASK |
 			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
 
@@ -237,26 +237,26 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
 
 	/* Configure & start Tone Generator */
-	snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
+	snd_soc_component_write(component, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
 	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
 			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
-	snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2,
+	snd_soc_component_update_bits(component, DA7219_TONE_GEN_CFG2,
 			    DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
 			    DA7219_SWG_SEL_SRAMP |
 			    DA7219_TONE_GEN_GAIN_MINUS_15DB);
-	snd_soc_write(codec, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
+	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
 
 	msleep(DA7219_AAD_HPTEST_PERIOD);
 
 	/* Grab comparator reading */
-	accdet_cfg8 = snd_soc_read(codec, DA7219_ACCDET_CONFIG_8);
+	accdet_cfg8 = snd_soc_component_read32(component, DA7219_ACCDET_CONFIG_8);
 	if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
 		report |= SND_JACK_HEADPHONE;
 	else
 		report |= SND_JACK_LINEOUT;
 
 	/* Stop tone generator */
-	snd_soc_write(codec, DA7219_TONE_GEN_CFG1, 0);
+	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
 
 	msleep(DA7219_AAD_HPTEST_PERIOD);
 
@@ -294,7 +294,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 	regcache_cache_bypass(da7219->regmap, false);
 
 	/* Disable HPTest block */
-	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8,
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
 			    DA7219_HPTEST_EN_MASK, 0);
 
 	/*
@@ -305,18 +305,18 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
 
 	/* Restore gain ramping rate */
-	snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
+	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
 
 	/* Drive Headphones/lineout */
-	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
 			    DA7219_HP_L_AMP_OE_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
 			    DA7219_HP_R_AMP_OE_MASK);
 
 	/* Restore PLL to previous configuration, if re-configured */
 	if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&
 	    ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))
-		da7219_set_pll(codec, DA7219_SYSCLK_MCLK, 0);
+		da7219_set_pll(component, DA7219_SYSCLK_MCLK, 0);
 
 	/* Remove MCLK, if previously enabled */
 	if (da7219->mclk)
@@ -343,9 +343,9 @@ static void da7219_aad_hptest_work(struct work_struct *work)
 static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
 {
 	struct da7219_aad_priv *da7219_aad = data;
-	struct snd_soc_codec *codec = da7219_aad->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = da7219_aad->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	u8 events[DA7219_AAD_IRQ_REG_MAX];
 	u8 statusa;
 	int i, report = 0, mask = 0;
@@ -358,13 +358,13 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
 		return IRQ_NONE;
 
 	/* Read status register for jack insertion & type status */
-	statusa = snd_soc_read(codec, DA7219_ACCDET_STATUS_A);
+	statusa = snd_soc_component_read32(component, DA7219_ACCDET_STATUS_A);
 
 	/* Clear events */
 	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
 			  events, DA7219_AAD_IRQ_REG_MAX);
 
-	dev_dbg(codec->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
+	dev_dbg(component->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
 		events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
 		statusa);
 
@@ -430,13 +430,13 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
 			da7219_aad->jack_inserted = false;
 
 			/* Un-drive headphones/lineout */
-			snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+			snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 					    DA7219_HP_R_AMP_OE_MASK, 0);
-			snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+			snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 					    DA7219_HP_L_AMP_OE_MASK, 0);
 
 			/* Ensure button detection disabled */
-			snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+			snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 					    DA7219_BUTTON_CONFIG_MASK, 0);
 
 			/* Disable mic bias */
@@ -459,7 +459,7 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
  */
 
 static enum da7219_aad_micbias_pulse_lvl
-	da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 2800:
@@ -467,13 +467,13 @@ static enum da7219_aad_micbias_pulse_lvl
 	case 2900:
 		return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
 	default:
-		dev_warn(codec->dev, "Invalid micbias pulse level");
+		dev_warn(component->dev, "Invalid micbias pulse level");
 		return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
 	}
 }
 
 static enum da7219_aad_btn_cfg
-	da7219_aad_fw_btn_cfg(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_btn_cfg(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 2:
@@ -491,13 +491,13 @@ static enum da7219_aad_btn_cfg
 	case 500:
 		return DA7219_AAD_BTN_CFG_500MS;
 	default:
-		dev_warn(codec->dev, "Invalid button config");
+		dev_warn(component->dev, "Invalid button config");
 		return DA7219_AAD_BTN_CFG_10MS;
 	}
 }
 
 static enum da7219_aad_mic_det_thr
-	da7219_aad_fw_mic_det_thr(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_mic_det_thr(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 200:
@@ -509,13 +509,13 @@ static enum da7219_aad_mic_det_thr
 	case 1000:
 		return DA7219_AAD_MIC_DET_THR_1000_OHMS;
 	default:
-		dev_warn(codec->dev, "Invalid mic detect threshold");
+		dev_warn(component->dev, "Invalid mic detect threshold");
 		return DA7219_AAD_MIC_DET_THR_500_OHMS;
 	}
 }
 
 static enum da7219_aad_jack_ins_deb
-	da7219_aad_fw_jack_ins_deb(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_jack_ins_deb(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 5:
@@ -535,13 +535,13 @@ static enum da7219_aad_jack_ins_deb
 	case 1000:
 		return DA7219_AAD_JACK_INS_DEB_1S;
 	default:
-		dev_warn(codec->dev, "Invalid jack insert debounce");
+		dev_warn(component->dev, "Invalid jack insert debounce");
 		return DA7219_AAD_JACK_INS_DEB_20MS;
 	}
 }
 
 static enum da7219_aad_jack_det_rate
-	da7219_aad_fw_jack_det_rate(struct snd_soc_codec *codec, const char *str)
+	da7219_aad_fw_jack_det_rate(struct snd_soc_component *component, const char *str)
 {
 	if (!strcmp(str, "32ms_64ms")) {
 		return DA7219_AAD_JACK_DET_RATE_32_64MS;
@@ -552,13 +552,13 @@ static enum da7219_aad_jack_det_rate
 	} else if (!strcmp(str, "256ms_512ms")) {
 		return DA7219_AAD_JACK_DET_RATE_256_512MS;
 	} else {
-		dev_warn(codec->dev, "Invalid jack detect rate");
+		dev_warn(component->dev, "Invalid jack detect rate");
 		return DA7219_AAD_JACK_DET_RATE_256_512MS;
 	}
 }
 
 static enum da7219_aad_jack_rem_deb
-	da7219_aad_fw_jack_rem_deb(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_jack_rem_deb(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1:
@@ -570,13 +570,13 @@ static enum da7219_aad_jack_rem_deb
 	case 20:
 		return DA7219_AAD_JACK_REM_DEB_20MS;
 	default:
-		dev_warn(codec->dev, "Invalid jack removal debounce");
+		dev_warn(component->dev, "Invalid jack removal debounce");
 		return DA7219_AAD_JACK_REM_DEB_1MS;
 	}
 }
 
 static enum da7219_aad_btn_avg
-	da7219_aad_fw_btn_avg(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_btn_avg(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1:
@@ -588,13 +588,13 @@ static enum da7219_aad_btn_avg
 	case 8:
 		return DA7219_AAD_BTN_AVG_8;
 	default:
-		dev_warn(codec->dev, "Invalid button average value");
+		dev_warn(component->dev, "Invalid button average value");
 		return DA7219_AAD_BTN_AVG_2;
 	}
 }
 
 static enum da7219_aad_adc_1bit_rpt
-	da7219_aad_fw_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val)
+	da7219_aad_fw_adc_1bit_rpt(struct snd_soc_component *component, u32 val)
 {
 	switch (val) {
 	case 1:
@@ -606,14 +606,14 @@ static enum da7219_aad_adc_1bit_rpt
 	case 8:
 		return DA7219_AAD_ADC_1BIT_RPT_8;
 	default:
-		dev_warn(codec->dev, "Invalid ADC 1-bit repeat value");
+		dev_warn(component->dev, "Invalid ADC 1-bit repeat value");
 		return DA7219_AAD_ADC_1BIT_RPT_1;
 	}
 }
 
-static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *codec)
+static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_component *component)
 {
-	struct device *dev = codec->dev;
+	struct device *dev = component->dev;
 	struct i2c_client *i2c = to_i2c_client(dev);
 	struct fwnode_handle *aad_np;
 	struct da7219_aad_pdata *aad_pdata;
@@ -624,7 +624,7 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *cod
 	if (!aad_np)
 		return NULL;
 
-	aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL);
+	aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);
 	if (!aad_pdata)
 		return NULL;
 
@@ -633,7 +633,7 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *cod
 	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
 				     &fw_val32) >= 0)
 		aad_pdata->micbias_pulse_lvl =
-			da7219_aad_fw_micbias_pulse_lvl(codec, fw_val32);
+			da7219_aad_fw_micbias_pulse_lvl(component, fw_val32);
 	else
 		aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
 
@@ -642,31 +642,31 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *cod
 		aad_pdata->micbias_pulse_time = fw_val32;
 
 	if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)
-		aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(codec, fw_val32);
+		aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(component, fw_val32);
 	else
 		aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
 
 	if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)
 		aad_pdata->mic_det_thr =
-			da7219_aad_fw_mic_det_thr(codec, fw_val32);
+			da7219_aad_fw_mic_det_thr(component, fw_val32);
 	else
 		aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
 
 	if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
 		aad_pdata->jack_ins_deb =
-			da7219_aad_fw_jack_ins_deb(codec, fw_val32);
+			da7219_aad_fw_jack_ins_deb(component, fw_val32);
 	else
 		aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
 
 	if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
 		aad_pdata->jack_det_rate =
-			da7219_aad_fw_jack_det_rate(codec, fw_str);
+			da7219_aad_fw_jack_det_rate(component, fw_str);
 	else
 		aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
 
 	if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)
 		aad_pdata->jack_rem_deb =
-			da7219_aad_fw_jack_rem_deb(codec, fw_val32);
+			da7219_aad_fw_jack_rem_deb(component, fw_val32);
 	else
 		aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
 
@@ -691,22 +691,22 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *cod
 		aad_pdata->c_mic_btn_thr = 0x3E;
 
 	if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)
-		aad_pdata->btn_avg = da7219_aad_fw_btn_avg(codec, fw_val32);
+		aad_pdata->btn_avg = da7219_aad_fw_btn_avg(component, fw_val32);
 	else
 		aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
 
 	if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)
 		aad_pdata->adc_1bit_rpt =
-			da7219_aad_fw_adc_1bit_rpt(codec, fw_val32);
+			da7219_aad_fw_adc_1bit_rpt(component, fw_val32);
 	else
 		aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
 
 	return aad_pdata;
 }
 
-static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
+static void da7219_aad_handle_pdata(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct da7219_aad_priv *da7219_aad = da7219->aad;
 	struct da7219_pdata *pdata = da7219->pdata;
 
@@ -752,7 +752,7 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
 				DA7219_MIC_DET_THRESH_SHIFT);
 			mask |= DA7219_MIC_DET_THRESH_MASK;
 		}
-		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, mask, cfg);
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, mask, cfg);
 
 		cfg = 0;
 		mask = 0;
@@ -787,15 +787,15 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
 				DA7219_JACKDET_REM_DEB_SHIFT);
 			mask |= DA7219_JACKDET_REM_DEB_MASK;
 		}
-		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_2, mask, cfg);
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_2, mask, cfg);
 
-		snd_soc_write(codec, DA7219_ACCDET_CONFIG_3,
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_3,
 			      aad_pdata->a_d_btn_thr);
-		snd_soc_write(codec, DA7219_ACCDET_CONFIG_4,
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_4,
 			      aad_pdata->d_b_btn_thr);
-		snd_soc_write(codec, DA7219_ACCDET_CONFIG_5,
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_5,
 			      aad_pdata->b_c_btn_thr);
-		snd_soc_write(codec, DA7219_ACCDET_CONFIG_6,
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_6,
 			      aad_pdata->c_mic_btn_thr);
 
 		cfg = 0;
@@ -818,7 +818,7 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
 			       DA7219_ADC_1_BIT_REPEAT_SHIFT);
 			mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
 		}
-		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_7, mask, cfg);
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg);
 	}
 }
 
@@ -827,16 +827,16 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec)
  * Suspend/Resume
  */
 
-void da7219_aad_suspend(struct snd_soc_codec *codec)
+void da7219_aad_suspend(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct da7219_aad_priv *da7219_aad = da7219->aad;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	u8 micbias_ctrl;
 
 	if (da7219_aad->jack) {
 		/* Disable jack detection during suspend */
-		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 				    DA7219_ACCDET_EN_MASK, 0);
 
 		/*
@@ -846,7 +846,7 @@ void da7219_aad_suspend(struct snd_soc_codec *codec)
 		 * suspend then this will be dealt with through the IRQ handler.
 		 */
 		if (da7219_aad->jack_inserted) {
-			micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL);
+			micbias_ctrl = snd_soc_component_read32(component, DA7219_MICBIAS_CTRL);
 			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
 				snd_soc_dapm_disable_pin(dapm, "Mic Bias");
 				snd_soc_dapm_sync(dapm);
@@ -856,11 +856,11 @@ void da7219_aad_suspend(struct snd_soc_codec *codec)
 	}
 }
 
-void da7219_aad_resume(struct snd_soc_codec *codec)
+void da7219_aad_resume(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct da7219_aad_priv *da7219_aad = da7219->aad;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (da7219_aad->jack) {
 		/* Re-enable micbias if previously enabled for 4-pole jack */
@@ -872,7 +872,7 @@ void da7219_aad_resume(struct snd_soc_codec *codec)
 		}
 
 		/* Re-enable jack detection */
-		snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 				    DA7219_ACCDET_EN_MASK,
 				    DA7219_ACCDET_EN_MASK);
 	}
@@ -883,28 +883,28 @@ void da7219_aad_resume(struct snd_soc_codec *codec)
  * Init/Exit
  */
 
-int da7219_aad_init(struct snd_soc_codec *codec)
+int da7219_aad_init(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct da7219_aad_priv *da7219_aad;
 	u8 mask[DA7219_AAD_IRQ_REG_MAX];
 	int ret;
 
-	da7219_aad = devm_kzalloc(codec->dev, sizeof(*da7219_aad), GFP_KERNEL);
+	da7219_aad = devm_kzalloc(component->dev, sizeof(*da7219_aad), GFP_KERNEL);
 	if (!da7219_aad)
 		return -ENOMEM;
 
 	da7219->aad = da7219_aad;
-	da7219_aad->codec = codec;
+	da7219_aad->component = component;
 
 	/* Handle any DT/ACPI/platform data */
 	if (da7219->pdata && !da7219->pdata->aad_pdata)
-		da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(codec);
+		da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(component);
 
-	da7219_aad_handle_pdata(codec);
+	da7219_aad_handle_pdata(component);
 
 	/* Disable button detection */
-	snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1,
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
 			    DA7219_BUTTON_CONFIG_MASK, 0);
 
 	INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
@@ -915,7 +915,7 @@ int da7219_aad_init(struct snd_soc_codec *codec)
 				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 				   "da7219-aad", da7219_aad);
 	if (ret) {
-		dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+		dev_err(component->dev, "Failed to request IRQ: %d\n", ret);
 		return ret;
 	}
 
@@ -928,9 +928,9 @@ int da7219_aad_init(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(da7219_aad_init);
 
-void da7219_aad_exit(struct snd_soc_codec *codec)
+void da7219_aad_exit(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct da7219_aad_priv *da7219_aad = da7219->aad;
 	u8 mask[DA7219_AAD_IRQ_REG_MAX];
 
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
index 117a3d7ccd31..b9c4a27e8e61 100644
--- a/sound/soc/codecs/da7219-aad.h
+++ b/sound/soc/codecs/da7219-aad.h
@@ -189,7 +189,7 @@ enum da7219_aad_event_regs {
 
 /* Private data */
 struct da7219_aad_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	int irq;
 
 	u8 micbias_pulse_lvl;
@@ -206,14 +206,14 @@ struct da7219_aad_priv {
 };
 
 /* AAD control */
-void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack);
 
 /* Suspend/Resume */
-void da7219_aad_suspend(struct snd_soc_codec *codec);
-void da7219_aad_resume(struct snd_soc_codec *codec);
+void da7219_aad_suspend(struct snd_soc_component *component);
+void da7219_aad_resume(struct snd_soc_component *component);
 
 /* Init/Exit */
-int da7219_aad_init(struct snd_soc_codec *codec);
-void da7219_aad_exit(struct snd_soc_codec *codec);
+int da7219_aad_init(struct snd_soc_component *component);
+void da7219_aad_exit(struct snd_soc_component *component);
 
 #endif /* __DA7219_AAD_H */
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 6f088536df32..5e043d082f4b 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -256,8 +256,8 @@ static const struct soc_enum da7219_cp_track_mode =
 static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&da7219->ctrl_lock);
@@ -270,8 +270,8 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
 static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&da7219->ctrl_lock);
@@ -284,8 +284,8 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
 static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&da7219->ctrl_lock);
@@ -298,8 +298,8 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
 static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&da7219->ctrl_lock);
@@ -310,55 +310,55 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
 }
 
 /* ALC */
-static void da7219_alc_calib(struct snd_soc_codec *codec)
+static void da7219_alc_calib(struct snd_soc_component *component)
 {
 	u8 mic_ctrl, mixin_ctrl, adc_ctrl, calib_ctrl;
 
 	/* Save current state of mic control register */
-	mic_ctrl = snd_soc_read(codec, DA7219_MIC_1_CTRL);
+	mic_ctrl = snd_soc_component_read32(component, DA7219_MIC_1_CTRL);
 
 	/* Save current state of input mixer control register */
-	mixin_ctrl = snd_soc_read(codec, DA7219_MIXIN_L_CTRL);
+	mixin_ctrl = snd_soc_component_read32(component, DA7219_MIXIN_L_CTRL);
 
 	/* Save current state of input ADC control register */
-	adc_ctrl = snd_soc_read(codec, DA7219_ADC_L_CTRL);
+	adc_ctrl = snd_soc_component_read32(component, DA7219_ADC_L_CTRL);
 
 	/* Enable then Mute MIC PGAs */
-	snd_soc_update_bits(codec, DA7219_MIC_1_CTRL, DA7219_MIC_1_AMP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7219_MIC_1_CTRL, DA7219_MIC_1_AMP_EN_MASK,
 			    DA7219_MIC_1_AMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_MIC_1_CTRL,
+	snd_soc_component_update_bits(component, DA7219_MIC_1_CTRL,
 			    DA7219_MIC_1_AMP_MUTE_EN_MASK,
 			    DA7219_MIC_1_AMP_MUTE_EN_MASK);
 
 	/* Enable input mixers unmuted */
-	snd_soc_update_bits(codec, DA7219_MIXIN_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_MIXIN_L_CTRL,
 			    DA7219_MIXIN_L_AMP_EN_MASK |
 			    DA7219_MIXIN_L_AMP_MUTE_EN_MASK,
 			    DA7219_MIXIN_L_AMP_EN_MASK);
 
 	/* Enable input filters unmuted */
-	snd_soc_update_bits(codec, DA7219_ADC_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_ADC_L_CTRL,
 			    DA7219_ADC_L_MUTE_EN_MASK | DA7219_ADC_L_EN_MASK,
 			    DA7219_ADC_L_EN_MASK);
 
 	/* Perform auto calibration */
-	snd_soc_update_bits(codec, DA7219_ALC_CTRL1,
+	snd_soc_component_update_bits(component, DA7219_ALC_CTRL1,
 			    DA7219_ALC_AUTO_CALIB_EN_MASK,
 			    DA7219_ALC_AUTO_CALIB_EN_MASK);
 	do {
-		calib_ctrl = snd_soc_read(codec, DA7219_ALC_CTRL1);
+		calib_ctrl = snd_soc_component_read32(component, DA7219_ALC_CTRL1);
 	} while (calib_ctrl & DA7219_ALC_AUTO_CALIB_EN_MASK);
 
 	/* If auto calibration fails, disable DC offset, hybrid ALC */
 	if (calib_ctrl & DA7219_ALC_CALIB_OVERFLOW_MASK) {
-		dev_warn(codec->dev,
+		dev_warn(component->dev,
 			 "ALC auto calibration failed with overflow\n");
-		snd_soc_update_bits(codec, DA7219_ALC_CTRL1,
+		snd_soc_component_update_bits(component, DA7219_ALC_CTRL1,
 				    DA7219_ALC_OFFSET_EN_MASK |
 				    DA7219_ALC_SYNC_MODE_MASK, 0);
 	} else {
 		/* Enable DC offset cancellation, hybrid mode */
-		snd_soc_update_bits(codec, DA7219_ALC_CTRL1,
+		snd_soc_component_update_bits(component, DA7219_ALC_CTRL1,
 				    DA7219_ALC_OFFSET_EN_MASK |
 				    DA7219_ALC_SYNC_MODE_MASK,
 				    DA7219_ALC_OFFSET_EN_MASK |
@@ -366,20 +366,20 @@ static void da7219_alc_calib(struct snd_soc_codec *codec)
 	}
 
 	/* Restore input filter control register to original state */
-	snd_soc_write(codec, DA7219_ADC_L_CTRL, adc_ctrl);
+	snd_soc_component_write(component, DA7219_ADC_L_CTRL, adc_ctrl);
 
 	/* Restore input mixer control registers to original state */
-	snd_soc_write(codec, DA7219_MIXIN_L_CTRL, mixin_ctrl);
+	snd_soc_component_write(component, DA7219_MIXIN_L_CTRL, mixin_ctrl);
 
 	/* Restore MIC control registers to original states */
-	snd_soc_write(codec, DA7219_MIC_1_CTRL, mic_ctrl);
+	snd_soc_component_write(component, DA7219_MIC_1_CTRL, mic_ctrl);
 }
 
 static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
@@ -389,7 +389,7 @@ static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
 	 * make sure calibrated offsets are updated.
 	 */
 	if ((ret == 1) && (da7219->alc_en))
-		da7219_alc_calib(codec);
+		da7219_alc_calib(component);
 
 	return ret;
 }
@@ -397,13 +397,13 @@ static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
 static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
 
 	/* Force ALC offset calibration if enabling ALC */
 	if ((ucontrol->value.integer.value[0]) && (!da7219->alc_en)) {
-		da7219_alc_calib(codec);
+		da7219_alc_calib(component);
 		da7219->alc_en = true;
 	} else {
 		da7219->alc_en = false;
@@ -416,8 +416,8 @@ static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol,
 static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mixer_ctrl =
 		(struct soc_mixer_control *) kcontrol->private_value;
 	unsigned int reg = mixer_ctrl->reg;
@@ -443,8 +443,8 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
 static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mixer_ctrl =
 		(struct soc_mixer_control *) kcontrol->private_value;
 	unsigned int reg = mixer_ctrl->reg;
@@ -769,8 +769,8 @@ static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = {
 static int da7219_dai_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	u8 pll_ctrl, pll_status;
 	int i = 0;
 	bool srm_lock = false;
@@ -779,22 +779,22 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_PRE_PMU:
 		if (da7219->master)
 			/* Enable DAI clks for master mode */
-			snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+			snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
 					    DA7219_DAI_CLK_EN_MASK,
 					    DA7219_DAI_CLK_EN_MASK);
 
 		/* PC synchronised to DAI */
-		snd_soc_update_bits(codec, DA7219_PC_COUNT,
+		snd_soc_component_update_bits(component, DA7219_PC_COUNT,
 				    DA7219_PC_FREERUN_MASK, 0);
 
 		/* Slave mode, if SRM not enabled no need for status checks */
-		pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL);
+		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
 		if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
 			return 0;
 
 		/* Check SRM has locked */
 		do {
-			pll_status = snd_soc_read(codec, DA7219_PLL_SRM_STS);
+			pll_status = snd_soc_component_read32(component, DA7219_PLL_SRM_STS);
 			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
 				srm_lock = true;
 			} else {
@@ -804,18 +804,18 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
 		} while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
 
 		if (!srm_lock)
-			dev_warn(codec->dev, "SRM failed to lock\n");
+			dev_warn(component->dev, "SRM failed to lock\n");
 
 		return 0;
 	case SND_SOC_DAPM_POST_PMD:
 		/* PC free-running */
-		snd_soc_update_bits(codec, DA7219_PC_COUNT,
+		snd_soc_component_update_bits(component, DA7219_PC_COUNT,
 				    DA7219_PC_FREERUN_MASK,
 				    DA7219_PC_FREERUN_MASK);
 
 		/* Disable DAI clks if in master mode */
 		if (da7219->master)
-			snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+			snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
 					    DA7219_DAI_CLK_EN_MASK, 0);
 		return 0;
 	default:
@@ -841,7 +841,7 @@ static int da7219_settling_event(struct snd_soc_dapm_widget *w,
 static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
 			       struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	u8 hp_ctrl, min_gain_mask;
 
 	switch (w->reg) {
@@ -860,7 +860,7 @@ static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Enable minimum gain on HP to avoid pops */
-		snd_soc_update_bits(codec, hp_ctrl, min_gain_mask,
+		snd_soc_component_update_bits(component, hp_ctrl, min_gain_mask,
 				    min_gain_mask);
 
 		msleep(DA7219_MIN_GAIN_DELAY);
@@ -868,7 +868,7 @@ static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		/* Remove minimum gain on HP */
-		snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0);
+		snd_soc_component_update_bits(component, hp_ctrl, min_gain_mask, 0);
 
 		break;
 	}
@@ -879,22 +879,22 @@ static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
 static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Ensure nominal gain ramping for DAPM sequence */
 		da7219->gain_ramp_ctrl =
-			snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
-		snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+			snd_soc_component_read32(component, DA7219_GAIN_RAMP_CTRL);
+		snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL,
 			      DA7219_GAIN_RAMP_RATE_NOMINAL);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_POST_PMD:
 		/* Restore previous gain ramp settings */
-		snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+		snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL,
 			      da7219->gain_ramp_ctrl);
 		break;
 	}
@@ -1116,8 +1116,8 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = {
 static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq))
@@ -1133,12 +1133,12 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 	switch (clk_id) {
 	case DA7219_CLKSRC_MCLK_SQR:
-		snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
 				    DA7219_PLL_MCLK_SQR_EN_MASK,
 				    DA7219_PLL_MCLK_SQR_EN_MASK);
 		break;
 	case DA7219_CLKSRC_MCLK:
-		snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
 				    DA7219_PLL_MCLK_SQR_EN_MASK, 0);
 		break;
 	default:
@@ -1167,9 +1167,9 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
+int da7219_set_pll(struct snd_soc_component *component, int source, unsigned int fout)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
 	u8 pll_ctrl, indiv_bits, indiv;
 	u8 pll_frac_top, pll_frac_bot, pll_integer;
@@ -1178,7 +1178,7 @@ int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
 
 	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
 	if (da7219->mclk_rate < 2000000) {
-		dev_err(codec->dev, "PLL input clock %d below valid range\n",
+		dev_err(component->dev, "PLL input clock %d below valid range\n",
 			da7219->mclk_rate);
 		return -EINVAL;
 	} else if (da7219->mclk_rate <= 4500000) {
@@ -1197,7 +1197,7 @@ int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
 		indiv_bits = DA7219_PLL_INDIV_36_TO_54_MHZ;
 		indiv = DA7219_PLL_INDIV_36_TO_54_MHZ_VAL;
 	} else {
-		dev_err(codec->dev, "PLL input clock %d above valid range\n",
+		dev_err(component->dev, "PLL input clock %d above valid range\n",
 			da7219->mclk_rate);
 		return -EINVAL;
 	}
@@ -1208,7 +1208,7 @@ int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
 	switch (source) {
 	case DA7219_SYSCLK_MCLK:
 		pll_ctrl |= DA7219_PLL_MODE_BYPASS;
-		snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
 				    DA7219_PLL_INDIV_MASK |
 				    DA7219_PLL_MODE_MASK, pll_ctrl);
 		return 0;
@@ -1219,7 +1219,7 @@ int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
 		pll_ctrl |= DA7219_PLL_MODE_SRM;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid PLL config\n");
+		dev_err(component->dev, "Invalid PLL config\n");
 		return -EINVAL;
 	}
 
@@ -1231,10 +1231,10 @@ int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
 	pll_frac_bot = (frac_div) & DA7219_BYTE_MASK;
 
 	/* Write PLL config & dividers */
-	snd_soc_write(codec, DA7219_PLL_FRAC_TOP, pll_frac_top);
-	snd_soc_write(codec, DA7219_PLL_FRAC_BOT, pll_frac_bot);
-	snd_soc_write(codec, DA7219_PLL_INTEGER, pll_integer);
-	snd_soc_update_bits(codec, DA7219_PLL_CTRL,
+	snd_soc_component_write(component, DA7219_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA7219_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA7219_PLL_INTEGER, pll_integer);
+	snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
 			    DA7219_PLL_INDIV_MASK | DA7219_PLL_MODE_MASK,
 			    pll_ctrl);
 
@@ -1244,12 +1244,12 @@ int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout)
 static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&da7219->pll_lock);
-	ret = da7219_set_pll(codec, source, fout);
+	ret = da7219_set_pll(component, source, fout);
 	mutex_unlock(&da7219->pll_lock);
 
 	return ret;
@@ -1257,8 +1257,8 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 
 static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	u8 dai_clk_mode = 0, dai_ctrl = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1335,11 +1335,11 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	/* By default 64 BCLKs per WCLK is supported */
 	dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64;
 
-	snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+	snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
 			    DA7219_DAI_BCLKS_PER_WCLK_MASK |
 			    DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK,
 			    dai_clk_mode);
-	snd_soc_update_bits(codec, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK,
+	snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK,
 			    dai_ctrl);
 
 	return 0;
@@ -1349,18 +1349,18 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				   unsigned int tx_mask, unsigned int rx_mask,
 				   int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	u8 dai_bclks_per_wclk;
 	u16 offset;
 	u32 frame_size;
 
 	/* No channels enabled so disable TDM, revert to 64-bit frames */
 	if (!tx_mask) {
-		snd_soc_update_bits(codec, DA7219_DAI_TDM_CTRL,
+		snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
 				    DA7219_DAI_TDM_CH_EN_MASK |
 				    DA7219_DAI_TDM_MODE_EN_MASK, 0);
-		snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+		snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
 				    DA7219_DAI_BCLKS_PER_WCLK_MASK,
 				    DA7219_DAI_BCLKS_PER_WCLK_64);
 		return 0;
@@ -1368,14 +1368,14 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
 
 	/* Check we have valid slots */
 	if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) {
-		dev_err(codec->dev, "Invalid number of slots, max = %d\n",
+		dev_err(component->dev, "Invalid number of slots, max = %d\n",
 			DA7219_DAI_TDM_MAX_SLOTS);
 		return -EINVAL;
 	}
 
 	/* Check we have a valid offset given */
 	if (rx_mask > DA7219_DAI_OFFSET_MAX) {
-		dev_err(codec->dev, "Invalid slot offset, max = %d\n",
+		dev_err(component->dev, "Invalid slot offset, max = %d\n",
 			DA7219_DAI_OFFSET_MAX);
 		return -EINVAL;
 	}
@@ -1396,11 +1396,11 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
 		dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid frame size %d\n", frame_size);
+		dev_err(component->dev, "Invalid frame size %d\n", frame_size);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE,
+	snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
 			    DA7219_DAI_BCLKS_PER_WCLK_MASK,
 			    dai_bclks_per_wclk);
 
@@ -1408,7 +1408,7 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER,
 			  &offset, sizeof(offset));
 
-	snd_soc_update_bits(codec, DA7219_DAI_TDM_CTRL,
+	snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
 			    DA7219_DAI_TDM_CH_EN_MASK |
 			    DA7219_DAI_TDM_MODE_EN_MASK,
 			    (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) |
@@ -1421,7 +1421,7 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 dai_ctrl = 0, fs;
 	unsigned int channels;
 
@@ -1444,7 +1444,7 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
 
 	channels = params_channels(params);
 	if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Invalid number of channels, only 1 to %d supported\n",
 			DA7219_DAI_CH_NUM_MAX);
 		return -EINVAL;
@@ -1489,11 +1489,11 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, DA7219_DAI_CTRL,
+	snd_soc_component_update_bits(component, DA7219_DAI_CTRL,
 			    DA7219_DAI_WORD_LENGTH_MASK |
 			    DA7219_DAI_CH_NUM_MASK,
 			    dai_ctrl);
-	snd_soc_write(codec, DA7219_SR, fs);
+	snd_soc_component_write(component, DA7219_SR, fs);
 
 	return 0;
 }
@@ -1585,9 +1585,9 @@ static enum da7219_mic_amp_in_sel
 	}
 }
 
-static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec)
+static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_component *component)
 {
-	struct device *dev = codec->dev;
+	struct device *dev = component->dev;
 	struct da7219_pdata *pdata;
 	const char *of_str;
 	u32 of_val32;
@@ -1616,10 +1616,10 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec)
  * Codec driver functions
  */
 
-static int da7219_set_bias_level(struct snd_soc_codec *codec,
+static int da7219_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1627,11 +1627,11 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Enable MCLK for transition to ON state */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
 			if (da7219->mclk) {
 				ret = clk_prepare_enable(da7219->mclk);
 				if (ret) {
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Failed to enable mclk\n");
 					return ret;
 				}
@@ -1640,13 +1640,13 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
 
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			/* Master bias */
-			snd_soc_update_bits(codec, DA7219_REFERENCES,
+			snd_soc_component_update_bits(component, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK,
 					    DA7219_BIAS_EN_MASK);
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
 			/* Remove MCLK */
 			if (da7219->mclk)
 				clk_disable_unprepare(da7219->mclk);
@@ -1655,7 +1655,7 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_OFF:
 		/* Only disable master bias if we're not a wake-up source */
 		if (!da7219->wakeup_source)
-			snd_soc_update_bits(codec, DA7219_REFERENCES,
+			snd_soc_component_update_bits(component, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK, 0);
 
 		break;
@@ -1670,9 +1670,9 @@ static const char *da7219_supply_names[DA7219_NUM_SUPPLIES] = {
 	[DA7219_SUPPLY_VDDIO] = "VDDIO",
 };
 
-static int da7219_handle_supplies(struct snd_soc_codec *codec)
+static int da7219_handle_supplies(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct regulator *vddio;
 	u8 io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V;
 	int i, ret;
@@ -1681,10 +1681,10 @@ static int da7219_handle_supplies(struct snd_soc_codec *codec)
 	for (i = 0; i < DA7219_NUM_SUPPLIES; ++i)
 		da7219->supplies[i].supply = da7219_supply_names[i];
 
-	ret = devm_regulator_bulk_get(codec->dev, DA7219_NUM_SUPPLIES,
+	ret = devm_regulator_bulk_get(component->dev, DA7219_NUM_SUPPLIES,
 				      da7219->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to get supplies");
+		dev_err(component->dev, "Failed to get supplies");
 		return ret;
 	}
 
@@ -1692,29 +1692,29 @@ static int da7219_handle_supplies(struct snd_soc_codec *codec)
 	vddio = da7219->supplies[DA7219_SUPPLY_VDDIO].consumer;
 	ret = regulator_get_voltage(vddio);
 	if (ret < 1200000)
-		dev_warn(codec->dev, "Invalid VDDIO voltage\n");
+		dev_warn(component->dev, "Invalid VDDIO voltage\n");
 	else if (ret < 2800000)
 		io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V;
 
 	/* Enable main supplies */
 	ret = regulator_bulk_enable(DA7219_NUM_SUPPLIES, da7219->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to enable supplies");
+		dev_err(component->dev, "Failed to enable supplies");
 		return ret;
 	}
 
 	/* Ensure device in active mode */
-	snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, DA7219_SYSTEM_ACTIVE_MASK);
+	snd_soc_component_write(component, DA7219_SYSTEM_ACTIVE, DA7219_SYSTEM_ACTIVE_MASK);
 
 	/* Update IO voltage level range */
-	snd_soc_write(codec, DA7219_IO_CTRL, io_voltage_lvl);
+	snd_soc_component_write(component, DA7219_IO_CTRL, io_voltage_lvl);
 
 	return 0;
 }
 
-static void da7219_handle_pdata(struct snd_soc_codec *codec)
+static void da7219_handle_pdata(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct da7219_pdata *pdata = da7219->pdata;
 
 	if (pdata) {
@@ -1735,14 +1735,14 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec)
 			break;
 		}
 
-		snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_lvl);
+		snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_lvl);
 
 		/* Mic */
 		switch (pdata->mic_amp_in_sel) {
 		case DA7219_MIC_AMP_IN_SEL_DIFF:
 		case DA7219_MIC_AMP_IN_SEL_SE_P:
 		case DA7219_MIC_AMP_IN_SEL_SE_N:
-			snd_soc_write(codec, DA7219_MIC_1_SELECT,
+			snd_soc_component_write(component, DA7219_MIC_1_SELECT,
 				      pdata->mic_amp_in_sel);
 			break;
 		}
@@ -1753,9 +1753,9 @@ static struct reg_sequence da7219_rev_aa_patch[] = {
 	{ DA7219_REFERENCES, 0x08 },
 };
 
-static int da7219_probe(struct snd_soc_codec *codec)
+static int da7219_probe(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	unsigned int rev;
 	int ret;
 
@@ -1763,13 +1763,13 @@ static int da7219_probe(struct snd_soc_codec *codec)
 	mutex_init(&da7219->pll_lock);
 
 	/* Regulator configuration */
-	ret = da7219_handle_supplies(codec);
+	ret = da7219_handle_supplies(component);
 	if (ret)
 		return ret;
 
 	ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev);
 	if (ret) {
-		dev_err(codec->dev, "Failed to read chip revision: %d\n", ret);
+		dev_err(component->dev, "Failed to read chip revision: %d\n", ret);
 		goto err_disable_reg;
 	}
 
@@ -1778,7 +1778,7 @@ static int da7219_probe(struct snd_soc_codec *codec)
 		ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch,
 					    ARRAY_SIZE(da7219_rev_aa_patch));
 		if (ret) {
-			dev_err(codec->dev, "Failed to register AA patch: %d\n",
+			dev_err(component->dev, "Failed to register AA patch: %d\n",
 				ret);
 			goto err_disable_reg;
 		}
@@ -1788,14 +1788,14 @@ static int da7219_probe(struct snd_soc_codec *codec)
 	}
 
 	/* Handle DT/ACPI/Platform data */
-	da7219->pdata = dev_get_platdata(codec->dev);
+	da7219->pdata = dev_get_platdata(component->dev);
 	if (!da7219->pdata)
-		da7219->pdata = da7219_fw_to_pdata(codec);
+		da7219->pdata = da7219_fw_to_pdata(component);
 
-	da7219_handle_pdata(codec);
+	da7219_handle_pdata(component);
 
 	/* Check if MCLK provided */
-	da7219->mclk = devm_clk_get(codec->dev, "mclk");
+	da7219->mclk = devm_clk_get(component->dev, "mclk");
 	if (IS_ERR(da7219->mclk)) {
 		if (PTR_ERR(da7219->mclk) != -ENOENT) {
 			ret = PTR_ERR(da7219->mclk);
@@ -1806,39 +1806,39 @@ static int da7219_probe(struct snd_soc_codec *codec)
 	}
 
 	/* Default PC counter to free-running */
-	snd_soc_update_bits(codec, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK,
+	snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK,
 			    DA7219_PC_FREERUN_MASK);
 
 	/* Default gain ramping */
-	snd_soc_update_bits(codec, DA7219_MIXIN_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_MIXIN_L_CTRL,
 			    DA7219_MIXIN_L_AMP_RAMP_EN_MASK,
 			    DA7219_MIXIN_L_AMP_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_ADC_L_CTRL, DA7219_ADC_L_RAMP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7219_ADC_L_CTRL, DA7219_ADC_L_RAMP_EN_MASK,
 			    DA7219_ADC_L_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_DAC_L_CTRL, DA7219_DAC_L_RAMP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL, DA7219_DAC_L_RAMP_EN_MASK,
 			    DA7219_DAC_L_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_DAC_R_CTRL, DA7219_DAC_R_RAMP_EN_MASK,
+	snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL, DA7219_DAC_R_RAMP_EN_MASK,
 			    DA7219_DAC_R_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 			    DA7219_HP_L_AMP_RAMP_EN_MASK,
 			    DA7219_HP_L_AMP_RAMP_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 			    DA7219_HP_R_AMP_RAMP_EN_MASK,
 			    DA7219_HP_R_AMP_RAMP_EN_MASK);
 
 	/* Default minimum gain on HP to avoid pops during DAPM sequencing */
-	snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
 			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK,
 			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK);
-	snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
 			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK,
 			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK);
 
 	/* Default infinite tone gen, start/stop by Kcontrol */
-	snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
+	snd_soc_component_write(component, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
 
 	/* Initialise AAD block */
-	ret = da7219_aad_init(codec);
+	ret = da7219_aad_init(component);
 	if (ret)
 		goto err_disable_reg;
 
@@ -1850,39 +1850,39 @@ static int da7219_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int da7219_remove(struct snd_soc_codec *codec)
+static void da7219_remove(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
-	da7219_aad_exit(codec);
+	da7219_aad_exit(component);
 
 	/* Supplies */
-	return regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+	regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
 }
 
 #ifdef CONFIG_PM
-static int da7219_suspend(struct snd_soc_codec *codec)
+static int da7219_suspend(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
 	/* Suspend AAD if we're not a wake-up source */
 	if (!da7219->wakeup_source)
-		da7219_aad_suspend(codec);
+		da7219_aad_suspend(component);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
 
-static int da7219_resume(struct snd_soc_codec *codec)
+static int da7219_resume(struct snd_soc_component *component)
 {
-	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* Resume AAD if previously suspended */
 	if (!da7219->wakeup_source)
-		da7219_aad_resume(codec);
+		da7219_aad_resume(component);
 
 	return 0;
 }
@@ -1891,21 +1891,22 @@ static int da7219_resume(struct snd_soc_codec *codec)
 #define da7219_resume NULL
 #endif
 
-static const struct snd_soc_codec_driver soc_codec_dev_da7219 = {
+static const struct snd_soc_component_driver soc_component_dev_da7219 = {
 	.probe			= da7219_probe,
 	.remove			= da7219_remove,
 	.suspend		= da7219_suspend,
 	.resume			= da7219_resume,
 	.set_bias_level		= da7219_set_bias_level,
-
-	.component_driver = {
-		.controls		= da7219_snd_controls,
-		.num_controls		= ARRAY_SIZE(da7219_snd_controls),
-		.dapm_widgets		= da7219_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
-		.dapm_routes		= da7219_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
-	},
+	.controls		= da7219_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7219_snd_controls),
+	.dapm_widgets		= da7219_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
+	.dapm_routes		= da7219_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 
@@ -2090,7 +2091,7 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
-	/* Soft reset codec */
+	/* Soft reset component */
 	regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1,
 			  DA7219_ACCDET_EN_MASK, 0);
 	regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL,
@@ -2101,10 +2102,11 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
 
 	regcache_cache_bypass(da7219->regmap, false);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_da7219,
 				     &da7219_dai, 1);
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register da7219 codec: %d\n",
+		dev_err(&i2c->dev, "Failed to register da7219 component: %d\n",
 			ret);
 	}
 	return ret;
@@ -2112,7 +2114,6 @@ static int da7219_i2c_probe(struct i2c_client *i2c,
 
 static int da7219_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index 8d6c3c8c8026..1acb34cd12ad 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -822,6 +822,6 @@ struct da7219_priv {
 	u8 gain_ramp_ctrl;
 };
 
-int da7219_set_pll(struct snd_soc_codec *codec, int source, unsigned int fout);
+int da7219_set_pll(struct snd_soc_component *component, int source, unsigned int fout);
 
 #endif /* __DA7219_H */
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 83db4d23c90b..de275df8f4ee 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -168,7 +168,7 @@ static const struct reg_default da732x_reg_cache[] = {
 	{ DA732X_REG_UNLOCK		, 0x00 },
 };
 
-static inline int da732x_get_input_div(struct snd_soc_codec *codec, int sysclk)
+static inline int da732x_get_input_div(struct snd_soc_component *component, int sysclk)
 {
 	int val;
 	int ret;
@@ -192,28 +192,28 @@ static inline int da732x_get_input_div(struct snd_soc_codec *codec, int sysclk)
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, DA732X_REG_PLL_CTRL, val);
+	snd_soc_component_write(component, DA732X_REG_PLL_CTRL, val);
 
 	return ret;
 }
 
-static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state)
+static void da732x_set_charge_pump(struct snd_soc_component *component, int state)
 {
 	switch (state) {
 	case DA732X_ENABLE_CP:
-		snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN);
-		snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_EN |
+		snd_soc_component_write(component, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN);
+		snd_soc_component_write(component, DA732X_REG_CP_HP2, DA732X_HP_CP_EN |
 			      DA732X_HP_CP_REG | DA732X_HP_CP_PULSESKIP);
-		snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA732X_CP_EN |
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL1, DA732X_CP_EN |
 			      DA732X_CP_CTRL_CPVDD1);
-		snd_soc_write(codec, DA732X_REG_CP_CTRL2,
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL2,
 			      DA732X_CP_MANAGE_MAGNITUDE | DA732X_CP_BOOST);
-		snd_soc_write(codec, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ);
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ);
 		break;
 	case DA732X_DISABLE_CP:
-		snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS);
-		snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS);
-		snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
+		snd_soc_component_write(component, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS);
+		snd_soc_component_write(component, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS);
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
 		break;
 	default:
 		pr_err("Wrong charge pump state\n");
@@ -331,7 +331,7 @@ static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
 static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
 	unsigned int reg = enum_ctrl->reg;
 	unsigned int sel = ucontrol->value.enumerated.item[0];
@@ -351,7 +351,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg, DA732X_HPF_MASK, bits);
+	snd_soc_component_update_bits(component, reg, DA732X_HPF_MASK, bits);
 
 	return 0;
 }
@@ -359,12 +359,12 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
 static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
 	unsigned int reg = enum_ctrl->reg;
 	int val;
 
-	val = snd_soc_read(codec, reg) & DA732X_HPF_MASK;
+	val = snd_soc_component_read32(component, reg) & DA732X_HPF_MASK;
 
 	switch (val) {
 	case DA732X_HPF_VOICE_EN:
@@ -609,18 +609,18 @@ static const struct snd_kcontrol_new da732x_snd_controls[] = {
 static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		switch (w->reg) {
 		case DA732X_REG_ADC1_PD:
-			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
 					    DA732X_ADCA_BB_CLK_EN,
 					    DA732X_ADCA_BB_CLK_EN);
 			break;
 		case DA732X_REG_ADC2_PD:
-			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
 					    DA732X_ADCC_BB_CLK_EN,
 					    DA732X_ADCC_BB_CLK_EN);
 			break;
@@ -628,24 +628,24 @@ static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 			return -EINVAL;
 		}
 
-		snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK,
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_RST_MASK,
 				    DA732X_ADC_SET_ACT);
-		snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK,
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_PD_MASK,
 				    DA732X_ADC_ON);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK,
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_PD_MASK,
 				    DA732X_ADC_OFF);
-		snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK,
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_RST_MASK,
 				    DA732X_ADC_SET_RST);
 
 		switch (w->reg) {
 		case DA732X_REG_ADC1_PD:
-			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
 					    DA732X_ADCA_BB_CLK_EN, 0);
 			break;
 		case DA732X_REG_ADC2_PD:
-			snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
 					    DA732X_ADCC_BB_CLK_EN, 0);
 			break;
 		default:
@@ -663,16 +663,16 @@ static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 static int da732x_out_pga_event(struct snd_soc_dapm_widget *w,
 				struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, w->reg,
+		snd_soc_component_update_bits(component, w->reg,
 				    (1 << w->shift) | DA732X_OUT_HIZ_EN,
 				    (1 << w->shift) | DA732X_OUT_HIZ_EN);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, w->reg,
+		snd_soc_component_update_bits(component, w->reg,
 				    (1 << w->shift) | DA732X_OUT_HIZ_EN,
 				    (1 << w->shift) | DA732X_OUT_HIZ_DIS);
 		break;
@@ -949,7 +949,7 @@ static int da732x_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u32 aif = 0;
 	u32 reg_aif;
 	u32 fs;
@@ -1011,15 +1011,15 @@ static int da732x_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg_aif, DA732X_AIF_WORD_MASK, aif);
-	snd_soc_update_bits(codec, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs);
+	snd_soc_component_update_bits(component, reg_aif, DA732X_AIF_WORD_MASK, aif);
+	snd_soc_component_update_bits(component, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs);
 
 	return 0;
 }
 
 static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u32 aif_mclk, pc_count;
 	u32 reg_aif1, aif1;
 	u32 reg_aif3, aif3;
@@ -1107,29 +1107,29 @@ static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, DA732X_REG_AIF_MCLK, aif_mclk);
-	snd_soc_update_bits(codec, reg_aif1, DA732X_AIF1_CLK_MASK, aif1);
-	snd_soc_update_bits(codec, reg_aif3, DA732X_AIF_BCLK_INV |
+	snd_soc_component_write(component, DA732X_REG_AIF_MCLK, aif_mclk);
+	snd_soc_component_update_bits(component, reg_aif1, DA732X_AIF1_CLK_MASK, aif1);
+	snd_soc_component_update_bits(component, reg_aif3, DA732X_AIF_BCLK_INV |
 			    DA732X_AIF_WCLK_INV | DA732X_AIF_MODE_MASK, aif3);
-	snd_soc_write(codec, DA732X_REG_PC_CTRL, pc_count);
+	snd_soc_component_write(component, DA732X_REG_PC_CTRL, pc_count);
 
 	return 0;
 }
 
 
 
-static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id,
+static int da732x_set_dai_pll(struct snd_soc_component *component, int pll_id,
 			      int source, unsigned int freq_in,
 			      unsigned int freq_out)
 {
-	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+	struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
 	int fref, indiv;
 	u8 div_lo, div_mid, div_hi;
 	u64 frac_div;
 
 	/* Disable PLL */
 	if (freq_out == 0) {
-		snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL,
+		snd_soc_component_update_bits(component, DA732X_REG_PLL_CTRL,
 				    DA732X_PLL_EN, 0);
 		da732x->pll_en = false;
 		return 0;
@@ -1147,17 +1147,17 @@ static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id,
 		case 24576000:
 		case 45160000:
 		case 49152000:
-			snd_soc_write(codec, DA732X_REG_PLL_CTRL,
+			snd_soc_component_write(component, DA732X_REG_PLL_CTRL,
 				      DA732X_PLL_BYPASS);
 			return 0;
 		default:
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Cannot use PLL Bypass, invalid SYSCLK rate\n");
 			return -EINVAL;
 		}
 	}
 
-	indiv = da732x_get_input_div(codec, da732x->sysclk);
+	indiv = da732x_get_input_div(component, da732x->sysclk);
 	if (indiv < 0)
 		return indiv;
 
@@ -1168,11 +1168,11 @@ static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id,
 	div_mid = (frac_div >> DA732X_1BYTE_SHIFT) & DA732X_U8_MASK;
 	div_lo = (frac_div) & DA732X_U8_MASK;
 
-	snd_soc_write(codec, DA732X_REG_PLL_DIV_LO, div_lo);
-	snd_soc_write(codec, DA732X_REG_PLL_DIV_MID, div_mid);
-	snd_soc_write(codec, DA732X_REG_PLL_DIV_HI, div_hi);
+	snd_soc_component_write(component, DA732X_REG_PLL_DIV_LO, div_lo);
+	snd_soc_component_write(component, DA732X_REG_PLL_DIV_MID, div_mid);
+	snd_soc_component_write(component, DA732X_REG_PLL_DIV_HI, div_hi);
 
-	snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, DA732X_PLL_EN,
+	snd_soc_component_update_bits(component, DA732X_REG_PLL_CTRL, DA732X_PLL_EN,
 			    DA732X_PLL_EN);
 
 	da732x->pll_en = true;
@@ -1183,8 +1183,8 @@ static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id,
 static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 				 unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
 
 	da732x->sysclk = freq;
 
@@ -1268,21 +1268,21 @@ static const struct regmap_config da732x_regmap = {
 };
 
 
-static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
+static void da732x_dac_offset_adjust(struct snd_soc_component *component)
 {
 	u8 offset[DA732X_HP_DACS];
 	u8 sign[DA732X_HP_DACS];
 	u8 step = DA732X_DAC_OFFSET_STEP;
 
 	/* Initialize DAC offset calibration circuits and registers */
-	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFFSET,
 		      DA732X_HP_DAC_OFFSET_TRIM_VAL);
-	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFFSET,
 		      DA732X_HP_DAC_OFFSET_TRIM_VAL);
-	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL,
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFF_CNTL,
 		      DA732X_HP_DAC_OFF_CALIBRATION |
 		      DA732X_HP_DAC_OFF_SCALE_STEPS);
-	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL,
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFF_CNTL,
 		      DA732X_HP_DAC_OFF_CALIBRATION |
 		      DA732X_HP_DAC_OFF_SCALE_STEPS);
 
@@ -1290,9 +1290,9 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
 	msleep(DA732X_WAIT_FOR_STABILIZATION);
 
 	/* Check DAC offset sign */
-	sign[DA732X_HPL_DAC] = (snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+	sign[DA732X_HPL_DAC] = (snd_soc_component_read32(component, DA732X_REG_HPL_DAC_OFF_CNTL) &
 				DA732X_HP_DAC_OFF_CNTL_COMPO);
-	sign[DA732X_HPR_DAC] = (snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+	sign[DA732X_HPR_DAC] = (snd_soc_component_read32(component, DA732X_REG_HPR_DAC_OFF_CNTL) &
 				DA732X_HP_DAC_OFF_CNTL_COMPO);
 
 	/* Binary search DAC offset values (both channels at once) */
@@ -1302,17 +1302,17 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
 	do {
 		offset[DA732X_HPL_DAC] |= step;
 		offset[DA732X_HPR_DAC] |= step;
-		snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+		snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFFSET,
 			      ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK);
-		snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+		snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFFSET,
 			      ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK);
 
 		msleep(DA732X_WAIT_FOR_STABILIZATION);
 
-		if ((snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+		if ((snd_soc_component_read32(component, DA732X_REG_HPL_DAC_OFF_CNTL) &
 		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])
 			offset[DA732X_HPL_DAC] &= ~step;
-		if ((snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+		if ((snd_soc_component_read32(component, DA732X_REG_HPR_DAC_OFF_CNTL) &
 		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])
 			offset[DA732X_HPR_DAC] &= ~step;
 
@@ -1320,19 +1320,19 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
 	} while (step);
 
 	/* Write final DAC offsets to registers */
-	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFFSET,
 		      ~offset[DA732X_HPL_DAC] &	DA732X_HP_DAC_OFF_MASK);
-	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFFSET,
 		      ~offset[DA732X_HPR_DAC] &	DA732X_HP_DAC_OFF_MASK);
 
 	/* End DAC calibration mode */
-	snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL,
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFF_CNTL,
 		DA732X_HP_DAC_OFF_SCALE_STEPS);
-	snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL,
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFF_CNTL,
 		DA732X_HP_DAC_OFF_SCALE_STEPS);
 }
 
-static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
+static void da732x_output_offset_adjust(struct snd_soc_component *component)
 {
 	u8 offset[DA732X_HP_AMPS];
 	u8 sign[DA732X_HP_AMPS];
@@ -1342,26 +1342,26 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
 	offset[DA732X_HPR_AMP] = DA732X_HP_OUT_TRIM_VAL;
 
 	/* Initialize output offset calibration circuits and registers  */
-	snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
-	snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
-	snd_soc_write(codec, DA732X_REG_HPL,
+	snd_soc_component_write(component, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+	snd_soc_component_write(component, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+	snd_soc_component_write(component, DA732X_REG_HPL,
 		      DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
-	snd_soc_write(codec, DA732X_REG_HPR,
+	snd_soc_component_write(component, DA732X_REG_HPR,
 		      DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
 
 	/* Wait for voltage stabilization */
 	msleep(DA732X_WAIT_FOR_STABILIZATION);
 
 	/* Check output offset sign */
-	sign[DA732X_HPL_AMP] = snd_soc_read(codec, DA732X_REG_HPL) &
+	sign[DA732X_HPL_AMP] = snd_soc_component_read32(component, DA732X_REG_HPL) &
 			       DA732X_HP_OUT_COMPO;
-	sign[DA732X_HPR_AMP] = snd_soc_read(codec, DA732X_REG_HPR) &
+	sign[DA732X_HPR_AMP] = snd_soc_component_read32(component, DA732X_REG_HPR) &
 			       DA732X_HP_OUT_COMPO;
 
-	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
+	snd_soc_component_write(component, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
 		      (sign[DA732X_HPL_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
 		      DA732X_HP_OUT_EN);
-	snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_COMP |
+	snd_soc_component_write(component, DA732X_REG_HPR, DA732X_HP_OUT_COMP |
 		      (sign[DA732X_HPR_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
 		      DA732X_HP_OUT_EN);
 
@@ -1369,17 +1369,17 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
 	do {
 		offset[DA732X_HPL_AMP] |= step;
 		offset[DA732X_HPR_AMP] |= step;
-		snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET,
+		snd_soc_component_write(component, DA732X_REG_HPL_OUT_OFFSET,
 			      offset[DA732X_HPL_AMP]);
-		snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET,
+		snd_soc_component_write(component, DA732X_REG_HPR_OUT_OFFSET,
 			      offset[DA732X_HPR_AMP]);
 
 		msleep(DA732X_WAIT_FOR_STABILIZATION);
 
-		if ((snd_soc_read(codec, DA732X_REG_HPL) &
+		if ((snd_soc_component_read32(component, DA732X_REG_HPL) &
 		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])
 			offset[DA732X_HPL_AMP] &= ~step;
-		if ((snd_soc_read(codec, DA732X_REG_HPR) &
+		if ((snd_soc_component_read32(component, DA732X_REG_HPR) &
 		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])
 			offset[DA732X_HPR_AMP] &= ~step;
 
@@ -1387,80 +1387,80 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
 	} while (step);
 
 	/* Write final DAC offsets to registers */
-	snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]);
-	snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]);
+	snd_soc_component_write(component, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]);
+	snd_soc_component_write(component, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]);
 }
 
-static void da732x_hp_dc_offset_cancellation(struct snd_soc_codec *codec)
+static void da732x_hp_dc_offset_cancellation(struct snd_soc_component *component)
 {
 	/* Make sure that we have Soft Mute enabled */
-	snd_soc_write(codec, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN |
+	snd_soc_component_write(component, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN |
 		      DA732X_GAIN_RAMPED | DA732X_16_SAMPLES);
-	snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACL_EN |
+	snd_soc_component_write(component, DA732X_REG_DAC1_SEL, DA732X_DACL_EN |
 		      DA732X_DACR_EN | DA732X_DACL_SDM | DA732X_DACR_SDM |
 		      DA732X_DACL_MUTE | DA732X_DACR_MUTE);
-	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN |
+	snd_soc_component_write(component, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN |
 		      DA732X_HP_OUT_MUTE | DA732X_HP_OUT_EN);
-	snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_EN |
+	snd_soc_component_write(component, DA732X_REG_HPR, DA732X_HP_OUT_EN |
 		      DA732X_HP_OUT_MUTE | DA732X_HP_OUT_DAC_EN);
 
-	da732x_dac_offset_adjust(codec);
-	da732x_output_offset_adjust(codec);
+	da732x_dac_offset_adjust(component);
+	da732x_output_offset_adjust(component);
 
-	snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS);
-	snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_DIS);
-	snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_DIS);
+	snd_soc_component_write(component, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS);
+	snd_soc_component_write(component, DA732X_REG_HPL, DA732X_HP_DIS);
+	snd_soc_component_write(component, DA732X_REG_HPR, DA732X_HP_DIS);
 }
 
-static int da732x_set_bias_level(struct snd_soc_codec *codec,
+static int da732x_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+	struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
+		snd_soc_component_update_bits(component, DA732X_REG_BIAS_EN,
 				    DA732X_BIAS_BOOST_MASK,
 				    DA732X_BIAS_BOOST_100PC);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Init Codec */
-			snd_soc_write(codec, DA732X_REG_REF1,
+			snd_soc_component_write(component, DA732X_REG_REF1,
 				      DA732X_VMID_FASTCHG);
-			snd_soc_write(codec, DA732X_REG_BIAS_EN,
+			snd_soc_component_write(component, DA732X_REG_BIAS_EN,
 				      DA732X_BIAS_EN);
 
 			mdelay(DA732X_STARTUP_DELAY);
 
 			/* Disable Fast Charge and enable DAC ref voltage */
-			snd_soc_write(codec, DA732X_REG_REF1,
+			snd_soc_component_write(component, DA732X_REG_REF1,
 				      DA732X_REFBUFX2_EN);
 
 			/* Enable bypass DSP routing */
-			snd_soc_write(codec, DA732X_REG_DATA_ROUTE,
+			snd_soc_component_write(component, DA732X_REG_DATA_ROUTE,
 				      DA732X_BYPASS_DSP);
 
 			/* Enable Digital subsystem */
-			snd_soc_write(codec, DA732X_REG_DSP_CTRL,
+			snd_soc_component_write(component, DA732X_REG_DSP_CTRL,
 				      DA732X_DIGITAL_EN);
 
-			snd_soc_write(codec, DA732X_REG_SPARE1_OUT,
+			snd_soc_component_write(component, DA732X_REG_SPARE1_OUT,
 				      DA732X_HP_DRIVER_EN |
 				      DA732X_HP_GATE_LOW |
 				      DA732X_HP_LOOP_GAIN_CTRL);
-			snd_soc_write(codec, DA732X_REG_HP_LIN1_GNDSEL,
+			snd_soc_component_write(component, DA732X_REG_HP_LIN1_GNDSEL,
 				      DA732X_HP_OUT_GNDSEL);
 
-			da732x_set_charge_pump(codec, DA732X_ENABLE_CP);
+			da732x_set_charge_pump(component, DA732X_ENABLE_CP);
 
-			snd_soc_write(codec, DA732X_REG_CLK_EN1,
+			snd_soc_component_write(component, DA732X_REG_CLK_EN1,
 			      DA732X_SYS3_CLK_EN | DA732X_PC_CLK_EN);
 
 			/* Enable Zero Crossing */
-			snd_soc_write(codec, DA732X_REG_INP_ZC_EN,
+			snd_soc_component_write(component, DA732X_REG_INP_ZC_EN,
 				      DA732X_MIC1_PRE_ZC_EN |
 				      DA732X_MIC1_ZC_EN |
 				      DA732X_MIC2_PRE_ZC_EN |
@@ -1469,28 +1469,28 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 				      DA732X_AUXR_ZC_EN |
 				      DA732X_MIC3_PRE_ZC_EN |
 				      DA732X_MIC3_ZC_EN);
-			snd_soc_write(codec, DA732X_REG_OUT_ZC_EN,
+			snd_soc_component_write(component, DA732X_REG_OUT_ZC_EN,
 				      DA732X_HPL_ZC_EN | DA732X_HPR_ZC_EN |
 				      DA732X_LIN2_ZC_EN | DA732X_LIN3_ZC_EN |
 				      DA732X_LIN4_ZC_EN);
 
-			da732x_hp_dc_offset_cancellation(codec);
+			da732x_hp_dc_offset_cancellation(component);
 
 			regcache_cache_only(da732x->regmap, false);
 			regcache_sync(da732x->regmap);
 		} else {
-			snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
+			snd_soc_component_update_bits(component, DA732X_REG_BIAS_EN,
 					    DA732X_BIAS_BOOST_MASK,
 					    DA732X_BIAS_BOOST_50PC);
-			snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL,
+			snd_soc_component_update_bits(component, DA732X_REG_PLL_CTRL,
 					    DA732X_PLL_EN, 0);
 			da732x->pll_en = false;
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		regcache_cache_only(da732x->regmap, true);
-		da732x_set_charge_pump(codec, DA732X_DISABLE_CP);
-		snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
+		da732x_set_charge_pump(component, DA732X_DISABLE_CP);
+		snd_soc_component_update_bits(component, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
 				    DA732X_BIAS_DIS);
 		da732x->pll_en = false;
 		break;
@@ -1499,17 +1499,19 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_da732x = {
+static const struct snd_soc_component_driver soc_component_dev_da732x = {
 	.set_bias_level		= da732x_set_bias_level,
-	.component_driver = {
-		.controls		= da732x_snd_controls,
-		.num_controls		= ARRAY_SIZE(da732x_snd_controls),
-		.dapm_widgets		= da732x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
-		.dapm_routes		= da732x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
-	},
+	.controls		= da732x_snd_controls,
+	.num_controls		= ARRAY_SIZE(da732x_snd_controls),
+	.dapm_widgets		= da732x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
+	.dapm_routes		= da732x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
 	.set_pll		= da732x_set_dai_pll,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int da732x_i2c_probe(struct i2c_client *i2c,
@@ -1543,10 +1545,11 @@ static int da732x_i2c_probe(struct i2c_client *i2c,
 		 (reg & DA732X_ID_MAJOR_MASK) >> 4,
 		 (reg & DA732X_ID_MINOR_MASK));
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_da732x,
 				     da732x_dai, ARRAY_SIZE(da732x_dai));
 	if (ret != 0)
-		dev_err(&i2c->dev, "Failed to register codec.\n");
+		dev_err(&i2c->dev, "Failed to register component.\n");
 
 err:
 	return ret;
@@ -1554,8 +1557,6 @@ static int da732x_i2c_probe(struct i2c_client *i2c,
 
 static int da732x_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index bd7faaee5802..afdf90c78884 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -451,7 +451,7 @@ static const char * const da9055_hold_time_txt[] = {
 static SOC_ENUM_SINGLE_DECL(da9055_hold_time,
 			    DA9055_ALC_CTRL3, 0, da9055_hold_time_txt);
 
-static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
+static int da9055_get_alc_data(struct snd_soc_component *component, u8 reg_val)
 {
 	int mid_data, top_data;
 	int sum = 0;
@@ -460,17 +460,17 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
 	for (iteration = 0; iteration < DA9055_ALC_AVG_ITERATIONS;
 	     iteration++) {
 		/* Select the left or right channel and capture data */
-		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL, reg_val);
+		snd_soc_component_write(component, DA9055_ALC_CIC_OP_LVL_CTRL, reg_val);
 
 		/* Select middle 8 bits for read back from data register */
-		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL,
+		snd_soc_component_write(component, DA9055_ALC_CIC_OP_LVL_CTRL,
 			      reg_val | DA9055_ALC_DATA_MIDDLE);
-		mid_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA);
+		mid_data = snd_soc_component_read32(component, DA9055_ALC_CIC_OP_LVL_DATA);
 
 		/* Select top 8 bits for read back from data register */
-		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL,
+		snd_soc_component_write(component, DA9055_ALC_CIC_OP_LVL_CTRL,
 			      reg_val | DA9055_ALC_DATA_TOP);
-		top_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA);
+		top_data = snd_soc_component_read32(component, DA9055_ALC_CIC_OP_LVL_DATA);
 
 		sum += ((mid_data << 8) | (top_data << 16));
 	}
@@ -481,7 +481,7 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
 static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	u8 reg_val, adc_left, adc_right, mic_left, mic_right;
 	int avg_left_data, avg_right_data, offset_l, offset_r;
 
@@ -492,31 +492,31 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
 		 */
 
 		/* Save current values from Mic control registers */
-		mic_left = snd_soc_read(codec, DA9055_MIC_L_CTRL);
-		mic_right = snd_soc_read(codec, DA9055_MIC_R_CTRL);
+		mic_left = snd_soc_component_read32(component, DA9055_MIC_L_CTRL);
+		mic_right = snd_soc_component_read32(component, DA9055_MIC_R_CTRL);
 
 		/* Mute Mic PGA Left and Right */
-		snd_soc_update_bits(codec, DA9055_MIC_L_CTRL,
+		snd_soc_component_update_bits(component, DA9055_MIC_L_CTRL,
 				    DA9055_MIC_L_MUTE_EN, DA9055_MIC_L_MUTE_EN);
-		snd_soc_update_bits(codec, DA9055_MIC_R_CTRL,
+		snd_soc_component_update_bits(component, DA9055_MIC_R_CTRL,
 				    DA9055_MIC_R_MUTE_EN, DA9055_MIC_R_MUTE_EN);
 
 		/* Save current values from ADC control registers */
-		adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL);
-		adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL);
+		adc_left = snd_soc_component_read32(component, DA9055_ADC_L_CTRL);
+		adc_right = snd_soc_component_read32(component, DA9055_ADC_R_CTRL);
 
 		/* Enable ADC Left and Right */
-		snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
+		snd_soc_component_update_bits(component, DA9055_ADC_L_CTRL,
 				    DA9055_ADC_L_EN, DA9055_ADC_L_EN);
-		snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
+		snd_soc_component_update_bits(component, DA9055_ADC_R_CTRL,
 				    DA9055_ADC_R_EN, DA9055_ADC_R_EN);
 
 		/* Calculate average for Left and Right data */
 		/* Left Data */
-		avg_left_data = da9055_get_alc_data(codec,
+		avg_left_data = da9055_get_alc_data(component,
 				DA9055_ALC_CIC_OP_CHANNEL_LEFT);
 		/* Right Data */
-		avg_right_data = da9055_get_alc_data(codec,
+		avg_right_data = da9055_get_alc_data(component,
 				 DA9055_ALC_CIC_OP_CHANNEL_RIGHT);
 
 		/* Calculate DC offset */
@@ -524,22 +524,22 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
 		offset_r = -avg_right_data;
 
 		reg_val = (offset_l & DA9055_ALC_OFFSET_15_8) >> 8;
-		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_L, reg_val);
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2M_L, reg_val);
 		reg_val = (offset_l & DA9055_ALC_OFFSET_17_16) >> 16;
-		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_L, reg_val);
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2U_L, reg_val);
 
 		reg_val = (offset_r & DA9055_ALC_OFFSET_15_8) >> 8;
-		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_R, reg_val);
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2M_R, reg_val);
 		reg_val = (offset_r & DA9055_ALC_OFFSET_17_16) >> 16;
-		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_R, reg_val);
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2U_R, reg_val);
 
 		/* Restore original values of ADC control registers */
-		snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left);
-		snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right);
+		snd_soc_component_write(component, DA9055_ADC_L_CTRL, adc_left);
+		snd_soc_component_write(component, DA9055_ADC_R_CTRL, adc_right);
 
 		/* Restore original values of Mic control registers */
-		snd_soc_write(codec, DA9055_MIC_L_CTRL, mic_left);
-		snd_soc_write(codec, DA9055_MIC_R_CTRL, mic_right);
+		snd_soc_component_write(component, DA9055_MIC_L_CTRL, mic_left);
+		snd_soc_component_write(component, DA9055_MIC_R_CTRL, mic_right);
 	}
 
 	return snd_soc_put_volsw(kcontrol, ucontrol);
@@ -1052,8 +1052,8 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
 	u8 aif_ctrl, fs;
 	u32 sysclk;
 
@@ -1075,7 +1075,7 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* Set AIF format */
-	snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_WORD_LENGTH_MASK,
+	snd_soc_component_update_bits(component, DA9055_AIF_CTRL, DA9055_AIF_WORD_LENGTH_MASK,
 			    aif_ctrl);
 
 	switch (params_rate(params)) {
@@ -1125,7 +1125,7 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
 
 	if (da9055->mclk_rate) {
 		/* PLL Mode, Write actual FS */
-		snd_soc_write(codec, DA9055_SR, fs);
+		snd_soc_component_write(component, DA9055_SR, fs);
 	} else {
 		/*
 		 * Non-PLL Mode
@@ -1134,24 +1134,24 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
 		 * to derive its sys clk. As sys clk has to be 256 * Fs, we
 		 * need to write constant sample rate i.e. 48KHz.
 		 */
-		snd_soc_write(codec, DA9055_SR, DA9055_SR_48000);
+		snd_soc_component_write(component, DA9055_SR, DA9055_SR_48000);
 	}
 
 	if (da9055->mclk_rate && (da9055->mclk_rate != sysclk)) {
 		/* PLL Mode */
 		if (!da9055->master) {
 			/* PLL slave mode, enable PLL and also SRM */
-			snd_soc_update_bits(codec, DA9055_PLL_CTRL,
+			snd_soc_component_update_bits(component, DA9055_PLL_CTRL,
 					    DA9055_PLL_EN | DA9055_PLL_SRM_EN,
 					    DA9055_PLL_EN | DA9055_PLL_SRM_EN);
 		} else {
 			/* PLL master mode, only enable PLL */
-			snd_soc_update_bits(codec, DA9055_PLL_CTRL,
+			snd_soc_component_update_bits(component, DA9055_PLL_CTRL,
 					    DA9055_PLL_EN, DA9055_PLL_EN);
 		}
 	} else {
 		/* Non PLL Mode, disable PLL */
-		snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+		snd_soc_component_update_bits(component, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
 	}
 
 	return 0;
@@ -1160,8 +1160,8 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
 /* Set DAI mode and Format */
 static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
 	u8 aif_clk_mode, aif_ctrl, mode;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1180,7 +1180,7 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	}
 
 	/* Don't allow change of mode if PLL is enabled */
-	if ((snd_soc_read(codec, DA9055_PLL_CTRL) & DA9055_PLL_EN) &&
+	if ((snd_soc_component_read32(component, DA9055_PLL_CTRL) & DA9055_PLL_EN) &&
 	    (da9055->master != mode))
 		return -EINVAL;
 
@@ -1207,27 +1207,27 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	/* By default only 32 BCLK per WCLK is supported */
 	aif_clk_mode |= DA9055_AIF_BCLKS_PER_WCLK_32;
 
-	snd_soc_update_bits(codec, DA9055_AIF_CLK_MODE,
+	snd_soc_component_update_bits(component, DA9055_AIF_CLK_MODE,
 			    (DA9055_AIF_CLK_MODE_MASK | DA9055_AIF_BCLK_MASK),
 			    aif_clk_mode);
-	snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_FORMAT_MASK,
+	snd_soc_component_update_bits(component, DA9055_AIF_CTRL, DA9055_AIF_FORMAT_MASK,
 			    aif_ctrl);
 	return 0;
 }
 
 static int da9055_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute) {
-		snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+		snd_soc_component_update_bits(component, DA9055_DAC_L_CTRL,
 				    DA9055_DAC_L_MUTE_EN, DA9055_DAC_L_MUTE_EN);
-		snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+		snd_soc_component_update_bits(component, DA9055_DAC_R_CTRL,
 				    DA9055_DAC_R_MUTE_EN, DA9055_DAC_R_MUTE_EN);
 	} else {
-		snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+		snd_soc_component_update_bits(component, DA9055_DAC_L_CTRL,
 				    DA9055_DAC_L_MUTE_EN, 0);
-		snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+		snd_soc_component_update_bits(component, DA9055_DAC_R_CTRL,
 				    DA9055_DAC_R_MUTE_EN, 0);
 	}
 
@@ -1240,8 +1240,8 @@ static int da9055_mute(struct snd_soc_dai *dai, int mute)
 static int da9055_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case DA9055_CLKSRC_MCLK:
@@ -1283,13 +1283,13 @@ static int da9055_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int fref, unsigned int fout)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
 
 	u8 pll_frac_top, pll_frac_bot, pll_integer, cnt;
 
 	/* Disable PLL before setting the divisors */
-	snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+	snd_soc_component_update_bits(component, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
 
 	/* In slave mode, there is only one set of divisors */
 	if (!da9055->master && (fout != 2822400))
@@ -1312,9 +1312,9 @@ static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		goto pll_err;
 
 	/* Write PLL dividers */
-	snd_soc_write(codec, DA9055_PLL_FRAC_TOP, pll_frac_top);
-	snd_soc_write(codec, DA9055_PLL_FRAC_BOT, pll_frac_bot);
-	snd_soc_write(codec, DA9055_PLL_INTEGER, pll_integer);
+	snd_soc_component_write(component, DA9055_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA9055_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA9055_PLL_INTEGER, pll_integer);
 
 	return 0;
 pll_err:
@@ -1353,7 +1353,7 @@ static struct snd_soc_dai_driver da9055_dai = {
 	.symmetric_rates = 1,
 };
 
-static int da9055_set_bias_level(struct snd_soc_codec *codec,
+static int da9055_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -1361,48 +1361,48 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Enable VMID reference & master bias */
-			snd_soc_update_bits(codec, DA9055_REFERENCES,
+			snd_soc_component_update_bits(component, DA9055_REFERENCES,
 					    DA9055_VMID_EN | DA9055_BIAS_EN,
 					    DA9055_VMID_EN | DA9055_BIAS_EN);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* Disable VMID reference & master bias */
-		snd_soc_update_bits(codec, DA9055_REFERENCES,
+		snd_soc_component_update_bits(component, DA9055_REFERENCES,
 				    DA9055_VMID_EN | DA9055_BIAS_EN, 0);
 		break;
 	}
 	return 0;
 }
 
-static int da9055_probe(struct snd_soc_codec *codec)
+static int da9055_probe(struct snd_soc_component *component)
 {
-	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
 
 	/* Enable all Gain Ramps */
-	snd_soc_update_bits(codec, DA9055_AUX_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_AUX_L_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_AUX_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_AUX_R_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_MIXIN_L_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_MIXIN_R_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_ADC_L_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_ADC_R_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_DAC_L_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_DAC_R_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_HP_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_HP_L_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_HP_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_HP_R_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
-	snd_soc_update_bits(codec, DA9055_LINE_CTRL,
+	snd_soc_component_update_bits(component, DA9055_LINE_CTRL,
 			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
 
 	/*
@@ -1412,28 +1412,28 @@ static int da9055_probe(struct snd_soc_codec *codec)
 	 * being managed by DAPM while other (non power related) bits are
 	 * enabled here
 	 */
-	snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_MIXIN_L_CTRL,
 			    DA9055_MIXIN_L_MIX_EN, DA9055_MIXIN_L_MIX_EN);
-	snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_MIXIN_R_CTRL,
 			    DA9055_MIXIN_R_MIX_EN, DA9055_MIXIN_R_MIX_EN);
 
-	snd_soc_update_bits(codec, DA9055_MIXOUT_L_CTRL,
+	snd_soc_component_update_bits(component, DA9055_MIXOUT_L_CTRL,
 			    DA9055_MIXOUT_L_MIX_EN, DA9055_MIXOUT_L_MIX_EN);
-	snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL,
+	snd_soc_component_update_bits(component, DA9055_MIXOUT_R_CTRL,
 			    DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN);
 
 	/* Set this as per your system configuration */
-	snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ);
+	snd_soc_component_write(component, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ);
 
 	/* Set platform data values */
 	if (da9055->pdata) {
 		/* set mic bias source */
 		if (da9055->pdata->micbias_source) {
-			snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT,
+			snd_soc_component_update_bits(component, DA9055_MIXIN_R_SELECT,
 					    DA9055_MICBIAS2_EN,
 					    DA9055_MICBIAS2_EN);
 		} else {
-			snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT,
+			snd_soc_component_update_bits(component, DA9055_MIXIN_R_SELECT,
 					    DA9055_MICBIAS2_EN, 0);
 		}
 		/* set mic bias voltage */
@@ -1442,7 +1442,7 @@ static int da9055_probe(struct snd_soc_codec *codec)
 		case DA9055_MICBIAS_2_1V:
 		case DA9055_MICBIAS_1_8V:
 		case DA9055_MICBIAS_1_6V:
-			snd_soc_update_bits(codec, DA9055_MIC_CONFIG,
+			snd_soc_component_update_bits(component, DA9055_MIC_CONFIG,
 					    DA9055_MICBIAS_LEVEL_MASK,
 					    (da9055->pdata->micbias) << 4);
 			break;
@@ -1451,18 +1451,19 @@ static int da9055_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_da9055 = {
+static const struct snd_soc_component_driver soc_component_dev_da9055 = {
 	.probe			= da9055_probe,
 	.set_bias_level		= da9055_set_bias_level,
-
-	.component_driver = {
-		.controls		= da9055_snd_controls,
-		.num_controls		= ARRAY_SIZE(da9055_snd_controls),
-		.dapm_widgets		= da9055_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
-		.dapm_routes		= da9055_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
-	},
+	.controls		= da9055_snd_controls,
+	.num_controls		= ARRAY_SIZE(da9055_snd_controls),
+	.dapm_widgets		= da9055_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
+	.dapm_routes		= da9055_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config da9055_regmap_config = {
@@ -1499,21 +1500,15 @@ static int da9055_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_da9055, &da9055_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da9055, &da9055_dai, 1);
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register da9055 codec: %d\n",
+		dev_err(&i2c->dev, "Failed to register da9055 component: %d\n",
 			ret);
 	}
 	return ret;
 }
 
-static int da9055_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 /*
  * DO NOT change the device Ids. The naming is intentionally specific as both
  * the CODEC and PMIC parts of this chip are instantiated separately as I2C
@@ -1540,7 +1535,6 @@ static struct i2c_driver da9055_i2c_driver = {
 		.of_match_table = of_match_ptr(da9055_of_match),
 	},
 	.probe		= da9055_i2c_probe,
-	.remove		= da9055_remove,
 	.id_table	= da9055_i2c_id,
 };
 
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index cf83c423394d..bac5bbb2dd59 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -19,6 +19,7 @@
  *
  */
 
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
@@ -29,34 +30,33 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-static int dmic_daiops_trigger(struct snd_pcm_substream *substream,
-		int cmd, struct snd_soc_dai *dai)
-{
-	struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai);
+struct dmic {
+	struct gpio_desc *gpio_en;
+	int wakeup_delay;
+};
+
+static int dmic_aif_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event) {
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct dmic *dmic = snd_soc_codec_get_drvdata(codec);
 
-	if (!dmic_en)
-		return 0;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (dmic->gpio_en)
+			gpiod_set_value(dmic->gpio_en, 1);
 
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		gpiod_set_value(dmic_en, 1);
+		if (dmic->wakeup_delay)
+			msleep(dmic->wakeup_delay);
 		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		gpiod_set_value(dmic_en, 0);
+	case SND_SOC_DAPM_POST_PMD:
+		if (dmic->gpio_en)
+			gpiod_set_value(dmic->gpio_en, 0);
 		break;
 	}
 
 	return 0;
 }
 
-static const struct snd_soc_dai_ops dmic_dai_ops = {
-	.trigger	= dmic_daiops_trigger,
-};
-
 static struct snd_soc_dai_driver dmic_dai = {
 	.name = "dmic-hifi",
 	.capture = {
@@ -68,26 +68,33 @@ static struct snd_soc_dai_driver dmic_dai = {
 			| SNDRV_PCM_FMTBIT_S24_LE
 			| SNDRV_PCM_FMTBIT_S16_LE,
 	},
-	.ops    = &dmic_dai_ops,
 };
 
-static int dmic_codec_probe(struct snd_soc_codec *codec)
+static int dmic_component_probe(struct snd_soc_component *component)
 {
-	struct gpio_desc *dmic_en;
+	struct dmic *dmic;
+
+	dmic = devm_kzalloc(component->dev, sizeof(*dmic), GFP_KERNEL);
+	if (!dmic)
+		return -ENOMEM;
 
-	dmic_en = devm_gpiod_get_optional(codec->dev,
-					"dmicen", GPIOD_OUT_LOW);
-	if (IS_ERR(dmic_en))
-		return PTR_ERR(dmic_en);
+	dmic->gpio_en = devm_gpiod_get_optional(component->dev,
+						"dmicen", GPIOD_OUT_LOW);
+	if (IS_ERR(dmic->gpio_en))
+		return PTR_ERR(dmic->gpio_en);
 
-	snd_soc_codec_set_drvdata(codec, dmic_en);
+	device_property_read_u32(component->dev, "wakeup-delay-ms",
+				 &dmic->wakeup_delay);
+
+	snd_soc_component_set_drvdata(component, dmic);
 
 	return 0;
 }
 
 static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
-	SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
-			     SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT_E("DMIC AIF", "Capture", 0,
+			       SND_SOC_NOPM, 0, 0, dmic_aif_event,
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_INPUT("DMic"),
 };
 
@@ -95,14 +102,16 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"DMIC AIF", NULL, "DMic"},
 };
 
-static const struct snd_soc_codec_driver soc_dmic = {
-	.probe = dmic_codec_probe,
-	.component_driver = {
-		.dapm_widgets		= dmic_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(dmic_dapm_widgets),
-		.dapm_routes		= intercon,
-		.num_dapm_routes	= ARRAY_SIZE(intercon),
-	},
+static const struct snd_soc_component_driver soc_dmic = {
+	.probe			= dmic_component_probe,
+	.dapm_widgets		= dmic_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dmic_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int dmic_dev_probe(struct platform_device *pdev)
@@ -129,16 +138,10 @@ static int dmic_dev_probe(struct platform_device *pdev)
 		}
 	}
 
-	return snd_soc_register_codec(&pdev->dev,
+	return devm_snd_soc_register_component(&pdev->dev,
 			&soc_dmic, dai_drv, 1);
 }
 
-static int dmic_dev_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 MODULE_ALIAS("platform:dmic-codec");
 
 static const struct of_device_id dmic_dev_match[] = {
@@ -152,7 +155,6 @@ static struct platform_driver dmic_driver = {
 		.of_match_table = dmic_dev_match,
 	},
 	.probe = dmic_dev_probe,
-	.remove = dmic_dev_remove,
 };
 
 module_platform_driver(dmic_driver);
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
index 3869025754d8..58515bb1a303 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -69,28 +69,24 @@ static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
 	{ "AOUTR", NULL, "DAC" },
 };
 
-static const struct snd_soc_codec_driver es7134_codec_driver = {
-	.component_driver = {
-		.dapm_widgets		= es7134_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(es7134_dapm_widgets),
-		.dapm_routes		= es7134_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(es7134_dapm_routes),
-	},
+static const struct snd_soc_component_driver es7134_component_driver = {
+	.dapm_widgets		= es7134_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es7134_dapm_widgets),
+	.dapm_routes		= es7134_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es7134_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int es7134_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-				      &es7134_codec_driver,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &es7134_component_driver,
 				      &es7134_dai, 1);
 }
 
-static int es7134_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id es7134_ids[] = {
 	{ .compatible = "everest,es7134", },
@@ -106,7 +102,6 @@ static struct platform_driver es7134_driver = {
 		.of_match_table = of_match_ptr(es7134_ids),
 	},
 	.probe = es7134_probe,
-	.remove = es7134_remove,
 };
 
 module_platform_driver(es7134_driver);
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index da2d353af5ba..e97d12d578b0 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -356,8 +356,8 @@ static const struct snd_soc_dapm_route es8316_dapm_routes[] = {
 static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 	int i;
 	int count = 0;
 
@@ -385,19 +385,19 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 serdata1 = 0;
 	u8 serdata2 = 0;
 	u8 clksw;
 	u8 mask;
 
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_err(codec->dev, "Codec driver only supports slave mode\n");
+		dev_err(component->dev, "Codec driver only supports slave mode\n");
 		return -EINVAL;
 	}
 
 	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
-		dev_err(codec->dev, "Codec driver only supports I2S format\n");
+		dev_err(component->dev, "Codec driver only supports I2S format\n");
 		return -EINVAL;
 	}
 
@@ -420,15 +420,15 @@ static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 
 	mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV;
-	snd_soc_update_bits(codec, ES8316_SERDATA1, mask, serdata1);
+	snd_soc_component_update_bits(component, ES8316_SERDATA1, mask, serdata1);
 
 	mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP;
-	snd_soc_update_bits(codec, ES8316_SERDATA_ADC, mask, serdata2);
-	snd_soc_update_bits(codec, ES8316_SERDATA_DAC, mask, serdata2);
+	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC, mask, serdata2);
+	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC, mask, serdata2);
 
 	/* Enable BCLK and MCLK inputs in slave mode */
 	clksw = ES8316_CLKMGR_CLKSW_MCLK_ON | ES8316_CLKMGR_CLKSW_BCLK_ON;
-	snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW, clksw, clksw);
+	snd_soc_component_update_bits(component, ES8316_CLKMGR_CLKSW, clksw, clksw);
 
 	return 0;
 }
@@ -436,11 +436,11 @@ static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int es8316_pcm_startup(struct snd_pcm_substream *substream,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 
 	if (es8316->sysclk == 0) {
-		dev_err(codec->dev, "No sysclk provided\n");
+		dev_err(component->dev, "No sysclk provided\n");
 		return -EINVAL;
 	}
 
@@ -458,13 +458,12 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
-	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 	u8 wordlen = 0;
 
 	if (!es8316->sysclk) {
-		dev_err(codec->dev, "No MCLK configured\n");
+		dev_err(component->dev, "No MCLK configured\n");
 		return -EINVAL;
 	}
 
@@ -485,16 +484,16 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, ES8316_SERDATA_DAC,
+	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC,
 			    ES8316_SERDATA2_LEN_MASK, wordlen);
-	snd_soc_update_bits(codec, ES8316_SERDATA_ADC,
+	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC,
 			    ES8316_SERDATA2_LEN_MASK, wordlen);
 	return 0;
 }
 
 static int es8316_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, ES8316_DAC_SET1, 0x20,
+	snd_soc_component_update_bits(dai->component, ES8316_DAC_SET1, 0x20,
 			    mute ? 0x20 : 0);
 	return 0;
 }
@@ -530,42 +529,41 @@ static struct snd_soc_dai_driver es8316_dai = {
 	.symmetric_rates = 1,
 };
 
-static int es8316_probe(struct snd_soc_codec *codec)
+static int es8316_probe(struct snd_soc_component *component)
 {
 	/* Reset codec and enable current state machine */
-	snd_soc_write(codec, ES8316_RESET, 0x3f);
+	snd_soc_component_write(component, ES8316_RESET, 0x3f);
 	usleep_range(5000, 5500);
-	snd_soc_write(codec, ES8316_RESET, ES8316_RESET_CSM_ON);
+	snd_soc_component_write(component, ES8316_RESET, ES8316_RESET_CSM_ON);
 	msleep(30);
 
 	/*
 	 * Documentation is unclear, but this value from the vendor driver is
 	 * needed otherwise audio output is silent.
 	 */
-	snd_soc_write(codec, ES8316_SYS_VMIDSEL, 0xff);
+	snd_soc_component_write(component, ES8316_SYS_VMIDSEL, 0xff);
 
 	/*
 	 * Documentation for this register is unclear and incomplete,
 	 * but here is a vendor-provided value that improves volume
 	 * and quality for Intel CHT platforms.
 	 */
-	snd_soc_write(codec, ES8316_CLKMGR_ADCOSR, 0x32);
+	snd_soc_component_write(component, ES8316_CLKMGR_ADCOSR, 0x32);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_es8316 = {
-	.probe		= es8316_probe,
-	.idle_bias_off	= true,
-
-	.component_driver = {
-		.controls		= es8316_snd_controls,
-		.num_controls		= ARRAY_SIZE(es8316_snd_controls),
-		.dapm_widgets		= es8316_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
-		.dapm_routes		= es8316_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_es8316 = {
+	.probe			= es8316_probe,
+	.controls		= es8316_snd_controls,
+	.num_controls		= ARRAY_SIZE(es8316_snd_controls),
+	.dapm_widgets		= es8316_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
+	.dapm_routes		= es8316_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config es8316_regmap = {
@@ -592,16 +590,11 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client,
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
-	return snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_es8316,
+	return devm_snd_soc_register_component(&i2c_client->dev,
+				      &soc_component_dev_es8316,
 				      &es8316_dai, 1);
 }
 
-static int es8316_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id es8316_i2c_id[] = {
 	{"es8316", 0 },
 	{}
@@ -627,7 +620,6 @@ static struct i2c_driver es8316_i2c_driver = {
 		.of_match_table		= of_match_ptr(es8316_of_match),
 	},
 	.probe		= es8316_i2c_probe,
-	.remove		= es8316_i2c_remove,
 	.id_table	= es8316_i2c_id,
 };
 module_i2c_driver(es8316_i2c_driver);
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
index 318ab28c5351..19baa3260f85 100644
--- a/sound/soc/codecs/es8328-i2c.c
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -39,19 +39,12 @@ static int es8328_i2c_probe(struct i2c_client *i2c,
 			devm_regmap_init_i2c(i2c, &es8328_regmap_config));
 }
 
-static int es8328_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
-}
-
 static struct i2c_driver es8328_i2c_driver = {
 	.driver = {
 		.name		= "es8328",
 		.of_match_table = es8328_of_match,
 	},
 	.probe    = es8328_i2c_probe,
-	.remove   = es8328_i2c_remove,
 	.id_table = es8328_id,
 };
 
diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c
index 8fbd935e1c76..d242bd1f7dcc 100644
--- a/sound/soc/codecs/es8328-spi.c
+++ b/sound/soc/codecs/es8328-spi.c
@@ -28,19 +28,12 @@ static int es8328_spi_probe(struct spi_device *spi)
 			devm_regmap_init_spi(spi, &es8328_regmap_config));
 }
 
-static int es8328_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver es8328_spi_driver = {
 	.driver = {
 		.name		= "es8328",
 		.of_match_table	= es8328_of_match,
 	},
 	.probe	= es8328_spi_probe,
-	.remove	= es8328_spi_remove,
 };
 
 module_spi_driver(es8328_spi_driver);
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index bcdb8914ec16..e9fc2fd97d2f 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -116,9 +116,9 @@ static const struct {
 	{ 48000, ES8328_DACCONTROL6_DEEMPH_48k },
 };
 
-static int es8328_set_deemph(struct snd_soc_codec *codec)
+static int es8328_set_deemph(struct snd_soc_component *component)
 {
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 	int val, i, best;
 
 	/*
@@ -138,17 +138,17 @@ static int es8328_set_deemph(struct snd_soc_codec *codec)
 		val = ES8328_DACCONTROL6_DEEMPH_OFF;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
 
-	return snd_soc_update_bits(codec, ES8328_DACCONTROL6,
+	return snd_soc_component_update_bits(component, ES8328_DACCONTROL6,
 			ES8328_DACCONTROL6_DEEMPH_MASK, val);
 }
 
 static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = es8328->deemph;
 	return 0;
@@ -157,15 +157,15 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
 static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 	int ret;
 
 	if (deemph > 1)
 		return -EINVAL;
 
-	ret = es8328_set_deemph(codec);
+	ret = es8328_set_deemph(component);
 	if (ret < 0)
 		return ret;
 
@@ -455,7 +455,7 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
 
 static int es8328_mute(struct snd_soc_dai *dai, int mute)
 {
-	return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3,
+	return snd_soc_component_update_bits(dai->component, ES8328_DACCONTROL3,
 			ES8328_DACCONTROL3_DACMUTE,
 			mute ? ES8328_DACCONTROL3_DACMUTE : 0);
 }
@@ -463,8 +463,8 @@ static int es8328_mute(struct snd_soc_dai *dai, int mute)
 static int es8328_startup(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 
 	if (es8328->master && es8328->sysclk_constraints)
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -478,8 +478,8 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 	int i;
 	int reg;
 	int wl;
@@ -492,7 +492,7 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
 
 	if (es8328->master) {
 		if (!es8328->sysclk_constraints) {
-			dev_err(codec->dev, "No MCLK configured\n");
+			dev_err(component->dev, "No MCLK configured\n");
 			return -EINVAL;
 		}
 
@@ -502,7 +502,7 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
 				break;
 
 		if (i == es8328->sysclk_constraints->count) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"LRCLK %d unsupported with current clock\n",
 				params_rate(params));
 			return -EINVAL;
@@ -513,7 +513,7 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
 		es8328->mclkdiv2 = 0;
 	}
 
-	snd_soc_update_bits(codec, ES8328_MASTERMODE,
+	snd_soc_component_update_bits(component, ES8328_MASTERMODE,
 			ES8328_MASTERMODE_MCLKDIV2,
 			es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0);
 
@@ -538,25 +538,25 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		snd_soc_update_bits(codec, ES8328_DACCONTROL1,
+		snd_soc_component_update_bits(component, ES8328_DACCONTROL1,
 				ES8328_DACCONTROL1_DACWL_MASK,
 				wl << ES8328_DACCONTROL1_DACWL_SHIFT);
 
 		es8328->playback_fs = params_rate(params);
-		es8328_set_deemph(codec);
+		es8328_set_deemph(component);
 	} else
-		snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
+		snd_soc_component_update_bits(component, ES8328_ADCCONTROL4,
 				ES8328_ADCCONTROL4_ADCWL_MASK,
 				wl << ES8328_ADCCONTROL4_ADCWL_SHIFT);
 
-	return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio);
+	return snd_soc_component_update_bits(component, reg, ES8328_RATEMASK, ratio);
 }
 
 static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 	int mclkdiv2 = 0;
 
 	switch (freq) {
@@ -589,22 +589,22 @@ static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
 static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
 	u8 dac_mode = 0;
 	u8 adc_mode = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 		/* Master serial port mode, with BCLK generated automatically */
-		snd_soc_update_bits(codec, ES8328_MASTERMODE,
+		snd_soc_component_update_bits(component, ES8328_MASTERMODE,
 				    ES8328_MASTERMODE_MSC,
 				    ES8328_MASTERMODE_MSC);
 		es8328->master = true;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* Slave serial port mode */
-		snd_soc_update_bits(codec, ES8328_MASTERMODE,
+		snd_soc_component_update_bits(component, ES8328_MASTERMODE,
 				    ES8328_MASTERMODE_MSC, 0);
 		es8328->master = false;
 		break;
@@ -634,15 +634,15 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
 		return -EINVAL;
 
-	snd_soc_update_bits(codec, ES8328_DACCONTROL1,
+	snd_soc_component_update_bits(component, ES8328_DACCONTROL1,
 			ES8328_DACCONTROL1_DACFORMAT_MASK, dac_mode);
-	snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
+	snd_soc_component_update_bits(component, ES8328_ADCCONTROL4,
 			ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode);
 
 	return 0;
 }
 
-static int es8328_set_bias_level(struct snd_soc_codec *codec,
+static int es8328_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -651,8 +651,8 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VREF, VMID=2x50k, digital enabled */
-		snd_soc_write(codec, ES8328_CHIPPOWER, 0);
-		snd_soc_update_bits(codec, ES8328_CONTROL1,
+		snd_soc_component_write(component, ES8328_CHIPPOWER, 0);
+		snd_soc_component_update_bits(component, ES8328_CONTROL1,
 				ES8328_CONTROL1_VMIDSEL_MASK |
 				ES8328_CONTROL1_ENREF,
 				ES8328_CONTROL1_VMIDSEL_50k |
@@ -660,8 +660,8 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_update_bits(codec, ES8328_CONTROL1,
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, ES8328_CONTROL1,
 					ES8328_CONTROL1_VMIDSEL_MASK |
 					ES8328_CONTROL1_ENREF,
 					ES8328_CONTROL1_VMIDSEL_5k |
@@ -671,12 +671,12 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
 			msleep(100);
 		}
 
-		snd_soc_write(codec, ES8328_CONTROL2,
+		snd_soc_component_write(component, ES8328_CONTROL2,
 				ES8328_CONTROL2_OVERCURRENT_ON |
 				ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
 
 		/* VREF, VMID=2*500k, digital stopped */
-		snd_soc_update_bits(codec, ES8328_CONTROL1,
+		snd_soc_component_update_bits(component, ES8328_CONTROL1,
 				ES8328_CONTROL1_VMIDSEL_MASK |
 				ES8328_CONTROL1_ENREF,
 				ES8328_CONTROL1_VMIDSEL_500k |
@@ -684,7 +684,7 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, ES8328_CONTROL1,
+		snd_soc_component_update_bits(component, ES8328_CONTROL1,
 				ES8328_CONTROL1_VMIDSEL_MASK |
 				ES8328_CONTROL1_ENREF,
 				0);
@@ -721,80 +721,80 @@ static struct snd_soc_dai_driver es8328_dai = {
 	.symmetric_rates = 1,
 };
 
-static int es8328_suspend(struct snd_soc_codec *codec)
+static int es8328_suspend(struct snd_soc_component *component)
 {
 	struct es8328_priv *es8328;
 	int ret;
 
-	es8328 = snd_soc_codec_get_drvdata(codec);
+	es8328 = snd_soc_component_get_drvdata(component);
 
 	clk_disable_unprepare(es8328->clk);
 
 	ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
 			es8328->supplies);
 	if (ret) {
-		dev_err(codec->dev, "unable to disable regulators\n");
+		dev_err(component->dev, "unable to disable regulators\n");
 		return ret;
 	}
 	return 0;
 }
 
-static int es8328_resume(struct snd_soc_codec *codec)
+static int es8328_resume(struct snd_soc_component *component)
 {
-	struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
 	struct es8328_priv *es8328;
 	int ret;
 
-	es8328 = snd_soc_codec_get_drvdata(codec);
+	es8328 = snd_soc_component_get_drvdata(component);
 
 	ret = clk_prepare_enable(es8328->clk);
 	if (ret) {
-		dev_err(codec->dev, "unable to enable clock\n");
+		dev_err(component->dev, "unable to enable clock\n");
 		return ret;
 	}
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
 					es8328->supplies);
 	if (ret) {
-		dev_err(codec->dev, "unable to enable regulators\n");
+		dev_err(component->dev, "unable to enable regulators\n");
 		return ret;
 	}
 
 	regcache_mark_dirty(regmap);
 	ret = regcache_sync(regmap);
 	if (ret) {
-		dev_err(codec->dev, "unable to sync regcache\n");
+		dev_err(component->dev, "unable to sync regcache\n");
 		return ret;
 	}
 
 	return 0;
 }
 
-static int es8328_codec_probe(struct snd_soc_codec *codec)
+static int es8328_component_probe(struct snd_soc_component *component)
 {
 	struct es8328_priv *es8328;
 	int ret;
 
-	es8328 = snd_soc_codec_get_drvdata(codec);
+	es8328 = snd_soc_component_get_drvdata(component);
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
 					es8328->supplies);
 	if (ret) {
-		dev_err(codec->dev, "unable to enable regulators\n");
+		dev_err(component->dev, "unable to enable regulators\n");
 		return ret;
 	}
 
 	/* Setup clocks */
-	es8328->clk = devm_clk_get(codec->dev, NULL);
+	es8328->clk = devm_clk_get(component->dev, NULL);
 	if (IS_ERR(es8328->clk)) {
-		dev_err(codec->dev, "codec clock missing or invalid\n");
+		dev_err(component->dev, "codec clock missing or invalid\n");
 		ret = PTR_ERR(es8328->clk);
 		goto clk_fail;
 	}
 
 	ret = clk_prepare_enable(es8328->clk);
 	if (ret) {
-		dev_err(codec->dev, "unable to prepare codec clk\n");
+		dev_err(component->dev, "unable to prepare codec clk\n");
 		goto clk_fail;
 	}
 
@@ -806,19 +806,17 @@ static int es8328_codec_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int es8328_remove(struct snd_soc_codec *codec)
+static void es8328_remove(struct snd_soc_component *component)
 {
 	struct es8328_priv *es8328;
 
-	es8328 = snd_soc_codec_get_drvdata(codec);
+	es8328 = snd_soc_component_get_drvdata(component);
 
 	if (es8328->clk)
 		clk_disable_unprepare(es8328->clk);
 
 	regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
 			       es8328->supplies);
-
-	return 0;
 }
 
 const struct regmap_config es8328_regmap_config = {
@@ -830,22 +828,23 @@ const struct regmap_config es8328_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(es8328_regmap_config);
 
-static const struct snd_soc_codec_driver es8328_codec_driver = {
-	.probe		  = es8328_codec_probe,
-	.suspend	  = es8328_suspend,
-	.resume		  = es8328_resume,
-	.remove		  = es8328_remove,
-	.set_bias_level	  = es8328_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= es8328_snd_controls,
-		.num_controls		= ARRAY_SIZE(es8328_snd_controls),
-		.dapm_widgets		= es8328_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(es8328_dapm_widgets),
-		.dapm_routes		= es8328_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(es8328_dapm_routes),
-	},
+static const struct snd_soc_component_driver es8328_component_driver = {
+	.probe			= es8328_component_probe,
+	.remove			= es8328_remove,
+	.suspend		= es8328_suspend,
+	.resume			= es8328_resume,
+	.set_bias_level		= es8328_set_bias_level,
+	.controls		= es8328_snd_controls,
+	.num_controls		= ARRAY_SIZE(es8328_snd_controls),
+	.dapm_widgets		= es8328_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es8328_dapm_widgets),
+	.dapm_routes		= es8328_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es8328_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 int es8328_probe(struct device *dev, struct regmap *regmap)
@@ -875,8 +874,8 @@ int es8328_probe(struct device *dev, struct regmap *regmap)
 
 	dev_set_drvdata(dev, es8328);
 
-	return snd_soc_register_codec(dev,
-			&es8328_codec_driver, &es8328_dai, 1);
+	return devm_snd_soc_register_component(dev,
+			&es8328_component_driver, &es8328_dai, 1);
 }
 EXPORT_SYMBOL_GPL(es8328_probe);
 
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
index 926b1a4e37d4..c11ed60ccefb 100644
--- a/sound/soc/codecs/gtm601.c
+++ b/sound/soc/codecs/gtm601.c
@@ -19,7 +19,6 @@
 #include <linux/device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
 
@@ -51,25 +50,21 @@ static struct snd_soc_dai_driver gtm601_dai = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = {
-	.component_driver = {
-		.dapm_widgets		= gtm601_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(gtm601_dapm_widgets),
-		.dapm_routes		= gtm601_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(gtm601_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_gtm601 = {
+	.dapm_widgets		= gtm601_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(gtm601_dapm_widgets),
+	.dapm_routes		= gtm601_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(gtm601_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int gtm601_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_gtm601, &gtm601_dai, 1);
-}
-
-static int gtm601_platform_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_gtm601, &gtm601_dai, 1);
 }
 
 #if defined(CONFIG_OF)
@@ -86,7 +81,6 @@ static struct platform_driver gtm601_codec_driver = {
 		.of_match_table = of_match_ptr(gtm601_codec_of_match),
 	},
 	.probe = gtm601_platform_probe,
-	.remove = gtm601_platform_remove,
 };
 
 module_platform_driver(gtm601_codec_driver);
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index dba6f4c5074a..84f7a7a36e4b 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -718,10 +718,22 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
 static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
 			     hda_nid_t nid, unsigned int pwr_state)
 {
+	int count;
+	unsigned int state;
+
 	if (get_wcaps(&edev->hdev, nid) & AC_WCAP_POWER) {
-		if (!snd_hdac_check_power_state(&edev->hdev, nid, pwr_state))
-			snd_hdac_codec_write(&edev->hdev, nid, 0,
-				AC_VERB_SET_POWER_STATE, pwr_state);
+		if (!snd_hdac_check_power_state(&edev->hdev, nid, pwr_state)) {
+			for (count = 0; count < 10; count++) {
+				snd_hdac_codec_read(&edev->hdev, nid, 0,
+						AC_VERB_SET_POWER_STATE,
+						pwr_state);
+				state = snd_hdac_sync_power_state(&edev->hdev,
+						nid, pwr_state);
+				if (!(state & AC_PWRST_ERROR))
+					break;
+			}
+		}
+
 	}
 }
 
@@ -1536,7 +1548,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
 	struct hdac_hdmi_pin *pin = NULL;
 	struct hdac_hdmi_port *hport = NULL;
-	struct snd_soc_codec *codec = edev->scodec;
+	struct snd_soc_component *component = edev->scodec;
 	int i;
 
 	/* Don't know how this mapping is derived */
@@ -1551,7 +1563,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
 	 * connection states are updated in anyway at the end of the resume,
 	 * we can skip it when received during PM process.
 	 */
-	if (snd_power_get_state(codec->component.card->snd_card) !=
+	if (snd_power_get_state(component->card->snd_card) !=
 			SNDRV_CTL_POWER_D0)
 		return;
 
@@ -1609,10 +1621,10 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card,
 	char kc_name[NAME_SIZE], xname[NAME_SIZE];
 	char *name;
 	int i = 0, j;
-	struct snd_soc_codec *codec = edev->scodec;
+	struct snd_soc_component *component = edev->scodec;
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
 
-	kc = devm_kcalloc(codec->dev, hdmi->num_ports,
+	kc = devm_kcalloc(component->dev, hdmi->num_ports,
 				sizeof(*kc), GFP_KERNEL);
 
 	if (!kc)
@@ -1622,11 +1634,11 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card,
 		for (j = 0; j < pin->num_ports; j++) {
 			snprintf(xname, sizeof(xname), "hif%d-%d Jack",
 						pin->nid, pin->ports[j].id);
-			name = devm_kstrdup(codec->dev, xname, GFP_KERNEL);
+			name = devm_kstrdup(component->dev, xname, GFP_KERNEL);
 			if (!name)
 				return -ENOMEM;
 			snprintf(kc_name, sizeof(kc_name), "%s Switch", xname);
-			kc[i].name = devm_kstrdup(codec->dev, kc_name,
+			kc[i].name = devm_kstrdup(component->dev, kc_name,
 							GFP_KERNEL);
 			if (!kc[i].name)
 				return -ENOMEM;
@@ -1644,10 +1656,10 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card,
 	return snd_soc_add_card_controls(card, kc, i);
 }
 
-int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
+int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
 			struct snd_soc_dapm_context *dapm)
 {
-	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
 	struct hdac_hdmi_pin *pin;
 	struct snd_soc_dapm_widget *widgets;
@@ -1722,8 +1734,8 @@ EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init);
 int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
 				struct snd_soc_jack *jack)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
 	struct hdac_hdmi_pcm *pcm;
 	struct snd_pcm *snd_pcm;
@@ -1784,16 +1796,16 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
 	}
 }
 
-static int hdmi_codec_probe(struct snd_soc_codec *codec)
+static int hdmi_codec_probe(struct snd_soc_component *component)
 {
-	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
 	struct snd_soc_dapm_context *dapm =
-		snd_soc_component_get_dapm(&codec->component);
+		snd_soc_component_get_dapm(component);
 	struct hdac_ext_link *hlink = NULL;
 	int ret;
 
-	edev->scodec = codec;
+	edev->scodec = component;
 
 	/*
 	 * hold the ref while we probe, also no need to drop the ref on
@@ -1834,12 +1846,11 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int hdmi_codec_remove(struct snd_soc_codec *codec)
+static void hdmi_codec_remove(struct snd_soc_component *component)
 {
-	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
 
 	pm_runtime_disable(&edev->hdev.dev);
-	return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1891,10 +1902,12 @@ static void hdmi_codec_complete(struct device *dev)
 #define hdmi_codec_complete NULL
 #endif
 
-static const struct snd_soc_codec_driver hdmi_hda_codec = {
-	.probe		= hdmi_codec_probe,
-	.remove		= hdmi_codec_remove,
-	.idle_bias_off	= true,
+static const struct snd_soc_component_driver hdmi_hda_codec = {
+	.probe			= hdmi_codec_probe,
+	.remove			= hdmi_codec_remove,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx,
@@ -2042,7 +2055,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
 	snd_hdac_refresh_widgets(hdev, true);
 
 	/* ASoC specific initialization */
-	ret = snd_soc_register_codec(&hdev->dev, &hdmi_hda_codec,
+	ret = devm_snd_soc_register_component(&hdev->dev, &hdmi_hda_codec,
 					hdmi_dais, num_dais);
 
 	snd_hdac_ext_bus_link_put(edev->ebus, hlink);
@@ -2059,8 +2072,6 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
 	struct hdac_hdmi_port *port, *port_next;
 	int i;
 
-	snd_soc_unregister_codec(&edev->hdev.dev);
-
 	list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
 		pcm->cvt = NULL;
 		if (list_empty(&pcm->port_list))
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
index b5b57a5cbbfd..4fa2fc9ee893 100644
--- a/sound/soc/codecs/hdac_hdmi.h
+++ b/sound/soc/codecs/hdac_hdmi.h
@@ -5,6 +5,6 @@
 int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
 				struct snd_soc_jack *jack);
 
-int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
+int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
 			struct snd_soc_dapm_context *dapm);
 #endif /* __HDAC_HDMI_H__ */
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 5672e516bec3..42df579cb507 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -730,14 +730,16 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
 	return ret;
 }
 
-static const struct snd_soc_codec_driver hdmi_codec = {
-	.component_driver = {
-		.dapm_widgets		= hdmi_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(hdmi_widgets),
-		.dapm_routes		= hdmi_routes,
-		.num_dapm_routes	= ARRAY_SIZE(hdmi_routes),
-		.of_xlate_dai_id	= hdmi_of_xlate_dai_id,
-	},
+static const struct snd_soc_component_driver hdmi_driver = {
+	.dapm_widgets		= hdmi_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(hdmi_widgets),
+	.dapm_routes		= hdmi_routes,
+	.num_dapm_routes	= ARRAY_SIZE(hdmi_routes),
+	.of_xlate_dai_id	= hdmi_of_xlate_dai_id,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
@@ -784,10 +786,10 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	if (hcd->spdif)
 		hcp->daidrv[i] = hdmi_spdif_dai;
 
-	ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv,
+	ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv,
 				     dai_count);
 	if (ret) {
-		dev_err(dev, "%s: snd_soc_register_codec() failed (%d)\n",
+		dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n",
 			__func__, ret);
 		return ret;
 	}
@@ -803,7 +805,6 @@ static int hdmi_codec_remove(struct platform_device *pdev)
 
 	hcp = dev_get_drvdata(dev);
 	kfree(hcp->chmap_info);
-	snd_soc_unregister_codec(dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c
index 651206273f36..148d6d6b2a2b 100644
--- a/sound/soc/codecs/ics43432.c
+++ b/sound/soc/codecs/ics43432.c
@@ -37,21 +37,20 @@ static struct snd_soc_dai_driver ics43432_dai = {
 	},
 };
 
-static const struct snd_soc_codec_driver ics43432_codec_driver = {
+static const struct snd_soc_component_driver ics43432_component_driver = {
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int ics43432_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &ics43432_codec_driver,
+	return devm_snd_soc_register_component(&pdev->dev,
+			&ics43432_component_driver,
 			&ics43432_dai, 1);
 }
 
-static int ics43432_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id ics43432_ids[] = {
 	{ .compatible = "invensense,ics43432", },
@@ -66,7 +65,6 @@ static struct platform_driver ics43432_driver = {
 		.of_match_table = of_match_ptr(ics43432_ids),
 	},
 	.probe = ics43432_probe,
-	.remove = ics43432_remove,
 };
 
 module_platform_driver(ics43432_driver);
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index 6b59b6f08298..85a336ba75f6 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -196,10 +196,10 @@ static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = {
 
 static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int reg01_val = 0,  reg02_val = 0, reg03_val = 0;
 
-	dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
+	dev_dbg(component->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
@@ -211,7 +211,7 @@ static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 			     INNO_R01_I2SMODE_MASTER;
 		break;
 	default:
-		dev_err(codec->dev, "invalid fmt\n");
+		dev_err(component->dev, "invalid fmt\n");
 		return -EINVAL;
 	}
 
@@ -229,7 +229,7 @@ static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		reg02_val |= INNO_R02_DACM_LJM;
 		break;
 	default:
-		dev_err(codec->dev, "set dai format failed\n");
+		dev_err(component->dev, "set dai format failed\n");
 		return -EINVAL;
 	}
 
@@ -251,15 +251,15 @@ static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		reg03_val |= INNO_R03_BCP_REVERSAL;
 		break;
 	default:
-		dev_err(codec->dev, "set dai format failed\n");
+		dev_err(component->dev, "set dai format failed\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK |
+	snd_soc_component_update_bits(component, INNO_R01, INNO_R01_I2SMODE_MSK |
 			    INNO_R01_PINDIR_MSK, reg01_val);
-	snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+	snd_soc_component_update_bits(component, INNO_R02, INNO_R02_LRCP_MSK |
 			    INNO_R02_DACM_MSK, reg02_val);
-	snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
+	snd_soc_component_update_bits(component, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
 
 	return 0;
 }
@@ -268,7 +268,7 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *hw_params,
 				      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int reg02_val = 0, reg03_val = 0;
 
 	switch (params_format(hw_params)) {
@@ -291,9 +291,9 @@ static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
 	reg02_val |= INNO_R02_LRCP_NORMAL;
 	reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK;
 
-	snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+	snd_soc_component_update_bits(component, INNO_R02, INNO_R02_LRCP_MSK |
 			    INNO_R02_VWL_MSK, reg02_val);
-	snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK |
+	snd_soc_component_update_bits(component, INNO_R03, INNO_R03_DACR_MSK |
 			    INNO_R03_FWL_MSK, reg03_val);
 	return 0;
 }
@@ -330,43 +330,42 @@ static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
 	},
 };
 
-static void rk3036_codec_reset(struct snd_soc_codec *codec)
+static void rk3036_codec_reset(struct snd_soc_component *component)
 {
-	snd_soc_write(codec, INNO_R00,
+	snd_soc_component_write(component, INNO_R00,
 		      INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET);
-	snd_soc_write(codec, INNO_R00,
+	snd_soc_component_write(component, INNO_R00,
 		      INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK);
 }
 
-static int rk3036_codec_probe(struct snd_soc_codec *codec)
+static int rk3036_codec_probe(struct snd_soc_component *component)
 {
-	rk3036_codec_reset(codec);
+	rk3036_codec_reset(component);
 	return 0;
 }
 
-static int rk3036_codec_remove(struct snd_soc_codec *codec)
+static void rk3036_codec_remove(struct snd_soc_component *component)
 {
-	rk3036_codec_reset(codec);
-	return 0;
+	rk3036_codec_reset(component);
 }
 
-static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
+static int rk3036_codec_set_bias_level(struct snd_soc_component *component,
 				       enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_STANDBY:
 		/* set a big current for capacitor charging. */
-		snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+		snd_soc_component_write(component, INNO_R10, INNO_R10_MAX_CUR);
 		/* start precharge */
-		snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE);
+		snd_soc_component_write(component, INNO_R06, INNO_R06_DAC_PRECHARGE);
 
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* set a big current for capacitor discharging. */
-		snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+		snd_soc_component_write(component, INNO_R10, INNO_R10_MAX_CUR);
 		/* start discharge. */
-		snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE);
+		snd_soc_component_write(component, INNO_R06, INNO_R06_DAC_DISCHARGE);
 
 		break;
 	default:
@@ -376,18 +375,20 @@ static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static const struct snd_soc_codec_driver rk3036_codec_driver = {
+static const struct snd_soc_component_driver rk3036_codec_driver = {
 	.probe			= rk3036_codec_probe,
 	.remove			= rk3036_codec_remove,
 	.set_bias_level		= rk3036_codec_set_bias_level,
-	.component_driver = {
-		.controls		= rk3036_codec_dapm_controls,
-		.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
-		.dapm_routes		= rk3036_codec_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
-		.dapm_widgets		= rk3036_codec_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
-	},
+	.controls		= rk3036_codec_dapm_controls,
+	.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
+	.dapm_routes		= rk3036_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
+	.dapm_widgets		= rk3036_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rk3036_codec_regmap_config = {
@@ -449,7 +450,7 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev)
 	priv->dev = &pdev->dev;
 	dev_set_drvdata(&pdev->dev, priv);
 
-	ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver,
+	ret = devm_snd_soc_register_component(&pdev->dev, &rk3036_codec_driver,
 				     rk3036_codec_dai_driver,
 				     ARRAY_SIZE(rk3036_codec_dai_driver));
 	if (ret) {
@@ -464,7 +465,6 @@ static int rk3036_codec_platform_remove(struct platform_device *pdev)
 {
 	struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_codec(&pdev->dev);
 	clk_disable_unprepare(priv->pclk);
 
 	return 0;
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 5ca99280ae00..166420376e67 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -867,7 +867,7 @@ static const struct snd_soc_dapm_route isabelle_intercon[] = {
 
 static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, ISABELLE_DAC1_SOFTRAMP_REG,
+	snd_soc_component_update_bits(dai->component, ISABELLE_DAC1_SOFTRAMP_REG,
 			BIT(4), (mute ? BIT(4) : 0));
 
 	return 0;
@@ -875,7 +875,7 @@ static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute)
 
 static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, ISABELLE_DAC2_SOFTRAMP_REG,
+	snd_soc_component_update_bits(dai->component, ISABELLE_DAC2_SOFTRAMP_REG,
 			BIT(4), (mute ? BIT(4) : 0));
 
 	return 0;
@@ -883,13 +883,13 @@ static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute)
 
 static int isabelle_line_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, ISABELLE_DAC3_SOFTRAMP_REG,
+	snd_soc_component_update_bits(dai->component, ISABELLE_DAC3_SOFTRAMP_REG,
 			BIT(4), (mute ? BIT(4) : 0));
 
 	return 0;
 }
 
-static int isabelle_set_bias_level(struct snd_soc_codec *codec,
+static int isabelle_set_bias_level(struct snd_soc_component *component,
 				enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -899,12 +899,12 @@ static int isabelle_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG,
+		snd_soc_component_update_bits(component, ISABELLE_PWR_EN_REG,
 				ISABELLE_CHIP_EN, BIT(0));
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG,
+		snd_soc_component_update_bits(component, ISABELLE_PWR_EN_REG,
 				ISABELLE_CHIP_EN, 0);
 		break;
 	}
@@ -916,7 +916,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *params,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 aif = 0;
 	unsigned int fs_val = 0;
 
@@ -952,7 +952,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, ISABELLE_FS_RATE_CFG_REG,
+	snd_soc_component_update_bits(component, ISABELLE_FS_RATE_CFG_REG,
 			ISABELLE_FS_RATE_MASK, fs_val);
 
 	/* bit size */
@@ -967,7 +967,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG,
+	snd_soc_component_update_bits(component, ISABELLE_INTF_CFG_REG,
 			ISABELLE_AIF_LENGTH_MASK, aif);
 
 	return 0;
@@ -975,7 +975,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
 
 static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int aif_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1003,7 +1003,7 @@ static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG,
+	snd_soc_component_update_bits(component, ISABELLE_INTF_CFG_REG,
 			(ISABELLE_AIF_MS | ISABELLE_AIF_FMT_MASK), aif_val);
 
 	return 0;
@@ -1087,17 +1087,17 @@ static struct snd_soc_dai_driver isabelle_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_isabelle = {
-	.set_bias_level = isabelle_set_bias_level,
-	.component_driver = {
-		.controls		= isabelle_snd_controls,
-		.num_controls		= ARRAY_SIZE(isabelle_snd_controls),
-		.dapm_widgets		= isabelle_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(isabelle_dapm_widgets),
-		.dapm_routes		= isabelle_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(isabelle_intercon),
-	},
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_isabelle = {
+	.set_bias_level		= isabelle_set_bias_level,
+	.controls		= isabelle_snd_controls,
+	.num_controls		= ARRAY_SIZE(isabelle_snd_controls),
+	.dapm_widgets		= isabelle_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(isabelle_dapm_widgets),
+	.dapm_routes		= isabelle_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(isabelle_intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config isabelle_regmap_config = {
@@ -1125,23 +1125,17 @@ static int isabelle_i2c_probe(struct i2c_client *i2c,
 	}
 	i2c_set_clientdata(i2c, isabelle_regmap);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-				&soc_codec_dev_isabelle, isabelle_dai,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_isabelle, isabelle_dai,
 				ARRAY_SIZE(isabelle_dai));
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
 		return ret;
 	}
 
 	return ret;
 }
 
-static int isabelle_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id isabelle_i2c_id[] = {
 	{ "isabelle", 0 },
 	{ }
@@ -1153,7 +1147,6 @@ static struct i2c_driver isabelle_i2c_driver = {
 		.name = "isabelle",
 	},
 	.probe = isabelle_i2c_probe,
-	.remove = isabelle_i2c_remove,
 	.id_table = isabelle_i2c_id,
 };
 
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 6324ccdc8a5c..9395b583432c 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -157,7 +157,7 @@ static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
 static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(dai->codec);
+	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(dai->component);
 	uint32_t val;
 
 	switch (params_rate(params)) {
@@ -236,10 +236,10 @@ static void jz4740_codec_wakeup(struct regmap *regmap)
 	regcache_sync(regmap);
 }
 
-static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
+static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap = jz4740_codec->regmap;
 	unsigned int mask;
 	unsigned int value;
@@ -257,7 +257,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* The only way to clear the suspend flag is to reset the codec */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			jz4740_codec_wakeup(regmap);
 
 		mask = JZ4740_CODEC_1_VREF_DISABLE |
@@ -283,9 +283,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
+static int jz4740_codec_dev_probe(struct snd_soc_component *component)
 {
-	struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
 
 	regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1,
 			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
@@ -293,19 +293,21 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
-	.probe = jz4740_codec_dev_probe,
-	.set_bias_level = jz4740_codec_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= jz4740_codec_controls,
-		.num_controls		= ARRAY_SIZE(jz4740_codec_controls),
-		.dapm_widgets		= jz4740_codec_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(jz4740_codec_dapm_widgets),
-		.dapm_routes		= jz4740_codec_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(jz4740_codec_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_codec_dev_jz4740_codec = {
+	.probe			= jz4740_codec_dev_probe,
+	.set_bias_level		= jz4740_codec_set_bias_level,
+	.controls		= jz4740_codec_controls,
+	.num_controls		= ARRAY_SIZE(jz4740_codec_controls),
+	.dapm_widgets		= jz4740_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(jz4740_codec_dapm_widgets),
+	.dapm_routes		= jz4740_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(jz4740_codec_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
 };
 
 static const struct regmap_config jz4740_codec_regmap_config = {
@@ -343,7 +345,7 @@ static int jz4740_codec_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, jz4740_codec);
 
-	ret = snd_soc_register_codec(&pdev->dev,
+	ret = devm_snd_soc_register_component(&pdev->dev,
 			&soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
 	if (ret)
 		dev_err(&pdev->dev, "Failed to register codec\n");
@@ -351,16 +353,8 @@ static int jz4740_codec_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int jz4740_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-
-	return 0;
-}
-
 static struct platform_driver jz4740_codec_driver = {
 	.probe = jz4740_codec_probe,
-	.remove = jz4740_codec_remove,
 	.driver = {
 		.name = "jz4740-codec",
 	},
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 41e09d1287b8..59a646cc03d4 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1110,7 +1110,7 @@ static int lm49453_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 clk_div = 0;
 
 	/* Setting DAC clock dividers based on substream sample rate. */
@@ -1134,15 +1134,15 @@ static int lm49453_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
-	snd_soc_write(codec, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
+	snd_soc_component_write(component, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
+	snd_soc_component_write(component, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
 
 	return 0;
 }
 
 static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	u16 aif_val;
 	int mode = 0;
@@ -1185,11 +1185,11 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
+	snd_soc_component_update_bits(component, LM49453_P0_AUDIO_PORT1_BASIC_REG,
 			    LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(0)|BIT(5),
 			    (aif_val | mode | clk_phase));
 
-	snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
+	snd_soc_component_write(component, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
 
 	return 0;
 }
@@ -1197,7 +1197,7 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 				  unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 pll_clk = 0;
 
 	switch (freq) {
@@ -1216,50 +1216,50 @@ static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
+	snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
 
 	return 0;
 }
 
 static int lm49453_hp_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
 			    (mute ? (BIT(1)|BIT(0)) : 0));
 	return 0;
 }
 
 static int lm49453_lo_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
 			    (mute ? (BIT(3)|BIT(2)) : 0));
 	return 0;
 }
 
 static int lm49453_ls_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
 			    (mute ? (BIT(5)|BIT(4)) : 0));
 	return 0;
 }
 
 static int lm49453_ep_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(4),
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(4),
 			    (mute ? BIT(4) : 0));
 	return 0;
 }
 
 static int lm49453_ha_mute(struct snd_soc_dai *dai, int mute)
 {
-	snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
 			    (mute ? (BIT(7)|BIT(6)) : 0));
 	return 0;
 }
 
-static int lm49453_set_bias_level(struct snd_soc_codec *codec,
+static int lm49453_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+	struct lm49453_priv *lm49453 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -1267,15 +1267,15 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			regcache_sync(lm49453->regmap);
 
-		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+		snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG,
 				    LM49453_PMC_SETUP_CHIP_EN, LM49453_CHIP_EN);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+		snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG,
 				    LM49453_PMC_SETUP_CHIP_EN, 0);
 		break;
 	}
@@ -1389,17 +1389,17 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
-	.set_bias_level = lm49453_set_bias_level,
-	.component_driver = {
-		.controls		= lm49453_snd_controls,
-		.num_controls		= ARRAY_SIZE(lm49453_snd_controls),
-		.dapm_widgets		= lm49453_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(lm49453_dapm_widgets),
-		.dapm_routes		= lm49453_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(lm49453_audio_map),
-	},
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_lm49453 = {
+	.set_bias_level		= lm49453_set_bias_level,
+	.controls		= lm49453_snd_controls,
+	.num_controls		= ARRAY_SIZE(lm49453_snd_controls),
+	.dapm_widgets		= lm49453_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(lm49453_dapm_widgets),
+	.dapm_routes		= lm49453_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(lm49453_audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config lm49453_regmap_config = {
@@ -1434,18 +1434,17 @@ static int lm49453_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-				      &soc_codec_dev_lm49453,
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_lm49453,
 				      lm49453_dai, ARRAY_SIZE(lm49453_dai));
 	if (ret < 0)
-		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
 
 	return ret;
 }
 
 static int lm49453_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index f0bb830874e5..865f64c40b79 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -307,7 +307,7 @@ static const struct regmap_config max98088_regmap = {
 /*
  * Load equalizer DSP coefficient configurations registers
  */
-static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+static void m98088_eq_band(struct snd_soc_component *component, unsigned int dai,
                    unsigned int band, u16 *coefs)
 {
        unsigned int eq_reg;
@@ -325,8 +325,8 @@ static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
 
        /* Step through the registers and coefs */
        for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
-               snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
-               snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+               snd_soc_component_write(component, eq_reg++, M98088_BYTE1(coefs[i]));
+               snd_soc_component_write(component, eq_reg++, M98088_BYTE0(coefs[i]));
        }
 }
 
@@ -380,12 +380,12 @@ static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
 static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        unsigned int sel = ucontrol->value.integer.value[0];
 
        max98088->mic1pre = sel;
-       snd_soc_update_bits(codec, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
+       snd_soc_component_update_bits(component, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
                (1+sel)<<M98088_MICPRE_SHIFT);
 
        return 0;
@@ -394,8 +394,8 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
 static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
 
        ucontrol->value.integer.value[0] = max98088->mic1pre;
        return 0;
@@ -404,12 +404,12 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
 static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        unsigned int sel = ucontrol->value.integer.value[0];
 
        max98088->mic2pre = sel;
-       snd_soc_update_bits(codec, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
+       snd_soc_component_update_bits(component, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
                (1+sel)<<M98088_MICPRE_SHIFT);
 
        return 0;
@@ -418,8 +418,8 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
 static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
 
        ucontrol->value.integer.value[0] = max98088->mic2pre;
        return 0;
@@ -617,21 +617,21 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
 static int max98088_mic_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                if (w->reg == M98088_REG_35_LVL_MIC1) {
-                       snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+                       snd_soc_component_update_bits(component, w->reg, M98088_MICPRE_MASK,
                                (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
                } else {
-                       snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+                       snd_soc_component_update_bits(component, w->reg, M98088_MICPRE_MASK,
                                (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
                }
                break;
        case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+               snd_soc_component_update_bits(component, w->reg, M98088_MICPRE_MASK, 0);
                break;
        default:
                return -EINVAL;
@@ -647,8 +647,8 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w,
 static int max98088_line_pga(struct snd_soc_dapm_widget *w,
                             int event, int line, u8 channel)
 {
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        u8 *state;
 
 	if (WARN_ON(!(channel == 1 || channel == 2)))
@@ -668,13 +668,13 @@ static int max98088_line_pga(struct snd_soc_dapm_widget *w,
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                *state |= channel;
-               snd_soc_update_bits(codec, w->reg,
+               snd_soc_component_update_bits(component, w->reg,
                        (1 << w->shift), (1 << w->shift));
                break;
        case SND_SOC_DAPM_POST_PMD:
                *state &= ~channel;
                if (*state == 0) {
-                       snd_soc_update_bits(codec, w->reg,
+                       snd_soc_component_update_bits(component, w->reg,
                                (1 << w->shift), 0);
                }
                break;
@@ -963,8 +963,8 @@ static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params,
                                   struct snd_soc_dai *dai)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_cdata *cdata;
        unsigned long long ni;
        unsigned int rate;
@@ -976,51 +976,51 @@ static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
 
        switch (params_width(params)) {
        case 16:
-               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+               snd_soc_component_update_bits(component, M98088_REG_14_DAI1_FORMAT,
                        M98088_DAI_WS, 0);
                break;
        case 24:
-               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+               snd_soc_component_update_bits(component, M98088_REG_14_DAI1_FORMAT,
                        M98088_DAI_WS, M98088_DAI_WS);
                break;
        default:
                return -EINVAL;
        }
 
-       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
 
        if (rate_value(rate, &regval))
                return -EINVAL;
 
-       snd_soc_update_bits(codec, M98088_REG_11_DAI1_CLKMODE,
+       snd_soc_component_update_bits(component, M98088_REG_11_DAI1_CLKMODE,
                M98088_CLKMODE_MASK, regval);
        cdata->rate = rate;
 
        /* Configure NI when operating as master */
-       if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+       if (snd_soc_component_read32(component, M98088_REG_14_DAI1_FORMAT)
                & M98088_DAI_MAS) {
                if (max98088->sysclk == 0) {
-                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       dev_err(component->dev, "Invalid system clock frequency\n");
                        return -EINVAL;
                }
                ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
                                * (unsigned long long int)rate;
                do_div(ni, (unsigned long long int)max98088->sysclk);
-               snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+               snd_soc_component_write(component, M98088_REG_12_DAI1_CLKCFG_HI,
                        (ni >> 8) & 0x7F);
-               snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+               snd_soc_component_write(component, M98088_REG_13_DAI1_CLKCFG_LO,
                        ni & 0xFF);
        }
 
        /* Update sample rate mode */
        if (rate < 50000)
-               snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+               snd_soc_component_update_bits(component, M98088_REG_18_DAI1_FILTERS,
                        M98088_DAI_DHF, 0);
        else
-               snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+               snd_soc_component_update_bits(component, M98088_REG_18_DAI1_FILTERS,
                        M98088_DAI_DHF, M98088_DAI_DHF);
 
-       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
                M98088_SHDNRUN);
 
        return 0;
@@ -1030,8 +1030,8 @@ static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params,
                                   struct snd_soc_dai *dai)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_cdata *cdata;
        unsigned long long ni;
        unsigned int rate;
@@ -1043,51 +1043,51 @@ static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
 
        switch (params_width(params)) {
        case 16:
-               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+               snd_soc_component_update_bits(component, M98088_REG_1C_DAI2_FORMAT,
                        M98088_DAI_WS, 0);
                break;
        case 24:
-               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+               snd_soc_component_update_bits(component, M98088_REG_1C_DAI2_FORMAT,
                        M98088_DAI_WS, M98088_DAI_WS);
                break;
        default:
                return -EINVAL;
        }
 
-       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
 
        if (rate_value(rate, &regval))
                return -EINVAL;
 
-       snd_soc_update_bits(codec, M98088_REG_19_DAI2_CLKMODE,
+       snd_soc_component_update_bits(component, M98088_REG_19_DAI2_CLKMODE,
                M98088_CLKMODE_MASK, regval);
        cdata->rate = rate;
 
        /* Configure NI when operating as master */
-       if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+       if (snd_soc_component_read32(component, M98088_REG_1C_DAI2_FORMAT)
                & M98088_DAI_MAS) {
                if (max98088->sysclk == 0) {
-                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       dev_err(component->dev, "Invalid system clock frequency\n");
                        return -EINVAL;
                }
                ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
                                * (unsigned long long int)rate;
                do_div(ni, (unsigned long long int)max98088->sysclk);
-               snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+               snd_soc_component_write(component, M98088_REG_1A_DAI2_CLKCFG_HI,
                        (ni >> 8) & 0x7F);
-               snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+               snd_soc_component_write(component, M98088_REG_1B_DAI2_CLKCFG_LO,
                        ni & 0xFF);
        }
 
        /* Update sample rate mode */
        if (rate < 50000)
-               snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+               snd_soc_component_update_bits(component, M98088_REG_20_DAI2_FILTERS,
                        M98088_DAI_DHF, 0);
        else
-               snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+               snd_soc_component_update_bits(component, M98088_REG_20_DAI2_FILTERS,
                        M98088_DAI_DHF, M98088_DAI_DHF);
 
-       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
                M98088_SHDNRUN);
 
        return 0;
@@ -1096,8 +1096,8 @@ static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
 static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
                                   int clk_id, unsigned int freq, int dir)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
 
        /* Requested clock frequency is already setup */
        if (freq == max98088->sysclk)
@@ -1108,18 +1108,18 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
         *         0x02 (when master clk is 20MHz to 30MHz)..
         */
        if ((freq >= 10000000) && (freq < 20000000)) {
-               snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+               snd_soc_component_write(component, M98088_REG_10_SYS_CLK, 0x10);
        } else if ((freq >= 20000000) && (freq < 30000000)) {
-               snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+               snd_soc_component_write(component, M98088_REG_10_SYS_CLK, 0x20);
        } else {
-               dev_err(codec->dev, "Invalid master clock frequency\n");
+               dev_err(component->dev, "Invalid master clock frequency\n");
                return -EINVAL;
        }
 
-       if (snd_soc_read(codec, M98088_REG_51_PWR_SYS)  & M98088_SHDNRUN) {
-               snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+       if (snd_soc_component_read32(component, M98088_REG_51_PWR_SYS)  & M98088_SHDNRUN) {
+               snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS,
                        M98088_SHDNRUN, 0);
-               snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+               snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS,
                        M98088_SHDNRUN, M98088_SHDNRUN);
        }
 
@@ -1132,8 +1132,8 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
 static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
                                 unsigned int fmt)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = codec_dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_cdata *cdata;
        u8 reg15val;
        u8 reg14val = 0;
@@ -1146,9 +1146,9 @@ static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
                switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
                case SND_SOC_DAIFMT_CBS_CFS:
                        /* Slave mode PLL */
-                       snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+                       snd_soc_component_write(component, M98088_REG_12_DAI1_CLKCFG_HI,
                                0x80);
-                       snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+                       snd_soc_component_write(component, M98088_REG_13_DAI1_CLKCFG_LO,
                                0x00);
                        break;
                case SND_SOC_DAIFMT_CBM_CFM:
@@ -1158,7 +1158,7 @@ static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
                case SND_SOC_DAIFMT_CBS_CFM:
                case SND_SOC_DAIFMT_CBM_CFS:
                default:
-                       dev_err(codec->dev, "Clock mode unsupported");
+                       dev_err(component->dev, "Clock mode unsupported");
                        return -EINVAL;
                }
 
@@ -1188,14 +1188,14 @@ static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
                        return -EINVAL;
                }
 
-               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+               snd_soc_component_update_bits(component, M98088_REG_14_DAI1_FORMAT,
                        M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
                        M98088_DAI_WCI, reg14val);
 
                reg15val = M98088_DAI_BSEL64;
                if (max98088->digmic)
                        reg15val |= M98088_DAI_OSR64;
-               snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+               snd_soc_component_write(component, M98088_REG_15_DAI1_CLOCK, reg15val);
        }
 
        return 0;
@@ -1204,8 +1204,8 @@ static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
 static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
                                 unsigned int fmt)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = codec_dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_cdata *cdata;
        u8 reg1Cval = 0;
 
@@ -1217,9 +1217,9 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
                switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
                case SND_SOC_DAIFMT_CBS_CFS:
                        /* Slave mode PLL */
-                       snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+                       snd_soc_component_write(component, M98088_REG_1A_DAI2_CLKCFG_HI,
                                0x80);
-                       snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+                       snd_soc_component_write(component, M98088_REG_1B_DAI2_CLKCFG_LO,
                                0x00);
                        break;
                case SND_SOC_DAIFMT_CBM_CFM:
@@ -1229,7 +1229,7 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
                case SND_SOC_DAIFMT_CBS_CFM:
                case SND_SOC_DAIFMT_CBM_CFS:
                default:
-                       dev_err(codec->dev, "Clock mode unsupported");
+                       dev_err(component->dev, "Clock mode unsupported");
                        return -EINVAL;
                }
 
@@ -1259,11 +1259,11 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
                        return -EINVAL;
                }
 
-               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+               snd_soc_component_update_bits(component, M98088_REG_1C_DAI2_FORMAT,
                        M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
                        M98088_DAI_WCI, reg1Cval);
 
-               snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+               snd_soc_component_write(component, M98088_REG_1D_DAI2_CLOCK,
                        M98088_DAI_BSEL64);
        }
 
@@ -1272,7 +1272,7 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
 
 static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_component *component = codec_dai->component;
        int reg;
 
        if (mute)
@@ -1280,14 +1280,14 @@ static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute)
        else
                reg = 0;
 
-       snd_soc_update_bits(codec, M98088_REG_2F_LVL_DAI1_PLAY,
+       snd_soc_component_update_bits(component, M98088_REG_2F_LVL_DAI1_PLAY,
                            M98088_DAI_MUTE_MASK, reg);
        return 0;
 }
 
 static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_component *component = codec_dai->component;
        int reg;
 
        if (mute)
@@ -1295,15 +1295,15 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
        else
                reg = 0;
 
-       snd_soc_update_bits(codec, M98088_REG_31_LVL_DAI2_PLAY,
+       snd_soc_component_update_bits(component, M98088_REG_31_LVL_DAI2_PLAY,
                            M98088_DAI_MUTE_MASK, reg);
        return 0;
 }
 
-static int max98088_set_bias_level(struct snd_soc_codec *codec,
+static int max98088_set_bias_level(struct snd_soc_component *component,
                                   enum snd_soc_bias_level level)
 {
-	struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+	struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -1313,15 +1313,15 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			regcache_sync(max98088->regmap);
 
-		snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+		snd_soc_component_update_bits(component, M98088_REG_4C_PWR_EN_IN,
 				   M98088_MBEN, M98088_MBEN);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+		snd_soc_component_update_bits(component, M98088_REG_4C_PWR_EN_IN,
 				    M98088_MBEN, 0);
 		regcache_mark_dirty(max98088->regmap);
 		break;
@@ -1380,7 +1380,7 @@ static struct snd_soc_dai_driver max98088_dai[] = {
 
 static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
 
-static int max98088_get_channel(struct snd_soc_codec *codec, const char *name)
+static int max98088_get_channel(struct snd_soc_component *component, const char *name)
 {
 	int i;
 
@@ -1389,13 +1389,13 @@ static int max98088_get_channel(struct snd_soc_codec *codec, const char *name)
 			return i;
 
 	/* Shouldn't happen */
-	dev_err(codec->dev, "Bad EQ channel name '%s'\n", name);
+	dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
 	return -EINVAL;
 }
 
-static void max98088_setup_eq1(struct snd_soc_codec *codec)
+static void max98088_setup_eq1(struct snd_soc_component *component)
 {
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_pdata *pdata = max98088->pdata;
        struct max98088_eq_cfg *coef_set;
        int best, best_val, save, i, sel, fs;
@@ -1420,29 +1420,29 @@ static void max98088_setup_eq1(struct snd_soc_codec *codec)
                }
        }
 
-       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+       dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
                pdata->eq_cfg[best].name,
                pdata->eq_cfg[best].rate, fs);
 
        /* Disable EQ while configuring, and save current on/off state */
-       save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
-       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+       save = snd_soc_component_read32(component, M98088_REG_49_CFG_LEVEL);
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
 
        coef_set = &pdata->eq_cfg[sel];
 
-       m98088_eq_band(codec, 0, 0, coef_set->band1);
-       m98088_eq_band(codec, 0, 1, coef_set->band2);
-       m98088_eq_band(codec, 0, 2, coef_set->band3);
-       m98088_eq_band(codec, 0, 3, coef_set->band4);
-       m98088_eq_band(codec, 0, 4, coef_set->band5);
+       m98088_eq_band(component, 0, 0, coef_set->band1);
+       m98088_eq_band(component, 0, 1, coef_set->band2);
+       m98088_eq_band(component, 0, 2, coef_set->band3);
+       m98088_eq_band(component, 0, 3, coef_set->band4);
+       m98088_eq_band(component, 0, 4, coef_set->band5);
 
        /* Restore the original on/off state */
-       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
 }
 
-static void max98088_setup_eq2(struct snd_soc_codec *codec)
+static void max98088_setup_eq2(struct snd_soc_component *component)
 {
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_pdata *pdata = max98088->pdata;
        struct max98088_eq_cfg *coef_set;
        int best, best_val, save, i, sel, fs;
@@ -1467,34 +1467,34 @@ static void max98088_setup_eq2(struct snd_soc_codec *codec)
                }
        }
 
-       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+       dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
                pdata->eq_cfg[best].name,
                pdata->eq_cfg[best].rate, fs);
 
        /* Disable EQ while configuring, and save current on/off state */
-       save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
-       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+       save = snd_soc_component_read32(component, M98088_REG_49_CFG_LEVEL);
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
 
        coef_set = &pdata->eq_cfg[sel];
 
-       m98088_eq_band(codec, 1, 0, coef_set->band1);
-       m98088_eq_band(codec, 1, 1, coef_set->band2);
-       m98088_eq_band(codec, 1, 2, coef_set->band3);
-       m98088_eq_band(codec, 1, 3, coef_set->band4);
-       m98088_eq_band(codec, 1, 4, coef_set->band5);
+       m98088_eq_band(component, 1, 0, coef_set->band1);
+       m98088_eq_band(component, 1, 1, coef_set->band2);
+       m98088_eq_band(component, 1, 2, coef_set->band3);
+       m98088_eq_band(component, 1, 3, coef_set->band4);
+       m98088_eq_band(component, 1, 4, coef_set->band5);
 
        /* Restore the original on/off state */
-       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
                save);
 }
 
 static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_pdata *pdata = max98088->pdata;
-       int channel = max98088_get_channel(codec, kcontrol->id.name);
+       int channel = max98088_get_channel(component, kcontrol->id.name);
        struct max98088_cdata *cdata;
 	int sel = ucontrol->value.enumerated.item[0];
 
@@ -1510,10 +1510,10 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
 
        switch (channel) {
        case 0:
-               max98088_setup_eq1(codec);
+               max98088_setup_eq1(component);
                break;
        case 1:
-               max98088_setup_eq2(codec);
+               max98088_setup_eq2(component);
                break;
        }
 
@@ -1523,9 +1523,9 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
 static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
-       int channel = max98088_get_channel(codec, kcontrol->id.name);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       int channel = max98088_get_channel(component, kcontrol->id.name);
        struct max98088_cdata *cdata;
 
        if (channel < 0)
@@ -1536,9 +1536,9 @@ static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
+static void max98088_handle_eq_pdata(struct snd_soc_component *component)
 {
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_pdata *pdata = max98088->pdata;
        struct max98088_eq_cfg *cfg;
        unsigned int cfgcnt;
@@ -1591,19 +1591,19 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
        max98088->eq_enum.texts = max98088->eq_texts;
        max98088->eq_enum.items = max98088->eq_textcnt;
 
-       ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
+       ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
        if (ret != 0)
-               dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+               dev_err(component->dev, "Failed to add EQ control: %d\n", ret);
 }
 
-static void max98088_handle_pdata(struct snd_soc_codec *codec)
+static void max98088_handle_pdata(struct snd_soc_component *component)
 {
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_pdata *pdata = max98088->pdata;
        u8 regval = 0;
 
        if (!pdata) {
-               dev_dbg(codec->dev, "No platform data\n");
+               dev_dbg(component->dev, "No platform data\n");
                return;
        }
 
@@ -1616,21 +1616,21 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
 
        max98088->digmic = (regval ? 1 : 0);
 
-       snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+       snd_soc_component_write(component, M98088_REG_48_CFG_MIC, regval);
 
        /* Configure receiver output */
        regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
-       snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+       snd_soc_component_update_bits(component, M98088_REG_2A_MIC_REC_CNTL,
                M98088_REC_LINEMODE_MASK, regval);
 
        /* Configure equalizers */
        if (pdata->eq_cfgcnt)
-               max98088_handle_eq_pdata(codec);
+               max98088_handle_eq_pdata(component);
 }
 
-static int max98088_probe(struct snd_soc_codec *codec)
+static int max98088_probe(struct snd_soc_component *component)
 {
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
        struct max98088_cdata *cdata;
        int ret = 0;
 
@@ -1658,60 +1658,59 @@ static int max98088_probe(struct snd_soc_codec *codec)
        max98088->mic1pre = 0;
        max98088->mic2pre = 0;
 
-       ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+       ret = snd_soc_component_read32(component, M98088_REG_FF_REV_ID);
        if (ret < 0) {
-               dev_err(codec->dev, "Failed to read device revision: %d\n",
+               dev_err(component->dev, "Failed to read device revision: %d\n",
                        ret);
                goto err_access;
        }
-       dev_info(codec->dev, "revision %c\n", ret - 0x40 + 'A');
+       dev_info(component->dev, "revision %c\n", ret - 0x40 + 'A');
 
-       snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+       snd_soc_component_write(component, M98088_REG_51_PWR_SYS, M98088_PWRSV);
 
-       snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+       snd_soc_component_write(component, M98088_REG_0F_IRQ_ENABLE, 0x00);
 
-       snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+       snd_soc_component_write(component, M98088_REG_22_MIX_DAC,
                M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
                M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
 
-       snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
-       snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+       snd_soc_component_write(component, M98088_REG_4E_BIAS_CNTL, 0xF0);
+       snd_soc_component_write(component, M98088_REG_50_DAC_BIAS2, 0x0F);
 
-       snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+       snd_soc_component_write(component, M98088_REG_16_DAI1_IOCFG,
                M98088_S1NORMAL|M98088_SDATA);
 
-       snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+       snd_soc_component_write(component, M98088_REG_1E_DAI2_IOCFG,
                M98088_S2NORMAL|M98088_SDATA);
 
-       max98088_handle_pdata(codec);
+       max98088_handle_pdata(component);
 
 err_access:
        return ret;
 }
 
-static int max98088_remove(struct snd_soc_codec *codec)
+static void max98088_remove(struct snd_soc_component *component)
 {
-       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
 
        kfree(max98088->eq_texts);
-
-       return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98088 = {
-	.probe   = max98088_probe,
-	.remove  = max98088_remove,
-	.set_bias_level = max98088_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= max98088_snd_controls,
-		.num_controls		= ARRAY_SIZE(max98088_snd_controls),
-		.dapm_widgets		= max98088_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max98088_dapm_widgets),
-		.dapm_routes		= max98088_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(max98088_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_max98088 = {
+	.probe			= max98088_probe,
+	.remove			= max98088_remove,
+	.set_bias_level		= max98088_set_bias_level,
+	.controls		= max98088_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98088_snd_controls),
+	.dapm_widgets		= max98088_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98088_dapm_widgets),
+	.dapm_routes		= max98088_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98088_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
@@ -1734,17 +1733,11 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
        i2c_set_clientdata(i2c, max98088);
        max98088->pdata = i2c->dev.platform_data;
 
-       ret = snd_soc_register_codec(&i2c->dev,
-                       &soc_codec_dev_max98088, &max98088_dai[0], 2);
+       ret = devm_snd_soc_register_component(&i2c->dev,
+                       &soc_component_dev_max98088, &max98088_dai[0], 2);
        return ret;
 }
 
-static int max98088_i2c_remove(struct i2c_client *client)
-{
-       snd_soc_unregister_codec(&client->dev);
-       return 0;
-}
-
 static const struct i2c_device_id max98088_i2c_id[] = {
        { "max98088", MAX98088 },
        { "max98089", MAX98089 },
@@ -1757,7 +1750,6 @@ static struct i2c_driver max98088_i2c_driver = {
 		.name = "max98088",
 	},
 	.probe  = max98088_i2c_probe,
-	.remove = max98088_i2c_remove,
 	.id_table = max98088_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index f5075d1f79e6..c97f21836c66 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -284,7 +284,7 @@ static int max98090_reset(struct max98090_priv *max98090)
 	ret = regmap_write(max98090->regmap, M98090_REG_SOFTWARE_RESET,
 		M98090_SWRESET_MASK);
 	if (ret < 0) {
-		dev_err(max98090->codec->dev,
+		dev_err(max98090->component->dev,
 			"Failed to reset codec: %d\n", ret);
 		return ret;
 	}
@@ -354,12 +354,12 @@ static const DECLARE_TLV_DB_RANGE(max98090_rcv_lout_tlv,
 static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int mask = (1 << fls(mc->max)) - 1;
-	unsigned int val = snd_soc_read(codec, mc->reg);
+	unsigned int val = snd_soc_component_read32(component, mc->reg);
 	unsigned int *select;
 
 	switch (mc->reg) {
@@ -394,13 +394,13 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
 static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int mask = (1 << fls(mc->max)) - 1;
 	unsigned int sel = ucontrol->value.integer.value[0];
-	unsigned int val = snd_soc_read(codec, mc->reg);
+	unsigned int val = snd_soc_component_read32(component, mc->reg);
 	unsigned int *select;
 
 	switch (mc->reg) {
@@ -429,7 +429,7 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
 		sel = val;
 	}
 
-	snd_soc_update_bits(codec, mc->reg,
+	snd_soc_component_update_bits(component, mc->reg,
 		mask << mc->shift,
 		sel << mc->shift);
 
@@ -733,10 +733,10 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
 static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
-	unsigned int val = snd_soc_read(codec, w->reg);
+	unsigned int val = snd_soc_component_read32(component, w->reg);
 
 	if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
 		val = (val & M98090_MIC_PA1EN_MASK) >> M98090_MIC_PA1EN_SHIFT;
@@ -768,10 +768,10 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
 	}
 
 	if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
-		snd_soc_update_bits(codec, w->reg, M98090_MIC_PA1EN_MASK,
+		snd_soc_component_update_bits(component, w->reg, M98090_MIC_PA1EN_MASK,
 			val << M98090_MIC_PA1EN_SHIFT);
 	else
-		snd_soc_update_bits(codec, w->reg, M98090_MIC_PA2EN_MASK,
+		snd_soc_component_update_bits(component, w->reg, M98090_MIC_PA2EN_MASK,
 			val << M98090_MIC_PA2EN_SHIFT);
 
 	return 0;
@@ -780,8 +780,8 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
 static int max98090_shdn_event(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
 	if (event & SND_SOC_DAPM_POST_PMU)
 		max98090->shdn_pending = true;
@@ -1441,16 +1441,16 @@ static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
 	{"DMIC4", NULL, "AHPF"},
 };
 
-static int max98090_add_widgets(struct snd_soc_codec *codec)
+static int max98090_add_widgets(struct snd_soc_component *component)
 {
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	snd_soc_add_codec_controls(codec, max98090_snd_controls,
+	snd_soc_add_component_controls(component, max98090_snd_controls,
 		ARRAY_SIZE(max98090_snd_controls));
 
 	if (max98090->devtype == MAX98091) {
-		snd_soc_add_codec_controls(codec, max98091_snd_controls,
+		snd_soc_add_component_controls(component, max98091_snd_controls,
 			ARRAY_SIZE(max98091_snd_controls));
 	}
 
@@ -1497,24 +1497,24 @@ static const unsigned long long mi_value[] = {
 	8125, 1625, 1500, 25
 };
 
-static void max98090_configure_bclk(struct snd_soc_codec *codec)
+static void max98090_configure_bclk(struct snd_soc_component *component)
 {
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	unsigned long long ni;
 	int i;
 
 	if (!max98090->sysclk) {
-		dev_err(codec->dev, "No SYSCLK configured\n");
+		dev_err(component->dev, "No SYSCLK configured\n");
 		return;
 	}
 
 	if (!max98090->bclk || !max98090->lrclk) {
-		dev_err(codec->dev, "No audio clocks configured\n");
+		dev_err(component->dev, "No audio clocks configured\n");
 		return;
 	}
 
 	/* Skip configuration when operating as slave */
-	if (!(snd_soc_read(codec, M98090_REG_MASTER_MODE) &
+	if (!(snd_soc_component_read32(component, M98090_REG_MASTER_MODE) &
 		M98090_MAS_MASK)) {
 		return;
 	}
@@ -1523,14 +1523,14 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
 	for (i = 0; i < ARRAY_SIZE(pclk_rates); i++) {
 		if ((pclk_rates[i] == max98090->sysclk) &&
 			(lrclk_rates[i] == max98090->lrclk)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Found supported PCLK to LRCLK rates 0x%x\n",
 				i + 0x8);
 
-			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 				M98090_FREQ_MASK,
 				(i + 0x8) << M98090_FREQ_SHIFT);
-			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 				M98090_USE_M1_MASK, 0);
 			return;
 		}
@@ -1540,24 +1540,24 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
 	for (i = 0; i < ARRAY_SIZE(user_pclk_rates); i++) {
 		if ((user_pclk_rates[i] == max98090->sysclk) &&
 			(user_lrclk_rates[i] == max98090->lrclk)) {
-			dev_dbg(codec->dev,
+			dev_dbg(component->dev,
 				"Found user supported PCLK to LRCLK rates\n");
-			dev_dbg(codec->dev, "i %d ni %lld mi %lld\n",
+			dev_dbg(component->dev, "i %d ni %lld mi %lld\n",
 				i, ni_value[i], mi_value[i]);
 
-			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 				M98090_FREQ_MASK, 0);
-			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 				M98090_USE_M1_MASK,
 					1 << M98090_USE_M1_SHIFT);
 
-			snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_MSB,
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB,
 				(ni_value[i] >> 8) & 0x7F);
-			snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_LSB,
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB,
 				ni_value[i] & 0xFF);
-			snd_soc_write(codec, M98090_REG_CLOCK_RATIO_MI_MSB,
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_MI_MSB,
 				(mi_value[i] >> 8) & 0x7F);
-			snd_soc_write(codec, M98090_REG_CLOCK_RATIO_MI_LSB,
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_MI_LSB,
 				mi_value[i] & 0xFF);
 
 			return;
@@ -1567,9 +1567,9 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
 	/*
 	 * Calculate based on MI = 65536 (not as good as either method above)
 	 */
-	snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+	snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 		M98090_FREQ_MASK, 0);
-	snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+	snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 		M98090_USE_M1_MASK, 0);
 
 	/*
@@ -1580,18 +1580,18 @@ static void max98090_configure_bclk(struct snd_soc_codec *codec)
 	ni = 65536ULL * (max98090->lrclk < 50000 ? 96ULL : 48ULL)
 			* (unsigned long long int)max98090->lrclk;
 	do_div(ni, (unsigned long long int)max98090->sysclk);
-	dev_info(codec->dev, "No better method found\n");
-	dev_info(codec->dev, "Calculating ni %lld with mi 65536\n", ni);
-	snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_MSB,
+	dev_info(component->dev, "No better method found\n");
+	dev_info(component->dev, "Calculating ni %lld with mi 65536\n", ni);
+	snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB,
 		(ni >> 8) & 0x7F);
-	snd_soc_write(codec, M98090_REG_CLOCK_RATIO_NI_LSB, ni & 0xFF);
+	snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB, ni & 0xFF);
 }
 
 static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 				 unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	struct max98090_cdata *cdata;
 	u8 regval;
 
@@ -1605,11 +1605,11 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 		case SND_SOC_DAIFMT_CBS_CFS:
 			/* Set to slave mode PLL - MAS mode off */
-			snd_soc_write(codec,
+			snd_soc_component_write(component,
 				M98090_REG_CLOCK_RATIO_NI_MSB, 0x00);
-			snd_soc_write(codec,
+			snd_soc_component_write(component,
 				M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
-			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
 				M98090_USE_M1_MASK, 0);
 			max98090->master = false;
 			break;
@@ -1633,10 +1633,10 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		case SND_SOC_DAIFMT_CBS_CFM:
 		case SND_SOC_DAIFMT_CBM_CFS:
 		default:
-			dev_err(codec->dev, "DAI clock mode unsupported");
+			dev_err(component->dev, "DAI clock mode unsupported");
 			return -EINVAL;
 		}
-		snd_soc_write(codec, M98090_REG_MASTER_MODE, regval);
+		snd_soc_component_write(component, M98090_REG_MASTER_MODE, regval);
 
 		regval = 0;
 		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -1651,7 +1651,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		case SND_SOC_DAIFMT_DSP_A:
 			/* Not supported mode */
 		default:
-			dev_err(codec->dev, "DAI format unsupported");
+			dev_err(component->dev, "DAI format unsupported");
 			return -EINVAL;
 		}
 
@@ -1668,7 +1668,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 			regval |= M98090_BCI_MASK|M98090_WCI_MASK;
 			break;
 		default:
-			dev_err(codec->dev, "DAI invert mode unsupported");
+			dev_err(component->dev, "DAI invert mode unsupported");
 			return -EINVAL;
 		}
 
@@ -1681,7 +1681,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		if (max98090->tdm_slots > 1)
 			regval ^= M98090_BCI_MASK;
 
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			M98090_REG_INTERFACE_FORMAT, regval);
 	}
 
@@ -1691,8 +1691,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	struct max98090_cdata *cdata;
 	cdata = &max98090->dai[0];
 
@@ -1704,13 +1704,13 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
 
 	if (max98090->tdm_slots > 1) {
 		/* SLOTL SLOTR SLOTDLY */
-		snd_soc_write(codec, M98090_REG_TDM_FORMAT,
+		snd_soc_component_write(component, M98090_REG_TDM_FORMAT,
 			0 << M98090_TDM_SLOTL_SHIFT |
 			1 << M98090_TDM_SLOTR_SHIFT |
 			0 << M98090_TDM_SLOTDLY_SHIFT);
 
 		/* FSW TDM */
-		snd_soc_update_bits(codec, M98090_REG_TDM_CONTROL,
+		snd_soc_component_update_bits(component, M98090_REG_TDM_CONTROL,
 			M98090_TDM_MASK,
 			M98090_TDM_MASK);
 	}
@@ -1724,10 +1724,10 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int max98090_set_bias_level(struct snd_soc_codec *codec,
+static int max98090_set_bias_level(struct snd_soc_component *component,
 				   enum snd_soc_bias_level level)
 {
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1745,7 +1745,7 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 		if (IS_ERR(max98090->mclk))
 			break;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
 			clk_disable_unprepare(max98090->mclk);
 		} else {
 			ret = clk_prepare_enable(max98090->mclk);
@@ -1755,10 +1755,10 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(max98090->regmap);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to sync cache: %d\n", ret);
 				return ret;
 			}
@@ -1767,7 +1767,7 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_OFF:
 		/* Set internal pull-up to lowest power mode */
-		snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
+		snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
 			M98090_JDWK_MASK, M98090_JDWK_MASK);
 		regcache_mark_dirty(max98090->regmap);
 		break;
@@ -1928,8 +1928,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	struct max98090_cdata *cdata;
 
 	cdata = &max98090->dai[0];
@@ -1941,7 +1941,7 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_width(params)) {
 	case 16:
-		snd_soc_update_bits(codec, M98090_REG_INTERFACE_FORMAT,
+		snd_soc_component_update_bits(component, M98090_REG_INTERFACE_FORMAT,
 			M98090_WS_MASK, 0);
 		break;
 	default:
@@ -1949,24 +1949,24 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (max98090->master)
-		max98090_configure_bclk(codec);
+		max98090_configure_bclk(component);
 
 	cdata->rate = max98090->lrclk;
 
 	/* Update filter mode */
 	if (max98090->lrclk < 24000)
-		snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
 			M98090_MODE_MASK, 0);
 	else
-		snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
 			M98090_MODE_MASK, M98090_MODE_MASK);
 
 	/* Update sample rate mode */
 	if (max98090->lrclk < 50000)
-		snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
 			M98090_DHF_MASK, 0);
 	else
-		snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
 			M98090_DHF_MASK, M98090_DHF_MASK);
 
 	max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
@@ -1981,8 +1981,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
 				   int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
 	/* Requested clock frequency is already setup */
 	if (freq == max98090->sysclk)
@@ -1999,19 +1999,19 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
 	 *		 0x03 (when master clk is 40MHz to 60MHz)..
 	 */
 	if ((freq >= 10000000) && (freq <= 20000000)) {
-		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
+		snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
 			M98090_PSCLK_DIV1);
 		max98090->pclk = freq;
 	} else if ((freq > 20000000) && (freq <= 40000000)) {
-		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
+		snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
 			M98090_PSCLK_DIV2);
 		max98090->pclk = freq >> 1;
 	} else if ((freq > 40000000) && (freq <= 60000000)) {
-		snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
+		snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
 			M98090_PSCLK_DIV4);
 		max98090->pclk = freq >> 2;
 	} else {
-		dev_err(codec->dev, "Invalid master clock frequency\n");
+		dev_err(component->dev, "Invalid master clock frequency\n");
 		return -EINVAL;
 	}
 
@@ -2022,11 +2022,11 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
 
 static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int regval;
 
 	regval = mute ? M98090_DVM_MASK : 0;
-	snd_soc_update_bits(codec, M98090_REG_DAI_PLAYBACK_LEVEL,
+	snd_soc_component_update_bits(component, M98090_REG_DAI_PLAYBACK_LEVEL,
 		M98090_DVM_MASK, regval);
 
 	return 0;
@@ -2035,8 +2035,8 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -2065,7 +2065,7 @@ static void max98090_pll_det_enable_work(struct work_struct *work)
 	struct max98090_priv *max98090 =
 		container_of(work, struct max98090_priv,
 			     pll_det_enable_work.work);
-	struct snd_soc_codec *codec = max98090->codec;
+	struct snd_soc_component *component = max98090->component;
 	unsigned int status, mask;
 
 	/*
@@ -2088,7 +2088,7 @@ static void max98090_pll_det_enable_work(struct work_struct *work)
 				   msecs_to_jiffies(100));
 
 	/* Enable PLL unlock interrupt */
-	snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+	snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
 			    M98090_IULK_MASK,
 			    1 << M98090_IULK_SHIFT);
 }
@@ -2097,12 +2097,12 @@ static void max98090_pll_det_disable_work(struct work_struct *work)
 {
 	struct max98090_priv *max98090 =
 		container_of(work, struct max98090_priv, pll_det_disable_work);
-	struct snd_soc_codec *codec = max98090->codec;
+	struct snd_soc_component *component = max98090->component;
 
 	cancel_delayed_work_sync(&max98090->pll_det_enable_work);
 
 	/* Disable PLL unlock interrupt */
-	snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+	snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
 			    M98090_IULK_MASK, 0);
 }
 
@@ -2110,18 +2110,18 @@ static void max98090_pll_work(struct work_struct *work)
 {
 	struct max98090_priv *max98090 =
 		container_of(work, struct max98090_priv, pll_work);
-	struct snd_soc_codec *codec = max98090->codec;
+	struct snd_soc_component *component = max98090->component;
 
-	if (!snd_soc_codec_is_active(codec))
+	if (!snd_soc_component_is_active(component))
 		return;
 
-	dev_info_ratelimited(codec->dev, "PLL unlocked\n");
+	dev_info_ratelimited(component->dev, "PLL unlocked\n");
 
 	/* Toggle shutdown OFF then ON */
-	snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+	snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
 			    M98090_SHDNN_MASK, 0);
 	msleep(10);
-	snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+	snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
 			    M98090_SHDNN_MASK, M98090_SHDNN_MASK);
 
 	/* Give PLL time to lock */
@@ -2133,7 +2133,7 @@ static void max98090_jack_work(struct work_struct *work)
 	struct max98090_priv *max98090 = container_of(work,
 		struct max98090_priv,
 		jack_work.work);
-	struct snd_soc_codec *codec = max98090->codec;
+	struct snd_soc_component *component = max98090->component;
 	int status = 0;
 	int reg;
 
@@ -2141,25 +2141,25 @@ static void max98090_jack_work(struct work_struct *work)
 	if (max98090->jack_state == M98090_JACK_STATE_NO_HEADSET) {
 
 		/* Strong pull up allows mic detection */
-		snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
+		snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
 			M98090_JDWK_MASK, 0);
 
 		msleep(50);
 
-		reg = snd_soc_read(codec, M98090_REG_JACK_STATUS);
+		reg = snd_soc_component_read32(component, M98090_REG_JACK_STATUS);
 
 		/* Weak pull up allows only insertion detection */
-		snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
+		snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
 			M98090_JDWK_MASK, M98090_JDWK_MASK);
 	} else {
-		reg = snd_soc_read(codec, M98090_REG_JACK_STATUS);
+		reg = snd_soc_component_read32(component, M98090_REG_JACK_STATUS);
 	}
 
-	reg = snd_soc_read(codec, M98090_REG_JACK_STATUS);
+	reg = snd_soc_component_read32(component, M98090_REG_JACK_STATUS);
 
 	switch (reg & (M98090_LSNS_MASK | M98090_JKSNS_MASK)) {
 		case M98090_LSNS_MASK | M98090_JKSNS_MASK:
-			dev_dbg(codec->dev, "No Headset Detected\n");
+			dev_dbg(component->dev, "No Headset Detected\n");
 
 			max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
 
@@ -2171,7 +2171,7 @@ static void max98090_jack_work(struct work_struct *work)
 			if (max98090->jack_state ==
 				M98090_JACK_STATE_HEADSET) {
 
-				dev_dbg(codec->dev,
+				dev_dbg(component->dev,
 					"Headset Button Down Detected\n");
 
 				/*
@@ -2188,7 +2188,7 @@ static void max98090_jack_work(struct work_struct *work)
 			/* Line is reported as Headphone */
 			/* Nokia Headset is reported as Headphone */
 			/* Mono Headphone is reported as Headphone */
-			dev_dbg(codec->dev, "Headphone Detected\n");
+			dev_dbg(component->dev, "Headphone Detected\n");
 
 			max98090->jack_state = M98090_JACK_STATE_HEADPHONE;
 
@@ -2197,7 +2197,7 @@ static void max98090_jack_work(struct work_struct *work)
 			break;
 
 		case M98090_JKSNS_MASK:
-			dev_dbg(codec->dev, "Headset Detected\n");
+			dev_dbg(component->dev, "Headset Detected\n");
 
 			max98090->jack_state = M98090_JACK_STATE_HEADSET;
 
@@ -2206,7 +2206,7 @@ static void max98090_jack_work(struct work_struct *work)
 			break;
 
 		default:
-			dev_dbg(codec->dev, "Unrecognized Jack Status\n");
+			dev_dbg(component->dev, "Unrecognized Jack Status\n");
 			break;
 	}
 
@@ -2217,21 +2217,21 @@ static void max98090_jack_work(struct work_struct *work)
 static irqreturn_t max98090_interrupt(int irq, void *data)
 {
 	struct max98090_priv *max98090 = data;
-	struct snd_soc_codec *codec = max98090->codec;
+	struct snd_soc_component *component = max98090->component;
 	int ret;
 	unsigned int mask;
 	unsigned int active;
 
 	/* Treat interrupt before codec is initialized as spurious */
-	if (codec == NULL)
+	if (component == NULL)
 		return IRQ_NONE;
 
-	dev_dbg(codec->dev, "***** max98090_interrupt *****\n");
+	dev_dbg(component->dev, "***** max98090_interrupt *****\n");
 
 	ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
 
 	if (ret != 0) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"failed to read M98090_REG_INTERRUPT_S: %d\n",
 			ret);
 		return IRQ_NONE;
@@ -2240,13 +2240,13 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 	ret = regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &active);
 
 	if (ret != 0) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"failed to read M98090_REG_DEVICE_STATUS: %d\n",
 			ret);
 		return IRQ_NONE;
 	}
 
-	dev_dbg(codec->dev, "active=0x%02x mask=0x%02x -> active=0x%02x\n",
+	dev_dbg(component->dev, "active=0x%02x mask=0x%02x -> active=0x%02x\n",
 		active, mask, active & mask);
 
 	active &= mask;
@@ -2255,20 +2255,20 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 		return IRQ_NONE;
 
 	if (active & M98090_CLD_MASK)
-		dev_err(codec->dev, "M98090_CLD_MASK\n");
+		dev_err(component->dev, "M98090_CLD_MASK\n");
 
 	if (active & M98090_SLD_MASK)
-		dev_dbg(codec->dev, "M98090_SLD_MASK\n");
+		dev_dbg(component->dev, "M98090_SLD_MASK\n");
 
 	if (active & M98090_ULK_MASK) {
-		dev_dbg(codec->dev, "M98090_ULK_MASK\n");
+		dev_dbg(component->dev, "M98090_ULK_MASK\n");
 		schedule_work(&max98090->pll_work);
 	}
 
 	if (active & M98090_JDET_MASK) {
-		dev_dbg(codec->dev, "M98090_JDET_MASK\n");
+		dev_dbg(component->dev, "M98090_JDET_MASK\n");
 
-		pm_wakeup_event(codec->dev, 100);
+		pm_wakeup_event(component->dev, 100);
 
 		queue_delayed_work(system_power_efficient_wq,
 				   &max98090->jack_work,
@@ -2276,10 +2276,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 	}
 
 	if (active & M98090_DRCACT_MASK)
-		dev_dbg(codec->dev, "M98090_DRCACT_MASK\n");
+		dev_dbg(component->dev, "M98090_DRCACT_MASK\n");
 
 	if (active & M98090_DRCCLP_MASK)
-		dev_err(codec->dev, "M98090_DRCCLP_MASK\n");
+		dev_err(component->dev, "M98090_DRCCLP_MASK\n");
 
 	return IRQ_HANDLED;
 }
@@ -2287,7 +2287,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 /**
  * max98090_mic_detect - Enable microphone detection via the MAX98090 IRQ
  *
- * @codec:  MAX98090 codec
+ * @component:  MAX98090 component
  * @jack:   jack to report detection events on
  *
  * Enable microphone detection via IRQ on the MAX98090.  If GPIOs are
@@ -2297,20 +2297,20 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
  *
  * If no jack is supplied detection will be disabled.
  */
-int max98090_mic_detect(struct snd_soc_codec *codec,
+int max98090_mic_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack)
 {
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "max98090_mic_detect\n");
+	dev_dbg(component->dev, "max98090_mic_detect\n");
 
 	max98090->jack = jack;
 	if (jack) {
-		snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+		snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
 			M98090_IJDET_MASK,
 			1 << M98090_IJDET_SHIFT);
 	} else {
-		snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+		snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
 			M98090_IJDET_MASK,
 			0);
 	}
@@ -2360,22 +2360,22 @@ static struct snd_soc_dai_driver max98090_dai[] = {
 }
 };
 
-static int max98090_probe(struct snd_soc_codec *codec)
+static int max98090_probe(struct snd_soc_component *component)
 {
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 	struct max98090_cdata *cdata;
 	enum max98090_type devtype;
 	int ret = 0;
 	int err;
 	unsigned int micbias;
 
-	dev_dbg(codec->dev, "max98090_probe\n");
+	dev_dbg(component->dev, "max98090_probe\n");
 
-	max98090->mclk = devm_clk_get(codec->dev, "mclk");
+	max98090->mclk = devm_clk_get(component->dev, "mclk");
 	if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
 
-	max98090->codec = codec;
+	max98090->component = component;
 
 	/* Reset the codec, the DSP core, and disable all interrupts */
 	max98090_reset(max98090);
@@ -2394,26 +2394,26 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	max98090->pa1en = 0;
 	max98090->pa2en = 0;
 
-	ret = snd_soc_read(codec, M98090_REG_REVISION_ID);
+	ret = snd_soc_component_read32(component, M98090_REG_REVISION_ID);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read device revision: %d\n",
+		dev_err(component->dev, "Failed to read device revision: %d\n",
 			ret);
 		goto err_access;
 	}
 
 	if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) {
 		devtype = MAX98090;
-		dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret);
+		dev_info(component->dev, "MAX98090 REVID=0x%02x\n", ret);
 	} else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) {
 		devtype = MAX98091;
-		dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret);
+		dev_info(component->dev, "MAX98091 REVID=0x%02x\n", ret);
 	} else {
 		devtype = MAX98090;
-		dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret);
+		dev_err(component->dev, "Unrecognized revision 0x%02x\n", ret);
 	}
 
 	if (max98090->devtype != devtype) {
-		dev_warn(codec->dev, "Mismatch in DT specified CODEC type.\n");
+		dev_warn(component->dev, "Mismatch in DT specified CODEC type.\n");
 		max98090->devtype = devtype;
 	}
 
@@ -2427,7 +2427,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	INIT_WORK(&max98090->pll_work, max98090_pll_work);
 
 	/* Enable jack detection */
-	snd_soc_write(codec, M98090_REG_JACK_DETECT,
+	snd_soc_component_write(component, M98090_REG_JACK_DETECT,
 		M98090_JDETEN_MASK | M98090_JDEB_25MS);
 
 	/*
@@ -2435,75 +2435,76 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	 * An old interrupt ocurring prior to installing the ISR
 	 * can keep a new interrupt from generating a trigger.
 	 */
-	snd_soc_read(codec, M98090_REG_DEVICE_STATUS);
+	snd_soc_component_read32(component, M98090_REG_DEVICE_STATUS);
 
 	/* High Performance is default */
-	snd_soc_update_bits(codec, M98090_REG_DAC_CONTROL,
+	snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
 		M98090_DACHP_MASK,
 		1 << M98090_DACHP_SHIFT);
-	snd_soc_update_bits(codec, M98090_REG_DAC_CONTROL,
+	snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
 		M98090_PERFMODE_MASK,
 		0 << M98090_PERFMODE_SHIFT);
-	snd_soc_update_bits(codec, M98090_REG_ADC_CONTROL,
+	snd_soc_component_update_bits(component, M98090_REG_ADC_CONTROL,
 		M98090_ADCHP_MASK,
 		1 << M98090_ADCHP_SHIFT);
 
 	/* Turn on VCM bandgap reference */
-	snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
+	snd_soc_component_write(component, M98090_REG_BIAS_CONTROL,
 		M98090_VCM_MODE_MASK);
 
-	err = device_property_read_u32(codec->dev, "maxim,micbias", &micbias);
+	err = device_property_read_u32(component->dev, "maxim,micbias", &micbias);
 	if (err) {
 		micbias = M98090_MBVSEL_2V8;
-		dev_info(codec->dev, "use default 2.8v micbias\n");
+		dev_info(component->dev, "use default 2.8v micbias\n");
 	} else if (micbias > M98090_MBVSEL_2V8) {
-		dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
+		dev_err(component->dev, "micbias out of range 0x%x\n", micbias);
 		micbias = M98090_MBVSEL_2V8;
 	}
 
-	snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
+	snd_soc_component_update_bits(component, M98090_REG_MIC_BIAS_VOLTAGE,
 		M98090_MBVSEL_MASK, micbias);
 
-	max98090_add_widgets(codec);
+	max98090_add_widgets(component);
 
 err_access:
 	return ret;
 }
 
-static int max98090_remove(struct snd_soc_codec *codec)
+static void max98090_remove(struct snd_soc_component *component)
 {
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
 	cancel_delayed_work_sync(&max98090->jack_work);
 	cancel_delayed_work_sync(&max98090->pll_det_enable_work);
 	cancel_work_sync(&max98090->pll_det_disable_work);
 	cancel_work_sync(&max98090->pll_work);
-	max98090->codec = NULL;
-
-	return 0;
+	max98090->component = NULL;
 }
 
-static void max98090_seq_notifier(struct snd_soc_dapm_context *dapm,
+static void max98090_seq_notifier(struct snd_soc_component *component,
 	enum snd_soc_dapm_type event, int subseq)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
 
 	if (max98090->shdn_pending) {
-		snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+		snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
 				M98090_SHDNN_MASK, 0);
 		msleep(40);
-		snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+		snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
 				M98090_SHDNN_MASK, M98090_SHDNN_MASK);
 		max98090->shdn_pending = false;
 	}
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98090 = {
-	.probe   = max98090_probe,
-	.remove  = max98090_remove,
-	.seq_notifier = max98090_seq_notifier,
-	.set_bias_level = max98090_set_bias_level,
+static const struct snd_soc_component_driver soc_component_dev_max98090 = {
+	.probe			= max98090_probe,
+	.remove			= max98090_remove,
+	.seq_notifier		= max98090_seq_notifier,
+	.set_bias_level		= max98090_set_bias_level,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config max98090_regmap = {
@@ -2570,8 +2571,8 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_max98090, max98090_dai,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max98090, max98090_dai,
 			ARRAY_SIZE(max98090_dai));
 err_enable:
 	return ret;
@@ -2595,7 +2596,7 @@ static void max98090_i2c_shutdown(struct i2c_client *i2c)
 static int max98090_i2c_remove(struct i2c_client *client)
 {
 	max98090_i2c_shutdown(client);
-	snd_soc_unregister_codec(&client->dev);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index bc610d9a9ecb..b1572a2d19da 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1519,7 +1519,7 @@ struct max98090_cdata {
 
 struct max98090_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	enum max98090_type devtype;
 	struct max98090_pdata *pdata;
 	struct clk *mclk;
@@ -1546,7 +1546,7 @@ struct max98090_priv {
 	bool shdn_pending;
 };
 
-int max98090_mic_detect(struct snd_soc_codec *codec,
+int max98090_mic_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack);
 
 #endif
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 5ead87d2ab1d..6bf2d0ba864f 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -251,7 +251,7 @@ static const struct regmap_config max98095_regmap = {
 /*
  * Load equalizer DSP coefficient configurations registers
  */
-static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+static void m98095_eq_band(struct snd_soc_component *component, unsigned int dai,
 		    unsigned int band, u16 *coefs)
 {
 	unsigned int eq_reg;
@@ -269,15 +269,15 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
 
 	/* Step through the registers and coefs */
 	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
-		snd_soc_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
-		snd_soc_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
+		snd_soc_component_write(component, eq_reg++, M98095_BYTE1(coefs[i]));
+		snd_soc_component_write(component, eq_reg++, M98095_BYTE0(coefs[i]));
 	}
 }
 
 /*
  * Load biquad filter coefficient configurations registers
  */
-static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
+static void m98095_biquad_band(struct snd_soc_component *component, unsigned int dai,
 		    unsigned int band, u16 *coefs)
 {
 	unsigned int bq_reg;
@@ -295,8 +295,8 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
 
 	/* Step through the registers and coefs */
 	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
-		snd_soc_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
-		snd_soc_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
+		snd_soc_component_write(component, bq_reg++, M98095_BYTE1(coefs[i]));
+		snd_soc_component_write(component, bq_reg++, M98095_BYTE0(coefs[i]));
 	}
 }
 
@@ -353,12 +353,12 @@ static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
 static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	unsigned int sel = ucontrol->value.integer.value[0];
 
 	max98095->mic1pre = sel;
-	snd_soc_update_bits(codec, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK,
+	snd_soc_component_update_bits(component, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK,
 		(1+sel)<<M98095_MICPRE_SHIFT);
 
 	return 0;
@@ -367,8 +367,8 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
 static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = max98095->mic1pre;
 	return 0;
@@ -377,12 +377,12 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
 static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	unsigned int sel = ucontrol->value.integer.value[0];
 
 	max98095->mic2pre = sel;
-	snd_soc_update_bits(codec, M98095_060_LVL_MIC2, M98095_MICPRE_MASK,
+	snd_soc_component_update_bits(component, M98095_060_LVL_MIC2, M98095_MICPRE_MASK,
 		(1+sel)<<M98095_MICPRE_SHIFT);
 
 	return 0;
@@ -391,8 +391,8 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
 static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = max98095->mic2pre;
 	return 0;
@@ -598,21 +598,21 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
 static int max98095_mic_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		if (w->reg == M98095_05F_LVL_MIC1) {
-			snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+			snd_soc_component_update_bits(component, w->reg, M98095_MICPRE_MASK,
 				(1+max98095->mic1pre)<<M98095_MICPRE_SHIFT);
 		} else {
-			snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+			snd_soc_component_update_bits(component, w->reg, M98095_MICPRE_MASK,
 				(1+max98095->mic2pre)<<M98095_MICPRE_SHIFT);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, 0);
+		snd_soc_component_update_bits(component, w->reg, M98095_MICPRE_MASK, 0);
 		break;
 	default:
 		return -EINVAL;
@@ -628,8 +628,8 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w,
 static int max98095_line_pga(struct snd_soc_dapm_widget *w,
 			     int event, u8 channel)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	u8 *state;
 
 	if (WARN_ON(!(channel == 1 || channel == 2)))
@@ -640,13 +640,13 @@ static int max98095_line_pga(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		*state |= channel;
-		snd_soc_update_bits(codec, w->reg,
+		snd_soc_component_update_bits(component, w->reg,
 			(1 << w->shift), (1 << w->shift));
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		*state &= ~channel;
 		if (*state == 0) {
-			snd_soc_update_bits(codec, w->reg,
+			snd_soc_component_update_bits(component, w->reg,
 				(1 << w->shift), 0);
 		}
 		break;
@@ -676,15 +676,15 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
 static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, w->reg,
+		snd_soc_component_update_bits(component, w->reg,
 			(1 << (w->shift+2)), (1 << (w->shift+2)));
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, w->reg,
+		snd_soc_component_update_bits(component, w->reg,
 			(1 << (w->shift+2)), 0);
 		break;
 	default:
@@ -942,8 +942,8 @@ static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	unsigned long long ni;
 	unsigned int rate;
@@ -955,11 +955,11 @@ static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_width(params)) {
 	case 16:
-		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+		snd_soc_component_update_bits(component, M98095_02A_DAI1_FORMAT,
 			M98095_DAI_WS, 0);
 		break;
 	case 24:
-		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+		snd_soc_component_update_bits(component, M98095_02A_DAI1_FORMAT,
 			M98095_DAI_WS, M98095_DAI_WS);
 		break;
 	default:
@@ -969,31 +969,31 @@ static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
 	if (rate_value(rate, &regval))
 		return -EINVAL;
 
-	snd_soc_update_bits(codec, M98095_027_DAI1_CLKMODE,
+	snd_soc_component_update_bits(component, M98095_027_DAI1_CLKMODE,
 		M98095_CLKMODE_MASK, regval);
 	cdata->rate = rate;
 
 	/* Configure NI when operating as master */
-	if (snd_soc_read(codec, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) {
+	if (snd_soc_component_read32(component, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) {
 		if (max98095->sysclk == 0) {
-			dev_err(codec->dev, "Invalid system clock frequency\n");
+			dev_err(component->dev, "Invalid system clock frequency\n");
 			return -EINVAL;
 		}
 		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
 				* (unsigned long long int)rate;
 		do_div(ni, (unsigned long long int)max98095->sysclk);
-		snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+		snd_soc_component_write(component, M98095_028_DAI1_CLKCFG_HI,
 			(ni >> 8) & 0x7F);
-		snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+		snd_soc_component_write(component, M98095_029_DAI1_CLKCFG_LO,
 			ni & 0xFF);
 	}
 
 	/* Update sample rate mode */
 	if (rate < 50000)
-		snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+		snd_soc_component_update_bits(component, M98095_02E_DAI1_FILTERS,
 			M98095_DAI_DHF, 0);
 	else
-		snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+		snd_soc_component_update_bits(component, M98095_02E_DAI1_FILTERS,
 			M98095_DAI_DHF, M98095_DAI_DHF);
 
 	return 0;
@@ -1003,8 +1003,8 @@ static int max98095_dai2_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	unsigned long long ni;
 	unsigned int rate;
@@ -1016,11 +1016,11 @@ static int max98095_dai2_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_width(params)) {
 	case 16:
-		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+		snd_soc_component_update_bits(component, M98095_034_DAI2_FORMAT,
 			M98095_DAI_WS, 0);
 		break;
 	case 24:
-		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+		snd_soc_component_update_bits(component, M98095_034_DAI2_FORMAT,
 			M98095_DAI_WS, M98095_DAI_WS);
 		break;
 	default:
@@ -1030,31 +1030,31 @@ static int max98095_dai2_hw_params(struct snd_pcm_substream *substream,
 	if (rate_value(rate, &regval))
 		return -EINVAL;
 
-	snd_soc_update_bits(codec, M98095_031_DAI2_CLKMODE,
+	snd_soc_component_update_bits(component, M98095_031_DAI2_CLKMODE,
 		M98095_CLKMODE_MASK, regval);
 	cdata->rate = rate;
 
 	/* Configure NI when operating as master */
-	if (snd_soc_read(codec, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) {
+	if (snd_soc_component_read32(component, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) {
 		if (max98095->sysclk == 0) {
-			dev_err(codec->dev, "Invalid system clock frequency\n");
+			dev_err(component->dev, "Invalid system clock frequency\n");
 			return -EINVAL;
 		}
 		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
 				* (unsigned long long int)rate;
 		do_div(ni, (unsigned long long int)max98095->sysclk);
-		snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+		snd_soc_component_write(component, M98095_032_DAI2_CLKCFG_HI,
 			(ni >> 8) & 0x7F);
-		snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+		snd_soc_component_write(component, M98095_033_DAI2_CLKCFG_LO,
 			ni & 0xFF);
 	}
 
 	/* Update sample rate mode */
 	if (rate < 50000)
-		snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+		snd_soc_component_update_bits(component, M98095_038_DAI2_FILTERS,
 			M98095_DAI_DHF, 0);
 	else
-		snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+		snd_soc_component_update_bits(component, M98095_038_DAI2_FILTERS,
 			M98095_DAI_DHF, M98095_DAI_DHF);
 
 	return 0;
@@ -1064,8 +1064,8 @@ static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	unsigned long long ni;
 	unsigned int rate;
@@ -1077,11 +1077,11 @@ static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_width(params)) {
 	case 16:
-		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+		snd_soc_component_update_bits(component, M98095_03E_DAI3_FORMAT,
 			M98095_DAI_WS, 0);
 		break;
 	case 24:
-		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+		snd_soc_component_update_bits(component, M98095_03E_DAI3_FORMAT,
 			M98095_DAI_WS, M98095_DAI_WS);
 		break;
 	default:
@@ -1091,31 +1091,31 @@ static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
 	if (rate_value(rate, &regval))
 		return -EINVAL;
 
-	snd_soc_update_bits(codec, M98095_03B_DAI3_CLKMODE,
+	snd_soc_component_update_bits(component, M98095_03B_DAI3_CLKMODE,
 		M98095_CLKMODE_MASK, regval);
 	cdata->rate = rate;
 
 	/* Configure NI when operating as master */
-	if (snd_soc_read(codec, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) {
+	if (snd_soc_component_read32(component, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) {
 		if (max98095->sysclk == 0) {
-			dev_err(codec->dev, "Invalid system clock frequency\n");
+			dev_err(component->dev, "Invalid system clock frequency\n");
 			return -EINVAL;
 		}
 		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
 				* (unsigned long long int)rate;
 		do_div(ni, (unsigned long long int)max98095->sysclk);
-		snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+		snd_soc_component_write(component, M98095_03C_DAI3_CLKCFG_HI,
 			(ni >> 8) & 0x7F);
-		snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+		snd_soc_component_write(component, M98095_03D_DAI3_CLKCFG_LO,
 			ni & 0xFF);
 	}
 
 	/* Update sample rate mode */
 	if (rate < 50000)
-		snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+		snd_soc_component_update_bits(component, M98095_042_DAI3_FILTERS,
 			M98095_DAI_DHF, 0);
 	else
-		snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+		snd_soc_component_update_bits(component, M98095_042_DAI3_FILTERS,
 			M98095_DAI_DHF, M98095_DAI_DHF);
 
 	return 0;
@@ -1124,8 +1124,8 @@ static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
 static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
 				   int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 
 	/* Requested clock frequency is already setup */
 	if (freq == max98095->sysclk)
@@ -1142,13 +1142,13 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
 	 *         0x03 (when master clk is 40MHz to 60MHz)..
 	 */
 	if ((freq >= 10000000) && (freq < 20000000)) {
-		snd_soc_write(codec, M98095_026_SYS_CLK, 0x10);
+		snd_soc_component_write(component, M98095_026_SYS_CLK, 0x10);
 	} else if ((freq >= 20000000) && (freq < 40000000)) {
-		snd_soc_write(codec, M98095_026_SYS_CLK, 0x20);
+		snd_soc_component_write(component, M98095_026_SYS_CLK, 0x20);
 	} else if ((freq >= 40000000) && (freq < 60000000)) {
-		snd_soc_write(codec, M98095_026_SYS_CLK, 0x30);
+		snd_soc_component_write(component, M98095_026_SYS_CLK, 0x30);
 	} else {
-		dev_err(codec->dev, "Invalid master clock frequency\n");
+		dev_err(component->dev, "Invalid master clock frequency\n");
 		return -EINVAL;
 	}
 
@@ -1161,8 +1161,8 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
 static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
 				 unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	u8 regval = 0;
 
@@ -1174,9 +1174,9 @@ static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
 		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 		case SND_SOC_DAIFMT_CBS_CFS:
 			/* Slave mode PLL */
-			snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+			snd_soc_component_write(component, M98095_028_DAI1_CLKCFG_HI,
 				0x80);
-			snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+			snd_soc_component_write(component, M98095_029_DAI1_CLKCFG_LO,
 				0x00);
 			break;
 		case SND_SOC_DAIFMT_CBM_CFM:
@@ -1186,7 +1186,7 @@ static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
 		case SND_SOC_DAIFMT_CBS_CFM:
 		case SND_SOC_DAIFMT_CBM_CFS:
 		default:
-			dev_err(codec->dev, "Clock mode unsupported");
+			dev_err(component->dev, "Clock mode unsupported");
 			return -EINVAL;
 		}
 
@@ -1216,11 +1216,11 @@ static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
 			return -EINVAL;
 		}
 
-		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+		snd_soc_component_update_bits(component, M98095_02A_DAI1_FORMAT,
 			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
 			M98095_DAI_WCI, regval);
 
-		snd_soc_write(codec, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64);
+		snd_soc_component_write(component, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64);
 	}
 
 	return 0;
@@ -1229,8 +1229,8 @@ static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
 static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
 				 unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	u8 regval = 0;
 
@@ -1242,9 +1242,9 @@ static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
 		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 		case SND_SOC_DAIFMT_CBS_CFS:
 			/* Slave mode PLL */
-			snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+			snd_soc_component_write(component, M98095_032_DAI2_CLKCFG_HI,
 				0x80);
-			snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+			snd_soc_component_write(component, M98095_033_DAI2_CLKCFG_LO,
 				0x00);
 			break;
 		case SND_SOC_DAIFMT_CBM_CFM:
@@ -1254,7 +1254,7 @@ static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
 		case SND_SOC_DAIFMT_CBS_CFM:
 		case SND_SOC_DAIFMT_CBM_CFS:
 		default:
-			dev_err(codec->dev, "Clock mode unsupported");
+			dev_err(component->dev, "Clock mode unsupported");
 			return -EINVAL;
 		}
 
@@ -1284,11 +1284,11 @@ static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
 			return -EINVAL;
 		}
 
-		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+		snd_soc_component_update_bits(component, M98095_034_DAI2_FORMAT,
 			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
 			M98095_DAI_WCI, regval);
 
-		snd_soc_write(codec, M98095_035_DAI2_CLOCK,
+		snd_soc_component_write(component, M98095_035_DAI2_CLOCK,
 			M98095_DAI_BSEL64);
 	}
 
@@ -1298,8 +1298,8 @@ static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
 static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
 				 unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	u8 regval = 0;
 
@@ -1311,9 +1311,9 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
 		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 		case SND_SOC_DAIFMT_CBS_CFS:
 			/* Slave mode PLL */
-			snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+			snd_soc_component_write(component, M98095_03C_DAI3_CLKCFG_HI,
 				0x80);
-			snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+			snd_soc_component_write(component, M98095_03D_DAI3_CLKCFG_LO,
 				0x00);
 			break;
 		case SND_SOC_DAIFMT_CBM_CFM:
@@ -1323,7 +1323,7 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
 		case SND_SOC_DAIFMT_CBS_CFM:
 		case SND_SOC_DAIFMT_CBM_CFS:
 		default:
-			dev_err(codec->dev, "Clock mode unsupported");
+			dev_err(component->dev, "Clock mode unsupported");
 			return -EINVAL;
 		}
 
@@ -1353,21 +1353,21 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
 			return -EINVAL;
 		}
 
-		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+		snd_soc_component_update_bits(component, M98095_03E_DAI3_FORMAT,
 			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
 			M98095_DAI_WCI, regval);
 
-		snd_soc_write(codec, M98095_03F_DAI3_CLOCK,
+		snd_soc_component_write(component, M98095_03F_DAI3_CLOCK,
 			M98095_DAI_BSEL64);
 	}
 
 	return 0;
 }
 
-static int max98095_set_bias_level(struct snd_soc_codec *codec,
+static int max98095_set_bias_level(struct snd_soc_component *component,
 				   enum snd_soc_bias_level level)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1385,7 +1385,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
 		if (IS_ERR(max98095->mclk))
 			break;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
 			clk_disable_unprepare(max98095->mclk);
 		} else {
 			ret = clk_prepare_enable(max98095->mclk);
@@ -1395,21 +1395,21 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(max98095->regmap);
 
 			if (ret != 0) {
-				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
 				return ret;
 			}
 		}
 
-		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+		snd_soc_component_update_bits(component, M98095_090_PWR_EN_IN,
 				M98095_MBEN, M98095_MBEN);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+		snd_soc_component_update_bits(component, M98095_090_PWR_EN_IN,
 				M98095_MBEN, 0);
 		regcache_mark_dirty(max98095->regmap);
 		break;
@@ -1494,8 +1494,8 @@ static int max98095_get_eq_channel(const char *name)
 static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_pdata *pdata = max98095->pdata;
 	int channel = max98095_get_eq_channel(kcontrol->id.name);
 	struct max98095_cdata *cdata;
@@ -1528,7 +1528,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
 		}
 	}
 
-	dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+	dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
 		pdata->eq_cfg[best].name,
 		pdata->eq_cfg[best].rate, fs);
 
@@ -1537,29 +1537,29 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
 	regmask = (channel == 0) ? M98095_EQ1EN : M98095_EQ2EN;
 
 	/* Disable filter while configuring, and save current on/off state */
-	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
-	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+	regsave = snd_soc_component_read32(component, M98095_088_CFG_LEVEL);
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
 
 	mutex_lock(&max98095->lock);
-	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
-	m98095_eq_band(codec, channel, 0, coef_set->band1);
-	m98095_eq_band(codec, channel, 1, coef_set->band2);
-	m98095_eq_band(codec, channel, 2, coef_set->band3);
-	m98095_eq_band(codec, channel, 3, coef_set->band4);
-	m98095_eq_band(codec, channel, 4, coef_set->band5);
-	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_eq_band(component, channel, 0, coef_set->band1);
+	m98095_eq_band(component, channel, 1, coef_set->band2);
+	m98095_eq_band(component, channel, 2, coef_set->band3);
+	m98095_eq_band(component, channel, 3, coef_set->band4);
+	m98095_eq_band(component, channel, 4, coef_set->band5);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
 	mutex_unlock(&max98095->lock);
 
 	/* Restore the original on/off state */
-	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
 	return 0;
 }
 
 static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	int channel = max98095_get_eq_channel(kcontrol->id.name);
 	struct max98095_cdata *cdata;
 
@@ -1569,9 +1569,9 @@ static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
+static void max98095_handle_eq_pdata(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_pdata *pdata = max98095->pdata;
 	struct max98095_eq_cfg *cfg;
 	unsigned int cfgcnt;
@@ -1624,14 +1624,14 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
 	max98095->eq_enum.texts = max98095->eq_texts;
 	max98095->eq_enum.items = max98095->eq_textcnt;
 
-	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
+	ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+		dev_err(component->dev, "Failed to add EQ control: %d\n", ret);
 }
 
 static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
 
-static int max98095_get_bq_channel(struct snd_soc_codec *codec,
+static int max98095_get_bq_channel(struct snd_soc_component *component,
 				   const char *name)
 {
 	int i;
@@ -1641,17 +1641,17 @@ static int max98095_get_bq_channel(struct snd_soc_codec *codec,
 			return i;
 
 	/* Shouldn't happen */
-	dev_err(codec->dev, "Bad biquad channel name '%s'\n", name);
+	dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
 	return -EINVAL;
 }
 
 static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_pdata *pdata = max98095->pdata;
-	int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
+	int channel = max98095_get_bq_channel(component, kcontrol->id.name);
 	struct max98095_cdata *cdata;
 	unsigned int sel = ucontrol->value.enumerated.item[0];
 	struct max98095_biquad_cfg *coef_set;
@@ -1682,7 +1682,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
 		}
 	}
 
-	dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+	dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
 		pdata->bq_cfg[best].name,
 		pdata->bq_cfg[best].rate, fs);
 
@@ -1691,27 +1691,27 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
 	regmask = (channel == 0) ? M98095_BQ1EN : M98095_BQ2EN;
 
 	/* Disable filter while configuring, and save current on/off state */
-	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
-	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+	regsave = snd_soc_component_read32(component, M98095_088_CFG_LEVEL);
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
 
 	mutex_lock(&max98095->lock);
-	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
-	m98095_biquad_band(codec, channel, 0, coef_set->band1);
-	m98095_biquad_band(codec, channel, 1, coef_set->band2);
-	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_biquad_band(component, channel, 0, coef_set->band1);
+	m98095_biquad_band(component, channel, 1, coef_set->band2);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
 	mutex_unlock(&max98095->lock);
 
 	/* Restore the original on/off state */
-	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
 	return 0;
 }
 
 static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
-	int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	int channel = max98095_get_bq_channel(component, kcontrol->id.name);
 	struct max98095_cdata *cdata;
 
 	if (channel < 0)
@@ -1723,9 +1723,9 @@ static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
+static void max98095_handle_bq_pdata(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_pdata *pdata = max98095->pdata;
 	struct max98095_biquad_cfg *cfg;
 	unsigned int cfgcnt;
@@ -1779,19 +1779,19 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
 	max98095->bq_enum.texts = max98095->bq_texts;
 	max98095->bq_enum.items = max98095->bq_textcnt;
 
-	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
+	ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret);
+		dev_err(component->dev, "Failed to add Biquad control: %d\n", ret);
 }
 
-static void max98095_handle_pdata(struct snd_soc_codec *codec)
+static void max98095_handle_pdata(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_pdata *pdata = max98095->pdata;
 	u8 regval = 0;
 
 	if (!pdata) {
-		dev_dbg(codec->dev, "No platform data\n");
+		dev_dbg(component->dev, "No platform data\n");
 		return;
 	}
 
@@ -1802,27 +1802,27 @@ static void max98095_handle_pdata(struct snd_soc_codec *codec)
 	if (pdata->digmic_right_mode)
 		regval |= M98095_DIGMIC_R;
 
-	snd_soc_write(codec, M98095_087_CFG_MIC, regval);
+	snd_soc_component_write(component, M98095_087_CFG_MIC, regval);
 
 	/* Configure equalizers */
 	if (pdata->eq_cfgcnt)
-		max98095_handle_eq_pdata(codec);
+		max98095_handle_eq_pdata(component);
 
 	/* Configure bi-quad filters */
 	if (pdata->bq_cfgcnt)
-		max98095_handle_bq_pdata(codec);
+		max98095_handle_bq_pdata(component);
 }
 
 static irqreturn_t max98095_report_jack(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = data;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	unsigned int value;
 	int hp_report = 0;
 	int mic_report = 0;
 
 	/* Read the Jack Status Register */
-	value = snd_soc_read(codec, M98095_007_JACK_AUTO_STS);
+	value = snd_soc_component_read32(component, M98095_007_JACK_AUTO_STS);
 
 	/* If ddone is not set, then detection isn't finished yet */
 	if ((value & M98095_DDONE) == 0)
@@ -1853,9 +1853,9 @@ static irqreturn_t max98095_report_jack(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+static int max98095_jack_detect_enable(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 	int detect_enable = M98095_JDEN;
 	unsigned int slew = M98095_DEFAULT_SLEW_DELAY;
@@ -1866,41 +1866,41 @@ static int max98095_jack_detect_enable(struct snd_soc_codec *codec)
 	if (max98095->pdata->jack_detect_delay)
 		slew = max98095->pdata->jack_detect_delay;
 
-	ret = snd_soc_write(codec, M98095_08E_JACK_DC_SLEW, slew);
+	ret = snd_soc_component_write(component, M98095_08E_JACK_DC_SLEW, slew);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		dev_err(component->dev, "Failed to cfg auto detect %d\n", ret);
 		return ret;
 	}
 
 	/* configure auto detection to be enabled */
-	ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, detect_enable);
+	ret = snd_soc_component_write(component, M98095_089_JACK_DET_AUTO, detect_enable);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		dev_err(component->dev, "Failed to cfg auto detect %d\n", ret);
 		return ret;
 	}
 
 	return ret;
 }
 
-static int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+static int max98095_jack_detect_disable(struct snd_soc_component *component)
 {
 	int ret = 0;
 
 	/* configure auto detection to be disabled */
-	ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, 0x0);
+	ret = snd_soc_component_write(component, M98095_089_JACK_DET_AUTO, 0x0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+		dev_err(component->dev, "Failed to cfg auto detect %d\n", ret);
 		return ret;
 	}
 
 	return ret;
 }
 
-int max98095_jack_detect(struct snd_soc_codec *codec,
+int max98095_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *client = to_i2c_client(codec->dev);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *client = to_i2c_client(component->dev);
 	int ret = 0;
 
 	max98095->headphone_jack = hp_jack;
@@ -1910,44 +1910,44 @@ int max98095_jack_detect(struct snd_soc_codec *codec,
 	if (!hp_jack && !mic_jack)
 		return -EINVAL;
 
-	max98095_jack_detect_enable(codec);
+	max98095_jack_detect_enable(component);
 
 	/* enable interrupts for headphone jack detection */
-	ret = snd_soc_update_bits(codec, M98095_013_JACK_INT_EN,
+	ret = snd_soc_component_update_bits(component, M98095_013_JACK_INT_EN,
 		M98095_IDDONE, M98095_IDDONE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to cfg jack irqs %d\n", ret);
+		dev_err(component->dev, "Failed to cfg jack irqs %d\n", ret);
 		return ret;
 	}
 
-	max98095_report_jack(client->irq, codec);
+	max98095_report_jack(client->irq, component);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(max98095_jack_detect);
 
 #ifdef CONFIG_PM
-static int max98095_suspend(struct snd_soc_codec *codec)
+static int max98095_suspend(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 
 	if (max98095->headphone_jack || max98095->mic_jack)
-		max98095_jack_detect_disable(codec);
+		max98095_jack_detect_disable(component);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
 
-static int max98095_resume(struct snd_soc_codec *codec)
+static int max98095_resume(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *client = to_i2c_client(codec->dev);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *client = to_i2c_client(component->dev);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	if (max98095->headphone_jack || max98095->mic_jack) {
-		max98095_jack_detect_enable(codec);
-		max98095_report_jack(client->irq, codec);
+		max98095_jack_detect_enable(component);
+		max98095_report_jack(client->irq, component);
 	}
 
 	return 0;
@@ -1957,30 +1957,30 @@ static int max98095_resume(struct snd_soc_codec *codec)
 #define max98095_resume NULL
 #endif
 
-static int max98095_reset(struct snd_soc_codec *codec)
+static int max98095_reset(struct snd_soc_component *component)
 {
 	int i, ret;
 
 	/* Gracefully reset the DSP core and the codec hardware
 	 * in a proper sequence */
-	ret = snd_soc_write(codec, M98095_00F_HOST_CFG, 0);
+	ret = snd_soc_component_write(component, M98095_00F_HOST_CFG, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
+		dev_err(component->dev, "Failed to reset DSP: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_write(codec, M98095_097_PWR_SYS, 0);
+	ret = snd_soc_component_write(component, M98095_097_PWR_SYS, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+		dev_err(component->dev, "Failed to reset component: %d\n", ret);
 		return ret;
 	}
 
 	/* Reset to hardware default for registers, as there is not
 	 * a soft reset hardware control register */
 	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
-		ret = snd_soc_write(codec, i, snd_soc_read(codec, i));
+		ret = snd_soc_component_write(component, i, snd_soc_component_read32(component, i));
 		if (ret < 0) {
-			dev_err(codec->dev, "Failed to reset: %d\n", ret);
+			dev_err(component->dev, "Failed to reset: %d\n", ret);
 			return ret;
 		}
 	}
@@ -1988,21 +1988,21 @@ static int max98095_reset(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int max98095_probe(struct snd_soc_codec *codec)
+static int max98095_probe(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
 	struct max98095_cdata *cdata;
 	struct i2c_client *client;
 	int ret = 0;
 
-	max98095->mclk = devm_clk_get(codec->dev, "mclk");
+	max98095->mclk = devm_clk_get(component->dev, "mclk");
 	if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
 
 	/* reset the codec, the DSP core, and disable all interrupts */
-	max98095_reset(codec);
+	max98095_reset(component);
 
-	client = to_i2c_client(codec->dev);
+	client = to_i2c_client(component->dev);
 
 	/* initialize private data */
 
@@ -2037,85 +2037,85 @@ static int max98095_probe(struct snd_soc_codec *codec)
 		ret = request_threaded_irq(client->irq, NULL,
 			max98095_report_jack,
 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
-			IRQF_ONESHOT, "max98095", codec);
+			IRQF_ONESHOT, "max98095", component);
 		if (ret) {
-			dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+			dev_err(component->dev, "Failed to request IRQ: %d\n", ret);
 			goto err_access;
 		}
 	}
 
-	ret = snd_soc_read(codec, M98095_0FF_REV_ID);
+	ret = snd_soc_component_read32(component, M98095_0FF_REV_ID);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failure reading hardware revision: %d\n",
+		dev_err(component->dev, "Failure reading hardware revision: %d\n",
 			ret);
 		goto err_irq;
 	}
-	dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
+	dev_info(component->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
 
-	snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
+	snd_soc_component_write(component, M98095_097_PWR_SYS, M98095_PWRSV);
 
-	snd_soc_write(codec, M98095_048_MIX_DAC_LR,
+	snd_soc_component_write(component, M98095_048_MIX_DAC_LR,
 		M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
 
-	snd_soc_write(codec, M98095_049_MIX_DAC_M,
+	snd_soc_component_write(component, M98095_049_MIX_DAC_M,
 		M98095_DAI2M_TO_DACM|M98095_DAI3M_TO_DACM);
 
-	snd_soc_write(codec, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM);
-	snd_soc_write(codec, M98095_045_CFG_DSP, M98095_DSPNORMAL);
-	snd_soc_write(codec, M98095_04E_CFG_HP, M98095_HPNORMAL);
+	snd_soc_component_write(component, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM);
+	snd_soc_component_write(component, M98095_045_CFG_DSP, M98095_DSPNORMAL);
+	snd_soc_component_write(component, M98095_04E_CFG_HP, M98095_HPNORMAL);
 
-	snd_soc_write(codec, M98095_02C_DAI1_IOCFG,
+	snd_soc_component_write(component, M98095_02C_DAI1_IOCFG,
 		M98095_S1NORMAL|M98095_SDATA);
 
-	snd_soc_write(codec, M98095_036_DAI2_IOCFG,
+	snd_soc_component_write(component, M98095_036_DAI2_IOCFG,
 		M98095_S2NORMAL|M98095_SDATA);
 
-	snd_soc_write(codec, M98095_040_DAI3_IOCFG,
+	snd_soc_component_write(component, M98095_040_DAI3_IOCFG,
 		M98095_S3NORMAL|M98095_SDATA);
 
-	max98095_handle_pdata(codec);
+	max98095_handle_pdata(component);
 
 	/* take the codec out of the shut down */
-	snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,
+	snd_soc_component_update_bits(component, M98095_097_PWR_SYS, M98095_SHDNRUN,
 		M98095_SHDNRUN);
 
 	return 0;
 
 err_irq:
 	if (client->irq)
-		free_irq(client->irq, codec);
+		free_irq(client->irq, component);
 err_access:
 	return ret;
 }
 
-static int max98095_remove(struct snd_soc_codec *codec)
+static void max98095_remove(struct snd_soc_component *component)
 {
-	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *client = to_i2c_client(codec->dev);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *client = to_i2c_client(component->dev);
 
 	if (max98095->headphone_jack || max98095->mic_jack)
-		max98095_jack_detect_disable(codec);
+		max98095_jack_detect_disable(component);
 
 	if (client->irq)
-		free_irq(client->irq, codec);
-
-	return 0;
+		free_irq(client->irq, component);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98095 = {
-	.probe   = max98095_probe,
-	.remove  = max98095_remove,
-	.suspend = max98095_suspend,
-	.resume  = max98095_resume,
-	.set_bias_level = max98095_set_bias_level,
-	.component_driver = {
-		.controls		= max98095_snd_controls,
-		.num_controls		= ARRAY_SIZE(max98095_snd_controls),
-		.dapm_widgets		= max98095_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max98095_dapm_widgets),
-		.dapm_routes		= max98095_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(max98095_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_max98095 = {
+	.probe			= max98095_probe,
+	.remove			= max98095_remove,
+	.suspend		= max98095_suspend,
+	.resume			= max98095_resume,
+	.set_bias_level		= max98095_set_bias_level,
+	.controls		= max98095_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98095_snd_controls),
+	.dapm_widgets		= max98095_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98095_dapm_widgets),
+	.dapm_routes		= max98095_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98095_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int max98095_i2c_probe(struct i2c_client *i2c,
@@ -2142,17 +2142,12 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
 	i2c_set_clientdata(i2c, max98095);
 	max98095->pdata = i2c->dev.platform_data;
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_max98095,
 				     max98095_dai, ARRAY_SIZE(max98095_dai));
 	return ret;
 }
 
-static int max98095_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max98095_i2c_id[] = {
 	{ "max98095", MAX98095 },
 	{ }
@@ -2171,7 +2166,6 @@ static struct i2c_driver max98095_i2c_driver = {
 		.of_match_table = of_match_ptr(max98095_of_match),
 	},
 	.probe  = max98095_i2c_probe,
-	.remove = max98095_i2c_remove,
 	.id_table = max98095_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
index 2ebbe4e894bf..67886cacddb2 100644
--- a/sound/soc/codecs/max98095.h
+++ b/sound/soc/codecs/max98095.h
@@ -315,7 +315,7 @@
 /* Default Delay used in Slew Rate Calculation for Jack detection */
 #define M98095_DEFAULT_SLEW_DELAY		0x18
 
-extern int max98095_jack_detect(struct snd_soc_codec *codec,
+extern int max98095_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
 
 #endif
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 426ed2dae6ca..d469576b5a7b 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -59,27 +59,29 @@ static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
 	{"Speaker", NULL, "HiFi Playback"},
 };
 
-static int max98357a_codec_probe(struct snd_soc_codec *codec)
+static int max98357a_component_probe(struct snd_soc_component *component)
 {
 	struct gpio_desc *sdmode;
 
-	sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW);
+	sdmode = devm_gpiod_get_optional(component->dev, "sdmode", GPIOD_OUT_LOW);
 	if (IS_ERR(sdmode))
 		return PTR_ERR(sdmode);
 
-	snd_soc_codec_set_drvdata(codec, sdmode);
+	snd_soc_component_set_drvdata(component, sdmode);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver max98357a_codec_driver = {
-	.probe			= max98357a_codec_probe,
-	.component_driver = {
-		.dapm_widgets		= max98357a_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
-		.dapm_routes		= max98357a_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
-	},
+static const struct snd_soc_component_driver max98357a_component_driver = {
+	.probe			= max98357a_component_probe,
+	.dapm_widgets		= max98357a_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
+	.dapm_routes		= max98357a_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct snd_soc_dai_ops max98357a_dai_ops = {
@@ -107,14 +109,13 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
 
 static int max98357a_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver,
+	return devm_snd_soc_register_component(&pdev->dev,
+			&max98357a_component_driver,
 			&max98357a_dai_driver, 1);
 }
 
 static int max98357a_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index 7bc2a17c1e94..d4ba1392aaf8 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -187,15 +187,15 @@ static const struct snd_kcontrol_new max98371_snd_controls[] = {
 static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98371_priv *max98371 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		break;
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported");
+		dev_err(component->dev, "DAI clock mode unsupported");
 		return -EINVAL;
 	}
 
@@ -210,7 +210,7 @@ static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		val |= MAX98371_DAI_LEFT;
 		break;
 	default:
-		dev_err(codec->dev, "DAI wrong mode unsupported");
+		dev_err(component->dev, "DAI wrong mode unsupported");
 		return -EINVAL;
 	}
 	regmap_update_bits(max98371->regmap, MAX98371_FMT,
@@ -222,8 +222,8 @@ static int max98371_dai_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98371_priv *max98371 = snd_soc_component_get_drvdata(component);
 	int blr_clk_ratio, ch_size, channels = params_channels(params);
 	int rate = params_rate(params);
 
@@ -348,15 +348,17 @@ static struct snd_soc_dai_driver max98371_dai[] = {
 	}
 };
 
-static const struct snd_soc_codec_driver max98371_codec = {
-	.component_driver = {
-		.controls = max98371_snd_controls,
-		.num_controls = ARRAY_SIZE(max98371_snd_controls),
-		.dapm_routes = max98371_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
-		.dapm_widgets = max98371_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
-	},
+static const struct snd_soc_component_driver max98371_component = {
+	.controls		= max98371_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98371_snd_controls),
+	.dapm_routes		= max98371_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98371_audio_map),
+	.dapm_widgets		= max98371_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98371_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config max98371_regmap = {
@@ -397,21 +399,15 @@ static int max98371_i2c_probe(struct i2c_client *i2c,
 	}
 	dev_info(&i2c->dev, "device version %x\n", reg);
 
-	ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
+	ret = devm_snd_soc_register_component(&i2c->dev, &max98371_component,
 			max98371_dai, ARRAY_SIZE(max98371_dai));
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
 		return ret;
 	}
 	return ret;
 }
 
-static int max98371_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max98371_i2c_id[] = {
 	{ "max98371", 0 },
 	{ }
@@ -432,7 +428,6 @@ static struct i2c_driver max98371_i2c_driver = {
 		.of_match_table = of_match_ptr(max98371_of_match),
 	},
 	.probe  = max98371_i2c_probe,
-	.remove = max98371_i2c_remove,
 	.id_table = max98371_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h
index 9f6330964d98..06e9ba784e0b 100644
--- a/sound/soc/codecs/max98371.h
+++ b/sound/soc/codecs/max98371.h
@@ -62,6 +62,5 @@
 
 struct max98371_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
 };
 #endif
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index 562e88765129..a92586106932 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -112,12 +112,12 @@ static struct reg_default max98373_reg[] = {
 
 static int max98373_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 	unsigned int format = 0;
 	unsigned int invert = 0;
 
-	dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF:
@@ -126,7 +126,7 @@ static int max98373_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		invert = MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported\n");
+		dev_err(component->dev, "DAI invert mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -177,10 +177,10 @@ static int max98373_get_bclk_sel(int bclk)
 	return 0;
 }
 
-static int max98373_set_clock(struct snd_soc_codec *codec,
+static int max98373_set_clock(struct snd_soc_component *component,
 	struct snd_pcm_hw_params *params)
 {
-	struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 	/* BCLK/LRCLK ratio calculation */
 	int blr_clk_ratio = params_channels(params) * max98373->ch_size;
 	int value;
@@ -189,7 +189,7 @@ static int max98373_set_clock(struct snd_soc_codec *codec,
 		/* BCLK configuration */
 		value = max98373_get_bclk_sel(blr_clk_ratio);
 		if (!value) {
-			dev_err(codec->dev, "format unsupported %d\n",
+			dev_err(component->dev, "format unsupported %d\n",
 				params_format(params));
 			return -EINVAL;
 		}
@@ -206,8 +206,8 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 	unsigned int sampling_rate = 0;
 	unsigned int chan_sz = 0;
 
@@ -223,7 +223,7 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
 		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32;
 		break;
 	default:
-		dev_err(codec->dev, "format unsupported %d\n",
+		dev_err(component->dev, "format unsupported %d\n",
 			params_format(params));
 		goto err;
 	}
@@ -234,7 +234,7 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
 		MAX98373_R2024_PCM_DATA_FMT_CFG,
 		MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
 
-	dev_dbg(codec->dev, "format supported %d",
+	dev_dbg(component->dev, "format supported %d",
 		params_format(params));
 
 	/* sampling rate configuration */
@@ -267,7 +267,7 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
 		sampling_rate = MAX98373_PCM_SR_SET1_SR_48000;
 		break;
 	default:
-		dev_err(codec->dev, "rate %d not supported\n",
+		dev_err(component->dev, "rate %d not supported\n",
 			params_rate(params));
 		goto err;
 	}
@@ -295,7 +295,7 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
 			MAX98373_PCM_SR_SET2_IVADC_SR_MASK,
 			sampling_rate);
 
-	return max98373_set_clock(codec, params);
+	return max98373_set_clock(component, params);
 err:
 	return -EINVAL;
 }
@@ -304,8 +304,8 @@ static int max98373_dai_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask,
 	int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 	int bsel = 0;
 	unsigned int chan_sz = 0;
 	unsigned int mask;
@@ -319,7 +319,7 @@ static int max98373_dai_tdm_slot(struct snd_soc_dai *dai,
 	/* BCLK configuration */
 	bsel = max98373_get_bclk_sel(slots * slot_width);
 	if (bsel == 0) {
-		dev_err(codec->dev, "BCLK %d not supported\n",
+		dev_err(component->dev, "BCLK %d not supported\n",
 			slots * slot_width);
 		return -EINVAL;
 	}
@@ -341,7 +341,7 @@ static int max98373_dai_tdm_slot(struct snd_soc_dai *dai,
 		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32;
 		break;
 	default:
-		dev_err(codec->dev, "format unsupported %d\n",
+		dev_err(component->dev, "format unsupported %d\n",
 			slot_width);
 		return -EINVAL;
 	}
@@ -394,8 +394,8 @@ static const struct snd_soc_dai_ops max98373_dai_ops = {
 static int max98373_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -721,11 +721,9 @@ static struct snd_soc_dai_driver max98373_dai[] = {
 	}
 };
 
-static int max98373_probe(struct snd_soc_codec *codec)
+static int max98373_probe(struct snd_soc_component *component)
 {
-	struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec);
-
-	codec->control_data = max98373->regmap;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
 
 	/* Software Reset */
 	regmap_write(max98373->regmap,
@@ -828,16 +826,18 @@ static const struct dev_pm_ops max98373_pm = {
 	SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98373 = {
-	.probe = max98373_probe,
-	.component_driver = {
-		.controls = max98373_snd_controls,
-		.num_controls = ARRAY_SIZE(max98373_snd_controls),
-		.dapm_widgets = max98373_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets),
-		.dapm_routes = max98373_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(max98373_audio_map),
-	},
+static const struct snd_soc_component_driver soc_codec_dev_max98373 = {
+	.probe			= max98373_probe,
+	.controls		= max98373_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98373_snd_controls),
+	.dapm_widgets		= max98373_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98373_dapm_widgets),
+	.dapm_routes		= max98373_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98373_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config max98373_regmap = {
@@ -920,7 +920,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
 	max98373_slot_config(i2c, max98373);
 
 	/* codec registeration */
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98373,
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_max98373,
 		max98373_dai, ARRAY_SIZE(max98373_dai));
 	if (ret < 0)
 		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
@@ -928,12 +928,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
 	return ret;
 }
 
-static int max98373_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max98373_i2c_id[] = {
 	{ "max98373", 0},
 	{ },
@@ -965,7 +959,6 @@ static struct i2c_driver max98373_i2c_driver = {
 		.pm = &max98373_pm,
 	},
 	.probe = max98373_i2c_probe,
-	.remove = max98373_i2c_remove,
 	.id_table = max98373_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index a3dfc918c278..74d7f52c7e73 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -130,8 +130,8 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
 	u64 lrclk_div;
 	u8 sf, da;
 
@@ -139,14 +139,14 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 
 	/* lrclk_div = 2^22 * rate / iclk with iclk = mclk / sf */
-	sf = (snd_soc_read(codec, MAX9850_CLOCK) >> 2) + 1;
+	sf = (snd_soc_component_read32(component, MAX9850_CLOCK) >> 2) + 1;
 	lrclk_div = (1 << 22);
 	lrclk_div *= params_rate(params);
 	lrclk_div *= sf;
 	do_div(lrclk_div, max9850->sysclk);
 
-	snd_soc_write(codec, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
-	snd_soc_write(codec, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
+	snd_soc_component_write(component, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
+	snd_soc_component_write(component, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
 
 	switch (params_width(params)) {
 	case 16:
@@ -161,7 +161,7 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, MAX9850_DIGITAL_AUDIO, 0x3, da);
+	snd_soc_component_update_bits(component, MAX9850_DIGITAL_AUDIO, 0x3, da);
 
 	return 0;
 }
@@ -169,16 +169,16 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,
 static int max9850_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
 
 	/* calculate mclk -> iclk divider */
 	if (freq <= 13000000)
-		snd_soc_write(codec, MAX9850_CLOCK, 0x0);
+		snd_soc_component_write(component, MAX9850_CLOCK, 0x0);
 	else if (freq <= 26000000)
-		snd_soc_write(codec, MAX9850_CLOCK, 0x4);
+		snd_soc_component_write(component, MAX9850_CLOCK, 0x4);
 	else if (freq <= 40000000)
-		snd_soc_write(codec, MAX9850_CLOCK, 0x8);
+		snd_soc_component_write(component, MAX9850_CLOCK, 0x8);
 	else
 		return -EINVAL;
 
@@ -188,7 +188,7 @@ static int max9850_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 da = 0;
 
 	/* set master/slave audio interface */
@@ -234,15 +234,15 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	}
 
 	/* set da */
-	snd_soc_write(codec, MAX9850_DIGITAL_AUDIO, da);
+	snd_soc_component_write(component, MAX9850_DIGITAL_AUDIO, da);
 
 	return 0;
 }
 
-static int max9850_set_bias_level(struct snd_soc_codec *codec,
+static int max9850_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
+	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -251,10 +251,10 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(max9850->regmap);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to sync cache: %d\n", ret);
 				return ret;
 			}
@@ -289,31 +289,32 @@ static struct snd_soc_dai_driver max9850_dai = {
 	.ops = &max9850_dai_ops,
 };
 
-static int max9850_probe(struct snd_soc_codec *codec)
+static int max9850_probe(struct snd_soc_component *component)
 {
 	/* enable zero-detect */
-	snd_soc_update_bits(codec, MAX9850_GENERAL_PURPOSE, 1, 1);
+	snd_soc_component_update_bits(component, MAX9850_GENERAL_PURPOSE, 1, 1);
 	/* enable slew-rate control */
-	snd_soc_update_bits(codec, MAX9850_VOLUME, 0x40, 0x40);
+	snd_soc_component_update_bits(component, MAX9850_VOLUME, 0x40, 0x40);
 	/* set slew-rate 125ms */
-	snd_soc_update_bits(codec, MAX9850_CHARGE_PUMP, 0xff, 0xc0);
+	snd_soc_component_update_bits(component, MAX9850_CHARGE_PUMP, 0xff, 0xc0);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_max9850 = {
-	.probe =	max9850_probe,
-	.set_bias_level = max9850_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= max9850_controls,
-		.num_controls		= ARRAY_SIZE(max9850_controls),
-		.dapm_widgets		= max9850_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max9850_dapm_widgets),
-		.dapm_routes		= max9850_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(max9850_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_max9850 = {
+	.probe			= max9850_probe,
+	.set_bias_level		= max9850_set_bias_level,
+	.controls		= max9850_controls,
+	.num_controls		= ARRAY_SIZE(max9850_controls),
+	.dapm_widgets		= max9850_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9850_dapm_widgets),
+	.dapm_routes		= max9850_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max9850_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int max9850_i2c_probe(struct i2c_client *i2c,
@@ -333,17 +334,11 @@ static int max9850_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, max9850);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_max9850, &max9850_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max9850, &max9850_dai, 1);
 	return ret;
 }
 
-static int max9850_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max9850_i2c_id[] = {
 	{ "max9850", 0 },
 	{ }
@@ -355,7 +350,6 @@ static struct i2c_driver max9850_i2c_driver = {
 		.name = "max9850",
 	},
 	.probe = max9850_i2c_probe,
-	.remove = max9850_i2c_remove,
 	.id_table = max9850_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index a2dc6a47f466..5bbf889ad98e 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -261,8 +261,8 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max9860_priv *max9860 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
 	u8 master;
 	u8 ifc1a = 0;
 	u8 ifc1b = 0;
@@ -270,7 +270,7 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 	unsigned long n;
 	int ret;
 
-	dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n",
+	dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
 		params_rate(params),
 		params_channels(params));
 
@@ -306,7 +306,7 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
 		if (params_width(params) != 16) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"DSP_A works for 16 bits per sample only.\n");
 			return -EINVAL;
 		}
@@ -315,7 +315,7 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
 		if (params_width(params) != 16) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"DSP_B works for 16 bits per sample only.\n");
 			return -EINVAL;
 		}
@@ -352,16 +352,16 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "IFC1A  %02x\n", ifc1a);
+	dev_dbg(component->dev, "IFC1A  %02x\n", ifc1a);
 	ret = regmap_write(max9860->regmap, MAX9860_IFC1A, ifc1a);
 	if (ret) {
-		dev_err(codec->dev, "Failed to set IFC1A: %d\n", ret);
+		dev_err(component->dev, "Failed to set IFC1A: %d\n", ret);
 		return ret;
 	}
-	dev_dbg(codec->dev, "IFC1B  %02x\n", ifc1b);
+	dev_dbg(component->dev, "IFC1B  %02x\n", ifc1b);
 	ret = regmap_write(max9860->regmap, MAX9860_IFC1B, ifc1b);
 	if (ret) {
-		dev_err(codec->dev, "Failed to set IFC1B: %d\n", ret);
+		dev_err(component->dev, "Failed to set IFC1B: %d\n", ret);
 		return ret;
 	}
 
@@ -417,33 +417,33 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	sysclk |= max9860->psclk;
-	dev_dbg(codec->dev, "SYSCLK %02x\n", sysclk);
+	dev_dbg(component->dev, "SYSCLK %02x\n", sysclk);
 	ret = regmap_write(max9860->regmap,
 			   MAX9860_SYSCLK, sysclk);
 	if (ret) {
-		dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+		dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret);
 		return ret;
 	}
-	dev_dbg(codec->dev, "N %lu\n", n);
+	dev_dbg(component->dev, "N %lu\n", n);
 	ret = regmap_write(max9860->regmap,
 			   MAX9860_AUDIOCLKHIGH, n >> 8);
 	if (ret) {
-		dev_err(codec->dev, "Failed to set NHI: %d\n", ret);
+		dev_err(component->dev, "Failed to set NHI: %d\n", ret);
 		return ret;
 	}
 	ret = regmap_write(max9860->regmap,
 			   MAX9860_AUDIOCLKLOW, n & 0xff);
 	if (ret) {
-		dev_err(codec->dev, "Failed to set NLO: %d\n", ret);
+		dev_err(component->dev, "Failed to set NLO: %d\n", ret);
 		return ret;
 	}
 
 	if (!master) {
-		dev_dbg(codec->dev, "Enable PLL\n");
+		dev_dbg(component->dev, "Enable PLL\n");
 		ret = regmap_update_bits(max9860->regmap, MAX9860_AUDIOCLKHIGH,
 					 MAX9860_PLL, MAX9860_PLL);
 		if (ret) {
-			dev_err(codec->dev, "Failed to enable PLL: %d\n", ret);
+			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
 			return ret;
 		}
 	}
@@ -453,8 +453,8 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
 
 static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max9860_priv *max9860 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -500,10 +500,10 @@ static struct snd_soc_dai_driver max9860_dai = {
 	.symmetric_rates = 1,
 };
 
-static int max9860_set_bias_level(struct snd_soc_codec *codec,
+static int max9860_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct max9860_priv *max9860 = dev_get_drvdata(codec->dev);
+	struct max9860_priv *max9860 = dev_get_drvdata(component->dev);
 	int ret;
 
 	switch (level) {
@@ -515,7 +515,7 @@ static int max9860_set_bias_level(struct snd_soc_codec *codec,
 		ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
 					 MAX9860_SHDN, MAX9860_SHDN);
 		if (ret) {
-			dev_err(codec->dev, "Failed to remove SHDN: %d\n", ret);
+			dev_err(component->dev, "Failed to remove SHDN: %d\n", ret);
 			return ret;
 		}
 		break;
@@ -524,7 +524,7 @@ static int max9860_set_bias_level(struct snd_soc_codec *codec,
 		ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
 					 MAX9860_SHDN, 0);
 		if (ret) {
-			dev_err(codec->dev, "Failed to request SHDN: %d\n",
+			dev_err(component->dev, "Failed to request SHDN: %d\n",
 				ret);
 			return ret;
 		}
@@ -534,18 +534,17 @@ static int max9860_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static const struct snd_soc_codec_driver max9860_codec_driver = {
-	.set_bias_level = max9860_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= max9860_controls,
-		.num_controls		= ARRAY_SIZE(max9860_controls),
-		.dapm_widgets		= max9860_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max9860_dapm_widgets),
-		.dapm_routes		= max9860_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(max9860_dapm_routes),
-	},
+static const struct snd_soc_component_driver max9860_component_driver = {
+	.set_bias_level		= max9860_set_bias_level,
+	.controls		= max9860_controls,
+	.num_controls		= ARRAY_SIZE(max9860_controls),
+	.dapm_widgets		= max9860_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9860_dapm_widgets),
+	.dapm_routes		= max9860_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max9860_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 #ifdef CONFIG_PM
@@ -698,7 +697,7 @@ static int max9860_probe(struct i2c_client *i2c,
 	pm_runtime_enable(dev);
 	pm_runtime_idle(dev);
 
-	ret = snd_soc_register_codec(dev, &max9860_codec_driver,
+	ret = devm_snd_soc_register_component(dev, &max9860_component_driver,
 				     &max9860_dai, 1);
 	if (ret) {
 		dev_err(dev, "Failed to register CODEC: %d\n", ret);
@@ -719,7 +718,6 @@ static int max9860_remove(struct i2c_client *i2c)
 	struct device *dev = &i2c->dev;
 	struct max9860_priv *max9860 = dev_get_drvdata(dev);
 
-	snd_soc_unregister_codec(dev);
 	pm_runtime_disable(dev);
 	regulator_disable(max9860->dvddio);
 	return 0;
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 2f60924fe919..a4e8fafb7e6d 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -179,8 +179,8 @@ static inline int get_ni_value(int mclk, int rate)
 static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 	unsigned int ni_h, ni_l;
 	int value;
 
@@ -227,7 +227,7 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
 				bclk_value = MAX9867_IFC1B_PCLK_16;
 				break;
 			default:
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"unsupported sampling rate\n");
 				return -EINVAL;
 			}
@@ -239,7 +239,7 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
 			bclk_value = MAX9867_IFC1B_32BIT;
 			break;
 		default:
-			dev_err(codec->dev, "unsupported sampling rate\n");
+			dev_err(component->dev, "unsupported sampling rate\n");
 			return -EINVAL;
 		}
 		regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
@@ -251,8 +251,8 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
 static int max9867_prepare(struct snd_pcm_substream *substream,
 			 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 
 	regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
 		MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
@@ -261,8 +261,8 @@ static int max9867_prepare(struct snd_pcm_substream *substream,
 
 static int max9867_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 
 	if (mute)
 		regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
@@ -276,8 +276,8 @@ static int max9867_mute(struct snd_soc_dai *dai, int mute)
 static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 	int value = 0;
 
 	/* Set the prescaler based on the master clock frequency*/
@@ -306,8 +306,8 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 	u8 iface1A = 0, iface1B = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -404,25 +404,27 @@ static int max9867_resume(struct device *dev)
 }
 #endif
 
-static int max9867_probe(struct snd_soc_codec *codec)
+static int max9867_probe(struct snd_soc_component *component)
 {
-	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "max98090_probe\n");
-	max9867->codec = codec;
+	dev_dbg(component->dev, "max98090_probe\n");
+	max9867->component = component;
 	return 0;
 }
 
-static const struct snd_soc_codec_driver max9867_codec = {
-	.probe = max9867_probe,
-	.component_driver = {
-		.controls		= max9867_snd_controls,
-		.num_controls		= ARRAY_SIZE(max9867_snd_controls),
-		.dapm_routes		= max9867_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(max9867_audio_map),
-		.dapm_widgets		= max9867_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max9867_dapm_widgets),
-	},
+static const struct snd_soc_component_driver max9867_component = {
+	.probe			= max9867_probe,
+	.controls		= max9867_snd_controls,
+	.num_controls		= ARRAY_SIZE(max9867_snd_controls),
+	.dapm_routes		= max9867_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max9867_audio_map),
+	.dapm_widgets		= max9867_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9867_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static bool max9867_volatile_register(struct device *dev, unsigned int reg)
@@ -497,21 +499,15 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 	dev_info(&i2c->dev, "device revision: %x\n", reg);
-	ret = snd_soc_register_codec(&i2c->dev, &max9867_codec,
+	ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
 			max9867_dai, ARRAY_SIZE(max9867_dai));
 	if (ret < 0) {
-		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
 		return ret;
 	}
 	return ret;
 }
 
-static int max9867_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max9867_i2c_id[] = {
 	{ "max9867", 0 },
 	{ }
@@ -535,7 +531,6 @@ static struct i2c_driver max9867_i2c_driver = {
 		.pm = &max9867_pm_ops,
 	},
 	.probe  = max9867_i2c_probe,
-	.remove = max9867_i2c_remove,
 	.id_table = max9867_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h
index 65590b4ad62a..c0aea3d1f2ba 100644
--- a/sound/soc/codecs/max9867.h
+++ b/sound/soc/codecs/max9867.h
@@ -75,7 +75,7 @@
 /* codec private data */
 struct max9867_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	unsigned int sysclk;
 	unsigned int pclk;
 	unsigned int master;
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index 921f95fc396d..29877730a2b0 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -99,8 +99,8 @@ static const struct snd_kcontrol_new max98925_dai_sel_mux =
 static int max98925_dac_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -256,7 +256,7 @@ static const struct {
 	},
 };
 
-static inline int max98925_rate_value(struct snd_soc_codec *codec,
+static inline int max98925_rate_value(struct snd_soc_component *component,
 		int rate, int clock, int *value, int *n, int *m)
 {
 	int ret = -EINVAL;
@@ -297,11 +297,11 @@ static void max98925_set_sense_data(struct max98925_priv *max98925)
 static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
 				 unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
 	unsigned int invert = 0;
 
-	dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* set DAI to slave mode */
@@ -322,7 +322,7 @@ static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
 	case SND_SOC_DAIFMT_CBS_CFM:
 	case SND_SOC_DAIFMT_CBM_CFS:
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported");
+		dev_err(component->dev, "DAI clock mode unsupported");
 		return -EINVAL;
 	}
 
@@ -339,7 +339,7 @@ static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported");
+		dev_err(component->dev, "DAI invert mode unsupported");
 		return -EINVAL;
 	}
 
@@ -352,7 +352,7 @@ static int max98925_set_clock(struct max98925_priv *max98925,
 		struct snd_pcm_hw_params *params)
 {
 	unsigned int dai_sr = 0, clock, mdll, n, m;
-	struct snd_soc_codec *codec = max98925->codec;
+	struct snd_soc_component *component = max98925->component;
 	int rate = params_rate(params);
 	/* BCLK/LRCLK ratio calculation */
 	int blr_clk_ratio = params_channels(params) * max98925->ch_size;
@@ -395,12 +395,12 @@ static int max98925_set_clock(struct max98925_priv *max98925,
 		mdll  = M98925_MDLL_MULT_MCLKx8;
 		break;
 	default:
-		dev_info(max98925->codec->dev, "unsupported sysclk %d\n",
+		dev_info(max98925->component->dev, "unsupported sysclk %d\n",
 					max98925->sysclk);
 		return -EINVAL;
 	}
 
-	if (max98925_rate_value(codec, rate, clock, &dai_sr, &n, &m))
+	if (max98925_rate_value(component, rate, clock, &dai_sr, &n, &m))
 		return -EINVAL;
 
 	/* set DAI_SR to correct LRCLK frequency */
@@ -427,8 +427,8 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
 
 	switch (params_width(params)) {
 	case 16:
@@ -454,7 +454,7 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
 				__func__, params_format(params));
 		return -EINVAL;
 	}
-	dev_dbg(codec->dev, "%s: format supported %d",
+	dev_dbg(component->dev, "%s: format supported %d",
 				__func__, params_format(params));
 	return max98925_set_clock(max98925, params);
 }
@@ -462,8 +462,8 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
 static int max98925_dai_set_sysclk(struct snd_soc_dai *dai,
 				   int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case 0:
@@ -516,11 +516,11 @@ static struct snd_soc_dai_driver max98925_dai[] = {
 	}
 };
 
-static int max98925_probe(struct snd_soc_codec *codec)
+static int max98925_probe(struct snd_soc_component *component)
 {
-	struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec);
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
 
-	max98925->codec = codec;
+	max98925->component = component;
 	regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00);
 	/* It's not the default but we need to set DAI_DLY */
 	regmap_write(max98925->regmap,
@@ -538,16 +538,18 @@ static int max98925_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98925 = {
-	.probe            = max98925_probe,
-	.component_driver = {
-		.controls		= max98925_snd_controls,
-		.num_controls		= ARRAY_SIZE(max98925_snd_controls),
-		.dapm_routes		= max98925_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(max98925_audio_map),
-		.dapm_widgets		= max98925_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max98925_dapm_widgets),
-	},
+static const struct snd_soc_component_driver soc_component_dev_max98925 = {
+	.probe			= max98925_probe,
+	.controls		= max98925_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98925_snd_controls),
+	.dapm_routes		= max98925_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98925_audio_map),
+	.dapm_widgets		= max98925_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98925_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config max98925_regmap = {
@@ -612,20 +614,15 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
 
 	dev_info(&i2c->dev, "device version 0x%02X\n", reg);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max98925,
 			max98925_dai, ARRAY_SIZE(max98925_dai));
 	if (ret < 0)
 		dev_err(&i2c->dev,
-				"Failed to register codec: %d\n", ret);
+				"Failed to register component: %d\n", ret);
 	return ret;
 }
 
-static int max98925_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max98925_i2c_id[] = {
 	{ "max98925", 0 },
 	{ }
@@ -645,7 +642,6 @@ static struct i2c_driver max98925_i2c_driver = {
 		.pm = NULL,
 	},
 	.probe  = max98925_i2c_probe,
-	.remove = max98925_i2c_remove,
 	.id_table = max98925_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h
index 3783248f2780..96f97085328d 100644
--- a/sound/soc/codecs/max98925.h
+++ b/sound/soc/codecs/max98925.h
@@ -821,7 +821,7 @@
 
 struct max98925_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct max98925_pdata *pdata;
 	unsigned int sysclk;
 	unsigned int v_slot;
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index 7b1d1b0fa879..d9b1f68f243d 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -336,18 +336,18 @@ static void max98926_set_sense_data(struct max98926_priv *max98926)
 static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component);
 	unsigned int invert = 0;
 
-	dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		max98926_set_sense_data(max98926);
 		break;
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported\n");
+		dev_err(component->dev, "DAI clock mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -364,7 +364,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai,
 		invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported\n");
+		dev_err(component->dev, "DAI invert mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -381,8 +381,8 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
 {
 	int dai_sr = -EINVAL;
 	int rate = params_rate(params), i;
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component);
 	int blr_clk_ratio;
 
 	switch (params_format(params)) {
@@ -408,7 +408,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
 		max98926->ch_size = 32;
 		break;
 	default:
-		dev_dbg(codec->dev, "format unsupported %d\n",
+		dev_dbg(component->dev, "format unsupported %d\n",
 			params_format(params));
 		return -EINVAL;
 	}
@@ -485,27 +485,29 @@ static struct snd_soc_dai_driver max98926_dai[] = {
 }
 };
 
-static int max98926_probe(struct snd_soc_codec *codec)
+static int max98926_probe(struct snd_soc_component *component)
 {
-	struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec);
+	struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component);
 
-	max98926->codec = codec;
+	max98926->component = component;
 
 	/* Hi-Z all the slots */
 	regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0);
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98926 = {
-	.probe	= max98926_probe,
-	.component_driver = {
-		.controls		= max98926_snd_controls,
-		.num_controls		= ARRAY_SIZE(max98926_snd_controls),
-		.dapm_routes		= max98926_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(max98926_audio_map),
-		.dapm_widgets		= max98926_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(max98926_dapm_widgets),
-	},
+static const struct snd_soc_component_driver soc_component_dev_max98926 = {
+	.probe			= max98926_probe,
+	.controls		= max98926_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98926_snd_controls),
+	.dapm_routes		= max98926_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98926_audio_map),
+	.dapm_widgets		= max98926_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98926_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config max98926_regmap = {
@@ -563,22 +565,17 @@ static int max98926_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98926,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max98926,
 			max98926_dai, ARRAY_SIZE(max98926_dai));
 	if (ret < 0)
 		dev_err(&i2c->dev,
-				"Failed to register codec: %d\n", ret);
+				"Failed to register component: %d\n", ret);
 	dev_info(&i2c->dev, "device version: %x\n", reg);
 err_out:
 	return ret;
 }
 
-static int max98926_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max98926_i2c_id[] = {
 	{ "max98926", 0 },
 	{ }
@@ -598,7 +595,6 @@ static struct i2c_driver max98926_i2c_driver = {
 		.pm = NULL,
 	},
 	.probe	= max98926_i2c_probe,
-	.remove = max98926_i2c_remove,
 	.id_table = max98926_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max98926.h b/sound/soc/codecs/max98926.h
index 9d7ab6df79ca..ccf2c3f66c07 100644
--- a/sound/soc/codecs/max98926.h
+++ b/sound/soc/codecs/max98926.h
@@ -838,7 +838,7 @@
 
 struct max98926_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	unsigned int sysclk;
 	unsigned int v_slot;
 	unsigned int i_slot;
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index f701fdc81175..065303a46535 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -142,14 +142,14 @@ static struct reg_default max98927_reg[] = {
 
 static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
 	unsigned int mode = 0;
 	unsigned int format = 0;
 	bool use_pdm = false;
 	unsigned int invert = 0;
 
-	dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
@@ -160,7 +160,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		mode = MAX98927_PCM_MASTER_MODE_MASTER;
 		break;
 	default:
-		dev_err(codec->dev, "DAI clock mode unsupported\n");
+		dev_err(component->dev, "DAI clock mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -176,7 +176,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
 		break;
 	default:
-		dev_err(codec->dev, "DAI invert mode unsupported\n");
+		dev_err(component->dev, "DAI invert mode unsupported\n");
 		return -EINVAL;
 	}
 
@@ -268,7 +268,7 @@ static int max98927_get_bclk_sel(int bclk)
 static int max98927_set_clock(struct max98927_priv *max98927,
 	struct snd_pcm_hw_params *params)
 {
-	struct snd_soc_codec *codec = max98927->codec;
+	struct snd_soc_component *component = max98927->component;
 	/* BCLK/LRCLK ratio calculation */
 	int blr_clk_ratio = params_channels(params) * max98927->ch_size;
 	int value;
@@ -281,7 +281,7 @@ static int max98927_set_clock(struct max98927_priv *max98927,
 				break;
 		}
 		if (i == ARRAY_SIZE(rate_table)) {
-			dev_err(codec->dev, "failed to find proper clock rate.\n");
+			dev_err(component->dev, "failed to find proper clock rate.\n");
 			return -EINVAL;
 		}
 		regmap_update_bits(max98927->regmap,
@@ -294,7 +294,7 @@ static int max98927_set_clock(struct max98927_priv *max98927,
 		/* BCLK configuration */
 		value = max98927_get_bclk_sel(blr_clk_ratio);
 		if (!value) {
-			dev_err(codec->dev, "format unsupported %d\n",
+			dev_err(component->dev, "format unsupported %d\n",
 				params_format(params));
 			return -EINVAL;
 		}
@@ -311,8 +311,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
 	unsigned int sampling_rate = 0;
 	unsigned int chan_sz = 0;
 
@@ -328,7 +328,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
 		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
 		break;
 	default:
-		dev_err(codec->dev, "format unsupported %d\n",
+		dev_err(component->dev, "format unsupported %d\n",
 			params_format(params));
 		goto err;
 	}
@@ -339,7 +339,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
 		MAX98927_R0020_PCM_MODE_CFG,
 		MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
 
-	dev_dbg(codec->dev, "format supported %d",
+	dev_dbg(component->dev, "format supported %d",
 		params_format(params));
 
 	/* sampling rate configuration */
@@ -372,7 +372,7 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
 		sampling_rate = MAX98927_PCM_SR_SET1_SR_48000;
 		break;
 	default:
-		dev_err(codec->dev, "rate %d not supported\n",
+		dev_err(component->dev, "rate %d not supported\n",
 			params_rate(params));
 		goto err;
 	}
@@ -407,8 +407,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask,
 	int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
 	int bsel = 0;
 	unsigned int chan_sz = 0;
 
@@ -417,7 +417,7 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
 	/* BCLK configuration */
 	bsel = max98927_get_bclk_sel(slots * slot_width);
 	if (bsel == 0) {
-		dev_err(codec->dev, "BCLK %d not supported\n",
+		dev_err(component->dev, "BCLK %d not supported\n",
 			slots * slot_width);
 		return -EINVAL;
 	}
@@ -439,7 +439,7 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
 		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
 		break;
 	default:
-		dev_err(codec->dev, "format unsupported %d\n",
+		dev_err(component->dev, "format unsupported %d\n",
 			slot_width);
 		return -EINVAL;
 	}
@@ -483,8 +483,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
 static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
 	int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
 
 	max98927->sysclk = freq;
 	return 0;
@@ -500,8 +500,8 @@ static const struct snd_soc_dai_ops max98927_dai_ops = {
 static int max98927_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -677,11 +677,11 @@ static struct snd_soc_dai_driver max98927_dai[] = {
 	}
 };
 
-static int max98927_probe(struct snd_soc_codec *codec)
+static int max98927_probe(struct snd_soc_component *component)
 {
-	struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
 
-	max98927->codec = codec;
+	max98927->component = component;
 
 	/* Software Reset */
 	regmap_write(max98927->regmap,
@@ -823,16 +823,18 @@ static const struct dev_pm_ops max98927_pm = {
 	SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume)
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
-	.probe = max98927_probe,
-	.component_driver = {
-		.controls = max98927_snd_controls,
-		.num_controls = ARRAY_SIZE(max98927_snd_controls),
-		.dapm_widgets = max98927_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets),
-		.dapm_routes = max98927_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_max98927 = {
+	.probe			= max98927_probe,
+	.controls		= max98927_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98927_snd_controls),
+	.dapm_widgets		= max98927_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98927_dapm_widgets),
+	.dapm_routes		= max98927_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98927_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config max98927_regmap = {
@@ -914,20 +916,15 @@ static int max98927_i2c_probe(struct i2c_client *i2c,
 	max98927_slot_config(i2c, max98927);
 
 	/* codec registeration */
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+		&soc_component_dev_max98927,
 		max98927_dai, ARRAY_SIZE(max98927_dai));
 	if (ret < 0)
-		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
 
 	return ret;
 }
 
-static int max98927_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id max98927_i2c_id[] = {
 	{ "max98927", 0},
 	{ },
@@ -959,7 +956,6 @@ static struct i2c_driver max98927_i2c_driver = {
 		.pm = &max98927_pm,
 	},
 	.probe  = max98927_i2c_probe,
-	.remove = max98927_i2c_remove,
 	.id_table = max98927_i2c_id,
 };
 
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
index 9ea839735433..42a9a244a9db 100644
--- a/sound/soc/codecs/max98927.h
+++ b/sound/soc/codecs/max98927.h
@@ -258,7 +258,7 @@
 
 struct max98927_priv {
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct max98927_pdata *pdata;
 	unsigned int spk_gain;
 	unsigned int sysclk;
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index be7a45f05bbf..7b0d2610cd27 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -107,13 +107,13 @@ static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int rate = params_rate(params);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
 		if (rate == mc13783_rates[i]) {
-			snd_soc_update_bits(codec, MC13783_AUDIO_DAC,
+			snd_soc_component_update_bits(component, MC13783_AUDIO_DAC,
 					0xf << 17, i << 17);
 			return 0;
 		}
@@ -126,7 +126,7 @@ static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int rate = params_rate(params);
 	unsigned int val;
 
@@ -141,7 +141,7 @@ static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
+	snd_soc_component_update_bits(component, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
 			val);
 
 	return 0;
@@ -160,7 +160,7 @@ static int mc13783_pcm_hw_params_sync(struct snd_pcm_substream *substream,
 static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
 			unsigned int reg)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val = 0;
 	unsigned int mask = AUDIO_CFS(3) | AUDIO_BCL_INV | AUDIO_CFS_INV |
 				AUDIO_CSM | AUDIO_C_CLK_EN | AUDIO_C_RESET;
@@ -208,7 +208,7 @@ static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
 
 	val |= AUDIO_C_RESET;
 
-	snd_soc_update_bits(codec, reg, mask, val);
+	snd_soc_component_update_bits(component, reg, mask, val);
 
 	return 0;
 }
@@ -255,7 +255,7 @@ static int mc13783_set_sysclk(struct snd_soc_dai *dai,
 				  int clk_id, unsigned int freq, int dir,
 				  unsigned int reg)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int clk;
 	unsigned int val = 0;
 	unsigned int mask = AUDIO_CLK(0x7) | AUDIO_CLK_SEL;
@@ -275,7 +275,7 @@ static int mc13783_set_sysclk(struct snd_soc_dai *dai,
 
 	val |= AUDIO_CLK(clk);
 
-	snd_soc_update_bits(codec, reg, mask, val);
+	snd_soc_component_update_bits(component, reg, mask, val);
 
 	return 0;
 }
@@ -308,7 +308,7 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots,
 	int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val = 0;
 	unsigned int mask = SSI_NETWORK_DAC_SLOT_MASK |
 				SSI_NETWORK_DAC_RXSLOT_MASK;
@@ -344,7 +344,7 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+	snd_soc_component_update_bits(component, MC13783_SSI_NETWORK, mask, val);
 
 	return 0;
 }
@@ -353,7 +353,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots,
 	int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val = 0;
 	unsigned int mask = 0x3f;
 
@@ -366,7 +366,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
 	val |= (0x00 << 2);	/* primary timeslot RX/TX(?) is 0 */
 	val |= (0x01 << 4);	/* secondary timeslot TX is 1 */
 
-	snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+	snd_soc_component_update_bits(component, MC13783_SSI_NETWORK, mask, val);
 
 	return 0;
 }
@@ -606,12 +606,12 @@ static struct snd_kcontrol_new mc13783_control_list[] = {
 	SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),
 };
 
-static int mc13783_probe(struct snd_soc_codec *codec)
+static int mc13783_probe(struct snd_soc_component *component)
 {
-	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct mc13783_priv *priv = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_init_regmap(codec,
-				  dev_get_regmap(codec->dev->parent, NULL));
+	snd_soc_component_init_regmap(component,
+				  dev_get_regmap(component->dev->parent, NULL));
 
 	/* these are the reset values */
 	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
@@ -638,14 +638,12 @@ static int mc13783_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int mc13783_remove(struct snd_soc_codec *codec)
+static void mc13783_remove(struct snd_soc_component *component)
 {
-	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct mc13783_priv *priv = snd_soc_component_get_drvdata(component);
 
 	/* Make sure VAUDIOON is off */
 	mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
-
-	return 0;
 }
 
 #define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
@@ -731,17 +729,19 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
 	}
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
-	.probe		= mc13783_probe,
-	.remove		= mc13783_remove,
-	.component_driver = {
-		.controls		= mc13783_control_list,
-		.num_controls		= ARRAY_SIZE(mc13783_control_list),
-		.dapm_widgets		= mc13783_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(mc13783_dapm_widgets),
-		.dapm_routes		= mc13783_routes,
-		.num_dapm_routes	= ARRAY_SIZE(mc13783_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_mc13783 = {
+	.probe			= mc13783_probe,
+	.remove			= mc13783_remove,
+	.controls		= mc13783_control_list,
+	.num_controls		= ARRAY_SIZE(mc13783_control_list),
+	.dapm_widgets		= mc13783_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(mc13783_dapm_widgets),
+	.dapm_routes		= mc13783_routes,
+	.num_dapm_routes	= ARRAY_SIZE(mc13783_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int __init mc13783_codec_probe(struct platform_device *pdev)
@@ -782,10 +782,10 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
 	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
 
 	if (priv->adc_ssi_port == priv->dac_ssi_port)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+		ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_mc13783,
 			mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
 	else
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+		ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_mc13783,
 			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
 
 	return ret;
@@ -793,8 +793,6 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
 
 static int mc13783_codec_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 5cc960d8211e..a5fa490dc145 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -338,8 +338,8 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *hw_params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
 	int i = get_coeff(priv->mclk, params_rate(hw_params));
 	int srate;
 
@@ -351,23 +351,23 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,
 	if (priv->clk_in) {
 		switch (priv->mclk / params_rate(hw_params)) {
 		case 256:
-			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+			snd_soc_component_update_bits(component, ML26124_CLK_CTL,
 					    BIT(0) | BIT(1), 1);
 			break;
 		case 512:
-			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+			snd_soc_component_update_bits(component, ML26124_CLK_CTL,
 					    BIT(0) | BIT(1), 2);
 			break;
 		case 1024:
-			snd_soc_update_bits(codec, ML26124_CLK_CTL,
+			snd_soc_component_update_bits(component, ML26124_CLK_CTL,
 					    BIT(0) | BIT(1), 3);
 			break;
 		default:
-			dev_err(codec->dev, "Unsupported MCLKI\n");
+			dev_err(component->dev, "Unsupported MCLKI\n");
 			break;
 		}
 	} else {
-		snd_soc_update_bits(codec, ML26124_CLK_CTL,
+		snd_soc_component_update_bits(component, ML26124_CLK_CTL,
 				    BIT(0) | BIT(1), 0);
 	}
 
@@ -375,35 +375,35 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,
 	if (srate < 0)
 		return srate;
 
-	snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf, srate);
-	snd_soc_update_bits(codec, ML26124_PLLNL, 0xff, coeff_div[i].pllnl);
-	snd_soc_update_bits(codec, ML26124_PLLNH, 0x1, coeff_div[i].pllnh);
-	snd_soc_update_bits(codec, ML26124_PLLML, 0xff, coeff_div[i].pllml);
-	snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f, coeff_div[i].pllmh);
-	snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f, coeff_div[i].plldiv);
+	snd_soc_component_update_bits(component, ML26124_SMPLING_RATE, 0xf, srate);
+	snd_soc_component_update_bits(component, ML26124_PLLNL, 0xff, coeff_div[i].pllnl);
+	snd_soc_component_update_bits(component, ML26124_PLLNH, 0x1, coeff_div[i].pllnh);
+	snd_soc_component_update_bits(component, ML26124_PLLML, 0xff, coeff_div[i].pllml);
+	snd_soc_component_update_bits(component, ML26124_PLLMH, 0x3f, coeff_div[i].pllmh);
+	snd_soc_component_update_bits(component, ML26124_PLLDIV, 0x1f, coeff_div[i].plldiv);
 
 	return 0;
 }
 
 static int ml26124_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
 
 	switch (priv->substream->stream) {
 	case SNDRV_PCM_STREAM_CAPTURE:
-		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
+		snd_soc_component_update_bits(component, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
 		break;
 	case SNDRV_PCM_STREAM_PLAYBACK:
-		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
+		snd_soc_component_update_bits(component, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
 		break;
 	}
 
 	if (mute)
-		snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+		snd_soc_component_update_bits(component, ML26124_DVOL_CTL, BIT(4),
 				    DVOL_CTL_DVMUTE_ON);
 	else
-		snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+		snd_soc_component_update_bits(component, ML26124_DVOL_CTL, BIT(4),
 				    DVOL_CTL_DVMUTE_OFF);
 
 	return 0;
@@ -413,7 +413,7 @@ static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
 	unsigned char mode;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -426,7 +426,7 @@ static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, ML26124_SAI_MODE_SEL, BIT(0), mode);
+	snd_soc_component_update_bits(component, ML26124_SAI_MODE_SEL, BIT(0), mode);
 
 	/* interface format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -450,8 +450,8 @@ static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int ml26124_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case ML26124_USE_PLLOUT:
@@ -469,17 +469,17 @@ static int ml26124_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int ml26124_set_bias_level(struct snd_soc_codec *codec,
+static int ml26124_set_bias_level(struct snd_soc_component *component,
 		enum snd_soc_bias_level level)
 {
-	struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+		snd_soc_component_update_bits(component, ML26124_PW_SPAMP_PW_MNG,
 				    ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
 		msleep(100);
-		snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+		snd_soc_component_update_bits(component, ML26124_PW_SPAMP_PW_MNG,
 				    ML26124_R26_MASK,
 				    ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
 		break;
@@ -487,8 +487,8 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* VMID ON */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, ML26124_PW_REF_PW_MNG,
 					    ML26124_VMID, ML26124_VMID);
 			msleep(500);
 			regcache_sync(priv->regmap);
@@ -496,7 +496,7 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* VMID OFF */
-		snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+		snd_soc_component_update_bits(component, ML26124_PW_REF_PW_MNG,
 				    ML26124_VMID, 0);
 		break;
 	}
@@ -528,27 +528,29 @@ static struct snd_soc_dai_driver ml26124_dai = {
 	.symmetric_rates = 1,
 };
 
-static int ml26124_probe(struct snd_soc_codec *codec)
+static int ml26124_probe(struct snd_soc_component *component)
 {
 	/* Software Reset */
-	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
-	snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
+	snd_soc_component_update_bits(component, ML26124_SW_RST, 0x01, 1);
+	snd_soc_component_update_bits(component, ML26124_SW_RST, 0x01, 0);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
-	.probe =	ml26124_probe,
-	.set_bias_level = ml26124_set_bias_level,
-	.suspend_bias_off = true,
-	.component_driver = {
-		.controls		= ml26124_snd_controls,
-		.num_controls		= ARRAY_SIZE(ml26124_snd_controls),
-		.dapm_widgets		= ml26124_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ml26124_dapm_widgets),
-		.dapm_routes		= ml26124_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(ml26124_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ml26124 = {
+	.probe			= ml26124_probe,
+	.set_bias_level		= ml26124_set_bias_level,
+	.controls		= ml26124_snd_controls,
+	.num_controls		= ARRAY_SIZE(ml26124_snd_controls),
+	.dapm_widgets		= ml26124_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ml26124_dapm_widgets),
+	.dapm_routes		= ml26124_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ml26124_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ml26124_i2c_regmap = {
@@ -580,14 +582,8 @@ static int ml26124_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	return snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_ml26124, &ml26124_dai, 1);
-}
-
-static int ml26124_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_ml26124, &ml26124_dai, 1);
 }
 
 static const struct i2c_device_id ml26124_i2c_id[] = {
@@ -601,7 +597,6 @@ static struct i2c_driver ml26124_i2c_driver = {
 		.name = "ml26124",
 	},
 	.probe = ml26124_i2c_probe,
-	.remove = ml26124_i2c_remove,
 	.id_table = ml26124_i2c_id,
 };
 
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index 44062bb7bf2f..12ee83d52405 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -288,7 +288,7 @@ struct pm8916_wcd_analog_priv {
 	int	mbhc_btn0_released;
 	bool	detect_accessory_type;
 	struct clk *mclk;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 	struct snd_soc_jack *jack;
 	bool hphl_jack_type_normally_open;
@@ -338,18 +338,18 @@ static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = {
 	SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain),
 };
 
-static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
+static void pm8916_wcd_analog_micbias_enable(struct snd_soc_component *component)
 {
-	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
-	snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+	snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
 			    MICB_1_CTL_EXT_PRECHARG_EN_MASK |
 			    MICB_1_CTL_INT_PRECHARG_BYP_MASK,
 			    MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
 			    | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
 
 	if (wcd->micbias_mv) {
-		snd_soc_update_bits(codec, CDC_A_MICB_1_VAL,
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_VAL,
 				    MICB_1_VAL_MICB_OUT_VAL_MASK,
 				    MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
 		/*
@@ -360,20 +360,20 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
 			msleep(50);
 	}
 
-	snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+	snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
 			    MICB_1_CTL_EXT_PRECHARG_EN_MASK |
 			    MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
 
 }
 
-static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
-						 *codec, int event,
+static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_component
+						 *component, int event,
 						 int reg, unsigned int cap_mode)
 {
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		pm8916_wcd_analog_micbias_enable(codec);
-		snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+		pm8916_wcd_analog_micbias_enable(component);
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
 				    MICB_1_EN_BYP_CAP_MASK, cap_mode);
 		break;
 	}
@@ -381,25 +381,25 @@ static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
 	return 0;
 }
 
-static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_codec
-						 *codec, int event,
+static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_component
+						 *component, int event,
 						 int reg, u32 cap_mode)
 {
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
 				    MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
 				    MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
-		snd_soc_update_bits(codec, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0);
-		snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+		snd_soc_component_update_bits(component, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0);
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
 				    MICB_1_EN_OPA_STG2_TAIL_CURR_MASK,
 				    MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA);
 
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pm8916_wcd_analog_micbias_enable(codec);
-		snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+		pm8916_wcd_analog_micbias_enable(component);
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
 				    MICB_1_EN_BYP_CAP_MASK, cap_mode);
 		break;
 	}
@@ -412,10 +412,10 @@ static int pm8916_wcd_analog_enable_micbias_ext1(struct
 						  *w, struct snd_kcontrol
 						  *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
-	return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg,
+	return pm8916_wcd_analog_enable_micbias_ext(component, event, w->reg,
 						     wcd->micbias1_cap_mode);
 }
 
@@ -424,10 +424,10 @@ static int pm8916_wcd_analog_enable_micbias_ext2(struct
 						  *w, struct snd_kcontrol
 						  *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
-	return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg,
+	return pm8916_wcd_analog_enable_micbias_ext(component, event, w->reg,
 						     wcd->micbias2_cap_mode);
 
 }
@@ -437,35 +437,35 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
 						  *w, struct snd_kcontrol
 						  *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
-	return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
+	return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg,
 						     wcd->micbias1_cap_mode);
 }
 
 static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
 				      bool micbias2_enabled)
 {
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_component *component = priv->component;
 	u32 coarse, fine, reg_val, reg_addr;
 	int *vrefs, i;
 
 	if (!micbias2_enabled) { /* use internal 100uA Current source */
 		/* Enable internal 2.2k Internal Rbias Resistor */
-		snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
 				    MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
 				    MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
 		/* Remove pull down on MIC BIAS2 */
-		snd_soc_update_bits(codec, CDC_A_MICB_2_EN,
+		snd_soc_component_update_bits(component, CDC_A_MICB_2_EN,
 				   CDC_A_MICB_2_PULL_DOWN_EN_MASK,
 				   0);
 		/* enable 100uA internal current source */
-		snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+		snd_soc_component_update_bits(component, CDC_A_MBHC_FSM_CTL,
 				    CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
 				    CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
 	}
-	snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
+	snd_soc_component_update_bits(component, CDC_A_MBHC_FSM_CTL,
 			CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
 			CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
 
@@ -482,7 +482,7 @@ static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
 		fine = ((vrefs[i] % 100) / 12);
 		reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
 			 (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
-		snd_soc_update_bits(codec, reg_addr,
+		snd_soc_component_update_bits(component, reg_addr,
 			       CDC_A_MBHC_BTN_VREF_MASK,
 			       reg_val);
 		reg_addr++;
@@ -493,12 +493,12 @@ static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
 
 static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
 {
-	struct snd_soc_codec *codec = wcd->codec;
+	struct snd_soc_component *component = wcd->component;
 	bool micbias_enabled = false;
 	u32 plug_type = 0;
 	u32 int_en_mask;
 
-	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
+	snd_soc_component_write(component, CDC_A_MBHC_DET_CTL_1,
 		      CDC_A_MBHC_DET_CTL_L_DET_EN |
 		      CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
 		      CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
@@ -510,23 +510,23 @@ static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
 	if (wcd->gnd_jack_type_normally_open)
 		plug_type |= CDC_A_GND_PLUG_TYPE_NO;
 
-	snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
+	snd_soc_component_write(component, CDC_A_MBHC_DET_CTL_2,
 		      CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
 		      CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
 		      plug_type |
 		      CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
 
 
-	snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
+	snd_soc_component_write(component, CDC_A_MBHC_DBNC_TIMER,
 		      CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
 		      CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
 
 	/* enable MBHC clock */
-	snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+	snd_soc_component_update_bits(component, CDC_D_CDC_DIG_CLK_CTL,
 			    DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
 			    DIG_CLK_CTL_D_MBHC_CLK_EN);
 
-	if (snd_soc_read(codec, CDC_A_MICB_2_EN) & CDC_A_MICB_2_EN_ENABLE)
+	if (snd_soc_component_read32(component, CDC_A_MICB_2_EN) & CDC_A_MICB_2_EN_ENABLE)
 		micbias_enabled = true;
 
 	pm8916_mbhc_configure_bias(wcd, micbias_enabled);
@@ -535,8 +535,8 @@ static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
 	if (wcd->mbhc_btn_enabled)
 		int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
 
-	snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
-	snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
+	snd_soc_component_update_bits(component, CDC_D_INT_EN_CLR, int_en_mask, 0);
+	snd_soc_component_update_bits(component, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
 	wcd->mbhc_btn0_released = false;
 	wcd->detect_accessory_type = true;
 }
@@ -546,8 +546,8 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
 						  *w, struct snd_kcontrol
 						  *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -558,7 +558,7 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
 		break;
 	}
 
-	return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
+	return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg,
 						     wcd->micbias2_cap_mode);
 }
 
@@ -566,7 +566,7 @@ static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
 					 struct snd_kcontrol *kcontrol,
 					 int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2;
 	u8 init_bit_shift;
 
@@ -578,7 +578,7 @@ static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (w->reg == CDC_A_TX_2_EN)
-			snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+			snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
 					    MICB_1_CTL_CFILT_REF_SEL_MASK,
 					    MICB_1_CTL_CFILT_REF_SEL_HPF_REF);
 		/*
@@ -587,17 +587,17 @@ static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
 		 * happen when the input voltage is changing too much.
 		 */
 		usleep_range(10000, 10010);
-		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+		snd_soc_component_update_bits(component, adc_reg, 1 << init_bit_shift,
 				    1 << init_bit_shift);
 		switch (w->reg) {
 		case CDC_A_TX_1_EN:
-			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL,
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX1_CTL,
 					    CONN_TX1_SERIAL_TX1_MUX,
 					    CONN_TX1_SERIAL_TX1_ADC_1);
 			break;
 		case CDC_A_TX_2_EN:
 		case CDC_A_TX_3_EN:
-			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX2_CTL,
 					    CONN_TX2_SERIAL_TX2_MUX,
 					    CONN_TX2_SERIAL_TX2_ADC_2);
 			break;
@@ -609,21 +609,21 @@ static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
 		 * to reduce the tx pop
 		 */
 		usleep_range(12000, 12010);
-		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+		snd_soc_component_update_bits(component, adc_reg, 1 << init_bit_shift, 0x00);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		switch (w->reg) {
 		case CDC_A_TX_1_EN:
-			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL,
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX1_CTL,
 					    CONN_TX1_SERIAL_TX1_MUX,
 					    CONN_TX1_SERIAL_TX1_ZERO);
 			break;
 		case CDC_A_TX_2_EN:
-			snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+			snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
 					    MICB_1_CTL_CFILT_REF_SEL_MASK, 0);
 			/* fall through */
 		case CDC_A_TX_3_EN:
-			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX2_CTL,
 					    CONN_TX2_SERIAL_TX2_MUX,
 					    CONN_TX2_SERIAL_TX2_ZERO);
 			break;
@@ -639,11 +639,11 @@ static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w,
 					    struct snd_kcontrol *kcontrol,
 					    int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+		snd_soc_component_update_bits(component, CDC_A_SPKR_PWRSTG_CTL,
 				    SPKR_PWRSTG_CTL_DAC_EN_MASK |
 				    SPKR_PWRSTG_CTL_BBM_MASK |
 				    SPKR_PWRSTG_CTL_HBRDGE_EN_MASK |
@@ -653,29 +653,29 @@ static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w,
 				    SPKR_PWRSTG_CTL_HBRDGE_EN |
 				    SPKR_PWRSTG_CTL_CLAMP_EN);
 
-		snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL,
+		snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
 				    RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK,
 				    RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, CDC_A_SPKR_DRV_CTL,
+		snd_soc_component_update_bits(component, CDC_A_SPKR_DRV_CTL,
 				    SPKR_DRV_CTL_DEF_MASK,
 				    SPKR_DRV_CTL_DEF_VAL);
-		snd_soc_update_bits(codec, w->reg,
+		snd_soc_component_update_bits(component, w->reg,
 				    SPKR_DRV_CLASSD_PA_EN_MASK,
 				    SPKR_DRV_CLASSD_PA_EN_ENABLE);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+		snd_soc_component_update_bits(component, CDC_A_SPKR_PWRSTG_CTL,
 				    SPKR_PWRSTG_CTL_DAC_EN_MASK|
 				    SPKR_PWRSTG_CTL_BBM_MASK |
 				    SPKR_PWRSTG_CTL_HBRDGE_EN_MASK |
 				    SPKR_PWRSTG_CTL_CLAMP_EN_MASK, 0);
 
-		snd_soc_update_bits(codec, CDC_A_SPKR_DAC_CTL,
+		snd_soc_component_update_bits(component, CDC_A_SPKR_DAC_CTL,
 				    SPKR_DAC_CTL_DAC_RESET_MASK,
 				    SPKR_DAC_CTL_DAC_RESET_NORMAL);
-		snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL,
+		snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
 				    RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0);
 		break;
 	}
@@ -701,36 +701,36 @@ static const struct reg_default wcd_reg_defaults_2_0[] = {
 	{CDC_A_MASTER_BIAS_CTL, 0x30},
 };
 
-static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
+static int pm8916_wcd_analog_probe(struct snd_soc_component *component)
 {
-	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
+	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
 	int err, reg;
 
 	err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
 	if (err != 0) {
-		dev_err(codec->dev, "failed to enable regulators (%d)\n", err);
+		dev_err(component->dev, "failed to enable regulators (%d)\n", err);
 		return err;
 	}
 
-	snd_soc_codec_init_regmap(codec,
-				  dev_get_regmap(codec->dev->parent, NULL));
-	snd_soc_codec_set_drvdata(codec, priv);
-	priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1);
-	priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE);
+	snd_soc_component_init_regmap(component,
+				  dev_get_regmap(component->dev->parent, NULL));
+	snd_soc_component_set_drvdata(component, priv);
+	priv->pmic_rev = snd_soc_component_read32(component, CDC_D_REVISION1);
+	priv->codec_version = snd_soc_component_read32(component, CDC_D_PERPH_SUBTYPE);
 
-	dev_info(codec->dev, "PMIC REV: %d\t CODEC Version: %d\n",
+	dev_info(component->dev, "PMIC REV: %d\t CODEC Version: %d\n",
 		 priv->pmic_rev, priv->codec_version);
 
-	snd_soc_write(codec, CDC_D_PERPH_RESET_CTL4, 0x01);
-	snd_soc_write(codec, CDC_A_PERPH_RESET_CTL4, 0x01);
+	snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01);
+	snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01);
 
 	for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++)
-		snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
+		snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg,
 			      wcd_reg_defaults_2_0[reg].def);
 
-	priv->codec = codec;
+	priv->component = component;
 
-	snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+	snd_soc_component_update_bits(component, CDC_D_CDC_RST_CTL,
 			    RST_CTL_DIG_SW_RST_N_MASK,
 			    RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
 
@@ -739,14 +739,14 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec)
+static void pm8916_wcd_analog_remove(struct snd_soc_component *component)
 {
-	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
+	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
 
-	snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+	snd_soc_component_update_bits(component, CDC_D_CDC_RST_CTL,
 			    RST_CTL_DIG_SW_RST_N_MASK, 0);
 
-	return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
 				      priv->supplies);
 }
 
@@ -934,11 +934,11 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
 };
 
-static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
+static int pm8916_wcd_analog_set_jack(struct snd_soc_component *component,
 				      struct snd_soc_jack *jack,
 				      void *data)
 {
-	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
 
 	wcd->jack = jack;
 
@@ -950,8 +950,8 @@ static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
 	struct pm8916_wcd_analog_priv *priv = arg;
 
 	if (priv->detect_accessory_type) {
-		struct snd_soc_codec *codec = priv->codec;
-		u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1);
+		struct snd_soc_component *component = priv->component;
+		u32 val = snd_soc_component_read32(component, CDC_A_MBHC_RESULT_1);
 
 		/* check if its BTN0 thats released */
 		if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
@@ -967,10 +967,10 @@ static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
 static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
 {
 	struct pm8916_wcd_analog_priv *priv = arg;
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_component *component = priv->component;
 	u32 btn_result;
 
-	btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) &
+	btn_result = snd_soc_component_read32(component, CDC_A_MBHC_RESULT_1) &
 				  CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
 
 	switch (btn_result) {
@@ -993,7 +993,7 @@ static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
 					    SND_JACK_BTN_0, btn_mask);
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Unexpected button press result (%x)", btn_result);
 		break;
 	}
@@ -1004,15 +1004,15 @@ static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
 static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
 {
 	struct pm8916_wcd_analog_priv *priv = arg;
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_component *component = priv->component;
 	bool ins = false;
 
-	if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) &
+	if (snd_soc_component_read32(component, CDC_A_MBHC_DET_CTL_1) &
 				CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
 		ins = true;
 
 	/* Set the detection type appropriately */
-	snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1,
+	snd_soc_component_update_bits(component, CDC_A_MBHC_DET_CTL_1,
 			    CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
 			    (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
 
@@ -1020,7 +1020,7 @@ static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
 	if (ins) { /* hs insertion */
 		bool micbias_enabled = false;
 
-		if (snd_soc_read(codec, CDC_A_MICB_2_EN) &
+		if (snd_soc_component_read32(component, CDC_A_MICB_2_EN) &
 				CDC_A_MICB_2_EN_ENABLE)
 			micbias_enabled = true;
 
@@ -1075,18 +1075,20 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
 	       },
 };
 
-static const struct snd_soc_codec_driver pm8916_wcd_analog = {
-	.probe = pm8916_wcd_analog_probe,
-	.remove = pm8916_wcd_analog_remove,
-	.set_jack = pm8916_wcd_analog_set_jack,
-	.component_driver = {
-		.controls = pm8916_wcd_analog_snd_controls,
-		.num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls),
-		.dapm_widgets = pm8916_wcd_analog_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets),
-		.dapm_routes = pm8916_wcd_analog_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(pm8916_wcd_analog_audio_map),
-	},
+static const struct snd_soc_component_driver pm8916_wcd_analog = {
+	.probe			= pm8916_wcd_analog_probe,
+	.remove			= pm8916_wcd_analog_remove,
+	.set_jack		= pm8916_wcd_analog_set_jack,
+	.controls		= pm8916_wcd_analog_snd_controls,
+	.num_controls		= ARRAY_SIZE(pm8916_wcd_analog_snd_controls),
+	.dapm_widgets		= pm8916_wcd_analog_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets),
+	.dapm_routes		= pm8916_wcd_analog_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(pm8916_wcd_analog_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int pm8916_wcd_analog_parse_dt(struct device *dev,
@@ -1223,7 +1225,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
 
 	dev_set_drvdata(dev, priv);
 
-	return snd_soc_register_codec(dev, &pm8916_wcd_analog,
+	return devm_snd_soc_register_component(dev, &pm8916_wcd_analog,
 				      pm8916_wcd_analog_dai,
 				      ARRAY_SIZE(pm8916_wcd_analog_dai));
 }
@@ -1232,7 +1234,6 @@ static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev)
 {
 	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_codec(&pdev->dev);
 	clk_disable_unprepare(priv->mclk);
 
 	return 0;
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index 13354d6304a8..3063dedd21cf 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -348,14 +348,14 @@ static int msm8916_wcd_digital_enable_interpolator(
 						struct snd_kcontrol *kcontrol,
 						int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* apply the digital gain after the interpolator is enabled */
 		usleep_range(10000, 10100);
-		snd_soc_write(codec, rx_gain_reg[w->shift],
-			      snd_soc_read(codec, rx_gain_reg[w->shift]));
+		snd_soc_component_write(component, rx_gain_reg[w->shift],
+			      snd_soc_component_read32(component, rx_gain_reg[w->shift]));
 		break;
 	}
 	return 0;
@@ -365,7 +365,7 @@ static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w,
 					  struct snd_kcontrol *kcontrol,
 					  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int decimator = w->shift + 1;
 	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
 	u8 dec_hpf_cut_of_freq;
@@ -377,46 +377,46 @@ static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Enable TX digital mute */
-		snd_soc_update_bits(codec, tx_vol_ctl_reg,
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 				    TX_VOL_CTL_CFG_MUTE_EN_MASK,
 				    TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
-		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) &
+		dec_hpf_cut_of_freq = snd_soc_component_read32(component, tx_mux_ctl_reg) &
 					TX_MUX_CTL_CUT_OFF_FREQ_MASK;
 		dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT;
 		if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) {
 			/* set cut of freq to CF_MIN_3DB_150HZ (0x1) */
-			snd_soc_update_bits(codec, tx_mux_ctl_reg,
+			snd_soc_component_update_bits(component, tx_mux_ctl_reg,
 					    TX_MUX_CTL_CUT_OFF_FREQ_MASK,
 					    TX_MUX_CTL_CF_NEG_3DB_150HZ);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		/* enable HPF */
-		snd_soc_update_bits(codec, tx_mux_ctl_reg,
+		snd_soc_component_update_bits(component, tx_mux_ctl_reg,
 				    TX_MUX_CTL_HPF_BP_SEL_MASK,
 				    TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS);
 		/* apply the digital gain after the decimator is enabled */
-		snd_soc_write(codec, tx_gain_reg[w->shift],
-			      snd_soc_read(codec, tx_gain_reg[w->shift]));
-		snd_soc_update_bits(codec, tx_vol_ctl_reg,
+		snd_soc_component_write(component, tx_gain_reg[w->shift],
+			      snd_soc_component_read32(component, tx_gain_reg[w->shift]));
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 				    TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, tx_vol_ctl_reg,
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 				    TX_VOL_CTL_CFG_MUTE_EN_MASK,
 				    TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
-		snd_soc_update_bits(codec, tx_mux_ctl_reg,
+		snd_soc_component_update_bits(component, tx_mux_ctl_reg,
 				    TX_MUX_CTL_HPF_BP_SEL_MASK,
 				    TX_MUX_CTL_HPF_BP_SEL_BYPASS);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+		snd_soc_component_update_bits(component, dec_reset_reg, 1 << w->shift,
 				    1 << w->shift);
-		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
-		snd_soc_update_bits(codec, tx_mux_ctl_reg,
+		snd_soc_component_update_bits(component, dec_reset_reg, 1 << w->shift, 0x0);
+		snd_soc_component_update_bits(component, tx_mux_ctl_reg,
 				    TX_MUX_CTL_HPF_BP_SEL_MASK,
 				    TX_MUX_CTL_HPF_BP_SEL_BYPASS);
-		snd_soc_update_bits(codec, tx_vol_ctl_reg,
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
 				    TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
 		break;
 	}
@@ -428,35 +428,35 @@ static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w,
 					   struct snd_kcontrol *kcontrol,
 					   int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int dmic;
 	int ret;
 	/* get dmic number out of widget name */
 	char *dmic_num = strpbrk(w->name, "12");
 
 	if (dmic_num == NULL) {
-		dev_err(codec->dev, "Invalid DMIC\n");
+		dev_err(component->dev, "Invalid DMIC\n");
 		return -EINVAL;
 	}
 	ret = kstrtouint(dmic_num, 10, &dmic);
 	if (ret < 0 || dmic > 2) {
-		dev_err(codec->dev, "Invalid DMIC line on the codec\n");
+		dev_err(component->dev, "Invalid DMIC line on the component\n");
 		return -EINVAL;
 	}
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL,
+		snd_soc_component_update_bits(component, LPASS_CDC_CLK_DMIC_B1_CTL,
 				    DMIC_B1_CTL_DMIC0_CLK_SEL_MASK,
 				    DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3);
 		switch (dmic) {
 		case 1:
-			snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL,
+			snd_soc_component_update_bits(component, LPASS_CDC_TX1_DMIC_CTL,
 					    TXN_DMIC_CTL_CLK_SEL_MASK,
 					    TXN_DMIC_CTL_CLK_SEL_DIV3);
 			break;
 		case 2:
-			snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL,
+			snd_soc_component_update_bits(component, LPASS_CDC_TX2_DMIC_CTL,
 					    TXN_DMIC_CTL_CLK_SEL_MASK,
 					    TXN_DMIC_CTL_CLK_SEL_DIV3);
 			break;
@@ -575,20 +575,20 @@ static int msm8916_wcd_digital_get_clks(struct platform_device *pdev,
 	return 0;
 }
 
-static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec)
+static int msm8916_wcd_digital_component_probe(struct snd_soc_component *component)
 {
-	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev);
+	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(component->dev);
 
-	snd_soc_codec_set_drvdata(codec, priv);
+	snd_soc_component_set_drvdata(component, priv);
 
 	return 0;
 }
 
-static int msm8916_wcd_digital_codec_set_sysclk(struct snd_soc_codec *codec,
+static int msm8916_wcd_digital_component_set_sysclk(struct snd_soc_component *component,
 						int clk_id, int source,
 						unsigned int freq, int dir)
 {
-	struct msm8916_wcd_digital_priv *p = dev_get_drvdata(codec->dev);
+	struct msm8916_wcd_digital_priv *p = dev_get_drvdata(component->dev);
 
 	return clk_set_rate(p->mclk, freq);
 }
@@ -618,18 +618,18 @@ static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
 		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ;
 		break;
 	default:
-		dev_err(dai->codec->dev, "Invalid sampling rate %d\n",
+		dev_err(dai->component->dev, "Invalid sampling rate %d\n",
 			params_rate(params));
 		return -EINVAL;
 	}
 
 	switch (substream->stream) {
 	case SNDRV_PCM_STREAM_CAPTURE:
-		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_TX_I2S_CTL,
 				    TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate);
 		break;
 	case SNDRV_PCM_STREAM_PLAYBACK:
-		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_RX_I2S_CTL,
 				    RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate);
 		break;
 	default:
@@ -638,18 +638,19 @@ static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_TX_I2S_CTL,
 				    TX_I2S_CTL_TX_I2S_MODE_MASK,
 				    TX_I2S_CTL_TX_I2S_MODE_16);
-		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_RX_I2S_CTL,
 				    RX_I2S_CTL_RX_I2S_MODE_MASK,
 				    RX_I2S_CTL_RX_I2S_MODE_16);
 		break;
+
 	case SNDRV_PCM_FORMAT_S32_LE:
-		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_TX_I2S_CTL,
 				    TX_I2S_CTL_TX_I2S_MODE_MASK,
 				    TX_I2S_CTL_TX_I2S_MODE_32);
-		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_RX_I2S_CTL,
 				    RX_I2S_CTL_RX_I2S_MODE_MASK,
 				    RX_I2S_CTL_RX_I2S_MODE_32);
 		break;
@@ -780,32 +781,32 @@ static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
 static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream,
 				       struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	struct msm8916_wcd_digital_priv *msm8916_wcd;
 	unsigned long mclk_rate;
 
-	msm8916_wcd = snd_soc_codec_get_drvdata(codec);
-	snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL,
+	msm8916_wcd = snd_soc_component_get_drvdata(component);
+	snd_soc_component_update_bits(component, LPASS_CDC_CLK_MCLK_CTL,
 			    MCLK_CTL_MCLK_EN_MASK,
 			    MCLK_CTL_MCLK_EN_ENABLE);
-	snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL,
+	snd_soc_component_update_bits(component, LPASS_CDC_CLK_PDM_CTL,
 			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK,
 			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB);
 
 	mclk_rate = clk_get_rate(msm8916_wcd->mclk);
 	switch (mclk_rate) {
 	case 12288000:
-		snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL,
+		snd_soc_component_update_bits(component, LPASS_CDC_TOP_CTL,
 				    TOP_CTL_DIG_MCLK_FREQ_MASK,
 				    TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ);
 		break;
 	case 9600000:
-		snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL,
+		snd_soc_component_update_bits(component, LPASS_CDC_TOP_CTL,
 				    TOP_CTL_DIG_MCLK_FREQ_MASK,
 				    TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate);
+		dev_err(component->dev, "Invalid mclk rate %ld\n", mclk_rate);
 		break;
 	}
 	return 0;
@@ -814,7 +815,7 @@ static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream,
 static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream,
 					 struct snd_soc_dai *dai)
 {
-	snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL,
+	snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_PDM_CTL,
 			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0);
 }
 
@@ -851,18 +852,19 @@ static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = {
 	       },
 };
 
-static const struct snd_soc_codec_driver msm8916_wcd_digital = {
-	.probe = msm8916_wcd_digital_codec_probe,
-	.set_sysclk = msm8916_wcd_digital_codec_set_sysclk,
-	.component_driver = {
-		.controls = msm8916_wcd_digital_snd_controls,
-		.num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls),
-		.dapm_widgets = msm8916_wcd_digital_dapm_widgets,
-		.num_dapm_widgets =
-				 ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets),
-		.dapm_routes = msm8916_wcd_digital_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map),
-	},
+static const struct snd_soc_component_driver msm8916_wcd_digital = {
+	.probe			= msm8916_wcd_digital_component_probe,
+	.set_sysclk		= msm8916_wcd_digital_component_set_sysclk,
+	.controls		= msm8916_wcd_digital_snd_controls,
+	.num_controls		= ARRAY_SIZE(msm8916_wcd_digital_snd_controls),
+	.dapm_widgets		= msm8916_wcd_digital_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets),
+	.dapm_routes		= msm8916_wcd_digital_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(msm8916_wcd_digital_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config msm8916_codec_regmap_config = {
@@ -915,7 +917,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev)
 
 	dev_set_drvdata(dev, priv);
 
-	return snd_soc_register_codec(dev, &msm8916_wcd_digital,
+	return devm_snd_soc_register_component(dev, &msm8916_wcd_digital,
 				      msm8916_wcd_digital_dai,
 				      ARRAY_SIZE(msm8916_wcd_digital_dai));
 }
@@ -924,7 +926,6 @@ static int msm8916_wcd_digital_remove(struct platform_device *pdev)
 {
 	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_codec(&pdev->dev);
 	clk_disable_unprepare(priv->mclk);
 	clk_disable_unprepare(priv->ahbclk);
 
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index b08fb7e243c3..17104f8dc1a9 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -236,8 +236,8 @@ static const struct snd_kcontrol_new digital_ch1_mux =
 static int adc_power_control(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		msleep(300);
@@ -258,8 +258,8 @@ static int adc_power_control(struct snd_soc_dapm_widget *w,
 static int aiftx_power_control(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0001);
@@ -379,8 +379,8 @@ static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
 static int nau8540_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, osr;
 
 	/* CLK_ADC = OSR * FS
@@ -422,8 +422,8 @@ static int nau8540_hw_params(struct snd_pcm_substream *substream,
 
 static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 	unsigned int ctrl1_val = 0, ctrl2_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -493,8 +493,8 @@ static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 	unsigned int ctrl2_val = 0, ctrl4_val = 0;
 
 	if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)))
@@ -649,10 +649,10 @@ static void nau8540_fll_apply(struct regmap *regmap,
 }
 
 /* freq_out must be 256*Fs in order to achieve the best performance */
-static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+static int nau8540_set_pll(struct snd_soc_component *component, int pll_id, int source,
 		unsigned int freq_in, unsigned int freq_out)
 {
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 	struct nau8540_fll fll_param;
 	int ret, fs;
 
@@ -702,10 +702,10 @@ static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
 	return 0;
 }
 
-static int nau8540_set_sysclk(struct snd_soc_codec *codec,
+static int nau8540_set_sysclk(struct snd_soc_component *component,
 	int clk_id, int source, unsigned int freq, int dir)
 {
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case NAU8540_CLK_DIS:
@@ -777,9 +777,9 @@ static void nau8540_init_regs(struct nau8540 *nau8540)
 		NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
 }
 
-static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)
+static int __maybe_unused nau8540_suspend(struct snd_soc_component *component)
 {
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(nau8540->regmap, true);
 	regcache_mark_dirty(nau8540->regmap);
@@ -787,9 +787,9 @@ static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
+static int __maybe_unused nau8540_resume(struct snd_soc_component *component)
 {
-	struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(nau8540->regmap, false);
 	regcache_sync(nau8540->regmap);
@@ -797,21 +797,22 @@ static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver nau8540_codec_driver = {
-	.set_sysclk = nau8540_set_sysclk,
-	.set_pll = nau8540_set_pll,
-	.suspend = nau8540_suspend,
-	.resume = nau8540_resume,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls = nau8540_snd_controls,
-		.num_controls = ARRAY_SIZE(nau8540_snd_controls),
-		.dapm_widgets = nau8540_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(nau8540_dapm_widgets),
-		.dapm_routes = nau8540_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(nau8540_dapm_routes),
-	},
+static const struct snd_soc_component_driver nau8540_component_driver = {
+	.set_sysclk		= nau8540_set_sysclk,
+	.set_pll		= nau8540_set_pll,
+	.suspend		= nau8540_suspend,
+	.resume			= nau8540_resume,
+	.controls		= nau8540_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8540_snd_controls),
+	.dapm_widgets		= nau8540_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8540_dapm_widgets),
+	.dapm_routes		= nau8540_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8540_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config nau8540_regmap_config = {
@@ -856,17 +857,10 @@ static int nau8540_i2c_probe(struct i2c_client *i2c,
 	nau8540_reset_chip(nau8540->regmap);
 	nau8540_init_regs(nau8540);
 
-	return snd_soc_register_codec(dev,
-		&nau8540_codec_driver, &nau8540_dai, 1);
-}
-
-static int nau8540_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
+	return devm_snd_soc_register_component(dev,
+		&nau8540_component_driver, &nau8540_dai, 1);
 }
 
-
 static const struct i2c_device_id nau8540_i2c_ids[] = {
 	{ "nau8540", 0 },
 	{ }
@@ -887,7 +881,6 @@ static struct i2c_driver nau8540_i2c_driver = {
 		.of_match_table = of_match_ptr(nau8540_of_ids),
 	},
 	.probe = nau8540_i2c_probe,
-	.remove = nau8540_i2c_remove,
 	.id_table = nau8540_i2c_ids,
 };
 module_i2c_driver(nau8540_i2c_driver);
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index c8e2451ae0a3..ca2ba1c7bb9a 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -167,8 +167,8 @@ static bool nau8810_volatile_reg(struct device *dev, unsigned int reg)
 static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
 	int i, reg, reg_val;
 	u16 *val;
@@ -198,8 +198,8 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
 static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
 	void *data;
 	u16 *val, value;
@@ -219,7 +219,7 @@ static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
 		value = be16_to_cpu(*(val + i));
 		ret = regmap_write(nau8810->regmap, reg + i, value);
 		if (ret) {
-			dev_err(codec->dev, "EQ configuration fail, register: %x ret: %d\n",
+			dev_err(component->dev, "EQ configuration fail, register: %x ret: %d\n",
 				reg + i, ret);
 			kfree(data);
 			return ret;
@@ -399,8 +399,8 @@ static const struct snd_kcontrol_new nau8810_loopback =
 static int check_mclk_select_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	unsigned int value;
 
 	regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &value);
@@ -485,8 +485,8 @@ static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
 static int nau8810_set_sysclk(struct snd_soc_dai *dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 
 	nau8810->clk_id = clk_id;
 	nau8810->sysclk = freq;
@@ -538,8 +538,8 @@ static int nau88l0_calc_pll(unsigned int pll_in,
 static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	struct regmap *map = nau8810->regmap;
 	struct nau8810_pll *pll_param = &nau8810->pll;
 	int ret, fs;
@@ -577,8 +577,8 @@ static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	u16 ctrl1_val = 0, ctrl2_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -667,8 +667,8 @@ static int nau8810_mclk_clkdiv(struct nau8810 *nau8810, int rate)
 static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	int val_len = 0, val_rate = 0, ret = 0;
 
 	switch (params_width(params)) {
@@ -723,10 +723,10 @@ static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int nau8810_set_bias_level(struct snd_soc_codec *codec,
+static int nau8810_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
 	struct regmap *map = nau8810->regmap;
 
 	switch (level) {
@@ -741,7 +741,7 @@ static int nau8810_set_bias_level(struct snd_soc_codec *codec,
 			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN,
 			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN);
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_sync(map);
 			regmap_update_bits(map, NAU8810_REG_POWER1,
 				NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K);
@@ -808,18 +808,19 @@ static const struct regmap_config nau8810_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults),
 };
 
-static const struct snd_soc_codec_driver nau8810_codec_driver = {
-	.set_bias_level = nau8810_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls = nau8810_snd_controls,
-		.num_controls = ARRAY_SIZE(nau8810_snd_controls),
-		.dapm_widgets = nau8810_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(nau8810_dapm_widgets),
-		.dapm_routes = nau8810_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(nau8810_dapm_routes),
-	},
+static const struct snd_soc_component_driver nau8810_component_driver = {
+	.set_bias_level		= nau8810_set_bias_level,
+	.controls		= nau8810_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8810_snd_controls),
+	.dapm_widgets		= nau8810_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8810_dapm_widgets),
+	.dapm_routes		= nau8810_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8810_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int nau8810_i2c_probe(struct i2c_client *i2c,
@@ -842,15 +843,8 @@ static int nau8810_i2c_probe(struct i2c_client *i2c,
 
 	regmap_write(nau8810->regmap, NAU8810_REG_RESET, 0x00);
 
-	return snd_soc_register_codec(dev,
-		&nau8810_codec_driver, &nau8810_dai, 1);
-}
-
-static int nau8810_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
+	return devm_snd_soc_register_component(dev,
+		&nau8810_component_driver, &nau8810_dai, 1);
 }
 
 static const struct i2c_device_id nau8810_i2c_id[] = {
@@ -873,7 +867,6 @@ static struct i2c_driver nau8810_i2c_driver = {
 		.of_match_table = of_match_ptr(nau8810_of_match),
 	},
 	.probe =    nau8810_i2c_probe,
-	.remove =   nau8810_i2c_remove,
 	.id_table = nau8810_i2c_id,
 };
 
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 088e0cef4cb8..4d9148a6a080 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -414,8 +414,8 @@ static const struct snd_kcontrol_new nau8824_snd_controls[] = {
 static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -437,8 +437,8 @@ static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,
 static int nau8824_spk_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -461,8 +461,8 @@ static int nau8824_spk_event(struct snd_soc_dapm_widget *w,
 static int nau8824_pump_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -487,8 +487,8 @@ static int nau8824_pump_event(struct snd_soc_dapm_widget *w,
 static int system_clock_control(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	if (SND_SOC_DAPM_EVENT_OFF(event)) {
 		/* Set clock source to disable or internal clock before the
@@ -509,8 +509,8 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
 static int dmic_clock_control(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	int src;
 
 	/* The DMIC clock is gotten from system clock (256fs) divided by
@@ -988,8 +988,8 @@ static int nau8824_clock_check(struct nau8824 *nau8824,
 static int nau8824_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
 
 	nau8824_sema_acquire(nau8824, HZ);
@@ -1072,8 +1072,8 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
 
 static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	unsigned int ctrl1_val = 0, ctrl2_val = 0;
 
 	nau8824_sema_acquire(nau8824, HZ);
@@ -1149,8 +1149,8 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int nau8824_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	unsigned int tslot_l = 0, ctrl_val = 0;
 
 	if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)) ||
@@ -1288,10 +1288,10 @@ static void nau8824_fll_apply(struct regmap *regmap,
 }
 
 /* freq_out must be 256*Fs in order to achieve the best performance */
-static int nau8824_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+static int nau8824_set_pll(struct snd_soc_component *component, int pll_id, int source,
 		unsigned int freq_in, unsigned int freq_out)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	struct nau8824_fll fll_param;
 	int ret, fs;
 
@@ -1374,10 +1374,10 @@ static int nau8824_config_sysclk(struct nau8824 *nau8824,
 	return 0;
 }
 
-static int nau8824_set_sysclk(struct snd_soc_codec *codec,
+static int nau8824_set_sysclk(struct snd_soc_component *component,
 	int clk_id, int source, unsigned int freq, int dir)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	return nau8824_config_sysclk(nau8824, clk_id, freq);
 }
@@ -1403,10 +1403,10 @@ static void nau8824_resume_setup(struct nau8824 *nau8824)
 	}
 }
 
-static int nau8824_set_bias_level(struct snd_soc_codec *codec,
+static int nau8824_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -1416,7 +1416,7 @@ static int nau8824_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Setup codec configuration after resume */
 			nau8824_resume_setup(nau8824);
 		}
@@ -1434,23 +1434,23 @@ static int nau8824_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int nau8824_codec_probe(struct snd_soc_codec *codec)
+static int nau8824_component_probe(struct snd_soc_component *component)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	nau8824->dapm = dapm;
 
 	return 0;
 }
 
-static int __maybe_unused nau8824_suspend(struct snd_soc_codec *codec)
+static int __maybe_unused nau8824_suspend(struct snd_soc_component *component)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	if (nau8824->irq) {
 		disable_irq(nau8824->irq);
-		snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+		snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 	}
 	regcache_cache_only(nau8824->regmap, true);
 	regcache_mark_dirty(nau8824->regmap);
@@ -1458,9 +1458,9 @@ static int __maybe_unused nau8824_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int __maybe_unused nau8824_resume(struct snd_soc_codec *codec)
+static int __maybe_unused nau8824_resume(struct snd_soc_component *component)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(nau8824->regmap, false);
 	regcache_sync(nau8824->regmap);
@@ -1475,23 +1475,24 @@ static int __maybe_unused nau8824_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver nau8824_codec_driver = {
-	.probe = nau8824_codec_probe,
-	.set_sysclk = nau8824_set_sysclk,
-	.set_pll = nau8824_set_pll,
-	.set_bias_level = nau8824_set_bias_level,
-	.suspend = nau8824_suspend,
-	.resume = nau8824_resume,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls = nau8824_snd_controls,
-		.num_controls = ARRAY_SIZE(nau8824_snd_controls),
-		.dapm_widgets = nau8824_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(nau8824_dapm_widgets),
-		.dapm_routes = nau8824_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(nau8824_dapm_routes),
-	},
+static const struct snd_soc_component_driver nau8824_component_driver = {
+	.probe			= nau8824_component_probe,
+	.set_sysclk		= nau8824_set_sysclk,
+	.set_pll		= nau8824_set_pll,
+	.set_bias_level		= nau8824_set_bias_level,
+	.suspend		= nau8824_suspend,
+	.resume			= nau8824_resume,
+	.controls		= nau8824_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8824_snd_controls),
+	.dapm_widgets		= nau8824_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8824_dapm_widgets),
+	.dapm_routes		= nau8824_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8824_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct snd_soc_dai_ops nau8824_dai_ops = {
@@ -1547,10 +1548,10 @@ static const struct regmap_config nau8824_regmap_config = {
  * events will be routed to the given jack.  Jack can be null to stop
  * reporting.
  */
-int nau8824_enable_jack_detect(struct snd_soc_codec *codec,
+int nau8824_enable_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack)
 {
-	struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	nau8824->jack = jack;
@@ -1838,15 +1839,8 @@ static int nau8824_i2c_probe(struct i2c_client *i2c,
 	if (i2c->irq)
 		nau8824_setup_irq(nau8824);
 
-	return snd_soc_register_codec(dev,
-		&nau8824_codec_driver, &nau8824_dai, 1);
-}
-
-
-static int nau8824_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
+	return devm_snd_soc_register_component(dev,
+		&nau8824_component_driver, &nau8824_dai, 1);
 }
 
 static const struct i2c_device_id nau8824_i2c_ids[] = {
@@ -1878,7 +1872,6 @@ static struct i2c_driver nau8824_i2c_driver = {
 		.acpi_match_table = ACPI_PTR(nau8824_acpi_match),
 	},
 	.probe = nau8824_i2c_probe,
-	.remove = nau8824_i2c_remove,
 	.id_table = nau8824_i2c_ids,
 };
 module_i2c_driver(nau8824_i2c_driver);
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
index 21eae2431c83..6184a2b5c941 100644
--- a/sound/soc/codecs/nau8824.h
+++ b/sound/soc/codecs/nau8824.h
@@ -471,7 +471,7 @@ struct nau8824_osr_attr {
 };
 
 
-int nau8824_enable_jack_detect(struct snd_soc_codec *codec,
+int nau8824_enable_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack);
 
 #endif				/* _NAU8824_H */
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index a1b697b6fb64..dc6ea4987b7d 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -914,8 +914,8 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
 static int nau8825_adc_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -938,8 +938,8 @@ static int nau8825_adc_event(struct snd_soc_dapm_widget *w,
 static int nau8825_pump_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -962,8 +962,8 @@ static int nau8825_pump_event(struct snd_soc_dapm_widget *w,
 static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1244,8 +1244,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
 
 	nau8825_sema_acquire(nau8825, 3 * HZ);
@@ -1329,8 +1329,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
 
 static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 	unsigned int ctrl1_val = 0, ctrl2_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1427,10 +1427,10 @@ static struct snd_soc_dai_driver nau8825_dai = {
  * events will be routed to the given jack.  Jack can be null to stop
  * reporting.
  */
-int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
+int nau8825_enable_jack_detect(struct snd_soc_component *component,
 				struct snd_soc_jack *jack)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap = nau8825->regmap;
 
 	nau8825->jack = jack;
@@ -1952,24 +1952,22 @@ static const struct regmap_config nau8825_regmap_config = {
 	.num_reg_defaults = ARRAY_SIZE(nau8825_reg_defaults),
 };
 
-static int nau8825_codec_probe(struct snd_soc_codec *codec)
+static int nau8825_component_probe(struct snd_soc_component *component)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	nau8825->dapm = dapm;
 
 	return 0;
 }
 
-static int nau8825_codec_remove(struct snd_soc_codec *codec)
+static void nau8825_component_remove(struct snd_soc_component *component)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 
 	/* Cancel and reset cross tak suppresstion detection funciton */
 	nau8825_xtalk_cancel(nau8825);
-
-	return 0;
 }
 
 /**
@@ -2084,20 +2082,20 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
 }
 
 /* freq_out must be 256*Fs in order to achieve the best performance */
-static int nau8825_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int source,
 		unsigned int freq_in, unsigned int freq_out)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 	struct nau8825_fll fll_param;
 	int ret, fs;
 
 	fs = freq_out / 256;
 	ret = nau8825_calc_fll_param(freq_in, fs, &fll_param);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupported input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupported input clock %d\n", freq_in);
 		return ret;
 	}
-	dev_dbg(codec->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+	dev_dbg(component->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
 		fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
 		fll_param.fll_int, fll_param.clk_ref_div);
 
@@ -2298,10 +2296,10 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
 	return 0;
 }
 
-static int nau8825_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int nau8825_set_sysclk(struct snd_soc_component *component, int clk_id,
 	int source, unsigned int freq, int dir)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 
 	return nau8825_configure_sysclk(nau8825, clk_id, freq);
 }
@@ -2331,10 +2329,10 @@ static int nau8825_resume_setup(struct nau8825 *nau8825)
 	return 0;
 }
 
-static int nau8825_set_bias_level(struct snd_soc_codec *codec,
+static int nau8825_set_bias_level(struct snd_soc_component *component,
 				   enum snd_soc_bias_level level)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -2345,11 +2343,11 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			if (nau8825->mclk_freq) {
 				ret = clk_prepare_enable(nau8825->mclk);
 				if (ret) {
-					dev_err(nau8825->dev, "Unable to prepare codec mclk\n");
+					dev_err(nau8825->dev, "Unable to prepare component mclk\n");
 					return ret;
 				}
 			}
@@ -2383,12 +2381,12 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec)
+static int __maybe_unused nau8825_suspend(struct snd_soc_component *component)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 
 	disable_irq(nau8825->irq);
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 	/* Power down codec power; don't suppoet button wakeup */
 	snd_soc_dapm_disable_pin(nau8825->dapm, "SAR");
 	snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS");
@@ -2399,9 +2397,9 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
+static int __maybe_unused nau8825_resume(struct snd_soc_component *component)
 {
-	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	regcache_cache_only(nau8825->regmap, false);
@@ -2415,24 +2413,25 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver nau8825_codec_driver = {
-	.probe = nau8825_codec_probe,
-	.remove = nau8825_codec_remove,
-	.set_sysclk = nau8825_set_sysclk,
-	.set_pll = nau8825_set_pll,
-	.set_bias_level = nau8825_set_bias_level,
-	.suspend_bias_off = true,
-	.suspend = nau8825_suspend,
-	.resume = nau8825_resume,
-
-	.component_driver = {
-		.controls		= nau8825_controls,
-		.num_controls		= ARRAY_SIZE(nau8825_controls),
-		.dapm_widgets		= nau8825_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(nau8825_dapm_widgets),
-		.dapm_routes		= nau8825_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(nau8825_dapm_routes),
-	},
+static const struct snd_soc_component_driver nau8825_component_driver = {
+	.probe			= nau8825_component_probe,
+	.remove			= nau8825_component_remove,
+	.set_sysclk		= nau8825_set_sysclk,
+	.set_pll		= nau8825_set_pll,
+	.set_bias_level		= nau8825_set_bias_level,
+	.suspend		= nau8825_suspend,
+	.resume			= nau8825_resume,
+	.controls		= nau8825_controls,
+	.num_controls		= ARRAY_SIZE(nau8825_controls),
+	.dapm_widgets		= nau8825_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8825_dapm_widgets),
+	.dapm_routes		= nau8825_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8825_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static void nau8825_reset_chip(struct regmap *regmap)
@@ -2619,13 +2618,13 @@ static int nau8825_i2c_probe(struct i2c_client *i2c,
 	if (i2c->irq)
 		nau8825_setup_irq(nau8825);
 
-	return snd_soc_register_codec(&i2c->dev, &nau8825_codec_driver,
+	return devm_snd_soc_register_component(&i2c->dev,
+		&nau8825_component_driver,
 		&nau8825_dai, 1);
 }
 
 static int nau8825_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index f7e732125882..f6074c618569 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -480,7 +480,7 @@ struct nau8825 {
 	bool xtalk_baktab_initialized; /* True if initialized. */
 };
 
-int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
+int nau8825_enable_jack_detect(struct snd_soc_component *component,
 				struct snd_soc_jack *jack);
 
 
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index c7e28dd2e815..84777d3fa464 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -90,9 +90,9 @@ struct pcm1681_private {
 
 static const int pcm1681_deemph[] = { 44100, 48000, 32000 };
 
-static int pcm1681_set_deemph(struct snd_soc_codec *codec)
+static int pcm1681_set_deemph(struct snd_soc_component *component)
 {
-	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
 	int i = 0, val = -1, enable = 0;
 
 	if (priv->deemph) {
@@ -120,8 +120,8 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)
 static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = priv->deemph;
 
@@ -131,23 +131,23 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
 static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
 
 	priv->deemph = ucontrol->value.integer.value[0];
 
-	return pcm1681_set_deemph(codec);
+	return pcm1681_set_deemph(component);
 }
 
 static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
 
 	/* The PCM1681 can only be slave to all clocks */
 	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_err(codec->dev, "Invalid clocking mode\n");
+		dev_err(component->dev, "Invalid clocking mode\n");
 		return -EINVAL;
 	}
 
@@ -158,8 +158,8 @@ static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
 	int val;
 
 	if (mute)
@@ -174,8 +174,8 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
 	int val = 0, ret;
 
 	priv->rate = params_rate(params);
@@ -200,7 +200,7 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
 		val = 0x05;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -208,7 +208,7 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		return ret;
 
-	return pcm1681_set_deemph(codec);
+	return pcm1681_set_deemph(component);
 }
 
 static const struct snd_soc_dai_ops pcm1681_dai_ops = {
@@ -288,15 +288,17 @@ static const struct regmap_config pcm1681_regmap = {
 	.readable_reg		= pcm1681_accessible_reg,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
-	.component_driver = {
-		.controls		= pcm1681_controls,
-		.num_controls		= ARRAY_SIZE(pcm1681_controls),
-		.dapm_widgets		= pcm1681_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
-		.dapm_routes		= pcm1681_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_pcm1681 = {
+	.controls		= pcm1681_controls,
+	.num_controls		= ARRAY_SIZE(pcm1681_controls),
+	.dapm_widgets		= pcm1681_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
+	.dapm_routes		= pcm1681_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct i2c_device_id pcm1681_i2c_id[] = {
@@ -324,16 +326,11 @@ static int pcm1681_i2c_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, priv);
 
-	return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm1681,
+	return devm_snd_soc_register_component(&client->dev,
+		&soc_component_dev_pcm1681,
 		&pcm1681_dai, 1);
 }
 
-static int pcm1681_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static struct i2c_driver pcm1681_i2c_driver = {
 	.driver = {
 		.name	= "pcm1681",
@@ -341,7 +338,6 @@ static struct i2c_driver pcm1681_i2c_driver = {
 	},
 	.id_table	= pcm1681_i2c_id,
 	.probe		= pcm1681_i2c_probe,
-	.remove		= pcm1681_i2c_remove,
 };
 
 module_i2c_driver(pcm1681_i2c_driver);
diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c
index 4118106abb8d..03747966c6bc 100644
--- a/sound/soc/codecs/pcm179x-i2c.c
+++ b/sound/soc/codecs/pcm179x-i2c.c
@@ -39,11 +39,6 @@ static int pcm179x_i2c_probe(struct i2c_client *client,
 	return pcm179x_common_init(&client->dev, regmap);
 }
 
-static int pcm179x_i2c_remove(struct i2c_client *client)
-{
-	return pcm179x_common_exit(&client->dev);
-}
-
 static const struct of_device_id pcm179x_of_match[] = {
 	{ .compatible = "ti,pcm1792a", },
 	{ }
@@ -63,7 +58,6 @@ static struct i2c_driver pcm179x_i2c_driver = {
 	},
 	.id_table	= pcm179x_i2c_ids,
 	.probe		= pcm179x_i2c_probe,
-	.remove		= pcm179x_i2c_remove,
 };
 
 module_i2c_driver(pcm179x_i2c_driver);
diff --git a/sound/soc/codecs/pcm179x-spi.c b/sound/soc/codecs/pcm179x-spi.c
index da924d444083..89ad715676fc 100644
--- a/sound/soc/codecs/pcm179x-spi.c
+++ b/sound/soc/codecs/pcm179x-spi.c
@@ -38,11 +38,6 @@ static int pcm179x_spi_probe(struct spi_device *spi)
 	return pcm179x_common_init(&spi->dev, regmap);
 }
 
-static int pcm179x_spi_remove(struct spi_device *spi)
-{
-	return pcm179x_common_exit(&spi->dev);
-}
-
 static const struct of_device_id pcm179x_of_match[] = {
 	{ .compatible = "ti,pcm1792a", },
 	{ }
@@ -62,7 +57,6 @@ static struct spi_driver pcm179x_spi_driver = {
 	},
 	.id_table = pcm179x_spi_ids,
 	.probe = pcm179x_spi_probe,
-	.remove = pcm179x_spi_remove,
 };
 
 module_spi_driver(pcm179x_spi_driver);
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index 82a3d9db32cb..4b311c06f97d 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -77,8 +77,8 @@ struct pcm179x_private {
 static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm179x_private *priv = snd_soc_component_get_drvdata(component);
 
 	priv->format = format;
 
@@ -87,8 +87,8 @@ static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm179x_private *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE,
@@ -103,8 +103,8 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm179x_private *priv = snd_soc_component_get_drvdata(component);
 	int val = 0, ret;
 
 	priv->rate = params_rate(params);
@@ -137,7 +137,7 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream,
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -205,15 +205,17 @@ const struct regmap_config pcm179x_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
 
-static const struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
-	.component_driver = {
-		.controls		= pcm179x_controls,
-		.num_controls		= ARRAY_SIZE(pcm179x_controls),
-		.dapm_widgets		= pcm179x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
-		.dapm_routes		= pcm179x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_pcm179x = {
+	.controls		= pcm179x_controls,
+	.num_controls		= ARRAY_SIZE(pcm179x_controls),
+	.dapm_widgets		= pcm179x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
+	.dapm_routes		= pcm179x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 int pcm179x_common_init(struct device *dev, struct regmap *regmap)
@@ -228,18 +230,11 @@ int pcm179x_common_init(struct device *dev, struct regmap *regmap)
 	pcm179x->regmap = regmap;
 	dev_set_drvdata(dev, pcm179x);
 
-	return snd_soc_register_codec(dev,
-			&soc_codec_dev_pcm179x, &pcm179x_dai, 1);
+	return devm_snd_soc_register_component(dev,
+			&soc_component_dev_pcm179x, &pcm179x_dai, 1);
 }
 EXPORT_SYMBOL_GPL(pcm179x_common_init);
 
-int pcm179x_common_exit(struct device *dev)
-{
-	snd_soc_unregister_codec(dev);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(pcm179x_common_exit);
-
 MODULE_DESCRIPTION("ASoC PCM179X driver");
 MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.h b/sound/soc/codecs/pcm179x.h
index 11e331268aae..cf8681c9a373 100644
--- a/sound/soc/codecs/pcm179x.h
+++ b/sound/soc/codecs/pcm179x.h
@@ -23,6 +23,5 @@
 extern const struct regmap_config pcm179x_regmap_config;
 
 int pcm179x_common_init(struct device *dev, struct regmap *regmap);
-int pcm179x_common_exit(struct device *dev);
 
 #endif
diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c
index 543621232d60..0214dc6d84d0 100644
--- a/sound/soc/codecs/pcm186x-i2c.c
+++ b/sound/soc/codecs/pcm186x-i2c.c
@@ -36,13 +36,6 @@ static int pcm186x_i2c_probe(struct i2c_client *i2c,
 	return pcm186x_probe(&i2c->dev, type, irq, regmap);
 }
 
-static int pcm186x_i2c_remove(struct i2c_client *i2c)
-{
-	pcm186x_remove(&i2c->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id pcm186x_i2c_id[] = {
 	{ "pcm1862", PCM1862 },
 	{ "pcm1863", PCM1863 },
@@ -54,7 +47,6 @@ MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id);
 
 static struct i2c_driver pcm186x_i2c_driver = {
 	.probe		= pcm186x_i2c_probe,
-	.remove		= pcm186x_i2c_remove,
 	.id_table	= pcm186x_i2c_id,
 	.driver		= {
 		.name	= "pcm186x",
diff --git a/sound/soc/codecs/pcm186x-spi.c b/sound/soc/codecs/pcm186x-spi.c
index 2366f8e4d4d4..b56e19827497 100644
--- a/sound/soc/codecs/pcm186x-spi.c
+++ b/sound/soc/codecs/pcm186x-spi.c
@@ -36,13 +36,6 @@ static int pcm186x_spi_probe(struct spi_device *spi)
 	return pcm186x_probe(&spi->dev, type, irq, regmap);
 }
 
-static int pcm186x_spi_remove(struct spi_device *spi)
-{
-	pcm186x_remove(&spi->dev);
-
-	return 0;
-}
-
 static const struct spi_device_id pcm186x_spi_id[] = {
 	{ "pcm1862", PCM1862 },
 	{ "pcm1863", PCM1863 },
@@ -54,7 +47,6 @@ MODULE_DEVICE_TABLE(spi, pcm186x_spi_id);
 
 static struct spi_driver pcm186x_spi_driver = {
 	.probe		= pcm186x_spi_probe,
-	.remove		= pcm186x_spi_remove,
 	.id_table	= pcm186x_spi_id,
 	.driver		= {
 		.name	= "pcm186x",
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index cdb51427facc..88fde70b1e9e 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -262,9 +262,8 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-
-	struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int rate = params_rate(params);
 	unsigned int format = params_format(params);
 	unsigned int width = params_width(params);
@@ -274,7 +273,7 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 	u8 tdm_tx_sel = 0;
 	u8 pcm_cfg = 0;
 
-	dev_dbg(codec->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
+	dev_dbg(component->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
 		__func__, rate, format, width, channels);
 
 	switch (width) {
@@ -306,7 +305,7 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, PCM186X_PCM_CFG,
+	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
 			    PCM186X_PCM_CFG_RX_WLEN_MASK |
 			    PCM186X_PCM_CFG_TX_WLEN_MASK,
 			    pcm_cfg);
@@ -329,14 +328,14 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 			return -EINVAL;
 		}
 
-		snd_soc_update_bits(codec, PCM186X_TDM_TX_SEL,
+		snd_soc_component_update_bits(component, PCM186X_TDM_TX_SEL,
 				    PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
 
 		/* In DSP/TDM mode, the LRCLK divider must be 256 */
 		div_lrck = 256;
 
 		/* Configure 1/256 duty cycle for LRCK */
-		snd_soc_update_bits(codec, PCM186X_PCM_CFG,
+		snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
 				    PCM186X_PCM_CFG_TDM_LRCK_MODE,
 				    PCM186X_PCM_CFG_TDM_LRCK_MODE);
 	}
@@ -345,12 +344,12 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 	if (priv->is_master_mode) {
 		div_bck = priv->sysclk / (div_lrck * rate);
 
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			"%s() master_clk=%u div_bck=%u div_lrck=%u\n",
 			__func__, priv->sysclk, div_bck, div_lrck);
 
-		snd_soc_write(codec, PCM186X_BCK_DIV, div_bck - 1);
-		snd_soc_write(codec, PCM186X_LRK_DIV, div_lrck - 1);
+		snd_soc_component_write(component, PCM186X_BCK_DIV, div_bck - 1);
+		snd_soc_component_write(component, PCM186X_LRK_DIV, div_lrck - 1);
 	}
 
 	return 0;
@@ -358,18 +357,18 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 
 static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 	u8 clk_ctrl = 0;
 	u8 pcm_cfg = 0;
 
-	dev_dbg(codec->dev, "%s() format=0x%x\n", __func__, format);
+	dev_dbg(component->dev, "%s() format=0x%x\n", __func__, format);
 
 	/* set master/slave audio interface */
 	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 		if (!priv->sysclk) {
-			dev_err(codec->dev, "operating in master mode requires sysclock to be configured\n");
+			dev_err(component->dev, "operating in master mode requires sysclock to be configured\n");
 			return -EINVAL;
 		}
 		clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
@@ -379,7 +378,7 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
 		priv->is_master_mode = false;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI master/slave interface\n");
+		dev_err(component->dev, "Invalid DAI master/slave interface\n");
 		return -EINVAL;
 	}
 
@@ -388,7 +387,7 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
 	case SND_SOC_DAIFMT_NB_NF:
 		break;
 	default:
-		dev_err(codec->dev, "Inverted DAI clocks not supported\n");
+		dev_err(component->dev, "Inverted DAI clocks not supported\n");
 		return -EINVAL;
 	}
 
@@ -410,16 +409,16 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
 		pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, PCM186X_CLK_CTRL,
+	snd_soc_component_update_bits(component, PCM186X_CLK_CTRL,
 			    PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
 
-	snd_soc_write(codec, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
+	snd_soc_component_write(component, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
 
-	snd_soc_update_bits(codec, PCM186X_PCM_CFG,
+	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
 			    PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
 
 	return 0;
@@ -428,16 +427,16 @@ static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
 static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 				unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int first_slot, last_slot, tdm_offset;
 
-	dev_dbg(codec->dev,
+	dev_dbg(component->dev,
 		"%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
 		__func__, tx_mask, rx_mask, slots, slot_width);
 
 	if (!tx_mask) {
-		dev_err(codec->dev, "tdm tx mask must not be 0\n");
+		dev_err(component->dev, "tdm tx mask must not be 0\n");
 		return -EINVAL;
 	}
 
@@ -445,14 +444,14 @@ static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	last_slot = __fls(tx_mask);
 
 	if (last_slot - first_slot != hweight32(tx_mask) - 1) {
-		dev_err(codec->dev, "tdm tx mask must be contiguous\n");
+		dev_err(component->dev, "tdm tx mask must be contiguous\n");
 		return -EINVAL;
 	}
 
 	tdm_offset = first_slot * slot_width;
 
 	if (tdm_offset > 255) {
-		dev_err(codec->dev, "tdm tx slot selection out of bounds\n");
+		dev_err(component->dev, "tdm tx slot selection out of bounds\n");
 		return -EINVAL;
 	}
 
@@ -464,10 +463,10 @@ static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 				  unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s() clk_id=%d freq=%u dir=%d\n",
+	dev_dbg(component->dev, "%s() clk_id=%d freq=%u dir=%d\n",
 		__func__, clk_id, freq, dir);
 
 	priv->sysclk = freq;
@@ -506,9 +505,9 @@ static struct snd_soc_dai_driver pcm1865_dai = {
 	.ops = &pcm186x_dai_ops,
 };
 
-static int pcm186x_power_on(struct snd_soc_codec *codec)
+static int pcm186x_power_on(struct snd_soc_component *component)
 {
-	struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
@@ -519,25 +518,25 @@ static int pcm186x_power_on(struct snd_soc_codec *codec)
 	regcache_cache_only(priv->regmap, false);
 	ret = regcache_sync(priv->regmap);
 	if (ret) {
-		dev_err(codec->dev, "Failed to restore cache\n");
+		dev_err(component->dev, "Failed to restore cache\n");
 		regcache_cache_only(priv->regmap, true);
 		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
 				       priv->supplies);
 		return ret;
 	}
 
-	snd_soc_update_bits(codec, PCM186X_POWER_CTRL,
+	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
 			    PCM186X_PWR_CTRL_PWRDN, 0);
 
 	return 0;
 }
 
-static int pcm186x_power_off(struct snd_soc_codec *codec)
+static int pcm186x_power_off(struct snd_soc_component *component)
 {
-	struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	snd_soc_update_bits(codec, PCM186X_POWER_CTRL,
+	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
 			    PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
 
 	regcache_cache_only(priv->regmap, true);
@@ -550,11 +549,11 @@ static int pcm186x_power_off(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int pcm186x_set_bias_level(struct snd_soc_codec *codec,
+static int pcm186x_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
-		snd_soc_codec_get_bias_level(codec), level);
+	dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
+		snd_soc_component_get_bias_level(component), level);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -562,42 +561,44 @@ static int pcm186x_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
-			pcm186x_power_on(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			pcm186x_power_on(component);
 		break;
 	case SND_SOC_BIAS_OFF:
-		pcm186x_power_off(codec);
+		pcm186x_power_off(component);
 		break;
 	}
 
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_pcm1863 = {
-	.set_bias_level = pcm186x_set_bias_level,
-
-	.component_driver = {
-		.controls = pcm1863_snd_controls,
-		.num_controls = ARRAY_SIZE(pcm1863_snd_controls),
-		.dapm_widgets = pcm1863_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(pcm1863_dapm_widgets),
-		.dapm_routes = pcm1863_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(pcm1863_dapm_routes),
-	},
+static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
+	.set_bias_level		= pcm186x_set_bias_level,
+	.controls		= pcm1863_snd_controls,
+	.num_controls		= ARRAY_SIZE(pcm1863_snd_controls),
+	.dapm_widgets		= pcm1863_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1863_dapm_widgets),
+	.dapm_routes		= pcm1863_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1863_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_pcm1865 = {
-	.set_bias_level = pcm186x_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls = pcm1865_snd_controls,
-		.num_controls = ARRAY_SIZE(pcm1865_snd_controls),
-		.dapm_widgets = pcm1865_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(pcm1865_dapm_widgets),
-		.dapm_routes = pcm1865_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(pcm1865_dapm_routes),
-	},
+static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
+	.set_bias_level		= pcm186x_set_bias_level,
+	.controls		= pcm1865_snd_controls,
+	.num_controls		= ARRAY_SIZE(pcm1865_snd_controls),
+	.dapm_widgets		= pcm1865_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1865_dapm_widgets),
+	.dapm_routes		= pcm1865_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1865_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static bool pcm186x_volatile(struct device *dev, unsigned int reg)
@@ -687,13 +688,13 @@ int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
 	switch (type) {
 	case PCM1865:
 	case PCM1864:
-		ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1865,
+		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1865,
 					     &pcm1865_dai, 1);
 		break;
 	case PCM1863:
 	case PCM1862:
 	default:
-		ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1863,
+		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1863,
 					     &pcm1863_dai, 1);
 	}
 	if (ret) {
@@ -705,14 +706,6 @@ int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
 }
 EXPORT_SYMBOL_GPL(pcm186x_probe);
 
-int pcm186x_remove(struct device *dev)
-{
-	snd_soc_unregister_codec(dev);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(pcm186x_remove);
-
 MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
 MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
diff --git a/sound/soc/codecs/pcm186x.h b/sound/soc/codecs/pcm186x.h
index b630111bb3c4..2c6ba55bf394 100644
--- a/sound/soc/codecs/pcm186x.h
+++ b/sound/soc/codecs/pcm186x.h
@@ -215,6 +215,5 @@ extern const struct regmap_config pcm186x_regmap;
 
 int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
 		  struct regmap *regmap);
-int pcm186x_remove(struct device *dev);
 
 #endif /* _PCM186X_H_ */
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index e59d8ffb93bd..c6ce9bd77c5e 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -32,8 +32,8 @@ static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct pcm3008_setup_data *setup = codec->dev->platform_data;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pcm3008_setup_data *setup = component->dev->platform_data;
 
 	gpio_set_value_cansleep(setup->pdda_pin,
 				SND_SOC_DAPM_EVENT_ON(event));
@@ -45,8 +45,8 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct pcm3008_setup_data *setup = codec->dev->platform_data;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pcm3008_setup_data *setup = component->dev->platform_data;
 
 	gpio_set_value_cansleep(setup->pdad_pin,
 				SND_SOC_DAPM_EVENT_ON(event));
@@ -98,13 +98,15 @@ static struct snd_soc_dai_driver pcm3008_dai = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
-	.component_driver = {
-		.dapm_widgets		= pcm3008_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pcm3008_dapm_widgets),
-		.dapm_routes		= pcm3008_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pcm3008_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_pcm3008 = {
+	.dapm_widgets		= pcm3008_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm3008_dapm_widgets),
+	.dapm_routes		= pcm3008_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm3008_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int pcm3008_codec_probe(struct platform_device *pdev)
@@ -146,22 +148,14 @@ static int pcm3008_codec_probe(struct platform_device *pdev)
 	if (ret != 0)
 		return ret;
 
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_pcm3008, &pcm3008_dai, 1);
-}
-
-static int pcm3008_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_pcm3008, &pcm3008_dai, 1);
 }
 
 MODULE_ALIAS("platform:pcm3008-codec");
 
 static struct platform_driver pcm3008_codec_driver = {
 	.probe		= pcm3008_codec_probe,
-	.remove		= pcm3008_codec_remove,
 	.driver		= {
 		.name	= "pcm3008-codec",
 	},
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index b9d1207ccef2..3356c91f55b0 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -287,8 +287,8 @@ static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
 
 static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
 
 	regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
 
@@ -298,7 +298,7 @@ static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
 static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec);
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
 	int ret;
 
 	if (freq > PCM1368A_MAX_SYSCLK)
@@ -316,8 +316,8 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
 static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
 			       unsigned int format, bool dac)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
 	u32 fmt, reg, mask, shift;
 	bool master_mode;
 
@@ -338,7 +338,7 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
 		fmt = PCM3168A_FMT_DSP_B;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported dai format\n");
+		dev_err(component->dev, "unsupported dai format\n");
 		return -EINVAL;
 	}
 
@@ -350,7 +350,7 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
 		master_mode = true;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported master/slave mode\n");
+		dev_err(component->dev, "unsupported master/slave mode\n");
 		return -EINVAL;
 	}
 
@@ -396,8 +396,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
 	bool tx, master_mode;
 	u32 val, mask, shift, reg;
 	unsigned int rate, fmt, ratio, max_ratio;
@@ -430,7 +430,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (i == max_ratio) {
-		dev_err(codec->dev, "unsupported sysclk ratio\n");
+		dev_err(component->dev, "unsupported sysclk ratio\n");
 		return -EINVAL;
 	}
 
@@ -438,21 +438,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
 	switch (min_frame_size) {
 	case 32:
 		if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
-			dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
+			dev_err(component->dev, "32-bit frames are supported only for slave mode using right justified\n");
 			return -EINVAL;
 		}
 		fmt = PCM3168A_FMT_RIGHT_J_16;
 		break;
 	case 48:
 		if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
-			dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
+			dev_err(component->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
 			return -EINVAL;
 		}
 		break;
 	case 64:
 		break;
 	default:
-		dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
+		dev_err(component->dev, "unsupported frame size: %d\n", min_frame_size);
 		return -EINVAL;
 	}
 
@@ -595,16 +595,16 @@ const struct regmap_config pcm3168a_regmap = {
 };
 EXPORT_SYMBOL_GPL(pcm3168a_regmap);
 
-static const struct snd_soc_codec_driver pcm3168a_driver = {
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= pcm3168a_snd_controls,
-		.num_controls		= ARRAY_SIZE(pcm3168a_snd_controls),
-		.dapm_widgets		= pcm3168a_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pcm3168a_dapm_widgets),
-		.dapm_routes		= pcm3168a_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pcm3168a_dapm_routes)
-	},
+static const struct snd_soc_component_driver pcm3168a_driver = {
+	.controls		= pcm3168a_snd_controls,
+	.num_controls		= ARRAY_SIZE(pcm3168a_snd_controls),
+	.dapm_widgets		= pcm3168a_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm3168a_dapm_widgets),
+	.dapm_routes		= pcm3168a_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm3168a_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 int pcm3168a_probe(struct device *dev, struct regmap *regmap)
@@ -669,10 +669,10 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
 	pm_runtime_enable(dev);
 	pm_runtime_idle(dev);
 
-	ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais,
+	ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais,
 			ARRAY_SIZE(pcm3168a_dais));
 	if (ret) {
-		dev_err(dev, "failed to register codec: %d\n", ret);
+		dev_err(dev, "failed to register component: %d\n", ret);
 		goto err_regulator;
 	}
 
@@ -692,7 +692,6 @@ void pcm3168a_remove(struct device *dev)
 {
 	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
 
-	snd_soc_unregister_codec(dev);
 	pm_runtime_disable(dev);
 	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
 				pcm3168a->supplies);
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
index 8ba322a00363..39ac2857a554 100644
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -32,20 +32,19 @@ static struct snd_soc_dai_driver pcm5102a_dai = {
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_pcm5102a;
+static struct snd_soc_component_driver soc_component_dev_pcm5102a = {
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
 
 static int pcm5102a_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a,
+	return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_pcm5102a,
 			&pcm5102a_dai, 1);
 }
 
-static int pcm5102a_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static const struct of_device_id pcm5102a_of_match[] = {
 	{ .compatible = "ti,pcm5102a", },
 	{ }
@@ -54,7 +53,6 @@ MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
 
 static struct platform_driver pcm5102a_codec_driver = {
 	.probe		= pcm5102a_probe,
-	.remove		= pcm5102a_remove,
 	.driver		= {
 		.name	= "pcm5102a-codec",
 		.of_match_table = pcm5102a_of_match,
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index e0f3556d3872..f0f2d4fd3769 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -226,8 +226,8 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
 static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
 	return 0;
@@ -236,10 +236,10 @@ static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
 static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
-	switch (snd_soc_codec_get_bias_level(codec)) {
+	switch (snd_soc_component_get_bias_level(component)) {
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_STANDBY:
 		break;
@@ -254,8 +254,8 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
 static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
 	return 0;
@@ -264,10 +264,10 @@ static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
 static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
-	switch (snd_soc_codec_get_bias_level(codec)) {
+	switch (snd_soc_component_get_bias_level(component)) {
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_STANDBY:
 		break;
@@ -282,8 +282,8 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
 static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
 	return 0;
@@ -292,10 +292,10 @@ static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
 static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
-	switch (snd_soc_codec_get_bias_level(codec)) {
+	switch (snd_soc_component_get_bias_level(component)) {
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_STANDBY:
 		break;
@@ -522,8 +522,8 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
 static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
 				      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	struct device *dev = dai->dev;
 	struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
 	struct snd_ratnum *rats_no_pll;
@@ -564,8 +564,8 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
 static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
 				     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	struct device *dev = dai->dev;
 	struct regmap *regmap = pcm512x->regmap;
 
@@ -590,8 +590,8 @@ static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
 static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
 	switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -606,10 +606,10 @@ static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
 	}
 }
 
-static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
+static int pcm512x_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev);
+	struct pcm512x_priv *pcm512x = dev_get_drvdata(component->dev);
 	int ret;
 
 	switch (level) {
@@ -621,7 +621,7 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
 					 PCM512x_RQST, 0);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to remove standby: %d\n",
+			dev_err(component->dev, "Failed to remove standby: %d\n",
 				ret);
 			return ret;
 		}
@@ -631,7 +631,7 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
 					 PCM512x_RQST, PCM512x_RQST);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to request standby: %d\n",
+			dev_err(component->dev, "Failed to request standby: %d\n",
 				ret);
 			return ret;
 		}
@@ -645,8 +645,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
 				      unsigned long bclk_rate)
 {
 	struct device *dev = dai->dev;
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	unsigned long sck_rate;
 	int pow2;
 
@@ -691,8 +691,8 @@ static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai,
 				  unsigned long pll_rate)
 {
 	struct device *dev = dai->dev;
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	unsigned long common;
 	int R, J, D, P;
 	unsigned long K; /* 10000 * J.D */
@@ -798,8 +798,8 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
 					    unsigned long osr_rate,
 					    unsigned long pllin_rate)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	unsigned long dac_rate;
 
 	if (!pcm512x->pll_out)
@@ -829,8 +829,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 				struct snd_pcm_hw_params *params)
 {
 	struct device *dev = dai->dev;
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	unsigned long pllin_rate = 0;
 	unsigned long pll_rate;
 	unsigned long sck_rate;
@@ -949,7 +949,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
 					 PCM512x_SDAC, PCM512x_SDAC_GPIO);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set gpio as dacref: %d\n", ret);
 			return ret;
 		}
@@ -958,7 +958,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN,
 					 PCM512x_GREF, gpio);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set gpio %d as dacin: %d\n",
 				pcm512x->pll_in, ret);
 			return ret;
@@ -987,7 +987,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
 					 PCM512x_SDAC, PCM512x_SDAC_SCK);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set sck as dacref: %d\n", ret);
 			return ret;
 		}
@@ -1082,18 +1082,18 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 	ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE,
 				 PCM512x_FSSP, fssp);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to set fs speed: %d\n", ret);
+		dev_err(component->dev, "Failed to set fs speed: %d\n", ret);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "DSP divider %d\n", dsp_div);
-	dev_dbg(codec->dev, "DAC divider %d\n", dac_div);
-	dev_dbg(codec->dev, "NCP divider %d\n", ncp_div);
-	dev_dbg(codec->dev, "OSR divider %d\n", osr_div);
-	dev_dbg(codec->dev, "BCK divider %d\n", bclk_div);
-	dev_dbg(codec->dev, "LRCK divider %d\n", lrclk_div);
-	dev_dbg(codec->dev, "IDAC %d\n", idac);
-	dev_dbg(codec->dev, "1<<FSSP %d\n", 1 << fssp);
+	dev_dbg(component->dev, "DSP divider %d\n", dsp_div);
+	dev_dbg(component->dev, "DAC divider %d\n", dac_div);
+	dev_dbg(component->dev, "NCP divider %d\n", ncp_div);
+	dev_dbg(component->dev, "OSR divider %d\n", osr_div);
+	dev_dbg(component->dev, "BCK divider %d\n", bclk_div);
+	dev_dbg(component->dev, "LRCK divider %d\n", lrclk_div);
+	dev_dbg(component->dev, "IDAC %d\n", idac);
+	dev_dbg(component->dev, "1<<FSSP %d\n", 1 << fssp);
 
 	return 0;
 }
@@ -1102,15 +1102,15 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 	int alen;
 	int gpio;
 	int clock_output;
 	int master_mode;
 	int ret;
 
-	dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n",
+	dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
 		params_rate(params),
 		params_channels(params));
 
@@ -1128,7 +1128,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		alen = PCM512x_ALEN_32;
 		break;
 	default:
-		dev_err(codec->dev, "Bad frame size: %d\n",
+		dev_err(component->dev, "Bad frame size: %d\n",
 			params_width(params));
 		return -EINVAL;
 	}
@@ -1141,7 +1141,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 					 | PCM512x_BCKO | PCM512x_LRKO,
 					 0);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to enable slave mode: %d\n", ret);
 			return ret;
 		}
@@ -1149,7 +1149,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
 					 PCM512x_DCAS, 0);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to enable clock divider autoset: %d\n",
 				ret);
 			return ret;
@@ -1170,20 +1170,20 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
 				 PCM512x_ALEN, alen);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to set frame size: %d\n", ret);
+		dev_err(component->dev, "Failed to set frame size: %d\n", ret);
 		return ret;
 	}
 
 	if (pcm512x->pll_out) {
 		ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to set FLEX_A: %d\n", ret);
+			dev_err(component->dev, "Failed to set FLEX_A: %d\n", ret);
 			return ret;
 		}
 
 		ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to set FLEX_B: %d\n", ret);
+			dev_err(component->dev, "Failed to set FLEX_B: %d\n", ret);
 			return ret;
 		}
 
@@ -1196,7 +1196,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 					 | PCM512x_IDSK | PCM512x_IDCH
 					 | PCM512x_DCAS);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to ignore auto-clock failures: %d\n",
 				ret);
 			return ret;
@@ -1211,7 +1211,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 					 | PCM512x_IDSK | PCM512x_IDCH
 					 | PCM512x_DCAS | PCM512x_IPLK);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to ignore auto-clock failures: %d\n",
 				ret);
 			return ret;
@@ -1220,7 +1220,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
 					 PCM512x_PLLE, 0);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to disable pll: %d\n", ret);
+			dev_err(component->dev, "Failed to disable pll: %d\n", ret);
 			return ret;
 		}
 	}
@@ -1233,7 +1233,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
 					 PCM512x_SREF, PCM512x_SREF_GPIO);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set gpio as pllref: %d\n", ret);
 			return ret;
 		}
@@ -1242,7 +1242,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN,
 					 PCM512x_GREF, gpio);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set gpio %d as pllin: %d\n",
 				pcm512x->pll_in, ret);
 			return ret;
@@ -1251,7 +1251,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
 					 PCM512x_PLLE, PCM512x_PLLE);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to enable pll: %d\n", ret);
+			dev_err(component->dev, "Failed to enable pll: %d\n", ret);
 			return ret;
 		}
 	}
@@ -1260,7 +1260,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 				 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
 				 clock_output);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable clock output: %d\n", ret);
+		dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
 		return ret;
 	}
 
@@ -1268,7 +1268,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 				 PCM512x_RLRK | PCM512x_RBCK,
 				 master_mode);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable master mode: %d\n", ret);
+		dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
 		return ret;
 	}
 
@@ -1277,7 +1277,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
 					 gpio, gpio);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+			dev_err(component->dev, "Failed to enable gpio %d: %d\n",
 				pcm512x->pll_out, ret);
 			return ret;
 		}
@@ -1286,7 +1286,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 		ret = regmap_update_bits(pcm512x->regmap, gpio,
 					 PCM512x_GxSL, PCM512x_GxSL_PLLCK);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to output pll on %d: %d\n",
+			dev_err(component->dev, "Failed to output pll on %d: %d\n",
 				ret, pcm512x->pll_out);
 			return ret;
 		}
@@ -1295,14 +1295,14 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 	ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
 				 PCM512x_RQSY, PCM512x_RQSY_HALT);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to halt clocks: %d\n", ret);
+		dev_err(component->dev, "Failed to halt clocks: %d\n", ret);
 		return ret;
 	}
 
 	ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
 				 PCM512x_RQSY, PCM512x_RQSY_RESUME);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to resume clocks: %d\n", ret);
+		dev_err(component->dev, "Failed to resume clocks: %d\n", ret);
 		return ret;
 	}
 
@@ -1311,8 +1311,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
 
 static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
 
 	pcm512x->fmt = fmt;
 
@@ -1341,18 +1341,17 @@ static struct snd_soc_dai_driver pcm512x_dai = {
 	.ops = &pcm512x_dai_ops,
 };
 
-static const struct snd_soc_codec_driver pcm512x_codec_driver = {
-	.set_bias_level = pcm512x_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= pcm512x_controls,
-		.num_controls		= ARRAY_SIZE(pcm512x_controls),
-		.dapm_widgets		= pcm512x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pcm512x_dapm_widgets),
-		.dapm_routes		= pcm512x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pcm512x_dapm_routes),
-	},
+static const struct snd_soc_component_driver pcm512x_component_driver = {
+	.set_bias_level		= pcm512x_set_bias_level,
+	.controls		= pcm512x_controls,
+	.num_controls		= ARRAY_SIZE(pcm512x_controls),
+	.dapm_widgets		= pcm512x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm512x_dapm_widgets),
+	.dapm_routes		= pcm512x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm512x_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_range_cfg pcm512x_range = {
@@ -1498,7 +1497,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
 	}
 #endif
 
-	ret = snd_soc_register_codec(dev, &pcm512x_codec_driver,
+	ret = devm_snd_soc_register_component(dev, &pcm512x_component_driver,
 				    &pcm512x_dai, 1);
 	if (ret != 0) {
 		dev_err(dev, "Failed to register CODEC: %d\n", ret);
@@ -1523,7 +1522,6 @@ void pcm512x_remove(struct device *dev)
 {
 	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
 
-	snd_soc_unregister_codec(dev);
 	pm_runtime_disable(dev);
 	if (!IS_ERR(pcm512x->sclk))
 		clk_disable_unprepare(pcm512x->sclk);
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index 8f92e5c4dd9d..d88e67341083 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -38,7 +38,7 @@ struct rt274_priv {
 	struct reg_default *index_cache;
 	int index_cache_size;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct i2c_client *i2c;
 	struct snd_soc_jack *jack;
 	struct delayed_work jack_detect_work;
@@ -338,13 +338,13 @@ static bool rt274_readable_register(struct device *dev, unsigned int reg)
 }
 
 #ifdef CONFIG_PM
-static void rt274_index_sync(struct snd_soc_codec *codec)
+static void rt274_index_sync(struct snd_soc_component *component)
 {
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
-		snd_soc_write(codec, rt274->index_cache[i].reg,
+		snd_soc_component_write(component, rt274->index_cache[i].reg,
 				  rt274->index_cache[i].def);
 	}
 }
@@ -357,7 +357,7 @@ static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic)
 	*hp = false;
 	*mic = false;
 
-	if (!rt274->codec)
+	if (!rt274->component)
 		return -EINVAL;
 
 	regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf);
@@ -393,10 +393,10 @@ static void rt274_jack_detect_work(struct work_struct *work)
 
 static irqreturn_t rt274_irq(int irq, void *data);
 
-static int rt274_mic_detect(struct snd_soc_codec *codec,
+static int rt274_mic_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack,  void *data)
 {
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
 	if (jack == NULL) {
 		/* Disable jack detection */
@@ -609,8 +609,8 @@ static int rt274_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 	int d_len_code = 0, c_len_code = 0;
 
@@ -620,7 +620,7 @@ static int rt274_hw_params(struct snd_pcm_substream *substream,
 	case 48000:
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported sample rate %d\n",
+		dev_err(component->dev, "Unsupported sample rate %d\n",
 					params_rate(params));
 		return -EINVAL;
 	}
@@ -628,7 +628,7 @@ static int rt274_hw_params(struct snd_pcm_substream *substream,
 	case 12288000:
 	case 24576000:
 		if (params_rate(params) != 48000) {
-			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
 					params_rate(params), rt274->sys_clk);
 			return -EINVAL;
 		}
@@ -636,7 +636,7 @@ static int rt274_hw_params(struct snd_pcm_substream *substream,
 	case 11289600:
 	case 22579200:
 		if (params_rate(params) != 44100) {
-			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
 					params_rate(params), rt274->sys_clk);
 			return -EINVAL;
 		}
@@ -647,7 +647,7 @@ static int rt274_hw_params(struct snd_pcm_substream *substream,
 		/* bit 3:0 Number of Channel */
 		val |= (params_channels(params) - 1);
 	} else {
-		dev_err(codec->dev, "Unsupported channels %d\n",
+		dev_err(component->dev, "Unsupported channels %d\n",
 					params_channels(params));
 		return -EINVAL;
 	}
@@ -685,29 +685,29 @@ static int rt274_hw_params(struct snd_pcm_substream *substream,
 	if (rt274->master)
 		c_len_code = 0x3;
 
-	snd_soc_update_bits(codec,
+	snd_soc_component_update_bits(component,
 		RT274_I2S_CTRL1, 0xc018, d_len_code << 3 | c_len_code << 14);
-	dev_dbg(codec->dev, "format val = 0x%x\n", val);
+	dev_dbg(component->dev, "format val = 0x%x\n", val);
 
-	snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x407f, val);
-	snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT274_DAC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT274_ADC_FORMAT, 0x407f, val);
 
 	return 0;
 }
 
 static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M);
 		rt274->master = true;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S);
 		rt274->master = false;
 		break;
@@ -717,27 +717,27 @@ static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
 					RT274_I2S_FMT_MASK, RT274_I2S_FMT_I2S);
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
 					RT274_I2S_FMT_MASK, RT274_I2S_FMT_LJ);
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
-		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
 					RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMA);
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		snd_soc_update_bits(codec, RT274_I2S_CTRL1,
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
 					RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMB);
 		break;
 	default:
 		return -EINVAL;
 	}
 	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
-	snd_soc_update_bits(codec, RT274_DAC_FORMAT, 0x8000, 0);
-	snd_soc_update_bits(codec, RT274_ADC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT274_DAC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT274_ADC_FORMAT, 0x8000, 0);
 
 	return 0;
 }
@@ -745,47 +745,47 @@ static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
 	switch (source) {
 	case RT274_PLL2_S_MCLK:
-		snd_soc_update_bits(codec, RT274_PLL2_CTRL,
+		snd_soc_component_update_bits(component, RT274_PLL2_CTRL,
 				RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_MCLK);
 		break;
 	default:
-		dev_warn(codec->dev, "invalid pll source, use BCLK\n");
+		dev_warn(component->dev, "invalid pll source, use BCLK\n");
 	case RT274_PLL2_S_BCLK:
-		snd_soc_update_bits(codec, RT274_PLL2_CTRL,
+		snd_soc_component_update_bits(component, RT274_PLL2_CTRL,
 				RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK);
 		break;
 	}
 
 	if (source == RT274_PLL2_S_BCLK) {
-		snd_soc_update_bits(codec, RT274_MCLK_CTRL,
+		snd_soc_component_update_bits(component, RT274_MCLK_CTRL,
 				(0x3 << 12), (0x3 << 12));
 		switch (rt274->fs) {
 		case 50:
-			snd_soc_write(codec, 0x7a, 0xaab6);
-			snd_soc_write(codec, 0x7b, 0x0301);
-			snd_soc_write(codec, 0x7c, 0x04fe);
+			snd_soc_component_write(component, 0x7a, 0xaab6);
+			snd_soc_component_write(component, 0x7b, 0x0301);
+			snd_soc_component_write(component, 0x7c, 0x04fe);
 			break;
 		case 64:
-			snd_soc_write(codec, 0x7a, 0xaa96);
-			snd_soc_write(codec, 0x7b, 0x8003);
-			snd_soc_write(codec, 0x7c, 0x081e);
+			snd_soc_component_write(component, 0x7a, 0xaa96);
+			snd_soc_component_write(component, 0x7b, 0x8003);
+			snd_soc_component_write(component, 0x7c, 0x081e);
 			break;
 		case 128:
-			snd_soc_write(codec, 0x7a, 0xaa96);
-			snd_soc_write(codec, 0x7b, 0x8003);
-			snd_soc_write(codec, 0x7c, 0x080e);
+			snd_soc_component_write(component, 0x7a, 0xaa96);
+			snd_soc_component_write(component, 0x7b, 0x8003);
+			snd_soc_component_write(component, 0x7c, 0x080e);
 			break;
 		default:
-			dev_warn(codec->dev, "invalid freq_in, assume 4.8M\n");
+			dev_warn(component->dev, "invalid freq_in, assume 4.8M\n");
 		case 100:
-			snd_soc_write(codec, 0x7a, 0xaab6);
-			snd_soc_write(codec, 0x7b, 0x0301);
-			snd_soc_write(codec, 0x7c, 0x047e);
+			snd_soc_component_write(component, 0x7a, 0xaab6);
+			snd_soc_component_write(component, 0x7b, 0x0301);
+			snd_soc_component_write(component, 0x7c, 0x047e);
 			break;
 		}
 	}
@@ -796,11 +796,11 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt274_set_dai_sysclk(struct snd_soc_dai *dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 	unsigned int clk_src, mclk_en;
 
-	dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq);
+	dev_dbg(component->dev, "%s freq=%d\n", __func__, freq);
 
 	switch (clk_id) {
 	case RT274_SCLK_S_MCLK:
@@ -818,43 +818,43 @@ static int rt274_set_dai_sysclk(struct snd_soc_dai *dai,
 	default:
 		mclk_en = RT274_MCLK_MODE_DIS;
 		clk_src = RT274_CLK_SRC_MCLK;
-		dev_warn(codec->dev, "invalid sysclk source, use PLL1\n");
+		dev_warn(component->dev, "invalid sysclk source, use PLL1\n");
 		break;
 	}
-	snd_soc_update_bits(codec, RT274_MCLK_CTRL,
+	snd_soc_component_update_bits(component, RT274_MCLK_CTRL,
 			RT274_MCLK_MODE_MASK, mclk_en);
-	snd_soc_update_bits(codec, RT274_CLK_CTRL,
+	snd_soc_component_update_bits(component, RT274_CLK_CTRL,
 			RT274_CLK_SRC_MASK, clk_src);
 
 	switch (freq) {
 	case 19200000:
 		if (clk_id == RT274_SCLK_S_MCLK) {
-			dev_err(codec->dev, "Should not use MCLK\n");
+			dev_err(component->dev, "Should not use MCLK\n");
 			return -EINVAL;
 		}
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL2, 0x40, 0x40);
 		break;
 	case 24000000:
 		if (clk_id == RT274_SCLK_S_MCLK) {
-			dev_err(codec->dev, "Should not use MCLK\n");
+			dev_err(component->dev, "Should not use MCLK\n");
 			return -EINVAL;
 		}
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL2, 0x40, 0x0);
 		break;
 	case 12288000:
 	case 11289600:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_MCLK_CTRL, 0x1fcf, 0x0008);
 		break;
 	case 24576000:
 	case 22579200:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_MCLK_CTRL, 0x1fcf, 0x1543);
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported system clock\n");
+		dev_err(component->dev, "Unsupported system clock\n");
 		return -EINVAL;
 	}
 
@@ -866,16 +866,16 @@ static int rt274_set_dai_sysclk(struct snd_soc_dai *dai,
 
 static int rt274_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
 	rt274->fs = ratio;
 	if ((ratio / 50) == 0)
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, 0x1000, 0x1000);
 	else
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, 0x1000, 0x0);
 
 
@@ -886,28 +886,28 @@ static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (rx_mask || tx_mask) {
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_EN);
 	} else {
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_DIS);
 		return 0;
 	}
 
 	switch (slots) {
 	case 4:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_4CH);
 		break;
 	case 2:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_2CH);
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Support 2 or 4 slots TDM only\n");
 		return -EINVAL;
 	}
@@ -915,20 +915,20 @@ static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
-static int rt274_set_bias_level(struct snd_soc_codec *codec,
+static int rt274_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 		if (SND_SOC_BIAS_STANDBY ==
-			snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_write(codec,
+			snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_write(component,
 				RT274_SET_AUDIO_POWER, AC_PWRST_D0);
 		}
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT274_SET_AUDIO_POWER, AC_PWRST_D3);
 		break;
 
@@ -968,11 +968,11 @@ static irqreturn_t rt274_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int rt274_probe(struct snd_soc_codec *codec)
+static int rt274_probe(struct snd_soc_component *component)
 {
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
-	rt274->codec = codec;
+	rt274->component = component;
 
 	if (rt274->i2c->irq) {
 		INIT_DELAYED_WORK(&rt274->jack_detect_work,
@@ -984,19 +984,17 @@ static int rt274_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt274_remove(struct snd_soc_codec *codec)
+static void rt274_remove(struct snd_soc_component *component)
 {
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
 	cancel_delayed_work_sync(&rt274->jack_detect_work);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt274_suspend(struct snd_soc_codec *codec)
+static int rt274_suspend(struct snd_soc_component *component)
 {
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt274->regmap, true);
 	regcache_mark_dirty(rt274->regmap);
@@ -1004,12 +1002,12 @@ static int rt274_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt274_resume(struct snd_soc_codec *codec)
+static int rt274_resume(struct snd_soc_component *component)
 {
-	struct rt274_priv *rt274 = snd_soc_codec_get_drvdata(codec);
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt274->regmap, false);
-	rt274_index_sync(codec);
+	rt274_index_sync(component);
 	regcache_sync(rt274->regmap);
 
 	return 0;
@@ -1055,22 +1053,22 @@ static struct snd_soc_dai_driver rt274_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt274 = {
-	.probe = rt274_probe,
-	.remove = rt274_remove,
-	.suspend = rt274_suspend,
-	.resume = rt274_resume,
-	.set_bias_level = rt274_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt274_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt274_snd_controls),
-		.dapm_widgets		= rt274_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt274_dapm_widgets),
-		.dapm_routes		= rt274_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt274_dapm_routes),
-	},
-	.set_jack = rt274_mic_detect,
+static const struct snd_soc_component_driver soc_component_dev_rt274 = {
+	.probe			= rt274_probe,
+	.remove			= rt274_remove,
+	.suspend		= rt274_suspend,
+	.resume			= rt274_resume,
+	.set_bias_level		= rt274_set_bias_level,
+	.set_jack		= rt274_mic_detect,
+	.controls		= rt274_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt274_snd_controls),
+	.dapm_widgets		= rt274_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt274_dapm_widgets),
+	.dapm_routes		= rt274_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt274_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt274_regmap = {
@@ -1191,7 +1189,8 @@ static int rt274_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt274,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_rt274,
 				     rt274_dai, ARRAY_SIZE(rt274_dai));
 
 	return ret;
@@ -1203,7 +1202,6 @@ static int rt274_i2c_remove(struct i2c_client *i2c)
 
 	if (i2c->irq)
 		free_irq(i2c->irq, rt274);
-	snd_soc_unregister_codec(&i2c->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index af6325c78292..e1643571d643 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -40,7 +40,7 @@ struct rt286_priv {
 	struct reg_default *index_cache;
 	int index_cache_size;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt286_platform_data pdata;
 	struct i2c_client *i2c;
 	struct snd_soc_jack *jack;
@@ -187,13 +187,13 @@ static bool rt286_readable_register(struct device *dev, unsigned int reg)
 }
 
 #ifdef CONFIG_PM
-static void rt286_index_sync(struct snd_soc_codec *codec)
+static void rt286_index_sync(struct snd_soc_component *component)
 {
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
-		snd_soc_write(codec, rt286->index_cache[i].reg,
+		snd_soc_component_write(component, rt286->index_cache[i].reg,
 				  rt286->index_cache[i].def);
 	}
 }
@@ -220,10 +220,10 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
 	*hp = false;
 	*mic = false;
 
-	if (!rt286->codec)
+	if (!rt286->component)
 		return -EINVAL;
 
-	dapm = snd_soc_codec_get_dapm(rt286->codec);
+	dapm = snd_soc_component_get_dapm(rt286->component);
 
 	if (rt286->pdata.cbj_en) {
 		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@@ -305,10 +305,10 @@ static void rt286_jack_detect_work(struct work_struct *work)
 		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
 }
 
-int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
 	rt286->jack = jack;
 
@@ -334,8 +334,8 @@ EXPORT_SYMBOL_GPL(rt286_mic_detect);
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
 	if (rt286->clk_id == RT286_SCLK_S_MCLK)
 		return 1;
@@ -434,15 +434,15 @@ SOC_DAPM_ENUM("SPO source", rt286_spo_enum);
 static int rt286_spk_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT286_SPK_EAPD, RT286_SET_EAPD_HIGH);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT286_SPK_EAPD, RT286_SET_EAPD_LOW);
 		break;
 
@@ -456,14 +456,14 @@ static int rt286_spk_event(struct snd_soc_dapm_widget *w,
 static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0x20);
+		snd_soc_component_write(component, RT286_SET_PIN_DMIC1, 0x20);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0);
+		snd_soc_component_write(component, RT286_SET_PIN_DMIC1, 0);
 		break;
 	default:
 		return 0;
@@ -475,14 +475,14 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
 static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08);
+		snd_soc_component_update_bits(component, RT286_POWER_CTRL2, 0x38, 0x08);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30);
+		snd_soc_component_update_bits(component, RT286_POWER_CTRL2, 0x38, 0x30);
 		break;
 	default:
 		return 0;
@@ -494,19 +494,19 @@ static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
 static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
 		break;
 	default:
@@ -674,8 +674,8 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 	int d_len_code;
 
@@ -687,7 +687,7 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
 	case 48000:
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported sample rate %d\n",
+		dev_err(component->dev, "Unsupported sample rate %d\n",
 					params_rate(params));
 		return -EINVAL;
 	}
@@ -695,7 +695,7 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
 	case 12288000:
 	case 24576000:
 		if (params_rate(params) != 48000) {
-			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
 					params_rate(params), rt286->sys_clk);
 			return -EINVAL;
 		}
@@ -703,7 +703,7 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
 	case 11289600:
 	case 22579200:
 		if (params_rate(params) != 44100) {
-			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
 					params_rate(params), rt286->sys_clk);
 			return -EINVAL;
 		}
@@ -714,7 +714,7 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
 		/* bit 3:0 Number of Channel */
 		val |= (params_channels(params) - 1);
 	} else {
-		dev_err(codec->dev, "Unsupported channels %d\n",
+		dev_err(component->dev, "Unsupported channels %d\n",
 					params_channels(params));
 		return -EINVAL;
 	}
@@ -745,27 +745,27 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec,
+	snd_soc_component_update_bits(component,
 		RT286_I2S_CTRL1, 0x0018, d_len_code << 3);
-	dev_dbg(codec->dev, "format val = 0x%x\n", val);
+	dev_dbg(component->dev, "format val = 0x%x\n", val);
 
-	snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val);
-	snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT286_DAC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT286_ADC_FORMAT, 0x407f, val);
 
 	return 0;
 }
 
 static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x800, 0x800);
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x800, 0x0);
 		break;
 	default:
@@ -774,27 +774,27 @@ static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x300, 0x0);
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x300, 0x1 << 8);
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x300, 0x2 << 8);
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x300, 0x3 << 8);
 		break;
 	default:
 		return -EINVAL;
 	}
 	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
-	snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x8000, 0);
-	snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT286_DAC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT286_ADC_FORMAT, 0x8000, 0);
 
 	return 0;
 }
@@ -802,58 +802,58 @@ static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq);
+	dev_dbg(component->dev, "%s freq=%d\n", __func__, freq);
 
 	if (RT286_SCLK_S_MCLK == clk_id) {
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL2, 0x0100, 0x0);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_PLL_CTRL1, 0x20, 0x20);
 	} else {
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL2, 0x0100, 0x0100);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_PLL_CTRL, 0x4, 0x4);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_PLL_CTRL1, 0x20, 0x0);
 	}
 
 	switch (freq) {
 	case 19200000:
 		if (RT286_SCLK_S_MCLK == clk_id) {
-			dev_err(codec->dev, "Should not use MCLK\n");
+			dev_err(component->dev, "Should not use MCLK\n");
 			return -EINVAL;
 		}
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL2, 0x40, 0x40);
 		break;
 	case 24000000:
 		if (RT286_SCLK_S_MCLK == clk_id) {
-			dev_err(codec->dev, "Should not use MCLK\n");
+			dev_err(component->dev, "Should not use MCLK\n");
 			return -EINVAL;
 		}
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL2, 0x40, 0x0);
 		break;
 	case 12288000:
 	case 11289600:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL2, 0x8, 0x0);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_CLK_DIV, 0xfc1e, 0x0004);
 		break;
 	case 24576000:
 	case 22579200:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL2, 0x8, 0x8);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_CLK_DIV, 0xfc1e, 0x5406);
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported system clock\n");
+		dev_err(component->dev, "Unsupported system clock\n");
 		return -EINVAL;
 	}
 
@@ -865,42 +865,42 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
 
 static int rt286_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
 	if (50 == ratio)
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x1000, 0x1000);
 	else
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_I2S_CTRL1, 0x1000, 0x0);
 
 
 	return 0;
 }
 
-static int rt286_set_bias_level(struct snd_soc_codec *codec,
+static int rt286_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_write(codec,
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_write(component,
 				RT286_SET_AUDIO_POWER, AC_PWRST_D0);
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 				RT286_DC_GAIN, 0x200, 0x200);
 		}
 		break;
 
 	case SND_SOC_BIAS_ON:
 		mdelay(10);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT286_DC_GAIN, 0x200, 0x0);
 
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT286_SET_AUDIO_POWER, AC_PWRST_D3);
 		break;
 
@@ -937,11 +937,11 @@ static irqreturn_t rt286_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int rt286_probe(struct snd_soc_codec *codec)
+static int rt286_probe(struct snd_soc_component *component)
 {
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
-	rt286->codec = codec;
+	rt286->component = component;
 
 	if (rt286->i2c->irq) {
 		regmap_update_bits(rt286->regmap,
@@ -956,19 +956,17 @@ static int rt286_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt286_remove(struct snd_soc_codec *codec)
+static void rt286_remove(struct snd_soc_component *component)
 {
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
 	cancel_delayed_work_sync(&rt286->jack_detect_work);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt286_suspend(struct snd_soc_codec *codec)
+static int rt286_suspend(struct snd_soc_component *component)
 {
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt286->regmap, true);
 	regcache_mark_dirty(rt286->regmap);
@@ -976,12 +974,12 @@ static int rt286_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt286_resume(struct snd_soc_codec *codec)
+static int rt286_resume(struct snd_soc_component *component)
 {
-	struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt286->regmap, false);
-	rt286_index_sync(codec);
+	rt286_index_sync(component);
 	regcache_sync(rt286->regmap);
 
 	return 0;
@@ -1046,21 +1044,21 @@ static struct snd_soc_dai_driver rt286_dai[] = {
 
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt286 = {
-	.probe = rt286_probe,
-	.remove = rt286_remove,
-	.suspend = rt286_suspend,
-	.resume = rt286_resume,
-	.set_bias_level = rt286_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt286_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt286_snd_controls),
-		.dapm_widgets		= rt286_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt286_dapm_widgets),
-		.dapm_routes		= rt286_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt286_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt286 = {
+	.probe			= rt286_probe,
+	.remove			= rt286_remove,
+	.suspend		= rt286_suspend,
+	.resume			= rt286_resume,
+	.set_bias_level		= rt286_set_bias_level,
+	.controls		= rt286_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt286_snd_controls),
+	.dapm_widgets		= rt286_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt286_dapm_widgets),
+	.dapm_routes		= rt286_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt286_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt286_regmap = {
@@ -1243,7 +1241,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt286,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_rt286,
 				     rt286_dai, ARRAY_SIZE(rt286_dai));
 
 	return ret;
@@ -1255,7 +1254,6 @@ static int rt286_i2c_remove(struct i2c_client *i2c)
 
 	if (i2c->irq)
 		free_irq(i2c->irq, rt286);
-	snd_soc_unregister_codec(&i2c->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h
index 7130edb152ef..c63d0e79ba86 100644
--- a/sound/soc/codecs/rt286.h
+++ b/sound/soc/codecs/rt286.h
@@ -199,7 +199,7 @@ enum {
 	RT286_AIFS,
 };
 
-int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
 
 #endif /* __RT286_H__ */
 
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index ce963768449f..7bf4b31bdf55 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -39,7 +39,7 @@ struct rt298_priv {
 	struct reg_default *index_cache;
 	int index_cache_size;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt298_platform_data pdata;
 	struct i2c_client *i2c;
 	struct snd_soc_jack *jack;
@@ -194,13 +194,13 @@ static bool rt298_readable_register(struct device *dev, unsigned int reg)
 }
 
 #ifdef CONFIG_PM
-static void rt298_index_sync(struct snd_soc_codec *codec)
+static void rt298_index_sync(struct snd_soc_component *component)
 {
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
-		snd_soc_write(codec, rt298->index_cache[i].reg,
+		snd_soc_component_write(component, rt298->index_cache[i].reg,
 				  rt298->index_cache[i].def);
 	}
 }
@@ -227,10 +227,10 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
 	*hp = false;
 	*mic = false;
 
-	if (!rt298->codec)
+	if (!rt298->component)
 		return -EINVAL;
 
-	dapm = snd_soc_codec_get_dapm(rt298->codec);
+	dapm = snd_soc_component_get_dapm(rt298->component);
 
 	if (rt298->pdata.cbj_en) {
 		regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
@@ -323,9 +323,9 @@ static void rt298_jack_detect_work(struct work_struct *work)
 		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
 }
 
-int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 	struct snd_soc_dapm_context *dapm;
 	bool hp = false;
 	bool mic = false;
@@ -334,7 +334,7 @@ int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 	/* If jack in NULL, disable HS jack */
 	if (!jack) {
 		regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0);
-		dapm = snd_soc_codec_get_dapm(codec);
+		dapm = snd_soc_component_get_dapm(component);
 		snd_soc_dapm_disable_pin(dapm, "LDO1");
 		snd_soc_dapm_sync(dapm);
 		return 0;
@@ -360,8 +360,8 @@ EXPORT_SYMBOL_GPL(rt298_mic_detect);
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
 	if (rt298->clk_id == RT298_SCLK_S_MCLK)
 		return 1;
@@ -458,15 +458,15 @@ SOC_DAPM_ENUM("SPO source", rt298_spo_enum);
 static int rt298_spk_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT298_SPK_EAPD, RT298_SET_EAPD_HIGH);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT298_SPK_EAPD, RT298_SET_EAPD_LOW);
 		break;
 
@@ -480,14 +480,14 @@ static int rt298_spk_event(struct snd_soc_dapm_widget *w,
 static int rt298_set_dmic1_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0x20);
+		snd_soc_component_write(component, RT298_SET_PIN_DMIC1, 0x20);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0);
+		snd_soc_component_write(component, RT298_SET_PIN_DMIC1, 0);
 		break;
 	default:
 		return 0;
@@ -499,39 +499,39 @@ static int rt298_set_dmic1_event(struct snd_soc_dapm_widget *w,
 static int rt298_adc_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int nid;
 
 	nid = (w->reg >> 20) & 0xff;
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
 			0x7080, 0x7000);
 		 /* If MCLK doesn't exist, reset AD filter */
-		if (!(snd_soc_read(codec, RT298_VAD_CTRL) & 0x200)) {
+		if (!(snd_soc_component_read32(component, RT298_VAD_CTRL) & 0x200)) {
 			pr_info("NO MCLK\n");
 			switch (nid) {
 			case RT298_ADC_IN1:
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					RT298_D_FILTER_CTRL, 0x2, 0x2);
 				mdelay(10);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					RT298_D_FILTER_CTRL, 0x2, 0x0);
 				break;
 			case RT298_ADC_IN2:
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					RT298_D_FILTER_CTRL, 0x4, 0x4);
 				mdelay(10);
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					RT298_D_FILTER_CTRL, 0x4, 0x0);
 				break;
 			}
 		}
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
 			0x7080, 0x7080);
 		break;
@@ -545,19 +545,19 @@ static int rt298_adc_event(struct snd_soc_dapm_widget *w,
 static int rt298_mic1_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_A_BIAS_CTRL3, 0xc000, 0x8000);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_A_BIAS_CTRL2, 0xc000, 0x8000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_A_BIAS_CTRL3, 0xc000, 0x0000);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_A_BIAS_CTRL2, 0xc000, 0x0000);
 		break;
 	default:
@@ -745,8 +745,8 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 	int d_len_code;
 
@@ -756,7 +756,7 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
 	case 48000:
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported sample rate %d\n",
+		dev_err(component->dev, "Unsupported sample rate %d\n",
 					params_rate(params));
 		return -EINVAL;
 	}
@@ -764,7 +764,7 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
 	case 12288000:
 	case 24576000:
 		if (params_rate(params) != 48000) {
-			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
 					params_rate(params), rt298->sys_clk);
 			return -EINVAL;
 		}
@@ -772,7 +772,7 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
 	case 11289600:
 	case 22579200:
 		if (params_rate(params) != 44100) {
-			dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n",
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
 					params_rate(params), rt298->sys_clk);
 			return -EINVAL;
 		}
@@ -783,7 +783,7 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
 		/* bit 3:0 Number of Channel */
 		val |= (params_channels(params) - 1);
 	} else {
-		dev_err(codec->dev, "Unsupported channels %d\n",
+		dev_err(component->dev, "Unsupported channels %d\n",
 					params_channels(params));
 		return -EINVAL;
 	}
@@ -814,27 +814,27 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec,
+	snd_soc_component_update_bits(component,
 		RT298_I2S_CTRL1, 0x0018, d_len_code << 3);
-	dev_dbg(codec->dev, "format val = 0x%x\n", val);
+	dev_dbg(component->dev, "format val = 0x%x\n", val);
 
-	snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x407f, val);
-	snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT298_DAC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT298_ADC_FORMAT, 0x407f, val);
 
 	return 0;
 }
 
 static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x800, 0x800);
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x800, 0x0);
 		break;
 	default:
@@ -843,27 +843,27 @@ static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x300, 0x0);
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x300, 0x1 << 8);
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x300, 0x2 << 8);
 		break;
 	case SND_SOC_DAIFMT_DSP_B:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x300, 0x3 << 8);
 		break;
 	default:
 		return -EINVAL;
 	}
 	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
-	snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x8000, 0);
-	snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT298_DAC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT298_ADC_FORMAT, 0x8000, 0);
 
 	return 0;
 }
@@ -871,56 +871,56 @@ static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt298_set_dai_sysclk(struct snd_soc_dai *dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq);
+	dev_dbg(component->dev, "%s freq=%d\n", __func__, freq);
 
 	if (RT298_SCLK_S_MCLK == clk_id) {
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL2, 0x0100, 0x0);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_PLL_CTRL1, 0x20, 0x20);
 	} else {
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL2, 0x0100, 0x0100);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_PLL_CTRL1, 0x20, 0x0);
 	}
 
 	switch (freq) {
 	case 19200000:
 		if (RT298_SCLK_S_MCLK == clk_id) {
-			dev_err(codec->dev, "Should not use MCLK\n");
+			dev_err(component->dev, "Should not use MCLK\n");
 			return -EINVAL;
 		}
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL2, 0x40, 0x40);
 		break;
 	case 24000000:
 		if (RT298_SCLK_S_MCLK == clk_id) {
-			dev_err(codec->dev, "Should not use MCLK\n");
+			dev_err(component->dev, "Should not use MCLK\n");
 			return -EINVAL;
 		}
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL2, 0x40, 0x0);
 		break;
 	case 12288000:
 	case 11289600:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL2, 0x8, 0x0);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_CLK_DIV, 0xfc1e, 0x0004);
 		break;
 	case 24576000:
 	case 22579200:
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL2, 0x8, 0x8);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_CLK_DIV, 0xfc1e, 0x5406);
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported system clock\n");
+		dev_err(component->dev, "Unsupported system clock\n");
 		return -EINVAL;
 	}
 
@@ -932,39 +932,39 @@ static int rt298_set_dai_sysclk(struct snd_soc_dai *dai,
 
 static int rt298_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
 	if (50 == ratio)
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x1000, 0x1000);
 	else
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 			RT298_I2S_CTRL1, 0x1000, 0x0);
 
 
 	return 0;
 }
 
-static int rt298_set_bias_level(struct snd_soc_codec *codec,
+static int rt298_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
 		if (SND_SOC_BIAS_STANDBY ==
-			snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_write(codec,
+			snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_write(component,
 				RT298_SET_AUDIO_POWER, AC_PWRST_D0);
-			snd_soc_update_bits(codec, 0x0d, 0x200, 0x200);
-			snd_soc_update_bits(codec, 0x52, 0x80, 0x0);
+			snd_soc_component_update_bits(component, 0x0d, 0x200, 0x200);
+			snd_soc_component_update_bits(component, 0x52, 0x80, 0x0);
 			mdelay(20);
-			snd_soc_update_bits(codec, 0x0d, 0x200, 0x0);
-			snd_soc_update_bits(codec, 0x52, 0x80, 0x80);
+			snd_soc_component_update_bits(component, 0x0d, 0x200, 0x0);
+			snd_soc_component_update_bits(component, 0x52, 0x80, 0x80);
 		}
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec,
+		snd_soc_component_write(component,
 			RT298_SET_AUDIO_POWER, AC_PWRST_D3);
 		break;
 
@@ -1003,11 +1003,11 @@ static irqreturn_t rt298_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int rt298_probe(struct snd_soc_codec *codec)
+static int rt298_probe(struct snd_soc_component *component)
 {
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
-	rt298->codec = codec;
+	rt298->component = component;
 
 	if (rt298->i2c->irq) {
 		regmap_update_bits(rt298->regmap,
@@ -1022,19 +1022,17 @@ static int rt298_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt298_remove(struct snd_soc_codec *codec)
+static void rt298_remove(struct snd_soc_component *component)
 {
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
 	cancel_delayed_work_sync(&rt298->jack_detect_work);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt298_suspend(struct snd_soc_codec *codec)
+static int rt298_suspend(struct snd_soc_component *component)
 {
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
 	rt298->is_hp_in = -1;
 	regcache_cache_only(rt298->regmap, true);
@@ -1043,12 +1041,12 @@ static int rt298_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt298_resume(struct snd_soc_codec *codec)
+static int rt298_resume(struct snd_soc_component *component)
 {
-	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt298->regmap, false);
-	rt298_index_sync(codec);
+	rt298_index_sync(component);
 	regcache_sync(rt298->regmap);
 
 	return 0;
@@ -1113,21 +1111,21 @@ static struct snd_soc_dai_driver rt298_dai[] = {
 
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt298 = {
-	.probe = rt298_probe,
-	.remove = rt298_remove,
-	.suspend = rt298_suspend,
-	.resume = rt298_resume,
-	.set_bias_level = rt298_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt298_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt298_snd_controls),
-		.dapm_widgets		= rt298_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt298_dapm_widgets),
-		.dapm_routes		= rt298_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt298_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt298 = {
+	.probe			= rt298_probe,
+	.remove			= rt298_remove,
+	.suspend		= rt298_suspend,
+	.resume			= rt298_resume,
+	.set_bias_level		= rt298_set_bias_level,
+	.controls		= rt298_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt298_snd_controls),
+	.dapm_widgets		= rt298_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt298_dapm_widgets),
+	.dapm_routes		= rt298_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt298_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt298_regmap = {
@@ -1288,7 +1286,8 @@ static int rt298_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt298,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_rt298,
 				     rt298_dai, ARRAY_SIZE(rt298_dai));
 
 	return ret;
@@ -1300,7 +1299,6 @@ static int rt298_i2c_remove(struct i2c_client *i2c)
 
 	if (i2c->irq)
 		free_irq(i2c->irq, rt298);
-	snd_soc_unregister_codec(&i2c->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h
index 3638f3d61209..b4db935359fa 100644
--- a/sound/soc/codecs/rt298.h
+++ b/sound/soc/codecs/rt298.h
@@ -210,7 +210,7 @@ enum {
 	RT298_AIFS,
 };
 
-int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
 
 #endif /* __RT298_H__ */
 
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 2144edca97b0..18686ffb0cd5 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -35,6 +35,8 @@
 
 #include "rt5514-spi.h"
 
+#define DRV_NAME "rt5514-spi"
+
 static struct spi_device *rt5514_spi;
 
 struct rt5514_dsp {
@@ -211,8 +213,9 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
 			       struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct rt5514_dsp *rt5514_dsp =
-			snd_soc_platform_get_drvdata(rtd->platform);
+		snd_soc_component_get_drvdata(component);
 	int ret;
 	u8 buf[8];
 
@@ -235,8 +238,9 @@ static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
 static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct rt5514_dsp *rt5514_dsp =
-			snd_soc_platform_get_drvdata(rtd->platform);
+		snd_soc_component_get_drvdata(component);
 
 	mutex_lock(&rt5514_dsp->dma_lock);
 	rt5514_dsp->substream = NULL;
@@ -252,8 +256,9 @@ static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct rt5514_dsp *rt5514_dsp =
-		snd_soc_platform_get_drvdata(rtd->platform);
+		snd_soc_component_get_drvdata(component);
 
 	return bytes_to_frames(runtime, rt5514_dsp->dma_offset);
 }
@@ -267,18 +272,18 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
 	.page		= snd_pcm_lib_get_vmalloc_page,
 };
 
-static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
+static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
 {
 	struct rt5514_dsp *rt5514_dsp;
 	int ret;
 
-	rt5514_dsp = devm_kzalloc(platform->dev, sizeof(*rt5514_dsp),
+	rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp),
 			GFP_KERNEL);
 
 	rt5514_dsp->dev = &rt5514_spi->dev;
 	mutex_init(&rt5514_dsp->dma_lock);
 	INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work);
-	snd_soc_platform_set_drvdata(platform, rt5514_dsp);
+	snd_soc_component_set_drvdata(component, rt5514_dsp);
 
 	if (rt5514_spi->irq) {
 		ret = devm_request_threaded_irq(&rt5514_spi->dev,
@@ -296,15 +301,12 @@ static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform)
 	return 0;
 }
 
-static const struct snd_soc_platform_driver rt5514_spi_platform = {
+static const struct snd_soc_component_driver rt5514_spi_component = {
+	.name  = DRV_NAME,
 	.probe = rt5514_spi_pcm_probe,
 	.ops = &rt5514_spi_pcm_ops,
 };
 
-static const struct snd_soc_component_driver rt5514_spi_dai_component = {
-	.name		= "rt5514-spi-dai",
-};
-
 /**
  * rt5514_spi_burst_read - Read data from SPI by rt5514 address.
  * @addr: Start address.
@@ -445,14 +447,8 @@ static int rt5514_spi_probe(struct spi_device *spi)
 
 	rt5514_spi = spi;
 
-	ret = devm_snd_soc_register_platform(&spi->dev, &rt5514_spi_platform);
-	if (ret < 0) {
-		dev_err(&spi->dev, "Failed to register platform.\n");
-		return ret;
-	}
-
 	ret = devm_snd_soc_register_component(&spi->dev,
-					      &rt5514_spi_dai_component,
+					      &rt5514_spi_component,
 					      &rt5514_spi_dai, 1);
 	if (ret < 0) {
 		dev_err(&spi->dev, "Failed to register component.\n");
@@ -474,9 +470,9 @@ static int __maybe_unused rt5514_suspend(struct device *dev)
 
 static int __maybe_unused rt5514_resume(struct device *dev)
 {
-	struct snd_soc_platform *platform = snd_soc_lookup_platform(dev);
+	struct snd_soc_component *component = snd_soc_lookup_component(dev, DRV_NAME);
 	struct rt5514_dsp *rt5514_dsp =
-		snd_soc_platform_get_drvdata(platform);
+		snd_soc_component_get_drvdata(component);
 	int irq = to_spi_device(dev)->irq;
 	u8 buf[8];
 
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 198df016802f..2d79571098ac 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -327,14 +327,13 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
-	struct snd_soc_codec *codec = rt5514->codec;
 	const struct firmware *fw = NULL;
 	u8 buf[8];
 
 	if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled)
 		return 0;
 
-	if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 		rt5514->dsp_enabled = ucontrol->value.integer.value[0];
 
 		if (rt5514->dsp_enabled) {
@@ -342,11 +341,11 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 				!IS_ERR(rt5514->dsp_calib_clk)) {
 				if (clk_set_rate(rt5514->dsp_calib_clk,
 					rt5514->pdata.dsp_calib_clk_rate))
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Can't set rate for mclk");
 
 				if (clk_prepare_enable(rt5514->dsp_calib_clk))
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Can't enable dsp_calib_clk");
 
 				rt5514_calibration(rt5514, true);
@@ -357,7 +356,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 					RT5514_DSP_MAPPING,
 					(u8 *)&buf, sizeof(buf));
 #else
-				dev_err(codec->dev, "There is no SPI driver for"
+				dev_err(component->dev, "There is no SPI driver for"
 					" loading the firmware\n");
 #endif
 				rt5514->pll3_cal_value = buf[0] | buf[1] << 8 |
@@ -369,26 +368,26 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
 
 			rt5514_enable_dsp_prepare(rt5514);
 
-			request_firmware(&fw, RT5514_FIRMWARE1, codec->dev);
+			request_firmware(&fw, RT5514_FIRMWARE1, component->dev);
 			if (fw) {
 #if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
 				rt5514_spi_burst_write(0x4ff60000, fw->data,
 					((fw->size/8)+1)*8);
 #else
-				dev_err(codec->dev, "There is no SPI driver for"
+				dev_err(component->dev, "There is no SPI driver for"
 					" loading the firmware\n");
 #endif
 				release_firmware(fw);
 				fw = NULL;
 			}
 
-			request_firmware(&fw, RT5514_FIRMWARE2, codec->dev);
+			request_firmware(&fw, RT5514_FIRMWARE2, component->dev);
 			if (fw) {
 #if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
 				rt5514_spi_burst_write(0x4ffc0000, fw->data,
 					((fw->size/8)+1)*8);
 #else
-				dev_err(codec->dev, "There is no SPI driver for"
+				dev_err(component->dev, "There is no SPI driver for"
 					" loading the firmware\n");
 #endif
 				release_firmware(fw);
@@ -492,7 +491,7 @@ static const struct snd_kcontrol_new rt5514_sto2_dmic_mux =
  * Choose divider parameter that gives the highest possible DMIC frequency in
  * 1MHz - 3MHz range.
  */
-static int rt5514_calc_dmic_clk(struct snd_soc_codec *codec, int rate)
+static int rt5514_calc_dmic_clk(struct snd_soc_component *component, int rate)
 {
 	int div[] = {2, 3, 4, 8, 12, 16, 24, 32};
 	int i;
@@ -508,20 +507,20 @@ static int rt5514_calc_dmic_clk(struct snd_soc_codec *codec, int rate)
 			return i;
 	}
 
-	dev_warn(codec->dev, "Base clock rate %d is too high\n", rate);
+	dev_warn(component->dev, "Base clock rate %d is too high\n", rate);
 	return -EINVAL;
 }
 
 static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	int idx;
 
-	idx = rt5514_calc_dmic_clk(codec, rt5514->sysclk);
+	idx = rt5514_calc_dmic_clk(component, rt5514->sysclk);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
 		regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1,
 			RT5514_CLK_DMIC_OUT_SEL_MASK,
@@ -536,8 +535,8 @@ static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 
 	if (rt5514->sysclk_src == RT5514_SCLK_S_PLL1)
 		return 1;
@@ -548,8 +547,8 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int rt5514_i2s_use_asrc(struct snd_soc_dapm_widget *source,
 	struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 
 	return (rt5514->sysclk > rt5514->lrck * 384);
 }
@@ -751,21 +750,21 @@ static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
 static int rt5514_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	int pre_div, bclk_ms, frame_size;
 	unsigned int val_len = 0;
 
 	rt5514->lrck = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5514->sysclk, rt5514->lrck);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting\n");
+		dev_err(component->dev, "Unsupported clock setting\n");
 		return -EINVAL;
 	}
 
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 
@@ -808,8 +807,8 @@ static int rt5514_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5514_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -862,8 +861,8 @@ static int rt5514_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5514_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5514->sysclk && clk_id == rt5514->sysclk_src)
@@ -879,7 +878,7 @@ static int rt5514_set_dai_sysclk(struct snd_soc_dai *dai,
 		break;
 
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
 
@@ -897,13 +896,13 @@ static int rt5514_set_dai_sysclk(struct snd_soc_dai *dai,
 static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5514->pll_in = 0;
 		rt5514->pll_out = 0;
@@ -930,17 +929,17 @@ static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		break;
 
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
@@ -961,8 +960,8 @@ static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0, val2 = 0;
 
 	if (rx_mask || tx_mask)
@@ -1047,10 +1046,10 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
-static int rt5514_set_bias_level(struct snd_soc_codec *codec,
+static int rt5514_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1058,7 +1057,7 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec,
 		if (IS_ERR(rt5514->mclk))
 			break;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
 			clk_disable_unprepare(rt5514->mclk);
 		} else {
 			ret = clk_prepare_enable(rt5514->mclk);
@@ -1068,7 +1067,7 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/*
 			 * If the DSP is enabled in start of recording, the DSP
 			 * should be disabled, and sync back to normal recording
@@ -1092,13 +1091,13 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5514_probe(struct snd_soc_codec *codec)
+static int rt5514_probe(struct snd_soc_component *component)
 {
-	struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec);
-	struct platform_device *pdev = container_of(codec->dev,
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	struct platform_device *pdev = container_of(component->dev,
 						   struct platform_device, dev);
 
-	rt5514->mclk = devm_clk_get(codec->dev, "mclk");
+	rt5514->mclk = devm_clk_get(component->dev, "mclk");
 	if (PTR_ERR(rt5514->mclk) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
 
@@ -1109,7 +1108,7 @@ static int rt5514_probe(struct snd_soc_codec *codec)
 			return -EPROBE_DEFER;
 	}
 
-	rt5514->codec = codec;
+	rt5514->component = component;
 	rt5514->pll3_cal_value = 0x0078b000;
 
 	return 0;
@@ -1162,18 +1161,18 @@ static struct snd_soc_dai_driver rt5514_dai[] = {
 	}
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5514 = {
-	.probe = rt5514_probe,
-	.idle_bias_off = true,
-	.set_bias_level = rt5514_set_bias_level,
-	.component_driver = {
-		.controls		= rt5514_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5514_snd_controls),
-		.dapm_widgets		= rt5514_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5514_dapm_widgets),
-		.dapm_routes		= rt5514_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5514_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5514 = {
+	.probe			= rt5514_probe,
+	.set_bias_level		= rt5514_set_bias_level,
+	.controls		= rt5514_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5514_snd_controls),
+	.dapm_widgets		= rt5514_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5514_dapm_widgets),
+	.dapm_routes		= rt5514_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5514_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5514_i2c_regmap = {
@@ -1313,17 +1312,11 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,
 	if (ret != 0)
 		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5514,
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5514,
 			rt5514_dai, ARRAY_SIZE(rt5514_dai));
 }
 
-static int rt5514_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static const struct dev_pm_ops rt5514_i2_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume)
 };
@@ -1336,7 +1329,6 @@ static struct i2c_driver rt5514_i2c_driver = {
 		.pm = &rt5514_i2_pm_ops,
 	},
 	.probe = rt5514_i2c_probe,
-	.remove   = rt5514_i2c_remove,
 	.id_table = rt5514_i2c_id,
 };
 module_i2c_driver(rt5514_i2c_driver);
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
index f0f3400ce6b1..d1ef0b3f566f 100644
--- a/sound/soc/codecs/rt5514.h
+++ b/sound/soc/codecs/rt5514.h
@@ -272,7 +272,7 @@ enum {
 
 struct rt5514_priv {
 	struct rt5514_platform_data pdata;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regmap *i2c_regmap, *regmap;
 	struct clk *mclk, *dsp_calib_clk;
 	int sysclk;
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 0e5f54a9bc7e..3dc795f444ce 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -142,7 +142,7 @@ static const struct reg_default rt5616_reg[] = {
 };
 
 struct rt5616_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct delayed_work patch_work;
 	struct regmap *regmap;
 	struct clk *mclk;
@@ -351,7 +351,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 {
 	unsigned int val;
 
-	val = snd_soc_read(snd_soc_dapm_to_codec(source->dapm), RT5616_GLB_CLK);
+	val = snd_soc_component_read32(snd_soc_dapm_to_component(source->dapm), RT5616_GLB_CLK);
 	val &= RT5616_SCLK_SRC_MASK;
 	if (val == RT5616_SCLK_SRC_PLL1)
 		return 1;
@@ -466,16 +466,16 @@ static const struct snd_kcontrol_new rt5616_lout_mix[] = {
 static int rt5616_adc_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+		snd_soc_component_update_bits(component, RT5616_ADC_DIG_VOL,
 				    RT5616_L_MUTE | RT5616_R_MUTE, 0);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+		snd_soc_component_update_bits(component, RT5616_ADC_DIG_VOL,
 				    RT5616_L_MUTE | RT5616_R_MUTE,
 				    RT5616_L_MUTE | RT5616_R_MUTE);
 		break;
@@ -490,51 +490,51 @@ static int rt5616_adc_event(struct snd_soc_dapm_widget *w,
 static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w,
 				    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* depop parameters */
-		snd_soc_update_bits(codec, RT5616_DEPOP_M2,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M2,
 				    RT5616_DEPOP_MASK, RT5616_DEPOP_MAN);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
 				    RT5616_HP_CB_MASK, RT5616_HP_CP_PU |
 				    RT5616_HP_SG_DIS | RT5616_HP_CB_PU);
-		snd_soc_write(codec, RT5616_PR_BASE +
+		snd_soc_component_write(component, RT5616_PR_BASE +
 			      RT5616_HP_DCC_INT1, 0x9f00);
 		/* headphone amp power on */
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 				    RT5616_PWR_FV1 | RT5616_PWR_FV2, 0);
-		snd_soc_update_bits(codec, RT5616_PWR_VOL,
+		snd_soc_component_update_bits(component, RT5616_PWR_VOL,
 				    RT5616_PWR_HV_L | RT5616_PWR_HV_R,
 				    RT5616_PWR_HV_L | RT5616_PWR_HV_R);
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 				    RT5616_PWR_HP_L | RT5616_PWR_HP_R |
 				    RT5616_PWR_HA, RT5616_PWR_HP_L |
 				    RT5616_PWR_HP_R | RT5616_PWR_HA);
 		msleep(50);
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 				    RT5616_PWR_FV1 | RT5616_PWR_FV2,
 				    RT5616_PWR_FV1 | RT5616_PWR_FV2);
 
-		snd_soc_update_bits(codec, RT5616_CHARGE_PUMP,
+		snd_soc_component_update_bits(component, RT5616_CHARGE_PUMP,
 				    RT5616_PM_HP_MASK, RT5616_PM_HP_HV);
-		snd_soc_update_bits(codec, RT5616_PR_BASE +
+		snd_soc_component_update_bits(component, RT5616_PR_BASE +
 				    RT5616_CHOP_DAC_ADC, 0x0200, 0x0200);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_HP_CO_MASK | RT5616_HP_SG_MASK,
 				    RT5616_HP_CO_EN | RT5616_HP_SG_EN);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5616_PR_BASE +
+		snd_soc_component_update_bits(component, RT5616_PR_BASE +
 				    RT5616_CHOP_DAC_ADC, 0x0200, 0x0);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
 				    RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
 				    RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
 		/* headphone amp power down */
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_SMT_TRIG_MASK |
 				    RT5616_HP_CD_PD_MASK | RT5616_HP_CO_MASK |
 				    RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
@@ -542,7 +542,7 @@ static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w,
 				    RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN |
 				    RT5616_HP_CO_DIS | RT5616_HP_CP_PD |
 				    RT5616_HP_SG_EN | RT5616_HP_CB_PD);
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 				    RT5616_PWR_HP_L | RT5616_PWR_HP_R |
 				    RT5616_PWR_HA, 0);
 		break;
@@ -556,61 +556,61 @@ static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w,
 static int rt5616_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* headphone unmute sequence */
-		snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M3,
 				    RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
 				    RT5616_CP_FQ3_MASK,
 				    RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT |
 				    RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT |
 				    RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT);
-		snd_soc_write(codec, RT5616_PR_BASE +
+		snd_soc_component_write(component, RT5616_PR_BASE +
 			      RT5616_MAMP_INT_REG2, 0xfc00);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_RSTN_MASK, RT5616_RSTN_EN);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK |
 				    RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS |
 				    RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
-		snd_soc_update_bits(codec, RT5616_HP_VOL,
+		snd_soc_component_update_bits(component, RT5616_HP_VOL,
 				    RT5616_L_MUTE | RT5616_R_MUTE, 0);
 		msleep(100);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
 				    RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
 				    RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
 		msleep(20);
-		snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+		snd_soc_component_update_bits(component, RT5616_HP_CALIB_AMP_DET,
 				    RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* headphone mute sequence */
-		snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M3,
 				    RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
 				    RT5616_CP_FQ3_MASK,
 				    RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT |
 				    RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT |
 				    RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT);
-		snd_soc_write(codec, RT5616_PR_BASE +
+		snd_soc_component_write(component, RT5616_PR_BASE +
 			      RT5616_MAMP_INT_REG2, 0xfc00);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_HP_SG_MASK, RT5616_HP_SG_EN);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_RSTP_MASK, RT5616_RSTP_EN);
-		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
 				    RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK |
 				    RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS |
 				    RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
-		snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+		snd_soc_component_update_bits(component, RT5616_HP_CALIB_AMP_DET,
 				    RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS);
 		msleep(90);
-		snd_soc_update_bits(codec, RT5616_HP_VOL,
+		snd_soc_component_update_bits(component, RT5616_HP_VOL,
 				    RT5616_L_MUTE | RT5616_R_MUTE,
 				    RT5616_L_MUTE | RT5616_R_MUTE);
 		msleep(30);
@@ -626,21 +626,21 @@ static int rt5616_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5616_lout_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 				    RT5616_PWR_LM, RT5616_PWR_LM);
-		snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+		snd_soc_component_update_bits(component, RT5616_LOUT_CTRL1,
 				    RT5616_L_MUTE | RT5616_R_MUTE, 0);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+		snd_soc_component_update_bits(component, RT5616_LOUT_CTRL1,
 				    RT5616_L_MUTE | RT5616_R_MUTE,
 				    RT5616_L_MUTE | RT5616_R_MUTE);
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 				    RT5616_PWR_LM, 0);
 		break;
 
@@ -654,16 +654,16 @@ static int rt5616_lout_event(struct snd_soc_dapm_widget *w,
 static int rt5616_bst1_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
 				    RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
 				    RT5616_PWR_BST1_OP2, 0);
 		break;
 
@@ -677,16 +677,16 @@ static int rt5616_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5616_bst2_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
 				    RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
 				    RT5616_PWR_BST2_OP2, 0);
 		break;
 
@@ -960,8 +960,8 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int pre_div, bclk_ms, frame_size;
 
@@ -970,12 +970,12 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream,
 	pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]);
 
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting\n");
+		dev_err(component->dev, "Unsupported clock setting\n");
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 	bclk_ms = frame_size > 32 ? 1 : 0;
@@ -1004,17 +1004,17 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream,
 
 	mask_clk = RT5616_I2S_PD1_MASK;
 	val_clk = pre_div << RT5616_I2S_PD1_SFT;
-	snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+	snd_soc_component_update_bits(component, RT5616_I2S1_SDP,
 			    RT5616_I2S_DL_MASK, val_len);
-	snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk);
+	snd_soc_component_update_bits(component, RT5616_ADDA_CLK1, mask_clk, val_clk);
 
 	return 0;
 }
 
 static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1055,7 +1055,7 @@ static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+	snd_soc_component_update_bits(component, RT5616_I2S1_SDP,
 			    RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK |
 			    RT5616_I2S_DF_MASK, reg_val);
 
@@ -1065,8 +1065,8 @@ static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src)
@@ -1080,11 +1080,11 @@ static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
 		reg_val |= RT5616_SCLK_SRC_PLL1;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5616_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5616_GLB_CLK,
 			    RT5616_SCLK_SRC_MASK, reg_val);
 	rt5616->sysclk = freq;
 	rt5616->sysclk_src = clk_id;
@@ -1097,8 +1097,8 @@ static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
 static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			      unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -1107,11 +1107,11 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5616->pll_in = 0;
 		rt5616->pll_out = 0;
-		snd_soc_update_bits(codec, RT5616_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5616_GLB_CLK,
 				    RT5616_SCLK_SRC_MASK,
 				    RT5616_SCLK_SRC_MCLK);
 		return 0;
@@ -1119,34 +1119,34 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 
 	switch (source) {
 	case RT5616_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5616_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5616_GLB_CLK,
 				    RT5616_PLL1_SRC_MASK,
 				    RT5616_PLL1_SRC_MCLK);
 		break;
 	case RT5616_PLL1_S_BCLK1:
 	case RT5616_PLL1_S_BCLK2:
-		snd_soc_update_bits(codec, RT5616_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5616_GLB_CLK,
 				    RT5616_PLL1_SRC_MASK,
 				    RT5616_PLL1_SRC_BCLK1);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5616_PLL_CTRL1,
+	snd_soc_component_write(component, RT5616_PLL_CTRL1,
 		      pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5616_PLL_CTRL2,
+	snd_soc_component_write(component, RT5616_PLL_CTRL2,
 		      (pll_code.m_bp ? 0 : pll_code.m_code) <<
 		      RT5616_PLL_M_SFT |
 		      pll_code.m_bp << RT5616_PLL_M_BP_SFT);
@@ -1158,10 +1158,10 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	return 0;
 }
 
-static int rt5616_set_bias_level(struct snd_soc_codec *codec,
+static int rt5616_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1180,7 +1180,7 @@ static int rt5616_set_bias_level(struct snd_soc_codec *codec,
 		if (IS_ERR(rt5616->mclk))
 			break;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
 			clk_disable_unprepare(rt5616->mclk);
 		} else {
 			ret = clk_prepare_enable(rt5616->mclk);
@@ -1190,30 +1190,30 @@ static int rt5616_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 					    RT5616_PWR_VREF1 | RT5616_PWR_MB |
 					    RT5616_PWR_BG | RT5616_PWR_VREF2,
 					    RT5616_PWR_VREF1 | RT5616_PWR_MB |
 					    RT5616_PWR_BG | RT5616_PWR_VREF2);
 			mdelay(10);
-			snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
 					    RT5616_PWR_FV1 | RT5616_PWR_FV2,
 					    RT5616_PWR_FV1 | RT5616_PWR_FV2);
-			snd_soc_update_bits(codec, RT5616_D_MISC,
+			snd_soc_component_update_bits(component, RT5616_D_MISC,
 					    RT5616_D_GATE_EN,
 					    RT5616_D_GATE_EN);
 		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, RT5616_D_MISC, RT5616_D_GATE_EN, 0);
-		snd_soc_write(codec, RT5616_PWR_DIG1, 0x0000);
-		snd_soc_write(codec, RT5616_PWR_DIG2, 0x0000);
-		snd_soc_write(codec, RT5616_PWR_VOL, 0x0000);
-		snd_soc_write(codec, RT5616_PWR_MIXER, 0x0000);
-		snd_soc_write(codec, RT5616_PWR_ANLG1, 0x0000);
-		snd_soc_write(codec, RT5616_PWR_ANLG2, 0x0000);
+		snd_soc_component_update_bits(component, RT5616_D_MISC, RT5616_D_GATE_EN, 0);
+		snd_soc_component_write(component, RT5616_PWR_DIG1, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_DIG2, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_VOL, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_MIXER, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_ANLG1, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_ANLG2, 0x0000);
 		break;
 
 	default:
@@ -1223,24 +1223,24 @@ static int rt5616_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5616_probe(struct snd_soc_codec *codec)
+static int rt5616_probe(struct snd_soc_component *component)
 {
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 
 	/* Check if MCLK provided */
-	rt5616->mclk = devm_clk_get(codec->dev, "mclk");
+	rt5616->mclk = devm_clk_get(component->dev, "mclk");
 	if (PTR_ERR(rt5616->mclk) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
 
-	rt5616->codec = codec;
+	rt5616->component = component;
 
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt5616_suspend(struct snd_soc_codec *codec)
+static int rt5616_suspend(struct snd_soc_component *component)
 {
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5616->regmap, true);
 	regcache_mark_dirty(rt5616->regmap);
@@ -1248,9 +1248,9 @@ static int rt5616_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5616_resume(struct snd_soc_codec *codec)
+static int rt5616_resume(struct snd_soc_component *component)
 {
-	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5616->regmap, false);
 	regcache_sync(rt5616->regmap);
@@ -1294,20 +1294,20 @@ static struct snd_soc_dai_driver rt5616_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
-	.probe = rt5616_probe,
-	.suspend = rt5616_suspend,
-	.resume = rt5616_resume,
-	.set_bias_level = rt5616_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5616_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5616_snd_controls),
-		.dapm_widgets		= rt5616_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5616_dapm_widgets),
-		.dapm_routes		= rt5616_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5616_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5616 = {
+	.probe			= rt5616_probe,
+	.suspend		= rt5616_suspend,
+	.resume			= rt5616_resume,
+	.set_bias_level		= rt5616_set_bias_level,
+	.controls		= rt5616_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5616_snd_controls),
+	.dapm_widgets		= rt5616_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5616_dapm_widgets),
+	.dapm_routes		= rt5616_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5616_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5616_regmap = {
@@ -1387,14 +1387,13 @@ static int rt5616_i2c_probe(struct i2c_client *i2c,
 	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
 			   RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V);
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616,
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5616,
 				      rt5616_dai, ARRAY_SIZE(rt5616_dai));
 }
 
 static int rt5616_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&i2c->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 55b04c55fb4b..cf6dce69eb2a 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -71,30 +71,30 @@ static const struct reg_default rt5631_reg[] = {
 /**
  * rt5631_write_index - write index register of 2nd layer
  */
-static void rt5631_write_index(struct snd_soc_codec *codec,
+static void rt5631_write_index(struct snd_soc_component *component,
 		unsigned int reg, unsigned int value)
 {
-	snd_soc_write(codec, RT5631_INDEX_ADD, reg);
-	snd_soc_write(codec, RT5631_INDEX_DATA, value);
+	snd_soc_component_write(component, RT5631_INDEX_ADD, reg);
+	snd_soc_component_write(component, RT5631_INDEX_DATA, value);
 }
 
 /**
  * rt5631_read_index - read index register of 2nd layer
  */
-static unsigned int rt5631_read_index(struct snd_soc_codec *codec,
+static unsigned int rt5631_read_index(struct snd_soc_component *component,
 				unsigned int reg)
 {
 	unsigned int value;
 
-	snd_soc_write(codec, RT5631_INDEX_ADD, reg);
-	value = snd_soc_read(codec, RT5631_INDEX_DATA);
+	snd_soc_component_write(component, RT5631_INDEX_ADD, reg);
+	value = snd_soc_component_read32(component, RT5631_INDEX_DATA);
 
 	return value;
 }
 
-static int rt5631_reset(struct snd_soc_codec *codec)
+static int rt5631_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, RT5631_RESET, 0);
+	return snd_soc_component_write(component, RT5631_RESET, 0);
 }
 
 static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
@@ -187,8 +187,8 @@ static const DECLARE_TLV_DB_RANGE(mic_bst_tlv,
 static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = rt5631->dmic_used_flag;
 
@@ -198,8 +198,8 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
 static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 
 	rt5631->dmic_used_flag = ucontrol->value.integer.value[0];
 	return 0;
@@ -286,78 +286,78 @@ static const struct snd_kcontrol_new rt5631_snd_controls[] = {
 static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_GLOBAL_CLK_CTRL);
+	reg = snd_soc_component_read32(component, RT5631_GLOBAL_CLK_CTRL);
 	return reg & RT5631_SYSCLK_SOUR_SEL_PLL;
 }
 
 static int check_dmic_used(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 	return rt5631->dmic_used_flag;
 }
 
 static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_OUTMIXER_L_CTRL);
+	reg = snd_soc_component_read32(component, RT5631_OUTMIXER_L_CTRL);
 	return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L);
 }
 
 static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_OUTMIXER_R_CTRL);
+	reg = snd_soc_component_read32(component, RT5631_OUTMIXER_R_CTRL);
 	return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R);
 }
 
 static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
+	reg = snd_soc_component_read32(component, RT5631_SPK_MIXER_CTRL);
 	return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L);
 }
 
 static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
+	reg = snd_soc_component_read32(component, RT5631_SPK_MIXER_CTRL);
 	return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R);
 }
 
 static int check_adcl_select(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
+	reg = snd_soc_component_read32(component, RT5631_ADC_REC_MIXER);
 	return !(reg & RT5631_M_MIC1_TO_RECMIXER_L);
 }
 
 static int check_adcr_select(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
+	reg = snd_soc_component_read32(component, RT5631_ADC_REC_MIXER);
 	return !(reg & RT5631_M_MIC2_TO_RECMIXER_R);
 }
 
@@ -367,36 +367,36 @@ static int check_adcr_select(struct snd_soc_dapm_widget *source,
  *
  * When power on/off headphone, the depop sequence is done by hardware.
  */
-static void onebit_depop_power_stage(struct snd_soc_codec *codec, int enable)
+static void onebit_depop_power_stage(struct snd_soc_component *component, int enable)
 {
 	unsigned int soft_vol, hp_zc;
 
 	/* enable one-bit depop function */
-	snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
 				RT5631_EN_ONE_BIT_DEPOP, 0);
 
 	/* keep soft volume and zero crossing setting */
-	soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
-	hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
 	if (enable) {
 		/* config one-bit depop parameter */
-		rt5631_write_index(codec, RT5631_TEST_MODE_CTRL, 0x84c0);
-		rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x309f);
-		rt5631_write_index(codec, RT5631_CP_INTL_REG2, 0x6530);
+		rt5631_write_index(component, RT5631_TEST_MODE_CTRL, 0x84c0);
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x309f);
+		rt5631_write_index(component, RT5631_CP_INTL_REG2, 0x6530);
 		/* power on capless block */
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_2,
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_2,
 				RT5631_EN_CAP_FREE_DEPOP);
 	} else {
 		/* power off capless block */
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_2, 0);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_2, 0);
 		msleep(100);
 	}
 
 	/* recover soft volume and zero crossing setting */
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
 }
 
 /**
@@ -405,36 +405,36 @@ static void onebit_depop_power_stage(struct snd_soc_codec *codec, int enable)
  *
  * When mute/unmute headphone, the depop sequence is done by hardware.
  */
-static void onebit_depop_mute_stage(struct snd_soc_codec *codec, int enable)
+static void onebit_depop_mute_stage(struct snd_soc_component *component, int enable)
 {
 	unsigned int soft_vol, hp_zc;
 
 	/* enable one-bit depop function */
-	snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
 				RT5631_EN_ONE_BIT_DEPOP, 0);
 
 	/* keep soft volume and zero crossing setting */
-	soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
-	hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
 	if (enable) {
 		schedule_timeout_uninterruptible(msecs_to_jiffies(10));
 		/* config one-bit depop parameter */
-		rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x307f);
-		snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x307f);
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
 				RT5631_L_MUTE | RT5631_R_MUTE, 0);
 		msleep(300);
 	} else {
-		snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
 			RT5631_L_MUTE | RT5631_R_MUTE,
 			RT5631_L_MUTE | RT5631_R_MUTE);
 		msleep(100);
 	}
 
 	/* recover soft volume and zero crossing setting */
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
 }
 
 /**
@@ -443,70 +443,70 @@ static void onebit_depop_mute_stage(struct snd_soc_codec *codec, int enable)
  *
  * When power on/off headphone, the depop sequence is done in step by step.
  */
-static void depop_seq_power_stage(struct snd_soc_codec *codec, int enable)
+static void depop_seq_power_stage(struct snd_soc_component *component, int enable)
 {
 	unsigned int soft_vol, hp_zc;
 
 	/* depop control by register */
-	snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
 		RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP);
 
 	/* keep soft volume and zero crossing setting */
-	soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
-	hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
 	if (enable) {
 		/* config depop sequence parameter */
-		rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x303e);
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x303e);
 
 		/* power on headphone and charge pump */
-		snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 			RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
 			RT5631_PWR_HP_R_AMP,
 			RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
 			RT5631_PWR_HP_R_AMP);
 
 		/* power on soft generator and depop mode2 */
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP);
 		msleep(100);
 
 		/* stop depop mode */
-		snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 			RT5631_PWR_HP_DEPOP_DIS, RT5631_PWR_HP_DEPOP_DIS);
 	} else {
 		/* config depop sequence parameter */
-		rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x303F);
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x303F);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
 			RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP);
 		msleep(75);
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN | RT5631_PD_HPAMP_L_ST_UP |
 			RT5631_PD_HPAMP_R_ST_UP);
 
 		/* start depop mode */
-		snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 				RT5631_PWR_HP_DEPOP_DIS, 0);
 
 		/* config depop sequence parameter */
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP |
 			RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP);
 		msleep(80);
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN);
 
 		/* power down headphone and charge pump */
-		snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 			RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
 			RT5631_PWR_HP_R_AMP, 0);
 	}
 
 	/* recover soft volume and zero crossing setting */
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
 }
 
 /**
@@ -515,75 +515,75 @@ static void depop_seq_power_stage(struct snd_soc_codec *codec, int enable)
  *
  * When mute/unmute headphone, the depop sequence is done in step by step.
  */
-static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable)
+static void depop_seq_mute_stage(struct snd_soc_component *component, int enable)
 {
 	unsigned int soft_vol, hp_zc;
 
 	/* depop control by register */
-	snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
 		RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP);
 
 	/* keep soft volume and zero crossing setting */
-	soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
-	hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
 	if (enable) {
 		schedule_timeout_uninterruptible(msecs_to_jiffies(10));
 
 		/* config depop sequence parameter */
-		rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x302f);
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x302f);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
 			RT5631_EN_HP_R_M_UN_MUTE_DEPOP |
 			RT5631_EN_HP_L_M_UN_MUTE_DEPOP);
 
-		snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
 				RT5631_L_MUTE | RT5631_R_MUTE, 0);
 		msleep(160);
 	} else {
 		/* config depop sequence parameter */
-		rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x302f);
-		snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x302f);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
 			RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
 			RT5631_EN_HP_R_M_UN_MUTE_DEPOP |
 			RT5631_EN_HP_L_M_UN_MUTE_DEPOP);
 
-		snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
 			RT5631_L_MUTE | RT5631_R_MUTE,
 			RT5631_L_MUTE | RT5631_R_MUTE);
 		msleep(150);
 	}
 
 	/* recover soft volume and zero crossing setting */
-	snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
 }
 
 static int hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMD:
 		if (rt5631->codec_version) {
-			onebit_depop_mute_stage(codec, 0);
-			onebit_depop_power_stage(codec, 0);
+			onebit_depop_mute_stage(component, 0);
+			onebit_depop_power_stage(component, 0);
 		} else {
-			depop_seq_mute_stage(codec, 0);
-			depop_seq_power_stage(codec, 0);
+			depop_seq_mute_stage(component, 0);
+			depop_seq_power_stage(component, 0);
 		}
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
 		if (rt5631->codec_version) {
-			onebit_depop_power_stage(codec, 1);
-			onebit_depop_mute_stage(codec, 1);
+			onebit_depop_power_stage(component, 1);
+			onebit_depop_mute_stage(component, 1);
 		} else {
-			depop_seq_power_stage(codec, 1);
-			depop_seq_mute_stage(codec, 1);
+			depop_seq_power_stage(component, 1);
+			depop_seq_mute_stage(component, 1);
 		}
 		break;
 
@@ -597,20 +597,20 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int set_dmic_params(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 
 	switch (rt5631->rx_rate) {
 	case 44100:
 	case 48000:
-		snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
 			RT5631_DMIC_CLK_CTRL_MASK,
 			RT5631_DMIC_CLK_CTRL_TO_32FS);
 		break;
 
 	case 32000:
 	case 22050:
-		snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
 			RT5631_DMIC_CLK_CTRL_MASK,
 			RT5631_DMIC_CLK_CTRL_TO_64FS);
 		break;
@@ -618,7 +618,7 @@ static int set_dmic_params(struct snd_soc_dapm_widget *w,
 	case 16000:
 	case 11025:
 	case 8000:
-		snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
 			RT5631_DMIC_CLK_CTRL_MASK,
 			RT5631_DMIC_CLK_CTRL_TO_128FS);
 		break;
@@ -1352,16 +1352,16 @@ static int get_coeff(int mclk, int rate, int timesofbclk)
 static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 	int timesofbclk = 32, coeff;
 	unsigned int iface = 0;
 
-	dev_dbg(codec->dev, "enter %s\n", __func__);
+	dev_dbg(component->dev, "enter %s\n", __func__);
 
 	rt5631->bclk_rate = snd_soc_params_to_bclk(params);
 	if (rt5631->bclk_rate < 0) {
-		dev_err(codec->dev, "Fail to get BCLK rate\n");
+		dev_err(component->dev, "Fail to get BCLK rate\n");
 		return rt5631->bclk_rate;
 	}
 	rt5631->rx_rate = params_rate(params);
@@ -1373,7 +1373,7 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
 		coeff = get_coeff(rt5631->sysclk, rt5631->rx_rate,
 					timesofbclk);
 	if (coeff < 0) {
-		dev_err(codec->dev, "Fail to get coeff\n");
+		dev_err(component->dev, "Fail to get coeff\n");
 		return coeff;
 	}
 
@@ -1393,9 +1393,9 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5631_SDP_CTRL,
+	snd_soc_component_update_bits(component, RT5631_SDP_CTRL,
 		RT5631_SDP_I2S_DL_MASK, iface);
-	snd_soc_write(codec, RT5631_STEREO_AD_DA_CLK_CTRL,
+	snd_soc_component_write(component, RT5631_STEREO_AD_DA_CLK_CTRL,
 					coeff_div[coeff].reg_val);
 
 	return 0;
@@ -1404,11 +1404,11 @@ static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
 static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
 						unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 	unsigned int iface = 0;
 
-	dev_dbg(codec->dev, "enter %s\n", __func__);
+	dev_dbg(component->dev, "enter %s\n", __func__);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -1448,7 +1448,7 @@ static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, RT5631_SDP_CTRL, iface);
+	snd_soc_component_write(component, RT5631_SDP_CTRL, iface);
 
 	return 0;
 }
@@ -1456,10 +1456,10 @@ static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int rt5631_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "enter %s, syclk=%d\n", __func__, freq);
+	dev_dbg(component->dev, "enter %s, syclk=%d\n", __func__, freq);
 
 	if ((freq >= (256 * 8000)) && (freq <= (512 * 96000))) {
 		rt5631->sysclk = freq;
@@ -1472,16 +1472,16 @@ static int rt5631_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 	int i, ret = -EINVAL;
 
-	dev_dbg(codec->dev, "enter %s\n", __func__);
+	dev_dbg(component->dev, "enter %s\n", __func__);
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
-		snd_soc_update_bits(codec, RT5631_GLOBAL_CLK_CTRL,
+		snd_soc_component_update_bits(component, RT5631_GLOBAL_CLK_CTRL,
 			RT5631_SYSCLK_SOUR_SEL_MASK,
 			RT5631_SYSCLK_SOUR_SEL_MCLK);
 
@@ -1492,13 +1492,13 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++)
 			if (freq_in == codec_master_pll_div[i].pll_in &&
 			freq_out == codec_master_pll_div[i].pll_out) {
-				dev_info(codec->dev,
+				dev_info(component->dev,
 					"change PLL in master mode\n");
-				snd_soc_write(codec, RT5631_PLL_CTRL,
+				snd_soc_component_write(component, RT5631_PLL_CTRL,
 					codec_master_pll_div[i].reg_val);
 				schedule_timeout_uninterruptible(
 					msecs_to_jiffies(20));
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					RT5631_GLOBAL_CLK_CTRL,
 					RT5631_SYSCLK_SOUR_SEL_MASK |
 					RT5631_PLLCLK_SOUR_SEL_MASK,
@@ -1511,13 +1511,13 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++)
 			if (freq_in == codec_slave_pll_div[i].pll_in &&
 			freq_out == codec_slave_pll_div[i].pll_out) {
-				dev_info(codec->dev,
+				dev_info(component->dev,
 					"change PLL in slave mode\n");
-				snd_soc_write(codec, RT5631_PLL_CTRL,
+				snd_soc_component_write(component, RT5631_PLL_CTRL,
 					codec_slave_pll_div[i].reg_val);
 				schedule_timeout_uninterruptible(
 					msecs_to_jiffies(20));
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 					RT5631_GLOBAL_CLK_CTRL,
 					RT5631_SYSCLK_SOUR_SEL_MASK |
 					RT5631_PLLCLK_SOUR_SEL_MASK,
@@ -1531,26 +1531,26 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	return ret;
 }
 
-static int rt5631_set_bias_level(struct snd_soc_codec *codec,
+static int rt5631_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD2,
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD2,
 			RT5631_PWR_MICBIAS1_VOL | RT5631_PWR_MICBIAS2_VOL,
 			RT5631_PWR_MICBIAS1_VOL | RT5631_PWR_MICBIAS2_VOL);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
 				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
 			msleep(80);
-			snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+			snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 				RT5631_PWR_FAST_VREF_CTRL,
 				RT5631_PWR_FAST_VREF_CTRL);
 			regcache_cache_only(rt5631->regmap, false);
@@ -1559,10 +1559,10 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, RT5631_PWR_MANAG_ADD1, 0x0000);
-		snd_soc_write(codec, RT5631_PWR_MANAG_ADD2, 0x0000);
-		snd_soc_write(codec, RT5631_PWR_MANAG_ADD3, 0x0000);
-		snd_soc_write(codec, RT5631_PWR_MANAG_ADD4, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD1, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD2, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD3, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD4, 0x0000);
 		break;
 
 	default:
@@ -1572,48 +1572,48 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5631_probe(struct snd_soc_codec *codec)
+static int rt5631_probe(struct snd_soc_component *component)
 {
-	struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
-	val = rt5631_read_index(codec, RT5631_ADDA_MIXER_INTL_REG3);
+	val = rt5631_read_index(component, RT5631_ADDA_MIXER_INTL_REG3);
 	if (val & 0x0002)
 		rt5631->codec_version = 1;
 	else
 		rt5631->codec_version = 0;
 
-	rt5631_reset(codec);
-	snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+	rt5631_reset(component);
+	snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 		RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
 		RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
 	msleep(80);
-	snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+	snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
 		RT5631_PWR_FAST_VREF_CTRL, RT5631_PWR_FAST_VREF_CTRL);
 	/* enable HP zero cross */
-	snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x0f18);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, 0x0f18);
 	/* power off ClassD auto Recovery */
 	if (rt5631->codec_version)
-		snd_soc_update_bits(codec, RT5631_INT_ST_IRQ_CTRL_2,
+		snd_soc_component_update_bits(component, RT5631_INT_ST_IRQ_CTRL_2,
 					0x2000, 0x2000);
 	else
-		snd_soc_update_bits(codec, RT5631_INT_ST_IRQ_CTRL_2,
+		snd_soc_component_update_bits(component, RT5631_INT_ST_IRQ_CTRL_2,
 					0x2000, 0);
 	/* DMIC */
 	if (rt5631->dmic_used_flag) {
-		snd_soc_update_bits(codec, RT5631_GPIO_CTRL,
+		snd_soc_component_update_bits(component, RT5631_GPIO_CTRL,
 			RT5631_GPIO_PIN_FUN_SEL_MASK |
 			RT5631_GPIO_DMIC_FUN_SEL_MASK,
 			RT5631_GPIO_PIN_FUN_SEL_GPIO_DIMC |
 			RT5631_GPIO_DMIC_FUN_SEL_DIMC);
-		snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
 			RT5631_DMIC_L_CH_LATCH_MASK |
 			RT5631_DMIC_R_CH_LATCH_MASK,
 			RT5631_DMIC_L_CH_LATCH_FALLING |
 			RT5631_DMIC_R_CH_LATCH_RISING);
 	}
 
-	snd_soc_codec_init_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_init_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	return 0;
 }
@@ -1653,18 +1653,20 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
-	.probe = rt5631_probe,
-	.set_bias_level = rt5631_set_bias_level,
-	.suspend_bias_off = true,
-	.component_driver = {
-		.controls		= rt5631_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5631_snd_controls),
-		.dapm_widgets		= rt5631_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5631_dapm_widgets),
-		.dapm_routes		= rt5631_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5631_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5631 = {
+	.probe			= rt5631_probe,
+	.set_bias_level		= rt5631_set_bias_level,
+	.controls		= rt5631_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5631_snd_controls),
+	.dapm_widgets		= rt5631_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5631_dapm_widgets),
+	.dapm_routes		= rt5631_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5631_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct i2c_device_id rt5631_i2c_id[] = {
@@ -1712,14 +1714,14 @@ static int rt5631_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(rt5631->regmap))
 		return PTR_ERR(rt5631->regmap);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5631,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5631,
 			rt5631_dai, ARRAY_SIZE(rt5631_dai));
 	return ret;
 }
 
 static int rt5631_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 438fe52a12df..05567426f211 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -166,9 +166,9 @@ static const struct reg_default rt5640_reg[] = {
 	{ 0xff, 0x6231 },
 };
 
-static int rt5640_reset(struct snd_soc_codec *codec)
+static int rt5640_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, RT5640_RESET, 0);
+	return snd_soc_component_write(component, RT5640_RESET, 0);
 }
 
 static bool rt5640_volatile_register(struct device *dev, unsigned int reg)
@@ -461,17 +461,17 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	int idx, rate;
 
 	rate = rt5640->sysclk / rl6231_get_pre_div(rt5640->regmap,
 		RT5640_ADDA_CLK1, RT5640_I2S_PD1_SFT);
 	idx = rl6231_calc_dmic_clk(rate);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
-		snd_soc_update_bits(codec, RT5640_DMIC, RT5640_DMIC_CLK_MASK,
+		snd_soc_component_update_bits(component, RT5640_DMIC, RT5640_DMIC_CLK_MASK,
 					idx << RT5640_DMIC_CLK_SFT);
 	return idx;
 }
@@ -479,10 +479,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(codec, RT5640_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5640_GLB_CLK);
 	val &= RT5640_SCLK_SRC_MASK;
 	if (val == RT5640_SCLK_SRC_PLL1)
 		return 1;
@@ -493,8 +493,8 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	if (!rt5640->asrc_en)
 		return 0;
@@ -930,9 +930,9 @@ static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
 static const struct snd_kcontrol_new rt5640_sdi_mux =
 	SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
 
-static void hp_amp_power_on(struct snd_soc_codec *codec)
+static void hp_amp_power_on(struct snd_soc_component *component)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	/* depop parameters */
 	regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
@@ -956,9 +956,9 @@ static void hp_amp_power_on(struct snd_soc_codec *codec)
 		RT5640_PWR_FV1 | RT5640_PWR_FV2);
 }
 
-static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+static void rt5640_pmu_depop(struct snd_soc_component *component)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
 		RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK,
@@ -984,12 +984,12 @@ static void rt5640_pmu_depop(struct snd_soc_codec *codec)
 static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		rt5640_pmu_depop(codec);
+		rt5640_pmu_depop(component);
 		rt5640->hp_mute = 0;
 		break;
 
@@ -1008,22 +1008,22 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5640_lout_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		hp_amp_power_on(codec);
-		snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+		hp_amp_power_on(component);
+		snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
 			RT5640_PWR_LM, RT5640_PWR_LM);
-		snd_soc_update_bits(codec, RT5640_OUTPUT,
+		snd_soc_component_update_bits(component, RT5640_OUTPUT,
 			RT5640_L_MUTE | RT5640_R_MUTE, 0);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5640_OUTPUT,
+		snd_soc_component_update_bits(component, RT5640_OUTPUT,
 			RT5640_L_MUTE | RT5640_R_MUTE,
 			RT5640_L_MUTE | RT5640_R_MUTE);
-		snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
 			RT5640_PWR_LM, 0);
 		break;
 
@@ -1037,11 +1037,11 @@ static int rt5640_lout_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		hp_amp_power_on(codec);
+		hp_amp_power_on(component);
 		break;
 	default:
 		return 0;
@@ -1053,8 +1053,8 @@ static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1671,14 +1671,14 @@ static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = {
 	{"IF2 DAC R", NULL, "DAC R2 Power"},
 };
 
-static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
+static int get_sdp_info(struct snd_soc_component *component, int dai_id)
 {
 	int ret = 0, val;
 
-	if (codec == NULL)
+	if (component == NULL)
 		return -EINVAL;
 
-	val = snd_soc_read(codec, RT5640_I2S1_SDP);
+	val = snd_soc_component_read32(component, RT5640_I2S1_SDP);
 	val = (val & RT5640_I2S_IF_MASK) >> RT5640_I2S_IF_SFT;
 	switch (dai_id) {
 	case RT5640_AIF1:
@@ -1722,21 +1722,21 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
 static int rt5640_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int dai_sel, pre_div, bclk_ms, frame_size;
 
 	rt5640->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
 			rt5640->lrck[dai->id], dai->id);
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return frame_size;
 	}
 	if (frame_size > 32)
@@ -1766,26 +1766,26 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	dai_sel = get_sdp_info(codec, dai->id);
+	dai_sel = get_sdp_info(component, dai->id);
 	if (dai_sel < 0) {
-		dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+		dev_err(component->dev, "Failed to get sdp info: %d\n", dai_sel);
 		return -EINVAL;
 	}
 	if (dai_sel & RT5640_U_IF1) {
 		mask_clk = RT5640_I2S_BCLK_MS1_MASK | RT5640_I2S_PD1_MASK;
 		val_clk = bclk_ms << RT5640_I2S_BCLK_MS1_SFT |
 			pre_div << RT5640_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5640_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5640_I2S1_SDP,
 			RT5640_I2S_DL_MASK, val_len);
-		snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5640_ADDA_CLK1, mask_clk, val_clk);
 	}
 	if (dai_sel & RT5640_U_IF2) {
 		mask_clk = RT5640_I2S_BCLK_MS2_MASK | RT5640_I2S_PD2_MASK;
 		val_clk = bclk_ms << RT5640_I2S_BCLK_MS2_SFT |
 			pre_div << RT5640_I2S_PD2_SFT;
-		snd_soc_update_bits(codec, RT5640_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5640_I2S2_SDP,
 			RT5640_I2S_DL_MASK, val_len);
-		snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5640_ADDA_CLK1, mask_clk, val_clk);
 	}
 
 	return 0;
@@ -1793,8 +1793,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 	int dai_sel;
 
@@ -1836,18 +1836,18 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	dai_sel = get_sdp_info(codec, dai->id);
+	dai_sel = get_sdp_info(component, dai->id);
 	if (dai_sel < 0) {
-		dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+		dev_err(component->dev, "Failed to get sdp info: %d\n", dai_sel);
 		return -EINVAL;
 	}
 	if (dai_sel & RT5640_U_IF1) {
-		snd_soc_update_bits(codec, RT5640_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5640_I2S1_SDP,
 			RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
 			RT5640_I2S_DF_MASK, reg_val);
 	}
 	if (dai_sel & RT5640_U_IF2) {
-		snd_soc_update_bits(codec, RT5640_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5640_I2S2_SDP,
 			RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
 			RT5640_I2S_DF_MASK, reg_val);
 	}
@@ -1858,8 +1858,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
@@ -1876,10 +1876,10 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 		reg_val |= RT5640_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5640_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5640_GLB_CLK,
 		RT5640_SCLK_SRC_MASK, reg_val);
 	rt5640->sysclk = freq;
 	rt5640->sysclk_src = clk_id;
@@ -1891,8 +1891,8 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
 static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -1901,46 +1901,46 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5640->pll_in = 0;
 		rt5640->pll_out = 0;
-		snd_soc_update_bits(codec, RT5640_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
 			RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5640_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5640_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
 			RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_MCLK);
 		break;
 	case RT5640_PLL1_S_BCLK1:
-		snd_soc_update_bits(codec, RT5640_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
 			RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK1);
 		break;
 	case RT5640_PLL1_S_BCLK2:
-		snd_soc_update_bits(codec, RT5640_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
 			RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK2);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5640_PLL_CTRL1,
+	snd_soc_component_write(component, RT5640_PLL_CTRL1,
 		pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5640_PLL_CTRL2,
+	snd_soc_component_write(component, RT5640_PLL_CTRL2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT |
 		pll_code.m_bp << RT5640_PLL_M_BP_SFT);
 
@@ -1951,10 +1951,10 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	return 0;
 }
 
-static int rt5640_set_bias_level(struct snd_soc_codec *codec,
+static int rt5640_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1972,7 +1972,7 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 		if (IS_ERR(rt5640->mclk))
 			break;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
 			clk_disable_unprepare(rt5640->mclk);
 		} else {
 			ret = clk_prepare_enable(rt5640->mclk);
@@ -1982,33 +1982,33 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (SND_SOC_BIAS_OFF == snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+		if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
 				RT5640_PWR_VREF1 | RT5640_PWR_MB |
 				RT5640_PWR_BG | RT5640_PWR_VREF2,
 				RT5640_PWR_VREF1 | RT5640_PWR_MB |
 				RT5640_PWR_BG | RT5640_PWR_VREF2);
 			usleep_range(10000, 15000);
-			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
 				RT5640_PWR_FV1 | RT5640_PWR_FV2,
 				RT5640_PWR_FV1 | RT5640_PWR_FV2);
-			snd_soc_update_bits(codec, RT5640_DUMMY1,
+			snd_soc_component_update_bits(component, RT5640_DUMMY1,
 						0x0301, 0x0301);
-			snd_soc_update_bits(codec, RT5640_MICBIAS,
+			snd_soc_component_update_bits(component, RT5640_MICBIAS,
 						0x0030, 0x0030);
 		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, RT5640_DEPOP_M1, 0x0004);
-		snd_soc_write(codec, RT5640_DEPOP_M2, 0x1100);
-		snd_soc_update_bits(codec, RT5640_DUMMY1, 0x1, 0);
-		snd_soc_write(codec, RT5640_PWR_DIG1, 0x0000);
-		snd_soc_write(codec, RT5640_PWR_DIG2, 0x0000);
-		snd_soc_write(codec, RT5640_PWR_VOL, 0x0000);
-		snd_soc_write(codec, RT5640_PWR_MIXER, 0x0000);
-		snd_soc_write(codec, RT5640_PWR_ANLG1, 0x0000);
-		snd_soc_write(codec, RT5640_PWR_ANLG2, 0x0000);
+		snd_soc_component_write(component, RT5640_DEPOP_M1, 0x0004);
+		snd_soc_component_write(component, RT5640_DEPOP_M2, 0x1100);
+		snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x1, 0);
+		snd_soc_component_write(component, RT5640_PWR_DIG1, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000);
 		break;
 
 	default:
@@ -2018,10 +2018,10 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-int rt5640_dmic_enable(struct snd_soc_codec *codec,
+int rt5640_dmic_enable(struct snd_soc_component *component,
 		       bool dmic1_data_pin, bool dmic2_data_pin)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
 		RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
@@ -2044,10 +2044,10 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
 
-int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 	unsigned int asrc2_mask = 0;
 	unsigned int asrc2_value = 0;
 
@@ -2099,43 +2099,43 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
 			| (clk_src << RT5640_MAD_R_M_SFT);
 	}
 
-	snd_soc_update_bits(codec, RT5640_ASRC_2,
+	snd_soc_component_update_bits(component, RT5640_ASRC_2,
 		asrc2_mask, asrc2_value);
 
-	if (snd_soc_read(codec, RT5640_ASRC_2)) {
+	if (snd_soc_component_read32(component, RT5640_ASRC_2)) {
 		rt5640->asrc_en = true;
-		snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3);
+		snd_soc_component_update_bits(component, RT5640_JD_CTRL, 0x3, 0x3);
 	} else {
 		rt5640->asrc_en = false;
-		snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0);
+		snd_soc_component_update_bits(component, RT5640_JD_CTRL, 0x3, 0x0);
 	}
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
 
-static int rt5640_probe(struct snd_soc_codec *codec)
+static int rt5640_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	/* Check if MCLK provided */
-	rt5640->mclk = devm_clk_get(codec->dev, "mclk");
+	rt5640->mclk = devm_clk_get(component->dev, "mclk");
 	if (PTR_ERR(rt5640->mclk) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
 
-	rt5640->codec = codec;
+	rt5640->component = component;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
-	snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
-	snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
-	snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
+	snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x0301, 0x0301);
+	snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030);
+	snd_soc_component_update_bits(component, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
 
-	switch (snd_soc_read(codec, RT5640_RESET) & RT5640_ID_MASK) {
+	switch (snd_soc_component_read32(component, RT5640_RESET) & RT5640_ID_MASK) {
 	case RT5640_ID_5640:
 	case RT5640_ID_5642:
-		snd_soc_add_codec_controls(codec,
+		snd_soc_add_component_controls(component,
 			rt5640_specific_snd_controls,
 			ARRAY_SIZE(rt5640_specific_snd_controls));
 		snd_soc_dapm_new_controls(dapm,
@@ -2154,32 +2154,30 @@ static int rt5640_probe(struct snd_soc_codec *codec)
 			ARRAY_SIZE(rt5639_specific_dapm_routes));
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"The driver is for RT5639 RT5640 or RT5642 only\n");
 		return -ENODEV;
 	}
 
 	if (rt5640->pdata.dmic_en)
-		rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin,
+		rt5640_dmic_enable(component, rt5640->pdata.dmic1_data_pin,
 					  rt5640->pdata.dmic2_data_pin);
 
 	return 0;
 }
 
-static int rt5640_remove(struct snd_soc_codec *codec)
+static void rt5640_remove(struct snd_soc_component *component)
 {
-	rt5640_reset(codec);
-
-	return 0;
+	rt5640_reset(component);
 }
 
 #ifdef CONFIG_PM
-static int rt5640_suspend(struct snd_soc_codec *codec)
+static int rt5640_suspend(struct snd_soc_component *component)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
-	rt5640_reset(codec);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+	rt5640_reset(component);
 	regcache_cache_only(rt5640->regmap, true);
 	regcache_mark_dirty(rt5640->regmap);
 	if (gpio_is_valid(rt5640->pdata.ldo1_en))
@@ -2188,9 +2186,9 @@ static int rt5640_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5640_resume(struct snd_soc_codec *codec)
+static int rt5640_resume(struct snd_soc_component *component)
 {
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
 		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1);
@@ -2259,21 +2257,22 @@ static struct snd_soc_dai_driver rt5640_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
-	.probe = rt5640_probe,
-	.remove = rt5640_remove,
-	.suspend = rt5640_suspend,
-	.resume = rt5640_resume,
-	.set_bias_level = rt5640_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5640_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5640_snd_controls),
-		.dapm_widgets		= rt5640_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5640_dapm_widgets),
-		.dapm_routes		= rt5640_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5640_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5640 = {
+	.probe			= rt5640_probe,
+	.remove			= rt5640_remove,
+	.suspend		= rt5640_suspend,
+	.resume			= rt5640_resume,
+	.set_bias_level		= rt5640_set_bias_level,
+	.controls		= rt5640_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5640_snd_controls),
+	.dapm_widgets		= rt5640_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5640_dapm_widgets),
+	.dapm_routes		= rt5640_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5640_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
 };
 
 static const struct regmap_config rt5640_regmap = {
@@ -2427,17 +2426,11 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
 
 	rt5640->hp_mute = 1;
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5640,
 				      rt5640_dai, ARRAY_SIZE(rt5640_dai));
 }
 
-static int rt5640_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static struct i2c_driver rt5640_i2c_driver = {
 	.driver = {
 		.name = "rt5640",
@@ -2445,7 +2438,6 @@ static struct i2c_driver rt5640_i2c_driver = {
 		.of_match_table = of_match_ptr(rt5640_of_match),
 	},
 	.probe = rt5640_i2c_probe,
-	.remove   = rt5640_i2c_remove,
 	.id_table = rt5640_i2c_id,
 };
 module_i2c_driver(rt5640_i2c_driver);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index b8a811732a52..c473e8ae2eda 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -2102,7 +2102,7 @@ enum {
 };
 
 struct rt5640_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5640_platform_data pdata;
 	struct regmap *regmap;
 	struct clk *mclk;
@@ -2121,9 +2121,9 @@ struct rt5640_priv {
 	bool asrc_en;
 };
 
-int rt5640_dmic_enable(struct snd_soc_codec *codec,
+int rt5640_dmic_enable(struct snd_soc_component *component,
 		       bool dmic1_data_pin, bool dmic2_data_pin);
-int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src);
 
 #endif
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 8f140c8b93ac..bc8d829ce45b 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -407,7 +407,7 @@ static const char *const rt5645_supply_names[] = {
 };
 
 struct rt5645_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5645_platform_data pdata;
 	struct regmap *regmap;
 	struct i2c_client *i2c;
@@ -437,9 +437,9 @@ struct rt5645_priv {
 	int v_id;
 };
 
-static int rt5645_reset(struct snd_soc_codec *codec)
+static int rt5645_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, RT5645_RESET, 0);
+	return snd_soc_component_write(component, RT5645_RESET, 0);
 }
 
 static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
@@ -846,17 +846,17 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	int idx, rate;
 
 	rate = rt5645->sysclk / rl6231_get_pre_div(rt5645->regmap,
 		RT5645_ADDA_CLK1, RT5645_I2S_PD1_SFT);
 	idx = rl6231_calc_dmic_clk(rate);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
-		snd_soc_update_bits(codec, RT5645_DMIC_CTRL1,
+		snd_soc_component_update_bits(component, RT5645_DMIC_CTRL1,
 			RT5645_DMIC_CLK_MASK, idx << RT5645_DMIC_CLK_SFT);
 	return idx;
 }
@@ -864,10 +864,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(codec, RT5645_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5645_GLB_CLK);
 	val &= RT5645_SCLK_SRC_MASK;
 	if (val == RT5645_SCLK_SRC_PLL1)
 		return 1;
@@ -878,7 +878,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg, shift, val;
 
 	switch (source->shift) {
@@ -910,7 +910,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 		return 0;
 	}
 
-	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
 	switch (val) {
 	case 1:
 	case 2:
@@ -923,9 +923,9 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 
 }
 
-static int rt5645_enable_hweq(struct snd_soc_codec *codec)
+static int rt5645_enable_hweq(struct snd_soc_component *component)
 {
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < RT5645_HWEQ_NUM; i++) {
@@ -941,7 +941,7 @@ static int rt5645_enable_hweq(struct snd_soc_codec *codec)
 
 /**
  * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @filter_mask: mask of filters.
  * @clk_src: clock source
  *
@@ -953,7 +953,7 @@ static int rt5645_enable_hweq(struct snd_soc_codec *codec)
  * set of filters specified by the mask. And the codec driver will turn on ASRC
  * for these filters if ASRC is selected as their clock source.
  */
-int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5645_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src)
 {
 	unsigned int asrc2_mask = 0;
@@ -1009,11 +1009,11 @@ int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
 	}
 
 	if (asrc2_mask)
-		snd_soc_update_bits(codec, RT5645_ASRC_2,
+		snd_soc_component_update_bits(component, RT5645_ASRC_2,
 			asrc2_mask, asrc2_value);
 
 	if (asrc3_mask)
-		snd_soc_update_bits(codec, RT5645_ASRC_3,
+		snd_soc_component_update_bits(component, RT5645_ASRC_3,
 			asrc3_mask, asrc3_value);
 
 	return 0;
@@ -1678,56 +1678,56 @@ static const struct snd_kcontrol_new pdm1_r_vol_control =
 	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL,
 		RT5645_M_PDM1_R, 1, 1);
 
-static void hp_amp_power(struct snd_soc_codec *codec, int on)
+static void hp_amp_power(struct snd_soc_component *component, int on)
 {
 	static int hp_amp_power_count;
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	if (on) {
 		if (hp_amp_power_count <= 0) {
 			if (rt5645->codec_type == CODEC_TYPE_RT5650) {
-				snd_soc_write(codec, RT5645_DEPOP_M2, 0x3100);
-				snd_soc_write(codec, RT5645_CHARGE_PUMP,
+				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x3100);
+				snd_soc_component_write(component, RT5645_CHARGE_PUMP,
 					0x0e06);
-				snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x000d);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					RT5645_HP_DCC_INT1, 0x9f01);
 				msleep(20);
-				snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 					RT5645_HP_CO_MASK, RT5645_HP_CO_EN);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					0x3e, 0x7400);
-				snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+				snd_soc_component_write(component, RT5645_DEPOP_M3, 0x0737);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					RT5645_MAMP_INT_REG2, 0xfc00);
-				snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
 				msleep(90);
 				rt5645->hp_on = true;
 			} else {
 				/* depop parameters */
-				snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M2,
 					RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
-				snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x000d);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					RT5645_HP_DCC_INT1, 0x9f01);
 				mdelay(150);
 				/* headphone amp power on */
-				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 					RT5645_PWR_FV1 | RT5645_PWR_FV2, 0);
-				snd_soc_update_bits(codec, RT5645_PWR_VOL,
+				snd_soc_component_update_bits(component, RT5645_PWR_VOL,
 					RT5645_PWR_HV_L | RT5645_PWR_HV_R,
 					RT5645_PWR_HV_L | RT5645_PWR_HV_R);
-				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
 					RT5645_PWR_HA,
 					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
 					RT5645_PWR_HA);
 				mdelay(5);
-				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 					RT5645_PWR_FV1 | RT5645_PWR_FV2,
 					RT5645_PWR_FV1 | RT5645_PWR_FV2);
 
-				snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 					RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
 					RT5645_HP_CO_EN | RT5645_HP_SG_EN);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
@@ -1743,15 +1743,15 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 			if (rt5645->codec_type == CODEC_TYPE_RT5650) {
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					0x3e, 0x7400);
-				snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+				snd_soc_component_write(component, RT5645_DEPOP_M3, 0x0737);
 				regmap_write(rt5645->regmap, RT5645_PR_BASE +
 					RT5645_MAMP_INT_REG2, 0xfc00);
-				snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
 				msleep(100);
-				snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001);
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001);
 
 			} else {
-				snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 					RT5645_HP_SG_MASK |
 					RT5645_HP_L_SMT_MASK |
 					RT5645_HP_R_SMT_MASK,
@@ -1759,11 +1759,11 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 					RT5645_HP_L_SMT_DIS |
 					RT5645_HP_R_SMT_DIS);
 				/* headphone amp power down */
-				snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
-				snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0000);
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
 					RT5645_PWR_HA, 0);
-				snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M2,
 					RT5645_DEPOP_MASK, 0);
 			}
 		}
@@ -1773,15 +1773,15 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		hp_amp_power(codec, 1);
+		hp_amp_power(component, 1);
 		/* headphone unmute sequence */
 		if (rt5645->codec_type == CODEC_TYPE_RT5645) {
-			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M3,
 				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
 				RT5645_CP_FQ3_MASK,
 				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
@@ -1789,16 +1789,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
 			regmap_write(rt5645->regmap, RT5645_PR_BASE +
 				RT5645_MAMP_INT_REG2, 0xfc00);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_RSTN_MASK, RT5645_RSTN_EN);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
 				RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
 				RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
 			msleep(40);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
 				RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
 				RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
@@ -1808,7 +1808,7 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_PRE_PMD:
 		/* headphone mute sequence */
 		if (rt5645->codec_type == CODEC_TYPE_RT5645) {
-			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M3,
 				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
 				RT5645_CP_FQ3_MASK,
 				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
@@ -1816,17 +1816,17 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
 			regmap_write(rt5645->regmap, RT5645_PR_BASE +
 				RT5645_MAMP_INT_REG2, 0xfc00);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_RSTP_MASK, RT5645_RSTP_EN);
-			snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
 				RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
 				RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
 				RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
 			msleep(30);
 		}
-		hp_amp_power(codec, 0);
+		hp_amp_power(component, 0);
 		break;
 
 	default:
@@ -1839,25 +1839,25 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		rt5645_enable_hweq(codec);
-		snd_soc_update_bits(codec, RT5645_PWR_DIG1,
+		rt5645_enable_hweq(component);
+		snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
 			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
 			RT5645_PWR_CLS_D_L,
 			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
 			RT5645_PWR_CLS_D_L);
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
 			RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
 			RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
-		snd_soc_write(codec, RT5645_EQ_CTRL2, 0);
-		snd_soc_update_bits(codec, RT5645_PWR_DIG1,
+		snd_soc_component_write(component, RT5645_EQ_CTRL2, 0);
+		snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
 			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
 			RT5645_PWR_CLS_D_L, 0);
 		break;
@@ -1872,24 +1872,24 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		hp_amp_power(codec, 1);
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+		hp_amp_power(component, 1);
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 			RT5645_PWR_LM, RT5645_PWR_LM);
-		snd_soc_update_bits(codec, RT5645_LOUT1,
+		snd_soc_component_update_bits(component, RT5645_LOUT1,
 			RT5645_L_MUTE | RT5645_R_MUTE, 0);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5645_LOUT1,
+		snd_soc_component_update_bits(component, RT5645_LOUT1,
 			RT5645_L_MUTE | RT5645_R_MUTE,
 			RT5645_L_MUTE | RT5645_R_MUTE);
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 			RT5645_PWR_LM, 0);
-		hp_amp_power(codec, 0);
+		hp_amp_power(component, 0);
 		break;
 
 	default:
@@ -1902,16 +1902,16 @@ static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
 static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG2,
 			RT5645_PWR_BST2_P, RT5645_PWR_BST2_P);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG2,
 			RT5645_PWR_BST2_P, 0);
 		break;
 
@@ -1925,8 +1925,8 @@ static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1946,17 +1946,17 @@ static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
 			RT5645_MICBIAS1_POW_CTRL_SEL_MASK,
 			RT5645_MICBIAS1_POW_CTRL_SEL_M);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
 			RT5645_MICBIAS1_POW_CTRL_SEL_MASK,
 			RT5645_MICBIAS1_POW_CTRL_SEL_A);
 		break;
@@ -1971,17 +1971,17 @@ static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w,
 static int rt5645_set_micbias2_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *k, int  event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
 			RT5645_MICBIAS2_POW_CTRL_SEL_MASK,
 			RT5645_MICBIAS2_POW_CTRL_SEL_M);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, RT5645_GEN_CTRL2,
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
 			RT5645_MICBIAS2_POW_CTRL_SEL_MASK,
 			RT5645_MICBIAS2_POW_CTRL_SEL_A);
 		break;
@@ -2768,20 +2768,20 @@ static const struct snd_soc_dapm_route rt5645_old_dapm_routes[] = {
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk, dl_sft;
 	int pre_div, bclk_ms, frame_size;
 
 	rt5645->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting\n");
+		dev_err(component->dev, "Unsupported clock setting\n");
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 
@@ -2822,20 +2822,20 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
 	case RT5645_AIF1:
 		mask_clk = RT5645_I2S_PD1_MASK;
 		val_clk = pre_div << RT5645_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5645_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5645_I2S1_SDP,
 			(0x3 << dl_sft), (val_len << dl_sft));
-		snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5645_ADDA_CLK1, mask_clk, val_clk);
 		break;
 	case  RT5645_AIF2:
 		mask_clk = RT5645_I2S_BCLK_MS2_MASK | RT5645_I2S_PD2_MASK;
 		val_clk = bclk_ms << RT5645_I2S_BCLK_MS2_SFT |
 			pre_div << RT5645_I2S_PD2_SFT;
-		snd_soc_update_bits(codec, RT5645_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5645_I2S2_SDP,
 			(0x3 << dl_sft), (val_len << dl_sft));
-		snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5645_ADDA_CLK1, mask_clk, val_clk);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
@@ -2844,8 +2844,8 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0, pol_sft;
 
 	switch (rt5645->codec_type) {
@@ -2896,17 +2896,17 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 	switch (dai->id) {
 	case RT5645_AIF1:
-		snd_soc_update_bits(codec, RT5645_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5645_I2S1_SDP,
 			RT5645_I2S_MS_MASK | (1 << pol_sft) |
 			RT5645_I2S_DF_MASK, reg_val);
 		break;
 	case RT5645_AIF2:
-		snd_soc_update_bits(codec, RT5645_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5645_I2S2_SDP,
 			RT5645_I2S_MS_MASK | (1 << pol_sft) |
 			RT5645_I2S_DF_MASK, reg_val);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 	return 0;
@@ -2915,8 +2915,8 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5645->sysclk && clk_id == rt5645->sysclk_src)
@@ -2933,10 +2933,10 @@ static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai,
 		reg_val |= RT5645_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5645_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5645_GLB_CLK,
 		RT5645_SCLK_SRC_MASK, reg_val);
 	rt5645->sysclk = freq;
 	rt5645->sysclk_src = clk_id;
@@ -2949,8 +2949,8 @@ static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai,
 static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -2959,54 +2959,54 @@ static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5645->pll_in = 0;
 		rt5645->pll_out = 0;
-		snd_soc_update_bits(codec, RT5645_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5645_GLB_CLK,
 			RT5645_SCLK_SRC_MASK, RT5645_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5645_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5645_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5645_GLB_CLK,
 			RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_MCLK);
 		break;
 	case RT5645_PLL1_S_BCLK1:
 	case RT5645_PLL1_S_BCLK2:
 		switch (dai->id) {
 		case RT5645_AIF1:
-			snd_soc_update_bits(codec, RT5645_GLB_CLK,
+			snd_soc_component_update_bits(component, RT5645_GLB_CLK,
 				RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK1);
 			break;
 		case  RT5645_AIF2:
-			snd_soc_update_bits(codec, RT5645_GLB_CLK,
+			snd_soc_component_update_bits(component, RT5645_GLB_CLK,
 				RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK2);
 			break;
 		default:
-			dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+			dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 			return -EINVAL;
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5645_PLL_CTRL1,
+	snd_soc_component_write(component, RT5645_PLL_CTRL1,
 		pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5645_PLL_CTRL2,
+	snd_soc_component_write(component, RT5645_PLL_CTRL2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT |
 		pll_code.m_bp << RT5645_PLL_M_BP_SFT);
 
@@ -3020,8 +3020,8 @@ static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	unsigned int i_slot_sft, o_slot_sft, i_width_sht, o_width_sht, en_sft;
 	unsigned int mask, val = 0;
 
@@ -3044,7 +3044,7 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	if (rx_mask || tx_mask) {
 		val |= (1 << en_sft);
 		if (rt5645->codec_type == CODEC_TYPE_RT5645)
-			snd_soc_update_bits(codec, RT5645_BASS_BACK,
+			snd_soc_component_update_bits(component, RT5645_BASS_BACK,
 				RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
 	}
 
@@ -3078,45 +3078,45 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		break;
 	}
 
-	snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, mask, val);
+	snd_soc_component_update_bits(component, RT5645_TDM_CTRL_1, mask, val);
 
 	return 0;
 }
 
-static int rt5645_set_bias_level(struct snd_soc_codec *codec,
+static int rt5645_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_BG | RT5645_PWR_VREF2,
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_BG | RT5645_PWR_VREF2);
 			mdelay(10);
-			snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 				RT5645_PWR_FV1 | RT5645_PWR_FV2,
 				RT5645_PWR_FV1 | RT5645_PWR_FV2);
-			snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+			snd_soc_component_update_bits(component, RT5645_GEN_CTRL1,
 				RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
 		}
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 			RT5645_PWR_VREF1 | RT5645_PWR_MB |
 			RT5645_PWR_BG | RT5645_PWR_VREF2,
 			RT5645_PWR_VREF1 | RT5645_PWR_MB |
 			RT5645_PWR_BG | RT5645_PWR_VREF2);
 		mdelay(10);
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 			RT5645_PWR_FV1 | RT5645_PWR_FV2,
 			RT5645_PWR_FV1 | RT5645_PWR_FV2);
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
 			msleep(40);
 			if (rt5645->en_button_func)
 				queue_delayed_work(system_power_efficient_wq,
@@ -3126,11 +3126,11 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
+		snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1100);
 		if (!rt5645->en_button_func)
-			snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+			snd_soc_component_update_bits(component, RT5645_GEN_CTRL1,
 					RT5645_DIG_GATE_CTRL, 0);
-		snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
 				RT5645_PWR_VREF1 | RT5645_PWR_MB |
 				RT5645_PWR_BG | RT5645_PWR_VREF2 |
 				RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0);
@@ -3143,27 +3143,27 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
+static void rt5645_enable_push_button_irq(struct snd_soc_component *component,
 	bool enable)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (enable) {
 		snd_soc_dapm_force_enable_pin(dapm, "ADC L power");
 		snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
 		snd_soc_dapm_sync(dapm);
 
-		snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
+		snd_soc_component_update_bits(component,
 					RT5645_INT_IRQ_ST, 0x8, 0x8);
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 					RT5650_4BTN_IL_CMD2, 0x8000, 0x8000);
-		snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+		snd_soc_component_read32(component, RT5650_4BTN_IL_CMD1);
 		pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
-			snd_soc_read(codec, RT5650_4BTN_IL_CMD1));
+			snd_soc_component_read32(component, RT5650_4BTN_IL_CMD1));
 	} else {
-		snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
-		snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0);
+		snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
+		snd_soc_component_update_bits(component, RT5645_INT_IRQ_ST, 0x8, 0x0);
 
 		snd_soc_dapm_disable_pin(dapm, "ADC L power");
 		snd_soc_dapm_disable_pin(dapm, "ADC R power");
@@ -3171,10 +3171,10 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
 	}
 }
 
-static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5645_jack_detect(struct snd_soc_component *component, int jack_insert)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (jack_insert) {
@@ -3208,12 +3208,12 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 		msleep(600);
 		regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
 		val &= 0x7;
-		dev_dbg(codec->dev, "val = %d\n", val);
+		dev_dbg(component->dev, "val = %d\n", val);
 
 		if (val == 1 || val == 2) {
 			rt5645->jack_type = SND_JACK_HEADSET;
 			if (rt5645->en_button_func) {
-				rt5645_enable_push_button_irq(codec, true);
+				rt5645_enable_push_button_irq(component, true);
 			}
 		} else {
 			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
@@ -3235,7 +3235,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 			RT5645_CBJ_BST1_EN, 0);
 
 		if (rt5645->en_button_func)
-			rt5645_enable_push_button_irq(codec, false);
+			rt5645_enable_push_button_irq(component, false);
 
 		if (rt5645->pdata.jd_mode == 0)
 			snd_soc_dapm_disable_pin(dapm, "LDO2");
@@ -3249,25 +3249,25 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 	return rt5645->jack_type;
 }
 
-static int rt5645_button_detect(struct snd_soc_codec *codec)
+static int rt5645_button_detect(struct snd_soc_component *component)
 {
 	int btn_type, val;
 
-	val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+	val = snd_soc_component_read32(component, RT5650_4BTN_IL_CMD1);
 	pr_debug("val=0x%x\n", val);
 	btn_type = val & 0xfff0;
-	snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val);
+	snd_soc_component_write(component, RT5650_4BTN_IL_CMD1, val);
 
 	return btn_type;
 }
 
 static irqreturn_t rt5645_irq(int irq, void *data);
 
-int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+int rt5645_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
 	struct snd_soc_jack *btn_jack)
 {
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	rt5645->hp_jack = hp_jack;
 	rt5645->mic_jack = mic_jack;
@@ -3291,16 +3291,16 @@ static void rt5645_jack_detect_work(struct work_struct *work)
 		container_of(work, struct rt5645_priv, jack_detect_work.work);
 	int val, btn_type, gpio_state = 0, report = 0;
 
-	if (!rt5645->codec)
+	if (!rt5645->component)
 		return;
 
 	switch (rt5645->pdata.jd_mode) {
 	case 0: /* Not using rt5645 JD */
 		if (rt5645->gpiod_hp_det) {
 			gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
-			dev_dbg(rt5645->codec->dev, "gpio_state = %d\n",
+			dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
 				gpio_state);
-			report = rt5645_jack_detect(rt5645->codec, gpio_state);
+			report = rt5645_jack_detect(rt5645->component, gpio_state);
 		}
 		snd_soc_jack_report(rt5645->hp_jack,
 				    report, SND_JACK_HEADPHONE);
@@ -3308,20 +3308,20 @@ static void rt5645_jack_detect_work(struct work_struct *work)
 				    report, SND_JACK_MICROPHONE);
 		return;
 	default: /* read rt5645 jd1_1 status */
-		val = snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x1000;
+		val = snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000;
 		break;
 
 	}
 
 	if (!val && (rt5645->jack_type == 0)) { /* jack in */
-		report = rt5645_jack_detect(rt5645->codec, 1);
+		report = rt5645_jack_detect(rt5645->component, 1);
 	} else if (!val && rt5645->jack_type != 0) {
 		/* for push button and jack out */
 		btn_type = 0;
-		if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) {
+		if (snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
 			/* button pressed */
 			report = SND_JACK_HEADSET;
-			btn_type = rt5645_button_detect(rt5645->codec);
+			btn_type = rt5645_button_detect(rt5645->component);
 			/* rt5650 can report three kinds of button behavior,
 			   one click, double click and hold. However,
 			   currently we will report button pressed/released
@@ -3351,7 +3351,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
 			case 0x0000: /* unpressed */
 				break;
 			default:
-				dev_err(rt5645->codec->dev,
+				dev_err(rt5645->component->dev,
 					"Unexpected button code 0x%04x\n",
 					btn_type);
 				break;
@@ -3366,9 +3366,9 @@ static void rt5645_jack_detect_work(struct work_struct *work)
 	} else {
 		/* jack out */
 		report = 0;
-		snd_soc_update_bits(rt5645->codec,
+		snd_soc_component_update_bits(rt5645->component,
 				    RT5645_INT_IRQ_ST, 0x1, 0x0);
-		rt5645_jack_detect(rt5645->codec, 0);
+		rt5645_jack_detect(rt5645->component, 0);
 	}
 
 	snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
@@ -3406,12 +3406,12 @@ static void rt5645_btn_check_callback(struct timer_list *t)
 		   &rt5645->jack_detect_work, msecs_to_jiffies(5));
 }
 
-static int rt5645_probe(struct snd_soc_codec *codec)
+static int rt5645_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
-	rt5645->codec = codec;
+	rt5645->component = component;
 
 	switch (rt5645->codec_type) {
 	case CODEC_TYPE_RT5645:
@@ -3437,7 +3437,7 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 		break;
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	/* for JD function */
 	if (rt5645->pdata.jd_mode) {
@@ -3447,24 +3447,23 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 	}
 
 	if (rt5645->pdata.long_name)
-		codec->component.card->long_name = rt5645->pdata.long_name;
+		component->card->long_name = rt5645->pdata.long_name;
 
-	rt5645->eq_param = devm_kzalloc(codec->dev,
+	rt5645->eq_param = devm_kzalloc(component->dev,
 		RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s), GFP_KERNEL);
 
 	return 0;
 }
 
-static int rt5645_remove(struct snd_soc_codec *codec)
+static void rt5645_remove(struct snd_soc_component *component)
 {
-	rt5645_reset(codec);
-	return 0;
+	rt5645_reset(component);
 }
 
 #ifdef CONFIG_PM
-static int rt5645_suspend(struct snd_soc_codec *codec)
+static int rt5645_suspend(struct snd_soc_component *component)
 {
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5645->regmap, true);
 	regcache_mark_dirty(rt5645->regmap);
@@ -3472,9 +3471,9 @@ static int rt5645_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5645_resume(struct snd_soc_codec *codec)
+static int rt5645_resume(struct snd_soc_component *component)
 {
-	struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5645->regmap, false);
 	regcache_sync(rt5645->regmap);
@@ -3539,21 +3538,21 @@ static struct snd_soc_dai_driver rt5645_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
-	.probe = rt5645_probe,
-	.remove = rt5645_remove,
-	.suspend = rt5645_suspend,
-	.resume = rt5645_resume,
-	.set_bias_level = rt5645_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5645_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5645_snd_controls),
-		.dapm_widgets		= rt5645_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5645_dapm_widgets),
-		.dapm_routes		= rt5645_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5645_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5645 = {
+	.probe			= rt5645_probe,
+	.remove			= rt5645_remove,
+	.suspend		= rt5645_suspend,
+	.resume			= rt5645_resume,
+	.set_bias_level		= rt5645_set_bias_level,
+	.controls		= rt5645_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5645_snd_controls),
+	.dapm_widgets		= rt5645_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5645_dapm_widgets),
+	.dapm_routes		= rt5645_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5645_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5645_regmap = {
@@ -4028,7 +4027,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5645,
 				     rt5645_dai, ARRAY_SIZE(rt5645_dai));
 	if (ret)
 		goto err_irq;
@@ -4054,7 +4053,6 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
 	cancel_delayed_work_sync(&rt5645->rcclock_work);
 	del_timer_sync(&rt5645->btn_check_timer);
 
-	snd_soc_unregister_codec(&i2c->dev);
 	regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
 
 	return 0;
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 940325b28c29..cc2455768368 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -2200,10 +2200,10 @@ enum {
 	RT5645_AD_MONO_R_FILTER = (0x1 << 5),
 };
 
-int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5645_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src);
 
-int rt5645_set_jack_detect(struct snd_soc_codec *codec,
+int rt5645_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
 	struct snd_soc_jack *btn_jack);
 #endif /* __RT5645_H__ */
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 831b297978a4..de9034418ce3 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -384,17 +384,17 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 	int idx, rate;
 
 	rate = rt5651->sysclk / rl6231_get_pre_div(rt5651->regmap,
 		RT5651_ADDA_CLK1, RT5651_I2S_PD1_SFT);
 	idx = rl6231_calc_dmic_clk(rate);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
-		snd_soc_update_bits(codec, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
+		snd_soc_component_update_bits(component, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
 					idx << RT5651_DMIC_CLK_SFT);
 
 	return idx;
@@ -403,10 +403,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(codec, RT5651_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5651_GLB_CLK);
 	val &= RT5651_SCLK_SRC_MASK;
 	if (val == RT5651_SCLK_SRC_PLL1)
 		return 1;
@@ -703,8 +703,8 @@ static const struct snd_kcontrol_new rt5651_pdm_r_mux =
 static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -741,8 +741,8 @@ static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -786,8 +786,8 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
 
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -806,16 +806,16 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
 			RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
 			RT5651_PWR_BST1_OP2, 0);
 		break;
 
@@ -829,16 +829,16 @@ static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
 			RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
 			RT5651_PWR_BST2_OP2, 0);
 		break;
 
@@ -852,16 +852,16 @@ static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
 			RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
 			RT5651_PWR_BST3_OP2, 0);
 		break;
 
@@ -1313,8 +1313,8 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
 static int rt5651_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int pre_div, bclk_ms, frame_size;
 
@@ -1322,12 +1322,12 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
 	pre_div = rl6231_get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
 
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting\n");
+		dev_err(component->dev, "Unsupported clock setting\n");
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 	bclk_ms = frame_size > 32 ? 1 : 0;
@@ -1358,19 +1358,19 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
 	case RT5651_AIF1:
 		mask_clk = RT5651_I2S_PD1_MASK;
 		val_clk = pre_div << RT5651_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5651_I2S1_SDP,
 			RT5651_I2S_DL_MASK, val_len);
-		snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5651_ADDA_CLK1, mask_clk, val_clk);
 		break;
 	case RT5651_AIF2:
 		mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK;
 		val_clk = pre_div << RT5651_I2S_PD2_SFT;
-		snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5651_I2S2_SDP,
 			RT5651_I2S_DL_MASK, val_len);
-		snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5651_ADDA_CLK1, mask_clk, val_clk);
 		break;
 	default:
-		dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Wrong dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
@@ -1379,8 +1379,8 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1423,17 +1423,17 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (dai->id) {
 	case RT5651_AIF1:
-		snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5651_I2S1_SDP,
 			RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
 			RT5651_I2S_DF_MASK, reg_val);
 		break;
 	case RT5651_AIF2:
-		snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5651_I2S2_SDP,
 			RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
 			RT5651_I2S_DF_MASK, reg_val);
 		break;
 	default:
-		dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Wrong dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 	return 0;
@@ -1442,8 +1442,8 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src)
@@ -1460,10 +1460,10 @@ static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
 		reg_val |= RT5651_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5651_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5651_GLB_CLK,
 		RT5651_SCLK_SRC_MASK, reg_val);
 	rt5651->sysclk = freq;
 	rt5651->sysclk_src = clk_id;
@@ -1476,8 +1476,8 @@ static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
 static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -1486,46 +1486,46 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5651->pll_in = 0;
 		rt5651->pll_out = 0;
-		snd_soc_update_bits(codec, RT5651_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5651_GLB_CLK,
 			RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5651_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5651_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5651_GLB_CLK,
 			RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK);
 		break;
 	case RT5651_PLL1_S_BCLK1:
-		snd_soc_update_bits(codec, RT5651_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5651_GLB_CLK,
 				RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1);
 		break;
 	case RT5651_PLL1_S_BCLK2:
-			snd_soc_update_bits(codec, RT5651_GLB_CLK,
+			snd_soc_component_update_bits(component, RT5651_GLB_CLK,
 				RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5651_PLL_CTRL1,
+	snd_soc_component_write(component, RT5651_PLL_CTRL1,
 		pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5651_PLL_CTRL2,
+	snd_soc_component_write(component, RT5651_PLL_CTRL2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT |
 		pll_code.m_bp << RT5651_PLL_M_BP_SFT);
 
@@ -1536,45 +1536,45 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	return 0;
 }
 
-static int rt5651_set_bias_level(struct snd_soc_codec *codec,
+static int rt5651_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
 				RT5651_PWR_VREF1 | RT5651_PWR_MB |
 				RT5651_PWR_BG | RT5651_PWR_VREF2,
 				RT5651_PWR_VREF1 | RT5651_PWR_MB |
 				RT5651_PWR_BG | RT5651_PWR_VREF2);
 			usleep_range(10000, 15000);
-			snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
 				RT5651_PWR_FV1 | RT5651_PWR_FV2,
 				RT5651_PWR_FV1 | RT5651_PWR_FV2);
-			snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
 				RT5651_PWR_LDO_DVO_MASK,
 				RT5651_PWR_LDO_DVO_1_2V);
-			snd_soc_update_bits(codec, RT5651_D_MISC, 0x1, 0x1);
-			if (snd_soc_read(codec, RT5651_PLL_MODE_1) & 0x9200)
-				snd_soc_update_bits(codec, RT5651_D_MISC,
+			snd_soc_component_update_bits(component, RT5651_D_MISC, 0x1, 0x1);
+			if (snd_soc_component_read32(component, RT5651_PLL_MODE_1) & 0x9200)
+				snd_soc_component_update_bits(component, RT5651_D_MISC,
 						    0xc00, 0xc00);
 		}
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec, RT5651_D_MISC, 0x0010);
-		snd_soc_write(codec, RT5651_PWR_DIG1, 0x0000);
-		snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000);
-		snd_soc_write(codec, RT5651_PWR_VOL, 0x0000);
-		snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000);
+		snd_soc_component_write(component, RT5651_D_MISC, 0x0010);
+		snd_soc_component_write(component, RT5651_PWR_DIG1, 0x0000);
+		snd_soc_component_write(component, RT5651_PWR_DIG2, 0x0000);
+		snd_soc_component_write(component, RT5651_PWR_VOL, 0x0000);
+		snd_soc_component_write(component, RT5651_PWR_MIXER, 0x0000);
 		if (rt5651->pdata.jd_src) {
-			snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0204);
-			snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0002);
+			snd_soc_component_write(component, RT5651_PWR_ANLG2, 0x0204);
+			snd_soc_component_write(component, RT5651_PWR_ANLG1, 0x0002);
 		} else {
-			snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
-			snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
+			snd_soc_component_write(component, RT5651_PWR_ANLG1, 0x0000);
+			snd_soc_component_write(component, RT5651_PWR_ANLG2, 0x0000);
 		}
 		break;
 
@@ -1585,24 +1585,24 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5651_probe(struct snd_soc_codec *codec)
+static int rt5651_probe(struct snd_soc_component *component)
 {
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	rt5651->codec = codec;
+	rt5651->component = component;
 
-	snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+	snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
 		RT5651_PWR_VREF1 | RT5651_PWR_MB |
 		RT5651_PWR_BG | RT5651_PWR_VREF2,
 		RT5651_PWR_VREF1 | RT5651_PWR_MB |
 		RT5651_PWR_BG | RT5651_PWR_VREF2);
 	usleep_range(10000, 15000);
-	snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+	snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
 		RT5651_PWR_FV1 | RT5651_PWR_FV2,
 		RT5651_PWR_FV1 | RT5651_PWR_FV2);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	if (rt5651->pdata.jd_src) {
 		snd_soc_dapm_force_enable_pin(dapm, "JD Power");
@@ -1617,21 +1617,21 @@ static int rt5651_probe(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int rt5651_suspend(struct snd_soc_codec *codec)
+static int rt5651_suspend(struct snd_soc_component *component)
 {
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5651->regmap, true);
 	regcache_mark_dirty(rt5651->regmap);
 	return 0;
 }
 
-static int rt5651_resume(struct snd_soc_codec *codec)
+static int rt5651_resume(struct snd_soc_component *component)
 {
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5651->regmap, false);
-	snd_soc_cache_sync(codec);
+	snd_soc_component_cache_sync(component);
 
 	return 0;
 }
@@ -1692,20 +1692,20 @@ static struct snd_soc_dai_driver rt5651_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
-	.probe = rt5651_probe,
-	.suspend = rt5651_suspend,
-	.resume = rt5651_resume,
-	.set_bias_level = rt5651_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5651_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5651_snd_controls),
-		.dapm_widgets		= rt5651_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5651_dapm_widgets),
-		.dapm_routes		= rt5651_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5651_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5651 = {
+	.probe			= rt5651_probe,
+	.suspend		= rt5651_suspend,
+	.resume			= rt5651_resume,
+	.set_bias_level		= rt5651_set_bias_level,
+	.controls		= rt5651_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5651_snd_controls),
+	.dapm_widgets		= rt5651_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5651_dapm_widgets),
+	.dapm_routes		= rt5651_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5651_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5651_regmap = {
@@ -1722,6 +1722,7 @@ static const struct regmap_config rt5651_regmap = {
 	.num_reg_defaults = ARRAY_SIZE(rt5651_reg),
 	.ranges = rt5651_ranges,
 	.num_ranges = ARRAY_SIZE(rt5651_ranges),
+	.use_single_rw = true,
 };
 
 #if defined(CONFIG_OF)
@@ -1794,16 +1795,16 @@ static irqreturn_t rt5651_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int rt5651_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5651_jack_detect(struct snd_soc_component *component, int jack_insert)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int jack_type;
 
 	if (jack_insert) {
 		snd_soc_dapm_force_enable_pin(dapm, "LDO");
 		snd_soc_dapm_sync(dapm);
 
-		snd_soc_update_bits(codec, RT5651_MICBIAS,
+		snd_soc_component_update_bits(component, RT5651_MICBIAS,
 				    RT5651_MIC1_OVCD_MASK |
 				    RT5651_MIC1_OVTH_MASK |
 				    RT5651_PWR_CLK12M_MASK |
@@ -1813,16 +1814,16 @@ static int rt5651_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 				    RT5651_PWR_MB_PU |
 				    RT5651_PWR_CLK12M_PU);
 		msleep(100);
-		if (snd_soc_read(codec, RT5651_IRQ_CTRL2) & RT5651_MB1_OC_CLR)
+		if (snd_soc_component_read32(component, RT5651_IRQ_CTRL2) & RT5651_MB1_OC_CLR)
 			jack_type = SND_JACK_HEADPHONE;
 		else
 			jack_type = SND_JACK_HEADSET;
-		snd_soc_update_bits(codec, RT5651_IRQ_CTRL2,
+		snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
 				    RT5651_MB1_OC_CLR, 0);
 	} else { /* jack out */
 		jack_type = 0;
 
-		snd_soc_update_bits(codec, RT5651_MICBIAS,
+		snd_soc_component_update_bits(component, RT5651_MICBIAS,
 				    RT5651_MIC1_OVCD_MASK,
 				    RT5651_MIC1_OVCD_DIS);
 	}
@@ -1837,32 +1838,32 @@ static void rt5651_jack_detect_work(struct work_struct *work)
 
 	int report, val = 0;
 
-	if (!rt5651->codec)
+	if (!rt5651->component)
 		return;
 
 	switch (rt5651->pdata.jd_src) {
 	case RT5651_JD1_1:
-		val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x1000;
+		val = snd_soc_component_read32(rt5651->component, RT5651_INT_IRQ_ST) & 0x1000;
 		break;
 	case RT5651_JD1_2:
-		val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x2000;
+		val = snd_soc_component_read32(rt5651->component, RT5651_INT_IRQ_ST) & 0x2000;
 		break;
 	case RT5651_JD2:
-		val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x4000;
+		val = snd_soc_component_read32(rt5651->component, RT5651_INT_IRQ_ST) & 0x4000;
 		break;
 	default:
 		break;
 	}
 
-	report = rt5651_jack_detect(rt5651->codec, !val);
+	report = rt5651_jack_detect(rt5651->component, !val);
 
 	snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
 }
 
-int rt5651_set_jack_detect(struct snd_soc_codec *codec,
+int rt5651_set_jack_detect(struct snd_soc_component *component,
 			   struct snd_soc_jack *hp_jack)
 {
-	struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
 
 	rt5651->hp_jack = hp_jack;
 	rt5651_irq(0, rt5651);
@@ -1979,7 +1980,8 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
 		}
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_rt5651,
 				rt5651_dai, ARRAY_SIZE(rt5651_dai));
 
 	return ret;
@@ -1990,7 +1992,6 @@ static int rt5651_i2c_remove(struct i2c_client *i2c)
 	struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c);
 
 	cancel_delayed_work_sync(&rt5651->jack_detect_work);
-	snd_soc_unregister_codec(&i2c->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
index 4f8b202121d7..1ef38429e6a0 100644
--- a/sound/soc/codecs/rt5651.h
+++ b/sound/soc/codecs/rt5651.h
@@ -2059,7 +2059,7 @@ struct rt5651_pll_code {
 };
 
 struct rt5651_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5651_platform_data pdata;
 	struct regmap *regmap;
 	struct snd_soc_jack *hp_jack;
@@ -2079,6 +2079,6 @@ struct rt5651_priv {
 	bool hp_mute;
 };
 
-int rt5651_set_jack_detect(struct snd_soc_codec *codec,
+int rt5651_set_jack_detect(struct snd_soc_component *component,
 			   struct snd_soc_jack *hp_jack);
 #endif /* __RT5651_H__ */
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 07e7757417bc..b7721940b76f 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -1238,26 +1238,26 @@ static SOC_VALUE_ENUM_SINGLE_DECL(
 static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
-	if (snd_soc_read(codec, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
-		snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+	if (snd_soc_component_read32(component, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
+		snd_soc_component_update_bits(component, RT5659_STO_NG2_CTRL_1,
 			RT5659_NG2_EN_MASK, RT5659_NG2_DIS);
-		snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+		snd_soc_component_update_bits(component, RT5659_STO_NG2_CTRL_1,
 			RT5659_NG2_EN_MASK, RT5659_NG2_EN);
 	}
 
 	return ret;
 }
 
-static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
+static void rt5659_enable_push_button_irq(struct snd_soc_component *component,
 	bool enable)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (enable) {
-		snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, 0x000b);
+		snd_soc_component_write(component, RT5659_4BTN_IL_CMD_1, 0x000b);
 
 		/* MICBIAS1 and Mic Det Power for button detect*/
 		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
@@ -1265,19 +1265,19 @@ static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
 			"Mic Det Power");
 		snd_soc_dapm_sync(dapm);
 
-		snd_soc_update_bits(codec, RT5659_PWR_ANLG_2,
+		snd_soc_component_update_bits(component, RT5659_PWR_ANLG_2,
 			RT5659_PWR_MB1, RT5659_PWR_MB1);
-		snd_soc_update_bits(codec, RT5659_PWR_VOL,
+		snd_soc_component_update_bits(component, RT5659_PWR_VOL,
 			RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET);
 
-		snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+		snd_soc_component_update_bits(component, RT5659_IRQ_CTRL_2,
 				RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
-		snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+		snd_soc_component_update_bits(component, RT5659_4BTN_IL_CMD_2,
 				RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
 	} else {
-		snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+		snd_soc_component_update_bits(component, RT5659_4BTN_IL_CMD_2,
 				RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS);
-		snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+		snd_soc_component_update_bits(component, RT5659_IRQ_CTRL_2,
 				RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS);
 		/* MICBIAS1 and Mic Det Power for button detect*/
 		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
@@ -1288,7 +1288,7 @@ static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
 
 /**
  * rt5659_headset_detect - Detect headset.
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @jack_insert: Jack insert or not.
  *
  * Detect whether is headset or not when jack inserted.
@@ -1296,37 +1296,37 @@ static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
  * Returns detect status.
  */
 
-static int rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5659_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
 	int reg_63;
 
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
 	if (jack_insert) {
 		snd_soc_dapm_force_enable_pin(dapm,
 			"Mic Det Power");
 		snd_soc_dapm_sync(dapm);
-		reg_63 = snd_soc_read(codec, RT5659_PWR_ANLG_1);
+		reg_63 = snd_soc_component_read32(component, RT5659_PWR_ANLG_1);
 
-		snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+		snd_soc_component_update_bits(component, RT5659_PWR_ANLG_1,
 			RT5659_PWR_VREF2 | RT5659_PWR_MB,
 			RT5659_PWR_VREF2 | RT5659_PWR_MB);
 		msleep(20);
-		snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+		snd_soc_component_update_bits(component, RT5659_PWR_ANLG_1,
 			RT5659_PWR_FV2, RT5659_PWR_FV2);
 
-		snd_soc_write(codec, RT5659_EJD_CTRL_2, 0x4160);
-		snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+		snd_soc_component_write(component, RT5659_EJD_CTRL_2, 0x4160);
+		snd_soc_component_update_bits(component, RT5659_EJD_CTRL_1,
 			0x20, 0x0);
 		msleep(20);
-		snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+		snd_soc_component_update_bits(component, RT5659_EJD_CTRL_1,
 			0x20, 0x20);
 
 		while (i < 5) {
 			msleep(sleep_time[i]);
-			val = snd_soc_read(codec, RT5659_EJD_CTRL_2) & 0x0003;
+			val = snd_soc_component_read32(component, RT5659_EJD_CTRL_2) & 0x0003;
 			i++;
 			if (val == 0x1 || val == 0x2 || val == 0x3)
 				break;
@@ -1335,10 +1335,10 @@ static int rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 		switch (val) {
 		case 1:
 			rt5659->jack_type = SND_JACK_HEADSET;
-			rt5659_enable_push_button_irq(codec, true);
+			rt5659_enable_push_button_irq(component, true);
 			break;
 		default:
-			snd_soc_write(codec, RT5659_PWR_ANLG_1, reg_63);
+			snd_soc_component_write(component, RT5659_PWR_ANLG_1, reg_63);
 			rt5659->jack_type = SND_JACK_HEADPHONE;
 			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
 			snd_soc_dapm_sync(dapm);
@@ -1348,21 +1348,21 @@ static int rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
 		snd_soc_dapm_sync(dapm);
 		if (rt5659->jack_type == SND_JACK_HEADSET)
-			rt5659_enable_push_button_irq(codec, false);
+			rt5659_enable_push_button_irq(component, false);
 		rt5659->jack_type = 0;
 	}
 
-	dev_dbg(codec->dev, "jack_type = %d\n", rt5659->jack_type);
+	dev_dbg(component->dev, "jack_type = %d\n", rt5659->jack_type);
 	return rt5659->jack_type;
 }
 
-static int rt5659_button_detect(struct snd_soc_codec *codec)
+static int rt5659_button_detect(struct snd_soc_component *component)
 {
 	int btn_type, val;
 
-	val = snd_soc_read(codec, RT5659_4BTN_IL_CMD_1);
+	val = snd_soc_component_read32(component, RT5659_4BTN_IL_CMD_1);
 	btn_type = val & 0xfff0;
-	snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, val);
+	snd_soc_component_write(component, RT5659_4BTN_IL_CMD_1, val);
 
 	return btn_type;
 }
@@ -1377,10 +1377,10 @@ static irqreturn_t rt5659_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+int rt5659_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hs_jack)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
 	rt5659->hs_jack = hs_jack;
 
@@ -1396,19 +1396,19 @@ static void rt5659_jack_detect_work(struct work_struct *work)
 		container_of(work, struct rt5659_priv, jack_detect_work.work);
 	int val, btn_type, report = 0;
 
-	if (!rt5659->codec)
+	if (!rt5659->component)
 		return;
 
-	val = snd_soc_read(rt5659->codec, RT5659_INT_ST_1) & 0x0080;
+	val = snd_soc_component_read32(rt5659->component, RT5659_INT_ST_1) & 0x0080;
 	if (!val) {
 		/* jack in */
 		if (rt5659->jack_type == 0) {
 			/* jack was out, report jack type */
-			report = rt5659_headset_detect(rt5659->codec, 1);
+			report = rt5659_headset_detect(rt5659->component, 1);
 		} else {
 			/* jack is already in, report button event */
 			report = SND_JACK_HEADSET;
-			btn_type = rt5659_button_detect(rt5659->codec);
+			btn_type = rt5659_button_detect(rt5659->component);
 			/**
 			 * rt5659 can report three kinds of button behavior,
 			 * one click, double click and hold. However,
@@ -1441,7 +1441,7 @@ static void rt5659_jack_detect_work(struct work_struct *work)
 				break;
 			default:
 				btn_type = 0;
-				dev_err(rt5659->codec->dev,
+				dev_err(rt5659->component->dev,
 					"Unexpected button code 0x%04x\n",
 					btn_type);
 				break;
@@ -1453,7 +1453,7 @@ static void rt5659_jack_detect_work(struct work_struct *work)
 		}
 	} else {
 		/* jack out */
-		report = rt5659_headset_detect(rt5659->codec, 0);
+		report = rt5659_headset_detect(rt5659->component, 0);
 	}
 
 	snd_soc_jack_report(rt5659->hs_jack, report, SND_JACK_HEADSET |
@@ -1461,6 +1461,61 @@ static void rt5659_jack_detect_work(struct work_struct *work)
 			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
 }
 
+static void rt5659_jack_detect_intel_hd_header(struct work_struct *work)
+{
+	struct rt5659_priv *rt5659 =
+		container_of(work, struct rt5659_priv, jack_detect_work.work);
+	unsigned int value;
+	bool hp_flag, mic_flag;
+
+	if (!rt5659->hs_jack)
+		return;
+
+	/* headphone jack */
+	regmap_read(rt5659->regmap, RT5659_GPIO_STA, &value);
+	hp_flag = (!(value & 0x8)) ? true : false;
+
+	if (hp_flag != rt5659->hda_hp_plugged) {
+		rt5659->hda_hp_plugged = hp_flag;
+
+		if (hp_flag) {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+				0x10, 0x0);
+			rt5659->jack_type |= SND_JACK_HEADPHONE;
+		} else {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+				0x10, 0x10);
+			rt5659->jack_type = rt5659->jack_type &
+				(~SND_JACK_HEADPHONE);
+		}
+
+		snd_soc_jack_report(rt5659->hs_jack, rt5659->jack_type,
+			SND_JACK_HEADPHONE);
+	}
+
+	/* mic jack */
+	regmap_read(rt5659->regmap, RT5659_4BTN_IL_CMD_1, &value);
+	regmap_write(rt5659->regmap, RT5659_4BTN_IL_CMD_1, value);
+	mic_flag = (value & 0x2000) ? true : false;
+
+	if (mic_flag != rt5659->hda_mic_plugged) {
+		rt5659->hda_mic_plugged = mic_flag;
+		if (mic_flag) {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+				0x2, 0x2);
+			rt5659->jack_type |= SND_JACK_MICROPHONE;
+		} else {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+				0x2, 0x0);
+			rt5659->jack_type = rt5659->jack_type
+				& (~SND_JACK_MICROPHONE);
+		}
+
+		snd_soc_jack_report(rt5659->hs_jack, rt5659->jack_type,
+			SND_JACK_MICROPHONE);
+	}
+}
+
 static const struct snd_kcontrol_new rt5659_snd_controls[] = {
 	/* Speaker Output Volume */
 	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL,
@@ -1550,8 +1605,8 @@ static const struct snd_kcontrol_new rt5659_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 	int pd, idx = -EINVAL;
 
 	pd = rl6231_get_pre_div(rt5659->regmap,
@@ -1559,9 +1614,9 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd);
 
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else {
-		snd_soc_update_bits(codec, RT5659_DMIC_CTRL_1,
+		snd_soc_component_update_bits(component, RT5659_DMIC_CTRL_1,
 			RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT);
 	}
 	return idx;
@@ -1570,17 +1625,17 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int set_adc_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+		snd_soc_component_update_bits(component, RT5659_CHOP_ADC,
 			RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK,
 			RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+		snd_soc_component_update_bits(component, RT5659_CHOP_ADC,
 			RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, 0);
 		break;
 
@@ -1595,15 +1650,15 @@ static int set_adc_clk(struct snd_soc_dapm_widget *w,
 static int rt5659_charge_pump_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Depop */
-		snd_soc_write(codec, RT5659_DEPOP_1, 0x0009);
+		snd_soc_component_write(component, RT5659_DEPOP_1, 0x0009);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+		snd_soc_component_write(component, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
 		break;
 	default:
 		return 0;
@@ -1616,9 +1671,9 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
 			 struct snd_soc_dapm_widget *sink)
 {
 	unsigned int val;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
-	val = snd_soc_read(codec, RT5659_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5659_GLB_CLK);
 	val &= RT5659_SCLK_SRC_MASK;
 	if (val == RT5659_SCLK_SRC_PLL1)
 		return 1;
@@ -1630,7 +1685,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *w,
 			 struct snd_soc_dapm_widget *sink)
 {
 	unsigned int reg, shift, val;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (w->shift) {
 	case RT5659_ADC_MONO_R_ASRC_SFT:
@@ -1661,13 +1716,13 @@ static int is_using_asrc(struct snd_soc_dapm_widget *w,
 		return 0;
 	}
 
-	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
 	switch (val) {
 	case 1:
 	case 2:
 	case 3:
 		/* I2S_Pre_Div1 should be 1 in asrc mode */
-		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
 			RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2);
 		return 1;
 	default:
@@ -2303,24 +2358,24 @@ static const struct snd_kcontrol_new pdm_r_switch =
 static int rt5659_spk_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+		snd_soc_component_update_bits(component, RT5659_CLASSD_CTRL_1,
 			RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN);
-		snd_soc_update_bits(codec, RT5659_CLASSD_2,
+		snd_soc_component_update_bits(component, RT5659_CLASSD_2,
 			RT5659_M_RI_DIG, RT5659_M_RI_DIG);
-		snd_soc_write(codec, RT5659_CLASSD_1, 0x0803);
-		snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+		snd_soc_component_write(component, RT5659_CLASSD_1, 0x0803);
+		snd_soc_component_write(component, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, RT5659_CLASSD_1, 0x0011);
-		snd_soc_update_bits(codec, RT5659_CLASSD_2,
+		snd_soc_component_write(component, RT5659_CLASSD_1, 0x0011);
+		snd_soc_component_update_bits(component, RT5659_CLASSD_2,
 			RT5659_M_RI_DIG, 0x0);
-		snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
-		snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+		snd_soc_component_write(component, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+		snd_soc_component_update_bits(component, RT5659_CLASSD_CTRL_1,
 			RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS);
 		break;
 
@@ -2335,15 +2390,15 @@ static int rt5659_spk_event(struct snd_soc_dapm_widget *w,
 static int rt5659_mono_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+		snd_soc_component_write(component, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+		snd_soc_component_write(component, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
 		break;
 
 	default:
@@ -2357,16 +2412,16 @@ static int rt5659_mono_event(struct snd_soc_dapm_widget *w,
 static int rt5659_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0e1e);
-		snd_soc_update_bits(codec, RT5659_DEPOP_1, 0x0010, 0x0010);
+		snd_soc_component_write(component, RT5659_HP_CHARGE_PUMP_1, 0x0e1e);
+		snd_soc_component_update_bits(component, RT5659_DEPOP_1, 0x0010, 0x0010);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_write(codec, RT5659_DEPOP_1, 0x0000);
+		snd_soc_component_write(component, RT5659_DEPOP_1, 0x0000);
 		break;
 
 	default:
@@ -2818,11 +2873,6 @@ static const struct snd_soc_dapm_route rt5659_dapm_routes[] = {
 	{ "I2S2", NULL, "I2S2 ASRC" },
 	{ "I2S3", NULL, "I2S3 ASRC" },
 
-	{ "IN1P", NULL, "LDO2" },
-	{ "IN2P", NULL, "LDO2" },
-	{ "IN3P", NULL, "LDO2" },
-	{ "IN4P", NULL, "LDO2" },
-
 	{ "DMIC1", NULL, "DMIC L1" },
 	{ "DMIC1", NULL, "DMIC R1" },
 	{ "DMIC2", NULL, "DMIC L2" },
@@ -3237,21 +3287,21 @@ static const struct snd_soc_dapm_route rt5659_dapm_routes[] = {
 static int rt5659_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int pre_div, frame_size;
 
 	rt5659->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
 			rt5659->lrck[dai->id], dai->id);
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 
@@ -3278,39 +3328,39 @@ static int rt5659_hw_params(struct snd_pcm_substream *substream,
 	case RT5659_AIF1:
 		mask_clk = RT5659_I2S_PD1_MASK;
 		val_clk = pre_div << RT5659_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5659_I2S1_SDP,
 			RT5659_I2S_DL_MASK, val_len);
 		break;
 	case RT5659_AIF2:
 		mask_clk = RT5659_I2S_PD2_MASK;
 		val_clk = pre_div << RT5659_I2S_PD2_SFT;
-		snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5659_I2S2_SDP,
 			RT5659_I2S_DL_MASK, val_len);
 		break;
 	case RT5659_AIF3:
 		mask_clk = RT5659_I2S_PD3_MASK;
 		val_clk = pre_div << RT5659_I2S_PD3_SFT;
-		snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+		snd_soc_component_update_bits(component, RT5659_I2S3_SDP,
 			RT5659_I2S_DL_MASK, val_len);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, mask_clk, val_clk);
+	snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1, mask_clk, val_clk);
 
 	switch (rt5659->lrck[dai->id]) {
 	case 192000:
-		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
 			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32);
 		break;
 	case 96000:
-		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
 			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64);
 		break;
 	default:
-		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
 			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128);
 		break;
 	}
@@ -3320,8 +3370,8 @@ static int rt5659_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -3364,31 +3414,31 @@ static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (dai->id) {
 	case RT5659_AIF1:
-		snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5659_I2S1_SDP,
 			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
 			RT5659_I2S_DF_MASK, reg_val);
 		break;
 	case RT5659_AIF2:
-		snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5659_I2S2_SDP,
 			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
 			RT5659_I2S_DF_MASK, reg_val);
 		break;
 	case RT5659_AIF3:
-		snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+		snd_soc_component_update_bits(component, RT5659_I2S3_SDP,
 			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
 			RT5659_I2S_DF_MASK, reg_val);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 	return 0;
 }
 
-static int rt5659_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int rt5659_set_component_sysclk(struct snd_soc_component *component, int clk_id,
 				   int source, unsigned int freq, int dir)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
@@ -3405,25 +3455,25 @@ static int rt5659_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
 		reg_val |= RT5659_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5659_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5659_GLB_CLK,
 		RT5659_SCLK_SRC_MASK, reg_val);
 	rt5659->sysclk = freq;
 	rt5659->sysclk_src = clk_id;
 
-	dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n",
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
 		freq, clk_id);
 
 	return 0;
 }
 
-static int rt5659_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
+static int rt5659_set_component_pll(struct snd_soc_component *component, int pll_id,
 				int source, unsigned int freq_in,
 				unsigned int freq_out)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -3432,50 +3482,50 @@ static int rt5659_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5659->pll_in = 0;
 		rt5659->pll_out = 0;
-		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
 			RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5659_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
 			RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
 		break;
 	case RT5659_PLL1_S_BCLK1:
-		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
 				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1);
 		break;
 	case RT5659_PLL1_S_BCLK2:
-		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
 				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2);
 		break;
 	case RT5659_PLL1_S_BCLK3:
-		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
 				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5659_PLL_CTRL_1,
+	snd_soc_component_write(component, RT5659_PLL_CTRL_1,
 		pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5659_PLL_CTRL_2,
+	snd_soc_component_write(component, RT5659_PLL_CTRL_2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT |
 		pll_code.m_bp << RT5659_PLL_M_BP_SFT);
 
@@ -3489,7 +3539,7 @@ static int rt5659_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
 static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val = 0;
 
 	if (rx_mask || tx_mask)
@@ -3533,29 +3583,29 @@ static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5659_TDM_CTRL_1, 0x8ff0, val);
+	snd_soc_component_update_bits(component, RT5659_TDM_CTRL_1, 0x8ff0, val);
 
 	return 0;
 }
 
 static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
 
 	rt5659->bclk[dai->id] = ratio;
 
 	if (ratio == 64) {
 		switch (dai->id) {
 		case RT5659_AIF2:
-			snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+			snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
 				RT5659_I2S_BCLK_MS2_MASK,
 				RT5659_I2S_BCLK_MS2_64);
 			break;
 		case RT5659_AIF3:
-			snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+			snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
 				RT5659_I2S_BCLK_MS3_MASK,
 				RT5659_I2S_BCLK_MS3_64);
 			break;
@@ -3565,11 +3615,11 @@ static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 	return 0;
 }
 
-static int rt5659_set_bias_level(struct snd_soc_codec *codec,
+static int rt5659_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -3591,7 +3641,7 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec,
 		if (dapm->bias_level == SND_SOC_BIAS_OFF) {
 			ret = clk_prepare_enable(rt5659->mclk);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"failed to enable MCLK: %d\n", ret);
 				return ret;
 			}
@@ -3617,37 +3667,35 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5659_probe(struct snd_soc_codec *codec)
+static int rt5659_probe(struct snd_soc_component *component)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
-	rt5659->codec = codec;
+	rt5659->component = component;
 
 	return 0;
 }
 
-static int rt5659_remove(struct snd_soc_codec *codec)
+static void rt5659_remove(struct snd_soc_component *component)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
 	regmap_write(rt5659->regmap, RT5659_RESET, 0);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt5659_suspend(struct snd_soc_codec *codec)
+static int rt5659_suspend(struct snd_soc_component *component)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5659->regmap, true);
 	regcache_mark_dirty(rt5659->regmap);
 	return 0;
 }
 
-static int rt5659_resume(struct snd_soc_codec *codec)
+static int rt5659_resume(struct snd_soc_component *component)
 {
-	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5659->regmap, false);
 	regcache_sync(rt5659->regmap);
@@ -3730,23 +3778,23 @@ static struct snd_soc_dai_driver rt5659_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
-	.probe = rt5659_probe,
-	.remove = rt5659_remove,
-	.suspend = rt5659_suspend,
-	.resume = rt5659_resume,
-	.set_bias_level = rt5659_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5659_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5659_snd_controls),
-		.dapm_widgets		= rt5659_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5659_dapm_widgets),
-		.dapm_routes		= rt5659_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5659_dapm_routes),
-	},
-	.set_sysclk = rt5659_set_codec_sysclk,
-	.set_pll = rt5659_set_codec_pll,
+static const struct snd_soc_component_driver soc_component_dev_rt5659 = {
+	.probe			= rt5659_probe,
+	.remove			= rt5659_remove,
+	.suspend		= rt5659_suspend,
+	.resume			= rt5659_resume,
+	.set_bias_level		= rt5659_set_bias_level,
+	.controls		= rt5659_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5659_snd_controls),
+	.dapm_widgets		= rt5659_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5659_dapm_widgets),
+	.dapm_routes		= rt5659_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5659_dapm_routes),
+	.set_sysclk		= rt5659_set_component_sysclk,
+	.set_pll		= rt5659_set_component_pll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 
@@ -3849,7 +3897,7 @@ static void rt5659_calibrate(struct rt5659_priv *rt5659)
 			break;
 
 		if (count > 30) {
-			dev_err(rt5659->codec->dev,
+			dev_err(rt5659->component->dev,
 				"HP Calibration 1 Failure\n");
 			return;
 		}
@@ -3874,7 +3922,7 @@ static void rt5659_calibrate(struct rt5659_priv *rt5659)
 			break;
 
 		if (count > 85) {
-			dev_err(rt5659->codec->dev,
+			dev_err(rt5659->component->dev,
 				"HP Calibration 2 Failure\n");
 			return;
 		}
@@ -3922,7 +3970,7 @@ static void rt5659_calibrate(struct rt5659_priv *rt5659)
 			break;
 
 		if (count > 10) {
-			dev_err(rt5659->codec->dev,
+			dev_err(rt5659->component->dev,
 				"SPK Calibration Failure\n");
 			return;
 		}
@@ -3955,7 +4003,7 @@ static void rt5659_calibrate(struct rt5659_priv *rt5659)
 			break;
 
 		if (count > 35) {
-			dev_err(rt5659->codec->dev,
+			dev_err(rt5659->component->dev,
 				"Mono Calibration Failure\n");
 			return;
 		}
@@ -3990,6 +4038,54 @@ static void rt5659_calibrate(struct rt5659_priv *rt5659)
 	regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
 }
 
+static void rt5659_intel_hd_header_probe_setup(struct rt5659_priv *rt5659)
+{
+	int value;
+
+	regmap_read(rt5659->regmap, RT5659_GPIO_STA, &value);
+	if (!(value & 0x8)) {
+		rt5659->hda_hp_plugged = true;
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+			0x10, 0x0);
+	} else {
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+			0x10, 0x10);
+	}
+
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+		RT5659_PWR_VREF2 | RT5659_PWR_MB,
+		RT5659_PWR_VREF2 | RT5659_PWR_MB);
+	msleep(20);
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+		RT5659_PWR_FV2, RT5659_PWR_FV2);
+
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_3, RT5659_PWR_LDO2,
+		RT5659_PWR_LDO2);
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_2, RT5659_PWR_MB1,
+		RT5659_PWR_MB1);
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_VOL, RT5659_PWR_MIC_DET,
+		RT5659_PWR_MIC_DET);
+	msleep(20);
+
+	regmap_update_bits(rt5659->regmap, RT5659_4BTN_IL_CMD_2,
+		RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
+	regmap_read(rt5659->regmap, RT5659_4BTN_IL_CMD_1, &value);
+	regmap_write(rt5659->regmap, RT5659_4BTN_IL_CMD_1, value);
+	regmap_read(rt5659->regmap, RT5659_4BTN_IL_CMD_1, &value);
+
+	if (value & 0x2000) {
+		rt5659->hda_mic_plugged = true;
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+			0x2, 0x2);
+	} else {
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+			0x2, 0x0);
+	}
+
+	regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+		RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
+}
+
 static int rt5659_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
@@ -4174,16 +4270,23 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
 				RT5659_PWR_MB, RT5659_PWR_MB);
 		regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001);
 		regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040);
+		INIT_DELAYED_WORK(&rt5659->jack_detect_work,
+			rt5659_jack_detect_work);
 		break;
-	case RT5659_JD_NULL:
+	case RT5659_JD_HDA_HEADER:
+		regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_3, 0x8000);
+		regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x0900);
+		regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1,  0x70c0);
+		regmap_write(rt5659->regmap, RT5659_JD_CTRL_1,   0x2000);
+		regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_1,  0x0040);
+		INIT_DELAYED_WORK(&rt5659->jack_detect_work,
+			rt5659_jack_detect_intel_hd_header);
+		rt5659_intel_hd_header_probe_setup(rt5659);
 		break;
 	default:
-		dev_warn(&i2c->dev, "Currently, support JD3 only\n");
 		break;
 	}
 
-	INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work);
-
 	if (i2c->irq) {
 		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
 			rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
@@ -4196,17 +4299,11 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
 				   RT5659_GP1_PIN_MASK, RT5659_GP1_PIN_IRQ);
 	}
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5659,
 			rt5659_dai, ARRAY_SIZE(rt5659_dai));
 }
 
-static int rt5659_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static void rt5659_i2c_shutdown(struct i2c_client *client)
 {
 	struct rt5659_priv *rt5659 = i2c_get_clientdata(client);
@@ -4239,7 +4336,6 @@ static struct i2c_driver rt5659_i2c_driver = {
 		.acpi_match_table = ACPI_PTR(rt5659_acpi_match),
 	},
 	.probe = rt5659_i2c_probe,
-	.remove = rt5659_i2c_remove,
 	.shutdown = rt5659_i2c_shutdown,
 	.id_table = rt5659_i2c_id,
 };
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
index 8f1aeef08489..73969ef5029f 100644
--- a/sound/soc/codecs/rt5659.h
+++ b/sound/soc/codecs/rt5659.h
@@ -1789,7 +1789,7 @@ struct rt5659_pll_code {
 };
 
 struct rt5659_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5659_platform_data pdata;
 	struct regmap *regmap;
 	struct gpio_desc *gpiod_ldo1_en;
@@ -1810,10 +1810,11 @@ struct rt5659_priv {
 	int pll_out;
 
 	int jack_type;
-
+	bool hda_hp_plugged;
+	bool hda_mic_plugged;
 };
 
-int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+int rt5659_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hs_jack);
 
 #endif /* __RT5659_H__ */
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index d22ef00e0d96..20a755137e63 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -354,17 +354,17 @@ static const struct snd_kcontrol_new rt5660_snd_controls[] = {
 static int rt5660_set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 	int idx, rate;
 
 	rate = rt5660->sysclk / rl6231_get_pre_div(rt5660->regmap,
 		RT5660_ADDA_CLK1, RT5660_I2S_PD1_SFT);
 	idx = rl6231_calc_dmic_clk(rate);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
-		snd_soc_update_bits(codec, RT5660_DMIC_CTRL1,
+		snd_soc_component_update_bits(component, RT5660_DMIC_CTRL1,
 			RT5660_DMIC_CLK_MASK, idx << RT5660_DMIC_CLK_SFT);
 
 	return idx;
@@ -373,10 +373,10 @@ static int rt5660_set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int rt5660_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int val;
 
-	val = snd_soc_read(codec, RT5660_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5660_GLB_CLK);
 	val &= RT5660_SCLK_SRC_MASK;
 	if (val == RT5660_SCLK_SRC_PLL1)
 		return 1;
@@ -541,17 +541,17 @@ static const struct snd_kcontrol_new rt5660_if1_adc_swap_mux =
 static int rt5660_lout_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL,
+		snd_soc_component_update_bits(component, RT5660_LOUT_AMP_CTRL,
 			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
 			RT5660_LOUT_CO_EN | RT5660_LOUT_CB_PU);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL,
+		snd_soc_component_update_bits(component, RT5660_LOUT_AMP_CTRL,
 			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
 			RT5660_LOUT_CO_DIS | RT5660_LOUT_CB_PD);
 		break;
@@ -838,22 +838,22 @@ static const struct snd_soc_dapm_route rt5660_dapm_routes[] = {
 static int rt5660_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int pre_div, bclk_ms, frame_size;
 
 	rt5660->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5660->sysclk, rt5660->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
 			rt5660->lrck[dai->id], dai->id);
 		return -EINVAL;
 	}
 
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return frame_size;
 	}
 
@@ -890,13 +890,13 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream,
 		mask_clk = RT5660_I2S_BCLK_MS1_MASK | RT5660_I2S_PD1_MASK;
 		val_clk = bclk_ms << RT5660_I2S_BCLK_MS1_SFT |
 			pre_div << RT5660_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK,
+		snd_soc_component_update_bits(component, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK,
 			val_len);
-		snd_soc_update_bits(codec, RT5660_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5660_ADDA_CLK1, mask_clk, val_clk);
 		break;
 
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
@@ -905,8 +905,8 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -957,13 +957,13 @@ static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (dai->id) {
 	case RT5660_AIF1:
-		snd_soc_update_bits(codec, RT5660_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5660_I2S1_SDP,
 			RT5660_I2S_MS_MASK | RT5660_I2S_BP_MASK |
 			RT5660_I2S_DF_MASK, reg_val);
 		break;
 
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
@@ -973,8 +973,8 @@ static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5660->sysclk && clk_id == rt5660->sysclk_src)
@@ -994,11 +994,11 @@ static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai,
 		break;
 
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK,
+	snd_soc_component_update_bits(component, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK,
 		reg_val);
 
 	rt5660->sysclk = freq;
@@ -1012,8 +1012,8 @@ static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai,
 static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -1022,44 +1022,44 @@ static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5660->pll_in = 0;
 		rt5660->pll_out = 0;
-		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5660_GLB_CLK,
 			RT5660_SCLK_SRC_MASK, RT5660_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5660_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5660_GLB_CLK,
 			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_MCLK);
 		break;
 
 	case RT5660_PLL1_S_BCLK:
-		snd_soc_update_bits(codec, RT5660_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5660_GLB_CLK,
 			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_BCLK1);
 		break;
 
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5660_PLL_CTRL1,
+	snd_soc_component_write(component, RT5660_PLL_CTRL1,
 		pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5660_PLL_CTRL2,
+	snd_soc_component_write(component, RT5660_PLL_CTRL2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT |
 		pll_code.m_bp << RT5660_PLL_M_BP_SFT);
 
@@ -1070,10 +1070,10 @@ static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	return 0;
 }
 
-static int rt5660_set_bias_level(struct snd_soc_codec *codec,
+static int rt5660_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1081,13 +1081,13 @@ static int rt5660_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, RT5660_GEN_CTRL1,
+		snd_soc_component_update_bits(component, RT5660_GEN_CTRL1,
 			RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL);
 
 		if (IS_ERR(rt5660->mclk))
 			break;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
 			clk_disable_unprepare(rt5660->mclk);
 		} else {
 			ret = clk_prepare_enable(rt5660->mclk);
@@ -1097,21 +1097,21 @@ static int rt5660_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_update_bits(codec, RT5660_PWR_ANLG1,
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, RT5660_PWR_ANLG1,
 				RT5660_PWR_VREF1 | RT5660_PWR_MB |
 				RT5660_PWR_BG | RT5660_PWR_VREF2,
 				RT5660_PWR_VREF1 | RT5660_PWR_MB |
 				RT5660_PWR_BG | RT5660_PWR_VREF2);
 			usleep_range(10000, 15000);
-			snd_soc_update_bits(codec, RT5660_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5660_PWR_ANLG1,
 				RT5660_PWR_FV1 | RT5660_PWR_FV2,
 				RT5660_PWR_FV1 | RT5660_PWR_FV2);
 		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, RT5660_GEN_CTRL1,
+		snd_soc_component_update_bits(component, RT5660_GEN_CTRL1,
 			RT5660_DIG_GATE_CTRL, 0);
 		break;
 
@@ -1122,24 +1122,24 @@ static int rt5660_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5660_probe(struct snd_soc_codec *codec)
+static int rt5660_probe(struct snd_soc_component *component)
 {
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 
-	rt5660->codec = codec;
+	rt5660->component = component;
 
 	return 0;
 }
 
-static int rt5660_remove(struct snd_soc_codec *codec)
+static void rt5660_remove(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, RT5660_RESET, 0);
+	snd_soc_component_write(component, RT5660_RESET, 0);
 }
 
 #ifdef CONFIG_PM
-static int rt5660_suspend(struct snd_soc_codec *codec)
+static int rt5660_suspend(struct snd_soc_component *component)
 {
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5660->regmap, true);
 	regcache_mark_dirty(rt5660->regmap);
@@ -1147,9 +1147,9 @@ static int rt5660_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5660_resume(struct snd_soc_codec *codec)
+static int rt5660_resume(struct snd_soc_component *component)
 {
-	struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec);
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
 
 	if (rt5660->pdata.poweroff_codec_in_suspend)
 		msleep(350);
@@ -1197,21 +1197,21 @@ static struct snd_soc_dai_driver rt5660_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5660 = {
-	.probe = rt5660_probe,
-	.remove = rt5660_remove,
-	.suspend = rt5660_suspend,
-	.resume = rt5660_resume,
-	.set_bias_level = rt5660_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5660_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5660_snd_controls),
-		.dapm_widgets		= rt5660_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5660_dapm_widgets),
-		.dapm_routes		= rt5660_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5660_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5660 = {
+	.probe			= rt5660_probe,
+	.remove			= rt5660_remove,
+	.suspend		= rt5660_suspend,
+	.resume			= rt5660_resume,
+	.set_bias_level		= rt5660_set_bias_level,
+	.controls		= rt5660_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5660_snd_controls),
+	.dapm_widgets		= rt5660_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5660_dapm_widgets),
+	.dapm_routes		= rt5660_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5660_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5660_regmap = {
@@ -1329,17 +1329,11 @@ static int rt5660_i2c_probe(struct i2c_client *i2c,
 				RT5660_SEL_DMIC_DATA_IN1P);
 	}
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5660,
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5660,
 				      rt5660_dai, ARRAY_SIZE(rt5660_dai));
 }
 
-static int rt5660_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static struct i2c_driver rt5660_i2c_driver = {
 	.driver = {
 		.name = "rt5660",
@@ -1347,7 +1341,6 @@ static struct i2c_driver rt5660_i2c_driver = {
 		.of_match_table = of_match_ptr(rt5660_of_match),
 	},
 	.probe = rt5660_i2c_probe,
-	.remove   = rt5660_i2c_remove,
 	.id_table = rt5660_i2c_id,
 };
 module_i2c_driver(rt5660_i2c_driver);
diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h
index bba18fb66b6f..c65de0a20a49 100644
--- a/sound/soc/codecs/rt5660.h
+++ b/sound/soc/codecs/rt5660.h
@@ -831,7 +831,7 @@ enum {
 };
 
 struct rt5660_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5660_platform_data pdata;
 	struct regmap *regmap;
 	struct clk *mclk;
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index d329bf719d80..20c0aeea6ca3 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -49,7 +49,7 @@ struct impedance_mapping_table {
 };
 
 struct rt5663_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5663_platform_data pdata;
 	struct regmap *regmap;
 	struct delayed_work jack_detect_work, jd_unplug_work;
@@ -1384,57 +1384,57 @@ static const char * const rt5663_if1_adc_data_select[] = {
 static SOC_ENUM_SINGLE_DECL(rt5663_if1_adc_enum, RT5663_TDM_2,
 	RT5663_DATA_SWAP_ADCDAT1_SHIFT, rt5663_if1_adc_data_select);
 
-static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,
+static void rt5663_enable_push_button_irq(struct snd_soc_component *component,
 	bool enable)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	if (enable) {
-		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
 			RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_EN);
 		/* reset in-line command */
-		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
 			RT5663_RESET_4BTN_INL_MASK,
 			RT5663_RESET_4BTN_INL_RESET);
-		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
 			RT5663_RESET_4BTN_INL_MASK,
 			RT5663_RESET_4BTN_INL_NOR);
 		switch (rt5663->codec_ver) {
 		case CODEC_VER_1:
-			snd_soc_update_bits(codec, RT5663_IRQ_3,
+			snd_soc_component_update_bits(component, RT5663_IRQ_3,
 				RT5663_V2_EN_IRQ_INLINE_MASK,
 				RT5663_V2_EN_IRQ_INLINE_NOR);
 			break;
 		case CODEC_VER_0:
-			snd_soc_update_bits(codec, RT5663_IRQ_2,
+			snd_soc_component_update_bits(component, RT5663_IRQ_2,
 				RT5663_EN_IRQ_INLINE_MASK,
 				RT5663_EN_IRQ_INLINE_NOR);
 			break;
 		default:
-			dev_err(codec->dev, "Unknown CODEC Version\n");
+			dev_err(component->dev, "Unknown CODEC Version\n");
 		}
 	} else {
 		switch (rt5663->codec_ver) {
 		case CODEC_VER_1:
-			snd_soc_update_bits(codec, RT5663_IRQ_3,
+			snd_soc_component_update_bits(component, RT5663_IRQ_3,
 				RT5663_V2_EN_IRQ_INLINE_MASK,
 				RT5663_V2_EN_IRQ_INLINE_BYP);
 			break;
 		case CODEC_VER_0:
-			snd_soc_update_bits(codec, RT5663_IRQ_2,
+			snd_soc_component_update_bits(component, RT5663_IRQ_2,
 				RT5663_EN_IRQ_INLINE_MASK,
 				RT5663_EN_IRQ_INLINE_BYP);
 			break;
 		default:
-			dev_err(codec->dev, "Unknown CODEC Version\n");
+			dev_err(component->dev, "Unknown CODEC Version\n");
 		}
-		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
 			RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_DIS);
 		/* reset in-line command */
-		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
 			RT5663_RESET_4BTN_INL_MASK,
 			RT5663_RESET_4BTN_INL_RESET);
-		snd_soc_update_bits(codec, RT5663_IL_CMD_6,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
 			RT5663_RESET_4BTN_INL_MASK,
 			RT5663_RESET_4BTN_INL_NOR);
 	}
@@ -1442,7 +1442,7 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,
 
 /**
  * rt5663_v2_jack_detect - Detect headset.
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @jack_insert: Jack insert or not.
  *
  * Detect whether is headset or not when jack inserted.
@@ -1450,41 +1450,41 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,
  * Returns detect status.
  */
 
-static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5663_v2_jack_detect(struct snd_soc_component *component, int jack_insert)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
 
-	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+	dev_dbg(component->dev, "%s jack_insert:%d\n", __func__, jack_insert);
 	if (jack_insert) {
-		snd_soc_write(codec, RT5663_CBJ_TYPE_2, 0x8040);
-		snd_soc_write(codec, RT5663_CBJ_TYPE_3, 0x1484);
+		snd_soc_component_write(component, RT5663_CBJ_TYPE_2, 0x8040);
+		snd_soc_component_write(component, RT5663_CBJ_TYPE_3, 0x1484);
 
 		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
 		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
 		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
 		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
 		snd_soc_dapm_sync(dapm);
-		snd_soc_update_bits(codec, RT5663_RC_CLK,
+		snd_soc_component_update_bits(component, RT5663_RC_CLK,
 			RT5663_DIG_1M_CLK_MASK, RT5663_DIG_1M_CLK_EN);
-		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8);
+		snd_soc_component_update_bits(component, RT5663_RECMIX, 0x8, 0x8);
 
 		while (i < 5) {
 			msleep(sleep_time[i]);
-			val = snd_soc_read(codec, RT5663_CBJ_TYPE_2) & 0x0003;
+			val = snd_soc_component_read32(component, RT5663_CBJ_TYPE_2) & 0x0003;
 			if (val == 0x1 || val == 0x2 || val == 0x3)
 				break;
-			dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n",
+			dev_dbg(component->dev, "%s: MX-0011 val=%x sleep %d\n",
 				__func__, val, sleep_time[i]);
 			i++;
 		}
-		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+		dev_dbg(component->dev, "%s val = %d\n", __func__, val);
 		switch (val) {
 		case 1:
 		case 2:
 			rt5663->jack_type = SND_JACK_HEADSET;
-			rt5663_enable_push_button_irq(codec, true);
+			rt5663_enable_push_button_irq(component, true);
 			break;
 		default:
 			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
@@ -1496,10 +1496,10 @@ static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 			break;
 		}
 	} else {
-		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0);
+		snd_soc_component_update_bits(component, RT5663_RECMIX, 0x8, 0x0);
 
 		if (rt5663->jack_type == SND_JACK_HEADSET) {
-			rt5663_enable_push_button_irq(codec, false);
+			rt5663_enable_push_button_irq(component, false);
 			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
 			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
 			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
@@ -1509,60 +1509,60 @@ static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 		rt5663->jack_type = 0;
 	}
 
-	dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type);
+	dev_dbg(component->dev, "jack_type = %d\n", rt5663->jack_type);
 	return rt5663->jack_type;
 }
 
 /**
  * rt5663_jack_detect - Detect headset.
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @jack_insert: Jack insert or not.
  *
  * Detect whether is headset or not when jack inserted.
  *
  * Returns detect status.
  */
-static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5663_jack_detect(struct snd_soc_component *component, int jack_insert)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	int val, i = 0;
 
-	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+	dev_dbg(component->dev, "%s jack_insert:%d\n", __func__, jack_insert);
 
 	if (jack_insert) {
-		snd_soc_update_bits(codec, RT5663_DIG_MISC,
+		snd_soc_component_update_bits(component, RT5663_DIG_MISC,
 			RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN);
-		snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 			RT5663_SI_HP_MASK | RT5663_OSW_HP_L_MASK |
 			RT5663_OSW_HP_R_MASK, RT5663_SI_HP_EN |
 			RT5663_OSW_HP_L_DIS | RT5663_OSW_HP_R_DIS);
-		snd_soc_update_bits(codec, RT5663_DUMMY_1,
+		snd_soc_component_update_bits(component, RT5663_DUMMY_1,
 			RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK |
 			RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN |
 			RT5663_HPA_CPL_BIAS_1 | RT5663_HPA_CPR_BIAS_1);
-		snd_soc_update_bits(codec, RT5663_CBJ_1,
+		snd_soc_component_update_bits(component, RT5663_CBJ_1,
 			RT5663_INBUF_CBJ_BST1_MASK | RT5663_CBJ_SENSE_BST1_MASK,
 			RT5663_INBUF_CBJ_BST1_ON | RT5663_CBJ_SENSE_BST1_L);
-		snd_soc_update_bits(codec, RT5663_IL_CMD_2,
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_2,
 			RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON);
 		/* BST1 power on for JD */
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
 			RT5663_PWR_BST1_MASK, RT5663_PWR_BST1_ON);
-		snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+		snd_soc_component_update_bits(component, RT5663_EM_JACK_TYPE_1,
 			RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK |
 			RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN |
 			RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN);
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 			RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK |
 			RT5663_AMP_HP_MASK, RT5663_PWR_MB |
 			RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);
-		snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK,
+		snd_soc_component_update_bits(component, RT5663_AUTO_1MRC_CLK,
 			RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
-		snd_soc_update_bits(codec, RT5663_IRQ_1,
+		snd_soc_component_update_bits(component, RT5663_IRQ_1,
 			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
-		snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+		snd_soc_component_update_bits(component, RT5663_EM_JACK_TYPE_1,
 			RT5663_EM_JD_MASK, RT5663_EM_JD_RST);
-		snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,
+		snd_soc_component_update_bits(component, RT5663_EM_JACK_TYPE_1,
 			RT5663_EM_JD_MASK, RT5663_EM_JD_NOR);
 
 		while (true) {
@@ -1577,10 +1577,10 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 			i++;
 		}
 
-		val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & 0x0003;
-		dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
+		val = snd_soc_component_read32(component, RT5663_EM_JACK_TYPE_2) & 0x0003;
+		dev_dbg(component->dev, "%s val = %d\n", __func__, val);
 
-		snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 			RT5663_OSW_HP_L_MASK | RT5663_OSW_HP_R_MASK,
 			RT5663_OSW_HP_L_EN | RT5663_OSW_HP_R_EN);
 
@@ -1588,7 +1588,7 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 		case 1:
 		case 2:
 			rt5663->jack_type = SND_JACK_HEADSET;
-			rt5663_enable_push_button_irq(codec, true);
+			rt5663_enable_push_button_irq(component, true);
 
 			if (rt5663->pdata.impedance_sensing_num)
 				break;
@@ -1636,17 +1636,17 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
 		}
 	} else {
 		if (rt5663->jack_type == SND_JACK_HEADSET)
-			rt5663_enable_push_button_irq(codec, false);
+			rt5663_enable_push_button_irq(component, false);
 		rt5663->jack_type = 0;
 	}
 
-	dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type);
+	dev_dbg(component->dev, "jack_type = %d\n", rt5663->jack_type);
 	return rt5663->jack_type;
 }
 
-static int rt5663_impedance_sensing(struct snd_soc_codec *codec)
+static int rt5663_impedance_sensing(struct snd_soc_component *component)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	unsigned int value, i, reg84, reg26, reg2fa, reg91, reg10, reg80;
 
 	for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
@@ -1655,59 +1655,59 @@ static int rt5663_impedance_sensing(struct snd_soc_codec *codec)
 	}
 
 	if (rt5663->jack_type == SND_JACK_HEADSET) {
-		snd_soc_write(codec, RT5663_MIC_DECRO_2,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
 			rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_3,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
 			rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
-		snd_soc_write(codec, RT5663_MIC_DECRO_5,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
 			rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_6,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
 			rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
 	} else {
-		snd_soc_write(codec, RT5663_MIC_DECRO_2,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
 			rt5663->imp_table[i].dc_offset_l_manual >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_3,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
 			rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
-		snd_soc_write(codec, RT5663_MIC_DECRO_5,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
 			rt5663->imp_table[i].dc_offset_r_manual >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_6,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
 			rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
 	}
 
-	reg84 = snd_soc_read(codec, RT5663_ASRC_2);
-	reg26 = snd_soc_read(codec, RT5663_STO1_ADC_MIXER);
-	reg2fa = snd_soc_read(codec, RT5663_DUMMY_1);
-	reg91 = snd_soc_read(codec, RT5663_HP_CHARGE_PUMP_1);
-	reg10 = snd_soc_read(codec, RT5663_RECMIX);
-	reg80 = snd_soc_read(codec, RT5663_GLB_CLK);
-
-	snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000, 0);
-	snd_soc_write(codec, RT5663_ASRC_2, 0);
-	snd_soc_write(codec, RT5663_STO1_ADC_MIXER, 0x4040);
-	snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+	reg84 = snd_soc_component_read32(component, RT5663_ASRC_2);
+	reg26 = snd_soc_component_read32(component, RT5663_STO1_ADC_MIXER);
+	reg2fa = snd_soc_component_read32(component, RT5663_DUMMY_1);
+	reg91 = snd_soc_component_read32(component, RT5663_HP_CHARGE_PUMP_1);
+	reg10 = snd_soc_component_read32(component, RT5663_RECMIX);
+	reg80 = snd_soc_component_read32(component, RT5663_GLB_CLK);
+
+	snd_soc_component_update_bits(component, RT5663_STO_DRE_1, 0x8000, 0);
+	snd_soc_component_write(component, RT5663_ASRC_2, 0);
+	snd_soc_component_write(component, RT5663_STO1_ADC_MIXER, 0x4040);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 		RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
 		RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
 		RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
 	usleep_range(10000, 10005);
-	snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 		RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
 		RT5663_PWR_FV1 | RT5663_PWR_FV2);
-	snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
+	snd_soc_component_update_bits(component, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
 		RT5663_SCLK_SRC_RCCLK);
-	snd_soc_update_bits(codec, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
+	snd_soc_component_update_bits(component, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
 		RT5663_DIG_25M_CLK_EN);
-	snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, RT5663_I2S_PD1_MASK, 0);
-	snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00);
-	snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc);
-	snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_1, 0x1232);
-	snd_soc_write(codec, RT5663_HP_LOGIC_2, 0x0005);
-	snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
-	snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0030);
-	snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0x0003);
-	snd_soc_update_bits(codec, RT5663_PWR_DIG_2,
+	snd_soc_component_update_bits(component, RT5663_ADDA_CLK_1, RT5663_I2S_PD1_MASK, 0);
+	snd_soc_component_write(component, RT5663_PRE_DIV_GATING_1, 0xff00);
+	snd_soc_component_write(component, RT5663_PRE_DIV_GATING_2, 0xfffc);
+	snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_1, 0x1232);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_2, 0x0005);
+	snd_soc_component_write(component, RT5663_DEPOP_2, 0x3003);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030, 0x0030);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003, 0x0003);
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_2,
 		RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F,
 		RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F);
-	snd_soc_update_bits(codec, RT5663_PWR_DIG_1,
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_1,
 		RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
 		RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
 		RT5663_PWR_ADC_R1,
@@ -1715,71 +1715,71 @@ static int rt5663_impedance_sensing(struct snd_soc_codec *codec)
 		RT5663_PWR_LDO_DACREF_ON | RT5663_PWR_ADC_L1 |
 		RT5663_PWR_ADC_R1);
 	msleep(40);
-	snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
 		RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2,
 		RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2);
 	msleep(30);
-	snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
-	snd_soc_write(codec, RT5663_STO_DAC_MIXER, 0);
-	snd_soc_write(codec, RT5663_BYPASS_STO_DAC, 0x000c);
-	snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
-	snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224);
-	snd_soc_write(codec, RT5663_HP_OUT_EN, 0x8088);
-	snd_soc_write(codec, RT5663_CHOP_ADC, 0x3000);
-	snd_soc_write(codec, RT5663_ADDA_RST, 0xc000);
-	snd_soc_write(codec, RT5663_STO1_HPF_ADJ1, 0x3320);
-	snd_soc_write(codec, RT5663_HP_CALIB_2, 0x00c9);
-	snd_soc_write(codec, RT5663_DUMMY_1, 0x004c);
-	snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7733);
-	snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
-	snd_soc_write(codec, RT5663_STO_DRE_9, 0x0007);
-	snd_soc_write(codec, RT5663_STO_DRE_10, 0x0007);
-	snd_soc_write(codec, RT5663_DUMMY_2, 0x02a4);
-	snd_soc_write(codec, RT5663_RECMIX, 0x0005);
-	snd_soc_write(codec, RT5663_HP_IMP_SEN_1, 0x4334);
-	snd_soc_update_bits(codec, RT5663_IRQ_3, 0x0004, 0x0004);
-	snd_soc_write(codec, RT5663_HP_LOGIC_1, 0x2200);
-	snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x3000);
-	snd_soc_write(codec, RT5663_HP_LOGIC_1, 0x6200);
+	snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+	snd_soc_component_write(component, RT5663_STO_DAC_MIXER, 0);
+	snd_soc_component_write(component, RT5663_BYPASS_STO_DAC, 0x000c);
+	snd_soc_component_write(component, RT5663_HP_BIAS, 0xafaa);
+	snd_soc_component_write(component, RT5663_CHARGE_PUMP_1, 0x2224);
+	snd_soc_component_write(component, RT5663_HP_OUT_EN, 0x8088);
+	snd_soc_component_write(component, RT5663_CHOP_ADC, 0x3000);
+	snd_soc_component_write(component, RT5663_ADDA_RST, 0xc000);
+	snd_soc_component_write(component, RT5663_STO1_HPF_ADJ1, 0x3320);
+	snd_soc_component_write(component, RT5663_HP_CALIB_2, 0x00c9);
+	snd_soc_component_write(component, RT5663_DUMMY_1, 0x004c);
+	snd_soc_component_write(component, RT5663_ANA_BIAS_CUR_1, 0x7733);
+	snd_soc_component_write(component, RT5663_CHARGE_PUMP_2, 0x7777);
+	snd_soc_component_write(component, RT5663_STO_DRE_9, 0x0007);
+	snd_soc_component_write(component, RT5663_STO_DRE_10, 0x0007);
+	snd_soc_component_write(component, RT5663_DUMMY_2, 0x02a4);
+	snd_soc_component_write(component, RT5663_RECMIX, 0x0005);
+	snd_soc_component_write(component, RT5663_HP_IMP_SEN_1, 0x4334);
+	snd_soc_component_update_bits(component, RT5663_IRQ_3, 0x0004, 0x0004);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_1, 0x2200);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x3000);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_1, 0x6200);
 
 	for (i = 0; i < 100; i++) {
 		msleep(20);
-		if (snd_soc_read(codec, RT5663_INT_ST_1) & 0x2)
+		if (snd_soc_component_read32(component, RT5663_INT_ST_1) & 0x2)
 			break;
 	}
 
-	value = snd_soc_read(codec, RT5663_HP_IMP_SEN_4);
+	value = snd_soc_component_read32(component, RT5663_HP_IMP_SEN_4);
 
-	snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0);
-	snd_soc_write(codec, RT5663_INT_ST_1, 0);
-	snd_soc_write(codec, RT5663_HP_LOGIC_1, 0);
-	snd_soc_update_bits(codec, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0);
+	snd_soc_component_write(component, RT5663_INT_ST_1, 0);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_1, 0);
+	snd_soc_component_update_bits(component, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
 		RT5663_DIG_25M_CLK_DIS);
-	snd_soc_write(codec, RT5663_GLB_CLK, reg80);
-	snd_soc_write(codec, RT5663_RECMIX, reg10);
-	snd_soc_write(codec, RT5663_DUMMY_2, 0x00a4);
-	snd_soc_write(codec, RT5663_DUMMY_1, reg2fa);
-	snd_soc_write(codec, RT5663_HP_CALIB_2, 0x00c8);
-	snd_soc_write(codec, RT5663_STO1_HPF_ADJ1, 0xb320);
-	snd_soc_write(codec, RT5663_ADDA_RST, 0xe400);
-	snd_soc_write(codec, RT5663_CHOP_ADC, 0x2000);
-	snd_soc_write(codec, RT5663_HP_OUT_EN, 0x0008);
-	snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+	snd_soc_component_write(component, RT5663_GLB_CLK, reg80);
+	snd_soc_component_write(component, RT5663_RECMIX, reg10);
+	snd_soc_component_write(component, RT5663_DUMMY_2, 0x00a4);
+	snd_soc_component_write(component, RT5663_DUMMY_1, reg2fa);
+	snd_soc_component_write(component, RT5663_HP_CALIB_2, 0x00c8);
+	snd_soc_component_write(component, RT5663_STO1_HPF_ADJ1, 0xb320);
+	snd_soc_component_write(component, RT5663_ADDA_RST, 0xe400);
+	snd_soc_component_write(component, RT5663_CHOP_ADC, 0x2000);
+	snd_soc_component_write(component, RT5663_HP_OUT_EN, 0x0008);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
 		RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2, 0);
-	snd_soc_update_bits(codec, RT5663_PWR_DIG_1,
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_1,
 		RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
 		RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
 		RT5663_PWR_ADC_R1, 0);
-	snd_soc_update_bits(codec, RT5663_PWR_DIG_2,
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_2,
 		RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F, 0);
-	snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0);
-	snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0);
-	snd_soc_write(codec, RT5663_HP_LOGIC_2, 0);
-	snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_1, reg91);
-	snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003, 0);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030, 0);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_2, 0);
+	snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_1, reg91);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 		RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK, 0);
-	snd_soc_write(codec, RT5663_STO1_ADC_MIXER, reg26);
-	snd_soc_write(codec, RT5663_ASRC_2, reg84);
+	snd_soc_component_write(component, RT5663_STO1_ADC_MIXER, reg26);
+	snd_soc_component_write(component, RT5663_ASRC_2, reg84);
 
 	for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
 		if (value >= rt5663->imp_table[i].imp_min &&
@@ -1787,42 +1787,42 @@ static int rt5663_impedance_sensing(struct snd_soc_codec *codec)
 			break;
 	}
 
-	snd_soc_update_bits(codec, RT5663_STO_DRE_9, RT5663_DRE_GAIN_HP_MASK,
+	snd_soc_component_update_bits(component, RT5663_STO_DRE_9, RT5663_DRE_GAIN_HP_MASK,
 		rt5663->imp_table[i].vol);
-	snd_soc_update_bits(codec, RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_MASK,
+	snd_soc_component_update_bits(component, RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_MASK,
 		rt5663->imp_table[i].vol);
 
 	if (rt5663->jack_type == SND_JACK_HEADSET) {
-		snd_soc_write(codec, RT5663_MIC_DECRO_2,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
 			rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_3,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
 			rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
-		snd_soc_write(codec, RT5663_MIC_DECRO_5,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
 			rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_6,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
 			rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
 	} else {
-		snd_soc_write(codec, RT5663_MIC_DECRO_2,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
 			rt5663->imp_table[i].dc_offset_l_manual >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_3,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
 			rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
-		snd_soc_write(codec, RT5663_MIC_DECRO_5,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
 			rt5663->imp_table[i].dc_offset_r_manual >> 16);
-		snd_soc_write(codec, RT5663_MIC_DECRO_6,
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
 			rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
 	}
 
 	return 0;
 }
 
-static int rt5663_button_detect(struct snd_soc_codec *codec)
+static int rt5663_button_detect(struct snd_soc_component *component)
 {
 	int btn_type, val;
 
-	val = snd_soc_read(codec, RT5663_IL_CMD_5);
-	dev_dbg(codec->dev, "%s: val=0x%x\n", __func__, val);
+	val = snd_soc_component_read32(component, RT5663_IL_CMD_5);
+	dev_dbg(component->dev, "%s: val=0x%x\n", __func__, val);
 	btn_type = val & 0xfff0;
-	snd_soc_write(codec, RT5663_IL_CMD_5, val);
+	snd_soc_component_write(component, RT5663_IL_CMD_5, val);
 
 	return btn_type;
 }
@@ -1840,10 +1840,10 @@ static irqreturn_t rt5663_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int rt5663_set_jack_detect(struct snd_soc_codec *codec,
+int rt5663_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hs_jack)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	rt5663->hs_jack = hs_jack;
 
@@ -1853,12 +1853,12 @@ int rt5663_set_jack_detect(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(rt5663_set_jack_detect);
 
-static bool rt5663_check_jd_status(struct snd_soc_codec *codec)
+static bool rt5663_check_jd_status(struct snd_soc_component *component)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
-	int val = snd_soc_read(codec, RT5663_INT_ST_1);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	int val = snd_soc_component_read32(component, RT5663_INT_ST_1);
 
-	dev_dbg(codec->dev, "%s val=%x\n", __func__, val);
+	dev_dbg(component->dev, "%s val=%x\n", __func__, val);
 
 	/* JD1 */
 	switch (rt5663->codec_ver) {
@@ -1867,7 +1867,7 @@ static bool rt5663_check_jd_status(struct snd_soc_codec *codec)
 	case CODEC_VER_0:
 		return !(val & 0x1000);
 	default:
-		dev_err(codec->dev, "Unknown CODEC Version\n");
+		dev_err(component->dev, "Unknown CODEC Version\n");
 	}
 
 	return false;
@@ -1877,28 +1877,28 @@ static void rt5663_jack_detect_work(struct work_struct *work)
 {
 	struct rt5663_priv *rt5663 =
 		container_of(work, struct rt5663_priv, jack_detect_work.work);
-	struct snd_soc_codec *codec = rt5663->codec;
+	struct snd_soc_component *component = rt5663->component;
 	int btn_type, report = 0;
 
-	if (!codec)
+	if (!component)
 		return;
 
-	if (rt5663_check_jd_status(codec)) {
+	if (rt5663_check_jd_status(component)) {
 		/* jack in */
 		if (rt5663->jack_type == 0) {
 			/* jack was out, report jack type */
 			switch (rt5663->codec_ver) {
 			case CODEC_VER_1:
 				report = rt5663_v2_jack_detect(
-						rt5663->codec, 1);
+						rt5663->component, 1);
 				break;
 			case CODEC_VER_0:
-				report = rt5663_jack_detect(rt5663->codec, 1);
+				report = rt5663_jack_detect(rt5663->component, 1);
 				if (rt5663->pdata.impedance_sensing_num)
-					rt5663_impedance_sensing(rt5663->codec);
+					rt5663_impedance_sensing(rt5663->component);
 				break;
 			default:
-				dev_err(codec->dev, "Unknown CODEC Version\n");
+				dev_err(component->dev, "Unknown CODEC Version\n");
 			}
 
 			/* Delay the jack insert report to avoid pop noise */
@@ -1906,7 +1906,7 @@ static void rt5663_jack_detect_work(struct work_struct *work)
 		} else {
 			/* jack is already in, report button event */
 			report = SND_JACK_HEADSET;
-			btn_type = rt5663_button_detect(rt5663->codec);
+			btn_type = rt5663_button_detect(rt5663->component);
 			/**
 			 * rt5663 can report three kinds of button behavior,
 			 * one click, double click and hold. However,
@@ -1939,7 +1939,7 @@ static void rt5663_jack_detect_work(struct work_struct *work)
 				break;
 			default:
 				btn_type = 0;
-				dev_err(rt5663->codec->dev,
+				dev_err(rt5663->component->dev,
 					"Unexpected button code 0x%04x\n",
 					btn_type);
 				break;
@@ -1959,16 +1959,16 @@ static void rt5663_jack_detect_work(struct work_struct *work)
 		/* jack out */
 		switch (rt5663->codec_ver) {
 		case CODEC_VER_1:
-			report = rt5663_v2_jack_detect(rt5663->codec, 0);
+			report = rt5663_v2_jack_detect(rt5663->component, 0);
 			break;
 		case CODEC_VER_0:
-			report = rt5663_jack_detect(rt5663->codec, 0);
+			report = rt5663_jack_detect(rt5663->component, 0);
 			break;
 		default:
-			dev_err(codec->dev, "Unknown CODEC Version\n");
+			dev_err(component->dev, "Unknown CODEC Version\n");
 		}
 	}
-	dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report);
+	dev_dbg(component->dev, "%s jack report: 0x%04x\n", __func__, report);
 	snd_soc_jack_report(rt5663->hs_jack, report, SND_JACK_HEADSET |
 			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
@@ -1978,22 +1978,22 @@ static void rt5663_jd_unplug_work(struct work_struct *work)
 {
 	struct rt5663_priv *rt5663 =
 		container_of(work, struct rt5663_priv, jd_unplug_work.work);
-	struct snd_soc_codec *codec = rt5663->codec;
+	struct snd_soc_component *component = rt5663->component;
 
-	if (!codec)
+	if (!component)
 		return;
 
-	if (!rt5663_check_jd_status(codec)) {
+	if (!rt5663_check_jd_status(component)) {
 		/* jack out */
 		switch (rt5663->codec_ver) {
 		case CODEC_VER_1:
-			rt5663_v2_jack_detect(rt5663->codec, 0);
+			rt5663_v2_jack_detect(rt5663->component, 0);
 			break;
 		case CODEC_VER_0:
-			rt5663_jack_detect(rt5663->codec, 0);
+			rt5663_jack_detect(rt5663->component, 0);
 			break;
 		default:
-			dev_err(codec->dev, "Unknown CODEC Version\n");
+			dev_err(component->dev, "Unknown CODEC Version\n");
 		}
 
 		snd_soc_jack_report(rt5663->hs_jack, 0, SND_JACK_HEADSET |
@@ -2047,9 +2047,9 @@ static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
 	struct snd_soc_dapm_widget *sink)
 {
 	unsigned int val;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
-	val = snd_soc_read(codec, RT5663_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5663_GLB_CLK);
 	val &= RT5663_SCLK_SRC_MASK;
 	if (val == RT5663_SCLK_SRC_PLL1)
 		return 1;
@@ -2061,8 +2061,8 @@ static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,
 	struct snd_soc_dapm_widget *sink)
 {
 	unsigned int reg, shift, val;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	if (rt5663->codec_ver == CODEC_VER_1) {
 		switch (w->shift) {
@@ -2092,7 +2092,7 @@ static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,
 		}
 	}
 
-	val = (snd_soc_read(codec, reg) >> shift) & 0x7;
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0x7;
 
 	if (val)
 		return 1;
@@ -2103,23 +2103,23 @@ static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,
 static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,
 	struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	int da_asrc_en, ad_asrc_en;
 
-	da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &
+	da_asrc_en = (snd_soc_component_read32(component, RT5663_ASRC_2) &
 		RT5663_DA_STO1_TRACK_MASK) ? 1 : 0;
 	switch (rt5663->codec_ver) {
 	case CODEC_VER_1:
-		ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_3) &
+		ad_asrc_en = (snd_soc_component_read32(component, RT5663_ASRC_3) &
 			RT5663_V2_AD_STO1_TRACK_MASK) ? 1 : 0;
 		break;
 	case CODEC_VER_0:
-		ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &
+		ad_asrc_en = (snd_soc_component_read32(component, RT5663_ASRC_2) &
 			RT5663_AD_STO1_TRACK_MASK) ? 1 : 0;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown CODEC Version\n");
+		dev_err(component->dev, "Unknown CODEC Version\n");
 		return 1;
 	}
 
@@ -2127,14 +2127,14 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,
 		if (rt5663->sysclk > rt5663->lrck * 384)
 			return 1;
 
-	dev_err(codec->dev, "sysclk < 384 x fs, disable i2s asrc\n");
+	dev_err(component->dev, "sysclk < 384 x fs, disable i2s asrc\n");
 
 	return 0;
 }
 
 /**
  * rt5663_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @filter_mask: mask of filters.
  * @clk_src: clock source
  *
@@ -2146,10 +2146,10 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,
  * set of filters specified by the mask. And the codec driver will turn on ASRC
  * for these filters if ASRC is selected as their clock source.
  */
-int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5663_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	unsigned int asrc2_mask = 0;
 	unsigned int asrc2_value = 0;
 	unsigned int asrc3_mask = 0;
@@ -2180,16 +2180,16 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,
 			asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT;
 			break;
 		default:
-			dev_err(codec->dev, "Unknown CODEC Version\n");
+			dev_err(component->dev, "Unknown CODEC Version\n");
 		}
 	}
 
 	if (asrc2_mask)
-		snd_soc_update_bits(codec, RT5663_ASRC_2, asrc2_mask,
+		snd_soc_component_update_bits(component, RT5663_ASRC_2, asrc2_mask,
 			asrc2_value);
 
 	if (asrc3_mask)
-		snd_soc_update_bits(codec, RT5663_ASRC_3, asrc3_mask,
+		snd_soc_component_update_bits(component, RT5663_ASRC_3, asrc3_mask,
 			asrc3_value);
 
 	return 0;
@@ -2295,42 +2295,42 @@ static const struct snd_kcontrol_new rt5663_alg_dacr_mux =
 static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		if (rt5663->codec_ver == CODEC_VER_1) {
-			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_SEL_PM_HP_SHIFT, RT5663_SEL_PM_HP_HIGH);
-			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2,
+			snd_soc_component_update_bits(component, RT5663_HP_LOGIC_2,
 				RT5663_HP_SIG_SRC1_MASK,
 				RT5663_HP_SIG_SRC1_SILENCE);
 		} else {
-			snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
-			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+			snd_soc_component_write(component, RT5663_DEPOP_2, 0x3003);
+			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);
-			snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
-			snd_soc_write(codec, RT5663_HP_BIAS, 0xabba);
-			snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224);
-			snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766);
-			snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
-			snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
-			snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000,
+			snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+			snd_soc_component_write(component, RT5663_HP_BIAS, 0xabba);
+			snd_soc_component_write(component, RT5663_CHARGE_PUMP_1, 0x2224);
+			snd_soc_component_write(component, RT5663_ANA_BIAS_CUR_1, 0x7766);
+			snd_soc_component_write(component, RT5663_HP_BIAS, 0xafaa);
+			snd_soc_component_write(component, RT5663_CHARGE_PUMP_2, 0x7777);
+			snd_soc_component_update_bits(component, RT5663_STO_DRE_1, 0x8000,
 				0x8000);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000,
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000,
 				0x3000);
 		}
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 		if (rt5663->codec_ver == CODEC_VER_1) {
-			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2,
+			snd_soc_component_update_bits(component, RT5663_HP_LOGIC_2,
 				RT5663_HP_SIG_SRC1_MASK,
 				RT5663_HP_SIG_SRC1_REG);
 		} else {
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0);
-			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1,
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x0);
+			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
 				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
 		}
 		break;
@@ -2345,23 +2345,23 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (rt5663->codec_ver == CODEC_VER_0) {
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030,
 				0x0030);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003,
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003,
 				0x0003);
 		}
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		if (rt5663->codec_ver == CODEC_VER_0) {
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0);
-			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0);
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003, 0);
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030, 0);
 		}
 		break;
 
@@ -2375,17 +2375,17 @@ static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w,
 static int rt5663_bst2_power(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
 			RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK,
 			RT5663_PWR_BST2 | RT5663_PWR_BST2_OP);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
 			RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, 0);
 		break;
 
@@ -2399,17 +2399,17 @@ static int rt5663_bst2_power(struct snd_soc_dapm_widget *w,
 static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00);
-		snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc);
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_1, 0xff00);
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_2, 0xfffc);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0x0000);
-		snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0x0000);
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_1, 0x0000);
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_2, 0x0000);
 		break;
 
 	default:
@@ -2731,8 +2731,8 @@ static const struct snd_soc_dapm_route rt5663_specific_dapm_routes[] = {
 static int rt5663_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0;
 	int pre_div;
 
@@ -2743,7 +2743,7 @@ static int rt5663_hw_params(struct snd_pcm_substream *substream,
 
 	pre_div = rl6231_get_clk_info(rt5663->sysclk, rt5663->lrck);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
 			rt5663->lrck, dai->id);
 		return -EINVAL;
 	}
@@ -2767,10 +2767,10 @@ static int rt5663_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5663_I2S1_SDP,
+	snd_soc_component_update_bits(component, RT5663_I2S1_SDP,
 		RT5663_I2S_DL_MASK, val_len);
 
-	snd_soc_update_bits(codec, RT5663_ADDA_CLK_1,
+	snd_soc_component_update_bits(component, RT5663_ADDA_CLK_1,
 		RT5663_I2S_PD1_MASK, pre_div << RT5663_I2S_PD1_SHIFT);
 
 	return 0;
@@ -2778,7 +2778,7 @@ static int rt5663_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -2817,7 +2817,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5663_I2S_MS_MASK |
+	snd_soc_component_update_bits(component, RT5663_I2S1_SDP, RT5663_I2S_MS_MASK |
 		RT5663_I2S_BP_MASK | RT5663_I2S_DF_MASK, reg_val);
 
 	return 0;
@@ -2826,8 +2826,8 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5663->sysclk && clk_id == rt5663->sysclk_src)
@@ -2844,15 +2844,15 @@ static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 		reg_val |= RT5663_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
+	snd_soc_component_update_bits(component, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
 		reg_val);
 	rt5663->sysclk = freq;
 	rt5663->sysclk_src = clk_id;
 
-	dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n",
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
 		freq, clk_id);
 
 	return 0;
@@ -2861,8 +2861,8 @@ static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 	int mask, shift, val;
@@ -2872,11 +2872,11 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5663->pll_in = 0;
 		rt5663->pll_out = 0;
-		snd_soc_update_bits(codec, RT5663_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5663_GLB_CLK,
 			RT5663_SCLK_SRC_MASK, RT5663_SCLK_SRC_MCLK);
 		return 0;
 	}
@@ -2891,7 +2891,7 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		shift = RT5663_PLL1_SRC_SHIFT;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown CODEC Version\n");
+		dev_err(component->dev, "Unknown CODEC Version\n");
 		return -EINVAL;
 	}
 
@@ -2903,24 +2903,24 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		val = 0x1;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5663_GLB_CLK, mask, (val << shift));
+	snd_soc_component_update_bits(component, RT5663_GLB_CLK, mask, (val << shift));
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", pll_code.m_bp,
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n", pll_code.m_bp,
 		(pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code,
 		pll_code.k_code);
 
-	snd_soc_write(codec, RT5663_PLL_1,
+	snd_soc_component_write(component, RT5663_PLL_1,
 		pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code);
-	snd_soc_write(codec, RT5663_PLL_2,
+	snd_soc_component_write(component, RT5663_PLL_2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT |
 		pll_code.m_bp << RT5663_PLL_M_BP_SHIFT);
 
@@ -2934,8 +2934,8 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0, reg;
 
 	if (rx_mask || tx_mask)
@@ -2987,11 +2987,11 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		reg = RT5663_TDM_1;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown CODEC Version\n");
+		dev_err(component->dev, "Unknown CODEC Version\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg, RT5663_TDM_MODE_MASK |
+	snd_soc_component_update_bits(component, reg, RT5663_TDM_MODE_MASK |
 		RT5663_TDM_IN_CH_MASK | RT5663_TDM_OUT_CH_MASK |
 		RT5663_TDM_IN_LEN_MASK | RT5663_TDM_OUT_LEN_MASK, val);
 
@@ -3000,11 +3000,11 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
 static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 
-	dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio = %d\n", __func__, ratio);
 
 	if (rt5663->codec_ver == CODEC_VER_1)
 		reg = RT5663_TDM_9;
@@ -3013,51 +3013,51 @@ static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 
 	switch (ratio) {
 	case 32:
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 			RT5663_TDM_LENGTN_MASK,
 			RT5663_TDM_LENGTN_16);
 		break;
 	case 40:
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 			RT5663_TDM_LENGTN_MASK,
 			RT5663_TDM_LENGTN_20);
 		break;
 	case 48:
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 			RT5663_TDM_LENGTN_MASK,
 			RT5663_TDM_LENGTN_24);
 		break;
 	case 64:
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 			RT5663_TDM_LENGTN_MASK,
 			RT5663_TDM_LENGTN_32);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid ratio!\n");
+		dev_err(component->dev, "Invalid ratio!\n");
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int rt5663_set_bias_level(struct snd_soc_codec *codec,
+static int rt5663_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
 			RT5663_PWR_FV1 | RT5663_PWR_FV2);
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
 		if (rt5663->codec_ver == CODEC_VER_1) {
-			snd_soc_update_bits(codec, RT5663_DIG_MISC,
+			snd_soc_component_update_bits(component, RT5663_DIG_MISC,
 				RT5663_DIG_GATE_CTRL_MASK,
 				RT5663_DIG_GATE_CTRL_EN);
-			snd_soc_update_bits(codec, RT5663_SIG_CLK_DET,
+			snd_soc_component_update_bits(component, RT5663_SIG_CLK_DET,
 				RT5663_EN_ANA_CLK_DET_MASK |
 				RT5663_PWR_CLK_DET_MASK,
 				RT5663_EN_ANA_CLK_DET_AUTO |
@@ -3067,17 +3067,17 @@ static int rt5663_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		if (rt5663->codec_ver == CODEC_VER_1)
-			snd_soc_update_bits(codec, RT5663_DIG_MISC,
+			snd_soc_component_update_bits(component, RT5663_DIG_MISC,
 				RT5663_DIG_GATE_CTRL_MASK,
 				RT5663_DIG_GATE_CTRL_DIS);
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
 			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK |
 			RT5663_PWR_MB_MASK, RT5663_PWR_VREF1 |
 			RT5663_PWR_VREF2 | RT5663_PWR_MB);
 		usleep_range(10000, 10005);
 		if (rt5663->codec_ver == CODEC_VER_1) {
-			snd_soc_update_bits(codec, RT5663_SIG_CLK_DET,
+			snd_soc_component_update_bits(component, RT5663_SIG_CLK_DET,
 				RT5663_EN_ANA_CLK_DET_MASK |
 				RT5663_PWR_CLK_DET_MASK,
 				RT5663_EN_ANA_CLK_DET_DIS |
@@ -3086,7 +3086,7 @@ static int rt5663_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
 			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
 			RT5663_PWR_FV1 | RT5663_PWR_FV2, 0x0);
 		break;
@@ -3098,12 +3098,12 @@ static int rt5663_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5663_probe(struct snd_soc_codec *codec)
+static int rt5663_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
-	rt5663->codec = codec;
+	rt5663->component = component;
 
 	switch (rt5663->codec_ver) {
 	case CODEC_VER_1:
@@ -3113,7 +3113,7 @@ static int rt5663_probe(struct snd_soc_codec *codec)
 		snd_soc_dapm_add_routes(dapm,
 			rt5663_v2_specific_dapm_routes,
 			ARRAY_SIZE(rt5663_v2_specific_dapm_routes));
-		snd_soc_add_codec_controls(codec, rt5663_v2_specific_controls,
+		snd_soc_add_component_controls(component, rt5663_v2_specific_controls,
 			ARRAY_SIZE(rt5663_v2_specific_controls));
 		break;
 	case CODEC_VER_0:
@@ -3123,11 +3123,11 @@ static int rt5663_probe(struct snd_soc_codec *codec)
 		snd_soc_dapm_add_routes(dapm,
 			rt5663_specific_dapm_routes,
 			ARRAY_SIZE(rt5663_specific_dapm_routes));
-		snd_soc_add_codec_controls(codec, rt5663_specific_controls,
+		snd_soc_add_component_controls(component, rt5663_specific_controls,
 			ARRAY_SIZE(rt5663_specific_controls));
 
 		if (!rt5663->imp_table)
-			snd_soc_add_codec_controls(codec, rt5663_hpvol_controls,
+			snd_soc_add_component_controls(component, rt5663_hpvol_controls,
 				ARRAY_SIZE(rt5663_hpvol_controls));
 		break;
 	}
@@ -3135,19 +3135,17 @@ static int rt5663_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5663_remove(struct snd_soc_codec *codec)
+static void rt5663_remove(struct snd_soc_component *component)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	regmap_write(rt5663->regmap, RT5663_RESET, 0);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt5663_suspend(struct snd_soc_codec *codec)
+static int rt5663_suspend(struct snd_soc_component *component)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5663->regmap, true);
 	regcache_mark_dirty(rt5663->regmap);
@@ -3155,9 +3153,9 @@ static int rt5663_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5663_resume(struct snd_soc_codec *codec)
+static int rt5663_resume(struct snd_soc_component *component)
 {
-	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5663->regmap, false);
 	regcache_sync(rt5663->regmap);
@@ -3206,21 +3204,22 @@ static struct snd_soc_dai_driver rt5663_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5663 = {
-	.probe = rt5663_probe,
-	.remove = rt5663_remove,
-	.suspend = rt5663_suspend,
-	.resume = rt5663_resume,
-	.set_bias_level = rt5663_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls = rt5663_snd_controls,
-		.num_controls = ARRAY_SIZE(rt5663_snd_controls),
-		.dapm_widgets = rt5663_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(rt5663_dapm_widgets),
-		.dapm_routes = rt5663_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(rt5663_dapm_routes),
-	}
+static const struct snd_soc_component_driver soc_component_dev_rt5663 = {
+	.probe			= rt5663_probe,
+	.remove			= rt5663_remove,
+	.suspend		= rt5663_suspend,
+	.resume			= rt5663_resume,
+	.set_bias_level		= rt5663_set_bias_level,
+	.controls		= rt5663_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5663_snd_controls),
+	.dapm_widgets		= rt5663_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5663_dapm_widgets),
+	.dapm_routes		= rt5663_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5663_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
 };
 
 static const struct regmap_config rt5663_v2_regmap = {
@@ -3610,7 +3609,8 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
 				__func__, ret);
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5663,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5663,
 			rt5663_dai, ARRAY_SIZE(rt5663_dai));
 
 	if (ret) {
@@ -3628,8 +3628,6 @@ static int rt5663_i2c_remove(struct i2c_client *i2c)
 	if (i2c->irq)
 		free_irq(i2c->irq, rt5663);
 
-	snd_soc_unregister_codec(&i2c->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
index 03adc8004ba9..865203cc2034 100644
--- a/sound/soc/codecs/rt5663.h
+++ b/sound/soc/codecs/rt5663.h
@@ -1125,9 +1125,9 @@ enum {
 	RT5663_AD_STEREO_FILTER = 0x2,
 };
 
-int rt5663_set_jack_detect(struct snd_soc_codec *codec,
+int rt5663_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hs_jack);
-int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5663_sel_asrc_clk_src(struct snd_soc_component *component,
 	unsigned int filter_mask, unsigned int clk_src);
 
 #endif /* __RT5663_H__ */
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index f05d362c4e23..6ba99f5ed3f4 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -44,7 +44,7 @@ static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = {
 };
 
 struct rt5665_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5665_platform_data pdata;
 	struct regmap *regmap;
 	struct gpio_desc *gpiod_ldo1_en;
@@ -1000,13 +1000,13 @@ static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux =
 static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
-	if (snd_soc_read(codec, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) {
-		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+	if (snd_soc_component_read32(component, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) {
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
-		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
 	}
 
@@ -1016,13 +1016,13 @@ static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol,
 static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
-	if (snd_soc_read(codec, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) {
-		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+	if (snd_soc_component_read32(component, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) {
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
-		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
 	}
 
@@ -1031,7 +1031,7 @@ static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
 
 /**
  * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @filter_mask: mask of filters.
  * @clk_src: clock source
  *
@@ -1043,7 +1043,7 @@ static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
  * set of filters specified by the mask. And the codec driver will turn on ASRC
  * for these filters if ASRC is selected as their clock source.
  */
-int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5665_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src)
 {
 	unsigned int asrc2_mask = 0;
@@ -1114,63 +1114,63 @@ int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec,
 	}
 
 	if (asrc2_mask)
-		snd_soc_update_bits(codec, RT5665_ASRC_2,
+		snd_soc_component_update_bits(component, RT5665_ASRC_2,
 			asrc2_mask, asrc2_value);
 
 	if (asrc3_mask)
-		snd_soc_update_bits(codec, RT5665_ASRC_3,
+		snd_soc_component_update_bits(component, RT5665_ASRC_3,
 			asrc3_mask, asrc3_value);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src);
 
-static int rt5665_button_detect(struct snd_soc_codec *codec)
+static int rt5665_button_detect(struct snd_soc_component *component)
 {
 	int btn_type, val;
 
-	val = snd_soc_read(codec, RT5665_4BTN_IL_CMD_1);
+	val = snd_soc_component_read32(component, RT5665_4BTN_IL_CMD_1);
 	btn_type = val & 0xfff0;
-	snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, val);
+	snd_soc_component_write(component, RT5665_4BTN_IL_CMD_1, val);
 
 	return btn_type;
 }
 
-static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec,
+static void rt5665_enable_push_button_irq(struct snd_soc_component *component,
 	bool enable)
 {
 	if (enable) {
-		snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x0003);
-		snd_soc_update_bits(codec, RT5665_SAR_IL_CMD_9, 0x1, 0x1);
-		snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048);
-		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
+		snd_soc_component_write(component, RT5665_4BTN_IL_CMD_1, 0x0003);
+		snd_soc_component_update_bits(component, RT5665_SAR_IL_CMD_9, 0x1, 0x1);
+		snd_soc_component_write(component, RT5665_IL_CMD_1, 0x0048);
+		snd_soc_component_update_bits(component, RT5665_4BTN_IL_CMD_2,
 				RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK,
 				RT5665_4BTN_IL_EN | RT5665_4BTN_IL_NOR);
-		snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3,
+		snd_soc_component_update_bits(component, RT5665_IRQ_CTRL_3,
 				RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_EN);
 	} else {
-		snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3,
+		snd_soc_component_update_bits(component, RT5665_IRQ_CTRL_3,
 				RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_DIS);
-		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
+		snd_soc_component_update_bits(component, RT5665_4BTN_IL_CMD_2,
 				RT5665_4BTN_IL_MASK, RT5665_4BTN_IL_DIS);
-		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
+		snd_soc_component_update_bits(component, RT5665_4BTN_IL_CMD_2,
 				RT5665_4BTN_IL_RST_MASK, RT5665_4BTN_IL_RST);
 	}
 }
 
 /**
  * rt5665_headset_detect - Detect headset.
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @jack_insert: Jack insert or not.
  *
  * Detect whether is headset or not when jack inserted.
  *
  * Returns detect status.
  */
-static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5665_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	unsigned int sar_hs_type, val;
 
 	if (jack_insert) {
@@ -1201,7 +1201,7 @@ static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 
 		usleep_range(10000, 15000);
 
-		rt5665->sar_adc_value = snd_soc_read(rt5665->codec,
+		rt5665->sar_adc_value = snd_soc_component_read32(rt5665->component,
 			RT5665_SAR_IL_CMD_4) & 0x7ff;
 
 		sar_hs_type = rt5665->pdata.sar_hs_type ?
@@ -1209,7 +1209,7 @@ static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 
 		if (rt5665->sar_adc_value > sar_hs_type) {
 			rt5665->jack_type = SND_JACK_HEADSET;
-			rt5665_enable_push_button_irq(codec, true);
+			rt5665_enable_push_button_irq(component, true);
 			} else {
 			rt5665->jack_type = SND_JACK_HEADPHONE;
 			regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1,
@@ -1225,11 +1225,11 @@ static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
 		snd_soc_dapm_sync(dapm);
 		if (rt5665->jack_type == SND_JACK_HEADSET)
-			rt5665_enable_push_button_irq(codec, false);
+			rt5665_enable_push_button_irq(component, false);
 		rt5665->jack_type = 0;
 	}
 
-	dev_dbg(codec->dev, "jack_type = %d\n", rt5665->jack_type);
+	dev_dbg(component->dev, "jack_type = %d\n", rt5665->jack_type);
 	return rt5665->jack_type;
 }
 
@@ -1248,9 +1248,9 @@ static void rt5665_jd_check_handler(struct work_struct *work)
 	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
 		jd_check_work.work);
 
-	if (snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010) {
+	if (snd_soc_component_read32(rt5665->component, RT5665_AJD1_CTRL) & 0x0010) {
 		/* jack out */
-		rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0);
+		rt5665->jack_type = rt5665_headset_detect(rt5665->component, 0);
 
 		snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type,
 				SND_JACK_HEADSET |
@@ -1261,10 +1261,10 @@ static void rt5665_jd_check_handler(struct work_struct *work)
 	}
 }
 
-static int rt5665_set_jack_detect(struct snd_soc_codec *codec,
+static int rt5665_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *hs_jack, void *data)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
 	switch (rt5665->pdata.jd_src) {
 	case RT5665_JD1:
@@ -1281,7 +1281,7 @@ static int rt5665_set_jack_detect(struct snd_soc_codec *codec,
 		break;
 
 	default:
-		dev_warn(codec->dev, "Wrong JD source\n");
+		dev_warn(component->dev, "Wrong JD source\n");
 		break;
 	}
 
@@ -1296,12 +1296,12 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
 		container_of(work, struct rt5665_priv, jack_detect_work.work);
 	int val, btn_type;
 
-	while (!rt5665->codec) {
+	while (!rt5665->component) {
 		pr_debug("%s codec = null\n", __func__);
 		usleep_range(10000, 15000);
 	}
 
-	while (!rt5665->codec->component.card->instantiated) {
+	while (!rt5665->component->card->instantiated) {
 		pr_debug("%s\n", __func__);
 		usleep_range(10000, 15000);
 	}
@@ -1313,17 +1313,17 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
 
 	mutex_lock(&rt5665->calibrate_mutex);
 
-	val = snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010;
+	val = snd_soc_component_read32(rt5665->component, RT5665_AJD1_CTRL) & 0x0010;
 	if (!val) {
 		/* jack in */
 		if (rt5665->jack_type == 0) {
 			/* jack was out, report jack type */
 			rt5665->jack_type =
-				rt5665_headset_detect(rt5665->codec, 1);
+				rt5665_headset_detect(rt5665->component, 1);
 		} else {
 			/* jack is already in, report button event */
 			rt5665->jack_type = SND_JACK_HEADSET;
-			btn_type = rt5665_button_detect(rt5665->codec);
+			btn_type = rt5665_button_detect(rt5665->component);
 			/**
 			 * rt5665 can report three kinds of button behavior,
 			 * one click, double click and hold. However,
@@ -1356,7 +1356,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
 				break;
 			default:
 				btn_type = 0;
-				dev_err(rt5665->codec->dev,
+				dev_err(rt5665->component->dev,
 					"Unexpected button code 0x%04x\n",
 					btn_type);
 				break;
@@ -1364,7 +1364,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
 		}
 	} else {
 		/* jack out */
-		rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0);
+		rt5665->jack_type = rt5665_headset_detect(rt5665->component, 0);
 	}
 
 	snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type,
@@ -1479,8 +1479,8 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 	int pd, idx = -EINVAL;
 
 	pd = rl6231_get_pre_div(rt5665->regmap,
@@ -1488,9 +1488,9 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	idx = rl6231_calc_dmic_clk(rt5665->sysclk / pd);
 
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else {
-		snd_soc_update_bits(codec, RT5665_DMIC_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_DMIC_CTRL_1,
 			RT5665_DMIC_CLK_MASK, idx << RT5665_DMIC_CLK_SFT);
 	}
 	return idx;
@@ -1499,16 +1499,16 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int rt5665_charge_pump_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, RT5665_HP_CHARGE_PUMP_1,
 			RT5665_PM_HP_MASK | RT5665_OSW_L_MASK,
 			RT5665_PM_HP_HV | RT5665_OSW_L_EN);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, RT5665_HP_CHARGE_PUMP_1,
 			RT5665_PM_HP_MASK | RT5665_OSW_L_MASK,
 			RT5665_PM_HP_LV | RT5665_OSW_L_DIS);
 		break;
@@ -1523,9 +1523,9 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
 			 struct snd_soc_dapm_widget *sink)
 {
 	unsigned int val;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
-	val = snd_soc_read(codec, RT5665_GLB_CLK);
+	val = snd_soc_component_read32(component, RT5665_GLB_CLK);
 	val &= RT5665_SCLK_SRC_MASK;
 	if (val == RT5665_SCLK_SRC_PLL1)
 		return 1;
@@ -1537,7 +1537,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *w,
 			 struct snd_soc_dapm_widget *sink)
 {
 	unsigned int reg, shift, val;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (w->shift) {
 	case RT5665_ADC_MONO_R_ASRC_SFT:
@@ -1576,13 +1576,13 @@ static int is_using_asrc(struct snd_soc_dapm_widget *w,
 		return 0;
 	}
 
-	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
 	switch (val) {
 	case RT5665_CLK_SEL_I2S1_ASRC:
 	case RT5665_CLK_SEL_I2S2_ASRC:
 	case RT5665_CLK_SEL_I2S3_ASRC:
 		/* I2S_Pre_Div1 should be 1 in asrc mode */
-		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
 			RT5665_I2S_PD1_MASK, RT5665_I2S_PD1_2);
 		return 1;
 	default:
@@ -2474,24 +2474,24 @@ static const struct snd_kcontrol_new pdm_r_switch =
 static int rt5665_mono_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
-		snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
+		snd_soc_component_update_bits(component, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
 			0x0);
-		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0x10);
-		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0x20);
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x10, 0x10);
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x20, 0x20);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0);
-		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0);
-		snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x20, 0);
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x10, 0);
+		snd_soc_component_update_bits(component, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
 			0x40);
-		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
 		break;
 
@@ -2506,18 +2506,18 @@ static int rt5665_mono_event(struct snd_soc_dapm_widget *w,
 static int rt5665_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
-		snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0003);
+		snd_soc_component_write(component, RT5665_HP_LOGIC_CTRL_2, 0x0003);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0002);
-		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+		snd_soc_component_write(component, RT5665_HP_LOGIC_CTRL_2, 0x0002);
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
 			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
 		break;
 
@@ -2532,16 +2532,16 @@ static int rt5665_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5665_lout_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5665_DEPOP_1,
+		snd_soc_component_update_bits(component, RT5665_DEPOP_1,
 			RT5665_PUMP_EN, RT5665_PUMP_EN);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5665_DEPOP_1,
+		snd_soc_component_update_bits(component, RT5665_DEPOP_1,
 			RT5665_PUMP_EN, 0);
 		break;
 
@@ -2572,23 +2572,23 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
 static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		switch (w->shift) {
 		case RT5665_PWR_VREF1_BIT:
-			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
 				RT5665_PWR_FV1, 0);
 			break;
 
 		case RT5665_PWR_VREF2_BIT:
-			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
 				RT5665_PWR_FV2, 0);
 			break;
 
 		case RT5665_PWR_VREF3_BIT:
-			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
 				RT5665_PWR_FV3, 0);
 			break;
 
@@ -2601,17 +2601,17 @@ static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
 		usleep_range(15000, 20000);
 		switch (w->shift) {
 		case RT5665_PWR_VREF1_BIT:
-			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
 				RT5665_PWR_FV1, RT5665_PWR_FV1);
 			break;
 
 		case RT5665_PWR_VREF2_BIT:
-			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
 				RT5665_PWR_FV2, RT5665_PWR_FV2);
 			break;
 
 		case RT5665_PWR_VREF3_BIT:
-			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
 				RT5665_PWR_FV3, RT5665_PWR_FV3);
 			break;
 
@@ -2630,7 +2630,7 @@ static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
 static int rt5665_i2s_pin_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int val1, val2, mask1 = 0, mask2 = 0;
 
 	switch (w->shift) {
@@ -2660,18 +2660,18 @@ static int rt5665_i2s_pin_event(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (mask1)
-			snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1,
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_1,
 					    mask1, val1);
 		if (mask2)
-			snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2,
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_2,
 					    mask2, val2);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		if (mask1)
-			snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1,
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_1,
 					    mask1, 0);
 		if (mask2)
-			snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2,
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_2,
 					    mask2, 0);
 		break;
 	default:
@@ -4052,7 +4052,7 @@ static const struct snd_soc_dapm_route rt5665_dapm_routes[] = {
 static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val = 0;
 
 	if (rx_mask || tx_mask)
@@ -4096,7 +4096,7 @@ static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5665_TDM_CTRL_1,
+	snd_soc_component_update_bits(component, RT5665_TDM_CTRL_1,
 		RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK |
 		RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK |
 		RT5665_TDM_OUT_LEN_MASK, val);
@@ -4108,24 +4108,24 @@ static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int rt5665_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, reg_clk, mask_clk, val_bits = 0x0100;
 	int pre_div, frame_size;
 
 	rt5665->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_warn(codec->dev, "Force using PLL");
-		snd_soc_codec_set_pll(codec, 0, RT5665_PLL1_S_MCLK,
+		dev_warn(component->dev, "Force using PLL");
+		snd_soc_component_set_pll(component, 0, RT5665_PLL1_S_MCLK,
 			rt5665->sysclk,	rt5665->lrck[dai->id] * 512);
-		snd_soc_codec_set_sysclk(codec, RT5665_SCLK_S_PLL1, 0,
+		snd_soc_component_set_sysclk(component, RT5665_SCLK_S_PLL1, 0,
 			rt5665->lrck[dai->id] * 512, 0);
 		pre_div = 1;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 
@@ -4160,7 +4160,7 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
 		reg_clk = RT5665_ADDA_CLK_1;
 		mask_clk = RT5665_I2S_PD1_MASK;
 		val_clk = pre_div << RT5665_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5665_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5665_I2S1_SDP,
 			RT5665_I2S_DL_MASK, val_len);
 		break;
 	case RT5665_AIF2_1:
@@ -4168,48 +4168,48 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
 		reg_clk = RT5665_ADDA_CLK_2;
 		mask_clk = RT5665_I2S_PD2_MASK;
 		val_clk = pre_div << RT5665_I2S_PD2_SFT;
-		snd_soc_update_bits(codec, RT5665_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5665_I2S2_SDP,
 			RT5665_I2S_DL_MASK, val_len);
 		break;
 	case RT5665_AIF3:
 		reg_clk = RT5665_ADDA_CLK_2;
 		mask_clk = RT5665_I2S_PD3_MASK;
 		val_clk = pre_div << RT5665_I2S_PD3_SFT;
-		snd_soc_update_bits(codec, RT5665_I2S3_SDP,
+		snd_soc_component_update_bits(component, RT5665_I2S3_SDP,
 			RT5665_I2S_DL_MASK, val_len);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg_clk, mask_clk, val_clk);
-	snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits);
+	snd_soc_component_update_bits(component, reg_clk, mask_clk, val_clk);
+	snd_soc_component_update_bits(component, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits);
 
 	switch (rt5665->lrck[dai->id]) {
 	case 192000:
-		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
 			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
 			RT5665_DAC_OSR_32 | RT5665_ADC_OSR_32);
 		break;
 	case 96000:
-		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
 			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
 			RT5665_DAC_OSR_64 | RT5665_ADC_OSR_64);
 		break;
 	default:
-		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
 			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
 			RT5665_DAC_OSR_128 | RT5665_ADC_OSR_128);
 		break;
 	}
 
 	if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
-		snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
 			RT5665_I2S2_M_PD_MASK, pre_div << RT5665_I2S2_M_PD_SFT);
 	}
 	if (rt5665->master[RT5665_AIF3]) {
-		snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
 			RT5665_I2S3_M_PD_MASK, pre_div << RT5665_I2S3_M_PD_SFT);
 	}
 
@@ -4218,8 +4218,8 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -4263,32 +4263,32 @@ static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	switch (dai->id) {
 	case RT5665_AIF1_1:
 	case RT5665_AIF1_2:
-		snd_soc_update_bits(codec, RT5665_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5665_I2S1_SDP,
 			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
 			RT5665_I2S_DF_MASK, reg_val);
 		break;
 	case RT5665_AIF2_1:
 	case RT5665_AIF2_2:
-		snd_soc_update_bits(codec, RT5665_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5665_I2S2_SDP,
 			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
 			RT5665_I2S_DF_MASK, reg_val);
 		break;
 	case RT5665_AIF3:
-		snd_soc_update_bits(codec, RT5665_I2S3_SDP,
+		snd_soc_component_update_bits(component, RT5665_I2S3_SDP,
 			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
 			RT5665_I2S_DF_MASK, reg_val);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 	return 0;
 }
 
-static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int rt5665_set_component_sysclk(struct snd_soc_component *component, int clk_id,
 				   int source, unsigned int freq, int dir)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0, src = 0;
 
 	if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src)
@@ -4308,34 +4308,34 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
 		src = RT5665_CLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5665_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5665_GLB_CLK,
 		RT5665_SCLK_SRC_MASK, reg_val);
 
 	if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
-		snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
 			RT5665_I2S2_SRC_MASK, src << RT5665_I2S2_SRC_SFT);
 	}
 	if (rt5665->master[RT5665_AIF3]) {
-		snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
 			RT5665_I2S3_SRC_MASK, src << RT5665_I2S3_SRC_SFT);
 	}
 
 	rt5665->sysclk = freq;
 	rt5665->sysclk_src = clk_id;
 
-	dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
 
 	return 0;
 }
 
-static int rt5665_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
+static int rt5665_set_component_pll(struct snd_soc_component *component, int pll_id,
 				int source, unsigned int freq_in,
 				unsigned int freq_out)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -4344,50 +4344,50 @@ static int rt5665_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5665->pll_in = 0;
 		rt5665->pll_out = 0;
-		snd_soc_update_bits(codec, RT5665_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
 			RT5665_SCLK_SRC_MASK, RT5665_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5665_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5665_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
 			RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK);
 		break;
 	case RT5665_PLL1_S_BCLK1:
-		snd_soc_update_bits(codec, RT5665_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
 				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK1);
 		break;
 	case RT5665_PLL1_S_BCLK2:
-		snd_soc_update_bits(codec, RT5665_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
 				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK2);
 		break;
 	case RT5665_PLL1_S_BCLK3:
-		snd_soc_update_bits(codec, RT5665_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
 				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL Source %d\n", source);
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5665_PLL_CTRL_1,
+	snd_soc_component_write(component, RT5665_PLL_CTRL_1,
 		pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5665_PLL_CTRL_2,
+	snd_soc_component_write(component, RT5665_PLL_CTRL_2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT |
 		pll_code.m_bp << RT5665_PLL_M_BP_SFT);
 
@@ -4400,10 +4400,10 @@ static int rt5665_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
 
 static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
 
 	rt5665->bclk[dai->id] = ratio;
 
@@ -4411,12 +4411,12 @@ static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 		switch (dai->id) {
 		case RT5665_AIF2_1:
 		case RT5665_AIF2_2:
-			snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
+			snd_soc_component_update_bits(component, RT5665_ADDA_CLK_2,
 				RT5665_I2S_BCLK_MS2_MASK,
 				RT5665_I2S_BCLK_MS2_64);
 			break;
 		case RT5665_AIF3:
-			snd_soc_update_bits(codec, RT5665_ADDA_CLK_2,
+			snd_soc_component_update_bits(component, RT5665_ADDA_CLK_2,
 				RT5665_I2S_BCLK_MS3_MASK,
 				RT5665_I2S_BCLK_MS3_64);
 			break;
@@ -4426,10 +4426,10 @@ static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 	return 0;
 }
 
-static int rt5665_set_bias_level(struct snd_soc_codec *codec,
+static int rt5665_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
@@ -4459,39 +4459,37 @@ static int rt5665_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5665_probe(struct snd_soc_codec *codec)
+static int rt5665_probe(struct snd_soc_component *component)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
-	rt5665->codec = codec;
+	rt5665->component = component;
 
 	schedule_delayed_work(&rt5665->calibrate_work, msecs_to_jiffies(100));
 
 	return 0;
 }
 
-static int rt5665_remove(struct snd_soc_codec *codec)
+static void rt5665_remove(struct snd_soc_component *component)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
 	regmap_write(rt5665->regmap, RT5665_RESET, 0);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt5665_suspend(struct snd_soc_codec *codec)
+static int rt5665_suspend(struct snd_soc_component *component)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5665->regmap, true);
 	regcache_mark_dirty(rt5665->regmap);
 	return 0;
 }
 
-static int rt5665_resume(struct snd_soc_codec *codec)
+static int rt5665_resume(struct snd_soc_component *component)
 {
-	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5665->regmap, false);
 	regcache_sync(rt5665->regmap);
@@ -4605,24 +4603,24 @@ static struct snd_soc_dai_driver rt5665_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
-	.probe = rt5665_probe,
-	.remove = rt5665_remove,
-	.suspend = rt5665_suspend,
-	.resume = rt5665_resume,
-	.set_bias_level = rt5665_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls = rt5665_snd_controls,
-		.num_controls = ARRAY_SIZE(rt5665_snd_controls),
-		.dapm_widgets = rt5665_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(rt5665_dapm_widgets),
-		.dapm_routes = rt5665_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes),
-	},
-	.set_sysclk = rt5665_set_codec_sysclk,
-	.set_pll = rt5665_set_codec_pll,
-	.set_jack = rt5665_set_jack_detect,
+static const struct snd_soc_component_driver soc_component_dev_rt5665 = {
+	.probe			= rt5665_probe,
+	.remove			= rt5665_remove,
+	.suspend		= rt5665_suspend,
+	.resume			= rt5665_resume,
+	.set_bias_level		= rt5665_set_bias_level,
+	.controls		= rt5665_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5665_snd_controls),
+	.dapm_widgets		= rt5665_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5665_dapm_widgets),
+	.dapm_routes		= rt5665_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5665_dapm_routes),
+	.set_sysclk		= rt5665_set_component_sysclk,
+	.set_pll		= rt5665_set_component_pll,
+	.set_jack		= rt5665_set_jack_detect,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 
@@ -4753,7 +4751,7 @@ static void rt5665_calibrate_handler(struct work_struct *work)
 	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
 		calibrate_work.work);
 
-	while (!rt5665->codec->component.card->instantiated) {
+	while (!rt5665->component->card->instantiated) {
 		pr_debug("%s\n", __func__);
 		usleep_range(10000, 15000);
 	}
@@ -4828,9 +4826,6 @@ static int rt5665_i2c_probe(struct i2c_client *i2c,
 	case 0x0:
 		rt5665->id = CODEC_5666;
 		break;
-	case 0x6:
-		rt5665->id = CODEC_5668;
-		break;
 	case 0x3:
 	default:
 		rt5665->id = CODEC_5665;
@@ -4941,17 +4936,11 @@ static int rt5665_i2c_probe(struct i2c_client *i2c,
 
 	}
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5665,
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5665,
 			rt5665_dai, ARRAY_SIZE(rt5665_dai));
 }
 
-static int rt5665_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static void rt5665_i2c_shutdown(struct i2c_client *client)
 {
 	struct rt5665_priv *rt5665 = i2c_get_clientdata(client);
@@ -4963,7 +4952,6 @@ static void rt5665_i2c_shutdown(struct i2c_client *client)
 static const struct of_device_id rt5665_of_match[] = {
 	{.compatible = "realtek,rt5665"},
 	{.compatible = "realtek,rt5666"},
-	{.compatible = "realtek,rt5668"},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rt5665_of_match);
@@ -4973,7 +4961,6 @@ MODULE_DEVICE_TABLE(of, rt5665_of_match);
 static const struct acpi_device_id rt5665_acpi_match[] = {
 	{"10EC5665", 0,},
 	{"10EC5666", 0,},
-	{"10EC5668", 0,},
 	{},
 };
 MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match);
@@ -4986,7 +4973,6 @@ static struct i2c_driver rt5665_i2c_driver = {
 		.acpi_match_table = ACPI_PTR(rt5665_acpi_match),
 	},
 	.probe = rt5665_i2c_probe,
-	.remove = rt5665_i2c_remove,
 	.shutdown = rt5665_i2c_shutdown,
 	.id_table = rt5665_i2c_id,
 };
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
index 5ddebd6a4a1b..b0a98ca39c5b 100644
--- a/sound/soc/codecs/rt5665.h
+++ b/sound/soc/codecs/rt5665.h
@@ -1978,7 +1978,6 @@ enum {
 enum {
 	CODEC_5665,
 	CODEC_5666,
-	CODEC_5668,
 };
 
 /* filter mask */
@@ -2003,7 +2002,7 @@ enum {
 	RT5665_CLK_SEL_SYS4,
 };
 
-int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5665_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src);
 
 #endif /* __RT5665_H__ */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index c5094b4399e2..dc7df337d5f8 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -423,7 +423,7 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
 
 /**
  * rt5670_headset_detect - Detect headset.
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @jack_insert: Jack insert or not.
  *
  * Detect whether is headset or not when jack inserted.
@@ -431,46 +431,46 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
  * Returns detect status.
  */
 
-static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+static int rt5670_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
 	int val;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	if (jack_insert) {
 		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
 		snd_soc_dapm_sync(dapm);
-		snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0);
-		snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3, 0x4, 0x0);
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL2,
 			RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
 			RT5670_CBJ_MN_JD);
-		snd_soc_write(codec, RT5670_GPIO_CTRL2, 0x0004);
-		snd_soc_update_bits(codec, RT5670_GPIO_CTRL1,
+		snd_soc_component_write(component, RT5670_GPIO_CTRL2, 0x0004);
+		snd_soc_component_update_bits(component, RT5670_GPIO_CTRL1,
 			RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
-		snd_soc_update_bits(codec, RT5670_CJ_CTRL1,
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL1,
 			RT5670_CBJ_BST1_EN, RT5670_CBJ_BST1_EN);
-		snd_soc_write(codec, RT5670_JD_CTRL3, 0x00f0);
-		snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
+		snd_soc_component_write(component, RT5670_JD_CTRL3, 0x00f0);
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL2,
 			RT5670_CBJ_MN_JD, RT5670_CBJ_MN_JD);
-		snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL2,
 			RT5670_CBJ_MN_JD, 0);
 		msleep(300);
-		val = snd_soc_read(codec, RT5670_CJ_CTRL3) & 0x7;
+		val = snd_soc_component_read32(component, RT5670_CJ_CTRL3) & 0x7;
 		if (val == 0x1 || val == 0x2) {
 			rt5670->jack_type = SND_JACK_HEADSET;
 			/* for push button */
-			snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x8);
-			snd_soc_update_bits(codec, RT5670_IL_CMD, 0x40, 0x40);
-			snd_soc_read(codec, RT5670_IL_CMD);
+			snd_soc_component_update_bits(component, RT5670_INT_IRQ_ST, 0x8, 0x8);
+			snd_soc_component_update_bits(component, RT5670_IL_CMD, 0x40, 0x40);
+			snd_soc_component_read32(component, RT5670_IL_CMD);
 		} else {
-			snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
+			snd_soc_component_update_bits(component, RT5670_GEN_CTRL3, 0x4, 0x4);
 			rt5670->jack_type = SND_JACK_HEADPHONE;
 			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
 			snd_soc_dapm_sync(dapm);
 		}
 	} else {
-		snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0);
-		snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
+		snd_soc_component_update_bits(component, RT5670_INT_IRQ_ST, 0x8, 0x0);
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3, 0x4, 0x4);
 		rt5670->jack_type = 0;
 		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
 		snd_soc_dapm_sync(dapm);
@@ -479,35 +479,35 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 	return rt5670->jack_type;
 }
 
-void rt5670_jack_suspend(struct snd_soc_codec *codec)
+void rt5670_jack_suspend(struct snd_soc_component *component)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	rt5670->jack_type_saved = rt5670->jack_type;
-	rt5670_headset_detect(codec, 0);
+	rt5670_headset_detect(component, 0);
 }
 EXPORT_SYMBOL_GPL(rt5670_jack_suspend);
 
-void rt5670_jack_resume(struct snd_soc_codec *codec)
+void rt5670_jack_resume(struct snd_soc_component *component)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	if (rt5670->jack_type_saved)
-		rt5670_headset_detect(codec, 1);
+		rt5670_headset_detect(component, 1);
 }
 EXPORT_SYMBOL_GPL(rt5670_jack_resume);
 
-static int rt5670_button_detect(struct snd_soc_codec *codec)
+static int rt5670_button_detect(struct snd_soc_component *component)
 {
 	int btn_type, val;
 
-	val = snd_soc_read(codec, RT5670_IL_CMD);
+	val = snd_soc_component_read32(component, RT5670_IL_CMD);
 	btn_type = val & 0xff80;
-	snd_soc_write(codec, RT5670_IL_CMD, val);
+	snd_soc_component_write(component, RT5670_IL_CMD, val);
 	if (btn_type != 0) {
 		msleep(20);
-		val = snd_soc_read(codec, RT5670_IL_CMD);
-		snd_soc_write(codec, RT5670_IL_CMD, val);
+		val = snd_soc_component_read32(component, RT5670_IL_CMD);
+		snd_soc_component_write(component, RT5670_IL_CMD, val);
 	}
 
 	return btn_type;
@@ -521,25 +521,25 @@ static int rt5670_irq_detection(void *data)
 	int val, btn_type, report = jack->status;
 
 	if (rt5670->pdata.jd_mode == 1) /* 2 port */
-		val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0070;
+		val = snd_soc_component_read32(rt5670->component, RT5670_A_JD_CTRL1) & 0x0070;
 	else
-		val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0020;
+		val = snd_soc_component_read32(rt5670->component, RT5670_A_JD_CTRL1) & 0x0020;
 
 	switch (val) {
 	/* jack in */
 	case 0x30: /* 2 port */
 	case 0x0: /* 1 port or 2 port */
 		if (rt5670->jack_type == 0) {
-			report = rt5670_headset_detect(rt5670->codec, 1);
+			report = rt5670_headset_detect(rt5670->component, 1);
 			/* for push button and jack out */
 			gpio->debounce_time = 25;
 			break;
 		}
 		btn_type = 0;
-		if (snd_soc_read(rt5670->codec, RT5670_INT_IRQ_ST) & 0x4) {
+		if (snd_soc_component_read32(rt5670->component, RT5670_INT_IRQ_ST) & 0x4) {
 			/* button pressed */
 			report = SND_JACK_HEADSET;
-			btn_type = rt5670_button_detect(rt5670->codec);
+			btn_type = rt5670_button_detect(rt5670->component);
 			switch (btn_type) {
 			case 0x2000: /* up */
 				report |= SND_JACK_BTN_1;
@@ -551,7 +551,7 @@ static int rt5670_irq_detection(void *data)
 				report |= SND_JACK_BTN_2;
 				break;
 			default:
-				dev_err(rt5670->codec->dev,
+				dev_err(rt5670->component->dev,
 					"Unexpected button code 0x%04x\n",
 					btn_type);
 				break;
@@ -566,8 +566,8 @@ static int rt5670_irq_detection(void *data)
 	case 0x10: /* 2 port */
 	case 0x20: /* 1 port */
 		report = 0;
-		snd_soc_update_bits(rt5670->codec, RT5670_INT_IRQ_ST, 0x1, 0x0);
-		rt5670_headset_detect(rt5670->codec, 0);
+		snd_soc_component_update_bits(rt5670->component, RT5670_INT_IRQ_ST, 0x1, 0x0);
+		rt5670_headset_detect(rt5670->component, 0);
 		gpio->debounce_time = 150; /* for jack in */
 		break;
 	default:
@@ -577,14 +577,14 @@ static int rt5670_irq_detection(void *data)
 	return report;
 }
 
-int rt5670_set_jack_detect(struct snd_soc_codec *codec,
+int rt5670_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	rt5670->jack = jack;
-	rt5670->hp_gpio.gpiod_dev = codec->dev;
+	rt5670->hp_gpio.gpiod_dev = component->dev;
 	rt5670->hp_gpio.name = "headset";
 	rt5670->hp_gpio.report = SND_JACK_HEADSET |
 		SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2;
@@ -596,7 +596,7 @@ int rt5670_set_jack_detect(struct snd_soc_codec *codec,
 	ret = snd_soc_jack_add_gpios(rt5670->jack, 1,
 			&rt5670->hp_gpio);
 	if (ret) {
-		dev_err(codec->dev, "Adding jack GPIO failed\n");
+		dev_err(component->dev, "Adding jack GPIO failed\n");
 		return ret;
 	}
 
@@ -699,17 +699,17 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 	int idx, rate;
 
 	rate = rt5670->sysclk / rl6231_get_pre_div(rt5670->regmap,
 		RT5670_ADDA_CLK1, RT5670_I2S_PD1_SFT);
 	idx = rl6231_calc_dmic_clk(rate);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
-		snd_soc_update_bits(codec, RT5670_DMIC_CTRL1,
+		snd_soc_component_update_bits(component, RT5670_DMIC_CTRL1,
 			RT5670_DMIC_CLK_MASK, idx << RT5670_DMIC_CLK_SFT);
 	return idx;
 }
@@ -717,8 +717,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1)
 		return 1;
@@ -729,7 +729,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg, shift, val;
 
 	switch (source->shift) {
@@ -765,7 +765,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 		return 0;
 	}
 
-	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
 	switch (val) {
 	case 1:
 	case 2:
@@ -781,8 +781,8 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 static int can_use_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384)
 		return 1;
@@ -793,7 +793,7 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
 
 /**
  * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @filter_mask: mask of filters.
  * @clk_src: clock source
  *
@@ -805,7 +805,7 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
  * set of filters specified by the mask. And the codec driver will turn on ASRC
  * for these filters if ASRC is selected as their clock source.
  */
-int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5670_sel_asrc_clk_src(struct snd_soc_component *component,
 			    unsigned int filter_mask, unsigned int clk_src)
 {
 	unsigned int asrc2_mask = 0, asrc2_value = 0;
@@ -863,11 +863,11 @@ int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
 	}
 
 	if (asrc2_mask)
-		snd_soc_update_bits(codec, RT5670_ASRC_2,
+		snd_soc_component_update_bits(component, RT5670_ASRC_2,
 				    asrc2_mask, asrc2_value);
 
 	if (asrc3_mask)
-		snd_soc_update_bits(codec, RT5670_ASRC_3,
+		snd_soc_component_update_bits(component, RT5670_ASRC_3,
 				    asrc3_mask, asrc3_value);
 	return 0;
 }
@@ -1421,8 +1421,8 @@ static const struct snd_kcontrol_new rt5670_vad_adc_mux =
 static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1457,8 +1457,8 @@ static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1507,16 +1507,16 @@ static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5670_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
 				    RT5670_PWR_BST1_P, RT5670_PWR_BST1_P);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5670_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
 				    RT5670_PWR_BST1_P, 0);
 		break;
 
@@ -1530,16 +1530,16 @@ static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, RT5670_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
 				    RT5670_PWR_BST2_P, RT5670_PWR_BST2_P);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, RT5670_PWR_ANLG2,
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
 				    RT5670_PWR_BST2_P, 0);
 		break;
 
@@ -2322,21 +2322,21 @@ static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = {
 static int rt5670_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int pre_div, bclk_ms, frame_size;
 
 	rt5670->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5670->sysclk, rt5670->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
 			rt5670->lrck[dai->id], dai->id);
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 	bclk_ms = frame_size > 32;
@@ -2368,20 +2368,20 @@ static int rt5670_hw_params(struct snd_pcm_substream *substream,
 		mask_clk = RT5670_I2S_BCLK_MS1_MASK | RT5670_I2S_PD1_MASK;
 		val_clk = bclk_ms << RT5670_I2S_BCLK_MS1_SFT |
 			pre_div << RT5670_I2S_PD1_SFT;
-		snd_soc_update_bits(codec, RT5670_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5670_I2S1_SDP,
 			RT5670_I2S_DL_MASK, val_len);
-		snd_soc_update_bits(codec, RT5670_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5670_ADDA_CLK1, mask_clk, val_clk);
 		break;
 	case RT5670_AIF2:
 		mask_clk = RT5670_I2S_BCLK_MS2_MASK | RT5670_I2S_PD2_MASK;
 		val_clk = bclk_ms << RT5670_I2S_BCLK_MS2_SFT |
 			pre_div << RT5670_I2S_PD2_SFT;
-		snd_soc_update_bits(codec, RT5670_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5670_I2S2_SDP,
 			RT5670_I2S_DL_MASK, val_len);
-		snd_soc_update_bits(codec, RT5670_ADDA_CLK1, mask_clk, val_clk);
+		snd_soc_component_update_bits(component, RT5670_ADDA_CLK1, mask_clk, val_clk);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 
@@ -2390,8 +2390,8 @@ static int rt5670_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -2434,26 +2434,26 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 	switch (dai->id) {
 	case RT5670_AIF1:
-		snd_soc_update_bits(codec, RT5670_I2S1_SDP,
+		snd_soc_component_update_bits(component, RT5670_I2S1_SDP,
 			RT5670_I2S_MS_MASK | RT5670_I2S_BP_MASK |
 			RT5670_I2S_DF_MASK, reg_val);
 		break;
 	case RT5670_AIF2:
-		snd_soc_update_bits(codec, RT5670_I2S2_SDP,
+		snd_soc_component_update_bits(component, RT5670_I2S2_SDP,
 			RT5670_I2S_MS_MASK | RT5670_I2S_BP_MASK |
 			RT5670_I2S_DF_MASK, reg_val);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 		return -EINVAL;
 	}
 	return 0;
 }
 
-static int rt5670_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int rt5670_set_codec_sysclk(struct snd_soc_component *component, int clk_id,
 				   int source, unsigned int freq, int dir)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (clk_id) {
@@ -2467,16 +2467,16 @@ static int rt5670_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
 		reg_val |= RT5670_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, RT5670_GLB_CLK,
+	snd_soc_component_update_bits(component, RT5670_GLB_CLK,
 		RT5670_SCLK_SRC_MASK, reg_val);
 	rt5670->sysclk = freq;
 	if (clk_id != RT5670_SCLK_S_RCCLK)
 		rt5670->sysclk_src = clk_id;
 
-	dev_dbg(codec->dev, "Sysclk : %dHz clock id : %d\n", freq, clk_id);
+	dev_dbg(component->dev, "Sysclk : %dHz clock id : %d\n", freq, clk_id);
 
 	return 0;
 }
@@ -2484,8 +2484,8 @@ static int rt5670_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
 static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -2494,18 +2494,18 @@ static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5670->pll_in = 0;
 		rt5670->pll_out = 0;
-		snd_soc_update_bits(codec, RT5670_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5670_GLB_CLK,
 			RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_MCLK);
 		return 0;
 	}
 
 	switch (source) {
 	case RT5670_PLL1_S_MCLK:
-		snd_soc_update_bits(codec, RT5670_GLB_CLK,
+		snd_soc_component_update_bits(component, RT5670_GLB_CLK,
 			RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_MCLK);
 		break;
 	case RT5670_PLL1_S_BCLK1:
@@ -2514,36 +2514,36 @@ static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 	case RT5670_PLL1_S_BCLK4:
 		switch (dai->id) {
 		case RT5670_AIF1:
-			snd_soc_update_bits(codec, RT5670_GLB_CLK,
+			snd_soc_component_update_bits(component, RT5670_GLB_CLK,
 				RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_BCLK1);
 			break;
 		case RT5670_AIF2:
-			snd_soc_update_bits(codec, RT5670_GLB_CLK,
+			snd_soc_component_update_bits(component, RT5670_GLB_CLK,
 				RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_BCLK2);
 			break;
 		default:
-			dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+			dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
 			return -EINVAL;
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
-	snd_soc_write(codec, RT5670_PLL_CTRL1,
+	snd_soc_component_write(component, RT5670_PLL_CTRL1,
 		pll_code.n_code << RT5670_PLL_N_SFT | pll_code.k_code);
-	snd_soc_write(codec, RT5670_PLL_CTRL2,
+	snd_soc_component_write(component, RT5670_PLL_CTRL2,
 		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT |
 		pll_code.m_bp << RT5670_PLL_M_BP_SFT);
 
@@ -2557,7 +2557,7 @@ static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val = 0;
 
 	if (rx_mask || tx_mask)
@@ -2595,75 +2595,75 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, RT5670_TDM_CTRL_1, 0x7c00, val);
+	snd_soc_component_update_bits(component, RT5670_TDM_CTRL_1, 0x7c00, val);
 
 	return 0;
 }
 
 static int rt5670_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
 	if (dai->id != RT5670_AIF1)
 		return 0;
 
 	if ((ratio % 50) == 0)
-		snd_soc_update_bits(codec, RT5670_GEN_CTRL3,
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3,
 			RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_50FS);
 	else
-		snd_soc_update_bits(codec, RT5670_GEN_CTRL3,
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3,
 			RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_NOR);
 
 	return 0;
 }
 
-static int rt5670_set_bias_level(struct snd_soc_codec *codec,
+static int rt5670_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_PREPARE:
-		if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
-			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_PWR_VREF1 | RT5670_PWR_MB |
 				RT5670_PWR_BG | RT5670_PWR_VREF2,
 				RT5670_PWR_VREF1 | RT5670_PWR_MB |
 				RT5670_PWR_BG | RT5670_PWR_VREF2);
 			mdelay(10);
-			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_PWR_FV1 | RT5670_PWR_FV2,
 				RT5670_PWR_FV1 | RT5670_PWR_FV2);
-			snd_soc_update_bits(codec, RT5670_CHARGE_PUMP,
+			snd_soc_component_update_bits(component, RT5670_CHARGE_PUMP,
 				RT5670_OSW_L_MASK | RT5670_OSW_R_MASK,
 				RT5670_OSW_L_DIS | RT5670_OSW_R_DIS);
-			snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1);
-			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5670_DIG_MISC, 0x1, 0x1);
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_LDO_SEL_MASK, 0x5);
 		}
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
 				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
-		snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_LDO_SEL_MASK, 0x3);
 		break;
 	case SND_SOC_BIAS_OFF:
 		if (rt5670->pdata.jd_mode)
-			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_PWR_VREF1 | RT5670_PWR_MB |
 				RT5670_PWR_BG | RT5670_PWR_VREF2 |
 				RT5670_PWR_FV1 | RT5670_PWR_FV2,
 				RT5670_PWR_MB | RT5670_PWR_BG);
 		else
-			snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
 				RT5670_PWR_VREF1 | RT5670_PWR_MB |
 				RT5670_PWR_BG | RT5670_PWR_VREF2 |
 				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
 
-		snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
+		snd_soc_component_update_bits(component, RT5670_DIG_MISC, 0x1, 0x0);
 		break;
 
 	default:
@@ -2673,12 +2673,12 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int rt5670_probe(struct snd_soc_codec *codec)
+static int rt5670_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
-	switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
+	switch (snd_soc_component_read32(component, RT5670_RESET) & RT5670_ID_MASK) {
 	case RT5670_ID_5670:
 	case RT5670_ID_5671:
 		snd_soc_dapm_new_controls(dapm,
@@ -2697,37 +2697,36 @@ static int rt5670_probe(struct snd_soc_codec *codec)
 			ARRAY_SIZE(rt5672_specific_dapm_routes));
 		break;
 	default:
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"The driver is for RT5670 RT5671 or RT5672 only\n");
 		return -ENODEV;
 	}
-	rt5670->codec = codec;
+	rt5670->component = component;
 
 	return 0;
 }
 
-static int rt5670_remove(struct snd_soc_codec *codec)
+static void rt5670_remove(struct snd_soc_component *component)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	regmap_write(rt5670->regmap, RT5670_RESET, 0);
 	snd_soc_jack_free_gpios(rt5670->jack, 1, &rt5670->hp_gpio);
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt5670_suspend(struct snd_soc_codec *codec)
+static int rt5670_suspend(struct snd_soc_component *component)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5670->regmap, true);
 	regcache_mark_dirty(rt5670->regmap);
 	return 0;
 }
 
-static int rt5670_resume(struct snd_soc_codec *codec)
+static int rt5670_resume(struct snd_soc_component *component)
 {
-	struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(rt5670->regmap, false);
 	regcache_sync(rt5670->regmap);
@@ -2794,22 +2793,22 @@ static struct snd_soc_dai_driver rt5670_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
-	.probe = rt5670_probe,
-	.remove = rt5670_remove,
-	.suspend = rt5670_suspend,
-	.resume = rt5670_resume,
-	.set_bias_level = rt5670_set_bias_level,
-	.idle_bias_off = true,
-	.set_sysclk = rt5670_set_codec_sysclk,
-	.component_driver = {
-		.controls		= rt5670_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5670_snd_controls),
-		.dapm_widgets		= rt5670_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5670_dapm_widgets),
-		.dapm_routes		= rt5670_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5670_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5670 = {
+	.probe			= rt5670_probe,
+	.remove			= rt5670_remove,
+	.suspend		= rt5670_suspend,
+	.resume			= rt5670_resume,
+	.set_bias_level		= rt5670_set_bias_level,
+	.set_sysclk		= rt5670_set_codec_sysclk,
+	.controls		= rt5670_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5670_snd_controls),
+	.dapm_widgets		= rt5670_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5670_dapm_widgets),
+	.dapm_routes		= rt5670_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5670_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5670_regmap = {
@@ -3171,7 +3170,8 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 	pm_runtime_enable(&i2c->dev);
 	pm_request_idle(&i2c->dev);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5670,
 			rt5670_dai, ARRAY_SIZE(rt5670_dai));
 	if (ret < 0)
 		goto err;
@@ -3188,7 +3188,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 static int rt5670_i2c_remove(struct i2c_client *i2c)
 {
 	pm_runtime_disable(&i2c->dev);
-	snd_soc_unregister_codec(&i2c->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index 265df80d504e..97e8eebe63fa 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -1986,11 +1986,11 @@ enum {
 	RT5670_DOWN_RATE_FILTER = (0x1 << 7),
 };
 
-int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5670_sel_asrc_clk_src(struct snd_soc_component *component,
 			    unsigned int filter_mask, unsigned int clk_src);
 
 struct rt5670_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5670_platform_data pdata;
 	struct regmap *regmap;
 	struct snd_soc_jack *jack;
@@ -2012,8 +2012,8 @@ struct rt5670_priv {
 	int jack_type_saved;
 };
 
-void rt5670_jack_suspend(struct snd_soc_codec *codec);
-void rt5670_jack_resume(struct snd_soc_codec *codec);
-int rt5670_set_jack_detect(struct snd_soc_codec *codec,
+void rt5670_jack_suspend(struct snd_soc_component *component);
+void rt5670_jack_resume(struct snd_soc_component *component);
+int rt5670_set_jack_detect(struct snd_soc_component *component,
 	struct snd_soc_jack *jack);
 #endif /* __RT5670_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 0791fec398fb..bc1a23dd7c2d 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -554,7 +554,7 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg)
 static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
 		unsigned int addr, unsigned int value, unsigned int opcode)
 {
-	struct snd_soc_codec *codec = rt5677->codec;
+	struct snd_soc_component *component = rt5677->component;
 	int ret;
 
 	mutex_lock(&rt5677->dsp_cmd_lock);
@@ -562,35 +562,35 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
 		addr >> 16);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
+		dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
 		goto err;
 	}
 
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
 		addr & 0xffff);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
+		dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
 		goto err;
 	}
 
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
 		value >> 16);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set data msb value: %d\n", ret);
+		dev_err(component->dev, "Failed to set data msb value: %d\n", ret);
 		goto err;
 	}
 
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
 		value & 0xffff);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret);
+		dev_err(component->dev, "Failed to set data lsb value: %d\n", ret);
 		goto err;
 	}
 
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
 		opcode);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
+		dev_err(component->dev, "Failed to set op code value: %d\n", ret);
 		goto err;
 	}
 
@@ -612,7 +612,7 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
 static int rt5677_dsp_mode_i2c_read_addr(
 	struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value)
 {
-	struct snd_soc_codec *codec = rt5677->codec;
+	struct snd_soc_component *component = rt5677->component;
 	int ret;
 	unsigned int msb, lsb;
 
@@ -621,21 +621,21 @@ static int rt5677_dsp_mode_i2c_read_addr(
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
 		addr >> 16);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
+		dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
 		goto err;
 	}
 
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
 		addr & 0xffff);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
+		dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
 		goto err;
 	}
 
 	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
 		0x0002);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
+		dev_err(component->dev, "Failed to set op code value: %d\n", ret);
 		goto err;
 	}
 
@@ -685,9 +685,9 @@ static int rt5677_dsp_mode_i2c_read(
 	return ret;
 }
 
-static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on)
+static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	if (on) {
 		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2);
@@ -698,9 +698,9 @@ static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on)
 	}
 }
 
-static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
+static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	static bool activity;
 	int ret;
 
@@ -740,17 +740,17 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
 		}
 		regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
 		regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
-		rt5677_set_dsp_mode(codec, true);
+		rt5677_set_dsp_mode(component, true);
 
 		ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1,
-			codec->dev);
+			component->dev);
 		if (ret == 0) {
 			rt5677_spi_write_firmware(0x50000000, rt5677->fw1);
 			release_firmware(rt5677->fw1);
 		}
 
 		ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2,
-			codec->dev);
+			component->dev);
 		if (ret == 0) {
 			rt5677_spi_write_firmware(0x60000000, rt5677->fw2);
 			release_firmware(rt5677->fw2);
@@ -767,7 +767,7 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
 		regcache_cache_bypass(rt5677->regmap, true);
 
 		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1);
-		rt5677_set_dsp_mode(codec, false);
+		rt5677_set_dsp_mode(component, false);
 		regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001);
 
 		regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
@@ -812,12 +812,11 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
 	rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
 
-	if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
-		rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+		rt5677_set_dsp_vad(component, rt5677->dsp_vad_en);
 
 	return 0;
 }
@@ -911,15 +910,15 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	int idx, rate;
 
 	rate = rt5677->sysclk / rl6231_get_pre_div(rt5677->regmap,
 		RT5677_CLK_TREE_CTRL1, RT5677_I2S_PD1_SFT);
 	idx = rl6231_calc_dmic_clk(rate);
 	if (idx < 0)
-		dev_err(codec->dev, "Failed to set DMIC clock\n");
+		dev_err(component->dev, "Failed to set DMIC clock\n");
 	else
 		regmap_update_bits(rt5677->regmap, RT5677_DMIC_CTRL1,
 			RT5677_DMIC_CLK_MASK, idx << RT5677_DMIC_CLK_SFT);
@@ -929,8 +928,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val);
@@ -944,8 +943,8 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int reg, shift, val;
 
 	if (source->reg == RT5677_ASRC_1) {
@@ -1027,8 +1026,8 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 static int can_use_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384)
 		return 1;
@@ -1038,7 +1037,7 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
 
 /**
  * rt5677_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @codec: SoC audio codec device.
+ * @component: SoC audio component device.
  * @filter_mask: mask of filters.
  * @clk_src: clock source
  *
@@ -1050,10 +1049,10 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
  * set of filters specified by the mask. And the codec driver will turn on ASRC
  * for these filters if ASRC is selected as their clock source.
  */
-int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5677_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int asrc3_mask = 0, asrc3_value = 0;
 	unsigned int asrc4_mask = 0, asrc4_value = 0;
 	unsigned int asrc5_mask = 0, asrc5_value = 0;
@@ -1232,8 +1231,8 @@ EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
 static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int asrc_setting;
 
 	switch (source->shift) {
@@ -2393,8 +2392,8 @@ static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
 static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -2417,8 +2416,8 @@ static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -2441,8 +2440,8 @@ static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -2463,8 +2462,8 @@ static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -2485,8 +2484,8 @@ static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -2512,8 +2511,8 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int value;
 
 	switch (event) {
@@ -2535,8 +2534,8 @@ static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int value;
 
 	switch (event) {
@@ -2558,12 +2557,12 @@ static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON &&
+		if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON &&
 			!rt5677->is_vref_slow) {
 			mdelay(20);
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@ -4098,21 +4097,21 @@ static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = {
 static int rt5677_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int val_len = 0, val_clk, mask_clk;
 	int pre_div, bclk_ms, frame_size;
 
 	rt5677->lrck[dai->id] = params_rate(params);
 	pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]);
 	if (pre_div < 0) {
-		dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n",
+		dev_err(component->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n",
 			rt5677->sysclk, rt5677->lrck[dai->id]);
 		return -EINVAL;
 	}
 	frame_size = snd_soc_params_to_frame_size(params);
 	if (frame_size < 0) {
-		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
 		return -EINVAL;
 	}
 	bclk_ms = frame_size > 32;
@@ -4183,8 +4182,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream,
 
 static int rt5677_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -4257,8 +4256,8 @@ static int rt5677_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int rt5677_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int reg_val = 0;
 
 	if (freq == rt5677->sysclk && clk_id == rt5677->sysclk_src)
@@ -4275,7 +4274,7 @@ static int rt5677_set_dai_sysclk(struct snd_soc_dai *dai,
 		reg_val |= RT5677_SCLK_SRC_RCCLK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
 		return -EINVAL;
 	}
 	regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
@@ -4310,8 +4309,8 @@ static int rt5677_pll_calc(const unsigned int freq_in,
 static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 			unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	struct rl6231_pll_code pll_code;
 	int ret;
 
@@ -4320,7 +4319,7 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		return 0;
 
 	if (!freq_in || !freq_out) {
-		dev_dbg(codec->dev, "PLL disabled\n");
+		dev_dbg(component->dev, "PLL disabled\n");
 
 		rt5677->pll_in = 0;
 		rt5677->pll_out = 0;
@@ -4360,17 +4359,17 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 		}
 		break;
 	default:
-		dev_err(codec->dev, "Unknown PLL source %d\n", source);
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
 		return -EINVAL;
 	}
 
 	ret = rt5677_pll_calc(freq_in, freq_out, &pll_code);
 	if (ret < 0) {
-		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "m_bypass=%d m=%d n=%d k=%d\n",
+	dev_dbg(component->dev, "m_bypass=%d m=%d n=%d k=%d\n",
 		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
 		pll_code.n_code, pll_code.k_code);
 
@@ -4390,8 +4389,8 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
 static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0, slot_width_25 = 0;
 
 	if (rx_mask || tx_mask)
@@ -4449,18 +4448,18 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	return 0;
 }
 
-static int rt5677_set_bias_level(struct snd_soc_codec *codec,
+static int rt5677_set_bias_level(struct snd_soc_component *component,
 			enum snd_soc_bias_level level)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
-			rt5677_set_dsp_vad(codec, false);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+			rt5677_set_dsp_vad(component, false);
 
 			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
 				RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
@@ -4495,7 +4494,7 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
 			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
 
 		if (rt5677->dsp_vad_en)
-			rt5677_set_dsp_vad(codec, true);
+			rt5677_set_dsp_vad(component, true);
 		break;
 
 	default:
@@ -4696,13 +4695,13 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
 }
 #endif
 
-static int rt5677_probe(struct snd_soc_codec *codec)
+static int rt5677_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 	int i;
 
-	rt5677->codec = codec;
+	rt5677->component = component;
 
 	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
 		snd_soc_dapm_add_routes(dapm,
@@ -4714,7 +4713,7 @@ static int rt5677_probe(struct snd_soc_codec *codec)
 			ARRAY_SIZE(rt5677_dmic2_clk_1));
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
 	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
@@ -4753,21 +4752,19 @@ static int rt5677_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5677_remove(struct snd_soc_codec *codec)
+static void rt5677_remove(struct snd_soc_component *component)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
 	gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
 	gpiod_set_value_cansleep(rt5677->reset_pin, 1);
-
-	return 0;
 }
 
 #ifdef CONFIG_PM
-static int rt5677_suspend(struct snd_soc_codec *codec)
+static int rt5677_suspend(struct snd_soc_component *component)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	if (!rt5677->dsp_vad_en) {
 		regcache_cache_only(rt5677->regmap, true);
@@ -4780,9 +4777,9 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int rt5677_resume(struct snd_soc_codec *codec)
+static int rt5677_resume(struct snd_soc_component *component)
 {
-	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
 	if (!rt5677->dsp_vad_en) {
 		rt5677->pll_src = 0;
@@ -4959,21 +4956,21 @@ static struct snd_soc_dai_driver rt5677_dai[] = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
-	.probe = rt5677_probe,
-	.remove = rt5677_remove,
-	.suspend = rt5677_suspend,
-	.resume = rt5677_resume,
-	.set_bias_level = rt5677_set_bias_level,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= rt5677_snd_controls,
-		.num_controls		= ARRAY_SIZE(rt5677_snd_controls),
-		.dapm_widgets		= rt5677_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(rt5677_dapm_widgets),
-		.dapm_routes		= rt5677_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(rt5677_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_rt5677 = {
+	.probe			= rt5677_probe,
+	.remove			= rt5677_remove,
+	.suspend		= rt5677_suspend,
+	.resume			= rt5677_resume,
+	.set_bias_level		= rt5677_set_bias_level,
+	.controls		= rt5677_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5677_snd_controls),
+	.dapm_widgets		= rt5677_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5677_dapm_widgets),
+	.dapm_routes		= rt5677_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5677_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config rt5677_regmap_physical = {
@@ -5262,13 +5259,13 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 	rt5677_init_gpio(i2c);
 	rt5677_init_irq(i2c);
 
-	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5677,
 				      rt5677_dai, ARRAY_SIZE(rt5677_dai));
 }
 
 static int rt5677_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&i2c->dev);
 	rt5677_free_irq(i2c);
 	rt5677_free_gpio(i2c);
 
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 97239973edc4..183d92b03045 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -1790,7 +1790,7 @@ struct rt5677_platform_data {
 };
 
 struct rt5677_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct rt5677_platform_data pdata;
 	struct regmap *regmap, *regmap_physical;
 	const struct firmware *fw1, *fw2;
@@ -1816,7 +1816,7 @@ struct rt5677_priv {
 	bool is_vref_slow;
 };
 
-int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
+int rt5677_sel_asrc_clk_src(struct snd_soc_component *component,
 		unsigned int filter_mask, unsigned int clk_src);
 
 #endif /* __RT5677_H__ */
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index e1ab5537d27a..7c1d65830c05 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -147,19 +147,19 @@ struct sgtl5000_priv {
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* change mic bias resistor */
-		snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
 			SGTL5000_BIAS_R_MASK,
 			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
 				SGTL5000_BIAS_R_MASK, 0);
 		break;
 	}
@@ -174,12 +174,12 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
 static int power_vag_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
 			SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
 		msleep(400);
 		break;
@@ -190,9 +190,9 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
 		 * operational to prevent inadvertently starving the
 		 * other one of them.
 		 */
-		if ((snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER) &
+		if ((snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) &
 				mask) != mask) {
-			snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+			snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
 				SGTL5000_VAG_POWERUP, 0);
 			msleep(400);
 		}
@@ -216,17 +216,54 @@ static SOC_ENUM_SINGLE_DECL(adc_enum,
 static const struct snd_kcontrol_new adc_mux =
 SOC_DAPM_ENUM("Capture Mux", adc_enum);
 
+/* input sources for headphone */
+static const char *hp_mux_text[] = {
+	"DAC", "LINE_IN"
+};
+
+static SOC_ENUM_SINGLE_DECL(hp_enum,
+			    SGTL5000_CHIP_ANA_CTRL, 6,
+			    hp_mux_text);
+
+static const struct snd_kcontrol_new hp_mux =
+SOC_DAPM_ENUM("Headphone Mux", hp_enum);
+
 /* input sources for DAC */
 static const char *dac_mux_text[] = {
-	"DAC", "LINE_IN"
+	"ADC", "I2S", "Rsvrd", "DAP"
 };
 
 static SOC_ENUM_SINGLE_DECL(dac_enum,
-			    SGTL5000_CHIP_ANA_CTRL, 6,
+			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAC_SEL_SHIFT,
 			    dac_mux_text);
 
 static const struct snd_kcontrol_new dac_mux =
-SOC_DAPM_ENUM("Headphone Mux", dac_enum);
+SOC_DAPM_ENUM("Digital Input Mux", dac_enum);
+
+/* input sources for DAP */
+static const char *dap_mux_text[] = {
+	"ADC", "I2S"
+};
+
+static SOC_ENUM_SINGLE_DECL(dap_enum,
+			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAP_SEL_SHIFT,
+			    dap_mux_text);
+
+static const struct snd_kcontrol_new dap_mux =
+SOC_DAPM_ENUM("DAP Mux", dap_enum);
+
+/* input sources for DAP mix */
+static const char *dapmix_mux_text[] = {
+	"ADC", "I2S"
+};
+
+static SOC_ENUM_SINGLE_DECL(dapmix_enum,
+			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAP_MIX_SEL_SHIFT,
+			    dapmix_mux_text);
+
+static const struct snd_kcontrol_new dapmix_mux =
+SOC_DAPM_ENUM("DAP MIX Mux", dapmix_enum);
+
 
 static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("LINE_IN"),
@@ -243,7 +280,12 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
 	SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
 
 	SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
-	SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
+	SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &hp_mux),
+	SND_SOC_DAPM_MUX("Digital Input Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
+	SND_SOC_DAPM_MUX("DAP Mux", SGTL5000_DAP_CTRL, 0, 0, &dap_mux),
+	SND_SOC_DAPM_MUX("DAP MIX Mux", SGTL5000_DAP_CTRL, 4, 0, &dapmix_mux),
+	SND_SOC_DAPM_MIXER("DAP", SGTL5000_CHIP_DIG_POWER, 4, 0, NULL, 0),
+
 
 	/* aif for i2s input */
 	SND_SOC_DAPM_AIF_IN("AIFIN", "Playback",
@@ -270,7 +312,19 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
 	{"ADC", NULL, "Capture Mux"},		/* adc_mux --> adc */
 	{"AIFOUT", NULL, "ADC"},		/* adc --> i2s_out */
 
-	{"DAC", NULL, "AIFIN"},			/* i2s-->dac,skip audio mux */
+	{"DAP Mux", "ADC", "ADC"},		/* adc --> DAP mux */
+	{"DAP Mux", NULL, "AIFIN"},		/* i2s --> DAP mux */
+	{"DAP", NULL, "DAP Mux"},		/* DAP mux --> dap */
+
+	{"DAP MIX Mux", "ADC", "ADC"},		/* adc --> DAP MIX mux */
+	{"DAP MIX Mux", NULL, "AIFIN"},		/* i2s --> DAP MIX mux */
+	{"DAP", NULL, "DAP MIX Mux"},		/* DAP MIX mux --> dap */
+
+	{"Digital Input Mux", "ADC", "ADC"},	/* adc --> audio mux */
+	{"Digital Input Mux", NULL, "AIFIN"},	/* i2s --> audio mux */
+	{"Digital Input Mux", NULL, "DAP"},	/* dap --> audio mux */
+	{"DAC", NULL, "Digital Input Mux"},	/* audio mux --> dac */
+
 	{"Headphone Mux", "DAC", "DAC"},	/* dac --> hp_mux */
 	{"LO", NULL, "DAC"},			/* dac --> line_out */
 
@@ -318,12 +372,12 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol,
 static int dac_get_volsw(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int reg;
 	int l;
 	int r;
 
-	reg = snd_soc_read(codec, SGTL5000_CHIP_DAC_VOL);
+	reg = snd_soc_component_read32(component, SGTL5000_CHIP_DAC_VOL);
 
 	/* get left channel volume */
 	l = (reg & SGTL5000_DAC_VOL_LEFT_MASK) >> SGTL5000_DAC_VOL_LEFT_SHIFT;
@@ -371,7 +425,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol,
 static int dac_put_volsw(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int reg;
 	int l;
 	int r;
@@ -391,7 +445,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
 	reg = l << SGTL5000_DAC_VOL_LEFT_SHIFT |
 		r << SGTL5000_DAC_VOL_RIGHT_SHIFT;
 
-	snd_soc_write(codec, SGTL5000_CHIP_DAC_VOL, reg);
+	snd_soc_component_write(component, SGTL5000_CHIP_DAC_VOL, reg);
 
 	return 0;
 }
@@ -409,9 +463,9 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
 static int avc_get_threshold(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int db, i;
-	u16 reg = snd_soc_read(codec, SGTL5000_DAP_AVC_THRESHOLD);
+	u16 reg = snd_soc_component_read32(component, SGTL5000_DAP_AVC_THRESHOLD);
 
 	/* register value 0 => -96dB */
 	if (!reg) {
@@ -442,7 +496,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
 static int avc_put_threshold(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int db;
 	u16 reg;
 
@@ -450,7 +504,7 @@ static int avc_put_threshold(struct snd_kcontrol *kcontrol,
 	if (db < 0 || db > 96)
 		return -EINVAL;
 	reg = avc_thr_db2reg[db];
-	snd_soc_write(codec, SGTL5000_DAP_AVC_THRESHOLD, reg);
+	snd_soc_component_write(component, SGTL5000_DAP_AVC_THRESHOLD, reg);
 
 	return 0;
 }
@@ -463,6 +517,12 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
 	1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0)
 );
 
+/* tlv for DAP channels, 0% - 100% - 200% */
+static const DECLARE_TLV_DB_SCALE(dap_volume, 0, 1, 0);
+
+/* tlv for bass bands, -11.75db to 12.0db, step .25db */
+static const DECLARE_TLV_DB_SCALE(bass_band, -1175, 25, 0);
+
 /* tlv for hp volume, -51.5db to 12.0db, step .5db */
 static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);
 
@@ -514,6 +574,11 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
 			lineout_volume),
 	SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1),
 
+	SOC_SINGLE_TLV("DAP Main channel", SGTL5000_DAP_MAIN_CHAN,
+	0, 0xffff, 0, dap_volume),
+
+	SOC_SINGLE_TLV("DAP Mix channel", SGTL5000_DAP_MIX_CHAN,
+	0, 0xffff, 0, dap_volume),
 	/* Automatic Volume Control (DAP AVC) */
 	SOC_SINGLE("AVC Switch", SGTL5000_DAP_AVC_CTRL, 0, 1, 0),
 	SOC_SINGLE("AVC Hard Limiter Switch", SGTL5000_DAP_AVC_CTRL, 5, 1, 0),
@@ -523,16 +588,36 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
 	SOC_SINGLE_EXT_TLV("AVC Threshold Volume", SGTL5000_DAP_AVC_THRESHOLD,
 			0, 96, 0, avc_get_threshold, avc_put_threshold,
 			avc_threshold),
+
+	SOC_SINGLE_TLV("BASS 0", SGTL5000_DAP_EQ_BASS_BAND0,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 1", SGTL5000_DAP_EQ_BASS_BAND1,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 2", SGTL5000_DAP_EQ_BASS_BAND2,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 3", SGTL5000_DAP_EQ_BASS_BAND3,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 4", SGTL5000_DAP_EQ_BASS_BAND4,
+	0, 0x5F, 0, bass_band),
 };
 
 /* mute the codec used by alsa core */
 static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 adcdac_ctrl = SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT;
+	struct snd_soc_component *component = codec_dai->component;
+	u16 i2s_pwr = SGTL5000_I2S_IN_POWERUP;
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL,
-			adcdac_ctrl, mute ? adcdac_ctrl : 0);
+	/*
+	 * During 'digital mute' do not mute DAC
+	 * because LINE_IN would be muted aswell. We want to mute
+	 * only I2S block - this can be done by powering it off
+	 */
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_DIG_POWER,
+			i2s_pwr, mute ? 0 : i2s_pwr);
 
 	return 0;
 }
@@ -540,8 +625,8 @@ static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 /* set codec format */
 static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 	u16 i2sctl = 0;
 
 	sgtl5000->master = 0;
@@ -599,7 +684,7 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, SGTL5000_CHIP_I2S_CTRL, i2sctl);
+	snd_soc_component_write(component, SGTL5000_CHIP_I2S_CTRL, i2sctl);
 
 	return 0;
 }
@@ -608,8 +693,8 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				   int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case SGTL5000_SYSCLK:
@@ -635,9 +720,9 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
  * and above.
  * 3. usage of sys_mclk is preferred over pll to save power.
  */
-static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
+static int sgtl5000_set_clock(struct snd_soc_component *component, int frame_rate)
 {
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 	int clk_ctl = 0;
 	int sys_fs;	/* sample freq */
 
@@ -690,7 +775,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 		clk_ctl |= SGTL5000_SYS_FS_96k << SGTL5000_SYS_FS_SHIFT;
 		break;
 	default:
-		dev_err(codec->dev, "frame rate %d not supported\n",
+		dev_err(component->dev, "frame rate %d not supported\n",
 			frame_rate);
 		return -EINVAL;
 	}
@@ -719,9 +804,9 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 			clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
 				SGTL5000_MCLK_FREQ_SHIFT;
 		} else {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"PLL not supported in slave mode\n");
-			dev_err(codec->dev, "%d ratio is not supported. "
+			dev_err(component->dev, "%d ratio is not supported. "
 				"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
 				sgtl5000->sysclk / frame_rate);
 			return -EINVAL;
@@ -754,31 +839,31 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
 		pll_ctl = int_div << SGTL5000_PLL_INT_DIV_SHIFT |
 		    frac_div << SGTL5000_PLL_FRAC_DIV_SHIFT;
 
-		snd_soc_write(codec, SGTL5000_CHIP_PLL_CTRL, pll_ctl);
+		snd_soc_component_write(component, SGTL5000_CHIP_PLL_CTRL, pll_ctl);
 		if (div2)
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 				SGTL5000_CHIP_CLK_TOP_CTRL,
 				SGTL5000_INPUT_FREQ_DIV2,
 				SGTL5000_INPUT_FREQ_DIV2);
 		else
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 				SGTL5000_CHIP_CLK_TOP_CTRL,
 				SGTL5000_INPUT_FREQ_DIV2,
 				0);
 
 		/* power up pll */
-		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
 			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
 			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP);
 
 		/* if using pll, clk_ctrl must be set after pll power up */
-		snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+		snd_soc_component_write(component, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
 	} else {
 		/* otherwise, clk_ctrl must be set before pll power down */
-		snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+		snd_soc_component_write(component, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
 
 		/* power down pll */
-		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
 			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
 			0);
 	}
@@ -794,8 +879,8 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
 				  struct snd_pcm_hw_params *params,
 				  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 	int channels = params_channels(params);
 	int i2s_ctl = 0;
 	int stereo;
@@ -803,7 +888,7 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	/* sysclk should already set */
 	if (!sgtl5000->sysclk) {
-		dev_err(codec->dev, "%s: set sysclk first!\n", __func__);
+		dev_err(component->dev, "%s: set sysclk first!\n", __func__);
 		return -EFAULT;
 	}
 
@@ -813,11 +898,11 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
 		stereo = SGTL5000_ADC_STEREO;
 
 	/* set mono to save power */
-	snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, stereo,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, stereo,
 			channels == 1 ? 0 : stereo);
 
 	/* set codec clock base on lrclk */
-	ret = sgtl5000_set_clock(codec, params_rate(params));
+	ret = sgtl5000_set_clock(component, params_rate(params));
 	if (ret)
 		return ret;
 
@@ -851,7 +936,7 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_I2S_CTRL,
 			    SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK,
 			    i2s_ctl);
 
@@ -868,19 +953,30 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
  * stop:
  * on --> prepare --> standby
  */
-static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
+static int sgtl5000_set_bias_level(struct snd_soc_component *component,
 				   enum snd_soc_bias_level level)
 {
+	struct sgtl5000_priv *sgtl = snd_soc_component_get_drvdata(component);
+	int ret;
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+		regcache_cache_only(sgtl->regmap, false);
+		ret = regcache_sync(sgtl->regmap);
+		if (ret) {
+			regcache_cache_only(sgtl->regmap, true);
+			return ret;
+		}
+
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
 				    SGTL5000_REFTOP_POWERUP,
 				    SGTL5000_REFTOP_POWERUP);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+		regcache_cache_only(sgtl->regmap, true);
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
 				    SGTL5000_REFTOP_POWERUP, 0);
 		break;
 	}
@@ -1020,7 +1116,7 @@ static const u8 vol_quot_table[] = {
  * 1. vddd provided by external or not
  * 2. vdda and vddio voltage value. > 3.1v or not
  */
-static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
+static int sgtl5000_set_power_regs(struct snd_soc_component *component)
 {
 	int vddd;
 	int vdda;
@@ -1032,7 +1128,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 	int vol_quot;
 	int lo_vol;
 	size_t i;
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 
 	vdda  = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
 	vddio = regulator_get_voltage(sgtl5000->supplies[VDDIO].consumer);
@@ -1045,14 +1141,14 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 	vddd  = vddd / 1000;
 
 	if (vdda <= 0 || vddio <= 0 || vddd < 0) {
-		dev_err(codec->dev, "regulator voltage not set correctly\n");
+		dev_err(component->dev, "regulator voltage not set correctly\n");
 
 		return -EINVAL;
 	}
 
 	/* according to datasheet, maximum voltage of supplies */
 	if (vdda > 3600 || vddio > 3600 || vddd > 1980) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"exceed max voltage vdda %dmV vddio %dmV vddd %dmV\n",
 			vdda, vddio, vddd);
 
@@ -1060,15 +1156,15 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 	}
 
 	/* reset value */
-	ana_pwr = snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER);
+	ana_pwr = snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER);
 	ana_pwr |= SGTL5000_DAC_STEREO |
 			SGTL5000_ADC_STEREO |
 			SGTL5000_REFTOP_POWERUP;
-	lreg_ctrl = snd_soc_read(codec, SGTL5000_CHIP_LINREG_CTRL);
+	lreg_ctrl = snd_soc_component_read32(component, SGTL5000_CHIP_LINREG_CTRL);
 
 	if (vddio < 3100 && vdda < 3100) {
 		/* enable internal oscillator used for charge pump */
-		snd_soc_update_bits(codec, SGTL5000_CHIP_CLK_TOP_CTRL,
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_CLK_TOP_CTRL,
 					SGTL5000_INT_OSC_EN,
 					SGTL5000_INT_OSC_EN);
 		/* Enable VDDC charge pump */
@@ -1081,9 +1177,9 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 			    SGTL5000_VDDC_MAN_ASSN_SHIFT;
 	}
 
-	snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl);
+	snd_soc_component_write(component, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl);
 
-	snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr);
+	snd_soc_component_write(component, SGTL5000_CHIP_ANA_POWER, ana_pwr);
 
 	/*
 	 * set ADC/DAC VAG to vdda / 2,
@@ -1098,7 +1194,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 	else
 		vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL,
 			SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
 
 	/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
@@ -1112,7 +1208,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 		lo_vag = (lo_vag - SGTL5000_LINE_OUT_GND_BASE) /
 		    SGTL5000_LINE_OUT_GND_STP;
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_LINE_OUT_CTRL,
 			SGTL5000_LINE_OUT_CURRENT_MASK |
 			SGTL5000_LINE_OUT_GND_MASK,
 			lo_vag << SGTL5000_LINE_OUT_GND_SHIFT |
@@ -1135,7 +1231,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
 			break;
 	}
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_VOL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_LINE_OUT_VOL,
 		SGTL5000_LINE_OUT_VOL_RIGHT_MASK |
 		SGTL5000_LINE_OUT_VOL_LEFT_MASK,
 		lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT |
@@ -1183,59 +1279,57 @@ static int sgtl5000_enable_regulators(struct i2c_client *client)
 	return ret;
 }
 
-static int sgtl5000_probe(struct snd_soc_codec *codec)
+static int sgtl5000_probe(struct snd_soc_component *component)
 {
 	int ret;
 	u16 reg;
-	struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
 
 	/* power up sgtl5000 */
-	ret = sgtl5000_set_power_regs(codec);
+	ret = sgtl5000_set_power_regs(component);
 	if (ret)
 		goto err;
 
 	/* enable small pop, introduce 400ms delay in turning off */
-	snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL,
 				SGTL5000_SMALL_POP, 1);
 
 	/* disable short cut detector */
-	snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0);
+	snd_soc_component_write(component, SGTL5000_CHIP_SHORT_CTRL, 0);
 
-	/*
-	 * set i2s as default input of sound switch
-	 * TODO: add sound switch to control and dapm widge.
-	 */
-	snd_soc_write(codec, SGTL5000_CHIP_SSS_CTRL,
-			SGTL5000_DAC_SEL_I2S_IN << SGTL5000_DAC_SEL_SHIFT);
-	snd_soc_write(codec, SGTL5000_CHIP_DIG_POWER,
+	snd_soc_component_write(component, SGTL5000_CHIP_DIG_POWER,
 			SGTL5000_ADC_EN | SGTL5000_DAC_EN);
 
 	/* enable dac volume ramp by default */
-	snd_soc_write(codec, SGTL5000_CHIP_ADCDAC_CTRL,
+	snd_soc_component_write(component, SGTL5000_CHIP_ADCDAC_CTRL,
 			SGTL5000_DAC_VOL_RAMP_EN |
 			SGTL5000_DAC_MUTE_RIGHT |
 			SGTL5000_DAC_MUTE_LEFT);
 
 	reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | 0x5f);
-	snd_soc_write(codec, SGTL5000_CHIP_PAD_STRENGTH, reg);
+	snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg);
 
-	snd_soc_write(codec, SGTL5000_CHIP_ANA_CTRL,
+	snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL,
 			SGTL5000_HP_ZCD_EN |
 			SGTL5000_ADC_ZCD_EN);
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
 			SGTL5000_BIAS_R_MASK,
 			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
 
-	snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
 			SGTL5000_BIAS_VOLT_MASK,
 			sgtl5000->micbias_voltage << SGTL5000_BIAS_VOLT_SHIFT);
 	/*
-	 * disable DAP
+	 * enable DAP Graphic EQ
 	 * TODO:
-	 * Enable DAP in kcontrol and dapm.
+	 * Add control for changing between PEQ/Tone Control/GEQ
 	 */
-	snd_soc_write(codec, SGTL5000_DAP_CTRL, 0);
+	snd_soc_component_write(component, SGTL5000_DAP_AUDIO_EQ, SGTL5000_DAP_SEL_GEQ);
+
+	/* Unmute DAC after start */
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_ADCDAC_CTRL,
+		SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT, 0);
 
 	return 0;
 
@@ -1243,24 +1337,20 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int sgtl5000_remove(struct snd_soc_codec *codec)
-{
-	return 0;
-}
-
-static const struct snd_soc_codec_driver sgtl5000_driver = {
-	.probe = sgtl5000_probe,
-	.remove = sgtl5000_remove,
-	.set_bias_level = sgtl5000_set_bias_level,
-	.suspend_bias_off = true,
-	.component_driver = {
-		.controls		= sgtl5000_snd_controls,
-		.num_controls		= ARRAY_SIZE(sgtl5000_snd_controls),
-		.dapm_widgets		= sgtl5000_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(sgtl5000_dapm_widgets),
-		.dapm_routes		= sgtl5000_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(sgtl5000_dapm_routes),
-	},
+static const struct snd_soc_component_driver sgtl5000_driver = {
+	.probe			= sgtl5000_probe,
+	.set_bias_level		= sgtl5000_set_bias_level,
+	.controls		= sgtl5000_snd_controls,
+	.num_controls		= ARRAY_SIZE(sgtl5000_snd_controls),
+	.dapm_widgets		= sgtl5000_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sgtl5000_dapm_widgets),
+	.dapm_routes		= sgtl5000_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sgtl5000_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sgtl5000_regmap = {
@@ -1459,7 +1549,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
 	/* Ensure sgtl5000 will start with sane register values */
 	sgtl5000_fill_defaults(client);
 
-	ret = snd_soc_register_codec(&client->dev,
+	ret = devm_snd_soc_register_component(&client->dev,
 			&sgtl5000_driver, &sgtl5000_dai, 1);
 	if (ret)
 		goto disable_clk;
@@ -1480,7 +1570,6 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
 {
 	struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
 	clk_disable_unprepare(sgtl5000->mclk);
 	regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies);
 	regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies);
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
index 22f3442af982..28cf637155bb 100644
--- a/sound/soc/codecs/sgtl5000.h
+++ b/sound/soc/codecs/sgtl5000.h
@@ -399,4 +399,11 @@
 #define SGTL5000_SYSCLK				0x00
 #define SGTL5000_LRCLK				0x01
 
+/*
+ * SGTL5000_DAP_AUDIO_EQ
+ */
+#define SGTL5000_DAP_SEL_PEQ			1
+#define SGTL5000_DAP_SEL_TONE_CTRL		2
+#define SGTL5000_DAP_SEL_GEQ			3
+
 #endif
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 7b91ee267b4e..b779c2855c01 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -140,14 +140,14 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 	si476x_core_lock(core);
 
-	err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
+	err = snd_soc_component_update_bits(codec_dai->component, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
 				  SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,
 				  format);
 
 	si476x_core_unlock(core);
 
 	if (err < 0) {
-		dev_err(codec_dai->codec->dev, "Failed to set output format\n");
+		dev_err(codec_dai->component->dev, "Failed to set output format\n");
 		return err;
 	}
 
@@ -163,7 +163,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
 
 	rate = params_rate(params);
 	if (rate < 32000 || rate > 48000) {
-		dev_err(dai->codec->dev, "Rate: %d is not supported\n", rate);
+		dev_err(dai->component->dev, "Rate: %d is not supported\n", rate);
 		return -EINVAL;
 	}
 
@@ -186,19 +186,19 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
 
 	si476x_core_lock(core);
 
-	err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,
+	err = snd_soc_component_write(dai->component, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,
 			    rate);
 	if (err < 0) {
-		dev_err(dai->codec->dev, "Failed to set sample rate\n");
+		dev_err(dai->component->dev, "Failed to set sample rate\n");
 		goto out;
 	}
 
-	err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
+	err = snd_soc_component_update_bits(dai->component, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
 				  SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
 				  (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
 				  (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
 	if (err < 0) {
-		dev_err(dai->codec->dev, "Failed to set output width\n");
+		dev_err(dai->component->dev, "Failed to set output width\n");
 		goto out;
 	}
 
@@ -239,28 +239,25 @@ static int si476x_probe(struct snd_soc_component *component)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_si476x = {
-	.component_driver = {
-		.probe			= si476x_probe,
-		.dapm_widgets		= si476x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(si476x_dapm_widgets),
-		.dapm_routes		= si476x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(si476x_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_si476x = {
+	.probe			= si476x_probe,
+	.dapm_widgets		= si476x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(si476x_dapm_widgets),
+	.dapm_routes		= si476x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(si476x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int si476x_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_si476x,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_si476x,
 				      &si476x_dai, 1);
 }
 
-static int si476x_platform_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 MODULE_ALIAS("platform:si476x-codec");
 
 static struct platform_driver si476x_platform_driver = {
@@ -268,7 +265,6 @@ static struct platform_driver si476x_platform_driver = {
 		.name	= "si476x-codec",
 	},
 	.probe		= si476x_platform_probe,
-	.remove		= si476x_platform_remove,
 };
 module_platform_driver(si476x_platform_driver);
 
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 7ae8c181d1a4..e424499a8450 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -120,8 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
 {
 #define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
 #define ATLAS6_CODEC_RESET_BITS (1 << 28)
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		enable_and_reset_codec(sirf_audio_codec->regmap,
@@ -143,8 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
 {
 #define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
 #define PRIMA2_CODEC_RESET_BITS (1 << 26)
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		enable_and_reset_codec(sirf_audio_codec->regmap,
@@ -333,8 +333,8 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
 		int cmd,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
 	int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
 	/*
@@ -346,7 +346,7 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (playback) {
-			snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+			snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
 				IC_HSLEN | IC_HSREN, 0);
 			sirf_audio_codec_tx_disable(sirf_audio_codec);
 		} else
@@ -357,7 +357,7 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (playback) {
 			sirf_audio_codec_tx_enable(sirf_audio_codec);
-			snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+			snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
 				IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
 		} else
 			sirf_audio_codec_rx_enable(sirf_audio_codec,
@@ -393,29 +393,29 @@ static struct snd_soc_dai_driver sirf_audio_codec_dai = {
 	.ops = &sirf_audio_codec_dai_ops,
 };
 
-static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
+static int sirf_audio_codec_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	pm_runtime_enable(codec->dev);
+	pm_runtime_enable(component->dev);
 
-	if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
+	if (of_device_is_compatible(component->dev->of_node, "sirf,prima2-audio-codec")) {
 		snd_soc_dapm_new_controls(dapm,
 			prima2_output_driver_dapm_widgets,
 			ARRAY_SIZE(prima2_output_driver_dapm_widgets));
 		snd_soc_dapm_new_controls(dapm,
 			&prima2_codec_clock_dapm_widget, 1);
-		return snd_soc_add_codec_controls(codec,
+		return snd_soc_add_component_controls(component,
 			volume_controls_prima2,
 			ARRAY_SIZE(volume_controls_prima2));
 	}
-	if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) {
+	if (of_device_is_compatible(component->dev->of_node, "sirf,atlas6-audio-codec")) {
 		snd_soc_dapm_new_controls(dapm,
 			atlas6_output_driver_dapm_widgets,
 			ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
 		snd_soc_dapm_new_controls(dapm,
 			&atlas6_codec_clock_dapm_widget, 1);
-		return snd_soc_add_codec_controls(codec,
+		return snd_soc_add_component_controls(component,
 			volume_controls_atlas6,
 			ARRAY_SIZE(volume_controls_atlas6));
 	}
@@ -423,22 +423,21 @@ static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
 	return -EINVAL;
 }
 
-static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
+static void sirf_audio_codec_remove(struct snd_soc_component *component)
 {
-	pm_runtime_disable(codec->dev);
-	return 0;
+	pm_runtime_disable(component->dev);
 }
 
-static const struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
-	.probe = sirf_audio_codec_probe,
-	.remove = sirf_audio_codec_remove,
-	.component_driver = {
-		.dapm_widgets = sirf_audio_codec_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
-		.dapm_routes = sirf_audio_codec_map,
-		.num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
-	},
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_codec_device_sirf_audio_codec = {
+	.probe			= sirf_audio_codec_probe,
+	.remove			= sirf_audio_codec_remove,
+	.dapm_widgets		= sirf_audio_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
+	.dapm_routes		= sirf_audio_codec_map,
+	.num_dapm_routes	= ARRAY_SIZE(sirf_audio_codec_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id sirf_audio_codec_of_match[] = {
@@ -495,7 +494,7 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&(pdev->dev),
+	ret = devm_snd_soc_register_component(&(pdev->dev),
 			&soc_codec_device_sirf_audio_codec,
 			&sirf_audio_codec_dai, 1);
 	if (ret) {
@@ -525,7 +524,6 @@ static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
 	struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
 
 	clk_disable_unprepare(sirf_audio_codec->clk);
-	snd_soc_unregister_codec(&(pdev->dev));
 
 	return 0;
 }
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index c8fd6367f6c0..ac69d495d121 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -38,13 +38,15 @@ static const struct snd_soc_dapm_route dir_routes[] = {
 			SNDRV_PCM_FMTBIT_S32_LE | \
 			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
-static struct snd_soc_codec_driver soc_codec_spdif_dir = {
-	.component_driver = {
-		.dapm_widgets		= dir_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(dir_widgets),
-		.dapm_routes		= dir_routes,
-		.num_dapm_routes	= ARRAY_SIZE(dir_routes),
-	},
+static struct snd_soc_component_driver soc_codec_spdif_dir = {
+	.dapm_widgets		= dir_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dir_widgets),
+	.dapm_routes		= dir_routes,
+	.num_dapm_routes	= ARRAY_SIZE(dir_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct snd_soc_dai_driver dir_stub_dai = {
@@ -60,16 +62,11 @@ static struct snd_soc_dai_driver dir_stub_dai = {
 
 static int spdif_dir_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dir,
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_codec_spdif_dir,
 			&dir_stub_dai, 1);
 }
 
-static int spdif_dir_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id spdif_dir_dt_ids[] = {
 	{ .compatible = "linux,spdif-dir", },
@@ -80,7 +77,6 @@ MODULE_DEVICE_TABLE(of, spdif_dir_dt_ids);
 
 static struct platform_driver spdif_dir_driver = {
 	.probe		= spdif_dir_probe,
-	.remove		= spdif_dir_remove,
 	.driver		= {
 		.name	= "spdif-dir",
 		.of_match_table = of_match_ptr(spdif_dir_dt_ids),
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index 037aa1d45559..b4f7fc4acb39 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -38,13 +38,15 @@ static const struct snd_soc_dapm_route dit_routes[] = {
 	{ "spdif-out", NULL, "Playback" },
 };
 
-static struct snd_soc_codec_driver soc_codec_spdif_dit = {
-	.component_driver = {
-		.dapm_widgets		= dit_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(dit_widgets),
-		.dapm_routes		= dit_routes,
-		.num_dapm_routes	= ARRAY_SIZE(dit_routes),
-	},
+static struct snd_soc_component_driver soc_codec_spdif_dit = {
+	.dapm_widgets		= dit_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dit_widgets),
+	.dapm_routes		= dit_routes,
+	.num_dapm_routes	= ARRAY_SIZE(dit_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct snd_soc_dai_driver dit_stub_dai = {
@@ -60,16 +62,11 @@ static struct snd_soc_dai_driver dit_stub_dai = {
 
 static int spdif_dit_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_codec_spdif_dit,
 			&dit_stub_dai, 1);
 }
 
-static int spdif_dit_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id spdif_dit_dt_ids[] = {
 	{ .compatible = "linux,spdif-dit", },
@@ -80,7 +77,6 @@ MODULE_DEVICE_TABLE(of, spdif_dit_dt_ids);
 
 static struct platform_driver spdif_dit_driver = {
 	.probe		= spdif_dit_probe,
-	.remove		= spdif_dit_remove,
 	.driver		= {
 		.name	= DRV_NAME,
 		.of_match_table = of_match_ptr(spdif_dit_dt_ids),
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 15486fd16269..4a1d42a33030 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -336,8 +336,8 @@ static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
 static int ssm2518_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
 	unsigned int rate = params_rate(params);
 	unsigned int ctrl1, ctrl1_mask;
 	int mcs;
@@ -391,7 +391,7 @@ static int ssm2518_hw_params(struct snd_pcm_substream *substream,
 
 static int ssm2518_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int val;
 
 	if (mute)
@@ -405,7 +405,7 @@ static int ssm2518_mute(struct snd_soc_dai *dai, int mute)
 
 static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int ctrl1 = 0, ctrl2 = 0;
 	bool invert_fclk;
 	int ret;
@@ -498,10 +498,10 @@ static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable)
 	return ret;
 }
 
-static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
+static int ssm2518_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (level) {
@@ -510,7 +510,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			ret = ssm2518_set_power(ssm2518, true);
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -524,7 +524,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
 static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	unsigned int rx_mask, int slots, int width)
 {
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int ctrl1, ctrl2;
 	int left_slot, right_slot;
 	int ret;
@@ -609,7 +609,7 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int ssm2518_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
 
 	if (ssm2518->constraints)
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -641,10 +641,10 @@ static struct snd_soc_dai_driver ssm2518_dai = {
 	.ops = &ssm2518_dai_ops,
 };
 
-static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int ssm2518_set_sysclk(struct snd_soc_component *component, int clk_id,
 	int source, unsigned int freq, int dir)
 {
-	struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 
 	if (clk_id != SSM2518_SYSCLK)
@@ -710,19 +710,18 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 			SSM2518_POWER1_NO_BCLK, val);
 }
 
-static const struct snd_soc_codec_driver ssm2518_codec_driver = {
-	.set_bias_level = ssm2518_set_bias_level,
-	.set_sysclk = ssm2518_set_sysclk,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= ssm2518_snd_controls,
-		.num_controls		= ARRAY_SIZE(ssm2518_snd_controls),
-		.dapm_widgets		= ssm2518_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ssm2518_dapm_widgets),
-		.dapm_routes		= ssm2518_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ssm2518_routes),
-	},
+static const struct snd_soc_component_driver ssm2518_component_driver = {
+	.set_bias_level		= ssm2518_set_bias_level,
+	.set_sysclk		= ssm2518_set_sysclk,
+	.controls		= ssm2518_snd_controls,
+	.num_controls		= ARRAY_SIZE(ssm2518_snd_controls),
+	.dapm_widgets		= ssm2518_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm2518_dapm_widgets),
+	.dapm_routes		= ssm2518_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm2518_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ssm2518_regmap_config = {
@@ -792,16 +791,11 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c,
 	if (ret)
 		return ret;
 
-	return snd_soc_register_codec(&i2c->dev, &ssm2518_codec_driver,
+	return devm_snd_soc_register_component(&i2c->dev,
+			&ssm2518_component_driver,
 			&ssm2518_dai, 1);
 }
 
-static int ssm2518_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id ssm2518_dt_ids[] = {
 	{ .compatible = "adi,ssm2518", },
@@ -822,7 +816,6 @@ static struct i2c_driver ssm2518_driver = {
 		.of_match_table = of_match_ptr(ssm2518_dt_ids),
 	},
 	.probe = ssm2518_i2c_probe,
-	.remove = ssm2518_i2c_remove,
 	.id_table = ssm2518_i2c_ids,
 };
 module_i2c_driver(ssm2518_driver);
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
index 173ba85ff59e..f1c2b1a3ada3 100644
--- a/sound/soc/codecs/ssm2602-i2c.c
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -27,12 +27,6 @@ static int ssm2602_i2c_probe(struct i2c_client *client,
 		devm_regmap_init_i2c(client, &ssm2602_regmap_config));
 }
 
-static int ssm2602_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id ssm2602_i2c_id[] = {
 	{ "ssm2602", SSM2602 },
 	{ "ssm2603", SSM2602 },
@@ -55,7 +49,6 @@ static struct i2c_driver ssm2602_i2c_driver = {
 		.of_match_table = ssm2602_of_match,
 	},
 	.probe = ssm2602_i2c_probe,
-	.remove = ssm2602_i2c_remove,
 	.id_table = ssm2602_i2c_id,
 };
 module_i2c_driver(ssm2602_i2c_driver);
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c
index 842f373045c6..8848628571a1 100644
--- a/sound/soc/codecs/ssm2602-spi.c
+++ b/sound/soc/codecs/ssm2602-spi.c
@@ -20,12 +20,6 @@ static int ssm2602_spi_probe(struct spi_device *spi)
 		devm_regmap_init_spi(spi, &ssm2602_regmap_config));
 }
 
-static int ssm2602_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static const struct of_device_id ssm2602_of_match[] = {
 	{ .compatible = "adi,ssm2602", },
 	{ }
@@ -38,7 +32,6 @@ static struct spi_driver ssm2602_spi_driver = {
 		.of_match_table = ssm2602_of_match,
 	},
 	.probe		= ssm2602_spi_probe,
-	.remove		= ssm2602_spi_remove,
 };
 module_spi_driver(ssm2602_spi_driver);
 
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 9b341c23f62b..031e0eabcc1f 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -273,8 +273,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
 	unsigned int iface;
 
@@ -308,8 +308,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 static int ssm2602_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 
 	if (ssm2602->sysclk_constraints) {
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -322,7 +322,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
 
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(dai->component);
 
 	if (mute)
 		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
@@ -337,8 +337,8 @@ static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 
 	if (dir == SND_SOC_CLOCK_IN) {
 		if (clk_id != SSM2602_SYSCLK)
@@ -389,7 +389,7 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec_dai->codec);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(codec_dai->component);
 	unsigned int iface = 0;
 
 	/* set master/slave audio interface */
@@ -445,10 +445,10 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
+static int ssm2602_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -511,19 +511,19 @@ static struct snd_soc_dai_driver ssm2602_dai = {
 	.symmetric_samplebits = 1,
 };
 
-static int ssm2602_resume(struct snd_soc_codec *codec)
+static int ssm2602_resume(struct snd_soc_component *component)
 {
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 
 	regcache_sync(ssm2602->regmap);
 
 	return 0;
 }
 
-static int ssm2602_codec_probe(struct snd_soc_codec *codec)
+static int ssm2602_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
@@ -531,7 +531,7 @@ static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 	regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
 			    ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
 
-	ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls,
+	ret = snd_soc_add_component_controls(component, ssm2602_snd_controls,
 			ARRAY_SIZE(ssm2602_snd_controls));
 	if (ret)
 		return ret;
@@ -545,9 +545,9 @@ static int ssm2602_codec_probe(struct snd_soc_codec *codec)
 			ARRAY_SIZE(ssm2602_routes));
 }
 
-static int ssm2604_codec_probe(struct snd_soc_codec *codec)
+static int ssm2604_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int ret;
 
 	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
@@ -559,14 +559,14 @@ static int ssm2604_codec_probe(struct snd_soc_codec *codec)
 			ARRAY_SIZE(ssm2604_routes));
 }
 
-static int ssm260x_codec_probe(struct snd_soc_codec *codec)
+static int ssm260x_component_probe(struct snd_soc_component *component)
 {
-	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		return ret;
 	}
 
@@ -581,30 +581,31 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec)
 
 	switch (ssm2602->type) {
 	case SSM2602:
-		ret = ssm2602_codec_probe(codec);
+		ret = ssm2602_component_probe(component);
 		break;
 	case SSM2604:
-		ret = ssm2604_codec_probe(codec);
+		ret = ssm2604_component_probe(component);
 		break;
 	}
 
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
-	.probe =	ssm260x_codec_probe,
-	.resume =	ssm2602_resume,
-	.set_bias_level = ssm2602_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= ssm260x_snd_controls,
-		.num_controls		= ARRAY_SIZE(ssm260x_snd_controls),
-		.dapm_widgets		= ssm260x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ssm260x_dapm_widgets),
-		.dapm_routes		= ssm260x_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ssm260x_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_ssm2602 = {
+	.probe			= ssm260x_component_probe,
+	.resume			= ssm2602_resume,
+	.set_bias_level		= ssm2602_set_bias_level,
+	.controls		= ssm260x_snd_controls,
+	.num_controls		= ARRAY_SIZE(ssm260x_snd_controls),
+	.dapm_widgets		= ssm260x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm260x_dapm_widgets),
+	.dapm_routes		= ssm260x_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm260x_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
@@ -641,7 +642,7 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type,
 	ssm2602->type = type;
 	ssm2602->regmap = regmap;
 
-	return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602,
+	return devm_snd_soc_register_component(dev, &soc_component_dev_ssm2602,
 		&ssm2602_dai, 1);
 }
 EXPORT_SYMBOL_GPL(ssm2602_probe);
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 4afeddef7728..90119ea00498 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -199,8 +199,8 @@ static const struct snd_soc_dapm_route ssm4567_routes[] = {
 static int ssm4567_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
 	unsigned int rate = params_rate(params);
 	unsigned int dacfs;
 
@@ -223,7 +223,7 @@ static int ssm4567_hw_params(struct snd_pcm_substream *substream,
 
 static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(dai->codec);
+	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(dai->component);
 	unsigned int val;
 
 	val = mute ? SSM4567_DAC_MUTE : 0;
@@ -366,10 +366,10 @@ static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
 	return ret;
 }
 
-static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
+static int ssm4567_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec);
+	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (level) {
@@ -378,7 +378,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			ret = ssm4567_set_power(ssm4567, true);
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -417,18 +417,17 @@ static struct snd_soc_dai_driver ssm4567_dai = {
 	.ops = &ssm4567_dai_ops,
 };
 
-static const struct snd_soc_codec_driver ssm4567_codec_driver = {
-	.set_bias_level = ssm4567_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= ssm4567_snd_controls,
-		.num_controls		= ARRAY_SIZE(ssm4567_snd_controls),
-		.dapm_widgets		= ssm4567_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(ssm4567_dapm_widgets),
-		.dapm_routes		= ssm4567_routes,
-		.num_dapm_routes	= ARRAY_SIZE(ssm4567_routes),
-	},
+static const struct snd_soc_component_driver ssm4567_component_driver = {
+	.set_bias_level		= ssm4567_set_bias_level,
+	.controls		= ssm4567_snd_controls,
+	.num_controls		= ARRAY_SIZE(ssm4567_snd_controls),
+	.dapm_widgets		= ssm4567_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm4567_dapm_widgets),
+	.dapm_routes		= ssm4567_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm4567_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config ssm4567_regmap_config = {
@@ -469,16 +468,10 @@ static int ssm4567_i2c_probe(struct i2c_client *i2c,
 	if (ret)
 		return ret;
 
-	return snd_soc_register_codec(&i2c->dev, &ssm4567_codec_driver,
+	return devm_snd_soc_register_component(&i2c->dev, &ssm4567_component_driver,
 			&ssm4567_dai, 1);
 }
 
-static int ssm4567_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id ssm4567_i2c_ids[] = {
 	{ "ssm4567", 0 },
 	{ }
@@ -510,7 +503,6 @@ static struct i2c_driver ssm4567_driver = {
 		.acpi_match_table = ACPI_PTR(ssm4567_acpi_match),
 	},
 	.probe = ssm4567_i2c_probe,
-	.remove = ssm4567_i2c_remove,
 	.id_table = ssm4567_i2c_ids,
 };
 module_i2c_driver(ssm4567_driver);
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 5b888476d9ff..d5035f2f2b2b 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -143,7 +143,7 @@ static const char *sta32x_supply_names[] = {
 struct sta32x_priv {
 	struct regmap *regmap;
 	struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct sta32x_platform_data *pdata;
 
 	unsigned int mclk;
@@ -270,8 +270,8 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
 static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
 	unsigned int cfud, val;
@@ -312,8 +312,8 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
 static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
 	unsigned int cfud;
@@ -347,9 +347,9 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
+static int sta32x_sync_coef_shadow(struct snd_soc_component *component)
 {
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	unsigned int cfud;
 	int i;
 
@@ -375,16 +375,16 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int sta32x_cache_sync(struct snd_soc_codec *codec)
+static int sta32x_cache_sync(struct snd_soc_component *component)
 {
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	unsigned int mute;
 	int rc;
 
 	/* mute during register sync */
 	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
-	sta32x_sync_coef_shadow(codec);
+	sta32x_sync_coef_shadow(component);
 	rc = regcache_sync(sta32x->regmap);
 	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
 	return rc;
@@ -395,17 +395,17 @@ static void sta32x_watchdog(struct work_struct *work)
 {
 	struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
 						  watchdog_work.work);
-	struct snd_soc_codec *codec = sta32x->codec;
+	struct snd_soc_component *component = sta32x->component;
 	unsigned int confa, confa_cached;
 
 	/* check if sta32x has reset itself */
-	confa_cached = snd_soc_read(codec, STA32X_CONFA);
+	confa_cached = snd_soc_component_read32(component, STA32X_CONFA);
 	regcache_cache_bypass(sta32x->regmap, true);
-	confa = snd_soc_read(codec, STA32X_CONFA);
+	confa = snd_soc_component_read32(component, STA32X_CONFA);
 	regcache_cache_bypass(sta32x->regmap, false);
 	if (confa != confa_cached) {
 		regcache_mark_dirty(sta32x->regmap);
-		sta32x_cache_sync(codec);
+		sta32x_cache_sync(component);
 	}
 
 	if (!sta32x->shutdown)
@@ -582,10 +582,10 @@ static int mcs_ratio_table[3][7] = {
 static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "mclk=%u\n", freq);
+	dev_dbg(component->dev, "mclk=%u\n", freq);
 	sta32x->mclk = freq;
 
 	return 0;
@@ -602,8 +602,8 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	u8 confb = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -651,22 +651,22 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	int i, mcs = -EINVAL, ir = -EINVAL;
 	unsigned int confa, confb;
 	unsigned int rate, ratio;
 	int ret;
 
 	if (!sta32x->mclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"sta32x->mclk is unset. Unable to determine ratio\n");
 		return -EIO;
 	}
 
 	rate = params_rate(params);
 	ratio = sta32x->mclk / rate;
-	dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+	dev_dbg(component->dev, "rate: %u, ratio: %u\n", rate, ratio);
 
 	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
 		if (interpolation_ratios[i].fs == rate) {
@@ -676,7 +676,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (ir < 0) {
-		dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
+		dev_err(component->dev, "Unsupported samplerate: %u\n", rate);
 		return -EINVAL;
 	}
 
@@ -688,7 +688,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (mcs < 0) {
-		dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
+		dev_err(component->dev, "Unresolvable ratio: %u\n", ratio);
 		return -EINVAL;
 	}
 
@@ -698,10 +698,10 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_width(params)) {
 	case 24:
-		dev_dbg(codec->dev, "24bit\n");
+		dev_dbg(component->dev, "24bit\n");
 		/* fall through */
 	case 32:
-		dev_dbg(codec->dev, "24bit or 32bit\n");
+		dev_dbg(component->dev, "24bit or 32bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x0;
@@ -716,7 +716,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 20:
-		dev_dbg(codec->dev, "20bit\n");
+		dev_dbg(component->dev, "20bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x4;
@@ -731,7 +731,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 18:
-		dev_dbg(codec->dev, "18bit\n");
+		dev_dbg(component->dev, "18bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x8;
@@ -746,7 +746,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 16:
-		dev_dbg(codec->dev, "16bit\n");
+		dev_dbg(component->dev, "16bit\n");
 		switch (sta32x->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x0;
@@ -793,20 +793,20 @@ static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
 
 /**
  * sta32x_set_bias_level - DAPM callback
- * @codec: the codec device
+ * @component: the component device
  * @level: DAPM power level
  *
- * This is called by ALSA to put the codec into low power mode
- * or to wake it up.  If the codec is powered off completely
+ * This is called by ALSA to put the component into low power mode
+ * or to wake it up.  If the component is powered off completely
  * all registers must be restored after power on.
  */
-static int sta32x_set_bias_level(struct snd_soc_codec *codec,
+static int sta32x_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	int ret;
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "level = %d\n", level);
+	dev_dbg(component->dev, "level = %d\n", level);
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
@@ -819,17 +819,17 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
 						    sta32x->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n", ret);
 				return ret;
 			}
 
 			sta32x_startup_sequence(sta32x);
-			sta32x_cache_sync(codec);
+			sta32x_cache_sync(component);
 			sta32x_watchdog_start(sta32x);
 		}
 
@@ -874,21 +874,21 @@ static struct snd_soc_dai_driver sta32x_dai = {
 	.ops = &sta32x_dai_ops,
 };
 
-static int sta32x_probe(struct snd_soc_codec *codec)
+static int sta32x_probe(struct snd_soc_component *component)
 {
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 	struct sta32x_platform_data *pdata = sta32x->pdata;
 	int i, ret = 0, thermal = 0;
 	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
 				    sta32x->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
 	ret = sta32x_startup_sequence(sta32x);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to startup device\n");
+		dev_err(component->dev, "Failed to startup device\n");
 		return ret;
 	}
 
@@ -968,36 +968,36 @@ static int sta32x_probe(struct snd_soc_codec *codec)
 	if (sta32x->pdata->needs_esd_watchdog)
 		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 
 	return 0;
 }
 
-static int sta32x_remove(struct snd_soc_codec *codec)
+static void sta32x_remove(struct snd_soc_component *component)
 {
-	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
 
 	sta32x_watchdog_stop(sta32x);
 	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver sta32x_codec = {
-	.probe =		sta32x_probe,
-	.remove =		sta32x_remove,
-	.set_bias_level =	sta32x_set_bias_level,
-	.suspend_bias_off =	true,
-	.component_driver = {
-		.controls =		sta32x_snd_controls,
-		.num_controls =		ARRAY_SIZE(sta32x_snd_controls),
-		.dapm_widgets =		sta32x_dapm_widgets,
-		.num_dapm_widgets =	ARRAY_SIZE(sta32x_dapm_widgets),
-		.dapm_routes =		sta32x_dapm_routes,
-		.num_dapm_routes =	ARRAY_SIZE(sta32x_dapm_routes),
-	},
+static const struct snd_soc_component_driver sta32x_component = {
+	.probe			= sta32x_probe,
+	.remove			= sta32x_remove,
+	.set_bias_level		= sta32x_set_bias_level,
+	.controls		= sta32x_snd_controls,
+	.num_controls		= ARRAY_SIZE(sta32x_snd_controls),
+	.dapm_widgets		= sta32x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sta32x_dapm_widgets),
+	.dapm_routes		= sta32x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sta32x_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sta32x_regmap = {
@@ -1121,19 +1121,14 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, sta32x);
 
-	ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
+	ret = devm_snd_soc_register_component(dev, &sta32x_component,
+					      &sta32x_dai, 1);
 	if (ret < 0)
-		dev_err(dev, "Failed to register codec (%d)\n", ret);
+		dev_err(dev, "Failed to register component (%d)\n", ret);
 
 	return ret;
 }
 
-static int sta32x_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id sta32x_i2c_id[] = {
 	{ "sta326", 0 },
 	{ "sta328", 0 },
@@ -1148,7 +1143,6 @@ static struct i2c_driver sta32x_i2c_driver = {
 		.of_match_table = of_match_ptr(st32x_dt_ids),
 	},
 	.probe =    sta32x_i2c_probe,
-	.remove =   sta32x_i2c_remove,
 	.id_table = sta32x_i2c_id,
 };
 
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 9644c20f44e3..0b870319b106 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -309,8 +309,8 @@ static int sta350_coefficient_info(struct snd_kcontrol *kcontrol,
 static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
 	unsigned int cfud, val;
@@ -351,8 +351,8 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
 static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
 	unsigned int cfud;
@@ -386,9 +386,9 @@ static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static int sta350_sync_coef_shadow(struct snd_soc_codec *codec)
+static int sta350_sync_coef_shadow(struct snd_soc_component *component)
 {
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	unsigned int cfud;
 	int i;
 
@@ -414,16 +414,16 @@ static int sta350_sync_coef_shadow(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int sta350_cache_sync(struct snd_soc_codec *codec)
+static int sta350_cache_sync(struct snd_soc_component *component)
 {
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	unsigned int mute;
 	int rc;
 
 	/* mute during register sync */
 	regmap_read(sta350->regmap, STA350_CFUD, &mute);
 	regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE);
-	sta350_sync_coef_shadow(codec);
+	sta350_sync_coef_shadow(component);
 	rc = regcache_sync(sta350->regmap);
 	regmap_write(sta350->regmap, STA350_MMUTE, mute);
 	return rc;
@@ -613,10 +613,10 @@ static int mcs_ratio_table[3][6] = {
 static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "mclk=%u\n", freq);
+	dev_dbg(component->dev, "mclk=%u\n", freq);
 	sta350->mclk = freq;
 
 	return 0;
@@ -633,8 +633,8 @@ static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	unsigned int confb = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -682,22 +682,22 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	int i, mcs = -EINVAL, ir = -EINVAL;
 	unsigned int confa, confb;
 	unsigned int rate, ratio;
 	int ret;
 
 	if (!sta350->mclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"sta350->mclk is unset. Unable to determine ratio\n");
 		return -EIO;
 	}
 
 	rate = params_rate(params);
 	ratio = sta350->mclk / rate;
-	dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+	dev_dbg(component->dev, "rate: %u, ratio: %u\n", rate, ratio);
 
 	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
 		if (interpolation_ratios[i].fs == rate) {
@@ -707,7 +707,7 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (ir < 0) {
-		dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
+		dev_err(component->dev, "Unsupported samplerate: %u\n", rate);
 		return -EINVAL;
 	}
 
@@ -719,7 +719,7 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (mcs < 0) {
-		dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
+		dev_err(component->dev, "Unresolvable ratio: %u\n", ratio);
 		return -EINVAL;
 	}
 
@@ -729,10 +729,10 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 
 	switch (params_width(params)) {
 	case 24:
-		dev_dbg(codec->dev, "24bit\n");
+		dev_dbg(component->dev, "24bit\n");
 		/* fall through */
 	case 32:
-		dev_dbg(codec->dev, "24bit or 32bit\n");
+		dev_dbg(component->dev, "24bit or 32bit\n");
 		switch (sta350->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x0;
@@ -747,7 +747,7 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 20:
-		dev_dbg(codec->dev, "20bit\n");
+		dev_dbg(component->dev, "20bit\n");
 		switch (sta350->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x4;
@@ -762,7 +762,7 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 18:
-		dev_dbg(codec->dev, "18bit\n");
+		dev_dbg(component->dev, "18bit\n");
 		switch (sta350->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x8;
@@ -777,7 +777,7 @@ static int sta350_hw_params(struct snd_pcm_substream *substream,
 
 		break;
 	case 16:
-		dev_dbg(codec->dev, "16bit\n");
+		dev_dbg(component->dev, "16bit\n");
 		switch (sta350->format) {
 		case SND_SOC_DAIFMT_I2S:
 			confb |= 0x0;
@@ -827,20 +827,20 @@ static int sta350_startup_sequence(struct sta350_priv *sta350)
 
 /**
  * sta350_set_bias_level - DAPM callback
- * @codec: the codec device
+ * @component: the component device
  * @level: DAPM power level
  *
- * This is called by ALSA to put the codec into low power mode
- * or to wake it up.  If the codec is powered off completely
+ * This is called by ALSA to put the component into low power mode
+ * or to wake it up.  If the component is powered off completely
  * all registers must be restored after power on.
  */
-static int sta350_set_bias_level(struct snd_soc_codec *codec,
+static int sta350_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	dev_dbg(codec->dev, "level = %d\n", level);
+	dev_dbg(component->dev, "level = %d\n", level);
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
@@ -853,18 +853,18 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(
 				ARRAY_SIZE(sta350->supplies),
 				sta350->supplies);
 			if (ret < 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
 			}
 			sta350_startup_sequence(sta350);
-			sta350_cache_sync(codec);
+			sta350_cache_sync(component);
 		}
 
 		/* Power down */
@@ -911,22 +911,22 @@ static struct snd_soc_dai_driver sta350_dai = {
 	.ops = &sta350_dai_ops,
 };
 
-static int sta350_probe(struct snd_soc_codec *codec)
+static int sta350_probe(struct snd_soc_component *component)
 {
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 	struct sta350_platform_data *pdata = sta350->pdata;
 	int i, ret = 0, thermal = 0;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies),
 				    sta350->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
 	ret = sta350_startup_sequence(sta350);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to startup device\n");
+		dev_err(component->dev, "Failed to startup device\n");
 		return ret;
 	}
 
@@ -1036,35 +1036,35 @@ static int sta350_probe(struct snd_soc_codec *codec)
 	sta350->coef_shadow[60] = 0x400000;
 	sta350->coef_shadow[61] = 0x400000;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
 
 	return 0;
 }
 
-static int sta350_remove(struct snd_soc_codec *codec)
+static void sta350_remove(struct snd_soc_component *component)
 {
-	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
 
 	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver sta350_codec = {
-	.probe =		sta350_probe,
-	.remove =		sta350_remove,
-	.set_bias_level =	sta350_set_bias_level,
-	.suspend_bias_off =	true,
-	.component_driver = {
-		.controls =		sta350_snd_controls,
-		.num_controls =		ARRAY_SIZE(sta350_snd_controls),
-		.dapm_widgets =		sta350_dapm_widgets,
-		.num_dapm_widgets =	ARRAY_SIZE(sta350_dapm_widgets),
-		.dapm_routes =		sta350_dapm_routes,
-		.num_dapm_routes =	ARRAY_SIZE(sta350_dapm_routes),
-	},
+static const struct snd_soc_component_driver sta350_component = {
+	.probe			= sta350_probe,
+	.remove			= sta350_remove,
+	.set_bias_level		= sta350_set_bias_level,
+	.controls		= sta350_snd_controls,
+	.num_controls		= ARRAY_SIZE(sta350_snd_controls),
+	.dapm_widgets		= sta350_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sta350_dapm_widgets),
+	.dapm_routes		= sta350_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sta350_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sta350_regmap = {
@@ -1244,16 +1244,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, sta350);
 
-	ret = snd_soc_register_codec(dev, &sta350_codec, &sta350_dai, 1);
+	ret = devm_snd_soc_register_component(dev, &sta350_component, &sta350_dai, 1);
 	if (ret < 0)
-		dev_err(dev, "Failed to register codec (%d)\n", ret);
+		dev_err(dev, "Failed to register component (%d)\n", ret);
 
 	return ret;
 }
 
 static int sta350_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 660734359bf3..2881a0f7bb39 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -151,28 +151,28 @@ static const struct snd_kcontrol_new sta529_snd_controls[] = {
 	SOC_ENUM("PWM Select", pwm_src),
 };
 
-static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
+static int sta529_set_bias_level(struct snd_soc_component *component, enum
 		snd_soc_bias_level level)
 {
-	struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
+	struct sta529 *sta529 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
+		snd_soc_component_update_bits(component, STA529_FFXCFG0, POWER_CNTLMSAK,
 				POWER_UP);
-		snd_soc_update_bits(codec, STA529_MISC,	FFX_CLK_MSK,
+		snd_soc_component_update_bits(component, STA529_MISC,	FFX_CLK_MSK,
 				FFX_CLK_ENB);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			regcache_sync(sta529->regmap);
-		snd_soc_update_bits(codec, STA529_FFXCFG0,
+		snd_soc_component_update_bits(component, STA529_FFXCFG0,
 					POWER_CNTLMSAK, POWER_STDBY);
 		/* Making FFX output to zero */
-		snd_soc_update_bits(codec, STA529_FFXCFG0, FFX_MASK,
+		snd_soc_component_update_bits(component, STA529_FFXCFG0, FFX_MASK,
 				FFX_OFF);
-		snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK,
+		snd_soc_component_update_bits(component, STA529_MISC, FFX_CLK_MSK,
 				FFX_CLK_DIS);
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -187,7 +187,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int pdata, play_freq_val, record_freq_val;
 	int bclk_to_fs_ratio;
 
@@ -205,7 +205,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
 		bclk_to_fs_ratio = 2;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported format\n");
+		dev_err(component->dev, "Unsupported format\n");
 		return -EINVAL;
 	}
 
@@ -228,23 +228,23 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
 		record_freq_val = 0;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported rate\n");
+		dev_err(component->dev, "Unsupported rate\n");
 		return -EINVAL;
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		snd_soc_update_bits(codec, STA529_S2PCFG1, PDATA_LEN_MSK,
+		snd_soc_component_update_bits(component, STA529_S2PCFG1, PDATA_LEN_MSK,
 				pdata << 6);
-		snd_soc_update_bits(codec, STA529_S2PCFG1, BCLK_TO_FS_MSK,
+		snd_soc_component_update_bits(component, STA529_S2PCFG1, BCLK_TO_FS_MSK,
 				bclk_to_fs_ratio << 4);
-		snd_soc_update_bits(codec, STA529_MISC, PLAY_FREQ_RANGE_MSK,
+		snd_soc_component_update_bits(component, STA529_MISC, PLAY_FREQ_RANGE_MSK,
 				play_freq_val << 4);
 	} else {
-		snd_soc_update_bits(codec, STA529_P2SCFG1, PDATA_LEN_MSK,
+		snd_soc_component_update_bits(component, STA529_P2SCFG1, PDATA_LEN_MSK,
 				pdata << 6);
-		snd_soc_update_bits(codec, STA529_P2SCFG1, BCLK_TO_FS_MSK,
+		snd_soc_component_update_bits(component, STA529_P2SCFG1, BCLK_TO_FS_MSK,
 				bclk_to_fs_ratio << 4);
-		snd_soc_update_bits(codec, STA529_MISC, CAP_FREQ_RANGE_MSK,
+		snd_soc_component_update_bits(component, STA529_MISC, CAP_FREQ_RANGE_MSK,
 				record_freq_val << 2);
 	}
 
@@ -258,14 +258,14 @@ static int sta529_mute(struct snd_soc_dai *dai, int mute)
 	if (mute)
 		val |= CODEC_MUTE_VAL;
 
-	snd_soc_update_bits(dai->codec, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
+	snd_soc_component_update_bits(dai->component, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
 
 	return 0;
 }
 
 static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 mode = 0;
 
 	/* interface format */
@@ -283,7 +283,7 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
+	snd_soc_component_update_bits(component, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
 
 	return 0;
 }
@@ -313,14 +313,15 @@ static struct snd_soc_dai_driver sta529_dai = {
 	.ops	= &sta529_dai_ops,
 };
 
-static const struct snd_soc_codec_driver sta529_codec_driver = {
-	.set_bias_level = sta529_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= sta529_snd_controls,
-		.num_controls		= ARRAY_SIZE(sta529_snd_controls),
-	},
+static const struct snd_soc_component_driver sta529_component_driver = {
+	.set_bias_level		= sta529_set_bias_level,
+	.controls		= sta529_snd_controls,
+	.num_controls		= ARRAY_SIZE(sta529_snd_controls),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sta529_regmap = {
@@ -354,21 +355,14 @@ static int sta529_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, sta529);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&sta529_codec_driver, &sta529_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&sta529_component_driver, &sta529_dai, 1);
 	if (ret != 0)
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
 
 	return ret;
 }
 
-static int sta529_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id sta529_i2c_id[] = {
 	{ "sta529", 0 },
 	{ }
@@ -387,7 +381,6 @@ static struct i2c_driver sta529_i2c_driver = {
 		.of_match_table = sta529_of_match,
 	},
 	.probe		= sta529_i2c_probe,
-	.remove		= sta529_i2c_remove,
 	.id_table	= sta529_i2c_id,
 };
 
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index c66363a2cac7..f62101a629e0 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -168,58 +168,58 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
 static int ac97_analog_prepare(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	unsigned short reg;
 
 	/* enable variable rate audio, disable SPDIF output */
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x5, 0x1);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = AC97_PCM_FRONT_DAC_RATE;
 	else
 		reg = AC97_PCM_LR_ADC_RATE;
 
-	return snd_soc_write(codec, reg, runtime->rate);
+	return snd_soc_component_write(component, reg, runtime->rate);
 }
 
 static int ac97_digital_prepare(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	unsigned short reg;
 
-	snd_soc_write(codec, AC97_SPDIF, 0x2002);
+	snd_soc_component_write(component, AC97_SPDIF, 0x2002);
 
 	/* Enable VRA and SPDIF out */
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x5, 0x5);
 
 	reg = AC97_PCM_FRONT_DAC_RATE;
 
-	return snd_soc_write(codec, reg, runtime->rate);
+	return snd_soc_component_write(component, reg, runtime->rate);
 }
 
-static int stac9766_set_bias_level(struct snd_soc_codec *codec,
+static int stac9766_set_bias_level(struct snd_soc_component *component,
 				   enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON: /* full On */
 	case SND_SOC_BIAS_PREPARE: /* partial On */
 	case SND_SOC_BIAS_STANDBY: /* Off, with power */
-		snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
 		break;
 	case SND_SOC_BIAS_OFF: /* Off, without power */
 		/* disable everything including AC link */
-		snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
 		break;
 	}
 	return 0;
 }
 
-static int stac9766_codec_resume(struct snd_soc_codec *codec)
+static int stac9766_component_resume(struct snd_soc_component *component)
 {
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 
 	return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID,
 		STAC9766_VENDOR_ID_MASK);
@@ -272,13 +272,13 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
 }
 };
 
-static int stac9766_codec_probe(struct snd_soc_codec *codec)
+static int stac9766_component_probe(struct snd_soc_component *component)
 {
 	struct snd_ac97 *ac97;
 	struct regmap *regmap;
 	int ret;
 
-	ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID,
+	ac97 = snd_soc_new_ac97_component(component, STAC9766_VENDOR_ID,
 			STAC9766_VENDOR_ID_MASK);
 	if (IS_ERR(ac97))
 		return PTR_ERR(ac97);
@@ -289,46 +289,42 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
 		goto err_free_ac97;
 	}
 
-	snd_soc_codec_init_regmap(codec, regmap);
-	snd_soc_codec_set_drvdata(codec, ac97);
+	snd_soc_component_init_regmap(component, regmap);
+	snd_soc_component_set_drvdata(component, ac97);
 
 	return 0;
 err_free_ac97:
-	snd_soc_free_ac97_codec(ac97);
+	snd_soc_free_ac97_component(ac97);
 	return ret;
 }
 
-static int stac9766_codec_remove(struct snd_soc_codec *codec)
+static void stac9766_component_remove(struct snd_soc_component *component)
 {
-	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_exit_regmap(codec);
-	snd_soc_free_ac97_codec(ac97);
-	return 0;
+	snd_soc_component_exit_regmap(component);
+	snd_soc_free_ac97_component(ac97);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
-	.component_driver = {
-		.controls		= stac9766_snd_ac97_controls,
-		.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),
-	},
-	.set_bias_level = stac9766_set_bias_level,
-	.suspend_bias_off = true,
-	.probe = stac9766_codec_probe,
-	.remove = stac9766_codec_remove,
-	.resume = stac9766_codec_resume,
+static const struct snd_soc_component_driver soc_component_dev_stac9766 = {
+	.controls		= stac9766_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),
+	.set_bias_level		= stac9766_set_bias_level,
+	.probe			= stac9766_component_probe,
+	.remove			= stac9766_component_remove,
+	.resume			= stac9766_component_resume,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
 };
 
 static int stac9766_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
-}
-
-static int stac9766_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
 }
 
 static struct platform_driver stac9766_codec_driver = {
@@ -337,7 +333,6 @@ static struct platform_driver stac9766_codec_driver = {
 	},
 
 	.probe = stac9766_probe,
-	.remove = stac9766_remove,
 };
 
 module_platform_driver(stac9766_codec_driver);
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 62c618765224..7316c80b8179 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -106,7 +106,7 @@ static int sti_sas_write_reg(void *context, unsigned int reg,
 	return status;
 }
 
-static int  sti_sas_init_sas_registers(struct snd_soc_codec *codec,
+static int  sti_sas_init_sas_registers(struct snd_soc_component *component,
 				       struct sti_sas_data *data)
 {
 	int ret;
@@ -116,35 +116,35 @@ static int  sti_sas_init_sas_registers(struct snd_soc_codec *codec,
 	 */
 
 	/* Initialise bi-phase formatter to disabled */
-	ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+	ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 				  SPDIF_BIPHASE_ENABLE_MASK, 0);
 
 	if (!ret)
 		/* Initialise bi-phase formatter idle value to 0 */
-		ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 					  SPDIF_BIPHASE_IDLE_MASK, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to update SPDIF registers\n");
+		dev_err(component->dev, "Failed to update SPDIF registers\n");
 		return ret;
 	}
 
 	/* Init DAC configuration */
 	/* init configuration */
-	ret =  snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+	ret =  snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 				   STIH407_DAC_STANDBY_MASK,
 				   STIH407_DAC_STANDBY_MASK);
 
 	if (!ret)
-		ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 					  STIH407_DAC_STANDBY_ANA_MASK,
 					  STIH407_DAC_STANDBY_ANA_MASK);
 	if (!ret)
-		ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 					  STIH407_DAC_SOFTMUTE_MASK,
 					  STIH407_DAC_SOFTMUTE_MASK);
 
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to update DAC registers\n");
+		dev_err(component->dev, "Failed to update DAC registers\n");
 		return ret;
 	}
 
@@ -158,7 +158,7 @@ static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	/* Sanity check only */
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupporter master mask 0x%x\n",
 			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
@@ -183,14 +183,14 @@ static const struct snd_soc_dapm_route stih407_sas_route[] = {
 
 static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute) {
-		return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 					    STIH407_DAC_SOFTMUTE_MASK,
 					    STIH407_DAC_SOFTMUTE_MASK);
 	} else {
-		return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 					    STIH407_DAC_SOFTMUTE_MASK,
 					    0);
 	}
@@ -203,7 +203,7 @@ static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
 				 unsigned int fmt)
 {
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_err(dai->codec->dev,
+		dev_err(dai->component->dev,
 			"%s: ERROR: Unsupporter master mask 0x%x\n",
 			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
@@ -221,19 +221,19 @@ static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
 static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 					    SPDIF_BIPHASE_ENABLE_MASK,
 					    SPDIF_BIPHASE_ENABLE_MASK);
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-		return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 					    SPDIF_BIPHASE_ENABLE_MASK,
 					    0);
 	default:
@@ -260,8 +260,8 @@ static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
 static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 			      unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = dai->component;
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 
 	if (dir == SND_SOC_CLOCK_OUT)
 		return 0;
@@ -285,20 +285,20 @@ static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 static int sti_sas_prepare(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = dai->component;
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	switch (dai->id) {
 	case STI_SAS_DAI_SPDIF_OUT:
 		if ((drvdata->spdif.mclk / runtime->rate) != 128) {
-			dev_err(codec->dev, "unexpected mclk-fs ratio\n");
+			dev_err(component->dev, "unexpected mclk-fs ratio\n");
 			return -EINVAL;
 		}
 		break;
 	case STI_SAS_DAI_ANALOG_OUT:
 		if ((drvdata->dac.mclk / runtime->rate) != 256) {
-			dev_err(codec->dev, "unexpected mclk-fs ratio\n");
+			dev_err(component->dev, "unexpected mclk-fs ratio\n");
 			return -EINVAL;
 		}
 		break;
@@ -375,29 +375,33 @@ static struct snd_soc_dai_driver sti_sas_dai[] = {
 };
 
 #ifdef CONFIG_PM_SLEEP
-static int sti_sas_resume(struct snd_soc_codec *codec)
+static int sti_sas_resume(struct snd_soc_component *component)
 {
-	struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 
-	return sti_sas_init_sas_registers(codec, drvdata);
+	return sti_sas_init_sas_registers(component, drvdata);
 }
 #else
 #define sti_sas_resume NULL
 #endif
 
-static int sti_sas_codec_probe(struct snd_soc_codec *codec)
+static int sti_sas_component_probe(struct snd_soc_component *component)
 {
-	struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 	int ret;
 
-	ret = sti_sas_init_sas_registers(codec, drvdata);
+	ret = sti_sas_init_sas_registers(component, drvdata);
 
 	return ret;
 }
 
-static struct snd_soc_codec_driver sti_sas_driver = {
-	.probe = sti_sas_codec_probe,
-	.resume = sti_sas_resume,
+static struct snd_soc_component_driver sti_sas_driver = {
+	.probe			= sti_sas_component_probe,
+	.resume			= sti_sas_resume,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id sti_sas_dev_match[] = {
@@ -452,34 +456,26 @@ static int sti_sas_driver_probe(struct platform_device *pdev)
 	sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
 
 	/* Set dapms*/
-	sti_sas_driver.component_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
-	sti_sas_driver.component_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
+	sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
+	sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
 
-	sti_sas_driver.component_driver.dapm_routes = drvdata->dev_data->dapm_routes;
-	sti_sas_driver.component_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
+	sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
+	sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
 
 	/* Store context */
 	dev_set_drvdata(&pdev->dev, drvdata);
 
-	return snd_soc_register_codec(&pdev->dev, &sti_sas_driver,
+	return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
 					sti_sas_dai,
 					ARRAY_SIZE(sti_sas_dai));
 }
 
-static int sti_sas_driver_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-
-	return 0;
-}
-
 static struct platform_driver sti_sas_platform_driver = {
 	.driver = {
 		.name = "sti-sas-codec",
 		.of_match_table = sti_sas_dev_match,
 	},
 	.probe = sti_sas_driver_probe,
-	.remove = sti_sas_driver_remove,
 };
 
 module_platform_driver(sti_sas_platform_driver);
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 87307dd0f12e..355ecafb7c0f 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -70,7 +70,7 @@ static const char *tas2552_supply_names[TAS2552_NUM_SUPPLIES] = {
 };
 
 struct tas2552_data {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regmap *regmap;
 	struct i2c_client *tas2552_client;
 	struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
@@ -88,22 +88,22 @@ struct tas2552_data {
 static int tas2552_post_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0);
-		snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5),
+		snd_soc_component_write(component, TAS2552_RESERVED_0D, 0xc0);
+		snd_soc_component_update_bits(component, TAS2552_LIMIT_RATE_HYS, (1 << 5),
 				    (1 << 5));
-		snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0);
-		snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0);
+		snd_soc_component_update_bits(component, TAS2552_CFG_2, 1, 0);
+		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_SWS, 0);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS,
+		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_SWS,
 				    TAS2552_SWS);
-		snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1);
-		snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
-		snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe);
+		snd_soc_component_update_bits(component, TAS2552_CFG_2, 1, 1);
+		snd_soc_component_update_bits(component, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
+		snd_soc_component_write(component, TAS2552_RESERVED_0D, 0xbe);
 		break;
 	}
 	return 0;
@@ -149,21 +149,21 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown)
 {
 	u8 cfg1_reg = 0;
 
-	if (!tas2552->codec)
+	if (!tas2552->component)
 		return;
 
 	if (sw_shutdown)
 		cfg1_reg = TAS2552_SWS;
 
-	snd_soc_update_bits(tas2552->codec, TAS2552_CFG_1, TAS2552_SWS,
+	snd_soc_component_update_bits(tas2552->component, TAS2552_CFG_1, TAS2552_SWS,
 			    cfg1_reg);
 }
 #endif
 
-static int tas2552_setup_pll(struct snd_soc_codec *codec,
+static int tas2552_setup_pll(struct snd_soc_component *component,
 			     struct snd_pcm_hw_params *params)
 {
-	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
 	bool bypass_pll = false;
 	unsigned int pll_clk = params_rate(params) * 512;
 	unsigned int pll_clkin = tas2552->pll_clkin;
@@ -177,15 +177,15 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec,
 		pll_clkin += tas2552->tdm_delay;
 	}
 
-	pll_enable = snd_soc_read(codec, TAS2552_CFG_2) & TAS2552_PLL_ENABLE;
-	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
+	pll_enable = snd_soc_component_read32(component, TAS2552_CFG_2) & TAS2552_PLL_ENABLE;
+	snd_soc_component_update_bits(component, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
 
 	if (pll_clkin == pll_clk)
 		bypass_pll = true;
 
 	if (bypass_pll) {
 		/* By pass the PLL configuration */
-		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
+		snd_soc_component_update_bits(component, TAS2552_PLL_CTRL_2,
 				    TAS2552_PLL_BYPASS, TAS2552_PLL_BYPASS);
 	} else {
 		/* Fill in the PLL control registers for J & D
@@ -195,7 +195,7 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec,
 		unsigned int d, q, t;
 		u8 j;
 		u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK;
-		u8 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
+		u8 p = snd_soc_component_read32(component, TAS2552_PLL_CTRL_1);
 
 		p = (p >> 7);
 
@@ -221,20 +221,20 @@ static int tas2552_setup_pll(struct snd_soc_codec *codec,
 			goto recalc;
 		}
 
-		snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_PLL_SRC_MASK,
+		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_PLL_SRC_MASK,
 				    pll_sel);
 
-		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
+		snd_soc_component_update_bits(component, TAS2552_PLL_CTRL_1,
 				    TAS2552_PLL_J_MASK, j);
 		/* Will clear the PLL_BYPASS bit */
-		snd_soc_write(codec, TAS2552_PLL_CTRL_2,
+		snd_soc_component_write(component, TAS2552_PLL_CTRL_2,
 			      TAS2552_PLL_D_UPPER(d));
-		snd_soc_write(codec, TAS2552_PLL_CTRL_3,
+		snd_soc_component_write(component, TAS2552_PLL_CTRL_3,
 			      TAS2552_PLL_D_LOWER(d));
 	}
 
 	/* Restore PLL status */
-	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
+	snd_soc_component_update_bits(component, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
 			    pll_enable);
 
 	return 0;
@@ -244,8 +244,8 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
 	int cpf;
 	u8 ser_ctrl1_reg, wclk_rate;
 
@@ -267,7 +267,7 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 		cpf = 64 + tas2552->tdm_delay;
 		break;
 	default:
-		dev_err(codec->dev, "Not supported sample size: %d\n",
+		dev_err(component->dev, "Not supported sample size: %d\n",
 			params_width(params));
 		return -EINVAL;
 	}
@@ -281,7 +281,7 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 	else
 		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256;
 
-	snd_soc_update_bits(codec, TAS2552_SER_CTRL_1,
+	snd_soc_component_update_bits(component, TAS2552_SER_CTRL_1,
 			    TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK,
 			    ser_ctrl1_reg);
 
@@ -316,15 +316,15 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 		wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ;
 		break;
 	default:
-		dev_err(codec->dev, "Not supported sample rate: %d\n",
+		dev_err(component->dev, "Not supported sample rate: %d\n",
 			params_rate(params));
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
+	snd_soc_component_update_bits(component, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
 			    wclk_rate);
 
-	return tas2552_setup_pll(codec, params);
+	return tas2552_setup_pll(component, params);
 }
 
 #define TAS2552_DAI_FMT_MASK	(TAS2552_BCLKDIR | \
@@ -333,8 +333,8 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
 static int tas2552_prepare(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
 	int delay = 0;
 
 	/* TDM slot selection only valid in DSP_A/_B mode */
@@ -344,15 +344,15 @@ static int tas2552_prepare(struct snd_pcm_substream *substream,
 		delay += tas2552->tdm_delay;
 
 	/* Configure data delay */
-	snd_soc_write(codec, TAS2552_SER_CTRL_2, delay);
+	snd_soc_component_write(component, TAS2552_SER_CTRL_2, delay);
 
 	return 0;
 }
 
 static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
 	u8 serial_format;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -369,7 +369,7 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
 		break;
 	default:
-		dev_vdbg(codec->dev, "DAI Format master is not found\n");
+		dev_vdbg(component->dev, "DAI Format master is not found\n");
 		return -EINVAL;
 	}
 
@@ -388,12 +388,12 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		serial_format |= TAS2552_DATAFORMAT_LEFT_J;
 		break;
 	default:
-		dev_vdbg(codec->dev, "DAI Format is not found\n");
+		dev_vdbg(component->dev, "DAI Format is not found\n");
 		return -EINVAL;
 	}
 	tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
-	snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
+	snd_soc_component_update_bits(component, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
 			    serial_format);
 	return 0;
 }
@@ -401,8 +401,8 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 				  unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
 	u8 reg, mask, val;
 
 	switch (clk_id) {
@@ -410,7 +410,7 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	case TAS2552_PLL_CLKIN_IVCLKIN:
 		if (freq < 512000 || freq > 24576000) {
 			/* out of range PLL_CLKIN, fall back to use BCLK */
-			dev_warn(codec->dev, "Out of range PLL_CLKIN: %u\n",
+			dev_warn(component->dev, "Out of range PLL_CLKIN: %u\n",
 				 freq);
 			clk_id = TAS2552_PLL_CLKIN_BCLK;
 			freq = 0;
@@ -435,11 +435,11 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 		tas2552->pdm_clk = freq;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clk id: %d\n", clk_id);
+		dev_err(component->dev, "Invalid clk id: %d\n", clk_id);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg, mask, val);
+	snd_soc_component_update_bits(component, reg, mask, val);
 
 	return 0;
 }
@@ -448,26 +448,26 @@ static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
 	unsigned int lsb;
 
 	if (unlikely(!tx_mask)) {
-		dev_err(codec->dev, "tx masks need to be non 0\n");
+		dev_err(component->dev, "tx masks need to be non 0\n");
 		return -EINVAL;
 	}
 
 	/* TDM based on DSP mode requires slots to be adjacent */
 	lsb = __ffs(tx_mask);
 	if ((lsb + 1) != __fls(tx_mask)) {
-		dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
+		dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
 		return -EINVAL;
 	}
 
 	tas2552->tdm_delay = lsb * slot_width;
 
 	/* DOUT in high-impedance on inactive bit clocks */
-	snd_soc_update_bits(codec, TAS2552_DOUT,
+	snd_soc_component_update_bits(component, TAS2552_DOUT,
 			    TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
 
 	return 0;
@@ -476,12 +476,12 @@ static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
 static int tas2552_mute(struct snd_soc_dai *dai, int mute)
 {
 	u8 cfg1_reg = 0;
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute)
 		cfg1_reg |= TAS2552_MUTE;
 
-	snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
+	snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
 
 	return 0;
 }
@@ -570,41 +570,41 @@ static const struct snd_kcontrol_new tas2552_snd_controls[] = {
 	SOC_ENUM("DIN source", tas2552_din_source_enum),
 };
 
-static int tas2552_codec_probe(struct snd_soc_codec *codec)
+static int tas2552_component_probe(struct snd_soc_component *component)
 {
-	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	tas2552->codec = codec;
+	tas2552->component = component;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
 				    tas2552->supplies);
 
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n",
+		dev_err(component->dev, "Failed to enable supplies: %d\n",
 			ret);
 		return ret;
 	}
 
 	gpiod_set_value(tas2552->enable_gpio, 1);
 
-	ret = pm_runtime_get_sync(codec->dev);
+	ret = pm_runtime_get_sync(component->dev);
 	if (ret < 0) {
-		dev_err(codec->dev, "Enabling device failed: %d\n",
+		dev_err(component->dev, "Enabling device failed: %d\n",
 			ret);
 		goto probe_fail;
 	}
 
-	snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
-	snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
+	snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
+	snd_soc_component_write(component, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
 					    TAS2552_DIN_SRC_SEL_AVG_L_R);
-	snd_soc_write(codec, TAS2552_OUTPUT_DATA,
+	snd_soc_component_write(component, TAS2552_OUTPUT_DATA,
 		      TAS2552_PDM_DATA_SEL_V_I |
 		      TAS2552_R_DATA_OUT(TAS2552_DATA_OUT_V_DATA));
-	snd_soc_write(codec, TAS2552_BOOST_APT_CTRL, TAS2552_APT_DELAY_200 |
+	snd_soc_component_write(component, TAS2552_BOOST_APT_CTRL, TAS2552_APT_DELAY_200 |
 						     TAS2552_APT_THRESH_20_17);
 
-	snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | TAS2552_APT_EN |
+	snd_soc_component_write(component, TAS2552_CFG_2, TAS2552_BOOST_EN | TAS2552_APT_EN |
 					    TAS2552_LIM_EN);
 
 	return 0;
@@ -617,42 +617,40 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int tas2552_codec_remove(struct snd_soc_codec *codec)
+static void tas2552_component_remove(struct snd_soc_component *component)
 {
-	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
 
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 
 	gpiod_set_value(tas2552->enable_gpio, 0);
-
-	return 0;
 };
 
 #ifdef CONFIG_PM
-static int tas2552_suspend(struct snd_soc_codec *codec)
+static int tas2552_suspend(struct snd_soc_component *component)
 {
-	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
 					tas2552->supplies);
 
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to disable supplies: %d\n",
+		dev_err(component->dev, "Failed to disable supplies: %d\n",
 			ret);
 	return ret;
 }
 
-static int tas2552_resume(struct snd_soc_codec *codec)
+static int tas2552_resume(struct snd_soc_component *component)
 {
-	struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
 				    tas2552->supplies);
 
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n",
+		dev_err(component->dev, "Failed to enable supplies: %d\n",
 			ret);
 	}
 
@@ -663,21 +661,20 @@ static int tas2552_resume(struct snd_soc_codec *codec)
 #define tas2552_resume NULL
 #endif
 
-static const struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
-	.probe = tas2552_codec_probe,
-	.remove = tas2552_codec_remove,
-	.suspend =	tas2552_suspend,
-	.resume = tas2552_resume,
-	.ignore_pmdown_time = true,
-
-	.component_driver = {
-		.controls		= tas2552_snd_controls,
-		.num_controls		= ARRAY_SIZE(tas2552_snd_controls),
-		.dapm_widgets		= tas2552_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tas2552_dapm_widgets),
-		.dapm_routes		= tas2552_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(tas2552_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_tas2552 = {
+	.probe			= tas2552_component_probe,
+	.remove			= tas2552_component_remove,
+	.suspend		= tas2552_suspend,
+	.resume			= tas2552_resume,
+	.controls		= tas2552_snd_controls,
+	.num_controls		= ARRAY_SIZE(tas2552_snd_controls),
+	.dapm_widgets		= tas2552_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas2552_dapm_widgets),
+	.dapm_routes		= tas2552_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(tas2552_audio_map),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config tas2552_regmap_config = {
@@ -736,18 +733,17 @@ static int tas2552_probe(struct i2c_client *client,
 
 	dev_set_drvdata(&client->dev, data);
 
-	ret = snd_soc_register_codec(&client->dev,
-				      &soc_codec_dev_tas2552,
+	ret = devm_snd_soc_register_component(&client->dev,
+				      &soc_component_dev_tas2552,
 				      tas2552_dai, ARRAY_SIZE(tas2552_dai));
 	if (ret < 0)
-		dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&client->dev, "Failed to register component: %d\n", ret);
 
 	return ret;
 }
 
 static int tas2552_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	pm_runtime_disable(&client->dev);
 	return 0;
 }
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 199272d5cb6a..5efc4b7145d4 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -261,9 +261,9 @@ struct tas5086_private {
 
 static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
 
-static int tas5086_set_deemph(struct snd_soc_codec *codec)
+static int tas5086_set_deemph(struct snd_soc_component *component)
 {
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 	int i, val = 0;
 
 	if (priv->deemph) {
@@ -282,8 +282,8 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec)
 static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = priv->deemph;
 
@@ -293,20 +293,20 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
 static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
 	priv->deemph = ucontrol->value.integer.value[0];
 
-	return tas5086_set_deemph(codec);
+	return tas5086_set_deemph(component);
 }
 
 
 static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case TAS5086_CLK_IDX_MCLK:
@@ -323,12 +323,12 @@ static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			       unsigned int format)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
 	/* The TAS5086 can only be slave to all clocks */
 	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_err(codec->dev, "Invalid clocking mode\n");
+		dev_err(component->dev, "Invalid clocking mode\n");
 		return -EINVAL;
 	}
 
@@ -361,8 +361,8 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 	int val;
 	int ret;
 
@@ -373,7 +373,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
 			     ARRAY_SIZE(tas5086_sample_rates), priv->rate);
 
 	if (val < 0) {
-		dev_err(codec->dev, "Invalid sample rate\n");
+		dev_err(component->dev, "Invalid sample rate\n");
 		return -EINVAL;
 	}
 
@@ -387,7 +387,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
 	val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios),
 			     priv->mclk / priv->rate);
 	if (val < 0) {
-		dev_err(codec->dev, "Invalid MCLK / Fs ratio\n");
+		dev_err(component->dev, "Invalid MCLK / Fs ratio\n");
 		return -EINVAL;
 	}
 
@@ -424,7 +424,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
 		val = 0x06;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
+		dev_err(component->dev, "Invalid DAI format\n");
 		return -EINVAL;
 	}
 
@@ -440,7 +440,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
 		val += 2;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid bit width\n");
+		dev_err(component->dev, "Invalid bit width\n");
 		return -EINVAL;
 	}
 
@@ -454,13 +454,13 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		return ret;
 
-	return tas5086_set_deemph(codec);
+	return tas5086_set_deemph(component);
 }
 
 static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 
 	if (mute)
@@ -773,9 +773,9 @@ static struct snd_soc_dai_driver tas5086_dai = {
 };
 
 #ifdef CONFIG_PM
-static int tas5086_soc_suspend(struct snd_soc_codec *codec)
+static int tas5086_soc_suspend(struct snd_soc_component *component)
 {
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	/* Shut down all channels */
@@ -788,9 +788,9 @@ static int tas5086_soc_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int tas5086_soc_resume(struct snd_soc_codec *codec)
+static int tas5086_soc_resume(struct snd_soc_component *component)
 {
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
@@ -800,7 +800,7 @@ static int tas5086_soc_resume(struct snd_soc_codec *codec)
 	tas5086_reset(priv);
 	regcache_mark_dirty(priv->regmap);
 
-	ret = tas5086_init(codec->dev, priv);
+	ret = tas5086_init(component->dev, priv);
 	if (ret < 0)
 		return ret;
 
@@ -823,22 +823,22 @@ static const struct of_device_id tas5086_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
 #endif
 
-static int tas5086_probe(struct snd_soc_codec *codec)
+static int tas5086_probe(struct snd_soc_component *component)
 {
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 	int i, ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
 		return ret;
 	}
 
 	priv->pwm_start_mid_z = 0;
 	priv->charge_period = 1300000; /* hardware default is 1300 ms */
 
-	if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
-		struct device_node *of_node = codec->dev->of_node;
+	if (of_match_device(of_match_ptr(tas5086_dt_ids), component->dev)) {
+		struct device_node *of_node = component->dev->of_node;
 
 		of_property_read_u32(of_node, "ti,charge-period",
 				     &priv->charge_period);
@@ -855,7 +855,7 @@ static int tas5086_probe(struct snd_soc_codec *codec)
 	}
 
 	tas5086_reset(priv);
-	ret = tas5086_init(codec->dev, priv);
+	ret = tas5086_init(component->dev, priv);
 	if (ret < 0)
 		goto exit_disable_regulators;
 
@@ -872,32 +872,32 @@ static int tas5086_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int tas5086_remove(struct snd_soc_codec *codec)
+static void tas5086_remove(struct snd_soc_component *component)
 {
-	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(priv->gpio_nreset))
 		/* Set codec to the reset state */
 		gpio_set_value(priv->gpio_nreset, 0);
 
 	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
-
-	return 0;
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
+static const struct snd_soc_component_driver soc_component_dev_tas5086 = {
 	.probe			= tas5086_probe,
 	.remove			= tas5086_remove,
 	.suspend		= tas5086_soc_suspend,
 	.resume			= tas5086_soc_resume,
-	.component_driver = {
-		.controls		= tas5086_controls,
-		.num_controls		= ARRAY_SIZE(tas5086_controls),
-		.dapm_widgets		= tas5086_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tas5086_dapm_widgets),
-		.dapm_routes		= tas5086_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(tas5086_dapm_routes),
-	},
+	.controls		= tas5086_controls,
+	.num_controls		= ARRAY_SIZE(tas5086_controls),
+	.dapm_widgets		= tas5086_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas5086_dapm_widgets),
+	.dapm_routes		= tas5086_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tas5086_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct i2c_device_id tas5086_i2c_id[] = {
@@ -985,7 +985,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
 	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
 
 	if (ret == 0)
-		ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
+		ret = devm_snd_soc_register_component(&i2c->dev,
+					     &soc_component_dev_tas5086,
 					     &tas5086_dai, 1);
 
 	return ret;
@@ -993,7 +994,6 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
 
 static int tas5086_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&i2c->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index a09499977be4..52f34c94ec25 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -51,7 +51,7 @@ struct tas571x_private {
 	unsigned int			format;
 	struct gpio_desc		*reset_gpio;
 	struct gpio_desc		*pdn_gpio;
-	struct snd_soc_codec_driver	codec_driver;
+	struct snd_soc_component_driver	component_driver;
 };
 
 static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
@@ -242,8 +242,8 @@ static int tas571x_coefficient_info(struct snd_kcontrol *kcontrol,
 static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
 
@@ -254,8 +254,8 @@ static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
 static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
 	int numcoef = kcontrol->private_value >> 16;
 	int index = kcontrol->private_value & 0xffff;
 
@@ -265,7 +265,7 @@ static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol,
 
 static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
 {
-	struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct tas571x_private *priv = snd_soc_component_get_drvdata(dai->component);
 
 	priv->format = format;
 
@@ -276,7 +276,7 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct tas571x_private *priv = snd_soc_component_get_drvdata(dai->component);
 	u32 val;
 
 	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -304,13 +304,13 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream,
 
 static int tas571x_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 sysctl2;
 	int ret;
 
 	sysctl2 = mute ? TAS571X_SYS_CTRL_2_SDN_MASK : 0;
 
-	ret = snd_soc_update_bits(codec,
+	ret = snd_soc_component_update_bits(component,
 			    TAS571X_SYS_CTRL_2_REG,
 		     TAS571X_SYS_CTRL_2_SDN_MASK,
 		     sysctl2);
@@ -319,10 +319,10 @@ static int tas571x_mute(struct snd_soc_dai *dai, int mute)
 	return ret;
 }
 
-static int tas571x_set_bias_level(struct snd_soc_codec *codec,
+static int tas571x_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct tas571x_private *priv = snd_soc_codec_get_drvdata(codec);
+	struct tas571x_private *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -331,11 +331,11 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			if (!IS_ERR(priv->mclk)) {
 				ret = clk_prepare_enable(priv->mclk);
 				if (ret) {
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Failed to enable master clock: %d\n",
 						ret);
 					return ret;
@@ -643,16 +643,15 @@ static const struct snd_soc_dapm_route tas571x_dapm_routes[] = {
 	{ "OUT_D", NULL, "DACR" },
 };
 
-static const struct snd_soc_codec_driver tas571x_codec = {
-	.set_bias_level = tas571x_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.dapm_widgets		= tas571x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tas571x_dapm_widgets),
-		.dapm_routes		= tas571x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(tas571x_dapm_routes),
-	},
+static const struct snd_soc_component_driver tas571x_component = {
+	.set_bias_level		= tas571x_set_bias_level,
+	.dapm_widgets		= tas571x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas571x_dapm_widgets),
+	.dapm_routes		= tas571x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tas571x_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct snd_soc_dai_driver tas571x_dai = {
@@ -746,9 +745,9 @@ static int tas571x_i2c_probe(struct i2c_client *client,
 
 	usleep_range(50000, 60000);
 
-	memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
-	priv->codec_driver.component_driver.controls = priv->chip->controls;
-	priv->codec_driver.component_driver.num_controls = priv->chip->num_controls;
+	memcpy(&priv->component_driver, &tas571x_component, sizeof(priv->component_driver));
+	priv->component_driver.controls = priv->chip->controls;
+	priv->component_driver.num_controls = priv->chip->num_controls;
 
 	if (priv->chip->vol_reg_size == 2) {
 		/*
@@ -761,7 +760,8 @@ static int tas571x_i2c_probe(struct i2c_client *client,
 			return ret;
 	}
 
-	return snd_soc_register_codec(&client->dev, &priv->codec_driver,
+	return devm_snd_soc_register_component(&client->dev,
+				      &priv->component_driver,
 				      &tas571x_dai, 1);
 }
 
@@ -769,7 +769,6 @@ static int tas571x_i2c_remove(struct i2c_client *client)
 {
 	struct tas571x_private *priv = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
 	regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies);
 
 	return 0;
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index f3006f301fe8..ae3d032ac35a 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -49,7 +49,7 @@ static const char * const tas5720_supply_names[] = {
 #define TAS5720_NUM_SUPPLIES	ARRAY_SIZE(tas5720_supply_names)
 
 struct tas5720_data {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regmap *regmap;
 	struct i2c_client *tas5720_client;
 	enum tas572x_type devtype;
@@ -62,7 +62,7 @@ static int tas5720_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int rate = params_rate(params);
 	bool ssz_ds;
 	int ret;
@@ -77,14 +77,14 @@ static int tas5720_hw_params(struct snd_pcm_substream *substream,
 		ssz_ds = true;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported sample rate: %u\n", rate);
+		dev_err(component->dev, "unsupported sample rate: %u\n", rate);
 		return -EINVAL;
 	}
 
-	ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
 				  TAS5720_SSZ_DS, ssz_ds);
 	if (ret < 0) {
-		dev_err(codec->dev, "error setting sample rate: %d\n", ret);
+		dev_err(component->dev, "error setting sample rate: %d\n", ret);
 		return ret;
 	}
 
@@ -93,12 +93,12 @@ static int tas5720_hw_params(struct snd_pcm_substream *substream,
 
 static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 serial_format;
 	int ret;
 
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_vdbg(codec->dev, "DAI Format master is not found\n");
+		dev_vdbg(component->dev, "DAI Format master is not found\n");
 		return -EINVAL;
 	}
 
@@ -132,15 +132,15 @@ static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		serial_format = TAS5720_SAIF_LEFTJ;
 		break;
 	default:
-		dev_vdbg(codec->dev, "DAI Format is not found\n");
+		dev_vdbg(component->dev, "DAI Format is not found\n");
 		return -EINVAL;
 	}
 
-	ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
 				  TAS5720_SAIF_FORMAT_MASK,
 				  serial_format);
 	if (ret < 0) {
-		dev_err(codec->dev, "error setting SAIF format: %d\n", ret);
+		dev_err(component->dev, "error setting SAIF format: %d\n", ret);
 		return ret;
 	}
 
@@ -151,12 +151,12 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int first_slot;
 	int ret;
 
 	if (!tx_mask) {
-		dev_err(codec->dev, "tx masks must not be 0\n");
+		dev_err(component->dev, "tx masks must not be 0\n");
 		return -EINVAL;
 	}
 
@@ -168,39 +168,39 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	first_slot = __ffs(tx_mask);
 
 	if (first_slot > 7) {
-		dev_err(codec->dev, "slot selection out of bounds (%u)\n",
+		dev_err(component->dev, "slot selection out of bounds (%u)\n",
 			first_slot);
 		return -EINVAL;
 	}
 
 	/* Enable manual TDM slot selection (instead of I2C ID based) */
-	ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
 				  TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC);
 	if (ret < 0)
-		goto error_snd_soc_update_bits;
+		goto error_snd_soc_component_update_bits;
 
 	/* Configure the TDM slot to process audio from */
-	ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
 				  TAS5720_TDM_SLOT_SEL_MASK, first_slot);
 	if (ret < 0)
-		goto error_snd_soc_update_bits;
+		goto error_snd_soc_component_update_bits;
 
 	return 0;
 
-error_snd_soc_update_bits:
-	dev_err(codec->dev, "error configuring TDM mode: %d\n", ret);
+error_snd_soc_component_update_bits:
+	dev_err(component->dev, "error configuring TDM mode: %d\n", ret);
 	return ret;
 }
 
 static int tas5720_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int ret;
 
-	ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
 				  TAS5720_MUTE, mute ? TAS5720_MUTE : 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "error (un-)muting device: %d\n", ret);
+		dev_err(component->dev, "error (un-)muting device: %d\n", ret);
 		return ret;
 	}
 
@@ -211,7 +211,7 @@ static void tas5720_fault_check_work(struct work_struct *work)
 {
 	struct tas5720_data *tas5720 = container_of(work, struct tas5720_data,
 			fault_check_work.work);
-	struct device *dev = tas5720->codec->dev;
+	struct device *dev = tas5720->component->dev;
 	unsigned int curr_fault;
 	int ret;
 
@@ -267,18 +267,18 @@ static void tas5720_fault_check_work(struct work_struct *work)
 			      msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
 }
 
-static int tas5720_codec_probe(struct snd_soc_codec *codec)
+static int tas5720_codec_probe(struct snd_soc_component *component)
 {
-	struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
 	unsigned int device_id, expected_device_id;
 	int ret;
 
-	tas5720->codec = codec;
+	tas5720->component = component;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
 				    tas5720->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
@@ -289,7 +289,7 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
 	 */
 	ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to read device ID register: %d\n",
+		dev_err(component->dev, "failed to read device ID register: %d\n",
 			ret);
 		goto probe_fail;
 	}
@@ -302,19 +302,19 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
 		expected_device_id = TAS5722_DEVICE_ID;
 		break;
 	default:
-		dev_err(codec->dev, "unexpected private driver data\n");
+		dev_err(component->dev, "unexpected private driver data\n");
 		return -EINVAL;
 	}
 
 	if (device_id != expected_device_id)
-		dev_warn(codec->dev, "wrong device ID. expected: %u read: %u\n",
+		dev_warn(component->dev, "wrong device ID. expected: %u read: %u\n",
 			 expected_device_id, device_id);
 
 	/* Set device to mute */
-	ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
 				  TAS5720_MUTE, TAS5720_MUTE);
 	if (ret < 0)
-		goto error_snd_soc_update_bits;
+		goto error_snd_soc_component_update_bits;
 
 	/*
 	 * Enter shutdown mode - our default when not playing audio - to
@@ -322,17 +322,17 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
 	 * side doing so as all device registers are preserved and the wakeup
 	 * of the codec is rather quick which we do using a dapm widget.
 	 */
-	ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG,
+	ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
 				  TAS5720_SDZ, 0);
 	if (ret < 0)
-		goto error_snd_soc_update_bits;
+		goto error_snd_soc_component_update_bits;
 
 	INIT_DELAYED_WORK(&tas5720->fault_check_work, tas5720_fault_check_work);
 
 	return 0;
 
-error_snd_soc_update_bits:
-	dev_err(codec->dev, "error configuring device registers: %d\n", ret);
+error_snd_soc_component_update_bits:
+	dev_err(component->dev, "error configuring device registers: %d\n", ret);
 
 probe_fail:
 	regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
@@ -340,9 +340,9 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int tas5720_codec_remove(struct snd_soc_codec *codec)
+static void tas5720_codec_remove(struct snd_soc_component *component)
 {
-	struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	cancel_delayed_work_sync(&tas5720->fault_check_work);
@@ -350,24 +350,22 @@ static int tas5720_codec_remove(struct snd_soc_codec *codec)
 	ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
 				     tas5720->supplies);
 	if (ret < 0)
-		dev_err(codec->dev, "failed to disable supplies: %d\n", ret);
-
-	return ret;
+		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
 };
 
 static int tas5720_dac_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Take TAS5720 out of shutdown mode */
-		ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG,
+		ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
 					  TAS5720_SDZ, TAS5720_SDZ);
 		if (ret < 0) {
-			dev_err(codec->dev, "error waking codec: %d\n", ret);
+			dev_err(component->dev, "error waking component: %d\n", ret);
 			return ret;
 		}
 
@@ -390,10 +388,10 @@ static int tas5720_dac_event(struct snd_soc_dapm_widget *w,
 		cancel_delayed_work_sync(&tas5720->fault_check_work);
 
 		/* Place TAS5720 in shutdown mode to minimize current draw */
-		ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG,
+		ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
 					  TAS5720_SDZ, 0);
 		if (ret < 0) {
-			dev_err(codec->dev, "error shutting down codec: %d\n",
+			dev_err(component->dev, "error shutting down component: %d\n",
 				ret);
 			return ret;
 		}
@@ -403,9 +401,9 @@ static int tas5720_dac_event(struct snd_soc_dapm_widget *w,
 }
 
 #ifdef CONFIG_PM
-static int tas5720_suspend(struct snd_soc_codec *codec)
+static int tas5720_suspend(struct snd_soc_component *component)
 {
-	struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	regcache_cache_only(tas5720->regmap, true);
@@ -414,20 +412,20 @@ static int tas5720_suspend(struct snd_soc_codec *codec)
 	ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
 				     tas5720->supplies);
 	if (ret < 0)
-		dev_err(codec->dev, "failed to disable supplies: %d\n", ret);
+		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
 
 	return ret;
 }
 
-static int tas5720_resume(struct snd_soc_codec *codec)
+static int tas5720_resume(struct snd_soc_component *component)
 {
-	struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
 				    tas5720->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
@@ -435,7 +433,7 @@ static int tas5720_resume(struct snd_soc_codec *codec)
 
 	ret = regcache_sync(tas5720->regmap);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to sync regcache: %d\n", ret);
+		dev_err(component->dev, "failed to sync regcache: %d\n", ret);
 		return ret;
 	}
 
@@ -512,20 +510,21 @@ static const struct snd_soc_dapm_route tas5720_audio_map[] = {
 	{ "OUT", NULL, "DAC" },
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_tas5720 = {
-	.probe = tas5720_codec_probe,
-	.remove = tas5720_codec_remove,
-	.suspend = tas5720_suspend,
-	.resume = tas5720_resume,
-
-	.component_driver = {
-		.controls		= tas5720_snd_controls,
-		.num_controls		= ARRAY_SIZE(tas5720_snd_controls),
-		.dapm_widgets		= tas5720_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tas5720_dapm_widgets),
-		.dapm_routes		= tas5720_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(tas5720_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
+	.probe			= tas5720_codec_probe,
+	.remove			= tas5720_codec_remove,
+	.suspend		= tas5720_suspend,
+	.resume			= tas5720_resume,
+	.controls		= tas5720_snd_controls,
+	.num_controls		= ARRAY_SIZE(tas5720_snd_controls),
+	.dapm_widgets		= tas5720_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas5720_dapm_widgets),
+	.dapm_routes		= tas5720_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(tas5720_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* PCM rates supported by the TAS5720 driver */
@@ -614,26 +613,17 @@ static int tas5720_probe(struct i2c_client *client,
 
 	dev_set_drvdata(dev, data);
 
-	ret = snd_soc_register_codec(&client->dev,
-				     &soc_codec_dev_tas5720,
+	ret = devm_snd_soc_register_component(&client->dev,
+				     &soc_component_dev_tas5720,
 				     tas5720_dai, ARRAY_SIZE(tas5720_dai));
 	if (ret < 0) {
-		dev_err(dev, "failed to register codec: %d\n", ret);
+		dev_err(dev, "failed to register component: %d\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
-static int tas5720_remove(struct i2c_client *client)
-{
-	struct device *dev = &client->dev;
-
-	snd_soc_unregister_codec(dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id tas5720_id[] = {
 	{ "tas5720", TAS5720 },
 	{ "tas5722", TAS5722 },
@@ -656,7 +646,6 @@ static struct i2c_driver tas5720_i2c_driver = {
 		.of_match_table = of_match_ptr(tas5720_of_match),
 	},
 	.probe = tas5720_probe,
-	.remove = tas5720_remove,
 	.id_table = tas5720_id,
 };
 
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index 49b87f6e85bf..4f3a16c520a2 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -66,10 +66,10 @@ static const struct snd_kcontrol_new tas6424_snd_controls[] = {
 static int tas6424_dac_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s() event=0x%0x\n", __func__, event);
+	dev_dbg(component->dev, "%s() event=0x%0x\n", __func__, event);
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Observe codec shutdown-to-active time */
@@ -105,12 +105,12 @@ static int tas6424_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int rate = params_rate(params);
 	unsigned int width = params_width(params);
 	u8 sap_ctrl = 0;
 
-	dev_dbg(codec->dev, "%s() rate=%u width=%u\n", __func__, rate, width);
+	dev_dbg(component->dev, "%s() rate=%u width=%u\n", __func__, rate, width);
 
 	switch (rate) {
 	case 44100:
@@ -123,7 +123,7 @@ static int tas6424_hw_params(struct snd_pcm_substream *substream,
 		sap_ctrl |= TAS6424_SAP_RATE_96000;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported sample rate: %u\n", rate);
+		dev_err(component->dev, "unsupported sample rate: %u\n", rate);
 		return -EINVAL;
 	}
 
@@ -134,11 +134,11 @@ static int tas6424_hw_params(struct snd_pcm_substream *substream,
 	case 24:
 		break;
 	default:
-		dev_err(codec->dev, "unsupported sample width: %u\n", width);
+		dev_err(component->dev, "unsupported sample width: %u\n", width);
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, TAS6424_SAP_CTRL,
+	snd_soc_component_update_bits(component, TAS6424_SAP_CTRL,
 			    TAS6424_SAP_RATE_MASK |
 			    TAS6424_SAP_TDM_SLOT_SZ_16,
 			    sap_ctrl);
@@ -148,17 +148,17 @@ static int tas6424_hw_params(struct snd_pcm_substream *substream,
 
 static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 serial_format = 0;
 
-	dev_dbg(codec->dev, "%s() fmt=0x%0x\n", __func__, fmt);
+	dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt);
 
 	/* clock masters */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI master/slave interface\n");
+		dev_err(component->dev, "Invalid DAI master/slave interface\n");
 		return -EINVAL;
 	}
 
@@ -167,7 +167,7 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	case SND_SOC_DAIFMT_NB_NF:
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
+		dev_err(component->dev, "Invalid DAI clock signal polarity\n");
 		return -EINVAL;
 	}
 
@@ -191,11 +191,11 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		serial_format |= TAS6424_SAP_LEFTJ;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI interface format\n");
+		dev_err(component->dev, "Invalid DAI interface format\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, TAS6424_SAP_CTRL,
+	snd_soc_component_update_bits(component, TAS6424_SAP_CTRL,
 			    TAS6424_SAP_FMT_MASK, serial_format);
 
 	return 0;
@@ -205,11 +205,11 @@ static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				    unsigned int tx_mask, unsigned int rx_mask,
 				    int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int first_slot, last_slot;
 	bool sap_tdm_slot_last;
 
-	dev_dbg(codec->dev, "%s() tx_mask=%d rx_mask=%d\n", __func__,
+	dev_dbg(component->dev, "%s() tx_mask=%d rx_mask=%d\n", __func__,
 		tx_mask, rx_mask);
 
 	if (!tx_mask || !rx_mask)
@@ -224,7 +224,7 @@ static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
 	last_slot = __fls(rx_mask);
 
 	if (last_slot - first_slot != 4) {
-		dev_err(codec->dev, "tdm mask must cover 4 contiguous slots\n");
+		dev_err(component->dev, "tdm mask must cover 4 contiguous slots\n");
 		return -EINVAL;
 	}
 
@@ -236,11 +236,11 @@ static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
 		sap_tdm_slot_last = true;
 		break;
 	default:
-		dev_err(codec->dev, "tdm mask must start at slot 0 or 4\n");
+		dev_err(component->dev, "tdm mask must start at slot 0 or 4\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, TAS6424_SAP_CTRL, TAS6424_SAP_TDM_SLOT_LAST,
+	snd_soc_component_update_bits(component, TAS6424_SAP_CTRL, TAS6424_SAP_TDM_SLOT_LAST,
 			    sap_tdm_slot_last ? TAS6424_SAP_TDM_SLOT_LAST : 0);
 
 	return 0;
@@ -248,27 +248,27 @@ static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
 
 static int tas6424_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val;
 
-	dev_dbg(codec->dev, "%s() mute=%d\n", __func__, mute);
+	dev_dbg(component->dev, "%s() mute=%d\n", __func__, mute);
 
 	if (mute)
 		val = TAS6424_ALL_STATE_MUTE;
 	else
 		val = TAS6424_ALL_STATE_PLAY;
 
-	snd_soc_write(codec, TAS6424_CH_STATE_CTRL, val);
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, val);
 
 	return 0;
 }
 
-static int tas6424_power_off(struct snd_soc_codec *codec)
+static int tas6424_power_off(struct snd_soc_component *component)
 {
-	struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_HIZ);
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_HIZ);
 
 	regcache_cache_only(tas6424->regmap, true);
 	regcache_mark_dirty(tas6424->regmap);
@@ -276,22 +276,22 @@ static int tas6424_power_off(struct snd_soc_codec *codec)
 	ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
 				     tas6424->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to disable supplies: %d\n", ret);
+		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
-static int tas6424_power_on(struct snd_soc_codec *codec)
+static int tas6424_power_on(struct snd_soc_component *component)
 {
-	struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
 				    tas6424->supplies);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
@@ -299,11 +299,11 @@ static int tas6424_power_on(struct snd_soc_codec *codec)
 
 	ret = regcache_sync(tas6424->regmap);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to sync regcache: %d\n", ret);
+		dev_err(component->dev, "failed to sync regcache: %d\n", ret);
 		return ret;
 	}
 
-	snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE);
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE);
 
 	/* any time we come out of HIZ, the output channels automatically run DC
 	 * load diagnostics, wait here until this completes
@@ -313,39 +313,38 @@ static int tas6424_power_on(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int tas6424_set_bias_level(struct snd_soc_codec *codec,
+static int tas6424_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	dev_dbg(codec->dev, "%s() level=%d\n", __func__, level);
+	dev_dbg(component->dev, "%s() level=%d\n", __func__, level);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
-			tas6424_power_on(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			tas6424_power_on(component);
 		break;
 	case SND_SOC_BIAS_OFF:
-		tas6424_power_off(codec);
+		tas6424_power_off(component);
 		break;
 	}
 
 	return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_tas6424 = {
-	.set_bias_level = tas6424_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls = tas6424_snd_controls,
-		.num_controls = ARRAY_SIZE(tas6424_snd_controls),
-		.dapm_widgets = tas6424_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(tas6424_dapm_widgets),
-		.dapm_routes = tas6424_audio_map,
-		.num_dapm_routes = ARRAY_SIZE(tas6424_audio_map),
-	},
+static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
+	.set_bias_level		= tas6424_set_bias_level,
+	.controls		= tas6424_snd_controls,
+	.num_controls		= ARRAY_SIZE(tas6424_snd_controls),
+	.dapm_widgets		= tas6424_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas6424_dapm_widgets),
+	.dapm_routes		= tas6424_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(tas6424_audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
@@ -654,7 +653,7 @@ static int tas6424_i2c_probe(struct i2c_client *client,
 
 	INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work);
 
-	ret = snd_soc_register_codec(dev, &soc_codec_dev_tas6424,
+	ret = devm_snd_soc_register_component(dev, &soc_codec_dev_tas6424,
 				     tas6424_dai, ARRAY_SIZE(tas6424_dai));
 	if (ret < 0) {
 		dev_err(dev, "unable to register codec: %d\n", ret);
@@ -670,8 +669,6 @@ static int tas6424_i2c_remove(struct i2c_client *client)
 	struct tas6424_data *tas6424 = dev_get_drvdata(dev);
 	int ret;
 
-	snd_soc_unregister_codec(dev);
-
 	cancel_delayed_work_sync(&tas6424->fault_check_work);
 
 	ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index e7ca764b5729..6d213c6d3920 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -30,8 +30,8 @@ static int tfa9879_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tfa9879_priv *tfa9879 = snd_soc_component_get_drvdata(component);
 	int fs;
 	int i2s_set = 0;
 
@@ -88,11 +88,11 @@ static int tfa9879_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (tfa9879->lsb_justified)
-		snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+		snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
 				    TFA9879_I2S_SET_MASK,
 				    i2s_set << TFA9879_I2S_SET_SHIFT);
 
-	snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
 			    TFA9879_I2S_FS_MASK,
 			    fs << TFA9879_I2S_FS_SHIFT);
 	return 0;
@@ -100,9 +100,9 @@ static int tfa9879_hw_params(struct snd_pcm_substream *substream,
 
 static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	snd_soc_update_bits(codec, TFA9879_MISC_CONTROL,
+	snd_soc_component_update_bits(component, TFA9879_MISC_CONTROL,
 			    TFA9879_S_MUTE_MASK,
 			    !!mute << TFA9879_S_MUTE_SHIFT);
 
@@ -111,8 +111,8 @@ static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute)
 
 static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tfa9879_priv *tfa9879 = snd_soc_component_get_drvdata(component);
 	int i2s_set;
 	int sck_pol;
 
@@ -151,10 +151,10 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
 			    TFA9879_SCK_POL_MASK,
 			    sck_pol << TFA9879_SCK_POL_SHIFT);
-	snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
 			    TFA9879_I2S_SET_MASK,
 			    i2s_set << TFA9879_I2S_SET_SHIFT);
 	return 0;
@@ -230,15 +230,17 @@ static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = {
 	{ "DAC", NULL, "POWER" },
 };
 
-static const struct snd_soc_codec_driver tfa9879_codec = {
-	.component_driver = {
-		.controls		= tfa9879_controls,
-		.num_controls		= ARRAY_SIZE(tfa9879_controls),
-		.dapm_widgets		= tfa9879_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tfa9879_dapm_widgets),
-		.dapm_routes		= tfa9879_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(tfa9879_dapm_routes),
-	},
+static const struct snd_soc_component_driver tfa9879_component = {
+	.controls		= tfa9879_controls,
+	.num_controls		= ARRAY_SIZE(tfa9879_controls),
+	.dapm_widgets		= tfa9879_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tfa9879_dapm_widgets),
+	.dapm_routes		= tfa9879_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tfa9879_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config tfa9879_regmap = {
@@ -295,17 +297,10 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c,
 		regmap_write(tfa9879->regmap,
 			     tfa9879_regs[i].reg, tfa9879_regs[i].def);
 
-	return snd_soc_register_codec(&i2c->dev, &tfa9879_codec,
+	return devm_snd_soc_register_component(&i2c->dev, &tfa9879_component,
 				      &tfa9879_dai, 1);
 }
 
-static int tfa9879_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id tfa9879_i2c_id[] = {
 	{ "tfa9879", 0 },
 	{ }
@@ -324,7 +319,6 @@ static struct i2c_driver tfa9879_i2c_driver = {
 		.of_match_table = tfa9879_of_match,
 	},
 	.probe = tfa9879_i2c_probe,
-	.remove = tfa9879_i2c_remove,
 	.id_table = tfa9879_i2c_id,
 };
 
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
index 78a94af65518..1d7c117316fb 100644
--- a/sound/soc/codecs/tlv320aic23-i2c.c
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -31,12 +31,6 @@ static int tlv320aic23_i2c_probe(struct i2c_client *i2c,
 	return tlv320aic23_probe(&i2c->dev, regmap);
 }
 
-static int tlv320aic23_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
-}
-
 static const struct i2c_device_id tlv320aic23_id[] = {
 	{"tlv320aic23", 0},
 	{}
@@ -56,7 +50,6 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
 		   .of_match_table = of_match_ptr(tlv320aic23_of_match),
 		   },
 	.probe = tlv320aic23_i2c_probe,
-	.remove = tlv320aic23_i2c_remove,
 	.id_table = tlv320aic23_id,
 };
 
diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c
index f801ae051658..d8c9ec1e9201 100644
--- a/sound/soc/codecs/tlv320aic23-spi.c
+++ b/sound/soc/codecs/tlv320aic23-spi.c
@@ -34,18 +34,11 @@ static int aic23_spi_probe(struct spi_device *spi)
 	return tlv320aic23_probe(&spi->dev, regmap);
 }
 
-static int aic23_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver aic23_spi = {
 	.driver = {
 		.name = "tlv320aic23",
 	},
 	.probe = aic23_spi_probe,
-	.remove = aic23_spi_remove,
 };
 
 module_spi_driver(aic23_spi);
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 74909211c608..47480cb4d078 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -82,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
 static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	u16 val, reg;
 
 	val = (ucontrol->value.integer.value[0] & 0x07);
@@ -96,8 +96,8 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
 	*/
 	val = (val >= 4) ? 4  : (3 - val);
 
-	reg = snd_soc_read(codec, TLV320AIC23_ANLG) & (~0x1C0);
-	snd_soc_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+	reg = snd_soc_component_read32(component, TLV320AIC23_ANLG) & (~0x1C0);
+	snd_soc_component_write(component, TLV320AIC23_ANLG, reg | (val << 6));
 
 	return 0;
 }
@@ -105,10 +105,10 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
 static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	u16 val;
 
-	val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0);
+	val = snd_soc_component_read32(component, TLV320AIC23_ANLG) & (0x1C0);
 	val = val >> 6;
 	val = (val >= 4) ? 4  : (3 -  val);
 	ucontrol->value.integer.value[0] = val;
@@ -296,10 +296,10 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac)
 }
 
 #ifdef DEBUG
-static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
+static void get_current_sample_rates(struct snd_soc_component *component, int mclk,
 		u32 *sample_rate_adc, u32 *sample_rate_dac)
 {
-	int src = snd_soc_read(codec, TLV320AIC23_SRATE);
+	int src = snd_soc_component_read32(component, TLV320AIC23_SRATE);
 	int sr = (src >> 2) & 0x0f;
 	int val = (mclk / bosr_usb_divisor_table[src & 3]);
 	int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
@@ -313,7 +313,7 @@ static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
 }
 #endif
 
-static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
+static int set_sample_rate_control(struct snd_soc_component *component, int mclk,
 		u32 sample_rate_adc, u32 sample_rate_dac)
 {
 	/* Search for the right sample rate */
@@ -323,11 +323,11 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
 				__func__, sample_rate_adc, sample_rate_dac);
 		return -EINVAL;
 	}
-	snd_soc_write(codec, TLV320AIC23_SRATE, data);
+	snd_soc_component_write(component, TLV320AIC23_SRATE, data);
 #ifdef DEBUG
 	{
 		u32 adc, dac;
-		get_current_sample_rates(codec, mclk, &adc, &dac);
+		get_current_sample_rates(component, mclk, &adc, &dac);
 		printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n",
 			adc, dac, data);
 	}
@@ -339,10 +339,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 iface_reg;
 	int ret;
-	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+	struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
 	u32 sample_rate_adc = aic23->requested_adc;
 	u32 sample_rate_dac = aic23->requested_dac;
 	u32 sample_rate = params_rate(params);
@@ -356,12 +356,12 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 		if (!sample_rate_dac)
 			sample_rate_dac = sample_rate;
 	}
-	ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc,
+	ret = set_sample_rate_control(component, aic23->mclk, sample_rate_adc,
 			sample_rate_dac);
 	if (ret < 0)
 		return ret;
 
-	iface_reg = snd_soc_read(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+	iface_reg = snd_soc_component_read32(component, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
 
 	switch (params_width(params)) {
 	case 16:
@@ -376,7 +376,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 		iface_reg |= (0x03 << 2);
 		break;
 	}
-	snd_soc_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+	snd_soc_component_write(component, TLV320AIC23_DIGT_FMT, iface_reg);
 
 	return 0;
 }
@@ -384,10 +384,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	/* set active */
-	snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+	snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0001);
 
 	return 0;
 }
@@ -395,13 +395,13 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
 static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
 
 	/* deactivate */
-	if (!snd_soc_codec_is_active(codec)) {
+	if (!snd_soc_component_is_active(component)) {
 		udelay(50);
-		snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
+		snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0);
 	}
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		aic23->requested_dac = 0;
@@ -411,17 +411,17 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
 
 static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 reg;
 
-	reg = snd_soc_read(codec, TLV320AIC23_DIGT);
+	reg = snd_soc_component_read32(component, TLV320AIC23_DIGT);
 	if (mute)
 		reg |= TLV320AIC23_DACM_MUTE;
 
 	else
 		reg &= ~TLV320AIC23_DACM_MUTE;
 
-	snd_soc_write(codec, TLV320AIC23_DIGT, reg);
+	snd_soc_component_write(component, TLV320AIC23_DIGT, reg);
 
 	return 0;
 }
@@ -429,10 +429,10 @@ static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
 static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
 				   unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface_reg;
 
-	iface_reg = snd_soc_read(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+	iface_reg = snd_soc_component_read32(component, TLV320AIC23_DIGT_FMT) & (~0x03);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -468,7 +468,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 	}
 
-	snd_soc_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+	snd_soc_component_write(component, TLV320AIC23_DIGT_FMT, iface_reg);
 
 	return 0;
 }
@@ -481,29 +481,29 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
+static int tlv320aic23_set_bias_level(struct snd_soc_component *component,
 				      enum snd_soc_bias_level level)
 {
-	u16 reg = snd_soc_read(codec, TLV320AIC23_PWR) & 0x17f;
+	u16 reg = snd_soc_component_read32(component, TLV320AIC23_PWR) & 0x17f;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* vref/mid, osc on, dac unmute */
 		reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
 			TLV320AIC23_DAC_OFF);
-		snd_soc_write(codec, TLV320AIC23_PWR, reg);
+		snd_soc_component_write(component, TLV320AIC23_PWR, reg);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* everything off except vref/vmid, */
-		snd_soc_write(codec, TLV320AIC23_PWR,
+		snd_soc_component_write(component, TLV320AIC23_PWR,
 			      reg | TLV320AIC23_CLK_OFF);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* everything off, dac mute, inactive */
-		snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
-		snd_soc_write(codec, TLV320AIC23_PWR, 0x1ff);
+		snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0);
+		snd_soc_component_write(component, TLV320AIC23_PWR, 0x1ff);
 		break;
 	}
 	return 0;
@@ -539,58 +539,59 @@ static struct snd_soc_dai_driver tlv320aic23_dai = {
 	.ops = &tlv320aic23_dai_ops,
 };
 
-static int tlv320aic23_resume(struct snd_soc_codec *codec)
+static int tlv320aic23_resume(struct snd_soc_component *component)
 {
-	struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+	struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
 	regcache_mark_dirty(aic23->regmap);
 	regcache_sync(aic23->regmap);
 
 	return 0;
 }
 
-static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
+static int tlv320aic23_component_probe(struct snd_soc_component *component)
 {
 	/* Reset codec */
-	snd_soc_write(codec, TLV320AIC23_RESET, 0);
+	snd_soc_component_write(component, TLV320AIC23_RESET, 0);
 
-	snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+	snd_soc_component_write(component, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
 
 	/* Unmute input */
-	snd_soc_update_bits(codec, TLV320AIC23_LINVOL,
+	snd_soc_component_update_bits(component, TLV320AIC23_LINVOL,
 			    TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
 
-	snd_soc_update_bits(codec, TLV320AIC23_RINVOL,
+	snd_soc_component_update_bits(component, TLV320AIC23_RINVOL,
 			    TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
 
-	snd_soc_update_bits(codec, TLV320AIC23_ANLG,
+	snd_soc_component_update_bits(component, TLV320AIC23_ANLG,
 			    TLV320AIC23_BYPASS_ON | TLV320AIC23_MICM_MUTED,
 			    0);
 
 	/* Default output volume */
-	snd_soc_write(codec, TLV320AIC23_LCHNVOL,
+	snd_soc_component_write(component, TLV320AIC23_LCHNVOL,
 		      TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
-	snd_soc_write(codec, TLV320AIC23_RCHNVOL,
+	snd_soc_component_write(component, TLV320AIC23_RCHNVOL,
 		      TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
 
-	snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1);
+	snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x1);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
-	.probe = tlv320aic23_codec_probe,
-	.resume = tlv320aic23_resume,
-	.set_bias_level = tlv320aic23_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= tlv320aic23_snd_controls,
-		.num_controls		= ARRAY_SIZE(tlv320aic23_snd_controls),
-		.dapm_widgets		= tlv320aic23_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tlv320aic23_dapm_widgets),
-		.dapm_routes		= tlv320aic23_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(tlv320aic23_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_tlv320aic23 = {
+	.probe			= tlv320aic23_component_probe,
+	.resume			= tlv320aic23_resume,
+	.set_bias_level		= tlv320aic23_set_bias_level,
+	.controls		= tlv320aic23_snd_controls,
+	.num_controls		= ARRAY_SIZE(tlv320aic23_snd_controls),
+	.dapm_widgets		= tlv320aic23_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tlv320aic23_dapm_widgets),
+	.dapm_routes		= tlv320aic23_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(tlv320aic23_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
@@ -608,7 +609,8 @@ int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
 
 	dev_set_drvdata(dev, aic23);
 
-	return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23,
+	return devm_snd_soc_register_component(dev,
+				      &soc_component_dev_tlv320aic23,
 				      &tlv320aic23_dai, 1);
 }
 EXPORT_SYMBOL(tlv320aic23_probe);
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 89421caaeb70..b91b8d5f1ba3 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL");
 struct aic26 {
 	struct spi_device *spi;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	int master;
 	int datfm;
 	int mclk;
@@ -64,8 +64,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
 			   struct snd_pcm_hw_params *params,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
 	int fsref, divisor, wlen, pval, jval, dval, qval;
 	u16 reg;
 
@@ -112,20 +112,20 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
 	dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval);
 	qval = 0;
 	reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
-	snd_soc_write(codec, AIC26_REG_PLL_PROG1, reg);
+	snd_soc_component_write(component, AIC26_REG_PLL_PROG1, reg);
 	reg = dval << 2;
-	snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg);
+	snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg);
 
 	/* Audio Control 3 (master mode, fsref rate) */
 	if (aic26->master)
 		reg = 0x0800;
 	if (fsref == 48000)
 		reg = 0x2000;
-	snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL3, 0xf800, reg);
+	snd_soc_component_update_bits(component, AIC26_REG_AUDIO_CTRL3, 0xf800, reg);
 
 	/* Audio Control 1 (FSref divisor) */
 	reg = wlen | aic26->datfm | (divisor << 3) | divisor;
-	snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL1, 0xfff, reg);
+	snd_soc_component_update_bits(component, AIC26_REG_AUDIO_CTRL1, 0xfff, reg);
 
 	return 0;
 }
@@ -135,8 +135,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
  */
 static int aic26_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
 	u16 reg;
 
 	dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
@@ -146,7 +146,7 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute)
 		reg = 0x8080;
 	else
 		reg = 0;
-	snd_soc_update_bits(codec, AIC26_REG_DAC_GAIN, 0x8000, reg);
+	snd_soc_component_update_bits(component, AIC26_REG_DAC_GAIN, 0x8000, reg);
 
 	return 0;
 }
@@ -154,8 +154,8 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute)
 static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
 			    int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
 
 	dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
 		" freq=%i, dir=%i)\n",
@@ -171,8 +171,8 @@ static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
 
 static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
 
 	dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
 		codec_dai, fmt);
@@ -265,7 +265,7 @@ static ssize_t aic26_keyclick_show(struct device *dev,
 	struct aic26 *aic26 = dev_get_drvdata(dev);
 	int val, amp, freq, len;
 
-	val = snd_soc_read(aic26->codec, AIC26_REG_AUDIO_CTRL2);
+	val = snd_soc_component_read32(aic26->component, AIC26_REG_AUDIO_CTRL2);
 	amp = (val >> 12) & 0x7;
 	freq = (125 << ((val >> 8) & 0x7)) >> 1;
 	len = 2 * (1 + ((val >> 4) & 0xf));
@@ -280,7 +280,7 @@ static ssize_t aic26_keyclick_set(struct device *dev,
 {
 	struct aic26 *aic26 = dev_get_drvdata(dev);
 
-	snd_soc_update_bits(aic26->codec, AIC26_REG_AUDIO_CTRL2,
+	snd_soc_component_update_bits(aic26->component, AIC26_REG_AUDIO_CTRL2,
 			    0x8000, 0x800);
 
 	return count;
@@ -291,44 +291,46 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
 /* ---------------------------------------------------------------------
  * SoC CODEC portion of driver: probe and release routines
  */
-static int aic26_probe(struct snd_soc_codec *codec)
+static int aic26_probe(struct snd_soc_component *component)
 {
-	struct aic26 *aic26 = dev_get_drvdata(codec->dev);
+	struct aic26 *aic26 = dev_get_drvdata(component->dev);
 	int ret, reg;
 
-	aic26->codec = codec;
+	aic26->component = component;
 
 	/* Reset the codec to power on defaults */
-	snd_soc_write(codec, AIC26_REG_RESET, 0xBB00);
+	snd_soc_component_write(component, AIC26_REG_RESET, 0xBB00);
 
 	/* Power up CODEC */
-	snd_soc_write(codec, AIC26_REG_POWER_CTRL, 0);
+	snd_soc_component_write(component, AIC26_REG_POWER_CTRL, 0);
 
 	/* Audio Control 3 (master mode, fsref rate) */
-	reg = snd_soc_read(codec, AIC26_REG_AUDIO_CTRL3);
+	reg = snd_soc_component_read32(component, AIC26_REG_AUDIO_CTRL3);
 	reg &= ~0xf800;
 	reg |= 0x0800; /* set master mode */
-	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+	snd_soc_component_write(component, AIC26_REG_AUDIO_CTRL3, reg);
 
 	/* Register the sysfs files for debugging */
 	/* Create SysFS files */
-	ret = device_create_file(codec->dev, &dev_attr_keyclick);
+	ret = device_create_file(component->dev, &dev_attr_keyclick);
 	if (ret)
-		dev_info(codec->dev, "error creating sysfs files\n");
+		dev_info(component->dev, "error creating sysfs files\n");
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver aic26_soc_codec_dev = {
-	.probe = aic26_probe,
-	.component_driver = {
-		.controls		= aic26_snd_controls,
-		.num_controls		= ARRAY_SIZE(aic26_snd_controls),
-		.dapm_widgets		= tlv320aic26_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(tlv320aic26_dapm_widgets),
-		.dapm_routes		= tlv320aic26_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(tlv320aic26_dapm_routes),
-	},
+static const struct snd_soc_component_driver aic26_soc_component_dev = {
+	.probe			= aic26_probe,
+	.controls		= aic26_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic26_snd_controls),
+	.dapm_widgets		= tlv320aic26_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tlv320aic26_dapm_widgets),
+	.dapm_routes		= tlv320aic26_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tlv320aic26_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config aic26_regmap = {
@@ -361,23 +363,16 @@ static int aic26_spi_probe(struct spi_device *spi)
 	dev_set_drvdata(&spi->dev, aic26);
 	aic26->master = 1;
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&aic26_soc_codec_dev, &aic26_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&aic26_soc_component_dev, &aic26_dai, 1);
 	return ret;
 }
 
-static int aic26_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver aic26_spi = {
 	.driver = {
 		.name = "tlv320aic26-codec",
 	},
 	.probe = aic26_spi_probe,
-	.remove = aic26_spi_remove,
 };
 
 module_spi_driver(aic26_spi);
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 858cb8be445f..bf92d36b8f8a 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -153,7 +153,7 @@ struct aic31xx_disable_nb {
 };
 
 struct aic31xx_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	u8 i2c_regs_status;
 	struct device *dev;
 	struct regmap *regmap;
@@ -166,6 +166,7 @@ struct aic31xx_priv {
 	unsigned int sysclk;
 	u8 p_div;
 	int rate_div_line;
+	bool master_dapm_route_applied;
 };
 
 struct aic31xx_rate_divs {
@@ -348,8 +349,8 @@ static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
 static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 				    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	unsigned int reg = AIC31XX_DACFLAG1;
 	unsigned int mask;
 
@@ -377,7 +378,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 		reg = AIC31XX_ADCFLAG;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown widget '%s' calling %s\n",
+		dev_err(component->dev, "Unknown widget '%s' calling %s\n",
 			w->name, __func__);
 		return -EINVAL;
 	}
@@ -388,7 +389,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMD:
 		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
 	default:
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			"Unhandled dapm widget event %d from %s\n",
 			event, w->name);
 	}
@@ -444,30 +445,30 @@ static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* change mic bias voltage to user defined */
-		snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+		snd_soc_component_update_bits(component, AIC31XX_MICBIAS,
 				    AIC31XX_MICBIAS_MASK,
 				    aic31xx->micbias_vg <<
 				    AIC31XX_MICBIAS_SHIFT);
-		dev_dbg(codec->dev, "%s: turned on\n", __func__);
+		dev_dbg(component->dev, "%s: turned on\n", __func__);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		/* turn mic bias off */
-		snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+		snd_soc_component_update_bits(component, AIC31XX_MICBIAS,
 				    AIC31XX_MICBIAS_MASK, 0);
-		dev_dbg(codec->dev, "%s: turned off\n", __func__);
+		dev_dbg(component->dev, "%s: turned off\n", __func__);
 		break;
 	}
 	return 0;
 }
 
 static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = {
-	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
 
 	SND_SOC_DAPM_MUX("DAC Left Input",
 			 SND_SOC_NOPM, 0, 0, &ldac_in_control),
@@ -500,6 +501,10 @@ static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
 			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
+	/* Keep BCLK/WCLK enabled even if DAC/ADC is powered down */
+	SND_SOC_DAPM_SUPPLY("Activate I2S clocks", AIC31XX_IFACE2, 2, 0,
+			    NULL, 0),
+
 	/* Outputs */
 	SND_SOC_DAPM_OUTPUT("HPL"),
 	SND_SOC_DAPM_OUTPUT("HPR"),
@@ -552,6 +557,8 @@ static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
 	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
 			   aic31xx_right_output_switches,
 			   ARRAY_SIZE(aic31xx_right_output_switches)),
+
+	SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
 };
 
 static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
@@ -583,12 +590,12 @@ static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
 static const struct snd_soc_dapm_route
 common31xx_audio_map[] = {
 	/* DAC Input Routing */
-	{"DAC Left Input", "Left Data", "DAC IN"},
-	{"DAC Left Input", "Right Data", "DAC IN"},
-	{"DAC Left Input", "Mono", "DAC IN"},
-	{"DAC Right Input", "Left Data", "DAC IN"},
-	{"DAC Right Input", "Right Data", "DAC IN"},
-	{"DAC Right Input", "Mono", "DAC IN"},
+	{"DAC Left Input", "Left Data", "AIF IN"},
+	{"DAC Left Input", "Right Data", "AIF IN"},
+	{"DAC Left Input", "Mono", "AIF IN"},
+	{"DAC Right Input", "Left Data", "AIF IN"},
+	{"DAC Right Input", "Right Data", "AIF IN"},
+	{"DAC Right Input", "Mono", "AIF IN"},
 	{"DAC Left", NULL, "DAC Left Input"},
 	{"DAC Right", NULL, "DAC Right Input"},
 
@@ -639,6 +646,8 @@ aic31xx_audio_map[] = {
 
 	{"ADC", NULL, "MIC_GAIN_CTL"},
 
+	{"AIF OUT", NULL, "ADC"},
+
 	/* Left Output */
 	{"Output Left", "From Left DAC", "DAC Left"},
 	{"Output Left", "From MIC1LP", "MIC1LP"},
@@ -670,34 +679,61 @@ aic310x_audio_map[] = {
 	{"SPK", NULL, "SPK ClassD"},
 };
 
-static int aic31xx_add_controls(struct snd_soc_codec *codec)
+/*
+ * Always connected DAPM routes for codec clock master modes.
+ * If the codec is the master on the I2S bus, we need to power up components
+ * to have valid DAC_CLK.
+ *
+ * In order to have the I2S clocks on the bus either the DACs/ADC need to be
+ * enabled, or the P0/R29/D2 (Keep bclk/wclk in power down) need to be set.
+ *
+ * Otherwise the codec will not generate clocks on the bus.
+ */
+static const struct snd_soc_dapm_route
+common31xx_cm_audio_map[] = {
+	{"HPL", NULL, "AIF IN"},
+	{"HPR", NULL, "AIF IN"},
+
+	{"AIF IN", NULL, "Activate I2S clocks"},
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_cm_audio_map[] = {
+	{"AIF OUT", NULL, "MIC1LP"},
+	{"AIF OUT", NULL, "MIC1RP"},
+	{"AIF OUT", NULL, "MIC1LM"},
+
+	{"AIF OUT", NULL, "Activate I2S clocks"},
+};
+
+static int aic31xx_add_controls(struct snd_soc_component *component)
 {
 	int ret = 0;
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 
 	if (!(aic31xx->codec_type & DAC31XX_BIT))
-		ret = snd_soc_add_codec_controls(
-			codec, aic31xx_snd_controls,
+		ret = snd_soc_add_component_controls(
+			component, aic31xx_snd_controls,
 			ARRAY_SIZE(aic31xx_snd_controls));
 	if (ret)
 		return ret;
 
 	if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT)
-		ret = snd_soc_add_codec_controls(
-			codec, aic311x_snd_controls,
+		ret = snd_soc_add_component_controls(
+			component, aic311x_snd_controls,
 			ARRAY_SIZE(aic311x_snd_controls));
 	else
-		ret = snd_soc_add_codec_controls(
-			codec, aic310x_snd_controls,
+		ret = snd_soc_add_component_controls(
+			component, aic310x_snd_controls,
 			ARRAY_SIZE(aic310x_snd_controls));
 
 	return ret;
 }
 
-static int aic31xx_add_widgets(struct snd_soc_codec *codec)
+static int aic31xx_add_widgets(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if (aic31xx->codec_type & DAC31XX_BIT) {
@@ -751,10 +787,10 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int aic31xx_setup_pll(struct snd_soc_codec *codec,
+static int aic31xx_setup_pll(struct snd_soc_component *component,
 			     struct snd_pcm_hw_params *params)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	int bclk_score = snd_soc_params_to_frame_size(params);
 	int mclk_p;
 	int bclk_n = 0;
@@ -762,15 +798,15 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
 	int i;
 
 	if (!aic31xx->sysclk || !aic31xx->p_div) {
-		dev_err(codec->dev, "Master clock not supplied\n");
+		dev_err(component->dev, "Master clock not supplied\n");
 		return -EINVAL;
 	}
 	mclk_p = aic31xx->sysclk / aic31xx->p_div;
 
 	/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
-	snd_soc_update_bits(codec, AIC31XX_CLKMUX,
+	snd_soc_component_update_bits(component, AIC31XX_CLKMUX,
 			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
-	snd_soc_update_bits(codec, AIC31XX_IFACE2,
+	snd_soc_component_update_bits(component, AIC31XX_IFACE2,
 			    AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);
 
 	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
@@ -789,14 +825,14 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
 	}
 
 	if (match == -1) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: Sample rate (%u) and format not supported\n",
 			__func__, params_rate(params));
 		/* See bellow for details how fix this. */
 		return -EINVAL;
 	}
 	if (bclk_score != 0) {
-		dev_warn(codec->dev, "Can not produce exact bitclock");
+		dev_warn(component->dev, "Can not produce exact bitclock");
 		/* This is fine if using dsp format, but if using i2s
 		   there may be trouble. To fix the issue edit the
 		   aic31xx_divs table for your mclk and sample
@@ -808,39 +844,39 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
 	i = match;
 
 	/* PLL configuration */
-	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
+	snd_soc_component_update_bits(component, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
 			    (aic31xx->p_div << 4) | 0x01);
-	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
+	snd_soc_component_write(component, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
 
-	snd_soc_write(codec, AIC31XX_PLLDMSB,
+	snd_soc_component_write(component, AIC31XX_PLLDMSB,
 		      aic31xx_divs[i].pll_d >> 8);
-	snd_soc_write(codec, AIC31XX_PLLDLSB,
+	snd_soc_component_write(component, AIC31XX_PLLDLSB,
 		      aic31xx_divs[i].pll_d & 0xff);
 
 	/* DAC dividers configuration */
-	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
+	snd_soc_component_update_bits(component, AIC31XX_NDAC, AIC31XX_PLL_MASK,
 			    aic31xx_divs[i].ndac);
-	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
+	snd_soc_component_update_bits(component, AIC31XX_MDAC, AIC31XX_PLL_MASK,
 			    aic31xx_divs[i].mdac);
 
-	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
-	snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
+	snd_soc_component_write(component, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
+	snd_soc_component_write(component, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
 
 	/* ADC dividers configuration. Write reset value 1 if not used. */
-	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
+	snd_soc_component_update_bits(component, AIC31XX_NADC, AIC31XX_PLL_MASK,
 			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
-	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
+	snd_soc_component_update_bits(component, AIC31XX_MADC, AIC31XX_PLL_MASK,
 			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);
 
-	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
+	snd_soc_component_write(component, AIC31XX_AOSR, aic31xx_divs[i].aosr);
 
 	/* Bit clock divider configuration. */
-	snd_soc_update_bits(codec, AIC31XX_BCLKN,
+	snd_soc_component_update_bits(component, AIC31XX_BCLKN,
 			    AIC31XX_PLL_MASK, bclk_n);
 
 	aic31xx->rate_div_line = i;
 
-	dev_dbg(codec->dev,
+	dev_dbg(component->dev,
 		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
 		aic31xx_divs[i].pll_j,
 		aic31xx_divs[i].pll_d,
@@ -861,10 +897,10 @@ static int aic31xx_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u8 data = 0;
 
-	dev_dbg(codec->dev, "## %s: width %d rate %d\n",
+	dev_dbg(component->dev, "## %s: width %d rate %d\n",
 		__func__, params_width(params),
 		params_rate(params));
 
@@ -884,43 +920,90 @@ static int aic31xx_hw_params(struct snd_pcm_substream *substream,
 			AIC31XX_IFACE1_DATALEN_SHIFT);
 		break;
 	default:
-		dev_err(codec->dev, "%s: Unsupported width %d\n",
+		dev_err(component->dev, "%s: Unsupported width %d\n",
 			__func__, params_width(params));
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AIC31XX_IFACE1,
+	snd_soc_component_update_bits(component, AIC31XX_IFACE1,
 			    AIC31XX_IFACE1_DATALEN_MASK,
 			    data);
 
-	return aic31xx_setup_pll(codec, params);
+	return aic31xx_setup_pll(component, params);
 }
 
 static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	if (mute) {
-		snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+		snd_soc_component_update_bits(component, AIC31XX_DACMUTE,
 				    AIC31XX_DACMUTE_MASK,
 				    AIC31XX_DACMUTE_MASK);
 	} else {
-		snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+		snd_soc_component_update_bits(component, AIC31XX_DACMUTE,
 				    AIC31XX_DACMUTE_MASK, 0x0);
 	}
 
 	return 0;
 }
 
+static int aic31xx_clock_master_routes(struct snd_soc_component *component,
+				       unsigned int fmt)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	fmt &= SND_SOC_DAIFMT_MASTER_MASK;
+	if (fmt == SND_SOC_DAIFMT_CBS_CFS &&
+	    aic31xx->master_dapm_route_applied) {
+		/*
+		 * Remove the DAPM route(s) for codec clock master modes,
+		 * if applied
+		 */
+		ret = snd_soc_dapm_del_routes(dapm, common31xx_cm_audio_map,
+					ARRAY_SIZE(common31xx_cm_audio_map));
+		if (!ret && !(aic31xx->codec_type & DAC31XX_BIT))
+			ret = snd_soc_dapm_del_routes(dapm,
+					aic31xx_cm_audio_map,
+					ARRAY_SIZE(aic31xx_cm_audio_map));
+
+		if (ret)
+			return ret;
+
+		aic31xx->master_dapm_route_applied = false;
+	} else if (fmt != SND_SOC_DAIFMT_CBS_CFS &&
+		   !aic31xx->master_dapm_route_applied) {
+		/*
+		 * Add the needed DAPM route(s) for codec clock master modes,
+		 * if it is not done already
+		 */
+		ret = snd_soc_dapm_add_routes(dapm, common31xx_cm_audio_map,
+					ARRAY_SIZE(common31xx_cm_audio_map));
+		if (!ret && !(aic31xx->codec_type & DAC31XX_BIT))
+			ret = snd_soc_dapm_add_routes(dapm,
+					aic31xx_cm_audio_map,
+					ARRAY_SIZE(aic31xx_cm_audio_map));
+
+		if (ret)
+			return ret;
+
+		aic31xx->master_dapm_route_applied = true;
+	}
+
+	return 0;
+}
+
 static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			       unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 iface_reg1 = 0;
 	u8 iface_reg2 = 0;
 	u8 dsp_a_val = 0;
 
-	dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
+	dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -936,7 +1019,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	case SND_SOC_DAIFMT_CBS_CFS:
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI master/slave interface\n");
+		dev_err(component->dev, "Invalid DAI master/slave interface\n");
 		return -EINVAL;
 	}
 
@@ -948,7 +1031,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		iface_reg2 |= AIC31XX_BCLKINV_MASK;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
+		dev_err(component->dev, "Invalid DAI clock signal polarity\n");
 		return -EINVAL;
 	}
 
@@ -977,32 +1060,32 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			       AIC31XX_IFACE1_DATATYPE_SHIFT);
 		break;
 	default:
-		dev_err(codec->dev, "Invalid DAI interface format\n");
+		dev_err(component->dev, "Invalid DAI interface format\n");
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AIC31XX_IFACE1,
+	snd_soc_component_update_bits(component, AIC31XX_IFACE1,
 			    AIC31XX_IFACE1_DATATYPE_MASK |
 			    AIC31XX_IFACE1_MASTER_MASK,
 			    iface_reg1);
-	snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET,
+	snd_soc_component_update_bits(component, AIC31XX_DATA_OFFSET,
 			    AIC31XX_DATA_OFFSET_MASK,
 			    dsp_a_val);
-	snd_soc_update_bits(codec, AIC31XX_IFACE2,
+	snd_soc_component_update_bits(component, AIC31XX_IFACE2,
 			    AIC31XX_BCLKINV_MASK,
 			    iface_reg2);
 
-	return 0;
+	return aic31xx_clock_master_routes(component, fmt);
 }
 
 static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	int i;
 
-	dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
+	dev_dbg(component->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
 		__func__, clk_id, freq, dir);
 
 	for (i = 1; i < 8; i++)
@@ -1025,7 +1108,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	}
 
 	/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
-	snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
+	snd_soc_component_update_bits(component, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
 			    clk_id << AIC31XX_PLL_CLKIN_SHIFT);
 
 	aic31xx->sysclk = freq;
@@ -1071,42 +1154,42 @@ static int aic31xx_reset(struct aic31xx_priv *aic31xx)
 	return ret;
 }
 
-static void aic31xx_clk_on(struct snd_soc_codec *codec)
+static void aic31xx_clk_on(struct snd_soc_component *component)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	u8 mask = AIC31XX_PM_MASK;
 	u8 on = AIC31XX_PM_MASK;
 
-	dev_dbg(codec->dev, "codec clock -> on (rate %d)\n",
+	dev_dbg(component->dev, "codec clock -> on (rate %d)\n",
 		aic31xx_divs[aic31xx->rate_div_line].rate);
-	snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, on);
+	snd_soc_component_update_bits(component, AIC31XX_PLLPR, mask, on);
 	mdelay(10);
-	snd_soc_update_bits(codec, AIC31XX_NDAC, mask, on);
-	snd_soc_update_bits(codec, AIC31XX_MDAC, mask, on);
+	snd_soc_component_update_bits(component, AIC31XX_NDAC, mask, on);
+	snd_soc_component_update_bits(component, AIC31XX_MDAC, mask, on);
 	if (aic31xx_divs[aic31xx->rate_div_line].nadc)
-		snd_soc_update_bits(codec, AIC31XX_NADC, mask, on);
+		snd_soc_component_update_bits(component, AIC31XX_NADC, mask, on);
 	if (aic31xx_divs[aic31xx->rate_div_line].madc)
-		snd_soc_update_bits(codec, AIC31XX_MADC, mask, on);
-	snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, on);
+		snd_soc_component_update_bits(component, AIC31XX_MADC, mask, on);
+	snd_soc_component_update_bits(component, AIC31XX_BCLKN, mask, on);
 }
 
-static void aic31xx_clk_off(struct snd_soc_codec *codec)
+static void aic31xx_clk_off(struct snd_soc_component *component)
 {
 	u8 mask = AIC31XX_PM_MASK;
 	u8 off = 0;
 
-	dev_dbg(codec->dev, "codec clock -> off\n");
-	snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, off);
-	snd_soc_update_bits(codec, AIC31XX_MADC, mask, off);
-	snd_soc_update_bits(codec, AIC31XX_NADC, mask, off);
-	snd_soc_update_bits(codec, AIC31XX_MDAC, mask, off);
-	snd_soc_update_bits(codec, AIC31XX_NDAC, mask, off);
-	snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, off);
+	dev_dbg(component->dev, "codec clock -> off\n");
+	snd_soc_component_update_bits(component, AIC31XX_BCLKN, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_MADC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_NADC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_MDAC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_NDAC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_PLLPR, mask, off);
 }
 
-static int aic31xx_power_on(struct snd_soc_codec *codec)
+static int aic31xx_power_on(struct snd_soc_component *component)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
@@ -1123,7 +1206,7 @@ static int aic31xx_power_on(struct snd_soc_codec *codec)
 
 	ret = regcache_sync(aic31xx->regmap);
 	if (ret) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Failed to restore cache: %d\n", ret);
 		regcache_cache_only(aic31xx->regmap, true);
 		regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
@@ -1134,57 +1217,57 @@ static int aic31xx_power_on(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static void aic31xx_power_off(struct snd_soc_codec *codec)
+static void aic31xx_power_off(struct snd_soc_component *component)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 
 	regcache_cache_only(aic31xx->regmap, true);
 	regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
 			       aic31xx->supplies);
 }
 
-static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
+static int aic31xx_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
-		snd_soc_codec_get_bias_level(codec), level);
+	dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
+		snd_soc_component_get_bias_level(component), level);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
-			aic31xx_clk_on(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			aic31xx_clk_on(component);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		switch (snd_soc_codec_get_bias_level(codec)) {
+		switch (snd_soc_component_get_bias_level(component)) {
 		case SND_SOC_BIAS_OFF:
-			aic31xx_power_on(codec);
+			aic31xx_power_on(component);
 			break;
 		case SND_SOC_BIAS_PREPARE:
-			aic31xx_clk_off(codec);
+			aic31xx_clk_off(component);
 			break;
 		default:
 			BUG();
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
-			aic31xx_power_off(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			aic31xx_power_off(component);
 		break;
 	}
 
 	return 0;
 }
 
-static int aic31xx_codec_probe(struct snd_soc_codec *codec)
+static int aic31xx_codec_probe(struct snd_soc_component *component)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	int i, ret;
 
 	dev_dbg(aic31xx->dev, "## %s\n", __func__);
 
-	aic31xx->codec = codec;
+	aic31xx->component = component;
 
 	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
 		aic31xx->disable_nb[i].nb.notifier_call =
@@ -1193,7 +1276,7 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
 		ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
 						  &aic31xx->disable_nb[i].nb);
 		if (ret) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to request regulator notifier: %d\n",
 				ret);
 			return ret;
@@ -1203,43 +1286,42 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
 	regcache_cache_only(aic31xx->regmap, true);
 	regcache_mark_dirty(aic31xx->regmap);
 
-	ret = aic31xx_add_controls(codec);
+	ret = aic31xx_add_controls(component);
 	if (ret)
 		return ret;
 
-	ret = aic31xx_add_widgets(codec);
+	ret = aic31xx_add_widgets(component);
 	if (ret)
 		return ret;
 
 	return 0;
 }
 
-static int aic31xx_codec_remove(struct snd_soc_codec *codec)
+static void aic31xx_codec_remove(struct snd_soc_component *component)
 {
-	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
 		regulator_unregister_notifier(aic31xx->supplies[i].consumer,
 					      &aic31xx->disable_nb[i].nb);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
+static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
 	.probe			= aic31xx_codec_probe,
 	.remove			= aic31xx_codec_remove,
 	.set_bias_level		= aic31xx_set_bias_level,
-	.suspend_bias_off	= true,
-
-	.component_driver = {
-		.controls		= common31xx_snd_controls,
-		.num_controls		= ARRAY_SIZE(common31xx_snd_controls),
-		.dapm_widgets		= common31xx_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(common31xx_dapm_widgets),
-		.dapm_routes		= common31xx_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(common31xx_audio_map),
-	},
+	.controls		= common31xx_snd_controls,
+	.num_controls		= ARRAY_SIZE(common31xx_snd_controls),
+	.dapm_widgets		= common31xx_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(common31xx_dapm_widgets),
+	.dapm_routes		= common31xx_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(common31xx_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct snd_soc_dai_ops aic31xx_dai_ops = {
@@ -1375,23 +1457,17 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
 	}
 
 	if (aic31xx->codec_type & DAC31XX_BIT)
-		return snd_soc_register_codec(&i2c->dev,
+		return devm_snd_soc_register_component(&i2c->dev,
 				&soc_codec_driver_aic31xx,
 				dac31xx_dai_driver,
 				ARRAY_SIZE(dac31xx_dai_driver));
 	else
-		return snd_soc_register_codec(&i2c->dev,
+		return devm_snd_soc_register_component(&i2c->dev,
 				&soc_codec_driver_aic31xx,
 				aic31xx_dai_driver,
 				ARRAY_SIZE(aic31xx_dai_driver));
 }
 
-static int aic31xx_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
-}
-
 static const struct i2c_device_id aic31xx_i2c_id[] = {
 	{ "tlv320aic310x", AIC3100 },
 	{ "tlv320aic311x", AIC3110 },
@@ -1412,7 +1488,6 @@ static struct i2c_driver aic31xx_i2c_driver = {
 		.acpi_match_table = ACPI_PTR(aic31xx_acpi_match),
 	},
 	.probe		= aic31xx_i2c_probe,
-	.remove		= aic31xx_i2c_remove,
 	.id_table	= aic31xx_i2c_id,
 };
 module_i2c_driver(aic31xx_i2c_driver);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 15ac7cba86fe..0b587585b38b 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -160,6 +160,7 @@ struct aic31xx_pdata {
 #define AIC31XX_DACMOD2BCLK		0x01
 #define AIC31XX_ADC2BCLK		0x02
 #define AIC31XX_ADCMOD2BCLK		0x03
+#define AIC31XX_KEEP_I2SCLK		BIT(2)
 
 /* AIC31XX_ADCFLAG */
 #define AIC31XX_ADCPWRSTATUS_MASK	BIT(6)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index fea019343c3b..e2b5a11b16d1 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -82,10 +82,10 @@ struct aic32x4_priv {
 static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	u8 val;
 
-	val = snd_soc_read(codec, AIC32X4_DINCTL);
+	val = snd_soc_component_read32(component, AIC32X4_DINCTL);
 
 	ucontrol->value.integer.value[0] = (val & 0x01);
 
@@ -95,11 +95,11 @@ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
 static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	u8 val;
 	u8 gpio_check;
 
-	val = snd_soc_read(codec, AIC32X4_DOUTCTL);
+	val = snd_soc_component_read32(component, AIC32X4_DOUTCTL);
 	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
 	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
 		printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
@@ -115,7 +115,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
 	else
 		val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH;
 
-	snd_soc_write(codec, AIC32X4_DOUTCTL, val);
+	snd_soc_component_write(component, AIC32X4_DOUTCTL, val);
 
 	return 0;
 };
@@ -123,10 +123,10 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
 static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	u8 val;
 
-	val = snd_soc_read(codec, AIC32X4_SCLKCTL);
+	val = snd_soc_component_read32(component, AIC32X4_SCLKCTL);
 
 	ucontrol->value.integer.value[0] = (val & 0x01);
 
@@ -136,11 +136,11 @@ static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
 static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	u8 val;
 	u8 gpio_check;
 
-	val = snd_soc_read(codec, AIC32X4_MISOCTL);
+	val = snd_soc_component_read32(component, AIC32X4_MISOCTL);
 	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
 	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
 		printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
@@ -156,7 +156,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
 	else
 		val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH;
 
-	snd_soc_write(codec, AIC32X4_MISOCTL, val);
+	snd_soc_component_write(component, AIC32X4_MISOCTL, val);
 
 	return 0;
 };
@@ -164,10 +164,10 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
 static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	u8 val;
 
-	val = snd_soc_read(codec, AIC32X4_GPIOCTL);
+	val = snd_soc_component_read32(component, AIC32X4_GPIOCTL);
 	ucontrol->value.integer.value[0] = ((val & 0x2) >> 1);
 
 	return 0;
@@ -176,11 +176,11 @@ static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
 static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	u8 val;
 	u8 gpio_check;
 
-	val = snd_soc_read(codec, AIC32X4_GPIOCTL);
+	val = snd_soc_component_read32(component, AIC32X4_GPIOCTL);
 	gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
 	if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
 		printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
@@ -196,7 +196,7 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
 	else
 		val &= 0xfe;
 
-	snd_soc_write(codec, AIC32X4_GPIOCTL, val);
+	snd_soc_component_write(component, AIC32X4_GPIOCTL, val);
 
 	return 0;
 };
@@ -597,8 +597,8 @@ static inline int aic32x4_get_divs(int mclk, int rate)
 static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 12000000:
@@ -613,7 +613,7 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u8 iface_reg_1 = 0;
 	u8 iface_reg_2 = 0;
 	u8 iface_reg_3 = 0;
@@ -657,12 +657,12 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, AIC32X4_IFACE1,
+	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
 			    AIC32X4_IFACE1_DATATYPE_MASK |
 			    AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
-	snd_soc_update_bits(codec, AIC32X4_IFACE2,
+	snd_soc_component_update_bits(component, AIC32X4_IFACE2,
 			    AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
-	snd_soc_update_bits(codec, AIC32X4_IFACE3,
+	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
 			    AIC32X4_BCLKINV_MASK, iface_reg_3);
 
 	return 0;
@@ -672,8 +672,8 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 	u8 iface1_reg = 0;
 	u8 dacsetup_reg = 0;
 	int i;
@@ -685,54 +685,54 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* MCLK as PLL_CLKIN */
-	snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
+	snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
 			    AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
 	/* PLL as CODEC_CLKIN */
-	snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
+	snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
 			    AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
 	/* DAC_MOD_CLK as BDIV_CLKIN */
-	snd_soc_update_bits(codec, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
+	snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
 			    AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
 
 	/* We will fix R value to 1 and will make P & J=K.D as variable */
-	snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
+	snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
 
 	/* PLL P value */
-	snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
+	snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
 			    aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
 
 	/* PLL J value */
-	snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
+	snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
 
 	/* PLL D value */
-	snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
-	snd_soc_write(codec, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
+	snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
+	snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
 
 	/* NDAC divider value */
-	snd_soc_update_bits(codec, AIC32X4_NDAC,
+	snd_soc_component_update_bits(component, AIC32X4_NDAC,
 			    AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
 
 	/* MDAC divider value */
-	snd_soc_update_bits(codec, AIC32X4_MDAC,
+	snd_soc_component_update_bits(component, AIC32X4_MDAC,
 			    AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
 
 	/* DOSR MSB & LSB values */
-	snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
-	snd_soc_write(codec, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
+	snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+	snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
 
 	/* NADC divider value */
-	snd_soc_update_bits(codec, AIC32X4_NADC,
+	snd_soc_component_update_bits(component, AIC32X4_NADC,
 			    AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
 
 	/* MADC divider value */
-	snd_soc_update_bits(codec, AIC32X4_MADC,
+	snd_soc_component_update_bits(component, AIC32X4_MADC,
 			    AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
 
 	/* AOSR value */
-	snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+	snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
 
 	/* BCLK N divider */
-	snd_soc_update_bits(codec, AIC32X4_BCLKN,
+	snd_soc_component_update_bits(component, AIC32X4_BCLKN,
 			    AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
 
 	switch (params_width(params)) {
@@ -753,7 +753,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 			       AIC32X4_IFACE1_DATALEN_SHIFT);
 		break;
 	}
-	snd_soc_update_bits(codec, AIC32X4_IFACE1,
+	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
 			    AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
 
 	if (params_channels(params) == 1) {
@@ -764,7 +764,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 		else
 			dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
 	}
-	snd_soc_update_bits(codec, AIC32X4_DACSETUP,
+	snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
 			    AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
 
 	return 0;
@@ -772,18 +772,18 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 
 static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	snd_soc_update_bits(codec, AIC32X4_DACMUTE,
+	snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
 			    AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
 
 	return 0;
 }
 
-static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
+static int aic32x4_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -791,59 +791,59 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
 		/* Switch on master clock */
 		ret = clk_prepare_enable(aic32x4->mclk);
 		if (ret) {
-			dev_err(codec->dev, "Failed to enable master clock\n");
+			dev_err(component->dev, "Failed to enable master clock\n");
 			return ret;
 		}
 
 		/* Switch on PLL */
-		snd_soc_update_bits(codec, AIC32X4_PLLPR,
+		snd_soc_component_update_bits(component, AIC32X4_PLLPR,
 				    AIC32X4_PLLEN, AIC32X4_PLLEN);
 
 		/* Switch on NDAC Divider */
-		snd_soc_update_bits(codec, AIC32X4_NDAC,
+		snd_soc_component_update_bits(component, AIC32X4_NDAC,
 				    AIC32X4_NDACEN, AIC32X4_NDACEN);
 
 		/* Switch on MDAC Divider */
-		snd_soc_update_bits(codec, AIC32X4_MDAC,
+		snd_soc_component_update_bits(component, AIC32X4_MDAC,
 				    AIC32X4_MDACEN, AIC32X4_MDACEN);
 
 		/* Switch on NADC Divider */
-		snd_soc_update_bits(codec, AIC32X4_NADC,
+		snd_soc_component_update_bits(component, AIC32X4_NADC,
 				    AIC32X4_NADCEN, AIC32X4_NADCEN);
 
 		/* Switch on MADC Divider */
-		snd_soc_update_bits(codec, AIC32X4_MADC,
+		snd_soc_component_update_bits(component, AIC32X4_MADC,
 				    AIC32X4_MADCEN, AIC32X4_MADCEN);
 
 		/* Switch on BCLK_N Divider */
-		snd_soc_update_bits(codec, AIC32X4_BCLKN,
+		snd_soc_component_update_bits(component, AIC32X4_BCLKN,
 				    AIC32X4_BCLKEN, AIC32X4_BCLKEN);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* Switch off BCLK_N Divider */
-		snd_soc_update_bits(codec, AIC32X4_BCLKN,
+		snd_soc_component_update_bits(component, AIC32X4_BCLKN,
 				    AIC32X4_BCLKEN, 0);
 
 		/* Switch off MADC Divider */
-		snd_soc_update_bits(codec, AIC32X4_MADC,
+		snd_soc_component_update_bits(component, AIC32X4_MADC,
 				    AIC32X4_MADCEN, 0);
 
 		/* Switch off NADC Divider */
-		snd_soc_update_bits(codec, AIC32X4_NADC,
+		snd_soc_component_update_bits(component, AIC32X4_NADC,
 				    AIC32X4_NADCEN, 0);
 
 		/* Switch off MDAC Divider */
-		snd_soc_update_bits(codec, AIC32X4_MDAC,
+		snd_soc_component_update_bits(component, AIC32X4_MDAC,
 				    AIC32X4_MDACEN, 0);
 
 		/* Switch off NDAC Divider */
-		snd_soc_update_bits(codec, AIC32X4_NDAC,
+		snd_soc_component_update_bits(component, AIC32X4_NDAC,
 				    AIC32X4_NDACEN, 0);
 
 		/* Switch off PLL */
-		snd_soc_update_bits(codec, AIC32X4_PLLPR,
+		snd_soc_component_update_bits(component, AIC32X4_PLLPR,
 				    AIC32X4_PLLEN, 0);
 
 		/* Switch off master clock */
@@ -884,55 +884,55 @@ static struct snd_soc_dai_driver aic32x4_dai = {
 	.symmetric_rates = 1,
 };
 
-static void aic32x4_setup_gpios(struct snd_soc_codec *codec)
+static void aic32x4_setup_gpios(struct snd_soc_component *component)
 {
-	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 
 	/* setup GPIO functions */
 	/* MFP1 */
 	if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
-		snd_soc_write(codec, AIC32X4_DINCTL,
+		snd_soc_component_write(component, AIC32X4_DINCTL,
 		      aic32x4->setup->gpio_func[0]);
-		snd_soc_add_codec_controls(codec, aic32x4_mfp1,
+		snd_soc_add_component_controls(component, aic32x4_mfp1,
 			ARRAY_SIZE(aic32x4_mfp1));
 	}
 
 	/* MFP2 */
 	if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
-		snd_soc_write(codec, AIC32X4_DOUTCTL,
+		snd_soc_component_write(component, AIC32X4_DOUTCTL,
 		      aic32x4->setup->gpio_func[1]);
-		snd_soc_add_codec_controls(codec, aic32x4_mfp2,
+		snd_soc_add_component_controls(component, aic32x4_mfp2,
 			ARRAY_SIZE(aic32x4_mfp2));
 	}
 
 	/* MFP3 */
 	if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
-		snd_soc_write(codec, AIC32X4_SCLKCTL,
+		snd_soc_component_write(component, AIC32X4_SCLKCTL,
 		      aic32x4->setup->gpio_func[2]);
-		snd_soc_add_codec_controls(codec, aic32x4_mfp3,
+		snd_soc_add_component_controls(component, aic32x4_mfp3,
 			ARRAY_SIZE(aic32x4_mfp3));
 	}
 
 	/* MFP4 */
 	if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
-		snd_soc_write(codec, AIC32X4_MISOCTL,
+		snd_soc_component_write(component, AIC32X4_MISOCTL,
 		      aic32x4->setup->gpio_func[3]);
-		snd_soc_add_codec_controls(codec, aic32x4_mfp4,
+		snd_soc_add_component_controls(component, aic32x4_mfp4,
 			ARRAY_SIZE(aic32x4_mfp4));
 	}
 
 	/* MFP5 */
 	if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
-		snd_soc_write(codec, AIC32X4_GPIOCTL,
+		snd_soc_component_write(component, AIC32X4_GPIOCTL,
 		      aic32x4->setup->gpio_func[4]);
-		snd_soc_add_codec_controls(codec, aic32x4_mfp5,
+		snd_soc_add_component_controls(component, aic32x4_mfp5,
 			ARRAY_SIZE(aic32x4_mfp5));
 	}
 }
 
-static int aic32x4_codec_probe(struct snd_soc_codec *codec)
+static int aic32x4_component_probe(struct snd_soc_component *component)
 {
-	struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 	u32 tmp_reg;
 
 	if (gpio_is_valid(aic32x4->rstn_gpio)) {
@@ -940,42 +940,42 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec)
 		gpio_set_value(aic32x4->rstn_gpio, 1);
 	}
 
-	snd_soc_write(codec, AIC32X4_RESET, 0x01);
+	snd_soc_component_write(component, AIC32X4_RESET, 0x01);
 
 	if (aic32x4->setup)
-		aic32x4_setup_gpios(codec);
+		aic32x4_setup_gpios(component);
 
 	/* Power platform configuration */
 	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
-		snd_soc_write(codec, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
+		snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
 						      AIC32X4_MICBIAS_2075V);
 	}
 	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
-		snd_soc_write(codec, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
+		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
 
 	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
 			AIC32X4_LDOCTLEN : 0;
-	snd_soc_write(codec, AIC32X4_LDOCTL, tmp_reg);
+	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
 
-	tmp_reg = snd_soc_read(codec, AIC32X4_CMMODE);
+	tmp_reg = snd_soc_component_read32(component, AIC32X4_CMMODE);
 	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
 		tmp_reg |= AIC32X4_LDOIN_18_36;
 	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
 		tmp_reg |= AIC32X4_LDOIN2HP;
-	snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg);
+	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
 
 	/* Mic PGA routing */
 	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
-		snd_soc_write(codec, AIC32X4_LMICPGANIN,
+		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
 				AIC32X4_LMICPGANIN_IN2R_10K);
 	else
-		snd_soc_write(codec, AIC32X4_LMICPGANIN,
+		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
 				AIC32X4_LMICPGANIN_CM1L_10K);
 	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
-		snd_soc_write(codec, AIC32X4_RMICPGANIN,
+		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
 				AIC32X4_RMICPGANIN_IN1L_10K);
 	else
-		snd_soc_write(codec, AIC32X4_RMICPGANIN,
+		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
 				AIC32X4_RMICPGANIN_CM1R_10K);
 
 	/*
@@ -983,27 +983,28 @@ static int aic32x4_codec_probe(struct snd_soc_codec *codec)
 	 * and down for the first capture to work properly. It seems related to
 	 * a HW BUG or some kind of behavior not documented in the datasheet.
 	 */
-	tmp_reg = snd_soc_read(codec, AIC32X4_ADCSETUP);
-	snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg |
+	tmp_reg = snd_soc_component_read32(component, AIC32X4_ADCSETUP);
+	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
 				AIC32X4_LADC_EN | AIC32X4_RADC_EN);
-	snd_soc_write(codec, AIC32X4_ADCSETUP, tmp_reg);
+	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
-	.probe = aic32x4_codec_probe,
-	.set_bias_level = aic32x4_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= aic32x4_snd_controls,
-		.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
-		.dapm_widgets		= aic32x4_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
-		.dapm_routes		= aic32x4_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
+	.probe			= aic32x4_component_probe,
+	.set_bias_level		= aic32x4_set_bias_level,
+	.controls		= aic32x4_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
+	.dapm_widgets		= aic32x4_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
+	.dapm_routes		= aic32x4_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
@@ -1181,10 +1182,10 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(dev,
-			&soc_codec_dev_aic32x4, &aic32x4_dai, 1);
+	ret = devm_snd_soc_register_component(dev,
+			&soc_component_dev_aic32x4, &aic32x4_dai, 1);
 	if (ret) {
-		dev_err(dev, "Failed to register codec\n");
+		dev_err(dev, "Failed to register component\n");
 		aic32x4_disable_regulators(aic32x4);
 		return ret;
 	}
@@ -1199,8 +1200,6 @@ int aic32x4_remove(struct device *dev)
 
 	aic32x4_disable_regulators(aic32x4);
 
-	snd_soc_unregister_codec(dev);
-
 	return 0;
 }
 EXPORT_SYMBOL(aic32x4_remove);
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index b751cad545da..6a271e6e6b8f 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -72,7 +72,7 @@ struct aic3x_disable_nb {
 
 /* codec private data */
 struct aic3x_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regmap *regmap;
 	struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
 	struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
@@ -162,8 +162,8 @@ static const struct regmap_config aic3x_regmap = {
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -172,7 +172,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 	unsigned int mask = (1 << fls(max)) - 1;
 	unsigned int invert = mc->invert;
 	unsigned short val;
-	struct snd_soc_dapm_update update = { 0 };
+	struct snd_soc_dapm_update update = {};
 	int connect, change;
 
 	val = (ucontrol->value.integer.value[0] & mask);
@@ -189,7 +189,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 	mask <<= shift;
 	val <<= shift;
 
-	change = snd_soc_test_bits(codec, reg, mask, val);
+	change = snd_soc_component_test_bits(component, reg, mask, val);
 	if (change) {
 		update.kcontrol = kcontrol;
 		update.reg = reg;
@@ -215,19 +215,19 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* change mic bias voltage to user defined */
-		snd_soc_update_bits(codec, MICBIAS_CTRL,
+		snd_soc_component_update_bits(component, MICBIAS_CTRL,
 				MICBIAS_LEVEL_MASK,
 				aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, MICBIAS_CTRL,
+		snd_soc_component_update_bits(component, MICBIAS_CTRL,
 				MICBIAS_LEVEL_MASK, 0);
 		break;
 	}
@@ -993,10 +993,10 @@ static const struct snd_soc_dapm_route intercon_3007[] = {
 	{"SPOM", NULL, "Right Class-D Out"},
 };
 
-static int aic3x_add_widgets(struct snd_soc_codec *codec)
+static int aic3x_add_widgets(struct snd_soc_component *component)
 {
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	switch (aic3x->model) {
 	case AIC3X_MODEL_3X:
@@ -1035,8 +1035,8 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 			   struct snd_pcm_hw_params *params,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
 	u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
 	u16 d, pll_d = 1;
@@ -1047,7 +1047,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 		width = params_width(params);
 
 	/* select data word length */
-	data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+	data = snd_soc_component_read32(component, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
 	switch (width) {
 	case 16:
 		break;
@@ -1061,7 +1061,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 		data |= (0x03 << 4);
 		break;
 	}
-	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLB, data);
 
 	/* Fsref can be 44100 or 48000 */
 	fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
@@ -1076,15 +1076,15 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 
 	if (bypass_pll) {
 		pll_q &= 0xf;
-		snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
-		snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+		snd_soc_component_write(component, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+		snd_soc_component_write(component, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
 		/* disable PLL if it is bypassed */
-		snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLL_ENABLE, 0);
+		snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG, PLL_ENABLE, 0);
 
 	} else {
-		snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+		snd_soc_component_write(component, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
 		/* enable PLL when it is used */
-		snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
+		snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
 				    PLL_ENABLE, PLL_ENABLE);
 	}
 
@@ -1094,7 +1094,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 	data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
 	if (params_rate(params) >= 64000)
 		data |= DUAL_RATE_MODE;
-	snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
+	snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
 
 	/* codec sample rate select */
 	data = (fsref * 20) / params_rate(params);
@@ -1103,7 +1103,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 	data /= 5;
 	data -= 2;
 	data |= (data << 4);
-	snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
+	snd_soc_component_write(component, AIC3X_SAMPLE_RATE_SEL_REG, data);
 
 	if (bypass_pll)
 		return 0;
@@ -1172,13 +1172,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 	}
 
 found:
-	snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
-	snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
+	snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
+	snd_soc_component_write(component, AIC3X_OVRF_STATUS_AND_PLLR_REG,
 		      pll_r << PLLR_SHIFT);
-	snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
-	snd_soc_write(codec, AIC3X_PLL_PROGC_REG,
+	snd_soc_component_write(component, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+	snd_soc_component_write(component, AIC3X_PLL_PROGC_REG,
 		      (pll_d >> 6) << PLLD_MSB_SHIFT);
-	snd_soc_write(codec, AIC3X_PLL_PROGD_REG,
+	snd_soc_component_write(component, AIC3X_PLL_PROGD_REG,
 		      (pll_d & 0x3F) << PLLD_LSB_SHIFT);
 
 	return 0;
@@ -1187,8 +1187,8 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 static int aic3x_prepare(struct snd_pcm_substream *substream,
 			 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	int delay = 0;
 	int width = aic3x->slot_width;
 
@@ -1202,23 +1202,23 @@ static int aic3x_prepare(struct snd_pcm_substream *substream,
 		delay += aic3x->tdm_delay*width;
 
 	/* Configure data delay */
-	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLC, delay);
 
 	return 0;
 }
 
 static int aic3x_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON;
-	u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON;
+	struct snd_soc_component *component = dai->component;
+	u8 ldac_reg = snd_soc_component_read32(component, LDAC_VOL) & ~MUTE_ON;
+	u8 rdac_reg = snd_soc_component_read32(component, RDAC_VOL) & ~MUTE_ON;
 
 	if (mute) {
-		snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
-		snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
+		snd_soc_component_write(component, LDAC_VOL, ldac_reg | MUTE_ON);
+		snd_soc_component_write(component, RDAC_VOL, rdac_reg | MUTE_ON);
 	} else {
-		snd_soc_write(codec, LDAC_VOL, ldac_reg);
-		snd_soc_write(codec, RDAC_VOL, rdac_reg);
+		snd_soc_component_write(component, LDAC_VOL, ldac_reg);
+		snd_soc_component_write(component, RDAC_VOL, rdac_reg);
 	}
 
 	return 0;
@@ -1227,13 +1227,13 @@ static int aic3x_mute(struct snd_soc_dai *dai, int mute)
 static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 
 	/* set clock on MCLK or GPIO2 or BCLK */
-	snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK,
+	snd_soc_component_update_bits(component, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK,
 				clk_id << PLLCLK_IN_SHIFT);
-	snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK,
+	snd_soc_component_update_bits(component, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK,
 				clk_id << CLKDIV_IN_SHIFT);
 
 	aic3x->sysclk = freq;
@@ -1243,12 +1243,12 @@ static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			     unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	u8 iface_areg, iface_breg;
 
-	iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
-	iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
+	iface_areg = snd_soc_component_read32(component, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+	iface_breg = snd_soc_component_read32(component, AIC3X_ASD_INTF_CTRLB) & 0x3f;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1289,8 +1289,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
 	/* set iface */
-	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
-	snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLA, iface_areg);
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLB, iface_breg);
 
 	return 0;
 }
@@ -1299,24 +1299,24 @@ static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 				  unsigned int tx_mask, unsigned int rx_mask,
 				  int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	unsigned int lsb;
 
 	if (tx_mask != rx_mask) {
-		dev_err(codec->dev, "tx and rx masks must be symmetric\n");
+		dev_err(component->dev, "tx and rx masks must be symmetric\n");
 		return -EINVAL;
 	}
 
 	if (unlikely(!tx_mask)) {
-		dev_err(codec->dev, "tx and rx masks need to be non 0\n");
+		dev_err(component->dev, "tx and rx masks need to be non 0\n");
 		return -EINVAL;
 	}
 
 	/* TDM based on DSP mode requires slots to be adjacent */
 	lsb = __ffs(tx_mask);
 	if ((lsb + 1) != __fls(tx_mask)) {
-		dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
+		dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
 		return -EINVAL;
 	}
 
@@ -1327,7 +1327,7 @@ static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 	case 32:
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported slot width %d\n", slot_width);
+		dev_err(component->dev, "Unsupported slot width %d\n", slot_width);
 		return -EINVAL;
 	}
 
@@ -1336,7 +1336,7 @@ static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 	aic3x->slot_width = slot_width;
 
 	/* DOUT in high-impedance on inactive bit clocks */
-	snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA,
+	snd_soc_component_update_bits(component, AIC3X_ASD_INTF_CTRLA,
 			    DOUT_TRISTATE, DOUT_TRISTATE);
 
 	return 0;
@@ -1362,9 +1362,9 @@ static int aic3x_regulator_event(struct notifier_block *nb,
 	return 0;
 }
 
-static int aic3x_set_power(struct snd_soc_codec *codec, int power)
+static int aic3x_set_power(struct snd_soc_component *component, int power)
 {
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	unsigned int pll_c, pll_d;
 	int ret;
 
@@ -1388,12 +1388,12 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 		 * writing one of them and thus caused other one also not
 		 * being written
 		 */
-		pll_c = snd_soc_read(codec, AIC3X_PLL_PROGC_REG);
-		pll_d = snd_soc_read(codec, AIC3X_PLL_PROGD_REG);
+		pll_c = snd_soc_component_read32(component, AIC3X_PLL_PROGC_REG);
+		pll_d = snd_soc_component_read32(component, AIC3X_PLL_PROGD_REG);
 		if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def ||
 			pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) {
-			snd_soc_write(codec, AIC3X_PLL_PROGC_REG, pll_c);
-			snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d);
+			snd_soc_component_write(component, AIC3X_PLL_PROGC_REG, pll_c);
+			snd_soc_component_write(component, AIC3X_PLL_PROGD_REG, pll_d);
 		}
 
 		/*
@@ -1407,7 +1407,7 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 		 * possible VDD leakage currents in case the supply regulators
 		 * remain on
 		 */
-		snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
+		snd_soc_component_write(component, AIC3X_RESET, SOFT_RESET);
 		regcache_mark_dirty(aic3x->regmap);
 		aic3x->power = 0;
 		/* HW writes are needless when bias is off */
@@ -1419,35 +1419,35 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 	return ret;
 }
 
-static int aic3x_set_bias_level(struct snd_soc_codec *codec,
+static int aic3x_set_bias_level(struct snd_soc_component *component,
 				enum snd_soc_bias_level level)
 {
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY &&
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY &&
 		    aic3x->master) {
 			/* enable pll */
-			snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
+			snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
 					    PLL_ENABLE, PLL_ENABLE);
 		}
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		if (!aic3x->power)
-			aic3x_set_power(codec, 1);
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE &&
+			aic3x_set_power(component, 1);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE &&
 		    aic3x->master) {
 			/* disable pll */
-			snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
+			snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
 					    PLL_ENABLE, 0);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		if (aic3x->power)
-			aic3x_set_power(codec, 0);
+			aic3x_set_power(component, 0);
 		break;
 	}
 
@@ -1486,96 +1486,96 @@ static struct snd_soc_dai_driver aic3x_dai = {
 	.symmetric_rates = 1,
 };
 
-static void aic3x_mono_init(struct snd_soc_codec *codec)
+static void aic3x_mono_init(struct snd_soc_component *component)
 {
 	/* DAC to Mono Line Out default volume and route to Output mixer */
-	snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-	snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 
 	/* unmute all outputs */
-	snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, MONOLOPM_CTRL, UNMUTE, UNMUTE);
 
 	/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
-	snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
 
 	/* Line2 to Mono Out default volume, disconnect from Output Mixer */
-	snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
 }
 
 /*
  * initialise the AIC3X driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int aic3x_init(struct snd_soc_codec *codec)
+static int aic3x_init(struct snd_soc_component *component)
 {
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 
-	snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
-	snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
+	snd_soc_component_write(component, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+	snd_soc_component_write(component, AIC3X_RESET, SOFT_RESET);
 
 	/* DAC default volume and mute */
-	snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
-	snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+	snd_soc_component_write(component, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+	snd_soc_component_write(component, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
 
 	/* DAC to HP default volume and route to Output mixer */
-	snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
-	snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
-	snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
-	snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
 	/* DAC to Line Out default volume and route to Output mixer */
-	snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-	snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 
 	/* unmute all outputs */
-	snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE);
-	snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE);
-	snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE);
-	snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE);
-	snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE);
-	snd_soc_update_bits(codec, HPRCOM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, LLOPM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, RLOPM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPLOUT_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPROUT_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPLCOM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPRCOM_CTRL, UNMUTE, UNMUTE);
 
 	/* ADC default volume and unmute */
-	snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN);
-	snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN);
+	snd_soc_component_write(component, LADC_VOL, DEFAULT_GAIN);
+	snd_soc_component_write(component, RADC_VOL, DEFAULT_GAIN);
 	/* By default route Line1 to ADC PGA mixer */
-	snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0);
-	snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0);
+	snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x0);
+	snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x0);
 
 	/* PGA to HP Bypass default volume, disconnect from Output Mixer */
-	snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
 	/* PGA to Line Out default volume, disconnect from Output Mixer */
-	snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
-	snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
 
 	/* On tlv320aic3104, these registers are reserved and must not be written */
 	if (aic3x->model != AIC3X_MODEL_3104) {
 		/* Line2 to HP Bypass default volume, disconnect from Output Mixer */
-		snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
-		snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
-		snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
-		snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
 		/* Line2 Line Out default volume, disconnect from Output Mixer */
-		snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
-		snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
 	}
 
 	switch (aic3x->model) {
 	case AIC3X_MODEL_3X:
 	case AIC3X_MODEL_33:
-		aic3x_mono_init(codec);
+		aic3x_mono_init(component);
 		break;
 	case AIC3X_MODEL_3007:
-		snd_soc_write(codec, CLASSD_CTRL, 0);
+		snd_soc_component_write(component, CLASSD_CTRL, 0);
 		break;
 	}
 
 	/*  Output common-mode voltage = 1.5 V */
-	snd_soc_update_bits(codec, HPOUT_SC, HPOUT_SC_OCMV_MASK,
+	snd_soc_component_update_bits(component, HPOUT_SC, HPOUT_SC_OCMV_MASK,
 			    aic3x->ocmv << HPOUT_SC_OCMV_SHIFT);
 
 	return 0;
@@ -1594,13 +1594,13 @@ static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
 	return false;
 }
 
-static int aic3x_probe(struct snd_soc_codec *codec)
+static int aic3x_probe(struct snd_soc_component *component)
 {
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	int ret, i;
 
 	INIT_LIST_HEAD(&aic3x->list);
-	aic3x->codec = codec;
+	aic3x->component = component;
 
 	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
 		aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
@@ -1608,7 +1608,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 		ret = regulator_register_notifier(aic3x->supplies[i].consumer,
 						  &aic3x->disable_nb[i].nb);
 		if (ret) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to request regulator notifier: %d\n",
 				 ret);
 			goto err_notif;
@@ -1616,32 +1616,32 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 	}
 
 	regcache_mark_dirty(aic3x->regmap);
-	aic3x_init(codec);
+	aic3x_init(component);
 
 	if (aic3x->setup) {
 		if (aic3x->model != AIC3X_MODEL_3104) {
 			/* setup GPIO functions */
-			snd_soc_write(codec, AIC3X_GPIO1_REG,
+			snd_soc_component_write(component, AIC3X_GPIO1_REG,
 				      (aic3x->setup->gpio_func[0] & 0xf) << 4);
-			snd_soc_write(codec, AIC3X_GPIO2_REG,
+			snd_soc_component_write(component, AIC3X_GPIO2_REG,
 				      (aic3x->setup->gpio_func[1] & 0xf) << 4);
 		} else {
-			dev_warn(codec->dev, "GPIO functionality is not supported on tlv320aic3104\n");
+			dev_warn(component->dev, "GPIO functionality is not supported on tlv320aic3104\n");
 		}
 	}
 
 	switch (aic3x->model) {
 	case AIC3X_MODEL_3X:
 	case AIC3X_MODEL_33:
-		snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+		snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
 				ARRAY_SIZE(aic3x_extra_snd_controls));
-		snd_soc_add_codec_controls(codec, aic3x_mono_controls,
+		snd_soc_add_component_controls(component, aic3x_mono_controls,
 				ARRAY_SIZE(aic3x_mono_controls));
 		break;
 	case AIC3X_MODEL_3007:
-		snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+		snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
 				ARRAY_SIZE(aic3x_extra_snd_controls));
-		snd_soc_add_codec_controls(codec,
+		snd_soc_add_component_controls(component,
 				&aic3x_classd_amp_gain_ctrl, 1);
 		break;
 	case AIC3X_MODEL_3104:
@@ -1653,7 +1653,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 	case AIC3X_MICBIAS_2_0V:
 	case AIC3X_MICBIAS_2_5V:
 	case AIC3X_MICBIAS_AVDDV:
-		snd_soc_update_bits(codec, MICBIAS_CTRL,
+		snd_soc_component_update_bits(component, MICBIAS_CTRL,
 				    MICBIAS_LEVEL_MASK,
 				    (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
 		break;
@@ -1666,7 +1666,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 		break;
 	}
 
-	aic3x_add_widgets(codec);
+	aic3x_add_widgets(component);
 
 	return 0;
 
@@ -1677,32 +1677,30 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int aic3x_remove(struct snd_soc_codec *codec)
+static void aic3x_remove(struct snd_soc_component *component)
 {
-	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
 	int i;
 
 	list_del(&aic3x->list);
 	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
 		regulator_unregister_notifier(aic3x->supplies[i].consumer,
 					      &aic3x->disable_nb[i].nb);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_aic3x = {
-	.set_bias_level = aic3x_set_bias_level,
-	.idle_bias_off = true,
-	.probe = aic3x_probe,
-	.remove = aic3x_remove,
-	.component_driver = {
-		.controls		= aic3x_snd_controls,
-		.num_controls		= ARRAY_SIZE(aic3x_snd_controls),
-		.dapm_widgets		= aic3x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(aic3x_dapm_widgets),
-		.dapm_routes		= intercon,
-		.num_dapm_routes	= ARRAY_SIZE(intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_aic3x = {
+	.set_bias_level		= aic3x_set_bias_level,
+	.probe			= aic3x_probe,
+	.remove			= aic3x_remove,
+	.controls		= aic3x_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic3x_snd_controls),
+	.dapm_widgets		= aic3x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aic3x_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static void aic3x_configure_ocmv(struct i2c_client *client)
@@ -1876,8 +1874,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 				ret);
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_aic3x, &aic3x_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_aic3x, &aic3x_dai, 1);
 
 	if (ret != 0)
 		goto err_gpio;
@@ -1898,7 +1896,6 @@ static int aic3x_i2c_remove(struct i2c_client *client)
 {
 	struct aic3x_priv *aic3x = i2c_get_clientdata(client);
 
-	snd_soc_unregister_codec(&client->dev);
 	if (gpio_is_valid(aic3x->gpio_reset) &&
 	    !aic3x_is_shared_reset(aic3x)) {
 		gpio_set_value(aic3x->gpio_reset, 0);
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 8c71d2f876ff..a957eaeb7bc1 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -63,9 +63,9 @@
 	(((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
 
 static void dac33_calculate_times(struct snd_pcm_substream *substream,
-				  struct snd_soc_codec *codec);
+				  struct snd_soc_component *component);
 static int dac33_prepare_chip(struct snd_pcm_substream *substream,
-			      struct snd_soc_codec *codec);
+			      struct snd_soc_component *component);
 
 enum dac33_state {
 	DAC33_IDLE = 0,
@@ -91,7 +91,7 @@ static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
 struct tlv320dac33_priv {
 	struct mutex mutex;
 	struct work_struct work;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
 	struct snd_pcm_substream *substream;
 	int power_gpio;
@@ -171,10 +171,10 @@ static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
 };
 
 /* Register read and write */
-static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec,
+static inline unsigned int dac33_read_reg_cache(struct snd_soc_component *component,
 						unsigned reg)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	u8 *cache = dac33->reg_cache;
 	if (reg >= DAC33_CACHEREGNUM)
 		return 0;
@@ -182,10 +182,10 @@ static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec,
 	return cache[reg];
 }
 
-static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
+static inline void dac33_write_reg_cache(struct snd_soc_component *component,
 					 u8 reg, u8 value)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	u8 *cache = dac33->reg_cache;
 	if (reg >= DAC33_CACHEREGNUM)
 		return;
@@ -193,10 +193,10 @@ static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
 	cache[reg] = value;
 }
 
-static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
+static int dac33_read(struct snd_soc_component *component, unsigned int reg,
 		      u8 *value)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	int val, ret = 0;
 
 	*value = reg & 0xff;
@@ -205,24 +205,24 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
 	if (dac33->chip_power) {
 		val = i2c_smbus_read_byte_data(dac33->i2c, value[0]);
 		if (val < 0) {
-			dev_err(codec->dev, "Read failed (%d)\n", val);
-			value[0] = dac33_read_reg_cache(codec, reg);
+			dev_err(component->dev, "Read failed (%d)\n", val);
+			value[0] = dac33_read_reg_cache(component, reg);
 			ret = val;
 		} else {
 			value[0] = val;
-			dac33_write_reg_cache(codec, reg, val);
+			dac33_write_reg_cache(component, reg, val);
 		}
 	} else {
-		value[0] = dac33_read_reg_cache(codec, reg);
+		value[0] = dac33_read_reg_cache(component, reg);
 	}
 
 	return ret;
 }
 
-static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
+static int dac33_write(struct snd_soc_component *component, unsigned int reg,
 		       unsigned int value)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	u8 data[2];
 	int ret = 0;
 
@@ -234,11 +234,11 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
 	data[0] = reg & 0xff;
 	data[1] = value & 0xff;
 
-	dac33_write_reg_cache(codec, data[0], data[1]);
+	dac33_write_reg_cache(component, data[0], data[1]);
 	if (dac33->chip_power) {
 		ret = i2c_master_send(dac33->i2c, data, 2);
 		if (ret != 2)
-			dev_err(codec->dev, "Write failed (%d)\n", ret);
+			dev_err(component->dev, "Write failed (%d)\n", ret);
 		else
 			ret = 0;
 	}
@@ -246,24 +246,24 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
 	return ret;
 }
 
-static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
+static int dac33_write_locked(struct snd_soc_component *component, unsigned int reg,
 			      unsigned int value)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&dac33->mutex);
-	ret = dac33_write(codec, reg, value);
+	ret = dac33_write(component, reg, value);
 	mutex_unlock(&dac33->mutex);
 
 	return ret;
 }
 
 #define DAC33_I2C_ADDR_AUTOINC	0x80
-static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
+static int dac33_write16(struct snd_soc_component *component, unsigned int reg,
 		       unsigned int value)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	u8 data[3];
 	int ret = 0;
 
@@ -277,15 +277,15 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
 	data[1] = (value >> 8) & 0xff;
 	data[2] = value & 0xff;
 
-	dac33_write_reg_cache(codec, data[0], data[1]);
-	dac33_write_reg_cache(codec, data[0] + 1, data[2]);
+	dac33_write_reg_cache(component, data[0], data[1]);
+	dac33_write_reg_cache(component, data[0] + 1, data[2]);
 
 	if (dac33->chip_power) {
 		/* We need to set autoincrement mode for 16 bit writes */
 		data[0] |= DAC33_I2C_ADDR_AUTOINC;
 		ret = i2c_master_send(dac33->i2c, data, 3);
 		if (ret != 3)
-			dev_err(codec->dev, "Write failed (%d)\n", ret);
+			dev_err(component->dev, "Write failed (%d)\n", ret);
 		else
 			ret = 0;
 	}
@@ -293,52 +293,52 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
 	return ret;
 }
 
-static void dac33_init_chip(struct snd_soc_codec *codec)
+static void dac33_init_chip(struct snd_soc_component *component)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	if (unlikely(!dac33->chip_power))
 		return;
 
 	/* A : DAC sample rate Fsref/1.5 */
-	dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
+	dac33_write(component, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
 	/* B : DAC src=normal, not muted */
-	dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
+	dac33_write(component, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
 					     DAC33_DACSRCL_LEFT);
 	/* C : (defaults) */
-	dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);
+	dac33_write(component, DAC33_DAC_CTRL_C, 0x00);
 
 	/* 73 : volume soft stepping control,
 	 clock source = internal osc (?) */
-	dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
+	dac33_write(component, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
 
 	/* Restore only selected registers (gains mostly) */
-	dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL,
-		    dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL));
-	dac33_write(codec, DAC33_RDAC_DIG_VOL_CTRL,
-		    dac33_read_reg_cache(codec, DAC33_RDAC_DIG_VOL_CTRL));
-
-	dac33_write(codec, DAC33_LINEL_TO_LLO_VOL,
-		    dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL));
-	dac33_write(codec, DAC33_LINER_TO_RLO_VOL,
-		    dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
-
-	dac33_write(codec, DAC33_OUT_AMP_CTRL,
-		    dac33_read_reg_cache(codec, DAC33_OUT_AMP_CTRL));
-
-	dac33_write(codec, DAC33_LDAC_PWR_CTRL,
-		    dac33_read_reg_cache(codec, DAC33_LDAC_PWR_CTRL));
-	dac33_write(codec, DAC33_RDAC_PWR_CTRL,
-		    dac33_read_reg_cache(codec, DAC33_RDAC_PWR_CTRL));
+	dac33_write(component, DAC33_LDAC_DIG_VOL_CTRL,
+		    dac33_read_reg_cache(component, DAC33_LDAC_DIG_VOL_CTRL));
+	dac33_write(component, DAC33_RDAC_DIG_VOL_CTRL,
+		    dac33_read_reg_cache(component, DAC33_RDAC_DIG_VOL_CTRL));
+
+	dac33_write(component, DAC33_LINEL_TO_LLO_VOL,
+		    dac33_read_reg_cache(component, DAC33_LINEL_TO_LLO_VOL));
+	dac33_write(component, DAC33_LINER_TO_RLO_VOL,
+		    dac33_read_reg_cache(component, DAC33_LINER_TO_RLO_VOL));
+
+	dac33_write(component, DAC33_OUT_AMP_CTRL,
+		    dac33_read_reg_cache(component, DAC33_OUT_AMP_CTRL));
+
+	dac33_write(component, DAC33_LDAC_PWR_CTRL,
+		    dac33_read_reg_cache(component, DAC33_LDAC_PWR_CTRL));
+	dac33_write(component, DAC33_RDAC_PWR_CTRL,
+		    dac33_read_reg_cache(component, DAC33_RDAC_PWR_CTRL));
 }
 
-static inline int dac33_read_id(struct snd_soc_codec *codec)
+static inline int dac33_read_id(struct snd_soc_component *component)
 {
 	int i, ret = 0;
 	u8 reg;
 
 	for (i = 0; i < 3; i++) {
-		ret = dac33_read(codec, DAC33_DEVICE_ID_MSB + i, &reg);
+		ret = dac33_read(component, DAC33_DEVICE_ID_MSB + i, &reg);
 		if (ret < 0)
 			break;
 	}
@@ -346,44 +346,44 @@ static inline int dac33_read_id(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
+static inline void dac33_soft_power(struct snd_soc_component *component, int power)
 {
 	u8 reg;
 
-	reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+	reg = dac33_read_reg_cache(component, DAC33_PWR_CTRL);
 	if (power)
 		reg |= DAC33_PDNALLB;
 	else
 		reg &= ~(DAC33_PDNALLB | DAC33_OSCPDNB |
 			 DAC33_DACRPDNB | DAC33_DACLPDNB);
-	dac33_write(codec, DAC33_PWR_CTRL, reg);
+	dac33_write(component, DAC33_PWR_CTRL, reg);
 }
 
-static inline void dac33_disable_digital(struct snd_soc_codec *codec)
+static inline void dac33_disable_digital(struct snd_soc_component *component)
 {
 	u8 reg;
 
 	/* Stop the DAI clock */
-	reg = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+	reg = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
 	reg &= ~DAC33_BCLKON;
-	dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg);
+	dac33_write(component, DAC33_SER_AUDIOIF_CTRL_B, reg);
 
 	/* Power down the Oscillator, and DACs */
-	reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+	reg = dac33_read_reg_cache(component, DAC33_PWR_CTRL);
 	reg &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
-	dac33_write(codec, DAC33_PWR_CTRL, reg);
+	dac33_write(component, DAC33_PWR_CTRL, reg);
 }
 
-static int dac33_hard_power(struct snd_soc_codec *codec, int power)
+static int dac33_hard_power(struct snd_soc_component *component, int power)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	mutex_lock(&dac33->mutex);
 
 	/* Safety check */
 	if (unlikely(power == dac33->chip_power)) {
-		dev_dbg(codec->dev, "Trying to set the same power state: %s\n",
+		dev_dbg(component->dev, "Trying to set the same power state: %s\n",
 			power ? "ON" : "OFF");
 		goto exit;
 	}
@@ -392,7 +392,7 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 		ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
 					  dac33->supplies);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to enable supplies: %d\n", ret);
 				goto exit;
 		}
@@ -402,14 +402,14 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 
 		dac33->chip_power = 1;
 	} else {
-		dac33_soft_power(codec, 0);
+		dac33_soft_power(component, 0);
 		if (dac33->power_gpio >= 0)
 			gpio_set_value(dac33->power_gpio, 0);
 
 		ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies),
 					     dac33->supplies);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to disable supplies: %d\n", ret);
 			goto exit;
 		}
@@ -425,18 +425,18 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 static int dac33_playback_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (likely(dac33->substream)) {
-			dac33_calculate_times(dac33->substream, codec);
-			dac33_prepare_chip(dac33->substream, codec);
+			dac33_calculate_times(dac33->substream, component);
+			dac33_prepare_chip(dac33->substream, component);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		dac33_disable_digital(codec);
+		dac33_disable_digital(component);
 		break;
 	}
 	return 0;
@@ -445,8 +445,8 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,
 static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = dac33->fifo_mode;
 
@@ -456,14 +456,14 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
 static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
 			 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if (dac33->fifo_mode == ucontrol->value.enumerated.item[0])
 		return 0;
 	/* Do not allow changes while stream is running*/
-	if (snd_soc_codec_is_active(codec))
+	if (snd_soc_component_is_active(component))
 		return -EPERM;
 
 	if (ucontrol->value.enumerated.item[0] >= DAC33_FIFO_LAST_MODE)
@@ -623,7 +623,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"RIGHT_LO", NULL, "Codec Power"},
 };
 
-static int dac33_set_bias_level(struct snd_soc_codec *codec,
+static int dac33_set_bias_level(struct snd_soc_component *component,
 				enum snd_soc_bias_level level)
 {
 	int ret;
@@ -634,20 +634,20 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			/* Coming from OFF, switch on the codec */
-			ret = dac33_hard_power(codec, 1);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Coming from OFF, switch on the component */
+			ret = dac33_hard_power(component, 1);
 			if (ret != 0)
 				return ret;
 
-			dac33_init_chip(codec);
+			dac33_init_chip(component);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		/* Do not power off, when the codec is already off */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		/* Do not power off, when the component is already off */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			return 0;
-		ret = dac33_hard_power(codec, 0);
+		ret = dac33_hard_power(component, 0);
 		if (ret != 0)
 			return ret;
 		break;
@@ -658,13 +658,13 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
 
 static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 {
-	struct snd_soc_codec *codec = dac33->codec;
+	struct snd_soc_component *component = dac33->component;
 	unsigned int delay;
 	unsigned long flags;
 
 	switch (dac33->fifo_mode) {
 	case DAC33_FIFO_MODE1:
-		dac33_write16(codec, DAC33_NSAMPLE_MSB,
+		dac33_write16(component, DAC33_NSAMPLE_MSB,
 			DAC33_THRREG(dac33->nsample));
 
 		/* Take the timestamps */
@@ -673,13 +673,13 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 		dac33->t_stamp1 = dac33->t_stamp2;
 		spin_unlock_irqrestore(&dac33->lock, flags);
 
-		dac33_write16(codec, DAC33_PREFILL_MSB,
+		dac33_write16(component, DAC33_PREFILL_MSB,
 				DAC33_THRREG(dac33->alarm_threshold));
 		/* Enable Alarm Threshold IRQ with a delay */
 		delay = SAMPLES_TO_US(dac33->burst_rate,
 				     dac33->alarm_threshold) + 1000;
 		usleep_range(delay, delay + 500);
-		dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
+		dac33_write(component, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
 		break;
 	case DAC33_FIFO_MODE7:
 		/* Take the timestamp */
@@ -689,14 +689,14 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 		dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
 		spin_unlock_irqrestore(&dac33->lock, flags);
 
-		dac33_write16(codec, DAC33_PREFILL_MSB,
+		dac33_write16(component, DAC33_PREFILL_MSB,
 				DAC33_THRREG(DAC33_MODE7_MARGIN));
 
 		/* Enable Upper Threshold IRQ */
-		dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
+		dac33_write(component, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
 		break;
 	default:
-		dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
+		dev_warn(component->dev, "Unhandled FIFO mode: %d\n",
 							dac33->fifo_mode);
 		break;
 	}
@@ -704,7 +704,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 
 static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
 {
-	struct snd_soc_codec *codec = dac33->codec;
+	struct snd_soc_component *component = dac33->component;
 	unsigned long flags;
 
 	switch (dac33->fifo_mode) {
@@ -714,14 +714,14 @@ static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
 		dac33->t_stamp2 = ktime_to_us(ktime_get());
 		spin_unlock_irqrestore(&dac33->lock, flags);
 
-		dac33_write16(codec, DAC33_NSAMPLE_MSB,
+		dac33_write16(component, DAC33_NSAMPLE_MSB,
 				DAC33_THRREG(dac33->nsample));
 		break;
 	case DAC33_FIFO_MODE7:
 		/* At the moment we are not using interrupts in mode7 */
 		break;
 	default:
-		dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
+		dev_warn(component->dev, "Unhandled FIFO mode: %d\n",
 							dac33->fifo_mode);
 		break;
 	}
@@ -729,12 +729,12 @@ static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
 
 static void dac33_work(struct work_struct *work)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct tlv320dac33_priv *dac33;
 	u8 reg;
 
 	dac33 = container_of(work, struct tlv320dac33_priv, work);
-	codec = dac33->codec;
+	component = dac33->component;
 
 	mutex_lock(&dac33->mutex);
 	switch (dac33->state) {
@@ -750,12 +750,12 @@ static void dac33_work(struct work_struct *work)
 	case DAC33_FLUSH:
 		dac33->state = DAC33_IDLE;
 		/* Mask all interrupts from dac33 */
-		dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
+		dac33_write(component, DAC33_FIFO_IRQ_MASK, 0);
 
 		/* flush fifo */
-		reg = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+		reg = dac33_read_reg_cache(component, DAC33_FIFO_CTRL_A);
 		reg |= DAC33_FIFOFLUSH;
-		dac33_write(codec, DAC33_FIFO_CTRL_A, reg);
+		dac33_write(component, DAC33_FIFO_CTRL_A, reg);
 		break;
 	}
 	mutex_unlock(&dac33->mutex);
@@ -763,8 +763,8 @@ static void dac33_work(struct work_struct *work)
 
 static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 {
-	struct snd_soc_codec *codec = dev;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dev;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	unsigned long flags;
 
 	spin_lock_irqsave(&dac33->lock, flags);
@@ -778,25 +778,25 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static void dac33_oscwait(struct snd_soc_codec *codec)
+static void dac33_oscwait(struct snd_soc_component *component)
 {
 	int timeout = 60;
 	u8 reg;
 
 	do {
 		usleep_range(1000, 2000);
-		dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
+		dac33_read(component, DAC33_INT_OSC_STATUS, &reg);
 	} while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
 	if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"internal oscillator calibration failed\n");
 }
 
 static int dac33_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	/* Stream started, save the substream pointer */
 	dac33->substream = substream;
@@ -807,8 +807,8 @@ static int dac33_startup(struct snd_pcm_substream *substream,
 static void dac33_shutdown(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	dac33->substream = NULL;
 }
@@ -819,8 +819,8 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 			   struct snd_pcm_hw_params *params,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	/* Check parameters for validity */
 	switch (params_rate(params)) {
@@ -828,7 +828,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 	case 48000:
 		break;
 	default:
-		dev_err(codec->dev, "unsupported rate %d\n",
+		dev_err(component->dev, "unsupported rate %d\n",
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -843,7 +843,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 		dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 64);
 		break;
 	default:
-		dev_err(codec->dev, "unsupported width %d\n",
+		dev_err(component->dev, "unsupported width %d\n",
 			params_width(params));
 		return -EINVAL;
 	}
@@ -862,9 +862,9 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
  * Use the known, working sequence of register writes to initialize the dac33.
  */
 static int dac33_prepare_chip(struct snd_pcm_substream *substream,
-			      struct snd_soc_codec *codec)
+			      struct snd_soc_component *component)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
 	u8 aictrl_a, aictrl_b, fifoctrl_a;
 
@@ -876,16 +876,16 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 					 dac33->refclk);
 		break;
 	default:
-		dev_err(codec->dev, "unsupported rate %d\n",
+		dev_err(component->dev, "unsupported rate %d\n",
 			substream->runtime->rate);
 		return -EINVAL;
 	}
 
 
-	aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
+	aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A);
 	aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK);
 	/* Read FIFO control A, and clear FIFO flush bit */
-	fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+	fifoctrl_a = dac33_read_reg_cache(component, DAC33_FIFO_CTRL_A);
 	fifoctrl_a &= ~DAC33_FIFOFLUSH;
 
 	fifoctrl_a &= ~DAC33_WIDTH;
@@ -898,7 +898,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 		aictrl_a |= (DAC33_NCYCL_32 | DAC33_WLEN_24);
 		break;
 	default:
-		dev_err(codec->dev, "unsupported format %d\n",
+		dev_err(component->dev, "unsupported format %d\n",
 			substream->runtime->format);
 		return -EINVAL;
 	}
@@ -914,57 +914,57 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 		return 0;
 	}
 
-	dac33_soft_power(codec, 0);
-	dac33_soft_power(codec, 1);
+	dac33_soft_power(component, 0);
+	dac33_soft_power(component, 1);
 
-	reg_tmp = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
-	dac33_write(codec, DAC33_INT_OSC_CTRL, reg_tmp);
+	reg_tmp = dac33_read_reg_cache(component, DAC33_INT_OSC_CTRL);
+	dac33_write(component, DAC33_INT_OSC_CTRL, reg_tmp);
 
 	/* Write registers 0x08 and 0x09 (MSB, LSB) */
-	dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
+	dac33_write16(component, DAC33_INT_OSC_FREQ_RAT_A, oscset);
 
 	/* OSC calibration time */
-	dac33_write(codec, DAC33_CALIB_TIME, 96);
+	dac33_write(component, DAC33_CALIB_TIME, 96);
 
 	/* adjustment treshold & step */
-	dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
+	dac33_write(component, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
 						 DAC33_ADJSTEP(1));
 
 	/* div=4 / gain=1 / div */
-	dac33_write(codec, DAC33_INT_OSC_CTRL_C, DAC33_REFDIV(4));
+	dac33_write(component, DAC33_INT_OSC_CTRL_C, DAC33_REFDIV(4));
 
-	pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+	pwr_ctrl = dac33_read_reg_cache(component, DAC33_PWR_CTRL);
 	pwr_ctrl |= DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB;
-	dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
+	dac33_write(component, DAC33_PWR_CTRL, pwr_ctrl);
 
-	dac33_oscwait(codec);
+	dac33_oscwait(component);
 
 	if (dac33->fifo_mode) {
 		/* Generic for all FIFO modes */
 		/* 50-51 : ASRC Control registers */
-		dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCLKDIV(1));
-		dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */
+		dac33_write(component, DAC33_ASRC_CTRL_A, DAC33_SRCLKDIV(1));
+		dac33_write(component, DAC33_ASRC_CTRL_B, 1); /* ??? */
 
 		/* Write registers 0x34 and 0x35 (MSB, LSB) */
-		dac33_write16(codec, DAC33_SRC_REF_CLK_RATIO_A, ratioset);
+		dac33_write16(component, DAC33_SRC_REF_CLK_RATIO_A, ratioset);
 
 		/* Set interrupts to high active */
-		dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
+		dac33_write(component, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
 	} else {
 		/* FIFO bypass mode */
 		/* 50-51 : ASRC Control registers */
-		dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
-		dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */
+		dac33_write(component, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
+		dac33_write(component, DAC33_ASRC_CTRL_B, 0); /* ??? */
 	}
 
 	/* Interrupt behaviour configuration */
 	switch (dac33->fifo_mode) {
 	case DAC33_FIFO_MODE1:
-		dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
+		dac33_write(component, DAC33_FIFO_IRQ_MODE_B,
 			    DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
 		break;
 	case DAC33_FIFO_MODE7:
-		dac33_write(codec, DAC33_FIFO_IRQ_MODE_A,
+		dac33_write(component, DAC33_FIFO_IRQ_MODE_A,
 			DAC33_UTM(DAC33_FIFO_IRQ_MODE_LEVEL));
 		break;
 	default:
@@ -972,7 +972,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+	aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
 
 	switch (dac33->fifo_mode) {
 	case DAC33_FIFO_MODE1:
@@ -1014,9 +1014,9 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a);
-	dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
-	dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
+	dac33_write(component, DAC33_FIFO_CTRL_A, fifoctrl_a);
+	dac33_write(component, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+	dac33_write(component, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
 
 	/*
 	 * BCLK divide ratio
@@ -1028,17 +1028,17 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 	 * 255: 255
 	 */
 	if (dac33->fifo_mode)
-		dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C,
+		dac33_write(component, DAC33_SER_AUDIOIF_CTRL_C,
 							dac33->burst_bclkdiv);
 	else
 		if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE)
-			dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
+			dac33_write(component, DAC33_SER_AUDIOIF_CTRL_C, 32);
 		else
-			dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 16);
+			dac33_write(component, DAC33_SER_AUDIOIF_CTRL_C, 16);
 
 	switch (dac33->fifo_mode) {
 	case DAC33_FIFO_MODE1:
-		dac33_write16(codec, DAC33_ATHR_MSB,
+		dac33_write16(component, DAC33_ATHR_MSB,
 			      DAC33_THRREG(dac33->alarm_threshold));
 		break;
 	case DAC33_FIFO_MODE7:
@@ -1046,8 +1046,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 		 * Configure the threshold levels, and leave 10 sample space
 		 * at the bottom, and also at the top of the FIFO
 		 */
-		dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
-		dac33_write16(codec, DAC33_LTHR_MSB,
+		dac33_write16(component, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
+		dac33_write16(component, DAC33_LTHR_MSB,
 			      DAC33_THRREG(DAC33_MODE7_MARGIN));
 		break;
 	default:
@@ -1060,9 +1060,9 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
 }
 
 static void dac33_calculate_times(struct snd_pcm_substream *substream,
-				  struct snd_soc_codec *codec)
+				  struct snd_soc_component *component)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	unsigned int period_size = substream->runtime->period_size;
 	unsigned int rate = substream->runtime->rate;
 	unsigned int nsample_limit;
@@ -1119,8 +1119,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream,
 static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (cmd) {
@@ -1151,8 +1151,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
 			struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	unsigned long long t0, t1, t_now;
 	unsigned int time_delta, uthr;
 	int samples_out, samples_in, samples;
@@ -1284,7 +1284,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
 		}
 		break;
 	default:
-		dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
+		dev_warn(component->dev, "Unhandled FIFO mode: %d\n",
 							dac33->fifo_mode);
 		break;
 	}
@@ -1295,12 +1295,12 @@ static snd_pcm_sframes_t dac33_dai_delay(
 static int dac33_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	u8 ioc_reg, asrcb_reg;
 
-	ioc_reg = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
-	asrcb_reg = dac33_read_reg_cache(codec, DAC33_ASRC_CTRL_B);
+	ioc_reg = dac33_read_reg_cache(component, DAC33_INT_OSC_CTRL);
+	asrcb_reg = dac33_read_reg_cache(component, DAC33_ASRC_CTRL_B);
 	switch (clk_id) {
 	case TLV320DAC33_MCLK:
 		ioc_reg |= DAC33_REFSEL;
@@ -1311,13 +1311,13 @@ static int dac33_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		asrcb_reg &= ~DAC33_SRCREFSEL;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock ID (%d)\n", clk_id);
+		dev_err(component->dev, "Invalid clock ID (%d)\n", clk_id);
 		break;
 	}
 	dac33->refclk = freq;
 
-	dac33_write_reg_cache(codec, DAC33_INT_OSC_CTRL, ioc_reg);
-	dac33_write_reg_cache(codec, DAC33_ASRC_CTRL_B, asrcb_reg);
+	dac33_write_reg_cache(component, DAC33_INT_OSC_CTRL, ioc_reg);
+	dac33_write_reg_cache(component, DAC33_ASRC_CTRL_B, asrcb_reg);
 
 	return 0;
 }
@@ -1325,12 +1325,12 @@ static int dac33_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			     unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	u8 aictrl_a, aictrl_b;
 
-	aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
-	aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+	aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A);
+	aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -1340,7 +1340,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* Codec Slave */
 		if (dac33->fifo_mode) {
-			dev_err(codec->dev, "FIFO mode requires master mode\n");
+			dev_err(component->dev, "FIFO mode requires master mode\n");
 			return -EINVAL;
 		} else
 			aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
@@ -1366,35 +1366,35 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		aictrl_a |= DAC33_AFMT_LEFT_J;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported format (%u)\n",
+		dev_err(component->dev, "Unsupported format (%u)\n",
 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
 		return -EINVAL;
 	}
 
-	dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
-	dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
+	dac33_write_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+	dac33_write_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
 
 	return 0;
 }
 
-static int dac33_soc_probe(struct snd_soc_codec *codec)
+static int dac33_soc_probe(struct snd_soc_component *component)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
-	dac33->codec = codec;
+	dac33->component = component;
 
 	/* Read the tlv320dac33 ID registers */
-	ret = dac33_hard_power(codec, 1);
+	ret = dac33_hard_power(component, 1);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+		dev_err(component->dev, "Failed to power up component: %d\n", ret);
 		goto err_power;
 	}
-	ret = dac33_read_id(codec);
-	dac33_hard_power(codec, 0);
+	ret = dac33_read_id(component);
+	dac33_hard_power(component, 0);
 
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read chip ID: %d\n", ret);
+		dev_err(component->dev, "Failed to read chip ID: %d\n", ret);
 		ret = -ENODEV;
 		goto err_power;
 	}
@@ -1403,9 +1403,9 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
 	if (dac33->irq >= 0) {
 		ret = request_irq(dac33->irq, dac33_interrupt_handler,
 				  IRQF_TRIGGER_RISING,
-				  codec->component.name, codec);
+				  component->name, component);
 		if (ret < 0) {
-			dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+			dev_err(component->dev, "Could not request IRQ%d (%d)\n",
 						dac33->irq, ret);
 			dac33->irq = -1;
 		}
@@ -1416,41 +1416,38 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
 
 	/* Only add the FIFO controls, if we have valid IRQ number */
 	if (dac33->irq >= 0)
-		snd_soc_add_codec_controls(codec, dac33_mode_snd_controls,
+		snd_soc_add_component_controls(component, dac33_mode_snd_controls,
 				     ARRAY_SIZE(dac33_mode_snd_controls));
 
 err_power:
 	return ret;
 }
 
-static int dac33_soc_remove(struct snd_soc_codec *codec)
+static void dac33_soc_remove(struct snd_soc_component *component)
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
 
 	if (dac33->irq >= 0) {
-		free_irq(dac33->irq, dac33->codec);
+		free_irq(dac33->irq, dac33->component);
 		flush_work(&dac33->work);
 	}
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
-	.read = dac33_read_reg_cache,
-	.write = dac33_write_locked,
-	.set_bias_level = dac33_set_bias_level,
-	.idle_bias_off = true,
-
-	.probe = dac33_soc_probe,
-	.remove = dac33_soc_remove,
-
-	.component_driver = {
-		.controls		= dac33_snd_controls,
-		.num_controls		= ARRAY_SIZE(dac33_snd_controls),
-		.dapm_widgets		= dac33_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(dac33_dapm_widgets),
-		.dapm_routes		= audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_tlv320dac33 = {
+	.read			= dac33_read_reg_cache,
+	.write			= dac33_write_locked,
+	.set_bias_level		= dac33_set_bias_level,
+	.probe			= dac33_soc_probe,
+	.remove			= dac33_soc_remove,
+	.controls		= dac33_snd_controls,
+	.num_controls		= ARRAY_SIZE(dac33_snd_controls),
+	.dapm_widgets		= dac33_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dac33_dapm_widgets),
+	.dapm_routes		= audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 #define DAC33_RATES	(SNDRV_PCM_RATE_44100 | \
@@ -1544,8 +1541,8 @@ static int dac33_i2c_probe(struct i2c_client *client,
 		goto err_get;
 	}
 
-	ret = snd_soc_register_codec(&client->dev,
-			&soc_codec_dev_tlv320dac33, &dac33_dai, 1);
+	ret = devm_snd_soc_register_component(&client->dev,
+			&soc_component_dev_tlv320dac33, &dac33_dai, 1);
 	if (ret < 0)
 		goto err_get;
 
@@ -1562,12 +1559,11 @@ static int dac33_i2c_remove(struct i2c_client *client)
 	struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
 
 	if (unlikely(dac33->chip_power))
-		dac33_hard_power(dac33->codec, 0);
+		dac33_hard_power(dac33->component, 0);
 
 	if (dac33->power_gpio >= 0)
 		gpio_free(dac33->power_gpio);
 
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index e7661d0315e6..e915261fa1cb 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -91,15 +91,15 @@ static const struct regmap_config tscs42xx_regmap = {
 };
 
 #define MAX_PLL_LOCK_20MS_WAITS 1
-static bool plls_locked(struct snd_soc_codec *codec)
+static bool plls_locked(struct snd_soc_component *component)
 {
 	int ret;
 	int count = MAX_PLL_LOCK_20MS_WAITS;
 
 	do {
-		ret = snd_soc_read(codec, R_PLLCTL0);
+		ret = snd_soc_component_read32(component, R_PLLCTL0);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to read PLL lock status (%d)\n", ret);
 			return false;
 		} else if (ret > 0) {
@@ -131,10 +131,10 @@ static int sample_rate_to_pll_freq_out(int sample_rate)
 }
 
 #define DACCRSTAT_MAX_TRYS 10
-static int write_coeff_ram(struct snd_soc_codec *codec, u8 *coeff_ram,
+static int write_coeff_ram(struct snd_soc_component *component, u8 *coeff_ram,
 	unsigned int addr, unsigned int coeff_cnt)
 {
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	int cnt;
 	int trys;
 	int ret;
@@ -142,9 +142,9 @@ static int write_coeff_ram(struct snd_soc_codec *codec, u8 *coeff_ram,
 	for (cnt = 0; cnt < coeff_cnt; cnt++, addr++) {
 
 		for (trys = 0; trys < DACCRSTAT_MAX_TRYS; trys++) {
-			ret = snd_soc_read(codec, R_DACCRSTAT);
+			ret = snd_soc_component_read32(component, R_DACCRSTAT);
 			if (ret < 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to read stat (%d)\n", ret);
 				return ret;
 			}
@@ -154,14 +154,14 @@ static int write_coeff_ram(struct snd_soc_codec *codec, u8 *coeff_ram,
 
 		if (trys == DACCRSTAT_MAX_TRYS) {
 			ret = -EIO;
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"dac coefficient write error (%d)\n", ret);
 			return ret;
 		}
 
 		ret = regmap_write(tscs42xx->regmap, R_DACCRADDR, addr);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to write dac ram address (%d)\n", ret);
 			return ret;
 		}
@@ -170,7 +170,7 @@ static int write_coeff_ram(struct snd_soc_codec *codec, u8 *coeff_ram,
 			&coeff_ram[addr * COEFF_SIZE],
 			COEFF_SIZE);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to write dac ram (%d)\n", ret);
 			return ret;
 		}
@@ -179,9 +179,9 @@ static int write_coeff_ram(struct snd_soc_codec *codec, u8 *coeff_ram,
 	return 0;
 }
 
-static int power_up_audio_plls(struct snd_soc_codec *codec)
+static int power_up_audio_plls(struct snd_soc_component *component)
 {
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	int freq_out;
 	int ret;
 	unsigned int mask;
@@ -199,20 +199,20 @@ static int power_up_audio_plls(struct snd_soc_codec *codec)
 		break;
 	default:
 		ret = -EINVAL;
-		dev_err(codec->dev, "Unrecognized PLL output freq (%d)\n", ret);
+		dev_err(component->dev, "Unrecognized PLL output freq (%d)\n", ret);
 		return ret;
 	}
 
 	mutex_lock(&tscs42xx->pll_lock);
 
-	ret = snd_soc_update_bits(codec, R_PLLCTL1C, mask, val);
+	ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to turn PLL on (%d)\n", ret);
+		dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret);
 		goto exit;
 	}
 
-	if (!plls_locked(codec)) {
-		dev_err(codec->dev, "Failed to lock plls\n");
+	if (!plls_locked(component)) {
+		dev_err(component->dev, "Failed to lock plls\n");
 		ret = -ENOMSG;
 		goto exit;
 	}
@@ -224,25 +224,25 @@ static int power_up_audio_plls(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int power_down_audio_plls(struct snd_soc_codec *codec)
+static int power_down_audio_plls(struct snd_soc_component *component)
 {
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&tscs42xx->pll_lock);
 
-	ret = snd_soc_update_bits(codec, R_PLLCTL1C,
+	ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
 			RM_PLLCTL1C_PDB_PLL1,
 			RV_PLLCTL1C_PDB_PLL1_DISABLE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to turn PLL off (%d)\n", ret);
+		dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
 		goto exit;
 	}
-	ret = snd_soc_update_bits(codec, R_PLLCTL1C,
+	ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
 			RM_PLLCTL1C_PDB_PLL2,
 			RV_PLLCTL1C_PDB_PLL2_DISABLE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to turn PLL off (%d)\n", ret);
+		dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
 		goto exit;
 	}
 
@@ -256,8 +256,8 @@ static int power_down_audio_plls(struct snd_soc_codec *codec)
 static int coeff_ram_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	struct coeff_ram_ctl *ctl =
 		(struct coeff_ram_ctl *)kcontrol->private_value;
 	struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -275,8 +275,8 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
 static int coeff_ram_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	struct coeff_ram_ctl *ctl =
 		(struct coeff_ram_ctl *)kcontrol->private_value;
 	struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -292,11 +292,11 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
 
 	mutex_lock(&tscs42xx->pll_lock);
 
-	if (plls_locked(codec)) {
-		ret = write_coeff_ram(codec, tscs42xx->coeff_ram,
+	if (plls_locked(component)) {
+		ret = write_coeff_ram(component, tscs42xx->coeff_ram,
 			ctl->addr, coeff_cnt);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to flush coeff ram cache (%d)\n", ret);
 			goto exit;
 		}
@@ -358,13 +358,13 @@ static int dapm_micb_event(struct snd_soc_dapm_widget *w,
 static int pll_event(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int ret;
 
 	if (SND_SOC_DAPM_EVENT_ON(event))
-		ret = power_up_audio_plls(codec);
+		ret = power_up_audio_plls(component);
 	else
-		ret = power_down_audio_plls(codec);
+		ret = power_down_audio_plls(component);
 
 	return ret;
 }
@@ -372,14 +372,14 @@ static int pll_event(struct snd_soc_dapm_widget *w,
 static int dac_event(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	mutex_lock(&tscs42xx->coeff_ram_lock);
 
 	if (tscs42xx->coeff_ram_synced == false) {
-		ret = write_coeff_ram(codec, tscs42xx->coeff_ram, 0x00,
+		ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00,
 			COEFF_RAM_COEFF_COUNT);
 		if (ret < 0)
 			goto exit;
@@ -790,7 +790,7 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
 		R_DACMBCREL3L, 2),
 };
 
-static int setup_sample_format(struct snd_soc_codec *codec,
+static int setup_sample_format(struct snd_soc_component *component,
 		snd_pcm_format_t format)
 {
 	unsigned int width;
@@ -811,21 +811,21 @@ static int setup_sample_format(struct snd_soc_codec *codec,
 		break;
 	default:
 		ret = -EINVAL;
-		dev_err(codec->dev, "Unsupported format width (%d)\n", ret);
+		dev_err(component->dev, "Unsupported format width (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_update_bits(codec, R_AIC1, RM_AIC1_WL, width);
+	ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_WL, width);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set sample width (%d)\n", ret);
+		dev_err(component->dev, "Failed to set sample width (%d)\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
-static int setup_sample_rate(struct snd_soc_codec *codec, unsigned int rate)
+static int setup_sample_rate(struct snd_soc_component *component, unsigned int rate)
 {
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	unsigned int br, bm;
 	int ret;
 
@@ -871,29 +871,29 @@ static int setup_sample_rate(struct snd_soc_codec *codec, unsigned int rate)
 		bm = RV_DACSR_DBM_2;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported sample rate %d\n", rate);
+		dev_err(component->dev, "Unsupported sample rate %d\n", rate);
 		return -EINVAL;
 	}
 
 	/* DAC and ADC share bit and frame clock */
-	ret = snd_soc_update_bits(codec, R_DACSR, RM_DACSR_DBR, br);
+	ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBR, br);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev, "Failed to update register (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_update_bits(codec, R_DACSR, RM_DACSR_DBM, bm);
+	ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBM, bm);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev, "Failed to update register (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_update_bits(codec, R_ADCSR, RM_DACSR_DBR, br);
+	ret = snd_soc_component_update_bits(component, R_ADCSR, RM_DACSR_DBR, br);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev, "Failed to update register (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_update_bits(codec, R_ADCSR, RM_DACSR_DBM, bm);
+	ret = snd_soc_component_update_bits(component, R_ADCSR, RM_DACSR_DBM, bm);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to update register (%d)\n", ret);
+		dev_err(component->dev, "Failed to update register (%d)\n", ret);
 		return ret;
 	}
 
@@ -1025,7 +1025,7 @@ static const struct pll_ctl *get_pll_ctl(int input_freq)
 	return pll_ctl;
 }
 
-static int set_pll_ctl_from_input_freq(struct snd_soc_codec *codec,
+static int set_pll_ctl_from_input_freq(struct snd_soc_component *component,
 		const int input_freq)
 {
 	int ret;
@@ -1035,18 +1035,18 @@ static int set_pll_ctl_from_input_freq(struct snd_soc_codec *codec,
 	pll_ctl = get_pll_ctl(input_freq);
 	if (!pll_ctl) {
 		ret = -EINVAL;
-		dev_err(codec->dev, "No PLL input entry for %d (%d)\n",
+		dev_err(component->dev, "No PLL input entry for %d (%d)\n",
 			input_freq, ret);
 		return ret;
 	}
 
 	for (i = 0; i < PLL_REG_SETTINGS_COUNT; ++i) {
-		ret = snd_soc_update_bits(codec,
+		ret = snd_soc_component_update_bits(component,
 			pll_ctl->settings[i].addr,
 			pll_ctl->settings[i].mask,
 			pll_ctl->settings[i].val);
 		if (ret < 0) {
-			dev_err(codec->dev, "Failed to set pll ctl (%d)\n",
+			dev_err(component->dev, "Failed to set pll ctl (%d)\n",
 				ret);
 			return ret;
 		}
@@ -1059,33 +1059,33 @@ static int tscs42xx_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *codec_dai)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int ret;
 
-	ret = setup_sample_format(codec, params_format(params));
+	ret = setup_sample_format(component, params_format(params));
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to setup sample format (%d)\n",
+		dev_err(component->dev, "Failed to setup sample format (%d)\n",
 			ret);
 		return ret;
 	}
 
-	ret = setup_sample_rate(codec, params_rate(params));
+	ret = setup_sample_rate(component, params_rate(params));
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to setup sample rate (%d)\n", ret);
+		dev_err(component->dev, "Failed to setup sample rate (%d)\n", ret);
 		return ret;
 	}
 
 	return 0;
 }
 
-static inline int dac_mute(struct snd_soc_codec *codec)
+static inline int dac_mute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_update_bits(codec, R_CNVRTR1, RM_CNVRTR1_DACMU,
+	ret = snd_soc_component_update_bits(component, R_CNVRTR1, RM_CNVRTR1_DACMU,
 		RV_CNVRTR1_DACMU_ENABLE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to mute DAC (%d)\n",
+		dev_err(component->dev, "Failed to mute DAC (%d)\n",
 				ret);
 		return ret;
 	}
@@ -1093,14 +1093,14 @@ static inline int dac_mute(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static inline int dac_unmute(struct snd_soc_codec *codec)
+static inline int dac_unmute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_update_bits(codec, R_CNVRTR1, RM_CNVRTR1_DACMU,
+	ret = snd_soc_component_update_bits(component, R_CNVRTR1, RM_CNVRTR1_DACMU,
 		RV_CNVRTR1_DACMU_DISABLE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to unmute DAC (%d)\n",
+		dev_err(component->dev, "Failed to unmute DAC (%d)\n",
 				ret);
 		return ret;
 	}
@@ -1108,14 +1108,14 @@ static inline int dac_unmute(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static inline int adc_mute(struct snd_soc_codec *codec)
+static inline int adc_mute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_update_bits(codec, R_CNVRTR0, RM_CNVRTR0_ADCMU,
+	ret = snd_soc_component_update_bits(component, R_CNVRTR0, RM_CNVRTR0_ADCMU,
 		RV_CNVRTR0_ADCMU_ENABLE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to mute ADC (%d)\n",
+		dev_err(component->dev, "Failed to mute ADC (%d)\n",
 				ret);
 		return ret;
 	}
@@ -1123,14 +1123,14 @@ static inline int adc_mute(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static inline int adc_unmute(struct snd_soc_codec *codec)
+static inline int adc_unmute(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = snd_soc_update_bits(codec, R_CNVRTR0, RM_CNVRTR0_ADCMU,
+	ret = snd_soc_component_update_bits(component, R_CNVRTR0, RM_CNVRTR0_ADCMU,
 		RV_CNVRTR0_ADCMU_DISABLE);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to unmute ADC (%d)\n",
+		dev_err(component->dev, "Failed to unmute ADC (%d)\n",
 				ret);
 		return ret;
 	}
@@ -1140,19 +1140,19 @@ static inline int adc_unmute(struct snd_soc_codec *codec)
 
 static int tscs42xx_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int ret;
 
 	if (mute)
 		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-			ret = dac_mute(codec);
+			ret = dac_mute(component);
 		else
-			ret = adc_mute(codec);
+			ret = adc_mute(component);
 	else
 		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-			ret = dac_unmute(codec);
+			ret = dac_unmute(component);
 		else
-			ret = adc_unmute(codec);
+			ret = adc_unmute(component);
 
 	return ret;
 }
@@ -1160,23 +1160,23 @@ static int tscs42xx_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int ret;
 
 	/* Slave mode not supported since it needs always-on frame clock */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
-		ret = snd_soc_update_bits(codec, R_AIC1, RM_AIC1_MS,
+		ret = snd_soc_component_update_bits(component, R_AIC1, RM_AIC1_MS,
 				RV_AIC1_MS_MASTER);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set codec DAI master (%d)\n", ret);
 			return ret;
 		}
 		break;
 	default:
 		ret = -EINVAL;
-		dev_err(codec->dev, "Unsupported format (%d)\n", ret);
+		dev_err(component->dev, "Unsupported format (%d)\n", ret);
 		return ret;
 	}
 
@@ -1186,8 +1186,8 @@ static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
 		unsigned int ratio)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
 	unsigned int value;
 	int ret = 0;
 
@@ -1202,18 +1202,18 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
 		value = RV_DACSR_DBCM_64;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported bclk ratio (%d)\n", ret);
+		dev_err(component->dev, "Unsupported bclk ratio (%d)\n", ret);
 		return -EINVAL;
 	}
 
-	ret = snd_soc_update_bits(codec, R_DACSR, RM_DACSR_DBCM, value);
+	ret = snd_soc_component_update_bits(component, R_DACSR, RM_DACSR_DBCM, value);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set DAC BCLK ratio (%d)\n", ret);
+		dev_err(component->dev, "Failed to set DAC BCLK ratio (%d)\n", ret);
 		return ret;
 	}
-	ret = snd_soc_update_bits(codec, R_ADCSR, RM_ADCSR_ABCM, value);
+	ret = snd_soc_component_update_bits(component, R_ADCSR, RM_ADCSR_ABCM, value);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set ADC BCLK ratio (%d)\n", ret);
+		dev_err(component->dev, "Failed to set ADC BCLK ratio (%d)\n", ret);
 		return ret;
 	}
 
@@ -1229,40 +1229,40 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
 static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int ret;
 
 	switch (clk_id) {
 	case TSCS42XX_PLL_SRC_XTAL:
 	case TSCS42XX_PLL_SRC_MCLK1:
-		ret = snd_soc_write(codec, R_PLLREFSEL,
+		ret = snd_soc_component_write(component, R_PLLREFSEL,
 				RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 |
 				RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set pll reference input (%d)\n",
 				ret);
 			return ret;
 		}
 		break;
 	case TSCS42XX_PLL_SRC_MCLK2:
-		ret = snd_soc_write(codec, R_PLLREFSEL,
+		ret = snd_soc_component_write(component, R_PLLREFSEL,
 				RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 |
 				RV_PLLREFSEL_PLL2_REF_SEL_MCLK2);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to set PLL reference (%d)\n", ret);
 			return ret;
 		}
 		break;
 	default:
-		dev_err(codec->dev, "pll src is unsupported\n");
+		dev_err(component->dev, "pll src is unsupported\n");
 		return -EINVAL;
 	}
 
-	ret = set_pll_ctl_from_input_freq(codec, freq);
+	ret = set_pll_ctl_from_input_freq(component, freq);
 	if (ret < 0) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Failed to setup PLL input freq (%d)\n", ret);
 		return ret;
 	}
@@ -1304,24 +1304,28 @@ static int part_is_valid(struct tscs42xx *tscs42xx)
 	};
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_tscs42xx = {
-	.component_driver = {
-		.dapm_widgets = tscs42xx_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(tscs42xx_dapm_widgets),
-		.dapm_routes = tscs42xx_intercon,
-		.num_dapm_routes = ARRAY_SIZE(tscs42xx_intercon),
-		.controls =	tscs42xx_snd_controls,
-		.num_controls = ARRAY_SIZE(tscs42xx_snd_controls),
-	},
+static struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
+	.dapm_widgets		= tscs42xx_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tscs42xx_dapm_widgets),
+	.dapm_routes		= tscs42xx_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(tscs42xx_intercon),
+	.controls		= tscs42xx_snd_controls,
+	.num_controls		= ARRAY_SIZE(tscs42xx_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx)
 {
-	const u8 norm_addrs[] = { 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1f,
-		0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45, 0x4a,
-		0x4f, 0x54, 0x59, 0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79,
-		0x7f, 0x80, 0x85, 0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3, 0xa8,
-		0xad, 0xaf, 0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, };
+	static const u8 norm_addrs[] = {
+		0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1f, 0x20, 0x25, 0x2a,
+		0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59,
+		0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7f, 0x80, 0x85,
+		0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3, 0xa8, 0xad, 0xaf, 0xb0,
+		0xb5, 0xba, 0xbf, 0xc4, 0xc9,
+	};
 	u8 *coeff_ram = tscs42xx->coeff_ram;
 	int i;
 
@@ -1407,7 +1411,7 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
 	mutex_init(&tscs42xx->coeff_ram_lock);
 	mutex_init(&tscs42xx->pll_lock);
 
-	ret = snd_soc_register_codec(tscs42xx->dev, &soc_codec_dev_tscs42xx,
+	ret = devm_snd_soc_register_component(tscs42xx->dev, &soc_codec_dev_tscs42xx,
 			&tscs42xx_dai, 1);
 	if (ret) {
 		dev_err(tscs42xx->dev, "Failed to register codec (%d)\n", ret);
@@ -1417,13 +1421,6 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c,
 	return 0;
 }
 
-static int tscs42xx_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id tscs42xx_i2c_id[] = {
 	{ "tscs42A1", 0 },
 	{ "tscs42A2", 0 },
@@ -1445,7 +1442,6 @@ static struct i2c_driver tscs42xx_i2c_driver = {
 		.of_match_table = tscs42xx_of_match,
 	},
 	.probe =    tscs42xx_i2c_probe,
-	.remove =   tscs42xx_i2c_remove,
 	.id_table = tscs42xx_i2c_id,
 };
 
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index e4d7f397d361..25b752caf95e 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -86,9 +86,9 @@ static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030)
 	}
 }
 
-static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg)
+static unsigned int twl4030_read(struct snd_soc_component *component, unsigned int reg)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 value = 0;
 
 	if (reg >= TWL4030_CACHEREGNUM)
@@ -151,10 +151,10 @@ static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030,
 	return write_to_reg;
 }
 
-static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg,
+static int twl4030_write(struct snd_soc_component *component, unsigned int reg,
 			 unsigned int value)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	/* Update the ctl cache */
 	switch (reg) {
@@ -186,9 +186,9 @@ static inline void twl4030_wait_ms(int time)
 	}
 }
 
-static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
+static void twl4030_codec_enable(struct snd_soc_component *component, int enable)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	int mode;
 
 	if (enable == twl4030->codec_powered)
@@ -227,16 +227,16 @@ static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
 		pdata->hs_extmute = 1;
 }
 
-static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
+static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component)
 {
-	struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
+	struct twl4030_codec_data *pdata = dev_get_platdata(component->dev);
 	struct device_node *twl4030_codec_node = NULL;
 
-	twl4030_codec_node = of_get_child_by_name(codec->dev->parent->of_node,
+	twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node,
 						  "codec");
 
 	if (!pdata && twl4030_codec_node) {
-		pdata = devm_kzalloc(codec->dev,
+		pdata = devm_kzalloc(component->dev,
 				     sizeof(struct twl4030_codec_data),
 				     GFP_KERNEL);
 		if (!pdata) {
@@ -250,28 +250,28 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
 	return pdata;
 }
 
-static void twl4030_init_chip(struct snd_soc_codec *codec)
+static void twl4030_init_chip(struct snd_soc_component *component)
 {
 	struct twl4030_codec_data *pdata;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 reg, byte;
 	int i = 0;
 
-	pdata = twl4030_get_pdata(codec);
+	pdata = twl4030_get_pdata(component);
 
 	if (pdata && pdata->hs_extmute) {
 		if (gpio_is_valid(pdata->hs_extmute_gpio)) {
 			int ret;
 
 			if (!pdata->hs_extmute_gpio)
-				dev_warn(codec->dev,
+				dev_warn(component->dev,
 					"Extmute GPIO is 0 is this correct?\n");
 
 			ret = gpio_request_one(pdata->hs_extmute_gpio,
 					       GPIOF_OUT_INIT_LOW,
 					       "hs_extmute");
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to get hs_extmute GPIO\n");
 				pdata->hs_extmute_gpio = -1;
 			}
@@ -292,16 +292,16 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
 	tw4030_init_ctl_cache(twl4030);
 
 	/* anti-pop when changing analog gain */
-	reg = twl4030_read(codec, TWL4030_REG_MISC_SET_1);
-	twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+	reg = twl4030_read(component, TWL4030_REG_MISC_SET_1);
+	twl4030_write(component, TWL4030_REG_MISC_SET_1,
 		      reg | TWL4030_SMOOTH_ANAVOL_EN);
 
-	twl4030_write(codec, TWL4030_REG_OPTION,
+	twl4030_write(component, TWL4030_REG_OPTION,
 		      TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
 		      TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
 
 	/* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
-	twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
+	twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
 
 	/* Machine dependent setup */
 	if (!pdata)
@@ -309,18 +309,18 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
 
 	twl4030->pdata = pdata;
 
-	reg = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
+	reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
 	reg &= ~TWL4030_RAMP_DELAY;
 	reg |= (pdata->ramp_delay_value << 2);
-	twl4030_write(codec, TWL4030_REG_HS_POPN_SET, reg);
+	twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg);
 
 	/* initiate offset cancellation */
-	twl4030_codec_enable(codec, 1);
+	twl4030_codec_enable(component, 1);
 
-	reg = twl4030_read(codec, TWL4030_REG_ANAMICL);
+	reg = twl4030_read(component, TWL4030_REG_ANAMICL);
 	reg &= ~TWL4030_OFFSET_CNCL_SEL;
 	reg |= pdata->offset_cncl_path;
-	twl4030_write(codec, TWL4030_REG_ANAMICL,
+	twl4030_write(component, TWL4030_REG_ANAMICL,
 		      reg | TWL4030_CNCL_OFFSET_START);
 
 	/*
@@ -339,12 +339,12 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
 		 ((byte & TWL4030_CNCL_OFFSET_START) ==
 		  TWL4030_CNCL_OFFSET_START));
 
-	twl4030_codec_enable(codec, 0);
+	twl4030_codec_enable(component, 0);
 }
 
-static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
+static void twl4030_apll_enable(struct snd_soc_component *component, int enable)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	if (enable) {
 		twl4030->apll_enabled++;
@@ -567,13 +567,13 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
 static int pin_name##pga_event(struct snd_soc_dapm_widget *w,		\
 			       struct snd_kcontrol *kcontrol, int event) \
 {									\
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);	\
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); \
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);	\
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); \
 									\
 	switch (event) {						\
 	case SND_SOC_DAPM_POST_PMU:					\
 		twl4030->pin_name##_enabled = 1;			\
-		twl4030_write(codec, reg, twl4030_read(codec, reg));	\
+		twl4030_write(component, reg, twl4030_read(component, reg));	\
 		break;							\
 	case SND_SOC_DAPM_POST_PMD:					\
 		twl4030->pin_name##_enabled = 0;			\
@@ -589,47 +589,47 @@ TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN);
 TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN);
 TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN);
 
-static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
+static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp)
 {
 	unsigned char hs_ctl;
 
-	hs_ctl = twl4030_read(codec, reg);
+	hs_ctl = twl4030_read(component, reg);
 
 	if (ramp) {
 		/* HF ramp-up */
 		hs_ctl |= TWL4030_HF_CTL_REF_EN;
-		twl4030_write(codec, reg, hs_ctl);
+		twl4030_write(component, reg, hs_ctl);
 		udelay(10);
 		hs_ctl |= TWL4030_HF_CTL_RAMP_EN;
-		twl4030_write(codec, reg, hs_ctl);
+		twl4030_write(component, reg, hs_ctl);
 		udelay(40);
 		hs_ctl |= TWL4030_HF_CTL_LOOP_EN;
 		hs_ctl |= TWL4030_HF_CTL_HB_EN;
-		twl4030_write(codec, reg, hs_ctl);
+		twl4030_write(component, reg, hs_ctl);
 	} else {
 		/* HF ramp-down */
 		hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN;
 		hs_ctl &= ~TWL4030_HF_CTL_HB_EN;
-		twl4030_write(codec, reg, hs_ctl);
+		twl4030_write(component, reg, hs_ctl);
 		hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN;
-		twl4030_write(codec, reg, hs_ctl);
+		twl4030_write(component, reg, hs_ctl);
 		udelay(40);
 		hs_ctl &= ~TWL4030_HF_CTL_REF_EN;
-		twl4030_write(codec, reg, hs_ctl);
+		twl4030_write(component, reg, hs_ctl);
 	}
 }
 
 static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
 			       struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 1);
+		handsfree_ramp(component, TWL4030_REG_HFL_CTL, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 0);
+		handsfree_ramp(component, TWL4030_REG_HFL_CTL, 0);
 		break;
 	}
 	return 0;
@@ -638,14 +638,14 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
 static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 			       struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 1);
+		handsfree_ramp(component, TWL4030_REG_HFR_CTL, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 0);
+		handsfree_ramp(component, TWL4030_REG_HFR_CTL, 0);
 		break;
 	}
 	return 0;
@@ -654,23 +654,23 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 static int vibramux_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
-	twl4030_write(codec, TWL4030_REG_VIBRA_SET, 0xff);
+	twl4030_write(component, TWL4030_REG_VIBRA_SET, 0xff);
 	return 0;
 }
 
 static int apll_event(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		twl4030_apll_enable(codec, 1);
+		twl4030_apll_enable(component, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		twl4030_apll_enable(codec, 0);
+		twl4030_apll_enable(component, 0);
 		break;
 	}
 	return 0;
@@ -679,41 +679,41 @@ static int apll_event(struct snd_soc_dapm_widget *w,
 static int aif_event(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	u8 audio_if;
 
-	audio_if = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
+	audio_if = twl4030_read(component, TWL4030_REG_AUDIO_IF);
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Enable AIF */
 		/* enable the PLL before we use it to clock the DAI */
-		twl4030_apll_enable(codec, 1);
+		twl4030_apll_enable(component, 1);
 
-		twl4030_write(codec, TWL4030_REG_AUDIO_IF,
+		twl4030_write(component, TWL4030_REG_AUDIO_IF,
 			      audio_if | TWL4030_AIF_EN);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* disable the DAI before we stop it's source PLL */
-		twl4030_write(codec, TWL4030_REG_AUDIO_IF,
+		twl4030_write(component, TWL4030_REG_AUDIO_IF,
 			      audio_if &  ~TWL4030_AIF_EN);
-		twl4030_apll_enable(codec, 0);
+		twl4030_apll_enable(component, 0);
 		break;
 	}
 	return 0;
 }
 
-static void headset_ramp(struct snd_soc_codec *codec, int ramp)
+static void headset_ramp(struct snd_soc_component *component, int ramp)
 {
 	unsigned char hs_gain, hs_pop;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	struct twl4030_codec_data *pdata = twl4030->pdata;
 	/* Base values for ramp delay calculation: 2^19 - 2^26 */
 	unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
 				    8388608, 16777216, 33554432, 67108864};
 	unsigned int delay;
 
-	hs_gain = twl4030_read(codec, TWL4030_REG_HS_GAIN_SET);
-	hs_pop = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
+	hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
+	hs_pop = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
 	delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
 		twl4030->sysclk) + 1;
 
@@ -724,26 +724,26 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 			gpio_set_value(pdata->hs_extmute_gpio, 1);
 		} else {
 			hs_pop |= TWL4030_EXTMUTE;
-			twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+			twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
 		}
 	}
 
 	if (ramp) {
 		/* Headset ramp-up according to the TRM */
 		hs_pop |= TWL4030_VMID_EN;
-		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
 		/* Actually write to the register */
 		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain,
 				 TWL4030_REG_HS_GAIN_SET);
 		hs_pop |= TWL4030_RAMP_EN;
-		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
 		/* Wait ramp delay time + 1, so the VMID can settle */
 		twl4030_wait_ms(delay);
 	} else {
 		/* Headset ramp-down _not_ according to
 		 * the TRM, but in a way that it is working */
 		hs_pop &= ~TWL4030_RAMP_EN;
-		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
 		/* Wait ramp delay time + 1, so the VMID can settle */
 		twl4030_wait_ms(delay);
 		/* Bypass the reg_cache to mute the headset */
@@ -751,7 +751,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 				 TWL4030_REG_HS_GAIN_SET);
 
 		hs_pop &= ~TWL4030_VMID_EN;
-		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
 	}
 
 	/* Disable external mute */
@@ -760,7 +760,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 			gpio_set_value(pdata->hs_extmute_gpio, 0);
 		} else {
 			hs_pop &= ~TWL4030_EXTMUTE;
-			twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+			twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
 		}
 	}
 }
@@ -768,21 +768,21 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* Do the ramp-up only once */
 		if (!twl4030->hsr_enabled)
-			headset_ramp(codec, 1);
+			headset_ramp(component, 1);
 
 		twl4030->hsl_enabled = 1;
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Do the ramp-down only if both headsetL/R is disabled */
 		if (!twl4030->hsr_enabled)
-			headset_ramp(codec, 0);
+			headset_ramp(component, 0);
 
 		twl4030->hsl_enabled = 0;
 		break;
@@ -793,21 +793,21 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* Do the ramp-up only once */
 		if (!twl4030->hsl_enabled)
-			headset_ramp(codec, 1);
+			headset_ramp(component, 1);
 
 		twl4030->hsr_enabled = 1;
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* Do the ramp-down only if both headsetL/R is disabled */
 		if (!twl4030->hsl_enabled)
-			headset_ramp(codec, 0);
+			headset_ramp(component, 0);
 
 		twl4030->hsr_enabled = 0;
 		break;
@@ -818,8 +818,8 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 static int digimic_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	struct twl4030_codec_data *pdata = twl4030->pdata;
 
 	if (pdata && pdata->digimic_delay)
@@ -842,7 +842,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int shift = mc->shift;
 	unsigned int rshift = mc->rshift;
@@ -850,14 +850,14 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
 	int mask = (1 << fls(max)) - 1;
 
 	ucontrol->value.integer.value[0] =
-		(twl4030_read(codec, reg) >> shift) & mask;
+		(twl4030_read(component, reg) >> shift) & mask;
 	if (ucontrol->value.integer.value[0])
 		ucontrol->value.integer.value[0] =
 			max + 1 - ucontrol->value.integer.value[0];
 
 	if (shift != rshift) {
 		ucontrol->value.integer.value[1] =
-			(twl4030_read(codec, reg) >> rshift) & mask;
+			(twl4030_read(component, reg) >> rshift) & mask;
 		if (ucontrol->value.integer.value[1])
 			ucontrol->value.integer.value[1] =
 				max + 1 - ucontrol->value.integer.value[1];
@@ -871,7 +871,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int shift = mc->shift;
 	unsigned int rshift = mc->rshift;
@@ -892,7 +892,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
 			val2 = max + 1 - val2;
 		val |= val2 << rshift;
 	}
-	return snd_soc_update_bits(codec, reg, val_mask, val);
+	return snd_soc_component_update_bits(component, reg, val_mask, val);
 }
 
 static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
@@ -900,7 +900,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	unsigned int shift = mc->shift;
@@ -908,9 +908,9 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 	int mask = (1<<fls(max))-1;
 
 	ucontrol->value.integer.value[0] =
-		(twl4030_read(codec, reg) >> shift) & mask;
+		(twl4030_read(component, reg) >> shift) & mask;
 	ucontrol->value.integer.value[1] =
-		(twl4030_read(codec, reg2) >> shift) & mask;
+		(twl4030_read(component, reg2) >> shift) & mask;
 
 	if (ucontrol->value.integer.value[0])
 		ucontrol->value.integer.value[0] =
@@ -927,7 +927,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	unsigned int shift = mc->shift;
@@ -948,11 +948,11 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
 	val = val << shift;
 	val2 = val2 << shift;
 
-	err = snd_soc_update_bits(codec, reg, val_mask, val);
+	err = snd_soc_component_update_bits(component, reg, val_mask, val);
 	if (err < 0)
 		return err;
 
-	err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+	err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
 	return err;
 }
 
@@ -968,11 +968,11 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
 static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	if (twl4030->configured) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"operation mode cannot be changed on-the-fly\n");
 		return -EBUSY;
 	}
@@ -1579,7 +1579,7 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 };
 
-static int twl4030_set_bias_level(struct snd_soc_codec *codec,
+static int twl4030_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -1588,11 +1588,11 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
-			twl4030_codec_enable(codec, 1);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			twl4030_codec_enable(component, 1);
 		break;
 	case SND_SOC_BIAS_OFF:
-		twl4030_codec_enable(codec, 0);
+		twl4030_codec_enable(component, 0);
 		break;
 	}
 
@@ -1628,12 +1628,12 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,
 
 /* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
  * capture has to be enabled/disabled. */
-static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
+static void twl4030_tdm_enable(struct snd_soc_component *component, int direction,
 			       int enable)
 {
 	u8 reg, mask;
 
-	reg = twl4030_read(codec, TWL4030_REG_OPTION);
+	reg = twl4030_read(component, TWL4030_REG_OPTION);
 
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
 		mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
@@ -1645,14 +1645,14 @@ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
 	else
 		reg &= ~mask;
 
-	twl4030_write(codec, TWL4030_REG_OPTION, reg);
+	twl4030_write(component, TWL4030_REG_OPTION, reg);
 }
 
 static int twl4030_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	if (twl4030->master_substream) {
 		twl4030->slave_substream = substream;
@@ -1662,7 +1662,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
 		if (twl4030->configured)
 			twl4030_constraints(twl4030, twl4030->master_substream);
 	} else {
-		if (!(twl4030_read(codec, TWL4030_REG_CODEC_MODE) &
+		if (!(twl4030_read(component, TWL4030_REG_CODEC_MODE) &
 			TWL4030_OPTION_1)) {
 			/* In option2 4 channel is not supported, set the
 			 * constraint for the first stream for channels, the
@@ -1680,8 +1680,8 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
 static void twl4030_shutdown(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	if (twl4030->master_substream == substream)
 		twl4030->master_substream = twl4030->slave_substream;
@@ -1697,27 +1697,27 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
 
 	 /* If the closing substream had 4 channel, do the necessary cleanup */
 	if (substream->runtime->channels == 4)
-		twl4030_tdm_enable(codec, substream->stream, 0);
+		twl4030_tdm_enable(component, substream->stream, 0);
 }
 
 static int twl4030_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 mode, old_mode, format, old_format;
 
 	 /* If the substream has 4 channel, do the necessary setup */
 	if (params_channels(params) == 4) {
-		format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
-		mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE);
+		format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+		mode = twl4030_read(component, TWL4030_REG_CODEC_MODE);
 
 		/* Safety check: are we in the correct operating mode and
 		 * the interface is in TDM mode? */
 		if ((mode & TWL4030_OPTION_1) &&
 		    ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
-			twl4030_tdm_enable(codec, substream->stream, 1);
+			twl4030_tdm_enable(component, substream->stream, 1);
 		else
 			return -EINVAL;
 	}
@@ -1727,7 +1727,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 		return 0;
 
 	/* bit rate */
-	old_mode = twl4030_read(codec,
+	old_mode = twl4030_read(component,
 				TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
 	mode = old_mode & ~TWL4030_APLL_RATE;
 
@@ -1763,13 +1763,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 		mode |= TWL4030_APLL_RATE_96000;
 		break;
 	default:
-		dev_err(codec->dev, "%s: unknown rate %d\n", __func__,
+		dev_err(component->dev, "%s: unknown rate %d\n", __func__,
 			params_rate(params));
 		return -EINVAL;
 	}
 
 	/* sample size */
-	old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
+	old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
 	format = old_format;
 	format &= ~TWL4030_DATA_WIDTH;
 	switch (params_width(params)) {
@@ -1780,7 +1780,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 		format |= TWL4030_DATA_WIDTH_32S_24W;
 		break;
 	default:
-		dev_err(codec->dev, "%s: unsupported bits/sample %d\n",
+		dev_err(component->dev, "%s: unsupported bits/sample %d\n",
 			__func__, params_width(params));
 		return -EINVAL;
 	}
@@ -1791,13 +1791,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 			 * If the codec is powered, than we need to toggle the
 			 * codec power.
 			 */
-			twl4030_codec_enable(codec, 0);
-			twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
-			twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
-			twl4030_codec_enable(codec, 1);
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
+			twl4030_codec_enable(component, 1);
 		} else {
-			twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
-			twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
 		}
 	}
 
@@ -1821,8 +1821,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
 static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 				  unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 19200000:
@@ -1830,12 +1830,12 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 	case 38400000:
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported HFCLKIN: %u\n", freq);
+		dev_err(component->dev, "Unsupported HFCLKIN: %u\n", freq);
 		return -EINVAL;
 	}
 
 	if ((freq / 1000) != twl4030->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Mismatch in HFCLKIN: %u (configured: %u)\n",
 			freq, twl4030->sysclk * 1000);
 		return -EINVAL;
@@ -1846,12 +1846,12 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 
 static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 old_format, format;
 
 	/* get format */
-	old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
+	old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
 	format = old_format;
 
 	/* set master/slave audio interface */
@@ -1887,11 +1887,11 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 			 * If the codec is powered, than we need to toggle the
 			 * codec power.
 			 */
-			twl4030_codec_enable(codec, 0);
-			twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
-			twl4030_codec_enable(codec, 1);
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
+			twl4030_codec_enable(component, 1);
 		} else {
-			twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
 		}
 	}
 
@@ -1900,25 +1900,25 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
 static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u8 reg = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
+	struct snd_soc_component *component = dai->component;
+	u8 reg = twl4030_read(component, TWL4030_REG_AUDIO_IF);
 
 	if (tristate)
 		reg |= TWL4030_AIF_TRI_EN;
 	else
 		reg &= ~TWL4030_AIF_TRI_EN;
 
-	return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg);
+	return twl4030_write(component, TWL4030_REG_AUDIO_IF, reg);
 }
 
 /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
  * (VTXL, VTXR) for uplink has to be enabled/disabled. */
-static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
+static void twl4030_voice_enable(struct snd_soc_component *component, int direction,
 				 int enable)
 {
 	u8 reg, mask;
 
-	reg = twl4030_read(codec, TWL4030_REG_OPTION);
+	reg = twl4030_read(component, TWL4030_REG_OPTION);
 
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
 		mask = TWL4030_ARXL1_VRX_EN;
@@ -1930,21 +1930,21 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
 	else
 		reg &= ~mask;
 
-	twl4030_write(codec, TWL4030_REG_OPTION, reg);
+	twl4030_write(component, TWL4030_REG_OPTION, reg);
 }
 
 static int twl4030_voice_startup(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 mode;
 
 	/* If the system master clock is not 26MHz, the voice PCM interface is
 	 * not available.
 	 */
 	if (twl4030->sysclk != 26000) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
 			__func__, twl4030->sysclk);
 		return -EINVAL;
@@ -1953,11 +1953,11 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
 	/* If the codec mode is not option2, the voice PCM interface is not
 	 * available.
 	 */
-	mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE)
+	mode = twl4030_read(component, TWL4030_REG_CODEC_MODE)
 		& TWL4030_OPT_MODE;
 
 	if (mode != TWL4030_OPTION_2) {
-		dev_err(codec->dev, "%s: the codec mode is not option2\n",
+		dev_err(component->dev, "%s: the codec mode is not option2\n",
 			__func__);
 		return -EINVAL;
 	}
@@ -1968,25 +1968,25 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
 static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	/* Enable voice digital filters */
-	twl4030_voice_enable(codec, substream->stream, 0);
+	twl4030_voice_enable(component, substream->stream, 0);
 }
 
 static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_pcm_hw_params *params,
 				   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 old_mode, mode;
 
 	/* Enable voice digital filters */
-	twl4030_voice_enable(codec, substream->stream, 1);
+	twl4030_voice_enable(component, substream->stream, 1);
 
 	/* bit rate */
-	old_mode = twl4030_read(codec,
+	old_mode = twl4030_read(component,
 				TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
 	mode = old_mode;
 
@@ -1998,7 +1998,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
 		mode |= TWL4030_SEL_16K;
 		break;
 	default:
-		dev_err(codec->dev, "%s: unknown rate %d\n", __func__,
+		dev_err(component->dev, "%s: unknown rate %d\n", __func__,
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -2009,11 +2009,11 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
 			 * If the codec is powered, than we need to toggle the
 			 * codec power.
 			 */
-			twl4030_codec_enable(codec, 0);
-			twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
-			twl4030_codec_enable(codec, 1);
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_codec_enable(component, 1);
 		} else {
-			twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
 		}
 	}
 
@@ -2023,17 +2023,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
 static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 					int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 
 	if (freq != 26000000) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
 			__func__, freq / 1000);
 		return -EINVAL;
 	}
 	if ((freq / 1000) != twl4030->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Mismatch in HFCLKIN: %u (configured: %u)\n",
 			freq, twl4030->sysclk * 1000);
 		return -EINVAL;
@@ -2044,12 +2044,12 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
 				     unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	u8 old_format, format;
 
 	/* get format */
-	old_format = twl4030_read(codec, TWL4030_REG_VOICE_IF);
+	old_format = twl4030_read(component, TWL4030_REG_VOICE_IF);
 	format = old_format;
 
 	/* set master/slave audio interface */
@@ -2082,11 +2082,11 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			 * If the codec is powered, than we need to toggle the
 			 * codec power.
 			 */
-			twl4030_codec_enable(codec, 0);
-			twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
-			twl4030_codec_enable(codec, 1);
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_VOICE_IF, format);
+			twl4030_codec_enable(component, 1);
 		} else {
-			twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+			twl4030_write(component, TWL4030_REG_VOICE_IF, format);
 		}
 	}
 
@@ -2095,15 +2095,15 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u8 reg = twl4030_read(codec, TWL4030_REG_VOICE_IF);
+	struct snd_soc_component *component = dai->component;
+	u8 reg = twl4030_read(component, TWL4030_REG_VOICE_IF);
 
 	if (tristate)
 		reg |= TWL4030_VIF_TRI_EN;
 	else
 		reg &= ~TWL4030_VIF_TRI_EN;
 
-	return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg);
+	return twl4030_write(component, TWL4030_REG_VOICE_IF, reg);
 }
 
 #define TWL4030_RATES	 (SNDRV_PCM_RATE_8000_48000)
@@ -2164,69 +2164,60 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
 },
 };
 
-static int twl4030_soc_probe(struct snd_soc_codec *codec)
+static int twl4030_soc_probe(struct snd_soc_component *component)
 {
 	struct twl4030_priv *twl4030;
 
-	twl4030 = devm_kzalloc(codec->dev, sizeof(struct twl4030_priv),
+	twl4030 = devm_kzalloc(component->dev, sizeof(struct twl4030_priv),
 			       GFP_KERNEL);
 	if (!twl4030)
 		return -ENOMEM;
-	snd_soc_codec_set_drvdata(codec, twl4030);
+	snd_soc_component_set_drvdata(component, twl4030);
 	/* Set the defaults, and power up the codec */
 	twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
 
-	twl4030_init_chip(codec);
+	twl4030_init_chip(component);
 
 	return 0;
 }
 
-static int twl4030_soc_remove(struct snd_soc_codec *codec)
+static void twl4030_soc_remove(struct snd_soc_component *component)
 {
-	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
 	struct twl4030_codec_data *pdata = twl4030->pdata;
 
 	if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
 		gpio_free(pdata->hs_extmute_gpio);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
-	.probe = twl4030_soc_probe,
-	.remove = twl4030_soc_remove,
-	.read = twl4030_read,
-	.write = twl4030_write,
-	.set_bias_level = twl4030_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= twl4030_snd_controls,
-		.num_controls		= ARRAY_SIZE(twl4030_snd_controls),
-		.dapm_widgets		= twl4030_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(twl4030_dapm_widgets),
-		.dapm_routes		= intercon,
-		.num_dapm_routes	= ARRAY_SIZE(intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
+	.probe			= twl4030_soc_probe,
+	.remove			= twl4030_soc_remove,
+	.read			= twl4030_read,
+	.write			= twl4030_write,
+	.set_bias_level		= twl4030_set_bias_level,
+	.controls		= twl4030_snd_controls,
+	.num_controls		= ARRAY_SIZE(twl4030_snd_controls),
+	.dapm_widgets		= twl4030_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(twl4030_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int twl4030_codec_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_twl4030,
 				      twl4030_dai, ARRAY_SIZE(twl4030_dai));
 }
 
-static int twl4030_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 MODULE_ALIAS("platform:twl4030-codec");
 
 static struct platform_driver twl4030_codec_driver = {
 	.probe		= twl4030_codec_probe,
-	.remove		= twl4030_codec_remove,
 	.driver		= {
 		.name	= "twl4030-codec",
 	},
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 573a523ed0b3..9bf23f8e7162 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -76,7 +76,7 @@ struct twl6040_data {
 	unsigned int clk_in;
 	unsigned int sysclk;
 	struct twl6040_jack_data hs_jack;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct mutex mutex;
 };
 
@@ -106,12 +106,12 @@ static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
 	{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
 };
 
-#define to_twl6040(codec)	dev_get_drvdata((codec)->dev->parent)
+#define to_twl6040(component)	dev_get_drvdata((component)->dev->parent)
 
-static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
+static unsigned int twl6040_read(struct snd_soc_component *component, unsigned int reg)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct twl6040 *twl6040 = to_twl6040(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	struct twl6040 *twl6040 = to_twl6040(component);
 	u8 value;
 
 	if (reg >= TWL6040_CACHEREGNUM)
@@ -133,10 +133,10 @@ static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
 	return value;
 }
 
-static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
+static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
 				  unsigned int reg)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	switch (reg) {
 	case TWL6040_REG_HSLCTL:
@@ -152,10 +152,10 @@ static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
 	}
 }
 
-static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
+static inline void twl6040_update_dl12_cache(struct snd_soc_component *component,
 					     u8 reg, u8 value)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	switch (reg) {
 	case TWL6040_REG_HSLCTL:
@@ -170,54 +170,54 @@ static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
 	}
 }
 
-static int twl6040_write(struct snd_soc_codec *codec,
+static int twl6040_write(struct snd_soc_component *component,
 			unsigned int reg, unsigned int value)
 {
-	struct twl6040 *twl6040 = to_twl6040(codec);
+	struct twl6040 *twl6040 = to_twl6040(component);
 
 	if (reg >= TWL6040_CACHEREGNUM)
 		return -EIO;
 
-	twl6040_update_dl12_cache(codec, reg, value);
-	if (twl6040_can_write_to_chip(codec, reg))
+	twl6040_update_dl12_cache(component, reg, value);
+	if (twl6040_can_write_to_chip(component, reg))
 		return twl6040_reg_write(twl6040, reg, value);
 	else
 		return 0;
 }
 
-static void twl6040_init_chip(struct snd_soc_codec *codec)
+static void twl6040_init_chip(struct snd_soc_component *component)
 {
-	twl6040_read(codec, TWL6040_REG_TRIM1);
-	twl6040_read(codec, TWL6040_REG_TRIM2);
-	twl6040_read(codec, TWL6040_REG_TRIM3);
-	twl6040_read(codec, TWL6040_REG_HSOTRIM);
-	twl6040_read(codec, TWL6040_REG_HFOTRIM);
+	twl6040_read(component, TWL6040_REG_TRIM1);
+	twl6040_read(component, TWL6040_REG_TRIM2);
+	twl6040_read(component, TWL6040_REG_TRIM3);
+	twl6040_read(component, TWL6040_REG_HSOTRIM);
+	twl6040_read(component, TWL6040_REG_HFOTRIM);
 
 	/* Change chip defaults */
 	/* No imput selected for microphone amplifiers */
-	twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18);
-	twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);
+	twl6040_write(component, TWL6040_REG_MICLCTL, 0x18);
+	twl6040_write(component, TWL6040_REG_MICRCTL, 0x18);
 
 	/*
 	 * We need to lower the default gain values, so the ramp code
 	 * can work correctly for the first playback.
 	 * This reduces the pop noise heard at the first playback.
 	 */
-	twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff);
-	twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e);
-	twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d);
-	twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d);
-	twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);
+	twl6040_write(component, TWL6040_REG_HSGAIN, 0xff);
+	twl6040_write(component, TWL6040_REG_EARCTL, 0x1e);
+	twl6040_write(component, TWL6040_REG_HFLGAIN, 0x1d);
+	twl6040_write(component, TWL6040_REG_HFRGAIN, 0x1d);
+	twl6040_write(component, TWL6040_REG_LINEGAIN, 0);
 }
 
 /* set headset dac and driver power mode */
-static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
+static int headset_power_mode(struct snd_soc_component *component, int high_perf)
 {
 	int hslctl, hsrctl;
 	int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
 
-	hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
-	hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
+	hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
+	hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
 
 	if (high_perf) {
 		hslctl &= ~mask;
@@ -227,8 +227,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 		hsrctl |= mask;
 	}
 
-	twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
-	twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
+	twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
+	twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
 
 	return 0;
 }
@@ -236,7 +236,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	u8 hslctl, hsrctl;
 
 	/*
@@ -244,8 +244,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 	 * Both HS DAC need to be turned on (before the HS driver) and off at
 	 * the same time.
 	 */
-	hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
-	hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
+	hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
+	hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		hslctl |= TWL6040_HSDACENA;
 		hsrctl |= TWL6040_HSDACENA;
@@ -253,8 +253,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 		hslctl &= ~TWL6040_HSDACENA;
 		hsrctl &= ~TWL6040_HSDACENA;
 	}
-	twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
-	twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
+	twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
+	twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
 
 	msleep(1);
 	return 0;
@@ -263,17 +263,17 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		/* Earphone doesn't support low power mode */
 		priv->hs_power_mode_locked = 1;
-		ret = headset_power_mode(codec, 1);
+		ret = headset_power_mode(component, 1);
 	} else {
 		priv->hs_power_mode_locked = 0;
-		ret = headset_power_mode(codec, priv->hs_power_mode);
+		ret = headset_power_mode(component, priv->hs_power_mode);
 	}
 
 	msleep(1);
@@ -281,16 +281,16 @@ static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
 	return ret;
 }
 
-static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
+static void twl6040_hs_jack_report(struct snd_soc_component *component,
 				   struct snd_soc_jack *jack, int report)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int status;
 
 	mutex_lock(&priv->mutex);
 
 	/* Sync status */
-	status = twl6040_read(codec, TWL6040_REG_STATUS);
+	status = twl6040_read(component, TWL6040_REG_STATUS);
 	if (status & TWL6040_PLUGCOMP)
 		snd_soc_jack_report(jack, report, report);
 	else
@@ -299,16 +299,16 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
 	mutex_unlock(&priv->mutex);
 }
 
-void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
+void twl6040_hs_jack_detect(struct snd_soc_component *component,
 				struct snd_soc_jack *jack, int report)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	struct twl6040_jack_data *hs_jack = &priv->hs_jack;
 
 	hs_jack->jack = jack;
 	hs_jack->report = report;
 
-	twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+	twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
 }
 EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
 
@@ -316,17 +316,17 @@ static void twl6040_accessory_work(struct work_struct *work)
 {
 	struct twl6040_data *priv = container_of(work,
 					struct twl6040_data, hs_jack.work.work);
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_component *component = priv->component;
 	struct twl6040_jack_data *hs_jack = &priv->hs_jack;
 
-	twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+	twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
 }
 
 /* audio interrupt handler */
 static irqreturn_t twl6040_audio_handler(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = data;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	queue_delayed_work(system_power_efficient_wq,
 			   &priv->hs_jack.work, msecs_to_jiffies(200));
@@ -337,12 +337,12 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val;
 
 	/* Do not allow changes while Input/FF efect is running */
-	val = twl6040_read(codec, e->reg);
+	val = twl6040_read(component, e->reg);
 	if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
 		return -EBUSY;
 
@@ -486,8 +486,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
 static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
 
@@ -497,13 +497,13 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
 static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int high_perf = ucontrol->value.enumerated.item[0];
 	int ret = 0;
 
 	if (!priv->hs_power_mode_locked)
-		ret = headset_power_mode(codec, high_perf);
+		ret = headset_power_mode(component, high_perf);
 
 	if (!ret)
 		priv->hs_power_mode = high_perf;
@@ -514,8 +514,8 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
 static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
 
@@ -525,17 +525,17 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
 static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	priv->pll_power_mode = ucontrol->value.enumerated.item[0];
 
 	return 0;
 }
 
-int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
+int twl6040_get_dl1_gain(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (snd_soc_dapm_get_pin_status(dapm, "EP"))
 		return -1; /* -1dB */
@@ -543,7 +543,7 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
 	if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
 		snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
 
-		u8 val = twl6040_read(codec, TWL6040_REG_HSLCTL);
+		u8 val = twl6040_read(component, TWL6040_REG_HSLCTL);
 		if (val & TWL6040_HSDACMODE)
 			/* HSDACL in LP mode */
 			return -8; /* -8dB */
@@ -555,26 +555,26 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain);
 
-int twl6040_get_clk_id(struct snd_soc_codec *codec)
+int twl6040_get_clk_id(struct snd_soc_component *component)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	return priv->pll_power_mode;
 }
 EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
 
-int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
+int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim)
 {
 	if (unlikely(trim >= TWL6040_TRIM_INVAL))
 		return -EINVAL;
 
-	return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);
+	return twl6040_read(component, TWL6040_REG_TRIM1 + trim);
 }
 EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
 
-int twl6040_get_hs_step_size(struct snd_soc_codec *codec)
+int twl6040_get_hs_step_size(struct snd_soc_component *component)
 {
-	struct twl6040 *twl6040 = to_twl6040(codec);
+	struct twl6040 *twl6040 = to_twl6040(component);
 
 	if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
 		/* For ES under ES_1.3 HS step is 2 mV */
@@ -829,11 +829,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"VIBRAR", NULL, "Vibra Right Driver"},
 };
 
-static int twl6040_set_bias_level(struct snd_soc_codec *codec,
+static int twl6040_set_bias_level(struct snd_soc_component *component,
 				enum snd_soc_bias_level level)
 {
-	struct twl6040 *twl6040 = to_twl6040(codec);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040 *twl6040 = to_twl6040(component);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (level) {
@@ -856,7 +856,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
 		priv->codec_powered = 1;
 
 		/* Set external boost GPO */
-		twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
+		twl6040_write(component, TWL6040_REG_GPOCTL, 0x02);
 		break;
 	case SND_SOC_BIAS_OFF:
 		if (!priv->codec_powered)
@@ -873,8 +873,8 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
 static int twl6040_startup(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	snd_pcm_hw_constraint_list(substream->runtime, 0,
 				SNDRV_PCM_HW_PARAM_RATE,
@@ -887,8 +887,8 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
 			struct snd_pcm_hw_params *params,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int rate;
 
 	rate = params_rate(params);
@@ -899,7 +899,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
 	case 88200:
 		/* These rates are not supported when HPPLL is in use */
 		if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
-			dev_err(codec->dev, "HPPLL does not support rate %d\n",
+			dev_err(component->dev, "HPPLL does not support rate %d\n",
 				rate);
 			return -EINVAL;
 		}
@@ -913,7 +913,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
 		priv->sysclk = 19200000;
 		break;
 	default:
-		dev_err(codec->dev, "unsupported rate %d\n", rate);
+		dev_err(component->dev, "unsupported rate %d\n", rate);
 		return -EINVAL;
 	}
 
@@ -923,20 +923,20 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
 static int twl6040_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct twl6040 *twl6040 = to_twl6040(codec);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct twl6040 *twl6040 = to_twl6040(component);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	if (!priv->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"no mclk configured, call set_sysclk() on init\n");
 		return -EINVAL;
 	}
 
 	ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
 	if (ret) {
-		dev_err(codec->dev, "Can not set PLL (%d)\n", ret);
+		dev_err(component->dev, "Can not set PLL (%d)\n", ret);
 		return -EPERM;
 	}
 
@@ -946,8 +946,8 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
 static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case TWL6040_SYSCLK_SEL_LPPLL:
@@ -956,26 +956,26 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		priv->clk_in = freq;
 		break;
 	default:
-		dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
+		dev_err(component->dev, "unknown clk_id %d\n", clk_id);
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
+static void twl6040_mute_path(struct snd_soc_component *component, enum twl6040_dai_id id,
 			     int mute)
 {
-	struct twl6040 *twl6040 = to_twl6040(codec);
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040 *twl6040 = to_twl6040(component);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 	int hslctl, hsrctl, earctl;
 	int hflctl, hfrctl;
 
 	switch (id) {
 	case TWL6040_DAI_DL1:
-		hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
-		hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
-		earctl = twl6040_read(codec, TWL6040_REG_EARCTL);
+		hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
+		hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
+		earctl = twl6040_read(component, TWL6040_REG_EARCTL);
 
 		if (mute) {
 			/* Power down drivers and DACs */
@@ -991,8 +991,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
 		priv->dl1_unmuted = !mute;
 		break;
 	case TWL6040_DAI_DL2:
-		hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL);
-		hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);
+		hflctl = twl6040_read(component, TWL6040_REG_HFLCTL);
+		hfrctl = twl6040_read(component, TWL6040_REG_HFRCTL);
 
 		if (mute) {
 			/* Power down drivers and DACs */
@@ -1015,12 +1015,12 @@ static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
 {
 	switch (dai->id) {
 	case TWL6040_DAI_LEGACY:
-		twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute);
-		twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute);
+		twl6040_mute_path(dai->component, TWL6040_DAI_DL1, mute);
+		twl6040_mute_path(dai->component, TWL6040_DAI_DL2, mute);
 		break;
 	case TWL6040_DAI_DL1:
 	case TWL6040_DAI_DL2:
-		twl6040_mute_path(dai->codec, dai->id, mute);
+		twl6040_mute_path(dai->component, dai->id, mute);
 		break;
 	default:
 		break;
@@ -1107,23 +1107,23 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 },
 };
 
-static int twl6040_probe(struct snd_soc_codec *codec)
+static int twl6040_probe(struct snd_soc_component *component)
 {
 	struct twl6040_data *priv;
-	struct platform_device *pdev = to_platform_device(codec->dev);
+	struct platform_device *pdev = to_platform_device(component->dev);
 	int ret = 0;
 
-	priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(component->dev, sizeof(*priv), GFP_KERNEL);
 	if (priv == NULL)
 		return -ENOMEM;
 
-	snd_soc_codec_set_drvdata(codec, priv);
+	snd_soc_component_set_drvdata(component, priv);
 
-	priv->codec = codec;
+	priv->component = component;
 
 	priv->plug_irq = platform_get_irq(pdev, 0);
 	if (priv->plug_irq < 0) {
-		dev_err(codec->dev, "invalid irq: %d\n", priv->plug_irq);
+		dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq);
 		return priv->plug_irq;
 	}
 
@@ -1134,64 +1134,55 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 	ret = request_threaded_irq(priv->plug_irq, NULL,
 					twl6040_audio_handler,
 					IRQF_NO_SUSPEND | IRQF_ONESHOT,
-					"twl6040_irq_plug", codec);
+					"twl6040_irq_plug", component);
 	if (ret) {
-		dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
+		dev_err(component->dev, "PLUG IRQ request failed: %d\n", ret);
 		return ret;
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	twl6040_init_chip(codec);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+	twl6040_init_chip(component);
 
 	return 0;
 }
 
-static int twl6040_remove(struct snd_soc_codec *codec)
+static void twl6040_remove(struct snd_soc_component *component)
 {
-	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
 
-	free_irq(priv->plug_irq, codec);
-
-	return 0;
+	free_irq(priv->plug_irq, component);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
-	.probe = twl6040_probe,
-	.remove = twl6040_remove,
-	.read = twl6040_read,
-	.write = twl6040_write,
-	.set_bias_level = twl6040_set_bias_level,
-	.suspend_bias_off = true,
-	.ignore_pmdown_time = true,
-
-	.component_driver = {
-		.controls		= twl6040_snd_controls,
-		.num_controls		= ARRAY_SIZE(twl6040_snd_controls),
-		.dapm_widgets		= twl6040_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(twl6040_dapm_widgets),
-		.dapm_routes		= intercon,
-		.num_dapm_routes	= ARRAY_SIZE(intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
+	.probe			= twl6040_probe,
+	.remove			= twl6040_remove,
+	.read			= twl6040_read,
+	.remove			= twl6040_remove,
+	.set_bias_level		= twl6040_set_bias_level,
+	.controls		= twl6040_snd_controls,
+	.num_controls		= ARRAY_SIZE(twl6040_snd_controls),
+	.dapm_widgets		= twl6040_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(twl6040_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int twl6040_codec_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_twl6040,
 				      twl6040_dai, ARRAY_SIZE(twl6040_dai));
 }
 
-static int twl6040_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static struct platform_driver twl6040_codec_driver = {
 	.driver = {
 		.name = "twl6040-codec",
 	},
 	.probe = twl6040_codec_probe,
-	.remove = twl6040_codec_remove,
 };
 
 module_platform_driver(twl6040_codec_driver);
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index 0611406ca7c0..3d9f957077ef 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -34,11 +34,11 @@ enum twl6040_trim {
 #define TWL6040_HSF_TRIM_LEFT(x)	(x & 0x0f)
 #define TWL6040_HSF_TRIM_RIGHT(x)	((x >> 4) & 0x0f)
 
-int twl6040_get_dl1_gain(struct snd_soc_codec *codec);
-void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
+int twl6040_get_dl1_gain(struct snd_soc_component *component);
+void twl6040_hs_jack_detect(struct snd_soc_component *component,
 			    struct snd_soc_jack *jack, int report);
-int twl6040_get_clk_id(struct snd_soc_codec *codec);
-int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim);
-int twl6040_get_hs_step_size(struct snd_soc_codec *codec);
+int twl6040_get_clk_id(struct snd_soc_component *component);
+int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim);
+int twl6040_get_hs_step_size(struct snd_soc_component *component);
 
 #endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 77c9cc4467b8..3c935a941129 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -110,9 +110,9 @@ static int uda134x_regmap_write(void *context, unsigned int reg,
 	return 0;
 }
 
-static inline void uda134x_reset(struct snd_soc_codec *codec)
+static inline void uda134x_reset(struct snd_soc_component *component)
 {
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 	unsigned int mask = 1<<6;
 
 	regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
@@ -122,7 +122,7 @@ static inline void uda134x_reset(struct snd_soc_codec *codec)
 
 static int uda134x_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec);
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
 	unsigned int mask = 1<<2;
 	unsigned int val;
 
@@ -139,8 +139,8 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute)
 static int uda134x_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *master_runtime;
 
 	if (uda134x->master_substream) {
@@ -168,8 +168,8 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
 static void uda134x_shutdown(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 
 	if (uda134x->master_substream == substream)
 		uda134x->master_substream = uda134x->slave_substream;
@@ -181,8 +181,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 	unsigned int hw_params = 0;
 
 	if (substream == uda134x->slave_substream) {
@@ -248,8 +248,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
 static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 
 	pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
 		 clk_id, freq, dir);
@@ -270,8 +270,8 @@ static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			       unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 
 	pr_debug("%s fmt: %08X\n", __func__, fmt);
 
@@ -294,10 +294,10 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int uda134x_set_bias_level(struct snd_soc_codec *codec,
+static int uda134x_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 	struct uda134x_platform_data *pd = uda134x->pd;
 	pr_debug("%s bias level %d\n", __func__, level);
 
@@ -446,10 +446,10 @@ static struct snd_soc_dai_driver uda134x_dai = {
 	.ops = &uda134x_dai_ops,
 };
 
-static int uda134x_soc_probe(struct snd_soc_codec *codec)
+static int uda134x_soc_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
 	struct uda134x_platform_data *pd = uda134x->pd;
 	const struct snd_soc_dapm_widget *widgets;
 	unsigned num_widgets;
@@ -473,7 +473,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
 	if (pd->power)
 		pd->power(1);
 
-	uda134x_reset(codec);
+	uda134x_reset(component);
 
 	if (pd->model == UDA134X_UDA1341) {
 		widgets = uda1341_dapm_widgets;
@@ -493,15 +493,15 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
 	switch (pd->model) {
 	case UDA134X_UDA1340:
 	case UDA134X_UDA1344:
-		ret = snd_soc_add_codec_controls(codec, uda1340_snd_controls,
+		ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
 					ARRAY_SIZE(uda1340_snd_controls));
 	break;
 	case UDA134X_UDA1341:
-		ret = snd_soc_add_codec_controls(codec, uda1341_snd_controls,
+		ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
 					ARRAY_SIZE(uda1341_snd_controls));
 	break;
 	case UDA134X_UDA1345:
-		ret = snd_soc_add_codec_controls(codec, uda1345_snd_controls,
+		ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
 					ARRAY_SIZE(uda1345_snd_controls));
 	break;
 	default:
@@ -518,17 +518,18 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_uda134x = {
-	.probe =        uda134x_soc_probe,
-	.set_bias_level = uda134x_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.dapm_widgets		= uda134x_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(uda134x_dapm_widgets),
-		.dapm_routes		= uda134x_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(uda134x_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_uda134x = {
+	.probe			= uda134x_soc_probe,
+	.set_bias_level		= uda134x_set_bias_level,
+	.dapm_widgets		= uda134x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(uda134x_dapm_widgets),
+	.dapm_routes		= uda134x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(uda134x_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config uda134x_regmap_config = {
@@ -571,14 +572,8 @@ static int uda134x_codec_probe(struct platform_device *pdev)
 	if (IS_ERR(uda134x->regmap))
 		return PTR_ERR(uda134x->regmap);
 
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_uda134x, &uda134x_dai, 1);
-}
-
-static int uda134x_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_uda134x, &uda134x_dai, 1);
 }
 
 static struct platform_driver uda134x_codec_driver = {
@@ -586,7 +581,6 @@ static struct platform_driver uda134x_codec_driver = {
 		.name = "uda134x-codec",
 	},
 	.probe = uda134x_codec_probe,
-	.remove = uda134x_codec_remove,
 };
 
 module_platform_driver(uda134x_codec_driver);
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index c73e6a192224..584a032b3cb1 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -34,7 +34,7 @@
 
 /* codec private data */
 struct uda1380_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	unsigned int dac_clk;
 	struct work_struct work;
 	struct i2c_client *i2c;
@@ -61,10 +61,10 @@ static unsigned long uda1380_cache_dirty;
 /*
  * read uda1380 register cache
  */
-static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
+static inline unsigned int uda1380_read_reg_cache(struct snd_soc_component *component,
 	unsigned int reg)
 {
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
 	u16 *cache = uda1380->reg_cache;
 
 	if (reg == UDA1380_RESET)
@@ -77,10 +77,10 @@ static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
 /*
  * write uda1380 register cache
  */
-static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
+static inline void uda1380_write_reg_cache(struct snd_soc_component *component,
 	u16 reg, unsigned int value)
 {
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
 	u16 *cache = uda1380->reg_cache;
 
 	if (reg >= UDA1380_CACHEREGNUM)
@@ -93,10 +93,10 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
 /*
  * write to the UDA1380 register space
  */
-static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
+static int uda1380_write(struct snd_soc_component *component, unsigned int reg,
 	unsigned int value)
 {
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
 	u8 data[3];
 
 	/* data is
@@ -108,12 +108,12 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
 	data[1] = (value & 0xff00) >> 8;
 	data[2] = value & 0x00ff;
 
-	uda1380_write_reg_cache(codec, reg, value);
+	uda1380_write_reg_cache(component, reg, value);
 
 	/* the interpolator & decimator regs must only be written when the
 	 * codec DAI is active.
 	 */
-	if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
+	if (!snd_soc_component_is_active(component) && (reg >= UDA1380_MVOL))
 		return 0;
 	pr_debug("uda1380: hw write %x val %x\n", reg, value);
 	if (i2c_master_send(uda1380->i2c, data, 3) == 3) {
@@ -133,9 +133,9 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
 		return -EIO;
 }
 
-static void uda1380_sync_cache(struct snd_soc_codec *codec)
+static void uda1380_sync_cache(struct snd_soc_component *component)
 {
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
 	int reg;
 	u8 data[3];
 	u16 *cache = uda1380->reg_cache;
@@ -146,15 +146,15 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec)
 		data[1] = (cache[reg] & 0xff00) >> 8;
 		data[2] = cache[reg] & 0x00ff;
 		if (i2c_master_send(uda1380->i2c, data, 3) != 3)
-			dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
+			dev_err(component->dev, "%s: write to reg 0x%x failed\n",
 				__func__, reg);
 	}
 }
 
-static int uda1380_reset(struct snd_soc_codec *codec)
+static int uda1380_reset(struct snd_soc_component *component)
 {
-	struct uda1380_platform_data *pdata = codec->dev->platform_data;
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+	struct uda1380_platform_data *pdata = component->dev->platform_data;
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
 
 	if (gpio_is_valid(pdata->gpio_reset)) {
 		gpio_set_value(pdata->gpio_reset, 1);
@@ -168,7 +168,7 @@ static int uda1380_reset(struct snd_soc_codec *codec)
 		data[2] = 0;
 
 		if (i2c_master_send(uda1380->i2c, data, 3) != 3) {
-			dev_err(codec->dev, "%s: failed\n", __func__);
+			dev_err(component->dev, "%s: failed\n", __func__);
 			return -EIO;
 		}
 	}
@@ -179,15 +179,15 @@ static int uda1380_reset(struct snd_soc_codec *codec)
 static void uda1380_flush_work(struct work_struct *work)
 {
 	struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
-	struct snd_soc_codec *uda1380_codec = uda1380->codec;
+	struct snd_soc_component *uda1380_component = uda1380->component;
 	int bit, reg;
 
 	for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
 		reg = 0x10 + bit;
 		pr_debug("uda1380: flush reg %x val %x:\n", reg,
-				uda1380_read_reg_cache(uda1380_codec, reg));
-		uda1380_write(uda1380_codec, reg,
-				uda1380_read_reg_cache(uda1380_codec, reg));
+				uda1380_read_reg_cache(uda1380_component, reg));
+		uda1380_write(uda1380_component, reg,
+				uda1380_read_reg_cache(uda1380_component, reg));
 		clear_bit(bit, &uda1380_cache_dirty);
 	}
 
@@ -420,11 +420,11 @@ static const struct snd_soc_dapm_route uda1380_dapm_routes[] = {
 static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int iface;
 
 	/* set up DAI based upon fmt */
-	iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+	iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
 	iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -442,7 +442,7 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
 		return -EINVAL;
 
-	uda1380_write_reg_cache(codec, UDA1380_IFACE, iface);
+	uda1380_write_reg_cache(component, UDA1380_IFACE, iface);
 
 	return 0;
 }
@@ -450,11 +450,11 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
 static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int iface;
 
 	/* set up DAI based upon fmt */
-	iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+	iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
 	iface &= ~R01_SFORI_MASK;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -472,7 +472,7 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
 		return -EINVAL;
 
-	uda1380_write(codec, UDA1380_IFACE, iface);
+	uda1380_write(component, UDA1380_IFACE, iface);
 
 	return 0;
 }
@@ -480,11 +480,11 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
 static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int iface;
 
 	/* set up DAI based upon fmt */
-	iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+	iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
 	iface &= ~(R01_SIM | R01_SFORO_MASK);
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -501,7 +501,7 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
 		iface |= R01_SIM;
 
-	uda1380_write(codec, UDA1380_IFACE, iface);
+	uda1380_write(component, UDA1380_IFACE, iface);
 
 	return 0;
 }
@@ -509,20 +509,20 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
 static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
-	int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
+	struct snd_soc_component *component = dai->component;
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	int mixer = uda1380_read_reg_cache(component, UDA1380_MIXER);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		uda1380_write_reg_cache(codec, UDA1380_MIXER,
+		uda1380_write_reg_cache(component, UDA1380_MIXER,
 					mixer & ~R14_SILENCE);
 		schedule_work(&uda1380->work);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		uda1380_write_reg_cache(codec, UDA1380_MIXER,
+		uda1380_write_reg_cache(component, UDA1380_MIXER,
 					mixer | R14_SILENCE);
 		schedule_work(&uda1380->work);
 		break;
@@ -534,13 +534,13 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
+	struct snd_soc_component *component = dai->component;
+	u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
 
 	/* set WSPLL power and divider if running from this clock */
 	if (clk & R00_DAC_CLK) {
 		int rate = params_rate(params);
-		u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+		u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
 		clk &= ~0x3; /* clear SEL_LOOP_DIV */
 		switch (rate) {
 		case 6250 ... 12500:
@@ -556,7 +556,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
 			clk |= 0x3;
 			break;
 		}
-		uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm);
+		uda1380_write(component, UDA1380_PM, R02_PON_PLL | pm);
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -564,20 +564,20 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
 	else
 		clk |= R00_EN_ADC | R00_EN_DEC;
 
-	uda1380_write(codec, UDA1380_CLK, clk);
+	uda1380_write(component, UDA1380_CLK, clk);
 	return 0;
 }
 
 static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
+	struct snd_soc_component *component = dai->component;
+	u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
 
 	/* shut down WSPLL power if running from this clock */
 	if (clk & R00_DAC_CLK) {
-		u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
-		uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm);
+		u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
+		uda1380_write(component, UDA1380_PM, ~R02_PON_PLL & pm);
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -585,33 +585,33 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
 	else
 		clk &= ~(R00_EN_ADC | R00_EN_DEC);
 
-	uda1380_write(codec, UDA1380_CLK, clk);
+	uda1380_write(component, UDA1380_CLK, clk);
 }
 
-static int uda1380_set_bias_level(struct snd_soc_codec *codec,
+static int uda1380_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+	int pm = uda1380_read_reg_cache(component, UDA1380_PM);
 	int reg;
-	struct uda1380_platform_data *pdata = codec->dev->platform_data;
+	struct uda1380_platform_data *pdata = component->dev->platform_data;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		/* ADC, DAC on */
-		uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
+		uda1380_write(component, UDA1380_PM, R02_PON_BIAS | pm);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			if (gpio_is_valid(pdata->gpio_power)) {
 				gpio_set_value(pdata->gpio_power, 1);
 				mdelay(1);
-				uda1380_reset(codec);
+				uda1380_reset(component);
 			}
 
-			uda1380_sync_cache(codec);
+			uda1380_sync_cache(component);
 		}
-		uda1380_write(codec, UDA1380_PM, 0x0);
+		uda1380_write(component, UDA1380_PM, 0x0);
 		break;
 	case SND_SOC_BIAS_OFF:
 		if (!gpio_is_valid(pdata->gpio_power))
@@ -694,16 +694,16 @@ static struct snd_soc_dai_driver uda1380_dai[] = {
 },
 };
 
-static int uda1380_probe(struct snd_soc_codec *codec)
+static int uda1380_probe(struct snd_soc_component *component)
 {
-	struct uda1380_platform_data *pdata =codec->dev->platform_data;
-	struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+	struct uda1380_platform_data *pdata =component->dev->platform_data;
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	uda1380->codec = codec;
+	uda1380->component = component;
 
 	if (!gpio_is_valid(pdata->gpio_power)) {
-		ret = uda1380_reset(codec);
+		ret = uda1380_reset(component);
 		if (ret)
 			return ret;
 	}
@@ -713,10 +713,10 @@ static int uda1380_probe(struct snd_soc_codec *codec)
 	/* set clock input */
 	switch (pdata->dac_clk) {
 	case UDA1380_DAC_CLK_SYSCLK:
-		uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
+		uda1380_write_reg_cache(component, UDA1380_CLK, 0);
 		break;
 	case UDA1380_DAC_CLK_WSPLL:
-		uda1380_write_reg_cache(codec, UDA1380_CLK,
+		uda1380_write_reg_cache(component, UDA1380_CLK,
 			R00_DAC_CLK);
 		break;
 	}
@@ -724,21 +724,22 @@ static int uda1380_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
-	.probe =	uda1380_probe,
-	.read =		uda1380_read_reg_cache,
-	.write =	uda1380_write,
-	.set_bias_level = uda1380_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= uda1380_snd_controls,
-		.num_controls		= ARRAY_SIZE(uda1380_snd_controls),
-		.dapm_widgets		= uda1380_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(uda1380_dapm_widgets),
-		.dapm_routes		= uda1380_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(uda1380_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_uda1380 = {
+	.probe			= uda1380_probe,
+	.read			= uda1380_read_reg_cache,
+	.write			= uda1380_write,
+	.set_bias_level		= uda1380_set_bias_level,
+	.controls		= uda1380_snd_controls,
+	.num_controls		= ARRAY_SIZE(uda1380_snd_controls),
+	.dapm_widgets		= uda1380_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(uda1380_dapm_widgets),
+	.dapm_routes		= uda1380_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(uda1380_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int uda1380_i2c_probe(struct i2c_client *i2c,
@@ -780,17 +781,11 @@ static int uda1380_i2c_probe(struct i2c_client *i2c,
 	i2c_set_clientdata(i2c, uda1380);
 	uda1380->i2c = i2c;
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
 	return ret;
 }
 
-static int uda1380_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
-}
-
 static const struct i2c_device_id uda1380_i2c_id[] = {
 	{ "uda1380", 0 },
 	{ }
@@ -809,7 +804,6 @@ static struct i2c_driver uda1380_i2c_driver = {
 		.of_match_table = uda1380_of_match,
 	},
 	.probe =    uda1380_i2c_probe,
-	.remove =   uda1380_i2c_remove,
 	.id_table = uda1380_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 942f1644973e..929ef1fdbb69 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -172,8 +172,8 @@ static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
 static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wl1273->mode;
 
@@ -190,14 +190,14 @@ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
 static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 
 	if (wl1273->mode == ucontrol->value.enumerated.item[0])
 		return 0;
 
 	/* Do not allow changes while stream is running */
-	if (snd_soc_codec_is_active(codec))
+	if (snd_soc_component_is_active(component))
 		return -EPERM;
 
 	if (ucontrol->value.enumerated.item[0] >=  ARRAY_SIZE(wl1273_audio_route))
@@ -213,10 +213,10 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
 static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s: enter.\n", __func__);
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
 
 	ucontrol->value.enumerated.item[0] = wl1273->core->audio_mode;
 
@@ -226,11 +226,11 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
 static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 	int val, r = 0;
 
-	dev_dbg(codec->dev, "%s: enter.\n", __func__);
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
 
 	val = ucontrol->value.enumerated.item[0];
 	if (wl1273->core->audio_mode == val)
@@ -250,10 +250,10 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
 static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s: enter.\n", __func__);
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
 
 	ucontrol->value.integer.value[0] = wl1273->core->volume;
 
@@ -263,11 +263,11 @@ static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
 static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 	int r;
 
-	dev_dbg(codec->dev, "%s: enter.\n", __func__);
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
 
 	r = wl1273->core->set_volume(wl1273->core,
 				     ucontrol->value.integer.value[0]);
@@ -301,8 +301,8 @@ static const struct snd_soc_dapm_route wl1273_dapm_routes[] = {
 static int wl1273_startup(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 
 	switch (wl1273->mode) {
 	case WL1273_MODE_BT:
@@ -335,7 +335,7 @@ static int wl1273_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(dai->codec);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(dai->component);
 	struct wl1273_core *core = wl1273->core;
 	unsigned int rate, width, r;
 
@@ -415,14 +415,14 @@ static struct snd_soc_dai_driver wl1273_dai = {
 };
 
 /* Audio interface format for the soc_card driver */
-int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
+int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt)
 {
 	struct wl1273_priv *wl1273;
 
-	if (codec == NULL || fmt == NULL)
+	if (component == NULL || fmt == NULL)
 		return -EINVAL;
 
-	wl1273 = snd_soc_codec_get_drvdata(codec);
+	wl1273 = snd_soc_component_get_drvdata(component);
 
 	switch (wl1273->mode) {
 	case WL1273_MODE_FM_RX:
@@ -446,15 +446,15 @@ int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
 }
 EXPORT_SYMBOL_GPL(wl1273_get_format);
 
-static int wl1273_probe(struct snd_soc_codec *codec)
+static int wl1273_probe(struct snd_soc_component *component)
 {
-	struct wl1273_core **core = codec->dev->platform_data;
+	struct wl1273_core **core = component->dev->platform_data;
 	struct wl1273_priv *wl1273;
 
-	dev_dbg(codec->dev, "%s.\n", __func__);
+	dev_dbg(component->dev, "%s.\n", __func__);
 
 	if (!core) {
-		dev_err(codec->dev, "Platform data is missing.\n");
+		dev_err(component->dev, "Platform data is missing.\n");
 		return -EINVAL;
 	}
 
@@ -465,44 +465,43 @@ static int wl1273_probe(struct snd_soc_codec *codec)
 	wl1273->mode = WL1273_MODE_BT;
 	wl1273->core = *core;
 
-	snd_soc_codec_set_drvdata(codec, wl1273);
+	snd_soc_component_set_drvdata(component, wl1273);
 
 	return 0;
 }
 
-static int wl1273_remove(struct snd_soc_codec *codec)
+static void wl1273_remove(struct snd_soc_component *component)
 {
-	struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "%s\n", __func__);
+	dev_dbg(component->dev, "%s\n", __func__);
 	kfree(wl1273);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
-	.probe = wl1273_probe,
-	.remove = wl1273_remove,
-
-	.component_driver = {
-		.controls		= wl1273_controls,
-		.num_controls		= ARRAY_SIZE(wl1273_controls),
-		.dapm_widgets		= wl1273_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wl1273_dapm_widgets),
-		.dapm_routes		= wl1273_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wl1273_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wl1273 = {
+	.probe			= wl1273_probe,
+	.remove			= wl1273_remove,
+	.controls		= wl1273_controls,
+	.num_controls		= ARRAY_SIZE(wl1273_controls),
+	.dapm_widgets		= wl1273_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wl1273_dapm_widgets),
+	.dapm_routes		= wl1273_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wl1273_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wl1273_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273,
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_wl1273,
 				      &wl1273_dai, 1);
 }
 
 static int wl1273_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
index 43ec7e668c51..43a81d5cab4d 100644
--- a/sound/soc/codecs/wl1273.h
+++ b/sound/soc/codecs/wl1273.h
@@ -25,6 +25,6 @@
 #ifndef __WL1273_CODEC_H__
 #define __WL1273_CODEC_H__
 
-int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
+int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt);
 
 #endif	/* End of __WL1273_CODEC_H__ */
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 0147d2fb7b0a..abd2defe7530 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -90,7 +90,7 @@ enum wm0010_state {
 };
 
 struct wm0010_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
 	struct mutex lock;
 	struct device *dev;
@@ -157,9 +157,9 @@ static const char *wm0010_state_to_str(enum wm0010_state state)
 }
 
 /* Called with wm0010->lock held */
-static void wm0010_halt(struct snd_soc_codec *codec)
+static void wm0010_halt(struct snd_soc_component *component)
 {
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 	unsigned long flags;
 	enum wm0010_state state;
 
@@ -193,7 +193,7 @@ static void wm0010_halt(struct snd_soc_codec *codec)
 
 struct wm0010_boot_xfer {
 	struct list_head list;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct completion *done;
 	struct spi_message m;
 	struct spi_transfer t;
@@ -218,13 +218,13 @@ static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
 static void wm0010_boot_xfer_complete(void *data)
 {
 	struct wm0010_boot_xfer *xfer = data;
-	struct snd_soc_codec *codec = xfer->codec;
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = xfer->component;
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 	u32 *out32 = xfer->t.rx_buf;
 	int i;
 
 	if (xfer->m.status != 0) {
-		dev_err(codec->dev, "SPI transfer failed: %d\n",
+		dev_err(component->dev, "SPI transfer failed: %d\n",
 			xfer->m.status);
 		wm0010_mark_boot_failure(wm0010);
 		if (xfer->done)
@@ -233,11 +233,11 @@ static void wm0010_boot_xfer_complete(void *data)
 	}
 
 	for (i = 0; i < xfer->t.len / 4; i++) {
-		dev_dbg(codec->dev, "%d: %04x\n", i, out32[i]);
+		dev_dbg(component->dev, "%d: %04x\n", i, out32[i]);
 
 		switch (be32_to_cpu(out32[i])) {
 		case 0xe0e0e0e0:
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"%d: ROM error reported in stage 2\n", i);
 			wm0010_mark_boot_failure(wm0010);
 			break;
@@ -245,82 +245,82 @@ static void wm0010_boot_xfer_complete(void *data)
 		case 0x55555555:
 			if (wm0010->state < WM0010_STAGE2)
 				break;
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"%d: ROM bootloader running in stage 2\n", i);
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0000:
-			dev_dbg(codec->dev, "Stage2 loader running\n");
+			dev_dbg(component->dev, "Stage2 loader running\n");
 			break;
 
 		case 0x0fed0007:
-			dev_dbg(codec->dev, "CODE_HDR packet received\n");
+			dev_dbg(component->dev, "CODE_HDR packet received\n");
 			break;
 
 		case 0x0fed0008:
-			dev_dbg(codec->dev, "CODE_DATA packet received\n");
+			dev_dbg(component->dev, "CODE_DATA packet received\n");
 			break;
 
 		case 0x0fed0009:
-			dev_dbg(codec->dev, "Download complete\n");
+			dev_dbg(component->dev, "Download complete\n");
 			break;
 
 		case 0x0fed000c:
-			dev_dbg(codec->dev, "Application start\n");
+			dev_dbg(component->dev, "Application start\n");
 			break;
 
 		case 0x0fed000e:
-			dev_dbg(codec->dev, "PLL packet received\n");
+			dev_dbg(component->dev, "PLL packet received\n");
 			wm0010->pll_running = true;
 			break;
 
 		case 0x0fed0025:
-			dev_err(codec->dev, "Device reports image too long\n");
+			dev_err(component->dev, "Device reports image too long\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed002c:
-			dev_err(codec->dev, "Device reports bad SPI packet\n");
+			dev_err(component->dev, "Device reports bad SPI packet\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0031:
-			dev_err(codec->dev, "Device reports SPI read overflow\n");
+			dev_err(component->dev, "Device reports SPI read overflow\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0032:
-			dev_err(codec->dev, "Device reports SPI underclock\n");
+			dev_err(component->dev, "Device reports SPI underclock\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0033:
-			dev_err(codec->dev, "Device reports bad header packet\n");
+			dev_err(component->dev, "Device reports bad header packet\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0034:
-			dev_err(codec->dev, "Device reports invalid packet type\n");
+			dev_err(component->dev, "Device reports invalid packet type\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0035:
-			dev_err(codec->dev, "Device reports data before header error\n");
+			dev_err(component->dev, "Device reports data before header error\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		case 0x0fed0038:
-			dev_err(codec->dev, "Device reports invalid PLL packet\n");
+			dev_err(component->dev, "Device reports invalid PLL packet\n");
 			break;
 
 		case 0x0fed003a:
-			dev_err(codec->dev, "Device reports packet alignment error\n");
+			dev_err(component->dev, "Device reports packet alignment error\n");
 			wm0010_mark_boot_failure(wm0010);
 			break;
 
 		default:
-			dev_err(codec->dev, "Unrecognised return 0x%x\n",
+			dev_err(component->dev, "Unrecognised return 0x%x\n",
 			    be32_to_cpu(out32[i]));
 			wm0010_mark_boot_failure(wm0010);
 			break;
@@ -342,10 +342,10 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
 		data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
 }
 
-static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
+static int wm0010_firmware_load(const char *name, struct snd_soc_component *component)
 {
-	struct spi_device *spi = to_spi_device(codec->dev);
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct spi_device *spi = to_spi_device(component->dev);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 	struct list_head xfer_list;
 	struct wm0010_boot_xfer *xfer;
 	int ret;
@@ -359,9 +359,9 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 
 	INIT_LIST_HEAD(&xfer_list);
 
-	ret = request_firmware(&fw, name, codec->dev);
+	ret = request_firmware(&fw, name, component->dev);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to request application(%s): %d\n",
+		dev_err(component->dev, "Failed to request application(%s): %d\n",
 			name, ret);
 		return ret;
 	}
@@ -377,25 +377,25 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 
 	/* First record should be INFO */
 	if (rec->command != DFW_CMD_INFO) {
-		dev_err(codec->dev, "First record not INFO\r\n");
+		dev_err(component->dev, "First record not INFO\r\n");
 		ret = -EINVAL;
 		goto abort;
 	}
 
 	if (inforec->info_version != INFO_VERSION) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Unsupported version (%02d) of INFO record\r\n",
 			inforec->info_version);
 		ret = -EINVAL;
 		goto abort;
 	}
 
-	dev_dbg(codec->dev, "Version v%02d INFO record found\r\n",
+	dev_dbg(component->dev, "Version v%02d INFO record found\r\n",
 		inforec->info_version);
 
 	/* Check it's a DSP file */
 	if (dsp != DEVICE_ID_WM0010) {
-		dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+		dev_err(component->dev, "Not a WM0010 firmware file.\r\n");
 		ret = -EINVAL;
 		goto abort;
 	}
@@ -405,7 +405,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 	rec = (void *)&rec->data[rec->length];
 
 	while (offset < fw->size) {
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			"Packet: command %d, data length = 0x%x\r\n",
 			rec->command, rec->length);
 		len = rec->length + 8;
@@ -416,7 +416,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 			goto abort;
 		}
 
-		xfer->codec = codec;
+		xfer->component = component;
 		list_add_tail(&xfer->list, &xfer_list);
 
 		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
@@ -460,18 +460,18 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 		rec = (void *)&rec->data[rec->length];
 
 		if (offset >= fw->size) {
-			dev_dbg(codec->dev, "All transfers scheduled\n");
+			dev_dbg(component->dev, "All transfers scheduled\n");
 			xfer->done = &done;
 		}
 
 		ret = spi_async(spi, &xfer->m);
 		if (ret != 0) {
-			dev_err(codec->dev, "Write failed: %d\n", ret);
+			dev_err(component->dev, "Write failed: %d\n", ret);
 			goto abort1;
 		}
 
 		if (wm0010->boot_failed) {
-			dev_dbg(codec->dev, "Boot fail!\n");
+			dev_dbg(component->dev, "Boot fail!\n");
 			ret = -EINVAL;
 			goto abort1;
 		}
@@ -496,10 +496,10 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int wm0010_stage2_load(struct snd_soc_codec *codec)
+static int wm0010_stage2_load(struct snd_soc_component *component)
 {
-	struct spi_device *spi = to_spi_device(codec->dev);
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct spi_device *spi = to_spi_device(component->dev);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 	const struct firmware *fw;
 	struct spi_message m;
 	struct spi_transfer t;
@@ -508,14 +508,14 @@ static int wm0010_stage2_load(struct snd_soc_codec *codec)
 	int i;
 	int ret = 0;
 
-	ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev);
+	ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to request stage2 loader: %d\n",
+		dev_err(component->dev, "Failed to request stage2 loader: %d\n",
 			ret);
 		return ret;
 	}
 
-	dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
+	dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
 
 	/* Copy to local buffer first as vmalloc causes problems for dma */
 	img = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
@@ -541,19 +541,19 @@ static int wm0010_stage2_load(struct snd_soc_codec *codec)
 	t.speed_hz = wm0010->sysclk / 10;
 	spi_message_add_tail(&t, &m);
 
-	dev_dbg(codec->dev, "Starting initial download at %dHz\n",
+	dev_dbg(component->dev, "Starting initial download at %dHz\n",
 		t.speed_hz);
 
 	ret = spi_sync(spi, &m);
 	if (ret != 0) {
-		dev_err(codec->dev, "Initial download failed: %d\n", ret);
+		dev_err(component->dev, "Initial download failed: %d\n", ret);
 		goto abort;
 	}
 
 	/* Look for errors from the boot ROM */
 	for (i = 0; i < fw->size; i++) {
 		if (out[i] != 0x55) {
-			dev_err(codec->dev, "Boot ROM error: %x in %d\n",
+			dev_err(component->dev, "Boot ROM error: %x in %d\n",
 				out[i], i);
 			wm0010_mark_boot_failure(wm0010);
 			ret = -EBUSY;
@@ -570,10 +570,10 @@ static int wm0010_stage2_load(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int wm0010_boot(struct snd_soc_codec *codec)
+static int wm0010_boot(struct snd_soc_component *component)
 {
-	struct spi_device *spi = to_spi_device(codec->dev);
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct spi_device *spi = to_spi_device(component->dev);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 	unsigned long flags;
 	int ret;
 	struct spi_message m;
@@ -590,7 +590,7 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
 
 	if (wm0010->sysclk > 26000000) {
-		dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n");
+		dev_err(component->dev, "Max DSP clock frequency is 26MHz\n");
 		ret = -ECANCELED;
 		goto err;
 	}
@@ -598,7 +598,7 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 	mutex_lock(&wm0010->lock);
 	wm0010->pll_running = false;
 
-	dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
+	dev_dbg(component->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
 				    wm0010->core_supplies);
@@ -623,19 +623,19 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 
 	if (!wait_for_completion_timeout(&wm0010->boot_completion,
 					 msecs_to_jiffies(20)))
-		dev_err(codec->dev, "Failed to get interrupt from DSP\n");
+		dev_err(component->dev, "Failed to get interrupt from DSP\n");
 
 	spin_lock_irqsave(&wm0010->irq_lock, flags);
 	wm0010->state = WM0010_BOOTROM;
 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
 
-	ret = wm0010_stage2_load(codec);
+	ret = wm0010_stage2_load(component);
 	if (ret)
 		goto abort;
 
 	if (!wait_for_completion_timeout(&wm0010->boot_completion,
 					 msecs_to_jiffies(20)))
-		dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n");
+		dev_err(component->dev, "Failed to get interrupt from DSP loader.\n");
 
 	spin_lock_irqsave(&wm0010->irq_lock, flags);
 	wm0010->state = WM0010_STAGE2;
@@ -676,14 +676,14 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 
 		ret = spi_sync(spi, &m);
 		if (ret) {
-			dev_err(codec->dev, "First PLL write failed: %d\n", ret);
+			dev_err(component->dev, "First PLL write failed: %d\n", ret);
 			goto abort_swap;
 		}
 
 		/* Use a second send of the message to get the return status */
 		ret = spi_sync(spi, &m);
 		if (ret) {
-			dev_err(codec->dev, "Second PLL write failed: %d\n", ret);
+			dev_err(component->dev, "Second PLL write failed: %d\n", ret);
 			goto abort_swap;
 		}
 
@@ -692,7 +692,7 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 		/* Look for PLL active code from the DSP */
 		for (i = 0; i < len / 4; i++) {
 			if (*p == 0x0e00ed0f) {
-				dev_dbg(codec->dev, "PLL packet received\n");
+				dev_dbg(component->dev, "PLL packet received\n");
 				wm0010->pll_running = true;
 				break;
 			}
@@ -702,9 +702,9 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 		kfree(img_swap);
 		kfree(out);
 	} else
-		dev_dbg(codec->dev, "Not enabling DSP PLL.");
+		dev_dbg(component->dev, "Not enabling DSP PLL.");
 
-	ret = wm0010_firmware_load("wm0010.dfw", codec);
+	ret = wm0010_firmware_load("wm0010.dfw", component);
 
 	if (ret != 0)
 		goto abort;
@@ -723,7 +723,7 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 	kfree(out);
 abort:
 	/* Put the chip back into reset */
-	wm0010_halt(codec);
+	wm0010_halt(component);
 	mutex_unlock(&wm0010->lock);
 	return ret;
 
@@ -735,22 +735,22 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int wm0010_set_bias_level(struct snd_soc_codec *codec,
+static int wm0010_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
-			wm0010_boot(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
+			wm0010_boot(component);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
 			mutex_lock(&wm0010->lock);
-			wm0010_halt(codec);
+			wm0010_halt(component);
 			mutex_unlock(&wm0010->lock);
 		}
 		break;
@@ -761,10 +761,10 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,
+static int wm0010_set_sysclk(struct snd_soc_component *component, int source,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 	unsigned int i;
 
 	wm0010->sysclk = freq;
@@ -783,20 +783,19 @@ static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,
 	return 0;
 }
 
-static int wm0010_probe(struct snd_soc_codec *codec);
-
-static const struct snd_soc_codec_driver soc_codec_dev_wm0010 = {
-	.probe = wm0010_probe,
-	.set_bias_level = wm0010_set_bias_level,
-	.set_sysclk = wm0010_set_sysclk,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.dapm_widgets		= wm0010_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm0010_dapm_widgets),
-		.dapm_routes		= wm0010_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm0010_dapm_routes),
-	},
+static int wm0010_probe(struct snd_soc_component *component);
+
+static const struct snd_soc_component_driver soc_component_dev_wm0010 = {
+	.probe			= wm0010_probe,
+	.set_bias_level		= wm0010_set_bias_level,
+	.set_sysclk		= wm0010_set_sysclk,
+	.dapm_widgets		= wm0010_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm0010_dapm_widgets),
+	.dapm_routes		= wm0010_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm0010_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
@@ -860,11 +859,11 @@ static irqreturn_t wm0010_irq(int irq, void *data)
 	return IRQ_NONE;
 }
 
-static int wm0010_probe(struct snd_soc_codec *codec)
+static int wm0010_probe(struct snd_soc_component *component)
 {
-	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
 
-	wm0010->codec = codec;
+	wm0010->component = component;
 
 	return 0;
 }
@@ -967,8 +966,8 @@ static int wm0010_spi_probe(struct spi_device *spi)
 	else
 		wm0010->board_max_spi_speed = 0;
 
-	ret = snd_soc_register_codec(&spi->dev,
-				     &soc_codec_dev_wm0010, wm0010_dai,
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm0010, wm0010_dai,
 				     ARRAY_SIZE(wm0010_dai));
 	if (ret < 0)
 		return ret;
@@ -980,8 +979,6 @@ static int wm0010_spi_remove(struct spi_device *spi)
 {
 	struct wm0010_priv *wm0010 = spi_get_drvdata(spi);
 
-	snd_soc_unregister_codec(&spi->dev);
-
 	gpio_set_value_cansleep(wm0010->gpio_reset,
 				wm0010->gpio_reset_value);
 
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index cf5f0580df6a..9727eec6d01b 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -32,10 +32,10 @@ struct wm1250_priv {
 	struct gpio gpios[WM1250_EV1_NUM_GPIOS];
 };
 
-static int wm1250_ev1_set_bias_level(struct snd_soc_codec *codec,
+static int wm1250_ev1_set_bias_level(struct snd_soc_component *component,
 				     enum snd_soc_bias_level level)
 {
-	struct wm1250_priv *wm1250 = dev_get_drvdata(codec->dev);
+	struct wm1250_priv *wm1250 = dev_get_drvdata(component->dev);
 	int ena;
 
 	if (wm1250)
@@ -81,7 +81,7 @@ static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct wm1250_priv *wm1250 = snd_soc_codec_get_drvdata(dai->codec);
+	struct wm1250_priv *wm1250 = snd_soc_component_get_drvdata(dai->component);
 
 	switch (params_rate(params)) {
 	case 8000:
@@ -141,15 +141,15 @@ static struct snd_soc_dai_driver wm1250_ev1_dai = {
 	.ops = &wm1250_ev1_ops,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
-	.component_driver = {
-		.dapm_widgets		= wm1250_ev1_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm1250_ev1_dapm_widgets),
-		.dapm_routes		= wm1250_ev1_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm1250_ev1_dapm_routes),
-	},
-	.set_bias_level = wm1250_ev1_set_bias_level,
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_wm1250_ev1 = {
+	.dapm_widgets		= wm1250_ev1_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm1250_ev1_dapm_widgets),
+	.dapm_routes		= wm1250_ev1_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm1250_ev1_dapm_routes),
+	.set_bias_level		= wm1250_ev1_set_bias_level,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm1250_ev1_pdata(struct i2c_client *i2c)
@@ -224,7 +224,7 @@ static int wm1250_ev1_probe(struct i2c_client *i2c,
 	if (ret != 0)
 		return ret;
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_wm1250_ev1,
 				     &wm1250_ev1_dai, 1);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
@@ -237,7 +237,6 @@ static int wm1250_ev1_probe(struct i2c_client *i2c,
 
 static int wm1250_ev1_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&i2c->dev);
 	wm1250_ev1_free(i2c);
 
 	return 0;
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index abfa052c07d8..c5ae07234a00 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -607,8 +607,8 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
 static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 
 	ucontrol->value.integer.value[0] = wm2000->anc_active;
 
@@ -618,8 +618,8 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
 static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 	unsigned int anc_active = ucontrol->value.integer.value[0];
 	int ret;
 
@@ -640,8 +640,8 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 
 	ucontrol->value.integer.value[0] = wm2000->spk_ena;
 
@@ -651,8 +651,8 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
 static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 	unsigned int val = ucontrol->value.integer.value[0];
 	int ret;
 
@@ -683,8 +683,8 @@ static const struct snd_kcontrol_new wm2000_controls[] = {
 static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
 				  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 	int ret;
 
 	mutex_lock(&wm2000->lock);
@@ -724,16 +724,16 @@ static const struct snd_soc_dapm_route wm2000_audio_map[] = {
 };
 
 #ifdef CONFIG_PM
-static int wm2000_suspend(struct snd_soc_codec *codec)
+static int wm2000_suspend(struct snd_soc_component *component)
 {
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 
 	return wm2000_anc_transition(wm2000, ANC_OFF);
 }
 
-static int wm2000_resume(struct snd_soc_codec *codec)
+static int wm2000_resume(struct snd_soc_component *component)
 {
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 
 	return wm2000_anc_set_mode(wm2000);
 }
@@ -782,9 +782,9 @@ static const struct regmap_config wm2000_regmap = {
 	.readable_reg = wm2000_readable_reg,
 };
 
-static int wm2000_probe(struct snd_soc_codec *codec)
+static int wm2000_probe(struct snd_soc_component *component)
 {
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 
 	/* This will trigger a transition to standby mode by default */
 	wm2000_anc_set_mode(wm2000);
@@ -792,27 +792,28 @@ static int wm2000_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int wm2000_remove(struct snd_soc_codec *codec)
+static void wm2000_remove(struct snd_soc_component *component)
 {
-	struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
 
-	return wm2000_anc_transition(wm2000, ANC_OFF);
+	wm2000_anc_transition(wm2000, ANC_OFF);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm2000 = {
-	.probe = wm2000_probe,
-	.remove = wm2000_remove,
-	.suspend = wm2000_suspend,
-	.resume = wm2000_resume,
-
-	.component_driver = {
-		.controls		= wm2000_controls,
-		.num_controls		= ARRAY_SIZE(wm2000_controls),
-		.dapm_widgets		= wm2000_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm2000_dapm_widgets),
-		.dapm_routes		= wm2000_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(wm2000_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm2000 = {
+	.probe			= wm2000_probe,
+	.remove			= wm2000_remove,
+	.suspend		= wm2000_suspend,
+	.resume			= wm2000_resume,
+	.controls		= wm2000_controls,
+	.num_controls		= ARRAY_SIZE(wm2000_controls),
+	.dapm_widgets		= wm2000_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm2000_dapm_widgets),
+	.dapm_routes		= wm2000_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm2000_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm2000_i2c_probe(struct i2c_client *i2c,
@@ -916,7 +917,8 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
 
 	wm2000_reset(wm2000);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+					&soc_component_dev_wm2000, NULL, 0);
 
 err_supplies:
 	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
@@ -926,13 +928,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
 	return ret;
 }
 
-static int wm2000_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm2000_i2c_id[] = {
 	{ "wm2000", 0 },
 	{ }
@@ -944,7 +939,6 @@ static struct i2c_driver wm2000_i2c_driver = {
 		.name = "wm2000",
 	},
 	.probe = wm2000_i2c_probe,
-	.remove = wm2000_i2c_remove,
 	.id_table = wm2000_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 5c2f5727244d..d5f4bbf27182 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -87,7 +87,7 @@ struct wm2200_priv {
 	struct wm_adsp dsp[2];
 	struct regmap *regmap;
 	struct device *dev;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm2200_pdata pdata;
 	struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES];
 
@@ -1550,14 +1550,14 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
 	WM2200_MIXER_ROUTES("LHPF2", "LHPF2"),
 };
 
-static int wm2200_probe(struct snd_soc_codec *codec)
+static int wm2200_probe(struct snd_soc_component *component)
 {
-	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	wm2200->codec = codec;
+	wm2200->component = component;
 
-	ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
+	ret = snd_soc_add_component_controls(component, wm_adsp_fw_controls, 2);
 	if (ret != 0)
 		return ret;
 
@@ -1566,7 +1566,7 @@ static int wm2200_probe(struct snd_soc_codec *codec)
 
 static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int lrclk, bclk, fmt_val;
 
 	lrclk = 0;
@@ -1580,7 +1580,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		fmt_val = 2;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported DAI format %d\n",
+		dev_err(component->dev, "Unsupported DAI format %d\n",
 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
 		return -EINVAL;
 	}
@@ -1599,7 +1599,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		bclk |= WM2200_AIF1_BCLK_MSTR;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported master mode %d\n",
+		dev_err(component->dev, "Unsupported master mode %d\n",
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
@@ -1621,15 +1621,15 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
 			    WM2200_AIF1_BCLK_INV, bclk);
-	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_2,
 			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
 			    lrclk);
-	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_3,
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_3,
 			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
 			    lrclk);
-	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_5,
 			    WM2200_AIF1_FMT_MASK, fmt_val);
 
 	return 0;
@@ -1698,8 +1698,8 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
 	int i, bclk, lrclk, wl, fl, sr_code;
 	int *bclk_rates;
 
@@ -1711,7 +1711,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
 	if (fl < 0)
 		return fl;
 
-	dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
+	dev_dbg(component->dev, "Word length %d bits, frame length %d bits\n",
 		wl, fl);
 
 	/* Target BCLK rate */
@@ -1720,7 +1720,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
 		return bclk;
 
 	if (!wm2200->sysclk) {
-		dev_err(codec->dev, "SYSCLK has no rate set\n");
+		dev_err(component->dev, "SYSCLK has no rate set\n");
 		return -EINVAL;
 	}
 
@@ -1728,13 +1728,13 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
 		if (wm2200_sr_code[i] == params_rate(params))
 			break;
 	if (i == ARRAY_SIZE(wm2200_sr_code)) {
-		dev_err(codec->dev, "Unsupported sample rate: %dHz\n",
+		dev_err(component->dev, "Unsupported sample rate: %dHz\n",
 			params_rate(params));
 		return -EINVAL;
 	}
 	sr_code = i;
 
-	dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
+	dev_dbg(component->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
 		bclk, wm2200->sysclk);
 
 	if (wm2200->sysclk % 4000)
@@ -1746,38 +1746,38 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
 		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
 			break;
 	if (i == WM2200_NUM_BCLK_RATES) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"No valid BCLK for %dHz found from %dHz SYSCLK\n",
 			bclk, wm2200->sysclk);
 		return -EINVAL;
 	}
 
 	bclk = i;
-	dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
-	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1,
+	dev_dbg(component->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_1,
 			    WM2200_AIF1_BCLK_DIV_MASK, bclk);
 
 	lrclk = bclk_rates[bclk] / params_rate(params);
-	dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+	dev_dbg(component->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
 	    wm2200->symmetric_rates)
-		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_7,
 				    WM2200_AIF1RX_BCPF_MASK, lrclk);
 	else
-		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_6,
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_6,
 				    WM2200_AIF1TX_BCPF_MASK, lrclk);
 
 	i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_9,
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_9,
 				    WM2200_AIF1RX_WL_MASK |
 				    WM2200_AIF1RX_SLOT_LEN_MASK, i);
 	else
-		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_8,
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_8,
 				    WM2200_AIF1TX_WL_MASK |
 				    WM2200_AIF1TX_SLOT_LEN_MASK, i);
 
-	snd_soc_update_bits(codec, WM2200_CLOCKING_4,
+	snd_soc_component_update_bits(component, WM2200_CLOCKING_4,
 			    WM2200_SAMPLE_RATE_1_MASK, sr_code);
 
 	return 0;
@@ -1788,10 +1788,10 @@ static const struct snd_soc_dai_ops wm2200_dai_ops = {
 	.hw_params = wm2200_hw_params,
 };
 
-static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id,
 			     int source, unsigned int freq, int dir)
 {
-	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
 	int fval;
 
 	switch (clk_id) {
@@ -1799,7 +1799,7 @@ static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		break;
 
 	default:
-		dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+		dev_err(component->dev, "Unknown clock %d\n", clk_id);
 		return -EINVAL;
 	}
 
@@ -1810,7 +1810,7 @@ static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	case WM2200_CLKSRC_BCLK1:
 		break;
 	default:
-		dev_err(codec->dev, "Invalid source %d\n", source);
+		dev_err(component->dev, "Invalid source %d\n", source);
 		return -EINVAL;
 	}
 
@@ -1820,7 +1820,7 @@ static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		fval = 2;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
+		dev_err(component->dev, "Invalid clock rate: %d\n", freq);
 		return -EINVAL;
 	}
 
@@ -1828,7 +1828,7 @@ static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	 * match.
 	 */
 
-	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
+	snd_soc_component_update_bits(component, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
 			    WM2200_SYSCLK_SRC_MASK,
 			    fval << WM2200_SYSCLK_FREQ_SHIFT | source);
 
@@ -1936,23 +1936,23 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm2200_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
 	struct _fll_div factors;
 	int ret, i, timeout;
 	unsigned long time_left;
 
 	if (!Fout) {
-		dev_dbg(codec->dev, "FLL disabled");
+		dev_dbg(component->dev, "FLL disabled");
 
 		if (wm2200->fll_fout)
-			pm_runtime_put(codec->dev);
+			pm_runtime_put(component->dev);
 
 		wm2200->fll_fout = 0;
-		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_1,
 				    WM2200_FLL_ENA, 0);
 		return 0;
 	}
@@ -1963,7 +1963,7 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	case WM2200_FLL_SRC_BCLK:
 		break;
 	default:
-		dev_err(codec->dev, "Invalid FLL source %d\n", source);
+		dev_err(component->dev, "Invalid FLL source %d\n", source);
 		return -EINVAL;
 	}
 
@@ -1972,44 +1972,44 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return ret;
 
 	/* Disable the FLL while we reconfigure */
-	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
 
-	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_2,
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_2,
 			    WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK,
 			    (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) |
 			    factors.fll_fratio);
 	if (factors.theta) {
-		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
+		snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_3,
 				    WM2200_FLL_FRACN_ENA,
 				    WM2200_FLL_FRACN_ENA);
-		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
+		snd_soc_component_update_bits(component, WM2200_FLL_EFS_2,
 				    WM2200_FLL_EFS_ENA,
 				    WM2200_FLL_EFS_ENA);
 	} else {
-		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
+		snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_3,
 				    WM2200_FLL_FRACN_ENA, 0);
-		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
+		snd_soc_component_update_bits(component, WM2200_FLL_EFS_2,
 				    WM2200_FLL_EFS_ENA, 0);
 	}
 
-	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
 			    factors.theta);
-	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
 			    factors.n);
-	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_7,
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_7,
 			    WM2200_FLL_CLK_REF_DIV_MASK |
 			    WM2200_FLL_CLK_REF_SRC_MASK,
 			    (factors.fll_refclk_div
 			     << WM2200_FLL_CLK_REF_DIV_SHIFT) | source);
-	snd_soc_update_bits(codec, WM2200_FLL_EFS_1,
+	snd_soc_component_update_bits(component, WM2200_FLL_EFS_1,
 			    WM2200_FLL_LAMBDA_MASK, factors.lambda);
 
 	/* Clear any pending completions */
 	try_wait_for_completion(&wm2200->fll_lock);
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
-	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_1,
 			    WM2200_FLL_ENA, WM2200_FLL_ENA);
 
 	if (i2c->irq)
@@ -2017,7 +2017,7 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	else
 		timeout = 50;
 
-	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
+	snd_soc_component_update_bits(component, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
 			    WM2200_SYSCLK_ENA);
 
 	/* Poll for the lock; will use the interrupt to exit quickly */
@@ -2032,10 +2032,10 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			msleep(1);
 		}
 
-		ret = snd_soc_read(codec,
+		ret = snd_soc_component_read32(component,
 				   WM2200_INTERRUPT_RAW_STATUS_2);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to read FLL status: %d\n",
 				ret);
 			continue;
@@ -2044,8 +2044,8 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			break;
 	}
 	if (i == timeout) {
-		dev_err(codec->dev, "FLL lock timed out\n");
-		pm_runtime_put(codec->dev);
+		dev_err(component->dev, "FLL lock timed out\n");
+		pm_runtime_put(component->dev);
 		return -ETIMEDOUT;
 	}
 
@@ -2053,29 +2053,29 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	wm2200->fll_fref = Fref;
 	wm2200->fll_fout = Fout;
 
-	dev_dbg(codec->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
+	dev_dbg(component->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
 
 	return 0;
 }
 
 static int wm2200_dai_probe(struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
 	unsigned int val = 0;
 	int ret;
 
-	ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
+	ret = snd_soc_component_read32(component, WM2200_GPIO_CTRL_1);
 	if (ret >= 0) {
 		if ((ret & WM2200_GP1_FN_MASK) != 0) {
 			wm2200->symmetric_rates = true;
 			val = WM2200_AIF1TX_LRCLK_SRC;
 		}
 	} else {
-		dev_err(codec->dev, "Failed to read GPIO 1 config: %d\n", ret);
+		dev_err(component->dev, "Failed to read GPIO 1 config: %d\n", ret);
 	}
 
-	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_2,
 			    WM2200_AIF1TX_LRCLK_SRC, val);
 
 	return 0;
@@ -2106,22 +2106,18 @@ static struct snd_soc_dai_driver wm2200_dai = {
 	.ops = &wm2200_dai_ops,
 };
 
-static const struct snd_soc_codec_driver soc_codec_wm2200 = {
-	.probe = wm2200_probe,
-
-	.idle_bias_off = true,
-	.ignore_pmdown_time = true,
-	.set_sysclk = wm2200_set_sysclk,
-	.set_pll = wm2200_set_fll,
-
-	.component_driver = {
-		.controls		= wm2200_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm2200_snd_controls),
-		.dapm_widgets		= wm2200_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm2200_dapm_widgets),
-		.dapm_routes		= wm2200_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm2200_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_wm2200 = {
+	.probe			= wm2200_probe,
+	.set_sysclk		= wm2200_set_sysclk,
+	.set_pll		= wm2200_set_fll,
+	.controls		= wm2200_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm2200_snd_controls),
+	.dapm_widgets		= wm2200_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm2200_dapm_widgets),
+	.dapm_routes		= wm2200_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm2200_dapm_routes),
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static irqreturn_t wm2200_irq(int irq, void *data)
@@ -2408,7 +2404,7 @@ static int wm2200_i2c_probe(struct i2c_client *i2c,
 	pm_runtime_enable(&i2c->dev);
 	pm_request_idle(&i2c->dev);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_wm2200,
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_wm2200,
 				     &wm2200_dai, 1);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
@@ -2435,7 +2431,6 @@ static int wm2200_i2c_remove(struct i2c_client *i2c)
 {
 	struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
 
-	snd_soc_unregister_codec(&i2c->dev);
 	if (i2c->irq)
 		free_irq(i2c->irq, wm2200);
 	if (wm2200->pdata.reset)
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 138a84efdd54..87f9a99ce978 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -55,7 +55,7 @@ struct wm5100_fll {
 struct wm5100_priv {
 	struct device *dev;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
 	struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
 
@@ -118,16 +118,16 @@ static int wm5100_sr_regs[WM5100_SYNC_SRS] = {
 	WM5100_CLOCKING_6,
 };
 
-static int wm5100_alloc_sr(struct snd_soc_codec *codec, int rate)
+static int wm5100_alloc_sr(struct snd_soc_component *component, int rate)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	int sr_code, sr_free, i;
 
 	for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
 		if (wm5100_sr_code[i] == rate)
 			break;
 	if (i == ARRAY_SIZE(wm5100_sr_code)) {
-		dev_err(codec->dev, "Unsupported sample rate: %dHz\n", rate);
+		dev_err(component->dev, "Unsupported sample rate: %dHz\n", rate);
 		return -EINVAL;
 	}
 	sr_code = i;
@@ -140,50 +140,50 @@ static int wm5100_alloc_sr(struct snd_soc_codec *codec, int rate)
 				sr_free = i;
 				continue;
 			}
-			if ((snd_soc_read(codec, wm5100_sr_regs[i]) &
+			if ((snd_soc_component_read32(component, wm5100_sr_regs[i]) &
 			     WM5100_SAMPLE_RATE_1_MASK) == sr_code)
 				break;
 		}
 
 		if (i < ARRAY_SIZE(wm5100_sr_regs)) {
 			wm5100->sr_ref[i]++;
-			dev_dbg(codec->dev, "SR %dHz, slot %d, ref %d\n",
+			dev_dbg(component->dev, "SR %dHz, slot %d, ref %d\n",
 				rate, i, wm5100->sr_ref[i]);
 			return i;
 		}
 
 		if (sr_free == -1) {
-			dev_err(codec->dev, "All SR slots already in use\n");
+			dev_err(component->dev, "All SR slots already in use\n");
 			return -EBUSY;
 		}
 
-		dev_dbg(codec->dev, "Allocating SR slot %d for %dHz\n",
+		dev_dbg(component->dev, "Allocating SR slot %d for %dHz\n",
 			sr_free, rate);
 		wm5100->sr_ref[sr_free]++;
-		snd_soc_update_bits(codec, wm5100_sr_regs[sr_free],
+		snd_soc_component_update_bits(component, wm5100_sr_regs[sr_free],
 				    WM5100_SAMPLE_RATE_1_MASK,
 				    sr_code);
 
 		return sr_free;
 
 	} else {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"SR %dHz incompatible with %dHz SYSCLK and %dHz ASYNCCLK\n",
 			rate, wm5100->sysclk, wm5100->asyncclk);
 		return -EINVAL;
 	}
 }
 
-static void wm5100_free_sr(struct snd_soc_codec *codec, int rate)
+static void wm5100_free_sr(struct snd_soc_component *component, int rate)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	int i, sr_code;
 
 	for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
 		if (wm5100_sr_code[i] == rate)
 			break;
 	if (i == ARRAY_SIZE(wm5100_sr_code)) {
-		dev_err(codec->dev, "Unsupported sample rate: %dHz\n", rate);
+		dev_err(component->dev, "Unsupported sample rate: %dHz\n", rate);
 		return;
 	}
 	sr_code = wm5100_sr_code[i];
@@ -192,16 +192,16 @@ static void wm5100_free_sr(struct snd_soc_codec *codec, int rate)
 		if (!wm5100->sr_ref[i])
 			continue;
 
-		if ((snd_soc_read(codec, wm5100_sr_regs[i]) &
+		if ((snd_soc_component_read32(component, wm5100_sr_regs[i]) &
 		     WM5100_SAMPLE_RATE_1_MASK) == sr_code)
 			break;
 	}
 	if (i < ARRAY_SIZE(wm5100_sr_regs)) {
 		wm5100->sr_ref[i]--;
-		dev_dbg(codec->dev, "Dereference SR %dHz, count now %d\n",
+		dev_dbg(component->dev, "Dereference SR %dHz, count now %d\n",
 			rate, wm5100->sr_ref[i]);
 	} else {
-		dev_warn(codec->dev, "Freeing unreferenced sample rate %dHz\n",
+		dev_warn(component->dev, "Freeing unreferenced sample rate %dHz\n",
 			 rate);
 	}
 }
@@ -733,40 +733,39 @@ WM5100_MIXER_CONTROLS("LHPF3", WM5100_HPLP3MIX_INPUT_1_SOURCE),
 WM5100_MIXER_CONTROLS("LHPF4", WM5100_HPLP4MIX_INPUT_1_SOURCE),
 };
 
-static void wm5100_seq_notifier(struct snd_soc_dapm_context *dapm,
+static void wm5100_seq_notifier(struct snd_soc_component *component,
 				enum snd_soc_dapm_type event, int subseq)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	u16 val, expect, i;
 
 	/* Wait for the outputs to flag themselves as enabled */
 	if (wm5100->out_ena[0]) {
-		expect = snd_soc_read(codec, WM5100_CHANNEL_ENABLES_1);
+		expect = snd_soc_component_read32(component, WM5100_CHANNEL_ENABLES_1);
 		for (i = 0; i < 200; i++) {
-			val = snd_soc_read(codec, WM5100_OUTPUT_STATUS_1);
+			val = snd_soc_component_read32(component, WM5100_OUTPUT_STATUS_1);
 			if (val == expect) {
 				wm5100->out_ena[0] = false;
 				break;
 			}
 		}
 		if (i == 200) {
-			dev_err(codec->dev, "Timeout waiting for OUTPUT1 %x\n",
+			dev_err(component->dev, "Timeout waiting for OUTPUT1 %x\n",
 				expect);
 		}
 	}
 
 	if (wm5100->out_ena[1]) {
-		expect = snd_soc_read(codec, WM5100_OUTPUT_ENABLES_2);
+		expect = snd_soc_component_read32(component, WM5100_OUTPUT_ENABLES_2);
 		for (i = 0; i < 200; i++) {
-			val = snd_soc_read(codec, WM5100_OUTPUT_STATUS_2);
+			val = snd_soc_component_read32(component, WM5100_OUTPUT_STATUS_2);
 			if (val == expect) {
 				wm5100->out_ena[1] = false;
 				break;
 			}
 		}
 		if (i == 200) {
-			dev_err(codec->dev, "Timeout waiting for OUTPUT2 %x\n",
+			dev_err(component->dev, "Timeout waiting for OUTPUT2 %x\n",
 				expect);
 		}
 	}
@@ -776,8 +775,8 @@ static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol,
 			 int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 
 	switch (w->reg) {
 	case WM5100_CHANNEL_ENABLES_1:
@@ -841,17 +840,17 @@ static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_3);
+	ret = snd_soc_component_read32(component, WM5100_INTERRUPT_RAW_STATUS_3);
 	ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
 		WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
 		WM5100_CLKGEN_ERR_ASYNC_STS;
 	wm5100_log_status3(wm5100, ret);
 
-	ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_4);
+	ret = snd_soc_component_read32(component, WM5100_INTERRUPT_RAW_STATUS_4);
 	wm5100_log_status4(wm5100, ret);
 
 	return 0;
@@ -1282,7 +1281,7 @@ static const struct reg_sequence wm5100_reva_patches[] = {
 
 static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int lrclk, bclk, mask, base;
 
 	base = dai->driver->base;
@@ -1298,7 +1297,7 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		mask = 2;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported DAI format %d\n",
+		dev_err(component->dev, "Unsupported DAI format %d\n",
 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
 		return -EINVAL;
 	}
@@ -1317,7 +1316,7 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		bclk |= WM5100_AIF1_BCLK_MSTR;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported master mode %d\n",
+		dev_err(component->dev, "Unsupported master mode %d\n",
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
@@ -1339,13 +1338,13 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, base + 1, WM5100_AIF1_BCLK_MSTR |
+	snd_soc_component_update_bits(component, base + 1, WM5100_AIF1_BCLK_MSTR |
 			    WM5100_AIF1_BCLK_INV, bclk);
-	snd_soc_update_bits(codec, base + 2, WM5100_AIF1TX_LRCLK_MSTR |
+	snd_soc_component_update_bits(component, base + 2, WM5100_AIF1TX_LRCLK_MSTR |
 			    WM5100_AIF1TX_LRCLK_INV, lrclk);
-	snd_soc_update_bits(codec, base + 3, WM5100_AIF1TX_LRCLK_MSTR |
+	snd_soc_component_update_bits(component, base + 3, WM5100_AIF1TX_LRCLK_MSTR |
 			    WM5100_AIF1TX_LRCLK_INV, lrclk);
-	snd_soc_update_bits(codec, base + 5, WM5100_AIF1_FMT_MASK, mask);
+	snd_soc_component_update_bits(component, base + 5, WM5100_AIF1_FMT_MASK, mask);
 
 	return 0;
 }
@@ -1400,8 +1399,8 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	bool async = wm5100->aif_async[dai->id];
 	int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
 	int *bclk_rates;
@@ -1416,7 +1415,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
 	if (fl < 0)
 		return fl;
 
-	dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
+	dev_dbg(component->dev, "Word length %d bits, frame length %d bits\n",
 		wl, fl);
 
 	/* Target BCLK rate */
@@ -1427,7 +1426,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
 	/* Root for BCLK depends on SYS/ASYNCCLK */
 	if (!async) {
 		aif_rate = wm5100->sysclk;
-		sr = wm5100_alloc_sr(codec, params_rate(params));
+		sr = wm5100_alloc_sr(component, params_rate(params));
 		if (sr < 0)
 			return sr;
 	} else {
@@ -1439,23 +1438,23 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
 			if (params_rate(params) == wm5100_sr_code[i])
 				break;
 		if (i == ARRAY_SIZE(wm5100_sr_code)) {
-			dev_err(codec->dev, "Invalid rate %dHzn",
+			dev_err(component->dev, "Invalid rate %dHzn",
 				params_rate(params));
 			return -EINVAL;
 		}
 
 		/* TODO: We should really check for symmetry */
-		snd_soc_update_bits(codec, WM5100_CLOCKING_8,
+		snd_soc_component_update_bits(component, WM5100_CLOCKING_8,
 				    WM5100_ASYNC_SAMPLE_RATE_MASK, i);
 	}
 
 	if (!aif_rate) {
-		dev_err(codec->dev, "%s has no rate set\n",
+		dev_err(component->dev, "%s has no rate set\n",
 			async ? "ASYNCCLK" : "SYSCLK");
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz %s\n",
+	dev_dbg(component->dev, "Target BCLK is %dHz, using %dHz %s\n",
 		bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
 
 	if (aif_rate % 4000)
@@ -1467,37 +1466,37 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
 		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
 			break;
 	if (i == WM5100_NUM_BCLK_RATES) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"No valid BCLK for %dHz found from %dHz %s\n",
 			bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
 		return -EINVAL;
 	}
 
 	bclk = i;
-	dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
-	snd_soc_update_bits(codec, base + 1, WM5100_AIF1_BCLK_FREQ_MASK, bclk);
+	dev_dbg(component->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+	snd_soc_component_update_bits(component, base + 1, WM5100_AIF1_BCLK_FREQ_MASK, bclk);
 
 	lrclk = bclk_rates[bclk] / params_rate(params);
-	dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+	dev_dbg(component->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
 	    wm5100->aif_symmetric[dai->id])
-		snd_soc_update_bits(codec, base + 7,
+		snd_soc_component_update_bits(component, base + 7,
 				    WM5100_AIF1RX_BCPF_MASK, lrclk);
 	else
-		snd_soc_update_bits(codec, base + 6,
+		snd_soc_component_update_bits(component, base + 6,
 				    WM5100_AIF1TX_BCPF_MASK, lrclk);
 
 	i = (wl << WM5100_AIF1TX_WL_SHIFT) | fl;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		snd_soc_update_bits(codec, base + 9,
+		snd_soc_component_update_bits(component, base + 9,
 				    WM5100_AIF1RX_WL_MASK |
 				    WM5100_AIF1RX_SLOT_LEN_MASK, i);
 	else
-		snd_soc_update_bits(codec, base + 8,
+		snd_soc_component_update_bits(component, base + 8,
 				    WM5100_AIF1TX_WL_MASK |
 				    WM5100_AIF1TX_SLOT_LEN_MASK, i);
 
-	snd_soc_update_bits(codec, base + 4, WM5100_AIF1_RATE_MASK, sr);
+	snd_soc_component_update_bits(component, base + 4, WM5100_AIF1_RATE_MASK, sr);
 
 	return 0;
 }
@@ -1507,10 +1506,10 @@ static const struct snd_soc_dai_ops wm5100_dai_ops = {
 	.hw_params = wm5100_hw_params,
 };
 
-static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int wm5100_set_sysclk(struct snd_soc_component *component, int clk_id,
 			     int source, unsigned int freq, int dir)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	int *rate_store;
 	int fval, audio_rate, ret, reg;
 
@@ -1529,7 +1528,7 @@ static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		case WM5100_CLKSRC_MCLK1:
 		case WM5100_CLKSRC_MCLK2:
 		case WM5100_CLKSRC_SYSCLK:
-			snd_soc_update_bits(codec, WM5100_CLOCKING_1,
+			snd_soc_component_update_bits(component, WM5100_CLOCKING_1,
 					    WM5100_CLK_32K_SRC_MASK,
 					    source);
 			break;
@@ -1550,7 +1549,7 @@ static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 			wm5100->aif_async[clk_id - 1] = true;
 			break;
 		default:
-			dev_err(codec->dev, "Invalid source %d\n", source);
+			dev_err(component->dev, "Invalid source %d\n", source);
 			return -EINVAL;
 		}	
 		return 0;
@@ -1559,35 +1558,35 @@ static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		switch (freq) {
 		case 5644800:
 		case 6144000:
-			snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
+			snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
 					    WM5100_OPCLK_SEL_MASK, 0);
 			break;
 		case 11289600:
 		case 12288000:
-			snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
+			snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
 					    WM5100_OPCLK_SEL_MASK, 0);
 			break;
 		case 22579200:
 		case 24576000:
-			snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
+			snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
 					    WM5100_OPCLK_SEL_MASK, 0);
 			break;
 		default:
-			dev_err(codec->dev, "Unsupported OPCLK %dHz\n",
+			dev_err(component->dev, "Unsupported OPCLK %dHz\n",
 				freq);
 			return -EINVAL;
 		}
 		return 0;
 
 	default:
-		dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+		dev_err(component->dev, "Unknown clock %d\n", clk_id);
 		return -EINVAL;
 	}
 
 	switch (source) {
 	case WM5100_CLKSRC_SYSCLK:
 	case WM5100_CLKSRC_ASYNCCLK:
-		dev_err(codec->dev, "Invalid source %d\n", source);
+		dev_err(component->dev, "Invalid source %d\n", source);
 		return -EINVAL;
 	}
 
@@ -1605,7 +1604,7 @@ static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 		fval = 2;
 		break;
 	default:
-		dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
+		dev_err(component->dev, "Invalid clock rate: %d\n", freq);
 		return -EINVAL;
 	}
 
@@ -1632,7 +1631,7 @@ static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	 * match.
 	 */
 
-	snd_soc_update_bits(codec, reg, WM5100_SYSCLK_FREQ_MASK |
+	snd_soc_component_update_bits(component, reg, WM5100_SYSCLK_FREQ_MASK |
 			    WM5100_SYSCLK_SRC_MASK,
 			    fval << WM5100_SYSCLK_FREQ_SHIFT | source);
 
@@ -1641,13 +1640,13 @@ static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	 * this clock rate.
 	 */
 	if (clk_id == WM5100_CLK_SYSCLK) {
-		dev_dbg(codec->dev, "Setting primary audio rate to %dHz",
+		dev_dbg(component->dev, "Setting primary audio rate to %dHz",
 			audio_rate);
 		if (0 && *rate_store)
-			wm5100_free_sr(codec, audio_rate);
-		ret = wm5100_alloc_sr(codec, audio_rate);
+			wm5100_free_sr(component, audio_rate);
+		ret = wm5100_alloc_sr(component, audio_rate);
 		if (ret != 0)
-			dev_warn(codec->dev, "Primary audio slot is %d\n",
+			dev_warn(component->dev, "Primary audio slot is %d\n",
 				 ret);
 	}
 
@@ -1755,11 +1754,11 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm5100_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	struct _fll_div factors;
 	struct wm5100_fll *fll;
 	int ret, base, lock, i, timeout;
@@ -1777,16 +1776,16 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		lock = WM5100_FLL2_LOCK_STS;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown FLL %d\n",fll_id);
+		dev_err(component->dev, "Unknown FLL %d\n",fll_id);
 		return -EINVAL;
 	}
 
 	if (!Fout) {
-		dev_dbg(codec->dev, "FLL%d disabled", fll_id);
+		dev_dbg(component->dev, "FLL%d disabled", fll_id);
 		if (fll->fout)
-			pm_runtime_put(codec->dev);
+			pm_runtime_put(component->dev);
 		fll->fout = 0;
-		snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
+		snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, 0);
 		return 0;
 	}
 
@@ -1800,7 +1799,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	case WM5100_FLL_SRC_AIF3BCLK:
 		break;
 	default:
-		dev_err(codec->dev, "Invalid FLL source %d\n", source);
+		dev_err(component->dev, "Invalid FLL source %d\n", source);
 		return -EINVAL;
 	}
 
@@ -1809,36 +1808,36 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return ret;
 
 	/* Disable the FLL while we reconfigure */
-	snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
+	snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, 0);
 
-	snd_soc_update_bits(codec, base + 2,
+	snd_soc_component_update_bits(component, base + 2,
 			    WM5100_FLL1_OUTDIV_MASK | WM5100_FLL1_FRATIO_MASK,
 			    (factors.fll_outdiv << WM5100_FLL1_OUTDIV_SHIFT) |
 			    factors.fll_fratio);
-	snd_soc_update_bits(codec, base + 3, WM5100_FLL1_THETA_MASK,
+	snd_soc_component_update_bits(component, base + 3, WM5100_FLL1_THETA_MASK,
 			    factors.theta);
-	snd_soc_update_bits(codec, base + 5, WM5100_FLL1_N_MASK, factors.n);
-	snd_soc_update_bits(codec, base + 6,
+	snd_soc_component_update_bits(component, base + 5, WM5100_FLL1_N_MASK, factors.n);
+	snd_soc_component_update_bits(component, base + 6,
 			    WM5100_FLL1_REFCLK_DIV_MASK |
 			    WM5100_FLL1_REFCLK_SRC_MASK,
 			    (factors.fll_refclk_div
 			     << WM5100_FLL1_REFCLK_DIV_SHIFT) | source);
-	snd_soc_update_bits(codec, base + 7, WM5100_FLL1_LAMBDA_MASK,
+	snd_soc_component_update_bits(component, base + 7, WM5100_FLL1_LAMBDA_MASK,
 			    factors.lambda);
 
 	/* Clear any pending completions */
 	try_wait_for_completion(&fll->lock);
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
-	snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
+	snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
 
 	if (i2c->irq)
 		timeout = 2;
 	else
 		timeout = 50;
 
-	snd_soc_update_bits(codec, WM5100_CLOCKING_3, WM5100_SYSCLK_ENA,
+	snd_soc_component_update_bits(component, WM5100_CLOCKING_3, WM5100_SYSCLK_ENA,
 			    WM5100_SYSCLK_ENA);
 
 	/* Poll for the lock; will use interrupt when we can test */
@@ -1852,10 +1851,10 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			msleep(1);
 		}
 
-		ret = snd_soc_read(codec,
+		ret = snd_soc_component_read32(component,
 				   WM5100_INTERRUPT_RAW_STATUS_3);
 		if (ret < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to read FLL status: %d\n",
 				ret);
 			continue;
@@ -1864,8 +1863,8 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			break;
 	}
 	if (i == timeout) {
-		dev_err(codec->dev, "FLL%d lock timed out\n", fll_id);
-		pm_runtime_put(codec->dev);
+		dev_err(component->dev, "FLL%d lock timed out\n", fll_id);
+		pm_runtime_put(component->dev);
 		return -ETIMEDOUT;
 	}
 
@@ -1873,7 +1872,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	fll->fref = Fref;
 	fll->fout = Fout;
 
-	dev_dbg(codec->dev, "FLL%d running %dHz->%dHz\n", fll_id,
+	dev_dbg(component->dev, "FLL%d running %dHz->%dHz\n", fll_id,
 		Fref, Fout);
 
 	return 0;
@@ -2099,10 +2098,10 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)
 	}
 }
 
-int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+int wm5100_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	if (jack) {
 		wm5100->jack = jack;
@@ -2113,7 +2112,7 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 
 		/* Slowest detection rate, gives debounce for initial
 		 * detection */
-		snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
 				    WM5100_ACCDET_BIAS_STARTTIME_MASK |
 				    WM5100_ACCDET_RATE_MASK,
 				    (7 << WM5100_ACCDET_BIAS_STARTTIME_SHIFT) |
@@ -2132,18 +2131,18 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 		/* We start off just enabling microphone detection - even a
 		 * plain headphone will trigger detection.
 		 */
-		snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
 				    WM5100_ACCDET_ENA, WM5100_ACCDET_ENA);
 
-		snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
+		snd_soc_component_update_bits(component, WM5100_INTERRUPT_STATUS_3_MASK,
 				    WM5100_IM_ACCDET_EINT, 0);
 	} else {
-		snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
+		snd_soc_component_update_bits(component, WM5100_INTERRUPT_STATUS_3_MASK,
 				    WM5100_IM_HPDET_EINT |
 				    WM5100_IM_ACCDET_EINT,
 				    WM5100_IM_HPDET_EINT |
 				    WM5100_IM_ACCDET_EINT);
-		snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
 				    WM5100_ACCDET_ENA, 0);
 		wm5100->jack = NULL;
 	}
@@ -2330,22 +2329,22 @@ static void wm5100_free_gpio(struct i2c_client *i2c)
 }
 #endif
 
-static int wm5100_probe(struct snd_soc_codec *codec)
+static int wm5100_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 	int ret, i;
 
-	wm5100->codec = codec;
+	wm5100->component = component;
 
 	for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
-		snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
+		snd_soc_component_update_bits(component, wm5100_dig_vu[i], WM5100_OUT_VU,
 				    WM5100_OUT_VU);
 
 	/* Don't debounce interrupts to support use of SYSCLK only */
-	snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_1, 0);
-	snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_2, 0);
+	snd_soc_component_write(component, WM5100_IRQ_DEBOUNCE_1, 0);
+	snd_soc_component_write(component, WM5100_IRQ_DEBOUNCE_2, 0);
 
 	/* TODO: check if we're symmetric */
 
@@ -2370,34 +2369,30 @@ static int wm5100_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int wm5100_remove(struct snd_soc_codec *codec)
+static void wm5100_remove(struct snd_soc_component *component)
 {
-	struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
 
 	if (wm5100->pdata.hp_pol) {
 		gpio_free(wm5100->pdata.hp_pol);
 	}
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
-	.probe =	wm5100_probe,
-	.remove =	wm5100_remove,
-
-	.set_sysclk = wm5100_set_sysclk,
-	.set_pll = wm5100_set_fll,
-	.idle_bias_off = 1,
-
-	.seq_notifier = wm5100_seq_notifier,
-	.component_driver = {
-		.controls		= wm5100_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm5100_snd_controls),
-		.dapm_widgets		= wm5100_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm5100_dapm_widgets),
-		.dapm_routes		= wm5100_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm5100_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm5100 = {
+	.probe			= wm5100_probe,
+	.remove			= wm5100_remove,
+	.set_sysclk		= wm5100_set_sysclk,
+	.set_pll		= wm5100_set_fll,
+	.seq_notifier		= wm5100_seq_notifier,
+	.controls		= wm5100_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm5100_snd_controls),
+	.dapm_widgets		= wm5100_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm5100_dapm_widgets),
+	.dapm_routes		= wm5100_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm5100_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm5100_regmap = {
@@ -2614,8 +2609,8 @@ static int wm5100_i2c_probe(struct i2c_client *i2c,
 	pm_runtime_enable(&i2c->dev);
 	pm_request_idle(&i2c->dev);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm5100, wm5100_dai,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm5100, wm5100_dai,
 				     ARRAY_SIZE(wm5100_dai));
 	if (ret < 0) {
 		dev_err(&i2c->dev, "Failed to register WM5100: %d\n", ret);
@@ -2648,7 +2643,6 @@ static int wm5100_i2c_remove(struct i2c_client *i2c)
 {
 	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
 
-	snd_soc_unregister_codec(&i2c->dev);
 	if (i2c->irq)
 		free_irq(i2c->irq, wm5100);
 	wm5100_free_gpio(i2c);
diff --git a/sound/soc/codecs/wm5100.h b/sound/soc/codecs/wm5100.h
index 935a9b7fb274..6076493cfd67 100644
--- a/sound/soc/codecs/wm5100.h
+++ b/sound/soc/codecs/wm5100.h
@@ -17,7 +17,7 @@
 #include <sound/soc.h>
 #include <linux/regmap.h>
 
-int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+int wm5100_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
 
 #define WM5100_CLK_AIF1     1
 #define WM5100_CLK_AIF2     2
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index fc066caa1918..24f19cfc98f5 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -34,6 +34,8 @@
 #include "wm5102.h"
 #include "wm_adsp.h"
 
+#define DRV_NAME "wm5102-codec"
+
 struct wm5102_priv {
 	struct arizona_priv core;
 	struct arizona_fll fll[2];
@@ -581,8 +583,8 @@ static const struct reg_default wm5102_sysclk_revb_patch[] = {
 static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	struct regmap *regmap = arizona->regmap;
 	const struct reg_default *patch = NULL;
 	int i, patch_size;
@@ -620,8 +622,8 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
 static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	unsigned int v = 0;
 	int ret;
 
@@ -629,7 +631,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_PRE_PMU:
 		ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to read SYSCLK state: %d\n", ret);
 			return -EIO;
 		}
@@ -637,9 +639,9 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
 		v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
 
 		if (v >= 3) {
-			ret = arizona_dvfs_up(codec, ARIZONA_DVFS_ADSP1_RQ);
+			ret = arizona_dvfs_up(component, ARIZONA_DVFS_ADSP1_RQ);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to raise DVFS: %d\n", ret);
 				return ret;
 			}
@@ -647,9 +649,9 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		ret = arizona_dvfs_down(codec, ARIZONA_DVFS_ADSP1_RQ);
+		ret = arizona_dvfs_down(component, ARIZONA_DVFS_ADSP1_RQ);
 		if (ret)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				 "Failed to lower DVFS: %d\n", ret);
 		break;
 
@@ -663,8 +665,8 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
 static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 
 	mutex_lock(&arizona->dac_comp_lock);
 	put_unaligned_be16(arizona->dac_comp_coeff,
@@ -677,8 +679,8 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
 static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 
 	mutex_lock(&arizona->dac_comp_lock);
 	memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
@@ -692,8 +694,8 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
 static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 
 	mutex_lock(&arizona->dac_comp_lock);
 	ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
@@ -705,8 +707,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
 static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 
 	mutex_lock(&arizona->dac_comp_lock);
 	arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
@@ -1734,10 +1736,10 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
 	{ "DRC1 Signal Activity", NULL, "DRC1R" },
 };
 
-static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm5102_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
+	struct wm5102_priv *wm5102 = snd_soc_component_get_drvdata(component);
 
 	switch (fll_id) {
 	case WM5102_FLL1:
@@ -1910,7 +1912,8 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
 static int wm5102_open(struct snd_compr_stream *stream)
 {
 	struct snd_soc_pcm_runtime *rtd = stream->private_data;
-	struct wm5102_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
 
 	return wm_adsp_compr_open(&priv->core.adsp[0], stream);
 }
@@ -1930,30 +1933,29 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int wm5102_codec_probe(struct snd_soc_codec *codec)
+static int wm5102_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->core.arizona;
 	int ret;
 
-	snd_soc_codec_init_regmap(codec, arizona->regmap);
+	snd_soc_component_init_regmap(component, arizona->regmap);
 
-	ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
+	ret = wm_adsp2_component_probe(&priv->core.adsp[0], component);
 	if (ret)
 		return ret;
 
-	ret = snd_soc_add_codec_controls(codec,
+	ret = snd_soc_add_component_controls(component,
 					 arizona_adsp2_rate_controls, 1);
 	if (ret)
 		goto err_adsp2_codec_probe;
 
-	ret = arizona_init_spk(codec);
+	ret = arizona_init_spk(component);
 	if (ret < 0)
 		return ret;
 
-	arizona_init_gpio(codec);
+	arizona_init_gpio(component);
 
 	snd_soc_component_disable_pin(component, "HAPTICS");
 
@@ -1962,20 +1964,18 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 
 err_adsp2_codec_probe:
-	wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
+	wm_adsp2_component_remove(&priv->core.adsp[0], component);
 
 	return ret;
 }
 
-static int wm5102_codec_remove(struct snd_soc_codec *codec)
+static void wm5102_component_remove(struct snd_soc_component *component)
 {
-	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
 
-	wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
+	wm_adsp2_component_remove(&priv->core.adsp[0], component);
 
 	priv->core.arizona->dapm = NULL;
-
-	return 0;
 }
 
 #define WM5102_DIG_VU 0x0200
@@ -1992,37 +1992,32 @@ static unsigned int wm5102_digital_vu[] = {
 	ARIZONA_DAC_DIGITAL_VOLUME_5R,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
-	.probe = wm5102_codec_probe,
-	.remove = wm5102_codec_remove,
-
-	.idle_bias_off = true,
-
-	.set_sysclk = arizona_set_sysclk,
-	.set_pll = wm5102_set_fll,
-
-	.component_driver = {
-		.controls		= wm5102_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm5102_snd_controls),
-		.dapm_widgets		= wm5102_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm5102_dapm_widgets),
-		.dapm_routes		= wm5102_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm5102_dapm_routes),
-	},
-};
-
-static const struct snd_compr_ops wm5102_compr_ops = {
-	.open = wm5102_open,
-	.free = wm_adsp_compr_free,
-	.set_params = wm_adsp_compr_set_params,
-	.get_caps = wm_adsp_compr_get_caps,
-	.trigger = wm_adsp_compr_trigger,
-	.pointer = wm_adsp_compr_pointer,
-	.copy = wm_adsp_compr_copy,
+static struct snd_compr_ops wm5102_compr_ops = {
+	.open		= wm5102_open,
+	.free		= wm_adsp_compr_free,
+	.set_params	= wm_adsp_compr_set_params,
+	.get_caps	= wm_adsp_compr_get_caps,
+	.trigger	= wm_adsp_compr_trigger,
+	.pointer	= wm_adsp_compr_pointer,
+	.copy		= wm_adsp_compr_copy,
 };
 
-static const struct snd_soc_platform_driver wm5102_compr_platform = {
-	.compr_ops = &wm5102_compr_ops,
+static const struct snd_soc_component_driver soc_component_dev_wm5102 = {
+	.probe			= wm5102_component_probe,
+	.remove			= wm5102_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm5102_set_fll,
+	.name			= DRV_NAME,
+	.compr_ops		= &wm5102_compr_ops,
+	.controls		= wm5102_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm5102_snd_controls),
+	.dapm_widgets		= wm5102_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm5102_dapm_widgets),
+	.dapm_routes		= wm5102_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm5102_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm5102_probe(struct platform_device *pdev)
@@ -2109,23 +2104,16 @@ static int wm5102_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_dsp_irq;
 
-	ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
-		goto err_spk_irqs;
-	}
-
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_wm5102,
 				      wm5102_dai, ARRAY_SIZE(wm5102_dai));
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
-		goto err_platform;
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
 	}
 
 	return ret;
 
-err_platform:
-	snd_soc_unregister_platform(&pdev->dev);
 err_spk_irqs:
 	arizona_free_spk_irqs(arizona);
 err_dsp_irq:
@@ -2139,8 +2127,6 @@ static int wm5102_remove(struct platform_device *pdev)
 	struct wm5102_priv *wm5102 = platform_get_drvdata(pdev);
 	struct arizona *arizona = wm5102->core.arizona;
 
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	wm_adsp2_remove(&wm5102->core.adsp[0]);
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index fb0cf9c61f48..b33cbd0161d3 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -35,6 +35,8 @@
 
 #define WM5110_NUM_ADSP 4
 
+#define DRV_NAME "wm5110-codec"
+
 struct wm5110_priv {
 	struct arizona_priv core;
 	struct arizona_fll fll[2];
@@ -159,8 +161,8 @@ static const struct reg_default wm5110_sysclk_reve_patch[] = {
 static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	struct regmap *regmap = arizona->regmap;
 	const struct reg_default *patch = NULL;
 	int i, patch_size;
@@ -196,14 +198,14 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
 static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
 				struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	unsigned int v;
 	int ret;
 
 	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret);
+		dev_err(component->dev, "Failed to read SYSCLK state: %d\n", ret);
 		return ret;
 	}
 
@@ -286,10 +288,10 @@ static const struct reg_sequence wm5110_dre_right_enable[] = {
 
 static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
-	unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
+	unsigned int val = snd_soc_component_read32(component, ARIZONA_DRE_ENABLE);
 	const struct reg_sequence *wseq;
 	int nregs;
 
@@ -323,25 +325,25 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
 
 static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
-	unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int val = snd_soc_component_read32(component, ARIZONA_DRE_ENABLE);
 
 	switch (w->shift) {
 	case ARIZONA_OUT1L_ENA_SHIFT:
 		if (!(val & ARIZONA_DRE1L_ENA_MASK)) {
-			snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+			snd_soc_component_update_bits(component, ARIZONA_SPARE_TRIGGERS,
 					    ARIZONA_WS_TRG1, ARIZONA_WS_TRG1);
-			snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+			snd_soc_component_update_bits(component, ARIZONA_SPARE_TRIGGERS,
 					    ARIZONA_WS_TRG1, 0);
 			priv->out_down_delay += 27;
 		}
 		break;
 	case ARIZONA_OUT1R_ENA_SHIFT:
 		if (!(val & ARIZONA_DRE1R_ENA_MASK)) {
-			snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+			snd_soc_component_update_bits(component, ARIZONA_SPARE_TRIGGERS,
 					    ARIZONA_WS_TRG2, ARIZONA_WS_TRG2);
-			snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS,
+			snd_soc_component_update_bits(component, ARIZONA_SPARE_TRIGGERS,
 					    ARIZONA_WS_TRG2, 0);
 			priv->out_down_delay += 27;
 		}
@@ -356,8 +358,8 @@ static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
 static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 
 	switch (priv->arizona->rev) {
 	case 0 ... 3:
@@ -395,9 +397,9 @@ static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
 static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int ena, dre;
@@ -456,8 +458,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
 static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int ret;
 
 	/*
@@ -476,8 +478,8 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
 static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int ret;
 
 	/*
@@ -496,9 +498,9 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
 static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
 			       struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
-	struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct wm5110_priv *wm5110 = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 	unsigned int reg, mask;
 	struct reg_sequence analog_seq[] = {
@@ -517,9 +519,9 @@ static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
 		wm5110->in_post_pending++;
 		return 0;
 	case SND_SOC_DAPM_PRE_PMU:
-		wm5110->in_pga_cache[w->shift] = snd_soc_read(codec, reg);
+		wm5110->in_pga_cache[w->shift] = snd_soc_component_read32(component, reg);
 
-		snd_soc_update_bits(codec, reg, mask,
+		snd_soc_component_update_bits(component, reg, mask,
 				    0x40 << ARIZONA_IN1L_PGA_VOL_SHIFT);
 
 		wm5110->in_pre_pending--;
@@ -536,7 +538,7 @@ static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
 
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, reg, mask,
+		snd_soc_component_update_bits(component, reg, mask,
 				    wm5110->in_pga_cache[w->shift]);
 
 		wm5110->in_post_pending--;
@@ -555,13 +557,13 @@ static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
 static int wm5110_in_ev(struct snd_soc_dapm_widget *w,
 			struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->arizona;
 
 	switch (arizona->rev) {
 	case 0 ... 4:
-		if (arizona_input_analog(codec, w->shift))
+		if (arizona_input_analog(component, w->shift))
 			wm5110_in_analog_ev(w, kcontrol, event);
 
 		break;
@@ -2032,10 +2034,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	{ "DSP3 Voice Trigger", "Switch", "DSP3" },
 };
 
-static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm5110_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec);
+	struct wm5110_priv *wm5110 = snd_soc_component_get_drvdata(component);
 
 	switch (fll_id) {
 	case WM5110_FLL1:
@@ -2229,7 +2231,8 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 static int wm5110_open(struct snd_compr_stream *stream)
 {
 	struct snd_soc_pcm_runtime *rtd = stream->private_data;
-	struct wm5110_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->core.arizona;
 	int n_adsp;
 
@@ -2275,31 +2278,30 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int wm5110_codec_probe(struct snd_soc_codec *codec)
+static int wm5110_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->core.arizona;
 	int i, ret;
 
 	arizona->dapm = dapm;
-	snd_soc_codec_init_regmap(codec, arizona->regmap);
+	snd_soc_component_init_regmap(component, arizona->regmap);
 
-	ret = arizona_init_spk(codec);
+	ret = arizona_init_spk(component);
 	if (ret < 0)
 		return ret;
 
-	arizona_init_gpio(codec);
-	arizona_init_mono(codec);
+	arizona_init_gpio(component);
+	arizona_init_mono(component);
 
 	for (i = 0; i < WM5110_NUM_ADSP; ++i) {
-		ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
+		ret = wm_adsp2_component_probe(&priv->core.adsp[i], component);
 		if (ret)
 			goto err_adsp2_codec_probe;
 	}
 
-	ret = snd_soc_add_codec_controls(codec,
+	ret = snd_soc_add_component_controls(component,
 					 arizona_adsp2_rate_controls,
 					 WM5110_NUM_ADSP);
 	if (ret)
@@ -2311,22 +2313,20 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
 
 err_adsp2_codec_probe:
 	for (--i; i >= 0; --i)
-		wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
+		wm_adsp2_component_remove(&priv->core.adsp[i], component);
 
 	return ret;
 }
 
-static int wm5110_codec_remove(struct snd_soc_codec *codec)
+static void wm5110_component_remove(struct snd_soc_component *component)
 {
-	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < WM5110_NUM_ADSP; ++i)
-		wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
+		wm_adsp2_component_remove(&priv->core.adsp[i], component);
 
 	priv->core.arizona->dapm = NULL;
-
-	return 0;
 }
 
 #define WM5110_DIG_VU 0x0200
@@ -2346,37 +2346,32 @@ static unsigned int wm5110_digital_vu[] = {
 	ARIZONA_DAC_DIGITAL_VOLUME_6R,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
-	.probe = wm5110_codec_probe,
-	.remove = wm5110_codec_remove,
-
-	.idle_bias_off = true,
-
-	.set_sysclk = arizona_set_sysclk,
-	.set_pll = wm5110_set_fll,
-
-	.component_driver = {
-		.controls		= wm5110_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm5110_snd_controls),
-		.dapm_widgets		= wm5110_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm5110_dapm_widgets),
-		.dapm_routes		= wm5110_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm5110_dapm_routes),
-	},
-};
-
-static const struct snd_compr_ops wm5110_compr_ops = {
-	.open = wm5110_open,
-	.free = wm_adsp_compr_free,
-	.set_params = wm_adsp_compr_set_params,
-	.get_caps = wm_adsp_compr_get_caps,
-	.trigger = wm_adsp_compr_trigger,
-	.pointer = wm_adsp_compr_pointer,
-	.copy = wm_adsp_compr_copy,
+static struct snd_compr_ops wm5110_compr_ops = {
+	.open		= wm5110_open,
+	.free		= wm_adsp_compr_free,
+	.set_params	= wm_adsp_compr_set_params,
+	.get_caps	= wm_adsp_compr_get_caps,
+	.trigger	= wm_adsp_compr_trigger,
+	.pointer	= wm_adsp_compr_pointer,
+	.copy		= wm_adsp_compr_copy,
 };
 
-static const struct snd_soc_platform_driver wm5110_compr_platform = {
-	.compr_ops = &wm5110_compr_ops,
+static const struct snd_soc_component_driver soc_component_dev_wm5110 = {
+	.probe			= wm5110_component_probe,
+	.remove			= wm5110_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm5110_set_fll,
+	.name			= DRV_NAME,
+	.compr_ops		= &wm5110_compr_ops,
+	.controls		= wm5110_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm5110_snd_controls),
+	.dapm_widgets		= wm5110_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm5110_dapm_widgets),
+	.dapm_routes		= wm5110_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm5110_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm5110_probe(struct platform_device *pdev)
@@ -2464,23 +2459,16 @@ static int wm5110_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_dsp_irq;
 
-	ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
-		goto err_spk_irqs;
-	}
-
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_wm5110,
 				      wm5110_dai, ARRAY_SIZE(wm5110_dai));
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
-		goto err_platform;
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
 	}
 
 	return ret;
 
-err_platform:
-	snd_soc_unregister_platform(&pdev->dev);
 err_spk_irqs:
 	arizona_free_spk_irqs(arizona);
 err_dsp_irq:
@@ -2495,8 +2483,6 @@ static int wm5110_remove(struct platform_device *pdev)
 	struct arizona *arizona = wm5110->core.arizona;
 	int i;
 
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	for (i = 0; i < WM5110_NUM_ADSP; i++)
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index fc79c6725d06..e92ebe52d485 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -256,8 +256,8 @@ static void wm8350_pga_work(struct work_struct *work)
 static int pga_event(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
 	struct wm8350_output *out;
 
 	switch (w->shift) {
@@ -299,8 +299,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
 static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
 	struct wm8350_output *out = NULL;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
@@ -334,16 +334,16 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
 		return ret;
 
 	/* now hit the volume update bits (always bit 8) */
-	val = snd_soc_read(codec, reg);
-	snd_soc_write(codec, reg, val | WM8350_OUT1_VU);
+	val = snd_soc_component_read32(component, reg);
+	snd_soc_component_write(component, reg, val | WM8350_OUT1_VU);
 	return 1;
 }
 
 static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
 	struct wm8350_output *out1 = &wm8350_priv->out1;
 	struct wm8350_output *out2 = &wm8350_priv->out2;
 	struct soc_mixer_control *mc =
@@ -753,8 +753,8 @@ static const struct snd_soc_dapm_route wm8350_dapm_routes[] = {
 static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
 	struct wm8350 *wm8350 = wm8350_data->wm8350;
 	u16 fll_4;
 
@@ -769,9 +769,9 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	case WM8350_MCLK_SEL_PLL_32K:
 		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
 				WM8350_MCLK_SEL);
-		fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
+		fll_4 = snd_soc_component_read32(component, WM8350_FLL_CONTROL_4) &
 		    ~WM8350_FLL_CLK_SRC_MASK;
-		snd_soc_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
+		snd_soc_component_write(component, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
 		break;
 	}
 
@@ -788,44 +788,44 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 
 static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 val;
 
 	switch (div_id) {
 	case WM8350_ADC_CLKDIV:
-		val = snd_soc_read(codec, WM8350_ADC_DIVIDER) &
+		val = snd_soc_component_read32(component, WM8350_ADC_DIVIDER) &
 		    ~WM8350_ADC_CLKDIV_MASK;
-		snd_soc_write(codec, WM8350_ADC_DIVIDER, val | div);
+		snd_soc_component_write(component, WM8350_ADC_DIVIDER, val | div);
 		break;
 	case WM8350_DAC_CLKDIV:
-		val = snd_soc_read(codec, WM8350_DAC_CLOCK_CONTROL) &
+		val = snd_soc_component_read32(component, WM8350_DAC_CLOCK_CONTROL) &
 		    ~WM8350_DAC_CLKDIV_MASK;
-		snd_soc_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
+		snd_soc_component_write(component, WM8350_DAC_CLOCK_CONTROL, val | div);
 		break;
 	case WM8350_BCLK_CLKDIV:
-		val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
+		val = snd_soc_component_read32(component, WM8350_CLOCK_CONTROL_1) &
 		    ~WM8350_BCLK_DIV_MASK;
-		snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
 		break;
 	case WM8350_OPCLK_CLKDIV:
-		val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
+		val = snd_soc_component_read32(component, WM8350_CLOCK_CONTROL_1) &
 		    ~WM8350_OPCLK_DIV_MASK;
-		snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
 		break;
 	case WM8350_SYS_CLKDIV:
-		val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
+		val = snd_soc_component_read32(component, WM8350_CLOCK_CONTROL_1) &
 		    ~WM8350_MCLK_DIV_MASK;
-		snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
 		break;
 	case WM8350_DACLR_CLKDIV:
-		val = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
+		val = snd_soc_component_read32(component, WM8350_DAC_LR_RATE) &
 		    ~WM8350_DACLRC_RATE_MASK;
-		snd_soc_write(codec, WM8350_DAC_LR_RATE, val | div);
+		snd_soc_component_write(component, WM8350_DAC_LR_RATE, val | div);
 		break;
 	case WM8350_ADCLR_CLKDIV:
-		val = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
+		val = snd_soc_component_read32(component, WM8350_ADC_LR_RATE) &
 		    ~WM8350_ADCLRC_RATE_MASK;
-		snd_soc_write(codec, WM8350_ADC_LR_RATE, val | div);
+		snd_soc_component_write(component, WM8350_ADC_LR_RATE, val | div);
 		break;
 	default:
 		return -EINVAL;
@@ -836,14 +836,14 @@ static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
 
 static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8350_AI_FORMATING) &
 	    ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
-	u16 master = snd_soc_read(codec, WM8350_AI_DAC_CONTROL) &
+	u16 master = snd_soc_component_read32(component, WM8350_AI_DAC_CONTROL) &
 	    ~WM8350_BCLK_MSTR;
-	u16 dac_lrc = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
+	u16 dac_lrc = snd_soc_component_read32(component, WM8350_DAC_LR_RATE) &
 	    ~WM8350_DACLRC_ENA;
-	u16 adc_lrc = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
+	u16 adc_lrc = snd_soc_component_read32(component, WM8350_ADC_LR_RATE) &
 	    ~WM8350_ADCLRC_ENA;
 
 	/* set master/slave audio interface */
@@ -896,10 +896,10 @@ static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8350_AI_FORMATING, iface);
-	snd_soc_write(codec, WM8350_AI_DAC_CONTROL, master);
-	snd_soc_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
-	snd_soc_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
+	snd_soc_component_write(component, WM8350_AI_FORMATING, iface);
+	snd_soc_component_write(component, WM8350_AI_DAC_CONTROL, master);
+	snd_soc_component_write(component, WM8350_DAC_LR_RATE, dac_lrc);
+	snd_soc_component_write(component, WM8350_ADC_LR_RATE, adc_lrc);
 	return 0;
 }
 
@@ -907,10 +907,10 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *codec_dai)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
 	struct wm8350 *wm8350 = wm8350_data->wm8350;
-	u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
+	u16 iface = snd_soc_component_read32(component, WM8350_AI_FORMATING) &
 	    ~WM8350_AIF_WL_MASK;
 
 	/* bit size */
@@ -928,7 +928,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8350_AI_FORMATING, iface);
+	snd_soc_component_write(component, WM8350_AI_FORMATING, iface);
 
 	/* The sloping stopband filter is recommended for use with
 	 * lower sample rates to improve performance.
@@ -947,7 +947,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8350_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int val;
 
 	if (mute)
@@ -955,7 +955,7 @@ static int wm8350_mute(struct snd_soc_dai *dai, int mute)
 	else
 		val = 0;
 
-	snd_soc_update_bits(codec, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
+	snd_soc_component_update_bits(component, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
 
 	return 0;
 }
@@ -1024,8 +1024,8 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
 			  int pll_id, int source, unsigned int freq_in,
 			  unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
 	struct wm8350 *wm8350 = priv->wm8350;
 	struct _fll_div fll_div;
 	int ret = 0;
@@ -1050,17 +1050,17 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
 		fll_div.ratio);
 
 	/* set up N.K & dividers */
-	fll_1 = snd_soc_read(codec, WM8350_FLL_CONTROL_1) &
+	fll_1 = snd_soc_component_read32(component, WM8350_FLL_CONTROL_1) &
 	    ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
-	snd_soc_write(codec, WM8350_FLL_CONTROL_1,
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_1,
 			   fll_1 | (fll_div.div << 8) | 0x50);
-	snd_soc_write(codec, WM8350_FLL_CONTROL_2,
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_2,
 			   (fll_div.ratio << 11) | (fll_div.
 						    n & WM8350_FLL_N_MASK));
-	snd_soc_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
-	fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_3, fll_div.k);
+	fll_4 = snd_soc_component_read32(component, WM8350_FLL_CONTROL_4) &
 	    ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
-	snd_soc_write(codec, WM8350_FLL_CONTROL_4,
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_4,
 			   fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
 			   (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
 
@@ -1074,10 +1074,10 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int wm8350_set_bias_level(struct snd_soc_codec *codec,
+static int wm8350_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
 	struct wm8350 *wm8350 = priv->wm8350;
 	struct wm8350_audio_platform_data *platform =
 		wm8350->codec.platform_data;
@@ -1101,7 +1101,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
 						    priv->supplies);
 			if (ret != 0)
@@ -1310,7 +1310,7 @@ static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
 /**
  * wm8350_hp_jack_detect - Enable headphone jack detection.
  *
- * @codec:  WM8350 codec
+ * @component:  WM8350 component
  * @which:  left or right jack detect signal
  * @jack:   jack to report detection events on
  * @report: value to report
@@ -1318,10 +1318,10 @@ static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
  * Enables the headphone jack detection of the WM8350.  If no report
  * is specified then detection is disabled.
  */
-int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
+int wm8350_hp_jack_detect(struct snd_soc_component *component, enum wm8350_jack which,
 			  struct snd_soc_jack *jack, int report)
 {
-	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
 	struct wm8350 *wm8350 = priv->wm8350;
 	int ena;
 
@@ -1389,7 +1389,7 @@ static irqreturn_t wm8350_mic_handler(int irq, void *data)
 /**
  * wm8350_mic_jack_detect - Enable microphone jack detection.
  *
- * @codec:         WM8350 codec
+ * @component:         WM8350 component
  * @jack:          jack to report detection events on
  * @detect_report: value to report when presence detected
  * @short_report:  value to report when microphone short detected
@@ -1397,11 +1397,11 @@ static irqreturn_t wm8350_mic_handler(int irq, void *data)
  * Enables the microphone jack detection of the WM8350.  If both reports
  * are specified as zero then detection is disabled.
  */
-int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
+int wm8350_mic_jack_detect(struct snd_soc_component *component,
 			   struct snd_soc_jack *jack,
 			   int detect_report, int short_report)
 {
-	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
 	struct wm8350 *wm8350 = priv->wm8350;
 
 	priv->mic.jack = jack;
@@ -1455,26 +1455,26 @@ static struct snd_soc_dai_driver wm8350_dai = {
 	.ops = &wm8350_dai_ops,
 };
 
-static  int wm8350_codec_probe(struct snd_soc_codec *codec)
+static  int wm8350_component_probe(struct snd_soc_component *component)
 {
-	struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
+	struct wm8350 *wm8350 = dev_get_platdata(component->dev);
 	struct wm8350_data *priv;
 	struct wm8350_output *out1;
 	struct wm8350_output *out2;
 	int ret, i;
 
 	if (wm8350->codec.platform_data == NULL) {
-		dev_err(codec->dev, "No audio platform data supplied\n");
+		dev_err(component->dev, "No audio platform data supplied\n");
 		return -EINVAL;
 	}
 
-	priv = devm_kzalloc(codec->dev, sizeof(struct wm8350_data),
+	priv = devm_kzalloc(component->dev, sizeof(struct wm8350_data),
 			    GFP_KERNEL);
 	if (priv == NULL)
 		return -ENOMEM;
 
-	snd_soc_codec_init_regmap(codec, wm8350->regmap);
-	snd_soc_codec_set_drvdata(codec, priv);
+	snd_soc_component_init_regmap(component, wm8350->regmap);
+	snd_soc_component_set_drvdata(component, priv);
 
 	priv->wm8350 = wm8350;
 
@@ -1497,9 +1497,9 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
 	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
 	/* Enable robust clocking mode in ADC */
-	snd_soc_write(codec, WM8350_SECURITY, 0xa7);
-	snd_soc_write(codec, 0xde, 0x13);
-	snd_soc_write(codec, WM8350_SECURITY, 0);
+	snd_soc_component_write(component, WM8350_SECURITY, 0xa7);
+	snd_soc_component_write(component, 0xde, 0x13);
+	snd_soc_component_write(component, WM8350_SECURITY, 0);
 
 	/* read OUT1 & OUT2 volumes */
 	out1 = &priv->out1;
@@ -1552,10 +1552,10 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int  wm8350_codec_remove(struct snd_soc_codec *codec)
+static void wm8350_component_remove(struct snd_soc_component *component)
 {
-	struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-	struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = dev_get_platdata(component->dev);
 
 	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
 			  WM8350_JDL_ENA | WM8350_JDR_ENA);
@@ -1578,44 +1578,37 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)
 	flush_delayed_work(&priv->pga_work);
 
 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
-	.probe =	wm8350_codec_probe,
-	.remove =	wm8350_codec_remove,
-	.set_bias_level = wm8350_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8350_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8350_snd_controls),
-		.dapm_widgets		= wm8350_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8350_dapm_widgets),
-		.dapm_routes		= wm8350_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8350_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
+	.probe			= wm8350_component_probe,
+	.remove			= wm8350_component_remove,
+	.set_bias_level		= wm8350_set_bias_level,
+	.controls		= wm8350_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8350_snd_controls),
+	.dapm_widgets		= wm8350_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8350_dapm_widgets),
+	.dapm_routes		= wm8350_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8350_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8350_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8350,
 			&wm8350_dai, 1);
 }
 
-static int wm8350_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static struct platform_driver wm8350_codec_driver = {
 	.driver = {
 		   .name = "wm8350-codec",
 		   },
 	.probe = wm8350_probe,
-	.remove = wm8350_remove,
 };
 
 module_platform_driver(wm8350_codec_driver);
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
index 74108eb82938..1191326c4a61 100644
--- a/sound/soc/codecs/wm8350.h
+++ b/sound/soc/codecs/wm8350.h
@@ -20,9 +20,9 @@ enum wm8350_jack {
 	WM8350_JDR = 2,
 };
 
-int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
+int wm8350_hp_jack_detect(struct snd_soc_component *component, enum wm8350_jack which,
 			  struct snd_soc_jack *jack, int report);
-int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
+int wm8350_mic_jack_detect(struct snd_soc_component *component,
 			   struct snd_soc_jack *jack,
 			   int detect_report, int short_report);
 
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index a36adf881bca..c237365d1184 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -65,9 +65,9 @@ struct wm8400_priv {
 	int fll_in, fll_out;
 };
 
-static void wm8400_codec_reset(struct snd_soc_codec *codec)
+static void wm8400_component_reset(struct snd_soc_component *component)
 {
-	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
 
 	wm8400_reset_codec_reg_cache(wm8400->wm8400);
 }
@@ -91,7 +91,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
         struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	int reg = mc->reg;
@@ -103,8 +103,8 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
                 return ret;
 
         /* now hit the volume update bits (always bit 8) */
-        val = snd_soc_read(codec, reg);
-        return snd_soc_write(codec, reg, val | 0x0100);
+        val = snd_soc_component_read32(component, reg);
+        return snd_soc_component_write(component, reg, val | 0x0100);
 }
 
 #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
@@ -324,7 +324,7 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_event (struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol * kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	u32 reg_shift = mc->shift;
@@ -333,7 +333,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 
 	switch (reg_shift) {
 	case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-		reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER1);
+		reg = snd_soc_component_read32(component, WM8400_OUTPUT_MIXER1);
 		if (reg & WM8400_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -341,7 +341,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-		reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER2);
+		reg = snd_soc_component_read32(component, WM8400_OUTPUT_MIXER2);
 		if (reg & WM8400_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -349,7 +349,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-		reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_component_read32(component, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -357,7 +357,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-		reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
+		reg = snd_soc_component_read32(component, WM8400_SPEAKER_MIXER);
 		if (reg & WM8400_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");
@@ -849,8 +849,8 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
 static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
 
 	wm8400->sysclk = freq;
 	return 0;
@@ -938,8 +938,8 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 			      int source, unsigned int freq_in,
 			      unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
 	struct fll_factors factors;
 	int ret;
 	u16 reg;
@@ -962,13 +962,13 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	wm8400->fll_in = freq_in;
 
 	/* We *must* disable the FLL before any changes */
-	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_2);
+	reg = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_2);
 	reg &= ~WM8400_FLL_ENA;
-	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+	snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_2, reg);
 
-	reg = snd_soc_read(codec, WM8400_FLL_CONTROL_1);
+	reg = snd_soc_component_read32(component, WM8400_FLL_CONTROL_1);
 	reg &= ~WM8400_FLL_OSC_ENA;
-	snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_1, reg);
 
 	if (!freq_out)
 		return 0;
@@ -976,15 +976,15 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
 	reg |= WM8400_FLL_FRAC | factors.fratio;
 	reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
-	snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_1, reg);
 
-	snd_soc_write(codec, WM8400_FLL_CONTROL_2, factors.k);
-	snd_soc_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_2, factors.k);
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_3, factors.n);
 
-	reg = snd_soc_read(codec, WM8400_FLL_CONTROL_4);
+	reg = snd_soc_component_read32(component, WM8400_FLL_CONTROL_4);
 	reg &= ~WM8400_FLL_OUTDIV_MASK;
 	reg |= factors.outdiv;
-	snd_soc_write(codec, WM8400_FLL_CONTROL_4, reg);
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_4, reg);
 
 	return 0;
 }
@@ -995,11 +995,11 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 audio1, audio3;
 
-	audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
-	audio3 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_3);
+	audio1 = snd_soc_component_read32(component, WM8400_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_component_read32(component, WM8400_AUDIO_INTERFACE_3);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1040,37 +1040,37 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
-	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+	snd_soc_component_write(component, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8400_AUDIO_INTERFACE_3, audio3);
 	return 0;
 }
 
 static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8400_MCLK_DIV:
-		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_2) &
 			~WM8400_MCLK_DIV_MASK;
-		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_component_write(component, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_DACCLK_DIV:
-		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_2) &
 			~WM8400_DAC_CLKDIV_MASK;
-		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_component_write(component, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_ADCCLK_DIV:
-		reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_2) &
 			~WM8400_ADC_CLKDIV_MASK;
-		snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
+		snd_soc_component_write(component, WM8400_CLOCKING_2, reg | div);
 		break;
 	case WM8400_BCLK_DIV:
-		reg = snd_soc_read(codec, WM8400_CLOCKING_1) &
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_1) &
 			~WM8400_BCLK_DIV_MASK;
-		snd_soc_write(codec, WM8400_CLOCKING_1, reg | div);
+		snd_soc_component_write(component, WM8400_CLOCKING_1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1086,8 +1086,8 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
+	struct snd_soc_component *component = dai->component;
+	u16 audio1 = snd_soc_component_read32(component, WM8400_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8400_AIF_WL_MASK;
 	/* bit size */
@@ -1105,28 +1105,28 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8400_AUDIO_INTERFACE_1, audio1);
 	return 0;
 }
 
 static int wm8400_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 val = snd_soc_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+	struct snd_soc_component *component = dai->component;
+	u16 val = snd_soc_component_read32(component, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
 
 	if (mute)
-		snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+		snd_soc_component_write(component, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 	else
-		snd_soc_write(codec, WM8400_DAC_CTRL, val);
+		snd_soc_component_write(component, WM8400_DAC_CTRL, val);
 
 	return 0;
 }
 
 /* TODO: set bias for best performance at standby */
-static int wm8400_set_bias_level(struct snd_soc_codec *codec,
+static int wm8400_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
 	u16 val;
 	int ret;
 
@@ -1136,13 +1136,13 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*50k */
-		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
+		val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1) &
 			~WM8400_VMID_MODE_MASK;
-		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val | 0x2);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(power),
 						    &power[0]);
 			if (ret != 0) {
@@ -1152,74 +1152,74 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
 				return ret;
 			}
 
-			snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
+			snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1,
 				     WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
 
 			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+			snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
 				     WM8400_BUFDCOPEN | WM8400_POBCTRL);
 
 			msleep(50);
 
 			/* Enable VREF & VMID at 2x50k */
-			val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+			val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
 			val |= 0x2 | WM8400_VREF_ENA;
-			snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+			snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
 
 			/* Enable BUFIOEN */
-			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+			snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
 				     WM8400_BUFDCOPEN | WM8400_POBCTRL |
 				     WM8400_BUFIOEN);
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-			snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+			snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_BUFIOEN);
 		}
 
 		/* VMID=2*300k */
-		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
+		val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1) &
 			~WM8400_VMID_MODE_MASK;
-		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val | 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable POBCTRL and SOFT_ST */
-		snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+		snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
 			WM8400_POBCTRL | WM8400_BUFIOEN);
 
 		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-		snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+		snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
 			WM8400_BUFDCOPEN | WM8400_POBCTRL |
 			WM8400_BUFIOEN);
 
 		/* mute DAC */
-		val = snd_soc_read(codec, WM8400_DAC_CTRL);
-		snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+		val = snd_soc_component_read32(component, WM8400_DAC_CTRL);
+		snd_soc_component_write(component, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
 
 		/* Enable any disabled outputs */
-		val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+		val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
 		val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
 			WM8400_OUT4_ENA | WM8400_LOUT_ENA |
 			WM8400_ROUT_ENA;
-		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
 
 		/* Disable VMID */
 		val &= ~WM8400_VMID_MODE_MASK;
-		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
 
 		msleep(300);
 
 		/* Enable all output discharge bits */
-		snd_soc_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+		snd_soc_component_write(component, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
 			WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
 			WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
 			WM8400_DIS_ROUT);
 
 		/* Disable VREF */
 		val &= ~WM8400_VREF_ENA;
-		snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-		snd_soc_write(codec, WM8400_ANTIPOP2, 0x0);
+		snd_soc_component_write(component, WM8400_ANTIPOP2, 0x0);
 
 		ret = regulator_bulk_disable(ARRAY_SIZE(power),
 					     &power[0]);
@@ -1273,93 +1273,86 @@ static struct snd_soc_dai_driver wm8400_dai = {
 	.ops = &wm8400_dai_ops,
 };
 
-static int wm8400_codec_probe(struct snd_soc_codec *codec)
+static int wm8400_component_probe(struct snd_soc_component *component)
 {
-	struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
+	struct wm8400 *wm8400 = dev_get_platdata(component->dev);
 	struct wm8400_priv *priv;
 	int ret;
 	u16 reg;
 
-	priv = devm_kzalloc(codec->dev, sizeof(struct wm8400_priv),
+	priv = devm_kzalloc(component->dev, sizeof(struct wm8400_priv),
 			    GFP_KERNEL);
 	if (priv == NULL)
 		return -ENOMEM;
 
-	snd_soc_codec_init_regmap(codec, wm8400->regmap);
-	snd_soc_codec_set_drvdata(codec, priv);
+	snd_soc_component_init_regmap(component, wm8400->regmap);
+	snd_soc_component_set_drvdata(component, priv);
 	priv->wm8400 = wm8400;
 
 	ret = devm_regulator_bulk_get(wm8400->dev,
 				 ARRAY_SIZE(power), &power[0]);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
+		dev_err(component->dev, "Failed to get regulators: %d\n", ret);
 		return ret;
 	}
 
-	wm8400_codec_reset(codec);
+	wm8400_component_reset(component);
 
-	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
-	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+	reg = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
 
 	/* Latch volume update bits */
-	reg = snd_soc_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
-	snd_soc_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+	reg = snd_soc_component_read32(component, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_component_write(component, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
 		     reg & WM8400_IPVU);
-	reg = snd_soc_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
-	snd_soc_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+	reg = snd_soc_component_read32(component, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_component_write(component, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
 		     reg & WM8400_IPVU);
 
-	snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-	snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_component_write(component, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_component_write(component, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
 	return 0;
 }
 
-static int  wm8400_codec_remove(struct snd_soc_codec *codec)
+static void  wm8400_component_remove(struct snd_soc_component *component)
 {
 	u16 reg;
 
-	reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
-	snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
+	reg = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1,
 		     reg & (~WM8400_CODEC_ENA));
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
-	.probe =	wm8400_codec_probe,
-	.remove =	wm8400_codec_remove,
-	.set_bias_level = wm8400_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8400_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8400_snd_controls),
-		.dapm_widgets		= wm8400_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8400_dapm_widgets),
-		.dapm_routes		= wm8400_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8400_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8400 = {
+	.probe			= wm8400_component_probe,
+	.remove			= wm8400_component_remove,
+	.set_bias_level		= wm8400_set_bias_level,
+	.controls		= wm8400_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8400_snd_controls),
+	.dapm_widgets		= wm8400_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8400_dapm_widgets),
+	.dapm_routes		= wm8400_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8400_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8400_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
+	return snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8400,
 			&wm8400_dai, 1);
 }
 
-static int wm8400_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static struct platform_driver wm8400_codec_driver = {
 	.driver = {
 		   .name = "wm8400-codec",
 		   },
 	.probe = wm8400_probe,
-	.remove = wm8400_remove,
 };
 
 module_platform_driver(wm8400_codec_driver);
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 119ceac684ae..1a2412d73e35 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -106,7 +106,7 @@ static bool wm8510_volatile(struct device *dev, unsigned int reg)
 #define WM8510_POWER1_BIASEN  0x08
 #define WM8510_POWER1_BUFIOEN 0x10
 
-#define wm8510_reset(c)	snd_soc_write(c, WM8510_RESET, 0)
+#define wm8510_reset(c)	snd_soc_component_write(c, WM8510_RESET, 0)
 
 /* codec private data */
 struct wm8510_priv {
@@ -316,32 +316,32 @@ static void pll_factors(unsigned int target, unsigned int source)
 static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	if (freq_in == 0 || freq_out == 0) {
 		/* Clock CODEC directly from MCLK */
-		reg = snd_soc_read(codec, WM8510_CLOCK);
-		snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff);
+		reg = snd_soc_component_read32(component, WM8510_CLOCK);
+		snd_soc_component_write(component, WM8510_CLOCK, reg & 0x0ff);
 
 		/* Turn off PLL */
-		reg = snd_soc_read(codec, WM8510_POWER1);
-		snd_soc_write(codec, WM8510_POWER1, reg & 0x1df);
+		reg = snd_soc_component_read32(component, WM8510_POWER1);
+		snd_soc_component_write(component, WM8510_POWER1, reg & 0x1df);
 		return 0;
 	}
 
 	pll_factors(freq_out*4, freq_in);
 
-	snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
-	snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18);
-	snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
-	snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
-	reg = snd_soc_read(codec, WM8510_POWER1);
-	snd_soc_write(codec, WM8510_POWER1, reg | 0x020);
+	snd_soc_component_write(component, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8510_PLLK1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8510_PLLK3, pll_div.k & 0x1ff);
+	reg = snd_soc_component_read32(component, WM8510_POWER1);
+	snd_soc_component_write(component, WM8510_POWER1, reg | 0x020);
 
 	/* Run CODEC from PLL instead of MCLK */
-	reg = snd_soc_read(codec, WM8510_CLOCK);
-	snd_soc_write(codec, WM8510_CLOCK, reg | 0x100);
+	reg = snd_soc_component_read32(component, WM8510_CLOCK);
+	snd_soc_component_write(component, WM8510_CLOCK, reg | 0x100);
 
 	return 0;
 }
@@ -352,29 +352,29 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8510_OPCLKDIV:
-		reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf;
-		snd_soc_write(codec, WM8510_GPIO, reg | div);
+		reg = snd_soc_component_read32(component, WM8510_GPIO) & 0x1cf;
+		snd_soc_component_write(component, WM8510_GPIO, reg | div);
 		break;
 	case WM8510_MCLKDIV:
-		reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f;
-		snd_soc_write(codec, WM8510_CLOCK, reg | div);
+		reg = snd_soc_component_read32(component, WM8510_CLOCK) & 0x11f;
+		snd_soc_component_write(component, WM8510_CLOCK, reg | div);
 		break;
 	case WM8510_ADCCLK:
-		reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7;
-		snd_soc_write(codec, WM8510_ADC, reg | div);
+		reg = snd_soc_component_read32(component, WM8510_ADC) & 0x1f7;
+		snd_soc_component_write(component, WM8510_ADC, reg | div);
 		break;
 	case WM8510_DACCLK:
-		reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7;
-		snd_soc_write(codec, WM8510_DAC, reg | div);
+		reg = snd_soc_component_read32(component, WM8510_DAC) & 0x1f7;
+		snd_soc_component_write(component, WM8510_DAC, reg | div);
 		break;
 	case WM8510_BCLKDIV:
-		reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3;
-		snd_soc_write(codec, WM8510_CLOCK, reg | div);
+		reg = snd_soc_component_read32(component, WM8510_CLOCK) & 0x1e3;
+		snd_soc_component_write(component, WM8510_CLOCK, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -386,9 +386,9 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
-	u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe;
+	u16 clk = snd_soc_component_read32(component, WM8510_CLOCK) & 0x1fe;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -435,8 +435,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8510_IFACE, iface);
-	snd_soc_write(codec, WM8510_CLOCK, clk);
+	snd_soc_component_write(component, WM8510_IFACE, iface);
+	snd_soc_component_write(component, WM8510_CLOCK, clk);
 	return 0;
 }
 
@@ -444,9 +444,9 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
-	u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
+	struct snd_soc_component *component = dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8510_IFACE) & 0x19f;
+	u16 adn = snd_soc_component_read32(component, WM8510_ADD) & 0x1f1;
 
 	/* bit size */
 	switch (params_width(params)) {
@@ -485,56 +485,56 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8510_IFACE, iface);
-	snd_soc_write(codec, WM8510_ADD, adn);
+	snd_soc_component_write(component, WM8510_IFACE, iface);
+	snd_soc_component_write(component, WM8510_ADD, adn);
 	return 0;
 }
 
 static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8510_DAC) & 0xffbf;
 
 	if (mute)
-		snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40);
+		snd_soc_component_write(component, WM8510_DAC, mute_reg | 0x40);
 	else
-		snd_soc_write(codec, WM8510_DAC, mute_reg);
+		snd_soc_component_write(component, WM8510_DAC, mute_reg);
 	return 0;
 }
 
 /* liam need to make this lower power with dapm */
-static int wm8510_set_bias_level(struct snd_soc_codec *codec,
+static int wm8510_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
-	u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;
+	struct wm8510_priv *wm8510 = snd_soc_component_get_drvdata(component);
+	u16 power1 = snd_soc_component_read32(component, WM8510_POWER1) & ~0x3;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		power1 |= 0x1;  /* VMID 50k */
-		snd_soc_write(codec, WM8510_POWER1, power1);
+		snd_soc_component_write(component, WM8510_POWER1, power1);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_sync(wm8510->regmap);
 
 			/* Initial cap charge at VMID 5k */
-			snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
+			snd_soc_component_write(component, WM8510_POWER1, power1 | 0x3);
 			mdelay(100);
 		}
 
 		power1 |= 0x2;  /* VMID 500k */
-		snd_soc_write(codec, WM8510_POWER1, power1);
+		snd_soc_component_write(component, WM8510_POWER1, power1);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, WM8510_POWER1, 0);
-		snd_soc_write(codec, WM8510_POWER2, 0);
-		snd_soc_write(codec, WM8510_POWER3, 0);
+		snd_soc_component_write(component, WM8510_POWER1, 0);
+		snd_soc_component_write(component, WM8510_POWER2, 0);
+		snd_soc_component_write(component, WM8510_POWER3, 0);
 		break;
 	}
 
@@ -574,26 +574,27 @@ static struct snd_soc_dai_driver wm8510_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8510_probe(struct snd_soc_codec *codec)
+static int wm8510_probe(struct snd_soc_component *component)
 {
-	wm8510_reset(codec);
+	wm8510_reset(component);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
-	.probe =	wm8510_probe,
-	.set_bias_level = wm8510_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8510_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8510_snd_controls),
-		.dapm_widgets		= wm8510_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8510_dapm_widgets),
-		.dapm_routes		= wm8510_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8510_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8510 = {
+	.probe			= wm8510_probe,
+	.set_bias_level		= wm8510_set_bias_level,
+	.controls		= wm8510_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8510_snd_controls),
+	.dapm_widgets		= wm8510_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8510_dapm_widgets),
+	.dapm_routes		= wm8510_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8510_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8510_of_match[] = {
@@ -631,25 +632,18 @@ static int wm8510_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8510);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8510, &wm8510_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8510, &wm8510_dai, 1);
 
 	return ret;
 }
 
-static int wm8510_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8510_spi_driver = {
 	.driver = {
 		.name	= "wm8510",
 		.of_match_table = wm8510_of_match,
 	},
 	.probe		= wm8510_spi_probe,
-	.remove		= wm8510_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -671,18 +665,12 @@ static int wm8510_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8510);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8510, &wm8510_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8510, &wm8510_dai, 1);
 
 	return ret;
 }
 
-static int wm8510_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8510_i2c_id[] = {
 	{ "wm8510", 0 },
 	{ }
@@ -695,7 +683,6 @@ static struct i2c_driver wm8510_i2c_driver = {
 		.of_match_table = wm8510_of_match,
 	},
 	.probe =    wm8510_i2c_probe,
-	.remove =   wm8510_i2c_remove,
 	.id_table = wm8510_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index c7c33e98fbcb..f4a9e25fb334 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -125,14 +125,14 @@ static const struct {
 static int wm8523_startup(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
 
 	/* The set of sample rates that can be supported depends on the
 	 * MCLK supplied to the CODEC - enforce this.
 	 */
 	if (!wm8523->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"No MCLK configured, call set_sysclk() on init\n");
 		return -EINVAL;
 	}
@@ -148,11 +148,11 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
 	int i;
-	u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
-	u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2);
+	u16 aifctrl1 = snd_soc_component_read32(component, WM8523_AIF_CTRL1);
+	u16 aifctrl2 = snd_soc_component_read32(component, WM8523_AIF_CTRL2);
 
 	/* Find a supported LRCLK ratio */
 	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
@@ -163,7 +163,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
 
 	/* Should never happen, should be handled by constraints */
 	if (i == ARRAY_SIZE(lrclk_ratios)) {
-		dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n",
+		dev_err(component->dev, "MCLK/fs ratio %d unsupported\n",
 			wm8523->sysclk / params_rate(params));
 		return -EINVAL;
 	}
@@ -178,7 +178,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
 				break;
 
 		if (i == ARRAY_SIZE(bclk_ratios)) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"No matching BCLK/fs ratio for word length %d\n",
 				params_width(params));
 			return -EINVAL;
@@ -203,8 +203,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1);
-	snd_soc_write(codec, WM8523_AIF_CTRL2, aifctrl2);
+	snd_soc_component_write(component, WM8523_AIF_CTRL1, aifctrl1);
+	snd_soc_component_write(component, WM8523_AIF_CTRL2, aifctrl2);
 
 	return 0;
 }
@@ -212,8 +212,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
 static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 	int i;
 
@@ -239,13 +239,13 @@ static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		case 96000:
 		case 176400:
 		case 192000:
-			dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
+			dev_dbg(component->dev, "Supported sample rate: %dHz\n",
 				val);
 			wm8523->rate_constraint_list[i] = val;
 			wm8523->rate_constraint.count++;
 			break;
 		default:
-			dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
+			dev_dbg(component->dev, "Skipping sample rate: %dHz\n",
 				val);
 		}
 	}
@@ -261,8 +261,8 @@ static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
+	struct snd_soc_component *component = codec_dai->component;
+	u16 aifctrl1 = snd_soc_component_read32(component, WM8523_AIF_CTRL1);
 
 	aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK |
 		      WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
@@ -312,15 +312,15 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1);
+	snd_soc_component_write(component, WM8523_AIF_CTRL1, aifctrl1);
 
 	return 0;
 }
 
-static int wm8523_set_bias_level(struct snd_soc_codec *codec,
+static int wm8523_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -329,16 +329,16 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* Full power on */
-		snd_soc_update_bits(codec, WM8523_PSCTRL1,
+		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
 				    WM8523_SYS_ENA_MASK, 3);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
 						    wm8523->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -348,21 +348,21 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
 			regcache_sync(wm8523->regmap);
 
 			/* Initial power up */
-			snd_soc_update_bits(codec, WM8523_PSCTRL1,
+			snd_soc_component_update_bits(component, WM8523_PSCTRL1,
 					    WM8523_SYS_ENA_MASK, 1);
 
 			msleep(100);
 		}
 
 		/* Power up to mute */
-		snd_soc_update_bits(codec, WM8523_PSCTRL1,
+		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
 				    WM8523_SYS_ENA_MASK, 2);
 
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* The chip runs through the power down sequence for us. */
-		snd_soc_update_bits(codec, WM8523_PSCTRL1,
+		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
 				    WM8523_SYS_ENA_MASK, 0);
 		msleep(100);
 
@@ -397,35 +397,36 @@ static struct snd_soc_dai_driver wm8523_dai = {
 	.ops = &wm8523_dai_ops,
 };
 
-static int wm8523_probe(struct snd_soc_codec *codec)
+static int wm8523_probe(struct snd_soc_component *component)
 {
-	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
 
 	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
 	wm8523->rate_constraint.count =
 		ARRAY_SIZE(wm8523->rate_constraint_list);
 
 	/* Change some default settings - latch VU and enable ZC */
-	snd_soc_update_bits(codec, WM8523_DAC_GAINR,
+	snd_soc_component_update_bits(component, WM8523_DAC_GAINR,
 			    WM8523_DACR_VU, WM8523_DACR_VU);
-	snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);
+	snd_soc_component_update_bits(component, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
-	.probe =	wm8523_probe,
-	.set_bias_level = wm8523_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8523_controls,
-		.num_controls		= ARRAY_SIZE(wm8523_controls),
-		.dapm_widgets		= wm8523_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8523_dapm_widgets),
-		.dapm_routes		= wm8523_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8523_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8523 = {
+	.probe			= wm8523_probe,
+	.set_bias_level		= wm8523_set_bias_level,
+	.controls		= wm8523_controls,
+	.num_controls		= ARRAY_SIZE(wm8523_controls),
+	.dapm_widgets		= wm8523_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8523_dapm_widgets),
+	.dapm_routes		= wm8523_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8523_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8523_of_match[] = {
@@ -511,8 +512,8 @@ static int wm8523_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8523);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8523, &wm8523_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8523, &wm8523_dai, 1);
 
 	return ret;
 
@@ -521,12 +522,6 @@ static int wm8523_i2c_probe(struct i2c_client *i2c,
 	return ret;
 }
 
-static int wm8523_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8523_i2c_id[] = {
 	{ "wm8523", 0 },
 	{ }
@@ -539,7 +534,6 @@ static struct i2c_driver wm8523_i2c_driver = {
 		.of_match_table = wm8523_of_match,
 	},
 	.probe =    wm8523_i2c_probe,
-	.remove =   wm8523_i2c_remove,
 	.id_table = wm8523_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index 856a6950a451..fde444d826ca 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -62,14 +62,14 @@ static const struct {
 static int wm8524_startup(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
 
 	/* The set of sample rates that can be supported depends on the
 	 * MCLK supplied to the CODEC - enforce this.
 	 */
 	if (!wm8524->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"No MCLK configured, call set_sysclk() on init\n");
 		return -EINVAL;
 	}
@@ -86,8 +86,8 @@ static int wm8524_startup(struct snd_pcm_substream *substream,
 static void wm8524_shutdown(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
 
 	gpiod_set_value_cansleep(wm8524->mute, 0);
 }
@@ -95,8 +95,8 @@ static void wm8524_shutdown(struct snd_pcm_substream *substream,
 static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
 	unsigned int val;
 	int i, j = 0;
 
@@ -118,13 +118,13 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		case 96000:
 		case 176400:
 		case 192000:
-			dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
+			dev_dbg(component->dev, "Supported sample rate: %dHz\n",
 				val);
 			wm8524->rate_constraint_list[j++] = val;
 			wm8524->rate_constraint.count++;
 			break;
 		default:
-			dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
+			dev_dbg(component->dev, "Skipping sample rate: %dHz\n",
 				val);
 		}
 	}
@@ -152,7 +152,7 @@ static int wm8524_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
 static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
-	struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(dai->codec);
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(dai->component);
 
 	if (wm8524->mute)
 		gpiod_set_value_cansleep(wm8524->mute, mute);
@@ -184,9 +184,9 @@ static struct snd_soc_dai_driver wm8524_dai = {
 	.ops = &wm8524_dai_ops,
 };
 
-static int wm8524_probe(struct snd_soc_codec *codec)
+static int wm8524_probe(struct snd_soc_component *component)
 {
-	struct wm8524_priv *wm8524 = snd_soc_codec_get_drvdata(codec);
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
 
 	wm8524->rate_constraint.list = &wm8524->rate_constraint_list[0];
 	wm8524->rate_constraint.count =
@@ -195,15 +195,16 @@ static int wm8524_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8524 = {
-	.probe =	wm8524_probe,
-
-	.component_driver = {
-		.dapm_widgets		= wm8524_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8524_dapm_widgets),
-		.dapm_routes		= wm8524_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8524_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8524 = {
+	.probe			= wm8524_probe,
+	.dapm_widgets		= wm8524_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8524_dapm_widgets),
+	.dapm_routes		= wm8524_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8524_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8524_of_match[] = {
@@ -231,23 +232,16 @@ static int wm8524_codec_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret =  snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_wm8524, &wm8524_dai, 1);
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8524, &wm8524_dai, 1);
 	if (ret < 0)
-		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
 
 	return ret;
 }
 
-static int wm8524_codec_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-
 static struct platform_driver wm8524_codec_driver = {
 	.probe		= wm8524_codec_probe,
-	.remove		= wm8524_codec_remove,
 	.driver		= {
 		.name	= "wm8524-codec",
 		.of_match_table = wm8524_of_match,
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 910801dddd64..fa4ad1b093eb 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -262,8 +262,8 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
 	unsigned int reg = mc->reg;
 	unsigned int reg2 = mc->rreg;
 	int ret;
@@ -279,8 +279,8 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
 		return ret;
 
 	/* Now write again with the volume update bit set */
-	snd_soc_update_bits(codec, reg, 0x100, 0x100);
-	snd_soc_update_bits(codec, reg2, 0x100, 0x100);
+	snd_soc_component_update_bits(component, reg, 0x100, 0x100);
+	snd_soc_component_update_bits(component, reg2, 0x100, 0x100);
 
 	return 0;
 }
@@ -465,8 +465,8 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
 	int offset;
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
 	struct pll_state *state;
 	struct _pll_div pll_div;
 	unsigned int reg;
@@ -505,25 +505,25 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	/* Always disable the PLL - it is not safe to leave it running
 	 * while reprogramming it.
 	 */
-	snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, pwr_mask);
+	snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, pwr_mask);
 
 	if (!freq_in || !freq_out)
 		return 0;
 
-	snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
-	snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff);
-	snd_soc_write(codec, WM8580_PLLA3 + offset,
+	snd_soc_component_write(component, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
+	snd_soc_component_write(component, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8580_PLLA3 + offset,
 		     (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
 
-	reg = snd_soc_read(codec, WM8580_PLLA4 + offset);
+	reg = snd_soc_component_read32(component, WM8580_PLLA4 + offset);
 	reg &= ~0x1b;
 	reg |= pll_div.prescale | pll_div.postscale << 1 |
 		pll_div.freqmode << 3;
 
-	snd_soc_write(codec, WM8580_PLLA4 + offset, reg);
+	snd_soc_component_write(component, WM8580_PLLA4 + offset, reg);
 
 	/* All done, turn it on */
-	snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, 0);
+	snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, 0);
 
 	return 0;
 }
@@ -539,8 +539,8 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
 	u16 paifa = 0;
 	u16 paifb = 0;
 	int i, ratio, osr;
@@ -572,12 +572,12 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
 		if (ratio == wm8580_sysclk_ratios[i])
 			break;
 	if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
-		dev_err(codec->dev, "Invalid clock ratio %d/%d\n",
+		dev_err(component->dev, "Invalid clock ratio %d/%d\n",
 			wm8580->sysclk[dai->driver->id], params_rate(params));
 		return -EINVAL;
 	}
 	paifa |= i;
-	dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n",
+	dev_dbg(component->dev, "Running at %dfs with %dHz clock\n",
 		wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -585,21 +585,21 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
 		case 128:
 		case 192:
 			osr = WM8580_DACOSR;
-			dev_dbg(codec->dev, "Selecting 64x OSR\n");
+			dev_dbg(component->dev, "Selecting 64x OSR\n");
 			break;
 		default:
 			osr = 0;
-			dev_dbg(codec->dev, "Selecting 128x OSR\n");
+			dev_dbg(component->dev, "Selecting 128x OSR\n");
 			break;
 		}
 
-		snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr);
+		snd_soc_component_update_bits(component, WM8580_PAIF3, WM8580_DACOSR, osr);
 	}
 
-	snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id,
+	snd_soc_component_update_bits(component, WM8580_PAIF1 + dai->driver->id,
 			    WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
 			    paifa);
-	snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id,
+	snd_soc_component_update_bits(component, WM8580_PAIF3 + dai->driver->id,
 			    WM8580_AIF_LENGTH_MASK, paifb);
 	return 0;
 }
@@ -607,13 +607,13 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
 static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
 				      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int aifa;
 	unsigned int aifb;
 	int can_invert_lrclk;
 
-	aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id);
-	aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id);
+	aifa = snd_soc_component_read32(component, WM8580_PAIF1 + codec_dai->driver->id);
+	aifb = snd_soc_component_read32(component, WM8580_PAIF3 + codec_dai->driver->id);
 
 	aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
 
@@ -679,8 +679,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa);
-	snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb);
+	snd_soc_component_write(component, WM8580_PAIF1 + codec_dai->driver->id, aifa);
+	snd_soc_component_write(component, WM8580_PAIF3 + codec_dai->driver->id, aifb);
 
 	return 0;
 }
@@ -688,12 +688,12 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
 static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 				 int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int reg;
 
 	switch (div_id) {
 	case WM8580_MCLK:
-		reg = snd_soc_read(codec, WM8580_PLLB4);
+		reg = snd_soc_component_read32(component, WM8580_PLLB4);
 		reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
 
 		switch (div) {
@@ -715,11 +715,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		default:
 			return -EINVAL;
 		}
-		snd_soc_write(codec, WM8580_PLLB4, reg);
+		snd_soc_component_write(component, WM8580_PLLB4, reg);
 		break;
 
 	case WM8580_CLKOUTSRC:
-		reg = snd_soc_read(codec, WM8580_PLLB4);
+		reg = snd_soc_component_read32(component, WM8580_PLLB4);
 		reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
 
 		switch (div) {
@@ -741,7 +741,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		default:
 			return -EINVAL;
 		}
-		snd_soc_write(codec, WM8580_PLLB4, reg);
+		snd_soc_component_write(component, WM8580_PLLB4, reg);
 		break;
 
 	default:
@@ -754,8 +754,8 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 			     unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
 	int ret, sel, sel_mask, sel_shift;
 
 	switch (dai->driver->id) {
@@ -790,14 +790,14 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 		sel = 3 << sel_shift;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+		dev_err(component->dev, "Unknown clock %d\n", clk_id);
 		return -EINVAL;
 	}
 
 	/* We really should validate PLL settings but not yet */
 	wm8580->sysclk[dai->driver->id] = freq;
 
-	ret = snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+	ret = snd_soc_component_update_bits(component, WM8580_CLKSEL, sel_mask, sel);
 	if (ret < 0)
 		return ret;
 
@@ -806,22 +806,22 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM8580_DAC_CONTROL5);
+	reg = snd_soc_component_read32(component, WM8580_DAC_CONTROL5);
 
 	if (mute)
 		reg |= WM8580_DAC_CONTROL5_MUTEALL;
 	else
 		reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
 
-	snd_soc_write(codec, WM8580_DAC_CONTROL5, reg);
+	snd_soc_component_write(component, WM8580_DAC_CONTROL5, reg);
 
 	return 0;
 }
 
-static int wm8580_set_bias_level(struct snd_soc_codec *codec,
+static int wm8580_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -830,20 +830,20 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Power up and get individual control of the DACs */
-			snd_soc_update_bits(codec, WM8580_PWRDN1,
+			snd_soc_component_update_bits(component, WM8580_PWRDN1,
 					    WM8580_PWRDN1_PWDN |
 					    WM8580_PWRDN1_ALLDACPD, 0);
 
 			/* Make VMID high impedance */
-			snd_soc_update_bits(codec, WM8580_ADC_CONTROL1,
+			snd_soc_component_update_bits(component, WM8580_ADC_CONTROL1,
 					    0x100, 0);
 		}
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8580_PWRDN1,
+		snd_soc_component_update_bits(component, WM8580_PWRDN1,
 				    WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
 		break;
 	}
@@ -853,8 +853,8 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
 static int wm8580_playback_startup(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
 
 	return snd_pcm_hw_constraint_minmax(substream->runtime,
 		SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2);
@@ -907,15 +907,15 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
 	},
 };
 
-static int wm8580_probe(struct snd_soc_codec *codec)
+static int wm8580_probe(struct snd_soc_component *component)
 {
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int ret = 0;
 
 	switch (wm8580->drvdata->num_dacs) {
 	case 4:
-		snd_soc_add_codec_controls(codec, wm8581_snd_controls,
+		snd_soc_add_component_controls(component, wm8581_snd_controls,
 					ARRAY_SIZE(wm8581_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets,
 					ARRAY_SIZE(wm8581_dapm_widgets));
@@ -929,14 +929,14 @@ static int wm8580_probe(struct snd_soc_codec *codec)
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
 				    wm8580->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		goto err_regulator_get;
 	}
 
 	/* Get the codec into a known state */
-	ret = snd_soc_write(codec, WM8580_RESET, 0);
+	ret = snd_soc_component_write(component, WM8580_RESET, 0);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+		dev_err(component->dev, "Failed to reset component: %d\n", ret);
 		goto err_regulator_enable;
 	}
 
@@ -949,28 +949,27 @@ static int wm8580_probe(struct snd_soc_codec *codec)
 }
 
 /* power down chip */
-static int wm8580_remove(struct snd_soc_codec *codec)
+static void wm8580_remove(struct snd_soc_component *component)
 {
-	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
 
 	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
-	.probe =	wm8580_probe,
-	.remove =	wm8580_remove,
-	.set_bias_level = wm8580_set_bias_level,
-
-	.component_driver = {
-		.controls		= wm8580_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8580_snd_controls),
-		.dapm_widgets		= wm8580_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8580_dapm_widgets),
-		.dapm_routes		= wm8580_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8580_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8580 = {
+	.probe			= wm8580_probe,
+	.remove			= wm8580_remove,
+	.set_bias_level		= wm8580_set_bias_level,
+	.controls		= wm8580_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8580_snd_controls),
+	.dapm_widgets		= wm8580_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8580_dapm_widgets),
+	.dapm_routes		= wm8580_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8580_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8580_regmap = {
@@ -1037,18 +1036,12 @@ static int wm8580_i2c_probe(struct i2c_client *i2c,
 		return -EINVAL;
 	}
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
 
 	return ret;
 }
 
-static int wm8580_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8580_i2c_id[] = {
 	{ "wm8580", (kernel_ulong_t)&wm8580_data },
 	{ "wm8581", (kernel_ulong_t)&wm8581_data },
@@ -1062,7 +1055,6 @@ static struct i2c_driver wm8580_i2c_driver = {
 		.of_match_table = wm8580_of_match,
 	},
 	.probe =    wm8580_i2c_probe,
-	.remove =   wm8580_i2c_remove,
 	.id_table = wm8580_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 2b376c9c99af..1da08d281ae7 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -58,7 +58,7 @@ static bool wm8711_volatile(struct device *dev, unsigned int reg)
 	}
 }
 
-#define wm8711_reset(c)	snd_soc_write(c, WM8711_RESET, 0)
+#define wm8711_reset(c)	snd_soc_component_write(c, WM8711_RESET, 0)
 
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
 
@@ -159,14 +159,14 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfff3;
+	struct snd_soc_component *component = dai->component;
+	struct wm8711_priv *wm8711 =  snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8711_IFACE) & 0xfff3;
 	int i = get_coeff(wm8711->sysclk, params_rate(params));
 	u16 srate = (coeff_div[i].sr << 2) |
 		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
 
-	snd_soc_write(codec, WM8711_SRATE, srate);
+	snd_soc_component_write(component, WM8711_SRATE, srate);
 
 	/* bit size */
 	switch (params_width(params)) {
@@ -180,17 +180,17 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8711_IFACE, iface);
+	snd_soc_component_write(component, WM8711_IFACE, iface);
 	return 0;
 }
 
 static int wm8711_pcm_prepare(struct snd_pcm_substream *substream,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	/* set active */
-	snd_soc_write(codec, WM8711_ACTIVE, 0x0001);
+	snd_soc_component_write(component, WM8711_ACTIVE, 0x0001);
 
 	return 0;
 }
@@ -198,24 +198,24 @@ static int wm8711_pcm_prepare(struct snd_pcm_substream *substream,
 static void wm8711_shutdown(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	/* deactivate */
-	if (!snd_soc_codec_is_active(codec)) {
+	if (!snd_soc_component_is_active(component)) {
 		udelay(50);
-		snd_soc_write(codec, WM8711_ACTIVE, 0x0);
+		snd_soc_component_write(component, WM8711_ACTIVE, 0x0);
 	}
 }
 
 static int wm8711_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8711_APDIGI) & 0xfff7;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8711_APDIGI) & 0xfff7;
 
 	if (mute)
-		snd_soc_write(codec, WM8711_APDIGI, mute_reg | 0x8);
+		snd_soc_component_write(component, WM8711_APDIGI, mute_reg | 0x8);
 	else
-		snd_soc_write(codec, WM8711_APDIGI, mute_reg);
+		snd_soc_component_write(component, WM8711_APDIGI, mute_reg);
 
 	return 0;
 }
@@ -223,8 +223,8 @@ static int wm8711_mute(struct snd_soc_dai *dai, int mute)
 static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8711_priv *wm8711 =  snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 11289600:
@@ -241,8 +241,8 @@ static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0x000c;
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8711_IFACE) & 0x000c;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -293,31 +293,31 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 
 	/* set iface */
-	snd_soc_write(codec, WM8711_IFACE, iface);
+	snd_soc_component_write(component, WM8711_IFACE, iface);
 	return 0;
 }
 
-static int wm8711_set_bias_level(struct snd_soc_codec *codec,
+static int wm8711_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
-	u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f;
+	struct wm8711_priv *wm8711 = snd_soc_component_get_drvdata(component);
+	u16 reg = snd_soc_component_read32(component, WM8711_PWR) & 0xff7f;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_write(codec, WM8711_PWR, reg);
+		snd_soc_component_write(component, WM8711_PWR, reg);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			regcache_sync(wm8711->regmap);
 
-		snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
+		snd_soc_component_write(component, WM8711_PWR, reg | 0x0040);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, WM8711_ACTIVE, 0x0);
-		snd_soc_write(codec, WM8711_PWR, 0xffff);
+		snd_soc_component_write(component, WM8711_ACTIVE, 0x0);
+		snd_soc_component_write(component, WM8711_PWR, 0xffff);
 		break;
 	}
 	return 0;
@@ -349,37 +349,38 @@ static struct snd_soc_dai_driver wm8711_dai = {
 	.ops = &wm8711_ops,
 };
 
-static int wm8711_probe(struct snd_soc_codec *codec)
+static int wm8711_probe(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = wm8711_reset(codec);
+	ret = wm8711_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
+		dev_err(component->dev, "Failed to issue reset\n");
 		return ret;
 	}
 
 	/* Latch the update bits */
-	snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8711_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8711_ROUT1V, 0x0100, 0x0100);
 
 	return ret;
 
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
-	.probe =	wm8711_probe,
-	.set_bias_level = wm8711_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8711_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8711_snd_controls),
-		.dapm_widgets		= wm8711_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8711_dapm_widgets),
-		.dapm_routes		= wm8711_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(wm8711_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8711 = {
+	.probe			= wm8711_probe,
+	.set_bias_level		= wm8711_set_bias_level,
+	.controls		= wm8711_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8711_snd_controls),
+	.dapm_widgets		= wm8711_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8711_dapm_widgets),
+	.dapm_routes		= wm8711_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8711_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8711_of_match[] = {
@@ -417,26 +418,18 @@ static int wm8711_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8711);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8711, &wm8711_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8711, &wm8711_dai, 1);
 
 	return ret;
 }
 
-static int wm8711_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-
-	return 0;
-}
-
 static struct spi_driver wm8711_spi_driver = {
 	.driver = {
 		.name	= "wm8711",
 		.of_match_table = wm8711_of_match,
 	},
 	.probe		= wm8711_spi_probe,
-	.remove		= wm8711_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -458,18 +451,12 @@ static int wm8711_i2c_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, wm8711);
 
-	ret =  snd_soc_register_codec(&client->dev,
-			&soc_codec_dev_wm8711, &wm8711_dai, 1);
+	ret = devm_snd_soc_register_component(&client->dev,
+			&soc_component_dev_wm8711, &wm8711_dai, 1);
 
 	return ret;
 }
 
-static int wm8711_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8711_i2c_id[] = {
 	{ "wm8711", 0 },
 	{ }
@@ -482,7 +469,6 @@ static struct i2c_driver wm8711_i2c_driver = {
 		.of_match_table = wm8711_of_match,
 	},
 	.probe =    wm8711_i2c_probe,
-	.remove =   wm8711_i2c_remove,
 	.id_table = wm8711_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
index 7fde077a014b..087ec6db8cd0 100644
--- a/sound/soc/codecs/wm8727.c
+++ b/sound/soc/codecs/wm8727.c
@@ -19,7 +19,6 @@
 #include <linux/device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
 
@@ -41,7 +40,6 @@ static const struct snd_soc_dapm_route wm8727_dapm_routes[] = {
 			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
 			SNDRV_PCM_RATE_192000)
 
-
 static struct snd_soc_dai_driver wm8727_dai = {
 	.name = "wm8727-hifi",
 	.playback = {
@@ -53,25 +51,21 @@ static struct snd_soc_dai_driver wm8727_dai = {
 		},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8727 = {
-	.component_driver = {
-		.dapm_widgets		= wm8727_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8727_dapm_widgets),
-		.dapm_routes		= wm8727_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8727_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8727 = {
+	.dapm_widgets		= wm8727_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8727_dapm_widgets),
+	.dapm_routes		= wm8727_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8727_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8727_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_wm8727, &wm8727_dai, 1);
-}
-
-static int wm8727_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8727, &wm8727_dai, 1);
 }
 
 static struct platform_driver wm8727_codec_driver = {
@@ -80,7 +74,6 @@ static struct platform_driver wm8727_codec_driver = {
 	},
 
 	.probe = wm8727_probe,
-	.remove = wm8727_remove,
 };
 
 module_platform_driver(wm8727_codec_driver);
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 797cc6e7c70f..839aee35ab56 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -74,13 +74,13 @@ static const struct snd_soc_dapm_route wm8728_intercon[] = {
 
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL);
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8728_DACCTL);
 
 	if (mute)
-		snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1);
+		snd_soc_component_write(component, WM8728_DACCTL, mute_reg | 1);
 	else
-		snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1);
+		snd_soc_component_write(component, WM8728_DACCTL, mute_reg & ~1);
 
 	return 0;
 }
@@ -89,8 +89,8 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 dac = snd_soc_read(codec, WM8728_DACCTL);
+	struct snd_soc_component *component = dai->component;
+	u16 dac = snd_soc_component_read32(component, WM8728_DACCTL);
 
 	dac &= ~0x18;
 
@@ -107,7 +107,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8728_DACCTL, dac);
+	snd_soc_component_write(component, WM8728_DACCTL, dac);
 
 	return 0;
 }
@@ -115,8 +115,8 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
 static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = snd_soc_read(codec, WM8728_IFCTL);
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8728_IFCTL);
 
 	/* Currently only I2S is supported by the driver, though the
 	 * hardware is more flexible.
@@ -156,24 +156,24 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8728_IFCTL, iface);
+	snd_soc_component_write(component, WM8728_IFCTL, iface);
 	return 0;
 }
 
-static int wm8728_set_bias_level(struct snd_soc_codec *codec,
+static int wm8728_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
+	struct wm8728_priv *wm8728 = snd_soc_component_get_drvdata(component);
 	u16 reg;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Power everything up... */
-			reg = snd_soc_read(codec, WM8728_DACCTL);
-			snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
+			reg = snd_soc_component_read32(component, WM8728_DACCTL);
+			snd_soc_component_write(component, WM8728_DACCTL, reg & ~0x4);
 
 			/* ..then sync in the register cache. */
 			regcache_sync(wm8728->regmap);
@@ -181,8 +181,8 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		reg = snd_soc_read(codec, WM8728_DACCTL);
-		snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
+		reg = snd_soc_component_read32(component, WM8728_DACCTL);
+		snd_soc_component_write(component, WM8728_DACCTL, reg | 0x4);
 		break;
 	}
 	return 0;
@@ -211,18 +211,19 @@ static struct snd_soc_dai_driver wm8728_dai = {
 	.ops = &wm8728_dai_ops,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
-	.set_bias_level = wm8728_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8728_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8728_snd_controls),
-		.dapm_widgets		= wm8728_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8728_dapm_widgets),
-		.dapm_routes		= wm8728_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(wm8728_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8728 = {
+	.set_bias_level		= wm8728_set_bias_level,
+	.controls		= wm8728_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8728_snd_controls),
+	.dapm_widgets		= wm8728_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8728_dapm_widgets),
+	.dapm_routes		= wm8728_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8728_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8728_of_match[] = {
@@ -258,26 +259,18 @@ static int wm8728_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8728);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8728, &wm8728_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8728, &wm8728_dai, 1);
 
 	return ret;
 }
 
-static int wm8728_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-
-	return 0;
-}
-
 static struct spi_driver wm8728_spi_driver = {
 	.driver = {
 		.name	= "wm8728",
 		.of_match_table = wm8728_of_match,
 	},
 	.probe		= wm8728_spi_probe,
-	.remove		= wm8728_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -299,18 +292,12 @@ static int wm8728_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8728);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8728, &wm8728_dai, 1);
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8728, &wm8728_dai, 1);
 
 	return ret;
 }
 
-static int wm8728_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8728_i2c_id[] = {
 	{ "wm8728", 0 },
 	{ }
@@ -323,7 +310,6 @@ static struct i2c_driver wm8728_i2c_driver = {
 		.of_match_table = wm8728_of_match,
 	},
 	.probe =    wm8728_i2c_probe,
-	.remove =   wm8728_i2c_remove,
 	.id_table = wm8728_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 4f9a1eb28120..7c8fad865d6b 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -88,9 +88,9 @@ static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum,
 
 static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
 
-static int wm8731_set_deemph(struct snd_soc_codec *codec)
+static int wm8731_set_deemph(struct snd_soc_component *component)
 {
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
 	int val, i, best;
 
 	/* If we're using deemphasis select the nearest available sample
@@ -110,17 +110,17 @@ static int wm8731_set_deemph(struct snd_soc_codec *codec)
 		val = 0;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
+	dev_dbg(component->dev, "Set deemphasis %d (%dHz)\n",
 		best, wm8731_deemph[best]);
 
-	return snd_soc_update_bits(codec, WM8731_APDIGI, 0x6, val);
+	return snd_soc_component_update_bits(component, WM8731_APDIGI, 0x6, val);
 }
 
 static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8731->deemph;
 
@@ -130,8 +130,8 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 	int ret = 0;
 
@@ -142,7 +142,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
 	if (wm8731->deemph != deemph) {
 		wm8731->deemph = deemph;
 
-		wm8731_set_deemph(codec);
+		wm8731_set_deemph(component);
 
 		ret = 1;
 	}
@@ -214,8 +214,8 @@ SND_SOC_DAPM_INPUT("LLINEIN"),
 static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
 			    struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
 
 	return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
 }
@@ -337,16 +337,16 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
+	struct snd_soc_component *component = dai->component;
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8731_IFACE) & 0xfff3;
 	int i = get_coeff(wm8731->sysclk, params_rate(params));
 	u16 srate = (coeff_div[i].sr << 2) |
 		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
 
 	wm8731->playback_fs = params_rate(params);
 
-	snd_soc_write(codec, WM8731_SRATE, srate);
+	snd_soc_component_write(component, WM8731_SRATE, srate);
 
 	/* bit size */
 	switch (params_width(params)) {
@@ -363,30 +363,30 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	wm8731_set_deemph(codec);
+	wm8731_set_deemph(component);
 
-	snd_soc_write(codec, WM8731_IFACE, iface);
+	snd_soc_component_write(component, WM8731_IFACE, iface);
 	return 0;
 }
 
 static int wm8731_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8731_APDIGI) & 0xfff7;
 
 	if (mute)
-		snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8);
+		snd_soc_component_write(component, WM8731_APDIGI, mute_reg | 0x8);
 	else
-		snd_soc_write(codec, WM8731_APDIGI, mute_reg);
+		snd_soc_component_write(component, WM8731_APDIGI, mute_reg);
 	return 0;
 }
 
 static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM8731_SYSCLK_XTAL:
@@ -429,7 +429,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -481,14 +481,14 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 
 	/* set iface */
-	snd_soc_write(codec, WM8731_IFACE, iface);
+	snd_soc_component_write(component, WM8731_IFACE, iface);
 	return 0;
 }
 
-static int wm8731_set_bias_level(struct snd_soc_codec *codec,
+static int wm8731_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
 	int ret;
 	u16 reg;
 
@@ -503,7 +503,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
 						    wm8731->supplies);
 			if (ret != 0)
@@ -513,13 +513,13 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 		}
 
 		/* Clear PWROFF, gate CLKOUT, everything else as-is */
-		reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f;
-		snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
+		reg = snd_soc_component_read32(component, WM8731_PWR) & 0xff7f;
+		snd_soc_component_write(component, WM8731_PWR, reg | 0x0040);
 		break;
 	case SND_SOC_BIAS_OFF:
 		if (wm8731->mclk)
 			clk_disable_unprepare(wm8731->mclk);
-		snd_soc_write(codec, WM8731_PWR, 0xffff);
+		snd_soc_component_write(component, WM8731_PWR, 0xffff);
 		regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
 				       wm8731->supplies);
 		regcache_mark_dirty(wm8731->regmap);
@@ -531,7 +531,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 static int wm8731_startup(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
-	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(dai->codec);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(dai->component);
 
 	if (wm8731->constraints)
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -628,18 +628,19 @@ static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731)
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
-	.set_bias_level = wm8731_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8731_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8731_snd_controls),
-		.dapm_widgets		= wm8731_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8731_dapm_widgets),
-		.dapm_routes		= wm8731_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(wm8731_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8731 = {
+	.set_bias_level		= wm8731_set_bias_level,
+	.controls		= wm8731_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8731_snd_controls),
+	.dapm_widgets		= wm8731_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8731_dapm_widgets),
+	.dapm_routes		= wm8731_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8731_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8731_of_match[] = {
@@ -704,8 +705,8 @@ static int wm8731_spi_probe(struct spi_device *spi)
 	if (ret != 0)
 		return ret;
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8731, &wm8731_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8731, &wm8731_dai, 1);
 	if (ret != 0) {
 		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
 		return ret;
@@ -716,7 +717,6 @@ static int wm8731_spi_probe(struct spi_device *spi)
 
 static int wm8731_spi_remove(struct spi_device *spi)
 {
-	snd_soc_unregister_codec(&spi->dev);
 	return 0;
 }
 
@@ -775,8 +775,8 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
 	if (ret != 0)
 		return ret;
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8731, &wm8731_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8731, &wm8731_dai, 1);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
 		return ret;
@@ -787,7 +787,6 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
 
 static int wm8731_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index f0cb1c4afe3c..e9ae821e7609 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -74,9 +74,9 @@ static bool wm8737_volatile(struct device *dev, unsigned int reg)
 	}
 }
 
-static int wm8737_reset(struct snd_soc_codec *codec)
+static int wm8737_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, WM8737_RESET, 0);
+	return snd_soc_component_write(component, WM8737_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_RANGE(micboost_tlv,
@@ -328,8 +328,8 @@ static int wm8737_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
 	int i;
 	u16 clocking = 0;
 	u16 af = 0;
@@ -348,7 +348,7 @@ static int wm8737_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (i == ARRAY_SIZE(coeff_div)) {
-		dev_err(codec->dev, "%dHz MCLK can't support %dHz\n",
+		dev_err(component->dev, "%dHz MCLK can't support %dHz\n",
 			wm8737->mclk, params_rate(params));
 		return -EINVAL;
 	}
@@ -371,8 +371,8 @@ static int wm8737_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT, WM8737_WL_MASK, af);
-	snd_soc_update_bits(codec, WM8737_CLOCKING,
+	snd_soc_component_update_bits(component, WM8737_AUDIO_FORMAT, WM8737_WL_MASK, af);
+	snd_soc_component_update_bits(component, WM8737_CLOCKING,
 			    WM8737_USB_MODE | WM8737_CLKDIV2 | WM8737_SR_MASK,
 			    clocking);
 
@@ -382,8 +382,8 @@ static int wm8737_hw_params(struct snd_pcm_substream *substream,
 static int wm8737_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
@@ -394,7 +394,7 @@ static int wm8737_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		}
 	}
 
-	dev_err(codec->dev, "MCLK rate %dHz not supported\n", freq);
+	dev_err(component->dev, "MCLK rate %dHz not supported\n", freq);
 
 	return -EINVAL;
 }
@@ -403,7 +403,7 @@ static int wm8737_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 af = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -445,16 +445,16 @@ static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT,
+	snd_soc_component_update_bits(component, WM8737_AUDIO_FORMAT,
 			    WM8737_FORMAT_MASK | WM8737_LRP | WM8737_MS, af);
 
 	return 0;
 }
 
-static int wm8737_set_bias_level(struct snd_soc_codec *codec,
+static int wm8737_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -463,16 +463,16 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID at 2*75k */
-		snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
+		snd_soc_component_update_bits(component, WM8737_MISC_BIAS_CONTROL,
 				    WM8737_VMIDSEL_MASK, 0);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
 						    wm8737->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -481,12 +481,12 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
 			regcache_sync(wm8737->regmap);
 
 			/* Fast VMID ramp at 2*2.5k */
-			snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
+			snd_soc_component_update_bits(component, WM8737_MISC_BIAS_CONTROL,
 					    WM8737_VMIDSEL_MASK,
 					    2 << WM8737_VMIDSEL_SHIFT);
 
 			/* Bring VMID up */
-			snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
+			snd_soc_component_update_bits(component, WM8737_POWER_MANAGEMENT,
 					    WM8737_VMID_MASK |
 					    WM8737_VREF_MASK,
 					    WM8737_VMID_MASK |
@@ -496,14 +496,14 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
 		}
 
 		/* VMID at 2*300k */
-		snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
+		snd_soc_component_update_bits(component, WM8737_MISC_BIAS_CONTROL,
 				    WM8737_VMIDSEL_MASK,
 				    1 << WM8737_VMIDSEL_SHIFT);
 
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
+		snd_soc_component_update_bits(component, WM8737_POWER_MANAGEMENT,
 				    WM8737_VMID_MASK | WM8737_VREF_MASK, 0);
 
 		regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies),
@@ -537,30 +537,30 @@ static struct snd_soc_dai_driver wm8737_dai = {
 	.ops = &wm8737_dai_ops,
 };
 
-static int wm8737_probe(struct snd_soc_codec *codec)
+static int wm8737_probe(struct snd_soc_component *component)
 {
-	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
 				    wm8737->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		goto err_get;
 	}
 
-	ret = wm8737_reset(codec);
+	ret = wm8737_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
+		dev_err(component->dev, "Failed to issue reset\n");
 		goto err_enable;
 	}
 
-	snd_soc_update_bits(codec, WM8737_LEFT_PGA_VOLUME, WM8737_LVU,
+	snd_soc_component_update_bits(component, WM8737_LEFT_PGA_VOLUME, WM8737_LVU,
 			    WM8737_LVU);
-	snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
+	snd_soc_component_update_bits(component, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
 			    WM8737_RVU);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
@@ -573,19 +573,20 @@ static int wm8737_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
-	.probe		= wm8737_probe,
-	.set_bias_level = wm8737_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8737_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8737_snd_controls),
-		.dapm_widgets		= wm8737_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8737_dapm_widgets),
-		.dapm_routes		= intercon,
-		.num_dapm_routes	= ARRAY_SIZE(intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8737 = {
+	.probe			= wm8737_probe,
+	.set_bias_level		= wm8737_set_bias_level,
+	.controls		= wm8737_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8737_snd_controls),
+	.dapm_widgets		= wm8737_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8737_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8737_of_match[] = {
@@ -635,20 +636,13 @@ static int wm8737_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8737);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-				      &soc_codec_dev_wm8737, &wm8737_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_wm8737, &wm8737_dai, 1);
 
 	return ret;
 
 }
 
-static int wm8737_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8737_i2c_id[] = {
 	{ "wm8737", 0 },
 	{ }
@@ -661,7 +655,6 @@ static struct i2c_driver wm8737_i2c_driver = {
 		.of_match_table = wm8737_of_match,
 	},
 	.probe =    wm8737_i2c_probe,
-	.remove =   wm8737_i2c_remove,
 	.id_table = wm8737_i2c_id,
 };
 #endif
@@ -693,26 +686,18 @@ static int wm8737_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8737);
 
-	ret = snd_soc_register_codec(&spi->dev,
-				     &soc_codec_dev_wm8737, &wm8737_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+				&soc_component_dev_wm8737, &wm8737_dai, 1);
 
 	return ret;
 }
 
-static int wm8737_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-
-	return 0;
-}
-
 static struct spi_driver wm8737_spi_driver = {
 	.driver = {
 		.name	= "wm8737",
 		.of_match_table = wm8737_of_match,
 	},
 	.probe		= wm8737_spi_probe,
-	.remove		= wm8737_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index a394dbee77aa..1fedf74da705 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -59,9 +59,9 @@ static const struct reg_default wm8741_reg_defaults[] = {
 	{ 32, 0x0002 },     /* R32 - ADDITONAL_CONTROL_1 */
 };
 
-static int wm8741_reset(struct snd_soc_codec *codec)
+static int wm8741_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, WM8741_RESET, 0);
+	return snd_soc_component_write(component, WM8741_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
@@ -179,8 +179,8 @@ static const struct snd_pcm_hw_constraint_list constraints_36864 = {
 static int wm8741_startup(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 
 	if (wm8741->sysclk)
 		snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -194,8 +194,8 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 	unsigned int iface;
 	int i;
 
@@ -203,7 +203,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
 	 * MCLK supplied to the CODEC - enforce this.
 	 */
 	if (!wm8741->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"No MCLK configured, call set_sysclk() on init or in hw_params\n");
 		return -EINVAL;
 	}
@@ -215,7 +215,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (i == wm8741->sysclk_constraints->count) {
-		dev_err(codec->dev, "LRCLK %d unsupported with MCLK %d\n",
+		dev_err(component->dev, "LRCLK %d unsupported with MCLK %d\n",
 			params_rate(params), wm8741->sysclk);
 		return -EINVAL;
 	}
@@ -235,15 +235,15 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
 		iface = 0x3;
 		break;
 	default:
-		dev_dbg(codec->dev, "wm8741_hw_params:    Unsupported bit size param = %d",
+		dev_dbg(component->dev, "wm8741_hw_params:    Unsupported bit size param = %d",
 			params_width(params));
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "wm8741_hw_params:    bit size param = %d, rate param = %d",
+	dev_dbg(component->dev, "wm8741_hw_params:    bit size param = %d, rate param = %d",
 		params_width(params), params_rate(params));
 
-	snd_soc_update_bits(codec, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK,
+	snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK,
 			    iface);
 
 	return 0;
@@ -252,10 +252,10 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
 static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
+	dev_dbg(component->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
 
 	switch (freq) {
 	case 0:
@@ -297,7 +297,7 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int iface;
 
 	/* check master/slave audio interface */
@@ -347,11 +347,11 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 
 
-	dev_dbg(codec->dev, "wm8741_set_dai_fmt:    Format=%x, Clock Inv=%x\n",
+	dev_dbg(component->dev, "wm8741_set_dai_fmt:    Format=%x, Clock Inv=%x\n",
 				fmt & SND_SOC_DAIFMT_FORMAT_MASK,
 				((fmt & SND_SOC_DAIFMT_INV_MASK)));
 
-	snd_soc_update_bits(codec, WM8741_FORMAT_CONTROL,
+	snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL,
 			    WM8741_BCP_MASK | WM8741_LRP_MASK | WM8741_FMT_MASK,
 			    iface);
 
@@ -386,18 +386,18 @@ static struct snd_soc_dai_driver wm8741_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8741_resume(struct snd_soc_codec *codec)
+static int wm8741_resume(struct snd_soc_component *component)
 {
-	snd_soc_cache_sync(codec);
+	snd_soc_component_cache_sync(component);
 	return 0;
 }
 #else
 #define wm8741_resume NULL
 #endif
 
-static int wm8741_configure(struct snd_soc_codec *codec)
+static int wm8741_configure(struct snd_soc_component *component)
 {
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 
 	/* Configure differential mode */
 	switch (wm8741->pdata.diff_mode) {
@@ -405,7 +405,7 @@ static int wm8741_configure(struct snd_soc_codec *codec)
 	case WM8741_DIFF_MODE_STEREO_REVERSED:
 	case WM8741_DIFF_MODE_MONO_LEFT:
 	case WM8741_DIFF_MODE_MONO_RIGHT:
-		snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2,
+		snd_soc_component_update_bits(component, WM8741_MODE_CONTROL_2,
 				WM8741_DIFF_MASK,
 				wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
 		break;
@@ -414,36 +414,36 @@ static int wm8741_configure(struct snd_soc_codec *codec)
 	}
 
 	/* Change some default settings - latch VU */
-	snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
+	snd_soc_component_update_bits(component, WM8741_DACLLSB_ATTENUATION,
 			WM8741_UPDATELL, WM8741_UPDATELL);
-	snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
+	snd_soc_component_update_bits(component, WM8741_DACLMSB_ATTENUATION,
 			WM8741_UPDATELM, WM8741_UPDATELM);
-	snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
+	snd_soc_component_update_bits(component, WM8741_DACRLSB_ATTENUATION,
 			WM8741_UPDATERL, WM8741_UPDATERL);
-	snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
+	snd_soc_component_update_bits(component, WM8741_DACRMSB_ATTENUATION,
 			WM8741_UPDATERM, WM8741_UPDATERM);
 
 	return 0;
 }
 
-static int wm8741_add_controls(struct snd_soc_codec *codec)
+static int wm8741_add_controls(struct snd_soc_component *component)
 {
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 
 	switch (wm8741->pdata.diff_mode) {
 	case WM8741_DIFF_MODE_STEREO:
 	case WM8741_DIFF_MODE_STEREO_REVERSED:
-		snd_soc_add_codec_controls(codec,
+		snd_soc_add_component_controls(component,
 				wm8741_snd_controls_stereo,
 				ARRAY_SIZE(wm8741_snd_controls_stereo));
 		break;
 	case WM8741_DIFF_MODE_MONO_LEFT:
-		snd_soc_add_codec_controls(codec,
+		snd_soc_add_component_controls(component,
 				wm8741_snd_controls_mono_left,
 				ARRAY_SIZE(wm8741_snd_controls_mono_left));
 		break;
 	case WM8741_DIFF_MODE_MONO_RIGHT:
-		snd_soc_add_codec_controls(codec,
+		snd_soc_add_component_controls(component,
 				wm8741_snd_controls_mono_right,
 				ARRAY_SIZE(wm8741_snd_controls_mono_right));
 		break;
@@ -454,37 +454,37 @@ static int wm8741_add_controls(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int wm8741_probe(struct snd_soc_codec *codec)
+static int wm8741_probe(struct snd_soc_component *component)
 {
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
 				    wm8741->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		goto err_get;
 	}
 
-	ret = wm8741_reset(codec);
+	ret = wm8741_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
+		dev_err(component->dev, "Failed to issue reset\n");
 		goto err_enable;
 	}
 
-	ret = wm8741_configure(codec);
+	ret = wm8741_configure(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to change default settings\n");
+		dev_err(component->dev, "Failed to change default settings\n");
 		goto err_enable;
 	}
 
-	ret = wm8741_add_controls(codec);
+	ret = wm8741_add_controls(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to add controls\n");
+		dev_err(component->dev, "Failed to add controls\n");
 		goto err_enable;
 	}
 
-	dev_dbg(codec->dev, "Successful registration\n");
+	dev_dbg(component->dev, "Successful registration\n");
 	return ret;
 
 err_enable:
@@ -493,26 +493,25 @@ static int wm8741_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static int wm8741_remove(struct snd_soc_codec *codec)
+static void wm8741_remove(struct snd_soc_component *component)
 {
-	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
 
 	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
-	.probe =	wm8741_probe,
-	.remove =	wm8741_remove,
-	.resume =	wm8741_resume,
-
-	.component_driver = {
-		.dapm_widgets		= wm8741_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8741_dapm_widgets),
-		.dapm_routes		= wm8741_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8741_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8741 = {
+	.probe			= wm8741_probe,
+	.remove			= wm8741_remove,
+	.resume			= wm8741_resume,
+	.dapm_widgets		= wm8741_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8741_dapm_widgets),
+	.dapm_routes		= wm8741_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8741_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8741_of_match[] = {
@@ -585,18 +584,12 @@ static int wm8741_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8741);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8741, &wm8741_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8741, &wm8741_dai, 1);
 
 	return ret;
 }
 
-static int wm8741_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8741_i2c_id[] = {
 	{ "wm8741", 0 },
 	{ }
@@ -609,7 +602,6 @@ static struct i2c_driver wm8741_i2c_driver = {
 		.of_match_table = wm8741_of_match,
 	},
 	.probe =    wm8741_i2c_probe,
-	.remove =   wm8741_i2c_remove,
 	.id_table = wm8741_i2c_id,
 };
 #endif
@@ -650,24 +642,17 @@ static int wm8741_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8741);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8741, &wm8741_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8741, &wm8741_dai, 1);
 	return ret;
 }
 
-static int wm8741_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8741_spi_driver = {
 	.driver = {
 		.name	= "wm8741",
 		.of_match_table = wm8741_of_match,
 	},
 	.probe		= wm8741_spi_probe,
-	.remove		= wm8741_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 0da2bbaf06d1..97239bc9d253 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -86,7 +86,7 @@ struct wm8750_priv {
 	unsigned int sysclk;
 };
 
-#define wm8750_reset(c)	snd_soc_write(c, WM8750_RESET, 0)
+#define wm8750_reset(c)	snd_soc_component_write(c, WM8750_RESET, 0)
 
 /*
  * WM8750 Controls
@@ -502,8 +502,8 @@ static inline int get_coeff(int mclk, int rate)
 static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 11289600:
@@ -520,7 +520,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -571,7 +571,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8750_IFACE, iface);
+	snd_soc_component_write(component, WM8750_IFACE, iface);
 	return 0;
 }
 
@@ -579,10 +579,10 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
-	u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
+	struct snd_soc_component *component = dai->component;
+	struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8750_IFACE) & 0x1f3;
+	u16 srate = snd_soc_component_read32(component, WM8750_SRATE) & 0x1c0;
 	int coeff = get_coeff(wm8750->sysclk, params_rate(params));
 
 	/* bit size */
@@ -601,9 +601,9 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set iface & srate */
-	snd_soc_write(codec, WM8750_IFACE, iface);
+	snd_soc_component_write(component, WM8750_IFACE, iface);
 	if (coeff >= 0)
-		snd_soc_write(codec, WM8750_SRATE, srate |
+		snd_soc_component_write(component, WM8750_SRATE, srate |
 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
 
 	return 0;
@@ -611,44 +611,44 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8750_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8750_ADCDAC) & 0xfff7;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8750_ADCDAC) & 0xfff7;
 
 	if (mute)
-		snd_soc_write(codec, WM8750_ADCDAC, mute_reg | 0x8);
+		snd_soc_component_write(component, WM8750_ADCDAC, mute_reg | 0x8);
 	else
-		snd_soc_write(codec, WM8750_ADCDAC, mute_reg);
+		snd_soc_component_write(component, WM8750_ADCDAC, mute_reg);
 	return 0;
 }
 
-static int wm8750_set_bias_level(struct snd_soc_codec *codec,
+static int wm8750_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	u16 pwr_reg = snd_soc_read(codec, WM8750_PWR1) & 0xfe3e;
+	u16 pwr_reg = snd_soc_component_read32(component, WM8750_PWR1) & 0xfe3e;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* set vmid to 50k and unmute dac */
-		snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
+		snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x00c0);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_cache_sync(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_cache_sync(component);
 
 			/* Set VMID to 5k */
-			snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
+			snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x01c1);
 
 			/* ...and ramp */
 			msleep(1000);
 		}
 
 		/* mute dac and set vmid to 500k, enable VREF */
-		snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
+		snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x0141);
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, WM8750_PWR1, 0x0001);
+		snd_soc_component_write(component, WM8750_PWR1, 0x0001);
 		break;
 	}
 	return 0;
@@ -685,42 +685,43 @@ static struct snd_soc_dai_driver wm8750_dai = {
 	.ops = &wm8750_dai_ops,
 };
 
-static int wm8750_probe(struct snd_soc_codec *codec)
+static int wm8750_probe(struct snd_soc_component *component)
 {
 	int ret;
 
-	ret = wm8750_reset(codec);
+	ret = wm8750_reset(component);
 	if (ret < 0) {
 		printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
 		return ret;
 	}
 
 	/* set the update bits */
-	snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_LOUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_ROUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_LOUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_ROUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_LINVOL, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8750_RINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LOUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_RINVOL, 0x0100, 0x0100);
 
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
-	.probe =	wm8750_probe,
-	.set_bias_level = wm8750_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8750_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8750_snd_controls),
-		.dapm_widgets		= wm8750_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8750_dapm_widgets),
-		.dapm_routes		= wm8750_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8750_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8750 = {
+	.probe			= wm8750_probe,
+	.set_bias_level		= wm8750_set_bias_level,
+	.controls		= wm8750_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8750_snd_controls),
+	.dapm_widgets		= wm8750_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8750_dapm_widgets),
+	.dapm_routes		= wm8750_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8750_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8750_of_match[] = {
@@ -758,17 +759,11 @@ static int wm8750_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8750);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8750, &wm8750_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8750, &wm8750_dai, 1);
 	return ret;
 }
 
-static int wm8750_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static const struct spi_device_id wm8750_spi_ids[] = {
 	{ "wm8750", 0 },
 	{ "wm8987", 0 },
@@ -783,7 +778,6 @@ static struct spi_driver wm8750_spi_driver = {
 	},
 	.id_table	= wm8750_spi_ids,
 	.probe		= wm8750_spi_probe,
-	.remove		= wm8750_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -806,17 +800,11 @@ static int wm8750_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8750, &wm8750_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8750, &wm8750_dai, 1);
 	return ret;
 }
 
-static int wm8750_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8750_i2c_id[] = {
 	{ "wm8750", 0 },
 	{ "wm8987", 0 },
@@ -830,7 +818,6 @@ static struct i2c_driver wm8750_i2c_driver = {
 		.of_match_table = wm8750_of_match,
 	},
 	.probe =    wm8750_i2c_probe,
-	.remove =   wm8750_i2c_remove,
 	.id_table = wm8750_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 0271a5253bd3..1e2823e2a906 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -55,9 +55,9 @@ static int caps_charge = 2000;
 module_param(caps_charge, int, 0);
 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
 
-static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_hifi_write_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt);
-static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_voice_write_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt);
 
 /*
@@ -150,7 +150,7 @@ struct wm8753_priv {
 	struct delayed_work charge_work;
 };
 
-#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)
+#define wm8753_reset(c) snd_soc_component_write(c, WM8753_RESET, 0)
 
 /*
  * WM8753 Controls
@@ -229,8 +229,8 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
 static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8753->dai_func;
 	return 0;
@@ -239,17 +239,17 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
 static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 	u16 ioctl;
 
 	if (wm8753->dai_func == ucontrol->value.enumerated.item[0])
 		return 0;
 
-	if (snd_soc_codec_is_active(codec))
+	if (snd_soc_component_is_active(component))
 		return -EBUSY;
 
-	ioctl = snd_soc_read(codec, WM8753_IOCTL);
+	ioctl = snd_soc_component_read32(component, WM8753_IOCTL);
 
 	wm8753->dai_func = ucontrol->value.enumerated.item[0];
 
@@ -257,11 +257,11 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
 		return 1;
 
 	ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2);
-	snd_soc_write(codec, WM8753_IOCTL, ioctl);
+	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
 
 
-	wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt);
-	wm8753_voice_write_dai_fmt(codec, wm8753->voice_fmt);
+	wm8753_hifi_write_dai_fmt(component, wm8753->hifi_fmt);
+	wm8753_voice_write_dai_fmt(component, wm8753->voice_fmt);
 
 	return 1;
 }
@@ -745,7 +745,7 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 {
 	u16 reg, enable;
 	int offset;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2)
 		return -ENODEV;
@@ -753,17 +753,17 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 	if (pll_id == WM8753_PLL1) {
 		offset = 0;
 		enable = 0x10;
-		reg = snd_soc_read(codec, WM8753_CLOCK) & 0xffef;
+		reg = snd_soc_component_read32(component, WM8753_CLOCK) & 0xffef;
 	} else {
 		offset = 4;
 		enable = 0x8;
-		reg = snd_soc_read(codec, WM8753_CLOCK) & 0xfff7;
+		reg = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfff7;
 	}
 
 	if (!freq_in || !freq_out) {
 		/* disable PLL  */
-		snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);
-		snd_soc_write(codec, WM8753_CLOCK, reg);
+		snd_soc_component_write(component, WM8753_PLL1CTL1 + offset, 0x0026);
+		snd_soc_component_write(component, WM8753_CLOCK, reg);
 		return 0;
 	} else {
 		u16 value = 0;
@@ -774,20 +774,20 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		/* set up N and K PLL divisor ratios */
 		/* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
 		value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);
-		snd_soc_write(codec, WM8753_PLL1CTL2 + offset, value);
+		snd_soc_component_write(component, WM8753_PLL1CTL2 + offset, value);
 
 		/* bits 8:0 = PLL_K[17:9] */
 		value = (pll_div.k & 0x03fe00) >> 9;
-		snd_soc_write(codec, WM8753_PLL1CTL3 + offset, value);
+		snd_soc_component_write(component, WM8753_PLL1CTL3 + offset, value);
 
 		/* bits 8:0 = PLL_K[8:0] */
 		value = pll_div.k & 0x0001ff;
-		snd_soc_write(codec, WM8753_PLL1CTL4 + offset, value);
+		snd_soc_component_write(component, WM8753_PLL1CTL4 + offset, value);
 
 		/* set PLL as input and enable */
-		snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |
+		snd_soc_component_write(component, WM8753_PLL1CTL1 + offset, 0x0027 |
 			(pll_div.div2 << 3));
-		snd_soc_write(codec, WM8753_CLOCK, reg | enable);
+		snd_soc_component_write(component, WM8753_CLOCK, reg | enable);
 	}
 	return 0;
 }
@@ -866,8 +866,8 @@ static int get_coeff(int mclk, int rate)
 static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 11289600:
@@ -890,10 +890,10 @@ static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 /*
  * Set's ADC and Voice DAC format.
  */
-static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
-	u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec;
+	u16 voice = snd_soc_component_read32(component, WM8753_PCM) & 0x01ec;
 
 	/* interface format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -915,7 +915,7 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8753_PCM, voice);
+	snd_soc_component_write(component, WM8753_PCM, voice);
 	return 0;
 }
 
@@ -926,10 +926,10 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
-	u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
-	u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
+	struct snd_soc_component *component = dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 voice = snd_soc_component_read32(component, WM8753_PCM) & 0x01f3;
+	u16 srate = snd_soc_component_read32(component, WM8753_SRATE1) & 0x017f;
 
 	/* bit size */
 	switch (params_width(params)) {
@@ -949,22 +949,22 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
 	/* sample rate */
 	if (params_rate(params) * 384 == wm8753->pcmclk)
 		srate |= 0x80;
-	snd_soc_write(codec, WM8753_SRATE1, srate);
+	snd_soc_component_write(component, WM8753_SRATE1, srate);
 
-	snd_soc_write(codec, WM8753_PCM, voice);
+	snd_soc_component_write(component, WM8753_PCM, voice);
 	return 0;
 }
 
 /*
  * Set's PCM dai fmt and BCLK.
  */
-static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_pcm_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
 	u16 voice, ioctl;
 
-	voice = snd_soc_read(codec, WM8753_PCM) & 0x011f;
-	ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x015d;
+	voice = snd_soc_component_read32(component, WM8753_PCM) & 0x011f;
+	ioctl = snd_soc_component_read32(component, WM8753_IOCTL) & 0x015d;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1018,29 +1018,29 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8753_PCM, voice);
-	snd_soc_write(codec, WM8753_IOCTL, ioctl);
+	snd_soc_component_write(component, WM8753_PCM, voice);
+	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
 	return 0;
 }
 
 static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8753_PCMDIV:
-		reg = snd_soc_read(codec, WM8753_CLOCK) & 0x003f;
-		snd_soc_write(codec, WM8753_CLOCK, reg | div);
+		reg = snd_soc_component_read32(component, WM8753_CLOCK) & 0x003f;
+		snd_soc_component_write(component, WM8753_CLOCK, reg | div);
 		break;
 	case WM8753_BCLKDIV:
-		reg = snd_soc_read(codec, WM8753_SRATE2) & 0x01c7;
-		snd_soc_write(codec, WM8753_SRATE2, reg | div);
+		reg = snd_soc_component_read32(component, WM8753_SRATE2) & 0x01c7;
+		snd_soc_component_write(component, WM8753_SRATE2, reg | div);
 		break;
 	case WM8753_VXCLKDIV:
-		reg = snd_soc_read(codec, WM8753_SRATE2) & 0x003f;
-		snd_soc_write(codec, WM8753_SRATE2, reg | div);
+		reg = snd_soc_component_read32(component, WM8753_SRATE2) & 0x003f;
+		snd_soc_component_write(component, WM8753_SRATE2, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1051,10 +1051,10 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 /*
  * Set's HiFi DAC format.
  */
-static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_hdac_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
-	u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0;
+	u16 hifi = snd_soc_component_read32(component, WM8753_HIFI) & 0x01e0;
 
 	/* interface format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -1076,20 +1076,20 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8753_HIFI, hifi);
+	snd_soc_component_write(component, WM8753_HIFI, hifi);
 	return 0;
 }
 
 /*
  * Set's I2S DAI format.
  */
-static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_i2s_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
 	u16 ioctl, hifi;
 
-	hifi = snd_soc_read(codec, WM8753_HIFI) & 0x013f;
-	ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae;
+	hifi = snd_soc_component_read32(component, WM8753_HIFI) & 0x013f;
+	ioctl = snd_soc_component_read32(component, WM8753_IOCTL) & 0x00ae;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1143,8 +1143,8 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8753_HIFI, hifi);
-	snd_soc_write(codec, WM8753_IOCTL, ioctl);
+	snd_soc_component_write(component, WM8753_HIFI, hifi);
+	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
 	return 0;
 }
 
@@ -1155,10 +1155,10 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
-	u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
-	u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
+	struct snd_soc_component *component = dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 srate = snd_soc_component_read32(component, WM8753_SRATE1) & 0x01c0;
+	u16 hifi = snd_soc_component_read32(component, WM8753_HIFI) & 0x01f3;
 	int coeff;
 
 	/* is digital filter coefficient valid ? */
@@ -1167,7 +1167,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
 		printk(KERN_ERR "wm8753 invalid MCLK or rate\n");
 		return coeff;
 	}
-	snd_soc_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
+	snd_soc_component_write(component, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
 		coeff_div[coeff].usb);
 
 	/* bit size */
@@ -1185,70 +1185,70 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8753_HIFI, hifi);
+	snd_soc_component_write(component, WM8753_HIFI, hifi);
 	return 0;
 }
 
-static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_mode1v_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
 	u16 clock;
 
 	/* set clk source as pcmclk */
-	clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
-	snd_soc_write(codec, WM8753_CLOCK, clock);
+	clock = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfffb;
+	snd_soc_component_write(component, WM8753_CLOCK, clock);
 
-	return wm8753_vdac_adc_set_dai_fmt(codec, fmt);
+	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
 }
 
-static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_mode1h_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
-	return wm8753_hdac_set_dai_fmt(codec, fmt);
+	return wm8753_hdac_set_dai_fmt(component, fmt);
 }
 
-static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_mode2_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
 	u16 clock;
 
 	/* set clk source as pcmclk */
-	clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
-	snd_soc_write(codec, WM8753_CLOCK, clock);
+	clock = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfffb;
+	snd_soc_component_write(component, WM8753_CLOCK, clock);
 
-	return wm8753_vdac_adc_set_dai_fmt(codec, fmt);
+	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
 }
 
-static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
 	u16 clock;
 
 	/* set clk source as mclk */
-	clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
-	snd_soc_write(codec, WM8753_CLOCK, clock | 0x4);
+	clock = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfffb;
+	snd_soc_component_write(component, WM8753_CLOCK, clock | 0x4);
 
-	if (wm8753_hdac_set_dai_fmt(codec, fmt) < 0)
+	if (wm8753_hdac_set_dai_fmt(component, fmt) < 0)
 		return -EINVAL;
-	return wm8753_vdac_adc_set_dai_fmt(codec, fmt);
+	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
 }
 
-static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_hifi_write_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (wm8753->dai_func) {
 	case 0:
-		ret = wm8753_mode1h_set_dai_fmt(codec, fmt);
+		ret = wm8753_mode1h_set_dai_fmt(component, fmt);
 		break;
 	case 1:
-		ret = wm8753_mode2_set_dai_fmt(codec, fmt);
+		ret = wm8753_mode2_set_dai_fmt(component, fmt);
 		break;
 	case 2:
 	case 3:
-		ret = wm8753_mode3_4_set_dai_fmt(codec, fmt);
+		ret = wm8753_mode3_4_set_dai_fmt(component, fmt);
 		break;
 	default:
 		 break;
@@ -1256,33 +1256,33 @@ static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
 	if (ret)
 		return ret;
 
-	return wm8753_i2s_set_dai_fmt(codec, fmt);
+	return wm8753_i2s_set_dai_fmt(component, fmt);
 }
 
 static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 
 	wm8753->hifi_fmt = fmt;
 
-	return wm8753_hifi_write_dai_fmt(codec, fmt);
+	return wm8753_hifi_write_dai_fmt(component, fmt);
 };
 
-static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
+static int wm8753_voice_write_dai_fmt(struct snd_soc_component *component,
 		unsigned int fmt)
 {
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if (wm8753->dai_func != 0)
 		return 0;
 
-	ret = wm8753_mode1v_set_dai_fmt(codec, fmt);
+	ret = wm8753_mode1v_set_dai_fmt(component, fmt);
 	if (ret)
 		return ret;
-	ret = wm8753_pcm_set_dai_fmt(codec, fmt);
+	ret = wm8753_pcm_set_dai_fmt(component, fmt);
 	if (ret)
 		return ret;
 
@@ -1292,30 +1292,30 @@ static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
 static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 
 	wm8753->voice_fmt = fmt;
 
-	return wm8753_voice_write_dai_fmt(codec, fmt);
+	return wm8753_voice_write_dai_fmt(component, fmt);
 };
 
 static int wm8753_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8753_DAC) & 0xfff7;
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8753_DAC) & 0xfff7;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 
 	/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
 	 * make sure we check if they are not both active when we mute */
 	if (mute && wm8753->dai_func == 1) {
-		if (!snd_soc_codec_is_active(codec))
-			snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
+		if (!snd_soc_component_is_active(component))
+			snd_soc_component_write(component, WM8753_DAC, mute_reg | 0x8);
 	} else {
 		if (mute)
-			snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
+			snd_soc_component_write(component, WM8753_DAC, mute_reg | 0x8);
 		else
-			snd_soc_write(codec, WM8753_DAC, mute_reg);
+			snd_soc_component_write(component, WM8753_DAC, mute_reg);
 	}
 
 	return 0;
@@ -1330,35 +1330,35 @@ static void wm8753_charge_work(struct work_struct *work)
 	regmap_update_bits(wm8753->regmap, WM8753_PWR1, 0x0180, 0x0100);
 }
 
-static int wm8753_set_bias_level(struct snd_soc_codec *codec,
+static int wm8753_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
-	u16 pwr_reg = snd_soc_read(codec, WM8753_PWR1) & 0xfe3e;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8753_PWR1) & 0xfe3e;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* set vmid to 50k and unmute dac */
-		snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
+		snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x00c0);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Wait until fully charged */
 		flush_delayed_work(&wm8753->charge_work);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* set vmid to 5k for quick power up */
-			snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
+			snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x01c1);
 			schedule_delayed_work(&wm8753->charge_work,
 				msecs_to_jiffies(caps_charge));
 		} else {
 			/* mute dac and set vmid to 500k, enable VREF */
-			snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
+			snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x0141);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		cancel_delayed_work_sync(&wm8753->charge_work);
-		snd_soc_write(codec, WM8753_PWR1, 0x0001);
+		snd_soc_component_write(component, WM8753_PWR1, 0x0001);
 		break;
 	}
 	return 0;
@@ -1440,59 +1440,60 @@ static struct snd_soc_dai_driver wm8753_dai[] = {
 },
 };
 
-static int wm8753_resume(struct snd_soc_codec *codec)
+static int wm8753_resume(struct snd_soc_component *component)
 {
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 
 	regcache_sync(wm8753->regmap);
 
 	return 0;
 }
 
-static int wm8753_probe(struct snd_soc_codec *codec)
+static int wm8753_probe(struct snd_soc_component *component)
 {
-	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	INIT_DELAYED_WORK(&wm8753->charge_work, wm8753_charge_work);
 
-	ret = wm8753_reset(codec);
+	ret = wm8753_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		return ret;
 	}
 
 	wm8753->dai_func = 0;
 
 	/* set the update bits */
-	snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_LADC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_RADC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_ROUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LADC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_RADC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LOUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_RINVOL, 0x0100, 0x0100);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
-	.probe =	wm8753_probe,
-	.resume =	wm8753_resume,
-	.set_bias_level = wm8753_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8753_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8753_snd_controls),
-		.dapm_widgets		= wm8753_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8753_dapm_widgets),
-		.dapm_routes		= wm8753_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8753_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8753 = {
+	.probe			= wm8753_probe,
+	.resume			= wm8753_resume,
+	.set_bias_level		= wm8753_set_bias_level,
+	.controls		= wm8753_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8753_snd_controls),
+	.dapm_widgets		= wm8753_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8753_dapm_widgets),
+	.dapm_routes		= wm8753_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8753_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8753_of_match[] = {
@@ -1534,7 +1535,7 @@ static int wm8753_spi_probe(struct spi_device *spi)
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753,
+	ret = devm_snd_soc_register_component(&spi->dev, &soc_component_dev_wm8753,
 				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
 	if (ret != 0)
 		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
@@ -1542,19 +1543,12 @@ static int wm8753_spi_probe(struct spi_device *spi)
 	return ret;
 }
 
-static int wm8753_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8753_spi_driver = {
 	.driver = {
 		.name	= "wm8753",
 		.of_match_table = wm8753_of_match,
 	},
 	.probe		= wm8753_spi_probe,
-	.remove		= wm8753_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -1580,7 +1574,7 @@ static int wm8753_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753,
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_wm8753,
 				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
 	if (ret != 0)
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
@@ -1588,12 +1582,6 @@ static int wm8753_i2c_probe(struct i2c_client *i2c,
 	return ret;
 }
 
-static int wm8753_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8753_i2c_id[] = {
 	{ "wm8753", 0 },
 	{ }
@@ -1606,7 +1594,6 @@ static struct i2c_driver wm8753_i2c_driver = {
 		.of_match_table = wm8753_of_match,
 	},
 	.probe =    wm8753_i2c_probe,
-	.remove =   wm8753_i2c_remove,
 	.id_table = wm8753_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index d6edcbbdec12..806245c70f8b 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -84,7 +84,7 @@ struct wm8770_priv {
 	struct regmap *regmap;
 	struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
 	struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	int sysclk;
 };
 
@@ -308,14 +308,14 @@ static const struct snd_soc_dapm_route wm8770_intercon[] = {
 static int vout12supply_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0);
+		snd_soc_component_update_bits(component, WM8770_OUTMUX1, 0x180, 0);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0x180);
+		snd_soc_component_update_bits(component, WM8770_OUTMUX1, 0x180, 0x180);
 		break;
 	}
 
@@ -325,31 +325,31 @@ static int vout12supply_event(struct snd_soc_dapm_widget *w,
 static int vout34supply_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0);
+		snd_soc_component_update_bits(component, WM8770_OUTMUX2, 0x180, 0);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0x180);
+		snd_soc_component_update_bits(component, WM8770_OUTMUX2, 0x180, 0x180);
 		break;
 	}
 
 	return 0;
 }
 
-static int wm8770_reset(struct snd_soc_codec *codec)
+static int wm8770_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, WM8770_RESET, 0);
+	return snd_soc_component_write(component, WM8770_RESET, 0);
 }
 
 static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	int iface, master;
 
-	codec = dai->codec;
+	component = dai->component;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -392,8 +392,8 @@ static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8770_IFACECTRL, 0xf, iface);
-	snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x100, master);
+	snd_soc_component_update_bits(component, WM8770_IFACECTRL, 0xf, iface);
+	snd_soc_component_update_bits(component, WM8770_MSTRCTRL, 0x100, master);
 
 	return 0;
 }
@@ -411,15 +411,15 @@ static int wm8770_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8770_priv *wm8770;
 	int i;
 	int iface;
 	int shift;
 	int ratio;
 
-	codec = dai->codec;
-	wm8770 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8770 = snd_soc_component_get_drvdata(component);
 
 	iface = 0;
 	switch (params_width(params)) {
@@ -450,7 +450,7 @@ static int wm8770_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* Only need to set MCLK/LRCLK ratio if we're master */
-	if (snd_soc_read(codec, WM8770_MSTRCTRL) & 0x100) {
+	if (snd_soc_component_read32(component, WM8770_MSTRCTRL) & 0x100) {
 		for (; i < ARRAY_SIZE(mclk_ratios); ++i) {
 			ratio = wm8770->sysclk / params_rate(params);
 			if (ratio == mclk_ratios[i])
@@ -458,51 +458,51 @@ static int wm8770_hw_params(struct snd_pcm_substream *substream,
 		}
 
 		if (i == ARRAY_SIZE(mclk_ratios)) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Unable to configure MCLK ratio %d/%d\n",
 				wm8770->sysclk, params_rate(params));
 			return -EINVAL;
 		}
 
-		dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);
+		dev_dbg(component->dev, "MCLK is %dfs\n", mclk_ratios[i]);
 
-		snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x7 << shift,
+		snd_soc_component_update_bits(component, WM8770_MSTRCTRL, 0x7 << shift,
 				    i << shift);
 	}
 
-	snd_soc_update_bits(codec, WM8770_IFACECTRL, 0x30, iface);
+	snd_soc_component_update_bits(component, WM8770_IFACECTRL, 0x30, iface);
 
 	return 0;
 }
 
 static int wm8770_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
-	codec = dai->codec;
-	return snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10,
+	component = dai->component;
+	return snd_soc_component_update_bits(component, WM8770_DACMUTE, 0x10,
 				   !!mute << 4);
 }
 
 static int wm8770_set_sysclk(struct snd_soc_dai *dai,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8770_priv *wm8770;
 
-	codec = dai->codec;
-	wm8770 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8770 = snd_soc_component_get_drvdata(component);
 	wm8770->sysclk = freq;
 	return 0;
 }
 
-static int wm8770_set_bias_level(struct snd_soc_codec *codec,
+static int wm8770_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	int ret;
 	struct wm8770_priv *wm8770;
 
-	wm8770 = snd_soc_codec_get_drvdata(codec);
+	wm8770 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -510,11 +510,11 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
 						    wm8770->supplies);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -523,12 +523,12 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
 			regcache_sync(wm8770->regmap);
 
 			/* global powerup */
-			snd_soc_write(codec, WM8770_PWDNCTRL, 0);
+			snd_soc_component_write(component, WM8770_PWDNCTRL, 0);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* global powerdown */
-		snd_soc_write(codec, WM8770_PWDNCTRL, 1);
+		snd_soc_component_write(component, WM8770_PWDNCTRL, 1);
 		regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies),
 				       wm8770->supplies);
 		break;
@@ -567,60 +567,59 @@ static struct snd_soc_dai_driver wm8770_dai = {
 	.symmetric_rates = 1
 };
 
-static int wm8770_probe(struct snd_soc_codec *codec)
+static int wm8770_probe(struct snd_soc_component *component)
 {
 	struct wm8770_priv *wm8770;
 	int ret;
 
-	wm8770 = snd_soc_codec_get_drvdata(codec);
-	wm8770->codec = codec;
+	wm8770 = snd_soc_component_get_drvdata(component);
+	wm8770->component = component;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
 				    wm8770->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
-	ret = wm8770_reset(codec);
+	ret = wm8770_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		goto err_reg_enable;
 	}
 
 	/* latch the volume update bits */
-	snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_VOUT1RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_VOUT2RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_VOUT3RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_VOUT4RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_DAC1RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_DAC2RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_DAC3RVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8770_DAC4RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_MSDIGVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_MSALGVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT1RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT2RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT3RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT4RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC1RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC2RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC3RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC4RVOL, 0x100, 0x100);
 
 	/* mute all DACs */
-	snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10);
+	snd_soc_component_update_bits(component, WM8770_DACMUTE, 0x10, 0x10);
 
 err_reg_enable:
 	regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
-	.probe = wm8770_probe,
-	.set_bias_level = wm8770_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8770_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8770_snd_controls),
-		.dapm_widgets		= wm8770_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8770_dapm_widgets),
-		.dapm_routes		= wm8770_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(wm8770_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8770 = {
+	.probe			= wm8770_probe,
+	.set_bias_level		= wm8770_set_bias_level,
+	.controls		= wm8770_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8770_snd_controls),
+	.dapm_widgets		= wm8770_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8770_dapm_widgets),
+	.dapm_routes		= wm8770_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8770_intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8770_of_match[] = {
@@ -682,8 +681,8 @@ static int wm8770_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8770);
 
-	ret = snd_soc_register_codec(&spi->dev,
-				     &soc_codec_dev_wm8770, &wm8770_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm8770, &wm8770_dai, 1);
 
 	return ret;
 }
@@ -697,8 +696,6 @@ static int wm8770_spi_remove(struct spi_device *spi)
 		regulator_unregister_notifier(wm8770->supplies[i].consumer,
 					      &wm8770->disable_nb[i]);
 
-	snd_soc_unregister_codec(&spi->dev);
-
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index ae30480b3976..fb357e23f221 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -78,9 +78,9 @@ static bool wm8776_volatile(struct device *dev, unsigned int reg)
 	}
 }
 
-static int wm8776_reset(struct snd_soc_codec *codec)
+static int wm8776_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, WM8776_RESET, 0);
+	return snd_soc_component_write(component, WM8776_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1);
@@ -166,7 +166,7 @@ static const struct snd_soc_dapm_route routes[] = {
 
 static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int reg, iface, master;
 
 	switch (dai->driver->id) {
@@ -224,8 +224,8 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	/* Finally, write out the values */
-	snd_soc_update_bits(codec, reg, 0xf, iface);
-	snd_soc_update_bits(codec, WM8776_MSTRCTRL, 0x180, master);
+	snd_soc_component_update_bits(component, reg, 0xf, iface);
+	snd_soc_component_update_bits(component, WM8776_MSTRCTRL, 0x180, master);
 
 	return 0;
 }
@@ -243,8 +243,8 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
 	int iface_reg, iface;
 	int ratio_shift, master;
 	int i;
@@ -279,13 +279,13 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
 		iface = 0x30;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported sample size: %i\n",
+		dev_err(component->dev, "Unsupported sample size: %i\n",
 			params_width(params));
 		return -EINVAL;
 	}
 
 	/* Only need to set MCLK/LRCLK ratio if we're master */
-	if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
+	if (snd_soc_component_read32(component, WM8776_MSTRCTRL) & master) {
 		for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
 			if (wm8776->sysclk[dai->driver->id] / params_rate(params)
 			    == mclk_ratios[i])
@@ -293,37 +293,37 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
 		}
 
 		if (i == ARRAY_SIZE(mclk_ratios)) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Unable to configure MCLK ratio %d/%d\n",
 				wm8776->sysclk[dai->driver->id], params_rate(params));
 			return -EINVAL;
 		}
 
-		dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);
+		dev_dbg(component->dev, "MCLK is %dfs\n", mclk_ratios[i]);
 
-		snd_soc_update_bits(codec, WM8776_MSTRCTRL,
+		snd_soc_component_update_bits(component, WM8776_MSTRCTRL,
 				    0x7 << ratio_shift, i << ratio_shift);
 	} else {
-		dev_dbg(codec->dev, "DAI in slave mode\n");
+		dev_dbg(component->dev, "DAI in slave mode\n");
 	}
 
-	snd_soc_update_bits(codec, iface_reg, 0x30, iface);
+	snd_soc_component_update_bits(component, iface_reg, 0x30, iface);
 
 	return 0;
 }
 
 static int wm8776_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	return snd_soc_write(codec, WM8776_DACMUTE, !!mute);
+	return snd_soc_component_write(component, WM8776_DACMUTE, !!mute);
 }
 
 static int wm8776_set_sysclk(struct snd_soc_dai *dai,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
 
 	if (WARN_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk)))
 		return -EINVAL;
@@ -333,10 +333,10 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static int wm8776_set_bias_level(struct snd_soc_codec *codec,
+static int wm8776_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
+	struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -344,16 +344,16 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_sync(wm8776->regmap);
 
 			/* Disable the global powerdown; DAPM does the rest */
-			snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
+			snd_soc_component_update_bits(component, WM8776_PWRDOWN, 1, 0);
 		}
 
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 1);
+		snd_soc_component_update_bits(component, WM8776_PWRDOWN, 1, 1);
 		break;
 	}
 
@@ -407,37 +407,38 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
 	},
 };
 
-static int wm8776_probe(struct snd_soc_codec *codec)
+static int wm8776_probe(struct snd_soc_component *component)
 {
 	int ret = 0;
 
-	ret = wm8776_reset(codec);
+	ret = wm8776_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		return ret;
 	}
 
 	/* Latch the update bits; right channel only since we always
 	 * update both. */
-	snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8776_HPRVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8776_DACRVOL, 0x100, 0x100);
 
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
-	.probe = 	wm8776_probe,
-	.set_bias_level = wm8776_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8776_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8776_snd_controls),
-		.dapm_widgets		= wm8776_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8776_dapm_widgets),
-		.dapm_routes		= routes,
-		.num_dapm_routes	= ARRAY_SIZE(routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8776 = {
+	.probe			= wm8776_probe,
+	.set_bias_level		= wm8776_set_bias_level,
+	.controls		= wm8776_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8776_snd_controls),
+	.dapm_widgets		= wm8776_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8776_dapm_widgets),
+	.dapm_routes		= routes,
+	.num_dapm_routes	= ARRAY_SIZE(routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct of_device_id wm8776_of_match[] = {
@@ -475,25 +476,18 @@ static int wm8776_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8776);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
 
 	return ret;
 }
 
-static int wm8776_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8776_spi_driver = {
 	.driver = {
 		.name	= "wm8776",
 		.of_match_table = wm8776_of_match,
 	},
 	.probe		= wm8776_spi_probe,
-	.remove		= wm8776_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -515,18 +509,12 @@ static int wm8776_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8776);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
 
 	return ret;
 }
 
-static int wm8776_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8776_i2c_id[] = {
 	{ "wm8775", WM8775 },
 	{ "wm8776", WM8776 },
@@ -540,7 +528,6 @@ static struct i2c_driver wm8776_i2c_driver = {
 		.of_match_table = wm8776_of_match,
 	},
 	.probe =    wm8776_i2c_probe,
-	.remove =   wm8776_i2c_remove,
 	.id_table = wm8776_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index bcda21018505..7949703f3d04 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -50,25 +50,21 @@ static struct snd_soc_dai_driver wm8782_dai = {
 	},
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8782 = {
-	.component_driver = {
-		.dapm_widgets		= wm8782_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8782_dapm_widgets),
-		.dapm_routes		= wm8782_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8782_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
+	.dapm_widgets		= wm8782_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8782_dapm_widgets),
+	.dapm_routes		= wm8782_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8782_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8782_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_wm8782, &wm8782_dai, 1);
-}
-
-static int wm8782_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8782, &wm8782_dai, 1);
 }
 
 static struct platform_driver wm8782_codec_driver = {
@@ -76,7 +72,6 @@ static struct platform_driver wm8782_codec_driver = {
 		.name = "wm8782",
 	},
 	.probe = wm8782_probe,
-	.remove = wm8782_remove,
 };
 
 module_platform_driver(wm8782_codec_driver);
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index fc69b87443d8..89f13249966e 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -137,21 +137,21 @@ static const struct snd_soc_dapm_route wm8804_dapm_routes[] = {
 static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8804_priv *wm8804 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8804_priv *wm8804 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/* power up the aif */
 		if (!wm8804->aif_pwr)
-			snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0x0);
+			snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x0);
 		wm8804->aif_pwr++;
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		/* power down only both paths are disabled */
 		wm8804->aif_pwr--;
 		if (!wm8804->aif_pwr)
-			snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0x10);
+			snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x10);
 		break;
 	}
 
@@ -161,8 +161,8 @@ static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
 static int txsrc_put(struct snd_kcontrol *kcontrol,
 		     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l;
 	unsigned int mask = 1 << e->shift_l;
@@ -173,18 +173,18 @@ static int txsrc_put(struct snd_kcontrol *kcontrol,
 
 	snd_soc_dapm_mutex_lock(dapm);
 
-	if (snd_soc_test_bits(codec, e->reg, mask, val)) {
+	if (snd_soc_component_test_bits(component, e->reg, mask, val)) {
 		/* save the current power state of the transmitter */
-		txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
+		txpwr = snd_soc_component_read32(component, WM8804_PWRDN) & 0x4;
 
 		/* power down the transmitter */
-		snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
+		snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x4);
 
 		/* set the tx source */
-		snd_soc_update_bits(codec, e->reg, mask, val);
+		snd_soc_component_update_bits(component, e->reg, mask, val);
 
 		/* restore the transmitter's configuration */
-		snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
+		snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, txpwr);
 	}
 
 	snd_soc_dapm_mutex_unlock(dapm);
@@ -218,10 +218,10 @@ static int wm8804_soft_reset(struct wm8804_priv *wm8804)
 
 static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	u16 format, master, bcp, lrp;
 
-	codec = dai->codec;
+	component = dai->component;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
@@ -243,8 +243,8 @@ static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	/* set data format */
-	snd_soc_update_bits(codec, WM8804_AIFTX, 0x3, format);
-	snd_soc_update_bits(codec, WM8804_AIFRX, 0x3, format);
+	snd_soc_component_update_bits(component, WM8804_AIFTX, 0x3, format);
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0x3, format);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -259,7 +259,7 @@ static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	/* set master/slave mode */
-	snd_soc_update_bits(codec, WM8804_AIFRX, 0x40, master << 6);
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0x40, master << 6);
 
 	bcp = lrp = 0;
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -280,9 +280,9 @@ static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	}
 
 	/* set frame inversion */
-	snd_soc_update_bits(codec, WM8804_AIFTX, 0x10 | 0x20,
+	snd_soc_component_update_bits(component, WM8804_AIFTX, 0x10 | 0x20,
 			    (bcp << 4) | (lrp << 5));
-	snd_soc_update_bits(codec, WM8804_AIFRX, 0x10 | 0x20,
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0x10 | 0x20,
 			    (bcp << 4) | (lrp << 5));
 	return 0;
 }
@@ -291,10 +291,10 @@ static int wm8804_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	u16 blen;
 
-	codec = dai->codec;
+	component = dai->component;
 
 	switch (params_width(params)) {
 	case 16:
@@ -313,8 +313,8 @@ static int wm8804_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set word length */
-	snd_soc_update_bits(codec, WM8804_AIFTX, 0xc, blen << 2);
-	snd_soc_update_bits(codec, WM8804_AIFRX, 0xc, blen << 2);
+	snd_soc_component_update_bits(component, WM8804_AIFTX, 0xc, blen << 2);
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0xc, blen << 2);
 
 	return 0;
 }
@@ -405,8 +405,8 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
 			  int source, unsigned int freq_in,
 			  unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8804_priv *wm8804 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8804_priv *wm8804 = snd_soc_component_get_drvdata(component);
 	bool change;
 
 	if (!freq_in || !freq_out) {
@@ -431,18 +431,18 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
 			pm_runtime_get_sync(wm8804->dev);
 
 		/* set PLLN and PRESCALE */
-		snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
+		snd_soc_component_update_bits(component, WM8804_PLL4, 0xf | 0x10,
 				    pll_div.n | (pll_div.prescale << 4));
 		/* set mclkdiv and freqmode */
-		snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
+		snd_soc_component_update_bits(component, WM8804_PLL5, 0x3 | 0x8,
 				    pll_div.freqmode | (pll_div.mclkdiv << 3));
 		/* set PLLK */
-		snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
-		snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
-		snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
+		snd_soc_component_write(component, WM8804_PLL1, pll_div.k & 0xff);
+		snd_soc_component_write(component, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+		snd_soc_component_write(component, WM8804_PLL3, pll_div.k >> 16);
 
 		/* power up the PLL */
-		snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
+		snd_soc_component_update_bits(component, WM8804_PWRDN, 0x1, 0);
 	}
 
 	return 0;
@@ -451,15 +451,15 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
 static int wm8804_set_sysclk(struct snd_soc_dai *dai,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
-	codec = dai->codec;
+	component = dai->component;
 
 	switch (clk_id) {
 	case WM8804_TX_CLKSRC_MCLK:
 		if ((freq >= 10000000 && freq <= 14400000)
 				|| (freq >= 16280000 && freq <= 27000000))
-			snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0x80);
+			snd_soc_component_update_bits(component, WM8804_PLL6, 0x80, 0x80);
 		else {
 			dev_err(dai->dev, "OSCCLOCK is not within the "
 				"recommended range: %uHz\n", freq);
@@ -467,13 +467,13 @@ static int wm8804_set_sysclk(struct snd_soc_dai *dai,
 		}
 		break;
 	case WM8804_TX_CLKSRC_PLL:
-		snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0);
+		snd_soc_component_update_bits(component, WM8804_PLL6, 0x80, 0);
 		break;
 	case WM8804_CLKOUT_SRC_CLK1:
-		snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0);
+		snd_soc_component_update_bits(component, WM8804_PLL6, 0x8, 0);
 		break;
 	case WM8804_CLKOUT_SRC_OSCCLK:
-		snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0x8);
+		snd_soc_component_update_bits(component, WM8804_PLL6, 0x8, 0x8);
 		break;
 	default:
 		dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
@@ -486,17 +486,17 @@ static int wm8804_set_sysclk(struct snd_soc_dai *dai,
 static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
 			     int div_id, int div)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8804_priv *wm8804;
 
-	codec = dai->codec;
+	component = dai->component;
 	switch (div_id) {
 	case WM8804_CLKOUT_DIV:
-		snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
+		snd_soc_component_update_bits(component, WM8804_PLL5, 0x30,
 				    (div & 0x3) << 4);
 		break;
 	case WM8804_MCLK_DIV:
-		wm8804 = snd_soc_codec_get_drvdata(codec);
+		wm8804 = snd_soc_component_get_drvdata(component);
 		wm8804->mclk_div = div;
 		break;
 	default:
@@ -542,15 +542,14 @@ static struct snd_soc_dai_driver wm8804_dai = {
 	.symmetric_rates = 1
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.dapm_widgets		= wm8804_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8804_dapm_widgets),
-		.dapm_routes		= wm8804_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8804_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8804 = {
+	.dapm_widgets		= wm8804_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8804_dapm_widgets),
+	.dapm_routes		= wm8804_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8804_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 const struct regmap_config wm8804_regmap_config = {
@@ -661,7 +660,7 @@ int wm8804_probe(struct device *dev, struct regmap *regmap)
 		}
 	}
 
-	ret = snd_soc_register_codec(dev, &soc_codec_dev_wm8804,
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_wm8804,
 				     &wm8804_dai, 1);
 	if (ret < 0) {
 		dev_err(dev, "Failed to register CODEC: %d\n", ret);
@@ -683,7 +682,6 @@ EXPORT_SYMBOL_GPL(wm8804_probe);
 void wm8804_remove(struct device *dev)
 {
 	pm_runtime_disable(dev);
-	snd_soc_unregister_codec(dev);
 }
 EXPORT_SYMBOL_GPL(wm8804_remove);
 
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index c77b49a29311..1a14e902949d 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -216,23 +216,23 @@ static bool wm8900_volatile_register(struct device *dev, unsigned int reg)
 	}
 }
 
-static void wm8900_reset(struct snd_soc_codec *codec)
+static void wm8900_reset(struct snd_soc_component *component)
 {
-	snd_soc_write(codec, WM8900_REG_RESET, 0);
+	snd_soc_component_write(component, WM8900_REG_RESET, 0);
 }
 
 static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 hpctl1 = snd_soc_component_read32(component, WM8900_REG_HPCTL1);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Clamp headphone outputs */
 		hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
 			WM8900_REG_HPCTL1_HP_CLAMP_OP;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
@@ -241,41 +241,41 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
 		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
 			WM8900_REG_HPCTL1_HP_SHORT2 |
 			WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 
 		msleep(400);
 
 		/* Enable the output stage */
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
 		hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 
 		/* Remove the shorts */
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Short the output */
 		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 
 		/* Disable the output stage */
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 
 		/* Clamp the outputs and power down input */
 		hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
 			WM8900_REG_HPCTL1_HP_CLAMP_OP;
 		hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
-		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		/* Disable everything */
-		snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
 		break;
 
 	default:
@@ -635,10 +635,10 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 reg;
 
-	reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
+	reg = snd_soc_component_read32(component, WM8900_REG_AUDIO1) & ~0x60;
 
 	switch (params_width(params)) {
 	case 16:
@@ -656,17 +656,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8900_REG_AUDIO1, reg);
+	snd_soc_component_write(component, WM8900_REG_AUDIO1, reg);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
+		reg = snd_soc_component_read32(component, WM8900_REG_DACCTRL);
 
 		if (params_rate(params) <= 24000)
 			reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
 		else
 			reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
 
-		snd_soc_write(codec, WM8900_REG_DACCTRL, reg);
+		snd_soc_component_write(component, WM8900_REG_DACCTRL, reg);
 	}
 
 	return 0;
@@ -751,24 +751,24 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm8900_set_fll(struct snd_soc_codec *codec,
+static int wm8900_set_fll(struct snd_soc_component *component,
 	int fll_id, unsigned int freq_in, unsigned int freq_out)
 {
-	struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+	struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
 	struct _fll_div fll_div;
 
 	if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
 		return 0;
 
 	/* The digital side should be disabled during any change. */
-	snd_soc_update_bits(codec, WM8900_REG_POWER1,
+	snd_soc_component_update_bits(component, WM8900_REG_POWER1,
 			    WM8900_REG_POWER1_FLL_ENA, 0);
 
 	/* Disable the FLL? */
 	if (!freq_in || !freq_out) {
-		snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
 				    WM8900_REG_CLOCKING1_MCLK_SRC, 0);
-		snd_soc_update_bits(codec, WM8900_REG_FLLCTL1,
+		snd_soc_component_update_bits(component, WM8900_REG_FLLCTL1,
 				    WM8900_REG_FLLCTL1_OSC_ENA, 0);
 		wm8900->fll_in = freq_in;
 		wm8900->fll_out = freq_out;
@@ -784,32 +784,32 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
 
 	/* The osclilator *MUST* be enabled before we enable the
 	 * digital circuit. */
-	snd_soc_write(codec, WM8900_REG_FLLCTL1,
+	snd_soc_component_write(component, WM8900_REG_FLLCTL1,
 		     fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
 
-	snd_soc_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5);
-	snd_soc_write(codec, WM8900_REG_FLLCTL5,
+	snd_soc_component_write(component, WM8900_REG_FLLCTL4, fll_div.n >> 5);
+	snd_soc_component_write(component, WM8900_REG_FLLCTL5,
 		     (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
 
 	if (fll_div.k) {
-		snd_soc_write(codec, WM8900_REG_FLLCTL2,
+		snd_soc_component_write(component, WM8900_REG_FLLCTL2,
 			     (fll_div.k >> 8) | 0x100);
-		snd_soc_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
+		snd_soc_component_write(component, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
 	} else
-		snd_soc_write(codec, WM8900_REG_FLLCTL2, 0);
+		snd_soc_component_write(component, WM8900_REG_FLLCTL2, 0);
 
 	if (fll_div.fll_slow_lock_ref)
-		snd_soc_write(codec, WM8900_REG_FLLCTL6,
+		snd_soc_component_write(component, WM8900_REG_FLLCTL6,
 			     WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
 	else
-		snd_soc_write(codec, WM8900_REG_FLLCTL6, 0);
+		snd_soc_component_write(component, WM8900_REG_FLLCTL6, 0);
 
-	snd_soc_update_bits(codec, WM8900_REG_POWER1,
+	snd_soc_component_update_bits(component, WM8900_REG_POWER1,
 			    WM8900_REG_POWER1_FLL_ENA,
 			    WM8900_REG_POWER1_FLL_ENA);
 
 reenable:
-	snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+	snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
 			    WM8900_REG_CLOCKING1_MCLK_SRC,
 			    WM8900_REG_CLOCKING1_MCLK_SRC);
 	return 0;
@@ -818,41 +818,41 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
 static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out);
+	return wm8900_set_fll(codec_dai->component, pll_id, freq_in, freq_out);
 }
 
 static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 				 int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	switch (div_id) {
 	case WM8900_BCLK_DIV:
-		snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
 				    WM8900_REG_CLOCKING1_BCLK_MASK, div);
 		break;
 	case WM8900_OPCLK_DIV:
-		snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
 				    WM8900_REG_CLOCKING1_OPCLK_MASK, div);
 		break;
 	case WM8900_DAC_LRCLK:
-		snd_soc_update_bits(codec, WM8900_REG_AUDIO4,
+		snd_soc_component_update_bits(component, WM8900_REG_AUDIO4,
 				    WM8900_LRC_MASK, div);
 		break;
 	case WM8900_ADC_LRCLK:
-		snd_soc_update_bits(codec, WM8900_REG_AUDIO3,
+		snd_soc_component_update_bits(component, WM8900_REG_AUDIO3,
 				    WM8900_LRC_MASK, div);
 		break;
 	case WM8900_DAC_CLKDIV:
-		snd_soc_update_bits(codec, WM8900_REG_CLOCKING2,
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING2,
 				    WM8900_REG_CLOCKING2_DAC_CLKDIV, div);
 		break;
 	case WM8900_ADC_CLKDIV:
-		snd_soc_update_bits(codec, WM8900_REG_CLOCKING2,
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING2,
 				    WM8900_REG_CLOCKING2_ADC_CLKDIV, div);
 		break;
 	case WM8900_LRCLK_MODE:
-		snd_soc_update_bits(codec, WM8900_REG_DACCTRL,
+		snd_soc_component_update_bits(component, WM8900_REG_DACCTRL,
 				    WM8900_REG_DACCTRL_AIF_LRCLKRATE, div);
 		break;
 	default:
@@ -866,13 +866,13 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int clocking1, aif1, aif3, aif4;
 
-	clocking1 = snd_soc_read(codec, WM8900_REG_CLOCKING1);
-	aif1 = snd_soc_read(codec, WM8900_REG_AUDIO1);
-	aif3 = snd_soc_read(codec, WM8900_REG_AUDIO3);
-	aif4 = snd_soc_read(codec, WM8900_REG_AUDIO4);
+	clocking1 = snd_soc_component_read32(component, WM8900_REG_CLOCKING1);
+	aif1 = snd_soc_component_read32(component, WM8900_REG_AUDIO1);
+	aif3 = snd_soc_component_read32(component, WM8900_REG_AUDIO3);
+	aif4 = snd_soc_component_read32(component, WM8900_REG_AUDIO4);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -968,27 +968,27 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8900_REG_CLOCKING1, clocking1);
-	snd_soc_write(codec, WM8900_REG_AUDIO1, aif1);
-	snd_soc_write(codec, WM8900_REG_AUDIO3, aif3);
-	snd_soc_write(codec, WM8900_REG_AUDIO4, aif4);
+	snd_soc_component_write(component, WM8900_REG_CLOCKING1, clocking1);
+	snd_soc_component_write(component, WM8900_REG_AUDIO1, aif1);
+	snd_soc_component_write(component, WM8900_REG_AUDIO3, aif3);
+	snd_soc_component_write(component, WM8900_REG_AUDIO4, aif4);
 
 	return 0;
 }
 
 static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
-	reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
+	reg = snd_soc_component_read32(component, WM8900_REG_DACCTRL);
 
 	if (mute)
 		reg |= WM8900_REG_DACCTRL_MUTE;
 	else
 		reg &= ~WM8900_REG_DACCTRL_MUTE;
 
-	snd_soc_write(codec, WM8900_REG_DACCTRL, reg);
+	snd_soc_component_write(component, WM8900_REG_DACCTRL, reg);
 
 	return 0;
 }
@@ -1028,7 +1028,7 @@ static struct snd_soc_dai_driver wm8900_dai = {
 	.ops = &wm8900_dai_ops,
 };
 
-static int wm8900_set_bias_level(struct snd_soc_codec *codec,
+static int wm8900_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	u16 reg;
@@ -1036,10 +1036,10 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* Enable thermal shutdown */
-		snd_soc_update_bits(codec, WM8900_REG_GPIO,
+		snd_soc_component_update_bits(component, WM8900_REG_GPIO,
 				    WM8900_REG_GPIO_TEMP_ENA,
 				    WM8900_REG_GPIO_TEMP_ENA);
-		snd_soc_update_bits(codec, WM8900_REG_ADDCTL,
+		snd_soc_component_update_bits(component, WM8900_REG_ADDCTL,
 				    WM8900_REG_ADDCTL_TEMP_SD,
 				    WM8900_REG_ADDCTL_TEMP_SD);
 		break;
@@ -1049,113 +1049,113 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		/* Charge capacitors if initial power up */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* STARTUP_BIAS_ENA on */
-			snd_soc_write(codec, WM8900_REG_POWER1,
+			snd_soc_component_write(component, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
 
 			/* Startup bias mode */
-			snd_soc_write(codec, WM8900_REG_ADDCTL,
+			snd_soc_component_write(component, WM8900_REG_ADDCTL,
 				     WM8900_REG_ADDCTL_BIAS_SRC |
 				     WM8900_REG_ADDCTL_VMID_SOFTST);
 
 			/* VMID 2x50k */
-			snd_soc_write(codec, WM8900_REG_POWER1,
+			snd_soc_component_write(component, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
 
 			/* Allow capacitors to charge */
 			schedule_timeout_interruptible(msecs_to_jiffies(400));
 
 			/* Enable bias */
-			snd_soc_write(codec, WM8900_REG_POWER1,
+			snd_soc_component_write(component, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_STARTUP_BIAS_ENA |
 				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
 
-			snd_soc_write(codec, WM8900_REG_ADDCTL, 0);
+			snd_soc_component_write(component, WM8900_REG_ADDCTL, 0);
 
-			snd_soc_write(codec, WM8900_REG_POWER1,
+			snd_soc_component_write(component, WM8900_REG_POWER1,
 				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
 		}
 
-		reg = snd_soc_read(codec, WM8900_REG_POWER1);
-		snd_soc_write(codec, WM8900_REG_POWER1,
+		reg = snd_soc_component_read32(component, WM8900_REG_POWER1);
+		snd_soc_component_write(component, WM8900_REG_POWER1,
 			     (reg & WM8900_REG_POWER1_FLL_ENA) |
 			     WM8900_REG_POWER1_BIAS_ENA | 0x1);
-		snd_soc_write(codec, WM8900_REG_POWER2,
+		snd_soc_component_write(component, WM8900_REG_POWER2,
 			     WM8900_REG_POWER2_SYSCLK_ENA);
-		snd_soc_write(codec, WM8900_REG_POWER3, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER3, 0);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Startup bias enable */
-		reg = snd_soc_read(codec, WM8900_REG_POWER1);
-		snd_soc_write(codec, WM8900_REG_POWER1,
+		reg = snd_soc_component_read32(component, WM8900_REG_POWER1);
+		snd_soc_component_write(component, WM8900_REG_POWER1,
 			     reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
-		snd_soc_write(codec, WM8900_REG_ADDCTL,
+		snd_soc_component_write(component, WM8900_REG_ADDCTL,
 			     WM8900_REG_ADDCTL_BIAS_SRC |
 			     WM8900_REG_ADDCTL_VMID_SOFTST);
 
 		/* Discharge caps */
-		snd_soc_write(codec, WM8900_REG_POWER1,
+		snd_soc_component_write(component, WM8900_REG_POWER1,
 			     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
 		schedule_timeout_interruptible(msecs_to_jiffies(500));
 
 		/* Remove clamp */
-		snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
 
 		/* Power down */
-		snd_soc_write(codec, WM8900_REG_ADDCTL, 0);
-		snd_soc_write(codec, WM8900_REG_POWER1, 0);
-		snd_soc_write(codec, WM8900_REG_POWER2, 0);
-		snd_soc_write(codec, WM8900_REG_POWER3, 0);
+		snd_soc_component_write(component, WM8900_REG_ADDCTL, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER1, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER2, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER3, 0);
 
 		/* Need to let things settle before stopping the clock
 		 * to ensure that restart works, see "Stopping the
 		 * master clock" in the datasheet. */
 		schedule_timeout_interruptible(msecs_to_jiffies(1));
-		snd_soc_write(codec, WM8900_REG_POWER2,
+		snd_soc_component_write(component, WM8900_REG_POWER2,
 			     WM8900_REG_POWER2_SYSCLK_ENA);
 		break;
 	}
 	return 0;
 }
 
-static int wm8900_suspend(struct snd_soc_codec *codec)
+static int wm8900_suspend(struct snd_soc_component *component)
 {
-	struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+	struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
 	int fll_out = wm8900->fll_out;
 	int fll_in  = wm8900->fll_in;
 	int ret;
 
 	/* Stop the FLL in an orderly fashion */
-	ret = wm8900_set_fll(codec, 0, 0, 0);
+	ret = wm8900_set_fll(component, 0, 0, 0);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to stop FLL\n");
+		dev_err(component->dev, "Failed to stop FLL\n");
 		return ret;
 	}
 
 	wm8900->fll_out = fll_out;
 	wm8900->fll_in = fll_in;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
 
-static int wm8900_resume(struct snd_soc_codec *codec)
+static int wm8900_resume(struct snd_soc_component *component)
 {
-	struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+	struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	wm8900_reset(codec);
+	wm8900_reset(component);
 
 	ret = regcache_sync(wm8900->regmap);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to restore cache: %d\n", ret);
+		dev_err(component->dev, "Failed to restore cache: %d\n", ret);
 		return ret;
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* Restart the FLL? */
 	if (wm8900->fll_out) {
@@ -1165,9 +1165,9 @@ static int wm8900_resume(struct snd_soc_codec *codec)
 		wm8900->fll_in = 0;
 		wm8900->fll_out = 0;
 
-		ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
+		ret = wm8900_set_fll(component, 0, fll_in, fll_out);
 		if (ret != 0) {
-			dev_err(codec->dev, "Failed to restart FLL\n");
+			dev_err(component->dev, "Failed to restart FLL\n");
 			return ret;
 		}
 	}
@@ -1175,53 +1175,54 @@ static int wm8900_resume(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int wm8900_probe(struct snd_soc_codec *codec)
+static int wm8900_probe(struct snd_soc_component *component)
 {
 	int reg;
 
-	reg = snd_soc_read(codec, WM8900_REG_ID);
+	reg = snd_soc_component_read32(component, WM8900_REG_ID);
 	if (reg != 0x8900) {
-		dev_err(codec->dev, "Device is not a WM8900 - ID %x\n", reg);
+		dev_err(component->dev, "Device is not a WM8900 - ID %x\n", reg);
 		return -ENODEV;
 	}
 
-	wm8900_reset(codec);
+	wm8900_reset(component);
 
 	/* Turn the chip on */
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* Latch the volume update bits */
-	snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_RINVOL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_LOUT1CTL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_ROUT1CTL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_LOUT2CTL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_ROUT2CTL, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_LDAC_DV, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_RDAC_DV, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_LADC_DV, 0x100, 0x100);
-	snd_soc_update_bits(codec, WM8900_REG_RADC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LINVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_RINVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LOUT1CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_ROUT1CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LOUT2CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_ROUT2CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LDAC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_RDAC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LADC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_RADC_DV, 0x100, 0x100);
 
 	/* Set the DAC and mixer output bias */
-	snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
+	snd_soc_component_write(component, WM8900_REG_OUTBIASCTL, 0x81);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
-	.probe =	wm8900_probe,
-	.suspend =	wm8900_suspend,
-	.resume =	wm8900_resume,
-	.set_bias_level = wm8900_set_bias_level,
-
-	.component_driver = {
-		.controls		= wm8900_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8900_snd_controls),
-		.dapm_widgets		= wm8900_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8900_dapm_widgets),
-		.dapm_routes		= wm8900_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8900_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8900 = {
+	.probe			= wm8900_probe,
+	.suspend		= wm8900_suspend,
+	.resume			= wm8900_resume,
+	.set_bias_level		= wm8900_set_bias_level,
+	.controls		= wm8900_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8900_snd_controls),
+	.dapm_widgets		= wm8900_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8900_dapm_widgets),
+	.dapm_routes		= wm8900_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8900_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8900_regmap = {
@@ -1253,15 +1254,14 @@ static int wm8900_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8900);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8900, &wm8900_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8900, &wm8900_dai, 1);
 
 	return ret;
 }
 
 static int wm8900_spi_remove(struct spi_device *spi)
 {
-	snd_soc_unregister_codec(&spi->dev);
 	return 0;
 }
 
@@ -1292,15 +1292,14 @@ static int wm8900_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8900);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8900, &wm8900_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8900, &wm8900_dai, 1);
 
 	return ret;
 }
 
 static int wm8900_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index cba90f21161f..7b8b6ef2f632 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -270,15 +270,15 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
 static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		wm8903->dcs_pending |= 1 << w->shift;
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, WM8903_DC_SERVO_0,
+		snd_soc_component_update_bits(component, WM8903_DC_SERVO_0,
 				    1 << w->shift, 0);
 		break;
 	}
@@ -289,17 +289,16 @@ static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
 #define WM8903_DCS_MODE_WRITE_STOP 0
 #define WM8903_DCS_MODE_START_STOP 2
 
-static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
+static void wm8903_seq_notifier(struct snd_soc_component *component,
 				enum snd_soc_dapm_type event, int subseq)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 	int dcs_mode = WM8903_DCS_MODE_WRITE_STOP;
 	int i, val;
 
 	/* Complete any pending DC servo starts */
 	if (wm8903->dcs_pending) {
-		dev_dbg(codec->dev, "Starting DC servo for %x\n",
+		dev_dbg(component->dev, "Starting DC servo for %x\n",
 			wm8903->dcs_pending);
 
 		/* If we've no cached values then we need to do startup */
@@ -308,14 +307,14 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 				continue;
 
 			if (wm8903->dcs_cache[i]) {
-				dev_dbg(codec->dev,
+				dev_dbg(component->dev,
 					"Restore DC servo %d value %x\n",
 					3 - i, wm8903->dcs_cache[i]);
 
-				snd_soc_write(codec, WM8903_DC_SERVO_4 + i,
+				snd_soc_component_write(component, WM8903_DC_SERVO_4 + i,
 					      wm8903->dcs_cache[i] & 0xff);
 			} else {
-				dev_dbg(codec->dev,
+				dev_dbg(component->dev,
 					"Calibrate DC servo %d\n", 3 - i);
 				dcs_mode = WM8903_DCS_MODE_START_STOP;
 			}
@@ -325,10 +324,10 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 		if (wm8903->class_w_users)
 			dcs_mode = WM8903_DCS_MODE_START_STOP;
 
-		snd_soc_update_bits(codec, WM8903_DC_SERVO_2,
+		snd_soc_component_update_bits(component, WM8903_DC_SERVO_2,
 				    WM8903_DCS_MODE_MASK, dcs_mode);
 
-		snd_soc_update_bits(codec, WM8903_DC_SERVO_0,
+		snd_soc_component_update_bits(component, WM8903_DC_SERVO_0,
 				    WM8903_DCS_ENA_MASK, wm8903->dcs_pending);
 
 		switch (dcs_mode) {
@@ -346,9 +345,9 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 				if (!(wm8903->dcs_pending & (1 << i)))
 					continue;
 
-				val = snd_soc_read(codec,
+				val = snd_soc_component_read32(component,
 						   WM8903_DC_SERVO_READBACK_1 + i);
-				dev_dbg(codec->dev, "DC servo %d: %x\n",
+				dev_dbg(component->dev, "DC servo %d: %x\n",
 					3 - i, val);
 				wm8903->dcs_cache[i] = val;
 			}
@@ -374,18 +373,18 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 	u16 reg;
 	int ret;
 
-	reg = snd_soc_read(codec, WM8903_CLASS_W_0);
+	reg = snd_soc_component_read32(component, WM8903_CLASS_W_0);
 
 	/* Turn it off if we're about to enable bypass */
 	if (ucontrol->value.integer.value[0]) {
 		if (wm8903->class_w_users == 0) {
-			dev_dbg(codec->dev, "Disabling Class W\n");
-			snd_soc_write(codec, WM8903_CLASS_W_0, reg &
+			dev_dbg(component->dev, "Disabling Class W\n");
+			snd_soc_component_write(component, WM8903_CLASS_W_0, reg &
 				     ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
 		}
 		wm8903->class_w_users++;
@@ -397,14 +396,14 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 	/* If we've just disabled the last bypass path turn Class W on */
 	if (!ucontrol->value.integer.value[0]) {
 		if (wm8903->class_w_users == 1) {
-			dev_dbg(codec->dev, "Enabling Class W\n");
-			snd_soc_write(codec, WM8903_CLASS_W_0, reg |
+			dev_dbg(component->dev, "Enabling Class W\n");
+			snd_soc_component_write(component, WM8903_CLASS_W_0, reg |
 				     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
 		}
 		wm8903->class_w_users--;
 	}
 
-	dev_dbg(codec->dev, "Bypass use count now %d\n",
+	dev_dbg(component->dev, "Bypass use count now %d\n",
 		wm8903->class_w_users);
 
 	return ret;
@@ -417,9 +416,9 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 
 static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
 
-static int wm8903_set_deemph(struct snd_soc_codec *codec)
+static int wm8903_set_deemph(struct snd_soc_component *component)
 {
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 	int val, i, best;
 
 	/* If we're using deemphasis select the nearest available sample
@@ -439,18 +438,18 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec)
 		val = 0;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
+	dev_dbg(component->dev, "Set deemphasis %d (%dHz)\n",
 		best, wm8903_deemph[best]);
 
-	return snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
+	return snd_soc_component_update_bits(component, WM8903_DAC_DIGITAL_1,
 				   WM8903_DEEMPH_MASK, val);
 }
 
 static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8903->deemph;
 
@@ -460,8 +459,8 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 	int ret = 0;
 
@@ -472,7 +471,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 	if (wm8903->deemph != deemph) {
 		wm8903->deemph = deemph;
 
-		wm8903_set_deemph(codec);
+		wm8903_set_deemph(component);
 
 		ret = 1;
 	}
@@ -1101,7 +1100,7 @@ static const struct snd_soc_dapm_route wm8903_intercon[] = {
 	{ "Right Line Output PGA", NULL, "Charge Pump" },
 };
 
-static int wm8903_set_bias_level(struct snd_soc_codec *codec,
+static int wm8903_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -1109,14 +1108,14 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 				    WM8903_VMID_RES_MASK,
 				    WM8903_VMID_RES_50K);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
 					    WM8903_POBCTRL | WM8903_ISEL_MASK |
 					    WM8903_STARTUP_BIAS_ENA |
 					    WM8903_BIAS_ENA,
@@ -1124,22 +1123,22 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 					    (2 << WM8903_ISEL_SHIFT) |
 					    WM8903_STARTUP_BIAS_ENA);
 
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					    WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
 					    WM8903_SPK_DISCHARGE,
 					    WM8903_SPK_DISCHARGE);
 
 			msleep(33);
 
-			snd_soc_update_bits(codec, WM8903_POWER_MANAGEMENT_5,
+			snd_soc_component_update_bits(component, WM8903_POWER_MANAGEMENT_5,
 					    WM8903_SPKL_ENA | WM8903_SPKR_ENA,
 					    WM8903_SPKL_ENA | WM8903_SPKR_ENA);
 
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					    WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
 					    WM8903_SPK_DISCHARGE, 0);
 
-			snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+			snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 					    WM8903_VMID_TIE_ENA |
 					    WM8903_BUFIO_ENA |
 					    WM8903_VMID_IO_ENA |
@@ -1155,57 +1154,57 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 
 			msleep(129);
 
-			snd_soc_update_bits(codec, WM8903_POWER_MANAGEMENT_5,
+			snd_soc_component_update_bits(component, WM8903_POWER_MANAGEMENT_5,
 					    WM8903_SPKL_ENA | WM8903_SPKR_ENA,
 					    0);
 
-			snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+			snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 					    WM8903_VMID_SOFT_MASK, 0);
 
-			snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+			snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 					    WM8903_VMID_RES_MASK,
 					    WM8903_VMID_RES_50K);
 
-			snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+			snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
 					    WM8903_BIAS_ENA | WM8903_POBCTRL,
 					    WM8903_BIAS_ENA);
 
 			/* By default no bypass paths are enabled so
 			 * enable Class W support.
 			 */
-			dev_dbg(codec->dev, "Enabling Class W\n");
-			snd_soc_update_bits(codec, WM8903_CLASS_W_0,
+			dev_dbg(component->dev, "Enabling Class W\n");
+			snd_soc_component_update_bits(component, WM8903_CLASS_W_0,
 					    WM8903_CP_DYN_FREQ |
 					    WM8903_CP_DYN_V,
 					    WM8903_CP_DYN_FREQ |
 					    WM8903_CP_DYN_V);
 		}
 
-		snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 				    WM8903_VMID_RES_MASK,
 				    WM8903_VMID_RES_250K);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
 				    WM8903_BIAS_ENA, 0);
 
-		snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 				    WM8903_VMID_SOFT_MASK,
 				    2 << WM8903_VMID_SOFT_SHIFT);
 
-		snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 				    WM8903_VMID_BUF_ENA, 0);
 
 		msleep(290);
 
-		snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
 				    WM8903_VMID_TIE_ENA | WM8903_BUFIO_ENA |
 				    WM8903_VMID_IO_ENA | WM8903_VMID_RES_MASK |
 				    WM8903_VMID_SOFT_MASK |
 				    WM8903_VMID_BUF_ENA, 0);
 
-		snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
 				    WM8903_STARTUP_BIAS_ENA, 0);
 		break;
 	}
@@ -1216,8 +1215,8 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 
 	wm8903->sysclk = freq;
 
@@ -1227,8 +1226,8 @@ static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1);
+	struct snd_soc_component *component = codec_dai->component;
+	u16 aif1 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_1);
 
 	aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
 		  WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
@@ -1306,24 +1305,24 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_1, aif1);
 
 	return 0;
 }
 
 static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
-	reg = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
+	reg = snd_soc_component_read32(component, WM8903_DAC_DIGITAL_1);
 
 	if (mute)
 		reg |= WM8903_DAC_MUTE;
 	else
 		reg &= ~WM8903_DAC_MUTE;
 
-	snd_soc_write(codec, WM8903_DAC_DIGITAL_1, reg);
+	snd_soc_component_write(component, WM8903_DAC_DIGITAL_1, reg);
 
 	return 0;
 }
@@ -1443,8 +1442,8 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 	int fs = params_rate(params);
 	int bclk;
 	int bclk_div;
@@ -1455,12 +1454,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 	int cur_val;
 	int clk_sys;
 
-	u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1);
-	u16 aif2 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_2);
-	u16 aif3 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_3);
-	u16 clock0 = snd_soc_read(codec, WM8903_CLOCK_RATES_0);
-	u16 clock1 = snd_soc_read(codec, WM8903_CLOCK_RATES_1);
-	u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
+	u16 aif1 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_1);
+	u16 aif2 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_2);
+	u16 aif3 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_3);
+	u16 clock0 = snd_soc_component_read32(component, WM8903_CLOCK_RATES_0);
+	u16 clock1 = snd_soc_component_read32(component, WM8903_CLOCK_RATES_1);
+	u16 dac_digital1 = snd_soc_component_read32(component, WM8903_DAC_DIGITAL_1);
 
 	/* Enable sloping stopband filter for low sample rates */
 	if (fs <= 24000)
@@ -1479,7 +1478,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	dev_dbg(codec->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+	dev_dbg(component->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
 	clock1 &= ~WM8903_SAMPLE_RATE_MASK;
 	clock1 |= sample_rates[dsp_config].value;
 
@@ -1505,7 +1504,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+	dev_dbg(component->dev, "MCLK = %dHz, target sample rate = %dHz\n",
 		wm8903->sysclk, fs);
 
 	/* We may not have an MCLK which allows us to generate exactly
@@ -1540,12 +1539,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 	clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
 	clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
 
-	dev_dbg(codec->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+	dev_dbg(component->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
 		clk_sys_ratios[clk_config].rate,
 		clk_sys_ratios[clk_config].mode,
 		clk_sys_ratios[clk_config].div);
 
-	dev_dbg(codec->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+	dev_dbg(component->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
 
 	/* We may not get quite the right frequency if using
 	 * approximate clocks so look for the closest match that is
@@ -1567,7 +1566,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 	aif2 &= ~WM8903_BCLK_DIV_MASK;
 	aif3 &= ~WM8903_LRCLK_RATE_MASK;
 
-	dev_dbg(codec->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+	dev_dbg(component->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
 		bclk_divs[bclk_div].ratio / 10, bclk,
 		(clk_sys * 10) / bclk_divs[bclk_div].ratio);
 
@@ -1575,14 +1574,14 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 	aif3 |= bclk / fs;
 
 	wm8903->fs = params_rate(params);
-	wm8903_set_deemph(codec);
+	wm8903_set_deemph(component);
 
-	snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0);
-	snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1);
-	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
-	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
-	snd_soc_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
-	snd_soc_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1);
+	snd_soc_component_write(component, WM8903_CLOCK_RATES_0, clock0);
+	snd_soc_component_write(component, WM8903_CLOCK_RATES_1, clock1);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_2, aif2);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_3, aif3);
+	snd_soc_component_write(component, WM8903_DAC_DIGITAL_1, dac_digital1);
 
 	return 0;
 }
@@ -1590,7 +1589,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
 /**
  * wm8903_mic_detect - Enable microphone detection via the WM8903 IRQ
  *
- * @codec:  WM8903 codec
+ * @component:  WM8903 component
  * @jack:   jack to report detection events on
  * @det:    value to report for presence detection
  * @shrt:   value to report for short detection
@@ -1604,13 +1603,13 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
  * micdet_cfg in the platform data.  Using this function will force on
  * the microphone bias for the device.
  */
-int wm8903_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8903_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		      int det, int shrt)
 {
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 	int irq_mask = WM8903_MICDET_EINT | WM8903_MICSHRT_EINT;
 
-	dev_dbg(codec->dev, "Enabling microphone detection: %x %x\n",
+	dev_dbg(component->dev, "Enabling microphone detection: %x %x\n",
 		det, shrt);
 
 	/* Store the configuration */
@@ -1624,19 +1623,19 @@ int wm8903_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 	if (shrt)
 		irq_mask &= ~WM8903_MICSHRT_EINT;
 
-	snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
+	snd_soc_component_update_bits(component, WM8903_INTERRUPT_STATUS_1_MASK,
 			    WM8903_MICDET_EINT | WM8903_MICSHRT_EINT,
 			    irq_mask);
 
 	if (det || shrt) {
 		/* Enable mic detection, this may not have been set through
 		 * platform data (eg, if the defaults are OK). */
-		snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
+		snd_soc_component_update_bits(component, WM8903_WRITE_SEQUENCER_0,
 				    WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
-		snd_soc_update_bits(codec, WM8903_MIC_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_MIC_BIAS_CONTROL_0,
 				    WM8903_MICDET_ENA, WM8903_MICDET_ENA);
 	} else {
-		snd_soc_update_bits(codec, WM8903_MIC_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8903_MIC_BIAS_CONTROL_0,
 				    WM8903_MICDET_ENA, 0);
 	}
 
@@ -1766,9 +1765,9 @@ static struct snd_soc_dai_driver wm8903_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8903_resume(struct snd_soc_codec *codec)
+static int wm8903_resume(struct snd_soc_component *component)
 {
-	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
 
 	regcache_sync(wm8903->regmap);
 
@@ -1884,20 +1883,21 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 }
 #endif
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
-	.resume =	wm8903_resume,
-	.set_bias_level = wm8903_set_bias_level,
-	.seq_notifier = wm8903_seq_notifier,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8903_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8903_snd_controls),
-		.dapm_widgets		= wm8903_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8903_dapm_widgets),
-		.dapm_routes		= wm8903_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(wm8903_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8903 = {
+	.resume			= wm8903_resume,
+	.set_bias_level		= wm8903_set_bias_level,
+	.seq_notifier		= wm8903_seq_notifier,
+	.controls		= wm8903_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8903_snd_controls),
+	.dapm_widgets		= wm8903_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8903_dapm_widgets),
+	.dapm_routes		= wm8903_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8903_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8903_regmap = {
@@ -2176,8 +2176,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c,
 			   WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
 			   WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8903, &wm8903_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8903, &wm8903_dai, 1);
 	if (ret != 0)
 		goto err;
 
@@ -2197,7 +2197,6 @@ static int wm8903_i2c_remove(struct i2c_client *client)
 	if (client->irq)
 		free_irq(client->irq, wm8903);
 	wm8903_free_gpio(wm8903);
-	snd_soc_unregister_codec(&client->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
index 0bb4a647755d..1301aa9dce6f 100644
--- a/sound/soc/codecs/wm8903.h
+++ b/sound/soc/codecs/wm8903.h
@@ -15,7 +15,7 @@
 
 #include <linux/i2c.h>
 
-extern int wm8903_mic_detect(struct snd_soc_codec *codec,
+extern int wm8903_mic_detect(struct snd_soc_component *component,
 			     struct snd_soc_jack *jack,
 			     int det, int shrt);
 
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 4fd350e8420d..20fdcae06c6b 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -316,31 +316,31 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg)
 	}
 }
 
-static int wm8904_configure_clocking(struct snd_soc_codec *codec)
+static int wm8904_configure_clocking(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	unsigned int clock0, clock2, rate;
 
 	/* Gate the clock while we're updating to avoid misclocking */
-	clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+	clock2 = snd_soc_component_read32(component, WM8904_CLOCK_RATES_2);
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
 			    WM8904_SYSCLK_SRC, 0);
 
 	/* This should be done on init() for bypass paths */
 	switch (wm8904->sysclk_src) {
 	case WM8904_CLK_MCLK:
-		dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate);
+		dev_dbg(component->dev, "Using %dHz MCLK\n", wm8904->mclk_rate);
 
 		clock2 &= ~WM8904_SYSCLK_SRC;
 		rate = wm8904->mclk_rate;
 
 		/* Ensure the FLL is stopped */
-		snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 				    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
 		break;
 
 	case WM8904_CLK_FLL:
-		dev_dbg(codec->dev, "Using %dHz FLL clock\n",
+		dev_dbg(component->dev, "Using %dHz FLL clock\n",
 			wm8904->fll_fout);
 
 		clock2 |= WM8904_SYSCLK_SRC;
@@ -348,7 +348,7 @@ static int wm8904_configure_clocking(struct snd_soc_codec *codec)
 		break;
 
 	default:
-		dev_err(codec->dev, "System clock not configured\n");
+		dev_err(component->dev, "System clock not configured\n");
 		return -EINVAL;
 	}
 
@@ -361,40 +361,40 @@ static int wm8904_configure_clocking(struct snd_soc_codec *codec)
 		wm8904->sysclk_rate = rate;
 	}
 
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV,
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV,
 			    clock0);
 
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
 			    WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2);
 
-	dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate);
+	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate);
 
 	return 0;
 }
 
-static void wm8904_set_drc(struct snd_soc_codec *codec)
+static void wm8904_set_drc(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct wm8904_pdata *pdata = wm8904->pdata;
 	int save, i;
 
 	/* Save any enables; the configuration should clear them. */
-	save = snd_soc_read(codec, WM8904_DRC_0);
+	save = snd_soc_component_read32(component, WM8904_DRC_0);
 
 	for (i = 0; i < WM8904_DRC_REGS; i++)
-		snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff,
+		snd_soc_component_update_bits(component, WM8904_DRC_0 + i, 0xffff,
 				    pdata->drc_cfgs[wm8904->drc_cfg].regs[i]);
 
 	/* Reenable the DRC */
-	snd_soc_update_bits(codec, WM8904_DRC_0,
+	snd_soc_component_update_bits(component, WM8904_DRC_0,
 			    WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save);
 }
 
 static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct wm8904_pdata *pdata = wm8904->pdata;
 	int value = ucontrol->value.enumerated.item[0];
 
@@ -403,7 +403,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
 
 	wm8904->drc_cfg = value;
 
-	wm8904_set_drc(codec);
+	wm8904_set_drc(component);
 
 	return 0;
 }
@@ -411,17 +411,17 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
 static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
 
 	return 0;
 }
 
-static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
+static void wm8904_set_retune_mobile(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct wm8904_pdata *pdata = wm8904->pdata;
 	int best, best_val, save, i, cfg;
 
@@ -444,7 +444,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
 		}
 	}
 
-	dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n",
+	dev_dbg(component->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n",
 		pdata->retune_mobile_cfgs[best].name,
 		pdata->retune_mobile_cfgs[best].rate,
 		wm8904->fs);
@@ -452,20 +452,20 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
 	/* The EQ will be disabled while reconfiguring it, remember the
 	 * current configuration. 
 	 */
-	save = snd_soc_read(codec, WM8904_EQ1);
+	save = snd_soc_component_read32(component, WM8904_EQ1);
 
 	for (i = 0; i < WM8904_EQ_REGS; i++)
-		snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff,
+		snd_soc_component_update_bits(component, WM8904_EQ1 + i, 0xffff,
 				pdata->retune_mobile_cfgs[best].regs[i]);
 
-	snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save);
+	snd_soc_component_update_bits(component, WM8904_EQ1, WM8904_EQ_ENA, save);
 }
 
 static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct wm8904_pdata *pdata = wm8904->pdata;
 	int value = ucontrol->value.enumerated.item[0];
 
@@ -474,7 +474,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 
 	wm8904->retune_mobile_cfg = value;
 
-	wm8904_set_retune_mobile(codec);
+	wm8904_set_retune_mobile(component);
 
 	return 0;
 }
@@ -482,8 +482,8 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
 
@@ -492,9 +492,9 @@ static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 
 static int deemph_settings[] = { 0, 32000, 44100, 48000 };
 
-static int wm8904_set_deemph(struct snd_soc_codec *codec)
+static int wm8904_set_deemph(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	int val, i, best;
 
 	/* If we're using deemphasis select the nearest available sample 
@@ -513,17 +513,17 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec)
 		val = 0;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
 
-	return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
+	return snd_soc_component_update_bits(component, WM8904_DAC_DIGITAL_1,
 				   WM8904_DEEMPH_MASK, val);
 }
 
 static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8904->deemph;
 	return 0;
@@ -532,8 +532,8 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 
 	if (deemph > 1)
@@ -541,7 +541,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
 
 	wm8904->deemph = deemph;
 
-	return wm8904_set_deemph(codec);
+	return wm8904_set_deemph(component);
 }
 
 static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
@@ -572,7 +572,7 @@ static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
 static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int val;
 	int ret;
 
@@ -585,7 +585,7 @@ static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
 	else
 		val = WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5;
 
-	snd_soc_update_bits(codec, WM8904_ADC_TEST_0,
+	snd_soc_component_update_bits(component, WM8904_ADC_TEST_0,
 			    WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5,
 			    val);
 
@@ -673,8 +673,8 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int sysclk_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -685,11 +685,11 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 		 */
 		switch (wm8904->sysclk_src) {
 		case WM8904_CLK_FLL:
-			snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+			snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 					    WM8904_FLL_OSC_ENA,
 					    WM8904_FLL_OSC_ENA);
 
-			snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+			snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 					    WM8904_FLL_ENA,
 					    WM8904_FLL_ENA);
 			break;
@@ -700,7 +700,7 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 				    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
 		break;
 	}
@@ -711,8 +711,8 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	int reg, val;
 	int dcs_mask;
 	int dcs_l, dcs_r;
@@ -751,43 +751,43 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Power on the PGAs */
-		snd_soc_update_bits(codec, pwr_reg,
+		snd_soc_component_update_bits(component, pwr_reg,
 				    WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA,
 				    WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA);
 
 		/* Power on the amplifier */
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    WM8904_HPL_ENA | WM8904_HPR_ENA,
 				    WM8904_HPL_ENA | WM8904_HPR_ENA);
 
 
 		/* Enable the first stage */
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY,
 				    WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY);
 
 		/* Power up the DC servo */
-		snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
+		snd_soc_component_update_bits(component, WM8904_DC_SERVO_0,
 				    dcs_mask, dcs_mask);
 
 		/* Either calibrate the DC servo or restore cached state
 		 * if we have that.
 		 */
 		if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) {
-			dev_dbg(codec->dev, "Restoring DC servo state\n");
+			dev_dbg(component->dev, "Restoring DC servo state\n");
 
-			snd_soc_write(codec, dcs_l_reg,
+			snd_soc_component_write(component, dcs_l_reg,
 				      wm8904->dcs_state[dcs_l]);
-			snd_soc_write(codec, dcs_r_reg,
+			snd_soc_component_write(component, dcs_r_reg,
 				      wm8904->dcs_state[dcs_r]);
 
-			snd_soc_write(codec, WM8904_DC_SERVO_1, dcs_mask);
+			snd_soc_component_write(component, WM8904_DC_SERVO_1, dcs_mask);
 
 			timeout = 20;
 		} else {
-			dev_dbg(codec->dev, "Calibrating DC servo\n");
+			dev_dbg(component->dev, "Calibrating DC servo\n");
 
-			snd_soc_write(codec, WM8904_DC_SERVO_1,
+			snd_soc_component_write(component, WM8904_DC_SERVO_1,
 				dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT);
 
 			timeout = 500;
@@ -796,7 +796,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 		/* Wait for DC servo to complete */
 		dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT;
 		do {
-			val = snd_soc_read(codec, WM8904_DC_SERVO_READBACK_0);
+			val = snd_soc_component_read32(component, WM8904_DC_SERVO_READBACK_0);
 			if ((val & dcs_mask) == dcs_mask)
 				break;
 
@@ -804,19 +804,19 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 		} while (--timeout);
 
 		if ((val & dcs_mask) != dcs_mask)
-			dev_warn(codec->dev, "DC servo timed out\n");
+			dev_warn(component->dev, "DC servo timed out\n");
 		else
-			dev_dbg(codec->dev, "DC servo ready\n");
+			dev_dbg(component->dev, "DC servo ready\n");
 
 		/* Enable the output stage */
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
 				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
 		/* Unshort the output itself */
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    WM8904_HPL_RMV_SHORT |
 				    WM8904_HPR_RMV_SHORT,
 				    WM8904_HPL_RMV_SHORT |
@@ -826,7 +826,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Short the output */
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    WM8904_HPL_RMV_SHORT |
 				    WM8904_HPR_RMV_SHORT, 0);
 		break;
@@ -834,21 +834,21 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 	case SND_SOC_DAPM_POST_PMD:
 		/* Cache the DC servo configuration; this will be
 		 * invalidated if we change the configuration. */
-		wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg);
-		wm8904->dcs_state[dcs_r] = snd_soc_read(codec, dcs_r_reg);
+		wm8904->dcs_state[dcs_l] = snd_soc_component_read32(component, dcs_l_reg);
+		wm8904->dcs_state[dcs_r] = snd_soc_component_read32(component, dcs_r_reg);
 
-		snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
+		snd_soc_component_update_bits(component, WM8904_DC_SERVO_0,
 				    dcs_mask, 0);
 
 		/* Disable the amplifier input and output stages */
-		snd_soc_update_bits(codec, reg,
+		snd_soc_component_update_bits(component, reg,
 				    WM8904_HPL_ENA | WM8904_HPR_ENA |
 				    WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY |
 				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
 				    0);
 
 		/* PGAs too */
-		snd_soc_update_bits(codec, pwr_reg,
+		snd_soc_component_update_bits(component, pwr_reg,
 				    WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA,
 				    0);
 		break;
@@ -1165,10 +1165,10 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = {
 	{ "LINER PGA", NULL, "DACR" },
 };
 
-static int wm8904_add_widgets(struct snd_soc_codec *codec)
+static int wm8904_add_widgets(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets,
 				  ARRAY_SIZE(wm8904_core_dapm_widgets));
@@ -1177,11 +1177,11 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)
 
 	switch (wm8904->devtype) {
 	case WM8904:
-		snd_soc_add_codec_controls(codec, wm8904_adc_snd_controls,
+		snd_soc_add_component_controls(component, wm8904_adc_snd_controls,
 				     ARRAY_SIZE(wm8904_adc_snd_controls));
-		snd_soc_add_codec_controls(codec, wm8904_dac_snd_controls,
+		snd_soc_add_component_controls(component, wm8904_dac_snd_controls,
 				     ARRAY_SIZE(wm8904_dac_snd_controls));
-		snd_soc_add_codec_controls(codec, wm8904_snd_controls,
+		snd_soc_add_component_controls(component, wm8904_snd_controls,
 				     ARRAY_SIZE(wm8904_snd_controls));
 
 		snd_soc_dapm_new_controls(dapm, wm8904_adc_dapm_widgets,
@@ -1200,7 +1200,7 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)
 		break;
 
 	case WM8912:
-		snd_soc_add_codec_controls(codec, wm8904_dac_snd_controls,
+		snd_soc_add_component_controls(component, wm8904_dac_snd_controls,
 				     ARRAY_SIZE(wm8904_dac_snd_controls));
 
 		snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets,
@@ -1278,8 +1278,8 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	int ret, i, best, best_val, cur_val;
 	unsigned int aif1 = 0;
 	unsigned int aif2 = 0;
@@ -1290,7 +1290,7 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 	/* What BCLK do we need? */
 	wm8904->fs = params_rate(params);
 	if (wm8904->tdm_slots) {
-		dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
+		dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
 			wm8904->tdm_slots, wm8904->tdm_width);
 		wm8904->bclk = snd_soc_calc_bclk(wm8904->fs,
 						 wm8904->tdm_width, 2,
@@ -1316,9 +1316,9 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 	}
 
 
-	dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk);
+	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm8904->bclk);
 
-	ret = wm8904_configure_clocking(codec);
+	ret = wm8904_configure_clocking(component);
 	if (ret != 0)
 		return ret;
 
@@ -1334,7 +1334,7 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 			best_val = cur_val;
 		}
 	}
-	dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
 		clk_sys_rates[best].ratio);
 	clock1 |= (clk_sys_rates[best].clk_sys_rate
 		   << WM8904_CLK_SYS_RATE_SHIFT);
@@ -1350,7 +1350,7 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 			best_val = cur_val;
 		}
 	}
-	dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
 		sample_rates[best].rate);
 	clock1 |= (sample_rates[best].sample_rate
 		   << WM8904_SAMPLE_RATE_SHIFT);
@@ -1373,30 +1373,30 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 	wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div;
-	dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
 		bclk_divs[best].div, wm8904->bclk);
 	aif2 |= bclk_divs[best].bclk_div;
 
 	/* LRCLK is a simple fraction of BCLK */
-	dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs);
+	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs);
 	aif3 |= wm8904->bclk / wm8904->fs;
 
 	/* Apply the settings */
-	snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
+	snd_soc_component_update_bits(component, WM8904_DAC_DIGITAL_1,
 			    WM8904_DAC_SB_FILT, dac_digital1);
-	snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_1,
 			    WM8904_AIF_WL_MASK, aif1);
-	snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_2,
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_2,
 			    WM8904_BCLK_DIV_MASK, aif2);
-	snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_3,
 			    WM8904_LRCLK_RATE_MASK, aif3);
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_1,
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_1,
 			    WM8904_SAMPLE_RATE_MASK |
 			    WM8904_CLK_SYS_RATE_MASK, clock1);
 
 	/* Update filters for the new settings */
-	wm8904_set_retune_mobile(codec);
-	wm8904_set_deemph(codec);
+	wm8904_set_retune_mobile(component);
+	wm8904_set_deemph(component);
 
 	return 0;
 }
@@ -1405,8 +1405,8 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
 static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 			     unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8904_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *priv = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM8904_CLK_MCLK:
@@ -1424,14 +1424,14 @@ static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 	dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
 
-	wm8904_configure_clocking(codec);
+	wm8904_configure_clocking(component);
 
 	return 0;
 }
 
 static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	unsigned int aif1 = 0;
 	unsigned int aif3 = 0;
 
@@ -1508,10 +1508,10 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_1,
 			    WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV |
 			    WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1);
-	snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_3,
 			    WM8904_LRCLK_DIR, aif3);
 
 	return 0;
@@ -1521,8 +1521,8 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			       unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	int aif1 = 0;
 
 	/* Don't need to validate anything if we're turning off TDM */
@@ -1560,7 +1560,7 @@ static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	wm8904->tdm_width = slot_width;
 	wm8904->tdm_slots = slots / 2;
 
-	snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_1,
 			    WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN |
 			    WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1);
 
@@ -1678,8 +1678,8 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct _fll_div fll_div;
 	int ret, val;
 	int clock2, fll1;
@@ -1689,19 +1689,19 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 	    Fout == wm8904->fll_fout)
 		return 0;
 
-	clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
+	clock2 = snd_soc_component_read32(component, WM8904_CLOCK_RATES_2);
 
 	if (Fout == 0) {
-		dev_dbg(codec->dev, "FLL disabled\n");
+		dev_dbg(component->dev, "FLL disabled\n");
 
 		wm8904->fll_fref = 0;
 		wm8904->fll_fout = 0;
 
 		/* Gate SYSCLK to avoid glitches */
-		snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+		snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
 				    WM8904_CLK_SYS_ENA, 0);
 
-		snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 				    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
 
 		goto out;
@@ -1718,7 +1718,7 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 		break;
 
 	case WM8904_FLL_FREE_RUNNING:
-		dev_dbg(codec->dev, "Using free running FLL\n");
+		dev_dbg(component->dev, "Using free running FLL\n");
 		/* Force 12MHz and output/4 for now */
 		Fout = 12000000;
 		Fref = 12000000;
@@ -1728,20 +1728,20 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 		break;
 
 	default:
-		dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
 		return -EINVAL;
 	}
 
 	/* Save current state then disable the FLL and SYSCLK to avoid
 	 * misclocking */
-	fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1);
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+	fll1 = snd_soc_component_read32(component, WM8904_FLL_CONTROL_1);
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
 			    WM8904_CLK_SYS_ENA, 0);
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 			    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
 
 	/* Unlock forced oscilator control to switch it on/off */
-	snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
+	snd_soc_component_update_bits(component, WM8904_CONTROL_INTERFACE_TEST_1,
 			    WM8904_USER_KEY, WM8904_USER_KEY);
 
 	if (fll_id == WM8904_FLL_FREE_RUNNING) {
@@ -1750,24 +1750,24 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 		val = 0;
 	}
 
-	snd_soc_update_bits(codec, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO,
+	snd_soc_component_update_bits(component, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO,
 			    val);
-	snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
+	snd_soc_component_update_bits(component, WM8904_CONTROL_INTERFACE_TEST_1,
 			    WM8904_USER_KEY, 0);
 
 	switch (fll_id) {
 	case WM8904_FLL_MCLK:
-		snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
 				    WM8904_FLL_CLK_REF_SRC_MASK, 0);
 		break;
 
 	case WM8904_FLL_LRCLK:
-		snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
 				    WM8904_FLL_CLK_REF_SRC_MASK, 1);
 		break;
 
 	case WM8904_FLL_BCLK:
-		snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
 				    WM8904_FLL_CLK_REF_SRC_MASK, 2);
 		break;
 	}
@@ -1776,39 +1776,39 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 		val = WM8904_FLL_FRACN_ENA;
 	else
 		val = 0;
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 			    WM8904_FLL_FRACN_ENA, val);
 
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_2,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_2,
 			    WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK,
 			    (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) |
 			    (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT));
 
-	snd_soc_write(codec, WM8904_FLL_CONTROL_3, fll_div.k);
+	snd_soc_component_write(component, WM8904_FLL_CONTROL_3, fll_div.k);
 
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK,
 			    fll_div.n << WM8904_FLL_N_SHIFT);
 
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
 			    WM8904_FLL_CLK_REF_DIV_MASK,
 			    fll_div.fll_clk_ref_div 
 			    << WM8904_FLL_CLK_REF_DIV_SHIFT);
 
-	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+	dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
 	wm8904->fll_fref = Fref;
 	wm8904->fll_fout = Fout;
 	wm8904->fll_src = source;
 
 	/* Enable the FLL if it was previously active */
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 			    WM8904_FLL_OSC_ENA, fll1);
-	snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
 			    WM8904_FLL_ENA, fll1);
 
 out:
 	/* Reenable SYSCLK if it was previously active */
-	snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
 			    WM8904_CLK_SYS_ENA, clock2);
 
 	return 0;
@@ -1816,7 +1816,7 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 
 static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int val;
 
 	if (mute)
@@ -1824,15 +1824,15 @@ static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 	else
 		val = 0;
 
-	snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val);
+	snd_soc_component_update_bits(component, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val);
 
 	return 0;
 }
 
-static int wm8904_set_bias_level(struct snd_soc_codec *codec,
+static int wm8904_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1844,21 +1844,21 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID resistance 2*50k */
-		snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
 				    WM8904_VMID_RES_MASK,
 				    0x1 << WM8904_VMID_RES_SHIFT);
 
 		/* Normal bias current */
-		snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
 				    WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
 						    wm8904->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -1868,11 +1868,11 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
 			regcache_sync(wm8904->regmap);
 
 			/* Enable bias */
-			snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+			snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
 					    WM8904_BIAS_ENA, WM8904_BIAS_ENA);
 
 			/* Enable VMID, VMID buffering, 2*5k resistance */
-			snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+			snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
 					    WM8904_VMID_ENA |
 					    WM8904_VMID_RES_MASK,
 					    WM8904_VMID_ENA |
@@ -1883,22 +1883,22 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
 		}
 
 		/* Maintain VMID with 2*250k */
-		snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
 				    WM8904_VMID_RES_MASK,
 				    0x2 << WM8904_VMID_RES_SHIFT);
 
 		/* Bias current *0.5 */
-		snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
 				    WM8904_ISEL_MASK, 0);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Turn off VMID */
-		snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
 				    WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0);
 
 		/* Stop bias generation */
-		snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+		snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
 				    WM8904_BIAS_ENA, 0);
 
 		regcache_cache_only(wm8904->regmap, true);
@@ -1946,9 +1946,9 @@ static struct snd_soc_dai_driver wm8904_dai = {
 	.symmetric_rates = 1,
 };
 
-static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
+static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct wm8904_pdata *pdata = wm8904->pdata;
 	struct snd_kcontrol_new control =
 		SOC_ENUM_EXT("EQ Mode",
@@ -1991,31 +1991,31 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
 		wm8904->retune_mobile_texts = t;
 	}
 
-	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+	dev_dbg(component->dev, "Allocated %d unique ReTune Mobile names\n",
 		wm8904->num_retune_mobile_texts);
 
 	wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts;
 	wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
 
-	ret = snd_soc_add_codec_controls(codec, &control, 1);
+	ret = snd_soc_add_component_controls(component, &control, 1);
 	if (ret != 0)
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Failed to add ReTune Mobile control: %d\n", ret);
 }
 
-static void wm8904_handle_pdata(struct snd_soc_codec *codec)
+static void wm8904_handle_pdata(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 	struct wm8904_pdata *pdata = wm8904->pdata;
 	int ret, i;
 
 	if (!pdata) {
-		snd_soc_add_codec_controls(codec, wm8904_eq_controls,
+		snd_soc_add_component_controls(component, wm8904_eq_controls,
 				     ARRAY_SIZE(wm8904_eq_controls));
 		return;
 	}
 
-	dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+	dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
 
 	if (pdata->num_drc_cfgs) {
 		struct snd_kcontrol_new control =
@@ -2034,28 +2034,28 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
 		wm8904->drc_enum.items = pdata->num_drc_cfgs;
 		wm8904->drc_enum.texts = wm8904->drc_texts;
 
-		ret = snd_soc_add_codec_controls(codec, &control, 1);
+		ret = snd_soc_add_component_controls(component, &control, 1);
 		if (ret != 0)
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to add DRC mode control: %d\n", ret);
 
-		wm8904_set_drc(codec);
+		wm8904_set_drc(component);
 	}
 
-	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
+	dev_dbg(component->dev, "%d ReTune Mobile configurations\n",
 		pdata->num_retune_mobile_cfgs);
 
 	if (pdata->num_retune_mobile_cfgs)
-		wm8904_handle_retune_mobile_pdata(codec);
+		wm8904_handle_retune_mobile_pdata(component);
 	else
-		snd_soc_add_codec_controls(codec, wm8904_eq_controls,
+		snd_soc_add_component_controls(component, wm8904_eq_controls,
 				     ARRAY_SIZE(wm8904_eq_controls));
 }
 
 
-static int wm8904_probe(struct snd_soc_codec *codec)
+static int wm8904_probe(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 
 	switch (wm8904->devtype) {
 	case WM8904:
@@ -2064,33 +2064,33 @@ static int wm8904_probe(struct snd_soc_codec *codec)
 		memset(&wm8904_dai.capture, 0, sizeof(wm8904_dai.capture));
 		break;
 	default:
-		dev_err(codec->dev, "Unknown device type %d\n",
+		dev_err(component->dev, "Unknown device type %d\n",
 			wm8904->devtype);
 		return -EINVAL;
 	}
 
-	wm8904_handle_pdata(codec);
+	wm8904_handle_pdata(component);
 
-	wm8904_add_widgets(codec);
+	wm8904_add_widgets(component);
 
 	return 0;
 }
 
-static int wm8904_remove(struct snd_soc_codec *codec)
+static void wm8904_remove(struct snd_soc_component *component)
 {
-	struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
 
 	kfree(wm8904->retune_mobile_texts);
 	kfree(wm8904->drc_texts);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
-	.probe =	wm8904_probe,
-	.remove =	wm8904_remove,
-	.set_bias_level = wm8904_set_bias_level,
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_wm8904 = {
+	.probe			= wm8904_probe,
+	.remove			= wm8904_remove,
+	.set_bias_level		= wm8904_set_bias_level,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8904_regmap = {
@@ -2265,8 +2265,8 @@ static int wm8904_i2c_probe(struct i2c_client *i2c,
 	regcache_cache_only(wm8904->regmap, true);
 	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8904, &wm8904_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8904, &wm8904_dai, 1);
 	if (ret != 0)
 		return ret;
 
@@ -2277,12 +2277,6 @@ static int wm8904_i2c_probe(struct i2c_client *i2c,
 	return ret;
 }
 
-static int wm8904_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8904_i2c_id[] = {
 	{ "wm8904", WM8904 },
 	{ "wm8912", WM8912 },
@@ -2297,7 +2291,6 @@ static struct i2c_driver wm8904_i2c_driver = {
 		.of_match_table = of_match_ptr(wm8904_of_match),
 	},
 	.probe =    wm8904_i2c_probe,
-	.remove =   wm8904_i2c_remove,
 	.id_table = wm8904_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b5935625feeb..be4fce0c7b36 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -334,14 +334,14 @@ static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
 	{"ADC", NULL, "Boost Mixer"},
 };
 
-#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
+#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0);
 
 static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67;
-	u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe;
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8940_IFACE) & 0xFE67;
+	u16 clk = snd_soc_component_read32(component, WM8940_CLOCK) & 0x1fe;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
@@ -352,7 +352,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_write(codec, WM8940_CLOCK, clk);
+	snd_soc_component_write(component, WM8940_CLOCK, clk);
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
@@ -385,7 +385,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		break;
 	}
 
-	snd_soc_write(codec, WM8940_IFACE, iface);
+	snd_soc_component_write(component, WM8940_IFACE, iface);
 
 	return 0;
 }
@@ -394,10 +394,10 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
-	u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
-	u16 companding =  snd_soc_read(codec,
+	struct snd_soc_component *component = dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8940_IFACE) & 0xFD9F;
+	u16 addcntrl = snd_soc_component_read32(component, WM8940_ADDCNTRL) & 0xFFF1;
+	u16 companding =  snd_soc_component_read32(component,
 						WM8940_COMPANDINGCTL) & 0xFFDF;
 	int ret;
 
@@ -426,7 +426,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
 	case 48000:
 		break;
 	}
-	ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl);
+	ret = snd_soc_component_write(component, WM8940_ADDCNTRL, addcntrl);
 	if (ret)
 		goto error_ret;
 
@@ -446,10 +446,10 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
 		iface |= (3 << 5);
 		break;
 	}
-	ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding);
+	ret = snd_soc_component_write(component, WM8940_COMPANDINGCTL, companding);
 	if (ret)
 		goto error_ret;
-	ret = snd_soc_write(codec, WM8940_IFACE, iface);
+	ret = snd_soc_component_write(component, WM8940_IFACE, iface);
 
 error_ret:
 	return ret;
@@ -457,21 +457,21 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8940_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8940_DAC) & 0xffbf;
 
 	if (mute)
 		mute_reg |= 0x40;
 
-	return snd_soc_write(codec, WM8940_DAC, mute_reg);
+	return snd_soc_component_write(component, WM8940_DAC, mute_reg);
 }
 
-static int wm8940_set_bias_level(struct snd_soc_codec *codec,
+static int wm8940_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
+	struct wm8940_priv *wm8940 = snd_soc_component_get_drvdata(component);
 	u16 val;
-	u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
+	u16 pwr_reg = snd_soc_component_read32(component, WM8940_POWER1) & 0x1F0;
 	int ret = 0;
 
 	switch (level) {
@@ -479,23 +479,23 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
 		/* Enable thermal shutdown */
-		val = snd_soc_read(codec, WM8940_OUTPUTCTL);
-		ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2);
+		val = snd_soc_component_read32(component, WM8940_OUTPUTCTL);
+		ret = snd_soc_component_write(component, WM8940_OUTPUTCTL, val | 0x2);
 		if (ret)
 			break;
 		/* set vmid to 75k */
-		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x1);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
-		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x1);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(wm8940->regmap);
 			if (ret < 0) {
-				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
 				return ret;
 			}
 		}
@@ -503,10 +503,10 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
 		/* set vmid to 300k for standby */
-		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2);
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x2);
 		break;
 	case SND_SOC_BIAS_OFF:
-		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg);
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg);
 		break;
 	}
 
@@ -576,40 +576,40 @@ static void pll_factors(unsigned int target, unsigned int source)
 static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	/* Turn off PLL */
-	reg = snd_soc_read(codec, WM8940_POWER1);
-	snd_soc_write(codec, WM8940_POWER1, reg & 0x1df);
+	reg = snd_soc_component_read32(component, WM8940_POWER1);
+	snd_soc_component_write(component, WM8940_POWER1, reg & 0x1df);
 
 	if (freq_in == 0 || freq_out == 0) {
 		/* Clock CODEC directly from MCLK */
-		reg = snd_soc_read(codec, WM8940_CLOCK);
-		snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff);
+		reg = snd_soc_component_read32(component, WM8940_CLOCK);
+		snd_soc_component_write(component, WM8940_CLOCK, reg & 0x0ff);
 		/* Pll power down */
-		snd_soc_write(codec, WM8940_PLLN, (1 << 7));
+		snd_soc_component_write(component, WM8940_PLLN, (1 << 7));
 		return 0;
 	}
 
 	/* Pll is followed by a frequency divide by 4 */
 	pll_factors(freq_out*4, freq_in);
 	if (pll_div.k)
-		snd_soc_write(codec, WM8940_PLLN,
+		snd_soc_component_write(component, WM8940_PLLN,
 			     (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
 	else /* No factional component */
-		snd_soc_write(codec, WM8940_PLLN,
+		snd_soc_component_write(component, WM8940_PLLN,
 			     (pll_div.pre_scale << 4) | pll_div.n);
-	snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18);
-	snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
-	snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
+	snd_soc_component_write(component, WM8940_PLLK1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8940_PLLK3, pll_div.k & 0x1ff);
 	/* Enable the PLL */
-	reg = snd_soc_read(codec, WM8940_POWER1);
-	snd_soc_write(codec, WM8940_POWER1, reg | 0x020);
+	reg = snd_soc_component_read32(component, WM8940_POWER1);
+	snd_soc_component_write(component, WM8940_POWER1, reg | 0x020);
 
 	/* Run CODEC from PLL instead of MCLK */
-	reg = snd_soc_read(codec, WM8940_CLOCK);
-	snd_soc_write(codec, WM8940_CLOCK, reg | 0x100);
+	reg = snd_soc_component_read32(component, WM8940_CLOCK);
+	snd_soc_component_write(component, WM8940_CLOCK, reg | 0x100);
 
 	return 0;
 }
@@ -617,8 +617,8 @@ static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8940_priv *wm8940 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 11289600:
@@ -635,22 +635,22 @@ static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 				 int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 	int ret = 0;
 
 	switch (div_id) {
 	case WM8940_BCLKDIV:
-		reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3;
-		ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2));
+		reg = snd_soc_component_read32(component, WM8940_CLOCK) & 0xFFE3;
+		ret = snd_soc_component_write(component, WM8940_CLOCK, reg | (div << 2));
 		break;
 	case WM8940_MCLKDIV:
-		reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F;
-		ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
+		reg = snd_soc_component_read32(component, WM8940_CLOCK) & 0xFF1F;
+		ret = snd_soc_component_write(component, WM8940_CLOCK, reg | (div << 5));
 		break;
 	case WM8940_OPCLKDIV:
-		reg = snd_soc_read(codec, WM8940_GPIO) & 0xFFCF;
-		ret = snd_soc_write(codec, WM8940_GPIO, reg | (div << 4));
+		reg = snd_soc_component_read32(component, WM8940_GPIO) & 0xFFCF;
+		ret = snd_soc_component_write(component, WM8940_GPIO, reg | (div << 4));
 		break;
 	}
 	return ret;
@@ -693,29 +693,29 @@ static struct snd_soc_dai_driver wm8940_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8940_probe(struct snd_soc_codec *codec)
+static int wm8940_probe(struct snd_soc_component *component)
 {
-	struct wm8940_setup_data *pdata = codec->dev->platform_data;
+	struct wm8940_setup_data *pdata = component->dev->platform_data;
 	int ret;
 	u16 reg;
 
-	ret = wm8940_reset(codec);
+	ret = wm8940_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
+		dev_err(component->dev, "Failed to issue reset\n");
 		return ret;
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
-	ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
+	ret = snd_soc_component_write(component, WM8940_POWER1, 0x180);
 	if (ret < 0)
 		return ret;
 
 	if (!pdata)
-		dev_warn(codec->dev, "No platform data supplied\n");
+		dev_warn(component->dev, "No platform data supplied\n");
 	else {
-		reg = snd_soc_read(codec, WM8940_OUTPUTCTL);
-		ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
+		reg = snd_soc_component_read32(component, WM8940_OUTPUTCTL);
+		ret = snd_soc_component_write(component, WM8940_OUTPUTCTL, reg | pdata->vroi);
 		if (ret < 0)
 			return ret;
 	}
@@ -723,19 +723,20 @@ static int wm8940_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
-	.probe =	wm8940_probe,
-	.set_bias_level = wm8940_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8940_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8940_snd_controls),
-		.dapm_widgets		= wm8940_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8940_dapm_widgets),
-		.dapm_routes		= wm8940_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8940_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8940 = {
+	.probe			= wm8940_probe,
+	.set_bias_level		= wm8940_set_bias_level,
+	.controls		= wm8940_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8940_snd_controls),
+	.dapm_widgets		= wm8940_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8940_dapm_widgets),
+	.dapm_routes		= wm8940_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8940_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8940_regmap = {
@@ -768,19 +769,12 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8940);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8940, &wm8940_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8940, &wm8940_dai, 1);
 
 	return ret;
 }
 
-static int wm8940_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8940_i2c_id[] = {
 	{ "wm8940", 0 },
 	{ }
@@ -792,7 +786,6 @@ static struct i2c_driver wm8940_i2c_driver = {
 		.name = "wm8940",
 	},
 	.probe =    wm8940_i2c_probe,
-	.remove =   wm8940_i2c_remove,
 	.id_table = wm8940_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 1edc7b1df31d..ba44e3d6c1e0 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -128,9 +128,9 @@ static bool wm8955_volatile(struct device *dev, unsigned int reg)
 	}
 }
 
-static int wm8955_reset(struct snd_soc_codec *codec)
+static int wm8955_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, WM8955_RESET, 0);
+	return snd_soc_component_write(component, WM8955_RESET, 0);
 }
 
 struct pll_factors {
@@ -242,9 +242,9 @@ static struct {
 	{ 11289600, 88200, 0, 31, },
 };
 
-static int wm8955_configure_clocking(struct snd_soc_codec *codec)
+static int wm8955_configure_clocking(struct snd_soc_component *component)
 {
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
 	int i, ret, val;
 	int clocking = 0;
 	int srate = 0;
@@ -267,7 +267,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 
 	/* We should never get here with an unsupported sample rate */
 	if (sr == -1) {
-		dev_err(codec->dev, "Sample rate %dHz unsupported\n",
+		dev_err(component->dev, "Sample rate %dHz unsupported\n",
 			wm8955->fs);
 		WARN_ON(sr == -1);
 		return -EINVAL;
@@ -282,30 +282,30 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 
 		/* Use the last divider configuration we saw for the
 		 * sample rate. */
-		ret = wm8995_pll_factors(codec->dev, wm8955->mclk_rate,
+		ret = wm8995_pll_factors(component->dev, wm8955->mclk_rate,
 					 clock_cfgs[sr].mclk, &pll);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Unable to generate %dHz from %dHz MCLK\n",
 				wm8955->fs, wm8955->mclk_rate);
 			return -EINVAL;
 		}
 
-		snd_soc_update_bits(codec, WM8955_PLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_1,
 				    WM8955_N_MASK | WM8955_K_21_18_MASK,
 				    (pll.n << WM8955_N_SHIFT) |
 				    pll.k >> 18);
-		snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
+		snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_2,
 				    WM8955_K_17_9_MASK,
 				    (pll.k >> 9) & WM8955_K_17_9_MASK);
-		snd_soc_update_bits(codec, WM8955_PLL_CONTROL_3,
+		snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_3,
 				    WM8955_K_8_0_MASK,
 				    pll.k & WM8955_K_8_0_MASK);
 		if (pll.k)
-			snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
+			snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_4,
 					    WM8955_KEN, WM8955_KEN);
 		else
-			snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
+			snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_4,
 					    WM8955_KEN, 0);
 
 		if (pll.outdiv)
@@ -314,17 +314,17 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 			val = WM8955_PLL_RB;
 
 		/* Now start the PLL running */
-		snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+		snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
 				    WM8955_PLL_RB | WM8955_PLLOUTDIV2, val);
-		snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+		snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
 				    WM8955_PLLEN, WM8955_PLLEN);
 	}
 
 	srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT);
 
-	snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
+	snd_soc_component_update_bits(component, WM8955_SAMPLE_RATE,
 			    WM8955_USB | WM8955_SR_MASK, srate);
-	snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+	snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
 			    WM8955_MCLKSEL, clocking);
 
 	return 0;
@@ -333,22 +333,22 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int ret = 0;
 
 	/* Always disable the clocks - if we're doing reconfiguration this
 	 * avoids misclocking.
 	 */
-	snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+	snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
 			    WM8955_DIGENB, 0);
-	snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+	snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
 			    WM8955_PLL_RB | WM8955_PLLEN, 0);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 		break;
 	case SND_SOC_DAPM_PRE_PMU:
-		ret = wm8955_configure_clocking(codec);
+		ret = wm8955_configure_clocking(component);
 		break;
 	default:
 		ret = -EINVAL;
@@ -360,9 +360,9 @@ static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
 
 static int deemph_settings[] = { 0, 32000, 44100, 48000 };
 
-static int wm8955_set_deemph(struct snd_soc_codec *codec)
+static int wm8955_set_deemph(struct snd_soc_component *component)
 {
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
 	int val, i, best;
 
 	/* If we're using deemphasis select the nearest available sample
@@ -381,17 +381,17 @@ static int wm8955_set_deemph(struct snd_soc_codec *codec)
 		val = 0;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
 
-	return snd_soc_update_bits(codec, WM8955_DAC_CONTROL,
+	return snd_soc_component_update_bits(component, WM8955_DAC_CONTROL,
 				   WM8955_DEEMPH_MASK, val);
 }
 
 static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8955->deemph;
 	return 0;
@@ -400,8 +400,8 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 
 	if (deemph > 1)
@@ -409,7 +409,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
 
 	wm8955->deemph = deemph;
 
-	return wm8955_set_deemph(codec);
+	return wm8955_set_deemph(component);
 }
 
 static const char *bass_mode_text[] = {
@@ -592,8 +592,8 @@ static int wm8955_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
 	int ret;
 	int wl;
 
@@ -613,25 +613,25 @@ static int wm8955_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8955_AUDIO_INTERFACE,
 			    WM8955_WL_MASK, wl);
 
 	wm8955->fs = params_rate(params);
-	wm8955_set_deemph(codec);
+	wm8955_set_deemph(component);
 
 	/* If the chip is clocked then disable the clocks and force a
 	 * reconfiguration, otherwise DAPM will power up the
 	 * clocks for us later. */
-	ret = snd_soc_read(codec, WM8955_POWER_MANAGEMENT_1);
+	ret = snd_soc_component_read32(component, WM8955_POWER_MANAGEMENT_1);
 	if (ret < 0)
 		return ret;
 	if (ret & WM8955_DIGENB) {
-		snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
 				    WM8955_DIGENB, 0);
-		snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
+		snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
 				    WM8955_PLL_RB | WM8955_PLLEN, 0);
 
-		wm8955_configure_clocking(codec);
+		wm8955_configure_clocking(component);
 	}
 
 	return 0;
@@ -641,8 +641,8 @@ static int wm8955_hw_params(struct snd_pcm_substream *substream,
 static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 			     unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8955_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8955_priv *priv = snd_soc_component_get_drvdata(component);
 	int div;
 
 	switch (clk_id) {
@@ -655,7 +655,7 @@ static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 			div = 0;
 		}
 
-		snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
+		snd_soc_component_update_bits(component, WM8955_SAMPLE_RATE,
 				    WM8955_MCLKDIV2, div);
 		break;
 
@@ -670,7 +670,7 @@ static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 aif = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -739,7 +739,7 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8955_AUDIO_INTERFACE,
 			    WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV |
 			    WM8955_LRP, aif);
 
@@ -749,7 +749,7 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
 static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int val;
 
 	if (mute)
@@ -757,15 +757,15 @@ static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 	else
 		val = 0;
 
-	snd_soc_update_bits(codec, WM8955_DAC_CONTROL, WM8955_DACMU, val);
+	snd_soc_component_update_bits(component, WM8955_DAC_CONTROL, WM8955_DACMU, val);
 
 	return 0;
 }
 
-static int wm8955_set_bias_level(struct snd_soc_codec *codec,
+static int wm8955_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -774,22 +774,22 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID resistance 2*50k */
-		snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
 				    WM8955_VMIDSEL_MASK,
 				    0x1 << WM8955_VMIDSEL_SHIFT);
 
 		/* Default bias current */
-		snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_1,
 				    WM8955_VSEL_MASK,
 				    0x2 << WM8955_VSEL_SHIFT);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
 						    wm8955->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -798,7 +798,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
 			regcache_sync(wm8955->regmap);
 
 			/* Enable VREF and VMID */
-			snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
 					    WM8955_VREF |
 					    WM8955_VMIDSEL_MASK,
 					    WM8955_VREF |
@@ -808,29 +808,29 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
 			msleep(500);
 
 			/* High resistance VROI to maintain outputs */
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					    WM8955_ADDITIONAL_CONTROL_3,
 					    WM8955_VROI, WM8955_VROI);
 		}
 
 		/* Maintain VMID with 2*250k */
-		snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
 				    WM8955_VMIDSEL_MASK,
 				    0x2 << WM8955_VMIDSEL_SHIFT);
 
 		/* Minimum bias current */
-		snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_1,
 				    WM8955_VSEL_MASK, 0);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Low resistance VROI to help discharge */
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 				    WM8955_ADDITIONAL_CONTROL_3,
 				    WM8955_VROI, 0);
 
 		/* Turn off VMID and VREF */
-		snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
 				    WM8955_VREF |
 				    WM8955_VMIDSEL_MASK, 0);
 
@@ -865,70 +865,70 @@ static struct snd_soc_dai_driver wm8955_dai = {
 	.ops = &wm8955_dai_ops,
 };
 
-static int wm8955_probe(struct snd_soc_codec *codec)
+static int wm8955_probe(struct snd_soc_component *component)
 {
-	struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-	struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	struct wm8955_pdata *pdata = dev_get_platdata(component->dev);
 	int ret, i;
 
 	for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
 		wm8955->supplies[i].supply = wm8955_supply_names[i];
 
-	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
+	ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(wm8955->supplies),
 				 wm8955->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
 		return ret;
 	}
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
 				    wm8955->supplies);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
-	ret = wm8955_reset(codec);
+	ret = wm8955_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		goto err_enable;
 	}
 
 	/* Change some default settings - latch VU and enable ZC */
-	snd_soc_update_bits(codec, WM8955_LEFT_DAC_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_LEFT_DAC_VOLUME,
 			    WM8955_LDVU, WM8955_LDVU);
-	snd_soc_update_bits(codec, WM8955_RIGHT_DAC_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_RIGHT_DAC_VOLUME,
 			    WM8955_RDVU, WM8955_RDVU);
-	snd_soc_update_bits(codec, WM8955_LOUT1_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_LOUT1_VOLUME,
 			    WM8955_LO1VU | WM8955_LO1ZC,
 			    WM8955_LO1VU | WM8955_LO1ZC);
-	snd_soc_update_bits(codec, WM8955_ROUT1_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_ROUT1_VOLUME,
 			    WM8955_RO1VU | WM8955_RO1ZC,
 			    WM8955_RO1VU | WM8955_RO1ZC);
-	snd_soc_update_bits(codec, WM8955_LOUT2_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_LOUT2_VOLUME,
 			    WM8955_LO2VU | WM8955_LO2ZC,
 			    WM8955_LO2VU | WM8955_LO2ZC);
-	snd_soc_update_bits(codec, WM8955_ROUT2_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_ROUT2_VOLUME,
 			    WM8955_RO2VU | WM8955_RO2ZC,
 			    WM8955_RO2VU | WM8955_RO2ZC);
-	snd_soc_update_bits(codec, WM8955_MONOOUT_VOLUME,
+	snd_soc_component_update_bits(component, WM8955_MONOOUT_VOLUME,
 			    WM8955_MOZC, WM8955_MOZC);
 
 	/* Also enable adaptive bass boost by default */
-	snd_soc_update_bits(codec, WM8955_BASS_CONTROL, WM8955_BB, WM8955_BB);
+	snd_soc_component_update_bits(component, WM8955_BASS_CONTROL, WM8955_BB, WM8955_BB);
 
 	/* Set platform data values */
 	if (pdata) {
 		if (pdata->out2_speaker)
-			snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_2,
+			snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_2,
 					    WM8955_ROUT2INV, WM8955_ROUT2INV);
 
 		if (pdata->monoin_diff)
-			snd_soc_update_bits(codec, WM8955_MONO_OUT_MIX_1,
+			snd_soc_component_update_bits(component, WM8955_MONO_OUT_MIX_1,
 					    WM8955_DMEN, WM8955_DMEN);
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* Bias level configuration will have done an extra enable */
 	regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
@@ -940,19 +940,20 @@ static int wm8955_probe(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
-	.probe =	wm8955_probe,
-	.set_bias_level = wm8955_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8955_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8955_snd_controls),
-		.dapm_widgets		= wm8955_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8955_dapm_widgets),
-		.dapm_routes		= wm8955_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8955_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8955 = {
+	.probe			= wm8955_probe,
+	.set_bias_level		= wm8955_set_bias_level,
+	.controls		= wm8955_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8955_snd_controls),
+	.dapm_widgets		= wm8955_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8955_dapm_widgets),
+	.dapm_routes		= wm8955_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8955_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8955_regmap = {
@@ -989,19 +990,12 @@ static int wm8955_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8955);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8955, &wm8955_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8955, &wm8955_dai, 1);
 
 	return ret;
 }
 
-static int wm8955_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8955_i2c_id[] = {
 	{ "wm8955", 0 },
 	{ }
@@ -1013,7 +1007,6 @@ static struct i2c_driver wm8955_i2c_driver = {
 		.name = "wm8955",
 	},
 	.probe =    wm8955_i2c_probe,
-	.remove =   wm8955_i2c_remove,
 	.id_table = wm8955_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 6b864c0fc2b6..8d495220fa25 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -39,10 +39,10 @@
 #define WM_FW_BLOCK_A    0x08
 #define WM_FW_BLOCK_C    0x0c
 
-static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
+static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
 			  const struct firmware *fw, bool check)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	u64 data64;
 	u32 data32;
 	const u8 *data;
@@ -55,7 +55,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 		return 0;
 
 	if (fw->size < 32) {
-		dev_err(codec->dev, "%s: firmware too short (%zd bytes)\n",
+		dev_err(component->dev, "%s: firmware too short (%zd bytes)\n",
 			name, fw->size);
 		goto err;
 	}
@@ -63,7 +63,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 	if (memcmp(fw->data, "WMFW", 4) != 0) {
 		memcpy(&data32, fw->data, sizeof(data32));
 		data32 = be32_to_cpu(data32);
-		dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
+		dev_err(component->dev, "%s: firmware has bad file magic %08x\n",
 			name, data32);
 		goto err;
 	}
@@ -74,35 +74,35 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 	memcpy(&data32, fw->data + 8, sizeof(data32));
 	data32 = be32_to_cpu(data32);
 	if ((data32 >> 24) & 0xff) {
-		dev_err(codec->dev, "%s: unsupported firmware version %d\n",
+		dev_err(component->dev, "%s: unsupported firmware version %d\n",
 			name, (data32 >> 24) & 0xff);
 		goto err;
 	}
 	if ((data32 & 0xffff) != 8958) {
-		dev_err(codec->dev, "%s: unsupported target device %d\n",
+		dev_err(component->dev, "%s: unsupported target device %d\n",
 			name, data32 & 0xffff);
 		goto err;
 	}
 	if (((data32 >> 16) & 0xff) != 0xc) {
-		dev_err(codec->dev, "%s: unsupported target core %d\n",
+		dev_err(component->dev, "%s: unsupported target core %d\n",
 			name, (data32 >> 16) & 0xff);
 		goto err;
 	}
 
 	if (check) {
 		memcpy(&data64, fw->data + 24, sizeof(u64));
-		dev_info(codec->dev, "%s timestamp %llx\n",
+		dev_info(component->dev, "%s timestamp %llx\n",
 			 name, be64_to_cpu(data64));
 	} else {
-		snd_soc_write(codec, 0x102, 0x2);
-		snd_soc_write(codec, 0x900, 0x2);
+		snd_soc_component_write(component, 0x102, 0x2);
+		snd_soc_component_write(component, 0x900, 0x2);
 	}
 
 	data = fw->data + len;
 	len = fw->size - len;
 	while (len) {
 		if (len < 12) {
-			dev_err(codec->dev, "%s short data block of %zd\n",
+			dev_err(component->dev, "%s short data block of %zd\n",
 				name, len);
 			goto err;
 		}
@@ -110,12 +110,12 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 		memcpy(&data32, data + 4, sizeof(data32));
 		block_len = be32_to_cpu(data32);
 		if (block_len + 8 > len) {
-			dev_err(codec->dev, "%zd byte block longer than file\n",
+			dev_err(component->dev, "%zd byte block longer than file\n",
 				block_len);
 			goto err;
 		}
 		if (block_len == 0) {
-			dev_err(codec->dev, "Zero length block\n");
+			dev_err(component->dev, "Zero length block\n");
 			goto err;
 		}
 
@@ -131,10 +131,10 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 			str = kzalloc(block_len + 1, GFP_KERNEL);
 			if (str) {
 				memcpy(str, data + 8, block_len);
-				dev_info(codec->dev, "%s: %s\n", name, str);
+				dev_info(component->dev, "%s: %s\n", name, str);
 				kfree(str);
 			} else {
-				dev_err(codec->dev, "Out of memory\n");
+				dev_err(component->dev, "Out of memory\n");
 			}
 			break;
 		case WM_FW_BLOCK_PM:
@@ -144,7 +144,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 		case WM_FW_BLOCK_I:
 		case WM_FW_BLOCK_A:
 		case WM_FW_BLOCK_C:
-			dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name,
+			dev_dbg(component->dev, "%s: %zd bytes of %x@%x\n", name,
 				block_len, (data32 >> 24) & 0xff,
 				data32 & 0xffffff);
 
@@ -160,7 +160,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 
 			break;
 		default:
-			dev_warn(codec->dev, "%s: unknown block type %d\n",
+			dev_warn(component->dev, "%s: unknown block type %d\n",
 				 name, (data32 >> 24) & 0xff);
 			break;
 		}
@@ -173,10 +173,10 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 	}
 
 	if (!check) {
-		dev_dbg(codec->dev, "%s: download done\n", name);
+		dev_dbg(component->dev, "%s: download done\n", name);
 		wm8994->cur_fw = fw;
 	} else {
-		dev_info(codec->dev, "%s: got firmware\n", name);
+		dev_info(component->dev, "%s: got firmware\n", name);
 	}
 
 	goto ok;
@@ -185,28 +185,28 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 	ret = -EINVAL;
 ok:
 	if (!check) {
-		snd_soc_write(codec, 0x900, 0x0);
-		snd_soc_write(codec, 0x102, 0x0);
+		snd_soc_component_write(component, 0x900, 0x0);
+		snd_soc_component_write(component, 0x102, 0x0);
 	}
 
 	return ret;
 }
 
-static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
+static void wm8958_dsp_start_mbc(struct snd_soc_component *component, int path)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int i;
 
 	/* If the DSP is already running then noop */
-	if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
+	if (snd_soc_component_read32(component, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
 		return;
 
 	/* If we have MBC firmware download it */
 	if (wm8994->mbc)
-		wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
+		wm8958_dsp2_fw(component, "MBC", wm8994->mbc, false);
 
-	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 
 	/* If we've got user supplied MBC settings use them */
@@ -215,37 +215,37 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
 			= &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
 
 		for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
-			snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
+			snd_soc_component_write(component, i + WM8958_MBC_BAND_1_K_1,
 				      cfg->coeff_regs[i]);
 
 		for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
-			snd_soc_write(codec,
+			snd_soc_component_write(component,
 				      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
 				      cfg->cutoff_regs[i]);
 	}
 
 	/* Run the DSP */
-	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 		      WM8958_DSP2_RUNR);
 
 	/* And we're off! */
-	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 			    WM8958_MBC_ENA |
 			    WM8958_MBC_SEL_MASK,
 			    path << WM8958_MBC_SEL_SHIFT |
 			    WM8958_MBC_ENA);
 }
 
-static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
+static void wm8958_dsp_start_vss(struct snd_soc_component *component, int path)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int i, ena;
 
 	if (wm8994->mbc_vss)
-		wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
+		wm8958_dsp2_fw(component, "MBC+VSS", wm8994->mbc_vss, false);
 
-	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 
 	/* If we've got user supplied settings use them */
@@ -254,7 +254,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
 			= &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
 
 		for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
-			snd_soc_write(codec, i + 0x2800,
+			snd_soc_component_write(component, i + 0x2800,
 				      cfg->combined_regs[i]);
 	}
 
@@ -263,7 +263,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
 			= &control->pdata.vss_cfgs[wm8994->vss_cfg];
 
 		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
-			snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
+			snd_soc_component_write(component, i + 0x2600, cfg->regs[i]);
 	}
 
 	if (control->pdata.num_vss_hpf_cfgs) {
@@ -271,11 +271,11 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
 			= &control->pdata.vss_hpf_cfgs[wm8994->vss_hpf_cfg];
 
 		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
-			snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
+			snd_soc_component_write(component, i + 0x2400, cfg->regs[i]);
 	}
 
 	/* Run the DSP */
-	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 		      WM8958_DSP2_RUNR);
 
 	/* Enable the algorithms we've selected */
@@ -289,23 +289,23 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
 	if (wm8994->vss_ena[path])
 		ena |= 0x1;
 
-	snd_soc_write(codec, 0x2201, ena);
+	snd_soc_component_write(component, 0x2201, ena);
 
 	/* Switch the DSP into the data path */
-	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
 			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
 }
 
-static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
+static void wm8958_dsp_start_enh_eq(struct snd_soc_component *component, int path)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int i;
 
-	wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
+	wm8958_dsp2_fw(component, "ENH_EQ", wm8994->enh_eq, false);
 
-	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 
 	/* If we've got user supplied settings use them */
@@ -314,24 +314,24 @@ static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
 			= &control->pdata.enh_eq_cfgs[wm8994->enh_eq_cfg];
 
 		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
-			snd_soc_write(codec, i + 0x2200,
+			snd_soc_component_write(component, i + 0x2200,
 				      cfg->regs[i]);
 	}
 
 	/* Run the DSP */
-	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 		      WM8958_DSP2_RUNR);
 
 	/* Switch the DSP into the data path */
-	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
 			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
 }
 
-static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
+static void wm8958_dsp_apply(struct snd_soc_component *component, int path, int start)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int pwr_reg = snd_soc_component_read32(component, WM8994_POWER_MANAGEMENT_5);
 	int ena, reg, aif;
 
 	switch (path) {
@@ -359,9 +359,9 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 	if (!pwr_reg)
 		ena = 0;
 
-	reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
+	reg = snd_soc_component_read32(component, WM8958_DSP2_PROGRAM);
 
-	dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
+	dev_dbg(component->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
 		path, wm8994->dsp_active, start, pwr_reg, reg);
 
 	if (start && ena) {
@@ -370,29 +370,29 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 			return;
 
 		/* If either AIFnCLK is not yet enabled postpone */
-		if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
+		if (!(snd_soc_component_read32(component, WM8994_AIF1_CLOCKING_1)
 		      & WM8994_AIF1CLK_ENA_MASK) &&
-		    !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
+		    !(snd_soc_component_read32(component, WM8994_AIF2_CLOCKING_1)
 		      & WM8994_AIF2CLK_ENA_MASK))
 			return;
 
 		/* Switch the clock over to the appropriate AIF */
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
 				    aif << WM8958_DSP2CLK_SRC_SHIFT |
 				    WM8958_DSP2CLK_ENA);
 
 		if (wm8994->enh_eq_ena[path])
-			wm8958_dsp_start_enh_eq(codec, path);
+			wm8958_dsp_start_enh_eq(component, path);
 		else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
 		    wm8994->hpf2_ena[path])
-			wm8958_dsp_start_vss(codec, path);
+			wm8958_dsp_start_vss(component, path);
 		else if (wm8994->mbc_ena[path])
-			wm8958_dsp_start_mbc(codec, path);
+			wm8958_dsp_start_mbc(component, path);
 
 		wm8994->dsp_active = path;
 
-		dev_dbg(codec->dev, "DSP running in path %d\n", path);
+		dev_dbg(component->dev, "DSP running in path %d\n", path);
 	}
 
 	if (!start && wm8994->dsp_active == path) {
@@ -400,37 +400,37 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 		if (!(reg & WM8958_DSP2_ENA))
 			return;
 
-		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+		snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
 				    WM8958_MBC_ENA, 0);	
-		snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
 			      WM8958_DSP2_STOP);
-		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+		snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
 				    WM8958_DSP2_ENA, 0);
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				    WM8958_DSP2CLK_ENA, 0);
 
 		wm8994->dsp_active = -1;
 
-		dev_dbg(codec->dev, "DSP stopped\n");
+		dev_dbg(component->dev, "DSP stopped\n");
 	}
 }
 
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
 		  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int i;
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 	case SND_SOC_DAPM_PRE_PMU:
 		for (i = 0; i < 3; i++)
-			wm8958_dsp_apply(codec, i, 1);
+			wm8958_dsp_apply(component, i, 1);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 	case SND_SOC_DAPM_PRE_PMD:
 		for (i = 0; i < 3; i++)
-			wm8958_dsp_apply(codec, i, 0);
+			wm8958_dsp_apply(component, i, 0);
 		break;
 	}
 
@@ -456,14 +456,14 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
 static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int value = ucontrol->value.enumerated.item[0];
 	int reg;
 
 	/* Don't allow on the fly reconfiguration */
-	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 		return -EBUSY;
 
@@ -478,8 +478,8 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
 
@@ -500,8 +500,8 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int mbc = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
 
@@ -512,8 +512,8 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int mbc = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
 		return 0;
@@ -522,7 +522,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 		return -EINVAL;
 
 	if (wm8958_dsp2_busy(wm8994, mbc)) {
-		dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
+		dev_dbg(component->dev, "DSP2 active on %d already\n", mbc);
 		return -EBUSY;
 	}
 
@@ -531,7 +531,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 
 	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
 
-	wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
+	wm8958_dsp_apply(component, mbc, wm8994->mbc_ena[mbc]);
 
 	return 0;
 }
@@ -546,14 +546,14 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int value = ucontrol->value.enumerated.item[0];
 	int reg;
 
 	/* Don't allow on the fly reconfiguration */
-	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 		return -EBUSY;
 
@@ -568,8 +568,8 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
 
@@ -579,14 +579,14 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int value = ucontrol->value.enumerated.item[0];
 	int reg;
 
 	/* Don't allow on the fly reconfiguration */
-	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 		return -EBUSY;
 
@@ -601,8 +601,8 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
 
@@ -623,8 +623,8 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int vss = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
 
@@ -635,8 +635,8 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int vss = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
 		return 0;
@@ -648,7 +648,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
 		return -ENODEV;
 
 	if (wm8958_dsp2_busy(wm8994, vss)) {
-		dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
+		dev_dbg(component->dev, "DSP2 active on %d already\n", vss);
 		return -EBUSY;
 	}
 
@@ -657,7 +657,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
 
 	wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
 
-	wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
+	wm8958_dsp_apply(component, vss, wm8994->vss_ena[vss]);
 
 	return 0;
 }
@@ -684,8 +684,8 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int hpf = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (hpf < 3)
 		ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
@@ -699,8 +699,8 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int hpf = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (hpf < 3) {
 		if (wm8994->hpf1_ena[hpf % 3] ==
@@ -719,7 +719,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 		return -ENODEV;
 
 	if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
-		dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
+		dev_dbg(component->dev, "DSP2 active on %d already\n", hpf);
 		return -EBUSY;
 	}
 
@@ -731,7 +731,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 	else
 		wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
 
-	wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
+	wm8958_dsp_apply(component, hpf % 3, ucontrol->value.integer.value[0]);
 
 	return 0;
 }
@@ -746,14 +746,14 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int value = ucontrol->value.enumerated.item[0];
 	int reg;
 
 	/* Don't allow on the fly reconfiguration */
-	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 		return -EBUSY;
 
@@ -768,8 +768,8 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
 static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
 
@@ -790,8 +790,8 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int eq = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
 
@@ -802,8 +802,8 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
 	int eq = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
 		return 0;
@@ -815,7 +815,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
 		return -ENODEV;
 
 	if (wm8958_dsp2_busy(wm8994, eq)) {
-		dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
+		dev_dbg(component->dev, "DSP2 active on %d already\n", eq);
 		return -EBUSY;
 	}
 
@@ -825,7 +825,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
 
 	wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
 
-	wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
+	wm8958_dsp_apply(component, eq, ucontrol->value.integer.value[0]);
 
 	return 0;
 }
@@ -863,10 +863,10 @@ WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
 
 static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
 {
-	struct snd_soc_codec *codec = context;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = context;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
-	if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
+	if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) {
 		mutex_lock(&wm8994->fw_lock);
 		wm8994->enh_eq = fw;
 		mutex_unlock(&wm8994->fw_lock);
@@ -875,10 +875,10 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
 
 static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
 {
-	struct snd_soc_codec *codec = context;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = context;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
-	if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
+	if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) {
 		mutex_lock(&wm8994->fw_lock);
 		wm8994->mbc_vss = fw;
 		mutex_unlock(&wm8994->fw_lock);
@@ -887,43 +887,43 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
 
 static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
 {
-	struct snd_soc_codec *codec = context;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = context;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
-	if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) {
+	if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) {
 		mutex_lock(&wm8994->fw_lock);
 		wm8994->mbc = fw;
 		mutex_unlock(&wm8994->fw_lock);
 	}
 }
 
-void wm8958_dsp2_init(struct snd_soc_codec *codec)
+void wm8958_dsp2_init(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int ret, i;
 
 	wm8994->dsp_active = -1;
 
-	snd_soc_add_codec_controls(codec, wm8958_mbc_snd_controls,
+	snd_soc_add_component_controls(component, wm8958_mbc_snd_controls,
 			     ARRAY_SIZE(wm8958_mbc_snd_controls));
-	snd_soc_add_codec_controls(codec, wm8958_vss_snd_controls,
+	snd_soc_add_component_controls(component, wm8958_vss_snd_controls,
 			     ARRAY_SIZE(wm8958_vss_snd_controls));
-	snd_soc_add_codec_controls(codec, wm8958_enh_eq_snd_controls,
+	snd_soc_add_component_controls(component, wm8958_enh_eq_snd_controls,
 			     ARRAY_SIZE(wm8958_enh_eq_snd_controls));
 
 
 	/* We don't *require* firmware and don't want to delay boot */
 	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
-				"wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
-				codec, wm8958_mbc_loaded);
+				"wm8958_mbc.wfw", component->dev, GFP_KERNEL,
+				component, wm8958_mbc_loaded);
 	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
-				"wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
-				codec, wm8958_mbc_vss_loaded);
+				"wm8958_mbc_vss.wfw", component->dev, GFP_KERNEL,
+				component, wm8958_mbc_vss_loaded);
 	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
-				"wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
-				codec, wm8958_enh_eq_loaded);
+				"wm8958_enh_eq.wfw", component->dev, GFP_KERNEL,
+				component, wm8958_enh_eq_loaded);
 
 	if (pdata->num_mbc_cfgs) {
 		struct snd_kcontrol_new control[] = {
@@ -943,10 +943,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
 		wm8994->mbc_enum.items = pdata->num_mbc_cfgs;
 		wm8994->mbc_enum.texts = wm8994->mbc_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->hubs.codec->dev,
+			dev_err(wm8994->hubs.component->dev,
 				"Failed to add MBC mode controls: %d\n", ret);
 	}
 
@@ -968,10 +968,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
 		wm8994->vss_enum.items = pdata->num_vss_cfgs;
 		wm8994->vss_enum.texts = wm8994->vss_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->hubs.codec->dev,
+			dev_err(wm8994->hubs.component->dev,
 				"Failed to add VSS mode controls: %d\n", ret);
 	}
 
@@ -994,10 +994,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
 		wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs;
 		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->hubs.codec->dev,
+			dev_err(wm8994->hubs.component->dev,
 				"Failed to add VSS HPFmode controls: %d\n",
 				ret);
 	}
@@ -1021,10 +1021,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
 		wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs;
 		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 						 control, 1);
 		if (ret != 0)
-			dev_err(wm8994->hubs.codec->dev,
+			dev_err(wm8994->hubs.component->dev,
 				"Failed to add enhanced EQ controls: %d\n",
 				ret);
 	}
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 9ed455700954..c30f5aa392c6 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -49,7 +49,7 @@
 #define WM8960_DRES_MASK 0x30
 
 static bool is_pll_freq_available(unsigned int source, unsigned int target);
-static int wm8960_set_pll(struct snd_soc_codec *codec,
+static int wm8960_set_pll(struct snd_soc_component *component,
 		unsigned int freq_in, unsigned int freq_out);
 /*
  * wm8960 register cache
@@ -123,7 +123,7 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
 struct wm8960_priv {
 	struct clk *mclk;
 	struct regmap *regmap;
-	int (*set_bias_level)(struct snd_soc_codec *,
+	int (*set_bias_level)(struct snd_soc_component *,
 			      enum snd_soc_bias_level level);
 	struct snd_soc_dapm_widget *lout1;
 	struct snd_soc_dapm_widget *rout1;
@@ -168,9 +168,9 @@ static const struct soc_enum wm8960_enum[] = {
 
 static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
 
-static int wm8960_set_deemph(struct snd_soc_codec *codec)
+static int wm8960_set_deemph(struct snd_soc_component *component)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	int val, i, best;
 
 	/* If we're using deemphasis select the nearest available sample
@@ -189,17 +189,17 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
 		val = 0;
 	}
 
-	dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
 
-	return snd_soc_update_bits(codec, WM8960_DACCTL1,
+	return snd_soc_component_update_bits(component, WM8960_DACCTL1,
 				   0x6, val);
 }
 
 static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = wm8960->deemph;
 	return 0;
@@ -208,8 +208,8 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
 static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	unsigned int deemph = ucontrol->value.integer.value[0];
 
 	if (deemph > 1)
@@ -217,7 +217,7 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
 
 	wm8960->deemph = deemph;
 
-	return wm8960_set_deemph(codec);
+	return wm8960_set_deemph(component);
 }
 
 static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
@@ -470,11 +470,11 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = {
 	{ "OUT3 VMID", NULL, "Right Output Mixer" },
 };
 
-static int wm8960_add_widgets(struct snd_soc_codec *codec)
+static int wm8960_add_widgets(struct snd_soc_component *component)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	struct wm8960_data *pdata = &wm8960->pdata;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct snd_soc_dapm_widget *w;
 
 	snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
@@ -504,7 +504,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
 	 * list each time to find the desired power state do so now
 	 * and save the result.
 	 */
-	list_for_each_entry(w, &codec->component.card->widgets, list) {
+	list_for_each_entry(w, &component->card->widgets, list) {
 		if (w->dapm != dapm)
 			continue;
 		if (strcmp(w->name, "LOUT1 PGA") == 0)
@@ -521,7 +521,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
 static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -573,7 +573,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 
 	/* set iface */
-	snd_soc_write(codec, WM8960_IFACE1, iface);
+	snd_soc_component_write(component, WM8960_IFACE1, iface);
 	return 0;
 }
 
@@ -683,7 +683,7 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
  * 	triplet, we relax the bclk such that bclk is chosen as the
  * 	closest available frequency greater than expected bclk.
  *
- * @codec: codec structure
+ * @component: component structure
  * @freq_in: input frequency used to derive freq out via PLL
  * @sysclk_idx: sysclk_divs index for found sysclk
  * @dac_idx: dac_divs index for found lrclk
@@ -695,10 +695,10 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
  *      (@sysclk_idx, @dac_idx, @bclk_idx) dividers
  */
 static
-int wm8960_configure_pll(struct snd_soc_codec *codec, int freq_in,
+int wm8960_configure_pll(struct snd_soc_component *component, int freq_in,
 			 int *sysclk_idx, int *dac_idx, int *bclk_idx)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	int sysclk, bclk, lrclk, freq_out;
 	int diff, closest, best_freq_out;
 	int i, j, k;
@@ -741,22 +741,22 @@ int wm8960_configure_pll(struct snd_soc_codec *codec, int freq_in,
 
 	return best_freq_out;
 }
-static int wm8960_configure_clocking(struct snd_soc_codec *codec)
+static int wm8960_configure_clocking(struct snd_soc_component *component)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	int freq_out, freq_in;
-	u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
+	u16 iface1 = snd_soc_component_read32(component, WM8960_IFACE1);
 	int i, j, k;
 	int ret;
 
 	if (!(iface1 & (1<<6))) {
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			"Codec is slave mode, no need to configure clock\n");
 		return 0;
 	}
 
 	if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) {
-		dev_err(codec->dev, "No MCLK configured\n");
+		dev_err(component->dev, "No MCLK configured\n");
 		return -EINVAL;
 	}
 
@@ -769,12 +769,12 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
 	 */
 	if (wm8960->clk_id == WM8960_SYSCLK_AUTO) {
 		/* disable the PLL and using MCLK to provide sysclk */
-		wm8960_set_pll(codec, 0, 0);
+		wm8960_set_pll(component, 0, 0);
 		freq_out = freq_in;
 	} else if (wm8960->sysclk) {
 		freq_out = wm8960->sysclk;
 	} else {
-		dev_err(codec->dev, "No SYSCLK configured\n");
+		dev_err(component->dev, "No SYSCLK configured\n");
 		return -EINVAL;
 	}
 
@@ -783,28 +783,28 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
 		if (ret >= 0) {
 			goto configure_clock;
 		} else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
-			dev_err(codec->dev, "failed to configure clock\n");
+			dev_err(component->dev, "failed to configure clock\n");
 			return -EINVAL;
 		}
 	}
 
-	freq_out = wm8960_configure_pll(codec, freq_in, &i, &j, &k);
+	freq_out = wm8960_configure_pll(component, freq_in, &i, &j, &k);
 	if (freq_out < 0) {
-		dev_err(codec->dev, "failed to configure clock via PLL\n");
+		dev_err(component->dev, "failed to configure clock via PLL\n");
 		return freq_out;
 	}
-	wm8960_set_pll(codec, freq_in, freq_out);
+	wm8960_set_pll(component, freq_in, freq_out);
 
 configure_clock:
 	/* configure sysclk clock */
-	snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 3 << 1, i << 1);
 
 	/* configure frame clock */
-	snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3);
-	snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x7 << 3, j << 3);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x7 << 6, j << 6);
 
 	/* configure bit clock */
-	snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k);
+	snd_soc_component_update_bits(component, WM8960_CLOCK2, 0xf, k);
 
 	return 0;
 }
@@ -813,9 +813,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
+	struct snd_soc_component *component = dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8960_IFACE1) & 0xfff3;
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	int i;
 
@@ -840,7 +840,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
 			break;
 		}
 	default:
-		dev_err(codec->dev, "unsupported width %d\n",
+		dev_err(component->dev, "unsupported width %d\n",
 			params_width(params));
 		return -EINVAL;
 	}
@@ -848,23 +848,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
 	wm8960->lrclk = params_rate(params);
 	/* Update filters for the new rate */
 	if (tx) {
-		wm8960_set_deemph(codec);
+		wm8960_set_deemph(component);
 	} else {
 		for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
 			if (alc_rates[i].rate == params_rate(params))
-				snd_soc_update_bits(codec,
+				snd_soc_component_update_bits(component,
 						    WM8960_ADDCTL3, 0x7,
 						    alc_rates[i].val);
 	}
 
 	/* set iface */
-	snd_soc_write(codec, WM8960_IFACE1, iface);
+	snd_soc_component_write(component, WM8960_IFACE1, iface);
 
 	wm8960->is_stream_in_use[tx] = true;
 
-	if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON &&
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON &&
 	    !wm8960->is_stream_in_use[!tx])
-		return wm8960_configure_clocking(codec);
+		return wm8960_configure_clocking(component);
 
 	return 0;
 }
@@ -872,8 +872,8 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
 static int wm8960_hw_free(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
 	wm8960->is_stream_in_use[tx] = false;
@@ -883,20 +883,20 @@ static int wm8960_hw_free(struct snd_pcm_substream *substream,
 
 static int wm8960_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	if (mute)
-		snd_soc_update_bits(codec, WM8960_DACCTL1, 0x8, 0x8);
+		snd_soc_component_update_bits(component, WM8960_DACCTL1, 0x8, 0x8);
 	else
-		snd_soc_update_bits(codec, WM8960_DACCTL1, 0x8, 0);
+		snd_soc_component_update_bits(component, WM8960_DACCTL1, 0x8, 0);
 	return 0;
 }
 
-static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
+static int wm8960_set_bias_level_out3(struct snd_soc_component *component,
 				      enum snd_soc_bias_level level)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-	u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	u16 pm2 = snd_soc_component_read32(component, WM8960_POWER2);
 	int ret;
 
 	switch (level) {
@@ -904,24 +904,24 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		switch (snd_soc_codec_get_bias_level(codec)) {
+		switch (snd_soc_component_get_bias_level(component)) {
 		case SND_SOC_BIAS_STANDBY:
 			if (!IS_ERR(wm8960->mclk)) {
 				ret = clk_prepare_enable(wm8960->mclk);
 				if (ret) {
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Failed to enable MCLK: %d\n",
 						ret);
 					return ret;
 				}
 			}
 
-			ret = wm8960_configure_clocking(codec);
+			ret = wm8960_configure_clocking(component);
 			if (ret)
 				return ret;
 
 			/* Set VMID to 2x50k */
-			snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
+			snd_soc_component_update_bits(component, WM8960_POWER1, 0x180, 0x80);
 			break;
 
 		case SND_SOC_BIAS_ON:
@@ -930,7 +930,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 			 * disable the pll
 			 */
 			if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
-				wm8960_set_pll(codec, 0, 0);
+				wm8960_set_pll(component, 0, 0);
 
 			if (!IS_ERR(wm8960->mclk))
 				clk_disable_unprepare(wm8960->mclk);
@@ -943,38 +943,38 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_sync(wm8960->regmap);
 
 			/* Enable anti-pop features */
-			snd_soc_write(codec, WM8960_APOP1,
+			snd_soc_component_write(component, WM8960_APOP1,
 				      WM8960_POBCTRL | WM8960_SOFT_ST |
 				      WM8960_BUFDCOPEN | WM8960_BUFIOEN);
 
 			/* Enable & ramp VMID at 2x50k */
-			snd_soc_update_bits(codec, WM8960_POWER1, 0x80, 0x80);
+			snd_soc_component_update_bits(component, WM8960_POWER1, 0x80, 0x80);
 			msleep(100);
 
 			/* Enable VREF */
-			snd_soc_update_bits(codec, WM8960_POWER1, WM8960_VREF,
+			snd_soc_component_update_bits(component, WM8960_POWER1, WM8960_VREF,
 					    WM8960_VREF);
 
 			/* Disable anti-pop features */
-			snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
+			snd_soc_component_write(component, WM8960_APOP1, WM8960_BUFIOEN);
 		}
 
 		/* Set VMID to 2x250k */
-		snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x100);
+		snd_soc_component_update_bits(component, WM8960_POWER1, 0x180, 0x100);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable anti-pop features */
-		snd_soc_write(codec, WM8960_APOP1,
+		snd_soc_component_write(component, WM8960_APOP1,
 			     WM8960_POBCTRL | WM8960_SOFT_ST |
 			     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
 
 		/* Disable VMID and VREF, let them discharge */
-		snd_soc_write(codec, WM8960_POWER1, 0);
+		snd_soc_component_write(component, WM8960_POWER1, 0);
 		msleep(600);
 		break;
 	}
@@ -982,11 +982,11 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
+static int wm8960_set_bias_level_capless(struct snd_soc_component *component,
 					 enum snd_soc_bias_level level)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-	u16 pm2 = snd_soc_read(codec, WM8960_POWER2);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	u16 pm2 = snd_soc_component_read32(component, WM8960_POWER2);
 	int reg, ret;
 
 	switch (level) {
@@ -994,10 +994,10 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		switch (snd_soc_codec_get_bias_level(codec)) {
+		switch (snd_soc_component_get_bias_level(component)) {
 		case SND_SOC_BIAS_STANDBY:
 			/* Enable anti pop mode */
-			snd_soc_update_bits(codec, WM8960_APOP1,
+			snd_soc_component_update_bits(component, WM8960_APOP1,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
 					    WM8960_BUFDCOPEN,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -1011,20 +1011,20 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 				reg |= WM8960_PWR2_ROUT1;
 			if (wm8960->out3 && wm8960->out3->power)
 				reg |= WM8960_PWR2_OUT3;
-			snd_soc_update_bits(codec, WM8960_POWER2,
+			snd_soc_component_update_bits(component, WM8960_POWER2,
 					    WM8960_PWR2_LOUT1 |
 					    WM8960_PWR2_ROUT1 |
 					    WM8960_PWR2_OUT3, reg);
 
 			/* Enable VMID at 2*50k */
-			snd_soc_update_bits(codec, WM8960_POWER1,
+			snd_soc_component_update_bits(component, WM8960_POWER1,
 					    WM8960_VMID_MASK, 0x80);
 
 			/* Ramp */
 			msleep(100);
 
 			/* Enable VREF */
-			snd_soc_update_bits(codec, WM8960_POWER1,
+			snd_soc_component_update_bits(component, WM8960_POWER1,
 					    WM8960_VREF, WM8960_VREF);
 
 			msleep(100);
@@ -1032,14 +1032,14 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 			if (!IS_ERR(wm8960->mclk)) {
 				ret = clk_prepare_enable(wm8960->mclk);
 				if (ret) {
-					dev_err(codec->dev,
+					dev_err(component->dev,
 						"Failed to enable MCLK: %d\n",
 						ret);
 					return ret;
 				}
 			}
 
-			ret = wm8960_configure_clocking(codec);
+			ret = wm8960_configure_clocking(component);
 			if (ret)
 				return ret;
 
@@ -1051,20 +1051,20 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 			 * disable the pll
 			 */
 			if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
-				wm8960_set_pll(codec, 0, 0);
+				wm8960_set_pll(component, 0, 0);
 
 			if (!IS_ERR(wm8960->mclk))
 				clk_disable_unprepare(wm8960->mclk);
 
 			/* Enable anti-pop mode */
-			snd_soc_update_bits(codec, WM8960_APOP1,
+			snd_soc_component_update_bits(component, WM8960_APOP1,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
 					    WM8960_BUFDCOPEN,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
 					    WM8960_BUFDCOPEN);
 
 			/* Disable VMID and VREF */
-			snd_soc_update_bits(codec, WM8960_POWER1,
+			snd_soc_component_update_bits(component, WM8960_POWER1,
 					    WM8960_VREF | WM8960_VMID_MASK, 0);
 			break;
 
@@ -1077,15 +1077,15 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		switch (snd_soc_codec_get_bias_level(codec)) {
+		switch (snd_soc_component_get_bias_level(component)) {
 		case SND_SOC_BIAS_PREPARE:
 			/* Disable HP discharge */
-			snd_soc_update_bits(codec, WM8960_APOP2,
+			snd_soc_component_update_bits(component, WM8960_APOP2,
 					    WM8960_DISOP | WM8960_DRES_MASK,
 					    0);
 
 			/* Disable anti-pop features */
-			snd_soc_update_bits(codec, WM8960_APOP1,
+			snd_soc_component_update_bits(component, WM8960_APOP1,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
 					    WM8960_BUFDCOPEN,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -1184,7 +1184,7 @@ static int pll_factors(unsigned int source, unsigned int target,
 	return 0;
 }
 
-static int wm8960_set_pll(struct snd_soc_codec *codec,
+static int wm8960_set_pll(struct snd_soc_component *component,
 		unsigned int freq_in, unsigned int freq_out)
 {
 	u16 reg;
@@ -1199,29 +1199,29 @@ static int wm8960_set_pll(struct snd_soc_codec *codec,
 
 	/* Disable the PLL: even if we are changing the frequency the
 	 * PLL needs to be disabled while we do so. */
-	snd_soc_update_bits(codec, WM8960_CLOCK1, 0x1, 0);
-	snd_soc_update_bits(codec, WM8960_POWER2, 0x1, 0);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x1, 0);
+	snd_soc_component_update_bits(component, WM8960_POWER2, 0x1, 0);
 
 	if (!freq_in || !freq_out)
 		return 0;
 
-	reg = snd_soc_read(codec, WM8960_PLL1) & ~0x3f;
+	reg = snd_soc_component_read32(component, WM8960_PLL1) & ~0x3f;
 	reg |= pll_div.pre_div << 4;
 	reg |= pll_div.n;
 
 	if (pll_div.k) {
 		reg |= 0x20;
 
-		snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
-		snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
-		snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff);
+		snd_soc_component_write(component, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
+		snd_soc_component_write(component, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
+		snd_soc_component_write(component, WM8960_PLL4, pll_div.k & 0xff);
 	}
-	snd_soc_write(codec, WM8960_PLL1, reg);
+	snd_soc_component_write(component, WM8960_PLL1, reg);
 
 	/* Turn it on */
-	snd_soc_update_bits(codec, WM8960_POWER2, 0x1, 0x1);
+	snd_soc_component_update_bits(component, WM8960_POWER2, 0x1, 0x1);
 	msleep(250);
-	snd_soc_update_bits(codec, WM8960_CLOCK1, 0x1, 0x1);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x1, 0x1);
 
 	return 0;
 }
@@ -1229,43 +1229,43 @@ static int wm8960_set_pll(struct snd_soc_codec *codec,
 static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 
 	wm8960->freq_in = freq_in;
 
 	if (pll_id == WM8960_SYSCLK_AUTO)
 		return 0;
 
-	return wm8960_set_pll(codec, freq_in, freq_out);
+	return wm8960_set_pll(component, freq_in, freq_out);
 }
 
 static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8960_SYSCLKDIV:
-		reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9;
-		snd_soc_write(codec, WM8960_CLOCK1, reg | div);
+		reg = snd_soc_component_read32(component, WM8960_CLOCK1) & 0x1f9;
+		snd_soc_component_write(component, WM8960_CLOCK1, reg | div);
 		break;
 	case WM8960_DACDIV:
-		reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7;
-		snd_soc_write(codec, WM8960_CLOCK1, reg | div);
+		reg = snd_soc_component_read32(component, WM8960_CLOCK1) & 0x1c7;
+		snd_soc_component_write(component, WM8960_CLOCK1, reg | div);
 		break;
 	case WM8960_OPCLKDIV:
-		reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f;
-		snd_soc_write(codec, WM8960_PLL1, reg | div);
+		reg = snd_soc_component_read32(component, WM8960_PLL1) & 0x03f;
+		snd_soc_component_write(component, WM8960_PLL1, reg | div);
 		break;
 	case WM8960_DCLKDIV:
-		reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f;
-		snd_soc_write(codec, WM8960_CLOCK2, reg | div);
+		reg = snd_soc_component_read32(component, WM8960_CLOCK2) & 0x03f;
+		snd_soc_component_write(component, WM8960_CLOCK2, reg | div);
 		break;
 	case WM8960_TOCLKSEL:
-		reg = snd_soc_read(codec, WM8960_ADDCTL1) & 0x1fd;
-		snd_soc_write(codec, WM8960_ADDCTL1, reg | div);
+		reg = snd_soc_component_read32(component, WM8960_ADDCTL1) & 0x1fd;
+		snd_soc_component_write(component, WM8960_ADDCTL1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1274,27 +1274,27 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+static int wm8960_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 
-	return wm8960->set_bias_level(codec, level);
+	return wm8960->set_bias_level(component, level);
 }
 
 static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 					unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM8960_SYSCLK_MCLK:
-		snd_soc_update_bits(codec, WM8960_CLOCK1,
+		snd_soc_component_update_bits(component, WM8960_CLOCK1,
 					0x1, WM8960_SYSCLK_MCLK);
 		break;
 	case WM8960_SYSCLK_PLL:
-		snd_soc_update_bits(codec, WM8960_CLOCK1,
+		snd_soc_component_update_bits(component, WM8960_CLOCK1,
 					0x1, WM8960_SYSCLK_PLL);
 		break;
 	case WM8960_SYSCLK_AUTO:
@@ -1343,9 +1343,9 @@ static struct snd_soc_dai_driver wm8960_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8960_probe(struct snd_soc_codec *codec)
+static int wm8960_probe(struct snd_soc_component *component)
 {
-	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
 	struct wm8960_data *pdata = &wm8960->pdata;
 
 	if (pdata->capless)
@@ -1353,17 +1353,21 @@ static int wm8960_probe(struct snd_soc_codec *codec)
 	else
 		wm8960->set_bias_level = wm8960_set_bias_level_out3;
 
-	snd_soc_add_codec_controls(codec, wm8960_snd_controls,
+	snd_soc_add_component_controls(component, wm8960_snd_controls,
 				     ARRAY_SIZE(wm8960_snd_controls));
-	wm8960_add_widgets(codec);
+	wm8960_add_widgets(component);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
-	.probe =	wm8960_probe,
-	.set_bias_level = wm8960_set_bias_level,
-	.suspend_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_wm8960 = {
+	.probe			= wm8960_probe,
+	.set_bias_level		= wm8960_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8960_regmap = {
@@ -1447,15 +1451,14 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8960);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8960, &wm8960_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8960, &wm8960_dai, 1);
 
 	return ret;
 }
 
 static int wm8960_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index e23ceac76015..f70f563d59f3 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -194,89 +194,89 @@ static bool wm8961_readable(struct device *dev, unsigned int reg)
 static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
-	u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
-	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
-	u16 dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 hp_reg = snd_soc_component_read32(component, WM8961_ANALOGUE_HP_0);
+	u16 cp_reg = snd_soc_component_read32(component, WM8961_CHARGE_PUMP_1);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_2);
+	u16 dcs_reg = snd_soc_component_read32(component, WM8961_DC_SERVO_1);
 	int timeout = 500;
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Make sure the output is shorted */
 		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Enable the charge pump */
 		cp_reg |= WM8961_CP_ENA;
-		snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg);
+		snd_soc_component_write(component, WM8961_CHARGE_PUMP_1, cp_reg);
 		mdelay(5);
 
 		/* Enable the PGA */
 		pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA;
-		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
 
 		/* Enable the amplifier */
 		hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA;
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Second stage enable */
 		hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY;
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Enable the DC servo & trigger startup */
 		dcs_reg |=
 			WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_TRIG_STARTUP_HPR |
 			WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL;
-		dev_dbg(codec->dev, "Enabling DC servo\n");
+		dev_dbg(component->dev, "Enabling DC servo\n");
 
-		snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
+		snd_soc_component_write(component, WM8961_DC_SERVO_1, dcs_reg);
 		do {
 			msleep(1);
-			dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
+			dcs_reg = snd_soc_component_read32(component, WM8961_DC_SERVO_1);
 		} while (--timeout &&
 			 dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
 				WM8961_DCS_TRIG_STARTUP_HPL));
 		if (dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
 			       WM8961_DCS_TRIG_STARTUP_HPL))
-			dev_err(codec->dev, "DC servo timed out\n");
+			dev_err(component->dev, "DC servo timed out\n");
 		else
-			dev_dbg(codec->dev, "DC servo startup complete\n");
+			dev_dbg(component->dev, "DC servo startup complete\n");
 
 		/* Enable the output stage */
 		hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP;
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Remove the short on the output stage */
 		hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT;
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMD) {
 		/* Short the output */
 		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Disable the output stage */
 		hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP);
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Disable DC offset cancellation */
 		dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR |
 			     WM8961_DCS_ENA_CHAN_HPL);
-		snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
+		snd_soc_component_write(component, WM8961_DC_SERVO_1, dcs_reg);
 
 		/* Finish up */
 		hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA |
 			    WM8961_HPL_ENA_DLY | WM8961_HPL_ENA);
-		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
 
 		/* Disable the PGA */
 		pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA);
-		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
 
 		/* Disable the charge pump */
-		dev_dbg(codec->dev, "Disabling charge pump\n");
-		snd_soc_write(codec, WM8961_CHARGE_PUMP_1,
+		dev_dbg(component->dev, "Disabling charge pump\n");
+		snd_soc_component_write(component, WM8961_CHARGE_PUMP_1,
 			     cp_reg & ~WM8961_CP_ENA);
 	}
 
@@ -286,28 +286,28 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
 static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
-	u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_2);
+	u16 spk_reg = snd_soc_component_read32(component, WM8961_CLASS_D_CONTROL_1);
 
 	if (event & SND_SOC_DAPM_POST_PMU) {
 		/* Enable the PGA */
 		pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA;
-		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
 
 		/* Enable the amplifier */
 		spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA;
-		snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
+		snd_soc_component_write(component, WM8961_CLASS_D_CONTROL_1, spk_reg);
 	}
 
 	if (event & SND_SOC_DAPM_PRE_PMD) {
 		/* Disable the amplifier */
 		spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA);
-		snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
+		snd_soc_component_write(component, WM8961_CLASS_D_CONTROL_1, spk_reg);
 
 		/* Disable the PGA */
 		pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA);
-		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
 	}
 
 	return 0;
@@ -505,15 +505,15 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8961_priv *wm8961 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8961_priv *wm8961 = snd_soc_component_get_drvdata(component);
 	int i, best, target, fs;
 	u16 reg;
 
 	fs = params_rate(params);
 
 	if (!wm8961->sysclk) {
-		dev_err(codec->dev, "MCLK has not been specified\n");
+		dev_err(component->dev, "MCLK has not been specified\n");
 		return -EINVAL;
 	}
 
@@ -524,23 +524,23 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
 		    abs(wm8961_srate[best].rate - fs))
 			best = i;
 	}
-	reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3);
+	reg = snd_soc_component_read32(component, WM8961_ADDITIONAL_CONTROL_3);
 	reg &= ~WM8961_SAMPLE_RATE_MASK;
 	reg |= wm8961_srate[best].val;
-	snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg);
-	dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n",
+	snd_soc_component_write(component, WM8961_ADDITIONAL_CONTROL_3, reg);
+	dev_dbg(component->dev, "Selected SRATE %dHz for %dHz\n",
 		wm8961_srate[best].rate, fs);
 
 	/* Select a CLK_SYS/fs ratio equal to or higher than required */
 	target = wm8961->sysclk / fs;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"SYSCLK must be at least 64*fs for DAC\n");
 		return -EINVAL;
 	}
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"SYSCLK must be at least 256*fs for ADC\n");
 		return -EINVAL;
 	}
@@ -550,19 +550,19 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
 			break;
 	}
 	if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) {
-		dev_err(codec->dev, "Unable to generate CLK_SYS_RATE\n");
+		dev_err(component->dev, "Unable to generate CLK_SYS_RATE\n");
 		return -EINVAL;
 	}
-	dev_dbg(codec->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n",
+	dev_dbg(component->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n",
 		wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs,
 		wm8961->sysclk / fs);
 
-	reg = snd_soc_read(codec, WM8961_CLOCKING_4);
+	reg = snd_soc_component_read32(component, WM8961_CLOCKING_4);
 	reg &= ~WM8961_CLK_SYS_RATE_MASK;
 	reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT;
-	snd_soc_write(codec, WM8961_CLOCKING_4, reg);
+	snd_soc_component_write(component, WM8961_CLOCKING_4, reg);
 
-	reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
+	reg = snd_soc_component_read32(component, WM8961_AUDIO_INTERFACE_0);
 	reg &= ~WM8961_WL_MASK;
 	switch (params_width(params)) {
 	case 16:
@@ -579,15 +579,15 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
 	default:
 		return -EINVAL;
 	}
-	snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg);
+	snd_soc_component_write(component, WM8961_AUDIO_INTERFACE_0, reg);
 
 	/* Sloping stop-band filter is recommended for <= 24kHz */
-	reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
+	reg = snd_soc_component_read32(component, WM8961_ADC_DAC_CONTROL_2);
 	if (fs <= 24000)
 		reg |= WM8961_DACSLOPE;
 	else
 		reg &= ~WM8961_DACSLOPE;
-	snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
+	snd_soc_component_write(component, WM8961_ADC_DAC_CONTROL_2, reg);
 
 	return 0;
 }
@@ -596,25 +596,25 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 			     unsigned int freq,
 			     int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8961_priv *wm8961 = snd_soc_codec_get_drvdata(codec);
-	u16 reg = snd_soc_read(codec, WM8961_CLOCKING1);
+	struct snd_soc_component *component = dai->component;
+	struct wm8961_priv *wm8961 = snd_soc_component_get_drvdata(component);
+	u16 reg = snd_soc_component_read32(component, WM8961_CLOCKING1);
 
 	if (freq > 33000000) {
-		dev_err(codec->dev, "MCLK must be <33MHz\n");
+		dev_err(component->dev, "MCLK must be <33MHz\n");
 		return -EINVAL;
 	}
 
 	if (freq > 16500000) {
-		dev_dbg(codec->dev, "Using MCLK/2 for %dHz MCLK\n", freq);
+		dev_dbg(component->dev, "Using MCLK/2 for %dHz MCLK\n", freq);
 		reg |= WM8961_MCLKDIV;
 		freq /= 2;
 	} else {
-		dev_dbg(codec->dev, "Using MCLK/1 for %dHz MCLK\n", freq);
+		dev_dbg(component->dev, "Using MCLK/1 for %dHz MCLK\n", freq);
 		reg &= ~WM8961_MCLKDIV;
 	}
 
-	snd_soc_write(codec, WM8961_CLOCKING1, reg);
+	snd_soc_component_write(component, WM8961_CLOCKING1, reg);
 
 	wm8961->sysclk = freq;
 
@@ -623,8 +623,8 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 aif = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
+	struct snd_soc_component *component = dai->component;
+	u16 aif = snd_soc_component_read32(component, WM8961_AUDIO_INTERFACE_0);
 
 	aif &= ~(WM8961_BCLKINV | WM8961_LRP |
 		 WM8961_MS | WM8961_FORMAT_MASK);
@@ -684,26 +684,26 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	return snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, aif);
+	return snd_soc_component_write(component, WM8961_AUDIO_INTERFACE_0, aif);
 }
 
 static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_2);
+	struct snd_soc_component *component = dai->component;
+	u16 reg = snd_soc_component_read32(component, WM8961_ADDITIONAL_CONTROL_2);
 
 	if (tristate)
 		reg |= WM8961_TRIS;
 	else
 		reg &= ~WM8961_TRIS;
 
-	return snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg);
+	return snd_soc_component_write(component, WM8961_ADDITIONAL_CONTROL_2, reg);
 }
 
 static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_1);
+	struct snd_soc_component *component = dai->component;
+	u16 reg = snd_soc_component_read32(component, WM8961_ADC_DAC_CONTROL_1);
 
 	if (mute)
 		reg |= WM8961_DACMU;
@@ -712,27 +712,27 @@ static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
 
 	msleep(17);
 
-	return snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_1, reg);
+	return snd_soc_component_write(component, WM8961_ADC_DAC_CONTROL_1, reg);
 }
 
 static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8961_BCLK:
-		reg = snd_soc_read(codec, WM8961_CLOCKING2);
+		reg = snd_soc_component_read32(component, WM8961_CLOCKING2);
 		reg &= ~WM8961_BCLKDIV_MASK;
 		reg |= div;
-		snd_soc_write(codec, WM8961_CLOCKING2, reg);
+		snd_soc_component_write(component, WM8961_CLOCKING2, reg);
 		break;
 
 	case WM8961_LRCLK:
-		reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_2);
+		reg = snd_soc_component_read32(component, WM8961_AUDIO_INTERFACE_2);
 		reg &= ~WM8961_LRCLK_RATE_MASK;
 		reg |= div;
-		snd_soc_write(codec, WM8961_AUDIO_INTERFACE_2, reg);
+		snd_soc_component_write(component, WM8961_AUDIO_INTERFACE_2, reg);
 		break;
 
 	default:
@@ -742,7 +742,7 @@ static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
 	return 0;
 }
 
-static int wm8961_set_bias_level(struct snd_soc_codec *codec,
+static int wm8961_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	u16 reg;
@@ -757,36 +757,36 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
 			/* Enable bias generation */
-			reg = snd_soc_read(codec, WM8961_ANTI_POP);
+			reg = snd_soc_component_read32(component, WM8961_ANTI_POP);
 			reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
-			snd_soc_write(codec, WM8961_ANTI_POP, reg);
+			snd_soc_component_write(component, WM8961_ANTI_POP, reg);
 
 			/* VMID=2*50k, VREF */
-			reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
+			reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_1);
 			reg &= ~WM8961_VMIDSEL_MASK;
 			reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF;
-			snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
+			snd_soc_component_write(component, WM8961_PWR_MGMT_1, reg);
 		}
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
 			/* VREF off */
-			reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
+			reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_1);
 			reg &= ~WM8961_VREF;
-			snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
+			snd_soc_component_write(component, WM8961_PWR_MGMT_1, reg);
 
 			/* Bias generation off */
-			reg = snd_soc_read(codec, WM8961_ANTI_POP);
+			reg = snd_soc_component_read32(component, WM8961_ANTI_POP);
 			reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN);
-			snd_soc_write(codec, WM8961_ANTI_POP, reg);
+			snd_soc_component_write(component, WM8961_ANTI_POP, reg);
 
 			/* VMID off */
-			reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
+			reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_1);
 			reg &= ~WM8961_VMIDSEL_MASK;
-			snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
+			snd_soc_component_write(component, WM8961_PWR_MGMT_1, reg);
 		}
 		break;
 
@@ -830,51 +830,51 @@ static struct snd_soc_dai_driver wm8961_dai = {
 	.ops = &wm8961_dai_ops,
 };
 
-static int wm8961_probe(struct snd_soc_codec *codec)
+static int wm8961_probe(struct snd_soc_component *component)
 {
 	u16 reg;
 
 	/* Enable class W */
-	reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);
+	reg = snd_soc_component_read32(component, WM8961_CHARGE_PUMP_B);
 	reg |= WM8961_CP_DYN_PWR_MASK;
-	snd_soc_write(codec, WM8961_CHARGE_PUMP_B, reg);
+	snd_soc_component_write(component, WM8961_CHARGE_PUMP_B, reg);
 
 	/* Latch volume update bits (right channel only, we always
 	 * write both out) and default ZC on. */
-	reg = snd_soc_read(codec, WM8961_ROUT1_VOLUME);
-	snd_soc_write(codec, WM8961_ROUT1_VOLUME,
+	reg = snd_soc_component_read32(component, WM8961_ROUT1_VOLUME);
+	snd_soc_component_write(component, WM8961_ROUT1_VOLUME,
 		     reg | WM8961_LO1ZC | WM8961_OUT1VU);
-	snd_soc_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
-	reg = snd_soc_read(codec, WM8961_ROUT2_VOLUME);
-	snd_soc_write(codec, WM8961_ROUT2_VOLUME,
+	snd_soc_component_write(component, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
+	reg = snd_soc_component_read32(component, WM8961_ROUT2_VOLUME);
+	snd_soc_component_write(component, WM8961_ROUT2_VOLUME,
 		     reg | WM8961_SPKRZC | WM8961_SPKVU);
-	snd_soc_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
+	snd_soc_component_write(component, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
 
-	reg = snd_soc_read(codec, WM8961_RIGHT_ADC_VOLUME);
-	snd_soc_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
-	reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME);
-	snd_soc_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
+	reg = snd_soc_component_read32(component, WM8961_RIGHT_ADC_VOLUME);
+	snd_soc_component_write(component, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
+	reg = snd_soc_component_read32(component, WM8961_RIGHT_INPUT_VOLUME);
+	snd_soc_component_write(component, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
 
 	/* Use soft mute by default */
-	reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
+	reg = snd_soc_component_read32(component, WM8961_ADC_DAC_CONTROL_2);
 	reg |= WM8961_DACSMM;
-	snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
+	snd_soc_component_write(component, WM8961_ADC_DAC_CONTROL_2, reg);
 
 	/* Use automatic clocking mode by default; for now this is all
 	 * we support.
 	 */
-	reg = snd_soc_read(codec, WM8961_CLOCKING_3);
+	reg = snd_soc_component_read32(component, WM8961_CLOCKING_3);
 	reg &= ~WM8961_MANUAL_MODE;
-	snd_soc_write(codec, WM8961_CLOCKING_3, reg);
+	snd_soc_component_write(component, WM8961_CLOCKING_3, reg);
 
 	return 0;
 }
 
 #ifdef CONFIG_PM
 
-static int wm8961_resume(struct snd_soc_codec *codec)
+static int wm8961_resume(struct snd_soc_component *component)
 {
-	snd_soc_cache_sync(codec);
+	snd_soc_component_cache_sync(component);
 
 	return 0;
 }
@@ -882,20 +882,21 @@ static int wm8961_resume(struct snd_soc_codec *codec)
 #define wm8961_resume NULL
 #endif
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
-	.probe =	wm8961_probe,
-	.resume =	wm8961_resume,
-	.set_bias_level = wm8961_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8961_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8961_snd_controls),
-		.dapm_widgets		= wm8961_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8961_dapm_widgets),
-		.dapm_routes		= audio_paths,
-		.num_dapm_routes	= ARRAY_SIZE(audio_paths),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8961 = {
+	.probe			= wm8961_probe,
+	.resume			= wm8961_resume,
+	.set_bias_level		= wm8961_set_bias_level,
+	.controls		= wm8961_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8961_snd_controls),
+	.dapm_widgets		= wm8961_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8961_dapm_widgets),
+	.dapm_routes		= audio_paths,
+	.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8961_regmap = {
@@ -961,19 +962,12 @@ static int wm8961_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8961);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8961, &wm8961_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8961, &wm8961_dai, 1);
 
 	return ret;
 }
 
-static int wm8961_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8961_i2c_id[] = {
 	{ "wm8961", 0 },
 	{ }
@@ -985,7 +979,6 @@ static struct i2c_driver wm8961_i2c_driver = {
 		.name = "wm8961",
 	},
 	.probe =    wm8961_i2c_probe,
-	.remove =   wm8961_i2c_remove,
 	.id_table = wm8961_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index fd2731d171dd..a11e9d6bf950 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -55,7 +55,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
 struct wm8962_priv {
 	struct wm8962_pdata pdata;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
 	int sysclk;
 	int sysclk_rate;
@@ -1475,55 +1475,55 @@ static const DECLARE_TLV_DB_RANGE(classd_tlv,
 );
 static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
 
-static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
+static int wm8962_dsp2_write_config(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
 	return regcache_sync_region(wm8962->regmap,
 				    WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
 }
 
-static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
+static int wm8962_dsp2_set_enable(struct snd_soc_component *component, u16 val)
 {
-	u16 adcl = snd_soc_read(codec, WM8962_LEFT_ADC_VOLUME);
-	u16 adcr = snd_soc_read(codec, WM8962_RIGHT_ADC_VOLUME);
-	u16 dac = snd_soc_read(codec, WM8962_ADC_DAC_CONTROL_1);
+	u16 adcl = snd_soc_component_read32(component, WM8962_LEFT_ADC_VOLUME);
+	u16 adcr = snd_soc_component_read32(component, WM8962_RIGHT_ADC_VOLUME);
+	u16 dac = snd_soc_component_read32(component, WM8962_ADC_DAC_CONTROL_1);
 
 	/* Mute the ADCs and DACs */
-	snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, 0);
-	snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
-	snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+	snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, 0);
+	snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
+	snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
 			    WM8962_DAC_MUTE, WM8962_DAC_MUTE);
 
-	snd_soc_write(codec, WM8962_SOUNDSTAGE_ENABLES_0, val);
+	snd_soc_component_write(component, WM8962_SOUNDSTAGE_ENABLES_0, val);
 
 	/* Restore the ADCs and DACs */
-	snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, adcl);
-	snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, adcr);
-	snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+	snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, adcl);
+	snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, adcr);
+	snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
 			    WM8962_DAC_MUTE, dac);
 
 	return 0;
 }
 
-static int wm8962_dsp2_start(struct snd_soc_codec *codec)
+static int wm8962_dsp2_start(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
-	wm8962_dsp2_write_config(codec);
+	wm8962_dsp2_write_config(component);
 
-	snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
+	snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
 
-	wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
+	wm8962_dsp2_set_enable(component, wm8962->dsp2_ena);
 
 	return 0;
 }
 
-static int wm8962_dsp2_stop(struct snd_soc_codec *codec)
+static int wm8962_dsp2_stop(struct snd_soc_component *component)
 {
-	wm8962_dsp2_set_enable(codec, 0);
+	wm8962_dsp2_set_enable(component, 0);
 
-	snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
+	snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
 
 	return 0;
 }
@@ -1550,8 +1550,8 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
 	int shift = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
 
@@ -1562,11 +1562,11 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
 	int shift = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int old = wm8962->dsp2_ena;
 	int ret = 0;
-	int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) &
+	int dsp2_running = snd_soc_component_read32(component, WM8962_DSP2_POWER_MANAGEMENT) &
 		WM8962_DSP2_ENA;
 
 	mutex_lock(&wm8962->dsp2_ena_lock);
@@ -1583,9 +1583,9 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
 
 	if (dsp2_running) {
 		if (wm8962->dsp2_ena)
-			wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
+			wm8962_dsp2_set_enable(component, wm8962->dsp2_ena);
 		else
-			wm8962_dsp2_stop(codec);
+			wm8962_dsp2_stop(component);
 	}
 
 out:
@@ -1600,7 +1600,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
 static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int ret;
 
 	/* Apply the update (if any) */
@@ -1609,17 +1609,17 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
 		return 0;
 
 	/* If the left PGA is enabled hit that VU bit... */
-	ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+	ret = snd_soc_component_read32(component, WM8962_PWR_MGMT_2);
 	if (ret & WM8962_HPOUTL_PGA_ENA) {
-		snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
-			      snd_soc_read(codec, WM8962_HPOUTL_VOLUME));
+		snd_soc_component_write(component, WM8962_HPOUTL_VOLUME,
+			      snd_soc_component_read32(component, WM8962_HPOUTL_VOLUME));
 		return 1;
 	}
 
 	/* ...otherwise the right.  The VU is stereo. */
 	if (ret & WM8962_HPOUTR_PGA_ENA)
-		snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
-			      snd_soc_read(codec, WM8962_HPOUTR_VOLUME));
+		snd_soc_component_write(component, WM8962_HPOUTR_VOLUME,
+			      snd_soc_component_read32(component, WM8962_HPOUTR_VOLUME));
 
 	return 1;
 }
@@ -1630,7 +1630,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
 static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int ret;
 
 	/* Apply the update (if any) */
@@ -1639,17 +1639,17 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
 		return 0;
 
 	/* If the left PGA is enabled hit that VU bit... */
-	ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+	ret = snd_soc_component_read32(component, WM8962_PWR_MGMT_2);
 	if (ret & WM8962_SPKOUTL_PGA_ENA) {
-		snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
-			      snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
+		snd_soc_component_write(component, WM8962_SPKOUTL_VOLUME,
+			      snd_soc_component_read32(component, WM8962_SPKOUTL_VOLUME));
 		return 1;
 	}
 
 	/* ...otherwise the right.  The VU is stereo. */
 	if (ret & WM8962_SPKOUTR_PGA_ENA)
-		snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
-			      snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
+		snd_soc_component_write(component, WM8962_SPKOUTR_VOLUME,
+			      snd_soc_component_read32(component, WM8962_SPKOUTR_VOLUME));
 
 	return 1;
 }
@@ -1863,7 +1863,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int timeout;
 	int reg;
 	int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
@@ -1871,17 +1871,17 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
 				    WM8962_HP1L_ENA | WM8962_HP1R_ENA,
 				    WM8962_HP1L_ENA | WM8962_HP1R_ENA);
 		udelay(20);
 
-		snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
 				    WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
 				    WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
 
 		/* Start the DC servo */
-		snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+		snd_soc_component_update_bits(component, WM8962_DC_SERVO_1,
 				    WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
 				    WM8962_HP1L_DCS_STARTUP |
 				    WM8962_HP1R_DCS_STARTUP,
@@ -1893,30 +1893,30 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 		timeout = 0;
 		do {
 			msleep(1);
-			reg = snd_soc_read(codec, WM8962_DC_SERVO_6);
+			reg = snd_soc_component_read32(component, WM8962_DC_SERVO_6);
 			if (reg < 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to read DCS status: %d\n",
 					reg);
 				continue;
 			}
-			dev_dbg(codec->dev, "DCS status: %x\n", reg);
+			dev_dbg(component->dev, "DCS status: %x\n", reg);
 		} while (++timeout < 200 && (reg & expected) != expected);
 
 		if ((reg & expected) != expected)
-			dev_err(codec->dev, "DC servo timed out\n");
+			dev_err(component->dev, "DC servo timed out\n");
 		else
-			dev_dbg(codec->dev, "DC servo complete after %dms\n",
+			dev_dbg(component->dev, "DC servo complete after %dms\n",
 				timeout);
 
-		snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
 				    WM8962_HP1L_ENA_OUTP |
 				    WM8962_HP1R_ENA_OUTP,
 				    WM8962_HP1L_ENA_OUTP |
 				    WM8962_HP1R_ENA_OUTP);
 		udelay(20);
 
-		snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
 				    WM8962_HP1L_RMV_SHORT |
 				    WM8962_HP1R_RMV_SHORT,
 				    WM8962_HP1L_RMV_SHORT |
@@ -1924,19 +1924,19 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
 				    WM8962_HP1L_RMV_SHORT |
 				    WM8962_HP1R_RMV_SHORT, 0);
 
 		udelay(20);
 
-		snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+		snd_soc_component_update_bits(component, WM8962_DC_SERVO_1,
 				    WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
 				    WM8962_HP1L_DCS_STARTUP |
 				    WM8962_HP1R_DCS_STARTUP,
 				    0);
 
-		snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
 				    WM8962_HP1L_ENA | WM8962_HP1R_ENA |
 				    WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
 				    WM8962_HP1L_ENA_OUTP |
@@ -1957,7 +1957,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int reg;
 
 	switch (w->shift) {
@@ -1980,7 +1980,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
+		return snd_soc_component_write(component, reg, snd_soc_component_read32(component, reg));
 	default:
 		WARN(1, "Invalid event %d\n", event);
 		return -EINVAL;
@@ -1990,18 +1990,18 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 static int dsp2_event(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		if (wm8962->dsp2_ena)
-			wm8962_dsp2_start(codec);
+			wm8962_dsp2_start(component);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 		if (wm8962->dsp2_ena)
-			wm8962_dsp2_stop(codec);
+			wm8962_dsp2_stop(component);
 		break;
 
 	default:
@@ -2354,19 +2354,19 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
 	{ "SPKOUTR", NULL, "SPKOUTR Output" },
 };
 
-static int wm8962_add_widgets(struct snd_soc_codec *codec)
+static int wm8962_add_widgets(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	struct wm8962_pdata *pdata = &wm8962->pdata;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	snd_soc_add_codec_controls(codec, wm8962_snd_controls,
+	snd_soc_add_component_controls(component, wm8962_snd_controls,
 			     ARRAY_SIZE(wm8962_snd_controls));
 	if (pdata->spk_mono)
-		snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls,
+		snd_soc_add_component_controls(component, wm8962_spk_mono_controls,
 				     ARRAY_SIZE(wm8962_spk_mono_controls));
 	else
-		snd_soc_add_codec_controls(codec, wm8962_spk_stereo_controls,
+		snd_soc_add_component_controls(component, wm8962_spk_stereo_controls,
 				     ARRAY_SIZE(wm8962_spk_stereo_controls));
 
 
@@ -2403,21 +2403,21 @@ static const int sysclk_rates[] = {
 	64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, 3072, 6144
 };
 
-static void wm8962_configure_bclk(struct snd_soc_codec *codec)
+static void wm8962_configure_bclk(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int dspclk, i;
 	int clocking2 = 0;
 	int clocking4 = 0;
 	int aif2 = 0;
 
 	if (!wm8962->sysclk_rate) {
-		dev_dbg(codec->dev, "No SYSCLK configured\n");
+		dev_dbg(component->dev, "No SYSCLK configured\n");
 		return;
 	}
 
 	if (!wm8962->bclk || !wm8962->lrclk) {
-		dev_dbg(codec->dev, "No audio clocks configured\n");
+		dev_dbg(component->dev, "No audio clocks configured\n");
 		return;
 	}
 
@@ -2429,32 +2429,32 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
 	}
 
 	if (i == ARRAY_SIZE(sysclk_rates)) {
-		dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+		dev_err(component->dev, "Unsupported sysclk ratio %d\n",
 			wm8962->sysclk_rate / wm8962->lrclk);
 		return;
 	}
 
-	dev_dbg(codec->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]);
+	dev_dbg(component->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]);
 
-	snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+	snd_soc_component_update_bits(component, WM8962_CLOCKING_4,
 			    WM8962_SYSCLK_RATE_MASK, clocking4);
 
 	/* DSPCLK_DIV can be only generated correctly after enabling SYSCLK.
 	 * So we here provisionally enable it and then disable it afterward
 	 * if current bias_level hasn't reached SND_SOC_BIAS_ON.
 	 */
-	if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
-		snd_soc_update_bits(codec, WM8962_CLOCKING2,
+	if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+		snd_soc_component_update_bits(component, WM8962_CLOCKING2,
 				WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
 
-	dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+	dspclk = snd_soc_component_read32(component, WM8962_CLOCKING1);
 
-	if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
-		snd_soc_update_bits(codec, WM8962_CLOCKING2,
+	if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+		snd_soc_component_update_bits(component, WM8962_CLOCKING2,
 				WM8962_SYSCLK_ENA_MASK, 0);
 
 	if (dspclk < 0) {
-		dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
+		dev_err(component->dev, "Failed to read DSPCLK: %d\n", dspclk);
 		return;
 	}
 
@@ -2470,11 +2470,11 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
 		dspclk = wm8962->sysclk_rate / 4;
 		break;
 	default:
-		dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n");
+		dev_warn(component->dev, "Unknown DSPCLK divisor read back\n");
 		dspclk = wm8962->sysclk_rate;
 	}
 
-	dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+	dev_dbg(component->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
 
 	/* We're expecting an exact match */
 	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
@@ -2482,29 +2482,29 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
 			continue;
 
 		if (dspclk / bclk_divs[i] == wm8962->bclk) {
-			dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n",
+			dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n",
 				bclk_divs[i], wm8962->bclk);
 			clocking2 |= i;
 			break;
 		}
 	}
 	if (i == ARRAY_SIZE(bclk_divs)) {
-		dev_err(codec->dev, "Unsupported BCLK ratio %d\n",
+		dev_err(component->dev, "Unsupported BCLK ratio %d\n",
 			dspclk / wm8962->bclk);
 		return;
 	}
 
 	aif2 |= wm8962->bclk / wm8962->lrclk;
-	dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n",
+	dev_dbg(component->dev, "Selected LRCLK divisor %d for %dHz\n",
 		wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
 
-	snd_soc_update_bits(codec, WM8962_CLOCKING2,
+	snd_soc_component_update_bits(component, WM8962_CLOCKING2,
 			    WM8962_BCLK_DIV_MASK, clocking2);
-	snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2,
+	snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_2,
 			    WM8962_AIF_RATE_MASK, aif2);
 }
 
-static int wm8962_set_bias_level(struct snd_soc_codec *codec,
+static int wm8962_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -2513,18 +2513,18 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID 2*50k */
-		snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+		snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
 				    WM8962_VMID_SEL_MASK, 0x80);
 
-		wm8962_configure_bclk(codec);
+		wm8962_configure_bclk(component);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		/* VMID 2*250k */
-		snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+		snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
 				    WM8962_VMID_SEL_MASK, 0x100);
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 			msleep(100);
 		break;
 
@@ -2556,8 +2556,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int i;
 	int aif0 = 0;
 	int adctl3 = 0;
@@ -2575,7 +2575,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 	if (i == ARRAY_SIZE(sr_vals)) {
-		dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk);
+		dev_err(component->dev, "Unsupported rate %dHz\n", wm8962->lrclk);
 		return -EINVAL;
 	}
 
@@ -2598,17 +2598,17 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+	snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0,
 			    WM8962_WL_MASK, aif0);
-	snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
+	snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_3,
 			    WM8962_SAMPLE_RATE_INT_MODE |
 			    WM8962_SAMPLE_RATE_MASK, adctl3);
 
-	dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
+	dev_dbg(component->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
 		wm8962->bclk, wm8962->lrclk);
 
-	if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
-		wm8962_configure_bclk(codec);
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON)
+		wm8962_configure_bclk(component);
 
 	return 0;
 }
@@ -2616,8 +2616,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
 static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 				 unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int src;
 
 	switch (clk_id) {
@@ -2633,7 +2633,7 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+	snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
 			    src);
 
 	wm8962->sysclk_rate = freq;
@@ -2643,7 +2643,7 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int aif0 = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -2699,7 +2699,7 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+	snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0,
 			    WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
 			    WM8962_LRCLK_INV, aif0);
 
@@ -2809,10 +2809,10 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	struct _fll_div fll_div;
 	unsigned long timeout;
 	int ret;
@@ -2824,15 +2824,15 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return 0;
 
 	if (Fout == 0) {
-		dev_dbg(codec->dev, "FLL disabled\n");
+		dev_dbg(component->dev, "FLL disabled\n");
 
 		wm8962->fll_fref = 0;
 		wm8962->fll_fout = 0;
 
-		snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
 				    WM8962_FLL_ENA, 0);
 
-		pm_runtime_put(codec->dev);
+		pm_runtime_put(component->dev);
 
 		return 0;
 	}
@@ -2842,7 +2842,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return ret;
 
 	/* Parameters good, disable so we can reprogram */
-	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
 
 	switch (fll_id) {
 	case WM8962_FLL_MCLK:
@@ -2851,13 +2851,13 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
 		break;
 	case WM8962_FLL_INT:
-		snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
 				    WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
-		snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5,
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_5,
 				    WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
 		break;
 	default:
-		dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+		dev_err(component->dev, "Unknown FLL source %d\n", ret);
 		return -EINVAL;
 	}
 
@@ -2865,34 +2865,34 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		fll1 |= WM8962_FLL_FRAC;
 
 	/* Stop the FLL while we reconfigure */
-	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
 
-	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2,
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_2,
 			    WM8962_FLL_OUTDIV_MASK |
 			    WM8962_FLL_REFCLK_DIV_MASK,
 			    (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
 			    (fll_div.fll_refclk_div));
 
-	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3,
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_3,
 			    WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
 
-	snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta);
-	snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
-	snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+	snd_soc_component_write(component, WM8962_FLL_CONTROL_6, fll_div.theta);
+	snd_soc_component_write(component, WM8962_FLL_CONTROL_7, fll_div.lambda);
+	snd_soc_component_write(component, WM8962_FLL_CONTROL_8, fll_div.n);
 
 	reinit_completion(&wm8962->fll_lock);
 
-	ret = pm_runtime_get_sync(codec->dev);
+	ret = pm_runtime_get_sync(component->dev);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to resume device: %d\n", ret);
+		dev_err(component->dev, "Failed to resume device: %d\n", ret);
 		return ret;
 	}
 
-	snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
 			    WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
 			    WM8962_FLL_ENA, fll1 | WM8962_FLL_ENA);
 
-	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+	dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
 	/* This should be a massive overestimate but go even
 	 * higher if we'll error out
@@ -2906,10 +2906,10 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 					      timeout);
 
 	if (timeout == 0 && wm8962->irq) {
-		dev_err(codec->dev, "FLL lock timed out");
-		snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+		dev_err(component->dev, "FLL lock timed out");
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
 				    WM8962_FLL_ENA, 0);
-		pm_runtime_put(codec->dev);
+		pm_runtime_put(component->dev);
 		return -ETIMEDOUT;
 	}
 
@@ -2922,7 +2922,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
 static int wm8962_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int val, ret;
 
 	if (mute)
@@ -2934,12 +2934,12 @@ static int wm8962_mute(struct snd_soc_dai *dai, int mute)
 	 * The DAC mute bit is mirrored in two registers, update both to keep
 	 * the register cache consistent.
 	 */
-	ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1,
+	ret = snd_soc_component_update_bits(component, WM8962_CLASS_D_CONTROL_1,
 				  WM8962_DAC_MUTE_ALT, val);
 	if (ret < 0)
 		return ret;
 
-	return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+	return snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
 				   WM8962_DAC_MUTE, val);
 }
 
@@ -2981,12 +2981,12 @@ static void wm8962_mic_work(struct work_struct *work)
 	struct wm8962_priv *wm8962 = container_of(work,
 						  struct wm8962_priv,
 						  mic_work.work);
-	struct snd_soc_codec *codec = wm8962->codec;
+	struct snd_soc_component *component = wm8962->component;
 	int status = 0;
 	int irq_pol = 0;
 	int reg;
 
-	reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+	reg = snd_soc_component_read32(component, WM8962_ADDITIONAL_CONTROL_4);
 
 	if (reg & WM8962_MICDET_STS) {
 		status |= SND_JACK_MICROPHONE;
@@ -3001,7 +3001,7 @@ static void wm8962_mic_work(struct work_struct *work)
 	snd_soc_jack_report(wm8962->jack, status,
 			    SND_JACK_MICROPHONE | SND_JACK_BTN_0);
 
-	snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+	snd_soc_component_update_bits(component, WM8962_MICINT_SOURCE_POL,
 			    WM8962_MICSCD_IRQ_POL |
 			    WM8962_MICD_IRQ_POL, irq_pol);
 }
@@ -3099,7 +3099,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 /**
  * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
  *
- * @codec:  WM8962 codec
+ * @component:  WM8962 component
  * @jack:   jack to report detection events on
  *
  * Enable microphone detection via IRQ on the WM8962.  If GPIOs are
@@ -3109,10 +3109,10 @@ static irqreturn_t wm8962_irq(int irq, void *data)
  *
  * If no jack is supplied detection will be disabled.
  */
-int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int irq_mask, enable;
 
 	wm8962->jack = jack;
@@ -3124,9 +3124,9 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 		enable = 0;
 	}
 
-	snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+	snd_soc_component_update_bits(component, WM8962_INTERRUPT_STATUS_2_MASK,
 			    WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
-	snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+	snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_4,
 			    WM8962_MICDET_ENA, enable);
 
 	/* Send an initial empty report */
@@ -3157,8 +3157,8 @@ static void wm8962_beep_work(struct work_struct *work)
 {
 	struct wm8962_priv *wm8962 =
 		container_of(work, struct wm8962_priv, beep_work);
-	struct snd_soc_codec *codec = wm8962->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = wm8962->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int i;
 	int reg = 0;
 	int best = 0;
@@ -3170,18 +3170,18 @@ static void wm8962_beep_work(struct work_struct *work)
 				best = i;
 		}
 
-		dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
 			beep_rates[best], wm8962->beep_rate);
 
 		reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
 
 		snd_soc_dapm_enable_pin(dapm, "Beep");
 	} else {
-		dev_dbg(codec->dev, "Disabling beep\n");
+		dev_dbg(component->dev, "Disabling beep\n");
 		snd_soc_dapm_disable_pin(dapm, "Beep");
 	}
 
-	snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
+	snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1,
 			    WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
 
 	snd_soc_dapm_sync(dapm);
@@ -3193,10 +3193,10 @@ static void wm8962_beep_work(struct work_struct *work)
 static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
 			     unsigned int code, int hz)
 {
-	struct snd_soc_codec *codec = input_get_drvdata(dev);
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = input_get_drvdata(dev);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
-	dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
 
 	switch (code) {
 	case SND_BELL:
@@ -3233,14 +3233,14 @@ static ssize_t wm8962_beep_set(struct device *dev,
 
 static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
 
-static void wm8962_init_beep(struct snd_soc_codec *codec)
+static void wm8962_init_beep(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	wm8962->beep = devm_input_allocate_device(codec->dev);
+	wm8962->beep = devm_input_allocate_device(component->dev);
 	if (!wm8962->beep) {
-		dev_err(codec->dev, "Failed to allocate beep device\n");
+		dev_err(component->dev, "Failed to allocate beep device\n");
 		return;
 	}
 
@@ -3248,37 +3248,37 @@ static void wm8962_init_beep(struct snd_soc_codec *codec)
 	wm8962->beep_rate = 0;
 
 	wm8962->beep->name = "WM8962 Beep Generator";
-	wm8962->beep->phys = dev_name(codec->dev);
+	wm8962->beep->phys = dev_name(component->dev);
 	wm8962->beep->id.bustype = BUS_I2C;
 
 	wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
 	wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
 	wm8962->beep->event = wm8962_beep_event;
-	wm8962->beep->dev.parent = codec->dev;
-	input_set_drvdata(wm8962->beep, codec);
+	wm8962->beep->dev.parent = component->dev;
+	input_set_drvdata(wm8962->beep, component);
 
 	ret = input_register_device(wm8962->beep);
 	if (ret != 0) {
 		wm8962->beep = NULL;
-		dev_err(codec->dev, "Failed to register beep device\n");
+		dev_err(component->dev, "Failed to register beep device\n");
 	}
 
-	ret = device_create_file(codec->dev, &dev_attr_beep);
+	ret = device_create_file(component->dev, &dev_attr_beep);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+		dev_err(component->dev, "Failed to create keyclick file: %d\n",
 			ret);
 	}
 }
 
-static void wm8962_free_beep(struct snd_soc_codec *codec)
+static void wm8962_free_beep(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
-	device_remove_file(codec->dev, &dev_attr_beep);
+	device_remove_file(component->dev, &dev_attr_beep);
 	cancel_work_sync(&wm8962->beep_work);
 	wm8962->beep = NULL;
 
-	snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+	snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
 }
 
 static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
@@ -3333,9 +3333,9 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
-	struct snd_soc_codec *codec = wm8962->codec;
+	struct snd_soc_component *component = wm8962->component;
 
-	snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+	snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset,
 			    WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT);
 }
 
@@ -3343,13 +3343,13 @@ static int wm8962_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
 	struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
-	struct snd_soc_codec *codec = wm8962->codec;
+	struct snd_soc_component *component = wm8962->component;
 	int ret, val;
 
 	/* Force function 1 (logic output) */
 	val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
 
-	ret = snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+	ret = snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset,
 				  WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
 	if (ret < 0)
 		return ret;
@@ -3366,15 +3366,15 @@ static const struct gpio_chip wm8962_template_chip = {
 	.can_sleep		= 1,
 };
 
-static void wm8962_init_gpio(struct snd_soc_codec *codec)
+static void wm8962_init_gpio(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	struct wm8962_pdata *pdata = &wm8962->pdata;
 	int ret;
 
 	wm8962->gpio_chip = wm8962_template_chip;
 	wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
-	wm8962->gpio_chip.parent = codec->dev;
+	wm8962->gpio_chip.parent = component->dev;
 
 	if (pdata->gpio_base)
 		wm8962->gpio_chip.base = pdata->gpio_base;
@@ -3383,34 +3383,34 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
 
 	ret = gpiochip_add_data(&wm8962->gpio_chip, wm8962);
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+		dev_err(component->dev, "Failed to add GPIOs: %d\n", ret);
 }
 
-static void wm8962_free_gpio(struct snd_soc_codec *codec)
+static void wm8962_free_gpio(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 
 	gpiochip_remove(&wm8962->gpio_chip);
 }
 #else
-static void wm8962_init_gpio(struct snd_soc_codec *codec)
+static void wm8962_init_gpio(struct snd_soc_component *component)
 {
 }
 
-static void wm8962_free_gpio(struct snd_soc_codec *codec)
+static void wm8962_free_gpio(struct snd_soc_component *component)
 {
 }
 #endif
 
-static int wm8962_probe(struct snd_soc_codec *codec)
+static int wm8962_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int ret;
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int i;
 	bool dmicclk, dmicdat;
 
-	wm8962->codec = codec;
+	wm8962->component = component;
 
 	wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
 	wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
@@ -3426,19 +3426,19 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 		ret = regulator_register_notifier(wm8962->supplies[i].consumer,
 						  &wm8962->disable_nb[i]);
 		if (ret != 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to register regulator notifier: %d\n",
 				ret);
 		}
 	}
 
-	wm8962_add_widgets(codec);
+	wm8962_add_widgets(component);
 
 	/* Save boards having to disable DMIC when not in use */
 	dmicclk = false;
 	dmicdat = false;
 	for (i = 0; i < WM8962_MAX_GPIO; i++) {
-		switch (snd_soc_read(codec, WM8962_GPIO_BASE + i)
+		switch (snd_soc_component_read32(component, WM8962_GPIO_BASE + i)
 			& WM8962_GP2_FN_MASK) {
 		case WM8962_GPIO_FN_DMICCLK:
 			dmicclk = true;
@@ -3451,40 +3451,40 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 		}
 	}
 	if (!dmicclk || !dmicdat) {
-		dev_dbg(codec->dev, "DMIC not in use, disabling\n");
+		dev_dbg(component->dev, "DMIC not in use, disabling\n");
 		snd_soc_dapm_nc_pin(dapm, "DMICDAT");
 	}
 	if (dmicclk != dmicdat)
-		dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
+		dev_warn(component->dev, "DMIC GPIOs partially configured\n");
 
-	wm8962_init_beep(codec);
-	wm8962_init_gpio(codec);
+	wm8962_init_beep(component);
+	wm8962_init_gpio(component);
 
 	return 0;
 }
 
-static int wm8962_remove(struct snd_soc_codec *codec)
+static void wm8962_remove(struct snd_soc_component *component)
 {
-	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	cancel_delayed_work_sync(&wm8962->mic_work);
 
-	wm8962_free_gpio(codec);
-	wm8962_free_beep(codec);
+	wm8962_free_gpio(component);
+	wm8962_free_beep(component);
 	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
 		regulator_unregister_notifier(wm8962->supplies[i].consumer,
 					      &wm8962->disable_nb[i]);
-
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
-	.probe =	wm8962_probe,
-	.remove =	wm8962_remove,
-	.set_bias_level = wm8962_set_bias_level,
-	.set_pll = wm8962_set_fll,
-	.idle_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_wm8962 = {
+	.probe			= wm8962_probe,
+	.remove			= wm8962_remove,
+	.set_bias_level		= wm8962_set_bias_level,
+	.set_pll		= wm8962_set_fll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* Improve power consumption for IN4 DC measurement mode */
@@ -3751,8 +3751,8 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
 	pm_runtime_enable(&i2c->dev);
 	pm_request_idle(&i2c->dev);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8962, &wm8962_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8962, &wm8962_dai, 1);
 	if (ret < 0)
 		goto err_pm_runtime;
 
@@ -3773,7 +3773,6 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
 
 static int wm8962_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	pm_runtime_disable(&client->dev);
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
index e63a318a3015..a4a42d269747 100644
--- a/sound/soc/codecs/wm8962.h
+++ b/sound/soc/codecs/wm8962.h
@@ -3779,6 +3779,6 @@
 #define WM8962_VSS_ENA_SHIFT                         0  /* VSS_ENA */
 #define WM8962_VSS_ENA_WIDTH                         1  /* VSS_ENA */
 
-int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
 
 #endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 887d31cf3945..a79f7a7ab44b 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -89,7 +89,7 @@ static const struct reg_default wm8971_reg_defaults[] = {
 	{ 42, 0x0079 },
 };
 
-#define wm8971_reset(c)	snd_soc_write(c, WM8971_RESET, 0)
+#define wm8971_reset(c)	snd_soc_component_write(c, WM8971_RESET, 0)
 
 /* WM8971 Controls */
 static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
@@ -433,8 +433,8 @@ static int get_coeff(int mclk, int rate)
 static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 11289600:
@@ -451,7 +451,7 @@ static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -502,7 +502,7 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8971_IFACE, iface);
+	snd_soc_component_write(component, WM8971_IFACE, iface);
 	return 0;
 }
 
@@ -510,10 +510,10 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
-	u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
+	struct snd_soc_component *component = dai->component;
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8971_IFACE) & 0x1f3;
+	u16 srate = snd_soc_component_read32(component, WM8971_SRATE) & 0x1c0;
 	int coeff = get_coeff(wm8971->sysclk, params_rate(params));
 
 	/* bit size */
@@ -532,9 +532,9 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set iface & srate */
-	snd_soc_write(codec, WM8971_IFACE, iface);
+	snd_soc_component_write(component, WM8971_IFACE, iface);
 	if (coeff >= 0)
-		snd_soc_write(codec, WM8971_SRATE, srate |
+		snd_soc_component_write(component, WM8971_SRATE, srate |
 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
 
 	return 0;
@@ -542,13 +542,13 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8971_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8971_ADCDAC) & 0xfff7;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8971_ADCDAC) & 0xfff7;
 
 	if (mute)
-		snd_soc_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
+		snd_soc_component_write(component, WM8971_ADCDAC, mute_reg | 0x8);
 	else
-		snd_soc_write(codec, WM8971_ADCDAC, mute_reg);
+		snd_soc_component_write(component, WM8971_ADCDAC, mute_reg);
 	return 0;
 }
 
@@ -561,37 +561,37 @@ static void wm8971_charge_work(struct work_struct *work)
 	regmap_update_bits(wm8971->regmap, WM8971_PWR1, 0x0180, 0x0100);
 }
 
-static int wm8971_set_bias_level(struct snd_soc_codec *codec,
+static int wm8971_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
-	u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8971_PWR1) & 0xfe3e;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* set vmid to 50k and unmute dac */
-		snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
+		snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x00c1);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Wait until fully charged */
 		flush_delayed_work(&wm8971->charge_work);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			snd_soc_cache_sync(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_cache_sync(component);
 			/* charge output caps - set vmid to 5k for quick power up */
-			snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0);
+			snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x01c0);
 			queue_delayed_work(system_power_efficient_wq,
 				&wm8971->charge_work, msecs_to_jiffies(1000));
 		} else {
 			/* mute dac and set vmid to 500k, enable VREF */
-			snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
+			snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x0140);
 		}
 
 		break;
 	case SND_SOC_BIAS_OFF:
 		cancel_delayed_work_sync(&wm8971->charge_work);
-		snd_soc_write(codec, WM8971_PWR1, 0x0001);
+		snd_soc_component_write(component, WM8971_PWR1, 0x0001);
 		break;
 	}
 	return 0;
@@ -628,40 +628,41 @@ static struct snd_soc_dai_driver wm8971_dai = {
 	.ops = &wm8971_dai_ops,
 };
 
-static int wm8971_probe(struct snd_soc_codec *codec)
+static int wm8971_probe(struct snd_soc_component *component)
 {
-	struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
 
 	INIT_DELAYED_WORK(&wm8971->charge_work, wm8971_charge_work);
 
-	wm8971_reset(codec);
+	wm8971_reset(component);
 
 	/* set the update bits */
-	snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_LOUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_ROUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_LOUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_ROUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LOUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_RINVOL, 0x0100, 0x0100);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
-	.probe =	wm8971_probe,
-	.set_bias_level = wm8971_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8971_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8971_snd_controls),
-		.dapm_widgets		= wm8971_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8971_dapm_widgets),
-		.dapm_routes		= wm8971_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8971_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8971 = {
+	.probe			= wm8971_probe,
+	.set_bias_level		= wm8971_set_bias_level,
+	.controls		= wm8971_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8971_snd_controls),
+	.dapm_widgets		= wm8971_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8971_dapm_widgets),
+	.dapm_routes		= wm8971_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8971_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8971_regmap = {
@@ -691,18 +692,12 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8971);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8971, &wm8971_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8971, &wm8971_dai, 1);
 
 	return ret;
 }
 
-static int wm8971_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8971_i2c_id[] = {
 	{ "wm8971", 0 },
 	{ }
@@ -714,7 +709,6 @@ static struct i2c_driver wm8971_i2c_driver = {
 		.name = "wm8971",
 	},
 	.probe =    wm8971_i2c_probe,
-	.remove =   wm8971_i2c_remove,
 	.id_table = wm8971_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index d414ddd6e197..43edaf8cd276 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -54,7 +54,7 @@ static const struct reg_default wm8974_reg_defaults[] = {
 #define WM8974_POWER1_BIASEN  0x08
 #define WM8974_POWER1_BUFIOEN 0x04
 
-#define wm8974_reset(c)	snd_soc_write(c, WM8974_RESET, 0)
+#define wm8974_reset(c)	snd_soc_component_write(c, WM8974_RESET, 0)
 
 static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
 static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
@@ -324,33 +324,33 @@ static void pll_factors(struct pll_ *pll_div,
 static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	struct pll_ pll_div;
 	u16 reg;
 
 	if (freq_in == 0 || freq_out == 0) {
 		/* Clock CODEC directly from MCLK */
-		reg = snd_soc_read(codec, WM8974_CLOCK);
-		snd_soc_write(codec, WM8974_CLOCK, reg & 0x0ff);
+		reg = snd_soc_component_read32(component, WM8974_CLOCK);
+		snd_soc_component_write(component, WM8974_CLOCK, reg & 0x0ff);
 
 		/* Turn off PLL */
-		reg = snd_soc_read(codec, WM8974_POWER1);
-		snd_soc_write(codec, WM8974_POWER1, reg & 0x1df);
+		reg = snd_soc_component_read32(component, WM8974_POWER1);
+		snd_soc_component_write(component, WM8974_POWER1, reg & 0x1df);
 		return 0;
 	}
 
 	pll_factors(&pll_div, freq_out, freq_in);
 
-	snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
-	snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18);
-	snd_soc_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
-	snd_soc_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff);
-	reg = snd_soc_read(codec, WM8974_POWER1);
-	snd_soc_write(codec, WM8974_POWER1, reg | 0x020);
+	snd_soc_component_write(component, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8974_PLLK1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8974_PLLK3, pll_div.k & 0x1ff);
+	reg = snd_soc_component_read32(component, WM8974_POWER1);
+	snd_soc_component_write(component, WM8974_POWER1, reg | 0x020);
 
 	/* Run CODEC from PLL instead of MCLK */
-	reg = snd_soc_read(codec, WM8974_CLOCK);
-	snd_soc_write(codec, WM8974_CLOCK, reg | 0x100);
+	reg = snd_soc_component_read32(component, WM8974_CLOCK);
+	snd_soc_component_write(component, WM8974_CLOCK, reg | 0x100);
 
 	return 0;
 }
@@ -361,21 +361,21 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8974_OPCLKDIV:
-		reg = snd_soc_read(codec, WM8974_GPIO) & 0x1cf;
-		snd_soc_write(codec, WM8974_GPIO, reg | div);
+		reg = snd_soc_component_read32(component, WM8974_GPIO) & 0x1cf;
+		snd_soc_component_write(component, WM8974_GPIO, reg | div);
 		break;
 	case WM8974_MCLKDIV:
-		reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f;
-		snd_soc_write(codec, WM8974_CLOCK, reg | div);
+		reg = snd_soc_component_read32(component, WM8974_CLOCK) & 0x11f;
+		snd_soc_component_write(component, WM8974_CLOCK, reg | div);
 		break;
 	case WM8974_BCLKDIV:
-		reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3;
-		snd_soc_write(codec, WM8974_CLOCK, reg | div);
+		reg = snd_soc_component_read32(component, WM8974_CLOCK) & 0x1e3;
+		snd_soc_component_write(component, WM8974_CLOCK, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -418,8 +418,8 @@ static unsigned int wm8974_get_mclkdiv(unsigned int f_in, unsigned int f_out,
 
 static int wm8974_update_clocks(struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8974_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8974_priv *priv = snd_soc_component_get_drvdata(component);
 	unsigned int fs256;
 	unsigned int fpll = 0;
 	unsigned int f;
@@ -446,8 +446,8 @@ static int wm8974_update_clocks(struct snd_soc_dai *dai)
 static int wm8974_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 				 unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8974_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8974_priv *priv = snd_soc_component_get_drvdata(component);
 
 	if (dir != SND_SOC_CLOCK_IN)
 		return -EINVAL;
@@ -460,9 +460,9 @@ static int wm8974_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
-	u16 clk = snd_soc_read(codec, WM8974_CLOCK) & 0x1fe;
+	u16 clk = snd_soc_component_read32(component, WM8974_CLOCK) & 0x1fe;
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -509,8 +509,8 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8974_IFACE, iface);
-	snd_soc_write(codec, WM8974_CLOCK, clk);
+	snd_soc_component_write(component, WM8974_IFACE, iface);
+	snd_soc_component_write(component, WM8974_CLOCK, clk);
 	return 0;
 }
 
@@ -518,10 +518,10 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8974_priv *priv = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8974_IFACE) & 0x19f;
-	u16 adn = snd_soc_read(codec, WM8974_ADD) & 0x1f1;
+	struct snd_soc_component *component = dai->component;
+	struct wm8974_priv *priv = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8974_IFACE) & 0x19f;
+	u16 adn = snd_soc_component_read32(component, WM8974_ADD) & 0x1f1;
 	int err;
 
 	priv->fs = params_rate(params);
@@ -566,55 +566,55 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8974_IFACE, iface);
-	snd_soc_write(codec, WM8974_ADD, adn);
+	snd_soc_component_write(component, WM8974_IFACE, iface);
+	snd_soc_component_write(component, WM8974_ADD, adn);
 	return 0;
 }
 
 static int wm8974_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8974_DAC) & 0xffbf;
 
 	if (mute)
-		snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
+		snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40);
 	else
-		snd_soc_write(codec, WM8974_DAC, mute_reg);
+		snd_soc_component_write(component, WM8974_DAC, mute_reg);
 	return 0;
 }
 
 /* liam need to make this lower power with dapm */
-static int wm8974_set_bias_level(struct snd_soc_codec *codec,
+static int wm8974_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	u16 power1 = snd_soc_read(codec, WM8974_POWER1) & ~0x3;
+	u16 power1 = snd_soc_component_read32(component, WM8974_POWER1) & ~0x3;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		power1 |= 0x1;  /* VMID 50k */
-		snd_soc_write(codec, WM8974_POWER1, power1);
+		snd_soc_component_write(component, WM8974_POWER1, power1);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
-			regcache_sync(dev_get_regmap(codec->dev, NULL));
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(dev_get_regmap(component->dev, NULL));
 
 			/* Initial cap charge at VMID 5k */
-			snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
+			snd_soc_component_write(component, WM8974_POWER1, power1 | 0x3);
 			mdelay(100);
 		}
 
 		power1 |= 0x2;  /* VMID 500k */
-		snd_soc_write(codec, WM8974_POWER1, power1);
+		snd_soc_component_write(component, WM8974_POWER1, power1);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, WM8974_POWER1, 0);
-		snd_soc_write(codec, WM8974_POWER2, 0);
-		snd_soc_write(codec, WM8974_POWER3, 0);
+		snd_soc_component_write(component, WM8974_POWER1, 0);
+		snd_soc_component_write(component, WM8974_POWER2, 0);
+		snd_soc_component_write(component, WM8974_POWER3, 0);
 		break;
 	}
 
@@ -663,32 +663,33 @@ static const struct regmap_config wm8974_regmap = {
 	.cache_type = REGCACHE_FLAT,
 };
 
-static int wm8974_probe(struct snd_soc_codec *codec)
+static int wm8974_probe(struct snd_soc_component *component)
 {
 	int ret = 0;
 
-	ret = wm8974_reset(codec);
+	ret = wm8974_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
+		dev_err(component->dev, "Failed to issue reset\n");
 		return ret;
 	}
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
-	.probe = 	wm8974_probe,
-	.set_bias_level = wm8974_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8974_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8974_snd_controls),
-		.dapm_widgets		= wm8974_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8974_dapm_widgets),
-		.dapm_routes		= wm8974_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8974_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8974 = {
+	.probe			= wm8974_probe,
+	.set_bias_level		= wm8974_set_bias_level,
+	.controls		= wm8974_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8974_snd_controls),
+	.dapm_widgets		= wm8974_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8974_dapm_widgets),
+	.dapm_routes		= wm8974_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8974_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8974_i2c_probe(struct i2c_client *i2c,
@@ -708,19 +709,12 @@ static int wm8974_i2c_probe(struct i2c_client *i2c,
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8974, &wm8974_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8974, &wm8974_dai, 1);
 
 	return ret;
 }
 
-static int wm8974_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8974_i2c_id[] = {
 	{ "wm8974", 0 },
 	{ }
@@ -739,7 +733,6 @@ static struct i2c_driver wm8974_i2c_driver = {
 		.of_match_table = wm8974_of_match,
 	},
 	.probe =    wm8974_i2c_probe,
-	.remove =   wm8974_i2c_remove,
 	.id_table = wm8974_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index cf761e2d7546..bae4fe89dbf1 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -408,7 +408,7 @@ struct wm8978_pll_div {
 
 #define FIXED_PLL_SIZE (1 << 24)
 
-static void pll_factors(struct snd_soc_codec *codec,
+static void pll_factors(struct snd_soc_component *component,
 		struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source)
 {
 	u64 k_part;
@@ -424,7 +424,7 @@ static void pll_factors(struct snd_soc_codec *codec,
 	}
 
 	if (n_div < 6 || n_div > 12)
-		dev_warn(codec->dev,
+		dev_warn(component->dev,
 			 "WM8978 N value exceeds recommended range! N = %u\n",
 			 n_div);
 
@@ -471,9 +471,9 @@ static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk,
  * Calculate internal frequencies and dividers, according to Figure 40
  * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6
  */
-static int wm8978_configure_pll(struct snd_soc_codec *codec)
+static int wm8978_configure_pll(struct snd_soc_component *component)
 {
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 	struct wm8978_pll_div pll_div;
 	unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk,
 		f_256fs = wm8978->f_256fs;
@@ -505,9 +505,9 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec)
 		else
 			opclk_div = 1;
 
-		dev_dbg(codec->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div);
+		dev_dbg(component->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div);
 
-		snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 0x30,
+		snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, 0x30,
 				    (opclk_div - 1) << 4);
 
 		wm8978->f_pllout = f_opclk * opclk_div;
@@ -533,28 +533,28 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec)
 
 	f2 = wm8978->f_pllout * 4;
 
-	dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
+	dev_dbg(component->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
 		wm8978->f_mclk, wm8978->f_pllout);
 
-	pll_factors(codec, &pll_div, f2, wm8978->f_mclk);
+	pll_factors(component, &pll_div, f2, wm8978->f_mclk);
 
-	dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
+	dev_dbg(component->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
 		__func__, pll_div.n, pll_div.k, pll_div.div2);
 
 	/* Turn PLL off for configuration... */
-	snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
+	snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
 
-	snd_soc_write(codec, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n);
-	snd_soc_write(codec, WM8978_PLL_K1, pll_div.k >> 18);
-	snd_soc_write(codec, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff);
-	snd_soc_write(codec, WM8978_PLL_K3, pll_div.k & 0x1ff);
+	snd_soc_component_write(component, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8978_PLL_K1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8978_PLL_K3, pll_div.k & 0x1ff);
 
 	/* ...and on again */
-	snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
+	snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
 
 	if (f_opclk)
 		/* Output PLL (OPCLK) to GPIO1 */
-		snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 4);
+		snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, 7, 4);
 
 	return 0;
 }
@@ -565,8 +565,8 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec)
 static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 				 int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	switch (div_id) {
@@ -588,18 +588,18 @@ static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 			 * find an exact MCLK divider configuration - it will
 			 * be equal to or double the OPCLK divisor.
 			 */
-			ret = wm8978_configure_pll(codec);
+			ret = wm8978_configure_pll(component);
 		break;
 	case WM8978_BCLKDIV:
 		if (div & ~0x1c)
 			return -EINVAL;
-		snd_soc_update_bits(codec, WM8978_CLOCKING, 0x1c, div);
+		snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x1c, div);
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "%s: ID %d, value %u\n", __func__, div_id, div);
+	dev_dbg(component->dev, "%s: ID %d, value %u\n", __func__, div_id, div);
 
 	return ret;
 }
@@ -610,18 +610,18 @@ static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 				 unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
-	dev_dbg(codec->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq);
+	dev_dbg(component->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq);
 
 	if (freq) {
 		wm8978->f_mclk = freq;
 
 		/* Even if MCLK is used for system clock, might have to drive OPCLK */
 		if (wm8978->f_opclk)
-			ret = wm8978_configure_pll(codec);
+			ret = wm8978_configure_pll(component);
 
 		/* Our sysclk is fixed to 256 * fs, will configure in .hw_params()  */
 
@@ -631,13 +631,13 @@ static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
 
 	if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) {
 		/* Clock CODEC directly from MCLK */
-		snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0);
+		snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x100, 0);
 
 		/* GPIO1 into default mode as input - before configuring PLL */
-		snd_soc_update_bits(codec, WM8978_GPIO_CONTROL, 7, 0);
+		snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, 7, 0);
 
 		/* Turn off PLL */
-		snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
+		snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
 		wm8978->sysclk = WM8978_MCLK;
 		wm8978->f_pllout = 0;
 		wm8978->f_opclk = 0;
@@ -651,15 +651,15 @@ static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
  */
 static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	/*
 	 * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80,
 	 * Data Format mask = 0x18: all will be calculated anew
 	 */
-	u16 iface = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x198;
-	u16 clk = snd_soc_read(codec, WM8978_CLOCKING);
+	u16 iface = snd_soc_component_read32(component, WM8978_AUDIO_INTERFACE) & ~0x198;
+	u16 clk = snd_soc_component_read32(component, WM8978_CLOCKING);
 
-	dev_dbg(codec->dev, "%s\n", __func__);
+	dev_dbg(component->dev, "%s\n", __func__);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -707,8 +707,8 @@ static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface);
-	snd_soc_write(codec, WM8978_CLOCKING, clk);
+	snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, iface);
+	snd_soc_component_write(component, WM8978_CLOCKING, clk);
 
 	return 0;
 }
@@ -720,13 +720,13 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 	/* Word length mask = 0x60 */
-	u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
+	u16 iface_ctl = snd_soc_component_read32(component, WM8978_AUDIO_INTERFACE) & ~0x60;
 	/* Sampling rate mask = 0xe (for filters) */
-	u16 add_ctl = snd_soc_read(codec, WM8978_ADDITIONAL_CONTROL) & ~0xe;
-	u16 clking = snd_soc_read(codec, WM8978_CLOCKING);
+	u16 add_ctl = snd_soc_component_read32(component, WM8978_ADDITIONAL_CONTROL) & ~0xe;
+	u16 clking = snd_soc_component_read32(component, WM8978_CLOCKING);
 	enum wm8978_sysclk_src current_clk_id = clking & 0x100 ?
 		WM8978_PLL : WM8978_MCLK;
 	unsigned int f_sel, diff, diff_best = INT_MAX;
@@ -781,7 +781,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
 	} else {
 		if (!wm8978->f_opclk) {
 			/* We only enter here, if OPCLK is not used */
-			int ret = wm8978_configure_pll(codec);
+			int ret = wm8978_configure_pll(component);
 			if (ret < 0)
 				return ret;
 		}
@@ -812,28 +812,28 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (diff)
-		dev_warn(codec->dev, "Imprecise sampling rate: %uHz%s\n",
+		dev_warn(component->dev, "Imprecise sampling rate: %uHz%s\n",
 			f_sel * mclk_denominator[best] / mclk_numerator[best] / 256,
 			wm8978->sysclk == WM8978_MCLK ?
 			", consider using PLL" : "");
 
-	dev_dbg(codec->dev, "%s: width %d, rate %u, MCLK divisor #%d\n", __func__,
+	dev_dbg(component->dev, "%s: width %d, rate %u, MCLK divisor #%d\n", __func__,
 		params_width(params), params_rate(params), best);
 
 	/* MCLK divisor mask = 0xe0 */
-	snd_soc_update_bits(codec, WM8978_CLOCKING, 0xe0, best << 5);
+	snd_soc_component_update_bits(component, WM8978_CLOCKING, 0xe0, best << 5);
 
-	snd_soc_write(codec, WM8978_AUDIO_INTERFACE, iface_ctl);
-	snd_soc_write(codec, WM8978_ADDITIONAL_CONTROL, add_ctl);
+	snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, iface_ctl);
+	snd_soc_component_write(component, WM8978_ADDITIONAL_CONTROL, add_ctl);
 
 	if (wm8978->sysclk != current_clk_id) {
 		if (wm8978->sysclk == WM8978_PLL)
 			/* Run CODEC from PLL instead of MCLK */
-			snd_soc_update_bits(codec, WM8978_CLOCKING,
+			snd_soc_component_update_bits(component, WM8978_CLOCKING,
 					    0x100, 0x100);
 		else
 			/* Clock CODEC directly from MCLK */
-			snd_soc_update_bits(codec, WM8978_CLOCKING, 0x100, 0);
+			snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x100, 0);
 	}
 
 	return 0;
@@ -841,52 +841,52 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8978_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	dev_dbg(codec->dev, "%s: %d\n", __func__, mute);
+	dev_dbg(component->dev, "%s: %d\n", __func__, mute);
 
 	if (mute)
-		snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0x40);
+		snd_soc_component_update_bits(component, WM8978_DAC_CONTROL, 0x40, 0x40);
 	else
-		snd_soc_update_bits(codec, WM8978_DAC_CONTROL, 0x40, 0);
+		snd_soc_component_update_bits(component, WM8978_DAC_CONTROL, 0x40, 0);
 
 	return 0;
 }
 
-static int wm8978_set_bias_level(struct snd_soc_codec *codec,
+static int wm8978_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	u16 power1 = snd_soc_read(codec, WM8978_POWER_MANAGEMENT_1) & ~3;
+	u16 power1 = snd_soc_component_read32(component, WM8978_POWER_MANAGEMENT_1) & ~3;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		power1 |= 1;  /* VMID 75k */
-		snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1);
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, power1);
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* bit 3: enable bias, bit 2: enable I/O tie off buffer */
 		power1 |= 0xc;
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Initial cap charge at VMID 5k */
-			snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1,
+			snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1,
 				      power1 | 0x3);
 			mdelay(100);
 		}
 
 		power1 |= 0x2;  /* VMID 500k */
-		snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, power1);
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, power1);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* Preserve PLL - OPCLK may be used by someone */
-		snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, ~0x20, 0);
-		snd_soc_write(codec, WM8978_POWER_MANAGEMENT_2, 0);
-		snd_soc_write(codec, WM8978_POWER_MANAGEMENT_3, 0);
+		snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, ~0x20, 0);
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_2, 0);
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_3, 0);
 		break;
 	}
 
-	dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1);
+	dev_dbg(component->dev, "%s: %d, %x\n", __func__, level, power1);
 
 	return 0;
 }
@@ -923,31 +923,31 @@ static struct snd_soc_dai_driver wm8978_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8978_suspend(struct snd_soc_codec *codec)
+static int wm8978_suspend(struct snd_soc_component *component)
 {
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 	/* Also switch PLL off */
-	snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
+	snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, 0);
 
 	regcache_mark_dirty(wm8978->regmap);
 
 	return 0;
 }
 
-static int wm8978_resume(struct snd_soc_codec *codec)
+static int wm8978_resume(struct snd_soc_component *component)
 {
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 
 	/* Sync reg_cache with the hardware */
 	regcache_sync(wm8978->regmap);
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	if (wm8978->f_pllout)
 		/* Switch PLL on */
-		snd_soc_update_bits(codec, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
+		snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
 
 	return 0;
 }
@@ -971,9 +971,9 @@ static const int update_reg[] = {
 	WM8978_ROUT2_SPK_CONTROL,
 };
 
-static int wm8978_probe(struct snd_soc_codec *codec)
+static int wm8978_probe(struct snd_soc_component *component)
 {
-	struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	/*
@@ -988,25 +988,26 @@ static int wm8978_probe(struct snd_soc_codec *codec)
 	 * written.
 	 */
 	for (i = 0; i < ARRAY_SIZE(update_reg); i++)
-		snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100);
+		snd_soc_component_update_bits(component, update_reg[i], 0x100, 0x100);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
-	.probe =	wm8978_probe,
-	.suspend =	wm8978_suspend,
-	.resume =	wm8978_resume,
-	.set_bias_level = wm8978_set_bias_level,
-
-	.component_driver = {
-		.controls		= wm8978_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8978_snd_controls),
-		.dapm_widgets		= wm8978_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8978_dapm_widgets),
-		.dapm_routes		= wm8978_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8978_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8978 = {
+	.probe			= wm8978_probe,
+	.suspend		= wm8978_suspend,
+	.resume			= wm8978_resume,
+	.set_bias_level		= wm8978_set_bias_level,
+	.controls		= wm8978_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8978_snd_controls),
+	.dapm_widgets		= wm8978_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8978_dapm_widgets),
+	.dapm_routes		= wm8978_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8978_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8978_regmap_config = {
@@ -1048,8 +1049,8 @@ static int wm8978_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8978, &wm8978_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8978, &wm8978_dai, 1);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
 		return ret;
@@ -1058,13 +1059,6 @@ static int wm8978_i2c_probe(struct i2c_client *i2c,
 	return 0;
 }
 
-static int wm8978_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8978_i2c_id[] = {
 	{ "wm8978", 0 },
 	{ }
@@ -1083,7 +1077,6 @@ static struct i2c_driver wm8978_i2c_driver = {
 		.of_match_table = wm8978_of_match,
 	},
 	.probe =    wm8978_i2c_probe,
-	.remove =   wm8978_i2c_remove,
 	.id_table = wm8978_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index bfdbe72ee687..9f35801aa85f 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -492,10 +492,10 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = {
 static int eqmode_get(struct snd_kcontrol *kcontrol,
 		      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
+	reg = snd_soc_component_read32(component, WM8983_EQ1_LOW_SHELF);
 	if (reg & WM8983_EQ3DMODE)
 		ucontrol->value.enumerated.item[0] = 1;
 	else
@@ -507,7 +507,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
 static int eqmode_put(struct snd_kcontrol *kcontrol,
 		      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int regpwr2, regpwr3;
 	unsigned int reg_eq;
 
@@ -515,7 +515,7 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
 	    && ucontrol->value.enumerated.item[0] != 1)
 		return -EINVAL;
 
-	reg_eq = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
+	reg_eq = snd_soc_component_read32(component, WM8983_EQ1_LOW_SHELF);
 	switch ((reg_eq & WM8983_EQ3DMODE) >> WM8983_EQ3DMODE_SHIFT) {
 	case 0:
 		if (!ucontrol->value.enumerated.item[0])
@@ -527,21 +527,21 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
 		break;
 	}
 
-	regpwr2 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_2);
-	regpwr3 = snd_soc_read(codec, WM8983_POWER_MANAGEMENT_3);
+	regpwr2 = snd_soc_component_read32(component, WM8983_POWER_MANAGEMENT_2);
+	regpwr3 = snd_soc_component_read32(component, WM8983_POWER_MANAGEMENT_3);
 	/* disable the DACs and ADCs */
-	snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_2,
+	snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_2,
 			    WM8983_ADCENR_MASK | WM8983_ADCENL_MASK, 0);
-	snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_3,
+	snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_3,
 			    WM8983_DACENR_MASK | WM8983_DACENL_MASK, 0);
 	/* set the desired eqmode */
-	snd_soc_update_bits(codec, WM8983_EQ1_LOW_SHELF,
+	snd_soc_component_update_bits(component, WM8983_EQ1_LOW_SHELF,
 			    WM8983_EQ3DMODE_MASK,
 			    ucontrol->value.enumerated.item[0]
 			    << WM8983_EQ3DMODE_SHIFT);
 	/* restore DAC/ADC configuration */
-	snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, regpwr2);
-	snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, regpwr3);
+	snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_2, regpwr2);
+	snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_3, regpwr3);
 	return 0;
 }
 
@@ -562,16 +562,16 @@ static bool wm8983_writeable(struct device *dev, unsigned int reg)
 
 static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	return snd_soc_update_bits(codec, WM8983_DAC_CONTROL,
+	return snd_soc_component_update_bits(component, WM8983_DAC_CONTROL,
 				   WM8983_SOFTMUTE_MASK,
 				   !!mute << WM8983_SOFTMUTE_SHIFT);
 }
 
 static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 format, master, bcp, lrp;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -593,7 +593,7 @@ static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
 			    WM8983_FMT_MASK, format << WM8983_FMT_SHIFT);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -608,7 +608,7 @@ static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+	snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
 			    WM8983_MS_MASK, master << WM8983_MS_SHIFT);
 
 	/* FIXME: We don't currently support DSP A/B modes */
@@ -639,9 +639,9 @@ static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
 			    WM8983_LRCP_MASK, lrp << WM8983_LRCP_SHIFT);
-	snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
 			    WM8983_BCP_MASK, bcp << WM8983_BCP_SHIFT);
 	return 0;
 }
@@ -651,8 +651,8 @@ static int wm8983_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
 	int i;
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
 	u16 blen, srate_idx;
 	u32 tmp;
 	int srate_best;
@@ -660,7 +660,7 @@ static int wm8983_hw_params(struct snd_pcm_substream *substream,
 
 	ret = snd_soc_params_to_bclk(params);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to convert params to bclk: %d\n", ret);
+		dev_err(component->dev, "Failed to convert params to bclk: %d\n", ret);
 		return ret;
 	}
 
@@ -685,7 +685,7 @@ static int wm8983_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8983_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
 			    WM8983_WL_MASK, blen << WM8983_WL_SHIFT);
 
 	/*
@@ -702,7 +702,7 @@ static int wm8983_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
-	snd_soc_update_bits(codec, WM8983_ADDITIONAL_CONTROL,
+	snd_soc_component_update_bits(component, WM8983_ADDITIONAL_CONTROL,
 			    WM8983_SR_MASK, srate_idx << WM8983_SR_SHIFT);
 
 	dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8983->bclk);
@@ -721,7 +721,7 @@ static int wm8983_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
-	snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+	snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
 			    WM8983_MCLKDIV_MASK, i << WM8983_MCLKDIV_SHIFT);
 
 	/* select the appropriate bclk divider */
@@ -737,7 +737,7 @@ static int wm8983_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dev_dbg(dai->dev, "BCLK div = %d\n", i);
-	snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+	snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
 			    WM8983_BCLKDIV_MASK, i << WM8983_BCLKDIV_SHIFT);
 
 	return 0;
@@ -789,13 +789,13 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
 			  unsigned int freq_out)
 {
 	int ret;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct pll_div pll_div;
 
-	codec = dai->codec;
+	component = dai->component;
 	if (!freq_in || !freq_out) {
 		/* disable the PLL */
-		snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 				    WM8983_PLLEN_MASK, 0);
 		return 0;
 	} else {
@@ -804,19 +804,19 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
 			return ret;
 
 		/* disable the PLL before re-programming it */
-		snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 				    WM8983_PLLEN_MASK, 0);
 
 		/* set PLLN and PRESCALE */
-		snd_soc_write(codec, WM8983_PLL_N,
+		snd_soc_component_write(component, WM8983_PLL_N,
 			(pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
 			| pll_div.n);
 		/* set PLLK */
-		snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
-		snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
-		snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
+		snd_soc_component_write(component, WM8983_PLL_K_3, pll_div.k & 0x1ff);
+		snd_soc_component_write(component, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+		snd_soc_component_write(component, WM8983_PLL_K_1, (pll_div.k >> 18));
 		/* enable the PLL */
-		snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 					WM8983_PLLEN_MASK, WM8983_PLLEN);
 	}
 
@@ -826,16 +826,16 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
 static int wm8983_set_sysclk(struct snd_soc_dai *dai,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM8983_CLKSRC_MCLK:
-		snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+		snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
 				    WM8983_CLKSEL_MASK, 0);
 		break;
 	case WM8983_CLKSRC_PLL:
-		snd_soc_update_bits(codec, WM8983_CLOCK_GEN_CONTROL,
+		snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
 				    WM8983_CLKSEL_MASK, WM8983_CLKSEL);
 		break;
 	default:
@@ -847,100 +847,100 @@ static int wm8983_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static int wm8983_set_bias_level(struct snd_soc_codec *codec,
+static int wm8983_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
+	struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID at 100k */
-		snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 				    WM8983_VMIDSEL_MASK,
 				    1 << WM8983_VMIDSEL_SHIFT);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(wm8983->regmap);
 			if (ret < 0) {
-				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
 				return ret;
 			}
 			/* enable anti-pop features */
-			snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC,
+			snd_soc_component_update_bits(component, WM8983_OUT4_TO_ADC,
 					    WM8983_POBCTRL_MASK | WM8983_DELEN_MASK,
 					    WM8983_POBCTRL | WM8983_DELEN);
 			/* enable thermal shutdown */
-			snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL,
+			snd_soc_component_update_bits(component, WM8983_OUTPUT_CTRL,
 					    WM8983_TSDEN_MASK, WM8983_TSDEN);
 			/* enable BIASEN */
-			snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 					    WM8983_BIASEN_MASK, WM8983_BIASEN);
 			/* VMID at 100k */
-			snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 					    WM8983_VMIDSEL_MASK,
 					    1 << WM8983_VMIDSEL_SHIFT);
 			msleep(250);
 			/* disable anti-pop features */
-			snd_soc_update_bits(codec, WM8983_OUT4_TO_ADC,
+			snd_soc_component_update_bits(component, WM8983_OUT4_TO_ADC,
 					    WM8983_POBCTRL_MASK |
 					    WM8983_DELEN_MASK, 0);
 		}
 
 		/* VMID at 500k */
-		snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 				    WM8983_VMIDSEL_MASK,
 				    2 << WM8983_VMIDSEL_SHIFT);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* disable thermal shutdown */
-		snd_soc_update_bits(codec, WM8983_OUTPUT_CTRL,
+		snd_soc_component_update_bits(component, WM8983_OUTPUT_CTRL,
 				    WM8983_TSDEN_MASK, 0);
 		/* disable VMIDSEL and BIASEN */
-		snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
 				    WM8983_VMIDSEL_MASK | WM8983_BIASEN_MASK,
 				    0);
 		/* wait for VMID to discharge */
 		msleep(100);
-		snd_soc_write(codec, WM8983_POWER_MANAGEMENT_1, 0);
-		snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, 0);
-		snd_soc_write(codec, WM8983_POWER_MANAGEMENT_3, 0);
+		snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_1, 0);
+		snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_2, 0);
+		snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_3, 0);
 		break;
 	}
 
 	return 0;
 }
 
-static int wm8983_probe(struct snd_soc_codec *codec)
+static int wm8983_probe(struct snd_soc_component *component)
 {
 	int ret;
 	int i;
 
-	ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);
+	ret = snd_soc_component_write(component, WM8983_SOFTWARE_RESET, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		return ret;
 	}
 
 	/* set the vol/gain update bits */
 	for (i = 0; i < ARRAY_SIZE(vol_update_regs); ++i)
-		snd_soc_update_bits(codec, vol_update_regs[i],
+		snd_soc_component_update_bits(component, vol_update_regs[i],
 				    0x100, 0x100);
 
 	/* mute all outputs and set PGAs to minimum gain */
 	for (i = WM8983_LOUT1_HP_VOLUME_CTRL;
 	     i <= WM8983_OUT4_MONO_MIX_CTRL; ++i)
-		snd_soc_update_bits(codec, i, 0x40, 0x40);
+		snd_soc_component_update_bits(component, i, 0x40, 0x40);
 
 	/* enable soft mute */
-	snd_soc_update_bits(codec, WM8983_DAC_CONTROL,
+	snd_soc_component_update_bits(component, WM8983_DAC_CONTROL,
 			    WM8983_SOFTMUTE_MASK,
 			    WM8983_SOFTMUTE);
 
 	/* enable BIASCUT */
-	snd_soc_update_bits(codec, WM8983_BIAS_CTRL,
+	snd_soc_component_update_bits(component, WM8983_BIAS_CTRL,
 			    WM8983_BIASCUT, WM8983_BIASCUT);
 	return 0;
 }
@@ -976,18 +976,20 @@ static struct snd_soc_dai_driver wm8983_dai = {
 	.symmetric_rates = 1
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8983 = {
-	.probe = wm8983_probe,
-	.set_bias_level = wm8983_set_bias_level,
-	.suspend_bias_off = true,
-	.component_driver = {
-		.controls		= wm8983_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8983_snd_controls),
-		.dapm_widgets		= wm8983_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8983_dapm_widgets),
-		.dapm_routes		= wm8983_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(wm8983_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8983 = {
+	.probe			= wm8983_probe,
+	.set_bias_level		= wm8983_set_bias_level,
+	.controls		= wm8983_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8983_snd_controls),
+	.dapm_widgets		= wm8983_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8983_dapm_widgets),
+	.dapm_routes		= wm8983_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm8983_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8983_regmap = {
@@ -1021,23 +1023,16 @@ static int wm8983_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8983);
 
-	ret = snd_soc_register_codec(&spi->dev,
-				     &soc_codec_dev_wm8983, &wm8983_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+				&soc_component_dev_wm8983, &wm8983_dai, 1);
 	return ret;
 }
 
-static int wm8983_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8983_spi_driver = {
 	.driver = {
 		.name = "wm8983",
 	},
 	.probe = wm8983_spi_probe,
-	.remove = wm8983_spi_remove
 };
 #endif
 
@@ -1061,18 +1056,12 @@ static int wm8983_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8983);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8983, &wm8983_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_wm8983, &wm8983_dai, 1);
 
 	return ret;
 }
 
-static int wm8983_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8983_i2c_id[] = {
 	{ "wm8983", 0 },
 	{ }
@@ -1084,7 +1073,6 @@ static struct i2c_driver wm8983_i2c_driver = {
 		.name = "wm8983",
 	},
 	.probe = wm8983_i2c_probe,
-	.remove = wm8983_i2c_remove,
 	.id_table = wm8983_i2c_id
 };
 #endif
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 05344f974ff3..18b342ca4f8e 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -564,10 +564,10 @@ static const struct snd_soc_dapm_route wm8985_aux_dapm_routes[] = {
 	{ "Left Boost Mixer", "AUXL Volume", "AUXL" },
 };
 
-static int wm8985_add_widgets(struct snd_soc_codec *codec)
+static int wm8985_add_widgets(struct snd_soc_component *component)
 {
-	struct wm8985_priv *wm8985 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8985_priv *wm8985 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	switch (wm8985->dev_type) {
 	case WM8758:
@@ -576,7 +576,7 @@ static int wm8985_add_widgets(struct snd_soc_codec *codec)
 		break;
 
 	case WM8985:
-		snd_soc_add_codec_controls(codec, wm8985_specific_snd_controls,
+		snd_soc_add_component_controls(component, wm8985_specific_snd_controls,
 			ARRAY_SIZE(wm8985_specific_snd_controls));
 
 		snd_soc_dapm_new_controls(dapm, wm8985_dapm_widgets,
@@ -592,10 +592,10 @@ static int wm8985_add_widgets(struct snd_soc_codec *codec)
 static int eqmode_get(struct snd_kcontrol *kcontrol,
 		      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+	reg = snd_soc_component_read32(component, WM8985_EQ1_LOW_SHELF);
 	if (reg & WM8985_EQ3DMODE)
 		ucontrol->value.enumerated.item[0] = 1;
 	else
@@ -607,7 +607,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
 static int eqmode_put(struct snd_kcontrol *kcontrol,
 		      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int regpwr2, regpwr3;
 	unsigned int reg_eq;
 
@@ -615,7 +615,7 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
 			&& ucontrol->value.enumerated.item[0] != 1)
 		return -EINVAL;
 
-	reg_eq = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+	reg_eq = snd_soc_component_read32(component, WM8985_EQ1_LOW_SHELF);
 	switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
 	case 0:
 		if (!ucontrol->value.enumerated.item[0])
@@ -627,46 +627,46 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
 		break;
 	}
 
-	regpwr2 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_2);
-	regpwr3 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_3);
+	regpwr2 = snd_soc_component_read32(component, WM8985_POWER_MANAGEMENT_2);
+	regpwr3 = snd_soc_component_read32(component, WM8985_POWER_MANAGEMENT_3);
 	/* disable the DACs and ADCs */
-	snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_2,
+	snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_2,
 			    WM8985_ADCENR_MASK | WM8985_ADCENL_MASK, 0);
-	snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_3,
+	snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_3,
 			    WM8985_DACENR_MASK | WM8985_DACENL_MASK, 0);
-	snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+	snd_soc_component_update_bits(component, WM8985_ADDITIONAL_CONTROL,
 			    WM8985_M128ENB_MASK, WM8985_M128ENB);
 	/* set the desired eqmode */
-	snd_soc_update_bits(codec, WM8985_EQ1_LOW_SHELF,
+	snd_soc_component_update_bits(component, WM8985_EQ1_LOW_SHELF,
 			    WM8985_EQ3DMODE_MASK,
 			    ucontrol->value.enumerated.item[0]
 			    << WM8985_EQ3DMODE_SHIFT);
 	/* restore DAC/ADC configuration */
-	snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, regpwr2);
-	snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, regpwr3);
+	snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_2, regpwr2);
+	snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_3, regpwr3);
 	return 0;
 }
 
-static int wm8985_reset(struct snd_soc_codec *codec)
+static int wm8985_reset(struct snd_soc_component *component)
 {
-	return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
+	return snd_soc_component_write(component, WM8985_SOFTWARE_RESET, 0x0);
 }
 
 static int wm8985_dac_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
-	return snd_soc_update_bits(codec, WM8985_DAC_CONTROL,
+	return snd_soc_component_update_bits(component, WM8985_DAC_CONTROL,
 				   WM8985_SOFTMUTE_MASK,
 				   !!mute << WM8985_SOFTMUTE_SHIFT);
 }
 
 static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	u16 format, master, bcp, lrp;
 
-	codec = dai->codec;
+	component = dai->component;
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
@@ -687,7 +687,7 @@ static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
 			    WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -702,7 +702,7 @@ static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+	snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
 			    WM8985_MS_MASK, master << WM8985_MS_SHIFT);
 
 	/* frame inversion is not valid for dsp modes */
@@ -739,9 +739,9 @@ static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
 			    WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
-	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
 			    WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
 	return 0;
 }
@@ -751,14 +751,14 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
 	int i;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8985_priv *wm8985;
 	u16 blen, srate_idx;
 	unsigned int tmp;
 	int srate_best;
 
-	codec = dai->codec;
-	wm8985 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8985 = snd_soc_component_get_drvdata(component);
 
 	wm8985->bclk = snd_soc_params_to_bclk(params);
 	if ((int)wm8985->bclk < 0)
@@ -783,7 +783,7 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
 			    WM8985_WL_MASK, blen << WM8985_WL_SHIFT);
 
 	/*
@@ -800,7 +800,7 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
-	snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+	snd_soc_component_update_bits(component, WM8985_ADDITIONAL_CONTROL,
 			    WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
 
 	dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
@@ -819,7 +819,7 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
-	snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+	snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
 			    WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
 
 	/* select the appropriate bclk divider */
@@ -835,7 +835,7 @@ static int wm8985_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	dev_dbg(dai->dev, "BCLK div = %d\n", i);
-	snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+	snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
 			    WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
 	return 0;
 }
@@ -887,13 +887,13 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
 			  unsigned int freq_out)
 {
 	int ret;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct pll_div pll_div;
 
-	codec = dai->codec;
+	component = dai->component;
 	if (!freq_in || !freq_out) {
 		/* disable the PLL */
-		snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 				    WM8985_PLLEN_MASK, 0);
 	} else {
 		ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
@@ -901,18 +901,18 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
 			return ret;
 
 		/* set PLLN and PRESCALE */
-		snd_soc_write(codec, WM8985_PLL_N,
+		snd_soc_component_write(component, WM8985_PLL_N,
 			      (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
 			      | pll_div.n);
 		/* set PLLK */
-		snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
-		snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
-		snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
+		snd_soc_component_write(component, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+		snd_soc_component_write(component, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+		snd_soc_component_write(component, WM8985_PLL_K_1, (pll_div.k >> 18));
 		/* set the source of the clock to be the PLL */
-		snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+		snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
 				    WM8985_CLKSEL_MASK, WM8985_CLKSEL);
 		/* enable the PLL */
-		snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 				    WM8985_PLLEN_MASK, WM8985_PLLEN);
 	}
 	return 0;
@@ -921,21 +921,21 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
 static int wm8985_set_sysclk(struct snd_soc_dai *dai,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8985_priv *wm8985;
 
-	codec = dai->codec;
-	wm8985 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8985 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM8985_CLKSRC_MCLK:
-		snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+		snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
 				    WM8985_CLKSEL_MASK, 0);
-		snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 				    WM8985_PLLEN_MASK, 0);
 		break;
 	case WM8985_CLKSRC_PLL:
-		snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+		snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
 				    WM8985_CLKSEL_MASK, WM8985_CLKSEL);
 		break;
 	default:
@@ -947,27 +947,27 @@ static int wm8985_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static int wm8985_set_bias_level(struct snd_soc_codec *codec,
+static int wm8985_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	int ret;
 	struct wm8985_priv *wm8985;
 
-	wm8985 = snd_soc_codec_get_drvdata(codec);
+	wm8985 = snd_soc_component_get_drvdata(component);
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID at 75k */
-		snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 				    WM8985_VMIDSEL_MASK,
 				    1 << WM8985_VMIDSEL_SHIFT);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
 						    wm8985->supplies);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -976,45 +976,45 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
 			regcache_sync(wm8985->regmap);
 
 			/* enable anti-pop features */
-			snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+			snd_soc_component_update_bits(component, WM8985_OUT4_TO_ADC,
 					    WM8985_POBCTRL_MASK,
 					    WM8985_POBCTRL);
 			/* enable thermal shutdown */
-			snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+			snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
 					    WM8985_TSDEN_MASK, WM8985_TSDEN);
-			snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+			snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
 					    WM8985_TSOPCTRL_MASK,
 					    WM8985_TSOPCTRL);
 			/* enable BIASEN */
-			snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 					    WM8985_BIASEN_MASK, WM8985_BIASEN);
 			/* VMID at 75k */
-			snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 					    WM8985_VMIDSEL_MASK,
 					    1 << WM8985_VMIDSEL_SHIFT);
 			msleep(500);
 			/* disable anti-pop features */
-			snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+			snd_soc_component_update_bits(component, WM8985_OUT4_TO_ADC,
 					    WM8985_POBCTRL_MASK, 0);
 		}
 		/* VMID at 300k */
-		snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 				    WM8985_VMIDSEL_MASK,
 				    2 << WM8985_VMIDSEL_SHIFT);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* disable thermal shutdown */
-		snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+		snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
 				    WM8985_TSOPCTRL_MASK, 0);
-		snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+		snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
 				    WM8985_TSDEN_MASK, 0);
 		/* disable VMIDSEL and BIASEN */
-		snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
 				    WM8985_VMIDSEL_MASK | WM8985_BIASEN_MASK,
 				    0);
-		snd_soc_write(codec, WM8985_POWER_MANAGEMENT_1, 0);
-		snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
-		snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
+		snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_1, 0);
+		snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_2, 0);
+		snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_3, 0);
 
 		regcache_mark_dirty(wm8985->regmap);
 
@@ -1026,46 +1026,46 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int wm8985_probe(struct snd_soc_codec *codec)
+static int wm8985_probe(struct snd_soc_component *component)
 {
 	size_t i;
 	struct wm8985_priv *wm8985;
 	int ret;
 
-	wm8985 = snd_soc_codec_get_drvdata(codec);
+	wm8985 = snd_soc_component_get_drvdata(component);
 
 	for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
 		wm8985->supplies[i].supply = wm8985_supply_names[i];
 
-	ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+	ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(wm8985->supplies),
 				 wm8985->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
 		return ret;
 	}
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
 				    wm8985->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		return ret;
 	}
 
-	ret = wm8985_reset(codec);
+	ret = wm8985_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		goto err_reg_enable;
 	}
 
 	/* latch volume update bits */
 	for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
-		snd_soc_update_bits(codec, volume_update_regs[i],
+		snd_soc_component_update_bits(component, volume_update_regs[i],
 				    0x100, 0x100);
 	/* enable BIASCUT */
-	snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT,
+	snd_soc_component_update_bits(component, WM8985_BIAS_CTRL, WM8985_BIASCUT,
 			    WM8985_BIASCUT);
 
-	wm8985_add_widgets(codec);
+	wm8985_add_widgets(component);
 
 	return 0;
 
@@ -1105,19 +1105,20 @@ static struct snd_soc_dai_driver wm8985_dai = {
 	.symmetric_rates = 1
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
-	.probe = wm8985_probe,
-	.set_bias_level = wm8985_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8985_common_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8985_common_snd_controls),
-		.dapm_widgets		= wm8985_common_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8985_common_dapm_widgets),
-		.dapm_routes		= wm8985_common_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8985_common_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8985 = {
+	.probe			= wm8985_probe,
+	.set_bias_level		= wm8985_set_bias_level,
+	.controls		= wm8985_common_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8985_common_snd_controls),
+	.dapm_widgets		= wm8985_common_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8985_common_dapm_widgets),
+	.dapm_routes		= wm8985_common_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8985_common_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8985_regmap = {
@@ -1154,23 +1155,16 @@ static int wm8985_spi_probe(struct spi_device *spi)
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&spi->dev,
-				     &soc_codec_dev_wm8985, &wm8985_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm8985, &wm8985_dai, 1);
 	return ret;
 }
 
-static int wm8985_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8985_spi_driver = {
 	.driver = {
 		.name = "wm8985",
 	},
 	.probe = wm8985_spi_probe,
-	.remove = wm8985_spi_remove
 };
 #endif
 
@@ -1197,17 +1191,11 @@ static int wm8985_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8985, &wm8985_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8985, &wm8985_dai, 1);
 	return ret;
 }
 
-static int wm8985_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8985_i2c_id[] = {
 	{ "wm8985", WM8985 },
 	{ "wm8758", WM8758 },
@@ -1220,7 +1208,6 @@ static struct i2c_driver wm8985_i2c_driver = {
 		.name = "wm8985",
 	},
 	.probe = wm8985_i2c_probe,
-	.remove = wm8985_i2c_remove,
 	.id_table = wm8985_i2c_id
 };
 #endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index b0d0219532f2..62200117444b 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -119,7 +119,7 @@ struct wm8988_priv {
 	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
-#define wm8988_reset(c)	snd_soc_write(c, WM8988_RESET, 0)
+#define wm8988_reset(c)	snd_soc_component_write(c, WM8988_RESET, 0)
 
 /*
  * WM8988 Controls
@@ -244,16 +244,16 @@ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
 static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 adctl2 = snd_soc_component_read32(component, WM8988_ADCTL2);
 
 	/* Use the DAC to gate LRC if active, otherwise use ADC */
-	if (snd_soc_read(codec, WM8988_PWR2) & 0x180)
+	if (snd_soc_component_read32(component, WM8988_PWR2) & 0x180)
 		adctl2 &= ~0x4;
 	else
 		adctl2 |= 0x4;
 
-	return snd_soc_write(codec, WM8988_ADCTL2, adctl2);
+	return snd_soc_component_write(component, WM8988_ADCTL2, adctl2);
 }
 
 static const char *wm8988_line_texts[] = {
@@ -555,8 +555,8 @@ static const struct snd_pcm_hw_constraint_list constraints_12 = {
 static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
 
 	switch (freq) {
 	case 11289600:
@@ -587,7 +587,7 @@ static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 iface = 0;
 
 	/* set master/slave audio interface */
@@ -638,21 +638,21 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8988_IFACE, iface);
+	snd_soc_component_write(component, WM8988_IFACE, iface);
 	return 0;
 }
 
 static int wm8988_pcm_startup(struct snd_pcm_substream *substream,
 			      struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
 
 	/* The set of sample rates that can be supported depends on the
 	 * MCLK supplied to the CODEC - enforce this.
 	 */
 	if (!wm8988->sysclk) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"No MCLK configured, call set_sysclk() on init\n");
 		return -EINVAL;
 	}
@@ -668,10 +668,10 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
-	u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
-	u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
+	struct snd_soc_component *component = dai->component;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8988_IFACE) & 0x1f3;
+	u16 srate = snd_soc_component_read32(component, WM8988_SRATE) & 0x180;
 	int coeff;
 
 	coeff = get_coeff(wm8988->sysclk, params_rate(params));
@@ -680,7 +680,7 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
 		srate |= 0x40;
 	}
 	if (coeff < 0) {
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Unable to configure sample rate %dHz with %dHz MCLK\n",
 			params_rate(params), wm8988->sysclk);
 		return coeff;
@@ -702,9 +702,9 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set iface & srate */
-	snd_soc_write(codec, WM8988_IFACE, iface);
+	snd_soc_component_write(component, WM8988_IFACE, iface);
 	if (coeff >= 0)
-		snd_soc_write(codec, WM8988_SRATE, srate |
+		snd_soc_component_write(component, WM8988_SRATE, srate |
 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
 
 	return 0;
@@ -712,21 +712,21 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8988_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7;
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8988_ADCDAC) & 0xfff7;
 
 	if (mute)
-		snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
+		snd_soc_component_write(component, WM8988_ADCDAC, mute_reg | 0x8);
 	else
-		snd_soc_write(codec, WM8988_ADCDAC, mute_reg);
+		snd_soc_component_write(component, WM8988_ADCDAC, mute_reg);
 	return 0;
 }
 
-static int wm8988_set_bias_level(struct snd_soc_codec *codec,
+static int wm8988_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
-	u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8988_PWR1) & ~0x1c1;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -734,26 +734,26 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VREF, VMID=2x50k, digital enabled */
-		snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
+		snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x00c0);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_sync(wm8988->regmap);
 
 			/* VREF, VMID=2x5k */
-			snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
+			snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x1c1);
 
 			/* Charge caps */
 			msleep(100);
 		}
 
 		/* VREF, VMID=2*500k, digital stopped */
-		snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x0141);
+		snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x0141);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_write(codec, WM8988_PWR1, 0x0000);
+		snd_soc_component_write(component, WM8988_PWR1, 0x0000);
 		break;
 	}
 	return 0;
@@ -792,39 +792,40 @@ static struct snd_soc_dai_driver wm8988_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8988_probe(struct snd_soc_codec *codec)
+static int wm8988_probe(struct snd_soc_component *component)
 {
 	int ret = 0;
 
-	ret = wm8988_reset(codec);
+	ret = wm8988_reset(component);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset\n");
+		dev_err(component->dev, "Failed to issue reset\n");
 		return ret;
 	}
 
 	/* set the update bits (we always update left then right) */
-	snd_soc_update_bits(codec, WM8988_RADC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8988_RDAC, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8988_ROUT1V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100);
-	snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_RADC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_RINVOL, 0x0100, 0x0100);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
-	.probe =	wm8988_probe,
-	.set_bias_level = wm8988_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8988_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8988_snd_controls),
-		.dapm_widgets		= wm8988_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8988_dapm_widgets),
-		.dapm_routes		= wm8988_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8988_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8988 = {
+	.probe			= wm8988_probe,
+	.set_bias_level		= wm8988_set_bias_level,
+	.controls		= wm8988_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8988_snd_controls),
+	.dapm_widgets		= wm8988_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8988_dapm_widgets),
+	.dapm_routes		= wm8988_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8988_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8988_regmap = {
@@ -859,23 +860,16 @@ static int wm8988_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm8988);
 
-	ret = snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_wm8988, &wm8988_dai, 1);
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8988, &wm8988_dai, 1);
 	return ret;
 }
 
-static int wm8988_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8988_spi_driver = {
 	.driver = {
 		.name	= "wm8988",
 	},
 	.probe		= wm8988_spi_probe,
-	.remove		= wm8988_spi_remove,
 };
 #endif /* CONFIG_SPI_MASTER */
 
@@ -900,17 +894,11 @@ static int wm8988_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8988, &wm8988_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8988, &wm8988_dai, 1);
 	return ret;
 }
 
-static int wm8988_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8988_i2c_id[] = {
 	{ "wm8988", 0 },
 	{ }
@@ -922,7 +910,6 @@ static struct i2c_driver wm8988_i2c_driver = {
 		.name = "wm8988",
 	},
 	.probe =    wm8988_i2c_probe,
-	.remove =   wm8988_i2c_remove,
 	.id_table = wm8988_i2c_id,
 };
 #endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index a8945001e696..411b9eee88c2 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -111,7 +111,7 @@ static const struct reg_default wm8990_reg_defaults[] = {
 	{ 62, 0x0026 },     /* R62 - PLL3 */
 };
 
-#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
+#define wm8990_reset(c) snd_soc_component_write(c, WM8990_RESET, 0)
 
 static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
 
@@ -132,7 +132,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
 static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	int reg = mc->reg;
@@ -144,8 +144,8 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 		return ret;
 
 	/* now hit the volume update bits (always bit 8) */
-	val = snd_soc_read(codec, reg);
-	return snd_soc_write(codec, reg, val | 0x0100);
+	val = snd_soc_component_read32(component, reg);
+	return snd_soc_component_write(component, reg, val | 0x0100);
 }
 
 #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
@@ -374,14 +374,14 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	u32 reg_shift = kcontrol->private_value & 0xfff;
 	int ret = 0;
 	u16 reg;
 
 	switch (reg_shift) {
 	case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
-		reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER1);
+		reg = snd_soc_component_read32(component, WM8990_OUTPUT_MIXER1);
 		if (reg & WM8990_LDLO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -389,7 +389,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
-		reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER2);
+		reg = snd_soc_component_read32(component, WM8990_OUTPUT_MIXER2);
 		if (reg & WM8990_RDRO) {
 			printk(KERN_WARNING
 			"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -397,7 +397,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
-		reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
+		reg = snd_soc_component_read32(component, WM8990_SPEAKER_MIXER);
 		if (reg & WM8990_LDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -405,7 +405,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		}
 		break;
 	case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
-		reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
+		reg = snd_soc_component_read32(component, WM8990_SPEAKER_MIXER);
 		if (reg & WM8990_RDSPK) {
 			printk(KERN_WARNING
 			"Cannot set as Speaker Mixer RDSPK Set\n");
@@ -934,28 +934,28 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
 static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	struct _pll_div pll_div;
 
 	if (freq_in && freq_out) {
 		pll_factors(&pll_div, freq_out * 4, freq_in);
 
 		/* Turn on PLL */
-		snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2,
 				    WM8990_PLL_ENA, WM8990_PLL_ENA);
 
 		/* sysclk comes from PLL */
-		snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
 				    WM8990_SYSCLK_SRC, WM8990_SYSCLK_SRC);
 
 		/* set up N , fractional mode and pre-divisor if necessary */
-		snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
+		snd_soc_component_write(component, WM8990_PLL1, pll_div.n | WM8990_SDM |
 			(pll_div.div2?WM8990_PRESCALE:0));
-		snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
-		snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
+		snd_soc_component_write(component, WM8990_PLL2, (u8)(pll_div.k>>8));
+		snd_soc_component_write(component, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
 	} else {
 		/* Turn off PLL */
-		snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2,
 				    WM8990_PLL_ENA, 0);
 	}
 	return 0;
@@ -967,8 +967,8 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component);
 
 	wm8990->sysclk = freq;
 	return 0;
@@ -980,11 +980,11 @@ static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 audio1, audio3;
 
-	audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
-	audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3);
+	audio1 = snd_soc_component_read32(component, WM8990_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_component_read32(component, WM8990_AUDIO_INTERFACE_3);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1025,31 +1025,31 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
-	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
+	snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_3, audio3);
 	return 0;
 }
 
 static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	switch (div_id) {
 	case WM8990_MCLK_DIV:
-		snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
 				    WM8990_MCLK_DIV_MASK, div);
 		break;
 	case WM8990_DACCLK_DIV:
-		snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
 				    WM8990_DAC_CLKDIV_MASK, div);
 		break;
 	case WM8990_ADCCLK_DIV:
-		snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
 				    WM8990_ADC_CLKDIV_MASK, div);
 		break;
 	case WM8990_BCLK_DIV:
-		snd_soc_update_bits(codec, WM8990_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_1,
 				    WM8990_BCLK_DIV_MASK, div);
 		break;
 	default:
@@ -1066,8 +1066,8 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
+	struct snd_soc_component *component = dai->component;
+	u16 audio1 = snd_soc_component_read32(component, WM8990_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8990_AIF_WL_MASK;
 	/* bit size */
@@ -1085,29 +1085,29 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_1, audio1);
 	return 0;
 }
 
 static int wm8990_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 val;
 
-	val  = snd_soc_read(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
+	val  = snd_soc_component_read32(component, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
 
 	if (mute)
-		snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+		snd_soc_component_write(component, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
 	else
-		snd_soc_write(codec, WM8990_DAC_CTRL, val);
+		snd_soc_component_write(component, WM8990_DAC_CTRL, val);
 
 	return 0;
 }
 
-static int wm8990_set_bias_level(struct snd_soc_codec *codec,
+static int wm8990_set_bias_level(struct snd_soc_component *component,
 	enum snd_soc_bias_level level)
 {
-	struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
+	struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1116,26 +1116,26 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*50k */
-		snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_1,
 				    WM8990_VMID_MODE_MASK, 0x2);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regcache_sync(wm8990->regmap);
 			if (ret < 0) {
-				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
 				return ret;
 			}
 
 			/* Enable all output discharge bits */
-			snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+			snd_soc_component_write(component, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
 				WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
 				WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
 				WM8990_DIS_ROUT);
 
 			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
 				     WM8990_BUFDCOPEN | WM8990_POBCTRL |
 				     WM8990_VMIDTOG);
 
@@ -1143,82 +1143,82 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 			msleep(300);
 
 			/* Disable VMIDTOG */
-			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
 				     WM8990_BUFDCOPEN | WM8990_POBCTRL);
 
 			/* disable all output discharge bits */
-			snd_soc_write(codec, WM8990_ANTIPOP1, 0);
+			snd_soc_component_write(component, WM8990_ANTIPOP1, 0);
 
 			/* Enable outputs */
-			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1b00);
 
 			msleep(50);
 
 			/* Enable VMID at 2x50k */
-			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02);
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f02);
 
 			msleep(100);
 
 			/* Enable VREF */
-			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f03);
 
 			msleep(600);
 
 			/* Enable BUFIOEN */
-			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
 				     WM8990_BUFDCOPEN | WM8990_POBCTRL |
 				     WM8990_BUFIOEN);
 
 			/* Disable outputs */
-			snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3);
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x3);
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-			snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_BUFIOEN);
 
 			/* Enable workaround for ADC clocking issue. */
-			snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
-			snd_soc_write(codec, WM8990_EXT_CTL1, 0xa003);
-			snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0);
+			snd_soc_component_write(component, WM8990_EXT_ACCESS_ENA, 0x2);
+			snd_soc_component_write(component, WM8990_EXT_CTL1, 0xa003);
+			snd_soc_component_write(component, WM8990_EXT_ACCESS_ENA, 0);
 		}
 
 		/* VMID=2*250k */
-		snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_1,
 				    WM8990_VMID_MODE_MASK, 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable POBCTRL and SOFT_ST */
-		snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+		snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
 			WM8990_POBCTRL | WM8990_BUFIOEN);
 
 		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-		snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+		snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
 			WM8990_BUFDCOPEN | WM8990_POBCTRL |
 			WM8990_BUFIOEN);
 
 		/* mute DAC */
-		snd_soc_update_bits(codec, WM8990_DAC_CTRL,
+		snd_soc_component_update_bits(component, WM8990_DAC_CTRL,
 				    WM8990_DAC_MUTE, WM8990_DAC_MUTE);
 
 		/* Enable any disabled outputs */
-		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+		snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f03);
 
 		/* Disable VMID */
-		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
+		snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f01);
 
 		msleep(300);
 
 		/* Enable all output discharge bits */
-		snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+		snd_soc_component_write(component, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
 			WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
 			WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
 			WM8990_DIS_ROUT);
 
 		/* Disable VREF */
-		snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0);
+		snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x0);
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-		snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
+		snd_soc_component_write(component, WM8990_ANTIPOP2, 0x0);
 
 		regcache_mark_dirty(wm8990->regmap);
 		break;
@@ -1272,41 +1272,42 @@ static struct snd_soc_dai_driver wm8990_dai = {
  * initialise the WM8990 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int wm8990_probe(struct snd_soc_codec *codec)
+static int wm8990_probe(struct snd_soc_component *component)
 {
-	wm8990_reset(codec);
+	wm8990_reset(component);
 
 	/* charge output caps */
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
-	snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4,
+	snd_soc_component_update_bits(component, WM8990_AUDIO_INTERFACE_4,
 			    WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
 
-	snd_soc_update_bits(codec, WM8990_GPIO1_GPIO2,
+	snd_soc_component_update_bits(component, WM8990_GPIO1_GPIO2,
 			    WM8990_GPIO1_SEL_MASK, 1);
 
-	snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
+	snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2,
 			    WM8990_OPCLK_ENA, WM8990_OPCLK_ENA);
 
-	snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
-	snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_component_write(component, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_component_write(component, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
-	.probe =	wm8990_probe,
-	.set_bias_level = wm8990_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8990_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8990_snd_controls),
-		.dapm_widgets		= wm8990_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8990_dapm_widgets),
-		.dapm_routes		= wm8990_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8990_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8990 = {
+	.probe			= wm8990_probe,
+	.set_bias_level		= wm8990_set_bias_level,
+	.controls		= wm8990_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8990_snd_controls),
+	.dapm_widgets		= wm8990_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8990_dapm_widgets),
+	.dapm_routes		= wm8990_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8990_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8990_regmap = {
@@ -1333,19 +1334,12 @@ static int wm8990_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm8990);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8990, &wm8990_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8990, &wm8990_dai, 1);
 
 	return ret;
 }
 
-static int wm8990_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8990_i2c_id[] = {
 	{ "wm8990", 0 },
 	{ }
@@ -1357,7 +1351,6 @@ static struct i2c_driver wm8990_i2c_driver = {
 		.name = "wm8990",
 	},
 	.probe =    wm8990_i2c_probe,
-	.remove =   wm8990_i2c_remove,
 	.id_table = wm8990_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 802c0694e5c3..76a639df6417 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -133,7 +133,7 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_sidetone_tlv,
 static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 				      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int reg = kcontrol->private_value & 0xff;
 	int ret;
 	u16 val;
@@ -143,8 +143,8 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 		return ret;
 
 	/* now hit the volume update bits (always bit 8) */
-	val = snd_soc_read(codec, reg);
-	return snd_soc_write(codec, reg, val | 0x0100);
+	val = snd_soc_component_read32(component, reg);
+	return snd_soc_component_write(component, reg, val | 0x0100);
 }
 
 static const char *wm8991_digital_sidetone[] =
@@ -361,14 +361,14 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
 static int outmixer_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	u32 reg_shift = kcontrol->private_value & 0xfff;
 	int ret = 0;
 	u16 reg;
 
 	switch (reg_shift) {
 	case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
-		reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER1);
+		reg = snd_soc_component_read32(component, WM8991_OUTPUT_MIXER1);
 		if (reg & WM8991_LDLO) {
 			printk(KERN_WARNING
 			       "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -377,7 +377,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
-		reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER2);
+		reg = snd_soc_component_read32(component, WM8991_OUTPUT_MIXER2);
 		if (reg & WM8991_RDRO) {
 			printk(KERN_WARNING
 			       "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -386,7 +386,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
-		reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
+		reg = snd_soc_component_read32(component, WM8991_SPEAKER_MIXER);
 		if (reg & WM8991_LDSPK) {
 			printk(KERN_WARNING
 			       "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -395,7 +395,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
-		reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
+		reg = snd_soc_component_read32(component, WM8991_SPEAKER_MIXER);
 		if (reg & WM8991_RDSPK) {
 			printk(KERN_WARNING
 			       "Cannot set as Speaker Mixer RDSPK Set\n");
@@ -927,31 +927,31 @@ static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai,
 			      int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
 {
 	u16 reg;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	struct _pll_div pll_div;
 
 	if (freq_in && freq_out) {
 		pll_factors(&pll_div, freq_out * 4, freq_in);
 
 		/* Turn on PLL */
-		reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
+		reg = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_2);
 		reg |= WM8991_PLL_ENA;
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_2, reg);
 
 		/* sysclk comes from PLL */
-		reg = snd_soc_read(codec, WM8991_CLOCKING_2);
-		snd_soc_write(codec, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC);
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2);
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC);
 
 		/* set up N , fractional mode and pre-divisor if necessary */
-		snd_soc_write(codec, WM8991_PLL1, pll_div.n | WM8991_SDM |
+		snd_soc_component_write(component, WM8991_PLL1, pll_div.n | WM8991_SDM |
 			      (pll_div.div2 ? WM8991_PRESCALE : 0));
-		snd_soc_write(codec, WM8991_PLL2, (u8)(pll_div.k>>8));
-		snd_soc_write(codec, WM8991_PLL3, (u8)(pll_div.k & 0xFF));
+		snd_soc_component_write(component, WM8991_PLL2, (u8)(pll_div.k>>8));
+		snd_soc_component_write(component, WM8991_PLL3, (u8)(pll_div.k & 0xFF));
 	} else {
 		/* Turn on PLL */
-		reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
+		reg = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_2);
 		reg &= ~WM8991_PLL_ENA;
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_2, reg);
 	}
 	return 0;
 }
@@ -962,11 +962,11 @@ static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai,
 static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 audio1, audio3;
 
-	audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1);
-	audio3 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_3);
+	audio1 = snd_soc_component_read32(component, WM8991_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_component_read32(component, WM8991_AUDIO_INTERFACE_3);
 
 	/* set master/slave audio interface */
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1007,37 +1007,37 @@ static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1);
-	snd_soc_write(codec, WM8991_AUDIO_INTERFACE_3, audio3);
+	snd_soc_component_write(component, WM8991_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8991_AUDIO_INTERFACE_3, audio3);
 	return 0;
 }
 
 static int wm8991_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 				 int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	u16 reg;
 
 	switch (div_id) {
 	case WM8991_MCLK_DIV:
-		reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2) &
 		      ~WM8991_MCLK_DIV_MASK;
-		snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | div);
 		break;
 	case WM8991_DACCLK_DIV:
-		reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2) &
 		      ~WM8991_DAC_CLKDIV_MASK;
-		snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | div);
 		break;
 	case WM8991_ADCCLK_DIV:
-		reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2) &
 		      ~WM8991_ADC_CLKDIV_MASK;
-		snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | div);
 		break;
 	case WM8991_BCLK_DIV:
-		reg = snd_soc_read(codec, WM8991_CLOCKING_1) &
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_1) &
 		      ~WM8991_BCLK_DIV_MASK;
-		snd_soc_write(codec, WM8991_CLOCKING_1, reg | div);
+		snd_soc_component_write(component, WM8991_CLOCKING_1, reg | div);
 		break;
 	default:
 		return -EINVAL;
@@ -1053,8 +1053,8 @@ static int wm8991_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	u16 audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1);
+	struct snd_soc_component *component = dai->component;
+	u16 audio1 = snd_soc_component_read32(component, WM8991_AUDIO_INTERFACE_1);
 
 	audio1 &= ~WM8991_AIF_WL_MASK;
 	/* bit size */
@@ -1072,27 +1072,27 @@ static int wm8991_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8991_AUDIO_INTERFACE_1, audio1);
 	return 0;
 }
 
 static int wm8991_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	u16 val;
 
-	val  = snd_soc_read(codec, WM8991_DAC_CTRL) & ~WM8991_DAC_MUTE;
+	val  = snd_soc_component_read32(component, WM8991_DAC_CTRL) & ~WM8991_DAC_MUTE;
 	if (mute)
-		snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
+		snd_soc_component_write(component, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
 	else
-		snd_soc_write(codec, WM8991_DAC_CTRL, val);
+		snd_soc_component_write(component, WM8991_DAC_CTRL, val);
 	return 0;
 }
 
-static int wm8991_set_bias_level(struct snd_soc_codec *codec,
+static int wm8991_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8991_priv *wm8991 = snd_soc_codec_get_drvdata(codec);
+	struct wm8991_priv *wm8991 = snd_soc_component_get_drvdata(component);
 	u16 val;
 
 	switch (level) {
@@ -1101,22 +1101,22 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*50k */
-		val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) &
+		val = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_1) &
 		      ~WM8991_VMID_MODE_MASK;
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x2);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, val | 0x2);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_sync(wm8991->regmap);
 			/* Enable all output discharge bits */
-			snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
+			snd_soc_component_write(component, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
 				      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
 				      WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
 				      WM8991_DIS_ROUT);
 
 			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
-			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
 				      WM8991_BUFDCOPEN | WM8991_POBCTRL |
 				      WM8991_VMIDTOG);
 
@@ -1124,78 +1124,78 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
 			msleep(300);
 
 			/* Disable VMIDTOG */
-			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
 				      WM8991_BUFDCOPEN | WM8991_POBCTRL);
 
 			/* disable all output discharge bits */
-			snd_soc_write(codec, WM8991_ANTIPOP1, 0);
+			snd_soc_component_write(component, WM8991_ANTIPOP1, 0);
 
 			/* Enable outputs */
-			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1b00);
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1b00);
 
 			msleep(50);
 
 			/* Enable VMID at 2x50k */
-			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f02);
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f02);
 
 			msleep(100);
 
 			/* Enable VREF */
-			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03);
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f03);
 
 			msleep(600);
 
 			/* Enable BUFIOEN */
-			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
 				      WM8991_BUFDCOPEN | WM8991_POBCTRL |
 				      WM8991_BUFIOEN);
 
 			/* Disable outputs */
-			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x3);
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x3);
 
 			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_BUFIOEN);
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_BUFIOEN);
 		}
 
 		/* VMID=2*250k */
-		val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) &
+		val = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_1) &
 		      ~WM8991_VMID_MODE_MASK;
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x4);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, val | 0x4);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Enable POBCTRL and SOFT_ST */
-		snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+		snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
 			      WM8991_POBCTRL | WM8991_BUFIOEN);
 
 		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
-		snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+		snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
 			      WM8991_BUFDCOPEN | WM8991_POBCTRL |
 			      WM8991_BUFIOEN);
 
 		/* mute DAC */
-		val = snd_soc_read(codec, WM8991_DAC_CTRL);
-		snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
+		val = snd_soc_component_read32(component, WM8991_DAC_CTRL);
+		snd_soc_component_write(component, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
 
 		/* Enable any disabled outputs */
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f03);
 
 		/* Disable VMID */
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f01);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f01);
 
 		msleep(300);
 
 		/* Enable all output discharge bits */
-		snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
+		snd_soc_component_write(component, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
 			      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
 			      WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
 			      WM8991_DIS_ROUT);
 
 		/* Disable VREF */
-		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x0);
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x0);
 
 		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
-		snd_soc_write(codec, WM8991_ANTIPOP2, 0x0);
+		snd_soc_component_write(component, WM8991_ANTIPOP2, 0x0);
 		regcache_mark_dirty(wm8991->regmap);
 		break;
 	}
@@ -1242,18 +1242,19 @@ static struct snd_soc_dai_driver wm8991_dai = {
 	.ops = &wm8991_ops
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
-	.set_bias_level = wm8991_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8991_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8991_snd_controls),
-		.dapm_widgets		= wm8991_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8991_dapm_widgets),
-		.dapm_routes		= wm8991_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8991_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8991 = {
+	.set_bias_level		= wm8991_set_bias_level,
+	.controls		= wm8991_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8991_snd_controls),
+	.dapm_widgets		= wm8991_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8991_dapm_widgets),
+	.dapm_routes		= wm8991_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8991_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8991_regmap = {
@@ -1319,19 +1320,12 @@ static int wm8991_i2c_probe(struct i2c_client *i2c,
 	regmap_write(wm8991->regmap, WM8991_RIGHT_OUTPUT_VOLUME,
 		     0x50 | (1<<8));
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8991, &wm8991_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8991, &wm8991_dai, 1);
 
 	return ret;
 }
 
-static int wm8991_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-
-	return 0;
-}
-
 static const struct i2c_device_id wm8991_i2c_id[] = {
 	{ "wm8991", 0 },
 	{ }
@@ -1343,7 +1337,6 @@ static struct i2c_driver wm8991_i2c_driver = {
 		.name = "wm8991",
 	},
 	.probe = wm8991_i2c_probe,
-	.remove = wm8991_i2c_remove,
 	.id_table = wm8991_i2c_id,
 };
 
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 830ffd80de4a..2c61655c44ea 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -466,11 +466,11 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int _wm8993_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
 	u16 reg1, reg4, reg5;
 	struct _fll_div fll_div;
 	unsigned int timeout;
@@ -482,13 +482,13 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
 	/* Disable the FLL */
 	if (Fout == 0) {
-		dev_dbg(codec->dev, "FLL disabled\n");
+		dev_dbg(component->dev, "FLL disabled\n");
 		wm8993->fll_fref = 0;
 		wm8993->fll_fout = 0;
 
-		reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1);
+		reg1 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_1);
 		reg1 &= ~WM8993_FLL_ENA;
-		snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1);
+		snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
 
 		return 0;
 	}
@@ -497,7 +497,7 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	if (ret != 0)
 		return ret;
 
-	reg5 = snd_soc_read(codec, WM8993_FLL_CONTROL_5);
+	reg5 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_5);
 	reg5 &= ~WM8993_FLL_CLK_SRC_MASK;
 
 	switch (fll_id) {
@@ -513,36 +513,36 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		break;
 
 	default:
-		dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
 		return -EINVAL;
 	}
 
 	/* Any FLL configuration change requires that the FLL be
 	 * disabled first. */
-	reg1 = snd_soc_read(codec, WM8993_FLL_CONTROL_1);
+	reg1 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_1);
 	reg1 &= ~WM8993_FLL_ENA;
-	snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1);
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
 
 	/* Apply the configuration */
 	if (fll_div.k)
 		reg1 |= WM8993_FLL_FRAC_MASK;
 	else
 		reg1 &= ~WM8993_FLL_FRAC_MASK;
-	snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1);
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
 
-	snd_soc_write(codec, WM8993_FLL_CONTROL_2,
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_2,
 		      (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
 		      (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
-	snd_soc_write(codec, WM8993_FLL_CONTROL_3, fll_div.k);
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_3, fll_div.k);
 
-	reg4 = snd_soc_read(codec, WM8993_FLL_CONTROL_4);
+	reg4 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_4);
 	reg4 &= ~WM8993_FLL_N_MASK;
 	reg4 |= fll_div.n << WM8993_FLL_N_SHIFT;
-	snd_soc_write(codec, WM8993_FLL_CONTROL_4, reg4);
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_4, reg4);
 
 	reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK;
 	reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
-	snd_soc_write(codec, WM8993_FLL_CONTROL_5, reg5);
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_5, reg5);
 
 	/* If we've got an interrupt wired up make sure we get it */
 	if (i2c->irq)
@@ -555,13 +555,13 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	try_wait_for_completion(&wm8993->fll_lock);
 
 	/* Enable the FLL */
-	snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
 
 	timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
 	if (i2c->irq && !timeout)
-		dev_warn(codec->dev, "Timed out waiting for FLL\n");
+		dev_warn(component->dev, "Timed out waiting for FLL\n");
 
-	dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+	dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
 
 	wm8993->fll_fref = Fref;
 	wm8993->fll_fout = Fout;
@@ -573,20 +573,20 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	return _wm8993_set_fll(dai->codec, fll_id, source, Fref, Fout);
+	return _wm8993_set_fll(dai->component, fll_id, source, Fref, Fout);
 }
 
-static int configure_clock(struct snd_soc_codec *codec)
+static int configure_clock(struct snd_soc_component *component)
 {
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 
 	/* This should be done on init() for bypass paths */
 	switch (wm8993->sysclk_source) {
 	case WM8993_SYSCLK_MCLK:
-		dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
+		dev_dbg(component->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
 
-		reg = snd_soc_read(codec, WM8993_CLOCKING_2);
+		reg = snd_soc_component_read32(component, WM8993_CLOCKING_2);
 		reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC);
 		if (wm8993->mclk_rate > 13500000) {
 			reg |= WM8993_MCLK_DIV;
@@ -595,14 +595,14 @@ static int configure_clock(struct snd_soc_codec *codec)
 			reg &= ~WM8993_MCLK_DIV;
 			wm8993->sysclk_rate = wm8993->mclk_rate;
 		}
-		snd_soc_write(codec, WM8993_CLOCKING_2, reg);
+		snd_soc_component_write(component, WM8993_CLOCKING_2, reg);
 		break;
 
 	case WM8993_SYSCLK_FLL:
-		dev_dbg(codec->dev, "Using %dHz FLL clock\n",
+		dev_dbg(component->dev, "Using %dHz FLL clock\n",
 			wm8993->fll_fout);
 
-		reg = snd_soc_read(codec, WM8993_CLOCKING_2);
+		reg = snd_soc_component_read32(component, WM8993_CLOCKING_2);
 		reg |= WM8993_SYSCLK_SRC;
 		if (wm8993->fll_fout > 13500000) {
 			reg |= WM8993_MCLK_DIV;
@@ -611,15 +611,15 @@ static int configure_clock(struct snd_soc_codec *codec)
 			reg &= ~WM8993_MCLK_DIV;
 			wm8993->sysclk_rate = wm8993->fll_fout;
 		}
-		snd_soc_write(codec, WM8993_CLOCKING_2, reg);
+		snd_soc_component_write(component, WM8993_CLOCKING_2, reg);
 		break;
 
 	default:
-		dev_err(codec->dev, "System clock not configured\n");
+		dev_err(component->dev, "System clock not configured\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate);
+	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate);
 
 	return 0;
 }
@@ -809,11 +809,11 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		return configure_clock(codec);
+		return configure_clock(component);
 
 	case SND_SOC_DAPM_POST_PMD:
 		break;
@@ -972,26 +972,26 @@ static const struct snd_soc_dapm_route routes[] = {
 	{ "Right Headphone Mux", "DAC", "DACR" },
 };
 
-static int wm8993_set_bias_level(struct snd_soc_codec *codec,
+static int wm8993_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	wm_hubs_set_bias_level(codec, level);
+	wm_hubs_set_bias_level(component, level);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*40k */
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 				    WM8993_VMID_SEL_MASK, 0x2);
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_2,
 				    WM8993_TSHUT_ENA, WM8993_TSHUT_ENA);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
 						    wm8993->supplies);
 			if (ret != 0)
@@ -1000,10 +1000,10 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
 			regcache_cache_only(wm8993->regmap, false);
 			regcache_sync(wm8993->regmap);
 
-			wm_hubs_vmid_ena(codec);
+			wm_hubs_vmid_ena(component);
 
 			/* Bring up VMID with fast soft start */
-			snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+			snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
 					    WM8993_STARTUP_BIAS_ENA |
 					    WM8993_VMID_BUF_ENA |
 					    WM8993_VMID_RAMP_MASK |
@@ -1017,40 +1017,40 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
 			 * need the VMID buffer */
 			if (!wm8993->pdata.lineout1_diff ||
 			    !wm8993->pdata.lineout2_diff)
-				snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+				snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
 						 WM8993_LINEOUT_VMID_BUF_ENA,
 						 WM8993_LINEOUT_VMID_BUF_ENA);
 
 			/* VMID=2*40k */
-			snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 					    WM8993_VMID_SEL_MASK |
 					    WM8993_BIAS_ENA,
 					    WM8993_BIAS_ENA | 0x2);
 			msleep(32);
 
 			/* Switch to normal bias */
-			snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+			snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
 					    WM8993_BIAS_SRC |
 					    WM8993_STARTUP_BIAS_ENA, 0);
 		}
 
 		/* VMID=2*240k */
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 				    WM8993_VMID_SEL_MASK, 0x4);
 
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_2,
 				    WM8993_TSHUT_ENA, 0);
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+		snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
 				    WM8993_LINEOUT_VMID_BUF_ENA, 0);
 
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 				    WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
 				    0);
 
-		snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+		snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
 				    WM8993_STARTUP_BIAS_ENA |
 				    WM8993_VMID_BUF_ENA |
 				    WM8993_VMID_RAMP_MASK |
@@ -1070,8 +1070,8 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
 static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
 			     int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM8993_SYSCLK_MCLK:
@@ -1091,10 +1091,10 @@ static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
 static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-	unsigned int aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1);
-	unsigned int aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4);
+	struct snd_soc_component *component = dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	unsigned int aif1 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_1);
+	unsigned int aif4 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_4);
 
 	aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV |
 		  WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK);
@@ -1178,8 +1178,8 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
-	snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_4, aif4);
 
 	return 0;
 }
@@ -1188,28 +1188,28 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 	int ret, i, best, best_val, cur_val;
 	unsigned int clocking1, clocking3, aif1, aif4;
 
-	clocking1 = snd_soc_read(codec, WM8993_CLOCKING_1);
+	clocking1 = snd_soc_component_read32(component, WM8993_CLOCKING_1);
 	clocking1 &= ~WM8993_BCLK_DIV_MASK;
 
-	clocking3 = snd_soc_read(codec, WM8993_CLOCKING_3);
+	clocking3 = snd_soc_component_read32(component, WM8993_CLOCKING_3);
 	clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK);
 
-	aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1);
+	aif1 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_1);
 	aif1 &= ~WM8993_AIF_WL_MASK;
 
-	aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4);
+	aif4 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_4);
 	aif4 &= ~WM8993_LRCLK_RATE_MASK;
 
 	/* What BCLK do we need? */
 	wm8993->fs = params_rate(params);
 	wm8993->bclk = 2 * wm8993->fs;
 	if (wm8993->tdm_slots) {
-		dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
+		dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
 			wm8993->tdm_slots, wm8993->tdm_width);
 		wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots;
 	} else {
@@ -1234,9 +1234,9 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk);
+	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm8993->bclk);
 
-	ret = configure_clock(codec);
+	ret = configure_clock(component);
 	if (ret != 0)
 		return ret;
 
@@ -1252,7 +1252,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 			best_val = cur_val;
 		}
 	}
-	dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
 		clk_sys_rates[best].ratio);
 	clocking3 |= (clk_sys_rates[best].clk_sys_rate
 		      << WM8993_CLK_SYS_RATE_SHIFT);
@@ -1268,7 +1268,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 			best_val = cur_val;
 		}
 	}
-	dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
 		sample_rates[best].rate);
 	clocking3 |= (sample_rates[best].sample_rate
 		      << WM8993_SAMPLE_RATE_SHIFT);
@@ -1287,22 +1287,22 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 	wm8993->bclk = (wm8993->sysclk_rate * 10) / bclk_divs[best].div;
-	dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
 		bclk_divs[best].div, wm8993->bclk);
 	clocking1 |= bclk_divs[best].bclk_div << WM8993_BCLK_DIV_SHIFT;
 
 	/* LRCLK is a simple fraction of BCLK */
-	dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
+	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
 	aif4 |= wm8993->bclk / wm8993->fs;
 
-	snd_soc_write(codec, WM8993_CLOCKING_1, clocking1);
-	snd_soc_write(codec, WM8993_CLOCKING_3, clocking3);
-	snd_soc_write(codec, WM8993_AUDIO_INTERFACE_1, aif1);
-	snd_soc_write(codec, WM8993_AUDIO_INTERFACE_4, aif4);
+	snd_soc_component_write(component, WM8993_CLOCKING_1, clocking1);
+	snd_soc_component_write(component, WM8993_CLOCKING_3, clocking3);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_4, aif4);
 
 	/* ReTune Mobile? */
 	if (wm8993->pdata.num_retune_configs) {
-		u16 eq1 = snd_soc_read(codec, WM8993_EQ1);
+		u16 eq1 = snd_soc_component_read32(component, WM8993_EQ1);
 		struct wm8993_retune_mobile_setting *s;
 
 		best = 0;
@@ -1318,16 +1318,16 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 		}
 		s = &wm8993->pdata.retune_configs[best];
 
-		dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
+		dev_dbg(component->dev, "ReTune Mobile %s tuned for %dHz\n",
 			s->name, s->rate);
 
 		/* Disable EQ while we reconfigure */
-		snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0);
+		snd_soc_component_update_bits(component, WM8993_EQ1, WM8993_EQ_ENA, 0);
 
 		for (i = 1; i < ARRAY_SIZE(s->config); i++)
-			snd_soc_write(codec, WM8993_EQ1 + i, s->config[i]);
+			snd_soc_component_write(component, WM8993_EQ1 + i, s->config[i]);
 
-		snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1);
+		snd_soc_component_update_bits(component, WM8993_EQ1, WM8993_EQ_ENA, eq1);
 	}
 
 	return 0;
@@ -1335,17 +1335,17 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM8993_DAC_CTRL);
+	reg = snd_soc_component_read32(component, WM8993_DAC_CTRL);
 
 	if (mute)
 		reg |= WM8993_DAC_MUTE;
 	else
 		reg &= ~WM8993_DAC_MUTE;
 
-	snd_soc_write(codec, WM8993_DAC_CTRL, reg);
+	snd_soc_component_write(component, WM8993_DAC_CTRL, reg);
 
 	return 0;
 }
@@ -1353,8 +1353,8 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 			       unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 	int aif1 = 0;
 	int aif2 = 0;
 
@@ -1396,9 +1396,9 @@ static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 	wm8993->tdm_width = slot_width;
 	wm8993->tdm_slots = slots / 2;
 
-	snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_1,
+	snd_soc_component_update_bits(component, WM8993_AUDIO_INTERFACE_1,
 			    WM8993_AIFADC_TDM | WM8993_AIFADC_TDM_CHAN, aif1);
-	snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_2,
+	snd_soc_component_update_bits(component, WM8993_AUDIO_INTERFACE_2,
 			    WM8993_AIFDAC_TDM | WM8993_AIFDAC_TDM_CHAN, aif2);
 
 	return 0;
@@ -1481,10 +1481,10 @@ static struct snd_soc_dai_driver wm8993_dai = {
 	.symmetric_rates = 1,
 };
 
-static int wm8993_probe(struct snd_soc_codec *codec)
+static int wm8993_probe(struct snd_soc_component *component)
 {
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	wm8993->hubs_data.hp_startup_mode = 1;
 	wm8993->hubs_data.dcs_codes_l = -2;
@@ -1492,20 +1492,20 @@ static int wm8993_probe(struct snd_soc_codec *codec)
 	wm8993->hubs_data.series_startup = 1;
 
 	/* Latch volume update bits and default ZC on */
-	snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
 			    WM8993_DAC_VU, WM8993_DAC_VU);
-	snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
 			    WM8993_ADC_VU, WM8993_ADC_VU);
 
 	/* Manualy manage the HPOUT sequencing for independent stereo
 	 * control. */
-	snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+	snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
 			    WM8993_HPOUT1_AUTO_PU, 0);
 
 	/* Use automatic clock configuration */
-	snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
+	snd_soc_component_update_bits(component, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
 
-	wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
+	wm_hubs_handle_analogue_pdata(component, wm8993->pdata.lineout1_diff,
 				      wm8993->pdata.lineout2_diff,
 				      wm8993->pdata.lineout1fb,
 				      wm8993->pdata.lineout2fb,
@@ -1516,22 +1516,22 @@ static int wm8993_probe(struct snd_soc_codec *codec)
 				      wm8993->pdata.micbias1_lvl,
 				      wm8993->pdata.micbias2_lvl);
 
-	snd_soc_add_codec_controls(codec, wm8993_snd_controls,
+	snd_soc_add_component_controls(component, wm8993_snd_controls,
 			     ARRAY_SIZE(wm8993_snd_controls));
 	if (wm8993->pdata.num_retune_configs != 0) {
-		dev_dbg(codec->dev, "Using ReTune Mobile\n");
+		dev_dbg(component->dev, "Using ReTune Mobile\n");
 	} else {
-		dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n");
-		snd_soc_add_codec_controls(codec, wm8993_eq_controls,
+		dev_dbg(component->dev, "No ReTune Mobile, using normal EQ\n");
+		snd_soc_add_component_controls(component, wm8993_eq_controls,
 				     ARRAY_SIZE(wm8993_eq_controls));
 	}
 
 	snd_soc_dapm_new_controls(dapm, wm8993_dapm_widgets,
 				  ARRAY_SIZE(wm8993_dapm_widgets));
-	wm_hubs_add_analogue_controls(codec);
+	wm_hubs_add_analogue_controls(component);
 
 	snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
-	wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
+	wm_hubs_add_analogue_routes(component, wm8993->pdata.lineout1_diff,
 				    wm8993->pdata.lineout2_diff);
 
 	/* If the line outputs are differential then we aren't presenting
@@ -1545,34 +1545,34 @@ static int wm8993_probe(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm8993_suspend(struct snd_soc_codec *codec)
+static int wm8993_suspend(struct snd_soc_component *component)
 {
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 	int fll_fout = wm8993->fll_fout;
 	int fll_fref  = wm8993->fll_fref;
 	int ret;
 
 	/* Stop the FLL in an orderly fashion */
-	ret = _wm8993_set_fll(codec, 0, 0, 0, 0);
+	ret = _wm8993_set_fll(component, 0, 0, 0, 0);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to stop FLL\n");
+		dev_err(component->dev, "Failed to stop FLL\n");
 		return ret;
 	}
 
 	wm8993->fll_fout = fll_fout;
 	wm8993->fll_fref = fll_fref;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
 
-static int wm8993_resume(struct snd_soc_codec *codec)
+static int wm8993_resume(struct snd_soc_component *component)
 {
-	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* Restart the FLL? */
 	if (wm8993->fll_fout) {
@@ -1582,10 +1582,10 @@ static int wm8993_resume(struct snd_soc_codec *codec)
 		wm8993->fll_fref = 0;
 		wm8993->fll_fout = 0;
 
-		ret = _wm8993_set_fll(codec, 0, wm8993->fll_src,
+		ret = _wm8993_set_fll(component, 0, wm8993->fll_src,
 				     fll_fref, fll_fout);
 		if (ret != 0)
-			dev_err(codec->dev, "Failed to restart FLL\n");
+			dev_err(component->dev, "Failed to restart FLL\n");
 	}
 
 	return 0;
@@ -1615,11 +1615,15 @@ static const struct regmap_config wm8993_regmap = {
 	.num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
-	.probe = 	wm8993_probe,
-	.suspend =	wm8993_suspend,
-	.resume =	wm8993_resume,
-	.set_bias_level = wm8993_set_bias_level,
+static const struct snd_soc_component_driver soc_component_dev_wm8993 = {
+	.probe			= wm8993_probe,
+	.suspend		= wm8993_suspend,
+	.resume			= wm8993_resume,
+	.set_bias_level		= wm8993_set_bias_level,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8993_i2c_probe(struct i2c_client *i2c,
@@ -1705,8 +1709,8 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
 
 	regcache_cache_only(wm8993->regmap, true);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm8993, &wm8993_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8993, &wm8993_dai, 1);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
 		goto err_irq;
@@ -1726,7 +1730,6 @@ static int wm8993_i2c_remove(struct i2c_client *i2c)
 {
 	struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c);
 
-	snd_soc_unregister_codec(&i2c->dev);
 	if (i2c->irq)
 		free_irq(i2c->irq, wm8993);
 	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 21ffd6403173..6e9e32a07259 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -106,9 +106,9 @@ static const struct wm8958_micd_rate jackdet_rates[] = {
 	{ 44100 * 256, false, 7, 8 },
 };
 
-static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
+static void wm8958_micd_set_rate(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int best, i, sysclk, val;
 	bool idle;
@@ -117,7 +117,7 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
 
 	idle = !wm8994->jack_mic;
 
-	sysclk = snd_soc_read(codec, WM8994_CLOCKING_1);
+	sysclk = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	if (sysclk & WM8994_SYSCLK_SRC)
 		sysclk = wm8994->aifclk[1];
 	else
@@ -148,18 +148,18 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
 	val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
 		| rates[best].rate << WM8958_MICD_RATE_SHIFT;
 
-	dev_dbg(codec->dev, "MICD rate %d,%d for %dHz %s\n",
+	dev_dbg(component->dev, "MICD rate %d,%d for %dHz %s\n",
 		rates[best].start, rates[best].rate, sysclk,
 		idle ? "idle" : "active");
 
-	snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+	snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
 			    WM8958_MICD_BIAS_STARTTIME_MASK |
 			    WM8958_MICD_RATE_MASK, val);
 }
 
-static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
+static int configure_aif_clock(struct snd_soc_component *component, int aif)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int rate;
 	int reg1 = 0;
 	int offset;
@@ -197,28 +197,28 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
 		rate /= 2;
 		reg1 |= WM8994_AIF1CLK_DIV;
 
-		dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n",
+		dev_dbg(component->dev, "Dividing AIF%d clock to %dHz\n",
 			aif + 1, rate);
 	}
 
 	wm8994->aifclk[aif] = rate;
 
-	snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
+	snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1 + offset,
 			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
 			    reg1);
 
 	return 0;
 }
 
-static int configure_clock(struct snd_soc_codec *codec)
+static int configure_clock(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int change, new;
 
 	/* Bring up the AIF clocks first */
-	configure_aif_clock(codec, 0);
-	configure_aif_clock(codec, 1);
+	configure_aif_clock(component, 0);
+	configure_aif_clock(component, 1);
 
 	/* Then switch CLK_SYS over to the higher of them; a change
 	 * can only happen as a result of a clocking change which can
@@ -228,7 +228,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 
 	/* If they're equal it doesn't matter which is used */
 	if (wm8994->aifclk[0] == wm8994->aifclk[1]) {
-		wm8958_micd_set_rate(codec);
+		wm8958_micd_set_rate(component);
 		return 0;
 	}
 
@@ -237,12 +237,12 @@ static int configure_clock(struct snd_soc_codec *codec)
 	else
 		new = 0;
 
-	change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+	change = snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				     WM8994_SYSCLK_SRC, new);
 	if (change)
 		snd_soc_dapm_sync(dapm);
 
-	wm8958_micd_set_rate(codec);
+	wm8958_micd_set_rate(component);
 
 	return 0;
 }
@@ -250,8 +250,8 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
-	int reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	int reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	const char *clk;
 
 	/* Check what we're currently using for CLK_SYS */
@@ -300,7 +300,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
 {
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	int mask, ret;
 
 	/* Can't enable both ADC and DAC paths simultaneously */
@@ -310,7 +310,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
 	else
 		mask = WM8994_AIF1DAC1_DRC_ENA_MASK;
 
-	ret = snd_soc_read(codec, mc->reg);
+	ret = snd_soc_component_read32(component, mc->reg);
 	if (ret < 0)
 		return ret;
 	if (ret & mask)
@@ -319,9 +319,9 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
 	return snd_soc_put_volsw(kcontrol, ucontrol);
 }
 
-static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
+static void wm8994_set_drc(struct snd_soc_component *component, int drc)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int base = wm8994_drc_base[drc];
@@ -329,15 +329,15 @@ static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
 	int save, i;
 
 	/* Save any enables; the configuration should clear them. */
-	save = snd_soc_read(codec, base);
+	save = snd_soc_component_read32(component, base);
 	save &= WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
 		WM8994_AIF1ADC1R_DRC_ENA;
 
 	for (i = 0; i < WM8994_DRC_REGS; i++)
-		snd_soc_update_bits(codec, base + i, 0xffff,
+		snd_soc_component_update_bits(component, base + i, 0xffff,
 				    pdata->drc_cfgs[cfg].regs[i]);
 
-	snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_DRC_ENA |
+	snd_soc_component_update_bits(component, base, WM8994_AIF1DAC1_DRC_ENA |
 			     WM8994_AIF1ADC1L_DRC_ENA |
 			     WM8994_AIF1ADC1R_DRC_ENA, save);
 }
@@ -357,8 +357,8 @@ static int wm8994_get_drc(const char *name)
 static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int drc = wm8994_get_drc(kcontrol->id.name);
@@ -372,7 +372,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
 
 	wm8994->drc_cfg[drc] = value;
 
-	wm8994_set_drc(codec, drc);
+	wm8994_set_drc(component, drc);
 
 	return 0;
 }
@@ -380,8 +380,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
 static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int drc = wm8994_get_drc(kcontrol->id.name);
 
 	if (drc < 0)
@@ -391,9 +391,9 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
+static void wm8994_set_retune_mobile(struct snd_soc_component *component, int block)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int base = wm8994_retune_mobile_base[block];
@@ -430,7 +430,7 @@ static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
 		}
 	}
 
-	dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+	dev_dbg(component->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
 		block,
 		pdata->retune_mobile_cfgs[best].name,
 		pdata->retune_mobile_cfgs[best].rate,
@@ -439,14 +439,14 @@ static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
 	/* The EQ will be disabled while reconfiguring it, remember the
 	 * current configuration.
 	 */
-	save = snd_soc_read(codec, base);
+	save = snd_soc_component_read32(component, base);
 	save &= WM8994_AIF1DAC1_EQ_ENA;
 
 	for (i = 0; i < WM8994_EQ_REGS; i++)
-		snd_soc_update_bits(codec, base + i, 0xffff,
+		snd_soc_component_update_bits(component, base + i, 0xffff,
 				pdata->retune_mobile_cfgs[best].regs[i]);
 
-	snd_soc_update_bits(codec, base, WM8994_AIF1DAC1_EQ_ENA, save);
+	snd_soc_component_update_bits(component, base, WM8994_AIF1DAC1_EQ_ENA, save);
 }
 
 /* Icky as hell but saves code duplication */
@@ -464,8 +464,8 @@ static int wm8994_get_retune_mobile_block(const char *name)
 static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
@@ -479,7 +479,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 
 	wm8994->retune_mobile_cfg[block] = value;
 
-	wm8994_set_retune_mobile(codec, block);
+	wm8994_set_retune_mobile(component, block);
 
 	return 0;
 }
@@ -487,8 +487,8 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
 
 	if (block < 0)
@@ -740,9 +740,9 @@ SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
 };
 
 /* We run all mode setting through a function to enforce audio mode */
-static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
+static void wm1811_jackdet_set_mode(struct snd_soc_component *component, u16 mode)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (!wm8994->jackdet || !wm8994->micdet[0].jack)
 		return;
@@ -759,37 +759,37 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
 	if (mode != WM1811_JACKDET_MODE_NONE)
 		mode = WM1811_JACKDET_MODE_AUDIO;
 
-	snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+	snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 			    WM1811_JACKDET_MODE_MASK, mode);
 }
 
-static void active_reference(struct snd_soc_codec *codec)
+static void active_reference(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	mutex_lock(&wm8994->accdet_lock);
 
 	wm8994->active_refcount++;
 
-	dev_dbg(codec->dev, "Active refcount incremented, now %d\n",
+	dev_dbg(component->dev, "Active refcount incremented, now %d\n",
 		wm8994->active_refcount);
 
 	/* If we're using jack detection go into audio mode */
-	wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_AUDIO);
+	wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO);
 
 	mutex_unlock(&wm8994->accdet_lock);
 }
 
-static void active_dereference(struct snd_soc_codec *codec)
+static void active_dereference(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	u16 mode;
 
 	mutex_lock(&wm8994->accdet_lock);
 
 	wm8994->active_refcount--;
 
-	dev_dbg(codec->dev, "Active refcount decremented, now %d\n",
+	dev_dbg(component->dev, "Active refcount decremented, now %d\n",
 		wm8994->active_refcount);
 
 	if (wm8994->active_refcount == 0) {
@@ -799,7 +799,7 @@ static void active_dereference(struct snd_soc_codec *codec)
 		else
 			mode = WM1811_JACKDET_MODE_JACK;
 
-		wm1811_jackdet_set_mode(codec, mode);
+		wm1811_jackdet_set_mode(component, mode);
 	}
 
 	mutex_unlock(&wm8994->accdet_lock);
@@ -808,12 +808,12 @@ static void active_dereference(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		return configure_clock(codec);
+		return configure_clock(component);
 
 	case SND_SOC_DAPM_POST_PMU:
 		/*
@@ -832,30 +832,30 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		configure_clock(codec);
+		configure_clock(component);
 		break;
 	}
 
 	return 0;
 }
 
-static void vmid_reference(struct snd_soc_codec *codec)
+static void vmid_reference(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	wm8994->vmid_refcount++;
 
-	dev_dbg(codec->dev, "Referencing VMID, refcount is now %d\n",
+	dev_dbg(component->dev, "Referencing VMID, refcount is now %d\n",
 		wm8994->vmid_refcount);
 
 	if (wm8994->vmid_refcount == 1) {
-		snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
 				    WM8994_LINEOUT1_DISCH |
 				    WM8994_LINEOUT2_DISCH, 0);
 
-		wm_hubs_vmid_ena(codec);
+		wm_hubs_vmid_ena(component);
 
 		switch (wm8994->vmid_mode) {
 		default:
@@ -863,7 +863,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
 			/* fall through */
 		case WM8994_VMID_NORMAL:
 			/* Startup bias, VMID ramp & buffer */
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 					    WM8994_BIAS_SRC |
 					    WM8994_VMID_DISCH |
 					    WM8994_STARTUP_BIAS_ENA |
@@ -875,14 +875,14 @@ static void vmid_reference(struct snd_soc_codec *codec)
 					    (0x2 << WM8994_VMID_RAMP_SHIFT));
 
 			/* Main bias enable, VMID=2x40k */
-			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
 					    WM8994_BIAS_ENA |
 					    WM8994_VMID_SEL_MASK,
 					    WM8994_BIAS_ENA | 0x2);
 
 			msleep(300);
 
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 					    WM8994_VMID_RAMP_MASK |
 					    WM8994_BIAS_SRC,
 					    0);
@@ -890,7 +890,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
 
 		case WM8994_VMID_FORCE:
 			/* Startup bias, slow VMID ramp & buffer */
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 					    WM8994_BIAS_SRC |
 					    WM8994_VMID_DISCH |
 					    WM8994_STARTUP_BIAS_ENA |
@@ -902,14 +902,14 @@ static void vmid_reference(struct snd_soc_codec *codec)
 					    (0x2 << WM8994_VMID_RAMP_SHIFT));
 
 			/* Main bias enable, VMID=2x40k */
-			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
 					    WM8994_BIAS_ENA |
 					    WM8994_VMID_SEL_MASK,
 					    WM8994_BIAS_ENA | 0x2);
 
 			msleep(400);
 
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 					    WM8994_VMID_RAMP_MASK |
 					    WM8994_BIAS_SRC,
 					    0);
@@ -918,120 +918,120 @@ static void vmid_reference(struct snd_soc_codec *codec)
 	}
 }
 
-static void vmid_dereference(struct snd_soc_codec *codec)
+static void vmid_dereference(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	wm8994->vmid_refcount--;
 
-	dev_dbg(codec->dev, "Dereferencing VMID, refcount is now %d\n",
+	dev_dbg(component->dev, "Dereferencing VMID, refcount is now %d\n",
 		wm8994->vmid_refcount);
 
 	if (wm8994->vmid_refcount == 0) {
 		if (wm8994->hubs.lineout1_se)
-			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
 					    WM8994_LINEOUT1N_ENA |
 					    WM8994_LINEOUT1P_ENA,
 					    WM8994_LINEOUT1N_ENA |
 					    WM8994_LINEOUT1P_ENA);
 
 		if (wm8994->hubs.lineout2_se)
-			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
 					    WM8994_LINEOUT2N_ENA |
 					    WM8994_LINEOUT2P_ENA,
 					    WM8994_LINEOUT2N_ENA |
 					    WM8994_LINEOUT2P_ENA);
 
 		/* Start discharging VMID */
-		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 				    WM8994_BIAS_SRC |
 				    WM8994_VMID_DISCH,
 				    WM8994_BIAS_SRC |
 				    WM8994_VMID_DISCH);
 
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
 				    WM8994_VMID_SEL_MASK, 0);
 
 		msleep(400);
 
 		/* Active discharge */
-		snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
 				    WM8994_LINEOUT1_DISCH |
 				    WM8994_LINEOUT2_DISCH,
 				    WM8994_LINEOUT1_DISCH |
 				    WM8994_LINEOUT2_DISCH);
 
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
 				    WM8994_LINEOUT1N_ENA |
 				    WM8994_LINEOUT1P_ENA |
 				    WM8994_LINEOUT2N_ENA |
 				    WM8994_LINEOUT2P_ENA, 0);
 
 		/* Switch off startup biases */
-		snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
 				    WM8994_BIAS_SRC |
 				    WM8994_STARTUP_BIAS_ENA |
 				    WM8994_VMID_BUF_ENA |
 				    WM8994_VMID_RAMP_MASK, 0);
 
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
 				    WM8994_VMID_SEL_MASK, 0);
 	}
 
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 }
 
 static int vmid_event(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		vmid_reference(codec);
+		vmid_reference(component);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		vmid_dereference(codec);
+		vmid_dereference(component);
 		break;
 	}
 
 	return 0;
 }
 
-static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
+static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
 {
 	int source = 0;  /* GCC flow analysis can't track enable */
 	int reg, reg_r;
 
 	/* We also need the same AIF source for L/R and only one path */
-	reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
+	reg = snd_soc_component_read32(component, WM8994_DAC1_LEFT_MIXER_ROUTING);
 	switch (reg) {
 	case WM8994_AIF2DACL_TO_DAC1L:
-		dev_vdbg(codec->dev, "Class W source AIF2DAC\n");
+		dev_vdbg(component->dev, "Class W source AIF2DAC\n");
 		source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT;
 		break;
 	case WM8994_AIF1DAC2L_TO_DAC1L:
-		dev_vdbg(codec->dev, "Class W source AIF1DAC2\n");
+		dev_vdbg(component->dev, "Class W source AIF1DAC2\n");
 		source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT;
 		break;
 	case WM8994_AIF1DAC1L_TO_DAC1L:
-		dev_vdbg(codec->dev, "Class W source AIF1DAC1\n");
+		dev_vdbg(component->dev, "Class W source AIF1DAC1\n");
 		source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT;
 		break;
 	default:
-		dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
+		dev_vdbg(component->dev, "DAC mixer setting: %x\n", reg);
 		return false;
 	}
 
-	reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
+	reg_r = snd_soc_component_read32(component, WM8994_DAC1_RIGHT_MIXER_ROUTING);
 	if (reg_r != reg) {
-		dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
+		dev_vdbg(component->dev, "Left and right DAC mixers different\n");
 		return false;
 	}
 
 	/* Set the source up */
-	snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+	snd_soc_component_update_bits(component, WM8994_CLASS_W_1,
 			    WM8994_CP_DYN_SRC_SEL_MASK, source);
 
 	return true;
@@ -1040,8 +1040,8 @@ static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
 	int i;
@@ -1064,7 +1064,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 		if (wm8994->channels[0] <= 2)
 			mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
 
-		val = snd_soc_read(codec, WM8994_AIF1_CONTROL_1);
+		val = snd_soc_component_read32(component, WM8994_AIF1_CONTROL_1);
 		if ((val & WM8994_AIF1ADCL_SRC) &&
 		    (val & WM8994_AIF1ADCR_SRC))
 			adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA;
@@ -1075,7 +1075,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 			adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA |
 				WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;
 
-		val = snd_soc_read(codec, WM8994_AIF1_CONTROL_2);
+		val = snd_soc_component_read32(component, WM8994_AIF1_CONTROL_2);
 		if ((val & WM8994_AIF1DACL_SRC) &&
 		    (val & WM8994_AIF1DACR_SRC))
 			dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA;
@@ -1086,21 +1086,21 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 			dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA |
 				WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;
 
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
 				    mask, adc);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
 				    mask, dac);
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				    WM8994_AIF1DSPCLK_ENA |
 				    WM8994_SYSDSPCLK_ENA,
 				    WM8994_AIF1DSPCLK_ENA |
 				    WM8994_SYSDSPCLK_ENA);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4, mask,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4, mask,
 				    WM8994_AIF1ADC1R_ENA |
 				    WM8994_AIF1ADC1L_ENA |
 				    WM8994_AIF1ADC2R_ENA |
 				    WM8994_AIF1ADC2L_ENA);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, mask,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5, mask,
 				    WM8994_AIF1DAC1R_ENA |
 				    WM8994_AIF1DAC1L_ENA |
 				    WM8994_AIF1DAC2R_ENA |
@@ -1109,24 +1109,24 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 
 	case SND_SOC_DAPM_POST_PMU:
 		for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
-			snd_soc_write(codec, wm8994_vu_bits[i].reg,
-				      snd_soc_read(codec,
+			snd_soc_component_write(component, wm8994_vu_bits[i].reg,
+				      snd_soc_component_read32(component,
 						   wm8994_vu_bits[i].reg));
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
 				    mask, 0);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
 				    mask, 0);
 
-		val = snd_soc_read(codec, WM8994_CLOCKING_1);
+		val = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 		if (val & WM8994_AIF2DSPCLK_ENA)
 			val = WM8994_SYSDSPCLK_ENA;
 		else
 			val = 0;
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				    WM8994_SYSDSPCLK_ENA |
 				    WM8994_AIF1DSPCLK_ENA, val);
 		break;
@@ -1138,7 +1138,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int i;
 	int dac;
 	int adc;
@@ -1146,7 +1146,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		val = snd_soc_read(codec, WM8994_AIF2_CONTROL_1);
+		val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_1);
 		if ((val & WM8994_AIF2ADCL_SRC) &&
 		    (val & WM8994_AIF2ADCR_SRC))
 			adc = WM8994_AIF2ADCR_ENA;
@@ -1157,7 +1157,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 			adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA;
 
 
-		val = snd_soc_read(codec, WM8994_AIF2_CONTROL_2);
+		val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_2);
 		if ((val & WM8994_AIF2DACL_SRC) &&
 		    (val & WM8994_AIF2DACR_SRC))
 			dac = WM8994_AIF2DACR_ENA;
@@ -1167,23 +1167,23 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 		else
 			dac = WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA;
 
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
 				    WM8994_AIF2ADCL_ENA |
 				    WM8994_AIF2ADCR_ENA, adc);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
 				    WM8994_AIF2DACL_ENA |
 				    WM8994_AIF2DACR_ENA, dac);
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				    WM8994_AIF2DSPCLK_ENA |
 				    WM8994_SYSDSPCLK_ENA,
 				    WM8994_AIF2DSPCLK_ENA |
 				    WM8994_SYSDSPCLK_ENA);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
 				    WM8994_AIF2ADCL_ENA |
 				    WM8994_AIF2ADCR_ENA,
 				    WM8994_AIF2ADCL_ENA |
 				    WM8994_AIF2ADCR_ENA);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
 				    WM8994_AIF2DACL_ENA |
 				    WM8994_AIF2DACR_ENA,
 				    WM8994_AIF2DACL_ENA |
@@ -1192,26 +1192,26 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 
 	case SND_SOC_DAPM_POST_PMU:
 		for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
-			snd_soc_write(codec, wm8994_vu_bits[i].reg,
-				      snd_soc_read(codec,
+			snd_soc_component_write(component, wm8994_vu_bits[i].reg,
+				      snd_soc_component_read32(component,
 						   wm8994_vu_bits[i].reg));
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
 				    WM8994_AIF2DACL_ENA |
 				    WM8994_AIF2DACR_ENA, 0);
-		snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4,
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
 				    WM8994_AIF2ADCL_ENA |
 				    WM8994_AIF2ADCR_ENA, 0);
 
-		val = snd_soc_read(codec, WM8994_CLOCKING_1);
+		val = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 		if (val & WM8994_AIF1DSPCLK_ENA)
 			val = WM8994_SYSDSPCLK_ENA;
 		else
 			val = 0;
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
 				    WM8994_SYSDSPCLK_ENA |
 				    WM8994_AIF2DSPCLK_ENA, val);
 		break;
@@ -1223,8 +1223,8 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1241,8 +1241,8 @@ static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1259,14 +1259,14 @@ static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
 static int late_enable_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		if (wm8994->aif1clk_enable) {
 			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU);
-			snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
+			snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1,
 					    WM8994_AIF1CLK_ENA_MASK,
 					    WM8994_AIF1CLK_ENA);
 			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU);
@@ -1274,7 +1274,7 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 		}
 		if (wm8994->aif2clk_enable) {
 			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU);
-			snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
+			snd_soc_component_update_bits(component, WM8994_AIF2_CLOCKING_1,
 					    WM8994_AIF2CLK_ENA_MASK,
 					    WM8994_AIF2CLK_ENA);
 			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU);
@@ -1292,21 +1292,21 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 static int late_disable_ev(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
 		if (wm8994->aif1clk_disable) {
 			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
-			snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
+			snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1,
 					    WM8994_AIF1CLK_ENA_MASK, 0);
 			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD);
 			wm8994->aif1clk_disable = 0;
 		}
 		if (wm8994->aif2clk_disable) {
 			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
-			snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
+			snd_soc_component_update_bits(component, WM8994_AIF2_CLOCKING_1,
 					    WM8994_AIF2CLK_ENA_MASK, 0);
 			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD);
 			wm8994->aif2clk_disable = 0;
@@ -1334,10 +1334,10 @@ static int micbias_ev(struct snd_soc_dapm_widget *w,
 static int dac_ev(struct snd_soc_dapm_widget *w,
 		  struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int mask = 1 << w->shift;
 
-	snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+	snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
 			    mask, mask);
 	return 0;
 }
@@ -1375,9 +1375,9 @@ SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
 static int post_ev(struct snd_soc_dapm_widget *w,
 	    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	dev_dbg(codec->dev, "SRC status: %x\n",
-		snd_soc_read(codec,
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	dev_dbg(component->dev, "SRC status: %x\n",
+		snd_soc_component_read32(component,
 			     WM8994_RATE_STATUS));
 	return 0;
 }
@@ -1443,12 +1443,12 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 
-	wm_hubs_update_class_w(codec);
+	wm_hubs_update_class_w(component);
 
 	return ret;
 }
@@ -2130,10 +2130,10 @@ static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
 	return 0;
 }
 
-static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
+static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
 			  unsigned int freq_in, unsigned int freq_out)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int reg_offset, ret;
 	struct fll_div fll;
@@ -2156,7 +2156,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 		return -EINVAL;
 	}
 
-	reg = snd_soc_read(codec, WM8994_FLL1_CONTROL_1 + reg_offset);
+	reg = snd_soc_component_read32(component, WM8994_FLL1_CONTROL_1 + reg_offset);
 	was_enabled = reg & WM8994_FLL1_ENA;
 
 	switch (src) {
@@ -2197,57 +2197,57 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 		return ret;
 
 	/* Make sure that we're not providing SYSCLK right now */
-	clk1 = snd_soc_read(codec, WM8994_CLOCKING_1);
+	clk1 = snd_soc_component_read32(component, WM8994_CLOCKING_1);
 	if (clk1 & WM8994_SYSCLK_SRC)
 		aif_reg = WM8994_AIF2_CLOCKING_1;
 	else
 		aif_reg = WM8994_AIF1_CLOCKING_1;
-	reg = snd_soc_read(codec, aif_reg);
+	reg = snd_soc_component_read32(component, aif_reg);
 
 	if ((reg & WM8994_AIF1CLK_ENA) &&
 	    (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
-		dev_err(codec->dev, "FLL%d is currently providing SYSCLK\n",
+		dev_err(component->dev, "FLL%d is currently providing SYSCLK\n",
 			id + 1);
 		return -EBUSY;
 	}
 
 	/* We always need to disable the FLL while reconfiguring */
-	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_1 + reg_offset,
 			    WM8994_FLL1_ENA, 0);
 
 	if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
 	    freq_in == freq_out && freq_out) {
-		dev_dbg(codec->dev, "Bypassing FLL%d\n", id + 1);
-		snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+		dev_dbg(component->dev, "Bypassing FLL%d\n", id + 1);
+		snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_5 + reg_offset,
 				    WM8958_FLL1_BYP, WM8958_FLL1_BYP);
 		goto out;
 	}
 
 	reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
 		(fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
-	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset,
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_2 + reg_offset,
 			    WM8994_FLL1_OUTDIV_MASK |
 			    WM8994_FLL1_FRATIO_MASK, reg);
 
-	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_3 + reg_offset,
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_3 + reg_offset,
 			    WM8994_FLL1_K_MASK, fll.k);
 
-	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_4 + reg_offset,
 			    WM8994_FLL1_N_MASK,
 			    fll.n << WM8994_FLL1_N_SHIFT);
 
 	if (fll.lambda) {
-		snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset,
+		snd_soc_component_update_bits(component, WM8958_FLL1_EFS_1 + reg_offset,
 				    WM8958_FLL1_LAMBDA_MASK,
 				    fll.lambda);
-		snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+		snd_soc_component_update_bits(component, WM8958_FLL1_EFS_2 + reg_offset,
 				    WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA);
 	} else {
-		snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+		snd_soc_component_update_bits(component, WM8958_FLL1_EFS_2 + reg_offset,
 				    WM8958_FLL1_EFS_ENA, 0);
 	}
 
-	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_5 + reg_offset,
 			    WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
 			    WM8994_FLL1_REFCLK_DIV_MASK |
 			    WM8994_FLL1_REFCLK_SRC_MASK,
@@ -2263,15 +2263,15 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 	if (freq_out) {
 		/* Enable VMID if we need it */
 		if (!was_enabled) {
-			active_reference(codec);
+			active_reference(component);
 
 			switch (control->type) {
 			case WM8994:
-				vmid_reference(codec);
+				vmid_reference(component);
 				break;
 			case WM8958:
 				if (control->revision < 1)
-					vmid_reference(codec);
+					vmid_reference(component);
 				break;
 			default:
 				break;
@@ -2285,7 +2285,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 		if (src == WM8994_FLL_SRC_INTERNAL)
 			reg |= WM8994_FLL1_OSC_ENA;
 
-		snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
+		snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_1 + reg_offset,
 				    WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA |
 				    WM8994_FLL1_FRAC, reg);
 
@@ -2293,7 +2293,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 			timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
 							      msecs_to_jiffies(10));
 			if (timeout == 0)
-				dev_warn(codec->dev,
+				dev_warn(component->dev,
 					 "Timed out waiting for FLL lock\n");
 		} else {
 			msleep(5);
@@ -2302,17 +2302,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 		if (was_enabled) {
 			switch (control->type) {
 			case WM8994:
-				vmid_dereference(codec);
+				vmid_dereference(component);
 				break;
 			case WM8958:
 				if (control->revision < 1)
-					vmid_dereference(codec);
+					vmid_dereference(component);
 				break;
 			default:
 				break;
 			}
 
-			active_dereference(codec);
+			active_dereference(component);
 		}
 	}
 
@@ -2321,29 +2321,29 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 	wm8994->fll[id].out = freq_out;
 	wm8994->fll[id].src = src;
 
-	configure_clock(codec);
+	configure_clock(component);
 
 	/*
 	 * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
 	 * for detection.
 	 */
 	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
-		dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+		dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
 
-		wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+		wm8994->aifdiv[0] = snd_soc_component_read32(component, WM8994_AIF1_RATE)
 			& WM8994_AIF1CLK_RATE_MASK;
-		wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+		wm8994->aifdiv[1] = snd_soc_component_read32(component, WM8994_AIF2_RATE)
 			& WM8994_AIF1CLK_RATE_MASK;
 
-		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
 				    WM8994_AIF1CLK_RATE_MASK, 0x1);
-		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
 				    WM8994_AIF2CLK_RATE_MASK, 0x1);
 	} else if (wm8994->aifdiv[0]) {
-		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
 				    WM8994_AIF1CLK_RATE_MASK,
 				    wm8994->aifdiv[0]);
-		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
 				    WM8994_AIF2CLK_RATE_MASK,
 				    wm8994->aifdiv[1]);
 
@@ -2368,14 +2368,14 @@ static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
 static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
 			  unsigned int freq_in, unsigned int freq_out)
 {
-	return _wm8994_set_fll(dai->codec, id, src, freq_in, freq_out);
+	return _wm8994_set_fll(dai->component, id, src, freq_in, freq_out);
 }
 
 static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int i;
 
 	switch (dai->id) {
@@ -2424,12 +2424,12 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 					break;
 			if (i == ARRAY_SIZE(opclk_divs))
 				return -EINVAL;
-			snd_soc_update_bits(codec, WM8994_CLOCKING_2,
+			snd_soc_component_update_bits(component, WM8994_CLOCKING_2,
 					    WM8994_OPCLK_DIV_MASK, i);
-			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
 					    WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
 		} else {
-			snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
 					    WM8994_OPCLK_ENA, 0);
 		}
 
@@ -2437,29 +2437,29 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	configure_clock(codec);
+	configure_clock(component);
 
 	/*
 	 * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
 	 * for detection.
 	 */
 	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
-		dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+		dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
 
-		wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+		wm8994->aifdiv[0] = snd_soc_component_read32(component, WM8994_AIF1_RATE)
 			& WM8994_AIF1CLK_RATE_MASK;
-		wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+		wm8994->aifdiv[1] = snd_soc_component_read32(component, WM8994_AIF2_RATE)
 			& WM8994_AIF1CLK_RATE_MASK;
 
-		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
 				    WM8994_AIF1CLK_RATE_MASK, 0x1);
-		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
 				    WM8994_AIF2CLK_RATE_MASK, 0x1);
 	} else if (wm8994->aifdiv[0]) {
-		snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
 				    WM8994_AIF1CLK_RATE_MASK,
 				    wm8994->aifdiv[0]);
-		snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
 				    WM8994_AIF2CLK_RATE_MASK,
 				    wm8994->aifdiv[1]);
 
@@ -2470,13 +2470,13 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
-static int wm8994_set_bias_level(struct snd_soc_codec *codec,
+static int wm8994_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 
-	wm_hubs_set_bias_level(codec, level);
+	wm_hubs_set_bias_level(component, level);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -2487,26 +2487,26 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 		switch (control->type) {
 		case WM8958:
 		case WM1811:
-			snd_soc_update_bits(codec, WM8958_MICBIAS1,
+			snd_soc_component_update_bits(component, WM8958_MICBIAS1,
 					    WM8958_MICB1_MODE, 0);
-			snd_soc_update_bits(codec, WM8958_MICBIAS2,
+			snd_soc_component_update_bits(component, WM8958_MICBIAS2,
 					    WM8958_MICB2_MODE, 0);
 			break;
 		default:
 			break;
 		}
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
-			active_reference(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			active_reference(component);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			switch (control->type) {
 			case WM8958:
 				if (control->revision == 0) {
 					/* Optimise performance for rev A */
-					snd_soc_update_bits(codec,
+					snd_soc_component_update_bits(component,
 							    WM8958_CHARGE_PUMP_2,
 							    WM8958_CP_DISCH,
 							    WM8958_CP_DISCH);
@@ -2518,24 +2518,24 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 			}
 
 			/* Discharge LINEOUT1 & 2 */
-			snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
 					    WM8994_LINEOUT1_DISCH |
 					    WM8994_LINEOUT2_DISCH,
 					    WM8994_LINEOUT1_DISCH |
 					    WM8994_LINEOUT2_DISCH);
 		}
 
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
-			active_dereference(codec);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
+			active_dereference(component);
 
 		/* MICBIAS into bypass mode on newer devices */
 		switch (control->type) {
 		case WM8958:
 		case WM1811:
-			snd_soc_update_bits(codec, WM8958_MICBIAS1,
+			snd_soc_component_update_bits(component, WM8958_MICBIAS1,
 					    WM8958_MICB1_MODE,
 					    WM8958_MICB1_MODE);
-			snd_soc_update_bits(codec, WM8958_MICBIAS2,
+			snd_soc_component_update_bits(component, WM8958_MICBIAS2,
 					    WM8958_MICB2_MODE,
 					    WM8958_MICB2_MODE);
 			break;
@@ -2545,7 +2545,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_OFF:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
 			wm8994->cur_fw = NULL;
 		break;
 	}
@@ -2553,10 +2553,10 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
+int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	switch (mode) {
 	case WM8994_VMID_NORMAL:
@@ -2613,8 +2613,8 @@ int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
 
 static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int ms_reg;
 	int aif1_reg;
@@ -2717,7 +2717,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	case WM1811:
 	case WM8958:
 		if (dai->id == 2)
-			snd_soc_update_bits(codec, WM8958_AIF3_CONTROL_1,
+			snd_soc_component_update_bits(component, WM8958_AIF3_CONTROL_1,
 					    WM8994_AIF1_LRCLK_INV |
 					    WM8958_AIF3_FMT_MASK, aif1);
 		break;
@@ -2726,15 +2726,15 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		break;
 	}
 
-	snd_soc_update_bits(codec, aif1_reg,
+	snd_soc_component_update_bits(component, aif1_reg,
 			    WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV |
 			    WM8994_AIF1_FMT_MASK,
 			    aif1);
-	snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR,
+	snd_soc_component_update_bits(component, ms_reg, WM8994_AIF1_MSTR,
 			    ms);
-	snd_soc_update_bits(codec, dac_reg,
+	snd_soc_component_update_bits(component, dac_reg,
 			    WM8958_AIF1_LRCLK_INV, lrclk);
-	snd_soc_update_bits(codec, adc_reg,
+	snd_soc_component_update_bits(component, adc_reg,
 			    WM8958_AIF1_LRCLK_INV, lrclk);
 
 	return 0;
@@ -2769,8 +2769,8 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int aif1_reg;
@@ -2798,7 +2798,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 			lrclk_reg = WM8994_AIF1DAC_LRCLK;
 		} else {
 			lrclk_reg = WM8994_AIF1ADC_LRCLK;
-			dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+			dev_dbg(component->dev, "AIF1 using split LRCLK\n");
 		}
 		break;
 	case 2:
@@ -2811,7 +2811,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 			lrclk_reg = WM8994_AIF2DAC_LRCLK;
 		} else {
 			lrclk_reg = WM8994_AIF2ADC_LRCLK;
-			dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+			dev_dbg(component->dev, "AIF2 using split LRCLK\n");
 		}
 		break;
 	default:
@@ -2870,7 +2870,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 		dai->id, wm8994->aifclk[id], bclk_rate);
 
 	if (wm8994->channels[id] == 1 &&
-	    (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
+	    (snd_soc_component_read32(component, aif1_reg) & 0x18) == 0x18)
 		aif2 |= WM8994_AIF1_MONO;
 
 	if (wm8994->aifclk[id] == 0) {
@@ -2920,24 +2920,24 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
 		lrclk, bclk_rate / lrclk);
 
-	snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
-	snd_soc_update_bits(codec, aif2_reg, WM8994_AIF1_MONO, aif2);
-	snd_soc_update_bits(codec, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
-	snd_soc_update_bits(codec, lrclk_reg, WM8994_AIF1DAC_RATE_MASK,
+	snd_soc_component_update_bits(component, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+	snd_soc_component_update_bits(component, aif2_reg, WM8994_AIF1_MONO, aif2);
+	snd_soc_component_update_bits(component, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
+	snd_soc_component_update_bits(component, lrclk_reg, WM8994_AIF1DAC_RATE_MASK,
 			    lrclk);
-	snd_soc_update_bits(codec, rate_reg, WM8994_AIF1_SR_MASK |
+	snd_soc_component_update_bits(component, rate_reg, WM8994_AIF1_SR_MASK |
 			    WM8994_AIF1CLK_RATE_MASK, rate_val);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		switch (dai->id) {
 		case 1:
 			wm8994->dac_rates[0] = params_rate(params);
-			wm8994_set_retune_mobile(codec, 0);
-			wm8994_set_retune_mobile(codec, 1);
+			wm8994_set_retune_mobile(component, 0);
+			wm8994_set_retune_mobile(component, 1);
 			break;
 		case 2:
 			wm8994->dac_rates[1] = params_rate(params);
-			wm8994_set_retune_mobile(codec, 2);
+			wm8994_set_retune_mobile(component, 2);
 			break;
 		}
 	}
@@ -2949,8 +2949,8 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int aif1_reg;
 	int aif1 = 0;
@@ -2986,12 +2986,12 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+	return snd_soc_component_update_bits(component, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
 }
 
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int mute_reg;
 	int reg;
 
@@ -3011,14 +3011,14 @@ static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 	else
 		reg = 0;
 
-	snd_soc_update_bits(codec, mute_reg, WM8994_AIF1DAC1_MUTE, reg);
+	snd_soc_component_update_bits(component, mute_reg, WM8994_AIF1DAC1_MUTE, reg);
 
 	return 0;
 }
 
 static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int reg, val, mask;
 
 	switch (codec_dai->id) {
@@ -3039,19 +3039,19 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
 	else
 		val = 0;
 
-	return snd_soc_update_bits(codec, reg, mask, val);
+	return snd_soc_component_update_bits(component, reg, mask, val);
 }
 
 static int wm8994_aif2_probe(struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	/* Disable the pulls on the AIF if we're using it to save power. */
-	snd_soc_update_bits(codec, WM8994_GPIO_3,
+	snd_soc_component_update_bits(component, WM8994_GPIO_3,
 			    WM8994_GPN_PU | WM8994_GPN_PD, 0);
-	snd_soc_update_bits(codec, WM8994_GPIO_4,
+	snd_soc_component_update_bits(component, WM8994_GPIO_4,
 			    WM8994_GPN_PU | WM8994_GPN_PD, 0);
-	snd_soc_update_bits(codec, WM8994_GPIO_5,
+	snd_soc_component_update_bits(component, WM8994_GPIO_5,
 			    WM8994_GPN_PU | WM8994_GPN_PD, 0);
 
 	return 0;
@@ -3152,53 +3152,53 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
 };
 
 #ifdef CONFIG_PM
-static int wm8994_codec_suspend(struct snd_soc_codec *codec)
+static int wm8994_component_suspend(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int i, ret;
 
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
 		memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
 		       sizeof(struct wm8994_fll_config));
-		ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
+		ret = _wm8994_set_fll(component, i + 1, 0, 0, 0);
 		if (ret < 0)
-			dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
+			dev_warn(component->dev, "Failed to stop FLL%d: %d\n",
 				 i + 1, ret);
 	}
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
 
-static int wm8994_codec_resume(struct snd_soc_codec *codec)
+static int wm8994_component_resume(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int i, ret;
 
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
 		if (!wm8994->fll_suspend[i].out)
 			continue;
 
-		ret = _wm8994_set_fll(codec, i + 1,
+		ret = _wm8994_set_fll(component, i + 1,
 				     wm8994->fll_suspend[i].src,
 				     wm8994->fll_suspend[i].in,
 				     wm8994->fll_suspend[i].out);
 		if (ret < 0)
-			dev_warn(codec->dev, "Failed to restore FLL%d: %d\n",
+			dev_warn(component->dev, "Failed to restore FLL%d: %d\n",
 				 i + 1, ret);
 	}
 
 	return 0;
 }
 #else
-#define wm8994_codec_suspend NULL
-#define wm8994_codec_resume NULL
+#define wm8994_component_suspend NULL
+#define wm8994_component_resume NULL
 #endif
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 {
-	struct snd_soc_codec *codec = wm8994->hubs.codec;
+	struct snd_soc_component *component = wm8994->hubs.component;
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	struct snd_kcontrol_new controls[] = {
@@ -3251,22 +3251,22 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 		wm8994->retune_mobile_texts = t;
 	}
 
-	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+	dev_dbg(component->dev, "Allocated %d unique ReTune Mobile names\n",
 		wm8994->num_retune_mobile_texts);
 
 	wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts;
 	wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-	ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
+	ret = snd_soc_add_component_controls(wm8994->hubs.component, controls,
 				   ARRAY_SIZE(controls));
 	if (ret != 0)
-		dev_err(wm8994->hubs.codec->dev,
+		dev_err(wm8994->hubs.component->dev,
 			"Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
 static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 {
-	struct snd_soc_codec *codec = wm8994->hubs.codec;
+	struct snd_soc_component *component = wm8994->hubs.component;
 	struct wm8994 *control = wm8994->wm8994;
 	struct wm8994_pdata *pdata = &control->pdata;
 	int ret, i;
@@ -3274,7 +3274,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 	if (!pdata)
 		return;
 
-	wm_hubs_handle_analogue_pdata(codec, pdata->lineout1_diff,
+	wm_hubs_handle_analogue_pdata(component, pdata->lineout1_diff,
 				      pdata->lineout2_diff,
 				      pdata->lineout1fb,
 				      pdata->lineout2fb,
@@ -3285,7 +3285,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 				      pdata->micbias1_lvl,
 				      pdata->micbias2_lvl);
 
-	dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+	dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
 
 	if (pdata->num_drc_cfgs) {
 		struct snd_kcontrol_new controls[] = {
@@ -3298,7 +3298,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 		};
 
 		/* We need an array of texts for the enum API */
-		wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev,
+		wm8994->drc_texts = devm_kzalloc(wm8994->hubs.component->dev,
 			    sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL);
 		if (!wm8994->drc_texts)
 			return;
@@ -3309,33 +3309,33 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 		wm8994->drc_enum.items = pdata->num_drc_cfgs;
 		wm8994->drc_enum.texts = wm8994->drc_texts;
 
-		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
+		ret = snd_soc_add_component_controls(wm8994->hubs.component, controls,
 					   ARRAY_SIZE(controls));
 		for (i = 0; i < WM8994_NUM_DRC; i++)
-			wm8994_set_drc(codec, i);
+			wm8994_set_drc(component, i);
 	} else {
-		ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
 						 wm8994_drc_controls,
 						 ARRAY_SIZE(wm8994_drc_controls));
 	}
 
 	if (ret != 0)
-		dev_err(wm8994->hubs.codec->dev,
+		dev_err(wm8994->hubs.component->dev,
 			"Failed to add DRC mode controls: %d\n", ret);
 
 
-	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
+	dev_dbg(component->dev, "%d ReTune Mobile configurations\n",
 		pdata->num_retune_mobile_cfgs);
 
 	if (pdata->num_retune_mobile_cfgs)
 		wm8994_handle_retune_mobile_pdata(wm8994);
 	else
-		snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls,
+		snd_soc_add_component_controls(wm8994->hubs.component, wm8994_eq_controls,
 				     ARRAY_SIZE(wm8994_eq_controls));
 
 	for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
 		if (pdata->micbias[i]) {
-			snd_soc_write(codec, WM8958_MICBIAS1 + i,
+			snd_soc_component_write(component, WM8958_MICBIAS1 + i,
 				pdata->micbias[i] & 0xffff);
 		}
 	}
@@ -3344,7 +3344,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 /**
  * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
  *
- * @codec:   WM8994 codec
+ * @component:   WM8994 component
  * @jack:    jack to report detection events on
  * @micbias: microphone bias to detect on
  *
@@ -3356,17 +3356,17 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
  * Configuration of detection levels is available via the micbias1_lvl
  * and micbias2_lvl platform data members.
  */
-int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		      int micbias)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994_micdet *micdet;
 	struct wm8994 *control = wm8994->wm8994;
 	int reg, ret;
 
 	if (control->type != WM8994) {
-		dev_warn(codec->dev, "Not a WM8994\n");
+		dev_warn(component->dev, "Not a WM8994\n");
 		return -EINVAL;
 	}
 
@@ -3386,15 +3386,15 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 			ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
 		break;
 	default:
-		dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias);
+		dev_warn(component->dev, "Invalid MICBIAS %d\n", micbias);
 		return -EINVAL;
 	}
 
 	if (ret != 0)
-		dev_warn(codec->dev, "Failed to configure MICBIAS%d: %d\n",
+		dev_warn(component->dev, "Failed to configure MICBIAS%d: %d\n",
 			 micbias, ret);
 
-	dev_dbg(codec->dev, "Configuring microphone detection on %d %p\n",
+	dev_dbg(component->dev, "Configuring microphone detection on %d %p\n",
 		micbias, jack);
 
 	/* Store the configuration */
@@ -3407,10 +3407,10 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 	else
 		reg = 0;
 
-	snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
+	snd_soc_component_update_bits(component, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
 
 	/* enable MICDET and MICSHRT deboune */
-	snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE,
+	snd_soc_component_update_bits(component, WM8994_IRQ_DEBOUNCE,
 			    WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK |
 			    WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
 			    WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
@@ -3488,13 +3488,13 @@ static void wm8994_mic_work(struct work_struct *work)
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
 {
 	struct wm8994_priv *priv = data;
-	struct snd_soc_codec *codec = priv->hubs.codec;
+	struct snd_soc_component *component = priv->hubs.component;
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
-	trace_snd_soc_jack_irq(dev_name(codec->dev));
+	trace_snd_soc_jack_irq(dev_name(component->dev));
 #endif
 
-	pm_wakeup_event(codec->dev, 300);
+	pm_wakeup_event(component->dev, 300);
 
 	queue_delayed_work(system_power_efficient_wq,
 			   &priv->mic_work, msecs_to_jiffies(250));
@@ -3503,25 +3503,25 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
 }
 
 /* Should be called with accdet_lock held */
-static void wm1811_micd_stop(struct snd_soc_codec *codec)
+static void wm1811_micd_stop(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	if (!wm8994->jackdet)
 		return;
 
-	snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0);
+	snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0);
 
-	wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
+	wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_JACK);
 
 	if (wm8994->wm8994->pdata.jd_ext_cap)
 		snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
 }
 
-static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
+static void wm8958_button_det(struct snd_soc_component *component, u16 status)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	int report;
 
 	report = 0;
@@ -3556,14 +3556,14 @@ static void wm8958_open_circuit_work(struct work_struct *work)
 
 	mutex_lock(&wm8994->accdet_lock);
 
-	wm1811_micd_stop(wm8994->hubs.codec);
+	wm1811_micd_stop(wm8994->hubs.component);
 
 	dev_dbg(dev, "Reporting open circuit\n");
 
 	wm8994->jack_mic = false;
 	wm8994->mic_detecting = true;
 
-	wm8958_micd_set_rate(wm8994->hubs.codec);
+	wm8958_micd_set_rate(wm8994->hubs.component);
 
 	snd_soc_jack_report(wm8994->micdet[0].jack, 0,
 			    wm8994->btn_mask |
@@ -3574,13 +3574,13 @@ static void wm8958_open_circuit_work(struct work_struct *work)
 
 static void wm8958_mic_id(void *data, u16 status)
 {
-	struct snd_soc_codec *codec = data;
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = data;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 
 	/* Either nothing present or just starting detection */
 	if (!(status & WM8958_MICD_STS)) {
 		/* If nothing present then clear our statuses */
-		dev_dbg(codec->dev, "Detected open circuit\n");
+		dev_dbg(component->dev, "Detected open circuit\n");
 
 		queue_delayed_work(system_power_efficient_wq,
 				   &wm8994->open_circuit_work,
@@ -3592,12 +3592,12 @@ static void wm8958_mic_id(void *data, u16 status)
 	 * microphone.
 	 */
 	if (status & 0x600) {
-		dev_dbg(codec->dev, "Detected microphone\n");
+		dev_dbg(component->dev, "Detected microphone\n");
 
 		wm8994->mic_detecting = false;
 		wm8994->jack_mic = true;
 
-		wm8958_micd_set_rate(codec);
+		wm8958_micd_set_rate(component);
 
 		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADSET,
 				    SND_JACK_HEADSET);
@@ -3605,13 +3605,13 @@ static void wm8958_mic_id(void *data, u16 status)
 
 
 	if (status & 0xfc) {
-		dev_dbg(codec->dev, "Detected headphone\n");
+		dev_dbg(component->dev, "Detected headphone\n");
 		wm8994->mic_detecting = false;
 
-		wm8958_micd_set_rate(codec);
+		wm8958_micd_set_rate(component);
 
 		/* If we have jackdet that will detect removal */
-		wm1811_micd_stop(codec);
+		wm1811_micd_stop(component);
 
 		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
 				    SND_JACK_HEADSET);
@@ -3624,10 +3624,10 @@ static void wm1811_mic_work(struct work_struct *work)
 	struct wm8994_priv *wm8994 = container_of(work, struct wm8994_priv,
 						  mic_work.work);
 	struct wm8994 *control = wm8994->wm8994;
-	struct snd_soc_codec *codec = wm8994->hubs.codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = wm8994->hubs.component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	/* If required for an external cap force MICBIAS on */
 	if (control->pdata.jd_ext_cap) {
@@ -3637,7 +3637,7 @@ static void wm1811_mic_work(struct work_struct *work)
 
 	mutex_lock(&wm8994->accdet_lock);
 
-	dev_dbg(codec->dev, "Starting mic detection\n");
+	dev_dbg(component->dev, "Starting mic detection\n");
 
 	/* Use a user-supplied callback if we have one */
 	if (wm8994->micd_cb) {
@@ -3648,54 +3648,54 @@ static void wm1811_mic_work(struct work_struct *work)
 		 * what's actually there.
 		 */
 		wm8994->mic_detecting = true;
-		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
+		wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_MIC);
 
-		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, WM8958_MICD_ENA);
 	}
 
 	mutex_unlock(&wm8994->accdet_lock);
 
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 }
 
 static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 {
 	struct wm8994_priv *wm8994 = data;
 	struct wm8994 *control = wm8994->wm8994;
-	struct snd_soc_codec *codec = wm8994->hubs.codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = wm8994->hubs.component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int reg, delay;
 	bool present;
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	cancel_delayed_work_sync(&wm8994->mic_complete_work);
 
 	mutex_lock(&wm8994->accdet_lock);
 
-	reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
+	reg = snd_soc_component_read32(component, WM1811_JACKDET_CTRL);
 	if (reg < 0) {
-		dev_err(codec->dev, "Failed to read jack status: %d\n", reg);
+		dev_err(component->dev, "Failed to read jack status: %d\n", reg);
 		mutex_unlock(&wm8994->accdet_lock);
-		pm_runtime_put(codec->dev);
+		pm_runtime_put(component->dev);
 		return IRQ_NONE;
 	}
 
-	dev_dbg(codec->dev, "JACKDET %x\n", reg);
+	dev_dbg(component->dev, "JACKDET %x\n", reg);
 
 	present = reg & WM1811_JACKDET_LVL;
 
 	if (present) {
-		dev_dbg(codec->dev, "Jack detected\n");
+		dev_dbg(component->dev, "Jack detected\n");
 
-		wm8958_micd_set_rate(codec);
+		wm8958_micd_set_rate(component);
 
-		snd_soc_update_bits(codec, WM8958_MICBIAS2,
+		snd_soc_component_update_bits(component, WM8958_MICBIAS2,
 				    WM8958_MICB2_DISCH, 0);
 
 		/* Disable debounce while inserted */
-		snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+		snd_soc_component_update_bits(component, WM1811_JACKDET_CTRL,
 				    WM1811_JACKDET_DB, 0);
 
 		delay = control->pdata.micdet_delay;
@@ -3703,22 +3703,22 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 				   &wm8994->mic_work,
 				   msecs_to_jiffies(delay));
 	} else {
-		dev_dbg(codec->dev, "Jack not detected\n");
+		dev_dbg(component->dev, "Jack not detected\n");
 
 		cancel_delayed_work_sync(&wm8994->mic_work);
 
-		snd_soc_update_bits(codec, WM8958_MICBIAS2,
+		snd_soc_component_update_bits(component, WM8958_MICBIAS2,
 				    WM8958_MICB2_DISCH, WM8958_MICB2_DISCH);
 
 		/* Enable debounce while removed */
-		snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+		snd_soc_component_update_bits(component, WM1811_JACKDET_CTRL,
 				    WM1811_JACKDET_DB, WM1811_JACKDET_DB);
 
 		wm8994->mic_detecting = false;
 		wm8994->jack_mic = false;
-		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, 0);
-		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
+		wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_JACK);
 	}
 
 	mutex_unlock(&wm8994->accdet_lock);
@@ -3739,7 +3739,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 	 * avoid bootstrapping issues with the core. */
 	snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0);
 
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 	return IRQ_HANDLED;
 }
 
@@ -3754,7 +3754,7 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work)
 /**
  * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
  *
- * @codec:   WM8958 codec
+ * @component:   WM8958 component
  * @jack:    jack to report detection events on
  *
  * Enable microphone detection functionality for the WM8958.  By
@@ -3767,12 +3767,12 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work)
  * flexiblity a callback is provided which allows a completely custom
  * detection algorithm.
  */
-int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		      wm1811_micdet_cb det_cb, void *det_cb_data,
 		      wm1811_mic_id_cb id_cb, void *id_cb_data)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	u16 micd_lvl_sel;
 
@@ -3803,10 +3803,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 			wm8994->mic_id_cb_data = id_cb_data;
 		} else {
 			wm8994->mic_id_cb = wm8958_mic_id;
-			wm8994->mic_id_cb_data = codec;
+			wm8994->mic_id_cb_data = component;
 		}
 
-		wm8958_micd_set_rate(codec);
+		wm8958_micd_set_rate(component);
 
 		/* Detect microphones and short circuits by default */
 		if (control->pdata.micd_lvl_sel)
@@ -3818,10 +3818,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
 			SND_JACK_BTN_4 | SND_JACK_BTN_5;
 
-		snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_2,
 				    WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
 
-		WARN_ON(snd_soc_codec_get_bias_level(codec) > SND_SOC_BIAS_STANDBY);
+		WARN_ON(snd_soc_component_get_bias_level(component) > SND_SOC_BIAS_STANDBY);
 
 		/*
 		 * If we can use jack detection start off with that,
@@ -3829,25 +3829,25 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 		 */
 		if (wm8994->jackdet) {
 			/* Disable debounce for the initial detect */
-			snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+			snd_soc_component_update_bits(component, WM1811_JACKDET_CTRL,
 					    WM1811_JACKDET_DB, 0);
 
-			snd_soc_update_bits(codec, WM8958_MICBIAS2,
+			snd_soc_component_update_bits(component, WM8958_MICBIAS2,
 					    WM8958_MICB2_DISCH,
 					    WM8958_MICB2_DISCH);
-			snd_soc_update_bits(codec, WM8994_LDO_1,
+			snd_soc_component_update_bits(component, WM8994_LDO_1,
 					    WM8994_LDO1_DISCH, 0);
-			wm1811_jackdet_set_mode(codec,
+			wm1811_jackdet_set_mode(component,
 						WM1811_JACKDET_MODE_JACK);
 		} else {
-			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+			snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
 					    WM8958_MICD_ENA, WM8958_MICD_ENA);
 		}
 
 	} else {
-		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
 				    WM8958_MICD_ENA, 0);
-		wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE);
+		wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_NONE);
 		snd_soc_dapm_disable_pin(dapm, "CLK_SYS");
 		snd_soc_dapm_sync(dapm);
 	}
@@ -3861,9 +3861,9 @@ static void wm8958_mic_work(struct work_struct *work)
 	struct wm8994_priv *wm8994 = container_of(work,
 						  struct wm8994_priv,
 						  mic_complete_work.work);
-	struct snd_soc_codec *codec = wm8994->hubs.codec;
+	struct snd_soc_component *component = wm8994->hubs.component;
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	mutex_lock(&wm8994->accdet_lock);
 
@@ -3871,13 +3871,13 @@ static void wm8958_mic_work(struct work_struct *work)
 
 	mutex_unlock(&wm8994->accdet_lock);
 
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 }
 
 static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
 	struct wm8994_priv *wm8994 = data;
-	struct snd_soc_codec *codec = wm8994->hubs.codec;
+	struct snd_soc_component *component = wm8994->hubs.component;
 	int reg, count, ret, id_delay;
 
 	/*
@@ -3885,30 +3885,30 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 	 * with an update of the MICDET status; if so it will have
 	 * stopped detection and we can ignore this interrupt.
 	 */
-	if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
+	if (!(snd_soc_component_read32(component, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
 		return IRQ_HANDLED;
 
 	cancel_delayed_work_sync(&wm8994->mic_complete_work);
 	cancel_delayed_work_sync(&wm8994->open_circuit_work);
 
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	/* We may occasionally read a detection without an impedence
 	 * range being provided - if that happens loop again.
 	 */
 	count = 10;
 	do {
-		reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
+		reg = snd_soc_component_read32(component, WM8958_MIC_DETECT_3);
 		if (reg < 0) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to read mic detect status: %d\n",
 				reg);
-			pm_runtime_put(codec->dev);
+			pm_runtime_put(component->dev);
 			return IRQ_NONE;
 		}
 
 		if (!(reg & WM8958_MICD_VALID)) {
-			dev_dbg(codec->dev, "Mic detect data not valid\n");
+			dev_dbg(component->dev, "Mic detect data not valid\n");
 			goto out;
 		}
 
@@ -3919,20 +3919,20 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 	} while (count--);
 
 	if (count == 0)
-		dev_warn(codec->dev, "No impedance range reported for jack\n");
+		dev_warn(component->dev, "No impedance range reported for jack\n");
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
-	trace_snd_soc_jack_irq(dev_name(codec->dev));
+	trace_snd_soc_jack_irq(dev_name(component->dev));
 #endif
 
 	/* Avoid a transient report when the accessory is being removed */
 	if (wm8994->jackdet) {
-		ret = snd_soc_read(codec, WM1811_JACKDET_CTRL);
+		ret = snd_soc_component_read32(component, WM1811_JACKDET_CTRL);
 		if (ret < 0) {
-			dev_err(codec->dev, "Failed to read jack status: %d\n",
+			dev_err(component->dev, "Failed to read jack status: %d\n",
 				ret);
 		} else if (!(ret & WM1811_JACKDET_LVL)) {
-			dev_dbg(codec->dev, "Ignoring removed jack\n");
+			dev_dbg(component->dev, "Ignoring removed jack\n");
 			goto out;
 		}
 	} else if (!(reg & WM8958_MICD_STS)) {
@@ -3951,51 +3951,51 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
 				   &wm8994->mic_complete_work,
 				   msecs_to_jiffies(id_delay));
 	else
-		wm8958_button_det(codec, reg);
+		wm8958_button_det(component, reg);
 
 out:
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t wm8994_fifo_error(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
+	struct snd_soc_component *component = data;
 
-	dev_err(codec->dev, "FIFO error\n");
+	dev_err(component->dev, "FIFO error\n");
 
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t wm8994_temp_warn(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
+	struct snd_soc_component *component = data;
 
-	dev_err(codec->dev, "Thermal warning\n");
+	dev_err(component->dev, "Thermal warning\n");
 
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t wm8994_temp_shut(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
+	struct snd_soc_component *component = data;
 
-	dev_crit(codec->dev, "Thermal shutdown\n");
+	dev_crit(component->dev, "Thermal shutdown\n");
 
 	return IRQ_HANDLED;
 }
 
-static int wm8994_codec_probe(struct snd_soc_codec *codec)
+static int wm8994_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8994 *control = dev_get_drvdata(codec->dev->parent);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994 *control = dev_get_drvdata(component->dev->parent);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 	int ret, i;
 
-	snd_soc_codec_init_regmap(codec, control->regmap);
+	snd_soc_component_init_regmap(component, control->regmap);
 
-	wm8994->hubs.codec = codec;
+	wm8994->hubs.component = component;
 
 	mutex_init(&wm8994->accdet_lock);
 	INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
@@ -4070,7 +4070,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		wm8994->hubs.dcs_codes_l = -9;
 		wm8994->hubs.dcs_codes_r = -7;
 
-		snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1,
+		snd_soc_component_update_bits(component, WM8994_ANALOGUE_HP_1,
 				    WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN);
 		break;
 
@@ -4079,11 +4079,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	}
 
 	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR,
-			   wm8994_fifo_error, "FIFO error", codec);
+			   wm8994_fifo_error, "FIFO error", component);
 	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN,
-			   wm8994_temp_warn, "Thermal warning", codec);
+			   wm8994_temp_warn, "Thermal warning", component);
 	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,
-			   wm8994_temp_shut, "Thermal shutdown", codec);
+			   wm8994_temp_shut, "Thermal shutdown", component);
 
 	switch (control->type) {
 	case WM8994:
@@ -4101,7 +4101,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 					wm8994);
 
 		if (ret != 0)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				 "Failed to request Mic1 detect IRQ: %d\n",
 				 ret);
 
@@ -4111,7 +4111,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 					 wm8994_mic_irq, "Mic 1 short",
 					 wm8994);
 		if (ret != 0)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				 "Failed to request Mic1 short IRQ: %d\n",
 				 ret);
 
@@ -4120,7 +4120,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 					 wm8994_mic_irq, "Mic 2 detect",
 					 wm8994);
 		if (ret != 0)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				 "Failed to request Mic2 detect IRQ: %d\n",
 				 ret);
 
@@ -4129,7 +4129,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 					 wm8994_mic_irq, "Mic 2 short",
 					 wm8994);
 		if (ret != 0)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				 "Failed to request Mic2 short IRQ: %d\n",
 				 ret);
 		break;
@@ -4144,7 +4144,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 						   "Mic detect",
 						   wm8994);
 			if (ret != 0)
-				dev_warn(codec->dev,
+				dev_warn(component->dev,
 					 "Failed to request Mic detect IRQ: %d\n",
 					 ret);
 		} else {
@@ -4180,7 +4180,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	}
 
 	/* Make sure we can read from the GPIOs if they're inputs */
-	pm_runtime_get_sync(codec->dev);
+	pm_runtime_get_sync(component->dev);
 
 	/* Remember if AIFnLRCLK is configured as a GPIO.  This should be
 	 * configured on init - if a system wants to do this dynamically
@@ -4188,7 +4188,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	 */
 	ret = regmap_read(control->regmap, WM8994_GPIO_1, &reg);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret);
+		dev_err(component->dev, "Failed to read GPIO1 state: %d\n", ret);
 		goto err_irq;
 	}
 	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
@@ -4200,7 +4200,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
 	ret = regmap_read(control->regmap, WM8994_GPIO_6, &reg);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret);
+		dev_err(component->dev, "Failed to read GPIO6 state: %d\n", ret);
 		goto err_irq;
 	}
 	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
@@ -4210,22 +4210,22 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		wm8994->lrclk_shared[1] = 0;
 	}
 
-	pm_runtime_put(codec->dev);
+	pm_runtime_put(component->dev);
 
 	/* Latch volume update bits */
 	for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
-		snd_soc_update_bits(codec, wm8994_vu_bits[i].reg,
+		snd_soc_component_update_bits(component, wm8994_vu_bits[i].reg,
 				    wm8994_vu_bits[i].mask,
 				    wm8994_vu_bits[i].mask);
 
 	/* Set the low bit of the 3D stereo depth so TLV matches */
-	snd_soc_update_bits(codec, WM8994_AIF1_DAC1_FILTERS_2,
+	snd_soc_component_update_bits(component, WM8994_AIF1_DAC1_FILTERS_2,
 			    1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT,
 			    1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT);
-	snd_soc_update_bits(codec, WM8994_AIF1_DAC2_FILTERS_2,
+	snd_soc_component_update_bits(component, WM8994_AIF1_DAC2_FILTERS_2,
 			    1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT,
 			    1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT);
-	snd_soc_update_bits(codec, WM8994_AIF2_DAC_FILTERS_2,
+	snd_soc_component_update_bits(component, WM8994_AIF2_DAC_FILTERS_2,
 			    1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
 			    1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
 
@@ -4235,7 +4235,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	switch (control->type) {
 	case WM8994:
 	case WM8958:
-		snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8994_AIF1_CONTROL_1,
 				    WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
 		break;
 	default:
@@ -4246,9 +4246,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	switch (control->type) {
 	case WM8958:
 	case WM1811:
-		snd_soc_update_bits(codec, WM8958_MICBIAS1,
+		snd_soc_component_update_bits(component, WM8958_MICBIAS1,
 				    WM8958_MICB1_MODE, WM8958_MICB1_MODE);
-		snd_soc_update_bits(codec, WM8958_MICBIAS2,
+		snd_soc_component_update_bits(component, WM8958_MICBIAS2,
 				    WM8958_MICB2_MODE, WM8958_MICB2_MODE);
 		break;
 	default:
@@ -4256,12 +4256,12 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	}
 
 	wm8994->hubs.check_class_w_digital = wm8994_check_class_w_digital;
-	wm_hubs_update_class_w(codec);
+	wm_hubs_update_class_w(component);
 
 	wm8994_handle_pdata(wm8994);
 
-	wm_hubs_add_analogue_controls(codec);
-	snd_soc_add_codec_controls(codec, wm8994_snd_controls,
+	wm_hubs_add_analogue_controls(component);
+	snd_soc_add_component_controls(component, wm8994_snd_controls,
 			     ARRAY_SIZE(wm8994_snd_controls));
 	snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
 				  ARRAY_SIZE(wm8994_dapm_widgets));
@@ -4287,7 +4287,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		}
 		break;
 	case WM8958:
-		snd_soc_add_codec_controls(codec, wm8958_snd_controls,
+		snd_soc_add_component_controls(component, wm8958_snd_controls,
 				     ARRAY_SIZE(wm8958_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
@@ -4309,7 +4309,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		break;
 
 	case WM1811:
-		snd_soc_add_codec_controls(codec, wm8958_snd_controls,
+		snd_soc_add_component_controls(component, wm8958_snd_controls,
 				     ARRAY_SIZE(wm8958_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
@@ -4322,7 +4322,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		break;
 	}
 
-	wm_hubs_add_analogue_routes(codec, 0, 0);
+	wm_hubs_add_analogue_routes(component, 0, 0);
 	ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
 				 wm_hubs_dcs_done, "DC servo done",
 				 &wm8994->hubs);
@@ -4360,7 +4360,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 						ARRAY_SIZE(wm8958_intercon));
 		}
 
-		wm8958_dsp2_init(codec);
+		wm8958_dsp2_init(component);
 		break;
 	case WM1811:
 		snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
@@ -4385,16 +4385,16 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 				&wm8994->fll_locked[i]);
 	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
 			&wm8994->hubs);
-	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, codec);
-	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, codec);
-	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, codec);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, component);
 
 	return ret;
 }
 
-static int wm8994_codec_remove(struct snd_soc_codec *codec)
+static void wm8994_component_remove(struct snd_soc_component *component)
 {
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int i;
 
@@ -4404,9 +4404,9 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
 
 	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
 			&wm8994->hubs);
-	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, codec);
-	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, codec);
-	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, codec);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, component);
 
 	if (wm8994->jackdet)
 		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994);
@@ -4433,15 +4433,18 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
 	release_firmware(wm8994->mbc_vss);
 	release_firmware(wm8994->enh_eq);
 	kfree(wm8994->retune_mobile_texts);
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
-	.probe =	wm8994_codec_probe,
-	.remove =	wm8994_codec_remove,
-	.suspend =	wm8994_codec_suspend,
-	.resume =	wm8994_codec_resume,
-	.set_bias_level = wm8994_set_bias_level,
+static const struct snd_soc_component_driver soc_component_dev_wm8994 = {
+	.probe			= wm8994_component_probe,
+	.remove			= wm8994_component_remove,
+	.suspend		= wm8994_component_suspend,
+	.resume			= wm8994_component_resume,
+	.set_bias_level		= wm8994_set_bias_level,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8994_probe(struct platform_device *pdev)
@@ -4461,13 +4464,12 @@ static int wm8994_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_idle(&pdev->dev);
 
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
+	return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994,
 			wm8994_dai, ARRAY_SIZE(wm8994_dai));
 }
 
 static int wm8994_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	return 0;
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index dd73387b1cc4..a72efb0e6867 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -43,18 +43,18 @@ enum wm8994_vmid_mode {
 typedef void (*wm1811_micdet_cb)(void *data);
 typedef void (*wm1811_mic_id_cb)(void *data, u16 status);
 
-int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		      int micbias);
-int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		      wm1811_micdet_cb cb, void *det_cb_data,
 		      wm1811_mic_id_cb id_cb, void *id_cb_data);
 
-int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode);
+int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode);
 
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
 		  struct snd_kcontrol *kcontrol, int event);
 
-void wm8958_dsp2_init(struct snd_soc_codec *codec);
+void wm8958_dsp2_init(struct snd_soc_component *component);
 
 struct wm8994_micdet {
 	struct snd_soc_jack *jack;
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 19b08a5cae62..60e227832331 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -385,7 +385,7 @@ struct wm8995_priv {
 	struct fll_config fll[2], fll_suspend[2];
 	struct regulator_bulk_data supplies[WM8995_NUM_SUPPLIES];
 	struct notifier_block disable_nb[WM8995_NUM_SUPPLIES];
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 };
 
 /*
@@ -485,48 +485,48 @@ static const struct snd_kcontrol_new wm8995_snd_controls[] = {
 		WM8995_AIF2_ADC_RIGHT_VOLUME, 0, 96, 0, digital_tlv)
 };
 
-static void wm8995_update_class_w(struct snd_soc_codec *codec)
+static void wm8995_update_class_w(struct snd_soc_component *component)
 {
 	int enable = 1;
 	int source = 0;  /* GCC flow analysis can't track enable */
 	int reg, reg_r;
 
 	/* We also need the same setting for L/R and only one path */
-	reg = snd_soc_read(codec, WM8995_DAC1_LEFT_MIXER_ROUTING);
+	reg = snd_soc_component_read32(component, WM8995_DAC1_LEFT_MIXER_ROUTING);
 	switch (reg) {
 	case WM8995_AIF2DACL_TO_DAC1L:
-		dev_dbg(codec->dev, "Class W source AIF2DAC\n");
+		dev_dbg(component->dev, "Class W source AIF2DAC\n");
 		source = 2 << WM8995_CP_DYN_SRC_SEL_SHIFT;
 		break;
 	case WM8995_AIF1DAC2L_TO_DAC1L:
-		dev_dbg(codec->dev, "Class W source AIF1DAC2\n");
+		dev_dbg(component->dev, "Class W source AIF1DAC2\n");
 		source = 1 << WM8995_CP_DYN_SRC_SEL_SHIFT;
 		break;
 	case WM8995_AIF1DAC1L_TO_DAC1L:
-		dev_dbg(codec->dev, "Class W source AIF1DAC1\n");
+		dev_dbg(component->dev, "Class W source AIF1DAC1\n");
 		source = 0 << WM8995_CP_DYN_SRC_SEL_SHIFT;
 		break;
 	default:
-		dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg);
+		dev_dbg(component->dev, "DAC mixer setting: %x\n", reg);
 		enable = 0;
 		break;
 	}
 
-	reg_r = snd_soc_read(codec, WM8995_DAC1_RIGHT_MIXER_ROUTING);
+	reg_r = snd_soc_component_read32(component, WM8995_DAC1_RIGHT_MIXER_ROUTING);
 	if (reg_r != reg) {
-		dev_dbg(codec->dev, "Left and right DAC mixers different\n");
+		dev_dbg(component->dev, "Left and right DAC mixers different\n");
 		enable = 0;
 	}
 
 	if (enable) {
-		dev_dbg(codec->dev, "Class W enabled\n");
-		snd_soc_update_bits(codec, WM8995_CLASS_W_1,
+		dev_dbg(component->dev, "Class W enabled\n");
+		snd_soc_component_update_bits(component, WM8995_CLASS_W_1,
 				    WM8995_CP_DYN_PWR_MASK |
 				    WM8995_CP_DYN_SRC_SEL_MASK,
 				    source | WM8995_CP_DYN_PWR);
 	} else {
-		dev_dbg(codec->dev, "Class W disabled\n");
-		snd_soc_update_bits(codec, WM8995_CLASS_W_1,
+		dev_dbg(component->dev, "Class W disabled\n");
+		snd_soc_component_update_bits(component, WM8995_CLASS_W_1,
 				    WM8995_CP_DYN_PWR_MASK, 0);
 	}
 }
@@ -534,11 +534,11 @@ static void wm8995_update_class_w(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
 	unsigned int reg;
 	const char *clk;
 
-	reg = snd_soc_read(codec, WM8995_CLOCKING_1);
+	reg = snd_soc_component_read32(component, WM8995_CLOCKING_1);
 	/* Check what we're currently using for CLK_SYS */
 	if (reg & WM8995_SYSCLK_SRC)
 		clk = "AIF2CLK";
@@ -550,37 +550,37 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
-	wm8995_update_class_w(codec);
+	wm8995_update_class_w(component);
 	return ret;
 }
 
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Enable the headphone amp */
-		snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
 				    WM8995_HPOUT1L_ENA_MASK |
 				    WM8995_HPOUT1R_ENA_MASK,
 				    WM8995_HPOUT1L_ENA |
 				    WM8995_HPOUT1R_ENA);
 
 		/* Enable the second stage */
-		snd_soc_update_bits(codec, WM8995_ANALOGUE_HP_1,
+		snd_soc_component_update_bits(component, WM8995_ANALOGUE_HP_1,
 				    WM8995_HPOUT1L_DLY_MASK |
 				    WM8995_HPOUT1R_DLY_MASK,
 				    WM8995_HPOUT1L_DLY |
 				    WM8995_HPOUT1R_DLY);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, WM8995_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, WM8995_CHARGE_PUMP_1,
 				    WM8995_CP_ENA_MASK, 0);
 		break;
 	}
@@ -588,41 +588,41 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static void dc_servo_cmd(struct snd_soc_codec *codec,
+static void dc_servo_cmd(struct snd_soc_component *component,
 			 unsigned int reg, unsigned int val, unsigned int mask)
 {
 	int timeout = 10;
 
-	dev_dbg(codec->dev, "%s: reg = %#x, val = %#x, mask = %#x\n",
+	dev_dbg(component->dev, "%s: reg = %#x, val = %#x, mask = %#x\n",
 		__func__, reg, val, mask);
 
-	snd_soc_write(codec, reg, val);
+	snd_soc_component_write(component, reg, val);
 	while (timeout--) {
 		msleep(10);
-		val = snd_soc_read(codec, WM8995_DC_SERVO_READBACK_0);
+		val = snd_soc_component_read32(component, WM8995_DC_SERVO_READBACK_0);
 		if ((val & mask) == mask)
 			return;
 	}
 
-	dev_err(codec->dev, "Timed out waiting for DC Servo\n");
+	dev_err(component->dev, "Timed out waiting for DC Servo\n");
 }
 
 static int hp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM8995_ANALOGUE_HP_1);
+	reg = snd_soc_component_read32(component, WM8995_ANALOGUE_HP_1);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, WM8995_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, WM8995_CHARGE_PUMP_1,
 				    WM8995_CP_ENA_MASK, WM8995_CP_ENA);
 
 		msleep(5);
 
-		snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
 				    WM8995_HPOUT1L_ENA_MASK |
 				    WM8995_HPOUT1R_ENA_MASK,
 				    WM8995_HPOUT1L_ENA | WM8995_HPOUT1R_ENA);
@@ -630,12 +630,12 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 		udelay(20);
 
 		reg |= WM8995_HPOUT1L_DLY | WM8995_HPOUT1R_DLY;
-		snd_soc_write(codec, WM8995_ANALOGUE_HP_1, reg);
+		snd_soc_component_write(component, WM8995_ANALOGUE_HP_1, reg);
 
-		snd_soc_write(codec, WM8995_DC_SERVO_1, WM8995_DCS_ENA_CHAN_0 |
+		snd_soc_component_write(component, WM8995_DC_SERVO_1, WM8995_DCS_ENA_CHAN_0 |
 			      WM8995_DCS_ENA_CHAN_1);
 
-		dc_servo_cmd(codec, WM8995_DC_SERVO_2,
+		dc_servo_cmd(component, WM8995_DC_SERVO_2,
 			     WM8995_DCS_TRIG_STARTUP_0 |
 			     WM8995_DCS_TRIG_STARTUP_1,
 			     WM8995_DCS_TRIG_DAC_WR_0 |
@@ -643,23 +643,23 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 
 		reg |= WM8995_HPOUT1R_OUTP | WM8995_HPOUT1R_RMV_SHORT |
 		       WM8995_HPOUT1L_OUTP | WM8995_HPOUT1L_RMV_SHORT;
-		snd_soc_write(codec, WM8995_ANALOGUE_HP_1, reg);
+		snd_soc_component_write(component, WM8995_ANALOGUE_HP_1, reg);
 
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, WM8995_ANALOGUE_HP_1,
+		snd_soc_component_update_bits(component, WM8995_ANALOGUE_HP_1,
 				    WM8995_HPOUT1L_OUTP_MASK |
 				    WM8995_HPOUT1R_OUTP_MASK |
 				    WM8995_HPOUT1L_RMV_SHORT_MASK |
 				    WM8995_HPOUT1R_RMV_SHORT_MASK, 0);
 
-		snd_soc_update_bits(codec, WM8995_ANALOGUE_HP_1,
+		snd_soc_component_update_bits(component, WM8995_ANALOGUE_HP_1,
 				    WM8995_HPOUT1L_DLY_MASK |
 				    WM8995_HPOUT1R_DLY_MASK, 0);
 
-		snd_soc_write(codec, WM8995_DC_SERVO_1, 0);
+		snd_soc_component_write(component, WM8995_DC_SERVO_1, 0);
 
-		snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
 				    WM8995_HPOUT1L_ENA_MASK |
 				    WM8995_HPOUT1R_ENA_MASK,
 				    0);
@@ -669,14 +669,14 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
+static int configure_aif_clock(struct snd_soc_component *component, int aif)
 {
 	struct wm8995_priv *wm8995;
 	int rate;
 	int reg1 = 0;
 	int offset;
 
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	wm8995 = snd_soc_component_get_drvdata(component);
 
 	if (aif)
 		offset = 4;
@@ -707,29 +707,29 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
 		rate /= 2;
 		reg1 |= WM8995_AIF1CLK_DIV;
 
-		dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n",
+		dev_dbg(component->dev, "Dividing AIF%d clock to %dHz\n",
 			aif + 1, rate);
 	}
 
 	wm8995->aifclk[aif] = rate;
 
-	snd_soc_update_bits(codec, WM8995_AIF1_CLOCKING_1 + offset,
+	snd_soc_component_update_bits(component, WM8995_AIF1_CLOCKING_1 + offset,
 			    WM8995_AIF1CLK_SRC_MASK | WM8995_AIF1CLK_DIV_MASK,
 			    reg1);
 	return 0;
 }
 
-static int configure_clock(struct snd_soc_codec *codec)
+static int configure_clock(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct wm8995_priv *wm8995;
 	int change, new;
 
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	wm8995 = snd_soc_component_get_drvdata(component);
 
 	/* Bring up the AIF clocks first */
-	configure_aif_clock(codec, 0);
-	configure_aif_clock(codec, 1);
+	configure_aif_clock(component, 0);
+	configure_aif_clock(component, 1);
 
 	/*
 	 * Then switch CLK_SYS over to the higher of them; a change
@@ -747,7 +747,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 	else
 		new = 0;
 
-	change = snd_soc_update_bits(codec, WM8995_CLOCKING_1,
+	change = snd_soc_component_update_bits(component, WM8995_CLOCKING_1,
 				     WM8995_SYSCLK_SRC_MASK, new);
 	if (!change)
 		return 0;
@@ -760,14 +760,14 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		return configure_clock(codec);
+		return configure_clock(component);
 
 	case SND_SOC_DAPM_POST_PMD:
-		configure_clock(codec);
+		configure_clock(component);
 		break;
 	}
 
@@ -1422,7 +1422,7 @@ static bool wm8995_volatile(struct device *dev, unsigned int reg)
 
 static int wm8995_aif_mute(struct snd_soc_dai *dai, int mute)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int mute_reg;
 
 	switch (dai->id) {
@@ -1436,18 +1436,18 @@ static int wm8995_aif_mute(struct snd_soc_dai *dai, int mute)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, mute_reg, WM8995_AIF1DAC1_MUTE_MASK,
+	snd_soc_component_update_bits(component, mute_reg, WM8995_AIF1DAC1_MUTE_MASK,
 			    !!mute << WM8995_AIF1DAC1_MUTE_SHIFT);
 	return 0;
 }
 
 static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	int master;
 	int aif;
 
-	codec = dai->codec;
+	component = dai->component;
 
 	master = 0;
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1519,11 +1519,11 @@ static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, WM8995_AIF1_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8995_AIF1_CONTROL_1,
 			    WM8995_AIF1_BCLK_INV_MASK |
 			    WM8995_AIF1_LRCLK_INV_MASK |
 			    WM8995_AIF1_FMT_MASK, aif);
-	snd_soc_update_bits(codec, WM8995_AIF1_MASTER_SLAVE,
+	snd_soc_component_update_bits(component, WM8995_AIF1_MASTER_SLAVE,
 			    WM8995_AIF1_MSTR_MASK, master);
 	return 0;
 }
@@ -1546,7 +1546,7 @@ static int wm8995_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8995_priv *wm8995;
 	int aif1_reg;
 	int bclk_reg;
@@ -1557,8 +1557,8 @@ static int wm8995_hw_params(struct snd_pcm_substream *substream,
 	int lrclk, bclk;
 	int i, rate_val, best, best_val, cur_val;
 
-	codec = dai->codec;
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8995 = snd_soc_component_get_drvdata(component);
 
 	switch (dai->id) {
 	case 0:
@@ -1570,7 +1570,7 @@ static int wm8995_hw_params(struct snd_pcm_substream *substream,
 			lrclk_reg = WM8995_AIF1DAC_LRCLK;
 		} else {
 			lrclk_reg = WM8995_AIF1ADC_LRCLK;
-			dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+			dev_dbg(component->dev, "AIF1 using split LRCLK\n");
 		}
 		break;
 	case 1:
@@ -1582,7 +1582,7 @@ static int wm8995_hw_params(struct snd_pcm_substream *substream,
 			lrclk_reg = WM8995_AIF2DAC_LRCLK;
 		} else {
 			lrclk_reg = WM8995_AIF2ADC_LRCLK;
-			dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+			dev_dbg(component->dev, "AIF2 using split LRCLK\n");
 		}
 		break;
 	default:
@@ -1668,13 +1668,13 @@ static int wm8995_hw_params(struct snd_pcm_substream *substream,
 	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
 		lrclk, bclk_rate / lrclk);
 
-	snd_soc_update_bits(codec, aif1_reg,
+	snd_soc_component_update_bits(component, aif1_reg,
 			    WM8995_AIF1_WL_MASK, aif1);
-	snd_soc_update_bits(codec, bclk_reg,
+	snd_soc_component_update_bits(component, bclk_reg,
 			    WM8995_AIF1_BCLK_DIV_MASK, bclk);
-	snd_soc_update_bits(codec, lrclk_reg,
+	snd_soc_component_update_bits(component, lrclk_reg,
 			    WM8995_AIF1DAC_RATE_MASK, lrclk);
-	snd_soc_update_bits(codec, rate_reg,
+	snd_soc_component_update_bits(component, rate_reg,
 			    WM8995_AIF1_SR_MASK |
 			    WM8995_AIF1CLK_RATE_MASK, rate_val);
 	return 0;
@@ -1682,7 +1682,7 @@ static int wm8995_hw_params(struct snd_pcm_substream *substream,
 
 static int wm8995_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	int reg, val, mask;
 
 	switch (codec_dai->id) {
@@ -1707,7 +1707,7 @@ static int wm8995_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
 	else
 		val = 0;
 
-	return snd_soc_update_bits(codec, reg, mask, val);
+	return snd_soc_component_update_bits(component, reg, mask, val);
 }
 
 /* The size in bits of the FLL divide multiplied by 10
@@ -1797,19 +1797,19 @@ static int wm8995_set_fll(struct snd_soc_dai *dai, int id,
 			  int src, unsigned int freq_in,
 			  unsigned int freq_out)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8995_priv *wm8995;
 	int reg_offset, ret;
 	struct fll_div fll;
 	u16 reg, aif1, aif2;
 
-	codec = dai->codec;
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8995 = snd_soc_component_get_drvdata(component);
 
-	aif1 = snd_soc_read(codec, WM8995_AIF1_CLOCKING_1)
+	aif1 = snd_soc_component_read32(component, WM8995_AIF1_CLOCKING_1)
 	       & WM8995_AIF1CLK_ENA;
 
-	aif2 = snd_soc_read(codec, WM8995_AIF2_CLOCKING_1)
+	aif2 = snd_soc_component_read32(component, WM8995_AIF2_CLOCKING_1)
 	       & WM8995_AIF2CLK_ENA;
 
 	switch (id) {
@@ -1858,35 +1858,35 @@ static int wm8995_set_fll(struct snd_soc_dai *dai, int id,
 		return ret;
 
 	/* Gate the AIF clocks while we reclock */
-	snd_soc_update_bits(codec, WM8995_AIF1_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM8995_AIF1_CLOCKING_1,
 			    WM8995_AIF1CLK_ENA_MASK, 0);
-	snd_soc_update_bits(codec, WM8995_AIF2_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM8995_AIF2_CLOCKING_1,
 			    WM8995_AIF2CLK_ENA_MASK, 0);
 
 	/* We always need to disable the FLL while reconfiguring */
-	snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_1 + reg_offset,
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_1 + reg_offset,
 			    WM8995_FLL1_ENA_MASK, 0);
 
 	reg = (fll.outdiv << WM8995_FLL1_OUTDIV_SHIFT) |
 	      (fll.fll_fratio << WM8995_FLL1_FRATIO_SHIFT);
-	snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_2 + reg_offset,
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_2 + reg_offset,
 			    WM8995_FLL1_OUTDIV_MASK |
 			    WM8995_FLL1_FRATIO_MASK, reg);
 
-	snd_soc_write(codec, WM8995_FLL1_CONTROL_3 + reg_offset, fll.k);
+	snd_soc_component_write(component, WM8995_FLL1_CONTROL_3 + reg_offset, fll.k);
 
-	snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_4 + reg_offset,
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_4 + reg_offset,
 			    WM8995_FLL1_N_MASK,
 			    fll.n << WM8995_FLL1_N_SHIFT);
 
-	snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_5 + reg_offset,
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_5 + reg_offset,
 			    WM8995_FLL1_REFCLK_DIV_MASK |
 			    WM8995_FLL1_REFCLK_SRC_MASK,
 			    (fll.clk_ref_div << WM8995_FLL1_REFCLK_DIV_SHIFT) |
 			    (src - 1));
 
 	if (freq_out)
-		snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_1 + reg_offset,
+		snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_1 + reg_offset,
 				    WM8995_FLL1_ENA_MASK, WM8995_FLL1_ENA);
 
 	wm8995->fll[id].in = freq_in;
@@ -1894,12 +1894,12 @@ static int wm8995_set_fll(struct snd_soc_dai *dai, int id,
 	wm8995->fll[id].src = src;
 
 	/* Enable any gated AIF clocks */
-	snd_soc_update_bits(codec, WM8995_AIF1_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM8995_AIF1_CLOCKING_1,
 			    WM8995_AIF1CLK_ENA_MASK, aif1);
-	snd_soc_update_bits(codec, WM8995_AIF2_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM8995_AIF2_CLOCKING_1,
 			    WM8995_AIF2CLK_ENA_MASK, aif2);
 
-	configure_clock(codec);
+	configure_clock(component);
 
 	return 0;
 }
@@ -1907,11 +1907,11 @@ static int wm8995_set_fll(struct snd_soc_dai *dai, int id,
 static int wm8995_set_dai_sysclk(struct snd_soc_dai *dai,
 				 int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct wm8995_priv *wm8995;
 
-	codec = dai->codec;
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	component = dai->component;
+	wm8995 = snd_soc_component_get_drvdata(component);
 
 	switch (dai->id) {
 	case 0:
@@ -1949,24 +1949,24 @@ static int wm8995_set_dai_sysclk(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	configure_clock(codec);
+	configure_clock(component);
 
 	return 0;
 }
 
-static int wm8995_set_bias_level(struct snd_soc_codec *codec,
+static int wm8995_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	struct wm8995_priv *wm8995;
 	int ret;
 
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	wm8995 = snd_soc_component_get_drvdata(component);
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
 						    wm8995->supplies);
 			if (ret)
@@ -1974,17 +1974,17 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
 
 			ret = regcache_sync(wm8995->regmap);
 			if (ret) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to sync cache: %d\n", ret);
 				return ret;
 			}
 
-			snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
 					    WM8995_BG_ENA_MASK, WM8995_BG_ENA);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
 				    WM8995_BG_ENA_MASK, 0);
 		regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies),
 				       wm8995->supplies);
@@ -1994,37 +1994,36 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int wm8995_remove(struct snd_soc_codec *codec)
+static void wm8995_remove(struct snd_soc_component *component)
 {
 	struct wm8995_priv *wm8995;
 	int i;
 
-	wm8995 = snd_soc_codec_get_drvdata(codec);
+	wm8995 = snd_soc_component_get_drvdata(component);
 
 	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i)
 		regulator_unregister_notifier(wm8995->supplies[i].consumer,
 					      &wm8995->disable_nb[i]);
 
 	regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
-	return 0;
 }
 
-static int wm8995_probe(struct snd_soc_codec *codec)
+static int wm8995_probe(struct snd_soc_component *component)
 {
 	struct wm8995_priv *wm8995;
 	int i;
 	int ret;
 
-	wm8995 = snd_soc_codec_get_drvdata(codec);
-	wm8995->codec = codec;
+	wm8995 = snd_soc_component_get_drvdata(component);
+	wm8995->component = component;
 
 	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)
 		wm8995->supplies[i].supply = wm8995_supply_names[i];
 
-	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8995->supplies),
+	ret = regulator_bulk_get(component->dev, ARRAY_SIZE(wm8995->supplies),
 				 wm8995->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
 		return ret;
 	}
 
@@ -2042,7 +2041,7 @@ static int wm8995_probe(struct snd_soc_codec *codec)
 		ret = regulator_register_notifier(wm8995->supplies[i].consumer,
 						  &wm8995->disable_nb[i]);
 		if (ret) {
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to register regulator notifier: %d\n",
 				ret);
 		}
@@ -2051,49 +2050,49 @@ static int wm8995_probe(struct snd_soc_codec *codec)
 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
 				    wm8995->supplies);
 	if (ret) {
-		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
 		goto err_reg_get;
 	}
 
-	ret = snd_soc_read(codec, WM8995_SOFTWARE_RESET);
+	ret = snd_soc_component_read32(component, WM8995_SOFTWARE_RESET);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to read device ID: %d\n", ret);
+		dev_err(component->dev, "Failed to read device ID: %d\n", ret);
 		goto err_reg_enable;
 	}
 
 	if (ret != 0x8995) {
-		dev_err(codec->dev, "Invalid device ID: %#x\n", ret);
+		dev_err(component->dev, "Invalid device ID: %#x\n", ret);
 		ret = -EINVAL;
 		goto err_reg_enable;
 	}
 
-	ret = snd_soc_write(codec, WM8995_SOFTWARE_RESET, 0);
+	ret = snd_soc_component_write(component, WM8995_SOFTWARE_RESET, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
 		goto err_reg_enable;
 	}
 
 	/* Latch volume updates (right only; we always do left then right). */
-	snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_AIF1_DAC1_RIGHT_VOLUME,
 			    WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU);
-	snd_soc_update_bits(codec, WM8995_AIF1_DAC2_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_AIF1_DAC2_RIGHT_VOLUME,
 			    WM8995_AIF1DAC2_VU_MASK, WM8995_AIF1DAC2_VU);
-	snd_soc_update_bits(codec, WM8995_AIF2_DAC_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_AIF2_DAC_RIGHT_VOLUME,
 			    WM8995_AIF2DAC_VU_MASK, WM8995_AIF2DAC_VU);
-	snd_soc_update_bits(codec, WM8995_AIF1_ADC1_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_AIF1_ADC1_RIGHT_VOLUME,
 			    WM8995_AIF1ADC1_VU_MASK, WM8995_AIF1ADC1_VU);
-	snd_soc_update_bits(codec, WM8995_AIF1_ADC2_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_AIF1_ADC2_RIGHT_VOLUME,
 			    WM8995_AIF1ADC2_VU_MASK, WM8995_AIF1ADC2_VU);
-	snd_soc_update_bits(codec, WM8995_AIF2_ADC_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_AIF2_ADC_RIGHT_VOLUME,
 			    WM8995_AIF2ADC_VU_MASK, WM8995_AIF1ADC2_VU);
-	snd_soc_update_bits(codec, WM8995_DAC1_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_DAC1_RIGHT_VOLUME,
 			    WM8995_DAC1_VU_MASK, WM8995_DAC1_VU);
-	snd_soc_update_bits(codec, WM8995_DAC2_RIGHT_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_DAC2_RIGHT_VOLUME,
 			    WM8995_DAC2_VU_MASK, WM8995_DAC2_VU);
-	snd_soc_update_bits(codec, WM8995_RIGHT_LINE_INPUT_1_VOLUME,
+	snd_soc_component_update_bits(component, WM8995_RIGHT_LINE_INPUT_1_VOLUME,
 			    WM8995_IN1_VU_MASK, WM8995_IN1_VU);
 
-	wm8995_update_class_w(codec);
+	wm8995_update_class_w(component);
 
 	return 0;
 
@@ -2186,20 +2185,19 @@ static struct snd_soc_dai_driver wm8995_dai[] = {
 	}
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
-	.probe = wm8995_probe,
-	.remove = wm8995_remove,
-	.set_bias_level = wm8995_set_bias_level,
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm8995_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8995_snd_controls),
-		.dapm_widgets		= wm8995_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8995_dapm_widgets),
-		.dapm_routes		= wm8995_intercon,
-		.num_dapm_routes	= ARRAY_SIZE(wm8995_intercon),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8995 = {
+	.probe			= wm8995_probe,
+	.remove			= wm8995_remove,
+	.set_bias_level		= wm8995_set_bias_level,
+	.controls		= wm8995_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8995_snd_controls),
+	.dapm_widgets		= wm8995_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8995_dapm_widgets),
+	.dapm_routes		= wm8995_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8995_intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm8995_regmap = {
@@ -2233,24 +2231,17 @@ static int wm8995_spi_probe(struct spi_device *spi)
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&spi->dev,
-				     &soc_codec_dev_wm8995, wm8995_dai,
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm8995, wm8995_dai,
 				     ARRAY_SIZE(wm8995_dai));
 	return ret;
 }
 
-static int wm8995_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
 static struct spi_driver wm8995_spi_driver = {
 	.driver = {
 		.name = "wm8995",
 	},
 	.probe = wm8995_spi_probe,
-	.remove = wm8995_spi_remove
 };
 #endif
 
@@ -2274,8 +2265,8 @@ static int wm8995_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8995, wm8995_dai,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8995, wm8995_dai,
 				     ARRAY_SIZE(wm8995_dai));
 	if (ret < 0)
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
@@ -2283,12 +2274,6 @@ static int wm8995_i2c_probe(struct i2c_client *i2c,
 	return ret;
 }
 
-static int wm8995_i2c_remove(struct i2c_client *client)
-{
-	snd_soc_unregister_codec(&client->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm8995_i2c_id[] = {
 	{"wm8995", 0},
 	{}
@@ -2301,7 +2286,6 @@ static struct i2c_driver wm8995_i2c_driver = {
 		.name = "wm8995",
 	},
 	.probe = wm8995_i2c_probe,
-	.remove = wm8995_i2c_remove,
 	.id_table = wm8995_i2c_id
 };
 #endif
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 8affa4969120..d9d206046f8c 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -53,7 +53,7 @@ static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
 struct wm8996_priv {
 	struct device *dev;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
 	int ldo1ena;
 
@@ -335,9 +335,9 @@ static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_cutoff,
 static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_cutoff,
 			    WM8996_DSP2_TX_FILTERS, 0, hpf_cutoff_text);
 
-static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
+static void wm8996_set_retune_mobile(struct snd_soc_component *component, int block)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	struct wm8996_pdata *pdata = &wm8996->pdata;
 	int base, best, best_val, save, i, cfg, iface;
 
@@ -347,7 +347,7 @@ static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
 	switch (block) {
 	case 0:
 		base = WM8996_DSP1_RX_EQ_GAINS_1;
-		if (snd_soc_read(codec, WM8996_POWER_MANAGEMENT_8) &
+		if (snd_soc_component_read32(component, WM8996_POWER_MANAGEMENT_8) &
 		    WM8996_DSP1RX_SRC)
 			iface = 1;
 		else
@@ -355,7 +355,7 @@ static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
 		break;
 	case 1:
 		base = WM8996_DSP1_RX_EQ_GAINS_2;
-		if (snd_soc_read(codec, WM8996_POWER_MANAGEMENT_8) &
+		if (snd_soc_component_read32(component, WM8996_POWER_MANAGEMENT_8) &
 		    WM8996_DSP2RX_SRC)
 			iface = 1;
 		else
@@ -381,7 +381,7 @@ static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
 		}
 	}
 
-	dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+	dev_dbg(component->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
 		block,
 		pdata->retune_mobile_cfgs[best].name,
 		pdata->retune_mobile_cfgs[best].rate,
@@ -390,14 +390,14 @@ static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
 	/* The EQ will be disabled while reconfiguring it, remember the
 	 * current configuration. 
 	 */
-	save = snd_soc_read(codec, base);
+	save = snd_soc_component_read32(component, base);
 	save &= WM8996_DSP1RX_EQ_ENA;
 
 	for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
-		snd_soc_update_bits(codec, base + i, 0xffff,
+		snd_soc_component_update_bits(component, base + i, 0xffff,
 				    pdata->retune_mobile_cfgs[best].regs[i]);
 
-	snd_soc_update_bits(codec, base, WM8996_DSP1RX_EQ_ENA, save);
+	snd_soc_component_update_bits(component, base, WM8996_DSP1RX_EQ_ENA, save);
 }
 
 /* Icky as hell but saves code duplication */
@@ -413,8 +413,8 @@ static int wm8996_get_retune_mobile_block(const char *name)
 static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	struct wm8996_pdata *pdata = &wm8996->pdata;
 	int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
 	int value = ucontrol->value.enumerated.item[0];
@@ -427,7 +427,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 
 	wm8996->retune_mobile_cfg[block] = value;
 
-	wm8996_set_retune_mobile(codec, block);
+	wm8996_set_retune_mobile(component, block);
 
 	return 0;
 }
@@ -435,8 +435,8 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
 
 	if (block < 0)
@@ -575,40 +575,40 @@ SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
 	       eq_tlv),
 };
 
-static void wm8996_bg_enable(struct snd_soc_codec *codec)
+static void wm8996_bg_enable(struct snd_soc_component *component)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 
 	wm8996->bg_ena++;
 	if (wm8996->bg_ena == 1) {
-		snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8996_POWER_MANAGEMENT_1,
 				    WM8996_BG_ENA, WM8996_BG_ENA);
 		msleep(2);
 	}
 }
 
-static void wm8996_bg_disable(struct snd_soc_codec *codec)
+static void wm8996_bg_disable(struct snd_soc_component *component)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 
 	wm8996->bg_ena--;
 	if (!wm8996->bg_ena)
-		snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8996_POWER_MANAGEMENT_1,
 				    WM8996_BG_ENA, 0);
 }
 
 static int bg_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	int ret = 0;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		wm8996_bg_enable(codec);
+		wm8996_bg_enable(component);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		wm8996_bg_disable(codec);
+		wm8996_bg_disable(component);
 		break;
 	default:
 		WARN(1, "Invalid event %d\n", event);
@@ -635,8 +635,8 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int rmv_short_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 
 	/* Record which outputs we enabled */
 	switch (event) {
@@ -654,14 +654,14 @@ static int rmv_short_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
+static void wait_for_dc_servo(struct snd_soc_component *component, u16 mask)
 {
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int ret;
 	unsigned long timeout = 200;
 
-	snd_soc_write(codec, WM8996_DC_SERVO_2, mask);
+	snd_soc_component_write(component, WM8996_DC_SERVO_2, mask);
 
 	/* Use the interrupt if possible */
 	do {
@@ -669,44 +669,43 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
 			timeout = wait_for_completion_timeout(&wm8996->dcs_done,
 							      msecs_to_jiffies(200));
 			if (timeout == 0)
-				dev_err(codec->dev, "DC servo timed out\n");
+				dev_err(component->dev, "DC servo timed out\n");
 
 		} else {
 			msleep(1);
 			timeout--;
 		}
 
-		ret = snd_soc_read(codec, WM8996_DC_SERVO_2);
-		dev_dbg(codec->dev, "DC servo state: %x\n", ret);
+		ret = snd_soc_component_read32(component, WM8996_DC_SERVO_2);
+		dev_dbg(component->dev, "DC servo state: %x\n", ret);
 	} while (timeout && ret & mask);
 
 	if (timeout == 0)
-		dev_err(codec->dev, "DC servo timed out for %x\n", mask);
+		dev_err(component->dev, "DC servo timed out for %x\n", mask);
 	else
-		dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
+		dev_dbg(component->dev, "DC servo complete for %x\n", mask);
 }
 
-static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
+static void wm8996_seq_notifier(struct snd_soc_component *component,
 				enum snd_soc_dapm_type event, int subseq)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	u16 val, mask;
 
 	/* Complete any pending DC servo starts */
 	if (wm8996->dcs_pending) {
-		dev_dbg(codec->dev, "Starting DC servo for %x\n",
+		dev_dbg(component->dev, "Starting DC servo for %x\n",
 			wm8996->dcs_pending);
 
 		/* Trigger a startup sequence */
-		wait_for_dc_servo(codec, wm8996->dcs_pending
+		wait_for_dc_servo(component, wm8996->dcs_pending
 				         << WM8996_DCS_TRIG_STARTUP_0_SHIFT);
 
 		wm8996->dcs_pending = 0;
 	}
 
 	if (wm8996->hpout_pending != wm8996->hpout_ena) {
-		dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
+		dev_dbg(component->dev, "Applying RMV_SHORTs %x->%x\n",
 			wm8996->hpout_ena, wm8996->hpout_pending);
 
 		val = 0;
@@ -729,7 +728,7 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
 				WM8996_HPOUT1R_DLY;
 		}
 
-		snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1, mask, val);
+		snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1, mask, val);
 
 		val = 0;
 		mask = 0;
@@ -751,7 +750,7 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
 				WM8996_HPOUT2R_DLY;
 		}
 
-		snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_2, mask, val);
+		snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_2, mask, val);
 
 		wm8996->hpout_ena = wm8996->hpout_pending;
 	}
@@ -760,8 +759,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int dcs_start(struct snd_soc_dapm_widget *w,
 		     struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
@@ -1533,9 +1532,9 @@ static const int bclk_divs[] = {
 	1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
 };
 
-static void wm8996_update_bclk(struct snd_soc_codec *codec)
+static void wm8996_update_bclk(struct snd_soc_component *component)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int aif, best, cur_val, bclk_rate, bclk_reg, i;
 
 	/* Don't bother if we're in a low frequency idle mode that
@@ -1565,18 +1564,18 @@ static void wm8996_update_bclk(struct snd_soc_codec *codec)
 			best = i;
 		}
 		bclk_rate = wm8996->sysclk / bclk_divs[best];
-		dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+		dev_dbg(component->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
 			bclk_divs[best], bclk_rate);
 
-		snd_soc_update_bits(codec, bclk_reg,
+		snd_soc_component_update_bits(component, bclk_reg,
 				    WM8996_AIF1_BCLK_DIV_MASK, best);
 	}
 }
 
-static int wm8996_set_bias_level(struct snd_soc_codec *codec,
+static int wm8996_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	switch (level) {
@@ -1584,18 +1583,18 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* Put the MICBIASes into regulating mode */
-		snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_1,
 				    WM8996_MICB1_MODE, 0);
-		snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_2,
 				    WM8996_MICB2_MODE, 0);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
 						    wm8996->supplies);
 			if (ret != 0) {
-				dev_err(codec->dev,
+				dev_err(component->dev,
 					"Failed to enable supplies: %d\n",
 					ret);
 				return ret;
@@ -1612,9 +1611,9 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
 		}
 
 		/* Bypass the MICBIASes for lowest power */
-		snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_1,
 				    WM8996_MICB1_MODE, WM8996_MICB1_MODE);
-		snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_2,
 				    WM8996_MICB2_MODE, WM8996_MICB2_MODE);
 		break;
 
@@ -1634,7 +1633,7 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
 
 static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int aifctrl = 0;
 	int bclk = 0;
 	int lrclk_tx = 0;
@@ -1711,15 +1710,15 @@ static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, aifctrl_reg, WM8996_AIF1_FMT_MASK, aifctrl);
-	snd_soc_update_bits(codec, bclk_reg,
+	snd_soc_component_update_bits(component, aifctrl_reg, WM8996_AIF1_FMT_MASK, aifctrl);
+	snd_soc_component_update_bits(component, bclk_reg,
 			    WM8996_AIF1_BCLK_INV | WM8996_AIF1_BCLK_MSTR,
 			    bclk);
-	snd_soc_update_bits(codec, lrclk_tx_reg,
+	snd_soc_component_update_bits(component, lrclk_tx_reg,
 			    WM8996_AIF1TX_LRCLK_INV |
 			    WM8996_AIF1TX_LRCLK_MSTR,
 			    lrclk_tx);
-	snd_soc_update_bits(codec, lrclk_rx_reg,
+	snd_soc_component_update_bits(component, lrclk_rx_reg,
 			    WM8996_AIF1RX_LRCLK_INV |
 			    WM8996_AIF1RX_LRCLK_MSTR,
 			    lrclk_rx);
@@ -1735,8 +1734,8 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int bits, i, bclk_rate, best;
 	int aifdata = 0;
 	int lrclk = 0;
@@ -1746,7 +1745,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 	switch (dai->id) {
 	case 0:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-		    (snd_soc_read(codec, WM8996_GPIO_1)) & WM8996_GP1_FN_MASK) {
+		    (snd_soc_component_read32(component, WM8996_GPIO_1)) & WM8996_GP1_FN_MASK) {
 			aifdata_reg = WM8996_AIF1RX_DATA_CONFIGURATION;
 			lrclk_reg = WM8996_AIF1_RX_LRCLK_1;
 		} else {
@@ -1757,7 +1756,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 		break;
 	case 1:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-		    (snd_soc_read(codec, WM8996_GPIO_2)) & WM8996_GP2_FN_MASK) {
+		    (snd_soc_component_read32(component, WM8996_GPIO_2)) & WM8996_GP2_FN_MASK) {
 			aifdata_reg = WM8996_AIF2RX_DATA_CONFIGURATION;
 			lrclk_reg = WM8996_AIF2_RX_LRCLK_1;
 		} else {
@@ -1773,7 +1772,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 
 	bclk_rate = snd_soc_params_to_bclk(params);
 	if (bclk_rate < 0) {
-		dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+		dev_err(component->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
 		return bclk_rate;
 	}
 
@@ -1794,19 +1793,19 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 	}
 	dsp |= i << dsp_shift;
 
-	wm8996_update_bclk(codec);
+	wm8996_update_bclk(component);
 
 	lrclk = bclk_rate / params_rate(params);
 	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
 		lrclk, bclk_rate / lrclk);
 
-	snd_soc_update_bits(codec, aifdata_reg,
+	snd_soc_component_update_bits(component, aifdata_reg,
 			    WM8996_AIF1TX_WL_MASK |
 			    WM8996_AIF1TX_SLOT_LEN_MASK,
 			    aifdata);
-	snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
+	snd_soc_component_update_bits(component, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
 			    lrclk);
-	snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2,
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_2,
 			    WM8996_DSP1_DIV_MASK << dsp_shift, dsp);
 
 	return 0;
@@ -1815,8 +1814,8 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
 static int wm8996_set_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int lfclk = 0;
 	int ratediv = 0;
 	int sync = WM8996_REG_SYNC;
@@ -1827,8 +1826,8 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
 		return 0;
 
 	/* Disable SYSCLK while we reconfigure */
-	old = snd_soc_read(codec, WM8996_AIF_CLOCKING_1) & WM8996_SYSCLK_ENA;
-	snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+	old = snd_soc_component_read32(component, WM8996_AIF_CLOCKING_1) & WM8996_SYSCLK_ENA;
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_1,
 			    WM8996_SYSCLK_ENA, 0);
 
 	switch (clk_id) {
@@ -1845,14 +1844,14 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
 		src = 2;
 		break;
 	default:
-		dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
+		dev_err(component->dev, "Unsupported clock source %d\n", clk_id);
 		return -EINVAL;
 	}
 
 	switch (wm8996->sysclk) {
 	case 5644800:
 	case 6144000:
-		snd_soc_update_bits(codec, WM8996_AIF_RATE,
+		snd_soc_component_update_bits(component, WM8996_AIF_RATE,
 				    WM8996_SYSCLK_RATE, 0);
 		break;
 	case 22579200:
@@ -1861,7 +1860,7 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
 		wm8996->sysclk /= 2;
 	case 11289600:
 	case 12288000:
-		snd_soc_update_bits(codec, WM8996_AIF_RATE,
+		snd_soc_component_update_bits(component, WM8996_AIF_RATE,
 				    WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE);
 		break;
 	case 32000:
@@ -1870,20 +1869,20 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
 		sync = 0;
 		break;
 	default:
-		dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
+		dev_warn(component->dev, "Unsupported clock rate %dHz\n",
 			 wm8996->sysclk);
 		return -EINVAL;
 	}
 
-	wm8996_update_bclk(codec);
+	wm8996_update_bclk(component);
 
-	snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_1,
 			    WM8996_SYSCLK_SRC_MASK | WM8996_SYSCLK_DIV_MASK,
 			    src << WM8996_SYSCLK_SRC_SHIFT | ratediv);
-	snd_soc_update_bits(codec, WM8996_CLOCKING_1, WM8996_LFCLK_ENA, lfclk);
-	snd_soc_update_bits(codec, WM8996_CONTROL_INTERFACE_1,
+	snd_soc_component_update_bits(component, WM8996_CLOCKING_1, WM8996_LFCLK_ENA, lfclk);
+	snd_soc_component_update_bits(component, WM8996_CONTROL_INTERFACE_1,
 			    WM8996_REG_SYNC, sync);
-	snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_1,
 			    WM8996_SYSCLK_ENA, old);
 
 	wm8996->sysclk_src = clk_id;
@@ -2002,11 +2001,11 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm8996_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
 	struct _fll_div fll_div;
 	unsigned long timeout, time_left;
 	int ret, reg, retry;
@@ -2017,15 +2016,15 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		return 0;
 
 	if (Fout == 0) {
-		dev_dbg(codec->dev, "FLL disabled\n");
+		dev_dbg(component->dev, "FLL disabled\n");
 
 		wm8996->fll_fref = 0;
 		wm8996->fll_fout = 0;
 
-		snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
+		snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_1,
 				    WM8996_FLL_ENA, 0);
 
-		wm8996_bg_disable(codec);
+		wm8996_bg_disable(component);
 
 		return 0;
 	}
@@ -2048,14 +2047,14 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		reg = 3;
 		break;
 	default:
-		dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+		dev_err(component->dev, "Unknown FLL source %d\n", ret);
 		return -EINVAL;
 	}
 
 	reg |= fll_div.fll_refclk_div << WM8996_FLL_REFCLK_DIV_SHIFT;
 	reg |= fll_div.fll_ref_freq << WM8996_FLL_REF_FREQ_SHIFT;
 
-	snd_soc_update_bits(codec, WM8996_FLL_CONTROL_5,
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_5,
 			    WM8996_FLL_REFCLK_DIV_MASK | WM8996_FLL_REF_FREQ |
 			    WM8996_FLL_REFCLK_SRC_MASK, reg);
 
@@ -2064,38 +2063,38 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 		reg |= WM8996_FLL_EFS_ENA | (3 << WM8996_FLL_LFSR_SEL_SHIFT);
 	else
 		reg |= 1 << WM8996_FLL_LFSR_SEL_SHIFT;
-	snd_soc_write(codec, WM8996_FLL_EFS_2, reg);
+	snd_soc_component_write(component, WM8996_FLL_EFS_2, reg);
 
-	snd_soc_update_bits(codec, WM8996_FLL_CONTROL_2,
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_2,
 			    WM8996_FLL_OUTDIV_MASK |
 			    WM8996_FLL_FRATIO_MASK,
 			    (fll_div.fll_outdiv << WM8996_FLL_OUTDIV_SHIFT) |
 			    (fll_div.fll_fratio));
 
-	snd_soc_write(codec, WM8996_FLL_CONTROL_3, fll_div.theta);
+	snd_soc_component_write(component, WM8996_FLL_CONTROL_3, fll_div.theta);
 
-	snd_soc_update_bits(codec, WM8996_FLL_CONTROL_4,
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_4,
 			    WM8996_FLL_N_MASK | WM8996_FLL_LOOP_GAIN_MASK,
 			    (fll_div.n << WM8996_FLL_N_SHIFT) |
 			    fll_div.fll_loop_gain);
 
-	snd_soc_write(codec, WM8996_FLL_EFS_1, fll_div.lambda);
+	snd_soc_component_write(component, WM8996_FLL_EFS_1, fll_div.lambda);
 
 	/* Enable the bandgap if it's not already enabled */
-	ret = snd_soc_read(codec, WM8996_FLL_CONTROL_1);
+	ret = snd_soc_component_read32(component, WM8996_FLL_CONTROL_1);
 	if (!(ret & WM8996_FLL_ENA))
-		wm8996_bg_enable(codec);
+		wm8996_bg_enable(component);
 
 	/* Clear any pending completions (eg, from failed startups) */
 	try_wait_for_completion(&wm8996->fll_lock);
 
-	snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_1,
 			    WM8996_FLL_ENA, WM8996_FLL_ENA);
 
 	/* The FLL supports live reconfiguration - kick that in case we were
 	 * already enabled.
 	 */
-	snd_soc_write(codec, WM8996_FLL_CONTROL_6, WM8996_FLL_SWITCH_CLK);
+	snd_soc_component_write(component, WM8996_FLL_CONTROL_6, WM8996_FLL_SWITCH_CLK);
 
 	/* Wait for the FLL to lock, using the interrupt if possible */
 	if (Fref > 1000000)
@@ -2121,16 +2120,16 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			break;
 		}
 
-		ret = snd_soc_read(codec, WM8996_INTERRUPT_RAW_STATUS_2);
+		ret = snd_soc_component_read32(component, WM8996_INTERRUPT_RAW_STATUS_2);
 		if (ret & WM8996_FLL_LOCK_STS)
 			break;
 	}
 	if (retry == 10) {
-		dev_err(codec->dev, "Timed out waiting for FLL\n");
+		dev_err(component->dev, "Timed out waiting for FLL\n");
 		ret = -ETIMEDOUT;
 	}
 
-	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+	dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
 	wm8996->fll_fref = Fref;
 	wm8996->fll_fout = Fout;
@@ -2237,11 +2236,11 @@ static void wm8996_free_gpio(struct wm8996_priv *wm8996)
  * will also detect inverted microphone ground connections and update
  * the polarity of the connections.
  */
-int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8996_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		  wm8996_polarity_fn polarity_cb)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	wm8996->jack = jack;
 	wm8996->detecting = true;
@@ -2249,12 +2248,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 	wm8996->jack_flips = 0;
 
 	if (wm8996->polarity_cb)
-		wm8996->polarity_cb(codec, 0);
+		wm8996->polarity_cb(component, 0);
 
 	/* Clear discarge to avoid noise during detection */
-	snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+	snd_soc_component_update_bits(component, WM8996_MICBIAS_1,
 			    WM8996_MICB1_DISCH, 0);
-	snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+	snd_soc_component_update_bits(component, WM8996_MICBIAS_2,
 			    WM8996_MICB2_DISCH, 0);
 
 	/* LDO2 powers the microphones, SYSCLK clocks detection */
@@ -2268,26 +2267,26 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 	/* We start off just enabling microphone detection - even a
 	 * plain headphone will trigger detection.
 	 */
-	snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
 			    WM8996_MICD_ENA, WM8996_MICD_ENA);
 
 	/* Slowest detection rate, gives debounce for initial detection */
-	snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
 			    WM8996_MICD_RATE_MASK,
 			    WM8996_MICD_RATE_MASK);
 
 	/* Enable interrupts and we're off */
-	snd_soc_update_bits(codec, WM8996_INTERRUPT_STATUS_2_MASK,
+	snd_soc_component_update_bits(component, WM8996_INTERRUPT_STATUS_2_MASK,
 			    WM8996_IM_MICD_EINT | WM8996_HP_DONE_EINT, 0);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(wm8996_detect);
 
-static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
+static void wm8996_hpdet_irq(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int val, reg, report;
 
 	/* Assume headphone in error conditions; we need to report
@@ -2295,20 +2294,20 @@ static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
 	 */
 	report = SND_JACK_HEADPHONE;
 
-	reg = snd_soc_read(codec, WM8996_HEADPHONE_DETECT_2);
+	reg = snd_soc_component_read32(component, WM8996_HEADPHONE_DETECT_2);
 	if (reg < 0) {
-		dev_err(codec->dev, "Failed to read HPDET status\n");
+		dev_err(component->dev, "Failed to read HPDET status\n");
 		goto out;
 	}
 
 	if (!(reg & WM8996_HP_DONE)) {
-		dev_err(codec->dev, "Got HPDET IRQ but HPDET is busy\n");
+		dev_err(component->dev, "Got HPDET IRQ but HPDET is busy\n");
 		goto out;
 	}
 
 	val = reg & WM8996_HP_LVL_MASK;
 
-	dev_dbg(codec->dev, "HPDET measured %d ohms\n", val);
+	dev_dbg(component->dev, "HPDET measured %d ohms\n", val);
 
 	/* If we've got high enough impedence then report as line,
 	 * otherwise assume headphone.
@@ -2328,28 +2327,28 @@ static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
 	wm8996->detecting = false;
 
 	/* If the output isn't running re-clamp it */
-	if (!(snd_soc_read(codec, WM8996_POWER_MANAGEMENT_1) &
+	if (!(snd_soc_component_read32(component, WM8996_POWER_MANAGEMENT_1) &
 	      (WM8996_HPOUT1L_ENA | WM8996_HPOUT1R_RMV_SHORT)))
-		snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
+		snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1,
 				    WM8996_HPOUT1L_RMV_SHORT |
 				    WM8996_HPOUT1R_RMV_SHORT, 0);
 
 	/* Go back to looking at the microphone */
-	snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_1,
+	snd_soc_component_update_bits(component, WM8996_ACCESSORY_DETECT_MODE_1,
 			    WM8996_JD_MODE_MASK, 0);
-	snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
 			    WM8996_MICD_ENA);
 
 	snd_soc_dapm_disable_pin(dapm, "Bandgap");
 	snd_soc_dapm_sync(dapm);
 }
 
-static void wm8996_hpdet_start(struct snd_soc_codec *codec)
+static void wm8996_hpdet_start(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	/* Unclamp the output, we can't measure while we're shorting it */
-	snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
+	snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1,
 			    WM8996_HPOUT1L_RMV_SHORT |
 			    WM8996_HPOUT1R_RMV_SHORT,
 			    WM8996_HPOUT1L_RMV_SHORT |
@@ -2360,45 +2359,45 @@ static void wm8996_hpdet_start(struct snd_soc_codec *codec)
 	snd_soc_dapm_sync(dapm);
 
 	/* Go into headphone detect left mode */
-	snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
-	snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_1,
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
+	snd_soc_component_update_bits(component, WM8996_ACCESSORY_DETECT_MODE_1,
 			    WM8996_JD_MODE_MASK, 1);
 
 	/* Trigger a measurement */
-	snd_soc_update_bits(codec, WM8996_HEADPHONE_DETECT_1,
+	snd_soc_component_update_bits(component, WM8996_HEADPHONE_DETECT_1,
 			    WM8996_HP_POLL, WM8996_HP_POLL);
 }
 
-static void wm8996_report_headphone(struct snd_soc_codec *codec)
+static void wm8996_report_headphone(struct snd_soc_component *component)
 {
-	dev_dbg(codec->dev, "Headphone detected\n");
-	wm8996_hpdet_start(codec);
+	dev_dbg(component->dev, "Headphone detected\n");
+	wm8996_hpdet_start(component);
 
 	/* Increase the detection rate a bit for responsiveness. */
-	snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
 			    WM8996_MICD_RATE_MASK |
 			    WM8996_MICD_BIAS_STARTTIME_MASK,
 			    7 << WM8996_MICD_RATE_SHIFT |
 			    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
 }
 
-static void wm8996_micd(struct snd_soc_codec *codec)
+static void wm8996_micd(struct snd_soc_component *component)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int val, reg;
 
-	val = snd_soc_read(codec, WM8996_MIC_DETECT_3);
+	val = snd_soc_component_read32(component, WM8996_MIC_DETECT_3);
 
-	dev_dbg(codec->dev, "Microphone event: %x\n", val);
+	dev_dbg(component->dev, "Microphone event: %x\n", val);
 
 	if (!(val & WM8996_MICD_VALID)) {
-		dev_warn(codec->dev, "Microphone detection state invalid\n");
+		dev_warn(component->dev, "Microphone detection state invalid\n");
 		return;
 	}
 
 	/* No accessory, reset everything and report removal */
 	if (!(val & WM8996_MICD_STS)) {
-		dev_dbg(codec->dev, "Jack removal detected\n");
+		dev_dbg(component->dev, "Jack removal detected\n");
 		wm8996->jack_mic = false;
 		wm8996->detecting = true;
 		wm8996->jack_flips = 0;
@@ -2406,7 +2405,7 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 				    SND_JACK_LINEOUT | SND_JACK_HEADSET |
 				    SND_JACK_BTN_0);
 
-		snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+		snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
 				    WM8996_MICD_RATE_MASK |
 				    WM8996_MICD_BIAS_STARTTIME_MASK,
 				    WM8996_MICD_RATE_MASK |
@@ -2420,19 +2419,19 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 	 */
 	if (val & 0x400) {
 		if (wm8996->detecting) {
-			dev_dbg(codec->dev, "Microphone detected\n");
+			dev_dbg(component->dev, "Microphone detected\n");
 			wm8996->jack_mic = true;
-			wm8996_hpdet_start(codec);
+			wm8996_hpdet_start(component);
 
 			/* Increase poll rate to give better responsiveness
 			 * for buttons */
-			snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+			snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
 					    WM8996_MICD_RATE_MASK |
 					    WM8996_MICD_BIAS_STARTTIME_MASK,
 					    5 << WM8996_MICD_RATE_SHIFT |
 					    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
 		} else {
-			dev_dbg(codec->dev, "Mic button up\n");
+			dev_dbg(component->dev, "Mic button up\n");
 			snd_soc_jack_report(wm8996->jack, 0, SND_JACK_BTN_0);
 		}
 
@@ -2449,22 +2448,22 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 		wm8996->jack_flips++;
 
 		if (wm8996->jack_flips > 1) {
-			wm8996_report_headphone(codec);
+			wm8996_report_headphone(component);
 			return;
 		}
 
-		reg = snd_soc_read(codec, WM8996_ACCESSORY_DETECT_MODE_2);
+		reg = snd_soc_component_read32(component, WM8996_ACCESSORY_DETECT_MODE_2);
 		reg ^= WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
 			WM8996_MICD_BIAS_SRC;
-		snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
+		snd_soc_component_update_bits(component, WM8996_ACCESSORY_DETECT_MODE_2,
 				    WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
 				    WM8996_MICD_BIAS_SRC, reg);
 
 		if (wm8996->polarity_cb)
-			wm8996->polarity_cb(codec,
+			wm8996->polarity_cb(component,
 					    (reg & WM8996_MICD_SRC) != 0);
 
-		dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+		dev_dbg(component->dev, "Set microphone polarity to %d\n",
 			(reg & WM8996_MICD_SRC) != 0);
 
 		return;
@@ -2475,52 +2474,52 @@ static void wm8996_micd(struct snd_soc_codec *codec)
 	 */
 	if (val & 0x3fc) {
 		if (wm8996->jack_mic) {
-			dev_dbg(codec->dev, "Mic button detected\n");
+			dev_dbg(component->dev, "Mic button detected\n");
 			snd_soc_jack_report(wm8996->jack, SND_JACK_BTN_0,
 					    SND_JACK_BTN_0);
 		} else if (wm8996->detecting) {
-			wm8996_report_headphone(codec);
+			wm8996_report_headphone(component);
 		}
 	}
 }
 
 static irqreturn_t wm8996_irq(int irq, void *data)
 {
-	struct snd_soc_codec *codec = data;
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = data;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	int irq_val;
 
-	irq_val = snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2);
+	irq_val = snd_soc_component_read32(component, WM8996_INTERRUPT_STATUS_2);
 	if (irq_val < 0) {
-		dev_err(codec->dev, "Failed to read IRQ status: %d\n",
+		dev_err(component->dev, "Failed to read IRQ status: %d\n",
 			irq_val);
 		return IRQ_NONE;
 	}
-	irq_val &= ~snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2_MASK);
+	irq_val &= ~snd_soc_component_read32(component, WM8996_INTERRUPT_STATUS_2_MASK);
 
 	if (!irq_val)
 		return IRQ_NONE;
 
-	snd_soc_write(codec, WM8996_INTERRUPT_STATUS_2, irq_val);
+	snd_soc_component_write(component, WM8996_INTERRUPT_STATUS_2, irq_val);
 
 	if (irq_val & (WM8996_DCS_DONE_01_EINT | WM8996_DCS_DONE_23_EINT)) {
-		dev_dbg(codec->dev, "DC servo IRQ\n");
+		dev_dbg(component->dev, "DC servo IRQ\n");
 		complete(&wm8996->dcs_done);
 	}
 
 	if (irq_val & WM8996_FIFOS_ERR_EINT)
-		dev_err(codec->dev, "Digital core FIFO error\n");
+		dev_err(component->dev, "Digital core FIFO error\n");
 
 	if (irq_val & WM8996_FLL_LOCK_EINT) {
-		dev_dbg(codec->dev, "FLL locked\n");
+		dev_dbg(component->dev, "FLL locked\n");
 		complete(&wm8996->fll_lock);
 	}
 
 	if (irq_val & WM8996_MICD_EINT)
-		wm8996_micd(codec);
+		wm8996_micd(component);
 
 	if (irq_val & WM8996_HP_DONE_EINT)
-		wm8996_hpdet_irq(codec);
+		wm8996_hpdet_irq(component);
 
 	return IRQ_HANDLED;
 }
@@ -2539,9 +2538,9 @@ static irqreturn_t wm8996_edge_irq(int irq, void *data)
 	return ret;
 }
 
-static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
+static void wm8996_retune_mobile_pdata(struct snd_soc_component *component)
 {
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
 	struct wm8996_pdata *pdata = &wm8996->pdata;
 
 	struct snd_kcontrol_new controls[] = {
@@ -2590,15 +2589,15 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
 		wm8996->retune_mobile_texts = t;
 	}
 
-	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+	dev_dbg(component->dev, "Allocated %d unique ReTune Mobile names\n",
 		wm8996->num_retune_mobile_texts);
 
 	wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts;
 	wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
 
-	ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
+	ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
 	if (ret != 0)
-		dev_err(codec->dev,
+		dev_err(component->dev,
 			"Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
@@ -2614,22 +2613,22 @@ static const struct regmap_config wm8996_regmap = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
-static int wm8996_probe(struct snd_soc_codec *codec)
+static int wm8996_probe(struct snd_soc_component *component)
 {
 	int ret;
-	struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
 	int irq_flags;
 
-	wm8996->codec = codec;
+	wm8996->component = component;
 
 	init_completion(&wm8996->dcs_done);
 	init_completion(&wm8996->fll_lock);
 
 	if (wm8996->pdata.num_retune_mobile_cfgs)
-		wm8996_retune_mobile_pdata(codec);
+		wm8996_retune_mobile_pdata(component);
 	else
-		snd_soc_add_codec_controls(codec, wm8996_eq_controls,
+		snd_soc_add_component_controls(component, wm8996_eq_controls,
 				     ARRAY_SIZE(wm8996_eq_controls));
 
 	if (i2c->irq) {
@@ -2643,18 +2642,18 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 		if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
 			ret = request_threaded_irq(i2c->irq, NULL,
 						   wm8996_edge_irq,
-						   irq_flags, "wm8996", codec);
+						   irq_flags, "wm8996", component);
 		else
 			ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
-						   irq_flags, "wm8996", codec);
+						   irq_flags, "wm8996", component);
 
 		if (ret == 0) {
 			/* Unmask the interrupt */
-			snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
+			snd_soc_component_update_bits(component, WM8996_INTERRUPT_CONTROL,
 					    WM8996_IM_IRQ, 0);
 
 			/* Enable error reporting and DC servo status */
-			snd_soc_update_bits(codec,
+			snd_soc_component_update_bits(component,
 					    WM8996_INTERRUPT_STATUS_2_MASK,
 					    WM8996_IM_DCS_DONE_23_EINT |
 					    WM8996_IM_DCS_DONE_01_EINT |
@@ -2662,7 +2661,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 					    WM8996_IM_FIFOS_ERR_EINT,
 					    0);
 		} else {
-			dev_err(codec->dev, "Failed to request IRQ: %d\n",
+			dev_err(component->dev, "Failed to request IRQ: %d\n",
 				ret);
 			return ret;
 		}
@@ -2671,34 +2670,33 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int wm8996_remove(struct snd_soc_codec *codec)
+static void wm8996_remove(struct snd_soc_component *component)
 {
-	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
 
-	snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
+	snd_soc_component_update_bits(component, WM8996_INTERRUPT_CONTROL,
 			    WM8996_IM_IRQ, WM8996_IM_IRQ);
 
 	if (i2c->irq)
-		free_irq(i2c->irq, codec);
-
-	return 0;
+		free_irq(i2c->irq, component);
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
-	.probe =	wm8996_probe,
-	.remove =	wm8996_remove,
-	.set_bias_level = wm8996_set_bias_level,
-	.idle_bias_off	= true,
-	.seq_notifier = wm8996_seq_notifier,
-	.component_driver = {
-		.controls		= wm8996_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8996_snd_controls),
-		.dapm_widgets		= wm8996_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8996_dapm_widgets),
-		.dapm_routes		= wm8996_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8996_dapm_routes),
-	},
-	.set_pll = wm8996_set_fll,
+static const struct snd_soc_component_driver soc_component_dev_wm8996 = {
+	.probe			= wm8996_probe,
+	.remove			= wm8996_remove,
+	.set_bias_level		= wm8996_set_bias_level,
+	.seq_notifier		= wm8996_seq_notifier,
+	.controls		= wm8996_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8996_snd_controls),
+	.dapm_widgets		= wm8996_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8996_dapm_widgets),
+	.dapm_routes		= wm8996_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8996_dapm_routes),
+	.set_pll		= wm8996_set_fll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
 };
 
 #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
@@ -3046,8 +3044,8 @@ static int wm8996_i2c_probe(struct i2c_client *i2c,
 
 	wm8996_init_gpio(wm8996);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-				     &soc_codec_dev_wm8996, wm8996_dai,
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8996, wm8996_dai,
 				     ARRAY_SIZE(wm8996_dai));
 	if (ret < 0)
 		goto err_gpiolib;
@@ -3074,7 +3072,6 @@ static int wm8996_i2c_remove(struct i2c_client *client)
 	struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
 	int i;
 
-	snd_soc_unregister_codec(&client->dev);
 	wm8996_free_gpio(wm8996);
 	if (wm8996->pdata.ldo_ena > 0) {
 		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
diff --git a/sound/soc/codecs/wm8996.h b/sound/soc/codecs/wm8996.h
index de9ac3e44aec..b38769958752 100644
--- a/sound/soc/codecs/wm8996.h
+++ b/sound/soc/codecs/wm8996.h
@@ -22,9 +22,9 @@
 #define WM8996_FLL_DACLRCLK1  3
 #define WM8996_FLL_BCLK1      4
 
-typedef void (*wm8996_polarity_fn)(struct snd_soc_codec *codec, int polarity);
+typedef void (*wm8996_polarity_fn)(struct snd_soc_component *component, int polarity);
 
-int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+int wm8996_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
 		  wm8996_polarity_fn polarity_cb);
 
 /*
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index cac9b3e7e15d..45ee1e6bf715 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -84,8 +84,8 @@ static const struct reg_default wm8997_sysclk_reva_patch[] = {
 static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
 			    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
 	struct regmap *regmap = arizona->regmap;
 	const struct reg_default *patch = NULL;
 	int i, patch_size;
@@ -927,10 +927,10 @@ static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {
 	{ "MICSUPP", NULL, "SYSCLK" },
 };
 
-static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm8997_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm8997_priv *wm8997 = snd_soc_codec_get_drvdata(codec);
+	struct wm8997_priv *wm8997 = snd_soc_component_get_drvdata(component);
 
 	switch (fll_id) {
 	case WM8997_FLL1:
@@ -1057,17 +1057,16 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
 	},
 };
 
-static int wm8997_codec_probe(struct snd_soc_codec *codec)
+static int wm8997_component_probe(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-	struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = priv->core.arizona;
 	int ret;
 
-	snd_soc_codec_init_regmap(codec, arizona->regmap);
+	snd_soc_component_init_regmap(component, arizona->regmap);
 
-	ret = arizona_init_spk(codec);
+	ret = arizona_init_spk(component);
 	if (ret < 0)
 		return ret;
 
@@ -1078,13 +1077,11 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int wm8997_codec_remove(struct snd_soc_codec *codec)
+static void wm8997_component_remove(struct snd_soc_component *component)
 {
-	struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
 
 	priv->core.arizona->dapm = NULL;
-
-	return 0;
 }
 
 #define WM8997_DIG_VU 0x0200
@@ -1098,23 +1095,20 @@ static unsigned int wm8997_digital_vu[] = {
 	ARIZONA_DAC_DIGITAL_VOLUME_5R,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
-	.probe = wm8997_codec_probe,
-	.remove = wm8997_codec_remove,
-
-	.idle_bias_off = true,
-
-	.set_sysclk = arizona_set_sysclk,
-	.set_pll = wm8997_set_fll,
-
-	.component_driver = {
-		.controls		= wm8997_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8997_snd_controls),
-		.dapm_widgets		= wm8997_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8997_dapm_widgets),
-		.dapm_routes		= wm8997_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8997_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8997 = {
+	.probe			= wm8997_component_probe,
+	.remove			= wm8997_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm8997_set_fll,
+	.controls		= wm8997_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8997_snd_controls),
+	.dapm_widgets		= wm8997_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8997_dapm_widgets),
+	.dapm_routes		= wm8997_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8997_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8997_probe(struct platform_device *pdev)
@@ -1178,10 +1172,11 @@ static int wm8997_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				     &soc_component_dev_wm8997,
 				     wm8997_dai, ARRAY_SIZE(wm8997_dai));
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
 		goto err_spk_irqs;
 	}
 
@@ -1196,7 +1191,6 @@ static int wm8997_remove(struct platform_device *pdev)
 	struct wm8997_priv *wm8997 = platform_get_drvdata(pdev);
 	struct arizona *arizona = wm8997->core.arizona;
 
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	arizona_free_spk_irqs(arizona);
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 1288e1f67dcf..6f3fdd7b095e 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -41,12 +41,12 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *kcontrol,
 			  int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	unsigned int val;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		val = snd_soc_read(codec, ARIZONA_ASRC_RATE1);
+		val = snd_soc_component_read32(component, ARIZONA_ASRC_RATE1);
 		val &= ARIZONA_ASRC_RATE1_MASK;
 		val >>= ARIZONA_ASRC_RATE1_SHIFT;
 
@@ -54,23 +54,23 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
 		case 0:
 		case 1:
 		case 2:
-			val = snd_soc_read(codec,
+			val = snd_soc_component_read32(component,
 					   ARIZONA_SAMPLE_RATE_1 + val);
 			if (val >= 0x11) {
-				dev_warn(codec->dev,
+				dev_warn(component->dev,
 					 "Unsupported ASRC rate1 (%s)\n",
 					 arizona_sample_rate_val_to_name(val));
 			return -EINVAL;
 			}
 			break;
 		default:
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Illegal ASRC rate1 selector (0x%x)\n",
 				val);
 			return -EINVAL;
 		}
 
-		val = snd_soc_read(codec, ARIZONA_ASRC_RATE2);
+		val = snd_soc_component_read32(component, ARIZONA_ASRC_RATE2);
 		val &= ARIZONA_ASRC_RATE2_MASK;
 		val >>= ARIZONA_ASRC_RATE2_SHIFT;
 
@@ -78,17 +78,17 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
 		case 8:
 		case 9:
 			val -= 0x8;
-			val = snd_soc_read(codec,
+			val = snd_soc_component_read32(component,
 					   ARIZONA_ASYNC_SAMPLE_RATE_1 + val);
 			if (val >= 0x11) {
-				dev_warn(codec->dev,
+				dev_warn(component->dev,
 					 "Unsupported ASRC rate2 (%s)\n",
 					 arizona_sample_rate_val_to_name(val));
 				return -EINVAL;
 			}
 			break;
 		default:
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Illegal ASRC rate2 selector (0x%x)\n",
 				val);
 			return -EINVAL;
@@ -104,9 +104,9 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
 static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
 	struct arizona *arizona = wm8998->core.arizona;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int mode_reg, mode_index;
@@ -137,9 +137,9 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
 	if (inmode & ARIZONA_INMODE_SE)
 		src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
 
-	snd_soc_update_bits(codec, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val);
+	snd_soc_component_update_bits(component, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val);
 
-	snd_soc_update_bits(codec, e->reg,
+	snd_soc_component_update_bits(component, e->reg,
 			    ARIZONA_IN1L_SRC_MASK | ARIZONA_IN1L_SRC_SE_MASK,
 			    src_val);
 
@@ -1249,10 +1249,10 @@ static struct snd_soc_dai_driver wm8998_dai[] = {
 	},
 };
 
-static int wm8998_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+static int wm8998_set_fll(struct snd_soc_component *component, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
+	struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
 
 	switch (fll_id) {
 	case WM8998_FLL1:
@@ -1270,35 +1270,32 @@ static int wm8998_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 	}
 }
 
-static int wm8998_codec_probe(struct snd_soc_codec *codec)
+static int wm8998_component_probe(struct snd_soc_component *component)
 {
-	struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct arizona *arizona = priv->core.arizona;
 	int ret;
 
 	arizona->dapm = dapm;
-	snd_soc_codec_init_regmap(codec, arizona->regmap);
+	snd_soc_component_init_regmap(component, arizona->regmap);
 
-	ret = arizona_init_spk(codec);
+	ret = arizona_init_spk(component);
 	if (ret < 0)
 		return ret;
 
-	arizona_init_gpio(codec);
+	arizona_init_gpio(component);
 
 	snd_soc_component_disable_pin(component, "HAPTICS");
 
 	return 0;
 }
 
-static int wm8998_codec_remove(struct snd_soc_codec *codec)
+static void wm8998_component_remove(struct snd_soc_component *component)
 {
-	struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
 
 	priv->core.arizona->dapm = NULL;
-
-	return 0;
 }
 
 #define WM8998_DIG_VU 0x0200
@@ -1315,23 +1312,20 @@ static unsigned int wm8998_digital_vu[] = {
 	ARIZONA_DAC_DIGITAL_VOLUME_5R,
 };
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm8998 = {
-	.probe = wm8998_codec_probe,
-	.remove = wm8998_codec_remove,
-
-	.idle_bias_off = true,
-
-	.set_sysclk = arizona_set_sysclk,
-	.set_pll = wm8998_set_fll,
-
-	.component_driver = {
-		.controls		= wm8998_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm8998_snd_controls),
-		.dapm_widgets		= wm8998_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm8998_dapm_widgets),
-		.dapm_routes		= wm8998_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(wm8998_dapm_routes),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm8998 = {
+	.probe			= wm8998_component_probe,
+	.remove			= wm8998_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm8998_set_fll,
+	.controls		= wm8998_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8998_snd_controls),
+	.dapm_widgets		= wm8998_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8998_dapm_widgets),
+	.dapm_routes		= wm8998_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8998_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm8998_probe(struct platform_device *pdev)
@@ -1384,10 +1378,11 @@ static int wm8998_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				     &soc_component_dev_wm8998,
 				     wm8998_dai, ARRAY_SIZE(wm8998_dai));
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
 		goto err_spk_irqs;
 	}
 
@@ -1404,7 +1399,6 @@ static int wm8998_remove(struct platform_device *pdev)
 	struct wm8998_priv *wm8998 = platform_get_drvdata(pdev);
 	struct arizona *arizona = wm8998->core.arizona;
 
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	arizona_free_spk_irqs(arizona);
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 6febef337dd2..5a0ea7b3c149 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -339,10 +339,10 @@ static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
 static int speaker_mode_get(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+	reg = snd_soc_component_read32(component, WM9081_ANALOGUE_SPEAKER_2);
 	if (reg & WM9081_SPK_MODE)
 		ucontrol->value.enumerated.item[0] = 1;
 	else
@@ -360,9 +360,9 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,
 static int speaker_mode_put(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
-	unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg_pwr = snd_soc_component_read32(component, WM9081_POWER_MANAGEMENT);
+	unsigned int reg2 = snd_soc_component_read32(component, WM9081_ANALOGUE_SPEAKER_2);
 
 	/* Are we changing anything? */
 	if (ucontrol->value.enumerated.item[0] ==
@@ -383,7 +383,7 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol,
 		reg2 &= ~WM9081_SPK_MODE;
 	}
 
-	snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2);
+	snd_soc_component_write(component, WM9081_ANALOGUE_SPEAKER_2, reg2);
 
 	return 0;
 }
@@ -546,10 +546,10 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 }
 
-static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
+static int wm9081_set_fll(struct snd_soc_component *component, int fll_id,
 			  unsigned int Fref, unsigned int Fout)
 {
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 	u16 reg1, reg4, reg5;
 	struct _fll_div fll_div;
 	int ret;
@@ -561,7 +561,7 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
 
 	/* Disable the FLL */
 	if (Fout == 0) {
-		dev_dbg(codec->dev, "FLL disabled\n");
+		dev_dbg(component->dev, "FLL disabled\n");
 		wm9081->fll_fref = 0;
 		wm9081->fll_fout = 0;
 
@@ -572,7 +572,7 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
 	if (ret != 0)
 		return ret;
 
-	reg5 = snd_soc_read(codec, WM9081_FLL_CONTROL_5);
+	reg5 = snd_soc_component_read32(component, WM9081_FLL_CONTROL_5);
 	reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
 
 	switch (fll_id) {
@@ -581,55 +581,55 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
 		break;
 
 	default:
-		dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
+		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
 		return -EINVAL;
 	}
 
 	/* Disable CLK_SYS while we reconfigure */
-	clk_sys_reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
+	clk_sys_reg = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_3);
 	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
-		snd_soc_write(codec, WM9081_CLOCK_CONTROL_3,
+		snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3,
 			     clk_sys_reg & ~WM9081_CLK_SYS_ENA);
 
 	/* Any FLL configuration change requires that the FLL be
 	 * disabled first. */
-	reg1 = snd_soc_read(codec, WM9081_FLL_CONTROL_1);
+	reg1 = snd_soc_component_read32(component, WM9081_FLL_CONTROL_1);
 	reg1 &= ~WM9081_FLL_ENA;
-	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1);
 
 	/* Apply the configuration */
 	if (fll_div.k)
 		reg1 |= WM9081_FLL_FRAC_MASK;
 	else
 		reg1 &= ~WM9081_FLL_FRAC_MASK;
-	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1);
 
-	snd_soc_write(codec, WM9081_FLL_CONTROL_2,
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_2,
 		     (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
 		     (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
-	snd_soc_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_3, fll_div.k);
 
-	reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4);
+	reg4 = snd_soc_component_read32(component, WM9081_FLL_CONTROL_4);
 	reg4 &= ~WM9081_FLL_N_MASK;
 	reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
-	snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4);
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_4, reg4);
 
 	reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
 	reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
-	snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5);
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_5, reg5);
 
 	/* Set gain to the recommended value */
-	snd_soc_update_bits(codec, WM9081_FLL_CONTROL_4,
+	snd_soc_component_update_bits(component, WM9081_FLL_CONTROL_4,
 			    WM9081_FLL_GAIN_MASK, 0);
 
 	/* Enable the FLL */
-	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
 
 	/* Then bring CLK_SYS up again if it was disabled */
 	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
-		snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
+		snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
 
-	dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+	dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
 
 	wm9081->fll_fref = Fref;
 	wm9081->fll_fout = Fout;
@@ -637,9 +637,9 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
 	return 0;
 }
 
-static int configure_clock(struct snd_soc_codec *codec)
+static int configure_clock(struct snd_soc_component *component)
 {
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 	int new_sysclk, i, target;
 	unsigned int reg;
 	int ret = 0;
@@ -654,7 +654,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 		} else {
 			wm9081->sysclk_rate = wm9081->mclk_rate;
 		}
-		wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, 0, 0);
+		wm9081_set_fll(component, WM9081_SYSCLK_FLL_MCLK, 0, 0);
 		break;
 
 	case WM9081_SYSCLK_FLL_MCLK:
@@ -695,7 +695,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 			new_sysclk = 12288000;
 		}
 
-		ret = wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK,
+		ret = wm9081_set_fll(component, WM9081_SYSCLK_FLL_MCLK,
 				     wm9081->mclk_rate, new_sysclk);
 		if (ret == 0) {
 			wm9081->sysclk_rate = new_sysclk;
@@ -711,21 +711,21 @@ static int configure_clock(struct snd_soc_codec *codec)
 		return -EINVAL;
 	}
 
-	reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_1);
+	reg = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_1);
 	if (mclkdiv)
 		reg |= WM9081_MCLKDIV2;
 	else
 		reg &= ~WM9081_MCLKDIV2;
-	snd_soc_write(codec, WM9081_CLOCK_CONTROL_1, reg);
+	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_1, reg);
 
-	reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
+	reg = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_3);
 	if (fll)
 		reg |= WM9081_CLK_SRC_SEL;
 	else
 		reg &= ~WM9081_CLK_SRC_SEL;
-	snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, reg);
+	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3, reg);
 
-	dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
+	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
 
 	return ret;
 }
@@ -733,31 +733,31 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 
 	/* This should be done on init() for bypass paths */
 	switch (wm9081->sysclk_source) {
 	case WM9081_SYSCLK_MCLK:
-		dev_dbg(codec->dev, "Using %dHz MCLK\n", wm9081->mclk_rate);
+		dev_dbg(component->dev, "Using %dHz MCLK\n", wm9081->mclk_rate);
 		break;
 	case WM9081_SYSCLK_FLL_MCLK:
-		dev_dbg(codec->dev, "Using %dHz MCLK with FLL\n",
+		dev_dbg(component->dev, "Using %dHz MCLK with FLL\n",
 			wm9081->mclk_rate);
 		break;
 	default:
-		dev_err(codec->dev, "System clock not configured\n");
+		dev_err(component->dev, "System clock not configured\n");
 		return -EINVAL;
 	}
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		configure_clock(codec);
+		configure_clock(component);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		/* Disable the FLL if it's running */
-		wm9081_set_fll(codec, 0, 0, 0);
+		wm9081_set_fll(component, 0, 0, 0);
 		break;
 	}
 
@@ -816,10 +816,10 @@ static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
 	{ "SPKP", NULL, "Speaker" },
 };
 
-static int wm9081_set_bias_level(struct snd_soc_codec *codec,
+static int wm9081_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
@@ -827,31 +827,31 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_PREPARE:
 		/* VMID=2*40k */
-		snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
 				    WM9081_VMID_SEL_MASK, 0x2);
 
 		/* Normal bias current */
-		snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
 				    WM9081_STBY_BIAS_ENA, 0);
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
 		/* Initial cold start */
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			regcache_cache_only(wm9081->regmap, false);
 			regcache_sync(wm9081->regmap);
 
 			/* Disable LINEOUT discharge */
-			snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL,
+			snd_soc_component_update_bits(component, WM9081_ANTI_POP_CONTROL,
 					    WM9081_LINEOUT_DISCH, 0);
 
 			/* Select startup bias source */
-			snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+			snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
 					    WM9081_BIAS_SRC | WM9081_BIAS_ENA,
 					    WM9081_BIAS_SRC | WM9081_BIAS_ENA);
 
 			/* VMID 2*4k; Soft VMID ramp enable */
-			snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+			snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
 					    WM9081_VMID_RAMP |
 					    WM9081_VMID_SEL_MASK,
 					    WM9081_VMID_RAMP | 0x6);
@@ -859,37 +859,37 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
 			mdelay(100);
 
 			/* Normal bias enable & soft start off */
-			snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+			snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
 					    WM9081_VMID_RAMP, 0);
 
 			/* Standard bias source */
-			snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+			snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
 					    WM9081_BIAS_SRC, 0);
 		}
 
 		/* VMID 2*240k */
-		snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
 				    WM9081_VMID_SEL_MASK, 0x04);
 
 		/* Standby bias current on */
-		snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
 				    WM9081_STBY_BIAS_ENA,
 				    WM9081_STBY_BIAS_ENA);
 		break;
 
 	case SND_SOC_BIAS_OFF:
 		/* Startup bias source and disable bias */
-		snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
 				    WM9081_BIAS_SRC | WM9081_BIAS_ENA,
 				    WM9081_BIAS_SRC);
 
 		/* Disable VMID with soft ramping */
-		snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
 				    WM9081_VMID_RAMP | WM9081_VMID_SEL_MASK,
 				    WM9081_VMID_RAMP);
 
 		/* Actively discharge LINEOUT */
-		snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL,
+		snd_soc_component_update_bits(component, WM9081_ANTI_POP_CONTROL,
 				    WM9081_LINEOUT_DISCH,
 				    WM9081_LINEOUT_DISCH);
 
@@ -903,9 +903,9 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
 static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
 			      unsigned int fmt)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
-	unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
+	struct snd_soc_component *component = dai->component;
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	unsigned int aif2 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_2);
 
 	aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
 		  WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
@@ -986,7 +986,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_2, aif2);
 
 	return 0;
 }
@@ -995,23 +995,23 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = dai->component;
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 	int ret, i, best, best_val, cur_val;
 	unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
 
-	clk_ctrl2 = snd_soc_read(codec, WM9081_CLOCK_CONTROL_2);
+	clk_ctrl2 = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_2);
 	clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
 
-	aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
+	aif1 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_1);
 
-	aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
+	aif2 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_2);
 	aif2 &= ~WM9081_AIF_WL_MASK;
 
-	aif3 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_3);
+	aif3 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_3);
 	aif3 &= ~WM9081_BCLK_DIV_MASK;
 
-	aif4 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_4);
+	aif4 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_4);
 	aif4 &= ~WM9081_LRCLK_RATE_MASK;
 
 	wm9081->fs = params_rate(params);
@@ -1047,9 +1047,9 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm9081->bclk);
+	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm9081->bclk);
 
-	ret = configure_clock(codec);
+	ret = configure_clock(component);
 	if (ret != 0)
 		return ret;
 
@@ -1065,7 +1065,7 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
 			best_val = cur_val;
 		}
 	}
-	dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
+	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
 		clk_sys_rates[best].ratio);
 	clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate
 		      << WM9081_CLK_SYS_RATE_SHIFT);
@@ -1081,7 +1081,7 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
 			best_val = cur_val;
 		}
 	}
-	dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
+	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
 		sample_rates[best].rate);
 	clk_ctrl2 |= (sample_rates[best].sample_rate
 			<< WM9081_SAMPLE_RATE_SHIFT);
@@ -1100,12 +1100,12 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 	wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div;
-	dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
 		bclk_divs[best].div, wm9081->bclk);
 	aif3 |= bclk_divs[best].bclk_div;
 
 	/* LRCLK is a simple fraction of BCLK */
-	dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs);
+	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs);
 	aif4 |= wm9081->bclk / wm9081->fs;
 
 	/* Apply a ReTune Mobile configuration if it's in use */
@@ -1126,51 +1126,51 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
 		}
 		s = &pdata->retune_configs[best];
 
-		dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
+		dev_dbg(component->dev, "ReTune Mobile %s tuned for %dHz\n",
 			s->name, s->rate);
 
 		/* If the EQ is enabled then disable it while we write out */
-		eq1 = snd_soc_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA;
+		eq1 = snd_soc_component_read32(component, WM9081_EQ_1) & WM9081_EQ_ENA;
 		if (eq1 & WM9081_EQ_ENA)
-			snd_soc_write(codec, WM9081_EQ_1, 0);
+			snd_soc_component_write(component, WM9081_EQ_1, 0);
 
 		/* Write out the other values */
 		for (i = 1; i < ARRAY_SIZE(s->config); i++)
-			snd_soc_write(codec, WM9081_EQ_1 + i, s->config[i]);
+			snd_soc_component_write(component, WM9081_EQ_1 + i, s->config[i]);
 
 		eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
-		snd_soc_write(codec, WM9081_EQ_1, eq1);
+		snd_soc_component_write(component, WM9081_EQ_1, eq1);
 	}
 
-	snd_soc_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
-	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
-	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_3, aif3);
-	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_4, aif4);
+	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_2, aif2);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_3, aif3);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_4, aif4);
 
 	return 0;
 }
 
 static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	unsigned int reg;
 
-	reg = snd_soc_read(codec, WM9081_DAC_DIGITAL_2);
+	reg = snd_soc_component_read32(component, WM9081_DAC_DIGITAL_2);
 
 	if (mute)
 		reg |= WM9081_DAC_MUTE;
 	else
 		reg &= ~WM9081_DAC_MUTE;
 
-	snd_soc_write(codec, WM9081_DAC_DIGITAL_2, reg);
+	snd_soc_component_write(component, WM9081_DAC_DIGITAL_2, reg);
 
 	return 0;
 }
 
-static int wm9081_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+static int wm9081_set_sysclk(struct snd_soc_component *component, int clk_id,
 			     int source, unsigned int freq, int dir)
 {
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 
 	switch (clk_id) {
 	case WM9081_SYSCLK_MCLK:
@@ -1189,9 +1189,9 @@ static int wm9081_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
-	unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
+	struct snd_soc_component *component = dai->component;
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	unsigned int aif1 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_1);
 
 	aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
 
@@ -1221,7 +1221,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
 		return -EINVAL;
 	}
 
-	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_1, aif1);
 
 	return 0;
 }
@@ -1254,42 +1254,39 @@ static struct snd_soc_dai_driver wm9081_dai = {
 	.ops = &wm9081_dai_ops,
 };
 
-static int wm9081_probe(struct snd_soc_codec *codec)
+static int wm9081_probe(struct snd_soc_component *component)
 {
-	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
 
 	/* Enable zero cross by default */
-	snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT,
+	snd_soc_component_update_bits(component, WM9081_ANALOGUE_LINEOUT,
 			    WM9081_LINEOUTZC, WM9081_LINEOUTZC);
-	snd_soc_update_bits(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+	snd_soc_component_update_bits(component, WM9081_ANALOGUE_SPEAKER_PGA,
 			    WM9081_SPKPGAZC, WM9081_SPKPGAZC);
 
 	if (!wm9081->pdata.num_retune_configs) {
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			"No ReTune Mobile data, using normal EQ\n");
-		snd_soc_add_codec_controls(codec, wm9081_eq_controls,
+		snd_soc_add_component_controls(component, wm9081_eq_controls,
 				     ARRAY_SIZE(wm9081_eq_controls));
 	}
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
-	.probe = 	wm9081_probe,
-
-	.set_sysclk = wm9081_set_sysclk,
-	.set_bias_level = wm9081_set_bias_level,
-
-	.idle_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm9081_snd_controls,
-		.num_controls		= ARRAY_SIZE(wm9081_snd_controls),
-		.dapm_widgets		= wm9081_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm9081_dapm_widgets),
-		.dapm_routes		= wm9081_audio_paths,
-		.num_dapm_routes	= ARRAY_SIZE(wm9081_audio_paths),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm9081 = {
+	.probe			= wm9081_probe,
+	.set_sysclk		= wm9081_set_sysclk,
+	.set_bias_level		= wm9081_set_bias_level,
+	.controls		= wm9081_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm9081_snd_controls),
+	.dapm_widgets		= wm9081_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9081_dapm_widgets),
+	.dapm_routes		= wm9081_audio_paths,
+	.num_dapm_routes	= ARRAY_SIZE(wm9081_audio_paths),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm9081_regmap = {
@@ -1355,8 +1352,8 @@ static int wm9081_i2c_probe(struct i2c_client *i2c,
 
 	regcache_cache_only(wm9081->regmap, true);
 
-	ret = snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm9081, &wm9081_dai, 1);
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm9081, &wm9081_dai, 1);
 	if (ret < 0)
 		return ret;
 
@@ -1365,7 +1362,6 @@ static int wm9081_i2c_probe(struct i2c_client *i2c,
 
 static int wm9081_i2c_remove(struct i2c_client *client)
 {
-	snd_soc_unregister_codec(&client->dev);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 5a131385cb2f..a9f1a0360a19 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -143,23 +143,23 @@ static bool wm9090_readable(struct device *dev, unsigned int reg)
 	}
 }
 
-static void wait_for_dc_servo(struct snd_soc_codec *codec)
+static void wait_for_dc_servo(struct snd_soc_component *component)
 {
 	unsigned int reg;
 	int count = 0;
 
-	dev_dbg(codec->dev, "Waiting for DC servo...\n");
+	dev_dbg(component->dev, "Waiting for DC servo...\n");
 	do {
 		count++;
 		msleep(1);
-		reg = snd_soc_read(codec, WM9090_DC_SERVO_READBACK_0);
-		dev_dbg(codec->dev, "DC servo status: %x\n", reg);
+		reg = snd_soc_component_read32(component, WM9090_DC_SERVO_READBACK_0);
+		dev_dbg(component->dev, "DC servo status: %x\n", reg);
 	} while ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
 		 != WM9090_DCS_CAL_COMPLETE_MASK && count < 1000);
 
 	if ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
 	    != WM9090_DCS_CAL_COMPLETE_MASK)
-		dev_err(codec->dev, "Timed out waiting for DC Servo\n");
+		dev_err(component->dev, "Timed out waiting for DC Servo\n");
 }
 
 static const DECLARE_TLV_DB_RANGE(in_tlv,
@@ -251,22 +251,22 @@ SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
 static int hp_ev(struct snd_soc_dapm_widget *w,
 		 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int reg = snd_soc_component_read32(component, WM9090_ANALOGUE_HP_0);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, WM9090_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, WM9090_CHARGE_PUMP_1,
 				    WM9090_CP_ENA, WM9090_CP_ENA);
 
 		msleep(5);
 
-		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
 				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
 				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA);
 
 		reg |= WM9090_HPOUT1L_DLY | WM9090_HPOUT1R_DLY;
-		snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
+		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
 
 		/* Start the DC servo.  We don't currently use the
 		 * ability to save the state since we don't have full
@@ -274,16 +274,16 @@ static int hp_ev(struct snd_soc_dapm_widget *w,
 		 * DC offsets; see the WM8904 driver for an example of
 		 * doing so.
 		 */
-		snd_soc_write(codec, WM9090_DC_SERVO_0,
+		snd_soc_component_write(component, WM9090_DC_SERVO_0,
 			      WM9090_DCS_ENA_CHAN_0 |
 			      WM9090_DCS_ENA_CHAN_1 |
 			      WM9090_DCS_TRIG_STARTUP_1 |
 			      WM9090_DCS_TRIG_STARTUP_0);
-		wait_for_dc_servo(codec);
+		wait_for_dc_servo(component);
 
 		reg |= WM9090_HPOUT1R_OUTP | WM9090_HPOUT1R_RMV_SHORT |
 			WM9090_HPOUT1L_OUTP | WM9090_HPOUT1L_RMV_SHORT;
-		snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
+		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
@@ -294,15 +294,15 @@ static int hp_ev(struct snd_soc_dapm_widget *w,
 			 WM9090_HPOUT1R_DLY |
 			 WM9090_HPOUT1R_OUTP);
 
-		snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
+		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
 
-		snd_soc_write(codec, WM9090_DC_SERVO_0, 0);
+		snd_soc_component_write(component, WM9090_DC_SERVO_0, 0);
 
-		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
 				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
 				    0);
 
-		snd_soc_update_bits(codec, WM9090_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, WM9090_CHARGE_PUMP_1,
 				    WM9090_CP_ENA, 0);
 		break;
 	}
@@ -419,10 +419,10 @@ static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
 	{ "IN2A PGA", NULL, "IN2-" },	
 };
 
-static int wm9090_add_controls(struct snd_soc_codec *codec)
+static int wm9090_add_controls(struct snd_soc_component *component)
 {
-	struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int i;
 
 	snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
@@ -430,7 +430,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec)
 
 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-	snd_soc_add_codec_controls(codec, wm9090_controls,
+	snd_soc_add_component_controls(component, wm9090_controls,
 			     ARRAY_SIZE(wm9090_controls));
 
 	if (wm9090->pdata.lin1_diff) {
@@ -439,7 +439,7 @@ static int wm9090_add_controls(struct snd_soc_codec *codec)
 	} else {
 		snd_soc_dapm_add_routes(dapm, audio_map_in1_se,
 					ARRAY_SIZE(audio_map_in1_se));
-		snd_soc_add_codec_controls(codec, wm9090_in1_se_controls,
+		snd_soc_add_component_controls(component, wm9090_in1_se_controls,
 				     ARRAY_SIZE(wm9090_in1_se_controls));
 	}
 
@@ -449,18 +449,18 @@ static int wm9090_add_controls(struct snd_soc_codec *codec)
 	} else {
 		snd_soc_dapm_add_routes(dapm, audio_map_in2_se,
 					ARRAY_SIZE(audio_map_in2_se));
-		snd_soc_add_codec_controls(codec, wm9090_in2_se_controls,
+		snd_soc_add_component_controls(component, wm9090_in2_se_controls,
 				     ARRAY_SIZE(wm9090_in2_se_controls));
 	}
 
 	if (wm9090->pdata.agc_ena) {
 		for (i = 0; i < ARRAY_SIZE(wm9090->pdata.agc); i++)
-			snd_soc_write(codec, WM9090_AGC_CONTROL_0 + i,
+			snd_soc_component_write(component, WM9090_AGC_CONTROL_0 + i,
 				      wm9090->pdata.agc[i]);
-		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_3,
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_3,
 				    WM9090_AGC_ENA, WM9090_AGC_ENA);
 	} else {
-		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_3,
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_3,
 				    WM9090_AGC_ENA, 0);
 	}
 
@@ -472,19 +472,19 @@ static int wm9090_add_controls(struct snd_soc_codec *codec)
  * The machine driver should call this from their set_bias_level; if there
  * isn't one then this can just be set as the set_bias_level function.
  */
-static int wm9090_set_bias_level(struct snd_soc_codec *codec,
+static int wm9090_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
+	struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
-		snd_soc_update_bits(codec, WM9090_ANTIPOP2, WM9090_VMID_ENA,
+		snd_soc_component_update_bits(component, WM9090_ANTIPOP2, WM9090_VMID_ENA,
 				    WM9090_VMID_ENA);
-		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
 				    WM9090_BIAS_ENA |
 				    WM9090_VMID_RES_MASK,
 				    WM9090_BIAS_ENA |
@@ -493,7 +493,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
 		break;
 
 	case SND_SOC_BIAS_STANDBY:
-		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
 			/* Restore the register cache */
 			regcache_sync(wm9090->regmap);
 		}
@@ -502,9 +502,9 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
 		 * ground referenced outputs and class D speaker mean that
 		 * latency is not an issue.
 		 */
-		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
 				    WM9090_BIAS_ENA | WM9090_VMID_RES_MASK, 0);
-		snd_soc_update_bits(codec, WM9090_ANTIPOP2,
+		snd_soc_component_update_bits(component, WM9090_ANTIPOP2,
 				    WM9090_VMID_ENA, 0);
 		break;
 
@@ -515,45 +515,49 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int wm9090_probe(struct snd_soc_codec *codec)
+static int wm9090_probe(struct snd_soc_component *component)
 {
 	/* Configure some defaults; they will be written out when we
 	 * bring the bias up.
 	 */
-	snd_soc_update_bits(codec, WM9090_IN1_LINE_INPUT_A_VOLUME,
+	snd_soc_component_update_bits(component, WM9090_IN1_LINE_INPUT_A_VOLUME,
 			    WM9090_IN1_VU | WM9090_IN1A_ZC,
 			    WM9090_IN1_VU | WM9090_IN1A_ZC);
-	snd_soc_update_bits(codec, WM9090_IN1_LINE_INPUT_B_VOLUME,
+	snd_soc_component_update_bits(component, WM9090_IN1_LINE_INPUT_B_VOLUME,
 			    WM9090_IN1_VU | WM9090_IN1B_ZC,
 			    WM9090_IN1_VU | WM9090_IN1B_ZC);
-	snd_soc_update_bits(codec, WM9090_IN2_LINE_INPUT_A_VOLUME,
+	snd_soc_component_update_bits(component, WM9090_IN2_LINE_INPUT_A_VOLUME,
 			    WM9090_IN2_VU | WM9090_IN2A_ZC,
 			    WM9090_IN2_VU | WM9090_IN2A_ZC);
-	snd_soc_update_bits(codec, WM9090_IN2_LINE_INPUT_B_VOLUME,
+	snd_soc_component_update_bits(component, WM9090_IN2_LINE_INPUT_B_VOLUME,
 			    WM9090_IN2_VU | WM9090_IN2B_ZC,
 			    WM9090_IN2_VU | WM9090_IN2B_ZC);
-	snd_soc_update_bits(codec, WM9090_SPEAKER_VOLUME_LEFT,
+	snd_soc_component_update_bits(component, WM9090_SPEAKER_VOLUME_LEFT,
 			    WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC,
 			    WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC);
-	snd_soc_update_bits(codec, WM9090_LEFT_OUTPUT_VOLUME,
+	snd_soc_component_update_bits(component, WM9090_LEFT_OUTPUT_VOLUME,
 			    WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC,
 			    WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC);
-	snd_soc_update_bits(codec, WM9090_RIGHT_OUTPUT_VOLUME,
+	snd_soc_component_update_bits(component, WM9090_RIGHT_OUTPUT_VOLUME,
 			    WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC,
 			    WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC);
 
-	snd_soc_update_bits(codec, WM9090_CLOCKING_1,
+	snd_soc_component_update_bits(component, WM9090_CLOCKING_1,
 			    WM9090_TOCLK_ENA, WM9090_TOCLK_ENA);
 
-	wm9090_add_controls(codec);
+	wm9090_add_controls(component);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
-	.probe = 	wm9090_probe,
-	.set_bias_level = wm9090_set_bias_level,
-	.suspend_bias_off = true,
+static const struct snd_soc_component_driver soc_component_dev_wm9090 = {
+	.probe			= wm9090_probe,
+	.set_bias_level		= wm9090_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config wm9090_regmap = {
@@ -607,8 +611,8 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, wm9090);
 
-	ret =  snd_soc_register_codec(&i2c->dev,
-			&soc_codec_dev_wm9090,  NULL, 0);
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm9090,  NULL, 0);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
 		return ret;
@@ -617,12 +621,6 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
 	return 0;
 }
 
-static int wm9090_i2c_remove(struct i2c_client *i2c)
-{
-	snd_soc_unregister_codec(&i2c->dev);
-	return 0;
-}
-
 static const struct i2c_device_id wm9090_id[] = {
 	{ "wm9090", 0 },
 	{ "wm9093", 0 },
@@ -635,7 +633,6 @@ static struct i2c_driver wm9090_i2c_driver = {
 		.name = "wm9090",
 	},
 	.probe = wm9090_i2c_probe,
-	.remove = wm9090_i2c_remove,
 	.id_table = wm9090_id,
 };
 
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 2c09f71fe433..ccdf088461b7 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -235,17 +235,17 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = {
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int reg;
 
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = AC97_PCM_FRONT_DAC_RATE;
 	else
 		reg = AC97_PCM_LR_ADC_RATE;
 
-	return snd_soc_write(codec, reg, substream->runtime->rate);
+	return snd_soc_component_write(component, reg, substream->runtime->rate);
 }
 
 #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
@@ -289,18 +289,18 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
 };
 
 #ifdef CONFIG_PM
-static int wm9705_soc_suspend(struct snd_soc_codec *codec)
+static int wm9705_soc_suspend(struct snd_soc_component *component)
 {
-	regcache_cache_bypass(codec->component.regmap, true);
-	snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
-	regcache_cache_bypass(codec->component.regmap, false);
+	regcache_cache_bypass(component->regmap, true);
+	snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
+	regcache_cache_bypass(component->regmap, false);
 
 	return 0;
 }
 
-static int wm9705_soc_resume(struct snd_soc_codec *codec)
+static int wm9705_soc_resume(struct snd_soc_component *component)
 {
-	struct wm9705_priv *wm9705 = snd_soc_codec_get_drvdata(codec);
+	struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_ac97_reset(wm9705->ac97, true, WM9705_VENDOR_ID,
@@ -308,7 +308,7 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
 	if (ret < 0)
 		return ret;
 
-	regcache_sync(codec->component.regmap);
+	snd_soc_component_cache_sync(component);
 
 	return 0;
 }
@@ -317,9 +317,9 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
 #define wm9705_soc_resume NULL
 #endif
 
-static int wm9705_soc_probe(struct snd_soc_codec *codec)
+static int wm9705_soc_probe(struct snd_soc_component *component)
 {
-	struct wm9705_priv *wm9705 = snd_soc_codec_get_drvdata(codec);
+	struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap;
 
 	if (wm9705->mfd_pdata) {
@@ -327,54 +327,54 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 		regmap = wm9705->mfd_pdata->regmap;
 	} else {
 #ifdef CONFIG_SND_SOC_AC97_BUS
-		wm9705->ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID,
+		wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
 						      WM9705_VENDOR_ID_MASK);
 		if (IS_ERR(wm9705->ac97)) {
-			dev_err(codec->dev, "Failed to register AC97 codec\n");
+			dev_err(component->dev, "Failed to register AC97 codec\n");
 			return PTR_ERR(wm9705->ac97);
 		}
 
 		regmap = regmap_init_ac97(wm9705->ac97, &wm9705_regmap_config);
 		if (IS_ERR(regmap)) {
-			snd_soc_free_ac97_codec(wm9705->ac97);
+			snd_soc_free_ac97_component(wm9705->ac97);
 			return PTR_ERR(regmap);
 		}
 #endif
 	}
 
-	snd_soc_codec_set_drvdata(codec, wm9705->ac97);
-	snd_soc_codec_init_regmap(codec, regmap);
+	snd_soc_component_set_drvdata(component, wm9705->ac97);
+	snd_soc_component_init_regmap(component, regmap);
 
 	return 0;
 }
 
-static int wm9705_soc_remove(struct snd_soc_codec *codec)
+static void wm9705_soc_remove(struct snd_soc_component *component)
 {
 #ifdef CONFIG_SND_SOC_AC97_BUS
-	struct wm9705_priv *wm9705 = snd_soc_codec_get_drvdata(codec);
+	struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
 
 	if (!wm9705->mfd_pdata) {
-		snd_soc_codec_exit_regmap(codec);
-		snd_soc_free_ac97_codec(wm9705->ac97);
+		snd_soc_component_exit_regmap(component);
+		snd_soc_free_ac97_component(wm9705->ac97);
 	}
 #endif
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
-	.probe = 	wm9705_soc_probe,
-	.remove = 	wm9705_soc_remove,
-	.suspend =	wm9705_soc_suspend,
-	.resume =	wm9705_soc_resume,
-
-	.component_driver = {
-		.controls		= wm9705_snd_ac97_controls,
-		.num_controls		= ARRAY_SIZE(wm9705_snd_ac97_controls),
-		.dapm_widgets		= wm9705_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm9705_dapm_widgets),
-		.dapm_routes		= wm9705_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(wm9705_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm9705 = {
+	.probe			= wm9705_soc_probe,
+	.remove			= wm9705_soc_remove,
+	.suspend		= wm9705_soc_suspend,
+	.resume			= wm9705_soc_resume,
+	.controls		= wm9705_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(wm9705_snd_ac97_controls),
+	.dapm_widgets		= wm9705_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9705_dapm_widgets),
+	.dapm_routes		= wm9705_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm9705_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm9705_probe(struct platform_device *pdev)
@@ -388,14 +388,8 @@ static int wm9705_probe(struct platform_device *pdev)
 	wm9705->mfd_pdata = dev_get_platdata(&pdev->dev);
 	platform_set_drvdata(pdev, wm9705);
 
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
-}
-
-static int wm9705_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
 }
 
 static struct platform_driver wm9705_codec_driver = {
@@ -404,7 +398,6 @@ static struct platform_driver wm9705_codec_driver = {
 	},
 
 	.probe = wm9705_probe,
-	.remove = wm9705_remove,
 };
 
 module_platform_driver(wm9705_codec_driver);
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 4f6d1a442bc4..953d94d50586 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -220,13 +220,13 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 	unsigned int val = ucontrol->value.integer.value[0];
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int mixer, mask, shift, old;
-	struct snd_soc_dapm_update update = { 0 };
+	struct snd_soc_dapm_update update = {};
 	bool change;
 
 	mixer = mc->shift >> 8;
@@ -264,8 +264,8 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int shift, mixer;
@@ -527,33 +527,33 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = {
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	int reg;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = AC97_PCM_FRONT_DAC_RATE;
 	else
 		reg = AC97_PCM_LR_ADC_RATE;
 
-	return snd_soc_write(codec, reg, runtime->rate);
+	return snd_soc_component_write(component, reg, runtime->rate);
 }
 
 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1);
-	snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
+	snd_soc_component_update_bits(component, AC97_PCI_SID, 0x8000, 0x8000);
 
 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 		return -ENODEV;
 
-	return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+	return snd_soc_component_write(component, AC97_PCM_SURR_DAC_RATE, runtime->rate);
 }
 
 #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -597,7 +597,7 @@ static struct snd_soc_dai_driver wm9712_dai[] = {
 }
 };
 
-static int wm9712_set_bias_level(struct snd_soc_codec *codec,
+static int wm9712_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
@@ -605,20 +605,20 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* disable everything including AC link */
-		snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-		snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
+		snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
 		break;
 	}
 	return 0;
 }
 
-static int wm9712_soc_resume(struct snd_soc_codec *codec)
+static int wm9712_soc_resume(struct snd_soc_component *component)
 {
-	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,
@@ -626,17 +626,17 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
 	if (ret < 0)
 		return ret;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	if (ret == 0)
-		regcache_sync(codec->component.regmap);
+		snd_soc_component_cache_sync(component);
 
 	return ret;
 }
 
-static int wm9712_soc_probe(struct snd_soc_codec *codec)
+static int wm9712_soc_probe(struct snd_soc_component *component)
 {
-	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap;
 	int ret;
 
@@ -645,59 +645,59 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 		regmap = wm9712->mfd_pdata->regmap;
 	} else {
 #ifdef CONFIG_SND_SOC_AC97_BUS
-		wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID,
+		wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
 						      WM9712_VENDOR_ID_MASK);
 		if (IS_ERR(wm9712->ac97)) {
 			ret = PTR_ERR(wm9712->ac97);
-			dev_err(codec->dev,
+			dev_err(component->dev,
 				"Failed to register AC97 codec: %d\n", ret);
 			return ret;
 		}
 
 		regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config);
 		if (IS_ERR(regmap)) {
-			snd_soc_free_ac97_codec(wm9712->ac97);
+			snd_soc_free_ac97_component(wm9712->ac97);
 			return PTR_ERR(regmap);
 		}
 #endif
 	}
 
-	snd_soc_codec_init_regmap(codec, regmap);
+	snd_soc_component_init_regmap(component, regmap);
 
 	/* set alc mux to none */
-	snd_soc_update_bits(codec, AC97_VIDEO, 0x3000, 0x3000);
+	snd_soc_component_update_bits(component, AC97_VIDEO, 0x3000, 0x3000);
 
 	return 0;
 }
 
-static int wm9712_soc_remove(struct snd_soc_codec *codec)
+static void wm9712_soc_remove(struct snd_soc_component *component)
 {
 #ifdef CONFIG_SND_SOC_AC97_BUS
-	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
 
 	if (!wm9712->mfd_pdata) {
-		snd_soc_codec_exit_regmap(codec);
-		snd_soc_free_ac97_codec(wm9712->ac97);
+		snd_soc_component_exit_regmap(component);
+		snd_soc_free_ac97_component(wm9712->ac97);
 	}
 #endif
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
-	.probe = 	wm9712_soc_probe,
-	.remove = 	wm9712_soc_remove,
-	.resume =	wm9712_soc_resume,
-	.set_bias_level = wm9712_set_bias_level,
-	.suspend_bias_off = true,
-
-	.component_driver = {
-		.controls		= wm9712_snd_ac97_controls,
-		.num_controls		= ARRAY_SIZE(wm9712_snd_ac97_controls),
-		.dapm_widgets		= wm9712_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm9712_dapm_widgets),
-		.dapm_routes		= wm9712_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(wm9712_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
+	.probe			= wm9712_soc_probe,
+	.remove			= wm9712_soc_remove,
+	.resume			= wm9712_soc_resume,
+	.set_bias_level		= wm9712_set_bias_level,
+	.controls		= wm9712_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(wm9712_snd_ac97_controls),
+	.dapm_widgets		= wm9712_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9712_dapm_widgets),
+	.dapm_routes		= wm9712_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm9712_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm9712_probe(struct platform_device *pdev)
@@ -713,26 +713,19 @@ static int wm9712_probe(struct platform_device *pdev)
 	wm9712->mfd_pdata = dev_get_platdata(&pdev->dev);
 	platform_set_drvdata(pdev, wm9712);
 
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
-}
-
-static int wm9712_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
 }
 
-static struct platform_driver wm9712_codec_driver = {
+static struct platform_driver wm9712_component_driver = {
 	.driver = {
-		.name = "wm9712-codec",
+		.name = "wm9712-component",
 	},
 
 	.probe = wm9712_probe,
-	.remove = wm9712_remove,
 };
 
-module_platform_driver(wm9712_codec_driver);
+module_platform_driver(wm9712_component_driver);
 
 MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
 MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index df7220656d98..643863bb32e0 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -196,16 +196,16 @@ SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
 				 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 
 	if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
 		return -EINVAL;
 
 	/* Gracefully shut down the voice interface. */
-	snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0200);
+	snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, 0x0200);
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
-	snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
-	snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x1000, 0x1000);
+	snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x1000, 0x1000);
 
 	return 0;
 }
@@ -229,13 +229,13 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 	unsigned int val = ucontrol->value.integer.value[0];
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int mixer, mask, shift, old;
-	struct snd_soc_dapm_update update = { 0 };
+	struct snd_soc_dapm_update update = {};
 	bool change;
 
 	mixer = mc->shift >> 8;
@@ -273,8 +273,8 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int mixer, shift;
@@ -753,7 +753,7 @@ struct _pll_div {
  * to allow rounding later */
 #define FIXED_PLL_SIZE ((1 << 22) * 10)
 
-static void pll_factors(struct snd_soc_codec *codec,
+static void pll_factors(struct snd_soc_component *component,
 	struct _pll_div *pll_div, unsigned int source)
 {
 	u64 Kpart;
@@ -789,7 +789,7 @@ static void pll_factors(struct snd_soc_codec *codec,
 
 	Ndiv = target / source;
 	if ((Ndiv < 5) || (Ndiv > 12))
-		dev_warn(codec->dev,
+		dev_warn(component->dev,
 			"WM9713 PLL N value %u out of recommended range!\n",
 			Ndiv);
 
@@ -815,28 +815,28 @@ static void pll_factors(struct snd_soc_codec *codec,
  * Please note that changing the PLL input frequency may require
  * resynchronisation with the AC97 controller.
  */
-static int wm9713_set_pll(struct snd_soc_codec *codec,
+static int wm9713_set_pll(struct snd_soc_component *component,
 	int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 	u16 reg, reg2;
 	struct _pll_div pll_div;
 
 	/* turn PLL off ? */
 	if (freq_in == 0) {
 		/* disable PLL power and select ext source */
-		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0080);
-		snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0200);
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0080, 0x0080);
+		snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x0200, 0x0200);
 		wm9713->pll_in = 0;
 		return 0;
 	}
 
-	pll_factors(codec, &pll_div, freq_in);
+	pll_factors(component, &pll_div, freq_in);
 
 	if (pll_div.k == 0) {
 		reg = (pll_div.n << 12) | (pll_div.lf << 11) |
 			(pll_div.divsel << 9) | (pll_div.divctl << 8);
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 	} else {
 		/* write the fractional k to the reg 0x46 pages */
 		reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) |
@@ -844,31 +844,31 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
 
 		/* K [21:20] */
 		reg = reg2 | (0x5 << 4) | (pll_div.k >> 20);
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 
 		/* K [19:16] */
 		reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf);
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 
 		/* K [15:12] */
 		reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf);
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 
 		/* K [11:8] */
 		reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf);
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 
 		/* K [7:4] */
 		reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf);
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 
 		reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */
-		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
 	}
 
 	/* turn PLL on and select as source */
-	snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0000);
-	snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0000);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x0200, 0x0000);
+	snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0080, 0x0000);
 	wm9713->pll_in = freq_in;
 
 	/* wait 10ms AC97 link frames for the link to stabilise */
@@ -879,8 +879,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
 static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 		int source, unsigned int freq_in, unsigned int freq_out)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	return wm9713_set_pll(codec, pll_id, freq_in, freq_out);
+	struct snd_soc_component *component = codec_dai->component;
+	return wm9713_set_pll(component, pll_id, freq_in, freq_out);
 }
 
 /*
@@ -890,10 +890,10 @@ static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai,
 	int tristate)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	if (tristate)
-		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
 				    0x6000, 0x0000);
 
 	return 0;
@@ -906,30 +906,30 @@ static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai,
 static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 		int div_id, int div)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
 	switch (div_id) {
 	case WM9713_PCMCLK_DIV:
-		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, div);
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, div);
 		break;
 	case WM9713_CLKA_MULT:
-		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0002, div);
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0002, div);
 		break;
 	case WM9713_CLKB_MULT:
-		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0004, div);
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0004, div);
 		break;
 	case WM9713_HIFI_DIV:
-		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x7000, div);
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x7000, div);
 		break;
 	case WM9713_PCMBCLK_DIV:
-		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, 0x0e00, div);
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER, 0x0e00, div);
 		break;
 	case WM9713_PCMCLK_PLL_DIV:
-		snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+		snd_soc_component_update_bits(component, AC97_LINE1_LEVEL,
 				    0x007f, div | 0x60);
 		break;
 	case WM9713_HIFI_PLL_DIV:
-		snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+		snd_soc_component_update_bits(component, AC97_LINE1_LEVEL,
 				    0x007f, div | 0x70);
 		break;
 	default:
@@ -942,8 +942,8 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
 static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		unsigned int fmt)
 {
-	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 gpio = snd_soc_read(codec, AC97_GPIO_CFG) & 0xffc5;
+	struct snd_soc_component *component = codec_dai->component;
+	u16 gpio = snd_soc_component_read32(component, AC97_GPIO_CFG) & 0xffc5;
 	u16 reg = 0x8000;
 
 	/* clock masters */
@@ -996,8 +996,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
 		break;
 	}
 
-	snd_soc_write(codec, AC97_GPIO_CFG, gpio);
-	snd_soc_write(codec, AC97_CENTER_LFE_MASTER, reg);
+	snd_soc_component_write(component, AC97_GPIO_CFG, gpio);
+	snd_soc_component_write(component, AC97_CENTER_LFE_MASTER, reg);
 	return 0;
 }
 
@@ -1005,22 +1005,22 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 
 	/* enable PCM interface in master mode */
 	switch (params_width(params)) {
 	case 16:
 		break;
 	case 20:
-		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
 				    0x000c, 0x0004);
 		break;
 	case 24:
-		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
 				    0x000c, 0x0008);
 		break;
 	case 32:
-		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
 				    0x000c, 0x000c);
 		break;
 	}
@@ -1030,33 +1030,33 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
 static int ac97_hifi_prepare(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int reg;
 
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = AC97_PCM_FRONT_DAC_RATE;
 	else
 		reg = AC97_PCM_LR_ADC_RATE;
 
-	return snd_soc_write(codec, reg, runtime->rate);
+	return snd_soc_component_write(component, reg, runtime->rate);
 }
 
 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
-	struct snd_soc_codec *codec = dai->codec;
+	struct snd_soc_component *component = dai->component;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
-	snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+	snd_soc_component_update_bits(component, AC97_PCI_SID, 0x8000, 0x8000);
 
 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 		return -ENODEV;
 
-	return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+	return snd_soc_component_write(component, AC97_PCM_SURR_DAC_RATE, runtime->rate);
 }
 
 #define WM9713_RATES (SNDRV_PCM_RATE_8000  |	\
@@ -1142,48 +1142,48 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
 	},
 };
 
-static int wm9713_set_bias_level(struct snd_soc_codec *codec,
+static int wm9713_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* enable thermal shutdown */
-		snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xe400, 0x0000);
+		snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0xe400, 0x0000);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* enable master bias and vmid */
-		snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xc400, 0x0000);
-		snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
+		snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0xc400, 0x0000);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* disable everything including AC link */
-		snd_soc_write(codec, AC97_EXTENDED_MID, 0xffff);
-		snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-		snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
+		snd_soc_component_write(component, AC97_EXTENDED_MID, 0xffff);
+		snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
 		break;
 	}
 	return 0;
 }
 
-static int wm9713_soc_suspend(struct snd_soc_codec *codec)
+static int wm9713_soc_suspend(struct snd_soc_component *component)
 {
 	/* Disable everything except touchpanel - that will be handled
 	 * by the touch driver and left disabled if touch is not in
 	 * use. */
-	snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x7fff,
+	snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x7fff,
 				 0x7fff);
-	snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-	snd_soc_write(codec, AC97_POWERDOWN, 0x6f00);
-	snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
+	snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
+	snd_soc_component_write(component, AC97_POWERDOWN, 0x6f00);
+	snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
 
 	return 0;
 }
 
-static int wm9713_soc_resume(struct snd_soc_codec *codec)
+static int wm9713_soc_resume(struct snd_soc_component *component)
 {
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
@@ -1191,24 +1191,24 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
 	if (ret < 0)
 		return ret;
 
-	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
 
 	/* do we need to re-start the PLL ? */
 	if (wm9713->pll_in)
-		wm9713_set_pll(codec, 0, wm9713->pll_in, 0);
+		wm9713_set_pll(component, 0, wm9713->pll_in, 0);
 
 	/* only synchronise the codec if warm reset failed */
 	if (ret == 0) {
-		regcache_mark_dirty(codec->component.regmap);
-		snd_soc_cache_sync(codec);
+		regcache_mark_dirty(component->regmap);
+		snd_soc_component_cache_sync(component);
 	}
 
 	return ret;
 }
 
-static int wm9713_soc_probe(struct snd_soc_codec *codec)
+static int wm9713_soc_probe(struct snd_soc_component *component)
 {
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap = NULL;
 
 	if (wm9713->mfd_pdata) {
@@ -1216,54 +1216,54 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 		regmap = wm9713->mfd_pdata->regmap;
 	} else {
 #ifdef CONFIG_SND_SOC_AC97_BUS
-		wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
+		wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
 						      WM9713_VENDOR_ID_MASK);
 		if (IS_ERR(wm9713->ac97))
 			return PTR_ERR(wm9713->ac97);
 		regmap = regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
 		if (IS_ERR(regmap)) {
-			snd_soc_free_ac97_codec(wm9713->ac97);
+			snd_soc_free_ac97_component(wm9713->ac97);
 			return PTR_ERR(regmap);
 		}
 #endif
 	}
 
-	snd_soc_codec_init_regmap(codec, regmap);
+	snd_soc_component_init_regmap(component, regmap);
 
 	/* unmute the adc - move to kcontrol */
-	snd_soc_update_bits(codec, AC97_CD, 0x7fff, 0x0000);
+	snd_soc_component_update_bits(component, AC97_CD, 0x7fff, 0x0000);
 
 	return 0;
 }
 
-static int wm9713_soc_remove(struct snd_soc_codec *codec)
+static void wm9713_soc_remove(struct snd_soc_component *component)
 {
 #ifdef CONFIG_SND_SOC_AC97_BUS
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
 
 	if (!wm9713->mfd_pdata) {
-		snd_soc_codec_exit_regmap(codec);
-		snd_soc_free_ac97_codec(wm9713->ac97);
+		snd_soc_component_exit_regmap(component);
+		snd_soc_free_ac97_component(wm9713->ac97);
 	}
 #endif
-	return 0;
 }
 
-static const struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
-	.probe = 	wm9713_soc_probe,
-	.remove = 	wm9713_soc_remove,
-	.suspend =	wm9713_soc_suspend,
-	.resume = 	wm9713_soc_resume,
-	.set_bias_level = wm9713_set_bias_level,
-
-	.component_driver = {
-		.controls		= wm9713_snd_ac97_controls,
-		.num_controls		= ARRAY_SIZE(wm9713_snd_ac97_controls),
-		.dapm_widgets		= wm9713_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(wm9713_dapm_widgets),
-		.dapm_routes		= wm9713_audio_map,
-		.num_dapm_routes	= ARRAY_SIZE(wm9713_audio_map),
-	},
+static const struct snd_soc_component_driver soc_component_dev_wm9713 = {
+	.probe			= wm9713_soc_probe,
+	.remove			= wm9713_soc_remove,
+	.suspend		= wm9713_soc_suspend,
+	.resume			= wm9713_soc_resume,
+	.set_bias_level		= wm9713_set_bias_level,
+	.controls		= wm9713_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(wm9713_snd_ac97_controls),
+	.dapm_widgets		= wm9713_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9713_dapm_widgets),
+	.dapm_routes		= wm9713_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm9713_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int wm9713_probe(struct platform_device *pdev)
@@ -1279,14 +1279,8 @@ static int wm9713_probe(struct platform_device *pdev)
 	wm9713->mfd_pdata = dev_get_platdata(&pdev->dev);
 	platform_set_drvdata(pdev, wm9713);
 
-	return snd_soc_register_codec(&pdev->dev,
-			&soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
-}
-
-static int wm9713_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
 }
 
 static struct platform_driver wm9713_codec_driver = {
@@ -1295,7 +1289,6 @@ static struct platform_driver wm9713_codec_driver = {
 	},
 
 	.probe = wm9713_probe,
-	.remove = wm9713_remove,
 };
 
 module_platform_driver(wm9713_codec_driver);
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 66e32f5d2917..b6e7c614301f 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -605,13 +605,13 @@ static const struct {
 };
 
 static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
-				  struct snd_soc_codec *codec)
+				  struct snd_soc_component *component)
 {
 	struct dentry *root = NULL;
 	char *root_name;
 	int i;
 
-	if (!codec->component.debugfs_root) {
+	if (!component->debugfs_root) {
 		adsp_err(dsp, "No codec debugfs root\n");
 		goto err;
 	}
@@ -621,7 +621,7 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
 		goto err;
 
 	snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
-	root = debugfs_create_dir(root_name, codec->component.debugfs_root);
+	root = debugfs_create_dir(root_name, component->debugfs_root);
 	kfree(root_name);
 
 	if (!root)
@@ -662,7 +662,7 @@ static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
 }
 #else
 static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
-					 struct snd_soc_codec *codec)
+					 struct snd_soc_component *component)
 {
 }
 
@@ -688,9 +688,9 @@ static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
 
@@ -700,9 +700,9 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 			  struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 	int ret = 0;
 
 	if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
@@ -1213,7 +1213,7 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
 		break;
 	}
 
-	ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1);
+	ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
 	if (ret < 0)
 		goto err_kcontrol;
 
@@ -1237,9 +1237,16 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
 		if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
 			continue;
 
-		ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
-		if (ret < 0)
-			return ret;
+		/*
+		 * For readable controls populate the cache from the DSP memory.
+		 * For non-readable controls the cache was zero-filled when
+		 * created so we don't need to do anything.
+		 */
+		if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
+			ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	return 0;
@@ -2396,14 +2403,14 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol,
 		   int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 	struct wm_adsp *dsp = &dsps[w->shift];
 	struct wm_coeff_ctl *ctl;
 	int ret;
 	unsigned int val;
 
-	dsp->codec = codec;
+	dsp->component = component;
 
 	mutex_lock(&dsp->pwr_lock);
 
@@ -2633,8 +2640,8 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
 int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
 			   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = dsp->preloaded;
 
@@ -2645,9 +2652,9 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
 int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
 			   struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	char preload[32];
@@ -2683,8 +2690,8 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event,
 			 unsigned int freq)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 	struct wm_adsp *dsp = &dsps[w->shift];
 	struct wm_coeff_ctl *ctl;
 
@@ -2726,8 +2733,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
 	struct wm_adsp *dsp = &dsps[w->shift];
 	int ret;
 
@@ -2841,31 +2848,31 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_event);
 
-int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	char preload[32];
 
 	snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
 	snd_soc_dapm_disable_pin(dapm, preload);
 
-	wm_adsp2_init_debugfs(dsp, codec);
+	wm_adsp2_init_debugfs(dsp, component);
 
-	dsp->codec = codec;
+	dsp->component = component;
 
-	return snd_soc_add_codec_controls(codec,
+	return snd_soc_add_component_controls(component,
 					  &wm_adsp_fw_controls[dsp->num - 1],
 					  1);
 }
-EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe);
+EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
 
-int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
 {
 	wm_adsp2_cleanup_debugfs(dsp);
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove);
+EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
 
 int wm_adsp2_init(struct wm_adsp *dsp)
 {
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 41cc11c19b83..bc6d359f0533 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -62,12 +62,12 @@ struct wm_adsp {
 	int type;
 	struct device *dev;
 	struct regmap *regmap;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
-	int base;
-	int sysclk_reg;
-	int sysclk_mask;
-	int sysclk_shift;
+	unsigned int base;
+	unsigned int sysclk_reg;
+	unsigned int sysclk_mask;
+	unsigned int sysclk_shift;
 
 	struct list_head alg_regions;
 
@@ -126,8 +126,8 @@ extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
 int wm_adsp1_init(struct wm_adsp *dsp);
 int wm_adsp2_init(struct wm_adsp *dsp);
 void wm_adsp2_remove(struct wm_adsp *dsp);
-int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec);
-int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
+int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component);
+int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component);
 int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 63b2745f8169..fed6ea9b019f 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -60,9 +60,9 @@ static const char *speaker_mode_text[] = {
 static SOC_ENUM_SINGLE_DECL(speaker_mode,
 			    WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
 
-static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
+static void wait_for_dc_servo(struct snd_soc_component *component, unsigned int op)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	unsigned int reg;
 	int count = 0;
 	int timeout;
@@ -71,9 +71,9 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 	val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
 
 	/* Trigger the command */
-	snd_soc_write(codec, WM8993_DC_SERVO_0, val);
+	snd_soc_component_write(component, WM8993_DC_SERVO_0, val);
 
-	dev_dbg(codec->dev, "Waiting for DC servo...\n");
+	dev_dbg(component->dev, "Waiting for DC servo...\n");
 
 	if (hubs->dcs_done_irq)
 		timeout = 4;
@@ -89,12 +89,12 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 		else
 			msleep(1);
 
-		reg = snd_soc_read(codec, WM8993_DC_SERVO_0);
-		dev_dbg(codec->dev, "DC servo: %x\n", reg);
+		reg = snd_soc_component_read32(component, WM8993_DC_SERVO_0);
+		dev_dbg(component->dev, "DC servo: %x\n", reg);
 	} while (reg & op && count < timeout);
 
 	if (reg & op)
-		dev_err(codec->dev, "Timed out waiting for DC Servo %x\n",
+		dev_err(component->dev, "Timed out waiting for DC Servo %x\n",
 			op);
 }
 
@@ -108,35 +108,35 @@ irqreturn_t wm_hubs_dcs_done(int irq, void *data)
 }
 EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
 
-static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
+static bool wm_hubs_dac_hp_direct(struct snd_soc_component *component)
 {
 	int reg;
 
 	/* If we're going via the mixer we'll need to do additional checks */
-	reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
+	reg = snd_soc_component_read32(component, WM8993_OUTPUT_MIXER1);
 	if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
 		if (reg & ~WM8993_DACL_TO_MIXOUTL) {
-			dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
 				 reg & ~WM8993_DACL_TO_HPOUT1L);
 			return false;
 		} else {
-			dev_vdbg(codec->dev, "HPL connected to mixer\n");
+			dev_vdbg(component->dev, "HPL connected to mixer\n");
 		}
 	} else {
-		dev_vdbg(codec->dev, "HPL connected to DAC\n");
+		dev_vdbg(component->dev, "HPL connected to DAC\n");
 	}
 
-	reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
+	reg = snd_soc_component_read32(component, WM8993_OUTPUT_MIXER2);
 	if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
 		if (reg & ~WM8993_DACR_TO_MIXOUTR) {
-			dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
 				 reg & ~WM8993_DACR_TO_HPOUT1R);
 			return false;
 		} else {
-			dev_vdbg(codec->dev, "HPR connected to mixer\n");
+			dev_vdbg(component->dev, "HPR connected to mixer\n");
 		}
 	} else {
-		dev_vdbg(codec->dev, "HPR connected to DAC\n");
+		dev_vdbg(component->dev, "HPR connected to DAC\n");
 	}
 
 	return true;
@@ -149,17 +149,17 @@ struct wm_hubs_dcs_cache {
 	u16 dcs_cfg;
 };
 
-static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
+static bool wm_hubs_dcs_cache_get(struct snd_soc_component *component,
 				  struct wm_hubs_dcs_cache **entry)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	struct wm_hubs_dcs_cache *cache;
 	unsigned int left, right;
 
-	left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+	left = snd_soc_component_read32(component, WM8993_LEFT_OUTPUT_VOLUME);
 	left &= WM8993_HPOUT1L_VOL_MASK;
 
-	right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+	right = snd_soc_component_read32(component, WM8993_RIGHT_OUTPUT_VOLUME);
 	right &= WM8993_HPOUT1R_VOL_MASK;
 
 	list_for_each_entry(cache, &hubs->dcs_cache, list) {
@@ -173,22 +173,22 @@ static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
 	return false;
 }
 
-static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
+static void wm_hubs_dcs_cache_set(struct snd_soc_component *component, u16 dcs_cfg)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	struct wm_hubs_dcs_cache *cache;
 
 	if (hubs->no_cache_dac_hp_direct)
 		return;
 
-	cache = devm_kzalloc(codec->dev, sizeof(*cache), GFP_KERNEL);
+	cache = devm_kzalloc(component->dev, sizeof(*cache), GFP_KERNEL);
 	if (!cache)
 		return;
 
-	cache->left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+	cache->left = snd_soc_component_read32(component, WM8993_LEFT_OUTPUT_VOLUME);
 	cache->left &= WM8993_HPOUT1L_VOL_MASK;
 
-	cache->right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+	cache->right = snd_soc_component_read32(component, WM8993_RIGHT_OUTPUT_VOLUME);
 	cache->right &= WM8993_HPOUT1R_VOL_MASK;
 
 	cache->dcs_cfg = dcs_cfg;
@@ -196,10 +196,10 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
 	list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
-static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+static int wm_hubs_read_dc_servo(struct snd_soc_component *component,
 				  u16 *reg_l, u16 *reg_r)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	u16 dcs_reg, reg;
 	int ret = 0;
 
@@ -220,14 +220,14 @@ static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
 	 */
 	switch (hubs->dcs_readback_mode) {
 	case 0:
-		*reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
+		*reg_l = snd_soc_component_read32(component, WM8993_DC_SERVO_READBACK_1)
 			& WM8993_DCS_INTEG_CHAN_0_MASK;
-		*reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
+		*reg_r = snd_soc_component_read32(component, WM8993_DC_SERVO_READBACK_2)
 			& WM8993_DCS_INTEG_CHAN_1_MASK;
 		break;
 	case 2:
 	case 1:
-		reg = snd_soc_read(codec, dcs_reg);
+		reg = snd_soc_component_read32(component, dcs_reg);
 		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
 			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
@@ -242,9 +242,9 @@ static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
 /*
  * Startup calibration of the DC servo
  */
-static void enable_dc_servo(struct snd_soc_codec *codec)
+static void enable_dc_servo(struct snd_soc_component *component)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	struct wm_hubs_dcs_cache *cache;
 	s8 offset;
 	u16 reg_l, reg_r, dcs_cfg, dcs_reg;
@@ -260,12 +260,12 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
 
 	/* If we're using a digital only path and have a previously
 	 * callibrated DC servo offset stored then use that. */
-	if (wm_hubs_dac_hp_direct(codec) &&
-	    wm_hubs_dcs_cache_get(codec, &cache)) {
-		dev_dbg(codec->dev, "Using cached DCS offset %x for %d,%d\n",
+	if (wm_hubs_dac_hp_direct(component) &&
+	    wm_hubs_dcs_cache_get(component, &cache)) {
+		dev_dbg(component->dev, "Using cached DCS offset %x for %d,%d\n",
 			cache->dcs_cfg, cache->left, cache->right);
-		snd_soc_write(codec, dcs_reg, cache->dcs_cfg);
-		wait_for_dc_servo(codec,
+		snd_soc_component_write(component, dcs_reg, cache->dcs_cfg);
+		wait_for_dc_servo(component,
 				  WM8993_DCS_TRIG_DAC_WR_0 |
 				  WM8993_DCS_TRIG_DAC_WR_1);
 		return;
@@ -273,48 +273,48 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
 
 	if (hubs->series_startup) {
 		/* Set for 32 series updates */
-		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
 				    WM8993_DCS_SERIES_NO_01_MASK,
 				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
-		wait_for_dc_servo(codec,
+		wait_for_dc_servo(component,
 				  WM8993_DCS_TRIG_SERIES_0 |
 				  WM8993_DCS_TRIG_SERIES_1);
 	} else {
-		wait_for_dc_servo(codec,
+		wait_for_dc_servo(component,
 				  WM8993_DCS_TRIG_STARTUP_0 |
 				  WM8993_DCS_TRIG_STARTUP_1);
 	}
 
-	if (wm_hubs_read_dc_servo(codec, &reg_l, &reg_r) < 0)
+	if (wm_hubs_read_dc_servo(component, &reg_l, &reg_r) < 0)
 		return;
 
-	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
+	dev_dbg(component->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
 	/* Apply correction to DC servo result */
 	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
-		dev_dbg(codec->dev,
+		dev_dbg(component->dev,
 			"Applying %d/%d code DC servo correction\n",
 			hubs->dcs_codes_l, hubs->dcs_codes_r);
 
 		/* HPOUT1R */
 		offset = (s8)reg_r;
-		dev_dbg(codec->dev, "DCS right %d->%d\n", offset,
+		dev_dbg(component->dev, "DCS right %d->%d\n", offset,
 			offset + hubs->dcs_codes_r);
 		offset += hubs->dcs_codes_r;
 		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 
 		/* HPOUT1L */
 		offset = (s8)reg_l;
-		dev_dbg(codec->dev, "DCS left %d->%d\n", offset,
+		dev_dbg(component->dev, "DCS left %d->%d\n", offset,
 			offset + hubs->dcs_codes_l);
 		offset += hubs->dcs_codes_l;
 		dcs_cfg |= (u8)offset;
 
-		dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
+		dev_dbg(component->dev, "DCS result: %x\n", dcs_cfg);
 
 		/* Do it */
-		snd_soc_write(codec, dcs_reg, dcs_cfg);
-		wait_for_dc_servo(codec,
+		snd_soc_component_write(component, dcs_reg, dcs_cfg);
+		wait_for_dc_servo(component,
 				  WM8993_DCS_TRIG_DAC_WR_0 |
 				  WM8993_DCS_TRIG_DAC_WR_1);
 	} else {
@@ -324,8 +324,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
 
 	/* Save the callibrated offset if we're in class W mode and
 	 * therefore don't have any analogue signal mixed in. */
-	if (wm_hubs_dac_hp_direct(codec))
-		wm_hubs_dcs_cache_set(codec, dcs_cfg);
+	if (wm_hubs_dac_hp_direct(component))
+		wm_hubs_dcs_cache_set(component, dcs_cfg);
 }
 
 /*
@@ -334,8 +334,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
 static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
@@ -346,9 +346,9 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
 		return ret;
 
 	/* Only need to do this if the outputs are active */
-	if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1)
+	if (snd_soc_component_read32(component, WM8993_POWER_MANAGEMENT_1)
 	    & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
-		snd_soc_update_bits(codec,
+		snd_soc_component_update_bits(component,
 				    WM8993_DC_SERVO_0,
 				    WM8993_DCS_TRIG_SINGLE_0 |
 				    WM8993_DCS_TRIG_SINGLE_1,
@@ -499,8 +499,8 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
 			   struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -509,28 +509,28 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
 			break;
 		case 1:
 			/* Enable the headphone amp */
-			snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+			snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 					    WM8993_HPOUT1L_ENA |
 					    WM8993_HPOUT1R_ENA,
 					    WM8993_HPOUT1L_ENA |
 					    WM8993_HPOUT1R_ENA);
 
 			/* Enable the second stage */
-			snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+			snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
 					    WM8993_HPOUT1L_DLY |
 					    WM8993_HPOUT1R_DLY,
 					    WM8993_HPOUT1L_DLY |
 					    WM8993_HPOUT1R_DLY);
 			break;
 		default:
-			dev_err(codec->dev, "Unknown HP startup mode %d\n",
+			dev_err(component->dev, "Unknown HP startup mode %d\n",
 				hubs->hp_startup_mode);
 			break;
 		}
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
 				    WM8993_CP_ENA, 0);
 		break;
 	}
@@ -541,47 +541,47 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
 		    struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int reg = snd_soc_component_read32(component, WM8993_ANALOGUE_HP_0);
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
+		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
 				    WM8993_CP_ENA, WM8993_CP_ENA);
 
 		msleep(5);
 
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
 				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
 
 		reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
-		snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
+		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
 
-		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
 				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
 
-		enable_dc_servo(codec);
+		enable_dc_servo(component);
 
 		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
 			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
-		snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
+		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
 				    WM8993_HPOUT1L_OUTP |
 				    WM8993_HPOUT1R_OUTP |
 				    WM8993_HPOUT1L_RMV_SHORT |
 				    WM8993_HPOUT1R_RMV_SHORT, 0);
 
-		snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
 				    WM8993_HPOUT1L_DLY |
 				    WM8993_HPOUT1R_DLY, 0);
 
-		snd_soc_write(codec, WM8993_DC_SERVO_0, 0);
+		snd_soc_component_write(component, WM8993_DC_SERVO_0, 0);
 
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
 				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
 				    0);
 		break;
@@ -593,18 +593,18 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int earpiece_event(struct snd_soc_dapm_widget *w,
 			  struct snd_kcontrol *control, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 reg = snd_soc_component_read32(component, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		reg |= WM8993_HPOUT2_IN_ENA;
-		snd_soc_write(codec, WM8993_ANTIPOP1, reg);
+		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
 		udelay(50);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_write(codec, WM8993_ANTIPOP1, reg);
+		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
 		break;
 
 	default:
@@ -618,8 +618,8 @@ static int earpiece_event(struct snd_soc_dapm_widget *w,
 static int lineout_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *control, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	bool *flag;
 
 	switch (w->shift) {
@@ -648,8 +648,8 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
 static int micbias_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 
 	switch (w->shift) {
 	case WM8993_MICB1_ENA_SHIFT:
@@ -667,26 +667,26 @@ static int micbias_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-void wm_hubs_update_class_w(struct snd_soc_codec *codec)
+void wm_hubs_update_class_w(struct snd_soc_component *component)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
 
-	if (!wm_hubs_dac_hp_direct(codec))
+	if (!wm_hubs_dac_hp_direct(component))
 		enable = false;
 
-	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(codec))
+	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(component))
 		enable = false;
 
-	dev_vdbg(codec->dev, "Class W %s\n", enable ? "enabled" : "disabled");
+	dev_vdbg(component->dev, "Class W %s\n", enable ? "enabled" : "disabled");
 
-	snd_soc_update_bits(codec, WM8993_CLASS_W_0,
+	snd_soc_component_update_bits(component, WM8993_CLASS_W_0,
 			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
 
-	snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME,
-		      snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME));
-	snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME,
-		      snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));
+	snd_soc_component_write(component, WM8993_LEFT_OUTPUT_VOLUME,
+		      snd_soc_component_read32(component, WM8993_LEFT_OUTPUT_VOLUME));
+	snd_soc_component_write(component, WM8993_RIGHT_OUTPUT_VOLUME,
+		      snd_soc_component_read32(component, WM8993_RIGHT_OUTPUT_VOLUME));
 }
 EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 
@@ -697,12 +697,12 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 
-	wm_hubs_update_class_w(codec);
+	wm_hubs_update_class_w(component);
 
 	return ret;
 }
@@ -717,12 +717,12 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
 static int class_w_put_double(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
 
-	wm_hubs_update_class_w(codec);
+	wm_hubs_update_class_w(component);
 
 	return ret;
 }
@@ -1113,40 +1113,40 @@ static const struct snd_soc_dapm_route lineout2_se_routes[] = {
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
 };
 
-int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
+int wm_hubs_add_analogue_controls(struct snd_soc_component *component)
 {
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
 	/* Latch volume update bits & default ZC on */
-	snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
 			    WM8993_IN1_VU, WM8993_IN1_VU);
-	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
 			    WM8993_IN1_VU, WM8993_IN1_VU);
-	snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
 			    WM8993_IN2_VU, WM8993_IN2_VU);
-	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
 			    WM8993_IN2_VU, WM8993_IN2_VU);
 
-	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT,
+	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_LEFT,
 			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
-	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
+	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_RIGHT,
 			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 
-	snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_LEFT_OUTPUT_VOLUME,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
-	snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_RIGHT_OUTPUT_VOLUME,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
 
-	snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_LEFT_OPGA_VOLUME,
 			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
 			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
-	snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
+	snd_soc_component_update_bits(component, WM8993_RIGHT_OPGA_VOLUME,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
 
-	snd_soc_add_codec_controls(codec, analogue_snd_controls,
+	snd_soc_add_component_controls(component, analogue_snd_controls,
 			     ARRAY_SIZE(analogue_snd_controls));
 
 	snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
@@ -1155,13 +1155,13 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
 
-int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
+int wm_hubs_add_analogue_routes(struct snd_soc_component *component,
 				int lineout1_diff, int lineout2_diff)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-	hubs->codec = codec;
+	hubs->component = component;
 
 	INIT_LIST_HEAD(&hubs->dcs_cache);
 	init_completion(&hubs->dcs_done);
@@ -1191,14 +1191,14 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
 
-int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
+int wm_hubs_handle_analogue_pdata(struct snd_soc_component *component,
 				  int lineout1_diff, int lineout2_diff,
 				  int lineout1fb, int lineout2fb,
 				  int jd_scthr, int jd_thr,
 				  int micbias1_delay, int micbias2_delay,
 				  int micbias1_lvl, int micbias2_lvl)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 
 	hubs->lineout1_se = !lineout1_diff;
 	hubs->lineout2_se = !lineout2_diff;
@@ -1206,28 +1206,28 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
 	hubs->micb2_delay = micbias2_delay;
 
 	if (!lineout1_diff)
-		snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
+		snd_soc_component_update_bits(component, WM8993_LINE_MIXER1,
 				    WM8993_LINEOUT1_MODE,
 				    WM8993_LINEOUT1_MODE);
 	if (!lineout2_diff)
-		snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
+		snd_soc_component_update_bits(component, WM8993_LINE_MIXER2,
 				    WM8993_LINEOUT2_MODE,
 				    WM8993_LINEOUT2_MODE);
 
 	if (!lineout1_diff && !lineout2_diff)
-		snd_soc_update_bits(codec, WM8993_ANTIPOP1,
+		snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
 				    WM8993_LINEOUT_VMID_BUF_ENA,
 				    WM8993_LINEOUT_VMID_BUF_ENA);
 
 	if (lineout1fb)
-		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
+		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
 				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
 
 	if (lineout2fb)
-		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
+		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
 				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
 
-	snd_soc_update_bits(codec, WM8993_MICBIAS,
+	snd_soc_component_update_bits(component, WM8993_MICBIAS,
 			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
 			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
 			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
@@ -1239,9 +1239,9 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
 
-void wm_hubs_vmid_ena(struct snd_soc_codec *codec)
+void wm_hubs_vmid_ena(struct snd_soc_component *component)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	int val = 0;
 
 	if (hubs->lineout1_se)
@@ -1251,20 +1251,20 @@ void wm_hubs_vmid_ena(struct snd_soc_codec *codec)
 		val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
 
 	/* Enable the line outputs while we power up */
-	snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val);
+	snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3, val, val);
 }
 EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
 
-void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
+void wm_hubs_set_bias_level(struct snd_soc_component *component,
 			    enum snd_soc_bias_level level)
 {
-	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
 	int mask, val;
 
 	switch (level) {
 	case SND_SOC_BIAS_STANDBY:
 		/* Clamp the inputs to VMID while we ramp to charge caps */
-		snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
+		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
 				    WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
 		break;
 
@@ -1291,11 +1291,11 @@ void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
 		if (hubs->lineout2_se && hubs->lineout2p_ena)
 			val |= WM8993_LINEOUT2P_ENA;
 
-		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3,
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3,
 				    mask, val);
 
 		/* Remove the input clamps */
-		snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
+		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
 				    WM8993_INPUTS_CLAMP, 0);
 		break;
 
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 24c763df21f9..ee339ad8514d 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -19,7 +19,7 @@
 #include <linux/list.h>
 #include <sound/control.h>
 
-struct snd_soc_codec;
+struct snd_soc_component;
 
 extern const unsigned int wm_hubs_spkmix_tlv[];
 
@@ -34,7 +34,7 @@ struct wm_hubs_data {
 
 	bool no_cache_dac_hp_direct;
 	struct list_head dcs_cache;
-	bool (*check_class_w_digital)(struct snd_soc_codec *);
+	bool (*check_class_w_digital)(struct snd_soc_component *);
 
 	int micb1_delay;
 	int micb2_delay;
@@ -50,12 +50,12 @@ struct wm_hubs_data {
 	bool dcs_done_irq;
 	struct completion dcs_done;
 
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 };
 
-extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
-extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int);
-extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
+extern int wm_hubs_add_analogue_controls(struct snd_soc_component *);
+extern int wm_hubs_add_analogue_routes(struct snd_soc_component *, int, int);
+extern int wm_hubs_handle_analogue_pdata(struct snd_soc_component *,
 					 int lineout1_diff, int lineout2_diff,
 					 int lineout1fb, int lineout2fb,
 					 int jd_scthr, int jd_thr,
@@ -63,10 +63,10 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
 					 int micbias1_lvl, int micbias2_lvl);
 
 extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
-extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec);
-extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
+extern void wm_hubs_vmid_ena(struct snd_soc_component *component);
+extern void wm_hubs_set_bias_level(struct snd_soc_component *component,
 				   enum snd_soc_bias_level level);
-extern void wm_hubs_update_class_w(struct snd_soc_codec *codec);
+extern void wm_hubs_update_class_w(struct snd_soc_component *component);
 
 extern const struct snd_kcontrol_new wm_hubs_hpl_mux;
 extern const struct snd_kcontrol_new wm_hubs_hpr_mux;
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
index ca1932d13738..7a2d6eaf1786 100644
--- a/sound/soc/codecs/zx_aud96p22.c
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -57,8 +57,8 @@ struct aud96p22_priv {
 static int aud96p22_adc_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap = priv->regmap;
 
 	if (event != SND_SOC_DAPM_POST_PMU)
@@ -74,8 +74,8 @@ static int aud96p22_adc_event(struct snd_soc_dapm_widget *w,
 static int aud96p22_dac_event(struct snd_soc_dapm_widget *w,
 			      struct snd_kcontrol *kcontrol, int event)
 {
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
 	struct regmap *regmap = priv->regmap;
 
 	if (event != SND_SOC_DAPM_POST_PMU)
@@ -261,20 +261,22 @@ static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
 	{ "LINEOUTMN", NULL, "LD2" },
 };
 
-static const struct snd_soc_codec_driver aud96p22_driver = {
-	.component_driver = {
-		.controls = aud96p22_snd_controls,
-		.num_controls = ARRAY_SIZE(aud96p22_snd_controls),
-		.dapm_widgets = aud96p22_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(aud96p22_dapm_widgets),
-		.dapm_routes = aud96p22_dapm_routes,
-		.num_dapm_routes = ARRAY_SIZE(aud96p22_dapm_routes),
-	},
+static const struct snd_soc_component_driver aud96p22_driver = {
+	.controls		= aud96p22_snd_controls,
+	.num_controls		= ARRAY_SIZE(aud96p22_snd_controls),
+	.dapm_widgets		= aud96p22_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aud96p22_dapm_widgets),
+	.dapm_routes		= aud96p22_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(aud96p22_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(dai->codec);
+	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(dai->component);
 	struct regmap *regmap = priv->regmap;
 	unsigned int val;
 
@@ -367,9 +369,9 @@ static int aud96p22_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, priv);
 
-	ret = snd_soc_register_codec(dev, &aud96p22_driver, &aud96p22_dai, 1);
+	ret = devm_snd_soc_register_component(dev, &aud96p22_driver, &aud96p22_dai, 1);
 	if (ret) {
-		dev_err(dev, "failed to register codec: %d\n", ret);
+		dev_err(dev, "failed to register component: %d\n", ret);
 		return ret;
 	}
 
@@ -378,7 +380,6 @@ static int aud96p22_i2c_probe(struct i2c_client *i2c,
 
 static int aud96p22_i2c_remove(struct i2c_client *i2c)
 {
-	snd_soc_unregister_codec(&i2c->dev);
 	return 0;
 }
 
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 384961651904..807040bb3921 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -34,6 +34,7 @@
 #include "edma-pcm.h"
 #include "davinci-i2s.h"
 
+#define DRV_NAME "davinci-i2s"
 
 /*
  * NOTE:  terminology here is confusing.
@@ -190,7 +191,7 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 	u32 spcr;
 	u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
@@ -211,8 +212,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
 	if (playback) {
 		/* Stop the DMA to avoid data loss */
 		/* while the transmitter is out of reset to handle XSYNCERR */
-		if (platform->driver->ops->trigger) {
-			int ret = platform->driver->ops->trigger(substream,
+		if (component->driver->ops->trigger) {
+			int ret = component->driver->ops->trigger(substream,
 				SNDRV_PCM_TRIGGER_STOP);
 			if (ret < 0)
 				printk(KERN_DEBUG "Playback DMA stop failed\n");
@@ -233,8 +234,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
 		toggle_clock(dev, playback);
 
 		/* Restart the DMA */
-		if (platform->driver->ops->trigger) {
-			int ret = platform->driver->ops->trigger(substream,
+		if (component->driver->ops->trigger) {
+			int ret = component->driver->ops->trigger(substream,
 				SNDRV_PCM_TRIGGER_START);
 			if (ret < 0)
 				printk(KERN_DEBUG "Playback DMA start failed\n");
@@ -651,7 +652,7 @@ static struct snd_soc_dai_driver davinci_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver davinci_i2s_component = {
-	.name		= "davinci-i2s",
+	.name		= DRV_NAME,
 };
 
 static int davinci_i2s_probe(struct platform_device *pdev)
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index e27e21f8569a..65112b9d8588 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -491,6 +491,10 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,
 			dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
 		comp1 = comp1 & ~BIT(5);
 
+	if (dev->capability & DWC_I2S_PLAY &&
+			dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
+		comp1 = comp1 & ~BIT(6);
+
 	if (COMP1_TX_ENABLED(comp1)) {
 		dev_dbg(dev->dev, " designware: play supported\n");
 		idx = COMP1_TX_WORDSIZE_0(comp1);
diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c
index 406fd867117b..2cc9632024fc 100644
--- a/sound/soc/dwc/dwc-pcm.c
+++ b/sound/soc/dwc/dwc-pcm.c
@@ -269,7 +269,7 @@ static const struct snd_pcm_ops dw_pcm_ops = {
 	.pointer = dw_pcm_pointer,
 };
 
-static const struct snd_soc_platform_driver dw_pcm_platform = {
+static const struct snd_soc_component_driver dw_pcm_component = {
 	.pcm_new = dw_pcm_new,
 	.pcm_free = dw_pcm_free,
 	.ops = &dw_pcm_ops,
@@ -277,5 +277,6 @@ static const struct snd_soc_platform_driver dw_pcm_platform = {
 
 int dw_pcm_register(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev, &dw_pcm_platform);
+	return devm_snd_soc_register_component(&pdev->dev, &dw_pcm_component,
+					       NULL, 0);
 }
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 989be518c4ed..4a6750aa3637 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -91,9 +91,9 @@ struct fsl_asoc_card_priv {
 	struct cpu_priv cpu_priv;
 	struct snd_soc_card card;
 	u32 sample_rate;
-	u32 sample_format;
+	snd_pcm_format_t sample_format;
 	u32 asrc_rate;
-	u32 asrc_format;
+	snd_pcm_format_t asrc_format;
 	u32 dai_fmt;
 	char name[32];
 };
@@ -199,7 +199,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 
 	mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 	snd_mask_none(mask);
-	snd_mask_set(mask, priv->asrc_format);
+	snd_mask_set(mask, (__force int)priv->asrc_format);
 
 	return 0;
 }
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 806d39927318..adfb8135d739 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -582,10 +582,6 @@ static struct snd_soc_dai_driver fsl_asrc_dai = {
 	.ops = &fsl_asrc_dai_ops,
 };
 
-static const struct snd_soc_component_driver fsl_asrc_component = {
-	.name = "fsl-asrc-dai",
-};
-
 static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -927,12 +923,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = devm_snd_soc_register_platform(&pdev->dev, &fsl_asrc_platform);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to register ASoC platform\n");
-		return ret;
-	}
-
 	return 0;
 }
 
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 2c5856ac5bc3..d558dd5499a5 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -462,6 +462,7 @@ struct fsl_asrc {
 	u32 regcache_cfg;
 };
 
-extern struct snd_soc_platform_driver fsl_asrc_platform;
+#define DRV_NAME "fsl-asrc-dai"
+extern struct snd_soc_component_driver fsl_asrc_component;
 struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir);
 #endif /* _FSL_ASRC_H */
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index e1b97e59275a..565e16d8fe85 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -64,7 +64,8 @@ static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 	unsigned long flags = DMA_CTRL_ACK;
 
 	/* Prepare and submit Front-End DMA channel */
@@ -137,12 +138,13 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream,
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
 	struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
 	struct fsl_asrc *asrc_priv = pair->asrc_priv;
 	struct dma_slave_config config_fe, config_be;
 	enum asrc_pair_index index = pair->index;
-	struct device *dev = rtd->platform->dev;
+	struct device *dev = component->dev;
 	int stream = substream->stream;
 	struct imx_dma_data *tmp_data;
 	struct snd_soc_dpcm *dpcm;
@@ -274,7 +276,8 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
 	struct fsl_asrc_pair *pair;
 
@@ -381,9 +384,10 @@ static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm)
 	}
 }
 
-struct snd_soc_platform_driver fsl_asrc_platform = {
+struct snd_soc_component_driver fsl_asrc_component = {
+	.name		= DRV_NAME,
 	.ops		= &fsl_asrc_dma_pcm_ops,
 	.pcm_new	= fsl_asrc_dma_pcm_new,
 	.pcm_free	= fsl_asrc_dma_pcm_free,
 };
-EXPORT_SYMBOL_GPL(fsl_asrc_platform);
+EXPORT_SYMBOL_GPL(fsl_asrc_component);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 8c2981b70f64..fce2010d3c53 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -37,6 +37,8 @@
 #include "fsl_dma.h"
 #include "fsl_ssi.h"	/* For the offset of stx0 and srx0 */
 
+#define DRV_NAME "fsl_dma"
+
 /*
  * The formats that the DMA controller supports, which is anything
  * that is 8, 16, or 32 bits.
@@ -56,7 +58,7 @@
 			    SNDRV_PCM_FMTBIT_U32_LE     | \
 			    SNDRV_PCM_FMTBIT_U32_BE)
 struct dma_object {
-	struct snd_soc_platform_driver dai;
+	struct snd_soc_component_driver dai;
 	dma_addr_t ssi_stx_phys;
 	dma_addr_t ssi_srx_phys;
 	unsigned int ssi_fifo_depth;
@@ -203,7 +205,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
 	struct fsl_dma_private *dma_private = dev_id;
 	struct snd_pcm_substream *substream = dma_private->substream;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 	struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
 	irqreturn_t ret = IRQ_NONE;
 	u32 sr, sr2 = 0;
@@ -385,9 +388,10 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 	struct dma_object *dma =
-		container_of(rtd->platform->driver, struct dma_object, dai);
+		container_of(component->driver, struct dma_object, dai);
 	struct fsl_dma_private *dma_private;
 	struct ccsr_dma_channel __iomem *dma_channel;
 	dma_addr_t ld_buf_phys;
@@ -539,7 +543,8 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_dma_private *dma_private = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 
 	/* Number of bits per sample */
 	unsigned int sample_bits =
@@ -702,7 +707,8 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_dma_private *dma_private = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 	struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
 	dma_addr_t position;
 	snd_pcm_uframes_t frames;
@@ -799,9 +805,10 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_dma_private *dma_private = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct device *dev = rtd->platform->dev;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct device *dev = component->dev;
 	struct dma_object *dma =
-		container_of(rtd->platform->driver, struct dma_object, dai);
+		container_of(component->driver, struct dma_object, dai);
 
 	if (dma_private) {
 		if (dma_private->irq)
@@ -908,6 +915,7 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	dma->dai.name = DRV_NAME;
 	dma->dai.ops = &fsl_dma_ops;
 	dma->dai.pcm_new = fsl_dma_new;
 	dma->dai.pcm_free = fsl_dma_free_dma_buffers;
@@ -925,7 +933,7 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
 
 	of_node_put(ssi_np);
 
-	ret = snd_soc_register_platform(&pdev->dev, &dma->dai);
+	ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
 	if (ret) {
 		dev_err(&pdev->dev, "could not register platform\n");
 		kfree(dma);
@@ -944,7 +952,6 @@ static int fsl_soc_dma_remove(struct platform_device *pdev)
 {
 	struct dma_object *dma = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_platform(&pdev->dev);
 	iounmap(dma->channel);
 	irq_dispose_mapping(dma->irq);
 	kfree(dma);
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index cef79a1a620b..40a700493f4c 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -788,7 +788,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct fsl_esai *esai_priv;
 	struct resource *res;
-	const uint32_t *iprop;
+	const __be32 *iprop;
 	void __iomem *regs;
 	int irq, ret;
 
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index aecd00f7929d..24fb672f3c65 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1377,7 +1377,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *of_id;
 	const char *p, *sprop;
-	const uint32_t *iprop;
+	const __be32 *iprop;
 	struct resource *res;
 	void __iomem *iomem;
 	char name[64];
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index b9e42b503a37..7592b0406370 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -36,7 +36,7 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
 {
 	struct resource res;
 	struct device_node *dma_channel_np, *dma_np;
-	const u32 *iprop;
+	const __be32 *iprop;
 	int ret;
 
 	dma_channel_np = of_parse_phandle(ssi_np, name, 0);
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 4e5fefee111e..0578f3486847 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -341,7 +341,7 @@ static void imx_pcm_fiq_free(struct snd_pcm *pcm)
 	imx_pcm_free(pcm);
 }
 
-static const struct snd_soc_platform_driver imx_soc_platform_fiq = {
+static const struct snd_soc_component_driver imx_soc_component_fiq = {
 	.ops		= &imx_pcm_ops,
 	.pcm_new	= imx_pcm_fiq_new,
 	.pcm_free	= imx_pcm_fiq_free,
@@ -368,7 +368,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev,
 	params->dma_params_tx->maxburst = 4;
 	params->dma_params_rx->maxburst = 6;
 
-	ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
+	ret = devm_snd_soc_register_component(&pdev->dev, &imx_soc_component_fiq,
+					      NULL, 0);
 	if (ret)
 		goto failed_register;
 
@@ -384,7 +385,6 @@ EXPORT_SYMBOL_GPL(imx_pcm_fiq_init);
 
 void imx_pcm_fiq_exit(struct platform_device *pdev)
 {
-	snd_soc_unregister_platform(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
 
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index e63029f1aabc..c1a4544eb16b 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -22,6 +22,8 @@
 
 #include "mpc5200_dma.h"
 
+#define DRV_NAME "mpc5200_dma"
+
 /*
  * Interrupt handlers
  */
@@ -300,12 +302,13 @@ static const struct snd_pcm_ops psc_dma_ops = {
 static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_card *card = rtd->card->snd_card;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct snd_soc_dai *dai = rtd->cpu_dai;
 	struct snd_pcm *pcm = rtd->pcm;
 	size_t size = psc_dma_hardware.buffer_bytes_max;
 	int rc;
 
-	dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+	dev_dbg(component->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
 		card, dai, pcm);
 
 	rc = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
@@ -341,10 +344,11 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
 static void psc_dma_free(struct snd_pcm *pcm)
 {
 	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct snd_pcm_substream *substream;
 	int stream;
 
-	dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
+	dev_dbg(component->dev, "psc_dma_free(pcm=%p)\n", pcm);
 
 	for (stream = 0; stream < 2; stream++) {
 		substream = pcm->streams[stream].substream;
@@ -356,7 +360,8 @@ static void psc_dma_free(struct snd_pcm *pcm)
 	}
 }
 
-static const struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+static const struct snd_soc_component_driver mpc5200_audio_dma_component = {
+	.name		= DRV_NAME,
 	.ops		= &psc_dma_ops,
 	.pcm_new	= &psc_dma_new,
 	.pcm_free	= &psc_dma_free,
@@ -468,7 +473,8 @@ int mpc5200_audio_dma_create(struct platform_device *op)
 	dev_set_drvdata(&op->dev, psc_dma);
 
 	/* Tell the ASoC OF helpers about it */
-	return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
+	return devm_snd_soc_register_component(&op->dev,
+					&mpc5200_audio_dma_component, NULL, 0);
 out_irq:
 	free_irq(psc_dma->irq, psc_dma);
 	free_irq(psc_dma->capture.irq, &psc_dma->capture);
@@ -487,8 +493,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
 
 	dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
 
-	snd_soc_unregister_platform(&op->dev);
-
 	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
 	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
 
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
index cdaf16367b47..2f80b21b2921 100644
--- a/sound/soc/fsl/wm1133-ev1.c
+++ b/sound/soc/fsl/wm1133-ev1.c
@@ -201,18 +201,18 @@ static struct snd_soc_jack_pin mic_jack_pins[] = {
 
 static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	/* Headphone jack detection */
 	snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
 			      &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
-	wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
+	wm8350_hp_jack_detect(component, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
 
 	/* Microphone jack detection */
 	snd_soc_card_jack_new(rtd->card, "Microphone",
 			      SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
 			      mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
-	wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE,
+	wm8350_mic_jack_detect(component, &mic_jack, SND_JACK_MICROPHONE,
 			       SND_JACK_BTN_0);
 
 	snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
index 53e11c6d4e22..915b894f99ce 100644
--- a/sound/soc/img/pistachio-internal-dac.c
+++ b/sound/soc/img/pistachio-internal-dac.c
@@ -122,26 +122,26 @@ static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
 	},
 };
 
-static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec)
+static int pistachio_internal_dac_codec_probe(struct snd_soc_component *component)
 {
-	struct pistachio_internal_dac *dac = snd_soc_codec_get_drvdata(codec);
+	struct pistachio_internal_dac *dac = snd_soc_component_get_drvdata(component);
 
-	snd_soc_codec_init_regmap(codec, dac->regmap);
+	snd_soc_component_init_regmap(component, dac->regmap);
 
 	return 0;
 }
 
-static const struct snd_soc_codec_driver pistachio_internal_dac_driver = {
-	.probe = pistachio_internal_dac_codec_probe,
-	.idle_bias_off = true,
-	.component_driver = {
-		.controls		= pistachio_internal_dac_snd_controls,
-		.num_controls		= ARRAY_SIZE(pistachio_internal_dac_snd_controls),
-		.dapm_widgets		= pistachio_internal_dac_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(pistachio_internal_dac_widgets),
-		.dapm_routes		= pistachio_internal_dac_routes,
-		.num_dapm_routes	= ARRAY_SIZE(pistachio_internal_dac_routes),
-	},
+static const struct snd_soc_component_driver pistachio_internal_dac_driver = {
+	.probe			= pistachio_internal_dac_codec_probe,
+	.controls		= pistachio_internal_dac_snd_controls,
+	.num_controls		= ARRAY_SIZE(pistachio_internal_dac_snd_controls),
+	.dapm_widgets		= pistachio_internal_dac_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pistachio_internal_dac_widgets),
+	.dapm_routes		= pistachio_internal_dac_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pistachio_internal_dac_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static int pistachio_internal_dac_probe(struct platform_device *pdev)
@@ -202,11 +202,12 @@ static int pistachio_internal_dac_probe(struct platform_device *pdev)
 	pm_runtime_enable(dev);
 	pm_runtime_idle(dev);
 
-	ret = snd_soc_register_codec(dev, &pistachio_internal_dac_driver,
+	ret = devm_snd_soc_register_component(dev,
+			&pistachio_internal_dac_driver,
 			pistachio_internal_dac_dais,
 			ARRAY_SIZE(pistachio_internal_dac_dais));
 	if (ret) {
-		dev_err(dev, "failed to register codec: %d\n", ret);
+		dev_err(dev, "failed to register component: %d\n", ret);
 		goto err_pwr;
 	}
 
@@ -225,7 +226,6 @@ static int pistachio_internal_dac_remove(struct platform_device *pdev)
 {
 	struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_codec(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pistachio_internal_dac_pwr_off(dac);
 	regulator_disable(dac->supply);
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 0f3604b55942..3672d36b4b66 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -1414,11 +1414,11 @@ static int sst_fill_module_list(struct snd_kcontrol *kctl,
  * name. First part of control name contains the pipe name (widget name).
  */
 static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
-	struct snd_soc_platform *platform)
+	struct snd_soc_component *component)
 {
 	struct snd_kcontrol *kctl;
 	int index, ret = 0;
-	struct snd_card *card = platform->component.card->snd_card;
+	struct snd_card *card = component->card->snd_card;
 	char *idx;
 
 	down_read(&card->controls_rwsem);
@@ -1468,13 +1468,13 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
 /**
  * sst_fill_linked_widgets - fill the parent pointer for the linked widget
  */
-static void sst_fill_linked_widgets(struct snd_soc_platform *platform,
+static void sst_fill_linked_widgets(struct snd_soc_component *component,
 						struct sst_ids *ids)
 {
 	struct snd_soc_dapm_widget *w;
 	unsigned int len = strlen(ids->parent_wname);
 
-	list_for_each_entry(w, &platform->component.card->widgets, list) {
+	list_for_each_entry(w, &component->card->widgets, list) {
 		if (!strncmp(ids->parent_wname, w->name, len)) {
 			ids->parent_w = w;
 			break;
@@ -1485,41 +1485,41 @@ static void sst_fill_linked_widgets(struct snd_soc_platform *platform,
 /**
  * sst_map_modules_to_pipe - fill algo/gains list for all pipes
  */
-static int sst_map_modules_to_pipe(struct snd_soc_platform *platform)
+static int sst_map_modules_to_pipe(struct snd_soc_component *component)
 {
 	struct snd_soc_dapm_widget *w;
 	int ret = 0;
 
-	list_for_each_entry(w, &platform->component.card->widgets, list) {
+	list_for_each_entry(w, &component->card->widgets, list) {
 		if (is_sst_dapm_widget(w) && (w->priv)) {
 			struct sst_ids *ids = w->priv;
 
-			dev_dbg(platform->dev, "widget type=%d name=%s\n",
+			dev_dbg(component->dev, "widget type=%d name=%s\n",
 					w->id, w->name);
 			INIT_LIST_HEAD(&ids->algo_list);
 			INIT_LIST_HEAD(&ids->gain_list);
-			ret = sst_fill_widget_module_info(w, platform);
+			ret = sst_fill_widget_module_info(w, component);
 
 			if (ret < 0)
 				return ret;
 
 			/* fill linked widgets */
 			if (ids->parent_wname !=  NULL)
-				sst_fill_linked_widgets(platform, ids);
+				sst_fill_linked_widgets(component, ids);
 		}
 	}
 	return 0;
 }
 
-int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+int sst_dsp_init_v2_dpcm(struct snd_soc_component *component)
 {
 	int i, ret = 0;
 	struct snd_soc_dapm_context *dapm =
-			snd_soc_component_get_dapm(&platform->component);
-	struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+			snd_soc_component_get_dapm(component);
+	struct sst_data *drv = snd_soc_component_get_drvdata(component);
 	unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3;
 
-	drv->byte_stream = devm_kzalloc(platform->dev,
+	drv->byte_stream = devm_kzalloc(component->dev,
 					SST_MAX_BIN_BYTES, GFP_KERNEL);
 	if (!drv->byte_stream)
 		return -ENOMEM;
@@ -1537,26 +1537,26 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
 		sst_gains[i].ramp_duration = SST_GAIN_RAMP_DURATION_DEFAULT;
 	}
 
-	ret = snd_soc_add_platform_controls(platform, sst_gain_controls,
+	ret = snd_soc_add_component_controls(component, sst_gain_controls,
 			ARRAY_SIZE(sst_gain_controls));
 	if (ret)
 		return ret;
 
 	/* Initialize algo control params */
-	ret = sst_algo_control_init(platform->dev);
+	ret = sst_algo_control_init(component->dev);
 	if (ret)
 		return ret;
-	ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
+	ret = snd_soc_add_component_controls(component, sst_algo_controls,
 			ARRAY_SIZE(sst_algo_controls));
 	if (ret)
 		return ret;
 
-	ret = snd_soc_add_platform_controls(platform, sst_slot_controls,
+	ret = snd_soc_add_component_controls(component, sst_slot_controls,
 			ARRAY_SIZE(sst_slot_controls));
 	if (ret)
 		return ret;
 
-	ret = sst_map_modules_to_pipe(platform);
+	ret = sst_map_modules_to_pipe(component);
 
 	return ret;
 }
diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c
index 1dbcab5a6ff0..6a44b19423cf 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c
@@ -107,8 +107,8 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
 	struct snd_sst_params str_params;
 	struct sst_compress_cb cb;
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
-	struct snd_soc_platform *platform = rtd->platform;
-	struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_data *ctx = snd_soc_component_get_drvdata(component);
 
 	stream = cstream->runtime->private_data;
 	/* construct fw structure for this*/
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 43e7fdd19f29..6c36da560877 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -697,26 +697,22 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return retval;
 }
 
-static int sst_soc_probe(struct snd_soc_platform *platform)
+static int sst_soc_probe(struct snd_soc_component *component)
 {
-	struct sst_data *drv = dev_get_drvdata(platform->dev);
+	struct sst_data *drv = dev_get_drvdata(component->dev);
 
-	drv->soc_card = platform->component.card;
-	return sst_dsp_init_v2_dpcm(platform);
+	drv->soc_card = component->card;
+	return sst_dsp_init_v2_dpcm(component);
 }
 
-static const struct snd_soc_platform_driver sst_soc_platform_drv  = {
+static const struct snd_soc_component_driver sst_soc_platform_drv  = {
+	.name		= DRV_NAME,
 	.probe		= sst_soc_probe,
 	.ops		= &sst_platform_ops,
 	.compr_ops	= &sst_platform_compr_ops,
 	.pcm_new	= sst_pcm_new,
 };
 
-static const struct snd_soc_component_driver sst_component = {
-	.name		= "sst",
-};
-
-
 static int sst_platform_probe(struct platform_device *pdev)
 {
 	struct sst_data *drv;
@@ -740,26 +736,16 @@ static int sst_platform_probe(struct platform_device *pdev)
 	mutex_init(&drv->lock);
 	dev_set_drvdata(&pdev->dev, drv);
 
-	ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
-	if (ret) {
-		dev_err(&pdev->dev, "registering soc platform failed\n");
-		return ret;
-	}
-
-	ret = snd_soc_register_component(&pdev->dev, &sst_component,
+	ret = devm_snd_soc_register_component(&pdev->dev, &sst_soc_platform_drv,
 				sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
-	if (ret) {
+	if (ret)
 		dev_err(&pdev->dev, "registering cpu dais failed\n");
-		snd_soc_unregister_platform(&pdev->dev);
-	}
+
 	return ret;
 }
 
 static int sst_platform_remove(struct platform_device *pdev)
 {
-
-	snd_soc_unregister_component(&pdev->dev);
-	snd_soc_unregister_platform(&pdev->dev);
 	dev_dbg(&pdev->dev, "sst_platform_remove success\n");
 	return 0;
 }
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h
index 31a58c25472c..5f729df57bb5 100644
--- a/sound/soc/intel/atom/sst-mfld-platform.h
+++ b/sound/soc/intel/atom/sst-mfld-platform.h
@@ -27,6 +27,8 @@
 extern struct sst_device *sst;
 extern const struct snd_compr_ops sst_platform_compr_ops;
 
+#define DRV_NAME "sst"
+
 #define SST_MONO		1
 #define SST_STEREO		2
 #define SST_MAX_CAP		5
@@ -155,7 +157,7 @@ struct sst_device {
 
 struct sst_data;
 
-int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
+int sst_dsp_init_v2_dpcm(struct snd_soc_component *component);
 int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute);
 int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable);
 int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable);
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
index c54529320f07..aabb35bf6b96 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
@@ -23,6 +23,7 @@
 #include "../common/sst-dsp-priv.h"
 #include "../common/sst-dsp.h"
 
+#define DRV_NAME "byt-dai"
 #define BYT_PCM_COUNT		2
 
 static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
@@ -69,8 +70,8 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 	u32 rate, bits;
@@ -141,8 +142,8 @@ static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
 static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 	int ret;
@@ -174,8 +175,8 @@ static void sst_byt_pcm_work(struct work_struct *work)
 static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 
@@ -216,8 +217,8 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
 	struct snd_pcm_substream *substream = pcm_data->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt *byt = pdata->byt;
 	u32 pos, hw_pos;
 
@@ -238,8 +239,8 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 
 	dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
@@ -250,8 +251,8 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
 static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 
@@ -278,8 +279,8 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
 static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sst_byt_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_byt_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 	int ret;
@@ -324,8 +325,8 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_pcm *pcm = rtd->pcm;
 	size_t size;
-	struct snd_soc_platform *platform = rtd->platform;
-	struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_pdata *pdata = dev_get_platdata(component->dev);
 	int ret = 0;
 
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
@@ -366,21 +367,21 @@ static struct snd_soc_dai_driver byt_dais[] = {
 	},
 };
 
-static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
+static int sst_byt_pcm_probe(struct snd_soc_component *component)
 {
-	struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
+	struct sst_pdata *plat_data = dev_get_platdata(component->dev);
 	struct sst_byt_priv_data *priv_data;
 	int i;
 
 	if (!plat_data)
 		return -ENODEV;
 
-	priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
+	priv_data = devm_kzalloc(component->dev, sizeof(*priv_data),
 				 GFP_KERNEL);
 	if (!priv_data)
 		return -ENOMEM;
 	priv_data->byt = plat_data->dsp;
-	snd_soc_platform_set_drvdata(platform, priv_data);
+	snd_soc_component_set_drvdata(component, priv_data);
 
 	for (i = 0; i < BYT_PCM_COUNT; i++) {
 		mutex_init(&priv_data->pcm[i].mutex);
@@ -390,22 +391,13 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
 	return 0;
 }
 
-static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
-{
-	return 0;
-}
-
-static const struct snd_soc_platform_driver byt_soc_platform = {
+static const struct snd_soc_component_driver byt_dai_component = {
+	.name		= DRV_NAME,
 	.probe		= sst_byt_pcm_probe,
-	.remove		= sst_byt_pcm_remove,
 	.ops		= &sst_byt_pcm_ops,
 	.pcm_new	= sst_byt_pcm_new,
 };
 
-static const struct snd_soc_component_driver byt_dai_component = {
-	.name		= "byt-dai",
-};
-
 #ifdef CONFIG_PM
 static int sst_byt_pcm_dev_suspend_late(struct device *dev)
 {
@@ -461,19 +453,13 @@ static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return -ENODEV;
 
-	ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
-	if (ret < 0)
-		goto err_plat;
-
-	ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
+	ret = devm_snd_soc_register_component(&pdev->dev, &byt_dai_component,
 					 byt_dais, ARRAY_SIZE(byt_dais));
 	if (ret < 0)
-		goto err_comp;
+		goto err_plat;
 
 	return 0;
 
-err_comp:
-	snd_soc_unregister_platform(&pdev->dev);
 err_plat:
 	sst_byt_dsp_free(&pdev->dev, sst_pdata);
 	return ret;
@@ -483,8 +469,6 @@ static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
 {
 	struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
 
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
 	sst_byt_dsp_free(&pdev->dev, sst_pdata);
 
 	return 0;
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index fefb1ee9fec6..eedc83b96fbb 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -256,6 +256,20 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
           create an alsa sound card for RT5663 + RT5514 + MAX98927.
           Say Y or m if you have such a device. This is a recommended option.
           If unsure select "N".
+
+config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
+	tristate "KBL with DA7219 and MAX98357A in I2S Mode"
+	depends on MFD_INTEL_LPSS && I2C && ACPI
+	select SND_SOC_DA7219
+	select SND_SOC_MAX98357A
+	select SND_SOC_DMIC
+	select SND_SOC_HDAC_HDMI
+	help
+	  This adds support for ASoC Onboard Codec I2S machine driver. This will
+	  create an alsa sound card for DA7219 + MAX98357A I2S audio codec.
+	  Say Y if you have such a device.
+	  If unsure select "N".
+
 endif ## SND_SOC_INTEL_SKYLAKE
 
 endif ## SND_SOC_INTEL_MACH
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 69d2dfaeb00c..6fae506c40fa 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -14,6 +14,7 @@ snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
 snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
 snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
 snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
+snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
 snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
 snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
 snd-soc-skl_rt286-objs := skl_rt286.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max9
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o
+obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 058b8ccedf02..6ea360f33575 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -34,7 +34,7 @@
 
 struct bdw_rt5677_priv {
 	struct gpio_desc *gpio_hp_en;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 };
 
 static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w,
@@ -183,7 +183,8 @@ static const struct snd_soc_ops bdw_rt5677_ops = {
 
 static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_pdata *pdata = dev_get_platdata(component->dev);
 	struct sst_hsw *broadwell = pdata->dsp;
 	int ret;
 
@@ -203,26 +204,26 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct bdw_rt5677_priv *bdw_rt5677 =
 			snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct snd_soc_component *component = rtd->codec_dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 	int ret;
 
-	ret = devm_acpi_dev_add_driver_gpios(codec->dev, bdw_rt5677_gpios);
+	ret = devm_acpi_dev_add_driver_gpios(component->dev, bdw_rt5677_gpios);
 	if (ret)
-		dev_warn(codec->dev, "Failed to add driver gpios\n");
+		dev_warn(component->dev, "Failed to add driver gpios\n");
 
 	/* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1.
 	 * The ASRC clock source is clk_i2s1_asrc.
 	 */
-	rt5677_sel_asrc_clk_src(codec, RT5677_DA_STEREO_FILTER |
+	rt5677_sel_asrc_clk_src(component, RT5677_DA_STEREO_FILTER |
 			RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE,
 			RT5677_CLK_SEL_I2S1_ASRC);
 
 	/* Request rt5677 GPIO for headphone amp control */
-	bdw_rt5677->gpio_hp_en = devm_gpiod_get(codec->dev, "headphone-enable",
+	bdw_rt5677->gpio_hp_en = devm_gpiod_get(component->dev, "headphone-enable",
 						GPIOD_OUT_LOW);
 	if (IS_ERR(bdw_rt5677->gpio_hp_en)) {
-		dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n");
+		dev_err(component->dev, "Can't find HP_AMP_SHDN_L gpio\n");
 		return PTR_ERR(bdw_rt5677->gpio_hp_en);
 	}
 
@@ -230,25 +231,25 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
 	if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack",
 			SND_JACK_HEADPHONE, &headphone_jack,
 			&headphone_jack_pin, 1)) {
-		headphone_jack_gpio.gpiod_dev = codec->dev;
+		headphone_jack_gpio.gpiod_dev = component->dev;
 		if (snd_soc_jack_add_gpios(&headphone_jack, 1,
 				&headphone_jack_gpio))
-			dev_err(codec->dev, "Can't add headphone jack gpio\n");
+			dev_err(component->dev, "Can't add headphone jack gpio\n");
 	} else {
-		dev_err(codec->dev, "Can't create headphone jack\n");
+		dev_err(component->dev, "Can't create headphone jack\n");
 	}
 
 	/* Create and initialize mic jack */
 	if (!snd_soc_card_jack_new(rtd->card, "Mic Jack",
 			SND_JACK_MICROPHONE, &mic_jack,
 			&mic_jack_pin, 1)) {
-		mic_jack_gpio.gpiod_dev = codec->dev;
+		mic_jack_gpio.gpiod_dev = component->dev;
 		if (snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio))
-			dev_err(codec->dev, "Can't add mic jack gpio\n");
+			dev_err(component->dev, "Can't add mic jack gpio\n");
 	} else {
-		dev_err(codec->dev, "Can't create mic jack\n");
+		dev_err(component->dev, "Can't create mic jack\n");
 	}
-	bdw_rt5677->codec = codec;
+	bdw_rt5677->component = component;
 
 	snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
 	return 0;
@@ -301,8 +302,8 @@ static int bdw_rt5677_suspend_pre(struct snd_soc_card *card)
 	struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
 	struct snd_soc_dapm_context *dapm;
 
-	if (bdw_rt5677->codec) {
-		dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec);
+	if (bdw_rt5677->component) {
+		dapm = snd_soc_component_get_dapm(bdw_rt5677->component);
 		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
 	}
 	return 0;
@@ -313,8 +314,8 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card)
 	struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
 	struct snd_soc_dapm_context *dapm;
 
-	if (bdw_rt5677->codec) {
-		dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec);
+	if (bdw_rt5677->component) {
+		dapm = snd_soc_component_get_dapm(bdw_rt5677->component);
 		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
 	}
 	return 0;
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index 6dcbbcefc25b..7b0ee67b4fc8 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -78,7 +78,7 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
 
 static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	int ret = 0;
 	ret = snd_soc_card_jack_new(rtd->card, "Headset",
 		SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
@@ -86,7 +86,7 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
-	rt286_mic_detect(codec, &broadwell_headset);
+	rt286_mic_detect(component, &broadwell_headset);
 	return 0;
 }
 
@@ -132,7 +132,8 @@ static const struct snd_soc_ops broadwell_rt286_ops = {
 
 static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_pdata *pdata = dev_get_platdata(component->dev);
 	struct sst_hsw *broadwell = pdata->dsp;
 	int ret;
 
@@ -224,10 +225,9 @@ static int broadwell_suspend(struct snd_soc_card *card){
 
 	list_for_each_entry(component, &card->component_dev_list, card_list) {
 		if (!strcmp(component->name, "i2c-INT343A:00")) {
-			struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-			dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
-			rt286_mic_detect(codec, NULL);
+			dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
+			rt286_mic_detect(component, NULL);
 			break;
 		}
 	}
@@ -239,10 +239,9 @@ static int broadwell_resume(struct snd_soc_card *card){
 
 	list_for_each_entry(component, &card->component_dev_list, card_list) {
 		if (!strcmp(component->name, "i2c-INT343A:00")) {
-			struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-			dev_dbg(codec->dev, "enabling jack detect for resume.\n");
-			rt286_mic_detect(codec, &broadwell_headset);
+			dev_dbg(component->dev, "enabling jack detect for resume.\n");
+			rt286_mic_detect(component, &broadwell_headset);
 			break;
 		}
 	}
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index f8a91a6f2a17..668c0934e942 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -169,7 +169,7 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	/* Configure sysclk for codec */
 	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 19200000,
@@ -192,7 +192,7 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
-	da7219_aad_jack_det(codec, &broxton_headset);
+	da7219_aad_jack_det(component, &broxton_headset);
 
 	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
@@ -522,12 +522,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
 {
 	struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card);
 	struct bxt_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -545,10 +545,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 /* broxton audio machine driver for SPT + da7219 */
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index 7843104fadcb..875d85119c66 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -167,7 +167,7 @@ static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
 
 static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	int ret = 0;
 
 	ret = snd_soc_card_jack_new(rtd->card, "Headset",
@@ -178,7 +178,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
-	rt298_mic_detect(codec, &broxton_headset);
+	rt298_mic_detect(component, &broxton_headset);
 
 	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
@@ -496,12 +496,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
 {
 	struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card);
 	struct bxt_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -519,10 +519,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 
diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c
index de9788a3fd06..df902d82145e 100644
--- a/sound/soc/intel/boards/byt-rt5640.c
+++ b/sound/soc/intel/boards/byt-rt5640.c
@@ -131,7 +131,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
 	int ret;
-	struct snd_soc_codec *codec = runtime->codec;
+	struct snd_soc_component *component = runtime->codec_dai->component;
 	struct snd_soc_card *card = runtime->card;
 	const struct snd_soc_dapm_route *custom_map;
 	int num_routes;
@@ -165,7 +165,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 
 	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
-		ret = rt5640_dmic_enable(codec, 0, 0);
+		ret = rt5640_dmic_enable(component, 0, 0);
 		if (ret)
 			return ret;
 	}
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index b6a1cfeec830..a8d8bff788e7 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -444,14 +444,14 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
 	struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
-	struct snd_soc_codec *codec = runtime->codec;
+	struct snd_soc_component *component = runtime->codec_dai->component;
 	const struct snd_soc_dapm_route *custom_map;
 	int num_routes;
 	int ret;
 
 	card->dapm.idle_bias_off = true;
 
-	rt5640_sel_asrc_clk_src(codec,
+	rt5640_sel_asrc_clk_src(component,
 				RT5640_DA_STEREO_FILTER |
 				RT5640_DA_MONO_L_FILTER	|
 				RT5640_DA_MONO_R_FILTER	|
@@ -522,12 +522,12 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 
 	if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
-		snd_soc_update_bits(codec,  RT5640_IN1_IN2, RT5640_IN_DF1,
+		snd_soc_component_update_bits(component,  RT5640_IN1_IN2, RT5640_IN_DF1,
 				    RT5640_IN_DF1);
 	}
 
 	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
-		ret = rt5640_dmic_enable(codec, 0, 0);
+		ret = rt5640_dmic_enable(component, 0, 0);
 		if (ret)
 			return ret;
 	}
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 456526a93dd5..b6bf92191b9a 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -296,7 +296,7 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
 static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
-	struct snd_soc_codec *codec = runtime->codec;
+	struct snd_soc_component *codec = runtime->codec_dai->component;
 	struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
 	const struct snd_soc_dapm_route *custom_map;
 	int num_routes;
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 31641aab62cd..49ba1a956a06 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -252,14 +252,14 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
 	struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
-	struct snd_soc_codec *codec = runtime->codec;
+	struct snd_soc_component *component = runtime->codec_dai->component;
 	int jack_type;
 	int ret;
 
 	if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
 	    (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
 		/* Select clk_i2s2_asrc as ASRC clock source */
-		rt5645_sel_asrc_clk_src(codec,
+		rt5645_sel_asrc_clk_src(component,
 					RT5645_DA_STEREO_FILTER |
 					RT5645_DA_MONO_L_FILTER |
 					RT5645_DA_MONO_R_FILTER |
@@ -267,7 +267,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 					RT5645_CLK_SEL_I2S2_ASRC);
 	} else {
 		/* Select clk_i2s1_asrc as ASRC clock source */
-		rt5645_sel_asrc_clk_src(codec,
+		rt5645_sel_asrc_clk_src(component,
 					RT5645_DA_STEREO_FILTER |
 					RT5645_DA_MONO_L_FILTER |
 					RT5645_DA_MONO_R_FILTER |
@@ -310,7 +310,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 	}
 
-	rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack);
+	rt5645_set_jack_detect(component, &ctx->jack, &ctx->jack, &ctx->jack);
 
 
 	/*
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index c14a52d2f714..e68ec32720a4 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -183,10 +183,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 {
 	int ret;
 	struct snd_soc_dai *codec_dai = runtime->codec_dai;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
 
-	if (devm_acpi_dev_add_driver_gpios(codec->dev, cht_rt5672_gpios))
+	if (devm_acpi_dev_add_driver_gpios(component->dev, cht_rt5672_gpios))
 		dev_warn(runtime->dev, "Unable to add GPIO mapping table\n");
 
 	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
@@ -201,7 +201,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 	 * be supported by RT5672. Otherwise, ASRC will be disabled and cause
 	 * noise.
 	 */
-	rt5670_sel_asrc_clk_src(codec,
+	rt5670_sel_asrc_clk_src(component,
 				RT5670_DA_STEREO_FILTER
 				| RT5670_DA_MONO_L_FILTER
 				| RT5670_DA_MONO_R_FILTER
@@ -219,7 +219,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
         if (ret)
                 return ret;
 
-	rt5670_set_jack_detect(codec, &ctx->headset);
+	rt5670_set_jack_detect(component, &ctx->headset);
 	if (ctx->mclk) {
 		/*
 		 * The firmware might enable the clock at
@@ -333,10 +333,9 @@ static int cht_suspend_pre(struct snd_soc_card *card)
 	list_for_each_entry(component, &card->component_dev_list, card_list) {
 		if (!strncmp(component->name,
 			     ctx->codec_name, sizeof(ctx->codec_name))) {
-			struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-			dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
-			rt5670_jack_suspend(codec);
+			dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
+			rt5670_jack_suspend(component);
 			break;
 		}
 	}
@@ -351,10 +350,9 @@ static int cht_resume_post(struct snd_soc_card *card)
 	list_for_each_entry(component, &card->component_dev_list, card_list) {
 		if (!strncmp(component->name,
 			     ctx->codec_name, sizeof(ctx->codec_name))) {
-			struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-			dev_dbg(codec->dev, "enabling jack detect for resume.\n");
-			rt5670_jack_resume(codec);
+			dev_dbg(component->dev, "enabling jack detect for resume.\n");
+			rt5670_jack_resume(component);
 			break;
 		}
 	}
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
index 3c5160779204..eab1f439dd3f 100644
--- a/sound/soc/intel/boards/haswell.c
+++ b/sound/soc/intel/boards/haswell.c
@@ -87,7 +87,8 @@ static const struct snd_soc_ops haswell_rt5640_ops = {
 
 static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_pdata *pdata = dev_get_platdata(component->dev);
 	struct sst_hsw *haswell = pdata->dsp;
 	int ret;
 
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
new file mode 100644
index 000000000000..e84baafd5f63
--- /dev/null
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -0,0 +1,613 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2017-18 Intel Corporation.
+
+/*
+ * Intel Kabylake I2S Machine Driver with MAX98357A & DA7219 Codecs
+ *
+ * Modified from:
+ *   Intel Kabylake I2S Machine driver supporting MAXIM98927 and
+ *   RT5663 codecs
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/da7219.h"
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+#include "../../codecs/da7219-aad.h"
+
+#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
+#define KBL_MAXIM_CODEC_DAI "HiFi"
+#define MAXIM_DEV0_NAME "MX98357A:00"
+#define DUAL_CHANNEL 2
+#define QUAD_CHANNEL 4
+
+static struct snd_soc_card *kabylake_audio_card;
+static struct snd_soc_jack skylake_hdmi[3];
+
+struct kbl_hdmi_pcm {
+	struct list_head head;
+	struct snd_soc_dai *codec_dai;
+	int device;
+};
+
+struct kbl_codec_private {
+	struct snd_soc_jack kabylake_headset;
+	struct list_head hdmi_pcm_list;
+};
+
+enum {
+	KBL_DPCM_AUDIO_PB = 0,
+	KBL_DPCM_AUDIO_CP,
+	KBL_DPCM_AUDIO_DMIC_CP,
+	KBL_DPCM_AUDIO_HDMI1_PB,
+	KBL_DPCM_AUDIO_HDMI2_PB,
+	KBL_DPCM_AUDIO_HDMI3_PB,
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret = 0;
+
+	codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI);
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
+		return -EIO;
+	}
+
+	/* Configure sysclk for codec */
+	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
+				     SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(card->dev, "can't set codec sysclk configuration\n");
+		return ret;
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		ret = snd_soc_dai_set_pll(codec_dai, 0,
+				     DA7219_SYSCLK_MCLK, 0, 0);
+		if (ret)
+			dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+	} else if (SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = snd_soc_dai_set_pll(codec_dai, 0,	DA7219_SYSCLK_PLL_SRM,
+				     0, DA7219_PLL_FREQ_OUT_98304);
+		if (ret)
+			dev_err(card->dev, "failed to start PLL: %d\n", ret);
+	}
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new kabylake_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SPK("Spk", NULL),
+	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+	SND_SOC_DAPM_SPK("DP", NULL),
+	SND_SOC_DAPM_SPK("HDMI", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+			platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route kabylake_map[] = {
+	{ "Headphone Jack", NULL, "HPL" },
+	{ "Headphone Jack", NULL, "HPR" },
+
+	/* speaker */
+	{ "Spk", NULL, "Speaker" },
+
+	/* other jacks */
+	{ "MIC", NULL, "Headset Mic" },
+	{ "DMic", NULL, "SoC DMIC" },
+
+	{ "HDMI", NULL, "hif5 Output" },
+	{ "DP", NULL, "hif6 Output" },
+
+	/* CODEC BE connections */
+	{ "HiFi Playback", NULL, "ssp0 Tx" },
+	{ "ssp0 Tx", NULL, "codec0_out" },
+
+	{ "Playback", NULL, "ssp1 Tx" },
+	{ "ssp1 Tx", NULL, "codec1_out" },
+
+	{ "codec0_in", NULL, "ssp1 Rx" },
+	{ "ssp1 Rx", NULL, "Capture" },
+
+	/* DMIC */
+	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
+	{ "DMIC01 Rx", NULL, "DMIC AIF" },
+
+	{ "hifi1", NULL, "iDisp1 Tx" },
+	{ "iDisp1 Tx", NULL, "iDisp1_out" },
+	{ "hifi2", NULL, "iDisp2 Tx" },
+	{ "iDisp2 Tx", NULL, "iDisp2_out" },
+	{ "hifi3", NULL, "iDisp3 Tx"},
+	{ "iDisp3 Tx", NULL, "iDisp3_out"},
+
+	{ "Headphone Jack", NULL, "Platform Clock" },
+	{ "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will convert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = DUAL_CHANNEL;
+
+	/* set SSP to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+	return 0;
+}
+
+static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_component *component = rtd->codec_dai->component;
+	struct snd_soc_jack *jack;
+	int ret;
+
+	/*
+	 * Headset buttons map to the google Reference headset.
+	 * These can be configured by userspace.
+	 */
+	ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
+			SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+			&ctx->kabylake_headset, NULL, 0);
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+		return ret;
+	}
+
+	jack = &ctx->kabylake_headset;
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+	da7219_aad_jack_det(component, &ctx->kabylake_headset);
+
+	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+	if (ret)
+		dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret);
+
+	return ret;
+}
+
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
+{
+	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *dai = rtd->codec_dai;
+	struct kbl_hdmi_pcm *pcm;
+
+	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+	if (!pcm)
+		return -ENOMEM;
+
+	pcm->device = device;
+	pcm->codec_dai = dai;
+
+	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+	return 0;
+}
+
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
+}
+
+static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+	return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
+
+static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_component *component = rtd->cpu_dai->component;
+
+	dapm = snd_soc_component_get_dapm(component);
+	snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+	return 0;
+}
+
+static const unsigned int rates[] = {
+	48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list  = rates,
+	.mask = 0,
+};
+
+static const unsigned int channels[] = {
+	DUAL_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+	.count = ARRAY_SIZE(channels),
+	.list = channels,
+	.mask = 0,
+};
+
+static unsigned int channels_quad[] = {
+	QUAD_CHANNEL,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
+	.count = ARRAY_SIZE(channels_quad),
+	.list = channels_quad,
+	.mask = 0,
+};
+
+static int kbl_fe_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/*
+	 * On this platform for PCM device we support,
+	 * 48Khz
+	 * stereo
+	 * 16 bit audio
+	 */
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					   &constraints_channels);
+
+	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+	snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+	return 0;
+}
+
+static const struct snd_soc_ops kabylake_da7219_fe_ops = {
+	.startup = kbl_fe_startup,
+};
+
+static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *channels = hw_param_interval(params,
+				SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	/*
+	 * set BE channel constraint as user FE channels
+	 */
+
+	if (params_channels(params) == 2)
+		channels->min = channels->max = 2;
+	else
+		channels->min = channels->max = 4;
+
+	return 0;
+}
+
+static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+			&constraints_channels_quad);
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops kabylake_dmic_ops = {
+	.startup = kabylake_dmic_startup,
+};
+
+static const unsigned int rates_16000[] = {
+	16000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
+	.count = ARRAY_SIZE(rates_16000),
+	.list  = rates_16000,
+};
+
+static const unsigned int ch_mono[] = {
+	1,
+};
+
+/* kabylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link kabylake_dais[] = {
+	/* Front End DAI links */
+	[KBL_DPCM_AUDIO_PB] = {
+		.name = "Kbl Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.init = kabylake_da7219_fe_init,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_playback = 1,
+		.ops = &kabylake_da7219_fe_ops,
+	},
+	[KBL_DPCM_AUDIO_CP] = {
+		.name = "Kbl Audio Capture Port",
+		.stream_name = "Audio Record",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_capture = 1,
+	},
+	[KBL_DPCM_AUDIO_DMIC_CP] = {
+		.name = "Kbl Audio DMIC cap",
+		.stream_name = "dmiccap",
+		.cpu_dai_name = "DMIC Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &kabylake_dmic_ops,
+	},
+	[KBL_DPCM_AUDIO_HDMI1_PB] = {
+		.name = "Kbl HDMI Port1",
+		.stream_name = "Hdmi1",
+		.cpu_dai_name = "HDMI1 Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = NULL,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+	[KBL_DPCM_AUDIO_HDMI2_PB] = {
+		.name = "Kbl HDMI Port2",
+		.stream_name = "Hdmi2",
+		.cpu_dai_name = "HDMI2 Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = NULL,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+	[KBL_DPCM_AUDIO_HDMI3_PB] = {
+		.name = "Kbl HDMI Port3",
+		.stream_name = "Hdmi3",
+		.cpu_dai_name = "HDMI3 Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_playback = 1,
+		.init = NULL,
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+
+	/* Back End DAI links */
+	{
+		/* SSP0 - Codec */
+		.name = "SSP0-Codec",
+		.id = 0,
+		.cpu_dai_name = "SSP0 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codec_name = MAXIM_DEV0_NAME,
+		.codec_dai_name = KBL_MAXIM_CODEC_DAI,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = kabylake_ssp_fixup,
+		.dpcm_playback = 1,
+	},
+	{
+		/* SSP1 - Codec */
+		.name = "SSP1-Codec",
+		.id = 1,
+		.cpu_dai_name = "SSP1 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codec_name = "i2c-DLGS7219:00",
+		.codec_dai_name = KBL_DIALOG_CODEC_DAI,
+		.init = kabylake_da7219_codec_init,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = kabylake_ssp_fixup,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "dmic01",
+		.id = 2,
+		.cpu_dai_name = "DMIC01 Pin",
+		.codec_name = "dmic-codec",
+		.codec_dai_name = "dmic-hifi",
+		.platform_name = "0000:00:1f.3",
+		.be_hw_params_fixup = kabylake_dmic_fixup,
+		.ignore_suspend = 1,
+		.dpcm_capture = 1,
+		.no_pcm = 1,
+	},
+	{
+		.name = "iDisp1",
+		.id = 3,
+		.cpu_dai_name = "iDisp1 Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi1",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = kabylake_hdmi1_init,
+		.no_pcm = 1,
+	},
+	{
+		.name = "iDisp2",
+		.id = 4,
+		.cpu_dai_name = "iDisp2 Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi2",
+		.platform_name = "0000:00:1f.3",
+		.init = kabylake_hdmi2_init,
+		.dpcm_playback = 1,
+		.no_pcm = 1,
+	},
+	{
+		.name = "iDisp3",
+		.id = 5,
+		.cpu_dai_name = "iDisp3 Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi3",
+		.platform_name = "0000:00:1f.3",
+		.init = kabylake_hdmi3_init,
+		.dpcm_playback = 1,
+		.no_pcm = 1,
+	},
+};
+
+#define NAME_SIZE	32
+static int kabylake_card_late_probe(struct snd_soc_card *card)
+{
+	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
+	struct kbl_hdmi_pcm *pcm;
+	struct snd_soc_component *component = NULL;
+	int err, i = 0;
+	char jack_name[NAME_SIZE];
+
+	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+		component = pcm->codec_dai->component;
+		snprintf(jack_name, sizeof(jack_name),
+			"HDMI/DP, pcm=%d Jack", pcm->device);
+		err = snd_soc_card_jack_new(card, jack_name,
+					SND_JACK_AVOUT, &skylake_hdmi[i],
+					NULL, 0);
+
+		if (err)
+			return err;
+
+		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+				&skylake_hdmi[i]);
+		if (err < 0)
+			return err;
+
+		i++;
+
+	}
+
+	if (!component)
+		return -EINVAL;
+
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+/* kabylake audio machine driver for SPT + DA7219 */
+static struct snd_soc_card kabylake_audio_card_da7219_m98357a = {
+	.name = "kblda7219max",
+	.owner = THIS_MODULE,
+	.dai_link = kabylake_dais,
+	.num_links = ARRAY_SIZE(kabylake_dais),
+	.controls = kabylake_controls,
+	.num_controls = ARRAY_SIZE(kabylake_controls),
+	.dapm_widgets = kabylake_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
+	.dapm_routes = kabylake_map,
+	.num_dapm_routes = ARRAY_SIZE(kabylake_map),
+	.fully_routed = true,
+	.late_probe = kabylake_card_late_probe,
+};
+
+static int kabylake_audio_probe(struct platform_device *pdev)
+{
+	struct kbl_codec_private *ctx;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+	if (!ctx)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+	kabylake_audio_card =
+		(struct snd_soc_card *)pdev->id_entry->driver_data;
+
+	kabylake_audio_card->dev = &pdev->dev;
+	snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
+	return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
+}
+
+static const struct platform_device_id kbl_board_ids[] = {
+	{
+		.name = "kbl_da7219_max98357a",
+		.driver_data =
+			(kernel_ulong_t)&kabylake_audio_card_da7219_m98357a,
+	},
+	{ }
+};
+
+static struct platform_driver kabylake_audio = {
+	.probe = kabylake_audio_probe,
+	.driver = {
+		.name = "kbl_da7219_max98357a",
+		.pm = &snd_soc_pm_ops,
+	},
+	.id_table = kbl_board_ids,
+};
+
+module_platform_driver(kabylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode");
+MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_da7219_max98357a");
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index f5df6bca3156..3c9585eb6860 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -272,7 +272,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
 	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	struct snd_soc_jack *jack;
 
 	/*
@@ -294,7 +294,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-	rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+	rt5663_set_jack_detect(component, &ctx->kabylake_headset);
 	return ret;
 }
 
@@ -448,7 +448,7 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
 	int ret;
 
 	/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
-	rt5663_sel_asrc_clk_src(codec_dai->codec,
+	rt5663_sel_asrc_clk_src(codec_dai->component,
 			RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
 			RT5663_CLK_SEL_I2S1_ASRC);
 
@@ -898,12 +898,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -921,10 +921,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 /* kabylake audio machine driver for SPT + RT5663 */
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 90ea98f01c4c..69c3d8446f06 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -178,7 +178,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	struct snd_soc_jack *jack;
 
 	/*
@@ -200,7 +200,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-	rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
+	rt5663_set_jack_detect(component, &ctx->kabylake_headset);
 
 	ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
 	if (ret)
@@ -333,7 +333,7 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
 	int ret;
 
 	/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
-	rt5663_sel_asrc_clk_src(codec_dai->codec,
+	rt5663_sel_asrc_clk_src(codec_dai->component,
 			RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
 			RT5663_CLK_SEL_I2S1_ASRC);
 
@@ -599,12 +599,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
 	struct kbl_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP,pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -620,10 +620,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 /*
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 1b5a689dc99b..9a7a0646bffe 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -165,7 +165,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
 static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	/*
 	 * Headset buttons map to the google Reference headset.
@@ -180,7 +180,7 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
-	nau8825_enable_jack_detect(codec, &skylake_headset);
+	nau8825_enable_jack_detect(component, &skylake_headset);
 
 	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
@@ -592,12 +592,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card);
 	struct skl_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -616,10 +616,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 /* skylake audio machine driver for SPT + NAU88L25 */
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 7bea4bc77481..212ac8971e55 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -195,7 +195,7 @@ static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd)
 static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int ret;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	/*
 	 * 4 buttons here map to the google Reference headset
@@ -210,7 +210,7 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 	}
 
-	nau8825_enable_jack_detect(codec, &skylake_headset);
+	nau8825_enable_jack_detect(component, &skylake_headset);
 
 	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
@@ -643,12 +643,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
 	struct skl_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -667,10 +667,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 /* skylake audio machine driver for SPT + NAU88L25 */
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index 2bc4cfca594e..737d5615b0ef 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -130,7 +130,7 @@ static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd)
 
 static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	int ret;
 
 	ret = snd_soc_card_jack_new(rtd->card, "Headset",
@@ -141,7 +141,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
-	rt286_mic_detect(codec, &skylake_headset);
+	rt286_mic_detect(component, &skylake_headset);
 
 	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
@@ -478,12 +478,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card)
 {
 	struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
 	struct skl_hdmi_pcm *pcm;
-	struct snd_soc_codec *codec = NULL;
+	struct snd_soc_component *component = NULL;
 	int err, i = 0;
 	char jack_name[NAME_SIZE];
 
 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
-		codec = pcm->codec_dai->codec;
+		component = pcm->codec_dai->component;
 		snprintf(jack_name, sizeof(jack_name),
 			"HDMI/DP, pcm=%d Jack", pcm->device);
 		err = snd_soc_card_jack_new(card, jack_name,
@@ -501,10 +501,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card)
 		i++;
 	}
 
-	if (!codec)
+	if (!component)
 		return -EINVAL;
 
-	return hdac_hdmi_jack_port_init(codec, &card->dapm);
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
 /* skylake audio machine driver for SPT + RT286S */
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.h b/sound/soc/intel/haswell/sst-haswell-ipc.h
index 06d71aefa1fe..fbc14df139e4 100644
--- a/sound/soc/intel/haswell/sst-haswell-ipc.h
+++ b/sound/soc/intel/haswell/sst-haswell-ipc.h
@@ -22,6 +22,8 @@
 #include <linux/platform_device.h>
 #include <sound/asound.h>
 
+#define DRV_NAME "haswell-dai"
+
 #define SST_HSW_NO_CHANNELS		4
 #define SST_HSW_MAX_DX_REGIONS		14
 #define SST_HSW_DX_CONTEXT_SIZE        (640 * 1024)
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c
index c044400540ec..fe2c826e710c 100644
--- a/sound/soc/intel/haswell/sst-haswell-pcm.c
+++ b/sound/soc/intel/haswell/sst-haswell-pcm.c
@@ -181,11 +181,11 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
 static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(platform);
+		snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 volume;
@@ -230,11 +230,11 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
 static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(platform);
+		snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 volume;
@@ -273,8 +273,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
 static int hsw_volume_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 volume;
 
@@ -302,8 +302,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
 static int hsw_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 	unsigned int volume = 0;
 
@@ -322,8 +322,8 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol,
 static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
 
@@ -336,8 +336,8 @@ static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol,
 static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 	int ret = 0;
 	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
@@ -370,8 +370,8 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,
 static int hsw_waves_param_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 
 	/* return a matching line from param buffer */
@@ -381,8 +381,8 @@ static int hsw_waves_param_get(struct snd_kcontrol *kcontrol,
 static int hsw_waves_param_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
-	struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 	int ret;
 	enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES;
@@ -472,8 +472,8 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw *hsw = pdata->hsw;
 	struct sst_module *module_data;
@@ -674,8 +674,8 @@ static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
 static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw_stream *sst_stream;
 	struct sst_hsw *hsw = pdata->hsw;
@@ -718,8 +718,8 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
 	struct snd_pcm_substream *substream = pcm_data->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct sst_hsw *hsw = pdata->hsw;
 	u32 pos;
 	snd_pcm_uframes_t position = bytes_to_frames(runtime,
@@ -783,8 +783,8 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw *hsw = pdata->hsw;
 	snd_pcm_uframes_t offset;
@@ -807,8 +807,8 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
 static int hsw_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw *hsw = pdata->hsw;
 	int dai;
@@ -840,8 +840,8 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
 static int hsw_pcm_close(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct hsw_priv_data *pdata =
-		snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(component);
 	struct hsw_pcm_data *pcm_data;
 	struct sst_hsw *hsw = pdata->hsw;
 	int ret, dai;
@@ -942,9 +942,9 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
 static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_pcm *pcm = rtd->pcm;
-	struct snd_soc_platform *platform = rtd->platform;
-	struct sst_pdata *pdata = dev_get_platdata(platform->dev);
-	struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct sst_pdata *pdata = dev_get_platdata(component->dev);
+	struct hsw_priv_data *priv_data = dev_get_drvdata(component->dev);
 	struct device *dev = pdata->dma_dev;
 	int ret = 0;
 
@@ -1052,23 +1052,23 @@ static const struct snd_soc_dapm_route graph[] = {
 	{"Analog Capture", NULL, "SSP0 CODEC IN"},
 };
 
-static int hsw_pcm_probe(struct snd_soc_platform *platform)
+static int hsw_pcm_probe(struct snd_soc_component *component)
 {
-	struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
-	struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+	struct hsw_priv_data *priv_data = snd_soc_component_get_drvdata(component);
+	struct sst_pdata *pdata = dev_get_platdata(component->dev);
 	struct device *dma_dev, *dev;
 	int i, ret = 0;
 
 	if (!pdata)
 		return -ENODEV;
 
-	dev = platform->dev;
+	dev = component->dev;
 	dma_dev = pdata->dma_dev;
 
 	priv_data->hsw = pdata->dsp;
-	priv_data->dev = platform->dev;
+	priv_data->dev = dev;
 	priv_data->pm_state = HSW_PM_STATE_D0;
-	priv_data->soc_card = platform->component.card;
+	priv_data->soc_card = component->card;
 
 	/* allocate DSP buffer page tables */
 	for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
@@ -1098,11 +1098,10 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 		goto err;
 
 	/* enable runtime PM with auto suspend */
-	pm_runtime_set_autosuspend_delay(platform->dev,
-		SST_RUNTIME_SUSPEND_DELAY);
-	pm_runtime_use_autosuspend(platform->dev);
-	pm_runtime_enable(platform->dev);
-	pm_runtime_idle(platform->dev);
+	pm_runtime_set_autosuspend_delay(dev, SST_RUNTIME_SUSPEND_DELAY);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
 
 	return 0;
 
@@ -1116,13 +1115,13 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 	return ret;
 }
 
-static int hsw_pcm_remove(struct snd_soc_platform *platform)
+static void hsw_pcm_remove(struct snd_soc_component *component)
 {
 	struct hsw_priv_data *priv_data =
-		snd_soc_platform_get_drvdata(platform);
+		snd_soc_component_get_drvdata(component);
 	int i;
 
-	pm_runtime_disable(platform->dev);
+	pm_runtime_disable(component->dev);
 	hsw_pcm_free_modules(priv_data);
 
 	for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
@@ -1131,24 +1130,19 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
 		if (hsw_dais[i].capture.channels_min)
 			snd_dma_free_pages(&priv_data->dmab[i][1]);
 	}
-
-	return 0;
 }
 
-static const struct snd_soc_platform_driver hsw_soc_platform = {
+static const struct snd_soc_component_driver hsw_dai_component = {
+	.name		= DRV_NAME,
 	.probe		= hsw_pcm_probe,
 	.remove		= hsw_pcm_remove,
 	.ops		= &hsw_pcm_ops,
 	.pcm_new	= hsw_pcm_new,
-};
-
-static const struct snd_soc_component_driver hsw_dai_component = {
-	.name = "haswell-dai",
-	.controls = hsw_volume_controls,
-	.num_controls = ARRAY_SIZE(hsw_volume_controls),
-	.dapm_widgets = widgets,
+	.controls	= hsw_volume_controls,
+	.num_controls	= ARRAY_SIZE(hsw_volume_controls),
+	.dapm_widgets	= widgets,
 	.num_dapm_widgets = ARRAY_SIZE(widgets),
-	.dapm_routes = graph,
+	.dapm_routes	= graph,
 	.num_dapm_routes = ARRAY_SIZE(graph),
 };
 
@@ -1172,19 +1166,13 @@ static int hsw_pcm_dev_probe(struct platform_device *pdev)
 	priv_data->hsw = sst_pdata->dsp;
 	platform_set_drvdata(pdev, priv_data);
 
-	ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
-	if (ret < 0)
-		goto err_plat;
-
-	ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
+	ret = devm_snd_soc_register_component(&pdev->dev, &hsw_dai_component,
 		hsw_dais, ARRAY_SIZE(hsw_dais));
 	if (ret < 0)
-		goto err_comp;
+		goto err_plat;
 
 	return 0;
 
-err_comp:
-	snd_soc_unregister_platform(&pdev->dev);
 err_plat:
 	sst_hsw_dsp_free(&pdev->dev, sst_pdata);
 	return 0;
@@ -1194,8 +1182,6 @@ static int hsw_pcm_dev_remove(struct platform_device *pdev)
 {
 	struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
 
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
 	sst_hsw_dsp_free(&pdev->dev, sst_pdata);
 
 	return 0;
diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c
index dc20d91f62e6..a016455a6ddb 100644
--- a/sound/soc/intel/skylake/skl-debug.c
+++ b/sound/soc/intel/skylake/skl-debug.c
@@ -231,7 +231,7 @@ struct skl_debug *skl_debugfs_init(struct skl *skl)
 
 	/* create the debugfs dir with platform component's debugfs as parent */
 	d->fs = debugfs_create_dir("dsp",
-				   skl->platform->component.debugfs_root);
+				   skl->component->debugfs_root);
 	if (IS_ERR(d->fs) || !d->fs) {
 		dev_err(&skl->pci->dev, "debugfs root creation failed\n");
 		return NULL;
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index e46828533826..36a521562cf7 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1313,23 +1313,23 @@ static int skl_populate_modules(struct skl *skl)
 	return ret;
 }
 
-static int skl_platform_soc_probe(struct snd_soc_platform *platform)
+static int skl_platform_soc_probe(struct snd_soc_component *component)
 {
-	struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev);
+	struct hdac_ext_bus *ebus = dev_get_drvdata(component->dev);
 	struct skl *skl = ebus_to_skl(ebus);
 	const struct skl_dsp_ops *ops;
 	int ret;
 
-	pm_runtime_get_sync(platform->dev);
+	pm_runtime_get_sync(component->dev);
 	if ((ebus_to_hbus(ebus))->ppcap) {
-		skl->platform = platform;
+		skl->component = component;
 
 		/* init debugfs */
 		skl->debugfs = skl_debugfs_init(skl);
 
-		ret = skl_tplg_init(platform, ebus);
+		ret = skl_tplg_init(component, ebus);
 		if (ret < 0) {
-			dev_err(platform->dev, "Failed to init topology!\n");
+			dev_err(component->dev, "Failed to init topology!\n");
 			return ret;
 		}
 
@@ -1339,17 +1339,17 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
 			return -EIO;
 
 		if (skl->skl_sst->is_first_boot == false) {
-			dev_err(platform->dev, "DSP reports first boot done!!!\n");
+			dev_err(component->dev, "DSP reports first boot done!!!\n");
 			return -EIO;
 		}
 
 		/* disable dynamic clock gating during fw and lib download */
-		skl->skl_sst->enable_miscbdcge(platform->dev, false);
+		skl->skl_sst->enable_miscbdcge(component->dev, false);
 
-		ret = ops->init_fw(platform->dev, skl->skl_sst);
-		skl->skl_sst->enable_miscbdcge(platform->dev, true);
+		ret = ops->init_fw(component->dev, skl->skl_sst);
+		skl->skl_sst->enable_miscbdcge(component->dev, true);
 		if (ret < 0) {
-			dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
+			dev_err(component->dev, "Failed to boot first fw: %d\n", ret);
 			return ret;
 		}
 		skl_populate_modules(skl);
@@ -1362,22 +1362,20 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
 					skl->cfg.astate_cfg);
 		}
 	}
-	pm_runtime_mark_last_busy(platform->dev);
-	pm_runtime_put_autosuspend(platform->dev);
+	pm_runtime_mark_last_busy(component->dev);
+	pm_runtime_put_autosuspend(component->dev);
 
 	return 0;
 }
-static const struct snd_soc_platform_driver skl_platform_drv  = {
+
+static const struct snd_soc_component_driver skl_component  = {
+	.name		= "pcm",
 	.probe		= skl_platform_soc_probe,
 	.ops		= &skl_platform_ops,
 	.pcm_new	= skl_pcm_new,
 	.pcm_free	= skl_pcm_free,
 };
 
-static const struct snd_soc_component_driver skl_component = {
-	.name           = "pcm",
-};
-
 int skl_platform_register(struct device *dev)
 {
 	int ret;
@@ -1389,12 +1387,6 @@ int skl_platform_register(struct device *dev)
 	INIT_LIST_HEAD(&skl->ppl_list);
 	INIT_LIST_HEAD(&skl->bind_list);
 
-	ret = snd_soc_register_platform(dev, &skl_platform_drv);
-	if (ret) {
-		dev_err(dev, "soc platform registration failed %d\n", ret);
-		return ret;
-	}
-
 	skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai),
 			    GFP_KERNEL);
 	if (!skl->dais) {
@@ -1416,18 +1408,12 @@ int skl_platform_register(struct device *dev)
 		num_dais += ARRAY_SIZE(skl_fe_dai);
 	}
 
-	ret = snd_soc_register_component(dev, &skl_component,
+	ret = devm_snd_soc_register_component(dev, &skl_component,
 					 skl->dais, num_dais);
-	if (ret) {
+	if (ret)
 		dev_err(dev, "soc component registration failed %d\n", ret);
-		goto err;
-	}
-
-	return 0;
 err:
-	snd_soc_unregister_platform(dev);
 	return ret;
-
 }
 
 int skl_platform_unregister(struct device *dev)
@@ -1443,8 +1429,6 @@ int skl_platform_unregister(struct device *dev)
 		}
 	}
 
-	snd_soc_unregister_component(dev);
-	snd_soc_unregister_platform(dev);
 	kfree(skl->dais);
 
 	return 0;
diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c
index 7fbddf5e3b00..cda1b5fa7436 100644
--- a/sound/soc/intel/skylake/skl-ssp-clk.c
+++ b/sound/soc/intel/skylake/skl-ssp-clk.c
@@ -247,8 +247,8 @@ static unsigned long skl_clk_recalc_rate(struct clk_hw *hw,
 }
 
 /* Not supported by clk driver. Implemented to satisfy clk fw */
-long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate,
-				unsigned long *parent_rate)
+static long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long *parent_rate)
 {
 	return rate;
 }
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 73af6e19ebbd..515e4b6d1950 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -2710,15 +2710,15 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
 	return 0;
 }
 
-static void skl_clear_pin_config(struct snd_soc_platform *platform,
+static void skl_clear_pin_config(struct snd_soc_component *component,
 				struct snd_soc_dapm_widget *w)
 {
 	int i;
 	struct skl_module_cfg *mconfig;
 	struct skl_pipe *pipe;
 
-	if (!strncmp(w->dapm->component->name, platform->component.name,
-					strlen(platform->component.name))) {
+	if (!strncmp(w->dapm->component->name, component->name,
+					strlen(component->name))) {
 		mconfig = w->priv;
 		pipe = mconfig->pipe;
 		for (i = 0; i < mconfig->module->max_input_pins; i++) {
@@ -2737,14 +2737,14 @@ static void skl_clear_pin_config(struct snd_soc_platform *platform,
 void skl_cleanup_resources(struct skl *skl)
 {
 	struct skl_sst *ctx = skl->skl_sst;
-	struct snd_soc_platform *soc_platform = skl->platform;
+	struct snd_soc_component *soc_component = skl->component;
 	struct snd_soc_dapm_widget *w;
 	struct snd_soc_card *card;
 
-	if (soc_platform == NULL)
+	if (soc_component == NULL)
 		return;
 
-	card = soc_platform->component.card;
+	card = soc_component->card;
 	if (!card || !card->instantiated)
 		return;
 
@@ -2753,7 +2753,7 @@ void skl_cleanup_resources(struct skl *skl)
 
 	list_for_each_entry(w, &card->widgets, list) {
 		if (is_skl_dsp_widget_type(w) && (w->priv != NULL))
-			skl_clear_pin_config(soc_platform, w);
+			skl_clear_pin_config(soc_component, w);
 	}
 
 	skl_clear_module_cnt(ctx->dsp);
@@ -3400,19 +3400,19 @@ static struct snd_soc_tplg_ops skl_tplg_ops  = {
  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
  * helps to get the SKL type widgets in that pipeline
  */
-static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform)
+static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
 {
 	struct snd_soc_dapm_widget *w;
 	struct skl_module_cfg *mcfg = NULL;
 	struct skl_pipe_module *p_module = NULL;
 	struct skl_pipe *pipe;
 
-	list_for_each_entry(w, &platform->component.card->widgets, list) {
+	list_for_each_entry(w, &component->card->widgets, list) {
 		if (is_skl_dsp_widget_type(w) && w->priv != NULL) {
 			mcfg = w->priv;
 			pipe = mcfg->pipe;
 
-			p_module = devm_kzalloc(platform->dev,
+			p_module = devm_kzalloc(component->dev,
 						sizeof(*p_module), GFP_KERNEL);
 			if (!p_module)
 				return -ENOMEM;
@@ -3455,7 +3455,7 @@ static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
 /*
  * SKL topology init routine
  */
-int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
+int skl_tplg_init(struct snd_soc_component *component, struct hdac_ext_bus *ebus)
 {
 	int ret;
 	const struct firmware *fw;
@@ -3479,7 +3479,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
 	 * The complete tplg for SKL is loaded as index 0, we don't use
 	 * any other index
 	 */
-	ret = snd_soc_tplg_component_load(&platform->component,
+	ret = snd_soc_tplg_component_load(component,
 					&skl_tplg_ops, fw, 0);
 	if (ret < 0) {
 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
@@ -3491,7 +3491,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
 	skl->resource.max_mem = SKL_FW_MAX_MEM;
 
 	skl->tplg = fw;
-	ret = skl_tplg_create_pipe_widget_list(platform);
+	ret = skl_tplg_create_pipe_widget_list(component);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index b6496513fe55..87c946835705 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -460,7 +460,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
 			u32 caps_size, u32 node_id);
 void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
 	struct skl_pipe_params *params, int stream);
-int skl_tplg_init(struct snd_soc_platform *platform,
+int skl_tplg_init(struct snd_soc_component *component,
 				struct hdac_ext_bus *ebus);
 struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
 		struct snd_soc_dai *dai, int stream);
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 32ce64c6b2dc..aa9edc84eefb 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -1017,6 +1017,11 @@ static struct snd_soc_acpi_codecs kbl_5663_5514_codecs = {
 	.codecs = {"10EC5663", "10EC5514"}
 };
 
+static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = {
+	.num_codecs = 1,
+	.codecs = {"MX98357A"}
+};
+
 static struct skl_machine_pdata cnl_pdata = {
 	.use_tplg_pcm = true,
 };
@@ -1105,6 +1110,14 @@ static struct snd_soc_acpi_mach sst_kbl_devdata[] = {
 		.drv_name = "kbl_rt5663",
 		.fw_filename = "intel/dsp_fw_kbl.bin",
 	},
+	{
+		.id = "DLGS7219",
+		.drv_name = "kbl_da7219_max98357a",
+		.fw_filename = "intel/dsp_fw_kbl.bin",
+		.machine_quirk = snd_soc_acpi_codec_list,
+		.quirk_data = &kbl_7219_98357_codecs,
+		.pdata = &skl_dmic_data
+	},
 
 	{}
 };
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 2d13f3fd988a..ca46ad1d0a08 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -74,7 +74,7 @@ struct skl {
 	struct platform_device *dmic_dev;
 	struct platform_device *i2s_dev;
 	struct platform_device *clk_dev;
-	struct snd_soc_platform *platform;
+	struct snd_soc_component *component;
 	struct snd_soc_dai_driver *dais;
 
 	struct nhlt_acpi_table *nhlt; /* nhlt ptr */
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index 505b0ff03c3b..c6a58520d377 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -318,7 +318,8 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
 	}
 }
 
-const struct snd_soc_platform_driver kirkwood_soc_platform = {
+const struct snd_soc_component_driver kirkwood_soc_component = {
+	.name		= DRV_NAME,
 	.ops		= &kirkwood_dma_ops,
 	.pcm_new	= kirkwood_dma_new,
 	.pcm_free	= kirkwood_dma_free_dma_buffers,
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 105a73cc5158..9a2777b72dcd 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -26,8 +26,6 @@
 
 #include "kirkwood.h"
 
-#define DRV_NAME	"mvebu-audio"
-
 #define KIRKWOOD_I2S_FORMATS \
 	(SNDRV_PCM_FMTBIT_S16_LE | \
 	 SNDRV_PCM_FMTBIT_S24_LE | \
@@ -524,10 +522,6 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
     },
 };
 
-static const struct snd_soc_component_driver kirkwood_i2s_component = {
-	.name		= DRV_NAME,
-};
-
 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 {
 	struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
@@ -601,24 +595,17 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
 	}
 
-	err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
+	err = devm_snd_soc_register_component(&pdev->dev, &kirkwood_soc_component,
 					 soc_dai, 2);
 	if (err) {
 		dev_err(&pdev->dev, "snd_soc_register_component failed\n");
 		goto err_component;
 	}
 
-	err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
-	if (err) {
-		dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
-		goto err_platform;
-	}
-
 	kirkwood_i2s_init(priv);
 
 	return 0;
- err_platform:
-	snd_soc_unregister_component(&pdev->dev);
+
  err_component:
 	if (!IS_ERR(priv->extclk))
 		clk_disable_unprepare(priv->extclk);
@@ -631,9 +618,6 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
 	struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
-
 	if (!IS_ERR(priv->extclk))
 		clk_disable_unprepare(priv->extclk);
 	clk_disable_unprepare(priv->clk);
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index 783cb1a4f30e..c13ee5f69446 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -12,6 +12,8 @@
 #ifndef _KIRKWOOD_AUDIO_H
 #define _KIRKWOOD_AUDIO_H
 
+#define DRV_NAME	"mvebu-audio"
+
 #define KIRKWOOD_RECORD_WIN			0
 #define KIRKWOOD_PLAYBACK_WIN			1
 #define KIRKWOOD_MAX_AUDIO_WIN			2
@@ -143,6 +145,6 @@ struct kirkwood_dma_data {
 	int burst;
 };
 
-extern const struct snd_soc_platform_driver kirkwood_soc_platform;
+extern const struct snd_soc_component_driver kirkwood_soc_component;
 
 #endif
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index ac231d33d8fe..c91e5f4cd902 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -18,6 +18,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
+#include "mtk-afe-platform-driver.h"
 #include "mtk-afe-fe-dai.h"
 #include "mtk-base-afe.h"
 
@@ -43,7 +44,8 @@ int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
 		       struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int memif_num = rtd->cpu_dai->id;
 	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
@@ -105,7 +107,8 @@ void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
 			 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int irq_id;
 
@@ -128,7 +131,8 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
 			 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int msb_at_bit33 = 0;
 	int ret, fs = 0;
@@ -192,7 +196,8 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
 	const struct mtk_base_irq_data *irq_data = irqs->irq_data;
@@ -255,7 +260,8 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
 		       struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd  = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int hd_audio = 0;
 
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 82d439c15f4e..53215b52e4f2 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -25,7 +25,8 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer
 			 (struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	const struct mtk_base_memif_data *memif_data = memif->data;
 	struct regmap *regmap = afe->regmap;
@@ -65,7 +66,8 @@ static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	size_t size;
 	struct snd_card *card = rtd->card->snd_card;
 	struct snd_pcm *pcm = rtd->pcm;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 
 	size = afe->mtk_afe_hardware->buffer_bytes_max;
 	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -77,7 +79,8 @@ static void mtk_afe_pcm_free(struct snd_pcm *pcm)
 	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-const struct snd_soc_platform_driver mtk_afe_pcm_platform = {
+const struct snd_soc_component_driver mtk_afe_pcm_platform = {
+	.name = AFE_PCM_NAME,
 	.ops = &mtk_afe_pcm_ops,
 	.pcm_new = mtk_afe_pcm_new,
 	.pcm_free = mtk_afe_pcm_free,
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
index a973fc9253b4..8dcdbed959ea 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.h
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -17,7 +17,8 @@
 #ifndef _MTK_AFE_PLATFORM_DRIVER_H_
 #define _MTK_AFE_PLATFORM_DRIVER_H_
 
-extern const struct snd_soc_platform_driver mtk_afe_pcm_platform;
+#define AFE_PCM_NAME "mtk-afe-pcm"
+extern const struct snd_soc_component_driver mtk_afe_pcm_platform;
 
 #endif
 
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index d68b53f7cefe..f7e0702d92f8 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -93,7 +93,8 @@ static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
 
 	if (i2s_num < 0)
@@ -108,7 +109,8 @@ static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream,
 					int dir_invert)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num];
 	const struct mt2701_i2s_data *i2s_data;
@@ -144,7 +146,8 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
 	struct mt2701_i2s_path *i2s_path;
@@ -176,7 +179,8 @@ static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream,
 					  int dir_invert)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num];
 	const struct mt2701_i2s_data *i2s_data;
@@ -247,7 +251,8 @@ static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream,
 {
 	int clk_domain;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id);
 	struct mt2701_i2s_path *i2s_path;
@@ -312,7 +317,8 @@ static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 	int ret;
 
@@ -329,7 +335,8 @@ static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	int stream_fs;
 	u32 val, msk;
 
@@ -372,7 +379,8 @@ static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
 
 	/* if the other direction stream is not occupied */
@@ -392,7 +400,8 @@ static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	int stream_dir = substream->stream;
 	int memif_num = rtd->cpu_dai->id;
 	struct mtk_base_afe_memif *memif_tmp;
@@ -414,7 +423,8 @@ static int mt2701_simple_fe_hw_params(struct snd_pcm_substream *substream,
 				      struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	int stream_dir = substream->stream;
 
 	/* single DL use PAIR_INTERLEAVE */
@@ -431,7 +441,8 @@ static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream,
 				 struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif_tmp;
 	const struct mtk_base_memif_data *memif_data;
 	int i;
@@ -458,7 +469,8 @@ static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	const struct mtk_base_memif_data *memif_data;
 	int i;
 
@@ -477,7 +489,8 @@ static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	int channels = params_channels(params);
 
 	regmap_update_bits(afe->regmap,
@@ -500,7 +513,8 @@ static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream,
 				 int cmd, struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif_tmp = &afe->memif[MT2701_MEMIF_DL1];
 
 	switch (cmd) {
@@ -1517,7 +1531,8 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 	}
 	pm_runtime_get_sync(dev);
 
-	ret = snd_soc_register_platform(dev, &mtk_afe_pcm_platform);
+	ret = devm_snd_soc_register_component(&pdev->dev, &mtk_afe_pcm_platform,
+					      NULL, 0);
 	if (ret) {
 		dev_warn(dev, "err_platform\n");
 		goto err_platform;
@@ -1526,13 +1541,11 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
 	ret = mt2701_afe_add_component(afe);
 	if (ret) {
 		dev_warn(dev, "err_dai_component\n");
-		goto err_dai_component;
+		goto err_platform;
 	}
 
 	return 0;
 
-err_dai_component:
-	snd_soc_unregister_platform(dev);
 err_platform:
 	pm_runtime_put_sync(dev);
 err_pm_disable:
@@ -1549,7 +1562,6 @@ static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev)
 		mt2701_afe_runtime_suspend(&pdev->dev);
 
 	snd_soc_unregister_component(&pdev->dev);
-	snd_soc_unregister_platform(&pdev->dev);
 
 	return 0;
 }
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index c7f7f8add5d9..65d1433a0944 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -304,7 +304,8 @@ static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 
 	if (dai->active)
 		return 0;
@@ -318,7 +319,8 @@ static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 
 	if (dai->active)
 		return;
@@ -334,7 +336,8 @@ static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 	int ret;
 
@@ -356,7 +359,8 @@ static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	if (dai->active)
@@ -371,7 +375,8 @@ static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
 				     struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	if (dai->active)
@@ -386,7 +391,8 @@ static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	unsigned int val;
@@ -449,7 +455,8 @@ static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
 				   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 
 	dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
 
@@ -498,7 +505,8 @@ static int mt8173_memif_fs(struct snd_pcm_substream *substream,
 			   unsigned int rate)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
 	int fs;
 
@@ -1172,31 +1180,29 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 	afe->runtime_resume = mt8173_afe_runtime_resume;
 	afe->runtime_suspend = mt8173_afe_runtime_suspend;
 
-	ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform);
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					 &mtk_afe_pcm_platform,
+					 NULL, 0);
 	if (ret)
 		goto err_pm_disable;
 
-	ret = snd_soc_register_component(&pdev->dev,
+	ret = devm_snd_soc_register_component(&pdev->dev,
 					 &mt8173_afe_pcm_dai_component,
 					 mt8173_afe_pcm_dais,
 					 ARRAY_SIZE(mt8173_afe_pcm_dais));
 	if (ret)
-		goto err_platform;
+		goto err_pm_disable;
 
-	ret = snd_soc_register_component(&pdev->dev,
+	ret = devm_snd_soc_register_component(&pdev->dev,
 					 &mt8173_afe_hdmi_dai_component,
 					 mt8173_afe_hdmi_dais,
 					 ARRAY_SIZE(mt8173_afe_hdmi_dais));
 	if (ret)
-		goto err_comp;
+		goto err_pm_disable;
 
 	dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n");
 	return 0;
 
-err_comp:
-	snd_soc_unregister_component(&pdev->dev);
-err_platform:
-	snd_soc_unregister_platform(&pdev->dev);
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 	return ret;
@@ -1207,8 +1213,6 @@ static int mt8173_afe_pcm_dev_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		mt8173_afe_runtime_suspend(&pdev->dev);
-	snd_soc_unregister_component(&pdev->dev);
-	snd_soc_unregister_platform(&pdev->dev);
 	return 0;
 }
 
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c
index e0c2b23ec711..b49b527a7cf9 100644
--- a/sound/soc/mediatek/mt8173/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c
@@ -75,7 +75,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
 {
 	int ret;
 	struct snd_soc_card *card = runtime->card;
-	struct snd_soc_codec *codec = runtime->codec;
+	struct snd_soc_component *component = runtime->codec_dai->component;
 
 	/* enable jack detection */
 	ret = snd_soc_card_jack_new(card, "Headphone", SND_JACK_HEADPHONE,
@@ -87,7 +87,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 	}
 
-	return max98090_mic_detect(codec, &mt8173_max98090_jack);
+	return max98090_mic_detect(component, &mt8173_max98090_jack);
 }
 
 /* Digital audio interface glue - connects codec <---> CPU */
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 5a9a5482976e..904f3ee6b0eb 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -82,10 +82,10 @@ static struct snd_soc_jack mt8173_rt5650_rt5514_jack;
 static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
-	struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
+	struct snd_soc_component *component = runtime->codec_dais[0]->component;
 	int ret;
 
-	rt5645_sel_asrc_clk_src(codec,
+	rt5645_sel_asrc_clk_src(component,
 				RT5645_DA_STEREO_FILTER |
 				RT5645_AD_STEREO_FILTER,
 				RT5645_CLK_SEL_I2S1_ASRC);
@@ -101,7 +101,7 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 	}
 
-	return rt5645_set_jack_detect(codec,
+	return rt5645_set_jack_detect(component,
 				      &mt8173_rt5650_rt5514_jack,
 				      &mt8173_rt5650_rt5514_jack,
 				      &mt8173_rt5650_rt5514_jack);
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index b7248085ca04..9c61b8c099c5 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -86,19 +86,19 @@ static struct snd_soc_jack mt8173_rt5650_rt5676_jack;
 static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
-	struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
-	struct snd_soc_codec *codec_sub = runtime->codec_dais[1]->codec;
+	struct snd_soc_component *component = runtime->codec_dais[0]->component;
+	struct snd_soc_component *component_sub = runtime->codec_dais[1]->component;
 	int ret;
 
-	rt5645_sel_asrc_clk_src(codec,
+	rt5645_sel_asrc_clk_src(component,
 				RT5645_DA_STEREO_FILTER |
 				RT5645_AD_STEREO_FILTER,
 				RT5645_CLK_SEL_I2S1_ASRC);
-	rt5677_sel_asrc_clk_src(codec_sub,
+	rt5677_sel_asrc_clk_src(component_sub,
 				RT5677_DA_STEREO_FILTER |
 				RT5677_AD_STEREO1_FILTER,
 				RT5677_CLK_SEL_I2S1_ASRC);
-	rt5677_sel_asrc_clk_src(codec_sub,
+	rt5677_sel_asrc_clk_src(component_sub,
 				RT5677_AD_STEREO2_FILTER |
 				RT5677_I2S2_SOURCE,
 				RT5677_CLK_SEL_I2S2_ASRC);
@@ -114,7 +114,7 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 	}
 
-	return rt5645_set_jack_detect(codec,
+	return rt5645_set_jack_detect(component,
 				      &mt8173_rt5650_rt5676_jack,
 				      &mt8173_rt5650_rt5676_jack,
 				      &mt8173_rt5650_rt5676_jack);
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 679fc8bea0a3..84aa09d3dd98 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -112,26 +112,26 @@ static struct snd_soc_jack mt8173_rt5650_jack;
 static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
 {
 	struct snd_soc_card *card = runtime->card;
-	struct snd_soc_codec *codec = runtime->codec_dais[0]->codec;
+	struct snd_soc_component *component = runtime->codec_dais[0]->component;
 	const char *codec_capture_dai = runtime->codec_dais[1]->name;
 	int ret;
 
-	rt5645_sel_asrc_clk_src(codec,
+	rt5645_sel_asrc_clk_src(component,
 				RT5645_DA_STEREO_FILTER,
 				RT5645_CLK_SEL_I2S1_ASRC);
 
 	if (!strcmp(codec_capture_dai, "rt5645-aif1")) {
-		rt5645_sel_asrc_clk_src(codec,
+		rt5645_sel_asrc_clk_src(component,
 					RT5645_AD_STEREO_FILTER,
 					RT5645_CLK_SEL_I2S1_ASRC);
 	} else if (!strcmp(codec_capture_dai, "rt5645-aif2")) {
-		rt5645_sel_asrc_clk_src(codec,
+		rt5645_sel_asrc_clk_src(component,
 					RT5645_AD_STEREO_FILTER,
 					RT5645_CLK_SEL_I2S2_ASRC);
 	} else {
 		dev_warn(card->dev,
 			 "Only one dai codec found in DTS, enabled rt5645 AD filter\n");
-		rt5645_sel_asrc_clk_src(codec,
+		rt5645_sel_asrc_clk_src(component,
 					RT5645_AD_STEREO_FILTER,
 					RT5645_CLK_SEL_I2S1_ASRC);
 	}
@@ -147,7 +147,7 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 	}
 
-	return rt5645_set_jack_detect(codec,
+	return rt5645_set_jack_detect(component,
 				      &mt8173_rt5650_jack,
 				      &mt8173_rt5650_jack,
 				      &mt8173_rt5650_jack);
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index bd6dfa218d59..ad8392a87df9 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -299,14 +299,15 @@ static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static const struct snd_soc_platform_driver nuc900_soc_platform = {
+static const struct snd_soc_component_driver nuc900_soc_component = {
 	.ops		= &nuc900_dma_ops,
 	.pcm_new	= nuc900_dma_new,
 };
 
 static int nuc900_soc_platform_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev, &nuc900_soc_component,
+					       NULL, 0);
 }
 
 static struct platform_driver nuc900_pcm_driver = {
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index cb72c1e57da0..77a30f0f0c96 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -93,7 +93,7 @@ static unsigned short ams_delta_audio_agc;
  * Used for passing a codec structure pointer
  * from the board initialization code to the tty line discipline.
  */
-static struct snd_soc_codec *cx20442_codec;
+static struct snd_soc_component *cx20442_codec;
 
 static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
@@ -105,7 +105,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
 	int pin, changed = 0;
 
 	/* Refuse any mode changes if we are not able to control the codec. */
-	if (!cx20442_codec->component.card->pop_time)
+	if (!cx20442_codec->card->pop_time)
 		return -EUNATCH;
 
 	if (ucontrol->value.enumerated.item[0] >= control->items)
@@ -300,15 +300,15 @@ static int cx81801_open(struct tty_struct *tty)
 /* Line discipline .close() */
 static void cx81801_close(struct tty_struct *tty)
 {
-	struct snd_soc_codec *codec = tty->disc_data;
-	struct snd_soc_dapm_context *dapm = &codec->component.card->dapm;
+	struct snd_soc_component *component = tty->disc_data;
+	struct snd_soc_dapm_context *dapm = &component->card->dapm;
 
 	del_timer_sync(&cx81801_timer);
 
 	/* Prevent the hook switch from further changing the DAPM pins */
 	INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
 
-	if (!codec)
+	if (!component)
 		return;
 
 	v253_ops.close(tty);
@@ -338,14 +338,14 @@ static int cx81801_hangup(struct tty_struct *tty)
 static void cx81801_receive(struct tty_struct *tty,
 				const unsigned char *cp, char *fp, int count)
 {
-	struct snd_soc_codec *codec = tty->disc_data;
+	struct snd_soc_component *component = tty->disc_data;
 	const unsigned char *c;
 	int apply, ret;
 
-	if (!codec)
+	if (!component)
 		return;
 
-	if (!codec->component.card->pop_time) {
+	if (!component->card->pop_time) {
 		/* First modem response, complete setup procedure */
 
 		/* Initialize timer used for config pulse generation */
@@ -358,7 +358,7 @@ static void cx81801_receive(struct tty_struct *tty,
 					ARRAY_SIZE(ams_delta_hook_switch_pins),
 					ams_delta_hook_switch_pins);
 		if (ret)
-			dev_warn(codec->dev,
+			dev_warn(component->dev,
 				"Failed to link hook switch to DAPM pins, "
 				"will continue with hook switch unlinked.\n");
 
@@ -467,7 +467,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 	/* Codec is ready, now add/activate board specific controls */
 
 	/* Store a pointer to the codec structure for tty ldisc use */
-	cx20442_codec = rtd->codec;
+	cx20442_codec = rtd->codec_dai->component;
 
 	/* Set up digital mute if not provided by the codec */
 	if (!codec_dai->driver->ops) {
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 614b18d2f631..15ccbf479c96 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -52,7 +52,7 @@ static int omap_abe_hw_params(struct snd_pcm_substream *substream,
 	int clk_id, freq;
 	int ret;
 
-	clk_id = twl6040_get_clk_id(rtd->codec);
+	clk_id = twl6040_get_clk_id(codec_dai->component);
 	if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
 		freq = priv->mclk_freq;
 	else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
@@ -166,7 +166,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	struct snd_soc_card *card = rtd->card;
 	struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
 	int hs_trim;
@@ -176,7 +176,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 	 * Configure McPDM offset cancellation based on the HSOTRIM value from
 	 * twl6040.
 	 */
-	hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
+	hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM);
 	omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
 					TWL6040_HSF_TRIM_RIGHT(hs_trim));
 
@@ -189,7 +189,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 		if (ret)
 			return ret;
 
-		twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
+		twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET);
 	}
 
 	return 0;
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index aca2c43d0f03..778cc8f75b6a 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -243,7 +243,7 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static const struct snd_soc_platform_driver omap_soc_platform = {
+static const struct snd_soc_component_driver omap_soc_component = {
 	.ops		= &omap_pcm_ops,
 	.pcm_new	= omap_pcm_new,
 	.pcm_free	= omap_pcm_free_dma_buffers,
@@ -252,7 +252,8 @@ static const struct snd_soc_platform_driver omap_soc_platform = {
 int omap_pcm_platform_register(struct device *dev)
 {
 	omap_pcm_limit_supported_formats();
-	return devm_snd_soc_register_platform(dev, &omap_soc_platform);
+	return devm_snd_soc_register_component(dev, &omap_soc_component,
+					       NULL, 0);
 }
 EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
 
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index c4c6fbedc723..47052fe3f5f4 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -58,20 +58,20 @@
 #define AC97_GPIO_PULL		0x58
 
 /* Use GPIO8 for rear speaker amplifier */
-static int rear_amp_power(struct snd_soc_codec *codec, int power)
+static int rear_amp_power(struct snd_soc_component *component, int power)
 {
 	unsigned short reg;
 
 	if (power) {
-		reg = snd_soc_read(codec, AC97_GPIO_CFG);
-		snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100);
-		reg = snd_soc_read(codec, AC97_GPIO_PULL);
-		snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15));
+		reg = snd_soc_component_read32(component, AC97_GPIO_CFG);
+		snd_soc_component_write(component, AC97_GPIO_CFG, reg | 0x0100);
+		reg = snd_soc_component_read32(component, AC97_GPIO_PULL);
+		snd_soc_component_write(component, AC97_GPIO_PULL, reg | (1<<15));
 	} else {
-		reg = snd_soc_read(codec, AC97_GPIO_CFG);
-		snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100);
-		reg = snd_soc_read(codec, AC97_GPIO_PULL);
-		snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15));
+		reg = snd_soc_component_read32(component, AC97_GPIO_CFG);
+		snd_soc_component_write(component, AC97_GPIO_CFG, reg & ~0x0100);
+		reg = snd_soc_component_read32(component, AC97_GPIO_PULL);
+		snd_soc_component_write(component, AC97_GPIO_PULL, reg & ~(1<<15));
 	}
 
 	return 0;
@@ -82,11 +82,11 @@ static int rear_amp_event(struct snd_soc_dapm_widget *widget,
 {
 	struct snd_soc_card *card = widget->dapm->card;
 	struct snd_soc_pcm_runtime *rtd;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 
 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
-	codec = rtd->codec;
-	return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
+	component = rtd->codec_dai->component;
+	return rear_amp_power(component, SND_SOC_DAPM_EVENT_ON(event));
 }
 
 /* mioa701 machine dapm widgets */
@@ -129,13 +129,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	/* Prepare GPIO8 for rear speaker amplifier */
-	snd_soc_update_bits(codec, AC97_GPIO_CFG, 0x100, 0x100);
+	snd_soc_component_update_bits(component, AC97_GPIO_CFG, 0x100, 0x100);
 
 	/* Prepare MIC input */
-	snd_soc_update_bits(codec, AC97_3D_CONTROL, 0xc000, 0xc000);
+	snd_soc_component_update_bits(component, AC97_3D_CONTROL, 0xc000, 0xc000);
 
 	return 0;
 }
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 624d9bd5dadd..d2d4652de32c 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -25,6 +25,8 @@
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
+#define DRV_NAME "mmp-pcm"
+
 struct mmp_dma_data {
 	int ssp_id;
 	struct resource *dma_res;
@@ -100,7 +102,8 @@ static bool filter(struct dma_chan *chan, void *param)
 static int mmp_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct platform_device *pdev = to_platform_device(component->dev);
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct mmp_dma_data dma_data;
 	struct resource *r;
@@ -211,7 +214,8 @@ static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static const struct snd_soc_platform_driver mmp_soc_platform = {
+static const struct snd_soc_component_driver mmp_soc_component = {
+	.name		= DRV_NAME,
 	.ops		= &mmp_pcm_ops,
 	.pcm_new	= mmp_pcm_new,
 	.pcm_free	= mmp_pcm_free_dma_buffers,
@@ -231,7 +235,8 @@ static int mmp_pcm_probe(struct platform_device *pdev)
 		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
 						pdata->period_max_capture;
 	}
-	return devm_snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev, &mmp_soc_component,
+					       NULL, 0);
 }
 
 static struct platform_driver mmp_pcm_driver = {
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index e64958d8bff0..8b6a70e94c01 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -84,7 +84,7 @@ static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return ret;
 }
 
-static const struct snd_soc_platform_driver pxa2xx_soc_platform = {
+static const struct snd_soc_component_driver pxa2xx_soc_platform = {
 	.ops		= &pxa2xx_pcm_ops,
 	.pcm_new	= pxa2xx_soc_pcm_new,
 	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
@@ -92,7 +92,8 @@ static const struct snd_soc_platform_driver pxa2xx_soc_platform = {
 
 static int pxa2xx_soc_platform_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev, &pxa2xx_soc_platform,
+					       NULL, 0);
 }
 
 #ifdef CONFIG_OF
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c
index 65c20f779177..5d6e61a4bb7e 100644
--- a/sound/soc/pxa/ttc-dkb.c
+++ b/sound/soc/pxa/ttc-dkb.c
@@ -75,7 +75,7 @@ static const struct snd_soc_dapm_route ttc_audio_map[] = {
 
 static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	/* Headset jack detection */
 	snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE |
@@ -86,9 +86,9 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
 			      ARRAY_SIZE(mic_jack_pins));
 
 	/* headphone, microphone detection & headset short detection */
-	pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+	pm860x_hs_jack_detect(component, &hs_jack, SND_JACK_HEADPHONE,
 			      SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
-	pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+	pm860x_mic_jack_detect(component, &hs_jack, SND_JACK_MICROPHONE);
 
 	return 0;
 }
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index caf71aab8196..31fe78aa207f 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -24,6 +24,8 @@
 #include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
+#define DRV_NAME "lpass-platform"
+
 struct lpass_pcm_data {
 	int dma_ch;
 	int i2s_port;
@@ -61,8 +63,8 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct lpass_variant *v = drvdata->variant;
 	int ret, dma_ch, dir = substream->stream;
 	struct lpass_pcm_data *data;
@@ -115,8 +117,8 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct lpass_variant *v = drvdata->variant;
 	struct lpass_pcm_data *data;
 
@@ -132,8 +134,8 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
@@ -225,8 +227,8 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
@@ -246,8 +248,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
@@ -298,8 +300,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		int cmd)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
@@ -372,8 +374,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-			snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
@@ -509,13 +511,14 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 {
 	struct snd_pcm *pcm = soc_runtime->pcm;
 	struct snd_pcm_substream *psubstream, *csubstream;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
 	int ret = -EINVAL;
 	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 
 	psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	if (psubstream) {
 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-					soc_runtime->platform->dev,
+					component->dev,
 					size, &psubstream->dma_buffer);
 		if (ret) {
 			dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
@@ -526,7 +529,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
 	if (csubstream) {
 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-					soc_runtime->platform->dev,
+					component->dev,
 					size, &csubstream->dma_buffer);
 		if (ret) {
 			dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
@@ -555,7 +558,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	}
 }
 
-static const struct snd_soc_platform_driver lpass_platform_driver = {
+static const struct snd_soc_component_driver lpass_component_driver = {
+	.name		= DRV_NAME,
 	.pcm_new	= lpass_platform_pcm_new,
 	.pcm_free	= lpass_platform_pcm_free,
 	.ops		= &lpass_platform_pcm_ops,
@@ -591,8 +595,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 	}
 
 
-	return devm_snd_soc_register_platform(&pdev->dev,
-			&lpass_platform_driver);
+	return devm_snd_soc_register_component(&pdev->dev,
+			&lpass_component_driver, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
 
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 214bfc78cf5c..9a10181a0811 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -176,7 +176,7 @@ static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
 
 static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
+	struct snd_soc_component *component = rtd->codec_dais[0]->component;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	int ret;
 
@@ -215,7 +215,7 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
 	snd_jack_set_key(
 		rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 
-	da7219_aad_jack_det(codec, &rockchip_sound_jack);
+	da7219_aad_jack_det(component, &rockchip_sound_jack);
 
 	return 0;
 }
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index 9e0c17805807..4db4fd56db35 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -29,16 +29,12 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include "rockchip_i2s.h"
+#include "../codecs/rt5645.h"
 
 #define DRV_NAME "rockchip-snd-rt5645"
 
 static struct snd_soc_jack headset_jack;
 
-/* Jack detect via rt5645 driver. */
-extern int rt5645_set_jack_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
-	struct snd_soc_jack *btn_jack);
-
 static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
 	SND_SOC_DAPM_HP("Headphones", NULL),
 	SND_SOC_DAPM_SPK("Speakers", NULL),
@@ -129,7 +125,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
 		return ret;
 	}
 
-	return rt5645_set_jack_detect(runtime->codec,
+	return rt5645_set_jack_detect(runtime->codec_dai->component,
 				     &headset_jack,
 				     &headset_jack,
 				     &headset_jack);
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 030949e1e434..c3b76035f69c 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -21,8 +21,6 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
 # S3C24XX Machine Support
 snd-soc-jive-wm8750-objs := jive_wm8750.o
 snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
-snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
-snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
 snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
 snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
 snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
@@ -32,7 +30,6 @@ snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
 snd-soc-smdk-wm8580-objs := smdk_wm8580.o
 snd-soc-smdk-wm8994-objs := smdk_wm8994.o
 snd-soc-snow-objs := snow.o
-snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
 snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h
index fe6914005494..964985ea2e80 100644
--- a/sound/soc/samsung/i2s-regs.h
+++ b/sound/soc/samsung/i2s-regs.h
@@ -65,11 +65,12 @@
 #define CON_RXDMA_ACTIVE	(1 << 1)
 #define CON_ACTIVE		(1 << 0)
 
-#define MOD_OPCLK_CDCLK_OUT	(0 << 30)
-#define MOD_OPCLK_CDCLK_IN	(1 << 30)
-#define MOD_OPCLK_BCLK_OUT	(2 << 30)
-#define MOD_OPCLK_PCLK		(3 << 30)
-#define MOD_OPCLK_MASK		(3 << 30)
+#define MOD_OPCLK_SHIFT		30
+#define MOD_OPCLK_CDCLK_OUT	(0 << MOD_OPCLK_SHIFT)
+#define MOD_OPCLK_CDCLK_IN	(1 << MOD_OPCLK_SHIFT)
+#define MOD_OPCLK_BCLK_OUT	(2 << MOD_OPCLK_SHIFT)
+#define MOD_OPCLK_PCLK		(3 << MOD_OPCLK_SHIFT)
+#define MOD_OPCLK_MASK		(3 << MOD_OPCLK_SHIFT)
 #define MOD_TXS_IDMA		(1 << 28) /* Sec_TXFIFO use I-DMA */
 
 #define MOD_BLCS_SHIFT		26
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 233f1c9a4b6c..b6407fbabdd1 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -489,7 +489,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
 	switch (clk_id) {
 	case SAMSUNG_I2S_OPCLK:
 		mask = MOD_OPCLK_MASK;
-		val = dir;
+		val = (dir << MOD_OPCLK_SHIFT) & MOD_OPCLK_MASK;
 		break;
 	case SAMSUNG_I2S_CDCLK:
 		mask = 1 << i2s_regs->cdclkcon_off;
@@ -656,8 +656,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
 		tmp |= mod_slave;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
-		/* Set default source clock in Master mode */
-		if (i2s->rclk_srcrate == 0)
+		/*
+		 * Set default source clock in Master mode, only when the
+		 * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any
+		 * clock configuration assigned in DT is not overwritten.
+		 */
+		if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL)
 			i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
 							0, SND_SOC_CLOCK_IN);
 		break;
@@ -881,6 +885,11 @@ static int config_setup(struct i2s_dai *i2s)
 		return 0;
 
 	if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
+		struct clk *rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC];
+
+		if (i2s->rclk_srcrate == 0 && rclksrc && !IS_ERR(rclksrc))
+			i2s->rclk_srcrate = clk_get_rate(rclksrc);
+
 		psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
 		writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
 		dev_dbg(&i2s->pdev->dev,
@@ -1184,11 +1193,13 @@ static void i2s_unregister_clock_provider(struct platform_device *pdev)
 
 static int i2s_register_clock_provider(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
-	struct i2s_dai *i2s = dev_get_drvdata(dev);
+	const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" };
 	const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" };
 	const char *p_names[2] = { NULL };
+	struct device *dev = &pdev->dev;
+	struct i2s_dai *i2s = dev_get_drvdata(dev);
 	const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs;
+	const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)];
 	struct clk *rclksrc;
 	int ret, i;
 
@@ -1205,30 +1216,38 @@ static int i2s_register_clock_provider(struct platform_device *pdev)
 		clk_put(rclksrc);
 	}
 
+	for (i = 0; i < ARRAY_SIZE(i2s_clk_desc); i++) {
+		i2s_clk_name[i] = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						dev_name(dev), i2s_clk_desc[i]);
+		if (!i2s_clk_name[i])
+			return -ENOMEM;
+	}
+
 	if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
 		/* Activate the prescaler */
 		u32 val = readl(i2s->addr + I2SPSR);
 		writel(val | PSR_PSREN, i2s->addr + I2SPSR);
 
 		i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev,
-				"i2s_rclksrc", p_names, ARRAY_SIZE(p_names),
+				i2s_clk_name[CLK_I2S_RCLK_SRC], p_names,
+				ARRAY_SIZE(p_names),
 				CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
 				i2s->addr + I2SMOD, reg_info->rclksrc_off,
 				1, 0, i2s->lock);
 
 		i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev,
-				"i2s_presc", "i2s_rclksrc",
+				i2s_clk_name[CLK_I2S_RCLK_PSR],
+				i2s_clk_name[CLK_I2S_RCLK_SRC],
 				CLK_SET_RATE_PARENT,
 				i2s->addr + I2SPSR, 8, 6, 0, i2s->lock);
 
-		p_names[0] = "i2s_presc";
+		p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR];
 		i2s->clk_data.clk_num = 2;
 	}
-	of_property_read_string_index(dev->of_node,
-				"clock-output-names", 0, &clk_name[0]);
 
-	i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, clk_name[0],
-				p_names[0], CLK_SET_RATE_PARENT,
+	i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev,
+				i2s_clk_name[CLK_I2S_CDCLK], p_names[0],
+				CLK_SET_RATE_PARENT,
 				i2s->addr + I2SMOD, reg_info->cdclkcon_off,
 				CLK_GATE_SET_TO_DISABLE, i2s->lock);
 
@@ -1385,9 +1404,14 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 
 	ret = i2s_register_clock_provider(pdev);
-	if (!ret)
-		return 0;
+	if (ret < 0)
+		goto err_disable_pm;
+
+	pri_dai->op_clk = clk_get_parent(pri_dai->clk_table[CLK_I2S_RCLK_SRC]);
+
+	return 0;
 
+err_disable_pm:
 	pm_runtime_disable(&pdev->dev);
 err_disable_clk:
 	clk_disable_unprepare(pri_dai->clk);
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
index 79781de2f247..a9832a9555cb 100644
--- a/sound/soc/samsung/i2s.h
+++ b/sound/soc/samsung/i2s.h
@@ -16,11 +16,16 @@
 #define SAMSUNG_I2S_DAI        "samsung-i2s"
 #define SAMSUNG_I2S_DAI_SEC    "samsung-i2s-sec"
 
-#define SAMSUNG_I2S_DIV_BCLK	1
+#define SAMSUNG_I2S_DIV_BCLK		1
 
-#define SAMSUNG_I2S_RCLKSRC_0	0
-#define SAMSUNG_I2S_RCLKSRC_1	1
+#define SAMSUNG_I2S_RCLKSRC_0		0
+#define SAMSUNG_I2S_RCLKSRC_1		1
 #define SAMSUNG_I2S_CDCLK		2
+/* Operation clock for IIS logic */
 #define SAMSUNG_I2S_OPCLK		3
+#define  SAMSUNG_I2S_OPCLK_CDCLK_OUT	0	/* CODEC clock out */
+#define  SAMSUNG_I2S_OPCLK_CDCLK_IN	1	/* CODEC clock in */
+#define  SAMSUNG_I2S_OPCLK_BCLK_OUT	2	/* Bit clock out */
+#define  SAMSUNG_I2S_OPCLK_PCLK		3	/* Audio bus clock */
 
 #endif /* __SND_SOC_SAMSUNG_I2S_H */
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index a635df61f928..b1f09b942410 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -399,7 +399,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
 }
 EXPORT_SYMBOL_GPL(idma_reg_addr_init);
 
-static const struct snd_soc_platform_driver asoc_idma_platform = {
+static const struct snd_soc_component_driver asoc_idma_platform = {
 	.ops = &idma_ops,
 	.pcm_new = idma_new,
 	.pcm_free = idma_free,
@@ -411,7 +411,8 @@ static int asoc_idma_platform_probe(struct platform_device *pdev)
 	if (idma_irq < 0)
 		return idma_irq;
 
-	return devm_snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
+	return devm_snd_soc_register_component(&pdev->dev, &asoc_idma_platform,
+					       NULL, 0);
 }
 
 static struct platform_driver asoc_idma_driver = {
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 7cb204e649ca..087f8d738dfb 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -258,13 +258,13 @@ static struct snd_soc_jack littlemill_headset;
 static int littlemill_late_probe(struct snd_soc_card *card)
 {
 	struct snd_soc_pcm_runtime *rtd;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct snd_soc_dai *aif1_dai;
 	struct snd_soc_dai *aif2_dai;
 	int ret;
 
 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
-	codec = rtd->codec;
+	component = rtd->codec_dai->component;
 	aif1_dai = rtd->codec_dai;
 
 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
@@ -290,10 +290,10 @@ static int littlemill_late_probe(struct snd_soc_card *card)
 		return ret;
 
 	/* This will check device compatibility itself */
-	wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL, NULL, NULL);
+	wm8958_mic_detect(component, &littlemill_headset, NULL, NULL, NULL, NULL);
 
 	/* As will this */
-	wm8994_mic_detect(codec, &littlemill_headset, 1);
+	wm8994_mic_detect(component, &littlemill_headset, 1);
 
 	return 0;
 }
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 0d0f58208b75..c9081f42f373 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -37,10 +37,10 @@ static struct snd_soc_jack_pin lowland_headset_pins[] = {
 
 static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	int ret;
 
-	ret = snd_soc_codec_set_sysclk(codec, WM5100_CLK_SYSCLK,
+	ret = snd_soc_component_set_sysclk(component, WM5100_CLK_SYSCLK,
 				       WM5100_CLKSRC_MCLK1, MCLK1_RATE,
 				       SND_SOC_CLOCK_IN);
 	if (ret < 0) {
@@ -49,7 +49,7 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
 	}
 
 	/* Clock OPCLK, used by the other audio components. */
-	ret = snd_soc_codec_set_sysclk(codec, WM5100_CLK_OPCLK, 0,
+	ret = snd_soc_component_set_sysclk(component, WM5100_CLK_OPCLK, 0,
 				       CLKOUT_RATE, 0);
 	if (ret < 0) {
 		pr_err("Failed to set OPCLK rate: %d\n", ret);
@@ -63,19 +63,19 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
-	wm5100_detect(codec, &lowland_headset);
+	wm5100_detect(component, &lowland_headset);
 
 	return 0;
 }
 
 static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 
 	snd_soc_dapm_nc_pin(&rtd->card->dapm, "LINEOUT");
 
 	/* At any time the WM9081 is active it will have this clock */
-	return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
+	return snd_soc_component_set_sysclk(component, WM9081_SYSCLK_MCLK, 0,
 					CLKOUT_RATE, 0);
 }
 
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 083ef5e21b17..4b4147d07804 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -124,14 +124,14 @@ static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
 	return 0;
 }
 
-static void speyside_set_polarity(struct snd_soc_codec *codec,
+static void speyside_set_polarity(struct snd_soc_component *component,
 				  int polarity)
 {
 	speyside_jack_polarity = !polarity;
 	gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
 	/* Re-run DAPM to make sure we're using the correct mic bias */
-	snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
+	snd_soc_dapm_sync(snd_soc_component_get_dapm(component));
 }
 
 static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
@@ -149,7 +149,7 @@ static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
 static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *dai = rtd->codec_dai;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = dai->component;
 	int ret;
 
 	ret = snd_soc_dai_set_sysclk(dai, WM8996_SYSCLK_MCLK2, 32768, 0);
@@ -168,7 +168,7 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret)
 		return ret;
 
-	wm8996_detect(codec, &speyside_headset, speyside_set_polarity);
+	wm8996_detect(component, &speyside_headset, speyside_set_polarity);
 
 	return 0;
 }
@@ -232,10 +232,8 @@ static struct snd_soc_dai_link speyside_dai[] = {
 
 static int speyside_wm9081_init(struct snd_soc_component *component)
 {
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-
 	/* At any time the WM9081 is active it will have this clock */
-	return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
+	return snd_soc_component_set_sysclk(component, WM9081_SYSCLK_MCLK, 0,
 					MCLK_AUDIO_RATE, 0);
 }
 
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index a55d18703fe7..43332c32d7e9 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -31,7 +31,7 @@
 #define TM2_DAI_AIF2	1
 
 struct tm2_machine_priv {
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	unsigned int sysclk_rate;
 	struct gpio_desc *gpio_mic_bias;
 };
@@ -39,33 +39,33 @@ struct tm2_machine_priv {
 static int tm2_start_sysclk(struct snd_soc_card *card)
 {
 	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_component *component = priv->component;
 	int ret;
 
-	ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK,
+	ret = snd_soc_component_set_pll(component, WM5110_FLL1_REFCLK,
 				    ARIZONA_FLL_SRC_MCLK1,
 				    MCLK_RATE,
 				    priv->sysclk_rate);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret);
+		dev_err(component->dev, "Failed to set FLL1 source: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_codec_set_pll(codec, WM5110_FLL1,
+	ret = snd_soc_component_set_pll(component, WM5110_FLL1,
 				    ARIZONA_FLL_SRC_MCLK1,
 				    MCLK_RATE,
 				    priv->sysclk_rate);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to start FLL1: %d\n", ret);
+		dev_err(component->dev, "Failed to start FLL1: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+	ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
 				       ARIZONA_CLK_SRC_FLL1,
 				       priv->sysclk_rate,
 				       SND_SOC_CLOCK_IN);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret);
+		dev_err(component->dev, "Failed to set SYSCLK source: %d\n", ret);
 		return ret;
 	}
 
@@ -75,19 +75,19 @@ static int tm2_start_sysclk(struct snd_soc_card *card)
 static int tm2_stop_sysclk(struct snd_soc_card *card)
 {
 	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
-	struct snd_soc_codec *codec = priv->codec;
+	struct snd_soc_component *component = priv->component;
 	int ret;
 
-	ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0);
+	ret = snd_soc_component_set_pll(component, WM5110_FLL1, 0, 0, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret);
+		dev_err(component->dev, "Failed to stop FLL1: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+	ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
 				       ARIZONA_CLK_SRC_FLL1, 0, 0);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret);
+		dev_err(component->dev, "Failed to stop SYSCLK: %d\n", ret);
 		return ret;
 	}
 
@@ -98,7 +98,7 @@ static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 
 	switch (params_rate(params)) {
@@ -123,7 +123,7 @@ static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
 		priv->sysclk_rate = 135475200U;
 		break;
 	default:
-		dev_err(codec->dev, "Not supported sample rate: %d\n",
+		dev_err(component->dev, "Not supported sample rate: %d\n",
 			params_rate(params));
 		return -EINVAL;
 	}
@@ -139,7 +139,7 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	unsigned int asyncclk_rate;
 	int ret;
 
@@ -155,35 +155,35 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
 		asyncclk_rate = 45158400U;
 		break;
 	default:
-		dev_err(codec->dev, "Not supported sample rate: %d\n",
+		dev_err(component->dev, "Not supported sample rate: %d\n",
 			params_rate(params));
 		return -EINVAL;
 	}
 
-	ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK,
+	ret = snd_soc_component_set_pll(component, WM5110_FLL2_REFCLK,
 				    ARIZONA_FLL_SRC_MCLK1,
 				    MCLK_RATE,
 				    asyncclk_rate);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret);
+		dev_err(component->dev, "Failed to set FLL2 source: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_codec_set_pll(codec, WM5110_FLL2,
+	ret = snd_soc_component_set_pll(component, WM5110_FLL2,
 				    ARIZONA_FLL_SRC_MCLK1,
 				    MCLK_RATE,
 				    asyncclk_rate);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to start FLL2: %d\n", ret);
+		dev_err(component->dev, "Failed to start FLL2: %d\n", ret);
 		return ret;
 	}
 
-	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
+	ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK,
 				       ARIZONA_CLK_SRC_FLL2,
 				       asyncclk_rate,
 				       SND_SOC_CLOCK_IN);
 	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret);
+		dev_err(component->dev, "Failed to set ASYNCCLK source: %d\n", ret);
 		return ret;
 	}
 
@@ -193,14 +193,14 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
 static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_component *component = rtd->codec_dai->component;
 	int ret;
 
 	/* disable FLL2 */
-	ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
+	ret = snd_soc_component_set_pll(component, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
 				    0, 0);
 	if (ret < 0)
-		dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret);
+		dev_err(component->dev, "Failed to stop FLL2: %d\n", ret);
 
 	return ret;
 }
@@ -210,6 +210,59 @@ static struct snd_soc_ops tm2_aif2_ops = {
 	.hw_free = tm2_aif2_hw_free,
 };
 
+static int tm2_hdmi_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int bfs;
+	int bitwidth, ret;
+
+	bitwidth = snd_pcm_format_width(params_format(params));
+	if (bitwidth < 0) {
+		dev_err(rtd->card->dev, "Invalid bit-width: %d\n", bitwidth);
+		return bitwidth;
+	}
+
+	switch (bitwidth) {
+	case 48:
+		bfs = 64;
+		break;
+	case 16:
+		bfs = 32;
+		break;
+	default:
+		dev_err(rtd->card->dev, "Unsupported bit-width: %d\n", bitwidth);
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 48000:
+	case 96000:
+	case 192000:
+		break;
+	default:
+		dev_err(rtd->card->dev, "Unsupported sample rate: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK,
+					0, SAMSUNG_I2S_OPCLK_PCLK);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops tm2_hdmi_ops = {
+	.hw_params = tm2_hdmi_hw_params,
+};
+
 static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
 				struct snd_kcontrol *kcontrol, int event)
 {
@@ -269,7 +322,7 @@ static int tm2_late_probe(struct snd_soc_card *card)
 
 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
 	aif1_dai = rtd->codec_dai;
-	priv->codec = rtd->codec;
+	priv->component = rtd->codec_dai->component;
 
 	ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
 	if (ret < 0) {
@@ -405,6 +458,12 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
 		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 				  SND_SOC_DAIFMT_CBM_CFM,
 		.ignore_suspend = 1,
+	}, {
+		.name		= "HDMI",
+		.stream_name	= "i2s1",
+		.ops		= &tm2_hdmi_ops,
+		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				  SND_SOC_DAIFMT_CBS_CFS,
 	}
 };
 
@@ -412,7 +471,6 @@ static struct snd_soc_card tm2_card = {
 	.owner			= THIS_MODULE,
 
 	.dai_link		= tm2_dai_links,
-	.num_links		= ARRAY_SIZE(tm2_dai_links),
 	.controls		= tm2_controls,
 	.num_controls		= ARRAY_SIZE(tm2_controls),
 	.dapm_widgets		= tm2_dapm_widgets,
@@ -426,11 +484,14 @@ static struct snd_soc_card tm2_card = {
 
 static int tm2_probe(struct platform_device *pdev)
 {
+	struct device_node *cpu_dai_node[2] = {};
+	struct device_node *codec_dai_node[2] = {};
+	const char *cells_name = NULL;
 	struct device *dev = &pdev->dev;
 	struct snd_soc_card *card = &tm2_card;
 	struct tm2_machine_priv *priv;
-	struct device_node *cpu_dai_node, *codec_dai_node;
-	int ret, i;
+	struct of_phandle_args args;
+	int num_codecs, ret, i;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -464,47 +525,92 @@ static int tm2_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0);
-	if (!cpu_dai_node) {
-		dev_err(dev, "i2s-controllers property invalid or missing\n");
-		ret = -EINVAL;
-		goto amp_node_put;
+	num_codecs = of_count_phandle_with_args(dev->of_node, "audio-codec",
+						 NULL);
+
+	/* Skip the HDMI link if not specified in DT */
+	if (num_codecs > 1) {
+		card->num_links = ARRAY_SIZE(tm2_dai_links);
+		cells_name = "#sound-dai-cells";
+	} else {
+		card->num_links = ARRAY_SIZE(tm2_dai_links) - 1;
 	}
 
-	codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0);
-	if (!codec_dai_node) {
-		dev_err(dev, "audio-codec property invalid or missing\n");
-		ret = -EINVAL;
-		goto cpu_dai_node_put;
+	for (i = 0; i < num_codecs; i++) {
+		struct of_phandle_args args;
+
+		ret = of_parse_phandle_with_args(dev->of_node, "i2s-controller",
+						 cells_name, i, &args);
+		if (!args.np) {
+			dev_err(dev, "i2s-controller property parse error: %d\n", i);
+			ret = -EINVAL;
+			goto dai_node_put;
+		}
+		cpu_dai_node[i] = args.np;
+
+		codec_dai_node[i] = of_parse_phandle(dev->of_node,
+						     "audio-codec", i);
+		if (!codec_dai_node[i]) {
+			dev_err(dev, "audio-codec property parse error\n");
+			ret = -EINVAL;
+			goto dai_node_put;
+		}
 	}
 
+	/* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */
 	for (i = 0; i < card->num_links; i++) {
+		unsigned int dai_index = 0; /* WM5110 */
+
 		card->dai_link[i].cpu_name = NULL;
 		card->dai_link[i].platform_name = NULL;
-		card->dai_link[i].codec_of_node = codec_dai_node;
-		card->dai_link[i].cpu_of_node = cpu_dai_node;
-		card->dai_link[i].platform_of_node = cpu_dai_node;
+
+		if (num_codecs > 1 && i == card->num_links - 1)
+			dai_index = 1; /* HDMI */
+
+		card->dai_link[i].codec_of_node = codec_dai_node[dai_index];
+		card->dai_link[i].cpu_of_node = cpu_dai_node[dai_index];
+		card->dai_link[i].platform_of_node = cpu_dai_node[dai_index];
+	}
+
+	if (num_codecs > 1) {
+		/* HDMI DAI link (I2S1) */
+		i = card->num_links - 1;
+
+		ret = of_parse_phandle_with_fixed_args(dev->of_node,
+						"audio-codec", 0, 1, &args);
+		if (ret) {
+			dev_err(dev, "audio-codec property parse error\n");
+			goto dai_node_put;
+		}
+
+		ret = snd_soc_get_dai_name(&args, &card->dai_link[i].codec_dai_name);
+		if (ret) {
+			dev_err(dev, "Unable to get codec_dai_name\n");
+			goto dai_node_put;
+		}
 	}
 
 	ret = devm_snd_soc_register_component(dev, &tm2_component,
 				tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
 	if (ret < 0) {
 		dev_err(dev, "Failed to register component: %d\n", ret);
-		goto codec_dai_node_put;
+		goto dai_node_put;
 	}
 
 	ret = devm_snd_soc_register_card(dev, card);
 	if (ret < 0) {
 		dev_err(dev, "Failed to register card: %d\n", ret);
-		goto codec_dai_node_put;
+		goto dai_node_put;
+	}
+
+dai_node_put:
+	for (i = 0; i < num_codecs; i++) {
+		of_node_put(codec_dai_node[i]);
+		of_node_put(cpu_dai_node[i]);
 	}
 
-codec_dai_node_put:
-	of_node_put(codec_dai_node);
-cpu_dai_node_put:
-	of_node_put(cpu_dai_node);
-amp_node_put:
 	of_node_put(card->aux_dev[0].codec_of_node);
+
 	return ret;
 }
 
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 3310eda7cf53..998727cb4c31 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -179,12 +179,12 @@ static struct snd_soc_jack_pin tobermory_headset_pins[] = {
 static int tobermory_late_probe(struct snd_soc_card *card)
 {
 	struct snd_soc_pcm_runtime *rtd;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 	struct snd_soc_dai *codec_dai;
 	int ret;
 
 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
-	codec = rtd->codec;
+	component = rtd->codec_dai->component;
 	codec_dai = rtd->codec_dai;
 
 	ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
@@ -199,7 +199,7 @@ static int tobermory_late_probe(struct snd_soc_card *card)
 	if (ret)
 		return ret;
 
-	wm8962_mic_detect(codec, &tobermory_headset);
+	wm8962_mic_detect(component, &tobermory_headset);
 
 	return 0;
 }
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 1e7d417b53ef..2dc3b762fdd9 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -320,14 +320,15 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
-static const struct snd_soc_platform_driver sh7760_soc_platform = {
+static const struct snd_soc_component_driver sh7760_soc_component = {
 	.ops		= &camelot_pcm_ops,
 	.pcm_new	= camelot_pcm_new,
 };
 
 static int sh7760_soc_platform_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component,
+					       NULL, 0);
 }
 
 static struct platform_driver sh7760_pcm_driver = {
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index c3aaf4788557..3bae06dd121f 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1764,7 +1764,7 @@ static const struct snd_pcm_ops fsi_pcm_ops = {
 };
 
 /*
- *		snd_soc_platform
+ *		snd_soc_component
  */
 
 #define PREALLOC_BUFFER		(32 * 1024)
@@ -1818,13 +1818,10 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
 	},
 };
 
-static const struct snd_soc_platform_driver fsi_soc_platform = {
-	.ops		= &fsi_pcm_ops,
-	.pcm_new	= fsi_pcm_new,
-};
-
 static const struct snd_soc_component_driver fsi_soc_component = {
 	.name		= "fsi",
+	.ops		= &fsi_pcm_ops,
+	.pcm_new	= fsi_pcm_new,
 };
 
 /*
@@ -2007,23 +2004,15 @@ static int fsi_probe(struct platform_device *pdev)
 		goto exit_fsib;
 	}
 
-	ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "cannot snd soc register\n");
-		goto exit_fsib;
-	}
-
-	ret = snd_soc_register_component(&pdev->dev, &fsi_soc_component,
+	ret = devm_snd_soc_register_component(&pdev->dev, &fsi_soc_component,
 				    fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
 	if (ret < 0) {
 		dev_err(&pdev->dev, "cannot snd component register\n");
-		goto exit_snd_soc;
+		goto exit_fsib;
 	}
 
 	return ret;
 
-exit_snd_soc:
-	snd_soc_unregister_platform(&pdev->dev);
 exit_fsib:
 	pm_runtime_disable(&pdev->dev);
 	fsi_stream_remove(&master->fsib);
@@ -2041,9 +2030,6 @@ static int fsi_remove(struct platform_device *pdev)
 
 	pm_runtime_disable(&pdev->dev);
 
-	snd_soc_unregister_component(&pdev->dev);
-	snd_soc_unregister_platform(&pdev->dev);
-
 	fsi_stream_remove(&master->fsia);
 	fsi_stream_remove(&master->fsib);
 
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 64d5ecb86528..b53e9151538e 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -93,6 +93,15 @@
  *  [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
  *
  */
+
+/*
+ * you can enable below define if you don't need
+ * DAI status debug message when debugging
+ * see rsnd_dbg_dai_call()
+ *
+ * #define RSND_DEBUG_NO_DAI_CALL 1
+ */
+
 #include <linux/pm_runtime.h>
 #include "rsnd.h"
 
@@ -468,7 +477,7 @@ static int rsnd_status_update(u32 *status,
 						__rsnd_mod_shift_##fn,	\
 						__rsnd_mod_add_##fn,	\
 						__rsnd_mod_call_##fn);	\
-		dev_dbg(dev, "%s[%d]\t0x%08x %s\n",			\
+		rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n",		\
 			rsnd_mod_name(mod), rsnd_mod_id(mod), *status,	\
 			(func_call && (mod)->ops->fn) ? #fn : "");	\
 		if (func_call && (mod)->ops->fn)			\
@@ -1337,7 +1346,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
 }
 
 /*
- *		snd_soc_platform
+ *		snd_soc_component
  */
 
 #define PREALLOC_BUFFER		(32 * 1024)
@@ -1364,12 +1373,9 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 		PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
-static const struct snd_soc_platform_driver rsnd_soc_platform = {
+static const struct snd_soc_component_driver rsnd_soc_component = {
 	.ops		= &rsnd_pcm_ops,
 	.pcm_new	= rsnd_pcm_new,
-};
-
-static const struct snd_soc_component_driver rsnd_soc_component = {
 	.name		= "rsnd",
 };
 
@@ -1478,17 +1484,11 @@ static int rsnd_probe(struct platform_device *pdev)
 	/*
 	 *	asoc register
 	 */
-	ret = snd_soc_register_platform(dev, &rsnd_soc_platform);
-	if (ret < 0) {
-		dev_err(dev, "cannot snd soc register\n");
-		return ret;
-	}
-
-	ret = snd_soc_register_component(dev, &rsnd_soc_component,
+	ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
 					 priv->daidrv, rsnd_rdai_nr(priv));
 	if (ret < 0) {
 		dev_err(dev, "cannot snd dai register\n");
-		goto exit_snd_soc;
+		goto exit_snd_probe;
 	}
 
 	pm_runtime_enable(dev);
@@ -1496,8 +1496,6 @@ static int rsnd_probe(struct platform_device *pdev)
 	dev_info(dev, "probed\n");
 	return ret;
 
-exit_snd_soc:
-	snd_soc_unregister_platform(dev);
 exit_snd_probe:
 	for_each_rsnd_dai(rdai, priv, i) {
 		rsnd_dai_call(remove, &rdai->playback, priv);
@@ -1535,9 +1533,6 @@ static int rsnd_remove(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(remove_func); i++)
 		remove_func[i](priv);
 
-	snd_soc_unregister_component(&pdev->dev);
-	snd_soc_unregister_platform(&pdev->dev);
-
 	return ret;
 }
 
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index ad6523595b0a..172c8d612890 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -788,4 +788,24 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
 #define rsnd_mod_confirm_dvc(mdvc)
 #endif
 
+/*
+ * If you don't need interrupt status debug message,
+ * define RSND_DEBUG_NO_IRQ_STATUS as 1 on top of src.c/ssi.c
+ *
+ * #define RSND_DEBUG_NO_IRQ_STATUS 1
+ */
+#define rsnd_dbg_irq_status(dev, param...)		\
+	if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS))	\
+		dev_dbg(dev, param)
+
+/*
+ * If you don't need rsnd_dai_call debug message,
+ * define RSND_DEBUG_NO_DAI_CALL as 1 on top of core.c
+ *
+ * #define RSND_DEBUG_NO_DAI_CALL 1
+ */
+#define rsnd_dbg_dai_call(dev, param...)		\
+	if (!IS_BUILTIN(RSND_DEBUG_NO_DAI_CALL))	\
+		dev_dbg(dev, param)
+
 #endif
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 510b68a483b4..a727e71587b6 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -8,6 +8,15 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+/*
+ * you can enable below define if you don't need
+ * SSI interrupt status debug message when debugging
+ * see rsnd_dbg_irq_status()
+ *
+ * #define RSND_DEBUG_NO_IRQ_STATUS 1
+ */
+
 #include "rsnd.h"
 
 #define SRC_NAME "src"
@@ -325,7 +334,10 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)
 
 static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
 {
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
 	u32 val0, val1;
+	u32 status0, status1;
 	bool ret = false;
 
 	val0 = val1 = OUF_SRC(rsnd_mod_id(mod));
@@ -338,9 +350,15 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
 	if (rsnd_src_sync_is_enabled(mod))
 		val0 = val0 & 0xffff;
 
-	if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
-	    (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1))
+	status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
+	status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
+	if ((status0 & val0) || (status1 & val1)) {
+		rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x, 0x%08x\n",
+			rsnd_mod_name(mod), rsnd_mod_id(mod),
+			status0, status1);
+
 		ret = true;
+	}
 
 	return ret;
 }
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 97a9db892a8f..333b802681ad 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -11,6 +11,15 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+/*
+ * you can enable below define if you don't need
+ * SSI interrupt status debug message when debugging
+ * see rsnd_dbg_irq_status()
+ *
+ * #define RSND_DEBUG_NO_IRQ_STATUS 1
+ */
+
 #include <sound/simple_card_utils.h>
 #include <linux/delay.h>
 #include "rsnd.h"
@@ -603,6 +612,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 				 struct rsnd_dai_stream *io)
 {
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
 	int is_dma = rsnd_ssi_is_dma_mode(mod);
 	u32 status;
 	bool elapsed = false;
@@ -621,8 +631,12 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
 		elapsed = rsnd_ssi_pio_interrupt(mod, io);
 
 	/* DMA only */
-	if (is_dma && (status & (UIRQ | OIRQ)))
+	if (is_dma && (status & (UIRQ | OIRQ))) {
+		rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x\n",
+			rsnd_mod_name(mod), rsnd_mod_id(mod), status);
+
 		stop = true;
+	}
 
 	rsnd_ssi_status_clear(mod);
 rsnd_ssi_interrupt_out:
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
index 83c3430ad797..6088d627c0e4 100644
--- a/sound/soc/sh/siu.h
+++ b/sound/soc/sh/siu.h
@@ -183,7 +183,7 @@ static inline u32 siu_read32(u32 __iomem *addr)
 #define SIU_BRGBSEL	(0x108 / sizeof(u32))
 #define SIU_BRRB	(0x10c / sizeof(u32))
 
-extern struct snd_soc_platform_driver siu_platform;
+extern struct snd_soc_component_driver siu_component;
 extern struct siu_info *siu_i2s_data;
 
 int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index 160502947da2..ee2211635e92 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -727,10 +727,6 @@ static struct snd_soc_dai_driver siu_i2s_dai = {
 	.ops = &siu_dai_ops,
 };
 
-static const struct snd_soc_component_driver siu_i2s_component = {
-	.name		= "siu-i2s",
-};
-
 static int siu_probe(struct platform_device *pdev)
 {
 	const struct firmware *fw_entry;
@@ -786,15 +782,11 @@ static int siu_probe(struct platform_device *pdev)
 	dev_set_drvdata(&pdev->dev, info);
 
 	/* register using ARRAY version so we can keep dai name */
-	ret = devm_snd_soc_register_component(&pdev->dev, &siu_i2s_component,
+	ret = devm_snd_soc_register_component(&pdev->dev, &siu_component,
 					      &siu_i2s_dai, 1);
 	if (ret < 0)
 		return ret;
 
-	ret = devm_snd_soc_register_platform(&pdev->dev, &siu_platform);
-	if (ret < 0)
-		return ret;
-
 	pm_runtime_enable(&pdev->dev);
 
 	return 0;
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 3118cb0ee3f2..172909570ed5 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -35,6 +35,7 @@
 
 #include "siu.h"
 
+#define DRV_NAME "siu-i2s"
 #define GET_MAX_PERIODS(buf_bytes, period_bytes) \
 				((buf_bytes) / (period_bytes))
 #define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
@@ -340,7 +341,8 @@ static int siu_pcm_open(struct snd_pcm_substream *ss)
 {
 	/* Playback / Capture */
 	struct snd_soc_pcm_runtime *rtd = ss->private_data;
-	struct siu_platform *pdata = rtd->platform->dev->platform_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct siu_platform *pdata = component->dev->platform_data;
 	struct siu_info *info = siu_i2s_data;
 	struct siu_port *port_info = siu_port_info(ss);
 	struct siu_stream *siu_stream;
@@ -604,9 +606,10 @@ static const struct snd_pcm_ops siu_pcm_ops = {
 	.pointer	= siu_pcm_pointer_dma,
 };
 
-struct snd_soc_platform_driver siu_platform = {
+struct snd_soc_component_driver siu_component = {
+	.name		= DRV_NAME,
 	.ops			= &siu_pcm_ops,
 	.pcm_new	= siu_pcm_new,
 	.pcm_free	= siu_pcm_free,
 };
-EXPORT_SYMBOL_GPL(siu_platform);
+EXPORT_SYMBOL_GPL(siu_component);
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index 36dae41f65fc..3f424f214bca 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -44,7 +44,7 @@ struct snd_ac97_gpio_priv {
 	struct gpio_chip gpio_chip;
 #endif
 	unsigned int gpios_set;
-	struct snd_soc_codec *codec;
+	struct snd_soc_component *component;
 };
 
 static struct snd_ac97_bus soc_ac97_bus = {
@@ -57,11 +57,11 @@ static void soc_ac97_device_release(struct device *dev)
 }
 
 #ifdef CONFIG_GPIOLIB
-static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip)
+static inline struct snd_soc_component *gpio_to_component(struct gpio_chip *chip)
 {
 	struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip);
 
-	return gpio_priv->codec;
+	return gpio_priv->component;
 }
 
 static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -75,20 +75,22 @@ static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset)
 static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip,
 					  unsigned offset)
 {
-	struct snd_soc_codec *codec = gpio_to_codec(chip);
+	struct snd_soc_component *component = gpio_to_component(chip);
 
-	dev_dbg(codec->dev, "set gpio %d to output\n", offset);
-	return snd_soc_update_bits(codec, AC97_GPIO_CFG,
+	dev_dbg(component->dev, "set gpio %d to output\n", offset);
+	return snd_soc_component_update_bits(component, AC97_GPIO_CFG,
 				   1 << offset, 1 << offset);
 }
 
 static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct snd_soc_codec *codec = gpio_to_codec(chip);
+	struct snd_soc_component *component = gpio_to_component(chip);
 	int ret;
 
-	ret = snd_soc_read(codec, AC97_GPIO_STATUS);
-	dev_dbg(codec->dev, "get gpio %d : %d\n", offset,
+	if (snd_soc_component_read(component, AC97_GPIO_STATUS, &ret) < 0)
+		ret = -1;
+
+	dev_dbg(component->dev, "get gpio %d : %d\n", offset,
 		ret < 0 ? ret : ret & (1 << offset));
 
 	return ret < 0 ? ret : !!(ret & (1 << offset));
@@ -98,22 +100,24 @@ static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset,
 				  int value)
 {
 	struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip);
-	struct snd_soc_codec *codec = gpio_to_codec(chip);
+	struct snd_soc_component *component = gpio_to_component(chip);
 
 	gpio_priv->gpios_set &= ~(1 << offset);
 	gpio_priv->gpios_set |= (!!value) << offset;
-	snd_soc_write(codec, AC97_GPIO_STATUS, gpio_priv->gpios_set);
-	dev_dbg(codec->dev, "set gpio %d to %d\n", offset, !!value);
+	snd_soc_component_write(component, AC97_GPIO_STATUS,
+				gpio_priv->gpios_set);
+	dev_dbg(component->dev, "set gpio %d to %d\n", offset, !!value);
 }
 
 static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	struct snd_soc_codec *codec = gpio_to_codec(chip);
+	struct snd_soc_component *component = gpio_to_component(chip);
 
-	dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+	dev_dbg(component->dev, "set gpio %d to output\n", offset);
 	snd_soc_ac97_gpio_set(chip, offset, value);
-	return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0);
+	return snd_soc_component_update_bits(component, AC97_GPIO_CFG,
+					     1 << offset, 0);
 }
 
 static const struct gpio_chip snd_soc_ac97_gpio_chip = {
@@ -128,24 +132,24 @@ static const struct gpio_chip snd_soc_ac97_gpio_chip = {
 };
 
 static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
-				  struct snd_soc_codec *codec)
+				  struct snd_soc_component *component)
 {
 	struct snd_ac97_gpio_priv *gpio_priv;
 	int ret;
 
-	gpio_priv = devm_kzalloc(codec->dev, sizeof(*gpio_priv), GFP_KERNEL);
+	gpio_priv = devm_kzalloc(component->dev, sizeof(*gpio_priv), GFP_KERNEL);
 	if (!gpio_priv)
 		return -ENOMEM;
 	ac97->gpio_priv = gpio_priv;
-	gpio_priv->codec = codec;
+	gpio_priv->component = component;
 	gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip;
 	gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS;
-	gpio_priv->gpio_chip.parent = codec->dev;
+	gpio_priv->gpio_chip.parent = component->dev;
 	gpio_priv->gpio_chip.base = -1;
 
 	ret = gpiochip_add_data(&gpio_priv->gpio_chip, gpio_priv);
 	if (ret != 0)
-		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+		dev_err(component->dev, "Failed to add GPIOs: %d\n", ret);
 	return ret;
 }
 
@@ -155,7 +159,7 @@ static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
 }
 #else
 static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
-				  struct snd_soc_codec *codec)
+				  struct snd_soc_component *component)
 {
 	return 0;
 }
@@ -166,8 +170,8 @@ static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
 #endif
 
 /**
- * snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device
- * @codec: The CODEC for which to create the AC'97 device
+ * snd_soc_alloc_ac97_component() - Allocate new a AC'97 device
+ * @component: The COMPONENT for which to create the AC'97 device
  *
  * Allocated a new snd_ac97 device and intializes it, but does not yet register
  * it. The caller is responsible to either call device_add(&ac97->dev) to
@@ -175,7 +179,7 @@ static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
  *
  * Returns: A snd_ac97 device or a PTR_ERR in case of an error.
  */
-struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec)
+struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component)
 {
 	struct snd_ac97 *ac97;
 
@@ -187,26 +191,26 @@ struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec)
 	ac97->num = 0;
 
 	ac97->dev.bus = &ac97_bus_type;
-	ac97->dev.parent = codec->component.card->dev;
+	ac97->dev.parent = component->card->dev;
 	ac97->dev.release = soc_ac97_device_release;
 
 	dev_set_name(&ac97->dev, "%d-%d:%s",
-		     codec->component.card->snd_card->number, 0,
-		     codec->component.name);
+		     component->card->snd_card->number, 0,
+		     component->name);
 
 	device_initialize(&ac97->dev);
 
 	return ac97;
 }
-EXPORT_SYMBOL(snd_soc_alloc_ac97_codec);
+EXPORT_SYMBOL(snd_soc_alloc_ac97_component);
 
 /**
- * snd_soc_new_ac97_codec - initailise AC97 device
- * @codec: audio codec
+ * snd_soc_new_ac97_component - initailise AC97 device
+ * @component: audio component
  * @id: The expected device ID
  * @id_mask: Mask that is applied to the device ID before comparing with @id
  *
- * Initialises AC97 codec resources for use by ad-hoc devices only.
+ * Initialises AC97 component resources for use by ad-hoc devices only.
  *
  * If @id is not 0 this function will reset the device, then read the ID from
  * the device and check if it matches the expected ID. If it doesn't match an
@@ -214,20 +218,20 @@ EXPORT_SYMBOL(snd_soc_alloc_ac97_codec);
  *
  * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success.
  */
-struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
 	unsigned int id, unsigned int id_mask)
 {
 	struct snd_ac97 *ac97;
 	int ret;
 
-	ac97 = snd_soc_alloc_ac97_codec(codec);
+	ac97 = snd_soc_alloc_ac97_component(component);
 	if (IS_ERR(ac97))
 		return ac97;
 
 	if (id) {
 		ret = snd_ac97_reset(ac97, false, id, id_mask);
 		if (ret < 0) {
-			dev_err(codec->dev, "Failed to reset AC97 device: %d\n",
+			dev_err(component->dev, "Failed to reset AC97 device: %d\n",
 				ret);
 			goto err_put_device;
 		}
@@ -237,7 +241,7 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 	if (ret)
 		goto err_put_device;
 
-	ret = snd_soc_ac97_init_gpio(ac97, codec);
+	ret = snd_soc_ac97_init_gpio(ac97, component);
 	if (ret)
 		goto err_put_device;
 
@@ -247,22 +251,22 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 	put_device(&ac97->dev);
 	return ERR_PTR(ret);
 }
-EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
+EXPORT_SYMBOL_GPL(snd_soc_new_ac97_component);
 
 /**
- * snd_soc_free_ac97_codec - free AC97 codec device
+ * snd_soc_free_ac97_component - free AC97 component device
  * @ac97: snd_ac97 device to be freed
  *
- * Frees AC97 codec device resources.
+ * Frees AC97 component device resources.
  */
-void snd_soc_free_ac97_codec(struct snd_ac97 *ac97)
+void snd_soc_free_ac97_component(struct snd_ac97 *ac97)
 {
 	snd_soc_ac97_free_gpio(ac97);
 	device_del(&ac97->dev);
 	ac97->bus = NULL;
 	put_device(&ac97->dev);
 }
-EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
+EXPORT_SYMBOL_GPL(snd_soc_free_ac97_component);
 
 static struct snd_ac97_reset_cfg snd_ac97_rst_cfg;
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 96c44f6576c9..39876737c336 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -349,7 +349,7 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component)
 			"ASoC: Failed to create codec register debugfs file\n");
 }
 
-static int codec_list_seq_show(struct seq_file *m, void *v)
+static int codec_list_show(struct seq_file *m, void *v)
 {
 	struct snd_soc_codec *codec;
 
@@ -362,20 +362,9 @@ static int codec_list_seq_show(struct seq_file *m, void *v)
 
 	return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(codec_list);
 
-static int codec_list_seq_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, codec_list_seq_show, NULL);
-}
-
-static const struct file_operations codec_list_fops = {
-	.open = codec_list_seq_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int dai_list_seq_show(struct seq_file *m, void *v)
+static int dai_list_show(struct seq_file *m, void *v)
 {
 	struct snd_soc_component *component;
 	struct snd_soc_dai *dai;
@@ -390,20 +379,9 @@ static int dai_list_seq_show(struct seq_file *m, void *v)
 
 	return 0;
 }
+DEFINE_SHOW_ATTRIBUTE(dai_list);
 
-static int dai_list_seq_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, dai_list_seq_show, NULL);
-}
-
-static const struct file_operations dai_list_fops = {
-	.open = dai_list_seq_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int platform_list_seq_show(struct seq_file *m, void *v)
+static int platform_list_show(struct seq_file *m, void *v)
 {
 	struct snd_soc_platform *platform;
 
@@ -416,18 +394,7 @@ static int platform_list_seq_show(struct seq_file *m, void *v)
 
 	return 0;
 }
-
-static int platform_list_seq_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, platform_list_seq_show, NULL);
-}
-
-static const struct file_operations platform_list_fops = {
-	.open = platform_list_seq_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(platform_list);
 
 static void soc_init_card_debugfs(struct snd_soc_card *card)
 {
@@ -1100,8 +1067,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 	cpu_dai_component.dai_name = dai_link->cpu_dai_name;
 	rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
 	if (!rtd->cpu_dai) {
-		dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
-			dai_link->cpu_dai_name);
+		dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
+			 dai_link->cpu_dai_name);
 		goto _err_defer;
 	}
 	snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
@@ -1162,11 +1129,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 
 		rtd->platform = platform;
 	}
-	if (!rtd->platform) {
-		dev_err(card->dev, "ASoC: platform %s not registered\n",
-			dai_link->platform_name);
-		goto _err_defer;
-	}
 
 	soc_add_pcm_runtime(card, rtd);
 	return 0;
@@ -1624,22 +1586,21 @@ static int soc_probe_link_components(struct snd_soc_card *card,
 
 static int soc_probe_dai(struct snd_soc_dai *dai, int order)
 {
-	int ret;
+	if (dai->probed ||
+	    dai->driver->probe_order != order)
+		return 0;
 
-	if (!dai->probed && dai->driver->probe_order == order) {
-		if (dai->driver->probe) {
-			ret = dai->driver->probe(dai);
-			if (ret < 0) {
-				dev_err(dai->dev,
-					"ASoC: failed to probe DAI %s: %d\n",
-					dai->name, ret);
-				return ret;
-			}
+	if (dai->driver->probe) {
+		int ret = dai->driver->probe(dai);
+		if (ret < 0) {
+			dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n",
+				dai->name, ret);
+			return ret;
 		}
-
-		dai->probed = 1;
 	}
 
+	dai->probed = 1;
+
 	return 0;
 }
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 92894d9cac19..2f34590bcb72 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3165,7 +3165,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 	unsigned int invert = mc->invert;
 	unsigned int val, rval = 0;
 	int connect, rconnect = -1, change, reg_change = 0;
-	struct snd_soc_dapm_update update = { NULL };
+	struct snd_soc_dapm_update update = {};
 	int ret = 0;
 
 	val = (ucontrol->value.integer.value[0] & mask);
@@ -3292,7 +3292,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 	unsigned int *item = ucontrol->value.enumerated.item;
 	unsigned int val, change, reg_change = 0;
 	unsigned int mask;
-	struct snd_soc_dapm_update update = { NULL };
+	struct snd_soc_dapm_update update = {};
 	int ret = 0;
 
 	if (item[0] >= e->items)
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index d53786498b61..c07d5c79ca91 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -33,13 +33,13 @@
 struct dmaengine_pcm {
 	struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
 	const struct snd_dmaengine_pcm_config *config;
-	struct snd_soc_platform platform;
+	struct snd_soc_component component;
 	unsigned int flags;
 };
 
-static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
+static struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p)
 {
-	return container_of(p, struct dmaengine_pcm, platform);
+	return container_of(p, struct dmaengine_pcm, component);
 }
 
 static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
@@ -88,7 +88,9 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+	struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
 	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
 	int (*prepare_slave_config)(struct snd_pcm_substream *substream,
 			struct snd_pcm_hw_params *params,
@@ -119,7 +121,9 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
 static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+	struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
 	struct device *dma_dev = dmaengine_dma_dev(pcm, substream);
 	struct dma_chan *chan = pcm->chan[substream->stream];
 	struct snd_dmaengine_dai_dma_data *dma_data;
@@ -206,7 +210,9 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
 static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+	struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
 	struct dma_chan *chan = pcm->chan[substream->stream];
 	int ret;
 
@@ -221,7 +227,9 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
 	struct snd_soc_pcm_runtime *rtd,
 	struct snd_pcm_substream *substream)
 {
-	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+	struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
 	struct snd_dmaengine_dai_dma_data *dma_data;
 	dma_filter_fn fn = NULL;
 
@@ -260,9 +268,11 @@ static bool dmaengine_pcm_can_report_residue(struct device *dev,
 
 static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
-	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+	struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
 	const struct snd_dmaengine_pcm_config *config = pcm->config;
-	struct device *dev = rtd->platform->dev;
+	struct device *dev = component->dev;
 	struct snd_dmaengine_dai_dma_data *dma_data;
 	struct snd_pcm_substream *substream;
 	size_t prealloc_buffer_size;
@@ -296,7 +306,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
 		}
 
 		if (!pcm->chan[i]) {
-			dev_err(rtd->platform->dev,
+			dev_err(component->dev,
 				"Missing dma channel for stream: %d\n", i);
 			return -EINVAL;
 		}
@@ -320,7 +330,9 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
 	struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+	struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
 
 	if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
 		return snd_dmaengine_pcm_pointer_no_residue(substream);
@@ -338,10 +350,9 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = {
 	.pointer	= dmaengine_pcm_pointer,
 };
 
-static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
-	.component_driver = {
-		.probe_order = SND_SOC_COMP_ORDER_LATE,
-	},
+static const struct snd_soc_component_driver dmaengine_pcm_component = {
+	.name		= SND_DMAENGINE_PCM_DRV_NAME,
+	.probe_order	= SND_SOC_COMP_ORDER_LATE,
 	.ops		= &dmaengine_pcm_ops,
 	.pcm_new	= dmaengine_pcm_new,
 };
@@ -438,8 +449,8 @@ int snd_dmaengine_pcm_register(struct device *dev,
 	if (ret)
 		goto err_free_dma;
 
-	ret = snd_soc_add_platform(dev, &pcm->platform,
-		&dmaengine_pcm_platform);
+	ret = snd_soc_add_component(dev, &pcm->component,
+				    &dmaengine_pcm_component, NULL, 0);
 	if (ret)
 		goto err_free_dma;
 
@@ -461,16 +472,16 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
  */
 void snd_dmaengine_pcm_unregister(struct device *dev)
 {
-	struct snd_soc_platform *platform;
+	struct snd_soc_component *component;
 	struct dmaengine_pcm *pcm;
 
-	platform = snd_soc_lookup_platform(dev);
-	if (!platform)
+	component = snd_soc_lookup_component(dev, SND_DMAENGINE_PCM_DRV_NAME);
+	if (!component)
 		return;
 
-	pcm = soc_platform_to_pcm(platform);
+	pcm = soc_component_to_pcm(component);
 
-	snd_soc_remove_platform(platform);
+	snd_soc_unregister_component(dev);
 	dmaengine_pcm_release_chan(pcm);
 	kfree(pcm);
 }
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index bcd3da2739e2..2d9e98bd1530 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -284,11 +284,16 @@ static const struct snd_pcm_ops dummy_dma_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 };
 
-static const struct snd_soc_platform_driver dummy_platform = {
+static const struct snd_soc_component_driver dummy_platform = {
 	.ops = &dummy_dma_ops,
 };
 
-static const struct snd_soc_codec_driver dummy_codec;
+static const struct snd_soc_component_driver dummy_codec = {
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
 
 #define STUB_RATES	SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
@@ -338,33 +343,22 @@ static int snd_soc_dummy_probe(struct platform_device *pdev)
 {
 	int ret;
 
-	ret = snd_soc_register_codec(&pdev->dev, &dummy_codec, &dummy_dai, 1);
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &dummy_codec, &dummy_dai, 1);
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_register_platform(&pdev->dev, &dummy_platform);
-	if (ret < 0) {
-		snd_soc_unregister_codec(&pdev->dev);
-		return ret;
-	}
+	ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform,
+					      NULL, 0);
 
 	return ret;
 }
 
-static int snd_soc_dummy_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_platform(&pdev->dev);
-	snd_soc_unregister_codec(&pdev->dev);
-
-	return 0;
-}
-
 static struct platform_driver soc_dummy_driver = {
 	.driver = {
 		.name = "snd-soc-dummy",
 	},
 	.probe = snd_soc_dummy_probe,
-	.remove = snd_soc_dummy_remove,
 };
 
 static struct platform_device *soc_dummy_dev;
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 7306e3eca9e1..db73fef3e500 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -281,7 +281,7 @@ static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm)
 	}
 }
 
-static struct snd_soc_platform_driver stm32_adfsdm_soc_platform = {
+static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
 	.ops		= &stm32_adfsdm_pcm_ops,
 	.pcm_new	= stm32_adfsdm_pcm_new,
 	.pcm_free	= stm32_adfsdm_pcm_free,
@@ -322,8 +322,9 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
 	if (IS_ERR(priv->iio_cb))
 		return PTR_ERR(priv->iio_cb);
 
-	ret = devm_snd_soc_register_platform(&pdev->dev,
-					     &stm32_adfsdm_soc_platform);
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &stm32_adfsdm_soc_platform,
+					      NULL, 0);
 	if (ret < 0)
 		dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
 			__func__);
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index b9bdefcd3e10..373df4f24be1 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -819,7 +819,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = {
 
 static struct snd_soc_dai_driver stm32_spdifrx_dai[] = {
 	{
-		.name = "spdifrx-capture-cpu-dai",
 		.probe = stm32_spdifrx_dai_probe,
 		.capture = {
 			.stream_name = "CPU-Capture",
@@ -858,8 +857,8 @@ static const struct of_device_id stm32_spdifrx_ids[] = {
 	{}
 };
 
-static int stm_spdifrx_parse_of(struct platform_device *pdev,
-				struct stm32_spdifrx_data *spdifrx)
+static int stm32_spdifrx_parse_of(struct platform_device *pdev,
+				  struct stm32_spdifrx_data *spdifrx)
 {
 	struct device_node *np = pdev->dev.of_node;
 	const struct of_device_id *of_id;
@@ -914,7 +913,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, spdifrx);
 
-	ret = stm_spdifrx_parse_of(pdev, spdifrx);
+	ret = stm32_spdifrx_parse_of(pdev, spdifrx);
 	if (ret)
 		return ret;
 
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 886281673972..9a3cb7704810 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -792,15 +792,17 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
 	{ "Mic1", NULL, "VMIC" },
 };
 
-static const struct snd_soc_codec_driver sun4i_codec_codec = {
-	.component_driver = {
-		.controls		= sun4i_codec_controls,
-		.num_controls		= ARRAY_SIZE(sun4i_codec_controls),
-		.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
-		.dapm_routes		= sun4i_codec_codec_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
-	},
+static const struct snd_soc_component_driver sun4i_codec_codec = {
+	.controls		= sun4i_codec_controls,
+	.num_controls		= ARRAY_SIZE(sun4i_codec_controls),
+	.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
+	.dapm_routes		= sun4i_codec_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /*** sun6i Codec ***/
@@ -1098,15 +1100,17 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
 	{ "Right ADC", NULL, "Right ADC Mixer" },
 };
 
-static const struct snd_soc_codec_driver sun6i_codec_codec = {
-	.component_driver = {
-		.controls		= sun6i_codec_codec_widgets,
-		.num_controls		= ARRAY_SIZE(sun6i_codec_codec_widgets),
-		.dapm_widgets		= sun6i_codec_codec_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
-		.dapm_routes		= sun6i_codec_codec_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
-	},
+static const struct snd_soc_component_driver sun6i_codec_codec = {
+	.controls		= sun6i_codec_codec_widgets,
+	.num_controls		= ARRAY_SIZE(sun6i_codec_codec_widgets),
+	.dapm_widgets		= sun6i_codec_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
+	.dapm_routes		= sun6i_codec_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 /* sun8i A23 codec */
@@ -1126,13 +1130,15 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
 
 };
 
-static const struct snd_soc_codec_driver sun8i_a23_codec_codec = {
-	.component_driver = {
-		.controls		= sun8i_a23_codec_codec_controls,
-		.num_controls		= ARRAY_SIZE(sun8i_a23_codec_codec_controls),
-		.dapm_widgets		= sun8i_a23_codec_codec_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
-	},
+static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
+	.controls		= sun8i_a23_codec_codec_controls,
+	.num_controls		= ARRAY_SIZE(sun8i_a23_codec_codec_controls),
+	.dapm_widgets		= sun8i_a23_codec_codec_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct snd_soc_component_driver sun4i_codec_component = {
@@ -1450,7 +1456,7 @@ static const struct regmap_config sun8i_v3s_codec_regmap_config = {
 
 struct sun4i_codec_quirks {
 	const struct regmap_config *regmap_config;
-	const struct snd_soc_codec_driver *codec;
+	const struct snd_soc_component_driver *codec;
 	struct snd_soc_card * (*create_card)(struct device *dev);
 	struct reg_field reg_adc_fifoc;	/* used for regmap_field */
 	unsigned int reg_dac_txdata;	/* TX FIFO offset for DMA config */
@@ -1657,7 +1663,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 	scodec->capture_dma_data.maxburst = 8;
 	scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
-	ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
+	ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
 				     &sun4i_codec_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register our codec\n");
@@ -1669,20 +1675,20 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 					      &dummy_cpu_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register our DAI\n");
-		goto err_unregister_codec;
+		goto err_assert_reset;
 	}
 
 	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
-		goto err_unregister_codec;
+		goto err_assert_reset;
 	}
 
 	card = quirks->create_card(&pdev->dev);
 	if (IS_ERR(card)) {
 		ret = PTR_ERR(card);
 		dev_err(&pdev->dev, "Failed to create our card\n");
-		goto err_unregister_codec;
+		goto err_assert_reset;
 	}
 
 	snd_soc_card_set_drvdata(card, scodec);
@@ -1690,13 +1696,11 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 	ret = snd_soc_register_card(card);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register our card\n");
-		goto err_unregister_codec;
+		goto err_assert_reset;
 	}
 
 	return 0;
 
-err_unregister_codec:
-	snd_soc_unregister_codec(&pdev->dev);
 err_assert_reset:
 	if (scodec->rst)
 		reset_control_assert(scodec->rst);
@@ -1711,7 +1715,6 @@ static int sun4i_codec_remove(struct platform_device *pdev)
 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
 
 	snd_soc_unregister_card(card);
-	snd_soc_unregister_codec(&pdev->dev);
 	if (scodec->rst)
 		reset_control_assert(scodec->rst);
 	clk_disable_unprepare(scodec->clk_apb);
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7a15df924316..fb37dd927e33 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -184,7 +184,7 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
 
 static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-	struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
+	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
 	u32 value;
 
 	/* clock masters */
@@ -304,7 +304,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
+	struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
 	int sample_rate;
 	u8 bclk_div;
 
@@ -500,13 +500,15 @@ static struct snd_soc_dai_driver sun8i_codec_dai = {
 	.ops = &sun8i_codec_dai_ops,
 };
 
-static const struct snd_soc_codec_driver sun8i_soc_codec = {
-	.component_driver = {
-		.dapm_widgets		= sun8i_codec_dapm_widgets,
-		.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_dapm_widgets),
-		.dapm_routes		= sun8i_codec_dapm_routes,
-		.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_dapm_routes),
-	},
+static const struct snd_soc_component_driver sun8i_soc_component = {
+	.dapm_widgets		= sun8i_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_dapm_widgets),
+	.dapm_routes		= sun8i_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_config sun8i_codec_regmap_config = {
@@ -566,7 +568,7 @@ static int sun8i_codec_probe(struct platform_device *pdev)
 			goto err_pm_disable;
 	}
 
-	ret = snd_soc_register_codec(&pdev->dev, &sun8i_soc_codec,
+	ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
 				     &sun8i_codec_dai, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register codec\n");
@@ -594,7 +596,6 @@ static int sun8i_codec_remove(struct platform_device *pdev)
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		sun8i_codec_runtime_suspend(&pdev->dev);
 
-	snd_soc_unregister_codec(&pdev->dev);
 	clk_disable_unprepare(scodec->clk_module);
 	clk_disable_unprepare(scodec->clk_bus);
 
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 18bdae59a4df..69bc9461974b 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -170,7 +170,7 @@ static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
 static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 	struct snd_soc_card *card = rtd->card;
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
 
@@ -189,7 +189,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 			      &tegra_wm8903_mic_jack,
 			      tegra_wm8903_mic_jack_pins,
 			      ARRAY_SIZE(tegra_wm8903_mic_jack_pins));
-	wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
+	wm8903_mic_detect(component, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
 				0);
 
 	snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS");
@@ -202,9 +202,9 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
 	struct snd_soc_pcm_runtime *rtd =
 		snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_component *component = codec_dai->component;
 
-	wm8903_mic_detect(codec, NULL, 0, 0);
+	wm8903_mic_detect(component, NULL, 0, 0);
 
 	return 0;
 }
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index a2bb68fea5a3..8d31fe628e2f 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -23,6 +23,8 @@
 #include <sound/soc.h>
 #include "txx9aclc.h"
 
+#define DRV_NAME "txx9aclc"
+
 static struct txx9aclc_soc_device {
 	struct txx9aclc_dmadata dmadata[2];
 } txx9aclc_soc_device;
@@ -53,6 +55,7 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 	struct txx9aclc_dmadata *dmadata = runtime->private_data;
 	int ret;
 
@@ -60,13 +63,13 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		return ret;
 
-	dev_dbg(rtd->platform->dev,
+	dev_dbg(component->dev,
 		"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
 		"runtime->min_align %ld\n",
 		(unsigned long)runtime->dma_area,
 		(unsigned long)runtime->dma_addr, runtime->dma_bytes,
 		runtime->min_align);
-	dev_dbg(rtd->platform->dev,
+	dev_dbg(component->dev,
 		"periods %d period_bytes %d stream %d\n",
 		params_periods(params), params_period_bytes(params),
 		substream->stream);
@@ -287,7 +290,8 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	struct snd_card *card = rtd->card->snd_card;
 	struct snd_soc_dai *dai = rtd->cpu_dai;
 	struct snd_pcm *pcm = rtd->pcm;
-	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct platform_device *pdev = to_platform_device(component->dev);
 	struct txx9aclc_soc_device *dev;
 	struct resource *r;
 	int i;
@@ -371,15 +375,15 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
 	return 0;
 }
 
-static int txx9aclc_pcm_probe(struct snd_soc_platform *platform)
+static int txx9aclc_pcm_probe(struct snd_soc_component *component)
 {
-	snd_soc_platform_set_drvdata(platform, &txx9aclc_soc_device);
+	snd_soc_component_set_drvdata(component, &txx9aclc_soc_device);
 	return 0;
 }
 
-static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
+static void txx9aclc_pcm_remove(struct snd_soc_component *component)
 {
-	struct txx9aclc_soc_device *dev = snd_soc_platform_get_drvdata(platform);
+	struct txx9aclc_soc_device *dev = snd_soc_component_get_drvdata(component);
 	struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
 	void __iomem *base = drvdata->base;
 	int i;
@@ -400,10 +404,10 @@ static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
 		}
 		dev->dmadata[i].dma_chan = NULL;
 	}
-	return 0;
 }
 
-static const struct snd_soc_platform_driver txx9aclc_soc_platform = {
+static const struct snd_soc_component_driver txx9aclc_soc_component = {
+	.name		= DRV_NAME,
 	.probe		= txx9aclc_pcm_probe,
 	.remove		= txx9aclc_pcm_remove,
 	.ops		= &txx9aclc_pcm_ops,
@@ -412,8 +416,8 @@ static const struct snd_soc_platform_driver txx9aclc_soc_platform = {
 
 static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
 {
-	return devm_snd_soc_register_platform(&pdev->dev,
-					      &txx9aclc_soc_platform);
+	return devm_snd_soc_register_component(&pdev->dev,
+					&txx9aclc_soc_component, NULL, 0);
 }
 
 static struct platform_driver txx9aclc_pcm_driver = {
diff --git a/sound/soc/uniphier/Kconfig b/sound/soc/uniphier/Kconfig
index 02886a457eaf..5da545b9bf2a 100644
--- a/sound/soc/uniphier/Kconfig
+++ b/sound/soc/uniphier/Kconfig
@@ -8,6 +8,28 @@ config SND_SOC_UNIPHIER
 	  audio interfaces to support below.
 	  If unsure select "N".
 
+config SND_SOC_UNIPHIER_AIO
+	tristate "UniPhier AIO DAI Driver"
+	select REGMAP_MMIO
+	select SND_SOC_COMPRESS
+	depends on SND_SOC_UNIPHIER
+	help
+	  This adds ASoC driver support for Socionext UniPhier
+	  'AIO' Audio Input/Output subsystem.
+	  Select Y if you use such device.
+	  If unsure select "N".
+
+config SND_SOC_UNIPHIER_LD11
+	tristate "UniPhier LD11/LD20 Device Driver"
+	depends on SND_SOC_UNIPHIER
+	select SND_SOC_UNIPHIER_AIO
+	select SND_SOC_UNIPHIER_AIO_DMA
+	help
+	  This adds ASoC driver for Socionext UniPhier LD11/LD20
+	  input and output that can be used with other codecs.
+	  Select Y if you use such device.
+	  If unsure select "N".
+
 config SND_SOC_UNIPHIER_EVEA_CODEC
 	tristate "UniPhier SoC internal audio codec"
 	depends on SND_SOC_UNIPHIER
diff --git a/sound/soc/uniphier/Makefile b/sound/soc/uniphier/Makefile
index 3be00d72f5e5..587a89700950 100644
--- a/sound/soc/uniphier/Makefile
+++ b/sound/soc/uniphier/Makefile
@@ -1,3 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
+snd-soc-uniphier-aio-cpu-objs := aio-core.o aio-dma.o aio-cpu.o aio-compress.o
+snd-soc-uniphier-aio-ld11-objs := aio-ld11.o
+
+obj-$(CONFIG_SND_SOC_UNIPHIER_AIO) += snd-soc-uniphier-aio-cpu.o
+obj-$(CONFIG_SND_SOC_UNIPHIER_LD11) += snd-soc-uniphier-aio-ld11.o
+
 snd-soc-uniphier-evea-objs := evea.o
 obj-$(CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC) += snd-soc-uniphier-evea.o
diff --git a/sound/soc/uniphier/aio-compress.c b/sound/soc/uniphier/aio-compress.c
new file mode 100644
index 000000000000..4751c8bdabec
--- /dev/null
+++ b/sound/soc/uniphier/aio-compress.c
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier AIO Compress Audio driver.
+//
+// Copyright (c) 2017-2018 Socionext Inc.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include <linux/bitfield.h>
+#include <linux/circ_buf.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "aio.h"
+
+static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream);
+static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream);
+
+static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_compr *compr = rtd->compr;
+	struct device *dev = compr->card->dev;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
+	size_t size = AUD_RING_SIZE;
+	int dma_dir = DMA_FROM_DEVICE, ret;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
+	if (ret)
+		return ret;
+
+	sub->compr_area = kzalloc(size, GFP_KERNEL);
+	if (!sub->compr_area)
+		return -ENOMEM;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT)
+		dma_dir = DMA_TO_DEVICE;
+
+	sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir);
+	if (dma_mapping_error(dev, sub->compr_addr)) {
+		kfree(sub->compr_area);
+		sub->compr_area = NULL;
+
+		return -ENOMEM;
+	}
+
+	sub->compr_bytes = size;
+
+	return 0;
+}
+
+static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_compr *compr = rtd->compr;
+	struct device *dev = compr->card->dev;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
+	int dma_dir = DMA_FROM_DEVICE;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT)
+		dma_dir = DMA_TO_DEVICE;
+
+	dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir);
+	kfree(sub->compr_area);
+	sub->compr_area = NULL;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	int ret;
+
+	if (sub->cstream)
+		return -EBUSY;
+
+	sub->cstream = cstream;
+	sub->pass_through = 1;
+	sub->use_mmap = false;
+
+	ret = uniphier_aio_comprdma_new(rtd);
+	if (ret)
+		return ret;
+
+	ret = aio_init(sub);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	int ret;
+
+	ret = uniphier_aio_compr_hw_free(cstream);
+	if (ret)
+		return ret;
+	ret = uniphier_aio_comprdma_free(rtd);
+	if (ret)
+		return ret;
+
+	sub->cstream = NULL;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
+					 struct snd_codec *params)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+
+	*params = sub->cparams.codec;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
+					 struct snd_compr_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	struct device *dev = &aio->chip->pdev->dev;
+	int ret;
+
+	if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
+		dev_err(dev, "Codec ID is not supported(%d)\n",
+			params->codec.id);
+		return -EINVAL;
+	}
+	if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
+		dev_err(dev, "Codec profile is not supported(%d)\n",
+			params->codec.profile);
+		return -EINVAL;
+	}
+
+	/* IEC frame type will be changed after received valid data */
+	sub->iec_pc = IEC61937_PC_AAC;
+
+	sub->cparams = *params;
+	sub->setting = 1;
+
+	aio_port_reset(sub);
+	aio_src_reset(sub);
+
+	ret = uniphier_aio_compr_prepare(cstream);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+
+	sub->setting = 0;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	int bytes = runtime->fragment_size;
+	unsigned long flags;
+	int ret;
+
+	ret = aiodma_ch_set_param(sub);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&sub->lock, flags);
+	ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
+				   sub->compr_addr + sub->compr_bytes,
+				   bytes);
+	spin_unlock_irqrestore(&sub->lock, flags);
+	if (ret)
+		return ret;
+
+	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
+	if (ret)
+		return ret;
+	ret = aio_oport_set_stream_type(sub, sub->iec_pc);
+	if (ret)
+		return ret;
+	aio_port_set_enable(sub, 1);
+
+	ret = aio_if_set_param(sub, sub->pass_through);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
+				      int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	struct device *dev = &aio->chip->pdev->dev;
+	int bytes = runtime->fragment_size, ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sub->lock, flags);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
+		aiodma_ch_set_enable(sub, 1);
+		sub->running = 1;
+
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		sub->running = 0;
+		aiodma_ch_set_enable(sub, 0);
+
+		break;
+	default:
+		dev_warn(dev, "Unknown trigger(%d)\n", cmd);
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&sub->lock, flags);
+
+	return ret;
+}
+
+static int uniphier_aio_compr_pointer(struct snd_compr_stream *cstream,
+				      struct snd_compr_tstamp *tstamp)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	int bytes = runtime->fragment_size;
+	unsigned long flags;
+	u32 pos;
+
+	spin_lock_irqsave(&sub->lock, flags);
+
+	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		pos = sub->rd_offs;
+		/* Size of AIO output format is double of IEC61937 */
+		tstamp->copied_total = sub->rd_total / 2;
+	} else {
+		pos = sub->wr_offs;
+		tstamp->copied_total = sub->rd_total;
+	}
+	tstamp->byte_offset = pos;
+
+	spin_unlock_irqrestore(&sub->lock, flags);
+
+	return 0;
+}
+
+static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
+				char __user *buf, size_t dstsize)
+{
+	u32 __user *srcbuf = (u32 __user *)buf;
+	u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
+	int src = 0, dst = 0, ret;
+	u32 frm, frm_a, frm_b;
+
+	while (dstsize > 0) {
+		ret = get_user(frm, srcbuf + src);
+		if (ret)
+			return ret;
+		src++;
+
+		frm_a = frm & 0xffff;
+		frm_b = (frm >> 16) & 0xffff;
+
+		if (frm == IEC61937_HEADER_SIGN) {
+			frm_a |= 0x01000000;
+
+			/* Next data is Pc and Pd */
+			sub->iec_header = true;
+		} else {
+			u16 pc = be16_to_cpu((__be16)frm_a);
+
+			if (sub->iec_header && sub->iec_pc != pc) {
+				/* Force overwrite IEC frame type */
+				sub->iec_pc = pc;
+				ret = aio_oport_set_stream_type(sub, pc);
+				if (ret)
+					return ret;
+			}
+			sub->iec_header = false;
+		}
+		dstbuf[dst++] = frm_a;
+		dstbuf[dst++] = frm_b;
+
+		dstsize -= sizeof(u32) * 2;
+	}
+
+	return 0;
+}
+
+static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
+				   char __user *buf, size_t count)
+{
+	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct device *carddev = rtd->compr->card->dev;
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
+	size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
+	int bytes = runtime->fragment_size;
+	unsigned long flags;
+	size_t s;
+	int ret;
+
+	if (cnt < sizeof(u32))
+		return 0;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
+
+		/* Size of AIO output format is double of IEC61937 */
+		s = cnt * 2;
+
+		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
+		ret = aio_compr_send_to_hw(sub, buf, s);
+		dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
+	} else {
+		dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
+
+		s = cnt;
+
+		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
+		ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
+		dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
+	}
+	if (ret)
+		return -EFAULT;
+
+	spin_lock_irqsave(&sub->lock, flags);
+
+	sub->threshold = 2 * bytes;
+	aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		sub->wr_offs += s;
+		if (sub->wr_offs >= sub->compr_bytes)
+			sub->wr_offs -= sub->compr_bytes;
+	} else {
+		sub->rd_offs += s;
+		if (sub->rd_offs >= sub->compr_bytes)
+			sub->rd_offs -= sub->compr_bytes;
+	}
+	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
+
+	spin_unlock_irqrestore(&sub->lock, flags);
+
+	return cnt;
+}
+
+static int uniphier_aio_compr_get_caps(struct snd_compr_stream *cstream,
+				       struct snd_compr_caps *caps)
+{
+	caps->num_codecs = 1;
+	caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
+	caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
+	caps->min_fragments = AUD_MIN_FRAGMENT;
+	caps->max_fragments = AUD_MAX_FRAGMENT;
+	caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
+
+	return 0;
+}
+
+static const struct snd_compr_codec_caps caps_iec = {
+	.num_descriptors = 1,
+	.descriptor[0].max_ch = 8,
+	.descriptor[0].num_sample_rates = 0,
+	.descriptor[0].num_bitrates = 0,
+	.descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
+	.descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
+				SND_AUDIOMODE_IEC_MPEG1 |
+				SND_AUDIOMODE_IEC_MP3 |
+				SND_AUDIOMODE_IEC_DTS,
+	.descriptor[0].formats = 0,
+};
+
+static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
+					     struct snd_compr_codec_caps *codec)
+{
+	if (codec->codec == SND_AUDIOCODEC_IEC61937)
+		*codec = caps_iec;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+const struct snd_compr_ops uniphier_aio_compr_ops = {
+	.open           = uniphier_aio_compr_open,
+	.free           = uniphier_aio_compr_free,
+	.get_params     = uniphier_aio_compr_get_params,
+	.set_params     = uniphier_aio_compr_set_params,
+	.trigger        = uniphier_aio_compr_trigger,
+	.pointer        = uniphier_aio_compr_pointer,
+	.copy           = uniphier_aio_compr_copy,
+	.get_caps       = uniphier_aio_compr_get_caps,
+	.get_codec_caps = uniphier_aio_compr_get_codec_caps,
+};
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c
new file mode 100644
index 000000000000..1e5f053d9f6b
--- /dev/null
+++ b/sound/soc/uniphier/aio-core.c
@@ -0,0 +1,1104 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier AIO ALSA common driver.
+//
+// Copyright (c) 2016-2018 Socionext Inc.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "aio.h"
+#include "aio-reg.h"
+
+static u64 rb_cnt(u64 wr, u64 rd, u64 len)
+{
+	if (rd <= wr)
+		return wr - rd;
+	else
+		return len - (rd - wr);
+}
+
+static u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
+{
+	if (rd <= wr)
+		return wr - rd;
+	else
+		return len - rd;
+}
+
+static u64 rb_space(u64 wr, u64 rd, u64 len)
+{
+	if (rd <= wr)
+		return len - (wr - rd) - 8;
+	else
+		return rd - wr - 8;
+}
+
+static u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
+{
+	if (rd > wr)
+		return rd - wr - 8;
+	else if (rd > 0)
+		return len - wr;
+	else
+		return len - wr - 8;
+}
+
+u64 aio_rb_cnt(struct uniphier_aio_sub *sub)
+{
+	return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
+}
+
+u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
+{
+	return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
+}
+
+u64 aio_rb_space(struct uniphier_aio_sub *sub)
+{
+	return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
+}
+
+u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
+{
+	return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
+}
+
+/**
+ * aio_chip_set_pll - set frequency to audio PLL
+ * @chip  : the AIO chip pointer
+ * @source: PLL
+ * @freq  : frequency in Hz, 0 is ignored
+ *
+ * Sets frequency of audio PLL. This function can be called anytime,
+ * but it takes time till PLL is locked.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
+		     unsigned int freq)
+{
+	struct device *dev = &chip->pdev->dev;
+	struct regmap *r = chip->regmap;
+	int shift;
+	u32 v;
+
+	/* Not change */
+	if (freq == 0)
+		return 0;
+
+	switch (pll_id) {
+	case AUD_PLL_A1:
+		shift = 0;
+		break;
+	case AUD_PLL_F1:
+		shift = 1;
+		break;
+	case AUD_PLL_A2:
+		shift = 2;
+		break;
+	case AUD_PLL_F2:
+		shift = 3;
+		break;
+	default:
+		dev_err(dev, "PLL(%d) not supported\n", pll_id);
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 36864000:
+		v = A2APLLCTR1_APLLX_36MHZ;
+		break;
+	case 33868800:
+		v = A2APLLCTR1_APLLX_33MHZ;
+		break;
+	default:
+		dev_err(dev, "PLL frequency not supported(%d)\n", freq);
+		return -EINVAL;
+	}
+	chip->plls[pll_id].freq = freq;
+
+	regmap_update_bits(r, A2APLLCTR1, A2APLLCTR1_APLLX_MASK << shift,
+			   v << shift);
+
+	return 0;
+}
+
+/**
+ * aio_chip_init - initialize AIO whole settings
+ * @chip: the AIO chip pointer
+ *
+ * Sets AIO fixed and whole device settings to AIO.
+ * This function need to call once at driver startup.
+ *
+ * The register area that is changed by this function is shared by all
+ * modules of AIO. But there is not race condition since this function
+ * has always set the same initialize values.
+ */
+void aio_chip_init(struct uniphier_aio_chip *chip)
+{
+	struct regmap *r = chip->regmap;
+
+	regmap_update_bits(r, A2APLLCTR0,
+			   A2APLLCTR0_APLLXPOW_MASK,
+			   A2APLLCTR0_APLLXPOW_PWON);
+
+	regmap_update_bits(r, A2EXMCLKSEL0,
+			   A2EXMCLKSEL0_EXMCLK_MASK,
+			   A2EXMCLKSEL0_EXMCLK_OUTPUT);
+
+	regmap_update_bits(r, A2AIOINPUTSEL, A2AIOINPUTSEL_RXSEL_MASK,
+			   A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 |
+			   A2AIOINPUTSEL_RXSEL_PCMI2_SIF |
+			   A2AIOINPUTSEL_RXSEL_PCMI3_EVEA |
+			   A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1);
+
+	if (chip->chip_spec->addr_ext)
+		regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
+				   CDA2D_TEST_DDR_MODE_EXTON0);
+	else
+		regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
+				   CDA2D_TEST_DDR_MODE_EXTOFF1);
+}
+
+/**
+ * aio_init - initialize AIO substream
+ * @sub: the AIO substream pointer
+ *
+ * Sets fixed settings of each AIO substreams.
+ * This function need to call once at substream startup.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_init(struct uniphier_aio_sub *sub)
+{
+	struct device *dev = &sub->aio->chip->pdev->dev;
+	struct regmap *r = sub->aio->chip->regmap;
+
+	regmap_write(r, A2RBNMAPCTR0(sub->swm->rb.hw),
+		     MAPCTR0_EN | sub->swm->rb.map);
+	regmap_write(r, A2CHNMAPCTR0(sub->swm->ch.hw),
+		     MAPCTR0_EN | sub->swm->ch.map);
+
+	switch (sub->swm->type) {
+	case PORT_TYPE_I2S:
+	case PORT_TYPE_SPDIF:
+	case PORT_TYPE_EVE:
+		if (sub->swm->dir == PORT_DIR_INPUT) {
+			regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
+				     MAPCTR0_EN | sub->swm->iif.map);
+			regmap_write(r, A2IPORTNMAPCTR0(sub->swm->iport.hw),
+				     MAPCTR0_EN | sub->swm->iport.map);
+		} else {
+			regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
+				     MAPCTR0_EN | sub->swm->oif.map);
+			regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
+				     MAPCTR0_EN | sub->swm->oport.map);
+		}
+		break;
+	case PORT_TYPE_CONV:
+		regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
+			     MAPCTR0_EN | sub->swm->oif.map);
+		regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
+			     MAPCTR0_EN | sub->swm->oport.map);
+		regmap_write(r, A2CHNMAPCTR0(sub->swm->och.hw),
+			     MAPCTR0_EN | sub->swm->och.map);
+		regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
+			     MAPCTR0_EN | sub->swm->iif.map);
+		break;
+	default:
+		dev_err(dev, "Unknown port type %d.\n", sub->swm->type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * aio_port_reset - reset AIO port block
+ * @sub: the AIO substream pointer
+ *
+ * Resets the digital signal input/output port block of AIO.
+ */
+void aio_port_reset(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		regmap_write(r, AOUTRSTCTR0, BIT(sub->swm->oport.map));
+		regmap_write(r, AOUTRSTCTR1, BIT(sub->swm->oport.map));
+	} else {
+		regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
+				   IPORTMXRSTCTR_RSTPI_MASK,
+				   IPORTMXRSTCTR_RSTPI_RESET);
+		regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
+				   IPORTMXRSTCTR_RSTPI_MASK,
+				   IPORTMXRSTCTR_RSTPI_RELEASE);
+	}
+}
+
+/**
+ * aio_port_set_rate - set sampling rate of LPCM
+ * @sub: the AIO substream pointer, PCM substream only
+ * @rate: Sampling rate in Hz.
+ *
+ * Set suitable I2S format settings to input/output port block of AIO.
+ * Parameter is specified by hw_params().
+ *
+ * This function may return error if non-PCM substream.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	struct device *dev = &sub->aio->chip->pdev->dev;
+	u32 v;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		switch (rate) {
+		case 8000:
+			v = OPORTMXCTR1_FSSEL_8;
+			break;
+		case 11025:
+			v = OPORTMXCTR1_FSSEL_11_025;
+			break;
+		case 12000:
+			v = OPORTMXCTR1_FSSEL_12;
+			break;
+		case 16000:
+			v = OPORTMXCTR1_FSSEL_16;
+			break;
+		case 22050:
+			v = OPORTMXCTR1_FSSEL_22_05;
+			break;
+		case 24000:
+			v = OPORTMXCTR1_FSSEL_24;
+			break;
+		case 32000:
+			v = OPORTMXCTR1_FSSEL_32;
+			break;
+		case 44100:
+			v = OPORTMXCTR1_FSSEL_44_1;
+			break;
+		case 48000:
+			v = OPORTMXCTR1_FSSEL_48;
+			break;
+		case 88200:
+			v = OPORTMXCTR1_FSSEL_88_2;
+			break;
+		case 96000:
+			v = OPORTMXCTR1_FSSEL_96;
+			break;
+		case 176400:
+			v = OPORTMXCTR1_FSSEL_176_4;
+			break;
+		case 192000:
+			v = OPORTMXCTR1_FSSEL_192;
+			break;
+		default:
+			dev_err(dev, "Rate not supported(%d)\n", rate);
+			return -EINVAL;
+		}
+
+		regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
+				   OPORTMXCTR1_FSSEL_MASK, v);
+	} else {
+		switch (rate) {
+		case 8000:
+			v = IPORTMXCTR1_FSSEL_8;
+			break;
+		case 11025:
+			v = IPORTMXCTR1_FSSEL_11_025;
+			break;
+		case 12000:
+			v = IPORTMXCTR1_FSSEL_12;
+			break;
+		case 16000:
+			v = IPORTMXCTR1_FSSEL_16;
+			break;
+		case 22050:
+			v = IPORTMXCTR1_FSSEL_22_05;
+			break;
+		case 24000:
+			v = IPORTMXCTR1_FSSEL_24;
+			break;
+		case 32000:
+			v = IPORTMXCTR1_FSSEL_32;
+			break;
+		case 44100:
+			v = IPORTMXCTR1_FSSEL_44_1;
+			break;
+		case 48000:
+			v = IPORTMXCTR1_FSSEL_48;
+			break;
+		case 88200:
+			v = IPORTMXCTR1_FSSEL_88_2;
+			break;
+		case 96000:
+			v = IPORTMXCTR1_FSSEL_96;
+			break;
+		case 176400:
+			v = IPORTMXCTR1_FSSEL_176_4;
+			break;
+		case 192000:
+			v = IPORTMXCTR1_FSSEL_192;
+			break;
+		default:
+			dev_err(dev, "Rate not supported(%d)\n", rate);
+			return -EINVAL;
+		}
+
+		regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
+				   IPORTMXCTR1_FSSEL_MASK, v);
+	}
+
+	return 0;
+}
+
+/**
+ * aio_port_set_fmt - set format of I2S data
+ * @sub: the AIO substream pointer, PCM substream only
+ * This parameter has no effect if substream is I2S or PCM.
+ *
+ * Set suitable I2S format settings to input/output port block of AIO.
+ * Parameter is specified by set_fmt().
+ *
+ * This function may return error if non-PCM substream.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_port_set_fmt(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	struct device *dev = &sub->aio->chip->pdev->dev;
+	u32 v;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		switch (sub->aio->fmt) {
+		case SND_SOC_DAIFMT_LEFT_J:
+			v = OPORTMXCTR1_I2SLRSEL_LEFT;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			v = OPORTMXCTR1_I2SLRSEL_RIGHT;
+			break;
+		case SND_SOC_DAIFMT_I2S:
+			v = OPORTMXCTR1_I2SLRSEL_I2S;
+			break;
+		default:
+			dev_err(dev, "Format is not supported(%d)\n",
+				sub->aio->fmt);
+			return -EINVAL;
+		}
+
+		v |= OPORTMXCTR1_OUTBITSEL_24;
+		regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
+				   OPORTMXCTR1_I2SLRSEL_MASK |
+				   OPORTMXCTR1_OUTBITSEL_MASK, v);
+	} else {
+		switch (sub->aio->fmt) {
+		case SND_SOC_DAIFMT_LEFT_J:
+			v = IPORTMXCTR1_LRSEL_LEFT;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			v = IPORTMXCTR1_LRSEL_RIGHT;
+			break;
+		case SND_SOC_DAIFMT_I2S:
+			v = IPORTMXCTR1_LRSEL_I2S;
+			break;
+		default:
+			dev_err(dev, "Format is not supported(%d)\n",
+				sub->aio->fmt);
+			return -EINVAL;
+		}
+
+		v |= IPORTMXCTR1_OUTBITSEL_24 |
+			IPORTMXCTR1_CHSEL_ALL;
+		regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
+				   IPORTMXCTR1_LRSEL_MASK |
+				   IPORTMXCTR1_OUTBITSEL_MASK |
+				   IPORTMXCTR1_CHSEL_MASK, v);
+	}
+
+	return 0;
+}
+
+/**
+ * aio_port_set_clk - set clock and divider of AIO port block
+ * @sub: the AIO substream pointer
+ *
+ * Set suitable PLL clock divider and relational settings to
+ * input/output port block of AIO. Parameters are specified by
+ * set_sysclk() and set_pll().
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_port_set_clk(struct uniphier_aio_sub *sub)
+{
+	struct uniphier_aio_chip *chip = sub->aio->chip;
+	struct device *dev = &sub->aio->chip->pdev->dev;
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v_pll[] = {
+		OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
+		OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
+		OPORTMXCTR2_ACLKSEL_A2PLL,
+		OPORTMXCTR2_ACLKSEL_RX1,
+	};
+	u32 v_div[] = {
+		OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
+		OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
+	};
+	u32 v;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		if (sub->swm->type == PORT_TYPE_I2S) {
+			if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
+				dev_err(dev, "PLL(%d) is invalid\n",
+					sub->aio->pll_out);
+				return -EINVAL;
+			}
+			if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
+				dev_err(dev, "PLL divider(%d) is invalid\n",
+					sub->aio->plldiv);
+				return -EINVAL;
+			}
+
+			v = v_pll[sub->aio->pll_out] |
+				OPORTMXCTR2_MSSEL_MASTER |
+				v_div[sub->aio->plldiv];
+
+			switch (chip->plls[sub->aio->pll_out].freq) {
+			case 0:
+			case 36864000:
+			case 33868800:
+				v |= OPORTMXCTR2_EXTLSIFSSEL_36;
+				break;
+			default:
+				v |= OPORTMXCTR2_EXTLSIFSSEL_24;
+				break;
+			}
+		} else if (sub->swm->type == PORT_TYPE_EVE) {
+			v = OPORTMXCTR2_ACLKSEL_A2PLL |
+				OPORTMXCTR2_MSSEL_MASTER |
+				OPORTMXCTR2_EXTLSIFSSEL_36 |
+				OPORTMXCTR2_DACCKSEL_1_2;
+		} else {
+			if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
+				dev_err(dev, "PLL(%d) is invalid\n",
+					sub->aio->pll_out);
+				return -EINVAL;
+			}
+			v = v_pll[sub->aio->pll_out] |
+				OPORTMXCTR2_MSSEL_MASTER |
+				OPORTMXCTR2_DACCKSEL_1_2;
+
+			switch (chip->plls[sub->aio->pll_out].freq) {
+			case 0:
+			case 36864000:
+			case 33868800:
+				v |= OPORTMXCTR2_EXTLSIFSSEL_36;
+				break;
+			default:
+				v |= OPORTMXCTR2_EXTLSIFSSEL_24;
+				break;
+			}
+		}
+		regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
+	} else {
+		v = IPORTMXCTR2_ACLKSEL_A1 |
+			IPORTMXCTR2_MSSEL_SLAVE |
+			IPORTMXCTR2_EXTLSIFSSEL_36 |
+			IPORTMXCTR2_DACCKSEL_1_2;
+		regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
+	}
+
+	return 0;
+}
+
+/**
+ * aio_port_set_param - set parameters of AIO port block
+ * @sub: the AIO substream pointer
+ * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
+ * This parameter has no effect if substream is I2S or PCM.
+ * @params: hardware parameters of ALSA
+ *
+ * Set suitable setting to input/output port block of AIO to process the
+ * specified in params.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
+		       const struct snd_pcm_hw_params *params)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v;
+	int ret;
+
+	if (!pass_through) {
+		ret = aio_port_set_rate(sub, params_rate(params));
+		if (ret)
+			return ret;
+
+		ret = aio_port_set_fmt(sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = aio_port_set_clk(sub);
+	if (ret)
+		return ret;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		if (pass_through)
+			v = OPORTMXCTR3_SRCSEL_STREAM |
+				OPORTMXCTR3_VALID_STREAM;
+		else
+			v = OPORTMXCTR3_SRCSEL_PCM |
+				OPORTMXCTR3_VALID_PCM;
+
+		v |= OPORTMXCTR3_IECTHUR_IECOUT |
+			OPORTMXCTR3_PMSEL_PAUSE |
+			OPORTMXCTR3_PMSW_MUTE_OFF;
+		regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
+	} else {
+		regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
+			     IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
+		regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
+			     IPORTMXEXNOE_PCMINOE_INPUT);
+	}
+
+	return 0;
+}
+
+/**
+ * aio_port_set_enable - start or stop of AIO port block
+ * @sub: the AIO substream pointer
+ * @enable: zero to stop the block, otherwise to start
+ *
+ * Start or stop the signal input/output port block of AIO.
+ */
+void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
+			     sub->swm->oif.map);
+
+		regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
+				   OPORTMXMASK_IUDXMSK_MASK |
+				   OPORTMXMASK_IUXCKMSK_MASK |
+				   OPORTMXMASK_DXMSK_MASK |
+				   OPORTMXMASK_XCKMSK_MASK,
+				   OPORTMXMASK_IUDXMSK_OFF |
+				   OPORTMXMASK_IUXCKMSK_OFF |
+				   OPORTMXMASK_DXMSK_OFF |
+				   OPORTMXMASK_XCKMSK_OFF);
+
+		if (enable)
+			regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
+		else
+			regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
+	} else {
+		regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
+				   IPORTMXMASK_IUXCKMSK_MASK |
+				   IPORTMXMASK_XCKMSK_MASK,
+				   IPORTMXMASK_IUXCKMSK_OFF |
+				   IPORTMXMASK_XCKMSK_OFF);
+
+		if (enable)
+			regmap_update_bits(r,
+					   IPORTMXCTR2(sub->swm->iport.map),
+					   IPORTMXCTR2_REQEN_MASK,
+					   IPORTMXCTR2_REQEN_ENABLE);
+		else
+			regmap_update_bits(r,
+					   IPORTMXCTR2(sub->swm->iport.map),
+					   IPORTMXCTR2_REQEN_MASK,
+					   IPORTMXCTR2_REQEN_DISABLE);
+	}
+}
+
+/**
+ * aio_if_set_param - set parameters of AIO DMA I/F block
+ * @sub: the AIO substream pointer
+ * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
+ * This parameter has no effect if substream is I2S or PCM.
+ *
+ * Set suitable setting to DMA interface block of AIO to process the
+ * specified in settings.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		if (pass_through)
+			v = PBOUTMXCTR0_ENDIAN_0123 |
+				PBOUTMXCTR0_MEMFMT_STREAM;
+		else
+			v = PBOUTMXCTR0_ENDIAN_3210 |
+				PBOUTMXCTR0_MEMFMT_2CH;
+
+		regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
+		regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
+	} else {
+		regmap_write(r, PBINMXCTR(sub->swm->iif.map),
+			     PBINMXCTR_NCONNECT_CONNECT |
+			     PBINMXCTR_INOUTSEL_IN |
+			     (sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
+			     PBINMXCTR_ENDIAN_3210 |
+			     PBINMXCTR_MEMFMT_D0);
+	}
+
+	return 0;
+}
+
+/**
+ * aio_oport_set_stream_type - set parameters of AIO playback port block
+ * @sub: the AIO substream pointer
+ * @pc: Pc type of IEC61937
+ *
+ * Set special setting to output port block of AIO to output the stream
+ * via S/PDIF.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
+			      enum IEC61937_PC pc)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
+
+	switch (pc) {
+	case IEC61937_PC_AC3:
+		repet = OPORTMXREPET_STRLENGTH_AC3 |
+			OPORTMXREPET_PMLENGTH_AC3;
+		pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
+		break;
+	case IEC61937_PC_MPA:
+		repet = OPORTMXREPET_STRLENGTH_MPA |
+			OPORTMXREPET_PMLENGTH_MPA;
+		pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
+		break;
+	case IEC61937_PC_MP3:
+		repet = OPORTMXREPET_STRLENGTH_MP3 |
+			OPORTMXREPET_PMLENGTH_MP3;
+		pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
+		break;
+	case IEC61937_PC_DTS1:
+		repet = OPORTMXREPET_STRLENGTH_DTS1 |
+			OPORTMXREPET_PMLENGTH_DTS1;
+		pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
+		break;
+	case IEC61937_PC_DTS2:
+		repet = OPORTMXREPET_STRLENGTH_DTS2 |
+			OPORTMXREPET_PMLENGTH_DTS2;
+		pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
+		break;
+	case IEC61937_PC_DTS3:
+		repet = OPORTMXREPET_STRLENGTH_DTS3 |
+			OPORTMXREPET_PMLENGTH_DTS3;
+		pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
+		break;
+	case IEC61937_PC_AAC:
+		repet = OPORTMXREPET_STRLENGTH_AAC |
+			OPORTMXREPET_PMLENGTH_AAC;
+		pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
+		break;
+	case IEC61937_PC_PAUSE:
+		/* Do nothing */
+		break;
+	}
+
+	regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
+	regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
+
+	return 0;
+}
+
+/**
+ * aio_src_reset - reset AIO SRC block
+ * @sub: the AIO substream pointer
+ *
+ * Resets the digital signal input/output port with sampling rate converter
+ * block of AIO.
+ * This function has no effect if substream is not supported rate converter.
+ */
+void aio_src_reset(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	if (sub->swm->dir != PORT_DIR_OUTPUT)
+		return;
+
+	regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
+	regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
+}
+
+/**
+ * aio_src_set_param - set parameters of AIO SRC block
+ * @sub: the AIO substream pointer
+ * @params: hardware parameters of ALSA
+ *
+ * Set suitable setting to input/output port with sampling rate converter
+ * block of AIO to process the specified in params.
+ * This function has no effect if substream is not supported rate converter.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int aio_src_set_param(struct uniphier_aio_sub *sub,
+		      const struct snd_pcm_hw_params *params)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v;
+
+	if (sub->swm->dir != PORT_DIR_OUTPUT)
+		return 0;
+
+	regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
+		     OPORTMXSRC1CTR_THMODE_SRC |
+		     OPORTMXSRC1CTR_SRCPATH_CALC |
+		     OPORTMXSRC1CTR_SYNC_ASYNC |
+		     OPORTMXSRC1CTR_FSIIPSEL_INNER |
+		     OPORTMXSRC1CTR_FSISEL_ACLK);
+
+	switch (params_rate(params)) {
+	default:
+	case 48000:
+		v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
+			OPORTMXRATE_I_MCKSEL_36 |
+			OPORTMXRATE_I_FSSEL_48;
+		break;
+	case 44100:
+		v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
+			OPORTMXRATE_I_MCKSEL_33 |
+			OPORTMXRATE_I_FSSEL_44_1;
+		break;
+	case 32000:
+		v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
+			OPORTMXRATE_I_MCKSEL_36 |
+			OPORTMXRATE_I_FSSEL_32;
+		break;
+	}
+
+	regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
+		     v | OPORTMXRATE_I_ACLKSRC_APLL |
+		     OPORTMXRATE_I_LRCKSTP_STOP);
+	regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
+			   OPORTMXRATE_I_LRCKSTP_MASK,
+			   OPORTMXRATE_I_LRCKSTP_START);
+
+	return 0;
+}
+
+int aio_srcif_set_param(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	regmap_write(r, PBINMXCTR(sub->swm->iif.map),
+		     PBINMXCTR_NCONNECT_CONNECT |
+		     PBINMXCTR_INOUTSEL_OUT |
+		     (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
+		     PBINMXCTR_ENDIAN_3210 |
+		     PBINMXCTR_MEMFMT_D0);
+
+	return 0;
+}
+
+int aio_srcch_set_param(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
+		     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
+
+	regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
+		     CDA2D_CHMXAMODE_ENDIAN_3210 |
+		     CDA2D_CHMXAMODE_AUPDT_FIX |
+		     CDA2D_CHMXAMODE_TYPE_NORMAL);
+
+	regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
+		     CDA2D_CHMXAMODE_ENDIAN_3210 |
+		     CDA2D_CHMXAMODE_AUPDT_INC |
+		     CDA2D_CHMXAMODE_TYPE_RING |
+		     (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
+
+	return 0;
+}
+
+void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v;
+
+	if (enable)
+		v = CDA2D_STRT0_STOP_START;
+	else
+		v = CDA2D_STRT0_STOP_STOP;
+
+	regmap_write(r, CDA2D_STRT0,
+		     v | BIT(sub->swm->och.map));
+}
+
+int aiodma_ch_set_param(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 v;
+
+	regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
+		     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
+
+	v = CDA2D_CHMXAMODE_ENDIAN_3210 |
+		CDA2D_CHMXAMODE_AUPDT_INC |
+		CDA2D_CHMXAMODE_TYPE_NORMAL |
+		(sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
+	if (sub->swm->dir == PORT_DIR_OUTPUT)
+		regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
+	else
+		regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
+
+	return 0;
+}
+
+void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	if (enable) {
+		regmap_write(r, CDA2D_STRT0,
+			     CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
+
+		regmap_update_bits(r, INTRBIM(0),
+				   BIT(sub->swm->rb.map),
+				   BIT(sub->swm->rb.map));
+	} else {
+		regmap_write(r, CDA2D_STRT0,
+			     CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
+
+		regmap_update_bits(r, INTRBIM(0),
+				   BIT(sub->swm->rb.map),
+				   0);
+	}
+}
+
+static u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 pos_u, pos_l;
+	int i;
+
+	regmap_write(r, CDA2D_RDPTRLOAD,
+		     CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
+	/* Wait for setup */
+	for (i = 0; i < 6; i++)
+		regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
+
+	regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
+	regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
+	pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
+
+	return ((u64)pos_u << 32) | pos_l;
+}
+
+static void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 tmp;
+	int i;
+
+	regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
+	regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
+	regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
+	/* Wait for setup */
+	for (i = 0; i < 6; i++)
+		regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
+}
+
+static u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 pos_u, pos_l;
+	int i;
+
+	regmap_write(r, CDA2D_WRPTRLOAD,
+		     CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
+	/* Wait for setup */
+	for (i = 0; i < 6; i++)
+		regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
+
+	regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
+	regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
+	pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
+
+	return ((u64)pos_u << 32) | pos_l;
+}
+
+static void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 tmp;
+	int i;
+
+	regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
+		     lower_32_bits(pos));
+	regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
+		     upper_32_bits(pos));
+	regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
+	/* Wait for setup */
+	for (i = 0; i < 6; i++)
+		regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
+}
+
+int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	if (size <= th)
+		return -EINVAL;
+
+	regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
+	regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
+
+	return 0;
+}
+
+int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
+			 int period)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u64 size = end - start;
+	int ret;
+
+	if (end < start || period < 0)
+		return -EINVAL;
+
+	regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
+	regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
+		     lower_32_bits(start));
+	regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
+		     upper_32_bits(start));
+	regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
+		     lower_32_bits(end));
+	regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
+		     upper_32_bits(end));
+
+	regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
+
+	ret = aiodma_rb_set_threshold(sub, size, 2 * period);
+	if (ret)
+		return ret;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		aiodma_rb_set_rp(sub, start);
+		aiodma_rb_set_wp(sub, end - period);
+
+		regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
+				   CDA2D_RBMXIX_SPACE,
+				   CDA2D_RBMXIX_SPACE);
+	} else {
+		aiodma_rb_set_rp(sub, end - period);
+		aiodma_rb_set_wp(sub, start);
+
+		regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
+				   CDA2D_RBMXIX_REMAIN,
+				   CDA2D_RBMXIX_REMAIN);
+	}
+
+	sub->threshold = 2 * period;
+	sub->rd_offs = 0;
+	sub->wr_offs = 0;
+	sub->rd_org = 0;
+	sub->wr_org = 0;
+	sub->rd_total = 0;
+	sub->wr_total = 0;
+
+	return 0;
+}
+
+void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
+		    int period)
+{
+	if (sub->swm->dir == PORT_DIR_OUTPUT) {
+		sub->rd_offs = aiodma_rb_get_rp(sub) - start;
+
+		if (sub->use_mmap) {
+			sub->threshold = 2 * period;
+			aiodma_rb_set_threshold(sub, size, 2 * period);
+
+			sub->wr_offs = sub->rd_offs - period;
+			if (sub->rd_offs < period)
+				sub->wr_offs += size;
+		}
+		aiodma_rb_set_wp(sub, sub->wr_offs + start);
+	} else {
+		sub->wr_offs = aiodma_rb_get_wp(sub) - start;
+
+		if (sub->use_mmap) {
+			sub->threshold = 2 * period;
+			aiodma_rb_set_threshold(sub, size, 2 * period);
+
+			sub->rd_offs = sub->wr_offs - period;
+			if (sub->wr_offs < period)
+				sub->rd_offs += size;
+		}
+		aiodma_rb_set_rp(sub, sub->rd_offs + start);
+	}
+
+	sub->rd_total += sub->rd_offs - sub->rd_org;
+	if (sub->rd_offs < sub->rd_org)
+		sub->rd_total += size;
+	sub->wr_total += sub->wr_offs - sub->wr_org;
+	if (sub->wr_offs < sub->wr_org)
+		sub->wr_total += size;
+
+	sub->rd_org = sub->rd_offs;
+	sub->wr_org = sub->wr_offs;
+}
+
+bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+	u32 ir;
+
+	regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT)
+		return !!(ir & CDA2D_RBMXIX_SPACE);
+	else
+		return !!(ir & CDA2D_RBMXIX_REMAIN);
+}
+
+void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
+{
+	struct regmap *r = sub->aio->chip->regmap;
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT)
+		regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
+			     CDA2D_RBMXIX_SPACE);
+	else
+		regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
+			     CDA2D_RBMXIX_REMAIN);
+}
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
new file mode 100644
index 000000000000..7cf2316c69a2
--- /dev/null
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier AIO ALSA CPU DAI driver.
+//
+// Copyright (c) 2016-2018 Socionext Inc.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "aio.h"
+
+static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
+{
+	struct device *dev = &chip->pdev->dev;
+
+	if (pll_id < 0 || chip->num_plls <= pll_id) {
+		dev_err(dev, "PLL(%d) is not supported\n", pll_id);
+		return false;
+	}
+
+	return chip->plls[pll_id].enable;
+}
+
+static bool match_spec(const struct uniphier_aio_spec *spec,
+		       const char *name, int dir)
+{
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
+	    spec->swm.dir != PORT_DIR_OUTPUT) {
+		return false;
+	}
+
+	if (dir == SNDRV_PCM_STREAM_CAPTURE &&
+	    spec->swm.dir != PORT_DIR_INPUT) {
+		return false;
+	}
+
+	if (spec->name && strcmp(spec->name, name) == 0)
+		return true;
+
+	if (spec->gname && strcmp(spec->gname, name) == 0)
+		return true;
+
+	return false;
+}
+
+/**
+ * find_spec - find HW specification info by name
+ * @aio: the AIO device pointer
+ * @name: name of device
+ * @direction: the direction of substream, SNDRV_PCM_STREAM_*
+ *
+ * Find hardware specification information from list by device name. This
+ * information is used for telling the difference of SoCs to driver.
+ *
+ * Specification list is array of 'struct uniphier_aio_spec' which is defined
+ * in each drivers (see: aio-i2s.c).
+ *
+ * Return: The pointer of hardware specification of AIO if successful,
+ * otherwise NULL on error.
+ */
+static const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
+						 const char *name,
+						 int direction)
+{
+	const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
+	int i;
+
+	for (i = 0; i < chip_spec->num_specs; i++) {
+		const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
+
+		if (match_spec(spec, name, direction))
+			return spec;
+	}
+
+	return NULL;
+}
+
+/**
+ * find_divider - find clock divider by frequency
+ * @aio: the AIO device pointer
+ * @pll_id: PLL ID, should be AUD_PLL_XX
+ * @freq: required frequency
+ *
+ * Find suitable clock divider by frequency.
+ *
+ * Return: The ID of PLL if successful, otherwise negative error value.
+ */
+static int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
+{
+	struct uniphier_aio_pll *pll;
+	int mul[] = { 1, 1, 1, 2, };
+	int div[] = { 2, 3, 1, 3, };
+	int i;
+
+	if (!is_valid_pll(aio->chip, pll_id))
+		return -EINVAL;
+
+	pll = &aio->chip->plls[pll_id];
+	for (i = 0; i < ARRAY_SIZE(mul); i++)
+		if (pll->freq * mul[i] / div[i] == freq)
+			return i;
+
+	return -ENOTSUPP;
+}
+
+static int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+				   unsigned int freq, int dir)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct device *dev = &aio->chip->pdev->dev;
+	bool pll_auto = false;
+	int pll_id, div_id;
+
+	switch (clk_id) {
+	case AUD_CLK_IO:
+		return -ENOTSUPP;
+	case AUD_CLK_A1:
+		pll_id = AUD_PLL_A1;
+		break;
+	case AUD_CLK_F1:
+		pll_id = AUD_PLL_F1;
+		break;
+	case AUD_CLK_A2:
+		pll_id = AUD_PLL_A2;
+		break;
+	case AUD_CLK_F2:
+		pll_id = AUD_PLL_F2;
+		break;
+	case AUD_CLK_A:
+		pll_id = AUD_PLL_A1;
+		pll_auto = true;
+		break;
+	case AUD_CLK_F:
+		pll_id = AUD_PLL_F1;
+		pll_auto = true;
+		break;
+	case AUD_CLK_APLL:
+		pll_id = AUD_PLL_APLL;
+		break;
+	case AUD_CLK_RX0:
+		pll_id = AUD_PLL_RX0;
+		break;
+	case AUD_CLK_USB0:
+		pll_id = AUD_PLL_USB0;
+		break;
+	case AUD_CLK_HSC0:
+		pll_id = AUD_PLL_HSC0;
+		break;
+	default:
+		dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
+		return -EINVAL;
+	}
+
+	if (pll_auto) {
+		for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
+			div_id = find_divider(aio, pll_id, freq);
+			if (div_id >= 0) {
+				aio->plldiv = div_id;
+				break;
+			}
+		}
+		if (pll_id == aio->chip->num_plls) {
+			dev_err(dev, "Sysclk frequency is not supported(%d)\n",
+				freq);
+			return -EINVAL;
+		}
+	}
+
+	if (dir == SND_SOC_CLOCK_OUT)
+		aio->pll_out = pll_id;
+	else
+		aio->pll_in = pll_id;
+
+	return 0;
+}
+
+static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
+				int source, unsigned int freq_in,
+				unsigned int freq_out)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct device *dev = &aio->chip->pdev->dev;
+	int ret;
+
+	if (!is_valid_pll(aio->chip, pll_id))
+		return -EINVAL;
+	if (!aio->chip->plls[pll_id].enable) {
+		dev_err(dev, "PLL(%d) is not implemented\n", pll_id);
+		return -ENOTSUPP;
+	}
+
+	ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct device *dev = &aio->chip->pdev->dev;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_I2S:
+		aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(dev, "Format is not supported(%d)\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int uniphier_aio_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+	int ret;
+
+	sub->substream = substream;
+	sub->pass_through = 0;
+	sub->use_mmap = true;
+
+	ret = aio_init(sub);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+
+	sub->substream = NULL;
+}
+
+static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+	struct device *dev = &aio->chip->pdev->dev;
+	int freq, ret;
+
+	switch (params_rate(params)) {
+	case 48000:
+	case 32000:
+	case 24000:
+		freq = 12288000;
+		break;
+	case 44100:
+	case 22050:
+		freq = 11289600;
+		break;
+	default:
+		dev_err(dev, "Rate is not supported(%d)\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
+				     freq, SND_SOC_CLOCK_OUT);
+	if (ret)
+		return ret;
+
+	sub->params = *params;
+	sub->setting = 1;
+
+	aio_port_reset(sub);
+	aio_src_reset(sub);
+
+	return 0;
+}
+
+static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+
+	sub->setting = 0;
+
+	return 0;
+}
+
+static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+	int ret;
+
+	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
+	if (ret)
+		return ret;
+	ret = aio_src_set_param(sub, &sub->params);
+	if (ret)
+		return ret;
+	aio_port_set_enable(sub, 1);
+
+	ret = aio_if_set_param(sub, sub->pass_through);
+	if (ret)
+		return ret;
+
+	if (sub->swm->type == PORT_TYPE_CONV) {
+		ret = aio_srcif_set_param(sub);
+		if (ret)
+			return ret;
+		ret = aio_srcch_set_param(sub);
+		if (ret)
+			return ret;
+		aio_srcch_set_enable(sub, 1);
+	}
+
+	return 0;
+}
+
+const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
+	.set_sysclk  = uniphier_aio_set_sysclk,
+	.set_pll     = uniphier_aio_set_pll,
+	.set_fmt     = uniphier_aio_set_fmt,
+	.startup     = uniphier_aio_startup,
+	.shutdown    = uniphier_aio_shutdown,
+	.hw_params   = uniphier_aio_hw_params,
+	.hw_free     = uniphier_aio_hw_free,
+	.prepare     = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
+	.set_sysclk  = uniphier_aio_set_sysclk,
+	.set_pll     = uniphier_aio_set_pll,
+	.startup     = uniphier_aio_startup,
+	.shutdown    = uniphier_aio_shutdown,
+	.hw_params   = uniphier_aio_hw_params,
+	.hw_free     = uniphier_aio_hw_free,
+	.prepare     = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
+
+int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
+		struct uniphier_aio_sub *sub = &aio->sub[i];
+		const struct uniphier_aio_spec *spec;
+
+		spec = find_spec(aio, dai->name, i);
+		if (!spec)
+			continue;
+
+		sub->swm = &spec->swm;
+		sub->spec = spec;
+	}
+
+	aio_chip_init(aio->chip);
+	aio->chip->active = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
+
+int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+
+	aio->chip->active = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
+
+int uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+
+	reset_control_assert(aio->chip->rst);
+	clk_disable_unprepare(aio->chip->clk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(uniphier_aio_dai_suspend);
+
+int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
+{
+	struct uniphier_aio *aio = uniphier_priv(dai);
+	int ret, i;
+
+	if (!aio->chip->active)
+		return 0;
+
+	ret = clk_prepare_enable(aio->chip->clk);
+	if (ret)
+		return ret;
+
+	ret = reset_control_deassert(aio->chip->rst);
+	if (ret)
+		goto err_out_clock;
+
+	aio_chip_init(aio->chip);
+
+	for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
+		struct uniphier_aio_sub *sub = &aio->sub[i];
+
+		if (!sub->spec || !sub->substream)
+			continue;
+
+		ret = aio_init(sub);
+		if (ret)
+			goto err_out_clock;
+
+		if (!sub->setting)
+			continue;
+
+		aio_port_reset(sub);
+		aio_src_reset(sub);
+	}
+
+	return 0;
+
+err_out_clock:
+	clk_disable_unprepare(aio->chip->clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume);
+
+static const struct snd_soc_component_driver uniphier_aio_component = {
+	.name = "uniphier-aio",
+};
+
+int uniphier_aio_probe(struct platform_device *pdev)
+{
+	struct uniphier_aio_chip *chip;
+	struct device *dev = &pdev->dev;
+	int ret, i, j;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->chip_spec = of_device_get_match_data(dev);
+	if (!chip->chip_spec)
+		return -EINVAL;
+
+	chip->clk = devm_clk_get(dev, "aio");
+	if (IS_ERR(chip->clk))
+		return PTR_ERR(chip->clk);
+
+	chip->rst = devm_reset_control_get_shared(dev, "aio");
+	if (IS_ERR(chip->rst))
+		return PTR_ERR(chip->rst);
+
+	chip->num_aios = chip->chip_spec->num_dais;
+	chip->aios = devm_kzalloc(dev,
+				  sizeof(struct uniphier_aio) * chip->num_aios,
+				  GFP_KERNEL);
+	if (!chip->aios)
+		return -ENOMEM;
+
+	chip->num_plls = chip->chip_spec->num_plls;
+	chip->plls = devm_kzalloc(dev, sizeof(struct uniphier_aio_pll) *
+				  chip->num_plls, GFP_KERNEL);
+	if (!chip->plls)
+		return -ENOMEM;
+	memcpy(chip->plls, chip->chip_spec->plls,
+	       sizeof(struct uniphier_aio_pll) * chip->num_plls);
+
+	for (i = 0; i < chip->num_aios; i++) {
+		struct uniphier_aio *aio = &chip->aios[i];
+
+		aio->chip = chip;
+		aio->fmt = SND_SOC_DAIFMT_I2S;
+
+		for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
+			struct uniphier_aio_sub *sub = &aio->sub[j];
+
+			sub->aio = aio;
+			spin_lock_init(&sub->lock);
+		}
+	}
+
+	chip->pdev = pdev;
+	platform_set_drvdata(pdev, chip);
+
+	ret = clk_prepare_enable(chip->clk);
+	if (ret)
+		return ret;
+
+	ret = reset_control_deassert(chip->rst);
+	if (ret)
+		goto err_out_clock;
+
+	ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
+					      chip->chip_spec->dais,
+					      chip->chip_spec->num_dais);
+	if (ret) {
+		dev_err(dev, "Register component failed.\n");
+		goto err_out_reset;
+	}
+
+	ret = uniphier_aiodma_soc_register_platform(pdev);
+	if (ret) {
+		dev_err(dev, "Register platform failed.\n");
+		goto err_out_reset;
+	}
+
+	return 0;
+
+err_out_reset:
+	reset_control_assert(chip->rst);
+
+err_out_clock:
+	clk_disable_unprepare(chip->clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uniphier_aio_probe);
+
+int uniphier_aio_remove(struct platform_device *pdev)
+{
+	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
+
+	reset_control_assert(chip->rst);
+	clk_disable_unprepare(chip->clk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(uniphier_aio_remove);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
new file mode 100644
index 000000000000..ef7bafa8e171
--- /dev/null
+++ b/sound/soc/uniphier/aio-dma.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier AIO DMA driver.
+//
+// Copyright (c) 2016-2018 Socionext Inc.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "aio.h"
+
+static struct snd_pcm_hardware uniphier_aiodma_hw = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_INTERLEAVED,
+	.period_bytes_min = 256,
+	.period_bytes_max = 4096,
+	.periods_min      = 4,
+	.periods_max      = 1024,
+	.buffer_bytes_max = 128 * 1024,
+};
+
+static void aiodma_pcm_irq(struct uniphier_aio_sub *sub)
+{
+	struct snd_pcm_runtime *runtime = sub->substream->runtime;
+	int bytes = runtime->period_size *
+		runtime->channels * samples_to_bytes(runtime, 1);
+	int ret;
+
+	spin_lock(&sub->lock);
+	ret = aiodma_rb_set_threshold(sub, runtime->dma_bytes,
+				      sub->threshold + bytes);
+	if (!ret)
+		sub->threshold += bytes;
+
+	aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
+	aiodma_rb_clear_irq(sub);
+	spin_unlock(&sub->lock);
+
+	snd_pcm_period_elapsed(sub->substream);
+}
+
+static void aiodma_compr_irq(struct uniphier_aio_sub *sub)
+{
+	struct snd_compr_runtime *runtime = sub->cstream->runtime;
+	int bytes = runtime->fragment_size;
+	int ret;
+
+	spin_lock(&sub->lock);
+	ret = aiodma_rb_set_threshold(sub, sub->compr_bytes,
+				      sub->threshold + bytes);
+	if (!ret)
+		sub->threshold += bytes;
+
+	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
+	aiodma_rb_clear_irq(sub);
+	spin_unlock(&sub->lock);
+
+	snd_compr_fragment_elapsed(sub->cstream);
+}
+
+static irqreturn_t aiodma_irq(int irq, void *p)
+{
+	struct platform_device *pdev = p;
+	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
+	irqreturn_t ret = IRQ_NONE;
+	int i, j;
+
+	for (i = 0; i < chip->num_aios; i++) {
+		struct uniphier_aio *aio = &chip->aios[i];
+
+		for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
+			struct uniphier_aio_sub *sub = &aio->sub[j];
+
+			/* Skip channel that does not trigger */
+			if (!sub->running || !aiodma_rb_is_irq(sub))
+				continue;
+
+			if (sub->substream)
+				aiodma_pcm_irq(sub);
+			if (sub->cstream)
+				aiodma_compr_irq(sub);
+
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	return ret;
+}
+
+static int uniphier_aiodma_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_soc_set_runtime_hwparams(substream, &uniphier_aiodma_hw);
+
+	return snd_pcm_hw_constraint_step(runtime, 0,
+		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256);
+}
+
+static int uniphier_aiodma_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	substream->runtime->dma_bytes = params_buffer_bytes(params);
+
+	return 0;
+}
+
+static int uniphier_aiodma_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	substream->runtime->dma_bytes = 0;
+
+	return 0;
+}
+
+static int uniphier_aiodma_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+	int bytes = runtime->period_size *
+		runtime->channels * samples_to_bytes(runtime, 1);
+	unsigned long flags;
+	int ret;
+
+	ret = aiodma_ch_set_param(sub);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&sub->lock, flags);
+	ret = aiodma_rb_set_buffer(sub, runtime->dma_addr,
+				   runtime->dma_addr + runtime->dma_bytes,
+				   bytes);
+	spin_unlock_irqrestore(&sub->lock, flags);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int uniphier_aiodma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+	struct device *dev = &aio->chip->pdev->dev;
+	int bytes = runtime->period_size *
+		runtime->channels * samples_to_bytes(runtime, 1);
+	unsigned long flags;
+
+	spin_lock_irqsave(&sub->lock, flags);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes,
+			       bytes);
+		aiodma_ch_set_enable(sub, 1);
+		sub->running = 1;
+
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		sub->running = 0;
+		aiodma_ch_set_enable(sub, 0);
+
+		break;
+	default:
+		dev_warn(dev, "Unknown trigger(%d) ignored\n", cmd);
+		break;
+	}
+	spin_unlock_irqrestore(&sub->lock, flags);
+
+	return 0;
+}
+
+static snd_pcm_uframes_t uniphier_aiodma_pointer(
+					struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
+	struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
+	int bytes = runtime->period_size *
+		runtime->channels * samples_to_bytes(runtime, 1);
+	unsigned long flags;
+	snd_pcm_uframes_t pos;
+
+	spin_lock_irqsave(&sub->lock, flags);
+	aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
+
+	if (sub->swm->dir == PORT_DIR_OUTPUT)
+		pos = bytes_to_frames(runtime, sub->rd_offs);
+	else
+		pos = bytes_to_frames(runtime, sub->wr_offs);
+	spin_unlock_irqrestore(&sub->lock, flags);
+
+	return pos;
+}
+
+static int uniphier_aiodma_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	return remap_pfn_range(vma, vma->vm_start,
+			       substream->dma_buffer.addr >> PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static const struct snd_pcm_ops uniphier_aiodma_ops = {
+	.open      = uniphier_aiodma_open,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.hw_params = uniphier_aiodma_hw_params,
+	.hw_free   = uniphier_aiodma_hw_free,
+	.prepare   = uniphier_aiodma_prepare,
+	.trigger   = uniphier_aiodma_trigger,
+	.pointer   = uniphier_aiodma_pointer,
+	.mmap      = uniphier_aiodma_mmap,
+};
+
+static int uniphier_aiodma_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct device *dev = rtd->card->snd_card->dev;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
+	if (ret)
+		return ret;
+
+	return snd_pcm_lib_preallocate_pages_for_all(pcm,
+		SNDRV_DMA_TYPE_DEV, dev,
+		uniphier_aiodma_hw.buffer_bytes_max,
+		uniphier_aiodma_hw.buffer_bytes_max);
+}
+
+static void uniphier_aiodma_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static const struct snd_soc_component_driver uniphier_soc_platform = {
+	.pcm_new   = uniphier_aiodma_new,
+	.pcm_free  = uniphier_aiodma_free,
+	.ops       = &uniphier_aiodma_ops,
+	.compr_ops = &uniphier_aio_compr_ops,
+};
+
+static const struct regmap_config aiodma_regmap_config = {
+	.reg_bits      = 32,
+	.reg_stride    = 4,
+	.val_bits      = 32,
+	.max_register  = 0x7fffc,
+	.cache_type    = REGCACHE_NONE,
+};
+
+/**
+ * uniphier_aiodma_soc_register_platform - register the AIO DMA
+ * @pdev: the platform device
+ *
+ * Register and setup the DMA of AIO to transfer the sound data to device.
+ * This function need to call once at driver startup and need NOT to call
+ * unregister function.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+int uniphier_aiodma_soc_register_platform(struct platform_device *pdev)
+{
+	struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	void __iomem *preg;
+	int irq, ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	preg = devm_ioremap_resource(dev, res);
+	if (IS_ERR(preg))
+		return PTR_ERR(preg);
+
+	chip->regmap = devm_regmap_init_mmio(dev, preg,
+					     &aiodma_regmap_config);
+	if (IS_ERR(chip->regmap))
+		return PTR_ERR(chip->regmap);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "Could not get irq.\n");
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, aiodma_irq,
+			       IRQF_SHARED, dev_name(dev), pdev);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_component(dev, &uniphier_soc_platform,
+					       NULL, 0);
+}
+EXPORT_SYMBOL_GPL(uniphier_aiodma_soc_register_platform);
diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c
new file mode 100644
index 000000000000..8e40e6c2e42f
--- /dev/null
+++ b/sound/soc/uniphier/aio-ld11.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext UniPhier AIO ALSA driver for LD11/LD20.
+//
+// Copyright (c) 2016-2018 Socionext Inc.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include <linux/module.h>
+
+#include "aio.h"
+
+static const struct uniphier_aio_spec uniphier_aio_ld11[] = {
+	/* for HDMI PCM In, Pin:AI1Dx */
+	{
+		.name = AUD_NAME_PCMIN1,
+		.gname = AUD_GNAME_HDMI,
+		.swm = {
+			.type  = PORT_TYPE_I2S,
+			.dir   = PORT_DIR_INPUT,
+			.rb    = { 21, 14, },
+			.ch    = { 21, 14, },
+			.iif   = { 5, 3, },
+			.iport = { 0, AUD_HW_PCMIN1, },
+		},
+	},
+
+	/* for SIF In, Pin:AI2Dx */
+	{
+		.name = AUD_NAME_PCMIN2,
+		.swm = {
+			.type  = PORT_TYPE_I2S,
+			.dir   = PORT_DIR_INPUT,
+			.rb    = { 22, 15, },
+			.ch    = { 22, 15, },
+			.iif   = { 6, 4, },
+			.iport = { 1, AUD_HW_PCMIN2, },
+		},
+	},
+
+	/* for Line In, Pin:AI3Dx */
+	{
+		.name = AUD_NAME_PCMIN3,
+		.gname = AUD_GNAME_LINE,
+		.swm = {
+			.type  = PORT_TYPE_EVE,
+			.dir   = PORT_DIR_INPUT,
+			.rb    = { 23, 16, },
+			.ch    = { 23, 16, },
+			.iif   = { 7, 5, },
+			.iport = { 2, AUD_HW_PCMIN3, },
+		},
+	},
+
+	/* for S/PDIF In, Pin:AI1IEC */
+	{
+		.name = AUD_NAME_IECIN1,
+		.gname = AUD_GNAME_IEC,
+		.swm = {
+			.type  = PORT_TYPE_SPDIF,
+			.dir   = PORT_DIR_INPUT,
+			.rb    = { 26, 17, },
+			.ch    = { 26, 17, },
+			.iif   = { 10, 6, },
+			.iport = { 3, AUD_HW_IECIN1, },
+		},
+	},
+
+	/* for Speaker, Pin:AO1Dx */
+	{
+		.name = AUD_NAME_HPCMOUT1,
+		.swm = {
+			.type  = PORT_TYPE_I2S,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 0, 0, },
+			.ch    = { 0, 0, },
+			.oif   = { 0, 0, },
+			.oport = { 0, AUD_HW_HPCMOUT1, },
+		},
+	},
+
+	/* for HDMI PCM, Pin:AO2Dx */
+	{
+		.name = AUD_NAME_PCMOUT1,
+		.gname = AUD_GNAME_HDMI,
+		.swm = {
+			.type  = PORT_TYPE_I2S,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 0, 0, },
+			.ch    = { 0, 0, },
+			.oif   = { 0, 0, },
+			.oport = { 3, AUD_HW_PCMOUT1, },
+		},
+	},
+
+	/* for Line Out, Pin:LO2_x */
+	{
+		.name = AUD_NAME_PCMOUT2,
+		.gname = AUD_GNAME_LINE,
+		.swm = {
+			.type  = PORT_TYPE_EVE,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 2, 2, },
+			.ch    = { 2, 2, },
+			.oif   = { 2, 2, },
+			.oport = { 1, AUD_HW_PCMOUT2, },
+		},
+	},
+
+	/* for Headphone, Pin:HP1_x */
+	{
+		.name = AUD_NAME_PCMOUT3,
+		.swm = {
+			.type  = PORT_TYPE_EVE,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 3, 3, },
+			.ch    = { 3, 3, },
+			.oif   = { 3, 3, },
+			.oport = { 2, AUD_HW_PCMOUT3, },
+		},
+	},
+
+	/* for HW Sampling Rate Converter */
+	{
+		.name = AUD_NAME_EPCMOUT2,
+		.swm = {
+			.type  = PORT_TYPE_CONV,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 7, 5, },
+			.ch    = { 7, 5, },
+			.oif   = { 7, 5, },
+			.oport = { 6, AUD_HW_EPCMOUT2, },
+			.och   = { 17, 12, },
+			.iif   = { 1, 1, },
+		},
+	},
+
+	/* for HW Sampling Rate Converter 2 */
+	{
+		.name = AUD_NAME_EPCMOUT3,
+		.swm = {
+			.type  = PORT_TYPE_CONV,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 8, 6, },
+			.ch    = { 8, 6, },
+			.oif   = { 8, 6, },
+			.oport = { 7, AUD_HW_EPCMOUT3, },
+			.och   = { 18, 13, },
+			.iif   = { 2, 2, },
+		},
+	},
+
+	/* for S/PDIF Out, Pin:AO1IEC */
+	{
+		.name = AUD_NAME_HIECOUT1,
+		.gname = AUD_GNAME_IEC,
+		.swm = {
+			.type  = PORT_TYPE_SPDIF,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 1, 1, },
+			.ch    = { 1, 1, },
+			.oif   = { 1, 1, },
+			.oport = { 12, AUD_HW_HIECOUT1, },
+		},
+	},
+
+	/* for S/PDIF Out, Pin:AO1IEC, Compress */
+	{
+		.name = AUD_NAME_HIECCOMPOUT1,
+		.gname = AUD_GNAME_IEC,
+		.swm = {
+			.type  = PORT_TYPE_SPDIF,
+			.dir   = PORT_DIR_OUTPUT,
+			.rb    = { 1, 1, },
+			.ch    = { 1, 1, },
+			.oif   = { 1, 1, },
+			.oport = { 12, AUD_HW_HIECOUT1, },
+		},
+	},
+};
+
+static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = {
+	[AUD_PLL_A1]   = { .enable = true, },
+	[AUD_PLL_F1]   = { .enable = true, },
+	[AUD_PLL_A2]   = { .enable = true, },
+	[AUD_PLL_F2]   = { .enable = true, },
+	[AUD_PLL_APLL] = { .enable = true, },
+	[AUD_PLL_RX0]  = { .enable = true, },
+	[AUD_PLL_USB0] = { .enable = true, },
+	[AUD_PLL_HSC0] = { .enable = true, },
+};
+
+static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
+{
+	int ret;
+
+	ret = uniphier_aio_dai_probe(dai);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
+	if (ret < 0)
+		return ret;
+	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
+	if (ret < 0)
+		return ret;
+	ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
+	{
+		.name    = AUD_GNAME_HDMI,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_PCMOUT1,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.capture = {
+			.stream_name = AUD_NAME_PCMIN1,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_32000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_NAME_PCMIN2,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.capture = {
+			.stream_name = AUD_NAME_PCMIN2,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_GNAME_LINE,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_PCMOUT2,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.capture = {
+			.stream_name = AUD_NAME_PCMIN3,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_NAME_HPCMOUT1,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_HPCMOUT1,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_NAME_PCMOUT3,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_PCMOUT3,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_NAME_HIECOUT1,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_HIECOUT1,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_spdif_ops,
+	},
+	{
+		.name    = AUD_NAME_EPCMOUT2,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_EPCMOUT2,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_32000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_NAME_EPCMOUT3,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.playback = {
+			.stream_name = AUD_NAME_EPCMOUT3,
+			.formats     = SNDRV_PCM_FMTBIT_S32_LE,
+			.rates       = SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_32000,
+			.channels_min = 2,
+			.channels_max = 2,
+		},
+		.ops = &uniphier_aio_i2s_ops,
+	},
+	{
+		.name    = AUD_NAME_HIECCOMPOUT1,
+		.probe   = uniphier_aio_ld11_probe,
+		.remove  = uniphier_aio_dai_remove,
+		.suspend = uniphier_aio_dai_suspend,
+		.resume  = uniphier_aio_dai_resume,
+		.compress_new = snd_soc_new_compress,
+		.playback = {
+			.stream_name = AUD_NAME_HIECCOMPOUT1,
+			.channels_min = 1,
+			.channels_max = 1,
+		},
+		.ops = &uniphier_aio_spdif_ops,
+	},
+};
+
+static const struct uniphier_aio_chip_spec uniphier_aio_ld11_spec = {
+	.specs     = uniphier_aio_ld11,
+	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
+	.dais      = uniphier_aio_dai_ld11,
+	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
+	.plls      = uniphier_aio_pll_ld11,
+	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
+	.addr_ext  = 0,
+};
+
+static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
+	.specs     = uniphier_aio_ld11,
+	.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
+	.dais      = uniphier_aio_dai_ld11,
+	.num_dais  = ARRAY_SIZE(uniphier_aio_dai_ld11),
+	.plls      = uniphier_aio_pll_ld11,
+	.num_plls  = ARRAY_SIZE(uniphier_aio_pll_ld11),
+	.addr_ext  = 1,
+};
+
+static const struct of_device_id uniphier_aio_of_match[] = {
+	{
+		.compatible = "socionext,uniphier-ld11-aio",
+		.data = &uniphier_aio_ld11_spec,
+	},
+	{
+		.compatible = "socionext,uniphier-ld20-aio",
+		.data = &uniphier_aio_ld20_spec,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
+
+static struct platform_driver uniphier_aio_driver = {
+	.driver = {
+		.name = "snd-uniphier-aio",
+		.of_match_table = of_match_ptr(uniphier_aio_of_match),
+	},
+	.probe    = uniphier_aio_probe,
+	.remove   = uniphier_aio_remove,
+};
+module_platform_driver(uniphier_aio_driver);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/uniphier/aio-reg.h b/sound/soc/uniphier/aio-reg.h
new file mode 100644
index 000000000000..eaf2c65acf14
--- /dev/null
+++ b/sound/soc/uniphier/aio-reg.h
@@ -0,0 +1,462 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Socionext UniPhier AIO ALSA driver.
+ *
+ * Copyright (c) 2016-2018 Socionext Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SND_UNIPHIER_AIO_REG_H__
+#define SND_UNIPHIER_AIO_REG_H__
+
+#include <linux/bitops.h>
+
+/* SW view */
+#define A2CHNMAPCTR0(n)                 (0x00000 + 0x40 * (n))
+#define A2RBNMAPCTR0(n)                 (0x01000 + 0x40 * (n))
+#define A2IPORTNMAPCTR0(n)              (0x02000 + 0x40 * (n))
+#define A2IPORTNMAPCTR1(n)              (0x02004 + 0x40 * (n))
+#define A2IIFNMAPCTR0(n)                (0x03000 + 0x40 * (n))
+#define A2OPORTNMAPCTR0(n)              (0x04000 + 0x40 * (n))
+#define A2OPORTNMAPCTR1(n)              (0x04004 + 0x40 * (n))
+#define A2OPORTNMAPCTR2(n)              (0x04008 + 0x40 * (n))
+#define A2OIFNMAPCTR0(n)                (0x05000 + 0x40 * (n))
+#define A2ATNMAPCTR0(n)                 (0x06000 + 0x40 * (n))
+
+#define MAPCTR0_EN                      0x80000000
+
+/* CTL */
+#define A2APLLCTR0                      0x07000
+#define   A2APLLCTR0_APLLXPOW_MASK        GENMASK(3, 0)
+#define   A2APLLCTR0_APLLXPOW_PWOFF       (0x0 << 0)
+#define   A2APLLCTR0_APLLXPOW_PWON        (0xf << 0)
+#define A2APLLCTR1                      0x07004
+#define   A2APLLCTR1_APLLX_MASK           0x00010101
+#define   A2APLLCTR1_APLLX_36MHZ          0x00000000
+#define   A2APLLCTR1_APLLX_33MHZ          0x00000001
+#define A2EXMCLKSEL0                    0x07030
+#define   A2EXMCLKSEL0_EXMCLK_MASK        GENMASK(2, 0)
+#define   A2EXMCLKSEL0_EXMCLK_OUTPUT      (0x0 << 0)
+#define   A2EXMCLKSEL0_EXMCLK_INPUT       (0x7 << 0)
+#define A2SSIFSW                        0x07050
+#define A2CH22_2CTR                     0x07054
+#define A2AIOINPUTSEL                   0x070e0
+#define   A2AIOINPUTSEL_RXSEL_PCMI1_MASK      GENMASK(2, 0)
+#define   A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1   (0x2 << 0)
+#define   A2AIOINPUTSEL_RXSEL_PCMI2_MASK      GENMASK(6, 4)
+#define   A2AIOINPUTSEL_RXSEL_PCMI2_SIF       (0x7 << 4)
+#define   A2AIOINPUTSEL_RXSEL_PCMI3_MASK      GENMASK(10, 8)
+#define   A2AIOINPUTSEL_RXSEL_PCMI3_EVEA      (0x1 << 8)
+#define   A2AIOINPUTSEL_RXSEL_IECI1_MASK      GENMASK(14, 12)
+#define   A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1   (0x2 << 12)
+#define   A2AIOINPUTSEL_RXSEL_MASK        (A2AIOINPUTSEL_RXSEL_PCMI1_MASK | \
+					   A2AIOINPUTSEL_RXSEL_PCMI2_MASK | \
+					   A2AIOINPUTSEL_RXSEL_PCMI3_MASK | \
+					   A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1)
+
+/* INTC */
+#define INTCHIM(m)                       (0x9028 + 0x80 * (m))
+#define INTRBIM(m)                       (0x9030 + 0x80 * (m))
+#define INTCHID(m)                       (0xa028 + 0x80 * (m))
+#define INTRBID(m)                       (0xa030 + 0x80 * (m))
+
+/* AIN(PCMINN) */
+#define IPORTMXCTR1(n)                   (0x22000 + 0x400 * (n))
+#define   IPORTMXCTR1_LRSEL_MASK           GENMASK(11, 10)
+#define   IPORTMXCTR1_LRSEL_RIGHT          (0x0 << 10)
+#define   IPORTMXCTR1_LRSEL_LEFT           (0x1 << 10)
+#define   IPORTMXCTR1_LRSEL_I2S            (0x2 << 10)
+#define   IPORTMXCTR1_OUTBITSEL_MASK       (0x800003U << 8)
+#define   IPORTMXCTR1_OUTBITSEL_32         (0x800000U << 8)
+#define   IPORTMXCTR1_OUTBITSEL_24         (0x000000U << 8)
+#define   IPORTMXCTR1_OUTBITSEL_20         (0x000001U << 8)
+#define   IPORTMXCTR1_OUTBITSEL_16         (0x000002U << 8)
+#define   IPORTMXCTR1_CHSEL_MASK           GENMASK(6, 4)
+#define   IPORTMXCTR1_CHSEL_ALL            (0x0 << 4)
+#define   IPORTMXCTR1_CHSEL_D0_D2          (0x1 << 4)
+#define   IPORTMXCTR1_CHSEL_D0             (0x2 << 4)
+#define   IPORTMXCTR1_CHSEL_D1             (0x3 << 4)
+#define   IPORTMXCTR1_CHSEL_D2             (0x4 << 4)
+#define   IPORTMXCTR1_CHSEL_DMIX           (0x5 << 4)
+#define   IPORTMXCTR1_FSSEL_MASK           GENMASK(3, 0)
+#define   IPORTMXCTR1_FSSEL_48             (0x0 << 0)
+#define   IPORTMXCTR1_FSSEL_96             (0x1 << 0)
+#define   IPORTMXCTR1_FSSEL_192            (0x2 << 0)
+#define   IPORTMXCTR1_FSSEL_32             (0x3 << 0)
+#define   IPORTMXCTR1_FSSEL_44_1           (0x4 << 0)
+#define   IPORTMXCTR1_FSSEL_88_2           (0x5 << 0)
+#define   IPORTMXCTR1_FSSEL_176_4          (0x6 << 0)
+#define   IPORTMXCTR1_FSSEL_16             (0x8 << 0)
+#define   IPORTMXCTR1_FSSEL_22_05          (0x9 << 0)
+#define   IPORTMXCTR1_FSSEL_24             (0xa << 0)
+#define   IPORTMXCTR1_FSSEL_8              (0xb << 0)
+#define   IPORTMXCTR1_FSSEL_11_025         (0xc << 0)
+#define   IPORTMXCTR1_FSSEL_12             (0xd << 0)
+#define IPORTMXCTR2(n)                   (0x22004 + 0x400 * (n))
+#define   IPORTMXCTR2_ACLKSEL_MASK         GENMASK(19, 16)
+#define   IPORTMXCTR2_ACLKSEL_A1           (0x0 << 16)
+#define   IPORTMXCTR2_ACLKSEL_F1           (0x1 << 16)
+#define   IPORTMXCTR2_ACLKSEL_A2           (0x2 << 16)
+#define   IPORTMXCTR2_ACLKSEL_F2           (0x3 << 16)
+#define   IPORTMXCTR2_ACLKSEL_A2PLL        (0x4 << 16)
+#define   IPORTMXCTR2_ACLKSEL_RX1          (0x5 << 16)
+#define   IPORTMXCTR2_ACLKSEL_RX2          (0x6 << 16)
+#define   IPORTMXCTR2_MSSEL_MASK           BIT(15)
+#define   IPORTMXCTR2_MSSEL_SLAVE          (0x0 << 15)
+#define   IPORTMXCTR2_MSSEL_MASTER         (0x1 << 15)
+#define   IPORTMXCTR2_EXTLSIFSSEL_MASK     BIT(14)
+#define   IPORTMXCTR2_EXTLSIFSSEL_36       (0x0 << 14)
+#define   IPORTMXCTR2_EXTLSIFSSEL_24       (0x1 << 14)
+#define   IPORTMXCTR2_DACCKSEL_MASK        GENMASK(9, 8)
+#define   IPORTMXCTR2_DACCKSEL_1_2         (0x0 << 8)
+#define   IPORTMXCTR2_DACCKSEL_1_3         (0x1 << 8)
+#define   IPORTMXCTR2_DACCKSEL_1_1         (0x2 << 8)
+#define   IPORTMXCTR2_DACCKSEL_2_3         (0x3 << 8)
+#define   IPORTMXCTR2_REQEN_MASK           BIT(0)
+#define   IPORTMXCTR2_REQEN_DISABLE        (0x0 << 0)
+#define   IPORTMXCTR2_REQEN_ENABLE         (0x1 << 0)
+#define IPORTMXCNTCTR(n)                 (0x22010 + 0x400 * (n))
+#define IPORTMXCOUNTER(n)                (0x22014 + 0x400 * (n))
+#define IPORTMXCNTMONI(n)                (0x22018 + 0x400 * (n))
+#define IPORTMXACLKSEL0EX(n)             (0x22020 + 0x400 * (n))
+#define   IPORTMXACLKSEL0EX_ACLKSEL0EX_MASK        GENMASK(3, 0)
+#define   IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL    (0x0 << 0)
+#define   IPORTMXACLKSEL0EX_ACLKSEL0EX_EXTERNAL    (0xf << 0)
+#define IPORTMXEXNOE(n)                  (0x22070 + 0x400 * (n))
+#define   IPORTMXEXNOE_PCMINOE_MASK        BIT(0)
+#define   IPORTMXEXNOE_PCMINOE_OUTPUT      (0x0 << 0)
+#define   IPORTMXEXNOE_PCMINOE_INPUT       (0x1 << 0)
+#define IPORTMXMASK(n)                   (0x22078 + 0x400 * (n))
+#define   IPORTMXMASK_IUXCKMSK_MASK        GENMASK(18, 16)
+#define   IPORTMXMASK_IUXCKMSK_ON          (0x0 << 16)
+#define   IPORTMXMASK_IUXCKMSK_OFF         (0x7 << 16)
+#define   IPORTMXMASK_XCKMSK_MASK          GENMASK(2, 0)
+#define   IPORTMXMASK_XCKMSK_ON            (0x0 << 0)
+#define   IPORTMXMASK_XCKMSK_OFF           (0x7 << 0)
+#define IPORTMXRSTCTR(n)                 (0x2207c + 0x400 * (n))
+#define   IPORTMXRSTCTR_RSTPI_MASK         BIT(7)
+#define   IPORTMXRSTCTR_RSTPI_RELEASE      (0x0 << 7)
+#define   IPORTMXRSTCTR_RSTPI_RESET        (0x1 << 7)
+
+/* AIN(PBinMX) */
+#define PBINMXCTR(n)                     (0x20200 + 0x40 * (n))
+#define   PBINMXCTR_NCONNECT_MASK          BIT(15)
+#define   PBINMXCTR_NCONNECT_CONNECT       (0x0 << 15)
+#define   PBINMXCTR_NCONNECT_DISCONNECT    (0x1 << 15)
+#define   PBINMXCTR_INOUTSEL_MASK          BIT(14)
+#define   PBINMXCTR_INOUTSEL_IN            (0x0 << 14)
+#define   PBINMXCTR_INOUTSEL_OUT           (0x1 << 14)
+#define   PBINMXCTR_PBINSEL_SHIFT          (8)
+#define   PBINMXCTR_ENDIAN_MASK            GENMASK(5, 4)
+#define   PBINMXCTR_ENDIAN_3210            (0x0 << 4)
+#define   PBINMXCTR_ENDIAN_0123            (0x1 << 4)
+#define   PBINMXCTR_ENDIAN_1032            (0x2 << 4)
+#define   PBINMXCTR_ENDIAN_2301            (0x3 << 4)
+#define   PBINMXCTR_MEMFMT_MASK            GENMASK(3, 0)
+#define   PBINMXCTR_MEMFMT_D0              (0x0 << 0)
+#define   PBINMXCTR_MEMFMT_5_1CH_DMIX      (0x1 << 0)
+#define   PBINMXCTR_MEMFMT_6CH             (0x2 << 0)
+#define   PBINMXCTR_MEMFMT_4CH             (0x3 << 0)
+#define   PBINMXCTR_MEMFMT_DMIX            (0x4 << 0)
+#define   PBINMXCTR_MEMFMT_1CH             (0x5 << 0)
+#define   PBINMXCTR_MEMFMT_16LR            (0x6 << 0)
+#define   PBINMXCTR_MEMFMT_7_1CH           (0x7 << 0)
+#define   PBINMXCTR_MEMFMT_7_1CH_DMIX      (0x8 << 0)
+#define   PBINMXCTR_MEMFMT_STREAM          (0xf << 0)
+#define PBINMXPAUSECTR0(n)               (0x20204 + 0x40 * (n))
+#define PBINMXPAUSECTR1(n)               (0x20208 + 0x40 * (n))
+
+/* AOUT */
+#define AOUTENCTR0                       0x40040
+#define AOUTENCTR1                       0x40044
+#define AOUTENCTR2                       0x40048
+#define AOUTRSTCTR0                      0x40060
+#define AOUTRSTCTR1                      0x40064
+#define AOUTRSTCTR2                      0x40068
+#define AOUTSRCRSTCTR0                   0x400c0
+#define AOUTSRCRSTCTR1                   0x400c4
+#define AOUTSRCRSTCTR2                   0x400c8
+
+/* AOUT(PCMOUTN) */
+#define OPORTMXCTR1(n)                   (0x42000 + 0x400 * (n))
+#define   OPORTMXCTR1_I2SLRSEL_MASK        (0x11 << 10)
+#define   OPORTMXCTR1_I2SLRSEL_RIGHT       (0x00 << 10)
+#define   OPORTMXCTR1_I2SLRSEL_LEFT        (0x01 << 10)
+#define   OPORTMXCTR1_I2SLRSEL_I2S         (0x11 << 10)
+#define   OPORTMXCTR1_OUTBITSEL_MASK       (0x800003U << 8)
+#define   OPORTMXCTR1_OUTBITSEL_32         (0x800000U << 8)
+#define   OPORTMXCTR1_OUTBITSEL_24         (0x000000U << 8)
+#define   OPORTMXCTR1_OUTBITSEL_20         (0x000001U << 8)
+#define   OPORTMXCTR1_OUTBITSEL_16         (0x000002U << 8)
+#define   OPORTMXCTR1_FSSEL_MASK           GENMASK(3, 0)
+#define   OPORTMXCTR1_FSSEL_48             (0x0 << 0)
+#define   OPORTMXCTR1_FSSEL_96             (0x1 << 0)
+#define   OPORTMXCTR1_FSSEL_192            (0x2 << 0)
+#define   OPORTMXCTR1_FSSEL_32             (0x3 << 0)
+#define   OPORTMXCTR1_FSSEL_44_1           (0x4 << 0)
+#define   OPORTMXCTR1_FSSEL_88_2           (0x5 << 0)
+#define   OPORTMXCTR1_FSSEL_176_4          (0x6 << 0)
+#define   OPORTMXCTR1_FSSEL_16             (0x8 << 0)
+#define   OPORTMXCTR1_FSSEL_22_05          (0x9 << 0)
+#define   OPORTMXCTR1_FSSEL_24             (0xa << 0)
+#define   OPORTMXCTR1_FSSEL_8              (0xb << 0)
+#define   OPORTMXCTR1_FSSEL_11_025         (0xc << 0)
+#define   OPORTMXCTR1_FSSEL_12             (0xd << 0)
+#define OPORTMXCTR2(n)                   (0x42004 + 0x400 * (n))
+#define   OPORTMXCTR2_ACLKSEL_MASK         GENMASK(19, 16)
+#define   OPORTMXCTR2_ACLKSEL_A1           (0x0 << 16)
+#define   OPORTMXCTR2_ACLKSEL_F1           (0x1 << 16)
+#define   OPORTMXCTR2_ACLKSEL_A2           (0x2 << 16)
+#define   OPORTMXCTR2_ACLKSEL_F2           (0x3 << 16)
+#define   OPORTMXCTR2_ACLKSEL_A2PLL        (0x4 << 16)
+#define   OPORTMXCTR2_ACLKSEL_RX1          (0x5 << 16)
+#define   OPORTMXCTR2_ACLKSEL_RX2          (0x6 << 16)
+#define   OPORTMXCTR2_MSSEL_MASK           BIT(15)
+#define   OPORTMXCTR2_MSSEL_SLAVE          (0x0 << 15)
+#define   OPORTMXCTR2_MSSEL_MASTER         (0x1 << 15)
+#define   OPORTMXCTR2_EXTLSIFSSEL_MASK     BIT(14)
+#define   OPORTMXCTR2_EXTLSIFSSEL_36       (0x0 << 14)
+#define   OPORTMXCTR2_EXTLSIFSSEL_24       (0x1 << 14)
+#define   OPORTMXCTR2_DACCKSEL_MASK        GENMASK(9, 8)
+#define   OPORTMXCTR2_DACCKSEL_1_2         (0x0 << 8)
+#define   OPORTMXCTR2_DACCKSEL_1_3         (0x1 << 8)
+#define   OPORTMXCTR2_DACCKSEL_1_1         (0x2 << 8)
+#define   OPORTMXCTR2_DACCKSEL_2_3         (0x3 << 8)
+#define OPORTMXCTR3(n)                   (0x42008 + 0x400 * (n))
+#define   OPORTMXCTR3_IECTHUR_MASK         BIT(19)
+#define   OPORTMXCTR3_IECTHUR_IECOUT       (0x0 << 19)
+#define   OPORTMXCTR3_IECTHUR_IECIN        (0x1 << 19)
+#define   OPORTMXCTR3_SRCSEL_MASK          GENMASK(18, 16)
+#define   OPORTMXCTR3_SRCSEL_PCM           (0x0 << 16)
+#define   OPORTMXCTR3_SRCSEL_STREAM        (0x1 << 16)
+#define   OPORTMXCTR3_SRCSEL_CDDTS         (0x2 << 16)
+#define   OPORTMXCTR3_VALID_MASK           BIT(12)
+#define   OPORTMXCTR3_VALID_PCM            (0x0 << 12)
+#define   OPORTMXCTR3_VALID_STREAM         (0x1 << 12)
+#define   OPORTMXCTR3_PMSEL_MASK           BIT(3)
+#define   OPORTMXCTR3_PMSEL_MUTE           (0x0 << 3)
+#define   OPORTMXCTR3_PMSEL_PAUSE          (0x1 << 3)
+#define   OPORTMXCTR3_PMSW_MASK            BIT(2)
+#define   OPORTMXCTR3_PMSW_MUTE_OFF        (0x0 << 2)
+#define   OPORTMXCTR3_PMSW_MUTE_ON         (0x1 << 2)
+#define OPORTMXSRC1CTR(n)                (0x4200c + 0x400 * (n))
+#define   OPORTMXSRC1CTR_FSIIPNUM_SHIFT    (24)
+#define   OPORTMXSRC1CTR_THMODE_MASK       BIT(23)
+#define   OPORTMXSRC1CTR_THMODE_SRC        (0x0 << 23)
+#define   OPORTMXSRC1CTR_THMODE_BYPASS     (0x1 << 23)
+#define   OPORTMXSRC1CTR_LOCK_MASK         BIT(16)
+#define   OPORTMXSRC1CTR_LOCK_UNLOCK       (0x0 << 16)
+#define   OPORTMXSRC1CTR_LOCK_LOCK         (0x1 << 16)
+#define   OPORTMXSRC1CTR_SRCPATH_MASK      BIT(15)
+#define   OPORTMXSRC1CTR_SRCPATH_BYPASS    (0x0 << 15)
+#define   OPORTMXSRC1CTR_SRCPATH_CALC      (0x1 << 15)
+#define   OPORTMXSRC1CTR_SYNC_MASK         BIT(14)
+#define   OPORTMXSRC1CTR_SYNC_ASYNC        (0x0 << 14)
+#define   OPORTMXSRC1CTR_SYNC_SYNC         (0x1 << 14)
+#define   OPORTMXSRC1CTR_FSOCK_MASK        GENMASK(11, 10)
+#define   OPORTMXSRC1CTR_FSOCK_44_1        (0x0 << 10)
+#define   OPORTMXSRC1CTR_FSOCK_48          (0x1 << 10)
+#define   OPORTMXSRC1CTR_FSOCK_32          (0x2 << 10)
+#define   OPORTMXSRC1CTR_FSICK_MASK        GENMASK(9, 8)
+#define   OPORTMXSRC1CTR_FSICK_44_1        (0x0 << 8)
+#define   OPORTMXSRC1CTR_FSICK_48          (0x1 << 8)
+#define   OPORTMXSRC1CTR_FSICK_32          (0x2 << 8)
+#define   OPORTMXSRC1CTR_FSIIPSEL_MASK     GENMASK(5, 4)
+#define   OPORTMXSRC1CTR_FSIIPSEL_INNER    (0x0 << 4)
+#define   OPORTMXSRC1CTR_FSIIPSEL_OUTER    (0x1 << 4)
+#define   OPORTMXSRC1CTR_FSISEL_MASK       GENMASK(3, 0)
+#define   OPORTMXSRC1CTR_FSISEL_ACLK       (0x0 << 0)
+#define   OPORTMXSRC1CTR_FSISEL_DD         (0x1 << 0)
+#define OPORTMXDSDMUTEDAT(n)             (0x42020 + 0x400 * (n))
+#define OPORTMXDXDFREQMODE(n)            (0x42024 + 0x400 * (n))
+#define OPORTMXDSDSEL(n)                 (0x42028 + 0x400 * (n))
+#define OPORTMXDSDPORT(n)                (0x4202c + 0x400 * (n))
+#define OPORTMXACLKSEL0EX(n)             (0x42030 + 0x400 * (n))
+#define OPORTMXPATH(n)                   (0x42040 + 0x400 * (n))
+#define OPORTMXSYNC(n)                   (0x42044 + 0x400 * (n))
+#define OPORTMXREPET(n)                  (0x42050 + 0x400 * (n))
+#define   OPORTMXREPET_STRLENGTH_AC3       SBF_(IEC61937_FRM_STR_AC3, 16)
+#define   OPORTMXREPET_STRLENGTH_MPA       SBF_(IEC61937_FRM_STR_MPA, 16)
+#define   OPORTMXREPET_STRLENGTH_MP3       SBF_(IEC61937_FRM_STR_MP3, 16)
+#define   OPORTMXREPET_STRLENGTH_DTS1      SBF_(IEC61937_FRM_STR_DTS1, 16)
+#define   OPORTMXREPET_STRLENGTH_DTS2      SBF_(IEC61937_FRM_STR_DTS2, 16)
+#define   OPORTMXREPET_STRLENGTH_DTS3      SBF_(IEC61937_FRM_STR_DTS3, 16)
+#define   OPORTMXREPET_STRLENGTH_AAC       SBF_(IEC61937_FRM_STR_AAC, 16)
+#define   OPORTMXREPET_PMLENGTH_AC3        SBF_(IEC61937_FRM_PAU_AC3, 0)
+#define   OPORTMXREPET_PMLENGTH_MPA        SBF_(IEC61937_FRM_PAU_MPA, 0)
+#define   OPORTMXREPET_PMLENGTH_MP3        SBF_(IEC61937_FRM_PAU_MP3, 0)
+#define   OPORTMXREPET_PMLENGTH_DTS1       SBF_(IEC61937_FRM_PAU_DTS1, 0)
+#define   OPORTMXREPET_PMLENGTH_DTS2       SBF_(IEC61937_FRM_PAU_DTS2, 0)
+#define   OPORTMXREPET_PMLENGTH_DTS3       SBF_(IEC61937_FRM_PAU_DTS3, 0)
+#define   OPORTMXREPET_PMLENGTH_AAC        SBF_(IEC61937_FRM_PAU_AAC, 0)
+#define OPORTMXPAUDAT(n)                 (0x42054 + 0x400 * (n))
+#define   OPORTMXPAUDAT_PAUSEPC_CMN        (IEC61937_PC_PAUSE << 16)
+#define   OPORTMXPAUDAT_PAUSEPD_AC3        (IEC61937_FRM_PAU_AC3 * 4)
+#define   OPORTMXPAUDAT_PAUSEPD_MPA        (IEC61937_FRM_PAU_MPA * 4)
+#define   OPORTMXPAUDAT_PAUSEPD_MP3        (IEC61937_FRM_PAU_MP3 * 4)
+#define   OPORTMXPAUDAT_PAUSEPD_DTS1       (IEC61937_FRM_PAU_DTS1 * 4)
+#define   OPORTMXPAUDAT_PAUSEPD_DTS2       (IEC61937_FRM_PAU_DTS2 * 4)
+#define   OPORTMXPAUDAT_PAUSEPD_DTS3       (IEC61937_FRM_PAU_DTS3 * 4)
+#define   OPORTMXPAUDAT_PAUSEPD_AAC        (IEC61937_FRM_PAU_AAC * 4)
+#define OPORTMXRATE_I(n)                 (0x420e4 + 0x400 * (n))
+#define   OPORTMXRATE_I_EQU_MASK           BIT(31)
+#define   OPORTMXRATE_I_EQU_NOTEQUAL       (0x0 << 31)
+#define   OPORTMXRATE_I_EQU_EQUAL          (0x1 << 31)
+#define   OPORTMXRATE_I_SRCBPMD_MASK       BIT(29)
+#define   OPORTMXRATE_I_SRCBPMD_BYPASS     (0x0 << 29)
+#define   OPORTMXRATE_I_SRCBPMD_SRC        (0x1 << 29)
+#define   OPORTMXRATE_I_LRCKSTP_MASK       BIT(24)
+#define   OPORTMXRATE_I_LRCKSTP_START      (0x0 << 24)
+#define   OPORTMXRATE_I_LRCKSTP_STOP       (0x1 << 24)
+#define   OPORTMXRATE_I_ACLKSRC_MASK       GENMASK(15, 12)
+#define   OPORTMXRATE_I_ACLKSRC_APLL       (0x0 << 12)
+#define   OPORTMXRATE_I_ACLKSRC_USB        (0x1 << 12)
+#define   OPORTMXRATE_I_ACLKSRC_HSC        (0x3 << 12)
+/* if OPORTMXRATE_I_ACLKSRC_APLL */
+#define   OPORTMXRATE_I_ACLKSEL_MASK       GENMASK(11, 8)
+#define   OPORTMXRATE_I_ACLKSEL_APLLA1     (0x0 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_APLLF1     (0x1 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_APLLA2     (0x2 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_APLLF2     (0x3 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_APLL       (0x4 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_HDMI1      (0x5 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_HDMI2      (0x6 << 8)
+#define   OPORTMXRATE_I_ACLKSEL_AI1ADCCK   (0xc << 8)
+#define   OPORTMXRATE_I_ACLKSEL_AI2ADCCK   (0xd << 8)
+#define   OPORTMXRATE_I_ACLKSEL_AI3ADCCK   (0xe << 8)
+#define   OPORTMXRATE_I_MCKSEL_MASK        GENMASK(7, 4)
+#define   OPORTMXRATE_I_MCKSEL_36          (0x0 << 4)
+#define   OPORTMXRATE_I_MCKSEL_33          (0x1 << 4)
+#define   OPORTMXRATE_I_MCKSEL_HSC27       (0xb << 4)
+#define   OPORTMXRATE_I_FSSEL_MASK         GENMASK(3, 0)
+#define   OPORTMXRATE_I_FSSEL_48           (0x0 << 0)
+#define   OPORTMXRATE_I_FSSEL_96           (0x1 << 0)
+#define   OPORTMXRATE_I_FSSEL_192          (0x2 << 0)
+#define   OPORTMXRATE_I_FSSEL_32           (0x3 << 0)
+#define   OPORTMXRATE_I_FSSEL_44_1         (0x4 << 0)
+#define   OPORTMXRATE_I_FSSEL_88_2         (0x5 << 0)
+#define   OPORTMXRATE_I_FSSEL_176_4        (0x6 << 0)
+#define   OPORTMXRATE_I_FSSEL_16           (0x8 << 0)
+#define   OPORTMXRATE_I_FSSEL_22_05        (0x9 << 0)
+#define   OPORTMXRATE_I_FSSEL_24           (0xa << 0)
+#define   OPORTMXRATE_I_FSSEL_8            (0xb << 0)
+#define   OPORTMXRATE_I_FSSEL_11_025       (0xc << 0)
+#define   OPORTMXRATE_I_FSSEL_12           (0xd << 0)
+#define OPORTMXEXNOE(n)                  (0x420f0 + 0x400 * (n))
+#define OPORTMXMASK(n)                   (0x420f8 + 0x400 * (n))
+#define   OPORTMXMASK_IUDXMSK_MASK         GENMASK(28, 24)
+#define   OPORTMXMASK_IUDXMSK_ON           (0x00 << 24)
+#define   OPORTMXMASK_IUDXMSK_OFF          (0x1f << 24)
+#define   OPORTMXMASK_IUXCKMSK_MASK        GENMASK(18, 16)
+#define   OPORTMXMASK_IUXCKMSK_ON          (0x0 << 16)
+#define   OPORTMXMASK_IUXCKMSK_OFF         (0x7 << 16)
+#define   OPORTMXMASK_DXMSK_MASK           GENMASK(12, 8)
+#define   OPORTMXMASK_DXMSK_ON             (0x00 << 8)
+#define   OPORTMXMASK_DXMSK_OFF            (0x1f << 8)
+#define   OPORTMXMASK_XCKMSK_MASK          GENMASK(2, 0)
+#define   OPORTMXMASK_XCKMSK_ON            (0x0 << 0)
+#define   OPORTMXMASK_XCKMSK_OFF           (0x7 << 0)
+#define OPORTMXDEBUG(n)                  (0x420fc + 0x400 * (n))
+#define OPORTMXT0RSTCTR(n)               (0x4211c + 0x400 * (n))
+#define OPORTMXT1RSTCTR(n)               (0x4213c + 0x400 * (n))
+#define OPORTMXT2RSTCTR(n)               (0x4215c + 0x400 * (n))
+#define OPORTMXT3RSTCTR(n)               (0x4217c + 0x400 * (n))
+#define OPORTMXT4RSTCTR(n)               (0x4219c + 0x400 * (n))
+
+#define SBF_(frame, shift)    (((frame) * 2 - 1) << shift)
+
+/* AOUT(PBoutMX) */
+#define PBOUTMXCTR0(n)                   (0x40200 + 0x40 * (n))
+#define   PBOUTMXCTR0_ENDIAN_MASK         GENMASK(5, 4)
+#define   PBOUTMXCTR0_ENDIAN_3210         (0x0 << 4)
+#define   PBOUTMXCTR0_ENDIAN_0123         (0x1 << 4)
+#define   PBOUTMXCTR0_ENDIAN_1032         (0x2 << 4)
+#define   PBOUTMXCTR0_ENDIAN_2301         (0x3 << 4)
+#define   PBOUTMXCTR0_MEMFMT_MASK         GENMASK(3, 0)
+#define   PBOUTMXCTR0_MEMFMT_10CH         (0x0 << 0)
+#define   PBOUTMXCTR0_MEMFMT_8CH          (0x1 << 0)
+#define   PBOUTMXCTR0_MEMFMT_6CH          (0x2 << 0)
+#define   PBOUTMXCTR0_MEMFMT_4CH          (0x3 << 0)
+#define   PBOUTMXCTR0_MEMFMT_2CH          (0x4 << 0)
+#define   PBOUTMXCTR0_MEMFMT_STREAM       (0x5 << 0)
+#define   PBOUTMXCTR0_MEMFMT_1CH          (0x6 << 0)
+#define PBOUTMXCTR1(n)                   (0x40204 + 0x40 * (n))
+#define PBOUTMXINTCTR(n)                 (0x40208 + 0x40 * (n))
+
+/* A2D(subsystem) */
+#define CDA2D_STRT0                      0x10000
+#define   CDA2D_STRT0_STOP_MASK            BIT(31)
+#define   CDA2D_STRT0_STOP_START           (0x0 << 31)
+#define   CDA2D_STRT0_STOP_STOP            (0x1 << 31)
+#define CDA2D_STAT0                      0x10020
+#define CDA2D_TEST                       0x100a0
+#define   CDA2D_TEST_DDR_MODE_MASK         GENMASK(3, 2)
+#define   CDA2D_TEST_DDR_MODE_EXTON0       (0x0 << 2)
+#define   CDA2D_TEST_DDR_MODE_EXTOFF1      (0x3 << 2)
+#define CDA2D_STRTADRSLOAD               0x100b0
+
+#define CDA2D_CHMXCTRL1(n)               (0x12000 + 0x80 * (n))
+#define   CDA2D_CHMXCTRL1_INDSIZE_MASK     BIT(0)
+#define   CDA2D_CHMXCTRL1_INDSIZE_FINITE   (0x0 << 0)
+#define   CDA2D_CHMXCTRL1_INDSIZE_INFINITE (0x1 << 0)
+#define CDA2D_CHMXCTRL2(n)               (0x12004 + 0x80 * (n))
+#define CDA2D_CHMXSRCAMODE(n)            (0x12020 + 0x80 * (n))
+#define CDA2D_CHMXDSTAMODE(n)            (0x12024 + 0x80 * (n))
+#define   CDA2D_CHMXAMODE_ENDIAN_MASK      GENMASK(17, 16)
+#define   CDA2D_CHMXAMODE_ENDIAN_3210      (0x0 << 16)
+#define   CDA2D_CHMXAMODE_ENDIAN_0123      (0x1 << 16)
+#define   CDA2D_CHMXAMODE_ENDIAN_1032      (0x2 << 16)
+#define   CDA2D_CHMXAMODE_ENDIAN_2301      (0x3 << 16)
+#define   CDA2D_CHMXAMODE_RSSEL_SHIFT      (8)
+#define   CDA2D_CHMXAMODE_AUPDT_MASK       GENMASK(5, 4)
+#define   CDA2D_CHMXAMODE_AUPDT_INC        (0x0 << 4)
+#define   CDA2D_CHMXAMODE_AUPDT_FIX        (0x2 << 4)
+#define   CDA2D_CHMXAMODE_TYPE_MASK        GENMASK(3, 2)
+#define   CDA2D_CHMXAMODE_TYPE_NORMAL      (0x0 << 2)
+#define   CDA2D_CHMXAMODE_TYPE_RING        (0x1 << 2)
+#define CDA2D_CHMXSRCSTRTADRS(n)         (0x12030 + 0x80 * (n))
+#define CDA2D_CHMXSRCSTRTADRSU(n)        (0x12034 + 0x80 * (n))
+#define CDA2D_CHMXDSTSTRTADRS(n)         (0x12038 + 0x80 * (n))
+#define CDA2D_CHMXDSTSTRTADRSU(n)        (0x1203c + 0x80 * (n))
+
+/* A2D(ring buffer) */
+#define CDA2D_RBFLUSH0                   0x10040
+#define CDA2D_RBADRSLOAD                 0x100b4
+#define CDA2D_RDPTRLOAD                  0x100b8
+#define   CDA2D_RDPTRLOAD_LSFLAG_LOAD      (0x0 << 31)
+#define   CDA2D_RDPTRLOAD_LSFLAG_STORE     (0x1 << 31)
+#define CDA2D_WRPTRLOAD                  0x100bc
+#define   CDA2D_WRPTRLOAD_LSFLAG_LOAD      (0x0 << 31)
+#define   CDA2D_WRPTRLOAD_LSFLAG_STORE     (0x1 << 31)
+
+#define CDA2D_RBMXBGNADRS(n)             (0x14000 + 0x80 * (n))
+#define CDA2D_RBMXBGNADRSU(n)            (0x14004 + 0x80 * (n))
+#define CDA2D_RBMXENDADRS(n)             (0x14008 + 0x80 * (n))
+#define CDA2D_RBMXENDADRSU(n)            (0x1400c + 0x80 * (n))
+#define CDA2D_RBMXBTH(n)                 (0x14038 + 0x80 * (n))
+#define CDA2D_RBMXRTH(n)                 (0x1403c + 0x80 * (n))
+#define CDA2D_RBMXRDPTR(n)               (0x14020 + 0x80 * (n))
+#define CDA2D_RBMXRDPTRU(n)              (0x14024 + 0x80 * (n))
+#define CDA2D_RBMXWRPTR(n)               (0x14028 + 0x80 * (n))
+#define CDA2D_RBMXWRPTRU(n)              (0x1402c + 0x80 * (n))
+#define   CDA2D_RBMXPTRU_PTRU_MASK         GENMASK(1, 0)
+#define CDA2D_RBMXCNFG(n)                (0x14030 + 0x80 * (n))
+#define CDA2D_RBMXIR(n)                  (0x14014 + 0x80 * (n))
+#define CDA2D_RBMXIE(n)                  (0x14018 + 0x80 * (n))
+#define CDA2D_RBMXID(n)                  (0x1401c + 0x80 * (n))
+#define   CDA2D_RBMXIX_SPACE               BIT(3)
+#define   CDA2D_RBMXIX_REMAIN              BIT(4)
+
+#endif /* SND_UNIPHIER_AIO_REG_H__ */
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
new file mode 100644
index 000000000000..2cd64273fb5b
--- /dev/null
+++ b/sound/soc/uniphier/aio.h
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Socionext UniPhier AIO ALSA driver.
+ *
+ * Copyright (c) 2016-2018 Socionext Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SND_UNIPHIER_AIO_H__
+#define SND_UNIPHIER_AIO_H__
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+struct platform_device;
+
+enum ID_PORT_TYPE {
+	PORT_TYPE_UNKNOWN,
+	PORT_TYPE_I2S,
+	PORT_TYPE_SPDIF,
+	PORT_TYPE_EVE,
+	PORT_TYPE_CONV,
+};
+
+enum ID_PORT_DIR {
+	PORT_DIR_OUTPUT,
+	PORT_DIR_INPUT,
+};
+
+enum IEC61937_PC {
+	IEC61937_PC_AC3   = 0x0001,
+	IEC61937_PC_PAUSE = 0x0003,
+	IEC61937_PC_MPA   = 0x0004,
+	IEC61937_PC_MP3   = 0x0005,
+	IEC61937_PC_DTS1  = 0x000b,
+	IEC61937_PC_DTS2  = 0x000c,
+	IEC61937_PC_DTS3  = 0x000d,
+	IEC61937_PC_AAC   = 0x0007,
+};
+
+/* IEC61937 Repetition period of data-burst in IEC60958 frames */
+#define IEC61937_FRM_STR_AC3       1536
+#define IEC61937_FRM_STR_MPA       1152
+#define IEC61937_FRM_STR_MP3       1152
+#define IEC61937_FRM_STR_DTS1      512
+#define IEC61937_FRM_STR_DTS2      1024
+#define IEC61937_FRM_STR_DTS3      2048
+#define IEC61937_FRM_STR_AAC       1024
+
+/* IEC61937 Repetition period of Pause data-burst in IEC60958 frames */
+#define IEC61937_FRM_PAU_AC3       3
+#define IEC61937_FRM_PAU_MPA       32
+#define IEC61937_FRM_PAU_MP3       32
+#define IEC61937_FRM_PAU_DTS1      3
+#define IEC61937_FRM_PAU_DTS2      3
+#define IEC61937_FRM_PAU_DTS3      3
+#define IEC61937_FRM_PAU_AAC       32
+
+/* IEC61937 Pa and Pb */
+#define IEC61937_HEADER_SIGN       0x1f4e72f8
+
+#define AUD_HW_PCMIN1    0
+#define AUD_HW_PCMIN2    1
+#define AUD_HW_PCMIN3    2
+#define AUD_HW_IECIN1    3
+#define AUD_HW_DIECIN1   4
+
+#define AUD_NAME_PCMIN1     "aio-pcmin1"
+#define AUD_NAME_PCMIN2     "aio-pcmin2"
+#define AUD_NAME_PCMIN3     "aio-pcmin3"
+#define AUD_NAME_IECIN1     "aio-iecin1"
+#define AUD_NAME_DIECIN1    "aio-diecin1"
+
+#define AUD_HW_HPCMOUT1    0
+#define AUD_HW_PCMOUT1     1
+#define AUD_HW_PCMOUT2     2
+#define AUD_HW_PCMOUT3     3
+#define AUD_HW_EPCMOUT1    4
+#define AUD_HW_EPCMOUT2    5
+#define AUD_HW_EPCMOUT3    6
+#define AUD_HW_EPCMOUT6    9
+#define AUD_HW_HIECOUT1    10
+#define AUD_HW_IECOUT1     11
+#define AUD_HW_CMASTER     31
+
+#define AUD_NAME_HPCMOUT1        "aio-hpcmout1"
+#define AUD_NAME_PCMOUT1         "aio-pcmout1"
+#define AUD_NAME_PCMOUT2         "aio-pcmout2"
+#define AUD_NAME_PCMOUT3         "aio-pcmout3"
+#define AUD_NAME_EPCMOUT1        "aio-epcmout1"
+#define AUD_NAME_EPCMOUT2        "aio-epcmout2"
+#define AUD_NAME_EPCMOUT3        "aio-epcmout3"
+#define AUD_NAME_EPCMOUT6        "aio-epcmout6"
+#define AUD_NAME_HIECOUT1        "aio-hiecout1"
+#define AUD_NAME_IECOUT1         "aio-iecout1"
+#define AUD_NAME_CMASTER         "aio-cmaster"
+#define AUD_NAME_HIECCOMPOUT1    "aio-hieccompout1"
+
+#define AUD_GNAME_HDMI    "aio-hdmi"
+#define AUD_GNAME_LINE    "aio-line"
+#define AUD_GNAME_IEC     "aio-iec"
+
+#define AUD_CLK_IO        0
+#define AUD_CLK_A1        1
+#define AUD_CLK_F1        2
+#define AUD_CLK_A2        3
+#define AUD_CLK_F2        4
+#define AUD_CLK_A         5
+#define AUD_CLK_F         6
+#define AUD_CLK_APLL      7
+#define AUD_CLK_RX0       8
+#define AUD_CLK_USB0      9
+#define AUD_CLK_HSC0      10
+
+#define AUD_PLL_A1        0
+#define AUD_PLL_F1        1
+#define AUD_PLL_A2        2
+#define AUD_PLL_F2        3
+#define AUD_PLL_APLL      4
+#define AUD_PLL_RX0       5
+#define AUD_PLL_USB0      6
+#define AUD_PLL_HSC0      7
+
+#define AUD_PLLDIV_1_2    0
+#define AUD_PLLDIV_1_3    1
+#define AUD_PLLDIV_1_1    2
+#define AUD_PLLDIV_2_3    3
+
+#define AUD_RING_SIZE            (128 * 1024)
+
+#define AUD_MIN_FRAGMENT         4
+#define AUD_MAX_FRAGMENT         8
+#define AUD_MIN_FRAGMENT_SIZE    (4 * 1024)
+#define AUD_MAX_FRAGMENT_SIZE    (16 * 1024)
+
+/*
+ * This is a selector for virtual register map of AIO.
+ *
+ * map:  Specify the index of virtual register map.
+ * hw :  Specify the ID of real register map, selector uses this value.
+ *       A meaning of this value depends specification of SoC.
+ */
+struct uniphier_aio_selector {
+	int map;
+	int hw;
+};
+
+/**
+ * 'SoftWare MAPping' setting of UniPhier AIO registers.
+ *
+ * We have to setup 'virtual' register maps to access 'real' registers of AIO.
+ * This feature is legacy and meaningless but AIO needs this to work.
+ *
+ * Each hardware blocks have own virtual register maps as following:
+ *
+ * Address Virtual                      Real
+ * ------- ---------                    ---------------
+ * 0x12000 DMAC map0 --> [selector] --> DMAC hardware 3
+ * 0x12080 DMAC map1 --> [selector] --> DMAC hardware 1
+ * ...
+ * 0x42000 Port map0 --> [selector] --> Port hardware 1
+ * 0x42400 Port map1 --> [selector] --> Port hardware 2
+ * ...
+ *
+ * ch   : Input or output channel of DMAC
+ * rb   : Ring buffer
+ * iport: PCM input port
+ * iif  : Input interface
+ * oport: PCM output port
+ * oif  : Output interface
+ * och  : Output channel of DMAC for sampling rate converter
+ *
+ * These are examples for sound data paths:
+ *
+ * For caputure device:
+ *   (outer of AIO) -> iport -> iif -> ch -> rb -> (CPU)
+ * For playback device:
+ *   (CPU) -> rb -> ch -> oif -> oport -> (outer of AIO)
+ * For sampling rate converter device:
+ *   (CPU) -> rb -> ch -> oif -> (HW SRC) -> iif -> och -> orb -> (CPU)
+ */
+struct uniphier_aio_swmap {
+	int type;
+	int dir;
+
+	struct uniphier_aio_selector ch;
+	struct uniphier_aio_selector rb;
+	struct uniphier_aio_selector iport;
+	struct uniphier_aio_selector iif;
+	struct uniphier_aio_selector oport;
+	struct uniphier_aio_selector oif;
+	struct uniphier_aio_selector och;
+};
+
+struct uniphier_aio_spec {
+	const char *name;
+	const char *gname;
+	struct uniphier_aio_swmap swm;
+};
+
+struct uniphier_aio_pll {
+	bool enable;
+	unsigned int freq;
+};
+
+struct uniphier_aio_chip_spec {
+	const struct uniphier_aio_spec *specs;
+	int num_specs;
+	const struct uniphier_aio_pll *plls;
+	int num_plls;
+	struct snd_soc_dai_driver *dais;
+	int num_dais;
+
+	/* DMA access mode, this is workaround for DMA hungup */
+	int addr_ext;
+};
+
+struct uniphier_aio_sub {
+	struct uniphier_aio *aio;
+
+	/* Guard sub->rd_offs and wr_offs from IRQ handler. */
+	spinlock_t lock;
+
+	const struct uniphier_aio_swmap *swm;
+	const struct uniphier_aio_spec *spec;
+
+	/* For PCM audio */
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_hw_params params;
+
+	/* For compress audio */
+	struct snd_compr_stream *cstream;
+	struct snd_compr_params cparams;
+	unsigned char *compr_area;
+	dma_addr_t compr_addr;
+	size_t compr_bytes;
+	int pass_through;
+	enum IEC61937_PC iec_pc;
+	bool iec_header;
+
+	/* Both PCM and compress audio */
+	bool use_mmap;
+	int setting;
+	int running;
+	u64 rd_offs;
+	u64 wr_offs;
+	u32 threshold;
+	u64 rd_org;
+	u64 wr_org;
+	u64 rd_total;
+	u64 wr_total;
+};
+
+struct uniphier_aio {
+	struct uniphier_aio_chip *chip;
+
+	struct uniphier_aio_sub sub[2];
+
+	unsigned int fmt;
+	/* Set one of AUD_CLK_X */
+	int clk_in;
+	int clk_out;
+	/* Set one of AUD_PLL_X */
+	int pll_in;
+	int pll_out;
+	/* Set one of AUD_PLLDIV_X */
+	int plldiv;
+};
+
+struct uniphier_aio_chip {
+	struct platform_device *pdev;
+	const struct uniphier_aio_chip_spec *chip_spec;
+
+	struct uniphier_aio *aios;
+	int num_aios;
+	struct uniphier_aio_pll *plls;
+	int num_plls;
+
+	struct clk *clk;
+	struct reset_control *rst;
+	struct regmap *regmap;
+	int active;
+};
+
+static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai)
+{
+	struct uniphier_aio_chip *chip = snd_soc_dai_get_drvdata(dai);
+
+	return &chip->aios[dai->id];
+}
+
+int uniphier_aiodma_soc_register_platform(struct platform_device *pdev);
+extern const struct snd_compr_ops uniphier_aio_compr_ops;
+
+int uniphier_aio_dai_probe(struct snd_soc_dai *dai);
+int uniphier_aio_dai_remove(struct snd_soc_dai *dai);
+int uniphier_aio_dai_suspend(struct snd_soc_dai *dai);
+int uniphier_aio_dai_resume(struct snd_soc_dai *dai);
+int uniphier_aio_probe(struct platform_device *pdev);
+int uniphier_aio_remove(struct platform_device *pdev);
+extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops;
+
+u64 aio_rb_cnt(struct uniphier_aio_sub *sub);
+u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub);
+u64 aio_rb_space(struct uniphier_aio_sub *sub);
+u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub);
+
+int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
+		     unsigned int freq);
+void aio_chip_init(struct uniphier_aio_chip *chip);
+int aio_init(struct uniphier_aio_sub *sub);
+void aio_port_reset(struct uniphier_aio_sub *sub);
+int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate);
+int aio_port_set_fmt(struct uniphier_aio_sub *sub);
+int aio_port_set_clk(struct uniphier_aio_sub *sub);
+int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
+		       const struct snd_pcm_hw_params *params);
+void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
+int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through);
+int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
+			      enum IEC61937_PC pc);
+void aio_src_reset(struct uniphier_aio_sub *sub);
+int aio_src_set_param(struct uniphier_aio_sub *sub,
+		      const struct snd_pcm_hw_params *params);
+int aio_srcif_set_param(struct uniphier_aio_sub *sub);
+int aio_srcch_set_param(struct uniphier_aio_sub *sub);
+void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable);
+
+int aiodma_ch_set_param(struct uniphier_aio_sub *sub);
+void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable);
+int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th);
+int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
+			 int period);
+void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
+		    int period);
+bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub);
+void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub);
+
+#endif /* SND_UNIPHIER_AIO_H__ */
diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c
index 0cc9efff1d9a..cad7e60de21d 100644
--- a/sound/soc/uniphier/evea.c
+++ b/sound/soc/uniphier/evea.c
@@ -220,8 +220,8 @@ static void evea_update_switch_all(struct evea_priv *evea)
 static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = evea->switch_lin;
 
@@ -231,8 +231,8 @@ static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
 static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	if (evea->switch_lin == ucontrol->value.integer.value[0])
 		return 0;
@@ -245,8 +245,8 @@ static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
 static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = evea->switch_lo;
 
@@ -256,8 +256,8 @@ static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
 static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	if (evea->switch_lo == ucontrol->value.integer.value[0])
 		return 0;
@@ -270,8 +270,8 @@ static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
 static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = evea->switch_hp;
 
@@ -281,8 +281,8 @@ static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
 static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	if (evea->switch_hp == ucontrol->value.integer.value[0])
 		return 0;
@@ -301,9 +301,9 @@ static const struct snd_kcontrol_new eva_controls[] = {
 			    evea_get_switch_hp, evea_set_switch_hp),
 };
 
-static int evea_codec_probe(struct snd_soc_codec *codec)
+static int evea_codec_probe(struct snd_soc_component *component)
 {
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	evea->switch_lin = 1;
 	evea->switch_lo = 1;
@@ -315,9 +315,9 @@ static int evea_codec_probe(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int evea_codec_suspend(struct snd_soc_codec *codec)
+static int evea_codec_suspend(struct snd_soc_component *component)
 {
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 
 	evea_set_power_state_off(evea);
 
@@ -331,9 +331,9 @@ static int evea_codec_suspend(struct snd_soc_codec *codec)
 	return 0;
 }
 
-static int evea_codec_resume(struct snd_soc_codec *codec)
+static int evea_codec_resume(struct snd_soc_component *component)
 {
-	struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
+	struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 	int ret;
 
 	ret = clk_prepare_enable(evea->clk);
@@ -376,19 +376,20 @@ static int evea_codec_resume(struct snd_soc_codec *codec)
 	return ret;
 }
 
-static struct snd_soc_codec_driver soc_codec_evea = {
-	.probe   = evea_codec_probe,
-	.suspend = evea_codec_suspend,
-	.resume  = evea_codec_resume,
-
-	.component_driver = {
-		.dapm_widgets = evea_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(evea_widgets),
-		.dapm_routes = evea_routes,
-		.num_dapm_routes = ARRAY_SIZE(evea_routes),
-		.controls = eva_controls,
-		.num_controls = ARRAY_SIZE(eva_controls),
-	},
+static struct snd_soc_component_driver soc_codec_evea = {
+	.probe			= evea_codec_probe,
+	.suspend		= evea_codec_suspend,
+	.resume			= evea_codec_resume,
+	.dapm_widgets		= evea_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(evea_widgets),
+	.dapm_routes		= evea_routes,
+	.num_dapm_routes	= ARRAY_SIZE(evea_routes),
+	.controls		= eva_controls,
+	.num_controls		= ARRAY_SIZE(eva_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
 };
 
 static struct snd_soc_dai_driver soc_dai_evea[] = {
@@ -505,7 +506,7 @@ static int evea_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, evea);
 
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_evea,
+	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_evea,
 				     soc_dai_evea, ARRAY_SIZE(soc_dai_evea));
 	if (ret)
 		goto err_out_reset_adamv;
@@ -534,8 +535,6 @@ static int evea_remove(struct platform_device *pdev)
 {
 	struct evea_priv *evea = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_codec(&pdev->dev);
-
 	reset_control_assert(evea->rst_adamv);
 	reset_control_assert(evea->rst_exiv);
 	reset_control_assert(evea->rst);
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index 2472144b329e..503560916620 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -483,13 +483,10 @@ static const struct snd_pcm_ops xtfpga_pcm_ops = {
 	.pointer	= xtfpga_pcm_pointer,
 };
 
-static const struct snd_soc_platform_driver xtfpga_soc_platform = {
-	.pcm_new	= xtfpga_pcm_new,
-	.ops		= &xtfpga_pcm_ops,
-};
-
 static const struct snd_soc_component_driver xtfpga_i2s_component = {
 	.name		= DRV_NAME,
+	.pcm_new	= xtfpga_pcm_new,
+	.ops		= &xtfpga_pcm_ops,
 };
 
 static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = {
@@ -591,18 +588,13 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	err = snd_soc_register_platform(&pdev->dev, &xtfpga_soc_platform);
-	if (err < 0) {
-		dev_err(&pdev->dev, "couldn't register platform\n");
-		goto err;
-	}
 	err = devm_snd_soc_register_component(&pdev->dev,
 					      &xtfpga_i2s_component,
 					      xtfpga_i2s_dai,
 					      ARRAY_SIZE(xtfpga_i2s_dai));
 	if (err < 0) {
 		dev_err(&pdev->dev, "couldn't register component\n");
-		goto err_unregister_platform;
+		goto err;
 	}
 
 	pm_runtime_enable(&pdev->dev);
@@ -615,8 +607,6 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
 
 err_pm_disable:
 	pm_runtime_disable(&pdev->dev);
-err_unregister_platform:
-	snd_soc_unregister_platform(&pdev->dev);
 err:
 	dev_err(&pdev->dev, "%s: err = %d\n", __func__, err);
 	return err;
@@ -626,7 +616,6 @@ static int xtfpga_i2s_remove(struct platform_device *pdev)
 {
 	struct xtfpga_i2s *i2s = dev_get_drvdata(&pdev->dev);
 
-	snd_soc_unregister_platform(&pdev->dev);
 	if (i2s->regmap && !IS_ERR(i2s->regmap)) {
 		regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG, 0);
 		regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, 0);
diff --git a/tools/arch/powerpc/include/uapi/asm/unistd.h b/tools/arch/powerpc/include/uapi/asm/unistd.h
new file mode 100644
index 000000000000..389c36fd8299
--- /dev/null
+++ b/tools/arch/powerpc/include/uapi/asm/unistd.h
@@ -0,0 +1,402 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * This file contains the system call numbers.
+ *
+ * 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 _UAPI_ASM_POWERPC_UNISTD_H_
+#define _UAPI_ASM_POWERPC_UNISTD_H_
+
+
+#define __NR_restart_syscall	  0
+#define __NR_exit		  1
+#define __NR_fork		  2
+#define __NR_read		  3
+#define __NR_write		  4
+#define __NR_open		  5
+#define __NR_close		  6
+#define __NR_waitpid		  7
+#define __NR_creat		  8
+#define __NR_link		  9
+#define __NR_unlink		 10
+#define __NR_execve		 11
+#define __NR_chdir		 12
+#define __NR_time		 13
+#define __NR_mknod		 14
+#define __NR_chmod		 15
+#define __NR_lchown		 16
+#define __NR_break		 17
+#define __NR_oldstat		 18
+#define __NR_lseek		 19
+#define __NR_getpid		 20
+#define __NR_mount		 21
+#define __NR_umount		 22
+#define __NR_setuid		 23
+#define __NR_getuid		 24
+#define __NR_stime		 25
+#define __NR_ptrace		 26
+#define __NR_alarm		 27
+#define __NR_oldfstat		 28
+#define __NR_pause		 29
+#define __NR_utime		 30
+#define __NR_stty		 31
+#define __NR_gtty		 32
+#define __NR_access		 33
+#define __NR_nice		 34
+#define __NR_ftime		 35
+#define __NR_sync		 36
+#define __NR_kill		 37
+#define __NR_rename		 38
+#define __NR_mkdir		 39
+#define __NR_rmdir		 40
+#define __NR_dup		 41
+#define __NR_pipe		 42
+#define __NR_times		 43
+#define __NR_prof		 44
+#define __NR_brk		 45
+#define __NR_setgid		 46
+#define __NR_getgid		 47
+#define __NR_signal		 48
+#define __NR_geteuid		 49
+#define __NR_getegid		 50
+#define __NR_acct		 51
+#define __NR_umount2		 52
+#define __NR_lock		 53
+#define __NR_ioctl		 54
+#define __NR_fcntl		 55
+#define __NR_mpx		 56
+#define __NR_setpgid		 57
+#define __NR_ulimit		 58
+#define __NR_oldolduname	 59
+#define __NR_umask		 60
+#define __NR_chroot		 61
+#define __NR_ustat		 62
+#define __NR_dup2		 63
+#define __NR_getppid		 64
+#define __NR_getpgrp		 65
+#define __NR_setsid		 66
+#define __NR_sigaction		 67
+#define __NR_sgetmask		 68
+#define __NR_ssetmask		 69
+#define __NR_setreuid		 70
+#define __NR_setregid		 71
+#define __NR_sigsuspend		 72
+#define __NR_sigpending		 73
+#define __NR_sethostname	 74
+#define __NR_setrlimit		 75
+#define __NR_getrlimit		 76
+#define __NR_getrusage		 77
+#define __NR_gettimeofday	 78
+#define __NR_settimeofday	 79
+#define __NR_getgroups		 80
+#define __NR_setgroups		 81
+#define __NR_select		 82
+#define __NR_symlink		 83
+#define __NR_oldlstat		 84
+#define __NR_readlink		 85
+#define __NR_uselib		 86
+#define __NR_swapon		 87
+#define __NR_reboot		 88
+#define __NR_readdir		 89
+#define __NR_mmap		 90
+#define __NR_munmap		 91
+#define __NR_truncate		 92
+#define __NR_ftruncate		 93
+#define __NR_fchmod		 94
+#define __NR_fchown		 95
+#define __NR_getpriority	 96
+#define __NR_setpriority	 97
+#define __NR_profil		 98
+#define __NR_statfs		 99
+#define __NR_fstatfs		100
+#define __NR_ioperm		101
+#define __NR_socketcall		102
+#define __NR_syslog		103
+#define __NR_setitimer		104
+#define __NR_getitimer		105
+#define __NR_stat		106
+#define __NR_lstat		107
+#define __NR_fstat		108
+#define __NR_olduname		109
+#define __NR_iopl		110
+#define __NR_vhangup		111
+#define __NR_idle		112
+#define __NR_vm86		113
+#define __NR_wait4		114
+#define __NR_swapoff		115
+#define __NR_sysinfo		116
+#define __NR_ipc		117
+#define __NR_fsync		118
+#define __NR_sigreturn		119
+#define __NR_clone		120
+#define __NR_setdomainname	121
+#define __NR_uname		122
+#define __NR_modify_ldt		123
+#define __NR_adjtimex		124
+#define __NR_mprotect		125
+#define __NR_sigprocmask	126
+#define __NR_create_module	127
+#define __NR_init_module	128
+#define __NR_delete_module	129
+#define __NR_get_kernel_syms	130
+#define __NR_quotactl		131
+#define __NR_getpgid		132
+#define __NR_fchdir		133
+#define __NR_bdflush		134
+#define __NR_sysfs		135
+#define __NR_personality	136
+#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
+#define __NR_setfsuid		138
+#define __NR_setfsgid		139
+#define __NR__llseek		140
+#define __NR_getdents		141
+#define __NR__newselect		142
+#define __NR_flock		143
+#define __NR_msync		144
+#define __NR_readv		145
+#define __NR_writev		146
+#define __NR_getsid		147
+#define __NR_fdatasync		148
+#define __NR__sysctl		149
+#define __NR_mlock		150
+#define __NR_munlock		151
+#define __NR_mlockall		152
+#define __NR_munlockall		153
+#define __NR_sched_setparam		154
+#define __NR_sched_getparam		155
+#define __NR_sched_setscheduler		156
+#define __NR_sched_getscheduler		157
+#define __NR_sched_yield		158
+#define __NR_sched_get_priority_max	159
+#define __NR_sched_get_priority_min	160
+#define __NR_sched_rr_get_interval	161
+#define __NR_nanosleep		162
+#define __NR_mremap		163
+#define __NR_setresuid		164
+#define __NR_getresuid		165
+#define __NR_query_module	166
+#define __NR_poll		167
+#define __NR_nfsservctl		168
+#define __NR_setresgid		169
+#define __NR_getresgid		170
+#define __NR_prctl		171
+#define __NR_rt_sigreturn	172
+#define __NR_rt_sigaction	173
+#define __NR_rt_sigprocmask	174
+#define __NR_rt_sigpending	175
+#define __NR_rt_sigtimedwait	176
+#define __NR_rt_sigqueueinfo	177
+#define __NR_rt_sigsuspend	178
+#define __NR_pread64		179
+#define __NR_pwrite64		180
+#define __NR_chown		181
+#define __NR_getcwd		182
+#define __NR_capget		183
+#define __NR_capset		184
+#define __NR_sigaltstack	185
+#define __NR_sendfile		186
+#define __NR_getpmsg		187	/* some people actually want streams */
+#define __NR_putpmsg		188	/* some people actually want streams */
+#define __NR_vfork		189
+#define __NR_ugetrlimit		190	/* SuS compliant getrlimit */
+#define __NR_readahead		191
+#ifndef __powerpc64__			/* these are 32-bit only */
+#define __NR_mmap2		192
+#define __NR_truncate64		193
+#define __NR_ftruncate64	194
+#define __NR_stat64		195
+#define __NR_lstat64		196
+#define __NR_fstat64		197
+#endif
+#define __NR_pciconfig_read	198
+#define __NR_pciconfig_write	199
+#define __NR_pciconfig_iobase	200
+#define __NR_multiplexer	201
+#define __NR_getdents64		202
+#define __NR_pivot_root		203
+#ifndef __powerpc64__
+#define __NR_fcntl64		204
+#endif
+#define __NR_madvise		205
+#define __NR_mincore		206
+#define __NR_gettid		207
+#define __NR_tkill		208
+#define __NR_setxattr		209
+#define __NR_lsetxattr		210
+#define __NR_fsetxattr		211
+#define __NR_getxattr		212
+#define __NR_lgetxattr		213
+#define __NR_fgetxattr		214
+#define __NR_listxattr		215
+#define __NR_llistxattr		216
+#define __NR_flistxattr		217
+#define __NR_removexattr	218
+#define __NR_lremovexattr	219
+#define __NR_fremovexattr	220
+#define __NR_futex		221
+#define __NR_sched_setaffinity	222
+#define __NR_sched_getaffinity	223
+/* 224 currently unused */
+#define __NR_tuxcall		225
+#ifndef __powerpc64__
+#define __NR_sendfile64		226
+#endif
+#define __NR_io_setup		227
+#define __NR_io_destroy		228
+#define __NR_io_getevents	229
+#define __NR_io_submit		230
+#define __NR_io_cancel		231
+#define __NR_set_tid_address	232
+#define __NR_fadvise64		233
+#define __NR_exit_group		234
+#define __NR_lookup_dcookie	235
+#define __NR_epoll_create	236
+#define __NR_epoll_ctl		237
+#define __NR_epoll_wait		238
+#define __NR_remap_file_pages	239
+#define __NR_timer_create	240
+#define __NR_timer_settime	241
+#define __NR_timer_gettime	242
+#define __NR_timer_getoverrun	243
+#define __NR_timer_delete	244
+#define __NR_clock_settime	245
+#define __NR_clock_gettime	246
+#define __NR_clock_getres	247
+#define __NR_clock_nanosleep	248
+#define __NR_swapcontext	249
+#define __NR_tgkill		250
+#define __NR_utimes		251
+#define __NR_statfs64		252
+#define __NR_fstatfs64		253
+#ifndef __powerpc64__
+#define __NR_fadvise64_64	254
+#endif
+#define __NR_rtas		255
+#define __NR_sys_debug_setcontext 256
+/* Number 257 is reserved for vserver */
+#define __NR_migrate_pages	258
+#define __NR_mbind		259
+#define __NR_get_mempolicy	260
+#define __NR_set_mempolicy	261
+#define __NR_mq_open		262
+#define __NR_mq_unlink		263
+#define __NR_mq_timedsend	264
+#define __NR_mq_timedreceive	265
+#define __NR_mq_notify		266
+#define __NR_mq_getsetattr	267
+#define __NR_kexec_load		268
+#define __NR_add_key		269
+#define __NR_request_key	270
+#define __NR_keyctl		271
+#define __NR_waitid		272
+#define __NR_ioprio_set		273
+#define __NR_ioprio_get		274
+#define __NR_inotify_init	275
+#define __NR_inotify_add_watch	276
+#define __NR_inotify_rm_watch	277
+#define __NR_spu_run		278
+#define __NR_spu_create		279
+#define __NR_pselect6		280
+#define __NR_ppoll		281
+#define __NR_unshare		282
+#define __NR_splice		283
+#define __NR_tee		284
+#define __NR_vmsplice		285
+#define __NR_openat		286
+#define __NR_mkdirat		287
+#define __NR_mknodat		288
+#define __NR_fchownat		289
+#define __NR_futimesat		290
+#ifdef __powerpc64__
+#define __NR_newfstatat		291
+#else
+#define __NR_fstatat64		291
+#endif
+#define __NR_unlinkat		292
+#define __NR_renameat		293
+#define __NR_linkat		294
+#define __NR_symlinkat		295
+#define __NR_readlinkat		296
+#define __NR_fchmodat		297
+#define __NR_faccessat		298
+#define __NR_get_robust_list	299
+#define __NR_set_robust_list	300
+#define __NR_move_pages		301
+#define __NR_getcpu		302
+#define __NR_epoll_pwait	303
+#define __NR_utimensat		304
+#define __NR_signalfd		305
+#define __NR_timerfd_create	306
+#define __NR_eventfd		307
+#define __NR_sync_file_range2	308
+#define __NR_fallocate		309
+#define __NR_subpage_prot	310
+#define __NR_timerfd_settime	311
+#define __NR_timerfd_gettime	312
+#define __NR_signalfd4		313
+#define __NR_eventfd2		314
+#define __NR_epoll_create1	315
+#define __NR_dup3		316
+#define __NR_pipe2		317
+#define __NR_inotify_init1	318
+#define __NR_perf_event_open	319
+#define __NR_preadv		320
+#define __NR_pwritev		321
+#define __NR_rt_tgsigqueueinfo	322
+#define __NR_fanotify_init	323
+#define __NR_fanotify_mark	324
+#define __NR_prlimit64		325
+#define __NR_socket		326
+#define __NR_bind		327
+#define __NR_connect		328
+#define __NR_listen		329
+#define __NR_accept		330
+#define __NR_getsockname	331
+#define __NR_getpeername	332
+#define __NR_socketpair		333
+#define __NR_send		334
+#define __NR_sendto		335
+#define __NR_recv		336
+#define __NR_recvfrom		337
+#define __NR_shutdown		338
+#define __NR_setsockopt		339
+#define __NR_getsockopt		340
+#define __NR_sendmsg		341
+#define __NR_recvmsg		342
+#define __NR_recvmmsg		343
+#define __NR_accept4		344
+#define __NR_name_to_handle_at	345
+#define __NR_open_by_handle_at	346
+#define __NR_clock_adjtime	347
+#define __NR_syncfs		348
+#define __NR_sendmmsg		349
+#define __NR_setns		350
+#define __NR_process_vm_readv	351
+#define __NR_process_vm_writev	352
+#define __NR_finit_module	353
+#define __NR_kcmp		354
+#define __NR_sched_setattr	355
+#define __NR_sched_getattr	356
+#define __NR_renameat2		357
+#define __NR_seccomp		358
+#define __NR_getrandom		359
+#define __NR_memfd_create	360
+#define __NR_bpf		361
+#define __NR_execveat		362
+#define __NR_switch_endian	363
+#define __NR_userfaultfd	364
+#define __NR_membarrier		365
+#define __NR_mlock2		378
+#define __NR_copy_file_range	379
+#define __NR_preadv2		380
+#define __NR_pwritev2		381
+#define __NR_kexec_file_load	382
+#define __NR_statx		383
+#define __NR_pkey_alloc		384
+#define __NR_pkey_free		385
+#define __NR_pkey_mprotect	386
+
+#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index 3a0396d87c42..185acfa229b5 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -244,7 +244,7 @@ static int do_batch(int argc, char **argv)
 	}
 
 	if (errno && errno != ENOENT) {
-		perror("reading batch file failed");
+		p_err("reading batch file failed: %s", strerror(errno));
 		err = -1;
 	} else {
 		p_info("processed %d lines", lines);
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index e8e2baaf93c2..e549e329be82 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -774,6 +774,9 @@ static int do_dump(int argc, char **argv)
 			      n < 0 ? strerror(errno) : "short write");
 			goto err_free;
 		}
+
+		if (json_output)
+			jsonw_null(json_wtr);
 	} else {
 		if (member_len == &info.jited_prog_len) {
 			const char *name = NULL;
diff --git a/tools/cgroup/Makefile b/tools/cgroup/Makefile
index 860fa151640a..ffca068e4a76 100644
--- a/tools/cgroup/Makefile
+++ b/tools/cgroup/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for cgroup tools
 
-CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra
 
 all: cgroup_event_listener
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile
index 805a2c0cf4cd..240eda014b37 100644
--- a/tools/gpio/Makefile
+++ b/tools/gpio/Makefile
@@ -12,8 +12,6 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
diff --git a/tools/hv/Makefile b/tools/hv/Makefile
index 1139d71fa0cf..5db5e62cebda 100644
--- a/tools/hv/Makefile
+++ b/tools/hv/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for Hyper-V tools
 
-CC = $(CROSS_COMPILE)gcc
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g $(shell getconf LFS_CFLAGS)
 
diff --git a/tools/iio/Makefile b/tools/iio/Makefile
index a08e7a47d6a3..332ed2f6c2c2 100644
--- a/tools/iio/Makefile
+++ b/tools/iio/Makefile
@@ -12,8 +12,6 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := iio_event_monitor lsiio iio_generic_buffer
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index e0739a1aa4b2..6f873503552d 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -380,10 +380,14 @@ struct perf_event_attr {
 	__u32			bp_type;
 	union {
 		__u64		bp_addr;
+		__u64		kprobe_func; /* for perf_kprobe */
+		__u64		uprobe_path; /* for perf_uprobe */
 		__u64		config1; /* extension of config */
 	};
 	union {
 		__u64		bp_len;
+		__u64		kprobe_addr; /* when kprobe_func == NULL */
+		__u64		probe_offset; /* for perf_[k,u]probe */
 		__u64		config2; /* extension of config1 */
 	};
 	__u64	branch_sample_type; /* enum perf_branch_sample_type */
diff --git a/tools/laptop/freefall/Makefile b/tools/laptop/freefall/Makefile
index 5f758c489a20..b572d94255f6 100644
--- a/tools/laptop/freefall/Makefile
+++ b/tools/laptop/freefall/Makefile
@@ -2,7 +2,6 @@
 PREFIX ?= /usr
 SBINDIR ?= sbin
 INSTALL ?= install
-CC = $(CROSS_COMPILE)gcc
 
 TARGET = freefall
 
diff --git a/tools/leds/Makefile b/tools/leds/Makefile
index c379af003807..7b6bed13daaa 100644
--- a/tools/leds/Makefile
+++ b/tools/leds/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for LEDs tools
 
-CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra -g -I../../include/uapi
 
 all: uledmon led_hw_brightness_mon
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
index b24afc0e6e81..6a12bbf39f7b 100644
--- a/tools/lib/api/fs/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -315,12 +315,8 @@ int filename__read_int(const char *filename, int *value)
 	return err;
 }
 
-/*
- * Parses @value out of @filename with strtoull.
- * By using 0 for base, the strtoull detects the
- * base automatically (see man strtoull).
- */
-int filename__read_ull(const char *filename, unsigned long long *value)
+static int filename__read_ull_base(const char *filename,
+				   unsigned long long *value, int base)
 {
 	char line[64];
 	int fd = open(filename, O_RDONLY), err = -1;
@@ -329,7 +325,7 @@ int filename__read_ull(const char *filename, unsigned long long *value)
 		return -1;
 
 	if (read(fd, line, sizeof(line)) > 0) {
-		*value = strtoull(line, NULL, 0);
+		*value = strtoull(line, NULL, base);
 		if (*value != ULLONG_MAX)
 			err = 0;
 	}
@@ -338,6 +334,25 @@ int filename__read_ull(const char *filename, unsigned long long *value)
 	return err;
 }
 
+/*
+ * Parses @value out of @filename with strtoull.
+ * By using 16 for base to treat the number as hex.
+ */
+int filename__read_xll(const char *filename, unsigned long long *value)
+{
+	return filename__read_ull_base(filename, value, 16);
+}
+
+/*
+ * Parses @value out of @filename with strtoull.
+ * By using 0 for base, the strtoull detects the
+ * base automatically (see man strtoull).
+ */
+int filename__read_ull(const char *filename, unsigned long long *value)
+{
+	return filename__read_ull_base(filename, value, 0);
+}
+
 #define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
 
 int filename__read_str(const char *filename, char **buf, size_t *sizep)
@@ -417,7 +432,8 @@ int procfs__read_str(const char *entry, char **buf, size_t *sizep)
 	return filename__read_str(path, buf, sizep);
 }
 
-int sysfs__read_ull(const char *entry, unsigned long long *value)
+static int sysfs__read_ull_base(const char *entry,
+				unsigned long long *value, int base)
 {
 	char path[PATH_MAX];
 	const char *sysfs = sysfs__mountpoint();
@@ -427,7 +443,17 @@ int sysfs__read_ull(const char *entry, unsigned long long *value)
 
 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 
-	return filename__read_ull(path, value);
+	return filename__read_ull_base(path, value, base);
+}
+
+int sysfs__read_xll(const char *entry, unsigned long long *value)
+{
+	return sysfs__read_ull_base(entry, value, 16);
+}
+
+int sysfs__read_ull(const char *entry, unsigned long long *value)
+{
+	return sysfs__read_ull_base(entry, value, 0);
 }
 
 int sysfs__read_int(const char *entry, int *value)
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h
index dda49deefb52..92d03b8396b1 100644
--- a/tools/lib/api/fs/fs.h
+++ b/tools/lib/api/fs/fs.h
@@ -30,6 +30,7 @@ FS(bpf_fs)
 
 int filename__read_int(const char *filename, int *value);
 int filename__read_ull(const char *filename, unsigned long long *value);
+int filename__read_xll(const char *filename, unsigned long long *value);
 int filename__read_str(const char *filename, char **buf, size_t *sizep);
 
 int filename__write_int(const char *filename, int value);
@@ -39,6 +40,7 @@ int procfs__read_str(const char *entry, char **buf, size_t *sizep);
 int sysctl__read_int(const char *sysctl, int *value);
 int sysfs__read_int(const char *entry, int *value);
 int sysfs__read_ull(const char *entry, unsigned long long *value);
+int sysfs__read_xll(const char *entry, unsigned long long *value);
 int sysfs__read_str(const char *entry, char **buf, size_t *sizep);
 int sysfs__read_bool(const char *entry, bool *value);
 
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c
index 914cb8e3d40b..689b6a130dd7 100644
--- a/tools/lib/symbol/kallsyms.c
+++ b/tools/lib/symbol/kallsyms.c
@@ -38,6 +38,10 @@ int kallsyms__parse(const char *filename, void *arg,
 
 		len = hex2u64(line, &start);
 
+		/* Skip the line if we failed to parse the address. */
+		if (!len)
+			continue;
+
 		len++;
 		if (len + 2 >= line_len)
 			continue;
diff --git a/tools/memory-model/Documentation/cheatsheet.txt b/tools/memory-model/Documentation/cheatsheet.txt
new file mode 100644
index 000000000000..1917712bce99
--- /dev/null
+++ b/tools/memory-model/Documentation/cheatsheet.txt
@@ -0,0 +1,30 @@
+                                  Prior Operation     Subsequent Operation
+                                  ---------------  ---------------------------
+                               C  Self  R  W  RWM  Self  R  W  DR  DW  RMW  SV
+                              __  ----  -  -  ---  ----  -  -  --  --  ---  --
+
+Store, e.g., WRITE_ONCE()            Y                                       Y
+Load, e.g., READ_ONCE()              Y                              Y        Y
+Unsuccessful RMW operation           Y                              Y        Y
+smp_read_barrier_depends()              Y                       Y   Y
+*_dereference()                      Y                          Y   Y        Y
+Successful *_acquire()               R                   Y  Y   Y   Y    Y   Y
+Successful *_release()         C        Y  Y    Y     W                      Y
+smp_rmb()                               Y       R        Y      Y        R
+smp_wmb()                                  Y    W           Y       Y    W
+smp_mb() & synchronize_rcu()  CP        Y  Y    Y        Y  Y   Y   Y    Y
+Successful full non-void RMW  CP     Y  Y  Y    Y     Y  Y  Y   Y   Y    Y   Y
+smp_mb__before_atomic()       CP        Y  Y    Y        a  a   a   a    Y
+smp_mb__after_atomic()        CP        a  a    Y        Y  Y   Y   Y
+
+
+Key:	C:	Ordering is cumulative
+	P:	Ordering propagates
+	R:	Read, for example, READ_ONCE(), or read portion of RMW
+	W:	Write, for example, WRITE_ONCE(), or write portion of RMW
+	Y:	Provides ordering
+	a:	Provides ordering given intervening RMW atomic operation
+	DR:	Dependent read (address dependency)
+	DW:	Dependent write (address, data, or control dependency)
+	RMW:	Atomic read-modify-write operation
+	SV	Same-variable access
diff --git a/tools/memory-model/Documentation/explanation.txt b/tools/memory-model/Documentation/explanation.txt
new file mode 100644
index 000000000000..867e0ea69b6d
--- /dev/null
+++ b/tools/memory-model/Documentation/explanation.txt
@@ -0,0 +1,1840 @@
+Explanation of the Linux-Kernel Memory Model
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Author: Alan Stern <stern@rowland.harvard.edu>
+:Created: October 2017
+
+.. Contents
+
+  1. INTRODUCTION
+  2. BACKGROUND
+  3. A SIMPLE EXAMPLE
+  4. A SELECTION OF MEMORY MODELS
+  5. ORDERING AND CYCLES
+  6. EVENTS
+  7. THE PROGRAM ORDER RELATION: po AND po-loc
+  8. A WARNING
+  9. DEPENDENCY RELATIONS: data, addr, and ctrl
+  10. THE READS-FROM RELATION: rf, rfi, and rfe
+  11. CACHE COHERENCE AND THE COHERENCE ORDER RELATION: co, coi, and coe
+  12. THE FROM-READS RELATION: fr, fri, and fre
+  13. AN OPERATIONAL MODEL
+  14. PROPAGATION ORDER RELATION: cumul-fence
+  15. DERIVATION OF THE LKMM FROM THE OPERATIONAL MODEL
+  16. SEQUENTIAL CONSISTENCY PER VARIABLE
+  17. ATOMIC UPDATES: rmw
+  18. THE PRESERVED PROGRAM ORDER RELATION: ppo
+  19. AND THEN THERE WAS ALPHA
+  20. THE HAPPENS-BEFORE RELATION: hb
+  21. THE PROPAGATES-BEFORE RELATION: pb
+  22. RCU RELATIONS: link, gp-link, rscs-link, and rcu-path
+  23. ODDS AND ENDS
+
+
+
+INTRODUCTION
+------------
+
+The Linux-kernel memory model (LKMM) is rather complex and obscure.
+This is particularly evident if you read through the linux-kernel.bell
+and linux-kernel.cat files that make up the formal version of the
+memory model; they are extremely terse and their meanings are far from
+clear.
+
+This document describes the ideas underlying the LKMM.  It is meant
+for people who want to understand how the memory model was designed.
+It does not go into the details of the code in the .bell and .cat
+files; rather, it explains in English what the code expresses
+symbolically.
+
+Sections 2 (BACKGROUND) through 5 (ORDERING AND CYCLES) are aimed
+toward beginners; they explain what memory models are and the basic
+notions shared by all such models.  People already familiar with these
+concepts can skim or skip over them.  Sections 6 (EVENTS) through 12
+(THE FROM_READS RELATION) describe the fundamental relations used in
+many memory models.  Starting in Section 13 (AN OPERATIONAL MODEL),
+the workings of the LKMM itself are covered.
+
+Warning: The code examples in this document are not written in the
+proper format for litmus tests.  They don't include a header line, the
+initializations are not enclosed in braces, the global variables are
+not passed by pointers, and they don't have an "exists" clause at the
+end.  Converting them to the right format is left as an exercise for
+the reader.
+
+
+BACKGROUND
+----------
+
+A memory consistency model (or just memory model, for short) is
+something which predicts, given a piece of computer code running on a
+particular kind of system, what values may be obtained by the code's
+load instructions.  The LKMM makes these predictions for code running
+as part of the Linux kernel.
+
+In practice, people tend to use memory models the other way around.
+That is, given a piece of code and a collection of values specified
+for the loads, the model will predict whether it is possible for the
+code to run in such a way that the loads will indeed obtain the
+specified values.  Of course, this is just another way of expressing
+the same idea.
+
+For code running on a uniprocessor system, the predictions are easy:
+Each load instruction must obtain the value written by the most recent
+store instruction accessing the same location (we ignore complicating
+factors such as DMA and mixed-size accesses.)  But on multiprocessor
+systems, with multiple CPUs making concurrent accesses to shared
+memory locations, things aren't so simple.
+
+Different architectures have differing memory models, and the Linux
+kernel supports a variety of architectures.  The LKMM has to be fairly
+permissive, in the sense that any behavior allowed by one of these
+architectures also has to be allowed by the LKMM.
+
+
+A SIMPLE EXAMPLE
+----------------
+
+Here is a simple example to illustrate the basic concepts.  Consider
+some code running as part of a device driver for an input device.  The
+driver might contain an interrupt handler which collects data from the
+device, stores it in a buffer, and sets a flag to indicate the buffer
+is full.  Running concurrently on a different CPU might be a part of
+the driver code being executed by a process in the midst of a read(2)
+system call.  This code tests the flag to see whether the buffer is
+ready, and if it is, copies the data back to userspace.  The buffer
+and the flag are memory locations shared between the two CPUs.
+
+We can abstract out the important pieces of the driver code as follows
+(the reason for using WRITE_ONCE() and READ_ONCE() instead of simple
+assignment statements is discussed later):
+
+	int buf = 0, flag = 0;
+
+	P0()
+	{
+		WRITE_ONCE(buf, 1);
+		WRITE_ONCE(flag, 1);
+	}
+
+	P1()
+	{
+		int r1;
+		int r2 = 0;
+
+		r1 = READ_ONCE(flag);
+		if (r1)
+			r2 = READ_ONCE(buf);
+	}
+
+Here the P0() function represents the interrupt handler running on one
+CPU and P1() represents the read() routine running on another.  The
+value 1 stored in buf represents input data collected from the device.
+Thus, P0 stores the data in buf and then sets flag.  Meanwhile, P1
+reads flag into the private variable r1, and if it is set, reads the
+data from buf into a second private variable r2 for copying to
+userspace.  (Presumably if flag is not set then the driver will wait a
+while and try again.)
+
+This pattern of memory accesses, where one CPU stores values to two
+shared memory locations and another CPU loads from those locations in
+the opposite order, is widely known as the "Message Passing" or MP
+pattern.  It is typical of memory access patterns in the kernel.
+
+Please note that this example code is a simplified abstraction.  Real
+buffers are usually larger than a single integer, real device drivers
+usually use sleep and wakeup mechanisms rather than polling for I/O
+completion, and real code generally doesn't bother to copy values into
+private variables before using them.  All that is beside the point;
+the idea here is simply to illustrate the overall pattern of memory
+accesses by the CPUs.
+
+A memory model will predict what values P1 might obtain for its loads
+from flag and buf, or equivalently, what values r1 and r2 might end up
+with after the code has finished running.
+
+Some predictions are trivial.  For instance, no sane memory model would
+predict that r1 = 42 or r2 = -7, because neither of those values ever
+gets stored in flag or buf.
+
+Some nontrivial predictions are nonetheless quite simple.  For
+instance, P1 might run entirely before P0 begins, in which case r1 and
+r2 will both be 0 at the end.  Or P0 might run entirely before P1
+begins, in which case r1 and r2 will both be 1.
+
+The interesting predictions concern what might happen when the two
+routines run concurrently.  One possibility is that P1 runs after P0's
+store to buf but before the store to flag.  In this case, r1 and r2
+will again both be 0.  (If P1 had been designed to read buf
+unconditionally then we would instead have r1 = 0 and r2 = 1.)
+
+However, the most interesting possibility is where r1 = 1 and r2 = 0.
+If this were to occur it would mean the driver contains a bug, because
+incorrect data would get sent to the user: 0 instead of 1.  As it
+happens, the LKMM does predict this outcome can occur, and the example
+driver code shown above is indeed buggy.
+
+
+A SELECTION OF MEMORY MODELS
+----------------------------
+
+The first widely cited memory model, and the simplest to understand,
+is Sequential Consistency.  According to this model, systems behave as
+if each CPU executed its instructions in order but with unspecified
+timing.  In other words, the instructions from the various CPUs get
+interleaved in a nondeterministic way, always according to some single
+global order that agrees with the order of the instructions in the
+program source for each CPU.  The model says that the value obtained
+by each load is simply the value written by the most recently executed
+store to the same memory location, from any CPU.
+
+For the MP example code shown above, Sequential Consistency predicts
+that the undesired result r1 = 1, r2 = 0 cannot occur.  The reasoning
+goes like this:
+
+	Since r1 = 1, P0 must store 1 to flag before P1 loads 1 from
+	it, as loads can obtain values only from earlier stores.
+
+	P1 loads from flag before loading from buf, since CPUs execute
+	their instructions in order.
+
+	P1 must load 0 from buf before P0 stores 1 to it; otherwise r2
+	would be 1 since a load obtains its value from the most recent
+	store to the same address.
+
+	P0 stores 1 to buf before storing 1 to flag, since it executes
+	its instructions in order.
+
+	Since an instruction (in this case, P1's store to flag) cannot
+	execute before itself, the specified outcome is impossible.
+
+However, real computer hardware almost never follows the Sequential
+Consistency memory model; doing so would rule out too many valuable
+performance optimizations.  On ARM and PowerPC architectures, for
+instance, the MP example code really does sometimes yield r1 = 1 and
+r2 = 0.
+
+x86 and SPARC follow yet a different memory model: TSO (Total Store
+Ordering).  This model predicts that the undesired outcome for the MP
+pattern cannot occur, but in other respects it differs from Sequential
+Consistency.  One example is the Store Buffer (SB) pattern, in which
+each CPU stores to its own shared location and then loads from the
+other CPU's location:
+
+	int x = 0, y = 0;
+
+	P0()
+	{
+		int r0;
+
+		WRITE_ONCE(x, 1);
+		r0 = READ_ONCE(y);
+	}
+
+	P1()
+	{
+		int r1;
+
+		WRITE_ONCE(y, 1);
+		r1 = READ_ONCE(x);
+	}
+
+Sequential Consistency predicts that the outcome r0 = 0, r1 = 0 is
+impossible.  (Exercise: Figure out the reasoning.)  But TSO allows
+this outcome to occur, and in fact it does sometimes occur on x86 and
+SPARC systems.
+
+The LKMM was inspired by the memory models followed by PowerPC, ARM,
+x86, Alpha, and other architectures.  However, it is different in
+detail from each of them.
+
+
+ORDERING AND CYCLES
+-------------------
+
+Memory models are all about ordering.  Often this is temporal ordering
+(i.e., the order in which certain events occur) but it doesn't have to
+be; consider for example the order of instructions in a program's
+source code.  We saw above that Sequential Consistency makes an
+important assumption that CPUs execute instructions in the same order
+as those instructions occur in the code, and there are many other
+instances of ordering playing central roles in memory models.
+
+The counterpart to ordering is a cycle.  Ordering rules out cycles:
+It's not possible to have X ordered before Y, Y ordered before Z, and
+Z ordered before X, because this would mean that X is ordered before
+itself.  The analysis of the MP example under Sequential Consistency
+involved just such an impossible cycle:
+
+	W: P0 stores 1 to flag   executes before
+	X: P1 loads 1 from flag  executes before
+	Y: P1 loads 0 from buf   executes before
+	Z: P0 stores 1 to buf    executes before
+	W: P0 stores 1 to flag.
+
+In short, if a memory model requires certain accesses to be ordered,
+and a certain outcome for the loads in a piece of code can happen only
+if those accesses would form a cycle, then the memory model predicts
+that outcome cannot occur.
+
+The LKMM is defined largely in terms of cycles, as we will see.
+
+
+EVENTS
+------
+
+The LKMM does not work directly with the C statements that make up
+kernel source code.  Instead it considers the effects of those
+statements in a more abstract form, namely, events.  The model
+includes three types of events:
+
+	Read events correspond to loads from shared memory, such as
+	calls to READ_ONCE(), smp_load_acquire(), or
+	rcu_dereference().
+
+	Write events correspond to stores to shared memory, such as
+	calls to WRITE_ONCE(), smp_store_release(), or atomic_set().
+
+	Fence events correspond to memory barriers (also known as
+	fences), such as calls to smp_rmb() or rcu_read_lock().
+
+These categories are not exclusive; a read or write event can also be
+a fence.  This happens with functions like smp_load_acquire() or
+spin_lock().  However, no single event can be both a read and a write.
+Atomic read-modify-write accesses, such as atomic_inc() or xchg(),
+correspond to a pair of events: a read followed by a write.  (The
+write event is omitted for executions where it doesn't occur, such as
+a cmpxchg() where the comparison fails.)
+
+Other parts of the code, those which do not involve interaction with
+shared memory, do not give rise to events.  Thus, arithmetic and
+logical computations, control-flow instructions, or accesses to
+private memory or CPU registers are not of central interest to the
+memory model.  They only affect the model's predictions indirectly.
+For example, an arithmetic computation might determine the value that
+gets stored to a shared memory location (or in the case of an array
+index, the address where the value gets stored), but the memory model
+is concerned only with the store itself -- its value and its address
+-- not the computation leading up to it.
+
+Events in the LKMM can be linked by various relations, which we will
+describe in the following sections.  The memory model requires certain
+of these relations to be orderings, that is, it requires them not to
+have any cycles.
+
+
+THE PROGRAM ORDER RELATION: po AND po-loc
+-----------------------------------------
+
+The most important relation between events is program order (po).  You
+can think of it as the order in which statements occur in the source
+code after branches are taken into account and loops have been
+unrolled.  A better description might be the order in which
+instructions are presented to a CPU's execution unit.  Thus, we say
+that X is po-before Y (written as "X ->po Y" in formulas) if X occurs
+before Y in the instruction stream.
+
+This is inherently a single-CPU relation; two instructions executing
+on different CPUs are never linked by po.  Also, it is by definition
+an ordering so it cannot have any cycles.
+
+po-loc is a sub-relation of po.  It links two memory accesses when the
+first comes before the second in program order and they access the
+same memory location (the "-loc" suffix).
+
+Although this may seem straightforward, there is one subtle aspect to
+program order we need to explain.  The LKMM was inspired by low-level
+architectural memory models which describe the behavior of machine
+code, and it retains their outlook to a considerable extent.  The
+read, write, and fence events used by the model are close in spirit to
+individual machine instructions.  Nevertheless, the LKMM describes
+kernel code written in C, and the mapping from C to machine code can
+be extremely complex.
+
+Optimizing compilers have great freedom in the way they translate
+source code to object code.  They are allowed to apply transformations
+that add memory accesses, eliminate accesses, combine them, split them
+into pieces, or move them around.  Faced with all these possibilities,
+the LKMM basically gives up.  It insists that the code it analyzes
+must contain no ordinary accesses to shared memory; all accesses must
+be performed using READ_ONCE(), WRITE_ONCE(), or one of the other
+atomic or synchronization primitives.  These primitives prevent a
+large number of compiler optimizations.  In particular, it is
+guaranteed that the compiler will not remove such accesses from the
+generated code (unless it can prove the accesses will never be
+executed), it will not change the order in which they occur in the
+code (within limits imposed by the C standard), and it will not
+introduce extraneous accesses.
+
+This explains why the MP and SB examples above used READ_ONCE() and
+WRITE_ONCE() rather than ordinary memory accesses.  Thanks to this
+usage, we can be certain that in the MP example, P0's write event to
+buf really is po-before its write event to flag, and similarly for the
+other shared memory accesses in the examples.
+
+Private variables are not subject to this restriction.  Since they are
+not shared between CPUs, they can be accessed normally without
+READ_ONCE() or WRITE_ONCE(), and there will be no ill effects.  In
+fact, they need not even be stored in normal memory at all -- in
+principle a private variable could be stored in a CPU register (hence
+the convention that these variables have names starting with the
+letter 'r').
+
+
+A WARNING
+---------
+
+The protections provided by READ_ONCE(), WRITE_ONCE(), and others are
+not perfect; and under some circumstances it is possible for the
+compiler to undermine the memory model.  Here is an example.  Suppose
+both branches of an "if" statement store the same value to the same
+location:
+
+	r1 = READ_ONCE(x);
+	if (r1) {
+		WRITE_ONCE(y, 2);
+		...  /* do something */
+	} else {
+		WRITE_ONCE(y, 2);
+		...  /* do something else */
+	}
+
+For this code, the LKMM predicts that the load from x will always be
+executed before either of the stores to y.  However, a compiler could
+lift the stores out of the conditional, transforming the code into
+something resembling:
+
+	r1 = READ_ONCE(x);
+	WRITE_ONCE(y, 2);
+	if (r1) {
+		...  /* do something */
+	} else {
+		...  /* do something else */
+	}
+
+Given this version of the code, the LKMM would predict that the load
+from x could be executed after the store to y.  Thus, the memory
+model's original prediction could be invalidated by the compiler.
+
+Another issue arises from the fact that in C, arguments to many
+operators and function calls can be evaluated in any order.  For
+example:
+
+	r1 = f(5) + g(6);
+
+The object code might call f(5) either before or after g(6); the
+memory model cannot assume there is a fixed program order relation
+between them.  (In fact, if the functions are inlined then the
+compiler might even interleave their object code.)
+
+
+DEPENDENCY RELATIONS: data, addr, and ctrl
+------------------------------------------
+
+We say that two events are linked by a dependency relation when the
+execution of the second event depends in some way on a value obtained
+from memory by the first.  The first event must be a read, and the
+value it obtains must somehow affect what the second event does.
+There are three kinds of dependencies: data, address (addr), and
+control (ctrl).
+
+A read and a write event are linked by a data dependency if the value
+obtained by the read affects the value stored by the write.  As a very
+simple example:
+
+	int x, y;
+
+	r1 = READ_ONCE(x);
+	WRITE_ONCE(y, r1 + 5);
+
+The value stored by the WRITE_ONCE obviously depends on the value
+loaded by the READ_ONCE.  Such dependencies can wind through
+arbitrarily complicated computations, and a write can depend on the
+values of multiple reads.
+
+A read event and another memory access event are linked by an address
+dependency if the value obtained by the read affects the location
+accessed by the other event.  The second event can be either a read or
+a write.  Here's another simple example:
+
+	int a[20];
+	int i;
+
+	r1 = READ_ONCE(i);
+	r2 = READ_ONCE(a[r1]);
+
+Here the location accessed by the second READ_ONCE() depends on the
+index value loaded by the first.  Pointer indirection also gives rise
+to address dependencies, since the address of a location accessed
+through a pointer will depend on the value read earlier from that
+pointer.
+
+Finally, a read event and another memory access event are linked by a
+control dependency if the value obtained by the read affects whether
+the second event is executed at all.  Simple example:
+
+	int x, y;
+
+	r1 = READ_ONCE(x);
+	if (r1)
+		WRITE_ONCE(y, 1984);
+
+Execution of the WRITE_ONCE() is controlled by a conditional expression
+which depends on the value obtained by the READ_ONCE(); hence there is
+a control dependency from the load to the store.
+
+It should be pretty obvious that events can only depend on reads that
+come earlier in program order.  Symbolically, if we have R ->data X,
+R ->addr X, or R ->ctrl X (where R is a read event), then we must also
+have R ->po X.  It wouldn't make sense for a computation to depend
+somehow on a value that doesn't get loaded from shared memory until
+later in the code!
+
+
+THE READS-FROM RELATION: rf, rfi, and rfe
+-----------------------------------------
+
+The reads-from relation (rf) links a write event to a read event when
+the value loaded by the read is the value that was stored by the
+write.  In colloquial terms, the load "reads from" the store.  We
+write W ->rf R to indicate that the load R reads from the store W.  We
+further distinguish the cases where the load and the store occur on
+the same CPU (internal reads-from, or rfi) and where they occur on
+different CPUs (external reads-from, or rfe).
+
+For our purposes, a memory location's initial value is treated as
+though it had been written there by an imaginary initial store that
+executes on a separate CPU before the program runs.
+
+Usage of the rf relation implicitly assumes that loads will always
+read from a single store.  It doesn't apply properly in the presence
+of load-tearing, where a load obtains some of its bits from one store
+and some of them from another store.  Fortunately, use of READ_ONCE()
+and WRITE_ONCE() will prevent load-tearing; it's not possible to have:
+
+	int x = 0;
+
+	P0()
+	{
+		WRITE_ONCE(x, 0x1234);
+	}
+
+	P1()
+	{
+		int r1;
+
+		r1 = READ_ONCE(x);
+	}
+
+and end up with r1 = 0x1200 (partly from x's initial value and partly
+from the value stored by P0).
+
+On the other hand, load-tearing is unavoidable when mixed-size
+accesses are used.  Consider this example:
+
+	union {
+		u32	w;
+		u16	h[2];
+	} x;
+
+	P0()
+	{
+		WRITE_ONCE(x.h[0], 0x1234);
+		WRITE_ONCE(x.h[1], 0x5678);
+	}
+
+	P1()
+	{
+		int r1;
+
+		r1 = READ_ONCE(x.w);
+	}
+
+If r1 = 0x56781234 (little-endian!) at the end, then P1 must have read
+from both of P0's stores.  It is possible to handle mixed-size and
+unaligned accesses in a memory model, but the LKMM currently does not
+attempt to do so.  It requires all accesses to be properly aligned and
+of the location's actual size.
+
+
+CACHE COHERENCE AND THE COHERENCE ORDER RELATION: co, coi, and coe
+------------------------------------------------------------------
+
+Cache coherence is a general principle requiring that in a
+multi-processor system, the CPUs must share a consistent view of the
+memory contents.  Specifically, it requires that for each location in
+shared memory, the stores to that location must form a single global
+ordering which all the CPUs agree on (the coherence order), and this
+ordering must be consistent with the program order for accesses to
+that location.
+
+To put it another way, for any variable x, the coherence order (co) of
+the stores to x is simply the order in which the stores overwrite one
+another.  The imaginary store which establishes x's initial value
+comes first in the coherence order; the store which directly
+overwrites the initial value comes second; the store which overwrites
+that value comes third, and so on.
+
+You can think of the coherence order as being the order in which the
+stores reach x's location in memory (or if you prefer a more
+hardware-centric view, the order in which the stores get written to
+x's cache line).  We write W ->co W' if W comes before W' in the
+coherence order, that is, if the value stored by W gets overwritten,
+directly or indirectly, by the value stored by W'.
+
+Coherence order is required to be consistent with program order.  This
+requirement takes the form of four coherency rules:
+
+	Write-write coherence: If W ->po-loc W' (i.e., W comes before
+	W' in program order and they access the same location), where W
+	and W' are two stores, then W ->co W'.
+
+	Write-read coherence: If W ->po-loc R, where W is a store and R
+	is a load, then R must read from W or from some other store
+	which comes after W in the coherence order.
+
+	Read-write coherence: If R ->po-loc W, where R is a load and W
+	is a store, then the store which R reads from must come before
+	W in the coherence order.
+
+	Read-read coherence: If R ->po-loc R', where R and R' are two
+	loads, then either they read from the same store or else the
+	store read by R comes before the store read by R' in the
+	coherence order.
+
+This is sometimes referred to as sequential consistency per variable,
+because it means that the accesses to any single memory location obey
+the rules of the Sequential Consistency memory model.  (According to
+Wikipedia, sequential consistency per variable and cache coherence
+mean the same thing except that cache coherence includes an extra
+requirement that every store eventually becomes visible to every CPU.)
+
+Any reasonable memory model will include cache coherence.  Indeed, our
+expectation of cache coherence is so deeply ingrained that violations
+of its requirements look more like hardware bugs than programming
+errors:
+
+	int x;
+
+	P0()
+	{
+		WRITE_ONCE(x, 17);
+		WRITE_ONCE(x, 23);
+	}
+
+If the final value stored in x after this code ran was 17, you would
+think your computer was broken.  It would be a violation of the
+write-write coherence rule: Since the store of 23 comes later in
+program order, it must also come later in x's coherence order and
+thus must overwrite the store of 17.
+
+	int x = 0;
+
+	P0()
+	{
+		int r1;
+
+		r1 = READ_ONCE(x);
+		WRITE_ONCE(x, 666);
+	}
+
+If r1 = 666 at the end, this would violate the read-write coherence
+rule: The READ_ONCE() load comes before the WRITE_ONCE() store in
+program order, so it must not read from that store but rather from one
+coming earlier in the coherence order (in this case, x's initial
+value).
+
+	int x = 0;
+
+	P0()
+	{
+		WRITE_ONCE(x, 5);
+	}
+
+	P1()
+	{
+		int r1, r2;
+
+		r1 = READ_ONCE(x);
+		r2 = READ_ONCE(x);
+	}
+
+If r1 = 5 (reading from P0's store) and r2 = 0 (reading from the
+imaginary store which establishes x's initial value) at the end, this
+would violate the read-read coherence rule: The r1 load comes before
+the r2 load in program order, so it must not read from a store that
+comes later in the coherence order.
+
+(As a minor curiosity, if this code had used normal loads instead of
+READ_ONCE() in P1, on Itanium it sometimes could end up with r1 = 5
+and r2 = 0!  This results from parallel execution of the operations
+encoded in Itanium's Very-Long-Instruction-Word format, and it is yet
+another motivation for using READ_ONCE() when accessing shared memory
+locations.)
+
+Just like the po relation, co is inherently an ordering -- it is not
+possible for a store to directly or indirectly overwrite itself!  And
+just like with the rf relation, we distinguish between stores that
+occur on the same CPU (internal coherence order, or coi) and stores
+that occur on different CPUs (external coherence order, or coe).
+
+On the other hand, stores to different memory locations are never
+related by co, just as instructions on different CPUs are never
+related by po.  Coherence order is strictly per-location, or if you
+prefer, each location has its own independent coherence order.
+
+
+THE FROM-READS RELATION: fr, fri, and fre
+-----------------------------------------
+
+The from-reads relation (fr) can be a little difficult for people to
+grok.  It describes the situation where a load reads a value that gets
+overwritten by a store.  In other words, we have R ->fr W when the
+value that R reads is overwritten (directly or indirectly) by W, or
+equivalently, when R reads from a store which comes earlier than W in
+the coherence order.
+
+For example:
+
+	int x = 0;
+
+	P0()
+	{
+		int r1;
+
+		r1 = READ_ONCE(x);
+		WRITE_ONCE(x, 2);
+	}
+
+The value loaded from x will be 0 (assuming cache coherence!), and it
+gets overwritten by the value 2.  Thus there is an fr link from the
+READ_ONCE() to the WRITE_ONCE().  If the code contained any later
+stores to x, there would also be fr links from the READ_ONCE() to
+them.
+
+As with rf, rfi, and rfe, we subdivide the fr relation into fri (when
+the load and the store are on the same CPU) and fre (when they are on
+different CPUs).
+
+Note that the fr relation is determined entirely by the rf and co
+relations; it is not independent.  Given a read event R and a write
+event W for the same location, we will have R ->fr W if and only if
+the write which R reads from is co-before W.  In symbols,
+
+	(R ->fr W) := (there exists W' with W' ->rf R and W' ->co W).
+
+
+AN OPERATIONAL MODEL
+--------------------
+
+The LKMM is based on various operational memory models, meaning that
+the models arise from an abstract view of how a computer system
+operates.  Here are the main ideas, as incorporated into the LKMM.
+
+The system as a whole is divided into the CPUs and a memory subsystem.
+The CPUs are responsible for executing instructions (not necessarily
+in program order), and they communicate with the memory subsystem.
+For the most part, executing an instruction requires a CPU to perform
+only internal operations.  However, loads, stores, and fences involve
+more.
+
+When CPU C executes a store instruction, it tells the memory subsystem
+to store a certain value at a certain location.  The memory subsystem
+propagates the store to all the other CPUs as well as to RAM.  (As a
+special case, we say that the store propagates to its own CPU at the
+time it is executed.)  The memory subsystem also determines where the
+store falls in the location's coherence order.  In particular, it must
+arrange for the store to be co-later than (i.e., to overwrite) any
+other store to the same location which has already propagated to CPU C.
+
+When a CPU executes a load instruction R, it first checks to see
+whether there are any as-yet unexecuted store instructions, for the
+same location, that come before R in program order.  If there are, it
+uses the value of the po-latest such store as the value obtained by R,
+and we say that the store's value is forwarded to R.  Otherwise, the
+CPU asks the memory subsystem for the value to load and we say that R
+is satisfied from memory.  The memory subsystem hands back the value
+of the co-latest store to the location in question which has already
+propagated to that CPU.
+
+(In fact, the picture needs to be a little more complicated than this.
+CPUs have local caches, and propagating a store to a CPU really means
+propagating it to the CPU's local cache.  A local cache can take some
+time to process the stores that it receives, and a store can't be used
+to satisfy one of the CPU's loads until it has been processed.  On
+most architectures, the local caches process stores in
+First-In-First-Out order, and consequently the processing delay
+doesn't matter for the memory model.  But on Alpha, the local caches
+have a partitioned design that results in non-FIFO behavior.  We will
+discuss this in more detail later.)
+
+Note that load instructions may be executed speculatively and may be
+restarted under certain circumstances.  The memory model ignores these
+premature executions; we simply say that the load executes at the
+final time it is forwarded or satisfied.
+
+Executing a fence (or memory barrier) instruction doesn't require a
+CPU to do anything special other than informing the memory subsystem
+about the fence.  However, fences do constrain the way CPUs and the
+memory subsystem handle other instructions, in two respects.
+
+First, a fence forces the CPU to execute various instructions in
+program order.  Exactly which instructions are ordered depends on the
+type of fence:
+
+	Strong fences, including smp_mb() and synchronize_rcu(), force
+	the CPU to execute all po-earlier instructions before any
+	po-later instructions;
+
+	smp_rmb() forces the CPU to execute all po-earlier loads
+	before any po-later loads;
+
+	smp_wmb() forces the CPU to execute all po-earlier stores
+	before any po-later stores;
+
+	Acquire fences, such as smp_load_acquire(), force the CPU to
+	execute the load associated with the fence (e.g., the load
+	part of an smp_load_acquire()) before any po-later
+	instructions;
+
+	Release fences, such as smp_store_release(), force the CPU to
+	execute all po-earlier instructions before the store
+	associated with the fence (e.g., the store part of an
+	smp_store_release()).
+
+Second, some types of fence affect the way the memory subsystem
+propagates stores.  When a fence instruction is executed on CPU C:
+
+	For each other CPU C', smb_wmb() forces all po-earlier stores
+	on C to propagate to C' before any po-later stores do.
+
+	For each other CPU C', any store which propagates to C before
+	a release fence is executed (including all po-earlier
+	stores executed on C) is forced to propagate to C' before the
+	store associated with the release fence does.
+
+	Any store which propagates to C before a strong fence is
+	executed (including all po-earlier stores on C) is forced to
+	propagate to all other CPUs before any instructions po-after
+	the strong fence are executed on C.
+
+The propagation ordering enforced by release fences and strong fences
+affects stores from other CPUs that propagate to CPU C before the
+fence is executed, as well as stores that are executed on C before the
+fence.  We describe this property by saying that release fences and
+strong fences are A-cumulative.  By contrast, smp_wmb() fences are not
+A-cumulative; they only affect the propagation of stores that are
+executed on C before the fence (i.e., those which precede the fence in
+program order).
+
+smp_read_barrier_depends(), rcu_read_lock(), rcu_read_unlock(), and
+synchronize_rcu() fences have other properties which we discuss later.
+
+
+PROPAGATION ORDER RELATION: cumul-fence
+---------------------------------------
+
+The fences which affect propagation order (i.e., strong, release, and
+smp_wmb() fences) are collectively referred to as cumul-fences, even
+though smp_wmb() isn't A-cumulative.  The cumul-fence relation is
+defined to link memory access events E and F whenever:
+
+	E and F are both stores on the same CPU and an smp_wmb() fence
+	event occurs between them in program order; or
+
+	F is a release fence and some X comes before F in program order,
+	where either X = E or else E ->rf X; or
+
+	A strong fence event occurs between some X and F in program
+	order, where either X = E or else E ->rf X.
+
+The operational model requires that whenever W and W' are both stores
+and W ->cumul-fence W', then W must propagate to any given CPU
+before W' does.  However, for different CPUs C and C', it does not
+require W to propagate to C before W' propagates to C'.
+
+
+DERIVATION OF THE LKMM FROM THE OPERATIONAL MODEL
+-------------------------------------------------
+
+The LKMM is derived from the restrictions imposed by the design
+outlined above.  These restrictions involve the necessity of
+maintaining cache coherence and the fact that a CPU can't operate on a
+value before it knows what that value is, among other things.
+
+The formal version of the LKMM is defined by five requirements, or
+axioms:
+
+	Sequential consistency per variable: This requires that the
+	system obey the four coherency rules.
+
+	Atomicity: This requires that atomic read-modify-write
+	operations really are atomic, that is, no other stores can
+	sneak into the middle of such an update.
+
+	Happens-before: This requires that certain instructions are
+	executed in a specific order.
+
+	Propagation: This requires that certain stores propagate to
+	CPUs and to RAM in a specific order.
+
+	Rcu: This requires that RCU read-side critical sections and
+	grace periods obey the rules of RCU, in particular, the
+	Grace-Period Guarantee.
+
+The first and second are quite common; they can be found in many
+memory models (such as those for C11/C++11).  The "happens-before" and
+"propagation" axioms have analogs in other memory models as well.  The
+"rcu" axiom is specific to the LKMM.
+
+Each of these axioms is discussed below.
+
+
+SEQUENTIAL CONSISTENCY PER VARIABLE
+-----------------------------------
+
+According to the principle of cache coherence, the stores to any fixed
+shared location in memory form a global ordering.  We can imagine
+inserting the loads from that location into this ordering, by placing
+each load between the store that it reads from and the following
+store.  This leaves the relative positions of loads that read from the
+same store unspecified; let's say they are inserted in program order,
+first for CPU 0, then CPU 1, etc.
+
+You can check that the four coherency rules imply that the rf, co, fr,
+and po-loc relations agree with this global ordering; in other words,
+whenever we have X ->rf Y or X ->co Y or X ->fr Y or X ->po-loc Y, the
+X event comes before the Y event in the global ordering.  The LKMM's
+"coherence" axiom expresses this by requiring the union of these
+relations not to have any cycles.  This means it must not be possible
+to find events
+
+	X0 -> X1 -> X2 -> ... -> Xn -> X0,
+
+where each of the links is either rf, co, fr, or po-loc.  This has to
+hold if the accesses to the fixed memory location can be ordered as
+cache coherence demands.
+
+Although it is not obvious, it can be shown that the converse is also
+true: This LKMM axiom implies that the four coherency rules are
+obeyed.
+
+
+ATOMIC UPDATES: rmw
+-------------------
+
+What does it mean to say that a read-modify-write (rmw) update, such
+as atomic_inc(&x), is atomic?  It means that the memory location (x in
+this case) does not get altered between the read and the write events
+making up the atomic operation.  In particular, if two CPUs perform
+atomic_inc(&x) concurrently, it must be guaranteed that the final
+value of x will be the initial value plus two.  We should never have
+the following sequence of events:
+
+	CPU 0 loads x obtaining 13;
+					CPU 1 loads x obtaining 13;
+	CPU 0 stores 14 to x;
+					CPU 1 stores 14 to x;
+
+where the final value of x is wrong (14 rather than 15).
+
+In this example, CPU 0's increment effectively gets lost because it
+occurs in between CPU 1's load and store.  To put it another way, the
+problem is that the position of CPU 0's store in x's coherence order
+is between the store that CPU 1 reads from and the store that CPU 1
+performs.
+
+The same analysis applies to all atomic update operations.  Therefore,
+to enforce atomicity the LKMM requires that atomic updates follow this
+rule: Whenever R and W are the read and write events composing an
+atomic read-modify-write and W' is the write event which R reads from,
+there must not be any stores coming between W' and W in the coherence
+order.  Equivalently,
+
+	(R ->rmw W) implies (there is no X with R ->fr X and X ->co W),
+
+where the rmw relation links the read and write events making up each
+atomic update.  This is what the LKMM's "atomic" axiom says.
+
+
+THE PRESERVED PROGRAM ORDER RELATION: ppo
+-----------------------------------------
+
+There are many situations where a CPU is obligated to execute two
+instructions in program order.  We amalgamate them into the ppo (for
+"preserved program order") relation, which links the po-earlier
+instruction to the po-later instruction and is thus a sub-relation of
+po.
+
+The operational model already includes a description of one such
+situation: Fences are a source of ppo links.  Suppose X and Y are
+memory accesses with X ->po Y; then the CPU must execute X before Y if
+any of the following hold:
+
+	A strong (smp_mb() or synchronize_rcu()) fence occurs between
+	X and Y;
+
+	X and Y are both stores and an smp_wmb() fence occurs between
+	them;
+
+	X and Y are both loads and an smp_rmb() fence occurs between
+	them;
+
+	X is also an acquire fence, such as smp_load_acquire();
+
+	Y is also a release fence, such as smp_store_release().
+
+Another possibility, not mentioned earlier but discussed in the next
+section, is:
+
+	X and Y are both loads, X ->addr Y (i.e., there is an address
+	dependency from X to Y), and an smp_read_barrier_depends()
+	fence occurs between them.
+
+Dependencies can also cause instructions to be executed in program
+order.  This is uncontroversial when the second instruction is a
+store; either a data, address, or control dependency from a load R to
+a store W will force the CPU to execute R before W.  This is very
+simply because the CPU cannot tell the memory subsystem about W's
+store before it knows what value should be stored (in the case of a
+data dependency), what location it should be stored into (in the case
+of an address dependency), or whether the store should actually take
+place (in the case of a control dependency).
+
+Dependencies to load instructions are more problematic.  To begin with,
+there is no such thing as a data dependency to a load.  Next, a CPU
+has no reason to respect a control dependency to a load, because it
+can always satisfy the second load speculatively before the first, and
+then ignore the result if it turns out that the second load shouldn't
+be executed after all.  And lastly, the real difficulties begin when
+we consider address dependencies to loads.
+
+To be fair about it, all Linux-supported architectures do execute
+loads in program order if there is an address dependency between them.
+After all, a CPU cannot ask the memory subsystem to load a value from
+a particular location before it knows what that location is.  However,
+the split-cache design used by Alpha can cause it to behave in a way
+that looks as if the loads were executed out of order (see the next
+section for more details).  For this reason, the LKMM does not include
+address dependencies between read events in the ppo relation unless an
+smp_read_barrier_depends() fence is present.
+
+On the other hand, dependencies can indirectly affect the ordering of
+two loads.  This happens when there is a dependency from a load to a
+store and a second, po-later load reads from that store:
+
+	R ->dep W ->rfi R',
+
+where the dep link can be either an address or a data dependency.  In
+this situation we know it is possible for the CPU to execute R' before
+W, because it can forward the value that W will store to R'.  But it
+cannot execute R' before R, because it cannot forward the value before
+it knows what that value is, or that W and R' do access the same
+location.  However, if there is merely a control dependency between R
+and W then the CPU can speculatively forward W to R' before executing
+R; if the speculation turns out to be wrong then the CPU merely has to
+restart or abandon R'.
+
+(In theory, a CPU might forward a store to a load when it runs across
+an address dependency like this:
+
+	r1 = READ_ONCE(ptr);
+	WRITE_ONCE(*r1, 17);
+	r2 = READ_ONCE(*r1);
+
+because it could tell that the store and the second load access the
+same location even before it knows what the location's address is.
+However, none of the architectures supported by the Linux kernel do
+this.)
+
+Two memory accesses of the same location must always be executed in
+program order if the second access is a store.  Thus, if we have
+
+	R ->po-loc W
+
+(the po-loc link says that R comes before W in program order and they
+access the same location), the CPU is obliged to execute W after R.
+If it executed W first then the memory subsystem would respond to R's
+read request with the value stored by W (or an even later store), in
+violation of the read-write coherence rule.  Similarly, if we had
+
+	W ->po-loc W'
+
+and the CPU executed W' before W, then the memory subsystem would put
+W' before W in the coherence order.  It would effectively cause W to
+overwrite W', in violation of the write-write coherence rule.
+(Interestingly, an early ARMv8 memory model, now obsolete, proposed
+allowing out-of-order writes like this to occur.  The model avoided
+violating the write-write coherence rule by requiring the CPU not to
+send the W write to the memory subsystem at all!)
+
+There is one last example of preserved program order in the LKMM: when
+a load-acquire reads from an earlier store-release.  For example:
+
+	smp_store_release(&x, 123);
+	r1 = smp_load_acquire(&x);
+
+If the smp_load_acquire() ends up obtaining the 123 value that was
+stored by the smp_store_release(), the LKMM says that the load must be
+executed after the store; the store cannot be forwarded to the load.
+This requirement does not arise from the operational model, but it
+yields correct predictions on all architectures supported by the Linux
+kernel, although for differing reasons.
+
+On some architectures, including x86 and ARMv8, it is true that the
+store cannot be forwarded to the load.  On others, including PowerPC
+and ARMv7, smp_store_release() generates object code that starts with
+a fence and smp_load_acquire() generates object code that ends with a
+fence.  The upshot is that even though the store may be forwarded to
+the load, it is still true that any instruction preceding the store
+will be executed before the load or any following instructions, and
+the store will be executed before any instruction following the load.
+
+
+AND THEN THERE WAS ALPHA
+------------------------
+
+As mentioned above, the Alpha architecture is unique in that it does
+not appear to respect address dependencies to loads.  This means that
+code such as the following:
+
+	int x = 0;
+	int y = -1;
+	int *ptr = &y;
+
+	P0()
+	{
+		WRITE_ONCE(x, 1);
+		smp_wmb();
+		WRITE_ONCE(ptr, &x);
+	}
+
+	P1()
+	{
+		int *r1;
+		int r2;
+
+		r1 = READ_ONCE(ptr);
+		r2 = READ_ONCE(*r1);
+	}
+
+can malfunction on Alpha systems.  It is quite possible that r1 = &x
+and r2 = 0 at the end, in spite of the address dependency.
+
+At first glance this doesn't seem to make sense.  We know that the
+smp_wmb() forces P0's store to x to propagate to P1 before the store
+to ptr does.  And since P1 can't execute its second load
+until it knows what location to load from, i.e., after executing its
+first load, the value x = 1 must have propagated to P1 before the
+second load executed.  So why doesn't r2 end up equal to 1?
+
+The answer lies in the Alpha's split local caches.  Although the two
+stores do reach P1's local cache in the proper order, it can happen
+that the first store is processed by a busy part of the cache while
+the second store is processed by an idle part.  As a result, the x = 1
+value may not become available for P1's CPU to read until after the
+ptr = &x value does, leading to the undesirable result above.  The
+final effect is that even though the two loads really are executed in
+program order, it appears that they aren't.
+
+This could not have happened if the local cache had processed the
+incoming stores in FIFO order.  In constrast, other architectures
+maintain at least the appearance of FIFO order.
+
+In practice, this difficulty is solved by inserting an
+smp_read_barrier_depends() fence between P1's two loads.  The effect
+of this fence is to cause the CPU not to execute any po-later
+instructions until after the local cache has finished processing all
+the stores it has already received.  Thus, if the code was changed to:
+
+	P1()
+	{
+		int *r1;
+		int r2;
+
+		r1 = READ_ONCE(ptr);
+		smp_read_barrier_depends();
+		r2 = READ_ONCE(*r1);
+	}
+
+then we would never get r1 = &x and r2 = 0.  By the time P1 executed
+its second load, the x = 1 store would already be fully processed by
+the local cache and available for satisfying the read request.
+
+The LKMM requires that smp_rmb(), acquire fences, and strong fences
+share this property with smp_read_barrier_depends(): They do not allow
+the CPU to execute any po-later instructions (or po-later loads in the
+case of smp_rmb()) until all outstanding stores have been processed by
+the local cache.  In the case of a strong fence, the CPU first has to
+wait for all of its po-earlier stores to propagate to every other CPU
+in the system; then it has to wait for the local cache to process all
+the stores received as of that time -- not just the stores received
+when the strong fence began.
+
+And of course, none of this matters for any architecture other than
+Alpha.
+
+
+THE HAPPENS-BEFORE RELATION: hb
+-------------------------------
+
+The happens-before relation (hb) links memory accesses that have to
+execute in a certain order.  hb includes the ppo relation and two
+others, one of which is rfe.
+
+W ->rfe R implies that W and R are on different CPUs.  It also means
+that W's store must have propagated to R's CPU before R executed;
+otherwise R could not have read the value stored by W.  Therefore W
+must have executed before R, and so we have W ->hb R.
+
+The equivalent fact need not hold if W ->rfi R (i.e., W and R are on
+the same CPU).  As we have already seen, the operational model allows
+W's value to be forwarded to R in such cases, meaning that R may well
+execute before W does.
+
+It's important to understand that neither coe nor fre is included in
+hb, despite their similarities to rfe.  For example, suppose we have
+W ->coe W'.  This means that W and W' are stores to the same location,
+they execute on different CPUs, and W comes before W' in the coherence
+order (i.e., W' overwrites W).  Nevertheless, it is possible for W' to
+execute before W, because the decision as to which store overwrites
+the other is made later by the memory subsystem.  When the stores are
+nearly simultaneous, either one can come out on top.  Similarly,
+R ->fre W means that W overwrites the value which R reads, but it
+doesn't mean that W has to execute after R.  All that's necessary is
+for the memory subsystem not to propagate W to R's CPU until after R
+has executed, which is possible if W executes shortly before R.
+
+The third relation included in hb is like ppo, in that it only links
+events that are on the same CPU.  However it is more difficult to
+explain, because it arises only indirectly from the requirement of
+cache coherence.  The relation is called prop, and it links two events
+on CPU C in situations where a store from some other CPU comes after
+the first event in the coherence order and propagates to C before the
+second event executes.
+
+This is best explained with some examples.  The simplest case looks
+like this:
+
+	int x;
+
+	P0()
+	{
+		int r1;
+
+		WRITE_ONCE(x, 1);
+		r1 = READ_ONCE(x);
+	}
+
+	P1()
+	{
+		WRITE_ONCE(x, 8);
+	}
+
+If r1 = 8 at the end then P0's accesses must have executed in program
+order.  We can deduce this from the operational model; if P0's load
+had executed before its store then the value of the store would have
+been forwarded to the load, so r1 would have ended up equal to 1, not
+8.  In this case there is a prop link from P0's write event to its read
+event, because P1's store came after P0's store in x's coherence
+order, and P1's store propagated to P0 before P0's load executed.
+
+An equally simple case involves two loads of the same location that
+read from different stores:
+
+	int x = 0;
+
+	P0()
+	{
+		int r1, r2;
+
+		r1 = READ_ONCE(x);
+		r2 = READ_ONCE(x);
+	}
+
+	P1()
+	{
+		WRITE_ONCE(x, 9);
+	}
+
+If r1 = 0 and r2 = 9 at the end then P0's accesses must have executed
+in program order.  If the second load had executed before the first
+then the x = 9 store must have been propagated to P0 before the first
+load executed, and so r1 would have been 9 rather than 0.  In this
+case there is a prop link from P0's first read event to its second,
+because P1's store overwrote the value read by P0's first load, and
+P1's store propagated to P0 before P0's second load executed.
+
+Less trivial examples of prop all involve fences.  Unlike the simple
+examples above, they can require that some instructions are executed
+out of program order.  This next one should look familiar:
+
+	int buf = 0, flag = 0;
+
+	P0()
+	{
+		WRITE_ONCE(buf, 1);
+		smp_wmb();
+		WRITE_ONCE(flag, 1);
+	}
+
+	P1()
+	{
+		int r1;
+		int r2;
+
+		r1 = READ_ONCE(flag);
+		r2 = READ_ONCE(buf);
+	}
+
+This is the MP pattern again, with an smp_wmb() fence between the two
+stores.  If r1 = 1 and r2 = 0 at the end then there is a prop link
+from P1's second load to its first (backwards!).  The reason is
+similar to the previous examples: The value P1 loads from buf gets
+overwritten by P0's store to buf, the fence guarantees that the store
+to buf will propagate to P1 before the store to flag does, and the
+store to flag propagates to P1 before P1 reads flag.
+
+The prop link says that in order to obtain the r1 = 1, r2 = 0 result,
+P1 must execute its second load before the first.  Indeed, if the load
+from flag were executed first, then the buf = 1 store would already
+have propagated to P1 by the time P1's load from buf executed, so r2
+would have been 1 at the end, not 0.  (The reasoning holds even for
+Alpha, although the details are more complicated and we will not go
+into them.)
+
+But what if we put an smp_rmb() fence between P1's loads?  The fence
+would force the two loads to be executed in program order, and it
+would generate a cycle in the hb relation: The fence would create a ppo
+link (hence an hb link) from the first load to the second, and the
+prop relation would give an hb link from the second load to the first.
+Since an instruction can't execute before itself, we are forced to
+conclude that if an smp_rmb() fence is added, the r1 = 1, r2 = 0
+outcome is impossible -- as it should be.
+
+The formal definition of the prop relation involves a coe or fre link,
+followed by an arbitrary number of cumul-fence links, ending with an
+rfe link.  You can concoct more exotic examples, containing more than
+one fence, although this quickly leads to diminishing returns in terms
+of complexity.  For instance, here's an example containing a coe link
+followed by two fences and an rfe link, utilizing the fact that
+release fences are A-cumulative:
+
+	int x, y, z;
+
+	P0()
+	{
+		int r0;
+
+		WRITE_ONCE(x, 1);
+		r0 = READ_ONCE(z);
+	}
+
+	P1()
+	{
+		WRITE_ONCE(x, 2);
+		smp_wmb();
+		WRITE_ONCE(y, 1);
+	}
+
+	P2()
+	{
+		int r2;
+
+		r2 = READ_ONCE(y);
+		smp_store_release(&z, 1);
+	}
+
+If x = 2, r0 = 1, and r2 = 1 after this code runs then there is a prop
+link from P0's store to its load.  This is because P0's store gets
+overwritten by P1's store since x = 2 at the end (a coe link), the
+smp_wmb() ensures that P1's store to x propagates to P2 before the
+store to y does (the first fence), the store to y propagates to P2
+before P2's load and store execute, P2's smp_store_release()
+guarantees that the stores to x and y both propagate to P0 before the
+store to z does (the second fence), and P0's load executes after the
+store to z has propagated to P0 (an rfe link).
+
+In summary, the fact that the hb relation links memory access events
+in the order they execute means that it must not have cycles.  This
+requirement is the content of the LKMM's "happens-before" axiom.
+
+The LKMM defines yet another relation connected to times of
+instruction execution, but it is not included in hb.  It relies on the
+particular properties of strong fences, which we cover in the next
+section.
+
+
+THE PROPAGATES-BEFORE RELATION: pb
+----------------------------------
+
+The propagates-before (pb) relation capitalizes on the special
+features of strong fences.  It links two events E and F whenever some
+store is coherence-later than E and propagates to every CPU and to RAM
+before F executes.  The formal definition requires that E be linked to
+F via a coe or fre link, an arbitrary number of cumul-fences, an
+optional rfe link, a strong fence, and an arbitrary number of hb
+links.  Let's see how this definition works out.
+
+Consider first the case where E is a store (implying that the sequence
+of links begins with coe).  Then there are events W, X, Y, and Z such
+that:
+
+	E ->coe W ->cumul-fence* X ->rfe? Y ->strong-fence Z ->hb* F,
+
+where the * suffix indicates an arbitrary number of links of the
+specified type, and the ? suffix indicates the link is optional (Y may
+be equal to X).  Because of the cumul-fence links, we know that W will
+propagate to Y's CPU before X does, hence before Y executes and hence
+before the strong fence executes.  Because this fence is strong, we
+know that W will propagate to every CPU and to RAM before Z executes.
+And because of the hb links, we know that Z will execute before F.
+Thus W, which comes later than E in the coherence order, will
+propagate to every CPU and to RAM before F executes.
+
+The case where E is a load is exactly the same, except that the first
+link in the sequence is fre instead of coe.
+
+The existence of a pb link from E to F implies that E must execute
+before F.  To see why, suppose that F executed first.  Then W would
+have propagated to E's CPU before E executed.  If E was a store, the
+memory subsystem would then be forced to make E come after W in the
+coherence order, contradicting the fact that E ->coe W.  If E was a
+load, the memory subsystem would then be forced to satisfy E's read
+request with the value stored by W or an even later store,
+contradicting the fact that E ->fre W.
+
+A good example illustrating how pb works is the SB pattern with strong
+fences:
+
+	int x = 0, y = 0;
+
+	P0()
+	{
+		int r0;
+
+		WRITE_ONCE(x, 1);
+		smp_mb();
+		r0 = READ_ONCE(y);
+	}
+
+	P1()
+	{
+		int r1;
+
+		WRITE_ONCE(y, 1);
+		smp_mb();
+		r1 = READ_ONCE(x);
+	}
+
+If r0 = 0 at the end then there is a pb link from P0's load to P1's
+load: an fre link from P0's load to P1's store (which overwrites the
+value read by P0), and a strong fence between P1's store and its load.
+In this example, the sequences of cumul-fence and hb links are empty.
+Note that this pb link is not included in hb as an instance of prop,
+because it does not start and end on the same CPU.
+
+Similarly, if r1 = 0 at the end then there is a pb link from P1's load
+to P0's.  This means that if both r1 and r2 were 0 there would be a
+cycle in pb, which is not possible since an instruction cannot execute
+before itself.  Thus, adding smp_mb() fences to the SB pattern
+prevents the r0 = 0, r1 = 0 outcome.
+
+In summary, the fact that the pb relation links events in the order
+they execute means that it cannot have cycles.  This requirement is
+the content of the LKMM's "propagation" axiom.
+
+
+RCU RELATIONS: link, gp-link, rscs-link, and rcu-path
+-----------------------------------------------------
+
+RCU (Read-Copy-Update) is a powerful synchronization mechanism.  It
+rests on two concepts: grace periods and read-side critical sections.
+
+A grace period is the span of time occupied by a call to
+synchronize_rcu().  A read-side critical section (or just critical
+section, for short) is a region of code delimited by rcu_read_lock()
+at the start and rcu_read_unlock() at the end.  Critical sections can
+be nested, although we won't make use of this fact.
+
+As far as memory models are concerned, RCU's main feature is its
+Grace-Period Guarantee, which states that a critical section can never
+span a full grace period.  In more detail, the Guarantee says:
+
+	If a critical section starts before a grace period then it
+	must end before the grace period does.  In addition, every
+	store that propagates to the critical section's CPU before the
+	end of the critical section must propagate to every CPU before
+	the end of the grace period.
+
+	If a critical section ends after a grace period ends then it
+	must start after the grace period does.  In addition, every
+	store that propagates to the grace period's CPU before the
+	start of the grace period must propagate to every CPU before
+	the start of the critical section.
+
+Here is a simple example of RCU in action:
+
+	int x, y;
+
+	P0()
+	{
+		rcu_read_lock();
+		WRITE_ONCE(x, 1);
+		WRITE_ONCE(y, 1);
+		rcu_read_unlock();
+	}
+
+	P1()
+	{
+		int r1, r2;
+
+		r1 = READ_ONCE(x);
+		synchronize_rcu();
+		r2 = READ_ONCE(y);
+	}
+
+The Grace Period Guarantee tells us that when this code runs, it will
+never end with r1 = 1 and r2 = 0.  The reasoning is as follows.  r1 = 1
+means that P0's store to x propagated to P1 before P1 called
+synchronize_rcu(), so P0's critical section must have started before
+P1's grace period.  On the other hand, r2 = 0 means that P0's store to
+y, which occurs before the end of the critical section, did not
+propagate to P1 before the end of the grace period, violating the
+Guarantee.
+
+In the kernel's implementations of RCU, the business about stores
+propagating to every CPU is realized by placing strong fences at
+suitable places in the RCU-related code.  Thus, if a critical section
+starts before a grace period does then the critical section's CPU will
+execute an smp_mb() fence after the end of the critical section and
+some time before the grace period's synchronize_rcu() call returns.
+And if a critical section ends after a grace period does then the
+synchronize_rcu() routine will execute an smp_mb() fence at its start
+and some time before the critical section's opening rcu_read_lock()
+executes.
+
+What exactly do we mean by saying that a critical section "starts
+before" or "ends after" a grace period?  Some aspects of the meaning
+are pretty obvious, as in the example above, but the details aren't
+entirely clear.  The LKMM formalizes this notion by means of a
+relation with the unfortunately generic name "link".  It is a very
+general relation; among other things, X ->link Z includes cases where
+X happens-before or is equal to some event Y which is equal to or
+comes before Z in the coherence order.  Taking Y = Z, this says that
+X ->rfe Z implies X ->link Z, and taking Y = X, it says that X ->fr Z
+and X ->co Z each imply X ->link Z.
+
+The formal definition of the link relation is more than a little
+obscure, and we won't give it here.  It is closely related to the pb
+relation, and the details don't matter unless you want to comb through
+a somewhat lengthy formal proof.  Pretty much all you need to know
+about link is the information in the preceding paragraph.
+
+The LKMM goes on to define the gp-link and rscs-link relations.  They
+bring grace periods and read-side critical sections into the picture,
+in the following way:
+
+	E ->gp-link F means there is a synchronize_rcu() fence event S
+	and an event X such that E ->po S, either S ->po X or S = X,
+	and X ->link F.  In other words, E and F are connected by a
+	grace period followed by an instance of link.
+
+	E ->rscs-link F means there is a critical section delimited by
+	an rcu_read_lock() fence L and an rcu_read_unlock() fence U,
+	and an event X such that E ->po U, either L ->po X or L = X,
+	and X ->link F.  Roughly speaking, this says that some event
+	in the same critical section as E is connected by link to F.
+
+If we think of the link relation as standing for an extended "before",
+then E ->gp-link F says that E executes before a grace period which
+ends before F executes.  (In fact it says more than this, because it
+includes cases where E executes before a grace period and some store
+propagates to F's CPU before F executes and doesn't propagate to some
+other CPU until after the grace period ends.)  Similarly,
+E ->rscs-link F says that E is part of (or before the start of) a
+critical section which starts before F executes.
+
+Putting this all together, the LKMM expresses the Grace Period
+Guarantee by requiring that there are no cycles consisting of gp-link
+and rscs-link connections in which the number of gp-link instances is
+>= the number of rscs-link instances.  It does this by defining the
+rcu-path relation to link events E and F whenever it is possible to
+pass from E to F by a sequence of gp-link and rscs-link connections
+with at least as many of the former as the latter.  The LKMM's "rcu"
+axiom then says that there are no events E such that E ->rcu-path E.
+
+Justifying this axiom takes some intellectual effort, but it is in
+fact a valid formalization of the Grace Period Guarantee.  We won't
+attempt to go through the detailed argument, but the following
+analysis gives a taste of what is involved.  Suppose we have a
+violation of the first part of the Guarantee: A critical section
+starts before a grace period, and some store propagates to the
+critical section's CPU before the end of the critical section but
+doesn't propagate to some other CPU until after the end of the grace
+period.
+
+Putting symbols to these ideas, let L and U be the rcu_read_lock() and
+rcu_read_unlock() fence events delimiting the critical section in
+question, and let S be the synchronize_rcu() fence event for the grace
+period.  Saying that the critical section starts before S means there
+are events E and F where E is po-after L (which marks the start of the
+critical section), E is "before" F in the sense of the link relation,
+and F is po-before the grace period S:
+
+	L ->po E ->link F ->po S.
+
+Let W be the store mentioned above, let Z come before the end of the
+critical section and witness that W propagates to the critical
+section's CPU by reading from W, and let Y on some arbitrary CPU be a
+witness that W has not propagated to that CPU, where Y happens after
+some event X which is po-after S.  Symbolically, this amounts to:
+
+	S ->po X ->hb* Y ->fr W ->rf Z ->po U.
+
+The fr link from Y to W indicates that W has not propagated to Y's CPU
+at the time that Y executes.  From this, it can be shown (see the
+discussion of the link relation earlier) that X and Z are connected by
+link, yielding:
+
+	S ->po X ->link Z ->po U.
+
+These formulas say that S is po-between F and X, hence F ->gp-link Z
+via X.  They also say that Z comes before the end of the critical
+section and E comes after its start, hence Z ->rscs-link F via E.  But
+now we have a forbidden cycle: F ->gp-link Z ->rscs-link F.  Thus the
+"rcu" axiom rules out this violation of the Grace Period Guarantee.
+
+For something a little more down-to-earth, let's see how the axiom
+works out in practice.  Consider the RCU code example from above, this
+time with statement labels added to the memory access instructions:
+
+	int x, y;
+
+	P0()
+	{
+		rcu_read_lock();
+		W: WRITE_ONCE(x, 1);
+		X: WRITE_ONCE(y, 1);
+		rcu_read_unlock();
+	}
+
+	P1()
+	{
+		int r1, r2;
+
+		Y: r1 = READ_ONCE(x);
+		synchronize_rcu();
+		Z: r2 = READ_ONCE(y);
+	}
+
+
+If r2 = 0 at the end then P0's store at X overwrites the value
+that P1's load at Z reads from, so we have Z ->fre X and thus
+Z ->link X.  In addition, there is a synchronize_rcu() between Y and
+Z, so therefore we have Y ->gp-link X.
+
+If r1 = 1 at the end then P1's load at Y reads from P0's store at W,
+so we have W ->link Y.  In addition, W and X are in the same critical
+section, so therefore we have X ->rscs-link Y.
+
+This gives us a cycle, Y ->gp-link X ->rscs-link Y, with one gp-link
+and one rscs-link, violating the "rcu" axiom.  Hence the outcome is
+not allowed by the LKMM, as we would expect.
+
+For contrast, let's see what can happen in a more complicated example:
+
+	int x, y, z;
+
+	P0()
+	{
+		int r0;
+
+		rcu_read_lock();
+		W: r0 = READ_ONCE(x);
+		X: WRITE_ONCE(y, 1);
+		rcu_read_unlock();
+	}
+
+	P1()
+	{
+		int r1;
+
+		Y: r1 = READ_ONCE(y);
+		synchronize_rcu();
+		Z: WRITE_ONCE(z, 1);
+	}
+
+	P2()
+	{
+		int r2;
+
+		rcu_read_lock();
+		U: r2 = READ_ONCE(z);
+		V: WRITE_ONCE(x, 1);
+		rcu_read_unlock();
+	}
+
+If r0 = r1 = r2 = 1 at the end, then similar reasoning to before shows
+that W ->rscs-link Y via X, Y ->gp-link U via Z, and U ->rscs-link W
+via V.  And just as before, this gives a cycle:
+
+	W ->rscs-link Y ->gp-link U ->rscs-link W.
+
+However, this cycle has fewer gp-link instances than rscs-link
+instances, and consequently the outcome is not forbidden by the LKMM.
+The following instruction timing diagram shows how it might actually
+occur:
+
+P0			P1			P2
+--------------------	--------------------	--------------------
+rcu_read_lock()
+X: WRITE_ONCE(y, 1)
+			Y: r1 = READ_ONCE(y)
+			synchronize_rcu() starts
+			.			rcu_read_lock()
+			.			V: WRITE_ONCE(x, 1)
+W: r0 = READ_ONCE(x)	.
+rcu_read_unlock()	.
+			synchronize_rcu() ends
+			Z: WRITE_ONCE(z, 1)
+						U: r2 = READ_ONCE(z)
+						rcu_read_unlock()
+
+This requires P0 and P2 to execute their loads and stores out of
+program order, but of course they are allowed to do so.  And as you
+can see, the Grace Period Guarantee is not violated: The critical
+section in P0 both starts before P1's grace period does and ends
+before it does, and the critical section in P2 both starts after P1's
+grace period does and ends after it does.
+
+
+ODDS AND ENDS
+-------------
+
+This section covers material that didn't quite fit anywhere in the
+earlier sections.
+
+The descriptions in this document don't always match the formal
+version of the LKMM exactly.  For example, the actual formal
+definition of the prop relation makes the initial coe or fre part
+optional, and it doesn't require the events linked by the relation to
+be on the same CPU.  These differences are very unimportant; indeed,
+instances where the coe/fre part of prop is missing are of no interest
+because all the other parts (fences and rfe) are already included in
+hb anyway, and where the formal model adds prop into hb, it includes
+an explicit requirement that the events being linked are on the same
+CPU.
+
+Another minor difference has to do with events that are both memory
+accesses and fences, such as those corresponding to smp_load_acquire()
+calls.  In the formal model, these events aren't actually both reads
+and fences; rather, they are read events with an annotation marking
+them as acquires.  (Or write events annotated as releases, in the case
+smp_store_release().)  The final effect is the same.
+
+Although we didn't mention it above, the instruction execution
+ordering provided by the smp_rmb() fence doesn't apply to read events
+that are part of a non-value-returning atomic update.  For instance,
+given:
+
+	atomic_inc(&x);
+	smp_rmb();
+	r1 = READ_ONCE(y);
+
+it is not guaranteed that the load from y will execute after the
+update to x.  This is because the ARMv8 architecture allows
+non-value-returning atomic operations effectively to be executed off
+the CPU.  Basically, the CPU tells the memory subsystem to increment
+x, and then the increment is carried out by the memory hardware with
+no further involvement from the CPU.  Since the CPU doesn't ever read
+the value of x, there is nothing for the smp_rmb() fence to act on.
+
+The LKMM defines a few extra synchronization operations in terms of
+things we have already covered.  In particular, rcu_dereference() and
+lockless_dereference() are both treated as a READ_ONCE() followed by
+smp_read_barrier_depends() -- which also happens to be how they are
+defined in include/linux/rcupdate.h and include/linux/compiler.h,
+respectively.
+
+There are a few oddball fences which need special treatment:
+smp_mb__before_atomic(), smp_mb__after_atomic(), and
+smp_mb__after_spinlock().  The LKMM uses fence events with special
+annotations for them; they act as strong fences just like smp_mb()
+except for the sets of events that they order.  Instead of ordering
+all po-earlier events against all po-later events, as smp_mb() does,
+they behave as follows:
+
+	smp_mb__before_atomic() orders all po-earlier events against
+	po-later atomic updates and the events following them;
+
+	smp_mb__after_atomic() orders po-earlier atomic updates and
+	the events preceding them against all po-later events;
+
+	smp_mb_after_spinlock() orders po-earlier lock acquisition
+	events and the events preceding them against all po-later
+	events.
+
+The LKMM includes locking.  In fact, there is special code for locking
+in the formal model, added in order to make tools run faster.
+However, this special code is intended to be exactly equivalent to
+concepts we have already covered.  A spinlock_t variable is treated
+the same as an int, and spin_lock(&s) is treated the same as:
+
+	while (cmpxchg_acquire(&s, 0, 1) != 0)
+		cpu_relax();
+
+which waits until s is equal to 0 and then atomically sets it to 1,
+and where the read part of the atomic update is also an acquire fence.
+An alternate way to express the same thing would be:
+
+	r = xchg_acquire(&s, 1);
+
+along with a requirement that at the end, r = 0.  spin_unlock(&s) is
+treated the same as:
+
+	smp_store_release(&s, 0);
+
+Interestingly, RCU and locking each introduce the possibility of
+deadlock.  When faced with code sequences such as:
+
+	spin_lock(&s);
+	spin_lock(&s);
+	spin_unlock(&s);
+	spin_unlock(&s);
+
+or:
+
+	rcu_read_lock();
+	synchronize_rcu();
+	rcu_read_unlock();
+
+what does the LKMM have to say?  Answer: It says there are no allowed
+executions at all, which makes sense.  But this can also lead to
+misleading results, because if a piece of code has multiple possible
+executions, some of which deadlock, the model will report only on the
+non-deadlocking executions.  For example:
+
+	int x, y;
+
+	P0()
+	{
+		int r0;
+
+		WRITE_ONCE(x, 1);
+		r0 = READ_ONCE(y);
+	}
+
+	P1()
+	{
+		rcu_read_lock();
+		if (READ_ONCE(x) > 0) {
+			WRITE_ONCE(y, 36);
+			synchronize_rcu();
+		}
+		rcu_read_unlock();
+	}
+
+Is it possible to end up with r0 = 36 at the end?  The LKMM will tell
+you it is not, but the model won't mention that this is because P1
+will self-deadlock in the executions where it stores 36 in y.
diff --git a/tools/memory-model/Documentation/recipes.txt b/tools/memory-model/Documentation/recipes.txt
new file mode 100644
index 000000000000..ee4309a87fc4
--- /dev/null
+++ b/tools/memory-model/Documentation/recipes.txt
@@ -0,0 +1,570 @@
+This document provides "recipes", that is, litmus tests for commonly
+occurring situations, as well as a few that illustrate subtly broken but
+attractive nuisances.  Many of these recipes include example code from
+v4.13 of the Linux kernel.
+
+The first section covers simple special cases, the second section
+takes off the training wheels to cover more involved examples,
+and the third section provides a few rules of thumb.
+
+
+Simple special cases
+====================
+
+This section presents two simple special cases, the first being where
+there is only one CPU or only one memory location is accessed, and the
+second being use of that old concurrency workhorse, locking.
+
+
+Single CPU or single memory location
+------------------------------------
+
+If there is only one CPU on the one hand or only one variable
+on the other, the code will execute in order.  There are (as
+usual) some things to be careful of:
+
+1.	Some aspects of the C language are unordered.  For example,
+	in the expression "f(x) + g(y)", the order in which f and g are
+	called is not defined; the object code is allowed to use either
+	order or even to interleave the computations.
+
+2.	Compilers are permitted to use the "as-if" rule.  That is, a
+	compiler can emit whatever code it likes for normal accesses,
+	as long as the results of a single-threaded execution appear
+	just as if the compiler had followed all the relevant rules.
+	To see this, compile with a high level of optimization and run
+	the debugger on the resulting binary.
+
+3.	If there is only one variable but multiple CPUs, that variable
+	must be properly aligned and all accesses to that variable must
+	be full sized.	Variables that straddle cachelines or pages void
+	your full-ordering warranty, as do undersized accesses that load
+	from or store to only part of the variable.
+
+4.	If there are multiple CPUs, accesses to shared variables should
+	use READ_ONCE() and WRITE_ONCE() or stronger to prevent load/store
+	tearing, load/store fusing, and invented loads and stores.
+	There are exceptions to this rule, including:
+
+	i.	When there is no possibility of a given shared variable
+		being updated by some other CPU, for example, while
+		holding the update-side lock, reads from that variable
+		need not use READ_ONCE().
+
+	ii.	When there is no possibility of a given shared variable
+		being either read or updated by other CPUs, for example,
+		when running during early boot, reads from that variable
+		need not use READ_ONCE() and writes to that variable
+		need not use WRITE_ONCE().
+
+
+Locking
+-------
+
+Locking is well-known and straightforward, at least if you don't think
+about it too hard.  And the basic rule is indeed quite simple: Any CPU that
+has acquired a given lock sees any changes previously seen or made by any
+CPU before it released that same lock.  Note that this statement is a bit
+stronger than "Any CPU holding a given lock sees all changes made by any
+CPU during the time that CPU was holding this same lock".  For example,
+consider the following pair of code fragments:
+
+	/* See MP+polocks.litmus. */
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		spin_lock(&mylock);
+		WRITE_ONCE(y, 1);
+		spin_unlock(&mylock);
+	}
+
+	void CPU1(void)
+	{
+		spin_lock(&mylock);
+		r0 = READ_ONCE(y);
+		spin_unlock(&mylock);
+		r1 = READ_ONCE(x);
+	}
+
+The basic rule guarantees that if CPU0() acquires mylock before CPU1(),
+then both r0 and r1 must be set to the value 1.  This also has the
+consequence that if the final value of r0 is equal to 1, then the final
+value of r1 must also be equal to 1.  In contrast, the weaker rule would
+say nothing about the final value of r1.
+
+The converse to the basic rule also holds, as illustrated by the
+following litmus test:
+
+	/* See MP+porevlocks.litmus. */
+	void CPU0(void)
+	{
+		r0 = READ_ONCE(y);
+		spin_lock(&mylock);
+		r1 = READ_ONCE(x);
+		spin_unlock(&mylock);
+	}
+
+	void CPU1(void)
+	{
+		spin_lock(&mylock);
+		WRITE_ONCE(x, 1);
+		spin_unlock(&mylock);
+		WRITE_ONCE(y, 1);
+	}
+
+This converse to the basic rule guarantees that if CPU0() acquires
+mylock before CPU1(), then both r0 and r1 must be set to the value 0.
+This also has the consequence that if the final value of r1 is equal
+to 0, then the final value of r0 must also be equal to 0.  In contrast,
+the weaker rule would say nothing about the final value of r0.
+
+These examples show only a single pair of CPUs, but the effects of the
+locking basic rule extend across multiple acquisitions of a given lock
+across multiple CPUs.
+
+However, it is not necessarily the case that accesses ordered by
+locking will be seen as ordered by CPUs not holding that lock.
+Consider this example:
+
+	/* See Z6.0+pooncelock+pooncelock+pombonce.litmus. */
+	void CPU0(void)
+	{
+		spin_lock(&mylock);
+		WRITE_ONCE(x, 1);
+		WRITE_ONCE(y, 1);
+		spin_unlock(&mylock);
+	}
+
+	void CPU1(void)
+	{
+		spin_lock(&mylock);
+		r0 = READ_ONCE(y);
+		WRITE_ONCE(z, 1);
+		spin_unlock(&mylock);
+	}
+
+	void CPU2(void)
+	{
+		WRITE_ONCE(z, 2);
+		smp_mb();
+		r1 = READ_ONCE(x);
+	}
+
+Counter-intuitive though it might be, it is quite possible to have
+the final value of r0 be 1, the final value of z be 2, and the final
+value of r1 be 0.  The reason for this surprising outcome is that
+CPU2() never acquired the lock, and thus did not benefit from the
+lock's ordering properties.
+
+Ordering can be extended to CPUs not holding the lock by careful use
+of smp_mb__after_spinlock():
+
+	/* See Z6.0+pooncelock+poonceLock+pombonce.litmus. */
+	void CPU0(void)
+	{
+		spin_lock(&mylock);
+		WRITE_ONCE(x, 1);
+		WRITE_ONCE(y, 1);
+		spin_unlock(&mylock);
+	}
+
+	void CPU1(void)
+	{
+		spin_lock(&mylock);
+		smp_mb__after_spinlock();
+		r0 = READ_ONCE(y);
+		WRITE_ONCE(z, 1);
+		spin_unlock(&mylock);
+	}
+
+	void CPU2(void)
+	{
+		WRITE_ONCE(z, 2);
+		smp_mb();
+		r1 = READ_ONCE(x);
+	}
+
+This addition of smp_mb__after_spinlock() strengthens the lock acquisition
+sufficiently to rule out the counter-intuitive outcome.
+
+
+Taking off the training wheels
+==============================
+
+This section looks at more complex examples, including message passing,
+load buffering, release-acquire chains, store buffering.
+Many classes of litmus tests have abbreviated names, which may be found
+here: https://www.cl.cam.ac.uk/~pes20/ppc-supplemental/test6.pdf
+
+
+Message passing (MP)
+--------------------
+
+The MP pattern has one CPU execute a pair of stores to a pair of variables
+and another CPU execute a pair of loads from this same pair of variables,
+but in the opposite order.  The goal is to avoid the counter-intuitive
+outcome in which the first load sees the value written by the second store
+but the second load does not see the value written by the first store.
+In the absence of any ordering, this goal may not be met, as can be seen
+in the MP+poonceonces.litmus litmus test.  This section therefore looks at
+a number of ways of meeting this goal.
+
+
+Release and acquire
+~~~~~~~~~~~~~~~~~~~
+
+Use of smp_store_release() and smp_load_acquire() is one way to force
+the desired MP ordering.  The general approach is shown below:
+
+	/* See MP+pooncerelease+poacquireonce.litmus. */
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		smp_store_release(&y, 1);
+	}
+
+	void CPU1(void)
+	{
+		r0 = smp_load_acquire(&y);
+		r1 = READ_ONCE(x);
+	}
+
+The smp_store_release() macro orders any prior accesses against the
+store, while the smp_load_acquire macro orders the load against any
+subsequent accesses.  Therefore, if the final value of r0 is the value 1,
+the final value of r1 must also be the value 1.
+
+The init_stack_slab() function in lib/stackdepot.c uses release-acquire
+in this way to safely initialize of a slab of the stack.  Working out
+the mutual-exclusion design is left as an exercise for the reader.
+
+
+Assign and dereference
+~~~~~~~~~~~~~~~~~~~~~~
+
+Use of rcu_assign_pointer() and rcu_dereference() is quite similar to the
+use of smp_store_release() and smp_load_acquire(), except that both
+rcu_assign_pointer() and rcu_dereference() operate on RCU-protected
+pointers.  The general approach is shown below:
+
+	/* See MP+onceassign+derefonce.litmus. */
+	int z;
+	int *y = &z;
+	int x;
+
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		rcu_assign_pointer(y, &x);
+	}
+
+	void CPU1(void)
+	{
+		rcu_read_lock();
+		r0 = rcu_dereference(y);
+		r1 = READ_ONCE(*r0);
+		rcu_read_unlock();
+	}
+
+In this example, if the final value of r0 is &x then the final value of
+r1 must be 1.
+
+The rcu_assign_pointer() macro has the same ordering properties as does
+smp_store_release(), but the rcu_dereference() macro orders the load only
+against later accesses that depend on the value loaded.  A dependency
+is present if the value loaded determines the address of a later access
+(address dependency, as shown above), the value written by a later store
+(data dependency), or whether or not a later store is executed in the
+first place (control dependency).  Note that the term "data dependency"
+is sometimes casually used to cover both address and data dependencies.
+
+In lib/prime_numbers.c, the expand_to_next_prime() function invokes
+rcu_assign_pointer(), and the next_prime_number() function invokes
+rcu_dereference().  This combination mediates access to a bit vector
+that is expanded as additional primes are needed.
+
+
+Write and read memory barriers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is usually better to use smp_store_release() instead of smp_wmb()
+and to use smp_load_acquire() instead of smp_rmb().  However, the older
+smp_wmb() and smp_rmb() APIs are still heavily used, so it is important
+to understand their use cases.  The general approach is shown below:
+
+	/* See MP+wmbonceonce+rmbonceonce.litmus. */
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		smp_wmb();
+		WRITE_ONCE(y, 1);
+	}
+
+	void CPU1(void)
+	{
+		r0 = READ_ONCE(y);
+		smp_rmb();
+		r1 = READ_ONCE(x);
+	}
+
+The smp_wmb() macro orders prior stores against later stores, and the
+smp_rmb() macro orders prior loads against later loads.  Therefore, if
+the final value of r0 is 1, the final value of r1 must also be 1.
+
+The the xlog_state_switch_iclogs() function in fs/xfs/xfs_log.c contains
+the following write-side code fragment:
+
+	log->l_curr_block -= log->l_logBBsize;
+	ASSERT(log->l_curr_block >= 0);
+	smp_wmb();
+	log->l_curr_cycle++;
+
+And the xlog_valid_lsn() function in fs/xfs/xfs_log_priv.h contains
+the corresponding read-side code fragment:
+
+	cur_cycle = ACCESS_ONCE(log->l_curr_cycle);
+	smp_rmb();
+	cur_block = ACCESS_ONCE(log->l_curr_block);
+
+Alternatively, consider the following comment in function
+perf_output_put_handle() in kernel/events/ring_buffer.c:
+
+	 *   kernel				user
+	 *
+	 *   if (LOAD ->data_tail) {		LOAD ->data_head
+	 *			(A)		smp_rmb()	(C)
+	 *	STORE $data			LOAD $data
+	 *	smp_wmb()	(B)		smp_mb()	(D)
+	 *	STORE ->data_head		STORE ->data_tail
+	 *   }
+
+The B/C pairing is an example of the MP pattern using smp_wmb() on the
+write side and smp_rmb() on the read side.
+
+Of course, given that smp_mb() is strictly stronger than either smp_wmb()
+or smp_rmb(), any code fragment that would work with smp_rmb() and
+smp_wmb() would also work with smp_mb() replacing either or both of the
+weaker barriers.
+
+
+Load buffering (LB)
+-------------------
+
+The LB pattern has one CPU load from one variable and then store to a
+second, while another CPU loads from the second variable and then stores
+to the first.  The goal is to avoid the counter-intuitive situation where
+each load reads the value written by the other CPU's store.  In the
+absence of any ordering it is quite possible that this may happen, as
+can be seen in the LB+poonceonces.litmus litmus test.
+
+One way of avoiding the counter-intuitive outcome is through the use of a
+control dependency paired with a full memory barrier:
+
+	/* See LB+ctrlonceonce+mbonceonce.litmus. */
+	void CPU0(void)
+	{
+		r0 = READ_ONCE(x);
+		if (r0)
+			WRITE_ONCE(y, 1);
+	}
+
+	void CPU1(void)
+	{
+		r1 = READ_ONCE(y);
+		smp_mb();
+		WRITE_ONCE(x, 1);
+	}
+
+This pairing of a control dependency in CPU0() with a full memory
+barrier in CPU1() prevents r0 and r1 from both ending up equal to 1.
+
+The A/D pairing from the ring-buffer use case shown earlier also
+illustrates LB.  Here is a repeat of the comment in
+perf_output_put_handle() in kernel/events/ring_buffer.c, showing a
+control dependency on the kernel side and a full memory barrier on
+the user side:
+
+	 *   kernel				user
+	 *
+	 *   if (LOAD ->data_tail) {		LOAD ->data_head
+	 *			(A)		smp_rmb()	(C)
+	 *	STORE $data			LOAD $data
+	 *	smp_wmb()	(B)		smp_mb()	(D)
+	 *	STORE ->data_head		STORE ->data_tail
+	 *   }
+	 *
+	 * Where A pairs with D, and B pairs with C.
+
+The kernel's control dependency between the load from ->data_tail
+and the store to data combined with the user's full memory barrier
+between the load from data and the store to ->data_tail prevents
+the counter-intuitive outcome where the kernel overwrites the data
+before the user gets done loading it.
+
+
+Release-acquire chains
+----------------------
+
+Release-acquire chains are a low-overhead, flexible, and easy-to-use
+method of maintaining order.  However, they do have some limitations that
+need to be fully understood.  Here is an example that maintains order:
+
+	/* See ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus. */
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		smp_store_release(&y, 1);
+	}
+
+	void CPU1(void)
+	{
+		r0 = smp_load_acquire(y);
+		smp_store_release(&z, 1);
+	}
+
+	void CPU2(void)
+	{
+		r1 = smp_load_acquire(z);
+		r2 = READ_ONCE(x);
+	}
+
+In this case, if r0 and r1 both have final values of 1, then r2 must
+also have a final value of 1.
+
+The ordering in this example is stronger than it needs to be.  For
+example, ordering would still be preserved if CPU1()'s smp_load_acquire()
+invocation was replaced with READ_ONCE().
+
+It is tempting to assume that CPU0()'s store to x is globally ordered
+before CPU1()'s store to z, but this is not the case:
+
+	/* See Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus. */
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		smp_store_release(&y, 1);
+	}
+
+	void CPU1(void)
+	{
+		r0 = smp_load_acquire(y);
+		smp_store_release(&z, 1);
+	}
+
+	void CPU2(void)
+	{
+		WRITE_ONCE(z, 2);
+		smp_mb();
+		r1 = READ_ONCE(x);
+	}
+
+One might hope that if the final value of r0 is 1 and the final value
+of z is 2, then the final value of r1 must also be 1, but it really is
+possible for r1 to have the final value of 0.  The reason, of course,
+is that in this version, CPU2() is not part of the release-acquire chain.
+This situation is accounted for in the rules of thumb below.
+
+Despite this limitation, release-acquire chains are low-overhead as
+well as simple and powerful, at least as memory-ordering mechanisms go.
+
+
+Store buffering
+---------------
+
+Store buffering can be thought of as upside-down load buffering, so
+that one CPU first stores to one variable and then loads from a second,
+while another CPU stores to the second variable and then loads from the
+first.  Preserving order requires nothing less than full barriers:
+
+	/* See SB+mbonceonces.litmus. */
+	void CPU0(void)
+	{
+		WRITE_ONCE(x, 1);
+		smp_mb();
+		r0 = READ_ONCE(y);
+	}
+
+	void CPU1(void)
+	{
+		WRITE_ONCE(y, 1);
+		smp_mb();
+		r1 = READ_ONCE(x);
+	}
+
+Omitting either smp_mb() will allow both r0 and r1 to have final
+values of 0, but providing both full barriers as shown above prevents
+this counter-intuitive outcome.
+
+This pattern most famously appears as part of Dekker's locking
+algorithm, but it has a much more practical use within the Linux kernel
+of ordering wakeups.  The following comment taken from waitqueue_active()
+in include/linux/wait.h shows the canonical pattern:
+
+ *      CPU0 - waker                    CPU1 - waiter
+ *
+ *                                      for (;;) {
+ *      @cond = true;                     prepare_to_wait(&wq_head, &wait, state);
+ *      smp_mb();                         // smp_mb() from set_current_state()
+ *      if (waitqueue_active(wq_head))         if (@cond)
+ *        wake_up(wq_head);                      break;
+ *                                        schedule();
+ *                                      }
+ *                                      finish_wait(&wq_head, &wait);
+
+On CPU0, the store is to @cond and the load is in waitqueue_active().
+On CPU1, prepare_to_wait() contains both a store to wq_head and a call
+to set_current_state(), which contains an smp_mb() barrier; the load is
+"if (@cond)".  The full barriers prevent the undesirable outcome where
+CPU1 puts the waiting task to sleep and CPU0 fails to wake it up.
+
+Note that use of locking can greatly simplify this pattern.
+
+
+Rules of thumb
+==============
+
+There might seem to be no pattern governing what ordering primitives are
+needed in which situations, but this is not the case.  There is a pattern
+based on the relation between the accesses linking successive CPUs in a
+given litmus test.  There are three types of linkage:
+
+1.	Write-to-read, where the next CPU reads the value that the
+	previous CPU wrote.  The LB litmus-test patterns contain only
+	this type of relation.	In formal memory-modeling texts, this
+	relation is called "reads-from" and is usually abbreviated "rf".
+
+2.	Read-to-write, where the next CPU overwrites the value that the
+	previous CPU read.  The SB litmus test contains only this type
+	of relation.  In formal memory-modeling texts, this relation is
+	often called "from-reads" and is sometimes abbreviated "fr".
+
+3.	Write-to-write, where the next CPU overwrites the value written
+	by the previous CPU.  The Z6.0 litmus test pattern contains a
+	write-to-write relation between the last access of CPU1() and
+	the first access of CPU2().  In formal memory-modeling texts,
+	this relation is often called "coherence order" and is sometimes
+	abbreviated "co".  In the C++ standard, it is instead called
+	"modification order" and often abbreviated "mo".
+
+The strength of memory ordering required for a given litmus test to
+avoid a counter-intuitive outcome depends on the types of relations
+linking the memory accesses for the outcome in question:
+
+o	If all links are write-to-read links, then the weakest
+	possible ordering within each CPU suffices.  For example, in
+	the LB litmus test, a control dependency was enough to do the
+	job.
+
+o	If all but one of the links are write-to-read links, then a
+	release-acquire chain suffices.  Both the MP and the ISA2
+	litmus tests illustrate this case.
+
+o	If more than one of the links are something other than
+	write-to-read links, then a full memory barrier is required
+	between each successive pair of non-write-to-read links.  This
+	case is illustrated by the Z6.0 litmus tests, both in the
+	locking and in the release-acquire sections.
+
+However, if you find yourself having to stretch these rules of thumb
+to fit your situation, you should consider creating a litmus test and
+running it on the model.
diff --git a/tools/memory-model/Documentation/references.txt b/tools/memory-model/Documentation/references.txt
new file mode 100644
index 000000000000..ba2e34c2ec3f
--- /dev/null
+++ b/tools/memory-model/Documentation/references.txt
@@ -0,0 +1,107 @@
+This document provides background reading for memory models and related
+tools.  These documents are aimed at kernel hackers who are interested
+in memory models.
+
+
+Hardware manuals and models
+===========================
+
+o	SPARC International Inc. (Ed.). 1994. "The SPARC Architecture
+	Reference Manual Version 9". SPARC International Inc.
+
+o	Compaq Computer Corporation (Ed.). 2002. "Alpha Architecture
+	Reference Manual".  Compaq Computer Corporation.
+
+o	Intel Corporation (Ed.). 2002. "A Formal Specification of Intel
+	Itanium Processor Family Memory Ordering". Intel Corporation.
+
+o	Intel Corporation (Ed.). 2002. "Intel 64 and IA-32 Architectures
+	Software Developer’s Manual". Intel Corporation.
+
+o	Peter Sewell, Susmit Sarkar, Scott Owens, Francesco Zappa Nardelli,
+	and Magnus O. Myreen. 2010. "x86-TSO: A Rigorous and Usable
+	Programmer's Model for x86 Multiprocessors". Commun. ACM 53, 7
+	(July, 2010), 89-97. http://doi.acm.org/10.1145/1785414.1785443
+
+o	IBM Corporation (Ed.). 2009. "Power ISA Version 2.06". IBM
+	Corporation.
+
+o	ARM Ltd. (Ed.). 2009. "ARM Barrier Litmus Tests and Cookbook".
+	ARM Ltd.
+
+o	Susmit Sarkar, Peter Sewell, Jade Alglave, Luc Maranget, and
+	Derek Williams.  2011. "Understanding POWER Multiprocessors". In
+	Proceedings of the 32Nd ACM SIGPLAN Conference on Programming
+	Language Design and Implementation (PLDI ’11). ACM, New York,
+	NY, USA, 175–186.
+
+o	Susmit Sarkar, Kayvan Memarian, Scott Owens, Mark Batty,
+	Peter Sewell, Luc Maranget, Jade Alglave, and Derek Williams.
+	2012. "Synchronising C/C++ and POWER". In Proceedings of the 33rd
+	ACM SIGPLAN Conference on Programming Language Design and
+	Implementation (PLDI '12). ACM, New York, NY, USA, 311-322.
+
+o	ARM Ltd. (Ed.). 2014. "ARM Architecture Reference Manual (ARMv8,
+	for ARMv8-A architecture profile)". ARM Ltd.
+
+o	Imagination Technologies, LTD. 2015. "MIPS(R) Architecture
+	For Programmers, Volume II-A: The MIPS64(R) Instruction,
+	Set Reference Manual". Imagination Technologies,
+	LTD. https://imgtec.com/?do-download=4302.
+
+o	Shaked Flur, Kathryn E. Gray, Christopher Pulte, Susmit
+	Sarkar, Ali Sezgin, Luc Maranget, Will Deacon, and Peter
+	Sewell. 2016. "Modelling the ARMv8 Architecture, Operationally:
+	Concurrency and ISA". In Proceedings of the 43rd Annual ACM
+	SIGPLAN-SIGACT Symposium on Principles of Programming Languages
+	(POPL ’16). ACM, New York, NY, USA, 608–621.
+
+o	Shaked Flur, Susmit Sarkar, Christopher Pulte, Kyndylan Nienhuis,
+	Luc Maranget, Kathryn E. Gray, Ali Sezgin, Mark Batty, and Peter
+	Sewell. 2017. "Mixed-size Concurrency: ARM, POWER, C/C++11,
+	and SC". In Proceedings of the 44th ACM SIGPLAN Symposium on
+	Principles of Programming Languages (POPL 2017). ACM, New York,
+	NY, USA, 429–442.
+
+
+Linux-kernel memory model
+=========================
+
+o	Andrea Parri, Alan Stern, Luc Maranget, Paul E. McKenney,
+	and Jade Alglave.  2017. "A formal model of
+	Linux-kernel memory ordering - companion webpage".
+	http://moscova.inria.fr/∼maranget/cats7/linux/. (2017). [Online;
+	accessed 30-January-2017].
+
+o	Jade Alglave, Luc Maranget, Paul E. McKenney, Andrea Parri, and
+	Alan Stern.  2017.  "A formal kernel memory-ordering model (part 1)"
+	Linux Weekly News.  https://lwn.net/Articles/718628/
+
+o	Jade Alglave, Luc Maranget, Paul E. McKenney, Andrea Parri, and
+	Alan Stern.  2017.  "A formal kernel memory-ordering model (part 2)"
+	Linux Weekly News.  https://lwn.net/Articles/720550/
+
+
+Memory-model tooling
+====================
+
+o	Daniel Jackson. 2002. "Alloy: A Lightweight Object Modelling
+	Notation". ACM Trans. Softw. Eng. Methodol. 11, 2 (April 2002),
+	256–290. http://doi.acm.org/10.1145/505145.505149
+
+o	Jade Alglave, Luc Maranget, and Michael Tautschnig. 2014. "Herding
+	Cats: Modelling, Simulation, Testing, and Data Mining for Weak
+	Memory". ACM Trans. Program. Lang. Syst. 36, 2, Article 7 (July
+	2014), 7:1–7:74 pages.
+
+o	Jade Alglave, Patrick Cousot, and Luc Maranget. 2016. "Syntax and
+	semantics of the weak consistency model specification language
+	cat". CoRR abs/1608.07531 (2016). http://arxiv.org/abs/1608.07531
+
+
+Memory-model comparisons
+========================
+
+o	Paul E. McKenney, Ulrich Weigand, Andrea Parri, and Boqun
+	Feng. 2016. "Linux-Kernel Memory Model". (6 June 2016).
+	http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0124r2.html.
diff --git a/tools/memory-model/MAINTAINERS b/tools/memory-model/MAINTAINERS
new file mode 100644
index 000000000000..711cbe72d606
--- /dev/null
+++ b/tools/memory-model/MAINTAINERS
@@ -0,0 +1,15 @@
+LINUX KERNEL MEMORY MODEL
+M:	Alan Stern <stern@rowland.harvard.edu>
+M:	Andrea Parri <parri.andrea@gmail.com>
+M:	Will Deacon <will.deacon@arm.com>
+M:	Peter Zijlstra <peterz@infradead.org>
+M:	Boqun Feng <boqun.feng@gmail.com>
+M:	Nicholas Piggin <npiggin@gmail.com>
+M:	David Howells <dhowells@redhat.com>
+M:	Jade Alglave <j.alglave@ucl.ac.uk>
+M:	Luc Maranget <luc.maranget@inria.fr>
+M:	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
+F:	tools/memory-model/
diff --git a/tools/memory-model/README b/tools/memory-model/README
new file mode 100644
index 000000000000..43ba49492111
--- /dev/null
+++ b/tools/memory-model/README
@@ -0,0 +1,220 @@
+			=========================
+			LINUX KERNEL MEMORY MODEL
+			=========================
+
+============
+INTRODUCTION
+============
+
+This directory contains the memory model of the Linux kernel, written
+in the "cat" language and executable by the (externally provided)
+"herd7" simulator, which exhaustively explores the state space of
+small litmus tests.
+
+In addition, the "klitmus7" tool (also externally provided) may be used
+to convert a litmus test to a Linux kernel module, which in turn allows
+that litmus test to be exercised within the Linux kernel.
+
+
+============
+REQUIREMENTS
+============
+
+The "herd7" and "klitmus7" tools must be downloaded separately:
+
+  https://github.com/herd/herdtools7
+
+See "herdtools7/INSTALL.md" for installation instructions.
+
+Alternatively, Abhishek Bhardwaj has kindly provided a Docker image
+of these tools at "abhishek40/memory-model".  Abhishek suggests the
+following commands to install and use this image:
+
+  - Users should install Docker for their distribution.
+  - docker run -itd abhishek40/memory-model
+  - docker attach <id-emitted-from-the-previous-command>
+
+Gentoo users might wish to make use of Patrick McLean's package:
+
+  https://gitweb.gentoo.org/repo/gentoo.git/tree/dev-util/herdtools7
+
+These packages may not be up-to-date with respect to the GitHub
+repository.
+
+
+==================
+BASIC USAGE: HERD7
+==================
+
+The memory model is used, in conjunction with "herd7", to exhaustively
+explore the state space of small litmus tests.
+
+For example, to run SB+mbonceonces.litmus against the memory model:
+
+  $ herd7 -conf linux-kernel.cfg litmus-tests/SB+mbonceonces.litmus
+
+Here is the corresponding output:
+
+  Test SB+mbonceonces Allowed
+  States 3
+  0:r0=0; 1:r0=1;
+  0:r0=1; 1:r0=0;
+  0:r0=1; 1:r0=1;
+  No
+  Witnesses
+  Positive: 0 Negative: 3
+  Condition exists (0:r0=0 /\ 1:r0=0)
+  Observation SB+mbonceonces Never 0 3
+  Time SB+mbonceonces 0.01
+  Hash=d66d99523e2cac6b06e66f4c995ebb48
+
+The "Positive: 0 Negative: 3" and the "Never 0 3" each indicate that
+this litmus test's "exists" clause can not be satisfied.
+
+See "herd7 -help" or "herdtools7/doc/" for more information.
+
+
+=====================
+BASIC USAGE: KLITMUS7
+=====================
+
+The "klitmus7" tool converts a litmus test into a Linux kernel module,
+which may then be loaded and run.
+
+For example, to run SB+mbonceonces.litmus against hardware:
+
+  $ mkdir mymodules
+  $ klitmus7 -o mymodules litmus-tests/SB+mbonceonces.litmus
+  $ cd mymodules ; make
+  $ sudo sh run.sh
+
+The corresponding output includes:
+
+  Test SB+mbonceonces Allowed
+  Histogram (3 states)
+  644580  :>0:r0=1; 1:r0=0;
+  644328  :>0:r0=0; 1:r0=1;
+  711092  :>0:r0=1; 1:r0=1;
+  No
+  Witnesses
+  Positive: 0, Negative: 2000000
+  Condition exists (0:r0=0 /\ 1:r0=0) is NOT validated
+  Hash=d66d99523e2cac6b06e66f4c995ebb48
+  Observation SB+mbonceonces Never 0 2000000
+  Time SB+mbonceonces 0.16
+
+The "Positive: 0 Negative: 2000000" and the "Never 0 2000000" indicate
+that during two million trials, the state specified in this litmus
+test's "exists" clause was not reached.
+
+And, as with "herd7", please see "klitmus7 -help" or "herdtools7/doc/"
+for more information.
+
+
+====================
+DESCRIPTION OF FILES
+====================
+
+Documentation/cheatsheet.txt
+	Quick-reference guide to the Linux-kernel memory model.
+
+Documentation/explanation.txt
+	Describes the memory model in detail.
+
+Documentation/recipes.txt
+	Lists common memory-ordering patterns.
+
+Documentation/references.txt
+	Provides background reading.
+
+linux-kernel.bell
+	Categorizes the relevant instructions, including memory
+	references, memory barriers, atomic read-modify-write operations,
+	lock acquisition/release, and RCU operations.
+
+	More formally, this file (1) lists the subtypes of the various
+	event types used by the memory model and (2) performs RCU
+	read-side critical section nesting analysis.
+
+linux-kernel.cat
+	Specifies what reorderings are forbidden by memory references,
+	memory barriers, atomic read-modify-write operations, and RCU.
+
+	More formally, this file specifies what executions are forbidden
+	by the memory model.  Allowed executions are those which
+	satisfy the model's "coherence", "atomic", "happens-before",
+	"propagation", and "rcu" axioms, which are defined in the file.
+
+linux-kernel.cfg
+	Convenience file that gathers the common-case herd7 command-line
+	arguments.
+
+linux-kernel.def
+	Maps from C-like syntax to herd7's internal litmus-test
+	instruction-set architecture.
+
+litmus-tests
+	Directory containing a few representative litmus tests, which
+	are listed in litmus-tests/README.  A great deal more litmus
+	tests are available at https://github.com/paulmckrcu/litmus.
+
+lock.cat
+	Provides a front-end analysis of lock acquisition and release,
+	for example, associating a lock acquisition with the preceding
+	and following releases and checking for self-deadlock.
+
+	More formally, this file defines a performance-enhanced scheme
+	for generation of the possible reads-from and coherence order
+	relations on the locking primitives.
+
+README
+	This file.
+
+
+===========
+LIMITATIONS
+===========
+
+The Linux-kernel memory model has the following limitations:
+
+1.	Compiler optimizations are not modeled.  Of course, the use
+	of READ_ONCE() and WRITE_ONCE() limits the compiler's ability
+	to optimize, but there is Linux-kernel code that uses bare C
+	memory accesses.  Handling this code is on the to-do list.
+	For more information, see Documentation/explanation.txt (in
+	particular, the "THE PROGRAM ORDER RELATION: po AND po-loc"
+	and "A WARNING" sections).
+
+2.	Multiple access sizes for a single variable are not supported,
+	and neither are misaligned or partially overlapping accesses.
+
+3.	Exceptions and interrupts are not modeled.  In some cases,
+	this limitation can be overcome by modeling the interrupt or
+	exception with an additional process.
+
+4.	I/O such as MMIO or DMA is not supported.
+
+5.	Self-modifying code (such as that found in the kernel's
+	alternatives mechanism, function tracer, Berkeley Packet Filter
+	JIT compiler, and module loader) is not supported.
+
+6.	Complete modeling of all variants of atomic read-modify-write
+	operations, locking primitives, and RCU is not provided.
+	For example, call_rcu() and rcu_barrier() are not supported.
+	However, a substantial amount of support is provided for these
+	operations, as shown in the linux-kernel.def file.
+
+The "herd7" tool has some additional limitations of its own, apart from
+the memory model:
+
+1.	Non-trivial data structures such as arrays or structures are
+	not supported.	However, pointers are supported, allowing trivial
+	linked lists to be constructed.
+
+2.	Dynamic memory allocation is not supported, although this can
+	be worked around in some cases by supplying multiple statically
+	allocated variables.
+
+Some of these limitations may be overcome in the future, but others are
+more likely to be addressed by incorporating the Linux-kernel memory model
+into other tools.
diff --git a/tools/memory-model/linux-kernel.bell b/tools/memory-model/linux-kernel.bell
new file mode 100644
index 000000000000..57112505f5e0
--- /dev/null
+++ b/tools/memory-model/linux-kernel.bell
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+(*
+ * Copyright (C) 2015 Jade Alglave <j.alglave@ucl.ac.uk>,
+ * Copyright (C) 2016 Luc Maranget <luc.maranget@inria.fr> for Inria
+ * Copyright (C) 2017 Alan Stern <stern@rowland.harvard.edu>,
+ *                    Andrea Parri <parri.andrea@gmail.com>
+ *
+ * An earlier version of this file appears in the companion webpage for
+ * "Frightening small children and disconcerting grown-ups: Concurrency
+ * in the Linux kernel" by Alglave, Maranget, McKenney, Parri, and Stern,
+ * which is to appear in ASPLOS 2018.
+ *)
+
+"Linux kernel memory model"
+
+enum Accesses = 'once (*READ_ONCE,WRITE_ONCE,ACCESS_ONCE*) ||
+		'release (*smp_store_release*) ||
+		'acquire (*smp_load_acquire*) ||
+		'noreturn (* R of non-return RMW *)
+instructions R[{'once,'acquire,'noreturn}]
+instructions W[{'once,'release}]
+instructions RMW[{'once,'acquire,'release}]
+
+enum Barriers = 'wmb (*smp_wmb*) ||
+		'rmb (*smp_rmb*) ||
+		'mb (*smp_mb*) ||
+		'rb_dep (*smp_read_barrier_depends*) ||
+		'rcu-lock (*rcu_read_lock*)  ||
+		'rcu-unlock (*rcu_read_unlock*) ||
+		'sync-rcu (*synchronize_rcu*) ||
+		'before_atomic (*smp_mb__before_atomic*) ||
+		'after_atomic (*smp_mb__after_atomic*) ||
+		'after_spinlock (*smp_mb__after_spinlock*)
+instructions F[Barriers]
+
+(* Compute matching pairs of nested Rcu-lock and Rcu-unlock *)
+let matched = let rec
+	    unmatched-locks = Rcu-lock \ domain(matched)
+	and unmatched-unlocks = Rcu-unlock \ range(matched)
+	and unmatched = unmatched-locks | unmatched-unlocks
+	and unmatched-po = [unmatched] ; po ; [unmatched]
+	and unmatched-locks-to-unlocks =
+		[unmatched-locks] ; po ; [unmatched-unlocks]
+	and matched = matched | (unmatched-locks-to-unlocks \
+		(unmatched-po ; unmatched-po))
+	in matched
+
+(* Validate nesting *)
+flag ~empty Rcu-lock \ domain(matched) as unbalanced-rcu-locking
+flag ~empty Rcu-unlock \ range(matched) as unbalanced-rcu-locking
+
+(* Outermost level of nesting only *)
+let crit = matched \ (po^-1 ; matched ; po^-1)
diff --git a/tools/memory-model/linux-kernel.cat b/tools/memory-model/linux-kernel.cat
new file mode 100644
index 000000000000..15b7a5dd8a9a
--- /dev/null
+++ b/tools/memory-model/linux-kernel.cat
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+(*
+ * Copyright (C) 2015 Jade Alglave <j.alglave@ucl.ac.uk>,
+ * Copyright (C) 2016 Luc Maranget <luc.maranget@inria.fr> for Inria
+ * Copyright (C) 2017 Alan Stern <stern@rowland.harvard.edu>,
+ *                    Andrea Parri <parri.andrea@gmail.com>
+ *
+ * An earlier version of this file appears in the companion webpage for
+ * "Frightening small children and disconcerting grown-ups: Concurrency
+ * in the Linux kernel" by Alglave, Maranget, McKenney, Parri, and Stern,
+ * which is to appear in ASPLOS 2018.
+ *)
+
+"Linux kernel memory model"
+
+(*
+ * File "lock.cat" handles locks and is experimental.
+ * It can be replaced by include "cos.cat" for tests that do not use locks.
+ *)
+
+include "lock.cat"
+
+(*******************)
+(* Basic relations *)
+(*******************)
+
+(* Fences *)
+let rb-dep = [R] ; fencerel(Rb_dep) ; [R]
+let rmb = [R \ Noreturn] ; fencerel(Rmb) ; [R \ Noreturn]
+let wmb = [W] ; fencerel(Wmb) ; [W]
+let mb = ([M] ; fencerel(Mb) ; [M]) |
+	([M] ; fencerel(Before_atomic) ; [RMW] ; po? ; [M]) |
+	([M] ; po? ; [RMW] ; fencerel(After_atomic) ; [M]) |
+	([M] ; po? ; [LKW] ; fencerel(After_spinlock) ; [M])
+let gp = po ; [Sync-rcu] ; po?
+
+let strong-fence = mb | gp
+
+(* Release Acquire *)
+let acq-po = [Acquire] ; po ; [M]
+let po-rel = [M] ; po ; [Release]
+let rfi-rel-acq = [Release] ; rfi ; [Acquire]
+
+(**********************************)
+(* Fundamental coherence ordering *)
+(**********************************)
+
+(* Sequential Consistency Per Variable *)
+let com = rf | co | fr
+acyclic po-loc | com as coherence
+
+(* Atomic Read-Modify-Write *)
+empty rmw & (fre ; coe) as atomic
+
+(**********************************)
+(* Instruction execution ordering *)
+(**********************************)
+
+(* Preserved Program Order *)
+let dep = addr | data
+let rwdep = (dep | ctrl) ; [W]
+let overwrite = co | fr
+let to-w = rwdep | (overwrite & int)
+let rrdep = addr | (dep ; rfi)
+let strong-rrdep = rrdep+ & rb-dep
+let to-r = strong-rrdep | rfi-rel-acq
+let fence = strong-fence | wmb | po-rel | rmb | acq-po
+let ppo = rrdep* ; (to-r | to-w | fence)
+
+(* Propagation: Ordering from release operations and strong fences. *)
+let A-cumul(r) = rfe? ; r
+let cumul-fence = A-cumul(strong-fence | po-rel) | wmb
+let prop = (overwrite & ext)? ; cumul-fence* ; rfe?
+
+(*
+ * Happens Before: Ordering from the passage of time.
+ * No fences needed here for prop because relation confined to one process.
+ *)
+let hb = ppo | rfe | ((prop \ id) & int)
+acyclic hb as happens-before
+
+(****************************************)
+(* Write and fence propagation ordering *)
+(****************************************)
+
+(* Propagation: Each non-rf link needs a strong fence. *)
+let pb = prop ; strong-fence ; hb*
+acyclic pb as propagation
+
+(*******)
+(* RCU *)
+(*******)
+
+(*
+ * Effect of read-side critical section proceeds from the rcu_read_lock()
+ * onward on the one hand and from the rcu_read_unlock() backwards on the
+ * other hand.
+ *)
+let rscs = po ; crit^-1 ; po?
+
+(*
+ * The synchronize_rcu() strong fence is special in that it can order not
+ * one but two non-rf relations, but only in conjunction with an RCU
+ * read-side critical section.
+ *)
+let link = hb* ; pb* ; prop
+
+(* Chains that affect the RCU grace-period guarantee *)
+let gp-link = gp ; link
+let rscs-link = rscs ; link
+
+(*
+ * A cycle containing at least as many grace periods as RCU read-side
+ * critical sections is forbidden.
+ *)
+let rec rcu-path =
+	gp-link |
+	(gp-link ; rscs-link) |
+	(rscs-link ; gp-link) |
+	(rcu-path ; rcu-path) |
+	(gp-link ; rcu-path ; rscs-link) |
+	(rscs-link ; rcu-path ; gp-link)
+
+irreflexive rcu-path as rcu
diff --git a/tools/memory-model/linux-kernel.cfg b/tools/memory-model/linux-kernel.cfg
new file mode 100644
index 000000000000..3c8098e99f41
--- /dev/null
+++ b/tools/memory-model/linux-kernel.cfg
@@ -0,0 +1,21 @@
+macros linux-kernel.def
+bell linux-kernel.bell
+model linux-kernel.cat
+graph columns
+squished true
+showevents noregs
+movelabel true
+fontsize 8
+xscale 2.0
+yscale 1.5
+arrowsize 0.8
+showinitrf false
+showfinalrf false
+showinitwrites false
+splines spline
+pad 0.1
+edgeattr hb,color,indigo
+edgeattr co,color,blue
+edgeattr mb,color,darkgreen
+edgeattr wmb,color,darkgreen
+edgeattr rmb,color,darkgreen
diff --git a/tools/memory-model/linux-kernel.def b/tools/memory-model/linux-kernel.def
new file mode 100644
index 000000000000..a397387f77cc
--- /dev/null
+++ b/tools/memory-model/linux-kernel.def
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// An earlier version of this file appears in the companion webpage for
+// "Frightening small children and disconcerting grown-ups: Concurrency
+// in the Linux kernel" by Alglave, Maranget, McKenney, Parri, and Stern,
+// which is to appear in ASPLOS 2018.
+
+// ONCE
+READ_ONCE(X) __load{once}(X)
+WRITE_ONCE(X,V) { __store{once}(X,V); }
+
+// Release Acquire and friends
+smp_store_release(X,V) { __store{release}(*X,V); }
+smp_load_acquire(X) __load{acquire}(*X)
+rcu_assign_pointer(X,V) { __store{release}(X,V); }
+lockless_dereference(X) __load{lderef}(X)
+rcu_dereference(X) __load{deref}(X)
+
+// Fences
+smp_mb() { __fence{mb} ; }
+smp_rmb() { __fence{rmb} ; }
+smp_wmb() { __fence{wmb} ; }
+smp_read_barrier_depends() { __fence{rb_dep}; }
+smp_mb__before_atomic() { __fence{before_atomic} ; }
+smp_mb__after_atomic() { __fence{after_atomic} ; }
+smp_mb__after_spinlock() { __fence{after_spinlock} ; }
+
+// Exchange
+xchg(X,V)  __xchg{mb}(X,V)
+xchg_relaxed(X,V) __xchg{once}(X,V)
+xchg_release(X,V) __xchg{release}(X,V)
+xchg_acquire(X,V) __xchg{acquire}(X,V)
+cmpxchg(X,V,W) __cmpxchg{mb}(X,V,W)
+cmpxchg_relaxed(X,V,W) __cmpxchg{once}(X,V,W)
+cmpxchg_acquire(X,V,W) __cmpxchg{acquire}(X,V,W)
+cmpxchg_release(X,V,W) __cmpxchg{release}(X,V,W)
+
+// Spinlocks
+spin_lock(X) { __lock(X) ; }
+spin_unlock(X) { __unlock(X) ; }
+spin_trylock(X) __trylock(X)
+
+// RCU
+rcu_read_lock() { __fence{rcu-lock}; }
+rcu_read_unlock() { __fence{rcu-unlock};}
+synchronize_rcu() { __fence{sync-rcu}; }
+synchronize_rcu_expedited() { __fence{sync-rcu}; }
+
+// Atomic
+atomic_read(X) READ_ONCE(*X)
+atomic_set(X,V) { WRITE_ONCE(*X,V) ; }
+atomic_read_acquire(X) smp_load_acquire(X)
+atomic_set_release(X,V) { smp_store_release(X,V); }
+
+atomic_add(V,X) { __atomic_op(X,+,V) ; }
+atomic_sub(V,X) { __atomic_op(X,-,V) ; }
+atomic_inc(X)   { __atomic_op(X,+,1) ; }
+atomic_dec(X)   { __atomic_op(X,-,1) ; }
+
+atomic_add_return(V,X) __atomic_op_return{mb}(X,+,V)
+atomic_add_return_relaxed(V,X) __atomic_op_return{once}(X,+,V)
+atomic_add_return_acquire(V,X) __atomic_op_return{acquire}(X,+,V)
+atomic_add_return_release(V,X) __atomic_op_return{release}(X,+,V)
+atomic_fetch_add(V,X) __atomic_fetch_op{mb}(X,+,V)
+atomic_fetch_add_relaxed(V,X) __atomic_fetch_op{once}(X,+,V)
+atomic_fetch_add_acquire(V,X) __atomic_fetch_op{acquire}(X,+,V)
+atomic_fetch_add_release(V,X) __atomic_fetch_op{release}(X,+,V)
+
+atomic_inc_return(X) __atomic_op_return{mb}(X,+,1)
+atomic_inc_return_relaxed(X) __atomic_op_return{once}(X,+,1)
+atomic_inc_return_acquire(X) __atomic_op_return{acquire}(X,+,1)
+atomic_inc_return_release(X) __atomic_op_return{release}(X,+,1)
+atomic_fetch_inc(X) __atomic_fetch_op{mb}(X,+,1)
+atomic_fetch_inc_relaxed(X) __atomic_fetch_op{once}(X,+,1)
+atomic_fetch_inc_acquire(X) __atomic_fetch_op{acquire}(X,+,1)
+atomic_fetch_inc_release(X) __atomic_fetch_op{release}(X,+,1)
+
+atomic_sub_return(V,X) __atomic_op_return{mb}(X,-,V)
+atomic_sub_return_relaxed(V,X) __atomic_op_return{once}(X,-,V)
+atomic_sub_return_acquire(V,X) __atomic_op_return{acquire}(X,-,V)
+atomic_sub_return_release(V,X) __atomic_op_return{release}(X,-,V)
+atomic_fetch_sub(V,X) __atomic_fetch_op{mb}(X,-,V)
+atomic_fetch_sub_relaxed(V,X) __atomic_fetch_op{once}(X,-,V)
+atomic_fetch_sub_acquire(V,X) __atomic_fetch_op{acquire}(X,-,V)
+atomic_fetch_sub_release(V,X) __atomic_fetch_op{release}(X,-,V)
+
+atomic_dec_return(X) __atomic_op_return{mb}(X,-,1)
+atomic_dec_return_relaxed(X) __atomic_op_return{once}(X,-,1)
+atomic_dec_return_acquire(X) __atomic_op_return{acquire}(X,-,1)
+atomic_dec_return_release(X) __atomic_op_return{release}(X,-,1)
+atomic_fetch_dec(X) __atomic_fetch_op{mb}(X,-,1)
+atomic_fetch_dec_relaxed(X) __atomic_fetch_op{once}(X,-,1)
+atomic_fetch_dec_acquire(X) __atomic_fetch_op{acquire}(X,-,1)
+atomic_fetch_dec_release(X) __atomic_fetch_op{release}(X,-,1)
+
+atomic_xchg(X,V) __xchg{mb}(X,V)
+atomic_xchg_relaxed(X,V) __xchg{once}(X,V)
+atomic_xchg_release(X,V) __xchg{release}(X,V)
+atomic_xchg_acquire(X,V) __xchg{acquire}(X,V)
+atomic_cmpxchg(X,V,W) __cmpxchg{mb}(X,V,W)
+atomic_cmpxchg_relaxed(X,V,W) __cmpxchg{once}(X,V,W)
+atomic_cmpxchg_acquire(X,V,W) __cmpxchg{acquire}(X,V,W)
+atomic_cmpxchg_release(X,V,W) __cmpxchg{release}(X,V,W)
+
+atomic_sub_and_test(V,X) __atomic_op_return{mb}(X,-,V) == 0
+atomic_dec_and_test(X)  __atomic_op_return{mb}(X,-,1) == 0
+atomic_inc_and_test(X)  __atomic_op_return{mb}(X,+,1) == 0
+atomic_add_negative(V,X) __atomic_op_return{mb}(X,+,V) < 0
diff --git a/tools/memory-model/litmus-tests/CoRR+poonceonce+Once.litmus b/tools/memory-model/litmus-tests/CoRR+poonceonce+Once.litmus
new file mode 100644
index 000000000000..5b83d57f6ac5
--- /dev/null
+++ b/tools/memory-model/litmus-tests/CoRR+poonceonce+Once.litmus
@@ -0,0 +1,19 @@
+C CoRR+poonceonce+Once
+
+{}
+
+P0(int *x)
+{
+	WRITE_ONCE(*x, 1);
+}
+
+P1(int *x)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*x);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0)
diff --git a/tools/memory-model/litmus-tests/CoRW+poonceonce+Once.litmus b/tools/memory-model/litmus-tests/CoRW+poonceonce+Once.litmus
new file mode 100644
index 000000000000..fab91c13d52c
--- /dev/null
+++ b/tools/memory-model/litmus-tests/CoRW+poonceonce+Once.litmus
@@ -0,0 +1,18 @@
+C CoRW+poonceonce+Once
+
+{}
+
+P0(int *x)
+{
+	int r0;
+
+	r0 = READ_ONCE(*x);
+	WRITE_ONCE(*x, 1);
+}
+
+P1(int *x)
+{
+	WRITE_ONCE(*x, 2);
+}
+
+exists (x=2 /\ 0:r0=2)
diff --git a/tools/memory-model/litmus-tests/CoWR+poonceonce+Once.litmus b/tools/memory-model/litmus-tests/CoWR+poonceonce+Once.litmus
new file mode 100644
index 000000000000..6a35ec2042ea
--- /dev/null
+++ b/tools/memory-model/litmus-tests/CoWR+poonceonce+Once.litmus
@@ -0,0 +1,18 @@
+C CoWR+poonceonce+Once
+
+{}
+
+P0(int *x)
+{
+	int r0;
+
+	WRITE_ONCE(*x, 1);
+	r0 = READ_ONCE(*x);
+}
+
+P1(int *x)
+{
+	WRITE_ONCE(*x, 2);
+}
+
+exists (x=1 /\ 0:r0=2)
diff --git a/tools/memory-model/litmus-tests/CoWW+poonceonce.litmus b/tools/memory-model/litmus-tests/CoWW+poonceonce.litmus
new file mode 100644
index 000000000000..32a96b832021
--- /dev/null
+++ b/tools/memory-model/litmus-tests/CoWW+poonceonce.litmus
@@ -0,0 +1,11 @@
+C CoWW+poonceonce
+
+{}
+
+P0(int *x)
+{
+	WRITE_ONCE(*x, 1);
+	WRITE_ONCE(*x, 2);
+}
+
+exists (x=1)
diff --git a/tools/memory-model/litmus-tests/IRIW+mbonceonces+OnceOnce.litmus b/tools/memory-model/litmus-tests/IRIW+mbonceonces+OnceOnce.litmus
new file mode 100644
index 000000000000..7eba2c68992b
--- /dev/null
+++ b/tools/memory-model/litmus-tests/IRIW+mbonceonces+OnceOnce.litmus
@@ -0,0 +1,35 @@
+C IRIW+mbonceonces+OnceOnce
+
+{}
+
+P0(int *x)
+{
+	WRITE_ONCE(*x, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*x);
+	smp_mb();
+	r1 = READ_ONCE(*y);
+}
+
+P2(int *y)
+{
+	WRITE_ONCE(*y, 1);
+}
+
+P3(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	smp_mb();
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0 /\ 3:r0=1 /\ 3:r1=0)
diff --git a/tools/memory-model/litmus-tests/IRIW+poonceonces+OnceOnce.litmus b/tools/memory-model/litmus-tests/IRIW+poonceonces+OnceOnce.litmus
new file mode 100644
index 000000000000..b0556c6c75d4
--- /dev/null
+++ b/tools/memory-model/litmus-tests/IRIW+poonceonces+OnceOnce.litmus
@@ -0,0 +1,33 @@
+C IRIW+poonceonces+OnceOnce
+
+{}
+
+P0(int *x)
+{
+	WRITE_ONCE(*x, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*x);
+	r1 = READ_ONCE(*y);
+}
+
+P2(int *y)
+{
+	WRITE_ONCE(*y, 1);
+}
+
+P3(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0 /\ 3:r0=1 /\ 3:r1=0)
diff --git a/tools/memory-model/litmus-tests/ISA2+poonceonces.litmus b/tools/memory-model/litmus-tests/ISA2+poonceonces.litmus
new file mode 100644
index 000000000000..9a1a233d70c3
--- /dev/null
+++ b/tools/memory-model/litmus-tests/ISA2+poonceonces.litmus
@@ -0,0 +1,28 @@
+C ISA2+poonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *y, int *z)
+{
+	int r0;
+
+	r0 = READ_ONCE(*y);
+	WRITE_ONCE(*z, 1);
+}
+
+P2(int *x, int *z)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*z);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 2:r0=1 /\ 2:r1=0)
diff --git a/tools/memory-model/litmus-tests/ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus b/tools/memory-model/litmus-tests/ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus
new file mode 100644
index 000000000000..235195e87d4e
--- /dev/null
+++ b/tools/memory-model/litmus-tests/ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus
@@ -0,0 +1,28 @@
+C ISA2+pooncerelease+poacquirerelease+poacquireonce
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	smp_store_release(y, 1);
+}
+
+P1(int *y, int *z)
+{
+	int r0;
+
+	r0 = smp_load_acquire(y);
+	smp_store_release(z, 1);
+}
+
+P2(int *x, int *z)
+{
+	int r0;
+	int r1;
+
+	r0 = smp_load_acquire(z);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 2:r0=1 /\ 2:r1=0)
diff --git a/tools/memory-model/litmus-tests/LB+ctrlonceonce+mbonceonce.litmus b/tools/memory-model/litmus-tests/LB+ctrlonceonce+mbonceonce.litmus
new file mode 100644
index 000000000000..dd5ac3a8974a
--- /dev/null
+++ b/tools/memory-model/litmus-tests/LB+ctrlonceonce+mbonceonce.litmus
@@ -0,0 +1,23 @@
+C LB+ctrlonceonce+mbonceonce
+
+{}
+
+P0(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*x);
+	if (r0)
+		WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*y);
+	smp_mb();
+	WRITE_ONCE(*x, 1);
+}
+
+exists (0:r0=1 /\ 1:r0=1)
diff --git a/tools/memory-model/litmus-tests/LB+poacquireonce+pooncerelease.litmus b/tools/memory-model/litmus-tests/LB+poacquireonce+pooncerelease.litmus
new file mode 100644
index 000000000000..47bd61319d93
--- /dev/null
+++ b/tools/memory-model/litmus-tests/LB+poacquireonce+pooncerelease.litmus
@@ -0,0 +1,21 @@
+C LB+poacquireonce+pooncerelease
+
+{}
+
+P0(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*x);
+	smp_store_release(y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = smp_load_acquire(y);
+	WRITE_ONCE(*x, 1);
+}
+
+exists (0:r0=1 /\ 1:r0=1)
diff --git a/tools/memory-model/litmus-tests/LB+poonceonces.litmus b/tools/memory-model/litmus-tests/LB+poonceonces.litmus
new file mode 100644
index 000000000000..a5cdf027e34b
--- /dev/null
+++ b/tools/memory-model/litmus-tests/LB+poonceonces.litmus
@@ -0,0 +1,21 @@
+C LB+poonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*x);
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*y);
+	WRITE_ONCE(*x, 1);
+}
+
+exists (0:r0=1 /\ 1:r0=1)
diff --git a/tools/memory-model/litmus-tests/MP+onceassign+derefonce.litmus b/tools/memory-model/litmus-tests/MP+onceassign+derefonce.litmus
new file mode 100644
index 000000000000..1a2fe5830381
--- /dev/null
+++ b/tools/memory-model/litmus-tests/MP+onceassign+derefonce.litmus
@@ -0,0 +1,25 @@
+C MP+onceassign+derefonce.litmus
+
+{
+y=z;
+z=0;
+}
+
+P0(int *x, int **y)
+{
+	WRITE_ONCE(*x, 1);
+	rcu_assign_pointer(*y, x);
+}
+
+P1(int *x, int **y)
+{
+	int *r0;
+	int r1;
+
+	rcu_read_lock();
+	r0 = rcu_dereference(*y);
+	r1 = READ_ONCE(*r0);
+	rcu_read_unlock();
+}
+
+exists (1:r0=x /\ 1:r1=0)
diff --git a/tools/memory-model/litmus-tests/MP+polocks.litmus b/tools/memory-model/litmus-tests/MP+polocks.litmus
new file mode 100644
index 000000000000..5fe6f1e3c452
--- /dev/null
+++ b/tools/memory-model/litmus-tests/MP+polocks.litmus
@@ -0,0 +1,24 @@
+C MP+polocks
+
+{}
+
+P0(int *x, int *y, spinlock_t *mylock)
+{
+	WRITE_ONCE(*x, 1);
+	spin_lock(mylock);
+	WRITE_ONCE(*y, 1);
+	spin_unlock(mylock);
+}
+
+P1(int *x, int *y, spinlock_t *mylock)
+{
+	int r0;
+	int r1;
+
+	spin_lock(mylock);
+	r0 = READ_ONCE(*y);
+	spin_unlock(mylock);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0)
diff --git a/tools/memory-model/litmus-tests/MP+poonceonces.litmus b/tools/memory-model/litmus-tests/MP+poonceonces.litmus
new file mode 100644
index 000000000000..46e1ac7ba126
--- /dev/null
+++ b/tools/memory-model/litmus-tests/MP+poonceonces.litmus
@@ -0,0 +1,20 @@
+C MP+poonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0)
diff --git a/tools/memory-model/litmus-tests/MP+pooncerelease+poacquireonce.litmus b/tools/memory-model/litmus-tests/MP+pooncerelease+poacquireonce.litmus
new file mode 100644
index 000000000000..0b00cc7293ba
--- /dev/null
+++ b/tools/memory-model/litmus-tests/MP+pooncerelease+poacquireonce.litmus
@@ -0,0 +1,20 @@
+C MP+pooncerelease+poacquireonce
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	smp_store_release(y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = smp_load_acquire(y);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0)
diff --git a/tools/memory-model/litmus-tests/MP+porevlocks.litmus b/tools/memory-model/litmus-tests/MP+porevlocks.litmus
new file mode 100644
index 000000000000..90d011c34f33
--- /dev/null
+++ b/tools/memory-model/litmus-tests/MP+porevlocks.litmus
@@ -0,0 +1,24 @@
+C MP+porevlocks
+
+{}
+
+P0(int *x, int *y, spinlock_t *mylock)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	spin_lock(mylock);
+	r1 = READ_ONCE(*x);
+	spin_unlock(mylock);
+}
+
+P1(int *x, int *y, spinlock_t *mylock)
+{
+	spin_lock(mylock);
+	WRITE_ONCE(*x, 1);
+	spin_unlock(mylock);
+	WRITE_ONCE(*y, 1);
+}
+
+exists (0:r0=1 /\ 0:r1=0)
diff --git a/tools/memory-model/litmus-tests/MP+wmbonceonce+rmbonceonce.litmus b/tools/memory-model/litmus-tests/MP+wmbonceonce+rmbonceonce.litmus
new file mode 100644
index 000000000000..604ad41ea0c2
--- /dev/null
+++ b/tools/memory-model/litmus-tests/MP+wmbonceonce+rmbonceonce.litmus
@@ -0,0 +1,22 @@
+C MP+wmbonceonce+rmbonceonce
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	smp_wmb();
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	smp_rmb();
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 1:r1=0)
diff --git a/tools/memory-model/litmus-tests/R+mbonceonces.litmus b/tools/memory-model/litmus-tests/R+mbonceonces.litmus
new file mode 100644
index 000000000000..e69b9e3e9436
--- /dev/null
+++ b/tools/memory-model/litmus-tests/R+mbonceonces.litmus
@@ -0,0 +1,21 @@
+C R+mbonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	smp_mb();
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	WRITE_ONCE(*y, 2);
+	smp_mb();
+	r0 = READ_ONCE(*x);
+}
+
+exists (y=2 /\ 1:r0=0)
diff --git a/tools/memory-model/litmus-tests/R+poonceonces.litmus b/tools/memory-model/litmus-tests/R+poonceonces.litmus
new file mode 100644
index 000000000000..f7a12e00f82d
--- /dev/null
+++ b/tools/memory-model/litmus-tests/R+poonceonces.litmus
@@ -0,0 +1,19 @@
+C R+poonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	WRITE_ONCE(*y, 2);
+	r0 = READ_ONCE(*x);
+}
+
+exists (y=2 /\ 1:r0=0)
diff --git a/tools/memory-model/litmus-tests/README b/tools/memory-model/litmus-tests/README
new file mode 100644
index 000000000000..9a3bb5949191
--- /dev/null
+++ b/tools/memory-model/litmus-tests/README
@@ -0,0 +1,125 @@
+This directory contains the following litmus tests:
+
+CoRR+poonceonce+Once.litmus
+	Test of read-read coherence, that is, whether or not two
+	successive reads from the same variable are ordered.
+
+CoRW+poonceonce+Once.litmus
+	Test of read-write coherence, that is, whether or not a read
+	from a given variable followed by a write to that same variable
+	are ordered.
+
+CoWR+poonceonce+Once.litmus
+	Test of write-read coherence, that is, whether or not a write
+	to a given variable followed by a read from that same variable
+	are ordered.
+
+CoWW+poonceonce.litmus
+	Test of write-write coherence, that is, whether or not two
+	successive writes to the same variable are ordered.
+
+IRIW+mbonceonces+OnceOnce.litmus
+	Test of independent reads from independent writes with smp_mb()
+	between each pairs of reads.  In other words, is smp_mb()
+	sufficient to cause two different reading processes to agree on
+	the order of a pair of writes, where each write is to a different
+	variable by a different process.
+
+IRIW+poonceonces+OnceOnce.litmus
+	Test of independent reads from independent writes with nothing
+	between each pairs of reads.  In other words, is anything at all
+	needed to cause two different reading processes to agree on the
+	order of a pair of writes, where each write is to a different
+	variable by a different process.
+
+ISA2+poonceonces.litmus
+	As below, but with store-release replaced with WRITE_ONCE()
+	and load-acquire replaced with READ_ONCE().
+
+ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus
+	Can a release-acquire chain order a prior store against
+	a later load?
+
+LB+ctrlonceonce+mbonceonce.litmus
+	Does a control dependency and an smp_mb() suffice for the
+	load-buffering litmus test, where each process reads from one
+	of two variables then writes to the other?
+
+LB+poacquireonce+pooncerelease.litmus
+	Does a release-acquire pair suffice for the load-buffering
+	litmus test, where each process reads from one of two variables then
+	writes to the other?
+
+LB+poonceonces.litmus
+	As above, but with store-release replaced with WRITE_ONCE()
+	and load-acquire replaced with READ_ONCE().
+
+MP+onceassign+derefonce.litmus
+	As below, but with rcu_assign_pointer() and an rcu_dereference().
+
+MP+polocks.litmus
+	As below, but with the second access of the writer process
+	and the first access of reader process protected by a lock.
+
+MP+poonceonces.litmus
+	As below, but without the smp_rmb() and smp_wmb().
+
+MP+pooncerelease+poacquireonce.litmus
+	As below, but with a release-acquire chain.
+
+MP+porevlocks.litmus
+	As below, but with the first access of the writer process
+	and the second access of reader process protected by a lock.
+
+MP+wmbonceonce+rmbonceonce.litmus
+	Does a smp_wmb() (between the stores) and an smp_rmb() (between
+	the loads) suffice for the message-passing litmus test, where one
+	process writes data and then a flag, and the other process reads
+	the flag and then the data.  (This is similar to the ISA2 tests,
+	but with two processes instead of three.)
+
+R+mbonceonces.litmus
+	This is the fully ordered (via smp_mb()) version of one of
+	the classic counterintuitive litmus tests that illustrates the
+	effects of store propagation delays.
+
+R+poonceonces.litmus
+	As above, but without the smp_mb() invocations.
+
+SB+mbonceonces.litmus
+	This is the fully ordered (again, via smp_mb() version of store
+	buffering, which forms the core of Dekker's mutual-exclusion
+	algorithm.
+
+SB+poonceonces.litmus
+	As above, but without the smp_mb() invocations.
+
+S+poonceonces.litmus
+	As below, but without the smp_wmb() and acquire load.
+
+S+wmbonceonce+poacquireonce.litmus
+	Can a smp_wmb(), instead of a release, and an acquire order
+	a prior store against a subsequent store?
+
+WRC+poonceonces+Once.litmus
+WRC+pooncerelease+rmbonceonce+Once.litmus
+	These two are members of an extension of the MP litmus-test class
+	in which the first write is moved to a separate process.
+
+Z6.0+pooncelock+pooncelock+pombonce.litmus
+	Is the ordering provided by a spin_unlock() and a subsequent
+	spin_lock() sufficient to make ordering apparent to accesses
+	by a process not holding the lock?
+
+Z6.0+pooncelock+poonceLock+pombonce.litmus
+	As above, but with smp_mb__after_spinlock() immediately
+	following the spin_lock().
+
+Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus
+	Is the ordering provided by a release-acquire chain sufficient
+	to make ordering apparent to accesses by a process that does
+	not participate in that release-acquire chain?
+
+A great many more litmus tests are available here:
+
+	https://github.com/paulmckrcu/litmus
diff --git a/tools/memory-model/litmus-tests/S+poonceonces.litmus b/tools/memory-model/litmus-tests/S+poonceonces.litmus
new file mode 100644
index 000000000000..d0d541c8ec7d
--- /dev/null
+++ b/tools/memory-model/litmus-tests/S+poonceonces.litmus
@@ -0,0 +1,19 @@
+C S+poonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 2);
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*y);
+	WRITE_ONCE(*x, 1);
+}
+
+exists (x=2 /\ 1:r0=1)
diff --git a/tools/memory-model/litmus-tests/S+wmbonceonce+poacquireonce.litmus b/tools/memory-model/litmus-tests/S+wmbonceonce+poacquireonce.litmus
new file mode 100644
index 000000000000..1d292d0d6603
--- /dev/null
+++ b/tools/memory-model/litmus-tests/S+wmbonceonce+poacquireonce.litmus
@@ -0,0 +1,20 @@
+C S+wmbonceonce+poacquireonce
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 2);
+	smp_wmb();
+	WRITE_ONCE(*y, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = smp_load_acquire(y);
+	WRITE_ONCE(*x, 1);
+}
+
+exists (x=2 /\ 1:r0=1)
diff --git a/tools/memory-model/litmus-tests/SB+mbonceonces.litmus b/tools/memory-model/litmus-tests/SB+mbonceonces.litmus
new file mode 100644
index 000000000000..b76caa5af1af
--- /dev/null
+++ b/tools/memory-model/litmus-tests/SB+mbonceonces.litmus
@@ -0,0 +1,23 @@
+C SB+mbonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	int r0;
+
+	WRITE_ONCE(*x, 1);
+	smp_mb();
+	r0 = READ_ONCE(*y);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	WRITE_ONCE(*y, 1);
+	smp_mb();
+	r0 = READ_ONCE(*x);
+}
+
+exists (0:r0=0 /\ 1:r0=0)
diff --git a/tools/memory-model/litmus-tests/SB+poonceonces.litmus b/tools/memory-model/litmus-tests/SB+poonceonces.litmus
new file mode 100644
index 000000000000..c1797e03807e
--- /dev/null
+++ b/tools/memory-model/litmus-tests/SB+poonceonces.litmus
@@ -0,0 +1,21 @@
+C SB+poonceonces
+
+{}
+
+P0(int *x, int *y)
+{
+	int r0;
+
+	WRITE_ONCE(*x, 1);
+	r0 = READ_ONCE(*y);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	WRITE_ONCE(*y, 1);
+	r0 = READ_ONCE(*x);
+}
+
+exists (0:r0=0 /\ 1:r0=0)
diff --git a/tools/memory-model/litmus-tests/WRC+poonceonces+Once.litmus b/tools/memory-model/litmus-tests/WRC+poonceonces+Once.litmus
new file mode 100644
index 000000000000..f5e7c92f61cc
--- /dev/null
+++ b/tools/memory-model/litmus-tests/WRC+poonceonces+Once.litmus
@@ -0,0 +1,27 @@
+C WRC+poonceonces+Once
+
+{}
+
+P0(int *x)
+{
+	WRITE_ONCE(*x, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*x);
+	WRITE_ONCE(*y, 1);
+}
+
+P2(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 2:r0=1 /\ 2:r1=0)
diff --git a/tools/memory-model/litmus-tests/WRC+pooncerelease+rmbonceonce+Once.litmus b/tools/memory-model/litmus-tests/WRC+pooncerelease+rmbonceonce+Once.litmus
new file mode 100644
index 000000000000..e3d0018025dd
--- /dev/null
+++ b/tools/memory-model/litmus-tests/WRC+pooncerelease+rmbonceonce+Once.litmus
@@ -0,0 +1,28 @@
+C WRC+pooncerelease+rmbonceonce+Once
+
+{}
+
+P0(int *x)
+{
+	WRITE_ONCE(*x, 1);
+}
+
+P1(int *x, int *y)
+{
+	int r0;
+
+	r0 = READ_ONCE(*x);
+	smp_store_release(y, 1);
+}
+
+P2(int *x, int *y)
+{
+	int r0;
+	int r1;
+
+	r0 = READ_ONCE(*y);
+	smp_rmb();
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ 2:r0=1 /\ 2:r1=0)
diff --git a/tools/memory-model/litmus-tests/Z6.0+pooncelock+poonceLock+pombonce.litmus b/tools/memory-model/litmus-tests/Z6.0+pooncelock+poonceLock+pombonce.litmus
new file mode 100644
index 000000000000..9c2cb53e6ef0
--- /dev/null
+++ b/tools/memory-model/litmus-tests/Z6.0+pooncelock+poonceLock+pombonce.litmus
@@ -0,0 +1,33 @@
+C Z6.0+pooncelock+poonceLock+pombonce
+
+{}
+
+P0(int *x, int *y, spinlock_t *mylock)
+{
+	spin_lock(mylock);
+	WRITE_ONCE(*x, 1);
+	WRITE_ONCE(*y, 1);
+	spin_unlock(mylock);
+}
+
+P1(int *y, int *z, spinlock_t *mylock)
+{
+	int r0;
+
+	spin_lock(mylock);
+	smp_mb__after_spinlock();
+	r0 = READ_ONCE(*y);
+	WRITE_ONCE(*z, 1);
+	spin_unlock(mylock);
+}
+
+P2(int *x, int *z)
+{
+	int r1;
+
+	WRITE_ONCE(*z, 2);
+	smp_mb();
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ z=2 /\ 2:r1=0)
diff --git a/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus b/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus
new file mode 100644
index 000000000000..c9a1f1a49ae1
--- /dev/null
+++ b/tools/memory-model/litmus-tests/Z6.0+pooncelock+pooncelock+pombonce.litmus
@@ -0,0 +1,32 @@
+C Z6.0+pooncelock+pooncelock+pombonce
+
+{}
+
+P0(int *x, int *y, spinlock_t *mylock)
+{
+	spin_lock(mylock);
+	WRITE_ONCE(*x, 1);
+	WRITE_ONCE(*y, 1);
+	spin_unlock(mylock);
+}
+
+P1(int *y, int *z, spinlock_t *mylock)
+{
+	int r0;
+
+	spin_lock(mylock);
+	r0 = READ_ONCE(*y);
+	WRITE_ONCE(*z, 1);
+	spin_unlock(mylock);
+}
+
+P2(int *x, int *z)
+{
+	int r1;
+
+	WRITE_ONCE(*z, 2);
+	smp_mb();
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ z=2 /\ 2:r1=0)
diff --git a/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus b/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus
new file mode 100644
index 000000000000..25409a033514
--- /dev/null
+++ b/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus
@@ -0,0 +1,28 @@
+C Z6.0+pooncerelease+poacquirerelease+mbonceonce
+
+{}
+
+P0(int *x, int *y)
+{
+	WRITE_ONCE(*x, 1);
+	smp_store_release(y, 1);
+}
+
+P1(int *y, int *z)
+{
+	int r0;
+
+	r0 = smp_load_acquire(y);
+	smp_store_release(z, 1);
+}
+
+P2(int *x, int *z)
+{
+	int r1;
+
+	WRITE_ONCE(*z, 2);
+	smp_mb();
+	r1 = READ_ONCE(*x);
+}
+
+exists (1:r0=1 /\ z=2 /\ 2:r1=0)
diff --git a/tools/memory-model/lock.cat b/tools/memory-model/lock.cat
new file mode 100644
index 000000000000..ba4a4ec6d313
--- /dev/null
+++ b/tools/memory-model/lock.cat
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+(*
+ * Copyright (C) 2016 Luc Maranget <luc.maranget@inria.fr> for Inria
+ * Copyright (C) 2017 Alan Stern <stern@rowland.harvard.edu>
+ *)
+
+(* Generate coherence orders and handle lock operations *)
+
+include "cross.cat"
+
+(* From lock reads to their partner lock writes *)
+let lk-rmw = ([LKR] ; po-loc ; [LKW]) \ (po ; po)
+let rmw = rmw | lk-rmw
+
+(*
+ * A paired LKR must always see an unlocked value; spin_lock() calls nested
+ * inside a critical section (for the same lock) always deadlock.
+ *)
+empty ([LKW] ; po-loc ; [domain(lk-rmw)]) \ (po-loc ; [UL] ; po-loc)
+	as lock-nest
+
+(* The litmus test is invalid if an LKW event is not part of an RMW pair *)
+flag ~empty LKW \ range(lk-rmw) as unpaired-LKW
+
+(* This will be allowed if we implement spin_is_locked() *)
+flag ~empty LKR \ domain(lk-rmw) as unpaired-LKR
+
+(* There should be no R or W accesses to spinlocks *)
+let ALL-LOCKS = LKR | LKW | UL | LF
+flag ~empty [M \ IW] ; loc ; [ALL-LOCKS] as mixed-lock-accesses
+
+(* The final value of a spinlock should not be tested *)
+flag ~empty [FW] ; loc ; [ALL-LOCKS] as lock-final
+
+
+(*
+ * Put lock operations in their appropriate classes, but leave UL out of W
+ * until after the co relation has been generated.
+ *)
+let R = R | LKR | LF
+let W = W | LKW
+
+let Release = Release | UL
+let Acquire = Acquire | LKR
+
+
+(* Match LKW events to their corresponding UL events *)
+let critical = ([LKW] ; po-loc ; [UL]) \ (po-loc ; [LKW | UL] ; po-loc)
+
+flag ~empty UL \ range(critical) as unmatched-unlock
+
+(* Allow up to one unmatched LKW per location; more must deadlock *)
+let UNMATCHED-LKW = LKW \ domain(critical)
+empty ([UNMATCHED-LKW] ; loc ; [UNMATCHED-LKW]) \ id as unmatched-locks
+
+
+(* rfi for LF events: link each LKW to the LF events in its critical section *)
+let rfi-lf = ([LKW] ; po-loc ; [LF]) \ ([LKW] ; po-loc ; [UL] ; po-loc)
+
+(* rfe for LF events *)
+let all-possible-rfe-lf =
+  (*
+   * Given an LF event r, compute the possible rfe edges for that event
+   * (all those starting from LKW events in other threads),
+   * and then convert that relation to a set of single-edge relations.
+   *)
+  let possible-rfe-lf r =
+    let pair-to-relation p = p ++ 0
+    in map pair-to-relation ((LKW * {r}) & loc & ext)
+  (* Do this for each LF event r that isn't in rfi-lf *)
+  in map possible-rfe-lf (LF \ range(rfi-lf))
+
+(* Generate all rf relations for LF events *)
+with rfe-lf from cross(all-possible-rfe-lf)
+let rf = rf | rfi-lf | rfe-lf
+
+
+(* Generate all co relations, including LKW events but not UL *)
+let co0 = co0 | ([IW] ; loc ; [LKW]) |
+	(([LKW] ; loc ; [UNMATCHED-LKW]) \ [UNMATCHED-LKW])
+include "cos-opt.cat"
+let W = W | UL
+let M = R | W
+
+(* Merge UL events into co *)
+let co = (co | critical | (critical^-1 ; co))+
+let coe = co & ext
+let coi = co & int
+
+(* Merge LKR events into rf *)
+let rf = rf | ([IW | UL] ; singlestep(co) ; lk-rmw^-1)
+let rfe = rf & ext
+let rfi = rf & int
+
+let fr = rf^-1 ; co
+let fre = fr & ext
+let fri = fr & int
+
+show co,rf,fr
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c635eab6af54..292809c3c0ca 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -21,7 +21,7 @@ If there is no debug info in the object, then annotated assembly is displayed.
 OPTIONS
 -------
 -i::
---input=::
+--input=<file>::
         Input file name. (default: perf.data unless stdin is a fifo)
 
 -d::
@@ -69,7 +69,7 @@ OPTIONS
 
 --stdio:: Use the stdio interface.
 
---stdio-color::
+--stdio-color=<mode>::
 	'always', 'never' or 'auto', allowing configuring color output
 	via the command line, in addition to via "color.ui" .perfconfig.
 	Use '--stdio-color always' to generate color even when redirecting
@@ -84,7 +84,7 @@ OPTIONS
 --gtk:: Use the GTK interface.
 
 -C::
---cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
+--cpu=<cpu>:: Only report samples for the list of CPUs provided. Multiple CPUs can
 	be provided as a comma-separated list with no space: 0,1. Ranges of
 	CPUs are specified with -: 0-2. Default is to report samples on all
 	CPUs.
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 479fc3261a50..85b8ac695c87 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -25,6 +25,10 @@ OPTIONS
 --input=<file>::
 	Select the input file (default: perf.data unless stdin is a fifo)
 
+-f::
+--force::
+	Don't do ownership validation
+
 -v::
 --verbose::
         Be more verbose. (show symbol address, etc)
@@ -61,7 +65,7 @@ OPTIONS
 	default, but this option shows live (currently allocated) pages
 	instead.  (This option works with --page option only)
 
---time::
+--time=<start>,<stop>::
 	Only analyze samples within given time window: <start>,<stop>. Times
 	have the format seconds.microseconds. If start is not given (i.e., time
 	string is ',x.y') then analysis starts at the beginning of the file. If
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt
index 4be08a1e3f8d..b0211410969b 100644
--- a/tools/perf/Documentation/perf-mem.txt
+++ b/tools/perf/Documentation/perf-mem.txt
@@ -28,6 +28,10 @@ OPTIONS
 <command>...::
 	Any command you can specify in a shell.
 
+-f::
+--force::
+	Don't do ownership validation
+
 -t::
 --type=::
 	Select the memory operation type: load or store (default: load,store)
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 907e505b6309..cba16d8a970e 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -354,7 +354,8 @@ OPTIONS
         Path to objdump binary.
 
 --group::
-	Show event group information together.
+	Show event group information together. It forces group output also
+	if there are no groups defined in data file.
 
 --demangle::
 	Demangle symbol names to human readable form. It's enabled by default,
@@ -367,7 +368,7 @@ OPTIONS
 	Use the data addresses of samples in addition to instruction addresses
 	to build the histograms.  To generate meaningful output, the perf.data
 	file must have been obtained using perf record -d -W and using a
-	special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
+	special event -e cpu/mem-loads/p or -e cpu/mem-stores/p. See
 	'perf mem' for simpler access.
 
 --percent-limit::
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 7730c1d2b5d3..36ec0257f8d3 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -303,6 +303,9 @@ OPTIONS
 --show-lost-events
 	Display lost events i.e. events of type PERF_RECORD_LOST.
 
+--show-round-events
+	Display finished round events i.e. events of type PERF_RECORD_FINISHED_ROUND.
+
 --demangle::
 	Demangle symbol names to human readable form. It's enabled by default,
 	disable with --no-demangle.
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 823fce7674bb..2bbe79a50d3c 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -146,6 +146,16 @@ Print count deltas every N milliseconds (minimum: 10ms)
 The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals.  Use with caution.
 	example: 'perf stat -I 1000 -e cycles -a sleep 5'
 
+--interval-count times::
+Print count deltas for fixed number of times.
+This option should be used together with "-I" option.
+	example: 'perf stat -I 1000 --interval-count 2 -e cycles -a'
+
+--timeout msecs::
+Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms).
+This option is not supported with the "-I" option.
+	example: 'perf stat --time 2000 -e cycles -a'
+
 --metric-only::
 Only print computed metrics. Print them in a single line.
 Don't show any raw values. Not supported with --per-thread.
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 0dfdaa9fa81e..577a5d2988fe 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -27,6 +27,8 @@ NO_SYSCALL_TABLE := 1
 # Additional ARCH settings for ppc
 ifeq ($(SRCARCH),powerpc)
   NO_PERF_REGS := 0
+  NO_SYSCALL_TABLE := 0
+  CFLAGS += -I$(OUTPUT)arch/powerpc/include/generated
   LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
 endif
 
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 9b0351d3ce34..012328038594 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -146,12 +146,6 @@ define allow-override
     $(eval $(1) = $(2)))
 endef
 
-# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix.
-$(call allow-override,CC,$(CROSS_COMPILE)gcc)
-$(call allow-override,AR,$(CROSS_COMPILE)ar)
-$(call allow-override,LD,$(CROSS_COMPILE)ld)
-$(call allow-override,CXX,$(CROSS_COMPILE)g++)
-
 LD += $(EXTRA_LDFLAGS)
 
 HOSTCC  ?= gcc
diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c
index 2323581b157d..fa639e3e52ac 100644
--- a/tools/perf/arch/arm/util/auxtrace.c
+++ b/tools/perf/arch/arm/util/auxtrace.c
@@ -68,7 +68,7 @@ struct auxtrace_record
 	bool found_spe = false;
 	static struct perf_pmu **arm_spe_pmus = NULL;
 	static int nr_spes = 0;
-	int i;
+	int i = 0;
 
 	if (!evlist)
 		return NULL;
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index fbfc055d3f4d..5c655ad4621e 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -298,12 +298,17 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
 {
 	int i;
 	int etmv3 = 0, etmv4 = 0;
-	const struct cpu_map *cpus = evlist->cpus;
+	struct cpu_map *event_cpus = evlist->cpus;
+	struct cpu_map *online_cpus = cpu_map__new(NULL);
 
 	/* cpu map is not empty, we have specific CPUs to work with */
-	if (!cpu_map__empty(cpus)) {
-		for (i = 0; i < cpu_map__nr(cpus); i++) {
-			if (cs_etm_is_etmv4(itr, cpus->map[i]))
+	if (!cpu_map__empty(event_cpus)) {
+		for (i = 0; i < cpu__max_cpu(); i++) {
+			if (!cpu_map__has(event_cpus, i) ||
+			    !cpu_map__has(online_cpus, i))
+				continue;
+
+			if (cs_etm_is_etmv4(itr, i))
 				etmv4++;
 			else
 				etmv3++;
@@ -311,6 +316,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
 	} else {
 		/* get configuration for all CPUs in the system */
 		for (i = 0; i < cpu__max_cpu(); i++) {
+			if (!cpu_map__has(online_cpus, i))
+				continue;
+
 			if (cs_etm_is_etmv4(itr, i))
 				etmv4++;
 			else
@@ -318,6 +326,8 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
 		}
 	}
 
+	cpu_map__put(online_cpus);
+
 	return (CS_ETM_HEADER_SIZE +
 	       (etmv4 * CS_ETMV4_PRIV_SIZE) +
 	       (etmv3 * CS_ETMV3_PRIV_SIZE));
@@ -447,7 +457,9 @@ static int cs_etm_info_fill(struct auxtrace_record *itr,
 	int i;
 	u32 offset;
 	u64 nr_cpu, type;
-	const struct cpu_map *cpus = session->evlist->cpus;
+	struct cpu_map *cpu_map;
+	struct cpu_map *event_cpus = session->evlist->cpus;
+	struct cpu_map *online_cpus = cpu_map__new(NULL);
 	struct cs_etm_recording *ptr =
 			container_of(itr, struct cs_etm_recording, itr);
 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
@@ -458,8 +470,21 @@ static int cs_etm_info_fill(struct auxtrace_record *itr,
 	if (!session->evlist->nr_mmaps)
 		return -EINVAL;
 
-	/* If the cpu_map is empty all CPUs are involved */
-	nr_cpu = cpu_map__empty(cpus) ? cpu__max_cpu() : cpu_map__nr(cpus);
+	/* If the cpu_map is empty all online CPUs are involved */
+	if (cpu_map__empty(event_cpus)) {
+		cpu_map = online_cpus;
+	} else {
+		/* Make sure all specified CPUs are online */
+		for (i = 0; i < cpu_map__nr(event_cpus); i++) {
+			if (cpu_map__has(event_cpus, i) &&
+			    !cpu_map__has(online_cpus, i))
+				return -EINVAL;
+		}
+
+		cpu_map = event_cpus;
+	}
+
+	nr_cpu = cpu_map__nr(cpu_map);
 	/* Get PMU type as dynamically assigned by the core */
 	type = cs_etm_pmu->type;
 
@@ -472,15 +497,11 @@ static int cs_etm_info_fill(struct auxtrace_record *itr,
 
 	offset = CS_ETM_SNAPSHOT + 1;
 
-	/* cpu map is not empty, we have specific CPUs to work with */
-	if (!cpu_map__empty(cpus)) {
-		for (i = 0; i < cpu_map__nr(cpus) && offset < priv_size; i++)
-			cs_etm_get_metadata(cpus->map[i], &offset, itr, info);
-	} else {
-		/* get configuration for all CPUs in the system */
-		for (i = 0; i < cpu__max_cpu(); i++)
+	for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
+		if (cpu_map__has(cpu_map, i))
 			cs_etm_get_metadata(i, &offset, itr, info);
-	}
+
+	cpu_map__put(online_cpus);
 
 	return 0;
 }
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 42dab7c8f508..a111239df182 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -6,3 +6,28 @@ endif
 HAVE_KVM_STAT_SUPPORT := 1
 PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
 PERF_HAVE_JITDUMP := 1
+
+#
+# Syscall table generation for perf
+#
+
+out    := $(OUTPUT)arch/powerpc/include/generated/asm
+header32 := $(out)/syscalls_32.c
+header64 := $(out)/syscalls_64.c
+sysdef := $(srctree)/tools/arch/powerpc/include/uapi/asm/unistd.h
+sysprf := $(srctree)/tools/perf/arch/powerpc/entry/syscalls/
+systbl := $(sysprf)/mksyscalltbl
+
+# Create output directory if not already present
+_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
+
+$(header64): $(sysdef) $(systbl)
+	$(Q)$(SHELL) '$(systbl)' '64' '$(CC)' $(sysdef) > $@
+
+$(header32): $(sysdef) $(systbl)
+	$(Q)$(SHELL) '$(systbl)' '32' '$(CC)' $(sysdef) > $@
+
+clean::
+	$(call QUIET_CLEAN, powerpc) $(RM) $(header32) $(header64)
+
+archheaders: $(header32) $(header64)
diff --git a/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl b/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl
new file mode 100755
index 000000000000..ef52e1dd694b
--- /dev/null
+++ b/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl
@@ -0,0 +1,37 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Generate system call table for perf. Derived from
+# s390 script.
+#
+# Copyright IBM Corp. 2017
+# Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+# Changed by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
+
+wordsize=$1
+gcc=$2
+input=$3
+
+if ! test -r $input; then
+	echo "Could not read input file" >&2
+	exit 1
+fi
+
+create_table()
+{
+	local wordsize=$1
+	local max_nr
+
+	echo "static const char *syscalltbl_powerpc_${wordsize}[] = {"
+	while read sc nr; do
+		printf '\t[%d] = "%s",\n' $nr $sc
+		max_nr=$nr
+	done
+	echo '};'
+	echo "#define SYSCALLTBL_POWERPC_${wordsize}_MAX_ID $max_nr"
+}
+
+$gcc -m${wordsize} -E -dM -x c  $input	       \
+	|sed -ne 's/^#define __NR_//p' \
+	|sort -t' ' -k2 -nu	       \
+	|create_table ${wordsize}
diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
index 8c72b44444cb..01df9d8303e1 100644
--- a/tools/perf/arch/s390/annotate/instructions.c
+++ b/tools/perf/arch/s390/annotate/instructions.c
@@ -23,12 +23,37 @@ static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *na
 	return ops;
 }
 
+static int s390__cpuid_parse(struct arch *arch, char *cpuid)
+{
+	unsigned int family;
+	char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
+	int ret;
+
+	/*
+	 * cpuid string format:
+	 * "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
+	 */
+	ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
+		     model, cpumf_v, cpumf_a);
+	if (ret >= 2) {
+		arch->family = family;
+		arch->model = 0;
+		return 0;
+	}
+
+	return -1;
+}
+
 static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
 {
+	int err = 0;
+
 	if (!arch->initialized) {
 		arch->initialized = true;
 		arch->associate_instruction_ops = s390__associate_ins_ops;
+		if (cpuid)
+			err = s390__cpuid_parse(arch, cpuid);
 	}
 
-	return 0;
+	return err;
 }
diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
index 9fa6c3e5782c..231294b80dc4 100644
--- a/tools/perf/arch/s390/util/header.c
+++ b/tools/perf/arch/s390/util/header.c
@@ -1,8 +1,9 @@
 /*
  * Implementation of get_cpuid().
  *
- * Copyright 2014 IBM Corp.
+ * Copyright IBM Corp. 2014, 2018
  * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
+ *	      Thomas Richter <tmricht@linux.vnet.ibm.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 only)
@@ -13,16 +14,153 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "../../util/header.h"
+#include "../../util/util.h"
+
+#define SYSINFO_MANU	"Manufacturer:"
+#define SYSINFO_TYPE	"Type:"
+#define SYSINFO_MODEL	"Model:"
+#define SRVLVL_CPUMF	"CPU-MF:"
+#define SRVLVL_VERSION	"version="
+#define SRVLVL_AUTHORIZATION	"authorization="
+#define SYSINFO		"/proc/sysinfo"
+#define SRVLVL		"/proc/service_levels"
 
 int get_cpuid(char *buffer, size_t sz)
 {
-	const char *cpuid = "IBM/S390";
+	char *cp, *line = NULL, *line2;
+	char type[8], model[33], version[8], manufacturer[32], authorization[8];
+	int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0;
+	int read;
+	unsigned long line_sz;
+	size_t nbytes;
+	FILE *sysinfo;
+
+	/*
+	 * Scan /proc/sysinfo line by line and read out values for
+	 * Manufacturer:, Type: and Model:, for example:
+	 * Manufacturer:    IBM
+	 * Type:            2964
+	 * Model:           702              N96
+	 * The first word is the Model Capacity and the second word is
+	 * Model (can be omitted). Both words have a maximum size of 16
+	 * bytes.
+	 */
+	memset(manufacturer, 0, sizeof(manufacturer));
+	memset(type, 0, sizeof(type));
+	memset(model, 0, sizeof(model));
+	memset(version, 0, sizeof(version));
+	memset(authorization, 0, sizeof(authorization));
+
+	sysinfo = fopen(SYSINFO, "r");
+	if (sysinfo == NULL)
+		return -1;
+
+	while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
+		if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) {
+			line2 = line + strlen(SYSINFO_MANU);
+
+			while ((cp = strtok_r(line2, "\n ", &line2))) {
+				mfsize += scnprintf(manufacturer + mfsize,
+						    sizeof(manufacturer) - mfsize, "%s", cp);
+			}
+		}
+
+		if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) {
+			line2 = line + strlen(SYSINFO_TYPE);
 
-	if (strlen(cpuid) + 1 > sz)
+			while ((cp = strtok_r(line2, "\n ", &line2))) {
+				tpsize += scnprintf(type + tpsize,
+						    sizeof(type) - tpsize, "%s", cp);
+			}
+		}
+
+		if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) {
+			line2 = line + strlen(SYSINFO_MODEL);
+
+			while ((cp = strtok_r(line2, "\n ", &line2))) {
+				mdsize += scnprintf(model + mdsize, sizeof(type) - mdsize,
+						    "%s%s", model[0] ? "," : "", cp);
+			}
+			break;
+		}
+	}
+	fclose(sysinfo);
+
+	/* Missing manufacturer, type or model information should not happen */
+	if (!manufacturer[0] || !type[0] || !model[0])
 		return -1;
 
-	strcpy(buffer, cpuid);
-	return 0;
+	/*
+	 * Scan /proc/service_levels and return the CPU-MF counter facility
+	 * version number and authorization level.
+	 * Optional, does not exist on z/VM guests.
+	 */
+	sysinfo = fopen(SRVLVL, "r");
+	if (sysinfo == NULL)
+		goto skip_sysinfo;
+	while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
+		if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF)))
+			continue;
+
+		line2 = line + strlen(SRVLVL_CPUMF);
+		while ((cp = strtok_r(line2, "\n ", &line2))) {
+			if (!strncmp(cp, SRVLVL_VERSION,
+				     strlen(SRVLVL_VERSION))) {
+				char *sep = strchr(cp, '=');
+
+				vssize += scnprintf(version + vssize,
+						    sizeof(version) - vssize, "%s", sep + 1);
+			}
+			if (!strncmp(cp, SRVLVL_AUTHORIZATION,
+				     strlen(SRVLVL_AUTHORIZATION))) {
+				char *sep = strchr(cp, '=');
+
+				atsize += scnprintf(authorization + atsize,
+						    sizeof(authorization) - atsize, "%s", sep + 1);
+			}
+		}
+	}
+	fclose(sysinfo);
+
+skip_sysinfo:
+	free(line);
+
+	if (version[0] && authorization[0] )
+		nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s",
+				  manufacturer, type, model, version,
+				  authorization);
+	else
+		nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type,
+				  model);
+	return (nbytes >= sz) ? -1 : 0;
+}
+
+char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
+{
+	char *buf = malloc(128);
+
+	if (buf && get_cpuid(buf, 128) < 0)
+		zfree(&buf);
+	return buf;
+}
+
+/*
+ * Compare the cpuid string returned by get_cpuid() function
+ * with the name generated by the jevents file read from
+ * pmu-events/arch/s390/mapfile.csv.
+ *
+ * Parameter mapcpuid is the cpuid as stored in the
+ * pmu-events/arch/s390/mapfile.csv. This is just the type number.
+ * Parameter cpuid is the cpuid returned by function get_cpuid().
+ */
+int strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
+{
+	char *cp = strchr(cpuid, ',');
+
+	if (cp == NULL)
+		return -1;
+	return strncmp(cp + 1, mapcpuid, strlen(mapcpuid));
 }
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index bf4ca749d1ac..907267206973 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1803,7 +1803,7 @@ int cmd_record(int argc, const char **argv)
 	err = target__validate(&rec->opts.target);
 	if (err) {
 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
-		ui__warning("%s", errbuf);
+		ui__warning("%s\n", errbuf);
 	}
 
 	err = target__parse_uid(&rec->opts.target);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4ad5dc649716..1eedb1815c4c 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -614,6 +614,7 @@ static int stats_print(struct report *rep)
 static void tasks_setup(struct report *rep)
 {
 	memset(&rep->tool, 0, sizeof(rep->tool));
+	rep->tool.ordered_events = true;
 	if (rep->mmaps_mode) {
 		rep->tool.mmap = perf_event__process_mmap;
 		rep->tool.mmap2 = perf_event__process_mmap2;
@@ -937,6 +938,7 @@ int cmd_report(int argc, const char **argv)
 		"perf report [<options>]",
 		NULL
 	};
+	bool group_set = false;
 	struct report report = {
 		.tool = {
 			.sample		 = process_sample_event,
@@ -1056,7 +1058,7 @@ int cmd_report(int argc, const char **argv)
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
 	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
 		    "Show a column with the sum of periods"),
-	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
+	OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &group_set,
 		    "Show event group information together"),
 	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
 		    "use branch records for per branch histogram filling",
@@ -1173,6 +1175,9 @@ int cmd_report(int argc, const char **argv)
 	has_br_stack = perf_header__has_feat(&session->header,
 					     HEADER_BRANCH_STACK);
 
+	if (group_set && !session->evlist->nr_groups)
+		perf_evlist__set_leader(session->evlist);
+
 	if (itrace_synth_opts.last_branch)
 		has_br_stack = true;
 
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ab19a6ee4093..cce926aeb0c0 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1489,6 +1489,7 @@ struct perf_script {
 	bool			show_switch_events;
 	bool			show_namespace_events;
 	bool			show_lost_events;
+	bool			show_round_events;
 	bool			allocated;
 	bool			per_event_dump;
 	struct cpu_map		*cpus;
@@ -2104,6 +2105,16 @@ process_lost_event(struct perf_tool *tool,
 	return 0;
 }
 
+static int
+process_finished_round_event(struct perf_tool *tool __maybe_unused,
+			     union perf_event *event,
+			     struct ordered_events *oe __maybe_unused)
+
+{
+	perf_event__fprintf(event, stdout);
+	return 0;
+}
+
 static void sig_handler(int sig __maybe_unused)
 {
 	session_done = 1;
@@ -2200,6 +2211,10 @@ static int __cmd_script(struct perf_script *script)
 		script->tool.namespaces = process_namespaces_event;
 	if (script->show_lost_events)
 		script->tool.lost = process_lost_event;
+	if (script->show_round_events) {
+		script->tool.ordered_events = false;
+		script->tool.finished_round = process_finished_round_event;
+	}
 
 	if (perf_script__setup_per_event_dump(script)) {
 		pr_err("Couldn't create the per event dump files\n");
@@ -3139,6 +3154,8 @@ int cmd_script(int argc, const char **argv)
 		    "Show namespace events (if recorded)"),
 	OPT_BOOLEAN('\0', "show-lost-events", &script.show_lost_events,
 		    "Show lost events (if recorded)"),
+	OPT_BOOLEAN('\0', "show-round-events", &script.show_round_events,
+		    "Show round events (if recorded)"),
 	OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump,
 		    "Dump trace output to files named by the monitored events"),
 	OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 98bf9d32f222..2d49eccf98f2 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -168,6 +168,7 @@ static struct timespec		ref_time;
 static struct cpu_map		*aggr_map;
 static aggr_get_id_t		aggr_get_id;
 static bool			append_file;
+static bool			interval_count;
 static const char		*output_name;
 static int			output_fd;
 static int			print_free_counters_hint;
@@ -571,6 +572,8 @@ static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)
 static int __run_perf_stat(int argc, const char **argv)
 {
 	int interval = stat_config.interval;
+	int times = stat_config.times;
+	int timeout = stat_config.timeout;
 	char msg[BUFSIZ];
 	unsigned long long t0, t1;
 	struct perf_evsel *counter;
@@ -584,6 +587,9 @@ static int __run_perf_stat(int argc, const char **argv)
 	if (interval) {
 		ts.tv_sec  = interval / USEC_PER_MSEC;
 		ts.tv_nsec = (interval % USEC_PER_MSEC) * NSEC_PER_MSEC;
+	} else if (timeout) {
+		ts.tv_sec  = timeout / USEC_PER_MSEC;
+		ts.tv_nsec = (timeout % USEC_PER_MSEC) * NSEC_PER_MSEC;
 	} else {
 		ts.tv_sec  = 1;
 		ts.tv_nsec = 0;
@@ -696,10 +702,14 @@ static int __run_perf_stat(int argc, const char **argv)
 		perf_evlist__start_workload(evsel_list);
 		enable_counters();
 
-		if (interval) {
+		if (interval || timeout) {
 			while (!waitpid(child_pid, &status, WNOHANG)) {
 				nanosleep(&ts, NULL);
+				if (timeout)
+					break;
 				process_interval();
+				if (interval_count && !(--times))
+					break;
 			}
 		}
 		waitpid(child_pid, &status, 0);
@@ -716,8 +726,13 @@ static int __run_perf_stat(int argc, const char **argv)
 		enable_counters();
 		while (!done) {
 			nanosleep(&ts, NULL);
-			if (interval)
+			if (timeout)
+				break;
+			if (interval) {
 				process_interval();
+				if (interval_count && !(--times))
+					break;
+			}
 		}
 	}
 
@@ -1891,6 +1906,10 @@ static const struct option stat_options[] = {
 			"command to run after to the measured command"),
 	OPT_UINTEGER('I', "interval-print", &stat_config.interval,
 		    "print counts at regular interval in ms (>= 10)"),
+	OPT_INTEGER(0, "interval-count", &stat_config.times,
+		    "print counts for fixed number of times"),
+	OPT_UINTEGER(0, "timeout", &stat_config.timeout,
+		    "stop workload and print counts after a timeout period in ms (>= 10ms)"),
 	OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
 		     "aggregate counts per processor socket", AGGR_SOCKET),
 	OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
@@ -2688,7 +2707,7 @@ int cmd_stat(int argc, const char **argv)
 	int status = -EINVAL, run_idx;
 	const char *mode;
 	FILE *output = stderr;
-	unsigned int interval;
+	unsigned int interval, timeout;
 	const char * const stat_subcommands[] = { "record", "report" };
 
 	setlocale(LC_ALL, "");
@@ -2719,6 +2738,7 @@ int cmd_stat(int argc, const char **argv)
 		return __cmd_report(argc, argv);
 
 	interval = stat_config.interval;
+	timeout = stat_config.timeout;
 
 	/*
 	 * For record command the -o is already taken care of.
@@ -2871,6 +2891,33 @@ int cmd_stat(int argc, const char **argv)
 				   "Please proceed with caution.\n");
 	}
 
+	if (stat_config.times && interval)
+		interval_count = true;
+	else if (stat_config.times && !interval) {
+		pr_err("interval-count option should be used together with "
+				"interval-print.\n");
+		parse_options_usage(stat_usage, stat_options, "interval-count", 0);
+		parse_options_usage(stat_usage, stat_options, "I", 1);
+		goto out;
+	}
+
+	if (timeout && timeout < 100) {
+		if (timeout < 10) {
+			pr_err("timeout must be >= 10ms.\n");
+			parse_options_usage(stat_usage, stat_options, "timeout", 0);
+			goto out;
+		} else
+			pr_warning("timeout < 100ms. "
+				   "The overhead percentage could be high in some cases. "
+				   "Please proceed with caution.\n");
+	}
+	if (timeout && interval) {
+		pr_err("timeout option is not supported with interval-print.\n");
+		parse_options_usage(stat_usage, stat_options, "timeout", 0);
+		parse_options_usage(stat_usage, stat_options, "I", 1);
+		goto out;
+	}
+
 	if (perf_evlist__alloc_stats(evsel_list, interval))
 		goto out;
 
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index 790ec25919a0..bf206ffe5c45 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -42,6 +42,7 @@ arch/parisc/include/uapi/asm/errno.h
 arch/powerpc/include/uapi/asm/errno.h
 arch/sparc/include/uapi/asm/errno.h
 arch/x86/include/uapi/asm/errno.h
+arch/powerpc/include/uapi/asm/unistd.h
 include/asm-generic/bitops/arch_hweight.h
 include/asm-generic/bitops/const_hweight.h
 include/asm-generic/bitops/__fls.h
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 3bf7b145b826..c7115d369511 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -482,6 +482,34 @@ static void fs_something(void)
 	}
 }
 
+static const char *do_determine_event(bool excl_kernel)
+{
+	const char *event = excl_kernel ? "cycles:u" : "cycles";
+
+#ifdef __s390x__
+	char cpuid[128], model[16], model_c[16], cpum_cf_v[16];
+	unsigned int family;
+	int ret, cpum_cf_a;
+
+	if (get_cpuid(cpuid, sizeof(cpuid)))
+		goto out_clocks;
+	ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c,
+		     model, cpum_cf_v, &cpum_cf_a);
+	if (ret != 5)		 /* Not available */
+		goto out_clocks;
+	if (excl_kernel && (cpum_cf_a & 4))
+		return event;
+	if (!excl_kernel && (cpum_cf_a & 2))
+		return event;
+
+	/* Fall through: missing authorization */
+out_clocks:
+	event = excl_kernel ? "cpu-clock:u" : "cpu-clock";
+
+#endif
+	return event;
+}
+
 static void do_something(void)
 {
 	fs_something();
@@ -592,10 +620,7 @@ static int do_test_code_reading(bool try_kcore)
 
 		perf_evlist__set_maps(evlist, cpus, threads);
 
-		if (excl_kernel)
-			str = "cycles:u";
-		else
-			str = "cycles";
+		str = do_determine_event(excl_kernel);
 		pr_debug("Parsing event '%s'\n", str);
 		ret = parse_events(evlist, str, NULL);
 		if (ret < 0) {
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 260418969120..2f008067d989 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -37,6 +37,19 @@ static int init_live_machine(struct machine *machine)
 						  mmap_handler, machine, true, 500);
 }
 
+/*
+ * We need to keep these functions global, despite the
+ * fact that they are used only locally in this object,
+ * in order to keep them around even if the binary is
+ * stripped. If they are gone, the unwind check for
+ * symbol fails.
+ */
+int test_dwarf_unwind__thread(struct thread *thread);
+int test_dwarf_unwind__compare(void *p1, void *p2);
+int test_dwarf_unwind__krava_3(struct thread *thread);
+int test_dwarf_unwind__krava_2(struct thread *thread);
+int test_dwarf_unwind__krava_1(struct thread *thread);
+
 #define MAX_STACK 8
 
 static int unwind_entry(struct unwind_entry *entry, void *arg)
@@ -45,12 +58,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
 	char *symbol = entry->sym ? entry->sym->name : NULL;
 	static const char *funcs[MAX_STACK] = {
 		"test__arch_unwind_sample",
-		"unwind_thread",
-		"compare",
+		"test_dwarf_unwind__thread",
+		"test_dwarf_unwind__compare",
 		"bsearch",
-		"krava_3",
-		"krava_2",
-		"krava_1",
+		"test_dwarf_unwind__krava_3",
+		"test_dwarf_unwind__krava_2",
+		"test_dwarf_unwind__krava_1",
 		"test__dwarf_unwind"
 	};
 	/*
@@ -77,7 +90,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
 	return strcmp((const char *) symbol, funcs[idx]);
 }
 
-static noinline int unwind_thread(struct thread *thread)
+noinline int test_dwarf_unwind__thread(struct thread *thread)
 {
 	struct perf_sample sample;
 	unsigned long cnt = 0;
@@ -108,7 +121,7 @@ static noinline int unwind_thread(struct thread *thread)
 
 static int global_unwind_retval = -INT_MAX;
 
-static noinline int compare(void *p1, void *p2)
+noinline int test_dwarf_unwind__compare(void *p1, void *p2)
 {
 	/* Any possible value should be 'thread' */
 	struct thread *thread = *(struct thread **)p1;
@@ -117,17 +130,17 @@ static noinline int compare(void *p1, void *p2)
 		/* Call unwinder twice for both callchain orders. */
 		callchain_param.order = ORDER_CALLER;
 
-		global_unwind_retval = unwind_thread(thread);
+		global_unwind_retval = test_dwarf_unwind__thread(thread);
 		if (!global_unwind_retval) {
 			callchain_param.order = ORDER_CALLEE;
-			global_unwind_retval = unwind_thread(thread);
+			global_unwind_retval = test_dwarf_unwind__thread(thread);
 		}
 	}
 
 	return p1 - p2;
 }
 
-static noinline int krava_3(struct thread *thread)
+noinline int test_dwarf_unwind__krava_3(struct thread *thread)
 {
 	struct thread *array[2] = {thread, thread};
 	void *fp = &bsearch;
@@ -141,18 +154,19 @@ static noinline int krava_3(struct thread *thread)
 			size_t, int (*)(void *, void *));
 
 	_bsearch = fp;
-	_bsearch(array, &thread, 2, sizeof(struct thread **), compare);
+	_bsearch(array, &thread, 2, sizeof(struct thread **),
+		 test_dwarf_unwind__compare);
 	return global_unwind_retval;
 }
 
-static noinline int krava_2(struct thread *thread)
+noinline int test_dwarf_unwind__krava_2(struct thread *thread)
 {
-	return krava_3(thread);
+	return test_dwarf_unwind__krava_3(thread);
 }
 
-static noinline int krava_1(struct thread *thread)
+noinline int test_dwarf_unwind__krava_1(struct thread *thread)
 {
-	return krava_2(thread);
+	return test_dwarf_unwind__krava_2(thread);
 }
 
 int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unused)
@@ -189,7 +203,7 @@ int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unu
 		goto out;
 	}
 
-	err = krava_1(thread);
+	err = test_dwarf_unwind__krava_1(thread);
 	thread__put(thread);
 
  out:
diff --git a/tools/perf/tests/shell/lib/probe_vfs_getname.sh b/tools/perf/tests/shell/lib/probe_vfs_getname.sh
index 30a950c9d407..1c16e56cd93e 100644
--- a/tools/perf/tests/shell/lib/probe_vfs_getname.sh
+++ b/tools/perf/tests/shell/lib/probe_vfs_getname.sh
@@ -5,7 +5,7 @@ had_vfs_getname=$?
 
 cleanup_probe_vfs_getname() {
 	if [ $had_vfs_getname -eq 1 ] ; then
-		perf probe -q -d probe:vfs_getname
+		perf probe -q -d probe:vfs_getname*
 	fi
 }
 
diff --git a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh
index c446c894b297..8c4ab0b390c0 100755
--- a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh
+++ b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh
@@ -21,12 +21,12 @@ trace_libc_inet_pton_backtrace() {
 	expected[3]=".*packets transmitted.*"
 	expected[4]="rtt min.*"
 	expected[5]="[0-9]+\.[0-9]+[[:space:]]+probe_libc:inet_pton:\([[:xdigit:]]+\)"
-	expected[6]=".*inet_pton[[:space:]]\($libc\)$"
+	expected[6]=".*inet_pton[[:space:]]\($libc|inlined\)$"
 	case "$(uname -m)" in
 	s390x)
 		eventattr='call-graph=dwarf'
-		expected[7]="gaih_inet[[:space:]]\(inlined\)$"
-		expected[8]="__GI_getaddrinfo[[:space:]]\(inlined\)$"
+		expected[7]="gaih_inet.*[[:space:]]\($libc|inlined\)$"
+		expected[8]="__GI_getaddrinfo[[:space:]]\($libc|inlined\)$"
 		expected[9]="main[[:space:]]\(.*/bin/ping.*\)$"
 		expected[10]="__libc_start_main[[:space:]]\($libc\)$"
 		expected[11]="_start[[:space:]]\(.*/bin/ping.*\)$"
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index f6789fb029d6..1e5adb65632a 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -56,7 +56,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
 	 * be compacted against the list of modules found in the "vmlinux"
 	 * code and with the one got from /proc/modules from the "kallsyms" code.
 	 */
-	if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true) <= 0) {
+	if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type) <= 0) {
 		pr_debug("dso__load_kallsyms ");
 		goto out;
 	}
@@ -125,7 +125,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
 
 		if (pair && UM(pair->start) == mem_start) {
 next_pair:
-			if (strcmp(sym->name, pair->name) == 0) {
+			if (arch__compare_symbol_names(sym->name, pair->name) == 0) {
 				/*
 				 * kallsyms don't have the symbol end, so we
 				 * set that by using the next symbol start - 1,
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 286427975112..e2f666391ac4 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -319,6 +319,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 	struct map_symbol *ms = ab->b.priv;
 	struct symbol *sym = ms->sym;
 	u8 pcnt_width = annotate_browser__pcnt_width(ab);
+	int width = 0;
 
 	/* PLT symbols contain external offsets */
 	if (strstr(sym->name, "@plt"))
@@ -340,13 +341,17 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 		to = (u64)btarget->idx;
 	}
 
+	if (ab->have_cycles)
+		width = IPC_WIDTH + CYCLES_WIDTH;
+
 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
-	__ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
+	__ui_browser__line_arrow(browser,
+				 pcnt_width + 2 + ab->addr_width + width,
 				 from, to);
 
 	if (is_fused(ab, cursor)) {
 		ui_browser__mark_fused(browser,
-				       pcnt_width + 3 + ab->addr_width,
+				       pcnt_width + 3 + ab->addr_width + width,
 				       from - 1,
 				       to > from ? true : false);
 	}
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 7f8553630c4d..537eadd81914 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -316,7 +316,6 @@ static int machine__write_buildid_table(struct machine *machine,
 					struct feat_fd *fd)
 {
 	int err = 0;
-	char nm[PATH_MAX];
 	struct dso *pos;
 	u16 kmisc = PERF_RECORD_MISC_KERNEL,
 	    umisc = PERF_RECORD_MISC_USER;
@@ -338,9 +337,8 @@ static int machine__write_buildid_table(struct machine *machine,
 			name = pos->short_name;
 			name_len = pos->short_name_len;
 		} else if (dso__is_kcore(pos)) {
-			machine__mmap_name(machine, nm, sizeof(nm));
-			name = nm;
-			name_len = strlen(nm);
+			name = machine->mmap_name;
+			name_len = strlen(name);
 		} else {
 			name = pos->long_name;
 			name_len = pos->long_name_len;
@@ -813,12 +811,10 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine)
 	bool is_kallsyms = dso__is_kallsyms(dso);
 	bool is_vdso = dso__is_vdso(dso);
 	const char *name = dso->long_name;
-	char nm[PATH_MAX];
 
 	if (dso__is_kcore(dso)) {
 		is_kallsyms = true;
-		machine__mmap_name(machine, nm, sizeof(nm));
-		name = nm;
+		name = machine->mmap_name;
 	}
 	return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
 				     dso->nsinfo, is_kallsyms, is_vdso);
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 1fb01849f1c7..640af88331b4 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -78,6 +78,8 @@ int cs_etm_decoder__reset(struct cs_etm_decoder *decoder)
 {
 	ocsd_datapath_resp_t dp_ret;
 
+	decoder->prev_return = OCSD_RESP_CONT;
+
 	dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET,
 				      0, 0, NULL, NULL);
 	if (OCSD_DATA_RESP_IS_FATAL(dp_ret))
@@ -253,16 +255,16 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
 	decoder->packet_count = 0;
 	for (i = 0; i < MAX_BUFFER; i++) {
 		decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL;
-		decoder->packet_buffer[i].end_addr   = 0xdeadbeefdeadbeefUL;
-		decoder->packet_buffer[i].exc	     = false;
-		decoder->packet_buffer[i].exc_ret    = false;
-		decoder->packet_buffer[i].cpu	     = INT_MIN;
+		decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL;
+		decoder->packet_buffer[i].last_instr_taken_branch = false;
+		decoder->packet_buffer[i].exc = false;
+		decoder->packet_buffer[i].exc_ret = false;
+		decoder->packet_buffer[i].cpu = INT_MIN;
 	}
 }
 
 static ocsd_datapath_resp_t
 cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
-			      const ocsd_generic_trace_elem *elem,
 			      const u8 trace_chan_id,
 			      enum cs_etm_sample_type sample_type)
 {
@@ -278,18 +280,16 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 		return OCSD_RESP_FATAL_SYS_ERR;
 
 	et = decoder->tail;
+	et = (et + 1) & (MAX_BUFFER - 1);
+	decoder->tail = et;
+	decoder->packet_count++;
+
 	decoder->packet_buffer[et].sample_type = sample_type;
-	decoder->packet_buffer[et].start_addr = elem->st_addr;
-	decoder->packet_buffer[et].end_addr = elem->en_addr;
 	decoder->packet_buffer[et].exc = false;
 	decoder->packet_buffer[et].exc_ret = false;
 	decoder->packet_buffer[et].cpu = *((int *)inode->priv);
-
-	/* Wrap around if need be */
-	et = (et + 1) & (MAX_BUFFER - 1);
-
-	decoder->tail = et;
-	decoder->packet_count++;
+	decoder->packet_buffer[et].start_addr = 0xdeadbeefdeadbeefUL;
+	decoder->packet_buffer[et].end_addr = 0xdeadbeefdeadbeefUL;
 
 	if (decoder->packet_count == MAX_BUFFER - 1)
 		return OCSD_RESP_WAIT;
@@ -297,6 +297,47 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 	return OCSD_RESP_CONT;
 }
 
+static ocsd_datapath_resp_t
+cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
+			     const ocsd_generic_trace_elem *elem,
+			     const uint8_t trace_chan_id)
+{
+	int ret = 0;
+	struct cs_etm_packet *packet;
+
+	ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
+					    CS_ETM_RANGE);
+	if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
+		return ret;
+
+	packet = &decoder->packet_buffer[decoder->tail];
+
+	packet->start_addr = elem->st_addr;
+	packet->end_addr = elem->en_addr;
+	switch (elem->last_i_type) {
+	case OCSD_INSTR_BR:
+	case OCSD_INSTR_BR_INDIRECT:
+		packet->last_instr_taken_branch = elem->last_instr_exec;
+		break;
+	case OCSD_INSTR_ISB:
+	case OCSD_INSTR_DSB_DMB:
+	case OCSD_INSTR_OTHER:
+	default:
+		packet->last_instr_taken_branch = false;
+		break;
+	}
+
+	return ret;
+}
+
+static ocsd_datapath_resp_t
+cs_etm_decoder__buffer_trace_on(struct cs_etm_decoder *decoder,
+				const uint8_t trace_chan_id)
+{
+	return cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
+					     CS_ETM_TRACE_ON);
+}
+
 static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
 				const void *context,
 				const ocsd_trc_index_t indx __maybe_unused,
@@ -313,12 +354,13 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
 		decoder->trace_on = false;
 		break;
 	case OCSD_GEN_TRC_ELEM_TRACE_ON:
+		resp = cs_etm_decoder__buffer_trace_on(decoder,
+						       trace_chan_id);
 		decoder->trace_on = true;
 		break;
 	case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
-		resp = cs_etm_decoder__buffer_packet(decoder, elem,
-						     trace_chan_id,
-						     CS_ETM_RANGE);
+		resp = cs_etm_decoder__buffer_range(decoder, elem,
+						    trace_chan_id);
 		break;
 	case OCSD_GEN_TRC_ELEM_EXCEPTION:
 		decoder->packet_buffer[decoder->tail].exc = true;
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
index 3d2e6205d186..743f5f444304 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -24,12 +24,14 @@ struct cs_etm_buffer {
 
 enum cs_etm_sample_type {
 	CS_ETM_RANGE = 1 << 0,
+	CS_ETM_TRACE_ON = 1 << 1,
 };
 
 struct cs_etm_packet {
 	enum cs_etm_sample_type sample_type;
 	u64 start_addr;
 	u64 end_addr;
+	u8 last_instr_taken_branch;
 	u8 exc;
 	u8 exc_ret;
 	int cpu;
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index b9f0a53dfa65..1b0d422373be 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -32,6 +32,14 @@
 
 #define MAX_TIMESTAMP (~0ULL)
 
+/*
+ * A64 instructions are always 4 bytes
+ *
+ * Only A64 is supported, so can use this constant for converting between
+ * addresses and instruction counts, calculting offsets etc
+ */
+#define A64_INSTR_SIZE 4
+
 struct cs_etm_auxtrace {
 	struct auxtrace auxtrace;
 	struct auxtrace_queues queues;
@@ -45,11 +53,15 @@ struct cs_etm_auxtrace {
 	u8 snapshot_mode;
 	u8 data_queued;
 	u8 sample_branches;
+	u8 sample_instructions;
 
 	int num_cpu;
 	u32 auxtrace_type;
 	u64 branches_sample_type;
 	u64 branches_id;
+	u64 instructions_sample_type;
+	u64 instructions_sample_period;
+	u64 instructions_id;
 	u64 **metadata;
 	u64 kernel_start;
 	unsigned int pmu_type;
@@ -68,6 +80,12 @@ struct cs_etm_queue {
 	u64 time;
 	u64 timestamp;
 	u64 offset;
+	u64 period_instructions;
+	struct branch_stack *last_branch;
+	struct branch_stack *last_branch_rb;
+	size_t last_branch_pos;
+	struct cs_etm_packet *prev_packet;
+	struct cs_etm_packet *packet;
 };
 
 static int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
@@ -174,6 +192,16 @@ static void cs_etm__free_queue(void *priv)
 {
 	struct cs_etm_queue *etmq = priv;
 
+	if (!etmq)
+		return;
+
+	thread__zput(etmq->thread);
+	cs_etm_decoder__free(etmq->decoder);
+	zfree(&etmq->event_buf);
+	zfree(&etmq->last_branch);
+	zfree(&etmq->last_branch_rb);
+	zfree(&etmq->prev_packet);
+	zfree(&etmq->packet);
 	free(etmq);
 }
 
@@ -270,11 +298,35 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
 	struct cs_etm_decoder_params d_params;
 	struct cs_etm_trace_params  *t_params;
 	struct cs_etm_queue *etmq;
+	size_t szp = sizeof(struct cs_etm_packet);
 
 	etmq = zalloc(sizeof(*etmq));
 	if (!etmq)
 		return NULL;
 
+	etmq->packet = zalloc(szp);
+	if (!etmq->packet)
+		goto out_free;
+
+	if (etm->synth_opts.last_branch || etm->sample_branches) {
+		etmq->prev_packet = zalloc(szp);
+		if (!etmq->prev_packet)
+			goto out_free;
+	}
+
+	if (etm->synth_opts.last_branch) {
+		size_t sz = sizeof(struct branch_stack);
+
+		sz += etm->synth_opts.last_branch_sz *
+		      sizeof(struct branch_entry);
+		etmq->last_branch = zalloc(sz);
+		if (!etmq->last_branch)
+			goto out_free;
+		etmq->last_branch_rb = zalloc(sz);
+		if (!etmq->last_branch_rb)
+			goto out_free;
+	}
+
 	etmq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
 	if (!etmq->event_buf)
 		goto out_free;
@@ -329,6 +381,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
 		goto out_free_decoder;
 
 	etmq->offset = 0;
+	etmq->period_instructions = 0;
 
 	return etmq;
 
@@ -336,6 +389,10 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
 	cs_etm_decoder__free(etmq->decoder);
 out_free:
 	zfree(&etmq->event_buf);
+	zfree(&etmq->last_branch);
+	zfree(&etmq->last_branch_rb);
+	zfree(&etmq->prev_packet);
+	zfree(&etmq->packet);
 	free(etmq);
 
 	return NULL;
@@ -389,6 +446,129 @@ static int cs_etm__update_queues(struct cs_etm_auxtrace *etm)
 	return 0;
 }
 
+static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq)
+{
+	struct branch_stack *bs_src = etmq->last_branch_rb;
+	struct branch_stack *bs_dst = etmq->last_branch;
+	size_t nr = 0;
+
+	/*
+	 * Set the number of records before early exit: ->nr is used to
+	 * determine how many branches to copy from ->entries.
+	 */
+	bs_dst->nr = bs_src->nr;
+
+	/*
+	 * Early exit when there is nothing to copy.
+	 */
+	if (!bs_src->nr)
+		return;
+
+	/*
+	 * As bs_src->entries is a circular buffer, we need to copy from it in
+	 * two steps.  First, copy the branches from the most recently inserted
+	 * branch ->last_branch_pos until the end of bs_src->entries buffer.
+	 */
+	nr = etmq->etm->synth_opts.last_branch_sz - etmq->last_branch_pos;
+	memcpy(&bs_dst->entries[0],
+	       &bs_src->entries[etmq->last_branch_pos],
+	       sizeof(struct branch_entry) * nr);
+
+	/*
+	 * If we wrapped around at least once, the branches from the beginning
+	 * of the bs_src->entries buffer and until the ->last_branch_pos element
+	 * are older valid branches: copy them over.  The total number of
+	 * branches copied over will be equal to the number of branches asked by
+	 * the user in last_branch_sz.
+	 */
+	if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) {
+		memcpy(&bs_dst->entries[nr],
+		       &bs_src->entries[0],
+		       sizeof(struct branch_entry) * etmq->last_branch_pos);
+	}
+}
+
+static inline void cs_etm__reset_last_branch_rb(struct cs_etm_queue *etmq)
+{
+	etmq->last_branch_pos = 0;
+	etmq->last_branch_rb->nr = 0;
+}
+
+static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet)
+{
+	/*
+	 * The packet records the execution range with an exclusive end address
+	 *
+	 * A64 instructions are constant size, so the last executed
+	 * instruction is A64_INSTR_SIZE before the end address
+	 * Will need to do instruction level decode for T32 instructions as
+	 * they can be variable size (not yet supported).
+	 */
+	return packet->end_addr - A64_INSTR_SIZE;
+}
+
+static inline u64 cs_etm__instr_count(const struct cs_etm_packet *packet)
+{
+	/*
+	 * Only A64 instructions are currently supported, so can get
+	 * instruction count by dividing.
+	 * Will need to do instruction level decode for T32 instructions as
+	 * they can be variable size (not yet supported).
+	 */
+	return (packet->end_addr - packet->start_addr) / A64_INSTR_SIZE;
+}
+
+static inline u64 cs_etm__instr_addr(const struct cs_etm_packet *packet,
+				     u64 offset)
+{
+	/*
+	 * Only A64 instructions are currently supported, so can get
+	 * instruction address by muliplying.
+	 * Will need to do instruction level decode for T32 instructions as
+	 * they can be variable size (not yet supported).
+	 */
+	return packet->start_addr + offset * A64_INSTR_SIZE;
+}
+
+static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq)
+{
+	struct branch_stack *bs = etmq->last_branch_rb;
+	struct branch_entry *be;
+
+	/*
+	 * The branches are recorded in a circular buffer in reverse
+	 * chronological order: we start recording from the last element of the
+	 * buffer down.  After writing the first element of the stack, move the
+	 * insert position back to the end of the buffer.
+	 */
+	if (!etmq->last_branch_pos)
+		etmq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz;
+
+	etmq->last_branch_pos -= 1;
+
+	be       = &bs->entries[etmq->last_branch_pos];
+	be->from = cs_etm__last_executed_instr(etmq->prev_packet);
+	be->to	 = etmq->packet->start_addr;
+	/* No support for mispredict */
+	be->flags.mispred = 0;
+	be->flags.predicted = 1;
+
+	/*
+	 * Increment bs->nr until reaching the number of last branches asked by
+	 * the user on the command line.
+	 */
+	if (bs->nr < etmq->etm->synth_opts.last_branch_sz)
+		bs->nr += 1;
+}
+
+static int cs_etm__inject_event(union perf_event *event,
+			       struct perf_sample *sample, u64 type)
+{
+	event->header.size = perf_event__sample_event_size(sample, type, 0);
+	return perf_event__synthesize_sample(event, type, 0, sample);
+}
+
+
 static int
 cs_etm__get_trace(struct cs_etm_buffer *buff, struct cs_etm_queue *etmq)
 {
@@ -453,35 +633,105 @@ static void  cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm,
 	}
 }
 
+static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
+					    u64 addr, u64 period)
+{
+	int ret = 0;
+	struct cs_etm_auxtrace *etm = etmq->etm;
+	union perf_event *event = etmq->event_buf;
+	struct perf_sample sample = {.ip = 0,};
+
+	event->sample.header.type = PERF_RECORD_SAMPLE;
+	event->sample.header.misc = PERF_RECORD_MISC_USER;
+	event->sample.header.size = sizeof(struct perf_event_header);
+
+	sample.ip = addr;
+	sample.pid = etmq->pid;
+	sample.tid = etmq->tid;
+	sample.id = etmq->etm->instructions_id;
+	sample.stream_id = etmq->etm->instructions_id;
+	sample.period = period;
+	sample.cpu = etmq->packet->cpu;
+	sample.flags = 0;
+	sample.insn_len = 1;
+	sample.cpumode = event->header.misc;
+
+	if (etm->synth_opts.last_branch) {
+		cs_etm__copy_last_branch_rb(etmq);
+		sample.branch_stack = etmq->last_branch;
+	}
+
+	if (etm->synth_opts.inject) {
+		ret = cs_etm__inject_event(event, &sample,
+					   etm->instructions_sample_type);
+		if (ret)
+			return ret;
+	}
+
+	ret = perf_session__deliver_synth_event(etm->session, event, &sample);
+
+	if (ret)
+		pr_err(
+			"CS ETM Trace: failed to deliver instruction event, error %d\n",
+			ret);
+
+	if (etm->synth_opts.last_branch)
+		cs_etm__reset_last_branch_rb(etmq);
+
+	return ret;
+}
+
 /*
  * The cs etm packet encodes an instruction range between a branch target
  * and the next taken branch. Generate sample accordingly.
  */
-static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
-				       struct cs_etm_packet *packet)
+static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
 {
 	int ret = 0;
 	struct cs_etm_auxtrace *etm = etmq->etm;
 	struct perf_sample sample = {.ip = 0,};
 	union perf_event *event = etmq->event_buf;
-	u64 start_addr = packet->start_addr;
-	u64 end_addr = packet->end_addr;
+	struct dummy_branch_stack {
+		u64			nr;
+		struct branch_entry	entries;
+	} dummy_bs;
 
 	event->sample.header.type = PERF_RECORD_SAMPLE;
 	event->sample.header.misc = PERF_RECORD_MISC_USER;
 	event->sample.header.size = sizeof(struct perf_event_header);
 
-	sample.ip = start_addr;
+	sample.ip = cs_etm__last_executed_instr(etmq->prev_packet);
 	sample.pid = etmq->pid;
 	sample.tid = etmq->tid;
-	sample.addr = end_addr;
+	sample.addr = etmq->packet->start_addr;
 	sample.id = etmq->etm->branches_id;
 	sample.stream_id = etmq->etm->branches_id;
 	sample.period = 1;
-	sample.cpu = packet->cpu;
+	sample.cpu = etmq->packet->cpu;
 	sample.flags = 0;
 	sample.cpumode = PERF_RECORD_MISC_USER;
 
+	/*
+	 * perf report cannot handle events without a branch stack
+	 */
+	if (etm->synth_opts.last_branch) {
+		dummy_bs = (struct dummy_branch_stack){
+			.nr = 1,
+			.entries = {
+				.from = sample.ip,
+				.to = sample.addr,
+			},
+		};
+		sample.branch_stack = (struct branch_stack *)&dummy_bs;
+	}
+
+	if (etm->synth_opts.inject) {
+		ret = cs_etm__inject_event(event, &sample,
+					   etm->branches_sample_type);
+		if (ret)
+			return ret;
+	}
+
 	ret = perf_session__deliver_synth_event(etm->session, event, &sample);
 
 	if (ret)
@@ -578,6 +828,24 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
 		etm->sample_branches = true;
 		etm->branches_sample_type = attr.sample_type;
 		etm->branches_id = id;
+		id += 1;
+		attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR;
+	}
+
+	if (etm->synth_opts.last_branch)
+		attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
+
+	if (etm->synth_opts.instructions) {
+		attr.config = PERF_COUNT_HW_INSTRUCTIONS;
+		attr.sample_period = etm->synth_opts.period;
+		etm->instructions_sample_period = attr.sample_period;
+		err = cs_etm__synth_event(session, &attr, id);
+		if (err)
+			return err;
+		etm->sample_instructions = true;
+		etm->instructions_sample_type = attr.sample_type;
+		etm->instructions_id = id;
+		id += 1;
 	}
 
 	return 0;
@@ -585,25 +853,108 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
 
 static int cs_etm__sample(struct cs_etm_queue *etmq)
 {
+	struct cs_etm_auxtrace *etm = etmq->etm;
+	struct cs_etm_packet *tmp;
 	int ret;
-	struct cs_etm_packet packet;
+	u64 instrs_executed;
 
-	while (1) {
-		ret = cs_etm_decoder__get_packet(etmq->decoder, &packet);
-		if (ret <= 0)
+	instrs_executed = cs_etm__instr_count(etmq->packet);
+	etmq->period_instructions += instrs_executed;
+
+	/*
+	 * Record a branch when the last instruction in
+	 * PREV_PACKET is a branch.
+	 */
+	if (etm->synth_opts.last_branch &&
+	    etmq->prev_packet &&
+	    etmq->prev_packet->sample_type == CS_ETM_RANGE &&
+	    etmq->prev_packet->last_instr_taken_branch)
+		cs_etm__update_last_branch_rb(etmq);
+
+	if (etm->sample_instructions &&
+	    etmq->period_instructions >= etm->instructions_sample_period) {
+		/*
+		 * Emit instruction sample periodically
+		 * TODO: allow period to be defined in cycles and clock time
+		 */
+
+		/* Get number of instructions executed after the sample point */
+		u64 instrs_over = etmq->period_instructions -
+			etm->instructions_sample_period;
+
+		/*
+		 * Calculate the address of the sampled instruction (-1 as
+		 * sample is reported as though instruction has just been
+		 * executed, but PC has not advanced to next instruction)
+		 */
+		u64 offset = (instrs_executed - instrs_over - 1);
+		u64 addr = cs_etm__instr_addr(etmq->packet, offset);
+
+		ret = cs_etm__synth_instruction_sample(
+			etmq, addr, etm->instructions_sample_period);
+		if (ret)
+			return ret;
+
+		/* Carry remaining instructions into next sample period */
+		etmq->period_instructions = instrs_over;
+	}
+
+	if (etm->sample_branches &&
+	    etmq->prev_packet &&
+	    etmq->prev_packet->sample_type == CS_ETM_RANGE &&
+	    etmq->prev_packet->last_instr_taken_branch) {
+		ret = cs_etm__synth_branch_sample(etmq);
+		if (ret)
 			return ret;
+	}
 
+	if (etm->sample_branches || etm->synth_opts.last_branch) {
 		/*
-		 * If the packet contains an instruction range, generate an
-		 * instruction sequence event.
+		 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
+		 * the next incoming packet.
 		 */
-		if (packet.sample_type & CS_ETM_RANGE)
-			cs_etm__synth_branch_sample(etmq, &packet);
+		tmp = etmq->packet;
+		etmq->packet = etmq->prev_packet;
+		etmq->prev_packet = tmp;
 	}
 
 	return 0;
 }
 
+static int cs_etm__flush(struct cs_etm_queue *etmq)
+{
+	int err = 0;
+	struct cs_etm_packet *tmp;
+
+	if (etmq->etm->synth_opts.last_branch &&
+	    etmq->prev_packet &&
+	    etmq->prev_packet->sample_type == CS_ETM_RANGE) {
+		/*
+		 * Generate a last branch event for the branches left in the
+		 * circular buffer at the end of the trace.
+		 *
+		 * Use the address of the end of the last reported execution
+		 * range
+		 */
+		u64 addr = cs_etm__last_executed_instr(etmq->prev_packet);
+
+		err = cs_etm__synth_instruction_sample(
+			etmq, addr,
+			etmq->period_instructions);
+		etmq->period_instructions = 0;
+
+		/*
+		 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
+		 * the next incoming packet.
+		 */
+		tmp = etmq->packet;
+		etmq->packet = etmq->prev_packet;
+		etmq->prev_packet = tmp;
+	}
+
+	return err;
+}
+
 static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 {
 	struct cs_etm_auxtrace *etm = etmq->etm;
@@ -615,45 +966,72 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 		etm->kernel_start = machine__kernel_start(etm->machine);
 
 	/* Go through each buffer in the queue and decode them one by one */
-more:
-	buffer_used = 0;
-	memset(&buffer, 0, sizeof(buffer));
-	err = cs_etm__get_trace(&buffer, etmq);
-	if (err <= 0)
-		return err;
-	/*
-	 * We cannot assume consecutive blocks in the data file are contiguous,
-	 * reset the decoder to force re-sync.
-	 */
-	err = cs_etm_decoder__reset(etmq->decoder);
-	if (err != 0)
-		return err;
-
-	/* Run trace decoder until buffer consumed or end of trace */
-	do {
-		processed = 0;
-
-		err = cs_etm_decoder__process_data_block(
-						etmq->decoder,
-						etmq->offset,
-						&buffer.buf[buffer_used],
-						buffer.len - buffer_used,
-						&processed);
-
-		if (err)
+	while (1) {
+		buffer_used = 0;
+		memset(&buffer, 0, sizeof(buffer));
+		err = cs_etm__get_trace(&buffer, etmq);
+		if (err <= 0)
 			return err;
-
-		etmq->offset += processed;
-		buffer_used += processed;
-
 		/*
-		 * Nothing to do with an error condition, let's hope the next
-		 * chunk will be better.
+		 * We cannot assume consecutive blocks in the data file are
+		 * contiguous, reset the decoder to force re-sync.
 		 */
-		err = cs_etm__sample(etmq);
-	} while (buffer.len > buffer_used);
+		err = cs_etm_decoder__reset(etmq->decoder);
+		if (err != 0)
+			return err;
+
+		/* Run trace decoder until buffer consumed or end of trace */
+		do {
+			processed = 0;
+			err = cs_etm_decoder__process_data_block(
+				etmq->decoder,
+				etmq->offset,
+				&buffer.buf[buffer_used],
+				buffer.len - buffer_used,
+				&processed);
+			if (err)
+				return err;
+
+			etmq->offset += processed;
+			buffer_used += processed;
+
+			/* Process each packet in this chunk */
+			while (1) {
+				err = cs_etm_decoder__get_packet(etmq->decoder,
+								 etmq->packet);
+				if (err <= 0)
+					/*
+					 * Stop processing this chunk on
+					 * end of data or error
+					 */
+					break;
+
+				switch (etmq->packet->sample_type) {
+				case CS_ETM_RANGE:
+					/*
+					 * If the packet contains an instruction
+					 * range, generate instruction sequence
+					 * events.
+					 */
+					cs_etm__sample(etmq);
+					break;
+				case CS_ETM_TRACE_ON:
+					/*
+					 * Discontinuity in trace, flush
+					 * previous branch stack
+					 */
+					cs_etm__flush(etmq);
+					break;
+				default:
+					break;
+				}
+			}
+		} while (buffer.len > buffer_used);
 
-goto more;
+		if (err == 0)
+			/* Flush any remaining branch stack entries */
+			err = cs_etm__flush(etmq);
+	}
 
 	return err;
 }
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 44e603c27944..f0a6cbd033cc 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -894,8 +894,6 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
 				       struct machine *machine)
 {
 	size_t size;
-	const char *mmap_name;
-	char name_buff[PATH_MAX];
 	struct map *map = machine__kernel_map(machine);
 	struct kmap *kmap;
 	int err;
@@ -918,7 +916,6 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
 		return -1;
 	}
 
-	mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
 	if (machine__is_host(machine)) {
 		/*
 		 * kernel uses PERF_RECORD_MISC_USER for user space maps,
@@ -931,7 +928,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
 
 	kmap = map__kmap(map);
 	size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
-			"%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1;
+			"%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
 	size = PERF_ALIGN(size, sizeof(u64));
 	event->mmap.header.type = PERF_RECORD_MMAP;
 	event->mmap.header.size = (sizeof(event->mmap) -
@@ -1591,17 +1588,6 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
 		return -1;
 
 	dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
-	/*
-	 * Have we already created the kernel maps for this machine?
-	 *
-	 * This should have happened earlier, when we processed the kernel MMAP
-	 * events, but for older perf.data files there was no such thing, so do
-	 * it now.
-	 */
-	if (sample->cpumode == PERF_RECORD_MISC_KERNEL &&
-	    machine__kernel_map(machine) == NULL)
-		machine__create_kernel_maps(machine);
-
 	thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, al);
 	dump_printf(" ...... dso: %s\n",
 		    al->map ? al->map->dso->long_name :
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index e5fc14e53c05..7b7d535396f7 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1086,11 +1086,30 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages)
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
 {
+	bool all_threads = (target->per_thread && target->system_wide);
 	struct cpu_map *cpus;
 	struct thread_map *threads;
 
+	/*
+	 * If specify '-a' and '--per-thread' to perf record, perf record
+	 * will override '--per-thread'. target->per_thread = false and
+	 * target->system_wide = true.
+	 *
+	 * If specify '--per-thread' only to perf record,
+	 * target->per_thread = true and target->system_wide = false.
+	 *
+	 * So target->per_thread && target->system_wide is false.
+	 * For perf record, thread_map__new_str doesn't call
+	 * thread_map__new_all_cpus. That will keep perf record's
+	 * current behavior.
+	 *
+	 * For perf stat, it allows the case that target->per_thread and
+	 * target->system_wide are all true. It means to collect system-wide
+	 * per-thread data. thread_map__new_str will call
+	 * thread_map__new_all_cpus to enumerate all threads.
+	 */
 	threads = thread_map__new_str(target->pid, target->tid, target->uid,
-				      target->per_thread);
+				      all_threads);
 
 	if (!threads)
 		return -1;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f28aaaa3a440..942bdec6d70d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -174,4 +174,5 @@ int write_padded(struct feat_fd *fd, const void *bf,
 int get_cpuid(char *buffer, size_t sz);
 
 char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused);
+int strcmp_cpuid_str(const char *s1, const char *s2);
 #endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b6140950301e..44a8456cea10 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -879,7 +879,7 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter,
 	 * cumulated only one time to prevent entries more than 100%
 	 * overhead.
 	 */
-	he_cache = malloc(sizeof(*he_cache) * (iter->max_stack + 1));
+	he_cache = malloc(sizeof(*he_cache) * (callchain_cursor.nr + 1));
 	if (he_cache == NULL)
 		return -ENOMEM;
 
@@ -1045,8 +1045,6 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
 	if (err)
 		return err;
 
-	iter->max_stack = max_stack_depth;
-
 	err = iter->ops->prepare_entry(iter, al);
 	if (err)
 		goto out;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 02721b579746..e869cad4d89f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -107,7 +107,6 @@ struct hist_entry_iter {
 	int curr;
 
 	bool hide_unresolved;
-	int max_stack;
 
 	struct perf_evsel *evsel;
 	struct perf_sample *sample;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index b05a67464c03..fe27ef55cbb9 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -48,8 +48,31 @@ static void machine__threads_init(struct machine *machine)
 	}
 }
 
+static int machine__set_mmap_name(struct machine *machine)
+{
+	if (machine__is_host(machine)) {
+		if (symbol_conf.vmlinux_name)
+			machine->mmap_name = strdup(symbol_conf.vmlinux_name);
+		else
+			machine->mmap_name = strdup("[kernel.kallsyms]");
+	} else if (machine__is_default_guest(machine)) {
+		if (symbol_conf.default_guest_vmlinux_name)
+			machine->mmap_name = strdup(symbol_conf.default_guest_vmlinux_name);
+		else
+			machine->mmap_name = strdup("[guest.kernel.kallsyms]");
+	} else {
+		if (asprintf(&machine->mmap_name, "[guest.kernel.kallsyms.%d]",
+			 machine->pid) < 0)
+			machine->mmap_name = NULL;
+	}
+
+	return machine->mmap_name ? 0 : -ENOMEM;
+}
+
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
+	int err = -ENOMEM;
+
 	memset(machine, 0, sizeof(*machine));
 	map_groups__init(&machine->kmaps, machine);
 	RB_CLEAR_NODE(&machine->rb_node);
@@ -73,13 +96,16 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 	if (machine->root_dir == NULL)
 		return -ENOMEM;
 
+	if (machine__set_mmap_name(machine))
+		goto out;
+
 	if (pid != HOST_KERNEL_ID) {
 		struct thread *thread = machine__findnew_thread(machine, -1,
 								pid);
 		char comm[64];
 
 		if (thread == NULL)
-			return -ENOMEM;
+			goto out;
 
 		snprintf(comm, sizeof(comm), "[guest/%d]", pid);
 		thread__set_comm(thread, comm, 0);
@@ -87,7 +113,13 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 	}
 
 	machine->current_tid = NULL;
+	err = 0;
 
+out:
+	if (err) {
+		zfree(&machine->root_dir);
+		zfree(&machine->mmap_name);
+	}
 	return 0;
 }
 
@@ -119,7 +151,7 @@ struct machine *machine__new_kallsyms(void)
 	 *    ask for not using the kcore parsing code, once this one is fixed
 	 *    to create a map per module.
 	 */
-	if (machine && __machine__load_kallsyms(machine, "/proc/kallsyms", MAP__FUNCTION, true) <= 0) {
+	if (machine && machine__load_kallsyms(machine, "/proc/kallsyms", MAP__FUNCTION) <= 0) {
 		machine__delete(machine);
 		machine = NULL;
 	}
@@ -180,6 +212,7 @@ void machine__exit(struct machine *machine)
 	dsos__exit(&machine->dsos);
 	machine__exit_vdso(machine);
 	zfree(&machine->root_dir);
+	zfree(&machine->mmap_name);
 	zfree(&machine->current_tid);
 
 	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
@@ -322,20 +355,6 @@ void machines__process_guests(struct machines *machines,
 	}
 }
 
-char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
-{
-	if (machine__is_host(machine))
-		snprintf(bf, size, "[%s]", "kernel.kallsyms");
-	else if (machine__is_default_guest(machine))
-		snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
-	else {
-		snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
-			 machine->pid);
-	}
-
-	return bf;
-}
-
 void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 {
 	struct rb_node *node;
@@ -771,25 +790,13 @@ size_t machine__fprintf(struct machine *machine, FILE *fp)
 
 static struct dso *machine__get_kernel(struct machine *machine)
 {
-	const char *vmlinux_name = NULL;
+	const char *vmlinux_name = machine->mmap_name;
 	struct dso *kernel;
 
 	if (machine__is_host(machine)) {
-		vmlinux_name = symbol_conf.vmlinux_name;
-		if (!vmlinux_name)
-			vmlinux_name = DSO__NAME_KALLSYMS;
-
 		kernel = machine__findnew_kernel(machine, vmlinux_name,
 						 "[kernel]", DSO_TYPE_KERNEL);
 	} else {
-		char bf[PATH_MAX];
-
-		if (machine__is_default_guest(machine))
-			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
-		if (!vmlinux_name)
-			vmlinux_name = machine__mmap_name(machine, bf,
-							  sizeof(bf));
-
 		kernel = machine__findnew_kernel(machine, vmlinux_name,
 						 "[guest.kernel]",
 						 DSO_TYPE_GUEST_KERNEL);
@@ -849,13 +856,10 @@ static int machine__get_running_kernel_start(struct machine *machine,
 	return 0;
 }
 
-int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
+static int
+__machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
 {
 	int type;
-	u64 start = 0;
-
-	if (machine__get_running_kernel_start(machine, NULL, &start))
-		return -1;
 
 	/* In case of renewal the kernel map, destroy previous one */
 	machine__destroy_kernel_maps(machine);
@@ -864,7 +868,7 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
 		struct kmap *kmap;
 		struct map *map;
 
-		machine->vmlinux_maps[type] = map__new2(start, kernel, type);
+		machine->vmlinux_maps[type] = map__new2(0, kernel, type);
 		if (machine->vmlinux_maps[type] == NULL)
 			return -1;
 
@@ -987,11 +991,11 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid)
 	return machine__create_kernel_maps(machine);
 }
 
-int __machine__load_kallsyms(struct machine *machine, const char *filename,
-			     enum map_type type, bool no_kcore)
+int machine__load_kallsyms(struct machine *machine, const char *filename,
+			     enum map_type type)
 {
 	struct map *map = machine__kernel_map(machine);
-	int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore);
+	int ret = __dso__load_kallsyms(map->dso, filename, map, true);
 
 	if (ret > 0) {
 		dso__set_loaded(map->dso, type);
@@ -1006,12 +1010,6 @@ int __machine__load_kallsyms(struct machine *machine, const char *filename,
 	return ret;
 }
 
-int machine__load_kallsyms(struct machine *machine, const char *filename,
-			   enum map_type type)
-{
-	return __machine__load_kallsyms(machine, filename, type, false);
-}
-
 int machine__load_vmlinux_path(struct machine *machine, enum map_type type)
 {
 	struct map *map = machine__kernel_map(machine);
@@ -1215,6 +1213,24 @@ static int machine__create_modules(struct machine *machine)
 	return 0;
 }
 
+static void machine__set_kernel_mmap(struct machine *machine,
+				     u64 start, u64 end)
+{
+	int i;
+
+	for (i = 0; i < MAP__NR_TYPES; i++) {
+		machine->vmlinux_maps[i]->start = start;
+		machine->vmlinux_maps[i]->end   = end;
+
+		/*
+		 * Be a bit paranoid here, some perf.data file came with
+		 * a zero sized synthesized MMAP event for the kernel.
+		 */
+		if (machine->vmlinux_maps[i]->end == 0)
+			machine->vmlinux_maps[i]->end = ~0ULL;
+	}
+}
+
 int machine__create_kernel_maps(struct machine *machine)
 {
 	struct dso *kernel = machine__get_kernel(machine);
@@ -1239,40 +1255,22 @@ int machine__create_kernel_maps(struct machine *machine)
 				 "continuing anyway...\n", machine->pid);
 	}
 
-	/*
-	 * Now that we have all the maps created, just set the ->end of them:
-	 */
-	map_groups__fixup_end(&machine->kmaps);
-
 	if (!machine__get_running_kernel_start(machine, &name, &addr)) {
 		if (name &&
 		    maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) {
 			machine__destroy_kernel_maps(machine);
 			return -1;
 		}
+		machine__set_kernel_mmap(machine, addr, 0);
 	}
 
+	/*
+	 * Now that we have all the maps created, just set the ->end of them:
+	 */
+	map_groups__fixup_end(&machine->kmaps);
 	return 0;
 }
 
-static void machine__set_kernel_mmap_len(struct machine *machine,
-					 union perf_event *event)
-{
-	int i;
-
-	for (i = 0; i < MAP__NR_TYPES; i++) {
-		machine->vmlinux_maps[i]->start = event->mmap.start;
-		machine->vmlinux_maps[i]->end   = (event->mmap.start +
-						   event->mmap.len);
-		/*
-		 * Be a bit paranoid here, some perf.data file came with
-		 * a zero sized synthesized MMAP event for the kernel.
-		 */
-		if (machine->vmlinux_maps[i]->end == 0)
-			machine->vmlinux_maps[i]->end = ~0ULL;
-	}
-}
-
 static bool machine__uses_kcore(struct machine *machine)
 {
 	struct dso *dso;
@@ -1289,7 +1287,6 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 					      union perf_event *event)
 {
 	struct map *map;
-	char kmmap_prefix[PATH_MAX];
 	enum dso_kernel_type kernel_type;
 	bool is_kernel_mmap;
 
@@ -1297,15 +1294,14 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 	if (machine__uses_kcore(machine))
 		return 0;
 
-	machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
 	if (machine__is_host(machine))
 		kernel_type = DSO_TYPE_KERNEL;
 	else
 		kernel_type = DSO_TYPE_GUEST_KERNEL;
 
 	is_kernel_mmap = memcmp(event->mmap.filename,
-				kmmap_prefix,
-				strlen(kmmap_prefix) - 1) == 0;
+				machine->mmap_name,
+				strlen(machine->mmap_name) - 1) == 0;
 	if (event->mmap.filename[0] == '/' ||
 	    (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
 		map = machine__findnew_module_map(machine, event->mmap.start,
@@ -1316,7 +1312,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		map->end = map->start + event->mmap.len;
 	} else if (is_kernel_mmap) {
 		const char *symbol_name = (event->mmap.filename +
-				strlen(kmmap_prefix));
+				strlen(machine->mmap_name));
 		/*
 		 * Should be there already, from the build-id table in
 		 * the header.
@@ -1357,7 +1353,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		up_read(&machine->dsos.lock);
 
 		if (kernel == NULL)
-			kernel = machine__findnew_dso(machine, kmmap_prefix);
+			kernel = machine__findnew_dso(machine, machine->mmap_name);
 		if (kernel == NULL)
 			goto out_problem;
 
@@ -1370,7 +1366,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
 		if (strstr(kernel->long_name, "vmlinux"))
 			dso__set_short_name(kernel, "[kernel.vmlinux]", false);
 
-		machine__set_kernel_mmap_len(machine, event);
+		machine__set_kernel_mmap(machine, event->mmap.start,
+					 event->mmap.start + event->mmap.len);
 
 		/*
 		 * Avoid using a zero address (kptr_restrict) for the ref reloc
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 5ce860b64c74..66cc200ef86f 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -43,6 +43,7 @@ struct machine {
 	bool		  comm_exec;
 	bool		  kptr_restrict_warned;
 	char		  *root_dir;
+	char		  *mmap_name;
 	struct threads    threads[THREADS__TABLE_SIZE];
 	struct vdso_info  *vdso_info;
 	struct perf_env   *env;
@@ -142,8 +143,6 @@ struct machine *machines__find(struct machines *machines, pid_t pid);
 struct machine *machines__findnew(struct machines *machines, pid_t pid);
 
 void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
-char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
-
 void machines__set_comm_exec(struct machines *machines, bool comm_exec);
 
 struct machine *machine__new_host(void);
@@ -226,8 +225,6 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
 					const char *filename);
 int arch__fix_module_text_start(u64 *start, const char *name);
 
-int __machine__load_kallsyms(struct machine *machine, const char *filename,
-			     enum map_type type, bool no_kcore);
 int machine__load_kallsyms(struct machine *machine, const char *filename,
 			   enum map_type type);
 int machine__load_vmlinux_path(struct machine *machine, enum map_type type);
@@ -239,7 +236,6 @@ size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
 				     bool (skip)(struct dso *dso, int parm), int parm);
 
 void machine__destroy_kernel_maps(struct machine *machine);
-int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
 int machine__create_kernel_maps(struct machine *machine);
 
 int machines__create_kernel_maps(struct machines *machines, pid_t pid);
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 57e38fdf0b34..1111d5bf15ca 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -576,6 +576,34 @@ char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
 	return NULL;
 }
 
+/* Return zero when the cpuid from the mapfile.csv matches the
+ * cpuid string generated on this platform.
+ * Otherwise return non-zero.
+ */
+int __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
+{
+	regex_t re;
+	regmatch_t pmatch[1];
+	int match;
+
+	if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) {
+		/* Warn unable to generate match particular string. */
+		pr_info("Invalid regular expression %s\n", mapcpuid);
+		return 1;
+	}
+
+	match = !regexec(&re, cpuid, 1, pmatch, 0);
+	regfree(&re);
+	if (match) {
+		size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
+
+		/* Verify the entire string matched. */
+		if (match_len == strlen(cpuid))
+			return 0;
+	}
+	return 1;
+}
+
 static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 {
 	char *cpuid;
@@ -610,31 +638,14 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
 
 	i = 0;
 	for (;;) {
-		regex_t re;
-		regmatch_t pmatch[1];
-		int match;
-
 		map = &pmu_events_map[i++];
 		if (!map->table) {
 			map = NULL;
 			break;
 		}
 
-		if (regcomp(&re, map->cpuid, REG_EXTENDED) != 0) {
-			/* Warn unable to generate match particular string. */
-			pr_info("Invalid regular expression %s\n", map->cpuid);
+		if (!strcmp_cpuid_str(map->cpuid, cpuid))
 			break;
-		}
-
-		match = !regexec(&re, cpuid, 1, pmatch, 0);
-		regfree(&re);
-		if (match) {
-			size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
-
-			/* Verify the entire string matched. */
-			if (match_len == strlen(cpuid))
-				break;
-		}
 	}
 	free(cpuid);
 	return map;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2da4d0456a03..e8514f651865 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -111,17 +111,20 @@ struct sort_entry sort_thread = {
 
 /* --sort comm */
 
+/*
+ * We can't use pointer comparison in functions below,
+ * because it gives different results based on pointer
+ * values, which could break some sorting assumptions.
+ */
 static int64_t
 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 {
-	/* Compare the addr that should be unique among comm */
 	return strcmp(comm__str(right->comm), comm__str(left->comm));
 }
 
 static int64_t
 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
 {
-	/* Compare the addr that should be unique among comm */
 	return strcmp(comm__str(right->comm), comm__str(left->comm));
 }
 
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index dbc6f7134f61..2f44e386a0e8 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -90,6 +90,8 @@ struct perf_stat_config {
 	bool		scale;
 	FILE		*output;
 	unsigned int	interval;
+	unsigned int	timeout;
+	int		times;
 	struct runtime_stat *stats;
 	int		stats_num;
 };
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index cc065d4bfafc..a1a312d99f30 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1582,7 +1582,7 @@ int dso__load(struct dso *dso, struct map *map)
 		bool next_slot = false;
 		bool is_reg;
 		bool nsexit;
-		int sirc;
+		int sirc = -1;
 
 		enum dso_binary_type symtab_type = binary_type_symtab[i];
 
@@ -1600,16 +1600,14 @@ int dso__load(struct dso *dso, struct map *map)
 			nsinfo__mountns_exit(&nsc);
 
 		is_reg = is_regular_file(name);
-		sirc = symsrc__init(ss, dso, name, symtab_type);
+		if (is_reg)
+			sirc = symsrc__init(ss, dso, name, symtab_type);
 
 		if (nsexit)
 			nsinfo__mountns_enter(dso->nsinfo, &nsc);
 
-		if (!is_reg || sirc < 0) {
-			if (sirc >= 0)
-				symsrc__destroy(ss);
+		if (!is_reg || sirc < 0)
 			continue;
-		}
 
 		if (!syms_ss && symsrc__has_symtab(ss)) {
 			syms_ss = ss;
@@ -1960,8 +1958,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)
 		pr_debug("Using %s for symbols\n", kallsyms_filename);
 	if (err > 0 && !dso__is_kcore(dso)) {
 		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
-		machine__mmap_name(machine, path, sizeof(path));
-		dso__set_long_name(dso, strdup(path), true);
+		dso__set_long_name(dso, machine->mmap_name, false);
 		map__fixup_start(map);
 		map__fixup_end(map);
 	}
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c
index 303bdb84ab5a..895122d638dd 100644
--- a/tools/perf/util/syscalltbl.c
+++ b/tools/perf/util/syscalltbl.c
@@ -30,6 +30,14 @@ static const char **syscalltbl_native = syscalltbl_x86_64;
 #include <asm/syscalls_64.c>
 const int syscalltbl_native_max_id = SYSCALLTBL_S390_64_MAX_ID;
 static const char **syscalltbl_native = syscalltbl_s390_64;
+#elif defined(__powerpc64__)
+#include <asm/syscalls_64.c>
+const int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_64_MAX_ID;
+static const char **syscalltbl_native = syscalltbl_powerpc_64;
+#elif defined(__powerpc__)
+#include <asm/syscalls_32.c>
+const int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_32_MAX_ID;
+static const char **syscalltbl_native = syscalltbl_powerpc_32;
 #endif
 
 struct syscall {
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 3e1038f6491c..729dad8f412d 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -323,7 +323,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
 }
 
 struct thread_map *thread_map__new_str(const char *pid, const char *tid,
-				       uid_t uid, bool per_thread)
+				       uid_t uid, bool all_threads)
 {
 	if (pid)
 		return thread_map__new_by_pid_str(pid);
@@ -331,7 +331,7 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid,
 	if (!tid && uid != UINT_MAX)
 		return thread_map__new_by_uid(uid);
 
-	if (per_thread)
+	if (all_threads)
 		return thread_map__new_all_cpus();
 
 	return thread_map__new_by_tid_str(tid);
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 0a806b99e73c..5ec91cfd1869 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -31,7 +31,7 @@ struct thread_map *thread_map__get(struct thread_map *map);
 void thread_map__put(struct thread_map *map);
 
 struct thread_map *thread_map__new_str(const char *pid,
-		const char *tid, uid_t uid, bool per_thread);
+		const char *tid, uid_t uid, bool all_threads);
 
 struct thread_map *thread_map__new_by_tid_str(const char *tid_str);
 
diff --git a/tools/power/acpi/Makefile.config b/tools/power/acpi/Makefile.config
index a1883bbb0144..2cccbba64418 100644
--- a/tools/power/acpi/Makefile.config
+++ b/tools/power/acpi/Makefile.config
@@ -56,9 +56,6 @@ INSTALL_SCRIPT = ${INSTALL_PROGRAM}
 # to compile vs uClibc, that can be done here as well.
 CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc-
 CROSS_COMPILE ?= $(CROSS)
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)gcc
-STRIP = $(CROSS_COMPILE)strip
 HOSTCC = gcc
 
 # check if compiler option is supported
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index fcb3ed0be5f8..dd614463d4d6 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -42,6 +42,24 @@ EXTRA_WARNINGS += -Wformat
 
 CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
 
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting various cross-compile vars or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,LD,$(CROSS_COMPILE)ld)
+$(call allow-override,CXX,$(CROSS_COMPILE)g++)
+$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
+
 ifeq ($(CC_NO_CLANG), 1)
 EXTRA_WARNINGS += -Wstrict-aliasing=3
 endif
diff --git a/tools/spi/Makefile b/tools/spi/Makefile
index 90615e10c79a..815d15589177 100644
--- a/tools/spi/Makefile
+++ b/tools/spi/Makefile
@@ -11,8 +11,6 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := spidev_test spidev_fdx
diff --git a/tools/testing/selftests/android/Makefile b/tools/testing/selftests/android/Makefile
index 1a7492268993..f6304d2be90c 100644
--- a/tools/testing/selftests/android/Makefile
+++ b/tools/testing/selftests/android/Makefile
@@ -11,11 +11,11 @@ all:
 		BUILD_TARGET=$(OUTPUT)/$$DIR;	\
 		mkdir $$BUILD_TARGET  -p;	\
 		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
-		#SUBDIR test prog name should be in the form: SUBDIR_test.sh
+		#SUBDIR test prog name should be in the form: SUBDIR_test.sh \
 		TEST=$$DIR"_test.sh"; \
-		if [ -e $$DIR/$$TEST ]; then
-			rsync -a $$DIR/$$TEST $$BUILD_TARGET/;
-		fi
+		if [ -e $$DIR/$$TEST ]; then \
+			rsync -a $$DIR/$$TEST $$BUILD_TARGET/; \
+		fi \
 	done
 
 override define RUN_TESTS
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 5c43c187f27c..8567a858b789 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -35,12 +35,14 @@ TEST_GEN_PROGS_EXTENDED = test_libbpf_open
 
 include ../lib.mk
 
-BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c
+BPFOBJ := $(OUTPUT)/libbpf.a
 
 $(TEST_GEN_PROGS): $(BPFOBJ)
 
 $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
 
+$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
+
 .PHONY: force
 
 # force a rebuild of BPFOBJ when its dependencies are updated
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c
index 95a370f3d378..5d73db416460 100644
--- a/tools/testing/selftests/bpf/test_tcpbpf_user.c
+++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c
@@ -11,6 +11,8 @@
 #include <linux/ptrace.h>
 #include <linux/bpf.h>
 #include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -42,6 +44,7 @@ static int bpf_find_map(const char *test, struct bpf_object *obj,
 
 int main(int argc, char **argv)
 {
+	struct rlimit limit  = { RLIM_INFINITY, RLIM_INFINITY };
 	const char *file = "test_tcpbpf_kern.o";
 	struct tcpbpf_globals g = {0};
 	int cg_fd, prog_fd, map_fd;
@@ -54,6 +57,9 @@ int main(int argc, char **argv)
 	int pid;
 	int rv;
 
+	if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0)
+		perror("Unable to lift memlock rlimit");
+
 	if (argc > 1 && strcmp(argv[1], "-d") == 0)
 		debug_flag = true;
 
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index c0f16e93f9bd..2971ba2829ac 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -57,6 +57,9 @@
 #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS	(1 << 0)
 #define F_LOAD_WITH_STRICT_ALIGNMENT		(1 << 1)
 
+#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
+static bool unpriv_disabled = false;
+
 struct bpf_test {
 	const char *descr;
 	struct bpf_insn	insns[MAX_INSNS];
@@ -11291,7 +11294,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
 			goto fail_log;
 		}
 		if (!strstr(bpf_vlog, expected_err) && !reject_from_alignment) {
-			printf("FAIL\nUnexpected error message!\n");
+			printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n",
+			      expected_err, bpf_vlog);
 			goto fail_log;
 		}
 	}
@@ -11375,9 +11379,20 @@ static int set_admin(bool admin)
 	return ret;
 }
 
+static void get_unpriv_disabled()
+{
+	char buf[2];
+	FILE *fd;
+
+	fd = fopen("/proc/sys/"UNPRIV_SYSCTL, "r");
+	if (fgets(buf, 2, fd) == buf && atoi(buf))
+		unpriv_disabled = true;
+	fclose(fd);
+}
+
 static int do_test(bool unpriv, unsigned int from, unsigned int to)
 {
-	int i, passes = 0, errors = 0;
+	int i, passes = 0, errors = 0, skips = 0;
 
 	for (i = from; i < to; i++) {
 		struct bpf_test *test = &tests[i];
@@ -11385,7 +11400,10 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to)
 		/* Program types that are not supported by non-root we
 		 * skip right away.
 		 */
-		if (!test->prog_type) {
+		if (!test->prog_type && unpriv_disabled) {
+			printf("#%d/u %s SKIP\n", i, test->descr);
+			skips++;
+		} else if (!test->prog_type) {
 			if (!unpriv)
 				set_admin(false);
 			printf("#%d/u %s ", i, test->descr);
@@ -11394,13 +11412,17 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to)
 				set_admin(true);
 		}
 
-		if (!unpriv) {
+		if (unpriv) {
+			printf("#%d/p %s SKIP\n", i, test->descr);
+			skips++;
+		} else {
 			printf("#%d/p %s ", i, test->descr);
 			do_test_single(test, false, &passes, &errors);
 		}
 	}
 
-	printf("Summary: %d PASSED, %d FAILED\n", passes, errors);
+	printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes,
+	       skips, errors);
 	return errors ? EXIT_FAILURE : EXIT_SUCCESS;
 }
 
@@ -11428,6 +11450,13 @@ int main(int argc, char **argv)
 		}
 	}
 
+	get_unpriv_disabled();
+	if (unpriv && unpriv_disabled) {
+		printf("Cannot run as unprivileged user with sysctl %s.\n",
+		       UNPRIV_SYSCTL);
+		return EXIT_FAILURE;
+	}
+
 	setrlimit(RLIMIT_MEMLOCK, unpriv ? &rlim : &rinf);
 	return do_test(unpriv, from, to);
 }
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile
index cea4adcd42b8..a63e8453984d 100644
--- a/tools/testing/selftests/futex/Makefile
+++ b/tools/testing/selftests/futex/Makefile
@@ -12,9 +12,9 @@ all:
 		BUILD_TARGET=$(OUTPUT)/$$DIR;	\
 		mkdir $$BUILD_TARGET  -p;	\
 		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
-		if [ -e $$DIR/$(TEST_PROGS) ]; then
-			rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/;
-		fi
+		if [ -e $$DIR/$(TEST_PROGS) ]; then \
+			rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \
+		fi \
 	done
 
 override define RUN_TESTS
diff --git a/tools/testing/selftests/memfd/config b/tools/testing/selftests/memfd/config
new file mode 100644
index 000000000000..835c7f4dadcd
--- /dev/null
+++ b/tools/testing/selftests/memfd/config
@@ -0,0 +1 @@
+CONFIG_FUSE_FS=m
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 86636d207adf..183b46883875 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -4,7 +4,7 @@ all:
 include ../lib.mk
 
 TEST_PROGS := mem-on-off-test.sh
-override RUN_TESTS := ./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]"
+override RUN_TESTS := @./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]"
 override EMIT_TESTS := echo "$(RUN_TESTS)"
 
 run_full_test:
diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh
new file mode 100755
index 000000000000..06b1d7cc12cc
--- /dev/null
+++ b/tools/testing/selftests/net/fib-onlink-tests.sh
@@ -0,0 +1,375 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# IPv4 and IPv6 onlink tests
+
+PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
+
+# Network interfaces
+# - odd in current namespace; even in peer ns
+declare -A NETIFS
+# default VRF
+NETIFS[p1]=veth1
+NETIFS[p2]=veth2
+NETIFS[p3]=veth3
+NETIFS[p4]=veth4
+# VRF
+NETIFS[p5]=veth5
+NETIFS[p6]=veth6
+NETIFS[p7]=veth7
+NETIFS[p8]=veth8
+
+# /24 network
+declare -A V4ADDRS
+V4ADDRS[p1]=169.254.1.1
+V4ADDRS[p2]=169.254.1.2
+V4ADDRS[p3]=169.254.3.1
+V4ADDRS[p4]=169.254.3.2
+V4ADDRS[p5]=169.254.5.1
+V4ADDRS[p6]=169.254.5.2
+V4ADDRS[p7]=169.254.7.1
+V4ADDRS[p8]=169.254.7.2
+
+# /64 network
+declare -A V6ADDRS
+V6ADDRS[p1]=2001:db8:101::1
+V6ADDRS[p2]=2001:db8:101::2
+V6ADDRS[p3]=2001:db8:301::1
+V6ADDRS[p4]=2001:db8:301::2
+V6ADDRS[p5]=2001:db8:501::1
+V6ADDRS[p6]=2001:db8:501::2
+V6ADDRS[p7]=2001:db8:701::1
+V6ADDRS[p8]=2001:db8:701::2
+
+# Test networks:
+# [1] = default table
+# [2] = VRF
+#
+# /32 host routes
+declare -A TEST_NET4
+TEST_NET4[1]=169.254.101
+TEST_NET4[2]=169.254.102
+# /128 host routes
+declare -A TEST_NET6
+TEST_NET6[1]=2001:db8:101
+TEST_NET6[2]=2001:db8:102
+
+# connected gateway
+CONGW[1]=169.254.1.254
+CONGW[2]=169.254.5.254
+
+# recursive gateway
+RECGW4[1]=169.254.11.254
+RECGW4[2]=169.254.12.254
+RECGW6[1]=2001:db8:11::64
+RECGW6[2]=2001:db8:12::64
+
+# for v4 mapped to v6
+declare -A TEST_NET4IN6IN6
+TEST_NET4IN6[1]=10.1.1.254
+TEST_NET4IN6[2]=10.2.1.254
+
+# mcast address
+MCAST6=ff02::1
+
+
+PEER_NS=bart
+PEER_CMD="ip netns exec ${PEER_NS}"
+VRF=lisa
+VRF_TABLE=1101
+PBR_TABLE=101
+
+################################################################################
+# utilities
+
+log_test()
+{
+	local rc=$1
+	local expected=$2
+	local msg="$3"
+
+	if [ ${rc} -eq ${expected} ]; then
+		nsuccess=$((nsuccess+1))
+		printf "\n    TEST: %-50s  [ OK ]\n" "${msg}"
+	else
+		nfail=$((nfail+1))
+		printf "\n    TEST: %-50s  [FAIL]\n" "${msg}"
+		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+			echo
+			echo "hit enter to continue, 'q' to quit"
+			read a
+			[ "$a" = "q" ] && exit 1
+		fi
+	fi
+}
+
+log_section()
+{
+	echo
+	echo "######################################################################"
+	echo "TEST SECTION: $*"
+	echo "######################################################################"
+}
+
+log_subsection()
+{
+	echo
+	echo "#########################################"
+	echo "TEST SUBSECTION: $*"
+}
+
+run_cmd()
+{
+	echo
+	echo "COMMAND: $*"
+	eval $*
+}
+
+get_linklocal()
+{
+	local dev=$1
+	local pfx
+	local addr
+
+	addr=$(${pfx} ip -6 -br addr show dev ${dev} | \
+	awk '{
+		for (i = 3; i <= NF; ++i) {
+			if ($i ~ /^fe80/)
+				print $i
+		}
+	}'
+	)
+	addr=${addr/\/*}
+
+	[ -z "$addr" ] && return 1
+
+	echo $addr
+
+	return 0
+}
+
+################################################################################
+#
+
+setup()
+{
+	echo
+	echo "########################################"
+	echo "Configuring interfaces"
+
+	set -e
+
+	# create namespace
+	ip netns add ${PEER_NS}
+	ip -netns ${PEER_NS} li set lo up
+
+	# add vrf table
+	ip li add ${VRF} type vrf table ${VRF_TABLE}
+	ip li set ${VRF} up
+	ip ro add table ${VRF_TABLE} unreachable default
+	ip -6 ro add table ${VRF_TABLE} unreachable default
+
+	# create test interfaces
+	ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]}
+	ip li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]}
+	ip li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]}
+	ip li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]}
+
+	# enslave vrf interfaces
+	for n in 5 7; do
+		ip li set ${NETIFS[p${n}]} vrf ${VRF}
+	done
+
+	# add addresses
+	for n in 1 3 5 7; do
+		ip li set ${NETIFS[p${n}]} up
+		ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]}
+		ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]}
+	done
+
+	# move peer interfaces to namespace and add addresses
+	for n in 2 4 6 8; do
+		ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up
+		ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]}
+		ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]}
+	done
+
+	set +e
+
+	# let DAD complete - assume default of 1 probe
+	sleep 1
+}
+
+cleanup()
+{
+	# make sure we start from a clean slate
+	ip netns del ${PEER_NS} 2>/dev/null
+	for n in 1 3 5 7; do
+		ip link del ${NETIFS[p${n}]} 2>/dev/null
+	done
+	ip link del ${VRF} 2>/dev/null
+	ip ro flush table ${VRF_TABLE}
+	ip -6 ro flush table ${VRF_TABLE}
+}
+
+################################################################################
+# IPv4 tests
+#
+
+run_ip()
+{
+	local table="$1"
+	local prefix="$2"
+	local gw="$3"
+	local dev="$4"
+	local exp_rc="$5"
+	local desc="$6"
+
+	# dev arg may be empty
+	[ -n "${dev}" ] && dev="dev ${dev}"
+
+	run_cmd ip ro add table "${table}" "${prefix}"/32 via "${gw}" "${dev}" onlink
+	log_test $? ${exp_rc} "${desc}"
+}
+
+valid_onlink_ipv4()
+{
+	# - unicast connected, unicast recursive
+	#
+	log_subsection "default VRF - main table"
+
+	run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected"
+	run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive"
+
+	log_subsection "VRF ${VRF}"
+
+	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected"
+	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
+
+	log_subsection "VRF device, PBR table"
+
+	run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected"
+	run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
+}
+
+invalid_onlink_ipv4()
+{
+	run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \
+		"Invalid gw - local unicast address"
+
+	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \
+		"Invalid gw - local unicast address, VRF"
+
+	run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given"
+
+	run_ip 254 ${TEST_NET4[1]}.102 ${V4ADDRS[p3]} ${NETIFS[p1]} 2 \
+		"Gateway resolves to wrong nexthop device"
+
+	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.103 ${V4ADDRS[p7]} ${NETIFS[p5]} 2 \
+		"Gateway resolves to wrong nexthop device - VRF"
+}
+
+################################################################################
+# IPv6 tests
+#
+
+run_ip6()
+{
+	local table="$1"
+	local prefix="$2"
+	local gw="$3"
+	local dev="$4"
+	local exp_rc="$5"
+	local desc="$6"
+
+	# dev arg may be empty
+	[ -n "${dev}" ] && dev="dev ${dev}"
+
+	run_cmd ip -6 ro add table "${table}" "${prefix}"/128 via "${gw}" "${dev}" onlink
+	log_test $? ${exp_rc} "${desc}"
+}
+
+valid_onlink_ipv6()
+{
+	# - unicast connected, unicast recursive, v4-mapped
+	#
+	log_subsection "default VRF - main table"
+
+	run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected"
+	run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive"
+	run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped"
+
+	log_subsection "VRF ${VRF}"
+
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected"
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive"
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped"
+
+	log_subsection "VRF device, PBR table"
+
+	run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected"
+	run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive"
+	run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped"
+}
+
+invalid_onlink_ipv6()
+{
+	local lladdr
+
+	lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1
+
+	run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \
+		"Invalid gw - local unicast address"
+	run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \
+		"Invalid gw - local linklocal address"
+	run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \
+		"Invalid gw - multicast address"
+
+	lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \
+		"Invalid gw - local unicast address, VRF"
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \
+		"Invalid gw - local linklocal address, VRF"
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \
+		"Invalid gw - multicast address, VRF"
+
+	run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \
+		"No nexthop device given"
+
+	# default VRF validation is done against LOCAL table
+	# run_ip6 254 ${TEST_NET6[1]}::102 ${V6ADDRS[p3]/::[0-9]/::64} ${NETIFS[p1]} 2 \
+	#	"Gateway resolves to wrong nexthop device"
+
+	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::103 ${V6ADDRS[p7]/::[0-9]/::64} ${NETIFS[p5]} 2 \
+		"Gateway resolves to wrong nexthop device - VRF"
+}
+
+run_onlink_tests()
+{
+	log_section "IPv4 onlink"
+	log_subsection "Valid onlink commands"
+	valid_onlink_ipv4
+	log_subsection "Invalid onlink commands"
+	invalid_onlink_ipv4
+
+	log_section "IPv6 onlink"
+	log_subsection "Valid onlink commands"
+	valid_onlink_ipv6
+	invalid_onlink_ipv6
+}
+
+################################################################################
+# main
+
+nsuccess=0
+nfail=0
+
+cleanup
+setup
+run_onlink_tests
+cleanup
+
+if [ "$TESTS" != "none" ]; then
+	printf "\nTests passed: %3d\n" ${nsuccess}
+	printf "Tests failed: %3d\n"   ${nfail}
+fi
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index a9154eefb2e2..b617985ecdc1 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -6,154 +6,155 @@
 
 ret=0
 
-check_err()
-{
-	if [ $ret -eq 0 ]; then
-		ret=$1
-	fi
-}
+PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
 
-check_fail()
+log_test()
 {
-	if [ $1 -eq 0 ]; then
+	local rc=$1
+	local expected=$2
+	local msg="$3"
+
+	if [ ${rc} -eq ${expected} ]; then
+		printf "        %-60s  [ OK ]\n" "${msg}"
+	else
 		ret=1
+		printf "        %-60s  [FAIL]\n" "${msg}"
+		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+		echo
+			echo "hit enter to continue, 'q' to quit"
+			read a
+			[ "$a" = "q" ] && exit 1
+		fi
 	fi
 }
 
-netns_create()
+setup()
 {
-	local testns=$1
+	set -e
+	ip netns add testns
+	ip -netns testns link set dev lo up
+
+	ip -netns testns link add dummy0 type dummy
+	ip -netns testns link set dev dummy0 up
+	ip -netns testns address add 198.51.100.1/24 dev dummy0
+	ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0
+	set +e
 
-	ip netns add $testns
-	ip netns exec $testns ip link set dev lo up
 }
 
-fib_unreg_unicast_test()
+cleanup()
 {
-	ret=0
-
-	netns_create "testns"
-
-	ip netns exec testns ip link add dummy0 type dummy
-	ip netns exec testns ip link set dev dummy0 up
+	ip -netns testns link del dev dummy0 &> /dev/null
+	ip netns del testns
+}
 
-	ip netns exec testns ip address add 198.51.100.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0
+fib_unreg_unicast_test()
+{
+	echo
+	echo "Single path route test"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null
-	check_err $?
+	setup
 
-	ip netns exec testns ip link del dev dummy0
-	check_err $?
+	echo "    Start point"
+	ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null
-	check_fail $?
+	set -e
+	ip -netns testns link del dev dummy0
+	set +e
 
-	ip netns del testns
+	echo "    Nexthop device deleted"
+	ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null
+	log_test $? 2 "IPv4 fibmatch - no route"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null
+	log_test $? 2 "IPv6 fibmatch - no route"
 
-	if [ $ret -ne 0 ]; then
-		echo "FAIL: unicast route test"
-		return 1
-	fi
-	echo "PASS: unicast route test"
+	cleanup
 }
 
 fib_unreg_multipath_test()
 {
-	ret=0
-
-	netns_create "testns"
 
-	ip netns exec testns ip link add dummy0 type dummy
-	ip netns exec testns ip link set dev dummy0 up
+	echo
+	echo "Multipath route test"
 
-	ip netns exec testns ip link add dummy1 type dummy
-	ip netns exec testns ip link set dev dummy1 up
+	setup
 
-	ip netns exec testns ip address add 198.51.100.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0
+	set -e
+	ip -netns testns link add dummy1 type dummy
+	ip -netns testns link set dev dummy1 up
+	ip -netns testns address add 192.0.2.1/24 dev dummy1
+	ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1
 
-	ip netns exec testns ip address add 192.0.2.1/24 dev dummy1
-	ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy1
-
-	ip netns exec testns ip route add 203.0.113.0/24 \
+	ip -netns testns route add 203.0.113.0/24 \
 		nexthop via 198.51.100.2 dev dummy0 \
 		nexthop via 192.0.2.2 dev dummy1
-	ip netns exec testns ip -6 route add 2001:db8:3::/64 \
+	ip -netns testns -6 route add 2001:db8:3::/64 \
 		nexthop via 2001:db8:1::2 dev dummy0 \
 		nexthop via 2001:db8:2::2 dev dummy1
+	set +e
+
+	echo "    Start point"
+	ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null
-	check_err $?
+	set -e
+	ip -netns testns link del dev dummy0
+	set +e
 
-	ip netns exec testns ip link del dev dummy0
-	check_err $?
+	echo "    One nexthop device deleted"
+	ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null
+	log_test $? 2 "IPv4 - multipath route removed on delete"
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null
 	# In IPv6 we do not flush the entire multipath route.
-	check_err $?
+	log_test $? 0 "IPv6 - multipath down to single path"
 
-	ip netns exec testns ip link del dev dummy1
+	set -e
+	ip -netns testns link del dev dummy1
+	set +e
 
-	ip netns del testns
+	echo "    Second nexthop device deleted"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null
+	log_test $? 2 "IPv6 - no route"
 
-	if [ $ret -ne 0 ]; then
-		echo "FAIL: multipath route test"
-		return 1
-	fi
-	echo "PASS: multipath route test"
+	cleanup
 }
 
 fib_unreg_test()
 {
-	echo "Running netdev unregister tests"
-
 	fib_unreg_unicast_test
 	fib_unreg_multipath_test
 }
 
 fib_down_unicast_test()
 {
-	ret=0
-
-	netns_create "testns"
-
-	ip netns exec testns ip link add dummy0 type dummy
-	ip netns exec testns ip link set dev dummy0 up
-
-	ip netns exec testns ip address add 198.51.100.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0
+	echo
+	echo "Single path, admin down"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null
-	check_err $?
+	setup
 
-	ip netns exec testns ip link set dev dummy0 down
-	check_err $?
+	echo "    Start point"
+	ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null
-	check_fail $?
+	set -e
+	ip -netns testns link set dev dummy0 down
+	set +e
 
-	ip netns exec testns ip link del dev dummy0
+	echo "    Route deleted on down"
+	ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null
+	log_test $? 2 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null
+	log_test $? 2 "IPv6 fibmatch"
 
-	ip netns del testns
-
-	if [ $ret -ne 0 ]; then
-		echo "FAIL: unicast route test"
-		return 1
-	fi
-	echo "PASS: unicast route test"
+	cleanup
 }
 
 fib_down_multipath_test_do()
@@ -161,242 +162,229 @@ fib_down_multipath_test_do()
 	local down_dev=$1
 	local up_dev=$2
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 \
+	ip -netns testns route get fibmatch 203.0.113.1 \
 		oif $down_dev &> /dev/null
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 \
+	log_test $? 2 "IPv4 fibmatch on down device"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 \
 		oif $down_dev &> /dev/null
-	check_fail $?
+	log_test $? 2 "IPv6 fibmatch on down device"
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 \
+	ip -netns testns route get fibmatch 203.0.113.1 \
 		oif $up_dev &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 \
+	log_test $? 0 "IPv4 fibmatch on up device"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 \
 		oif $up_dev &> /dev/null
-	check_err $?
+	log_test $? 0 "IPv6 fibmatch on up device"
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 | \
+	ip -netns testns route get fibmatch 203.0.113.1 | \
 		grep $down_dev | grep -q "dead linkdown"
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 | \
+	log_test $? 0 "IPv4 flags on down device"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \
 		grep $down_dev | grep -q "dead linkdown"
-	check_err $?
+	log_test $? 0 "IPv6 flags on down device"
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 | \
+	ip -netns testns route get fibmatch 203.0.113.1 | \
 		grep $up_dev | grep -q "dead linkdown"
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 | \
+	log_test $? 1 "IPv4 flags on up device"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \
 		grep $up_dev | grep -q "dead linkdown"
-	check_fail $?
+	log_test $? 1 "IPv6 flags on up device"
 }
 
 fib_down_multipath_test()
 {
-	ret=0
+	echo
+	echo "Admin down multipath"
 
-	netns_create "testns"
+	setup
 
-	ip netns exec testns ip link add dummy0 type dummy
-	ip netns exec testns ip link set dev dummy0 up
+	set -e
+	ip -netns testns link add dummy1 type dummy
+	ip -netns testns link set dev dummy1 up
 
-	ip netns exec testns ip link add dummy1 type dummy
-	ip netns exec testns ip link set dev dummy1 up
+	ip -netns testns address add 192.0.2.1/24 dev dummy1
+	ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1
 
-	ip netns exec testns ip address add 198.51.100.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0
-
-	ip netns exec testns ip address add 192.0.2.1/24 dev dummy1
-	ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy1
-
-	ip netns exec testns ip route add 203.0.113.0/24 \
+	ip -netns testns route add 203.0.113.0/24 \
 		nexthop via 198.51.100.2 dev dummy0 \
 		nexthop via 192.0.2.2 dev dummy1
-	ip netns exec testns ip -6 route add 2001:db8:3::/64 \
+	ip -netns testns -6 route add 2001:db8:3::/64 \
 		nexthop via 2001:db8:1::2 dev dummy0 \
 		nexthop via 2001:db8:2::2 dev dummy1
+	set +e
+
+	echo "    Verify start point"
+	ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null
-	check_err $?
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip link set dev dummy0 down
-	check_err $?
+	set -e
+	ip -netns testns link set dev dummy0 down
+	set +e
 
+	echo "    One device down, one up"
 	fib_down_multipath_test_do "dummy0" "dummy1"
 
-	ip netns exec testns ip link set dev dummy0 up
-	check_err $?
-	ip netns exec testns ip link set dev dummy1 down
-	check_err $?
+	set -e
+	ip -netns testns link set dev dummy0 up
+	ip -netns testns link set dev dummy1 down
+	set +e
 
+	echo "    Other device down and up"
 	fib_down_multipath_test_do "dummy1" "dummy0"
 
-	ip netns exec testns ip link set dev dummy0 down
-	check_err $?
+	set -e
+	ip -netns testns link set dev dummy0 down
+	set +e
 
-	ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null
-	check_fail $?
+	echo "    Both devices down"
+	ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null
+	log_test $? 2 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null
+	log_test $? 2 "IPv6 fibmatch"
 
-	ip netns exec testns ip link del dev dummy1
-	ip netns exec testns ip link del dev dummy0
-
-	ip netns del testns
-
-	if [ $ret -ne 0 ]; then
-		echo "FAIL: multipath route test"
-		return 1
-	fi
-	echo "PASS: multipath route test"
+	ip -netns testns link del dev dummy1
+	cleanup
 }
 
 fib_down_test()
 {
-	echo "Running netdev down tests"
-
 	fib_down_unicast_test
 	fib_down_multipath_test
 }
 
+# Local routes should not be affected when carrier changes.
 fib_carrier_local_test()
 {
-	ret=0
+	echo
+	echo "Local carrier tests - single path"
 
-	# Local routes should not be affected when carrier changes.
-	netns_create "testns"
+	setup
 
-	ip netns exec testns ip link add dummy0 type dummy
-	ip netns exec testns ip link set dev dummy0 up
+	set -e
+	ip -netns testns link set dev dummy0 carrier on
+	set +e
 
-	ip netns exec testns ip link set dev dummy0 carrier on
+	echo "    Start point"
+	ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip address add 198.51.100.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0
-
-	ip netns exec testns ip route get fibmatch 198.51.100.1 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 &> /dev/null
-	check_err $?
-
-	ip netns exec testns ip route get fibmatch 198.51.100.1 | \
+	ip -netns testns route get fibmatch 198.51.100.1 | \
 		grep -q "linkdown"
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 | \
+	log_test $? 1 "IPv4 - no linkdown flag"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \
 		grep -q "linkdown"
-	check_fail $?
+	log_test $? 1 "IPv6 - no linkdown flag"
 
-	ip netns exec testns ip link set dev dummy0 carrier off
+	set -e
+	ip -netns testns link set dev dummy0 carrier off
+	sleep 1
+	set +e
 
-	ip netns exec testns ip route get fibmatch 198.51.100.1 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 &> /dev/null
-	check_err $?
+	echo "    Carrier off on nexthop"
+	ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.1 | \
+	ip -netns testns route get fibmatch 198.51.100.1 | \
 		grep -q "linkdown"
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 | \
+	log_test $? 1 "IPv4 - linkdown flag set"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \
 		grep -q "linkdown"
-	check_fail $?
+	log_test $? 1 "IPv6 - linkdown flag set"
 
-	ip netns exec testns ip address add 192.0.2.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy0
+	set -e
+	ip -netns testns address add 192.0.2.1/24 dev dummy0
+	ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0
+	set +e
 
-	ip netns exec testns ip route get fibmatch 192.0.2.1 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:2::1 &> /dev/null
-	check_err $?
+	echo "    Route to local address with carrier down"
+	ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 192.0.2.1 | \
+	ip -netns testns route get fibmatch 192.0.2.1 | \
 		grep -q "linkdown"
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:2::1 | \
+	log_test $? 1 "IPv4 linkdown flag set"
+	ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \
 		grep -q "linkdown"
-	check_fail $?
+	log_test $? 1 "IPv6 linkdown flag set"
 
-	ip netns exec testns ip link del dev dummy0
-
-	ip netns del testns
-
-	if [ $ret -ne 0 ]; then
-		echo "FAIL: local route carrier test"
-		return 1
-	fi
-	echo "PASS: local route carrier test"
+	cleanup
 }
 
 fib_carrier_unicast_test()
 {
 	ret=0
 
-	netns_create "testns"
-
-	ip netns exec testns ip link add dummy0 type dummy
-	ip netns exec testns ip link set dev dummy0 up
+	echo
+	echo "Single path route carrier test"
 
-	ip netns exec testns ip link set dev dummy0 carrier on
+	setup
 
-	ip netns exec testns ip address add 198.51.100.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0
+	set -e
+	ip -netns testns link set dev dummy0 carrier on
+	set +e
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null
-	check_err $?
+	echo "    Start point"
+	ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 | \
+	ip -netns testns route get fibmatch 198.51.100.2 | \
 		grep -q "linkdown"
-	check_fail $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 | \
+	log_test $? 1 "IPv4 no linkdown flag"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \
 		grep -q "linkdown"
-	check_fail $?
+	log_test $? 1 "IPv6 no linkdown flag"
 
-	ip netns exec testns ip link set dev dummy0 carrier off
+	set -e
+	ip -netns testns link set dev dummy0 carrier off
+	set +e
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null
-	check_err $?
+	echo "    Carrier down"
+	ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 198.51.100.2 | \
+	ip -netns testns route get fibmatch 198.51.100.2 | \
 		grep -q "linkdown"
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 | \
+	log_test $? 0 "IPv4 linkdown flag set"
+	ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \
 		grep -q "linkdown"
-	check_err $?
+	log_test $? 0 "IPv6 linkdown flag set"
 
-	ip netns exec testns ip address add 192.0.2.1/24 dev dummy0
-	ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy0
+	set -e
+	ip -netns testns address add 192.0.2.1/24 dev dummy0
+	ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0
+	set +e
 
-	ip netns exec testns ip route get fibmatch 192.0.2.2 &> /dev/null
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:2::2 &> /dev/null
-	check_err $?
+	echo "    Second address added with carrier down"
+	ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null
+	log_test $? 0 "IPv4 fibmatch"
+	ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null
+	log_test $? 0 "IPv6 fibmatch"
 
-	ip netns exec testns ip route get fibmatch 192.0.2.2 | \
+	ip -netns testns route get fibmatch 192.0.2.2 | \
 		grep -q "linkdown"
-	check_err $?
-	ip netns exec testns ip -6 route get fibmatch 2001:db8:2::2 | \
+	log_test $? 0 "IPv4 linkdown flag set"
+	ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \
 		grep -q "linkdown"
-	check_err $?
+	log_test $? 0 "IPv6 linkdown flag set"
 
-	ip netns exec testns ip link del dev dummy0
-
-	ip netns del testns
-
-	if [ $ret -ne 0 ]; then
-		echo "FAIL: unicast route carrier test"
-		return 1
-	fi
-	echo "PASS: unicast route carrier test"
+	cleanup
 }
 
 fib_carrier_test()
 {
-	echo "Running netdev carrier change tests"
-
 	fib_carrier_local_test
 	fib_carrier_unicast_test
 }
@@ -424,6 +412,9 @@ if [ $? -ne 0 ]; then
 	exit 0
 fi
 
+# start clean
+cleanup &> /dev/null
+
 fib_test
 
 exit $ret
diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c
index e11fe84de0fd..5cc2a53bb71c 100644
--- a/tools/testing/selftests/net/msg_zerocopy.c
+++ b/tools/testing/selftests/net/msg_zerocopy.c
@@ -14,6 +14,9 @@
  * - SOCK_DGRAM
  * - SOCK_RAW
  *
+ * PF_RDS
+ * - SOCK_SEQPACKET
+ *
  * Start this program on two connected hosts, one in send mode and
  * the other with option '-r' to put it in receiver mode.
  *
@@ -53,6 +56,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <linux/rds.h>
 
 #ifndef SO_EE_ORIGIN_ZEROCOPY
 #define SO_EE_ORIGIN_ZEROCOPY		5
@@ -164,17 +168,39 @@ static int do_accept(int fd)
 	return fd;
 }
 
-static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy)
+static void add_zcopy_cookie(struct msghdr *msg, uint32_t cookie)
+{
+	struct cmsghdr *cm;
+
+	if (!msg->msg_control)
+		error(1, errno, "NULL cookie");
+	cm = (void *)msg->msg_control;
+	cm->cmsg_len = CMSG_LEN(sizeof(cookie));
+	cm->cmsg_level = SOL_RDS;
+	cm->cmsg_type = RDS_CMSG_ZCOPY_COOKIE;
+	memcpy(CMSG_DATA(cm), &cookie, sizeof(cookie));
+}
+
+static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy, int domain)
 {
 	int ret, len, i, flags;
+	static uint32_t cookie;
+	char ckbuf[CMSG_SPACE(sizeof(cookie))];
 
 	len = 0;
 	for (i = 0; i < msg->msg_iovlen; i++)
 		len += msg->msg_iov[i].iov_len;
 
 	flags = MSG_DONTWAIT;
-	if (do_zerocopy)
+	if (do_zerocopy) {
 		flags |= MSG_ZEROCOPY;
+		if (domain == PF_RDS) {
+			memset(&msg->msg_control, 0, sizeof(msg->msg_control));
+			msg->msg_controllen = CMSG_SPACE(sizeof(cookie));
+			msg->msg_control = (struct cmsghdr *)ckbuf;
+			add_zcopy_cookie(msg, ++cookie);
+		}
+	}
 
 	ret = sendmsg(fd, msg, flags);
 	if (ret == -1 && errno == EAGAIN)
@@ -190,6 +216,10 @@ static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy)
 		if (do_zerocopy && ret)
 			expected_completions++;
 	}
+	if (do_zerocopy && domain == PF_RDS) {
+		msg->msg_control = NULL;
+		msg->msg_controllen = 0;
+	}
 
 	return true;
 }
@@ -216,7 +246,9 @@ static void do_sendmsg_corked(int fd, struct msghdr *msg)
 		msg->msg_iov[0].iov_len = payload_len + extra_len;
 		extra_len = 0;
 
-		do_sendmsg(fd, msg, do_zerocopy);
+		do_sendmsg(fd, msg, do_zerocopy,
+			   (cfg_dst_addr.ss_family == AF_INET ?
+			    PF_INET : PF_INET6));
 	}
 
 	do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0);
@@ -300,13 +332,38 @@ static int do_setup_tx(int domain, int type, int protocol)
 	if (cfg_zerocopy)
 		do_setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, 1);
 
-	if (domain != PF_PACKET)
+	if (domain != PF_PACKET && domain != PF_RDS)
 		if (connect(fd, (void *) &cfg_dst_addr, cfg_alen))
 			error(1, errno, "connect");
 
+	if (domain == PF_RDS) {
+		if (bind(fd, (void *) &cfg_src_addr, cfg_alen))
+			error(1, errno, "bind");
+	}
+
 	return fd;
 }
 
+static int do_process_zerocopy_cookies(struct sock_extended_err *serr,
+				       uint32_t *ckbuf, size_t nbytes)
+{
+	int ncookies, i;
+
+	if (serr->ee_errno != 0)
+		error(1, 0, "serr: wrong error code: %u", serr->ee_errno);
+	ncookies = serr->ee_data;
+	if (ncookies > SO_EE_ORIGIN_MAX_ZCOOKIES)
+		error(1, 0, "Returned %d cookies, max expected %d\n",
+		      ncookies, SO_EE_ORIGIN_MAX_ZCOOKIES);
+	if (nbytes != ncookies * sizeof(uint32_t))
+		error(1, 0, "Expected %d cookies, got %ld\n",
+		      ncookies, nbytes/sizeof(uint32_t));
+	for (i = 0; i < ncookies; i++)
+		if (cfg_verbose >= 2)
+			fprintf(stderr, "%d\n", ckbuf[i]);
+	return ncookies;
+}
+
 static bool do_recv_completion(int fd)
 {
 	struct sock_extended_err *serr;
@@ -315,10 +372,17 @@ static bool do_recv_completion(int fd)
 	uint32_t hi, lo, range;
 	int ret, zerocopy;
 	char control[100];
+	uint32_t ckbuf[SO_EE_ORIGIN_MAX_ZCOOKIES];
+	struct iovec iov;
 
 	msg.msg_control = control;
 	msg.msg_controllen = sizeof(control);
 
+	iov.iov_base = ckbuf;
+	iov.iov_len = (SO_EE_ORIGIN_MAX_ZCOOKIES * sizeof(ckbuf[0]));
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
 	ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
 	if (ret == -1 && errno == EAGAIN)
 		return false;
@@ -337,6 +401,11 @@ static bool do_recv_completion(int fd)
 		      cm->cmsg_level, cm->cmsg_type);
 
 	serr = (void *) CMSG_DATA(cm);
+
+	if (serr->ee_origin == SO_EE_ORIGIN_ZCOOKIE) {
+		completions += do_process_zerocopy_cookies(serr, ckbuf, ret);
+		return true;
+	}
 	if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY)
 		error(1, 0, "serr: wrong origin: %u", serr->ee_origin);
 	if (serr->ee_errno != 0)
@@ -444,6 +513,13 @@ static void do_tx(int domain, int type, int protocol)
 		msg.msg_iovlen++;
 	}
 
+	if (domain == PF_RDS) {
+		msg.msg_name = &cfg_dst_addr;
+		msg.msg_namelen =  (cfg_dst_addr.ss_family == AF_INET ?
+				    sizeof(struct sockaddr_in) :
+				    sizeof(struct sockaddr_in6));
+	}
+
 	iov[2].iov_base = payload;
 	iov[2].iov_len = cfg_payload_len;
 	msg.msg_iovlen++;
@@ -454,7 +530,7 @@ static void do_tx(int domain, int type, int protocol)
 		if (cfg_cork)
 			do_sendmsg_corked(fd, &msg);
 		else
-			do_sendmsg(fd, &msg, cfg_zerocopy);
+			do_sendmsg(fd, &msg, cfg_zerocopy, domain);
 
 		while (!do_poll(fd, POLLOUT)) {
 			if (cfg_zerocopy)
@@ -555,6 +631,40 @@ static void do_flush_datagram(int fd, int type)
 	bytes += cfg_payload_len;
 }
 
+
+static void do_recvmsg(int fd)
+{
+	int ret, off = 0;
+	char *buf;
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_storage din;
+
+	buf = calloc(cfg_payload_len, sizeof(char));
+	iov.iov_base = buf;
+	iov.iov_len = cfg_payload_len;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_name = &din;
+	msg.msg_namelen = sizeof(din);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = recvmsg(fd, &msg, MSG_TRUNC);
+
+	if (ret == -1)
+		error(1, errno, "recv");
+	if (ret != cfg_payload_len)
+		error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len);
+
+	if (memcmp(buf + off, payload, ret))
+		error(1, 0, "recv: data mismatch");
+
+	free(buf);
+	packets++;
+	bytes += cfg_payload_len;
+}
+
 static void do_rx(int domain, int type, int protocol)
 {
 	uint64_t tstop;
@@ -566,6 +676,8 @@ static void do_rx(int domain, int type, int protocol)
 	do {
 		if (type == SOCK_STREAM)
 			do_flush_tcp(fd);
+		else if (domain == PF_RDS)
+			do_recvmsg(fd);
 		else
 			do_flush_datagram(fd, type);
 
@@ -610,6 +722,7 @@ static void parse_opts(int argc, char **argv)
 				    40 /* max tcp options */;
 	int c;
 	char *daddr = NULL, *saddr = NULL;
+	char *cfg_test;
 
 	cfg_payload_len = max_payload_len;
 
@@ -667,6 +780,14 @@ static void parse_opts(int argc, char **argv)
 			break;
 		}
 	}
+
+	cfg_test = argv[argc - 1];
+	if (strcmp(cfg_test, "rds") == 0) {
+		if (!daddr)
+			error(1, 0, "-D <server addr> required for PF_RDS\n");
+		if (!cfg_rx && !saddr)
+			error(1, 0, "-S <client addr> required for PF_RDS\n");
+	}
 	setup_sockaddr(cfg_family, daddr, &cfg_dst_addr);
 	setup_sockaddr(cfg_family, saddr, &cfg_src_addr);
 
@@ -699,6 +820,8 @@ int main(int argc, char **argv)
 		do_test(cfg_family, SOCK_STREAM, 0);
 	else if (!strcmp(cfg_test, "udp"))
 		do_test(cfg_family, SOCK_DGRAM, 0);
+	else if (!strcmp(cfg_test, "rds"))
+		do_test(PF_RDS, SOCK_SEQPACKET, 0);
 	else
 		error(1, 0, "unknown cfg_test %s", cfg_test);
 
diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c
index 989f917068d1..d4346b16b2c1 100644
--- a/tools/testing/selftests/net/psock_fanout.c
+++ b/tools/testing/selftests/net/psock_fanout.c
@@ -128,6 +128,8 @@ static void sock_fanout_getopts(int fd, uint16_t *typeflags, uint16_t *group_id)
 
 static void sock_fanout_set_ebpf(int fd)
 {
+	static char log_buf[65536];
+
 	const int len_off = __builtin_offsetof(struct __sk_buff, len);
 	struct bpf_insn prog[] = {
 		{ BPF_ALU64 | BPF_MOV | BPF_X,   6, 1, 0, 0 },
@@ -140,7 +142,6 @@ static void sock_fanout_set_ebpf(int fd)
 		{ BPF_ALU   | BPF_MOV | BPF_K,   0, 0, 0, 0 },
 		{ BPF_JMP   | BPF_EXIT,          0, 0, 0, 0 }
 	};
-	char log_buf[512];
 	union bpf_attr attr;
 	int pfd;
 
diff --git a/tools/testing/selftests/pstore/config b/tools/testing/selftests/pstore/config
index 6a8e5a9bfc10..d148f9f89fb6 100644
--- a/tools/testing/selftests/pstore/config
+++ b/tools/testing/selftests/pstore/config
@@ -2,3 +2,4 @@ CONFIG_MISC_FILESYSTEMS=y
 CONFIG_PSTORE=y
 CONFIG_PSTORE_PMSG=y
 CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=m
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh
index 07a13779eece..65f6655026f0 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -136,6 +136,9 @@ identify_boot_image () {
 		qemu-system-x86_64|qemu-system-i386)
 			echo arch/x86/boot/bzImage
 			;;
+		qemu-system-aarch64)
+			echo arch/arm64/boot/Image
+			;;
 		*)
 			echo vmlinux
 			;;
@@ -158,6 +161,9 @@ identify_qemu () {
 	elif echo $u | grep -q "Intel 80386"
 	then
 		echo qemu-system-i386
+	elif echo $u | grep -q aarch64
+	then
+		echo qemu-system-aarch64
 	elif uname -a | grep -q ppc64
 	then
 		echo qemu-system-ppc64
@@ -176,16 +182,20 @@ identify_qemu () {
 # Output arguments for the qemu "-append" string based on CPU type
 # and the TORTURE_QEMU_INTERACTIVE environment variable.
 identify_qemu_append () {
+	local console=ttyS0
 	case "$1" in
 	qemu-system-x86_64|qemu-system-i386)
 		echo noapic selinux=0 initcall_debug debug
 		;;
+	qemu-system-aarch64)
+		console=ttyAMA0
+		;;
 	esac
 	if test -n "$TORTURE_QEMU_INTERACTIVE"
 	then
 		echo root=/dev/sda
 	else
-		echo console=ttyS0
+		echo console=$console
 	fi
 }
 
@@ -197,6 +207,9 @@ identify_qemu_args () {
 	case "$1" in
 	qemu-system-x86_64|qemu-system-i386)
 		;;
+	qemu-system-aarch64)
+		echo -machine virt,gic-version=host -cpu host
+		;;
 	qemu-system-ppc64)
 		echo -enable-kvm -M pseries -nodefaults
 		echo -device spapr-vscsi
@@ -254,7 +267,7 @@ specify_qemu_cpus () {
 		echo $2
 	else
 		case "$1" in
-		qemu-system-x86_64|qemu-system-i386)
+		qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64)
 			echo $2 -smp $3
 			;;
 		qemu-system-ppc64)
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh
index 963f71289d22..8948f7926b21 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh
@@ -39,30 +39,31 @@ sed -e 's/us : / : /' |
 tr -d '\015' |
 awk '
 $8 == "start" {
-	if (starttask != "")
+	if (startseq != "")
 		nlost++;
 	starttask = $1;
 	starttime = $3;
 	startseq = $7;
+	seqtask[startseq] = starttask;
 }
 
 $8 == "end" {
-	if (starttask == $1 && startseq == $7) {
+	if (startseq == $7) {
 		curgpdur = $3 - starttime;
 		gptimes[++n] = curgpdur;
 		gptaskcnt[starttask]++;
 		sum += curgpdur;
 		if (curgpdur > 1000)
 			print "Long GP " starttime "us to " $3 "us (" curgpdur "us)";
-		starttask = "";
+		startseq = "";
 	} else {
 		# Lost a message or some such, reset.
-		starttask = "";
+		startseq = "";
 		nlost++;
 	}
 }
 
-$8 == "done" {
+$8 == "done" && seqtask[$7] != $1 {
 	piggybackcnt[$1]++;
 }
 
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 1b78a12740e5..5f8fbb0d7c17 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -177,8 +177,8 @@ then
 	exit 0
 fi
 echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
-echo $QEMU $qemu_args -m 512 -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
-( $QEMU $qemu_args -m 512 -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat  $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) &
+echo $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
+( $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat  $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) &
 commandcompleted=0
 sleep 10 # Give qemu's pid a chance to reach the file
 if test -s "$resdir/qemu_pid"
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 7d1f607f0f76..56610dbbdf73 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -1,10 +1,8 @@
 #!/bin/bash
 #
-# Run a series of 14 tests under KVM.  These are not particularly
-# well-selected or well-tuned, but are the current set.
-#
-# Edit the definitions below to set the locations of the various directories,
-# as well as the test duration.
+# Run a series of tests under KVM.  By default, this series is specified
+# by the relevant CFLIST file, but can be overridden by the --configs
+# command-line argument.
 #
 # Usage: kvm.sh [ options ]
 #
@@ -44,6 +42,7 @@ TORTURE_BOOT_IMAGE=""
 TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
 TORTURE_KCONFIG_ARG=""
 TORTURE_KMAKE_ARG=""
+TORTURE_QEMU_MEM=512
 TORTURE_SHUTDOWN_GRACE=180
 TORTURE_SUITE=rcu
 resdir=""
@@ -70,6 +69,7 @@ usage () {
 	echo "       --kconfig Kconfig-options"
 	echo "       --kmake-arg kernel-make-arguments"
 	echo "       --mac nn:nn:nn:nn:nn:nn"
+	echo "       --memory megabytes | nnnG"
 	echo "       --no-initrd"
 	echo "       --qemu-args qemu-arguments"
 	echo "       --qemu-cmd qemu-system-..."
@@ -147,6 +147,11 @@ do
 		TORTURE_QEMU_MAC=$2
 		shift
 		;;
+	--memory)
+		checkarg --memory "(memory size)" $# "$2" '^[0-9]\+[MG]\?$' error
+		TORTURE_QEMU_MEM=$2
+		shift
+		;;
 	--no-initrd)
 		TORTURE_INITRD=""; export TORTURE_INITRD
 		;;
@@ -174,6 +179,12 @@ do
 		checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--'
 		TORTURE_SUITE=$2
 		shift
+		if test "$TORTURE_SUITE" = rcuperf
+		then
+			# If you really want jitter for rcuperf, specify
+			# it after specifying rcuperf.  (But why?)
+			jitter=0
+		fi
 		;;
 	*)
 		echo Unknown argument $1
@@ -288,6 +299,7 @@ TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
 TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
 TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
 TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
+TORTURE_QEMU_MEM="$TORTURE_QEMU_MEM"; export TORTURE_QEMU_MEM
 TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE
 TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
 if ! test -e $resdir
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
index c70c51d5ded1..28568b72a31b 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
@@ -9,5 +9,4 @@ CONFIG_PREEMPT=y
 CONFIG_HZ_PERIODIC=n
 CONFIG_NO_HZ_IDLE=n
 CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=y
 #CHECK#CONFIG_RCU_EXPERT=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
index cd2a188eeb6d..838297c58318 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
@@ -1 +1 @@
-rcutorture.torture_type=tasks
+rcutorture.torture_type=tasks nohz_full=1
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 27d22695d64c..24c9f6012e35 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -7,7 +7,6 @@ CONFIG_PREEMPT=n
 CONFIG_HZ_PERIODIC=n
 CONFIG_NO_HZ_IDLE=n
 CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_RCU_TRACE=y
 CONFIG_HOTPLUG_CPU=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
index e34c33430447..e6071bb96c7d 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
@@ -1 +1 @@
-rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4
+rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4 nohz_full=1-7
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index 0f4759f4232e..d7afb271a586 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -7,7 +7,6 @@ CONFIG_PREEMPT=n
 CONFIG_HZ_PERIODIC=n
 CONFIG_NO_HZ_IDLE=n
 CONFIG_NO_HZ_FULL=y
-CONFIG_NO_HZ_FULL_ALL=n
 CONFIG_RCU_FAST_NO_HZ=n
 CONFIG_RCU_TRACE=y
 CONFIG_HOTPLUG_CPU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh
index b9603115d7c7..d36b8fd6f0fc 100644
--- a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh
@@ -20,32 +20,10 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
 
-# rcuperf_param_nreaders bootparam-string
-#
-# Adds nreaders rcuperf module parameter if not already specified.
-rcuperf_param_nreaders () {
-	if ! echo "$1" | grep -q "rcuperf.nreaders"
-	then
-		echo rcuperf.nreaders=-1
-	fi
-}
-
-# rcuperf_param_nwriters bootparam-string
-#
-# Adds nwriters rcuperf module parameter if not already specified.
-rcuperf_param_nwriters () {
-	if ! echo "$1" | grep -q "rcuperf.nwriters"
-	then
-		echo rcuperf.nwriters=-1
-	fi
-}
-
 # per_version_boot_params bootparam-string config-file seconds
 #
 # Adds per-version torture-module parameters to kernels supporting them.
 per_version_boot_params () {
-	echo $1 `rcuperf_param_nreaders "$1"` \
-		`rcuperf_param_nwriters "$1"` \
-		rcuperf.shutdown=1 \
+	echo $1 rcuperf.shutdown=1 \
 		rcuperf.verbose=1
 }
diff --git a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt
index 66efb59a1bd1..449cf579d6f9 100644
--- a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt
+++ b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt
@@ -1,4 +1,4 @@
-This document describes one way to created the rcu-test-image file
+This document describes one way to create the rcu-test-image file
 that contains the filesystem used by the guest-OS kernel.  There are
 probably much better ways of doing this, and this filesystem could no
 doubt be smaller.  It is probably also possible to simply download
diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile
index b3c8ba3cb668..d0121a8a3523 100644
--- a/tools/testing/selftests/sync/Makefile
+++ b/tools/testing/selftests/sync/Makefile
@@ -30,7 +30,7 @@ $(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS)
 	$(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS)
 
 $(OBJS): $(OUTPUT)/%.o: %.c
-	$(CC) -c $^ -o $@
+	$(CC) -c $^ -o $@ $(CFLAGS)
 
 $(TESTS): $(OUTPUT)/%.o: %.c
 	$(CC) -c $^ -o $@
diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README
index 970ff294fec8..3a0336782d2d 100644
--- a/tools/testing/selftests/tc-testing/README
+++ b/tools/testing/selftests/tc-testing/README
@@ -14,11 +14,11 @@ REQUIREMENTS
 
 *  The kernel must have network namespace support
 
-*   The kernel must have veth support available, as a veth pair is created
+*  The kernel must have veth support available, as a veth pair is created
    prior to running the tests.
 
-*  All tc-related features must be built in or available as modules.
-   To check what is required in current setup run:
+*  All tc-related features being tested must be built in or available as
+   modules.  To check what is required in current setup run:
    ./tdc.py -c
 
    Note:
@@ -44,10 +44,13 @@ using the -p option when running tdc:
 RUNNING TDC
 -----------
 
-To use tdc, root privileges are required. tdc will not run otherwise.
+To use tdc, root privileges are required.  This is because the
+commands being tested must be run as root.  The code that enforces
+execution by root uid has been moved into a plugin (see PLUGIN
+ARCHITECTURE, below).
 
-All tests are executed inside a network namespace to prevent conflicts
-within the host.
+If nsPlugin is linked, all tests are executed inside a network
+namespace to prevent conflicts within the host.
 
 Running tdc without any arguments will run all tests. Refer to the section
 on command line arguments for more information, or run:
@@ -59,6 +62,33 @@ output captured from the failing test will be printed immediately following
 the failed test in the TAP output.
 
 
+OVERVIEW OF TDC EXECUTION
+-------------------------
+
+One run of tests is considered a "test suite" (this will be refined in the
+future).  A test suite has one or more test cases in it.
+
+A test case has four stages:
+
+  - setup
+  - execute
+  - verify
+  - teardown
+
+The setup and teardown stages can run zero or more commands.  The setup
+stage does some setup if the test needs it.  The teardown stage undoes
+the setup and returns the system to a "neutral" state so any other test
+can be run next.  These two stages require any commands run to return
+success, but do not otherwise verify the results.
+
+The execute and verify stages each run one command.  The execute stage
+tests the return code against one or more acceptable values.  The
+verify stage checks the return code for success, and also compares
+the stdout with a regular expression.
+
+Each of the commands in any stage will run in a shell instance.
+
+
 USER-DEFINED CONSTANTS
 ----------------------
 
@@ -70,23 +100,132 @@ executed as part of the test. More will be added as test cases require.
 Example:
 	$TC qdisc add dev $DEV1 ingress
 
+The NAMES values are used to substitute into the commands in the test cases.
+
 
 COMMAND LINE ARGUMENTS
 ----------------------
 
 Run tdc.py -h to see the full list of available arguments.
 
--p PATH           Specify the tc executable located at PATH to be used on this
-                  test run
--c                Show the available test case categories in this test file
--c CATEGORY       Run only tests that belong to CATEGORY
--f FILE           Read test cases from the JSON file named FILE
--l [CATEGORY]     List all test cases in the JSON file. If CATEGORY is
-                  specified, list test cases matching that category.
--s ID             Show the test case matching ID
--e ID             Execute the test case identified by ID
--i                Generate unique ID numbers for test cases with no existing
-                  ID number
+usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]]
+              [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v]
+              [-d DEVICE] [-n NS] [-V]
+
+Linux TC unit tests
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -p PATH, --path PATH  The full path to the tc executable to use
+  -v, --verbose         Show the commands that are being run
+  -d DEVICE, --device DEVICE
+                        Execute the test case in flower category
+
+selection:
+  select which test cases: files plus directories; filtered by categories
+  plus testids
+
+  -D DIR [DIR ...], --directory DIR [DIR ...]
+                        Collect tests from the specified directory(ies)
+                        (default [tc-tests])
+  -f FILE [FILE ...], --file FILE [FILE ...]
+                        Run tests from the specified file(s)
+  -c [CATG [CATG ...]], --category [CATG [CATG ...]]
+                        Run tests only from the specified category/ies, or if
+                        no category/ies is/are specified, list known
+                        categories.
+  -e ID [ID ...], --execute ID [ID ...]
+                        Execute the specified test cases with specified IDs
+
+action:
+  select action to perform on selected test cases
+
+  -l, --list            List all test cases, or those only within the
+                        specified category
+  -s, --show            Display the selected test cases
+  -i, --id              Generate ID numbers for new test cases
+
+netns:
+  options for nsPlugin(run commands in net namespace)
+
+  -n NS, --namespace NS
+                        Run commands in namespace NS
+
+valgrind:
+  options for valgrindPlugin (run command under test under Valgrind)
+
+  -V, --valgrind        Run commands under valgrind
+
+
+PLUGIN ARCHITECTURE
+-------------------
+
+There is now a plugin architecture, and some of the functionality that
+was in the tdc.py script has been moved into the plugins.
+
+The plugins are in the directory plugin-lib.  The are executed from
+directory plugins.  Put symbolic links from plugins to plugin-lib,
+and name them according to the order you want them to run.
+
+Example:
+
+bjb@bee:~/work/tc-testing$ ls -l plugins
+total 4
+lrwxrwxrwx  1 bjb  bjb    27 Oct  4 16:12 10-rootPlugin.py -> ../plugin-lib/rootPlugin.py
+lrwxrwxrwx  1 bjb  bjb    25 Oct 12 17:55 20-nsPlugin.py -> ../plugin-lib/nsPlugin.py
+-rwxr-xr-x  1 bjb  bjb     0 Sep 29 15:56 __init__.py
+
+The plugins are a subclass of TdcPlugin, defined in TdcPlugin.py and
+must be called "SubPlugin" so tdc can find them.  They are
+distinguished from each other in the python program by their module
+name.
+
+This base class supplies "hooks" to run extra functions.  These hooks are as follows:
+
+pre- and post-suite
+pre- and post-case
+pre- and post-execute stage
+adjust-command (runs in all stages and receives the stage name)
+
+The pre-suite hook receives the number of tests and an array of test ids.
+This allows you to dump out the list of skipped tests in the event of a
+failure during setup or teardown stage.
+
+The pre-case hook receives the ordinal number and test id of the current test.
+
+The adjust-command hook receives the stage id (see list below) and the
+full command to be executed.  This allows for last-minute adjustment
+of the command.
+
+The stages are identified by the following strings:
+
+  - pre  (pre-suite)
+  - setup
+  - command
+  - verify
+  - teardown
+  - post (post-suite)
+
+
+To write a plugin, you need to inherit from TdcPlugin in
+TdcPlugin.py.  To use the plugin, you have to put the
+implementation file in plugin-lib, and add a symbolic link to it from
+plugins.  It will be detected at run time and invoked at the
+appropriate times.  There are a few examples in the plugin-lib
+directory:
+
+  - rootPlugin.py:
+      implements the enforcement of running as root
+  - nsPlugin.py:
+      sets up a network namespace and runs all commands in that namespace
+  - valgrindPlugin.py
+      runs each command in the execute stage under valgrind,
+      and checks for leaks.
+      This plugin will output an extra test for each test in the test file,
+      one is the existing output as to whether the test passed or failed,
+      and the other is a test whether the command leaked memory or not.
+      (This one is a preliminary version, it may not work quite right yet,
+      but the overall template is there and it should only need tweaks.)
 
 
 ACKNOWLEDGEMENTS
diff --git a/tools/testing/selftests/tc-testing/TODO.txt b/tools/testing/selftests/tc-testing/TODO.txt
index 6a266d811a78..c40698557e2f 100644
--- a/tools/testing/selftests/tc-testing/TODO.txt
+++ b/tools/testing/selftests/tc-testing/TODO.txt
@@ -5,6 +5,27 @@ tc Testing Suite To-Do list:
 
 - Add support for multiple versions of tc to run successively
 
-- Improve error messages when tdc aborts its run
+- Improve error messages when tdc aborts its run.  Partially done - still
+  need to better handle problems in pre- and post-suite.
 
-- Allow tdc to write its results to file
+- Use python logger module for debug/verbose output
+
+- Allow tdc to write its results to file.
+  Maybe use python logger module for this too.
+
+- A better implementation of the "hooks".  Currently, every plugin
+  will attempt to run a function at every hook point.  Could be
+  changed so that plugin __init__ methods will register functions to
+  be run in the various predefined times.  Then if a plugin does not
+  require action at a specific point, no penalty will be paid for
+  trying to run a function that will do nothing.
+
+- Proper exception handling - make an exception class and use it
+
+- a TestCase class, for easier testcase handling, searching, comparison
+
+- a TestSuite class
+  and a way to configure a test suite,
+  to automate running multiple "test suites" with different requirements
+
+- super simple test case example using ls, touch, etc
diff --git a/tools/testing/selftests/tc-testing/TdcPlugin.py b/tools/testing/selftests/tc-testing/TdcPlugin.py
new file mode 100644
index 000000000000..3ee9a6dacb52
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/TdcPlugin.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+
+class TdcPlugin:
+    def __init__(self):
+        super().__init__()
+        print(' -- {}.__init__'.format(self.sub_class))
+
+    def pre_suite(self, testcount, testidlist):
+        '''run commands before test_runner goes into a test loop'''
+        self.testcount = testcount
+        self.testidlist = testidlist
+        if self.args.verbose > 1:
+            print(' -- {}.pre_suite'.format(self.sub_class))
+
+    def post_suite(self, index):
+        '''run commands after test_runner completes the test loop
+        index is the last ordinal number of test that was attempted'''
+        if self.args.verbose > 1:
+            print(' -- {}.post_suite'.format(self.sub_class))
+
+    def pre_case(self, test_ordinal, testid):
+        '''run commands before test_runner does one test'''
+        if self.args.verbose > 1:
+            print(' -- {}.pre_case'.format(self.sub_class))
+        self.args.testid = testid
+        self.args.test_ordinal = test_ordinal
+
+    def post_case(self):
+        '''run commands after test_runner does one test'''
+        if self.args.verbose > 1:
+            print(' -- {}.post_case'.format(self.sub_class))
+
+    def pre_execute(self):
+        '''run command before test-runner does the execute step'''
+        if self.args.verbose > 1:
+            print(' -- {}.pre_execute'.format(self.sub_class))
+
+    def post_execute(self):
+        '''run command after test-runner does the execute step'''
+        if self.args.verbose > 1:
+            print(' -- {}.post_execute'.format(self.sub_class))
+
+    def adjust_command(self, stage, command):
+        '''adjust the command'''
+        if self.args.verbose > 1:
+            print(' -- {}.adjust_command {}'.format(self.sub_class, stage))
+
+        # if stage == 'pre':
+        #     pass
+        # elif stage == 'setup':
+        #     pass
+        # elif stage == 'execute':
+        #     pass
+        # elif stage == 'verify':
+        #     pass
+        # elif stage == 'teardown':
+        #     pass
+        # elif stage == 'post':
+        #     pass
+        # else:
+        #     pass
+
+        return command
+
+    def add_args(self, parser):
+        '''Get the plugin args from the command line'''
+        self.argparser = parser
+        return self.argparser
+
+    def check_args(self, args, remaining):
+        '''Check that the args are set correctly'''
+        self.args = args
+        if self.args.verbose > 1:
+            print(' -- {}.check_args'.format(self.sub_class))
diff --git a/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt b/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt
new file mode 100644
index 000000000000..c18f88d09360
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt
@@ -0,0 +1,104 @@
+tdc - Adding plugins for tdc
+
+Author: Brenda J. Butler - bjb@mojatatu.com
+
+ADDING PLUGINS
+--------------
+
+A new plugin should be written in python as a class that inherits from TdcPlugin.
+There are some examples in plugin-lib.
+
+The plugin can be used to add functionality to the test framework,
+such as:
+
+- adding commands to be run before and/or after the test suite
+- adding commands to be run before and/or after the test cases
+- adding commands to be run before and/or after the execute phase of the test cases
+- ability to alter the command to be run in any phase:
+    pre        (the pre-suite stage)
+    prepare
+    execute
+    verify
+    teardown
+    post       (the post-suite stage)
+- ability to add to the command line args, and use them at run time
+
+
+The functions in the class should follow the following interfaces:
+
+    def __init__(self)
+    def pre_suite(self, testcount, testidlist)     # see "PRE_SUITE" below
+    def post_suite(self, ordinal)                  # see "SKIPPING" below
+    def pre_case(self, test_ordinal, testid)       # see "PRE_CASE" below
+    def post_case(self)
+    def pre_execute(self)
+    def post_execute(self)
+    def adjust_command(self, stage, command)       # see "ADJUST" below
+    def add_args(self, parser)                     # see "ADD_ARGS" below
+    def check_args(self, args, remaining)          # see "CHECK_ARGS" below
+
+
+PRE_SUITE
+
+This method takes a testcount (number of tests to be run) and
+testidlist (array of test ids for tests that will be run).  This is
+useful for various things, including when an exception occurs and the
+rest of the tests must be skipped.  The info is stored in the object,
+and the post_suite method can refer to it when dumping the "skipped"
+TAP output.  The tdc.py script will do that for the test suite as
+defined in the test case, but if the plugin is being used to run extra
+tests on each test (eg, check for memory leaks on associated
+co-processes) then that other tap output can be generated in the
+post-suite method using this info passed in to the pre_suite method.
+
+
+SKIPPING
+
+The post_suite method will receive the ordinal number of the last
+test to be attempted.  It can use this info when outputting
+the TAP output for the extra test cases.
+
+
+PRE_CASE
+
+The pre_case method will receive the ordinal number of the test
+and the test id.  Useful for outputing the extra test results.
+
+
+ADJUST
+
+The adjust_command method receives a string representing
+the execution stage and a string which is the actual command to be
+executed.  The plugin can adjust the command, based on the stage of
+execution.
+
+The stages are represented by the following strings:
+
+    'pre'
+    'setup'
+    'command'
+    'verify'
+    'teardown'
+    'post'
+
+The adjust_command method must return the adjusted command so tdc
+can use it.
+
+
+ADD_ARGS
+
+The add_args method receives the argparser object and can add
+arguments to it.  Care should be taken that the new arguments do not
+conflict with any from tdc.py or from other plugins that will be used
+concurrently.
+
+The add_args method should return the argparser object.
+
+
+CHECK_ARGS
+
+The check_args method is so that the plugin can do validation on
+the args, if needed.  If there is a problem, and Exception should
+be raised, with a string that explains the problem.
+
+eg:  raise Exception('plugin xxx, arg -y is wrong, fix it')
diff --git a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt
index 00438331ba47..17b267dedbd9 100644
--- a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt
+++ b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt
@@ -12,14 +12,18 @@ template.json for the required JSON format for test cases.
 Include the 'id' field, but do not assign a value. Running tdc with the -i
 option will generate a unique ID for that test case.
 
-tdc will recursively search the 'tc' subdirectory for .json files.  Any
-test case files you create in these directories will automatically be included.
-If you wish to store your custom test cases elsewhere, be sure to run tdc
-with the -f argument and the path to your file.
+tdc will recursively search the 'tc-tests' subdirectory (or the
+directories named with the -D option) for .json files.  Any test case
+files you create in these directories will automatically be included.
+If you wish to store your custom test cases elsewhere, be sure to run
+tdc with the -f argument and the path to your file, or the -D argument
+and the path to your directory(ies).
 
-Be aware of required escape characters in the JSON data - particularly when
-defining the match pattern. Refer to the tctests.json file for examples when
-in doubt.
+Be aware of required escape characters in the JSON data - particularly
+when defining the match pattern. Refer to the supplied json test files
+for examples when in doubt.  The match pattern is written in json, and
+will be used by python.  So the match pattern will be a python regular
+expression, but should be written using json syntax.
 
 
 TEST CASE STRUCTURE
@@ -69,7 +73,8 @@ SETUP/TEARDOWN ERRORS
 If an error is detected during the setup/teardown process, execution of the
 tests will immediately stop with an error message and the namespace in which
 the tests are run will be destroyed. This is to prevent inaccurate results
-in the test cases.
+in the test cases.  tdc will output a series of TAP results for the skipped
+tests.
 
 Repeated failures of the setup/teardown may indicate a problem with the test
 case, or possibly even a bug in one of the commands that are not being tested.
@@ -79,3 +84,17 @@ so that it doesn't halt the script for an error that doesn't matter. Turn the
 individual command into a list, with the command being first, followed by all
 acceptable exit codes for the command.
 
+Example:
+
+A pair of setup commands.  The first can have exit code 0, 1 or 255, the
+second must have exit code 0.
+
+        "setup": [
+            [
+                "$TC actions flush action gact",
+                0,
+                1,
+                255
+            ],
+            "$TC actions add action reclassify index 65536"
+        ],
diff --git a/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS b/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS
new file mode 100644
index 000000000000..aa8a2669702b
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS
@@ -0,0 +1,27 @@
+tdc.py will look for plugins in a directory plugins off the cwd.
+Make a set of numbered symbolic links from there to the actual plugins.
+Eg:
+
+tdc.py
+plugin-lib/
+plugins/
+    __init__.py
+    10-rootPlugin.py -> ../plugin-lib/rootPlugin.py
+    20-valgrindPlugin.py -> ../plugin-lib/valgrindPlugin.py
+    30-nsPlugin.py -> ../plugin-lib/nsPlugin.py
+
+
+tdc.py will find them and use them.
+
+
+rootPlugin
+    Check if the uid is root.  If not, bail out.
+
+valgrindPlugin
+    Run the command under test with valgrind, and produce an extra set of TAP results for the memory tests.
+    This plugin will write files to the cwd, called vgnd-xxx.log.  These will contain
+    the valgrind output for test xxx.  Any file matching the glob 'vgnd-*.log' will be
+    deleted at the end of the run.
+
+nsPlugin
+    Run all the commands in a network namespace.
diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py
new file mode 100644
index 000000000000..a194b1af2b30
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py
@@ -0,0 +1,141 @@
+import os
+import signal
+from string import Template
+import subprocess
+import time
+from TdcPlugin import TdcPlugin
+
+from tdc_config import *
+
+class SubPlugin(TdcPlugin):
+    def __init__(self):
+        self.sub_class = 'ns/SubPlugin'
+        super().__init__()
+
+    def pre_suite(self, testcount, testidlist):
+        '''run commands before test_runner goes into a test loop'''
+        super().pre_suite(testcount, testidlist)
+
+        if self.args.namespace:
+            self._ns_create()
+
+    def post_suite(self, index):
+        '''run commands after test_runner goes into a test loop'''
+        super().post_suite(index)
+        if self.args.verbose:
+            print('{}.post_suite'.format(self.sub_class))
+
+        if self.args.namespace:
+            self._ns_destroy()
+
+    def add_args(self, parser):
+        super().add_args(parser)
+        self.argparser_group = self.argparser.add_argument_group(
+            'netns',
+            'options for nsPlugin(run commands in net namespace)')
+        self.argparser_group.add_argument(
+            '-n', '--namespace', action='store_true',
+            help='Run commands in namespace')
+        return self.argparser
+
+    def adjust_command(self, stage, command):
+        super().adjust_command(stage, command)
+        cmdform = 'list'
+        cmdlist = list()
+
+        if not self.args.namespace:
+            return command
+
+        if self.args.verbose:
+            print('{}.adjust_command'.format(self.sub_class))
+
+        if not isinstance(command, list):
+            cmdform = 'str'
+            cmdlist = command.split()
+        else:
+            cmdlist = command
+        if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown':
+            if self.args.verbose:
+                print('adjust_command:  stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist))
+            cmdlist.insert(0, self.args.NAMES['NS'])
+            cmdlist.insert(0, 'exec')
+            cmdlist.insert(0, 'netns')
+            cmdlist.insert(0, 'ip')
+        else:
+            pass
+
+        if cmdform == 'str':
+            command = ' '.join(cmdlist)
+        else:
+            command = cmdlist
+
+        if self.args.verbose:
+            print('adjust_command:  return command [{}]'.format(command))
+        return command
+
+    def _ns_create(self):
+        '''
+        Create the network namespace in which the tests will be run and set up
+        the required network devices for it.
+        '''
+        if self.args.namespace:
+            cmd = 'ip netns add {}'.format(self.args.NAMES['NS'])
+            self._exec_cmd('pre', cmd)
+            cmd = 'ip link add $DEV0 type veth peer name $DEV1'
+            self._exec_cmd('pre', cmd)
+            cmd = 'ip link set $DEV1 netns {}'.format(self.args.NAMES['NS'])
+            self._exec_cmd('pre', cmd)
+            cmd = 'ip link set $DEV0 up'
+            self._exec_cmd('pre', cmd)
+            cmd = 'ip -n {} link set $DEV1 up'.format(self.args.NAMES['NS'])
+            self._exec_cmd('pre', cmd)
+            if self.args.device:
+                cmd = 'ip link set $DEV2 netns {}'.format(self.args.NAMES['NS'])
+                self._exec_cmd('pre', cmd)
+                cmd = 'ip -n {} link set $DEV2 up'.format(self.args.NAMES['NS'])
+                self._exec_cmd('pre', cmd)
+
+    def _ns_destroy(self):
+        '''
+        Destroy the network namespace for testing (and any associated network
+        devices as well)
+        '''
+        if self.args.namespace:
+            cmd = 'ip netns delete {}'.format(self.args.NAMES['NS'])
+            self._exec_cmd('post', cmd)
+
+    def _exec_cmd(self, stage, command):
+        '''
+        Perform any required modifications on an executable command, then run
+        it in a subprocess and return the results.
+        '''
+        if '$' in command:
+            command = self._replace_keywords(command)
+
+        self.adjust_command(stage, command)
+        if self.args.verbose:
+            print('_exec_cmd:  command "{}"'.format(command))
+        proc = subprocess.Popen(command,
+            shell=True,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            env=ENVIR)
+        (rawout, serr) = proc.communicate()
+
+        if proc.returncode != 0 and len(serr) > 0:
+            foutput = serr.decode("utf-8")
+        else:
+            foutput = rawout.decode("utf-8")
+
+        proc.stdout.close()
+        proc.stderr.close()
+        return proc, foutput
+
+    def _replace_keywords(self, cmd):
+        """
+        For a given executable command, substitute any known
+        variables contained within NAMES with the correct values
+        """
+        tcmd = Template(cmd)
+        subcmd = tcmd.safe_substitute(self.args.NAMES)
+        return subcmd
diff --git a/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py
new file mode 100644
index 000000000000..e36775bd4d12
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py
@@ -0,0 +1,19 @@
+import os
+import sys
+from TdcPlugin import TdcPlugin
+
+from tdc_config import *
+
+
+class SubPlugin(TdcPlugin):
+    def __init__(self):
+        self.sub_class = 'root/SubPlugin'
+        super().__init__()
+
+    def pre_suite(self, testcount, testidlist):
+        # run commands before test_runner goes into a test loop
+        super().pre_suite(testcount, testidlist)
+
+        if os.geteuid():
+            print('This script must be run with root privileges', file=sys.stderr)
+            exit(1)
diff --git a/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py
new file mode 100644
index 000000000000..477a7bd7d7fb
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py
@@ -0,0 +1,142 @@
+'''
+run the command under test, under valgrind and collect memory leak info
+as a separate test.
+'''
+
+
+import os
+import re
+import signal
+from string import Template
+import subprocess
+import time
+from TdcPlugin import TdcPlugin
+
+from tdc_config import *
+
+def vp_extract_num_from_string(num_as_string_maybe_with_commas):
+    return int(num_as_string_maybe_with_commas.replace(',',''))
+
+class SubPlugin(TdcPlugin):
+    def __init__(self):
+        self.sub_class = 'valgrind/SubPlugin'
+        self.tap = ''
+        super().__init__()
+
+    def pre_suite(self, testcount, testidlist):
+        '''run commands before test_runner goes into a test loop'''
+        super().pre_suite(testcount, testidlist)
+        if self.args.verbose > 1:
+            print('{}.pre_suite'.format(self.sub_class))
+        if self.args.valgrind:
+            self._add_to_tap('1..{}\n'.format(self.testcount))
+
+    def post_suite(self, index):
+        '''run commands after test_runner goes into a test loop'''
+        super().post_suite(index)
+        self._add_to_tap('\n|---\n')
+        if self.args.verbose > 1:
+            print('{}.post_suite'.format(self.sub_class))
+        print('{}'.format(self.tap))
+        if self.args.verbose < 4:
+            subprocess.check_output('rm -f vgnd-*.log', shell=True)
+
+    def add_args(self, parser):
+        super().add_args(parser)
+        self.argparser_group = self.argparser.add_argument_group(
+            'valgrind',
+            'options for valgrindPlugin (run command under test under Valgrind)')
+
+        self.argparser_group.add_argument(
+            '-V', '--valgrind', action='store_true',
+            help='Run commands under valgrind')
+
+        return self.argparser
+
+    def adjust_command(self, stage, command):
+        super().adjust_command(stage, command)
+        cmdform = 'list'
+        cmdlist = list()
+
+        if not self.args.valgrind:
+            return command
+
+        if self.args.verbose > 1:
+            print('{}.adjust_command'.format(self.sub_class))
+
+        if not isinstance(command, list):
+            cmdform = 'str'
+            cmdlist = command.split()
+        else:
+            cmdlist = command
+
+        if stage == 'execute':
+            if self.args.verbose > 1:
+                print('adjust_command:  stage is {}; inserting valgrind stuff in command [{}] list [{}]'.
+                      format(stage, command, cmdlist))
+            cmdlist.insert(0, '--track-origins=yes')
+            cmdlist.insert(0, '--show-leak-kinds=definite,indirect')
+            cmdlist.insert(0, '--leak-check=full')
+            cmdlist.insert(0, '--log-file=vgnd-{}.log'.format(self.args.testid))
+            cmdlist.insert(0, '-v')  # ask for summary of non-leak errors
+            cmdlist.insert(0, ENVIR['VALGRIND_BIN'])
+        else:
+            pass
+
+        if cmdform == 'str':
+            command = ' '.join(cmdlist)
+        else:
+            command = cmdlist
+
+        if self.args.verbose > 1:
+            print('adjust_command:  return command [{}]'.format(command))
+        return command
+
+    def post_execute(self):
+        if not self.args.valgrind:
+            return
+
+        self.definitely_lost_re = re.compile(
+            r'definitely lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\sblocks', re.MULTILINE | re.DOTALL)
+        self.indirectly_lost_re = re.compile(
+            r'indirectly lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL)
+        self.possibly_lost_re = re.compile(
+            r'possibly lost:\s+([,0-9]+)bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL)
+        self.non_leak_error_re = re.compile(
+            r'ERROR SUMMARY:\s+([,0-9]+) errors from\s+([,0-9]+)\s+contexts', re.MULTILINE | re.DOTALL)
+
+        def_num = 0
+        ind_num = 0
+        pos_num = 0
+        nle_num = 0
+
+        # what about concurrent test runs?  Maybe force them to be in different directories?
+        with open('vgnd-{}.log'.format(self.args.testid)) as vfd:
+            content = vfd.read()
+            def_mo = self.definitely_lost_re.search(content)
+            ind_mo = self.indirectly_lost_re.search(content)
+            pos_mo = self.possibly_lost_re.search(content)
+            nle_mo = self.non_leak_error_re.search(content)
+
+            if def_mo:
+                def_num = int(def_mo.group(2))
+            if ind_mo:
+                ind_num = int(ind_mo.group(2))
+            if pos_mo:
+                pos_num = int(pos_mo.group(2))
+            if nle_mo:
+                nle_num = int(nle_mo.group(1))
+
+        mem_results = ''
+        if (def_num > 0) or (ind_num > 0) or (pos_num > 0) or (nle_num > 0):
+            mem_results += 'not '
+
+        mem_results += 'ok {} - {}-mem # {}\n'.format(
+            self.args.test_ordinal, self.args.testid, 'memory leak check')
+        self._add_to_tap(mem_results)
+        if mem_results.startswith('not '):
+            print('{}'.format(content))
+            self._add_to_tap(content)
+
+    def _add_to_tap(self, more_tap_output):
+        self.tap += more_tap_output
diff --git a/tools/testing/selftests/tc-testing/plugins/__init__.py b/tools/testing/selftests/tc-testing/plugins/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py
index fc373fdf2bdc..b3754b9aa302 100755
--- a/tools/testing/selftests/tc-testing/tdc.py
+++ b/tools/testing/selftests/tc-testing/tdc.py
@@ -11,16 +11,88 @@ import re
 import os
 import sys
 import argparse
+import importlib
 import json
 import subprocess
+import time
 from collections import OrderedDict
 from string import Template
 
 from tdc_config import *
 from tdc_helper import *
 
-
-USE_NS = True
+import TdcPlugin
+
+class PluginMgr:
+    def __init__(self, argparser):
+        super().__init__()
+        self.plugins = {}
+        self.plugin_instances = []
+        self.args = []
+        self.argparser = argparser
+
+        # TODO, put plugins in order
+        plugindir = os.getenv('TDC_PLUGIN_DIR', './plugins')
+        for dirpath, dirnames, filenames in os.walk(plugindir):
+            for fn in filenames:
+                if (fn.endswith('.py') and
+                    not fn == '__init__.py' and
+                    not fn.startswith('#') and
+                    not fn.startswith('.#')):
+                    mn = fn[0:-3]
+                    foo = importlib.import_module('plugins.' + mn)
+                    self.plugins[mn] = foo
+                    self.plugin_instances.append(foo.SubPlugin())
+
+    def call_pre_suite(self, testcount, testidlist):
+        for pgn_inst in self.plugin_instances:
+            pgn_inst.pre_suite(testcount, testidlist)
+
+    def call_post_suite(self, index):
+        for pgn_inst in reversed(self.plugin_instances):
+            pgn_inst.post_suite(index)
+
+    def call_pre_case(self, test_ordinal, testid):
+        for pgn_inst in self.plugin_instances:
+            try:
+                pgn_inst.pre_case(test_ordinal, testid)
+            except Exception as ee:
+                print('exception {} in call to pre_case for {} plugin'.
+                      format(ee, pgn_inst.__class__))
+                print('test_ordinal is {}'.format(test_ordinal))
+                print('testid is {}'.format(testid))
+                raise
+
+    def call_post_case(self):
+        for pgn_inst in reversed(self.plugin_instances):
+            pgn_inst.post_case()
+
+    def call_pre_execute(self):
+        for pgn_inst in self.plugin_instances:
+            pgn_inst.pre_execute()
+
+    def call_post_execute(self):
+        for pgn_inst in reversed(self.plugin_instances):
+            pgn_inst.post_execute()
+
+    def call_add_args(self, parser):
+        for pgn_inst in self.plugin_instances:
+            parser = pgn_inst.add_args(parser)
+        return parser
+
+    def call_check_args(self, args, remaining):
+        for pgn_inst in self.plugin_instances:
+            pgn_inst.check_args(args, remaining)
+
+    def call_adjust_command(self, stage, command):
+        for pgn_inst in self.plugin_instances:
+            command = pgn_inst.adjust_command(stage, command)
+        return command
+
+    @staticmethod
+    def _make_argparser(args):
+        self.argparser = argparse.ArgumentParser(
+            description='Linux TC unit tests')
 
 
 def replace_keywords(cmd):
@@ -33,21 +105,24 @@ def replace_keywords(cmd):
     return subcmd
 
 
-def exec_cmd(command, nsonly=True):
+def exec_cmd(args, pm, stage, command):
     """
     Perform any required modifications on an executable command, then run
     it in a subprocess and return the results.
     """
-    if (USE_NS and nsonly):
-        command = 'ip netns exec $NS ' + command
-
+    if len(command.strip()) == 0:
+        return None, None
     if '$' in command:
         command = replace_keywords(command)
 
+    command = pm.call_adjust_command(stage, command)
+    if args.verbose > 0:
+        print('command "{}"'.format(command))
     proc = subprocess.Popen(command,
         shell=True,
         stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE)
+        stderr=subprocess.PIPE,
+        env=ENVIR)
     (rawout, serr) = proc.communicate()
 
     if proc.returncode != 0 and len(serr) > 0:
@@ -60,36 +135,85 @@ def exec_cmd(command, nsonly=True):
     return proc, foutput
 
 
-def prepare_env(cmdlist):
+def prepare_env(args, pm, stage, prefix, cmdlist):
     """
-    Execute the setup/teardown commands for a test case. Optionally
-    terminate test execution if the command fails.
+    Execute the setup/teardown commands for a test case.
+    Optionally terminate test execution if the command fails.
     """
+    if args.verbose > 0:
+        print('{}'.format(prefix))
     for cmdinfo in cmdlist:
-        if (type(cmdinfo) == list):
+        if isinstance(cmdinfo, list):
             exit_codes = cmdinfo[1:]
             cmd = cmdinfo[0]
         else:
             exit_codes = [0]
             cmd = cmdinfo
 
-        if (len(cmd) == 0):
+        if not cmd:
             continue
 
-        (proc, foutput) = exec_cmd(cmd)
+        (proc, foutput) = exec_cmd(args, pm, stage, cmd)
+
+        if proc and (proc.returncode not in exit_codes):
+            print('', file=sys.stderr)
+            print("{} *** Could not execute: \"{}\"".format(prefix, cmd),
+                  file=sys.stderr)
+            print("\n{} *** Error message: \"{}\"".format(prefix, foutput),
+                  file=sys.stderr)
+            print("\n{} *** Aborting test run.".format(prefix), file=sys.stderr)
+            print("\n\n{} *** stdout ***".format(proc.stdout), file=sys.stderr)
+            print("\n\n{} *** stderr ***".format(proc.stderr), file=sys.stderr)
+            raise Exception('"{}" did not complete successfully'.format(prefix))
+
+def run_one_test(pm, args, index, tidx):
+    result = True
+    tresult = ""
+    tap = ""
+    if args.verbose > 0:
+        print("\t====================\n=====> ", end="")
+    print("Test " + tidx["id"] + ": " + tidx["name"])
+
+    pm.call_pre_case(index, tidx['id'])
+    prepare_env(args, pm, 'setup', "-----> prepare stage", tidx["setup"])
+
+    if (args.verbose > 0):
+        print('-----> execute stage')
+    pm.call_pre_execute()
+    (p, procout) = exec_cmd(args, pm, 'execute', tidx["cmdUnderTest"])
+    exit_code = p.returncode
+    pm.call_post_execute()
+
+    if (exit_code != int(tidx["expExitCode"])):
+        result = False
+        print("exit:", exit_code, int(tidx["expExitCode"]))
+        print(procout)
+    else:
+        if args.verbose > 0:
+            print('-----> verify stage')
+        match_pattern = re.compile(
+            str(tidx["matchPattern"]), re.DOTALL | re.MULTILINE)
+        (p, procout) = exec_cmd(args, pm, 'verify', tidx["verifyCmd"])
+        match_index = re.findall(match_pattern, procout)
+        if len(match_index) != int(tidx["matchCount"]):
+            result = False
+
+    if not result:
+        tresult += 'not '
+    tresult += 'ok {} - {} # {}\n'.format(str(index), tidx['id'], tidx['name'])
+    tap += tresult
+
+    if result == False:
+        tap += procout
 
-        if proc.returncode not in exit_codes:
-            print
-            print("Could not execute:")
-            print(cmd)
-            print("\nError message:")
-            print(foutput)
-            print("\nAborting test run.")
-            ns_destroy()
-            exit(1)
+    prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown'])
+    pm.call_post_case()
 
+    index += 1
+
+    return tap
 
-def test_runner(filtered_tests, args):
+def test_runner(pm, args, filtered_tests):
     """
     Driver function for the unit tests.
 
@@ -102,74 +226,39 @@ def test_runner(filtered_tests, args):
     tcount = len(testlist)
     index = 1
     tap = str(index) + ".." + str(tcount) + "\n"
+    badtest = None
 
+    pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist])
+
+    if args.verbose > 1:
+        print('Run tests here')
     for tidx in testlist:
-        result = True
-        tresult = ""
         if "flower" in tidx["category"] and args.device == None:
             continue
-        print("Test " + tidx["id"] + ": " + tidx["name"])
-        prepare_env(tidx["setup"])
-        (p, procout) = exec_cmd(tidx["cmdUnderTest"])
-        exit_code = p.returncode
-
-        if (exit_code != int(tidx["expExitCode"])):
-            result = False
-            print("exit:", exit_code, int(tidx["expExitCode"]))
-            print(procout)
-        else:
-            match_pattern = re.compile(str(tidx["matchPattern"]), re.DOTALL)
-            (p, procout) = exec_cmd(tidx["verifyCmd"])
-            match_index = re.findall(match_pattern, procout)
-            if len(match_index) != int(tidx["matchCount"]):
-                result = False
-
-        if result == True:
-            tresult += "ok "
-        else:
-            tresult += "not ok "
-        tap += tresult + str(index) + " " + tidx["id"] + " " + tidx["name"] + "\n"
-
-        if result == False:
-            tap += procout
-
-        prepare_env(tidx["teardown"])
+        try:
+            badtest = tidx  # in case it goes bad
+            tap += run_one_test(pm, args, index, tidx)
+        except Exception as ee:
+            print('Exception {} (caught in test_runner, running test {} {} {})'.
+                  format(ee, index, tidx['id'], tidx['name']))
+            break
         index += 1
 
-    return tap
-
+    # if we failed in setup or teardown,
+    # fill in the remaining tests with not ok
+    count = index
+    tap += 'about to flush the tap output if tests need to be skipped\n'
+    if tcount + 1 != index:
+        for tidx in testlist[index - 1:]:
+            msg = 'skipped - previous setup or teardown failed'
+            tap += 'ok {} - {} # {} {} {}\n'.format(
+                count, tidx['id'], msg, index, badtest.get('id', '--Unknown--'))
+            count += 1
 
-def ns_create():
-    """
-    Create the network namespace in which the tests will be run and set up
-    the required network devices for it.
-    """
-    if (USE_NS):
-        cmd = 'ip netns add $NS'
-        exec_cmd(cmd, False)
-        cmd = 'ip link add $DEV0 type veth peer name $DEV1'
-        exec_cmd(cmd, False)
-        cmd = 'ip link set $DEV1 netns $NS'
-        exec_cmd(cmd, False)
-        cmd = 'ip link set $DEV0 up'
-        exec_cmd(cmd, False)
-        cmd = 'ip -n $NS link set $DEV1 up'
-        exec_cmd(cmd, False)
-        cmd = 'ip link set $DEV2 netns $NS'
-        exec_cmd(cmd, False)
-        cmd = 'ip -n $NS link set $DEV2 up'
-        exec_cmd(cmd, False)
-
-
-def ns_destroy():
-    """
-    Destroy the network namespace for testing (and any associated network
-    devices as well)
-    """
-    if (USE_NS):
-        cmd = 'ip netns delete $NS'
-        exec_cmd(cmd, False)
+    tap += 'done flushing skipped test tap output\n'
+    pm.call_post_suite(index)
 
+    return tap
 
 def has_blank_ids(idlist):
     """
@@ -209,29 +298,50 @@ def set_args(parser):
     """
     Set the command line arguments for tdc.
     """
-    parser.add_argument('-p', '--path', type=str,
-                        help='The full path to the tc executable to use')
-    parser.add_argument('-c', '--category', type=str, nargs='?', const='+c',
-                        help='Run tests only from the specified category, or if no category is specified, list known categories.')
-    parser.add_argument('-f', '--file', type=str,
-                        help='Run tests from the specified file')
-    parser.add_argument('-l', '--list', type=str, nargs='?', const="++", metavar='CATEGORY',
-                        help='List all test cases, or those only within the specified category')
-    parser.add_argument('-s', '--show', type=str, nargs=1, metavar='ID', dest='showID',
-                        help='Display the test case with specified id')
-    parser.add_argument('-e', '--execute', type=str, nargs=1, metavar='ID',
-                        help='Execute the single test case with specified ID')
-    parser.add_argument('-i', '--id', action='store_true', dest='gen_id',
-                        help='Generate ID numbers for new test cases')
+    parser.add_argument(
+        '-p', '--path', type=str,
+        help='The full path to the tc executable to use')
+    sg = parser.add_argument_group(
+        'selection', 'select which test cases: ' +
+        'files plus directories; filtered by categories plus testids')
+    ag = parser.add_argument_group(
+        'action', 'select action to perform on selected test cases')
+
+    sg.add_argument(
+        '-D', '--directory', nargs='+', metavar='DIR',
+        help='Collect tests from the specified directory(ies) ' +
+        '(default [tc-tests])')
+    sg.add_argument(
+        '-f', '--file', nargs='+', metavar='FILE',
+        help='Run tests from the specified file(s)')
+    sg.add_argument(
+        '-c', '--category', nargs='*', metavar='CATG', default=['+c'],
+        help='Run tests only from the specified category/ies, ' +
+        'or if no category/ies is/are specified, list known categories.')
+    sg.add_argument(
+        '-e', '--execute', nargs='+', metavar='ID',
+        help='Execute the specified test cases with specified IDs')
+    ag.add_argument(
+        '-l', '--list', action='store_true',
+        help='List all test cases, or those only within the specified category')
+    ag.add_argument(
+        '-s', '--show', action='store_true', dest='showID',
+        help='Display the selected test cases')
+    ag.add_argument(
+        '-i', '--id', action='store_true', dest='gen_id',
+        help='Generate ID numbers for new test cases')
+    parser.add_argument(
+        '-v', '--verbose', action='count', default=0,
+        help='Show the commands that are being run')
     parser.add_argument('-d', '--device',
                         help='Execute the test case in flower category')
     return parser
 
 
-def check_default_settings(args):
+def check_default_settings(args, remaining, pm):
     """
-    Process any arguments overriding the default settings, and ensure the
-    settings are correct.
+    Process any arguments overriding the default settings,
+    and ensure the settings are correct.
     """
     # Allow for overriding specific settings
     global NAMES
@@ -244,6 +354,8 @@ def check_default_settings(args):
         print("The specified tc path " + NAMES['TC'] + " does not exist.")
         exit(1)
 
+    pm.call_check_args(args, remaining)
+
 
 def get_id_list(alltests):
     """
@@ -300,40 +412,107 @@ def generate_case_ids(alltests):
         json.dump(testlist, outfile, indent=4)
         outfile.close()
 
+def filter_tests_by_id(args, testlist):
+    '''
+    Remove tests from testlist that are not in the named id list.
+    If id list is empty, return empty list.
+    '''
+    newlist = list()
+    if testlist and args.execute:
+        target_ids = args.execute
+
+        if isinstance(target_ids, list) and (len(target_ids) > 0):
+            newlist = list(filter(lambda x: x['id'] in target_ids, testlist))
+    return newlist
+
+def filter_tests_by_category(args, testlist):
+    '''
+    Remove tests from testlist that are not in a named category.
+    '''
+    answer = list()
+    if args.category and testlist:
+        test_ids = list()
+        for catg in set(args.category):
+            if catg == '+c':
+                continue
+            print('considering category {}'.format(catg))
+            for tc in testlist:
+                if catg in tc['category'] and tc['id'] not in test_ids:
+                    answer.append(tc)
+                    test_ids.append(tc['id'])
+
+    return answer
 
 def get_test_cases(args):
     """
     If a test case file is specified, retrieve tests from that file.
     Otherwise, glob for all json files in subdirectories and load from
     each one.
+    Also, if requested, filter by category, and add tests matching
+    certain ids.
     """
     import fnmatch
-    if args.file != None:
-        if not os.path.isfile(args.file):
-            print("The specified test case file " + args.file + " does not exist.")
-            exit(1)
-        flist = [args.file]
-    else:
-        flist = []
-        for root, dirnames, filenames in os.walk('tc-tests'):
+
+    flist = []
+    testdirs = ['tc-tests']
+
+    if args.file:
+        # at least one file was specified - remove the default directory
+        testdirs = []
+
+        for ff in args.file:
+            if not os.path.isfile(ff):
+                print("IGNORING file " + ff + "\n\tBECAUSE does not exist.")
+            else:
+                flist.append(os.path.abspath(ff))
+
+    if args.directory:
+        testdirs = args.directory
+
+    for testdir in testdirs:
+        for root, dirnames, filenames in os.walk(testdir):
             for filename in fnmatch.filter(filenames, '*.json'):
-                flist.append(os.path.join(root, filename))
-    alltests = list()
+                candidate = os.path.abspath(os.path.join(root, filename))
+                if candidate not in testdirs:
+                    flist.append(candidate)
+
+    alltestcases = list()
     for casefile in flist:
-        alltests = alltests + (load_from_file(casefile))
-    return alltests
+        alltestcases = alltestcases + (load_from_file(casefile))
+
+    allcatlist = get_test_categories(alltestcases)
+    allidlist = get_id_list(alltestcases)
+
+    testcases_by_cats = get_categorized_testlist(alltestcases, allcatlist)
+    idtestcases = filter_tests_by_id(args, alltestcases)
+    cattestcases = filter_tests_by_category(args, alltestcases)
+
+    cat_ids = [x['id'] for x in cattestcases]
+    if args.execute:
+        if args.category:
+            alltestcases = cattestcases + [x for x in idtestcases if x['id'] not in cat_ids]
+        else:
+            alltestcases = idtestcases
+    else:
+        if cat_ids:
+            alltestcases = cattestcases
+        else:
+            # just accept the existing value of alltestcases,
+            # which has been filtered by file/directory
+            pass
+
+    return allcatlist, allidlist, testcases_by_cats, alltestcases
 
 
-def set_operation_mode(args):
+def set_operation_mode(pm, args):
     """
     Load the test case data and process remaining arguments to determine
     what the script should do for this run, and call the appropriate
     function.
     """
-    alltests = get_test_cases(args)
+    ucat, idlist, testcases, alltests = get_test_cases(args)
 
     if args.gen_id:
-        idlist = get_id_list(alltests)
         if (has_blank_ids(idlist)):
             alltests = generate_case_ids(alltests)
         else:
@@ -347,70 +526,26 @@ def set_operation_mode(args):
         print("Please correct them before continuing.")
         exit(1)
 
-    ucat = get_test_categories(alltests)
-
     if args.showID:
-        show_test_case_by_id(alltests, args.showID[0])
+        for atest in alltests:
+            print_test_case(atest)
         exit(0)
 
-    if args.execute:
-        target_id = args.execute[0]
-    else:
-        target_id = ""
-
-    if args.category:
-        if (args.category == '+c'):
-            print("Available categories:")
-            print_sll(ucat)
-            exit(0)
-        else:
-            target_category = args.category
-    else:
-        target_category = ""
-
-
-    testcases = get_categorized_testlist(alltests, ucat)
+    if isinstance(args.category, list) and (len(args.category) == 0):
+        print("Available categories:")
+        print_sll(ucat)
+        exit(0)
 
     if args.list:
-        if (args.list == "++"):
+        if args.list:
             list_test_cases(alltests)
             exit(0)
-        elif(len(args.list) > 0):
-            if (args.list not in ucat):
-                print("Unknown category " + args.list)
-                print("Available categories:")
-                print_sll(ucat)
-                exit(1)
-            list_test_cases(testcases[args.list])
-            exit(0)
-
-    if (os.geteuid() != 0):
-        print("This script must be run with root privileges.\n")
-        exit(1)
-
-    ns_create()
-
-    if (len(target_category) == 0):
-        if (len(target_id) > 0):
-            alltests = list(filter(lambda x: target_id in x['id'], alltests))
-            if (len(alltests) == 0):
-                print("Cannot find a test case with ID matching " + target_id)
-                exit(1)
-        catresults = test_runner(alltests, args)
-        print("All test results: " + "\n\n" + catresults)
-    elif (len(target_category) > 0):
-        if (target_category == "flower") and args.device == None:
-            print("Please specify a NIC device (-d) to run category flower")
-            exit(1)
-        if (target_category not in ucat):
-            print("Specified category is not present in this file.")
-            exit(1)
-        else:
-            catresults = test_runner(testcases[target_category], args)
-            print("Category " + target_category + "\n\n" + catresults)
-
-    ns_destroy()
 
+    if len(alltests):
+        catresults = test_runner(pm, args, alltests)
+    else:
+        catresults = 'No tests found\n'
+    print('All test results: \n\n{}'.format(catresults))
 
 def main():
     """
@@ -419,10 +554,15 @@ def main():
     """
     parser = args_parse()
     parser = set_args(parser)
+    pm = PluginMgr(parser)
+    parser = pm.call_add_args(parser)
     (args, remaining) = parser.parse_known_args()
-    check_default_settings(args)
+    args.NAMES = NAMES
+    check_default_settings(args, remaining, pm)
+    if args.verbose > 2:
+        print('args is {}'.format(args))
 
-    set_operation_mode(args)
+    set_operation_mode(pm, args)
 
     exit(0)
 
diff --git a/tools/testing/selftests/tc-testing/tdc_helper.py b/tools/testing/selftests/tc-testing/tdc_helper.py
index db381120a566..9f35c96c88a0 100644
--- a/tools/testing/selftests/tc-testing/tdc_helper.py
+++ b/tools/testing/selftests/tc-testing/tdc_helper.py
@@ -57,20 +57,11 @@ def print_sll(items):
 
 def print_test_case(tcase):
     """ Pretty-printing of a given test case. """
+    print('\n==============\nTest {}\t{}\n'.format(tcase['id'], tcase['name']))
     for k in tcase.keys():
         if (isinstance(tcase[k], list)):
             print(k + ":")
             print_list(tcase[k])
         else:
-            print(k + ": " + tcase[k])
-
-
-def show_test_case_by_id(testlist, caseID):
-    """ Find the specified test case to pretty-print. """
-    if not any(d.get('id', None) == caseID for d in testlist):
-        print("That ID does not exist.")
-        exit(1)
-    else:
-        print_test_case(next((d for d in testlist if d['id'] == caseID)))
-
-
+            if not ((k == 'id') or (k == 'name')):
+                print(k + ": " + str(tcase[k]))
diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile
index 3d5a62ff7d31..f5d7a7851e21 100644
--- a/tools/testing/selftests/vDSO/Makefile
+++ b/tools/testing/selftests/vDSO/Makefile
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
+include ../lib.mk
+
 ifndef CROSS_COMPILE
 CFLAGS := -std=gnu99
 CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector
@@ -6,16 +8,14 @@ ifeq ($(CONFIG_X86_32),y)
 LDLIBS += -lgcc_s
 endif
 
-TEST_PROGS := vdso_test vdso_standalone_test_x86
+TEST_PROGS := $(OUTPUT)/vdso_test $(OUTPUT)/vdso_standalone_test_x86
 
 all: $(TEST_PROGS)
-vdso_test: parse_vdso.c vdso_test.c
-vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
+$(OUTPUT)/vdso_test: parse_vdso.c vdso_test.c
+$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
 	$(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \
 		vdso_standalone_test_x86.c parse_vdso.c \
-		-o vdso_standalone_test_x86
+		-o $@
 
-include ../lib.mk
-clean:
-	rm -fr $(TEST_PROGS)
+EXTRA_CLEAN := $(TEST_PROGS)
 endif
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index 63c94d776e89..342c7bc9dc8c 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -11,3 +11,4 @@ mlock-intersect-test
 mlock-random-test
 virtual_address_range
 gup_benchmark
+va_128TBswitch
diff --git a/tools/usb/Makefile b/tools/usb/Makefile
index 4e6506078494..01d758d73b6d 100644
--- a/tools/usb/Makefile
+++ b/tools/usb/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for USB tools
 
-CC = $(CROSS_COMPILE)gcc
 PTHREAD_LIBS = -lpthread
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g -I../include
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
index be320b905ea7..20f6cf04377f 100644
--- a/tools/vm/Makefile
+++ b/tools/vm/Makefile
@@ -6,7 +6,6 @@ TARGETS=page-types slabinfo page_owner_sort
 LIB_DIR = ../lib/api
 LIBS = $(LIB_DIR)/libapi.a
 
-CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra -I../lib/
 LDFLAGS = $(LIBS)
 
diff --git a/tools/wmi/Makefile b/tools/wmi/Makefile
index e664f1167388..e0e87239126b 100644
--- a/tools/wmi/Makefile
+++ b/tools/wmi/Makefile
@@ -2,7 +2,6 @@ PREFIX ?= /usr
 SBINDIR ?= sbin
 INSTALL ?= install
 CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
-CC = $(CROSS_COMPILE)gcc
 
 TARGET = dell-smbios-example
 
diff --git a/usr/initramfs_data.S b/usr/initramfs_data.S
index 10d325e24566..b28da799f6a6 100644
--- a/usr/initramfs_data.S
+++ b/usr/initramfs_data.S
@@ -10,7 +10,7 @@
 
   ld -m elf_i386  --format binary --oformat elf32-i386 -r \
   -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
-   ld -m elf_i386  -r -o built-in.o initramfs_data.o
+   ld -m elf_i386  -r -o built-in.a initramfs_data.o
 
   For including the .init.ramfs sections, see include/asm-generic/vmlinux.lds.
 
